From 05cbb89a461f4dd4311c6fd5cfd0cbfd34f0afb2 Mon Sep 17 00:00:00 2001 From: Nikolas Howard Date: Sat, 4 Feb 2023 14:41:56 +0000 Subject: [PATCH 01/48] added DSLParser with types and stubs --- src/DSLParser.ts | 283 +++++++++++++++++++++++++++++++++++++++++++++++ src/DSLtoJSON.js | 268 ++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 551 insertions(+) create mode 100644 src/DSLParser.ts create mode 100644 src/DSLtoJSON.js diff --git a/src/DSLParser.ts b/src/DSLParser.ts new file mode 100644 index 0000000..3c429eb --- /dev/null +++ b/src/DSLParser.ts @@ -0,0 +1,283 @@ +/** + * A type defining the arguments that can be passed to an agent function. + */ +export type AgentFunctionArguments = (string | number | boolean | null | undefined)[]; + +/** + * A guard attribute for a node. + */ +export type GuardAttributeDefinition = { + call: string; + args?: AgentFunctionArguments; +} + +/** + * A callback attribute for a node. + */ +export type CallbackAttributeDefinition = { + call: string; + args?: AgentFunctionArguments; +} + +/** + * A type defining a general node definition. + */ +export type NodeDefinition = { + type: string; + while?: GuardAttributeDefinition; + until?: GuardAttributeDefinition; + entry?: CallbackAttributeDefinition; + exit?: CallbackAttributeDefinition; + step?: CallbackAttributeDefinition; +} + +/** + * A composite node that can contain any number of child nodes. + */ +export type CompositeDefinition = NodeDefinition & { + children: AnyChildNode[]; +} + +/** + * A decorator node, a composite with only a single child node. + */ +export type DecoratorDefinition = NodeDefinition & { + child: AnyChildNode; +} + +/** + * A branch node. + */ +export type BranchDefinition = NodeDefinition & { + type: "branch"; + ref: string; +} + +/** + * An action node. + */ +export type ActionDefinition = NodeDefinition & { + type: "action"; + call: string; + args?: AgentFunctionArguments; +} + +/** + * A condition node. + */ +export type ConditionDefinition = NodeDefinition & { + type: "condition"; + call: string; + args?: AgentFunctionArguments; +} + +/** + * A wait node. + */ +export type WaitDefinition = NodeDefinition & { + type: "wait"; + duration: number | [number, number]; +} + +/** + * A sequence node. + */ +export type SequenceDefinition = CompositeDefinition & { + type: "sequence"; +} + +/** + * A selector node. + */ +export type SelectorDefinition = CompositeDefinition & { + type: "selector"; +} + +/** + * A lotto node. + */ +export type LottoDefinition = CompositeDefinition & { + type: "lotto"; + weights?: number[] +} + +/** + * A parallel node. + */ +export type ParallelDefinition = CompositeDefinition & { + type: "parallel"; +} + +/** + * A root node. + */ +export type RootDefinition = DecoratorDefinition & { + type: "root"; + id?: string; +} + +/** + * A repeat node. + */ +export type RepeatDefinition = DecoratorDefinition & { + type: "repeat"; + iterations?: number | [number, number]; +} + +/** + * A retry node. + */ +export type RetryDefinition = DecoratorDefinition & { + type: "retry"; + attempts?: number | [number, number]; +} + +/** + * A flip node. + */ +export type FlipDefinition = DecoratorDefinition & { + type: "flip"; +} + +/** + * A succeed node. + */ +export type SucceedDefinition = DecoratorDefinition & { + type: "succeed"; +} + +/** + * A fail node. + */ +export type FailDefinition = DecoratorDefinition & { + type: "fail"; +} + +/** + * A type defining any node type that can be a child of composite parent node. + */ +export type AnyChildNode = BranchDefinition | ActionDefinition | ConditionDefinition | WaitDefinition | SequenceDefinition | + SelectorDefinition | LottoDefinition | ParallelDefinition | RepeatDefinition | RetryDefinition | FlipDefinition | SucceedDefinition | FailDefinition; + +/** + * A type defining an object that holds a reference to substitued string literals parsed from the definition. + */ +type StringLiteralPlaceholders = { [key: string]: string }; + +/** + * Parse the tree definition string into a JSON definition. + * @param definition The tree definition string. + * @returns The root node JSON definitions. + */ +export function parse(definition: string): RootDefinition[] { + // Swap out any node/attribute argument string literals with a placeholder and get a mapping of placeholders to original values as well as the processed definition. + const { placeholders, processedDefinition } = substituteStringLiterals(definition); + + // Parse our definition definition string into an array of raw tokens. + const tokens = parseTokensFromDefinition(definition); + + // There must be at least 3 tokens for the tree definition to be valid. 'ROOT', '{' and '}'. + if (tokens.length < 3) { + throw new Error("invalid token count"); + } + + // We should have a matching number of '{' and '}' tokens. If not, then there are scopes that have not been properly closed. + if (tokens.filter((token) => token === "{").length !== tokens.filter((token) => token === "}").length) { + throw new Error("scope character mismatch"); + } + + return convertTokensToJSONDefinition(tokens, placeholders, processedDefinition); +} + +/** + * Converts the specified tree definition tokens into a JSON definition. + * @param tokens The tree definition tokens. + * @param placeholders The substituted string literal placeholders. + * @returns The root node JSON definitions. + */ +export function convertTokensToJSONDefinition(tokens: string[], placeholders: StringLiteralPlaceholders, processedDefinition: string): RootDefinition[] { + // TODO + return []; +} + +/** + * Swaps out any node/attribute argument string literals with placeholders. + * @param definition The definition. + * @returns An object containing a mapping of placeholders to original string values as well as the processed definition string. + */ +function substituteStringLiterals(definition: string): { + placeholders: StringLiteralPlaceholders; + processedDefinition: string; +} { + // Create an object to hold the mapping of placeholders to original string values. + const placeholders: StringLiteralPlaceholders = {}; + + // Replace any string literals wrapped with double quotes in our definition with placeholders to be processed later. + const processedDefinition = definition.replace(/\"(\\.|[^"\\])*\"/g, (match) => { + var strippedMatch = match.substring(1, match.length - 1); + var placeholder = Object.keys(placeholders).find((key) => placeholders[key] === strippedMatch); + + // If we have no existing string literal match then create a new placeholder. + if (!placeholder) { + placeholder = `@@${Object.keys(placeholders).length}@@`; + placeholders[placeholder] = strippedMatch; + } + + return placeholder; + }); + + return { placeholders, processedDefinition }; +} + +/** + * Parse the tree definition into an array of raw tokens. + * @param definition The definition. + * @returns An array of tokens parsed from the definition. + */ +function parseTokensFromDefinition(definition: string): string[] { + // Add some space around various important characters so that they can be plucked out easier as individual tokens. + definition = definition.replace(/\(/g, " ( "); + definition = definition.replace(/\)/g, " ) "); + definition = definition.replace(/\{/g, " { "); + definition = definition.replace(/\}/g, " } "); + definition = definition.replace(/\]/g, " ] "); + definition = definition.replace(/\[/g, " [ "); + definition = definition.replace(/\,/g, " , "); + + // Split the definition into raw token form and return it. + return definition.replace(/\s+/g, " ").trim().split(" "); +} + +/** + * Pop the next raw token off of the stack and throw an error if it wasn't the expected one. + * @param tokens The array of remaining tokens. + * @param expected An optional string or array or items, one of which must match the next popped token. + * @returns The popped token. + */ +function popAndCheck(tokens: string[], expected?: string | string[]): string { + // Get and remove the next token. + const popped = tokens.shift(); + + // We were expecting another token. + if (popped === undefined) { + throw new Error("unexpected end of definition"); + } + + // Do we have an expected token/tokens array? + if (expected != undefined) { + // Get an array of expected values, if the popped token matches any then we are all good. + const expectedValues = (typeof expected === "string") ? [expected] : expected; + + // Check whether the popped token matches at least one of our expected items. + var tokenMatchesExpectation = expectedValues.some((item) => popped.toUpperCase() === item.toUpperCase()); + + // Throw an error if the popped token didn't match any of our expected items. + if (!tokenMatchesExpectation) { + const expectationString = expectedValues.map((item) => "'" + item + "'").join(" or "); + throw new Error("unexpected token found. Expected " + expectationString + " but got '" + popped + "'"); + } + } + + // Return the popped token. + return popped; +} \ No newline at end of file diff --git a/src/DSLtoJSON.js b/src/DSLtoJSON.js new file mode 100644 index 0000000..6ce0e75 --- /dev/null +++ b/src/DSLtoJSON.js @@ -0,0 +1,268 @@ +//root { +// action [SomeAction] +//} + +let definition = { + type: "root", + children: [ + { + type: "action", + call: "SomeAction" + } + ] +} + + +//root { +// branch [SomeOtherTree] +//} +// +//root [SomeOtherTree] { +// action [Dance] +//} + +definition = [ + { + type: "root", + children: [ + { + type: "branch", + ref: "SomeOtherTree" + } + ] + }, + { + type: "root", + id: "SomeOtherTree", + children: [ + { + type: "action", + call: "SomeAction" + } + ] + } +] + +//root { +// action [Say, "hello world", 5, true] +//} + +definition = { + type: "root", + children: [ + { + type: "action", + call: "SomeAction", + args: ["hello world", 5, true] + } + ] +} + +//root { +// condition [SomeCondition] +//} + +definition = { + type: "root", + children: [ + { + type: "condition", + call: "SomeCondition" + } + ] +} + +//root { +// condition [HasItem, "gold", 500] +//} + +definition = { + type: "root", + children: [ + { + type: "condition", + call: "HasItem", + args: ["gold", 500] + } + ] +} + +//root { +// wait [2000] +//} + +definition = { + type: "root", + children: [ + { + type: "wait", + duration: 2000 + } + ] +} + +//root { +// wait [2000, 5000] +//} + +definition = { + type: "root", + children: [ + { + type: "wait", + duration: [2000, 5000] + } + ] +} + +//root { +// sequence { +// action [Walk] +// } +//} + +definition = { + type: "root", + children: [ + { + type: "sequence", + children: [ + { + type: "action", + call: "Walk" + } + ] + } + ] +} + +//root { +// selector { +// action [Walk] +// } +//} + +definition = { + type: "root", + children: [ + { + type: "selector", + children: [ + { + type: "action", + call: "Walk" + } + ] + } + ] +} + +//root { +// lotto { +// action [GoLeft] +// action [GoRight] +// } +//} + +definition = { + type: "root", + children: [ + { + type: "lotto", + children: [ + { + type: "action", + call: "GoLeft" + }, + { + type: "action", + call: "GoRight" + } + ] + } + ] +} + +//root { +// lotto [9, 1] { +// action [CommonAction] +// action [RareAction] +// } +//} + +definition = { + type: "root", + children: [ + { + type: "lotto", + weights: [9, 1], + children: [ + { + type: "action", + call: "CommonAction" + }, + { + type: "action", + call: "RareAction" + } + ] + } + ] +} + +//root { +// repeat { +// sequence { +// wait [1000] +// } +// } +//} + +definition = { + type: "root", + children: [ + { + type: "repeat", + child: { + type: "sequence", + children: [ + { + type: "wait", + duration: 1000 + } + ] + } + } + ] +} + +//root { +// selector { +// action [SomeAction] while(IsKeyDown, "Enter") +// } +//} + +//root { +// selector { +// action [Walk] +// } +//} + +definition = { + type: "root", + children: [ + { + type: "selector", + children: [ + { + type: "action", + call: "SomeAction", + while: { + call: "IsKeyDown", + args: ["Enter"] + } + } + ] + } + ] +} \ No newline at end of file From 584e1d70beeefcaa23e5400ff62592eda34077a6 Mon Sep 17 00:00:00 2001 From: Nikolas Howard Date: Sat, 4 Feb 2023 17:07:57 +0000 Subject: [PATCH 02/48] working through DSL parsing and definition stack building logic --- src/DSLParser.ts | 134 +++++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 123 insertions(+), 11 deletions(-) diff --git a/src/DSLParser.ts b/src/DSLParser.ts index 3c429eb..d07c93c 100644 --- a/src/DSLParser.ts +++ b/src/DSLParser.ts @@ -153,17 +153,34 @@ export type FailDefinition = DecoratorDefinition & { type: "fail"; } +/** + * A type defining any node type. + */ +export type AnyNode = BranchDefinition | ActionDefinition | ConditionDefinition | WaitDefinition | SequenceDefinition | + SelectorDefinition | LottoDefinition | ParallelDefinition | RootDefinition | RepeatDefinition | RetryDefinition | FlipDefinition | SucceedDefinition | FailDefinition; + /** * A type defining any node type that can be a child of composite parent node. */ -export type AnyChildNode = BranchDefinition | ActionDefinition | ConditionDefinition | WaitDefinition | SequenceDefinition | - SelectorDefinition | LottoDefinition | ParallelDefinition | RepeatDefinition | RetryDefinition | FlipDefinition | SucceedDefinition | FailDefinition; +export type AnyChildNode = Exclude; /** * A type defining an object that holds a reference to substitued string literals parsed from the definition. */ type StringLiteralPlaceholders = { [key: string]: string }; +function isLeafNode(node: NodeDefinition): node is NodeDefinition { + return ["branch", "action", "condition", "wait"].includes(node.type); +} + +function isDecoratorNode(node: NodeDefinition): node is DecoratorDefinition { + return ["root", "repeat", "retry", "flip", "succeed", "fail"].includes(node.type); +} + +function isCompositeNode(node: NodeDefinition): node is CompositeDefinition { + return ["sequence", "selector", "lotto", "parallel"].includes(node.type); +} + /** * Parse the tree definition string into a JSON definition. * @param definition The tree definition string. @@ -176,6 +193,16 @@ export function parse(definition: string): RootDefinition[] { // Parse our definition definition string into an array of raw tokens. const tokens = parseTokensFromDefinition(definition); + return convertTokensToJSONDefinition(tokens, placeholders, processedDefinition); +} + +/** + * Converts the specified tree definition tokens into a JSON definition. + * @param tokens The tree definition tokens. + * @param placeholders The substituted string literal placeholders. + * @returns The root node JSON definitions. + */ +export function convertTokensToJSONDefinition(tokens: string[], placeholders: StringLiteralPlaceholders, processedDefinition: string): RootDefinition[] { // There must be at least 3 tokens for the tree definition to be valid. 'ROOT', '{' and '}'. if (tokens.length < 3) { throw new Error("invalid token count"); @@ -186,16 +213,101 @@ export function parse(definition: string): RootDefinition[] { throw new Error("scope character mismatch"); } - return convertTokensToJSONDefinition(tokens, placeholders, processedDefinition); -} + // Create a stack of node children arrays, starting with a definition scope. + const rootStacks: [Partial, ...Partial[]][] = []; + + // ONLY COMPOSITE DEFINITIONS GET PUSHED ONTO A ROOT STACK. + // When coming across a new node in the definition it must be: + // - Set as the child of the top-most node in the root stack OR + // - Added to the array of children of the top-most node in the root stack OR + + const pushNode = (node: AnyChildNode) => { + // Get the current root stack that we are populating. + const currentRootStack = rootStacks[rootStacks.length - 1]; + + // TODO Handle cases where we may not have a current root stack. + // This may happen if a root node is not the initially defined one? + + // Get the top node in the current root stack. + const topNode = currentRootStack[currentRootStack.length - 1] as AnyNode; + + // TODO Handle cases where we may not have a top-most node. + // Also a potential issue with a badly defined tree. + + // If the top-most node in the current root stack is a composite or decorator + // node then the current node should be added as a child of the top-most node. + if (isCompositeNode(topNode)) { + topNode.children.push(node); + } else if (isDecoratorNode(topNode)) { + topNode.child = node; + } + + // If the node we are adding is also a composite or decorator node, then we should push it + // onto the current root stack, as subsequent nodes will be added as its child/children. + if (!isLeafNode(node)) { + currentRootStack.push(node); + } + }; + + const popNode = () => { + // Get the current root stack that we are populating. + const currentRootStack = rootStacks[rootStacks.length - 1]; + + // Pop the top-most node in the current root stack if there is one. + if (currentRootStack.length) { + currentRootStack.pop(); + } + + // We dont want any root stacks in our definition stack. + if (!currentRootStack.length) { + rootStacks.pop(); + } + }; + + // We should keep processing the raw tokens until we run out of them. + while (tokens.length) { + // Grab the next token. + const token = tokens.shift(); + + // How we create the next node depends on the current raw token value. + switch (token!.toUpperCase()) { + case "ROOT": { + const node = { + type: "root" + } as RootDefinition; + + // TODO Grab 'id' if defined as a node argument. + // TODO Grab attributes. + + // A root node will always be the base of a new root stack. + rootStacks.push([node]); + break; + } + + case "SEQUENCE": { + const node = { + type: "sequence", + children: [] + } as SequenceDefinition; + + // TODO Grab attributes. + + pushNode(node); + break; + } + + case "}": { + // The '}' character closes the current scope. + popNode(); + break; + } + + default: { + throw new Error("unexpected token: " + token); + } + } + } -/** - * Converts the specified tree definition tokens into a JSON definition. - * @param tokens The tree definition tokens. - * @param placeholders The substituted string literal placeholders. - * @returns The root node JSON definitions. - */ -export function convertTokensToJSONDefinition(tokens: string[], placeholders: StringLiteralPlaceholders, processedDefinition: string): RootDefinition[] { // TODO return []; } From 8c75a9c31e13738aead49050db2ef24a24b60072 Mon Sep 17 00:00:00 2001 From: Nikolas Howard Date: Sat, 4 Feb 2023 17:29:04 +0000 Subject: [PATCH 03/48] tidying up --- src/DSLParser.ts | 59 ++++++++++++++++++++++++++++-------------------- 1 file changed, 35 insertions(+), 24 deletions(-) diff --git a/src/DSLParser.ts b/src/DSLParser.ts index d07c93c..b1a7f9e 100644 --- a/src/DSLParser.ts +++ b/src/DSLParser.ts @@ -213,54 +213,65 @@ export function convertTokensToJSONDefinition(tokens: string[], placeholders: St throw new Error("scope character mismatch"); } - // Create a stack of node children arrays, starting with a definition scope. - const rootStacks: [Partial, ...Partial[]][] = []; + // Create a stack of tree stack arrays where root nodes will always be at the root. + const treeStacks: [Partial, ...Partial[]][] = []; + + // Create an array of all root node definitions that we create. + const rootNodes: Partial[] = []; // ONLY COMPOSITE DEFINITIONS GET PUSHED ONTO A ROOT STACK. // When coming across a new node in the definition it must be: // - Set as the child of the top-most node in the root stack OR // - Added to the array of children of the top-most node in the root stack OR + + const pushRootNode = (rootNode: RootDefinition) => { + // Add the root node definition to our array of all parsed root node definitions. + rootNodes.push(rootNode); + + // Add the root node definition to the root of a new tree stack. + treeStacks.push([rootNode]); + } const pushNode = (node: AnyChildNode) => { - // Get the current root stack that we are populating. - const currentRootStack = rootStacks[rootStacks.length - 1]; + // Get the current tree stack that we are populating. + const currentTreeStack = treeStacks[treeStacks.length - 1]; // TODO Handle cases where we may not have a current root stack. // This may happen if a root node is not the initially defined one? - // Get the top node in the current root stack. - const topNode = currentRootStack[currentRootStack.length - 1] as AnyNode; + // Get the bottom-most node in the current tree stack. + const bottomNode = currentTreeStack[currentTreeStack.length - 1] as AnyNode; - // TODO Handle cases where we may not have a top-most node. + // TODO Handle cases where we may not have a bottom-most node. // Also a potential issue with a badly defined tree. - // If the top-most node in the current root stack is a composite or decorator - // node then the current node should be added as a child of the top-most node. - if (isCompositeNode(topNode)) { - topNode.children.push(node); - } else if (isDecoratorNode(topNode)) { - topNode.child = node; + // If the bottom-most node in the current root stack is a composite or decorator + // node then the current node should be added as a child of the bottom-most node. + if (isCompositeNode(bottomNode)) { + bottomNode.children.push(node); + } else if (isDecoratorNode(bottomNode)) { + bottomNode.child = node; } // If the node we are adding is also a composite or decorator node, then we should push it - // onto the current root stack, as subsequent nodes will be added as its child/children. + // onto the current tree stack, as subsequent nodes will be added as its child/children. if (!isLeafNode(node)) { - currentRootStack.push(node); + currentTreeStack.push(node); } }; const popNode = () => { - // Get the current root stack that we are populating. - const currentRootStack = rootStacks[rootStacks.length - 1]; + // Get the current tree stack that we are populating. + const currentTreeStack = treeStacks[treeStacks.length - 1]; - // Pop the top-most node in the current root stack if there is one. - if (currentRootStack.length) { - currentRootStack.pop(); + // Pop the top-most node in the current tree stack if there is one. + if (currentTreeStack.length) { + currentTreeStack.pop(); } - // We dont want any root stacks in our definition stack. - if (!currentRootStack.length) { - rootStacks.pop(); + // We don't want any empty tree stacks in our stack of tree stacks. + if (!currentTreeStack.length) { + treeStacks.pop(); } }; @@ -280,7 +291,7 @@ export function convertTokensToJSONDefinition(tokens: string[], placeholders: St // TODO Grab attributes. // A root node will always be the base of a new root stack. - rootStacks.push([node]); + pushRootNode(node); break; } From a62d7c4db7459bad4338dde3a6170c9a85383db8 Mon Sep 17 00:00:00 2001 From: Nikolas Howard Date: Sat, 4 Feb 2023 17:31:59 +0000 Subject: [PATCH 04/48] more tidting --- src/DSLParser.ts | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/src/DSLParser.ts b/src/DSLParser.ts index b1a7f9e..44be4a5 100644 --- a/src/DSLParser.ts +++ b/src/DSLParser.ts @@ -248,6 +248,7 @@ export function convertTokensToJSONDefinition(tokens: string[], placeholders: St // If the bottom-most node in the current root stack is a composite or decorator // node then the current node should be added as a child of the bottom-most node. if (isCompositeNode(bottomNode)) { + bottomNode.children = bottomNode.children || []; bottomNode.children.push(node); } else if (isDecoratorNode(bottomNode)) { bottomNode.child = node; @@ -297,8 +298,7 @@ export function convertTokensToJSONDefinition(tokens: string[], placeholders: St case "SEQUENCE": { const node = { - type: "sequence", - children: [] + type: "sequence" } as SequenceDefinition; // TODO Grab attributes. @@ -307,6 +307,17 @@ export function convertTokensToJSONDefinition(tokens: string[], placeholders: St break; } + case "ACTION": { + const node = { + type: "action" + } as ActionDefinition; + + // TODO Grab attributes. + + pushNode(node); + break; + } + case "}": { // The '}' character closes the current scope. popNode(); From fa44018142ca1b7645ccd500e95d126a2069b53b Mon Sep 17 00:00:00 2001 From: Nikolas Howard Date: Sat, 4 Feb 2023 17:50:57 +0000 Subject: [PATCH 05/48] building super simple JSON structure for a few node types, cant handle attributes and args yet --- dist/DSLParser.d.ts | 163 +++++++++++++++++++++++++++++++++++++++++++ dist/bundle.js.map | 2 +- dist/index.js | 132 +++++++++++++++++++++++++++++++++++ dist/index.js.map | 8 +-- src/BehaviourTree.ts | 8 +++ src/DSLParser.ts | 13 +++- 6 files changed, 319 insertions(+), 7 deletions(-) create mode 100644 dist/DSLParser.d.ts diff --git a/dist/DSLParser.d.ts b/dist/DSLParser.d.ts new file mode 100644 index 0000000..ea0e67a --- /dev/null +++ b/dist/DSLParser.d.ts @@ -0,0 +1,163 @@ +/** + * A type defining the arguments that can be passed to an agent function. + */ +export type AgentFunctionArguments = (string | number | boolean | null | undefined)[]; +/** + * A guard attribute for a node. + */ +export type GuardAttributeDefinition = { + call: string; + args?: AgentFunctionArguments; +}; +/** + * A callback attribute for a node. + */ +export type CallbackAttributeDefinition = { + call: string; + args?: AgentFunctionArguments; +}; +/** + * A type defining a general node definition. + */ +export type NodeDefinition = { + type: string; + while?: GuardAttributeDefinition; + until?: GuardAttributeDefinition; + entry?: CallbackAttributeDefinition; + exit?: CallbackAttributeDefinition; + step?: CallbackAttributeDefinition; +}; +/** + * A composite node that can contain any number of child nodes. + */ +export type CompositeDefinition = NodeDefinition & { + children: AnyChildNode[]; +}; +/** + * A decorator node, a composite with only a single child node. + */ +export type DecoratorDefinition = NodeDefinition & { + child: AnyChildNode; +}; +/** + * A branch node. + */ +export type BranchDefinition = NodeDefinition & { + type: "branch"; + ref: string; +}; +/** + * An action node. + */ +export type ActionDefinition = NodeDefinition & { + type: "action"; + call: string; + args?: AgentFunctionArguments; +}; +/** + * A condition node. + */ +export type ConditionDefinition = NodeDefinition & { + type: "condition"; + call: string; + args?: AgentFunctionArguments; +}; +/** + * A wait node. + */ +export type WaitDefinition = NodeDefinition & { + type: "wait"; + duration: number | [number, number]; +}; +/** + * A sequence node. + */ +export type SequenceDefinition = CompositeDefinition & { + type: "sequence"; +}; +/** + * A selector node. + */ +export type SelectorDefinition = CompositeDefinition & { + type: "selector"; +}; +/** + * A lotto node. + */ +export type LottoDefinition = CompositeDefinition & { + type: "lotto"; + weights?: number[]; +}; +/** + * A parallel node. + */ +export type ParallelDefinition = CompositeDefinition & { + type: "parallel"; +}; +/** + * A root node. + */ +export type RootDefinition = DecoratorDefinition & { + type: "root"; + id?: string; +}; +/** + * A repeat node. + */ +export type RepeatDefinition = DecoratorDefinition & { + type: "repeat"; + iterations?: number | [number, number]; +}; +/** + * A retry node. + */ +export type RetryDefinition = DecoratorDefinition & { + type: "retry"; + attempts?: number | [number, number]; +}; +/** + * A flip node. + */ +export type FlipDefinition = DecoratorDefinition & { + type: "flip"; +}; +/** + * A succeed node. + */ +export type SucceedDefinition = DecoratorDefinition & { + type: "succeed"; +}; +/** + * A fail node. + */ +export type FailDefinition = DecoratorDefinition & { + type: "fail"; +}; +/** + * A type defining any node type. + */ +export type AnyNode = BranchDefinition | ActionDefinition | ConditionDefinition | WaitDefinition | SequenceDefinition | SelectorDefinition | LottoDefinition | ParallelDefinition | RootDefinition | RepeatDefinition | RetryDefinition | FlipDefinition | SucceedDefinition | FailDefinition; +/** + * A type defining any node type that can be a child of composite parent node. + */ +export type AnyChildNode = Exclude; +/** + * A type defining an object that holds a reference to substitued string literals parsed from the definition. + */ +type StringLiteralPlaceholders = { + [key: string]: string; +}; +/** + * Parse the tree definition string into a JSON definition. + * @param definition The tree definition string. + * @returns The root node JSON definitions. + */ +export declare function parse(definition: string): RootDefinition[]; +/** + * Converts the specified tree definition tokens into a JSON definition. + * @param tokens The tree definition tokens. + * @param placeholders The substituted string literal placeholders. + * @returns The root node JSON definitions. + */ +export declare function convertTokensToJSONDefinition(tokens: string[], placeholders: StringLiteralPlaceholders, processedDefinition: string): RootDefinition[]; +export {}; diff --git a/dist/bundle.js.map b/dist/bundle.js.map index dbc2bda..098b0e1 100644 --- a/dist/bundle.js.map +++ b/dist/bundle.js.map @@ -1,7 +1,7 @@ { "version": 3, "sources": ["../node_modules/lotto-draw/dist/Participant.js", "../node_modules/lotto-draw/dist/Utilities.js", "../node_modules/lotto-draw/dist/Lotto.js", "../node_modules/lotto-draw/dist/createLotto.js", "../node_modules/lotto-draw/dist/index.js", "../src/index.ts", "../src/attributes/guards/GuardUnsatisifedException.ts", "../src/attributes/guards/GuardPath.ts", "../src/State.ts", "../src/nodes/Node.ts", "../src/nodes/leaf/Leaf.ts", "../src/Lookup.ts", "../src/nodes/leaf/Action.ts", "../src/nodes/leaf/Condition.ts", "../src/nodes/leaf/Wait.ts", "../src/nodes/decorator/Decorator.ts", "../src/nodes/decorator/Root.ts", "../src/nodes/decorator/Repeat.ts", "../src/nodes/decorator/Retry.ts", "../src/nodes/decorator/Flip.ts", "../src/nodes/decorator/Succeed.ts", "../src/nodes/decorator/Fail.ts", "../src/nodes/composite/Lotto.ts", "../src/nodes/composite/Composite.ts", "../src/nodes/composite/Selector.ts", "../src/nodes/composite/Sequence.ts", "../src/nodes/composite/Parallel.ts", "../src/attributes/Attribute.ts", "../src/attributes/guards/Guard.ts", "../src/attributes/guards/While.ts", "../src/attributes/guards/Until.ts", "../src/attributes/callbacks/Callback.ts", "../src/attributes/callbacks/Entry.ts", "../src/attributes/callbacks/Exit.ts", "../src/attributes/callbacks/Step.ts", "../src/RootAstNodesBuilder.ts", "../src/BehaviourTree.ts"], - "sourcesContent": ["\"use strict\";\r\nObject.defineProperty(exports, \"__esModule\", { value: true });\r\nexports.Participant = void 0;\r\n/**\r\n * A participant that holds a number of tickets.\r\n */\r\nvar Participant = /** @class */ (function () {\r\n /**\r\n * Creates an instance of the Participant class.\r\n * @param participant The actual participant.\r\n * @param tickets The number of tickets held by the participant.\r\n */\r\n function Participant(participant, tickets) {\r\n if (tickets === void 0) { tickets = 1; }\r\n this._participant = participant;\r\n this._tickets = tickets;\r\n }\r\n Object.defineProperty(Participant.prototype, \"participant\", {\r\n /** Gets the actual participant. */\r\n get: function () {\r\n return this._participant;\r\n },\r\n enumerable: false,\r\n configurable: true\r\n });\r\n Object.defineProperty(Participant.prototype, \"tickets\", {\r\n /** Gets or sets the number of tickets held by the participant. */\r\n get: function () {\r\n return this._tickets;\r\n },\r\n set: function (value) {\r\n this._tickets = value;\r\n },\r\n enumerable: false,\r\n configurable: true\r\n });\r\n return Participant;\r\n}());\r\nexports.Participant = Participant;\r\n", "\"use strict\";\r\nObject.defineProperty(exports, \"__esModule\", { value: true });\r\nexports.isNaturalNumber = exports.isNullOrUndefined = void 0;\r\n/**\r\n * Gets whether the value provided is null or undefined.\r\n * @param value The value to check.\r\n * @returns Whether the value provided is null or undefined.\r\n */\r\nfunction isNullOrUndefined(value) {\r\n return value === null || value === undefined;\r\n}\r\nexports.isNullOrUndefined = isNullOrUndefined;\r\n/**\r\n * Gets whether the value provided is a natural number.\r\n * @param value The value to check.\r\n * @returns Whether the value provided is a natural number.\r\n */\r\nfunction isNaturalNumber(value) {\r\n return typeof value === \"number\" && value >= 1 && Math.floor(value) === value;\r\n}\r\nexports.isNaturalNumber = isNaturalNumber;\r\n", "\"use strict\";\r\nObject.defineProperty(exports, \"__esModule\", { value: true });\r\nexports.Lotto = void 0;\r\nvar Participant_1 = require(\"./Participant\");\r\nvar Utilities_1 = require(\"./Utilities\");\r\n/**\r\n * Represents a lotto consisting of a number of pickable ticket-holding participants.\r\n */\r\nvar Lotto = /** @class */ (function () {\r\n /**\r\n * Creates a new instance of Lotto.\r\n * @param customRandom The custom RNG to use in place of Math.random().\r\n */\r\n function Lotto(customRandom) {\r\n /** The array of participants that are holding tickets in the lotto. */\r\n this._participants = [];\r\n this._customRandom = customRandom;\r\n }\r\n /**\r\n * Adds a participant with the specified number of tickets, or adds to the participant ticket count if the participant already holds tickets.\r\n * @param participant The participant to add or to increase the ticket count for if they already hold tickets.\r\n * @param tickets The number of tickets, defaults to 1.\r\n * @returns The Lotto instance.\r\n */\r\n Lotto.prototype.add = function (participant, tickets) {\r\n if (tickets === void 0) { tickets = 1; }\r\n // Check that we have a valid ticket count.\r\n if (!(0, Utilities_1.isNaturalNumber)(tickets)) {\r\n throw new Error(\"tickets value must be a natural number\");\r\n }\r\n // Check whether this participant has already been added.\r\n var existingParticipant = this._participants.find(function (part) { return part.participant === participant; });\r\n if (existingParticipant) {\r\n // The participant has already been added to the lotto so just add to their ticket count.\r\n existingParticipant.tickets += tickets;\r\n }\r\n else {\r\n // The participant is not part of the lotto so we should add them.\r\n this._participants.push(new Participant_1.Participant(participant, tickets));\r\n }\r\n return this;\r\n };\r\n /**\r\n * Removes the specified number of tickets for the given participant from the draw, or all tickets if a ticket number is not defined.\r\n * @param participant The participant to remove tickets for.\r\n * @param tickets The number of tickets to remove, or undefined if all tickets are to be removed.\r\n * @returns The Lotto instance.\r\n */\r\n Lotto.prototype.remove = function (participant, tickets) {\r\n // Attempt to get the existing participant.\r\n var existingParticipant = this._participants.find(function (part) { return part.participant === participant; });\r\n // There is nothing to do if the specified participant isn't even part of the lotto.\r\n if (!existingParticipant) {\r\n return this;\r\n }\r\n // Check whether a tickets value was given.\r\n if (tickets !== undefined) {\r\n // Check that we have a valid ticket count.\r\n if (!(0, Utilities_1.isNaturalNumber)(tickets)) {\r\n throw new Error(\"tickets value must be a natural number\");\r\n }\r\n existingParticipant.tickets -= tickets;\r\n // If the participant no longer holds any tickets then they should be removed.\r\n if (existingParticipant.tickets < 1) {\r\n this._participants = this._participants.filter(function (part) { return part !== existingParticipant; });\r\n }\r\n }\r\n else {\r\n // We are removing all tickets for the participant so just remove them from the lotto.\r\n this._participants = this._participants.filter(function (part) { return part !== existingParticipant; });\r\n }\r\n return this;\r\n };\r\n /**\r\n * Draw a winning ticket and return the participant that holds the ticket.\r\n * @param options The draw options.\r\n * @returns The participant that holds the winning ticket.\r\n */\r\n Lotto.prototype.draw = function (options) {\r\n if (options === void 0) { options = {}; }\r\n // If we have no participants then just return null.\r\n if (this._participants.length === 0) {\r\n return null;\r\n }\r\n var redrawable = (0, Utilities_1.isNullOrUndefined)(options.redrawable) ? true : options.redrawable;\r\n var pickable = [];\r\n this._participants.forEach(function (_a) {\r\n var participant = _a.participant, tickets = _a.tickets;\r\n for (var ticketCount = 0; ticketCount < tickets; ticketCount++) {\r\n pickable.push(participant);\r\n }\r\n });\r\n var random;\r\n // We need a random floating-point number between 0 (inclusive) and 1 to scale up to pick our winner.\r\n // If a custom random function exists then we should use that or fall back to Math.random().\r\n if (this._customRandom) {\r\n // Call our custom random function to get a random floating-point number.\r\n random = this._customRandom();\r\n // Verify that the result of calling our custom random function is a number between 0 (inclusive) and 1.\r\n if (typeof random !== \"number\" || random < 0 || random >= 1) {\r\n throw new Error(\"the 'random' function provided did not return a number between 0 (inclusive) and 1\");\r\n }\r\n }\r\n else {\r\n // No custom random function was defined so just use good ol' Math.random().\r\n random = Math.random();\r\n }\r\n // Pick a winning participant.\r\n var winner = pickable[Math.floor(random * pickable.length)];\r\n // If the ticket isn't redrawable then we should remove a ticket from the winning participants ticket count.\r\n if (!redrawable) {\r\n this.remove(winner, 1);\r\n }\r\n // Return the winning participant.\r\n return winner;\r\n };\r\n /**\r\n * Draws multiple winning tickets and return an array of the participants that hold the winning tickets.\r\n * @param tickets The number of winning tickets to draw.\r\n * @param options The draw multiple options.\r\n * @returns An array of the participants that hold the winning tickets.\r\n */\r\n Lotto.prototype.drawMultiple = function (tickets, options) {\r\n if (options === void 0) { options = {}; }\r\n var uniqueResults = (0, Utilities_1.isNullOrUndefined)(options.unique) ? false : options.unique;\r\n // Handle cases where the user has asked for zero tickets (no idea why they would do this be we should trust them).\r\n if (tickets === 0) {\r\n return [];\r\n }\r\n // Now that we know out tickets value is not zero we should check that it is a valid natural number.\r\n if (!(0, Utilities_1.isNaturalNumber)(tickets)) {\r\n throw new Error(\"tickets value must be a natural number\");\r\n }\r\n var result = [];\r\n // Keep drawing tickets until we either reach the number of required tickets or we simply run out of tickets to draw.\r\n // We can run out of tickets to draw if 'options.redrawable' is explicity 'false' or we just had no participants when 'drawMultiple' was called.\r\n while (result.length < tickets && this._participants.length > 0) {\r\n result.push(this.draw(options));\r\n }\r\n // If the 'unique' draw option is set then we need to remove duplicates from the result list.\r\n if (uniqueResults) {\r\n // Create an array to store our unique results.\r\n var unique = [];\r\n // Iterate over all of our participants (with potential duplicates) and populate our array of unique values.\r\n for (var _i = 0, result_1 = result; _i < result_1.length; _i++) {\r\n var participant = result_1[_i];\r\n if (unique.indexOf(participant) === -1) {\r\n unique.push(participant);\r\n }\r\n }\r\n result = unique;\r\n }\r\n return result;\r\n };\r\n return Lotto;\r\n}());\r\nexports.Lotto = Lotto;\r\n", "\"use strict\";\r\nObject.defineProperty(exports, \"__esModule\", { value: true });\r\nexports.createLotto = void 0;\r\nvar Lotto_1 = require(\"./Lotto\");\r\n/**\r\n * A function that creates and returns a Lotto instance.\r\n * @param participantsOrOptions An array of initial participants or options relating to the creation of a Lotto instance.\r\n * @returns A new Lotto instance.\r\n */\r\nfunction createLotto(participantsOrOptions) {\r\n // If no initial participants or lotto options were provided as an argument then we can just return a new lotto instance now.\r\n if (!participantsOrOptions) {\r\n return new Lotto_1.Lotto();\r\n }\r\n // Check whether we were provided with an array of initial participants or a lotto options object.\r\n if (Array.isArray(participantsOrOptions)) {\r\n // We are dealing with a pre-defined array of participants.\r\n var participants = participantsOrOptions;\r\n var lotto_1 = new Lotto_1.Lotto();\r\n // If the lotto participants have been defined upfront then we will need to add them all to our lotto instance now.\r\n participants.forEach(function (_a) {\r\n var participant = _a[0], tokens = _a[1];\r\n return lotto_1.add(participant, tokens);\r\n });\r\n // Return the Lotto instance.\r\n return lotto_1;\r\n }\r\n else {\r\n // We are dealing with some lotto options.\r\n var random = participantsOrOptions.random, participants = participantsOrOptions.participants;\r\n // Create a Lotto instance passing the custom RNG function to use in place of Math.random() (which could be undefined).\r\n var lotto_2 = new Lotto_1.Lotto(random);\r\n // If the lotto participants have been defined upfront as part of the options then we will need to add them all to our lotto instance now.\r\n if (participants) {\r\n participants.forEach(function (_a) {\r\n var participant = _a[0], tokens = _a[1];\r\n return lotto_2.add(participant, tokens);\r\n });\r\n }\r\n // Return the Lotto instance.\r\n return lotto_2;\r\n }\r\n}\r\nexports.createLotto = createLotto;\r\n", "\"use strict\";\r\nObject.defineProperty(exports, \"__esModule\", { value: true });\r\nvar createLotto_1 = require(\"./createLotto\");\r\nexports.default = createLotto_1.createLotto;\r\n", "import { BehaviourTree, FlattenedTreeNode } from \"./BehaviourTree\";\nimport State from \"./State\";\n\nexport { BehaviourTree, State };\nexport type { FlattenedTreeNode };\n", "import Node from \"../../nodes/Node\";\n\n/**\n * An exception thrown when evaluating node guard path conditions and a conditions fails.\n */\nexport default class GuardUnsatisifedException extends Error {\n /**\n * @param source The node at which a guard condition failed.\n */\n constructor(private source: Node) {\n super(\"A guard path condition has failed\");\n }\n\n /**\n * Gets whether the specified node is the node at which a guard condition failed.\n * @param node The node to check against the source node.\n * @returns Whether the specified node is the node at which a guard condition failed.\n */\n isSourceNode = (node: Node) => node === this.source;\n}\n", "import { Agent } from \"../../Agent\";\nimport Guard from \"./Guard\";\nimport Node from \"../../nodes/Node\";\nimport GuardUnsatisifedException from \"./GuardUnsatisifedException\";\n\nexport type GuardPathPart = {\n node: Node;\n guards: Guard[];\n};\n\n/**\n * Represents a path of node guards along a root-to-leaf tree path.\n */\nexport default class GuardPath {\n /**\n * @param nodes An array of objects defining a node instance -> guard link, ordered by node depth.\n */\n constructor(private nodes: GuardPathPart[]) {}\n\n /**\n * Evaluate guard conditions for all guards in the tree path, moving outwards from the root.\n * @param agent The agent, required for guard evaluation.\n * @returns An evaluation results object.\n */\n evaluate = (agent: Agent) => {\n // We need to evaluate guard conditions for nodes up the tree, moving outwards from the root.\n for (const details of this.nodes) {\n // There can be multiple guards per node.\n for (const guard of details.guards) {\n // Check whether the guard condition passes, and throw an exception if not.\n if (!guard.isSatisfied(agent)) {\n throw new GuardUnsatisifedException(details.node);\n }\n }\n }\n };\n}\n", "/**\n * Enumeration of node state types.\n */\nexport enum State {\n READY = \"mistreevous.ready\",\n RUNNING = \"mistreevous.running\",\n SUCCEEDED = \"mistreevous.succeeded\",\n FAILED = \"mistreevous.failed\"\n}\n\nexport { State as default };\n\nexport type CompleteState = State.SUCCEEDED | State.FAILED;\nexport type AnyState = State.READY | State.RUNNING | CompleteState;\n", "import { Agent } from \"../Agent\";\nimport Attribute from \"../attributes/Attribute\";\nimport Entry from \"../attributes/callbacks/Entry\";\nimport Exit from \"../attributes/callbacks/Exit\";\nimport Step from \"../attributes/callbacks/Step\";\nimport Guard from \"../attributes/guards/Guard\";\nimport GuardPath from \"../attributes/guards/GuardPath\";\nimport GuardUnsatisifedException from \"../attributes/guards/GuardUnsatisifedException\";\nimport { BehaviourTreeOptions } from \"../BehaviourTreeOptions\";\nimport { AnyArgument } from \"../RootAstNodesBuilder\";\nimport State, { AnyState } from \"../State\";\nimport Leaf from \"./leaf/Leaf\";\n\n/**\n * A base node.\n */\nexport default abstract class Node {\n /**\n * The node uid.\n */\n private readonly uid: string = createNodeUid();\n /**\n * The node state.\n */\n private state: AnyState = State.READY;\n /**\n * The guard path to evaluate as part of a node update.\n */\n private guardPath: GuardPath | undefined;\n\n /**\n * @param type The node type.\n * @param attributes The node attributes.\n * @param args The node argument definitions.\n */\n constructor(private type: string, private attributes: Attribute[], private args: AnyArgument[]) {}\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected abstract onUpdate(agent: Agent, options: BehaviourTreeOptions): void;\n\n /**\n * Gets the name of the node.\n */\n public abstract getName(): string;\n\n /**\n * Gets whether this node is a leaf node.\n */\n public abstract isLeafNode: () => this is Leaf;\n\n /**\n * Gets/Sets the state of the node.\n */\n getState = (): AnyState => this.state;\n setState = (value: AnyState): void => {\n this.state = value;\n };\n\n /**\n * Gets the unique id of the node.\n */\n getUid = () => this.uid;\n\n /**\n * Gets the type of the node.\n */\n getType = () => this.type;\n\n /**\n * Gets the node attributes.\n */\n getAttributes = () => this.attributes;\n\n /**\n * Gets the node arguments.\n */\n getArguments = () => this.args;\n\n /**\n * Gets the node attribute with the specified type, or null if it does not exist.\n */\n getAttribute(type: \"entry\" | \"ENTRY\"): Entry;\n getAttribute(type: \"exit\" | \"EXIT\"): Exit;\n getAttribute(type: \"step\" | \"STEP\"): Step;\n getAttribute(type: string): Attribute {\n return (\n this.getAttributes().filter((decorator) => decorator.getType().toUpperCase() === type.toUpperCase())[0] ||\n null\n );\n }\n\n /**\n * Gets the node attributes.\n */\n getGuardAttributes = (): Guard[] => this.getAttributes().filter((decorator) => decorator.isGuard()) as Guard[];\n\n /**\n * Sets the guard path to evaluate as part of a node update.\n */\n setGuardPath = (value: GuardPath) => (this.guardPath = value);\n\n /**\n * Gets whether a guard path is assigned to this node.\n */\n hasGuardPath = () => !!this.guardPath;\n\n /**\n * Gets whether this node is in the specified state.\n * @param value The value to compare to the node state.\n */\n public is(value: AnyState): boolean {\n return this.state === value;\n }\n\n /**\n * Reset the state of the node.\n */\n public reset(): void {\n this.setState(State.READY);\n }\n\n /**\n * Abort the running of this node.\n * @param agent The agent.\n */\n public abort(agent: Agent): void {\n // There is nothing to do if this node is not in the running state.\n if (!this.is(State.RUNNING)) {\n return;\n }\n\n // Reset the state of this node.\n this.reset();\n\n this.getAttribute(\"exit\")?.callAgentFunction(agent, false, true);\n }\n\n /**\n * Update the node.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n * @returns The result of the update.\n */\n public update(agent: Agent, options: BehaviourTreeOptions): void {\n // If this node is already in a 'SUCCEEDED' or 'FAILED' state then there is nothing to do.\n if (this.is(State.SUCCEEDED) || this.is(State.FAILED)) {\n return;\n }\n\n try {\n // Evaluate all of the guard path conditions for the current tree path.\n this.guardPath!.evaluate(agent);\n\n // If this node is in the READY state then call the ENTRY for this node if it exists.\n if (this.is(State.READY)) {\n this.getAttribute(\"entry\")?.callAgentFunction(agent);\n }\n\n this.getAttribute(\"step\")?.callAgentFunction(agent);\n\n // Do the actual update.\n this.onUpdate(agent, options);\n\n // If this node is now in a 'SUCCEEDED' or 'FAILED' state then call the EXIT for this node if it exists.\n if (this.is(State.SUCCEEDED) || this.is(State.FAILED)) {\n this.getAttribute(\"exit\")?.callAgentFunction(agent, this.is(State.SUCCEEDED), false);\n }\n } catch (error) {\n // If the error is a GuardUnsatisfiedException then we need to determine if this node is the source.\n if (error instanceof GuardUnsatisifedException && error.isSourceNode(this)) {\n // Abort the current node.\n this.abort(agent);\n\n // Any node that is the source of an abort will be a failed node.\n this.setState(State.FAILED);\n } else {\n throw error;\n }\n }\n }\n}\n\n/**\n * Create a randomly generated node uid.\n * @returns A randomly generated node uid.\n */\nfunction createNodeUid(): string {\n var S4 = function () {\n return (((1 + Math.random()) * 0x10000) | 0).toString(16).substring(1);\n };\n return S4() + S4() + \"-\" + S4() + \"-\" + S4() + \"-\" + S4() + \"-\" + S4() + S4() + S4();\n}\n", "import Node from \"../Node\";\n\n/**\n * A leaf node.\n */\nexport default abstract class Leaf extends Node {\n /**\n * Gets whether this node is a leaf node.\n */\n isLeafNode = () => true;\n}\n", "import { ActionResult, Agent, ExitFunctionArg, FunctionArg, GlobalFunction } from \"./Agent\";\nimport { AnyArgument, RootAstNode } from \"./RootAstNodesBuilder\";\n\n// Exit callbacks receive their own special type of argument.\n// There's probably stricter ways to represent this but it feels overly complex right now.\ntype ExitResultArg = { value: ExitFunctionArg };\nexport type AnyExitArgument = AnyArgument | ExitResultArg;\n\nexport type InvokerFunction = (args: AnyExitArgument[]) => ActionResult;\n\n/**\n * A singleton used to store and lookup registered functions and subtrees.\n */\nexport default class Lookup {\n /**\n * The object holding any registered functions keyed on function name.\n */\n private static functionTable: { [key: string]: GlobalFunction } = {};\n /**\n * The object holding any registered sub-trees keyed on tree name.\n */\n private static subtreeTable: { [key: string]: RootAstNode } = {};\n\n /**\n * Gets the function with the specified name.\n * @param name The name of the function.\n * @returns The function with the specified name.\n */\n public static getFunc(name: string): GlobalFunction {\n return this.functionTable[name];\n }\n\n /**\n * Sets the function with the specified name for later lookup.\n * @param name The name of the function.\n * @param func The function.\n */\n public static setFunc(name: string, func: GlobalFunction): void {\n this.functionTable[name] = func;\n }\n\n /**\n * Gets the function invoker for the specified agent and function name.\n * If a function with the specified name exists on the agent object then it will\n * be returned, otherwise we will then check the registered functions for a match.\n * @param agent The agent instance that this behaviour tree is modelling behaviour for.\n * @param name The function name.\n * @returns The function invoker for the specified agent and function name.\n */\n static getFuncInvoker(agent: Agent, name: string): InvokerFunction | null {\n // Check whether the agent contains the specified function.\n const foundOnAgent = agent[name];\n if (foundOnAgent && typeof foundOnAgent === \"function\") {\n return (args: AnyExitArgument[]): boolean | ActionResult =>\n foundOnAgent.apply(\n agent,\n args.map((arg) => arg.value)\n );\n }\n\n // The agent does not contain the specified function but it may have been registered at some point.\n if (this.functionTable[name] && typeof this.functionTable[name] === \"function\") {\n return (args: AnyExitArgument[]) => this.functionTable[name](agent, ...args.map((arg) => arg.value));\n }\n\n // We have no function to invoke.\n return null;\n }\n\n /**\n * Gets the subtree with the specified name.\n * @param name The name of the subtree.\n * @returns The subtree with the specified name.\n */\n static getSubtree(name: string): RootAstNode {\n return this.subtreeTable[name];\n }\n\n /**\n * Sets the subtree with the specified name for later lookup.\n * @param name The name of the subtree.\n * @param subtree The subtree.\n */\n static setSubtree(name: string, subtree: RootAstNode) {\n this.subtreeTable[name] = subtree;\n }\n\n /**\n * Removes the registered function or subtree with the specified name.\n * @param name The name of the registered function or subtree.\n */\n static remove(name: string) {\n delete this.functionTable[name];\n delete this.subtreeTable[name];\n }\n\n /**\n * Remove all registered functions and subtrees.\n */\n static empty() {\n this.functionTable = {};\n this.subtreeTable = {};\n }\n}\n", "import Leaf from \"./Leaf\";\nimport State, { CompleteState } from \"../../State\";\nimport Lookup from \"../../Lookup\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { AnyArgument } from \"../../RootAstNodesBuilder\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * An Action leaf node.\n * This represents an immediate or ongoing state of behaviour.\n */\nexport default class Action extends Leaf {\n /**\n * @param attributes The node attributes.\n * @param actionName The action name.\n * @param actionArguments The array of action argument definitions.\n */\n constructor(attributes: Attribute[], private actionName: string, private actionArguments: AnyArgument[]) {\n super(\"action\", attributes, actionArguments);\n }\n\n /**\n * Whether there is a pending update promise.\n */\n private isUsingUpdatePromise = false;\n\n /**\n * The finished state result of an update promise.\n */\n private updatePromiseStateResult: CompleteState | null = null;\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // If the result of this action depends on an update promise then there is nothing to do until\n // it resolves, unless there has been a value set as a result of the update promise resolving.\n if (this.isUsingUpdatePromise) {\n // Check whether the update promise has resolved with a state value.\n if (this.updatePromiseStateResult) {\n // Set the state of this node to match the state returned by the promise.\n this.setState(this.updatePromiseStateResult);\n }\n\n return;\n }\n\n // Attempt to get the invoker for the action function.\n const actionFuncInvoker = Lookup.getFuncInvoker(agent, this.actionName);\n\n // The action function should be defined.\n if (actionFuncInvoker === null) {\n throw new Error(\n `cannot update action node as the action '${this.actionName}' function is not defined on the agent and has not been registered`\n );\n }\n\n // Call the action function, the result of which may be:\n // - The finished state of this action node.\n // - A promise to return a finished node state.\n // - Undefined if the node should remain in the running state.\n const updateResult = actionFuncInvoker(this.actionArguments) as CompleteState | Promise;\n\n if (updateResult instanceof Promise) {\n updateResult.then(\n (result) => {\n // If 'isUpdatePromisePending' is null then the promise was cleared as it was resolving, probably via an abort of reset.\n if (!this.isUsingUpdatePromise) {\n return;\n }\n\n // Check to make sure the result is a valid finished state.\n if (result !== State.SUCCEEDED && result !== State.FAILED) {\n throw new Error(\n \"action node promise resolved with an invalid value, expected a State.SUCCEEDED or State.FAILED value to be returned\"\n );\n }\n\n // Set pending update promise state result to be processed on next update.\n this.updatePromiseStateResult = result;\n },\n (reason) => {\n // If 'isUpdatePromisePending' is null then the promise was cleared as it was resolving, probably via an abort of reset.\n if (!this.isUsingUpdatePromise) {\n return;\n }\n\n // Just throw whatever was returned as the rejection argument.\n throw new Error(reason);\n }\n );\n\n // This node will be in the 'RUNNING' state until the update promise resolves.\n this.setState(State.RUNNING);\n\n // We are now waiting for the promise returned by the use to resolve before we know what state this node is in.\n this.isUsingUpdatePromise = true;\n } else {\n // Validate the returned value.\n this.validateUpdateResult(updateResult);\n\n // Set the state of this node, this may be undefined, which just means that the node is still in the 'RUNNING' state.\n this.setState(updateResult || State.RUNNING);\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => this.actionName;\n\n /**\n * Reset the state of the node.\n */\n reset = () => {\n // Reset the state of this node.\n this.setState(State.READY);\n\n // There is no longer an update promise that we care about.\n this.isUsingUpdatePromise = false;\n this.updatePromiseStateResult = null;\n };\n\n /**\n * Validate the result of an update function call.\n * @param result The result of an update function call.\n */\n private validateUpdateResult = (result: CompleteState | boolean) => {\n switch (result) {\n case State.SUCCEEDED:\n case State.FAILED:\n case undefined:\n return;\n default:\n throw new Error(\n `action '${this.actionName}' 'onUpdate' returned an invalid response, expected an optional State.SUCCEEDED or State.FAILED value to be returned`\n );\n }\n };\n}\n", "import Leaf from \"./Leaf\";\nimport State from \"../../State\";\nimport Lookup from \"../../Lookup\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { AnyArgument } from \"../../RootAstNodesBuilder\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A Condition leaf node.\n * This will succeed or fail immediately based on an agent predicate, without moving to the 'RUNNING' state.\n */\nexport default class Condition extends Leaf {\n /**\n * @param attributes The node attributes.\n * @param conditionName The name of the condition function.\n * @param conditionArguments The array of condition argument definitions.\n */\n constructor(attributes: Attribute[], private conditionName: string, private conditionArguments: AnyArgument[]) {\n super(\"condition\", attributes, conditionArguments);\n }\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // Attempt to get the invoker for the condition function.\n const conditionFuncInvoker = Lookup.getFuncInvoker(agent, this.conditionName);\n\n // The condition function should be defined.\n if (conditionFuncInvoker === null) {\n throw new Error(\n `cannot update condition node as the condition '${this.conditionName}' function is not defined on the agent and has not been registered`\n );\n }\n\n // Call the condition function to determine the state of this node.\n this.setState(!!conditionFuncInvoker(this.conditionArguments) ? State.SUCCEEDED : State.FAILED);\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => this.conditionName;\n}\n", "import Leaf from \"./Leaf\";\nimport State from \"../../State\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { Agent } from \"../../Agent\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A WAIT node.\n * The state of this node will change to SUCCEEDED after a duration of time\n */\nexport default class Wait extends Leaf {\n /**\n * @param attributes The node attributes.\n * @param duration The duration that this node will wait to succeed in milliseconds, or the earliest if longestDuration is defined.\n * @param longestDuration The longest possible duration in milliseconds that this node will wait to succeed.\n */\n constructor(attributes: Attribute[], private duration: number, private longestDuration: number) {\n super(\"wait\", attributes, []);\n }\n\n /**\n * The time in milliseconds at which this node was first updated.\n */\n private initialUpdateTime: number = 0;\n\n /**\n * The total duration in milliseconds that this node will be waiting for.\n */\n private totalDuration: number = 0;\n\n /**\n * The duration in milliseconds that this node has been waiting for.\n */\n private waitedDuration: number = 0;\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // If this node is in the READY state then we need to set the initial update time.\n if (this.is(State.READY)) {\n // Set the initial update time.\n this.initialUpdateTime = new Date().getTime();\n\n // Set the initial waited duration.\n this.waitedDuration = 0;\n\n // If a longestDuration value was defined then we will be randomly picking a duration between the\n // shortest and longest duration. If it was not defined, then we will be just using the duration.\n this.totalDuration = this.longestDuration\n ? Math.floor(Math.random() * (this.longestDuration - this.duration + 1) + this.duration)\n : this.duration;\n\n // The node is now running until we finish waiting.\n this.setState(State.RUNNING);\n }\n\n // If we have a 'getDeltaTime' function defined as part of our options then we will use it to figure out how long we have waited for.\n if (typeof options.getDeltaTime === \"function\") {\n // Get the delta time.\n const deltaTime = options.getDeltaTime();\n\n // Our delta time must be a valid number and cannot be NaN.\n if (typeof deltaTime !== \"number\" || isNaN(deltaTime)) {\n throw new Error(\"The delta time must be a valid number and not NaN.\");\n }\n\n // Update the amount of time that this node has been waiting for based on the delta time.\n this.waitedDuration += deltaTime * 1000;\n } else {\n // We are not using a delta time, so we will just work out hom much time has passed since the first update.\n this.waitedDuration = new Date().getTime() - this.initialUpdateTime;\n }\n\n // Have we waited long enough?\n if (this.waitedDuration >= this.totalDuration) {\n // We have finished waiting!\n this.setState(State.SUCCEEDED);\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () =>\n `WAIT ${this.longestDuration ? this.duration + \"ms-\" + this.longestDuration + \"ms\" : this.duration + \"ms\"}`;\n}\n", "import Node from \"../Node\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\n\n/**\n * A decorator node that wraps a single child node.\n */\nexport default abstract class Decorator extends Node {\n /**\n * @param type The node type.\n * @param attributes The node attributes.\n * @param child The child node.\n */\n constructor(type: string, attributes: Attribute[], protected child: Node) {\n super(type, attributes, []);\n }\n\n /**\n * Gets whether this node is a leaf node.\n */\n isLeafNode = () => false;\n\n /**\n * Gets the children of this node.\n */\n getChildren = () => [this.child];\n\n /**\n * Reset the state of the node.\n */\n reset = () => {\n // Reset the state of this node.\n this.setState(State.READY);\n\n // Reset the state of the child node.\n this.child.reset();\n };\n\n /**\n * Abort the running of this node.\n * @param agent The agent.\n */\n abort = (agent: Agent) => {\n // There is nothing to do if this node is not in the running state.\n if (!this.is(State.RUNNING)) {\n return;\n }\n\n // Abort the child node.\n this.child.abort(agent);\n\n // Reset the state of this node.\n this.reset();\n\n this.getAttribute(\"exit\")?.callAgentFunction(agent, false, true);\n };\n}\n", "import Node from \"../Node\";\nimport Decorator from \"./Decorator\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A Root node.\n * The root node will have a single child.\n */\nexport default class Root extends Decorator {\n /**\n * @param attributes The node attributes.\n * @param child The child node.\n */\n constructor(attributes: Attribute[], child: Node) {\n super(\"root\", attributes, child);\n }\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // If the child has never been updated or is running then we will need to update it now.\n if (this.child.getState() === State.READY || this.child.getState() === State.RUNNING) {\n // Update the child of this node.\n this.child.update(agent, options);\n }\n\n // The state of the root node is the state of its child.\n this.setState(this.child.getState());\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => \"ROOT\";\n}\n", "import Node from \"../Node\";\nimport Decorator from \"./Decorator\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A REPEAT node.\n * The node has a single child which can have:\n * -- A number of iterations for which to repeat the child node.\n * -- An infinite repeat loop if neither an iteration count or a condition function is defined.\n * The REPEAT node will stop and have a 'FAILED' state if its child is ever in a 'FAILED' state after an update.\n * The REPEAT node will attempt to move on to the next iteration if its child is ever in a 'SUCCEEDED' state.\n */\nexport default class Repeat extends Decorator {\n /**\n * @param attributes The node attributes.\n * @param iterations The number of iterations to repeat the child node, or the minimum number of iterations if maximumIterations is defined.\n * @param maximumIterations The maximum number of iterations to repeat the child node.\n * @param child The child node.\n */\n constructor(\n attributes: Attribute[],\n private iterations: number | null,\n private maximumIterations: number | null,\n child: Node\n ) {\n super(\"repeat\", attributes, child);\n }\n\n /**\n * The number of target iterations to make.\n */\n private targetIterationCount: number | null = null;\n\n /**\n * The current iteration count.\n */\n private currentIterationCount: number = 0;\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // If this node is in the READY state then we need to reset the child and the target iteration count.\n if (this.is(State.READY)) {\n // Reset the child node.\n this.child.reset();\n\n // Set the target iteration count.\n this.setTargetIterationCount();\n }\n\n // Do a check to see if we can iterate. If we can then this node will move into the 'RUNNING' state.\n // If we cannot iterate then we have hit our target iteration count, which means that the node has succeeded.\n if (this.canIterate()) {\n // This node is in the running state and can do its initial iteration.\n this.setState(State.RUNNING);\n\n // We may have already completed an iteration, meaning that the child node will be in the SUCCEEDED state.\n // If this is the case then we will have to reset the child node now.\n if (this.child.getState() === State.SUCCEEDED) {\n this.child.reset();\n }\n\n // Update the child of this node.\n this.child.update(agent, options);\n\n // If the child moved into the FAILED state when we updated it then there is nothing left to do and this node has also failed.\n // If it has moved into the SUCCEEDED state then we have completed the current iteration.\n if (this.child.getState() === State.FAILED) {\n // The child has failed, meaning that this node has failed.\n this.setState(State.FAILED);\n\n return;\n } else if (this.child.getState() === State.SUCCEEDED) {\n // We have completed an iteration.\n this.currentIterationCount += 1;\n }\n } else {\n // This node is in the 'SUCCEEDED' state as we cannot iterate any more.\n this.setState(State.SUCCEEDED);\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => {\n if (this.iterations !== null) {\n return `REPEAT ${\n this.maximumIterations ? this.iterations + \"x-\" + this.maximumIterations + \"x\" : this.iterations + \"x\"\n }`;\n }\n\n // Return the default repeat node name.\n return \"REPEAT\";\n };\n\n /**\n * Reset the state of the node.\n */\n reset = () => {\n // Reset the state of this node.\n this.setState(State.READY);\n\n // Reset the current iteration count.\n this.currentIterationCount = 0;\n\n // Reset the child node.\n this.child.reset();\n };\n\n /**\n * Gets whether an iteration can be made.\n * @returns Whether an iteration can be made.\n */\n private canIterate = () => {\n if (this.targetIterationCount !== null) {\n // We can iterate as long as we have not reached our target iteration count.\n return this.currentIterationCount < this.targetIterationCount;\n }\n\n // If neither an iteration count or a condition function were defined then we can iterate indefinitely.\n return true;\n };\n\n /**\n * Sets the target iteration count.\n */\n private setTargetIterationCount = () => {\n // Are we dealing with a finite number of iterations?\n if (typeof this.iterations === \"number\") {\n // If we have maximumIterations defined then we will want a random iteration count bounded by iterations and maximumIterations.\n this.targetIterationCount =\n typeof this.maximumIterations === \"number\"\n ? Math.floor(Math.random() * (this.maximumIterations - this.iterations + 1) + this.iterations)\n : this.iterations;\n } else {\n this.targetIterationCount = null;\n }\n };\n}\n", "import Node from \"../Node\";\nimport Decorator from \"./Decorator\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A RETRY node.\n * The node has a single child which can have:\n * -- A number of iterations for which to repeat the child node.\n * -- An infinite repeat loop if neither an iteration count or a condition function is defined.\n * The RETRY node will stop and have a 'SUCCEEDED' state if its child is ever in a 'SUCCEEDED' state after an update.\n * The RETRY node will attempt to move on to the next iteration if its child is ever in a 'FAILED' state.\n */\nexport default class Retry extends Decorator {\n /**\n * @param attributes The node attributes.\n * @param iterations The number of iterations to repeat the child node, or the minimum number of iterations if maximumIterations is defined.\n * @param maximumIterations The maximum number of iterations to repeat the child node.\n * @param child The child node.\n */\n constructor(\n attributes: Attribute[],\n private iterations: number | null,\n private maximumIterations: number | null,\n child: Node\n ) {\n super(\"retry\", attributes, child);\n }\n\n /**\n * The number of target iterations to make.\n */\n private targetIterationCount: number | null = null;\n\n /**\n * The current iteration count.\n */\n private currentIterationCount: number = 0;\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // If this node is in the READY state then we need to reset the child and the target iteration count.\n if (this.is(State.READY)) {\n // Reset the child node.\n this.child.reset();\n\n // Set the target iteration count.\n this.setTargetIterationCount();\n }\n\n // Do a check to see if we can iterate. If we can then this node will move into the 'RUNNING' state.\n // If we cannot iterate then we have hit our target iteration count, which means that the node has succeeded.\n if (this.canIterate()) {\n // This node is in the running state and can do its initial iteration.\n this.setState(State.RUNNING);\n\n // We may have already completed an iteration, meaning that the child node will be in the FAILED state.\n // If this is the case then we will have to reset the child node now.\n if (this.child.getState() === State.FAILED) {\n this.child.reset();\n }\n\n // Update the child of this node.\n this.child.update(agent, options);\n\n // If the child moved into the SUCCEEDED state when we updated it then there is nothing left to do and this node has also succeeded.\n // If it has moved into the FAILED state then we have completed the current iteration.\n if (this.child.getState() === State.SUCCEEDED) {\n // The child has succeeded, meaning that this node has succeeded.\n this.setState(State.SUCCEEDED);\n\n return;\n } else if (this.child.getState() === State.FAILED) {\n // We have completed an iteration.\n this.currentIterationCount += 1;\n }\n } else {\n // This node is in the 'FAILED' state as we cannot iterate any more.\n this.setState(State.FAILED);\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => {\n if (this.iterations !== null) {\n return `RETRY ${\n this.maximumIterations ? this.iterations + \"x-\" + this.maximumIterations + \"x\" : this.iterations + \"x\"\n }`;\n }\n\n // Return the default retry node name.\n return \"RETRY\";\n };\n\n /**\n * Reset the state of the node.\n */\n reset = () => {\n // Reset the state of this node.\n this.setState(State.READY);\n\n // Reset the current iteration count.\n this.currentIterationCount = 0;\n\n // Reset the child node.\n this.child.reset();\n };\n\n /**\n * Gets whether an iteration can be made.\n * @returns Whether an iteration can be made.\n */\n canIterate = () => {\n if (this.targetIterationCount !== null) {\n // We can iterate as long as we have not reached our target iteration count.\n return this.currentIterationCount < this.targetIterationCount;\n }\n\n // If neither an iteration count or a condition function were defined then we can iterate indefinitely.\n return true;\n };\n\n /**\n * Sets the target iteration count.\n */\n setTargetIterationCount = () => {\n // Are we dealing with a finite number of iterations?\n if (typeof this.iterations === \"number\") {\n // If we have maximumIterations defined then we will want a random iteration count bounded by iterations and maximumIterations.\n this.targetIterationCount =\n typeof this.maximumIterations === \"number\"\n ? Math.floor(Math.random() * (this.maximumIterations - this.iterations + 1) + this.iterations)\n : this.iterations;\n } else {\n this.targetIterationCount = null;\n }\n };\n}\n", "import Decorator from \"./Decorator\";\nimport State from \"../../State\";\nimport Node from \"../Node\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A Flip node.\n * This node wraps a single child and will flip the state of the child state.\n */\nexport default class Flip extends Decorator {\n /**\n * @param attributes The node attributes.\n * @param child The child node.\n */\n constructor(attributes: Attribute[], child: Node) {\n super(\"flip\", attributes, child);\n }\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // If the child has never been updated or is running then we will need to update it now.\n if (this.child.getState() === State.READY || this.child.getState() === State.RUNNING) {\n this.child.update(agent, options);\n }\n\n // The state of this node will depend in the state of its child.\n switch (this.child.getState()) {\n case State.RUNNING:\n this.setState(State.RUNNING);\n break;\n\n case State.SUCCEEDED:\n this.setState(State.FAILED);\n break;\n\n case State.FAILED:\n this.setState(State.SUCCEEDED);\n break;\n\n default:\n this.setState(State.READY);\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => \"FLIP\";\n}\n", "import Node from \"../Node\";\nimport Decorator from \"./Decorator\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A Succeed node.\n * This node wraps a single child and will always move to the 'SUCCEEDED' state when the child moves to a 'SUCCEEDED' or 'FAILED' state.\n */\nexport default class Succeed extends Decorator {\n /**\n * @param attributes The node attributes.\n * @param child The child node.\n */\n constructor(attributes: Attribute[], child: Node) {\n super(\"succeed\", attributes, child);\n }\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // If the child has never been updated or is running then we will need to update it now.\n if (this.child.getState() === State.READY || this.child.getState() === State.RUNNING) {\n this.child.update(agent, options);\n }\n\n // The state of this node will depend in the state of its child.\n switch (this.child.getState()) {\n case State.RUNNING:\n this.setState(State.RUNNING);\n break;\n\n case State.SUCCEEDED:\n case State.FAILED:\n this.setState(State.SUCCEEDED);\n break;\n\n default:\n this.setState(State.READY);\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => \"SUCCEED\";\n}\n", "import Node from \"../Node\";\nimport Decorator from \"./Decorator\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A Fail node.\n * This node wraps a single child and will always move to the 'FAILED' state when the child moves to a 'SUCCEEDED' or 'FAILED' state.\n */\nexport default class Fail extends Decorator {\n /**\n * @param attributes The node attributes.\n * @param child The child node.\n */\n constructor(attributes: Attribute[], child: Node) {\n super(\"fail\", attributes, child);\n }\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // If the child has never been updated or is running then we will need to update it now.\n if (this.child.getState() === State.READY || this.child.getState() === State.RUNNING) {\n this.child.update(agent, options);\n }\n\n // The state of this node will depend in the state of its child.\n switch (this.child.getState()) {\n case State.RUNNING:\n this.setState(State.RUNNING);\n break;\n\n case State.SUCCEEDED:\n case State.FAILED:\n this.setState(State.FAILED);\n break;\n\n default:\n this.setState(State.READY);\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => \"FAIL\";\n}\n", "import createLotto from \"lotto-draw\";\n\nimport Node from \"../Node\";\nimport Composite from \"./Composite\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A LOTTO node.\n * A winning child is picked on the initial update of this node, based on ticket weighting.\n * The state of this node will match the state of the winning child.\n */\nexport default class Lotto extends Composite {\n /**\n * @param attributes The node attributes.\n * @param tickets The child node tickets.\n * @param children The child nodes.\n */\n constructor(attributes: Attribute[], private tickets: number[], children: Node[]) {\n super(\"lotto\", attributes, children);\n }\n\n /**\n * The child node selected to be the active one.\n */\n private selectedChild: Node | undefined;\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // If this node is in the READY state then we need to pick a winning child node.\n if (this.is(State.READY)) {\n // Create a lotto draw with which to randomly pick a child node to become the active one.\n const lottoDraw = createLotto({\n // Hook up the optional 'random' behaviour tree function option to the one used by 'lotto-draw'.\n random: options.random,\n // Pass in each child node as a participant in the lotto draw with their respective ticket count.\n participants: this.children.map((child, index) => [child, this.tickets[index] || 1])\n });\n\n // Randomly pick a child based on ticket weighting, this will become the active child for this composite node.\n this.selectedChild = lottoDraw.draw() || undefined;\n }\n\n // If something went wrong and we don't have an active child then we should throw an error.\n if (!this.selectedChild) {\n throw new Error(\"failed to update lotto node as it has no active child\");\n }\n\n // If the selected child has never been updated or is running then we will need to update it now.\n if (this.selectedChild.getState() === State.READY || this.selectedChild.getState() === State.RUNNING) {\n this.selectedChild.update(agent, options);\n }\n\n // The state of the lotto node is the state of its selected child.\n this.setState(this.selectedChild.getState());\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => (this.tickets.length ? `LOTTO [${this.tickets.join(\",\")}]` : \"LOTTO\");\n}\n", "import Node from \"../Node\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\n\n/**\n * A composite node that wraps child nodes.\n */\nexport default abstract class Composite extends Node {\n /**\n * @param type The node type.\n * @param attributes The node attributes.\n * @param children The child nodes.\n */\n constructor(type: string, attributes: Attribute[], protected children: Node[]) {\n super(type, attributes, []);\n }\n\n /**\n * Gets whether this node is a leaf node.\n */\n isLeafNode = () => false;\n\n /**\n * Gets the children of this node.\n */\n getChildren = () => this.children;\n\n /**\n * Reset the state of the node.\n */\n reset = () => {\n // Reset the state of this node.\n this.setState(State.READY);\n\n // Reset the state of any child nodes.\n this.getChildren().forEach((child) => child.reset());\n };\n\n /**\n * Abort the running of this node.\n * @param agent The agent.\n */\n abort = (agent: Agent) => {\n // There is nothing to do if this node is not in the running state.\n if (!this.is(State.RUNNING)) {\n return;\n }\n\n // Abort any child nodes.\n this.getChildren().forEach((child) => child.abort(agent));\n\n // Reset the state of this node.\n this.reset();\n\n this.getAttribute(\"exit\")?.callAgentFunction(agent, false, true);\n };\n}\n", "import Composite from \"./Composite\";\nimport Node from \"../Node\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A SELECTOR node.\n * The child nodes are executed in sequence until one succeeds or all fail.\n */\nexport default class Selector extends Composite {\n /**\n * @param attributes The node attributes.\n * @param children The child nodes.\n */\n constructor(attributes: Attribute[], protected children: Node[]) {\n super(\"selector\", attributes, children);\n }\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // Iterate over all of the children of this node.\n for (const child of this.children) {\n // If the child has never been updated or is running then we will need to update it now.\n if (child.getState() === State.READY || child.getState() === State.RUNNING) {\n // Update the child of this node.\n child.update(agent, options);\n }\n\n // If the current child has a state of 'SUCCEEDED' then this node is also a 'SUCCEEDED' node.\n if (child.getState() === State.SUCCEEDED) {\n // This node is a 'SUCCEEDED' node.\n this.setState(State.SUCCEEDED);\n\n // There is no need to check the rest of the selector nodes.\n return;\n }\n\n // If the current child has a state of 'FAILED' then we should move on to the next child.\n if (child.getState() === State.FAILED) {\n // Find out if the current child is the last one in the selector.\n // If it is then this sequence node has also failed.\n if (this.children.indexOf(child) === this.children.length - 1) {\n // This node is a 'FAILED' node.\n this.setState(State.FAILED);\n\n // There is no need to check the rest of the selector as we have completed it.\n return;\n } else {\n // The child node failed, try the next one.\n continue;\n }\n }\n\n // The node should be in the 'RUNNING' state.\n if (child.getState() === State.RUNNING) {\n // This node is a 'RUNNING' node.\n this.setState(State.RUNNING);\n\n // There is no need to check the rest of the selector as the current child is still running.\n return;\n }\n\n // The child node was not in an expected state.\n throw new Error(\"child node was not in an expected state.\");\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => \"SELECTOR\";\n}\n", "import Composite from \"./Composite\";\nimport Node from \"../Node\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A SEQUENCE node.\n * The child nodes are executed in sequence until one fails or all succeed.\n */\nexport default class Sequence extends Composite {\n /**\n * @param attributes The node attributes.\n * @param children The child nodes.\n */\n constructor(attributes: Attribute[], protected children: Node[]) {\n super(\"sequence\", attributes, children);\n }\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // Iterate over all of the children of this node.\n for (const child of this.children) {\n // If the child has never been updated or is running then we will need to update it now.\n if (child.getState() === State.READY || child.getState() === State.RUNNING) {\n // Update the child of this node.\n child.update(agent, options);\n }\n\n // If the current child has a state of 'SUCCEEDED' then we should move on to the next child.\n if (child.getState() === State.SUCCEEDED) {\n // Find out if the current child is the last one in the sequence.\n // If it is then this sequence node has also succeeded.\n if (this.children.indexOf(child) === this.children.length - 1) {\n // This node is a 'SUCCEEDED' node.\n this.setState(State.SUCCEEDED);\n\n // There is no need to check the rest of the sequence as we have completed it.\n return;\n } else {\n // The child node succeeded, but we have not finished the sequence yet.\n continue;\n }\n }\n\n // If the current child has a state of 'FAILED' then this node is also a 'FAILED' node.\n if (child.getState() === State.FAILED) {\n // This node is a 'FAILED' node.\n this.setState(State.FAILED);\n\n // There is no need to check the rest of the sequence.\n return;\n }\n\n // The node should be in the 'RUNNING' state.\n if (child.getState() === State.RUNNING) {\n // This node is a 'RUNNING' node.\n this.setState(State.RUNNING);\n\n // There is no need to check the rest of the sequence as the current child is still running.\n return;\n }\n\n // The child node was not in an expected state.\n throw new Error(\"child node was not in an expected state.\");\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => \"SEQUENCE\";\n}\n", "import Composite from \"./Composite\";\nimport State from \"../../State\";\nimport Node from \"../Node\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A PARALLEL node.\n * The child nodes are executed concurrently until one fails or all succeed.\n */\nexport default class Parallel extends Composite {\n /**\n * @param attributes The node attributes.\n * @param children The child nodes.\n */\n constructor(attributes: Attribute[], children: Node[]) {\n super(\"parallel\", attributes, children);\n }\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // Keep a count of the number of succeeded child nodes.\n let succeededCount = 0;\n\n let hasChildFailed = false;\n\n // Iterate over all of the children of this node.\n for (const child of this.children) {\n // If the child has never been updated or is running then we will need to update it now.\n if (child.getState() === State.READY || child.getState() === State.RUNNING) {\n // Update the child of this node.\n child.update(agent, options);\n }\n\n // If the current child has a state of 'SUCCEEDED' then we should move on to the next child.\n if (child.getState() === State.SUCCEEDED) {\n // The child node has succeeded, keep track of this to determine if all children have.\n succeededCount++;\n\n // The child node succeeded, but we have not finished checking every child node yet.\n continue;\n }\n\n // If the current child has a state of 'FAILED' then this node is also a 'FAILED' node.\n if (child.getState() === State.FAILED) {\n hasChildFailed = true;\n\n // There is no need to check the rest of the children.\n break;\n }\n\n // The node should be in the 'RUNNING' state.\n if (child.getState() !== State.RUNNING) {\n // The child node was not in an expected state.\n throw new Error(\"child node was not in an expected state.\");\n }\n }\n\n if (hasChildFailed) {\n // This node is a 'FAILED' node.\n this.setState(State.FAILED);\n\n // Abort every running child.\n for (const child of this.children) {\n if (child.getState() === State.RUNNING) {\n child.abort(agent);\n }\n }\n } else {\n // If all children have succeeded then this node has also succeeded, otherwise it is still running.\n this.setState(succeededCount === this.children.length ? State.SUCCEEDED : State.RUNNING);\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => \"PARALLEL\";\n}\n", "import { AnyArgument } from \"../RootAstNodesBuilder\";\nimport Guard from \"./guards/Guard\";\n\nexport type AttributeDetails = {\n /** The attribute type. */\n type: string;\n\n /** The attribute arguments. */\n args: AnyArgument[];\n};\n\n/**\n * A base node attribute.\n */\nexport default abstract class Attribute {\n /**\n * @param type The node attribute type.\n * @param args The array of attribute argument definitions.\n */\n constructor(protected type: string, protected args: AnyArgument[]) {}\n\n /**\n * Gets the type of the attribute.\n */\n getType = () => this.type;\n\n /**\n * Gets the array of attribute argument definitions.\n */\n getArguments = () => this.args;\n\n /**\n * Gets the attribute details.\n */\n abstract getDetails(): TAttributeDetails;\n\n /**\n * Gets whether this attribute is a guard.\n */\n abstract isGuard: () => this is Guard;\n}\n", "import { Agent } from \"../../Agent\";\nimport { AnyArgument } from \"../../RootAstNodesBuilder\";\nimport Attribute, { AttributeDetails } from \"../Attribute\";\n\nexport type GuardAttributeDetails = {\n /** The name of the condition function that determines whether the guard is satisfied. */\n condition: string;\n} & AttributeDetails;\n\n/**\n * A base node guard attribute.\n */\nexport default abstract class Guard extends Attribute {\n /**\n * @param type The node attribute type.\n * @param args The array of decorator argument definitions.\n * @param condition The name of the condition function that determines whether the guard is satisfied.\n */\n constructor(type: string, args: AnyArgument[], private condition: string) {\n super(type, args);\n }\n\n /**\n * Gets the name of the condition function that determines whether the guard is satisfied.\n */\n getCondition = () => this.condition;\n\n /**\n * Gets whether this attribute is a guard.\n */\n isGuard = () => true;\n\n /**\n * Gets the attribute details.\n */\n getDetails(): GuardAttributeDetails {\n return {\n type: this.getType(),\n args: this.getArguments(),\n condition: this.getCondition()\n };\n }\n\n /**\n * Gets whether the guard is satisfied.\n * @param agent The agent.\n * @returns Whether the guard is satisfied.\n */\n abstract isSatisfied(agent: Agent): boolean;\n}\n", "import Guard from \"./Guard\";\nimport Lookup from \"../../Lookup\";\nimport { Agent } from \"../../Agent\";\nimport { AnyArgument } from \"../../RootAstNodesBuilder\";\n\n/**\n * A WHILE guard which is satisfied as long as the given condition remains true.\n */\nexport default class While extends Guard {\n /**\n * @param condition The name of the condition function that determines whether the guard is satisfied.\n * @param args The array of decorator argument definitions.\n */\n constructor(condition: string, args: AnyArgument[]) {\n super(\"while\", args, condition);\n }\n\n /**\n * Gets whether the guard is satisfied.\n * @param agent The agent.\n * @returns Whether the guard is satisfied.\n */\n isSatisfied = (agent: Agent) => {\n // Attempt to get the invoker for the condition function.\n const conditionFuncInvoker = Lookup.getFuncInvoker(agent, this.getCondition());\n\n // The condition function should be defined.\n if (conditionFuncInvoker === null) {\n throw new Error(\n `cannot evaluate node guard as the condition '${this.getCondition()}' function is not defined on the agent and has not been registered`\n );\n }\n\n // Call the condition function to determine whether this guard is satisfied.\n return !!conditionFuncInvoker(this.args);\n };\n}\n", "import Guard from \"./Guard\";\nimport Lookup from \"../../Lookup\";\nimport { Agent } from \"../../Agent\";\nimport { AnyArgument } from \"../../RootAstNodesBuilder\";\n\n/**\n * An UNTIL guard which is satisfied as long as the given condition remains false.\n */\nexport default class Until extends Guard {\n /**\n * @param condition The name of the condition function that determines whether the guard is satisfied.\n * @param args The array of decorator argument definitions.\n */\n constructor(condition: string, args: AnyArgument[]) {\n super(\"until\", args, condition);\n }\n\n /**\n * Gets whether the guard is satisfied.\n * @param agent The agent.\n * @returns Whether the guard is satisfied.\n */\n isSatisfied = (agent: Agent) => {\n // Attempt to get the invoker for the condition function.\n const conditionFuncInvoker = Lookup.getFuncInvoker(agent, this.getCondition());\n\n // The condition function should be defined.\n if (conditionFuncInvoker === null) {\n throw new Error(\n `cannot evaluate node guard as the condition '${this.getCondition()}' function is not defined on the agent and has not been registered`\n );\n }\n\n // Call the condition function to determine whether this guard is satisfied.\n return !!!conditionFuncInvoker(this.args);\n };\n}\n", "import { Agent } from \"../../Agent\";\nimport { AnyArgument } from \"../../RootAstNodesBuilder\";\nimport Attribute, { AttributeDetails } from \"../Attribute\";\n\nexport type CallbackAttributeDetails = {\n /** The name of the agent function that is called. */\n functionName: string;\n} & AttributeDetails;\n\n/**\n * A base node callback attribute.\n */\nexport default abstract class Callback extends Attribute {\n /**\n * @param type The node attribute type.\n * @param args The array of decorator argument definitions.\n * @param functionName The name of the agent function to call.\n */\n constructor(type: string, args: AnyArgument[], private functionName: string) {\n super(type, args);\n }\n\n /**\n * Gets the name of the agent function to call.\n */\n getFunctionName = () => this.functionName;\n\n /**\n * Gets whether this attribute is a guard.\n */\n isGuard = () => false;\n\n /**\n * Gets the attribute details.\n */\n getDetails(): CallbackAttributeDetails {\n return {\n type: this.getType(),\n args: this.getArguments(),\n functionName: this.getFunctionName()\n };\n }\n\n /**\n * Attempt to call the agent function that this callback refers to.\n * @param agent The agent.\n */\n abstract callAgentFunction: (agent: Agent, isSuccess: boolean, isAborted: boolean) => void;\n}\n", "import Callback from \"./Callback\";\nimport Lookup from \"../../Lookup\";\nimport { Agent } from \"../../Agent\";\nimport { AnyArgument } from \"../../RootAstNodesBuilder\";\n\n/**\n * An ENTRY callback which defines an agent function to call when the associated node is updated and moves out of running state.\n */\nexport default class Entry extends Callback {\n /**\n * @param functionName The name of the agent function to call.\n * @param args The array of callback argument definitions.\n */\n constructor(functionName: string, args: AnyArgument[]) {\n super(\"entry\", args, functionName);\n }\n\n /**\n * Attempt to call the agent function that this callback refers to.\n * @param agent The agent.\n */\n callAgentFunction = (agent: Agent) => {\n // Attempt to get the invoker for the callback function.\n const callbackFuncInvoker = Lookup.getFuncInvoker(agent, this.getFunctionName());\n\n // The callback function should be defined.\n if (callbackFuncInvoker === null) {\n throw new Error(\n `cannot call entry function '${this.getFunctionName()}' as is not defined on the agent and has not been registered`\n );\n }\n\n // Call the callback function.\n callbackFuncInvoker(this.args);\n };\n}\n", "import Callback from \"./Callback\";\nimport Lookup, { AnyExitArgument } from \"../../Lookup\";\nimport { Agent } from \"../../Agent\";\nimport { AnyArgument } from \"../../RootAstNodesBuilder\";\n\n/**\n * An EXIT callback which defines an agent function to call when the associated node is updated and moves to a finished state or is aborted.\n */\nexport default class Exit extends Callback {\n /**\n * @param functionName The name of the agent function to call.\n * @param args The array of callback argument definitions.\n */\n constructor(functionName: string, args: AnyArgument[]) {\n super(\"exit\", args, functionName);\n }\n\n /**\n * Attempt to call the agent function that this callback refers to.\n * @param agent The agent.\n * @param isSuccess Whether the decorated node was left with a success state.\n * @param isAborted Whether the decorated node was aborted.\n */\n callAgentFunction = (agent: Agent, isSuccess: boolean, isAborted: boolean) => {\n // Attempt to get the invoker for the callback function.\n const callbackFuncInvoker = Lookup.getFuncInvoker(agent, this.getFunctionName());\n\n // The callback function should be defined.\n if (callbackFuncInvoker === null) {\n throw new Error(\n `cannot call exit function '${this.getFunctionName()}' as is not defined on the agent and has not been registered`\n );\n }\n\n // Call the callback function\n callbackFuncInvoker([{ value: { succeeded: isSuccess, aborted: isAborted } }, ...this.args]);\n };\n}\n", "import Callback from \"./Callback\";\nimport Lookup from \"../../Lookup\";\nimport { Agent } from \"../../Agent\";\nimport { AnyArgument } from \"../../RootAstNodesBuilder\";\n\n/**\n * A STEP callback which defines an agent function to call when the associated node is updated.\n */\nexport default class Step extends Callback {\n /**\n * @param functionName The name of the agent function to call.\n * @param args The array of callback argument definitions.\n */\n constructor(functionName: string, args: AnyArgument[]) {\n super(\"step\", args, functionName);\n }\n\n /**\n * Attempt to call the agent function that this callback refers to.\n * @param agent The agent.\n */\n callAgentFunction = (agent: Agent) => {\n // Attempt to get the invoker for the callback function.\n const callbackFuncInvoker = Lookup.getFuncInvoker(agent, this.getFunctionName());\n\n // The callback function should be defined.\n if (callbackFuncInvoker === null) {\n throw new Error(\n `cannot call step function '${this.getFunctionName()}' as is not defined on the agent and has not been registered`\n );\n }\n\n // Call the callback function.\n callbackFuncInvoker(this.args);\n };\n}\n", "import Action from \"./nodes/leaf/Action\";\nimport Condition from \"./nodes/leaf/Condition\";\nimport Wait from \"./nodes/leaf/Wait\";\nimport Root from \"./nodes/decorator/Root\";\nimport Repeat from \"./nodes/decorator/Repeat\";\nimport Retry from \"./nodes/decorator/Retry\";\nimport Flip from \"./nodes/decorator/Flip\";\nimport Succeed from \"./nodes/decorator/Succeed\";\nimport Fail from \"./nodes/decorator/Fail\";\nimport Lotto from \"./nodes/composite/Lotto\";\nimport Selector from \"./nodes/composite/Selector\";\nimport Sequence from \"./nodes/composite/Sequence\";\nimport Parallel from \"./nodes/composite/Parallel\";\nimport Node from \"./nodes/Node\";\nimport While from \"./attributes/guards/While\";\nimport Until from \"./attributes/guards/Until\";\nimport Entry from \"./attributes/callbacks/Entry\";\nimport Exit from \"./attributes/callbacks/Exit\";\nimport Step from \"./attributes/callbacks/Step\";\nimport Callback from \"./attributes/callbacks/Callback\";\nimport Guard from \"./attributes/guards/Guard\";\nimport Attribute from \"./attributes/Attribute\";\nimport Composite from \"./nodes/composite/Composite\";\nimport Decorator from \"./nodes/decorator/Decorator\";\nimport Leaf from \"./nodes/leaf/Leaf\";\n\nexport type Argument = {\n value: T;\n type: string; // Used for validation.\n};\ntype NullArgument = Argument & {\n type: \"null\";\n};\ntype BooleanArgument = Argument & {\n type: \"boolean\";\n};\ntype NumberArgument = Argument & {\n type: \"number\";\n isInteger: boolean; // Used for validation.\n};\ntype StringPlaceholderArgument = Argument & {\n type: \"string\";\n};\ntype IdentifierArgument = Argument & {\n type: \"identifier\";\n};\nexport type AnyArgument =\n | NullArgument\n | BooleanArgument\n | NumberArgument\n | StringPlaceholderArgument\n | IdentifierArgument;\n\n/**\n * The node attribute factories.\n */\nconst AttributeFactories: {\n [key: string]: (functionName: string, attributeArguments: AnyArgument[]) => Callback | Guard;\n} = {\n WHILE: (condition: string, attributeArguments: AnyArgument[]) => new While(condition, attributeArguments),\n UNTIL: (condition: string, attributeArguments: AnyArgument[]) => new Until(condition, attributeArguments),\n ENTRY: (functionName: string, attributeArguments: AnyArgument[]) => new Entry(functionName, attributeArguments),\n EXIT: (functionName: string, attributeArguments: AnyArgument[]) => new Exit(functionName, attributeArguments),\n STEP: (functionName: string, attributeArguments: AnyArgument[]) => new Step(functionName, attributeArguments)\n};\n\ntype Validatable = {\n children?: AstNode[];\n validate: (depth: number) => void;\n};\n\ntype NodeInstanceCreator = (\n namedRootNodeProvider: (name: string) => RootAstNode,\n visitedBranches: string[]\n) => T;\n\nexport type AstNode = Validatable & {\n type: string;\n createNodeInstance: NodeInstanceCreator;\n};\n\nexport type LeafAstNode = AstNode & {\n type: \"action\" | \"condition\" | \"wait\";\n attributes: Attribute[];\n};\n\nexport type CompositeAstNode = AstNode & {\n type: \"lotto\" | \"parallel\" | \"selector\" | \"sequence\";\n attributes: Attribute[];\n children: AstNode[];\n};\n\nexport type DecoratorAstNode = AstNode & {\n type: \"fail\" | \"flip\" | \"repeat\" | \"retry\" | \"root\" | \"succeed\";\n attributes: Attribute[];\n children: AstNode[];\n};\n\nexport type BranchAstNode = AstNode & {\n type: \"branch\";\n branchName: \"\" | string;\n};\n\nexport type LottoAstNode = CompositeAstNode & {\n type: \"lotto\";\n tickets: number[];\n};\n\nexport type RootAstNode = DecoratorAstNode & {\n type: \"root\";\n name: null | string;\n};\n\nexport type IterableAstNode = DecoratorAstNode & {\n type: \"repeat\" | \"retry\";\n iterations: null | number;\n maximumIterations: null | number;\n};\n\nexport type ActionAstNode = LeafAstNode & {\n type: \"action\";\n actionName: string;\n actionArguments: AnyArgument[];\n};\n\nexport type ConditionAstNode = LeafAstNode & {\n type: \"condition\";\n conditionName: string;\n conditionArguments: AnyArgument[];\n};\n\nexport type WaitAstNode = LeafAstNode & {\n type: \"wait\";\n duration: number | null;\n longestDuration: number | null;\n};\n\nexport type AnyAstNode =\n | BranchAstNode\n | CompositeAstNode\n | LottoAstNode\n | DecoratorAstNode\n | RootAstNode\n | IterableAstNode\n | LeafAstNode\n | ActionAstNode\n | ConditionAstNode\n | WaitAstNode;\n\n/**\n * The AST node factories.\n */\nconst ASTNodeFactories = {\n ROOT: (): RootAstNode => ({\n type: \"root\",\n attributes: [],\n name: null,\n children: [],\n validate(depth: number) {\n // A root node cannot be the child of another node.\n if (depth > 1) {\n throw new Error(\"a root node cannot be the child of another node\");\n }\n\n // A root node must have a single child node.\n if (this.children.length !== 1) {\n throw new Error(\"a root node must have a single child\");\n }\n },\n createNodeInstance(namedRootNodeProvider, visitedBranches) {\n return new Root(\n this.attributes,\n this.children![0].createNodeInstance(namedRootNodeProvider, visitedBranches.slice())\n );\n }\n }),\n BRANCH: (): BranchAstNode => ({\n type: \"branch\",\n branchName: \"\",\n validate() {},\n createNodeInstance(namedRootNodeProvider, visitedBranches) {\n // Try to find the root node with a matching branch name.\n const targetRootNode = namedRootNodeProvider(this.branchName);\n\n // If we have already visited this branch then we have a circular dependency.\n if (visitedBranches.indexOf(this.branchName) !== -1) {\n throw new Error(`circular dependency found in branch node references for branch '${this.branchName}'`);\n }\n\n // If we have a target root node, then the node instance we want will be the first and only child of the referenced root node.\n if (targetRootNode) {\n return targetRootNode\n .createNodeInstance(namedRootNodeProvider, visitedBranches.concat(this.branchName))\n .getChildren()[0];\n } else {\n throw new Error(`branch references root node '${this.branchName}' which has not been defined`);\n }\n }\n }),\n SELECTOR: (): CompositeAstNode => ({\n type: \"selector\",\n attributes: [],\n children: [],\n validate() {\n // A selector node must have at least a single node.\n if (this.children.length < 1) {\n throw new Error(\"a selector node must have at least a single child\");\n }\n },\n createNodeInstance(namedRootNodeProvider, visitedBranches) {\n return new Selector(\n this.attributes,\n this.children.map((child) => child.createNodeInstance(namedRootNodeProvider, visitedBranches.slice()))\n );\n }\n }),\n SEQUENCE: (): CompositeAstNode => ({\n type: \"sequence\",\n attributes: [],\n children: [],\n validate() {\n // A sequence node must have at least a single node.\n if (this.children.length < 1) {\n throw new Error(\"a sequence node must have at least a single child\");\n }\n },\n createNodeInstance(namedRootNodeProvider, visitedBranches) {\n return new Sequence(\n this.attributes,\n this.children.map((child) => child.createNodeInstance(namedRootNodeProvider, visitedBranches.slice()))\n );\n }\n }),\n PARALLEL: (): CompositeAstNode => ({\n type: \"parallel\",\n attributes: [],\n children: [],\n validate() {\n // A parallel node must have at least a single node.\n if (this.children.length < 1) {\n throw new Error(\"a parallel node must have at least a single child\");\n }\n },\n createNodeInstance(namedRootNodeProvider, visitedBranches) {\n return new Parallel(\n this.attributes,\n this.children.map((child) => child.createNodeInstance(namedRootNodeProvider, visitedBranches.slice()))\n );\n }\n }),\n LOTTO: (): LottoAstNode => ({\n type: \"lotto\",\n attributes: [],\n children: [],\n tickets: [],\n validate() {\n // A lotto node must have at least a single node.\n if (this.children!.length < 1) {\n throw new Error(\"a lotto node must have at least a single child\");\n }\n },\n createNodeInstance(namedRootNodeProvider, visitedBranches) {\n return new Lotto(\n this.attributes,\n this.tickets!,\n this.children!.map((child) => child.createNodeInstance(namedRootNodeProvider, visitedBranches.slice()))\n );\n }\n }),\n REPEAT: (): IterableAstNode => ({\n type: \"repeat\",\n attributes: [],\n iterations: null,\n maximumIterations: null,\n children: [],\n validate() {\n // A repeat node must have a single node.\n if (this.children!.length !== 1) {\n throw new Error(\"a repeat node must have a single child\");\n }\n\n // A repeat node must have a positive number of iterations if defined.\n if (this.iterations !== null && this.iterations! < 0) {\n throw new Error(\"a repeat node must have a positive number of iterations if defined\");\n }\n\n // There is validation to carry out if a longest duration was defined.\n if (this.maximumIterations !== null) {\n // A repeat node must have a positive maximum iterations count if defined.\n if (this.maximumIterations! < 0) {\n throw new Error(\"a repeat node must have a positive maximum iterations count if defined\");\n }\n\n // A repeat node must not have an iteration count that exceeds the maximum iteration count.\n if (this.iterations! > this.maximumIterations!) {\n throw new Error(\n \"a repeat node must not have an iteration count that exceeds the maximum iteration count\"\n );\n }\n }\n },\n createNodeInstance(namedRootNodeProvider, visitedBranches) {\n return new Repeat(\n this.attributes,\n this.iterations!,\n this.maximumIterations!,\n this.children![0].createNodeInstance(namedRootNodeProvider, visitedBranches.slice())\n );\n }\n }),\n RETRY: (): IterableAstNode => ({\n type: \"retry\",\n attributes: [],\n iterations: null,\n maximumIterations: null,\n children: [],\n validate() {\n // A retry node must have a single node.\n if (this.children!.length !== 1) {\n throw new Error(\"a retry node must have a single child\");\n }\n\n // A retry node must have a positive number of iterations if defined.\n if (this.iterations !== null && this.iterations! < 0) {\n throw new Error(\"a retry node must have a positive number of iterations if defined\");\n }\n\n // There is validation to carry out if a longest duration was defined.\n if (this.maximumIterations !== null) {\n // A retry node must have a positive maximum iterations count if defined.\n if (this.maximumIterations! < 0) {\n throw new Error(\"a retry node must have a positive maximum iterations count if defined\");\n }\n\n // A retry node must not have an iteration count that exceeds the maximum iteration count.\n if (this.iterations! > this.maximumIterations!) {\n throw new Error(\n \"a retry node must not have an iteration count that exceeds the maximum iteration count\"\n );\n }\n }\n },\n createNodeInstance(namedRootNodeProvider, visitedBranches) {\n return new Retry(\n this.attributes,\n this.iterations!,\n this.maximumIterations!,\n this.children![0].createNodeInstance(namedRootNodeProvider, visitedBranches.slice())\n );\n }\n }),\n FLIP: (): DecoratorAstNode => ({\n type: \"flip\",\n attributes: [],\n children: [],\n validate() {\n // A flip node must have a single node.\n if (this.children!.length !== 1) {\n throw new Error(\"a flip node must have a single child\");\n }\n },\n createNodeInstance(namedRootNodeProvider, visitedBranches) {\n return new Flip(\n this.attributes,\n this.children![0].createNodeInstance(namedRootNodeProvider, visitedBranches.slice())\n );\n }\n }),\n SUCCEED: (): DecoratorAstNode => ({\n type: \"succeed\",\n attributes: [],\n children: [],\n validate() {\n // A succeed node must have a single node.\n if (this.children!.length !== 1) {\n throw new Error(\"a succeed node must have a single child\");\n }\n },\n createNodeInstance(namedRootNodeProvider, visitedBranches) {\n return new Succeed(\n this.attributes,\n this.children![0].createNodeInstance(namedRootNodeProvider, visitedBranches.slice())\n );\n }\n }),\n FAIL: (): DecoratorAstNode => ({\n type: \"fail\",\n attributes: [],\n children: [],\n validate() {\n // A fail node must have a single node.\n if (this.children!.length !== 1) {\n throw new Error(\"a fail node must have a single child\");\n }\n },\n createNodeInstance(namedRootNodeProvider, visitedBranches) {\n return new Fail(\n this.attributes,\n this.children![0].createNodeInstance(namedRootNodeProvider, visitedBranches.slice())\n );\n }\n }),\n WAIT: (): WaitAstNode => ({\n type: \"wait\",\n attributes: [],\n duration: null,\n longestDuration: null,\n validate() {\n // A wait node must have a positive duration.\n if (this.duration! < 0) {\n throw new Error(\"a wait node must have a positive duration\");\n }\n\n // There is validation to carry out if a longest duration was defined.\n if (this.longestDuration) {\n // A wait node must have a positive longest duration.\n if (this.longestDuration < 0) {\n throw new Error(\"a wait node must have a positive longest duration if one is defined\");\n }\n\n // A wait node must not have a duration that exceeds the longest duration.\n if (this.duration! > this.longestDuration) {\n throw new Error(\"a wait node must not have a shortest duration that exceeds the longest duration\");\n }\n }\n },\n createNodeInstance() {\n return new Wait(this.attributes, this.duration!, this.longestDuration!);\n }\n }),\n ACTION: (): ActionAstNode => ({\n type: \"action\",\n attributes: [],\n actionName: \"\",\n actionArguments: [],\n validate() {},\n createNodeInstance() {\n return new Action(this.attributes, this.actionName!, this.actionArguments!);\n }\n }),\n CONDITION: (): ConditionAstNode => ({\n type: \"condition\",\n attributes: [],\n conditionName: \"\",\n conditionArguments: [],\n validate() {},\n createNodeInstance() {\n return new Condition(this.attributes, this.conditionName!, this.conditionArguments!);\n }\n })\n};\n\ntype OtherAstNodes = AstNode[];\n\n/**\n * Create an array of root AST nodes based on the given definition.\n * @param definition The definition to parse the AST nodes from.\n * @returns The base definition AST nodes.\n */\nexport default function buildRootASTNodes(definition: string): RootAstNode[] {\n // Swap out any node/attribute argument string literals with a placeholder and get a mapping of placeholders to original values as well as the processed definition.\n const { placeholders, processedDefinition } = substituteStringLiterals(definition);\n\n // Convert the processed definition (with substituted string literals) into an array of raw tokens.\n const tokens = parseTokensFromDefinition(processedDefinition);\n\n // There must be at least 3 tokens for the tree definition to be valid. 'ROOT', '{' and '}'.\n if (tokens.length < 3) {\n throw new Error(\"invalid token count\");\n }\n\n // We should have a matching number of '{' and '}' tokens. If not, then there are scopes that have not been properly closed.\n if (tokens.filter((token) => token === \"{\").length !== tokens.filter((token) => token === \"}\").length) {\n throw new Error(\"scope character mismatch\");\n }\n\n // Create a stack of node children arrays, starting with a definition scope.\n const stack: [RootAstNode[], ...OtherAstNodes[]] = [[]];\n const rootScope = stack[0];\n\n // We should keep processing the raw tokens until we run out of them.\n while (tokens.length) {\n // Grab the next token.\n const token = tokens.shift();\n\n const currentScope = stack[stack.length - 1] as OtherAstNodes;\n\n // How we create the next AST token depends on the current raw token value.\n switch (token!.toUpperCase()) {\n case \"ROOT\": {\n // Create a ROOT AST node.\n const node = ASTNodeFactories.ROOT();\n\n // Push the ROOT node into the current scope.\n rootScope.push(node);\n\n // We may have a root node name defined as an argument.\n if (tokens[0] === \"[\") {\n const rootArguments = getArguments(tokens, placeholders);\n\n // We should have only a single argument that is not an empty string for a root node, which is the root name identifier.\n if (rootArguments.length === 1 && rootArguments[0].type === \"identifier\") {\n // The root name will be the first and only node argument.\n node.name = rootArguments[0].value as string;\n } else {\n throw new Error(\"expected single root name argument\");\n }\n }\n\n // Try to pick any attributes off of the token stack.\n node.attributes = getAttributes(tokens, placeholders);\n\n popAndCheck(tokens, \"{\");\n\n // The new scope is that of the new ROOT nodes children.\n stack.push(node.children!);\n break;\n }\n\n case \"BRANCH\": {\n // Create a BRANCH AST node.\n const node = ASTNodeFactories.BRANCH();\n\n // Push the BRANCH node into the current scope.\n currentScope.push(node);\n\n // We must have arguments defined, as we require a branch name argument.\n if (tokens[0] !== \"[\") {\n throw new Error(\"expected single branch name argument\");\n }\n\n // The branch name will be defined as a node argument.\n const branchArguments = getArguments(tokens, placeholders);\n\n // We should have only a single identifer argument for a branch node, which is the branch name.\n if (branchArguments.length === 1 && branchArguments[0].type === \"identifier\") {\n // The branch name will be the first and only node argument.\n node.branchName = branchArguments[0].value as string;\n } else {\n throw new Error(\"expected single branch name argument\");\n }\n break;\n }\n\n case \"SELECTOR\": {\n // Create a SELECTOR AST node.\n const node = ASTNodeFactories.SELECTOR();\n\n // Push the SELECTOR node into the current scope.\n currentScope.push(node);\n\n // Try to pick any attributes off of the token stack.\n node.attributes = getAttributes(tokens, placeholders);\n\n popAndCheck(tokens, \"{\");\n\n // The new scope is that of the new SELECTOR nodes children.\n stack.push(node.children!);\n break;\n }\n\n case \"SEQUENCE\": {\n // Create a SEQUENCE AST node.\n const node = ASTNodeFactories.SEQUENCE();\n\n // Push the SEQUENCE node into the current scope.\n currentScope.push(node);\n\n // Try to pick any attributes off of the token stack.\n node.attributes = getAttributes(tokens, placeholders);\n\n popAndCheck(tokens, \"{\");\n\n // The new scope is that of the new SEQUENCE nodes children.\n stack.push(node.children!);\n break;\n }\n\n case \"PARALLEL\": {\n // Create a PARALLEL AST node.\n const node = ASTNodeFactories.PARALLEL();\n\n // Push the PARALLEL node into the current scope.\n currentScope.push(node);\n\n // Try to pick any attributes off of the token stack.\n node.attributes = getAttributes(tokens, placeholders);\n\n popAndCheck(tokens, \"{\");\n\n // The new scope is that of the new PARALLEL nodes children.\n stack.push(node.children!);\n break;\n }\n\n case \"LOTTO\": {\n // Create a LOTTO AST node.\n const node = ASTNodeFactories.LOTTO();\n\n // Push the LOTTO node into the current scope.\n currentScope.push(node);\n\n // If the next token is a '[' character then some ticket counts have been defined as arguments.\n if (tokens[0] === \"[\") {\n // Get the ticket count arguments, each argument must be a number.\n node.tickets = getArguments(\n tokens,\n placeholders,\n (arg) => arg.type === \"number\" && !!arg.isInteger,\n \"lotto node ticket counts must be integer values\"\n ).map((argument) => argument.value as number);\n }\n\n // Try to pick any attributes off of the token stack.\n node.attributes = getAttributes(tokens, placeholders);\n\n popAndCheck(tokens, \"{\");\n\n // The new scope is that of the new LOTTO nodes children.\n stack.push(node.children!);\n break;\n }\n\n case \"CONDITION\": {\n // Create a CONDITION AST node.\n const node = ASTNodeFactories.CONDITION();\n\n // Push the CONDITION node into the current scope.\n currentScope.push(node);\n\n // We must have arguments defined, as we require a condition function name argument.\n if (tokens[0] !== \"[\") {\n throw new Error(\"expected condition name identifier argument\");\n }\n\n // Grab the condition node arguments.\n const conditionArguments = getArguments(tokens, placeholders);\n\n // We should have at least a single identifier argument for a condition node, which is the condition function name.\n if (conditionArguments.length && conditionArguments[0].type === \"identifier\") {\n // The condition function name will be the first node argument.\n node.conditionName = conditionArguments.shift()!.value as string;\n } else {\n throw new Error(\"expected condition name identifier argument\");\n }\n\n // Only the first argument should have been an identifier, all following arguments must be string, number, boolean or null.\n conditionArguments\n .filter((arg) => arg.type === \"identifier\")\n .forEach((arg) => {\n throw new Error(\n \"invalid condition node argument value '\" +\n arg.value +\n \"', must be string, number, boolean or null\"\n );\n });\n\n // Any node arguments that follow the condition name identifier will be treated as condition function arguments.\n node.conditionArguments = conditionArguments;\n\n // Try to pick any attributes off of the token stack.\n node.attributes = getAttributes(tokens, placeholders);\n break;\n }\n\n case \"FLIP\": {\n // Create a FLIP AST node.\n const node = ASTNodeFactories.FLIP();\n\n // Push the Flip node into the current scope.\n currentScope.push(node);\n\n // Try to pick any attributes off of the token stack.\n node.attributes = getAttributes(tokens, placeholders);\n\n popAndCheck(tokens, \"{\");\n\n // The new scope is that of the new FLIP nodes children.\n stack.push(node.children!);\n break;\n }\n\n case \"SUCCEED\": {\n // Create a SUCCEED AST node.\n const node = ASTNodeFactories.SUCCEED();\n\n // Push the Succeed node into the current scope.\n currentScope.push(node);\n\n // Try to pick any attributes off of the token stack.\n node.attributes = getAttributes(tokens, placeholders);\n\n popAndCheck(tokens, \"{\");\n\n // The new scope is that of the new Succeed nodes children.\n stack.push(node.children!);\n break;\n }\n\n case \"FAIL\": {\n // Create a FAIL AST node.\n const node = ASTNodeFactories.FAIL();\n\n // Push the Fail node into the current scope.\n currentScope.push(node);\n\n // Try to pick any attributes off of the token stack.\n node.attributes = getAttributes(tokens, placeholders);\n\n popAndCheck(tokens, \"{\");\n\n // The new scope is that of the new Fail nodes children.\n stack.push(node.children!);\n break;\n }\n\n case \"WAIT\": {\n // Create a WAIT AST node.\n const node = ASTNodeFactories.WAIT();\n\n // Push the WAIT node into the current scope.\n currentScope.push(node);\n\n // Get the duration and potential longest duration of the wait.\n const durations = getArguments(\n tokens,\n placeholders,\n (arg) => arg.type === \"number\" && !!arg.isInteger,\n \"wait node durations must be integer values\"\n ).map((argument) => argument.value);\n\n // We should have got one or two durations.\n if (durations.length === 1) {\n // A static duration was defined.\n node.duration = durations[0] as number;\n } else if (durations.length === 2) {\n // A shortest and longest duration was defined.\n node.duration = durations[0] as number;\n node.longestDuration = durations[1] as number;\n } else {\n // An incorrect number of durations was defined.\n throw new Error(\"invalid number of wait node duration arguments defined\");\n }\n\n // Try to pick any attributes off of the token stack.\n node.attributes = getAttributes(tokens, placeholders);\n break;\n }\n\n case \"REPEAT\": {\n // Create a REPEAT AST node.\n const node = ASTNodeFactories.REPEAT();\n\n // Push the REPEAT node into the current scope.\n currentScope.push(node);\n\n // Check for iteration counts ([])\n if (tokens[0] === \"[\") {\n // An iteration count has been defined. Get the iteration and potential maximum iteration of the wait.\n const iterationArguments = getArguments(\n tokens,\n placeholders,\n (arg) => arg.type === \"number\" && !!arg.isInteger,\n \"repeat node iteration counts must be integer values\"\n ).map((argument) => argument.value);\n\n // We should have got one or two iteration counts.\n if (iterationArguments.length === 1) {\n // A static iteration count was defined.\n node.iterations = iterationArguments[0] as number;\n } else if (iterationArguments.length === 2) {\n // A minimum and maximum iteration count was defined.\n node.iterations = iterationArguments[0] as number;\n node.maximumIterations = iterationArguments[1] as number;\n } else {\n // An incorrect number of iteration counts was defined.\n throw new Error(\"invalid number of repeat node iteration count arguments defined\");\n }\n }\n\n // Try to pick any attributes off of the token stack.\n node.attributes = getAttributes(tokens, placeholders);\n\n popAndCheck(tokens, \"{\");\n\n // The new scope is that of the new REPEAT nodes children.\n stack.push(node.children!);\n break;\n }\n\n case \"RETRY\": {\n // Create a RETRY AST node.\n const node = ASTNodeFactories.RETRY();\n\n // Push the RETRY node into the current scope.\n currentScope.push(node);\n\n // Check for iteration counts ([])\n if (tokens[0] === \"[\") {\n // An iteration count has been defined. Get the iteration and potential maximum iteration of the wait.\n const iterationArguments = getArguments(\n tokens,\n placeholders,\n (arg) => arg.type === \"number\" && !!arg.isInteger,\n \"retry node iteration counts must be integer values\"\n ).map((argument) => argument.value);\n\n // We should have got one or two iteration counts.\n if (iterationArguments.length === 1) {\n // A static iteration count was defined.\n node.iterations = iterationArguments[0] as number;\n } else if (iterationArguments.length === 2) {\n // A minimum and maximum iteration count was defined.\n node.iterations = iterationArguments[0] as number;\n node.maximumIterations = iterationArguments[1] as number;\n } else {\n // An incorrect number of iteration counts was defined.\n throw new Error(\"invalid number of retry node iteration count arguments defined\");\n }\n }\n\n // Try to pick any attributes off of the token stack.\n node.attributes = getAttributes(tokens, placeholders);\n\n popAndCheck(tokens, \"{\");\n\n // The new scope is that of the new RETRY nodes children.\n stack.push(node.children!);\n break;\n }\n\n case \"ACTION\": {\n // Create a ACTION AST node.\n const node = ASTNodeFactories.ACTION();\n\n // Push the ACTION node into the current scope.\n currentScope.push(node);\n\n // We must have arguments defined, as we require an action name argument.\n if (tokens[0] !== \"[\") {\n throw new Error(\"expected action name identifier argument\");\n }\n\n // The action name will be defined as a node argument.\n const actionArguments = getArguments(tokens, placeholders);\n\n // We should have at least one identifer argument for an action node, which is the action name.\n if (actionArguments.length && actionArguments[0].type === \"identifier\") {\n // The action name will be the first and only node argument.\n node.actionName = actionArguments.shift()!.value as string;\n } else {\n throw new Error(\"expected action name identifier argument\");\n }\n\n // Only the first argument should have been an identifier, all following arguments must be string, number, boolean or null.\n actionArguments\n .filter((arg) => arg.type === \"identifier\")\n .forEach((arg) => {\n throw new Error(\n \"invalid action node argument value '\" +\n arg.value +\n \"', must be string, number, boolean or null\"\n );\n });\n\n // Any node arguments that follow the action name identifier will be treated as action function arguments.\n node.actionArguments = actionArguments;\n\n // Try to pick any attributes off of the token stack.\n node.attributes = getAttributes(tokens, placeholders);\n break;\n }\n\n case \"}\": {\n // The '}' character closes the current scope.\n stack.pop();\n break;\n }\n\n default: {\n throw new Error(\"unexpected token: \" + token);\n }\n }\n }\n\n // A function to recursively validate each of the nodes in the AST.\n const validateASTNode = (node: Validatable, depth: number): void => {\n // Validate the node.\n node.validate(depth);\n\n // Validate each child of the node.\n (node.children || []).forEach((child) => validateASTNode(child, depth + 1));\n };\n\n // Start node validation from the definition root.\n validateASTNode(\n {\n children: stack[0] as RootAstNode[],\n validate(this: { children: RootAstNode[] }) {\n // We must have at least one node defined as the definition scope, which should be a root node.\n if (this.children.length === 0) {\n throw new Error(\"expected root node to have been defined\");\n }\n\n // Each node at the base of the definition scope MUST be a root node.\n for (const definitionLevelNode of this.children) {\n if (definitionLevelNode.type !== \"root\") {\n throw new Error(\"expected root node at base of definition\");\n }\n }\n\n // Exactly one root node must not have a name defined. This will be the main root, others will have to be referenced via branch nodes.\n if (this.children.filter((definitionLevelNode) => definitionLevelNode.name === null).length !== 1) {\n throw new Error(\"expected single unnamed root node at base of definition to act as main root\");\n }\n\n // No two named root nodes can have matching names.\n const rootNodeNames: string[] = [];\n for (const definitionLevelNode of this.children) {\n if (rootNodeNames.indexOf(definitionLevelNode.name!) !== -1) {\n throw new Error(`multiple root nodes found with duplicate name '${definitionLevelNode.name}'`);\n } else {\n rootNodeNames.push(definitionLevelNode.name!);\n }\n }\n }\n },\n 0\n );\n\n // Return the root AST nodes.\n return stack[0];\n}\n\n/**\n * Pop the next raw token off of the stack and throw an error if it wasn't the expected one.\n * @param tokens The array of remaining tokens.\n * @param expected An optional string or array or items, one of which must match the next popped token.\n * @returns The popped token.\n */\nfunction popAndCheck(tokens: string[], expected: string | string[]) {\n // Get and remove the next token.\n const popped = tokens.shift();\n\n // We were expecting another token.\n if (popped === undefined) {\n throw new Error(\"unexpected end of definition\");\n }\n\n // Do we have an expected token/tokens array?\n if (expected !== undefined) {\n // Check whether the popped token matches at least one of our expected items.\n var tokenMatchesExpectation = ([] as string[])\n .concat(expected)\n .some((item) => popped.toUpperCase() === item.toUpperCase());\n\n // Throw an error if the popped token didn't match any of our expected items.\n if (!tokenMatchesExpectation) {\n const expectationString = ([] as string[])\n .concat(expected)\n .map((item) => \"'\" + item + \"'\")\n .join(\" or \");\n throw new Error(\"unexpected token found. Expected \" + expectationString + \" but got '\" + popped + \"'\");\n }\n }\n\n // Return the popped token.\n return popped;\n}\n\ntype Placeholders = { [key: string]: string };\n\n/**\n * Pull an argument definition list off of the token stack.\n * @param tokens The array of remaining tokens.\n * @param stringArgumentPlaceholders The mapping of string literal node argument placeholders to original values.\n * @param argumentValidator The argument validator function.\n * @param validationFailedMessage The exception message to throw if argument validation fails.\n * @returns The argument definition list.\n */\nfunction getArguments(\n tokens: string[],\n stringArgumentPlaceholders: Placeholders,\n argumentValidator?: (arg: AnyArgument) => boolean,\n validationFailedMessage?: string\n) {\n // Any lists of arguments will always be wrapped in '[]' for node arguments or '()' for attribute arguments.\n // We are looking for a '[' or '(' opener that wraps the argument tokens and the relevant closer.\n const closer = popAndCheck(tokens, [\"[\", \"(\"]) === \"[\" ? \"]\" : \")\";\n\n const argumentListTokens: string[] = [];\n const argumentList: AnyArgument[] = [];\n\n // Grab all tokens between the '[' and ']' or '(' and ')'.\n while (tokens.length && tokens[0] !== closer) {\n // The next token is part of our arguments list.\n argumentListTokens.push(tokens.shift()!);\n }\n\n // Validate the order of the argument tokens. Each token must either be a ',' or a single argument that satisfies the validator.\n argumentListTokens.forEach((token, index) => {\n // Get whether this token should be an actual argument.\n const shouldBeArgumentToken = !(index & 1);\n\n // If the current token should be an actual argument then validate it,otherwise it should be a ',' token.\n if (shouldBeArgumentToken) {\n // Get the argument definition.\n const argumentDefinition = getArgumentDefinition(token!, stringArgumentPlaceholders);\n\n // Try to validate the argument.\n if (argumentValidator && !argumentValidator(argumentDefinition)) {\n throw new Error(validationFailedMessage);\n }\n\n // This is a valid argument!\n argumentList.push(argumentDefinition);\n } else {\n // The current token should be a ',' token.\n if (token !== \",\") {\n throw new Error(`invalid argument list, expected ',' or ']' but got '${token}'`);\n }\n }\n });\n\n // The arguments list should terminate with a ']' or ')' token, depending on the opener.\n popAndCheck(tokens, closer);\n\n // Return the argument list.\n return argumentList;\n}\n\n/**\n * Gets an argument value definition.\n * @param token The argument token.\n * @param stringArgumentPlaceholders The mapping of string literal node argument placeholders to original values.\n * @returns An argument value definition.\n */\nfunction getArgumentDefinition(token: string, stringArgumentPlaceholders: Placeholders): AnyArgument {\n // Check whether the token represents a null value.\n if (token === \"null\") {\n return {\n value: null,\n type: \"null\"\n } as NullArgument;\n }\n\n // Check whether the token represents a boolean value.\n if (token === \"true\" || token === \"false\") {\n return {\n value: token === \"true\",\n type: \"boolean\"\n } as BooleanArgument;\n }\n\n // Check whether the token represents a number value.\n // TODO: Relies on broken isNaN - see MDN.\n // if (!Number.isNaN(token)) {\n if (!isNaN(token as any)) {\n return {\n value: parseFloat(token),\n isInteger: parseFloat(token) === parseInt(token, 10),\n type: \"number\"\n } as NumberArgument;\n }\n\n // Check whether the token is a placeholder (e.g. @@0@@) representing a string literal.\n if (token.match(/^@@\\d+@@$/g)) {\n return {\n value: stringArgumentPlaceholders[token].replace('\\\\\"', '\"'),\n type: \"string\"\n } as StringPlaceholderArgument;\n }\n\n // The only remaining option is that the argument value is an identifier.\n return {\n value: token,\n type: \"identifier\"\n } as IdentifierArgument;\n}\n\n/**\n * Pull any attributes off of the token stack.\n * @param tokens The array of remaining tokens.\n * @param stringArgumentPlaceholders The mapping of string literal node argument placeholders to original values.\n * @returns An array of attributes defined by any directly following tokens.\n */\nfunction getAttributes(tokens: string[], stringArgumentPlaceholders: Placeholders) {\n // Create an array to hold any attributes found.\n const attributes: Attribute[] = [];\n\n // Keep track of names of attribute that we have found on the token stack, as we cannot have duplicates.\n const attributesFound: string[] = [];\n\n // Try to get the attribute factory for the next token.\n let attributeFactory = AttributeFactories[(tokens[0] || \"\").toUpperCase()];\n\n // Pull attribute tokens off of the tokens stack until we have no more.\n while (attributeFactory) {\n // Check to make sure that we have not already created a attribute of this type for this node.\n if (attributesFound.indexOf(tokens[0].toUpperCase()) !== -1) {\n throw new Error(`duplicate attribute '${tokens[0].toUpperCase()}' found for node`);\n }\n\n // Add the current attribute type to our array of found attributes.\n attributesFound.push(tokens.shift()!.toUpperCase());\n\n // Grab any attribute arguments.\n const attributeArguments = getArguments(tokens, stringArgumentPlaceholders);\n\n // The first attribute argument has to be an identifer, this will reference an agent function.\n if (attributeArguments.length === 0 || attributeArguments[0].type !== \"identifier\") {\n throw new Error(\"expected agent function name identifier argument for attribute\");\n }\n\n // Grab the first attribute which is an identifier that will reference an agent function.\n const attributeFunctionName = attributeArguments.shift()! as IdentifierArgument;\n\n // Any remaining attribute arguments must have a type of string, number, boolean or null.\n attributeArguments\n .filter((arg) => arg.type === \"identifier\")\n .forEach((arg) => {\n throw new Error(\n \"invalid attribute argument value '\" + arg.value + \"', must be string, number, boolean or null\"\n );\n });\n\n // Create the attribute and add it to the array of attributes found.\n attributes.push(attributeFactory(attributeFunctionName.value, attributeArguments));\n\n // Try to get the next attribute name token, as there could be multiple.\n attributeFactory = AttributeFactories[(tokens[0] || \"\").toUpperCase()];\n }\n\n return attributes;\n}\n\n/**\n * Swaps out any node/attribute argument string literals with placeholders.\n * @param definition The definition.\n * @returns An object containing a mapping of placeholders to original string values as well as the processed definition string.\n */\nfunction substituteStringLiterals(definition: string): {\n placeholders: { [key: string]: string };\n processedDefinition: string;\n} {\n // Create an object to hold the mapping of placeholders to original string values.\n const placeholders: Placeholders = {};\n\n // Replace any string literals wrapped with double quotes in our definition with placeholders to be processed later.\n const processedDefinition = definition.replace(/\\\"(\\\\.|[^\"\\\\])*\\\"/g, (match) => {\n var strippedMatch = match.substring(1, match.length - 1);\n var placeholder = Object.keys(placeholders).find((key) => placeholders[key] === strippedMatch);\n\n // If we have no existing string literal match then create a new placeholder.\n if (!placeholder) {\n placeholder = `@@${Object.keys(placeholders).length}@@`;\n placeholders[placeholder] = strippedMatch;\n }\n\n return placeholder;\n });\n\n return { placeholders, processedDefinition };\n}\n\n/**\n * Parse the tree definition into an array of raw tokens.\n * @param definition The definition.\n * @returns An array of tokens parsed from the definition.\n */\nfunction parseTokensFromDefinition(definition: string): string[] {\n // Add some space around various important characters so that they can be plucked out easier as individual tokens.\n definition = definition.replace(/\\(/g, \" ( \");\n definition = definition.replace(/\\)/g, \" ) \");\n definition = definition.replace(/\\{/g, \" { \");\n definition = definition.replace(/\\}/g, \" } \");\n definition = definition.replace(/\\]/g, \" ] \");\n definition = definition.replace(/\\[/g, \" [ \");\n definition = definition.replace(/\\,/g, \" , \");\n\n // Split the definition into raw token form and return it.\n return definition.replace(/\\s+/g, \" \").trim().split(\" \");\n}\n", "import GuardPath, { GuardPathPart } from \"./attributes/guards/GuardPath\";\nimport buildRootASTNodes, { AnyArgument, RootAstNode } from \"./RootAstNodesBuilder\";\nimport State, { AnyState } from \"./State\";\nimport Lookup from \"./Lookup\";\nimport Node from \"./nodes/Node\";\nimport Root from \"./nodes/decorator/Root\";\nimport Composite from \"./nodes/composite/Composite\";\nimport Decorator from \"./nodes/decorator/Decorator\";\nimport { Agent, GlobalFunction } from \"./Agent\";\nimport { CallbackAttributeDetails } from \"./attributes/callbacks/Callback\";\nimport { GuardAttributeDetails } from \"./attributes/guards/Guard\";\nimport { BehaviourTreeOptions } from \"./BehaviourTreeOptions\";\n\n// Purely for outside inspection of the tree.\nexport type FlattenedTreeNode = {\n id: string;\n type: string;\n caption: string;\n state: AnyState;\n guards: GuardAttributeDetails[];\n callbacks: CallbackAttributeDetails[];\n args: AnyArgument[];\n parentId: string | null;\n};\n\n/**\n * A representation of a behaviour tree.\n */\nexport class BehaviourTree {\n /**\n * The main root tree node.\n */\n public readonly rootNode: Root;\n\n /**\n * Creates a new instance of the BehaviourTree class.\n * @param definition The behaviour tree definition.\n * @param agent The agent instance that this behaviour tree is modelling behaviour for.\n * @param options The behaviour tree options object.\n */\n constructor(definition: string, private agent: Agent, private options: BehaviourTreeOptions = {}) {\n // The tree definition must be defined and a valid string.\n if (typeof definition !== \"string\") {\n throw new Error(\"the tree definition must be a string\");\n }\n\n // The agent must be defined and not null.\n if (typeof agent !== \"object\" || agent === null) {\n throw new Error(\"the agent must be defined and not null\");\n }\n\n // Parse the behaviour tree definition, create the populated tree of behaviour tree nodes, and get the root.\n this.rootNode = BehaviourTree.createRootNode(definition);\n }\n\n /**\n * Gets whether the tree is in the RUNNING state.\n * @returns true if the tree is in the RUNNING state, otherwise false.\n */\n isRunning() {\n return this.rootNode.getState() === State.RUNNING;\n }\n\n /**\n * Gets the current tree state of SUCCEEDED, FAILED, READY or RUNNING.\n * @returns The current tree state.\n */\n getState() {\n return this.rootNode.getState();\n }\n\n /**\n * Step the tree.\n * 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.\n * 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\n * 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.\n *\n * 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.\n */\n step() {\n // If the root node has already been stepped to completion then we need to reset it.\n if (this.rootNode.getState() === State.SUCCEEDED || this.rootNode.getState() === State.FAILED) {\n this.rootNode.reset();\n }\n\n try {\n this.rootNode.update(this.agent, this.options);\n } catch (exception) {\n throw new Error(`error stepping tree: ${(exception as Error).message}`);\n }\n }\n\n /**\n * Resets the tree from the root node outwards to each nested node, giving each a state of READY.\n */\n reset() {\n this.rootNode.reset();\n }\n\n /**\n * Gets the flattened details of every node in the tree.\n * @returns The flattened details of every node in the tree.\n */\n getFlattenedNodeDetails(): FlattenedTreeNode[] {\n // Create an empty flattened array of tree nodes.\n const flattenedTreeNodes: FlattenedTreeNode[] = [];\n\n /**\n * Helper function to process a node instance and push details into the flattened tree nodes array.\n * @param node The current node.\n * @param parentUid The UID of the node parent, or null if the node is the main root node.\n */\n const processNode = (node: Node, parentUid: string | null) => {\n // Get the guard and callback attribute details for this node.\n const guards = node\n .getAttributes()\n .filter((attribute) => attribute.isGuard())\n .map((attribute) => attribute.getDetails()) as GuardAttributeDetails[];\n const callbacks = node\n .getAttributes()\n .filter((attribute) => !attribute.isGuard())\n .map((attribute) => attribute.getDetails()) as CallbackAttributeDetails[];\n\n // Push the current node into the flattened nodes array.\n flattenedTreeNodes.push({\n id: node.getUid(),\n type: node.getType(),\n caption: node.getName(),\n state: node.getState(),\n guards,\n callbacks,\n args: node.getArguments(),\n parentId: parentUid\n });\n\n // Process each of the nodes children if it is not a leaf node.\n if (!node.isLeafNode()) {\n (node as Composite | Decorator)\n .getChildren()\n .forEach((child) => processNode(child, (node as Composite | Decorator).getUid()));\n }\n };\n\n // Convert the nested node structure into a flattened array of node details.\n processNode(this.rootNode, null);\n\n return flattenedTreeNodes;\n }\n\n /**\n * Registers the action/condition/guard/callback function or subtree with the given name.\n * @param name The name of the function or subtree to register.\n * @param value The function or subtree definition to register.\n */\n static register(name: string, value: GlobalFunction | string) {\n if (typeof value === \"function\") {\n // We are going to register a action/condition/guard/callback function.\n Lookup.setFunc(name, value);\n } else if (typeof value === \"string\") {\n // We are going to register a subtree.\n let rootASTNodes: RootAstNode[];\n\n try {\n // Try to create the behaviour tree AST based on the definition provided, this could fail if the definition is invalid.\n rootASTNodes = buildRootASTNodes(value);\n } catch (exception) {\n // There was an issue in trying to parse and build the tree definition.\n throw new Error(`error registering definition: ${(exception as Error).message}`);\n }\n\n // This function should only ever be called with a definition containing a single unnamed root node.\n if (rootASTNodes.length != 1 || rootASTNodes[0].name !== null) {\n throw new Error(\"error registering definition: expected a single unnamed root node\");\n }\n\n Lookup.setSubtree(name, rootASTNodes[0]);\n } else {\n throw new Error(\"unexpected value, expected string definition or function\");\n }\n }\n\n /**\n * Unregisters the registered action/condition/guard/callback function or subtree with the given name.\n * @param name The name of the registered action/condition/guard/callback function or subtree to unregister.\n */\n static unregister(name: string): void {\n Lookup.remove(name);\n }\n\n /**\n * Unregister all registered action/condition/guard/callback functions and subtrees.\n */\n static unregisterAll(): void {\n Lookup.empty();\n }\n\n /**\n * Parses a behaviour tree definition and creates a tree of behaviour tree nodes.\n * @param {string} definition The behaviour tree definition.\n * @returns The root behaviour tree node.\n */\n private static createRootNode(definition: string): Root {\n try {\n // Try to create the behaviour tree AST based on the definition provided, this could fail if the definition is invalid.\n const rootASTNodes = buildRootASTNodes(definition);\n\n // Create a symbol to use as the main root key in our root node mapping.\n const mainRootNodeKey = Symbol(\"__root__\");\n\n // Create a mapping of root node names to root AST tokens. The main root node will have a key of Symbol(\"__root__\").\n const rootNodeMap: { [key: string | symbol]: RootAstNode } = {};\n for (const rootASTNode of rootASTNodes) {\n rootNodeMap[rootASTNode.name === null ? mainRootNodeKey : rootASTNode.name!] = rootASTNode;\n }\n\n // Convert the AST to our actual tree and get the root node.\n const rootNode: Root = rootNodeMap[mainRootNodeKey].createNodeInstance(\n // Create a provider for named root nodes that are part of our definition or have been registered. Prioritising the former.\n (name: string): RootAstNode => (rootNodeMap[name] ? rootNodeMap[name] : Lookup.getSubtree(name)),\n []\n );\n\n // Set a guard path on every leaf of the tree to evaluate as part of its update.\n BehaviourTree.applyLeafNodeGuardPaths(rootNode);\n\n // Return the root node.\n return rootNode;\n } catch (exception) {\n // There was an issue in trying to parse and build the tree definition.\n throw new Error(`error parsing tree: ${(exception as Error).message}\\n${(exception as Error).stack}`);\n }\n }\n\n /**\n * Applies a guard path to every leaf of the tree to evaluate as part of each update.\n * @param rootNode The main root tree node.\n */\n private static applyLeafNodeGuardPaths(rootNode: Root) {\n const nodePaths: Node[][] = [];\n\n const findLeafNodes = (path: Node[], node: Node) => {\n // Add the current node to the path.\n path = path.concat(node);\n\n // Check whether the current node is a leaf node.\n if (node.isLeafNode()) {\n nodePaths.push(path);\n } else {\n (node as Composite | Decorator).getChildren().forEach((child) => findLeafNodes(path, child));\n }\n };\n\n // Find all leaf node paths, starting from the root.\n findLeafNodes([], rootNode);\n\n nodePaths.forEach((path) => {\n // Each node in the current path will have to be assigned a guard path, working from the root outwards.\n for (let depth = 0; depth < path.length; depth++) {\n // Get the node in the path at the current depth.\n const currentNode = path[depth];\n\n // The node may already have been assigned a guard path, if so just skip it.\n if (currentNode.hasGuardPath()) {\n continue;\n }\n\n // Create the guard path for the current node.\n const guardPath = new GuardPath(\n path\n .slice(0, depth + 1)\n .map((node) => ({ node, guards: node.getGuardAttributes() }))\n .filter((details) => details.guards.length > 0)\n );\n\n // Assign the guard path to the current node.\n currentNode.setGuardPath(guardPath);\n }\n });\n }\n}\n"], + "sourcesContent": ["\"use strict\";\r\nObject.defineProperty(exports, \"__esModule\", { value: true });\r\nexports.Participant = void 0;\r\n/**\r\n * A participant that holds a number of tickets.\r\n */\r\nvar Participant = /** @class */ (function () {\r\n /**\r\n * Creates an instance of the Participant class.\r\n * @param participant The actual participant.\r\n * @param tickets The number of tickets held by the participant.\r\n */\r\n function Participant(participant, tickets) {\r\n if (tickets === void 0) { tickets = 1; }\r\n this._participant = participant;\r\n this._tickets = tickets;\r\n }\r\n Object.defineProperty(Participant.prototype, \"participant\", {\r\n /** Gets the actual participant. */\r\n get: function () {\r\n return this._participant;\r\n },\r\n enumerable: false,\r\n configurable: true\r\n });\r\n Object.defineProperty(Participant.prototype, \"tickets\", {\r\n /** Gets or sets the number of tickets held by the participant. */\r\n get: function () {\r\n return this._tickets;\r\n },\r\n set: function (value) {\r\n this._tickets = value;\r\n },\r\n enumerable: false,\r\n configurable: true\r\n });\r\n return Participant;\r\n}());\r\nexports.Participant = Participant;\r\n", "\"use strict\";\r\nObject.defineProperty(exports, \"__esModule\", { value: true });\r\nexports.isNaturalNumber = exports.isNullOrUndefined = void 0;\r\n/**\r\n * Gets whether the value provided is null or undefined.\r\n * @param value The value to check.\r\n * @returns Whether the value provided is null or undefined.\r\n */\r\nfunction isNullOrUndefined(value) {\r\n return value === null || value === undefined;\r\n}\r\nexports.isNullOrUndefined = isNullOrUndefined;\r\n/**\r\n * Gets whether the value provided is a natural number.\r\n * @param value The value to check.\r\n * @returns Whether the value provided is a natural number.\r\n */\r\nfunction isNaturalNumber(value) {\r\n return typeof value === \"number\" && value >= 1 && Math.floor(value) === value;\r\n}\r\nexports.isNaturalNumber = isNaturalNumber;\r\n", "\"use strict\";\r\nObject.defineProperty(exports, \"__esModule\", { value: true });\r\nexports.Lotto = void 0;\r\nvar Participant_1 = require(\"./Participant\");\r\nvar Utilities_1 = require(\"./Utilities\");\r\n/**\r\n * Represents a lotto consisting of a number of pickable ticket-holding participants.\r\n */\r\nvar Lotto = /** @class */ (function () {\r\n /**\r\n * Creates a new instance of Lotto.\r\n * @param customRandom The custom RNG to use in place of Math.random().\r\n */\r\n function Lotto(customRandom) {\r\n /** The array of participants that are holding tickets in the lotto. */\r\n this._participants = [];\r\n this._customRandom = customRandom;\r\n }\r\n /**\r\n * Adds a participant with the specified number of tickets, or adds to the participant ticket count if the participant already holds tickets.\r\n * @param participant The participant to add or to increase the ticket count for if they already hold tickets.\r\n * @param tickets The number of tickets, defaults to 1.\r\n * @returns The Lotto instance.\r\n */\r\n Lotto.prototype.add = function (participant, tickets) {\r\n if (tickets === void 0) { tickets = 1; }\r\n // Check that we have a valid ticket count.\r\n if (!(0, Utilities_1.isNaturalNumber)(tickets)) {\r\n throw new Error(\"tickets value must be a natural number\");\r\n }\r\n // Check whether this participant has already been added.\r\n var existingParticipant = this._participants.find(function (part) { return part.participant === participant; });\r\n if (existingParticipant) {\r\n // The participant has already been added to the lotto so just add to their ticket count.\r\n existingParticipant.tickets += tickets;\r\n }\r\n else {\r\n // The participant is not part of the lotto so we should add them.\r\n this._participants.push(new Participant_1.Participant(participant, tickets));\r\n }\r\n return this;\r\n };\r\n /**\r\n * Removes the specified number of tickets for the given participant from the draw, or all tickets if a ticket number is not defined.\r\n * @param participant The participant to remove tickets for.\r\n * @param tickets The number of tickets to remove, or undefined if all tickets are to be removed.\r\n * @returns The Lotto instance.\r\n */\r\n Lotto.prototype.remove = function (participant, tickets) {\r\n // Attempt to get the existing participant.\r\n var existingParticipant = this._participants.find(function (part) { return part.participant === participant; });\r\n // There is nothing to do if the specified participant isn't even part of the lotto.\r\n if (!existingParticipant) {\r\n return this;\r\n }\r\n // Check whether a tickets value was given.\r\n if (tickets !== undefined) {\r\n // Check that we have a valid ticket count.\r\n if (!(0, Utilities_1.isNaturalNumber)(tickets)) {\r\n throw new Error(\"tickets value must be a natural number\");\r\n }\r\n existingParticipant.tickets -= tickets;\r\n // If the participant no longer holds any tickets then they should be removed.\r\n if (existingParticipant.tickets < 1) {\r\n this._participants = this._participants.filter(function (part) { return part !== existingParticipant; });\r\n }\r\n }\r\n else {\r\n // We are removing all tickets for the participant so just remove them from the lotto.\r\n this._participants = this._participants.filter(function (part) { return part !== existingParticipant; });\r\n }\r\n return this;\r\n };\r\n /**\r\n * Draw a winning ticket and return the participant that holds the ticket.\r\n * @param options The draw options.\r\n * @returns The participant that holds the winning ticket.\r\n */\r\n Lotto.prototype.draw = function (options) {\r\n if (options === void 0) { options = {}; }\r\n // If we have no participants then just return null.\r\n if (this._participants.length === 0) {\r\n return null;\r\n }\r\n var redrawable = (0, Utilities_1.isNullOrUndefined)(options.redrawable) ? true : options.redrawable;\r\n var pickable = [];\r\n this._participants.forEach(function (_a) {\r\n var participant = _a.participant, tickets = _a.tickets;\r\n for (var ticketCount = 0; ticketCount < tickets; ticketCount++) {\r\n pickable.push(participant);\r\n }\r\n });\r\n var random;\r\n // We need a random floating-point number between 0 (inclusive) and 1 to scale up to pick our winner.\r\n // If a custom random function exists then we should use that or fall back to Math.random().\r\n if (this._customRandom) {\r\n // Call our custom random function to get a random floating-point number.\r\n random = this._customRandom();\r\n // Verify that the result of calling our custom random function is a number between 0 (inclusive) and 1.\r\n if (typeof random !== \"number\" || random < 0 || random >= 1) {\r\n throw new Error(\"the 'random' function provided did not return a number between 0 (inclusive) and 1\");\r\n }\r\n }\r\n else {\r\n // No custom random function was defined so just use good ol' Math.random().\r\n random = Math.random();\r\n }\r\n // Pick a winning participant.\r\n var winner = pickable[Math.floor(random * pickable.length)];\r\n // If the ticket isn't redrawable then we should remove a ticket from the winning participants ticket count.\r\n if (!redrawable) {\r\n this.remove(winner, 1);\r\n }\r\n // Return the winning participant.\r\n return winner;\r\n };\r\n /**\r\n * Draws multiple winning tickets and return an array of the participants that hold the winning tickets.\r\n * @param tickets The number of winning tickets to draw.\r\n * @param options The draw multiple options.\r\n * @returns An array of the participants that hold the winning tickets.\r\n */\r\n Lotto.prototype.drawMultiple = function (tickets, options) {\r\n if (options === void 0) { options = {}; }\r\n var uniqueResults = (0, Utilities_1.isNullOrUndefined)(options.unique) ? false : options.unique;\r\n // Handle cases where the user has asked for zero tickets (no idea why they would do this be we should trust them).\r\n if (tickets === 0) {\r\n return [];\r\n }\r\n // Now that we know out tickets value is not zero we should check that it is a valid natural number.\r\n if (!(0, Utilities_1.isNaturalNumber)(tickets)) {\r\n throw new Error(\"tickets value must be a natural number\");\r\n }\r\n var result = [];\r\n // Keep drawing tickets until we either reach the number of required tickets or we simply run out of tickets to draw.\r\n // We can run out of tickets to draw if 'options.redrawable' is explicity 'false' or we just had no participants when 'drawMultiple' was called.\r\n while (result.length < tickets && this._participants.length > 0) {\r\n result.push(this.draw(options));\r\n }\r\n // If the 'unique' draw option is set then we need to remove duplicates from the result list.\r\n if (uniqueResults) {\r\n // Create an array to store our unique results.\r\n var unique = [];\r\n // Iterate over all of our participants (with potential duplicates) and populate our array of unique values.\r\n for (var _i = 0, result_1 = result; _i < result_1.length; _i++) {\r\n var participant = result_1[_i];\r\n if (unique.indexOf(participant) === -1) {\r\n unique.push(participant);\r\n }\r\n }\r\n result = unique;\r\n }\r\n return result;\r\n };\r\n return Lotto;\r\n}());\r\nexports.Lotto = Lotto;\r\n", "\"use strict\";\r\nObject.defineProperty(exports, \"__esModule\", { value: true });\r\nexports.createLotto = void 0;\r\nvar Lotto_1 = require(\"./Lotto\");\r\n/**\r\n * A function that creates and returns a Lotto instance.\r\n * @param participantsOrOptions An array of initial participants or options relating to the creation of a Lotto instance.\r\n * @returns A new Lotto instance.\r\n */\r\nfunction createLotto(participantsOrOptions) {\r\n // If no initial participants or lotto options were provided as an argument then we can just return a new lotto instance now.\r\n if (!participantsOrOptions) {\r\n return new Lotto_1.Lotto();\r\n }\r\n // Check whether we were provided with an array of initial participants or a lotto options object.\r\n if (Array.isArray(participantsOrOptions)) {\r\n // We are dealing with a pre-defined array of participants.\r\n var participants = participantsOrOptions;\r\n var lotto_1 = new Lotto_1.Lotto();\r\n // If the lotto participants have been defined upfront then we will need to add them all to our lotto instance now.\r\n participants.forEach(function (_a) {\r\n var participant = _a[0], tokens = _a[1];\r\n return lotto_1.add(participant, tokens);\r\n });\r\n // Return the Lotto instance.\r\n return lotto_1;\r\n }\r\n else {\r\n // We are dealing with some lotto options.\r\n var random = participantsOrOptions.random, participants = participantsOrOptions.participants;\r\n // Create a Lotto instance passing the custom RNG function to use in place of Math.random() (which could be undefined).\r\n var lotto_2 = new Lotto_1.Lotto(random);\r\n // If the lotto participants have been defined upfront as part of the options then we will need to add them all to our lotto instance now.\r\n if (participants) {\r\n participants.forEach(function (_a) {\r\n var participant = _a[0], tokens = _a[1];\r\n return lotto_2.add(participant, tokens);\r\n });\r\n }\r\n // Return the Lotto instance.\r\n return lotto_2;\r\n }\r\n}\r\nexports.createLotto = createLotto;\r\n", "\"use strict\";\r\nObject.defineProperty(exports, \"__esModule\", { value: true });\r\nvar createLotto_1 = require(\"./createLotto\");\r\nexports.default = createLotto_1.createLotto;\r\n", "import { BehaviourTree, FlattenedTreeNode } from \"./BehaviourTree\";\nimport State from \"./State\";\n\nexport { BehaviourTree, State };\nexport type { FlattenedTreeNode };\n", "import Node from \"../../nodes/Node\";\n\n/**\n * An exception thrown when evaluating node guard path conditions and a conditions fails.\n */\nexport default class GuardUnsatisifedException extends Error {\n /**\n * @param source The node at which a guard condition failed.\n */\n constructor(private source: Node) {\n super(\"A guard path condition has failed\");\n }\n\n /**\n * Gets whether the specified node is the node at which a guard condition failed.\n * @param node The node to check against the source node.\n * @returns Whether the specified node is the node at which a guard condition failed.\n */\n isSourceNode = (node: Node) => node === this.source;\n}\n", "import { Agent } from \"../../Agent\";\nimport Guard from \"./Guard\";\nimport Node from \"../../nodes/Node\";\nimport GuardUnsatisifedException from \"./GuardUnsatisifedException\";\n\nexport type GuardPathPart = {\n node: Node;\n guards: Guard[];\n};\n\n/**\n * Represents a path of node guards along a root-to-leaf tree path.\n */\nexport default class GuardPath {\n /**\n * @param nodes An array of objects defining a node instance -> guard link, ordered by node depth.\n */\n constructor(private nodes: GuardPathPart[]) {}\n\n /**\n * Evaluate guard conditions for all guards in the tree path, moving outwards from the root.\n * @param agent The agent, required for guard evaluation.\n * @returns An evaluation results object.\n */\n evaluate = (agent: Agent) => {\n // We need to evaluate guard conditions for nodes up the tree, moving outwards from the root.\n for (const details of this.nodes) {\n // There can be multiple guards per node.\n for (const guard of details.guards) {\n // Check whether the guard condition passes, and throw an exception if not.\n if (!guard.isSatisfied(agent)) {\n throw new GuardUnsatisifedException(details.node);\n }\n }\n }\n };\n}\n", "/**\n * Enumeration of node state types.\n */\nexport enum State {\n READY = \"mistreevous.ready\",\n RUNNING = \"mistreevous.running\",\n SUCCEEDED = \"mistreevous.succeeded\",\n FAILED = \"mistreevous.failed\"\n}\n\nexport { State as default };\n\nexport type CompleteState = State.SUCCEEDED | State.FAILED;\nexport type AnyState = State.READY | State.RUNNING | CompleteState;\n", "import { Agent } from \"../Agent\";\nimport Attribute from \"../attributes/Attribute\";\nimport Entry from \"../attributes/callbacks/Entry\";\nimport Exit from \"../attributes/callbacks/Exit\";\nimport Step from \"../attributes/callbacks/Step\";\nimport Guard from \"../attributes/guards/Guard\";\nimport GuardPath from \"../attributes/guards/GuardPath\";\nimport GuardUnsatisifedException from \"../attributes/guards/GuardUnsatisifedException\";\nimport { BehaviourTreeOptions } from \"../BehaviourTreeOptions\";\nimport { AnyArgument } from \"../RootAstNodesBuilder\";\nimport State, { AnyState } from \"../State\";\nimport Leaf from \"./leaf/Leaf\";\n\n/**\n * A base node.\n */\nexport default abstract class Node {\n /**\n * The node uid.\n */\n private readonly uid: string = createNodeUid();\n /**\n * The node state.\n */\n private state: AnyState = State.READY;\n /**\n * The guard path to evaluate as part of a node update.\n */\n private guardPath: GuardPath | undefined;\n\n /**\n * @param type The node type.\n * @param attributes The node attributes.\n * @param args The node argument definitions.\n */\n constructor(private type: string, private attributes: Attribute[], private args: AnyArgument[]) {}\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected abstract onUpdate(agent: Agent, options: BehaviourTreeOptions): void;\n\n /**\n * Gets the name of the node.\n */\n public abstract getName(): string;\n\n /**\n * Gets whether this node is a leaf node.\n */\n public abstract isLeafNode: () => this is Leaf;\n\n /**\n * Gets/Sets the state of the node.\n */\n getState = (): AnyState => this.state;\n setState = (value: AnyState): void => {\n this.state = value;\n };\n\n /**\n * Gets the unique id of the node.\n */\n getUid = () => this.uid;\n\n /**\n * Gets the type of the node.\n */\n getType = () => this.type;\n\n /**\n * Gets the node attributes.\n */\n getAttributes = () => this.attributes;\n\n /**\n * Gets the node arguments.\n */\n getArguments = () => this.args;\n\n /**\n * Gets the node attribute with the specified type, or null if it does not exist.\n */\n getAttribute(type: \"entry\" | \"ENTRY\"): Entry;\n getAttribute(type: \"exit\" | \"EXIT\"): Exit;\n getAttribute(type: \"step\" | \"STEP\"): Step;\n getAttribute(type: string): Attribute {\n return (\n this.getAttributes().filter((decorator) => decorator.getType().toUpperCase() === type.toUpperCase())[0] ||\n null\n );\n }\n\n /**\n * Gets the node attributes.\n */\n getGuardAttributes = (): Guard[] => this.getAttributes().filter((decorator) => decorator.isGuard()) as Guard[];\n\n /**\n * Sets the guard path to evaluate as part of a node update.\n */\n setGuardPath = (value: GuardPath) => (this.guardPath = value);\n\n /**\n * Gets whether a guard path is assigned to this node.\n */\n hasGuardPath = () => !!this.guardPath;\n\n /**\n * Gets whether this node is in the specified state.\n * @param value The value to compare to the node state.\n */\n public is(value: AnyState): boolean {\n return this.state === value;\n }\n\n /**\n * Reset the state of the node.\n */\n public reset(): void {\n this.setState(State.READY);\n }\n\n /**\n * Abort the running of this node.\n * @param agent The agent.\n */\n public abort(agent: Agent): void {\n // There is nothing to do if this node is not in the running state.\n if (!this.is(State.RUNNING)) {\n return;\n }\n\n // Reset the state of this node.\n this.reset();\n\n this.getAttribute(\"exit\")?.callAgentFunction(agent, false, true);\n }\n\n /**\n * Update the node.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n * @returns The result of the update.\n */\n public update(agent: Agent, options: BehaviourTreeOptions): void {\n // If this node is already in a 'SUCCEEDED' or 'FAILED' state then there is nothing to do.\n if (this.is(State.SUCCEEDED) || this.is(State.FAILED)) {\n return;\n }\n\n try {\n // Evaluate all of the guard path conditions for the current tree path.\n this.guardPath!.evaluate(agent);\n\n // If this node is in the READY state then call the ENTRY for this node if it exists.\n if (this.is(State.READY)) {\n this.getAttribute(\"entry\")?.callAgentFunction(agent);\n }\n\n this.getAttribute(\"step\")?.callAgentFunction(agent);\n\n // Do the actual update.\n this.onUpdate(agent, options);\n\n // If this node is now in a 'SUCCEEDED' or 'FAILED' state then call the EXIT for this node if it exists.\n if (this.is(State.SUCCEEDED) || this.is(State.FAILED)) {\n this.getAttribute(\"exit\")?.callAgentFunction(agent, this.is(State.SUCCEEDED), false);\n }\n } catch (error) {\n // If the error is a GuardUnsatisfiedException then we need to determine if this node is the source.\n if (error instanceof GuardUnsatisifedException && error.isSourceNode(this)) {\n // Abort the current node.\n this.abort(agent);\n\n // Any node that is the source of an abort will be a failed node.\n this.setState(State.FAILED);\n } else {\n throw error;\n }\n }\n }\n}\n\n/**\n * Create a randomly generated node uid.\n * @returns A randomly generated node uid.\n */\nfunction createNodeUid(): string {\n var S4 = function () {\n return (((1 + Math.random()) * 0x10000) | 0).toString(16).substring(1);\n };\n return S4() + S4() + \"-\" + S4() + \"-\" + S4() + \"-\" + S4() + \"-\" + S4() + S4() + S4();\n}\n", "import Node from \"../Node\";\n\n/**\n * A leaf node.\n */\nexport default abstract class Leaf extends Node {\n /**\n * Gets whether this node is a leaf node.\n */\n isLeafNode = () => true;\n}\n", "import { ActionResult, Agent, ExitFunctionArg, FunctionArg, GlobalFunction } from \"./Agent\";\nimport { AnyArgument, RootAstNode } from \"./RootAstNodesBuilder\";\n\n// Exit callbacks receive their own special type of argument.\n// There's probably stricter ways to represent this but it feels overly complex right now.\ntype ExitResultArg = { value: ExitFunctionArg };\nexport type AnyExitArgument = AnyArgument | ExitResultArg;\n\nexport type InvokerFunction = (args: AnyExitArgument[]) => ActionResult;\n\n/**\n * A singleton used to store and lookup registered functions and subtrees.\n */\nexport default class Lookup {\n /**\n * The object holding any registered functions keyed on function name.\n */\n private static functionTable: { [key: string]: GlobalFunction } = {};\n /**\n * The object holding any registered sub-trees keyed on tree name.\n */\n private static subtreeTable: { [key: string]: RootAstNode } = {};\n\n /**\n * Gets the function with the specified name.\n * @param name The name of the function.\n * @returns The function with the specified name.\n */\n public static getFunc(name: string): GlobalFunction {\n return this.functionTable[name];\n }\n\n /**\n * Sets the function with the specified name for later lookup.\n * @param name The name of the function.\n * @param func The function.\n */\n public static setFunc(name: string, func: GlobalFunction): void {\n this.functionTable[name] = func;\n }\n\n /**\n * Gets the function invoker for the specified agent and function name.\n * If a function with the specified name exists on the agent object then it will\n * be returned, otherwise we will then check the registered functions for a match.\n * @param agent The agent instance that this behaviour tree is modelling behaviour for.\n * @param name The function name.\n * @returns The function invoker for the specified agent and function name.\n */\n static getFuncInvoker(agent: Agent, name: string): InvokerFunction | null {\n // Check whether the agent contains the specified function.\n const foundOnAgent = agent[name];\n if (foundOnAgent && typeof foundOnAgent === \"function\") {\n return (args: AnyExitArgument[]): boolean | ActionResult =>\n foundOnAgent.apply(\n agent,\n args.map((arg) => arg.value)\n );\n }\n\n // The agent does not contain the specified function but it may have been registered at some point.\n if (this.functionTable[name] && typeof this.functionTable[name] === \"function\") {\n return (args: AnyExitArgument[]) => this.functionTable[name](agent, ...args.map((arg) => arg.value));\n }\n\n // We have no function to invoke.\n return null;\n }\n\n /**\n * Gets the subtree with the specified name.\n * @param name The name of the subtree.\n * @returns The subtree with the specified name.\n */\n static getSubtree(name: string): RootAstNode {\n return this.subtreeTable[name];\n }\n\n /**\n * Sets the subtree with the specified name for later lookup.\n * @param name The name of the subtree.\n * @param subtree The subtree.\n */\n static setSubtree(name: string, subtree: RootAstNode) {\n this.subtreeTable[name] = subtree;\n }\n\n /**\n * Removes the registered function or subtree with the specified name.\n * @param name The name of the registered function or subtree.\n */\n static remove(name: string) {\n delete this.functionTable[name];\n delete this.subtreeTable[name];\n }\n\n /**\n * Remove all registered functions and subtrees.\n */\n static empty() {\n this.functionTable = {};\n this.subtreeTable = {};\n }\n}\n", "import Leaf from \"./Leaf\";\nimport State, { CompleteState } from \"../../State\";\nimport Lookup from \"../../Lookup\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { AnyArgument } from \"../../RootAstNodesBuilder\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * An Action leaf node.\n * This represents an immediate or ongoing state of behaviour.\n */\nexport default class Action extends Leaf {\n /**\n * @param attributes The node attributes.\n * @param actionName The action name.\n * @param actionArguments The array of action argument definitions.\n */\n constructor(attributes: Attribute[], private actionName: string, private actionArguments: AnyArgument[]) {\n super(\"action\", attributes, actionArguments);\n }\n\n /**\n * Whether there is a pending update promise.\n */\n private isUsingUpdatePromise = false;\n\n /**\n * The finished state result of an update promise.\n */\n private updatePromiseStateResult: CompleteState | null = null;\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // If the result of this action depends on an update promise then there is nothing to do until\n // it resolves, unless there has been a value set as a result of the update promise resolving.\n if (this.isUsingUpdatePromise) {\n // Check whether the update promise has resolved with a state value.\n if (this.updatePromiseStateResult) {\n // Set the state of this node to match the state returned by the promise.\n this.setState(this.updatePromiseStateResult);\n }\n\n return;\n }\n\n // Attempt to get the invoker for the action function.\n const actionFuncInvoker = Lookup.getFuncInvoker(agent, this.actionName);\n\n // The action function should be defined.\n if (actionFuncInvoker === null) {\n throw new Error(\n `cannot update action node as the action '${this.actionName}' function is not defined on the agent and has not been registered`\n );\n }\n\n // Call the action function, the result of which may be:\n // - The finished state of this action node.\n // - A promise to return a finished node state.\n // - Undefined if the node should remain in the running state.\n const updateResult = actionFuncInvoker(this.actionArguments) as CompleteState | Promise;\n\n if (updateResult instanceof Promise) {\n updateResult.then(\n (result) => {\n // If 'isUpdatePromisePending' is null then the promise was cleared as it was resolving, probably via an abort of reset.\n if (!this.isUsingUpdatePromise) {\n return;\n }\n\n // Check to make sure the result is a valid finished state.\n if (result !== State.SUCCEEDED && result !== State.FAILED) {\n throw new Error(\n \"action node promise resolved with an invalid value, expected a State.SUCCEEDED or State.FAILED value to be returned\"\n );\n }\n\n // Set pending update promise state result to be processed on next update.\n this.updatePromiseStateResult = result;\n },\n (reason) => {\n // If 'isUpdatePromisePending' is null then the promise was cleared as it was resolving, probably via an abort of reset.\n if (!this.isUsingUpdatePromise) {\n return;\n }\n\n // Just throw whatever was returned as the rejection argument.\n throw new Error(reason);\n }\n );\n\n // This node will be in the 'RUNNING' state until the update promise resolves.\n this.setState(State.RUNNING);\n\n // We are now waiting for the promise returned by the use to resolve before we know what state this node is in.\n this.isUsingUpdatePromise = true;\n } else {\n // Validate the returned value.\n this.validateUpdateResult(updateResult);\n\n // Set the state of this node, this may be undefined, which just means that the node is still in the 'RUNNING' state.\n this.setState(updateResult || State.RUNNING);\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => this.actionName;\n\n /**\n * Reset the state of the node.\n */\n reset = () => {\n // Reset the state of this node.\n this.setState(State.READY);\n\n // There is no longer an update promise that we care about.\n this.isUsingUpdatePromise = false;\n this.updatePromiseStateResult = null;\n };\n\n /**\n * Validate the result of an update function call.\n * @param result The result of an update function call.\n */\n private validateUpdateResult = (result: CompleteState | boolean) => {\n switch (result) {\n case State.SUCCEEDED:\n case State.FAILED:\n case undefined:\n return;\n default:\n throw new Error(\n `action '${this.actionName}' 'onUpdate' returned an invalid response, expected an optional State.SUCCEEDED or State.FAILED value to be returned`\n );\n }\n };\n}\n", "import Leaf from \"./Leaf\";\nimport State from \"../../State\";\nimport Lookup from \"../../Lookup\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { AnyArgument } from \"../../RootAstNodesBuilder\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A Condition leaf node.\n * This will succeed or fail immediately based on an agent predicate, without moving to the 'RUNNING' state.\n */\nexport default class Condition extends Leaf {\n /**\n * @param attributes The node attributes.\n * @param conditionName The name of the condition function.\n * @param conditionArguments The array of condition argument definitions.\n */\n constructor(attributes: Attribute[], private conditionName: string, private conditionArguments: AnyArgument[]) {\n super(\"condition\", attributes, conditionArguments);\n }\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // Attempt to get the invoker for the condition function.\n const conditionFuncInvoker = Lookup.getFuncInvoker(agent, this.conditionName);\n\n // The condition function should be defined.\n if (conditionFuncInvoker === null) {\n throw new Error(\n `cannot update condition node as the condition '${this.conditionName}' function is not defined on the agent and has not been registered`\n );\n }\n\n // Call the condition function to determine the state of this node.\n this.setState(!!conditionFuncInvoker(this.conditionArguments) ? State.SUCCEEDED : State.FAILED);\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => this.conditionName;\n}\n", "import Leaf from \"./Leaf\";\nimport State from \"../../State\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { Agent } from \"../../Agent\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A WAIT node.\n * The state of this node will change to SUCCEEDED after a duration of time\n */\nexport default class Wait extends Leaf {\n /**\n * @param attributes The node attributes.\n * @param duration The duration that this node will wait to succeed in milliseconds, or the earliest if longestDuration is defined.\n * @param longestDuration The longest possible duration in milliseconds that this node will wait to succeed.\n */\n constructor(attributes: Attribute[], private duration: number, private longestDuration: number) {\n super(\"wait\", attributes, []);\n }\n\n /**\n * The time in milliseconds at which this node was first updated.\n */\n private initialUpdateTime: number = 0;\n\n /**\n * The total duration in milliseconds that this node will be waiting for.\n */\n private totalDuration: number = 0;\n\n /**\n * The duration in milliseconds that this node has been waiting for.\n */\n private waitedDuration: number = 0;\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // If this node is in the READY state then we need to set the initial update time.\n if (this.is(State.READY)) {\n // Set the initial update time.\n this.initialUpdateTime = new Date().getTime();\n\n // Set the initial waited duration.\n this.waitedDuration = 0;\n\n // If a longestDuration value was defined then we will be randomly picking a duration between the\n // shortest and longest duration. If it was not defined, then we will be just using the duration.\n this.totalDuration = this.longestDuration\n ? Math.floor(Math.random() * (this.longestDuration - this.duration + 1) + this.duration)\n : this.duration;\n\n // The node is now running until we finish waiting.\n this.setState(State.RUNNING);\n }\n\n // If we have a 'getDeltaTime' function defined as part of our options then we will use it to figure out how long we have waited for.\n if (typeof options.getDeltaTime === \"function\") {\n // Get the delta time.\n const deltaTime = options.getDeltaTime();\n\n // Our delta time must be a valid number and cannot be NaN.\n if (typeof deltaTime !== \"number\" || isNaN(deltaTime)) {\n throw new Error(\"The delta time must be a valid number and not NaN.\");\n }\n\n // Update the amount of time that this node has been waiting for based on the delta time.\n this.waitedDuration += deltaTime * 1000;\n } else {\n // We are not using a delta time, so we will just work out hom much time has passed since the first update.\n this.waitedDuration = new Date().getTime() - this.initialUpdateTime;\n }\n\n // Have we waited long enough?\n if (this.waitedDuration >= this.totalDuration) {\n // We have finished waiting!\n this.setState(State.SUCCEEDED);\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () =>\n `WAIT ${this.longestDuration ? this.duration + \"ms-\" + this.longestDuration + \"ms\" : this.duration + \"ms\"}`;\n}\n", "import Node from \"../Node\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\n\n/**\n * A decorator node that wraps a single child node.\n */\nexport default abstract class Decorator extends Node {\n /**\n * @param type The node type.\n * @param attributes The node attributes.\n * @param child The child node.\n */\n constructor(type: string, attributes: Attribute[], protected child: Node) {\n super(type, attributes, []);\n }\n\n /**\n * Gets whether this node is a leaf node.\n */\n isLeafNode = () => false;\n\n /**\n * Gets the children of this node.\n */\n getChildren = () => [this.child];\n\n /**\n * Reset the state of the node.\n */\n reset = () => {\n // Reset the state of this node.\n this.setState(State.READY);\n\n // Reset the state of the child node.\n this.child.reset();\n };\n\n /**\n * Abort the running of this node.\n * @param agent The agent.\n */\n abort = (agent: Agent) => {\n // There is nothing to do if this node is not in the running state.\n if (!this.is(State.RUNNING)) {\n return;\n }\n\n // Abort the child node.\n this.child.abort(agent);\n\n // Reset the state of this node.\n this.reset();\n\n this.getAttribute(\"exit\")?.callAgentFunction(agent, false, true);\n };\n}\n", "import Node from \"../Node\";\nimport Decorator from \"./Decorator\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A Root node.\n * The root node will have a single child.\n */\nexport default class Root extends Decorator {\n /**\n * @param attributes The node attributes.\n * @param child The child node.\n */\n constructor(attributes: Attribute[], child: Node) {\n super(\"root\", attributes, child);\n }\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // If the child has never been updated or is running then we will need to update it now.\n if (this.child.getState() === State.READY || this.child.getState() === State.RUNNING) {\n // Update the child of this node.\n this.child.update(agent, options);\n }\n\n // The state of the root node is the state of its child.\n this.setState(this.child.getState());\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => \"ROOT\";\n}\n", "import Node from \"../Node\";\nimport Decorator from \"./Decorator\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A REPEAT node.\n * The node has a single child which can have:\n * -- A number of iterations for which to repeat the child node.\n * -- An infinite repeat loop if neither an iteration count or a condition function is defined.\n * The REPEAT node will stop and have a 'FAILED' state if its child is ever in a 'FAILED' state after an update.\n * The REPEAT node will attempt to move on to the next iteration if its child is ever in a 'SUCCEEDED' state.\n */\nexport default class Repeat extends Decorator {\n /**\n * @param attributes The node attributes.\n * @param iterations The number of iterations to repeat the child node, or the minimum number of iterations if maximumIterations is defined.\n * @param maximumIterations The maximum number of iterations to repeat the child node.\n * @param child The child node.\n */\n constructor(\n attributes: Attribute[],\n private iterations: number | null,\n private maximumIterations: number | null,\n child: Node\n ) {\n super(\"repeat\", attributes, child);\n }\n\n /**\n * The number of target iterations to make.\n */\n private targetIterationCount: number | null = null;\n\n /**\n * The current iteration count.\n */\n private currentIterationCount: number = 0;\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // If this node is in the READY state then we need to reset the child and the target iteration count.\n if (this.is(State.READY)) {\n // Reset the child node.\n this.child.reset();\n\n // Set the target iteration count.\n this.setTargetIterationCount();\n }\n\n // Do a check to see if we can iterate. If we can then this node will move into the 'RUNNING' state.\n // If we cannot iterate then we have hit our target iteration count, which means that the node has succeeded.\n if (this.canIterate()) {\n // This node is in the running state and can do its initial iteration.\n this.setState(State.RUNNING);\n\n // We may have already completed an iteration, meaning that the child node will be in the SUCCEEDED state.\n // If this is the case then we will have to reset the child node now.\n if (this.child.getState() === State.SUCCEEDED) {\n this.child.reset();\n }\n\n // Update the child of this node.\n this.child.update(agent, options);\n\n // If the child moved into the FAILED state when we updated it then there is nothing left to do and this node has also failed.\n // If it has moved into the SUCCEEDED state then we have completed the current iteration.\n if (this.child.getState() === State.FAILED) {\n // The child has failed, meaning that this node has failed.\n this.setState(State.FAILED);\n\n return;\n } else if (this.child.getState() === State.SUCCEEDED) {\n // We have completed an iteration.\n this.currentIterationCount += 1;\n }\n } else {\n // This node is in the 'SUCCEEDED' state as we cannot iterate any more.\n this.setState(State.SUCCEEDED);\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => {\n if (this.iterations !== null) {\n return `REPEAT ${\n this.maximumIterations ? this.iterations + \"x-\" + this.maximumIterations + \"x\" : this.iterations + \"x\"\n }`;\n }\n\n // Return the default repeat node name.\n return \"REPEAT\";\n };\n\n /**\n * Reset the state of the node.\n */\n reset = () => {\n // Reset the state of this node.\n this.setState(State.READY);\n\n // Reset the current iteration count.\n this.currentIterationCount = 0;\n\n // Reset the child node.\n this.child.reset();\n };\n\n /**\n * Gets whether an iteration can be made.\n * @returns Whether an iteration can be made.\n */\n private canIterate = () => {\n if (this.targetIterationCount !== null) {\n // We can iterate as long as we have not reached our target iteration count.\n return this.currentIterationCount < this.targetIterationCount;\n }\n\n // If neither an iteration count or a condition function were defined then we can iterate indefinitely.\n return true;\n };\n\n /**\n * Sets the target iteration count.\n */\n private setTargetIterationCount = () => {\n // Are we dealing with a finite number of iterations?\n if (typeof this.iterations === \"number\") {\n // If we have maximumIterations defined then we will want a random iteration count bounded by iterations and maximumIterations.\n this.targetIterationCount =\n typeof this.maximumIterations === \"number\"\n ? Math.floor(Math.random() * (this.maximumIterations - this.iterations + 1) + this.iterations)\n : this.iterations;\n } else {\n this.targetIterationCount = null;\n }\n };\n}\n", "import Node from \"../Node\";\nimport Decorator from \"./Decorator\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A RETRY node.\n * The node has a single child which can have:\n * -- A number of iterations for which to repeat the child node.\n * -- An infinite repeat loop if neither an iteration count or a condition function is defined.\n * The RETRY node will stop and have a 'SUCCEEDED' state if its child is ever in a 'SUCCEEDED' state after an update.\n * The RETRY node will attempt to move on to the next iteration if its child is ever in a 'FAILED' state.\n */\nexport default class Retry extends Decorator {\n /**\n * @param attributes The node attributes.\n * @param iterations The number of iterations to repeat the child node, or the minimum number of iterations if maximumIterations is defined.\n * @param maximumIterations The maximum number of iterations to repeat the child node.\n * @param child The child node.\n */\n constructor(\n attributes: Attribute[],\n private iterations: number | null,\n private maximumIterations: number | null,\n child: Node\n ) {\n super(\"retry\", attributes, child);\n }\n\n /**\n * The number of target iterations to make.\n */\n private targetIterationCount: number | null = null;\n\n /**\n * The current iteration count.\n */\n private currentIterationCount: number = 0;\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // If this node is in the READY state then we need to reset the child and the target iteration count.\n if (this.is(State.READY)) {\n // Reset the child node.\n this.child.reset();\n\n // Set the target iteration count.\n this.setTargetIterationCount();\n }\n\n // Do a check to see if we can iterate. If we can then this node will move into the 'RUNNING' state.\n // If we cannot iterate then we have hit our target iteration count, which means that the node has succeeded.\n if (this.canIterate()) {\n // This node is in the running state and can do its initial iteration.\n this.setState(State.RUNNING);\n\n // We may have already completed an iteration, meaning that the child node will be in the FAILED state.\n // If this is the case then we will have to reset the child node now.\n if (this.child.getState() === State.FAILED) {\n this.child.reset();\n }\n\n // Update the child of this node.\n this.child.update(agent, options);\n\n // If the child moved into the SUCCEEDED state when we updated it then there is nothing left to do and this node has also succeeded.\n // If it has moved into the FAILED state then we have completed the current iteration.\n if (this.child.getState() === State.SUCCEEDED) {\n // The child has succeeded, meaning that this node has succeeded.\n this.setState(State.SUCCEEDED);\n\n return;\n } else if (this.child.getState() === State.FAILED) {\n // We have completed an iteration.\n this.currentIterationCount += 1;\n }\n } else {\n // This node is in the 'FAILED' state as we cannot iterate any more.\n this.setState(State.FAILED);\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => {\n if (this.iterations !== null) {\n return `RETRY ${\n this.maximumIterations ? this.iterations + \"x-\" + this.maximumIterations + \"x\" : this.iterations + \"x\"\n }`;\n }\n\n // Return the default retry node name.\n return \"RETRY\";\n };\n\n /**\n * Reset the state of the node.\n */\n reset = () => {\n // Reset the state of this node.\n this.setState(State.READY);\n\n // Reset the current iteration count.\n this.currentIterationCount = 0;\n\n // Reset the child node.\n this.child.reset();\n };\n\n /**\n * Gets whether an iteration can be made.\n * @returns Whether an iteration can be made.\n */\n canIterate = () => {\n if (this.targetIterationCount !== null) {\n // We can iterate as long as we have not reached our target iteration count.\n return this.currentIterationCount < this.targetIterationCount;\n }\n\n // If neither an iteration count or a condition function were defined then we can iterate indefinitely.\n return true;\n };\n\n /**\n * Sets the target iteration count.\n */\n setTargetIterationCount = () => {\n // Are we dealing with a finite number of iterations?\n if (typeof this.iterations === \"number\") {\n // If we have maximumIterations defined then we will want a random iteration count bounded by iterations and maximumIterations.\n this.targetIterationCount =\n typeof this.maximumIterations === \"number\"\n ? Math.floor(Math.random() * (this.maximumIterations - this.iterations + 1) + this.iterations)\n : this.iterations;\n } else {\n this.targetIterationCount = null;\n }\n };\n}\n", "import Decorator from \"./Decorator\";\nimport State from \"../../State\";\nimport Node from \"../Node\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A Flip node.\n * This node wraps a single child and will flip the state of the child state.\n */\nexport default class Flip extends Decorator {\n /**\n * @param attributes The node attributes.\n * @param child The child node.\n */\n constructor(attributes: Attribute[], child: Node) {\n super(\"flip\", attributes, child);\n }\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // If the child has never been updated or is running then we will need to update it now.\n if (this.child.getState() === State.READY || this.child.getState() === State.RUNNING) {\n this.child.update(agent, options);\n }\n\n // The state of this node will depend in the state of its child.\n switch (this.child.getState()) {\n case State.RUNNING:\n this.setState(State.RUNNING);\n break;\n\n case State.SUCCEEDED:\n this.setState(State.FAILED);\n break;\n\n case State.FAILED:\n this.setState(State.SUCCEEDED);\n break;\n\n default:\n this.setState(State.READY);\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => \"FLIP\";\n}\n", "import Node from \"../Node\";\nimport Decorator from \"./Decorator\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A Succeed node.\n * This node wraps a single child and will always move to the 'SUCCEEDED' state when the child moves to a 'SUCCEEDED' or 'FAILED' state.\n */\nexport default class Succeed extends Decorator {\n /**\n * @param attributes The node attributes.\n * @param child The child node.\n */\n constructor(attributes: Attribute[], child: Node) {\n super(\"succeed\", attributes, child);\n }\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // If the child has never been updated or is running then we will need to update it now.\n if (this.child.getState() === State.READY || this.child.getState() === State.RUNNING) {\n this.child.update(agent, options);\n }\n\n // The state of this node will depend in the state of its child.\n switch (this.child.getState()) {\n case State.RUNNING:\n this.setState(State.RUNNING);\n break;\n\n case State.SUCCEEDED:\n case State.FAILED:\n this.setState(State.SUCCEEDED);\n break;\n\n default:\n this.setState(State.READY);\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => \"SUCCEED\";\n}\n", "import Node from \"../Node\";\nimport Decorator from \"./Decorator\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A Fail node.\n * This node wraps a single child and will always move to the 'FAILED' state when the child moves to a 'SUCCEEDED' or 'FAILED' state.\n */\nexport default class Fail extends Decorator {\n /**\n * @param attributes The node attributes.\n * @param child The child node.\n */\n constructor(attributes: Attribute[], child: Node) {\n super(\"fail\", attributes, child);\n }\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // If the child has never been updated or is running then we will need to update it now.\n if (this.child.getState() === State.READY || this.child.getState() === State.RUNNING) {\n this.child.update(agent, options);\n }\n\n // The state of this node will depend in the state of its child.\n switch (this.child.getState()) {\n case State.RUNNING:\n this.setState(State.RUNNING);\n break;\n\n case State.SUCCEEDED:\n case State.FAILED:\n this.setState(State.FAILED);\n break;\n\n default:\n this.setState(State.READY);\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => \"FAIL\";\n}\n", "import createLotto from \"lotto-draw\";\r\n\r\nimport Node from \"../Node\";\r\nimport Composite from \"./Composite\";\r\nimport State from \"../../State\";\r\nimport { Agent } from \"../../Agent\";\r\nimport Attribute from \"../../attributes/Attribute\";\r\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\r\n\r\n/**\r\n * A LOTTO node.\r\n * A winning child is picked on the initial update of this node, based on ticket weighting.\r\n * The state of this node will match the state of the winning child.\r\n */\r\nexport default class Lotto extends Composite {\r\n /**\r\n * @param attributes The node attributes.\r\n * @param tickets The child node tickets.\r\n * @param children The child nodes.\r\n */\r\n constructor(attributes: Attribute[], private tickets: number[], children: Node[]) {\r\n super(\"lotto\", attributes, children);\r\n }\r\n\r\n /**\r\n * The child node selected to be the active one.\r\n */\r\n private selectedChild: Node | undefined;\r\n\r\n /**\r\n * Called when the node is being updated.\r\n * @param agent The agent.\r\n * @param options The behaviour tree options object.\r\n */\r\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\r\n // If this node is in the READY state then we need to pick a winning child node.\r\n if (this.is(State.READY)) {\r\n // Create a lotto draw with which to randomly pick a child node to become the active one.\r\n const lottoDraw = createLotto({\r\n // Hook up the optional 'random' behaviour tree function option to the one used by 'lotto-draw'.\r\n random: options.random,\r\n // Pass in each child node as a participant in the lotto draw with their respective ticket count.\r\n participants: this.children.map((child, index) => [child, this.tickets[index] || 1])\r\n });\r\n\r\n // Randomly pick a child based on ticket weighting, this will become the active child for this composite node.\r\n this.selectedChild = lottoDraw.draw() || undefined;\r\n }\r\n\r\n // If something went wrong and we don't have an active child then we should throw an error.\r\n if (!this.selectedChild) {\r\n throw new Error(\"failed to update lotto node as it has no active child\");\r\n }\r\n\r\n // If the selected child has never been updated or is running then we will need to update it now.\r\n if (this.selectedChild.getState() === State.READY || this.selectedChild.getState() === State.RUNNING) {\r\n this.selectedChild.update(agent, options);\r\n }\r\n\r\n // The state of the lotto node is the state of its selected child.\r\n this.setState(this.selectedChild.getState());\r\n }\r\n\r\n /**\r\n * Gets the name of the node.\r\n */\r\n getName = () => (this.tickets.length ? `LOTTO [${this.tickets.join(\",\")}]` : \"LOTTO\");\r\n}\r\n", "import Node from \"../Node\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\n\n/**\n * A composite node that wraps child nodes.\n */\nexport default abstract class Composite extends Node {\n /**\n * @param type The node type.\n * @param attributes The node attributes.\n * @param children The child nodes.\n */\n constructor(type: string, attributes: Attribute[], protected children: Node[]) {\n super(type, attributes, []);\n }\n\n /**\n * Gets whether this node is a leaf node.\n */\n isLeafNode = () => false;\n\n /**\n * Gets the children of this node.\n */\n getChildren = () => this.children;\n\n /**\n * Reset the state of the node.\n */\n reset = () => {\n // Reset the state of this node.\n this.setState(State.READY);\n\n // Reset the state of any child nodes.\n this.getChildren().forEach((child) => child.reset());\n };\n\n /**\n * Abort the running of this node.\n * @param agent The agent.\n */\n abort = (agent: Agent) => {\n // There is nothing to do if this node is not in the running state.\n if (!this.is(State.RUNNING)) {\n return;\n }\n\n // Abort any child nodes.\n this.getChildren().forEach((child) => child.abort(agent));\n\n // Reset the state of this node.\n this.reset();\n\n this.getAttribute(\"exit\")?.callAgentFunction(agent, false, true);\n };\n}\n", "import Composite from \"./Composite\";\nimport Node from \"../Node\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A SELECTOR node.\n * The child nodes are executed in sequence until one succeeds or all fail.\n */\nexport default class Selector extends Composite {\n /**\n * @param attributes The node attributes.\n * @param children The child nodes.\n */\n constructor(attributes: Attribute[], protected children: Node[]) {\n super(\"selector\", attributes, children);\n }\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // Iterate over all of the children of this node.\n for (const child of this.children) {\n // If the child has never been updated or is running then we will need to update it now.\n if (child.getState() === State.READY || child.getState() === State.RUNNING) {\n // Update the child of this node.\n child.update(agent, options);\n }\n\n // If the current child has a state of 'SUCCEEDED' then this node is also a 'SUCCEEDED' node.\n if (child.getState() === State.SUCCEEDED) {\n // This node is a 'SUCCEEDED' node.\n this.setState(State.SUCCEEDED);\n\n // There is no need to check the rest of the selector nodes.\n return;\n }\n\n // If the current child has a state of 'FAILED' then we should move on to the next child.\n if (child.getState() === State.FAILED) {\n // Find out if the current child is the last one in the selector.\n // If it is then this sequence node has also failed.\n if (this.children.indexOf(child) === this.children.length - 1) {\n // This node is a 'FAILED' node.\n this.setState(State.FAILED);\n\n // There is no need to check the rest of the selector as we have completed it.\n return;\n } else {\n // The child node failed, try the next one.\n continue;\n }\n }\n\n // The node should be in the 'RUNNING' state.\n if (child.getState() === State.RUNNING) {\n // This node is a 'RUNNING' node.\n this.setState(State.RUNNING);\n\n // There is no need to check the rest of the selector as the current child is still running.\n return;\n }\n\n // The child node was not in an expected state.\n throw new Error(\"child node was not in an expected state.\");\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => \"SELECTOR\";\n}\n", "import Composite from \"./Composite\";\nimport Node from \"../Node\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A SEQUENCE node.\n * The child nodes are executed in sequence until one fails or all succeed.\n */\nexport default class Sequence extends Composite {\n /**\n * @param attributes The node attributes.\n * @param children The child nodes.\n */\n constructor(attributes: Attribute[], protected children: Node[]) {\n super(\"sequence\", attributes, children);\n }\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // Iterate over all of the children of this node.\n for (const child of this.children) {\n // If the child has never been updated or is running then we will need to update it now.\n if (child.getState() === State.READY || child.getState() === State.RUNNING) {\n // Update the child of this node.\n child.update(agent, options);\n }\n\n // If the current child has a state of 'SUCCEEDED' then we should move on to the next child.\n if (child.getState() === State.SUCCEEDED) {\n // Find out if the current child is the last one in the sequence.\n // If it is then this sequence node has also succeeded.\n if (this.children.indexOf(child) === this.children.length - 1) {\n // This node is a 'SUCCEEDED' node.\n this.setState(State.SUCCEEDED);\n\n // There is no need to check the rest of the sequence as we have completed it.\n return;\n } else {\n // The child node succeeded, but we have not finished the sequence yet.\n continue;\n }\n }\n\n // If the current child has a state of 'FAILED' then this node is also a 'FAILED' node.\n if (child.getState() === State.FAILED) {\n // This node is a 'FAILED' node.\n this.setState(State.FAILED);\n\n // There is no need to check the rest of the sequence.\n return;\n }\n\n // The node should be in the 'RUNNING' state.\n if (child.getState() === State.RUNNING) {\n // This node is a 'RUNNING' node.\n this.setState(State.RUNNING);\n\n // There is no need to check the rest of the sequence as the current child is still running.\n return;\n }\n\n // The child node was not in an expected state.\n throw new Error(\"child node was not in an expected state.\");\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => \"SEQUENCE\";\n}\n", "import Composite from \"./Composite\";\nimport State from \"../../State\";\nimport Node from \"../Node\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A PARALLEL node.\n * The child nodes are executed concurrently until one fails or all succeed.\n */\nexport default class Parallel extends Composite {\n /**\n * @param attributes The node attributes.\n * @param children The child nodes.\n */\n constructor(attributes: Attribute[], children: Node[]) {\n super(\"parallel\", attributes, children);\n }\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // Keep a count of the number of succeeded child nodes.\n let succeededCount = 0;\n\n let hasChildFailed = false;\n\n // Iterate over all of the children of this node.\n for (const child of this.children) {\n // If the child has never been updated or is running then we will need to update it now.\n if (child.getState() === State.READY || child.getState() === State.RUNNING) {\n // Update the child of this node.\n child.update(agent, options);\n }\n\n // If the current child has a state of 'SUCCEEDED' then we should move on to the next child.\n if (child.getState() === State.SUCCEEDED) {\n // The child node has succeeded, keep track of this to determine if all children have.\n succeededCount++;\n\n // The child node succeeded, but we have not finished checking every child node yet.\n continue;\n }\n\n // If the current child has a state of 'FAILED' then this node is also a 'FAILED' node.\n if (child.getState() === State.FAILED) {\n hasChildFailed = true;\n\n // There is no need to check the rest of the children.\n break;\n }\n\n // The node should be in the 'RUNNING' state.\n if (child.getState() !== State.RUNNING) {\n // The child node was not in an expected state.\n throw new Error(\"child node was not in an expected state.\");\n }\n }\n\n if (hasChildFailed) {\n // This node is a 'FAILED' node.\n this.setState(State.FAILED);\n\n // Abort every running child.\n for (const child of this.children) {\n if (child.getState() === State.RUNNING) {\n child.abort(agent);\n }\n }\n } else {\n // If all children have succeeded then this node has also succeeded, otherwise it is still running.\n this.setState(succeededCount === this.children.length ? State.SUCCEEDED : State.RUNNING);\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => \"PARALLEL\";\n}\n", "import { AnyArgument } from \"../RootAstNodesBuilder\";\nimport Guard from \"./guards/Guard\";\n\nexport type AttributeDetails = {\n /** The attribute type. */\n type: string;\n\n /** The attribute arguments. */\n args: AnyArgument[];\n};\n\n/**\n * A base node attribute.\n */\nexport default abstract class Attribute {\n /**\n * @param type The node attribute type.\n * @param args The array of attribute argument definitions.\n */\n constructor(protected type: string, protected args: AnyArgument[]) {}\n\n /**\n * Gets the type of the attribute.\n */\n getType = () => this.type;\n\n /**\n * Gets the array of attribute argument definitions.\n */\n getArguments = () => this.args;\n\n /**\n * Gets the attribute details.\n */\n abstract getDetails(): TAttributeDetails;\n\n /**\n * Gets whether this attribute is a guard.\n */\n abstract isGuard: () => this is Guard;\n}\n", "import { Agent } from \"../../Agent\";\nimport { AnyArgument } from \"../../RootAstNodesBuilder\";\nimport Attribute, { AttributeDetails } from \"../Attribute\";\n\nexport type GuardAttributeDetails = {\n /** The name of the condition function that determines whether the guard is satisfied. */\n condition: string;\n} & AttributeDetails;\n\n/**\n * A base node guard attribute.\n */\nexport default abstract class Guard extends Attribute {\n /**\n * @param type The node attribute type.\n * @param args The array of decorator argument definitions.\n * @param condition The name of the condition function that determines whether the guard is satisfied.\n */\n constructor(type: string, args: AnyArgument[], private condition: string) {\n super(type, args);\n }\n\n /**\n * Gets the name of the condition function that determines whether the guard is satisfied.\n */\n getCondition = () => this.condition;\n\n /**\n * Gets whether this attribute is a guard.\n */\n isGuard = () => true;\n\n /**\n * Gets the attribute details.\n */\n getDetails(): GuardAttributeDetails {\n return {\n type: this.getType(),\n args: this.getArguments(),\n condition: this.getCondition()\n };\n }\n\n /**\n * Gets whether the guard is satisfied.\n * @param agent The agent.\n * @returns Whether the guard is satisfied.\n */\n abstract isSatisfied(agent: Agent): boolean;\n}\n", "import Guard from \"./Guard\";\nimport Lookup from \"../../Lookup\";\nimport { Agent } from \"../../Agent\";\nimport { AnyArgument } from \"../../RootAstNodesBuilder\";\n\n/**\n * A WHILE guard which is satisfied as long as the given condition remains true.\n */\nexport default class While extends Guard {\n /**\n * @param condition The name of the condition function that determines whether the guard is satisfied.\n * @param args The array of decorator argument definitions.\n */\n constructor(condition: string, args: AnyArgument[]) {\n super(\"while\", args, condition);\n }\n\n /**\n * Gets whether the guard is satisfied.\n * @param agent The agent.\n * @returns Whether the guard is satisfied.\n */\n isSatisfied = (agent: Agent) => {\n // Attempt to get the invoker for the condition function.\n const conditionFuncInvoker = Lookup.getFuncInvoker(agent, this.getCondition());\n\n // The condition function should be defined.\n if (conditionFuncInvoker === null) {\n throw new Error(\n `cannot evaluate node guard as the condition '${this.getCondition()}' function is not defined on the agent and has not been registered`\n );\n }\n\n // Call the condition function to determine whether this guard is satisfied.\n return !!conditionFuncInvoker(this.args);\n };\n}\n", "import Guard from \"./Guard\";\nimport Lookup from \"../../Lookup\";\nimport { Agent } from \"../../Agent\";\nimport { AnyArgument } from \"../../RootAstNodesBuilder\";\n\n/**\n * An UNTIL guard which is satisfied as long as the given condition remains false.\n */\nexport default class Until extends Guard {\n /**\n * @param condition The name of the condition function that determines whether the guard is satisfied.\n * @param args The array of decorator argument definitions.\n */\n constructor(condition: string, args: AnyArgument[]) {\n super(\"until\", args, condition);\n }\n\n /**\n * Gets whether the guard is satisfied.\n * @param agent The agent.\n * @returns Whether the guard is satisfied.\n */\n isSatisfied = (agent: Agent) => {\n // Attempt to get the invoker for the condition function.\n const conditionFuncInvoker = Lookup.getFuncInvoker(agent, this.getCondition());\n\n // The condition function should be defined.\n if (conditionFuncInvoker === null) {\n throw new Error(\n `cannot evaluate node guard as the condition '${this.getCondition()}' function is not defined on the agent and has not been registered`\n );\n }\n\n // Call the condition function to determine whether this guard is satisfied.\n return !!!conditionFuncInvoker(this.args);\n };\n}\n", "import { Agent } from \"../../Agent\";\nimport { AnyArgument } from \"../../RootAstNodesBuilder\";\nimport Attribute, { AttributeDetails } from \"../Attribute\";\n\nexport type CallbackAttributeDetails = {\n /** The name of the agent function that is called. */\n functionName: string;\n} & AttributeDetails;\n\n/**\n * A base node callback attribute.\n */\nexport default abstract class Callback extends Attribute {\n /**\n * @param type The node attribute type.\n * @param args The array of decorator argument definitions.\n * @param functionName The name of the agent function to call.\n */\n constructor(type: string, args: AnyArgument[], private functionName: string) {\n super(type, args);\n }\n\n /**\n * Gets the name of the agent function to call.\n */\n getFunctionName = () => this.functionName;\n\n /**\n * Gets whether this attribute is a guard.\n */\n isGuard = () => false;\n\n /**\n * Gets the attribute details.\n */\n getDetails(): CallbackAttributeDetails {\n return {\n type: this.getType(),\n args: this.getArguments(),\n functionName: this.getFunctionName()\n };\n }\n\n /**\n * Attempt to call the agent function that this callback refers to.\n * @param agent The agent.\n */\n abstract callAgentFunction: (agent: Agent, isSuccess: boolean, isAborted: boolean) => void;\n}\n", "import Callback from \"./Callback\";\nimport Lookup from \"../../Lookup\";\nimport { Agent } from \"../../Agent\";\nimport { AnyArgument } from \"../../RootAstNodesBuilder\";\n\n/**\n * An ENTRY callback which defines an agent function to call when the associated node is updated and moves out of running state.\n */\nexport default class Entry extends Callback {\n /**\n * @param functionName The name of the agent function to call.\n * @param args The array of callback argument definitions.\n */\n constructor(functionName: string, args: AnyArgument[]) {\n super(\"entry\", args, functionName);\n }\n\n /**\n * Attempt to call the agent function that this callback refers to.\n * @param agent The agent.\n */\n callAgentFunction = (agent: Agent) => {\n // Attempt to get the invoker for the callback function.\n const callbackFuncInvoker = Lookup.getFuncInvoker(agent, this.getFunctionName());\n\n // The callback function should be defined.\n if (callbackFuncInvoker === null) {\n throw new Error(\n `cannot call entry function '${this.getFunctionName()}' as is not defined on the agent and has not been registered`\n );\n }\n\n // Call the callback function.\n callbackFuncInvoker(this.args);\n };\n}\n", "import Callback from \"./Callback\";\nimport Lookup, { AnyExitArgument } from \"../../Lookup\";\nimport { Agent } from \"../../Agent\";\nimport { AnyArgument } from \"../../RootAstNodesBuilder\";\n\n/**\n * An EXIT callback which defines an agent function to call when the associated node is updated and moves to a finished state or is aborted.\n */\nexport default class Exit extends Callback {\n /**\n * @param functionName The name of the agent function to call.\n * @param args The array of callback argument definitions.\n */\n constructor(functionName: string, args: AnyArgument[]) {\n super(\"exit\", args, functionName);\n }\n\n /**\n * Attempt to call the agent function that this callback refers to.\n * @param agent The agent.\n * @param isSuccess Whether the decorated node was left with a success state.\n * @param isAborted Whether the decorated node was aborted.\n */\n callAgentFunction = (agent: Agent, isSuccess: boolean, isAborted: boolean) => {\n // Attempt to get the invoker for the callback function.\n const callbackFuncInvoker = Lookup.getFuncInvoker(agent, this.getFunctionName());\n\n // The callback function should be defined.\n if (callbackFuncInvoker === null) {\n throw new Error(\n `cannot call exit function '${this.getFunctionName()}' as is not defined on the agent and has not been registered`\n );\n }\n\n // Call the callback function\n callbackFuncInvoker([{ value: { succeeded: isSuccess, aborted: isAborted } }, ...this.args]);\n };\n}\n", "import Callback from \"./Callback\";\nimport Lookup from \"../../Lookup\";\nimport { Agent } from \"../../Agent\";\nimport { AnyArgument } from \"../../RootAstNodesBuilder\";\n\n/**\n * A STEP callback which defines an agent function to call when the associated node is updated.\n */\nexport default class Step extends Callback {\n /**\n * @param functionName The name of the agent function to call.\n * @param args The array of callback argument definitions.\n */\n constructor(functionName: string, args: AnyArgument[]) {\n super(\"step\", args, functionName);\n }\n\n /**\n * Attempt to call the agent function that this callback refers to.\n * @param agent The agent.\n */\n callAgentFunction = (agent: Agent) => {\n // Attempt to get the invoker for the callback function.\n const callbackFuncInvoker = Lookup.getFuncInvoker(agent, this.getFunctionName());\n\n // The callback function should be defined.\n if (callbackFuncInvoker === null) {\n throw new Error(\n `cannot call step function '${this.getFunctionName()}' as is not defined on the agent and has not been registered`\n );\n }\n\n // Call the callback function.\n callbackFuncInvoker(this.args);\n };\n}\n", "import Action from \"./nodes/leaf/Action\";\nimport Condition from \"./nodes/leaf/Condition\";\nimport Wait from \"./nodes/leaf/Wait\";\nimport Root from \"./nodes/decorator/Root\";\nimport Repeat from \"./nodes/decorator/Repeat\";\nimport Retry from \"./nodes/decorator/Retry\";\nimport Flip from \"./nodes/decorator/Flip\";\nimport Succeed from \"./nodes/decorator/Succeed\";\nimport Fail from \"./nodes/decorator/Fail\";\nimport Lotto from \"./nodes/composite/Lotto\";\nimport Selector from \"./nodes/composite/Selector\";\nimport Sequence from \"./nodes/composite/Sequence\";\nimport Parallel from \"./nodes/composite/Parallel\";\nimport Node from \"./nodes/Node\";\nimport While from \"./attributes/guards/While\";\nimport Until from \"./attributes/guards/Until\";\nimport Entry from \"./attributes/callbacks/Entry\";\nimport Exit from \"./attributes/callbacks/Exit\";\nimport Step from \"./attributes/callbacks/Step\";\nimport Callback from \"./attributes/callbacks/Callback\";\nimport Guard from \"./attributes/guards/Guard\";\nimport Attribute from \"./attributes/Attribute\";\nimport Composite from \"./nodes/composite/Composite\";\nimport Decorator from \"./nodes/decorator/Decorator\";\nimport Leaf from \"./nodes/leaf/Leaf\";\n\nexport type Argument = {\n value: T;\n type: string; // Used for validation.\n};\ntype NullArgument = Argument & {\n type: \"null\";\n};\ntype BooleanArgument = Argument & {\n type: \"boolean\";\n};\ntype NumberArgument = Argument & {\n type: \"number\";\n isInteger: boolean; // Used for validation.\n};\ntype StringPlaceholderArgument = Argument & {\n type: \"string\";\n};\ntype IdentifierArgument = Argument & {\n type: \"identifier\";\n};\nexport type AnyArgument =\n | NullArgument\n | BooleanArgument\n | NumberArgument\n | StringPlaceholderArgument\n | IdentifierArgument;\n\n/**\n * The node attribute factories.\n */\nconst AttributeFactories: {\n [key: string]: (functionName: string, attributeArguments: AnyArgument[]) => Callback | Guard;\n} = {\n WHILE: (condition: string, attributeArguments: AnyArgument[]) => new While(condition, attributeArguments),\n UNTIL: (condition: string, attributeArguments: AnyArgument[]) => new Until(condition, attributeArguments),\n ENTRY: (functionName: string, attributeArguments: AnyArgument[]) => new Entry(functionName, attributeArguments),\n EXIT: (functionName: string, attributeArguments: AnyArgument[]) => new Exit(functionName, attributeArguments),\n STEP: (functionName: string, attributeArguments: AnyArgument[]) => new Step(functionName, attributeArguments)\n};\n\ntype Validatable = {\n children?: AstNode[];\n validate: (depth: number) => void;\n};\n\ntype NodeInstanceCreator = (\n namedRootNodeProvider: (name: string) => RootAstNode,\n visitedBranches: string[]\n) => T;\n\nexport type AstNode = Validatable & {\n type: string;\n createNodeInstance: NodeInstanceCreator;\n};\n\nexport type LeafAstNode = AstNode & {\n type: \"action\" | \"condition\" | \"wait\";\n attributes: Attribute[];\n};\n\nexport type CompositeAstNode = AstNode & {\n type: \"lotto\" | \"parallel\" | \"selector\" | \"sequence\";\n attributes: Attribute[];\n children: AstNode[];\n};\n\nexport type DecoratorAstNode = AstNode & {\n type: \"fail\" | \"flip\" | \"repeat\" | \"retry\" | \"root\" | \"succeed\";\n attributes: Attribute[];\n children: AstNode[];\n};\n\nexport type BranchAstNode = AstNode & {\n type: \"branch\";\n branchName: \"\" | string;\n};\n\nexport type LottoAstNode = CompositeAstNode & {\n type: \"lotto\";\n tickets: number[];\n};\n\nexport type RootAstNode = DecoratorAstNode & {\n type: \"root\";\n name: null | string;\n};\n\nexport type IterableAstNode = DecoratorAstNode & {\n type: \"repeat\" | \"retry\";\n iterations: null | number;\n maximumIterations: null | number;\n};\n\nexport type ActionAstNode = LeafAstNode & {\n type: \"action\";\n actionName: string;\n actionArguments: AnyArgument[];\n};\n\nexport type ConditionAstNode = LeafAstNode & {\n type: \"condition\";\n conditionName: string;\n conditionArguments: AnyArgument[];\n};\n\nexport type WaitAstNode = LeafAstNode & {\n type: \"wait\";\n duration: number | null;\n longestDuration: number | null;\n};\n\nexport type AnyAstNode =\n | BranchAstNode\n | CompositeAstNode\n | LottoAstNode\n | DecoratorAstNode\n | RootAstNode\n | IterableAstNode\n | LeafAstNode\n | ActionAstNode\n | ConditionAstNode\n | WaitAstNode;\n\n/**\n * The AST node factories.\n */\nconst ASTNodeFactories = {\n ROOT: (): RootAstNode => ({\n type: \"root\",\n attributes: [],\n name: null,\n children: [],\n validate(depth: number) {\n // A root node cannot be the child of another node.\n if (depth > 1) {\n throw new Error(\"a root node cannot be the child of another node\");\n }\n\n // A root node must have a single child node.\n if (this.children.length !== 1) {\n throw new Error(\"a root node must have a single child\");\n }\n },\n createNodeInstance(namedRootNodeProvider, visitedBranches) {\n return new Root(\n this.attributes,\n this.children![0].createNodeInstance(namedRootNodeProvider, visitedBranches.slice())\n );\n }\n }),\n BRANCH: (): BranchAstNode => ({\n type: \"branch\",\n branchName: \"\",\n validate() {},\n createNodeInstance(namedRootNodeProvider, visitedBranches) {\n // Try to find the root node with a matching branch name.\n const targetRootNode = namedRootNodeProvider(this.branchName);\n\n // If we have already visited this branch then we have a circular dependency.\n if (visitedBranches.indexOf(this.branchName) !== -1) {\n throw new Error(`circular dependency found in branch node references for branch '${this.branchName}'`);\n }\n\n // If we have a target root node, then the node instance we want will be the first and only child of the referenced root node.\n if (targetRootNode) {\n return targetRootNode\n .createNodeInstance(namedRootNodeProvider, visitedBranches.concat(this.branchName))\n .getChildren()[0];\n } else {\n throw new Error(`branch references root node '${this.branchName}' which has not been defined`);\n }\n }\n }),\n SELECTOR: (): CompositeAstNode => ({\n type: \"selector\",\n attributes: [],\n children: [],\n validate() {\n // A selector node must have at least a single node.\n if (this.children.length < 1) {\n throw new Error(\"a selector node must have at least a single child\");\n }\n },\n createNodeInstance(namedRootNodeProvider, visitedBranches) {\n return new Selector(\n this.attributes,\n this.children.map((child) => child.createNodeInstance(namedRootNodeProvider, visitedBranches.slice()))\n );\n }\n }),\n SEQUENCE: (): CompositeAstNode => ({\n type: \"sequence\",\n attributes: [],\n children: [],\n validate() {\n // A sequence node must have at least a single node.\n if (this.children.length < 1) {\n throw new Error(\"a sequence node must have at least a single child\");\n }\n },\n createNodeInstance(namedRootNodeProvider, visitedBranches) {\n return new Sequence(\n this.attributes,\n this.children.map((child) => child.createNodeInstance(namedRootNodeProvider, visitedBranches.slice()))\n );\n }\n }),\n PARALLEL: (): CompositeAstNode => ({\n type: \"parallel\",\n attributes: [],\n children: [],\n validate() {\n // A parallel node must have at least a single node.\n if (this.children.length < 1) {\n throw new Error(\"a parallel node must have at least a single child\");\n }\n },\n createNodeInstance(namedRootNodeProvider, visitedBranches) {\n return new Parallel(\n this.attributes,\n this.children.map((child) => child.createNodeInstance(namedRootNodeProvider, visitedBranches.slice()))\n );\n }\n }),\n LOTTO: (): LottoAstNode => ({\n type: \"lotto\",\n attributes: [],\n children: [],\n tickets: [],\n validate() {\n // A lotto node must have at least a single node.\n if (this.children!.length < 1) {\n throw new Error(\"a lotto node must have at least a single child\");\n }\n },\n createNodeInstance(namedRootNodeProvider, visitedBranches) {\n return new Lotto(\n this.attributes,\n this.tickets!,\n this.children!.map((child) => child.createNodeInstance(namedRootNodeProvider, visitedBranches.slice()))\n );\n }\n }),\n REPEAT: (): IterableAstNode => ({\n type: \"repeat\",\n attributes: [],\n iterations: null,\n maximumIterations: null,\n children: [],\n validate() {\n // A repeat node must have a single node.\n if (this.children!.length !== 1) {\n throw new Error(\"a repeat node must have a single child\");\n }\n\n // A repeat node must have a positive number of iterations if defined.\n if (this.iterations !== null && this.iterations! < 0) {\n throw new Error(\"a repeat node must have a positive number of iterations if defined\");\n }\n\n // There is validation to carry out if a longest duration was defined.\n if (this.maximumIterations !== null) {\n // A repeat node must have a positive maximum iterations count if defined.\n if (this.maximumIterations! < 0) {\n throw new Error(\"a repeat node must have a positive maximum iterations count if defined\");\n }\n\n // A repeat node must not have an iteration count that exceeds the maximum iteration count.\n if (this.iterations! > this.maximumIterations!) {\n throw new Error(\n \"a repeat node must not have an iteration count that exceeds the maximum iteration count\"\n );\n }\n }\n },\n createNodeInstance(namedRootNodeProvider, visitedBranches) {\n return new Repeat(\n this.attributes,\n this.iterations!,\n this.maximumIterations!,\n this.children![0].createNodeInstance(namedRootNodeProvider, visitedBranches.slice())\n );\n }\n }),\n RETRY: (): IterableAstNode => ({\n type: \"retry\",\n attributes: [],\n iterations: null,\n maximumIterations: null,\n children: [],\n validate() {\n // A retry node must have a single node.\n if (this.children!.length !== 1) {\n throw new Error(\"a retry node must have a single child\");\n }\n\n // A retry node must have a positive number of iterations if defined.\n if (this.iterations !== null && this.iterations! < 0) {\n throw new Error(\"a retry node must have a positive number of iterations if defined\");\n }\n\n // There is validation to carry out if a longest duration was defined.\n if (this.maximumIterations !== null) {\n // A retry node must have a positive maximum iterations count if defined.\n if (this.maximumIterations! < 0) {\n throw new Error(\"a retry node must have a positive maximum iterations count if defined\");\n }\n\n // A retry node must not have an iteration count that exceeds the maximum iteration count.\n if (this.iterations! > this.maximumIterations!) {\n throw new Error(\n \"a retry node must not have an iteration count that exceeds the maximum iteration count\"\n );\n }\n }\n },\n createNodeInstance(namedRootNodeProvider, visitedBranches) {\n return new Retry(\n this.attributes,\n this.iterations!,\n this.maximumIterations!,\n this.children![0].createNodeInstance(namedRootNodeProvider, visitedBranches.slice())\n );\n }\n }),\n FLIP: (): DecoratorAstNode => ({\n type: \"flip\",\n attributes: [],\n children: [],\n validate() {\n // A flip node must have a single node.\n if (this.children!.length !== 1) {\n throw new Error(\"a flip node must have a single child\");\n }\n },\n createNodeInstance(namedRootNodeProvider, visitedBranches) {\n return new Flip(\n this.attributes,\n this.children![0].createNodeInstance(namedRootNodeProvider, visitedBranches.slice())\n );\n }\n }),\n SUCCEED: (): DecoratorAstNode => ({\n type: \"succeed\",\n attributes: [],\n children: [],\n validate() {\n // A succeed node must have a single node.\n if (this.children!.length !== 1) {\n throw new Error(\"a succeed node must have a single child\");\n }\n },\n createNodeInstance(namedRootNodeProvider, visitedBranches) {\n return new Succeed(\n this.attributes,\n this.children![0].createNodeInstance(namedRootNodeProvider, visitedBranches.slice())\n );\n }\n }),\n FAIL: (): DecoratorAstNode => ({\n type: \"fail\",\n attributes: [],\n children: [],\n validate() {\n // A fail node must have a single node.\n if (this.children!.length !== 1) {\n throw new Error(\"a fail node must have a single child\");\n }\n },\n createNodeInstance(namedRootNodeProvider, visitedBranches) {\n return new Fail(\n this.attributes,\n this.children![0].createNodeInstance(namedRootNodeProvider, visitedBranches.slice())\n );\n }\n }),\n WAIT: (): WaitAstNode => ({\n type: \"wait\",\n attributes: [],\n duration: null,\n longestDuration: null,\n validate() {\n // A wait node must have a positive duration.\n if (this.duration! < 0) {\n throw new Error(\"a wait node must have a positive duration\");\n }\n\n // There is validation to carry out if a longest duration was defined.\n if (this.longestDuration) {\n // A wait node must have a positive longest duration.\n if (this.longestDuration < 0) {\n throw new Error(\"a wait node must have a positive longest duration if one is defined\");\n }\n\n // A wait node must not have a duration that exceeds the longest duration.\n if (this.duration! > this.longestDuration) {\n throw new Error(\"a wait node must not have a shortest duration that exceeds the longest duration\");\n }\n }\n },\n createNodeInstance() {\n return new Wait(this.attributes, this.duration!, this.longestDuration!);\n }\n }),\n ACTION: (): ActionAstNode => ({\n type: \"action\",\n attributes: [],\n actionName: \"\",\n actionArguments: [],\n validate() {},\n createNodeInstance() {\n return new Action(this.attributes, this.actionName!, this.actionArguments!);\n }\n }),\n CONDITION: (): ConditionAstNode => ({\n type: \"condition\",\n attributes: [],\n conditionName: \"\",\n conditionArguments: [],\n validate() {},\n createNodeInstance() {\n return new Condition(this.attributes, this.conditionName!, this.conditionArguments!);\n }\n })\n};\n\ntype OtherAstNodes = AstNode[];\n\n/**\n * Create an array of root AST nodes based on the given definition.\n * @param definition The definition to parse the AST nodes from.\n * @returns The base definition AST nodes.\n */\nexport default function buildRootASTNodes(definition: string): RootAstNode[] {\n // Swap out any node/attribute argument string literals with a placeholder and get a mapping of placeholders to original values as well as the processed definition.\n const { placeholders, processedDefinition } = substituteStringLiterals(definition);\n\n // Convert the processed definition (with substituted string literals) into an array of raw tokens.\n const tokens = parseTokensFromDefinition(processedDefinition);\n\n // There must be at least 3 tokens for the tree definition to be valid. 'ROOT', '{' and '}'.\n if (tokens.length < 3) {\n throw new Error(\"invalid token count\");\n }\n\n // We should have a matching number of '{' and '}' tokens. If not, then there are scopes that have not been properly closed.\n if (tokens.filter((token) => token === \"{\").length !== tokens.filter((token) => token === \"}\").length) {\n throw new Error(\"scope character mismatch\");\n }\n\n // Create a stack of node children arrays, starting with a definition scope.\n const stack: [RootAstNode[], ...OtherAstNodes[]] = [[]];\n const rootScope = stack[0];\n\n // We should keep processing the raw tokens until we run out of them.\n while (tokens.length) {\n // Grab the next token.\n const token = tokens.shift();\n\n const currentScope = stack[stack.length - 1] as OtherAstNodes;\n\n // How we create the next AST token depends on the current raw token value.\n switch (token!.toUpperCase()) {\n case \"ROOT\": {\n // Create a ROOT AST node.\n const node = ASTNodeFactories.ROOT();\n\n // Push the ROOT node into the current scope.\n rootScope.push(node);\n\n // We may have a root node name defined as an argument.\n if (tokens[0] === \"[\") {\n const rootArguments = getArguments(tokens, placeholders);\n\n // We should have only a single argument that is not an empty string for a root node, which is the root name identifier.\n if (rootArguments.length === 1 && rootArguments[0].type === \"identifier\") {\n // The root name will be the first and only node argument.\n node.name = rootArguments[0].value as string;\n } else {\n throw new Error(\"expected single root name argument\");\n }\n }\n\n // Try to pick any attributes off of the token stack.\n node.attributes = getAttributes(tokens, placeholders);\n\n popAndCheck(tokens, \"{\");\n\n // The new scope is that of the new ROOT nodes children.\n stack.push(node.children!);\n break;\n }\n\n case \"BRANCH\": {\n // Create a BRANCH AST node.\n const node = ASTNodeFactories.BRANCH();\n\n // Push the BRANCH node into the current scope.\n currentScope.push(node);\n\n // We must have arguments defined, as we require a branch name argument.\n if (tokens[0] !== \"[\") {\n throw new Error(\"expected single branch name argument\");\n }\n\n // The branch name will be defined as a node argument.\n const branchArguments = getArguments(tokens, placeholders);\n\n // We should have only a single identifer argument for a branch node, which is the branch name.\n if (branchArguments.length === 1 && branchArguments[0].type === \"identifier\") {\n // The branch name will be the first and only node argument.\n node.branchName = branchArguments[0].value as string;\n } else {\n throw new Error(\"expected single branch name argument\");\n }\n break;\n }\n\n case \"SELECTOR\": {\n // Create a SELECTOR AST node.\n const node = ASTNodeFactories.SELECTOR();\n\n // Push the SELECTOR node into the current scope.\n currentScope.push(node);\n\n // Try to pick any attributes off of the token stack.\n node.attributes = getAttributes(tokens, placeholders);\n\n popAndCheck(tokens, \"{\");\n\n // The new scope is that of the new SELECTOR nodes children.\n stack.push(node.children!);\n break;\n }\n\n case \"SEQUENCE\": {\n // Create a SEQUENCE AST node.\n const node = ASTNodeFactories.SEQUENCE();\n\n // Push the SEQUENCE node into the current scope.\n currentScope.push(node);\n\n // Try to pick any attributes off of the token stack.\n node.attributes = getAttributes(tokens, placeholders);\n\n popAndCheck(tokens, \"{\");\n\n // The new scope is that of the new SEQUENCE nodes children.\n stack.push(node.children!);\n break;\n }\n\n case \"PARALLEL\": {\n // Create a PARALLEL AST node.\n const node = ASTNodeFactories.PARALLEL();\n\n // Push the PARALLEL node into the current scope.\n currentScope.push(node);\n\n // Try to pick any attributes off of the token stack.\n node.attributes = getAttributes(tokens, placeholders);\n\n popAndCheck(tokens, \"{\");\n\n // The new scope is that of the new PARALLEL nodes children.\n stack.push(node.children!);\n break;\n }\n\n case \"LOTTO\": {\n // Create a LOTTO AST node.\n const node = ASTNodeFactories.LOTTO();\n\n // Push the LOTTO node into the current scope.\n currentScope.push(node);\n\n // If the next token is a '[' character then some ticket counts have been defined as arguments.\n if (tokens[0] === \"[\") {\n // Get the ticket count arguments, each argument must be a number.\n node.tickets = getArguments(\n tokens,\n placeholders,\n (arg) => arg.type === \"number\" && !!arg.isInteger,\n \"lotto node ticket counts must be integer values\"\n ).map((argument) => argument.value as number);\n }\n\n // Try to pick any attributes off of the token stack.\n node.attributes = getAttributes(tokens, placeholders);\n\n popAndCheck(tokens, \"{\");\n\n // The new scope is that of the new LOTTO nodes children.\n stack.push(node.children!);\n break;\n }\n\n case \"CONDITION\": {\n // Create a CONDITION AST node.\n const node = ASTNodeFactories.CONDITION();\n\n // Push the CONDITION node into the current scope.\n currentScope.push(node);\n\n // We must have arguments defined, as we require a condition function name argument.\n if (tokens[0] !== \"[\") {\n throw new Error(\"expected condition name identifier argument\");\n }\n\n // Grab the condition node arguments.\n const conditionArguments = getArguments(tokens, placeholders);\n\n // We should have at least a single identifier argument for a condition node, which is the condition function name.\n if (conditionArguments.length && conditionArguments[0].type === \"identifier\") {\n // The condition function name will be the first node argument.\n node.conditionName = conditionArguments.shift()!.value as string;\n } else {\n throw new Error(\"expected condition name identifier argument\");\n }\n\n // Only the first argument should have been an identifier, all following arguments must be string, number, boolean or null.\n conditionArguments\n .filter((arg) => arg.type === \"identifier\")\n .forEach((arg) => {\n throw new Error(\n \"invalid condition node argument value '\" +\n arg.value +\n \"', must be string, number, boolean or null\"\n );\n });\n\n // Any node arguments that follow the condition name identifier will be treated as condition function arguments.\n node.conditionArguments = conditionArguments;\n\n // Try to pick any attributes off of the token stack.\n node.attributes = getAttributes(tokens, placeholders);\n break;\n }\n\n case \"FLIP\": {\n // Create a FLIP AST node.\n const node = ASTNodeFactories.FLIP();\n\n // Push the Flip node into the current scope.\n currentScope.push(node);\n\n // Try to pick any attributes off of the token stack.\n node.attributes = getAttributes(tokens, placeholders);\n\n popAndCheck(tokens, \"{\");\n\n // The new scope is that of the new FLIP nodes children.\n stack.push(node.children!);\n break;\n }\n\n case \"SUCCEED\": {\n // Create a SUCCEED AST node.\n const node = ASTNodeFactories.SUCCEED();\n\n // Push the Succeed node into the current scope.\n currentScope.push(node);\n\n // Try to pick any attributes off of the token stack.\n node.attributes = getAttributes(tokens, placeholders);\n\n popAndCheck(tokens, \"{\");\n\n // The new scope is that of the new Succeed nodes children.\n stack.push(node.children!);\n break;\n }\n\n case \"FAIL\": {\n // Create a FAIL AST node.\n const node = ASTNodeFactories.FAIL();\n\n // Push the Fail node into the current scope.\n currentScope.push(node);\n\n // Try to pick any attributes off of the token stack.\n node.attributes = getAttributes(tokens, placeholders);\n\n popAndCheck(tokens, \"{\");\n\n // The new scope is that of the new Fail nodes children.\n stack.push(node.children!);\n break;\n }\n\n case \"WAIT\": {\n // Create a WAIT AST node.\n const node = ASTNodeFactories.WAIT();\n\n // Push the WAIT node into the current scope.\n currentScope.push(node);\n\n // Get the duration and potential longest duration of the wait.\n const durations = getArguments(\n tokens,\n placeholders,\n (arg) => arg.type === \"number\" && !!arg.isInteger,\n \"wait node durations must be integer values\"\n ).map((argument) => argument.value);\n\n // We should have got one or two durations.\n if (durations.length === 1) {\n // A static duration was defined.\n node.duration = durations[0] as number;\n } else if (durations.length === 2) {\n // A shortest and longest duration was defined.\n node.duration = durations[0] as number;\n node.longestDuration = durations[1] as number;\n } else {\n // An incorrect number of durations was defined.\n throw new Error(\"invalid number of wait node duration arguments defined\");\n }\n\n // Try to pick any attributes off of the token stack.\n node.attributes = getAttributes(tokens, placeholders);\n break;\n }\n\n case \"REPEAT\": {\n // Create a REPEAT AST node.\n const node = ASTNodeFactories.REPEAT();\n\n // Push the REPEAT node into the current scope.\n currentScope.push(node);\n\n // Check for iteration counts ([])\n if (tokens[0] === \"[\") {\n // An iteration count has been defined. Get the iteration and potential maximum iteration of the wait.\n const iterationArguments = getArguments(\n tokens,\n placeholders,\n (arg) => arg.type === \"number\" && !!arg.isInteger,\n \"repeat node iteration counts must be integer values\"\n ).map((argument) => argument.value);\n\n // We should have got one or two iteration counts.\n if (iterationArguments.length === 1) {\n // A static iteration count was defined.\n node.iterations = iterationArguments[0] as number;\n } else if (iterationArguments.length === 2) {\n // A minimum and maximum iteration count was defined.\n node.iterations = iterationArguments[0] as number;\n node.maximumIterations = iterationArguments[1] as number;\n } else {\n // An incorrect number of iteration counts was defined.\n throw new Error(\"invalid number of repeat node iteration count arguments defined\");\n }\n }\n\n // Try to pick any attributes off of the token stack.\n node.attributes = getAttributes(tokens, placeholders);\n\n popAndCheck(tokens, \"{\");\n\n // The new scope is that of the new REPEAT nodes children.\n stack.push(node.children!);\n break;\n }\n\n case \"RETRY\": {\n // Create a RETRY AST node.\n const node = ASTNodeFactories.RETRY();\n\n // Push the RETRY node into the current scope.\n currentScope.push(node);\n\n // Check for iteration counts ([])\n if (tokens[0] === \"[\") {\n // An iteration count has been defined. Get the iteration and potential maximum iteration of the wait.\n const iterationArguments = getArguments(\n tokens,\n placeholders,\n (arg) => arg.type === \"number\" && !!arg.isInteger,\n \"retry node iteration counts must be integer values\"\n ).map((argument) => argument.value);\n\n // We should have got one or two iteration counts.\n if (iterationArguments.length === 1) {\n // A static iteration count was defined.\n node.iterations = iterationArguments[0] as number;\n } else if (iterationArguments.length === 2) {\n // A minimum and maximum iteration count was defined.\n node.iterations = iterationArguments[0] as number;\n node.maximumIterations = iterationArguments[1] as number;\n } else {\n // An incorrect number of iteration counts was defined.\n throw new Error(\"invalid number of retry node iteration count arguments defined\");\n }\n }\n\n // Try to pick any attributes off of the token stack.\n node.attributes = getAttributes(tokens, placeholders);\n\n popAndCheck(tokens, \"{\");\n\n // The new scope is that of the new RETRY nodes children.\n stack.push(node.children!);\n break;\n }\n\n case \"ACTION\": {\n // Create a ACTION AST node.\n const node = ASTNodeFactories.ACTION();\n\n // Push the ACTION node into the current scope.\n currentScope.push(node);\n\n // We must have arguments defined, as we require an action name argument.\n if (tokens[0] !== \"[\") {\n throw new Error(\"expected action name identifier argument\");\n }\n\n // The action name will be defined as a node argument.\n const actionArguments = getArguments(tokens, placeholders);\n\n // We should have at least one identifer argument for an action node, which is the action name.\n if (actionArguments.length && actionArguments[0].type === \"identifier\") {\n // The action name will be the first and only node argument.\n node.actionName = actionArguments.shift()!.value as string;\n } else {\n throw new Error(\"expected action name identifier argument\");\n }\n\n // Only the first argument should have been an identifier, all following arguments must be string, number, boolean or null.\n actionArguments\n .filter((arg) => arg.type === \"identifier\")\n .forEach((arg) => {\n throw new Error(\n \"invalid action node argument value '\" +\n arg.value +\n \"', must be string, number, boolean or null\"\n );\n });\n\n // Any node arguments that follow the action name identifier will be treated as action function arguments.\n node.actionArguments = actionArguments;\n\n // Try to pick any attributes off of the token stack.\n node.attributes = getAttributes(tokens, placeholders);\n break;\n }\n\n case \"}\": {\n // The '}' character closes the current scope.\n stack.pop();\n break;\n }\n\n default: {\n throw new Error(\"unexpected token: \" + token);\n }\n }\n }\n\n // A function to recursively validate each of the nodes in the AST.\n const validateASTNode = (node: Validatable, depth: number): void => {\n // Validate the node.\n node.validate(depth);\n\n // Validate each child of the node.\n (node.children || []).forEach((child) => validateASTNode(child, depth + 1));\n };\n\n // Start node validation from the definition root.\n validateASTNode(\n {\n children: stack[0] as RootAstNode[],\n validate(this: { children: RootAstNode[] }) {\n // We must have at least one node defined as the definition scope, which should be a root node.\n if (this.children.length === 0) {\n throw new Error(\"expected root node to have been defined\");\n }\n\n // Each node at the base of the definition scope MUST be a root node.\n for (const definitionLevelNode of this.children) {\n if (definitionLevelNode.type !== \"root\") {\n throw new Error(\"expected root node at base of definition\");\n }\n }\n\n // Exactly one root node must not have a name defined. This will be the main root, others will have to be referenced via branch nodes.\n if (this.children.filter((definitionLevelNode) => definitionLevelNode.name === null).length !== 1) {\n throw new Error(\"expected single unnamed root node at base of definition to act as main root\");\n }\n\n // No two named root nodes can have matching names.\n const rootNodeNames: string[] = [];\n for (const definitionLevelNode of this.children) {\n if (rootNodeNames.indexOf(definitionLevelNode.name!) !== -1) {\n throw new Error(`multiple root nodes found with duplicate name '${definitionLevelNode.name}'`);\n } else {\n rootNodeNames.push(definitionLevelNode.name!);\n }\n }\n }\n },\n 0\n );\n\n // Return the root AST nodes.\n return stack[0];\n}\n\n/**\n * Pop the next raw token off of the stack and throw an error if it wasn't the expected one.\n * @param tokens The array of remaining tokens.\n * @param expected An optional string or array or items, one of which must match the next popped token.\n * @returns The popped token.\n */\nfunction popAndCheck(tokens: string[], expected: string | string[]) {\n // Get and remove the next token.\n const popped = tokens.shift();\n\n // We were expecting another token.\n if (popped === undefined) {\n throw new Error(\"unexpected end of definition\");\n }\n\n // Do we have an expected token/tokens array?\n if (expected !== undefined) {\n // Check whether the popped token matches at least one of our expected items.\n var tokenMatchesExpectation = ([] as string[])\n .concat(expected)\n .some((item) => popped.toUpperCase() === item.toUpperCase());\n\n // Throw an error if the popped token didn't match any of our expected items.\n if (!tokenMatchesExpectation) {\n const expectationString = ([] as string[])\n .concat(expected)\n .map((item) => \"'\" + item + \"'\")\n .join(\" or \");\n throw new Error(\"unexpected token found. Expected \" + expectationString + \" but got '\" + popped + \"'\");\n }\n }\n\n // Return the popped token.\n return popped;\n}\n\ntype Placeholders = { [key: string]: string };\n\n/**\n * Pull an argument definition list off of the token stack.\n * @param tokens The array of remaining tokens.\n * @param stringArgumentPlaceholders The mapping of string literal node argument placeholders to original values.\n * @param argumentValidator The argument validator function.\n * @param validationFailedMessage The exception message to throw if argument validation fails.\n * @returns The argument definition list.\n */\nfunction getArguments(\n tokens: string[],\n stringArgumentPlaceholders: Placeholders,\n argumentValidator?: (arg: AnyArgument) => boolean,\n validationFailedMessage?: string\n) {\n // Any lists of arguments will always be wrapped in '[]' for node arguments or '()' for attribute arguments.\n // We are looking for a '[' or '(' opener that wraps the argument tokens and the relevant closer.\n const closer = popAndCheck(tokens, [\"[\", \"(\"]) === \"[\" ? \"]\" : \")\";\n\n const argumentListTokens: string[] = [];\n const argumentList: AnyArgument[] = [];\n\n // Grab all tokens between the '[' and ']' or '(' and ')'.\n while (tokens.length && tokens[0] !== closer) {\n // The next token is part of our arguments list.\n argumentListTokens.push(tokens.shift()!);\n }\n\n // Validate the order of the argument tokens. Each token must either be a ',' or a single argument that satisfies the validator.\n argumentListTokens.forEach((token, index) => {\n // Get whether this token should be an actual argument.\n const shouldBeArgumentToken = !(index & 1);\n\n // If the current token should be an actual argument then validate it,otherwise it should be a ',' token.\n if (shouldBeArgumentToken) {\n // Get the argument definition.\n const argumentDefinition = getArgumentDefinition(token!, stringArgumentPlaceholders);\n\n // Try to validate the argument.\n if (argumentValidator && !argumentValidator(argumentDefinition)) {\n throw new Error(validationFailedMessage);\n }\n\n // This is a valid argument!\n argumentList.push(argumentDefinition);\n } else {\n // The current token should be a ',' token.\n if (token !== \",\") {\n throw new Error(`invalid argument list, expected ',' or ']' but got '${token}'`);\n }\n }\n });\n\n // The arguments list should terminate with a ']' or ')' token, depending on the opener.\n popAndCheck(tokens, closer);\n\n // Return the argument list.\n return argumentList;\n}\n\n/**\n * Gets an argument value definition.\n * @param token The argument token.\n * @param stringArgumentPlaceholders The mapping of string literal node argument placeholders to original values.\n * @returns An argument value definition.\n */\nfunction getArgumentDefinition(token: string, stringArgumentPlaceholders: Placeholders): AnyArgument {\n // Check whether the token represents a null value.\n if (token === \"null\") {\n return {\n value: null,\n type: \"null\"\n } as NullArgument;\n }\n\n // Check whether the token represents a boolean value.\n if (token === \"true\" || token === \"false\") {\n return {\n value: token === \"true\",\n type: \"boolean\"\n } as BooleanArgument;\n }\n\n // Check whether the token represents a number value.\n // TODO: Relies on broken isNaN - see MDN.\n // if (!Number.isNaN(token)) {\n if (!isNaN(token as any)) {\n return {\n value: parseFloat(token),\n isInteger: parseFloat(token) === parseInt(token, 10),\n type: \"number\"\n } as NumberArgument;\n }\n\n // Check whether the token is a placeholder (e.g. @@0@@) representing a string literal.\n if (token.match(/^@@\\d+@@$/g)) {\n return {\n value: stringArgumentPlaceholders[token].replace('\\\\\"', '\"'),\n type: \"string\"\n } as StringPlaceholderArgument;\n }\n\n // The only remaining option is that the argument value is an identifier.\n return {\n value: token,\n type: \"identifier\"\n } as IdentifierArgument;\n}\n\n/**\n * Pull any attributes off of the token stack.\n * @param tokens The array of remaining tokens.\n * @param stringArgumentPlaceholders The mapping of string literal node argument placeholders to original values.\n * @returns An array of attributes defined by any directly following tokens.\n */\nfunction getAttributes(tokens: string[], stringArgumentPlaceholders: Placeholders) {\n // Create an array to hold any attributes found.\n const attributes: Attribute[] = [];\n\n // Keep track of names of attribute that we have found on the token stack, as we cannot have duplicates.\n const attributesFound: string[] = [];\n\n // Try to get the attribute factory for the next token.\n let attributeFactory = AttributeFactories[(tokens[0] || \"\").toUpperCase()];\n\n // Pull attribute tokens off of the tokens stack until we have no more.\n while (attributeFactory) {\n // Check to make sure that we have not already created a attribute of this type for this node.\n if (attributesFound.indexOf(tokens[0].toUpperCase()) !== -1) {\n throw new Error(`duplicate attribute '${tokens[0].toUpperCase()}' found for node`);\n }\n\n // Add the current attribute type to our array of found attributes.\n attributesFound.push(tokens.shift()!.toUpperCase());\n\n // Grab any attribute arguments.\n const attributeArguments = getArguments(tokens, stringArgumentPlaceholders);\n\n // The first attribute argument has to be an identifer, this will reference an agent function.\n if (attributeArguments.length === 0 || attributeArguments[0].type !== \"identifier\") {\n throw new Error(\"expected agent function name identifier argument for attribute\");\n }\n\n // Grab the first attribute which is an identifier that will reference an agent function.\n const attributeFunctionName = attributeArguments.shift()! as IdentifierArgument;\n\n // Any remaining attribute arguments must have a type of string, number, boolean or null.\n attributeArguments\n .filter((arg) => arg.type === \"identifier\")\n .forEach((arg) => {\n throw new Error(\n \"invalid attribute argument value '\" + arg.value + \"', must be string, number, boolean or null\"\n );\n });\n\n // Create the attribute and add it to the array of attributes found.\n attributes.push(attributeFactory(attributeFunctionName.value, attributeArguments));\n\n // Try to get the next attribute name token, as there could be multiple.\n attributeFactory = AttributeFactories[(tokens[0] || \"\").toUpperCase()];\n }\n\n return attributes;\n}\n\n/**\n * Swaps out any node/attribute argument string literals with placeholders.\n * @param definition The definition.\n * @returns An object containing a mapping of placeholders to original string values as well as the processed definition string.\n */\nfunction substituteStringLiterals(definition: string): {\n placeholders: { [key: string]: string };\n processedDefinition: string;\n} {\n // Create an object to hold the mapping of placeholders to original string values.\n const placeholders: Placeholders = {};\n\n // Replace any string literals wrapped with double quotes in our definition with placeholders to be processed later.\n const processedDefinition = definition.replace(/\\\"(\\\\.|[^\"\\\\])*\\\"/g, (match) => {\n var strippedMatch = match.substring(1, match.length - 1);\n var placeholder = Object.keys(placeholders).find((key) => placeholders[key] === strippedMatch);\n\n // If we have no existing string literal match then create a new placeholder.\n if (!placeholder) {\n placeholder = `@@${Object.keys(placeholders).length}@@`;\n placeholders[placeholder] = strippedMatch;\n }\n\n return placeholder;\n });\n\n return { placeholders, processedDefinition };\n}\n\n/**\n * Parse the tree definition into an array of raw tokens.\n * @param definition The definition.\n * @returns An array of tokens parsed from the definition.\n */\nfunction parseTokensFromDefinition(definition: string): string[] {\n // Add some space around various important characters so that they can be plucked out easier as individual tokens.\n definition = definition.replace(/\\(/g, \" ( \");\n definition = definition.replace(/\\)/g, \" ) \");\n definition = definition.replace(/\\{/g, \" { \");\n definition = definition.replace(/\\}/g, \" } \");\n definition = definition.replace(/\\]/g, \" ] \");\n definition = definition.replace(/\\[/g, \" [ \");\n definition = definition.replace(/\\,/g, \" , \");\n\n // Split the definition into raw token form and return it.\n return definition.replace(/\\s+/g, \" \").trim().split(\" \");\n}\n", "import GuardPath, { GuardPathPart } from \"./attributes/guards/GuardPath\";\nimport buildRootASTNodes, { AnyArgument, RootAstNode } from \"./RootAstNodesBuilder\";\nimport State, { AnyState } from \"./State\";\nimport Lookup from \"./Lookup\";\nimport Node from \"./nodes/Node\";\nimport Root from \"./nodes/decorator/Root\";\nimport Composite from \"./nodes/composite/Composite\";\nimport Decorator from \"./nodes/decorator/Decorator\";\nimport { Agent, GlobalFunction } from \"./Agent\";\nimport { CallbackAttributeDetails } from \"./attributes/callbacks/Callback\";\nimport { GuardAttributeDetails } from \"./attributes/guards/Guard\";\nimport { BehaviourTreeOptions } from \"./BehaviourTreeOptions\";\n\n// Purely for outside inspection of the tree.\nexport type FlattenedTreeNode = {\n id: string;\n type: string;\n caption: string;\n state: AnyState;\n guards: GuardAttributeDetails[];\n callbacks: CallbackAttributeDetails[];\n args: AnyArgument[];\n parentId: string | null;\n};\n\n/**\n * A representation of a behaviour tree.\n */\nexport class BehaviourTree {\n /**\n * The main root tree node.\n */\n public readonly rootNode: Root;\n\n /**\n * Creates a new instance of the BehaviourTree class.\n * @param definition The behaviour tree definition.\n * @param agent The agent instance that this behaviour tree is modelling behaviour for.\n * @param options The behaviour tree options object.\n */\n constructor(definition: string, private agent: Agent, private options: BehaviourTreeOptions = {}) {\n // The tree definition must be defined and a valid string.\n if (typeof definition !== \"string\") {\n throw new Error(\"the tree definition must be a string\");\n }\n\n // The agent must be defined and not null.\n if (typeof agent !== \"object\" || agent === null) {\n throw new Error(\"the agent must be defined and not null\");\n }\n\n // Parse the behaviour tree definition, create the populated tree of behaviour tree nodes, and get the root.\n this.rootNode = BehaviourTree.createRootNode(definition);\n }\n\n /**\n * Gets whether the tree is in the RUNNING state.\n * @returns true if the tree is in the RUNNING state, otherwise false.\n */\n isRunning() {\n return this.rootNode.getState() === State.RUNNING;\n }\n\n /**\n * Gets the current tree state of SUCCEEDED, FAILED, READY or RUNNING.\n * @returns The current tree state.\n */\n getState() {\n return this.rootNode.getState();\n }\n\n /**\n * Step the tree.\n * 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.\n * 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\n * 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.\n *\n * 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.\n */\n step() {\n // If the root node has already been stepped to completion then we need to reset it.\n if (this.rootNode.getState() === State.SUCCEEDED || this.rootNode.getState() === State.FAILED) {\n this.rootNode.reset();\n }\n\n try {\n this.rootNode.update(this.agent, this.options);\n } catch (exception) {\n throw new Error(`error stepping tree: ${(exception as Error).message}`);\n }\n }\n\n /**\n * Resets the tree from the root node outwards to each nested node, giving each a state of READY.\n */\n reset() {\n this.rootNode.reset();\n }\n\n /**\n * Gets the flattened details of every node in the tree.\n * @returns The flattened details of every node in the tree.\n */\n getFlattenedNodeDetails(): FlattenedTreeNode[] {\n // Create an empty flattened array of tree nodes.\n const flattenedTreeNodes: FlattenedTreeNode[] = [];\n\n /**\n * Helper function to process a node instance and push details into the flattened tree nodes array.\n * @param node The current node.\n * @param parentUid The UID of the node parent, or null if the node is the main root node.\n */\n const processNode = (node: Node, parentUid: string | null) => {\n // Get the guard and callback attribute details for this node.\n const guards = node\n .getAttributes()\n .filter((attribute) => attribute.isGuard())\n .map((attribute) => attribute.getDetails()) as GuardAttributeDetails[];\n const callbacks = node\n .getAttributes()\n .filter((attribute) => !attribute.isGuard())\n .map((attribute) => attribute.getDetails()) as CallbackAttributeDetails[];\n\n // Push the current node into the flattened nodes array.\n flattenedTreeNodes.push({\n id: node.getUid(),\n type: node.getType(),\n caption: node.getName(),\n state: node.getState(),\n guards,\n callbacks,\n args: node.getArguments(),\n parentId: parentUid\n });\n\n // Process each of the nodes children if it is not a leaf node.\n if (!node.isLeafNode()) {\n (node as Composite | Decorator)\n .getChildren()\n .forEach((child) => processNode(child, (node as Composite | Decorator).getUid()));\n }\n };\n\n // Convert the nested node structure into a flattened array of node details.\n processNode(this.rootNode, null);\n\n return flattenedTreeNodes;\n }\n\n /**\n * Registers the action/condition/guard/callback function or subtree with the given name.\n * @param name The name of the function or subtree to register.\n * @param value The function or subtree definition to register.\n */\n static register(name: string, value: GlobalFunction | string) {\n if (typeof value === \"function\") {\n // We are going to register a action/condition/guard/callback function.\n Lookup.setFunc(name, value);\n } else if (typeof value === \"string\") {\n // We are going to register a subtree.\n let rootASTNodes: RootAstNode[];\n\n try {\n // Try to create the behaviour tree AST based on the definition provided, this could fail if the definition is invalid.\n rootASTNodes = buildRootASTNodes(value);\n } catch (exception) {\n // There was an issue in trying to parse and build the tree definition.\n throw new Error(`error registering definition: ${(exception as Error).message}`);\n }\n\n // This function should only ever be called with a definition containing a single unnamed root node.\n if (rootASTNodes.length != 1 || rootASTNodes[0].name !== null) {\n throw new Error(\"error registering definition: expected a single unnamed root node\");\n }\n\n Lookup.setSubtree(name, rootASTNodes[0]);\n } else {\n throw new Error(\"unexpected value, expected string definition or function\");\n }\n }\n\n /**\n * Unregisters the registered action/condition/guard/callback function or subtree with the given name.\n * @param name The name of the registered action/condition/guard/callback function or subtree to unregister.\n */\n static unregister(name: string): void {\n Lookup.remove(name);\n }\n\n /**\n * Unregister all registered action/condition/guard/callback functions and subtrees.\n */\n static unregisterAll(): void {\n Lookup.empty();\n }\n\n /**\n * Parses a behaviour tree definition and creates a tree of behaviour tree nodes.\n * @param {string} definition The behaviour tree definition.\n * @returns The root behaviour tree node.\n */\n private static createRootNode(definition: string): Root {\n try {\n // Try to create the behaviour tree AST based on the definition provided, this could fail if the definition is invalid.\n const rootASTNodes = buildRootASTNodes(definition);\n\n // Create a symbol to use as the main root key in our root node mapping.\n const mainRootNodeKey = Symbol(\"__root__\");\n\n // Create a mapping of root node names to root AST tokens. The main root node will have a key of Symbol(\"__root__\").\n const rootNodeMap: { [key: string | symbol]: RootAstNode } = {};\n for (const rootASTNode of rootASTNodes) {\n rootNodeMap[rootASTNode.name === null ? mainRootNodeKey : rootASTNode.name!] = rootASTNode;\n }\n\n // Convert the AST to our actual tree and get the root node.\n const rootNode: Root = rootNodeMap[mainRootNodeKey].createNodeInstance(\n // Create a provider for named root nodes that are part of our definition or have been registered. Prioritising the former.\n (name: string): RootAstNode => (rootNodeMap[name] ? rootNodeMap[name] : Lookup.getSubtree(name)),\n []\n );\n\n // Set a guard path on every leaf of the tree to evaluate as part of its update.\n BehaviourTree.applyLeafNodeGuardPaths(rootNode);\n\n // Return the root node.\n return rootNode;\n } catch (exception) {\n // There was an issue in trying to parse and build the tree definition.\n throw new Error(`error parsing tree: ${(exception as Error).message}\\n${(exception as Error).stack}`);\n }\n }\n\n /**\n * Applies a guard path to every leaf of the tree to evaluate as part of each update.\n * @param rootNode The main root tree node.\n */\n private static applyLeafNodeGuardPaths(rootNode: Root) {\n const nodePaths: Node[][] = [];\n\n const findLeafNodes = (path: Node[], node: Node) => {\n // Add the current node to the path.\n path = path.concat(node);\n\n // Check whether the current node is a leaf node.\n if (node.isLeafNode()) {\n nodePaths.push(path);\n } else {\n (node as Composite | Decorator).getChildren().forEach((child) => findLeafNodes(path, child));\n }\n };\n\n // Find all leaf node paths, starting from the root.\n findLeafNodes([], rootNode);\n\n nodePaths.forEach((path) => {\n // Each node in the current path will have to be assigned a guard path, working from the root outwards.\n for (let depth = 0; depth < path.length; depth++) {\n // Get the node in the path at the current depth.\n const currentNode = path[depth];\n\n // The node may already have been assigned a guard path, if so just skip it.\n if (currentNode.hasGuardPath()) {\n continue;\n }\n\n // Create the guard path for the current node.\n const guardPath = new GuardPath(\n path\n .slice(0, depth + 1)\n .map((node) => ({ node, guards: node.getGuardAttributes() }))\n .filter((details) => details.guards.length > 0)\n );\n\n // Assign the guard path to the current node.\n currentNode.setGuardPath(guardPath);\n }\n });\n }\n}\n"], "mappings": "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", "names": ["Participant", "Lotto", "createLotto", "State", "createLotto"] } diff --git a/dist/index.js b/dist/index.js index ea4c3c2..1551327 100644 --- a/dist/index.js +++ b/dist/index.js @@ -1673,6 +1673,133 @@ function parseTokensFromDefinition(definition) { return definition.replace(/\s+/g, " ").trim().split(" "); } +// src/DSLParser.ts +function isLeafNode(node) { + return ["branch", "action", "condition", "wait"].includes(node.type); +} +function isDecoratorNode(node) { + return ["root", "repeat", "retry", "flip", "succeed", "fail"].includes(node.type); +} +function isCompositeNode(node) { + return ["sequence", "selector", "lotto", "parallel"].includes(node.type); +} +function parseToJSON(definition) { + const { placeholders, processedDefinition } = substituteStringLiterals2(definition); + const tokens = parseTokensFromDefinition2(definition); + return convertTokensToJSONDefinition(tokens, placeholders, processedDefinition); +} +function convertTokensToJSONDefinition(tokens, placeholders, processedDefinition) { + if (tokens.length < 3) { + throw new Error("invalid token count"); + } + if (tokens.filter((token) => token === "{").length !== tokens.filter((token) => token === "}").length) { + throw new Error("scope character mismatch"); + } + const treeStacks = []; + const rootNodes = []; + const pushRootNode = (rootNode) => { + rootNodes.push(rootNode); + treeStacks.push([rootNode]); + }; + const pushNode = (node) => { + const currentTreeStack = treeStacks[treeStacks.length - 1]; + const bottomNode = currentTreeStack[currentTreeStack.length - 1]; + if (isCompositeNode(bottomNode)) { + bottomNode.children = bottomNode.children || []; + bottomNode.children.push(node); + } else if (isDecoratorNode(bottomNode)) { + bottomNode.child = node; + } + if (!isLeafNode(node)) { + currentTreeStack.push(node); + } + }; + const popNode = () => { + const currentTreeStack = treeStacks[treeStacks.length - 1]; + if (currentTreeStack.length) { + currentTreeStack.pop(); + } + if (!currentTreeStack.length) { + treeStacks.pop(); + } + }; + while (tokens.length) { + const token = tokens.shift(); + switch (token.toUpperCase()) { + case "ROOT": { + const node = { + type: "root" + }; + popAndCheck2(tokens, "{"); + pushRootNode(node); + break; + } + case "SEQUENCE": { + const node = { + type: "sequence" + }; + popAndCheck2(tokens, "{"); + pushNode(node); + break; + } + case "ACTION": { + const node = { + type: "action" + }; + pushNode(node); + break; + } + case "}": { + popNode(); + break; + } + default: { + throw new Error("unexpected token: " + token); + } + } + } + console.log(rootNodes); + return rootNodes; +} +function substituteStringLiterals2(definition) { + const placeholders = {}; + const processedDefinition = definition.replace(/\"(\\.|[^"\\])*\"/g, (match) => { + var strippedMatch = match.substring(1, match.length - 1); + var placeholder = Object.keys(placeholders).find((key) => placeholders[key] === strippedMatch); + if (!placeholder) { + placeholder = `@@${Object.keys(placeholders).length}@@`; + placeholders[placeholder] = strippedMatch; + } + return placeholder; + }); + return { placeholders, processedDefinition }; +} +function parseTokensFromDefinition2(definition) { + definition = definition.replace(/\(/g, " ( "); + definition = definition.replace(/\)/g, " ) "); + definition = definition.replace(/\{/g, " { "); + definition = definition.replace(/\}/g, " } "); + definition = definition.replace(/\]/g, " ] "); + definition = definition.replace(/\[/g, " [ "); + definition = definition.replace(/\,/g, " , "); + return definition.replace(/\s+/g, " ").trim().split(" "); +} +function popAndCheck2(tokens, expected) { + const popped = tokens.shift(); + if (popped === void 0) { + throw new Error("unexpected end of definition"); + } + if (expected != void 0) { + const expectedValues = typeof expected === "string" ? [expected] : expected; + var tokenMatchesExpectation = expectedValues.some((item) => popped.toUpperCase() === item.toUpperCase()); + if (!tokenMatchesExpectation) { + const expectationString = expectedValues.map((item) => "'" + item + "'").join(" or "); + throw new Error("unexpected token found. Expected " + expectationString + " but got '" + popped + "'"); + } + } + return popped; +} + // src/BehaviourTree.ts var BehaviourTree = class { constructor(definition, agent, options = {}) { @@ -1753,6 +1880,11 @@ var BehaviourTree = class { Lookup.empty(); } static createRootNode(definition) { + try { + parseToJSON(definition); + } catch (exception) { + console.log(exception); + } try { const rootASTNodes = buildRootASTNodes(definition); const mainRootNodeKey = Symbol("__root__"); diff --git a/dist/index.js.map b/dist/index.js.map index 49887ed..0ee43d2 100644 --- a/dist/index.js.map +++ b/dist/index.js.map @@ -1,7 +1,7 @@ { "version": 3, - "sources": ["../node_modules/lotto-draw/dist/Participant.js", "../node_modules/lotto-draw/dist/Utilities.js", "../node_modules/lotto-draw/dist/Lotto.js", "../node_modules/lotto-draw/dist/createLotto.js", "../node_modules/lotto-draw/dist/index.js", "../src/index.ts", "../src/attributes/guards/GuardUnsatisifedException.ts", "../src/attributes/guards/GuardPath.ts", "../src/State.ts", "../src/nodes/Node.ts", "../src/nodes/leaf/Leaf.ts", "../src/Lookup.ts", "../src/nodes/leaf/Action.ts", "../src/nodes/leaf/Condition.ts", "../src/nodes/leaf/Wait.ts", "../src/nodes/decorator/Decorator.ts", "../src/nodes/decorator/Root.ts", "../src/nodes/decorator/Repeat.ts", "../src/nodes/decorator/Retry.ts", "../src/nodes/decorator/Flip.ts", "../src/nodes/decorator/Succeed.ts", "../src/nodes/decorator/Fail.ts", "../src/nodes/composite/Lotto.ts", "../src/nodes/composite/Composite.ts", "../src/nodes/composite/Selector.ts", "../src/nodes/composite/Sequence.ts", "../src/nodes/composite/Parallel.ts", "../src/attributes/Attribute.ts", "../src/attributes/guards/Guard.ts", "../src/attributes/guards/While.ts", "../src/attributes/guards/Until.ts", "../src/attributes/callbacks/Callback.ts", "../src/attributes/callbacks/Entry.ts", "../src/attributes/callbacks/Exit.ts", "../src/attributes/callbacks/Step.ts", "../src/RootAstNodesBuilder.ts", "../src/BehaviourTree.ts"], - "sourcesContent": ["\"use strict\";\r\nObject.defineProperty(exports, \"__esModule\", { value: true });\r\nexports.Participant = void 0;\r\n/**\r\n * A participant that holds a number of tickets.\r\n */\r\nvar Participant = /** @class */ (function () {\r\n /**\r\n * Creates an instance of the Participant class.\r\n * @param participant The actual participant.\r\n * @param tickets The number of tickets held by the participant.\r\n */\r\n function Participant(participant, tickets) {\r\n if (tickets === void 0) { tickets = 1; }\r\n this._participant = participant;\r\n this._tickets = tickets;\r\n }\r\n Object.defineProperty(Participant.prototype, \"participant\", {\r\n /** Gets the actual participant. */\r\n get: function () {\r\n return this._participant;\r\n },\r\n enumerable: false,\r\n configurable: true\r\n });\r\n Object.defineProperty(Participant.prototype, \"tickets\", {\r\n /** Gets or sets the number of tickets held by the participant. */\r\n get: function () {\r\n return this._tickets;\r\n },\r\n set: function (value) {\r\n this._tickets = value;\r\n },\r\n enumerable: false,\r\n configurable: true\r\n });\r\n return Participant;\r\n}());\r\nexports.Participant = Participant;\r\n", "\"use strict\";\r\nObject.defineProperty(exports, \"__esModule\", { value: true });\r\nexports.isNaturalNumber = exports.isNullOrUndefined = void 0;\r\n/**\r\n * Gets whether the value provided is null or undefined.\r\n * @param value The value to check.\r\n * @returns Whether the value provided is null or undefined.\r\n */\r\nfunction isNullOrUndefined(value) {\r\n return value === null || value === undefined;\r\n}\r\nexports.isNullOrUndefined = isNullOrUndefined;\r\n/**\r\n * Gets whether the value provided is a natural number.\r\n * @param value The value to check.\r\n * @returns Whether the value provided is a natural number.\r\n */\r\nfunction isNaturalNumber(value) {\r\n return typeof value === \"number\" && value >= 1 && Math.floor(value) === value;\r\n}\r\nexports.isNaturalNumber = isNaturalNumber;\r\n", "\"use strict\";\r\nObject.defineProperty(exports, \"__esModule\", { value: true });\r\nexports.Lotto = void 0;\r\nvar Participant_1 = require(\"./Participant\");\r\nvar Utilities_1 = require(\"./Utilities\");\r\n/**\r\n * Represents a lotto consisting of a number of pickable ticket-holding participants.\r\n */\r\nvar Lotto = /** @class */ (function () {\r\n /**\r\n * Creates a new instance of Lotto.\r\n * @param customRandom The custom RNG to use in place of Math.random().\r\n */\r\n function Lotto(customRandom) {\r\n /** The array of participants that are holding tickets in the lotto. */\r\n this._participants = [];\r\n this._customRandom = customRandom;\r\n }\r\n /**\r\n * Adds a participant with the specified number of tickets, or adds to the participant ticket count if the participant already holds tickets.\r\n * @param participant The participant to add or to increase the ticket count for if they already hold tickets.\r\n * @param tickets The number of tickets, defaults to 1.\r\n * @returns The Lotto instance.\r\n */\r\n Lotto.prototype.add = function (participant, tickets) {\r\n if (tickets === void 0) { tickets = 1; }\r\n // Check that we have a valid ticket count.\r\n if (!(0, Utilities_1.isNaturalNumber)(tickets)) {\r\n throw new Error(\"tickets value must be a natural number\");\r\n }\r\n // Check whether this participant has already been added.\r\n var existingParticipant = this._participants.find(function (part) { return part.participant === participant; });\r\n if (existingParticipant) {\r\n // The participant has already been added to the lotto so just add to their ticket count.\r\n existingParticipant.tickets += tickets;\r\n }\r\n else {\r\n // The participant is not part of the lotto so we should add them.\r\n this._participants.push(new Participant_1.Participant(participant, tickets));\r\n }\r\n return this;\r\n };\r\n /**\r\n * Removes the specified number of tickets for the given participant from the draw, or all tickets if a ticket number is not defined.\r\n * @param participant The participant to remove tickets for.\r\n * @param tickets The number of tickets to remove, or undefined if all tickets are to be removed.\r\n * @returns The Lotto instance.\r\n */\r\n Lotto.prototype.remove = function (participant, tickets) {\r\n // Attempt to get the existing participant.\r\n var existingParticipant = this._participants.find(function (part) { return part.participant === participant; });\r\n // There is nothing to do if the specified participant isn't even part of the lotto.\r\n if (!existingParticipant) {\r\n return this;\r\n }\r\n // Check whether a tickets value was given.\r\n if (tickets !== undefined) {\r\n // Check that we have a valid ticket count.\r\n if (!(0, Utilities_1.isNaturalNumber)(tickets)) {\r\n throw new Error(\"tickets value must be a natural number\");\r\n }\r\n existingParticipant.tickets -= tickets;\r\n // If the participant no longer holds any tickets then they should be removed.\r\n if (existingParticipant.tickets < 1) {\r\n this._participants = this._participants.filter(function (part) { return part !== existingParticipant; });\r\n }\r\n }\r\n else {\r\n // We are removing all tickets for the participant so just remove them from the lotto.\r\n this._participants = this._participants.filter(function (part) { return part !== existingParticipant; });\r\n }\r\n return this;\r\n };\r\n /**\r\n * Draw a winning ticket and return the participant that holds the ticket.\r\n * @param options The draw options.\r\n * @returns The participant that holds the winning ticket.\r\n */\r\n Lotto.prototype.draw = function (options) {\r\n if (options === void 0) { options = {}; }\r\n // If we have no participants then just return null.\r\n if (this._participants.length === 0) {\r\n return null;\r\n }\r\n var redrawable = (0, Utilities_1.isNullOrUndefined)(options.redrawable) ? true : options.redrawable;\r\n var pickable = [];\r\n this._participants.forEach(function (_a) {\r\n var participant = _a.participant, tickets = _a.tickets;\r\n for (var ticketCount = 0; ticketCount < tickets; ticketCount++) {\r\n pickable.push(participant);\r\n }\r\n });\r\n var random;\r\n // We need a random floating-point number between 0 (inclusive) and 1 to scale up to pick our winner.\r\n // If a custom random function exists then we should use that or fall back to Math.random().\r\n if (this._customRandom) {\r\n // Call our custom random function to get a random floating-point number.\r\n random = this._customRandom();\r\n // Verify that the result of calling our custom random function is a number between 0 (inclusive) and 1.\r\n if (typeof random !== \"number\" || random < 0 || random >= 1) {\r\n throw new Error(\"the 'random' function provided did not return a number between 0 (inclusive) and 1\");\r\n }\r\n }\r\n else {\r\n // No custom random function was defined so just use good ol' Math.random().\r\n random = Math.random();\r\n }\r\n // Pick a winning participant.\r\n var winner = pickable[Math.floor(random * pickable.length)];\r\n // If the ticket isn't redrawable then we should remove a ticket from the winning participants ticket count.\r\n if (!redrawable) {\r\n this.remove(winner, 1);\r\n }\r\n // Return the winning participant.\r\n return winner;\r\n };\r\n /**\r\n * Draws multiple winning tickets and return an array of the participants that hold the winning tickets.\r\n * @param tickets The number of winning tickets to draw.\r\n * @param options The draw multiple options.\r\n * @returns An array of the participants that hold the winning tickets.\r\n */\r\n Lotto.prototype.drawMultiple = function (tickets, options) {\r\n if (options === void 0) { options = {}; }\r\n var uniqueResults = (0, Utilities_1.isNullOrUndefined)(options.unique) ? false : options.unique;\r\n // Handle cases where the user has asked for zero tickets (no idea why they would do this be we should trust them).\r\n if (tickets === 0) {\r\n return [];\r\n }\r\n // Now that we know out tickets value is not zero we should check that it is a valid natural number.\r\n if (!(0, Utilities_1.isNaturalNumber)(tickets)) {\r\n throw new Error(\"tickets value must be a natural number\");\r\n }\r\n var result = [];\r\n // Keep drawing tickets until we either reach the number of required tickets or we simply run out of tickets to draw.\r\n // We can run out of tickets to draw if 'options.redrawable' is explicity 'false' or we just had no participants when 'drawMultiple' was called.\r\n while (result.length < tickets && this._participants.length > 0) {\r\n result.push(this.draw(options));\r\n }\r\n // If the 'unique' draw option is set then we need to remove duplicates from the result list.\r\n if (uniqueResults) {\r\n // Create an array to store our unique results.\r\n var unique = [];\r\n // Iterate over all of our participants (with potential duplicates) and populate our array of unique values.\r\n for (var _i = 0, result_1 = result; _i < result_1.length; _i++) {\r\n var participant = result_1[_i];\r\n if (unique.indexOf(participant) === -1) {\r\n unique.push(participant);\r\n }\r\n }\r\n result = unique;\r\n }\r\n return result;\r\n };\r\n return Lotto;\r\n}());\r\nexports.Lotto = Lotto;\r\n", "\"use strict\";\r\nObject.defineProperty(exports, \"__esModule\", { value: true });\r\nexports.createLotto = void 0;\r\nvar Lotto_1 = require(\"./Lotto\");\r\n/**\r\n * A function that creates and returns a Lotto instance.\r\n * @param participantsOrOptions An array of initial participants or options relating to the creation of a Lotto instance.\r\n * @returns A new Lotto instance.\r\n */\r\nfunction createLotto(participantsOrOptions) {\r\n // If no initial participants or lotto options were provided as an argument then we can just return a new lotto instance now.\r\n if (!participantsOrOptions) {\r\n return new Lotto_1.Lotto();\r\n }\r\n // Check whether we were provided with an array of initial participants or a lotto options object.\r\n if (Array.isArray(participantsOrOptions)) {\r\n // We are dealing with a pre-defined array of participants.\r\n var participants = participantsOrOptions;\r\n var lotto_1 = new Lotto_1.Lotto();\r\n // If the lotto participants have been defined upfront then we will need to add them all to our lotto instance now.\r\n participants.forEach(function (_a) {\r\n var participant = _a[0], tokens = _a[1];\r\n return lotto_1.add(participant, tokens);\r\n });\r\n // Return the Lotto instance.\r\n return lotto_1;\r\n }\r\n else {\r\n // We are dealing with some lotto options.\r\n var random = participantsOrOptions.random, participants = participantsOrOptions.participants;\r\n // Create a Lotto instance passing the custom RNG function to use in place of Math.random() (which could be undefined).\r\n var lotto_2 = new Lotto_1.Lotto(random);\r\n // If the lotto participants have been defined upfront as part of the options then we will need to add them all to our lotto instance now.\r\n if (participants) {\r\n participants.forEach(function (_a) {\r\n var participant = _a[0], tokens = _a[1];\r\n return lotto_2.add(participant, tokens);\r\n });\r\n }\r\n // Return the Lotto instance.\r\n return lotto_2;\r\n }\r\n}\r\nexports.createLotto = createLotto;\r\n", "\"use strict\";\r\nObject.defineProperty(exports, \"__esModule\", { value: true });\r\nvar createLotto_1 = require(\"./createLotto\");\r\nexports.default = createLotto_1.createLotto;\r\n", "import { BehaviourTree, FlattenedTreeNode } from \"./BehaviourTree\";\nimport State from \"./State\";\n\nexport { BehaviourTree, State };\nexport type { FlattenedTreeNode };\n", "import Node from \"../../nodes/Node\";\n\n/**\n * An exception thrown when evaluating node guard path conditions and a conditions fails.\n */\nexport default class GuardUnsatisifedException extends Error {\n /**\n * @param source The node at which a guard condition failed.\n */\n constructor(private source: Node) {\n super(\"A guard path condition has failed\");\n }\n\n /**\n * Gets whether the specified node is the node at which a guard condition failed.\n * @param node The node to check against the source node.\n * @returns Whether the specified node is the node at which a guard condition failed.\n */\n isSourceNode = (node: Node) => node === this.source;\n}\n", "import { Agent } from \"../../Agent\";\nimport Guard from \"./Guard\";\nimport Node from \"../../nodes/Node\";\nimport GuardUnsatisifedException from \"./GuardUnsatisifedException\";\n\nexport type GuardPathPart = {\n node: Node;\n guards: Guard[];\n};\n\n/**\n * Represents a path of node guards along a root-to-leaf tree path.\n */\nexport default class GuardPath {\n /**\n * @param nodes An array of objects defining a node instance -> guard link, ordered by node depth.\n */\n constructor(private nodes: GuardPathPart[]) {}\n\n /**\n * Evaluate guard conditions for all guards in the tree path, moving outwards from the root.\n * @param agent The agent, required for guard evaluation.\n * @returns An evaluation results object.\n */\n evaluate = (agent: Agent) => {\n // We need to evaluate guard conditions for nodes up the tree, moving outwards from the root.\n for (const details of this.nodes) {\n // There can be multiple guards per node.\n for (const guard of details.guards) {\n // Check whether the guard condition passes, and throw an exception if not.\n if (!guard.isSatisfied(agent)) {\n throw new GuardUnsatisifedException(details.node);\n }\n }\n }\n };\n}\n", "/**\n * Enumeration of node state types.\n */\nexport enum State {\n READY = \"mistreevous.ready\",\n RUNNING = \"mistreevous.running\",\n SUCCEEDED = \"mistreevous.succeeded\",\n FAILED = \"mistreevous.failed\"\n}\n\nexport { State as default };\n\nexport type CompleteState = State.SUCCEEDED | State.FAILED;\nexport type AnyState = State.READY | State.RUNNING | CompleteState;\n", "import { Agent } from \"../Agent\";\nimport Attribute from \"../attributes/Attribute\";\nimport Entry from \"../attributes/callbacks/Entry\";\nimport Exit from \"../attributes/callbacks/Exit\";\nimport Step from \"../attributes/callbacks/Step\";\nimport Guard from \"../attributes/guards/Guard\";\nimport GuardPath from \"../attributes/guards/GuardPath\";\nimport GuardUnsatisifedException from \"../attributes/guards/GuardUnsatisifedException\";\nimport { BehaviourTreeOptions } from \"../BehaviourTreeOptions\";\nimport { AnyArgument } from \"../RootAstNodesBuilder\";\nimport State, { AnyState } from \"../State\";\nimport Leaf from \"./leaf/Leaf\";\n\n/**\n * A base node.\n */\nexport default abstract class Node {\n /**\n * The node uid.\n */\n private readonly uid: string = createNodeUid();\n /**\n * The node state.\n */\n private state: AnyState = State.READY;\n /**\n * The guard path to evaluate as part of a node update.\n */\n private guardPath: GuardPath | undefined;\n\n /**\n * @param type The node type.\n * @param attributes The node attributes.\n * @param args The node argument definitions.\n */\n constructor(private type: string, private attributes: Attribute[], private args: AnyArgument[]) {}\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected abstract onUpdate(agent: Agent, options: BehaviourTreeOptions): void;\n\n /**\n * Gets the name of the node.\n */\n public abstract getName(): string;\n\n /**\n * Gets whether this node is a leaf node.\n */\n public abstract isLeafNode: () => this is Leaf;\n\n /**\n * Gets/Sets the state of the node.\n */\n getState = (): AnyState => this.state;\n setState = (value: AnyState): void => {\n this.state = value;\n };\n\n /**\n * Gets the unique id of the node.\n */\n getUid = () => this.uid;\n\n /**\n * Gets the type of the node.\n */\n getType = () => this.type;\n\n /**\n * Gets the node attributes.\n */\n getAttributes = () => this.attributes;\n\n /**\n * Gets the node arguments.\n */\n getArguments = () => this.args;\n\n /**\n * Gets the node attribute with the specified type, or null if it does not exist.\n */\n getAttribute(type: \"entry\" | \"ENTRY\"): Entry;\n getAttribute(type: \"exit\" | \"EXIT\"): Exit;\n getAttribute(type: \"step\" | \"STEP\"): Step;\n getAttribute(type: string): Attribute {\n return (\n this.getAttributes().filter((decorator) => decorator.getType().toUpperCase() === type.toUpperCase())[0] ||\n null\n );\n }\n\n /**\n * Gets the node attributes.\n */\n getGuardAttributes = (): Guard[] => this.getAttributes().filter((decorator) => decorator.isGuard()) as Guard[];\n\n /**\n * Sets the guard path to evaluate as part of a node update.\n */\n setGuardPath = (value: GuardPath) => (this.guardPath = value);\n\n /**\n * Gets whether a guard path is assigned to this node.\n */\n hasGuardPath = () => !!this.guardPath;\n\n /**\n * Gets whether this node is in the specified state.\n * @param value The value to compare to the node state.\n */\n public is(value: AnyState): boolean {\n return this.state === value;\n }\n\n /**\n * Reset the state of the node.\n */\n public reset(): void {\n this.setState(State.READY);\n }\n\n /**\n * Abort the running of this node.\n * @param agent The agent.\n */\n public abort(agent: Agent): void {\n // There is nothing to do if this node is not in the running state.\n if (!this.is(State.RUNNING)) {\n return;\n }\n\n // Reset the state of this node.\n this.reset();\n\n this.getAttribute(\"exit\")?.callAgentFunction(agent, false, true);\n }\n\n /**\n * Update the node.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n * @returns The result of the update.\n */\n public update(agent: Agent, options: BehaviourTreeOptions): void {\n // If this node is already in a 'SUCCEEDED' or 'FAILED' state then there is nothing to do.\n if (this.is(State.SUCCEEDED) || this.is(State.FAILED)) {\n return;\n }\n\n try {\n // Evaluate all of the guard path conditions for the current tree path.\n this.guardPath!.evaluate(agent);\n\n // If this node is in the READY state then call the ENTRY for this node if it exists.\n if (this.is(State.READY)) {\n this.getAttribute(\"entry\")?.callAgentFunction(agent);\n }\n\n this.getAttribute(\"step\")?.callAgentFunction(agent);\n\n // Do the actual update.\n this.onUpdate(agent, options);\n\n // If this node is now in a 'SUCCEEDED' or 'FAILED' state then call the EXIT for this node if it exists.\n if (this.is(State.SUCCEEDED) || this.is(State.FAILED)) {\n this.getAttribute(\"exit\")?.callAgentFunction(agent, this.is(State.SUCCEEDED), false);\n }\n } catch (error) {\n // If the error is a GuardUnsatisfiedException then we need to determine if this node is the source.\n if (error instanceof GuardUnsatisifedException && error.isSourceNode(this)) {\n // Abort the current node.\n this.abort(agent);\n\n // Any node that is the source of an abort will be a failed node.\n this.setState(State.FAILED);\n } else {\n throw error;\n }\n }\n }\n}\n\n/**\n * Create a randomly generated node uid.\n * @returns A randomly generated node uid.\n */\nfunction createNodeUid(): string {\n var S4 = function () {\n return (((1 + Math.random()) * 0x10000) | 0).toString(16).substring(1);\n };\n return S4() + S4() + \"-\" + S4() + \"-\" + S4() + \"-\" + S4() + \"-\" + S4() + S4() + S4();\n}\n", "import Node from \"../Node\";\n\n/**\n * A leaf node.\n */\nexport default abstract class Leaf extends Node {\n /**\n * Gets whether this node is a leaf node.\n */\n isLeafNode = () => true;\n}\n", "import { ActionResult, Agent, ExitFunctionArg, FunctionArg, GlobalFunction } from \"./Agent\";\nimport { AnyArgument, RootAstNode } from \"./RootAstNodesBuilder\";\n\n// Exit callbacks receive their own special type of argument.\n// There's probably stricter ways to represent this but it feels overly complex right now.\ntype ExitResultArg = { value: ExitFunctionArg };\nexport type AnyExitArgument = AnyArgument | ExitResultArg;\n\nexport type InvokerFunction = (args: AnyExitArgument[]) => ActionResult;\n\n/**\n * A singleton used to store and lookup registered functions and subtrees.\n */\nexport default class Lookup {\n /**\n * The object holding any registered functions keyed on function name.\n */\n private static functionTable: { [key: string]: GlobalFunction } = {};\n /**\n * The object holding any registered sub-trees keyed on tree name.\n */\n private static subtreeTable: { [key: string]: RootAstNode } = {};\n\n /**\n * Gets the function with the specified name.\n * @param name The name of the function.\n * @returns The function with the specified name.\n */\n public static getFunc(name: string): GlobalFunction {\n return this.functionTable[name];\n }\n\n /**\n * Sets the function with the specified name for later lookup.\n * @param name The name of the function.\n * @param func The function.\n */\n public static setFunc(name: string, func: GlobalFunction): void {\n this.functionTable[name] = func;\n }\n\n /**\n * Gets the function invoker for the specified agent and function name.\n * If a function with the specified name exists on the agent object then it will\n * be returned, otherwise we will then check the registered functions for a match.\n * @param agent The agent instance that this behaviour tree is modelling behaviour for.\n * @param name The function name.\n * @returns The function invoker for the specified agent and function name.\n */\n static getFuncInvoker(agent: Agent, name: string): InvokerFunction | null {\n // Check whether the agent contains the specified function.\n const foundOnAgent = agent[name];\n if (foundOnAgent && typeof foundOnAgent === \"function\") {\n return (args: AnyExitArgument[]): boolean | ActionResult =>\n foundOnAgent.apply(\n agent,\n args.map((arg) => arg.value)\n );\n }\n\n // The agent does not contain the specified function but it may have been registered at some point.\n if (this.functionTable[name] && typeof this.functionTable[name] === \"function\") {\n return (args: AnyExitArgument[]) => this.functionTable[name](agent, ...args.map((arg) => arg.value));\n }\n\n // We have no function to invoke.\n return null;\n }\n\n /**\n * Gets the subtree with the specified name.\n * @param name The name of the subtree.\n * @returns The subtree with the specified name.\n */\n static getSubtree(name: string): RootAstNode {\n return this.subtreeTable[name];\n }\n\n /**\n * Sets the subtree with the specified name for later lookup.\n * @param name The name of the subtree.\n * @param subtree The subtree.\n */\n static setSubtree(name: string, subtree: RootAstNode) {\n this.subtreeTable[name] = subtree;\n }\n\n /**\n * Removes the registered function or subtree with the specified name.\n * @param name The name of the registered function or subtree.\n */\n static remove(name: string) {\n delete this.functionTable[name];\n delete this.subtreeTable[name];\n }\n\n /**\n * Remove all registered functions and subtrees.\n */\n static empty() {\n this.functionTable = {};\n this.subtreeTable = {};\n }\n}\n", "import Leaf from \"./Leaf\";\nimport State, { CompleteState } from \"../../State\";\nimport Lookup from \"../../Lookup\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { AnyArgument } from \"../../RootAstNodesBuilder\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * An Action leaf node.\n * This represents an immediate or ongoing state of behaviour.\n */\nexport default class Action extends Leaf {\n /**\n * @param attributes The node attributes.\n * @param actionName The action name.\n * @param actionArguments The array of action argument definitions.\n */\n constructor(attributes: Attribute[], private actionName: string, private actionArguments: AnyArgument[]) {\n super(\"action\", attributes, actionArguments);\n }\n\n /**\n * Whether there is a pending update promise.\n */\n private isUsingUpdatePromise = false;\n\n /**\n * The finished state result of an update promise.\n */\n private updatePromiseStateResult: CompleteState | null = null;\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // If the result of this action depends on an update promise then there is nothing to do until\n // it resolves, unless there has been a value set as a result of the update promise resolving.\n if (this.isUsingUpdatePromise) {\n // Check whether the update promise has resolved with a state value.\n if (this.updatePromiseStateResult) {\n // Set the state of this node to match the state returned by the promise.\n this.setState(this.updatePromiseStateResult);\n }\n\n return;\n }\n\n // Attempt to get the invoker for the action function.\n const actionFuncInvoker = Lookup.getFuncInvoker(agent, this.actionName);\n\n // The action function should be defined.\n if (actionFuncInvoker === null) {\n throw new Error(\n `cannot update action node as the action '${this.actionName}' function is not defined on the agent and has not been registered`\n );\n }\n\n // Call the action function, the result of which may be:\n // - The finished state of this action node.\n // - A promise to return a finished node state.\n // - Undefined if the node should remain in the running state.\n const updateResult = actionFuncInvoker(this.actionArguments) as CompleteState | Promise;\n\n if (updateResult instanceof Promise) {\n updateResult.then(\n (result) => {\n // If 'isUpdatePromisePending' is null then the promise was cleared as it was resolving, probably via an abort of reset.\n if (!this.isUsingUpdatePromise) {\n return;\n }\n\n // Check to make sure the result is a valid finished state.\n if (result !== State.SUCCEEDED && result !== State.FAILED) {\n throw new Error(\n \"action node promise resolved with an invalid value, expected a State.SUCCEEDED or State.FAILED value to be returned\"\n );\n }\n\n // Set pending update promise state result to be processed on next update.\n this.updatePromiseStateResult = result;\n },\n (reason) => {\n // If 'isUpdatePromisePending' is null then the promise was cleared as it was resolving, probably via an abort of reset.\n if (!this.isUsingUpdatePromise) {\n return;\n }\n\n // Just throw whatever was returned as the rejection argument.\n throw new Error(reason);\n }\n );\n\n // This node will be in the 'RUNNING' state until the update promise resolves.\n this.setState(State.RUNNING);\n\n // We are now waiting for the promise returned by the use to resolve before we know what state this node is in.\n this.isUsingUpdatePromise = true;\n } else {\n // Validate the returned value.\n this.validateUpdateResult(updateResult);\n\n // Set the state of this node, this may be undefined, which just means that the node is still in the 'RUNNING' state.\n this.setState(updateResult || State.RUNNING);\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => this.actionName;\n\n /**\n * Reset the state of the node.\n */\n reset = () => {\n // Reset the state of this node.\n this.setState(State.READY);\n\n // There is no longer an update promise that we care about.\n this.isUsingUpdatePromise = false;\n this.updatePromiseStateResult = null;\n };\n\n /**\n * Validate the result of an update function call.\n * @param result The result of an update function call.\n */\n private validateUpdateResult = (result: CompleteState | boolean) => {\n switch (result) {\n case State.SUCCEEDED:\n case State.FAILED:\n case undefined:\n return;\n default:\n throw new Error(\n `action '${this.actionName}' 'onUpdate' returned an invalid response, expected an optional State.SUCCEEDED or State.FAILED value to be returned`\n );\n }\n };\n}\n", "import Leaf from \"./Leaf\";\nimport State from \"../../State\";\nimport Lookup from \"../../Lookup\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { AnyArgument } from \"../../RootAstNodesBuilder\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A Condition leaf node.\n * This will succeed or fail immediately based on an agent predicate, without moving to the 'RUNNING' state.\n */\nexport default class Condition extends Leaf {\n /**\n * @param attributes The node attributes.\n * @param conditionName The name of the condition function.\n * @param conditionArguments The array of condition argument definitions.\n */\n constructor(attributes: Attribute[], private conditionName: string, private conditionArguments: AnyArgument[]) {\n super(\"condition\", attributes, conditionArguments);\n }\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // Attempt to get the invoker for the condition function.\n const conditionFuncInvoker = Lookup.getFuncInvoker(agent, this.conditionName);\n\n // The condition function should be defined.\n if (conditionFuncInvoker === null) {\n throw new Error(\n `cannot update condition node as the condition '${this.conditionName}' function is not defined on the agent and has not been registered`\n );\n }\n\n // Call the condition function to determine the state of this node.\n this.setState(!!conditionFuncInvoker(this.conditionArguments) ? State.SUCCEEDED : State.FAILED);\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => this.conditionName;\n}\n", "import Leaf from \"./Leaf\";\nimport State from \"../../State\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { Agent } from \"../../Agent\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A WAIT node.\n * The state of this node will change to SUCCEEDED after a duration of time\n */\nexport default class Wait extends Leaf {\n /**\n * @param attributes The node attributes.\n * @param duration The duration that this node will wait to succeed in milliseconds, or the earliest if longestDuration is defined.\n * @param longestDuration The longest possible duration in milliseconds that this node will wait to succeed.\n */\n constructor(attributes: Attribute[], private duration: number, private longestDuration: number) {\n super(\"wait\", attributes, []);\n }\n\n /**\n * The time in milliseconds at which this node was first updated.\n */\n private initialUpdateTime: number = 0;\n\n /**\n * The total duration in milliseconds that this node will be waiting for.\n */\n private totalDuration: number = 0;\n\n /**\n * The duration in milliseconds that this node has been waiting for.\n */\n private waitedDuration: number = 0;\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // If this node is in the READY state then we need to set the initial update time.\n if (this.is(State.READY)) {\n // Set the initial update time.\n this.initialUpdateTime = new Date().getTime();\n\n // Set the initial waited duration.\n this.waitedDuration = 0;\n\n // If a longestDuration value was defined then we will be randomly picking a duration between the\n // shortest and longest duration. If it was not defined, then we will be just using the duration.\n this.totalDuration = this.longestDuration\n ? Math.floor(Math.random() * (this.longestDuration - this.duration + 1) + this.duration)\n : this.duration;\n\n // The node is now running until we finish waiting.\n this.setState(State.RUNNING);\n }\n\n // If we have a 'getDeltaTime' function defined as part of our options then we will use it to figure out how long we have waited for.\n if (typeof options.getDeltaTime === \"function\") {\n // Get the delta time.\n const deltaTime = options.getDeltaTime();\n\n // Our delta time must be a valid number and cannot be NaN.\n if (typeof deltaTime !== \"number\" || isNaN(deltaTime)) {\n throw new Error(\"The delta time must be a valid number and not NaN.\");\n }\n\n // Update the amount of time that this node has been waiting for based on the delta time.\n this.waitedDuration += deltaTime * 1000;\n } else {\n // We are not using a delta time, so we will just work out hom much time has passed since the first update.\n this.waitedDuration = new Date().getTime() - this.initialUpdateTime;\n }\n\n // Have we waited long enough?\n if (this.waitedDuration >= this.totalDuration) {\n // We have finished waiting!\n this.setState(State.SUCCEEDED);\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () =>\n `WAIT ${this.longestDuration ? this.duration + \"ms-\" + this.longestDuration + \"ms\" : this.duration + \"ms\"}`;\n}\n", "import Node from \"../Node\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\n\n/**\n * A decorator node that wraps a single child node.\n */\nexport default abstract class Decorator extends Node {\n /**\n * @param type The node type.\n * @param attributes The node attributes.\n * @param child The child node.\n */\n constructor(type: string, attributes: Attribute[], protected child: Node) {\n super(type, attributes, []);\n }\n\n /**\n * Gets whether this node is a leaf node.\n */\n isLeafNode = () => false;\n\n /**\n * Gets the children of this node.\n */\n getChildren = () => [this.child];\n\n /**\n * Reset the state of the node.\n */\n reset = () => {\n // Reset the state of this node.\n this.setState(State.READY);\n\n // Reset the state of the child node.\n this.child.reset();\n };\n\n /**\n * Abort the running of this node.\n * @param agent The agent.\n */\n abort = (agent: Agent) => {\n // There is nothing to do if this node is not in the running state.\n if (!this.is(State.RUNNING)) {\n return;\n }\n\n // Abort the child node.\n this.child.abort(agent);\n\n // Reset the state of this node.\n this.reset();\n\n this.getAttribute(\"exit\")?.callAgentFunction(agent, false, true);\n };\n}\n", "import Node from \"../Node\";\nimport Decorator from \"./Decorator\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A Root node.\n * The root node will have a single child.\n */\nexport default class Root extends Decorator {\n /**\n * @param attributes The node attributes.\n * @param child The child node.\n */\n constructor(attributes: Attribute[], child: Node) {\n super(\"root\", attributes, child);\n }\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // If the child has never been updated or is running then we will need to update it now.\n if (this.child.getState() === State.READY || this.child.getState() === State.RUNNING) {\n // Update the child of this node.\n this.child.update(agent, options);\n }\n\n // The state of the root node is the state of its child.\n this.setState(this.child.getState());\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => \"ROOT\";\n}\n", "import Node from \"../Node\";\nimport Decorator from \"./Decorator\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A REPEAT node.\n * The node has a single child which can have:\n * -- A number of iterations for which to repeat the child node.\n * -- An infinite repeat loop if neither an iteration count or a condition function is defined.\n * The REPEAT node will stop and have a 'FAILED' state if its child is ever in a 'FAILED' state after an update.\n * The REPEAT node will attempt to move on to the next iteration if its child is ever in a 'SUCCEEDED' state.\n */\nexport default class Repeat extends Decorator {\n /**\n * @param attributes The node attributes.\n * @param iterations The number of iterations to repeat the child node, or the minimum number of iterations if maximumIterations is defined.\n * @param maximumIterations The maximum number of iterations to repeat the child node.\n * @param child The child node.\n */\n constructor(\n attributes: Attribute[],\n private iterations: number | null,\n private maximumIterations: number | null,\n child: Node\n ) {\n super(\"repeat\", attributes, child);\n }\n\n /**\n * The number of target iterations to make.\n */\n private targetIterationCount: number | null = null;\n\n /**\n * The current iteration count.\n */\n private currentIterationCount: number = 0;\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // If this node is in the READY state then we need to reset the child and the target iteration count.\n if (this.is(State.READY)) {\n // Reset the child node.\n this.child.reset();\n\n // Set the target iteration count.\n this.setTargetIterationCount();\n }\n\n // Do a check to see if we can iterate. If we can then this node will move into the 'RUNNING' state.\n // If we cannot iterate then we have hit our target iteration count, which means that the node has succeeded.\n if (this.canIterate()) {\n // This node is in the running state and can do its initial iteration.\n this.setState(State.RUNNING);\n\n // We may have already completed an iteration, meaning that the child node will be in the SUCCEEDED state.\n // If this is the case then we will have to reset the child node now.\n if (this.child.getState() === State.SUCCEEDED) {\n this.child.reset();\n }\n\n // Update the child of this node.\n this.child.update(agent, options);\n\n // If the child moved into the FAILED state when we updated it then there is nothing left to do and this node has also failed.\n // If it has moved into the SUCCEEDED state then we have completed the current iteration.\n if (this.child.getState() === State.FAILED) {\n // The child has failed, meaning that this node has failed.\n this.setState(State.FAILED);\n\n return;\n } else if (this.child.getState() === State.SUCCEEDED) {\n // We have completed an iteration.\n this.currentIterationCount += 1;\n }\n } else {\n // This node is in the 'SUCCEEDED' state as we cannot iterate any more.\n this.setState(State.SUCCEEDED);\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => {\n if (this.iterations !== null) {\n return `REPEAT ${\n this.maximumIterations ? this.iterations + \"x-\" + this.maximumIterations + \"x\" : this.iterations + \"x\"\n }`;\n }\n\n // Return the default repeat node name.\n return \"REPEAT\";\n };\n\n /**\n * Reset the state of the node.\n */\n reset = () => {\n // Reset the state of this node.\n this.setState(State.READY);\n\n // Reset the current iteration count.\n this.currentIterationCount = 0;\n\n // Reset the child node.\n this.child.reset();\n };\n\n /**\n * Gets whether an iteration can be made.\n * @returns Whether an iteration can be made.\n */\n private canIterate = () => {\n if (this.targetIterationCount !== null) {\n // We can iterate as long as we have not reached our target iteration count.\n return this.currentIterationCount < this.targetIterationCount;\n }\n\n // If neither an iteration count or a condition function were defined then we can iterate indefinitely.\n return true;\n };\n\n /**\n * Sets the target iteration count.\n */\n private setTargetIterationCount = () => {\n // Are we dealing with a finite number of iterations?\n if (typeof this.iterations === \"number\") {\n // If we have maximumIterations defined then we will want a random iteration count bounded by iterations and maximumIterations.\n this.targetIterationCount =\n typeof this.maximumIterations === \"number\"\n ? Math.floor(Math.random() * (this.maximumIterations - this.iterations + 1) + this.iterations)\n : this.iterations;\n } else {\n this.targetIterationCount = null;\n }\n };\n}\n", "import Node from \"../Node\";\nimport Decorator from \"./Decorator\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A RETRY node.\n * The node has a single child which can have:\n * -- A number of iterations for which to repeat the child node.\n * -- An infinite repeat loop if neither an iteration count or a condition function is defined.\n * The RETRY node will stop and have a 'SUCCEEDED' state if its child is ever in a 'SUCCEEDED' state after an update.\n * The RETRY node will attempt to move on to the next iteration if its child is ever in a 'FAILED' state.\n */\nexport default class Retry extends Decorator {\n /**\n * @param attributes The node attributes.\n * @param iterations The number of iterations to repeat the child node, or the minimum number of iterations if maximumIterations is defined.\n * @param maximumIterations The maximum number of iterations to repeat the child node.\n * @param child The child node.\n */\n constructor(\n attributes: Attribute[],\n private iterations: number | null,\n private maximumIterations: number | null,\n child: Node\n ) {\n super(\"retry\", attributes, child);\n }\n\n /**\n * The number of target iterations to make.\n */\n private targetIterationCount: number | null = null;\n\n /**\n * The current iteration count.\n */\n private currentIterationCount: number = 0;\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // If this node is in the READY state then we need to reset the child and the target iteration count.\n if (this.is(State.READY)) {\n // Reset the child node.\n this.child.reset();\n\n // Set the target iteration count.\n this.setTargetIterationCount();\n }\n\n // Do a check to see if we can iterate. If we can then this node will move into the 'RUNNING' state.\n // If we cannot iterate then we have hit our target iteration count, which means that the node has succeeded.\n if (this.canIterate()) {\n // This node is in the running state and can do its initial iteration.\n this.setState(State.RUNNING);\n\n // We may have already completed an iteration, meaning that the child node will be in the FAILED state.\n // If this is the case then we will have to reset the child node now.\n if (this.child.getState() === State.FAILED) {\n this.child.reset();\n }\n\n // Update the child of this node.\n this.child.update(agent, options);\n\n // If the child moved into the SUCCEEDED state when we updated it then there is nothing left to do and this node has also succeeded.\n // If it has moved into the FAILED state then we have completed the current iteration.\n if (this.child.getState() === State.SUCCEEDED) {\n // The child has succeeded, meaning that this node has succeeded.\n this.setState(State.SUCCEEDED);\n\n return;\n } else if (this.child.getState() === State.FAILED) {\n // We have completed an iteration.\n this.currentIterationCount += 1;\n }\n } else {\n // This node is in the 'FAILED' state as we cannot iterate any more.\n this.setState(State.FAILED);\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => {\n if (this.iterations !== null) {\n return `RETRY ${\n this.maximumIterations ? this.iterations + \"x-\" + this.maximumIterations + \"x\" : this.iterations + \"x\"\n }`;\n }\n\n // Return the default retry node name.\n return \"RETRY\";\n };\n\n /**\n * Reset the state of the node.\n */\n reset = () => {\n // Reset the state of this node.\n this.setState(State.READY);\n\n // Reset the current iteration count.\n this.currentIterationCount = 0;\n\n // Reset the child node.\n this.child.reset();\n };\n\n /**\n * Gets whether an iteration can be made.\n * @returns Whether an iteration can be made.\n */\n canIterate = () => {\n if (this.targetIterationCount !== null) {\n // We can iterate as long as we have not reached our target iteration count.\n return this.currentIterationCount < this.targetIterationCount;\n }\n\n // If neither an iteration count or a condition function were defined then we can iterate indefinitely.\n return true;\n };\n\n /**\n * Sets the target iteration count.\n */\n setTargetIterationCount = () => {\n // Are we dealing with a finite number of iterations?\n if (typeof this.iterations === \"number\") {\n // If we have maximumIterations defined then we will want a random iteration count bounded by iterations and maximumIterations.\n this.targetIterationCount =\n typeof this.maximumIterations === \"number\"\n ? Math.floor(Math.random() * (this.maximumIterations - this.iterations + 1) + this.iterations)\n : this.iterations;\n } else {\n this.targetIterationCount = null;\n }\n };\n}\n", "import Decorator from \"./Decorator\";\nimport State from \"../../State\";\nimport Node from \"../Node\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A Flip node.\n * This node wraps a single child and will flip the state of the child state.\n */\nexport default class Flip extends Decorator {\n /**\n * @param attributes The node attributes.\n * @param child The child node.\n */\n constructor(attributes: Attribute[], child: Node) {\n super(\"flip\", attributes, child);\n }\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // If the child has never been updated or is running then we will need to update it now.\n if (this.child.getState() === State.READY || this.child.getState() === State.RUNNING) {\n this.child.update(agent, options);\n }\n\n // The state of this node will depend in the state of its child.\n switch (this.child.getState()) {\n case State.RUNNING:\n this.setState(State.RUNNING);\n break;\n\n case State.SUCCEEDED:\n this.setState(State.FAILED);\n break;\n\n case State.FAILED:\n this.setState(State.SUCCEEDED);\n break;\n\n default:\n this.setState(State.READY);\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => \"FLIP\";\n}\n", "import Node from \"../Node\";\nimport Decorator from \"./Decorator\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A Succeed node.\n * This node wraps a single child and will always move to the 'SUCCEEDED' state when the child moves to a 'SUCCEEDED' or 'FAILED' state.\n */\nexport default class Succeed extends Decorator {\n /**\n * @param attributes The node attributes.\n * @param child The child node.\n */\n constructor(attributes: Attribute[], child: Node) {\n super(\"succeed\", attributes, child);\n }\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // If the child has never been updated or is running then we will need to update it now.\n if (this.child.getState() === State.READY || this.child.getState() === State.RUNNING) {\n this.child.update(agent, options);\n }\n\n // The state of this node will depend in the state of its child.\n switch (this.child.getState()) {\n case State.RUNNING:\n this.setState(State.RUNNING);\n break;\n\n case State.SUCCEEDED:\n case State.FAILED:\n this.setState(State.SUCCEEDED);\n break;\n\n default:\n this.setState(State.READY);\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => \"SUCCEED\";\n}\n", "import Node from \"../Node\";\nimport Decorator from \"./Decorator\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A Fail node.\n * This node wraps a single child and will always move to the 'FAILED' state when the child moves to a 'SUCCEEDED' or 'FAILED' state.\n */\nexport default class Fail extends Decorator {\n /**\n * @param attributes The node attributes.\n * @param child The child node.\n */\n constructor(attributes: Attribute[], child: Node) {\n super(\"fail\", attributes, child);\n }\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // If the child has never been updated or is running then we will need to update it now.\n if (this.child.getState() === State.READY || this.child.getState() === State.RUNNING) {\n this.child.update(agent, options);\n }\n\n // The state of this node will depend in the state of its child.\n switch (this.child.getState()) {\n case State.RUNNING:\n this.setState(State.RUNNING);\n break;\n\n case State.SUCCEEDED:\n case State.FAILED:\n this.setState(State.FAILED);\n break;\n\n default:\n this.setState(State.READY);\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => \"FAIL\";\n}\n", "import createLotto from \"lotto-draw\";\n\nimport Node from \"../Node\";\nimport Composite from \"./Composite\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A LOTTO node.\n * A winning child is picked on the initial update of this node, based on ticket weighting.\n * The state of this node will match the state of the winning child.\n */\nexport default class Lotto extends Composite {\n /**\n * @param attributes The node attributes.\n * @param tickets The child node tickets.\n * @param children The child nodes.\n */\n constructor(attributes: Attribute[], private tickets: number[], children: Node[]) {\n super(\"lotto\", attributes, children);\n }\n\n /**\n * The child node selected to be the active one.\n */\n private selectedChild: Node | undefined;\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // If this node is in the READY state then we need to pick a winning child node.\n if (this.is(State.READY)) {\n // Create a lotto draw with which to randomly pick a child node to become the active one.\n const lottoDraw = createLotto({\n // Hook up the optional 'random' behaviour tree function option to the one used by 'lotto-draw'.\n random: options.random,\n // Pass in each child node as a participant in the lotto draw with their respective ticket count.\n participants: this.children.map((child, index) => [child, this.tickets[index] || 1])\n });\n\n // Randomly pick a child based on ticket weighting, this will become the active child for this composite node.\n this.selectedChild = lottoDraw.draw() || undefined;\n }\n\n // If something went wrong and we don't have an active child then we should throw an error.\n if (!this.selectedChild) {\n throw new Error(\"failed to update lotto node as it has no active child\");\n }\n\n // If the selected child has never been updated or is running then we will need to update it now.\n if (this.selectedChild.getState() === State.READY || this.selectedChild.getState() === State.RUNNING) {\n this.selectedChild.update(agent, options);\n }\n\n // The state of the lotto node is the state of its selected child.\n this.setState(this.selectedChild.getState());\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => (this.tickets.length ? `LOTTO [${this.tickets.join(\",\")}]` : \"LOTTO\");\n}\n", "import Node from \"../Node\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\n\n/**\n * A composite node that wraps child nodes.\n */\nexport default abstract class Composite extends Node {\n /**\n * @param type The node type.\n * @param attributes The node attributes.\n * @param children The child nodes.\n */\n constructor(type: string, attributes: Attribute[], protected children: Node[]) {\n super(type, attributes, []);\n }\n\n /**\n * Gets whether this node is a leaf node.\n */\n isLeafNode = () => false;\n\n /**\n * Gets the children of this node.\n */\n getChildren = () => this.children;\n\n /**\n * Reset the state of the node.\n */\n reset = () => {\n // Reset the state of this node.\n this.setState(State.READY);\n\n // Reset the state of any child nodes.\n this.getChildren().forEach((child) => child.reset());\n };\n\n /**\n * Abort the running of this node.\n * @param agent The agent.\n */\n abort = (agent: Agent) => {\n // There is nothing to do if this node is not in the running state.\n if (!this.is(State.RUNNING)) {\n return;\n }\n\n // Abort any child nodes.\n this.getChildren().forEach((child) => child.abort(agent));\n\n // Reset the state of this node.\n this.reset();\n\n this.getAttribute(\"exit\")?.callAgentFunction(agent, false, true);\n };\n}\n", "import Composite from \"./Composite\";\nimport Node from \"../Node\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A SELECTOR node.\n * The child nodes are executed in sequence until one succeeds or all fail.\n */\nexport default class Selector extends Composite {\n /**\n * @param attributes The node attributes.\n * @param children The child nodes.\n */\n constructor(attributes: Attribute[], protected children: Node[]) {\n super(\"selector\", attributes, children);\n }\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // Iterate over all of the children of this node.\n for (const child of this.children) {\n // If the child has never been updated or is running then we will need to update it now.\n if (child.getState() === State.READY || child.getState() === State.RUNNING) {\n // Update the child of this node.\n child.update(agent, options);\n }\n\n // If the current child has a state of 'SUCCEEDED' then this node is also a 'SUCCEEDED' node.\n if (child.getState() === State.SUCCEEDED) {\n // This node is a 'SUCCEEDED' node.\n this.setState(State.SUCCEEDED);\n\n // There is no need to check the rest of the selector nodes.\n return;\n }\n\n // If the current child has a state of 'FAILED' then we should move on to the next child.\n if (child.getState() === State.FAILED) {\n // Find out if the current child is the last one in the selector.\n // If it is then this sequence node has also failed.\n if (this.children.indexOf(child) === this.children.length - 1) {\n // This node is a 'FAILED' node.\n this.setState(State.FAILED);\n\n // There is no need to check the rest of the selector as we have completed it.\n return;\n } else {\n // The child node failed, try the next one.\n continue;\n }\n }\n\n // The node should be in the 'RUNNING' state.\n if (child.getState() === State.RUNNING) {\n // This node is a 'RUNNING' node.\n this.setState(State.RUNNING);\n\n // There is no need to check the rest of the selector as the current child is still running.\n return;\n }\n\n // The child node was not in an expected state.\n throw new Error(\"child node was not in an expected state.\");\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => \"SELECTOR\";\n}\n", "import Composite from \"./Composite\";\nimport Node from \"../Node\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A SEQUENCE node.\n * The child nodes are executed in sequence until one fails or all succeed.\n */\nexport default class Sequence extends Composite {\n /**\n * @param attributes The node attributes.\n * @param children The child nodes.\n */\n constructor(attributes: Attribute[], protected children: Node[]) {\n super(\"sequence\", attributes, children);\n }\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // Iterate over all of the children of this node.\n for (const child of this.children) {\n // If the child has never been updated or is running then we will need to update it now.\n if (child.getState() === State.READY || child.getState() === State.RUNNING) {\n // Update the child of this node.\n child.update(agent, options);\n }\n\n // If the current child has a state of 'SUCCEEDED' then we should move on to the next child.\n if (child.getState() === State.SUCCEEDED) {\n // Find out if the current child is the last one in the sequence.\n // If it is then this sequence node has also succeeded.\n if (this.children.indexOf(child) === this.children.length - 1) {\n // This node is a 'SUCCEEDED' node.\n this.setState(State.SUCCEEDED);\n\n // There is no need to check the rest of the sequence as we have completed it.\n return;\n } else {\n // The child node succeeded, but we have not finished the sequence yet.\n continue;\n }\n }\n\n // If the current child has a state of 'FAILED' then this node is also a 'FAILED' node.\n if (child.getState() === State.FAILED) {\n // This node is a 'FAILED' node.\n this.setState(State.FAILED);\n\n // There is no need to check the rest of the sequence.\n return;\n }\n\n // The node should be in the 'RUNNING' state.\n if (child.getState() === State.RUNNING) {\n // This node is a 'RUNNING' node.\n this.setState(State.RUNNING);\n\n // There is no need to check the rest of the sequence as the current child is still running.\n return;\n }\n\n // The child node was not in an expected state.\n throw new Error(\"child node was not in an expected state.\");\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => \"SEQUENCE\";\n}\n", "import Composite from \"./Composite\";\nimport State from \"../../State\";\nimport Node from \"../Node\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A PARALLEL node.\n * The child nodes are executed concurrently until one fails or all succeed.\n */\nexport default class Parallel extends Composite {\n /**\n * @param attributes The node attributes.\n * @param children The child nodes.\n */\n constructor(attributes: Attribute[], children: Node[]) {\n super(\"parallel\", attributes, children);\n }\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // Keep a count of the number of succeeded child nodes.\n let succeededCount = 0;\n\n let hasChildFailed = false;\n\n // Iterate over all of the children of this node.\n for (const child of this.children) {\n // If the child has never been updated or is running then we will need to update it now.\n if (child.getState() === State.READY || child.getState() === State.RUNNING) {\n // Update the child of this node.\n child.update(agent, options);\n }\n\n // If the current child has a state of 'SUCCEEDED' then we should move on to the next child.\n if (child.getState() === State.SUCCEEDED) {\n // The child node has succeeded, keep track of this to determine if all children have.\n succeededCount++;\n\n // The child node succeeded, but we have not finished checking every child node yet.\n continue;\n }\n\n // If the current child has a state of 'FAILED' then this node is also a 'FAILED' node.\n if (child.getState() === State.FAILED) {\n hasChildFailed = true;\n\n // There is no need to check the rest of the children.\n break;\n }\n\n // The node should be in the 'RUNNING' state.\n if (child.getState() !== State.RUNNING) {\n // The child node was not in an expected state.\n throw new Error(\"child node was not in an expected state.\");\n }\n }\n\n if (hasChildFailed) {\n // This node is a 'FAILED' node.\n this.setState(State.FAILED);\n\n // Abort every running child.\n for (const child of this.children) {\n if (child.getState() === State.RUNNING) {\n child.abort(agent);\n }\n }\n } else {\n // If all children have succeeded then this node has also succeeded, otherwise it is still running.\n this.setState(succeededCount === this.children.length ? State.SUCCEEDED : State.RUNNING);\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => \"PARALLEL\";\n}\n", "import { AnyArgument } from \"../RootAstNodesBuilder\";\nimport Guard from \"./guards/Guard\";\n\nexport type AttributeDetails = {\n /** The attribute type. */\n type: string;\n\n /** The attribute arguments. */\n args: AnyArgument[];\n};\n\n/**\n * A base node attribute.\n */\nexport default abstract class Attribute {\n /**\n * @param type The node attribute type.\n * @param args The array of attribute argument definitions.\n */\n constructor(protected type: string, protected args: AnyArgument[]) {}\n\n /**\n * Gets the type of the attribute.\n */\n getType = () => this.type;\n\n /**\n * Gets the array of attribute argument definitions.\n */\n getArguments = () => this.args;\n\n /**\n * Gets the attribute details.\n */\n abstract getDetails(): TAttributeDetails;\n\n /**\n * Gets whether this attribute is a guard.\n */\n abstract isGuard: () => this is Guard;\n}\n", "import { Agent } from \"../../Agent\";\nimport { AnyArgument } from \"../../RootAstNodesBuilder\";\nimport Attribute, { AttributeDetails } from \"../Attribute\";\n\nexport type GuardAttributeDetails = {\n /** The name of the condition function that determines whether the guard is satisfied. */\n condition: string;\n} & AttributeDetails;\n\n/**\n * A base node guard attribute.\n */\nexport default abstract class Guard extends Attribute {\n /**\n * @param type The node attribute type.\n * @param args The array of decorator argument definitions.\n * @param condition The name of the condition function that determines whether the guard is satisfied.\n */\n constructor(type: string, args: AnyArgument[], private condition: string) {\n super(type, args);\n }\n\n /**\n * Gets the name of the condition function that determines whether the guard is satisfied.\n */\n getCondition = () => this.condition;\n\n /**\n * Gets whether this attribute is a guard.\n */\n isGuard = () => true;\n\n /**\n * Gets the attribute details.\n */\n getDetails(): GuardAttributeDetails {\n return {\n type: this.getType(),\n args: this.getArguments(),\n condition: this.getCondition()\n };\n }\n\n /**\n * Gets whether the guard is satisfied.\n * @param agent The agent.\n * @returns Whether the guard is satisfied.\n */\n abstract isSatisfied(agent: Agent): boolean;\n}\n", "import Guard from \"./Guard\";\nimport Lookup from \"../../Lookup\";\nimport { Agent } from \"../../Agent\";\nimport { AnyArgument } from \"../../RootAstNodesBuilder\";\n\n/**\n * A WHILE guard which is satisfied as long as the given condition remains true.\n */\nexport default class While extends Guard {\n /**\n * @param condition The name of the condition function that determines whether the guard is satisfied.\n * @param args The array of decorator argument definitions.\n */\n constructor(condition: string, args: AnyArgument[]) {\n super(\"while\", args, condition);\n }\n\n /**\n * Gets whether the guard is satisfied.\n * @param agent The agent.\n * @returns Whether the guard is satisfied.\n */\n isSatisfied = (agent: Agent) => {\n // Attempt to get the invoker for the condition function.\n const conditionFuncInvoker = Lookup.getFuncInvoker(agent, this.getCondition());\n\n // The condition function should be defined.\n if (conditionFuncInvoker === null) {\n throw new Error(\n `cannot evaluate node guard as the condition '${this.getCondition()}' function is not defined on the agent and has not been registered`\n );\n }\n\n // Call the condition function to determine whether this guard is satisfied.\n return !!conditionFuncInvoker(this.args);\n };\n}\n", "import Guard from \"./Guard\";\nimport Lookup from \"../../Lookup\";\nimport { Agent } from \"../../Agent\";\nimport { AnyArgument } from \"../../RootAstNodesBuilder\";\n\n/**\n * An UNTIL guard which is satisfied as long as the given condition remains false.\n */\nexport default class Until extends Guard {\n /**\n * @param condition The name of the condition function that determines whether the guard is satisfied.\n * @param args The array of decorator argument definitions.\n */\n constructor(condition: string, args: AnyArgument[]) {\n super(\"until\", args, condition);\n }\n\n /**\n * Gets whether the guard is satisfied.\n * @param agent The agent.\n * @returns Whether the guard is satisfied.\n */\n isSatisfied = (agent: Agent) => {\n // Attempt to get the invoker for the condition function.\n const conditionFuncInvoker = Lookup.getFuncInvoker(agent, this.getCondition());\n\n // The condition function should be defined.\n if (conditionFuncInvoker === null) {\n throw new Error(\n `cannot evaluate node guard as the condition '${this.getCondition()}' function is not defined on the agent and has not been registered`\n );\n }\n\n // Call the condition function to determine whether this guard is satisfied.\n return !!!conditionFuncInvoker(this.args);\n };\n}\n", "import { Agent } from \"../../Agent\";\nimport { AnyArgument } from \"../../RootAstNodesBuilder\";\nimport Attribute, { AttributeDetails } from \"../Attribute\";\n\nexport type CallbackAttributeDetails = {\n /** The name of the agent function that is called. */\n functionName: string;\n} & AttributeDetails;\n\n/**\n * A base node callback attribute.\n */\nexport default abstract class Callback extends Attribute {\n /**\n * @param type The node attribute type.\n * @param args The array of decorator argument definitions.\n * @param functionName The name of the agent function to call.\n */\n constructor(type: string, args: AnyArgument[], private functionName: string) {\n super(type, args);\n }\n\n /**\n * Gets the name of the agent function to call.\n */\n getFunctionName = () => this.functionName;\n\n /**\n * Gets whether this attribute is a guard.\n */\n isGuard = () => false;\n\n /**\n * Gets the attribute details.\n */\n getDetails(): CallbackAttributeDetails {\n return {\n type: this.getType(),\n args: this.getArguments(),\n functionName: this.getFunctionName()\n };\n }\n\n /**\n * Attempt to call the agent function that this callback refers to.\n * @param agent The agent.\n */\n abstract callAgentFunction: (agent: Agent, isSuccess: boolean, isAborted: boolean) => void;\n}\n", "import Callback from \"./Callback\";\nimport Lookup from \"../../Lookup\";\nimport { Agent } from \"../../Agent\";\nimport { AnyArgument } from \"../../RootAstNodesBuilder\";\n\n/**\n * An ENTRY callback which defines an agent function to call when the associated node is updated and moves out of running state.\n */\nexport default class Entry extends Callback {\n /**\n * @param functionName The name of the agent function to call.\n * @param args The array of callback argument definitions.\n */\n constructor(functionName: string, args: AnyArgument[]) {\n super(\"entry\", args, functionName);\n }\n\n /**\n * Attempt to call the agent function that this callback refers to.\n * @param agent The agent.\n */\n callAgentFunction = (agent: Agent) => {\n // Attempt to get the invoker for the callback function.\n const callbackFuncInvoker = Lookup.getFuncInvoker(agent, this.getFunctionName());\n\n // The callback function should be defined.\n if (callbackFuncInvoker === null) {\n throw new Error(\n `cannot call entry function '${this.getFunctionName()}' as is not defined on the agent and has not been registered`\n );\n }\n\n // Call the callback function.\n callbackFuncInvoker(this.args);\n };\n}\n", "import Callback from \"./Callback\";\nimport Lookup, { AnyExitArgument } from \"../../Lookup\";\nimport { Agent } from \"../../Agent\";\nimport { AnyArgument } from \"../../RootAstNodesBuilder\";\n\n/**\n * An EXIT callback which defines an agent function to call when the associated node is updated and moves to a finished state or is aborted.\n */\nexport default class Exit extends Callback {\n /**\n * @param functionName The name of the agent function to call.\n * @param args The array of callback argument definitions.\n */\n constructor(functionName: string, args: AnyArgument[]) {\n super(\"exit\", args, functionName);\n }\n\n /**\n * Attempt to call the agent function that this callback refers to.\n * @param agent The agent.\n * @param isSuccess Whether the decorated node was left with a success state.\n * @param isAborted Whether the decorated node was aborted.\n */\n callAgentFunction = (agent: Agent, isSuccess: boolean, isAborted: boolean) => {\n // Attempt to get the invoker for the callback function.\n const callbackFuncInvoker = Lookup.getFuncInvoker(agent, this.getFunctionName());\n\n // The callback function should be defined.\n if (callbackFuncInvoker === null) {\n throw new Error(\n `cannot call exit function '${this.getFunctionName()}' as is not defined on the agent and has not been registered`\n );\n }\n\n // Call the callback function\n callbackFuncInvoker([{ value: { succeeded: isSuccess, aborted: isAborted } }, ...this.args]);\n };\n}\n", "import Callback from \"./Callback\";\nimport Lookup from \"../../Lookup\";\nimport { Agent } from \"../../Agent\";\nimport { AnyArgument } from \"../../RootAstNodesBuilder\";\n\n/**\n * A STEP callback which defines an agent function to call when the associated node is updated.\n */\nexport default class Step extends Callback {\n /**\n * @param functionName The name of the agent function to call.\n * @param args The array of callback argument definitions.\n */\n constructor(functionName: string, args: AnyArgument[]) {\n super(\"step\", args, functionName);\n }\n\n /**\n * Attempt to call the agent function that this callback refers to.\n * @param agent The agent.\n */\n callAgentFunction = (agent: Agent) => {\n // Attempt to get the invoker for the callback function.\n const callbackFuncInvoker = Lookup.getFuncInvoker(agent, this.getFunctionName());\n\n // The callback function should be defined.\n if (callbackFuncInvoker === null) {\n throw new Error(\n `cannot call step function '${this.getFunctionName()}' as is not defined on the agent and has not been registered`\n );\n }\n\n // Call the callback function.\n callbackFuncInvoker(this.args);\n };\n}\n", "import Action from \"./nodes/leaf/Action\";\nimport Condition from \"./nodes/leaf/Condition\";\nimport Wait from \"./nodes/leaf/Wait\";\nimport Root from \"./nodes/decorator/Root\";\nimport Repeat from \"./nodes/decorator/Repeat\";\nimport Retry from \"./nodes/decorator/Retry\";\nimport Flip from \"./nodes/decorator/Flip\";\nimport Succeed from \"./nodes/decorator/Succeed\";\nimport Fail from \"./nodes/decorator/Fail\";\nimport Lotto from \"./nodes/composite/Lotto\";\nimport Selector from \"./nodes/composite/Selector\";\nimport Sequence from \"./nodes/composite/Sequence\";\nimport Parallel from \"./nodes/composite/Parallel\";\nimport Node from \"./nodes/Node\";\nimport While from \"./attributes/guards/While\";\nimport Until from \"./attributes/guards/Until\";\nimport Entry from \"./attributes/callbacks/Entry\";\nimport Exit from \"./attributes/callbacks/Exit\";\nimport Step from \"./attributes/callbacks/Step\";\nimport Callback from \"./attributes/callbacks/Callback\";\nimport Guard from \"./attributes/guards/Guard\";\nimport Attribute from \"./attributes/Attribute\";\nimport Composite from \"./nodes/composite/Composite\";\nimport Decorator from \"./nodes/decorator/Decorator\";\nimport Leaf from \"./nodes/leaf/Leaf\";\n\nexport type Argument = {\n value: T;\n type: string; // Used for validation.\n};\ntype NullArgument = Argument & {\n type: \"null\";\n};\ntype BooleanArgument = Argument & {\n type: \"boolean\";\n};\ntype NumberArgument = Argument & {\n type: \"number\";\n isInteger: boolean; // Used for validation.\n};\ntype StringPlaceholderArgument = Argument & {\n type: \"string\";\n};\ntype IdentifierArgument = Argument & {\n type: \"identifier\";\n};\nexport type AnyArgument =\n | NullArgument\n | BooleanArgument\n | NumberArgument\n | StringPlaceholderArgument\n | IdentifierArgument;\n\n/**\n * The node attribute factories.\n */\nconst AttributeFactories: {\n [key: string]: (functionName: string, attributeArguments: AnyArgument[]) => Callback | Guard;\n} = {\n WHILE: (condition: string, attributeArguments: AnyArgument[]) => new While(condition, attributeArguments),\n UNTIL: (condition: string, attributeArguments: AnyArgument[]) => new Until(condition, attributeArguments),\n ENTRY: (functionName: string, attributeArguments: AnyArgument[]) => new Entry(functionName, attributeArguments),\n EXIT: (functionName: string, attributeArguments: AnyArgument[]) => new Exit(functionName, attributeArguments),\n STEP: (functionName: string, attributeArguments: AnyArgument[]) => new Step(functionName, attributeArguments)\n};\n\ntype Validatable = {\n children?: AstNode[];\n validate: (depth: number) => void;\n};\n\ntype NodeInstanceCreator = (\n namedRootNodeProvider: (name: string) => RootAstNode,\n visitedBranches: string[]\n) => T;\n\nexport type AstNode = Validatable & {\n type: string;\n createNodeInstance: NodeInstanceCreator;\n};\n\nexport type LeafAstNode = AstNode & {\n type: \"action\" | \"condition\" | \"wait\";\n attributes: Attribute[];\n};\n\nexport type CompositeAstNode = AstNode & {\n type: \"lotto\" | \"parallel\" | \"selector\" | \"sequence\";\n attributes: Attribute[];\n children: AstNode[];\n};\n\nexport type DecoratorAstNode = AstNode & {\n type: \"fail\" | \"flip\" | \"repeat\" | \"retry\" | \"root\" | \"succeed\";\n attributes: Attribute[];\n children: AstNode[];\n};\n\nexport type BranchAstNode = AstNode & {\n type: \"branch\";\n branchName: \"\" | string;\n};\n\nexport type LottoAstNode = CompositeAstNode & {\n type: \"lotto\";\n tickets: number[];\n};\n\nexport type RootAstNode = DecoratorAstNode & {\n type: \"root\";\n name: null | string;\n};\n\nexport type IterableAstNode = DecoratorAstNode & {\n type: \"repeat\" | \"retry\";\n iterations: null | number;\n maximumIterations: null | number;\n};\n\nexport type ActionAstNode = LeafAstNode & {\n type: \"action\";\n actionName: string;\n actionArguments: AnyArgument[];\n};\n\nexport type ConditionAstNode = LeafAstNode & {\n type: \"condition\";\n conditionName: string;\n conditionArguments: AnyArgument[];\n};\n\nexport type WaitAstNode = LeafAstNode & {\n type: \"wait\";\n duration: number | null;\n longestDuration: number | null;\n};\n\nexport type AnyAstNode =\n | BranchAstNode\n | CompositeAstNode\n | LottoAstNode\n | DecoratorAstNode\n | RootAstNode\n | IterableAstNode\n | LeafAstNode\n | ActionAstNode\n | ConditionAstNode\n | WaitAstNode;\n\n/**\n * The AST node factories.\n */\nconst ASTNodeFactories = {\n ROOT: (): RootAstNode => ({\n type: \"root\",\n attributes: [],\n name: null,\n children: [],\n validate(depth: number) {\n // A root node cannot be the child of another node.\n if (depth > 1) {\n throw new Error(\"a root node cannot be the child of another node\");\n }\n\n // A root node must have a single child node.\n if (this.children.length !== 1) {\n throw new Error(\"a root node must have a single child\");\n }\n },\n createNodeInstance(namedRootNodeProvider, visitedBranches) {\n return new Root(\n this.attributes,\n this.children![0].createNodeInstance(namedRootNodeProvider, visitedBranches.slice())\n );\n }\n }),\n BRANCH: (): BranchAstNode => ({\n type: \"branch\",\n branchName: \"\",\n validate() {},\n createNodeInstance(namedRootNodeProvider, visitedBranches) {\n // Try to find the root node with a matching branch name.\n const targetRootNode = namedRootNodeProvider(this.branchName);\n\n // If we have already visited this branch then we have a circular dependency.\n if (visitedBranches.indexOf(this.branchName) !== -1) {\n throw new Error(`circular dependency found in branch node references for branch '${this.branchName}'`);\n }\n\n // If we have a target root node, then the node instance we want will be the first and only child of the referenced root node.\n if (targetRootNode) {\n return targetRootNode\n .createNodeInstance(namedRootNodeProvider, visitedBranches.concat(this.branchName))\n .getChildren()[0];\n } else {\n throw new Error(`branch references root node '${this.branchName}' which has not been defined`);\n }\n }\n }),\n SELECTOR: (): CompositeAstNode => ({\n type: \"selector\",\n attributes: [],\n children: [],\n validate() {\n // A selector node must have at least a single node.\n if (this.children.length < 1) {\n throw new Error(\"a selector node must have at least a single child\");\n }\n },\n createNodeInstance(namedRootNodeProvider, visitedBranches) {\n return new Selector(\n this.attributes,\n this.children.map((child) => child.createNodeInstance(namedRootNodeProvider, visitedBranches.slice()))\n );\n }\n }),\n SEQUENCE: (): CompositeAstNode => ({\n type: \"sequence\",\n attributes: [],\n children: [],\n validate() {\n // A sequence node must have at least a single node.\n if (this.children.length < 1) {\n throw new Error(\"a sequence node must have at least a single child\");\n }\n },\n createNodeInstance(namedRootNodeProvider, visitedBranches) {\n return new Sequence(\n this.attributes,\n this.children.map((child) => child.createNodeInstance(namedRootNodeProvider, visitedBranches.slice()))\n );\n }\n }),\n PARALLEL: (): CompositeAstNode => ({\n type: \"parallel\",\n attributes: [],\n children: [],\n validate() {\n // A parallel node must have at least a single node.\n if (this.children.length < 1) {\n throw new Error(\"a parallel node must have at least a single child\");\n }\n },\n createNodeInstance(namedRootNodeProvider, visitedBranches) {\n return new Parallel(\n this.attributes,\n this.children.map((child) => child.createNodeInstance(namedRootNodeProvider, visitedBranches.slice()))\n );\n }\n }),\n LOTTO: (): LottoAstNode => ({\n type: \"lotto\",\n attributes: [],\n children: [],\n tickets: [],\n validate() {\n // A lotto node must have at least a single node.\n if (this.children!.length < 1) {\n throw new Error(\"a lotto node must have at least a single child\");\n }\n },\n createNodeInstance(namedRootNodeProvider, visitedBranches) {\n return new Lotto(\n this.attributes,\n this.tickets!,\n this.children!.map((child) => child.createNodeInstance(namedRootNodeProvider, visitedBranches.slice()))\n );\n }\n }),\n REPEAT: (): IterableAstNode => ({\n type: \"repeat\",\n attributes: [],\n iterations: null,\n maximumIterations: null,\n children: [],\n validate() {\n // A repeat node must have a single node.\n if (this.children!.length !== 1) {\n throw new Error(\"a repeat node must have a single child\");\n }\n\n // A repeat node must have a positive number of iterations if defined.\n if (this.iterations !== null && this.iterations! < 0) {\n throw new Error(\"a repeat node must have a positive number of iterations if defined\");\n }\n\n // There is validation to carry out if a longest duration was defined.\n if (this.maximumIterations !== null) {\n // A repeat node must have a positive maximum iterations count if defined.\n if (this.maximumIterations! < 0) {\n throw new Error(\"a repeat node must have a positive maximum iterations count if defined\");\n }\n\n // A repeat node must not have an iteration count that exceeds the maximum iteration count.\n if (this.iterations! > this.maximumIterations!) {\n throw new Error(\n \"a repeat node must not have an iteration count that exceeds the maximum iteration count\"\n );\n }\n }\n },\n createNodeInstance(namedRootNodeProvider, visitedBranches) {\n return new Repeat(\n this.attributes,\n this.iterations!,\n this.maximumIterations!,\n this.children![0].createNodeInstance(namedRootNodeProvider, visitedBranches.slice())\n );\n }\n }),\n RETRY: (): IterableAstNode => ({\n type: \"retry\",\n attributes: [],\n iterations: null,\n maximumIterations: null,\n children: [],\n validate() {\n // A retry node must have a single node.\n if (this.children!.length !== 1) {\n throw new Error(\"a retry node must have a single child\");\n }\n\n // A retry node must have a positive number of iterations if defined.\n if (this.iterations !== null && this.iterations! < 0) {\n throw new Error(\"a retry node must have a positive number of iterations if defined\");\n }\n\n // There is validation to carry out if a longest duration was defined.\n if (this.maximumIterations !== null) {\n // A retry node must have a positive maximum iterations count if defined.\n if (this.maximumIterations! < 0) {\n throw new Error(\"a retry node must have a positive maximum iterations count if defined\");\n }\n\n // A retry node must not have an iteration count that exceeds the maximum iteration count.\n if (this.iterations! > this.maximumIterations!) {\n throw new Error(\n \"a retry node must not have an iteration count that exceeds the maximum iteration count\"\n );\n }\n }\n },\n createNodeInstance(namedRootNodeProvider, visitedBranches) {\n return new Retry(\n this.attributes,\n this.iterations!,\n this.maximumIterations!,\n this.children![0].createNodeInstance(namedRootNodeProvider, visitedBranches.slice())\n );\n }\n }),\n FLIP: (): DecoratorAstNode => ({\n type: \"flip\",\n attributes: [],\n children: [],\n validate() {\n // A flip node must have a single node.\n if (this.children!.length !== 1) {\n throw new Error(\"a flip node must have a single child\");\n }\n },\n createNodeInstance(namedRootNodeProvider, visitedBranches) {\n return new Flip(\n this.attributes,\n this.children![0].createNodeInstance(namedRootNodeProvider, visitedBranches.slice())\n );\n }\n }),\n SUCCEED: (): DecoratorAstNode => ({\n type: \"succeed\",\n attributes: [],\n children: [],\n validate() {\n // A succeed node must have a single node.\n if (this.children!.length !== 1) {\n throw new Error(\"a succeed node must have a single child\");\n }\n },\n createNodeInstance(namedRootNodeProvider, visitedBranches) {\n return new Succeed(\n this.attributes,\n this.children![0].createNodeInstance(namedRootNodeProvider, visitedBranches.slice())\n );\n }\n }),\n FAIL: (): DecoratorAstNode => ({\n type: \"fail\",\n attributes: [],\n children: [],\n validate() {\n // A fail node must have a single node.\n if (this.children!.length !== 1) {\n throw new Error(\"a fail node must have a single child\");\n }\n },\n createNodeInstance(namedRootNodeProvider, visitedBranches) {\n return new Fail(\n this.attributes,\n this.children![0].createNodeInstance(namedRootNodeProvider, visitedBranches.slice())\n );\n }\n }),\n WAIT: (): WaitAstNode => ({\n type: \"wait\",\n attributes: [],\n duration: null,\n longestDuration: null,\n validate() {\n // A wait node must have a positive duration.\n if (this.duration! < 0) {\n throw new Error(\"a wait node must have a positive duration\");\n }\n\n // There is validation to carry out if a longest duration was defined.\n if (this.longestDuration) {\n // A wait node must have a positive longest duration.\n if (this.longestDuration < 0) {\n throw new Error(\"a wait node must have a positive longest duration if one is defined\");\n }\n\n // A wait node must not have a duration that exceeds the longest duration.\n if (this.duration! > this.longestDuration) {\n throw new Error(\"a wait node must not have a shortest duration that exceeds the longest duration\");\n }\n }\n },\n createNodeInstance() {\n return new Wait(this.attributes, this.duration!, this.longestDuration!);\n }\n }),\n ACTION: (): ActionAstNode => ({\n type: \"action\",\n attributes: [],\n actionName: \"\",\n actionArguments: [],\n validate() {},\n createNodeInstance() {\n return new Action(this.attributes, this.actionName!, this.actionArguments!);\n }\n }),\n CONDITION: (): ConditionAstNode => ({\n type: \"condition\",\n attributes: [],\n conditionName: \"\",\n conditionArguments: [],\n validate() {},\n createNodeInstance() {\n return new Condition(this.attributes, this.conditionName!, this.conditionArguments!);\n }\n })\n};\n\ntype OtherAstNodes = AstNode[];\n\n/**\n * Create an array of root AST nodes based on the given definition.\n * @param definition The definition to parse the AST nodes from.\n * @returns The base definition AST nodes.\n */\nexport default function buildRootASTNodes(definition: string): RootAstNode[] {\n // Swap out any node/attribute argument string literals with a placeholder and get a mapping of placeholders to original values as well as the processed definition.\n const { placeholders, processedDefinition } = substituteStringLiterals(definition);\n\n // Convert the processed definition (with substituted string literals) into an array of raw tokens.\n const tokens = parseTokensFromDefinition(processedDefinition);\n\n // There must be at least 3 tokens for the tree definition to be valid. 'ROOT', '{' and '}'.\n if (tokens.length < 3) {\n throw new Error(\"invalid token count\");\n }\n\n // We should have a matching number of '{' and '}' tokens. If not, then there are scopes that have not been properly closed.\n if (tokens.filter((token) => token === \"{\").length !== tokens.filter((token) => token === \"}\").length) {\n throw new Error(\"scope character mismatch\");\n }\n\n // Create a stack of node children arrays, starting with a definition scope.\n const stack: [RootAstNode[], ...OtherAstNodes[]] = [[]];\n const rootScope = stack[0];\n\n // We should keep processing the raw tokens until we run out of them.\n while (tokens.length) {\n // Grab the next token.\n const token = tokens.shift();\n\n const currentScope = stack[stack.length - 1] as OtherAstNodes;\n\n // How we create the next AST token depends on the current raw token value.\n switch (token!.toUpperCase()) {\n case \"ROOT\": {\n // Create a ROOT AST node.\n const node = ASTNodeFactories.ROOT();\n\n // Push the ROOT node into the current scope.\n rootScope.push(node);\n\n // We may have a root node name defined as an argument.\n if (tokens[0] === \"[\") {\n const rootArguments = getArguments(tokens, placeholders);\n\n // We should have only a single argument that is not an empty string for a root node, which is the root name identifier.\n if (rootArguments.length === 1 && rootArguments[0].type === \"identifier\") {\n // The root name will be the first and only node argument.\n node.name = rootArguments[0].value as string;\n } else {\n throw new Error(\"expected single root name argument\");\n }\n }\n\n // Try to pick any attributes off of the token stack.\n node.attributes = getAttributes(tokens, placeholders);\n\n popAndCheck(tokens, \"{\");\n\n // The new scope is that of the new ROOT nodes children.\n stack.push(node.children!);\n break;\n }\n\n case \"BRANCH\": {\n // Create a BRANCH AST node.\n const node = ASTNodeFactories.BRANCH();\n\n // Push the BRANCH node into the current scope.\n currentScope.push(node);\n\n // We must have arguments defined, as we require a branch name argument.\n if (tokens[0] !== \"[\") {\n throw new Error(\"expected single branch name argument\");\n }\n\n // The branch name will be defined as a node argument.\n const branchArguments = getArguments(tokens, placeholders);\n\n // We should have only a single identifer argument for a branch node, which is the branch name.\n if (branchArguments.length === 1 && branchArguments[0].type === \"identifier\") {\n // The branch name will be the first and only node argument.\n node.branchName = branchArguments[0].value as string;\n } else {\n throw new Error(\"expected single branch name argument\");\n }\n break;\n }\n\n case \"SELECTOR\": {\n // Create a SELECTOR AST node.\n const node = ASTNodeFactories.SELECTOR();\n\n // Push the SELECTOR node into the current scope.\n currentScope.push(node);\n\n // Try to pick any attributes off of the token stack.\n node.attributes = getAttributes(tokens, placeholders);\n\n popAndCheck(tokens, \"{\");\n\n // The new scope is that of the new SELECTOR nodes children.\n stack.push(node.children!);\n break;\n }\n\n case \"SEQUENCE\": {\n // Create a SEQUENCE AST node.\n const node = ASTNodeFactories.SEQUENCE();\n\n // Push the SEQUENCE node into the current scope.\n currentScope.push(node);\n\n // Try to pick any attributes off of the token stack.\n node.attributes = getAttributes(tokens, placeholders);\n\n popAndCheck(tokens, \"{\");\n\n // The new scope is that of the new SEQUENCE nodes children.\n stack.push(node.children!);\n break;\n }\n\n case \"PARALLEL\": {\n // Create a PARALLEL AST node.\n const node = ASTNodeFactories.PARALLEL();\n\n // Push the PARALLEL node into the current scope.\n currentScope.push(node);\n\n // Try to pick any attributes off of the token stack.\n node.attributes = getAttributes(tokens, placeholders);\n\n popAndCheck(tokens, \"{\");\n\n // The new scope is that of the new PARALLEL nodes children.\n stack.push(node.children!);\n break;\n }\n\n case \"LOTTO\": {\n // Create a LOTTO AST node.\n const node = ASTNodeFactories.LOTTO();\n\n // Push the LOTTO node into the current scope.\n currentScope.push(node);\n\n // If the next token is a '[' character then some ticket counts have been defined as arguments.\n if (tokens[0] === \"[\") {\n // Get the ticket count arguments, each argument must be a number.\n node.tickets = getArguments(\n tokens,\n placeholders,\n (arg) => arg.type === \"number\" && !!arg.isInteger,\n \"lotto node ticket counts must be integer values\"\n ).map((argument) => argument.value as number);\n }\n\n // Try to pick any attributes off of the token stack.\n node.attributes = getAttributes(tokens, placeholders);\n\n popAndCheck(tokens, \"{\");\n\n // The new scope is that of the new LOTTO nodes children.\n stack.push(node.children!);\n break;\n }\n\n case \"CONDITION\": {\n // Create a CONDITION AST node.\n const node = ASTNodeFactories.CONDITION();\n\n // Push the CONDITION node into the current scope.\n currentScope.push(node);\n\n // We must have arguments defined, as we require a condition function name argument.\n if (tokens[0] !== \"[\") {\n throw new Error(\"expected condition name identifier argument\");\n }\n\n // Grab the condition node arguments.\n const conditionArguments = getArguments(tokens, placeholders);\n\n // We should have at least a single identifier argument for a condition node, which is the condition function name.\n if (conditionArguments.length && conditionArguments[0].type === \"identifier\") {\n // The condition function name will be the first node argument.\n node.conditionName = conditionArguments.shift()!.value as string;\n } else {\n throw new Error(\"expected condition name identifier argument\");\n }\n\n // Only the first argument should have been an identifier, all following arguments must be string, number, boolean or null.\n conditionArguments\n .filter((arg) => arg.type === \"identifier\")\n .forEach((arg) => {\n throw new Error(\n \"invalid condition node argument value '\" +\n arg.value +\n \"', must be string, number, boolean or null\"\n );\n });\n\n // Any node arguments that follow the condition name identifier will be treated as condition function arguments.\n node.conditionArguments = conditionArguments;\n\n // Try to pick any attributes off of the token stack.\n node.attributes = getAttributes(tokens, placeholders);\n break;\n }\n\n case \"FLIP\": {\n // Create a FLIP AST node.\n const node = ASTNodeFactories.FLIP();\n\n // Push the Flip node into the current scope.\n currentScope.push(node);\n\n // Try to pick any attributes off of the token stack.\n node.attributes = getAttributes(tokens, placeholders);\n\n popAndCheck(tokens, \"{\");\n\n // The new scope is that of the new FLIP nodes children.\n stack.push(node.children!);\n break;\n }\n\n case \"SUCCEED\": {\n // Create a SUCCEED AST node.\n const node = ASTNodeFactories.SUCCEED();\n\n // Push the Succeed node into the current scope.\n currentScope.push(node);\n\n // Try to pick any attributes off of the token stack.\n node.attributes = getAttributes(tokens, placeholders);\n\n popAndCheck(tokens, \"{\");\n\n // The new scope is that of the new Succeed nodes children.\n stack.push(node.children!);\n break;\n }\n\n case \"FAIL\": {\n // Create a FAIL AST node.\n const node = ASTNodeFactories.FAIL();\n\n // Push the Fail node into the current scope.\n currentScope.push(node);\n\n // Try to pick any attributes off of the token stack.\n node.attributes = getAttributes(tokens, placeholders);\n\n popAndCheck(tokens, \"{\");\n\n // The new scope is that of the new Fail nodes children.\n stack.push(node.children!);\n break;\n }\n\n case \"WAIT\": {\n // Create a WAIT AST node.\n const node = ASTNodeFactories.WAIT();\n\n // Push the WAIT node into the current scope.\n currentScope.push(node);\n\n // Get the duration and potential longest duration of the wait.\n const durations = getArguments(\n tokens,\n placeholders,\n (arg) => arg.type === \"number\" && !!arg.isInteger,\n \"wait node durations must be integer values\"\n ).map((argument) => argument.value);\n\n // We should have got one or two durations.\n if (durations.length === 1) {\n // A static duration was defined.\n node.duration = durations[0] as number;\n } else if (durations.length === 2) {\n // A shortest and longest duration was defined.\n node.duration = durations[0] as number;\n node.longestDuration = durations[1] as number;\n } else {\n // An incorrect number of durations was defined.\n throw new Error(\"invalid number of wait node duration arguments defined\");\n }\n\n // Try to pick any attributes off of the token stack.\n node.attributes = getAttributes(tokens, placeholders);\n break;\n }\n\n case \"REPEAT\": {\n // Create a REPEAT AST node.\n const node = ASTNodeFactories.REPEAT();\n\n // Push the REPEAT node into the current scope.\n currentScope.push(node);\n\n // Check for iteration counts ([])\n if (tokens[0] === \"[\") {\n // An iteration count has been defined. Get the iteration and potential maximum iteration of the wait.\n const iterationArguments = getArguments(\n tokens,\n placeholders,\n (arg) => arg.type === \"number\" && !!arg.isInteger,\n \"repeat node iteration counts must be integer values\"\n ).map((argument) => argument.value);\n\n // We should have got one or two iteration counts.\n if (iterationArguments.length === 1) {\n // A static iteration count was defined.\n node.iterations = iterationArguments[0] as number;\n } else if (iterationArguments.length === 2) {\n // A minimum and maximum iteration count was defined.\n node.iterations = iterationArguments[0] as number;\n node.maximumIterations = iterationArguments[1] as number;\n } else {\n // An incorrect number of iteration counts was defined.\n throw new Error(\"invalid number of repeat node iteration count arguments defined\");\n }\n }\n\n // Try to pick any attributes off of the token stack.\n node.attributes = getAttributes(tokens, placeholders);\n\n popAndCheck(tokens, \"{\");\n\n // The new scope is that of the new REPEAT nodes children.\n stack.push(node.children!);\n break;\n }\n\n case \"RETRY\": {\n // Create a RETRY AST node.\n const node = ASTNodeFactories.RETRY();\n\n // Push the RETRY node into the current scope.\n currentScope.push(node);\n\n // Check for iteration counts ([])\n if (tokens[0] === \"[\") {\n // An iteration count has been defined. Get the iteration and potential maximum iteration of the wait.\n const iterationArguments = getArguments(\n tokens,\n placeholders,\n (arg) => arg.type === \"number\" && !!arg.isInteger,\n \"retry node iteration counts must be integer values\"\n ).map((argument) => argument.value);\n\n // We should have got one or two iteration counts.\n if (iterationArguments.length === 1) {\n // A static iteration count was defined.\n node.iterations = iterationArguments[0] as number;\n } else if (iterationArguments.length === 2) {\n // A minimum and maximum iteration count was defined.\n node.iterations = iterationArguments[0] as number;\n node.maximumIterations = iterationArguments[1] as number;\n } else {\n // An incorrect number of iteration counts was defined.\n throw new Error(\"invalid number of retry node iteration count arguments defined\");\n }\n }\n\n // Try to pick any attributes off of the token stack.\n node.attributes = getAttributes(tokens, placeholders);\n\n popAndCheck(tokens, \"{\");\n\n // The new scope is that of the new RETRY nodes children.\n stack.push(node.children!);\n break;\n }\n\n case \"ACTION\": {\n // Create a ACTION AST node.\n const node = ASTNodeFactories.ACTION();\n\n // Push the ACTION node into the current scope.\n currentScope.push(node);\n\n // We must have arguments defined, as we require an action name argument.\n if (tokens[0] !== \"[\") {\n throw new Error(\"expected action name identifier argument\");\n }\n\n // The action name will be defined as a node argument.\n const actionArguments = getArguments(tokens, placeholders);\n\n // We should have at least one identifer argument for an action node, which is the action name.\n if (actionArguments.length && actionArguments[0].type === \"identifier\") {\n // The action name will be the first and only node argument.\n node.actionName = actionArguments.shift()!.value as string;\n } else {\n throw new Error(\"expected action name identifier argument\");\n }\n\n // Only the first argument should have been an identifier, all following arguments must be string, number, boolean or null.\n actionArguments\n .filter((arg) => arg.type === \"identifier\")\n .forEach((arg) => {\n throw new Error(\n \"invalid action node argument value '\" +\n arg.value +\n \"', must be string, number, boolean or null\"\n );\n });\n\n // Any node arguments that follow the action name identifier will be treated as action function arguments.\n node.actionArguments = actionArguments;\n\n // Try to pick any attributes off of the token stack.\n node.attributes = getAttributes(tokens, placeholders);\n break;\n }\n\n case \"}\": {\n // The '}' character closes the current scope.\n stack.pop();\n break;\n }\n\n default: {\n throw new Error(\"unexpected token: \" + token);\n }\n }\n }\n\n // A function to recursively validate each of the nodes in the AST.\n const validateASTNode = (node: Validatable, depth: number): void => {\n // Validate the node.\n node.validate(depth);\n\n // Validate each child of the node.\n (node.children || []).forEach((child) => validateASTNode(child, depth + 1));\n };\n\n // Start node validation from the definition root.\n validateASTNode(\n {\n children: stack[0] as RootAstNode[],\n validate(this: { children: RootAstNode[] }) {\n // We must have at least one node defined as the definition scope, which should be a root node.\n if (this.children.length === 0) {\n throw new Error(\"expected root node to have been defined\");\n }\n\n // Each node at the base of the definition scope MUST be a root node.\n for (const definitionLevelNode of this.children) {\n if (definitionLevelNode.type !== \"root\") {\n throw new Error(\"expected root node at base of definition\");\n }\n }\n\n // Exactly one root node must not have a name defined. This will be the main root, others will have to be referenced via branch nodes.\n if (this.children.filter((definitionLevelNode) => definitionLevelNode.name === null).length !== 1) {\n throw new Error(\"expected single unnamed root node at base of definition to act as main root\");\n }\n\n // No two named root nodes can have matching names.\n const rootNodeNames: string[] = [];\n for (const definitionLevelNode of this.children) {\n if (rootNodeNames.indexOf(definitionLevelNode.name!) !== -1) {\n throw new Error(`multiple root nodes found with duplicate name '${definitionLevelNode.name}'`);\n } else {\n rootNodeNames.push(definitionLevelNode.name!);\n }\n }\n }\n },\n 0\n );\n\n // Return the root AST nodes.\n return stack[0];\n}\n\n/**\n * Pop the next raw token off of the stack and throw an error if it wasn't the expected one.\n * @param tokens The array of remaining tokens.\n * @param expected An optional string or array or items, one of which must match the next popped token.\n * @returns The popped token.\n */\nfunction popAndCheck(tokens: string[], expected: string | string[]) {\n // Get and remove the next token.\n const popped = tokens.shift();\n\n // We were expecting another token.\n if (popped === undefined) {\n throw new Error(\"unexpected end of definition\");\n }\n\n // Do we have an expected token/tokens array?\n if (expected !== undefined) {\n // Check whether the popped token matches at least one of our expected items.\n var tokenMatchesExpectation = ([] as string[])\n .concat(expected)\n .some((item) => popped.toUpperCase() === item.toUpperCase());\n\n // Throw an error if the popped token didn't match any of our expected items.\n if (!tokenMatchesExpectation) {\n const expectationString = ([] as string[])\n .concat(expected)\n .map((item) => \"'\" + item + \"'\")\n .join(\" or \");\n throw new Error(\"unexpected token found. Expected \" + expectationString + \" but got '\" + popped + \"'\");\n }\n }\n\n // Return the popped token.\n return popped;\n}\n\ntype Placeholders = { [key: string]: string };\n\n/**\n * Pull an argument definition list off of the token stack.\n * @param tokens The array of remaining tokens.\n * @param stringArgumentPlaceholders The mapping of string literal node argument placeholders to original values.\n * @param argumentValidator The argument validator function.\n * @param validationFailedMessage The exception message to throw if argument validation fails.\n * @returns The argument definition list.\n */\nfunction getArguments(\n tokens: string[],\n stringArgumentPlaceholders: Placeholders,\n argumentValidator?: (arg: AnyArgument) => boolean,\n validationFailedMessage?: string\n) {\n // Any lists of arguments will always be wrapped in '[]' for node arguments or '()' for attribute arguments.\n // We are looking for a '[' or '(' opener that wraps the argument tokens and the relevant closer.\n const closer = popAndCheck(tokens, [\"[\", \"(\"]) === \"[\" ? \"]\" : \")\";\n\n const argumentListTokens: string[] = [];\n const argumentList: AnyArgument[] = [];\n\n // Grab all tokens between the '[' and ']' or '(' and ')'.\n while (tokens.length && tokens[0] !== closer) {\n // The next token is part of our arguments list.\n argumentListTokens.push(tokens.shift()!);\n }\n\n // Validate the order of the argument tokens. Each token must either be a ',' or a single argument that satisfies the validator.\n argumentListTokens.forEach((token, index) => {\n // Get whether this token should be an actual argument.\n const shouldBeArgumentToken = !(index & 1);\n\n // If the current token should be an actual argument then validate it,otherwise it should be a ',' token.\n if (shouldBeArgumentToken) {\n // Get the argument definition.\n const argumentDefinition = getArgumentDefinition(token!, stringArgumentPlaceholders);\n\n // Try to validate the argument.\n if (argumentValidator && !argumentValidator(argumentDefinition)) {\n throw new Error(validationFailedMessage);\n }\n\n // This is a valid argument!\n argumentList.push(argumentDefinition);\n } else {\n // The current token should be a ',' token.\n if (token !== \",\") {\n throw new Error(`invalid argument list, expected ',' or ']' but got '${token}'`);\n }\n }\n });\n\n // The arguments list should terminate with a ']' or ')' token, depending on the opener.\n popAndCheck(tokens, closer);\n\n // Return the argument list.\n return argumentList;\n}\n\n/**\n * Gets an argument value definition.\n * @param token The argument token.\n * @param stringArgumentPlaceholders The mapping of string literal node argument placeholders to original values.\n * @returns An argument value definition.\n */\nfunction getArgumentDefinition(token: string, stringArgumentPlaceholders: Placeholders): AnyArgument {\n // Check whether the token represents a null value.\n if (token === \"null\") {\n return {\n value: null,\n type: \"null\"\n } as NullArgument;\n }\n\n // Check whether the token represents a boolean value.\n if (token === \"true\" || token === \"false\") {\n return {\n value: token === \"true\",\n type: \"boolean\"\n } as BooleanArgument;\n }\n\n // Check whether the token represents a number value.\n // TODO: Relies on broken isNaN - see MDN.\n // if (!Number.isNaN(token)) {\n if (!isNaN(token as any)) {\n return {\n value: parseFloat(token),\n isInteger: parseFloat(token) === parseInt(token, 10),\n type: \"number\"\n } as NumberArgument;\n }\n\n // Check whether the token is a placeholder (e.g. @@0@@) representing a string literal.\n if (token.match(/^@@\\d+@@$/g)) {\n return {\n value: stringArgumentPlaceholders[token].replace('\\\\\"', '\"'),\n type: \"string\"\n } as StringPlaceholderArgument;\n }\n\n // The only remaining option is that the argument value is an identifier.\n return {\n value: token,\n type: \"identifier\"\n } as IdentifierArgument;\n}\n\n/**\n * Pull any attributes off of the token stack.\n * @param tokens The array of remaining tokens.\n * @param stringArgumentPlaceholders The mapping of string literal node argument placeholders to original values.\n * @returns An array of attributes defined by any directly following tokens.\n */\nfunction getAttributes(tokens: string[], stringArgumentPlaceholders: Placeholders) {\n // Create an array to hold any attributes found.\n const attributes: Attribute[] = [];\n\n // Keep track of names of attribute that we have found on the token stack, as we cannot have duplicates.\n const attributesFound: string[] = [];\n\n // Try to get the attribute factory for the next token.\n let attributeFactory = AttributeFactories[(tokens[0] || \"\").toUpperCase()];\n\n // Pull attribute tokens off of the tokens stack until we have no more.\n while (attributeFactory) {\n // Check to make sure that we have not already created a attribute of this type for this node.\n if (attributesFound.indexOf(tokens[0].toUpperCase()) !== -1) {\n throw new Error(`duplicate attribute '${tokens[0].toUpperCase()}' found for node`);\n }\n\n // Add the current attribute type to our array of found attributes.\n attributesFound.push(tokens.shift()!.toUpperCase());\n\n // Grab any attribute arguments.\n const attributeArguments = getArguments(tokens, stringArgumentPlaceholders);\n\n // The first attribute argument has to be an identifer, this will reference an agent function.\n if (attributeArguments.length === 0 || attributeArguments[0].type !== \"identifier\") {\n throw new Error(\"expected agent function name identifier argument for attribute\");\n }\n\n // Grab the first attribute which is an identifier that will reference an agent function.\n const attributeFunctionName = attributeArguments.shift()! as IdentifierArgument;\n\n // Any remaining attribute arguments must have a type of string, number, boolean or null.\n attributeArguments\n .filter((arg) => arg.type === \"identifier\")\n .forEach((arg) => {\n throw new Error(\n \"invalid attribute argument value '\" + arg.value + \"', must be string, number, boolean or null\"\n );\n });\n\n // Create the attribute and add it to the array of attributes found.\n attributes.push(attributeFactory(attributeFunctionName.value, attributeArguments));\n\n // Try to get the next attribute name token, as there could be multiple.\n attributeFactory = AttributeFactories[(tokens[0] || \"\").toUpperCase()];\n }\n\n return attributes;\n}\n\n/**\n * Swaps out any node/attribute argument string literals with placeholders.\n * @param definition The definition.\n * @returns An object containing a mapping of placeholders to original string values as well as the processed definition string.\n */\nfunction substituteStringLiterals(definition: string): {\n placeholders: { [key: string]: string };\n processedDefinition: string;\n} {\n // Create an object to hold the mapping of placeholders to original string values.\n const placeholders: Placeholders = {};\n\n // Replace any string literals wrapped with double quotes in our definition with placeholders to be processed later.\n const processedDefinition = definition.replace(/\\\"(\\\\.|[^\"\\\\])*\\\"/g, (match) => {\n var strippedMatch = match.substring(1, match.length - 1);\n var placeholder = Object.keys(placeholders).find((key) => placeholders[key] === strippedMatch);\n\n // If we have no existing string literal match then create a new placeholder.\n if (!placeholder) {\n placeholder = `@@${Object.keys(placeholders).length}@@`;\n placeholders[placeholder] = strippedMatch;\n }\n\n return placeholder;\n });\n\n return { placeholders, processedDefinition };\n}\n\n/**\n * Parse the tree definition into an array of raw tokens.\n * @param definition The definition.\n * @returns An array of tokens parsed from the definition.\n */\nfunction parseTokensFromDefinition(definition: string): string[] {\n // Add some space around various important characters so that they can be plucked out easier as individual tokens.\n definition = definition.replace(/\\(/g, \" ( \");\n definition = definition.replace(/\\)/g, \" ) \");\n definition = definition.replace(/\\{/g, \" { \");\n definition = definition.replace(/\\}/g, \" } \");\n definition = definition.replace(/\\]/g, \" ] \");\n definition = definition.replace(/\\[/g, \" [ \");\n definition = definition.replace(/\\,/g, \" , \");\n\n // Split the definition into raw token form and return it.\n return definition.replace(/\\s+/g, \" \").trim().split(\" \");\n}\n", "import GuardPath, { GuardPathPart } from \"./attributes/guards/GuardPath\";\nimport buildRootASTNodes, { AnyArgument, RootAstNode } from \"./RootAstNodesBuilder\";\nimport State, { AnyState } from \"./State\";\nimport Lookup from \"./Lookup\";\nimport Node from \"./nodes/Node\";\nimport Root from \"./nodes/decorator/Root\";\nimport Composite from \"./nodes/composite/Composite\";\nimport Decorator from \"./nodes/decorator/Decorator\";\nimport { Agent, GlobalFunction } from \"./Agent\";\nimport { CallbackAttributeDetails } from \"./attributes/callbacks/Callback\";\nimport { GuardAttributeDetails } from \"./attributes/guards/Guard\";\nimport { BehaviourTreeOptions } from \"./BehaviourTreeOptions\";\n\n// Purely for outside inspection of the tree.\nexport type FlattenedTreeNode = {\n id: string;\n type: string;\n caption: string;\n state: AnyState;\n guards: GuardAttributeDetails[];\n callbacks: CallbackAttributeDetails[];\n args: AnyArgument[];\n parentId: string | null;\n};\n\n/**\n * A representation of a behaviour tree.\n */\nexport class BehaviourTree {\n /**\n * The main root tree node.\n */\n public readonly rootNode: Root;\n\n /**\n * Creates a new instance of the BehaviourTree class.\n * @param definition The behaviour tree definition.\n * @param agent The agent instance that this behaviour tree is modelling behaviour for.\n * @param options The behaviour tree options object.\n */\n constructor(definition: string, private agent: Agent, private options: BehaviourTreeOptions = {}) {\n // The tree definition must be defined and a valid string.\n if (typeof definition !== \"string\") {\n throw new Error(\"the tree definition must be a string\");\n }\n\n // The agent must be defined and not null.\n if (typeof agent !== \"object\" || agent === null) {\n throw new Error(\"the agent must be defined and not null\");\n }\n\n // Parse the behaviour tree definition, create the populated tree of behaviour tree nodes, and get the root.\n this.rootNode = BehaviourTree.createRootNode(definition);\n }\n\n /**\n * Gets whether the tree is in the RUNNING state.\n * @returns true if the tree is in the RUNNING state, otherwise false.\n */\n isRunning() {\n return this.rootNode.getState() === State.RUNNING;\n }\n\n /**\n * Gets the current tree state of SUCCEEDED, FAILED, READY or RUNNING.\n * @returns The current tree state.\n */\n getState() {\n return this.rootNode.getState();\n }\n\n /**\n * Step the tree.\n * 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.\n * 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\n * 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.\n *\n * 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.\n */\n step() {\n // If the root node has already been stepped to completion then we need to reset it.\n if (this.rootNode.getState() === State.SUCCEEDED || this.rootNode.getState() === State.FAILED) {\n this.rootNode.reset();\n }\n\n try {\n this.rootNode.update(this.agent, this.options);\n } catch (exception) {\n throw new Error(`error stepping tree: ${(exception as Error).message}`);\n }\n }\n\n /**\n * Resets the tree from the root node outwards to each nested node, giving each a state of READY.\n */\n reset() {\n this.rootNode.reset();\n }\n\n /**\n * Gets the flattened details of every node in the tree.\n * @returns The flattened details of every node in the tree.\n */\n getFlattenedNodeDetails(): FlattenedTreeNode[] {\n // Create an empty flattened array of tree nodes.\n const flattenedTreeNodes: FlattenedTreeNode[] = [];\n\n /**\n * Helper function to process a node instance and push details into the flattened tree nodes array.\n * @param node The current node.\n * @param parentUid The UID of the node parent, or null if the node is the main root node.\n */\n const processNode = (node: Node, parentUid: string | null) => {\n // Get the guard and callback attribute details for this node.\n const guards = node\n .getAttributes()\n .filter((attribute) => attribute.isGuard())\n .map((attribute) => attribute.getDetails()) as GuardAttributeDetails[];\n const callbacks = node\n .getAttributes()\n .filter((attribute) => !attribute.isGuard())\n .map((attribute) => attribute.getDetails()) as CallbackAttributeDetails[];\n\n // Push the current node into the flattened nodes array.\n flattenedTreeNodes.push({\n id: node.getUid(),\n type: node.getType(),\n caption: node.getName(),\n state: node.getState(),\n guards,\n callbacks,\n args: node.getArguments(),\n parentId: parentUid\n });\n\n // Process each of the nodes children if it is not a leaf node.\n if (!node.isLeafNode()) {\n (node as Composite | Decorator)\n .getChildren()\n .forEach((child) => processNode(child, (node as Composite | Decorator).getUid()));\n }\n };\n\n // Convert the nested node structure into a flattened array of node details.\n processNode(this.rootNode, null);\n\n return flattenedTreeNodes;\n }\n\n /**\n * Registers the action/condition/guard/callback function or subtree with the given name.\n * @param name The name of the function or subtree to register.\n * @param value The function or subtree definition to register.\n */\n static register(name: string, value: GlobalFunction | string) {\n if (typeof value === \"function\") {\n // We are going to register a action/condition/guard/callback function.\n Lookup.setFunc(name, value);\n } else if (typeof value === \"string\") {\n // We are going to register a subtree.\n let rootASTNodes: RootAstNode[];\n\n try {\n // Try to create the behaviour tree AST based on the definition provided, this could fail if the definition is invalid.\n rootASTNodes = buildRootASTNodes(value);\n } catch (exception) {\n // There was an issue in trying to parse and build the tree definition.\n throw new Error(`error registering definition: ${(exception as Error).message}`);\n }\n\n // This function should only ever be called with a definition containing a single unnamed root node.\n if (rootASTNodes.length != 1 || rootASTNodes[0].name !== null) {\n throw new Error(\"error registering definition: expected a single unnamed root node\");\n }\n\n Lookup.setSubtree(name, rootASTNodes[0]);\n } else {\n throw new Error(\"unexpected value, expected string definition or function\");\n }\n }\n\n /**\n * Unregisters the registered action/condition/guard/callback function or subtree with the given name.\n * @param name The name of the registered action/condition/guard/callback function or subtree to unregister.\n */\n static unregister(name: string): void {\n Lookup.remove(name);\n }\n\n /**\n * Unregister all registered action/condition/guard/callback functions and subtrees.\n */\n static unregisterAll(): void {\n Lookup.empty();\n }\n\n /**\n * Parses a behaviour tree definition and creates a tree of behaviour tree nodes.\n * @param {string} definition The behaviour tree definition.\n * @returns The root behaviour tree node.\n */\n private static createRootNode(definition: string): Root {\n try {\n // Try to create the behaviour tree AST based on the definition provided, this could fail if the definition is invalid.\n const rootASTNodes = buildRootASTNodes(definition);\n\n // Create a symbol to use as the main root key in our root node mapping.\n const mainRootNodeKey = Symbol(\"__root__\");\n\n // Create a mapping of root node names to root AST tokens. The main root node will have a key of Symbol(\"__root__\").\n const rootNodeMap: { [key: string | symbol]: RootAstNode } = {};\n for (const rootASTNode of rootASTNodes) {\n rootNodeMap[rootASTNode.name === null ? mainRootNodeKey : rootASTNode.name!] = rootASTNode;\n }\n\n // Convert the AST to our actual tree and get the root node.\n const rootNode: Root = rootNodeMap[mainRootNodeKey].createNodeInstance(\n // Create a provider for named root nodes that are part of our definition or have been registered. Prioritising the former.\n (name: string): RootAstNode => (rootNodeMap[name] ? rootNodeMap[name] : Lookup.getSubtree(name)),\n []\n );\n\n // Set a guard path on every leaf of the tree to evaluate as part of its update.\n BehaviourTree.applyLeafNodeGuardPaths(rootNode);\n\n // Return the root node.\n return rootNode;\n } catch (exception) {\n // There was an issue in trying to parse and build the tree definition.\n throw new Error(`error parsing tree: ${(exception as Error).message}\\n${(exception as Error).stack}`);\n }\n }\n\n /**\n * Applies a guard path to every leaf of the tree to evaluate as part of each update.\n * @param rootNode The main root tree node.\n */\n private static applyLeafNodeGuardPaths(rootNode: Root) {\n const nodePaths: Node[][] = [];\n\n const findLeafNodes = (path: Node[], node: Node) => {\n // Add the current node to the path.\n path = path.concat(node);\n\n // Check whether the current node is a leaf node.\n if (node.isLeafNode()) {\n nodePaths.push(path);\n } else {\n (node as Composite | Decorator).getChildren().forEach((child) => findLeafNodes(path, child));\n }\n };\n\n // Find all leaf node paths, starting from the root.\n findLeafNodes([], rootNode);\n\n nodePaths.forEach((path) => {\n // Each node in the current path will have to be assigned a guard path, working from the root outwards.\n for (let depth = 0; depth < path.length; depth++) {\n // Get the node in the path at the current depth.\n const currentNode = path[depth];\n\n // The node may already have been assigned a guard path, if so just skip it.\n if (currentNode.hasGuardPath()) {\n continue;\n }\n\n // Create the guard path for the current node.\n const guardPath = new GuardPath(\n path\n .slice(0, depth + 1)\n .map((node) => ({ node, guards: node.getGuardAttributes() }))\n .filter((details) => details.guards.length > 0)\n );\n\n // Assign the guard path to the current node.\n currentNode.setGuardPath(guardPath);\n }\n });\n }\n}\n"], - "mappings": "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", - "names": ["Participant", "Lotto", "createLotto", "State", "createLotto"] + "sources": ["../node_modules/lotto-draw/dist/Participant.js", "../node_modules/lotto-draw/dist/Utilities.js", "../node_modules/lotto-draw/dist/Lotto.js", "../node_modules/lotto-draw/dist/createLotto.js", "../node_modules/lotto-draw/dist/index.js", "../src/index.ts", "../src/attributes/guards/GuardUnsatisifedException.ts", "../src/attributes/guards/GuardPath.ts", "../src/State.ts", "../src/nodes/Node.ts", "../src/nodes/leaf/Leaf.ts", "../src/Lookup.ts", "../src/nodes/leaf/Action.ts", "../src/nodes/leaf/Condition.ts", "../src/nodes/leaf/Wait.ts", "../src/nodes/decorator/Decorator.ts", "../src/nodes/decorator/Root.ts", "../src/nodes/decorator/Repeat.ts", "../src/nodes/decorator/Retry.ts", "../src/nodes/decorator/Flip.ts", "../src/nodes/decorator/Succeed.ts", "../src/nodes/decorator/Fail.ts", "../src/nodes/composite/Lotto.ts", "../src/nodes/composite/Composite.ts", "../src/nodes/composite/Selector.ts", "../src/nodes/composite/Sequence.ts", "../src/nodes/composite/Parallel.ts", "../src/attributes/Attribute.ts", "../src/attributes/guards/Guard.ts", "../src/attributes/guards/While.ts", "../src/attributes/guards/Until.ts", "../src/attributes/callbacks/Callback.ts", "../src/attributes/callbacks/Entry.ts", "../src/attributes/callbacks/Exit.ts", "../src/attributes/callbacks/Step.ts", "../src/RootAstNodesBuilder.ts", "../src/DSLParser.ts", "../src/BehaviourTree.ts"], + "sourcesContent": ["\"use strict\";\r\nObject.defineProperty(exports, \"__esModule\", { value: true });\r\nexports.Participant = void 0;\r\n/**\r\n * A participant that holds a number of tickets.\r\n */\r\nvar Participant = /** @class */ (function () {\r\n /**\r\n * Creates an instance of the Participant class.\r\n * @param participant The actual participant.\r\n * @param tickets The number of tickets held by the participant.\r\n */\r\n function Participant(participant, tickets) {\r\n if (tickets === void 0) { tickets = 1; }\r\n this._participant = participant;\r\n this._tickets = tickets;\r\n }\r\n Object.defineProperty(Participant.prototype, \"participant\", {\r\n /** Gets the actual participant. */\r\n get: function () {\r\n return this._participant;\r\n },\r\n enumerable: false,\r\n configurable: true\r\n });\r\n Object.defineProperty(Participant.prototype, \"tickets\", {\r\n /** Gets or sets the number of tickets held by the participant. */\r\n get: function () {\r\n return this._tickets;\r\n },\r\n set: function (value) {\r\n this._tickets = value;\r\n },\r\n enumerable: false,\r\n configurable: true\r\n });\r\n return Participant;\r\n}());\r\nexports.Participant = Participant;\r\n", "\"use strict\";\r\nObject.defineProperty(exports, \"__esModule\", { value: true });\r\nexports.isNaturalNumber = exports.isNullOrUndefined = void 0;\r\n/**\r\n * Gets whether the value provided is null or undefined.\r\n * @param value The value to check.\r\n * @returns Whether the value provided is null or undefined.\r\n */\r\nfunction isNullOrUndefined(value) {\r\n return value === null || value === undefined;\r\n}\r\nexports.isNullOrUndefined = isNullOrUndefined;\r\n/**\r\n * Gets whether the value provided is a natural number.\r\n * @param value The value to check.\r\n * @returns Whether the value provided is a natural number.\r\n */\r\nfunction isNaturalNumber(value) {\r\n return typeof value === \"number\" && value >= 1 && Math.floor(value) === value;\r\n}\r\nexports.isNaturalNumber = isNaturalNumber;\r\n", "\"use strict\";\r\nObject.defineProperty(exports, \"__esModule\", { value: true });\r\nexports.Lotto = void 0;\r\nvar Participant_1 = require(\"./Participant\");\r\nvar Utilities_1 = require(\"./Utilities\");\r\n/**\r\n * Represents a lotto consisting of a number of pickable ticket-holding participants.\r\n */\r\nvar Lotto = /** @class */ (function () {\r\n /**\r\n * Creates a new instance of Lotto.\r\n * @param customRandom The custom RNG to use in place of Math.random().\r\n */\r\n function Lotto(customRandom) {\r\n /** The array of participants that are holding tickets in the lotto. */\r\n this._participants = [];\r\n this._customRandom = customRandom;\r\n }\r\n /**\r\n * Adds a participant with the specified number of tickets, or adds to the participant ticket count if the participant already holds tickets.\r\n * @param participant The participant to add or to increase the ticket count for if they already hold tickets.\r\n * @param tickets The number of tickets, defaults to 1.\r\n * @returns The Lotto instance.\r\n */\r\n Lotto.prototype.add = function (participant, tickets) {\r\n if (tickets === void 0) { tickets = 1; }\r\n // Check that we have a valid ticket count.\r\n if (!(0, Utilities_1.isNaturalNumber)(tickets)) {\r\n throw new Error(\"tickets value must be a natural number\");\r\n }\r\n // Check whether this participant has already been added.\r\n var existingParticipant = this._participants.find(function (part) { return part.participant === participant; });\r\n if (existingParticipant) {\r\n // The participant has already been added to the lotto so just add to their ticket count.\r\n existingParticipant.tickets += tickets;\r\n }\r\n else {\r\n // The participant is not part of the lotto so we should add them.\r\n this._participants.push(new Participant_1.Participant(participant, tickets));\r\n }\r\n return this;\r\n };\r\n /**\r\n * Removes the specified number of tickets for the given participant from the draw, or all tickets if a ticket number is not defined.\r\n * @param participant The participant to remove tickets for.\r\n * @param tickets The number of tickets to remove, or undefined if all tickets are to be removed.\r\n * @returns The Lotto instance.\r\n */\r\n Lotto.prototype.remove = function (participant, tickets) {\r\n // Attempt to get the existing participant.\r\n var existingParticipant = this._participants.find(function (part) { return part.participant === participant; });\r\n // There is nothing to do if the specified participant isn't even part of the lotto.\r\n if (!existingParticipant) {\r\n return this;\r\n }\r\n // Check whether a tickets value was given.\r\n if (tickets !== undefined) {\r\n // Check that we have a valid ticket count.\r\n if (!(0, Utilities_1.isNaturalNumber)(tickets)) {\r\n throw new Error(\"tickets value must be a natural number\");\r\n }\r\n existingParticipant.tickets -= tickets;\r\n // If the participant no longer holds any tickets then they should be removed.\r\n if (existingParticipant.tickets < 1) {\r\n this._participants = this._participants.filter(function (part) { return part !== existingParticipant; });\r\n }\r\n }\r\n else {\r\n // We are removing all tickets for the participant so just remove them from the lotto.\r\n this._participants = this._participants.filter(function (part) { return part !== existingParticipant; });\r\n }\r\n return this;\r\n };\r\n /**\r\n * Draw a winning ticket and return the participant that holds the ticket.\r\n * @param options The draw options.\r\n * @returns The participant that holds the winning ticket.\r\n */\r\n Lotto.prototype.draw = function (options) {\r\n if (options === void 0) { options = {}; }\r\n // If we have no participants then just return null.\r\n if (this._participants.length === 0) {\r\n return null;\r\n }\r\n var redrawable = (0, Utilities_1.isNullOrUndefined)(options.redrawable) ? true : options.redrawable;\r\n var pickable = [];\r\n this._participants.forEach(function (_a) {\r\n var participant = _a.participant, tickets = _a.tickets;\r\n for (var ticketCount = 0; ticketCount < tickets; ticketCount++) {\r\n pickable.push(participant);\r\n }\r\n });\r\n var random;\r\n // We need a random floating-point number between 0 (inclusive) and 1 to scale up to pick our winner.\r\n // If a custom random function exists then we should use that or fall back to Math.random().\r\n if (this._customRandom) {\r\n // Call our custom random function to get a random floating-point number.\r\n random = this._customRandom();\r\n // Verify that the result of calling our custom random function is a number between 0 (inclusive) and 1.\r\n if (typeof random !== \"number\" || random < 0 || random >= 1) {\r\n throw new Error(\"the 'random' function provided did not return a number between 0 (inclusive) and 1\");\r\n }\r\n }\r\n else {\r\n // No custom random function was defined so just use good ol' Math.random().\r\n random = Math.random();\r\n }\r\n // Pick a winning participant.\r\n var winner = pickable[Math.floor(random * pickable.length)];\r\n // If the ticket isn't redrawable then we should remove a ticket from the winning participants ticket count.\r\n if (!redrawable) {\r\n this.remove(winner, 1);\r\n }\r\n // Return the winning participant.\r\n return winner;\r\n };\r\n /**\r\n * Draws multiple winning tickets and return an array of the participants that hold the winning tickets.\r\n * @param tickets The number of winning tickets to draw.\r\n * @param options The draw multiple options.\r\n * @returns An array of the participants that hold the winning tickets.\r\n */\r\n Lotto.prototype.drawMultiple = function (tickets, options) {\r\n if (options === void 0) { options = {}; }\r\n var uniqueResults = (0, Utilities_1.isNullOrUndefined)(options.unique) ? false : options.unique;\r\n // Handle cases where the user has asked for zero tickets (no idea why they would do this be we should trust them).\r\n if (tickets === 0) {\r\n return [];\r\n }\r\n // Now that we know out tickets value is not zero we should check that it is a valid natural number.\r\n if (!(0, Utilities_1.isNaturalNumber)(tickets)) {\r\n throw new Error(\"tickets value must be a natural number\");\r\n }\r\n var result = [];\r\n // Keep drawing tickets until we either reach the number of required tickets or we simply run out of tickets to draw.\r\n // We can run out of tickets to draw if 'options.redrawable' is explicity 'false' or we just had no participants when 'drawMultiple' was called.\r\n while (result.length < tickets && this._participants.length > 0) {\r\n result.push(this.draw(options));\r\n }\r\n // If the 'unique' draw option is set then we need to remove duplicates from the result list.\r\n if (uniqueResults) {\r\n // Create an array to store our unique results.\r\n var unique = [];\r\n // Iterate over all of our participants (with potential duplicates) and populate our array of unique values.\r\n for (var _i = 0, result_1 = result; _i < result_1.length; _i++) {\r\n var participant = result_1[_i];\r\n if (unique.indexOf(participant) === -1) {\r\n unique.push(participant);\r\n }\r\n }\r\n result = unique;\r\n }\r\n return result;\r\n };\r\n return Lotto;\r\n}());\r\nexports.Lotto = Lotto;\r\n", "\"use strict\";\r\nObject.defineProperty(exports, \"__esModule\", { value: true });\r\nexports.createLotto = void 0;\r\nvar Lotto_1 = require(\"./Lotto\");\r\n/**\r\n * A function that creates and returns a Lotto instance.\r\n * @param participantsOrOptions An array of initial participants or options relating to the creation of a Lotto instance.\r\n * @returns A new Lotto instance.\r\n */\r\nfunction createLotto(participantsOrOptions) {\r\n // If no initial participants or lotto options were provided as an argument then we can just return a new lotto instance now.\r\n if (!participantsOrOptions) {\r\n return new Lotto_1.Lotto();\r\n }\r\n // Check whether we were provided with an array of initial participants or a lotto options object.\r\n if (Array.isArray(participantsOrOptions)) {\r\n // We are dealing with a pre-defined array of participants.\r\n var participants = participantsOrOptions;\r\n var lotto_1 = new Lotto_1.Lotto();\r\n // If the lotto participants have been defined upfront then we will need to add them all to our lotto instance now.\r\n participants.forEach(function (_a) {\r\n var participant = _a[0], tokens = _a[1];\r\n return lotto_1.add(participant, tokens);\r\n });\r\n // Return the Lotto instance.\r\n return lotto_1;\r\n }\r\n else {\r\n // We are dealing with some lotto options.\r\n var random = participantsOrOptions.random, participants = participantsOrOptions.participants;\r\n // Create a Lotto instance passing the custom RNG function to use in place of Math.random() (which could be undefined).\r\n var lotto_2 = new Lotto_1.Lotto(random);\r\n // If the lotto participants have been defined upfront as part of the options then we will need to add them all to our lotto instance now.\r\n if (participants) {\r\n participants.forEach(function (_a) {\r\n var participant = _a[0], tokens = _a[1];\r\n return lotto_2.add(participant, tokens);\r\n });\r\n }\r\n // Return the Lotto instance.\r\n return lotto_2;\r\n }\r\n}\r\nexports.createLotto = createLotto;\r\n", "\"use strict\";\r\nObject.defineProperty(exports, \"__esModule\", { value: true });\r\nvar createLotto_1 = require(\"./createLotto\");\r\nexports.default = createLotto_1.createLotto;\r\n", "import { BehaviourTree, FlattenedTreeNode } from \"./BehaviourTree\";\nimport State from \"./State\";\n\nexport { BehaviourTree, State };\nexport type { FlattenedTreeNode };\n", "import Node from \"../../nodes/Node\";\n\n/**\n * An exception thrown when evaluating node guard path conditions and a conditions fails.\n */\nexport default class GuardUnsatisifedException extends Error {\n /**\n * @param source The node at which a guard condition failed.\n */\n constructor(private source: Node) {\n super(\"A guard path condition has failed\");\n }\n\n /**\n * Gets whether the specified node is the node at which a guard condition failed.\n * @param node The node to check against the source node.\n * @returns Whether the specified node is the node at which a guard condition failed.\n */\n isSourceNode = (node: Node) => node === this.source;\n}\n", "import { Agent } from \"../../Agent\";\nimport Guard from \"./Guard\";\nimport Node from \"../../nodes/Node\";\nimport GuardUnsatisifedException from \"./GuardUnsatisifedException\";\n\nexport type GuardPathPart = {\n node: Node;\n guards: Guard[];\n};\n\n/**\n * Represents a path of node guards along a root-to-leaf tree path.\n */\nexport default class GuardPath {\n /**\n * @param nodes An array of objects defining a node instance -> guard link, ordered by node depth.\n */\n constructor(private nodes: GuardPathPart[]) {}\n\n /**\n * Evaluate guard conditions for all guards in the tree path, moving outwards from the root.\n * @param agent The agent, required for guard evaluation.\n * @returns An evaluation results object.\n */\n evaluate = (agent: Agent) => {\n // We need to evaluate guard conditions for nodes up the tree, moving outwards from the root.\n for (const details of this.nodes) {\n // There can be multiple guards per node.\n for (const guard of details.guards) {\n // Check whether the guard condition passes, and throw an exception if not.\n if (!guard.isSatisfied(agent)) {\n throw new GuardUnsatisifedException(details.node);\n }\n }\n }\n };\n}\n", "/**\n * Enumeration of node state types.\n */\nexport enum State {\n READY = \"mistreevous.ready\",\n RUNNING = \"mistreevous.running\",\n SUCCEEDED = \"mistreevous.succeeded\",\n FAILED = \"mistreevous.failed\"\n}\n\nexport { State as default };\n\nexport type CompleteState = State.SUCCEEDED | State.FAILED;\nexport type AnyState = State.READY | State.RUNNING | CompleteState;\n", "import { Agent } from \"../Agent\";\nimport Attribute from \"../attributes/Attribute\";\nimport Entry from \"../attributes/callbacks/Entry\";\nimport Exit from \"../attributes/callbacks/Exit\";\nimport Step from \"../attributes/callbacks/Step\";\nimport Guard from \"../attributes/guards/Guard\";\nimport GuardPath from \"../attributes/guards/GuardPath\";\nimport GuardUnsatisifedException from \"../attributes/guards/GuardUnsatisifedException\";\nimport { BehaviourTreeOptions } from \"../BehaviourTreeOptions\";\nimport { AnyArgument } from \"../RootAstNodesBuilder\";\nimport State, { AnyState } from \"../State\";\nimport Leaf from \"./leaf/Leaf\";\n\n/**\n * A base node.\n */\nexport default abstract class Node {\n /**\n * The node uid.\n */\n private readonly uid: string = createNodeUid();\n /**\n * The node state.\n */\n private state: AnyState = State.READY;\n /**\n * The guard path to evaluate as part of a node update.\n */\n private guardPath: GuardPath | undefined;\n\n /**\n * @param type The node type.\n * @param attributes The node attributes.\n * @param args The node argument definitions.\n */\n constructor(private type: string, private attributes: Attribute[], private args: AnyArgument[]) {}\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected abstract onUpdate(agent: Agent, options: BehaviourTreeOptions): void;\n\n /**\n * Gets the name of the node.\n */\n public abstract getName(): string;\n\n /**\n * Gets whether this node is a leaf node.\n */\n public abstract isLeafNode: () => this is Leaf;\n\n /**\n * Gets/Sets the state of the node.\n */\n getState = (): AnyState => this.state;\n setState = (value: AnyState): void => {\n this.state = value;\n };\n\n /**\n * Gets the unique id of the node.\n */\n getUid = () => this.uid;\n\n /**\n * Gets the type of the node.\n */\n getType = () => this.type;\n\n /**\n * Gets the node attributes.\n */\n getAttributes = () => this.attributes;\n\n /**\n * Gets the node arguments.\n */\n getArguments = () => this.args;\n\n /**\n * Gets the node attribute with the specified type, or null if it does not exist.\n */\n getAttribute(type: \"entry\" | \"ENTRY\"): Entry;\n getAttribute(type: \"exit\" | \"EXIT\"): Exit;\n getAttribute(type: \"step\" | \"STEP\"): Step;\n getAttribute(type: string): Attribute {\n return (\n this.getAttributes().filter((decorator) => decorator.getType().toUpperCase() === type.toUpperCase())[0] ||\n null\n );\n }\n\n /**\n * Gets the node attributes.\n */\n getGuardAttributes = (): Guard[] => this.getAttributes().filter((decorator) => decorator.isGuard()) as Guard[];\n\n /**\n * Sets the guard path to evaluate as part of a node update.\n */\n setGuardPath = (value: GuardPath) => (this.guardPath = value);\n\n /**\n * Gets whether a guard path is assigned to this node.\n */\n hasGuardPath = () => !!this.guardPath;\n\n /**\n * Gets whether this node is in the specified state.\n * @param value The value to compare to the node state.\n */\n public is(value: AnyState): boolean {\n return this.state === value;\n }\n\n /**\n * Reset the state of the node.\n */\n public reset(): void {\n this.setState(State.READY);\n }\n\n /**\n * Abort the running of this node.\n * @param agent The agent.\n */\n public abort(agent: Agent): void {\n // There is nothing to do if this node is not in the running state.\n if (!this.is(State.RUNNING)) {\n return;\n }\n\n // Reset the state of this node.\n this.reset();\n\n this.getAttribute(\"exit\")?.callAgentFunction(agent, false, true);\n }\n\n /**\n * Update the node.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n * @returns The result of the update.\n */\n public update(agent: Agent, options: BehaviourTreeOptions): void {\n // If this node is already in a 'SUCCEEDED' or 'FAILED' state then there is nothing to do.\n if (this.is(State.SUCCEEDED) || this.is(State.FAILED)) {\n return;\n }\n\n try {\n // Evaluate all of the guard path conditions for the current tree path.\n this.guardPath!.evaluate(agent);\n\n // If this node is in the READY state then call the ENTRY for this node if it exists.\n if (this.is(State.READY)) {\n this.getAttribute(\"entry\")?.callAgentFunction(agent);\n }\n\n this.getAttribute(\"step\")?.callAgentFunction(agent);\n\n // Do the actual update.\n this.onUpdate(agent, options);\n\n // If this node is now in a 'SUCCEEDED' or 'FAILED' state then call the EXIT for this node if it exists.\n if (this.is(State.SUCCEEDED) || this.is(State.FAILED)) {\n this.getAttribute(\"exit\")?.callAgentFunction(agent, this.is(State.SUCCEEDED), false);\n }\n } catch (error) {\n // If the error is a GuardUnsatisfiedException then we need to determine if this node is the source.\n if (error instanceof GuardUnsatisifedException && error.isSourceNode(this)) {\n // Abort the current node.\n this.abort(agent);\n\n // Any node that is the source of an abort will be a failed node.\n this.setState(State.FAILED);\n } else {\n throw error;\n }\n }\n }\n}\n\n/**\n * Create a randomly generated node uid.\n * @returns A randomly generated node uid.\n */\nfunction createNodeUid(): string {\n var S4 = function () {\n return (((1 + Math.random()) * 0x10000) | 0).toString(16).substring(1);\n };\n return S4() + S4() + \"-\" + S4() + \"-\" + S4() + \"-\" + S4() + \"-\" + S4() + S4() + S4();\n}\n", "import Node from \"../Node\";\n\n/**\n * A leaf node.\n */\nexport default abstract class Leaf extends Node {\n /**\n * Gets whether this node is a leaf node.\n */\n isLeafNode = () => true;\n}\n", "import { ActionResult, Agent, ExitFunctionArg, FunctionArg, GlobalFunction } from \"./Agent\";\nimport { AnyArgument, RootAstNode } from \"./RootAstNodesBuilder\";\n\n// Exit callbacks receive their own special type of argument.\n// There's probably stricter ways to represent this but it feels overly complex right now.\ntype ExitResultArg = { value: ExitFunctionArg };\nexport type AnyExitArgument = AnyArgument | ExitResultArg;\n\nexport type InvokerFunction = (args: AnyExitArgument[]) => ActionResult;\n\n/**\n * A singleton used to store and lookup registered functions and subtrees.\n */\nexport default class Lookup {\n /**\n * The object holding any registered functions keyed on function name.\n */\n private static functionTable: { [key: string]: GlobalFunction } = {};\n /**\n * The object holding any registered sub-trees keyed on tree name.\n */\n private static subtreeTable: { [key: string]: RootAstNode } = {};\n\n /**\n * Gets the function with the specified name.\n * @param name The name of the function.\n * @returns The function with the specified name.\n */\n public static getFunc(name: string): GlobalFunction {\n return this.functionTable[name];\n }\n\n /**\n * Sets the function with the specified name for later lookup.\n * @param name The name of the function.\n * @param func The function.\n */\n public static setFunc(name: string, func: GlobalFunction): void {\n this.functionTable[name] = func;\n }\n\n /**\n * Gets the function invoker for the specified agent and function name.\n * If a function with the specified name exists on the agent object then it will\n * be returned, otherwise we will then check the registered functions for a match.\n * @param agent The agent instance that this behaviour tree is modelling behaviour for.\n * @param name The function name.\n * @returns The function invoker for the specified agent and function name.\n */\n static getFuncInvoker(agent: Agent, name: string): InvokerFunction | null {\n // Check whether the agent contains the specified function.\n const foundOnAgent = agent[name];\n if (foundOnAgent && typeof foundOnAgent === \"function\") {\n return (args: AnyExitArgument[]): boolean | ActionResult =>\n foundOnAgent.apply(\n agent,\n args.map((arg) => arg.value)\n );\n }\n\n // The agent does not contain the specified function but it may have been registered at some point.\n if (this.functionTable[name] && typeof this.functionTable[name] === \"function\") {\n return (args: AnyExitArgument[]) => this.functionTable[name](agent, ...args.map((arg) => arg.value));\n }\n\n // We have no function to invoke.\n return null;\n }\n\n /**\n * Gets the subtree with the specified name.\n * @param name The name of the subtree.\n * @returns The subtree with the specified name.\n */\n static getSubtree(name: string): RootAstNode {\n return this.subtreeTable[name];\n }\n\n /**\n * Sets the subtree with the specified name for later lookup.\n * @param name The name of the subtree.\n * @param subtree The subtree.\n */\n static setSubtree(name: string, subtree: RootAstNode) {\n this.subtreeTable[name] = subtree;\n }\n\n /**\n * Removes the registered function or subtree with the specified name.\n * @param name The name of the registered function or subtree.\n */\n static remove(name: string) {\n delete this.functionTable[name];\n delete this.subtreeTable[name];\n }\n\n /**\n * Remove all registered functions and subtrees.\n */\n static empty() {\n this.functionTable = {};\n this.subtreeTable = {};\n }\n}\n", "import Leaf from \"./Leaf\";\nimport State, { CompleteState } from \"../../State\";\nimport Lookup from \"../../Lookup\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { AnyArgument } from \"../../RootAstNodesBuilder\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * An Action leaf node.\n * This represents an immediate or ongoing state of behaviour.\n */\nexport default class Action extends Leaf {\n /**\n * @param attributes The node attributes.\n * @param actionName The action name.\n * @param actionArguments The array of action argument definitions.\n */\n constructor(attributes: Attribute[], private actionName: string, private actionArguments: AnyArgument[]) {\n super(\"action\", attributes, actionArguments);\n }\n\n /**\n * Whether there is a pending update promise.\n */\n private isUsingUpdatePromise = false;\n\n /**\n * The finished state result of an update promise.\n */\n private updatePromiseStateResult: CompleteState | null = null;\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // If the result of this action depends on an update promise then there is nothing to do until\n // it resolves, unless there has been a value set as a result of the update promise resolving.\n if (this.isUsingUpdatePromise) {\n // Check whether the update promise has resolved with a state value.\n if (this.updatePromiseStateResult) {\n // Set the state of this node to match the state returned by the promise.\n this.setState(this.updatePromiseStateResult);\n }\n\n return;\n }\n\n // Attempt to get the invoker for the action function.\n const actionFuncInvoker = Lookup.getFuncInvoker(agent, this.actionName);\n\n // The action function should be defined.\n if (actionFuncInvoker === null) {\n throw new Error(\n `cannot update action node as the action '${this.actionName}' function is not defined on the agent and has not been registered`\n );\n }\n\n // Call the action function, the result of which may be:\n // - The finished state of this action node.\n // - A promise to return a finished node state.\n // - Undefined if the node should remain in the running state.\n const updateResult = actionFuncInvoker(this.actionArguments) as CompleteState | Promise;\n\n if (updateResult instanceof Promise) {\n updateResult.then(\n (result) => {\n // If 'isUpdatePromisePending' is null then the promise was cleared as it was resolving, probably via an abort of reset.\n if (!this.isUsingUpdatePromise) {\n return;\n }\n\n // Check to make sure the result is a valid finished state.\n if (result !== State.SUCCEEDED && result !== State.FAILED) {\n throw new Error(\n \"action node promise resolved with an invalid value, expected a State.SUCCEEDED or State.FAILED value to be returned\"\n );\n }\n\n // Set pending update promise state result to be processed on next update.\n this.updatePromiseStateResult = result;\n },\n (reason) => {\n // If 'isUpdatePromisePending' is null then the promise was cleared as it was resolving, probably via an abort of reset.\n if (!this.isUsingUpdatePromise) {\n return;\n }\n\n // Just throw whatever was returned as the rejection argument.\n throw new Error(reason);\n }\n );\n\n // This node will be in the 'RUNNING' state until the update promise resolves.\n this.setState(State.RUNNING);\n\n // We are now waiting for the promise returned by the use to resolve before we know what state this node is in.\n this.isUsingUpdatePromise = true;\n } else {\n // Validate the returned value.\n this.validateUpdateResult(updateResult);\n\n // Set the state of this node, this may be undefined, which just means that the node is still in the 'RUNNING' state.\n this.setState(updateResult || State.RUNNING);\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => this.actionName;\n\n /**\n * Reset the state of the node.\n */\n reset = () => {\n // Reset the state of this node.\n this.setState(State.READY);\n\n // There is no longer an update promise that we care about.\n this.isUsingUpdatePromise = false;\n this.updatePromiseStateResult = null;\n };\n\n /**\n * Validate the result of an update function call.\n * @param result The result of an update function call.\n */\n private validateUpdateResult = (result: CompleteState | boolean) => {\n switch (result) {\n case State.SUCCEEDED:\n case State.FAILED:\n case undefined:\n return;\n default:\n throw new Error(\n `action '${this.actionName}' 'onUpdate' returned an invalid response, expected an optional State.SUCCEEDED or State.FAILED value to be returned`\n );\n }\n };\n}\n", "import Leaf from \"./Leaf\";\nimport State from \"../../State\";\nimport Lookup from \"../../Lookup\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { AnyArgument } from \"../../RootAstNodesBuilder\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A Condition leaf node.\n * This will succeed or fail immediately based on an agent predicate, without moving to the 'RUNNING' state.\n */\nexport default class Condition extends Leaf {\n /**\n * @param attributes The node attributes.\n * @param conditionName The name of the condition function.\n * @param conditionArguments The array of condition argument definitions.\n */\n constructor(attributes: Attribute[], private conditionName: string, private conditionArguments: AnyArgument[]) {\n super(\"condition\", attributes, conditionArguments);\n }\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // Attempt to get the invoker for the condition function.\n const conditionFuncInvoker = Lookup.getFuncInvoker(agent, this.conditionName);\n\n // The condition function should be defined.\n if (conditionFuncInvoker === null) {\n throw new Error(\n `cannot update condition node as the condition '${this.conditionName}' function is not defined on the agent and has not been registered`\n );\n }\n\n // Call the condition function to determine the state of this node.\n this.setState(!!conditionFuncInvoker(this.conditionArguments) ? State.SUCCEEDED : State.FAILED);\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => this.conditionName;\n}\n", "import Leaf from \"./Leaf\";\nimport State from \"../../State\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { Agent } from \"../../Agent\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A WAIT node.\n * The state of this node will change to SUCCEEDED after a duration of time\n */\nexport default class Wait extends Leaf {\n /**\n * @param attributes The node attributes.\n * @param duration The duration that this node will wait to succeed in milliseconds, or the earliest if longestDuration is defined.\n * @param longestDuration The longest possible duration in milliseconds that this node will wait to succeed.\n */\n constructor(attributes: Attribute[], private duration: number, private longestDuration: number) {\n super(\"wait\", attributes, []);\n }\n\n /**\n * The time in milliseconds at which this node was first updated.\n */\n private initialUpdateTime: number = 0;\n\n /**\n * The total duration in milliseconds that this node will be waiting for.\n */\n private totalDuration: number = 0;\n\n /**\n * The duration in milliseconds that this node has been waiting for.\n */\n private waitedDuration: number = 0;\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // If this node is in the READY state then we need to set the initial update time.\n if (this.is(State.READY)) {\n // Set the initial update time.\n this.initialUpdateTime = new Date().getTime();\n\n // Set the initial waited duration.\n this.waitedDuration = 0;\n\n // If a longestDuration value was defined then we will be randomly picking a duration between the\n // shortest and longest duration. If it was not defined, then we will be just using the duration.\n this.totalDuration = this.longestDuration\n ? Math.floor(Math.random() * (this.longestDuration - this.duration + 1) + this.duration)\n : this.duration;\n\n // The node is now running until we finish waiting.\n this.setState(State.RUNNING);\n }\n\n // If we have a 'getDeltaTime' function defined as part of our options then we will use it to figure out how long we have waited for.\n if (typeof options.getDeltaTime === \"function\") {\n // Get the delta time.\n const deltaTime = options.getDeltaTime();\n\n // Our delta time must be a valid number and cannot be NaN.\n if (typeof deltaTime !== \"number\" || isNaN(deltaTime)) {\n throw new Error(\"The delta time must be a valid number and not NaN.\");\n }\n\n // Update the amount of time that this node has been waiting for based on the delta time.\n this.waitedDuration += deltaTime * 1000;\n } else {\n // We are not using a delta time, so we will just work out hom much time has passed since the first update.\n this.waitedDuration = new Date().getTime() - this.initialUpdateTime;\n }\n\n // Have we waited long enough?\n if (this.waitedDuration >= this.totalDuration) {\n // We have finished waiting!\n this.setState(State.SUCCEEDED);\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () =>\n `WAIT ${this.longestDuration ? this.duration + \"ms-\" + this.longestDuration + \"ms\" : this.duration + \"ms\"}`;\n}\n", "import Node from \"../Node\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\n\n/**\n * A decorator node that wraps a single child node.\n */\nexport default abstract class Decorator extends Node {\n /**\n * @param type The node type.\n * @param attributes The node attributes.\n * @param child The child node.\n */\n constructor(type: string, attributes: Attribute[], protected child: Node) {\n super(type, attributes, []);\n }\n\n /**\n * Gets whether this node is a leaf node.\n */\n isLeafNode = () => false;\n\n /**\n * Gets the children of this node.\n */\n getChildren = () => [this.child];\n\n /**\n * Reset the state of the node.\n */\n reset = () => {\n // Reset the state of this node.\n this.setState(State.READY);\n\n // Reset the state of the child node.\n this.child.reset();\n };\n\n /**\n * Abort the running of this node.\n * @param agent The agent.\n */\n abort = (agent: Agent) => {\n // There is nothing to do if this node is not in the running state.\n if (!this.is(State.RUNNING)) {\n return;\n }\n\n // Abort the child node.\n this.child.abort(agent);\n\n // Reset the state of this node.\n this.reset();\n\n this.getAttribute(\"exit\")?.callAgentFunction(agent, false, true);\n };\n}\n", "import Node from \"../Node\";\nimport Decorator from \"./Decorator\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A Root node.\n * The root node will have a single child.\n */\nexport default class Root extends Decorator {\n /**\n * @param attributes The node attributes.\n * @param child The child node.\n */\n constructor(attributes: Attribute[], child: Node) {\n super(\"root\", attributes, child);\n }\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // If the child has never been updated or is running then we will need to update it now.\n if (this.child.getState() === State.READY || this.child.getState() === State.RUNNING) {\n // Update the child of this node.\n this.child.update(agent, options);\n }\n\n // The state of the root node is the state of its child.\n this.setState(this.child.getState());\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => \"ROOT\";\n}\n", "import Node from \"../Node\";\nimport Decorator from \"./Decorator\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A REPEAT node.\n * The node has a single child which can have:\n * -- A number of iterations for which to repeat the child node.\n * -- An infinite repeat loop if neither an iteration count or a condition function is defined.\n * The REPEAT node will stop and have a 'FAILED' state if its child is ever in a 'FAILED' state after an update.\n * The REPEAT node will attempt to move on to the next iteration if its child is ever in a 'SUCCEEDED' state.\n */\nexport default class Repeat extends Decorator {\n /**\n * @param attributes The node attributes.\n * @param iterations The number of iterations to repeat the child node, or the minimum number of iterations if maximumIterations is defined.\n * @param maximumIterations The maximum number of iterations to repeat the child node.\n * @param child The child node.\n */\n constructor(\n attributes: Attribute[],\n private iterations: number | null,\n private maximumIterations: number | null,\n child: Node\n ) {\n super(\"repeat\", attributes, child);\n }\n\n /**\n * The number of target iterations to make.\n */\n private targetIterationCount: number | null = null;\n\n /**\n * The current iteration count.\n */\n private currentIterationCount: number = 0;\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // If this node is in the READY state then we need to reset the child and the target iteration count.\n if (this.is(State.READY)) {\n // Reset the child node.\n this.child.reset();\n\n // Set the target iteration count.\n this.setTargetIterationCount();\n }\n\n // Do a check to see if we can iterate. If we can then this node will move into the 'RUNNING' state.\n // If we cannot iterate then we have hit our target iteration count, which means that the node has succeeded.\n if (this.canIterate()) {\n // This node is in the running state and can do its initial iteration.\n this.setState(State.RUNNING);\n\n // We may have already completed an iteration, meaning that the child node will be in the SUCCEEDED state.\n // If this is the case then we will have to reset the child node now.\n if (this.child.getState() === State.SUCCEEDED) {\n this.child.reset();\n }\n\n // Update the child of this node.\n this.child.update(agent, options);\n\n // If the child moved into the FAILED state when we updated it then there is nothing left to do and this node has also failed.\n // If it has moved into the SUCCEEDED state then we have completed the current iteration.\n if (this.child.getState() === State.FAILED) {\n // The child has failed, meaning that this node has failed.\n this.setState(State.FAILED);\n\n return;\n } else if (this.child.getState() === State.SUCCEEDED) {\n // We have completed an iteration.\n this.currentIterationCount += 1;\n }\n } else {\n // This node is in the 'SUCCEEDED' state as we cannot iterate any more.\n this.setState(State.SUCCEEDED);\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => {\n if (this.iterations !== null) {\n return `REPEAT ${\n this.maximumIterations ? this.iterations + \"x-\" + this.maximumIterations + \"x\" : this.iterations + \"x\"\n }`;\n }\n\n // Return the default repeat node name.\n return \"REPEAT\";\n };\n\n /**\n * Reset the state of the node.\n */\n reset = () => {\n // Reset the state of this node.\n this.setState(State.READY);\n\n // Reset the current iteration count.\n this.currentIterationCount = 0;\n\n // Reset the child node.\n this.child.reset();\n };\n\n /**\n * Gets whether an iteration can be made.\n * @returns Whether an iteration can be made.\n */\n private canIterate = () => {\n if (this.targetIterationCount !== null) {\n // We can iterate as long as we have not reached our target iteration count.\n return this.currentIterationCount < this.targetIterationCount;\n }\n\n // If neither an iteration count or a condition function were defined then we can iterate indefinitely.\n return true;\n };\n\n /**\n * Sets the target iteration count.\n */\n private setTargetIterationCount = () => {\n // Are we dealing with a finite number of iterations?\n if (typeof this.iterations === \"number\") {\n // If we have maximumIterations defined then we will want a random iteration count bounded by iterations and maximumIterations.\n this.targetIterationCount =\n typeof this.maximumIterations === \"number\"\n ? Math.floor(Math.random() * (this.maximumIterations - this.iterations + 1) + this.iterations)\n : this.iterations;\n } else {\n this.targetIterationCount = null;\n }\n };\n}\n", "import Node from \"../Node\";\nimport Decorator from \"./Decorator\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A RETRY node.\n * The node has a single child which can have:\n * -- A number of iterations for which to repeat the child node.\n * -- An infinite repeat loop if neither an iteration count or a condition function is defined.\n * The RETRY node will stop and have a 'SUCCEEDED' state if its child is ever in a 'SUCCEEDED' state after an update.\n * The RETRY node will attempt to move on to the next iteration if its child is ever in a 'FAILED' state.\n */\nexport default class Retry extends Decorator {\n /**\n * @param attributes The node attributes.\n * @param iterations The number of iterations to repeat the child node, or the minimum number of iterations if maximumIterations is defined.\n * @param maximumIterations The maximum number of iterations to repeat the child node.\n * @param child The child node.\n */\n constructor(\n attributes: Attribute[],\n private iterations: number | null,\n private maximumIterations: number | null,\n child: Node\n ) {\n super(\"retry\", attributes, child);\n }\n\n /**\n * The number of target iterations to make.\n */\n private targetIterationCount: number | null = null;\n\n /**\n * The current iteration count.\n */\n private currentIterationCount: number = 0;\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // If this node is in the READY state then we need to reset the child and the target iteration count.\n if (this.is(State.READY)) {\n // Reset the child node.\n this.child.reset();\n\n // Set the target iteration count.\n this.setTargetIterationCount();\n }\n\n // Do a check to see if we can iterate. If we can then this node will move into the 'RUNNING' state.\n // If we cannot iterate then we have hit our target iteration count, which means that the node has succeeded.\n if (this.canIterate()) {\n // This node is in the running state and can do its initial iteration.\n this.setState(State.RUNNING);\n\n // We may have already completed an iteration, meaning that the child node will be in the FAILED state.\n // If this is the case then we will have to reset the child node now.\n if (this.child.getState() === State.FAILED) {\n this.child.reset();\n }\n\n // Update the child of this node.\n this.child.update(agent, options);\n\n // If the child moved into the SUCCEEDED state when we updated it then there is nothing left to do and this node has also succeeded.\n // If it has moved into the FAILED state then we have completed the current iteration.\n if (this.child.getState() === State.SUCCEEDED) {\n // The child has succeeded, meaning that this node has succeeded.\n this.setState(State.SUCCEEDED);\n\n return;\n } else if (this.child.getState() === State.FAILED) {\n // We have completed an iteration.\n this.currentIterationCount += 1;\n }\n } else {\n // This node is in the 'FAILED' state as we cannot iterate any more.\n this.setState(State.FAILED);\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => {\n if (this.iterations !== null) {\n return `RETRY ${\n this.maximumIterations ? this.iterations + \"x-\" + this.maximumIterations + \"x\" : this.iterations + \"x\"\n }`;\n }\n\n // Return the default retry node name.\n return \"RETRY\";\n };\n\n /**\n * Reset the state of the node.\n */\n reset = () => {\n // Reset the state of this node.\n this.setState(State.READY);\n\n // Reset the current iteration count.\n this.currentIterationCount = 0;\n\n // Reset the child node.\n this.child.reset();\n };\n\n /**\n * Gets whether an iteration can be made.\n * @returns Whether an iteration can be made.\n */\n canIterate = () => {\n if (this.targetIterationCount !== null) {\n // We can iterate as long as we have not reached our target iteration count.\n return this.currentIterationCount < this.targetIterationCount;\n }\n\n // If neither an iteration count or a condition function were defined then we can iterate indefinitely.\n return true;\n };\n\n /**\n * Sets the target iteration count.\n */\n setTargetIterationCount = () => {\n // Are we dealing with a finite number of iterations?\n if (typeof this.iterations === \"number\") {\n // If we have maximumIterations defined then we will want a random iteration count bounded by iterations and maximumIterations.\n this.targetIterationCount =\n typeof this.maximumIterations === \"number\"\n ? Math.floor(Math.random() * (this.maximumIterations - this.iterations + 1) + this.iterations)\n : this.iterations;\n } else {\n this.targetIterationCount = null;\n }\n };\n}\n", "import Decorator from \"./Decorator\";\nimport State from \"../../State\";\nimport Node from \"../Node\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A Flip node.\n * This node wraps a single child and will flip the state of the child state.\n */\nexport default class Flip extends Decorator {\n /**\n * @param attributes The node attributes.\n * @param child The child node.\n */\n constructor(attributes: Attribute[], child: Node) {\n super(\"flip\", attributes, child);\n }\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // If the child has never been updated or is running then we will need to update it now.\n if (this.child.getState() === State.READY || this.child.getState() === State.RUNNING) {\n this.child.update(agent, options);\n }\n\n // The state of this node will depend in the state of its child.\n switch (this.child.getState()) {\n case State.RUNNING:\n this.setState(State.RUNNING);\n break;\n\n case State.SUCCEEDED:\n this.setState(State.FAILED);\n break;\n\n case State.FAILED:\n this.setState(State.SUCCEEDED);\n break;\n\n default:\n this.setState(State.READY);\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => \"FLIP\";\n}\n", "import Node from \"../Node\";\nimport Decorator from \"./Decorator\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A Succeed node.\n * This node wraps a single child and will always move to the 'SUCCEEDED' state when the child moves to a 'SUCCEEDED' or 'FAILED' state.\n */\nexport default class Succeed extends Decorator {\n /**\n * @param attributes The node attributes.\n * @param child The child node.\n */\n constructor(attributes: Attribute[], child: Node) {\n super(\"succeed\", attributes, child);\n }\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // If the child has never been updated or is running then we will need to update it now.\n if (this.child.getState() === State.READY || this.child.getState() === State.RUNNING) {\n this.child.update(agent, options);\n }\n\n // The state of this node will depend in the state of its child.\n switch (this.child.getState()) {\n case State.RUNNING:\n this.setState(State.RUNNING);\n break;\n\n case State.SUCCEEDED:\n case State.FAILED:\n this.setState(State.SUCCEEDED);\n break;\n\n default:\n this.setState(State.READY);\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => \"SUCCEED\";\n}\n", "import Node from \"../Node\";\nimport Decorator from \"./Decorator\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A Fail node.\n * This node wraps a single child and will always move to the 'FAILED' state when the child moves to a 'SUCCEEDED' or 'FAILED' state.\n */\nexport default class Fail extends Decorator {\n /**\n * @param attributes The node attributes.\n * @param child The child node.\n */\n constructor(attributes: Attribute[], child: Node) {\n super(\"fail\", attributes, child);\n }\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // If the child has never been updated or is running then we will need to update it now.\n if (this.child.getState() === State.READY || this.child.getState() === State.RUNNING) {\n this.child.update(agent, options);\n }\n\n // The state of this node will depend in the state of its child.\n switch (this.child.getState()) {\n case State.RUNNING:\n this.setState(State.RUNNING);\n break;\n\n case State.SUCCEEDED:\n case State.FAILED:\n this.setState(State.FAILED);\n break;\n\n default:\n this.setState(State.READY);\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => \"FAIL\";\n}\n", "import createLotto from \"lotto-draw\";\r\n\r\nimport Node from \"../Node\";\r\nimport Composite from \"./Composite\";\r\nimport State from \"../../State\";\r\nimport { Agent } from \"../../Agent\";\r\nimport Attribute from \"../../attributes/Attribute\";\r\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\r\n\r\n/**\r\n * A LOTTO node.\r\n * A winning child is picked on the initial update of this node, based on ticket weighting.\r\n * The state of this node will match the state of the winning child.\r\n */\r\nexport default class Lotto extends Composite {\r\n /**\r\n * @param attributes The node attributes.\r\n * @param tickets The child node tickets.\r\n * @param children The child nodes.\r\n */\r\n constructor(attributes: Attribute[], private tickets: number[], children: Node[]) {\r\n super(\"lotto\", attributes, children);\r\n }\r\n\r\n /**\r\n * The child node selected to be the active one.\r\n */\r\n private selectedChild: Node | undefined;\r\n\r\n /**\r\n * Called when the node is being updated.\r\n * @param agent The agent.\r\n * @param options The behaviour tree options object.\r\n */\r\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\r\n // If this node is in the READY state then we need to pick a winning child node.\r\n if (this.is(State.READY)) {\r\n // Create a lotto draw with which to randomly pick a child node to become the active one.\r\n const lottoDraw = createLotto({\r\n // Hook up the optional 'random' behaviour tree function option to the one used by 'lotto-draw'.\r\n random: options.random,\r\n // Pass in each child node as a participant in the lotto draw with their respective ticket count.\r\n participants: this.children.map((child, index) => [child, this.tickets[index] || 1])\r\n });\r\n\r\n // Randomly pick a child based on ticket weighting, this will become the active child for this composite node.\r\n this.selectedChild = lottoDraw.draw() || undefined;\r\n }\r\n\r\n // If something went wrong and we don't have an active child then we should throw an error.\r\n if (!this.selectedChild) {\r\n throw new Error(\"failed to update lotto node as it has no active child\");\r\n }\r\n\r\n // If the selected child has never been updated or is running then we will need to update it now.\r\n if (this.selectedChild.getState() === State.READY || this.selectedChild.getState() === State.RUNNING) {\r\n this.selectedChild.update(agent, options);\r\n }\r\n\r\n // The state of the lotto node is the state of its selected child.\r\n this.setState(this.selectedChild.getState());\r\n }\r\n\r\n /**\r\n * Gets the name of the node.\r\n */\r\n getName = () => (this.tickets.length ? `LOTTO [${this.tickets.join(\",\")}]` : \"LOTTO\");\r\n}\r\n", "import Node from \"../Node\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\n\n/**\n * A composite node that wraps child nodes.\n */\nexport default abstract class Composite extends Node {\n /**\n * @param type The node type.\n * @param attributes The node attributes.\n * @param children The child nodes.\n */\n constructor(type: string, attributes: Attribute[], protected children: Node[]) {\n super(type, attributes, []);\n }\n\n /**\n * Gets whether this node is a leaf node.\n */\n isLeafNode = () => false;\n\n /**\n * Gets the children of this node.\n */\n getChildren = () => this.children;\n\n /**\n * Reset the state of the node.\n */\n reset = () => {\n // Reset the state of this node.\n this.setState(State.READY);\n\n // Reset the state of any child nodes.\n this.getChildren().forEach((child) => child.reset());\n };\n\n /**\n * Abort the running of this node.\n * @param agent The agent.\n */\n abort = (agent: Agent) => {\n // There is nothing to do if this node is not in the running state.\n if (!this.is(State.RUNNING)) {\n return;\n }\n\n // Abort any child nodes.\n this.getChildren().forEach((child) => child.abort(agent));\n\n // Reset the state of this node.\n this.reset();\n\n this.getAttribute(\"exit\")?.callAgentFunction(agent, false, true);\n };\n}\n", "import Composite from \"./Composite\";\nimport Node from \"../Node\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A SELECTOR node.\n * The child nodes are executed in sequence until one succeeds or all fail.\n */\nexport default class Selector extends Composite {\n /**\n * @param attributes The node attributes.\n * @param children The child nodes.\n */\n constructor(attributes: Attribute[], protected children: Node[]) {\n super(\"selector\", attributes, children);\n }\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // Iterate over all of the children of this node.\n for (const child of this.children) {\n // If the child has never been updated or is running then we will need to update it now.\n if (child.getState() === State.READY || child.getState() === State.RUNNING) {\n // Update the child of this node.\n child.update(agent, options);\n }\n\n // If the current child has a state of 'SUCCEEDED' then this node is also a 'SUCCEEDED' node.\n if (child.getState() === State.SUCCEEDED) {\n // This node is a 'SUCCEEDED' node.\n this.setState(State.SUCCEEDED);\n\n // There is no need to check the rest of the selector nodes.\n return;\n }\n\n // If the current child has a state of 'FAILED' then we should move on to the next child.\n if (child.getState() === State.FAILED) {\n // Find out if the current child is the last one in the selector.\n // If it is then this sequence node has also failed.\n if (this.children.indexOf(child) === this.children.length - 1) {\n // This node is a 'FAILED' node.\n this.setState(State.FAILED);\n\n // There is no need to check the rest of the selector as we have completed it.\n return;\n } else {\n // The child node failed, try the next one.\n continue;\n }\n }\n\n // The node should be in the 'RUNNING' state.\n if (child.getState() === State.RUNNING) {\n // This node is a 'RUNNING' node.\n this.setState(State.RUNNING);\n\n // There is no need to check the rest of the selector as the current child is still running.\n return;\n }\n\n // The child node was not in an expected state.\n throw new Error(\"child node was not in an expected state.\");\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => \"SELECTOR\";\n}\n", "import Composite from \"./Composite\";\nimport Node from \"../Node\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A SEQUENCE node.\n * The child nodes are executed in sequence until one fails or all succeed.\n */\nexport default class Sequence extends Composite {\n /**\n * @param attributes The node attributes.\n * @param children The child nodes.\n */\n constructor(attributes: Attribute[], protected children: Node[]) {\n super(\"sequence\", attributes, children);\n }\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // Iterate over all of the children of this node.\n for (const child of this.children) {\n // If the child has never been updated or is running then we will need to update it now.\n if (child.getState() === State.READY || child.getState() === State.RUNNING) {\n // Update the child of this node.\n child.update(agent, options);\n }\n\n // If the current child has a state of 'SUCCEEDED' then we should move on to the next child.\n if (child.getState() === State.SUCCEEDED) {\n // Find out if the current child is the last one in the sequence.\n // If it is then this sequence node has also succeeded.\n if (this.children.indexOf(child) === this.children.length - 1) {\n // This node is a 'SUCCEEDED' node.\n this.setState(State.SUCCEEDED);\n\n // There is no need to check the rest of the sequence as we have completed it.\n return;\n } else {\n // The child node succeeded, but we have not finished the sequence yet.\n continue;\n }\n }\n\n // If the current child has a state of 'FAILED' then this node is also a 'FAILED' node.\n if (child.getState() === State.FAILED) {\n // This node is a 'FAILED' node.\n this.setState(State.FAILED);\n\n // There is no need to check the rest of the sequence.\n return;\n }\n\n // The node should be in the 'RUNNING' state.\n if (child.getState() === State.RUNNING) {\n // This node is a 'RUNNING' node.\n this.setState(State.RUNNING);\n\n // There is no need to check the rest of the sequence as the current child is still running.\n return;\n }\n\n // The child node was not in an expected state.\n throw new Error(\"child node was not in an expected state.\");\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => \"SEQUENCE\";\n}\n", "import Composite from \"./Composite\";\nimport State from \"../../State\";\nimport Node from \"../Node\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A PARALLEL node.\n * The child nodes are executed concurrently until one fails or all succeed.\n */\nexport default class Parallel extends Composite {\n /**\n * @param attributes The node attributes.\n * @param children The child nodes.\n */\n constructor(attributes: Attribute[], children: Node[]) {\n super(\"parallel\", attributes, children);\n }\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // Keep a count of the number of succeeded child nodes.\n let succeededCount = 0;\n\n let hasChildFailed = false;\n\n // Iterate over all of the children of this node.\n for (const child of this.children) {\n // If the child has never been updated or is running then we will need to update it now.\n if (child.getState() === State.READY || child.getState() === State.RUNNING) {\n // Update the child of this node.\n child.update(agent, options);\n }\n\n // If the current child has a state of 'SUCCEEDED' then we should move on to the next child.\n if (child.getState() === State.SUCCEEDED) {\n // The child node has succeeded, keep track of this to determine if all children have.\n succeededCount++;\n\n // The child node succeeded, but we have not finished checking every child node yet.\n continue;\n }\n\n // If the current child has a state of 'FAILED' then this node is also a 'FAILED' node.\n if (child.getState() === State.FAILED) {\n hasChildFailed = true;\n\n // There is no need to check the rest of the children.\n break;\n }\n\n // The node should be in the 'RUNNING' state.\n if (child.getState() !== State.RUNNING) {\n // The child node was not in an expected state.\n throw new Error(\"child node was not in an expected state.\");\n }\n }\n\n if (hasChildFailed) {\n // This node is a 'FAILED' node.\n this.setState(State.FAILED);\n\n // Abort every running child.\n for (const child of this.children) {\n if (child.getState() === State.RUNNING) {\n child.abort(agent);\n }\n }\n } else {\n // If all children have succeeded then this node has also succeeded, otherwise it is still running.\n this.setState(succeededCount === this.children.length ? State.SUCCEEDED : State.RUNNING);\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => \"PARALLEL\";\n}\n", "import { AnyArgument } from \"../RootAstNodesBuilder\";\nimport Guard from \"./guards/Guard\";\n\nexport type AttributeDetails = {\n /** The attribute type. */\n type: string;\n\n /** The attribute arguments. */\n args: AnyArgument[];\n};\n\n/**\n * A base node attribute.\n */\nexport default abstract class Attribute {\n /**\n * @param type The node attribute type.\n * @param args The array of attribute argument definitions.\n */\n constructor(protected type: string, protected args: AnyArgument[]) {}\n\n /**\n * Gets the type of the attribute.\n */\n getType = () => this.type;\n\n /**\n * Gets the array of attribute argument definitions.\n */\n getArguments = () => this.args;\n\n /**\n * Gets the attribute details.\n */\n abstract getDetails(): TAttributeDetails;\n\n /**\n * Gets whether this attribute is a guard.\n */\n abstract isGuard: () => this is Guard;\n}\n", "import { Agent } from \"../../Agent\";\nimport { AnyArgument } from \"../../RootAstNodesBuilder\";\nimport Attribute, { AttributeDetails } from \"../Attribute\";\n\nexport type GuardAttributeDetails = {\n /** The name of the condition function that determines whether the guard is satisfied. */\n condition: string;\n} & AttributeDetails;\n\n/**\n * A base node guard attribute.\n */\nexport default abstract class Guard extends Attribute {\n /**\n * @param type The node attribute type.\n * @param args The array of decorator argument definitions.\n * @param condition The name of the condition function that determines whether the guard is satisfied.\n */\n constructor(type: string, args: AnyArgument[], private condition: string) {\n super(type, args);\n }\n\n /**\n * Gets the name of the condition function that determines whether the guard is satisfied.\n */\n getCondition = () => this.condition;\n\n /**\n * Gets whether this attribute is a guard.\n */\n isGuard = () => true;\n\n /**\n * Gets the attribute details.\n */\n getDetails(): GuardAttributeDetails {\n return {\n type: this.getType(),\n args: this.getArguments(),\n condition: this.getCondition()\n };\n }\n\n /**\n * Gets whether the guard is satisfied.\n * @param agent The agent.\n * @returns Whether the guard is satisfied.\n */\n abstract isSatisfied(agent: Agent): boolean;\n}\n", "import Guard from \"./Guard\";\nimport Lookup from \"../../Lookup\";\nimport { Agent } from \"../../Agent\";\nimport { AnyArgument } from \"../../RootAstNodesBuilder\";\n\n/**\n * A WHILE guard which is satisfied as long as the given condition remains true.\n */\nexport default class While extends Guard {\n /**\n * @param condition The name of the condition function that determines whether the guard is satisfied.\n * @param args The array of decorator argument definitions.\n */\n constructor(condition: string, args: AnyArgument[]) {\n super(\"while\", args, condition);\n }\n\n /**\n * Gets whether the guard is satisfied.\n * @param agent The agent.\n * @returns Whether the guard is satisfied.\n */\n isSatisfied = (agent: Agent) => {\n // Attempt to get the invoker for the condition function.\n const conditionFuncInvoker = Lookup.getFuncInvoker(agent, this.getCondition());\n\n // The condition function should be defined.\n if (conditionFuncInvoker === null) {\n throw new Error(\n `cannot evaluate node guard as the condition '${this.getCondition()}' function is not defined on the agent and has not been registered`\n );\n }\n\n // Call the condition function to determine whether this guard is satisfied.\n return !!conditionFuncInvoker(this.args);\n };\n}\n", "import Guard from \"./Guard\";\nimport Lookup from \"../../Lookup\";\nimport { Agent } from \"../../Agent\";\nimport { AnyArgument } from \"../../RootAstNodesBuilder\";\n\n/**\n * An UNTIL guard which is satisfied as long as the given condition remains false.\n */\nexport default class Until extends Guard {\n /**\n * @param condition The name of the condition function that determines whether the guard is satisfied.\n * @param args The array of decorator argument definitions.\n */\n constructor(condition: string, args: AnyArgument[]) {\n super(\"until\", args, condition);\n }\n\n /**\n * Gets whether the guard is satisfied.\n * @param agent The agent.\n * @returns Whether the guard is satisfied.\n */\n isSatisfied = (agent: Agent) => {\n // Attempt to get the invoker for the condition function.\n const conditionFuncInvoker = Lookup.getFuncInvoker(agent, this.getCondition());\n\n // The condition function should be defined.\n if (conditionFuncInvoker === null) {\n throw new Error(\n `cannot evaluate node guard as the condition '${this.getCondition()}' function is not defined on the agent and has not been registered`\n );\n }\n\n // Call the condition function to determine whether this guard is satisfied.\n return !!!conditionFuncInvoker(this.args);\n };\n}\n", "import { Agent } from \"../../Agent\";\nimport { AnyArgument } from \"../../RootAstNodesBuilder\";\nimport Attribute, { AttributeDetails } from \"../Attribute\";\n\nexport type CallbackAttributeDetails = {\n /** The name of the agent function that is called. */\n functionName: string;\n} & AttributeDetails;\n\n/**\n * A base node callback attribute.\n */\nexport default abstract class Callback extends Attribute {\n /**\n * @param type The node attribute type.\n * @param args The array of decorator argument definitions.\n * @param functionName The name of the agent function to call.\n */\n constructor(type: string, args: AnyArgument[], private functionName: string) {\n super(type, args);\n }\n\n /**\n * Gets the name of the agent function to call.\n */\n getFunctionName = () => this.functionName;\n\n /**\n * Gets whether this attribute is a guard.\n */\n isGuard = () => false;\n\n /**\n * Gets the attribute details.\n */\n getDetails(): CallbackAttributeDetails {\n return {\n type: this.getType(),\n args: this.getArguments(),\n functionName: this.getFunctionName()\n };\n }\n\n /**\n * Attempt to call the agent function that this callback refers to.\n * @param agent The agent.\n */\n abstract callAgentFunction: (agent: Agent, isSuccess: boolean, isAborted: boolean) => void;\n}\n", "import Callback from \"./Callback\";\nimport Lookup from \"../../Lookup\";\nimport { Agent } from \"../../Agent\";\nimport { AnyArgument } from \"../../RootAstNodesBuilder\";\n\n/**\n * An ENTRY callback which defines an agent function to call when the associated node is updated and moves out of running state.\n */\nexport default class Entry extends Callback {\n /**\n * @param functionName The name of the agent function to call.\n * @param args The array of callback argument definitions.\n */\n constructor(functionName: string, args: AnyArgument[]) {\n super(\"entry\", args, functionName);\n }\n\n /**\n * Attempt to call the agent function that this callback refers to.\n * @param agent The agent.\n */\n callAgentFunction = (agent: Agent) => {\n // Attempt to get the invoker for the callback function.\n const callbackFuncInvoker = Lookup.getFuncInvoker(agent, this.getFunctionName());\n\n // The callback function should be defined.\n if (callbackFuncInvoker === null) {\n throw new Error(\n `cannot call entry function '${this.getFunctionName()}' as is not defined on the agent and has not been registered`\n );\n }\n\n // Call the callback function.\n callbackFuncInvoker(this.args);\n };\n}\n", "import Callback from \"./Callback\";\nimport Lookup, { AnyExitArgument } from \"../../Lookup\";\nimport { Agent } from \"../../Agent\";\nimport { AnyArgument } from \"../../RootAstNodesBuilder\";\n\n/**\n * An EXIT callback which defines an agent function to call when the associated node is updated and moves to a finished state or is aborted.\n */\nexport default class Exit extends Callback {\n /**\n * @param functionName The name of the agent function to call.\n * @param args The array of callback argument definitions.\n */\n constructor(functionName: string, args: AnyArgument[]) {\n super(\"exit\", args, functionName);\n }\n\n /**\n * Attempt to call the agent function that this callback refers to.\n * @param agent The agent.\n * @param isSuccess Whether the decorated node was left with a success state.\n * @param isAborted Whether the decorated node was aborted.\n */\n callAgentFunction = (agent: Agent, isSuccess: boolean, isAborted: boolean) => {\n // Attempt to get the invoker for the callback function.\n const callbackFuncInvoker = Lookup.getFuncInvoker(agent, this.getFunctionName());\n\n // The callback function should be defined.\n if (callbackFuncInvoker === null) {\n throw new Error(\n `cannot call exit function '${this.getFunctionName()}' as is not defined on the agent and has not been registered`\n );\n }\n\n // Call the callback function\n callbackFuncInvoker([{ value: { succeeded: isSuccess, aborted: isAborted } }, ...this.args]);\n };\n}\n", "import Callback from \"./Callback\";\nimport Lookup from \"../../Lookup\";\nimport { Agent } from \"../../Agent\";\nimport { AnyArgument } from \"../../RootAstNodesBuilder\";\n\n/**\n * A STEP callback which defines an agent function to call when the associated node is updated.\n */\nexport default class Step extends Callback {\n /**\n * @param functionName The name of the agent function to call.\n * @param args The array of callback argument definitions.\n */\n constructor(functionName: string, args: AnyArgument[]) {\n super(\"step\", args, functionName);\n }\n\n /**\n * Attempt to call the agent function that this callback refers to.\n * @param agent The agent.\n */\n callAgentFunction = (agent: Agent) => {\n // Attempt to get the invoker for the callback function.\n const callbackFuncInvoker = Lookup.getFuncInvoker(agent, this.getFunctionName());\n\n // The callback function should be defined.\n if (callbackFuncInvoker === null) {\n throw new Error(\n `cannot call step function '${this.getFunctionName()}' as is not defined on the agent and has not been registered`\n );\n }\n\n // Call the callback function.\n callbackFuncInvoker(this.args);\n };\n}\n", "import Action from \"./nodes/leaf/Action\";\nimport Condition from \"./nodes/leaf/Condition\";\nimport Wait from \"./nodes/leaf/Wait\";\nimport Root from \"./nodes/decorator/Root\";\nimport Repeat from \"./nodes/decorator/Repeat\";\nimport Retry from \"./nodes/decorator/Retry\";\nimport Flip from \"./nodes/decorator/Flip\";\nimport Succeed from \"./nodes/decorator/Succeed\";\nimport Fail from \"./nodes/decorator/Fail\";\nimport Lotto from \"./nodes/composite/Lotto\";\nimport Selector from \"./nodes/composite/Selector\";\nimport Sequence from \"./nodes/composite/Sequence\";\nimport Parallel from \"./nodes/composite/Parallel\";\nimport Node from \"./nodes/Node\";\nimport While from \"./attributes/guards/While\";\nimport Until from \"./attributes/guards/Until\";\nimport Entry from \"./attributes/callbacks/Entry\";\nimport Exit from \"./attributes/callbacks/Exit\";\nimport Step from \"./attributes/callbacks/Step\";\nimport Callback from \"./attributes/callbacks/Callback\";\nimport Guard from \"./attributes/guards/Guard\";\nimport Attribute from \"./attributes/Attribute\";\nimport Composite from \"./nodes/composite/Composite\";\nimport Decorator from \"./nodes/decorator/Decorator\";\nimport Leaf from \"./nodes/leaf/Leaf\";\n\nexport type Argument = {\n value: T;\n type: string; // Used for validation.\n};\ntype NullArgument = Argument & {\n type: \"null\";\n};\ntype BooleanArgument = Argument & {\n type: \"boolean\";\n};\ntype NumberArgument = Argument & {\n type: \"number\";\n isInteger: boolean; // Used for validation.\n};\ntype StringPlaceholderArgument = Argument & {\n type: \"string\";\n};\ntype IdentifierArgument = Argument & {\n type: \"identifier\";\n};\nexport type AnyArgument =\n | NullArgument\n | BooleanArgument\n | NumberArgument\n | StringPlaceholderArgument\n | IdentifierArgument;\n\n/**\n * The node attribute factories.\n */\nconst AttributeFactories: {\n [key: string]: (functionName: string, attributeArguments: AnyArgument[]) => Callback | Guard;\n} = {\n WHILE: (condition: string, attributeArguments: AnyArgument[]) => new While(condition, attributeArguments),\n UNTIL: (condition: string, attributeArguments: AnyArgument[]) => new Until(condition, attributeArguments),\n ENTRY: (functionName: string, attributeArguments: AnyArgument[]) => new Entry(functionName, attributeArguments),\n EXIT: (functionName: string, attributeArguments: AnyArgument[]) => new Exit(functionName, attributeArguments),\n STEP: (functionName: string, attributeArguments: AnyArgument[]) => new Step(functionName, attributeArguments)\n};\n\ntype Validatable = {\n children?: AstNode[];\n validate: (depth: number) => void;\n};\n\ntype NodeInstanceCreator = (\n namedRootNodeProvider: (name: string) => RootAstNode,\n visitedBranches: string[]\n) => T;\n\nexport type AstNode = Validatable & {\n type: string;\n createNodeInstance: NodeInstanceCreator;\n};\n\nexport type LeafAstNode = AstNode & {\n type: \"action\" | \"condition\" | \"wait\";\n attributes: Attribute[];\n};\n\nexport type CompositeAstNode = AstNode & {\n type: \"lotto\" | \"parallel\" | \"selector\" | \"sequence\";\n attributes: Attribute[];\n children: AstNode[];\n};\n\nexport type DecoratorAstNode = AstNode & {\n type: \"fail\" | \"flip\" | \"repeat\" | \"retry\" | \"root\" | \"succeed\";\n attributes: Attribute[];\n children: AstNode[];\n};\n\nexport type BranchAstNode = AstNode & {\n type: \"branch\";\n branchName: \"\" | string;\n};\n\nexport type LottoAstNode = CompositeAstNode & {\n type: \"lotto\";\n tickets: number[];\n};\n\nexport type RootAstNode = DecoratorAstNode & {\n type: \"root\";\n name: null | string;\n};\n\nexport type IterableAstNode = DecoratorAstNode & {\n type: \"repeat\" | \"retry\";\n iterations: null | number;\n maximumIterations: null | number;\n};\n\nexport type ActionAstNode = LeafAstNode & {\n type: \"action\";\n actionName: string;\n actionArguments: AnyArgument[];\n};\n\nexport type ConditionAstNode = LeafAstNode & {\n type: \"condition\";\n conditionName: string;\n conditionArguments: AnyArgument[];\n};\n\nexport type WaitAstNode = LeafAstNode & {\n type: \"wait\";\n duration: number | null;\n longestDuration: number | null;\n};\n\nexport type AnyAstNode =\n | BranchAstNode\n | CompositeAstNode\n | LottoAstNode\n | DecoratorAstNode\n | RootAstNode\n | IterableAstNode\n | LeafAstNode\n | ActionAstNode\n | ConditionAstNode\n | WaitAstNode;\n\n/**\n * The AST node factories.\n */\nconst ASTNodeFactories = {\n ROOT: (): RootAstNode => ({\n type: \"root\",\n attributes: [],\n name: null,\n children: [],\n validate(depth: number) {\n // A root node cannot be the child of another node.\n if (depth > 1) {\n throw new Error(\"a root node cannot be the child of another node\");\n }\n\n // A root node must have a single child node.\n if (this.children.length !== 1) {\n throw new Error(\"a root node must have a single child\");\n }\n },\n createNodeInstance(namedRootNodeProvider, visitedBranches) {\n return new Root(\n this.attributes,\n this.children![0].createNodeInstance(namedRootNodeProvider, visitedBranches.slice())\n );\n }\n }),\n BRANCH: (): BranchAstNode => ({\n type: \"branch\",\n branchName: \"\",\n validate() {},\n createNodeInstance(namedRootNodeProvider, visitedBranches) {\n // Try to find the root node with a matching branch name.\n const targetRootNode = namedRootNodeProvider(this.branchName);\n\n // If we have already visited this branch then we have a circular dependency.\n if (visitedBranches.indexOf(this.branchName) !== -1) {\n throw new Error(`circular dependency found in branch node references for branch '${this.branchName}'`);\n }\n\n // If we have a target root node, then the node instance we want will be the first and only child of the referenced root node.\n if (targetRootNode) {\n return targetRootNode\n .createNodeInstance(namedRootNodeProvider, visitedBranches.concat(this.branchName))\n .getChildren()[0];\n } else {\n throw new Error(`branch references root node '${this.branchName}' which has not been defined`);\n }\n }\n }),\n SELECTOR: (): CompositeAstNode => ({\n type: \"selector\",\n attributes: [],\n children: [],\n validate() {\n // A selector node must have at least a single node.\n if (this.children.length < 1) {\n throw new Error(\"a selector node must have at least a single child\");\n }\n },\n createNodeInstance(namedRootNodeProvider, visitedBranches) {\n return new Selector(\n this.attributes,\n this.children.map((child) => child.createNodeInstance(namedRootNodeProvider, visitedBranches.slice()))\n );\n }\n }),\n SEQUENCE: (): CompositeAstNode => ({\n type: \"sequence\",\n attributes: [],\n children: [],\n validate() {\n // A sequence node must have at least a single node.\n if (this.children.length < 1) {\n throw new Error(\"a sequence node must have at least a single child\");\n }\n },\n createNodeInstance(namedRootNodeProvider, visitedBranches) {\n return new Sequence(\n this.attributes,\n this.children.map((child) => child.createNodeInstance(namedRootNodeProvider, visitedBranches.slice()))\n );\n }\n }),\n PARALLEL: (): CompositeAstNode => ({\n type: \"parallel\",\n attributes: [],\n children: [],\n validate() {\n // A parallel node must have at least a single node.\n if (this.children.length < 1) {\n throw new Error(\"a parallel node must have at least a single child\");\n }\n },\n createNodeInstance(namedRootNodeProvider, visitedBranches) {\n return new Parallel(\n this.attributes,\n this.children.map((child) => child.createNodeInstance(namedRootNodeProvider, visitedBranches.slice()))\n );\n }\n }),\n LOTTO: (): LottoAstNode => ({\n type: \"lotto\",\n attributes: [],\n children: [],\n tickets: [],\n validate() {\n // A lotto node must have at least a single node.\n if (this.children!.length < 1) {\n throw new Error(\"a lotto node must have at least a single child\");\n }\n },\n createNodeInstance(namedRootNodeProvider, visitedBranches) {\n return new Lotto(\n this.attributes,\n this.tickets!,\n this.children!.map((child) => child.createNodeInstance(namedRootNodeProvider, visitedBranches.slice()))\n );\n }\n }),\n REPEAT: (): IterableAstNode => ({\n type: \"repeat\",\n attributes: [],\n iterations: null,\n maximumIterations: null,\n children: [],\n validate() {\n // A repeat node must have a single node.\n if (this.children!.length !== 1) {\n throw new Error(\"a repeat node must have a single child\");\n }\n\n // A repeat node must have a positive number of iterations if defined.\n if (this.iterations !== null && this.iterations! < 0) {\n throw new Error(\"a repeat node must have a positive number of iterations if defined\");\n }\n\n // There is validation to carry out if a longest duration was defined.\n if (this.maximumIterations !== null) {\n // A repeat node must have a positive maximum iterations count if defined.\n if (this.maximumIterations! < 0) {\n throw new Error(\"a repeat node must have a positive maximum iterations count if defined\");\n }\n\n // A repeat node must not have an iteration count that exceeds the maximum iteration count.\n if (this.iterations! > this.maximumIterations!) {\n throw new Error(\n \"a repeat node must not have an iteration count that exceeds the maximum iteration count\"\n );\n }\n }\n },\n createNodeInstance(namedRootNodeProvider, visitedBranches) {\n return new Repeat(\n this.attributes,\n this.iterations!,\n this.maximumIterations!,\n this.children![0].createNodeInstance(namedRootNodeProvider, visitedBranches.slice())\n );\n }\n }),\n RETRY: (): IterableAstNode => ({\n type: \"retry\",\n attributes: [],\n iterations: null,\n maximumIterations: null,\n children: [],\n validate() {\n // A retry node must have a single node.\n if (this.children!.length !== 1) {\n throw new Error(\"a retry node must have a single child\");\n }\n\n // A retry node must have a positive number of iterations if defined.\n if (this.iterations !== null && this.iterations! < 0) {\n throw new Error(\"a retry node must have a positive number of iterations if defined\");\n }\n\n // There is validation to carry out if a longest duration was defined.\n if (this.maximumIterations !== null) {\n // A retry node must have a positive maximum iterations count if defined.\n if (this.maximumIterations! < 0) {\n throw new Error(\"a retry node must have a positive maximum iterations count if defined\");\n }\n\n // A retry node must not have an iteration count that exceeds the maximum iteration count.\n if (this.iterations! > this.maximumIterations!) {\n throw new Error(\n \"a retry node must not have an iteration count that exceeds the maximum iteration count\"\n );\n }\n }\n },\n createNodeInstance(namedRootNodeProvider, visitedBranches) {\n return new Retry(\n this.attributes,\n this.iterations!,\n this.maximumIterations!,\n this.children![0].createNodeInstance(namedRootNodeProvider, visitedBranches.slice())\n );\n }\n }),\n FLIP: (): DecoratorAstNode => ({\n type: \"flip\",\n attributes: [],\n children: [],\n validate() {\n // A flip node must have a single node.\n if (this.children!.length !== 1) {\n throw new Error(\"a flip node must have a single child\");\n }\n },\n createNodeInstance(namedRootNodeProvider, visitedBranches) {\n return new Flip(\n this.attributes,\n this.children![0].createNodeInstance(namedRootNodeProvider, visitedBranches.slice())\n );\n }\n }),\n SUCCEED: (): DecoratorAstNode => ({\n type: \"succeed\",\n attributes: [],\n children: [],\n validate() {\n // A succeed node must have a single node.\n if (this.children!.length !== 1) {\n throw new Error(\"a succeed node must have a single child\");\n }\n },\n createNodeInstance(namedRootNodeProvider, visitedBranches) {\n return new Succeed(\n this.attributes,\n this.children![0].createNodeInstance(namedRootNodeProvider, visitedBranches.slice())\n );\n }\n }),\n FAIL: (): DecoratorAstNode => ({\n type: \"fail\",\n attributes: [],\n children: [],\n validate() {\n // A fail node must have a single node.\n if (this.children!.length !== 1) {\n throw new Error(\"a fail node must have a single child\");\n }\n },\n createNodeInstance(namedRootNodeProvider, visitedBranches) {\n return new Fail(\n this.attributes,\n this.children![0].createNodeInstance(namedRootNodeProvider, visitedBranches.slice())\n );\n }\n }),\n WAIT: (): WaitAstNode => ({\n type: \"wait\",\n attributes: [],\n duration: null,\n longestDuration: null,\n validate() {\n // A wait node must have a positive duration.\n if (this.duration! < 0) {\n throw new Error(\"a wait node must have a positive duration\");\n }\n\n // There is validation to carry out if a longest duration was defined.\n if (this.longestDuration) {\n // A wait node must have a positive longest duration.\n if (this.longestDuration < 0) {\n throw new Error(\"a wait node must have a positive longest duration if one is defined\");\n }\n\n // A wait node must not have a duration that exceeds the longest duration.\n if (this.duration! > this.longestDuration) {\n throw new Error(\"a wait node must not have a shortest duration that exceeds the longest duration\");\n }\n }\n },\n createNodeInstance() {\n return new Wait(this.attributes, this.duration!, this.longestDuration!);\n }\n }),\n ACTION: (): ActionAstNode => ({\n type: \"action\",\n attributes: [],\n actionName: \"\",\n actionArguments: [],\n validate() {},\n createNodeInstance() {\n return new Action(this.attributes, this.actionName!, this.actionArguments!);\n }\n }),\n CONDITION: (): ConditionAstNode => ({\n type: \"condition\",\n attributes: [],\n conditionName: \"\",\n conditionArguments: [],\n validate() {},\n createNodeInstance() {\n return new Condition(this.attributes, this.conditionName!, this.conditionArguments!);\n }\n })\n};\n\ntype OtherAstNodes = AstNode[];\n\n/**\n * Create an array of root AST nodes based on the given definition.\n * @param definition The definition to parse the AST nodes from.\n * @returns The base definition AST nodes.\n */\nexport default function buildRootASTNodes(definition: string): RootAstNode[] {\n // Swap out any node/attribute argument string literals with a placeholder and get a mapping of placeholders to original values as well as the processed definition.\n const { placeholders, processedDefinition } = substituteStringLiterals(definition);\n\n // Convert the processed definition (with substituted string literals) into an array of raw tokens.\n const tokens = parseTokensFromDefinition(processedDefinition);\n\n // There must be at least 3 tokens for the tree definition to be valid. 'ROOT', '{' and '}'.\n if (tokens.length < 3) {\n throw new Error(\"invalid token count\");\n }\n\n // We should have a matching number of '{' and '}' tokens. If not, then there are scopes that have not been properly closed.\n if (tokens.filter((token) => token === \"{\").length !== tokens.filter((token) => token === \"}\").length) {\n throw new Error(\"scope character mismatch\");\n }\n\n // Create a stack of node children arrays, starting with a definition scope.\n const stack: [RootAstNode[], ...OtherAstNodes[]] = [[]];\n const rootScope = stack[0];\n\n // We should keep processing the raw tokens until we run out of them.\n while (tokens.length) {\n // Grab the next token.\n const token = tokens.shift();\n\n const currentScope = stack[stack.length - 1] as OtherAstNodes;\n\n // How we create the next AST token depends on the current raw token value.\n switch (token!.toUpperCase()) {\n case \"ROOT\": {\n // Create a ROOT AST node.\n const node = ASTNodeFactories.ROOT();\n\n // Push the ROOT node into the current scope.\n rootScope.push(node);\n\n // We may have a root node name defined as an argument.\n if (tokens[0] === \"[\") {\n const rootArguments = getArguments(tokens, placeholders);\n\n // We should have only a single argument that is not an empty string for a root node, which is the root name identifier.\n if (rootArguments.length === 1 && rootArguments[0].type === \"identifier\") {\n // The root name will be the first and only node argument.\n node.name = rootArguments[0].value as string;\n } else {\n throw new Error(\"expected single root name argument\");\n }\n }\n\n // Try to pick any attributes off of the token stack.\n node.attributes = getAttributes(tokens, placeholders);\n\n popAndCheck(tokens, \"{\");\n\n // The new scope is that of the new ROOT nodes children.\n stack.push(node.children!);\n break;\n }\n\n case \"BRANCH\": {\n // Create a BRANCH AST node.\n const node = ASTNodeFactories.BRANCH();\n\n // Push the BRANCH node into the current scope.\n currentScope.push(node);\n\n // We must have arguments defined, as we require a branch name argument.\n if (tokens[0] !== \"[\") {\n throw new Error(\"expected single branch name argument\");\n }\n\n // The branch name will be defined as a node argument.\n const branchArguments = getArguments(tokens, placeholders);\n\n // We should have only a single identifer argument for a branch node, which is the branch name.\n if (branchArguments.length === 1 && branchArguments[0].type === \"identifier\") {\n // The branch name will be the first and only node argument.\n node.branchName = branchArguments[0].value as string;\n } else {\n throw new Error(\"expected single branch name argument\");\n }\n break;\n }\n\n case \"SELECTOR\": {\n // Create a SELECTOR AST node.\n const node = ASTNodeFactories.SELECTOR();\n\n // Push the SELECTOR node into the current scope.\n currentScope.push(node);\n\n // Try to pick any attributes off of the token stack.\n node.attributes = getAttributes(tokens, placeholders);\n\n popAndCheck(tokens, \"{\");\n\n // The new scope is that of the new SELECTOR nodes children.\n stack.push(node.children!);\n break;\n }\n\n case \"SEQUENCE\": {\n // Create a SEQUENCE AST node.\n const node = ASTNodeFactories.SEQUENCE();\n\n // Push the SEQUENCE node into the current scope.\n currentScope.push(node);\n\n // Try to pick any attributes off of the token stack.\n node.attributes = getAttributes(tokens, placeholders);\n\n popAndCheck(tokens, \"{\");\n\n // The new scope is that of the new SEQUENCE nodes children.\n stack.push(node.children!);\n break;\n }\n\n case \"PARALLEL\": {\n // Create a PARALLEL AST node.\n const node = ASTNodeFactories.PARALLEL();\n\n // Push the PARALLEL node into the current scope.\n currentScope.push(node);\n\n // Try to pick any attributes off of the token stack.\n node.attributes = getAttributes(tokens, placeholders);\n\n popAndCheck(tokens, \"{\");\n\n // The new scope is that of the new PARALLEL nodes children.\n stack.push(node.children!);\n break;\n }\n\n case \"LOTTO\": {\n // Create a LOTTO AST node.\n const node = ASTNodeFactories.LOTTO();\n\n // Push the LOTTO node into the current scope.\n currentScope.push(node);\n\n // If the next token is a '[' character then some ticket counts have been defined as arguments.\n if (tokens[0] === \"[\") {\n // Get the ticket count arguments, each argument must be a number.\n node.tickets = getArguments(\n tokens,\n placeholders,\n (arg) => arg.type === \"number\" && !!arg.isInteger,\n \"lotto node ticket counts must be integer values\"\n ).map((argument) => argument.value as number);\n }\n\n // Try to pick any attributes off of the token stack.\n node.attributes = getAttributes(tokens, placeholders);\n\n popAndCheck(tokens, \"{\");\n\n // The new scope is that of the new LOTTO nodes children.\n stack.push(node.children!);\n break;\n }\n\n case \"CONDITION\": {\n // Create a CONDITION AST node.\n const node = ASTNodeFactories.CONDITION();\n\n // Push the CONDITION node into the current scope.\n currentScope.push(node);\n\n // We must have arguments defined, as we require a condition function name argument.\n if (tokens[0] !== \"[\") {\n throw new Error(\"expected condition name identifier argument\");\n }\n\n // Grab the condition node arguments.\n const conditionArguments = getArguments(tokens, placeholders);\n\n // We should have at least a single identifier argument for a condition node, which is the condition function name.\n if (conditionArguments.length && conditionArguments[0].type === \"identifier\") {\n // The condition function name will be the first node argument.\n node.conditionName = conditionArguments.shift()!.value as string;\n } else {\n throw new Error(\"expected condition name identifier argument\");\n }\n\n // Only the first argument should have been an identifier, all following arguments must be string, number, boolean or null.\n conditionArguments\n .filter((arg) => arg.type === \"identifier\")\n .forEach((arg) => {\n throw new Error(\n \"invalid condition node argument value '\" +\n arg.value +\n \"', must be string, number, boolean or null\"\n );\n });\n\n // Any node arguments that follow the condition name identifier will be treated as condition function arguments.\n node.conditionArguments = conditionArguments;\n\n // Try to pick any attributes off of the token stack.\n node.attributes = getAttributes(tokens, placeholders);\n break;\n }\n\n case \"FLIP\": {\n // Create a FLIP AST node.\n const node = ASTNodeFactories.FLIP();\n\n // Push the Flip node into the current scope.\n currentScope.push(node);\n\n // Try to pick any attributes off of the token stack.\n node.attributes = getAttributes(tokens, placeholders);\n\n popAndCheck(tokens, \"{\");\n\n // The new scope is that of the new FLIP nodes children.\n stack.push(node.children!);\n break;\n }\n\n case \"SUCCEED\": {\n // Create a SUCCEED AST node.\n const node = ASTNodeFactories.SUCCEED();\n\n // Push the Succeed node into the current scope.\n currentScope.push(node);\n\n // Try to pick any attributes off of the token stack.\n node.attributes = getAttributes(tokens, placeholders);\n\n popAndCheck(tokens, \"{\");\n\n // The new scope is that of the new Succeed nodes children.\n stack.push(node.children!);\n break;\n }\n\n case \"FAIL\": {\n // Create a FAIL AST node.\n const node = ASTNodeFactories.FAIL();\n\n // Push the Fail node into the current scope.\n currentScope.push(node);\n\n // Try to pick any attributes off of the token stack.\n node.attributes = getAttributes(tokens, placeholders);\n\n popAndCheck(tokens, \"{\");\n\n // The new scope is that of the new Fail nodes children.\n stack.push(node.children!);\n break;\n }\n\n case \"WAIT\": {\n // Create a WAIT AST node.\n const node = ASTNodeFactories.WAIT();\n\n // Push the WAIT node into the current scope.\n currentScope.push(node);\n\n // Get the duration and potential longest duration of the wait.\n const durations = getArguments(\n tokens,\n placeholders,\n (arg) => arg.type === \"number\" && !!arg.isInteger,\n \"wait node durations must be integer values\"\n ).map((argument) => argument.value);\n\n // We should have got one or two durations.\n if (durations.length === 1) {\n // A static duration was defined.\n node.duration = durations[0] as number;\n } else if (durations.length === 2) {\n // A shortest and longest duration was defined.\n node.duration = durations[0] as number;\n node.longestDuration = durations[1] as number;\n } else {\n // An incorrect number of durations was defined.\n throw new Error(\"invalid number of wait node duration arguments defined\");\n }\n\n // Try to pick any attributes off of the token stack.\n node.attributes = getAttributes(tokens, placeholders);\n break;\n }\n\n case \"REPEAT\": {\n // Create a REPEAT AST node.\n const node = ASTNodeFactories.REPEAT();\n\n // Push the REPEAT node into the current scope.\n currentScope.push(node);\n\n // Check for iteration counts ([])\n if (tokens[0] === \"[\") {\n // An iteration count has been defined. Get the iteration and potential maximum iteration of the wait.\n const iterationArguments = getArguments(\n tokens,\n placeholders,\n (arg) => arg.type === \"number\" && !!arg.isInteger,\n \"repeat node iteration counts must be integer values\"\n ).map((argument) => argument.value);\n\n // We should have got one or two iteration counts.\n if (iterationArguments.length === 1) {\n // A static iteration count was defined.\n node.iterations = iterationArguments[0] as number;\n } else if (iterationArguments.length === 2) {\n // A minimum and maximum iteration count was defined.\n node.iterations = iterationArguments[0] as number;\n node.maximumIterations = iterationArguments[1] as number;\n } else {\n // An incorrect number of iteration counts was defined.\n throw new Error(\"invalid number of repeat node iteration count arguments defined\");\n }\n }\n\n // Try to pick any attributes off of the token stack.\n node.attributes = getAttributes(tokens, placeholders);\n\n popAndCheck(tokens, \"{\");\n\n // The new scope is that of the new REPEAT nodes children.\n stack.push(node.children!);\n break;\n }\n\n case \"RETRY\": {\n // Create a RETRY AST node.\n const node = ASTNodeFactories.RETRY();\n\n // Push the RETRY node into the current scope.\n currentScope.push(node);\n\n // Check for iteration counts ([])\n if (tokens[0] === \"[\") {\n // An iteration count has been defined. Get the iteration and potential maximum iteration of the wait.\n const iterationArguments = getArguments(\n tokens,\n placeholders,\n (arg) => arg.type === \"number\" && !!arg.isInteger,\n \"retry node iteration counts must be integer values\"\n ).map((argument) => argument.value);\n\n // We should have got one or two iteration counts.\n if (iterationArguments.length === 1) {\n // A static iteration count was defined.\n node.iterations = iterationArguments[0] as number;\n } else if (iterationArguments.length === 2) {\n // A minimum and maximum iteration count was defined.\n node.iterations = iterationArguments[0] as number;\n node.maximumIterations = iterationArguments[1] as number;\n } else {\n // An incorrect number of iteration counts was defined.\n throw new Error(\"invalid number of retry node iteration count arguments defined\");\n }\n }\n\n // Try to pick any attributes off of the token stack.\n node.attributes = getAttributes(tokens, placeholders);\n\n popAndCheck(tokens, \"{\");\n\n // The new scope is that of the new RETRY nodes children.\n stack.push(node.children!);\n break;\n }\n\n case \"ACTION\": {\n // Create a ACTION AST node.\n const node = ASTNodeFactories.ACTION();\n\n // Push the ACTION node into the current scope.\n currentScope.push(node);\n\n // We must have arguments defined, as we require an action name argument.\n if (tokens[0] !== \"[\") {\n throw new Error(\"expected action name identifier argument\");\n }\n\n // The action name will be defined as a node argument.\n const actionArguments = getArguments(tokens, placeholders);\n\n // We should have at least one identifer argument for an action node, which is the action name.\n if (actionArguments.length && actionArguments[0].type === \"identifier\") {\n // The action name will be the first and only node argument.\n node.actionName = actionArguments.shift()!.value as string;\n } else {\n throw new Error(\"expected action name identifier argument\");\n }\n\n // Only the first argument should have been an identifier, all following arguments must be string, number, boolean or null.\n actionArguments\n .filter((arg) => arg.type === \"identifier\")\n .forEach((arg) => {\n throw new Error(\n \"invalid action node argument value '\" +\n arg.value +\n \"', must be string, number, boolean or null\"\n );\n });\n\n // Any node arguments that follow the action name identifier will be treated as action function arguments.\n node.actionArguments = actionArguments;\n\n // Try to pick any attributes off of the token stack.\n node.attributes = getAttributes(tokens, placeholders);\n break;\n }\n\n case \"}\": {\n // The '}' character closes the current scope.\n stack.pop();\n break;\n }\n\n default: {\n throw new Error(\"unexpected token: \" + token);\n }\n }\n }\n\n // A function to recursively validate each of the nodes in the AST.\n const validateASTNode = (node: Validatable, depth: number): void => {\n // Validate the node.\n node.validate(depth);\n\n // Validate each child of the node.\n (node.children || []).forEach((child) => validateASTNode(child, depth + 1));\n };\n\n // Start node validation from the definition root.\n validateASTNode(\n {\n children: stack[0] as RootAstNode[],\n validate(this: { children: RootAstNode[] }) {\n // We must have at least one node defined as the definition scope, which should be a root node.\n if (this.children.length === 0) {\n throw new Error(\"expected root node to have been defined\");\n }\n\n // Each node at the base of the definition scope MUST be a root node.\n for (const definitionLevelNode of this.children) {\n if (definitionLevelNode.type !== \"root\") {\n throw new Error(\"expected root node at base of definition\");\n }\n }\n\n // Exactly one root node must not have a name defined. This will be the main root, others will have to be referenced via branch nodes.\n if (this.children.filter((definitionLevelNode) => definitionLevelNode.name === null).length !== 1) {\n throw new Error(\"expected single unnamed root node at base of definition to act as main root\");\n }\n\n // No two named root nodes can have matching names.\n const rootNodeNames: string[] = [];\n for (const definitionLevelNode of this.children) {\n if (rootNodeNames.indexOf(definitionLevelNode.name!) !== -1) {\n throw new Error(`multiple root nodes found with duplicate name '${definitionLevelNode.name}'`);\n } else {\n rootNodeNames.push(definitionLevelNode.name!);\n }\n }\n }\n },\n 0\n );\n\n // Return the root AST nodes.\n return stack[0];\n}\n\n/**\n * Pop the next raw token off of the stack and throw an error if it wasn't the expected one.\n * @param tokens The array of remaining tokens.\n * @param expected An optional string or array or items, one of which must match the next popped token.\n * @returns The popped token.\n */\nfunction popAndCheck(tokens: string[], expected: string | string[]) {\n // Get and remove the next token.\n const popped = tokens.shift();\n\n // We were expecting another token.\n if (popped === undefined) {\n throw new Error(\"unexpected end of definition\");\n }\n\n // Do we have an expected token/tokens array?\n if (expected !== undefined) {\n // Check whether the popped token matches at least one of our expected items.\n var tokenMatchesExpectation = ([] as string[])\n .concat(expected)\n .some((item) => popped.toUpperCase() === item.toUpperCase());\n\n // Throw an error if the popped token didn't match any of our expected items.\n if (!tokenMatchesExpectation) {\n const expectationString = ([] as string[])\n .concat(expected)\n .map((item) => \"'\" + item + \"'\")\n .join(\" or \");\n throw new Error(\"unexpected token found. Expected \" + expectationString + \" but got '\" + popped + \"'\");\n }\n }\n\n // Return the popped token.\n return popped;\n}\n\ntype Placeholders = { [key: string]: string };\n\n/**\n * Pull an argument definition list off of the token stack.\n * @param tokens The array of remaining tokens.\n * @param stringArgumentPlaceholders The mapping of string literal node argument placeholders to original values.\n * @param argumentValidator The argument validator function.\n * @param validationFailedMessage The exception message to throw if argument validation fails.\n * @returns The argument definition list.\n */\nfunction getArguments(\n tokens: string[],\n stringArgumentPlaceholders: Placeholders,\n argumentValidator?: (arg: AnyArgument) => boolean,\n validationFailedMessage?: string\n) {\n // Any lists of arguments will always be wrapped in '[]' for node arguments or '()' for attribute arguments.\n // We are looking for a '[' or '(' opener that wraps the argument tokens and the relevant closer.\n const closer = popAndCheck(tokens, [\"[\", \"(\"]) === \"[\" ? \"]\" : \")\";\n\n const argumentListTokens: string[] = [];\n const argumentList: AnyArgument[] = [];\n\n // Grab all tokens between the '[' and ']' or '(' and ')'.\n while (tokens.length && tokens[0] !== closer) {\n // The next token is part of our arguments list.\n argumentListTokens.push(tokens.shift()!);\n }\n\n // Validate the order of the argument tokens. Each token must either be a ',' or a single argument that satisfies the validator.\n argumentListTokens.forEach((token, index) => {\n // Get whether this token should be an actual argument.\n const shouldBeArgumentToken = !(index & 1);\n\n // If the current token should be an actual argument then validate it,otherwise it should be a ',' token.\n if (shouldBeArgumentToken) {\n // Get the argument definition.\n const argumentDefinition = getArgumentDefinition(token!, stringArgumentPlaceholders);\n\n // Try to validate the argument.\n if (argumentValidator && !argumentValidator(argumentDefinition)) {\n throw new Error(validationFailedMessage);\n }\n\n // This is a valid argument!\n argumentList.push(argumentDefinition);\n } else {\n // The current token should be a ',' token.\n if (token !== \",\") {\n throw new Error(`invalid argument list, expected ',' or ']' but got '${token}'`);\n }\n }\n });\n\n // The arguments list should terminate with a ']' or ')' token, depending on the opener.\n popAndCheck(tokens, closer);\n\n // Return the argument list.\n return argumentList;\n}\n\n/**\n * Gets an argument value definition.\n * @param token The argument token.\n * @param stringArgumentPlaceholders The mapping of string literal node argument placeholders to original values.\n * @returns An argument value definition.\n */\nfunction getArgumentDefinition(token: string, stringArgumentPlaceholders: Placeholders): AnyArgument {\n // Check whether the token represents a null value.\n if (token === \"null\") {\n return {\n value: null,\n type: \"null\"\n } as NullArgument;\n }\n\n // Check whether the token represents a boolean value.\n if (token === \"true\" || token === \"false\") {\n return {\n value: token === \"true\",\n type: \"boolean\"\n } as BooleanArgument;\n }\n\n // Check whether the token represents a number value.\n // TODO: Relies on broken isNaN - see MDN.\n // if (!Number.isNaN(token)) {\n if (!isNaN(token as any)) {\n return {\n value: parseFloat(token),\n isInteger: parseFloat(token) === parseInt(token, 10),\n type: \"number\"\n } as NumberArgument;\n }\n\n // Check whether the token is a placeholder (e.g. @@0@@) representing a string literal.\n if (token.match(/^@@\\d+@@$/g)) {\n return {\n value: stringArgumentPlaceholders[token].replace('\\\\\"', '\"'),\n type: \"string\"\n } as StringPlaceholderArgument;\n }\n\n // The only remaining option is that the argument value is an identifier.\n return {\n value: token,\n type: \"identifier\"\n } as IdentifierArgument;\n}\n\n/**\n * Pull any attributes off of the token stack.\n * @param tokens The array of remaining tokens.\n * @param stringArgumentPlaceholders The mapping of string literal node argument placeholders to original values.\n * @returns An array of attributes defined by any directly following tokens.\n */\nfunction getAttributes(tokens: string[], stringArgumentPlaceholders: Placeholders) {\n // Create an array to hold any attributes found.\n const attributes: Attribute[] = [];\n\n // Keep track of names of attribute that we have found on the token stack, as we cannot have duplicates.\n const attributesFound: string[] = [];\n\n // Try to get the attribute factory for the next token.\n let attributeFactory = AttributeFactories[(tokens[0] || \"\").toUpperCase()];\n\n // Pull attribute tokens off of the tokens stack until we have no more.\n while (attributeFactory) {\n // Check to make sure that we have not already created a attribute of this type for this node.\n if (attributesFound.indexOf(tokens[0].toUpperCase()) !== -1) {\n throw new Error(`duplicate attribute '${tokens[0].toUpperCase()}' found for node`);\n }\n\n // Add the current attribute type to our array of found attributes.\n attributesFound.push(tokens.shift()!.toUpperCase());\n\n // Grab any attribute arguments.\n const attributeArguments = getArguments(tokens, stringArgumentPlaceholders);\n\n // The first attribute argument has to be an identifer, this will reference an agent function.\n if (attributeArguments.length === 0 || attributeArguments[0].type !== \"identifier\") {\n throw new Error(\"expected agent function name identifier argument for attribute\");\n }\n\n // Grab the first attribute which is an identifier that will reference an agent function.\n const attributeFunctionName = attributeArguments.shift()! as IdentifierArgument;\n\n // Any remaining attribute arguments must have a type of string, number, boolean or null.\n attributeArguments\n .filter((arg) => arg.type === \"identifier\")\n .forEach((arg) => {\n throw new Error(\n \"invalid attribute argument value '\" + arg.value + \"', must be string, number, boolean or null\"\n );\n });\n\n // Create the attribute and add it to the array of attributes found.\n attributes.push(attributeFactory(attributeFunctionName.value, attributeArguments));\n\n // Try to get the next attribute name token, as there could be multiple.\n attributeFactory = AttributeFactories[(tokens[0] || \"\").toUpperCase()];\n }\n\n return attributes;\n}\n\n/**\n * Swaps out any node/attribute argument string literals with placeholders.\n * @param definition The definition.\n * @returns An object containing a mapping of placeholders to original string values as well as the processed definition string.\n */\nfunction substituteStringLiterals(definition: string): {\n placeholders: { [key: string]: string };\n processedDefinition: string;\n} {\n // Create an object to hold the mapping of placeholders to original string values.\n const placeholders: Placeholders = {};\n\n // Replace any string literals wrapped with double quotes in our definition with placeholders to be processed later.\n const processedDefinition = definition.replace(/\\\"(\\\\.|[^\"\\\\])*\\\"/g, (match) => {\n var strippedMatch = match.substring(1, match.length - 1);\n var placeholder = Object.keys(placeholders).find((key) => placeholders[key] === strippedMatch);\n\n // If we have no existing string literal match then create a new placeholder.\n if (!placeholder) {\n placeholder = `@@${Object.keys(placeholders).length}@@`;\n placeholders[placeholder] = strippedMatch;\n }\n\n return placeholder;\n });\n\n return { placeholders, processedDefinition };\n}\n\n/**\n * Parse the tree definition into an array of raw tokens.\n * @param definition The definition.\n * @returns An array of tokens parsed from the definition.\n */\nfunction parseTokensFromDefinition(definition: string): string[] {\n // Add some space around various important characters so that they can be plucked out easier as individual tokens.\n definition = definition.replace(/\\(/g, \" ( \");\n definition = definition.replace(/\\)/g, \" ) \");\n definition = definition.replace(/\\{/g, \" { \");\n definition = definition.replace(/\\}/g, \" } \");\n definition = definition.replace(/\\]/g, \" ] \");\n definition = definition.replace(/\\[/g, \" [ \");\n definition = definition.replace(/\\,/g, \" , \");\n\n // Split the definition into raw token form and return it.\n return definition.replace(/\\s+/g, \" \").trim().split(\" \");\n}\n", "/**\r\n * A type defining the arguments that can be passed to an agent function.\r\n */\r\nexport type AgentFunctionArguments = (string | number | boolean | null | undefined)[];\r\n\r\n/**\r\n * A guard attribute for a node.\r\n */\r\nexport type GuardAttributeDefinition = {\r\n call: string;\r\n args?: AgentFunctionArguments;\r\n}\r\n\r\n/**\r\n * A callback attribute for a node.\r\n */\r\nexport type CallbackAttributeDefinition = {\r\n call: string;\r\n args?: AgentFunctionArguments;\r\n}\r\n\r\n/**\r\n * A type defining a general node definition.\r\n */\r\nexport type NodeDefinition = {\r\n type: string;\r\n while?: GuardAttributeDefinition;\r\n until?: GuardAttributeDefinition;\r\n entry?: CallbackAttributeDefinition;\r\n exit?: CallbackAttributeDefinition;\r\n step?: CallbackAttributeDefinition;\r\n}\r\n\r\n/**\r\n * A composite node that can contain any number of child nodes.\r\n */\r\nexport type CompositeDefinition = NodeDefinition & {\r\n children: AnyChildNode[];\r\n}\r\n\r\n/**\r\n * A decorator node, a composite with only a single child node.\r\n */\r\nexport type DecoratorDefinition = NodeDefinition & {\r\n child: AnyChildNode;\r\n}\r\n\r\n/**\r\n * A branch node.\r\n */\r\nexport type BranchDefinition = NodeDefinition & {\r\n type: \"branch\";\r\n ref: string;\r\n}\r\n\r\n/**\r\n * An action node.\r\n */\r\nexport type ActionDefinition = NodeDefinition & {\r\n type: \"action\";\r\n call: string;\r\n args?: AgentFunctionArguments;\r\n}\r\n\r\n/**\r\n * A condition node.\r\n */\r\nexport type ConditionDefinition = NodeDefinition & {\r\n type: \"condition\";\r\n call: string;\r\n args?: AgentFunctionArguments;\r\n}\r\n\r\n/**\r\n * A wait node.\r\n */\r\nexport type WaitDefinition = NodeDefinition & {\r\n type: \"wait\";\r\n duration: number | [number, number];\r\n}\r\n\r\n/**\r\n * A sequence node.\r\n */\r\nexport type SequenceDefinition = CompositeDefinition & {\r\n type: \"sequence\";\r\n}\r\n\r\n/**\r\n * A selector node.\r\n */\r\nexport type SelectorDefinition = CompositeDefinition & {\r\n type: \"selector\";\r\n}\r\n\r\n/**\r\n * A lotto node.\r\n */\r\nexport type LottoDefinition = CompositeDefinition & {\r\n type: \"lotto\";\r\n weights?: number[]\r\n}\r\n\r\n/**\r\n * A parallel node.\r\n */\r\nexport type ParallelDefinition = CompositeDefinition & {\r\n type: \"parallel\";\r\n}\r\n\r\n/**\r\n * A root node.\r\n */\r\nexport type RootDefinition = DecoratorDefinition & {\r\n type: \"root\";\r\n id?: string;\r\n}\r\n\r\n/**\r\n * A repeat node.\r\n */\r\nexport type RepeatDefinition = DecoratorDefinition & {\r\n type: \"repeat\";\r\n iterations?: number | [number, number];\r\n}\r\n\r\n/**\r\n * A retry node.\r\n */\r\nexport type RetryDefinition = DecoratorDefinition & {\r\n type: \"retry\";\r\n attempts?: number | [number, number];\r\n}\r\n\r\n/**\r\n * A flip node.\r\n */\r\nexport type FlipDefinition = DecoratorDefinition & {\r\n type: \"flip\";\r\n}\r\n\r\n/**\r\n * A succeed node.\r\n */\r\nexport type SucceedDefinition = DecoratorDefinition & {\r\n type: \"succeed\";\r\n}\r\n\r\n/**\r\n * A fail node.\r\n */\r\nexport type FailDefinition = DecoratorDefinition & {\r\n type: \"fail\";\r\n}\r\n\r\n/**\r\n * A type defining any node type.\r\n */\r\nexport type AnyNode = BranchDefinition | ActionDefinition | ConditionDefinition | WaitDefinition | SequenceDefinition |\r\n SelectorDefinition | LottoDefinition | ParallelDefinition | RootDefinition | RepeatDefinition | RetryDefinition | FlipDefinition | SucceedDefinition | FailDefinition;\r\n\r\n/**\r\n * A type defining any node type that can be a child of composite parent node.\r\n */\r\nexport type AnyChildNode = Exclude;\r\n\r\n/**\r\n * A type defining an object that holds a reference to substitued string literals parsed from the definition.\r\n */\r\ntype StringLiteralPlaceholders = { [key: string]: string };\r\n\r\nfunction isLeafNode(node: NodeDefinition): node is NodeDefinition {\r\n return [\"branch\", \"action\", \"condition\", \"wait\"].includes(node.type);\r\n}\r\n\r\nfunction isDecoratorNode(node: NodeDefinition): node is DecoratorDefinition {\r\n return [\"root\", \"repeat\", \"retry\", \"flip\", \"succeed\", \"fail\"].includes(node.type);\r\n}\r\n\r\nfunction isCompositeNode(node: NodeDefinition): node is CompositeDefinition {\r\n return [\"sequence\", \"selector\", \"lotto\", \"parallel\"].includes(node.type);\r\n}\r\n\r\n/**\r\n * Parse the tree definition string into a JSON definition.\r\n * @param definition The tree definition string.\r\n * @returns The root node JSON definitions.\r\n */\r\nexport function parseToJSON(definition: string): RootDefinition[] {\r\n // Swap out any node/attribute argument string literals with a placeholder and get a mapping of placeholders to original values as well as the processed definition.\r\n const { placeholders, processedDefinition } = substituteStringLiterals(definition);\r\n\r\n // Parse our definition definition string into an array of raw tokens.\r\n const tokens = parseTokensFromDefinition(definition);\r\n\r\n return convertTokensToJSONDefinition(tokens, placeholders, processedDefinition);\r\n}\r\n\r\n/**\r\n * Converts the specified tree definition tokens into a JSON definition.\r\n * @param tokens The tree definition tokens.\r\n * @param placeholders The substituted string literal placeholders.\r\n * @returns The root node JSON definitions.\r\n */\r\nexport function convertTokensToJSONDefinition(tokens: string[], placeholders: StringLiteralPlaceholders, processedDefinition: string): RootDefinition[] {\r\n // There must be at least 3 tokens for the tree definition to be valid. 'ROOT', '{' and '}'.\r\n if (tokens.length < 3) {\r\n throw new Error(\"invalid token count\");\r\n }\r\n\r\n // We should have a matching number of '{' and '}' tokens. If not, then there are scopes that have not been properly closed.\r\n if (tokens.filter((token) => token === \"{\").length !== tokens.filter((token) => token === \"}\").length) {\r\n throw new Error(\"scope character mismatch\");\r\n }\r\n\r\n // Create a stack of tree stack arrays where root nodes will always be at the root.\r\n const treeStacks: [Partial, ...Partial[]][] = [];\r\n\r\n // Create an array of all root node definitions that we create.\r\n const rootNodes: Partial[] = [];\r\n\r\n // ONLY COMPOSITE DEFINITIONS GET PUSHED ONTO A ROOT STACK.\r\n // When coming across a new node in the definition it must be:\r\n // - Set as the child of the top-most node in the root stack OR\r\n // - Added to the array of children of the top-most node in the root stack OR\r\n\r\n const pushRootNode = (rootNode: RootDefinition) => {\r\n // Add the root node definition to our array of all parsed root node definitions.\r\n rootNodes.push(rootNode);\r\n\r\n // Add the root node definition to the root of a new tree stack. \r\n treeStacks.push([rootNode]);\r\n }\r\n \r\n const pushNode = (node: AnyChildNode) => {\r\n // Get the current tree stack that we are populating.\r\n const currentTreeStack = treeStacks[treeStacks.length - 1];\r\n\r\n // TODO Handle cases where we may not have a current root stack.\r\n // This may happen if a root node is not the initially defined one?\r\n\r\n // Get the bottom-most node in the current tree stack.\r\n const bottomNode = currentTreeStack[currentTreeStack.length - 1] as AnyNode;\r\n\r\n // TODO Handle cases where we may not have a bottom-most node.\r\n // Also a potential issue with a badly defined tree.\r\n\r\n // If the bottom-most node in the current root stack is a composite or decorator\r\n // node then the current node should be added as a child of the bottom-most node.\r\n if (isCompositeNode(bottomNode)) {\r\n bottomNode.children = bottomNode.children || [];\r\n bottomNode.children.push(node);\r\n } else if (isDecoratorNode(bottomNode)) {\r\n bottomNode.child = node;\r\n }\r\n\r\n // If the node we are adding is also a composite or decorator node, then we should push it \r\n // onto the current tree stack, as subsequent nodes will be added as its child/children.\r\n if (!isLeafNode(node)) {\r\n currentTreeStack.push(node);\r\n }\r\n };\r\n\r\n const popNode = () => {\r\n // Get the current tree stack that we are populating.\r\n const currentTreeStack = treeStacks[treeStacks.length - 1];\r\n\r\n // Pop the top-most node in the current tree stack if there is one.\r\n if (currentTreeStack.length) {\r\n currentTreeStack.pop();\r\n }\r\n\r\n // We don't want any empty tree stacks in our stack of tree stacks. \r\n if (!currentTreeStack.length) {\r\n treeStacks.pop();\r\n }\r\n };\r\n\r\n // We should keep processing the raw tokens until we run out of them.\r\n while (tokens.length) {\r\n // Grab the next token.\r\n const token = tokens.shift();\r\n\r\n // How we create the next node depends on the current raw token value.\r\n switch (token!.toUpperCase()) {\r\n case \"ROOT\": {\r\n const node = {\r\n type: \"root\"\r\n } as RootDefinition;\r\n\r\n // TODO Grab 'id' if defined as a node argument.\r\n // TODO Grab attributes.\r\n\r\n // This is a decorator node, so we expect an opening '{'.\r\n popAndCheck(tokens, \"{\");\r\n\r\n // A root node will always be the base of a new root stack.\r\n pushRootNode(node);\r\n break;\r\n }\r\n\r\n case \"SEQUENCE\": {\r\n const node = {\r\n type: \"sequence\"\r\n } as SequenceDefinition;\r\n\r\n // TODO Grab attributes.\r\n\r\n // This is a composite node, so we expect an opening '{'.\r\n popAndCheck(tokens, \"{\");\r\n\r\n pushNode(node);\r\n break;\r\n }\r\n\r\n case \"ACTION\": {\r\n const node = {\r\n type: \"action\"\r\n } as ActionDefinition;\r\n\r\n // TODO Grab attributes.\r\n\r\n pushNode(node);\r\n break;\r\n }\r\n\r\n case \"}\": {\r\n // The '}' character closes the current scope.\r\n popNode();\r\n break;\r\n }\r\n\r\n default: {\r\n throw new Error(\"unexpected token: \" + token);\r\n }\r\n }\r\n }\r\n\r\n // TODO Remove!\r\n console.log(rootNodes);\r\n\r\n // TODO\r\n return rootNodes as RootDefinition[];\r\n}\r\n\r\n/**\r\n * Swaps out any node/attribute argument string literals with placeholders.\r\n * @param definition The definition.\r\n * @returns An object containing a mapping of placeholders to original string values as well as the processed definition string.\r\n */\r\nfunction substituteStringLiterals(definition: string): {\r\n placeholders: StringLiteralPlaceholders;\r\n processedDefinition: string;\r\n} {\r\n // Create an object to hold the mapping of placeholders to original string values.\r\n const placeholders: StringLiteralPlaceholders = {};\r\n\r\n // Replace any string literals wrapped with double quotes in our definition with placeholders to be processed later.\r\n const processedDefinition = definition.replace(/\\\"(\\\\.|[^\"\\\\])*\\\"/g, (match) => {\r\n var strippedMatch = match.substring(1, match.length - 1);\r\n var placeholder = Object.keys(placeholders).find((key) => placeholders[key] === strippedMatch);\r\n\r\n // If we have no existing string literal match then create a new placeholder.\r\n if (!placeholder) {\r\n placeholder = `@@${Object.keys(placeholders).length}@@`;\r\n placeholders[placeholder] = strippedMatch;\r\n }\r\n\r\n return placeholder;\r\n });\r\n\r\n return { placeholders, processedDefinition };\r\n}\r\n\r\n/**\r\n * Parse the tree definition into an array of raw tokens.\r\n * @param definition The definition.\r\n * @returns An array of tokens parsed from the definition.\r\n */\r\nfunction parseTokensFromDefinition(definition: string): string[] {\r\n // Add some space around various important characters so that they can be plucked out easier as individual tokens.\r\n definition = definition.replace(/\\(/g, \" ( \");\r\n definition = definition.replace(/\\)/g, \" ) \");\r\n definition = definition.replace(/\\{/g, \" { \");\r\n definition = definition.replace(/\\}/g, \" } \");\r\n definition = definition.replace(/\\]/g, \" ] \");\r\n definition = definition.replace(/\\[/g, \" [ \");\r\n definition = definition.replace(/\\,/g, \" , \");\r\n\r\n // Split the definition into raw token form and return it.\r\n return definition.replace(/\\s+/g, \" \").trim().split(\" \");\r\n}\r\n\r\n/**\r\n * Pop the next raw token off of the stack and throw an error if it wasn't the expected one.\r\n * @param tokens The array of remaining tokens.\r\n * @param expected An optional string or array or items, one of which must match the next popped token.\r\n * @returns The popped token.\r\n */\r\nfunction popAndCheck(tokens: string[], expected?: string | string[]): string {\r\n // Get and remove the next token.\r\n const popped = tokens.shift();\r\n\r\n // We were expecting another token.\r\n if (popped === undefined) {\r\n throw new Error(\"unexpected end of definition\");\r\n }\r\n\r\n // Do we have an expected token/tokens array?\r\n if (expected != undefined) {\r\n // Get an array of expected values, if the popped token matches any then we are all good.\r\n const expectedValues = (typeof expected === \"string\") ? [expected] : expected;\r\n\r\n // Check whether the popped token matches at least one of our expected items.\r\n var tokenMatchesExpectation = expectedValues.some((item) => popped.toUpperCase() === item.toUpperCase());\r\n\r\n // Throw an error if the popped token didn't match any of our expected items.\r\n if (!tokenMatchesExpectation) {\r\n const expectationString = expectedValues.map((item) => \"'\" + item + \"'\").join(\" or \");\r\n throw new Error(\"unexpected token found. Expected \" + expectationString + \" but got '\" + popped + \"'\");\r\n }\r\n }\r\n\r\n // Return the popped token.\r\n return popped;\r\n}", "import GuardPath, { GuardPathPart } from \"./attributes/guards/GuardPath\";\nimport buildRootASTNodes, { AnyArgument, RootAstNode } from \"./RootAstNodesBuilder\";\nimport State, { AnyState } from \"./State\";\nimport Lookup from \"./Lookup\";\nimport Node from \"./nodes/Node\";\nimport Root from \"./nodes/decorator/Root\";\nimport Composite from \"./nodes/composite/Composite\";\nimport Decorator from \"./nodes/decorator/Decorator\";\nimport { Agent, GlobalFunction } from \"./Agent\";\nimport { CallbackAttributeDetails } from \"./attributes/callbacks/Callback\";\nimport { GuardAttributeDetails } from \"./attributes/guards/Guard\";\nimport { BehaviourTreeOptions } from \"./BehaviourTreeOptions\";\nimport { parseToJSON } from \"./DSLParser\";\n\n// Purely for outside inspection of the tree.\nexport type FlattenedTreeNode = {\n id: string;\n type: string;\n caption: string;\n state: AnyState;\n guards: GuardAttributeDetails[];\n callbacks: CallbackAttributeDetails[];\n args: AnyArgument[];\n parentId: string | null;\n};\n\n/**\n * A representation of a behaviour tree.\n */\nexport class BehaviourTree {\n /**\n * The main root tree node.\n */\n public readonly rootNode: Root;\n\n /**\n * Creates a new instance of the BehaviourTree class.\n * @param definition The behaviour tree definition.\n * @param agent The agent instance that this behaviour tree is modelling behaviour for.\n * @param options The behaviour tree options object.\n */\n constructor(definition: string, private agent: Agent, private options: BehaviourTreeOptions = {}) {\n // The tree definition must be defined and a valid string.\n if (typeof definition !== \"string\") {\n throw new Error(\"the tree definition must be a string\");\n }\n\n // The agent must be defined and not null.\n if (typeof agent !== \"object\" || agent === null) {\n throw new Error(\"the agent must be defined and not null\");\n }\n\n // Parse the behaviour tree definition, create the populated tree of behaviour tree nodes, and get the root.\n this.rootNode = BehaviourTree.createRootNode(definition);\n }\n\n /**\n * Gets whether the tree is in the RUNNING state.\n * @returns true if the tree is in the RUNNING state, otherwise false.\n */\n isRunning() {\n return this.rootNode.getState() === State.RUNNING;\n }\n\n /**\n * Gets the current tree state of SUCCEEDED, FAILED, READY or RUNNING.\n * @returns The current tree state.\n */\n getState() {\n return this.rootNode.getState();\n }\n\n /**\n * Step the tree.\n * 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.\n * 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\n * 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.\n *\n * 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.\n */\n step() {\n // If the root node has already been stepped to completion then we need to reset it.\n if (this.rootNode.getState() === State.SUCCEEDED || this.rootNode.getState() === State.FAILED) {\n this.rootNode.reset();\n }\n\n try {\n this.rootNode.update(this.agent, this.options);\n } catch (exception) {\n throw new Error(`error stepping tree: ${(exception as Error).message}`);\n }\n }\n\n /**\n * Resets the tree from the root node outwards to each nested node, giving each a state of READY.\n */\n reset() {\n this.rootNode.reset();\n }\n\n /**\n * Gets the flattened details of every node in the tree.\n * @returns The flattened details of every node in the tree.\n */\n getFlattenedNodeDetails(): FlattenedTreeNode[] {\n // Create an empty flattened array of tree nodes.\n const flattenedTreeNodes: FlattenedTreeNode[] = [];\n\n /**\n * Helper function to process a node instance and push details into the flattened tree nodes array.\n * @param node The current node.\n * @param parentUid The UID of the node parent, or null if the node is the main root node.\n */\n const processNode = (node: Node, parentUid: string | null) => {\n // Get the guard and callback attribute details for this node.\n const guards = node\n .getAttributes()\n .filter((attribute) => attribute.isGuard())\n .map((attribute) => attribute.getDetails()) as GuardAttributeDetails[];\n const callbacks = node\n .getAttributes()\n .filter((attribute) => !attribute.isGuard())\n .map((attribute) => attribute.getDetails()) as CallbackAttributeDetails[];\n\n // Push the current node into the flattened nodes array.\n flattenedTreeNodes.push({\n id: node.getUid(),\n type: node.getType(),\n caption: node.getName(),\n state: node.getState(),\n guards,\n callbacks,\n args: node.getArguments(),\n parentId: parentUid\n });\n\n // Process each of the nodes children if it is not a leaf node.\n if (!node.isLeafNode()) {\n (node as Composite | Decorator)\n .getChildren()\n .forEach((child) => processNode(child, (node as Composite | Decorator).getUid()));\n }\n };\n\n // Convert the nested node structure into a flattened array of node details.\n processNode(this.rootNode, null);\n\n return flattenedTreeNodes;\n }\n\n /**\n * Registers the action/condition/guard/callback function or subtree with the given name.\n * @param name The name of the function or subtree to register.\n * @param value The function or subtree definition to register.\n */\n static register(name: string, value: GlobalFunction | string) {\n if (typeof value === \"function\") {\n // We are going to register a action/condition/guard/callback function.\n Lookup.setFunc(name, value);\n } else if (typeof value === \"string\") {\n // We are going to register a subtree.\n let rootASTNodes: RootAstNode[];\n\n try {\n // Try to create the behaviour tree AST based on the definition provided, this could fail if the definition is invalid.\n rootASTNodes = buildRootASTNodes(value);\n } catch (exception) {\n // There was an issue in trying to parse and build the tree definition.\n throw new Error(`error registering definition: ${(exception as Error).message}`);\n }\n\n // This function should only ever be called with a definition containing a single unnamed root node.\n if (rootASTNodes.length != 1 || rootASTNodes[0].name !== null) {\n throw new Error(\"error registering definition: expected a single unnamed root node\");\n }\n\n Lookup.setSubtree(name, rootASTNodes[0]);\n } else {\n throw new Error(\"unexpected value, expected string definition or function\");\n }\n }\n\n /**\n * Unregisters the registered action/condition/guard/callback function or subtree with the given name.\n * @param name The name of the registered action/condition/guard/callback function or subtree to unregister.\n */\n static unregister(name: string): void {\n Lookup.remove(name);\n }\n\n /**\n * Unregister all registered action/condition/guard/callback functions and subtrees.\n */\n static unregisterAll(): void {\n Lookup.empty();\n }\n\n /**\n * Parses a behaviour tree definition and creates a tree of behaviour tree nodes.\n * @param {string} definition The behaviour tree definition.\n * @returns The root behaviour tree node.\n */\n private static createRootNode(definition: string): Root {\n // TODO Remove!\n try {\n parseToJSON(definition);\n } catch (exception) {\n console.log(exception);\n }\n\n try {\n // Try to create the behaviour tree AST based on the definition provided, this could fail if the definition is invalid.\n const rootASTNodes = buildRootASTNodes(definition);\n\n // Create a symbol to use as the main root key in our root node mapping.\n const mainRootNodeKey = Symbol(\"__root__\");\n\n // Create a mapping of root node names to root AST tokens. The main root node will have a key of Symbol(\"__root__\").\n const rootNodeMap: { [key: string | symbol]: RootAstNode } = {};\n for (const rootASTNode of rootASTNodes) {\n rootNodeMap[rootASTNode.name === null ? mainRootNodeKey : rootASTNode.name!] = rootASTNode;\n }\n\n // Convert the AST to our actual tree and get the root node.\n const rootNode: Root = rootNodeMap[mainRootNodeKey].createNodeInstance(\n // Create a provider for named root nodes that are part of our definition or have been registered. Prioritising the former.\n (name: string): RootAstNode => (rootNodeMap[name] ? rootNodeMap[name] : Lookup.getSubtree(name)),\n []\n );\n\n // Set a guard path on every leaf of the tree to evaluate as part of its update.\n BehaviourTree.applyLeafNodeGuardPaths(rootNode);\n\n // Return the root node.\n return rootNode;\n } catch (exception) {\n // There was an issue in trying to parse and build the tree definition.\n throw new Error(`error parsing tree: ${(exception as Error).message}\\n${(exception as Error).stack}`);\n }\n }\n\n /**\n * Applies a guard path to every leaf of the tree to evaluate as part of each update.\n * @param rootNode The main root tree node.\n */\n private static applyLeafNodeGuardPaths(rootNode: Root) {\n const nodePaths: Node[][] = [];\n\n const findLeafNodes = (path: Node[], node: Node) => {\n // Add the current node to the path.\n path = path.concat(node);\n\n // Check whether the current node is a leaf node.\n if (node.isLeafNode()) {\n nodePaths.push(path);\n } else {\n (node as Composite | Decorator).getChildren().forEach((child) => findLeafNodes(path, child));\n }\n };\n\n // Find all leaf node paths, starting from the root.\n findLeafNodes([], rootNode);\n\n nodePaths.forEach((path) => {\n // Each node in the current path will have to be assigned a guard path, working from the root outwards.\n for (let depth = 0; depth < path.length; depth++) {\n // Get the node in the path at the current depth.\n const currentNode = path[depth];\n\n // The node may already have been assigned a guard path, if so just skip it.\n if (currentNode.hasGuardPath()) {\n continue;\n }\n\n // Create the guard path for the current node.\n const guardPath = new GuardPath(\n path\n .slice(0, depth + 1)\n .map((node) => ({ node, guards: node.getGuardAttributes() }))\n .filter((details) => details.guards.length > 0)\n );\n\n // Assign the guard path to the current node.\n currentNode.setGuardPath(guardPath);\n }\n });\n }\n}\n"], + "mappings": "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", + "names": ["Participant", "Lotto", "createLotto", "State", "createLotto", "substituteStringLiterals", "parseTokensFromDefinition", "popAndCheck"] } diff --git a/src/BehaviourTree.ts b/src/BehaviourTree.ts index cda86d7..bfd4840 100644 --- a/src/BehaviourTree.ts +++ b/src/BehaviourTree.ts @@ -10,6 +10,7 @@ import { Agent, GlobalFunction } from "./Agent"; import { CallbackAttributeDetails } from "./attributes/callbacks/Callback"; import { GuardAttributeDetails } from "./attributes/guards/Guard"; import { BehaviourTreeOptions } from "./BehaviourTreeOptions"; +import { parseToJSON } from "./DSLParser"; // Purely for outside inspection of the tree. export type FlattenedTreeNode = { @@ -200,6 +201,13 @@ export class BehaviourTree { * @returns The root behaviour tree node. */ private static createRootNode(definition: string): Root { + // TODO Remove! + try { + parseToJSON(definition); + } catch (exception) { + console.log(exception); + } + try { // Try to create the behaviour tree AST based on the definition provided, this could fail if the definition is invalid. const rootASTNodes = buildRootASTNodes(definition); diff --git a/src/DSLParser.ts b/src/DSLParser.ts index 44be4a5..4d81963 100644 --- a/src/DSLParser.ts +++ b/src/DSLParser.ts @@ -186,7 +186,7 @@ function isCompositeNode(node: NodeDefinition): node is CompositeDefinition { * @param definition The tree definition string. * @returns The root node JSON definitions. */ -export function parse(definition: string): RootDefinition[] { +export function parseToJSON(definition: string): RootDefinition[] { // Swap out any node/attribute argument string literals with a placeholder and get a mapping of placeholders to original values as well as the processed definition. const { placeholders, processedDefinition } = substituteStringLiterals(definition); @@ -291,6 +291,9 @@ export function convertTokensToJSONDefinition(tokens: string[], placeholders: St // TODO Grab 'id' if defined as a node argument. // TODO Grab attributes. + // This is a decorator node, so we expect an opening '{'. + popAndCheck(tokens, "{"); + // A root node will always be the base of a new root stack. pushRootNode(node); break; @@ -303,6 +306,9 @@ export function convertTokensToJSONDefinition(tokens: string[], placeholders: St // TODO Grab attributes. + // This is a composite node, so we expect an opening '{'. + popAndCheck(tokens, "{"); + pushNode(node); break; } @@ -330,8 +336,11 @@ export function convertTokensToJSONDefinition(tokens: string[], placeholders: St } } + // TODO Remove! + console.log(rootNodes); + // TODO - return []; + return rootNodes as RootDefinition[]; } /** From 4af85cee4f6988df4852d944a7b9985c5ec52d1e Mon Sep 17 00:00:00 2001 From: Nikolas Howard Date: Mon, 27 Feb 2023 17:34:24 +0000 Subject: [PATCH 06/48] Splitting out DSL parsing code --- dist/DSLParser.d.ts | 2 +- dist/behaviourTree.d.ts | 4 +- dist/bundle.js | 147 +++++++++++++++- dist/bundle.js.map | 8 +- dist/dsl/DSLDefinitionParser.d.ts | 163 ++++++++++++++++++ dist/dsl/DSLNodeArgumentParser.d.ts | 36 ++++ dist/dsl/DSLUtilities.d.ts | 7 + dist/index.js | 77 +++++---- dist/index.js.map | 8 +- src/BehaviourTree.ts | 10 +- .../DSLDefinitionParser.ts} | 122 ++++++------- src/dsl/DSLNodeArgumentParser.ts | 152 ++++++++++++++++ src/dsl/DSLUtilities.ts | 33 ++++ 13 files changed, 640 insertions(+), 129 deletions(-) create mode 100644 dist/dsl/DSLDefinitionParser.d.ts create mode 100644 dist/dsl/DSLNodeArgumentParser.d.ts create mode 100644 dist/dsl/DSLUtilities.d.ts rename src/{DSLParser.ts => dsl/DSLDefinitionParser.ts} (79%) create mode 100644 src/dsl/DSLNodeArgumentParser.ts create mode 100644 src/dsl/DSLUtilities.ts diff --git a/dist/DSLParser.d.ts b/dist/DSLParser.d.ts index ea0e67a..023bdfe 100644 --- a/dist/DSLParser.d.ts +++ b/dist/DSLParser.d.ts @@ -152,7 +152,7 @@ type StringLiteralPlaceholders = { * @param definition The tree definition string. * @returns The root node JSON definitions. */ -export declare function parse(definition: string): RootDefinition[]; +export declare function parseToJSON(definition: string): RootDefinition[]; /** * Converts the specified tree definition tokens into a JSON definition. * @param tokens The tree definition tokens. diff --git a/dist/behaviourTree.d.ts b/dist/behaviourTree.d.ts index 586452e..5b62d16 100644 --- a/dist/behaviourTree.d.ts +++ b/dist/behaviourTree.d.ts @@ -80,10 +80,10 @@ export declare class BehaviourTree { * @param {string} definition The behaviour tree definition. * @returns The root behaviour tree node. */ - private static createRootNode; + 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; + private static _applyLeafNodeGuardPaths; } diff --git a/dist/bundle.js b/dist/bundle.js index 01c25e1..392afa8 100644 --- a/dist/bundle.js +++ b/dist/bundle.js @@ -1673,6 +1673,140 @@ var mistreevous = (() => { return definition.replace(/\s+/g, " ").trim().split(" "); } + // src/dsl/DSLUtilities.ts + function popAndCheck2(tokens, expected) { + const popped = tokens.shift(); + if (popped === void 0) { + throw new Error("unexpected end of definition"); + } + if (expected != void 0) { + const expectedValues = typeof expected === "string" ? [expected] : expected; + var tokenMatchesExpectation = expectedValues.some((item) => popped.toUpperCase() === item.toUpperCase()); + if (!tokenMatchesExpectation) { + const expectationString = expectedValues.map((item) => "'" + item + "'").join(" or "); + throw new Error("unexpected token found. Expected " + expectationString + " but got '" + popped + "'"); + } + } + return popped; + } + + // src/dsl/DSLDefinitionParser.ts + function isLeafNode(node) { + return ["branch", "action", "condition", "wait"].includes(node.type); + } + function isDecoratorNode(node) { + return ["root", "repeat", "retry", "flip", "succeed", "fail"].includes(node.type); + } + function isCompositeNode(node) { + return ["sequence", "selector", "lotto", "parallel"].includes(node.type); + } + function parseToJSON(definition) { + const { placeholders, processedDefinition } = substituteStringLiterals2(definition); + const tokens = parseTokensFromDefinition2(definition); + return convertTokensToJSONDefinition(tokens, placeholders, processedDefinition); + } + function convertTokensToJSONDefinition(tokens, placeholders, processedDefinition) { + if (tokens.length < 3) { + throw new Error("invalid token count"); + } + if (tokens.filter((token) => token === "{").length !== tokens.filter((token) => token === "}").length) { + throw new Error("scope character mismatch"); + } + const treeStacks = []; + const rootNodes = []; + const pushRootNode = (rootNode) => { + rootNodes.push(rootNode); + treeStacks.push([rootNode]); + }; + const pushNode = (node) => { + const currentTreeStack = treeStacks[treeStacks.length - 1]; + const bottomNode = currentTreeStack[currentTreeStack.length - 1]; + if (isCompositeNode(bottomNode)) { + bottomNode.children = bottomNode.children || []; + bottomNode.children.push(node); + } else if (isDecoratorNode(bottomNode)) { + if (bottomNode.child) { + throw new Error("a decorator node must only have a single child node"); + } + bottomNode.child = node; + } + if (!isLeafNode(node)) { + currentTreeStack.push(node); + } + }; + const popNode = () => { + const currentTreeStack = treeStacks[treeStacks.length - 1]; + if (currentTreeStack.length) { + currentTreeStack.pop(); + } + if (!currentTreeStack.length) { + treeStacks.pop(); + } + }; + while (tokens.length) { + const token = tokens.shift(); + switch (token.toUpperCase()) { + case "ROOT": { + pushRootNode(createRootNode(tokens)); + break; + } + case "SEQUENCE": { + pushNode(createSequenceNode(tokens)); + break; + } + case "ACTION": { + pushNode(createActionNode(tokens)); + break; + } + case "}": { + popNode(); + break; + } + default: { + throw new Error("unexpected token: " + token); + } + } + } + return rootNodes; + } + function createRootNode(tokens) { + const node = { type: "root" }; + popAndCheck2(tokens, "{"); + return node; + } + function createSequenceNode(tokens) { + const node = { type: "sequence" }; + popAndCheck2(tokens, "{"); + return node; + } + function createActionNode(tokens) { + const node = { type: "action" }; + return node; + } + function substituteStringLiterals2(definition) { + const placeholders = {}; + const processedDefinition = definition.replace(/\"(\\.|[^"\\])*\"/g, (match) => { + var strippedMatch = match.substring(1, match.length - 1); + var placeholder = Object.keys(placeholders).find((key) => placeholders[key] === strippedMatch); + if (!placeholder) { + placeholder = `@@${Object.keys(placeholders).length}@@`; + placeholders[placeholder] = strippedMatch; + } + return placeholder; + }); + return { placeholders, processedDefinition }; + } + function parseTokensFromDefinition2(definition) { + definition = definition.replace(/\(/g, " ( "); + definition = definition.replace(/\)/g, " ) "); + definition = definition.replace(/\{/g, " { "); + definition = definition.replace(/\}/g, " } "); + definition = definition.replace(/\]/g, " ] "); + definition = definition.replace(/\[/g, " [ "); + definition = definition.replace(/\,/g, " , "); + return definition.replace(/\s+/g, " ").trim().split(" "); + } + // src/BehaviourTree.ts var BehaviourTree = class { constructor(definition, agent, options = {}) { @@ -1684,7 +1818,7 @@ var mistreevous = (() => { if (typeof agent !== "object" || agent === null) { throw new Error("the agent must be defined and not null"); } - this.rootNode = BehaviourTree.createRootNode(definition); + this.rootNode = BehaviourTree._createRootNode(definition); } rootNode; isRunning() { @@ -1752,7 +1886,12 @@ var mistreevous = (() => { static unregisterAll() { Lookup.empty(); } - static createRootNode(definition) { + static _createRootNode(definition) { + try { + parseToJSON(definition); + } catch (exception) { + console.log(exception); + } try { const rootASTNodes = buildRootASTNodes(definition); const mainRootNodeKey = Symbol("__root__"); @@ -1764,14 +1903,14 @@ var mistreevous = (() => { (name) => rootNodeMap[name] ? rootNodeMap[name] : Lookup.getSubtree(name), [] ); - BehaviourTree.applyLeafNodeGuardPaths(rootNode); + BehaviourTree._applyLeafNodeGuardPaths(rootNode); return rootNode; } catch (exception) { throw new Error(`error parsing tree: ${exception.message} ${exception.stack}`); } } - static applyLeafNodeGuardPaths(rootNode) { + static _applyLeafNodeGuardPaths(rootNode) { const nodePaths = []; const findLeafNodes = (path, node) => { path = path.concat(node); diff --git a/dist/bundle.js.map b/dist/bundle.js.map index 098b0e1..8509168 100644 --- a/dist/bundle.js.map +++ b/dist/bundle.js.map @@ -1,7 +1,7 @@ { "version": 3, - "sources": ["../node_modules/lotto-draw/dist/Participant.js", "../node_modules/lotto-draw/dist/Utilities.js", "../node_modules/lotto-draw/dist/Lotto.js", "../node_modules/lotto-draw/dist/createLotto.js", "../node_modules/lotto-draw/dist/index.js", "../src/index.ts", "../src/attributes/guards/GuardUnsatisifedException.ts", "../src/attributes/guards/GuardPath.ts", "../src/State.ts", "../src/nodes/Node.ts", "../src/nodes/leaf/Leaf.ts", "../src/Lookup.ts", "../src/nodes/leaf/Action.ts", "../src/nodes/leaf/Condition.ts", "../src/nodes/leaf/Wait.ts", "../src/nodes/decorator/Decorator.ts", "../src/nodes/decorator/Root.ts", "../src/nodes/decorator/Repeat.ts", "../src/nodes/decorator/Retry.ts", "../src/nodes/decorator/Flip.ts", "../src/nodes/decorator/Succeed.ts", "../src/nodes/decorator/Fail.ts", "../src/nodes/composite/Lotto.ts", "../src/nodes/composite/Composite.ts", "../src/nodes/composite/Selector.ts", "../src/nodes/composite/Sequence.ts", "../src/nodes/composite/Parallel.ts", "../src/attributes/Attribute.ts", "../src/attributes/guards/Guard.ts", "../src/attributes/guards/While.ts", "../src/attributes/guards/Until.ts", "../src/attributes/callbacks/Callback.ts", "../src/attributes/callbacks/Entry.ts", "../src/attributes/callbacks/Exit.ts", "../src/attributes/callbacks/Step.ts", "../src/RootAstNodesBuilder.ts", "../src/BehaviourTree.ts"], - "sourcesContent": ["\"use strict\";\r\nObject.defineProperty(exports, \"__esModule\", { value: true });\r\nexports.Participant = void 0;\r\n/**\r\n * A participant that holds a number of tickets.\r\n */\r\nvar Participant = /** @class */ (function () {\r\n /**\r\n * Creates an instance of the Participant class.\r\n * @param participant The actual participant.\r\n * @param tickets The number of tickets held by the participant.\r\n */\r\n function Participant(participant, tickets) {\r\n if (tickets === void 0) { tickets = 1; }\r\n this._participant = participant;\r\n this._tickets = tickets;\r\n }\r\n Object.defineProperty(Participant.prototype, \"participant\", {\r\n /** Gets the actual participant. */\r\n get: function () {\r\n return this._participant;\r\n },\r\n enumerable: false,\r\n configurable: true\r\n });\r\n Object.defineProperty(Participant.prototype, \"tickets\", {\r\n /** Gets or sets the number of tickets held by the participant. */\r\n get: function () {\r\n return this._tickets;\r\n },\r\n set: function (value) {\r\n this._tickets = value;\r\n },\r\n enumerable: false,\r\n configurable: true\r\n });\r\n return Participant;\r\n}());\r\nexports.Participant = Participant;\r\n", "\"use strict\";\r\nObject.defineProperty(exports, \"__esModule\", { value: true });\r\nexports.isNaturalNumber = exports.isNullOrUndefined = void 0;\r\n/**\r\n * Gets whether the value provided is null or undefined.\r\n * @param value The value to check.\r\n * @returns Whether the value provided is null or undefined.\r\n */\r\nfunction isNullOrUndefined(value) {\r\n return value === null || value === undefined;\r\n}\r\nexports.isNullOrUndefined = isNullOrUndefined;\r\n/**\r\n * Gets whether the value provided is a natural number.\r\n * @param value The value to check.\r\n * @returns Whether the value provided is a natural number.\r\n */\r\nfunction isNaturalNumber(value) {\r\n return typeof value === \"number\" && value >= 1 && Math.floor(value) === value;\r\n}\r\nexports.isNaturalNumber = isNaturalNumber;\r\n", "\"use strict\";\r\nObject.defineProperty(exports, \"__esModule\", { value: true });\r\nexports.Lotto = void 0;\r\nvar Participant_1 = require(\"./Participant\");\r\nvar Utilities_1 = require(\"./Utilities\");\r\n/**\r\n * Represents a lotto consisting of a number of pickable ticket-holding participants.\r\n */\r\nvar Lotto = /** @class */ (function () {\r\n /**\r\n * Creates a new instance of Lotto.\r\n * @param customRandom The custom RNG to use in place of Math.random().\r\n */\r\n function Lotto(customRandom) {\r\n /** The array of participants that are holding tickets in the lotto. */\r\n this._participants = [];\r\n this._customRandom = customRandom;\r\n }\r\n /**\r\n * Adds a participant with the specified number of tickets, or adds to the participant ticket count if the participant already holds tickets.\r\n * @param participant The participant to add or to increase the ticket count for if they already hold tickets.\r\n * @param tickets The number of tickets, defaults to 1.\r\n * @returns The Lotto instance.\r\n */\r\n Lotto.prototype.add = function (participant, tickets) {\r\n if (tickets === void 0) { tickets = 1; }\r\n // Check that we have a valid ticket count.\r\n if (!(0, Utilities_1.isNaturalNumber)(tickets)) {\r\n throw new Error(\"tickets value must be a natural number\");\r\n }\r\n // Check whether this participant has already been added.\r\n var existingParticipant = this._participants.find(function (part) { return part.participant === participant; });\r\n if (existingParticipant) {\r\n // The participant has already been added to the lotto so just add to their ticket count.\r\n existingParticipant.tickets += tickets;\r\n }\r\n else {\r\n // The participant is not part of the lotto so we should add them.\r\n this._participants.push(new Participant_1.Participant(participant, tickets));\r\n }\r\n return this;\r\n };\r\n /**\r\n * Removes the specified number of tickets for the given participant from the draw, or all tickets if a ticket number is not defined.\r\n * @param participant The participant to remove tickets for.\r\n * @param tickets The number of tickets to remove, or undefined if all tickets are to be removed.\r\n * @returns The Lotto instance.\r\n */\r\n Lotto.prototype.remove = function (participant, tickets) {\r\n // Attempt to get the existing participant.\r\n var existingParticipant = this._participants.find(function (part) { return part.participant === participant; });\r\n // There is nothing to do if the specified participant isn't even part of the lotto.\r\n if (!existingParticipant) {\r\n return this;\r\n }\r\n // Check whether a tickets value was given.\r\n if (tickets !== undefined) {\r\n // Check that we have a valid ticket count.\r\n if (!(0, Utilities_1.isNaturalNumber)(tickets)) {\r\n throw new Error(\"tickets value must be a natural number\");\r\n }\r\n existingParticipant.tickets -= tickets;\r\n // If the participant no longer holds any tickets then they should be removed.\r\n if (existingParticipant.tickets < 1) {\r\n this._participants = this._participants.filter(function (part) { return part !== existingParticipant; });\r\n }\r\n }\r\n else {\r\n // We are removing all tickets for the participant so just remove them from the lotto.\r\n this._participants = this._participants.filter(function (part) { return part !== existingParticipant; });\r\n }\r\n return this;\r\n };\r\n /**\r\n * Draw a winning ticket and return the participant that holds the ticket.\r\n * @param options The draw options.\r\n * @returns The participant that holds the winning ticket.\r\n */\r\n Lotto.prototype.draw = function (options) {\r\n if (options === void 0) { options = {}; }\r\n // If we have no participants then just return null.\r\n if (this._participants.length === 0) {\r\n return null;\r\n }\r\n var redrawable = (0, Utilities_1.isNullOrUndefined)(options.redrawable) ? true : options.redrawable;\r\n var pickable = [];\r\n this._participants.forEach(function (_a) {\r\n var participant = _a.participant, tickets = _a.tickets;\r\n for (var ticketCount = 0; ticketCount < tickets; ticketCount++) {\r\n pickable.push(participant);\r\n }\r\n });\r\n var random;\r\n // We need a random floating-point number between 0 (inclusive) and 1 to scale up to pick our winner.\r\n // If a custom random function exists then we should use that or fall back to Math.random().\r\n if (this._customRandom) {\r\n // Call our custom random function to get a random floating-point number.\r\n random = this._customRandom();\r\n // Verify that the result of calling our custom random function is a number between 0 (inclusive) and 1.\r\n if (typeof random !== \"number\" || random < 0 || random >= 1) {\r\n throw new Error(\"the 'random' function provided did not return a number between 0 (inclusive) and 1\");\r\n }\r\n }\r\n else {\r\n // No custom random function was defined so just use good ol' Math.random().\r\n random = Math.random();\r\n }\r\n // Pick a winning participant.\r\n var winner = pickable[Math.floor(random * pickable.length)];\r\n // If the ticket isn't redrawable then we should remove a ticket from the winning participants ticket count.\r\n if (!redrawable) {\r\n this.remove(winner, 1);\r\n }\r\n // Return the winning participant.\r\n return winner;\r\n };\r\n /**\r\n * Draws multiple winning tickets and return an array of the participants that hold the winning tickets.\r\n * @param tickets The number of winning tickets to draw.\r\n * @param options The draw multiple options.\r\n * @returns An array of the participants that hold the winning tickets.\r\n */\r\n Lotto.prototype.drawMultiple = function (tickets, options) {\r\n if (options === void 0) { options = {}; }\r\n var uniqueResults = (0, Utilities_1.isNullOrUndefined)(options.unique) ? false : options.unique;\r\n // Handle cases where the user has asked for zero tickets (no idea why they would do this be we should trust them).\r\n if (tickets === 0) {\r\n return [];\r\n }\r\n // Now that we know out tickets value is not zero we should check that it is a valid natural number.\r\n if (!(0, Utilities_1.isNaturalNumber)(tickets)) {\r\n throw new Error(\"tickets value must be a natural number\");\r\n }\r\n var result = [];\r\n // Keep drawing tickets until we either reach the number of required tickets or we simply run out of tickets to draw.\r\n // We can run out of tickets to draw if 'options.redrawable' is explicity 'false' or we just had no participants when 'drawMultiple' was called.\r\n while (result.length < tickets && this._participants.length > 0) {\r\n result.push(this.draw(options));\r\n }\r\n // If the 'unique' draw option is set then we need to remove duplicates from the result list.\r\n if (uniqueResults) {\r\n // Create an array to store our unique results.\r\n var unique = [];\r\n // Iterate over all of our participants (with potential duplicates) and populate our array of unique values.\r\n for (var _i = 0, result_1 = result; _i < result_1.length; _i++) {\r\n var participant = result_1[_i];\r\n if (unique.indexOf(participant) === -1) {\r\n unique.push(participant);\r\n }\r\n }\r\n result = unique;\r\n }\r\n return result;\r\n };\r\n return Lotto;\r\n}());\r\nexports.Lotto = Lotto;\r\n", "\"use strict\";\r\nObject.defineProperty(exports, \"__esModule\", { value: true });\r\nexports.createLotto = void 0;\r\nvar Lotto_1 = require(\"./Lotto\");\r\n/**\r\n * A function that creates and returns a Lotto instance.\r\n * @param participantsOrOptions An array of initial participants or options relating to the creation of a Lotto instance.\r\n * @returns A new Lotto instance.\r\n */\r\nfunction createLotto(participantsOrOptions) {\r\n // If no initial participants or lotto options were provided as an argument then we can just return a new lotto instance now.\r\n if (!participantsOrOptions) {\r\n return new Lotto_1.Lotto();\r\n }\r\n // Check whether we were provided with an array of initial participants or a lotto options object.\r\n if (Array.isArray(participantsOrOptions)) {\r\n // We are dealing with a pre-defined array of participants.\r\n var participants = participantsOrOptions;\r\n var lotto_1 = new Lotto_1.Lotto();\r\n // If the lotto participants have been defined upfront then we will need to add them all to our lotto instance now.\r\n participants.forEach(function (_a) {\r\n var participant = _a[0], tokens = _a[1];\r\n return lotto_1.add(participant, tokens);\r\n });\r\n // Return the Lotto instance.\r\n return lotto_1;\r\n }\r\n else {\r\n // We are dealing with some lotto options.\r\n var random = participantsOrOptions.random, participants = participantsOrOptions.participants;\r\n // Create a Lotto instance passing the custom RNG function to use in place of Math.random() (which could be undefined).\r\n var lotto_2 = new Lotto_1.Lotto(random);\r\n // If the lotto participants have been defined upfront as part of the options then we will need to add them all to our lotto instance now.\r\n if (participants) {\r\n participants.forEach(function (_a) {\r\n var participant = _a[0], tokens = _a[1];\r\n return lotto_2.add(participant, tokens);\r\n });\r\n }\r\n // Return the Lotto instance.\r\n return lotto_2;\r\n }\r\n}\r\nexports.createLotto = createLotto;\r\n", "\"use strict\";\r\nObject.defineProperty(exports, \"__esModule\", { value: true });\r\nvar createLotto_1 = require(\"./createLotto\");\r\nexports.default = createLotto_1.createLotto;\r\n", "import { BehaviourTree, FlattenedTreeNode } from \"./BehaviourTree\";\nimport State from \"./State\";\n\nexport { BehaviourTree, State };\nexport type { FlattenedTreeNode };\n", "import Node from \"../../nodes/Node\";\n\n/**\n * An exception thrown when evaluating node guard path conditions and a conditions fails.\n */\nexport default class GuardUnsatisifedException extends Error {\n /**\n * @param source The node at which a guard condition failed.\n */\n constructor(private source: Node) {\n super(\"A guard path condition has failed\");\n }\n\n /**\n * Gets whether the specified node is the node at which a guard condition failed.\n * @param node The node to check against the source node.\n * @returns Whether the specified node is the node at which a guard condition failed.\n */\n isSourceNode = (node: Node) => node === this.source;\n}\n", "import { Agent } from \"../../Agent\";\nimport Guard from \"./Guard\";\nimport Node from \"../../nodes/Node\";\nimport GuardUnsatisifedException from \"./GuardUnsatisifedException\";\n\nexport type GuardPathPart = {\n node: Node;\n guards: Guard[];\n};\n\n/**\n * Represents a path of node guards along a root-to-leaf tree path.\n */\nexport default class GuardPath {\n /**\n * @param nodes An array of objects defining a node instance -> guard link, ordered by node depth.\n */\n constructor(private nodes: GuardPathPart[]) {}\n\n /**\n * Evaluate guard conditions for all guards in the tree path, moving outwards from the root.\n * @param agent The agent, required for guard evaluation.\n * @returns An evaluation results object.\n */\n evaluate = (agent: Agent) => {\n // We need to evaluate guard conditions for nodes up the tree, moving outwards from the root.\n for (const details of this.nodes) {\n // There can be multiple guards per node.\n for (const guard of details.guards) {\n // Check whether the guard condition passes, and throw an exception if not.\n if (!guard.isSatisfied(agent)) {\n throw new GuardUnsatisifedException(details.node);\n }\n }\n }\n };\n}\n", "/**\n * Enumeration of node state types.\n */\nexport enum State {\n READY = \"mistreevous.ready\",\n RUNNING = \"mistreevous.running\",\n SUCCEEDED = \"mistreevous.succeeded\",\n FAILED = \"mistreevous.failed\"\n}\n\nexport { State as default };\n\nexport type CompleteState = State.SUCCEEDED | State.FAILED;\nexport type AnyState = State.READY | State.RUNNING | CompleteState;\n", "import { Agent } from \"../Agent\";\nimport Attribute from \"../attributes/Attribute\";\nimport Entry from \"../attributes/callbacks/Entry\";\nimport Exit from \"../attributes/callbacks/Exit\";\nimport Step from \"../attributes/callbacks/Step\";\nimport Guard from \"../attributes/guards/Guard\";\nimport GuardPath from \"../attributes/guards/GuardPath\";\nimport GuardUnsatisifedException from \"../attributes/guards/GuardUnsatisifedException\";\nimport { BehaviourTreeOptions } from \"../BehaviourTreeOptions\";\nimport { AnyArgument } from \"../RootAstNodesBuilder\";\nimport State, { AnyState } from \"../State\";\nimport Leaf from \"./leaf/Leaf\";\n\n/**\n * A base node.\n */\nexport default abstract class Node {\n /**\n * The node uid.\n */\n private readonly uid: string = createNodeUid();\n /**\n * The node state.\n */\n private state: AnyState = State.READY;\n /**\n * The guard path to evaluate as part of a node update.\n */\n private guardPath: GuardPath | undefined;\n\n /**\n * @param type The node type.\n * @param attributes The node attributes.\n * @param args The node argument definitions.\n */\n constructor(private type: string, private attributes: Attribute[], private args: AnyArgument[]) {}\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected abstract onUpdate(agent: Agent, options: BehaviourTreeOptions): void;\n\n /**\n * Gets the name of the node.\n */\n public abstract getName(): string;\n\n /**\n * Gets whether this node is a leaf node.\n */\n public abstract isLeafNode: () => this is Leaf;\n\n /**\n * Gets/Sets the state of the node.\n */\n getState = (): AnyState => this.state;\n setState = (value: AnyState): void => {\n this.state = value;\n };\n\n /**\n * Gets the unique id of the node.\n */\n getUid = () => this.uid;\n\n /**\n * Gets the type of the node.\n */\n getType = () => this.type;\n\n /**\n * Gets the node attributes.\n */\n getAttributes = () => this.attributes;\n\n /**\n * Gets the node arguments.\n */\n getArguments = () => this.args;\n\n /**\n * Gets the node attribute with the specified type, or null if it does not exist.\n */\n getAttribute(type: \"entry\" | \"ENTRY\"): Entry;\n getAttribute(type: \"exit\" | \"EXIT\"): Exit;\n getAttribute(type: \"step\" | \"STEP\"): Step;\n getAttribute(type: string): Attribute {\n return (\n this.getAttributes().filter((decorator) => decorator.getType().toUpperCase() === type.toUpperCase())[0] ||\n null\n );\n }\n\n /**\n * Gets the node attributes.\n */\n getGuardAttributes = (): Guard[] => this.getAttributes().filter((decorator) => decorator.isGuard()) as Guard[];\n\n /**\n * Sets the guard path to evaluate as part of a node update.\n */\n setGuardPath = (value: GuardPath) => (this.guardPath = value);\n\n /**\n * Gets whether a guard path is assigned to this node.\n */\n hasGuardPath = () => !!this.guardPath;\n\n /**\n * Gets whether this node is in the specified state.\n * @param value The value to compare to the node state.\n */\n public is(value: AnyState): boolean {\n return this.state === value;\n }\n\n /**\n * Reset the state of the node.\n */\n public reset(): void {\n this.setState(State.READY);\n }\n\n /**\n * Abort the running of this node.\n * @param agent The agent.\n */\n public abort(agent: Agent): void {\n // There is nothing to do if this node is not in the running state.\n if (!this.is(State.RUNNING)) {\n return;\n }\n\n // Reset the state of this node.\n this.reset();\n\n this.getAttribute(\"exit\")?.callAgentFunction(agent, false, true);\n }\n\n /**\n * Update the node.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n * @returns The result of the update.\n */\n public update(agent: Agent, options: BehaviourTreeOptions): void {\n // If this node is already in a 'SUCCEEDED' or 'FAILED' state then there is nothing to do.\n if (this.is(State.SUCCEEDED) || this.is(State.FAILED)) {\n return;\n }\n\n try {\n // Evaluate all of the guard path conditions for the current tree path.\n this.guardPath!.evaluate(agent);\n\n // If this node is in the READY state then call the ENTRY for this node if it exists.\n if (this.is(State.READY)) {\n this.getAttribute(\"entry\")?.callAgentFunction(agent);\n }\n\n this.getAttribute(\"step\")?.callAgentFunction(agent);\n\n // Do the actual update.\n this.onUpdate(agent, options);\n\n // If this node is now in a 'SUCCEEDED' or 'FAILED' state then call the EXIT for this node if it exists.\n if (this.is(State.SUCCEEDED) || this.is(State.FAILED)) {\n this.getAttribute(\"exit\")?.callAgentFunction(agent, this.is(State.SUCCEEDED), false);\n }\n } catch (error) {\n // If the error is a GuardUnsatisfiedException then we need to determine if this node is the source.\n if (error instanceof GuardUnsatisifedException && error.isSourceNode(this)) {\n // Abort the current node.\n this.abort(agent);\n\n // Any node that is the source of an abort will be a failed node.\n this.setState(State.FAILED);\n } else {\n throw error;\n }\n }\n }\n}\n\n/**\n * Create a randomly generated node uid.\n * @returns A randomly generated node uid.\n */\nfunction createNodeUid(): string {\n var S4 = function () {\n return (((1 + Math.random()) * 0x10000) | 0).toString(16).substring(1);\n };\n return S4() + S4() + \"-\" + S4() + \"-\" + S4() + \"-\" + S4() + \"-\" + S4() + S4() + S4();\n}\n", "import Node from \"../Node\";\n\n/**\n * A leaf node.\n */\nexport default abstract class Leaf extends Node {\n /**\n * Gets whether this node is a leaf node.\n */\n isLeafNode = () => true;\n}\n", "import { ActionResult, Agent, ExitFunctionArg, FunctionArg, GlobalFunction } from \"./Agent\";\nimport { AnyArgument, RootAstNode } from \"./RootAstNodesBuilder\";\n\n// Exit callbacks receive their own special type of argument.\n// There's probably stricter ways to represent this but it feels overly complex right now.\ntype ExitResultArg = { value: ExitFunctionArg };\nexport type AnyExitArgument = AnyArgument | ExitResultArg;\n\nexport type InvokerFunction = (args: AnyExitArgument[]) => ActionResult;\n\n/**\n * A singleton used to store and lookup registered functions and subtrees.\n */\nexport default class Lookup {\n /**\n * The object holding any registered functions keyed on function name.\n */\n private static functionTable: { [key: string]: GlobalFunction } = {};\n /**\n * The object holding any registered sub-trees keyed on tree name.\n */\n private static subtreeTable: { [key: string]: RootAstNode } = {};\n\n /**\n * Gets the function with the specified name.\n * @param name The name of the function.\n * @returns The function with the specified name.\n */\n public static getFunc(name: string): GlobalFunction {\n return this.functionTable[name];\n }\n\n /**\n * Sets the function with the specified name for later lookup.\n * @param name The name of the function.\n * @param func The function.\n */\n public static setFunc(name: string, func: GlobalFunction): void {\n this.functionTable[name] = func;\n }\n\n /**\n * Gets the function invoker for the specified agent and function name.\n * If a function with the specified name exists on the agent object then it will\n * be returned, otherwise we will then check the registered functions for a match.\n * @param agent The agent instance that this behaviour tree is modelling behaviour for.\n * @param name The function name.\n * @returns The function invoker for the specified agent and function name.\n */\n static getFuncInvoker(agent: Agent, name: string): InvokerFunction | null {\n // Check whether the agent contains the specified function.\n const foundOnAgent = agent[name];\n if (foundOnAgent && typeof foundOnAgent === \"function\") {\n return (args: AnyExitArgument[]): boolean | ActionResult =>\n foundOnAgent.apply(\n agent,\n args.map((arg) => arg.value)\n );\n }\n\n // The agent does not contain the specified function but it may have been registered at some point.\n if (this.functionTable[name] && typeof this.functionTable[name] === \"function\") {\n return (args: AnyExitArgument[]) => this.functionTable[name](agent, ...args.map((arg) => arg.value));\n }\n\n // We have no function to invoke.\n return null;\n }\n\n /**\n * Gets the subtree with the specified name.\n * @param name The name of the subtree.\n * @returns The subtree with the specified name.\n */\n static getSubtree(name: string): RootAstNode {\n return this.subtreeTable[name];\n }\n\n /**\n * Sets the subtree with the specified name for later lookup.\n * @param name The name of the subtree.\n * @param subtree The subtree.\n */\n static setSubtree(name: string, subtree: RootAstNode) {\n this.subtreeTable[name] = subtree;\n }\n\n /**\n * Removes the registered function or subtree with the specified name.\n * @param name The name of the registered function or subtree.\n */\n static remove(name: string) {\n delete this.functionTable[name];\n delete this.subtreeTable[name];\n }\n\n /**\n * Remove all registered functions and subtrees.\n */\n static empty() {\n this.functionTable = {};\n this.subtreeTable = {};\n }\n}\n", "import Leaf from \"./Leaf\";\nimport State, { CompleteState } from \"../../State\";\nimport Lookup from \"../../Lookup\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { AnyArgument } from \"../../RootAstNodesBuilder\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * An Action leaf node.\n * This represents an immediate or ongoing state of behaviour.\n */\nexport default class Action extends Leaf {\n /**\n * @param attributes The node attributes.\n * @param actionName The action name.\n * @param actionArguments The array of action argument definitions.\n */\n constructor(attributes: Attribute[], private actionName: string, private actionArguments: AnyArgument[]) {\n super(\"action\", attributes, actionArguments);\n }\n\n /**\n * Whether there is a pending update promise.\n */\n private isUsingUpdatePromise = false;\n\n /**\n * The finished state result of an update promise.\n */\n private updatePromiseStateResult: CompleteState | null = null;\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // If the result of this action depends on an update promise then there is nothing to do until\n // it resolves, unless there has been a value set as a result of the update promise resolving.\n if (this.isUsingUpdatePromise) {\n // Check whether the update promise has resolved with a state value.\n if (this.updatePromiseStateResult) {\n // Set the state of this node to match the state returned by the promise.\n this.setState(this.updatePromiseStateResult);\n }\n\n return;\n }\n\n // Attempt to get the invoker for the action function.\n const actionFuncInvoker = Lookup.getFuncInvoker(agent, this.actionName);\n\n // The action function should be defined.\n if (actionFuncInvoker === null) {\n throw new Error(\n `cannot update action node as the action '${this.actionName}' function is not defined on the agent and has not been registered`\n );\n }\n\n // Call the action function, the result of which may be:\n // - The finished state of this action node.\n // - A promise to return a finished node state.\n // - Undefined if the node should remain in the running state.\n const updateResult = actionFuncInvoker(this.actionArguments) as CompleteState | Promise;\n\n if (updateResult instanceof Promise) {\n updateResult.then(\n (result) => {\n // If 'isUpdatePromisePending' is null then the promise was cleared as it was resolving, probably via an abort of reset.\n if (!this.isUsingUpdatePromise) {\n return;\n }\n\n // Check to make sure the result is a valid finished state.\n if (result !== State.SUCCEEDED && result !== State.FAILED) {\n throw new Error(\n \"action node promise resolved with an invalid value, expected a State.SUCCEEDED or State.FAILED value to be returned\"\n );\n }\n\n // Set pending update promise state result to be processed on next update.\n this.updatePromiseStateResult = result;\n },\n (reason) => {\n // If 'isUpdatePromisePending' is null then the promise was cleared as it was resolving, probably via an abort of reset.\n if (!this.isUsingUpdatePromise) {\n return;\n }\n\n // Just throw whatever was returned as the rejection argument.\n throw new Error(reason);\n }\n );\n\n // This node will be in the 'RUNNING' state until the update promise resolves.\n this.setState(State.RUNNING);\n\n // We are now waiting for the promise returned by the use to resolve before we know what state this node is in.\n this.isUsingUpdatePromise = true;\n } else {\n // Validate the returned value.\n this.validateUpdateResult(updateResult);\n\n // Set the state of this node, this may be undefined, which just means that the node is still in the 'RUNNING' state.\n this.setState(updateResult || State.RUNNING);\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => this.actionName;\n\n /**\n * Reset the state of the node.\n */\n reset = () => {\n // Reset the state of this node.\n this.setState(State.READY);\n\n // There is no longer an update promise that we care about.\n this.isUsingUpdatePromise = false;\n this.updatePromiseStateResult = null;\n };\n\n /**\n * Validate the result of an update function call.\n * @param result The result of an update function call.\n */\n private validateUpdateResult = (result: CompleteState | boolean) => {\n switch (result) {\n case State.SUCCEEDED:\n case State.FAILED:\n case undefined:\n return;\n default:\n throw new Error(\n `action '${this.actionName}' 'onUpdate' returned an invalid response, expected an optional State.SUCCEEDED or State.FAILED value to be returned`\n );\n }\n };\n}\n", "import Leaf from \"./Leaf\";\nimport State from \"../../State\";\nimport Lookup from \"../../Lookup\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { AnyArgument } from \"../../RootAstNodesBuilder\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A Condition leaf node.\n * This will succeed or fail immediately based on an agent predicate, without moving to the 'RUNNING' state.\n */\nexport default class Condition extends Leaf {\n /**\n * @param attributes The node attributes.\n * @param conditionName The name of the condition function.\n * @param conditionArguments The array of condition argument definitions.\n */\n constructor(attributes: Attribute[], private conditionName: string, private conditionArguments: AnyArgument[]) {\n super(\"condition\", attributes, conditionArguments);\n }\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // Attempt to get the invoker for the condition function.\n const conditionFuncInvoker = Lookup.getFuncInvoker(agent, this.conditionName);\n\n // The condition function should be defined.\n if (conditionFuncInvoker === null) {\n throw new Error(\n `cannot update condition node as the condition '${this.conditionName}' function is not defined on the agent and has not been registered`\n );\n }\n\n // Call the condition function to determine the state of this node.\n this.setState(!!conditionFuncInvoker(this.conditionArguments) ? State.SUCCEEDED : State.FAILED);\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => this.conditionName;\n}\n", "import Leaf from \"./Leaf\";\nimport State from \"../../State\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { Agent } from \"../../Agent\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A WAIT node.\n * The state of this node will change to SUCCEEDED after a duration of time\n */\nexport default class Wait extends Leaf {\n /**\n * @param attributes The node attributes.\n * @param duration The duration that this node will wait to succeed in milliseconds, or the earliest if longestDuration is defined.\n * @param longestDuration The longest possible duration in milliseconds that this node will wait to succeed.\n */\n constructor(attributes: Attribute[], private duration: number, private longestDuration: number) {\n super(\"wait\", attributes, []);\n }\n\n /**\n * The time in milliseconds at which this node was first updated.\n */\n private initialUpdateTime: number = 0;\n\n /**\n * The total duration in milliseconds that this node will be waiting for.\n */\n private totalDuration: number = 0;\n\n /**\n * The duration in milliseconds that this node has been waiting for.\n */\n private waitedDuration: number = 0;\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // If this node is in the READY state then we need to set the initial update time.\n if (this.is(State.READY)) {\n // Set the initial update time.\n this.initialUpdateTime = new Date().getTime();\n\n // Set the initial waited duration.\n this.waitedDuration = 0;\n\n // If a longestDuration value was defined then we will be randomly picking a duration between the\n // shortest and longest duration. If it was not defined, then we will be just using the duration.\n this.totalDuration = this.longestDuration\n ? Math.floor(Math.random() * (this.longestDuration - this.duration + 1) + this.duration)\n : this.duration;\n\n // The node is now running until we finish waiting.\n this.setState(State.RUNNING);\n }\n\n // If we have a 'getDeltaTime' function defined as part of our options then we will use it to figure out how long we have waited for.\n if (typeof options.getDeltaTime === \"function\") {\n // Get the delta time.\n const deltaTime = options.getDeltaTime();\n\n // Our delta time must be a valid number and cannot be NaN.\n if (typeof deltaTime !== \"number\" || isNaN(deltaTime)) {\n throw new Error(\"The delta time must be a valid number and not NaN.\");\n }\n\n // Update the amount of time that this node has been waiting for based on the delta time.\n this.waitedDuration += deltaTime * 1000;\n } else {\n // We are not using a delta time, so we will just work out hom much time has passed since the first update.\n this.waitedDuration = new Date().getTime() - this.initialUpdateTime;\n }\n\n // Have we waited long enough?\n if (this.waitedDuration >= this.totalDuration) {\n // We have finished waiting!\n this.setState(State.SUCCEEDED);\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () =>\n `WAIT ${this.longestDuration ? this.duration + \"ms-\" + this.longestDuration + \"ms\" : this.duration + \"ms\"}`;\n}\n", "import Node from \"../Node\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\n\n/**\n * A decorator node that wraps a single child node.\n */\nexport default abstract class Decorator extends Node {\n /**\n * @param type The node type.\n * @param attributes The node attributes.\n * @param child The child node.\n */\n constructor(type: string, attributes: Attribute[], protected child: Node) {\n super(type, attributes, []);\n }\n\n /**\n * Gets whether this node is a leaf node.\n */\n isLeafNode = () => false;\n\n /**\n * Gets the children of this node.\n */\n getChildren = () => [this.child];\n\n /**\n * Reset the state of the node.\n */\n reset = () => {\n // Reset the state of this node.\n this.setState(State.READY);\n\n // Reset the state of the child node.\n this.child.reset();\n };\n\n /**\n * Abort the running of this node.\n * @param agent The agent.\n */\n abort = (agent: Agent) => {\n // There is nothing to do if this node is not in the running state.\n if (!this.is(State.RUNNING)) {\n return;\n }\n\n // Abort the child node.\n this.child.abort(agent);\n\n // Reset the state of this node.\n this.reset();\n\n this.getAttribute(\"exit\")?.callAgentFunction(agent, false, true);\n };\n}\n", "import Node from \"../Node\";\nimport Decorator from \"./Decorator\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A Root node.\n * The root node will have a single child.\n */\nexport default class Root extends Decorator {\n /**\n * @param attributes The node attributes.\n * @param child The child node.\n */\n constructor(attributes: Attribute[], child: Node) {\n super(\"root\", attributes, child);\n }\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // If the child has never been updated or is running then we will need to update it now.\n if (this.child.getState() === State.READY || this.child.getState() === State.RUNNING) {\n // Update the child of this node.\n this.child.update(agent, options);\n }\n\n // The state of the root node is the state of its child.\n this.setState(this.child.getState());\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => \"ROOT\";\n}\n", "import Node from \"../Node\";\nimport Decorator from \"./Decorator\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A REPEAT node.\n * The node has a single child which can have:\n * -- A number of iterations for which to repeat the child node.\n * -- An infinite repeat loop if neither an iteration count or a condition function is defined.\n * The REPEAT node will stop and have a 'FAILED' state if its child is ever in a 'FAILED' state after an update.\n * The REPEAT node will attempt to move on to the next iteration if its child is ever in a 'SUCCEEDED' state.\n */\nexport default class Repeat extends Decorator {\n /**\n * @param attributes The node attributes.\n * @param iterations The number of iterations to repeat the child node, or the minimum number of iterations if maximumIterations is defined.\n * @param maximumIterations The maximum number of iterations to repeat the child node.\n * @param child The child node.\n */\n constructor(\n attributes: Attribute[],\n private iterations: number | null,\n private maximumIterations: number | null,\n child: Node\n ) {\n super(\"repeat\", attributes, child);\n }\n\n /**\n * The number of target iterations to make.\n */\n private targetIterationCount: number | null = null;\n\n /**\n * The current iteration count.\n */\n private currentIterationCount: number = 0;\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // If this node is in the READY state then we need to reset the child and the target iteration count.\n if (this.is(State.READY)) {\n // Reset the child node.\n this.child.reset();\n\n // Set the target iteration count.\n this.setTargetIterationCount();\n }\n\n // Do a check to see if we can iterate. If we can then this node will move into the 'RUNNING' state.\n // If we cannot iterate then we have hit our target iteration count, which means that the node has succeeded.\n if (this.canIterate()) {\n // This node is in the running state and can do its initial iteration.\n this.setState(State.RUNNING);\n\n // We may have already completed an iteration, meaning that the child node will be in the SUCCEEDED state.\n // If this is the case then we will have to reset the child node now.\n if (this.child.getState() === State.SUCCEEDED) {\n this.child.reset();\n }\n\n // Update the child of this node.\n this.child.update(agent, options);\n\n // If the child moved into the FAILED state when we updated it then there is nothing left to do and this node has also failed.\n // If it has moved into the SUCCEEDED state then we have completed the current iteration.\n if (this.child.getState() === State.FAILED) {\n // The child has failed, meaning that this node has failed.\n this.setState(State.FAILED);\n\n return;\n } else if (this.child.getState() === State.SUCCEEDED) {\n // We have completed an iteration.\n this.currentIterationCount += 1;\n }\n } else {\n // This node is in the 'SUCCEEDED' state as we cannot iterate any more.\n this.setState(State.SUCCEEDED);\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => {\n if (this.iterations !== null) {\n return `REPEAT ${\n this.maximumIterations ? this.iterations + \"x-\" + this.maximumIterations + \"x\" : this.iterations + \"x\"\n }`;\n }\n\n // Return the default repeat node name.\n return \"REPEAT\";\n };\n\n /**\n * Reset the state of the node.\n */\n reset = () => {\n // Reset the state of this node.\n this.setState(State.READY);\n\n // Reset the current iteration count.\n this.currentIterationCount = 0;\n\n // Reset the child node.\n this.child.reset();\n };\n\n /**\n * Gets whether an iteration can be made.\n * @returns Whether an iteration can be made.\n */\n private canIterate = () => {\n if (this.targetIterationCount !== null) {\n // We can iterate as long as we have not reached our target iteration count.\n return this.currentIterationCount < this.targetIterationCount;\n }\n\n // If neither an iteration count or a condition function were defined then we can iterate indefinitely.\n return true;\n };\n\n /**\n * Sets the target iteration count.\n */\n private setTargetIterationCount = () => {\n // Are we dealing with a finite number of iterations?\n if (typeof this.iterations === \"number\") {\n // If we have maximumIterations defined then we will want a random iteration count bounded by iterations and maximumIterations.\n this.targetIterationCount =\n typeof this.maximumIterations === \"number\"\n ? Math.floor(Math.random() * (this.maximumIterations - this.iterations + 1) + this.iterations)\n : this.iterations;\n } else {\n this.targetIterationCount = null;\n }\n };\n}\n", "import Node from \"../Node\";\nimport Decorator from \"./Decorator\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A RETRY node.\n * The node has a single child which can have:\n * -- A number of iterations for which to repeat the child node.\n * -- An infinite repeat loop if neither an iteration count or a condition function is defined.\n * The RETRY node will stop and have a 'SUCCEEDED' state if its child is ever in a 'SUCCEEDED' state after an update.\n * The RETRY node will attempt to move on to the next iteration if its child is ever in a 'FAILED' state.\n */\nexport default class Retry extends Decorator {\n /**\n * @param attributes The node attributes.\n * @param iterations The number of iterations to repeat the child node, or the minimum number of iterations if maximumIterations is defined.\n * @param maximumIterations The maximum number of iterations to repeat the child node.\n * @param child The child node.\n */\n constructor(\n attributes: Attribute[],\n private iterations: number | null,\n private maximumIterations: number | null,\n child: Node\n ) {\n super(\"retry\", attributes, child);\n }\n\n /**\n * The number of target iterations to make.\n */\n private targetIterationCount: number | null = null;\n\n /**\n * The current iteration count.\n */\n private currentIterationCount: number = 0;\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // If this node is in the READY state then we need to reset the child and the target iteration count.\n if (this.is(State.READY)) {\n // Reset the child node.\n this.child.reset();\n\n // Set the target iteration count.\n this.setTargetIterationCount();\n }\n\n // Do a check to see if we can iterate. If we can then this node will move into the 'RUNNING' state.\n // If we cannot iterate then we have hit our target iteration count, which means that the node has succeeded.\n if (this.canIterate()) {\n // This node is in the running state and can do its initial iteration.\n this.setState(State.RUNNING);\n\n // We may have already completed an iteration, meaning that the child node will be in the FAILED state.\n // If this is the case then we will have to reset the child node now.\n if (this.child.getState() === State.FAILED) {\n this.child.reset();\n }\n\n // Update the child of this node.\n this.child.update(agent, options);\n\n // If the child moved into the SUCCEEDED state when we updated it then there is nothing left to do and this node has also succeeded.\n // If it has moved into the FAILED state then we have completed the current iteration.\n if (this.child.getState() === State.SUCCEEDED) {\n // The child has succeeded, meaning that this node has succeeded.\n this.setState(State.SUCCEEDED);\n\n return;\n } else if (this.child.getState() === State.FAILED) {\n // We have completed an iteration.\n this.currentIterationCount += 1;\n }\n } else {\n // This node is in the 'FAILED' state as we cannot iterate any more.\n this.setState(State.FAILED);\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => {\n if (this.iterations !== null) {\n return `RETRY ${\n this.maximumIterations ? this.iterations + \"x-\" + this.maximumIterations + \"x\" : this.iterations + \"x\"\n }`;\n }\n\n // Return the default retry node name.\n return \"RETRY\";\n };\n\n /**\n * Reset the state of the node.\n */\n reset = () => {\n // Reset the state of this node.\n this.setState(State.READY);\n\n // Reset the current iteration count.\n this.currentIterationCount = 0;\n\n // Reset the child node.\n this.child.reset();\n };\n\n /**\n * Gets whether an iteration can be made.\n * @returns Whether an iteration can be made.\n */\n canIterate = () => {\n if (this.targetIterationCount !== null) {\n // We can iterate as long as we have not reached our target iteration count.\n return this.currentIterationCount < this.targetIterationCount;\n }\n\n // If neither an iteration count or a condition function were defined then we can iterate indefinitely.\n return true;\n };\n\n /**\n * Sets the target iteration count.\n */\n setTargetIterationCount = () => {\n // Are we dealing with a finite number of iterations?\n if (typeof this.iterations === \"number\") {\n // If we have maximumIterations defined then we will want a random iteration count bounded by iterations and maximumIterations.\n this.targetIterationCount =\n typeof this.maximumIterations === \"number\"\n ? Math.floor(Math.random() * (this.maximumIterations - this.iterations + 1) + this.iterations)\n : this.iterations;\n } else {\n this.targetIterationCount = null;\n }\n };\n}\n", "import Decorator from \"./Decorator\";\nimport State from \"../../State\";\nimport Node from \"../Node\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A Flip node.\n * This node wraps a single child and will flip the state of the child state.\n */\nexport default class Flip extends Decorator {\n /**\n * @param attributes The node attributes.\n * @param child The child node.\n */\n constructor(attributes: Attribute[], child: Node) {\n super(\"flip\", attributes, child);\n }\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // If the child has never been updated or is running then we will need to update it now.\n if (this.child.getState() === State.READY || this.child.getState() === State.RUNNING) {\n this.child.update(agent, options);\n }\n\n // The state of this node will depend in the state of its child.\n switch (this.child.getState()) {\n case State.RUNNING:\n this.setState(State.RUNNING);\n break;\n\n case State.SUCCEEDED:\n this.setState(State.FAILED);\n break;\n\n case State.FAILED:\n this.setState(State.SUCCEEDED);\n break;\n\n default:\n this.setState(State.READY);\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => \"FLIP\";\n}\n", "import Node from \"../Node\";\nimport Decorator from \"./Decorator\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A Succeed node.\n * This node wraps a single child and will always move to the 'SUCCEEDED' state when the child moves to a 'SUCCEEDED' or 'FAILED' state.\n */\nexport default class Succeed extends Decorator {\n /**\n * @param attributes The node attributes.\n * @param child The child node.\n */\n constructor(attributes: Attribute[], child: Node) {\n super(\"succeed\", attributes, child);\n }\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // If the child has never been updated or is running then we will need to update it now.\n if (this.child.getState() === State.READY || this.child.getState() === State.RUNNING) {\n this.child.update(agent, options);\n }\n\n // The state of this node will depend in the state of its child.\n switch (this.child.getState()) {\n case State.RUNNING:\n this.setState(State.RUNNING);\n break;\n\n case State.SUCCEEDED:\n case State.FAILED:\n this.setState(State.SUCCEEDED);\n break;\n\n default:\n this.setState(State.READY);\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => \"SUCCEED\";\n}\n", "import Node from \"../Node\";\nimport Decorator from \"./Decorator\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A Fail node.\n * This node wraps a single child and will always move to the 'FAILED' state when the child moves to a 'SUCCEEDED' or 'FAILED' state.\n */\nexport default class Fail extends Decorator {\n /**\n * @param attributes The node attributes.\n * @param child The child node.\n */\n constructor(attributes: Attribute[], child: Node) {\n super(\"fail\", attributes, child);\n }\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // If the child has never been updated or is running then we will need to update it now.\n if (this.child.getState() === State.READY || this.child.getState() === State.RUNNING) {\n this.child.update(agent, options);\n }\n\n // The state of this node will depend in the state of its child.\n switch (this.child.getState()) {\n case State.RUNNING:\n this.setState(State.RUNNING);\n break;\n\n case State.SUCCEEDED:\n case State.FAILED:\n this.setState(State.FAILED);\n break;\n\n default:\n this.setState(State.READY);\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => \"FAIL\";\n}\n", "import createLotto from \"lotto-draw\";\r\n\r\nimport Node from \"../Node\";\r\nimport Composite from \"./Composite\";\r\nimport State from \"../../State\";\r\nimport { Agent } from \"../../Agent\";\r\nimport Attribute from \"../../attributes/Attribute\";\r\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\r\n\r\n/**\r\n * A LOTTO node.\r\n * A winning child is picked on the initial update of this node, based on ticket weighting.\r\n * The state of this node will match the state of the winning child.\r\n */\r\nexport default class Lotto extends Composite {\r\n /**\r\n * @param attributes The node attributes.\r\n * @param tickets The child node tickets.\r\n * @param children The child nodes.\r\n */\r\n constructor(attributes: Attribute[], private tickets: number[], children: Node[]) {\r\n super(\"lotto\", attributes, children);\r\n }\r\n\r\n /**\r\n * The child node selected to be the active one.\r\n */\r\n private selectedChild: Node | undefined;\r\n\r\n /**\r\n * Called when the node is being updated.\r\n * @param agent The agent.\r\n * @param options The behaviour tree options object.\r\n */\r\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\r\n // If this node is in the READY state then we need to pick a winning child node.\r\n if (this.is(State.READY)) {\r\n // Create a lotto draw with which to randomly pick a child node to become the active one.\r\n const lottoDraw = createLotto({\r\n // Hook up the optional 'random' behaviour tree function option to the one used by 'lotto-draw'.\r\n random: options.random,\r\n // Pass in each child node as a participant in the lotto draw with their respective ticket count.\r\n participants: this.children.map((child, index) => [child, this.tickets[index] || 1])\r\n });\r\n\r\n // Randomly pick a child based on ticket weighting, this will become the active child for this composite node.\r\n this.selectedChild = lottoDraw.draw() || undefined;\r\n }\r\n\r\n // If something went wrong and we don't have an active child then we should throw an error.\r\n if (!this.selectedChild) {\r\n throw new Error(\"failed to update lotto node as it has no active child\");\r\n }\r\n\r\n // If the selected child has never been updated or is running then we will need to update it now.\r\n if (this.selectedChild.getState() === State.READY || this.selectedChild.getState() === State.RUNNING) {\r\n this.selectedChild.update(agent, options);\r\n }\r\n\r\n // The state of the lotto node is the state of its selected child.\r\n this.setState(this.selectedChild.getState());\r\n }\r\n\r\n /**\r\n * Gets the name of the node.\r\n */\r\n getName = () => (this.tickets.length ? `LOTTO [${this.tickets.join(\",\")}]` : \"LOTTO\");\r\n}\r\n", "import Node from \"../Node\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\n\n/**\n * A composite node that wraps child nodes.\n */\nexport default abstract class Composite extends Node {\n /**\n * @param type The node type.\n * @param attributes The node attributes.\n * @param children The child nodes.\n */\n constructor(type: string, attributes: Attribute[], protected children: Node[]) {\n super(type, attributes, []);\n }\n\n /**\n * Gets whether this node is a leaf node.\n */\n isLeafNode = () => false;\n\n /**\n * Gets the children of this node.\n */\n getChildren = () => this.children;\n\n /**\n * Reset the state of the node.\n */\n reset = () => {\n // Reset the state of this node.\n this.setState(State.READY);\n\n // Reset the state of any child nodes.\n this.getChildren().forEach((child) => child.reset());\n };\n\n /**\n * Abort the running of this node.\n * @param agent The agent.\n */\n abort = (agent: Agent) => {\n // There is nothing to do if this node is not in the running state.\n if (!this.is(State.RUNNING)) {\n return;\n }\n\n // Abort any child nodes.\n this.getChildren().forEach((child) => child.abort(agent));\n\n // Reset the state of this node.\n this.reset();\n\n this.getAttribute(\"exit\")?.callAgentFunction(agent, false, true);\n };\n}\n", "import Composite from \"./Composite\";\nimport Node from \"../Node\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A SELECTOR node.\n * The child nodes are executed in sequence until one succeeds or all fail.\n */\nexport default class Selector extends Composite {\n /**\n * @param attributes The node attributes.\n * @param children The child nodes.\n */\n constructor(attributes: Attribute[], protected children: Node[]) {\n super(\"selector\", attributes, children);\n }\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // Iterate over all of the children of this node.\n for (const child of this.children) {\n // If the child has never been updated or is running then we will need to update it now.\n if (child.getState() === State.READY || child.getState() === State.RUNNING) {\n // Update the child of this node.\n child.update(agent, options);\n }\n\n // If the current child has a state of 'SUCCEEDED' then this node is also a 'SUCCEEDED' node.\n if (child.getState() === State.SUCCEEDED) {\n // This node is a 'SUCCEEDED' node.\n this.setState(State.SUCCEEDED);\n\n // There is no need to check the rest of the selector nodes.\n return;\n }\n\n // If the current child has a state of 'FAILED' then we should move on to the next child.\n if (child.getState() === State.FAILED) {\n // Find out if the current child is the last one in the selector.\n // If it is then this sequence node has also failed.\n if (this.children.indexOf(child) === this.children.length - 1) {\n // This node is a 'FAILED' node.\n this.setState(State.FAILED);\n\n // There is no need to check the rest of the selector as we have completed it.\n return;\n } else {\n // The child node failed, try the next one.\n continue;\n }\n }\n\n // The node should be in the 'RUNNING' state.\n if (child.getState() === State.RUNNING) {\n // This node is a 'RUNNING' node.\n this.setState(State.RUNNING);\n\n // There is no need to check the rest of the selector as the current child is still running.\n return;\n }\n\n // The child node was not in an expected state.\n throw new Error(\"child node was not in an expected state.\");\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => \"SELECTOR\";\n}\n", "import Composite from \"./Composite\";\nimport Node from \"../Node\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A SEQUENCE node.\n * The child nodes are executed in sequence until one fails or all succeed.\n */\nexport default class Sequence extends Composite {\n /**\n * @param attributes The node attributes.\n * @param children The child nodes.\n */\n constructor(attributes: Attribute[], protected children: Node[]) {\n super(\"sequence\", attributes, children);\n }\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // Iterate over all of the children of this node.\n for (const child of this.children) {\n // If the child has never been updated or is running then we will need to update it now.\n if (child.getState() === State.READY || child.getState() === State.RUNNING) {\n // Update the child of this node.\n child.update(agent, options);\n }\n\n // If the current child has a state of 'SUCCEEDED' then we should move on to the next child.\n if (child.getState() === State.SUCCEEDED) {\n // Find out if the current child is the last one in the sequence.\n // If it is then this sequence node has also succeeded.\n if (this.children.indexOf(child) === this.children.length - 1) {\n // This node is a 'SUCCEEDED' node.\n this.setState(State.SUCCEEDED);\n\n // There is no need to check the rest of the sequence as we have completed it.\n return;\n } else {\n // The child node succeeded, but we have not finished the sequence yet.\n continue;\n }\n }\n\n // If the current child has a state of 'FAILED' then this node is also a 'FAILED' node.\n if (child.getState() === State.FAILED) {\n // This node is a 'FAILED' node.\n this.setState(State.FAILED);\n\n // There is no need to check the rest of the sequence.\n return;\n }\n\n // The node should be in the 'RUNNING' state.\n if (child.getState() === State.RUNNING) {\n // This node is a 'RUNNING' node.\n this.setState(State.RUNNING);\n\n // There is no need to check the rest of the sequence as the current child is still running.\n return;\n }\n\n // The child node was not in an expected state.\n throw new Error(\"child node was not in an expected state.\");\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => \"SEQUENCE\";\n}\n", "import Composite from \"./Composite\";\nimport State from \"../../State\";\nimport Node from \"../Node\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A PARALLEL node.\n * The child nodes are executed concurrently until one fails or all succeed.\n */\nexport default class Parallel extends Composite {\n /**\n * @param attributes The node attributes.\n * @param children The child nodes.\n */\n constructor(attributes: Attribute[], children: Node[]) {\n super(\"parallel\", attributes, children);\n }\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // Keep a count of the number of succeeded child nodes.\n let succeededCount = 0;\n\n let hasChildFailed = false;\n\n // Iterate over all of the children of this node.\n for (const child of this.children) {\n // If the child has never been updated or is running then we will need to update it now.\n if (child.getState() === State.READY || child.getState() === State.RUNNING) {\n // Update the child of this node.\n child.update(agent, options);\n }\n\n // If the current child has a state of 'SUCCEEDED' then we should move on to the next child.\n if (child.getState() === State.SUCCEEDED) {\n // The child node has succeeded, keep track of this to determine if all children have.\n succeededCount++;\n\n // The child node succeeded, but we have not finished checking every child node yet.\n continue;\n }\n\n // If the current child has a state of 'FAILED' then this node is also a 'FAILED' node.\n if (child.getState() === State.FAILED) {\n hasChildFailed = true;\n\n // There is no need to check the rest of the children.\n break;\n }\n\n // The node should be in the 'RUNNING' state.\n if (child.getState() !== State.RUNNING) {\n // The child node was not in an expected state.\n throw new Error(\"child node was not in an expected state.\");\n }\n }\n\n if (hasChildFailed) {\n // This node is a 'FAILED' node.\n this.setState(State.FAILED);\n\n // Abort every running child.\n for (const child of this.children) {\n if (child.getState() === State.RUNNING) {\n child.abort(agent);\n }\n }\n } else {\n // If all children have succeeded then this node has also succeeded, otherwise it is still running.\n this.setState(succeededCount === this.children.length ? State.SUCCEEDED : State.RUNNING);\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => \"PARALLEL\";\n}\n", "import { AnyArgument } from \"../RootAstNodesBuilder\";\nimport Guard from \"./guards/Guard\";\n\nexport type AttributeDetails = {\n /** The attribute type. */\n type: string;\n\n /** The attribute arguments. */\n args: AnyArgument[];\n};\n\n/**\n * A base node attribute.\n */\nexport default abstract class Attribute {\n /**\n * @param type The node attribute type.\n * @param args The array of attribute argument definitions.\n */\n constructor(protected type: string, protected args: AnyArgument[]) {}\n\n /**\n * Gets the type of the attribute.\n */\n getType = () => this.type;\n\n /**\n * Gets the array of attribute argument definitions.\n */\n getArguments = () => this.args;\n\n /**\n * Gets the attribute details.\n */\n abstract getDetails(): TAttributeDetails;\n\n /**\n * Gets whether this attribute is a guard.\n */\n abstract isGuard: () => this is Guard;\n}\n", "import { Agent } from \"../../Agent\";\nimport { AnyArgument } from \"../../RootAstNodesBuilder\";\nimport Attribute, { AttributeDetails } from \"../Attribute\";\n\nexport type GuardAttributeDetails = {\n /** The name of the condition function that determines whether the guard is satisfied. */\n condition: string;\n} & AttributeDetails;\n\n/**\n * A base node guard attribute.\n */\nexport default abstract class Guard extends Attribute {\n /**\n * @param type The node attribute type.\n * @param args The array of decorator argument definitions.\n * @param condition The name of the condition function that determines whether the guard is satisfied.\n */\n constructor(type: string, args: AnyArgument[], private condition: string) {\n super(type, args);\n }\n\n /**\n * Gets the name of the condition function that determines whether the guard is satisfied.\n */\n getCondition = () => this.condition;\n\n /**\n * Gets whether this attribute is a guard.\n */\n isGuard = () => true;\n\n /**\n * Gets the attribute details.\n */\n getDetails(): GuardAttributeDetails {\n return {\n type: this.getType(),\n args: this.getArguments(),\n condition: this.getCondition()\n };\n }\n\n /**\n * Gets whether the guard is satisfied.\n * @param agent The agent.\n * @returns Whether the guard is satisfied.\n */\n abstract isSatisfied(agent: Agent): boolean;\n}\n", "import Guard from \"./Guard\";\nimport Lookup from \"../../Lookup\";\nimport { Agent } from \"../../Agent\";\nimport { AnyArgument } from \"../../RootAstNodesBuilder\";\n\n/**\n * A WHILE guard which is satisfied as long as the given condition remains true.\n */\nexport default class While extends Guard {\n /**\n * @param condition The name of the condition function that determines whether the guard is satisfied.\n * @param args The array of decorator argument definitions.\n */\n constructor(condition: string, args: AnyArgument[]) {\n super(\"while\", args, condition);\n }\n\n /**\n * Gets whether the guard is satisfied.\n * @param agent The agent.\n * @returns Whether the guard is satisfied.\n */\n isSatisfied = (agent: Agent) => {\n // Attempt to get the invoker for the condition function.\n const conditionFuncInvoker = Lookup.getFuncInvoker(agent, this.getCondition());\n\n // The condition function should be defined.\n if (conditionFuncInvoker === null) {\n throw new Error(\n `cannot evaluate node guard as the condition '${this.getCondition()}' function is not defined on the agent and has not been registered`\n );\n }\n\n // Call the condition function to determine whether this guard is satisfied.\n return !!conditionFuncInvoker(this.args);\n };\n}\n", "import Guard from \"./Guard\";\nimport Lookup from \"../../Lookup\";\nimport { Agent } from \"../../Agent\";\nimport { AnyArgument } from \"../../RootAstNodesBuilder\";\n\n/**\n * An UNTIL guard which is satisfied as long as the given condition remains false.\n */\nexport default class Until extends Guard {\n /**\n * @param condition The name of the condition function that determines whether the guard is satisfied.\n * @param args The array of decorator argument definitions.\n */\n constructor(condition: string, args: AnyArgument[]) {\n super(\"until\", args, condition);\n }\n\n /**\n * Gets whether the guard is satisfied.\n * @param agent The agent.\n * @returns Whether the guard is satisfied.\n */\n isSatisfied = (agent: Agent) => {\n // Attempt to get the invoker for the condition function.\n const conditionFuncInvoker = Lookup.getFuncInvoker(agent, this.getCondition());\n\n // The condition function should be defined.\n if (conditionFuncInvoker === null) {\n throw new Error(\n `cannot evaluate node guard as the condition '${this.getCondition()}' function is not defined on the agent and has not been registered`\n );\n }\n\n // Call the condition function to determine whether this guard is satisfied.\n return !!!conditionFuncInvoker(this.args);\n };\n}\n", "import { Agent } from \"../../Agent\";\nimport { AnyArgument } from \"../../RootAstNodesBuilder\";\nimport Attribute, { AttributeDetails } from \"../Attribute\";\n\nexport type CallbackAttributeDetails = {\n /** The name of the agent function that is called. */\n functionName: string;\n} & AttributeDetails;\n\n/**\n * A base node callback attribute.\n */\nexport default abstract class Callback extends Attribute {\n /**\n * @param type The node attribute type.\n * @param args The array of decorator argument definitions.\n * @param functionName The name of the agent function to call.\n */\n constructor(type: string, args: AnyArgument[], private functionName: string) {\n super(type, args);\n }\n\n /**\n * Gets the name of the agent function to call.\n */\n getFunctionName = () => this.functionName;\n\n /**\n * Gets whether this attribute is a guard.\n */\n isGuard = () => false;\n\n /**\n * Gets the attribute details.\n */\n getDetails(): CallbackAttributeDetails {\n return {\n type: this.getType(),\n args: this.getArguments(),\n functionName: this.getFunctionName()\n };\n }\n\n /**\n * Attempt to call the agent function that this callback refers to.\n * @param agent The agent.\n */\n abstract callAgentFunction: (agent: Agent, isSuccess: boolean, isAborted: boolean) => void;\n}\n", "import Callback from \"./Callback\";\nimport Lookup from \"../../Lookup\";\nimport { Agent } from \"../../Agent\";\nimport { AnyArgument } from \"../../RootAstNodesBuilder\";\n\n/**\n * An ENTRY callback which defines an agent function to call when the associated node is updated and moves out of running state.\n */\nexport default class Entry extends Callback {\n /**\n * @param functionName The name of the agent function to call.\n * @param args The array of callback argument definitions.\n */\n constructor(functionName: string, args: AnyArgument[]) {\n super(\"entry\", args, functionName);\n }\n\n /**\n * Attempt to call the agent function that this callback refers to.\n * @param agent The agent.\n */\n callAgentFunction = (agent: Agent) => {\n // Attempt to get the invoker for the callback function.\n const callbackFuncInvoker = Lookup.getFuncInvoker(agent, this.getFunctionName());\n\n // The callback function should be defined.\n if (callbackFuncInvoker === null) {\n throw new Error(\n `cannot call entry function '${this.getFunctionName()}' as is not defined on the agent and has not been registered`\n );\n }\n\n // Call the callback function.\n callbackFuncInvoker(this.args);\n };\n}\n", "import Callback from \"./Callback\";\nimport Lookup, { AnyExitArgument } from \"../../Lookup\";\nimport { Agent } from \"../../Agent\";\nimport { AnyArgument } from \"../../RootAstNodesBuilder\";\n\n/**\n * An EXIT callback which defines an agent function to call when the associated node is updated and moves to a finished state or is aborted.\n */\nexport default class Exit extends Callback {\n /**\n * @param functionName The name of the agent function to call.\n * @param args The array of callback argument definitions.\n */\n constructor(functionName: string, args: AnyArgument[]) {\n super(\"exit\", args, functionName);\n }\n\n /**\n * Attempt to call the agent function that this callback refers to.\n * @param agent The agent.\n * @param isSuccess Whether the decorated node was left with a success state.\n * @param isAborted Whether the decorated node was aborted.\n */\n callAgentFunction = (agent: Agent, isSuccess: boolean, isAborted: boolean) => {\n // Attempt to get the invoker for the callback function.\n const callbackFuncInvoker = Lookup.getFuncInvoker(agent, this.getFunctionName());\n\n // The callback function should be defined.\n if (callbackFuncInvoker === null) {\n throw new Error(\n `cannot call exit function '${this.getFunctionName()}' as is not defined on the agent and has not been registered`\n );\n }\n\n // Call the callback function\n callbackFuncInvoker([{ value: { succeeded: isSuccess, aborted: isAborted } }, ...this.args]);\n };\n}\n", "import Callback from \"./Callback\";\nimport Lookup from \"../../Lookup\";\nimport { Agent } from \"../../Agent\";\nimport { AnyArgument } from \"../../RootAstNodesBuilder\";\n\n/**\n * A STEP callback which defines an agent function to call when the associated node is updated.\n */\nexport default class Step extends Callback {\n /**\n * @param functionName The name of the agent function to call.\n * @param args The array of callback argument definitions.\n */\n constructor(functionName: string, args: AnyArgument[]) {\n super(\"step\", args, functionName);\n }\n\n /**\n * Attempt to call the agent function that this callback refers to.\n * @param agent The agent.\n */\n callAgentFunction = (agent: Agent) => {\n // Attempt to get the invoker for the callback function.\n const callbackFuncInvoker = Lookup.getFuncInvoker(agent, this.getFunctionName());\n\n // The callback function should be defined.\n if (callbackFuncInvoker === null) {\n throw new Error(\n `cannot call step function '${this.getFunctionName()}' as is not defined on the agent and has not been registered`\n );\n }\n\n // Call the callback function.\n callbackFuncInvoker(this.args);\n };\n}\n", "import Action from \"./nodes/leaf/Action\";\nimport Condition from \"./nodes/leaf/Condition\";\nimport Wait from \"./nodes/leaf/Wait\";\nimport Root from \"./nodes/decorator/Root\";\nimport Repeat from \"./nodes/decorator/Repeat\";\nimport Retry from \"./nodes/decorator/Retry\";\nimport Flip from \"./nodes/decorator/Flip\";\nimport Succeed from \"./nodes/decorator/Succeed\";\nimport Fail from \"./nodes/decorator/Fail\";\nimport Lotto from \"./nodes/composite/Lotto\";\nimport Selector from \"./nodes/composite/Selector\";\nimport Sequence from \"./nodes/composite/Sequence\";\nimport Parallel from \"./nodes/composite/Parallel\";\nimport Node from \"./nodes/Node\";\nimport While from \"./attributes/guards/While\";\nimport Until from \"./attributes/guards/Until\";\nimport Entry from \"./attributes/callbacks/Entry\";\nimport Exit from \"./attributes/callbacks/Exit\";\nimport Step from \"./attributes/callbacks/Step\";\nimport Callback from \"./attributes/callbacks/Callback\";\nimport Guard from \"./attributes/guards/Guard\";\nimport Attribute from \"./attributes/Attribute\";\nimport Composite from \"./nodes/composite/Composite\";\nimport Decorator from \"./nodes/decorator/Decorator\";\nimport Leaf from \"./nodes/leaf/Leaf\";\n\nexport type Argument = {\n value: T;\n type: string; // Used for validation.\n};\ntype NullArgument = Argument & {\n type: \"null\";\n};\ntype BooleanArgument = Argument & {\n type: \"boolean\";\n};\ntype NumberArgument = Argument & {\n type: \"number\";\n isInteger: boolean; // Used for validation.\n};\ntype StringPlaceholderArgument = Argument & {\n type: \"string\";\n};\ntype IdentifierArgument = Argument & {\n type: \"identifier\";\n};\nexport type AnyArgument =\n | NullArgument\n | BooleanArgument\n | NumberArgument\n | StringPlaceholderArgument\n | IdentifierArgument;\n\n/**\n * The node attribute factories.\n */\nconst AttributeFactories: {\n [key: string]: (functionName: string, attributeArguments: AnyArgument[]) => Callback | Guard;\n} = {\n WHILE: (condition: string, attributeArguments: AnyArgument[]) => new While(condition, attributeArguments),\n UNTIL: (condition: string, attributeArguments: AnyArgument[]) => new Until(condition, attributeArguments),\n ENTRY: (functionName: string, attributeArguments: AnyArgument[]) => new Entry(functionName, attributeArguments),\n EXIT: (functionName: string, attributeArguments: AnyArgument[]) => new Exit(functionName, attributeArguments),\n STEP: (functionName: string, attributeArguments: AnyArgument[]) => new Step(functionName, attributeArguments)\n};\n\ntype Validatable = {\n children?: AstNode[];\n validate: (depth: number) => void;\n};\n\ntype NodeInstanceCreator = (\n namedRootNodeProvider: (name: string) => RootAstNode,\n visitedBranches: string[]\n) => T;\n\nexport type AstNode = Validatable & {\n type: string;\n createNodeInstance: NodeInstanceCreator;\n};\n\nexport type LeafAstNode = AstNode & {\n type: \"action\" | \"condition\" | \"wait\";\n attributes: Attribute[];\n};\n\nexport type CompositeAstNode = AstNode & {\n type: \"lotto\" | \"parallel\" | \"selector\" | \"sequence\";\n attributes: Attribute[];\n children: AstNode[];\n};\n\nexport type DecoratorAstNode = AstNode & {\n type: \"fail\" | \"flip\" | \"repeat\" | \"retry\" | \"root\" | \"succeed\";\n attributes: Attribute[];\n children: AstNode[];\n};\n\nexport type BranchAstNode = AstNode & {\n type: \"branch\";\n branchName: \"\" | string;\n};\n\nexport type LottoAstNode = CompositeAstNode & {\n type: \"lotto\";\n tickets: number[];\n};\n\nexport type RootAstNode = DecoratorAstNode & {\n type: \"root\";\n name: null | string;\n};\n\nexport type IterableAstNode = DecoratorAstNode & {\n type: \"repeat\" | \"retry\";\n iterations: null | number;\n maximumIterations: null | number;\n};\n\nexport type ActionAstNode = LeafAstNode & {\n type: \"action\";\n actionName: string;\n actionArguments: AnyArgument[];\n};\n\nexport type ConditionAstNode = LeafAstNode & {\n type: \"condition\";\n conditionName: string;\n conditionArguments: AnyArgument[];\n};\n\nexport type WaitAstNode = LeafAstNode & {\n type: \"wait\";\n duration: number | null;\n longestDuration: number | null;\n};\n\nexport type AnyAstNode =\n | BranchAstNode\n | CompositeAstNode\n | LottoAstNode\n | DecoratorAstNode\n | RootAstNode\n | IterableAstNode\n | LeafAstNode\n | ActionAstNode\n | ConditionAstNode\n | WaitAstNode;\n\n/**\n * The AST node factories.\n */\nconst ASTNodeFactories = {\n ROOT: (): RootAstNode => ({\n type: \"root\",\n attributes: [],\n name: null,\n children: [],\n validate(depth: number) {\n // A root node cannot be the child of another node.\n if (depth > 1) {\n throw new Error(\"a root node cannot be the child of another node\");\n }\n\n // A root node must have a single child node.\n if (this.children.length !== 1) {\n throw new Error(\"a root node must have a single child\");\n }\n },\n createNodeInstance(namedRootNodeProvider, visitedBranches) {\n return new Root(\n this.attributes,\n this.children![0].createNodeInstance(namedRootNodeProvider, visitedBranches.slice())\n );\n }\n }),\n BRANCH: (): BranchAstNode => ({\n type: \"branch\",\n branchName: \"\",\n validate() {},\n createNodeInstance(namedRootNodeProvider, visitedBranches) {\n // Try to find the root node with a matching branch name.\n const targetRootNode = namedRootNodeProvider(this.branchName);\n\n // If we have already visited this branch then we have a circular dependency.\n if (visitedBranches.indexOf(this.branchName) !== -1) {\n throw new Error(`circular dependency found in branch node references for branch '${this.branchName}'`);\n }\n\n // If we have a target root node, then the node instance we want will be the first and only child of the referenced root node.\n if (targetRootNode) {\n return targetRootNode\n .createNodeInstance(namedRootNodeProvider, visitedBranches.concat(this.branchName))\n .getChildren()[0];\n } else {\n throw new Error(`branch references root node '${this.branchName}' which has not been defined`);\n }\n }\n }),\n SELECTOR: (): CompositeAstNode => ({\n type: \"selector\",\n attributes: [],\n children: [],\n validate() {\n // A selector node must have at least a single node.\n if (this.children.length < 1) {\n throw new Error(\"a selector node must have at least a single child\");\n }\n },\n createNodeInstance(namedRootNodeProvider, visitedBranches) {\n return new Selector(\n this.attributes,\n this.children.map((child) => child.createNodeInstance(namedRootNodeProvider, visitedBranches.slice()))\n );\n }\n }),\n SEQUENCE: (): CompositeAstNode => ({\n type: \"sequence\",\n attributes: [],\n children: [],\n validate() {\n // A sequence node must have at least a single node.\n if (this.children.length < 1) {\n throw new Error(\"a sequence node must have at least a single child\");\n }\n },\n createNodeInstance(namedRootNodeProvider, visitedBranches) {\n return new Sequence(\n this.attributes,\n this.children.map((child) => child.createNodeInstance(namedRootNodeProvider, visitedBranches.slice()))\n );\n }\n }),\n PARALLEL: (): CompositeAstNode => ({\n type: \"parallel\",\n attributes: [],\n children: [],\n validate() {\n // A parallel node must have at least a single node.\n if (this.children.length < 1) {\n throw new Error(\"a parallel node must have at least a single child\");\n }\n },\n createNodeInstance(namedRootNodeProvider, visitedBranches) {\n return new Parallel(\n this.attributes,\n this.children.map((child) => child.createNodeInstance(namedRootNodeProvider, visitedBranches.slice()))\n );\n }\n }),\n LOTTO: (): LottoAstNode => ({\n type: \"lotto\",\n attributes: [],\n children: [],\n tickets: [],\n validate() {\n // A lotto node must have at least a single node.\n if (this.children!.length < 1) {\n throw new Error(\"a lotto node must have at least a single child\");\n }\n },\n createNodeInstance(namedRootNodeProvider, visitedBranches) {\n return new Lotto(\n this.attributes,\n this.tickets!,\n this.children!.map((child) => child.createNodeInstance(namedRootNodeProvider, visitedBranches.slice()))\n );\n }\n }),\n REPEAT: (): IterableAstNode => ({\n type: \"repeat\",\n attributes: [],\n iterations: null,\n maximumIterations: null,\n children: [],\n validate() {\n // A repeat node must have a single node.\n if (this.children!.length !== 1) {\n throw new Error(\"a repeat node must have a single child\");\n }\n\n // A repeat node must have a positive number of iterations if defined.\n if (this.iterations !== null && this.iterations! < 0) {\n throw new Error(\"a repeat node must have a positive number of iterations if defined\");\n }\n\n // There is validation to carry out if a longest duration was defined.\n if (this.maximumIterations !== null) {\n // A repeat node must have a positive maximum iterations count if defined.\n if (this.maximumIterations! < 0) {\n throw new Error(\"a repeat node must have a positive maximum iterations count if defined\");\n }\n\n // A repeat node must not have an iteration count that exceeds the maximum iteration count.\n if (this.iterations! > this.maximumIterations!) {\n throw new Error(\n \"a repeat node must not have an iteration count that exceeds the maximum iteration count\"\n );\n }\n }\n },\n createNodeInstance(namedRootNodeProvider, visitedBranches) {\n return new Repeat(\n this.attributes,\n this.iterations!,\n this.maximumIterations!,\n this.children![0].createNodeInstance(namedRootNodeProvider, visitedBranches.slice())\n );\n }\n }),\n RETRY: (): IterableAstNode => ({\n type: \"retry\",\n attributes: [],\n iterations: null,\n maximumIterations: null,\n children: [],\n validate() {\n // A retry node must have a single node.\n if (this.children!.length !== 1) {\n throw new Error(\"a retry node must have a single child\");\n }\n\n // A retry node must have a positive number of iterations if defined.\n if (this.iterations !== null && this.iterations! < 0) {\n throw new Error(\"a retry node must have a positive number of iterations if defined\");\n }\n\n // There is validation to carry out if a longest duration was defined.\n if (this.maximumIterations !== null) {\n // A retry node must have a positive maximum iterations count if defined.\n if (this.maximumIterations! < 0) {\n throw new Error(\"a retry node must have a positive maximum iterations count if defined\");\n }\n\n // A retry node must not have an iteration count that exceeds the maximum iteration count.\n if (this.iterations! > this.maximumIterations!) {\n throw new Error(\n \"a retry node must not have an iteration count that exceeds the maximum iteration count\"\n );\n }\n }\n },\n createNodeInstance(namedRootNodeProvider, visitedBranches) {\n return new Retry(\n this.attributes,\n this.iterations!,\n this.maximumIterations!,\n this.children![0].createNodeInstance(namedRootNodeProvider, visitedBranches.slice())\n );\n }\n }),\n FLIP: (): DecoratorAstNode => ({\n type: \"flip\",\n attributes: [],\n children: [],\n validate() {\n // A flip node must have a single node.\n if (this.children!.length !== 1) {\n throw new Error(\"a flip node must have a single child\");\n }\n },\n createNodeInstance(namedRootNodeProvider, visitedBranches) {\n return new Flip(\n this.attributes,\n this.children![0].createNodeInstance(namedRootNodeProvider, visitedBranches.slice())\n );\n }\n }),\n SUCCEED: (): DecoratorAstNode => ({\n type: \"succeed\",\n attributes: [],\n children: [],\n validate() {\n // A succeed node must have a single node.\n if (this.children!.length !== 1) {\n throw new Error(\"a succeed node must have a single child\");\n }\n },\n createNodeInstance(namedRootNodeProvider, visitedBranches) {\n return new Succeed(\n this.attributes,\n this.children![0].createNodeInstance(namedRootNodeProvider, visitedBranches.slice())\n );\n }\n }),\n FAIL: (): DecoratorAstNode => ({\n type: \"fail\",\n attributes: [],\n children: [],\n validate() {\n // A fail node must have a single node.\n if (this.children!.length !== 1) {\n throw new Error(\"a fail node must have a single child\");\n }\n },\n createNodeInstance(namedRootNodeProvider, visitedBranches) {\n return new Fail(\n this.attributes,\n this.children![0].createNodeInstance(namedRootNodeProvider, visitedBranches.slice())\n );\n }\n }),\n WAIT: (): WaitAstNode => ({\n type: \"wait\",\n attributes: [],\n duration: null,\n longestDuration: null,\n validate() {\n // A wait node must have a positive duration.\n if (this.duration! < 0) {\n throw new Error(\"a wait node must have a positive duration\");\n }\n\n // There is validation to carry out if a longest duration was defined.\n if (this.longestDuration) {\n // A wait node must have a positive longest duration.\n if (this.longestDuration < 0) {\n throw new Error(\"a wait node must have a positive longest duration if one is defined\");\n }\n\n // A wait node must not have a duration that exceeds the longest duration.\n if (this.duration! > this.longestDuration) {\n throw new Error(\"a wait node must not have a shortest duration that exceeds the longest duration\");\n }\n }\n },\n createNodeInstance() {\n return new Wait(this.attributes, this.duration!, this.longestDuration!);\n }\n }),\n ACTION: (): ActionAstNode => ({\n type: \"action\",\n attributes: [],\n actionName: \"\",\n actionArguments: [],\n validate() {},\n createNodeInstance() {\n return new Action(this.attributes, this.actionName!, this.actionArguments!);\n }\n }),\n CONDITION: (): ConditionAstNode => ({\n type: \"condition\",\n attributes: [],\n conditionName: \"\",\n conditionArguments: [],\n validate() {},\n createNodeInstance() {\n return new Condition(this.attributes, this.conditionName!, this.conditionArguments!);\n }\n })\n};\n\ntype OtherAstNodes = AstNode[];\n\n/**\n * Create an array of root AST nodes based on the given definition.\n * @param definition The definition to parse the AST nodes from.\n * @returns The base definition AST nodes.\n */\nexport default function buildRootASTNodes(definition: string): RootAstNode[] {\n // Swap out any node/attribute argument string literals with a placeholder and get a mapping of placeholders to original values as well as the processed definition.\n const { placeholders, processedDefinition } = substituteStringLiterals(definition);\n\n // Convert the processed definition (with substituted string literals) into an array of raw tokens.\n const tokens = parseTokensFromDefinition(processedDefinition);\n\n // There must be at least 3 tokens for the tree definition to be valid. 'ROOT', '{' and '}'.\n if (tokens.length < 3) {\n throw new Error(\"invalid token count\");\n }\n\n // We should have a matching number of '{' and '}' tokens. If not, then there are scopes that have not been properly closed.\n if (tokens.filter((token) => token === \"{\").length !== tokens.filter((token) => token === \"}\").length) {\n throw new Error(\"scope character mismatch\");\n }\n\n // Create a stack of node children arrays, starting with a definition scope.\n const stack: [RootAstNode[], ...OtherAstNodes[]] = [[]];\n const rootScope = stack[0];\n\n // We should keep processing the raw tokens until we run out of them.\n while (tokens.length) {\n // Grab the next token.\n const token = tokens.shift();\n\n const currentScope = stack[stack.length - 1] as OtherAstNodes;\n\n // How we create the next AST token depends on the current raw token value.\n switch (token!.toUpperCase()) {\n case \"ROOT\": {\n // Create a ROOT AST node.\n const node = ASTNodeFactories.ROOT();\n\n // Push the ROOT node into the current scope.\n rootScope.push(node);\n\n // We may have a root node name defined as an argument.\n if (tokens[0] === \"[\") {\n const rootArguments = getArguments(tokens, placeholders);\n\n // We should have only a single argument that is not an empty string for a root node, which is the root name identifier.\n if (rootArguments.length === 1 && rootArguments[0].type === \"identifier\") {\n // The root name will be the first and only node argument.\n node.name = rootArguments[0].value as string;\n } else {\n throw new Error(\"expected single root name argument\");\n }\n }\n\n // Try to pick any attributes off of the token stack.\n node.attributes = getAttributes(tokens, placeholders);\n\n popAndCheck(tokens, \"{\");\n\n // The new scope is that of the new ROOT nodes children.\n stack.push(node.children!);\n break;\n }\n\n case \"BRANCH\": {\n // Create a BRANCH AST node.\n const node = ASTNodeFactories.BRANCH();\n\n // Push the BRANCH node into the current scope.\n currentScope.push(node);\n\n // We must have arguments defined, as we require a branch name argument.\n if (tokens[0] !== \"[\") {\n throw new Error(\"expected single branch name argument\");\n }\n\n // The branch name will be defined as a node argument.\n const branchArguments = getArguments(tokens, placeholders);\n\n // We should have only a single identifer argument for a branch node, which is the branch name.\n if (branchArguments.length === 1 && branchArguments[0].type === \"identifier\") {\n // The branch name will be the first and only node argument.\n node.branchName = branchArguments[0].value as string;\n } else {\n throw new Error(\"expected single branch name argument\");\n }\n break;\n }\n\n case \"SELECTOR\": {\n // Create a SELECTOR AST node.\n const node = ASTNodeFactories.SELECTOR();\n\n // Push the SELECTOR node into the current scope.\n currentScope.push(node);\n\n // Try to pick any attributes off of the token stack.\n node.attributes = getAttributes(tokens, placeholders);\n\n popAndCheck(tokens, \"{\");\n\n // The new scope is that of the new SELECTOR nodes children.\n stack.push(node.children!);\n break;\n }\n\n case \"SEQUENCE\": {\n // Create a SEQUENCE AST node.\n const node = ASTNodeFactories.SEQUENCE();\n\n // Push the SEQUENCE node into the current scope.\n currentScope.push(node);\n\n // Try to pick any attributes off of the token stack.\n node.attributes = getAttributes(tokens, placeholders);\n\n popAndCheck(tokens, \"{\");\n\n // The new scope is that of the new SEQUENCE nodes children.\n stack.push(node.children!);\n break;\n }\n\n case \"PARALLEL\": {\n // Create a PARALLEL AST node.\n const node = ASTNodeFactories.PARALLEL();\n\n // Push the PARALLEL node into the current scope.\n currentScope.push(node);\n\n // Try to pick any attributes off of the token stack.\n node.attributes = getAttributes(tokens, placeholders);\n\n popAndCheck(tokens, \"{\");\n\n // The new scope is that of the new PARALLEL nodes children.\n stack.push(node.children!);\n break;\n }\n\n case \"LOTTO\": {\n // Create a LOTTO AST node.\n const node = ASTNodeFactories.LOTTO();\n\n // Push the LOTTO node into the current scope.\n currentScope.push(node);\n\n // If the next token is a '[' character then some ticket counts have been defined as arguments.\n if (tokens[0] === \"[\") {\n // Get the ticket count arguments, each argument must be a number.\n node.tickets = getArguments(\n tokens,\n placeholders,\n (arg) => arg.type === \"number\" && !!arg.isInteger,\n \"lotto node ticket counts must be integer values\"\n ).map((argument) => argument.value as number);\n }\n\n // Try to pick any attributes off of the token stack.\n node.attributes = getAttributes(tokens, placeholders);\n\n popAndCheck(tokens, \"{\");\n\n // The new scope is that of the new LOTTO nodes children.\n stack.push(node.children!);\n break;\n }\n\n case \"CONDITION\": {\n // Create a CONDITION AST node.\n const node = ASTNodeFactories.CONDITION();\n\n // Push the CONDITION node into the current scope.\n currentScope.push(node);\n\n // We must have arguments defined, as we require a condition function name argument.\n if (tokens[0] !== \"[\") {\n throw new Error(\"expected condition name identifier argument\");\n }\n\n // Grab the condition node arguments.\n const conditionArguments = getArguments(tokens, placeholders);\n\n // We should have at least a single identifier argument for a condition node, which is the condition function name.\n if (conditionArguments.length && conditionArguments[0].type === \"identifier\") {\n // The condition function name will be the first node argument.\n node.conditionName = conditionArguments.shift()!.value as string;\n } else {\n throw new Error(\"expected condition name identifier argument\");\n }\n\n // Only the first argument should have been an identifier, all following arguments must be string, number, boolean or null.\n conditionArguments\n .filter((arg) => arg.type === \"identifier\")\n .forEach((arg) => {\n throw new Error(\n \"invalid condition node argument value '\" +\n arg.value +\n \"', must be string, number, boolean or null\"\n );\n });\n\n // Any node arguments that follow the condition name identifier will be treated as condition function arguments.\n node.conditionArguments = conditionArguments;\n\n // Try to pick any attributes off of the token stack.\n node.attributes = getAttributes(tokens, placeholders);\n break;\n }\n\n case \"FLIP\": {\n // Create a FLIP AST node.\n const node = ASTNodeFactories.FLIP();\n\n // Push the Flip node into the current scope.\n currentScope.push(node);\n\n // Try to pick any attributes off of the token stack.\n node.attributes = getAttributes(tokens, placeholders);\n\n popAndCheck(tokens, \"{\");\n\n // The new scope is that of the new FLIP nodes children.\n stack.push(node.children!);\n break;\n }\n\n case \"SUCCEED\": {\n // Create a SUCCEED AST node.\n const node = ASTNodeFactories.SUCCEED();\n\n // Push the Succeed node into the current scope.\n currentScope.push(node);\n\n // Try to pick any attributes off of the token stack.\n node.attributes = getAttributes(tokens, placeholders);\n\n popAndCheck(tokens, \"{\");\n\n // The new scope is that of the new Succeed nodes children.\n stack.push(node.children!);\n break;\n }\n\n case \"FAIL\": {\n // Create a FAIL AST node.\n const node = ASTNodeFactories.FAIL();\n\n // Push the Fail node into the current scope.\n currentScope.push(node);\n\n // Try to pick any attributes off of the token stack.\n node.attributes = getAttributes(tokens, placeholders);\n\n popAndCheck(tokens, \"{\");\n\n // The new scope is that of the new Fail nodes children.\n stack.push(node.children!);\n break;\n }\n\n case \"WAIT\": {\n // Create a WAIT AST node.\n const node = ASTNodeFactories.WAIT();\n\n // Push the WAIT node into the current scope.\n currentScope.push(node);\n\n // Get the duration and potential longest duration of the wait.\n const durations = getArguments(\n tokens,\n placeholders,\n (arg) => arg.type === \"number\" && !!arg.isInteger,\n \"wait node durations must be integer values\"\n ).map((argument) => argument.value);\n\n // We should have got one or two durations.\n if (durations.length === 1) {\n // A static duration was defined.\n node.duration = durations[0] as number;\n } else if (durations.length === 2) {\n // A shortest and longest duration was defined.\n node.duration = durations[0] as number;\n node.longestDuration = durations[1] as number;\n } else {\n // An incorrect number of durations was defined.\n throw new Error(\"invalid number of wait node duration arguments defined\");\n }\n\n // Try to pick any attributes off of the token stack.\n node.attributes = getAttributes(tokens, placeholders);\n break;\n }\n\n case \"REPEAT\": {\n // Create a REPEAT AST node.\n const node = ASTNodeFactories.REPEAT();\n\n // Push the REPEAT node into the current scope.\n currentScope.push(node);\n\n // Check for iteration counts ([])\n if (tokens[0] === \"[\") {\n // An iteration count has been defined. Get the iteration and potential maximum iteration of the wait.\n const iterationArguments = getArguments(\n tokens,\n placeholders,\n (arg) => arg.type === \"number\" && !!arg.isInteger,\n \"repeat node iteration counts must be integer values\"\n ).map((argument) => argument.value);\n\n // We should have got one or two iteration counts.\n if (iterationArguments.length === 1) {\n // A static iteration count was defined.\n node.iterations = iterationArguments[0] as number;\n } else if (iterationArguments.length === 2) {\n // A minimum and maximum iteration count was defined.\n node.iterations = iterationArguments[0] as number;\n node.maximumIterations = iterationArguments[1] as number;\n } else {\n // An incorrect number of iteration counts was defined.\n throw new Error(\"invalid number of repeat node iteration count arguments defined\");\n }\n }\n\n // Try to pick any attributes off of the token stack.\n node.attributes = getAttributes(tokens, placeholders);\n\n popAndCheck(tokens, \"{\");\n\n // The new scope is that of the new REPEAT nodes children.\n stack.push(node.children!);\n break;\n }\n\n case \"RETRY\": {\n // Create a RETRY AST node.\n const node = ASTNodeFactories.RETRY();\n\n // Push the RETRY node into the current scope.\n currentScope.push(node);\n\n // Check for iteration counts ([])\n if (tokens[0] === \"[\") {\n // An iteration count has been defined. Get the iteration and potential maximum iteration of the wait.\n const iterationArguments = getArguments(\n tokens,\n placeholders,\n (arg) => arg.type === \"number\" && !!arg.isInteger,\n \"retry node iteration counts must be integer values\"\n ).map((argument) => argument.value);\n\n // We should have got one or two iteration counts.\n if (iterationArguments.length === 1) {\n // A static iteration count was defined.\n node.iterations = iterationArguments[0] as number;\n } else if (iterationArguments.length === 2) {\n // A minimum and maximum iteration count was defined.\n node.iterations = iterationArguments[0] as number;\n node.maximumIterations = iterationArguments[1] as number;\n } else {\n // An incorrect number of iteration counts was defined.\n throw new Error(\"invalid number of retry node iteration count arguments defined\");\n }\n }\n\n // Try to pick any attributes off of the token stack.\n node.attributes = getAttributes(tokens, placeholders);\n\n popAndCheck(tokens, \"{\");\n\n // The new scope is that of the new RETRY nodes children.\n stack.push(node.children!);\n break;\n }\n\n case \"ACTION\": {\n // Create a ACTION AST node.\n const node = ASTNodeFactories.ACTION();\n\n // Push the ACTION node into the current scope.\n currentScope.push(node);\n\n // We must have arguments defined, as we require an action name argument.\n if (tokens[0] !== \"[\") {\n throw new Error(\"expected action name identifier argument\");\n }\n\n // The action name will be defined as a node argument.\n const actionArguments = getArguments(tokens, placeholders);\n\n // We should have at least one identifer argument for an action node, which is the action name.\n if (actionArguments.length && actionArguments[0].type === \"identifier\") {\n // The action name will be the first and only node argument.\n node.actionName = actionArguments.shift()!.value as string;\n } else {\n throw new Error(\"expected action name identifier argument\");\n }\n\n // Only the first argument should have been an identifier, all following arguments must be string, number, boolean or null.\n actionArguments\n .filter((arg) => arg.type === \"identifier\")\n .forEach((arg) => {\n throw new Error(\n \"invalid action node argument value '\" +\n arg.value +\n \"', must be string, number, boolean or null\"\n );\n });\n\n // Any node arguments that follow the action name identifier will be treated as action function arguments.\n node.actionArguments = actionArguments;\n\n // Try to pick any attributes off of the token stack.\n node.attributes = getAttributes(tokens, placeholders);\n break;\n }\n\n case \"}\": {\n // The '}' character closes the current scope.\n stack.pop();\n break;\n }\n\n default: {\n throw new Error(\"unexpected token: \" + token);\n }\n }\n }\n\n // A function to recursively validate each of the nodes in the AST.\n const validateASTNode = (node: Validatable, depth: number): void => {\n // Validate the node.\n node.validate(depth);\n\n // Validate each child of the node.\n (node.children || []).forEach((child) => validateASTNode(child, depth + 1));\n };\n\n // Start node validation from the definition root.\n validateASTNode(\n {\n children: stack[0] as RootAstNode[],\n validate(this: { children: RootAstNode[] }) {\n // We must have at least one node defined as the definition scope, which should be a root node.\n if (this.children.length === 0) {\n throw new Error(\"expected root node to have been defined\");\n }\n\n // Each node at the base of the definition scope MUST be a root node.\n for (const definitionLevelNode of this.children) {\n if (definitionLevelNode.type !== \"root\") {\n throw new Error(\"expected root node at base of definition\");\n }\n }\n\n // Exactly one root node must not have a name defined. This will be the main root, others will have to be referenced via branch nodes.\n if (this.children.filter((definitionLevelNode) => definitionLevelNode.name === null).length !== 1) {\n throw new Error(\"expected single unnamed root node at base of definition to act as main root\");\n }\n\n // No two named root nodes can have matching names.\n const rootNodeNames: string[] = [];\n for (const definitionLevelNode of this.children) {\n if (rootNodeNames.indexOf(definitionLevelNode.name!) !== -1) {\n throw new Error(`multiple root nodes found with duplicate name '${definitionLevelNode.name}'`);\n } else {\n rootNodeNames.push(definitionLevelNode.name!);\n }\n }\n }\n },\n 0\n );\n\n // Return the root AST nodes.\n return stack[0];\n}\n\n/**\n * Pop the next raw token off of the stack and throw an error if it wasn't the expected one.\n * @param tokens The array of remaining tokens.\n * @param expected An optional string or array or items, one of which must match the next popped token.\n * @returns The popped token.\n */\nfunction popAndCheck(tokens: string[], expected: string | string[]) {\n // Get and remove the next token.\n const popped = tokens.shift();\n\n // We were expecting another token.\n if (popped === undefined) {\n throw new Error(\"unexpected end of definition\");\n }\n\n // Do we have an expected token/tokens array?\n if (expected !== undefined) {\n // Check whether the popped token matches at least one of our expected items.\n var tokenMatchesExpectation = ([] as string[])\n .concat(expected)\n .some((item) => popped.toUpperCase() === item.toUpperCase());\n\n // Throw an error if the popped token didn't match any of our expected items.\n if (!tokenMatchesExpectation) {\n const expectationString = ([] as string[])\n .concat(expected)\n .map((item) => \"'\" + item + \"'\")\n .join(\" or \");\n throw new Error(\"unexpected token found. Expected \" + expectationString + \" but got '\" + popped + \"'\");\n }\n }\n\n // Return the popped token.\n return popped;\n}\n\ntype Placeholders = { [key: string]: string };\n\n/**\n * Pull an argument definition list off of the token stack.\n * @param tokens The array of remaining tokens.\n * @param stringArgumentPlaceholders The mapping of string literal node argument placeholders to original values.\n * @param argumentValidator The argument validator function.\n * @param validationFailedMessage The exception message to throw if argument validation fails.\n * @returns The argument definition list.\n */\nfunction getArguments(\n tokens: string[],\n stringArgumentPlaceholders: Placeholders,\n argumentValidator?: (arg: AnyArgument) => boolean,\n validationFailedMessage?: string\n) {\n // Any lists of arguments will always be wrapped in '[]' for node arguments or '()' for attribute arguments.\n // We are looking for a '[' or '(' opener that wraps the argument tokens and the relevant closer.\n const closer = popAndCheck(tokens, [\"[\", \"(\"]) === \"[\" ? \"]\" : \")\";\n\n const argumentListTokens: string[] = [];\n const argumentList: AnyArgument[] = [];\n\n // Grab all tokens between the '[' and ']' or '(' and ')'.\n while (tokens.length && tokens[0] !== closer) {\n // The next token is part of our arguments list.\n argumentListTokens.push(tokens.shift()!);\n }\n\n // Validate the order of the argument tokens. Each token must either be a ',' or a single argument that satisfies the validator.\n argumentListTokens.forEach((token, index) => {\n // Get whether this token should be an actual argument.\n const shouldBeArgumentToken = !(index & 1);\n\n // If the current token should be an actual argument then validate it,otherwise it should be a ',' token.\n if (shouldBeArgumentToken) {\n // Get the argument definition.\n const argumentDefinition = getArgumentDefinition(token!, stringArgumentPlaceholders);\n\n // Try to validate the argument.\n if (argumentValidator && !argumentValidator(argumentDefinition)) {\n throw new Error(validationFailedMessage);\n }\n\n // This is a valid argument!\n argumentList.push(argumentDefinition);\n } else {\n // The current token should be a ',' token.\n if (token !== \",\") {\n throw new Error(`invalid argument list, expected ',' or ']' but got '${token}'`);\n }\n }\n });\n\n // The arguments list should terminate with a ']' or ')' token, depending on the opener.\n popAndCheck(tokens, closer);\n\n // Return the argument list.\n return argumentList;\n}\n\n/**\n * Gets an argument value definition.\n * @param token The argument token.\n * @param stringArgumentPlaceholders The mapping of string literal node argument placeholders to original values.\n * @returns An argument value definition.\n */\nfunction getArgumentDefinition(token: string, stringArgumentPlaceholders: Placeholders): AnyArgument {\n // Check whether the token represents a null value.\n if (token === \"null\") {\n return {\n value: null,\n type: \"null\"\n } as NullArgument;\n }\n\n // Check whether the token represents a boolean value.\n if (token === \"true\" || token === \"false\") {\n return {\n value: token === \"true\",\n type: \"boolean\"\n } as BooleanArgument;\n }\n\n // Check whether the token represents a number value.\n // TODO: Relies on broken isNaN - see MDN.\n // if (!Number.isNaN(token)) {\n if (!isNaN(token as any)) {\n return {\n value: parseFloat(token),\n isInteger: parseFloat(token) === parseInt(token, 10),\n type: \"number\"\n } as NumberArgument;\n }\n\n // Check whether the token is a placeholder (e.g. @@0@@) representing a string literal.\n if (token.match(/^@@\\d+@@$/g)) {\n return {\n value: stringArgumentPlaceholders[token].replace('\\\\\"', '\"'),\n type: \"string\"\n } as StringPlaceholderArgument;\n }\n\n // The only remaining option is that the argument value is an identifier.\n return {\n value: token,\n type: \"identifier\"\n } as IdentifierArgument;\n}\n\n/**\n * Pull any attributes off of the token stack.\n * @param tokens The array of remaining tokens.\n * @param stringArgumentPlaceholders The mapping of string literal node argument placeholders to original values.\n * @returns An array of attributes defined by any directly following tokens.\n */\nfunction getAttributes(tokens: string[], stringArgumentPlaceholders: Placeholders) {\n // Create an array to hold any attributes found.\n const attributes: Attribute[] = [];\n\n // Keep track of names of attribute that we have found on the token stack, as we cannot have duplicates.\n const attributesFound: string[] = [];\n\n // Try to get the attribute factory for the next token.\n let attributeFactory = AttributeFactories[(tokens[0] || \"\").toUpperCase()];\n\n // Pull attribute tokens off of the tokens stack until we have no more.\n while (attributeFactory) {\n // Check to make sure that we have not already created a attribute of this type for this node.\n if (attributesFound.indexOf(tokens[0].toUpperCase()) !== -1) {\n throw new Error(`duplicate attribute '${tokens[0].toUpperCase()}' found for node`);\n }\n\n // Add the current attribute type to our array of found attributes.\n attributesFound.push(tokens.shift()!.toUpperCase());\n\n // Grab any attribute arguments.\n const attributeArguments = getArguments(tokens, stringArgumentPlaceholders);\n\n // The first attribute argument has to be an identifer, this will reference an agent function.\n if (attributeArguments.length === 0 || attributeArguments[0].type !== \"identifier\") {\n throw new Error(\"expected agent function name identifier argument for attribute\");\n }\n\n // Grab the first attribute which is an identifier that will reference an agent function.\n const attributeFunctionName = attributeArguments.shift()! as IdentifierArgument;\n\n // Any remaining attribute arguments must have a type of string, number, boolean or null.\n attributeArguments\n .filter((arg) => arg.type === \"identifier\")\n .forEach((arg) => {\n throw new Error(\n \"invalid attribute argument value '\" + arg.value + \"', must be string, number, boolean or null\"\n );\n });\n\n // Create the attribute and add it to the array of attributes found.\n attributes.push(attributeFactory(attributeFunctionName.value, attributeArguments));\n\n // Try to get the next attribute name token, as there could be multiple.\n attributeFactory = AttributeFactories[(tokens[0] || \"\").toUpperCase()];\n }\n\n return attributes;\n}\n\n/**\n * Swaps out any node/attribute argument string literals with placeholders.\n * @param definition The definition.\n * @returns An object containing a mapping of placeholders to original string values as well as the processed definition string.\n */\nfunction substituteStringLiterals(definition: string): {\n placeholders: { [key: string]: string };\n processedDefinition: string;\n} {\n // Create an object to hold the mapping of placeholders to original string values.\n const placeholders: Placeholders = {};\n\n // Replace any string literals wrapped with double quotes in our definition with placeholders to be processed later.\n const processedDefinition = definition.replace(/\\\"(\\\\.|[^\"\\\\])*\\\"/g, (match) => {\n var strippedMatch = match.substring(1, match.length - 1);\n var placeholder = Object.keys(placeholders).find((key) => placeholders[key] === strippedMatch);\n\n // If we have no existing string literal match then create a new placeholder.\n if (!placeholder) {\n placeholder = `@@${Object.keys(placeholders).length}@@`;\n placeholders[placeholder] = strippedMatch;\n }\n\n return placeholder;\n });\n\n return { placeholders, processedDefinition };\n}\n\n/**\n * Parse the tree definition into an array of raw tokens.\n * @param definition The definition.\n * @returns An array of tokens parsed from the definition.\n */\nfunction parseTokensFromDefinition(definition: string): string[] {\n // Add some space around various important characters so that they can be plucked out easier as individual tokens.\n definition = definition.replace(/\\(/g, \" ( \");\n definition = definition.replace(/\\)/g, \" ) \");\n definition = definition.replace(/\\{/g, \" { \");\n definition = definition.replace(/\\}/g, \" } \");\n definition = definition.replace(/\\]/g, \" ] \");\n definition = definition.replace(/\\[/g, \" [ \");\n definition = definition.replace(/\\,/g, \" , \");\n\n // Split the definition into raw token form and return it.\n return definition.replace(/\\s+/g, \" \").trim().split(\" \");\n}\n", "import GuardPath, { GuardPathPart } from \"./attributes/guards/GuardPath\";\nimport buildRootASTNodes, { AnyArgument, RootAstNode } from \"./RootAstNodesBuilder\";\nimport State, { AnyState } from \"./State\";\nimport Lookup from \"./Lookup\";\nimport Node from \"./nodes/Node\";\nimport Root from \"./nodes/decorator/Root\";\nimport Composite from \"./nodes/composite/Composite\";\nimport Decorator from \"./nodes/decorator/Decorator\";\nimport { Agent, GlobalFunction } from \"./Agent\";\nimport { CallbackAttributeDetails } from \"./attributes/callbacks/Callback\";\nimport { GuardAttributeDetails } from \"./attributes/guards/Guard\";\nimport { BehaviourTreeOptions } from \"./BehaviourTreeOptions\";\n\n// Purely for outside inspection of the tree.\nexport type FlattenedTreeNode = {\n id: string;\n type: string;\n caption: string;\n state: AnyState;\n guards: GuardAttributeDetails[];\n callbacks: CallbackAttributeDetails[];\n args: AnyArgument[];\n parentId: string | null;\n};\n\n/**\n * A representation of a behaviour tree.\n */\nexport class BehaviourTree {\n /**\n * The main root tree node.\n */\n public readonly rootNode: Root;\n\n /**\n * Creates a new instance of the BehaviourTree class.\n * @param definition The behaviour tree definition.\n * @param agent The agent instance that this behaviour tree is modelling behaviour for.\n * @param options The behaviour tree options object.\n */\n constructor(definition: string, private agent: Agent, private options: BehaviourTreeOptions = {}) {\n // The tree definition must be defined and a valid string.\n if (typeof definition !== \"string\") {\n throw new Error(\"the tree definition must be a string\");\n }\n\n // The agent must be defined and not null.\n if (typeof agent !== \"object\" || agent === null) {\n throw new Error(\"the agent must be defined and not null\");\n }\n\n // Parse the behaviour tree definition, create the populated tree of behaviour tree nodes, and get the root.\n this.rootNode = BehaviourTree.createRootNode(definition);\n }\n\n /**\n * Gets whether the tree is in the RUNNING state.\n * @returns true if the tree is in the RUNNING state, otherwise false.\n */\n isRunning() {\n return this.rootNode.getState() === State.RUNNING;\n }\n\n /**\n * Gets the current tree state of SUCCEEDED, FAILED, READY or RUNNING.\n * @returns The current tree state.\n */\n getState() {\n return this.rootNode.getState();\n }\n\n /**\n * Step the tree.\n * 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.\n * 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\n * 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.\n *\n * 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.\n */\n step() {\n // If the root node has already been stepped to completion then we need to reset it.\n if (this.rootNode.getState() === State.SUCCEEDED || this.rootNode.getState() === State.FAILED) {\n this.rootNode.reset();\n }\n\n try {\n this.rootNode.update(this.agent, this.options);\n } catch (exception) {\n throw new Error(`error stepping tree: ${(exception as Error).message}`);\n }\n }\n\n /**\n * Resets the tree from the root node outwards to each nested node, giving each a state of READY.\n */\n reset() {\n this.rootNode.reset();\n }\n\n /**\n * Gets the flattened details of every node in the tree.\n * @returns The flattened details of every node in the tree.\n */\n getFlattenedNodeDetails(): FlattenedTreeNode[] {\n // Create an empty flattened array of tree nodes.\n const flattenedTreeNodes: FlattenedTreeNode[] = [];\n\n /**\n * Helper function to process a node instance and push details into the flattened tree nodes array.\n * @param node The current node.\n * @param parentUid The UID of the node parent, or null if the node is the main root node.\n */\n const processNode = (node: Node, parentUid: string | null) => {\n // Get the guard and callback attribute details for this node.\n const guards = node\n .getAttributes()\n .filter((attribute) => attribute.isGuard())\n .map((attribute) => attribute.getDetails()) as GuardAttributeDetails[];\n const callbacks = node\n .getAttributes()\n .filter((attribute) => !attribute.isGuard())\n .map((attribute) => attribute.getDetails()) as CallbackAttributeDetails[];\n\n // Push the current node into the flattened nodes array.\n flattenedTreeNodes.push({\n id: node.getUid(),\n type: node.getType(),\n caption: node.getName(),\n state: node.getState(),\n guards,\n callbacks,\n args: node.getArguments(),\n parentId: parentUid\n });\n\n // Process each of the nodes children if it is not a leaf node.\n if (!node.isLeafNode()) {\n (node as Composite | Decorator)\n .getChildren()\n .forEach((child) => processNode(child, (node as Composite | Decorator).getUid()));\n }\n };\n\n // Convert the nested node structure into a flattened array of node details.\n processNode(this.rootNode, null);\n\n return flattenedTreeNodes;\n }\n\n /**\n * Registers the action/condition/guard/callback function or subtree with the given name.\n * @param name The name of the function or subtree to register.\n * @param value The function or subtree definition to register.\n */\n static register(name: string, value: GlobalFunction | string) {\n if (typeof value === \"function\") {\n // We are going to register a action/condition/guard/callback function.\n Lookup.setFunc(name, value);\n } else if (typeof value === \"string\") {\n // We are going to register a subtree.\n let rootASTNodes: RootAstNode[];\n\n try {\n // Try to create the behaviour tree AST based on the definition provided, this could fail if the definition is invalid.\n rootASTNodes = buildRootASTNodes(value);\n } catch (exception) {\n // There was an issue in trying to parse and build the tree definition.\n throw new Error(`error registering definition: ${(exception as Error).message}`);\n }\n\n // This function should only ever be called with a definition containing a single unnamed root node.\n if (rootASTNodes.length != 1 || rootASTNodes[0].name !== null) {\n throw new Error(\"error registering definition: expected a single unnamed root node\");\n }\n\n Lookup.setSubtree(name, rootASTNodes[0]);\n } else {\n throw new Error(\"unexpected value, expected string definition or function\");\n }\n }\n\n /**\n * Unregisters the registered action/condition/guard/callback function or subtree with the given name.\n * @param name The name of the registered action/condition/guard/callback function or subtree to unregister.\n */\n static unregister(name: string): void {\n Lookup.remove(name);\n }\n\n /**\n * Unregister all registered action/condition/guard/callback functions and subtrees.\n */\n static unregisterAll(): void {\n Lookup.empty();\n }\n\n /**\n * Parses a behaviour tree definition and creates a tree of behaviour tree nodes.\n * @param {string} definition The behaviour tree definition.\n * @returns The root behaviour tree node.\n */\n private static createRootNode(definition: string): Root {\n try {\n // Try to create the behaviour tree AST based on the definition provided, this could fail if the definition is invalid.\n const rootASTNodes = buildRootASTNodes(definition);\n\n // Create a symbol to use as the main root key in our root node mapping.\n const mainRootNodeKey = Symbol(\"__root__\");\n\n // Create a mapping of root node names to root AST tokens. The main root node will have a key of Symbol(\"__root__\").\n const rootNodeMap: { [key: string | symbol]: RootAstNode } = {};\n for (const rootASTNode of rootASTNodes) {\n rootNodeMap[rootASTNode.name === null ? mainRootNodeKey : rootASTNode.name!] = rootASTNode;\n }\n\n // Convert the AST to our actual tree and get the root node.\n const rootNode: Root = rootNodeMap[mainRootNodeKey].createNodeInstance(\n // Create a provider for named root nodes that are part of our definition or have been registered. Prioritising the former.\n (name: string): RootAstNode => (rootNodeMap[name] ? rootNodeMap[name] : Lookup.getSubtree(name)),\n []\n );\n\n // Set a guard path on every leaf of the tree to evaluate as part of its update.\n BehaviourTree.applyLeafNodeGuardPaths(rootNode);\n\n // Return the root node.\n return rootNode;\n } catch (exception) {\n // There was an issue in trying to parse and build the tree definition.\n throw new Error(`error parsing tree: ${(exception as Error).message}\\n${(exception as Error).stack}`);\n }\n }\n\n /**\n * Applies a guard path to every leaf of the tree to evaluate as part of each update.\n * @param rootNode The main root tree node.\n */\n private static applyLeafNodeGuardPaths(rootNode: Root) {\n const nodePaths: Node[][] = [];\n\n const findLeafNodes = (path: Node[], node: Node) => {\n // Add the current node to the path.\n path = path.concat(node);\n\n // Check whether the current node is a leaf node.\n if (node.isLeafNode()) {\n nodePaths.push(path);\n } else {\n (node as Composite | Decorator).getChildren().forEach((child) => findLeafNodes(path, child));\n }\n };\n\n // Find all leaf node paths, starting from the root.\n findLeafNodes([], rootNode);\n\n nodePaths.forEach((path) => {\n // Each node in the current path will have to be assigned a guard path, working from the root outwards.\n for (let depth = 0; depth < path.length; depth++) {\n // Get the node in the path at the current depth.\n const currentNode = path[depth];\n\n // The node may already have been assigned a guard path, if so just skip it.\n if (currentNode.hasGuardPath()) {\n continue;\n }\n\n // Create the guard path for the current node.\n const guardPath = new GuardPath(\n path\n .slice(0, depth + 1)\n .map((node) => ({ node, guards: node.getGuardAttributes() }))\n .filter((details) => details.guards.length > 0)\n );\n\n // Assign the guard path to the current node.\n currentNode.setGuardPath(guardPath);\n }\n });\n }\n}\n"], - "mappings": "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", - "names": ["Participant", "Lotto", "createLotto", "State", "createLotto"] + "sources": ["../node_modules/lotto-draw/dist/Participant.js", "../node_modules/lotto-draw/dist/Utilities.js", "../node_modules/lotto-draw/dist/Lotto.js", "../node_modules/lotto-draw/dist/createLotto.js", "../node_modules/lotto-draw/dist/index.js", "../src/index.ts", "../src/attributes/guards/GuardUnsatisifedException.ts", "../src/attributes/guards/GuardPath.ts", "../src/State.ts", "../src/nodes/Node.ts", "../src/nodes/leaf/Leaf.ts", "../src/Lookup.ts", "../src/nodes/leaf/Action.ts", "../src/nodes/leaf/Condition.ts", "../src/nodes/leaf/Wait.ts", "../src/nodes/decorator/Decorator.ts", "../src/nodes/decorator/Root.ts", "../src/nodes/decorator/Repeat.ts", "../src/nodes/decorator/Retry.ts", "../src/nodes/decorator/Flip.ts", "../src/nodes/decorator/Succeed.ts", "../src/nodes/decorator/Fail.ts", "../src/nodes/composite/Lotto.ts", "../src/nodes/composite/Composite.ts", "../src/nodes/composite/Selector.ts", "../src/nodes/composite/Sequence.ts", "../src/nodes/composite/Parallel.ts", "../src/attributes/Attribute.ts", "../src/attributes/guards/Guard.ts", "../src/attributes/guards/While.ts", "../src/attributes/guards/Until.ts", "../src/attributes/callbacks/Callback.ts", "../src/attributes/callbacks/Entry.ts", "../src/attributes/callbacks/Exit.ts", "../src/attributes/callbacks/Step.ts", "../src/RootAstNodesBuilder.ts", "../src/dsl/DSLUtilities.ts", "../src/dsl/DSLDefinitionParser.ts", "../src/BehaviourTree.ts"], + "sourcesContent": ["\"use strict\";\r\nObject.defineProperty(exports, \"__esModule\", { value: true });\r\nexports.Participant = void 0;\r\n/**\r\n * A participant that holds a number of tickets.\r\n */\r\nvar Participant = /** @class */ (function () {\r\n /**\r\n * Creates an instance of the Participant class.\r\n * @param participant The actual participant.\r\n * @param tickets The number of tickets held by the participant.\r\n */\r\n function Participant(participant, tickets) {\r\n if (tickets === void 0) { tickets = 1; }\r\n this._participant = participant;\r\n this._tickets = tickets;\r\n }\r\n Object.defineProperty(Participant.prototype, \"participant\", {\r\n /** Gets the actual participant. */\r\n get: function () {\r\n return this._participant;\r\n },\r\n enumerable: false,\r\n configurable: true\r\n });\r\n Object.defineProperty(Participant.prototype, \"tickets\", {\r\n /** Gets or sets the number of tickets held by the participant. */\r\n get: function () {\r\n return this._tickets;\r\n },\r\n set: function (value) {\r\n this._tickets = value;\r\n },\r\n enumerable: false,\r\n configurable: true\r\n });\r\n return Participant;\r\n}());\r\nexports.Participant = Participant;\r\n", "\"use strict\";\r\nObject.defineProperty(exports, \"__esModule\", { value: true });\r\nexports.isNaturalNumber = exports.isNullOrUndefined = void 0;\r\n/**\r\n * Gets whether the value provided is null or undefined.\r\n * @param value The value to check.\r\n * @returns Whether the value provided is null or undefined.\r\n */\r\nfunction isNullOrUndefined(value) {\r\n return value === null || value === undefined;\r\n}\r\nexports.isNullOrUndefined = isNullOrUndefined;\r\n/**\r\n * Gets whether the value provided is a natural number.\r\n * @param value The value to check.\r\n * @returns Whether the value provided is a natural number.\r\n */\r\nfunction isNaturalNumber(value) {\r\n return typeof value === \"number\" && value >= 1 && Math.floor(value) === value;\r\n}\r\nexports.isNaturalNumber = isNaturalNumber;\r\n", "\"use strict\";\r\nObject.defineProperty(exports, \"__esModule\", { value: true });\r\nexports.Lotto = void 0;\r\nvar Participant_1 = require(\"./Participant\");\r\nvar Utilities_1 = require(\"./Utilities\");\r\n/**\r\n * Represents a lotto consisting of a number of pickable ticket-holding participants.\r\n */\r\nvar Lotto = /** @class */ (function () {\r\n /**\r\n * Creates a new instance of Lotto.\r\n * @param customRandom The custom RNG to use in place of Math.random().\r\n */\r\n function Lotto(customRandom) {\r\n /** The array of participants that are holding tickets in the lotto. */\r\n this._participants = [];\r\n this._customRandom = customRandom;\r\n }\r\n /**\r\n * Adds a participant with the specified number of tickets, or adds to the participant ticket count if the participant already holds tickets.\r\n * @param participant The participant to add or to increase the ticket count for if they already hold tickets.\r\n * @param tickets The number of tickets, defaults to 1.\r\n * @returns The Lotto instance.\r\n */\r\n Lotto.prototype.add = function (participant, tickets) {\r\n if (tickets === void 0) { tickets = 1; }\r\n // Check that we have a valid ticket count.\r\n if (!(0, Utilities_1.isNaturalNumber)(tickets)) {\r\n throw new Error(\"tickets value must be a natural number\");\r\n }\r\n // Check whether this participant has already been added.\r\n var existingParticipant = this._participants.find(function (part) { return part.participant === participant; });\r\n if (existingParticipant) {\r\n // The participant has already been added to the lotto so just add to their ticket count.\r\n existingParticipant.tickets += tickets;\r\n }\r\n else {\r\n // The participant is not part of the lotto so we should add them.\r\n this._participants.push(new Participant_1.Participant(participant, tickets));\r\n }\r\n return this;\r\n };\r\n /**\r\n * Removes the specified number of tickets for the given participant from the draw, or all tickets if a ticket number is not defined.\r\n * @param participant The participant to remove tickets for.\r\n * @param tickets The number of tickets to remove, or undefined if all tickets are to be removed.\r\n * @returns The Lotto instance.\r\n */\r\n Lotto.prototype.remove = function (participant, tickets) {\r\n // Attempt to get the existing participant.\r\n var existingParticipant = this._participants.find(function (part) { return part.participant === participant; });\r\n // There is nothing to do if the specified participant isn't even part of the lotto.\r\n if (!existingParticipant) {\r\n return this;\r\n }\r\n // Check whether a tickets value was given.\r\n if (tickets !== undefined) {\r\n // Check that we have a valid ticket count.\r\n if (!(0, Utilities_1.isNaturalNumber)(tickets)) {\r\n throw new Error(\"tickets value must be a natural number\");\r\n }\r\n existingParticipant.tickets -= tickets;\r\n // If the participant no longer holds any tickets then they should be removed.\r\n if (existingParticipant.tickets < 1) {\r\n this._participants = this._participants.filter(function (part) { return part !== existingParticipant; });\r\n }\r\n }\r\n else {\r\n // We are removing all tickets for the participant so just remove them from the lotto.\r\n this._participants = this._participants.filter(function (part) { return part !== existingParticipant; });\r\n }\r\n return this;\r\n };\r\n /**\r\n * Draw a winning ticket and return the participant that holds the ticket.\r\n * @param options The draw options.\r\n * @returns The participant that holds the winning ticket.\r\n */\r\n Lotto.prototype.draw = function (options) {\r\n if (options === void 0) { options = {}; }\r\n // If we have no participants then just return null.\r\n if (this._participants.length === 0) {\r\n return null;\r\n }\r\n var redrawable = (0, Utilities_1.isNullOrUndefined)(options.redrawable) ? true : options.redrawable;\r\n var pickable = [];\r\n this._participants.forEach(function (_a) {\r\n var participant = _a.participant, tickets = _a.tickets;\r\n for (var ticketCount = 0; ticketCount < tickets; ticketCount++) {\r\n pickable.push(participant);\r\n }\r\n });\r\n var random;\r\n // We need a random floating-point number between 0 (inclusive) and 1 to scale up to pick our winner.\r\n // If a custom random function exists then we should use that or fall back to Math.random().\r\n if (this._customRandom) {\r\n // Call our custom random function to get a random floating-point number.\r\n random = this._customRandom();\r\n // Verify that the result of calling our custom random function is a number between 0 (inclusive) and 1.\r\n if (typeof random !== \"number\" || random < 0 || random >= 1) {\r\n throw new Error(\"the 'random' function provided did not return a number between 0 (inclusive) and 1\");\r\n }\r\n }\r\n else {\r\n // No custom random function was defined so just use good ol' Math.random().\r\n random = Math.random();\r\n }\r\n // Pick a winning participant.\r\n var winner = pickable[Math.floor(random * pickable.length)];\r\n // If the ticket isn't redrawable then we should remove a ticket from the winning participants ticket count.\r\n if (!redrawable) {\r\n this.remove(winner, 1);\r\n }\r\n // Return the winning participant.\r\n return winner;\r\n };\r\n /**\r\n * Draws multiple winning tickets and return an array of the participants that hold the winning tickets.\r\n * @param tickets The number of winning tickets to draw.\r\n * @param options The draw multiple options.\r\n * @returns An array of the participants that hold the winning tickets.\r\n */\r\n Lotto.prototype.drawMultiple = function (tickets, options) {\r\n if (options === void 0) { options = {}; }\r\n var uniqueResults = (0, Utilities_1.isNullOrUndefined)(options.unique) ? false : options.unique;\r\n // Handle cases where the user has asked for zero tickets (no idea why they would do this be we should trust them).\r\n if (tickets === 0) {\r\n return [];\r\n }\r\n // Now that we know out tickets value is not zero we should check that it is a valid natural number.\r\n if (!(0, Utilities_1.isNaturalNumber)(tickets)) {\r\n throw new Error(\"tickets value must be a natural number\");\r\n }\r\n var result = [];\r\n // Keep drawing tickets until we either reach the number of required tickets or we simply run out of tickets to draw.\r\n // We can run out of tickets to draw if 'options.redrawable' is explicity 'false' or we just had no participants when 'drawMultiple' was called.\r\n while (result.length < tickets && this._participants.length > 0) {\r\n result.push(this.draw(options));\r\n }\r\n // If the 'unique' draw option is set then we need to remove duplicates from the result list.\r\n if (uniqueResults) {\r\n // Create an array to store our unique results.\r\n var unique = [];\r\n // Iterate over all of our participants (with potential duplicates) and populate our array of unique values.\r\n for (var _i = 0, result_1 = result; _i < result_1.length; _i++) {\r\n var participant = result_1[_i];\r\n if (unique.indexOf(participant) === -1) {\r\n unique.push(participant);\r\n }\r\n }\r\n result = unique;\r\n }\r\n return result;\r\n };\r\n return Lotto;\r\n}());\r\nexports.Lotto = Lotto;\r\n", "\"use strict\";\r\nObject.defineProperty(exports, \"__esModule\", { value: true });\r\nexports.createLotto = void 0;\r\nvar Lotto_1 = require(\"./Lotto\");\r\n/**\r\n * A function that creates and returns a Lotto instance.\r\n * @param participantsOrOptions An array of initial participants or options relating to the creation of a Lotto instance.\r\n * @returns A new Lotto instance.\r\n */\r\nfunction createLotto(participantsOrOptions) {\r\n // If no initial participants or lotto options were provided as an argument then we can just return a new lotto instance now.\r\n if (!participantsOrOptions) {\r\n return new Lotto_1.Lotto();\r\n }\r\n // Check whether we were provided with an array of initial participants or a lotto options object.\r\n if (Array.isArray(participantsOrOptions)) {\r\n // We are dealing with a pre-defined array of participants.\r\n var participants = participantsOrOptions;\r\n var lotto_1 = new Lotto_1.Lotto();\r\n // If the lotto participants have been defined upfront then we will need to add them all to our lotto instance now.\r\n participants.forEach(function (_a) {\r\n var participant = _a[0], tokens = _a[1];\r\n return lotto_1.add(participant, tokens);\r\n });\r\n // Return the Lotto instance.\r\n return lotto_1;\r\n }\r\n else {\r\n // We are dealing with some lotto options.\r\n var random = participantsOrOptions.random, participants = participantsOrOptions.participants;\r\n // Create a Lotto instance passing the custom RNG function to use in place of Math.random() (which could be undefined).\r\n var lotto_2 = new Lotto_1.Lotto(random);\r\n // If the lotto participants have been defined upfront as part of the options then we will need to add them all to our lotto instance now.\r\n if (participants) {\r\n participants.forEach(function (_a) {\r\n var participant = _a[0], tokens = _a[1];\r\n return lotto_2.add(participant, tokens);\r\n });\r\n }\r\n // Return the Lotto instance.\r\n return lotto_2;\r\n }\r\n}\r\nexports.createLotto = createLotto;\r\n", "\"use strict\";\r\nObject.defineProperty(exports, \"__esModule\", { value: true });\r\nvar createLotto_1 = require(\"./createLotto\");\r\nexports.default = createLotto_1.createLotto;\r\n", "import { BehaviourTree, FlattenedTreeNode } from \"./BehaviourTree\";\nimport State from \"./State\";\n\nexport { BehaviourTree, State };\nexport type { FlattenedTreeNode };\n", "import Node from \"../../nodes/Node\";\n\n/**\n * An exception thrown when evaluating node guard path conditions and a conditions fails.\n */\nexport default class GuardUnsatisifedException extends Error {\n /**\n * @param source The node at which a guard condition failed.\n */\n constructor(private source: Node) {\n super(\"A guard path condition has failed\");\n }\n\n /**\n * Gets whether the specified node is the node at which a guard condition failed.\n * @param node The node to check against the source node.\n * @returns Whether the specified node is the node at which a guard condition failed.\n */\n isSourceNode = (node: Node) => node === this.source;\n}\n", "import { Agent } from \"../../Agent\";\nimport Guard from \"./Guard\";\nimport Node from \"../../nodes/Node\";\nimport GuardUnsatisifedException from \"./GuardUnsatisifedException\";\n\nexport type GuardPathPart = {\n node: Node;\n guards: Guard[];\n};\n\n/**\n * Represents a path of node guards along a root-to-leaf tree path.\n */\nexport default class GuardPath {\n /**\n * @param nodes An array of objects defining a node instance -> guard link, ordered by node depth.\n */\n constructor(private nodes: GuardPathPart[]) {}\n\n /**\n * Evaluate guard conditions for all guards in the tree path, moving outwards from the root.\n * @param agent The agent, required for guard evaluation.\n * @returns An evaluation results object.\n */\n evaluate = (agent: Agent) => {\n // We need to evaluate guard conditions for nodes up the tree, moving outwards from the root.\n for (const details of this.nodes) {\n // There can be multiple guards per node.\n for (const guard of details.guards) {\n // Check whether the guard condition passes, and throw an exception if not.\n if (!guard.isSatisfied(agent)) {\n throw new GuardUnsatisifedException(details.node);\n }\n }\n }\n };\n}\n", "/**\n * Enumeration of node state types.\n */\nexport enum State {\n READY = \"mistreevous.ready\",\n RUNNING = \"mistreevous.running\",\n SUCCEEDED = \"mistreevous.succeeded\",\n FAILED = \"mistreevous.failed\"\n}\n\nexport { State as default };\n\nexport type CompleteState = State.SUCCEEDED | State.FAILED;\nexport type AnyState = State.READY | State.RUNNING | CompleteState;\n", "import { Agent } from \"../Agent\";\nimport Attribute from \"../attributes/Attribute\";\nimport Entry from \"../attributes/callbacks/Entry\";\nimport Exit from \"../attributes/callbacks/Exit\";\nimport Step from \"../attributes/callbacks/Step\";\nimport Guard from \"../attributes/guards/Guard\";\nimport GuardPath from \"../attributes/guards/GuardPath\";\nimport GuardUnsatisifedException from \"../attributes/guards/GuardUnsatisifedException\";\nimport { BehaviourTreeOptions } from \"../BehaviourTreeOptions\";\nimport { AnyArgument } from \"../RootAstNodesBuilder\";\nimport State, { AnyState } from \"../State\";\nimport Leaf from \"./leaf/Leaf\";\n\n/**\n * A base node.\n */\nexport default abstract class Node {\n /**\n * The node uid.\n */\n private readonly uid: string = createNodeUid();\n /**\n * The node state.\n */\n private state: AnyState = State.READY;\n /**\n * The guard path to evaluate as part of a node update.\n */\n private guardPath: GuardPath | undefined;\n\n /**\n * @param type The node type.\n * @param attributes The node attributes.\n * @param args The node argument definitions.\n */\n constructor(private type: string, private attributes: Attribute[], private args: AnyArgument[]) {}\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected abstract onUpdate(agent: Agent, options: BehaviourTreeOptions): void;\n\n /**\n * Gets the name of the node.\n */\n public abstract getName(): string;\n\n /**\n * Gets whether this node is a leaf node.\n */\n public abstract isLeafNode: () => this is Leaf;\n\n /**\n * Gets/Sets the state of the node.\n */\n getState = (): AnyState => this.state;\n setState = (value: AnyState): void => {\n this.state = value;\n };\n\n /**\n * Gets the unique id of the node.\n */\n getUid = () => this.uid;\n\n /**\n * Gets the type of the node.\n */\n getType = () => this.type;\n\n /**\n * Gets the node attributes.\n */\n getAttributes = () => this.attributes;\n\n /**\n * Gets the node arguments.\n */\n getArguments = () => this.args;\n\n /**\n * Gets the node attribute with the specified type, or null if it does not exist.\n */\n getAttribute(type: \"entry\" | \"ENTRY\"): Entry;\n getAttribute(type: \"exit\" | \"EXIT\"): Exit;\n getAttribute(type: \"step\" | \"STEP\"): Step;\n getAttribute(type: string): Attribute {\n return (\n this.getAttributes().filter((decorator) => decorator.getType().toUpperCase() === type.toUpperCase())[0] ||\n null\n );\n }\n\n /**\n * Gets the node attributes.\n */\n getGuardAttributes = (): Guard[] => this.getAttributes().filter((decorator) => decorator.isGuard()) as Guard[];\n\n /**\n * Sets the guard path to evaluate as part of a node update.\n */\n setGuardPath = (value: GuardPath) => (this.guardPath = value);\n\n /**\n * Gets whether a guard path is assigned to this node.\n */\n hasGuardPath = () => !!this.guardPath;\n\n /**\n * Gets whether this node is in the specified state.\n * @param value The value to compare to the node state.\n */\n public is(value: AnyState): boolean {\n return this.state === value;\n }\n\n /**\n * Reset the state of the node.\n */\n public reset(): void {\n this.setState(State.READY);\n }\n\n /**\n * Abort the running of this node.\n * @param agent The agent.\n */\n public abort(agent: Agent): void {\n // There is nothing to do if this node is not in the running state.\n if (!this.is(State.RUNNING)) {\n return;\n }\n\n // Reset the state of this node.\n this.reset();\n\n this.getAttribute(\"exit\")?.callAgentFunction(agent, false, true);\n }\n\n /**\n * Update the node.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n * @returns The result of the update.\n */\n public update(agent: Agent, options: BehaviourTreeOptions): void {\n // If this node is already in a 'SUCCEEDED' or 'FAILED' state then there is nothing to do.\n if (this.is(State.SUCCEEDED) || this.is(State.FAILED)) {\n return;\n }\n\n try {\n // Evaluate all of the guard path conditions for the current tree path.\n this.guardPath!.evaluate(agent);\n\n // If this node is in the READY state then call the ENTRY for this node if it exists.\n if (this.is(State.READY)) {\n this.getAttribute(\"entry\")?.callAgentFunction(agent);\n }\n\n this.getAttribute(\"step\")?.callAgentFunction(agent);\n\n // Do the actual update.\n this.onUpdate(agent, options);\n\n // If this node is now in a 'SUCCEEDED' or 'FAILED' state then call the EXIT for this node if it exists.\n if (this.is(State.SUCCEEDED) || this.is(State.FAILED)) {\n this.getAttribute(\"exit\")?.callAgentFunction(agent, this.is(State.SUCCEEDED), false);\n }\n } catch (error) {\n // If the error is a GuardUnsatisfiedException then we need to determine if this node is the source.\n if (error instanceof GuardUnsatisifedException && error.isSourceNode(this)) {\n // Abort the current node.\n this.abort(agent);\n\n // Any node that is the source of an abort will be a failed node.\n this.setState(State.FAILED);\n } else {\n throw error;\n }\n }\n }\n}\n\n/**\n * Create a randomly generated node uid.\n * @returns A randomly generated node uid.\n */\nfunction createNodeUid(): string {\n var S4 = function () {\n return (((1 + Math.random()) * 0x10000) | 0).toString(16).substring(1);\n };\n return S4() + S4() + \"-\" + S4() + \"-\" + S4() + \"-\" + S4() + \"-\" + S4() + S4() + S4();\n}\n", "import Node from \"../Node\";\n\n/**\n * A leaf node.\n */\nexport default abstract class Leaf extends Node {\n /**\n * Gets whether this node is a leaf node.\n */\n isLeafNode = () => true;\n}\n", "import { ActionResult, Agent, ExitFunctionArg, FunctionArg, GlobalFunction } from \"./Agent\";\nimport { AnyArgument, RootAstNode } from \"./RootAstNodesBuilder\";\n\n// Exit callbacks receive their own special type of argument.\n// There's probably stricter ways to represent this but it feels overly complex right now.\ntype ExitResultArg = { value: ExitFunctionArg };\nexport type AnyExitArgument = AnyArgument | ExitResultArg;\n\nexport type InvokerFunction = (args: AnyExitArgument[]) => ActionResult;\n\n/**\n * A singleton used to store and lookup registered functions and subtrees.\n */\nexport default class Lookup {\n /**\n * The object holding any registered functions keyed on function name.\n */\n private static functionTable: { [key: string]: GlobalFunction } = {};\n /**\n * The object holding any registered sub-trees keyed on tree name.\n */\n private static subtreeTable: { [key: string]: RootAstNode } = {};\n\n /**\n * Gets the function with the specified name.\n * @param name The name of the function.\n * @returns The function with the specified name.\n */\n public static getFunc(name: string): GlobalFunction {\n return this.functionTable[name];\n }\n\n /**\n * Sets the function with the specified name for later lookup.\n * @param name The name of the function.\n * @param func The function.\n */\n public static setFunc(name: string, func: GlobalFunction): void {\n this.functionTable[name] = func;\n }\n\n /**\n * Gets the function invoker for the specified agent and function name.\n * If a function with the specified name exists on the agent object then it will\n * be returned, otherwise we will then check the registered functions for a match.\n * @param agent The agent instance that this behaviour tree is modelling behaviour for.\n * @param name The function name.\n * @returns The function invoker for the specified agent and function name.\n */\n static getFuncInvoker(agent: Agent, name: string): InvokerFunction | null {\n // Check whether the agent contains the specified function.\n const foundOnAgent = agent[name];\n if (foundOnAgent && typeof foundOnAgent === \"function\") {\n return (args: AnyExitArgument[]): boolean | ActionResult =>\n foundOnAgent.apply(\n agent,\n args.map((arg) => arg.value)\n );\n }\n\n // The agent does not contain the specified function but it may have been registered at some point.\n if (this.functionTable[name] && typeof this.functionTable[name] === \"function\") {\n return (args: AnyExitArgument[]) => this.functionTable[name](agent, ...args.map((arg) => arg.value));\n }\n\n // We have no function to invoke.\n return null;\n }\n\n /**\n * Gets the subtree with the specified name.\n * @param name The name of the subtree.\n * @returns The subtree with the specified name.\n */\n static getSubtree(name: string): RootAstNode {\n return this.subtreeTable[name];\n }\n\n /**\n * Sets the subtree with the specified name for later lookup.\n * @param name The name of the subtree.\n * @param subtree The subtree.\n */\n static setSubtree(name: string, subtree: RootAstNode) {\n this.subtreeTable[name] = subtree;\n }\n\n /**\n * Removes the registered function or subtree with the specified name.\n * @param name The name of the registered function or subtree.\n */\n static remove(name: string) {\n delete this.functionTable[name];\n delete this.subtreeTable[name];\n }\n\n /**\n * Remove all registered functions and subtrees.\n */\n static empty() {\n this.functionTable = {};\n this.subtreeTable = {};\n }\n}\n", "import Leaf from \"./Leaf\";\nimport State, { CompleteState } from \"../../State\";\nimport Lookup from \"../../Lookup\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { AnyArgument } from \"../../RootAstNodesBuilder\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * An Action leaf node.\n * This represents an immediate or ongoing state of behaviour.\n */\nexport default class Action extends Leaf {\n /**\n * @param attributes The node attributes.\n * @param actionName The action name.\n * @param actionArguments The array of action argument definitions.\n */\n constructor(attributes: Attribute[], private actionName: string, private actionArguments: AnyArgument[]) {\n super(\"action\", attributes, actionArguments);\n }\n\n /**\n * Whether there is a pending update promise.\n */\n private isUsingUpdatePromise = false;\n\n /**\n * The finished state result of an update promise.\n */\n private updatePromiseStateResult: CompleteState | null = null;\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // If the result of this action depends on an update promise then there is nothing to do until\n // it resolves, unless there has been a value set as a result of the update promise resolving.\n if (this.isUsingUpdatePromise) {\n // Check whether the update promise has resolved with a state value.\n if (this.updatePromiseStateResult) {\n // Set the state of this node to match the state returned by the promise.\n this.setState(this.updatePromiseStateResult);\n }\n\n return;\n }\n\n // Attempt to get the invoker for the action function.\n const actionFuncInvoker = Lookup.getFuncInvoker(agent, this.actionName);\n\n // The action function should be defined.\n if (actionFuncInvoker === null) {\n throw new Error(\n `cannot update action node as the action '${this.actionName}' function is not defined on the agent and has not been registered`\n );\n }\n\n // Call the action function, the result of which may be:\n // - The finished state of this action node.\n // - A promise to return a finished node state.\n // - Undefined if the node should remain in the running state.\n const updateResult = actionFuncInvoker(this.actionArguments) as CompleteState | Promise;\n\n if (updateResult instanceof Promise) {\n updateResult.then(\n (result) => {\n // If 'isUpdatePromisePending' is null then the promise was cleared as it was resolving, probably via an abort of reset.\n if (!this.isUsingUpdatePromise) {\n return;\n }\n\n // Check to make sure the result is a valid finished state.\n if (result !== State.SUCCEEDED && result !== State.FAILED) {\n throw new Error(\n \"action node promise resolved with an invalid value, expected a State.SUCCEEDED or State.FAILED value to be returned\"\n );\n }\n\n // Set pending update promise state result to be processed on next update.\n this.updatePromiseStateResult = result;\n },\n (reason) => {\n // If 'isUpdatePromisePending' is null then the promise was cleared as it was resolving, probably via an abort of reset.\n if (!this.isUsingUpdatePromise) {\n return;\n }\n\n // Just throw whatever was returned as the rejection argument.\n throw new Error(reason);\n }\n );\n\n // This node will be in the 'RUNNING' state until the update promise resolves.\n this.setState(State.RUNNING);\n\n // We are now waiting for the promise returned by the use to resolve before we know what state this node is in.\n this.isUsingUpdatePromise = true;\n } else {\n // Validate the returned value.\n this.validateUpdateResult(updateResult);\n\n // Set the state of this node, this may be undefined, which just means that the node is still in the 'RUNNING' state.\n this.setState(updateResult || State.RUNNING);\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => this.actionName;\n\n /**\n * Reset the state of the node.\n */\n reset = () => {\n // Reset the state of this node.\n this.setState(State.READY);\n\n // There is no longer an update promise that we care about.\n this.isUsingUpdatePromise = false;\n this.updatePromiseStateResult = null;\n };\n\n /**\n * Validate the result of an update function call.\n * @param result The result of an update function call.\n */\n private validateUpdateResult = (result: CompleteState | boolean) => {\n switch (result) {\n case State.SUCCEEDED:\n case State.FAILED:\n case undefined:\n return;\n default:\n throw new Error(\n `action '${this.actionName}' 'onUpdate' returned an invalid response, expected an optional State.SUCCEEDED or State.FAILED value to be returned`\n );\n }\n };\n}\n", "import Leaf from \"./Leaf\";\nimport State from \"../../State\";\nimport Lookup from \"../../Lookup\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { AnyArgument } from \"../../RootAstNodesBuilder\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A Condition leaf node.\n * This will succeed or fail immediately based on an agent predicate, without moving to the 'RUNNING' state.\n */\nexport default class Condition extends Leaf {\n /**\n * @param attributes The node attributes.\n * @param conditionName The name of the condition function.\n * @param conditionArguments The array of condition argument definitions.\n */\n constructor(attributes: Attribute[], private conditionName: string, private conditionArguments: AnyArgument[]) {\n super(\"condition\", attributes, conditionArguments);\n }\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // Attempt to get the invoker for the condition function.\n const conditionFuncInvoker = Lookup.getFuncInvoker(agent, this.conditionName);\n\n // The condition function should be defined.\n if (conditionFuncInvoker === null) {\n throw new Error(\n `cannot update condition node as the condition '${this.conditionName}' function is not defined on the agent and has not been registered`\n );\n }\n\n // Call the condition function to determine the state of this node.\n this.setState(!!conditionFuncInvoker(this.conditionArguments) ? State.SUCCEEDED : State.FAILED);\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => this.conditionName;\n}\n", "import Leaf from \"./Leaf\";\nimport State from \"../../State\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { Agent } from \"../../Agent\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A WAIT node.\n * The state of this node will change to SUCCEEDED after a duration of time\n */\nexport default class Wait extends Leaf {\n /**\n * @param attributes The node attributes.\n * @param duration The duration that this node will wait to succeed in milliseconds, or the earliest if longestDuration is defined.\n * @param longestDuration The longest possible duration in milliseconds that this node will wait to succeed.\n */\n constructor(attributes: Attribute[], private duration: number, private longestDuration: number) {\n super(\"wait\", attributes, []);\n }\n\n /**\n * The time in milliseconds at which this node was first updated.\n */\n private initialUpdateTime: number = 0;\n\n /**\n * The total duration in milliseconds that this node will be waiting for.\n */\n private totalDuration: number = 0;\n\n /**\n * The duration in milliseconds that this node has been waiting for.\n */\n private waitedDuration: number = 0;\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // If this node is in the READY state then we need to set the initial update time.\n if (this.is(State.READY)) {\n // Set the initial update time.\n this.initialUpdateTime = new Date().getTime();\n\n // Set the initial waited duration.\n this.waitedDuration = 0;\n\n // If a longestDuration value was defined then we will be randomly picking a duration between the\n // shortest and longest duration. If it was not defined, then we will be just using the duration.\n this.totalDuration = this.longestDuration\n ? Math.floor(Math.random() * (this.longestDuration - this.duration + 1) + this.duration)\n : this.duration;\n\n // The node is now running until we finish waiting.\n this.setState(State.RUNNING);\n }\n\n // If we have a 'getDeltaTime' function defined as part of our options then we will use it to figure out how long we have waited for.\n if (typeof options.getDeltaTime === \"function\") {\n // Get the delta time.\n const deltaTime = options.getDeltaTime();\n\n // Our delta time must be a valid number and cannot be NaN.\n if (typeof deltaTime !== \"number\" || isNaN(deltaTime)) {\n throw new Error(\"The delta time must be a valid number and not NaN.\");\n }\n\n // Update the amount of time that this node has been waiting for based on the delta time.\n this.waitedDuration += deltaTime * 1000;\n } else {\n // We are not using a delta time, so we will just work out hom much time has passed since the first update.\n this.waitedDuration = new Date().getTime() - this.initialUpdateTime;\n }\n\n // Have we waited long enough?\n if (this.waitedDuration >= this.totalDuration) {\n // We have finished waiting!\n this.setState(State.SUCCEEDED);\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () =>\n `WAIT ${this.longestDuration ? this.duration + \"ms-\" + this.longestDuration + \"ms\" : this.duration + \"ms\"}`;\n}\n", "import Node from \"../Node\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\n\n/**\n * A decorator node that wraps a single child node.\n */\nexport default abstract class Decorator extends Node {\n /**\n * @param type The node type.\n * @param attributes The node attributes.\n * @param child The child node.\n */\n constructor(type: string, attributes: Attribute[], protected child: Node) {\n super(type, attributes, []);\n }\n\n /**\n * Gets whether this node is a leaf node.\n */\n isLeafNode = () => false;\n\n /**\n * Gets the children of this node.\n */\n getChildren = () => [this.child];\n\n /**\n * Reset the state of the node.\n */\n reset = () => {\n // Reset the state of this node.\n this.setState(State.READY);\n\n // Reset the state of the child node.\n this.child.reset();\n };\n\n /**\n * Abort the running of this node.\n * @param agent The agent.\n */\n abort = (agent: Agent) => {\n // There is nothing to do if this node is not in the running state.\n if (!this.is(State.RUNNING)) {\n return;\n }\n\n // Abort the child node.\n this.child.abort(agent);\n\n // Reset the state of this node.\n this.reset();\n\n this.getAttribute(\"exit\")?.callAgentFunction(agent, false, true);\n };\n}\n", "import Node from \"../Node\";\nimport Decorator from \"./Decorator\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A Root node.\n * The root node will have a single child.\n */\nexport default class Root extends Decorator {\n /**\n * @param attributes The node attributes.\n * @param child The child node.\n */\n constructor(attributes: Attribute[], child: Node) {\n super(\"root\", attributes, child);\n }\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // If the child has never been updated or is running then we will need to update it now.\n if (this.child.getState() === State.READY || this.child.getState() === State.RUNNING) {\n // Update the child of this node.\n this.child.update(agent, options);\n }\n\n // The state of the root node is the state of its child.\n this.setState(this.child.getState());\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => \"ROOT\";\n}\n", "import Node from \"../Node\";\nimport Decorator from \"./Decorator\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A REPEAT node.\n * The node has a single child which can have:\n * -- A number of iterations for which to repeat the child node.\n * -- An infinite repeat loop if neither an iteration count or a condition function is defined.\n * The REPEAT node will stop and have a 'FAILED' state if its child is ever in a 'FAILED' state after an update.\n * The REPEAT node will attempt to move on to the next iteration if its child is ever in a 'SUCCEEDED' state.\n */\nexport default class Repeat extends Decorator {\n /**\n * @param attributes The node attributes.\n * @param iterations The number of iterations to repeat the child node, or the minimum number of iterations if maximumIterations is defined.\n * @param maximumIterations The maximum number of iterations to repeat the child node.\n * @param child The child node.\n */\n constructor(\n attributes: Attribute[],\n private iterations: number | null,\n private maximumIterations: number | null,\n child: Node\n ) {\n super(\"repeat\", attributes, child);\n }\n\n /**\n * The number of target iterations to make.\n */\n private targetIterationCount: number | null = null;\n\n /**\n * The current iteration count.\n */\n private currentIterationCount: number = 0;\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // If this node is in the READY state then we need to reset the child and the target iteration count.\n if (this.is(State.READY)) {\n // Reset the child node.\n this.child.reset();\n\n // Set the target iteration count.\n this.setTargetIterationCount();\n }\n\n // Do a check to see if we can iterate. If we can then this node will move into the 'RUNNING' state.\n // If we cannot iterate then we have hit our target iteration count, which means that the node has succeeded.\n if (this.canIterate()) {\n // This node is in the running state and can do its initial iteration.\n this.setState(State.RUNNING);\n\n // We may have already completed an iteration, meaning that the child node will be in the SUCCEEDED state.\n // If this is the case then we will have to reset the child node now.\n if (this.child.getState() === State.SUCCEEDED) {\n this.child.reset();\n }\n\n // Update the child of this node.\n this.child.update(agent, options);\n\n // If the child moved into the FAILED state when we updated it then there is nothing left to do and this node has also failed.\n // If it has moved into the SUCCEEDED state then we have completed the current iteration.\n if (this.child.getState() === State.FAILED) {\n // The child has failed, meaning that this node has failed.\n this.setState(State.FAILED);\n\n return;\n } else if (this.child.getState() === State.SUCCEEDED) {\n // We have completed an iteration.\n this.currentIterationCount += 1;\n }\n } else {\n // This node is in the 'SUCCEEDED' state as we cannot iterate any more.\n this.setState(State.SUCCEEDED);\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => {\n if (this.iterations !== null) {\n return `REPEAT ${\n this.maximumIterations ? this.iterations + \"x-\" + this.maximumIterations + \"x\" : this.iterations + \"x\"\n }`;\n }\n\n // Return the default repeat node name.\n return \"REPEAT\";\n };\n\n /**\n * Reset the state of the node.\n */\n reset = () => {\n // Reset the state of this node.\n this.setState(State.READY);\n\n // Reset the current iteration count.\n this.currentIterationCount = 0;\n\n // Reset the child node.\n this.child.reset();\n };\n\n /**\n * Gets whether an iteration can be made.\n * @returns Whether an iteration can be made.\n */\n private canIterate = () => {\n if (this.targetIterationCount !== null) {\n // We can iterate as long as we have not reached our target iteration count.\n return this.currentIterationCount < this.targetIterationCount;\n }\n\n // If neither an iteration count or a condition function were defined then we can iterate indefinitely.\n return true;\n };\n\n /**\n * Sets the target iteration count.\n */\n private setTargetIterationCount = () => {\n // Are we dealing with a finite number of iterations?\n if (typeof this.iterations === \"number\") {\n // If we have maximumIterations defined then we will want a random iteration count bounded by iterations and maximumIterations.\n this.targetIterationCount =\n typeof this.maximumIterations === \"number\"\n ? Math.floor(Math.random() * (this.maximumIterations - this.iterations + 1) + this.iterations)\n : this.iterations;\n } else {\n this.targetIterationCount = null;\n }\n };\n}\n", "import Node from \"../Node\";\nimport Decorator from \"./Decorator\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A RETRY node.\n * The node has a single child which can have:\n * -- A number of iterations for which to repeat the child node.\n * -- An infinite repeat loop if neither an iteration count or a condition function is defined.\n * The RETRY node will stop and have a 'SUCCEEDED' state if its child is ever in a 'SUCCEEDED' state after an update.\n * The RETRY node will attempt to move on to the next iteration if its child is ever in a 'FAILED' state.\n */\nexport default class Retry extends Decorator {\n /**\n * @param attributes The node attributes.\n * @param iterations The number of iterations to repeat the child node, or the minimum number of iterations if maximumIterations is defined.\n * @param maximumIterations The maximum number of iterations to repeat the child node.\n * @param child The child node.\n */\n constructor(\n attributes: Attribute[],\n private iterations: number | null,\n private maximumIterations: number | null,\n child: Node\n ) {\n super(\"retry\", attributes, child);\n }\n\n /**\n * The number of target iterations to make.\n */\n private targetIterationCount: number | null = null;\n\n /**\n * The current iteration count.\n */\n private currentIterationCount: number = 0;\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // If this node is in the READY state then we need to reset the child and the target iteration count.\n if (this.is(State.READY)) {\n // Reset the child node.\n this.child.reset();\n\n // Set the target iteration count.\n this.setTargetIterationCount();\n }\n\n // Do a check to see if we can iterate. If we can then this node will move into the 'RUNNING' state.\n // If we cannot iterate then we have hit our target iteration count, which means that the node has succeeded.\n if (this.canIterate()) {\n // This node is in the running state and can do its initial iteration.\n this.setState(State.RUNNING);\n\n // We may have already completed an iteration, meaning that the child node will be in the FAILED state.\n // If this is the case then we will have to reset the child node now.\n if (this.child.getState() === State.FAILED) {\n this.child.reset();\n }\n\n // Update the child of this node.\n this.child.update(agent, options);\n\n // If the child moved into the SUCCEEDED state when we updated it then there is nothing left to do and this node has also succeeded.\n // If it has moved into the FAILED state then we have completed the current iteration.\n if (this.child.getState() === State.SUCCEEDED) {\n // The child has succeeded, meaning that this node has succeeded.\n this.setState(State.SUCCEEDED);\n\n return;\n } else if (this.child.getState() === State.FAILED) {\n // We have completed an iteration.\n this.currentIterationCount += 1;\n }\n } else {\n // This node is in the 'FAILED' state as we cannot iterate any more.\n this.setState(State.FAILED);\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => {\n if (this.iterations !== null) {\n return `RETRY ${\n this.maximumIterations ? this.iterations + \"x-\" + this.maximumIterations + \"x\" : this.iterations + \"x\"\n }`;\n }\n\n // Return the default retry node name.\n return \"RETRY\";\n };\n\n /**\n * Reset the state of the node.\n */\n reset = () => {\n // Reset the state of this node.\n this.setState(State.READY);\n\n // Reset the current iteration count.\n this.currentIterationCount = 0;\n\n // Reset the child node.\n this.child.reset();\n };\n\n /**\n * Gets whether an iteration can be made.\n * @returns Whether an iteration can be made.\n */\n canIterate = () => {\n if (this.targetIterationCount !== null) {\n // We can iterate as long as we have not reached our target iteration count.\n return this.currentIterationCount < this.targetIterationCount;\n }\n\n // If neither an iteration count or a condition function were defined then we can iterate indefinitely.\n return true;\n };\n\n /**\n * Sets the target iteration count.\n */\n setTargetIterationCount = () => {\n // Are we dealing with a finite number of iterations?\n if (typeof this.iterations === \"number\") {\n // If we have maximumIterations defined then we will want a random iteration count bounded by iterations and maximumIterations.\n this.targetIterationCount =\n typeof this.maximumIterations === \"number\"\n ? Math.floor(Math.random() * (this.maximumIterations - this.iterations + 1) + this.iterations)\n : this.iterations;\n } else {\n this.targetIterationCount = null;\n }\n };\n}\n", "import Decorator from \"./Decorator\";\nimport State from \"../../State\";\nimport Node from \"../Node\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A Flip node.\n * This node wraps a single child and will flip the state of the child state.\n */\nexport default class Flip extends Decorator {\n /**\n * @param attributes The node attributes.\n * @param child The child node.\n */\n constructor(attributes: Attribute[], child: Node) {\n super(\"flip\", attributes, child);\n }\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // If the child has never been updated or is running then we will need to update it now.\n if (this.child.getState() === State.READY || this.child.getState() === State.RUNNING) {\n this.child.update(agent, options);\n }\n\n // The state of this node will depend in the state of its child.\n switch (this.child.getState()) {\n case State.RUNNING:\n this.setState(State.RUNNING);\n break;\n\n case State.SUCCEEDED:\n this.setState(State.FAILED);\n break;\n\n case State.FAILED:\n this.setState(State.SUCCEEDED);\n break;\n\n default:\n this.setState(State.READY);\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => \"FLIP\";\n}\n", "import Node from \"../Node\";\nimport Decorator from \"./Decorator\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A Succeed node.\n * This node wraps a single child and will always move to the 'SUCCEEDED' state when the child moves to a 'SUCCEEDED' or 'FAILED' state.\n */\nexport default class Succeed extends Decorator {\n /**\n * @param attributes The node attributes.\n * @param child The child node.\n */\n constructor(attributes: Attribute[], child: Node) {\n super(\"succeed\", attributes, child);\n }\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // If the child has never been updated or is running then we will need to update it now.\n if (this.child.getState() === State.READY || this.child.getState() === State.RUNNING) {\n this.child.update(agent, options);\n }\n\n // The state of this node will depend in the state of its child.\n switch (this.child.getState()) {\n case State.RUNNING:\n this.setState(State.RUNNING);\n break;\n\n case State.SUCCEEDED:\n case State.FAILED:\n this.setState(State.SUCCEEDED);\n break;\n\n default:\n this.setState(State.READY);\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => \"SUCCEED\";\n}\n", "import Node from \"../Node\";\nimport Decorator from \"./Decorator\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A Fail node.\n * This node wraps a single child and will always move to the 'FAILED' state when the child moves to a 'SUCCEEDED' or 'FAILED' state.\n */\nexport default class Fail extends Decorator {\n /**\n * @param attributes The node attributes.\n * @param child The child node.\n */\n constructor(attributes: Attribute[], child: Node) {\n super(\"fail\", attributes, child);\n }\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // If the child has never been updated or is running then we will need to update it now.\n if (this.child.getState() === State.READY || this.child.getState() === State.RUNNING) {\n this.child.update(agent, options);\n }\n\n // The state of this node will depend in the state of its child.\n switch (this.child.getState()) {\n case State.RUNNING:\n this.setState(State.RUNNING);\n break;\n\n case State.SUCCEEDED:\n case State.FAILED:\n this.setState(State.FAILED);\n break;\n\n default:\n this.setState(State.READY);\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => \"FAIL\";\n}\n", "import createLotto from \"lotto-draw\";\r\n\r\nimport Node from \"../Node\";\r\nimport Composite from \"./Composite\";\r\nimport State from \"../../State\";\r\nimport { Agent } from \"../../Agent\";\r\nimport Attribute from \"../../attributes/Attribute\";\r\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\r\n\r\n/**\r\n * A LOTTO node.\r\n * A winning child is picked on the initial update of this node, based on ticket weighting.\r\n * The state of this node will match the state of the winning child.\r\n */\r\nexport default class Lotto extends Composite {\r\n /**\r\n * @param attributes The node attributes.\r\n * @param tickets The child node tickets.\r\n * @param children The child nodes.\r\n */\r\n constructor(attributes: Attribute[], private tickets: number[], children: Node[]) {\r\n super(\"lotto\", attributes, children);\r\n }\r\n\r\n /**\r\n * The child node selected to be the active one.\r\n */\r\n private selectedChild: Node | undefined;\r\n\r\n /**\r\n * Called when the node is being updated.\r\n * @param agent The agent.\r\n * @param options The behaviour tree options object.\r\n */\r\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\r\n // If this node is in the READY state then we need to pick a winning child node.\r\n if (this.is(State.READY)) {\r\n // Create a lotto draw with which to randomly pick a child node to become the active one.\r\n const lottoDraw = createLotto({\r\n // Hook up the optional 'random' behaviour tree function option to the one used by 'lotto-draw'.\r\n random: options.random,\r\n // Pass in each child node as a participant in the lotto draw with their respective ticket count.\r\n participants: this.children.map((child, index) => [child, this.tickets[index] || 1])\r\n });\r\n\r\n // Randomly pick a child based on ticket weighting, this will become the active child for this composite node.\r\n this.selectedChild = lottoDraw.draw() || undefined;\r\n }\r\n\r\n // If something went wrong and we don't have an active child then we should throw an error.\r\n if (!this.selectedChild) {\r\n throw new Error(\"failed to update lotto node as it has no active child\");\r\n }\r\n\r\n // If the selected child has never been updated or is running then we will need to update it now.\r\n if (this.selectedChild.getState() === State.READY || this.selectedChild.getState() === State.RUNNING) {\r\n this.selectedChild.update(agent, options);\r\n }\r\n\r\n // The state of the lotto node is the state of its selected child.\r\n this.setState(this.selectedChild.getState());\r\n }\r\n\r\n /**\r\n * Gets the name of the node.\r\n */\r\n getName = () => (this.tickets.length ? `LOTTO [${this.tickets.join(\",\")}]` : \"LOTTO\");\r\n}\r\n", "import Node from \"../Node\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\n\n/**\n * A composite node that wraps child nodes.\n */\nexport default abstract class Composite extends Node {\n /**\n * @param type The node type.\n * @param attributes The node attributes.\n * @param children The child nodes.\n */\n constructor(type: string, attributes: Attribute[], protected children: Node[]) {\n super(type, attributes, []);\n }\n\n /**\n * Gets whether this node is a leaf node.\n */\n isLeafNode = () => false;\n\n /**\n * Gets the children of this node.\n */\n getChildren = () => this.children;\n\n /**\n * Reset the state of the node.\n */\n reset = () => {\n // Reset the state of this node.\n this.setState(State.READY);\n\n // Reset the state of any child nodes.\n this.getChildren().forEach((child) => child.reset());\n };\n\n /**\n * Abort the running of this node.\n * @param agent The agent.\n */\n abort = (agent: Agent) => {\n // There is nothing to do if this node is not in the running state.\n if (!this.is(State.RUNNING)) {\n return;\n }\n\n // Abort any child nodes.\n this.getChildren().forEach((child) => child.abort(agent));\n\n // Reset the state of this node.\n this.reset();\n\n this.getAttribute(\"exit\")?.callAgentFunction(agent, false, true);\n };\n}\n", "import Composite from \"./Composite\";\nimport Node from \"../Node\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A SELECTOR node.\n * The child nodes are executed in sequence until one succeeds or all fail.\n */\nexport default class Selector extends Composite {\n /**\n * @param attributes The node attributes.\n * @param children The child nodes.\n */\n constructor(attributes: Attribute[], protected children: Node[]) {\n super(\"selector\", attributes, children);\n }\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // Iterate over all of the children of this node.\n for (const child of this.children) {\n // If the child has never been updated or is running then we will need to update it now.\n if (child.getState() === State.READY || child.getState() === State.RUNNING) {\n // Update the child of this node.\n child.update(agent, options);\n }\n\n // If the current child has a state of 'SUCCEEDED' then this node is also a 'SUCCEEDED' node.\n if (child.getState() === State.SUCCEEDED) {\n // This node is a 'SUCCEEDED' node.\n this.setState(State.SUCCEEDED);\n\n // There is no need to check the rest of the selector nodes.\n return;\n }\n\n // If the current child has a state of 'FAILED' then we should move on to the next child.\n if (child.getState() === State.FAILED) {\n // Find out if the current child is the last one in the selector.\n // If it is then this sequence node has also failed.\n if (this.children.indexOf(child) === this.children.length - 1) {\n // This node is a 'FAILED' node.\n this.setState(State.FAILED);\n\n // There is no need to check the rest of the selector as we have completed it.\n return;\n } else {\n // The child node failed, try the next one.\n continue;\n }\n }\n\n // The node should be in the 'RUNNING' state.\n if (child.getState() === State.RUNNING) {\n // This node is a 'RUNNING' node.\n this.setState(State.RUNNING);\n\n // There is no need to check the rest of the selector as the current child is still running.\n return;\n }\n\n // The child node was not in an expected state.\n throw new Error(\"child node was not in an expected state.\");\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => \"SELECTOR\";\n}\n", "import Composite from \"./Composite\";\nimport Node from \"../Node\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A SEQUENCE node.\n * The child nodes are executed in sequence until one fails or all succeed.\n */\nexport default class Sequence extends Composite {\n /**\n * @param attributes The node attributes.\n * @param children The child nodes.\n */\n constructor(attributes: Attribute[], protected children: Node[]) {\n super(\"sequence\", attributes, children);\n }\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // Iterate over all of the children of this node.\n for (const child of this.children) {\n // If the child has never been updated or is running then we will need to update it now.\n if (child.getState() === State.READY || child.getState() === State.RUNNING) {\n // Update the child of this node.\n child.update(agent, options);\n }\n\n // If the current child has a state of 'SUCCEEDED' then we should move on to the next child.\n if (child.getState() === State.SUCCEEDED) {\n // Find out if the current child is the last one in the sequence.\n // If it is then this sequence node has also succeeded.\n if (this.children.indexOf(child) === this.children.length - 1) {\n // This node is a 'SUCCEEDED' node.\n this.setState(State.SUCCEEDED);\n\n // There is no need to check the rest of the sequence as we have completed it.\n return;\n } else {\n // The child node succeeded, but we have not finished the sequence yet.\n continue;\n }\n }\n\n // If the current child has a state of 'FAILED' then this node is also a 'FAILED' node.\n if (child.getState() === State.FAILED) {\n // This node is a 'FAILED' node.\n this.setState(State.FAILED);\n\n // There is no need to check the rest of the sequence.\n return;\n }\n\n // The node should be in the 'RUNNING' state.\n if (child.getState() === State.RUNNING) {\n // This node is a 'RUNNING' node.\n this.setState(State.RUNNING);\n\n // There is no need to check the rest of the sequence as the current child is still running.\n return;\n }\n\n // The child node was not in an expected state.\n throw new Error(\"child node was not in an expected state.\");\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => \"SEQUENCE\";\n}\n", "import Composite from \"./Composite\";\nimport State from \"../../State\";\nimport Node from \"../Node\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A PARALLEL node.\n * The child nodes are executed concurrently until one fails or all succeed.\n */\nexport default class Parallel extends Composite {\n /**\n * @param attributes The node attributes.\n * @param children The child nodes.\n */\n constructor(attributes: Attribute[], children: Node[]) {\n super(\"parallel\", attributes, children);\n }\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // Keep a count of the number of succeeded child nodes.\n let succeededCount = 0;\n\n let hasChildFailed = false;\n\n // Iterate over all of the children of this node.\n for (const child of this.children) {\n // If the child has never been updated or is running then we will need to update it now.\n if (child.getState() === State.READY || child.getState() === State.RUNNING) {\n // Update the child of this node.\n child.update(agent, options);\n }\n\n // If the current child has a state of 'SUCCEEDED' then we should move on to the next child.\n if (child.getState() === State.SUCCEEDED) {\n // The child node has succeeded, keep track of this to determine if all children have.\n succeededCount++;\n\n // The child node succeeded, but we have not finished checking every child node yet.\n continue;\n }\n\n // If the current child has a state of 'FAILED' then this node is also a 'FAILED' node.\n if (child.getState() === State.FAILED) {\n hasChildFailed = true;\n\n // There is no need to check the rest of the children.\n break;\n }\n\n // The node should be in the 'RUNNING' state.\n if (child.getState() !== State.RUNNING) {\n // The child node was not in an expected state.\n throw new Error(\"child node was not in an expected state.\");\n }\n }\n\n if (hasChildFailed) {\n // This node is a 'FAILED' node.\n this.setState(State.FAILED);\n\n // Abort every running child.\n for (const child of this.children) {\n if (child.getState() === State.RUNNING) {\n child.abort(agent);\n }\n }\n } else {\n // If all children have succeeded then this node has also succeeded, otherwise it is still running.\n this.setState(succeededCount === this.children.length ? State.SUCCEEDED : State.RUNNING);\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => \"PARALLEL\";\n}\n", "import { AnyArgument } from \"../RootAstNodesBuilder\";\nimport Guard from \"./guards/Guard\";\n\nexport type AttributeDetails = {\n /** The attribute type. */\n type: string;\n\n /** The attribute arguments. */\n args: AnyArgument[];\n};\n\n/**\n * A base node attribute.\n */\nexport default abstract class Attribute {\n /**\n * @param type The node attribute type.\n * @param args The array of attribute argument definitions.\n */\n constructor(protected type: string, protected args: AnyArgument[]) {}\n\n /**\n * Gets the type of the attribute.\n */\n getType = () => this.type;\n\n /**\n * Gets the array of attribute argument definitions.\n */\n getArguments = () => this.args;\n\n /**\n * Gets the attribute details.\n */\n abstract getDetails(): TAttributeDetails;\n\n /**\n * Gets whether this attribute is a guard.\n */\n abstract isGuard: () => this is Guard;\n}\n", "import { Agent } from \"../../Agent\";\nimport { AnyArgument } from \"../../RootAstNodesBuilder\";\nimport Attribute, { AttributeDetails } from \"../Attribute\";\n\nexport type GuardAttributeDetails = {\n /** The name of the condition function that determines whether the guard is satisfied. */\n condition: string;\n} & AttributeDetails;\n\n/**\n * A base node guard attribute.\n */\nexport default abstract class Guard extends Attribute {\n /**\n * @param type The node attribute type.\n * @param args The array of decorator argument definitions.\n * @param condition The name of the condition function that determines whether the guard is satisfied.\n */\n constructor(type: string, args: AnyArgument[], private condition: string) {\n super(type, args);\n }\n\n /**\n * Gets the name of the condition function that determines whether the guard is satisfied.\n */\n getCondition = () => this.condition;\n\n /**\n * Gets whether this attribute is a guard.\n */\n isGuard = () => true;\n\n /**\n * Gets the attribute details.\n */\n getDetails(): GuardAttributeDetails {\n return {\n type: this.getType(),\n args: this.getArguments(),\n condition: this.getCondition()\n };\n }\n\n /**\n * Gets whether the guard is satisfied.\n * @param agent The agent.\n * @returns Whether the guard is satisfied.\n */\n abstract isSatisfied(agent: Agent): boolean;\n}\n", "import Guard from \"./Guard\";\nimport Lookup from \"../../Lookup\";\nimport { Agent } from \"../../Agent\";\nimport { AnyArgument } from \"../../RootAstNodesBuilder\";\n\n/**\n * A WHILE guard which is satisfied as long as the given condition remains true.\n */\nexport default class While extends Guard {\n /**\n * @param condition The name of the condition function that determines whether the guard is satisfied.\n * @param args The array of decorator argument definitions.\n */\n constructor(condition: string, args: AnyArgument[]) {\n super(\"while\", args, condition);\n }\n\n /**\n * Gets whether the guard is satisfied.\n * @param agent The agent.\n * @returns Whether the guard is satisfied.\n */\n isSatisfied = (agent: Agent) => {\n // Attempt to get the invoker for the condition function.\n const conditionFuncInvoker = Lookup.getFuncInvoker(agent, this.getCondition());\n\n // The condition function should be defined.\n if (conditionFuncInvoker === null) {\n throw new Error(\n `cannot evaluate node guard as the condition '${this.getCondition()}' function is not defined on the agent and has not been registered`\n );\n }\n\n // Call the condition function to determine whether this guard is satisfied.\n return !!conditionFuncInvoker(this.args);\n };\n}\n", "import Guard from \"./Guard\";\nimport Lookup from \"../../Lookup\";\nimport { Agent } from \"../../Agent\";\nimport { AnyArgument } from \"../../RootAstNodesBuilder\";\n\n/**\n * An UNTIL guard which is satisfied as long as the given condition remains false.\n */\nexport default class Until extends Guard {\n /**\n * @param condition The name of the condition function that determines whether the guard is satisfied.\n * @param args The array of decorator argument definitions.\n */\n constructor(condition: string, args: AnyArgument[]) {\n super(\"until\", args, condition);\n }\n\n /**\n * Gets whether the guard is satisfied.\n * @param agent The agent.\n * @returns Whether the guard is satisfied.\n */\n isSatisfied = (agent: Agent) => {\n // Attempt to get the invoker for the condition function.\n const conditionFuncInvoker = Lookup.getFuncInvoker(agent, this.getCondition());\n\n // The condition function should be defined.\n if (conditionFuncInvoker === null) {\n throw new Error(\n `cannot evaluate node guard as the condition '${this.getCondition()}' function is not defined on the agent and has not been registered`\n );\n }\n\n // Call the condition function to determine whether this guard is satisfied.\n return !!!conditionFuncInvoker(this.args);\n };\n}\n", "import { Agent } from \"../../Agent\";\nimport { AnyArgument } from \"../../RootAstNodesBuilder\";\nimport Attribute, { AttributeDetails } from \"../Attribute\";\n\nexport type CallbackAttributeDetails = {\n /** The name of the agent function that is called. */\n functionName: string;\n} & AttributeDetails;\n\n/**\n * A base node callback attribute.\n */\nexport default abstract class Callback extends Attribute {\n /**\n * @param type The node attribute type.\n * @param args The array of decorator argument definitions.\n * @param functionName The name of the agent function to call.\n */\n constructor(type: string, args: AnyArgument[], private functionName: string) {\n super(type, args);\n }\n\n /**\n * Gets the name of the agent function to call.\n */\n getFunctionName = () => this.functionName;\n\n /**\n * Gets whether this attribute is a guard.\n */\n isGuard = () => false;\n\n /**\n * Gets the attribute details.\n */\n getDetails(): CallbackAttributeDetails {\n return {\n type: this.getType(),\n args: this.getArguments(),\n functionName: this.getFunctionName()\n };\n }\n\n /**\n * Attempt to call the agent function that this callback refers to.\n * @param agent The agent.\n */\n abstract callAgentFunction: (agent: Agent, isSuccess: boolean, isAborted: boolean) => void;\n}\n", "import Callback from \"./Callback\";\nimport Lookup from \"../../Lookup\";\nimport { Agent } from \"../../Agent\";\nimport { AnyArgument } from \"../../RootAstNodesBuilder\";\n\n/**\n * An ENTRY callback which defines an agent function to call when the associated node is updated and moves out of running state.\n */\nexport default class Entry extends Callback {\n /**\n * @param functionName The name of the agent function to call.\n * @param args The array of callback argument definitions.\n */\n constructor(functionName: string, args: AnyArgument[]) {\n super(\"entry\", args, functionName);\n }\n\n /**\n * Attempt to call the agent function that this callback refers to.\n * @param agent The agent.\n */\n callAgentFunction = (agent: Agent) => {\n // Attempt to get the invoker for the callback function.\n const callbackFuncInvoker = Lookup.getFuncInvoker(agent, this.getFunctionName());\n\n // The callback function should be defined.\n if (callbackFuncInvoker === null) {\n throw new Error(\n `cannot call entry function '${this.getFunctionName()}' as is not defined on the agent and has not been registered`\n );\n }\n\n // Call the callback function.\n callbackFuncInvoker(this.args);\n };\n}\n", "import Callback from \"./Callback\";\nimport Lookup, { AnyExitArgument } from \"../../Lookup\";\nimport { Agent } from \"../../Agent\";\nimport { AnyArgument } from \"../../RootAstNodesBuilder\";\n\n/**\n * An EXIT callback which defines an agent function to call when the associated node is updated and moves to a finished state or is aborted.\n */\nexport default class Exit extends Callback {\n /**\n * @param functionName The name of the agent function to call.\n * @param args The array of callback argument definitions.\n */\n constructor(functionName: string, args: AnyArgument[]) {\n super(\"exit\", args, functionName);\n }\n\n /**\n * Attempt to call the agent function that this callback refers to.\n * @param agent The agent.\n * @param isSuccess Whether the decorated node was left with a success state.\n * @param isAborted Whether the decorated node was aborted.\n */\n callAgentFunction = (agent: Agent, isSuccess: boolean, isAborted: boolean) => {\n // Attempt to get the invoker for the callback function.\n const callbackFuncInvoker = Lookup.getFuncInvoker(agent, this.getFunctionName());\n\n // The callback function should be defined.\n if (callbackFuncInvoker === null) {\n throw new Error(\n `cannot call exit function '${this.getFunctionName()}' as is not defined on the agent and has not been registered`\n );\n }\n\n // Call the callback function\n callbackFuncInvoker([{ value: { succeeded: isSuccess, aborted: isAborted } }, ...this.args]);\n };\n}\n", "import Callback from \"./Callback\";\nimport Lookup from \"../../Lookup\";\nimport { Agent } from \"../../Agent\";\nimport { AnyArgument } from \"../../RootAstNodesBuilder\";\n\n/**\n * A STEP callback which defines an agent function to call when the associated node is updated.\n */\nexport default class Step extends Callback {\n /**\n * @param functionName The name of the agent function to call.\n * @param args The array of callback argument definitions.\n */\n constructor(functionName: string, args: AnyArgument[]) {\n super(\"step\", args, functionName);\n }\n\n /**\n * Attempt to call the agent function that this callback refers to.\n * @param agent The agent.\n */\n callAgentFunction = (agent: Agent) => {\n // Attempt to get the invoker for the callback function.\n const callbackFuncInvoker = Lookup.getFuncInvoker(agent, this.getFunctionName());\n\n // The callback function should be defined.\n if (callbackFuncInvoker === null) {\n throw new Error(\n `cannot call step function '${this.getFunctionName()}' as is not defined on the agent and has not been registered`\n );\n }\n\n // Call the callback function.\n callbackFuncInvoker(this.args);\n };\n}\n", "import Action from \"./nodes/leaf/Action\";\nimport Condition from \"./nodes/leaf/Condition\";\nimport Wait from \"./nodes/leaf/Wait\";\nimport Root from \"./nodes/decorator/Root\";\nimport Repeat from \"./nodes/decorator/Repeat\";\nimport Retry from \"./nodes/decorator/Retry\";\nimport Flip from \"./nodes/decorator/Flip\";\nimport Succeed from \"./nodes/decorator/Succeed\";\nimport Fail from \"./nodes/decorator/Fail\";\nimport Lotto from \"./nodes/composite/Lotto\";\nimport Selector from \"./nodes/composite/Selector\";\nimport Sequence from \"./nodes/composite/Sequence\";\nimport Parallel from \"./nodes/composite/Parallel\";\nimport Node from \"./nodes/Node\";\nimport While from \"./attributes/guards/While\";\nimport Until from \"./attributes/guards/Until\";\nimport Entry from \"./attributes/callbacks/Entry\";\nimport Exit from \"./attributes/callbacks/Exit\";\nimport Step from \"./attributes/callbacks/Step\";\nimport Callback from \"./attributes/callbacks/Callback\";\nimport Guard from \"./attributes/guards/Guard\";\nimport Attribute from \"./attributes/Attribute\";\nimport Composite from \"./nodes/composite/Composite\";\nimport Decorator from \"./nodes/decorator/Decorator\";\nimport Leaf from \"./nodes/leaf/Leaf\";\n\nexport type Argument = {\n value: T;\n type: string; // Used for validation.\n};\ntype NullArgument = Argument & {\n type: \"null\";\n};\ntype BooleanArgument = Argument & {\n type: \"boolean\";\n};\ntype NumberArgument = Argument & {\n type: \"number\";\n isInteger: boolean; // Used for validation.\n};\ntype StringPlaceholderArgument = Argument & {\n type: \"string\";\n};\ntype IdentifierArgument = Argument & {\n type: \"identifier\";\n};\nexport type AnyArgument =\n | NullArgument\n | BooleanArgument\n | NumberArgument\n | StringPlaceholderArgument\n | IdentifierArgument;\n\n/**\n * The node attribute factories.\n */\nconst AttributeFactories: {\n [key: string]: (functionName: string, attributeArguments: AnyArgument[]) => Callback | Guard;\n} = {\n WHILE: (condition: string, attributeArguments: AnyArgument[]) => new While(condition, attributeArguments),\n UNTIL: (condition: string, attributeArguments: AnyArgument[]) => new Until(condition, attributeArguments),\n ENTRY: (functionName: string, attributeArguments: AnyArgument[]) => new Entry(functionName, attributeArguments),\n EXIT: (functionName: string, attributeArguments: AnyArgument[]) => new Exit(functionName, attributeArguments),\n STEP: (functionName: string, attributeArguments: AnyArgument[]) => new Step(functionName, attributeArguments)\n};\n\ntype Validatable = {\n children?: AstNode[];\n validate: (depth: number) => void;\n};\n\ntype NodeInstanceCreator = (\n namedRootNodeProvider: (name: string) => RootAstNode,\n visitedBranches: string[]\n) => T;\n\nexport type AstNode = Validatable & {\n type: string;\n createNodeInstance: NodeInstanceCreator;\n};\n\nexport type LeafAstNode = AstNode & {\n type: \"action\" | \"condition\" | \"wait\";\n attributes: Attribute[];\n};\n\nexport type CompositeAstNode = AstNode & {\n type: \"lotto\" | \"parallel\" | \"selector\" | \"sequence\";\n attributes: Attribute[];\n children: AstNode[];\n};\n\nexport type DecoratorAstNode = AstNode & {\n type: \"fail\" | \"flip\" | \"repeat\" | \"retry\" | \"root\" | \"succeed\";\n attributes: Attribute[];\n children: AstNode[];\n};\n\nexport type BranchAstNode = AstNode & {\n type: \"branch\";\n branchName: \"\" | string;\n};\n\nexport type LottoAstNode = CompositeAstNode & {\n type: \"lotto\";\n tickets: number[];\n};\n\nexport type RootAstNode = DecoratorAstNode & {\n type: \"root\";\n name: null | string;\n};\n\nexport type IterableAstNode = DecoratorAstNode & {\n type: \"repeat\" | \"retry\";\n iterations: null | number;\n maximumIterations: null | number;\n};\n\nexport type ActionAstNode = LeafAstNode & {\n type: \"action\";\n actionName: string;\n actionArguments: AnyArgument[];\n};\n\nexport type ConditionAstNode = LeafAstNode & {\n type: \"condition\";\n conditionName: string;\n conditionArguments: AnyArgument[];\n};\n\nexport type WaitAstNode = LeafAstNode & {\n type: \"wait\";\n duration: number | null;\n longestDuration: number | null;\n};\n\nexport type AnyAstNode =\n | BranchAstNode\n | CompositeAstNode\n | LottoAstNode\n | DecoratorAstNode\n | RootAstNode\n | IterableAstNode\n | LeafAstNode\n | ActionAstNode\n | ConditionAstNode\n | WaitAstNode;\n\n/**\n * The AST node factories.\n */\nconst ASTNodeFactories = {\n ROOT: (): RootAstNode => ({\n type: \"root\",\n attributes: [],\n name: null,\n children: [],\n validate(depth: number) {\n // A root node cannot be the child of another node.\n if (depth > 1) {\n throw new Error(\"a root node cannot be the child of another node\");\n }\n\n // A root node must have a single child node.\n if (this.children.length !== 1) {\n throw new Error(\"a root node must have a single child\");\n }\n },\n createNodeInstance(namedRootNodeProvider, visitedBranches) {\n return new Root(\n this.attributes,\n this.children![0].createNodeInstance(namedRootNodeProvider, visitedBranches.slice())\n );\n }\n }),\n BRANCH: (): BranchAstNode => ({\n type: \"branch\",\n branchName: \"\",\n validate() {},\n createNodeInstance(namedRootNodeProvider, visitedBranches) {\n // Try to find the root node with a matching branch name.\n const targetRootNode = namedRootNodeProvider(this.branchName);\n\n // If we have already visited this branch then we have a circular dependency.\n if (visitedBranches.indexOf(this.branchName) !== -1) {\n throw new Error(`circular dependency found in branch node references for branch '${this.branchName}'`);\n }\n\n // If we have a target root node, then the node instance we want will be the first and only child of the referenced root node.\n if (targetRootNode) {\n return targetRootNode\n .createNodeInstance(namedRootNodeProvider, visitedBranches.concat(this.branchName))\n .getChildren()[0];\n } else {\n throw new Error(`branch references root node '${this.branchName}' which has not been defined`);\n }\n }\n }),\n SELECTOR: (): CompositeAstNode => ({\n type: \"selector\",\n attributes: [],\n children: [],\n validate() {\n // A selector node must have at least a single node.\n if (this.children.length < 1) {\n throw new Error(\"a selector node must have at least a single child\");\n }\n },\n createNodeInstance(namedRootNodeProvider, visitedBranches) {\n return new Selector(\n this.attributes,\n this.children.map((child) => child.createNodeInstance(namedRootNodeProvider, visitedBranches.slice()))\n );\n }\n }),\n SEQUENCE: (): CompositeAstNode => ({\n type: \"sequence\",\n attributes: [],\n children: [],\n validate() {\n // A sequence node must have at least a single node.\n if (this.children.length < 1) {\n throw new Error(\"a sequence node must have at least a single child\");\n }\n },\n createNodeInstance(namedRootNodeProvider, visitedBranches) {\n return new Sequence(\n this.attributes,\n this.children.map((child) => child.createNodeInstance(namedRootNodeProvider, visitedBranches.slice()))\n );\n }\n }),\n PARALLEL: (): CompositeAstNode => ({\n type: \"parallel\",\n attributes: [],\n children: [],\n validate() {\n // A parallel node must have at least a single node.\n if (this.children.length < 1) {\n throw new Error(\"a parallel node must have at least a single child\");\n }\n },\n createNodeInstance(namedRootNodeProvider, visitedBranches) {\n return new Parallel(\n this.attributes,\n this.children.map((child) => child.createNodeInstance(namedRootNodeProvider, visitedBranches.slice()))\n );\n }\n }),\n LOTTO: (): LottoAstNode => ({\n type: \"lotto\",\n attributes: [],\n children: [],\n tickets: [],\n validate() {\n // A lotto node must have at least a single node.\n if (this.children!.length < 1) {\n throw new Error(\"a lotto node must have at least a single child\");\n }\n },\n createNodeInstance(namedRootNodeProvider, visitedBranches) {\n return new Lotto(\n this.attributes,\n this.tickets!,\n this.children!.map((child) => child.createNodeInstance(namedRootNodeProvider, visitedBranches.slice()))\n );\n }\n }),\n REPEAT: (): IterableAstNode => ({\n type: \"repeat\",\n attributes: [],\n iterations: null,\n maximumIterations: null,\n children: [],\n validate() {\n // A repeat node must have a single node.\n if (this.children!.length !== 1) {\n throw new Error(\"a repeat node must have a single child\");\n }\n\n // A repeat node must have a positive number of iterations if defined.\n if (this.iterations !== null && this.iterations! < 0) {\n throw new Error(\"a repeat node must have a positive number of iterations if defined\");\n }\n\n // There is validation to carry out if a longest duration was defined.\n if (this.maximumIterations !== null) {\n // A repeat node must have a positive maximum iterations count if defined.\n if (this.maximumIterations! < 0) {\n throw new Error(\"a repeat node must have a positive maximum iterations count if defined\");\n }\n\n // A repeat node must not have an iteration count that exceeds the maximum iteration count.\n if (this.iterations! > this.maximumIterations!) {\n throw new Error(\n \"a repeat node must not have an iteration count that exceeds the maximum iteration count\"\n );\n }\n }\n },\n createNodeInstance(namedRootNodeProvider, visitedBranches) {\n return new Repeat(\n this.attributes,\n this.iterations!,\n this.maximumIterations!,\n this.children![0].createNodeInstance(namedRootNodeProvider, visitedBranches.slice())\n );\n }\n }),\n RETRY: (): IterableAstNode => ({\n type: \"retry\",\n attributes: [],\n iterations: null,\n maximumIterations: null,\n children: [],\n validate() {\n // A retry node must have a single node.\n if (this.children!.length !== 1) {\n throw new Error(\"a retry node must have a single child\");\n }\n\n // A retry node must have a positive number of iterations if defined.\n if (this.iterations !== null && this.iterations! < 0) {\n throw new Error(\"a retry node must have a positive number of iterations if defined\");\n }\n\n // There is validation to carry out if a longest duration was defined.\n if (this.maximumIterations !== null) {\n // A retry node must have a positive maximum iterations count if defined.\n if (this.maximumIterations! < 0) {\n throw new Error(\"a retry node must have a positive maximum iterations count if defined\");\n }\n\n // A retry node must not have an iteration count that exceeds the maximum iteration count.\n if (this.iterations! > this.maximumIterations!) {\n throw new Error(\n \"a retry node must not have an iteration count that exceeds the maximum iteration count\"\n );\n }\n }\n },\n createNodeInstance(namedRootNodeProvider, visitedBranches) {\n return new Retry(\n this.attributes,\n this.iterations!,\n this.maximumIterations!,\n this.children![0].createNodeInstance(namedRootNodeProvider, visitedBranches.slice())\n );\n }\n }),\n FLIP: (): DecoratorAstNode => ({\n type: \"flip\",\n attributes: [],\n children: [],\n validate() {\n // A flip node must have a single node.\n if (this.children!.length !== 1) {\n throw new Error(\"a flip node must have a single child\");\n }\n },\n createNodeInstance(namedRootNodeProvider, visitedBranches) {\n return new Flip(\n this.attributes,\n this.children![0].createNodeInstance(namedRootNodeProvider, visitedBranches.slice())\n );\n }\n }),\n SUCCEED: (): DecoratorAstNode => ({\n type: \"succeed\",\n attributes: [],\n children: [],\n validate() {\n // A succeed node must have a single node.\n if (this.children!.length !== 1) {\n throw new Error(\"a succeed node must have a single child\");\n }\n },\n createNodeInstance(namedRootNodeProvider, visitedBranches) {\n return new Succeed(\n this.attributes,\n this.children![0].createNodeInstance(namedRootNodeProvider, visitedBranches.slice())\n );\n }\n }),\n FAIL: (): DecoratorAstNode => ({\n type: \"fail\",\n attributes: [],\n children: [],\n validate() {\n // A fail node must have a single node.\n if (this.children!.length !== 1) {\n throw new Error(\"a fail node must have a single child\");\n }\n },\n createNodeInstance(namedRootNodeProvider, visitedBranches) {\n return new Fail(\n this.attributes,\n this.children![0].createNodeInstance(namedRootNodeProvider, visitedBranches.slice())\n );\n }\n }),\n WAIT: (): WaitAstNode => ({\n type: \"wait\",\n attributes: [],\n duration: null,\n longestDuration: null,\n validate() {\n // A wait node must have a positive duration.\n if (this.duration! < 0) {\n throw new Error(\"a wait node must have a positive duration\");\n }\n\n // There is validation to carry out if a longest duration was defined.\n if (this.longestDuration) {\n // A wait node must have a positive longest duration.\n if (this.longestDuration < 0) {\n throw new Error(\"a wait node must have a positive longest duration if one is defined\");\n }\n\n // A wait node must not have a duration that exceeds the longest duration.\n if (this.duration! > this.longestDuration) {\n throw new Error(\"a wait node must not have a shortest duration that exceeds the longest duration\");\n }\n }\n },\n createNodeInstance() {\n return new Wait(this.attributes, this.duration!, this.longestDuration!);\n }\n }),\n ACTION: (): ActionAstNode => ({\n type: \"action\",\n attributes: [],\n actionName: \"\",\n actionArguments: [],\n validate() {},\n createNodeInstance() {\n return new Action(this.attributes, this.actionName!, this.actionArguments!);\n }\n }),\n CONDITION: (): ConditionAstNode => ({\n type: \"condition\",\n attributes: [],\n conditionName: \"\",\n conditionArguments: [],\n validate() {},\n createNodeInstance() {\n return new Condition(this.attributes, this.conditionName!, this.conditionArguments!);\n }\n })\n};\n\ntype OtherAstNodes = AstNode[];\n\n/**\n * Create an array of root AST nodes based on the given definition.\n * @param definition The definition to parse the AST nodes from.\n * @returns The base definition AST nodes.\n */\nexport default function buildRootASTNodes(definition: string): RootAstNode[] {\n // Swap out any node/attribute argument string literals with a placeholder and get a mapping of placeholders to original values as well as the processed definition.\n const { placeholders, processedDefinition } = substituteStringLiterals(definition);\n\n // Convert the processed definition (with substituted string literals) into an array of raw tokens.\n const tokens = parseTokensFromDefinition(processedDefinition);\n\n // There must be at least 3 tokens for the tree definition to be valid. 'ROOT', '{' and '}'.\n if (tokens.length < 3) {\n throw new Error(\"invalid token count\");\n }\n\n // We should have a matching number of '{' and '}' tokens. If not, then there are scopes that have not been properly closed.\n if (tokens.filter((token) => token === \"{\").length !== tokens.filter((token) => token === \"}\").length) {\n throw new Error(\"scope character mismatch\");\n }\n\n // Create a stack of node children arrays, starting with a definition scope.\n const stack: [RootAstNode[], ...OtherAstNodes[]] = [[]];\n const rootScope = stack[0];\n\n // We should keep processing the raw tokens until we run out of them.\n while (tokens.length) {\n // Grab the next token.\n const token = tokens.shift();\n\n const currentScope = stack[stack.length - 1] as OtherAstNodes;\n\n // How we create the next AST token depends on the current raw token value.\n switch (token!.toUpperCase()) {\n case \"ROOT\": {\n // Create a ROOT AST node.\n const node = ASTNodeFactories.ROOT();\n\n // Push the ROOT node into the current scope.\n rootScope.push(node);\n\n // We may have a root node name defined as an argument.\n if (tokens[0] === \"[\") {\n const rootArguments = getArguments(tokens, placeholders);\n\n // We should have only a single argument that is not an empty string for a root node, which is the root name identifier.\n if (rootArguments.length === 1 && rootArguments[0].type === \"identifier\") {\n // The root name will be the first and only node argument.\n node.name = rootArguments[0].value as string;\n } else {\n throw new Error(\"expected single root name argument\");\n }\n }\n\n // Try to pick any attributes off of the token stack.\n node.attributes = getAttributes(tokens, placeholders);\n\n popAndCheck(tokens, \"{\");\n\n // The new scope is that of the new ROOT nodes children.\n stack.push(node.children!);\n break;\n }\n\n case \"BRANCH\": {\n // Create a BRANCH AST node.\n const node = ASTNodeFactories.BRANCH();\n\n // Push the BRANCH node into the current scope.\n currentScope.push(node);\n\n // We must have arguments defined, as we require a branch name argument.\n if (tokens[0] !== \"[\") {\n throw new Error(\"expected single branch name argument\");\n }\n\n // The branch name will be defined as a node argument.\n const branchArguments = getArguments(tokens, placeholders);\n\n // We should have only a single identifer argument for a branch node, which is the branch name.\n if (branchArguments.length === 1 && branchArguments[0].type === \"identifier\") {\n // The branch name will be the first and only node argument.\n node.branchName = branchArguments[0].value as string;\n } else {\n throw new Error(\"expected single branch name argument\");\n }\n break;\n }\n\n case \"SELECTOR\": {\n // Create a SELECTOR AST node.\n const node = ASTNodeFactories.SELECTOR();\n\n // Push the SELECTOR node into the current scope.\n currentScope.push(node);\n\n // Try to pick any attributes off of the token stack.\n node.attributes = getAttributes(tokens, placeholders);\n\n popAndCheck(tokens, \"{\");\n\n // The new scope is that of the new SELECTOR nodes children.\n stack.push(node.children!);\n break;\n }\n\n case \"SEQUENCE\": {\n // Create a SEQUENCE AST node.\n const node = ASTNodeFactories.SEQUENCE();\n\n // Push the SEQUENCE node into the current scope.\n currentScope.push(node);\n\n // Try to pick any attributes off of the token stack.\n node.attributes = getAttributes(tokens, placeholders);\n\n popAndCheck(tokens, \"{\");\n\n // The new scope is that of the new SEQUENCE nodes children.\n stack.push(node.children!);\n break;\n }\n\n case \"PARALLEL\": {\n // Create a PARALLEL AST node.\n const node = ASTNodeFactories.PARALLEL();\n\n // Push the PARALLEL node into the current scope.\n currentScope.push(node);\n\n // Try to pick any attributes off of the token stack.\n node.attributes = getAttributes(tokens, placeholders);\n\n popAndCheck(tokens, \"{\");\n\n // The new scope is that of the new PARALLEL nodes children.\n stack.push(node.children!);\n break;\n }\n\n case \"LOTTO\": {\n // Create a LOTTO AST node.\n const node = ASTNodeFactories.LOTTO();\n\n // Push the LOTTO node into the current scope.\n currentScope.push(node);\n\n // If the next token is a '[' character then some ticket counts have been defined as arguments.\n if (tokens[0] === \"[\") {\n // Get the ticket count arguments, each argument must be a number.\n node.tickets = getArguments(\n tokens,\n placeholders,\n (arg) => arg.type === \"number\" && !!arg.isInteger,\n \"lotto node ticket counts must be integer values\"\n ).map((argument) => argument.value as number);\n }\n\n // Try to pick any attributes off of the token stack.\n node.attributes = getAttributes(tokens, placeholders);\n\n popAndCheck(tokens, \"{\");\n\n // The new scope is that of the new LOTTO nodes children.\n stack.push(node.children!);\n break;\n }\n\n case \"CONDITION\": {\n // Create a CONDITION AST node.\n const node = ASTNodeFactories.CONDITION();\n\n // Push the CONDITION node into the current scope.\n currentScope.push(node);\n\n // We must have arguments defined, as we require a condition function name argument.\n if (tokens[0] !== \"[\") {\n throw new Error(\"expected condition name identifier argument\");\n }\n\n // Grab the condition node arguments.\n const conditionArguments = getArguments(tokens, placeholders);\n\n // We should have at least a single identifier argument for a condition node, which is the condition function name.\n if (conditionArguments.length && conditionArguments[0].type === \"identifier\") {\n // The condition function name will be the first node argument.\n node.conditionName = conditionArguments.shift()!.value as string;\n } else {\n throw new Error(\"expected condition name identifier argument\");\n }\n\n // Only the first argument should have been an identifier, all following arguments must be string, number, boolean or null.\n conditionArguments\n .filter((arg) => arg.type === \"identifier\")\n .forEach((arg) => {\n throw new Error(\n \"invalid condition node argument value '\" +\n arg.value +\n \"', must be string, number, boolean or null\"\n );\n });\n\n // Any node arguments that follow the condition name identifier will be treated as condition function arguments.\n node.conditionArguments = conditionArguments;\n\n // Try to pick any attributes off of the token stack.\n node.attributes = getAttributes(tokens, placeholders);\n break;\n }\n\n case \"FLIP\": {\n // Create a FLIP AST node.\n const node = ASTNodeFactories.FLIP();\n\n // Push the Flip node into the current scope.\n currentScope.push(node);\n\n // Try to pick any attributes off of the token stack.\n node.attributes = getAttributes(tokens, placeholders);\n\n popAndCheck(tokens, \"{\");\n\n // The new scope is that of the new FLIP nodes children.\n stack.push(node.children!);\n break;\n }\n\n case \"SUCCEED\": {\n // Create a SUCCEED AST node.\n const node = ASTNodeFactories.SUCCEED();\n\n // Push the Succeed node into the current scope.\n currentScope.push(node);\n\n // Try to pick any attributes off of the token stack.\n node.attributes = getAttributes(tokens, placeholders);\n\n popAndCheck(tokens, \"{\");\n\n // The new scope is that of the new Succeed nodes children.\n stack.push(node.children!);\n break;\n }\n\n case \"FAIL\": {\n // Create a FAIL AST node.\n const node = ASTNodeFactories.FAIL();\n\n // Push the Fail node into the current scope.\n currentScope.push(node);\n\n // Try to pick any attributes off of the token stack.\n node.attributes = getAttributes(tokens, placeholders);\n\n popAndCheck(tokens, \"{\");\n\n // The new scope is that of the new Fail nodes children.\n stack.push(node.children!);\n break;\n }\n\n case \"WAIT\": {\n // Create a WAIT AST node.\n const node = ASTNodeFactories.WAIT();\n\n // Push the WAIT node into the current scope.\n currentScope.push(node);\n\n // Get the duration and potential longest duration of the wait.\n const durations = getArguments(\n tokens,\n placeholders,\n (arg) => arg.type === \"number\" && !!arg.isInteger,\n \"wait node durations must be integer values\"\n ).map((argument) => argument.value);\n\n // We should have got one or two durations.\n if (durations.length === 1) {\n // A static duration was defined.\n node.duration = durations[0] as number;\n } else if (durations.length === 2) {\n // A shortest and longest duration was defined.\n node.duration = durations[0] as number;\n node.longestDuration = durations[1] as number;\n } else {\n // An incorrect number of durations was defined.\n throw new Error(\"invalid number of wait node duration arguments defined\");\n }\n\n // Try to pick any attributes off of the token stack.\n node.attributes = getAttributes(tokens, placeholders);\n break;\n }\n\n case \"REPEAT\": {\n // Create a REPEAT AST node.\n const node = ASTNodeFactories.REPEAT();\n\n // Push the REPEAT node into the current scope.\n currentScope.push(node);\n\n // Check for iteration counts ([])\n if (tokens[0] === \"[\") {\n // An iteration count has been defined. Get the iteration and potential maximum iteration of the wait.\n const iterationArguments = getArguments(\n tokens,\n placeholders,\n (arg) => arg.type === \"number\" && !!arg.isInteger,\n \"repeat node iteration counts must be integer values\"\n ).map((argument) => argument.value);\n\n // We should have got one or two iteration counts.\n if (iterationArguments.length === 1) {\n // A static iteration count was defined.\n node.iterations = iterationArguments[0] as number;\n } else if (iterationArguments.length === 2) {\n // A minimum and maximum iteration count was defined.\n node.iterations = iterationArguments[0] as number;\n node.maximumIterations = iterationArguments[1] as number;\n } else {\n // An incorrect number of iteration counts was defined.\n throw new Error(\"invalid number of repeat node iteration count arguments defined\");\n }\n }\n\n // Try to pick any attributes off of the token stack.\n node.attributes = getAttributes(tokens, placeholders);\n\n popAndCheck(tokens, \"{\");\n\n // The new scope is that of the new REPEAT nodes children.\n stack.push(node.children!);\n break;\n }\n\n case \"RETRY\": {\n // Create a RETRY AST node.\n const node = ASTNodeFactories.RETRY();\n\n // Push the RETRY node into the current scope.\n currentScope.push(node);\n\n // Check for iteration counts ([])\n if (tokens[0] === \"[\") {\n // An iteration count has been defined. Get the iteration and potential maximum iteration of the wait.\n const iterationArguments = getArguments(\n tokens,\n placeholders,\n (arg) => arg.type === \"number\" && !!arg.isInteger,\n \"retry node iteration counts must be integer values\"\n ).map((argument) => argument.value);\n\n // We should have got one or two iteration counts.\n if (iterationArguments.length === 1) {\n // A static iteration count was defined.\n node.iterations = iterationArguments[0] as number;\n } else if (iterationArguments.length === 2) {\n // A minimum and maximum iteration count was defined.\n node.iterations = iterationArguments[0] as number;\n node.maximumIterations = iterationArguments[1] as number;\n } else {\n // An incorrect number of iteration counts was defined.\n throw new Error(\"invalid number of retry node iteration count arguments defined\");\n }\n }\n\n // Try to pick any attributes off of the token stack.\n node.attributes = getAttributes(tokens, placeholders);\n\n popAndCheck(tokens, \"{\");\n\n // The new scope is that of the new RETRY nodes children.\n stack.push(node.children!);\n break;\n }\n\n case \"ACTION\": {\n // Create a ACTION AST node.\n const node = ASTNodeFactories.ACTION();\n\n // Push the ACTION node into the current scope.\n currentScope.push(node);\n\n // We must have arguments defined, as we require an action name argument.\n if (tokens[0] !== \"[\") {\n throw new Error(\"expected action name identifier argument\");\n }\n\n // The action name will be defined as a node argument.\n const actionArguments = getArguments(tokens, placeholders);\n\n // We should have at least one identifer argument for an action node, which is the action name.\n if (actionArguments.length && actionArguments[0].type === \"identifier\") {\n // The action name will be the first and only node argument.\n node.actionName = actionArguments.shift()!.value as string;\n } else {\n throw new Error(\"expected action name identifier argument\");\n }\n\n // Only the first argument should have been an identifier, all following arguments must be string, number, boolean or null.\n actionArguments\n .filter((arg) => arg.type === \"identifier\")\n .forEach((arg) => {\n throw new Error(\n \"invalid action node argument value '\" +\n arg.value +\n \"', must be string, number, boolean or null\"\n );\n });\n\n // Any node arguments that follow the action name identifier will be treated as action function arguments.\n node.actionArguments = actionArguments;\n\n // Try to pick any attributes off of the token stack.\n node.attributes = getAttributes(tokens, placeholders);\n break;\n }\n\n case \"}\": {\n // The '}' character closes the current scope.\n stack.pop();\n break;\n }\n\n default: {\n throw new Error(\"unexpected token: \" + token);\n }\n }\n }\n\n // A function to recursively validate each of the nodes in the AST.\n const validateASTNode = (node: Validatable, depth: number): void => {\n // Validate the node.\n node.validate(depth);\n\n // Validate each child of the node.\n (node.children || []).forEach((child) => validateASTNode(child, depth + 1));\n };\n\n // Start node validation from the definition root.\n validateASTNode(\n {\n children: stack[0] as RootAstNode[],\n validate(this: { children: RootAstNode[] }) {\n // We must have at least one node defined as the definition scope, which should be a root node.\n if (this.children.length === 0) {\n throw new Error(\"expected root node to have been defined\");\n }\n\n // Each node at the base of the definition scope MUST be a root node.\n for (const definitionLevelNode of this.children) {\n if (definitionLevelNode.type !== \"root\") {\n throw new Error(\"expected root node at base of definition\");\n }\n }\n\n // Exactly one root node must not have a name defined. This will be the main root, others will have to be referenced via branch nodes.\n if (this.children.filter((definitionLevelNode) => definitionLevelNode.name === null).length !== 1) {\n throw new Error(\"expected single unnamed root node at base of definition to act as main root\");\n }\n\n // No two named root nodes can have matching names.\n const rootNodeNames: string[] = [];\n for (const definitionLevelNode of this.children) {\n if (rootNodeNames.indexOf(definitionLevelNode.name!) !== -1) {\n throw new Error(`multiple root nodes found with duplicate name '${definitionLevelNode.name}'`);\n } else {\n rootNodeNames.push(definitionLevelNode.name!);\n }\n }\n }\n },\n 0\n );\n\n // Return the root AST nodes.\n return stack[0];\n}\n\n/**\n * Pop the next raw token off of the stack and throw an error if it wasn't the expected one.\n * @param tokens The array of remaining tokens.\n * @param expected An optional string or array or items, one of which must match the next popped token.\n * @returns The popped token.\n */\nfunction popAndCheck(tokens: string[], expected: string | string[]) {\n // Get and remove the next token.\n const popped = tokens.shift();\n\n // We were expecting another token.\n if (popped === undefined) {\n throw new Error(\"unexpected end of definition\");\n }\n\n // Do we have an expected token/tokens array?\n if (expected !== undefined) {\n // Check whether the popped token matches at least one of our expected items.\n var tokenMatchesExpectation = ([] as string[])\n .concat(expected)\n .some((item) => popped.toUpperCase() === item.toUpperCase());\n\n // Throw an error if the popped token didn't match any of our expected items.\n if (!tokenMatchesExpectation) {\n const expectationString = ([] as string[])\n .concat(expected)\n .map((item) => \"'\" + item + \"'\")\n .join(\" or \");\n throw new Error(\"unexpected token found. Expected \" + expectationString + \" but got '\" + popped + \"'\");\n }\n }\n\n // Return the popped token.\n return popped;\n}\n\ntype Placeholders = { [key: string]: string };\n\n/**\n * Pull an argument definition list off of the token stack.\n * @param tokens The array of remaining tokens.\n * @param stringArgumentPlaceholders The mapping of string literal node argument placeholders to original values.\n * @param argumentValidator The argument validator function.\n * @param validationFailedMessage The exception message to throw if argument validation fails.\n * @returns The argument definition list.\n */\nfunction getArguments(\n tokens: string[],\n stringArgumentPlaceholders: Placeholders,\n argumentValidator?: (arg: AnyArgument) => boolean,\n validationFailedMessage?: string\n) {\n // Any lists of arguments will always be wrapped in '[]' for node arguments or '()' for attribute arguments.\n // We are looking for a '[' or '(' opener that wraps the argument tokens and the relevant closer.\n const closer = popAndCheck(tokens, [\"[\", \"(\"]) === \"[\" ? \"]\" : \")\";\n\n const argumentListTokens: string[] = [];\n const argumentList: AnyArgument[] = [];\n\n // Grab all tokens between the '[' and ']' or '(' and ')'.\n while (tokens.length && tokens[0] !== closer) {\n // The next token is part of our arguments list.\n argumentListTokens.push(tokens.shift()!);\n }\n\n // Validate the order of the argument tokens. Each token must either be a ',' or a single argument that satisfies the validator.\n argumentListTokens.forEach((token, index) => {\n // Get whether this token should be an actual argument.\n const shouldBeArgumentToken = !(index & 1);\n\n // If the current token should be an actual argument then validate it,otherwise it should be a ',' token.\n if (shouldBeArgumentToken) {\n // Get the argument definition.\n const argumentDefinition = getArgumentDefinition(token!, stringArgumentPlaceholders);\n\n // Try to validate the argument.\n if (argumentValidator && !argumentValidator(argumentDefinition)) {\n throw new Error(validationFailedMessage);\n }\n\n // This is a valid argument!\n argumentList.push(argumentDefinition);\n } else {\n // The current token should be a ',' token.\n if (token !== \",\") {\n throw new Error(`invalid argument list, expected ',' or ']' but got '${token}'`);\n }\n }\n });\n\n // The arguments list should terminate with a ']' or ')' token, depending on the opener.\n popAndCheck(tokens, closer);\n\n // Return the argument list.\n return argumentList;\n}\n\n/**\n * Gets an argument value definition.\n * @param token The argument token.\n * @param stringArgumentPlaceholders The mapping of string literal node argument placeholders to original values.\n * @returns An argument value definition.\n */\nfunction getArgumentDefinition(token: string, stringArgumentPlaceholders: Placeholders): AnyArgument {\n // Check whether the token represents a null value.\n if (token === \"null\") {\n return {\n value: null,\n type: \"null\"\n } as NullArgument;\n }\n\n // Check whether the token represents a boolean value.\n if (token === \"true\" || token === \"false\") {\n return {\n value: token === \"true\",\n type: \"boolean\"\n } as BooleanArgument;\n }\n\n // Check whether the token represents a number value.\n // TODO: Relies on broken isNaN - see MDN.\n // if (!Number.isNaN(token)) {\n if (!isNaN(token as any)) {\n return {\n value: parseFloat(token),\n isInteger: parseFloat(token) === parseInt(token, 10),\n type: \"number\"\n } as NumberArgument;\n }\n\n // Check whether the token is a placeholder (e.g. @@0@@) representing a string literal.\n if (token.match(/^@@\\d+@@$/g)) {\n return {\n value: stringArgumentPlaceholders[token].replace('\\\\\"', '\"'),\n type: \"string\"\n } as StringPlaceholderArgument;\n }\n\n // The only remaining option is that the argument value is an identifier.\n return {\n value: token,\n type: \"identifier\"\n } as IdentifierArgument;\n}\n\n/**\n * Pull any attributes off of the token stack.\n * @param tokens The array of remaining tokens.\n * @param stringArgumentPlaceholders The mapping of string literal node argument placeholders to original values.\n * @returns An array of attributes defined by any directly following tokens.\n */\nfunction getAttributes(tokens: string[], stringArgumentPlaceholders: Placeholders) {\n // Create an array to hold any attributes found.\n const attributes: Attribute[] = [];\n\n // Keep track of names of attribute that we have found on the token stack, as we cannot have duplicates.\n const attributesFound: string[] = [];\n\n // Try to get the attribute factory for the next token.\n let attributeFactory = AttributeFactories[(tokens[0] || \"\").toUpperCase()];\n\n // Pull attribute tokens off of the tokens stack until we have no more.\n while (attributeFactory) {\n // Check to make sure that we have not already created a attribute of this type for this node.\n if (attributesFound.indexOf(tokens[0].toUpperCase()) !== -1) {\n throw new Error(`duplicate attribute '${tokens[0].toUpperCase()}' found for node`);\n }\n\n // Add the current attribute type to our array of found attributes.\n attributesFound.push(tokens.shift()!.toUpperCase());\n\n // Grab any attribute arguments.\n const attributeArguments = getArguments(tokens, stringArgumentPlaceholders);\n\n // The first attribute argument has to be an identifer, this will reference an agent function.\n if (attributeArguments.length === 0 || attributeArguments[0].type !== \"identifier\") {\n throw new Error(\"expected agent function name identifier argument for attribute\");\n }\n\n // Grab the first attribute which is an identifier that will reference an agent function.\n const attributeFunctionName = attributeArguments.shift()! as IdentifierArgument;\n\n // Any remaining attribute arguments must have a type of string, number, boolean or null.\n attributeArguments\n .filter((arg) => arg.type === \"identifier\")\n .forEach((arg) => {\n throw new Error(\n \"invalid attribute argument value '\" + arg.value + \"', must be string, number, boolean or null\"\n );\n });\n\n // Create the attribute and add it to the array of attributes found.\n attributes.push(attributeFactory(attributeFunctionName.value, attributeArguments));\n\n // Try to get the next attribute name token, as there could be multiple.\n attributeFactory = AttributeFactories[(tokens[0] || \"\").toUpperCase()];\n }\n\n return attributes;\n}\n\n/**\n * Swaps out any node/attribute argument string literals with placeholders.\n * @param definition The definition.\n * @returns An object containing a mapping of placeholders to original string values as well as the processed definition string.\n */\nfunction substituteStringLiterals(definition: string): {\n placeholders: { [key: string]: string };\n processedDefinition: string;\n} {\n // Create an object to hold the mapping of placeholders to original string values.\n const placeholders: Placeholders = {};\n\n // Replace any string literals wrapped with double quotes in our definition with placeholders to be processed later.\n const processedDefinition = definition.replace(/\\\"(\\\\.|[^\"\\\\])*\\\"/g, (match) => {\n var strippedMatch = match.substring(1, match.length - 1);\n var placeholder = Object.keys(placeholders).find((key) => placeholders[key] === strippedMatch);\n\n // If we have no existing string literal match then create a new placeholder.\n if (!placeholder) {\n placeholder = `@@${Object.keys(placeholders).length}@@`;\n placeholders[placeholder] = strippedMatch;\n }\n\n return placeholder;\n });\n\n return { placeholders, processedDefinition };\n}\n\n/**\n * Parse the tree definition into an array of raw tokens.\n * @param definition The definition.\n * @returns An array of tokens parsed from the definition.\n */\nfunction parseTokensFromDefinition(definition: string): string[] {\n // Add some space around various important characters so that they can be plucked out easier as individual tokens.\n definition = definition.replace(/\\(/g, \" ( \");\n definition = definition.replace(/\\)/g, \" ) \");\n definition = definition.replace(/\\{/g, \" { \");\n definition = definition.replace(/\\}/g, \" } \");\n definition = definition.replace(/\\]/g, \" ] \");\n definition = definition.replace(/\\[/g, \" [ \");\n definition = definition.replace(/\\,/g, \" , \");\n\n // Split the definition into raw token form and return it.\n return definition.replace(/\\s+/g, \" \").trim().split(\" \");\n}\n", "/**\r\n * Pop the next raw token from the specified array of tokens and throw an error if it wasn't the expected one.\r\n * @param tokens The array of tokens.\r\n * @param expected An optional string or array or items, one of which must match the next popped token.\r\n * @returns The popped token.\r\n */\r\nexport function popAndCheck(tokens: string[], expected?: string | string[]): string {\r\n // Get and remove the next token.\r\n const popped = tokens.shift();\r\n\r\n // We were expecting another token but there aren't any.\r\n if (popped === undefined) {\r\n throw new Error(\"unexpected end of definition\");\r\n }\r\n\r\n // Do we have an expected token/tokens array?\r\n if (expected != undefined) {\r\n // Get an array of expected values, if the popped token matches any then we are all good.\r\n const expectedValues = (typeof expected === \"string\") ? [expected] : expected;\r\n\r\n // Check whether the popped token matches at least one of our expected items.\r\n var tokenMatchesExpectation = expectedValues.some((item) => popped.toUpperCase() === item.toUpperCase());\r\n\r\n // Throw an error if the popped token didn't match any of our expected items.\r\n if (!tokenMatchesExpectation) {\r\n const expectationString = expectedValues.map((item) => \"'\" + item + \"'\").join(\" or \");\r\n throw new Error(\"unexpected token found. Expected \" + expectationString + \" but got '\" + popped + \"'\");\r\n }\r\n }\r\n\r\n // Return the popped token.\r\n return popped;\r\n}", "import { popAndCheck } from \"./DSLUtilities\";\r\n\r\n/**\r\n * A type defining the arguments that can be passed to an agent function.\r\n */\r\nexport type AgentFunctionArguments = (string | number | boolean | null | undefined)[];\r\n\r\n/**\r\n * A guard attribute for a node.\r\n */\r\nexport type GuardAttributeDefinition = {\r\n call: string;\r\n args?: AgentFunctionArguments;\r\n}\r\n\r\n/**\r\n * A callback attribute for a node.\r\n */\r\nexport type CallbackAttributeDefinition = {\r\n call: string;\r\n args?: AgentFunctionArguments;\r\n}\r\n\r\n/**\r\n * A type defining a general node definition.\r\n */\r\nexport type NodeDefinition = {\r\n type: string;\r\n while?: GuardAttributeDefinition;\r\n until?: GuardAttributeDefinition;\r\n entry?: CallbackAttributeDefinition;\r\n exit?: CallbackAttributeDefinition;\r\n step?: CallbackAttributeDefinition;\r\n}\r\n\r\n/**\r\n * A composite node that can contain any number of child nodes.\r\n */\r\nexport type CompositeDefinition = NodeDefinition & {\r\n children: AnyChildNode[];\r\n}\r\n\r\n/**\r\n * A decorator node, a composite with only a single child node.\r\n */\r\nexport type DecoratorDefinition = NodeDefinition & {\r\n child: AnyChildNode;\r\n}\r\n\r\n/**\r\n * A branch node.\r\n */\r\nexport type BranchDefinition = NodeDefinition & {\r\n type: \"branch\";\r\n ref: string;\r\n}\r\n\r\n/**\r\n * An action node.\r\n */\r\nexport type ActionDefinition = NodeDefinition & {\r\n type: \"action\";\r\n call: string;\r\n args?: AgentFunctionArguments;\r\n}\r\n\r\n/**\r\n * A condition node.\r\n */\r\nexport type ConditionDefinition = NodeDefinition & {\r\n type: \"condition\";\r\n call: string;\r\n args?: AgentFunctionArguments;\r\n}\r\n\r\n/**\r\n * A wait node.\r\n */\r\nexport type WaitDefinition = NodeDefinition & {\r\n type: \"wait\";\r\n duration: number | [number, number];\r\n}\r\n\r\n/**\r\n * A sequence node.\r\n */\r\nexport type SequenceDefinition = CompositeDefinition & {\r\n type: \"sequence\";\r\n}\r\n\r\n/**\r\n * A selector node.\r\n */\r\nexport type SelectorDefinition = CompositeDefinition & {\r\n type: \"selector\";\r\n}\r\n\r\n/**\r\n * A lotto node.\r\n */\r\nexport type LottoDefinition = CompositeDefinition & {\r\n type: \"lotto\";\r\n weights?: number[]\r\n}\r\n\r\n/**\r\n * A parallel node.\r\n */\r\nexport type ParallelDefinition = CompositeDefinition & {\r\n type: \"parallel\";\r\n}\r\n\r\n/**\r\n * A root node.\r\n */\r\nexport type RootDefinition = DecoratorDefinition & {\r\n type: \"root\";\r\n id?: string;\r\n}\r\n\r\n/**\r\n * A repeat node.\r\n */\r\nexport type RepeatDefinition = DecoratorDefinition & {\r\n type: \"repeat\";\r\n iterations?: number | [number, number];\r\n}\r\n\r\n/**\r\n * A retry node.\r\n */\r\nexport type RetryDefinition = DecoratorDefinition & {\r\n type: \"retry\";\r\n attempts?: number | [number, number];\r\n}\r\n\r\n/**\r\n * A flip node.\r\n */\r\nexport type FlipDefinition = DecoratorDefinition & {\r\n type: \"flip\";\r\n}\r\n\r\n/**\r\n * A succeed node.\r\n */\r\nexport type SucceedDefinition = DecoratorDefinition & {\r\n type: \"succeed\";\r\n}\r\n\r\n/**\r\n * A fail node.\r\n */\r\nexport type FailDefinition = DecoratorDefinition & {\r\n type: \"fail\";\r\n}\r\n\r\n/**\r\n * A type defining any node type.\r\n */\r\nexport type AnyNode = BranchDefinition | ActionDefinition | ConditionDefinition | WaitDefinition | SequenceDefinition |\r\n SelectorDefinition | LottoDefinition | ParallelDefinition | RootDefinition | RepeatDefinition | RetryDefinition | FlipDefinition | SucceedDefinition | FailDefinition;\r\n\r\n/**\r\n * A type defining any node type that can be a child of composite parent node.\r\n */\r\nexport type AnyChildNode = Exclude;\r\n\r\n/**\r\n * A type defining an object that holds a reference to substitued string literals parsed from the definition.\r\n */\r\ntype StringLiteralPlaceholders = { [key: string]: string };\r\n\r\nfunction isLeafNode(node: NodeDefinition): node is NodeDefinition {\r\n return [\"branch\", \"action\", \"condition\", \"wait\"].includes(node.type);\r\n}\r\n\r\nfunction isDecoratorNode(node: NodeDefinition): node is DecoratorDefinition {\r\n return [\"root\", \"repeat\", \"retry\", \"flip\", \"succeed\", \"fail\"].includes(node.type);\r\n}\r\n\r\nfunction isCompositeNode(node: NodeDefinition): node is CompositeDefinition {\r\n return [\"sequence\", \"selector\", \"lotto\", \"parallel\"].includes(node.type);\r\n}\r\n\r\n/**\r\n * Parse the tree definition string into a JSON definition.\r\n * @param definition The tree definition string.\r\n * @returns The root node JSON definitions.\r\n */\r\nexport function parseToJSON(definition: string): RootDefinition[] {\r\n // Swap out any node/attribute argument string literals with a placeholder and get a mapping of placeholders to original values as well as the processed definition.\r\n const { placeholders, processedDefinition } = substituteStringLiterals(definition);\r\n\r\n // Parse our definition definition string into an array of raw tokens.\r\n const tokens = parseTokensFromDefinition(definition);\r\n\r\n return convertTokensToJSONDefinition(tokens, placeholders, processedDefinition);\r\n}\r\n\r\n/**\r\n * Converts the specified tree definition tokens into a JSON definition.\r\n * @param tokens The tree definition tokens.\r\n * @param placeholders The substituted string literal placeholders.\r\n * @returns The root node JSON definitions.\r\n */\r\nexport function convertTokensToJSONDefinition(tokens: string[], placeholders: StringLiteralPlaceholders, processedDefinition: string): RootDefinition[] {\r\n // There must be at least 3 tokens for the tree definition to be valid. 'ROOT', '{' and '}'.\r\n if (tokens.length < 3) {\r\n throw new Error(\"invalid token count\");\r\n }\r\n\r\n // We should have a matching number of '{' and '}' tokens. If not, then there are scopes that have not been properly closed.\r\n if (tokens.filter((token) => token === \"{\").length !== tokens.filter((token) => token === \"}\").length) {\r\n throw new Error(\"scope character mismatch\");\r\n }\r\n\r\n // Create a stack of tree stack arrays where root nodes will always be at the root.\r\n const treeStacks: [Partial, ...Partial[]][] = [];\r\n\r\n // Create an array of all root node definitions that we create.\r\n const rootNodes: Partial[] = [];\r\n\r\n // A helper function used to push root node definitions onto the stack.\r\n const pushRootNode = (rootNode: RootDefinition) => {\r\n // Add the root node definition to our array of all parsed root node definitions.\r\n rootNodes.push(rootNode);\r\n\r\n // Add the root node definition to the root of a new tree stack. \r\n treeStacks.push([rootNode]);\r\n }\r\n \r\n // A helper function used to push non-root node definitions onto the stack.\r\n const pushNode = (node: AnyChildNode) => {\r\n // Get the current tree stack that we are populating.\r\n const currentTreeStack = treeStacks[treeStacks.length - 1];\r\n\r\n // TODO Handle cases where we may not have a current root stack.\r\n // This may happen if a root node is not the initially defined one?\r\n\r\n // Get the bottom-most node in the current tree stack.\r\n const bottomNode = currentTreeStack[currentTreeStack.length - 1] as AnyNode;\r\n\r\n // TODO Handle cases where we may not have a bottom-most node.\r\n // Also a potential issue with a badly defined tree.\r\n\r\n // If the bottom-most node in the current root stack is a composite or decorator\r\n // node then the current node should be added as a child of the bottom-most node.\r\n if (isCompositeNode(bottomNode)) {\r\n bottomNode.children = bottomNode.children || [];\r\n bottomNode.children.push(node);\r\n } else if (isDecoratorNode(bottomNode)) {\r\n // If the bottom node already has a chld node set then throw an error as a decorator should only have a single child.\r\n if (bottomNode.child) {\r\n throw new Error(\"a decorator node must only have a single child node\");\r\n }\r\n\r\n bottomNode.child = node;\r\n }\r\n\r\n // If the node we are adding is also a composite or decorator node, then we should push it \r\n // onto the current tree stack, as subsequent nodes will be added as its child/children.\r\n if (!isLeafNode(node)) {\r\n currentTreeStack.push(node);\r\n }\r\n };\r\n\r\n // A helper function used to pop node definitions off of the stack.\r\n const popNode = () => {\r\n // Get the current tree stack that we are populating.\r\n const currentTreeStack = treeStacks[treeStacks.length - 1];\r\n\r\n // Pop the top-most node in the current tree stack if there is one.\r\n if (currentTreeStack.length) {\r\n currentTreeStack.pop();\r\n }\r\n\r\n // We don't want any empty tree stacks in our stack of tree stacks. \r\n if (!currentTreeStack.length) {\r\n treeStacks.pop();\r\n }\r\n };\r\n\r\n // We should keep processing the raw tokens until we run out of them.\r\n while (tokens.length) {\r\n // Grab the next token.\r\n const token = tokens.shift()!;\r\n\r\n // How we create the next node depends on the current raw token value.\r\n switch (token.toUpperCase()) {\r\n case \"ROOT\": {\r\n // A root node will always be the base of a new root stack.\r\n pushRootNode(createRootNode(tokens));\r\n break;\r\n }\r\n\r\n case \"SEQUENCE\": {\r\n pushNode(createSequenceNode(tokens));\r\n break;\r\n }\r\n\r\n case \"ACTION\": {\r\n pushNode(createActionNode(tokens));\r\n break;\r\n }\r\n\r\n case \"}\": {\r\n // The '}' character closes the current scope and means that we have to pop a node off of the current stack.\r\n popNode();\r\n break;\r\n }\r\n\r\n default: {\r\n throw new Error(\"unexpected token: \" + token);\r\n }\r\n }\r\n }\r\n\r\n return rootNodes as RootDefinition[];\r\n}\r\n\r\nfunction createRootNode(tokens: string[]): RootDefinition {\r\n // Create the root node definition.\r\n const node = { type: \"root\" } as RootDefinition;\r\n\r\n // TODO Grab 'id' if defined as a node argument.\r\n // TODO Grab attributes.\r\n\r\n // This is a decorator node, so we expect an opening '{'.\r\n popAndCheck(tokens, \"{\");\r\n\r\n return node;\r\n}\r\n\r\nfunction createSequenceNode(tokens: string[]): SequenceDefinition {\r\n const node = { type: \"sequence\" } as SequenceDefinition;\r\n\r\n // TODO Grab attributes.\r\n\r\n // This is a composite node, so we expect an opening '{'.\r\n popAndCheck(tokens, \"{\");\r\n\r\n return node;\r\n}\r\n\r\nfunction createActionNode(tokens: string[]): ActionDefinition {\r\n const node = { type: \"action\" } as ActionDefinition;\r\n\r\n // TODO Grab attributes.\r\n\r\n return node;\r\n}\r\n\r\n/**\r\n * Swaps out any node/attribute argument string literals with placeholders.\r\n * @param definition The definition.\r\n * @returns An object containing a mapping of placeholders to original string values as well as the processed definition string.\r\n */\r\nfunction substituteStringLiterals(definition: string): {\r\n placeholders: StringLiteralPlaceholders;\r\n processedDefinition: string;\r\n} {\r\n // Create an object to hold the mapping of placeholders to original string values.\r\n const placeholders: StringLiteralPlaceholders = {};\r\n\r\n // Replace any string literals wrapped with double quotes in our definition with placeholders to be processed later.\r\n const processedDefinition = definition.replace(/\\\"(\\\\.|[^\"\\\\])*\\\"/g, (match) => {\r\n var strippedMatch = match.substring(1, match.length - 1);\r\n var placeholder = Object.keys(placeholders).find((key) => placeholders[key] === strippedMatch);\r\n\r\n // If we have no existing string literal match then create a new placeholder.\r\n if (!placeholder) {\r\n placeholder = `@@${Object.keys(placeholders).length}@@`;\r\n placeholders[placeholder] = strippedMatch;\r\n }\r\n\r\n return placeholder;\r\n });\r\n\r\n return { placeholders, processedDefinition };\r\n}\r\n\r\n/**\r\n * Parse the tree definition into an array of raw tokens.\r\n * @param definition The definition.\r\n * @returns An array of tokens parsed from the definition.\r\n */\r\nfunction parseTokensFromDefinition(definition: string): string[] {\r\n // Add some space around various important characters so that they can be plucked out easier as individual tokens.\r\n definition = definition.replace(/\\(/g, \" ( \");\r\n definition = definition.replace(/\\)/g, \" ) \");\r\n definition = definition.replace(/\\{/g, \" { \");\r\n definition = definition.replace(/\\}/g, \" } \");\r\n definition = definition.replace(/\\]/g, \" ] \");\r\n definition = definition.replace(/\\[/g, \" [ \");\r\n definition = definition.replace(/\\,/g, \" , \");\r\n\r\n // Split the definition into raw token form and return it.\r\n return definition.replace(/\\s+/g, \" \").trim().split(\" \");\r\n}", "import GuardPath, { GuardPathPart } from \"./attributes/guards/GuardPath\";\nimport buildRootASTNodes, { AnyArgument, RootAstNode } from \"./RootAstNodesBuilder\";\nimport State, { AnyState } from \"./State\";\nimport Lookup from \"./Lookup\";\nimport Node from \"./nodes/Node\";\nimport Root from \"./nodes/decorator/Root\";\nimport Composite from \"./nodes/composite/Composite\";\nimport Decorator from \"./nodes/decorator/Decorator\";\nimport { Agent, GlobalFunction } from \"./Agent\";\nimport { CallbackAttributeDetails } from \"./attributes/callbacks/Callback\";\nimport { GuardAttributeDetails } from \"./attributes/guards/Guard\";\nimport { BehaviourTreeOptions } from \"./BehaviourTreeOptions\";\nimport { parseToJSON } from \"./dsl/DSLDefinitionParser\";\n\n// Purely for outside inspection of the tree.\nexport type FlattenedTreeNode = {\n id: string;\n type: string;\n caption: string;\n state: AnyState;\n guards: GuardAttributeDetails[];\n callbacks: CallbackAttributeDetails[];\n args: AnyArgument[];\n parentId: string | null;\n};\n\n/**\n * A representation of a behaviour tree.\n */\nexport class BehaviourTree {\n /**\n * The main root tree node.\n */\n public readonly rootNode: Root;\n\n /**\n * Creates a new instance of the BehaviourTree class.\n * @param definition The behaviour tree definition.\n * @param agent The agent instance that this behaviour tree is modelling behaviour for.\n * @param options The behaviour tree options object.\n */\n constructor(definition: string, private agent: Agent, private options: BehaviourTreeOptions = {}) {\n // The tree definition must be defined and a valid string.\n if (typeof definition !== \"string\") {\n throw new Error(\"the tree definition must be a string\");\n }\n\n // The agent must be defined and not null.\n if (typeof agent !== \"object\" || agent === null) {\n throw new Error(\"the agent must be defined and not null\");\n }\n\n // Parse the behaviour tree definition, create the populated tree of behaviour tree nodes, and get the root.\n this.rootNode = BehaviourTree._createRootNode(definition);\n }\n\n /**\n * Gets whether the tree is in the RUNNING state.\n * @returns true if the tree is in the RUNNING state, otherwise false.\n */\n isRunning() {\n return this.rootNode.getState() === State.RUNNING;\n }\n\n /**\n * Gets the current tree state of SUCCEEDED, FAILED, READY or RUNNING.\n * @returns The current tree state.\n */\n getState() {\n return this.rootNode.getState();\n }\n\n /**\n * Step the tree.\n * 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.\n * 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\n * 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.\n *\n * 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.\n */\n step() {\n // If the root node has already been stepped to completion then we need to reset it.\n if (this.rootNode.getState() === State.SUCCEEDED || this.rootNode.getState() === State.FAILED) {\n this.rootNode.reset();\n }\n\n try {\n this.rootNode.update(this.agent, this.options);\n } catch (exception) {\n throw new Error(`error stepping tree: ${(exception as Error).message}`);\n }\n }\n\n /**\n * Resets the tree from the root node outwards to each nested node, giving each a state of READY.\n */\n reset() {\n this.rootNode.reset();\n }\n\n /**\n * Gets the flattened details of every node in the tree.\n * @returns The flattened details of every node in the tree.\n */\n getFlattenedNodeDetails(): FlattenedTreeNode[] {\n // Create an empty flattened array of tree nodes.\n const flattenedTreeNodes: FlattenedTreeNode[] = [];\n\n /**\n * Helper function to process a node instance and push details into the flattened tree nodes array.\n * @param node The current node.\n * @param parentUid The UID of the node parent, or null if the node is the main root node.\n */\n const processNode = (node: Node, parentUid: string | null) => {\n // Get the guard and callback attribute details for this node.\n const guards = node\n .getAttributes()\n .filter((attribute) => attribute.isGuard())\n .map((attribute) => attribute.getDetails()) as GuardAttributeDetails[];\n const callbacks = node\n .getAttributes()\n .filter((attribute) => !attribute.isGuard())\n .map((attribute) => attribute.getDetails()) as CallbackAttributeDetails[];\n\n // Push the current node into the flattened nodes array.\n flattenedTreeNodes.push({\n id: node.getUid(),\n type: node.getType(),\n caption: node.getName(),\n state: node.getState(),\n guards,\n callbacks,\n args: node.getArguments(),\n parentId: parentUid\n });\n\n // Process each of the nodes children if it is not a leaf node.\n if (!node.isLeafNode()) {\n (node as Composite | Decorator)\n .getChildren()\n .forEach((child) => processNode(child, (node as Composite | Decorator).getUid()));\n }\n };\n\n // Convert the nested node structure into a flattened array of node details.\n processNode(this.rootNode, null);\n\n return flattenedTreeNodes;\n }\n\n /**\n * Registers the action/condition/guard/callback function or subtree with the given name.\n * @param name The name of the function or subtree to register.\n * @param value The function or subtree definition to register.\n */\n static register(name: string, value: GlobalFunction | string) {\n if (typeof value === \"function\") {\n // We are going to register a action/condition/guard/callback function.\n Lookup.setFunc(name, value);\n } else if (typeof value === \"string\") {\n // We are going to register a subtree.\n let rootASTNodes: RootAstNode[];\n\n try {\n // Try to create the behaviour tree AST based on the definition provided, this could fail if the definition is invalid.\n rootASTNodes = buildRootASTNodes(value);\n } catch (exception) {\n // There was an issue in trying to parse and build the tree definition.\n throw new Error(`error registering definition: ${(exception as Error).message}`);\n }\n\n // This function should only ever be called with a definition containing a single unnamed root node.\n if (rootASTNodes.length != 1 || rootASTNodes[0].name !== null) {\n throw new Error(\"error registering definition: expected a single unnamed root node\");\n }\n\n Lookup.setSubtree(name, rootASTNodes[0]);\n } else {\n throw new Error(\"unexpected value, expected string definition or function\");\n }\n }\n\n /**\n * Unregisters the registered action/condition/guard/callback function or subtree with the given name.\n * @param name The name of the registered action/condition/guard/callback function or subtree to unregister.\n */\n static unregister(name: string): void {\n Lookup.remove(name);\n }\n\n /**\n * Unregister all registered action/condition/guard/callback functions and subtrees.\n */\n static unregisterAll(): void {\n Lookup.empty();\n }\n\n /**\n * Parses a behaviour tree definition and creates a tree of behaviour tree nodes.\n * @param {string} definition The behaviour tree definition.\n * @returns The root behaviour tree node.\n */\n private static _createRootNode(definition: string): Root {\n // TODO Remove!\n try {\n parseToJSON(definition);\n } catch (exception) {\n console.log(exception);\n }\n\n try {\n // Try to create the behaviour tree AST based on the definition provided, this could fail if the definition is invalid.\n const rootASTNodes = buildRootASTNodes(definition);\n\n // Create a symbol to use as the main root key in our root node mapping.\n const mainRootNodeKey = Symbol(\"__root__\");\n\n // Create a mapping of root node names to root AST tokens. The main root node will have a key of Symbol(\"__root__\").\n const rootNodeMap: { [key: string | symbol]: RootAstNode } = {};\n for (const rootASTNode of rootASTNodes) {\n rootNodeMap[rootASTNode.name === null ? mainRootNodeKey : rootASTNode.name!] = rootASTNode;\n }\n\n // Convert the AST to our actual tree and get the root node.\n const rootNode: Root = rootNodeMap[mainRootNodeKey].createNodeInstance(\n // Create a provider for named root nodes that are part of our definition or have been registered. Prioritising the former.\n (name: string): RootAstNode => (rootNodeMap[name] ? rootNodeMap[name] : Lookup.getSubtree(name)),\n []\n );\n\n // Set a guard path on every leaf of the tree to evaluate as part of its update.\n BehaviourTree._applyLeafNodeGuardPaths(rootNode);\n\n // Return the root node.\n return rootNode;\n } catch (exception) {\n // There was an issue in trying to parse and build the tree definition.\n throw new Error(`error parsing tree: ${(exception as Error).message}\\n${(exception as Error).stack}`);\n }\n }\n\n /**\n * Applies a guard path to every leaf of the tree to evaluate as part of each update.\n * @param rootNode The main root tree node.\n */\n private static _applyLeafNodeGuardPaths(rootNode: Root) {\n const nodePaths: Node[][] = [];\n\n const findLeafNodes = (path: Node[], node: Node) => {\n // Add the current node to the path.\n path = path.concat(node);\n\n // Check whether the current node is a leaf node.\n if (node.isLeafNode()) {\n nodePaths.push(path);\n } else {\n (node as Composite | Decorator).getChildren().forEach((child) => findLeafNodes(path, child));\n }\n };\n\n // Find all leaf node paths, starting from the root.\n findLeafNodes([], rootNode);\n\n nodePaths.forEach((path) => {\n // Each node in the current path will have to be assigned a guard path, working from the root outwards.\n for (let depth = 0; depth < path.length; depth++) {\n // Get the node in the path at the current depth.\n const currentNode = path[depth];\n\n // The node may already have been assigned a guard path, if so just skip it.\n if (currentNode.hasGuardPath()) {\n continue;\n }\n\n // Create the guard path for the current node.\n const guardPath = new GuardPath(\n path\n .slice(0, depth + 1)\n .map((node) => ({ node, guards: node.getGuardAttributes() }))\n .filter((details) => details.guards.length > 0)\n );\n\n // Assign the guard path to the current node.\n currentNode.setGuardPath(guardPath);\n }\n });\n }\n}\n"], + "mappings": "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", + "names": ["Participant", "Lotto", "createLotto", "State", "createLotto", "popAndCheck", "substituteStringLiterals", "parseTokensFromDefinition", "popAndCheck"] } diff --git a/dist/dsl/DSLDefinitionParser.d.ts b/dist/dsl/DSLDefinitionParser.d.ts new file mode 100644 index 0000000..023bdfe --- /dev/null +++ b/dist/dsl/DSLDefinitionParser.d.ts @@ -0,0 +1,163 @@ +/** + * A type defining the arguments that can be passed to an agent function. + */ +export type AgentFunctionArguments = (string | number | boolean | null | undefined)[]; +/** + * A guard attribute for a node. + */ +export type GuardAttributeDefinition = { + call: string; + args?: AgentFunctionArguments; +}; +/** + * A callback attribute for a node. + */ +export type CallbackAttributeDefinition = { + call: string; + args?: AgentFunctionArguments; +}; +/** + * A type defining a general node definition. + */ +export type NodeDefinition = { + type: string; + while?: GuardAttributeDefinition; + until?: GuardAttributeDefinition; + entry?: CallbackAttributeDefinition; + exit?: CallbackAttributeDefinition; + step?: CallbackAttributeDefinition; +}; +/** + * A composite node that can contain any number of child nodes. + */ +export type CompositeDefinition = NodeDefinition & { + children: AnyChildNode[]; +}; +/** + * A decorator node, a composite with only a single child node. + */ +export type DecoratorDefinition = NodeDefinition & { + child: AnyChildNode; +}; +/** + * A branch node. + */ +export type BranchDefinition = NodeDefinition & { + type: "branch"; + ref: string; +}; +/** + * An action node. + */ +export type ActionDefinition = NodeDefinition & { + type: "action"; + call: string; + args?: AgentFunctionArguments; +}; +/** + * A condition node. + */ +export type ConditionDefinition = NodeDefinition & { + type: "condition"; + call: string; + args?: AgentFunctionArguments; +}; +/** + * A wait node. + */ +export type WaitDefinition = NodeDefinition & { + type: "wait"; + duration: number | [number, number]; +}; +/** + * A sequence node. + */ +export type SequenceDefinition = CompositeDefinition & { + type: "sequence"; +}; +/** + * A selector node. + */ +export type SelectorDefinition = CompositeDefinition & { + type: "selector"; +}; +/** + * A lotto node. + */ +export type LottoDefinition = CompositeDefinition & { + type: "lotto"; + weights?: number[]; +}; +/** + * A parallel node. + */ +export type ParallelDefinition = CompositeDefinition & { + type: "parallel"; +}; +/** + * A root node. + */ +export type RootDefinition = DecoratorDefinition & { + type: "root"; + id?: string; +}; +/** + * A repeat node. + */ +export type RepeatDefinition = DecoratorDefinition & { + type: "repeat"; + iterations?: number | [number, number]; +}; +/** + * A retry node. + */ +export type RetryDefinition = DecoratorDefinition & { + type: "retry"; + attempts?: number | [number, number]; +}; +/** + * A flip node. + */ +export type FlipDefinition = DecoratorDefinition & { + type: "flip"; +}; +/** + * A succeed node. + */ +export type SucceedDefinition = DecoratorDefinition & { + type: "succeed"; +}; +/** + * A fail node. + */ +export type FailDefinition = DecoratorDefinition & { + type: "fail"; +}; +/** + * A type defining any node type. + */ +export type AnyNode = BranchDefinition | ActionDefinition | ConditionDefinition | WaitDefinition | SequenceDefinition | SelectorDefinition | LottoDefinition | ParallelDefinition | RootDefinition | RepeatDefinition | RetryDefinition | FlipDefinition | SucceedDefinition | FailDefinition; +/** + * A type defining any node type that can be a child of composite parent node. + */ +export type AnyChildNode = Exclude; +/** + * A type defining an object that holds a reference to substitued string literals parsed from the definition. + */ +type StringLiteralPlaceholders = { + [key: string]: string; +}; +/** + * Parse the tree definition string into a JSON definition. + * @param definition The tree definition string. + * @returns The root node JSON definitions. + */ +export declare function parseToJSON(definition: string): RootDefinition[]; +/** + * Converts the specified tree definition tokens into a JSON definition. + * @param tokens The tree definition tokens. + * @param placeholders The substituted string literal placeholders. + * @returns The root node JSON definitions. + */ +export declare function convertTokensToJSONDefinition(tokens: string[], placeholders: StringLiteralPlaceholders, processedDefinition: string): RootDefinition[]; +export {}; diff --git a/dist/dsl/DSLNodeArgumentParser.d.ts b/dist/dsl/DSLNodeArgumentParser.d.ts new file mode 100644 index 0000000..d9a29b1 --- /dev/null +++ b/dist/dsl/DSLNodeArgumentParser.d.ts @@ -0,0 +1,36 @@ +type Placeholders = { + [key: string]: string; +}; +export type Argument = { + /** The argument value. */ + value: T; + /** The argument type, used for validation. */ + type: string; +}; +type NullArgument = Argument & { + type: "null"; +}; +type BooleanArgument = Argument & { + type: "boolean"; +}; +type NumberArgument = Argument & { + type: "number"; + isInteger: boolean; +}; +type StringPlaceholderArgument = Argument & { + type: "string"; +}; +type IdentifierArgument = Argument & { + type: "identifier"; +}; +export type AnyArgument = NullArgument | BooleanArgument | NumberArgument | StringPlaceholderArgument | IdentifierArgument; +/** + * Parse an array of argument definitions from the specified tokens array. + * @param tokens The array tokens to parse the argument definitions from. + * @param stringArgumentPlaceholders The mapping of string literal node argument placeholders to original values. + * @param argumentValidator The argument validator function. + * @param validationFailedMessage The exception message to throw if argument validation fails. + * @returns An array of argument definitions parsed from the specified tokens array. + */ +export declare function getArguments(tokens: string[], stringArgumentPlaceholders: Placeholders, argumentValidator?: (arg: AnyArgument) => boolean, validationFailedMessage?: string): AnyArgument[]; +export {}; diff --git a/dist/dsl/DSLUtilities.d.ts b/dist/dsl/DSLUtilities.d.ts new file mode 100644 index 0000000..cdd7220 --- /dev/null +++ b/dist/dsl/DSLUtilities.d.ts @@ -0,0 +1,7 @@ +/** + * Pop the next raw token from the specified array of tokens and throw an error if it wasn't the expected one. + * @param tokens The array of tokens. + * @param expected An optional string or array or items, one of which must match the next popped token. + * @returns The popped token. + */ +export declare function popAndCheck(tokens: string[], expected?: string | string[]): string; diff --git a/dist/index.js b/dist/index.js index 1551327..6ab24cd 100644 --- a/dist/index.js +++ b/dist/index.js @@ -1673,7 +1673,24 @@ function parseTokensFromDefinition(definition) { return definition.replace(/\s+/g, " ").trim().split(" "); } -// src/DSLParser.ts +// src/dsl/DSLUtilities.ts +function popAndCheck2(tokens, expected) { + const popped = tokens.shift(); + if (popped === void 0) { + throw new Error("unexpected end of definition"); + } + if (expected != void 0) { + const expectedValues = typeof expected === "string" ? [expected] : expected; + var tokenMatchesExpectation = expectedValues.some((item) => popped.toUpperCase() === item.toUpperCase()); + if (!tokenMatchesExpectation) { + const expectationString = expectedValues.map((item) => "'" + item + "'").join(" or "); + throw new Error("unexpected token found. Expected " + expectationString + " but got '" + popped + "'"); + } + } + return popped; +} + +// src/dsl/DSLDefinitionParser.ts function isLeafNode(node) { return ["branch", "action", "condition", "wait"].includes(node.type); } @@ -1708,6 +1725,9 @@ function convertTokensToJSONDefinition(tokens, placeholders, processedDefinition bottomNode.children = bottomNode.children || []; bottomNode.children.push(node); } else if (isDecoratorNode(bottomNode)) { + if (bottomNode.child) { + throw new Error("a decorator node must only have a single child node"); + } bottomNode.child = node; } if (!isLeafNode(node)) { @@ -1727,26 +1747,15 @@ function convertTokensToJSONDefinition(tokens, placeholders, processedDefinition const token = tokens.shift(); switch (token.toUpperCase()) { case "ROOT": { - const node = { - type: "root" - }; - popAndCheck2(tokens, "{"); - pushRootNode(node); + pushRootNode(createRootNode(tokens)); break; } case "SEQUENCE": { - const node = { - type: "sequence" - }; - popAndCheck2(tokens, "{"); - pushNode(node); + pushNode(createSequenceNode(tokens)); break; } case "ACTION": { - const node = { - type: "action" - }; - pushNode(node); + pushNode(createActionNode(tokens)); break; } case "}": { @@ -1758,9 +1767,22 @@ function convertTokensToJSONDefinition(tokens, placeholders, processedDefinition } } } - console.log(rootNodes); return rootNodes; } +function createRootNode(tokens) { + const node = { type: "root" }; + popAndCheck2(tokens, "{"); + return node; +} +function createSequenceNode(tokens) { + const node = { type: "sequence" }; + popAndCheck2(tokens, "{"); + return node; +} +function createActionNode(tokens) { + const node = { type: "action" }; + return node; +} function substituteStringLiterals2(definition) { const placeholders = {}; const processedDefinition = definition.replace(/\"(\\.|[^"\\])*\"/g, (match) => { @@ -1784,21 +1806,6 @@ function parseTokensFromDefinition2(definition) { definition = definition.replace(/\,/g, " , "); return definition.replace(/\s+/g, " ").trim().split(" "); } -function popAndCheck2(tokens, expected) { - const popped = tokens.shift(); - if (popped === void 0) { - throw new Error("unexpected end of definition"); - } - if (expected != void 0) { - const expectedValues = typeof expected === "string" ? [expected] : expected; - var tokenMatchesExpectation = expectedValues.some((item) => popped.toUpperCase() === item.toUpperCase()); - if (!tokenMatchesExpectation) { - const expectationString = expectedValues.map((item) => "'" + item + "'").join(" or "); - throw new Error("unexpected token found. Expected " + expectationString + " but got '" + popped + "'"); - } - } - return popped; -} // src/BehaviourTree.ts var BehaviourTree = class { @@ -1811,7 +1818,7 @@ var BehaviourTree = class { if (typeof agent !== "object" || agent === null) { throw new Error("the agent must be defined and not null"); } - this.rootNode = BehaviourTree.createRootNode(definition); + this.rootNode = BehaviourTree._createRootNode(definition); } rootNode; isRunning() { @@ -1879,7 +1886,7 @@ var BehaviourTree = class { static unregisterAll() { Lookup.empty(); } - static createRootNode(definition) { + static _createRootNode(definition) { try { parseToJSON(definition); } catch (exception) { @@ -1896,14 +1903,14 @@ var BehaviourTree = class { (name) => rootNodeMap[name] ? rootNodeMap[name] : Lookup.getSubtree(name), [] ); - BehaviourTree.applyLeafNodeGuardPaths(rootNode); + BehaviourTree._applyLeafNodeGuardPaths(rootNode); return rootNode; } catch (exception) { throw new Error(`error parsing tree: ${exception.message} ${exception.stack}`); } } - static applyLeafNodeGuardPaths(rootNode) { + static _applyLeafNodeGuardPaths(rootNode) { const nodePaths = []; const findLeafNodes = (path, node) => { path = path.concat(node); diff --git a/dist/index.js.map b/dist/index.js.map index 0ee43d2..5792464 100644 --- a/dist/index.js.map +++ b/dist/index.js.map @@ -1,7 +1,7 @@ { "version": 3, - "sources": ["../node_modules/lotto-draw/dist/Participant.js", "../node_modules/lotto-draw/dist/Utilities.js", "../node_modules/lotto-draw/dist/Lotto.js", "../node_modules/lotto-draw/dist/createLotto.js", "../node_modules/lotto-draw/dist/index.js", "../src/index.ts", "../src/attributes/guards/GuardUnsatisifedException.ts", "../src/attributes/guards/GuardPath.ts", "../src/State.ts", "../src/nodes/Node.ts", "../src/nodes/leaf/Leaf.ts", "../src/Lookup.ts", "../src/nodes/leaf/Action.ts", "../src/nodes/leaf/Condition.ts", "../src/nodes/leaf/Wait.ts", "../src/nodes/decorator/Decorator.ts", "../src/nodes/decorator/Root.ts", "../src/nodes/decorator/Repeat.ts", "../src/nodes/decorator/Retry.ts", "../src/nodes/decorator/Flip.ts", "../src/nodes/decorator/Succeed.ts", "../src/nodes/decorator/Fail.ts", "../src/nodes/composite/Lotto.ts", "../src/nodes/composite/Composite.ts", "../src/nodes/composite/Selector.ts", "../src/nodes/composite/Sequence.ts", "../src/nodes/composite/Parallel.ts", "../src/attributes/Attribute.ts", "../src/attributes/guards/Guard.ts", "../src/attributes/guards/While.ts", "../src/attributes/guards/Until.ts", "../src/attributes/callbacks/Callback.ts", "../src/attributes/callbacks/Entry.ts", "../src/attributes/callbacks/Exit.ts", "../src/attributes/callbacks/Step.ts", "../src/RootAstNodesBuilder.ts", "../src/DSLParser.ts", "../src/BehaviourTree.ts"], - "sourcesContent": ["\"use strict\";\r\nObject.defineProperty(exports, \"__esModule\", { value: true });\r\nexports.Participant = void 0;\r\n/**\r\n * A participant that holds a number of tickets.\r\n */\r\nvar Participant = /** @class */ (function () {\r\n /**\r\n * Creates an instance of the Participant class.\r\n * @param participant The actual participant.\r\n * @param tickets The number of tickets held by the participant.\r\n */\r\n function Participant(participant, tickets) {\r\n if (tickets === void 0) { tickets = 1; }\r\n this._participant = participant;\r\n this._tickets = tickets;\r\n }\r\n Object.defineProperty(Participant.prototype, \"participant\", {\r\n /** Gets the actual participant. */\r\n get: function () {\r\n return this._participant;\r\n },\r\n enumerable: false,\r\n configurable: true\r\n });\r\n Object.defineProperty(Participant.prototype, \"tickets\", {\r\n /** Gets or sets the number of tickets held by the participant. */\r\n get: function () {\r\n return this._tickets;\r\n },\r\n set: function (value) {\r\n this._tickets = value;\r\n },\r\n enumerable: false,\r\n configurable: true\r\n });\r\n return Participant;\r\n}());\r\nexports.Participant = Participant;\r\n", "\"use strict\";\r\nObject.defineProperty(exports, \"__esModule\", { value: true });\r\nexports.isNaturalNumber = exports.isNullOrUndefined = void 0;\r\n/**\r\n * Gets whether the value provided is null or undefined.\r\n * @param value The value to check.\r\n * @returns Whether the value provided is null or undefined.\r\n */\r\nfunction isNullOrUndefined(value) {\r\n return value === null || value === undefined;\r\n}\r\nexports.isNullOrUndefined = isNullOrUndefined;\r\n/**\r\n * Gets whether the value provided is a natural number.\r\n * @param value The value to check.\r\n * @returns Whether the value provided is a natural number.\r\n */\r\nfunction isNaturalNumber(value) {\r\n return typeof value === \"number\" && value >= 1 && Math.floor(value) === value;\r\n}\r\nexports.isNaturalNumber = isNaturalNumber;\r\n", "\"use strict\";\r\nObject.defineProperty(exports, \"__esModule\", { value: true });\r\nexports.Lotto = void 0;\r\nvar Participant_1 = require(\"./Participant\");\r\nvar Utilities_1 = require(\"./Utilities\");\r\n/**\r\n * Represents a lotto consisting of a number of pickable ticket-holding participants.\r\n */\r\nvar Lotto = /** @class */ (function () {\r\n /**\r\n * Creates a new instance of Lotto.\r\n * @param customRandom The custom RNG to use in place of Math.random().\r\n */\r\n function Lotto(customRandom) {\r\n /** The array of participants that are holding tickets in the lotto. */\r\n this._participants = [];\r\n this._customRandom = customRandom;\r\n }\r\n /**\r\n * Adds a participant with the specified number of tickets, or adds to the participant ticket count if the participant already holds tickets.\r\n * @param participant The participant to add or to increase the ticket count for if they already hold tickets.\r\n * @param tickets The number of tickets, defaults to 1.\r\n * @returns The Lotto instance.\r\n */\r\n Lotto.prototype.add = function (participant, tickets) {\r\n if (tickets === void 0) { tickets = 1; }\r\n // Check that we have a valid ticket count.\r\n if (!(0, Utilities_1.isNaturalNumber)(tickets)) {\r\n throw new Error(\"tickets value must be a natural number\");\r\n }\r\n // Check whether this participant has already been added.\r\n var existingParticipant = this._participants.find(function (part) { return part.participant === participant; });\r\n if (existingParticipant) {\r\n // The participant has already been added to the lotto so just add to their ticket count.\r\n existingParticipant.tickets += tickets;\r\n }\r\n else {\r\n // The participant is not part of the lotto so we should add them.\r\n this._participants.push(new Participant_1.Participant(participant, tickets));\r\n }\r\n return this;\r\n };\r\n /**\r\n * Removes the specified number of tickets for the given participant from the draw, or all tickets if a ticket number is not defined.\r\n * @param participant The participant to remove tickets for.\r\n * @param tickets The number of tickets to remove, or undefined if all tickets are to be removed.\r\n * @returns The Lotto instance.\r\n */\r\n Lotto.prototype.remove = function (participant, tickets) {\r\n // Attempt to get the existing participant.\r\n var existingParticipant = this._participants.find(function (part) { return part.participant === participant; });\r\n // There is nothing to do if the specified participant isn't even part of the lotto.\r\n if (!existingParticipant) {\r\n return this;\r\n }\r\n // Check whether a tickets value was given.\r\n if (tickets !== undefined) {\r\n // Check that we have a valid ticket count.\r\n if (!(0, Utilities_1.isNaturalNumber)(tickets)) {\r\n throw new Error(\"tickets value must be a natural number\");\r\n }\r\n existingParticipant.tickets -= tickets;\r\n // If the participant no longer holds any tickets then they should be removed.\r\n if (existingParticipant.tickets < 1) {\r\n this._participants = this._participants.filter(function (part) { return part !== existingParticipant; });\r\n }\r\n }\r\n else {\r\n // We are removing all tickets for the participant so just remove them from the lotto.\r\n this._participants = this._participants.filter(function (part) { return part !== existingParticipant; });\r\n }\r\n return this;\r\n };\r\n /**\r\n * Draw a winning ticket and return the participant that holds the ticket.\r\n * @param options The draw options.\r\n * @returns The participant that holds the winning ticket.\r\n */\r\n Lotto.prototype.draw = function (options) {\r\n if (options === void 0) { options = {}; }\r\n // If we have no participants then just return null.\r\n if (this._participants.length === 0) {\r\n return null;\r\n }\r\n var redrawable = (0, Utilities_1.isNullOrUndefined)(options.redrawable) ? true : options.redrawable;\r\n var pickable = [];\r\n this._participants.forEach(function (_a) {\r\n var participant = _a.participant, tickets = _a.tickets;\r\n for (var ticketCount = 0; ticketCount < tickets; ticketCount++) {\r\n pickable.push(participant);\r\n }\r\n });\r\n var random;\r\n // We need a random floating-point number between 0 (inclusive) and 1 to scale up to pick our winner.\r\n // If a custom random function exists then we should use that or fall back to Math.random().\r\n if (this._customRandom) {\r\n // Call our custom random function to get a random floating-point number.\r\n random = this._customRandom();\r\n // Verify that the result of calling our custom random function is a number between 0 (inclusive) and 1.\r\n if (typeof random !== \"number\" || random < 0 || random >= 1) {\r\n throw new Error(\"the 'random' function provided did not return a number between 0 (inclusive) and 1\");\r\n }\r\n }\r\n else {\r\n // No custom random function was defined so just use good ol' Math.random().\r\n random = Math.random();\r\n }\r\n // Pick a winning participant.\r\n var winner = pickable[Math.floor(random * pickable.length)];\r\n // If the ticket isn't redrawable then we should remove a ticket from the winning participants ticket count.\r\n if (!redrawable) {\r\n this.remove(winner, 1);\r\n }\r\n // Return the winning participant.\r\n return winner;\r\n };\r\n /**\r\n * Draws multiple winning tickets and return an array of the participants that hold the winning tickets.\r\n * @param tickets The number of winning tickets to draw.\r\n * @param options The draw multiple options.\r\n * @returns An array of the participants that hold the winning tickets.\r\n */\r\n Lotto.prototype.drawMultiple = function (tickets, options) {\r\n if (options === void 0) { options = {}; }\r\n var uniqueResults = (0, Utilities_1.isNullOrUndefined)(options.unique) ? false : options.unique;\r\n // Handle cases where the user has asked for zero tickets (no idea why they would do this be we should trust them).\r\n if (tickets === 0) {\r\n return [];\r\n }\r\n // Now that we know out tickets value is not zero we should check that it is a valid natural number.\r\n if (!(0, Utilities_1.isNaturalNumber)(tickets)) {\r\n throw new Error(\"tickets value must be a natural number\");\r\n }\r\n var result = [];\r\n // Keep drawing tickets until we either reach the number of required tickets or we simply run out of tickets to draw.\r\n // We can run out of tickets to draw if 'options.redrawable' is explicity 'false' or we just had no participants when 'drawMultiple' was called.\r\n while (result.length < tickets && this._participants.length > 0) {\r\n result.push(this.draw(options));\r\n }\r\n // If the 'unique' draw option is set then we need to remove duplicates from the result list.\r\n if (uniqueResults) {\r\n // Create an array to store our unique results.\r\n var unique = [];\r\n // Iterate over all of our participants (with potential duplicates) and populate our array of unique values.\r\n for (var _i = 0, result_1 = result; _i < result_1.length; _i++) {\r\n var participant = result_1[_i];\r\n if (unique.indexOf(participant) === -1) {\r\n unique.push(participant);\r\n }\r\n }\r\n result = unique;\r\n }\r\n return result;\r\n };\r\n return Lotto;\r\n}());\r\nexports.Lotto = Lotto;\r\n", "\"use strict\";\r\nObject.defineProperty(exports, \"__esModule\", { value: true });\r\nexports.createLotto = void 0;\r\nvar Lotto_1 = require(\"./Lotto\");\r\n/**\r\n * A function that creates and returns a Lotto instance.\r\n * @param participantsOrOptions An array of initial participants or options relating to the creation of a Lotto instance.\r\n * @returns A new Lotto instance.\r\n */\r\nfunction createLotto(participantsOrOptions) {\r\n // If no initial participants or lotto options were provided as an argument then we can just return a new lotto instance now.\r\n if (!participantsOrOptions) {\r\n return new Lotto_1.Lotto();\r\n }\r\n // Check whether we were provided with an array of initial participants or a lotto options object.\r\n if (Array.isArray(participantsOrOptions)) {\r\n // We are dealing with a pre-defined array of participants.\r\n var participants = participantsOrOptions;\r\n var lotto_1 = new Lotto_1.Lotto();\r\n // If the lotto participants have been defined upfront then we will need to add them all to our lotto instance now.\r\n participants.forEach(function (_a) {\r\n var participant = _a[0], tokens = _a[1];\r\n return lotto_1.add(participant, tokens);\r\n });\r\n // Return the Lotto instance.\r\n return lotto_1;\r\n }\r\n else {\r\n // We are dealing with some lotto options.\r\n var random = participantsOrOptions.random, participants = participantsOrOptions.participants;\r\n // Create a Lotto instance passing the custom RNG function to use in place of Math.random() (which could be undefined).\r\n var lotto_2 = new Lotto_1.Lotto(random);\r\n // If the lotto participants have been defined upfront as part of the options then we will need to add them all to our lotto instance now.\r\n if (participants) {\r\n participants.forEach(function (_a) {\r\n var participant = _a[0], tokens = _a[1];\r\n return lotto_2.add(participant, tokens);\r\n });\r\n }\r\n // Return the Lotto instance.\r\n return lotto_2;\r\n }\r\n}\r\nexports.createLotto = createLotto;\r\n", "\"use strict\";\r\nObject.defineProperty(exports, \"__esModule\", { value: true });\r\nvar createLotto_1 = require(\"./createLotto\");\r\nexports.default = createLotto_1.createLotto;\r\n", "import { BehaviourTree, FlattenedTreeNode } from \"./BehaviourTree\";\nimport State from \"./State\";\n\nexport { BehaviourTree, State };\nexport type { FlattenedTreeNode };\n", "import Node from \"../../nodes/Node\";\n\n/**\n * An exception thrown when evaluating node guard path conditions and a conditions fails.\n */\nexport default class GuardUnsatisifedException extends Error {\n /**\n * @param source The node at which a guard condition failed.\n */\n constructor(private source: Node) {\n super(\"A guard path condition has failed\");\n }\n\n /**\n * Gets whether the specified node is the node at which a guard condition failed.\n * @param node The node to check against the source node.\n * @returns Whether the specified node is the node at which a guard condition failed.\n */\n isSourceNode = (node: Node) => node === this.source;\n}\n", "import { Agent } from \"../../Agent\";\nimport Guard from \"./Guard\";\nimport Node from \"../../nodes/Node\";\nimport GuardUnsatisifedException from \"./GuardUnsatisifedException\";\n\nexport type GuardPathPart = {\n node: Node;\n guards: Guard[];\n};\n\n/**\n * Represents a path of node guards along a root-to-leaf tree path.\n */\nexport default class GuardPath {\n /**\n * @param nodes An array of objects defining a node instance -> guard link, ordered by node depth.\n */\n constructor(private nodes: GuardPathPart[]) {}\n\n /**\n * Evaluate guard conditions for all guards in the tree path, moving outwards from the root.\n * @param agent The agent, required for guard evaluation.\n * @returns An evaluation results object.\n */\n evaluate = (agent: Agent) => {\n // We need to evaluate guard conditions for nodes up the tree, moving outwards from the root.\n for (const details of this.nodes) {\n // There can be multiple guards per node.\n for (const guard of details.guards) {\n // Check whether the guard condition passes, and throw an exception if not.\n if (!guard.isSatisfied(agent)) {\n throw new GuardUnsatisifedException(details.node);\n }\n }\n }\n };\n}\n", "/**\n * Enumeration of node state types.\n */\nexport enum State {\n READY = \"mistreevous.ready\",\n RUNNING = \"mistreevous.running\",\n SUCCEEDED = \"mistreevous.succeeded\",\n FAILED = \"mistreevous.failed\"\n}\n\nexport { State as default };\n\nexport type CompleteState = State.SUCCEEDED | State.FAILED;\nexport type AnyState = State.READY | State.RUNNING | CompleteState;\n", "import { Agent } from \"../Agent\";\nimport Attribute from \"../attributes/Attribute\";\nimport Entry from \"../attributes/callbacks/Entry\";\nimport Exit from \"../attributes/callbacks/Exit\";\nimport Step from \"../attributes/callbacks/Step\";\nimport Guard from \"../attributes/guards/Guard\";\nimport GuardPath from \"../attributes/guards/GuardPath\";\nimport GuardUnsatisifedException from \"../attributes/guards/GuardUnsatisifedException\";\nimport { BehaviourTreeOptions } from \"../BehaviourTreeOptions\";\nimport { AnyArgument } from \"../RootAstNodesBuilder\";\nimport State, { AnyState } from \"../State\";\nimport Leaf from \"./leaf/Leaf\";\n\n/**\n * A base node.\n */\nexport default abstract class Node {\n /**\n * The node uid.\n */\n private readonly uid: string = createNodeUid();\n /**\n * The node state.\n */\n private state: AnyState = State.READY;\n /**\n * The guard path to evaluate as part of a node update.\n */\n private guardPath: GuardPath | undefined;\n\n /**\n * @param type The node type.\n * @param attributes The node attributes.\n * @param args The node argument definitions.\n */\n constructor(private type: string, private attributes: Attribute[], private args: AnyArgument[]) {}\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected abstract onUpdate(agent: Agent, options: BehaviourTreeOptions): void;\n\n /**\n * Gets the name of the node.\n */\n public abstract getName(): string;\n\n /**\n * Gets whether this node is a leaf node.\n */\n public abstract isLeafNode: () => this is Leaf;\n\n /**\n * Gets/Sets the state of the node.\n */\n getState = (): AnyState => this.state;\n setState = (value: AnyState): void => {\n this.state = value;\n };\n\n /**\n * Gets the unique id of the node.\n */\n getUid = () => this.uid;\n\n /**\n * Gets the type of the node.\n */\n getType = () => this.type;\n\n /**\n * Gets the node attributes.\n */\n getAttributes = () => this.attributes;\n\n /**\n * Gets the node arguments.\n */\n getArguments = () => this.args;\n\n /**\n * Gets the node attribute with the specified type, or null if it does not exist.\n */\n getAttribute(type: \"entry\" | \"ENTRY\"): Entry;\n getAttribute(type: \"exit\" | \"EXIT\"): Exit;\n getAttribute(type: \"step\" | \"STEP\"): Step;\n getAttribute(type: string): Attribute {\n return (\n this.getAttributes().filter((decorator) => decorator.getType().toUpperCase() === type.toUpperCase())[0] ||\n null\n );\n }\n\n /**\n * Gets the node attributes.\n */\n getGuardAttributes = (): Guard[] => this.getAttributes().filter((decorator) => decorator.isGuard()) as Guard[];\n\n /**\n * Sets the guard path to evaluate as part of a node update.\n */\n setGuardPath = (value: GuardPath) => (this.guardPath = value);\n\n /**\n * Gets whether a guard path is assigned to this node.\n */\n hasGuardPath = () => !!this.guardPath;\n\n /**\n * Gets whether this node is in the specified state.\n * @param value The value to compare to the node state.\n */\n public is(value: AnyState): boolean {\n return this.state === value;\n }\n\n /**\n * Reset the state of the node.\n */\n public reset(): void {\n this.setState(State.READY);\n }\n\n /**\n * Abort the running of this node.\n * @param agent The agent.\n */\n public abort(agent: Agent): void {\n // There is nothing to do if this node is not in the running state.\n if (!this.is(State.RUNNING)) {\n return;\n }\n\n // Reset the state of this node.\n this.reset();\n\n this.getAttribute(\"exit\")?.callAgentFunction(agent, false, true);\n }\n\n /**\n * Update the node.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n * @returns The result of the update.\n */\n public update(agent: Agent, options: BehaviourTreeOptions): void {\n // If this node is already in a 'SUCCEEDED' or 'FAILED' state then there is nothing to do.\n if (this.is(State.SUCCEEDED) || this.is(State.FAILED)) {\n return;\n }\n\n try {\n // Evaluate all of the guard path conditions for the current tree path.\n this.guardPath!.evaluate(agent);\n\n // If this node is in the READY state then call the ENTRY for this node if it exists.\n if (this.is(State.READY)) {\n this.getAttribute(\"entry\")?.callAgentFunction(agent);\n }\n\n this.getAttribute(\"step\")?.callAgentFunction(agent);\n\n // Do the actual update.\n this.onUpdate(agent, options);\n\n // If this node is now in a 'SUCCEEDED' or 'FAILED' state then call the EXIT for this node if it exists.\n if (this.is(State.SUCCEEDED) || this.is(State.FAILED)) {\n this.getAttribute(\"exit\")?.callAgentFunction(agent, this.is(State.SUCCEEDED), false);\n }\n } catch (error) {\n // If the error is a GuardUnsatisfiedException then we need to determine if this node is the source.\n if (error instanceof GuardUnsatisifedException && error.isSourceNode(this)) {\n // Abort the current node.\n this.abort(agent);\n\n // Any node that is the source of an abort will be a failed node.\n this.setState(State.FAILED);\n } else {\n throw error;\n }\n }\n }\n}\n\n/**\n * Create a randomly generated node uid.\n * @returns A randomly generated node uid.\n */\nfunction createNodeUid(): string {\n var S4 = function () {\n return (((1 + Math.random()) * 0x10000) | 0).toString(16).substring(1);\n };\n return S4() + S4() + \"-\" + S4() + \"-\" + S4() + \"-\" + S4() + \"-\" + S4() + S4() + S4();\n}\n", "import Node from \"../Node\";\n\n/**\n * A leaf node.\n */\nexport default abstract class Leaf extends Node {\n /**\n * Gets whether this node is a leaf node.\n */\n isLeafNode = () => true;\n}\n", "import { ActionResult, Agent, ExitFunctionArg, FunctionArg, GlobalFunction } from \"./Agent\";\nimport { AnyArgument, RootAstNode } from \"./RootAstNodesBuilder\";\n\n// Exit callbacks receive their own special type of argument.\n// There's probably stricter ways to represent this but it feels overly complex right now.\ntype ExitResultArg = { value: ExitFunctionArg };\nexport type AnyExitArgument = AnyArgument | ExitResultArg;\n\nexport type InvokerFunction = (args: AnyExitArgument[]) => ActionResult;\n\n/**\n * A singleton used to store and lookup registered functions and subtrees.\n */\nexport default class Lookup {\n /**\n * The object holding any registered functions keyed on function name.\n */\n private static functionTable: { [key: string]: GlobalFunction } = {};\n /**\n * The object holding any registered sub-trees keyed on tree name.\n */\n private static subtreeTable: { [key: string]: RootAstNode } = {};\n\n /**\n * Gets the function with the specified name.\n * @param name The name of the function.\n * @returns The function with the specified name.\n */\n public static getFunc(name: string): GlobalFunction {\n return this.functionTable[name];\n }\n\n /**\n * Sets the function with the specified name for later lookup.\n * @param name The name of the function.\n * @param func The function.\n */\n public static setFunc(name: string, func: GlobalFunction): void {\n this.functionTable[name] = func;\n }\n\n /**\n * Gets the function invoker for the specified agent and function name.\n * If a function with the specified name exists on the agent object then it will\n * be returned, otherwise we will then check the registered functions for a match.\n * @param agent The agent instance that this behaviour tree is modelling behaviour for.\n * @param name The function name.\n * @returns The function invoker for the specified agent and function name.\n */\n static getFuncInvoker(agent: Agent, name: string): InvokerFunction | null {\n // Check whether the agent contains the specified function.\n const foundOnAgent = agent[name];\n if (foundOnAgent && typeof foundOnAgent === \"function\") {\n return (args: AnyExitArgument[]): boolean | ActionResult =>\n foundOnAgent.apply(\n agent,\n args.map((arg) => arg.value)\n );\n }\n\n // The agent does not contain the specified function but it may have been registered at some point.\n if (this.functionTable[name] && typeof this.functionTable[name] === \"function\") {\n return (args: AnyExitArgument[]) => this.functionTable[name](agent, ...args.map((arg) => arg.value));\n }\n\n // We have no function to invoke.\n return null;\n }\n\n /**\n * Gets the subtree with the specified name.\n * @param name The name of the subtree.\n * @returns The subtree with the specified name.\n */\n static getSubtree(name: string): RootAstNode {\n return this.subtreeTable[name];\n }\n\n /**\n * Sets the subtree with the specified name for later lookup.\n * @param name The name of the subtree.\n * @param subtree The subtree.\n */\n static setSubtree(name: string, subtree: RootAstNode) {\n this.subtreeTable[name] = subtree;\n }\n\n /**\n * Removes the registered function or subtree with the specified name.\n * @param name The name of the registered function or subtree.\n */\n static remove(name: string) {\n delete this.functionTable[name];\n delete this.subtreeTable[name];\n }\n\n /**\n * Remove all registered functions and subtrees.\n */\n static empty() {\n this.functionTable = {};\n this.subtreeTable = {};\n }\n}\n", "import Leaf from \"./Leaf\";\nimport State, { CompleteState } from \"../../State\";\nimport Lookup from \"../../Lookup\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { AnyArgument } from \"../../RootAstNodesBuilder\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * An Action leaf node.\n * This represents an immediate or ongoing state of behaviour.\n */\nexport default class Action extends Leaf {\n /**\n * @param attributes The node attributes.\n * @param actionName The action name.\n * @param actionArguments The array of action argument definitions.\n */\n constructor(attributes: Attribute[], private actionName: string, private actionArguments: AnyArgument[]) {\n super(\"action\", attributes, actionArguments);\n }\n\n /**\n * Whether there is a pending update promise.\n */\n private isUsingUpdatePromise = false;\n\n /**\n * The finished state result of an update promise.\n */\n private updatePromiseStateResult: CompleteState | null = null;\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // If the result of this action depends on an update promise then there is nothing to do until\n // it resolves, unless there has been a value set as a result of the update promise resolving.\n if (this.isUsingUpdatePromise) {\n // Check whether the update promise has resolved with a state value.\n if (this.updatePromiseStateResult) {\n // Set the state of this node to match the state returned by the promise.\n this.setState(this.updatePromiseStateResult);\n }\n\n return;\n }\n\n // Attempt to get the invoker for the action function.\n const actionFuncInvoker = Lookup.getFuncInvoker(agent, this.actionName);\n\n // The action function should be defined.\n if (actionFuncInvoker === null) {\n throw new Error(\n `cannot update action node as the action '${this.actionName}' function is not defined on the agent and has not been registered`\n );\n }\n\n // Call the action function, the result of which may be:\n // - The finished state of this action node.\n // - A promise to return a finished node state.\n // - Undefined if the node should remain in the running state.\n const updateResult = actionFuncInvoker(this.actionArguments) as CompleteState | Promise;\n\n if (updateResult instanceof Promise) {\n updateResult.then(\n (result) => {\n // If 'isUpdatePromisePending' is null then the promise was cleared as it was resolving, probably via an abort of reset.\n if (!this.isUsingUpdatePromise) {\n return;\n }\n\n // Check to make sure the result is a valid finished state.\n if (result !== State.SUCCEEDED && result !== State.FAILED) {\n throw new Error(\n \"action node promise resolved with an invalid value, expected a State.SUCCEEDED or State.FAILED value to be returned\"\n );\n }\n\n // Set pending update promise state result to be processed on next update.\n this.updatePromiseStateResult = result;\n },\n (reason) => {\n // If 'isUpdatePromisePending' is null then the promise was cleared as it was resolving, probably via an abort of reset.\n if (!this.isUsingUpdatePromise) {\n return;\n }\n\n // Just throw whatever was returned as the rejection argument.\n throw new Error(reason);\n }\n );\n\n // This node will be in the 'RUNNING' state until the update promise resolves.\n this.setState(State.RUNNING);\n\n // We are now waiting for the promise returned by the use to resolve before we know what state this node is in.\n this.isUsingUpdatePromise = true;\n } else {\n // Validate the returned value.\n this.validateUpdateResult(updateResult);\n\n // Set the state of this node, this may be undefined, which just means that the node is still in the 'RUNNING' state.\n this.setState(updateResult || State.RUNNING);\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => this.actionName;\n\n /**\n * Reset the state of the node.\n */\n reset = () => {\n // Reset the state of this node.\n this.setState(State.READY);\n\n // There is no longer an update promise that we care about.\n this.isUsingUpdatePromise = false;\n this.updatePromiseStateResult = null;\n };\n\n /**\n * Validate the result of an update function call.\n * @param result The result of an update function call.\n */\n private validateUpdateResult = (result: CompleteState | boolean) => {\n switch (result) {\n case State.SUCCEEDED:\n case State.FAILED:\n case undefined:\n return;\n default:\n throw new Error(\n `action '${this.actionName}' 'onUpdate' returned an invalid response, expected an optional State.SUCCEEDED or State.FAILED value to be returned`\n );\n }\n };\n}\n", "import Leaf from \"./Leaf\";\nimport State from \"../../State\";\nimport Lookup from \"../../Lookup\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { AnyArgument } from \"../../RootAstNodesBuilder\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A Condition leaf node.\n * This will succeed or fail immediately based on an agent predicate, without moving to the 'RUNNING' state.\n */\nexport default class Condition extends Leaf {\n /**\n * @param attributes The node attributes.\n * @param conditionName The name of the condition function.\n * @param conditionArguments The array of condition argument definitions.\n */\n constructor(attributes: Attribute[], private conditionName: string, private conditionArguments: AnyArgument[]) {\n super(\"condition\", attributes, conditionArguments);\n }\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // Attempt to get the invoker for the condition function.\n const conditionFuncInvoker = Lookup.getFuncInvoker(agent, this.conditionName);\n\n // The condition function should be defined.\n if (conditionFuncInvoker === null) {\n throw new Error(\n `cannot update condition node as the condition '${this.conditionName}' function is not defined on the agent and has not been registered`\n );\n }\n\n // Call the condition function to determine the state of this node.\n this.setState(!!conditionFuncInvoker(this.conditionArguments) ? State.SUCCEEDED : State.FAILED);\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => this.conditionName;\n}\n", "import Leaf from \"./Leaf\";\nimport State from \"../../State\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { Agent } from \"../../Agent\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A WAIT node.\n * The state of this node will change to SUCCEEDED after a duration of time\n */\nexport default class Wait extends Leaf {\n /**\n * @param attributes The node attributes.\n * @param duration The duration that this node will wait to succeed in milliseconds, or the earliest if longestDuration is defined.\n * @param longestDuration The longest possible duration in milliseconds that this node will wait to succeed.\n */\n constructor(attributes: Attribute[], private duration: number, private longestDuration: number) {\n super(\"wait\", attributes, []);\n }\n\n /**\n * The time in milliseconds at which this node was first updated.\n */\n private initialUpdateTime: number = 0;\n\n /**\n * The total duration in milliseconds that this node will be waiting for.\n */\n private totalDuration: number = 0;\n\n /**\n * The duration in milliseconds that this node has been waiting for.\n */\n private waitedDuration: number = 0;\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // If this node is in the READY state then we need to set the initial update time.\n if (this.is(State.READY)) {\n // Set the initial update time.\n this.initialUpdateTime = new Date().getTime();\n\n // Set the initial waited duration.\n this.waitedDuration = 0;\n\n // If a longestDuration value was defined then we will be randomly picking a duration between the\n // shortest and longest duration. If it was not defined, then we will be just using the duration.\n this.totalDuration = this.longestDuration\n ? Math.floor(Math.random() * (this.longestDuration - this.duration + 1) + this.duration)\n : this.duration;\n\n // The node is now running until we finish waiting.\n this.setState(State.RUNNING);\n }\n\n // If we have a 'getDeltaTime' function defined as part of our options then we will use it to figure out how long we have waited for.\n if (typeof options.getDeltaTime === \"function\") {\n // Get the delta time.\n const deltaTime = options.getDeltaTime();\n\n // Our delta time must be a valid number and cannot be NaN.\n if (typeof deltaTime !== \"number\" || isNaN(deltaTime)) {\n throw new Error(\"The delta time must be a valid number and not NaN.\");\n }\n\n // Update the amount of time that this node has been waiting for based on the delta time.\n this.waitedDuration += deltaTime * 1000;\n } else {\n // We are not using a delta time, so we will just work out hom much time has passed since the first update.\n this.waitedDuration = new Date().getTime() - this.initialUpdateTime;\n }\n\n // Have we waited long enough?\n if (this.waitedDuration >= this.totalDuration) {\n // We have finished waiting!\n this.setState(State.SUCCEEDED);\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () =>\n `WAIT ${this.longestDuration ? this.duration + \"ms-\" + this.longestDuration + \"ms\" : this.duration + \"ms\"}`;\n}\n", "import Node from \"../Node\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\n\n/**\n * A decorator node that wraps a single child node.\n */\nexport default abstract class Decorator extends Node {\n /**\n * @param type The node type.\n * @param attributes The node attributes.\n * @param child The child node.\n */\n constructor(type: string, attributes: Attribute[], protected child: Node) {\n super(type, attributes, []);\n }\n\n /**\n * Gets whether this node is a leaf node.\n */\n isLeafNode = () => false;\n\n /**\n * Gets the children of this node.\n */\n getChildren = () => [this.child];\n\n /**\n * Reset the state of the node.\n */\n reset = () => {\n // Reset the state of this node.\n this.setState(State.READY);\n\n // Reset the state of the child node.\n this.child.reset();\n };\n\n /**\n * Abort the running of this node.\n * @param agent The agent.\n */\n abort = (agent: Agent) => {\n // There is nothing to do if this node is not in the running state.\n if (!this.is(State.RUNNING)) {\n return;\n }\n\n // Abort the child node.\n this.child.abort(agent);\n\n // Reset the state of this node.\n this.reset();\n\n this.getAttribute(\"exit\")?.callAgentFunction(agent, false, true);\n };\n}\n", "import Node from \"../Node\";\nimport Decorator from \"./Decorator\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A Root node.\n * The root node will have a single child.\n */\nexport default class Root extends Decorator {\n /**\n * @param attributes The node attributes.\n * @param child The child node.\n */\n constructor(attributes: Attribute[], child: Node) {\n super(\"root\", attributes, child);\n }\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // If the child has never been updated or is running then we will need to update it now.\n if (this.child.getState() === State.READY || this.child.getState() === State.RUNNING) {\n // Update the child of this node.\n this.child.update(agent, options);\n }\n\n // The state of the root node is the state of its child.\n this.setState(this.child.getState());\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => \"ROOT\";\n}\n", "import Node from \"../Node\";\nimport Decorator from \"./Decorator\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A REPEAT node.\n * The node has a single child which can have:\n * -- A number of iterations for which to repeat the child node.\n * -- An infinite repeat loop if neither an iteration count or a condition function is defined.\n * The REPEAT node will stop and have a 'FAILED' state if its child is ever in a 'FAILED' state after an update.\n * The REPEAT node will attempt to move on to the next iteration if its child is ever in a 'SUCCEEDED' state.\n */\nexport default class Repeat extends Decorator {\n /**\n * @param attributes The node attributes.\n * @param iterations The number of iterations to repeat the child node, or the minimum number of iterations if maximumIterations is defined.\n * @param maximumIterations The maximum number of iterations to repeat the child node.\n * @param child The child node.\n */\n constructor(\n attributes: Attribute[],\n private iterations: number | null,\n private maximumIterations: number | null,\n child: Node\n ) {\n super(\"repeat\", attributes, child);\n }\n\n /**\n * The number of target iterations to make.\n */\n private targetIterationCount: number | null = null;\n\n /**\n * The current iteration count.\n */\n private currentIterationCount: number = 0;\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // If this node is in the READY state then we need to reset the child and the target iteration count.\n if (this.is(State.READY)) {\n // Reset the child node.\n this.child.reset();\n\n // Set the target iteration count.\n this.setTargetIterationCount();\n }\n\n // Do a check to see if we can iterate. If we can then this node will move into the 'RUNNING' state.\n // If we cannot iterate then we have hit our target iteration count, which means that the node has succeeded.\n if (this.canIterate()) {\n // This node is in the running state and can do its initial iteration.\n this.setState(State.RUNNING);\n\n // We may have already completed an iteration, meaning that the child node will be in the SUCCEEDED state.\n // If this is the case then we will have to reset the child node now.\n if (this.child.getState() === State.SUCCEEDED) {\n this.child.reset();\n }\n\n // Update the child of this node.\n this.child.update(agent, options);\n\n // If the child moved into the FAILED state when we updated it then there is nothing left to do and this node has also failed.\n // If it has moved into the SUCCEEDED state then we have completed the current iteration.\n if (this.child.getState() === State.FAILED) {\n // The child has failed, meaning that this node has failed.\n this.setState(State.FAILED);\n\n return;\n } else if (this.child.getState() === State.SUCCEEDED) {\n // We have completed an iteration.\n this.currentIterationCount += 1;\n }\n } else {\n // This node is in the 'SUCCEEDED' state as we cannot iterate any more.\n this.setState(State.SUCCEEDED);\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => {\n if (this.iterations !== null) {\n return `REPEAT ${\n this.maximumIterations ? this.iterations + \"x-\" + this.maximumIterations + \"x\" : this.iterations + \"x\"\n }`;\n }\n\n // Return the default repeat node name.\n return \"REPEAT\";\n };\n\n /**\n * Reset the state of the node.\n */\n reset = () => {\n // Reset the state of this node.\n this.setState(State.READY);\n\n // Reset the current iteration count.\n this.currentIterationCount = 0;\n\n // Reset the child node.\n this.child.reset();\n };\n\n /**\n * Gets whether an iteration can be made.\n * @returns Whether an iteration can be made.\n */\n private canIterate = () => {\n if (this.targetIterationCount !== null) {\n // We can iterate as long as we have not reached our target iteration count.\n return this.currentIterationCount < this.targetIterationCount;\n }\n\n // If neither an iteration count or a condition function were defined then we can iterate indefinitely.\n return true;\n };\n\n /**\n * Sets the target iteration count.\n */\n private setTargetIterationCount = () => {\n // Are we dealing with a finite number of iterations?\n if (typeof this.iterations === \"number\") {\n // If we have maximumIterations defined then we will want a random iteration count bounded by iterations and maximumIterations.\n this.targetIterationCount =\n typeof this.maximumIterations === \"number\"\n ? Math.floor(Math.random() * (this.maximumIterations - this.iterations + 1) + this.iterations)\n : this.iterations;\n } else {\n this.targetIterationCount = null;\n }\n };\n}\n", "import Node from \"../Node\";\nimport Decorator from \"./Decorator\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A RETRY node.\n * The node has a single child which can have:\n * -- A number of iterations for which to repeat the child node.\n * -- An infinite repeat loop if neither an iteration count or a condition function is defined.\n * The RETRY node will stop and have a 'SUCCEEDED' state if its child is ever in a 'SUCCEEDED' state after an update.\n * The RETRY node will attempt to move on to the next iteration if its child is ever in a 'FAILED' state.\n */\nexport default class Retry extends Decorator {\n /**\n * @param attributes The node attributes.\n * @param iterations The number of iterations to repeat the child node, or the minimum number of iterations if maximumIterations is defined.\n * @param maximumIterations The maximum number of iterations to repeat the child node.\n * @param child The child node.\n */\n constructor(\n attributes: Attribute[],\n private iterations: number | null,\n private maximumIterations: number | null,\n child: Node\n ) {\n super(\"retry\", attributes, child);\n }\n\n /**\n * The number of target iterations to make.\n */\n private targetIterationCount: number | null = null;\n\n /**\n * The current iteration count.\n */\n private currentIterationCount: number = 0;\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // If this node is in the READY state then we need to reset the child and the target iteration count.\n if (this.is(State.READY)) {\n // Reset the child node.\n this.child.reset();\n\n // Set the target iteration count.\n this.setTargetIterationCount();\n }\n\n // Do a check to see if we can iterate. If we can then this node will move into the 'RUNNING' state.\n // If we cannot iterate then we have hit our target iteration count, which means that the node has succeeded.\n if (this.canIterate()) {\n // This node is in the running state and can do its initial iteration.\n this.setState(State.RUNNING);\n\n // We may have already completed an iteration, meaning that the child node will be in the FAILED state.\n // If this is the case then we will have to reset the child node now.\n if (this.child.getState() === State.FAILED) {\n this.child.reset();\n }\n\n // Update the child of this node.\n this.child.update(agent, options);\n\n // If the child moved into the SUCCEEDED state when we updated it then there is nothing left to do and this node has also succeeded.\n // If it has moved into the FAILED state then we have completed the current iteration.\n if (this.child.getState() === State.SUCCEEDED) {\n // The child has succeeded, meaning that this node has succeeded.\n this.setState(State.SUCCEEDED);\n\n return;\n } else if (this.child.getState() === State.FAILED) {\n // We have completed an iteration.\n this.currentIterationCount += 1;\n }\n } else {\n // This node is in the 'FAILED' state as we cannot iterate any more.\n this.setState(State.FAILED);\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => {\n if (this.iterations !== null) {\n return `RETRY ${\n this.maximumIterations ? this.iterations + \"x-\" + this.maximumIterations + \"x\" : this.iterations + \"x\"\n }`;\n }\n\n // Return the default retry node name.\n return \"RETRY\";\n };\n\n /**\n * Reset the state of the node.\n */\n reset = () => {\n // Reset the state of this node.\n this.setState(State.READY);\n\n // Reset the current iteration count.\n this.currentIterationCount = 0;\n\n // Reset the child node.\n this.child.reset();\n };\n\n /**\n * Gets whether an iteration can be made.\n * @returns Whether an iteration can be made.\n */\n canIterate = () => {\n if (this.targetIterationCount !== null) {\n // We can iterate as long as we have not reached our target iteration count.\n return this.currentIterationCount < this.targetIterationCount;\n }\n\n // If neither an iteration count or a condition function were defined then we can iterate indefinitely.\n return true;\n };\n\n /**\n * Sets the target iteration count.\n */\n setTargetIterationCount = () => {\n // Are we dealing with a finite number of iterations?\n if (typeof this.iterations === \"number\") {\n // If we have maximumIterations defined then we will want a random iteration count bounded by iterations and maximumIterations.\n this.targetIterationCount =\n typeof this.maximumIterations === \"number\"\n ? Math.floor(Math.random() * (this.maximumIterations - this.iterations + 1) + this.iterations)\n : this.iterations;\n } else {\n this.targetIterationCount = null;\n }\n };\n}\n", "import Decorator from \"./Decorator\";\nimport State from \"../../State\";\nimport Node from \"../Node\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A Flip node.\n * This node wraps a single child and will flip the state of the child state.\n */\nexport default class Flip extends Decorator {\n /**\n * @param attributes The node attributes.\n * @param child The child node.\n */\n constructor(attributes: Attribute[], child: Node) {\n super(\"flip\", attributes, child);\n }\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // If the child has never been updated or is running then we will need to update it now.\n if (this.child.getState() === State.READY || this.child.getState() === State.RUNNING) {\n this.child.update(agent, options);\n }\n\n // The state of this node will depend in the state of its child.\n switch (this.child.getState()) {\n case State.RUNNING:\n this.setState(State.RUNNING);\n break;\n\n case State.SUCCEEDED:\n this.setState(State.FAILED);\n break;\n\n case State.FAILED:\n this.setState(State.SUCCEEDED);\n break;\n\n default:\n this.setState(State.READY);\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => \"FLIP\";\n}\n", "import Node from \"../Node\";\nimport Decorator from \"./Decorator\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A Succeed node.\n * This node wraps a single child and will always move to the 'SUCCEEDED' state when the child moves to a 'SUCCEEDED' or 'FAILED' state.\n */\nexport default class Succeed extends Decorator {\n /**\n * @param attributes The node attributes.\n * @param child The child node.\n */\n constructor(attributes: Attribute[], child: Node) {\n super(\"succeed\", attributes, child);\n }\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // If the child has never been updated or is running then we will need to update it now.\n if (this.child.getState() === State.READY || this.child.getState() === State.RUNNING) {\n this.child.update(agent, options);\n }\n\n // The state of this node will depend in the state of its child.\n switch (this.child.getState()) {\n case State.RUNNING:\n this.setState(State.RUNNING);\n break;\n\n case State.SUCCEEDED:\n case State.FAILED:\n this.setState(State.SUCCEEDED);\n break;\n\n default:\n this.setState(State.READY);\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => \"SUCCEED\";\n}\n", "import Node from \"../Node\";\nimport Decorator from \"./Decorator\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A Fail node.\n * This node wraps a single child and will always move to the 'FAILED' state when the child moves to a 'SUCCEEDED' or 'FAILED' state.\n */\nexport default class Fail extends Decorator {\n /**\n * @param attributes The node attributes.\n * @param child The child node.\n */\n constructor(attributes: Attribute[], child: Node) {\n super(\"fail\", attributes, child);\n }\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // If the child has never been updated or is running then we will need to update it now.\n if (this.child.getState() === State.READY || this.child.getState() === State.RUNNING) {\n this.child.update(agent, options);\n }\n\n // The state of this node will depend in the state of its child.\n switch (this.child.getState()) {\n case State.RUNNING:\n this.setState(State.RUNNING);\n break;\n\n case State.SUCCEEDED:\n case State.FAILED:\n this.setState(State.FAILED);\n break;\n\n default:\n this.setState(State.READY);\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => \"FAIL\";\n}\n", "import createLotto from \"lotto-draw\";\r\n\r\nimport Node from \"../Node\";\r\nimport Composite from \"./Composite\";\r\nimport State from \"../../State\";\r\nimport { Agent } from \"../../Agent\";\r\nimport Attribute from \"../../attributes/Attribute\";\r\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\r\n\r\n/**\r\n * A LOTTO node.\r\n * A winning child is picked on the initial update of this node, based on ticket weighting.\r\n * The state of this node will match the state of the winning child.\r\n */\r\nexport default class Lotto extends Composite {\r\n /**\r\n * @param attributes The node attributes.\r\n * @param tickets The child node tickets.\r\n * @param children The child nodes.\r\n */\r\n constructor(attributes: Attribute[], private tickets: number[], children: Node[]) {\r\n super(\"lotto\", attributes, children);\r\n }\r\n\r\n /**\r\n * The child node selected to be the active one.\r\n */\r\n private selectedChild: Node | undefined;\r\n\r\n /**\r\n * Called when the node is being updated.\r\n * @param agent The agent.\r\n * @param options The behaviour tree options object.\r\n */\r\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\r\n // If this node is in the READY state then we need to pick a winning child node.\r\n if (this.is(State.READY)) {\r\n // Create a lotto draw with which to randomly pick a child node to become the active one.\r\n const lottoDraw = createLotto({\r\n // Hook up the optional 'random' behaviour tree function option to the one used by 'lotto-draw'.\r\n random: options.random,\r\n // Pass in each child node as a participant in the lotto draw with their respective ticket count.\r\n participants: this.children.map((child, index) => [child, this.tickets[index] || 1])\r\n });\r\n\r\n // Randomly pick a child based on ticket weighting, this will become the active child for this composite node.\r\n this.selectedChild = lottoDraw.draw() || undefined;\r\n }\r\n\r\n // If something went wrong and we don't have an active child then we should throw an error.\r\n if (!this.selectedChild) {\r\n throw new Error(\"failed to update lotto node as it has no active child\");\r\n }\r\n\r\n // If the selected child has never been updated or is running then we will need to update it now.\r\n if (this.selectedChild.getState() === State.READY || this.selectedChild.getState() === State.RUNNING) {\r\n this.selectedChild.update(agent, options);\r\n }\r\n\r\n // The state of the lotto node is the state of its selected child.\r\n this.setState(this.selectedChild.getState());\r\n }\r\n\r\n /**\r\n * Gets the name of the node.\r\n */\r\n getName = () => (this.tickets.length ? `LOTTO [${this.tickets.join(\",\")}]` : \"LOTTO\");\r\n}\r\n", "import Node from \"../Node\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\n\n/**\n * A composite node that wraps child nodes.\n */\nexport default abstract class Composite extends Node {\n /**\n * @param type The node type.\n * @param attributes The node attributes.\n * @param children The child nodes.\n */\n constructor(type: string, attributes: Attribute[], protected children: Node[]) {\n super(type, attributes, []);\n }\n\n /**\n * Gets whether this node is a leaf node.\n */\n isLeafNode = () => false;\n\n /**\n * Gets the children of this node.\n */\n getChildren = () => this.children;\n\n /**\n * Reset the state of the node.\n */\n reset = () => {\n // Reset the state of this node.\n this.setState(State.READY);\n\n // Reset the state of any child nodes.\n this.getChildren().forEach((child) => child.reset());\n };\n\n /**\n * Abort the running of this node.\n * @param agent The agent.\n */\n abort = (agent: Agent) => {\n // There is nothing to do if this node is not in the running state.\n if (!this.is(State.RUNNING)) {\n return;\n }\n\n // Abort any child nodes.\n this.getChildren().forEach((child) => child.abort(agent));\n\n // Reset the state of this node.\n this.reset();\n\n this.getAttribute(\"exit\")?.callAgentFunction(agent, false, true);\n };\n}\n", "import Composite from \"./Composite\";\nimport Node from \"../Node\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A SELECTOR node.\n * The child nodes are executed in sequence until one succeeds or all fail.\n */\nexport default class Selector extends Composite {\n /**\n * @param attributes The node attributes.\n * @param children The child nodes.\n */\n constructor(attributes: Attribute[], protected children: Node[]) {\n super(\"selector\", attributes, children);\n }\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // Iterate over all of the children of this node.\n for (const child of this.children) {\n // If the child has never been updated or is running then we will need to update it now.\n if (child.getState() === State.READY || child.getState() === State.RUNNING) {\n // Update the child of this node.\n child.update(agent, options);\n }\n\n // If the current child has a state of 'SUCCEEDED' then this node is also a 'SUCCEEDED' node.\n if (child.getState() === State.SUCCEEDED) {\n // This node is a 'SUCCEEDED' node.\n this.setState(State.SUCCEEDED);\n\n // There is no need to check the rest of the selector nodes.\n return;\n }\n\n // If the current child has a state of 'FAILED' then we should move on to the next child.\n if (child.getState() === State.FAILED) {\n // Find out if the current child is the last one in the selector.\n // If it is then this sequence node has also failed.\n if (this.children.indexOf(child) === this.children.length - 1) {\n // This node is a 'FAILED' node.\n this.setState(State.FAILED);\n\n // There is no need to check the rest of the selector as we have completed it.\n return;\n } else {\n // The child node failed, try the next one.\n continue;\n }\n }\n\n // The node should be in the 'RUNNING' state.\n if (child.getState() === State.RUNNING) {\n // This node is a 'RUNNING' node.\n this.setState(State.RUNNING);\n\n // There is no need to check the rest of the selector as the current child is still running.\n return;\n }\n\n // The child node was not in an expected state.\n throw new Error(\"child node was not in an expected state.\");\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => \"SELECTOR\";\n}\n", "import Composite from \"./Composite\";\nimport Node from \"../Node\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A SEQUENCE node.\n * The child nodes are executed in sequence until one fails or all succeed.\n */\nexport default class Sequence extends Composite {\n /**\n * @param attributes The node attributes.\n * @param children The child nodes.\n */\n constructor(attributes: Attribute[], protected children: Node[]) {\n super(\"sequence\", attributes, children);\n }\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // Iterate over all of the children of this node.\n for (const child of this.children) {\n // If the child has never been updated or is running then we will need to update it now.\n if (child.getState() === State.READY || child.getState() === State.RUNNING) {\n // Update the child of this node.\n child.update(agent, options);\n }\n\n // If the current child has a state of 'SUCCEEDED' then we should move on to the next child.\n if (child.getState() === State.SUCCEEDED) {\n // Find out if the current child is the last one in the sequence.\n // If it is then this sequence node has also succeeded.\n if (this.children.indexOf(child) === this.children.length - 1) {\n // This node is a 'SUCCEEDED' node.\n this.setState(State.SUCCEEDED);\n\n // There is no need to check the rest of the sequence as we have completed it.\n return;\n } else {\n // The child node succeeded, but we have not finished the sequence yet.\n continue;\n }\n }\n\n // If the current child has a state of 'FAILED' then this node is also a 'FAILED' node.\n if (child.getState() === State.FAILED) {\n // This node is a 'FAILED' node.\n this.setState(State.FAILED);\n\n // There is no need to check the rest of the sequence.\n return;\n }\n\n // The node should be in the 'RUNNING' state.\n if (child.getState() === State.RUNNING) {\n // This node is a 'RUNNING' node.\n this.setState(State.RUNNING);\n\n // There is no need to check the rest of the sequence as the current child is still running.\n return;\n }\n\n // The child node was not in an expected state.\n throw new Error(\"child node was not in an expected state.\");\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => \"SEQUENCE\";\n}\n", "import Composite from \"./Composite\";\nimport State from \"../../State\";\nimport Node from \"../Node\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A PARALLEL node.\n * The child nodes are executed concurrently until one fails or all succeed.\n */\nexport default class Parallel extends Composite {\n /**\n * @param attributes The node attributes.\n * @param children The child nodes.\n */\n constructor(attributes: Attribute[], children: Node[]) {\n super(\"parallel\", attributes, children);\n }\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // Keep a count of the number of succeeded child nodes.\n let succeededCount = 0;\n\n let hasChildFailed = false;\n\n // Iterate over all of the children of this node.\n for (const child of this.children) {\n // If the child has never been updated or is running then we will need to update it now.\n if (child.getState() === State.READY || child.getState() === State.RUNNING) {\n // Update the child of this node.\n child.update(agent, options);\n }\n\n // If the current child has a state of 'SUCCEEDED' then we should move on to the next child.\n if (child.getState() === State.SUCCEEDED) {\n // The child node has succeeded, keep track of this to determine if all children have.\n succeededCount++;\n\n // The child node succeeded, but we have not finished checking every child node yet.\n continue;\n }\n\n // If the current child has a state of 'FAILED' then this node is also a 'FAILED' node.\n if (child.getState() === State.FAILED) {\n hasChildFailed = true;\n\n // There is no need to check the rest of the children.\n break;\n }\n\n // The node should be in the 'RUNNING' state.\n if (child.getState() !== State.RUNNING) {\n // The child node was not in an expected state.\n throw new Error(\"child node was not in an expected state.\");\n }\n }\n\n if (hasChildFailed) {\n // This node is a 'FAILED' node.\n this.setState(State.FAILED);\n\n // Abort every running child.\n for (const child of this.children) {\n if (child.getState() === State.RUNNING) {\n child.abort(agent);\n }\n }\n } else {\n // If all children have succeeded then this node has also succeeded, otherwise it is still running.\n this.setState(succeededCount === this.children.length ? State.SUCCEEDED : State.RUNNING);\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => \"PARALLEL\";\n}\n", "import { AnyArgument } from \"../RootAstNodesBuilder\";\nimport Guard from \"./guards/Guard\";\n\nexport type AttributeDetails = {\n /** The attribute type. */\n type: string;\n\n /** The attribute arguments. */\n args: AnyArgument[];\n};\n\n/**\n * A base node attribute.\n */\nexport default abstract class Attribute {\n /**\n * @param type The node attribute type.\n * @param args The array of attribute argument definitions.\n */\n constructor(protected type: string, protected args: AnyArgument[]) {}\n\n /**\n * Gets the type of the attribute.\n */\n getType = () => this.type;\n\n /**\n * Gets the array of attribute argument definitions.\n */\n getArguments = () => this.args;\n\n /**\n * Gets the attribute details.\n */\n abstract getDetails(): TAttributeDetails;\n\n /**\n * Gets whether this attribute is a guard.\n */\n abstract isGuard: () => this is Guard;\n}\n", "import { Agent } from \"../../Agent\";\nimport { AnyArgument } from \"../../RootAstNodesBuilder\";\nimport Attribute, { AttributeDetails } from \"../Attribute\";\n\nexport type GuardAttributeDetails = {\n /** The name of the condition function that determines whether the guard is satisfied. */\n condition: string;\n} & AttributeDetails;\n\n/**\n * A base node guard attribute.\n */\nexport default abstract class Guard extends Attribute {\n /**\n * @param type The node attribute type.\n * @param args The array of decorator argument definitions.\n * @param condition The name of the condition function that determines whether the guard is satisfied.\n */\n constructor(type: string, args: AnyArgument[], private condition: string) {\n super(type, args);\n }\n\n /**\n * Gets the name of the condition function that determines whether the guard is satisfied.\n */\n getCondition = () => this.condition;\n\n /**\n * Gets whether this attribute is a guard.\n */\n isGuard = () => true;\n\n /**\n * Gets the attribute details.\n */\n getDetails(): GuardAttributeDetails {\n return {\n type: this.getType(),\n args: this.getArguments(),\n condition: this.getCondition()\n };\n }\n\n /**\n * Gets whether the guard is satisfied.\n * @param agent The agent.\n * @returns Whether the guard is satisfied.\n */\n abstract isSatisfied(agent: Agent): boolean;\n}\n", "import Guard from \"./Guard\";\nimport Lookup from \"../../Lookup\";\nimport { Agent } from \"../../Agent\";\nimport { AnyArgument } from \"../../RootAstNodesBuilder\";\n\n/**\n * A WHILE guard which is satisfied as long as the given condition remains true.\n */\nexport default class While extends Guard {\n /**\n * @param condition The name of the condition function that determines whether the guard is satisfied.\n * @param args The array of decorator argument definitions.\n */\n constructor(condition: string, args: AnyArgument[]) {\n super(\"while\", args, condition);\n }\n\n /**\n * Gets whether the guard is satisfied.\n * @param agent The agent.\n * @returns Whether the guard is satisfied.\n */\n isSatisfied = (agent: Agent) => {\n // Attempt to get the invoker for the condition function.\n const conditionFuncInvoker = Lookup.getFuncInvoker(agent, this.getCondition());\n\n // The condition function should be defined.\n if (conditionFuncInvoker === null) {\n throw new Error(\n `cannot evaluate node guard as the condition '${this.getCondition()}' function is not defined on the agent and has not been registered`\n );\n }\n\n // Call the condition function to determine whether this guard is satisfied.\n return !!conditionFuncInvoker(this.args);\n };\n}\n", "import Guard from \"./Guard\";\nimport Lookup from \"../../Lookup\";\nimport { Agent } from \"../../Agent\";\nimport { AnyArgument } from \"../../RootAstNodesBuilder\";\n\n/**\n * An UNTIL guard which is satisfied as long as the given condition remains false.\n */\nexport default class Until extends Guard {\n /**\n * @param condition The name of the condition function that determines whether the guard is satisfied.\n * @param args The array of decorator argument definitions.\n */\n constructor(condition: string, args: AnyArgument[]) {\n super(\"until\", args, condition);\n }\n\n /**\n * Gets whether the guard is satisfied.\n * @param agent The agent.\n * @returns Whether the guard is satisfied.\n */\n isSatisfied = (agent: Agent) => {\n // Attempt to get the invoker for the condition function.\n const conditionFuncInvoker = Lookup.getFuncInvoker(agent, this.getCondition());\n\n // The condition function should be defined.\n if (conditionFuncInvoker === null) {\n throw new Error(\n `cannot evaluate node guard as the condition '${this.getCondition()}' function is not defined on the agent and has not been registered`\n );\n }\n\n // Call the condition function to determine whether this guard is satisfied.\n return !!!conditionFuncInvoker(this.args);\n };\n}\n", "import { Agent } from \"../../Agent\";\nimport { AnyArgument } from \"../../RootAstNodesBuilder\";\nimport Attribute, { AttributeDetails } from \"../Attribute\";\n\nexport type CallbackAttributeDetails = {\n /** The name of the agent function that is called. */\n functionName: string;\n} & AttributeDetails;\n\n/**\n * A base node callback attribute.\n */\nexport default abstract class Callback extends Attribute {\n /**\n * @param type The node attribute type.\n * @param args The array of decorator argument definitions.\n * @param functionName The name of the agent function to call.\n */\n constructor(type: string, args: AnyArgument[], private functionName: string) {\n super(type, args);\n }\n\n /**\n * Gets the name of the agent function to call.\n */\n getFunctionName = () => this.functionName;\n\n /**\n * Gets whether this attribute is a guard.\n */\n isGuard = () => false;\n\n /**\n * Gets the attribute details.\n */\n getDetails(): CallbackAttributeDetails {\n return {\n type: this.getType(),\n args: this.getArguments(),\n functionName: this.getFunctionName()\n };\n }\n\n /**\n * Attempt to call the agent function that this callback refers to.\n * @param agent The agent.\n */\n abstract callAgentFunction: (agent: Agent, isSuccess: boolean, isAborted: boolean) => void;\n}\n", "import Callback from \"./Callback\";\nimport Lookup from \"../../Lookup\";\nimport { Agent } from \"../../Agent\";\nimport { AnyArgument } from \"../../RootAstNodesBuilder\";\n\n/**\n * An ENTRY callback which defines an agent function to call when the associated node is updated and moves out of running state.\n */\nexport default class Entry extends Callback {\n /**\n * @param functionName The name of the agent function to call.\n * @param args The array of callback argument definitions.\n */\n constructor(functionName: string, args: AnyArgument[]) {\n super(\"entry\", args, functionName);\n }\n\n /**\n * Attempt to call the agent function that this callback refers to.\n * @param agent The agent.\n */\n callAgentFunction = (agent: Agent) => {\n // Attempt to get the invoker for the callback function.\n const callbackFuncInvoker = Lookup.getFuncInvoker(agent, this.getFunctionName());\n\n // The callback function should be defined.\n if (callbackFuncInvoker === null) {\n throw new Error(\n `cannot call entry function '${this.getFunctionName()}' as is not defined on the agent and has not been registered`\n );\n }\n\n // Call the callback function.\n callbackFuncInvoker(this.args);\n };\n}\n", "import Callback from \"./Callback\";\nimport Lookup, { AnyExitArgument } from \"../../Lookup\";\nimport { Agent } from \"../../Agent\";\nimport { AnyArgument } from \"../../RootAstNodesBuilder\";\n\n/**\n * An EXIT callback which defines an agent function to call when the associated node is updated and moves to a finished state or is aborted.\n */\nexport default class Exit extends Callback {\n /**\n * @param functionName The name of the agent function to call.\n * @param args The array of callback argument definitions.\n */\n constructor(functionName: string, args: AnyArgument[]) {\n super(\"exit\", args, functionName);\n }\n\n /**\n * Attempt to call the agent function that this callback refers to.\n * @param agent The agent.\n * @param isSuccess Whether the decorated node was left with a success state.\n * @param isAborted Whether the decorated node was aborted.\n */\n callAgentFunction = (agent: Agent, isSuccess: boolean, isAborted: boolean) => {\n // Attempt to get the invoker for the callback function.\n const callbackFuncInvoker = Lookup.getFuncInvoker(agent, this.getFunctionName());\n\n // The callback function should be defined.\n if (callbackFuncInvoker === null) {\n throw new Error(\n `cannot call exit function '${this.getFunctionName()}' as is not defined on the agent and has not been registered`\n );\n }\n\n // Call the callback function\n callbackFuncInvoker([{ value: { succeeded: isSuccess, aborted: isAborted } }, ...this.args]);\n };\n}\n", "import Callback from \"./Callback\";\nimport Lookup from \"../../Lookup\";\nimport { Agent } from \"../../Agent\";\nimport { AnyArgument } from \"../../RootAstNodesBuilder\";\n\n/**\n * A STEP callback which defines an agent function to call when the associated node is updated.\n */\nexport default class Step extends Callback {\n /**\n * @param functionName The name of the agent function to call.\n * @param args The array of callback argument definitions.\n */\n constructor(functionName: string, args: AnyArgument[]) {\n super(\"step\", args, functionName);\n }\n\n /**\n * Attempt to call the agent function that this callback refers to.\n * @param agent The agent.\n */\n callAgentFunction = (agent: Agent) => {\n // Attempt to get the invoker for the callback function.\n const callbackFuncInvoker = Lookup.getFuncInvoker(agent, this.getFunctionName());\n\n // The callback function should be defined.\n if (callbackFuncInvoker === null) {\n throw new Error(\n `cannot call step function '${this.getFunctionName()}' as is not defined on the agent and has not been registered`\n );\n }\n\n // Call the callback function.\n callbackFuncInvoker(this.args);\n };\n}\n", "import Action from \"./nodes/leaf/Action\";\nimport Condition from \"./nodes/leaf/Condition\";\nimport Wait from \"./nodes/leaf/Wait\";\nimport Root from \"./nodes/decorator/Root\";\nimport Repeat from \"./nodes/decorator/Repeat\";\nimport Retry from \"./nodes/decorator/Retry\";\nimport Flip from \"./nodes/decorator/Flip\";\nimport Succeed from \"./nodes/decorator/Succeed\";\nimport Fail from \"./nodes/decorator/Fail\";\nimport Lotto from \"./nodes/composite/Lotto\";\nimport Selector from \"./nodes/composite/Selector\";\nimport Sequence from \"./nodes/composite/Sequence\";\nimport Parallel from \"./nodes/composite/Parallel\";\nimport Node from \"./nodes/Node\";\nimport While from \"./attributes/guards/While\";\nimport Until from \"./attributes/guards/Until\";\nimport Entry from \"./attributes/callbacks/Entry\";\nimport Exit from \"./attributes/callbacks/Exit\";\nimport Step from \"./attributes/callbacks/Step\";\nimport Callback from \"./attributes/callbacks/Callback\";\nimport Guard from \"./attributes/guards/Guard\";\nimport Attribute from \"./attributes/Attribute\";\nimport Composite from \"./nodes/composite/Composite\";\nimport Decorator from \"./nodes/decorator/Decorator\";\nimport Leaf from \"./nodes/leaf/Leaf\";\n\nexport type Argument = {\n value: T;\n type: string; // Used for validation.\n};\ntype NullArgument = Argument & {\n type: \"null\";\n};\ntype BooleanArgument = Argument & {\n type: \"boolean\";\n};\ntype NumberArgument = Argument & {\n type: \"number\";\n isInteger: boolean; // Used for validation.\n};\ntype StringPlaceholderArgument = Argument & {\n type: \"string\";\n};\ntype IdentifierArgument = Argument & {\n type: \"identifier\";\n};\nexport type AnyArgument =\n | NullArgument\n | BooleanArgument\n | NumberArgument\n | StringPlaceholderArgument\n | IdentifierArgument;\n\n/**\n * The node attribute factories.\n */\nconst AttributeFactories: {\n [key: string]: (functionName: string, attributeArguments: AnyArgument[]) => Callback | Guard;\n} = {\n WHILE: (condition: string, attributeArguments: AnyArgument[]) => new While(condition, attributeArguments),\n UNTIL: (condition: string, attributeArguments: AnyArgument[]) => new Until(condition, attributeArguments),\n ENTRY: (functionName: string, attributeArguments: AnyArgument[]) => new Entry(functionName, attributeArguments),\n EXIT: (functionName: string, attributeArguments: AnyArgument[]) => new Exit(functionName, attributeArguments),\n STEP: (functionName: string, attributeArguments: AnyArgument[]) => new Step(functionName, attributeArguments)\n};\n\ntype Validatable = {\n children?: AstNode[];\n validate: (depth: number) => void;\n};\n\ntype NodeInstanceCreator = (\n namedRootNodeProvider: (name: string) => RootAstNode,\n visitedBranches: string[]\n) => T;\n\nexport type AstNode = Validatable & {\n type: string;\n createNodeInstance: NodeInstanceCreator;\n};\n\nexport type LeafAstNode = AstNode & {\n type: \"action\" | \"condition\" | \"wait\";\n attributes: Attribute[];\n};\n\nexport type CompositeAstNode = AstNode & {\n type: \"lotto\" | \"parallel\" | \"selector\" | \"sequence\";\n attributes: Attribute[];\n children: AstNode[];\n};\n\nexport type DecoratorAstNode = AstNode & {\n type: \"fail\" | \"flip\" | \"repeat\" | \"retry\" | \"root\" | \"succeed\";\n attributes: Attribute[];\n children: AstNode[];\n};\n\nexport type BranchAstNode = AstNode & {\n type: \"branch\";\n branchName: \"\" | string;\n};\n\nexport type LottoAstNode = CompositeAstNode & {\n type: \"lotto\";\n tickets: number[];\n};\n\nexport type RootAstNode = DecoratorAstNode & {\n type: \"root\";\n name: null | string;\n};\n\nexport type IterableAstNode = DecoratorAstNode & {\n type: \"repeat\" | \"retry\";\n iterations: null | number;\n maximumIterations: null | number;\n};\n\nexport type ActionAstNode = LeafAstNode & {\n type: \"action\";\n actionName: string;\n actionArguments: AnyArgument[];\n};\n\nexport type ConditionAstNode = LeafAstNode & {\n type: \"condition\";\n conditionName: string;\n conditionArguments: AnyArgument[];\n};\n\nexport type WaitAstNode = LeafAstNode & {\n type: \"wait\";\n duration: number | null;\n longestDuration: number | null;\n};\n\nexport type AnyAstNode =\n | BranchAstNode\n | CompositeAstNode\n | LottoAstNode\n | DecoratorAstNode\n | RootAstNode\n | IterableAstNode\n | LeafAstNode\n | ActionAstNode\n | ConditionAstNode\n | WaitAstNode;\n\n/**\n * The AST node factories.\n */\nconst ASTNodeFactories = {\n ROOT: (): RootAstNode => ({\n type: \"root\",\n attributes: [],\n name: null,\n children: [],\n validate(depth: number) {\n // A root node cannot be the child of another node.\n if (depth > 1) {\n throw new Error(\"a root node cannot be the child of another node\");\n }\n\n // A root node must have a single child node.\n if (this.children.length !== 1) {\n throw new Error(\"a root node must have a single child\");\n }\n },\n createNodeInstance(namedRootNodeProvider, visitedBranches) {\n return new Root(\n this.attributes,\n this.children![0].createNodeInstance(namedRootNodeProvider, visitedBranches.slice())\n );\n }\n }),\n BRANCH: (): BranchAstNode => ({\n type: \"branch\",\n branchName: \"\",\n validate() {},\n createNodeInstance(namedRootNodeProvider, visitedBranches) {\n // Try to find the root node with a matching branch name.\n const targetRootNode = namedRootNodeProvider(this.branchName);\n\n // If we have already visited this branch then we have a circular dependency.\n if (visitedBranches.indexOf(this.branchName) !== -1) {\n throw new Error(`circular dependency found in branch node references for branch '${this.branchName}'`);\n }\n\n // If we have a target root node, then the node instance we want will be the first and only child of the referenced root node.\n if (targetRootNode) {\n return targetRootNode\n .createNodeInstance(namedRootNodeProvider, visitedBranches.concat(this.branchName))\n .getChildren()[0];\n } else {\n throw new Error(`branch references root node '${this.branchName}' which has not been defined`);\n }\n }\n }),\n SELECTOR: (): CompositeAstNode => ({\n type: \"selector\",\n attributes: [],\n children: [],\n validate() {\n // A selector node must have at least a single node.\n if (this.children.length < 1) {\n throw new Error(\"a selector node must have at least a single child\");\n }\n },\n createNodeInstance(namedRootNodeProvider, visitedBranches) {\n return new Selector(\n this.attributes,\n this.children.map((child) => child.createNodeInstance(namedRootNodeProvider, visitedBranches.slice()))\n );\n }\n }),\n SEQUENCE: (): CompositeAstNode => ({\n type: \"sequence\",\n attributes: [],\n children: [],\n validate() {\n // A sequence node must have at least a single node.\n if (this.children.length < 1) {\n throw new Error(\"a sequence node must have at least a single child\");\n }\n },\n createNodeInstance(namedRootNodeProvider, visitedBranches) {\n return new Sequence(\n this.attributes,\n this.children.map((child) => child.createNodeInstance(namedRootNodeProvider, visitedBranches.slice()))\n );\n }\n }),\n PARALLEL: (): CompositeAstNode => ({\n type: \"parallel\",\n attributes: [],\n children: [],\n validate() {\n // A parallel node must have at least a single node.\n if (this.children.length < 1) {\n throw new Error(\"a parallel node must have at least a single child\");\n }\n },\n createNodeInstance(namedRootNodeProvider, visitedBranches) {\n return new Parallel(\n this.attributes,\n this.children.map((child) => child.createNodeInstance(namedRootNodeProvider, visitedBranches.slice()))\n );\n }\n }),\n LOTTO: (): LottoAstNode => ({\n type: \"lotto\",\n attributes: [],\n children: [],\n tickets: [],\n validate() {\n // A lotto node must have at least a single node.\n if (this.children!.length < 1) {\n throw new Error(\"a lotto node must have at least a single child\");\n }\n },\n createNodeInstance(namedRootNodeProvider, visitedBranches) {\n return new Lotto(\n this.attributes,\n this.tickets!,\n this.children!.map((child) => child.createNodeInstance(namedRootNodeProvider, visitedBranches.slice()))\n );\n }\n }),\n REPEAT: (): IterableAstNode => ({\n type: \"repeat\",\n attributes: [],\n iterations: null,\n maximumIterations: null,\n children: [],\n validate() {\n // A repeat node must have a single node.\n if (this.children!.length !== 1) {\n throw new Error(\"a repeat node must have a single child\");\n }\n\n // A repeat node must have a positive number of iterations if defined.\n if (this.iterations !== null && this.iterations! < 0) {\n throw new Error(\"a repeat node must have a positive number of iterations if defined\");\n }\n\n // There is validation to carry out if a longest duration was defined.\n if (this.maximumIterations !== null) {\n // A repeat node must have a positive maximum iterations count if defined.\n if (this.maximumIterations! < 0) {\n throw new Error(\"a repeat node must have a positive maximum iterations count if defined\");\n }\n\n // A repeat node must not have an iteration count that exceeds the maximum iteration count.\n if (this.iterations! > this.maximumIterations!) {\n throw new Error(\n \"a repeat node must not have an iteration count that exceeds the maximum iteration count\"\n );\n }\n }\n },\n createNodeInstance(namedRootNodeProvider, visitedBranches) {\n return new Repeat(\n this.attributes,\n this.iterations!,\n this.maximumIterations!,\n this.children![0].createNodeInstance(namedRootNodeProvider, visitedBranches.slice())\n );\n }\n }),\n RETRY: (): IterableAstNode => ({\n type: \"retry\",\n attributes: [],\n iterations: null,\n maximumIterations: null,\n children: [],\n validate() {\n // A retry node must have a single node.\n if (this.children!.length !== 1) {\n throw new Error(\"a retry node must have a single child\");\n }\n\n // A retry node must have a positive number of iterations if defined.\n if (this.iterations !== null && this.iterations! < 0) {\n throw new Error(\"a retry node must have a positive number of iterations if defined\");\n }\n\n // There is validation to carry out if a longest duration was defined.\n if (this.maximumIterations !== null) {\n // A retry node must have a positive maximum iterations count if defined.\n if (this.maximumIterations! < 0) {\n throw new Error(\"a retry node must have a positive maximum iterations count if defined\");\n }\n\n // A retry node must not have an iteration count that exceeds the maximum iteration count.\n if (this.iterations! > this.maximumIterations!) {\n throw new Error(\n \"a retry node must not have an iteration count that exceeds the maximum iteration count\"\n );\n }\n }\n },\n createNodeInstance(namedRootNodeProvider, visitedBranches) {\n return new Retry(\n this.attributes,\n this.iterations!,\n this.maximumIterations!,\n this.children![0].createNodeInstance(namedRootNodeProvider, visitedBranches.slice())\n );\n }\n }),\n FLIP: (): DecoratorAstNode => ({\n type: \"flip\",\n attributes: [],\n children: [],\n validate() {\n // A flip node must have a single node.\n if (this.children!.length !== 1) {\n throw new Error(\"a flip node must have a single child\");\n }\n },\n createNodeInstance(namedRootNodeProvider, visitedBranches) {\n return new Flip(\n this.attributes,\n this.children![0].createNodeInstance(namedRootNodeProvider, visitedBranches.slice())\n );\n }\n }),\n SUCCEED: (): DecoratorAstNode => ({\n type: \"succeed\",\n attributes: [],\n children: [],\n validate() {\n // A succeed node must have a single node.\n if (this.children!.length !== 1) {\n throw new Error(\"a succeed node must have a single child\");\n }\n },\n createNodeInstance(namedRootNodeProvider, visitedBranches) {\n return new Succeed(\n this.attributes,\n this.children![0].createNodeInstance(namedRootNodeProvider, visitedBranches.slice())\n );\n }\n }),\n FAIL: (): DecoratorAstNode => ({\n type: \"fail\",\n attributes: [],\n children: [],\n validate() {\n // A fail node must have a single node.\n if (this.children!.length !== 1) {\n throw new Error(\"a fail node must have a single child\");\n }\n },\n createNodeInstance(namedRootNodeProvider, visitedBranches) {\n return new Fail(\n this.attributes,\n this.children![0].createNodeInstance(namedRootNodeProvider, visitedBranches.slice())\n );\n }\n }),\n WAIT: (): WaitAstNode => ({\n type: \"wait\",\n attributes: [],\n duration: null,\n longestDuration: null,\n validate() {\n // A wait node must have a positive duration.\n if (this.duration! < 0) {\n throw new Error(\"a wait node must have a positive duration\");\n }\n\n // There is validation to carry out if a longest duration was defined.\n if (this.longestDuration) {\n // A wait node must have a positive longest duration.\n if (this.longestDuration < 0) {\n throw new Error(\"a wait node must have a positive longest duration if one is defined\");\n }\n\n // A wait node must not have a duration that exceeds the longest duration.\n if (this.duration! > this.longestDuration) {\n throw new Error(\"a wait node must not have a shortest duration that exceeds the longest duration\");\n }\n }\n },\n createNodeInstance() {\n return new Wait(this.attributes, this.duration!, this.longestDuration!);\n }\n }),\n ACTION: (): ActionAstNode => ({\n type: \"action\",\n attributes: [],\n actionName: \"\",\n actionArguments: [],\n validate() {},\n createNodeInstance() {\n return new Action(this.attributes, this.actionName!, this.actionArguments!);\n }\n }),\n CONDITION: (): ConditionAstNode => ({\n type: \"condition\",\n attributes: [],\n conditionName: \"\",\n conditionArguments: [],\n validate() {},\n createNodeInstance() {\n return new Condition(this.attributes, this.conditionName!, this.conditionArguments!);\n }\n })\n};\n\ntype OtherAstNodes = AstNode[];\n\n/**\n * Create an array of root AST nodes based on the given definition.\n * @param definition The definition to parse the AST nodes from.\n * @returns The base definition AST nodes.\n */\nexport default function buildRootASTNodes(definition: string): RootAstNode[] {\n // Swap out any node/attribute argument string literals with a placeholder and get a mapping of placeholders to original values as well as the processed definition.\n const { placeholders, processedDefinition } = substituteStringLiterals(definition);\n\n // Convert the processed definition (with substituted string literals) into an array of raw tokens.\n const tokens = parseTokensFromDefinition(processedDefinition);\n\n // There must be at least 3 tokens for the tree definition to be valid. 'ROOT', '{' and '}'.\n if (tokens.length < 3) {\n throw new Error(\"invalid token count\");\n }\n\n // We should have a matching number of '{' and '}' tokens. If not, then there are scopes that have not been properly closed.\n if (tokens.filter((token) => token === \"{\").length !== tokens.filter((token) => token === \"}\").length) {\n throw new Error(\"scope character mismatch\");\n }\n\n // Create a stack of node children arrays, starting with a definition scope.\n const stack: [RootAstNode[], ...OtherAstNodes[]] = [[]];\n const rootScope = stack[0];\n\n // We should keep processing the raw tokens until we run out of them.\n while (tokens.length) {\n // Grab the next token.\n const token = tokens.shift();\n\n const currentScope = stack[stack.length - 1] as OtherAstNodes;\n\n // How we create the next AST token depends on the current raw token value.\n switch (token!.toUpperCase()) {\n case \"ROOT\": {\n // Create a ROOT AST node.\n const node = ASTNodeFactories.ROOT();\n\n // Push the ROOT node into the current scope.\n rootScope.push(node);\n\n // We may have a root node name defined as an argument.\n if (tokens[0] === \"[\") {\n const rootArguments = getArguments(tokens, placeholders);\n\n // We should have only a single argument that is not an empty string for a root node, which is the root name identifier.\n if (rootArguments.length === 1 && rootArguments[0].type === \"identifier\") {\n // The root name will be the first and only node argument.\n node.name = rootArguments[0].value as string;\n } else {\n throw new Error(\"expected single root name argument\");\n }\n }\n\n // Try to pick any attributes off of the token stack.\n node.attributes = getAttributes(tokens, placeholders);\n\n popAndCheck(tokens, \"{\");\n\n // The new scope is that of the new ROOT nodes children.\n stack.push(node.children!);\n break;\n }\n\n case \"BRANCH\": {\n // Create a BRANCH AST node.\n const node = ASTNodeFactories.BRANCH();\n\n // Push the BRANCH node into the current scope.\n currentScope.push(node);\n\n // We must have arguments defined, as we require a branch name argument.\n if (tokens[0] !== \"[\") {\n throw new Error(\"expected single branch name argument\");\n }\n\n // The branch name will be defined as a node argument.\n const branchArguments = getArguments(tokens, placeholders);\n\n // We should have only a single identifer argument for a branch node, which is the branch name.\n if (branchArguments.length === 1 && branchArguments[0].type === \"identifier\") {\n // The branch name will be the first and only node argument.\n node.branchName = branchArguments[0].value as string;\n } else {\n throw new Error(\"expected single branch name argument\");\n }\n break;\n }\n\n case \"SELECTOR\": {\n // Create a SELECTOR AST node.\n const node = ASTNodeFactories.SELECTOR();\n\n // Push the SELECTOR node into the current scope.\n currentScope.push(node);\n\n // Try to pick any attributes off of the token stack.\n node.attributes = getAttributes(tokens, placeholders);\n\n popAndCheck(tokens, \"{\");\n\n // The new scope is that of the new SELECTOR nodes children.\n stack.push(node.children!);\n break;\n }\n\n case \"SEQUENCE\": {\n // Create a SEQUENCE AST node.\n const node = ASTNodeFactories.SEQUENCE();\n\n // Push the SEQUENCE node into the current scope.\n currentScope.push(node);\n\n // Try to pick any attributes off of the token stack.\n node.attributes = getAttributes(tokens, placeholders);\n\n popAndCheck(tokens, \"{\");\n\n // The new scope is that of the new SEQUENCE nodes children.\n stack.push(node.children!);\n break;\n }\n\n case \"PARALLEL\": {\n // Create a PARALLEL AST node.\n const node = ASTNodeFactories.PARALLEL();\n\n // Push the PARALLEL node into the current scope.\n currentScope.push(node);\n\n // Try to pick any attributes off of the token stack.\n node.attributes = getAttributes(tokens, placeholders);\n\n popAndCheck(tokens, \"{\");\n\n // The new scope is that of the new PARALLEL nodes children.\n stack.push(node.children!);\n break;\n }\n\n case \"LOTTO\": {\n // Create a LOTTO AST node.\n const node = ASTNodeFactories.LOTTO();\n\n // Push the LOTTO node into the current scope.\n currentScope.push(node);\n\n // If the next token is a '[' character then some ticket counts have been defined as arguments.\n if (tokens[0] === \"[\") {\n // Get the ticket count arguments, each argument must be a number.\n node.tickets = getArguments(\n tokens,\n placeholders,\n (arg) => arg.type === \"number\" && !!arg.isInteger,\n \"lotto node ticket counts must be integer values\"\n ).map((argument) => argument.value as number);\n }\n\n // Try to pick any attributes off of the token stack.\n node.attributes = getAttributes(tokens, placeholders);\n\n popAndCheck(tokens, \"{\");\n\n // The new scope is that of the new LOTTO nodes children.\n stack.push(node.children!);\n break;\n }\n\n case \"CONDITION\": {\n // Create a CONDITION AST node.\n const node = ASTNodeFactories.CONDITION();\n\n // Push the CONDITION node into the current scope.\n currentScope.push(node);\n\n // We must have arguments defined, as we require a condition function name argument.\n if (tokens[0] !== \"[\") {\n throw new Error(\"expected condition name identifier argument\");\n }\n\n // Grab the condition node arguments.\n const conditionArguments = getArguments(tokens, placeholders);\n\n // We should have at least a single identifier argument for a condition node, which is the condition function name.\n if (conditionArguments.length && conditionArguments[0].type === \"identifier\") {\n // The condition function name will be the first node argument.\n node.conditionName = conditionArguments.shift()!.value as string;\n } else {\n throw new Error(\"expected condition name identifier argument\");\n }\n\n // Only the first argument should have been an identifier, all following arguments must be string, number, boolean or null.\n conditionArguments\n .filter((arg) => arg.type === \"identifier\")\n .forEach((arg) => {\n throw new Error(\n \"invalid condition node argument value '\" +\n arg.value +\n \"', must be string, number, boolean or null\"\n );\n });\n\n // Any node arguments that follow the condition name identifier will be treated as condition function arguments.\n node.conditionArguments = conditionArguments;\n\n // Try to pick any attributes off of the token stack.\n node.attributes = getAttributes(tokens, placeholders);\n break;\n }\n\n case \"FLIP\": {\n // Create a FLIP AST node.\n const node = ASTNodeFactories.FLIP();\n\n // Push the Flip node into the current scope.\n currentScope.push(node);\n\n // Try to pick any attributes off of the token stack.\n node.attributes = getAttributes(tokens, placeholders);\n\n popAndCheck(tokens, \"{\");\n\n // The new scope is that of the new FLIP nodes children.\n stack.push(node.children!);\n break;\n }\n\n case \"SUCCEED\": {\n // Create a SUCCEED AST node.\n const node = ASTNodeFactories.SUCCEED();\n\n // Push the Succeed node into the current scope.\n currentScope.push(node);\n\n // Try to pick any attributes off of the token stack.\n node.attributes = getAttributes(tokens, placeholders);\n\n popAndCheck(tokens, \"{\");\n\n // The new scope is that of the new Succeed nodes children.\n stack.push(node.children!);\n break;\n }\n\n case \"FAIL\": {\n // Create a FAIL AST node.\n const node = ASTNodeFactories.FAIL();\n\n // Push the Fail node into the current scope.\n currentScope.push(node);\n\n // Try to pick any attributes off of the token stack.\n node.attributes = getAttributes(tokens, placeholders);\n\n popAndCheck(tokens, \"{\");\n\n // The new scope is that of the new Fail nodes children.\n stack.push(node.children!);\n break;\n }\n\n case \"WAIT\": {\n // Create a WAIT AST node.\n const node = ASTNodeFactories.WAIT();\n\n // Push the WAIT node into the current scope.\n currentScope.push(node);\n\n // Get the duration and potential longest duration of the wait.\n const durations = getArguments(\n tokens,\n placeholders,\n (arg) => arg.type === \"number\" && !!arg.isInteger,\n \"wait node durations must be integer values\"\n ).map((argument) => argument.value);\n\n // We should have got one or two durations.\n if (durations.length === 1) {\n // A static duration was defined.\n node.duration = durations[0] as number;\n } else if (durations.length === 2) {\n // A shortest and longest duration was defined.\n node.duration = durations[0] as number;\n node.longestDuration = durations[1] as number;\n } else {\n // An incorrect number of durations was defined.\n throw new Error(\"invalid number of wait node duration arguments defined\");\n }\n\n // Try to pick any attributes off of the token stack.\n node.attributes = getAttributes(tokens, placeholders);\n break;\n }\n\n case \"REPEAT\": {\n // Create a REPEAT AST node.\n const node = ASTNodeFactories.REPEAT();\n\n // Push the REPEAT node into the current scope.\n currentScope.push(node);\n\n // Check for iteration counts ([])\n if (tokens[0] === \"[\") {\n // An iteration count has been defined. Get the iteration and potential maximum iteration of the wait.\n const iterationArguments = getArguments(\n tokens,\n placeholders,\n (arg) => arg.type === \"number\" && !!arg.isInteger,\n \"repeat node iteration counts must be integer values\"\n ).map((argument) => argument.value);\n\n // We should have got one or two iteration counts.\n if (iterationArguments.length === 1) {\n // A static iteration count was defined.\n node.iterations = iterationArguments[0] as number;\n } else if (iterationArguments.length === 2) {\n // A minimum and maximum iteration count was defined.\n node.iterations = iterationArguments[0] as number;\n node.maximumIterations = iterationArguments[1] as number;\n } else {\n // An incorrect number of iteration counts was defined.\n throw new Error(\"invalid number of repeat node iteration count arguments defined\");\n }\n }\n\n // Try to pick any attributes off of the token stack.\n node.attributes = getAttributes(tokens, placeholders);\n\n popAndCheck(tokens, \"{\");\n\n // The new scope is that of the new REPEAT nodes children.\n stack.push(node.children!);\n break;\n }\n\n case \"RETRY\": {\n // Create a RETRY AST node.\n const node = ASTNodeFactories.RETRY();\n\n // Push the RETRY node into the current scope.\n currentScope.push(node);\n\n // Check for iteration counts ([])\n if (tokens[0] === \"[\") {\n // An iteration count has been defined. Get the iteration and potential maximum iteration of the wait.\n const iterationArguments = getArguments(\n tokens,\n placeholders,\n (arg) => arg.type === \"number\" && !!arg.isInteger,\n \"retry node iteration counts must be integer values\"\n ).map((argument) => argument.value);\n\n // We should have got one or two iteration counts.\n if (iterationArguments.length === 1) {\n // A static iteration count was defined.\n node.iterations = iterationArguments[0] as number;\n } else if (iterationArguments.length === 2) {\n // A minimum and maximum iteration count was defined.\n node.iterations = iterationArguments[0] as number;\n node.maximumIterations = iterationArguments[1] as number;\n } else {\n // An incorrect number of iteration counts was defined.\n throw new Error(\"invalid number of retry node iteration count arguments defined\");\n }\n }\n\n // Try to pick any attributes off of the token stack.\n node.attributes = getAttributes(tokens, placeholders);\n\n popAndCheck(tokens, \"{\");\n\n // The new scope is that of the new RETRY nodes children.\n stack.push(node.children!);\n break;\n }\n\n case \"ACTION\": {\n // Create a ACTION AST node.\n const node = ASTNodeFactories.ACTION();\n\n // Push the ACTION node into the current scope.\n currentScope.push(node);\n\n // We must have arguments defined, as we require an action name argument.\n if (tokens[0] !== \"[\") {\n throw new Error(\"expected action name identifier argument\");\n }\n\n // The action name will be defined as a node argument.\n const actionArguments = getArguments(tokens, placeholders);\n\n // We should have at least one identifer argument for an action node, which is the action name.\n if (actionArguments.length && actionArguments[0].type === \"identifier\") {\n // The action name will be the first and only node argument.\n node.actionName = actionArguments.shift()!.value as string;\n } else {\n throw new Error(\"expected action name identifier argument\");\n }\n\n // Only the first argument should have been an identifier, all following arguments must be string, number, boolean or null.\n actionArguments\n .filter((arg) => arg.type === \"identifier\")\n .forEach((arg) => {\n throw new Error(\n \"invalid action node argument value '\" +\n arg.value +\n \"', must be string, number, boolean or null\"\n );\n });\n\n // Any node arguments that follow the action name identifier will be treated as action function arguments.\n node.actionArguments = actionArguments;\n\n // Try to pick any attributes off of the token stack.\n node.attributes = getAttributes(tokens, placeholders);\n break;\n }\n\n case \"}\": {\n // The '}' character closes the current scope.\n stack.pop();\n break;\n }\n\n default: {\n throw new Error(\"unexpected token: \" + token);\n }\n }\n }\n\n // A function to recursively validate each of the nodes in the AST.\n const validateASTNode = (node: Validatable, depth: number): void => {\n // Validate the node.\n node.validate(depth);\n\n // Validate each child of the node.\n (node.children || []).forEach((child) => validateASTNode(child, depth + 1));\n };\n\n // Start node validation from the definition root.\n validateASTNode(\n {\n children: stack[0] as RootAstNode[],\n validate(this: { children: RootAstNode[] }) {\n // We must have at least one node defined as the definition scope, which should be a root node.\n if (this.children.length === 0) {\n throw new Error(\"expected root node to have been defined\");\n }\n\n // Each node at the base of the definition scope MUST be a root node.\n for (const definitionLevelNode of this.children) {\n if (definitionLevelNode.type !== \"root\") {\n throw new Error(\"expected root node at base of definition\");\n }\n }\n\n // Exactly one root node must not have a name defined. This will be the main root, others will have to be referenced via branch nodes.\n if (this.children.filter((definitionLevelNode) => definitionLevelNode.name === null).length !== 1) {\n throw new Error(\"expected single unnamed root node at base of definition to act as main root\");\n }\n\n // No two named root nodes can have matching names.\n const rootNodeNames: string[] = [];\n for (const definitionLevelNode of this.children) {\n if (rootNodeNames.indexOf(definitionLevelNode.name!) !== -1) {\n throw new Error(`multiple root nodes found with duplicate name '${definitionLevelNode.name}'`);\n } else {\n rootNodeNames.push(definitionLevelNode.name!);\n }\n }\n }\n },\n 0\n );\n\n // Return the root AST nodes.\n return stack[0];\n}\n\n/**\n * Pop the next raw token off of the stack and throw an error if it wasn't the expected one.\n * @param tokens The array of remaining tokens.\n * @param expected An optional string or array or items, one of which must match the next popped token.\n * @returns The popped token.\n */\nfunction popAndCheck(tokens: string[], expected: string | string[]) {\n // Get and remove the next token.\n const popped = tokens.shift();\n\n // We were expecting another token.\n if (popped === undefined) {\n throw new Error(\"unexpected end of definition\");\n }\n\n // Do we have an expected token/tokens array?\n if (expected !== undefined) {\n // Check whether the popped token matches at least one of our expected items.\n var tokenMatchesExpectation = ([] as string[])\n .concat(expected)\n .some((item) => popped.toUpperCase() === item.toUpperCase());\n\n // Throw an error if the popped token didn't match any of our expected items.\n if (!tokenMatchesExpectation) {\n const expectationString = ([] as string[])\n .concat(expected)\n .map((item) => \"'\" + item + \"'\")\n .join(\" or \");\n throw new Error(\"unexpected token found. Expected \" + expectationString + \" but got '\" + popped + \"'\");\n }\n }\n\n // Return the popped token.\n return popped;\n}\n\ntype Placeholders = { [key: string]: string };\n\n/**\n * Pull an argument definition list off of the token stack.\n * @param tokens The array of remaining tokens.\n * @param stringArgumentPlaceholders The mapping of string literal node argument placeholders to original values.\n * @param argumentValidator The argument validator function.\n * @param validationFailedMessage The exception message to throw if argument validation fails.\n * @returns The argument definition list.\n */\nfunction getArguments(\n tokens: string[],\n stringArgumentPlaceholders: Placeholders,\n argumentValidator?: (arg: AnyArgument) => boolean,\n validationFailedMessage?: string\n) {\n // Any lists of arguments will always be wrapped in '[]' for node arguments or '()' for attribute arguments.\n // We are looking for a '[' or '(' opener that wraps the argument tokens and the relevant closer.\n const closer = popAndCheck(tokens, [\"[\", \"(\"]) === \"[\" ? \"]\" : \")\";\n\n const argumentListTokens: string[] = [];\n const argumentList: AnyArgument[] = [];\n\n // Grab all tokens between the '[' and ']' or '(' and ')'.\n while (tokens.length && tokens[0] !== closer) {\n // The next token is part of our arguments list.\n argumentListTokens.push(tokens.shift()!);\n }\n\n // Validate the order of the argument tokens. Each token must either be a ',' or a single argument that satisfies the validator.\n argumentListTokens.forEach((token, index) => {\n // Get whether this token should be an actual argument.\n const shouldBeArgumentToken = !(index & 1);\n\n // If the current token should be an actual argument then validate it,otherwise it should be a ',' token.\n if (shouldBeArgumentToken) {\n // Get the argument definition.\n const argumentDefinition = getArgumentDefinition(token!, stringArgumentPlaceholders);\n\n // Try to validate the argument.\n if (argumentValidator && !argumentValidator(argumentDefinition)) {\n throw new Error(validationFailedMessage);\n }\n\n // This is a valid argument!\n argumentList.push(argumentDefinition);\n } else {\n // The current token should be a ',' token.\n if (token !== \",\") {\n throw new Error(`invalid argument list, expected ',' or ']' but got '${token}'`);\n }\n }\n });\n\n // The arguments list should terminate with a ']' or ')' token, depending on the opener.\n popAndCheck(tokens, closer);\n\n // Return the argument list.\n return argumentList;\n}\n\n/**\n * Gets an argument value definition.\n * @param token The argument token.\n * @param stringArgumentPlaceholders The mapping of string literal node argument placeholders to original values.\n * @returns An argument value definition.\n */\nfunction getArgumentDefinition(token: string, stringArgumentPlaceholders: Placeholders): AnyArgument {\n // Check whether the token represents a null value.\n if (token === \"null\") {\n return {\n value: null,\n type: \"null\"\n } as NullArgument;\n }\n\n // Check whether the token represents a boolean value.\n if (token === \"true\" || token === \"false\") {\n return {\n value: token === \"true\",\n type: \"boolean\"\n } as BooleanArgument;\n }\n\n // Check whether the token represents a number value.\n // TODO: Relies on broken isNaN - see MDN.\n // if (!Number.isNaN(token)) {\n if (!isNaN(token as any)) {\n return {\n value: parseFloat(token),\n isInteger: parseFloat(token) === parseInt(token, 10),\n type: \"number\"\n } as NumberArgument;\n }\n\n // Check whether the token is a placeholder (e.g. @@0@@) representing a string literal.\n if (token.match(/^@@\\d+@@$/g)) {\n return {\n value: stringArgumentPlaceholders[token].replace('\\\\\"', '\"'),\n type: \"string\"\n } as StringPlaceholderArgument;\n }\n\n // The only remaining option is that the argument value is an identifier.\n return {\n value: token,\n type: \"identifier\"\n } as IdentifierArgument;\n}\n\n/**\n * Pull any attributes off of the token stack.\n * @param tokens The array of remaining tokens.\n * @param stringArgumentPlaceholders The mapping of string literal node argument placeholders to original values.\n * @returns An array of attributes defined by any directly following tokens.\n */\nfunction getAttributes(tokens: string[], stringArgumentPlaceholders: Placeholders) {\n // Create an array to hold any attributes found.\n const attributes: Attribute[] = [];\n\n // Keep track of names of attribute that we have found on the token stack, as we cannot have duplicates.\n const attributesFound: string[] = [];\n\n // Try to get the attribute factory for the next token.\n let attributeFactory = AttributeFactories[(tokens[0] || \"\").toUpperCase()];\n\n // Pull attribute tokens off of the tokens stack until we have no more.\n while (attributeFactory) {\n // Check to make sure that we have not already created a attribute of this type for this node.\n if (attributesFound.indexOf(tokens[0].toUpperCase()) !== -1) {\n throw new Error(`duplicate attribute '${tokens[0].toUpperCase()}' found for node`);\n }\n\n // Add the current attribute type to our array of found attributes.\n attributesFound.push(tokens.shift()!.toUpperCase());\n\n // Grab any attribute arguments.\n const attributeArguments = getArguments(tokens, stringArgumentPlaceholders);\n\n // The first attribute argument has to be an identifer, this will reference an agent function.\n if (attributeArguments.length === 0 || attributeArguments[0].type !== \"identifier\") {\n throw new Error(\"expected agent function name identifier argument for attribute\");\n }\n\n // Grab the first attribute which is an identifier that will reference an agent function.\n const attributeFunctionName = attributeArguments.shift()! as IdentifierArgument;\n\n // Any remaining attribute arguments must have a type of string, number, boolean or null.\n attributeArguments\n .filter((arg) => arg.type === \"identifier\")\n .forEach((arg) => {\n throw new Error(\n \"invalid attribute argument value '\" + arg.value + \"', must be string, number, boolean or null\"\n );\n });\n\n // Create the attribute and add it to the array of attributes found.\n attributes.push(attributeFactory(attributeFunctionName.value, attributeArguments));\n\n // Try to get the next attribute name token, as there could be multiple.\n attributeFactory = AttributeFactories[(tokens[0] || \"\").toUpperCase()];\n }\n\n return attributes;\n}\n\n/**\n * Swaps out any node/attribute argument string literals with placeholders.\n * @param definition The definition.\n * @returns An object containing a mapping of placeholders to original string values as well as the processed definition string.\n */\nfunction substituteStringLiterals(definition: string): {\n placeholders: { [key: string]: string };\n processedDefinition: string;\n} {\n // Create an object to hold the mapping of placeholders to original string values.\n const placeholders: Placeholders = {};\n\n // Replace any string literals wrapped with double quotes in our definition with placeholders to be processed later.\n const processedDefinition = definition.replace(/\\\"(\\\\.|[^\"\\\\])*\\\"/g, (match) => {\n var strippedMatch = match.substring(1, match.length - 1);\n var placeholder = Object.keys(placeholders).find((key) => placeholders[key] === strippedMatch);\n\n // If we have no existing string literal match then create a new placeholder.\n if (!placeholder) {\n placeholder = `@@${Object.keys(placeholders).length}@@`;\n placeholders[placeholder] = strippedMatch;\n }\n\n return placeholder;\n });\n\n return { placeholders, processedDefinition };\n}\n\n/**\n * Parse the tree definition into an array of raw tokens.\n * @param definition The definition.\n * @returns An array of tokens parsed from the definition.\n */\nfunction parseTokensFromDefinition(definition: string): string[] {\n // Add some space around various important characters so that they can be plucked out easier as individual tokens.\n definition = definition.replace(/\\(/g, \" ( \");\n definition = definition.replace(/\\)/g, \" ) \");\n definition = definition.replace(/\\{/g, \" { \");\n definition = definition.replace(/\\}/g, \" } \");\n definition = definition.replace(/\\]/g, \" ] \");\n definition = definition.replace(/\\[/g, \" [ \");\n definition = definition.replace(/\\,/g, \" , \");\n\n // Split the definition into raw token form and return it.\n return definition.replace(/\\s+/g, \" \").trim().split(\" \");\n}\n", "/**\r\n * A type defining the arguments that can be passed to an agent function.\r\n */\r\nexport type AgentFunctionArguments = (string | number | boolean | null | undefined)[];\r\n\r\n/**\r\n * A guard attribute for a node.\r\n */\r\nexport type GuardAttributeDefinition = {\r\n call: string;\r\n args?: AgentFunctionArguments;\r\n}\r\n\r\n/**\r\n * A callback attribute for a node.\r\n */\r\nexport type CallbackAttributeDefinition = {\r\n call: string;\r\n args?: AgentFunctionArguments;\r\n}\r\n\r\n/**\r\n * A type defining a general node definition.\r\n */\r\nexport type NodeDefinition = {\r\n type: string;\r\n while?: GuardAttributeDefinition;\r\n until?: GuardAttributeDefinition;\r\n entry?: CallbackAttributeDefinition;\r\n exit?: CallbackAttributeDefinition;\r\n step?: CallbackAttributeDefinition;\r\n}\r\n\r\n/**\r\n * A composite node that can contain any number of child nodes.\r\n */\r\nexport type CompositeDefinition = NodeDefinition & {\r\n children: AnyChildNode[];\r\n}\r\n\r\n/**\r\n * A decorator node, a composite with only a single child node.\r\n */\r\nexport type DecoratorDefinition = NodeDefinition & {\r\n child: AnyChildNode;\r\n}\r\n\r\n/**\r\n * A branch node.\r\n */\r\nexport type BranchDefinition = NodeDefinition & {\r\n type: \"branch\";\r\n ref: string;\r\n}\r\n\r\n/**\r\n * An action node.\r\n */\r\nexport type ActionDefinition = NodeDefinition & {\r\n type: \"action\";\r\n call: string;\r\n args?: AgentFunctionArguments;\r\n}\r\n\r\n/**\r\n * A condition node.\r\n */\r\nexport type ConditionDefinition = NodeDefinition & {\r\n type: \"condition\";\r\n call: string;\r\n args?: AgentFunctionArguments;\r\n}\r\n\r\n/**\r\n * A wait node.\r\n */\r\nexport type WaitDefinition = NodeDefinition & {\r\n type: \"wait\";\r\n duration: number | [number, number];\r\n}\r\n\r\n/**\r\n * A sequence node.\r\n */\r\nexport type SequenceDefinition = CompositeDefinition & {\r\n type: \"sequence\";\r\n}\r\n\r\n/**\r\n * A selector node.\r\n */\r\nexport type SelectorDefinition = CompositeDefinition & {\r\n type: \"selector\";\r\n}\r\n\r\n/**\r\n * A lotto node.\r\n */\r\nexport type LottoDefinition = CompositeDefinition & {\r\n type: \"lotto\";\r\n weights?: number[]\r\n}\r\n\r\n/**\r\n * A parallel node.\r\n */\r\nexport type ParallelDefinition = CompositeDefinition & {\r\n type: \"parallel\";\r\n}\r\n\r\n/**\r\n * A root node.\r\n */\r\nexport type RootDefinition = DecoratorDefinition & {\r\n type: \"root\";\r\n id?: string;\r\n}\r\n\r\n/**\r\n * A repeat node.\r\n */\r\nexport type RepeatDefinition = DecoratorDefinition & {\r\n type: \"repeat\";\r\n iterations?: number | [number, number];\r\n}\r\n\r\n/**\r\n * A retry node.\r\n */\r\nexport type RetryDefinition = DecoratorDefinition & {\r\n type: \"retry\";\r\n attempts?: number | [number, number];\r\n}\r\n\r\n/**\r\n * A flip node.\r\n */\r\nexport type FlipDefinition = DecoratorDefinition & {\r\n type: \"flip\";\r\n}\r\n\r\n/**\r\n * A succeed node.\r\n */\r\nexport type SucceedDefinition = DecoratorDefinition & {\r\n type: \"succeed\";\r\n}\r\n\r\n/**\r\n * A fail node.\r\n */\r\nexport type FailDefinition = DecoratorDefinition & {\r\n type: \"fail\";\r\n}\r\n\r\n/**\r\n * A type defining any node type.\r\n */\r\nexport type AnyNode = BranchDefinition | ActionDefinition | ConditionDefinition | WaitDefinition | SequenceDefinition |\r\n SelectorDefinition | LottoDefinition | ParallelDefinition | RootDefinition | RepeatDefinition | RetryDefinition | FlipDefinition | SucceedDefinition | FailDefinition;\r\n\r\n/**\r\n * A type defining any node type that can be a child of composite parent node.\r\n */\r\nexport type AnyChildNode = Exclude;\r\n\r\n/**\r\n * A type defining an object that holds a reference to substitued string literals parsed from the definition.\r\n */\r\ntype StringLiteralPlaceholders = { [key: string]: string };\r\n\r\nfunction isLeafNode(node: NodeDefinition): node is NodeDefinition {\r\n return [\"branch\", \"action\", \"condition\", \"wait\"].includes(node.type);\r\n}\r\n\r\nfunction isDecoratorNode(node: NodeDefinition): node is DecoratorDefinition {\r\n return [\"root\", \"repeat\", \"retry\", \"flip\", \"succeed\", \"fail\"].includes(node.type);\r\n}\r\n\r\nfunction isCompositeNode(node: NodeDefinition): node is CompositeDefinition {\r\n return [\"sequence\", \"selector\", \"lotto\", \"parallel\"].includes(node.type);\r\n}\r\n\r\n/**\r\n * Parse the tree definition string into a JSON definition.\r\n * @param definition The tree definition string.\r\n * @returns The root node JSON definitions.\r\n */\r\nexport function parseToJSON(definition: string): RootDefinition[] {\r\n // Swap out any node/attribute argument string literals with a placeholder and get a mapping of placeholders to original values as well as the processed definition.\r\n const { placeholders, processedDefinition } = substituteStringLiterals(definition);\r\n\r\n // Parse our definition definition string into an array of raw tokens.\r\n const tokens = parseTokensFromDefinition(definition);\r\n\r\n return convertTokensToJSONDefinition(tokens, placeholders, processedDefinition);\r\n}\r\n\r\n/**\r\n * Converts the specified tree definition tokens into a JSON definition.\r\n * @param tokens The tree definition tokens.\r\n * @param placeholders The substituted string literal placeholders.\r\n * @returns The root node JSON definitions.\r\n */\r\nexport function convertTokensToJSONDefinition(tokens: string[], placeholders: StringLiteralPlaceholders, processedDefinition: string): RootDefinition[] {\r\n // There must be at least 3 tokens for the tree definition to be valid. 'ROOT', '{' and '}'.\r\n if (tokens.length < 3) {\r\n throw new Error(\"invalid token count\");\r\n }\r\n\r\n // We should have a matching number of '{' and '}' tokens. If not, then there are scopes that have not been properly closed.\r\n if (tokens.filter((token) => token === \"{\").length !== tokens.filter((token) => token === \"}\").length) {\r\n throw new Error(\"scope character mismatch\");\r\n }\r\n\r\n // Create a stack of tree stack arrays where root nodes will always be at the root.\r\n const treeStacks: [Partial, ...Partial[]][] = [];\r\n\r\n // Create an array of all root node definitions that we create.\r\n const rootNodes: Partial[] = [];\r\n\r\n // ONLY COMPOSITE DEFINITIONS GET PUSHED ONTO A ROOT STACK.\r\n // When coming across a new node in the definition it must be:\r\n // - Set as the child of the top-most node in the root stack OR\r\n // - Added to the array of children of the top-most node in the root stack OR\r\n\r\n const pushRootNode = (rootNode: RootDefinition) => {\r\n // Add the root node definition to our array of all parsed root node definitions.\r\n rootNodes.push(rootNode);\r\n\r\n // Add the root node definition to the root of a new tree stack. \r\n treeStacks.push([rootNode]);\r\n }\r\n \r\n const pushNode = (node: AnyChildNode) => {\r\n // Get the current tree stack that we are populating.\r\n const currentTreeStack = treeStacks[treeStacks.length - 1];\r\n\r\n // TODO Handle cases where we may not have a current root stack.\r\n // This may happen if a root node is not the initially defined one?\r\n\r\n // Get the bottom-most node in the current tree stack.\r\n const bottomNode = currentTreeStack[currentTreeStack.length - 1] as AnyNode;\r\n\r\n // TODO Handle cases where we may not have a bottom-most node.\r\n // Also a potential issue with a badly defined tree.\r\n\r\n // If the bottom-most node in the current root stack is a composite or decorator\r\n // node then the current node should be added as a child of the bottom-most node.\r\n if (isCompositeNode(bottomNode)) {\r\n bottomNode.children = bottomNode.children || [];\r\n bottomNode.children.push(node);\r\n } else if (isDecoratorNode(bottomNode)) {\r\n bottomNode.child = node;\r\n }\r\n\r\n // If the node we are adding is also a composite or decorator node, then we should push it \r\n // onto the current tree stack, as subsequent nodes will be added as its child/children.\r\n if (!isLeafNode(node)) {\r\n currentTreeStack.push(node);\r\n }\r\n };\r\n\r\n const popNode = () => {\r\n // Get the current tree stack that we are populating.\r\n const currentTreeStack = treeStacks[treeStacks.length - 1];\r\n\r\n // Pop the top-most node in the current tree stack if there is one.\r\n if (currentTreeStack.length) {\r\n currentTreeStack.pop();\r\n }\r\n\r\n // We don't want any empty tree stacks in our stack of tree stacks. \r\n if (!currentTreeStack.length) {\r\n treeStacks.pop();\r\n }\r\n };\r\n\r\n // We should keep processing the raw tokens until we run out of them.\r\n while (tokens.length) {\r\n // Grab the next token.\r\n const token = tokens.shift();\r\n\r\n // How we create the next node depends on the current raw token value.\r\n switch (token!.toUpperCase()) {\r\n case \"ROOT\": {\r\n const node = {\r\n type: \"root\"\r\n } as RootDefinition;\r\n\r\n // TODO Grab 'id' if defined as a node argument.\r\n // TODO Grab attributes.\r\n\r\n // This is a decorator node, so we expect an opening '{'.\r\n popAndCheck(tokens, \"{\");\r\n\r\n // A root node will always be the base of a new root stack.\r\n pushRootNode(node);\r\n break;\r\n }\r\n\r\n case \"SEQUENCE\": {\r\n const node = {\r\n type: \"sequence\"\r\n } as SequenceDefinition;\r\n\r\n // TODO Grab attributes.\r\n\r\n // This is a composite node, so we expect an opening '{'.\r\n popAndCheck(tokens, \"{\");\r\n\r\n pushNode(node);\r\n break;\r\n }\r\n\r\n case \"ACTION\": {\r\n const node = {\r\n type: \"action\"\r\n } as ActionDefinition;\r\n\r\n // TODO Grab attributes.\r\n\r\n pushNode(node);\r\n break;\r\n }\r\n\r\n case \"}\": {\r\n // The '}' character closes the current scope.\r\n popNode();\r\n break;\r\n }\r\n\r\n default: {\r\n throw new Error(\"unexpected token: \" + token);\r\n }\r\n }\r\n }\r\n\r\n // TODO Remove!\r\n console.log(rootNodes);\r\n\r\n // TODO\r\n return rootNodes as RootDefinition[];\r\n}\r\n\r\n/**\r\n * Swaps out any node/attribute argument string literals with placeholders.\r\n * @param definition The definition.\r\n * @returns An object containing a mapping of placeholders to original string values as well as the processed definition string.\r\n */\r\nfunction substituteStringLiterals(definition: string): {\r\n placeholders: StringLiteralPlaceholders;\r\n processedDefinition: string;\r\n} {\r\n // Create an object to hold the mapping of placeholders to original string values.\r\n const placeholders: StringLiteralPlaceholders = {};\r\n\r\n // Replace any string literals wrapped with double quotes in our definition with placeholders to be processed later.\r\n const processedDefinition = definition.replace(/\\\"(\\\\.|[^\"\\\\])*\\\"/g, (match) => {\r\n var strippedMatch = match.substring(1, match.length - 1);\r\n var placeholder = Object.keys(placeholders).find((key) => placeholders[key] === strippedMatch);\r\n\r\n // If we have no existing string literal match then create a new placeholder.\r\n if (!placeholder) {\r\n placeholder = `@@${Object.keys(placeholders).length}@@`;\r\n placeholders[placeholder] = strippedMatch;\r\n }\r\n\r\n return placeholder;\r\n });\r\n\r\n return { placeholders, processedDefinition };\r\n}\r\n\r\n/**\r\n * Parse the tree definition into an array of raw tokens.\r\n * @param definition The definition.\r\n * @returns An array of tokens parsed from the definition.\r\n */\r\nfunction parseTokensFromDefinition(definition: string): string[] {\r\n // Add some space around various important characters so that they can be plucked out easier as individual tokens.\r\n definition = definition.replace(/\\(/g, \" ( \");\r\n definition = definition.replace(/\\)/g, \" ) \");\r\n definition = definition.replace(/\\{/g, \" { \");\r\n definition = definition.replace(/\\}/g, \" } \");\r\n definition = definition.replace(/\\]/g, \" ] \");\r\n definition = definition.replace(/\\[/g, \" [ \");\r\n definition = definition.replace(/\\,/g, \" , \");\r\n\r\n // Split the definition into raw token form and return it.\r\n return definition.replace(/\\s+/g, \" \").trim().split(\" \");\r\n}\r\n\r\n/**\r\n * Pop the next raw token off of the stack and throw an error if it wasn't the expected one.\r\n * @param tokens The array of remaining tokens.\r\n * @param expected An optional string or array or items, one of which must match the next popped token.\r\n * @returns The popped token.\r\n */\r\nfunction popAndCheck(tokens: string[], expected?: string | string[]): string {\r\n // Get and remove the next token.\r\n const popped = tokens.shift();\r\n\r\n // We were expecting another token.\r\n if (popped === undefined) {\r\n throw new Error(\"unexpected end of definition\");\r\n }\r\n\r\n // Do we have an expected token/tokens array?\r\n if (expected != undefined) {\r\n // Get an array of expected values, if the popped token matches any then we are all good.\r\n const expectedValues = (typeof expected === \"string\") ? [expected] : expected;\r\n\r\n // Check whether the popped token matches at least one of our expected items.\r\n var tokenMatchesExpectation = expectedValues.some((item) => popped.toUpperCase() === item.toUpperCase());\r\n\r\n // Throw an error if the popped token didn't match any of our expected items.\r\n if (!tokenMatchesExpectation) {\r\n const expectationString = expectedValues.map((item) => \"'\" + item + \"'\").join(\" or \");\r\n throw new Error(\"unexpected token found. Expected \" + expectationString + \" but got '\" + popped + \"'\");\r\n }\r\n }\r\n\r\n // Return the popped token.\r\n return popped;\r\n}", "import GuardPath, { GuardPathPart } from \"./attributes/guards/GuardPath\";\nimport buildRootASTNodes, { AnyArgument, RootAstNode } from \"./RootAstNodesBuilder\";\nimport State, { AnyState } from \"./State\";\nimport Lookup from \"./Lookup\";\nimport Node from \"./nodes/Node\";\nimport Root from \"./nodes/decorator/Root\";\nimport Composite from \"./nodes/composite/Composite\";\nimport Decorator from \"./nodes/decorator/Decorator\";\nimport { Agent, GlobalFunction } from \"./Agent\";\nimport { CallbackAttributeDetails } from \"./attributes/callbacks/Callback\";\nimport { GuardAttributeDetails } from \"./attributes/guards/Guard\";\nimport { BehaviourTreeOptions } from \"./BehaviourTreeOptions\";\nimport { parseToJSON } from \"./DSLParser\";\n\n// Purely for outside inspection of the tree.\nexport type FlattenedTreeNode = {\n id: string;\n type: string;\n caption: string;\n state: AnyState;\n guards: GuardAttributeDetails[];\n callbacks: CallbackAttributeDetails[];\n args: AnyArgument[];\n parentId: string | null;\n};\n\n/**\n * A representation of a behaviour tree.\n */\nexport class BehaviourTree {\n /**\n * The main root tree node.\n */\n public readonly rootNode: Root;\n\n /**\n * Creates a new instance of the BehaviourTree class.\n * @param definition The behaviour tree definition.\n * @param agent The agent instance that this behaviour tree is modelling behaviour for.\n * @param options The behaviour tree options object.\n */\n constructor(definition: string, private agent: Agent, private options: BehaviourTreeOptions = {}) {\n // The tree definition must be defined and a valid string.\n if (typeof definition !== \"string\") {\n throw new Error(\"the tree definition must be a string\");\n }\n\n // The agent must be defined and not null.\n if (typeof agent !== \"object\" || agent === null) {\n throw new Error(\"the agent must be defined and not null\");\n }\n\n // Parse the behaviour tree definition, create the populated tree of behaviour tree nodes, and get the root.\n this.rootNode = BehaviourTree.createRootNode(definition);\n }\n\n /**\n * Gets whether the tree is in the RUNNING state.\n * @returns true if the tree is in the RUNNING state, otherwise false.\n */\n isRunning() {\n return this.rootNode.getState() === State.RUNNING;\n }\n\n /**\n * Gets the current tree state of SUCCEEDED, FAILED, READY or RUNNING.\n * @returns The current tree state.\n */\n getState() {\n return this.rootNode.getState();\n }\n\n /**\n * Step the tree.\n * 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.\n * 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\n * 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.\n *\n * 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.\n */\n step() {\n // If the root node has already been stepped to completion then we need to reset it.\n if (this.rootNode.getState() === State.SUCCEEDED || this.rootNode.getState() === State.FAILED) {\n this.rootNode.reset();\n }\n\n try {\n this.rootNode.update(this.agent, this.options);\n } catch (exception) {\n throw new Error(`error stepping tree: ${(exception as Error).message}`);\n }\n }\n\n /**\n * Resets the tree from the root node outwards to each nested node, giving each a state of READY.\n */\n reset() {\n this.rootNode.reset();\n }\n\n /**\n * Gets the flattened details of every node in the tree.\n * @returns The flattened details of every node in the tree.\n */\n getFlattenedNodeDetails(): FlattenedTreeNode[] {\n // Create an empty flattened array of tree nodes.\n const flattenedTreeNodes: FlattenedTreeNode[] = [];\n\n /**\n * Helper function to process a node instance and push details into the flattened tree nodes array.\n * @param node The current node.\n * @param parentUid The UID of the node parent, or null if the node is the main root node.\n */\n const processNode = (node: Node, parentUid: string | null) => {\n // Get the guard and callback attribute details for this node.\n const guards = node\n .getAttributes()\n .filter((attribute) => attribute.isGuard())\n .map((attribute) => attribute.getDetails()) as GuardAttributeDetails[];\n const callbacks = node\n .getAttributes()\n .filter((attribute) => !attribute.isGuard())\n .map((attribute) => attribute.getDetails()) as CallbackAttributeDetails[];\n\n // Push the current node into the flattened nodes array.\n flattenedTreeNodes.push({\n id: node.getUid(),\n type: node.getType(),\n caption: node.getName(),\n state: node.getState(),\n guards,\n callbacks,\n args: node.getArguments(),\n parentId: parentUid\n });\n\n // Process each of the nodes children if it is not a leaf node.\n if (!node.isLeafNode()) {\n (node as Composite | Decorator)\n .getChildren()\n .forEach((child) => processNode(child, (node as Composite | Decorator).getUid()));\n }\n };\n\n // Convert the nested node structure into a flattened array of node details.\n processNode(this.rootNode, null);\n\n return flattenedTreeNodes;\n }\n\n /**\n * Registers the action/condition/guard/callback function or subtree with the given name.\n * @param name The name of the function or subtree to register.\n * @param value The function or subtree definition to register.\n */\n static register(name: string, value: GlobalFunction | string) {\n if (typeof value === \"function\") {\n // We are going to register a action/condition/guard/callback function.\n Lookup.setFunc(name, value);\n } else if (typeof value === \"string\") {\n // We are going to register a subtree.\n let rootASTNodes: RootAstNode[];\n\n try {\n // Try to create the behaviour tree AST based on the definition provided, this could fail if the definition is invalid.\n rootASTNodes = buildRootASTNodes(value);\n } catch (exception) {\n // There was an issue in trying to parse and build the tree definition.\n throw new Error(`error registering definition: ${(exception as Error).message}`);\n }\n\n // This function should only ever be called with a definition containing a single unnamed root node.\n if (rootASTNodes.length != 1 || rootASTNodes[0].name !== null) {\n throw new Error(\"error registering definition: expected a single unnamed root node\");\n }\n\n Lookup.setSubtree(name, rootASTNodes[0]);\n } else {\n throw new Error(\"unexpected value, expected string definition or function\");\n }\n }\n\n /**\n * Unregisters the registered action/condition/guard/callback function or subtree with the given name.\n * @param name The name of the registered action/condition/guard/callback function or subtree to unregister.\n */\n static unregister(name: string): void {\n Lookup.remove(name);\n }\n\n /**\n * Unregister all registered action/condition/guard/callback functions and subtrees.\n */\n static unregisterAll(): void {\n Lookup.empty();\n }\n\n /**\n * Parses a behaviour tree definition and creates a tree of behaviour tree nodes.\n * @param {string} definition The behaviour tree definition.\n * @returns The root behaviour tree node.\n */\n private static createRootNode(definition: string): Root {\n // TODO Remove!\n try {\n parseToJSON(definition);\n } catch (exception) {\n console.log(exception);\n }\n\n try {\n // Try to create the behaviour tree AST based on the definition provided, this could fail if the definition is invalid.\n const rootASTNodes = buildRootASTNodes(definition);\n\n // Create a symbol to use as the main root key in our root node mapping.\n const mainRootNodeKey = Symbol(\"__root__\");\n\n // Create a mapping of root node names to root AST tokens. The main root node will have a key of Symbol(\"__root__\").\n const rootNodeMap: { [key: string | symbol]: RootAstNode } = {};\n for (const rootASTNode of rootASTNodes) {\n rootNodeMap[rootASTNode.name === null ? mainRootNodeKey : rootASTNode.name!] = rootASTNode;\n }\n\n // Convert the AST to our actual tree and get the root node.\n const rootNode: Root = rootNodeMap[mainRootNodeKey].createNodeInstance(\n // Create a provider for named root nodes that are part of our definition or have been registered. Prioritising the former.\n (name: string): RootAstNode => (rootNodeMap[name] ? rootNodeMap[name] : Lookup.getSubtree(name)),\n []\n );\n\n // Set a guard path on every leaf of the tree to evaluate as part of its update.\n BehaviourTree.applyLeafNodeGuardPaths(rootNode);\n\n // Return the root node.\n return rootNode;\n } catch (exception) {\n // There was an issue in trying to parse and build the tree definition.\n throw new Error(`error parsing tree: ${(exception as Error).message}\\n${(exception as Error).stack}`);\n }\n }\n\n /**\n * Applies a guard path to every leaf of the tree to evaluate as part of each update.\n * @param rootNode The main root tree node.\n */\n private static applyLeafNodeGuardPaths(rootNode: Root) {\n const nodePaths: Node[][] = [];\n\n const findLeafNodes = (path: Node[], node: Node) => {\n // Add the current node to the path.\n path = path.concat(node);\n\n // Check whether the current node is a leaf node.\n if (node.isLeafNode()) {\n nodePaths.push(path);\n } else {\n (node as Composite | Decorator).getChildren().forEach((child) => findLeafNodes(path, child));\n }\n };\n\n // Find all leaf node paths, starting from the root.\n findLeafNodes([], rootNode);\n\n nodePaths.forEach((path) => {\n // Each node in the current path will have to be assigned a guard path, working from the root outwards.\n for (let depth = 0; depth < path.length; depth++) {\n // Get the node in the path at the current depth.\n const currentNode = path[depth];\n\n // The node may already have been assigned a guard path, if so just skip it.\n if (currentNode.hasGuardPath()) {\n continue;\n }\n\n // Create the guard path for the current node.\n const guardPath = new GuardPath(\n path\n .slice(0, depth + 1)\n .map((node) => ({ node, guards: node.getGuardAttributes() }))\n .filter((details) => details.guards.length > 0)\n );\n\n // Assign the guard path to the current node.\n currentNode.setGuardPath(guardPath);\n }\n });\n }\n}\n"], - "mappings": "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", - "names": ["Participant", "Lotto", "createLotto", "State", "createLotto", "substituteStringLiterals", "parseTokensFromDefinition", "popAndCheck"] + "sources": ["../node_modules/lotto-draw/dist/Participant.js", "../node_modules/lotto-draw/dist/Utilities.js", "../node_modules/lotto-draw/dist/Lotto.js", "../node_modules/lotto-draw/dist/createLotto.js", "../node_modules/lotto-draw/dist/index.js", "../src/index.ts", "../src/attributes/guards/GuardUnsatisifedException.ts", "../src/attributes/guards/GuardPath.ts", "../src/State.ts", "../src/nodes/Node.ts", "../src/nodes/leaf/Leaf.ts", "../src/Lookup.ts", "../src/nodes/leaf/Action.ts", "../src/nodes/leaf/Condition.ts", "../src/nodes/leaf/Wait.ts", "../src/nodes/decorator/Decorator.ts", "../src/nodes/decorator/Root.ts", "../src/nodes/decorator/Repeat.ts", "../src/nodes/decorator/Retry.ts", "../src/nodes/decorator/Flip.ts", "../src/nodes/decorator/Succeed.ts", "../src/nodes/decorator/Fail.ts", "../src/nodes/composite/Lotto.ts", "../src/nodes/composite/Composite.ts", "../src/nodes/composite/Selector.ts", "../src/nodes/composite/Sequence.ts", "../src/nodes/composite/Parallel.ts", "../src/attributes/Attribute.ts", "../src/attributes/guards/Guard.ts", "../src/attributes/guards/While.ts", "../src/attributes/guards/Until.ts", "../src/attributes/callbacks/Callback.ts", "../src/attributes/callbacks/Entry.ts", "../src/attributes/callbacks/Exit.ts", "../src/attributes/callbacks/Step.ts", "../src/RootAstNodesBuilder.ts", "../src/dsl/DSLUtilities.ts", "../src/dsl/DSLDefinitionParser.ts", "../src/BehaviourTree.ts"], + "sourcesContent": ["\"use strict\";\r\nObject.defineProperty(exports, \"__esModule\", { value: true });\r\nexports.Participant = void 0;\r\n/**\r\n * A participant that holds a number of tickets.\r\n */\r\nvar Participant = /** @class */ (function () {\r\n /**\r\n * Creates an instance of the Participant class.\r\n * @param participant The actual participant.\r\n * @param tickets The number of tickets held by the participant.\r\n */\r\n function Participant(participant, tickets) {\r\n if (tickets === void 0) { tickets = 1; }\r\n this._participant = participant;\r\n this._tickets = tickets;\r\n }\r\n Object.defineProperty(Participant.prototype, \"participant\", {\r\n /** Gets the actual participant. */\r\n get: function () {\r\n return this._participant;\r\n },\r\n enumerable: false,\r\n configurable: true\r\n });\r\n Object.defineProperty(Participant.prototype, \"tickets\", {\r\n /** Gets or sets the number of tickets held by the participant. */\r\n get: function () {\r\n return this._tickets;\r\n },\r\n set: function (value) {\r\n this._tickets = value;\r\n },\r\n enumerable: false,\r\n configurable: true\r\n });\r\n return Participant;\r\n}());\r\nexports.Participant = Participant;\r\n", "\"use strict\";\r\nObject.defineProperty(exports, \"__esModule\", { value: true });\r\nexports.isNaturalNumber = exports.isNullOrUndefined = void 0;\r\n/**\r\n * Gets whether the value provided is null or undefined.\r\n * @param value The value to check.\r\n * @returns Whether the value provided is null or undefined.\r\n */\r\nfunction isNullOrUndefined(value) {\r\n return value === null || value === undefined;\r\n}\r\nexports.isNullOrUndefined = isNullOrUndefined;\r\n/**\r\n * Gets whether the value provided is a natural number.\r\n * @param value The value to check.\r\n * @returns Whether the value provided is a natural number.\r\n */\r\nfunction isNaturalNumber(value) {\r\n return typeof value === \"number\" && value >= 1 && Math.floor(value) === value;\r\n}\r\nexports.isNaturalNumber = isNaturalNumber;\r\n", "\"use strict\";\r\nObject.defineProperty(exports, \"__esModule\", { value: true });\r\nexports.Lotto = void 0;\r\nvar Participant_1 = require(\"./Participant\");\r\nvar Utilities_1 = require(\"./Utilities\");\r\n/**\r\n * Represents a lotto consisting of a number of pickable ticket-holding participants.\r\n */\r\nvar Lotto = /** @class */ (function () {\r\n /**\r\n * Creates a new instance of Lotto.\r\n * @param customRandom The custom RNG to use in place of Math.random().\r\n */\r\n function Lotto(customRandom) {\r\n /** The array of participants that are holding tickets in the lotto. */\r\n this._participants = [];\r\n this._customRandom = customRandom;\r\n }\r\n /**\r\n * Adds a participant with the specified number of tickets, or adds to the participant ticket count if the participant already holds tickets.\r\n * @param participant The participant to add or to increase the ticket count for if they already hold tickets.\r\n * @param tickets The number of tickets, defaults to 1.\r\n * @returns The Lotto instance.\r\n */\r\n Lotto.prototype.add = function (participant, tickets) {\r\n if (tickets === void 0) { tickets = 1; }\r\n // Check that we have a valid ticket count.\r\n if (!(0, Utilities_1.isNaturalNumber)(tickets)) {\r\n throw new Error(\"tickets value must be a natural number\");\r\n }\r\n // Check whether this participant has already been added.\r\n var existingParticipant = this._participants.find(function (part) { return part.participant === participant; });\r\n if (existingParticipant) {\r\n // The participant has already been added to the lotto so just add to their ticket count.\r\n existingParticipant.tickets += tickets;\r\n }\r\n else {\r\n // The participant is not part of the lotto so we should add them.\r\n this._participants.push(new Participant_1.Participant(participant, tickets));\r\n }\r\n return this;\r\n };\r\n /**\r\n * Removes the specified number of tickets for the given participant from the draw, or all tickets if a ticket number is not defined.\r\n * @param participant The participant to remove tickets for.\r\n * @param tickets The number of tickets to remove, or undefined if all tickets are to be removed.\r\n * @returns The Lotto instance.\r\n */\r\n Lotto.prototype.remove = function (participant, tickets) {\r\n // Attempt to get the existing participant.\r\n var existingParticipant = this._participants.find(function (part) { return part.participant === participant; });\r\n // There is nothing to do if the specified participant isn't even part of the lotto.\r\n if (!existingParticipant) {\r\n return this;\r\n }\r\n // Check whether a tickets value was given.\r\n if (tickets !== undefined) {\r\n // Check that we have a valid ticket count.\r\n if (!(0, Utilities_1.isNaturalNumber)(tickets)) {\r\n throw new Error(\"tickets value must be a natural number\");\r\n }\r\n existingParticipant.tickets -= tickets;\r\n // If the participant no longer holds any tickets then they should be removed.\r\n if (existingParticipant.tickets < 1) {\r\n this._participants = this._participants.filter(function (part) { return part !== existingParticipant; });\r\n }\r\n }\r\n else {\r\n // We are removing all tickets for the participant so just remove them from the lotto.\r\n this._participants = this._participants.filter(function (part) { return part !== existingParticipant; });\r\n }\r\n return this;\r\n };\r\n /**\r\n * Draw a winning ticket and return the participant that holds the ticket.\r\n * @param options The draw options.\r\n * @returns The participant that holds the winning ticket.\r\n */\r\n Lotto.prototype.draw = function (options) {\r\n if (options === void 0) { options = {}; }\r\n // If we have no participants then just return null.\r\n if (this._participants.length === 0) {\r\n return null;\r\n }\r\n var redrawable = (0, Utilities_1.isNullOrUndefined)(options.redrawable) ? true : options.redrawable;\r\n var pickable = [];\r\n this._participants.forEach(function (_a) {\r\n var participant = _a.participant, tickets = _a.tickets;\r\n for (var ticketCount = 0; ticketCount < tickets; ticketCount++) {\r\n pickable.push(participant);\r\n }\r\n });\r\n var random;\r\n // We need a random floating-point number between 0 (inclusive) and 1 to scale up to pick our winner.\r\n // If a custom random function exists then we should use that or fall back to Math.random().\r\n if (this._customRandom) {\r\n // Call our custom random function to get a random floating-point number.\r\n random = this._customRandom();\r\n // Verify that the result of calling our custom random function is a number between 0 (inclusive) and 1.\r\n if (typeof random !== \"number\" || random < 0 || random >= 1) {\r\n throw new Error(\"the 'random' function provided did not return a number between 0 (inclusive) and 1\");\r\n }\r\n }\r\n else {\r\n // No custom random function was defined so just use good ol' Math.random().\r\n random = Math.random();\r\n }\r\n // Pick a winning participant.\r\n var winner = pickable[Math.floor(random * pickable.length)];\r\n // If the ticket isn't redrawable then we should remove a ticket from the winning participants ticket count.\r\n if (!redrawable) {\r\n this.remove(winner, 1);\r\n }\r\n // Return the winning participant.\r\n return winner;\r\n };\r\n /**\r\n * Draws multiple winning tickets and return an array of the participants that hold the winning tickets.\r\n * @param tickets The number of winning tickets to draw.\r\n * @param options The draw multiple options.\r\n * @returns An array of the participants that hold the winning tickets.\r\n */\r\n Lotto.prototype.drawMultiple = function (tickets, options) {\r\n if (options === void 0) { options = {}; }\r\n var uniqueResults = (0, Utilities_1.isNullOrUndefined)(options.unique) ? false : options.unique;\r\n // Handle cases where the user has asked for zero tickets (no idea why they would do this be we should trust them).\r\n if (tickets === 0) {\r\n return [];\r\n }\r\n // Now that we know out tickets value is not zero we should check that it is a valid natural number.\r\n if (!(0, Utilities_1.isNaturalNumber)(tickets)) {\r\n throw new Error(\"tickets value must be a natural number\");\r\n }\r\n var result = [];\r\n // Keep drawing tickets until we either reach the number of required tickets or we simply run out of tickets to draw.\r\n // We can run out of tickets to draw if 'options.redrawable' is explicity 'false' or we just had no participants when 'drawMultiple' was called.\r\n while (result.length < tickets && this._participants.length > 0) {\r\n result.push(this.draw(options));\r\n }\r\n // If the 'unique' draw option is set then we need to remove duplicates from the result list.\r\n if (uniqueResults) {\r\n // Create an array to store our unique results.\r\n var unique = [];\r\n // Iterate over all of our participants (with potential duplicates) and populate our array of unique values.\r\n for (var _i = 0, result_1 = result; _i < result_1.length; _i++) {\r\n var participant = result_1[_i];\r\n if (unique.indexOf(participant) === -1) {\r\n unique.push(participant);\r\n }\r\n }\r\n result = unique;\r\n }\r\n return result;\r\n };\r\n return Lotto;\r\n}());\r\nexports.Lotto = Lotto;\r\n", "\"use strict\";\r\nObject.defineProperty(exports, \"__esModule\", { value: true });\r\nexports.createLotto = void 0;\r\nvar Lotto_1 = require(\"./Lotto\");\r\n/**\r\n * A function that creates and returns a Lotto instance.\r\n * @param participantsOrOptions An array of initial participants or options relating to the creation of a Lotto instance.\r\n * @returns A new Lotto instance.\r\n */\r\nfunction createLotto(participantsOrOptions) {\r\n // If no initial participants or lotto options were provided as an argument then we can just return a new lotto instance now.\r\n if (!participantsOrOptions) {\r\n return new Lotto_1.Lotto();\r\n }\r\n // Check whether we were provided with an array of initial participants or a lotto options object.\r\n if (Array.isArray(participantsOrOptions)) {\r\n // We are dealing with a pre-defined array of participants.\r\n var participants = participantsOrOptions;\r\n var lotto_1 = new Lotto_1.Lotto();\r\n // If the lotto participants have been defined upfront then we will need to add them all to our lotto instance now.\r\n participants.forEach(function (_a) {\r\n var participant = _a[0], tokens = _a[1];\r\n return lotto_1.add(participant, tokens);\r\n });\r\n // Return the Lotto instance.\r\n return lotto_1;\r\n }\r\n else {\r\n // We are dealing with some lotto options.\r\n var random = participantsOrOptions.random, participants = participantsOrOptions.participants;\r\n // Create a Lotto instance passing the custom RNG function to use in place of Math.random() (which could be undefined).\r\n var lotto_2 = new Lotto_1.Lotto(random);\r\n // If the lotto participants have been defined upfront as part of the options then we will need to add them all to our lotto instance now.\r\n if (participants) {\r\n participants.forEach(function (_a) {\r\n var participant = _a[0], tokens = _a[1];\r\n return lotto_2.add(participant, tokens);\r\n });\r\n }\r\n // Return the Lotto instance.\r\n return lotto_2;\r\n }\r\n}\r\nexports.createLotto = createLotto;\r\n", "\"use strict\";\r\nObject.defineProperty(exports, \"__esModule\", { value: true });\r\nvar createLotto_1 = require(\"./createLotto\");\r\nexports.default = createLotto_1.createLotto;\r\n", "import { BehaviourTree, FlattenedTreeNode } from \"./BehaviourTree\";\nimport State from \"./State\";\n\nexport { BehaviourTree, State };\nexport type { FlattenedTreeNode };\n", "import Node from \"../../nodes/Node\";\n\n/**\n * An exception thrown when evaluating node guard path conditions and a conditions fails.\n */\nexport default class GuardUnsatisifedException extends Error {\n /**\n * @param source The node at which a guard condition failed.\n */\n constructor(private source: Node) {\n super(\"A guard path condition has failed\");\n }\n\n /**\n * Gets whether the specified node is the node at which a guard condition failed.\n * @param node The node to check against the source node.\n * @returns Whether the specified node is the node at which a guard condition failed.\n */\n isSourceNode = (node: Node) => node === this.source;\n}\n", "import { Agent } from \"../../Agent\";\nimport Guard from \"./Guard\";\nimport Node from \"../../nodes/Node\";\nimport GuardUnsatisifedException from \"./GuardUnsatisifedException\";\n\nexport type GuardPathPart = {\n node: Node;\n guards: Guard[];\n};\n\n/**\n * Represents a path of node guards along a root-to-leaf tree path.\n */\nexport default class GuardPath {\n /**\n * @param nodes An array of objects defining a node instance -> guard link, ordered by node depth.\n */\n constructor(private nodes: GuardPathPart[]) {}\n\n /**\n * Evaluate guard conditions for all guards in the tree path, moving outwards from the root.\n * @param agent The agent, required for guard evaluation.\n * @returns An evaluation results object.\n */\n evaluate = (agent: Agent) => {\n // We need to evaluate guard conditions for nodes up the tree, moving outwards from the root.\n for (const details of this.nodes) {\n // There can be multiple guards per node.\n for (const guard of details.guards) {\n // Check whether the guard condition passes, and throw an exception if not.\n if (!guard.isSatisfied(agent)) {\n throw new GuardUnsatisifedException(details.node);\n }\n }\n }\n };\n}\n", "/**\n * Enumeration of node state types.\n */\nexport enum State {\n READY = \"mistreevous.ready\",\n RUNNING = \"mistreevous.running\",\n SUCCEEDED = \"mistreevous.succeeded\",\n FAILED = \"mistreevous.failed\"\n}\n\nexport { State as default };\n\nexport type CompleteState = State.SUCCEEDED | State.FAILED;\nexport type AnyState = State.READY | State.RUNNING | CompleteState;\n", "import { Agent } from \"../Agent\";\nimport Attribute from \"../attributes/Attribute\";\nimport Entry from \"../attributes/callbacks/Entry\";\nimport Exit from \"../attributes/callbacks/Exit\";\nimport Step from \"../attributes/callbacks/Step\";\nimport Guard from \"../attributes/guards/Guard\";\nimport GuardPath from \"../attributes/guards/GuardPath\";\nimport GuardUnsatisifedException from \"../attributes/guards/GuardUnsatisifedException\";\nimport { BehaviourTreeOptions } from \"../BehaviourTreeOptions\";\nimport { AnyArgument } from \"../RootAstNodesBuilder\";\nimport State, { AnyState } from \"../State\";\nimport Leaf from \"./leaf/Leaf\";\n\n/**\n * A base node.\n */\nexport default abstract class Node {\n /**\n * The node uid.\n */\n private readonly uid: string = createNodeUid();\n /**\n * The node state.\n */\n private state: AnyState = State.READY;\n /**\n * The guard path to evaluate as part of a node update.\n */\n private guardPath: GuardPath | undefined;\n\n /**\n * @param type The node type.\n * @param attributes The node attributes.\n * @param args The node argument definitions.\n */\n constructor(private type: string, private attributes: Attribute[], private args: AnyArgument[]) {}\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected abstract onUpdate(agent: Agent, options: BehaviourTreeOptions): void;\n\n /**\n * Gets the name of the node.\n */\n public abstract getName(): string;\n\n /**\n * Gets whether this node is a leaf node.\n */\n public abstract isLeafNode: () => this is Leaf;\n\n /**\n * Gets/Sets the state of the node.\n */\n getState = (): AnyState => this.state;\n setState = (value: AnyState): void => {\n this.state = value;\n };\n\n /**\n * Gets the unique id of the node.\n */\n getUid = () => this.uid;\n\n /**\n * Gets the type of the node.\n */\n getType = () => this.type;\n\n /**\n * Gets the node attributes.\n */\n getAttributes = () => this.attributes;\n\n /**\n * Gets the node arguments.\n */\n getArguments = () => this.args;\n\n /**\n * Gets the node attribute with the specified type, or null if it does not exist.\n */\n getAttribute(type: \"entry\" | \"ENTRY\"): Entry;\n getAttribute(type: \"exit\" | \"EXIT\"): Exit;\n getAttribute(type: \"step\" | \"STEP\"): Step;\n getAttribute(type: string): Attribute {\n return (\n this.getAttributes().filter((decorator) => decorator.getType().toUpperCase() === type.toUpperCase())[0] ||\n null\n );\n }\n\n /**\n * Gets the node attributes.\n */\n getGuardAttributes = (): Guard[] => this.getAttributes().filter((decorator) => decorator.isGuard()) as Guard[];\n\n /**\n * Sets the guard path to evaluate as part of a node update.\n */\n setGuardPath = (value: GuardPath) => (this.guardPath = value);\n\n /**\n * Gets whether a guard path is assigned to this node.\n */\n hasGuardPath = () => !!this.guardPath;\n\n /**\n * Gets whether this node is in the specified state.\n * @param value The value to compare to the node state.\n */\n public is(value: AnyState): boolean {\n return this.state === value;\n }\n\n /**\n * Reset the state of the node.\n */\n public reset(): void {\n this.setState(State.READY);\n }\n\n /**\n * Abort the running of this node.\n * @param agent The agent.\n */\n public abort(agent: Agent): void {\n // There is nothing to do if this node is not in the running state.\n if (!this.is(State.RUNNING)) {\n return;\n }\n\n // Reset the state of this node.\n this.reset();\n\n this.getAttribute(\"exit\")?.callAgentFunction(agent, false, true);\n }\n\n /**\n * Update the node.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n * @returns The result of the update.\n */\n public update(agent: Agent, options: BehaviourTreeOptions): void {\n // If this node is already in a 'SUCCEEDED' or 'FAILED' state then there is nothing to do.\n if (this.is(State.SUCCEEDED) || this.is(State.FAILED)) {\n return;\n }\n\n try {\n // Evaluate all of the guard path conditions for the current tree path.\n this.guardPath!.evaluate(agent);\n\n // If this node is in the READY state then call the ENTRY for this node if it exists.\n if (this.is(State.READY)) {\n this.getAttribute(\"entry\")?.callAgentFunction(agent);\n }\n\n this.getAttribute(\"step\")?.callAgentFunction(agent);\n\n // Do the actual update.\n this.onUpdate(agent, options);\n\n // If this node is now in a 'SUCCEEDED' or 'FAILED' state then call the EXIT for this node if it exists.\n if (this.is(State.SUCCEEDED) || this.is(State.FAILED)) {\n this.getAttribute(\"exit\")?.callAgentFunction(agent, this.is(State.SUCCEEDED), false);\n }\n } catch (error) {\n // If the error is a GuardUnsatisfiedException then we need to determine if this node is the source.\n if (error instanceof GuardUnsatisifedException && error.isSourceNode(this)) {\n // Abort the current node.\n this.abort(agent);\n\n // Any node that is the source of an abort will be a failed node.\n this.setState(State.FAILED);\n } else {\n throw error;\n }\n }\n }\n}\n\n/**\n * Create a randomly generated node uid.\n * @returns A randomly generated node uid.\n */\nfunction createNodeUid(): string {\n var S4 = function () {\n return (((1 + Math.random()) * 0x10000) | 0).toString(16).substring(1);\n };\n return S4() + S4() + \"-\" + S4() + \"-\" + S4() + \"-\" + S4() + \"-\" + S4() + S4() + S4();\n}\n", "import Node from \"../Node\";\n\n/**\n * A leaf node.\n */\nexport default abstract class Leaf extends Node {\n /**\n * Gets whether this node is a leaf node.\n */\n isLeafNode = () => true;\n}\n", "import { ActionResult, Agent, ExitFunctionArg, FunctionArg, GlobalFunction } from \"./Agent\";\nimport { AnyArgument, RootAstNode } from \"./RootAstNodesBuilder\";\n\n// Exit callbacks receive their own special type of argument.\n// There's probably stricter ways to represent this but it feels overly complex right now.\ntype ExitResultArg = { value: ExitFunctionArg };\nexport type AnyExitArgument = AnyArgument | ExitResultArg;\n\nexport type InvokerFunction = (args: AnyExitArgument[]) => ActionResult;\n\n/**\n * A singleton used to store and lookup registered functions and subtrees.\n */\nexport default class Lookup {\n /**\n * The object holding any registered functions keyed on function name.\n */\n private static functionTable: { [key: string]: GlobalFunction } = {};\n /**\n * The object holding any registered sub-trees keyed on tree name.\n */\n private static subtreeTable: { [key: string]: RootAstNode } = {};\n\n /**\n * Gets the function with the specified name.\n * @param name The name of the function.\n * @returns The function with the specified name.\n */\n public static getFunc(name: string): GlobalFunction {\n return this.functionTable[name];\n }\n\n /**\n * Sets the function with the specified name for later lookup.\n * @param name The name of the function.\n * @param func The function.\n */\n public static setFunc(name: string, func: GlobalFunction): void {\n this.functionTable[name] = func;\n }\n\n /**\n * Gets the function invoker for the specified agent and function name.\n * If a function with the specified name exists on the agent object then it will\n * be returned, otherwise we will then check the registered functions for a match.\n * @param agent The agent instance that this behaviour tree is modelling behaviour for.\n * @param name The function name.\n * @returns The function invoker for the specified agent and function name.\n */\n static getFuncInvoker(agent: Agent, name: string): InvokerFunction | null {\n // Check whether the agent contains the specified function.\n const foundOnAgent = agent[name];\n if (foundOnAgent && typeof foundOnAgent === \"function\") {\n return (args: AnyExitArgument[]): boolean | ActionResult =>\n foundOnAgent.apply(\n agent,\n args.map((arg) => arg.value)\n );\n }\n\n // The agent does not contain the specified function but it may have been registered at some point.\n if (this.functionTable[name] && typeof this.functionTable[name] === \"function\") {\n return (args: AnyExitArgument[]) => this.functionTable[name](agent, ...args.map((arg) => arg.value));\n }\n\n // We have no function to invoke.\n return null;\n }\n\n /**\n * Gets the subtree with the specified name.\n * @param name The name of the subtree.\n * @returns The subtree with the specified name.\n */\n static getSubtree(name: string): RootAstNode {\n return this.subtreeTable[name];\n }\n\n /**\n * Sets the subtree with the specified name for later lookup.\n * @param name The name of the subtree.\n * @param subtree The subtree.\n */\n static setSubtree(name: string, subtree: RootAstNode) {\n this.subtreeTable[name] = subtree;\n }\n\n /**\n * Removes the registered function or subtree with the specified name.\n * @param name The name of the registered function or subtree.\n */\n static remove(name: string) {\n delete this.functionTable[name];\n delete this.subtreeTable[name];\n }\n\n /**\n * Remove all registered functions and subtrees.\n */\n static empty() {\n this.functionTable = {};\n this.subtreeTable = {};\n }\n}\n", "import Leaf from \"./Leaf\";\nimport State, { CompleteState } from \"../../State\";\nimport Lookup from \"../../Lookup\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { AnyArgument } from \"../../RootAstNodesBuilder\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * An Action leaf node.\n * This represents an immediate or ongoing state of behaviour.\n */\nexport default class Action extends Leaf {\n /**\n * @param attributes The node attributes.\n * @param actionName The action name.\n * @param actionArguments The array of action argument definitions.\n */\n constructor(attributes: Attribute[], private actionName: string, private actionArguments: AnyArgument[]) {\n super(\"action\", attributes, actionArguments);\n }\n\n /**\n * Whether there is a pending update promise.\n */\n private isUsingUpdatePromise = false;\n\n /**\n * The finished state result of an update promise.\n */\n private updatePromiseStateResult: CompleteState | null = null;\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // If the result of this action depends on an update promise then there is nothing to do until\n // it resolves, unless there has been a value set as a result of the update promise resolving.\n if (this.isUsingUpdatePromise) {\n // Check whether the update promise has resolved with a state value.\n if (this.updatePromiseStateResult) {\n // Set the state of this node to match the state returned by the promise.\n this.setState(this.updatePromiseStateResult);\n }\n\n return;\n }\n\n // Attempt to get the invoker for the action function.\n const actionFuncInvoker = Lookup.getFuncInvoker(agent, this.actionName);\n\n // The action function should be defined.\n if (actionFuncInvoker === null) {\n throw new Error(\n `cannot update action node as the action '${this.actionName}' function is not defined on the agent and has not been registered`\n );\n }\n\n // Call the action function, the result of which may be:\n // - The finished state of this action node.\n // - A promise to return a finished node state.\n // - Undefined if the node should remain in the running state.\n const updateResult = actionFuncInvoker(this.actionArguments) as CompleteState | Promise;\n\n if (updateResult instanceof Promise) {\n updateResult.then(\n (result) => {\n // If 'isUpdatePromisePending' is null then the promise was cleared as it was resolving, probably via an abort of reset.\n if (!this.isUsingUpdatePromise) {\n return;\n }\n\n // Check to make sure the result is a valid finished state.\n if (result !== State.SUCCEEDED && result !== State.FAILED) {\n throw new Error(\n \"action node promise resolved with an invalid value, expected a State.SUCCEEDED or State.FAILED value to be returned\"\n );\n }\n\n // Set pending update promise state result to be processed on next update.\n this.updatePromiseStateResult = result;\n },\n (reason) => {\n // If 'isUpdatePromisePending' is null then the promise was cleared as it was resolving, probably via an abort of reset.\n if (!this.isUsingUpdatePromise) {\n return;\n }\n\n // Just throw whatever was returned as the rejection argument.\n throw new Error(reason);\n }\n );\n\n // This node will be in the 'RUNNING' state until the update promise resolves.\n this.setState(State.RUNNING);\n\n // We are now waiting for the promise returned by the use to resolve before we know what state this node is in.\n this.isUsingUpdatePromise = true;\n } else {\n // Validate the returned value.\n this.validateUpdateResult(updateResult);\n\n // Set the state of this node, this may be undefined, which just means that the node is still in the 'RUNNING' state.\n this.setState(updateResult || State.RUNNING);\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => this.actionName;\n\n /**\n * Reset the state of the node.\n */\n reset = () => {\n // Reset the state of this node.\n this.setState(State.READY);\n\n // There is no longer an update promise that we care about.\n this.isUsingUpdatePromise = false;\n this.updatePromiseStateResult = null;\n };\n\n /**\n * Validate the result of an update function call.\n * @param result The result of an update function call.\n */\n private validateUpdateResult = (result: CompleteState | boolean) => {\n switch (result) {\n case State.SUCCEEDED:\n case State.FAILED:\n case undefined:\n return;\n default:\n throw new Error(\n `action '${this.actionName}' 'onUpdate' returned an invalid response, expected an optional State.SUCCEEDED or State.FAILED value to be returned`\n );\n }\n };\n}\n", "import Leaf from \"./Leaf\";\nimport State from \"../../State\";\nimport Lookup from \"../../Lookup\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { AnyArgument } from \"../../RootAstNodesBuilder\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A Condition leaf node.\n * This will succeed or fail immediately based on an agent predicate, without moving to the 'RUNNING' state.\n */\nexport default class Condition extends Leaf {\n /**\n * @param attributes The node attributes.\n * @param conditionName The name of the condition function.\n * @param conditionArguments The array of condition argument definitions.\n */\n constructor(attributes: Attribute[], private conditionName: string, private conditionArguments: AnyArgument[]) {\n super(\"condition\", attributes, conditionArguments);\n }\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // Attempt to get the invoker for the condition function.\n const conditionFuncInvoker = Lookup.getFuncInvoker(agent, this.conditionName);\n\n // The condition function should be defined.\n if (conditionFuncInvoker === null) {\n throw new Error(\n `cannot update condition node as the condition '${this.conditionName}' function is not defined on the agent and has not been registered`\n );\n }\n\n // Call the condition function to determine the state of this node.\n this.setState(!!conditionFuncInvoker(this.conditionArguments) ? State.SUCCEEDED : State.FAILED);\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => this.conditionName;\n}\n", "import Leaf from \"./Leaf\";\nimport State from \"../../State\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { Agent } from \"../../Agent\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A WAIT node.\n * The state of this node will change to SUCCEEDED after a duration of time\n */\nexport default class Wait extends Leaf {\n /**\n * @param attributes The node attributes.\n * @param duration The duration that this node will wait to succeed in milliseconds, or the earliest if longestDuration is defined.\n * @param longestDuration The longest possible duration in milliseconds that this node will wait to succeed.\n */\n constructor(attributes: Attribute[], private duration: number, private longestDuration: number) {\n super(\"wait\", attributes, []);\n }\n\n /**\n * The time in milliseconds at which this node was first updated.\n */\n private initialUpdateTime: number = 0;\n\n /**\n * The total duration in milliseconds that this node will be waiting for.\n */\n private totalDuration: number = 0;\n\n /**\n * The duration in milliseconds that this node has been waiting for.\n */\n private waitedDuration: number = 0;\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // If this node is in the READY state then we need to set the initial update time.\n if (this.is(State.READY)) {\n // Set the initial update time.\n this.initialUpdateTime = new Date().getTime();\n\n // Set the initial waited duration.\n this.waitedDuration = 0;\n\n // If a longestDuration value was defined then we will be randomly picking a duration between the\n // shortest and longest duration. If it was not defined, then we will be just using the duration.\n this.totalDuration = this.longestDuration\n ? Math.floor(Math.random() * (this.longestDuration - this.duration + 1) + this.duration)\n : this.duration;\n\n // The node is now running until we finish waiting.\n this.setState(State.RUNNING);\n }\n\n // If we have a 'getDeltaTime' function defined as part of our options then we will use it to figure out how long we have waited for.\n if (typeof options.getDeltaTime === \"function\") {\n // Get the delta time.\n const deltaTime = options.getDeltaTime();\n\n // Our delta time must be a valid number and cannot be NaN.\n if (typeof deltaTime !== \"number\" || isNaN(deltaTime)) {\n throw new Error(\"The delta time must be a valid number and not NaN.\");\n }\n\n // Update the amount of time that this node has been waiting for based on the delta time.\n this.waitedDuration += deltaTime * 1000;\n } else {\n // We are not using a delta time, so we will just work out hom much time has passed since the first update.\n this.waitedDuration = new Date().getTime() - this.initialUpdateTime;\n }\n\n // Have we waited long enough?\n if (this.waitedDuration >= this.totalDuration) {\n // We have finished waiting!\n this.setState(State.SUCCEEDED);\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () =>\n `WAIT ${this.longestDuration ? this.duration + \"ms-\" + this.longestDuration + \"ms\" : this.duration + \"ms\"}`;\n}\n", "import Node from \"../Node\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\n\n/**\n * A decorator node that wraps a single child node.\n */\nexport default abstract class Decorator extends Node {\n /**\n * @param type The node type.\n * @param attributes The node attributes.\n * @param child The child node.\n */\n constructor(type: string, attributes: Attribute[], protected child: Node) {\n super(type, attributes, []);\n }\n\n /**\n * Gets whether this node is a leaf node.\n */\n isLeafNode = () => false;\n\n /**\n * Gets the children of this node.\n */\n getChildren = () => [this.child];\n\n /**\n * Reset the state of the node.\n */\n reset = () => {\n // Reset the state of this node.\n this.setState(State.READY);\n\n // Reset the state of the child node.\n this.child.reset();\n };\n\n /**\n * Abort the running of this node.\n * @param agent The agent.\n */\n abort = (agent: Agent) => {\n // There is nothing to do if this node is not in the running state.\n if (!this.is(State.RUNNING)) {\n return;\n }\n\n // Abort the child node.\n this.child.abort(agent);\n\n // Reset the state of this node.\n this.reset();\n\n this.getAttribute(\"exit\")?.callAgentFunction(agent, false, true);\n };\n}\n", "import Node from \"../Node\";\nimport Decorator from \"./Decorator\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A Root node.\n * The root node will have a single child.\n */\nexport default class Root extends Decorator {\n /**\n * @param attributes The node attributes.\n * @param child The child node.\n */\n constructor(attributes: Attribute[], child: Node) {\n super(\"root\", attributes, child);\n }\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // If the child has never been updated or is running then we will need to update it now.\n if (this.child.getState() === State.READY || this.child.getState() === State.RUNNING) {\n // Update the child of this node.\n this.child.update(agent, options);\n }\n\n // The state of the root node is the state of its child.\n this.setState(this.child.getState());\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => \"ROOT\";\n}\n", "import Node from \"../Node\";\nimport Decorator from \"./Decorator\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A REPEAT node.\n * The node has a single child which can have:\n * -- A number of iterations for which to repeat the child node.\n * -- An infinite repeat loop if neither an iteration count or a condition function is defined.\n * The REPEAT node will stop and have a 'FAILED' state if its child is ever in a 'FAILED' state after an update.\n * The REPEAT node will attempt to move on to the next iteration if its child is ever in a 'SUCCEEDED' state.\n */\nexport default class Repeat extends Decorator {\n /**\n * @param attributes The node attributes.\n * @param iterations The number of iterations to repeat the child node, or the minimum number of iterations if maximumIterations is defined.\n * @param maximumIterations The maximum number of iterations to repeat the child node.\n * @param child The child node.\n */\n constructor(\n attributes: Attribute[],\n private iterations: number | null,\n private maximumIterations: number | null,\n child: Node\n ) {\n super(\"repeat\", attributes, child);\n }\n\n /**\n * The number of target iterations to make.\n */\n private targetIterationCount: number | null = null;\n\n /**\n * The current iteration count.\n */\n private currentIterationCount: number = 0;\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // If this node is in the READY state then we need to reset the child and the target iteration count.\n if (this.is(State.READY)) {\n // Reset the child node.\n this.child.reset();\n\n // Set the target iteration count.\n this.setTargetIterationCount();\n }\n\n // Do a check to see if we can iterate. If we can then this node will move into the 'RUNNING' state.\n // If we cannot iterate then we have hit our target iteration count, which means that the node has succeeded.\n if (this.canIterate()) {\n // This node is in the running state and can do its initial iteration.\n this.setState(State.RUNNING);\n\n // We may have already completed an iteration, meaning that the child node will be in the SUCCEEDED state.\n // If this is the case then we will have to reset the child node now.\n if (this.child.getState() === State.SUCCEEDED) {\n this.child.reset();\n }\n\n // Update the child of this node.\n this.child.update(agent, options);\n\n // If the child moved into the FAILED state when we updated it then there is nothing left to do and this node has also failed.\n // If it has moved into the SUCCEEDED state then we have completed the current iteration.\n if (this.child.getState() === State.FAILED) {\n // The child has failed, meaning that this node has failed.\n this.setState(State.FAILED);\n\n return;\n } else if (this.child.getState() === State.SUCCEEDED) {\n // We have completed an iteration.\n this.currentIterationCount += 1;\n }\n } else {\n // This node is in the 'SUCCEEDED' state as we cannot iterate any more.\n this.setState(State.SUCCEEDED);\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => {\n if (this.iterations !== null) {\n return `REPEAT ${\n this.maximumIterations ? this.iterations + \"x-\" + this.maximumIterations + \"x\" : this.iterations + \"x\"\n }`;\n }\n\n // Return the default repeat node name.\n return \"REPEAT\";\n };\n\n /**\n * Reset the state of the node.\n */\n reset = () => {\n // Reset the state of this node.\n this.setState(State.READY);\n\n // Reset the current iteration count.\n this.currentIterationCount = 0;\n\n // Reset the child node.\n this.child.reset();\n };\n\n /**\n * Gets whether an iteration can be made.\n * @returns Whether an iteration can be made.\n */\n private canIterate = () => {\n if (this.targetIterationCount !== null) {\n // We can iterate as long as we have not reached our target iteration count.\n return this.currentIterationCount < this.targetIterationCount;\n }\n\n // If neither an iteration count or a condition function were defined then we can iterate indefinitely.\n return true;\n };\n\n /**\n * Sets the target iteration count.\n */\n private setTargetIterationCount = () => {\n // Are we dealing with a finite number of iterations?\n if (typeof this.iterations === \"number\") {\n // If we have maximumIterations defined then we will want a random iteration count bounded by iterations and maximumIterations.\n this.targetIterationCount =\n typeof this.maximumIterations === \"number\"\n ? Math.floor(Math.random() * (this.maximumIterations - this.iterations + 1) + this.iterations)\n : this.iterations;\n } else {\n this.targetIterationCount = null;\n }\n };\n}\n", "import Node from \"../Node\";\nimport Decorator from \"./Decorator\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A RETRY node.\n * The node has a single child which can have:\n * -- A number of iterations for which to repeat the child node.\n * -- An infinite repeat loop if neither an iteration count or a condition function is defined.\n * The RETRY node will stop and have a 'SUCCEEDED' state if its child is ever in a 'SUCCEEDED' state after an update.\n * The RETRY node will attempt to move on to the next iteration if its child is ever in a 'FAILED' state.\n */\nexport default class Retry extends Decorator {\n /**\n * @param attributes The node attributes.\n * @param iterations The number of iterations to repeat the child node, or the minimum number of iterations if maximumIterations is defined.\n * @param maximumIterations The maximum number of iterations to repeat the child node.\n * @param child The child node.\n */\n constructor(\n attributes: Attribute[],\n private iterations: number | null,\n private maximumIterations: number | null,\n child: Node\n ) {\n super(\"retry\", attributes, child);\n }\n\n /**\n * The number of target iterations to make.\n */\n private targetIterationCount: number | null = null;\n\n /**\n * The current iteration count.\n */\n private currentIterationCount: number = 0;\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // If this node is in the READY state then we need to reset the child and the target iteration count.\n if (this.is(State.READY)) {\n // Reset the child node.\n this.child.reset();\n\n // Set the target iteration count.\n this.setTargetIterationCount();\n }\n\n // Do a check to see if we can iterate. If we can then this node will move into the 'RUNNING' state.\n // If we cannot iterate then we have hit our target iteration count, which means that the node has succeeded.\n if (this.canIterate()) {\n // This node is in the running state and can do its initial iteration.\n this.setState(State.RUNNING);\n\n // We may have already completed an iteration, meaning that the child node will be in the FAILED state.\n // If this is the case then we will have to reset the child node now.\n if (this.child.getState() === State.FAILED) {\n this.child.reset();\n }\n\n // Update the child of this node.\n this.child.update(agent, options);\n\n // If the child moved into the SUCCEEDED state when we updated it then there is nothing left to do and this node has also succeeded.\n // If it has moved into the FAILED state then we have completed the current iteration.\n if (this.child.getState() === State.SUCCEEDED) {\n // The child has succeeded, meaning that this node has succeeded.\n this.setState(State.SUCCEEDED);\n\n return;\n } else if (this.child.getState() === State.FAILED) {\n // We have completed an iteration.\n this.currentIterationCount += 1;\n }\n } else {\n // This node is in the 'FAILED' state as we cannot iterate any more.\n this.setState(State.FAILED);\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => {\n if (this.iterations !== null) {\n return `RETRY ${\n this.maximumIterations ? this.iterations + \"x-\" + this.maximumIterations + \"x\" : this.iterations + \"x\"\n }`;\n }\n\n // Return the default retry node name.\n return \"RETRY\";\n };\n\n /**\n * Reset the state of the node.\n */\n reset = () => {\n // Reset the state of this node.\n this.setState(State.READY);\n\n // Reset the current iteration count.\n this.currentIterationCount = 0;\n\n // Reset the child node.\n this.child.reset();\n };\n\n /**\n * Gets whether an iteration can be made.\n * @returns Whether an iteration can be made.\n */\n canIterate = () => {\n if (this.targetIterationCount !== null) {\n // We can iterate as long as we have not reached our target iteration count.\n return this.currentIterationCount < this.targetIterationCount;\n }\n\n // If neither an iteration count or a condition function were defined then we can iterate indefinitely.\n return true;\n };\n\n /**\n * Sets the target iteration count.\n */\n setTargetIterationCount = () => {\n // Are we dealing with a finite number of iterations?\n if (typeof this.iterations === \"number\") {\n // If we have maximumIterations defined then we will want a random iteration count bounded by iterations and maximumIterations.\n this.targetIterationCount =\n typeof this.maximumIterations === \"number\"\n ? Math.floor(Math.random() * (this.maximumIterations - this.iterations + 1) + this.iterations)\n : this.iterations;\n } else {\n this.targetIterationCount = null;\n }\n };\n}\n", "import Decorator from \"./Decorator\";\nimport State from \"../../State\";\nimport Node from \"../Node\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A Flip node.\n * This node wraps a single child and will flip the state of the child state.\n */\nexport default class Flip extends Decorator {\n /**\n * @param attributes The node attributes.\n * @param child The child node.\n */\n constructor(attributes: Attribute[], child: Node) {\n super(\"flip\", attributes, child);\n }\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // If the child has never been updated or is running then we will need to update it now.\n if (this.child.getState() === State.READY || this.child.getState() === State.RUNNING) {\n this.child.update(agent, options);\n }\n\n // The state of this node will depend in the state of its child.\n switch (this.child.getState()) {\n case State.RUNNING:\n this.setState(State.RUNNING);\n break;\n\n case State.SUCCEEDED:\n this.setState(State.FAILED);\n break;\n\n case State.FAILED:\n this.setState(State.SUCCEEDED);\n break;\n\n default:\n this.setState(State.READY);\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => \"FLIP\";\n}\n", "import Node from \"../Node\";\nimport Decorator from \"./Decorator\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A Succeed node.\n * This node wraps a single child and will always move to the 'SUCCEEDED' state when the child moves to a 'SUCCEEDED' or 'FAILED' state.\n */\nexport default class Succeed extends Decorator {\n /**\n * @param attributes The node attributes.\n * @param child The child node.\n */\n constructor(attributes: Attribute[], child: Node) {\n super(\"succeed\", attributes, child);\n }\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // If the child has never been updated or is running then we will need to update it now.\n if (this.child.getState() === State.READY || this.child.getState() === State.RUNNING) {\n this.child.update(agent, options);\n }\n\n // The state of this node will depend in the state of its child.\n switch (this.child.getState()) {\n case State.RUNNING:\n this.setState(State.RUNNING);\n break;\n\n case State.SUCCEEDED:\n case State.FAILED:\n this.setState(State.SUCCEEDED);\n break;\n\n default:\n this.setState(State.READY);\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => \"SUCCEED\";\n}\n", "import Node from \"../Node\";\nimport Decorator from \"./Decorator\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A Fail node.\n * This node wraps a single child and will always move to the 'FAILED' state when the child moves to a 'SUCCEEDED' or 'FAILED' state.\n */\nexport default class Fail extends Decorator {\n /**\n * @param attributes The node attributes.\n * @param child The child node.\n */\n constructor(attributes: Attribute[], child: Node) {\n super(\"fail\", attributes, child);\n }\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // If the child has never been updated or is running then we will need to update it now.\n if (this.child.getState() === State.READY || this.child.getState() === State.RUNNING) {\n this.child.update(agent, options);\n }\n\n // The state of this node will depend in the state of its child.\n switch (this.child.getState()) {\n case State.RUNNING:\n this.setState(State.RUNNING);\n break;\n\n case State.SUCCEEDED:\n case State.FAILED:\n this.setState(State.FAILED);\n break;\n\n default:\n this.setState(State.READY);\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => \"FAIL\";\n}\n", "import createLotto from \"lotto-draw\";\r\n\r\nimport Node from \"../Node\";\r\nimport Composite from \"./Composite\";\r\nimport State from \"../../State\";\r\nimport { Agent } from \"../../Agent\";\r\nimport Attribute from \"../../attributes/Attribute\";\r\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\r\n\r\n/**\r\n * A LOTTO node.\r\n * A winning child is picked on the initial update of this node, based on ticket weighting.\r\n * The state of this node will match the state of the winning child.\r\n */\r\nexport default class Lotto extends Composite {\r\n /**\r\n * @param attributes The node attributes.\r\n * @param tickets The child node tickets.\r\n * @param children The child nodes.\r\n */\r\n constructor(attributes: Attribute[], private tickets: number[], children: Node[]) {\r\n super(\"lotto\", attributes, children);\r\n }\r\n\r\n /**\r\n * The child node selected to be the active one.\r\n */\r\n private selectedChild: Node | undefined;\r\n\r\n /**\r\n * Called when the node is being updated.\r\n * @param agent The agent.\r\n * @param options The behaviour tree options object.\r\n */\r\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\r\n // If this node is in the READY state then we need to pick a winning child node.\r\n if (this.is(State.READY)) {\r\n // Create a lotto draw with which to randomly pick a child node to become the active one.\r\n const lottoDraw = createLotto({\r\n // Hook up the optional 'random' behaviour tree function option to the one used by 'lotto-draw'.\r\n random: options.random,\r\n // Pass in each child node as a participant in the lotto draw with their respective ticket count.\r\n participants: this.children.map((child, index) => [child, this.tickets[index] || 1])\r\n });\r\n\r\n // Randomly pick a child based on ticket weighting, this will become the active child for this composite node.\r\n this.selectedChild = lottoDraw.draw() || undefined;\r\n }\r\n\r\n // If something went wrong and we don't have an active child then we should throw an error.\r\n if (!this.selectedChild) {\r\n throw new Error(\"failed to update lotto node as it has no active child\");\r\n }\r\n\r\n // If the selected child has never been updated or is running then we will need to update it now.\r\n if (this.selectedChild.getState() === State.READY || this.selectedChild.getState() === State.RUNNING) {\r\n this.selectedChild.update(agent, options);\r\n }\r\n\r\n // The state of the lotto node is the state of its selected child.\r\n this.setState(this.selectedChild.getState());\r\n }\r\n\r\n /**\r\n * Gets the name of the node.\r\n */\r\n getName = () => (this.tickets.length ? `LOTTO [${this.tickets.join(\",\")}]` : \"LOTTO\");\r\n}\r\n", "import Node from \"../Node\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\n\n/**\n * A composite node that wraps child nodes.\n */\nexport default abstract class Composite extends Node {\n /**\n * @param type The node type.\n * @param attributes The node attributes.\n * @param children The child nodes.\n */\n constructor(type: string, attributes: Attribute[], protected children: Node[]) {\n super(type, attributes, []);\n }\n\n /**\n * Gets whether this node is a leaf node.\n */\n isLeafNode = () => false;\n\n /**\n * Gets the children of this node.\n */\n getChildren = () => this.children;\n\n /**\n * Reset the state of the node.\n */\n reset = () => {\n // Reset the state of this node.\n this.setState(State.READY);\n\n // Reset the state of any child nodes.\n this.getChildren().forEach((child) => child.reset());\n };\n\n /**\n * Abort the running of this node.\n * @param agent The agent.\n */\n abort = (agent: Agent) => {\n // There is nothing to do if this node is not in the running state.\n if (!this.is(State.RUNNING)) {\n return;\n }\n\n // Abort any child nodes.\n this.getChildren().forEach((child) => child.abort(agent));\n\n // Reset the state of this node.\n this.reset();\n\n this.getAttribute(\"exit\")?.callAgentFunction(agent, false, true);\n };\n}\n", "import Composite from \"./Composite\";\nimport Node from \"../Node\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A SELECTOR node.\n * The child nodes are executed in sequence until one succeeds or all fail.\n */\nexport default class Selector extends Composite {\n /**\n * @param attributes The node attributes.\n * @param children The child nodes.\n */\n constructor(attributes: Attribute[], protected children: Node[]) {\n super(\"selector\", attributes, children);\n }\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // Iterate over all of the children of this node.\n for (const child of this.children) {\n // If the child has never been updated or is running then we will need to update it now.\n if (child.getState() === State.READY || child.getState() === State.RUNNING) {\n // Update the child of this node.\n child.update(agent, options);\n }\n\n // If the current child has a state of 'SUCCEEDED' then this node is also a 'SUCCEEDED' node.\n if (child.getState() === State.SUCCEEDED) {\n // This node is a 'SUCCEEDED' node.\n this.setState(State.SUCCEEDED);\n\n // There is no need to check the rest of the selector nodes.\n return;\n }\n\n // If the current child has a state of 'FAILED' then we should move on to the next child.\n if (child.getState() === State.FAILED) {\n // Find out if the current child is the last one in the selector.\n // If it is then this sequence node has also failed.\n if (this.children.indexOf(child) === this.children.length - 1) {\n // This node is a 'FAILED' node.\n this.setState(State.FAILED);\n\n // There is no need to check the rest of the selector as we have completed it.\n return;\n } else {\n // The child node failed, try the next one.\n continue;\n }\n }\n\n // The node should be in the 'RUNNING' state.\n if (child.getState() === State.RUNNING) {\n // This node is a 'RUNNING' node.\n this.setState(State.RUNNING);\n\n // There is no need to check the rest of the selector as the current child is still running.\n return;\n }\n\n // The child node was not in an expected state.\n throw new Error(\"child node was not in an expected state.\");\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => \"SELECTOR\";\n}\n", "import Composite from \"./Composite\";\nimport Node from \"../Node\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A SEQUENCE node.\n * The child nodes are executed in sequence until one fails or all succeed.\n */\nexport default class Sequence extends Composite {\n /**\n * @param attributes The node attributes.\n * @param children The child nodes.\n */\n constructor(attributes: Attribute[], protected children: Node[]) {\n super(\"sequence\", attributes, children);\n }\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // Iterate over all of the children of this node.\n for (const child of this.children) {\n // If the child has never been updated or is running then we will need to update it now.\n if (child.getState() === State.READY || child.getState() === State.RUNNING) {\n // Update the child of this node.\n child.update(agent, options);\n }\n\n // If the current child has a state of 'SUCCEEDED' then we should move on to the next child.\n if (child.getState() === State.SUCCEEDED) {\n // Find out if the current child is the last one in the sequence.\n // If it is then this sequence node has also succeeded.\n if (this.children.indexOf(child) === this.children.length - 1) {\n // This node is a 'SUCCEEDED' node.\n this.setState(State.SUCCEEDED);\n\n // There is no need to check the rest of the sequence as we have completed it.\n return;\n } else {\n // The child node succeeded, but we have not finished the sequence yet.\n continue;\n }\n }\n\n // If the current child has a state of 'FAILED' then this node is also a 'FAILED' node.\n if (child.getState() === State.FAILED) {\n // This node is a 'FAILED' node.\n this.setState(State.FAILED);\n\n // There is no need to check the rest of the sequence.\n return;\n }\n\n // The node should be in the 'RUNNING' state.\n if (child.getState() === State.RUNNING) {\n // This node is a 'RUNNING' node.\n this.setState(State.RUNNING);\n\n // There is no need to check the rest of the sequence as the current child is still running.\n return;\n }\n\n // The child node was not in an expected state.\n throw new Error(\"child node was not in an expected state.\");\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => \"SEQUENCE\";\n}\n", "import Composite from \"./Composite\";\nimport State from \"../../State\";\nimport Node from \"../Node\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A PARALLEL node.\n * The child nodes are executed concurrently until one fails or all succeed.\n */\nexport default class Parallel extends Composite {\n /**\n * @param attributes The node attributes.\n * @param children The child nodes.\n */\n constructor(attributes: Attribute[], children: Node[]) {\n super(\"parallel\", attributes, children);\n }\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // Keep a count of the number of succeeded child nodes.\n let succeededCount = 0;\n\n let hasChildFailed = false;\n\n // Iterate over all of the children of this node.\n for (const child of this.children) {\n // If the child has never been updated or is running then we will need to update it now.\n if (child.getState() === State.READY || child.getState() === State.RUNNING) {\n // Update the child of this node.\n child.update(agent, options);\n }\n\n // If the current child has a state of 'SUCCEEDED' then we should move on to the next child.\n if (child.getState() === State.SUCCEEDED) {\n // The child node has succeeded, keep track of this to determine if all children have.\n succeededCount++;\n\n // The child node succeeded, but we have not finished checking every child node yet.\n continue;\n }\n\n // If the current child has a state of 'FAILED' then this node is also a 'FAILED' node.\n if (child.getState() === State.FAILED) {\n hasChildFailed = true;\n\n // There is no need to check the rest of the children.\n break;\n }\n\n // The node should be in the 'RUNNING' state.\n if (child.getState() !== State.RUNNING) {\n // The child node was not in an expected state.\n throw new Error(\"child node was not in an expected state.\");\n }\n }\n\n if (hasChildFailed) {\n // This node is a 'FAILED' node.\n this.setState(State.FAILED);\n\n // Abort every running child.\n for (const child of this.children) {\n if (child.getState() === State.RUNNING) {\n child.abort(agent);\n }\n }\n } else {\n // If all children have succeeded then this node has also succeeded, otherwise it is still running.\n this.setState(succeededCount === this.children.length ? State.SUCCEEDED : State.RUNNING);\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => \"PARALLEL\";\n}\n", "import { AnyArgument } from \"../RootAstNodesBuilder\";\nimport Guard from \"./guards/Guard\";\n\nexport type AttributeDetails = {\n /** The attribute type. */\n type: string;\n\n /** The attribute arguments. */\n args: AnyArgument[];\n};\n\n/**\n * A base node attribute.\n */\nexport default abstract class Attribute {\n /**\n * @param type The node attribute type.\n * @param args The array of attribute argument definitions.\n */\n constructor(protected type: string, protected args: AnyArgument[]) {}\n\n /**\n * Gets the type of the attribute.\n */\n getType = () => this.type;\n\n /**\n * Gets the array of attribute argument definitions.\n */\n getArguments = () => this.args;\n\n /**\n * Gets the attribute details.\n */\n abstract getDetails(): TAttributeDetails;\n\n /**\n * Gets whether this attribute is a guard.\n */\n abstract isGuard: () => this is Guard;\n}\n", "import { Agent } from \"../../Agent\";\nimport { AnyArgument } from \"../../RootAstNodesBuilder\";\nimport Attribute, { AttributeDetails } from \"../Attribute\";\n\nexport type GuardAttributeDetails = {\n /** The name of the condition function that determines whether the guard is satisfied. */\n condition: string;\n} & AttributeDetails;\n\n/**\n * A base node guard attribute.\n */\nexport default abstract class Guard extends Attribute {\n /**\n * @param type The node attribute type.\n * @param args The array of decorator argument definitions.\n * @param condition The name of the condition function that determines whether the guard is satisfied.\n */\n constructor(type: string, args: AnyArgument[], private condition: string) {\n super(type, args);\n }\n\n /**\n * Gets the name of the condition function that determines whether the guard is satisfied.\n */\n getCondition = () => this.condition;\n\n /**\n * Gets whether this attribute is a guard.\n */\n isGuard = () => true;\n\n /**\n * Gets the attribute details.\n */\n getDetails(): GuardAttributeDetails {\n return {\n type: this.getType(),\n args: this.getArguments(),\n condition: this.getCondition()\n };\n }\n\n /**\n * Gets whether the guard is satisfied.\n * @param agent The agent.\n * @returns Whether the guard is satisfied.\n */\n abstract isSatisfied(agent: Agent): boolean;\n}\n", "import Guard from \"./Guard\";\nimport Lookup from \"../../Lookup\";\nimport { Agent } from \"../../Agent\";\nimport { AnyArgument } from \"../../RootAstNodesBuilder\";\n\n/**\n * A WHILE guard which is satisfied as long as the given condition remains true.\n */\nexport default class While extends Guard {\n /**\n * @param condition The name of the condition function that determines whether the guard is satisfied.\n * @param args The array of decorator argument definitions.\n */\n constructor(condition: string, args: AnyArgument[]) {\n super(\"while\", args, condition);\n }\n\n /**\n * Gets whether the guard is satisfied.\n * @param agent The agent.\n * @returns Whether the guard is satisfied.\n */\n isSatisfied = (agent: Agent) => {\n // Attempt to get the invoker for the condition function.\n const conditionFuncInvoker = Lookup.getFuncInvoker(agent, this.getCondition());\n\n // The condition function should be defined.\n if (conditionFuncInvoker === null) {\n throw new Error(\n `cannot evaluate node guard as the condition '${this.getCondition()}' function is not defined on the agent and has not been registered`\n );\n }\n\n // Call the condition function to determine whether this guard is satisfied.\n return !!conditionFuncInvoker(this.args);\n };\n}\n", "import Guard from \"./Guard\";\nimport Lookup from \"../../Lookup\";\nimport { Agent } from \"../../Agent\";\nimport { AnyArgument } from \"../../RootAstNodesBuilder\";\n\n/**\n * An UNTIL guard which is satisfied as long as the given condition remains false.\n */\nexport default class Until extends Guard {\n /**\n * @param condition The name of the condition function that determines whether the guard is satisfied.\n * @param args The array of decorator argument definitions.\n */\n constructor(condition: string, args: AnyArgument[]) {\n super(\"until\", args, condition);\n }\n\n /**\n * Gets whether the guard is satisfied.\n * @param agent The agent.\n * @returns Whether the guard is satisfied.\n */\n isSatisfied = (agent: Agent) => {\n // Attempt to get the invoker for the condition function.\n const conditionFuncInvoker = Lookup.getFuncInvoker(agent, this.getCondition());\n\n // The condition function should be defined.\n if (conditionFuncInvoker === null) {\n throw new Error(\n `cannot evaluate node guard as the condition '${this.getCondition()}' function is not defined on the agent and has not been registered`\n );\n }\n\n // Call the condition function to determine whether this guard is satisfied.\n return !!!conditionFuncInvoker(this.args);\n };\n}\n", "import { Agent } from \"../../Agent\";\nimport { AnyArgument } from \"../../RootAstNodesBuilder\";\nimport Attribute, { AttributeDetails } from \"../Attribute\";\n\nexport type CallbackAttributeDetails = {\n /** The name of the agent function that is called. */\n functionName: string;\n} & AttributeDetails;\n\n/**\n * A base node callback attribute.\n */\nexport default abstract class Callback extends Attribute {\n /**\n * @param type The node attribute type.\n * @param args The array of decorator argument definitions.\n * @param functionName The name of the agent function to call.\n */\n constructor(type: string, args: AnyArgument[], private functionName: string) {\n super(type, args);\n }\n\n /**\n * Gets the name of the agent function to call.\n */\n getFunctionName = () => this.functionName;\n\n /**\n * Gets whether this attribute is a guard.\n */\n isGuard = () => false;\n\n /**\n * Gets the attribute details.\n */\n getDetails(): CallbackAttributeDetails {\n return {\n type: this.getType(),\n args: this.getArguments(),\n functionName: this.getFunctionName()\n };\n }\n\n /**\n * Attempt to call the agent function that this callback refers to.\n * @param agent The agent.\n */\n abstract callAgentFunction: (agent: Agent, isSuccess: boolean, isAborted: boolean) => void;\n}\n", "import Callback from \"./Callback\";\nimport Lookup from \"../../Lookup\";\nimport { Agent } from \"../../Agent\";\nimport { AnyArgument } from \"../../RootAstNodesBuilder\";\n\n/**\n * An ENTRY callback which defines an agent function to call when the associated node is updated and moves out of running state.\n */\nexport default class Entry extends Callback {\n /**\n * @param functionName The name of the agent function to call.\n * @param args The array of callback argument definitions.\n */\n constructor(functionName: string, args: AnyArgument[]) {\n super(\"entry\", args, functionName);\n }\n\n /**\n * Attempt to call the agent function that this callback refers to.\n * @param agent The agent.\n */\n callAgentFunction = (agent: Agent) => {\n // Attempt to get the invoker for the callback function.\n const callbackFuncInvoker = Lookup.getFuncInvoker(agent, this.getFunctionName());\n\n // The callback function should be defined.\n if (callbackFuncInvoker === null) {\n throw new Error(\n `cannot call entry function '${this.getFunctionName()}' as is not defined on the agent and has not been registered`\n );\n }\n\n // Call the callback function.\n callbackFuncInvoker(this.args);\n };\n}\n", "import Callback from \"./Callback\";\nimport Lookup, { AnyExitArgument } from \"../../Lookup\";\nimport { Agent } from \"../../Agent\";\nimport { AnyArgument } from \"../../RootAstNodesBuilder\";\n\n/**\n * An EXIT callback which defines an agent function to call when the associated node is updated and moves to a finished state or is aborted.\n */\nexport default class Exit extends Callback {\n /**\n * @param functionName The name of the agent function to call.\n * @param args The array of callback argument definitions.\n */\n constructor(functionName: string, args: AnyArgument[]) {\n super(\"exit\", args, functionName);\n }\n\n /**\n * Attempt to call the agent function that this callback refers to.\n * @param agent The agent.\n * @param isSuccess Whether the decorated node was left with a success state.\n * @param isAborted Whether the decorated node was aborted.\n */\n callAgentFunction = (agent: Agent, isSuccess: boolean, isAborted: boolean) => {\n // Attempt to get the invoker for the callback function.\n const callbackFuncInvoker = Lookup.getFuncInvoker(agent, this.getFunctionName());\n\n // The callback function should be defined.\n if (callbackFuncInvoker === null) {\n throw new Error(\n `cannot call exit function '${this.getFunctionName()}' as is not defined on the agent and has not been registered`\n );\n }\n\n // Call the callback function\n callbackFuncInvoker([{ value: { succeeded: isSuccess, aborted: isAborted } }, ...this.args]);\n };\n}\n", "import Callback from \"./Callback\";\nimport Lookup from \"../../Lookup\";\nimport { Agent } from \"../../Agent\";\nimport { AnyArgument } from \"../../RootAstNodesBuilder\";\n\n/**\n * A STEP callback which defines an agent function to call when the associated node is updated.\n */\nexport default class Step extends Callback {\n /**\n * @param functionName The name of the agent function to call.\n * @param args The array of callback argument definitions.\n */\n constructor(functionName: string, args: AnyArgument[]) {\n super(\"step\", args, functionName);\n }\n\n /**\n * Attempt to call the agent function that this callback refers to.\n * @param agent The agent.\n */\n callAgentFunction = (agent: Agent) => {\n // Attempt to get the invoker for the callback function.\n const callbackFuncInvoker = Lookup.getFuncInvoker(agent, this.getFunctionName());\n\n // The callback function should be defined.\n if (callbackFuncInvoker === null) {\n throw new Error(\n `cannot call step function '${this.getFunctionName()}' as is not defined on the agent and has not been registered`\n );\n }\n\n // Call the callback function.\n callbackFuncInvoker(this.args);\n };\n}\n", "import Action from \"./nodes/leaf/Action\";\nimport Condition from \"./nodes/leaf/Condition\";\nimport Wait from \"./nodes/leaf/Wait\";\nimport Root from \"./nodes/decorator/Root\";\nimport Repeat from \"./nodes/decorator/Repeat\";\nimport Retry from \"./nodes/decorator/Retry\";\nimport Flip from \"./nodes/decorator/Flip\";\nimport Succeed from \"./nodes/decorator/Succeed\";\nimport Fail from \"./nodes/decorator/Fail\";\nimport Lotto from \"./nodes/composite/Lotto\";\nimport Selector from \"./nodes/composite/Selector\";\nimport Sequence from \"./nodes/composite/Sequence\";\nimport Parallel from \"./nodes/composite/Parallel\";\nimport Node from \"./nodes/Node\";\nimport While from \"./attributes/guards/While\";\nimport Until from \"./attributes/guards/Until\";\nimport Entry from \"./attributes/callbacks/Entry\";\nimport Exit from \"./attributes/callbacks/Exit\";\nimport Step from \"./attributes/callbacks/Step\";\nimport Callback from \"./attributes/callbacks/Callback\";\nimport Guard from \"./attributes/guards/Guard\";\nimport Attribute from \"./attributes/Attribute\";\nimport Composite from \"./nodes/composite/Composite\";\nimport Decorator from \"./nodes/decorator/Decorator\";\nimport Leaf from \"./nodes/leaf/Leaf\";\n\nexport type Argument = {\n value: T;\n type: string; // Used for validation.\n};\ntype NullArgument = Argument & {\n type: \"null\";\n};\ntype BooleanArgument = Argument & {\n type: \"boolean\";\n};\ntype NumberArgument = Argument & {\n type: \"number\";\n isInteger: boolean; // Used for validation.\n};\ntype StringPlaceholderArgument = Argument & {\n type: \"string\";\n};\ntype IdentifierArgument = Argument & {\n type: \"identifier\";\n};\nexport type AnyArgument =\n | NullArgument\n | BooleanArgument\n | NumberArgument\n | StringPlaceholderArgument\n | IdentifierArgument;\n\n/**\n * The node attribute factories.\n */\nconst AttributeFactories: {\n [key: string]: (functionName: string, attributeArguments: AnyArgument[]) => Callback | Guard;\n} = {\n WHILE: (condition: string, attributeArguments: AnyArgument[]) => new While(condition, attributeArguments),\n UNTIL: (condition: string, attributeArguments: AnyArgument[]) => new Until(condition, attributeArguments),\n ENTRY: (functionName: string, attributeArguments: AnyArgument[]) => new Entry(functionName, attributeArguments),\n EXIT: (functionName: string, attributeArguments: AnyArgument[]) => new Exit(functionName, attributeArguments),\n STEP: (functionName: string, attributeArguments: AnyArgument[]) => new Step(functionName, attributeArguments)\n};\n\ntype Validatable = {\n children?: AstNode[];\n validate: (depth: number) => void;\n};\n\ntype NodeInstanceCreator = (\n namedRootNodeProvider: (name: string) => RootAstNode,\n visitedBranches: string[]\n) => T;\n\nexport type AstNode = Validatable & {\n type: string;\n createNodeInstance: NodeInstanceCreator;\n};\n\nexport type LeafAstNode = AstNode & {\n type: \"action\" | \"condition\" | \"wait\";\n attributes: Attribute[];\n};\n\nexport type CompositeAstNode = AstNode & {\n type: \"lotto\" | \"parallel\" | \"selector\" | \"sequence\";\n attributes: Attribute[];\n children: AstNode[];\n};\n\nexport type DecoratorAstNode = AstNode & {\n type: \"fail\" | \"flip\" | \"repeat\" | \"retry\" | \"root\" | \"succeed\";\n attributes: Attribute[];\n children: AstNode[];\n};\n\nexport type BranchAstNode = AstNode & {\n type: \"branch\";\n branchName: \"\" | string;\n};\n\nexport type LottoAstNode = CompositeAstNode & {\n type: \"lotto\";\n tickets: number[];\n};\n\nexport type RootAstNode = DecoratorAstNode & {\n type: \"root\";\n name: null | string;\n};\n\nexport type IterableAstNode = DecoratorAstNode & {\n type: \"repeat\" | \"retry\";\n iterations: null | number;\n maximumIterations: null | number;\n};\n\nexport type ActionAstNode = LeafAstNode & {\n type: \"action\";\n actionName: string;\n actionArguments: AnyArgument[];\n};\n\nexport type ConditionAstNode = LeafAstNode & {\n type: \"condition\";\n conditionName: string;\n conditionArguments: AnyArgument[];\n};\n\nexport type WaitAstNode = LeafAstNode & {\n type: \"wait\";\n duration: number | null;\n longestDuration: number | null;\n};\n\nexport type AnyAstNode =\n | BranchAstNode\n | CompositeAstNode\n | LottoAstNode\n | DecoratorAstNode\n | RootAstNode\n | IterableAstNode\n | LeafAstNode\n | ActionAstNode\n | ConditionAstNode\n | WaitAstNode;\n\n/**\n * The AST node factories.\n */\nconst ASTNodeFactories = {\n ROOT: (): RootAstNode => ({\n type: \"root\",\n attributes: [],\n name: null,\n children: [],\n validate(depth: number) {\n // A root node cannot be the child of another node.\n if (depth > 1) {\n throw new Error(\"a root node cannot be the child of another node\");\n }\n\n // A root node must have a single child node.\n if (this.children.length !== 1) {\n throw new Error(\"a root node must have a single child\");\n }\n },\n createNodeInstance(namedRootNodeProvider, visitedBranches) {\n return new Root(\n this.attributes,\n this.children![0].createNodeInstance(namedRootNodeProvider, visitedBranches.slice())\n );\n }\n }),\n BRANCH: (): BranchAstNode => ({\n type: \"branch\",\n branchName: \"\",\n validate() {},\n createNodeInstance(namedRootNodeProvider, visitedBranches) {\n // Try to find the root node with a matching branch name.\n const targetRootNode = namedRootNodeProvider(this.branchName);\n\n // If we have already visited this branch then we have a circular dependency.\n if (visitedBranches.indexOf(this.branchName) !== -1) {\n throw new Error(`circular dependency found in branch node references for branch '${this.branchName}'`);\n }\n\n // If we have a target root node, then the node instance we want will be the first and only child of the referenced root node.\n if (targetRootNode) {\n return targetRootNode\n .createNodeInstance(namedRootNodeProvider, visitedBranches.concat(this.branchName))\n .getChildren()[0];\n } else {\n throw new Error(`branch references root node '${this.branchName}' which has not been defined`);\n }\n }\n }),\n SELECTOR: (): CompositeAstNode => ({\n type: \"selector\",\n attributes: [],\n children: [],\n validate() {\n // A selector node must have at least a single node.\n if (this.children.length < 1) {\n throw new Error(\"a selector node must have at least a single child\");\n }\n },\n createNodeInstance(namedRootNodeProvider, visitedBranches) {\n return new Selector(\n this.attributes,\n this.children.map((child) => child.createNodeInstance(namedRootNodeProvider, visitedBranches.slice()))\n );\n }\n }),\n SEQUENCE: (): CompositeAstNode => ({\n type: \"sequence\",\n attributes: [],\n children: [],\n validate() {\n // A sequence node must have at least a single node.\n if (this.children.length < 1) {\n throw new Error(\"a sequence node must have at least a single child\");\n }\n },\n createNodeInstance(namedRootNodeProvider, visitedBranches) {\n return new Sequence(\n this.attributes,\n this.children.map((child) => child.createNodeInstance(namedRootNodeProvider, visitedBranches.slice()))\n );\n }\n }),\n PARALLEL: (): CompositeAstNode => ({\n type: \"parallel\",\n attributes: [],\n children: [],\n validate() {\n // A parallel node must have at least a single node.\n if (this.children.length < 1) {\n throw new Error(\"a parallel node must have at least a single child\");\n }\n },\n createNodeInstance(namedRootNodeProvider, visitedBranches) {\n return new Parallel(\n this.attributes,\n this.children.map((child) => child.createNodeInstance(namedRootNodeProvider, visitedBranches.slice()))\n );\n }\n }),\n LOTTO: (): LottoAstNode => ({\n type: \"lotto\",\n attributes: [],\n children: [],\n tickets: [],\n validate() {\n // A lotto node must have at least a single node.\n if (this.children!.length < 1) {\n throw new Error(\"a lotto node must have at least a single child\");\n }\n },\n createNodeInstance(namedRootNodeProvider, visitedBranches) {\n return new Lotto(\n this.attributes,\n this.tickets!,\n this.children!.map((child) => child.createNodeInstance(namedRootNodeProvider, visitedBranches.slice()))\n );\n }\n }),\n REPEAT: (): IterableAstNode => ({\n type: \"repeat\",\n attributes: [],\n iterations: null,\n maximumIterations: null,\n children: [],\n validate() {\n // A repeat node must have a single node.\n if (this.children!.length !== 1) {\n throw new Error(\"a repeat node must have a single child\");\n }\n\n // A repeat node must have a positive number of iterations if defined.\n if (this.iterations !== null && this.iterations! < 0) {\n throw new Error(\"a repeat node must have a positive number of iterations if defined\");\n }\n\n // There is validation to carry out if a longest duration was defined.\n if (this.maximumIterations !== null) {\n // A repeat node must have a positive maximum iterations count if defined.\n if (this.maximumIterations! < 0) {\n throw new Error(\"a repeat node must have a positive maximum iterations count if defined\");\n }\n\n // A repeat node must not have an iteration count that exceeds the maximum iteration count.\n if (this.iterations! > this.maximumIterations!) {\n throw new Error(\n \"a repeat node must not have an iteration count that exceeds the maximum iteration count\"\n );\n }\n }\n },\n createNodeInstance(namedRootNodeProvider, visitedBranches) {\n return new Repeat(\n this.attributes,\n this.iterations!,\n this.maximumIterations!,\n this.children![0].createNodeInstance(namedRootNodeProvider, visitedBranches.slice())\n );\n }\n }),\n RETRY: (): IterableAstNode => ({\n type: \"retry\",\n attributes: [],\n iterations: null,\n maximumIterations: null,\n children: [],\n validate() {\n // A retry node must have a single node.\n if (this.children!.length !== 1) {\n throw new Error(\"a retry node must have a single child\");\n }\n\n // A retry node must have a positive number of iterations if defined.\n if (this.iterations !== null && this.iterations! < 0) {\n throw new Error(\"a retry node must have a positive number of iterations if defined\");\n }\n\n // There is validation to carry out if a longest duration was defined.\n if (this.maximumIterations !== null) {\n // A retry node must have a positive maximum iterations count if defined.\n if (this.maximumIterations! < 0) {\n throw new Error(\"a retry node must have a positive maximum iterations count if defined\");\n }\n\n // A retry node must not have an iteration count that exceeds the maximum iteration count.\n if (this.iterations! > this.maximumIterations!) {\n throw new Error(\n \"a retry node must not have an iteration count that exceeds the maximum iteration count\"\n );\n }\n }\n },\n createNodeInstance(namedRootNodeProvider, visitedBranches) {\n return new Retry(\n this.attributes,\n this.iterations!,\n this.maximumIterations!,\n this.children![0].createNodeInstance(namedRootNodeProvider, visitedBranches.slice())\n );\n }\n }),\n FLIP: (): DecoratorAstNode => ({\n type: \"flip\",\n attributes: [],\n children: [],\n validate() {\n // A flip node must have a single node.\n if (this.children!.length !== 1) {\n throw new Error(\"a flip node must have a single child\");\n }\n },\n createNodeInstance(namedRootNodeProvider, visitedBranches) {\n return new Flip(\n this.attributes,\n this.children![0].createNodeInstance(namedRootNodeProvider, visitedBranches.slice())\n );\n }\n }),\n SUCCEED: (): DecoratorAstNode => ({\n type: \"succeed\",\n attributes: [],\n children: [],\n validate() {\n // A succeed node must have a single node.\n if (this.children!.length !== 1) {\n throw new Error(\"a succeed node must have a single child\");\n }\n },\n createNodeInstance(namedRootNodeProvider, visitedBranches) {\n return new Succeed(\n this.attributes,\n this.children![0].createNodeInstance(namedRootNodeProvider, visitedBranches.slice())\n );\n }\n }),\n FAIL: (): DecoratorAstNode => ({\n type: \"fail\",\n attributes: [],\n children: [],\n validate() {\n // A fail node must have a single node.\n if (this.children!.length !== 1) {\n throw new Error(\"a fail node must have a single child\");\n }\n },\n createNodeInstance(namedRootNodeProvider, visitedBranches) {\n return new Fail(\n this.attributes,\n this.children![0].createNodeInstance(namedRootNodeProvider, visitedBranches.slice())\n );\n }\n }),\n WAIT: (): WaitAstNode => ({\n type: \"wait\",\n attributes: [],\n duration: null,\n longestDuration: null,\n validate() {\n // A wait node must have a positive duration.\n if (this.duration! < 0) {\n throw new Error(\"a wait node must have a positive duration\");\n }\n\n // There is validation to carry out if a longest duration was defined.\n if (this.longestDuration) {\n // A wait node must have a positive longest duration.\n if (this.longestDuration < 0) {\n throw new Error(\"a wait node must have a positive longest duration if one is defined\");\n }\n\n // A wait node must not have a duration that exceeds the longest duration.\n if (this.duration! > this.longestDuration) {\n throw new Error(\"a wait node must not have a shortest duration that exceeds the longest duration\");\n }\n }\n },\n createNodeInstance() {\n return new Wait(this.attributes, this.duration!, this.longestDuration!);\n }\n }),\n ACTION: (): ActionAstNode => ({\n type: \"action\",\n attributes: [],\n actionName: \"\",\n actionArguments: [],\n validate() {},\n createNodeInstance() {\n return new Action(this.attributes, this.actionName!, this.actionArguments!);\n }\n }),\n CONDITION: (): ConditionAstNode => ({\n type: \"condition\",\n attributes: [],\n conditionName: \"\",\n conditionArguments: [],\n validate() {},\n createNodeInstance() {\n return new Condition(this.attributes, this.conditionName!, this.conditionArguments!);\n }\n })\n};\n\ntype OtherAstNodes = AstNode[];\n\n/**\n * Create an array of root AST nodes based on the given definition.\n * @param definition The definition to parse the AST nodes from.\n * @returns The base definition AST nodes.\n */\nexport default function buildRootASTNodes(definition: string): RootAstNode[] {\n // Swap out any node/attribute argument string literals with a placeholder and get a mapping of placeholders to original values as well as the processed definition.\n const { placeholders, processedDefinition } = substituteStringLiterals(definition);\n\n // Convert the processed definition (with substituted string literals) into an array of raw tokens.\n const tokens = parseTokensFromDefinition(processedDefinition);\n\n // There must be at least 3 tokens for the tree definition to be valid. 'ROOT', '{' and '}'.\n if (tokens.length < 3) {\n throw new Error(\"invalid token count\");\n }\n\n // We should have a matching number of '{' and '}' tokens. If not, then there are scopes that have not been properly closed.\n if (tokens.filter((token) => token === \"{\").length !== tokens.filter((token) => token === \"}\").length) {\n throw new Error(\"scope character mismatch\");\n }\n\n // Create a stack of node children arrays, starting with a definition scope.\n const stack: [RootAstNode[], ...OtherAstNodes[]] = [[]];\n const rootScope = stack[0];\n\n // We should keep processing the raw tokens until we run out of them.\n while (tokens.length) {\n // Grab the next token.\n const token = tokens.shift();\n\n const currentScope = stack[stack.length - 1] as OtherAstNodes;\n\n // How we create the next AST token depends on the current raw token value.\n switch (token!.toUpperCase()) {\n case \"ROOT\": {\n // Create a ROOT AST node.\n const node = ASTNodeFactories.ROOT();\n\n // Push the ROOT node into the current scope.\n rootScope.push(node);\n\n // We may have a root node name defined as an argument.\n if (tokens[0] === \"[\") {\n const rootArguments = getArguments(tokens, placeholders);\n\n // We should have only a single argument that is not an empty string for a root node, which is the root name identifier.\n if (rootArguments.length === 1 && rootArguments[0].type === \"identifier\") {\n // The root name will be the first and only node argument.\n node.name = rootArguments[0].value as string;\n } else {\n throw new Error(\"expected single root name argument\");\n }\n }\n\n // Try to pick any attributes off of the token stack.\n node.attributes = getAttributes(tokens, placeholders);\n\n popAndCheck(tokens, \"{\");\n\n // The new scope is that of the new ROOT nodes children.\n stack.push(node.children!);\n break;\n }\n\n case \"BRANCH\": {\n // Create a BRANCH AST node.\n const node = ASTNodeFactories.BRANCH();\n\n // Push the BRANCH node into the current scope.\n currentScope.push(node);\n\n // We must have arguments defined, as we require a branch name argument.\n if (tokens[0] !== \"[\") {\n throw new Error(\"expected single branch name argument\");\n }\n\n // The branch name will be defined as a node argument.\n const branchArguments = getArguments(tokens, placeholders);\n\n // We should have only a single identifer argument for a branch node, which is the branch name.\n if (branchArguments.length === 1 && branchArguments[0].type === \"identifier\") {\n // The branch name will be the first and only node argument.\n node.branchName = branchArguments[0].value as string;\n } else {\n throw new Error(\"expected single branch name argument\");\n }\n break;\n }\n\n case \"SELECTOR\": {\n // Create a SELECTOR AST node.\n const node = ASTNodeFactories.SELECTOR();\n\n // Push the SELECTOR node into the current scope.\n currentScope.push(node);\n\n // Try to pick any attributes off of the token stack.\n node.attributes = getAttributes(tokens, placeholders);\n\n popAndCheck(tokens, \"{\");\n\n // The new scope is that of the new SELECTOR nodes children.\n stack.push(node.children!);\n break;\n }\n\n case \"SEQUENCE\": {\n // Create a SEQUENCE AST node.\n const node = ASTNodeFactories.SEQUENCE();\n\n // Push the SEQUENCE node into the current scope.\n currentScope.push(node);\n\n // Try to pick any attributes off of the token stack.\n node.attributes = getAttributes(tokens, placeholders);\n\n popAndCheck(tokens, \"{\");\n\n // The new scope is that of the new SEQUENCE nodes children.\n stack.push(node.children!);\n break;\n }\n\n case \"PARALLEL\": {\n // Create a PARALLEL AST node.\n const node = ASTNodeFactories.PARALLEL();\n\n // Push the PARALLEL node into the current scope.\n currentScope.push(node);\n\n // Try to pick any attributes off of the token stack.\n node.attributes = getAttributes(tokens, placeholders);\n\n popAndCheck(tokens, \"{\");\n\n // The new scope is that of the new PARALLEL nodes children.\n stack.push(node.children!);\n break;\n }\n\n case \"LOTTO\": {\n // Create a LOTTO AST node.\n const node = ASTNodeFactories.LOTTO();\n\n // Push the LOTTO node into the current scope.\n currentScope.push(node);\n\n // If the next token is a '[' character then some ticket counts have been defined as arguments.\n if (tokens[0] === \"[\") {\n // Get the ticket count arguments, each argument must be a number.\n node.tickets = getArguments(\n tokens,\n placeholders,\n (arg) => arg.type === \"number\" && !!arg.isInteger,\n \"lotto node ticket counts must be integer values\"\n ).map((argument) => argument.value as number);\n }\n\n // Try to pick any attributes off of the token stack.\n node.attributes = getAttributes(tokens, placeholders);\n\n popAndCheck(tokens, \"{\");\n\n // The new scope is that of the new LOTTO nodes children.\n stack.push(node.children!);\n break;\n }\n\n case \"CONDITION\": {\n // Create a CONDITION AST node.\n const node = ASTNodeFactories.CONDITION();\n\n // Push the CONDITION node into the current scope.\n currentScope.push(node);\n\n // We must have arguments defined, as we require a condition function name argument.\n if (tokens[0] !== \"[\") {\n throw new Error(\"expected condition name identifier argument\");\n }\n\n // Grab the condition node arguments.\n const conditionArguments = getArguments(tokens, placeholders);\n\n // We should have at least a single identifier argument for a condition node, which is the condition function name.\n if (conditionArguments.length && conditionArguments[0].type === \"identifier\") {\n // The condition function name will be the first node argument.\n node.conditionName = conditionArguments.shift()!.value as string;\n } else {\n throw new Error(\"expected condition name identifier argument\");\n }\n\n // Only the first argument should have been an identifier, all following arguments must be string, number, boolean or null.\n conditionArguments\n .filter((arg) => arg.type === \"identifier\")\n .forEach((arg) => {\n throw new Error(\n \"invalid condition node argument value '\" +\n arg.value +\n \"', must be string, number, boolean or null\"\n );\n });\n\n // Any node arguments that follow the condition name identifier will be treated as condition function arguments.\n node.conditionArguments = conditionArguments;\n\n // Try to pick any attributes off of the token stack.\n node.attributes = getAttributes(tokens, placeholders);\n break;\n }\n\n case \"FLIP\": {\n // Create a FLIP AST node.\n const node = ASTNodeFactories.FLIP();\n\n // Push the Flip node into the current scope.\n currentScope.push(node);\n\n // Try to pick any attributes off of the token stack.\n node.attributes = getAttributes(tokens, placeholders);\n\n popAndCheck(tokens, \"{\");\n\n // The new scope is that of the new FLIP nodes children.\n stack.push(node.children!);\n break;\n }\n\n case \"SUCCEED\": {\n // Create a SUCCEED AST node.\n const node = ASTNodeFactories.SUCCEED();\n\n // Push the Succeed node into the current scope.\n currentScope.push(node);\n\n // Try to pick any attributes off of the token stack.\n node.attributes = getAttributes(tokens, placeholders);\n\n popAndCheck(tokens, \"{\");\n\n // The new scope is that of the new Succeed nodes children.\n stack.push(node.children!);\n break;\n }\n\n case \"FAIL\": {\n // Create a FAIL AST node.\n const node = ASTNodeFactories.FAIL();\n\n // Push the Fail node into the current scope.\n currentScope.push(node);\n\n // Try to pick any attributes off of the token stack.\n node.attributes = getAttributes(tokens, placeholders);\n\n popAndCheck(tokens, \"{\");\n\n // The new scope is that of the new Fail nodes children.\n stack.push(node.children!);\n break;\n }\n\n case \"WAIT\": {\n // Create a WAIT AST node.\n const node = ASTNodeFactories.WAIT();\n\n // Push the WAIT node into the current scope.\n currentScope.push(node);\n\n // Get the duration and potential longest duration of the wait.\n const durations = getArguments(\n tokens,\n placeholders,\n (arg) => arg.type === \"number\" && !!arg.isInteger,\n \"wait node durations must be integer values\"\n ).map((argument) => argument.value);\n\n // We should have got one or two durations.\n if (durations.length === 1) {\n // A static duration was defined.\n node.duration = durations[0] as number;\n } else if (durations.length === 2) {\n // A shortest and longest duration was defined.\n node.duration = durations[0] as number;\n node.longestDuration = durations[1] as number;\n } else {\n // An incorrect number of durations was defined.\n throw new Error(\"invalid number of wait node duration arguments defined\");\n }\n\n // Try to pick any attributes off of the token stack.\n node.attributes = getAttributes(tokens, placeholders);\n break;\n }\n\n case \"REPEAT\": {\n // Create a REPEAT AST node.\n const node = ASTNodeFactories.REPEAT();\n\n // Push the REPEAT node into the current scope.\n currentScope.push(node);\n\n // Check for iteration counts ([])\n if (tokens[0] === \"[\") {\n // An iteration count has been defined. Get the iteration and potential maximum iteration of the wait.\n const iterationArguments = getArguments(\n tokens,\n placeholders,\n (arg) => arg.type === \"number\" && !!arg.isInteger,\n \"repeat node iteration counts must be integer values\"\n ).map((argument) => argument.value);\n\n // We should have got one or two iteration counts.\n if (iterationArguments.length === 1) {\n // A static iteration count was defined.\n node.iterations = iterationArguments[0] as number;\n } else if (iterationArguments.length === 2) {\n // A minimum and maximum iteration count was defined.\n node.iterations = iterationArguments[0] as number;\n node.maximumIterations = iterationArguments[1] as number;\n } else {\n // An incorrect number of iteration counts was defined.\n throw new Error(\"invalid number of repeat node iteration count arguments defined\");\n }\n }\n\n // Try to pick any attributes off of the token stack.\n node.attributes = getAttributes(tokens, placeholders);\n\n popAndCheck(tokens, \"{\");\n\n // The new scope is that of the new REPEAT nodes children.\n stack.push(node.children!);\n break;\n }\n\n case \"RETRY\": {\n // Create a RETRY AST node.\n const node = ASTNodeFactories.RETRY();\n\n // Push the RETRY node into the current scope.\n currentScope.push(node);\n\n // Check for iteration counts ([])\n if (tokens[0] === \"[\") {\n // An iteration count has been defined. Get the iteration and potential maximum iteration of the wait.\n const iterationArguments = getArguments(\n tokens,\n placeholders,\n (arg) => arg.type === \"number\" && !!arg.isInteger,\n \"retry node iteration counts must be integer values\"\n ).map((argument) => argument.value);\n\n // We should have got one or two iteration counts.\n if (iterationArguments.length === 1) {\n // A static iteration count was defined.\n node.iterations = iterationArguments[0] as number;\n } else if (iterationArguments.length === 2) {\n // A minimum and maximum iteration count was defined.\n node.iterations = iterationArguments[0] as number;\n node.maximumIterations = iterationArguments[1] as number;\n } else {\n // An incorrect number of iteration counts was defined.\n throw new Error(\"invalid number of retry node iteration count arguments defined\");\n }\n }\n\n // Try to pick any attributes off of the token stack.\n node.attributes = getAttributes(tokens, placeholders);\n\n popAndCheck(tokens, \"{\");\n\n // The new scope is that of the new RETRY nodes children.\n stack.push(node.children!);\n break;\n }\n\n case \"ACTION\": {\n // Create a ACTION AST node.\n const node = ASTNodeFactories.ACTION();\n\n // Push the ACTION node into the current scope.\n currentScope.push(node);\n\n // We must have arguments defined, as we require an action name argument.\n if (tokens[0] !== \"[\") {\n throw new Error(\"expected action name identifier argument\");\n }\n\n // The action name will be defined as a node argument.\n const actionArguments = getArguments(tokens, placeholders);\n\n // We should have at least one identifer argument for an action node, which is the action name.\n if (actionArguments.length && actionArguments[0].type === \"identifier\") {\n // The action name will be the first and only node argument.\n node.actionName = actionArguments.shift()!.value as string;\n } else {\n throw new Error(\"expected action name identifier argument\");\n }\n\n // Only the first argument should have been an identifier, all following arguments must be string, number, boolean or null.\n actionArguments\n .filter((arg) => arg.type === \"identifier\")\n .forEach((arg) => {\n throw new Error(\n \"invalid action node argument value '\" +\n arg.value +\n \"', must be string, number, boolean or null\"\n );\n });\n\n // Any node arguments that follow the action name identifier will be treated as action function arguments.\n node.actionArguments = actionArguments;\n\n // Try to pick any attributes off of the token stack.\n node.attributes = getAttributes(tokens, placeholders);\n break;\n }\n\n case \"}\": {\n // The '}' character closes the current scope.\n stack.pop();\n break;\n }\n\n default: {\n throw new Error(\"unexpected token: \" + token);\n }\n }\n }\n\n // A function to recursively validate each of the nodes in the AST.\n const validateASTNode = (node: Validatable, depth: number): void => {\n // Validate the node.\n node.validate(depth);\n\n // Validate each child of the node.\n (node.children || []).forEach((child) => validateASTNode(child, depth + 1));\n };\n\n // Start node validation from the definition root.\n validateASTNode(\n {\n children: stack[0] as RootAstNode[],\n validate(this: { children: RootAstNode[] }) {\n // We must have at least one node defined as the definition scope, which should be a root node.\n if (this.children.length === 0) {\n throw new Error(\"expected root node to have been defined\");\n }\n\n // Each node at the base of the definition scope MUST be a root node.\n for (const definitionLevelNode of this.children) {\n if (definitionLevelNode.type !== \"root\") {\n throw new Error(\"expected root node at base of definition\");\n }\n }\n\n // Exactly one root node must not have a name defined. This will be the main root, others will have to be referenced via branch nodes.\n if (this.children.filter((definitionLevelNode) => definitionLevelNode.name === null).length !== 1) {\n throw new Error(\"expected single unnamed root node at base of definition to act as main root\");\n }\n\n // No two named root nodes can have matching names.\n const rootNodeNames: string[] = [];\n for (const definitionLevelNode of this.children) {\n if (rootNodeNames.indexOf(definitionLevelNode.name!) !== -1) {\n throw new Error(`multiple root nodes found with duplicate name '${definitionLevelNode.name}'`);\n } else {\n rootNodeNames.push(definitionLevelNode.name!);\n }\n }\n }\n },\n 0\n );\n\n // Return the root AST nodes.\n return stack[0];\n}\n\n/**\n * Pop the next raw token off of the stack and throw an error if it wasn't the expected one.\n * @param tokens The array of remaining tokens.\n * @param expected An optional string or array or items, one of which must match the next popped token.\n * @returns The popped token.\n */\nfunction popAndCheck(tokens: string[], expected: string | string[]) {\n // Get and remove the next token.\n const popped = tokens.shift();\n\n // We were expecting another token.\n if (popped === undefined) {\n throw new Error(\"unexpected end of definition\");\n }\n\n // Do we have an expected token/tokens array?\n if (expected !== undefined) {\n // Check whether the popped token matches at least one of our expected items.\n var tokenMatchesExpectation = ([] as string[])\n .concat(expected)\n .some((item) => popped.toUpperCase() === item.toUpperCase());\n\n // Throw an error if the popped token didn't match any of our expected items.\n if (!tokenMatchesExpectation) {\n const expectationString = ([] as string[])\n .concat(expected)\n .map((item) => \"'\" + item + \"'\")\n .join(\" or \");\n throw new Error(\"unexpected token found. Expected \" + expectationString + \" but got '\" + popped + \"'\");\n }\n }\n\n // Return the popped token.\n return popped;\n}\n\ntype Placeholders = { [key: string]: string };\n\n/**\n * Pull an argument definition list off of the token stack.\n * @param tokens The array of remaining tokens.\n * @param stringArgumentPlaceholders The mapping of string literal node argument placeholders to original values.\n * @param argumentValidator The argument validator function.\n * @param validationFailedMessage The exception message to throw if argument validation fails.\n * @returns The argument definition list.\n */\nfunction getArguments(\n tokens: string[],\n stringArgumentPlaceholders: Placeholders,\n argumentValidator?: (arg: AnyArgument) => boolean,\n validationFailedMessage?: string\n) {\n // Any lists of arguments will always be wrapped in '[]' for node arguments or '()' for attribute arguments.\n // We are looking for a '[' or '(' opener that wraps the argument tokens and the relevant closer.\n const closer = popAndCheck(tokens, [\"[\", \"(\"]) === \"[\" ? \"]\" : \")\";\n\n const argumentListTokens: string[] = [];\n const argumentList: AnyArgument[] = [];\n\n // Grab all tokens between the '[' and ']' or '(' and ')'.\n while (tokens.length && tokens[0] !== closer) {\n // The next token is part of our arguments list.\n argumentListTokens.push(tokens.shift()!);\n }\n\n // Validate the order of the argument tokens. Each token must either be a ',' or a single argument that satisfies the validator.\n argumentListTokens.forEach((token, index) => {\n // Get whether this token should be an actual argument.\n const shouldBeArgumentToken = !(index & 1);\n\n // If the current token should be an actual argument then validate it,otherwise it should be a ',' token.\n if (shouldBeArgumentToken) {\n // Get the argument definition.\n const argumentDefinition = getArgumentDefinition(token!, stringArgumentPlaceholders);\n\n // Try to validate the argument.\n if (argumentValidator && !argumentValidator(argumentDefinition)) {\n throw new Error(validationFailedMessage);\n }\n\n // This is a valid argument!\n argumentList.push(argumentDefinition);\n } else {\n // The current token should be a ',' token.\n if (token !== \",\") {\n throw new Error(`invalid argument list, expected ',' or ']' but got '${token}'`);\n }\n }\n });\n\n // The arguments list should terminate with a ']' or ')' token, depending on the opener.\n popAndCheck(tokens, closer);\n\n // Return the argument list.\n return argumentList;\n}\n\n/**\n * Gets an argument value definition.\n * @param token The argument token.\n * @param stringArgumentPlaceholders The mapping of string literal node argument placeholders to original values.\n * @returns An argument value definition.\n */\nfunction getArgumentDefinition(token: string, stringArgumentPlaceholders: Placeholders): AnyArgument {\n // Check whether the token represents a null value.\n if (token === \"null\") {\n return {\n value: null,\n type: \"null\"\n } as NullArgument;\n }\n\n // Check whether the token represents a boolean value.\n if (token === \"true\" || token === \"false\") {\n return {\n value: token === \"true\",\n type: \"boolean\"\n } as BooleanArgument;\n }\n\n // Check whether the token represents a number value.\n // TODO: Relies on broken isNaN - see MDN.\n // if (!Number.isNaN(token)) {\n if (!isNaN(token as any)) {\n return {\n value: parseFloat(token),\n isInteger: parseFloat(token) === parseInt(token, 10),\n type: \"number\"\n } as NumberArgument;\n }\n\n // Check whether the token is a placeholder (e.g. @@0@@) representing a string literal.\n if (token.match(/^@@\\d+@@$/g)) {\n return {\n value: stringArgumentPlaceholders[token].replace('\\\\\"', '\"'),\n type: \"string\"\n } as StringPlaceholderArgument;\n }\n\n // The only remaining option is that the argument value is an identifier.\n return {\n value: token,\n type: \"identifier\"\n } as IdentifierArgument;\n}\n\n/**\n * Pull any attributes off of the token stack.\n * @param tokens The array of remaining tokens.\n * @param stringArgumentPlaceholders The mapping of string literal node argument placeholders to original values.\n * @returns An array of attributes defined by any directly following tokens.\n */\nfunction getAttributes(tokens: string[], stringArgumentPlaceholders: Placeholders) {\n // Create an array to hold any attributes found.\n const attributes: Attribute[] = [];\n\n // Keep track of names of attribute that we have found on the token stack, as we cannot have duplicates.\n const attributesFound: string[] = [];\n\n // Try to get the attribute factory for the next token.\n let attributeFactory = AttributeFactories[(tokens[0] || \"\").toUpperCase()];\n\n // Pull attribute tokens off of the tokens stack until we have no more.\n while (attributeFactory) {\n // Check to make sure that we have not already created a attribute of this type for this node.\n if (attributesFound.indexOf(tokens[0].toUpperCase()) !== -1) {\n throw new Error(`duplicate attribute '${tokens[0].toUpperCase()}' found for node`);\n }\n\n // Add the current attribute type to our array of found attributes.\n attributesFound.push(tokens.shift()!.toUpperCase());\n\n // Grab any attribute arguments.\n const attributeArguments = getArguments(tokens, stringArgumentPlaceholders);\n\n // The first attribute argument has to be an identifer, this will reference an agent function.\n if (attributeArguments.length === 0 || attributeArguments[0].type !== \"identifier\") {\n throw new Error(\"expected agent function name identifier argument for attribute\");\n }\n\n // Grab the first attribute which is an identifier that will reference an agent function.\n const attributeFunctionName = attributeArguments.shift()! as IdentifierArgument;\n\n // Any remaining attribute arguments must have a type of string, number, boolean or null.\n attributeArguments\n .filter((arg) => arg.type === \"identifier\")\n .forEach((arg) => {\n throw new Error(\n \"invalid attribute argument value '\" + arg.value + \"', must be string, number, boolean or null\"\n );\n });\n\n // Create the attribute and add it to the array of attributes found.\n attributes.push(attributeFactory(attributeFunctionName.value, attributeArguments));\n\n // Try to get the next attribute name token, as there could be multiple.\n attributeFactory = AttributeFactories[(tokens[0] || \"\").toUpperCase()];\n }\n\n return attributes;\n}\n\n/**\n * Swaps out any node/attribute argument string literals with placeholders.\n * @param definition The definition.\n * @returns An object containing a mapping of placeholders to original string values as well as the processed definition string.\n */\nfunction substituteStringLiterals(definition: string): {\n placeholders: { [key: string]: string };\n processedDefinition: string;\n} {\n // Create an object to hold the mapping of placeholders to original string values.\n const placeholders: Placeholders = {};\n\n // Replace any string literals wrapped with double quotes in our definition with placeholders to be processed later.\n const processedDefinition = definition.replace(/\\\"(\\\\.|[^\"\\\\])*\\\"/g, (match) => {\n var strippedMatch = match.substring(1, match.length - 1);\n var placeholder = Object.keys(placeholders).find((key) => placeholders[key] === strippedMatch);\n\n // If we have no existing string literal match then create a new placeholder.\n if (!placeholder) {\n placeholder = `@@${Object.keys(placeholders).length}@@`;\n placeholders[placeholder] = strippedMatch;\n }\n\n return placeholder;\n });\n\n return { placeholders, processedDefinition };\n}\n\n/**\n * Parse the tree definition into an array of raw tokens.\n * @param definition The definition.\n * @returns An array of tokens parsed from the definition.\n */\nfunction parseTokensFromDefinition(definition: string): string[] {\n // Add some space around various important characters so that they can be plucked out easier as individual tokens.\n definition = definition.replace(/\\(/g, \" ( \");\n definition = definition.replace(/\\)/g, \" ) \");\n definition = definition.replace(/\\{/g, \" { \");\n definition = definition.replace(/\\}/g, \" } \");\n definition = definition.replace(/\\]/g, \" ] \");\n definition = definition.replace(/\\[/g, \" [ \");\n definition = definition.replace(/\\,/g, \" , \");\n\n // Split the definition into raw token form and return it.\n return definition.replace(/\\s+/g, \" \").trim().split(\" \");\n}\n", "/**\r\n * Pop the next raw token from the specified array of tokens and throw an error if it wasn't the expected one.\r\n * @param tokens The array of tokens.\r\n * @param expected An optional string or array or items, one of which must match the next popped token.\r\n * @returns The popped token.\r\n */\r\nexport function popAndCheck(tokens: string[], expected?: string | string[]): string {\r\n // Get and remove the next token.\r\n const popped = tokens.shift();\r\n\r\n // We were expecting another token but there aren't any.\r\n if (popped === undefined) {\r\n throw new Error(\"unexpected end of definition\");\r\n }\r\n\r\n // Do we have an expected token/tokens array?\r\n if (expected != undefined) {\r\n // Get an array of expected values, if the popped token matches any then we are all good.\r\n const expectedValues = (typeof expected === \"string\") ? [expected] : expected;\r\n\r\n // Check whether the popped token matches at least one of our expected items.\r\n var tokenMatchesExpectation = expectedValues.some((item) => popped.toUpperCase() === item.toUpperCase());\r\n\r\n // Throw an error if the popped token didn't match any of our expected items.\r\n if (!tokenMatchesExpectation) {\r\n const expectationString = expectedValues.map((item) => \"'\" + item + \"'\").join(\" or \");\r\n throw new Error(\"unexpected token found. Expected \" + expectationString + \" but got '\" + popped + \"'\");\r\n }\r\n }\r\n\r\n // Return the popped token.\r\n return popped;\r\n}", "import { popAndCheck } from \"./DSLUtilities\";\r\n\r\n/**\r\n * A type defining the arguments that can be passed to an agent function.\r\n */\r\nexport type AgentFunctionArguments = (string | number | boolean | null | undefined)[];\r\n\r\n/**\r\n * A guard attribute for a node.\r\n */\r\nexport type GuardAttributeDefinition = {\r\n call: string;\r\n args?: AgentFunctionArguments;\r\n}\r\n\r\n/**\r\n * A callback attribute for a node.\r\n */\r\nexport type CallbackAttributeDefinition = {\r\n call: string;\r\n args?: AgentFunctionArguments;\r\n}\r\n\r\n/**\r\n * A type defining a general node definition.\r\n */\r\nexport type NodeDefinition = {\r\n type: string;\r\n while?: GuardAttributeDefinition;\r\n until?: GuardAttributeDefinition;\r\n entry?: CallbackAttributeDefinition;\r\n exit?: CallbackAttributeDefinition;\r\n step?: CallbackAttributeDefinition;\r\n}\r\n\r\n/**\r\n * A composite node that can contain any number of child nodes.\r\n */\r\nexport type CompositeDefinition = NodeDefinition & {\r\n children: AnyChildNode[];\r\n}\r\n\r\n/**\r\n * A decorator node, a composite with only a single child node.\r\n */\r\nexport type DecoratorDefinition = NodeDefinition & {\r\n child: AnyChildNode;\r\n}\r\n\r\n/**\r\n * A branch node.\r\n */\r\nexport type BranchDefinition = NodeDefinition & {\r\n type: \"branch\";\r\n ref: string;\r\n}\r\n\r\n/**\r\n * An action node.\r\n */\r\nexport type ActionDefinition = NodeDefinition & {\r\n type: \"action\";\r\n call: string;\r\n args?: AgentFunctionArguments;\r\n}\r\n\r\n/**\r\n * A condition node.\r\n */\r\nexport type ConditionDefinition = NodeDefinition & {\r\n type: \"condition\";\r\n call: string;\r\n args?: AgentFunctionArguments;\r\n}\r\n\r\n/**\r\n * A wait node.\r\n */\r\nexport type WaitDefinition = NodeDefinition & {\r\n type: \"wait\";\r\n duration: number | [number, number];\r\n}\r\n\r\n/**\r\n * A sequence node.\r\n */\r\nexport type SequenceDefinition = CompositeDefinition & {\r\n type: \"sequence\";\r\n}\r\n\r\n/**\r\n * A selector node.\r\n */\r\nexport type SelectorDefinition = CompositeDefinition & {\r\n type: \"selector\";\r\n}\r\n\r\n/**\r\n * A lotto node.\r\n */\r\nexport type LottoDefinition = CompositeDefinition & {\r\n type: \"lotto\";\r\n weights?: number[]\r\n}\r\n\r\n/**\r\n * A parallel node.\r\n */\r\nexport type ParallelDefinition = CompositeDefinition & {\r\n type: \"parallel\";\r\n}\r\n\r\n/**\r\n * A root node.\r\n */\r\nexport type RootDefinition = DecoratorDefinition & {\r\n type: \"root\";\r\n id?: string;\r\n}\r\n\r\n/**\r\n * A repeat node.\r\n */\r\nexport type RepeatDefinition = DecoratorDefinition & {\r\n type: \"repeat\";\r\n iterations?: number | [number, number];\r\n}\r\n\r\n/**\r\n * A retry node.\r\n */\r\nexport type RetryDefinition = DecoratorDefinition & {\r\n type: \"retry\";\r\n attempts?: number | [number, number];\r\n}\r\n\r\n/**\r\n * A flip node.\r\n */\r\nexport type FlipDefinition = DecoratorDefinition & {\r\n type: \"flip\";\r\n}\r\n\r\n/**\r\n * A succeed node.\r\n */\r\nexport type SucceedDefinition = DecoratorDefinition & {\r\n type: \"succeed\";\r\n}\r\n\r\n/**\r\n * A fail node.\r\n */\r\nexport type FailDefinition = DecoratorDefinition & {\r\n type: \"fail\";\r\n}\r\n\r\n/**\r\n * A type defining any node type.\r\n */\r\nexport type AnyNode = BranchDefinition | ActionDefinition | ConditionDefinition | WaitDefinition | SequenceDefinition |\r\n SelectorDefinition | LottoDefinition | ParallelDefinition | RootDefinition | RepeatDefinition | RetryDefinition | FlipDefinition | SucceedDefinition | FailDefinition;\r\n\r\n/**\r\n * A type defining any node type that can be a child of composite parent node.\r\n */\r\nexport type AnyChildNode = Exclude;\r\n\r\n/**\r\n * A type defining an object that holds a reference to substitued string literals parsed from the definition.\r\n */\r\ntype StringLiteralPlaceholders = { [key: string]: string };\r\n\r\nfunction isLeafNode(node: NodeDefinition): node is NodeDefinition {\r\n return [\"branch\", \"action\", \"condition\", \"wait\"].includes(node.type);\r\n}\r\n\r\nfunction isDecoratorNode(node: NodeDefinition): node is DecoratorDefinition {\r\n return [\"root\", \"repeat\", \"retry\", \"flip\", \"succeed\", \"fail\"].includes(node.type);\r\n}\r\n\r\nfunction isCompositeNode(node: NodeDefinition): node is CompositeDefinition {\r\n return [\"sequence\", \"selector\", \"lotto\", \"parallel\"].includes(node.type);\r\n}\r\n\r\n/**\r\n * Parse the tree definition string into a JSON definition.\r\n * @param definition The tree definition string.\r\n * @returns The root node JSON definitions.\r\n */\r\nexport function parseToJSON(definition: string): RootDefinition[] {\r\n // Swap out any node/attribute argument string literals with a placeholder and get a mapping of placeholders to original values as well as the processed definition.\r\n const { placeholders, processedDefinition } = substituteStringLiterals(definition);\r\n\r\n // Parse our definition definition string into an array of raw tokens.\r\n const tokens = parseTokensFromDefinition(definition);\r\n\r\n return convertTokensToJSONDefinition(tokens, placeholders, processedDefinition);\r\n}\r\n\r\n/**\r\n * Converts the specified tree definition tokens into a JSON definition.\r\n * @param tokens The tree definition tokens.\r\n * @param placeholders The substituted string literal placeholders.\r\n * @returns The root node JSON definitions.\r\n */\r\nexport function convertTokensToJSONDefinition(tokens: string[], placeholders: StringLiteralPlaceholders, processedDefinition: string): RootDefinition[] {\r\n // There must be at least 3 tokens for the tree definition to be valid. 'ROOT', '{' and '}'.\r\n if (tokens.length < 3) {\r\n throw new Error(\"invalid token count\");\r\n }\r\n\r\n // We should have a matching number of '{' and '}' tokens. If not, then there are scopes that have not been properly closed.\r\n if (tokens.filter((token) => token === \"{\").length !== tokens.filter((token) => token === \"}\").length) {\r\n throw new Error(\"scope character mismatch\");\r\n }\r\n\r\n // Create a stack of tree stack arrays where root nodes will always be at the root.\r\n const treeStacks: [Partial, ...Partial[]][] = [];\r\n\r\n // Create an array of all root node definitions that we create.\r\n const rootNodes: Partial[] = [];\r\n\r\n // A helper function used to push root node definitions onto the stack.\r\n const pushRootNode = (rootNode: RootDefinition) => {\r\n // Add the root node definition to our array of all parsed root node definitions.\r\n rootNodes.push(rootNode);\r\n\r\n // Add the root node definition to the root of a new tree stack. \r\n treeStacks.push([rootNode]);\r\n }\r\n \r\n // A helper function used to push non-root node definitions onto the stack.\r\n const pushNode = (node: AnyChildNode) => {\r\n // Get the current tree stack that we are populating.\r\n const currentTreeStack = treeStacks[treeStacks.length - 1];\r\n\r\n // TODO Handle cases where we may not have a current root stack.\r\n // This may happen if a root node is not the initially defined one?\r\n\r\n // Get the bottom-most node in the current tree stack.\r\n const bottomNode = currentTreeStack[currentTreeStack.length - 1] as AnyNode;\r\n\r\n // TODO Handle cases where we may not have a bottom-most node.\r\n // Also a potential issue with a badly defined tree.\r\n\r\n // If the bottom-most node in the current root stack is a composite or decorator\r\n // node then the current node should be added as a child of the bottom-most node.\r\n if (isCompositeNode(bottomNode)) {\r\n bottomNode.children = bottomNode.children || [];\r\n bottomNode.children.push(node);\r\n } else if (isDecoratorNode(bottomNode)) {\r\n // If the bottom node already has a chld node set then throw an error as a decorator should only have a single child.\r\n if (bottomNode.child) {\r\n throw new Error(\"a decorator node must only have a single child node\");\r\n }\r\n\r\n bottomNode.child = node;\r\n }\r\n\r\n // If the node we are adding is also a composite or decorator node, then we should push it \r\n // onto the current tree stack, as subsequent nodes will be added as its child/children.\r\n if (!isLeafNode(node)) {\r\n currentTreeStack.push(node);\r\n }\r\n };\r\n\r\n // A helper function used to pop node definitions off of the stack.\r\n const popNode = () => {\r\n // Get the current tree stack that we are populating.\r\n const currentTreeStack = treeStacks[treeStacks.length - 1];\r\n\r\n // Pop the top-most node in the current tree stack if there is one.\r\n if (currentTreeStack.length) {\r\n currentTreeStack.pop();\r\n }\r\n\r\n // We don't want any empty tree stacks in our stack of tree stacks. \r\n if (!currentTreeStack.length) {\r\n treeStacks.pop();\r\n }\r\n };\r\n\r\n // We should keep processing the raw tokens until we run out of them.\r\n while (tokens.length) {\r\n // Grab the next token.\r\n const token = tokens.shift()!;\r\n\r\n // How we create the next node depends on the current raw token value.\r\n switch (token.toUpperCase()) {\r\n case \"ROOT\": {\r\n // A root node will always be the base of a new root stack.\r\n pushRootNode(createRootNode(tokens));\r\n break;\r\n }\r\n\r\n case \"SEQUENCE\": {\r\n pushNode(createSequenceNode(tokens));\r\n break;\r\n }\r\n\r\n case \"ACTION\": {\r\n pushNode(createActionNode(tokens));\r\n break;\r\n }\r\n\r\n case \"}\": {\r\n // The '}' character closes the current scope and means that we have to pop a node off of the current stack.\r\n popNode();\r\n break;\r\n }\r\n\r\n default: {\r\n throw new Error(\"unexpected token: \" + token);\r\n }\r\n }\r\n }\r\n\r\n return rootNodes as RootDefinition[];\r\n}\r\n\r\nfunction createRootNode(tokens: string[]): RootDefinition {\r\n // Create the root node definition.\r\n const node = { type: \"root\" } as RootDefinition;\r\n\r\n // TODO Grab 'id' if defined as a node argument.\r\n // TODO Grab attributes.\r\n\r\n // This is a decorator node, so we expect an opening '{'.\r\n popAndCheck(tokens, \"{\");\r\n\r\n return node;\r\n}\r\n\r\nfunction createSequenceNode(tokens: string[]): SequenceDefinition {\r\n const node = { type: \"sequence\" } as SequenceDefinition;\r\n\r\n // TODO Grab attributes.\r\n\r\n // This is a composite node, so we expect an opening '{'.\r\n popAndCheck(tokens, \"{\");\r\n\r\n return node;\r\n}\r\n\r\nfunction createActionNode(tokens: string[]): ActionDefinition {\r\n const node = { type: \"action\" } as ActionDefinition;\r\n\r\n // TODO Grab attributes.\r\n\r\n return node;\r\n}\r\n\r\n/**\r\n * Swaps out any node/attribute argument string literals with placeholders.\r\n * @param definition The definition.\r\n * @returns An object containing a mapping of placeholders to original string values as well as the processed definition string.\r\n */\r\nfunction substituteStringLiterals(definition: string): {\r\n placeholders: StringLiteralPlaceholders;\r\n processedDefinition: string;\r\n} {\r\n // Create an object to hold the mapping of placeholders to original string values.\r\n const placeholders: StringLiteralPlaceholders = {};\r\n\r\n // Replace any string literals wrapped with double quotes in our definition with placeholders to be processed later.\r\n const processedDefinition = definition.replace(/\\\"(\\\\.|[^\"\\\\])*\\\"/g, (match) => {\r\n var strippedMatch = match.substring(1, match.length - 1);\r\n var placeholder = Object.keys(placeholders).find((key) => placeholders[key] === strippedMatch);\r\n\r\n // If we have no existing string literal match then create a new placeholder.\r\n if (!placeholder) {\r\n placeholder = `@@${Object.keys(placeholders).length}@@`;\r\n placeholders[placeholder] = strippedMatch;\r\n }\r\n\r\n return placeholder;\r\n });\r\n\r\n return { placeholders, processedDefinition };\r\n}\r\n\r\n/**\r\n * Parse the tree definition into an array of raw tokens.\r\n * @param definition The definition.\r\n * @returns An array of tokens parsed from the definition.\r\n */\r\nfunction parseTokensFromDefinition(definition: string): string[] {\r\n // Add some space around various important characters so that they can be plucked out easier as individual tokens.\r\n definition = definition.replace(/\\(/g, \" ( \");\r\n definition = definition.replace(/\\)/g, \" ) \");\r\n definition = definition.replace(/\\{/g, \" { \");\r\n definition = definition.replace(/\\}/g, \" } \");\r\n definition = definition.replace(/\\]/g, \" ] \");\r\n definition = definition.replace(/\\[/g, \" [ \");\r\n definition = definition.replace(/\\,/g, \" , \");\r\n\r\n // Split the definition into raw token form and return it.\r\n return definition.replace(/\\s+/g, \" \").trim().split(\" \");\r\n}", "import GuardPath, { GuardPathPart } from \"./attributes/guards/GuardPath\";\nimport buildRootASTNodes, { AnyArgument, RootAstNode } from \"./RootAstNodesBuilder\";\nimport State, { AnyState } from \"./State\";\nimport Lookup from \"./Lookup\";\nimport Node from \"./nodes/Node\";\nimport Root from \"./nodes/decorator/Root\";\nimport Composite from \"./nodes/composite/Composite\";\nimport Decorator from \"./nodes/decorator/Decorator\";\nimport { Agent, GlobalFunction } from \"./Agent\";\nimport { CallbackAttributeDetails } from \"./attributes/callbacks/Callback\";\nimport { GuardAttributeDetails } from \"./attributes/guards/Guard\";\nimport { BehaviourTreeOptions } from \"./BehaviourTreeOptions\";\nimport { parseToJSON } from \"./dsl/DSLDefinitionParser\";\n\n// Purely for outside inspection of the tree.\nexport type FlattenedTreeNode = {\n id: string;\n type: string;\n caption: string;\n state: AnyState;\n guards: GuardAttributeDetails[];\n callbacks: CallbackAttributeDetails[];\n args: AnyArgument[];\n parentId: string | null;\n};\n\n/**\n * A representation of a behaviour tree.\n */\nexport class BehaviourTree {\n /**\n * The main root tree node.\n */\n public readonly rootNode: Root;\n\n /**\n * Creates a new instance of the BehaviourTree class.\n * @param definition The behaviour tree definition.\n * @param agent The agent instance that this behaviour tree is modelling behaviour for.\n * @param options The behaviour tree options object.\n */\n constructor(definition: string, private agent: Agent, private options: BehaviourTreeOptions = {}) {\n // The tree definition must be defined and a valid string.\n if (typeof definition !== \"string\") {\n throw new Error(\"the tree definition must be a string\");\n }\n\n // The agent must be defined and not null.\n if (typeof agent !== \"object\" || agent === null) {\n throw new Error(\"the agent must be defined and not null\");\n }\n\n // Parse the behaviour tree definition, create the populated tree of behaviour tree nodes, and get the root.\n this.rootNode = BehaviourTree._createRootNode(definition);\n }\n\n /**\n * Gets whether the tree is in the RUNNING state.\n * @returns true if the tree is in the RUNNING state, otherwise false.\n */\n isRunning() {\n return this.rootNode.getState() === State.RUNNING;\n }\n\n /**\n * Gets the current tree state of SUCCEEDED, FAILED, READY or RUNNING.\n * @returns The current tree state.\n */\n getState() {\n return this.rootNode.getState();\n }\n\n /**\n * Step the tree.\n * 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.\n * 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\n * 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.\n *\n * 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.\n */\n step() {\n // If the root node has already been stepped to completion then we need to reset it.\n if (this.rootNode.getState() === State.SUCCEEDED || this.rootNode.getState() === State.FAILED) {\n this.rootNode.reset();\n }\n\n try {\n this.rootNode.update(this.agent, this.options);\n } catch (exception) {\n throw new Error(`error stepping tree: ${(exception as Error).message}`);\n }\n }\n\n /**\n * Resets the tree from the root node outwards to each nested node, giving each a state of READY.\n */\n reset() {\n this.rootNode.reset();\n }\n\n /**\n * Gets the flattened details of every node in the tree.\n * @returns The flattened details of every node in the tree.\n */\n getFlattenedNodeDetails(): FlattenedTreeNode[] {\n // Create an empty flattened array of tree nodes.\n const flattenedTreeNodes: FlattenedTreeNode[] = [];\n\n /**\n * Helper function to process a node instance and push details into the flattened tree nodes array.\n * @param node The current node.\n * @param parentUid The UID of the node parent, or null if the node is the main root node.\n */\n const processNode = (node: Node, parentUid: string | null) => {\n // Get the guard and callback attribute details for this node.\n const guards = node\n .getAttributes()\n .filter((attribute) => attribute.isGuard())\n .map((attribute) => attribute.getDetails()) as GuardAttributeDetails[];\n const callbacks = node\n .getAttributes()\n .filter((attribute) => !attribute.isGuard())\n .map((attribute) => attribute.getDetails()) as CallbackAttributeDetails[];\n\n // Push the current node into the flattened nodes array.\n flattenedTreeNodes.push({\n id: node.getUid(),\n type: node.getType(),\n caption: node.getName(),\n state: node.getState(),\n guards,\n callbacks,\n args: node.getArguments(),\n parentId: parentUid\n });\n\n // Process each of the nodes children if it is not a leaf node.\n if (!node.isLeafNode()) {\n (node as Composite | Decorator)\n .getChildren()\n .forEach((child) => processNode(child, (node as Composite | Decorator).getUid()));\n }\n };\n\n // Convert the nested node structure into a flattened array of node details.\n processNode(this.rootNode, null);\n\n return flattenedTreeNodes;\n }\n\n /**\n * Registers the action/condition/guard/callback function or subtree with the given name.\n * @param name The name of the function or subtree to register.\n * @param value The function or subtree definition to register.\n */\n static register(name: string, value: GlobalFunction | string) {\n if (typeof value === \"function\") {\n // We are going to register a action/condition/guard/callback function.\n Lookup.setFunc(name, value);\n } else if (typeof value === \"string\") {\n // We are going to register a subtree.\n let rootASTNodes: RootAstNode[];\n\n try {\n // Try to create the behaviour tree AST based on the definition provided, this could fail if the definition is invalid.\n rootASTNodes = buildRootASTNodes(value);\n } catch (exception) {\n // There was an issue in trying to parse and build the tree definition.\n throw new Error(`error registering definition: ${(exception as Error).message}`);\n }\n\n // This function should only ever be called with a definition containing a single unnamed root node.\n if (rootASTNodes.length != 1 || rootASTNodes[0].name !== null) {\n throw new Error(\"error registering definition: expected a single unnamed root node\");\n }\n\n Lookup.setSubtree(name, rootASTNodes[0]);\n } else {\n throw new Error(\"unexpected value, expected string definition or function\");\n }\n }\n\n /**\n * Unregisters the registered action/condition/guard/callback function or subtree with the given name.\n * @param name The name of the registered action/condition/guard/callback function or subtree to unregister.\n */\n static unregister(name: string): void {\n Lookup.remove(name);\n }\n\n /**\n * Unregister all registered action/condition/guard/callback functions and subtrees.\n */\n static unregisterAll(): void {\n Lookup.empty();\n }\n\n /**\n * Parses a behaviour tree definition and creates a tree of behaviour tree nodes.\n * @param {string} definition The behaviour tree definition.\n * @returns The root behaviour tree node.\n */\n private static _createRootNode(definition: string): Root {\n // TODO Remove!\n try {\n parseToJSON(definition);\n } catch (exception) {\n console.log(exception);\n }\n\n try {\n // Try to create the behaviour tree AST based on the definition provided, this could fail if the definition is invalid.\n const rootASTNodes = buildRootASTNodes(definition);\n\n // Create a symbol to use as the main root key in our root node mapping.\n const mainRootNodeKey = Symbol(\"__root__\");\n\n // Create a mapping of root node names to root AST tokens. The main root node will have a key of Symbol(\"__root__\").\n const rootNodeMap: { [key: string | symbol]: RootAstNode } = {};\n for (const rootASTNode of rootASTNodes) {\n rootNodeMap[rootASTNode.name === null ? mainRootNodeKey : rootASTNode.name!] = rootASTNode;\n }\n\n // Convert the AST to our actual tree and get the root node.\n const rootNode: Root = rootNodeMap[mainRootNodeKey].createNodeInstance(\n // Create a provider for named root nodes that are part of our definition or have been registered. Prioritising the former.\n (name: string): RootAstNode => (rootNodeMap[name] ? rootNodeMap[name] : Lookup.getSubtree(name)),\n []\n );\n\n // Set a guard path on every leaf of the tree to evaluate as part of its update.\n BehaviourTree._applyLeafNodeGuardPaths(rootNode);\n\n // Return the root node.\n return rootNode;\n } catch (exception) {\n // There was an issue in trying to parse and build the tree definition.\n throw new Error(`error parsing tree: ${(exception as Error).message}\\n${(exception as Error).stack}`);\n }\n }\n\n /**\n * Applies a guard path to every leaf of the tree to evaluate as part of each update.\n * @param rootNode The main root tree node.\n */\n private static _applyLeafNodeGuardPaths(rootNode: Root) {\n const nodePaths: Node[][] = [];\n\n const findLeafNodes = (path: Node[], node: Node) => {\n // Add the current node to the path.\n path = path.concat(node);\n\n // Check whether the current node is a leaf node.\n if (node.isLeafNode()) {\n nodePaths.push(path);\n } else {\n (node as Composite | Decorator).getChildren().forEach((child) => findLeafNodes(path, child));\n }\n };\n\n // Find all leaf node paths, starting from the root.\n findLeafNodes([], rootNode);\n\n nodePaths.forEach((path) => {\n // Each node in the current path will have to be assigned a guard path, working from the root outwards.\n for (let depth = 0; depth < path.length; depth++) {\n // Get the node in the path at the current depth.\n const currentNode = path[depth];\n\n // The node may already have been assigned a guard path, if so just skip it.\n if (currentNode.hasGuardPath()) {\n continue;\n }\n\n // Create the guard path for the current node.\n const guardPath = new GuardPath(\n path\n .slice(0, depth + 1)\n .map((node) => ({ node, guards: node.getGuardAttributes() }))\n .filter((details) => details.guards.length > 0)\n );\n\n // Assign the guard path to the current node.\n currentNode.setGuardPath(guardPath);\n }\n });\n }\n}\n"], + "mappings": "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", + "names": ["Participant", "Lotto", "createLotto", "State", "createLotto", "popAndCheck", "substituteStringLiterals", "parseTokensFromDefinition", "popAndCheck"] } diff --git a/src/BehaviourTree.ts b/src/BehaviourTree.ts index bfd4840..c2a69fa 100644 --- a/src/BehaviourTree.ts +++ b/src/BehaviourTree.ts @@ -10,7 +10,7 @@ import { Agent, GlobalFunction } from "./Agent"; import { CallbackAttributeDetails } from "./attributes/callbacks/Callback"; import { GuardAttributeDetails } from "./attributes/guards/Guard"; import { BehaviourTreeOptions } from "./BehaviourTreeOptions"; -import { parseToJSON } from "./DSLParser"; +import { parseToJSON } from "./dsl/DSLDefinitionParser"; // Purely for outside inspection of the tree. export type FlattenedTreeNode = { @@ -51,7 +51,7 @@ export class BehaviourTree { } // Parse the behaviour tree definition, create the populated tree of behaviour tree nodes, and get the root. - this.rootNode = BehaviourTree.createRootNode(definition); + this.rootNode = BehaviourTree._createRootNode(definition); } /** @@ -200,7 +200,7 @@ export class BehaviourTree { * @param {string} definition The behaviour tree definition. * @returns The root behaviour tree node. */ - private static createRootNode(definition: string): Root { + private static _createRootNode(definition: string): Root { // TODO Remove! try { parseToJSON(definition); @@ -229,7 +229,7 @@ export class BehaviourTree { ); // Set a guard path on every leaf of the tree to evaluate as part of its update. - BehaviourTree.applyLeafNodeGuardPaths(rootNode); + BehaviourTree._applyLeafNodeGuardPaths(rootNode); // Return the root node. return rootNode; @@ -243,7 +243,7 @@ export class BehaviourTree { * 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(rootNode: Root) { + private static _applyLeafNodeGuardPaths(rootNode: Root) { const nodePaths: Node[][] = []; const findLeafNodes = (path: Node[], node: Node) => { diff --git a/src/DSLParser.ts b/src/dsl/DSLDefinitionParser.ts similarity index 79% rename from src/DSLParser.ts rename to src/dsl/DSLDefinitionParser.ts index 4d81963..bcec8ac 100644 --- a/src/DSLParser.ts +++ b/src/dsl/DSLDefinitionParser.ts @@ -1,3 +1,5 @@ +import { popAndCheck } from "./DSLUtilities"; + /** * A type defining the arguments that can be passed to an agent function. */ @@ -219,11 +221,7 @@ export function convertTokensToJSONDefinition(tokens: string[], placeholders: St // Create an array of all root node definitions that we create. const rootNodes: Partial[] = []; - // ONLY COMPOSITE DEFINITIONS GET PUSHED ONTO A ROOT STACK. - // When coming across a new node in the definition it must be: - // - Set as the child of the top-most node in the root stack OR - // - Added to the array of children of the top-most node in the root stack OR - + // A helper function used to push root node definitions onto the stack. const pushRootNode = (rootNode: RootDefinition) => { // Add the root node definition to our array of all parsed root node definitions. rootNodes.push(rootNode); @@ -232,6 +230,7 @@ export function convertTokensToJSONDefinition(tokens: string[], placeholders: St treeStacks.push([rootNode]); } + // A helper function used to push non-root node definitions onto the stack. const pushNode = (node: AnyChildNode) => { // Get the current tree stack that we are populating. const currentTreeStack = treeStacks[treeStacks.length - 1]; @@ -251,6 +250,11 @@ export function convertTokensToJSONDefinition(tokens: string[], placeholders: St bottomNode.children = bottomNode.children || []; bottomNode.children.push(node); } else if (isDecoratorNode(bottomNode)) { + // If the bottom node already has a chld node set then throw an error as a decorator should only have a single child. + if (bottomNode.child) { + throw new Error("a decorator node must only have a single child node"); + } + bottomNode.child = node; } @@ -261,6 +265,7 @@ export function convertTokensToJSONDefinition(tokens: string[], placeholders: St } }; + // A helper function used to pop node definitions off of the stack. const popNode = () => { // Get the current tree stack that we are populating. const currentTreeStack = treeStacks[treeStacks.length - 1]; @@ -279,53 +284,28 @@ export function convertTokensToJSONDefinition(tokens: string[], placeholders: St // We should keep processing the raw tokens until we run out of them. while (tokens.length) { // Grab the next token. - const token = tokens.shift(); + const token = tokens.shift()!; // How we create the next node depends on the current raw token value. - switch (token!.toUpperCase()) { + switch (token.toUpperCase()) { case "ROOT": { - const node = { - type: "root" - } as RootDefinition; - - // TODO Grab 'id' if defined as a node argument. - // TODO Grab attributes. - - // This is a decorator node, so we expect an opening '{'. - popAndCheck(tokens, "{"); - // A root node will always be the base of a new root stack. - pushRootNode(node); + pushRootNode(createRootNode(tokens)); break; } case "SEQUENCE": { - const node = { - type: "sequence" - } as SequenceDefinition; - - // TODO Grab attributes. - - // This is a composite node, so we expect an opening '{'. - popAndCheck(tokens, "{"); - - pushNode(node); + pushNode(createSequenceNode(tokens)); break; } case "ACTION": { - const node = { - type: "action" - } as ActionDefinition; - - // TODO Grab attributes. - - pushNode(node); + pushNode(createActionNode(tokens)); break; } case "}": { - // The '}' character closes the current scope. + // The '}' character closes the current scope and means that we have to pop a node off of the current stack. popNode(); break; } @@ -336,13 +316,41 @@ export function convertTokensToJSONDefinition(tokens: string[], placeholders: St } } - // TODO Remove! - console.log(rootNodes); - - // TODO return rootNodes as RootDefinition[]; } +function createRootNode(tokens: string[]): RootDefinition { + // Create the root node definition. + const node = { type: "root" } as RootDefinition; + + // TODO Grab 'id' if defined as a node argument. + // TODO Grab attributes. + + // This is a decorator node, so we expect an opening '{'. + popAndCheck(tokens, "{"); + + return node; +} + +function createSequenceNode(tokens: string[]): SequenceDefinition { + const node = { type: "sequence" } as SequenceDefinition; + + // TODO Grab attributes. + + // This is a composite node, so we expect an opening '{'. + popAndCheck(tokens, "{"); + + return node; +} + +function createActionNode(tokens: string[]): ActionDefinition { + const node = { type: "action" } as ActionDefinition; + + // TODO Grab attributes. + + return node; +} + /** * Swaps out any node/attribute argument string literals with placeholders. * @param definition The definition. @@ -389,38 +397,4 @@ function parseTokensFromDefinition(definition: string): string[] { // Split the definition into raw token form and return it. return definition.replace(/\s+/g, " ").trim().split(" "); -} - -/** - * Pop the next raw token off of the stack and throw an error if it wasn't the expected one. - * @param tokens The array of remaining tokens. - * @param expected An optional string or array or items, one of which must match the next popped token. - * @returns The popped token. - */ -function popAndCheck(tokens: string[], expected?: string | string[]): string { - // Get and remove the next token. - const popped = tokens.shift(); - - // We were expecting another token. - if (popped === undefined) { - throw new Error("unexpected end of definition"); - } - - // Do we have an expected token/tokens array? - if (expected != undefined) { - // Get an array of expected values, if the popped token matches any then we are all good. - const expectedValues = (typeof expected === "string") ? [expected] : expected; - - // Check whether the popped token matches at least one of our expected items. - var tokenMatchesExpectation = expectedValues.some((item) => popped.toUpperCase() === item.toUpperCase()); - - // Throw an error if the popped token didn't match any of our expected items. - if (!tokenMatchesExpectation) { - const expectationString = expectedValues.map((item) => "'" + item + "'").join(" or "); - throw new Error("unexpected token found. Expected " + expectationString + " but got '" + popped + "'"); - } - } - - // Return the popped token. - return popped; } \ No newline at end of file diff --git a/src/dsl/DSLNodeArgumentParser.ts b/src/dsl/DSLNodeArgumentParser.ts new file mode 100644 index 0000000..7f93bd5 --- /dev/null +++ b/src/dsl/DSLNodeArgumentParser.ts @@ -0,0 +1,152 @@ +import { popAndCheck } from "./DSLUtilities"; + +type Placeholders = { [key: string]: string }; + +export type Argument = { + /** The argument value. */ + value: T; + /** The argument type, used for validation. */ + type: string; +}; + +type NullArgument = Argument & { + type: "null"; +}; + +type BooleanArgument = Argument & { + type: "boolean"; +}; + +type NumberArgument = Argument & { + type: "number"; + isInteger: boolean; // Used for validation. +}; + +type StringPlaceholderArgument = Argument & { + type: "string"; +}; + +type IdentifierArgument = Argument & { + type: "identifier"; +}; + +export type AnyArgument = + | NullArgument + | BooleanArgument + | NumberArgument + | StringPlaceholderArgument + | IdentifierArgument; + +/** + * Parse an array of argument definitions from the specified tokens array. + * @param tokens The array tokens to parse the argument definitions from. + * @param stringArgumentPlaceholders The mapping of string literal node argument placeholders to original values. + * @param argumentValidator The argument validator function. + * @param validationFailedMessage The exception message to throw if argument validation fails. + * @returns An array of argument definitions parsed from the specified tokens array. + */ +export function getArguments( + tokens: string[], + stringArgumentPlaceholders: Placeholders, + argumentValidator?: (arg: AnyArgument) => boolean, + validationFailedMessage?: string +): AnyArgument[] { + const argumentList: AnyArgument[] = []; + + // If the next token is not a '[' or '(' then we have no arguments to parse. + if (!["[","("].includes(tokens[0])) { + return argumentList; + }; + + // Any lists of arguments will always be wrapped in '[]' for node arguments or '()' for attribute arguments. + // We are looking for a '[' or '(' opener that wraps the argument tokens and the relevant closer. + const closer = popAndCheck(tokens, ["[", "("]) === "[" ? "]" : ")"; + + const argumentListTokens: string[] = []; + + // Grab all tokens between the '[' and ']' or '(' and ')'. + while (tokens.length && tokens[0] !== closer) { + // The next token is part of our arguments list. + argumentListTokens.push(tokens.shift()!); + } + + // Validate the order of the argument tokens. Each token must either be a ',' or a single argument that satisfies the validator. + argumentListTokens.forEach((token, index) => { + // Get whether this token should be an actual argument. + const shouldBeArgumentToken = !(index & 1); + + // If the current token should be an actual argument then validate it, otherwise it should be a ',' token. + if (shouldBeArgumentToken) { + // Get the argument definition. + const argumentDefinition = getArgumentDefinition(token, stringArgumentPlaceholders); + + // Try to validate the argument. + if (argumentValidator && !argumentValidator(argumentDefinition)) { + throw new Error(validationFailedMessage); + } + + // This is a valid argument! + argumentList.push(argumentDefinition); + } else { + // The current token should be a ',' token. + if (token !== ",") { + throw new Error(`invalid argument list, expected ',' or ']' but got '${token}'`); + } + } + }); + + // The arguments list should terminate with a ']' or ')' token, depending on the opener. + popAndCheck(tokens, closer); + + // Return the arguments. + return argumentList; +} + +/** + * Gets an argument value definition. + * @param token The argument token. + * @param stringArgumentPlaceholders The mapping of string literal node argument placeholders to original values. + * @returns An argument value definition. + */ +function getArgumentDefinition(token: string, stringArgumentPlaceholders: Placeholders): AnyArgument { + // Check whether the token represents a null value. + if (token === "null") { + return { + value: null, + type: "null" + } as NullArgument; + } + + // Check whether the token represents a boolean value. + if (token === "true" || token === "false") { + return { + value: token === "true", + type: "boolean" + } as BooleanArgument; + } + + // Check whether the token represents a number value. + // TODO: Relies on broken isNaN - see MDN. + // if (!Number.isNaN(token)) { + if (!isNaN(token as any)) { + return { + value: parseFloat(token), + isInteger: parseFloat(token) === parseInt(token, 10), + type: "number" + } as NumberArgument; + } + + // Check whether the token is a placeholder (e.g. @@0@@) representing a string literal. + if (token.match(/^@@\d+@@$/g)) { + return { + value: stringArgumentPlaceholders[token].replace('\\"', '"'), + type: "string" + } as StringPlaceholderArgument; + } + + // The only remaining option is that the argument value is an identifier. + return { + value: token, + type: "identifier" + } as IdentifierArgument; +} \ No newline at end of file diff --git a/src/dsl/DSLUtilities.ts b/src/dsl/DSLUtilities.ts new file mode 100644 index 0000000..d165555 --- /dev/null +++ b/src/dsl/DSLUtilities.ts @@ -0,0 +1,33 @@ +/** + * Pop the next raw token from the specified array of tokens and throw an error if it wasn't the expected one. + * @param tokens The array of tokens. + * @param expected An optional string or array or items, one of which must match the next popped token. + * @returns The popped token. + */ +export function popAndCheck(tokens: string[], expected?: string | string[]): string { + // Get and remove the next token. + const popped = tokens.shift(); + + // We were expecting another token but there aren't any. + if (popped === undefined) { + throw new Error("unexpected end of definition"); + } + + // Do we have an expected token/tokens array? + if (expected != undefined) { + // Get an array of expected values, if the popped token matches any then we are all good. + const expectedValues = (typeof expected === "string") ? [expected] : expected; + + // Check whether the popped token matches at least one of our expected items. + var tokenMatchesExpectation = expectedValues.some((item) => popped.toUpperCase() === item.toUpperCase()); + + // Throw an error if the popped token didn't match any of our expected items. + if (!tokenMatchesExpectation) { + const expectationString = expectedValues.map((item) => "'" + item + "'").join(" or "); + throw new Error("unexpected token found. Expected " + expectationString + " but got '" + popped + "'"); + } + } + + // Return the popped token. + return popped; +} \ No newline at end of file From cf84399fe30581af2a97f6cdb1417a0bb3574f35 Mon Sep 17 00:00:00 2001 From: Nikolas Howard Date: Fri, 29 Sep 2023 08:43:58 +0100 Subject: [PATCH 07/48] Tidying --- dist/Agent.d.ts | 12 + dist/BehaviourTree.d.ts | 89 + dist/BehaviourTreeOptions.d.ts | 15 + dist/Lookup.d.ts | 63 + dist/RootAstNodesBuilder.d.ts | 104 + dist/State.d.ts | 12 + dist/attributes/Attribute.d.ts | 36 + dist/attributes/callbacks/Callback.d.ts | 36 + dist/attributes/callbacks/Entry.d.ts | 18 + dist/attributes/callbacks/Exit.d.ts | 20 + dist/attributes/callbacks/Step.d.ts | 18 + dist/attributes/guards/Guard.d.ts | 37 + dist/attributes/guards/GuardPath.d.ts | 23 + .../guards/GuardUnsatisifedException.d.ts | 17 + dist/attributes/guards/Until.d.ts | 19 + dist/attributes/guards/While.d.ts | 19 + dist/bundle.js | 1860 ++++++++++++++++ dist/bundle.js.map | 7 + dist/dsl/DSLDefinitionParser.d.ts | 163 ++ dist/dsl/DSLNodeArgumentParser.d.ts | 36 + dist/dsl/DSLUtilities.d.ts | 7 + dist/index.d.ts | 4 + dist/index.js | 1863 +++++++++++++++++ dist/index.js.map | 7 + dist/nodes/Node.d.ts | 111 + dist/nodes/composite/Composite.d.ts | 32 + dist/nodes/composite/Lotto.d.ts | 33 + dist/nodes/composite/Parallel.d.ts | 26 + dist/nodes/composite/Selector.d.ts | 27 + dist/nodes/composite/Sequence.d.ts | 27 + dist/nodes/decorator/Decorator.d.ts | 32 + dist/nodes/decorator/Fail.d.ts | 26 + dist/nodes/decorator/Flip.d.ts | 26 + dist/nodes/decorator/Repeat.d.ts | 58 + dist/nodes/decorator/Retry.d.ts | 58 + dist/nodes/decorator/Root.d.ts | 26 + dist/nodes/decorator/Succeed.d.ts | 26 + dist/nodes/leaf/Action.d.ts | 46 + dist/nodes/leaf/Condition.d.ts | 29 + dist/nodes/leaf/Leaf.d.ts | 10 + dist/nodes/leaf/Wait.d.ts | 42 + src/BehaviourTree.ts | 2 +- src/dsl/DSLDefinitionParser.ts | 75 +- src/dsl/DSLNodeArgumentParser.ts | 8 +- src/dsl/DSLUtilities.ts | 4 +- 45 files changed, 5173 insertions(+), 36 deletions(-) create mode 100644 dist/Agent.d.ts create mode 100644 dist/BehaviourTree.d.ts create mode 100644 dist/BehaviourTreeOptions.d.ts create mode 100644 dist/Lookup.d.ts create mode 100644 dist/RootAstNodesBuilder.d.ts create mode 100644 dist/State.d.ts create mode 100644 dist/attributes/Attribute.d.ts create mode 100644 dist/attributes/callbacks/Callback.d.ts create mode 100644 dist/attributes/callbacks/Entry.d.ts create mode 100644 dist/attributes/callbacks/Exit.d.ts create mode 100644 dist/attributes/callbacks/Step.d.ts create mode 100644 dist/attributes/guards/Guard.d.ts create mode 100644 dist/attributes/guards/GuardPath.d.ts create mode 100644 dist/attributes/guards/GuardUnsatisifedException.d.ts create mode 100644 dist/attributes/guards/Until.d.ts create mode 100644 dist/attributes/guards/While.d.ts create mode 100644 dist/bundle.js create mode 100644 dist/bundle.js.map create mode 100644 dist/dsl/DSLDefinitionParser.d.ts create mode 100644 dist/dsl/DSLNodeArgumentParser.d.ts create mode 100644 dist/dsl/DSLUtilities.d.ts create mode 100644 dist/index.d.ts create mode 100644 dist/index.js create mode 100644 dist/index.js.map create mode 100644 dist/nodes/Node.d.ts create mode 100644 dist/nodes/composite/Composite.d.ts create mode 100644 dist/nodes/composite/Lotto.d.ts create mode 100644 dist/nodes/composite/Parallel.d.ts create mode 100644 dist/nodes/composite/Selector.d.ts create mode 100644 dist/nodes/composite/Sequence.d.ts create mode 100644 dist/nodes/decorator/Decorator.d.ts create mode 100644 dist/nodes/decorator/Fail.d.ts create mode 100644 dist/nodes/decorator/Flip.d.ts create mode 100644 dist/nodes/decorator/Repeat.d.ts create mode 100644 dist/nodes/decorator/Retry.d.ts create mode 100644 dist/nodes/decorator/Root.d.ts create mode 100644 dist/nodes/decorator/Succeed.d.ts create mode 100644 dist/nodes/leaf/Action.d.ts create mode 100644 dist/nodes/leaf/Condition.d.ts create mode 100644 dist/nodes/leaf/Leaf.d.ts create mode 100644 dist/nodes/leaf/Wait.d.ts diff --git a/dist/Agent.d.ts b/dist/Agent.d.ts new file mode 100644 index 0000000..abde15d --- /dev/null +++ b/dist/Agent.d.ts @@ -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 | boolean; +export type AgentFunction = (this: Agent, ...args: FunctionArg[]) => ActionResult; +export type GlobalFunction = (agent: Agent, ...args: FunctionArg[]) => ActionResult; diff --git a/dist/BehaviourTree.d.ts b/dist/BehaviourTree.d.ts new file mode 100644 index 0000000..5b62d16 --- /dev/null +++ b/dist/BehaviourTree.d.ts @@ -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; +} diff --git a/dist/BehaviourTreeOptions.d.ts b/dist/BehaviourTreeOptions.d.ts new file mode 100644 index 0000000..138cc72 --- /dev/null +++ b/dist/BehaviourTreeOptions.d.ts @@ -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; +} diff --git a/dist/Lookup.d.ts b/dist/Lookup.d.ts new file mode 100644 index 0000000..8efbc28 --- /dev/null +++ b/dist/Lookup.d.ts @@ -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 {}; diff --git a/dist/RootAstNodesBuilder.d.ts b/dist/RootAstNodesBuilder.d.ts new file mode 100644 index 0000000..23c835b --- /dev/null +++ b/dist/RootAstNodesBuilder.d.ts @@ -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 = { + value: T; + type: string; +}; +type NullArgument = Argument & { + type: "null"; +}; +type BooleanArgument = Argument & { + type: "boolean"; +}; +type NumberArgument = Argument & { + type: "number"; + isInteger: boolean; +}; +type StringPlaceholderArgument = Argument & { + type: "string"; +}; +type IdentifierArgument = Argument & { + type: "identifier"; +}; +export type AnyArgument = NullArgument | BooleanArgument | NumberArgument | StringPlaceholderArgument | IdentifierArgument; +type Validatable = { + children?: AstNode[]; + validate: (depth: number) => void; +}; +type NodeInstanceCreator = (namedRootNodeProvider: (name: string) => RootAstNode, visitedBranches: string[]) => T; +export type AstNode = Validatable & { + type: string; + createNodeInstance: NodeInstanceCreator; +}; +export type LeafAstNode = AstNode & { + type: "action" | "condition" | "wait"; + attributes: Attribute[]; +}; +export type CompositeAstNode = AstNode & { + type: "lotto" | "parallel" | "selector" | "sequence"; + attributes: Attribute[]; + children: AstNode[]; +}; +export type DecoratorAstNode = AstNode & { + type: "fail" | "flip" | "repeat" | "retry" | "root" | "succeed"; + attributes: Attribute[]; + children: AstNode[]; +}; +export type BranchAstNode = AstNode & { + type: "branch"; + branchName: "" | string; +}; +export type LottoAstNode = CompositeAstNode & { + type: "lotto"; + tickets: number[]; +}; +export type RootAstNode = DecoratorAstNode & { + type: "root"; + name: null | string; +}; +export type RepeatAstNode = DecoratorAstNode & { + type: "repeat"; + iterations: number | null; + iterationsMin: number | null; + iterationsMax: number | null; +}; +export type RetryAstNode = DecoratorAstNode & { + type: "retry"; + attempts: number | null; + attemptsMin: number | null; + attemptsMax: number | null; +}; +export type ActionAstNode = LeafAstNode & { + type: "action"; + actionName: string; + actionArguments: AnyArgument[]; +}; +export type ConditionAstNode = LeafAstNode & { + type: "condition"; + conditionName: string; + conditionArguments: AnyArgument[]; +}; +export type WaitAstNode = LeafAstNode & { + 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 {}; diff --git a/dist/State.d.ts b/dist/State.d.ts new file mode 100644 index 0000000..18da32d --- /dev/null +++ b/dist/State.d.ts @@ -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; diff --git a/dist/attributes/Attribute.d.ts b/dist/attributes/Attribute.d.ts new file mode 100644 index 0000000..6fb7bb3 --- /dev/null +++ b/dist/attributes/Attribute.d.ts @@ -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 { + 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; +} diff --git a/dist/attributes/callbacks/Callback.d.ts b/dist/attributes/callbacks/Callback.d.ts new file mode 100644 index 0000000..6a294b7 --- /dev/null +++ b/dist/attributes/callbacks/Callback.d.ts @@ -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 { + 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; +} diff --git a/dist/attributes/callbacks/Entry.d.ts b/dist/attributes/callbacks/Entry.d.ts new file mode 100644 index 0000000..0db55e9 --- /dev/null +++ b/dist/attributes/callbacks/Entry.d.ts @@ -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; +} diff --git a/dist/attributes/callbacks/Exit.d.ts b/dist/attributes/callbacks/Exit.d.ts new file mode 100644 index 0000000..7c3bbe8 --- /dev/null +++ b/dist/attributes/callbacks/Exit.d.ts @@ -0,0 +1,20 @@ +import Callback from "./Callback"; +import { Agent } from "../../Agent"; +import { AnyArgument } from "../../RootAstNodesBuilder"; +/** + * An EXIT callback which defines an agent function to call when the associated node is updated and moves to a finished state or is aborted. + */ +export default class Exit 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. + * @param isSuccess Whether the decorated node was left with a success state. + * @param isAborted Whether the decorated node was aborted. + */ + callAgentFunction: (agent: Agent, isSuccess: boolean, isAborted: boolean) => void; +} diff --git a/dist/attributes/callbacks/Step.d.ts b/dist/attributes/callbacks/Step.d.ts new file mode 100644 index 0000000..d4e0a1c --- /dev/null +++ b/dist/attributes/callbacks/Step.d.ts @@ -0,0 +1,18 @@ +import Callback from "./Callback"; +import { Agent } from "../../Agent"; +import { AnyArgument } from "../../RootAstNodesBuilder"; +/** + * A STEP callback which defines an agent function to call when the associated node is updated. + */ +export default class Step 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; +} diff --git a/dist/attributes/guards/Guard.d.ts b/dist/attributes/guards/Guard.d.ts new file mode 100644 index 0000000..4332517 --- /dev/null +++ b/dist/attributes/guards/Guard.d.ts @@ -0,0 +1,37 @@ +import { Agent } from "../../Agent"; +import { AnyArgument } from "../../RootAstNodesBuilder"; +import Attribute, { AttributeDetails } from "../Attribute"; +export type GuardAttributeDetails = { + /** The name of the condition function that determines whether the guard is satisfied. */ + condition: string; +} & AttributeDetails; +/** + * A base node guard attribute. + */ +export default abstract class Guard extends Attribute { + private condition; + /** + * @param type The node attribute type. + * @param args The array of decorator argument definitions. + * @param condition The name of the condition function that determines whether the guard is satisfied. + */ + constructor(type: string, args: AnyArgument[], condition: string); + /** + * Gets the name of the condition function that determines whether the guard is satisfied. + */ + getCondition: () => string; + /** + * Gets whether this attribute is a guard. + */ + isGuard: () => boolean; + /** + * Gets the attribute details. + */ + getDetails(): GuardAttributeDetails; + /** + * Gets whether the guard is satisfied. + * @param agent The agent. + * @returns Whether the guard is satisfied. + */ + abstract isSatisfied(agent: Agent): boolean; +} diff --git a/dist/attributes/guards/GuardPath.d.ts b/dist/attributes/guards/GuardPath.d.ts new file mode 100644 index 0000000..a6fea20 --- /dev/null +++ b/dist/attributes/guards/GuardPath.d.ts @@ -0,0 +1,23 @@ +import { Agent } from "../../Agent"; +import Guard from "./Guard"; +import Node from "../../nodes/Node"; +export type GuardPathPart = { + node: Node; + guards: Guard[]; +}; +/** + * Represents a path of node guards along a root-to-leaf tree path. + */ +export default class GuardPath { + private nodes; + /** + * @param nodes An array of objects defining a node instance -> guard link, ordered by node depth. + */ + constructor(nodes: GuardPathPart[]); + /** + * Evaluate guard conditions for all guards in the tree path, moving outwards from the root. + * @param agent The agent, required for guard evaluation. + * @returns An evaluation results object. + */ + evaluate: (agent: Agent) => void; +} diff --git a/dist/attributes/guards/GuardUnsatisifedException.d.ts b/dist/attributes/guards/GuardUnsatisifedException.d.ts new file mode 100644 index 0000000..71c51f5 --- /dev/null +++ b/dist/attributes/guards/GuardUnsatisifedException.d.ts @@ -0,0 +1,17 @@ +import Node from "../../nodes/Node"; +/** + * An exception thrown when evaluating node guard path conditions and a conditions fails. + */ +export default class GuardUnsatisifedException extends Error { + private source; + /** + * @param source The node at which a guard condition failed. + */ + constructor(source: Node); + /** + * Gets whether the specified node is the node at which a guard condition failed. + * @param node The node to check against the source node. + * @returns Whether the specified node is the node at which a guard condition failed. + */ + isSourceNode: (node: Node) => boolean; +} diff --git a/dist/attributes/guards/Until.d.ts b/dist/attributes/guards/Until.d.ts new file mode 100644 index 0000000..5ec505f --- /dev/null +++ b/dist/attributes/guards/Until.d.ts @@ -0,0 +1,19 @@ +import Guard from "./Guard"; +import { Agent } from "../../Agent"; +import { AnyArgument } from "../../RootAstNodesBuilder"; +/** + * An UNTIL guard which is satisfied as long as the given condition remains false. + */ +export default class Until extends Guard { + /** + * @param condition The name of the condition function that determines whether the guard is satisfied. + * @param args The array of decorator argument definitions. + */ + constructor(condition: string, args: AnyArgument[]); + /** + * Gets whether the guard is satisfied. + * @param agent The agent. + * @returns Whether the guard is satisfied. + */ + isSatisfied: (agent: Agent) => boolean; +} diff --git a/dist/attributes/guards/While.d.ts b/dist/attributes/guards/While.d.ts new file mode 100644 index 0000000..dd4f6bf --- /dev/null +++ b/dist/attributes/guards/While.d.ts @@ -0,0 +1,19 @@ +import Guard from "./Guard"; +import { Agent } from "../../Agent"; +import { AnyArgument } from "../../RootAstNodesBuilder"; +/** + * A WHILE guard which is satisfied as long as the given condition remains true. + */ +export default class While extends Guard { + /** + * @param condition The name of the condition function that determines whether the guard is satisfied. + * @param args The array of decorator argument definitions. + */ + constructor(condition: string, args: AnyArgument[]); + /** + * Gets whether the guard is satisfied. + * @param agent The agent. + * @returns Whether the guard is satisfied. + */ + isSatisfied: (agent: Agent) => boolean; +} diff --git a/dist/bundle.js b/dist/bundle.js new file mode 100644 index 0000000..12265f3 --- /dev/null +++ b/dist/bundle.js @@ -0,0 +1,1860 @@ +"use strict"; +var mistreevous = (() => { + var __create = Object.create; + var __defProp = Object.defineProperty; + var __getOwnPropDesc = Object.getOwnPropertyDescriptor; + var __getOwnPropNames = Object.getOwnPropertyNames; + var __getProtoOf = Object.getPrototypeOf; + var __hasOwnProp = Object.prototype.hasOwnProperty; + var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value; + var __commonJS = (cb, mod) => function __require() { + return mod || (0, cb[__getOwnPropNames(cb)[0]])((mod = { exports: {} }).exports, mod), mod.exports; + }; + var __export = (target, all) => { + for (var name in all) + __defProp(target, name, { get: all[name], enumerable: true }); + }; + var __copyProps = (to, from, except, desc) => { + if (from && typeof from === "object" || typeof from === "function") { + for (let key of __getOwnPropNames(from)) + if (!__hasOwnProp.call(to, key) && key !== except) + __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable }); + } + return to; + }; + var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps( + isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target, + mod + )); + var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod); + var __publicField = (obj, key, value) => { + __defNormalProp(obj, typeof key !== "symbol" ? key + "" : key, value); + return value; + }; + + // node_modules/lotto-draw/dist/Participant.js + var require_Participant = __commonJS({ + "node_modules/lotto-draw/dist/Participant.js"(exports) { + "use strict"; + Object.defineProperty(exports, "__esModule", { value: true }); + exports.Participant = void 0; + var Participant = function() { + function Participant2(participant, tickets) { + if (tickets === void 0) { + tickets = 1; + } + this._participant = participant; + this._tickets = tickets; + } + Object.defineProperty(Participant2.prototype, "participant", { + get: function() { + return this._participant; + }, + enumerable: false, + configurable: true + }); + Object.defineProperty(Participant2.prototype, "tickets", { + get: function() { + return this._tickets; + }, + set: function(value) { + this._tickets = value; + }, + enumerable: false, + configurable: true + }); + return Participant2; + }(); + exports.Participant = Participant; + } + }); + + // node_modules/lotto-draw/dist/Utilities.js + var require_Utilities = __commonJS({ + "node_modules/lotto-draw/dist/Utilities.js"(exports) { + "use strict"; + Object.defineProperty(exports, "__esModule", { value: true }); + exports.isNaturalNumber = exports.isNullOrUndefined = void 0; + function isNullOrUndefined(value) { + return value === null || value === void 0; + } + exports.isNullOrUndefined = isNullOrUndefined; + function isNaturalNumber(value) { + return typeof value === "number" && value >= 1 && Math.floor(value) === value; + } + exports.isNaturalNumber = isNaturalNumber; + } + }); + + // node_modules/lotto-draw/dist/Lotto.js + var require_Lotto = __commonJS({ + "node_modules/lotto-draw/dist/Lotto.js"(exports) { + "use strict"; + Object.defineProperty(exports, "__esModule", { value: true }); + exports.Lotto = void 0; + var Participant_1 = require_Participant(); + var Utilities_1 = require_Utilities(); + var Lotto2 = function() { + function Lotto3(customRandom) { + this._participants = []; + this._customRandom = customRandom; + } + Lotto3.prototype.add = function(participant, tickets) { + if (tickets === void 0) { + tickets = 1; + } + if (!(0, Utilities_1.isNaturalNumber)(tickets)) { + throw new Error("tickets value must be a natural number"); + } + var existingParticipant = this._participants.find(function(part) { + return part.participant === participant; + }); + if (existingParticipant) { + existingParticipant.tickets += tickets; + } else { + this._participants.push(new Participant_1.Participant(participant, tickets)); + } + return this; + }; + Lotto3.prototype.remove = function(participant, tickets) { + var existingParticipant = this._participants.find(function(part) { + return part.participant === participant; + }); + if (!existingParticipant) { + return this; + } + if (tickets !== void 0) { + if (!(0, Utilities_1.isNaturalNumber)(tickets)) { + throw new Error("tickets value must be a natural number"); + } + existingParticipant.tickets -= tickets; + if (existingParticipant.tickets < 1) { + this._participants = this._participants.filter(function(part) { + return part !== existingParticipant; + }); + } + } else { + this._participants = this._participants.filter(function(part) { + return part !== existingParticipant; + }); + } + return this; + }; + Lotto3.prototype.draw = function(options) { + if (options === void 0) { + options = {}; + } + if (this._participants.length === 0) { + return null; + } + var redrawable = (0, Utilities_1.isNullOrUndefined)(options.redrawable) ? true : options.redrawable; + var pickable = []; + this._participants.forEach(function(_a) { + var participant = _a.participant, tickets = _a.tickets; + for (var ticketCount = 0; ticketCount < tickets; ticketCount++) { + pickable.push(participant); + } + }); + var random; + if (this._customRandom) { + random = this._customRandom(); + if (typeof random !== "number" || random < 0 || random >= 1) { + throw new Error("the 'random' function provided did not return a number between 0 (inclusive) and 1"); + } + } else { + random = Math.random(); + } + var winner = pickable[Math.floor(random * pickable.length)]; + if (!redrawable) { + this.remove(winner, 1); + } + return winner; + }; + Lotto3.prototype.drawMultiple = function(tickets, options) { + if (options === void 0) { + options = {}; + } + var uniqueResults = (0, Utilities_1.isNullOrUndefined)(options.unique) ? false : options.unique; + if (tickets === 0) { + return []; + } + if (!(0, Utilities_1.isNaturalNumber)(tickets)) { + throw new Error("tickets value must be a natural number"); + } + var result = []; + while (result.length < tickets && this._participants.length > 0) { + result.push(this.draw(options)); + } + if (uniqueResults) { + var unique = []; + for (var _i = 0, result_1 = result; _i < result_1.length; _i++) { + var participant = result_1[_i]; + if (unique.indexOf(participant) === -1) { + unique.push(participant); + } + } + result = unique; + } + return result; + }; + return Lotto3; + }(); + exports.Lotto = Lotto2; + } + }); + + // node_modules/lotto-draw/dist/createLotto.js + var require_createLotto = __commonJS({ + "node_modules/lotto-draw/dist/createLotto.js"(exports) { + "use strict"; + Object.defineProperty(exports, "__esModule", { value: true }); + exports.createLotto = void 0; + var Lotto_1 = require_Lotto(); + function createLotto2(participantsOrOptions) { + if (!participantsOrOptions) { + return new Lotto_1.Lotto(); + } + if (Array.isArray(participantsOrOptions)) { + var participants = participantsOrOptions; + var lotto_1 = new Lotto_1.Lotto(); + participants.forEach(function(_a) { + var participant = _a[0], tokens = _a[1]; + return lotto_1.add(participant, tokens); + }); + return lotto_1; + } else { + var random = participantsOrOptions.random, participants = participantsOrOptions.participants; + var lotto_2 = new Lotto_1.Lotto(random); + if (participants) { + participants.forEach(function(_a) { + var participant = _a[0], tokens = _a[1]; + return lotto_2.add(participant, tokens); + }); + } + return lotto_2; + } + } + exports.createLotto = createLotto2; + } + }); + + // node_modules/lotto-draw/dist/index.js + var require_dist = __commonJS({ + "node_modules/lotto-draw/dist/index.js"(exports) { + "use strict"; + Object.defineProperty(exports, "__esModule", { value: true }); + var createLotto_1 = require_createLotto(); + exports.default = createLotto_1.createLotto; + } + }); + + // src/index.ts + var src_exports = {}; + __export(src_exports, { + BehaviourTree: () => BehaviourTree, + State: () => State + }); + + // src/attributes/guards/GuardUnsatisifedException.ts + var GuardUnsatisifedException = class extends Error { + constructor(source) { + super("A guard path condition has failed"); + this.source = source; + } + isSourceNode = (node) => node === this.source; + }; + + // src/attributes/guards/GuardPath.ts + var GuardPath = class { + constructor(nodes) { + this.nodes = nodes; + } + evaluate = (agent) => { + for (const details of this.nodes) { + for (const guard of details.guards) { + if (!guard.isSatisfied(agent)) { + throw new GuardUnsatisifedException(details.node); + } + } + } + }; + }; + + // src/State.ts + var State = /* @__PURE__ */ ((State2) => { + State2["READY"] = "mistreevous.ready"; + State2["RUNNING"] = "mistreevous.running"; + State2["SUCCEEDED"] = "mistreevous.succeeded"; + State2["FAILED"] = "mistreevous.failed"; + return State2; + })(State || {}); + + // src/nodes/Node.ts + var Node = class { + constructor(type, attributes, args) { + this.type = type; + this.attributes = attributes; + this.args = args; + } + uid = createNodeUid(); + state = "mistreevous.ready" /* READY */; + guardPath; + getState = () => this.state; + setState = (value) => { + this.state = value; + }; + getUid = () => this.uid; + getType = () => this.type; + getAttributes = () => this.attributes; + getArguments = () => this.args; + getAttribute(type) { + return this.getAttributes().filter((decorator) => decorator.getType().toUpperCase() === type.toUpperCase())[0] || null; + } + getGuardAttributes = () => this.getAttributes().filter((decorator) => decorator.isGuard()); + setGuardPath = (value) => this.guardPath = value; + hasGuardPath = () => !!this.guardPath; + is(value) { + return this.state === value; + } + reset() { + this.setState("mistreevous.ready" /* READY */); + } + abort(agent) { + if (!this.is("mistreevous.running" /* RUNNING */)) { + return; + } + this.reset(); + this.getAttribute("exit")?.callAgentFunction(agent, false, true); + } + update(agent, options) { + if (this.is("mistreevous.succeeded" /* SUCCEEDED */) || this.is("mistreevous.failed" /* FAILED */)) { + return; + } + try { + this.guardPath.evaluate(agent); + if (this.is("mistreevous.ready" /* READY */)) { + this.getAttribute("entry")?.callAgentFunction(agent); + } + this.getAttribute("step")?.callAgentFunction(agent); + this.onUpdate(agent, options); + if (this.is("mistreevous.succeeded" /* SUCCEEDED */) || this.is("mistreevous.failed" /* FAILED */)) { + this.getAttribute("exit")?.callAgentFunction(agent, this.is("mistreevous.succeeded" /* SUCCEEDED */), false); + } + } catch (error) { + if (error instanceof GuardUnsatisifedException && error.isSourceNode(this)) { + this.abort(agent); + this.setState("mistreevous.failed" /* FAILED */); + } else { + throw error; + } + } + } + }; + function createNodeUid() { + var S4 = function() { + return ((1 + Math.random()) * 65536 | 0).toString(16).substring(1); + }; + return S4() + S4() + "-" + S4() + "-" + S4() + "-" + S4() + "-" + S4() + S4() + S4(); + } + + // src/nodes/leaf/Leaf.ts + var Leaf = class extends Node { + isLeafNode = () => true; + }; + + // src/Lookup.ts + var Lookup = class { + static getFunc(name) { + return this.functionTable[name]; + } + static setFunc(name, func) { + this.functionTable[name] = func; + } + static getFuncInvoker(agent, name) { + const foundOnAgent = agent[name]; + if (foundOnAgent && typeof foundOnAgent === "function") { + return (args) => foundOnAgent.apply( + agent, + args.map((arg) => arg.value) + ); + } + if (this.functionTable[name] && typeof this.functionTable[name] === "function") { + return (args) => this.functionTable[name](agent, ...args.map((arg) => arg.value)); + } + return null; + } + static getSubtree(name) { + return this.subtreeTable[name]; + } + static setSubtree(name, subtree) { + this.subtreeTable[name] = subtree; + } + static remove(name) { + delete this.functionTable[name]; + delete this.subtreeTable[name]; + } + static empty() { + this.functionTable = {}; + this.subtreeTable = {}; + } + }; + __publicField(Lookup, "functionTable", {}); + __publicField(Lookup, "subtreeTable", {}); + + // src/nodes/leaf/Action.ts + var Action = class extends Leaf { + constructor(attributes, actionName, actionArguments) { + super("action", attributes, actionArguments); + this.actionName = actionName; + this.actionArguments = actionArguments; + } + isUsingUpdatePromise = false; + updatePromiseStateResult = null; + onUpdate(agent, options) { + if (this.isUsingUpdatePromise) { + if (this.updatePromiseStateResult) { + this.setState(this.updatePromiseStateResult); + } + return; + } + const actionFuncInvoker = Lookup.getFuncInvoker(agent, this.actionName); + if (actionFuncInvoker === null) { + throw new Error( + `cannot update action node as the action '${this.actionName}' function is not defined on the agent and has not been registered` + ); + } + const updateResult = actionFuncInvoker(this.actionArguments); + if (updateResult instanceof Promise) { + updateResult.then( + (result) => { + if (!this.isUsingUpdatePromise) { + return; + } + if (result !== "mistreevous.succeeded" /* SUCCEEDED */ && result !== "mistreevous.failed" /* FAILED */) { + throw new Error( + "action node promise resolved with an invalid value, expected a State.SUCCEEDED or State.FAILED value to be returned" + ); + } + this.updatePromiseStateResult = result; + }, + (reason) => { + if (!this.isUsingUpdatePromise) { + return; + } + throw new Error(reason); + } + ); + this.setState("mistreevous.running" /* RUNNING */); + this.isUsingUpdatePromise = true; + } else { + this.validateUpdateResult(updateResult); + this.setState(updateResult || "mistreevous.running" /* RUNNING */); + } + } + getName = () => this.actionName; + reset = () => { + this.setState("mistreevous.ready" /* READY */); + this.isUsingUpdatePromise = false; + this.updatePromiseStateResult = null; + }; + validateUpdateResult = (result) => { + switch (result) { + case "mistreevous.succeeded" /* SUCCEEDED */: + case "mistreevous.failed" /* FAILED */: + case void 0: + return; + default: + throw new Error( + `action '${this.actionName}' 'onUpdate' returned an invalid response, expected an optional State.SUCCEEDED or State.FAILED value to be returned` + ); + } + }; + }; + + // src/nodes/leaf/Condition.ts + var Condition = class extends Leaf { + constructor(attributes, conditionName, conditionArguments) { + super("condition", attributes, conditionArguments); + this.conditionName = conditionName; + this.conditionArguments = conditionArguments; + } + onUpdate(agent, options) { + const conditionFuncInvoker = Lookup.getFuncInvoker(agent, this.conditionName); + if (conditionFuncInvoker === null) { + throw new Error( + `cannot update condition node as the condition '${this.conditionName}' function is not defined on the agent and has not been registered` + ); + } + this.setState(!!conditionFuncInvoker(this.conditionArguments) ? "mistreevous.succeeded" /* SUCCEEDED */ : "mistreevous.failed" /* FAILED */); + } + getName = () => this.conditionName; + }; + + // src/nodes/leaf/Wait.ts + var Wait = class extends Leaf { + constructor(attributes, duration, durationMin, durationMax) { + super("wait", attributes, []); + this.duration = duration; + this.durationMin = durationMin; + this.durationMax = durationMax; + } + initialUpdateTime = 0; + totalDuration = null; + waitedDuration = 0; + onUpdate(agent, options) { + if (this.is("mistreevous.ready" /* READY */)) { + this.initialUpdateTime = new Date().getTime(); + this.waitedDuration = 0; + if (this.duration !== null) { + this.totalDuration = this.duration; + } else if (this.durationMin !== null && this.durationMax !== null) { + const random = typeof options.random === "function" ? options.random : Math.random; + this.totalDuration = Math.floor( + random() * (this.durationMax - this.durationMin + 1) + this.durationMin + ); + } else { + this.totalDuration = null; + } + this.setState("mistreevous.running" /* RUNNING */); + } + if (this.totalDuration === null) { + return; + } + if (typeof options.getDeltaTime === "function") { + const deltaTime = options.getDeltaTime(); + if (typeof deltaTime !== "number" || isNaN(deltaTime)) { + throw new Error("The delta time must be a valid number and not NaN."); + } + this.waitedDuration += deltaTime * 1e3; + } else { + this.waitedDuration = new Date().getTime() - this.initialUpdateTime; + } + if (this.waitedDuration >= this.totalDuration) { + this.setState("mistreevous.succeeded" /* SUCCEEDED */); + } + } + getName = () => { + if (this.duration !== null) { + return `WAIT ${this.duration}ms`; + } else if (this.durationMin !== null && this.durationMax !== null) { + return `WAIT ${this.durationMin}ms-${this.durationMax}ms`; + } else { + return "WAIT"; + } + }; + }; + + // src/nodes/decorator/Decorator.ts + var Decorator = class extends Node { + constructor(type, attributes, child) { + super(type, attributes, []); + this.child = child; + } + isLeafNode = () => false; + getChildren = () => [this.child]; + reset = () => { + this.setState("mistreevous.ready" /* READY */); + this.child.reset(); + }; + abort = (agent) => { + if (!this.is("mistreevous.running" /* RUNNING */)) { + return; + } + this.child.abort(agent); + this.reset(); + this.getAttribute("exit")?.callAgentFunction(agent, false, true); + }; + }; + + // src/nodes/decorator/Root.ts + var Root = class extends Decorator { + constructor(attributes, child) { + super("root", attributes, child); + } + onUpdate(agent, options) { + if (this.child.getState() === "mistreevous.ready" /* READY */ || this.child.getState() === "mistreevous.running" /* RUNNING */) { + this.child.update(agent, options); + } + this.setState(this.child.getState()); + } + getName = () => "ROOT"; + }; + + // src/nodes/decorator/Repeat.ts + var Repeat = class extends Decorator { + constructor(attributes, iterations, iterationsMin, iterationsMax, child) { + super("repeat", attributes, child); + this.iterations = iterations; + this.iterationsMin = iterationsMin; + this.iterationsMax = iterationsMax; + } + targetIterationCount = null; + currentIterationCount = 0; + onUpdate(agent, options) { + if (this.is("mistreevous.ready" /* READY */)) { + this.child.reset(); + this.currentIterationCount = 0; + this.setTargetIterationCount(options); + } + if (this.canIterate()) { + this.setState("mistreevous.running" /* RUNNING */); + if (this.child.getState() === "mistreevous.succeeded" /* SUCCEEDED */) { + this.child.reset(); + } + this.child.update(agent, options); + if (this.child.getState() === "mistreevous.failed" /* FAILED */) { + this.setState("mistreevous.failed" /* FAILED */); + return; + } else if (this.child.getState() === "mistreevous.succeeded" /* SUCCEEDED */) { + this.currentIterationCount += 1; + } + } else { + this.setState("mistreevous.succeeded" /* SUCCEEDED */); + } + } + getName = () => { + if (this.iterations !== null) { + return `REPEAT ${this.iterations}x`; + } else if (this.iterationsMin !== null && this.iterationsMax !== null) { + return `REPEAT ${this.iterationsMin}x-${this.iterationsMax}x`; + } else { + return "REPEAT"; + } + }; + reset = () => { + this.setState("mistreevous.ready" /* READY */); + this.currentIterationCount = 0; + this.child.reset(); + }; + canIterate = () => { + if (this.targetIterationCount !== null) { + return this.currentIterationCount < this.targetIterationCount; + } + return true; + }; + setTargetIterationCount = (options) => { + if (this.iterations !== null) { + this.targetIterationCount = this.iterations; + } else if (this.iterationsMin !== null && this.iterationsMax !== null) { + const random = typeof options.random === "function" ? options.random : Math.random; + this.targetIterationCount = Math.floor( + random() * (this.iterationsMax - this.iterationsMin + 1) + this.iterationsMin + ); + } else { + this.targetIterationCount = null; + } + }; + }; + + // src/nodes/decorator/Retry.ts + var Retry = class extends Decorator { + constructor(attributes, attempts, attemptsMin, attemptsMax, child) { + super("retry", attributes, child); + this.attempts = attempts; + this.attemptsMin = attemptsMin; + this.attemptsMax = attemptsMax; + } + targetAttemptCount = null; + currentAttemptCount = 0; + onUpdate(agent, options) { + if (this.is("mistreevous.ready" /* READY */)) { + this.child.reset(); + this.currentAttemptCount = 0; + this.setTargetAttemptCount(options); + } + if (this.canAttempt()) { + this.setState("mistreevous.running" /* RUNNING */); + if (this.child.getState() === "mistreevous.failed" /* FAILED */) { + this.child.reset(); + } + this.child.update(agent, options); + if (this.child.getState() === "mistreevous.succeeded" /* SUCCEEDED */) { + this.setState("mistreevous.succeeded" /* SUCCEEDED */); + return; + } else if (this.child.getState() === "mistreevous.failed" /* FAILED */) { + this.currentAttemptCount += 1; + } + } else { + this.setState("mistreevous.failed" /* FAILED */); + } + } + getName = () => { + if (this.attempts !== null) { + return `RETRY ${this.attempts}x`; + } else if (this.attemptsMin !== null && this.attemptsMax !== null) { + return `RETRY ${this.attemptsMin}x-${this.attemptsMax}x`; + } else { + return "RETRY"; + } + }; + reset = () => { + this.setState("mistreevous.ready" /* READY */); + this.currentAttemptCount = 0; + this.child.reset(); + }; + canAttempt = () => { + if (this.targetAttemptCount !== null) { + return this.currentAttemptCount < this.targetAttemptCount; + } + return true; + }; + setTargetAttemptCount = (options) => { + if (this.attempts !== null) { + this.targetAttemptCount = this.attempts; + } else if (this.attemptsMin !== null && this.attemptsMax !== null) { + const random = typeof options.random === "function" ? options.random : Math.random; + this.targetAttemptCount = Math.floor( + random() * (this.attemptsMax - this.attemptsMin + 1) + this.attemptsMin + ); + } else { + this.targetAttemptCount = null; + } + }; + }; + + // src/nodes/decorator/Flip.ts + var Flip = class extends Decorator { + constructor(attributes, child) { + super("flip", attributes, child); + } + onUpdate(agent, options) { + if (this.child.getState() === "mistreevous.ready" /* READY */ || this.child.getState() === "mistreevous.running" /* RUNNING */) { + this.child.update(agent, options); + } + switch (this.child.getState()) { + case "mistreevous.running" /* RUNNING */: + this.setState("mistreevous.running" /* RUNNING */); + break; + case "mistreevous.succeeded" /* SUCCEEDED */: + this.setState("mistreevous.failed" /* FAILED */); + break; + case "mistreevous.failed" /* FAILED */: + this.setState("mistreevous.succeeded" /* SUCCEEDED */); + break; + default: + this.setState("mistreevous.ready" /* READY */); + } + } + getName = () => "FLIP"; + }; + + // src/nodes/decorator/Succeed.ts + var Succeed = class extends Decorator { + constructor(attributes, child) { + super("succeed", attributes, child); + } + onUpdate(agent, options) { + if (this.child.getState() === "mistreevous.ready" /* READY */ || this.child.getState() === "mistreevous.running" /* RUNNING */) { + this.child.update(agent, options); + } + switch (this.child.getState()) { + case "mistreevous.running" /* RUNNING */: + this.setState("mistreevous.running" /* RUNNING */); + break; + case "mistreevous.succeeded" /* SUCCEEDED */: + case "mistreevous.failed" /* FAILED */: + this.setState("mistreevous.succeeded" /* SUCCEEDED */); + break; + default: + this.setState("mistreevous.ready" /* READY */); + } + } + getName = () => "SUCCEED"; + }; + + // src/nodes/decorator/Fail.ts + var Fail = class extends Decorator { + constructor(attributes, child) { + super("fail", attributes, child); + } + onUpdate(agent, options) { + if (this.child.getState() === "mistreevous.ready" /* READY */ || this.child.getState() === "mistreevous.running" /* RUNNING */) { + this.child.update(agent, options); + } + switch (this.child.getState()) { + case "mistreevous.running" /* RUNNING */: + this.setState("mistreevous.running" /* RUNNING */); + break; + case "mistreevous.succeeded" /* SUCCEEDED */: + case "mistreevous.failed" /* FAILED */: + this.setState("mistreevous.failed" /* FAILED */); + break; + default: + this.setState("mistreevous.ready" /* READY */); + } + } + getName = () => "FAIL"; + }; + + // src/nodes/composite/Lotto.ts + var import_lotto_draw = __toESM(require_dist()); + + // src/nodes/composite/Composite.ts + var Composite = class extends Node { + constructor(type, attributes, children) { + super(type, attributes, []); + this.children = children; + } + isLeafNode = () => false; + getChildren = () => this.children; + reset = () => { + this.setState("mistreevous.ready" /* READY */); + this.getChildren().forEach((child) => child.reset()); + }; + abort = (agent) => { + if (!this.is("mistreevous.running" /* RUNNING */)) { + return; + } + this.getChildren().forEach((child) => child.abort(agent)); + this.reset(); + this.getAttribute("exit")?.callAgentFunction(agent, false, true); + }; + }; + + // src/nodes/composite/Lotto.ts + var Lotto = class extends Composite { + constructor(attributes, tickets, children) { + super("lotto", attributes, children); + this.tickets = tickets; + } + selectedChild; + onUpdate(agent, options) { + if (this.is("mistreevous.ready" /* READY */)) { + const lottoDraw = (0, import_lotto_draw.default)({ + random: options.random, + participants: this.children.map((child, index) => [child, this.tickets[index] || 1]) + }); + this.selectedChild = lottoDraw.draw() || void 0; + } + if (!this.selectedChild) { + throw new Error("failed to update lotto node as it has no active child"); + } + if (this.selectedChild.getState() === "mistreevous.ready" /* READY */ || this.selectedChild.getState() === "mistreevous.running" /* RUNNING */) { + this.selectedChild.update(agent, options); + } + this.setState(this.selectedChild.getState()); + } + getName = () => this.tickets.length ? `LOTTO [${this.tickets.join(",")}]` : "LOTTO"; + }; + + // src/nodes/composite/Selector.ts + var Selector = class extends Composite { + constructor(attributes, children) { + super("selector", attributes, children); + this.children = children; + } + onUpdate(agent, options) { + for (const child of this.children) { + if (child.getState() === "mistreevous.ready" /* READY */ || child.getState() === "mistreevous.running" /* RUNNING */) { + child.update(agent, options); + } + if (child.getState() === "mistreevous.succeeded" /* SUCCEEDED */) { + this.setState("mistreevous.succeeded" /* SUCCEEDED */); + return; + } + if (child.getState() === "mistreevous.failed" /* FAILED */) { + if (this.children.indexOf(child) === this.children.length - 1) { + this.setState("mistreevous.failed" /* FAILED */); + return; + } else { + continue; + } + } + if (child.getState() === "mistreevous.running" /* RUNNING */) { + this.setState("mistreevous.running" /* RUNNING */); + return; + } + throw new Error("child node was not in an expected state."); + } + } + getName = () => "SELECTOR"; + }; + + // src/nodes/composite/Sequence.ts + var Sequence = class extends Composite { + constructor(attributes, children) { + super("sequence", attributes, children); + this.children = children; + } + onUpdate(agent, options) { + for (const child of this.children) { + if (child.getState() === "mistreevous.ready" /* READY */ || child.getState() === "mistreevous.running" /* RUNNING */) { + child.update(agent, options); + } + if (child.getState() === "mistreevous.succeeded" /* SUCCEEDED */) { + if (this.children.indexOf(child) === this.children.length - 1) { + this.setState("mistreevous.succeeded" /* SUCCEEDED */); + return; + } else { + continue; + } + } + if (child.getState() === "mistreevous.failed" /* FAILED */) { + this.setState("mistreevous.failed" /* FAILED */); + return; + } + if (child.getState() === "mistreevous.running" /* RUNNING */) { + this.setState("mistreevous.running" /* RUNNING */); + return; + } + throw new Error("child node was not in an expected state."); + } + } + getName = () => "SEQUENCE"; + }; + + // src/nodes/composite/Parallel.ts + var Parallel = class extends Composite { + constructor(attributes, children) { + super("parallel", attributes, children); + } + onUpdate(agent, options) { + let succeededCount = 0; + let hasChildFailed = false; + for (const child of this.children) { + if (child.getState() === "mistreevous.ready" /* READY */ || child.getState() === "mistreevous.running" /* RUNNING */) { + child.update(agent, options); + } + if (child.getState() === "mistreevous.succeeded" /* SUCCEEDED */) { + succeededCount++; + continue; + } + if (child.getState() === "mistreevous.failed" /* FAILED */) { + hasChildFailed = true; + break; + } + if (child.getState() !== "mistreevous.running" /* RUNNING */) { + throw new Error("child node was not in an expected state."); + } + } + if (hasChildFailed) { + this.setState("mistreevous.failed" /* FAILED */); + for (const child of this.children) { + if (child.getState() === "mistreevous.running" /* RUNNING */) { + child.abort(agent); + } + } + } else { + this.setState(succeededCount === this.children.length ? "mistreevous.succeeded" /* SUCCEEDED */ : "mistreevous.running" /* RUNNING */); + } + } + getName = () => "PARALLEL"; + }; + + // src/attributes/Attribute.ts + var Attribute = class { + constructor(type, args) { + this.type = type; + this.args = args; + } + getType = () => this.type; + getArguments = () => this.args; + }; + + // src/attributes/guards/Guard.ts + var Guard = class extends Attribute { + constructor(type, args, condition) { + super(type, args); + this.condition = condition; + } + getCondition = () => this.condition; + isGuard = () => true; + getDetails() { + return { + type: this.getType(), + args: this.getArguments(), + condition: this.getCondition() + }; + } + }; + + // src/attributes/guards/While.ts + var While = class extends Guard { + constructor(condition, args) { + super("while", args, condition); + } + isSatisfied = (agent) => { + const conditionFuncInvoker = Lookup.getFuncInvoker(agent, this.getCondition()); + if (conditionFuncInvoker === null) { + throw new Error( + `cannot evaluate node guard as the condition '${this.getCondition()}' function is not defined on the agent and has not been registered` + ); + } + return !!conditionFuncInvoker(this.args); + }; + }; + + // src/attributes/guards/Until.ts + var Until = class extends Guard { + constructor(condition, args) { + super("until", args, condition); + } + isSatisfied = (agent) => { + const conditionFuncInvoker = Lookup.getFuncInvoker(agent, this.getCondition()); + if (conditionFuncInvoker === null) { + throw new Error( + `cannot evaluate node guard as the condition '${this.getCondition()}' function is not defined on the agent and has not been registered` + ); + } + return !!!conditionFuncInvoker(this.args); + }; + }; + + // src/attributes/callbacks/Callback.ts + var Callback = class extends Attribute { + constructor(type, args, functionName) { + super(type, args); + this.functionName = functionName; + } + getFunctionName = () => this.functionName; + isGuard = () => false; + getDetails() { + return { + type: this.getType(), + args: this.getArguments(), + functionName: this.getFunctionName() + }; + } + }; + + // src/attributes/callbacks/Entry.ts + var Entry = class extends Callback { + constructor(functionName, args) { + super("entry", args, functionName); + } + callAgentFunction = (agent) => { + const callbackFuncInvoker = Lookup.getFuncInvoker(agent, this.getFunctionName()); + if (callbackFuncInvoker === null) { + throw new Error( + `cannot call entry function '${this.getFunctionName()}' as is not defined on the agent and has not been registered` + ); + } + callbackFuncInvoker(this.args); + }; + }; + + // src/attributes/callbacks/Exit.ts + var Exit = class extends Callback { + constructor(functionName, args) { + super("exit", args, functionName); + } + callAgentFunction = (agent, isSuccess, isAborted) => { + const callbackFuncInvoker = Lookup.getFuncInvoker(agent, this.getFunctionName()); + if (callbackFuncInvoker === null) { + throw new Error( + `cannot call exit function '${this.getFunctionName()}' as is not defined on the agent and has not been registered` + ); + } + callbackFuncInvoker([{ value: { succeeded: isSuccess, aborted: isAborted } }, ...this.args]); + }; + }; + + // src/attributes/callbacks/Step.ts + var Step = class extends Callback { + constructor(functionName, args) { + super("step", args, functionName); + } + callAgentFunction = (agent) => { + const callbackFuncInvoker = Lookup.getFuncInvoker(agent, this.getFunctionName()); + if (callbackFuncInvoker === null) { + throw new Error( + `cannot call step function '${this.getFunctionName()}' as is not defined on the agent and has not been registered` + ); + } + callbackFuncInvoker(this.args); + }; + }; + + // src/RootAstNodesBuilder.ts + var AttributeFactories = { + WHILE: (condition, attributeArguments) => new While(condition, attributeArguments), + UNTIL: (condition, attributeArguments) => new Until(condition, attributeArguments), + ENTRY: (functionName, attributeArguments) => new Entry(functionName, attributeArguments), + EXIT: (functionName, attributeArguments) => new Exit(functionName, attributeArguments), + STEP: (functionName, attributeArguments) => new Step(functionName, attributeArguments) + }; + var ASTNodeFactories = { + ROOT: () => ({ + type: "root", + attributes: [], + name: null, + children: [], + validate(depth) { + if (depth > 1) { + throw new Error("a root node cannot be the child of another node"); + } + if (this.children.length !== 1) { + throw new Error("a root node must have a single child"); + } + }, + createNodeInstance(namedRootNodeProvider, visitedBranches) { + return new Root( + this.attributes, + this.children[0].createNodeInstance(namedRootNodeProvider, visitedBranches.slice()) + ); + } + }), + BRANCH: () => ({ + type: "branch", + branchName: "", + validate() { + }, + createNodeInstance(namedRootNodeProvider, visitedBranches) { + const targetRootNode = namedRootNodeProvider(this.branchName); + if (visitedBranches.indexOf(this.branchName) !== -1) { + throw new Error(`circular dependency found in branch node references for branch '${this.branchName}'`); + } + if (targetRootNode) { + return targetRootNode.createNodeInstance(namedRootNodeProvider, visitedBranches.concat(this.branchName)).getChildren()[0]; + } else { + throw new Error(`branch references root node '${this.branchName}' which has not been defined`); + } + } + }), + SELECTOR: () => ({ + type: "selector", + attributes: [], + children: [], + validate() { + if (this.children.length < 1) { + throw new Error("a selector node must have at least a single child"); + } + }, + createNodeInstance(namedRootNodeProvider, visitedBranches) { + return new Selector( + this.attributes, + this.children.map((child) => child.createNodeInstance(namedRootNodeProvider, visitedBranches.slice())) + ); + } + }), + SEQUENCE: () => ({ + type: "sequence", + attributes: [], + children: [], + validate() { + if (this.children.length < 1) { + throw new Error("a sequence node must have at least a single child"); + } + }, + createNodeInstance(namedRootNodeProvider, visitedBranches) { + return new Sequence( + this.attributes, + this.children.map((child) => child.createNodeInstance(namedRootNodeProvider, visitedBranches.slice())) + ); + } + }), + PARALLEL: () => ({ + type: "parallel", + attributes: [], + children: [], + validate() { + if (this.children.length < 1) { + throw new Error("a parallel node must have at least a single child"); + } + }, + createNodeInstance(namedRootNodeProvider, visitedBranches) { + return new Parallel( + this.attributes, + this.children.map((child) => child.createNodeInstance(namedRootNodeProvider, visitedBranches.slice())) + ); + } + }), + LOTTO: () => ({ + type: "lotto", + attributes: [], + children: [], + tickets: [], + validate() { + if (this.children.length < 1) { + throw new Error("a lotto node must have at least a single child"); + } + }, + createNodeInstance(namedRootNodeProvider, visitedBranches) { + return new Lotto( + this.attributes, + this.tickets, + this.children.map((child) => child.createNodeInstance(namedRootNodeProvider, visitedBranches.slice())) + ); + } + }), + REPEAT: () => ({ + type: "repeat", + attributes: [], + iterations: null, + iterationsMin: null, + iterationsMax: null, + children: [], + validate() { + if (this.children.length !== 1) { + throw new Error("a repeat node must have a single child"); + } + if (this.iterations !== null) { + if (this.iterations < 0) { + throw new Error("a repeat node must have a positive number of iterations if defined"); + } + } else if (this.iterationsMin !== null && this.iterationsMax !== null) { + if (this.iterationsMin < 0 || this.iterationsMax < 0) { + throw new Error( + "a repeat node must have a positive minimum and maximum iteration count if defined" + ); + } + if (this.iterationsMin > this.iterationsMax) { + throw new Error( + "a repeat node must not have a minimum iteration count that exceeds the maximum iteration count" + ); + } + } else { + } + }, + createNodeInstance(namedRootNodeProvider, visitedBranches) { + return new Repeat( + this.attributes, + this.iterations, + this.iterationsMin, + this.iterationsMax, + this.children[0].createNodeInstance(namedRootNodeProvider, visitedBranches.slice()) + ); + } + }), + RETRY: () => ({ + type: "retry", + attributes: [], + attempts: null, + attemptsMin: null, + attemptsMax: null, + children: [], + validate() { + if (this.children.length !== 1) { + throw new Error("a retry node must have a single child"); + } + if (this.attempts !== null) { + if (this.attempts < 0) { + throw new Error("a retry node must have a positive number of attempts if defined"); + } + } else if (this.attemptsMin !== null && this.attemptsMax !== null) { + if (this.attemptsMin < 0 || this.attemptsMax < 0) { + throw new Error("a retry node must have a positive minimum and maximum attempt count if defined"); + } + if (this.attemptsMin > this.attemptsMax) { + throw new Error( + "a retry node must not have a minimum attempt count that exceeds the maximum attempt count" + ); + } + } else { + } + }, + createNodeInstance(namedRootNodeProvider, visitedBranches) { + return new Retry( + this.attributes, + this.attempts, + this.attemptsMin, + this.attemptsMax, + this.children[0].createNodeInstance(namedRootNodeProvider, visitedBranches.slice()) + ); + } + }), + FLIP: () => ({ + type: "flip", + attributes: [], + children: [], + validate() { + if (this.children.length !== 1) { + throw new Error("a flip node must have a single child"); + } + }, + createNodeInstance(namedRootNodeProvider, visitedBranches) { + return new Flip( + this.attributes, + this.children[0].createNodeInstance(namedRootNodeProvider, visitedBranches.slice()) + ); + } + }), + SUCCEED: () => ({ + type: "succeed", + attributes: [], + children: [], + validate() { + if (this.children.length !== 1) { + throw new Error("a succeed node must have a single child"); + } + }, + createNodeInstance(namedRootNodeProvider, visitedBranches) { + return new Succeed( + this.attributes, + this.children[0].createNodeInstance(namedRootNodeProvider, visitedBranches.slice()) + ); + } + }), + FAIL: () => ({ + type: "fail", + attributes: [], + children: [], + validate() { + if (this.children.length !== 1) { + throw new Error("a fail node must have a single child"); + } + }, + createNodeInstance(namedRootNodeProvider, visitedBranches) { + return new Fail( + this.attributes, + this.children[0].createNodeInstance(namedRootNodeProvider, visitedBranches.slice()) + ); + } + }), + WAIT: () => ({ + type: "wait", + attributes: [], + duration: null, + durationMin: null, + durationMax: null, + validate() { + if (this.duration !== null) { + if (this.duration < 0) { + throw new Error("a wait node must have a positive duration"); + } + } else if (this.durationMin !== null && this.durationMax !== null) { + if (this.durationMin < 0 || this.durationMax < 0) { + throw new Error("a wait node must have a positive minimum and maximum duration"); + } + if (this.durationMin > this.durationMax) { + throw new Error("a wait node must not have a minimum duration that exceeds the maximum duration"); + } + } else { + } + }, + createNodeInstance() { + return new Wait(this.attributes, this.duration, this.durationMin, this.durationMax); + } + }), + ACTION: () => ({ + type: "action", + attributes: [], + actionName: "", + actionArguments: [], + validate() { + }, + createNodeInstance() { + return new Action(this.attributes, this.actionName, this.actionArguments); + } + }), + CONDITION: () => ({ + type: "condition", + attributes: [], + conditionName: "", + conditionArguments: [], + validate() { + }, + createNodeInstance() { + return new Condition(this.attributes, this.conditionName, this.conditionArguments); + } + }) + }; + function buildRootASTNodes(definition) { + const { placeholders, processedDefinition } = substituteStringLiterals(definition); + const tokens = parseTokensFromDefinition(processedDefinition); + if (tokens.length < 3) { + throw new Error("invalid token count"); + } + if (tokens.filter((token) => token === "{").length !== tokens.filter((token) => token === "}").length) { + throw new Error("scope character mismatch"); + } + const stack = [[]]; + const rootScope = stack[0]; + while (tokens.length) { + const token = tokens.shift(); + const currentScope = stack[stack.length - 1]; + switch (token.toUpperCase()) { + case "ROOT": { + const node = ASTNodeFactories.ROOT(); + rootScope.push(node); + if (tokens[0] === "[") { + const rootArguments = getArguments(tokens, placeholders); + if (rootArguments.length === 1 && rootArguments[0].type === "identifier") { + node.name = rootArguments[0].value; + } else { + throw new Error("expected single root name argument"); + } + } + node.attributes = getAttributes(tokens, placeholders); + popAndCheck(tokens, "{"); + stack.push(node.children); + break; + } + case "BRANCH": { + const node = ASTNodeFactories.BRANCH(); + currentScope.push(node); + if (tokens[0] !== "[") { + throw new Error("expected single branch name argument"); + } + const branchArguments = getArguments(tokens, placeholders); + if (branchArguments.length === 1 && branchArguments[0].type === "identifier") { + node.branchName = branchArguments[0].value; + } else { + throw new Error("expected single branch name argument"); + } + break; + } + case "SELECTOR": { + const node = ASTNodeFactories.SELECTOR(); + currentScope.push(node); + node.attributes = getAttributes(tokens, placeholders); + popAndCheck(tokens, "{"); + stack.push(node.children); + break; + } + case "SEQUENCE": { + const node = ASTNodeFactories.SEQUENCE(); + currentScope.push(node); + node.attributes = getAttributes(tokens, placeholders); + popAndCheck(tokens, "{"); + stack.push(node.children); + break; + } + case "PARALLEL": { + const node = ASTNodeFactories.PARALLEL(); + currentScope.push(node); + node.attributes = getAttributes(tokens, placeholders); + popAndCheck(tokens, "{"); + stack.push(node.children); + break; + } + case "LOTTO": { + const node = ASTNodeFactories.LOTTO(); + currentScope.push(node); + if (tokens[0] === "[") { + node.tickets = getArguments( + tokens, + placeholders, + (arg) => arg.type === "number" && !!arg.isInteger, + "lotto node ticket counts must be integer values" + ).map((argument) => argument.value); + } + node.attributes = getAttributes(tokens, placeholders); + popAndCheck(tokens, "{"); + stack.push(node.children); + break; + } + case "CONDITION": { + const node = ASTNodeFactories.CONDITION(); + currentScope.push(node); + if (tokens[0] !== "[") { + throw new Error("expected condition name identifier argument"); + } + const conditionArguments = getArguments(tokens, placeholders); + if (conditionArguments.length && conditionArguments[0].type === "identifier") { + node.conditionName = conditionArguments.shift().value; + } else { + throw new Error("expected condition name identifier argument"); + } + conditionArguments.filter((arg) => arg.type === "identifier").forEach((arg) => { + throw new Error( + "invalid condition node argument value '" + arg.value + "', must be string, number, boolean or null" + ); + }); + node.conditionArguments = conditionArguments; + node.attributes = getAttributes(tokens, placeholders); + break; + } + case "FLIP": { + const node = ASTNodeFactories.FLIP(); + currentScope.push(node); + node.attributes = getAttributes(tokens, placeholders); + popAndCheck(tokens, "{"); + stack.push(node.children); + break; + } + case "SUCCEED": { + const node = ASTNodeFactories.SUCCEED(); + currentScope.push(node); + node.attributes = getAttributes(tokens, placeholders); + popAndCheck(tokens, "{"); + stack.push(node.children); + break; + } + case "FAIL": { + const node = ASTNodeFactories.FAIL(); + currentScope.push(node); + node.attributes = getAttributes(tokens, placeholders); + popAndCheck(tokens, "{"); + stack.push(node.children); + break; + } + case "WAIT": { + const node = ASTNodeFactories.WAIT(); + currentScope.push(node); + if (tokens[0] === "[") { + const nodeArguments = getArguments( + tokens, + placeholders, + (arg) => arg.type === "number" && !!arg.isInteger, + "wait node durations must be integer values" + ).map((argument) => argument.value); + if (nodeArguments.length === 1) { + node.duration = nodeArguments[0]; + } else if (nodeArguments.length === 2) { + node.durationMin = nodeArguments[0]; + node.durationMax = nodeArguments[1]; + } else if (nodeArguments.length > 2) { + throw new Error("invalid number of wait node duration arguments defined"); + } + } + node.attributes = getAttributes(tokens, placeholders); + break; + } + case "REPEAT": { + const node = ASTNodeFactories.REPEAT(); + currentScope.push(node); + if (tokens[0] === "[") { + const nodeArguments = getArguments( + tokens, + placeholders, + (arg) => arg.type === "number" && !!arg.isInteger, + "repeat node iteration counts must be integer values" + ).map((argument) => argument.value); + if (nodeArguments.length === 1) { + node.iterations = nodeArguments[0]; + } else if (nodeArguments.length === 2) { + node.iterationsMin = nodeArguments[0]; + node.iterationsMax = nodeArguments[1]; + } else { + throw new Error("invalid number of repeat node iteration count arguments defined"); + } + } + node.attributes = getAttributes(tokens, placeholders); + popAndCheck(tokens, "{"); + stack.push(node.children); + break; + } + case "RETRY": { + const node = ASTNodeFactories.RETRY(); + currentScope.push(node); + if (tokens[0] === "[") { + const nodeArguments = getArguments( + tokens, + placeholders, + (arg) => arg.type === "number" && !!arg.isInteger, + "retry node attempt counts must be integer values" + ).map((argument) => argument.value); + if (nodeArguments.length === 1) { + node.attempts = nodeArguments[0]; + } else if (nodeArguments.length === 2) { + node.attemptsMin = nodeArguments[0]; + node.attemptsMax = nodeArguments[1]; + } else { + throw new Error("invalid number of retry node attempt count arguments defined"); + } + } + node.attributes = getAttributes(tokens, placeholders); + popAndCheck(tokens, "{"); + stack.push(node.children); + break; + } + case "ACTION": { + const node = ASTNodeFactories.ACTION(); + currentScope.push(node); + if (tokens[0] !== "[") { + throw new Error("expected action name identifier argument"); + } + const actionArguments = getArguments(tokens, placeholders); + if (actionArguments.length && actionArguments[0].type === "identifier") { + node.actionName = actionArguments.shift().value; + } else { + throw new Error("expected action name identifier argument"); + } + actionArguments.filter((arg) => arg.type === "identifier").forEach((arg) => { + throw new Error( + "invalid action node argument value '" + arg.value + "', must be string, number, boolean or null" + ); + }); + node.actionArguments = actionArguments; + node.attributes = getAttributes(tokens, placeholders); + break; + } + case "}": { + stack.pop(); + break; + } + default: { + throw new Error(`unexpected token '${token}'`); + } + } + } + const validateASTNode = (node, depth) => { + node.validate(depth); + (node.children || []).forEach((child) => validateASTNode(child, depth + 1)); + }; + validateASTNode( + { + children: stack[0], + validate() { + if (this.children.length === 0) { + throw new Error("expected root node to have been defined"); + } + for (const definitionLevelNode of this.children) { + if (definitionLevelNode.type !== "root") { + throw new Error("expected root node at base of definition"); + } + } + if (this.children.filter((definitionLevelNode) => definitionLevelNode.name === null).length !== 1) { + throw new Error("expected single unnamed root node at base of definition to act as main root"); + } + const rootNodeNames = []; + for (const definitionLevelNode of this.children) { + if (rootNodeNames.indexOf(definitionLevelNode.name) !== -1) { + throw new Error(`multiple root nodes found with duplicate name '${definitionLevelNode.name}'`); + } else { + rootNodeNames.push(definitionLevelNode.name); + } + } + } + }, + 0 + ); + return stack[0]; + } + function popAndCheck(tokens, expected) { + const popped = tokens.shift(); + if (popped === void 0) { + throw new Error("unexpected end of definition"); + } + if (expected !== void 0) { + var tokenMatchesExpectation = [].concat(expected).some((item) => popped.toUpperCase() === item.toUpperCase()); + if (!tokenMatchesExpectation) { + const expectationString = [].concat(expected).map((item) => "'" + item + "'").join(" or "); + throw new Error(`unexpected token found. Expected '${expectationString}' but got '${popped}'`); + } + } + return popped; + } + function getArguments(tokens, stringArgumentPlaceholders, argumentValidator, validationFailedMessage) { + const closer = popAndCheck(tokens, ["[", "("]) === "[" ? "]" : ")"; + const argumentListTokens = []; + const argumentList = []; + while (tokens.length && tokens[0] !== closer) { + argumentListTokens.push(tokens.shift()); + } + argumentListTokens.forEach((token, index) => { + const shouldBeArgumentToken = !(index & 1); + if (shouldBeArgumentToken) { + const argumentDefinition = getArgumentDefinition(token, stringArgumentPlaceholders); + if (argumentValidator && !argumentValidator(argumentDefinition)) { + throw new Error(validationFailedMessage); + } + argumentList.push(argumentDefinition); + } else { + if (token !== ",") { + throw new Error(`invalid argument list, expected ',' or ']' but got '${token}'`); + } + } + }); + popAndCheck(tokens, closer); + return argumentList; + } + function getArgumentDefinition(token, stringArgumentPlaceholders) { + if (token === "null") { + return { + value: null, + type: "null" + }; + } + if (token === "true" || token === "false") { + return { + value: token === "true", + type: "boolean" + }; + } + if (!isNaN(token)) { + return { + value: parseFloat(token), + isInteger: parseFloat(token) === parseInt(token, 10), + type: "number" + }; + } + if (token.match(/^@@\d+@@$/g)) { + return { + value: stringArgumentPlaceholders[token].replace('\\"', '"'), + type: "string" + }; + } + return { + value: token, + type: "identifier" + }; + } + function getAttributes(tokens, stringArgumentPlaceholders) { + const attributes = []; + const attributesFound = []; + let attributeFactory = AttributeFactories[(tokens[0] || "").toUpperCase()]; + while (attributeFactory) { + if (attributesFound.indexOf(tokens[0].toUpperCase()) !== -1) { + throw new Error(`duplicate attribute '${tokens[0].toUpperCase()}' found for node`); + } + attributesFound.push(tokens.shift().toUpperCase()); + const attributeArguments = getArguments(tokens, stringArgumentPlaceholders); + if (attributeArguments.length === 0 || attributeArguments[0].type !== "identifier") { + throw new Error("expected agent function name identifier argument for attribute"); + } + const attributeFunctionName = attributeArguments.shift(); + attributeArguments.filter((arg) => arg.type === "identifier").forEach((arg) => { + throw new Error( + "invalid attribute argument value '" + arg.value + "', must be string, number, boolean or null" + ); + }); + attributes.push(attributeFactory(attributeFunctionName.value, attributeArguments)); + attributeFactory = AttributeFactories[(tokens[0] || "").toUpperCase()]; + } + return attributes; + } + function substituteStringLiterals(definition) { + const placeholders = {}; + const processedDefinition = definition.replace(/\"(\\.|[^"\\])*\"/g, (match) => { + var strippedMatch = match.substring(1, match.length - 1); + var placeholder = Object.keys(placeholders).find((key) => placeholders[key] === strippedMatch); + if (!placeholder) { + placeholder = `@@${Object.keys(placeholders).length}@@`; + placeholders[placeholder] = strippedMatch; + } + return placeholder; + }); + return { placeholders, processedDefinition }; + } + function parseTokensFromDefinition(definition) { + definition = definition.replace(/\(/g, " ( "); + definition = definition.replace(/\)/g, " ) "); + definition = definition.replace(/\{/g, " { "); + definition = definition.replace(/\}/g, " } "); + definition = definition.replace(/\]/g, " ] "); + definition = definition.replace(/\[/g, " [ "); + definition = definition.replace(/\,/g, " , "); + return definition.replace(/\s+/g, " ").trim().split(" "); + } + + // src/BehaviourTree.ts + var BehaviourTree = class { + constructor(definition, agent, options = {}) { + this.agent = agent; + this.options = options; + if (typeof definition !== "string") { + throw new Error("the tree definition must be a string"); + } + if (typeof agent !== "object" || agent === null) { + throw new Error("the agent must be defined and not null"); + } + this.rootNode = BehaviourTree._createRootNode(definition); + } + rootNode; + isRunning() { + return this.rootNode.getState() === "mistreevous.running" /* RUNNING */; + } + getState() { + return this.rootNode.getState(); + } + step() { + if (this.rootNode.getState() === "mistreevous.succeeded" /* SUCCEEDED */ || this.rootNode.getState() === "mistreevous.failed" /* FAILED */) { + this.rootNode.reset(); + } + try { + this.rootNode.update(this.agent, this.options); + } catch (exception) { + throw new Error(`error stepping tree: ${exception.message}`); + } + } + reset() { + this.rootNode.reset(); + } + getFlattenedNodeDetails() { + const flattenedTreeNodes = []; + const processNode = (node, parentUid) => { + const guards = node.getAttributes().filter((attribute) => attribute.isGuard()).map((attribute) => attribute.getDetails()); + const callbacks = node.getAttributes().filter((attribute) => !attribute.isGuard()).map((attribute) => attribute.getDetails()); + flattenedTreeNodes.push({ + id: node.getUid(), + type: node.getType(), + caption: node.getName(), + state: node.getState(), + guards, + callbacks, + args: node.getArguments(), + parentId: parentUid + }); + if (!node.isLeafNode()) { + node.getChildren().forEach((child) => processNode(child, node.getUid())); + } + }; + processNode(this.rootNode, null); + return flattenedTreeNodes; + } + static register(name, value) { + if (typeof value === "function") { + Lookup.setFunc(name, value); + } else if (typeof value === "string") { + let rootASTNodes; + try { + rootASTNodes = buildRootASTNodes(value); + } catch (exception) { + throw new Error(`error registering definition: ${exception.message}`); + } + if (rootASTNodes.length != 1 || rootASTNodes[0].name !== null) { + throw new Error("error registering definition: expected a single unnamed root node"); + } + Lookup.setSubtree(name, rootASTNodes[0]); + } else { + throw new Error("unexpected value, expected string definition or function"); + } + } + static unregister(name) { + Lookup.remove(name); + } + static unregisterAll() { + Lookup.empty(); + } + static _createRootNode(definition) { + try { + } catch (exception) { + console.log(exception); + } + try { + const rootASTNodes = buildRootASTNodes(definition); + const mainRootNodeKey = Symbol("__root__"); + const rootNodeMap = {}; + for (const rootASTNode of rootASTNodes) { + rootNodeMap[rootASTNode.name === null ? mainRootNodeKey : rootASTNode.name] = rootASTNode; + } + const rootNode = rootNodeMap[mainRootNodeKey].createNodeInstance( + (name) => rootNodeMap[name] ? rootNodeMap[name] : Lookup.getSubtree(name), + [] + ); + BehaviourTree._applyLeafNodeGuardPaths(rootNode); + return rootNode; + } catch (exception) { + throw new Error(`error parsing tree: ${exception.message}`); + } + } + static _applyLeafNodeGuardPaths(rootNode) { + const nodePaths = []; + const findLeafNodes = (path, node) => { + path = path.concat(node); + if (node.isLeafNode()) { + nodePaths.push(path); + } else { + node.getChildren().forEach((child) => findLeafNodes(path, child)); + } + }; + findLeafNodes([], rootNode); + nodePaths.forEach((path) => { + for (let depth = 0; depth < path.length; depth++) { + const currentNode = path[depth]; + if (currentNode.hasGuardPath()) { + continue; + } + const guardPath = new GuardPath( + path.slice(0, depth + 1).map((node) => ({ node, guards: node.getGuardAttributes() })).filter((details) => details.guards.length > 0) + ); + currentNode.setGuardPath(guardPath); + } + }); + } + }; + return __toCommonJS(src_exports); +})(); +//# sourceMappingURL=bundle.js.map diff --git a/dist/bundle.js.map b/dist/bundle.js.map new file mode 100644 index 0000000..b76ce81 --- /dev/null +++ b/dist/bundle.js.map @@ -0,0 +1,7 @@ +{ + "version": 3, + "sources": ["../node_modules/lotto-draw/dist/Participant.js", "../node_modules/lotto-draw/dist/Utilities.js", "../node_modules/lotto-draw/dist/Lotto.js", "../node_modules/lotto-draw/dist/createLotto.js", "../node_modules/lotto-draw/dist/index.js", "../src/index.ts", "../src/attributes/guards/GuardUnsatisifedException.ts", "../src/attributes/guards/GuardPath.ts", "../src/State.ts", "../src/nodes/Node.ts", "../src/nodes/leaf/Leaf.ts", "../src/Lookup.ts", "../src/nodes/leaf/Action.ts", "../src/nodes/leaf/Condition.ts", "../src/nodes/leaf/Wait.ts", "../src/nodes/decorator/Decorator.ts", "../src/nodes/decorator/Root.ts", "../src/nodes/decorator/Repeat.ts", "../src/nodes/decorator/Retry.ts", "../src/nodes/decorator/Flip.ts", "../src/nodes/decorator/Succeed.ts", "../src/nodes/decorator/Fail.ts", "../src/nodes/composite/Lotto.ts", "../src/nodes/composite/Composite.ts", "../src/nodes/composite/Selector.ts", "../src/nodes/composite/Sequence.ts", "../src/nodes/composite/Parallel.ts", "../src/attributes/Attribute.ts", "../src/attributes/guards/Guard.ts", "../src/attributes/guards/While.ts", "../src/attributes/guards/Until.ts", "../src/attributes/callbacks/Callback.ts", "../src/attributes/callbacks/Entry.ts", "../src/attributes/callbacks/Exit.ts", "../src/attributes/callbacks/Step.ts", "../src/RootAstNodesBuilder.ts", "../src/BehaviourTree.ts"], + "sourcesContent": ["\"use strict\";\r\nObject.defineProperty(exports, \"__esModule\", { value: true });\r\nexports.Participant = void 0;\r\n/**\r\n * A participant that holds a number of tickets.\r\n */\r\nvar Participant = /** @class */ (function () {\r\n /**\r\n * Creates an instance of the Participant class.\r\n * @param participant The actual participant.\r\n * @param tickets The number of tickets held by the participant.\r\n */\r\n function Participant(participant, tickets) {\r\n if (tickets === void 0) { tickets = 1; }\r\n this._participant = participant;\r\n this._tickets = tickets;\r\n }\r\n Object.defineProperty(Participant.prototype, \"participant\", {\r\n /** Gets the actual participant. */\r\n get: function () {\r\n return this._participant;\r\n },\r\n enumerable: false,\r\n configurable: true\r\n });\r\n Object.defineProperty(Participant.prototype, \"tickets\", {\r\n /** Gets or sets the number of tickets held by the participant. */\r\n get: function () {\r\n return this._tickets;\r\n },\r\n set: function (value) {\r\n this._tickets = value;\r\n },\r\n enumerable: false,\r\n configurable: true\r\n });\r\n return Participant;\r\n}());\r\nexports.Participant = Participant;\r\n", "\"use strict\";\r\nObject.defineProperty(exports, \"__esModule\", { value: true });\r\nexports.isNaturalNumber = exports.isNullOrUndefined = void 0;\r\n/**\r\n * Gets whether the value provided is null or undefined.\r\n * @param value The value to check.\r\n * @returns Whether the value provided is null or undefined.\r\n */\r\nfunction isNullOrUndefined(value) {\r\n return value === null || value === undefined;\r\n}\r\nexports.isNullOrUndefined = isNullOrUndefined;\r\n/**\r\n * Gets whether the value provided is a natural number.\r\n * @param value The value to check.\r\n * @returns Whether the value provided is a natural number.\r\n */\r\nfunction isNaturalNumber(value) {\r\n return typeof value === \"number\" && value >= 1 && Math.floor(value) === value;\r\n}\r\nexports.isNaturalNumber = isNaturalNumber;\r\n", "\"use strict\";\r\nObject.defineProperty(exports, \"__esModule\", { value: true });\r\nexports.Lotto = void 0;\r\nvar Participant_1 = require(\"./Participant\");\r\nvar Utilities_1 = require(\"./Utilities\");\r\n/**\r\n * Represents a lotto consisting of a number of pickable ticket-holding participants.\r\n */\r\nvar Lotto = /** @class */ (function () {\r\n /**\r\n * Creates a new instance of Lotto.\r\n * @param customRandom The custom RNG to use in place of Math.random().\r\n */\r\n function Lotto(customRandom) {\r\n /** The array of participants that are holding tickets in the lotto. */\r\n this._participants = [];\r\n this._customRandom = customRandom;\r\n }\r\n /**\r\n * Adds a participant with the specified number of tickets, or adds to the participant ticket count if the participant already holds tickets.\r\n * @param participant The participant to add or to increase the ticket count for if they already hold tickets.\r\n * @param tickets The number of tickets, defaults to 1.\r\n * @returns The Lotto instance.\r\n */\r\n Lotto.prototype.add = function (participant, tickets) {\r\n if (tickets === void 0) { tickets = 1; }\r\n // Check that we have a valid ticket count.\r\n if (!(0, Utilities_1.isNaturalNumber)(tickets)) {\r\n throw new Error(\"tickets value must be a natural number\");\r\n }\r\n // Check whether this participant has already been added.\r\n var existingParticipant = this._participants.find(function (part) { return part.participant === participant; });\r\n if (existingParticipant) {\r\n // The participant has already been added to the lotto so just add to their ticket count.\r\n existingParticipant.tickets += tickets;\r\n }\r\n else {\r\n // The participant is not part of the lotto so we should add them.\r\n this._participants.push(new Participant_1.Participant(participant, tickets));\r\n }\r\n return this;\r\n };\r\n /**\r\n * Removes the specified number of tickets for the given participant from the draw, or all tickets if a ticket number is not defined.\r\n * @param participant The participant to remove tickets for.\r\n * @param tickets The number of tickets to remove, or undefined if all tickets are to be removed.\r\n * @returns The Lotto instance.\r\n */\r\n Lotto.prototype.remove = function (participant, tickets) {\r\n // Attempt to get the existing participant.\r\n var existingParticipant = this._participants.find(function (part) { return part.participant === participant; });\r\n // There is nothing to do if the specified participant isn't even part of the lotto.\r\n if (!existingParticipant) {\r\n return this;\r\n }\r\n // Check whether a tickets value was given.\r\n if (tickets !== undefined) {\r\n // Check that we have a valid ticket count.\r\n if (!(0, Utilities_1.isNaturalNumber)(tickets)) {\r\n throw new Error(\"tickets value must be a natural number\");\r\n }\r\n existingParticipant.tickets -= tickets;\r\n // If the participant no longer holds any tickets then they should be removed.\r\n if (existingParticipant.tickets < 1) {\r\n this._participants = this._participants.filter(function (part) { return part !== existingParticipant; });\r\n }\r\n }\r\n else {\r\n // We are removing all tickets for the participant so just remove them from the lotto.\r\n this._participants = this._participants.filter(function (part) { return part !== existingParticipant; });\r\n }\r\n return this;\r\n };\r\n /**\r\n * Draw a winning ticket and return the participant that holds the ticket.\r\n * @param options The draw options.\r\n * @returns The participant that holds the winning ticket.\r\n */\r\n Lotto.prototype.draw = function (options) {\r\n if (options === void 0) { options = {}; }\r\n // If we have no participants then just return null.\r\n if (this._participants.length === 0) {\r\n return null;\r\n }\r\n var redrawable = (0, Utilities_1.isNullOrUndefined)(options.redrawable) ? true : options.redrawable;\r\n var pickable = [];\r\n this._participants.forEach(function (_a) {\r\n var participant = _a.participant, tickets = _a.tickets;\r\n for (var ticketCount = 0; ticketCount < tickets; ticketCount++) {\r\n pickable.push(participant);\r\n }\r\n });\r\n var random;\r\n // We need a random floating-point number between 0 (inclusive) and 1 to scale up to pick our winner.\r\n // If a custom random function exists then we should use that or fall back to Math.random().\r\n if (this._customRandom) {\r\n // Call our custom random function to get a random floating-point number.\r\n random = this._customRandom();\r\n // Verify that the result of calling our custom random function is a number between 0 (inclusive) and 1.\r\n if (typeof random !== \"number\" || random < 0 || random >= 1) {\r\n throw new Error(\"the 'random' function provided did not return a number between 0 (inclusive) and 1\");\r\n }\r\n }\r\n else {\r\n // No custom random function was defined so just use good ol' Math.random().\r\n random = Math.random();\r\n }\r\n // Pick a winning participant.\r\n var winner = pickable[Math.floor(random * pickable.length)];\r\n // If the ticket isn't redrawable then we should remove a ticket from the winning participants ticket count.\r\n if (!redrawable) {\r\n this.remove(winner, 1);\r\n }\r\n // Return the winning participant.\r\n return winner;\r\n };\r\n /**\r\n * Draws multiple winning tickets and return an array of the participants that hold the winning tickets.\r\n * @param tickets The number of winning tickets to draw.\r\n * @param options The draw multiple options.\r\n * @returns An array of the participants that hold the winning tickets.\r\n */\r\n Lotto.prototype.drawMultiple = function (tickets, options) {\r\n if (options === void 0) { options = {}; }\r\n var uniqueResults = (0, Utilities_1.isNullOrUndefined)(options.unique) ? false : options.unique;\r\n // Handle cases where the user has asked for zero tickets (no idea why they would do this be we should trust them).\r\n if (tickets === 0) {\r\n return [];\r\n }\r\n // Now that we know out tickets value is not zero we should check that it is a valid natural number.\r\n if (!(0, Utilities_1.isNaturalNumber)(tickets)) {\r\n throw new Error(\"tickets value must be a natural number\");\r\n }\r\n var result = [];\r\n // Keep drawing tickets until we either reach the number of required tickets or we simply run out of tickets to draw.\r\n // We can run out of tickets to draw if 'options.redrawable' is explicity 'false' or we just had no participants when 'drawMultiple' was called.\r\n while (result.length < tickets && this._participants.length > 0) {\r\n result.push(this.draw(options));\r\n }\r\n // If the 'unique' draw option is set then we need to remove duplicates from the result list.\r\n if (uniqueResults) {\r\n // Create an array to store our unique results.\r\n var unique = [];\r\n // Iterate over all of our participants (with potential duplicates) and populate our array of unique values.\r\n for (var _i = 0, result_1 = result; _i < result_1.length; _i++) {\r\n var participant = result_1[_i];\r\n if (unique.indexOf(participant) === -1) {\r\n unique.push(participant);\r\n }\r\n }\r\n result = unique;\r\n }\r\n return result;\r\n };\r\n return Lotto;\r\n}());\r\nexports.Lotto = Lotto;\r\n", "\"use strict\";\r\nObject.defineProperty(exports, \"__esModule\", { value: true });\r\nexports.createLotto = void 0;\r\nvar Lotto_1 = require(\"./Lotto\");\r\n/**\r\n * A function that creates and returns a Lotto instance.\r\n * @param participantsOrOptions An array of initial participants or options relating to the creation of a Lotto instance.\r\n * @returns A new Lotto instance.\r\n */\r\nfunction createLotto(participantsOrOptions) {\r\n // If no initial participants or lotto options were provided as an argument then we can just return a new lotto instance now.\r\n if (!participantsOrOptions) {\r\n return new Lotto_1.Lotto();\r\n }\r\n // Check whether we were provided with an array of initial participants or a lotto options object.\r\n if (Array.isArray(participantsOrOptions)) {\r\n // We are dealing with a pre-defined array of participants.\r\n var participants = participantsOrOptions;\r\n var lotto_1 = new Lotto_1.Lotto();\r\n // If the lotto participants have been defined upfront then we will need to add them all to our lotto instance now.\r\n participants.forEach(function (_a) {\r\n var participant = _a[0], tokens = _a[1];\r\n return lotto_1.add(participant, tokens);\r\n });\r\n // Return the Lotto instance.\r\n return lotto_1;\r\n }\r\n else {\r\n // We are dealing with some lotto options.\r\n var random = participantsOrOptions.random, participants = participantsOrOptions.participants;\r\n // Create a Lotto instance passing the custom RNG function to use in place of Math.random() (which could be undefined).\r\n var lotto_2 = new Lotto_1.Lotto(random);\r\n // If the lotto participants have been defined upfront as part of the options then we will need to add them all to our lotto instance now.\r\n if (participants) {\r\n participants.forEach(function (_a) {\r\n var participant = _a[0], tokens = _a[1];\r\n return lotto_2.add(participant, tokens);\r\n });\r\n }\r\n // Return the Lotto instance.\r\n return lotto_2;\r\n }\r\n}\r\nexports.createLotto = createLotto;\r\n", "\"use strict\";\r\nObject.defineProperty(exports, \"__esModule\", { value: true });\r\nvar createLotto_1 = require(\"./createLotto\");\r\nexports.default = createLotto_1.createLotto;\r\n", "import { BehaviourTree, FlattenedTreeNode } from \"./BehaviourTree\";\nimport State from \"./State\";\n\nexport { BehaviourTree, State };\nexport type { FlattenedTreeNode };\n", "import Node from \"../../nodes/Node\";\n\n/**\n * An exception thrown when evaluating node guard path conditions and a conditions fails.\n */\nexport default class GuardUnsatisifedException extends Error {\n /**\n * @param source The node at which a guard condition failed.\n */\n constructor(private source: Node) {\n super(\"A guard path condition has failed\");\n }\n\n /**\n * Gets whether the specified node is the node at which a guard condition failed.\n * @param node The node to check against the source node.\n * @returns Whether the specified node is the node at which a guard condition failed.\n */\n isSourceNode = (node: Node) => node === this.source;\n}\n", "import { Agent } from \"../../Agent\";\nimport Guard from \"./Guard\";\nimport Node from \"../../nodes/Node\";\nimport GuardUnsatisifedException from \"./GuardUnsatisifedException\";\n\nexport type GuardPathPart = {\n node: Node;\n guards: Guard[];\n};\n\n/**\n * Represents a path of node guards along a root-to-leaf tree path.\n */\nexport default class GuardPath {\n /**\n * @param nodes An array of objects defining a node instance -> guard link, ordered by node depth.\n */\n constructor(private nodes: GuardPathPart[]) {}\n\n /**\n * Evaluate guard conditions for all guards in the tree path, moving outwards from the root.\n * @param agent The agent, required for guard evaluation.\n * @returns An evaluation results object.\n */\n evaluate = (agent: Agent) => {\n // We need to evaluate guard conditions for nodes up the tree, moving outwards from the root.\n for (const details of this.nodes) {\n // There can be multiple guards per node.\n for (const guard of details.guards) {\n // Check whether the guard condition passes, and throw an exception if not.\n if (!guard.isSatisfied(agent)) {\n throw new GuardUnsatisifedException(details.node);\n }\n }\n }\n };\n}\n", "/**\n * Enumeration of node state types.\n */\nexport enum State {\n READY = \"mistreevous.ready\",\n RUNNING = \"mistreevous.running\",\n SUCCEEDED = \"mistreevous.succeeded\",\n FAILED = \"mistreevous.failed\"\n}\n\nexport { State as default };\n\nexport type CompleteState = State.SUCCEEDED | State.FAILED;\nexport type AnyState = State.READY | State.RUNNING | CompleteState;\n", "import { Agent } from \"../Agent\";\nimport Attribute from \"../attributes/Attribute\";\nimport Entry from \"../attributes/callbacks/Entry\";\nimport Exit from \"../attributes/callbacks/Exit\";\nimport Step from \"../attributes/callbacks/Step\";\nimport Guard from \"../attributes/guards/Guard\";\nimport GuardPath from \"../attributes/guards/GuardPath\";\nimport GuardUnsatisifedException from \"../attributes/guards/GuardUnsatisifedException\";\nimport { BehaviourTreeOptions } from \"../BehaviourTreeOptions\";\nimport { AnyArgument } from \"../RootAstNodesBuilder\";\nimport State, { AnyState } from \"../State\";\nimport Leaf from \"./leaf/Leaf\";\n\n/**\n * A base node.\n */\nexport default abstract class Node {\n /**\n * The node uid.\n */\n private readonly uid: string = createNodeUid();\n /**\n * The node state.\n */\n private state: AnyState = State.READY;\n /**\n * The guard path to evaluate as part of a node update.\n */\n private guardPath: GuardPath | undefined;\n\n /**\n * @param type The node type.\n * @param attributes The node attributes.\n * @param args The node argument definitions.\n */\n constructor(private type: string, private attributes: Attribute[], private args: AnyArgument[]) {}\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected abstract onUpdate(agent: Agent, options: BehaviourTreeOptions): void;\n\n /**\n * Gets the name of the node.\n */\n public abstract getName(): string;\n\n /**\n * Gets whether this node is a leaf node.\n */\n public abstract isLeafNode: () => this is Leaf;\n\n /**\n * Gets/Sets the state of the node.\n */\n getState = (): AnyState => this.state;\n setState = (value: AnyState): void => {\n this.state = value;\n };\n\n /**\n * Gets the unique id of the node.\n */\n getUid = () => this.uid;\n\n /**\n * Gets the type of the node.\n */\n getType = () => this.type;\n\n /**\n * Gets the node attributes.\n */\n getAttributes = () => this.attributes;\n\n /**\n * Gets the node arguments.\n */\n getArguments = () => this.args;\n\n /**\n * Gets the node attribute with the specified type, or null if it does not exist.\n */\n getAttribute(type: \"entry\" | \"ENTRY\"): Entry;\n getAttribute(type: \"exit\" | \"EXIT\"): Exit;\n getAttribute(type: \"step\" | \"STEP\"): Step;\n getAttribute(type: string): Attribute {\n return (\n this.getAttributes().filter((decorator) => decorator.getType().toUpperCase() === type.toUpperCase())[0] ||\n null\n );\n }\n\n /**\n * Gets the node attributes.\n */\n getGuardAttributes = (): Guard[] => this.getAttributes().filter((decorator) => decorator.isGuard()) as Guard[];\n\n /**\n * Sets the guard path to evaluate as part of a node update.\n */\n setGuardPath = (value: GuardPath) => (this.guardPath = value);\n\n /**\n * Gets whether a guard path is assigned to this node.\n */\n hasGuardPath = () => !!this.guardPath;\n\n /**\n * Gets whether this node is in the specified state.\n * @param value The value to compare to the node state.\n */\n public is(value: AnyState): boolean {\n return this.state === value;\n }\n\n /**\n * Reset the state of the node.\n */\n public reset(): void {\n this.setState(State.READY);\n }\n\n /**\n * Abort the running of this node.\n * @param agent The agent.\n */\n public abort(agent: Agent): void {\n // There is nothing to do if this node is not in the running state.\n if (!this.is(State.RUNNING)) {\n return;\n }\n\n // Reset the state of this node.\n this.reset();\n\n this.getAttribute(\"exit\")?.callAgentFunction(agent, false, true);\n }\n\n /**\n * Update the node.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n * @returns The result of the update.\n */\n public update(agent: Agent, options: BehaviourTreeOptions): void {\n // If this node is already in a 'SUCCEEDED' or 'FAILED' state then there is nothing to do.\n if (this.is(State.SUCCEEDED) || this.is(State.FAILED)) {\n return;\n }\n\n try {\n // Evaluate all of the guard path conditions for the current tree path.\n this.guardPath!.evaluate(agent);\n\n // If this node is in the READY state then call the ENTRY for this node if it exists.\n if (this.is(State.READY)) {\n this.getAttribute(\"entry\")?.callAgentFunction(agent);\n }\n\n this.getAttribute(\"step\")?.callAgentFunction(agent);\n\n // Do the actual update.\n this.onUpdate(agent, options);\n\n // If this node is now in a 'SUCCEEDED' or 'FAILED' state then call the EXIT for this node if it exists.\n if (this.is(State.SUCCEEDED) || this.is(State.FAILED)) {\n this.getAttribute(\"exit\")?.callAgentFunction(agent, this.is(State.SUCCEEDED), false);\n }\n } catch (error) {\n // If the error is a GuardUnsatisfiedException then we need to determine if this node is the source.\n if (error instanceof GuardUnsatisifedException && error.isSourceNode(this)) {\n // Abort the current node.\n this.abort(agent);\n\n // Any node that is the source of an abort will be a failed node.\n this.setState(State.FAILED);\n } else {\n throw error;\n }\n }\n }\n}\n\n/**\n * Create a randomly generated node uid.\n * @returns A randomly generated node uid.\n */\nfunction createNodeUid(): string {\n var S4 = function () {\n return (((1 + Math.random()) * 0x10000) | 0).toString(16).substring(1);\n };\n return S4() + S4() + \"-\" + S4() + \"-\" + S4() + \"-\" + S4() + \"-\" + S4() + S4() + S4();\n}\n", "import Node from \"../Node\";\n\n/**\n * A leaf node.\n */\nexport default abstract class Leaf extends Node {\n /**\n * Gets whether this node is a leaf node.\n */\n isLeafNode = () => true;\n}\n", "import { ActionResult, Agent, ExitFunctionArg, FunctionArg, GlobalFunction } from \"./Agent\";\nimport { AnyArgument, RootAstNode } from \"./RootAstNodesBuilder\";\n\n// Exit callbacks receive their own special type of argument.\n// There's probably stricter ways to represent this but it feels overly complex right now.\ntype ExitResultArg = { value: ExitFunctionArg };\nexport type AnyExitArgument = AnyArgument | ExitResultArg;\n\nexport type InvokerFunction = (args: AnyExitArgument[]) => ActionResult;\n\n/**\n * A singleton used to store and lookup registered functions and subtrees.\n */\nexport default class Lookup {\n /**\n * The object holding any registered functions keyed on function name.\n */\n private static functionTable: { [key: string]: GlobalFunction } = {};\n /**\n * The object holding any registered sub-trees keyed on tree name.\n */\n private static subtreeTable: { [key: string]: RootAstNode } = {};\n\n /**\n * Gets the function with the specified name.\n * @param name The name of the function.\n * @returns The function with the specified name.\n */\n public static getFunc(name: string): GlobalFunction {\n return this.functionTable[name];\n }\n\n /**\n * Sets the function with the specified name for later lookup.\n * @param name The name of the function.\n * @param func The function.\n */\n public static setFunc(name: string, func: GlobalFunction): void {\n this.functionTable[name] = func;\n }\n\n /**\n * Gets the function invoker for the specified agent and function name.\n * If a function with the specified name exists on the agent object then it will\n * be returned, otherwise we will then check the registered functions for a match.\n * @param agent The agent instance that this behaviour tree is modelling behaviour for.\n * @param name The function name.\n * @returns The function invoker for the specified agent and function name.\n */\n static getFuncInvoker(agent: Agent, name: string): InvokerFunction | null {\n // Check whether the agent contains the specified function.\n const foundOnAgent = agent[name];\n if (foundOnAgent && typeof foundOnAgent === \"function\") {\n return (args: AnyExitArgument[]): boolean | ActionResult =>\n foundOnAgent.apply(\n agent,\n args.map((arg) => arg.value)\n );\n }\n\n // The agent does not contain the specified function but it may have been registered at some point.\n if (this.functionTable[name] && typeof this.functionTable[name] === \"function\") {\n return (args: AnyExitArgument[]) => this.functionTable[name](agent, ...args.map((arg) => arg.value));\n }\n\n // We have no function to invoke.\n return null;\n }\n\n /**\n * Gets the subtree with the specified name.\n * @param name The name of the subtree.\n * @returns The subtree with the specified name.\n */\n static getSubtree(name: string): RootAstNode {\n return this.subtreeTable[name];\n }\n\n /**\n * Sets the subtree with the specified name for later lookup.\n * @param name The name of the subtree.\n * @param subtree The subtree.\n */\n static setSubtree(name: string, subtree: RootAstNode) {\n this.subtreeTable[name] = subtree;\n }\n\n /**\n * Removes the registered function or subtree with the specified name.\n * @param name The name of the registered function or subtree.\n */\n static remove(name: string) {\n delete this.functionTable[name];\n delete this.subtreeTable[name];\n }\n\n /**\n * Remove all registered functions and subtrees.\n */\n static empty() {\n this.functionTable = {};\n this.subtreeTable = {};\n }\n}\n", "import Leaf from \"./Leaf\";\nimport State, { CompleteState } from \"../../State\";\nimport Lookup from \"../../Lookup\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { AnyArgument } from \"../../RootAstNodesBuilder\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * An Action leaf node.\n * This represents an immediate or ongoing state of behaviour.\n */\nexport default class Action extends Leaf {\n /**\n * @param attributes The node attributes.\n * @param actionName The action name.\n * @param actionArguments The array of action argument definitions.\n */\n constructor(attributes: Attribute[], private actionName: string, private actionArguments: AnyArgument[]) {\n super(\"action\", attributes, actionArguments);\n }\n\n /**\n * Whether there is a pending update promise.\n */\n private isUsingUpdatePromise = false;\n\n /**\n * The finished state result of an update promise.\n */\n private updatePromiseStateResult: CompleteState | null = null;\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // If the result of this action depends on an update promise then there is nothing to do until\n // it resolves, unless there has been a value set as a result of the update promise resolving.\n if (this.isUsingUpdatePromise) {\n // Check whether the update promise has resolved with a state value.\n if (this.updatePromiseStateResult) {\n // Set the state of this node to match the state returned by the promise.\n this.setState(this.updatePromiseStateResult);\n }\n\n return;\n }\n\n // Attempt to get the invoker for the action function.\n const actionFuncInvoker = Lookup.getFuncInvoker(agent, this.actionName);\n\n // The action function should be defined.\n if (actionFuncInvoker === null) {\n throw new Error(\n `cannot update action node as the action '${this.actionName}' function is not defined on the agent and has not been registered`\n );\n }\n\n // Call the action function, the result of which may be:\n // - The finished state of this action node.\n // - A promise to return a finished node state.\n // - Undefined if the node should remain in the running state.\n const updateResult = actionFuncInvoker(this.actionArguments) as CompleteState | Promise;\n\n if (updateResult instanceof Promise) {\n updateResult.then(\n (result) => {\n // If 'isUpdatePromisePending' is null then the promise was cleared as it was resolving, probably via an abort of reset.\n if (!this.isUsingUpdatePromise) {\n return;\n }\n\n // Check to make sure the result is a valid finished state.\n if (result !== State.SUCCEEDED && result !== State.FAILED) {\n throw new Error(\n \"action node promise resolved with an invalid value, expected a State.SUCCEEDED or State.FAILED value to be returned\"\n );\n }\n\n // Set pending update promise state result to be processed on next update.\n this.updatePromiseStateResult = result;\n },\n (reason) => {\n // If 'isUpdatePromisePending' is null then the promise was cleared as it was resolving, probably via an abort of reset.\n if (!this.isUsingUpdatePromise) {\n return;\n }\n\n // Just throw whatever was returned as the rejection argument.\n throw new Error(reason);\n }\n );\n\n // This node will be in the 'RUNNING' state until the update promise resolves.\n this.setState(State.RUNNING);\n\n // We are now waiting for the promise returned by the use to resolve before we know what state this node is in.\n this.isUsingUpdatePromise = true;\n } else {\n // Validate the returned value.\n this.validateUpdateResult(updateResult);\n\n // Set the state of this node, this may be undefined, which just means that the node is still in the 'RUNNING' state.\n this.setState(updateResult || State.RUNNING);\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => this.actionName;\n\n /**\n * Reset the state of the node.\n */\n reset = () => {\n // Reset the state of this node.\n this.setState(State.READY);\n\n // There is no longer an update promise that we care about.\n this.isUsingUpdatePromise = false;\n this.updatePromiseStateResult = null;\n };\n\n /**\n * Validate the result of an update function call.\n * @param result The result of an update function call.\n */\n private validateUpdateResult = (result: CompleteState | boolean) => {\n switch (result) {\n case State.SUCCEEDED:\n case State.FAILED:\n case undefined:\n return;\n default:\n throw new Error(\n `action '${this.actionName}' 'onUpdate' returned an invalid response, expected an optional State.SUCCEEDED or State.FAILED value to be returned`\n );\n }\n };\n}\n", "import Leaf from \"./Leaf\";\nimport State from \"../../State\";\nimport Lookup from \"../../Lookup\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { AnyArgument } from \"../../RootAstNodesBuilder\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A Condition leaf node.\n * This will succeed or fail immediately based on an agent predicate, without moving to the 'RUNNING' state.\n */\nexport default class Condition extends Leaf {\n /**\n * @param attributes The node attributes.\n * @param conditionName The name of the condition function.\n * @param conditionArguments The array of condition argument definitions.\n */\n constructor(attributes: Attribute[], private conditionName: string, private conditionArguments: AnyArgument[]) {\n super(\"condition\", attributes, conditionArguments);\n }\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // Attempt to get the invoker for the condition function.\n const conditionFuncInvoker = Lookup.getFuncInvoker(agent, this.conditionName);\n\n // The condition function should be defined.\n if (conditionFuncInvoker === null) {\n throw new Error(\n `cannot update condition node as the condition '${this.conditionName}' function is not defined on the agent and has not been registered`\n );\n }\n\n // Call the condition function to determine the state of this node.\n this.setState(!!conditionFuncInvoker(this.conditionArguments) ? State.SUCCEEDED : State.FAILED);\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => this.conditionName;\n}\n", "import Leaf from \"./Leaf\";\nimport State from \"../../State\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { Agent } from \"../../Agent\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A WAIT node.\n * The state of this node will change to SUCCEEDED after a duration of time\n */\nexport default class Wait extends Leaf {\n /**\n * @param attributes The node attributes.\n * @param duration The duration that this node will wait to succeed in milliseconds.\n * @param durationMin The minimum possible duration in milliseconds that this node will wait to succeed.\n * @param durationMax The maximum possible duration in milliseconds that this node will wait to succeed.\n */\n constructor(\n attributes: Attribute[],\n private duration: number | null,\n private durationMin: number | null,\n private durationMax: number | null\n ) {\n super(\"wait\", attributes, []);\n }\n\n /**\n * The time in milliseconds at which this node was first updated.\n */\n private initialUpdateTime: number = 0;\n\n /**\n * The total duration in milliseconds that this node will be waiting for.\n */\n private totalDuration: number | null = null;\n\n /**\n * The duration in milliseconds that this node has been waiting for.\n */\n private waitedDuration: number = 0;\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // If this node is in the READY state then we need to set the initial update time.\n if (this.is(State.READY)) {\n // Set the initial update time.\n this.initialUpdateTime = new Date().getTime();\n\n // Set the initial waited duration.\n this.waitedDuration = 0;\n\n // Are we dealing with an explicit duration or will we be randomly picking a duration between the min and max duration.\n if (this.duration !== null) {\n this.totalDuration = this.duration;\n } else if (this.durationMin !== null && this.durationMax !== null) {\n // We will be picking a random duration between a min and max duration, if the optional 'random' behaviour tree\n // function option is defined then we will be using that, otherwise we will fall back to using Math.random.\n const random = typeof options.random === \"function\" ? options.random : Math.random;\n\n // Pick a random duration between a min and max duration.\n this.totalDuration = Math.floor(\n random() * (this.durationMax - this.durationMin + 1) + this.durationMin\n );\n } else {\n this.totalDuration = null;\n }\n\n // The node is now running until we finish waiting.\n this.setState(State.RUNNING);\n }\n\n // If we have no total duration then this wait node will wait indefinitely until it is aborted.\n if (this.totalDuration === null) {\n return;\n }\n\n // If we have a 'getDeltaTime' function defined as part of our options then we will use it to figure out how long we have waited for.\n if (typeof options.getDeltaTime === \"function\") {\n // Get the delta time.\n const deltaTime = options.getDeltaTime();\n\n // Our delta time must be a valid number and cannot be NaN.\n if (typeof deltaTime !== \"number\" || isNaN(deltaTime)) {\n throw new Error(\"The delta time must be a valid number and not NaN.\");\n }\n\n // Update the amount of time that this node has been waiting for based on the delta time.\n this.waitedDuration += deltaTime * 1000;\n } else {\n // We are not using a delta time, so we will just work out hom much time has passed since the first update.\n this.waitedDuration = new Date().getTime() - this.initialUpdateTime;\n }\n\n // Have we waited long enough?\n if (this.waitedDuration >= this.totalDuration) {\n // We have finished waiting!\n this.setState(State.SUCCEEDED);\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => {\n if (this.duration !== null) {\n return `WAIT ${this.duration}ms`;\n } else if (this.durationMin !== null && this.durationMax !== null) {\n return `WAIT ${this.durationMin}ms-${this.durationMax}ms`;\n } else {\n return \"WAIT\";\n }\n };\n}\n", "import Node from \"../Node\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\n\n/**\n * A decorator node that wraps a single child node.\n */\nexport default abstract class Decorator extends Node {\n /**\n * @param type The node type.\n * @param attributes The node attributes.\n * @param child The child node.\n */\n constructor(type: string, attributes: Attribute[], protected child: Node) {\n super(type, attributes, []);\n }\n\n /**\n * Gets whether this node is a leaf node.\n */\n isLeafNode = () => false;\n\n /**\n * Gets the children of this node.\n */\n getChildren = () => [this.child];\n\n /**\n * Reset the state of the node.\n */\n reset = () => {\n // Reset the state of this node.\n this.setState(State.READY);\n\n // Reset the state of the child node.\n this.child.reset();\n };\n\n /**\n * Abort the running of this node.\n * @param agent The agent.\n */\n abort = (agent: Agent) => {\n // There is nothing to do if this node is not in the running state.\n if (!this.is(State.RUNNING)) {\n return;\n }\n\n // Abort the child node.\n this.child.abort(agent);\n\n // Reset the state of this node.\n this.reset();\n\n this.getAttribute(\"exit\")?.callAgentFunction(agent, false, true);\n };\n}\n", "import Node from \"../Node\";\nimport Decorator from \"./Decorator\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A Root node.\n * The root node will have a single child.\n */\nexport default class Root extends Decorator {\n /**\n * @param attributes The node attributes.\n * @param child The child node.\n */\n constructor(attributes: Attribute[], child: Node) {\n super(\"root\", attributes, child);\n }\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // If the child has never been updated or is running then we will need to update it now.\n if (this.child.getState() === State.READY || this.child.getState() === State.RUNNING) {\n // Update the child of this node.\n this.child.update(agent, options);\n }\n\n // The state of the root node is the state of its child.\n this.setState(this.child.getState());\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => \"ROOT\";\n}\n", "import Node from \"../Node\";\nimport Decorator from \"./Decorator\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A REPEAT node.\n * The node has a single child which can have:\n * -- A number of iterations for which to repeat the child node.\n * -- An infinite repeat loop if neither an iteration count or a condition function is defined.\n * The REPEAT node will stop and have a 'FAILED' state if its child is ever in a 'FAILED' state after an update.\n * The REPEAT node will attempt to move on to the next iteration if its child is ever in a 'SUCCEEDED' state.\n */\nexport default class Repeat extends Decorator {\n /**\n * @param attributes The node attributes.\n * @param iterations The number of iterations to repeat the child node.\n * @param iterationsMin The minimum possible number of iterations to repeat the child node.\n * @param iterationsMax The maximum possible number of iterations to repeat the child node.\n * @param child The child node.\n */\n constructor(\n attributes: Attribute[],\n private iterations: number | null,\n private iterationsMin: number | null,\n private iterationsMax: number | null,\n child: Node\n ) {\n super(\"repeat\", attributes, child);\n }\n\n /**\n * The number of target iterations to make.\n */\n private targetIterationCount: number | null = null;\n\n /**\n * The current iteration count.\n */\n private currentIterationCount: number = 0;\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // If this node is in the READY state then we need to reset the child and the target iteration count.\n if (this.is(State.READY)) {\n // Reset the child node.\n this.child.reset();\n\n // Reset the current iteration count.\n this.currentIterationCount = 0;\n\n // Set the target iteration count.\n this.setTargetIterationCount(options);\n }\n\n // Do a check to see if we can iterate. If we can then this node will move into the 'RUNNING' state.\n // If we cannot iterate then we have hit our target iteration count, which means that the node has succeeded.\n if (this.canIterate()) {\n // This node is in the running state and can do its initial iteration.\n this.setState(State.RUNNING);\n\n // We may have already completed an iteration, meaning that the child node will be in the SUCCEEDED state.\n // If this is the case then we will have to reset the child node now.\n if (this.child.getState() === State.SUCCEEDED) {\n this.child.reset();\n }\n\n // Update the child of this node.\n this.child.update(agent, options);\n\n // If the child moved into the FAILED state when we updated it then there is nothing left to do and this node has also failed.\n // If it has moved into the SUCCEEDED state then we have completed the current iteration.\n if (this.child.getState() === State.FAILED) {\n // The child has failed, meaning that this node has failed.\n this.setState(State.FAILED);\n\n return;\n } else if (this.child.getState() === State.SUCCEEDED) {\n // We have completed an iteration.\n this.currentIterationCount += 1;\n }\n } else {\n // This node is in the 'SUCCEEDED' state as we cannot iterate any more.\n this.setState(State.SUCCEEDED);\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => {\n if (this.iterations !== null) {\n return `REPEAT ${this.iterations}x`;\n } else if (this.iterationsMin !== null && this.iterationsMax !== null) {\n return `REPEAT ${this.iterationsMin}x-${this.iterationsMax}x`;\n } else {\n return \"REPEAT\";\n }\n };\n\n /**\n * Reset the state of the node.\n */\n reset = () => {\n // Reset the state of this node.\n this.setState(State.READY);\n\n // Reset the current iteration count.\n this.currentIterationCount = 0;\n\n // Reset the child node.\n this.child.reset();\n };\n\n /**\n * Gets whether an iteration can be made.\n * @returns Whether an iteration can be made.\n */\n private canIterate = () => {\n if (this.targetIterationCount !== null) {\n // We can iterate as long as we have not reached our target iteration count.\n return this.currentIterationCount < this.targetIterationCount;\n }\n\n // If neither an iteration count or a condition function were defined then we can iterate indefinitely.\n return true;\n };\n\n /**\n * Sets the target iteration count.\n * @param options The behaviour tree options object.\n */\n private setTargetIterationCount = (options: BehaviourTreeOptions) => {\n // Are we dealing with an explicit iteration count or will we be randomly picking a iteration count between the min and max iteration count.\n if (this.iterations !== null) {\n this.targetIterationCount = this.iterations;\n } else if (this.iterationsMin !== null && this.iterationsMax !== null) {\n // We will be picking a random iteration count between a min and max iteration count, if the optional 'random'\n // behaviour tree function option is defined then we will be using that, otherwise we will fall back to using Math.random.\n const random = typeof options.random === \"function\" ? options.random : Math.random;\n\n // Pick a random iteration count between a min and max iteration count.\n this.targetIterationCount = Math.floor(\n random() * (this.iterationsMax - this.iterationsMin + 1) + this.iterationsMin\n );\n } else {\n this.targetIterationCount = null;\n }\n };\n}\n", "import Node from \"../Node\";\nimport Decorator from \"./Decorator\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A RETRY node.\n * The node has a single child which can have:\n * -- A number of iterations for which to repeat the child node.\n * -- An infinite repeat loop if neither an iteration count or a condition function is defined.\n * The RETRY node will stop and have a 'SUCCEEDED' state if its child is ever in a 'SUCCEEDED' state after an update.\n * The RETRY node will attempt to move on to the next iteration if its child is ever in a 'FAILED' state.\n */\nexport default class Retry extends Decorator {\n /**\n * @param attributes The node attributes.\n * @param attempts The number of attempts to retry the child node.\n * @param attemptsMin The minimum possible number of attempts to retry the child node.\n * @param attemptsMax The maximum possible number of attempts to retry the child node.\n * @param child The child node.\n */\n constructor(\n attributes: Attribute[],\n private attempts: number | null,\n private attemptsMin: number | null,\n private attemptsMax: number | null,\n child: Node\n ) {\n super(\"retry\", attributes, child);\n }\n\n /**\n * The number of target attempts to make.\n */\n private targetAttemptCount: number | null = null;\n\n /**\n * The current attempt count.\n */\n private currentAttemptCount: number = 0;\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // If this node is in the READY state then we need to reset the child and the target attempt count.\n if (this.is(State.READY)) {\n // Reset the child node.\n this.child.reset();\n\n // Reset the current attempt count.\n this.currentAttemptCount = 0;\n\n // Set the target attempt count.\n this.setTargetAttemptCount(options);\n }\n\n // Do a check to see if we can attempt. If we can then this node will move into the 'RUNNING' state.\n // If we cannot attempt then we have hit our target attempt count, which means that the node has succeeded.\n if (this.canAttempt()) {\n // This node is in the running state and can do its initial attempt.\n this.setState(State.RUNNING);\n\n // We may have already completed an attempt, meaning that the child node will be in the FAILED state.\n // If this is the case then we will have to reset the child node now.\n if (this.child.getState() === State.FAILED) {\n this.child.reset();\n }\n\n // Update the child of this node.\n this.child.update(agent, options);\n\n // If the child moved into the SUCCEEDED state when we updated it then there is nothing left to do and this node has also succeeded.\n // If it has moved into the FAILED state then we have completed the current attempt.\n if (this.child.getState() === State.SUCCEEDED) {\n // The child has succeeded, meaning that this node has succeeded.\n this.setState(State.SUCCEEDED);\n\n return;\n } else if (this.child.getState() === State.FAILED) {\n // We have completed an attempt.\n this.currentAttemptCount += 1;\n }\n } else {\n // This node is in the 'FAILED' state as we cannot iterate any more.\n this.setState(State.FAILED);\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => {\n if (this.attempts !== null) {\n return `RETRY ${this.attempts}x`;\n } else if (this.attemptsMin !== null && this.attemptsMax !== null) {\n return `RETRY ${this.attemptsMin}x-${this.attemptsMax}x`;\n } else {\n return \"RETRY\";\n }\n };\n\n /**\n * Reset the state of the node.\n */\n reset = () => {\n // Reset the state of this node.\n this.setState(State.READY);\n\n // Reset the current attempt count.\n this.currentAttemptCount = 0;\n\n // Reset the child node.\n this.child.reset();\n };\n\n /**\n * Gets whether an attempt can be made.\n * @returns Whether an attempt can be made.\n */\n canAttempt = () => {\n if (this.targetAttemptCount !== null) {\n // We can attempt as long as we have not reached our target attempt count.\n return this.currentAttemptCount < this.targetAttemptCount;\n }\n\n // If neither an attempt count or a condition function were defined then we can attempt indefinitely.\n return true;\n };\n\n /**\n * Sets the target attempt count.\n * @param options The behaviour tree options object.\n */\n setTargetAttemptCount = (options: BehaviourTreeOptions) => {\n // Are we dealing with an explicit attempt count or will we be randomly picking an attempt count between the min and max attempt count.\n if (this.attempts !== null) {\n this.targetAttemptCount = this.attempts;\n } else if (this.attemptsMin !== null && this.attemptsMax !== null) {\n // We will be picking a random attempt count between a min and max attempt count, if the optional 'random'\n // behaviour tree function option is defined then we will be using that, otherwise we will fall back to using Math.random.\n const random = typeof options.random === \"function\" ? options.random : Math.random;\n\n // Pick a random attempt count between a min and max attempt count.\n this.targetAttemptCount = Math.floor(\n random() * (this.attemptsMax - this.attemptsMin + 1) + this.attemptsMin\n );\n } else {\n this.targetAttemptCount = null;\n }\n };\n}\n", "import Decorator from \"./Decorator\";\nimport State from \"../../State\";\nimport Node from \"../Node\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A Flip node.\n * This node wraps a single child and will flip the state of the child state.\n */\nexport default class Flip extends Decorator {\n /**\n * @param attributes The node attributes.\n * @param child The child node.\n */\n constructor(attributes: Attribute[], child: Node) {\n super(\"flip\", attributes, child);\n }\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // If the child has never been updated or is running then we will need to update it now.\n if (this.child.getState() === State.READY || this.child.getState() === State.RUNNING) {\n this.child.update(agent, options);\n }\n\n // The state of this node will depend in the state of its child.\n switch (this.child.getState()) {\n case State.RUNNING:\n this.setState(State.RUNNING);\n break;\n\n case State.SUCCEEDED:\n this.setState(State.FAILED);\n break;\n\n case State.FAILED:\n this.setState(State.SUCCEEDED);\n break;\n\n default:\n this.setState(State.READY);\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => \"FLIP\";\n}\n", "import Node from \"../Node\";\nimport Decorator from \"./Decorator\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A Succeed node.\n * This node wraps a single child and will always move to the 'SUCCEEDED' state when the child moves to a 'SUCCEEDED' or 'FAILED' state.\n */\nexport default class Succeed extends Decorator {\n /**\n * @param attributes The node attributes.\n * @param child The child node.\n */\n constructor(attributes: Attribute[], child: Node) {\n super(\"succeed\", attributes, child);\n }\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // If the child has never been updated or is running then we will need to update it now.\n if (this.child.getState() === State.READY || this.child.getState() === State.RUNNING) {\n this.child.update(agent, options);\n }\n\n // The state of this node will depend in the state of its child.\n switch (this.child.getState()) {\n case State.RUNNING:\n this.setState(State.RUNNING);\n break;\n\n case State.SUCCEEDED:\n case State.FAILED:\n this.setState(State.SUCCEEDED);\n break;\n\n default:\n this.setState(State.READY);\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => \"SUCCEED\";\n}\n", "import Node from \"../Node\";\nimport Decorator from \"./Decorator\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A Fail node.\n * This node wraps a single child and will always move to the 'FAILED' state when the child moves to a 'SUCCEEDED' or 'FAILED' state.\n */\nexport default class Fail extends Decorator {\n /**\n * @param attributes The node attributes.\n * @param child The child node.\n */\n constructor(attributes: Attribute[], child: Node) {\n super(\"fail\", attributes, child);\n }\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // If the child has never been updated or is running then we will need to update it now.\n if (this.child.getState() === State.READY || this.child.getState() === State.RUNNING) {\n this.child.update(agent, options);\n }\n\n // The state of this node will depend in the state of its child.\n switch (this.child.getState()) {\n case State.RUNNING:\n this.setState(State.RUNNING);\n break;\n\n case State.SUCCEEDED:\n case State.FAILED:\n this.setState(State.FAILED);\n break;\n\n default:\n this.setState(State.READY);\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => \"FAIL\";\n}\n", "import createLotto from \"lotto-draw\";\n\nimport Node from \"../Node\";\nimport Composite from \"./Composite\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A LOTTO node.\n * A winning child is picked on the initial update of this node, based on ticket weighting.\n * The state of this node will match the state of the winning child.\n */\nexport default class Lotto extends Composite {\n /**\n * @param attributes The node attributes.\n * @param tickets The child node tickets.\n * @param children The child nodes.\n */\n constructor(attributes: Attribute[], private tickets: number[], children: Node[]) {\n super(\"lotto\", attributes, children);\n }\n\n /**\n * The child node selected to be the active one.\n */\n private selectedChild: Node | undefined;\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // If this node is in the READY state then we need to pick a winning child node.\n if (this.is(State.READY)) {\n // Create a lotto draw with which to randomly pick a child node to become the active one.\n const lottoDraw = createLotto({\n // Hook up the optional 'random' behaviour tree function option to the one used by 'lotto-draw'.\n random: options.random,\n // Pass in each child node as a participant in the lotto draw with their respective ticket count.\n participants: this.children.map((child, index) => [child, this.tickets[index] || 1])\n });\n\n // Randomly pick a child based on ticket weighting, this will become the active child for this composite node.\n this.selectedChild = lottoDraw.draw() || undefined;\n }\n\n // If something went wrong and we don't have an active child then we should throw an error.\n if (!this.selectedChild) {\n throw new Error(\"failed to update lotto node as it has no active child\");\n }\n\n // If the selected child has never been updated or is running then we will need to update it now.\n if (this.selectedChild.getState() === State.READY || this.selectedChild.getState() === State.RUNNING) {\n this.selectedChild.update(agent, options);\n }\n\n // The state of the lotto node is the state of its selected child.\n this.setState(this.selectedChild.getState());\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => (this.tickets.length ? `LOTTO [${this.tickets.join(\",\")}]` : \"LOTTO\");\n}\n", "import Node from \"../Node\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\n\n/**\n * A composite node that wraps child nodes.\n */\nexport default abstract class Composite extends Node {\n /**\n * @param type The node type.\n * @param attributes The node attributes.\n * @param children The child nodes.\n */\n constructor(type: string, attributes: Attribute[], protected children: Node[]) {\n super(type, attributes, []);\n }\n\n /**\n * Gets whether this node is a leaf node.\n */\n isLeafNode = () => false;\n\n /**\n * Gets the children of this node.\n */\n getChildren = () => this.children;\n\n /**\n * Reset the state of the node.\n */\n reset = () => {\n // Reset the state of this node.\n this.setState(State.READY);\n\n // Reset the state of any child nodes.\n this.getChildren().forEach((child) => child.reset());\n };\n\n /**\n * Abort the running of this node.\n * @param agent The agent.\n */\n abort = (agent: Agent) => {\n // There is nothing to do if this node is not in the running state.\n if (!this.is(State.RUNNING)) {\n return;\n }\n\n // Abort any child nodes.\n this.getChildren().forEach((child) => child.abort(agent));\n\n // Reset the state of this node.\n this.reset();\n\n this.getAttribute(\"exit\")?.callAgentFunction(agent, false, true);\n };\n}\n", "import Composite from \"./Composite\";\nimport Node from \"../Node\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A SELECTOR node.\n * The child nodes are executed in sequence until one succeeds or all fail.\n */\nexport default class Selector extends Composite {\n /**\n * @param attributes The node attributes.\n * @param children The child nodes.\n */\n constructor(attributes: Attribute[], protected children: Node[]) {\n super(\"selector\", attributes, children);\n }\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // Iterate over all of the children of this node.\n for (const child of this.children) {\n // If the child has never been updated or is running then we will need to update it now.\n if (child.getState() === State.READY || child.getState() === State.RUNNING) {\n // Update the child of this node.\n child.update(agent, options);\n }\n\n // If the current child has a state of 'SUCCEEDED' then this node is also a 'SUCCEEDED' node.\n if (child.getState() === State.SUCCEEDED) {\n // This node is a 'SUCCEEDED' node.\n this.setState(State.SUCCEEDED);\n\n // There is no need to check the rest of the selector nodes.\n return;\n }\n\n // If the current child has a state of 'FAILED' then we should move on to the next child.\n if (child.getState() === State.FAILED) {\n // Find out if the current child is the last one in the selector.\n // If it is then this sequence node has also failed.\n if (this.children.indexOf(child) === this.children.length - 1) {\n // This node is a 'FAILED' node.\n this.setState(State.FAILED);\n\n // There is no need to check the rest of the selector as we have completed it.\n return;\n } else {\n // The child node failed, try the next one.\n continue;\n }\n }\n\n // The node should be in the 'RUNNING' state.\n if (child.getState() === State.RUNNING) {\n // This node is a 'RUNNING' node.\n this.setState(State.RUNNING);\n\n // There is no need to check the rest of the selector as the current child is still running.\n return;\n }\n\n // The child node was not in an expected state.\n throw new Error(\"child node was not in an expected state.\");\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => \"SELECTOR\";\n}\n", "import Composite from \"./Composite\";\nimport Node from \"../Node\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A SEQUENCE node.\n * The child nodes are executed in sequence until one fails or all succeed.\n */\nexport default class Sequence extends Composite {\n /**\n * @param attributes The node attributes.\n * @param children The child nodes.\n */\n constructor(attributes: Attribute[], protected children: Node[]) {\n super(\"sequence\", attributes, children);\n }\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // Iterate over all of the children of this node.\n for (const child of this.children) {\n // If the child has never been updated or is running then we will need to update it now.\n if (child.getState() === State.READY || child.getState() === State.RUNNING) {\n // Update the child of this node.\n child.update(agent, options);\n }\n\n // If the current child has a state of 'SUCCEEDED' then we should move on to the next child.\n if (child.getState() === State.SUCCEEDED) {\n // Find out if the current child is the last one in the sequence.\n // If it is then this sequence node has also succeeded.\n if (this.children.indexOf(child) === this.children.length - 1) {\n // This node is a 'SUCCEEDED' node.\n this.setState(State.SUCCEEDED);\n\n // There is no need to check the rest of the sequence as we have completed it.\n return;\n } else {\n // The child node succeeded, but we have not finished the sequence yet.\n continue;\n }\n }\n\n // If the current child has a state of 'FAILED' then this node is also a 'FAILED' node.\n if (child.getState() === State.FAILED) {\n // This node is a 'FAILED' node.\n this.setState(State.FAILED);\n\n // There is no need to check the rest of the sequence.\n return;\n }\n\n // The node should be in the 'RUNNING' state.\n if (child.getState() === State.RUNNING) {\n // This node is a 'RUNNING' node.\n this.setState(State.RUNNING);\n\n // There is no need to check the rest of the sequence as the current child is still running.\n return;\n }\n\n // The child node was not in an expected state.\n throw new Error(\"child node was not in an expected state.\");\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => \"SEQUENCE\";\n}\n", "import Composite from \"./Composite\";\nimport State from \"../../State\";\nimport Node from \"../Node\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A PARALLEL node.\n * The child nodes are executed concurrently until one fails or all succeed.\n */\nexport default class Parallel extends Composite {\n /**\n * @param attributes The node attributes.\n * @param children The child nodes.\n */\n constructor(attributes: Attribute[], children: Node[]) {\n super(\"parallel\", attributes, children);\n }\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // Keep a count of the number of succeeded child nodes.\n let succeededCount = 0;\n\n let hasChildFailed = false;\n\n // Iterate over all of the children of this node.\n for (const child of this.children) {\n // If the child has never been updated or is running then we will need to update it now.\n if (child.getState() === State.READY || child.getState() === State.RUNNING) {\n // Update the child of this node.\n child.update(agent, options);\n }\n\n // If the current child has a state of 'SUCCEEDED' then we should move on to the next child.\n if (child.getState() === State.SUCCEEDED) {\n // The child node has succeeded, keep track of this to determine if all children have.\n succeededCount++;\n\n // The child node succeeded, but we have not finished checking every child node yet.\n continue;\n }\n\n // If the current child has a state of 'FAILED' then this node is also a 'FAILED' node.\n if (child.getState() === State.FAILED) {\n hasChildFailed = true;\n\n // There is no need to check the rest of the children.\n break;\n }\n\n // The node should be in the 'RUNNING' state.\n if (child.getState() !== State.RUNNING) {\n // The child node was not in an expected state.\n throw new Error(\"child node was not in an expected state.\");\n }\n }\n\n if (hasChildFailed) {\n // This node is a 'FAILED' node.\n this.setState(State.FAILED);\n\n // Abort every running child.\n for (const child of this.children) {\n if (child.getState() === State.RUNNING) {\n child.abort(agent);\n }\n }\n } else {\n // If all children have succeeded then this node has also succeeded, otherwise it is still running.\n this.setState(succeededCount === this.children.length ? State.SUCCEEDED : State.RUNNING);\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => \"PARALLEL\";\n}\n", "import { AnyArgument } from \"../RootAstNodesBuilder\";\nimport Guard from \"./guards/Guard\";\n\nexport type AttributeDetails = {\n /** The attribute type. */\n type: string;\n\n /** The attribute arguments. */\n args: AnyArgument[];\n};\n\n/**\n * A base node attribute.\n */\nexport default abstract class Attribute {\n /**\n * @param type The node attribute type.\n * @param args The array of attribute argument definitions.\n */\n constructor(protected type: string, protected args: AnyArgument[]) {}\n\n /**\n * Gets the type of the attribute.\n */\n getType = () => this.type;\n\n /**\n * Gets the array of attribute argument definitions.\n */\n getArguments = () => this.args;\n\n /**\n * Gets the attribute details.\n */\n abstract getDetails(): TAttributeDetails;\n\n /**\n * Gets whether this attribute is a guard.\n */\n abstract isGuard: () => this is Guard;\n}\n", "import { Agent } from \"../../Agent\";\nimport { AnyArgument } from \"../../RootAstNodesBuilder\";\nimport Attribute, { AttributeDetails } from \"../Attribute\";\n\nexport type GuardAttributeDetails = {\n /** The name of the condition function that determines whether the guard is satisfied. */\n condition: string;\n} & AttributeDetails;\n\n/**\n * A base node guard attribute.\n */\nexport default abstract class Guard extends Attribute {\n /**\n * @param type The node attribute type.\n * @param args The array of decorator argument definitions.\n * @param condition The name of the condition function that determines whether the guard is satisfied.\n */\n constructor(type: string, args: AnyArgument[], private condition: string) {\n super(type, args);\n }\n\n /**\n * Gets the name of the condition function that determines whether the guard is satisfied.\n */\n getCondition = () => this.condition;\n\n /**\n * Gets whether this attribute is a guard.\n */\n isGuard = () => true;\n\n /**\n * Gets the attribute details.\n */\n getDetails(): GuardAttributeDetails {\n return {\n type: this.getType(),\n args: this.getArguments(),\n condition: this.getCondition()\n };\n }\n\n /**\n * Gets whether the guard is satisfied.\n * @param agent The agent.\n * @returns Whether the guard is satisfied.\n */\n abstract isSatisfied(agent: Agent): boolean;\n}\n", "import Guard from \"./Guard\";\nimport Lookup from \"../../Lookup\";\nimport { Agent } from \"../../Agent\";\nimport { AnyArgument } from \"../../RootAstNodesBuilder\";\n\n/**\n * A WHILE guard which is satisfied as long as the given condition remains true.\n */\nexport default class While extends Guard {\n /**\n * @param condition The name of the condition function that determines whether the guard is satisfied.\n * @param args The array of decorator argument definitions.\n */\n constructor(condition: string, args: AnyArgument[]) {\n super(\"while\", args, condition);\n }\n\n /**\n * Gets whether the guard is satisfied.\n * @param agent The agent.\n * @returns Whether the guard is satisfied.\n */\n isSatisfied = (agent: Agent) => {\n // Attempt to get the invoker for the condition function.\n const conditionFuncInvoker = Lookup.getFuncInvoker(agent, this.getCondition());\n\n // The condition function should be defined.\n if (conditionFuncInvoker === null) {\n throw new Error(\n `cannot evaluate node guard as the condition '${this.getCondition()}' function is not defined on the agent and has not been registered`\n );\n }\n\n // Call the condition function to determine whether this guard is satisfied.\n return !!conditionFuncInvoker(this.args);\n };\n}\n", "import Guard from \"./Guard\";\nimport Lookup from \"../../Lookup\";\nimport { Agent } from \"../../Agent\";\nimport { AnyArgument } from \"../../RootAstNodesBuilder\";\n\n/**\n * An UNTIL guard which is satisfied as long as the given condition remains false.\n */\nexport default class Until extends Guard {\n /**\n * @param condition The name of the condition function that determines whether the guard is satisfied.\n * @param args The array of decorator argument definitions.\n */\n constructor(condition: string, args: AnyArgument[]) {\n super(\"until\", args, condition);\n }\n\n /**\n * Gets whether the guard is satisfied.\n * @param agent The agent.\n * @returns Whether the guard is satisfied.\n */\n isSatisfied = (agent: Agent) => {\n // Attempt to get the invoker for the condition function.\n const conditionFuncInvoker = Lookup.getFuncInvoker(agent, this.getCondition());\n\n // The condition function should be defined.\n if (conditionFuncInvoker === null) {\n throw new Error(\n `cannot evaluate node guard as the condition '${this.getCondition()}' function is not defined on the agent and has not been registered`\n );\n }\n\n // Call the condition function to determine whether this guard is satisfied.\n return !!!conditionFuncInvoker(this.args);\n };\n}\n", "import { Agent } from \"../../Agent\";\nimport { AnyArgument } from \"../../RootAstNodesBuilder\";\nimport Attribute, { AttributeDetails } from \"../Attribute\";\n\nexport type CallbackAttributeDetails = {\n /** The name of the agent function that is called. */\n functionName: string;\n} & AttributeDetails;\n\n/**\n * A base node callback attribute.\n */\nexport default abstract class Callback extends Attribute {\n /**\n * @param type The node attribute type.\n * @param args The array of decorator argument definitions.\n * @param functionName The name of the agent function to call.\n */\n constructor(type: string, args: AnyArgument[], private functionName: string) {\n super(type, args);\n }\n\n /**\n * Gets the name of the agent function to call.\n */\n getFunctionName = () => this.functionName;\n\n /**\n * Gets whether this attribute is a guard.\n */\n isGuard = () => false;\n\n /**\n * Gets the attribute details.\n */\n getDetails(): CallbackAttributeDetails {\n return {\n type: this.getType(),\n args: this.getArguments(),\n functionName: this.getFunctionName()\n };\n }\n\n /**\n * Attempt to call the agent function that this callback refers to.\n * @param agent The agent.\n */\n abstract callAgentFunction: (agent: Agent, isSuccess: boolean, isAborted: boolean) => void;\n}\n", "import Callback from \"./Callback\";\nimport Lookup from \"../../Lookup\";\nimport { Agent } from \"../../Agent\";\nimport { AnyArgument } from \"../../RootAstNodesBuilder\";\n\n/**\n * An ENTRY callback which defines an agent function to call when the associated node is updated and moves out of running state.\n */\nexport default class Entry extends Callback {\n /**\n * @param functionName The name of the agent function to call.\n * @param args The array of callback argument definitions.\n */\n constructor(functionName: string, args: AnyArgument[]) {\n super(\"entry\", args, functionName);\n }\n\n /**\n * Attempt to call the agent function that this callback refers to.\n * @param agent The agent.\n */\n callAgentFunction = (agent: Agent) => {\n // Attempt to get the invoker for the callback function.\n const callbackFuncInvoker = Lookup.getFuncInvoker(agent, this.getFunctionName());\n\n // The callback function should be defined.\n if (callbackFuncInvoker === null) {\n throw new Error(\n `cannot call entry function '${this.getFunctionName()}' as is not defined on the agent and has not been registered`\n );\n }\n\n // Call the callback function.\n callbackFuncInvoker(this.args);\n };\n}\n", "import Callback from \"./Callback\";\nimport Lookup, { AnyExitArgument } from \"../../Lookup\";\nimport { Agent } from \"../../Agent\";\nimport { AnyArgument } from \"../../RootAstNodesBuilder\";\n\n/**\n * An EXIT callback which defines an agent function to call when the associated node is updated and moves to a finished state or is aborted.\n */\nexport default class Exit extends Callback {\n /**\n * @param functionName The name of the agent function to call.\n * @param args The array of callback argument definitions.\n */\n constructor(functionName: string, args: AnyArgument[]) {\n super(\"exit\", args, functionName);\n }\n\n /**\n * Attempt to call the agent function that this callback refers to.\n * @param agent The agent.\n * @param isSuccess Whether the decorated node was left with a success state.\n * @param isAborted Whether the decorated node was aborted.\n */\n callAgentFunction = (agent: Agent, isSuccess: boolean, isAborted: boolean) => {\n // Attempt to get the invoker for the callback function.\n const callbackFuncInvoker = Lookup.getFuncInvoker(agent, this.getFunctionName());\n\n // The callback function should be defined.\n if (callbackFuncInvoker === null) {\n throw new Error(\n `cannot call exit function '${this.getFunctionName()}' as is not defined on the agent and has not been registered`\n );\n }\n\n // Call the callback function\n callbackFuncInvoker([{ value: { succeeded: isSuccess, aborted: isAborted } }, ...this.args]);\n };\n}\n", "import Callback from \"./Callback\";\nimport Lookup from \"../../Lookup\";\nimport { Agent } from \"../../Agent\";\nimport { AnyArgument } from \"../../RootAstNodesBuilder\";\n\n/**\n * A STEP callback which defines an agent function to call when the associated node is updated.\n */\nexport default class Step extends Callback {\n /**\n * @param functionName The name of the agent function to call.\n * @param args The array of callback argument definitions.\n */\n constructor(functionName: string, args: AnyArgument[]) {\n super(\"step\", args, functionName);\n }\n\n /**\n * Attempt to call the agent function that this callback refers to.\n * @param agent The agent.\n */\n callAgentFunction = (agent: Agent) => {\n // Attempt to get the invoker for the callback function.\n const callbackFuncInvoker = Lookup.getFuncInvoker(agent, this.getFunctionName());\n\n // The callback function should be defined.\n if (callbackFuncInvoker === null) {\n throw new Error(\n `cannot call step function '${this.getFunctionName()}' as is not defined on the agent and has not been registered`\n );\n }\n\n // Call the callback function.\n callbackFuncInvoker(this.args);\n };\n}\n", "import Action from \"./nodes/leaf/Action\";\nimport Condition from \"./nodes/leaf/Condition\";\nimport Wait from \"./nodes/leaf/Wait\";\nimport Root from \"./nodes/decorator/Root\";\nimport Repeat from \"./nodes/decorator/Repeat\";\nimport Retry from \"./nodes/decorator/Retry\";\nimport Flip from \"./nodes/decorator/Flip\";\nimport Succeed from \"./nodes/decorator/Succeed\";\nimport Fail from \"./nodes/decorator/Fail\";\nimport Lotto from \"./nodes/composite/Lotto\";\nimport Selector from \"./nodes/composite/Selector\";\nimport Sequence from \"./nodes/composite/Sequence\";\nimport Parallel from \"./nodes/composite/Parallel\";\nimport Node from \"./nodes/Node\";\nimport While from \"./attributes/guards/While\";\nimport Until from \"./attributes/guards/Until\";\nimport Entry from \"./attributes/callbacks/Entry\";\nimport Exit from \"./attributes/callbacks/Exit\";\nimport Step from \"./attributes/callbacks/Step\";\nimport Callback from \"./attributes/callbacks/Callback\";\nimport Guard from \"./attributes/guards/Guard\";\nimport Attribute from \"./attributes/Attribute\";\nimport Composite from \"./nodes/composite/Composite\";\nimport Decorator from \"./nodes/decorator/Decorator\";\nimport Leaf from \"./nodes/leaf/Leaf\";\n\nexport type Argument = {\n value: T;\n type: string; // Used for validation.\n};\ntype NullArgument = Argument & {\n type: \"null\";\n};\ntype BooleanArgument = Argument & {\n type: \"boolean\";\n};\ntype NumberArgument = Argument & {\n type: \"number\";\n isInteger: boolean; // Used for validation.\n};\ntype StringPlaceholderArgument = Argument & {\n type: \"string\";\n};\ntype IdentifierArgument = Argument & {\n type: \"identifier\";\n};\nexport type AnyArgument =\n | NullArgument\n | BooleanArgument\n | NumberArgument\n | StringPlaceholderArgument\n | IdentifierArgument;\n\n/**\n * The node attribute factories.\n */\nconst AttributeFactories: {\n [key: string]: (functionName: string, attributeArguments: AnyArgument[]) => Callback | Guard;\n} = {\n WHILE: (condition: string, attributeArguments: AnyArgument[]) => new While(condition, attributeArguments),\n UNTIL: (condition: string, attributeArguments: AnyArgument[]) => new Until(condition, attributeArguments),\n ENTRY: (functionName: string, attributeArguments: AnyArgument[]) => new Entry(functionName, attributeArguments),\n EXIT: (functionName: string, attributeArguments: AnyArgument[]) => new Exit(functionName, attributeArguments),\n STEP: (functionName: string, attributeArguments: AnyArgument[]) => new Step(functionName, attributeArguments)\n};\n\ntype Validatable = {\n children?: AstNode[];\n validate: (depth: number) => void;\n};\n\ntype NodeInstanceCreator = (\n namedRootNodeProvider: (name: string) => RootAstNode,\n visitedBranches: string[]\n) => T;\n\nexport type AstNode = Validatable & {\n type: string;\n createNodeInstance: NodeInstanceCreator;\n};\n\nexport type LeafAstNode = AstNode & {\n type: \"action\" | \"condition\" | \"wait\";\n attributes: Attribute[];\n};\n\nexport type CompositeAstNode = AstNode & {\n type: \"lotto\" | \"parallel\" | \"selector\" | \"sequence\";\n attributes: Attribute[];\n children: AstNode[];\n};\n\nexport type DecoratorAstNode = AstNode & {\n type: \"fail\" | \"flip\" | \"repeat\" | \"retry\" | \"root\" | \"succeed\";\n attributes: Attribute[];\n children: AstNode[];\n};\n\nexport type BranchAstNode = AstNode & {\n type: \"branch\";\n branchName: \"\" | string;\n};\n\nexport type LottoAstNode = CompositeAstNode & {\n type: \"lotto\";\n tickets: number[];\n};\n\nexport type RootAstNode = DecoratorAstNode & {\n type: \"root\";\n name: null | string;\n};\n\nexport type RepeatAstNode = DecoratorAstNode & {\n type: \"repeat\";\n iterations: number | null;\n iterationsMin: number | null;\n iterationsMax: number | null;\n};\n\nexport type RetryAstNode = DecoratorAstNode & {\n type: \"retry\";\n attempts: number | null;\n attemptsMin: number | null;\n attemptsMax: number | null;\n};\n\nexport type ActionAstNode = LeafAstNode & {\n type: \"action\";\n actionName: string;\n actionArguments: AnyArgument[];\n};\n\nexport type ConditionAstNode = LeafAstNode & {\n type: \"condition\";\n conditionName: string;\n conditionArguments: AnyArgument[];\n};\n\nexport type WaitAstNode = LeafAstNode & {\n type: \"wait\";\n duration: number | null;\n durationMin: number | null;\n durationMax: number | null;\n};\n\nexport type AnyAstNode =\n | BranchAstNode\n | CompositeAstNode\n | LottoAstNode\n | DecoratorAstNode\n | RootAstNode\n | RepeatAstNode\n | RetryAstNode\n | LeafAstNode\n | ActionAstNode\n | ConditionAstNode\n | WaitAstNode;\n\n/**\n * The AST node factories.\n */\nconst ASTNodeFactories = {\n ROOT: (): RootAstNode => ({\n type: \"root\",\n attributes: [],\n name: null,\n children: [],\n validate(depth: number) {\n // A root node cannot be the child of another node.\n if (depth > 1) {\n throw new Error(\"a root node cannot be the child of another node\");\n }\n\n // A root node must have a single child node.\n if (this.children.length !== 1) {\n throw new Error(\"a root node must have a single child\");\n }\n },\n createNodeInstance(namedRootNodeProvider, visitedBranches) {\n return new Root(\n this.attributes,\n this.children![0].createNodeInstance(namedRootNodeProvider, visitedBranches.slice())\n );\n }\n }),\n BRANCH: (): BranchAstNode => ({\n type: \"branch\",\n branchName: \"\",\n validate() {},\n createNodeInstance(namedRootNodeProvider, visitedBranches) {\n // Try to find the root node with a matching branch name.\n const targetRootNode = namedRootNodeProvider(this.branchName);\n\n // If we have already visited this branch then we have a circular dependency.\n if (visitedBranches.indexOf(this.branchName) !== -1) {\n throw new Error(`circular dependency found in branch node references for branch '${this.branchName}'`);\n }\n\n // If we have a target root node, then the node instance we want will be the first and only child of the referenced root node.\n if (targetRootNode) {\n return targetRootNode\n .createNodeInstance(namedRootNodeProvider, visitedBranches.concat(this.branchName))\n .getChildren()[0];\n } else {\n throw new Error(`branch references root node '${this.branchName}' which has not been defined`);\n }\n }\n }),\n SELECTOR: (): CompositeAstNode => ({\n type: \"selector\",\n attributes: [],\n children: [],\n validate() {\n // A selector node must have at least a single node.\n if (this.children.length < 1) {\n throw new Error(\"a selector node must have at least a single child\");\n }\n },\n createNodeInstance(namedRootNodeProvider, visitedBranches) {\n return new Selector(\n this.attributes,\n this.children.map((child) => child.createNodeInstance(namedRootNodeProvider, visitedBranches.slice()))\n );\n }\n }),\n SEQUENCE: (): CompositeAstNode => ({\n type: \"sequence\",\n attributes: [],\n children: [],\n validate() {\n // A sequence node must have at least a single node.\n if (this.children.length < 1) {\n throw new Error(\"a sequence node must have at least a single child\");\n }\n },\n createNodeInstance(namedRootNodeProvider, visitedBranches) {\n return new Sequence(\n this.attributes,\n this.children.map((child) => child.createNodeInstance(namedRootNodeProvider, visitedBranches.slice()))\n );\n }\n }),\n PARALLEL: (): CompositeAstNode => ({\n type: \"parallel\",\n attributes: [],\n children: [],\n validate() {\n // A parallel node must have at least a single node.\n if (this.children.length < 1) {\n throw new Error(\"a parallel node must have at least a single child\");\n }\n },\n createNodeInstance(namedRootNodeProvider, visitedBranches) {\n return new Parallel(\n this.attributes,\n this.children.map((child) => child.createNodeInstance(namedRootNodeProvider, visitedBranches.slice()))\n );\n }\n }),\n LOTTO: (): LottoAstNode => ({\n type: \"lotto\",\n attributes: [],\n children: [],\n tickets: [],\n validate() {\n // A lotto node must have at least a single node.\n if (this.children!.length < 1) {\n throw new Error(\"a lotto node must have at least a single child\");\n }\n },\n createNodeInstance(namedRootNodeProvider, visitedBranches) {\n return new Lotto(\n this.attributes,\n this.tickets!,\n this.children!.map((child) => child.createNodeInstance(namedRootNodeProvider, visitedBranches.slice()))\n );\n }\n }),\n REPEAT: (): RepeatAstNode => ({\n type: \"repeat\",\n attributes: [],\n iterations: null,\n iterationsMin: null,\n iterationsMax: null,\n children: [],\n validate() {\n // A repeat node must have a single node.\n if (this.children!.length !== 1) {\n throw new Error(\"a repeat node must have a single child\");\n }\n\n if (this.iterations !== null) {\n // A repeat node must have a positive number of iterations if defined.\n if (this.iterations < 0) {\n throw new Error(\"a repeat node must have a positive number of iterations if defined\");\n }\n } else if (this.iterationsMin !== null && this.iterationsMax !== null) {\n // A repeat node must have a positive min and max iteration count if they are defined.\n if (this.iterationsMin < 0 || this.iterationsMax < 0) {\n throw new Error(\n \"a repeat node must have a positive minimum and maximum iteration count if defined\"\n );\n }\n\n // A repeat node must not have an minimum iteration count that exceeds the maximum iteration count.\n if (this.iterationsMin > this.iterationsMax) {\n throw new Error(\n \"a repeat node must not have a minimum iteration count that exceeds the maximum iteration count\"\n );\n }\n } else {\n // If we have no explicit iteration count or a minimum and maximum iteration count set then we are dealing with a repeat node that iterates indefinitely.\n }\n },\n createNodeInstance(namedRootNodeProvider, visitedBranches) {\n return new Repeat(\n this.attributes,\n this.iterations,\n this.iterationsMin,\n this.iterationsMax,\n this.children![0].createNodeInstance(namedRootNodeProvider, visitedBranches.slice())\n );\n }\n }),\n RETRY: (): RetryAstNode => ({\n type: \"retry\",\n attributes: [],\n attempts: null,\n attemptsMin: null,\n attemptsMax: null,\n children: [],\n validate() {\n // A retry node must have a single node.\n if (this.children!.length !== 1) {\n throw new Error(\"a retry node must have a single child\");\n }\n\n if (this.attempts !== null) {\n // A retry node must have a positive number of attempts if defined.\n if (this.attempts < 0) {\n throw new Error(\"a retry node must have a positive number of attempts if defined\");\n }\n } else if (this.attemptsMin !== null && this.attemptsMax !== null) {\n // A retry node must have a positive min and max attempts count if they are defined.\n if (this.attemptsMin < 0 || this.attemptsMax < 0) {\n throw new Error(\"a retry node must have a positive minimum and maximum attempt count if defined\");\n }\n\n // A retry node must not have a minimum attempt count that exceeds the maximum attempt count.\n if (this.attemptsMin > this.attemptsMax) {\n throw new Error(\n \"a retry node must not have a minimum attempt count that exceeds the maximum attempt count\"\n );\n }\n } else {\n // If we have no explicit attempt count or a minimum and maximum attempt count set then we are dealing with a retry node that attempts indefinitely.\n }\n },\n createNodeInstance(namedRootNodeProvider, visitedBranches) {\n return new Retry(\n this.attributes,\n this.attempts,\n this.attemptsMin,\n this.attemptsMax,\n this.children![0].createNodeInstance(namedRootNodeProvider, visitedBranches.slice())\n );\n }\n }),\n FLIP: (): DecoratorAstNode => ({\n type: \"flip\",\n attributes: [],\n children: [],\n validate() {\n // A flip node must have a single node.\n if (this.children!.length !== 1) {\n throw new Error(\"a flip node must have a single child\");\n }\n },\n createNodeInstance(namedRootNodeProvider, visitedBranches) {\n return new Flip(\n this.attributes,\n this.children![0].createNodeInstance(namedRootNodeProvider, visitedBranches.slice())\n );\n }\n }),\n SUCCEED: (): DecoratorAstNode => ({\n type: \"succeed\",\n attributes: [],\n children: [],\n validate() {\n // A succeed node must have a single node.\n if (this.children!.length !== 1) {\n throw new Error(\"a succeed node must have a single child\");\n }\n },\n createNodeInstance(namedRootNodeProvider, visitedBranches) {\n return new Succeed(\n this.attributes,\n this.children![0].createNodeInstance(namedRootNodeProvider, visitedBranches.slice())\n );\n }\n }),\n FAIL: (): DecoratorAstNode => ({\n type: \"fail\",\n attributes: [],\n children: [],\n validate() {\n // A fail node must have a single node.\n if (this.children!.length !== 1) {\n throw new Error(\"a fail node must have a single child\");\n }\n },\n createNodeInstance(namedRootNodeProvider, visitedBranches) {\n return new Fail(\n this.attributes,\n this.children![0].createNodeInstance(namedRootNodeProvider, visitedBranches.slice())\n );\n }\n }),\n WAIT: (): WaitAstNode => ({\n type: \"wait\",\n attributes: [],\n duration: null,\n durationMin: null,\n durationMax: null,\n validate() {\n if (this.duration !== null) {\n // If an explict duration was defined then it must be a positive number.\n if (this.duration < 0) {\n throw new Error(\"a wait node must have a positive duration\");\n }\n } else if (this.durationMin !== null && this.durationMax !== null) {\n // A wait node must have a positive min and max duration.\n if (this.durationMin < 0 || this.durationMax < 0) {\n throw new Error(\"a wait node must have a positive minimum and maximum duration\");\n }\n\n // A wait node must not have a minimum duration that exceeds the maximum duration.\n if (this.durationMin > this.durationMax) {\n throw new Error(\"a wait node must not have a minimum duration that exceeds the maximum duration\");\n }\n } else {\n // If we have no explicit duration or duration bounds set then we are dealing with a wait node that waits indefinitely.\n }\n },\n createNodeInstance() {\n return new Wait(this.attributes, this.duration, this.durationMin, this.durationMax);\n }\n }),\n ACTION: (): ActionAstNode => ({\n type: \"action\",\n attributes: [],\n actionName: \"\",\n actionArguments: [],\n validate() {},\n createNodeInstance() {\n return new Action(this.attributes, this.actionName!, this.actionArguments!);\n }\n }),\n CONDITION: (): ConditionAstNode => ({\n type: \"condition\",\n attributes: [],\n conditionName: \"\",\n conditionArguments: [],\n validate() {},\n createNodeInstance() {\n return new Condition(this.attributes, this.conditionName!, this.conditionArguments!);\n }\n })\n};\n\ntype OtherAstNodes = AstNode[];\n\n/**\n * Create an array of root AST nodes based on the given definition.\n * @param definition The definition to parse the AST nodes from.\n * @returns The base definition AST nodes.\n */\nexport default function buildRootASTNodes(definition: string): RootAstNode[] {\n // Swap out any node/attribute argument string literals with a placeholder and get a mapping of placeholders to original values as well as the processed definition.\n const { placeholders, processedDefinition } = substituteStringLiterals(definition);\n\n // Convert the processed definition (with substituted string literals) into an array of raw tokens.\n const tokens = parseTokensFromDefinition(processedDefinition);\n\n // There must be at least 3 tokens for the tree definition to be valid. 'ROOT', '{' and '}'.\n if (tokens.length < 3) {\n throw new Error(\"invalid token count\");\n }\n\n // We should have a matching number of '{' and '}' tokens. If not, then there are scopes that have not been properly closed.\n if (tokens.filter((token) => token === \"{\").length !== tokens.filter((token) => token === \"}\").length) {\n throw new Error(\"scope character mismatch\");\n }\n\n // Create a stack of node children arrays, starting with a definition scope.\n const stack: [RootAstNode[], ...OtherAstNodes[]] = [[]];\n const rootScope = stack[0];\n\n // We should keep processing the raw tokens until we run out of them.\n while (tokens.length) {\n // Grab the next token.\n const token = tokens.shift();\n\n const currentScope = stack[stack.length - 1] as OtherAstNodes;\n\n // How we create the next AST token depends on the current raw token value.\n switch (token!.toUpperCase()) {\n case \"ROOT\": {\n // Create a ROOT AST node.\n const node = ASTNodeFactories.ROOT();\n\n // Push the ROOT node into the current scope.\n rootScope.push(node);\n\n // We may have a root node name defined as an argument.\n if (tokens[0] === \"[\") {\n const rootArguments = getArguments(tokens, placeholders);\n\n // We should have only a single argument that is not an empty string for a root node, which is the root name identifier.\n if (rootArguments.length === 1 && rootArguments[0].type === \"identifier\") {\n // The root name will be the first and only node argument.\n node.name = rootArguments[0].value as string;\n } else {\n throw new Error(\"expected single root name argument\");\n }\n }\n\n // Try to pick any attributes off of the token stack.\n node.attributes = getAttributes(tokens, placeholders);\n\n popAndCheck(tokens, \"{\");\n\n // The new scope is that of the new ROOT nodes children.\n stack.push(node.children!);\n break;\n }\n\n case \"BRANCH\": {\n // Create a BRANCH AST node.\n const node = ASTNodeFactories.BRANCH();\n\n // Push the BRANCH node into the current scope.\n currentScope.push(node);\n\n // We must have arguments defined, as we require a branch name argument.\n if (tokens[0] !== \"[\") {\n throw new Error(\"expected single branch name argument\");\n }\n\n // The branch name will be defined as a node argument.\n const branchArguments = getArguments(tokens, placeholders);\n\n // We should have only a single identifer argument for a branch node, which is the branch name.\n if (branchArguments.length === 1 && branchArguments[0].type === \"identifier\") {\n // The branch name will be the first and only node argument.\n node.branchName = branchArguments[0].value as string;\n } else {\n throw new Error(\"expected single branch name argument\");\n }\n break;\n }\n\n case \"SELECTOR\": {\n // Create a SELECTOR AST node.\n const node = ASTNodeFactories.SELECTOR();\n\n // Push the SELECTOR node into the current scope.\n currentScope.push(node);\n\n // Try to pick any attributes off of the token stack.\n node.attributes = getAttributes(tokens, placeholders);\n\n popAndCheck(tokens, \"{\");\n\n // The new scope is that of the new SELECTOR nodes children.\n stack.push(node.children!);\n break;\n }\n\n case \"SEQUENCE\": {\n // Create a SEQUENCE AST node.\n const node = ASTNodeFactories.SEQUENCE();\n\n // Push the SEQUENCE node into the current scope.\n currentScope.push(node);\n\n // Try to pick any attributes off of the token stack.\n node.attributes = getAttributes(tokens, placeholders);\n\n popAndCheck(tokens, \"{\");\n\n // The new scope is that of the new SEQUENCE nodes children.\n stack.push(node.children!);\n break;\n }\n\n case \"PARALLEL\": {\n // Create a PARALLEL AST node.\n const node = ASTNodeFactories.PARALLEL();\n\n // Push the PARALLEL node into the current scope.\n currentScope.push(node);\n\n // Try to pick any attributes off of the token stack.\n node.attributes = getAttributes(tokens, placeholders);\n\n popAndCheck(tokens, \"{\");\n\n // The new scope is that of the new PARALLEL nodes children.\n stack.push(node.children!);\n break;\n }\n\n case \"LOTTO\": {\n // Create a LOTTO AST node.\n const node = ASTNodeFactories.LOTTO();\n\n // Push the LOTTO node into the current scope.\n currentScope.push(node);\n\n // If the next token is a '[' character then some ticket counts have been defined as arguments.\n if (tokens[0] === \"[\") {\n // Get the ticket count arguments, each argument must be a number.\n node.tickets = getArguments(\n tokens,\n placeholders,\n (arg) => arg.type === \"number\" && !!arg.isInteger,\n \"lotto node ticket counts must be integer values\"\n ).map((argument) => argument.value as number);\n }\n\n // Try to pick any attributes off of the token stack.\n node.attributes = getAttributes(tokens, placeholders);\n\n popAndCheck(tokens, \"{\");\n\n // The new scope is that of the new LOTTO nodes children.\n stack.push(node.children!);\n break;\n }\n\n case \"CONDITION\": {\n // Create a CONDITION AST node.\n const node = ASTNodeFactories.CONDITION();\n\n // Push the CONDITION node into the current scope.\n currentScope.push(node);\n\n // We must have arguments defined, as we require a condition function name argument.\n if (tokens[0] !== \"[\") {\n throw new Error(\"expected condition name identifier argument\");\n }\n\n // Grab the condition node arguments.\n const conditionArguments = getArguments(tokens, placeholders);\n\n // We should have at least a single identifier argument for a condition node, which is the condition function name.\n if (conditionArguments.length && conditionArguments[0].type === \"identifier\") {\n // The condition function name will be the first node argument.\n node.conditionName = conditionArguments.shift()!.value as string;\n } else {\n throw new Error(\"expected condition name identifier argument\");\n }\n\n // Only the first argument should have been an identifier, all following arguments must be string, number, boolean or null.\n conditionArguments\n .filter((arg) => arg.type === \"identifier\")\n .forEach((arg) => {\n throw new Error(\n \"invalid condition node argument value '\" +\n arg.value +\n \"', must be string, number, boolean or null\"\n );\n });\n\n // Any node arguments that follow the condition name identifier will be treated as condition function arguments.\n node.conditionArguments = conditionArguments;\n\n // Try to pick any attributes off of the token stack.\n node.attributes = getAttributes(tokens, placeholders);\n break;\n }\n\n case \"FLIP\": {\n // Create a FLIP AST node.\n const node = ASTNodeFactories.FLIP();\n\n // Push the Flip node into the current scope.\n currentScope.push(node);\n\n // Try to pick any attributes off of the token stack.\n node.attributes = getAttributes(tokens, placeholders);\n\n popAndCheck(tokens, \"{\");\n\n // The new scope is that of the new FLIP nodes children.\n stack.push(node.children!);\n break;\n }\n\n case \"SUCCEED\": {\n // Create a SUCCEED AST node.\n const node = ASTNodeFactories.SUCCEED();\n\n // Push the Succeed node into the current scope.\n currentScope.push(node);\n\n // Try to pick any attributes off of the token stack.\n node.attributes = getAttributes(tokens, placeholders);\n\n popAndCheck(tokens, \"{\");\n\n // The new scope is that of the new Succeed nodes children.\n stack.push(node.children!);\n break;\n }\n\n case \"FAIL\": {\n // Create a FAIL AST node.\n const node = ASTNodeFactories.FAIL();\n\n // Push the Fail node into the current scope.\n currentScope.push(node);\n\n // Try to pick any attributes off of the token stack.\n node.attributes = getAttributes(tokens, placeholders);\n\n popAndCheck(tokens, \"{\");\n\n // The new scope is that of the new Fail nodes children.\n stack.push(node.children!);\n break;\n }\n\n case \"WAIT\": {\n // Create a WAIT AST node.\n const node = ASTNodeFactories.WAIT();\n\n // Push the WAIT node into the current scope.\n currentScope.push(node);\n\n // The arguments of a wait node are optional. We may have:\n // - No node arguments, in which case the wait will be indefinite until it is aborted.\n // - One node argument which will be the explicit duration of the wait.\n // - Two node arguments which define the min and max duration bounds from which a random duration will be picked.\n if (tokens[0] === \"[\") {\n // Get the optional duration and longest duration of the wait.\n const nodeArguments = getArguments(\n tokens,\n placeholders,\n (arg) => arg.type === \"number\" && !!arg.isInteger,\n \"wait node durations must be integer values\"\n ).map((argument) => argument.value);\n\n // We may have:\n // - One node argument which will be the explicit duration of the wait.\n // - Two node arguments which define the min and max duration bounds from which a random duration will be picked.\n // - Too many arguments, which is not valid.\n if (nodeArguments.length === 1) {\n // An explicit duration was defined.\n node.duration = nodeArguments[0] as number;\n } else if (nodeArguments.length === 2) {\n // Min and max duration bounds were defined from which a random duration will be picked.\n node.durationMin = nodeArguments[0] as number;\n node.durationMax = nodeArguments[1] as number;\n } else if (nodeArguments.length > 2) {\n // An incorrect number of durations was defined.\n throw new Error(\"invalid number of wait node duration arguments defined\");\n }\n }\n\n // Try to pick any attributes off of the token stack.\n node.attributes = getAttributes(tokens, placeholders);\n break;\n }\n\n case \"REPEAT\": {\n // Create a REPEAT AST node.\n const node = ASTNodeFactories.REPEAT();\n\n // Push the REPEAT node into the current scope.\n currentScope.push(node);\n\n // The arguments of a repeat node are optional. We may have:\n // - No node arguments, in which case the repeat note will iterate indefinitely.\n // - One node argument which will be the explicit number of iterations to make.\n // - Two node arguments which define the min and max iteration bounds from which a random iteration count will be picked.\n if (tokens[0] === \"[\") {\n // An iteration count has been defined. Get the iteration and potential maximum iteration of the wait.\n const nodeArguments = getArguments(\n tokens,\n placeholders,\n (arg) => arg.type === \"number\" && !!arg.isInteger,\n \"repeat node iteration counts must be integer values\"\n ).map((argument) => argument.value);\n\n // We should have got one or two iteration counts.\n if (nodeArguments.length === 1) {\n // A static iteration count was defined.\n node.iterations = nodeArguments[0] as number;\n } else if (nodeArguments.length === 2) {\n // A minimum and maximum iteration count was defined.\n node.iterationsMin = nodeArguments[0] as number;\n node.iterationsMax = nodeArguments[1] as number;\n } else {\n // An incorrect number of iteration counts was defined.\n throw new Error(\"invalid number of repeat node iteration count arguments defined\");\n }\n }\n\n // Try to pick any attributes off of the token stack.\n node.attributes = getAttributes(tokens, placeholders);\n\n popAndCheck(tokens, \"{\");\n\n // The new scope is that of the new REPEAT nodes children.\n stack.push(node.children!);\n break;\n }\n\n case \"RETRY\": {\n // Create a RETRY AST node.\n const node = ASTNodeFactories.RETRY();\n\n // Push the RETRY node into the current scope.\n currentScope.push(node);\n\n // The arguments of a retry node are optional. We may have:\n // - No node arguments, in which case the retry note will attempt indefinitely.\n // - One node argument which will be the explicit number of attempts to make.\n // - Two node arguments which define the min and max attempt bounds from which a random attempt count will be picked.\n if (tokens[0] === \"[\") {\n // An attempt count has been defined. Get the attempt count and potential maximum attempt count of the wait.\n const nodeArguments = getArguments(\n tokens,\n placeholders,\n (arg) => arg.type === \"number\" && !!arg.isInteger,\n \"retry node attempt counts must be integer values\"\n ).map((argument) => argument.value);\n\n // We should have got one or two attempt counts.\n if (nodeArguments.length === 1) {\n // A static attempt count was defined.\n node.attempts = nodeArguments[0] as number;\n } else if (nodeArguments.length === 2) {\n // A minimum and maximum attempt count was defined.\n node.attemptsMin = nodeArguments[0] as number;\n node.attemptsMax = nodeArguments[1] as number;\n } else {\n // An incorrect number of attempt counts was defined.\n throw new Error(\"invalid number of retry node attempt count arguments defined\");\n }\n }\n\n // Try to pick any attributes off of the token stack.\n node.attributes = getAttributes(tokens, placeholders);\n\n popAndCheck(tokens, \"{\");\n\n // The new scope is that of the new RETRY nodes children.\n stack.push(node.children!);\n break;\n }\n\n case \"ACTION\": {\n // Create a ACTION AST node.\n const node = ASTNodeFactories.ACTION();\n\n // Push the ACTION node into the current scope.\n currentScope.push(node);\n\n // We must have arguments defined, as we require an action name argument.\n if (tokens[0] !== \"[\") {\n throw new Error(\"expected action name identifier argument\");\n }\n\n // The action name will be defined as a node argument.\n const actionArguments = getArguments(tokens, placeholders);\n\n // We should have at least one identifer argument for an action node, which is the action name.\n if (actionArguments.length && actionArguments[0].type === \"identifier\") {\n // The action name will be the first and only node argument.\n node.actionName = actionArguments.shift()!.value as string;\n } else {\n throw new Error(\"expected action name identifier argument\");\n }\n\n // Only the first argument should have been an identifier, all following arguments must be string, number, boolean or null.\n actionArguments\n .filter((arg) => arg.type === \"identifier\")\n .forEach((arg) => {\n throw new Error(\n \"invalid action node argument value '\" +\n arg.value +\n \"', must be string, number, boolean or null\"\n );\n });\n\n // Any node arguments that follow the action name identifier will be treated as action function arguments.\n node.actionArguments = actionArguments;\n\n // Try to pick any attributes off of the token stack.\n node.attributes = getAttributes(tokens, placeholders);\n break;\n }\n\n case \"}\": {\n // The '}' character closes the current scope.\n stack.pop();\n break;\n }\n\n default: {\n throw new Error(`unexpected token '${token}'`);\n }\n }\n }\n\n // A function to recursively validate each of the nodes in the AST.\n const validateASTNode = (node: Validatable, depth: number): void => {\n // Validate the node.\n node.validate(depth);\n\n // Validate each child of the node.\n (node.children || []).forEach((child) => validateASTNode(child, depth + 1));\n };\n\n // Start node validation from the definition root.\n validateASTNode(\n {\n children: stack[0] as RootAstNode[],\n validate(this: { children: RootAstNode[] }) {\n // We must have at least one node defined as the definition scope, which should be a root node.\n if (this.children.length === 0) {\n throw new Error(\"expected root node to have been defined\");\n }\n\n // Each node at the base of the definition scope MUST be a root node.\n for (const definitionLevelNode of this.children) {\n if (definitionLevelNode.type !== \"root\") {\n throw new Error(\"expected root node at base of definition\");\n }\n }\n\n // Exactly one root node must not have a name defined. This will be the main root, others will have to be referenced via branch nodes.\n if (this.children.filter((definitionLevelNode) => definitionLevelNode.name === null).length !== 1) {\n throw new Error(\"expected single unnamed root node at base of definition to act as main root\");\n }\n\n // No two named root nodes can have matching names.\n const rootNodeNames: string[] = [];\n for (const definitionLevelNode of this.children) {\n if (rootNodeNames.indexOf(definitionLevelNode.name!) !== -1) {\n throw new Error(`multiple root nodes found with duplicate name '${definitionLevelNode.name}'`);\n } else {\n rootNodeNames.push(definitionLevelNode.name!);\n }\n }\n }\n },\n 0\n );\n\n // Return the root AST nodes.\n return stack[0];\n}\n\n/**\n * Pop the next raw token off of the stack and throw an error if it wasn't the expected one.\n * @param tokens The array of remaining tokens.\n * @param expected An optional string or array or items, one of which must match the next popped token.\n * @returns The popped token.\n */\nfunction popAndCheck(tokens: string[], expected: string | string[]) {\n // Get and remove the next token.\n const popped = tokens.shift();\n\n // We were expecting another token.\n if (popped === undefined) {\n throw new Error(\"unexpected end of definition\");\n }\n\n // Do we have an expected token/tokens array?\n if (expected !== undefined) {\n // Check whether the popped token matches at least one of our expected items.\n var tokenMatchesExpectation = ([] as string[])\n .concat(expected)\n .some((item) => popped.toUpperCase() === item.toUpperCase());\n\n // Throw an error if the popped token didn't match any of our expected items.\n if (!tokenMatchesExpectation) {\n const expectationString = ([] as string[])\n .concat(expected)\n .map((item) => \"'\" + item + \"'\")\n .join(\" or \");\n\n throw new Error(`unexpected token found. Expected '${expectationString}' but got '${popped}'`);\n }\n }\n\n // Return the popped token.\n return popped;\n}\n\ntype Placeholders = { [key: string]: string };\n\n/**\n * Pull an argument definition list off of the token stack.\n * @param tokens The array of remaining tokens.\n * @param stringArgumentPlaceholders The mapping of string literal node argument placeholders to original values.\n * @param argumentValidator The argument validator function.\n * @param validationFailedMessage The exception message to throw if argument validation fails.\n * @returns The argument definition list.\n */\nfunction getArguments(\n tokens: string[],\n stringArgumentPlaceholders: Placeholders,\n argumentValidator?: (arg: AnyArgument) => boolean,\n validationFailedMessage?: string\n) {\n // Any lists of arguments will always be wrapped in '[]' for node arguments or '()' for attribute arguments.\n // We are looking for a '[' or '(' opener that wraps the argument tokens and the relevant closer.\n const closer = popAndCheck(tokens, [\"[\", \"(\"]) === \"[\" ? \"]\" : \")\";\n\n const argumentListTokens: string[] = [];\n const argumentList: AnyArgument[] = [];\n\n // Grab all tokens between the '[' and ']' or '(' and ')'.\n while (tokens.length && tokens[0] !== closer) {\n // The next token is part of our arguments list.\n argumentListTokens.push(tokens.shift()!);\n }\n\n // Validate the order of the argument tokens. Each token must either be a ',' or a single argument that satisfies the validator.\n argumentListTokens.forEach((token, index) => {\n // Get whether this token should be an actual argument.\n const shouldBeArgumentToken = !(index & 1);\n\n // If the current token should be an actual argument then validate it,otherwise it should be a ',' token.\n if (shouldBeArgumentToken) {\n // Get the argument definition.\n const argumentDefinition = getArgumentDefinition(token!, stringArgumentPlaceholders);\n\n // Try to validate the argument.\n if (argumentValidator && !argumentValidator(argumentDefinition)) {\n throw new Error(validationFailedMessage);\n }\n\n // This is a valid argument!\n argumentList.push(argumentDefinition);\n } else {\n // The current token should be a ',' token.\n if (token !== \",\") {\n throw new Error(`invalid argument list, expected ',' or ']' but got '${token}'`);\n }\n }\n });\n\n // The arguments list should terminate with a ']' or ')' token, depending on the opener.\n popAndCheck(tokens, closer);\n\n // Return the argument list.\n return argumentList;\n}\n\n/**\n * Gets an argument value definition.\n * @param token The argument token.\n * @param stringArgumentPlaceholders The mapping of string literal node argument placeholders to original values.\n * @returns An argument value definition.\n */\nfunction getArgumentDefinition(token: string, stringArgumentPlaceholders: Placeholders): AnyArgument {\n // Check whether the token represents a null value.\n if (token === \"null\") {\n return {\n value: null,\n type: \"null\"\n } as NullArgument;\n }\n\n // Check whether the token represents a boolean value.\n if (token === \"true\" || token === \"false\") {\n return {\n value: token === \"true\",\n type: \"boolean\"\n } as BooleanArgument;\n }\n\n // Check whether the token represents a number value.\n // TODO: Relies on broken isNaN - see MDN.\n // if (!Number.isNaN(token)) {\n if (!isNaN(token as any)) {\n return {\n value: parseFloat(token),\n isInteger: parseFloat(token) === parseInt(token, 10),\n type: \"number\"\n } as NumberArgument;\n }\n\n // Check whether the token is a placeholder (e.g. @@0@@) representing a string literal.\n if (token.match(/^@@\\d+@@$/g)) {\n return {\n value: stringArgumentPlaceholders[token].replace('\\\\\"', '\"'),\n type: \"string\"\n } as StringPlaceholderArgument;\n }\n\n // The only remaining option is that the argument value is an identifier.\n return {\n value: token,\n type: \"identifier\"\n } as IdentifierArgument;\n}\n\n/**\n * Pull any attributes off of the token stack.\n * @param tokens The array of remaining tokens.\n * @param stringArgumentPlaceholders The mapping of string literal node argument placeholders to original values.\n * @returns An array of attributes defined by any directly following tokens.\n */\nfunction getAttributes(tokens: string[], stringArgumentPlaceholders: Placeholders) {\n // Create an array to hold any attributes found.\n const attributes: Attribute[] = [];\n\n // Keep track of names of attribute that we have found on the token stack, as we cannot have duplicates.\n const attributesFound: string[] = [];\n\n // Try to get the attribute factory for the next token.\n let attributeFactory = AttributeFactories[(tokens[0] || \"\").toUpperCase()];\n\n // Pull attribute tokens off of the tokens stack until we have no more.\n while (attributeFactory) {\n // Check to make sure that we have not already created a attribute of this type for this node.\n if (attributesFound.indexOf(tokens[0].toUpperCase()) !== -1) {\n throw new Error(`duplicate attribute '${tokens[0].toUpperCase()}' found for node`);\n }\n\n // Add the current attribute type to our array of found attributes.\n attributesFound.push(tokens.shift()!.toUpperCase());\n\n // Grab any attribute arguments.\n const attributeArguments = getArguments(tokens, stringArgumentPlaceholders);\n\n // The first attribute argument has to be an identifer, this will reference an agent function.\n if (attributeArguments.length === 0 || attributeArguments[0].type !== \"identifier\") {\n throw new Error(\"expected agent function name identifier argument for attribute\");\n }\n\n // Grab the first attribute which is an identifier that will reference an agent function.\n const attributeFunctionName = attributeArguments.shift()! as IdentifierArgument;\n\n // Any remaining attribute arguments must have a type of string, number, boolean or null.\n attributeArguments\n .filter((arg) => arg.type === \"identifier\")\n .forEach((arg) => {\n throw new Error(\n \"invalid attribute argument value '\" + arg.value + \"', must be string, number, boolean or null\"\n );\n });\n\n // Create the attribute and add it to the array of attributes found.\n attributes.push(attributeFactory(attributeFunctionName.value, attributeArguments));\n\n // Try to get the next attribute name token, as there could be multiple.\n attributeFactory = AttributeFactories[(tokens[0] || \"\").toUpperCase()];\n }\n\n return attributes;\n}\n\n/**\n * Swaps out any node/attribute argument string literals with placeholders.\n * @param definition The definition.\n * @returns An object containing a mapping of placeholders to original string values as well as the processed definition string.\n */\nfunction substituteStringLiterals(definition: string): {\n placeholders: { [key: string]: string };\n processedDefinition: string;\n} {\n // Create an object to hold the mapping of placeholders to original string values.\n const placeholders: Placeholders = {};\n\n // Replace any string literals wrapped with double quotes in our definition with placeholders to be processed later.\n const processedDefinition = definition.replace(/\\\"(\\\\.|[^\"\\\\])*\\\"/g, (match) => {\n var strippedMatch = match.substring(1, match.length - 1);\n var placeholder = Object.keys(placeholders).find((key) => placeholders[key] === strippedMatch);\n\n // If we have no existing string literal match then create a new placeholder.\n if (!placeholder) {\n placeholder = `@@${Object.keys(placeholders).length}@@`;\n placeholders[placeholder] = strippedMatch;\n }\n\n return placeholder;\n });\n\n return { placeholders, processedDefinition };\n}\n\n/**\n * Parse the tree definition into an array of raw tokens.\n * @param definition The definition.\n * @returns An array of tokens parsed from the definition.\n */\nfunction parseTokensFromDefinition(definition: string): string[] {\n // Add some space around various important characters so that they can be plucked out easier as individual tokens.\n definition = definition.replace(/\\(/g, \" ( \");\n definition = definition.replace(/\\)/g, \" ) \");\n definition = definition.replace(/\\{/g, \" { \");\n definition = definition.replace(/\\}/g, \" } \");\n definition = definition.replace(/\\]/g, \" ] \");\n definition = definition.replace(/\\[/g, \" [ \");\n definition = definition.replace(/\\,/g, \" , \");\n\n // Split the definition into raw token form and return it.\n return definition.replace(/\\s+/g, \" \").trim().split(\" \");\n}\n", "import GuardPath, { GuardPathPart } from \"./attributes/guards/GuardPath\";\nimport buildRootASTNodes, { AnyArgument, RootAstNode } from \"./RootAstNodesBuilder\";\nimport State, { AnyState } from \"./State\";\nimport Lookup from \"./Lookup\";\nimport Node from \"./nodes/Node\";\nimport Root from \"./nodes/decorator/Root\";\nimport Composite from \"./nodes/composite/Composite\";\nimport Decorator from \"./nodes/decorator/Decorator\";\nimport { Agent, GlobalFunction } from \"./Agent\";\nimport { CallbackAttributeDetails } from \"./attributes/callbacks/Callback\";\nimport { GuardAttributeDetails } from \"./attributes/guards/Guard\";\nimport { BehaviourTreeOptions } from \"./BehaviourTreeOptions\";\nimport { parseToJSON } from \"./dsl/DSLDefinitionParser\";\n\n// Purely for outside inspection of the tree.\nexport type FlattenedTreeNode = {\n id: string;\n type: string;\n caption: string;\n state: AnyState;\n guards: GuardAttributeDetails[];\n callbacks: CallbackAttributeDetails[];\n args: AnyArgument[];\n parentId: string | null;\n};\n\n/**\n * A representation of a behaviour tree.\n */\nexport class BehaviourTree {\n /**\n * The main root tree node.\n */\n public readonly rootNode: Root;\n\n /**\n * Creates a new instance of the BehaviourTree class.\n * @param definition The behaviour tree definition.\n * @param agent The agent instance that this behaviour tree is modelling behaviour for.\n * @param options The behaviour tree options object.\n */\n constructor(definition: string, private agent: Agent, private options: BehaviourTreeOptions = {}) {\n // The tree definition must be defined and a valid string.\n if (typeof definition !== \"string\") {\n throw new Error(\"the tree definition must be a string\");\n }\n\n // The agent must be defined and not null.\n if (typeof agent !== \"object\" || agent === null) {\n throw new Error(\"the agent must be defined and not null\");\n }\n\n // Parse the behaviour tree definition, create the populated tree of behaviour tree nodes, and get the root.\n this.rootNode = BehaviourTree._createRootNode(definition);\n }\n\n /**\n * Gets whether the tree is in the RUNNING state.\n * @returns true if the tree is in the RUNNING state, otherwise false.\n */\n isRunning() {\n return this.rootNode.getState() === State.RUNNING;\n }\n\n /**\n * Gets the current tree state of SUCCEEDED, FAILED, READY or RUNNING.\n * @returns The current tree state.\n */\n getState() {\n return this.rootNode.getState();\n }\n\n /**\n * Step the tree.\n * 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.\n * 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\n * 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.\n *\n * 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.\n */\n step() {\n // If the root node has already been stepped to completion then we need to reset it.\n if (this.rootNode.getState() === State.SUCCEEDED || this.rootNode.getState() === State.FAILED) {\n this.rootNode.reset();\n }\n\n try {\n this.rootNode.update(this.agent, this.options);\n } catch (exception) {\n throw new Error(`error stepping tree: ${(exception as Error).message}`);\n }\n }\n\n /**\n * Resets the tree from the root node outwards to each nested node, giving each a state of READY.\n */\n reset() {\n this.rootNode.reset();\n }\n\n /**\n * Gets the flattened details of every node in the tree.\n * @returns The flattened details of every node in the tree.\n */\n getFlattenedNodeDetails(): FlattenedTreeNode[] {\n // Create an empty flattened array of tree nodes.\n const flattenedTreeNodes: FlattenedTreeNode[] = [];\n\n /**\n * Helper function to process a node instance and push details into the flattened tree nodes array.\n * @param node The current node.\n * @param parentUid The UID of the node parent, or null if the node is the main root node.\n */\n const processNode = (node: Node, parentUid: string | null) => {\n // Get the guard and callback attribute details for this node.\n const guards = node\n .getAttributes()\n .filter((attribute) => attribute.isGuard())\n .map((attribute) => attribute.getDetails()) as GuardAttributeDetails[];\n const callbacks = node\n .getAttributes()\n .filter((attribute) => !attribute.isGuard())\n .map((attribute) => attribute.getDetails()) as CallbackAttributeDetails[];\n\n // Push the current node into the flattened nodes array.\n flattenedTreeNodes.push({\n id: node.getUid(),\n type: node.getType(),\n caption: node.getName(),\n state: node.getState(),\n guards,\n callbacks,\n args: node.getArguments(),\n parentId: parentUid\n });\n\n // Process each of the nodes children if it is not a leaf node.\n if (!node.isLeafNode()) {\n (node as Composite | Decorator)\n .getChildren()\n .forEach((child) => processNode(child, (node as Composite | Decorator).getUid()));\n }\n };\n\n // Convert the nested node structure into a flattened array of node details.\n processNode(this.rootNode, null);\n\n return flattenedTreeNodes;\n }\n\n /**\n * Registers the action/condition/guard/callback function or subtree with the given name.\n * @param name The name of the function or subtree to register.\n * @param value The function or subtree definition to register.\n */\n static register(name: string, value: GlobalFunction | string) {\n if (typeof value === \"function\") {\n // We are going to register a action/condition/guard/callback function.\n Lookup.setFunc(name, value);\n } else if (typeof value === \"string\") {\n // We are going to register a subtree.\n let rootASTNodes: RootAstNode[];\n\n try {\n // Try to create the behaviour tree AST based on the definition provided, this could fail if the definition is invalid.\n rootASTNodes = buildRootASTNodes(value);\n } catch (exception) {\n // There was an issue in trying to parse and build the tree definition.\n throw new Error(`error registering definition: ${(exception as Error).message}`);\n }\n\n // This function should only ever be called with a definition containing a single unnamed root node.\n if (rootASTNodes.length != 1 || rootASTNodes[0].name !== null) {\n throw new Error(\"error registering definition: expected a single unnamed root node\");\n }\n\n Lookup.setSubtree(name, rootASTNodes[0]);\n } else {\n throw new Error(\"unexpected value, expected string definition or function\");\n }\n }\n\n /**\n * Unregisters the registered action/condition/guard/callback function or subtree with the given name.\n * @param name The name of the registered action/condition/guard/callback function or subtree to unregister.\n */\n static unregister(name: string): void {\n Lookup.remove(name);\n }\n\n /**\n * Unregister all registered action/condition/guard/callback functions and subtrees.\n */\n static unregisterAll(): void {\n Lookup.empty();\n }\n\n /**\n * Parses a behaviour tree definition and creates a tree of behaviour tree nodes.\n * @param {string} definition The behaviour tree definition.\n * @returns The root behaviour tree node.\n */\n private static _createRootNode(definition: string): Root {\n // TODO Remove!\n try {\n //parseToJSON(definition);\n } catch (exception) {\n console.log(exception);\n }\n\n try {\n // Try to create the behaviour tree AST based on the definition provided, this could fail if the definition is invalid.\n const rootASTNodes = buildRootASTNodes(definition);\n\n // Create a symbol to use as the main root key in our root node mapping.\n const mainRootNodeKey = Symbol(\"__root__\");\n\n // Create a mapping of root node names to root AST tokens. The main root node will have a key of Symbol(\"__root__\").\n const rootNodeMap: { [key: string | symbol]: RootAstNode } = {};\n for (const rootASTNode of rootASTNodes) {\n rootNodeMap[rootASTNode.name === null ? mainRootNodeKey : rootASTNode.name!] = rootASTNode;\n }\n\n // Convert the AST to our actual tree and get the root node.\n const rootNode: Root = rootNodeMap[mainRootNodeKey].createNodeInstance(\n // Create a provider for named root nodes that are part of our definition or have been registered. Prioritising the former.\n (name: string): RootAstNode => (rootNodeMap[name] ? rootNodeMap[name] : Lookup.getSubtree(name)),\n []\n );\n\n // Set a guard path on every leaf of the tree to evaluate as part of its update.\n BehaviourTree._applyLeafNodeGuardPaths(rootNode);\n\n // Return the root node.\n return rootNode;\n } catch (exception) {\n // There was an issue in trying to parse and build the tree definition.\n throw new Error(`error parsing tree: ${(exception as Error).message}`);\n }\n }\n\n /**\n * Applies a guard path to every leaf of the tree to evaluate as part of each update.\n * @param rootNode The main root tree node.\n */\n private static _applyLeafNodeGuardPaths(rootNode: Root) {\n const nodePaths: Node[][] = [];\n\n const findLeafNodes = (path: Node[], node: Node) => {\n // Add the current node to the path.\n path = path.concat(node);\n\n // Check whether the current node is a leaf node.\n if (node.isLeafNode()) {\n nodePaths.push(path);\n } else {\n (node as Composite | Decorator).getChildren().forEach((child) => findLeafNodes(path, child));\n }\n };\n\n // Find all leaf node paths, starting from the root.\n findLeafNodes([], rootNode);\n\n nodePaths.forEach((path) => {\n // Each node in the current path will have to be assigned a guard path, working from the root outwards.\n for (let depth = 0; depth < path.length; depth++) {\n // Get the node in the path at the current depth.\n const currentNode = path[depth];\n\n // The node may already have been assigned a guard path, if so just skip it.\n if (currentNode.hasGuardPath()) {\n continue;\n }\n\n // Create the guard path for the current node.\n const guardPath = new GuardPath(\n path\n .slice(0, depth + 1)\n .map((node) => ({ node, guards: node.getGuardAttributes() }))\n .filter((details) => details.guards.length > 0)\n );\n\n // Assign the guard path to the current node.\n currentNode.setGuardPath(guardPath);\n }\n });\n }\n}\n"], + "mappings": "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", + "names": ["Participant", "Lotto", "createLotto", "State", "createLotto"] +} diff --git a/dist/dsl/DSLDefinitionParser.d.ts b/dist/dsl/DSLDefinitionParser.d.ts new file mode 100644 index 0000000..023bdfe --- /dev/null +++ b/dist/dsl/DSLDefinitionParser.d.ts @@ -0,0 +1,163 @@ +/** + * A type defining the arguments that can be passed to an agent function. + */ +export type AgentFunctionArguments = (string | number | boolean | null | undefined)[]; +/** + * A guard attribute for a node. + */ +export type GuardAttributeDefinition = { + call: string; + args?: AgentFunctionArguments; +}; +/** + * A callback attribute for a node. + */ +export type CallbackAttributeDefinition = { + call: string; + args?: AgentFunctionArguments; +}; +/** + * A type defining a general node definition. + */ +export type NodeDefinition = { + type: string; + while?: GuardAttributeDefinition; + until?: GuardAttributeDefinition; + entry?: CallbackAttributeDefinition; + exit?: CallbackAttributeDefinition; + step?: CallbackAttributeDefinition; +}; +/** + * A composite node that can contain any number of child nodes. + */ +export type CompositeDefinition = NodeDefinition & { + children: AnyChildNode[]; +}; +/** + * A decorator node, a composite with only a single child node. + */ +export type DecoratorDefinition = NodeDefinition & { + child: AnyChildNode; +}; +/** + * A branch node. + */ +export type BranchDefinition = NodeDefinition & { + type: "branch"; + ref: string; +}; +/** + * An action node. + */ +export type ActionDefinition = NodeDefinition & { + type: "action"; + call: string; + args?: AgentFunctionArguments; +}; +/** + * A condition node. + */ +export type ConditionDefinition = NodeDefinition & { + type: "condition"; + call: string; + args?: AgentFunctionArguments; +}; +/** + * A wait node. + */ +export type WaitDefinition = NodeDefinition & { + type: "wait"; + duration: number | [number, number]; +}; +/** + * A sequence node. + */ +export type SequenceDefinition = CompositeDefinition & { + type: "sequence"; +}; +/** + * A selector node. + */ +export type SelectorDefinition = CompositeDefinition & { + type: "selector"; +}; +/** + * A lotto node. + */ +export type LottoDefinition = CompositeDefinition & { + type: "lotto"; + weights?: number[]; +}; +/** + * A parallel node. + */ +export type ParallelDefinition = CompositeDefinition & { + type: "parallel"; +}; +/** + * A root node. + */ +export type RootDefinition = DecoratorDefinition & { + type: "root"; + id?: string; +}; +/** + * A repeat node. + */ +export type RepeatDefinition = DecoratorDefinition & { + type: "repeat"; + iterations?: number | [number, number]; +}; +/** + * A retry node. + */ +export type RetryDefinition = DecoratorDefinition & { + type: "retry"; + attempts?: number | [number, number]; +}; +/** + * A flip node. + */ +export type FlipDefinition = DecoratorDefinition & { + type: "flip"; +}; +/** + * A succeed node. + */ +export type SucceedDefinition = DecoratorDefinition & { + type: "succeed"; +}; +/** + * A fail node. + */ +export type FailDefinition = DecoratorDefinition & { + type: "fail"; +}; +/** + * A type defining any node type. + */ +export type AnyNode = BranchDefinition | ActionDefinition | ConditionDefinition | WaitDefinition | SequenceDefinition | SelectorDefinition | LottoDefinition | ParallelDefinition | RootDefinition | RepeatDefinition | RetryDefinition | FlipDefinition | SucceedDefinition | FailDefinition; +/** + * A type defining any node type that can be a child of composite parent node. + */ +export type AnyChildNode = Exclude; +/** + * A type defining an object that holds a reference to substitued string literals parsed from the definition. + */ +type StringLiteralPlaceholders = { + [key: string]: string; +}; +/** + * Parse the tree definition string into a JSON definition. + * @param definition The tree definition string. + * @returns The root node JSON definitions. + */ +export declare function parseToJSON(definition: string): RootDefinition[]; +/** + * Converts the specified tree definition tokens into a JSON definition. + * @param tokens The tree definition tokens. + * @param placeholders The substituted string literal placeholders. + * @returns The root node JSON definitions. + */ +export declare function convertTokensToJSONDefinition(tokens: string[], placeholders: StringLiteralPlaceholders, processedDefinition: string): RootDefinition[]; +export {}; diff --git a/dist/dsl/DSLNodeArgumentParser.d.ts b/dist/dsl/DSLNodeArgumentParser.d.ts new file mode 100644 index 0000000..d9a29b1 --- /dev/null +++ b/dist/dsl/DSLNodeArgumentParser.d.ts @@ -0,0 +1,36 @@ +type Placeholders = { + [key: string]: string; +}; +export type Argument = { + /** The argument value. */ + value: T; + /** The argument type, used for validation. */ + type: string; +}; +type NullArgument = Argument & { + type: "null"; +}; +type BooleanArgument = Argument & { + type: "boolean"; +}; +type NumberArgument = Argument & { + type: "number"; + isInteger: boolean; +}; +type StringPlaceholderArgument = Argument & { + type: "string"; +}; +type IdentifierArgument = Argument & { + type: "identifier"; +}; +export type AnyArgument = NullArgument | BooleanArgument | NumberArgument | StringPlaceholderArgument | IdentifierArgument; +/** + * Parse an array of argument definitions from the specified tokens array. + * @param tokens The array tokens to parse the argument definitions from. + * @param stringArgumentPlaceholders The mapping of string literal node argument placeholders to original values. + * @param argumentValidator The argument validator function. + * @param validationFailedMessage The exception message to throw if argument validation fails. + * @returns An array of argument definitions parsed from the specified tokens array. + */ +export declare function getArguments(tokens: string[], stringArgumentPlaceholders: Placeholders, argumentValidator?: (arg: AnyArgument) => boolean, validationFailedMessage?: string): AnyArgument[]; +export {}; diff --git a/dist/dsl/DSLUtilities.d.ts b/dist/dsl/DSLUtilities.d.ts new file mode 100644 index 0000000..cdd7220 --- /dev/null +++ b/dist/dsl/DSLUtilities.d.ts @@ -0,0 +1,7 @@ +/** + * Pop the next raw token from the specified array of tokens and throw an error if it wasn't the expected one. + * @param tokens The array of tokens. + * @param expected An optional string or array or items, one of which must match the next popped token. + * @returns The popped token. + */ +export declare function popAndCheck(tokens: string[], expected?: string | string[]): string; diff --git a/dist/index.d.ts b/dist/index.d.ts new file mode 100644 index 0000000..6adc674 --- /dev/null +++ b/dist/index.d.ts @@ -0,0 +1,4 @@ +import { BehaviourTree, FlattenedTreeNode } from "./BehaviourTree"; +import State from "./State"; +export { BehaviourTree, State }; +export type { FlattenedTreeNode }; diff --git a/dist/index.js b/dist/index.js new file mode 100644 index 0000000..4b59440 --- /dev/null +++ b/dist/index.js @@ -0,0 +1,1863 @@ +"use strict"; +var __create = Object.create; +var __defProp = Object.defineProperty; +var __getOwnPropDesc = Object.getOwnPropertyDescriptor; +var __getOwnPropNames = Object.getOwnPropertyNames; +var __getProtoOf = Object.getPrototypeOf; +var __hasOwnProp = Object.prototype.hasOwnProperty; +var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value; +var __commonJS = (cb, mod) => function __require() { + return mod || (0, cb[__getOwnPropNames(cb)[0]])((mod = { exports: {} }).exports, mod), mod.exports; +}; +var __export = (target, all) => { + for (var name in all) + __defProp(target, name, { get: all[name], enumerable: true }); +}; +var __copyProps = (to, from, except, desc) => { + if (from && typeof from === "object" || typeof from === "function") { + for (let key of __getOwnPropNames(from)) + if (!__hasOwnProp.call(to, key) && key !== except) + __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable }); + } + return to; +}; +var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps( + isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target, + mod +)); +var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod); +var __publicField = (obj, key, value) => { + __defNormalProp(obj, typeof key !== "symbol" ? key + "" : key, value); + return value; +}; + +// node_modules/lotto-draw/dist/Participant.js +var require_Participant = __commonJS({ + "node_modules/lotto-draw/dist/Participant.js"(exports) { + "use strict"; + Object.defineProperty(exports, "__esModule", { value: true }); + exports.Participant = void 0; + var Participant = function() { + function Participant2(participant, tickets) { + if (tickets === void 0) { + tickets = 1; + } + this._participant = participant; + this._tickets = tickets; + } + Object.defineProperty(Participant2.prototype, "participant", { + get: function() { + return this._participant; + }, + enumerable: false, + configurable: true + }); + Object.defineProperty(Participant2.prototype, "tickets", { + get: function() { + return this._tickets; + }, + set: function(value) { + this._tickets = value; + }, + enumerable: false, + configurable: true + }); + return Participant2; + }(); + exports.Participant = Participant; + } +}); + +// node_modules/lotto-draw/dist/Utilities.js +var require_Utilities = __commonJS({ + "node_modules/lotto-draw/dist/Utilities.js"(exports) { + "use strict"; + Object.defineProperty(exports, "__esModule", { value: true }); + exports.isNaturalNumber = exports.isNullOrUndefined = void 0; + function isNullOrUndefined(value) { + return value === null || value === void 0; + } + exports.isNullOrUndefined = isNullOrUndefined; + function isNaturalNumber(value) { + return typeof value === "number" && value >= 1 && Math.floor(value) === value; + } + exports.isNaturalNumber = isNaturalNumber; + } +}); + +// node_modules/lotto-draw/dist/Lotto.js +var require_Lotto = __commonJS({ + "node_modules/lotto-draw/dist/Lotto.js"(exports) { + "use strict"; + Object.defineProperty(exports, "__esModule", { value: true }); + exports.Lotto = void 0; + var Participant_1 = require_Participant(); + var Utilities_1 = require_Utilities(); + var Lotto2 = function() { + function Lotto3(customRandom) { + this._participants = []; + this._customRandom = customRandom; + } + Lotto3.prototype.add = function(participant, tickets) { + if (tickets === void 0) { + tickets = 1; + } + if (!(0, Utilities_1.isNaturalNumber)(tickets)) { + throw new Error("tickets value must be a natural number"); + } + var existingParticipant = this._participants.find(function(part) { + return part.participant === participant; + }); + if (existingParticipant) { + existingParticipant.tickets += tickets; + } else { + this._participants.push(new Participant_1.Participant(participant, tickets)); + } + return this; + }; + Lotto3.prototype.remove = function(participant, tickets) { + var existingParticipant = this._participants.find(function(part) { + return part.participant === participant; + }); + if (!existingParticipant) { + return this; + } + if (tickets !== void 0) { + if (!(0, Utilities_1.isNaturalNumber)(tickets)) { + throw new Error("tickets value must be a natural number"); + } + existingParticipant.tickets -= tickets; + if (existingParticipant.tickets < 1) { + this._participants = this._participants.filter(function(part) { + return part !== existingParticipant; + }); + } + } else { + this._participants = this._participants.filter(function(part) { + return part !== existingParticipant; + }); + } + return this; + }; + Lotto3.prototype.draw = function(options) { + if (options === void 0) { + options = {}; + } + if (this._participants.length === 0) { + return null; + } + var redrawable = (0, Utilities_1.isNullOrUndefined)(options.redrawable) ? true : options.redrawable; + var pickable = []; + this._participants.forEach(function(_a) { + var participant = _a.participant, tickets = _a.tickets; + for (var ticketCount = 0; ticketCount < tickets; ticketCount++) { + pickable.push(participant); + } + }); + var random; + if (this._customRandom) { + random = this._customRandom(); + if (typeof random !== "number" || random < 0 || random >= 1) { + throw new Error("the 'random' function provided did not return a number between 0 (inclusive) and 1"); + } + } else { + random = Math.random(); + } + var winner = pickable[Math.floor(random * pickable.length)]; + if (!redrawable) { + this.remove(winner, 1); + } + return winner; + }; + Lotto3.prototype.drawMultiple = function(tickets, options) { + if (options === void 0) { + options = {}; + } + var uniqueResults = (0, Utilities_1.isNullOrUndefined)(options.unique) ? false : options.unique; + if (tickets === 0) { + return []; + } + if (!(0, Utilities_1.isNaturalNumber)(tickets)) { + throw new Error("tickets value must be a natural number"); + } + var result = []; + while (result.length < tickets && this._participants.length > 0) { + result.push(this.draw(options)); + } + if (uniqueResults) { + var unique = []; + for (var _i = 0, result_1 = result; _i < result_1.length; _i++) { + var participant = result_1[_i]; + if (unique.indexOf(participant) === -1) { + unique.push(participant); + } + } + result = unique; + } + return result; + }; + return Lotto3; + }(); + exports.Lotto = Lotto2; + } +}); + +// node_modules/lotto-draw/dist/createLotto.js +var require_createLotto = __commonJS({ + "node_modules/lotto-draw/dist/createLotto.js"(exports) { + "use strict"; + Object.defineProperty(exports, "__esModule", { value: true }); + exports.createLotto = void 0; + var Lotto_1 = require_Lotto(); + function createLotto2(participantsOrOptions) { + if (!participantsOrOptions) { + return new Lotto_1.Lotto(); + } + if (Array.isArray(participantsOrOptions)) { + var participants = participantsOrOptions; + var lotto_1 = new Lotto_1.Lotto(); + participants.forEach(function(_a) { + var participant = _a[0], tokens = _a[1]; + return lotto_1.add(participant, tokens); + }); + return lotto_1; + } else { + var random = participantsOrOptions.random, participants = participantsOrOptions.participants; + var lotto_2 = new Lotto_1.Lotto(random); + if (participants) { + participants.forEach(function(_a) { + var participant = _a[0], tokens = _a[1]; + return lotto_2.add(participant, tokens); + }); + } + return lotto_2; + } + } + exports.createLotto = createLotto2; + } +}); + +// node_modules/lotto-draw/dist/index.js +var require_dist = __commonJS({ + "node_modules/lotto-draw/dist/index.js"(exports) { + "use strict"; + Object.defineProperty(exports, "__esModule", { value: true }); + var createLotto_1 = require_createLotto(); + exports.default = createLotto_1.createLotto; + } +}); + +// src/index.ts +var src_exports = {}; +__export(src_exports, { + BehaviourTree: () => BehaviourTree, + State: () => State +}); +module.exports = __toCommonJS(src_exports); + +// src/attributes/guards/GuardUnsatisifedException.ts +var GuardUnsatisifedException = class extends Error { + constructor(source) { + super("A guard path condition has failed"); + this.source = source; + } + isSourceNode = (node) => node === this.source; +}; + +// src/attributes/guards/GuardPath.ts +var GuardPath = class { + constructor(nodes) { + this.nodes = nodes; + } + evaluate = (agent) => { + for (const details of this.nodes) { + for (const guard of details.guards) { + if (!guard.isSatisfied(agent)) { + throw new GuardUnsatisifedException(details.node); + } + } + } + }; +}; + +// src/State.ts +var State = /* @__PURE__ */ ((State2) => { + State2["READY"] = "mistreevous.ready"; + State2["RUNNING"] = "mistreevous.running"; + State2["SUCCEEDED"] = "mistreevous.succeeded"; + State2["FAILED"] = "mistreevous.failed"; + return State2; +})(State || {}); + +// src/nodes/Node.ts +var Node = class { + constructor(type, attributes, args) { + this.type = type; + this.attributes = attributes; + this.args = args; + } + uid = createNodeUid(); + state = "mistreevous.ready" /* READY */; + guardPath; + getState = () => this.state; + setState = (value) => { + this.state = value; + }; + getUid = () => this.uid; + getType = () => this.type; + getAttributes = () => this.attributes; + getArguments = () => this.args; + getAttribute(type) { + return this.getAttributes().filter((decorator) => decorator.getType().toUpperCase() === type.toUpperCase())[0] || null; + } + getGuardAttributes = () => this.getAttributes().filter((decorator) => decorator.isGuard()); + setGuardPath = (value) => this.guardPath = value; + hasGuardPath = () => !!this.guardPath; + is(value) { + return this.state === value; + } + reset() { + this.setState("mistreevous.ready" /* READY */); + } + abort(agent) { + if (!this.is("mistreevous.running" /* RUNNING */)) { + return; + } + this.reset(); + this.getAttribute("exit")?.callAgentFunction(agent, false, true); + } + update(agent, options) { + if (this.is("mistreevous.succeeded" /* SUCCEEDED */) || this.is("mistreevous.failed" /* FAILED */)) { + return; + } + try { + this.guardPath.evaluate(agent); + if (this.is("mistreevous.ready" /* READY */)) { + this.getAttribute("entry")?.callAgentFunction(agent); + } + this.getAttribute("step")?.callAgentFunction(agent); + this.onUpdate(agent, options); + if (this.is("mistreevous.succeeded" /* SUCCEEDED */) || this.is("mistreevous.failed" /* FAILED */)) { + this.getAttribute("exit")?.callAgentFunction(agent, this.is("mistreevous.succeeded" /* SUCCEEDED */), false); + } + } catch (error) { + if (error instanceof GuardUnsatisifedException && error.isSourceNode(this)) { + this.abort(agent); + this.setState("mistreevous.failed" /* FAILED */); + } else { + throw error; + } + } + } +}; +function createNodeUid() { + var S4 = function() { + return ((1 + Math.random()) * 65536 | 0).toString(16).substring(1); + }; + return S4() + S4() + "-" + S4() + "-" + S4() + "-" + S4() + "-" + S4() + S4() + S4(); +} + +// src/nodes/leaf/Leaf.ts +var Leaf = class extends Node { + isLeafNode = () => true; +}; + +// src/Lookup.ts +var Lookup = class { + static getFunc(name) { + return this.functionTable[name]; + } + static setFunc(name, func) { + this.functionTable[name] = func; + } + static getFuncInvoker(agent, name) { + const foundOnAgent = agent[name]; + if (foundOnAgent && typeof foundOnAgent === "function") { + return (args) => foundOnAgent.apply( + agent, + args.map((arg) => arg.value) + ); + } + if (this.functionTable[name] && typeof this.functionTable[name] === "function") { + return (args) => this.functionTable[name](agent, ...args.map((arg) => arg.value)); + } + return null; + } + static getSubtree(name) { + return this.subtreeTable[name]; + } + static setSubtree(name, subtree) { + this.subtreeTable[name] = subtree; + } + static remove(name) { + delete this.functionTable[name]; + delete this.subtreeTable[name]; + } + static empty() { + this.functionTable = {}; + this.subtreeTable = {}; + } +}; +__publicField(Lookup, "functionTable", {}); +__publicField(Lookup, "subtreeTable", {}); + +// src/nodes/leaf/Action.ts +var Action = class extends Leaf { + constructor(attributes, actionName, actionArguments) { + super("action", attributes, actionArguments); + this.actionName = actionName; + this.actionArguments = actionArguments; + } + isUsingUpdatePromise = false; + updatePromiseStateResult = null; + onUpdate(agent, options) { + if (this.isUsingUpdatePromise) { + if (this.updatePromiseStateResult) { + this.setState(this.updatePromiseStateResult); + } + return; + } + const actionFuncInvoker = Lookup.getFuncInvoker(agent, this.actionName); + if (actionFuncInvoker === null) { + throw new Error( + `cannot update action node as the action '${this.actionName}' function is not defined on the agent and has not been registered` + ); + } + const updateResult = actionFuncInvoker(this.actionArguments); + if (updateResult instanceof Promise) { + updateResult.then( + (result) => { + if (!this.isUsingUpdatePromise) { + return; + } + if (result !== "mistreevous.succeeded" /* SUCCEEDED */ && result !== "mistreevous.failed" /* FAILED */) { + throw new Error( + "action node promise resolved with an invalid value, expected a State.SUCCEEDED or State.FAILED value to be returned" + ); + } + this.updatePromiseStateResult = result; + }, + (reason) => { + if (!this.isUsingUpdatePromise) { + return; + } + throw new Error(reason); + } + ); + this.setState("mistreevous.running" /* RUNNING */); + this.isUsingUpdatePromise = true; + } else { + this.validateUpdateResult(updateResult); + this.setState(updateResult || "mistreevous.running" /* RUNNING */); + } + } + getName = () => this.actionName; + reset = () => { + this.setState("mistreevous.ready" /* READY */); + this.isUsingUpdatePromise = false; + this.updatePromiseStateResult = null; + }; + validateUpdateResult = (result) => { + switch (result) { + case "mistreevous.succeeded" /* SUCCEEDED */: + case "mistreevous.failed" /* FAILED */: + case void 0: + return; + default: + throw new Error( + `action '${this.actionName}' 'onUpdate' returned an invalid response, expected an optional State.SUCCEEDED or State.FAILED value to be returned` + ); + } + }; +}; + +// src/nodes/leaf/Condition.ts +var Condition = class extends Leaf { + constructor(attributes, conditionName, conditionArguments) { + super("condition", attributes, conditionArguments); + this.conditionName = conditionName; + this.conditionArguments = conditionArguments; + } + onUpdate(agent, options) { + const conditionFuncInvoker = Lookup.getFuncInvoker(agent, this.conditionName); + if (conditionFuncInvoker === null) { + throw new Error( + `cannot update condition node as the condition '${this.conditionName}' function is not defined on the agent and has not been registered` + ); + } + this.setState(!!conditionFuncInvoker(this.conditionArguments) ? "mistreevous.succeeded" /* SUCCEEDED */ : "mistreevous.failed" /* FAILED */); + } + getName = () => this.conditionName; +}; + +// src/nodes/leaf/Wait.ts +var Wait = class extends Leaf { + constructor(attributes, duration, durationMin, durationMax) { + super("wait", attributes, []); + this.duration = duration; + this.durationMin = durationMin; + this.durationMax = durationMax; + } + initialUpdateTime = 0; + totalDuration = null; + waitedDuration = 0; + onUpdate(agent, options) { + if (this.is("mistreevous.ready" /* READY */)) { + this.initialUpdateTime = new Date().getTime(); + this.waitedDuration = 0; + if (this.duration !== null) { + this.totalDuration = this.duration; + } else if (this.durationMin !== null && this.durationMax !== null) { + const random = typeof options.random === "function" ? options.random : Math.random; + this.totalDuration = Math.floor( + random() * (this.durationMax - this.durationMin + 1) + this.durationMin + ); + } else { + this.totalDuration = null; + } + this.setState("mistreevous.running" /* RUNNING */); + } + if (this.totalDuration === null) { + return; + } + if (typeof options.getDeltaTime === "function") { + const deltaTime = options.getDeltaTime(); + if (typeof deltaTime !== "number" || isNaN(deltaTime)) { + throw new Error("The delta time must be a valid number and not NaN."); + } + this.waitedDuration += deltaTime * 1e3; + } else { + this.waitedDuration = new Date().getTime() - this.initialUpdateTime; + } + if (this.waitedDuration >= this.totalDuration) { + this.setState("mistreevous.succeeded" /* SUCCEEDED */); + } + } + getName = () => { + if (this.duration !== null) { + return `WAIT ${this.duration}ms`; + } else if (this.durationMin !== null && this.durationMax !== null) { + return `WAIT ${this.durationMin}ms-${this.durationMax}ms`; + } else { + return "WAIT"; + } + }; +}; + +// src/nodes/decorator/Decorator.ts +var Decorator = class extends Node { + constructor(type, attributes, child) { + super(type, attributes, []); + this.child = child; + } + isLeafNode = () => false; + getChildren = () => [this.child]; + reset = () => { + this.setState("mistreevous.ready" /* READY */); + this.child.reset(); + }; + abort = (agent) => { + if (!this.is("mistreevous.running" /* RUNNING */)) { + return; + } + this.child.abort(agent); + this.reset(); + this.getAttribute("exit")?.callAgentFunction(agent, false, true); + }; +}; + +// src/nodes/decorator/Root.ts +var Root = class extends Decorator { + constructor(attributes, child) { + super("root", attributes, child); + } + onUpdate(agent, options) { + if (this.child.getState() === "mistreevous.ready" /* READY */ || this.child.getState() === "mistreevous.running" /* RUNNING */) { + this.child.update(agent, options); + } + this.setState(this.child.getState()); + } + getName = () => "ROOT"; +}; + +// src/nodes/decorator/Repeat.ts +var Repeat = class extends Decorator { + constructor(attributes, iterations, iterationsMin, iterationsMax, child) { + super("repeat", attributes, child); + this.iterations = iterations; + this.iterationsMin = iterationsMin; + this.iterationsMax = iterationsMax; + } + targetIterationCount = null; + currentIterationCount = 0; + onUpdate(agent, options) { + if (this.is("mistreevous.ready" /* READY */)) { + this.child.reset(); + this.currentIterationCount = 0; + this.setTargetIterationCount(options); + } + if (this.canIterate()) { + this.setState("mistreevous.running" /* RUNNING */); + if (this.child.getState() === "mistreevous.succeeded" /* SUCCEEDED */) { + this.child.reset(); + } + this.child.update(agent, options); + if (this.child.getState() === "mistreevous.failed" /* FAILED */) { + this.setState("mistreevous.failed" /* FAILED */); + return; + } else if (this.child.getState() === "mistreevous.succeeded" /* SUCCEEDED */) { + this.currentIterationCount += 1; + } + } else { + this.setState("mistreevous.succeeded" /* SUCCEEDED */); + } + } + getName = () => { + if (this.iterations !== null) { + return `REPEAT ${this.iterations}x`; + } else if (this.iterationsMin !== null && this.iterationsMax !== null) { + return `REPEAT ${this.iterationsMin}x-${this.iterationsMax}x`; + } else { + return "REPEAT"; + } + }; + reset = () => { + this.setState("mistreevous.ready" /* READY */); + this.currentIterationCount = 0; + this.child.reset(); + }; + canIterate = () => { + if (this.targetIterationCount !== null) { + return this.currentIterationCount < this.targetIterationCount; + } + return true; + }; + setTargetIterationCount = (options) => { + if (this.iterations !== null) { + this.targetIterationCount = this.iterations; + } else if (this.iterationsMin !== null && this.iterationsMax !== null) { + const random = typeof options.random === "function" ? options.random : Math.random; + this.targetIterationCount = Math.floor( + random() * (this.iterationsMax - this.iterationsMin + 1) + this.iterationsMin + ); + } else { + this.targetIterationCount = null; + } + }; +}; + +// src/nodes/decorator/Retry.ts +var Retry = class extends Decorator { + constructor(attributes, attempts, attemptsMin, attemptsMax, child) { + super("retry", attributes, child); + this.attempts = attempts; + this.attemptsMin = attemptsMin; + this.attemptsMax = attemptsMax; + } + targetAttemptCount = null; + currentAttemptCount = 0; + onUpdate(agent, options) { + if (this.is("mistreevous.ready" /* READY */)) { + this.child.reset(); + this.currentAttemptCount = 0; + this.setTargetAttemptCount(options); + } + if (this.canAttempt()) { + this.setState("mistreevous.running" /* RUNNING */); + if (this.child.getState() === "mistreevous.failed" /* FAILED */) { + this.child.reset(); + } + this.child.update(agent, options); + if (this.child.getState() === "mistreevous.succeeded" /* SUCCEEDED */) { + this.setState("mistreevous.succeeded" /* SUCCEEDED */); + return; + } else if (this.child.getState() === "mistreevous.failed" /* FAILED */) { + this.currentAttemptCount += 1; + } + } else { + this.setState("mistreevous.failed" /* FAILED */); + } + } + getName = () => { + if (this.attempts !== null) { + return `RETRY ${this.attempts}x`; + } else if (this.attemptsMin !== null && this.attemptsMax !== null) { + return `RETRY ${this.attemptsMin}x-${this.attemptsMax}x`; + } else { + return "RETRY"; + } + }; + reset = () => { + this.setState("mistreevous.ready" /* READY */); + this.currentAttemptCount = 0; + this.child.reset(); + }; + canAttempt = () => { + if (this.targetAttemptCount !== null) { + return this.currentAttemptCount < this.targetAttemptCount; + } + return true; + }; + setTargetAttemptCount = (options) => { + if (this.attempts !== null) { + this.targetAttemptCount = this.attempts; + } else if (this.attemptsMin !== null && this.attemptsMax !== null) { + const random = typeof options.random === "function" ? options.random : Math.random; + this.targetAttemptCount = Math.floor( + random() * (this.attemptsMax - this.attemptsMin + 1) + this.attemptsMin + ); + } else { + this.targetAttemptCount = null; + } + }; +}; + +// src/nodes/decorator/Flip.ts +var Flip = class extends Decorator { + constructor(attributes, child) { + super("flip", attributes, child); + } + onUpdate(agent, options) { + if (this.child.getState() === "mistreevous.ready" /* READY */ || this.child.getState() === "mistreevous.running" /* RUNNING */) { + this.child.update(agent, options); + } + switch (this.child.getState()) { + case "mistreevous.running" /* RUNNING */: + this.setState("mistreevous.running" /* RUNNING */); + break; + case "mistreevous.succeeded" /* SUCCEEDED */: + this.setState("mistreevous.failed" /* FAILED */); + break; + case "mistreevous.failed" /* FAILED */: + this.setState("mistreevous.succeeded" /* SUCCEEDED */); + break; + default: + this.setState("mistreevous.ready" /* READY */); + } + } + getName = () => "FLIP"; +}; + +// src/nodes/decorator/Succeed.ts +var Succeed = class extends Decorator { + constructor(attributes, child) { + super("succeed", attributes, child); + } + onUpdate(agent, options) { + if (this.child.getState() === "mistreevous.ready" /* READY */ || this.child.getState() === "mistreevous.running" /* RUNNING */) { + this.child.update(agent, options); + } + switch (this.child.getState()) { + case "mistreevous.running" /* RUNNING */: + this.setState("mistreevous.running" /* RUNNING */); + break; + case "mistreevous.succeeded" /* SUCCEEDED */: + case "mistreevous.failed" /* FAILED */: + this.setState("mistreevous.succeeded" /* SUCCEEDED */); + break; + default: + this.setState("mistreevous.ready" /* READY */); + } + } + getName = () => "SUCCEED"; +}; + +// src/nodes/decorator/Fail.ts +var Fail = class extends Decorator { + constructor(attributes, child) { + super("fail", attributes, child); + } + onUpdate(agent, options) { + if (this.child.getState() === "mistreevous.ready" /* READY */ || this.child.getState() === "mistreevous.running" /* RUNNING */) { + this.child.update(agent, options); + } + switch (this.child.getState()) { + case "mistreevous.running" /* RUNNING */: + this.setState("mistreevous.running" /* RUNNING */); + break; + case "mistreevous.succeeded" /* SUCCEEDED */: + case "mistreevous.failed" /* FAILED */: + this.setState("mistreevous.failed" /* FAILED */); + break; + default: + this.setState("mistreevous.ready" /* READY */); + } + } + getName = () => "FAIL"; +}; + +// src/nodes/composite/Lotto.ts +var import_lotto_draw = __toESM(require_dist()); + +// src/nodes/composite/Composite.ts +var Composite = class extends Node { + constructor(type, attributes, children) { + super(type, attributes, []); + this.children = children; + } + isLeafNode = () => false; + getChildren = () => this.children; + reset = () => { + this.setState("mistreevous.ready" /* READY */); + this.getChildren().forEach((child) => child.reset()); + }; + abort = (agent) => { + if (!this.is("mistreevous.running" /* RUNNING */)) { + return; + } + this.getChildren().forEach((child) => child.abort(agent)); + this.reset(); + this.getAttribute("exit")?.callAgentFunction(agent, false, true); + }; +}; + +// src/nodes/composite/Lotto.ts +var Lotto = class extends Composite { + constructor(attributes, tickets, children) { + super("lotto", attributes, children); + this.tickets = tickets; + } + selectedChild; + onUpdate(agent, options) { + if (this.is("mistreevous.ready" /* READY */)) { + const lottoDraw = (0, import_lotto_draw.default)({ + random: options.random, + participants: this.children.map((child, index) => [child, this.tickets[index] || 1]) + }); + this.selectedChild = lottoDraw.draw() || void 0; + } + if (!this.selectedChild) { + throw new Error("failed to update lotto node as it has no active child"); + } + if (this.selectedChild.getState() === "mistreevous.ready" /* READY */ || this.selectedChild.getState() === "mistreevous.running" /* RUNNING */) { + this.selectedChild.update(agent, options); + } + this.setState(this.selectedChild.getState()); + } + getName = () => this.tickets.length ? `LOTTO [${this.tickets.join(",")}]` : "LOTTO"; +}; + +// src/nodes/composite/Selector.ts +var Selector = class extends Composite { + constructor(attributes, children) { + super("selector", attributes, children); + this.children = children; + } + onUpdate(agent, options) { + for (const child of this.children) { + if (child.getState() === "mistreevous.ready" /* READY */ || child.getState() === "mistreevous.running" /* RUNNING */) { + child.update(agent, options); + } + if (child.getState() === "mistreevous.succeeded" /* SUCCEEDED */) { + this.setState("mistreevous.succeeded" /* SUCCEEDED */); + return; + } + if (child.getState() === "mistreevous.failed" /* FAILED */) { + if (this.children.indexOf(child) === this.children.length - 1) { + this.setState("mistreevous.failed" /* FAILED */); + return; + } else { + continue; + } + } + if (child.getState() === "mistreevous.running" /* RUNNING */) { + this.setState("mistreevous.running" /* RUNNING */); + return; + } + throw new Error("child node was not in an expected state."); + } + } + getName = () => "SELECTOR"; +}; + +// src/nodes/composite/Sequence.ts +var Sequence = class extends Composite { + constructor(attributes, children) { + super("sequence", attributes, children); + this.children = children; + } + onUpdate(agent, options) { + for (const child of this.children) { + if (child.getState() === "mistreevous.ready" /* READY */ || child.getState() === "mistreevous.running" /* RUNNING */) { + child.update(agent, options); + } + if (child.getState() === "mistreevous.succeeded" /* SUCCEEDED */) { + if (this.children.indexOf(child) === this.children.length - 1) { + this.setState("mistreevous.succeeded" /* SUCCEEDED */); + return; + } else { + continue; + } + } + if (child.getState() === "mistreevous.failed" /* FAILED */) { + this.setState("mistreevous.failed" /* FAILED */); + return; + } + if (child.getState() === "mistreevous.running" /* RUNNING */) { + this.setState("mistreevous.running" /* RUNNING */); + return; + } + throw new Error("child node was not in an expected state."); + } + } + getName = () => "SEQUENCE"; +}; + +// src/nodes/composite/Parallel.ts +var Parallel = class extends Composite { + constructor(attributes, children) { + super("parallel", attributes, children); + } + onUpdate(agent, options) { + let succeededCount = 0; + let hasChildFailed = false; + for (const child of this.children) { + if (child.getState() === "mistreevous.ready" /* READY */ || child.getState() === "mistreevous.running" /* RUNNING */) { + child.update(agent, options); + } + if (child.getState() === "mistreevous.succeeded" /* SUCCEEDED */) { + succeededCount++; + continue; + } + if (child.getState() === "mistreevous.failed" /* FAILED */) { + hasChildFailed = true; + break; + } + if (child.getState() !== "mistreevous.running" /* RUNNING */) { + throw new Error("child node was not in an expected state."); + } + } + if (hasChildFailed) { + this.setState("mistreevous.failed" /* FAILED */); + for (const child of this.children) { + if (child.getState() === "mistreevous.running" /* RUNNING */) { + child.abort(agent); + } + } + } else { + this.setState(succeededCount === this.children.length ? "mistreevous.succeeded" /* SUCCEEDED */ : "mistreevous.running" /* RUNNING */); + } + } + getName = () => "PARALLEL"; +}; + +// src/attributes/Attribute.ts +var Attribute = class { + constructor(type, args) { + this.type = type; + this.args = args; + } + getType = () => this.type; + getArguments = () => this.args; +}; + +// src/attributes/guards/Guard.ts +var Guard = class extends Attribute { + constructor(type, args, condition) { + super(type, args); + this.condition = condition; + } + getCondition = () => this.condition; + isGuard = () => true; + getDetails() { + return { + type: this.getType(), + args: this.getArguments(), + condition: this.getCondition() + }; + } +}; + +// src/attributes/guards/While.ts +var While = class extends Guard { + constructor(condition, args) { + super("while", args, condition); + } + isSatisfied = (agent) => { + const conditionFuncInvoker = Lookup.getFuncInvoker(agent, this.getCondition()); + if (conditionFuncInvoker === null) { + throw new Error( + `cannot evaluate node guard as the condition '${this.getCondition()}' function is not defined on the agent and has not been registered` + ); + } + return !!conditionFuncInvoker(this.args); + }; +}; + +// src/attributes/guards/Until.ts +var Until = class extends Guard { + constructor(condition, args) { + super("until", args, condition); + } + isSatisfied = (agent) => { + const conditionFuncInvoker = Lookup.getFuncInvoker(agent, this.getCondition()); + if (conditionFuncInvoker === null) { + throw new Error( + `cannot evaluate node guard as the condition '${this.getCondition()}' function is not defined on the agent and has not been registered` + ); + } + return !!!conditionFuncInvoker(this.args); + }; +}; + +// src/attributes/callbacks/Callback.ts +var Callback = class extends Attribute { + constructor(type, args, functionName) { + super(type, args); + this.functionName = functionName; + } + getFunctionName = () => this.functionName; + isGuard = () => false; + getDetails() { + return { + type: this.getType(), + args: this.getArguments(), + functionName: this.getFunctionName() + }; + } +}; + +// src/attributes/callbacks/Entry.ts +var Entry = class extends Callback { + constructor(functionName, args) { + super("entry", args, functionName); + } + callAgentFunction = (agent) => { + const callbackFuncInvoker = Lookup.getFuncInvoker(agent, this.getFunctionName()); + if (callbackFuncInvoker === null) { + throw new Error( + `cannot call entry function '${this.getFunctionName()}' as is not defined on the agent and has not been registered` + ); + } + callbackFuncInvoker(this.args); + }; +}; + +// src/attributes/callbacks/Exit.ts +var Exit = class extends Callback { + constructor(functionName, args) { + super("exit", args, functionName); + } + callAgentFunction = (agent, isSuccess, isAborted) => { + const callbackFuncInvoker = Lookup.getFuncInvoker(agent, this.getFunctionName()); + if (callbackFuncInvoker === null) { + throw new Error( + `cannot call exit function '${this.getFunctionName()}' as is not defined on the agent and has not been registered` + ); + } + callbackFuncInvoker([{ value: { succeeded: isSuccess, aborted: isAborted } }, ...this.args]); + }; +}; + +// src/attributes/callbacks/Step.ts +var Step = class extends Callback { + constructor(functionName, args) { + super("step", args, functionName); + } + callAgentFunction = (agent) => { + const callbackFuncInvoker = Lookup.getFuncInvoker(agent, this.getFunctionName()); + if (callbackFuncInvoker === null) { + throw new Error( + `cannot call step function '${this.getFunctionName()}' as is not defined on the agent and has not been registered` + ); + } + callbackFuncInvoker(this.args); + }; +}; + +// src/RootAstNodesBuilder.ts +var AttributeFactories = { + WHILE: (condition, attributeArguments) => new While(condition, attributeArguments), + UNTIL: (condition, attributeArguments) => new Until(condition, attributeArguments), + ENTRY: (functionName, attributeArguments) => new Entry(functionName, attributeArguments), + EXIT: (functionName, attributeArguments) => new Exit(functionName, attributeArguments), + STEP: (functionName, attributeArguments) => new Step(functionName, attributeArguments) +}; +var ASTNodeFactories = { + ROOT: () => ({ + type: "root", + attributes: [], + name: null, + children: [], + validate(depth) { + if (depth > 1) { + throw new Error("a root node cannot be the child of another node"); + } + if (this.children.length !== 1) { + throw new Error("a root node must have a single child"); + } + }, + createNodeInstance(namedRootNodeProvider, visitedBranches) { + return new Root( + this.attributes, + this.children[0].createNodeInstance(namedRootNodeProvider, visitedBranches.slice()) + ); + } + }), + BRANCH: () => ({ + type: "branch", + branchName: "", + validate() { + }, + createNodeInstance(namedRootNodeProvider, visitedBranches) { + const targetRootNode = namedRootNodeProvider(this.branchName); + if (visitedBranches.indexOf(this.branchName) !== -1) { + throw new Error(`circular dependency found in branch node references for branch '${this.branchName}'`); + } + if (targetRootNode) { + return targetRootNode.createNodeInstance(namedRootNodeProvider, visitedBranches.concat(this.branchName)).getChildren()[0]; + } else { + throw new Error(`branch references root node '${this.branchName}' which has not been defined`); + } + } + }), + SELECTOR: () => ({ + type: "selector", + attributes: [], + children: [], + validate() { + if (this.children.length < 1) { + throw new Error("a selector node must have at least a single child"); + } + }, + createNodeInstance(namedRootNodeProvider, visitedBranches) { + return new Selector( + this.attributes, + this.children.map((child) => child.createNodeInstance(namedRootNodeProvider, visitedBranches.slice())) + ); + } + }), + SEQUENCE: () => ({ + type: "sequence", + attributes: [], + children: [], + validate() { + if (this.children.length < 1) { + throw new Error("a sequence node must have at least a single child"); + } + }, + createNodeInstance(namedRootNodeProvider, visitedBranches) { + return new Sequence( + this.attributes, + this.children.map((child) => child.createNodeInstance(namedRootNodeProvider, visitedBranches.slice())) + ); + } + }), + PARALLEL: () => ({ + type: "parallel", + attributes: [], + children: [], + validate() { + if (this.children.length < 1) { + throw new Error("a parallel node must have at least a single child"); + } + }, + createNodeInstance(namedRootNodeProvider, visitedBranches) { + return new Parallel( + this.attributes, + this.children.map((child) => child.createNodeInstance(namedRootNodeProvider, visitedBranches.slice())) + ); + } + }), + LOTTO: () => ({ + type: "lotto", + attributes: [], + children: [], + tickets: [], + validate() { + if (this.children.length < 1) { + throw new Error("a lotto node must have at least a single child"); + } + }, + createNodeInstance(namedRootNodeProvider, visitedBranches) { + return new Lotto( + this.attributes, + this.tickets, + this.children.map((child) => child.createNodeInstance(namedRootNodeProvider, visitedBranches.slice())) + ); + } + }), + REPEAT: () => ({ + type: "repeat", + attributes: [], + iterations: null, + iterationsMin: null, + iterationsMax: null, + children: [], + validate() { + if (this.children.length !== 1) { + throw new Error("a repeat node must have a single child"); + } + if (this.iterations !== null) { + if (this.iterations < 0) { + throw new Error("a repeat node must have a positive number of iterations if defined"); + } + } else if (this.iterationsMin !== null && this.iterationsMax !== null) { + if (this.iterationsMin < 0 || this.iterationsMax < 0) { + throw new Error( + "a repeat node must have a positive minimum and maximum iteration count if defined" + ); + } + if (this.iterationsMin > this.iterationsMax) { + throw new Error( + "a repeat node must not have a minimum iteration count that exceeds the maximum iteration count" + ); + } + } else { + } + }, + createNodeInstance(namedRootNodeProvider, visitedBranches) { + return new Repeat( + this.attributes, + this.iterations, + this.iterationsMin, + this.iterationsMax, + this.children[0].createNodeInstance(namedRootNodeProvider, visitedBranches.slice()) + ); + } + }), + RETRY: () => ({ + type: "retry", + attributes: [], + attempts: null, + attemptsMin: null, + attemptsMax: null, + children: [], + validate() { + if (this.children.length !== 1) { + throw new Error("a retry node must have a single child"); + } + if (this.attempts !== null) { + if (this.attempts < 0) { + throw new Error("a retry node must have a positive number of attempts if defined"); + } + } else if (this.attemptsMin !== null && this.attemptsMax !== null) { + if (this.attemptsMin < 0 || this.attemptsMax < 0) { + throw new Error("a retry node must have a positive minimum and maximum attempt count if defined"); + } + if (this.attemptsMin > this.attemptsMax) { + throw new Error( + "a retry node must not have a minimum attempt count that exceeds the maximum attempt count" + ); + } + } else { + } + }, + createNodeInstance(namedRootNodeProvider, visitedBranches) { + return new Retry( + this.attributes, + this.attempts, + this.attemptsMin, + this.attemptsMax, + this.children[0].createNodeInstance(namedRootNodeProvider, visitedBranches.slice()) + ); + } + }), + FLIP: () => ({ + type: "flip", + attributes: [], + children: [], + validate() { + if (this.children.length !== 1) { + throw new Error("a flip node must have a single child"); + } + }, + createNodeInstance(namedRootNodeProvider, visitedBranches) { + return new Flip( + this.attributes, + this.children[0].createNodeInstance(namedRootNodeProvider, visitedBranches.slice()) + ); + } + }), + SUCCEED: () => ({ + type: "succeed", + attributes: [], + children: [], + validate() { + if (this.children.length !== 1) { + throw new Error("a succeed node must have a single child"); + } + }, + createNodeInstance(namedRootNodeProvider, visitedBranches) { + return new Succeed( + this.attributes, + this.children[0].createNodeInstance(namedRootNodeProvider, visitedBranches.slice()) + ); + } + }), + FAIL: () => ({ + type: "fail", + attributes: [], + children: [], + validate() { + if (this.children.length !== 1) { + throw new Error("a fail node must have a single child"); + } + }, + createNodeInstance(namedRootNodeProvider, visitedBranches) { + return new Fail( + this.attributes, + this.children[0].createNodeInstance(namedRootNodeProvider, visitedBranches.slice()) + ); + } + }), + WAIT: () => ({ + type: "wait", + attributes: [], + duration: null, + durationMin: null, + durationMax: null, + validate() { + if (this.duration !== null) { + if (this.duration < 0) { + throw new Error("a wait node must have a positive duration"); + } + } else if (this.durationMin !== null && this.durationMax !== null) { + if (this.durationMin < 0 || this.durationMax < 0) { + throw new Error("a wait node must have a positive minimum and maximum duration"); + } + if (this.durationMin > this.durationMax) { + throw new Error("a wait node must not have a minimum duration that exceeds the maximum duration"); + } + } else { + } + }, + createNodeInstance() { + return new Wait(this.attributes, this.duration, this.durationMin, this.durationMax); + } + }), + ACTION: () => ({ + type: "action", + attributes: [], + actionName: "", + actionArguments: [], + validate() { + }, + createNodeInstance() { + return new Action(this.attributes, this.actionName, this.actionArguments); + } + }), + CONDITION: () => ({ + type: "condition", + attributes: [], + conditionName: "", + conditionArguments: [], + validate() { + }, + createNodeInstance() { + return new Condition(this.attributes, this.conditionName, this.conditionArguments); + } + }) +}; +function buildRootASTNodes(definition) { + const { placeholders, processedDefinition } = substituteStringLiterals(definition); + const tokens = parseTokensFromDefinition(processedDefinition); + if (tokens.length < 3) { + throw new Error("invalid token count"); + } + if (tokens.filter((token) => token === "{").length !== tokens.filter((token) => token === "}").length) { + throw new Error("scope character mismatch"); + } + const stack = [[]]; + const rootScope = stack[0]; + while (tokens.length) { + const token = tokens.shift(); + const currentScope = stack[stack.length - 1]; + switch (token.toUpperCase()) { + case "ROOT": { + const node = ASTNodeFactories.ROOT(); + rootScope.push(node); + if (tokens[0] === "[") { + const rootArguments = getArguments(tokens, placeholders); + if (rootArguments.length === 1 && rootArguments[0].type === "identifier") { + node.name = rootArguments[0].value; + } else { + throw new Error("expected single root name argument"); + } + } + node.attributes = getAttributes(tokens, placeholders); + popAndCheck(tokens, "{"); + stack.push(node.children); + break; + } + case "BRANCH": { + const node = ASTNodeFactories.BRANCH(); + currentScope.push(node); + if (tokens[0] !== "[") { + throw new Error("expected single branch name argument"); + } + const branchArguments = getArguments(tokens, placeholders); + if (branchArguments.length === 1 && branchArguments[0].type === "identifier") { + node.branchName = branchArguments[0].value; + } else { + throw new Error("expected single branch name argument"); + } + break; + } + case "SELECTOR": { + const node = ASTNodeFactories.SELECTOR(); + currentScope.push(node); + node.attributes = getAttributes(tokens, placeholders); + popAndCheck(tokens, "{"); + stack.push(node.children); + break; + } + case "SEQUENCE": { + const node = ASTNodeFactories.SEQUENCE(); + currentScope.push(node); + node.attributes = getAttributes(tokens, placeholders); + popAndCheck(tokens, "{"); + stack.push(node.children); + break; + } + case "PARALLEL": { + const node = ASTNodeFactories.PARALLEL(); + currentScope.push(node); + node.attributes = getAttributes(tokens, placeholders); + popAndCheck(tokens, "{"); + stack.push(node.children); + break; + } + case "LOTTO": { + const node = ASTNodeFactories.LOTTO(); + currentScope.push(node); + if (tokens[0] === "[") { + node.tickets = getArguments( + tokens, + placeholders, + (arg) => arg.type === "number" && !!arg.isInteger, + "lotto node ticket counts must be integer values" + ).map((argument) => argument.value); + } + node.attributes = getAttributes(tokens, placeholders); + popAndCheck(tokens, "{"); + stack.push(node.children); + break; + } + case "CONDITION": { + const node = ASTNodeFactories.CONDITION(); + currentScope.push(node); + if (tokens[0] !== "[") { + throw new Error("expected condition name identifier argument"); + } + const conditionArguments = getArguments(tokens, placeholders); + if (conditionArguments.length && conditionArguments[0].type === "identifier") { + node.conditionName = conditionArguments.shift().value; + } else { + throw new Error("expected condition name identifier argument"); + } + conditionArguments.filter((arg) => arg.type === "identifier").forEach((arg) => { + throw new Error( + "invalid condition node argument value '" + arg.value + "', must be string, number, boolean or null" + ); + }); + node.conditionArguments = conditionArguments; + node.attributes = getAttributes(tokens, placeholders); + break; + } + case "FLIP": { + const node = ASTNodeFactories.FLIP(); + currentScope.push(node); + node.attributes = getAttributes(tokens, placeholders); + popAndCheck(tokens, "{"); + stack.push(node.children); + break; + } + case "SUCCEED": { + const node = ASTNodeFactories.SUCCEED(); + currentScope.push(node); + node.attributes = getAttributes(tokens, placeholders); + popAndCheck(tokens, "{"); + stack.push(node.children); + break; + } + case "FAIL": { + const node = ASTNodeFactories.FAIL(); + currentScope.push(node); + node.attributes = getAttributes(tokens, placeholders); + popAndCheck(tokens, "{"); + stack.push(node.children); + break; + } + case "WAIT": { + const node = ASTNodeFactories.WAIT(); + currentScope.push(node); + if (tokens[0] === "[") { + const nodeArguments = getArguments( + tokens, + placeholders, + (arg) => arg.type === "number" && !!arg.isInteger, + "wait node durations must be integer values" + ).map((argument) => argument.value); + if (nodeArguments.length === 1) { + node.duration = nodeArguments[0]; + } else if (nodeArguments.length === 2) { + node.durationMin = nodeArguments[0]; + node.durationMax = nodeArguments[1]; + } else if (nodeArguments.length > 2) { + throw new Error("invalid number of wait node duration arguments defined"); + } + } + node.attributes = getAttributes(tokens, placeholders); + break; + } + case "REPEAT": { + const node = ASTNodeFactories.REPEAT(); + currentScope.push(node); + if (tokens[0] === "[") { + const nodeArguments = getArguments( + tokens, + placeholders, + (arg) => arg.type === "number" && !!arg.isInteger, + "repeat node iteration counts must be integer values" + ).map((argument) => argument.value); + if (nodeArguments.length === 1) { + node.iterations = nodeArguments[0]; + } else if (nodeArguments.length === 2) { + node.iterationsMin = nodeArguments[0]; + node.iterationsMax = nodeArguments[1]; + } else { + throw new Error("invalid number of repeat node iteration count arguments defined"); + } + } + node.attributes = getAttributes(tokens, placeholders); + popAndCheck(tokens, "{"); + stack.push(node.children); + break; + } + case "RETRY": { + const node = ASTNodeFactories.RETRY(); + currentScope.push(node); + if (tokens[0] === "[") { + const nodeArguments = getArguments( + tokens, + placeholders, + (arg) => arg.type === "number" && !!arg.isInteger, + "retry node attempt counts must be integer values" + ).map((argument) => argument.value); + if (nodeArguments.length === 1) { + node.attempts = nodeArguments[0]; + } else if (nodeArguments.length === 2) { + node.attemptsMin = nodeArguments[0]; + node.attemptsMax = nodeArguments[1]; + } else { + throw new Error("invalid number of retry node attempt count arguments defined"); + } + } + node.attributes = getAttributes(tokens, placeholders); + popAndCheck(tokens, "{"); + stack.push(node.children); + break; + } + case "ACTION": { + const node = ASTNodeFactories.ACTION(); + currentScope.push(node); + if (tokens[0] !== "[") { + throw new Error("expected action name identifier argument"); + } + const actionArguments = getArguments(tokens, placeholders); + if (actionArguments.length && actionArguments[0].type === "identifier") { + node.actionName = actionArguments.shift().value; + } else { + throw new Error("expected action name identifier argument"); + } + actionArguments.filter((arg) => arg.type === "identifier").forEach((arg) => { + throw new Error( + "invalid action node argument value '" + arg.value + "', must be string, number, boolean or null" + ); + }); + node.actionArguments = actionArguments; + node.attributes = getAttributes(tokens, placeholders); + break; + } + case "}": { + stack.pop(); + break; + } + default: { + throw new Error(`unexpected token '${token}'`); + } + } + } + const validateASTNode = (node, depth) => { + node.validate(depth); + (node.children || []).forEach((child) => validateASTNode(child, depth + 1)); + }; + validateASTNode( + { + children: stack[0], + validate() { + if (this.children.length === 0) { + throw new Error("expected root node to have been defined"); + } + for (const definitionLevelNode of this.children) { + if (definitionLevelNode.type !== "root") { + throw new Error("expected root node at base of definition"); + } + } + if (this.children.filter((definitionLevelNode) => definitionLevelNode.name === null).length !== 1) { + throw new Error("expected single unnamed root node at base of definition to act as main root"); + } + const rootNodeNames = []; + for (const definitionLevelNode of this.children) { + if (rootNodeNames.indexOf(definitionLevelNode.name) !== -1) { + throw new Error(`multiple root nodes found with duplicate name '${definitionLevelNode.name}'`); + } else { + rootNodeNames.push(definitionLevelNode.name); + } + } + } + }, + 0 + ); + return stack[0]; +} +function popAndCheck(tokens, expected) { + const popped = tokens.shift(); + if (popped === void 0) { + throw new Error("unexpected end of definition"); + } + if (expected !== void 0) { + var tokenMatchesExpectation = [].concat(expected).some((item) => popped.toUpperCase() === item.toUpperCase()); + if (!tokenMatchesExpectation) { + const expectationString = [].concat(expected).map((item) => "'" + item + "'").join(" or "); + throw new Error(`unexpected token found. Expected '${expectationString}' but got '${popped}'`); + } + } + return popped; +} +function getArguments(tokens, stringArgumentPlaceholders, argumentValidator, validationFailedMessage) { + const closer = popAndCheck(tokens, ["[", "("]) === "[" ? "]" : ")"; + const argumentListTokens = []; + const argumentList = []; + while (tokens.length && tokens[0] !== closer) { + argumentListTokens.push(tokens.shift()); + } + argumentListTokens.forEach((token, index) => { + const shouldBeArgumentToken = !(index & 1); + if (shouldBeArgumentToken) { + const argumentDefinition = getArgumentDefinition(token, stringArgumentPlaceholders); + if (argumentValidator && !argumentValidator(argumentDefinition)) { + throw new Error(validationFailedMessage); + } + argumentList.push(argumentDefinition); + } else { + if (token !== ",") { + throw new Error(`invalid argument list, expected ',' or ']' but got '${token}'`); + } + } + }); + popAndCheck(tokens, closer); + return argumentList; +} +function getArgumentDefinition(token, stringArgumentPlaceholders) { + if (token === "null") { + return { + value: null, + type: "null" + }; + } + if (token === "true" || token === "false") { + return { + value: token === "true", + type: "boolean" + }; + } + if (!isNaN(token)) { + return { + value: parseFloat(token), + isInteger: parseFloat(token) === parseInt(token, 10), + type: "number" + }; + } + if (token.match(/^@@\d+@@$/g)) { + return { + value: stringArgumentPlaceholders[token].replace('\\"', '"'), + type: "string" + }; + } + return { + value: token, + type: "identifier" + }; +} +function getAttributes(tokens, stringArgumentPlaceholders) { + const attributes = []; + const attributesFound = []; + let attributeFactory = AttributeFactories[(tokens[0] || "").toUpperCase()]; + while (attributeFactory) { + if (attributesFound.indexOf(tokens[0].toUpperCase()) !== -1) { + throw new Error(`duplicate attribute '${tokens[0].toUpperCase()}' found for node`); + } + attributesFound.push(tokens.shift().toUpperCase()); + const attributeArguments = getArguments(tokens, stringArgumentPlaceholders); + if (attributeArguments.length === 0 || attributeArguments[0].type !== "identifier") { + throw new Error("expected agent function name identifier argument for attribute"); + } + const attributeFunctionName = attributeArguments.shift(); + attributeArguments.filter((arg) => arg.type === "identifier").forEach((arg) => { + throw new Error( + "invalid attribute argument value '" + arg.value + "', must be string, number, boolean or null" + ); + }); + attributes.push(attributeFactory(attributeFunctionName.value, attributeArguments)); + attributeFactory = AttributeFactories[(tokens[0] || "").toUpperCase()]; + } + return attributes; +} +function substituteStringLiterals(definition) { + const placeholders = {}; + const processedDefinition = definition.replace(/\"(\\.|[^"\\])*\"/g, (match) => { + var strippedMatch = match.substring(1, match.length - 1); + var placeholder = Object.keys(placeholders).find((key) => placeholders[key] === strippedMatch); + if (!placeholder) { + placeholder = `@@${Object.keys(placeholders).length}@@`; + placeholders[placeholder] = strippedMatch; + } + return placeholder; + }); + return { placeholders, processedDefinition }; +} +function parseTokensFromDefinition(definition) { + definition = definition.replace(/\(/g, " ( "); + definition = definition.replace(/\)/g, " ) "); + definition = definition.replace(/\{/g, " { "); + definition = definition.replace(/\}/g, " } "); + definition = definition.replace(/\]/g, " ] "); + definition = definition.replace(/\[/g, " [ "); + definition = definition.replace(/\,/g, " , "); + return definition.replace(/\s+/g, " ").trim().split(" "); +} + +// src/BehaviourTree.ts +var BehaviourTree = class { + constructor(definition, agent, options = {}) { + this.agent = agent; + this.options = options; + if (typeof definition !== "string") { + throw new Error("the tree definition must be a string"); + } + if (typeof agent !== "object" || agent === null) { + throw new Error("the agent must be defined and not null"); + } + this.rootNode = BehaviourTree._createRootNode(definition); + } + rootNode; + isRunning() { + return this.rootNode.getState() === "mistreevous.running" /* RUNNING */; + } + getState() { + return this.rootNode.getState(); + } + step() { + if (this.rootNode.getState() === "mistreevous.succeeded" /* SUCCEEDED */ || this.rootNode.getState() === "mistreevous.failed" /* FAILED */) { + this.rootNode.reset(); + } + try { + this.rootNode.update(this.agent, this.options); + } catch (exception) { + throw new Error(`error stepping tree: ${exception.message}`); + } + } + reset() { + this.rootNode.reset(); + } + getFlattenedNodeDetails() { + const flattenedTreeNodes = []; + const processNode = (node, parentUid) => { + const guards = node.getAttributes().filter((attribute) => attribute.isGuard()).map((attribute) => attribute.getDetails()); + const callbacks = node.getAttributes().filter((attribute) => !attribute.isGuard()).map((attribute) => attribute.getDetails()); + flattenedTreeNodes.push({ + id: node.getUid(), + type: node.getType(), + caption: node.getName(), + state: node.getState(), + guards, + callbacks, + args: node.getArguments(), + parentId: parentUid + }); + if (!node.isLeafNode()) { + node.getChildren().forEach((child) => processNode(child, node.getUid())); + } + }; + processNode(this.rootNode, null); + return flattenedTreeNodes; + } + static register(name, value) { + if (typeof value === "function") { + Lookup.setFunc(name, value); + } else if (typeof value === "string") { + let rootASTNodes; + try { + rootASTNodes = buildRootASTNodes(value); + } catch (exception) { + throw new Error(`error registering definition: ${exception.message}`); + } + if (rootASTNodes.length != 1 || rootASTNodes[0].name !== null) { + throw new Error("error registering definition: expected a single unnamed root node"); + } + Lookup.setSubtree(name, rootASTNodes[0]); + } else { + throw new Error("unexpected value, expected string definition or function"); + } + } + static unregister(name) { + Lookup.remove(name); + } + static unregisterAll() { + Lookup.empty(); + } + static _createRootNode(definition) { + try { + } catch (exception) { + console.log(exception); + } + try { + const rootASTNodes = buildRootASTNodes(definition); + const mainRootNodeKey = Symbol("__root__"); + const rootNodeMap = {}; + for (const rootASTNode of rootASTNodes) { + rootNodeMap[rootASTNode.name === null ? mainRootNodeKey : rootASTNode.name] = rootASTNode; + } + const rootNode = rootNodeMap[mainRootNodeKey].createNodeInstance( + (name) => rootNodeMap[name] ? rootNodeMap[name] : Lookup.getSubtree(name), + [] + ); + BehaviourTree._applyLeafNodeGuardPaths(rootNode); + return rootNode; + } catch (exception) { + throw new Error(`error parsing tree: ${exception.message}`); + } + } + static _applyLeafNodeGuardPaths(rootNode) { + const nodePaths = []; + const findLeafNodes = (path, node) => { + path = path.concat(node); + if (node.isLeafNode()) { + nodePaths.push(path); + } else { + node.getChildren().forEach((child) => findLeafNodes(path, child)); + } + }; + findLeafNodes([], rootNode); + nodePaths.forEach((path) => { + for (let depth = 0; depth < path.length; depth++) { + const currentNode = path[depth]; + if (currentNode.hasGuardPath()) { + continue; + } + const guardPath = new GuardPath( + path.slice(0, depth + 1).map((node) => ({ node, guards: node.getGuardAttributes() })).filter((details) => details.guards.length > 0) + ); + currentNode.setGuardPath(guardPath); + } + }); + } +}; +// Annotate the CommonJS export names for ESM import in node: +0 && (module.exports = { + BehaviourTree, + State +}); +//# sourceMappingURL=index.js.map diff --git a/dist/index.js.map b/dist/index.js.map new file mode 100644 index 0000000..4f0aab2 --- /dev/null +++ b/dist/index.js.map @@ -0,0 +1,7 @@ +{ + "version": 3, + "sources": ["../node_modules/lotto-draw/dist/Participant.js", "../node_modules/lotto-draw/dist/Utilities.js", "../node_modules/lotto-draw/dist/Lotto.js", "../node_modules/lotto-draw/dist/createLotto.js", "../node_modules/lotto-draw/dist/index.js", "../src/index.ts", "../src/attributes/guards/GuardUnsatisifedException.ts", "../src/attributes/guards/GuardPath.ts", "../src/State.ts", "../src/nodes/Node.ts", "../src/nodes/leaf/Leaf.ts", "../src/Lookup.ts", "../src/nodes/leaf/Action.ts", "../src/nodes/leaf/Condition.ts", "../src/nodes/leaf/Wait.ts", "../src/nodes/decorator/Decorator.ts", "../src/nodes/decorator/Root.ts", "../src/nodes/decorator/Repeat.ts", "../src/nodes/decorator/Retry.ts", "../src/nodes/decorator/Flip.ts", "../src/nodes/decorator/Succeed.ts", "../src/nodes/decorator/Fail.ts", "../src/nodes/composite/Lotto.ts", "../src/nodes/composite/Composite.ts", "../src/nodes/composite/Selector.ts", "../src/nodes/composite/Sequence.ts", "../src/nodes/composite/Parallel.ts", "../src/attributes/Attribute.ts", "../src/attributes/guards/Guard.ts", "../src/attributes/guards/While.ts", "../src/attributes/guards/Until.ts", "../src/attributes/callbacks/Callback.ts", "../src/attributes/callbacks/Entry.ts", "../src/attributes/callbacks/Exit.ts", "../src/attributes/callbacks/Step.ts", "../src/RootAstNodesBuilder.ts", "../src/BehaviourTree.ts"], + "sourcesContent": ["\"use strict\";\r\nObject.defineProperty(exports, \"__esModule\", { value: true });\r\nexports.Participant = void 0;\r\n/**\r\n * A participant that holds a number of tickets.\r\n */\r\nvar Participant = /** @class */ (function () {\r\n /**\r\n * Creates an instance of the Participant class.\r\n * @param participant The actual participant.\r\n * @param tickets The number of tickets held by the participant.\r\n */\r\n function Participant(participant, tickets) {\r\n if (tickets === void 0) { tickets = 1; }\r\n this._participant = participant;\r\n this._tickets = tickets;\r\n }\r\n Object.defineProperty(Participant.prototype, \"participant\", {\r\n /** Gets the actual participant. */\r\n get: function () {\r\n return this._participant;\r\n },\r\n enumerable: false,\r\n configurable: true\r\n });\r\n Object.defineProperty(Participant.prototype, \"tickets\", {\r\n /** Gets or sets the number of tickets held by the participant. */\r\n get: function () {\r\n return this._tickets;\r\n },\r\n set: function (value) {\r\n this._tickets = value;\r\n },\r\n enumerable: false,\r\n configurable: true\r\n });\r\n return Participant;\r\n}());\r\nexports.Participant = Participant;\r\n", "\"use strict\";\r\nObject.defineProperty(exports, \"__esModule\", { value: true });\r\nexports.isNaturalNumber = exports.isNullOrUndefined = void 0;\r\n/**\r\n * Gets whether the value provided is null or undefined.\r\n * @param value The value to check.\r\n * @returns Whether the value provided is null or undefined.\r\n */\r\nfunction isNullOrUndefined(value) {\r\n return value === null || value === undefined;\r\n}\r\nexports.isNullOrUndefined = isNullOrUndefined;\r\n/**\r\n * Gets whether the value provided is a natural number.\r\n * @param value The value to check.\r\n * @returns Whether the value provided is a natural number.\r\n */\r\nfunction isNaturalNumber(value) {\r\n return typeof value === \"number\" && value >= 1 && Math.floor(value) === value;\r\n}\r\nexports.isNaturalNumber = isNaturalNumber;\r\n", "\"use strict\";\r\nObject.defineProperty(exports, \"__esModule\", { value: true });\r\nexports.Lotto = void 0;\r\nvar Participant_1 = require(\"./Participant\");\r\nvar Utilities_1 = require(\"./Utilities\");\r\n/**\r\n * Represents a lotto consisting of a number of pickable ticket-holding participants.\r\n */\r\nvar Lotto = /** @class */ (function () {\r\n /**\r\n * Creates a new instance of Lotto.\r\n * @param customRandom The custom RNG to use in place of Math.random().\r\n */\r\n function Lotto(customRandom) {\r\n /** The array of participants that are holding tickets in the lotto. */\r\n this._participants = [];\r\n this._customRandom = customRandom;\r\n }\r\n /**\r\n * Adds a participant with the specified number of tickets, or adds to the participant ticket count if the participant already holds tickets.\r\n * @param participant The participant to add or to increase the ticket count for if they already hold tickets.\r\n * @param tickets The number of tickets, defaults to 1.\r\n * @returns The Lotto instance.\r\n */\r\n Lotto.prototype.add = function (participant, tickets) {\r\n if (tickets === void 0) { tickets = 1; }\r\n // Check that we have a valid ticket count.\r\n if (!(0, Utilities_1.isNaturalNumber)(tickets)) {\r\n throw new Error(\"tickets value must be a natural number\");\r\n }\r\n // Check whether this participant has already been added.\r\n var existingParticipant = this._participants.find(function (part) { return part.participant === participant; });\r\n if (existingParticipant) {\r\n // The participant has already been added to the lotto so just add to their ticket count.\r\n existingParticipant.tickets += tickets;\r\n }\r\n else {\r\n // The participant is not part of the lotto so we should add them.\r\n this._participants.push(new Participant_1.Participant(participant, tickets));\r\n }\r\n return this;\r\n };\r\n /**\r\n * Removes the specified number of tickets for the given participant from the draw, or all tickets if a ticket number is not defined.\r\n * @param participant The participant to remove tickets for.\r\n * @param tickets The number of tickets to remove, or undefined if all tickets are to be removed.\r\n * @returns The Lotto instance.\r\n */\r\n Lotto.prototype.remove = function (participant, tickets) {\r\n // Attempt to get the existing participant.\r\n var existingParticipant = this._participants.find(function (part) { return part.participant === participant; });\r\n // There is nothing to do if the specified participant isn't even part of the lotto.\r\n if (!existingParticipant) {\r\n return this;\r\n }\r\n // Check whether a tickets value was given.\r\n if (tickets !== undefined) {\r\n // Check that we have a valid ticket count.\r\n if (!(0, Utilities_1.isNaturalNumber)(tickets)) {\r\n throw new Error(\"tickets value must be a natural number\");\r\n }\r\n existingParticipant.tickets -= tickets;\r\n // If the participant no longer holds any tickets then they should be removed.\r\n if (existingParticipant.tickets < 1) {\r\n this._participants = this._participants.filter(function (part) { return part !== existingParticipant; });\r\n }\r\n }\r\n else {\r\n // We are removing all tickets for the participant so just remove them from the lotto.\r\n this._participants = this._participants.filter(function (part) { return part !== existingParticipant; });\r\n }\r\n return this;\r\n };\r\n /**\r\n * Draw a winning ticket and return the participant that holds the ticket.\r\n * @param options The draw options.\r\n * @returns The participant that holds the winning ticket.\r\n */\r\n Lotto.prototype.draw = function (options) {\r\n if (options === void 0) { options = {}; }\r\n // If we have no participants then just return null.\r\n if (this._participants.length === 0) {\r\n return null;\r\n }\r\n var redrawable = (0, Utilities_1.isNullOrUndefined)(options.redrawable) ? true : options.redrawable;\r\n var pickable = [];\r\n this._participants.forEach(function (_a) {\r\n var participant = _a.participant, tickets = _a.tickets;\r\n for (var ticketCount = 0; ticketCount < tickets; ticketCount++) {\r\n pickable.push(participant);\r\n }\r\n });\r\n var random;\r\n // We need a random floating-point number between 0 (inclusive) and 1 to scale up to pick our winner.\r\n // If a custom random function exists then we should use that or fall back to Math.random().\r\n if (this._customRandom) {\r\n // Call our custom random function to get a random floating-point number.\r\n random = this._customRandom();\r\n // Verify that the result of calling our custom random function is a number between 0 (inclusive) and 1.\r\n if (typeof random !== \"number\" || random < 0 || random >= 1) {\r\n throw new Error(\"the 'random' function provided did not return a number between 0 (inclusive) and 1\");\r\n }\r\n }\r\n else {\r\n // No custom random function was defined so just use good ol' Math.random().\r\n random = Math.random();\r\n }\r\n // Pick a winning participant.\r\n var winner = pickable[Math.floor(random * pickable.length)];\r\n // If the ticket isn't redrawable then we should remove a ticket from the winning participants ticket count.\r\n if (!redrawable) {\r\n this.remove(winner, 1);\r\n }\r\n // Return the winning participant.\r\n return winner;\r\n };\r\n /**\r\n * Draws multiple winning tickets and return an array of the participants that hold the winning tickets.\r\n * @param tickets The number of winning tickets to draw.\r\n * @param options The draw multiple options.\r\n * @returns An array of the participants that hold the winning tickets.\r\n */\r\n Lotto.prototype.drawMultiple = function (tickets, options) {\r\n if (options === void 0) { options = {}; }\r\n var uniqueResults = (0, Utilities_1.isNullOrUndefined)(options.unique) ? false : options.unique;\r\n // Handle cases where the user has asked for zero tickets (no idea why they would do this be we should trust them).\r\n if (tickets === 0) {\r\n return [];\r\n }\r\n // Now that we know out tickets value is not zero we should check that it is a valid natural number.\r\n if (!(0, Utilities_1.isNaturalNumber)(tickets)) {\r\n throw new Error(\"tickets value must be a natural number\");\r\n }\r\n var result = [];\r\n // Keep drawing tickets until we either reach the number of required tickets or we simply run out of tickets to draw.\r\n // We can run out of tickets to draw if 'options.redrawable' is explicity 'false' or we just had no participants when 'drawMultiple' was called.\r\n while (result.length < tickets && this._participants.length > 0) {\r\n result.push(this.draw(options));\r\n }\r\n // If the 'unique' draw option is set then we need to remove duplicates from the result list.\r\n if (uniqueResults) {\r\n // Create an array to store our unique results.\r\n var unique = [];\r\n // Iterate over all of our participants (with potential duplicates) and populate our array of unique values.\r\n for (var _i = 0, result_1 = result; _i < result_1.length; _i++) {\r\n var participant = result_1[_i];\r\n if (unique.indexOf(participant) === -1) {\r\n unique.push(participant);\r\n }\r\n }\r\n result = unique;\r\n }\r\n return result;\r\n };\r\n return Lotto;\r\n}());\r\nexports.Lotto = Lotto;\r\n", "\"use strict\";\r\nObject.defineProperty(exports, \"__esModule\", { value: true });\r\nexports.createLotto = void 0;\r\nvar Lotto_1 = require(\"./Lotto\");\r\n/**\r\n * A function that creates and returns a Lotto instance.\r\n * @param participantsOrOptions An array of initial participants or options relating to the creation of a Lotto instance.\r\n * @returns A new Lotto instance.\r\n */\r\nfunction createLotto(participantsOrOptions) {\r\n // If no initial participants or lotto options were provided as an argument then we can just return a new lotto instance now.\r\n if (!participantsOrOptions) {\r\n return new Lotto_1.Lotto();\r\n }\r\n // Check whether we were provided with an array of initial participants or a lotto options object.\r\n if (Array.isArray(participantsOrOptions)) {\r\n // We are dealing with a pre-defined array of participants.\r\n var participants = participantsOrOptions;\r\n var lotto_1 = new Lotto_1.Lotto();\r\n // If the lotto participants have been defined upfront then we will need to add them all to our lotto instance now.\r\n participants.forEach(function (_a) {\r\n var participant = _a[0], tokens = _a[1];\r\n return lotto_1.add(participant, tokens);\r\n });\r\n // Return the Lotto instance.\r\n return lotto_1;\r\n }\r\n else {\r\n // We are dealing with some lotto options.\r\n var random = participantsOrOptions.random, participants = participantsOrOptions.participants;\r\n // Create a Lotto instance passing the custom RNG function to use in place of Math.random() (which could be undefined).\r\n var lotto_2 = new Lotto_1.Lotto(random);\r\n // If the lotto participants have been defined upfront as part of the options then we will need to add them all to our lotto instance now.\r\n if (participants) {\r\n participants.forEach(function (_a) {\r\n var participant = _a[0], tokens = _a[1];\r\n return lotto_2.add(participant, tokens);\r\n });\r\n }\r\n // Return the Lotto instance.\r\n return lotto_2;\r\n }\r\n}\r\nexports.createLotto = createLotto;\r\n", "\"use strict\";\r\nObject.defineProperty(exports, \"__esModule\", { value: true });\r\nvar createLotto_1 = require(\"./createLotto\");\r\nexports.default = createLotto_1.createLotto;\r\n", "import { BehaviourTree, FlattenedTreeNode } from \"./BehaviourTree\";\nimport State from \"./State\";\n\nexport { BehaviourTree, State };\nexport type { FlattenedTreeNode };\n", "import Node from \"../../nodes/Node\";\n\n/**\n * An exception thrown when evaluating node guard path conditions and a conditions fails.\n */\nexport default class GuardUnsatisifedException extends Error {\n /**\n * @param source The node at which a guard condition failed.\n */\n constructor(private source: Node) {\n super(\"A guard path condition has failed\");\n }\n\n /**\n * Gets whether the specified node is the node at which a guard condition failed.\n * @param node The node to check against the source node.\n * @returns Whether the specified node is the node at which a guard condition failed.\n */\n isSourceNode = (node: Node) => node === this.source;\n}\n", "import { Agent } from \"../../Agent\";\nimport Guard from \"./Guard\";\nimport Node from \"../../nodes/Node\";\nimport GuardUnsatisifedException from \"./GuardUnsatisifedException\";\n\nexport type GuardPathPart = {\n node: Node;\n guards: Guard[];\n};\n\n/**\n * Represents a path of node guards along a root-to-leaf tree path.\n */\nexport default class GuardPath {\n /**\n * @param nodes An array of objects defining a node instance -> guard link, ordered by node depth.\n */\n constructor(private nodes: GuardPathPart[]) {}\n\n /**\n * Evaluate guard conditions for all guards in the tree path, moving outwards from the root.\n * @param agent The agent, required for guard evaluation.\n * @returns An evaluation results object.\n */\n evaluate = (agent: Agent) => {\n // We need to evaluate guard conditions for nodes up the tree, moving outwards from the root.\n for (const details of this.nodes) {\n // There can be multiple guards per node.\n for (const guard of details.guards) {\n // Check whether the guard condition passes, and throw an exception if not.\n if (!guard.isSatisfied(agent)) {\n throw new GuardUnsatisifedException(details.node);\n }\n }\n }\n };\n}\n", "/**\n * Enumeration of node state types.\n */\nexport enum State {\n READY = \"mistreevous.ready\",\n RUNNING = \"mistreevous.running\",\n SUCCEEDED = \"mistreevous.succeeded\",\n FAILED = \"mistreevous.failed\"\n}\n\nexport { State as default };\n\nexport type CompleteState = State.SUCCEEDED | State.FAILED;\nexport type AnyState = State.READY | State.RUNNING | CompleteState;\n", "import { Agent } from \"../Agent\";\nimport Attribute from \"../attributes/Attribute\";\nimport Entry from \"../attributes/callbacks/Entry\";\nimport Exit from \"../attributes/callbacks/Exit\";\nimport Step from \"../attributes/callbacks/Step\";\nimport Guard from \"../attributes/guards/Guard\";\nimport GuardPath from \"../attributes/guards/GuardPath\";\nimport GuardUnsatisifedException from \"../attributes/guards/GuardUnsatisifedException\";\nimport { BehaviourTreeOptions } from \"../BehaviourTreeOptions\";\nimport { AnyArgument } from \"../RootAstNodesBuilder\";\nimport State, { AnyState } from \"../State\";\nimport Leaf from \"./leaf/Leaf\";\n\n/**\n * A base node.\n */\nexport default abstract class Node {\n /**\n * The node uid.\n */\n private readonly uid: string = createNodeUid();\n /**\n * The node state.\n */\n private state: AnyState = State.READY;\n /**\n * The guard path to evaluate as part of a node update.\n */\n private guardPath: GuardPath | undefined;\n\n /**\n * @param type The node type.\n * @param attributes The node attributes.\n * @param args The node argument definitions.\n */\n constructor(private type: string, private attributes: Attribute[], private args: AnyArgument[]) {}\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected abstract onUpdate(agent: Agent, options: BehaviourTreeOptions): void;\n\n /**\n * Gets the name of the node.\n */\n public abstract getName(): string;\n\n /**\n * Gets whether this node is a leaf node.\n */\n public abstract isLeafNode: () => this is Leaf;\n\n /**\n * Gets/Sets the state of the node.\n */\n getState = (): AnyState => this.state;\n setState = (value: AnyState): void => {\n this.state = value;\n };\n\n /**\n * Gets the unique id of the node.\n */\n getUid = () => this.uid;\n\n /**\n * Gets the type of the node.\n */\n getType = () => this.type;\n\n /**\n * Gets the node attributes.\n */\n getAttributes = () => this.attributes;\n\n /**\n * Gets the node arguments.\n */\n getArguments = () => this.args;\n\n /**\n * Gets the node attribute with the specified type, or null if it does not exist.\n */\n getAttribute(type: \"entry\" | \"ENTRY\"): Entry;\n getAttribute(type: \"exit\" | \"EXIT\"): Exit;\n getAttribute(type: \"step\" | \"STEP\"): Step;\n getAttribute(type: string): Attribute {\n return (\n this.getAttributes().filter((decorator) => decorator.getType().toUpperCase() === type.toUpperCase())[0] ||\n null\n );\n }\n\n /**\n * Gets the node attributes.\n */\n getGuardAttributes = (): Guard[] => this.getAttributes().filter((decorator) => decorator.isGuard()) as Guard[];\n\n /**\n * Sets the guard path to evaluate as part of a node update.\n */\n setGuardPath = (value: GuardPath) => (this.guardPath = value);\n\n /**\n * Gets whether a guard path is assigned to this node.\n */\n hasGuardPath = () => !!this.guardPath;\n\n /**\n * Gets whether this node is in the specified state.\n * @param value The value to compare to the node state.\n */\n public is(value: AnyState): boolean {\n return this.state === value;\n }\n\n /**\n * Reset the state of the node.\n */\n public reset(): void {\n this.setState(State.READY);\n }\n\n /**\n * Abort the running of this node.\n * @param agent The agent.\n */\n public abort(agent: Agent): void {\n // There is nothing to do if this node is not in the running state.\n if (!this.is(State.RUNNING)) {\n return;\n }\n\n // Reset the state of this node.\n this.reset();\n\n this.getAttribute(\"exit\")?.callAgentFunction(agent, false, true);\n }\n\n /**\n * Update the node.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n * @returns The result of the update.\n */\n public update(agent: Agent, options: BehaviourTreeOptions): void {\n // If this node is already in a 'SUCCEEDED' or 'FAILED' state then there is nothing to do.\n if (this.is(State.SUCCEEDED) || this.is(State.FAILED)) {\n return;\n }\n\n try {\n // Evaluate all of the guard path conditions for the current tree path.\n this.guardPath!.evaluate(agent);\n\n // If this node is in the READY state then call the ENTRY for this node if it exists.\n if (this.is(State.READY)) {\n this.getAttribute(\"entry\")?.callAgentFunction(agent);\n }\n\n this.getAttribute(\"step\")?.callAgentFunction(agent);\n\n // Do the actual update.\n this.onUpdate(agent, options);\n\n // If this node is now in a 'SUCCEEDED' or 'FAILED' state then call the EXIT for this node if it exists.\n if (this.is(State.SUCCEEDED) || this.is(State.FAILED)) {\n this.getAttribute(\"exit\")?.callAgentFunction(agent, this.is(State.SUCCEEDED), false);\n }\n } catch (error) {\n // If the error is a GuardUnsatisfiedException then we need to determine if this node is the source.\n if (error instanceof GuardUnsatisifedException && error.isSourceNode(this)) {\n // Abort the current node.\n this.abort(agent);\n\n // Any node that is the source of an abort will be a failed node.\n this.setState(State.FAILED);\n } else {\n throw error;\n }\n }\n }\n}\n\n/**\n * Create a randomly generated node uid.\n * @returns A randomly generated node uid.\n */\nfunction createNodeUid(): string {\n var S4 = function () {\n return (((1 + Math.random()) * 0x10000) | 0).toString(16).substring(1);\n };\n return S4() + S4() + \"-\" + S4() + \"-\" + S4() + \"-\" + S4() + \"-\" + S4() + S4() + S4();\n}\n", "import Node from \"../Node\";\n\n/**\n * A leaf node.\n */\nexport default abstract class Leaf extends Node {\n /**\n * Gets whether this node is a leaf node.\n */\n isLeafNode = () => true;\n}\n", "import { ActionResult, Agent, ExitFunctionArg, FunctionArg, GlobalFunction } from \"./Agent\";\nimport { AnyArgument, RootAstNode } from \"./RootAstNodesBuilder\";\n\n// Exit callbacks receive their own special type of argument.\n// There's probably stricter ways to represent this but it feels overly complex right now.\ntype ExitResultArg = { value: ExitFunctionArg };\nexport type AnyExitArgument = AnyArgument | ExitResultArg;\n\nexport type InvokerFunction = (args: AnyExitArgument[]) => ActionResult;\n\n/**\n * A singleton used to store and lookup registered functions and subtrees.\n */\nexport default class Lookup {\n /**\n * The object holding any registered functions keyed on function name.\n */\n private static functionTable: { [key: string]: GlobalFunction } = {};\n /**\n * The object holding any registered sub-trees keyed on tree name.\n */\n private static subtreeTable: { [key: string]: RootAstNode } = {};\n\n /**\n * Gets the function with the specified name.\n * @param name The name of the function.\n * @returns The function with the specified name.\n */\n public static getFunc(name: string): GlobalFunction {\n return this.functionTable[name];\n }\n\n /**\n * Sets the function with the specified name for later lookup.\n * @param name The name of the function.\n * @param func The function.\n */\n public static setFunc(name: string, func: GlobalFunction): void {\n this.functionTable[name] = func;\n }\n\n /**\n * Gets the function invoker for the specified agent and function name.\n * If a function with the specified name exists on the agent object then it will\n * be returned, otherwise we will then check the registered functions for a match.\n * @param agent The agent instance that this behaviour tree is modelling behaviour for.\n * @param name The function name.\n * @returns The function invoker for the specified agent and function name.\n */\n static getFuncInvoker(agent: Agent, name: string): InvokerFunction | null {\n // Check whether the agent contains the specified function.\n const foundOnAgent = agent[name];\n if (foundOnAgent && typeof foundOnAgent === \"function\") {\n return (args: AnyExitArgument[]): boolean | ActionResult =>\n foundOnAgent.apply(\n agent,\n args.map((arg) => arg.value)\n );\n }\n\n // The agent does not contain the specified function but it may have been registered at some point.\n if (this.functionTable[name] && typeof this.functionTable[name] === \"function\") {\n return (args: AnyExitArgument[]) => this.functionTable[name](agent, ...args.map((arg) => arg.value));\n }\n\n // We have no function to invoke.\n return null;\n }\n\n /**\n * Gets the subtree with the specified name.\n * @param name The name of the subtree.\n * @returns The subtree with the specified name.\n */\n static getSubtree(name: string): RootAstNode {\n return this.subtreeTable[name];\n }\n\n /**\n * Sets the subtree with the specified name for later lookup.\n * @param name The name of the subtree.\n * @param subtree The subtree.\n */\n static setSubtree(name: string, subtree: RootAstNode) {\n this.subtreeTable[name] = subtree;\n }\n\n /**\n * Removes the registered function or subtree with the specified name.\n * @param name The name of the registered function or subtree.\n */\n static remove(name: string) {\n delete this.functionTable[name];\n delete this.subtreeTable[name];\n }\n\n /**\n * Remove all registered functions and subtrees.\n */\n static empty() {\n this.functionTable = {};\n this.subtreeTable = {};\n }\n}\n", "import Leaf from \"./Leaf\";\nimport State, { CompleteState } from \"../../State\";\nimport Lookup from \"../../Lookup\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { AnyArgument } from \"../../RootAstNodesBuilder\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * An Action leaf node.\n * This represents an immediate or ongoing state of behaviour.\n */\nexport default class Action extends Leaf {\n /**\n * @param attributes The node attributes.\n * @param actionName The action name.\n * @param actionArguments The array of action argument definitions.\n */\n constructor(attributes: Attribute[], private actionName: string, private actionArguments: AnyArgument[]) {\n super(\"action\", attributes, actionArguments);\n }\n\n /**\n * Whether there is a pending update promise.\n */\n private isUsingUpdatePromise = false;\n\n /**\n * The finished state result of an update promise.\n */\n private updatePromiseStateResult: CompleteState | null = null;\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // If the result of this action depends on an update promise then there is nothing to do until\n // it resolves, unless there has been a value set as a result of the update promise resolving.\n if (this.isUsingUpdatePromise) {\n // Check whether the update promise has resolved with a state value.\n if (this.updatePromiseStateResult) {\n // Set the state of this node to match the state returned by the promise.\n this.setState(this.updatePromiseStateResult);\n }\n\n return;\n }\n\n // Attempt to get the invoker for the action function.\n const actionFuncInvoker = Lookup.getFuncInvoker(agent, this.actionName);\n\n // The action function should be defined.\n if (actionFuncInvoker === null) {\n throw new Error(\n `cannot update action node as the action '${this.actionName}' function is not defined on the agent and has not been registered`\n );\n }\n\n // Call the action function, the result of which may be:\n // - The finished state of this action node.\n // - A promise to return a finished node state.\n // - Undefined if the node should remain in the running state.\n const updateResult = actionFuncInvoker(this.actionArguments) as CompleteState | Promise;\n\n if (updateResult instanceof Promise) {\n updateResult.then(\n (result) => {\n // If 'isUpdatePromisePending' is null then the promise was cleared as it was resolving, probably via an abort of reset.\n if (!this.isUsingUpdatePromise) {\n return;\n }\n\n // Check to make sure the result is a valid finished state.\n if (result !== State.SUCCEEDED && result !== State.FAILED) {\n throw new Error(\n \"action node promise resolved with an invalid value, expected a State.SUCCEEDED or State.FAILED value to be returned\"\n );\n }\n\n // Set pending update promise state result to be processed on next update.\n this.updatePromiseStateResult = result;\n },\n (reason) => {\n // If 'isUpdatePromisePending' is null then the promise was cleared as it was resolving, probably via an abort of reset.\n if (!this.isUsingUpdatePromise) {\n return;\n }\n\n // Just throw whatever was returned as the rejection argument.\n throw new Error(reason);\n }\n );\n\n // This node will be in the 'RUNNING' state until the update promise resolves.\n this.setState(State.RUNNING);\n\n // We are now waiting for the promise returned by the use to resolve before we know what state this node is in.\n this.isUsingUpdatePromise = true;\n } else {\n // Validate the returned value.\n this.validateUpdateResult(updateResult);\n\n // Set the state of this node, this may be undefined, which just means that the node is still in the 'RUNNING' state.\n this.setState(updateResult || State.RUNNING);\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => this.actionName;\n\n /**\n * Reset the state of the node.\n */\n reset = () => {\n // Reset the state of this node.\n this.setState(State.READY);\n\n // There is no longer an update promise that we care about.\n this.isUsingUpdatePromise = false;\n this.updatePromiseStateResult = null;\n };\n\n /**\n * Validate the result of an update function call.\n * @param result The result of an update function call.\n */\n private validateUpdateResult = (result: CompleteState | boolean) => {\n switch (result) {\n case State.SUCCEEDED:\n case State.FAILED:\n case undefined:\n return;\n default:\n throw new Error(\n `action '${this.actionName}' 'onUpdate' returned an invalid response, expected an optional State.SUCCEEDED or State.FAILED value to be returned`\n );\n }\n };\n}\n", "import Leaf from \"./Leaf\";\nimport State from \"../../State\";\nimport Lookup from \"../../Lookup\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { AnyArgument } from \"../../RootAstNodesBuilder\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A Condition leaf node.\n * This will succeed or fail immediately based on an agent predicate, without moving to the 'RUNNING' state.\n */\nexport default class Condition extends Leaf {\n /**\n * @param attributes The node attributes.\n * @param conditionName The name of the condition function.\n * @param conditionArguments The array of condition argument definitions.\n */\n constructor(attributes: Attribute[], private conditionName: string, private conditionArguments: AnyArgument[]) {\n super(\"condition\", attributes, conditionArguments);\n }\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // Attempt to get the invoker for the condition function.\n const conditionFuncInvoker = Lookup.getFuncInvoker(agent, this.conditionName);\n\n // The condition function should be defined.\n if (conditionFuncInvoker === null) {\n throw new Error(\n `cannot update condition node as the condition '${this.conditionName}' function is not defined on the agent and has not been registered`\n );\n }\n\n // Call the condition function to determine the state of this node.\n this.setState(!!conditionFuncInvoker(this.conditionArguments) ? State.SUCCEEDED : State.FAILED);\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => this.conditionName;\n}\n", "import Leaf from \"./Leaf\";\nimport State from \"../../State\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { Agent } from \"../../Agent\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A WAIT node.\n * The state of this node will change to SUCCEEDED after a duration of time\n */\nexport default class Wait extends Leaf {\n /**\n * @param attributes The node attributes.\n * @param duration The duration that this node will wait to succeed in milliseconds.\n * @param durationMin The minimum possible duration in milliseconds that this node will wait to succeed.\n * @param durationMax The maximum possible duration in milliseconds that this node will wait to succeed.\n */\n constructor(\n attributes: Attribute[],\n private duration: number | null,\n private durationMin: number | null,\n private durationMax: number | null\n ) {\n super(\"wait\", attributes, []);\n }\n\n /**\n * The time in milliseconds at which this node was first updated.\n */\n private initialUpdateTime: number = 0;\n\n /**\n * The total duration in milliseconds that this node will be waiting for.\n */\n private totalDuration: number | null = null;\n\n /**\n * The duration in milliseconds that this node has been waiting for.\n */\n private waitedDuration: number = 0;\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // If this node is in the READY state then we need to set the initial update time.\n if (this.is(State.READY)) {\n // Set the initial update time.\n this.initialUpdateTime = new Date().getTime();\n\n // Set the initial waited duration.\n this.waitedDuration = 0;\n\n // Are we dealing with an explicit duration or will we be randomly picking a duration between the min and max duration.\n if (this.duration !== null) {\n this.totalDuration = this.duration;\n } else if (this.durationMin !== null && this.durationMax !== null) {\n // We will be picking a random duration between a min and max duration, if the optional 'random' behaviour tree\n // function option is defined then we will be using that, otherwise we will fall back to using Math.random.\n const random = typeof options.random === \"function\" ? options.random : Math.random;\n\n // Pick a random duration between a min and max duration.\n this.totalDuration = Math.floor(\n random() * (this.durationMax - this.durationMin + 1) + this.durationMin\n );\n } else {\n this.totalDuration = null;\n }\n\n // The node is now running until we finish waiting.\n this.setState(State.RUNNING);\n }\n\n // If we have no total duration then this wait node will wait indefinitely until it is aborted.\n if (this.totalDuration === null) {\n return;\n }\n\n // If we have a 'getDeltaTime' function defined as part of our options then we will use it to figure out how long we have waited for.\n if (typeof options.getDeltaTime === \"function\") {\n // Get the delta time.\n const deltaTime = options.getDeltaTime();\n\n // Our delta time must be a valid number and cannot be NaN.\n if (typeof deltaTime !== \"number\" || isNaN(deltaTime)) {\n throw new Error(\"The delta time must be a valid number and not NaN.\");\n }\n\n // Update the amount of time that this node has been waiting for based on the delta time.\n this.waitedDuration += deltaTime * 1000;\n } else {\n // We are not using a delta time, so we will just work out hom much time has passed since the first update.\n this.waitedDuration = new Date().getTime() - this.initialUpdateTime;\n }\n\n // Have we waited long enough?\n if (this.waitedDuration >= this.totalDuration) {\n // We have finished waiting!\n this.setState(State.SUCCEEDED);\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => {\n if (this.duration !== null) {\n return `WAIT ${this.duration}ms`;\n } else if (this.durationMin !== null && this.durationMax !== null) {\n return `WAIT ${this.durationMin}ms-${this.durationMax}ms`;\n } else {\n return \"WAIT\";\n }\n };\n}\n", "import Node from \"../Node\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\n\n/**\n * A decorator node that wraps a single child node.\n */\nexport default abstract class Decorator extends Node {\n /**\n * @param type The node type.\n * @param attributes The node attributes.\n * @param child The child node.\n */\n constructor(type: string, attributes: Attribute[], protected child: Node) {\n super(type, attributes, []);\n }\n\n /**\n * Gets whether this node is a leaf node.\n */\n isLeafNode = () => false;\n\n /**\n * Gets the children of this node.\n */\n getChildren = () => [this.child];\n\n /**\n * Reset the state of the node.\n */\n reset = () => {\n // Reset the state of this node.\n this.setState(State.READY);\n\n // Reset the state of the child node.\n this.child.reset();\n };\n\n /**\n * Abort the running of this node.\n * @param agent The agent.\n */\n abort = (agent: Agent) => {\n // There is nothing to do if this node is not in the running state.\n if (!this.is(State.RUNNING)) {\n return;\n }\n\n // Abort the child node.\n this.child.abort(agent);\n\n // Reset the state of this node.\n this.reset();\n\n this.getAttribute(\"exit\")?.callAgentFunction(agent, false, true);\n };\n}\n", "import Node from \"../Node\";\nimport Decorator from \"./Decorator\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A Root node.\n * The root node will have a single child.\n */\nexport default class Root extends Decorator {\n /**\n * @param attributes The node attributes.\n * @param child The child node.\n */\n constructor(attributes: Attribute[], child: Node) {\n super(\"root\", attributes, child);\n }\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // If the child has never been updated or is running then we will need to update it now.\n if (this.child.getState() === State.READY || this.child.getState() === State.RUNNING) {\n // Update the child of this node.\n this.child.update(agent, options);\n }\n\n // The state of the root node is the state of its child.\n this.setState(this.child.getState());\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => \"ROOT\";\n}\n", "import Node from \"../Node\";\nimport Decorator from \"./Decorator\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A REPEAT node.\n * The node has a single child which can have:\n * -- A number of iterations for which to repeat the child node.\n * -- An infinite repeat loop if neither an iteration count or a condition function is defined.\n * The REPEAT node will stop and have a 'FAILED' state if its child is ever in a 'FAILED' state after an update.\n * The REPEAT node will attempt to move on to the next iteration if its child is ever in a 'SUCCEEDED' state.\n */\nexport default class Repeat extends Decorator {\n /**\n * @param attributes The node attributes.\n * @param iterations The number of iterations to repeat the child node.\n * @param iterationsMin The minimum possible number of iterations to repeat the child node.\n * @param iterationsMax The maximum possible number of iterations to repeat the child node.\n * @param child The child node.\n */\n constructor(\n attributes: Attribute[],\n private iterations: number | null,\n private iterationsMin: number | null,\n private iterationsMax: number | null,\n child: Node\n ) {\n super(\"repeat\", attributes, child);\n }\n\n /**\n * The number of target iterations to make.\n */\n private targetIterationCount: number | null = null;\n\n /**\n * The current iteration count.\n */\n private currentIterationCount: number = 0;\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // If this node is in the READY state then we need to reset the child and the target iteration count.\n if (this.is(State.READY)) {\n // Reset the child node.\n this.child.reset();\n\n // Reset the current iteration count.\n this.currentIterationCount = 0;\n\n // Set the target iteration count.\n this.setTargetIterationCount(options);\n }\n\n // Do a check to see if we can iterate. If we can then this node will move into the 'RUNNING' state.\n // If we cannot iterate then we have hit our target iteration count, which means that the node has succeeded.\n if (this.canIterate()) {\n // This node is in the running state and can do its initial iteration.\n this.setState(State.RUNNING);\n\n // We may have already completed an iteration, meaning that the child node will be in the SUCCEEDED state.\n // If this is the case then we will have to reset the child node now.\n if (this.child.getState() === State.SUCCEEDED) {\n this.child.reset();\n }\n\n // Update the child of this node.\n this.child.update(agent, options);\n\n // If the child moved into the FAILED state when we updated it then there is nothing left to do and this node has also failed.\n // If it has moved into the SUCCEEDED state then we have completed the current iteration.\n if (this.child.getState() === State.FAILED) {\n // The child has failed, meaning that this node has failed.\n this.setState(State.FAILED);\n\n return;\n } else if (this.child.getState() === State.SUCCEEDED) {\n // We have completed an iteration.\n this.currentIterationCount += 1;\n }\n } else {\n // This node is in the 'SUCCEEDED' state as we cannot iterate any more.\n this.setState(State.SUCCEEDED);\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => {\n if (this.iterations !== null) {\n return `REPEAT ${this.iterations}x`;\n } else if (this.iterationsMin !== null && this.iterationsMax !== null) {\n return `REPEAT ${this.iterationsMin}x-${this.iterationsMax}x`;\n } else {\n return \"REPEAT\";\n }\n };\n\n /**\n * Reset the state of the node.\n */\n reset = () => {\n // Reset the state of this node.\n this.setState(State.READY);\n\n // Reset the current iteration count.\n this.currentIterationCount = 0;\n\n // Reset the child node.\n this.child.reset();\n };\n\n /**\n * Gets whether an iteration can be made.\n * @returns Whether an iteration can be made.\n */\n private canIterate = () => {\n if (this.targetIterationCount !== null) {\n // We can iterate as long as we have not reached our target iteration count.\n return this.currentIterationCount < this.targetIterationCount;\n }\n\n // If neither an iteration count or a condition function were defined then we can iterate indefinitely.\n return true;\n };\n\n /**\n * Sets the target iteration count.\n * @param options The behaviour tree options object.\n */\n private setTargetIterationCount = (options: BehaviourTreeOptions) => {\n // Are we dealing with an explicit iteration count or will we be randomly picking a iteration count between the min and max iteration count.\n if (this.iterations !== null) {\n this.targetIterationCount = this.iterations;\n } else if (this.iterationsMin !== null && this.iterationsMax !== null) {\n // We will be picking a random iteration count between a min and max iteration count, if the optional 'random'\n // behaviour tree function option is defined then we will be using that, otherwise we will fall back to using Math.random.\n const random = typeof options.random === \"function\" ? options.random : Math.random;\n\n // Pick a random iteration count between a min and max iteration count.\n this.targetIterationCount = Math.floor(\n random() * (this.iterationsMax - this.iterationsMin + 1) + this.iterationsMin\n );\n } else {\n this.targetIterationCount = null;\n }\n };\n}\n", "import Node from \"../Node\";\nimport Decorator from \"./Decorator\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A RETRY node.\n * The node has a single child which can have:\n * -- A number of iterations for which to repeat the child node.\n * -- An infinite repeat loop if neither an iteration count or a condition function is defined.\n * The RETRY node will stop and have a 'SUCCEEDED' state if its child is ever in a 'SUCCEEDED' state after an update.\n * The RETRY node will attempt to move on to the next iteration if its child is ever in a 'FAILED' state.\n */\nexport default class Retry extends Decorator {\n /**\n * @param attributes The node attributes.\n * @param attempts The number of attempts to retry the child node.\n * @param attemptsMin The minimum possible number of attempts to retry the child node.\n * @param attemptsMax The maximum possible number of attempts to retry the child node.\n * @param child The child node.\n */\n constructor(\n attributes: Attribute[],\n private attempts: number | null,\n private attemptsMin: number | null,\n private attemptsMax: number | null,\n child: Node\n ) {\n super(\"retry\", attributes, child);\n }\n\n /**\n * The number of target attempts to make.\n */\n private targetAttemptCount: number | null = null;\n\n /**\n * The current attempt count.\n */\n private currentAttemptCount: number = 0;\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // If this node is in the READY state then we need to reset the child and the target attempt count.\n if (this.is(State.READY)) {\n // Reset the child node.\n this.child.reset();\n\n // Reset the current attempt count.\n this.currentAttemptCount = 0;\n\n // Set the target attempt count.\n this.setTargetAttemptCount(options);\n }\n\n // Do a check to see if we can attempt. If we can then this node will move into the 'RUNNING' state.\n // If we cannot attempt then we have hit our target attempt count, which means that the node has succeeded.\n if (this.canAttempt()) {\n // This node is in the running state and can do its initial attempt.\n this.setState(State.RUNNING);\n\n // We may have already completed an attempt, meaning that the child node will be in the FAILED state.\n // If this is the case then we will have to reset the child node now.\n if (this.child.getState() === State.FAILED) {\n this.child.reset();\n }\n\n // Update the child of this node.\n this.child.update(agent, options);\n\n // If the child moved into the SUCCEEDED state when we updated it then there is nothing left to do and this node has also succeeded.\n // If it has moved into the FAILED state then we have completed the current attempt.\n if (this.child.getState() === State.SUCCEEDED) {\n // The child has succeeded, meaning that this node has succeeded.\n this.setState(State.SUCCEEDED);\n\n return;\n } else if (this.child.getState() === State.FAILED) {\n // We have completed an attempt.\n this.currentAttemptCount += 1;\n }\n } else {\n // This node is in the 'FAILED' state as we cannot iterate any more.\n this.setState(State.FAILED);\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => {\n if (this.attempts !== null) {\n return `RETRY ${this.attempts}x`;\n } else if (this.attemptsMin !== null && this.attemptsMax !== null) {\n return `RETRY ${this.attemptsMin}x-${this.attemptsMax}x`;\n } else {\n return \"RETRY\";\n }\n };\n\n /**\n * Reset the state of the node.\n */\n reset = () => {\n // Reset the state of this node.\n this.setState(State.READY);\n\n // Reset the current attempt count.\n this.currentAttemptCount = 0;\n\n // Reset the child node.\n this.child.reset();\n };\n\n /**\n * Gets whether an attempt can be made.\n * @returns Whether an attempt can be made.\n */\n canAttempt = () => {\n if (this.targetAttemptCount !== null) {\n // We can attempt as long as we have not reached our target attempt count.\n return this.currentAttemptCount < this.targetAttemptCount;\n }\n\n // If neither an attempt count or a condition function were defined then we can attempt indefinitely.\n return true;\n };\n\n /**\n * Sets the target attempt count.\n * @param options The behaviour tree options object.\n */\n setTargetAttemptCount = (options: BehaviourTreeOptions) => {\n // Are we dealing with an explicit attempt count or will we be randomly picking an attempt count between the min and max attempt count.\n if (this.attempts !== null) {\n this.targetAttemptCount = this.attempts;\n } else if (this.attemptsMin !== null && this.attemptsMax !== null) {\n // We will be picking a random attempt count between a min and max attempt count, if the optional 'random'\n // behaviour tree function option is defined then we will be using that, otherwise we will fall back to using Math.random.\n const random = typeof options.random === \"function\" ? options.random : Math.random;\n\n // Pick a random attempt count between a min and max attempt count.\n this.targetAttemptCount = Math.floor(\n random() * (this.attemptsMax - this.attemptsMin + 1) + this.attemptsMin\n );\n } else {\n this.targetAttemptCount = null;\n }\n };\n}\n", "import Decorator from \"./Decorator\";\nimport State from \"../../State\";\nimport Node from \"../Node\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A Flip node.\n * This node wraps a single child and will flip the state of the child state.\n */\nexport default class Flip extends Decorator {\n /**\n * @param attributes The node attributes.\n * @param child The child node.\n */\n constructor(attributes: Attribute[], child: Node) {\n super(\"flip\", attributes, child);\n }\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // If the child has never been updated or is running then we will need to update it now.\n if (this.child.getState() === State.READY || this.child.getState() === State.RUNNING) {\n this.child.update(agent, options);\n }\n\n // The state of this node will depend in the state of its child.\n switch (this.child.getState()) {\n case State.RUNNING:\n this.setState(State.RUNNING);\n break;\n\n case State.SUCCEEDED:\n this.setState(State.FAILED);\n break;\n\n case State.FAILED:\n this.setState(State.SUCCEEDED);\n break;\n\n default:\n this.setState(State.READY);\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => \"FLIP\";\n}\n", "import Node from \"../Node\";\nimport Decorator from \"./Decorator\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A Succeed node.\n * This node wraps a single child and will always move to the 'SUCCEEDED' state when the child moves to a 'SUCCEEDED' or 'FAILED' state.\n */\nexport default class Succeed extends Decorator {\n /**\n * @param attributes The node attributes.\n * @param child The child node.\n */\n constructor(attributes: Attribute[], child: Node) {\n super(\"succeed\", attributes, child);\n }\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // If the child has never been updated or is running then we will need to update it now.\n if (this.child.getState() === State.READY || this.child.getState() === State.RUNNING) {\n this.child.update(agent, options);\n }\n\n // The state of this node will depend in the state of its child.\n switch (this.child.getState()) {\n case State.RUNNING:\n this.setState(State.RUNNING);\n break;\n\n case State.SUCCEEDED:\n case State.FAILED:\n this.setState(State.SUCCEEDED);\n break;\n\n default:\n this.setState(State.READY);\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => \"SUCCEED\";\n}\n", "import Node from \"../Node\";\nimport Decorator from \"./Decorator\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A Fail node.\n * This node wraps a single child and will always move to the 'FAILED' state when the child moves to a 'SUCCEEDED' or 'FAILED' state.\n */\nexport default class Fail extends Decorator {\n /**\n * @param attributes The node attributes.\n * @param child The child node.\n */\n constructor(attributes: Attribute[], child: Node) {\n super(\"fail\", attributes, child);\n }\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // If the child has never been updated or is running then we will need to update it now.\n if (this.child.getState() === State.READY || this.child.getState() === State.RUNNING) {\n this.child.update(agent, options);\n }\n\n // The state of this node will depend in the state of its child.\n switch (this.child.getState()) {\n case State.RUNNING:\n this.setState(State.RUNNING);\n break;\n\n case State.SUCCEEDED:\n case State.FAILED:\n this.setState(State.FAILED);\n break;\n\n default:\n this.setState(State.READY);\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => \"FAIL\";\n}\n", "import createLotto from \"lotto-draw\";\n\nimport Node from \"../Node\";\nimport Composite from \"./Composite\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A LOTTO node.\n * A winning child is picked on the initial update of this node, based on ticket weighting.\n * The state of this node will match the state of the winning child.\n */\nexport default class Lotto extends Composite {\n /**\n * @param attributes The node attributes.\n * @param tickets The child node tickets.\n * @param children The child nodes.\n */\n constructor(attributes: Attribute[], private tickets: number[], children: Node[]) {\n super(\"lotto\", attributes, children);\n }\n\n /**\n * The child node selected to be the active one.\n */\n private selectedChild: Node | undefined;\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // If this node is in the READY state then we need to pick a winning child node.\n if (this.is(State.READY)) {\n // Create a lotto draw with which to randomly pick a child node to become the active one.\n const lottoDraw = createLotto({\n // Hook up the optional 'random' behaviour tree function option to the one used by 'lotto-draw'.\n random: options.random,\n // Pass in each child node as a participant in the lotto draw with their respective ticket count.\n participants: this.children.map((child, index) => [child, this.tickets[index] || 1])\n });\n\n // Randomly pick a child based on ticket weighting, this will become the active child for this composite node.\n this.selectedChild = lottoDraw.draw() || undefined;\n }\n\n // If something went wrong and we don't have an active child then we should throw an error.\n if (!this.selectedChild) {\n throw new Error(\"failed to update lotto node as it has no active child\");\n }\n\n // If the selected child has never been updated or is running then we will need to update it now.\n if (this.selectedChild.getState() === State.READY || this.selectedChild.getState() === State.RUNNING) {\n this.selectedChild.update(agent, options);\n }\n\n // The state of the lotto node is the state of its selected child.\n this.setState(this.selectedChild.getState());\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => (this.tickets.length ? `LOTTO [${this.tickets.join(\",\")}]` : \"LOTTO\");\n}\n", "import Node from \"../Node\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\n\n/**\n * A composite node that wraps child nodes.\n */\nexport default abstract class Composite extends Node {\n /**\n * @param type The node type.\n * @param attributes The node attributes.\n * @param children The child nodes.\n */\n constructor(type: string, attributes: Attribute[], protected children: Node[]) {\n super(type, attributes, []);\n }\n\n /**\n * Gets whether this node is a leaf node.\n */\n isLeafNode = () => false;\n\n /**\n * Gets the children of this node.\n */\n getChildren = () => this.children;\n\n /**\n * Reset the state of the node.\n */\n reset = () => {\n // Reset the state of this node.\n this.setState(State.READY);\n\n // Reset the state of any child nodes.\n this.getChildren().forEach((child) => child.reset());\n };\n\n /**\n * Abort the running of this node.\n * @param agent The agent.\n */\n abort = (agent: Agent) => {\n // There is nothing to do if this node is not in the running state.\n if (!this.is(State.RUNNING)) {\n return;\n }\n\n // Abort any child nodes.\n this.getChildren().forEach((child) => child.abort(agent));\n\n // Reset the state of this node.\n this.reset();\n\n this.getAttribute(\"exit\")?.callAgentFunction(agent, false, true);\n };\n}\n", "import Composite from \"./Composite\";\nimport Node from \"../Node\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A SELECTOR node.\n * The child nodes are executed in sequence until one succeeds or all fail.\n */\nexport default class Selector extends Composite {\n /**\n * @param attributes The node attributes.\n * @param children The child nodes.\n */\n constructor(attributes: Attribute[], protected children: Node[]) {\n super(\"selector\", attributes, children);\n }\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // Iterate over all of the children of this node.\n for (const child of this.children) {\n // If the child has never been updated or is running then we will need to update it now.\n if (child.getState() === State.READY || child.getState() === State.RUNNING) {\n // Update the child of this node.\n child.update(agent, options);\n }\n\n // If the current child has a state of 'SUCCEEDED' then this node is also a 'SUCCEEDED' node.\n if (child.getState() === State.SUCCEEDED) {\n // This node is a 'SUCCEEDED' node.\n this.setState(State.SUCCEEDED);\n\n // There is no need to check the rest of the selector nodes.\n return;\n }\n\n // If the current child has a state of 'FAILED' then we should move on to the next child.\n if (child.getState() === State.FAILED) {\n // Find out if the current child is the last one in the selector.\n // If it is then this sequence node has also failed.\n if (this.children.indexOf(child) === this.children.length - 1) {\n // This node is a 'FAILED' node.\n this.setState(State.FAILED);\n\n // There is no need to check the rest of the selector as we have completed it.\n return;\n } else {\n // The child node failed, try the next one.\n continue;\n }\n }\n\n // The node should be in the 'RUNNING' state.\n if (child.getState() === State.RUNNING) {\n // This node is a 'RUNNING' node.\n this.setState(State.RUNNING);\n\n // There is no need to check the rest of the selector as the current child is still running.\n return;\n }\n\n // The child node was not in an expected state.\n throw new Error(\"child node was not in an expected state.\");\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => \"SELECTOR\";\n}\n", "import Composite from \"./Composite\";\nimport Node from \"../Node\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A SEQUENCE node.\n * The child nodes are executed in sequence until one fails or all succeed.\n */\nexport default class Sequence extends Composite {\n /**\n * @param attributes The node attributes.\n * @param children The child nodes.\n */\n constructor(attributes: Attribute[], protected children: Node[]) {\n super(\"sequence\", attributes, children);\n }\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // Iterate over all of the children of this node.\n for (const child of this.children) {\n // If the child has never been updated or is running then we will need to update it now.\n if (child.getState() === State.READY || child.getState() === State.RUNNING) {\n // Update the child of this node.\n child.update(agent, options);\n }\n\n // If the current child has a state of 'SUCCEEDED' then we should move on to the next child.\n if (child.getState() === State.SUCCEEDED) {\n // Find out if the current child is the last one in the sequence.\n // If it is then this sequence node has also succeeded.\n if (this.children.indexOf(child) === this.children.length - 1) {\n // This node is a 'SUCCEEDED' node.\n this.setState(State.SUCCEEDED);\n\n // There is no need to check the rest of the sequence as we have completed it.\n return;\n } else {\n // The child node succeeded, but we have not finished the sequence yet.\n continue;\n }\n }\n\n // If the current child has a state of 'FAILED' then this node is also a 'FAILED' node.\n if (child.getState() === State.FAILED) {\n // This node is a 'FAILED' node.\n this.setState(State.FAILED);\n\n // There is no need to check the rest of the sequence.\n return;\n }\n\n // The node should be in the 'RUNNING' state.\n if (child.getState() === State.RUNNING) {\n // This node is a 'RUNNING' node.\n this.setState(State.RUNNING);\n\n // There is no need to check the rest of the sequence as the current child is still running.\n return;\n }\n\n // The child node was not in an expected state.\n throw new Error(\"child node was not in an expected state.\");\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => \"SEQUENCE\";\n}\n", "import Composite from \"./Composite\";\nimport State from \"../../State\";\nimport Node from \"../Node\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A PARALLEL node.\n * The child nodes are executed concurrently until one fails or all succeed.\n */\nexport default class Parallel extends Composite {\n /**\n * @param attributes The node attributes.\n * @param children The child nodes.\n */\n constructor(attributes: Attribute[], children: Node[]) {\n super(\"parallel\", attributes, children);\n }\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // Keep a count of the number of succeeded child nodes.\n let succeededCount = 0;\n\n let hasChildFailed = false;\n\n // Iterate over all of the children of this node.\n for (const child of this.children) {\n // If the child has never been updated or is running then we will need to update it now.\n if (child.getState() === State.READY || child.getState() === State.RUNNING) {\n // Update the child of this node.\n child.update(agent, options);\n }\n\n // If the current child has a state of 'SUCCEEDED' then we should move on to the next child.\n if (child.getState() === State.SUCCEEDED) {\n // The child node has succeeded, keep track of this to determine if all children have.\n succeededCount++;\n\n // The child node succeeded, but we have not finished checking every child node yet.\n continue;\n }\n\n // If the current child has a state of 'FAILED' then this node is also a 'FAILED' node.\n if (child.getState() === State.FAILED) {\n hasChildFailed = true;\n\n // There is no need to check the rest of the children.\n break;\n }\n\n // The node should be in the 'RUNNING' state.\n if (child.getState() !== State.RUNNING) {\n // The child node was not in an expected state.\n throw new Error(\"child node was not in an expected state.\");\n }\n }\n\n if (hasChildFailed) {\n // This node is a 'FAILED' node.\n this.setState(State.FAILED);\n\n // Abort every running child.\n for (const child of this.children) {\n if (child.getState() === State.RUNNING) {\n child.abort(agent);\n }\n }\n } else {\n // If all children have succeeded then this node has also succeeded, otherwise it is still running.\n this.setState(succeededCount === this.children.length ? State.SUCCEEDED : State.RUNNING);\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => \"PARALLEL\";\n}\n", "import { AnyArgument } from \"../RootAstNodesBuilder\";\nimport Guard from \"./guards/Guard\";\n\nexport type AttributeDetails = {\n /** The attribute type. */\n type: string;\n\n /** The attribute arguments. */\n args: AnyArgument[];\n};\n\n/**\n * A base node attribute.\n */\nexport default abstract class Attribute {\n /**\n * @param type The node attribute type.\n * @param args The array of attribute argument definitions.\n */\n constructor(protected type: string, protected args: AnyArgument[]) {}\n\n /**\n * Gets the type of the attribute.\n */\n getType = () => this.type;\n\n /**\n * Gets the array of attribute argument definitions.\n */\n getArguments = () => this.args;\n\n /**\n * Gets the attribute details.\n */\n abstract getDetails(): TAttributeDetails;\n\n /**\n * Gets whether this attribute is a guard.\n */\n abstract isGuard: () => this is Guard;\n}\n", "import { Agent } from \"../../Agent\";\nimport { AnyArgument } from \"../../RootAstNodesBuilder\";\nimport Attribute, { AttributeDetails } from \"../Attribute\";\n\nexport type GuardAttributeDetails = {\n /** The name of the condition function that determines whether the guard is satisfied. */\n condition: string;\n} & AttributeDetails;\n\n/**\n * A base node guard attribute.\n */\nexport default abstract class Guard extends Attribute {\n /**\n * @param type The node attribute type.\n * @param args The array of decorator argument definitions.\n * @param condition The name of the condition function that determines whether the guard is satisfied.\n */\n constructor(type: string, args: AnyArgument[], private condition: string) {\n super(type, args);\n }\n\n /**\n * Gets the name of the condition function that determines whether the guard is satisfied.\n */\n getCondition = () => this.condition;\n\n /**\n * Gets whether this attribute is a guard.\n */\n isGuard = () => true;\n\n /**\n * Gets the attribute details.\n */\n getDetails(): GuardAttributeDetails {\n return {\n type: this.getType(),\n args: this.getArguments(),\n condition: this.getCondition()\n };\n }\n\n /**\n * Gets whether the guard is satisfied.\n * @param agent The agent.\n * @returns Whether the guard is satisfied.\n */\n abstract isSatisfied(agent: Agent): boolean;\n}\n", "import Guard from \"./Guard\";\nimport Lookup from \"../../Lookup\";\nimport { Agent } from \"../../Agent\";\nimport { AnyArgument } from \"../../RootAstNodesBuilder\";\n\n/**\n * A WHILE guard which is satisfied as long as the given condition remains true.\n */\nexport default class While extends Guard {\n /**\n * @param condition The name of the condition function that determines whether the guard is satisfied.\n * @param args The array of decorator argument definitions.\n */\n constructor(condition: string, args: AnyArgument[]) {\n super(\"while\", args, condition);\n }\n\n /**\n * Gets whether the guard is satisfied.\n * @param agent The agent.\n * @returns Whether the guard is satisfied.\n */\n isSatisfied = (agent: Agent) => {\n // Attempt to get the invoker for the condition function.\n const conditionFuncInvoker = Lookup.getFuncInvoker(agent, this.getCondition());\n\n // The condition function should be defined.\n if (conditionFuncInvoker === null) {\n throw new Error(\n `cannot evaluate node guard as the condition '${this.getCondition()}' function is not defined on the agent and has not been registered`\n );\n }\n\n // Call the condition function to determine whether this guard is satisfied.\n return !!conditionFuncInvoker(this.args);\n };\n}\n", "import Guard from \"./Guard\";\nimport Lookup from \"../../Lookup\";\nimport { Agent } from \"../../Agent\";\nimport { AnyArgument } from \"../../RootAstNodesBuilder\";\n\n/**\n * An UNTIL guard which is satisfied as long as the given condition remains false.\n */\nexport default class Until extends Guard {\n /**\n * @param condition The name of the condition function that determines whether the guard is satisfied.\n * @param args The array of decorator argument definitions.\n */\n constructor(condition: string, args: AnyArgument[]) {\n super(\"until\", args, condition);\n }\n\n /**\n * Gets whether the guard is satisfied.\n * @param agent The agent.\n * @returns Whether the guard is satisfied.\n */\n isSatisfied = (agent: Agent) => {\n // Attempt to get the invoker for the condition function.\n const conditionFuncInvoker = Lookup.getFuncInvoker(agent, this.getCondition());\n\n // The condition function should be defined.\n if (conditionFuncInvoker === null) {\n throw new Error(\n `cannot evaluate node guard as the condition '${this.getCondition()}' function is not defined on the agent and has not been registered`\n );\n }\n\n // Call the condition function to determine whether this guard is satisfied.\n return !!!conditionFuncInvoker(this.args);\n };\n}\n", "import { Agent } from \"../../Agent\";\nimport { AnyArgument } from \"../../RootAstNodesBuilder\";\nimport Attribute, { AttributeDetails } from \"../Attribute\";\n\nexport type CallbackAttributeDetails = {\n /** The name of the agent function that is called. */\n functionName: string;\n} & AttributeDetails;\n\n/**\n * A base node callback attribute.\n */\nexport default abstract class Callback extends Attribute {\n /**\n * @param type The node attribute type.\n * @param args The array of decorator argument definitions.\n * @param functionName The name of the agent function to call.\n */\n constructor(type: string, args: AnyArgument[], private functionName: string) {\n super(type, args);\n }\n\n /**\n * Gets the name of the agent function to call.\n */\n getFunctionName = () => this.functionName;\n\n /**\n * Gets whether this attribute is a guard.\n */\n isGuard = () => false;\n\n /**\n * Gets the attribute details.\n */\n getDetails(): CallbackAttributeDetails {\n return {\n type: this.getType(),\n args: this.getArguments(),\n functionName: this.getFunctionName()\n };\n }\n\n /**\n * Attempt to call the agent function that this callback refers to.\n * @param agent The agent.\n */\n abstract callAgentFunction: (agent: Agent, isSuccess: boolean, isAborted: boolean) => void;\n}\n", "import Callback from \"./Callback\";\nimport Lookup from \"../../Lookup\";\nimport { Agent } from \"../../Agent\";\nimport { AnyArgument } from \"../../RootAstNodesBuilder\";\n\n/**\n * An ENTRY callback which defines an agent function to call when the associated node is updated and moves out of running state.\n */\nexport default class Entry extends Callback {\n /**\n * @param functionName The name of the agent function to call.\n * @param args The array of callback argument definitions.\n */\n constructor(functionName: string, args: AnyArgument[]) {\n super(\"entry\", args, functionName);\n }\n\n /**\n * Attempt to call the agent function that this callback refers to.\n * @param agent The agent.\n */\n callAgentFunction = (agent: Agent) => {\n // Attempt to get the invoker for the callback function.\n const callbackFuncInvoker = Lookup.getFuncInvoker(agent, this.getFunctionName());\n\n // The callback function should be defined.\n if (callbackFuncInvoker === null) {\n throw new Error(\n `cannot call entry function '${this.getFunctionName()}' as is not defined on the agent and has not been registered`\n );\n }\n\n // Call the callback function.\n callbackFuncInvoker(this.args);\n };\n}\n", "import Callback from \"./Callback\";\nimport Lookup, { AnyExitArgument } from \"../../Lookup\";\nimport { Agent } from \"../../Agent\";\nimport { AnyArgument } from \"../../RootAstNodesBuilder\";\n\n/**\n * An EXIT callback which defines an agent function to call when the associated node is updated and moves to a finished state or is aborted.\n */\nexport default class Exit extends Callback {\n /**\n * @param functionName The name of the agent function to call.\n * @param args The array of callback argument definitions.\n */\n constructor(functionName: string, args: AnyArgument[]) {\n super(\"exit\", args, functionName);\n }\n\n /**\n * Attempt to call the agent function that this callback refers to.\n * @param agent The agent.\n * @param isSuccess Whether the decorated node was left with a success state.\n * @param isAborted Whether the decorated node was aborted.\n */\n callAgentFunction = (agent: Agent, isSuccess: boolean, isAborted: boolean) => {\n // Attempt to get the invoker for the callback function.\n const callbackFuncInvoker = Lookup.getFuncInvoker(agent, this.getFunctionName());\n\n // The callback function should be defined.\n if (callbackFuncInvoker === null) {\n throw new Error(\n `cannot call exit function '${this.getFunctionName()}' as is not defined on the agent and has not been registered`\n );\n }\n\n // Call the callback function\n callbackFuncInvoker([{ value: { succeeded: isSuccess, aborted: isAborted } }, ...this.args]);\n };\n}\n", "import Callback from \"./Callback\";\nimport Lookup from \"../../Lookup\";\nimport { Agent } from \"../../Agent\";\nimport { AnyArgument } from \"../../RootAstNodesBuilder\";\n\n/**\n * A STEP callback which defines an agent function to call when the associated node is updated.\n */\nexport default class Step extends Callback {\n /**\n * @param functionName The name of the agent function to call.\n * @param args The array of callback argument definitions.\n */\n constructor(functionName: string, args: AnyArgument[]) {\n super(\"step\", args, functionName);\n }\n\n /**\n * Attempt to call the agent function that this callback refers to.\n * @param agent The agent.\n */\n callAgentFunction = (agent: Agent) => {\n // Attempt to get the invoker for the callback function.\n const callbackFuncInvoker = Lookup.getFuncInvoker(agent, this.getFunctionName());\n\n // The callback function should be defined.\n if (callbackFuncInvoker === null) {\n throw new Error(\n `cannot call step function '${this.getFunctionName()}' as is not defined on the agent and has not been registered`\n );\n }\n\n // Call the callback function.\n callbackFuncInvoker(this.args);\n };\n}\n", "import Action from \"./nodes/leaf/Action\";\nimport Condition from \"./nodes/leaf/Condition\";\nimport Wait from \"./nodes/leaf/Wait\";\nimport Root from \"./nodes/decorator/Root\";\nimport Repeat from \"./nodes/decorator/Repeat\";\nimport Retry from \"./nodes/decorator/Retry\";\nimport Flip from \"./nodes/decorator/Flip\";\nimport Succeed from \"./nodes/decorator/Succeed\";\nimport Fail from \"./nodes/decorator/Fail\";\nimport Lotto from \"./nodes/composite/Lotto\";\nimport Selector from \"./nodes/composite/Selector\";\nimport Sequence from \"./nodes/composite/Sequence\";\nimport Parallel from \"./nodes/composite/Parallel\";\nimport Node from \"./nodes/Node\";\nimport While from \"./attributes/guards/While\";\nimport Until from \"./attributes/guards/Until\";\nimport Entry from \"./attributes/callbacks/Entry\";\nimport Exit from \"./attributes/callbacks/Exit\";\nimport Step from \"./attributes/callbacks/Step\";\nimport Callback from \"./attributes/callbacks/Callback\";\nimport Guard from \"./attributes/guards/Guard\";\nimport Attribute from \"./attributes/Attribute\";\nimport Composite from \"./nodes/composite/Composite\";\nimport Decorator from \"./nodes/decorator/Decorator\";\nimport Leaf from \"./nodes/leaf/Leaf\";\n\nexport type Argument = {\n value: T;\n type: string; // Used for validation.\n};\ntype NullArgument = Argument & {\n type: \"null\";\n};\ntype BooleanArgument = Argument & {\n type: \"boolean\";\n};\ntype NumberArgument = Argument & {\n type: \"number\";\n isInteger: boolean; // Used for validation.\n};\ntype StringPlaceholderArgument = Argument & {\n type: \"string\";\n};\ntype IdentifierArgument = Argument & {\n type: \"identifier\";\n};\nexport type AnyArgument =\n | NullArgument\n | BooleanArgument\n | NumberArgument\n | StringPlaceholderArgument\n | IdentifierArgument;\n\n/**\n * The node attribute factories.\n */\nconst AttributeFactories: {\n [key: string]: (functionName: string, attributeArguments: AnyArgument[]) => Callback | Guard;\n} = {\n WHILE: (condition: string, attributeArguments: AnyArgument[]) => new While(condition, attributeArguments),\n UNTIL: (condition: string, attributeArguments: AnyArgument[]) => new Until(condition, attributeArguments),\n ENTRY: (functionName: string, attributeArguments: AnyArgument[]) => new Entry(functionName, attributeArguments),\n EXIT: (functionName: string, attributeArguments: AnyArgument[]) => new Exit(functionName, attributeArguments),\n STEP: (functionName: string, attributeArguments: AnyArgument[]) => new Step(functionName, attributeArguments)\n};\n\ntype Validatable = {\n children?: AstNode[];\n validate: (depth: number) => void;\n};\n\ntype NodeInstanceCreator = (\n namedRootNodeProvider: (name: string) => RootAstNode,\n visitedBranches: string[]\n) => T;\n\nexport type AstNode = Validatable & {\n type: string;\n createNodeInstance: NodeInstanceCreator;\n};\n\nexport type LeafAstNode = AstNode & {\n type: \"action\" | \"condition\" | \"wait\";\n attributes: Attribute[];\n};\n\nexport type CompositeAstNode = AstNode & {\n type: \"lotto\" | \"parallel\" | \"selector\" | \"sequence\";\n attributes: Attribute[];\n children: AstNode[];\n};\n\nexport type DecoratorAstNode = AstNode & {\n type: \"fail\" | \"flip\" | \"repeat\" | \"retry\" | \"root\" | \"succeed\";\n attributes: Attribute[];\n children: AstNode[];\n};\n\nexport type BranchAstNode = AstNode & {\n type: \"branch\";\n branchName: \"\" | string;\n};\n\nexport type LottoAstNode = CompositeAstNode & {\n type: \"lotto\";\n tickets: number[];\n};\n\nexport type RootAstNode = DecoratorAstNode & {\n type: \"root\";\n name: null | string;\n};\n\nexport type RepeatAstNode = DecoratorAstNode & {\n type: \"repeat\";\n iterations: number | null;\n iterationsMin: number | null;\n iterationsMax: number | null;\n};\n\nexport type RetryAstNode = DecoratorAstNode & {\n type: \"retry\";\n attempts: number | null;\n attemptsMin: number | null;\n attemptsMax: number | null;\n};\n\nexport type ActionAstNode = LeafAstNode & {\n type: \"action\";\n actionName: string;\n actionArguments: AnyArgument[];\n};\n\nexport type ConditionAstNode = LeafAstNode & {\n type: \"condition\";\n conditionName: string;\n conditionArguments: AnyArgument[];\n};\n\nexport type WaitAstNode = LeafAstNode & {\n type: \"wait\";\n duration: number | null;\n durationMin: number | null;\n durationMax: number | null;\n};\n\nexport type AnyAstNode =\n | BranchAstNode\n | CompositeAstNode\n | LottoAstNode\n | DecoratorAstNode\n | RootAstNode\n | RepeatAstNode\n | RetryAstNode\n | LeafAstNode\n | ActionAstNode\n | ConditionAstNode\n | WaitAstNode;\n\n/**\n * The AST node factories.\n */\nconst ASTNodeFactories = {\n ROOT: (): RootAstNode => ({\n type: \"root\",\n attributes: [],\n name: null,\n children: [],\n validate(depth: number) {\n // A root node cannot be the child of another node.\n if (depth > 1) {\n throw new Error(\"a root node cannot be the child of another node\");\n }\n\n // A root node must have a single child node.\n if (this.children.length !== 1) {\n throw new Error(\"a root node must have a single child\");\n }\n },\n createNodeInstance(namedRootNodeProvider, visitedBranches) {\n return new Root(\n this.attributes,\n this.children![0].createNodeInstance(namedRootNodeProvider, visitedBranches.slice())\n );\n }\n }),\n BRANCH: (): BranchAstNode => ({\n type: \"branch\",\n branchName: \"\",\n validate() {},\n createNodeInstance(namedRootNodeProvider, visitedBranches) {\n // Try to find the root node with a matching branch name.\n const targetRootNode = namedRootNodeProvider(this.branchName);\n\n // If we have already visited this branch then we have a circular dependency.\n if (visitedBranches.indexOf(this.branchName) !== -1) {\n throw new Error(`circular dependency found in branch node references for branch '${this.branchName}'`);\n }\n\n // If we have a target root node, then the node instance we want will be the first and only child of the referenced root node.\n if (targetRootNode) {\n return targetRootNode\n .createNodeInstance(namedRootNodeProvider, visitedBranches.concat(this.branchName))\n .getChildren()[0];\n } else {\n throw new Error(`branch references root node '${this.branchName}' which has not been defined`);\n }\n }\n }),\n SELECTOR: (): CompositeAstNode => ({\n type: \"selector\",\n attributes: [],\n children: [],\n validate() {\n // A selector node must have at least a single node.\n if (this.children.length < 1) {\n throw new Error(\"a selector node must have at least a single child\");\n }\n },\n createNodeInstance(namedRootNodeProvider, visitedBranches) {\n return new Selector(\n this.attributes,\n this.children.map((child) => child.createNodeInstance(namedRootNodeProvider, visitedBranches.slice()))\n );\n }\n }),\n SEQUENCE: (): CompositeAstNode => ({\n type: \"sequence\",\n attributes: [],\n children: [],\n validate() {\n // A sequence node must have at least a single node.\n if (this.children.length < 1) {\n throw new Error(\"a sequence node must have at least a single child\");\n }\n },\n createNodeInstance(namedRootNodeProvider, visitedBranches) {\n return new Sequence(\n this.attributes,\n this.children.map((child) => child.createNodeInstance(namedRootNodeProvider, visitedBranches.slice()))\n );\n }\n }),\n PARALLEL: (): CompositeAstNode => ({\n type: \"parallel\",\n attributes: [],\n children: [],\n validate() {\n // A parallel node must have at least a single node.\n if (this.children.length < 1) {\n throw new Error(\"a parallel node must have at least a single child\");\n }\n },\n createNodeInstance(namedRootNodeProvider, visitedBranches) {\n return new Parallel(\n this.attributes,\n this.children.map((child) => child.createNodeInstance(namedRootNodeProvider, visitedBranches.slice()))\n );\n }\n }),\n LOTTO: (): LottoAstNode => ({\n type: \"lotto\",\n attributes: [],\n children: [],\n tickets: [],\n validate() {\n // A lotto node must have at least a single node.\n if (this.children!.length < 1) {\n throw new Error(\"a lotto node must have at least a single child\");\n }\n },\n createNodeInstance(namedRootNodeProvider, visitedBranches) {\n return new Lotto(\n this.attributes,\n this.tickets!,\n this.children!.map((child) => child.createNodeInstance(namedRootNodeProvider, visitedBranches.slice()))\n );\n }\n }),\n REPEAT: (): RepeatAstNode => ({\n type: \"repeat\",\n attributes: [],\n iterations: null,\n iterationsMin: null,\n iterationsMax: null,\n children: [],\n validate() {\n // A repeat node must have a single node.\n if (this.children!.length !== 1) {\n throw new Error(\"a repeat node must have a single child\");\n }\n\n if (this.iterations !== null) {\n // A repeat node must have a positive number of iterations if defined.\n if (this.iterations < 0) {\n throw new Error(\"a repeat node must have a positive number of iterations if defined\");\n }\n } else if (this.iterationsMin !== null && this.iterationsMax !== null) {\n // A repeat node must have a positive min and max iteration count if they are defined.\n if (this.iterationsMin < 0 || this.iterationsMax < 0) {\n throw new Error(\n \"a repeat node must have a positive minimum and maximum iteration count if defined\"\n );\n }\n\n // A repeat node must not have an minimum iteration count that exceeds the maximum iteration count.\n if (this.iterationsMin > this.iterationsMax) {\n throw new Error(\n \"a repeat node must not have a minimum iteration count that exceeds the maximum iteration count\"\n );\n }\n } else {\n // If we have no explicit iteration count or a minimum and maximum iteration count set then we are dealing with a repeat node that iterates indefinitely.\n }\n },\n createNodeInstance(namedRootNodeProvider, visitedBranches) {\n return new Repeat(\n this.attributes,\n this.iterations,\n this.iterationsMin,\n this.iterationsMax,\n this.children![0].createNodeInstance(namedRootNodeProvider, visitedBranches.slice())\n );\n }\n }),\n RETRY: (): RetryAstNode => ({\n type: \"retry\",\n attributes: [],\n attempts: null,\n attemptsMin: null,\n attemptsMax: null,\n children: [],\n validate() {\n // A retry node must have a single node.\n if (this.children!.length !== 1) {\n throw new Error(\"a retry node must have a single child\");\n }\n\n if (this.attempts !== null) {\n // A retry node must have a positive number of attempts if defined.\n if (this.attempts < 0) {\n throw new Error(\"a retry node must have a positive number of attempts if defined\");\n }\n } else if (this.attemptsMin !== null && this.attemptsMax !== null) {\n // A retry node must have a positive min and max attempts count if they are defined.\n if (this.attemptsMin < 0 || this.attemptsMax < 0) {\n throw new Error(\"a retry node must have a positive minimum and maximum attempt count if defined\");\n }\n\n // A retry node must not have a minimum attempt count that exceeds the maximum attempt count.\n if (this.attemptsMin > this.attemptsMax) {\n throw new Error(\n \"a retry node must not have a minimum attempt count that exceeds the maximum attempt count\"\n );\n }\n } else {\n // If we have no explicit attempt count or a minimum and maximum attempt count set then we are dealing with a retry node that attempts indefinitely.\n }\n },\n createNodeInstance(namedRootNodeProvider, visitedBranches) {\n return new Retry(\n this.attributes,\n this.attempts,\n this.attemptsMin,\n this.attemptsMax,\n this.children![0].createNodeInstance(namedRootNodeProvider, visitedBranches.slice())\n );\n }\n }),\n FLIP: (): DecoratorAstNode => ({\n type: \"flip\",\n attributes: [],\n children: [],\n validate() {\n // A flip node must have a single node.\n if (this.children!.length !== 1) {\n throw new Error(\"a flip node must have a single child\");\n }\n },\n createNodeInstance(namedRootNodeProvider, visitedBranches) {\n return new Flip(\n this.attributes,\n this.children![0].createNodeInstance(namedRootNodeProvider, visitedBranches.slice())\n );\n }\n }),\n SUCCEED: (): DecoratorAstNode => ({\n type: \"succeed\",\n attributes: [],\n children: [],\n validate() {\n // A succeed node must have a single node.\n if (this.children!.length !== 1) {\n throw new Error(\"a succeed node must have a single child\");\n }\n },\n createNodeInstance(namedRootNodeProvider, visitedBranches) {\n return new Succeed(\n this.attributes,\n this.children![0].createNodeInstance(namedRootNodeProvider, visitedBranches.slice())\n );\n }\n }),\n FAIL: (): DecoratorAstNode => ({\n type: \"fail\",\n attributes: [],\n children: [],\n validate() {\n // A fail node must have a single node.\n if (this.children!.length !== 1) {\n throw new Error(\"a fail node must have a single child\");\n }\n },\n createNodeInstance(namedRootNodeProvider, visitedBranches) {\n return new Fail(\n this.attributes,\n this.children![0].createNodeInstance(namedRootNodeProvider, visitedBranches.slice())\n );\n }\n }),\n WAIT: (): WaitAstNode => ({\n type: \"wait\",\n attributes: [],\n duration: null,\n durationMin: null,\n durationMax: null,\n validate() {\n if (this.duration !== null) {\n // If an explict duration was defined then it must be a positive number.\n if (this.duration < 0) {\n throw new Error(\"a wait node must have a positive duration\");\n }\n } else if (this.durationMin !== null && this.durationMax !== null) {\n // A wait node must have a positive min and max duration.\n if (this.durationMin < 0 || this.durationMax < 0) {\n throw new Error(\"a wait node must have a positive minimum and maximum duration\");\n }\n\n // A wait node must not have a minimum duration that exceeds the maximum duration.\n if (this.durationMin > this.durationMax) {\n throw new Error(\"a wait node must not have a minimum duration that exceeds the maximum duration\");\n }\n } else {\n // If we have no explicit duration or duration bounds set then we are dealing with a wait node that waits indefinitely.\n }\n },\n createNodeInstance() {\n return new Wait(this.attributes, this.duration, this.durationMin, this.durationMax);\n }\n }),\n ACTION: (): ActionAstNode => ({\n type: \"action\",\n attributes: [],\n actionName: \"\",\n actionArguments: [],\n validate() {},\n createNodeInstance() {\n return new Action(this.attributes, this.actionName!, this.actionArguments!);\n }\n }),\n CONDITION: (): ConditionAstNode => ({\n type: \"condition\",\n attributes: [],\n conditionName: \"\",\n conditionArguments: [],\n validate() {},\n createNodeInstance() {\n return new Condition(this.attributes, this.conditionName!, this.conditionArguments!);\n }\n })\n};\n\ntype OtherAstNodes = AstNode[];\n\n/**\n * Create an array of root AST nodes based on the given definition.\n * @param definition The definition to parse the AST nodes from.\n * @returns The base definition AST nodes.\n */\nexport default function buildRootASTNodes(definition: string): RootAstNode[] {\n // Swap out any node/attribute argument string literals with a placeholder and get a mapping of placeholders to original values as well as the processed definition.\n const { placeholders, processedDefinition } = substituteStringLiterals(definition);\n\n // Convert the processed definition (with substituted string literals) into an array of raw tokens.\n const tokens = parseTokensFromDefinition(processedDefinition);\n\n // There must be at least 3 tokens for the tree definition to be valid. 'ROOT', '{' and '}'.\n if (tokens.length < 3) {\n throw new Error(\"invalid token count\");\n }\n\n // We should have a matching number of '{' and '}' tokens. If not, then there are scopes that have not been properly closed.\n if (tokens.filter((token) => token === \"{\").length !== tokens.filter((token) => token === \"}\").length) {\n throw new Error(\"scope character mismatch\");\n }\n\n // Create a stack of node children arrays, starting with a definition scope.\n const stack: [RootAstNode[], ...OtherAstNodes[]] = [[]];\n const rootScope = stack[0];\n\n // We should keep processing the raw tokens until we run out of them.\n while (tokens.length) {\n // Grab the next token.\n const token = tokens.shift();\n\n const currentScope = stack[stack.length - 1] as OtherAstNodes;\n\n // How we create the next AST token depends on the current raw token value.\n switch (token!.toUpperCase()) {\n case \"ROOT\": {\n // Create a ROOT AST node.\n const node = ASTNodeFactories.ROOT();\n\n // Push the ROOT node into the current scope.\n rootScope.push(node);\n\n // We may have a root node name defined as an argument.\n if (tokens[0] === \"[\") {\n const rootArguments = getArguments(tokens, placeholders);\n\n // We should have only a single argument that is not an empty string for a root node, which is the root name identifier.\n if (rootArguments.length === 1 && rootArguments[0].type === \"identifier\") {\n // The root name will be the first and only node argument.\n node.name = rootArguments[0].value as string;\n } else {\n throw new Error(\"expected single root name argument\");\n }\n }\n\n // Try to pick any attributes off of the token stack.\n node.attributes = getAttributes(tokens, placeholders);\n\n popAndCheck(tokens, \"{\");\n\n // The new scope is that of the new ROOT nodes children.\n stack.push(node.children!);\n break;\n }\n\n case \"BRANCH\": {\n // Create a BRANCH AST node.\n const node = ASTNodeFactories.BRANCH();\n\n // Push the BRANCH node into the current scope.\n currentScope.push(node);\n\n // We must have arguments defined, as we require a branch name argument.\n if (tokens[0] !== \"[\") {\n throw new Error(\"expected single branch name argument\");\n }\n\n // The branch name will be defined as a node argument.\n const branchArguments = getArguments(tokens, placeholders);\n\n // We should have only a single identifer argument for a branch node, which is the branch name.\n if (branchArguments.length === 1 && branchArguments[0].type === \"identifier\") {\n // The branch name will be the first and only node argument.\n node.branchName = branchArguments[0].value as string;\n } else {\n throw new Error(\"expected single branch name argument\");\n }\n break;\n }\n\n case \"SELECTOR\": {\n // Create a SELECTOR AST node.\n const node = ASTNodeFactories.SELECTOR();\n\n // Push the SELECTOR node into the current scope.\n currentScope.push(node);\n\n // Try to pick any attributes off of the token stack.\n node.attributes = getAttributes(tokens, placeholders);\n\n popAndCheck(tokens, \"{\");\n\n // The new scope is that of the new SELECTOR nodes children.\n stack.push(node.children!);\n break;\n }\n\n case \"SEQUENCE\": {\n // Create a SEQUENCE AST node.\n const node = ASTNodeFactories.SEQUENCE();\n\n // Push the SEQUENCE node into the current scope.\n currentScope.push(node);\n\n // Try to pick any attributes off of the token stack.\n node.attributes = getAttributes(tokens, placeholders);\n\n popAndCheck(tokens, \"{\");\n\n // The new scope is that of the new SEQUENCE nodes children.\n stack.push(node.children!);\n break;\n }\n\n case \"PARALLEL\": {\n // Create a PARALLEL AST node.\n const node = ASTNodeFactories.PARALLEL();\n\n // Push the PARALLEL node into the current scope.\n currentScope.push(node);\n\n // Try to pick any attributes off of the token stack.\n node.attributes = getAttributes(tokens, placeholders);\n\n popAndCheck(tokens, \"{\");\n\n // The new scope is that of the new PARALLEL nodes children.\n stack.push(node.children!);\n break;\n }\n\n case \"LOTTO\": {\n // Create a LOTTO AST node.\n const node = ASTNodeFactories.LOTTO();\n\n // Push the LOTTO node into the current scope.\n currentScope.push(node);\n\n // If the next token is a '[' character then some ticket counts have been defined as arguments.\n if (tokens[0] === \"[\") {\n // Get the ticket count arguments, each argument must be a number.\n node.tickets = getArguments(\n tokens,\n placeholders,\n (arg) => arg.type === \"number\" && !!arg.isInteger,\n \"lotto node ticket counts must be integer values\"\n ).map((argument) => argument.value as number);\n }\n\n // Try to pick any attributes off of the token stack.\n node.attributes = getAttributes(tokens, placeholders);\n\n popAndCheck(tokens, \"{\");\n\n // The new scope is that of the new LOTTO nodes children.\n stack.push(node.children!);\n break;\n }\n\n case \"CONDITION\": {\n // Create a CONDITION AST node.\n const node = ASTNodeFactories.CONDITION();\n\n // Push the CONDITION node into the current scope.\n currentScope.push(node);\n\n // We must have arguments defined, as we require a condition function name argument.\n if (tokens[0] !== \"[\") {\n throw new Error(\"expected condition name identifier argument\");\n }\n\n // Grab the condition node arguments.\n const conditionArguments = getArguments(tokens, placeholders);\n\n // We should have at least a single identifier argument for a condition node, which is the condition function name.\n if (conditionArguments.length && conditionArguments[0].type === \"identifier\") {\n // The condition function name will be the first node argument.\n node.conditionName = conditionArguments.shift()!.value as string;\n } else {\n throw new Error(\"expected condition name identifier argument\");\n }\n\n // Only the first argument should have been an identifier, all following arguments must be string, number, boolean or null.\n conditionArguments\n .filter((arg) => arg.type === \"identifier\")\n .forEach((arg) => {\n throw new Error(\n \"invalid condition node argument value '\" +\n arg.value +\n \"', must be string, number, boolean or null\"\n );\n });\n\n // Any node arguments that follow the condition name identifier will be treated as condition function arguments.\n node.conditionArguments = conditionArguments;\n\n // Try to pick any attributes off of the token stack.\n node.attributes = getAttributes(tokens, placeholders);\n break;\n }\n\n case \"FLIP\": {\n // Create a FLIP AST node.\n const node = ASTNodeFactories.FLIP();\n\n // Push the Flip node into the current scope.\n currentScope.push(node);\n\n // Try to pick any attributes off of the token stack.\n node.attributes = getAttributes(tokens, placeholders);\n\n popAndCheck(tokens, \"{\");\n\n // The new scope is that of the new FLIP nodes children.\n stack.push(node.children!);\n break;\n }\n\n case \"SUCCEED\": {\n // Create a SUCCEED AST node.\n const node = ASTNodeFactories.SUCCEED();\n\n // Push the Succeed node into the current scope.\n currentScope.push(node);\n\n // Try to pick any attributes off of the token stack.\n node.attributes = getAttributes(tokens, placeholders);\n\n popAndCheck(tokens, \"{\");\n\n // The new scope is that of the new Succeed nodes children.\n stack.push(node.children!);\n break;\n }\n\n case \"FAIL\": {\n // Create a FAIL AST node.\n const node = ASTNodeFactories.FAIL();\n\n // Push the Fail node into the current scope.\n currentScope.push(node);\n\n // Try to pick any attributes off of the token stack.\n node.attributes = getAttributes(tokens, placeholders);\n\n popAndCheck(tokens, \"{\");\n\n // The new scope is that of the new Fail nodes children.\n stack.push(node.children!);\n break;\n }\n\n case \"WAIT\": {\n // Create a WAIT AST node.\n const node = ASTNodeFactories.WAIT();\n\n // Push the WAIT node into the current scope.\n currentScope.push(node);\n\n // The arguments of a wait node are optional. We may have:\n // - No node arguments, in which case the wait will be indefinite until it is aborted.\n // - One node argument which will be the explicit duration of the wait.\n // - Two node arguments which define the min and max duration bounds from which a random duration will be picked.\n if (tokens[0] === \"[\") {\n // Get the optional duration and longest duration of the wait.\n const nodeArguments = getArguments(\n tokens,\n placeholders,\n (arg) => arg.type === \"number\" && !!arg.isInteger,\n \"wait node durations must be integer values\"\n ).map((argument) => argument.value);\n\n // We may have:\n // - One node argument which will be the explicit duration of the wait.\n // - Two node arguments which define the min and max duration bounds from which a random duration will be picked.\n // - Too many arguments, which is not valid.\n if (nodeArguments.length === 1) {\n // An explicit duration was defined.\n node.duration = nodeArguments[0] as number;\n } else if (nodeArguments.length === 2) {\n // Min and max duration bounds were defined from which a random duration will be picked.\n node.durationMin = nodeArguments[0] as number;\n node.durationMax = nodeArguments[1] as number;\n } else if (nodeArguments.length > 2) {\n // An incorrect number of durations was defined.\n throw new Error(\"invalid number of wait node duration arguments defined\");\n }\n }\n\n // Try to pick any attributes off of the token stack.\n node.attributes = getAttributes(tokens, placeholders);\n break;\n }\n\n case \"REPEAT\": {\n // Create a REPEAT AST node.\n const node = ASTNodeFactories.REPEAT();\n\n // Push the REPEAT node into the current scope.\n currentScope.push(node);\n\n // The arguments of a repeat node are optional. We may have:\n // - No node arguments, in which case the repeat note will iterate indefinitely.\n // - One node argument which will be the explicit number of iterations to make.\n // - Two node arguments which define the min and max iteration bounds from which a random iteration count will be picked.\n if (tokens[0] === \"[\") {\n // An iteration count has been defined. Get the iteration and potential maximum iteration of the wait.\n const nodeArguments = getArguments(\n tokens,\n placeholders,\n (arg) => arg.type === \"number\" && !!arg.isInteger,\n \"repeat node iteration counts must be integer values\"\n ).map((argument) => argument.value);\n\n // We should have got one or two iteration counts.\n if (nodeArguments.length === 1) {\n // A static iteration count was defined.\n node.iterations = nodeArguments[0] as number;\n } else if (nodeArguments.length === 2) {\n // A minimum and maximum iteration count was defined.\n node.iterationsMin = nodeArguments[0] as number;\n node.iterationsMax = nodeArguments[1] as number;\n } else {\n // An incorrect number of iteration counts was defined.\n throw new Error(\"invalid number of repeat node iteration count arguments defined\");\n }\n }\n\n // Try to pick any attributes off of the token stack.\n node.attributes = getAttributes(tokens, placeholders);\n\n popAndCheck(tokens, \"{\");\n\n // The new scope is that of the new REPEAT nodes children.\n stack.push(node.children!);\n break;\n }\n\n case \"RETRY\": {\n // Create a RETRY AST node.\n const node = ASTNodeFactories.RETRY();\n\n // Push the RETRY node into the current scope.\n currentScope.push(node);\n\n // The arguments of a retry node are optional. We may have:\n // - No node arguments, in which case the retry note will attempt indefinitely.\n // - One node argument which will be the explicit number of attempts to make.\n // - Two node arguments which define the min and max attempt bounds from which a random attempt count will be picked.\n if (tokens[0] === \"[\") {\n // An attempt count has been defined. Get the attempt count and potential maximum attempt count of the wait.\n const nodeArguments = getArguments(\n tokens,\n placeholders,\n (arg) => arg.type === \"number\" && !!arg.isInteger,\n \"retry node attempt counts must be integer values\"\n ).map((argument) => argument.value);\n\n // We should have got one or two attempt counts.\n if (nodeArguments.length === 1) {\n // A static attempt count was defined.\n node.attempts = nodeArguments[0] as number;\n } else if (nodeArguments.length === 2) {\n // A minimum and maximum attempt count was defined.\n node.attemptsMin = nodeArguments[0] as number;\n node.attemptsMax = nodeArguments[1] as number;\n } else {\n // An incorrect number of attempt counts was defined.\n throw new Error(\"invalid number of retry node attempt count arguments defined\");\n }\n }\n\n // Try to pick any attributes off of the token stack.\n node.attributes = getAttributes(tokens, placeholders);\n\n popAndCheck(tokens, \"{\");\n\n // The new scope is that of the new RETRY nodes children.\n stack.push(node.children!);\n break;\n }\n\n case \"ACTION\": {\n // Create a ACTION AST node.\n const node = ASTNodeFactories.ACTION();\n\n // Push the ACTION node into the current scope.\n currentScope.push(node);\n\n // We must have arguments defined, as we require an action name argument.\n if (tokens[0] !== \"[\") {\n throw new Error(\"expected action name identifier argument\");\n }\n\n // The action name will be defined as a node argument.\n const actionArguments = getArguments(tokens, placeholders);\n\n // We should have at least one identifer argument for an action node, which is the action name.\n if (actionArguments.length && actionArguments[0].type === \"identifier\") {\n // The action name will be the first and only node argument.\n node.actionName = actionArguments.shift()!.value as string;\n } else {\n throw new Error(\"expected action name identifier argument\");\n }\n\n // Only the first argument should have been an identifier, all following arguments must be string, number, boolean or null.\n actionArguments\n .filter((arg) => arg.type === \"identifier\")\n .forEach((arg) => {\n throw new Error(\n \"invalid action node argument value '\" +\n arg.value +\n \"', must be string, number, boolean or null\"\n );\n });\n\n // Any node arguments that follow the action name identifier will be treated as action function arguments.\n node.actionArguments = actionArguments;\n\n // Try to pick any attributes off of the token stack.\n node.attributes = getAttributes(tokens, placeholders);\n break;\n }\n\n case \"}\": {\n // The '}' character closes the current scope.\n stack.pop();\n break;\n }\n\n default: {\n throw new Error(`unexpected token '${token}'`);\n }\n }\n }\n\n // A function to recursively validate each of the nodes in the AST.\n const validateASTNode = (node: Validatable, depth: number): void => {\n // Validate the node.\n node.validate(depth);\n\n // Validate each child of the node.\n (node.children || []).forEach((child) => validateASTNode(child, depth + 1));\n };\n\n // Start node validation from the definition root.\n validateASTNode(\n {\n children: stack[0] as RootAstNode[],\n validate(this: { children: RootAstNode[] }) {\n // We must have at least one node defined as the definition scope, which should be a root node.\n if (this.children.length === 0) {\n throw new Error(\"expected root node to have been defined\");\n }\n\n // Each node at the base of the definition scope MUST be a root node.\n for (const definitionLevelNode of this.children) {\n if (definitionLevelNode.type !== \"root\") {\n throw new Error(\"expected root node at base of definition\");\n }\n }\n\n // Exactly one root node must not have a name defined. This will be the main root, others will have to be referenced via branch nodes.\n if (this.children.filter((definitionLevelNode) => definitionLevelNode.name === null).length !== 1) {\n throw new Error(\"expected single unnamed root node at base of definition to act as main root\");\n }\n\n // No two named root nodes can have matching names.\n const rootNodeNames: string[] = [];\n for (const definitionLevelNode of this.children) {\n if (rootNodeNames.indexOf(definitionLevelNode.name!) !== -1) {\n throw new Error(`multiple root nodes found with duplicate name '${definitionLevelNode.name}'`);\n } else {\n rootNodeNames.push(definitionLevelNode.name!);\n }\n }\n }\n },\n 0\n );\n\n // Return the root AST nodes.\n return stack[0];\n}\n\n/**\n * Pop the next raw token off of the stack and throw an error if it wasn't the expected one.\n * @param tokens The array of remaining tokens.\n * @param expected An optional string or array or items, one of which must match the next popped token.\n * @returns The popped token.\n */\nfunction popAndCheck(tokens: string[], expected: string | string[]) {\n // Get and remove the next token.\n const popped = tokens.shift();\n\n // We were expecting another token.\n if (popped === undefined) {\n throw new Error(\"unexpected end of definition\");\n }\n\n // Do we have an expected token/tokens array?\n if (expected !== undefined) {\n // Check whether the popped token matches at least one of our expected items.\n var tokenMatchesExpectation = ([] as string[])\n .concat(expected)\n .some((item) => popped.toUpperCase() === item.toUpperCase());\n\n // Throw an error if the popped token didn't match any of our expected items.\n if (!tokenMatchesExpectation) {\n const expectationString = ([] as string[])\n .concat(expected)\n .map((item) => \"'\" + item + \"'\")\n .join(\" or \");\n\n throw new Error(`unexpected token found. Expected '${expectationString}' but got '${popped}'`);\n }\n }\n\n // Return the popped token.\n return popped;\n}\n\ntype Placeholders = { [key: string]: string };\n\n/**\n * Pull an argument definition list off of the token stack.\n * @param tokens The array of remaining tokens.\n * @param stringArgumentPlaceholders The mapping of string literal node argument placeholders to original values.\n * @param argumentValidator The argument validator function.\n * @param validationFailedMessage The exception message to throw if argument validation fails.\n * @returns The argument definition list.\n */\nfunction getArguments(\n tokens: string[],\n stringArgumentPlaceholders: Placeholders,\n argumentValidator?: (arg: AnyArgument) => boolean,\n validationFailedMessage?: string\n) {\n // Any lists of arguments will always be wrapped in '[]' for node arguments or '()' for attribute arguments.\n // We are looking for a '[' or '(' opener that wraps the argument tokens and the relevant closer.\n const closer = popAndCheck(tokens, [\"[\", \"(\"]) === \"[\" ? \"]\" : \")\";\n\n const argumentListTokens: string[] = [];\n const argumentList: AnyArgument[] = [];\n\n // Grab all tokens between the '[' and ']' or '(' and ')'.\n while (tokens.length && tokens[0] !== closer) {\n // The next token is part of our arguments list.\n argumentListTokens.push(tokens.shift()!);\n }\n\n // Validate the order of the argument tokens. Each token must either be a ',' or a single argument that satisfies the validator.\n argumentListTokens.forEach((token, index) => {\n // Get whether this token should be an actual argument.\n const shouldBeArgumentToken = !(index & 1);\n\n // If the current token should be an actual argument then validate it,otherwise it should be a ',' token.\n if (shouldBeArgumentToken) {\n // Get the argument definition.\n const argumentDefinition = getArgumentDefinition(token!, stringArgumentPlaceholders);\n\n // Try to validate the argument.\n if (argumentValidator && !argumentValidator(argumentDefinition)) {\n throw new Error(validationFailedMessage);\n }\n\n // This is a valid argument!\n argumentList.push(argumentDefinition);\n } else {\n // The current token should be a ',' token.\n if (token !== \",\") {\n throw new Error(`invalid argument list, expected ',' or ']' but got '${token}'`);\n }\n }\n });\n\n // The arguments list should terminate with a ']' or ')' token, depending on the opener.\n popAndCheck(tokens, closer);\n\n // Return the argument list.\n return argumentList;\n}\n\n/**\n * Gets an argument value definition.\n * @param token The argument token.\n * @param stringArgumentPlaceholders The mapping of string literal node argument placeholders to original values.\n * @returns An argument value definition.\n */\nfunction getArgumentDefinition(token: string, stringArgumentPlaceholders: Placeholders): AnyArgument {\n // Check whether the token represents a null value.\n if (token === \"null\") {\n return {\n value: null,\n type: \"null\"\n } as NullArgument;\n }\n\n // Check whether the token represents a boolean value.\n if (token === \"true\" || token === \"false\") {\n return {\n value: token === \"true\",\n type: \"boolean\"\n } as BooleanArgument;\n }\n\n // Check whether the token represents a number value.\n // TODO: Relies on broken isNaN - see MDN.\n // if (!Number.isNaN(token)) {\n if (!isNaN(token as any)) {\n return {\n value: parseFloat(token),\n isInteger: parseFloat(token) === parseInt(token, 10),\n type: \"number\"\n } as NumberArgument;\n }\n\n // Check whether the token is a placeholder (e.g. @@0@@) representing a string literal.\n if (token.match(/^@@\\d+@@$/g)) {\n return {\n value: stringArgumentPlaceholders[token].replace('\\\\\"', '\"'),\n type: \"string\"\n } as StringPlaceholderArgument;\n }\n\n // The only remaining option is that the argument value is an identifier.\n return {\n value: token,\n type: \"identifier\"\n } as IdentifierArgument;\n}\n\n/**\n * Pull any attributes off of the token stack.\n * @param tokens The array of remaining tokens.\n * @param stringArgumentPlaceholders The mapping of string literal node argument placeholders to original values.\n * @returns An array of attributes defined by any directly following tokens.\n */\nfunction getAttributes(tokens: string[], stringArgumentPlaceholders: Placeholders) {\n // Create an array to hold any attributes found.\n const attributes: Attribute[] = [];\n\n // Keep track of names of attribute that we have found on the token stack, as we cannot have duplicates.\n const attributesFound: string[] = [];\n\n // Try to get the attribute factory for the next token.\n let attributeFactory = AttributeFactories[(tokens[0] || \"\").toUpperCase()];\n\n // Pull attribute tokens off of the tokens stack until we have no more.\n while (attributeFactory) {\n // Check to make sure that we have not already created a attribute of this type for this node.\n if (attributesFound.indexOf(tokens[0].toUpperCase()) !== -1) {\n throw new Error(`duplicate attribute '${tokens[0].toUpperCase()}' found for node`);\n }\n\n // Add the current attribute type to our array of found attributes.\n attributesFound.push(tokens.shift()!.toUpperCase());\n\n // Grab any attribute arguments.\n const attributeArguments = getArguments(tokens, stringArgumentPlaceholders);\n\n // The first attribute argument has to be an identifer, this will reference an agent function.\n if (attributeArguments.length === 0 || attributeArguments[0].type !== \"identifier\") {\n throw new Error(\"expected agent function name identifier argument for attribute\");\n }\n\n // Grab the first attribute which is an identifier that will reference an agent function.\n const attributeFunctionName = attributeArguments.shift()! as IdentifierArgument;\n\n // Any remaining attribute arguments must have a type of string, number, boolean or null.\n attributeArguments\n .filter((arg) => arg.type === \"identifier\")\n .forEach((arg) => {\n throw new Error(\n \"invalid attribute argument value '\" + arg.value + \"', must be string, number, boolean or null\"\n );\n });\n\n // Create the attribute and add it to the array of attributes found.\n attributes.push(attributeFactory(attributeFunctionName.value, attributeArguments));\n\n // Try to get the next attribute name token, as there could be multiple.\n attributeFactory = AttributeFactories[(tokens[0] || \"\").toUpperCase()];\n }\n\n return attributes;\n}\n\n/**\n * Swaps out any node/attribute argument string literals with placeholders.\n * @param definition The definition.\n * @returns An object containing a mapping of placeholders to original string values as well as the processed definition string.\n */\nfunction substituteStringLiterals(definition: string): {\n placeholders: { [key: string]: string };\n processedDefinition: string;\n} {\n // Create an object to hold the mapping of placeholders to original string values.\n const placeholders: Placeholders = {};\n\n // Replace any string literals wrapped with double quotes in our definition with placeholders to be processed later.\n const processedDefinition = definition.replace(/\\\"(\\\\.|[^\"\\\\])*\\\"/g, (match) => {\n var strippedMatch = match.substring(1, match.length - 1);\n var placeholder = Object.keys(placeholders).find((key) => placeholders[key] === strippedMatch);\n\n // If we have no existing string literal match then create a new placeholder.\n if (!placeholder) {\n placeholder = `@@${Object.keys(placeholders).length}@@`;\n placeholders[placeholder] = strippedMatch;\n }\n\n return placeholder;\n });\n\n return { placeholders, processedDefinition };\n}\n\n/**\n * Parse the tree definition into an array of raw tokens.\n * @param definition The definition.\n * @returns An array of tokens parsed from the definition.\n */\nfunction parseTokensFromDefinition(definition: string): string[] {\n // Add some space around various important characters so that they can be plucked out easier as individual tokens.\n definition = definition.replace(/\\(/g, \" ( \");\n definition = definition.replace(/\\)/g, \" ) \");\n definition = definition.replace(/\\{/g, \" { \");\n definition = definition.replace(/\\}/g, \" } \");\n definition = definition.replace(/\\]/g, \" ] \");\n definition = definition.replace(/\\[/g, \" [ \");\n definition = definition.replace(/\\,/g, \" , \");\n\n // Split the definition into raw token form and return it.\n return definition.replace(/\\s+/g, \" \").trim().split(\" \");\n}\n", "import GuardPath, { GuardPathPart } from \"./attributes/guards/GuardPath\";\nimport buildRootASTNodes, { AnyArgument, RootAstNode } from \"./RootAstNodesBuilder\";\nimport State, { AnyState } from \"./State\";\nimport Lookup from \"./Lookup\";\nimport Node from \"./nodes/Node\";\nimport Root from \"./nodes/decorator/Root\";\nimport Composite from \"./nodes/composite/Composite\";\nimport Decorator from \"./nodes/decorator/Decorator\";\nimport { Agent, GlobalFunction } from \"./Agent\";\nimport { CallbackAttributeDetails } from \"./attributes/callbacks/Callback\";\nimport { GuardAttributeDetails } from \"./attributes/guards/Guard\";\nimport { BehaviourTreeOptions } from \"./BehaviourTreeOptions\";\nimport { parseToJSON } from \"./dsl/DSLDefinitionParser\";\n\n// Purely for outside inspection of the tree.\nexport type FlattenedTreeNode = {\n id: string;\n type: string;\n caption: string;\n state: AnyState;\n guards: GuardAttributeDetails[];\n callbacks: CallbackAttributeDetails[];\n args: AnyArgument[];\n parentId: string | null;\n};\n\n/**\n * A representation of a behaviour tree.\n */\nexport class BehaviourTree {\n /**\n * The main root tree node.\n */\n public readonly rootNode: Root;\n\n /**\n * Creates a new instance of the BehaviourTree class.\n * @param definition The behaviour tree definition.\n * @param agent The agent instance that this behaviour tree is modelling behaviour for.\n * @param options The behaviour tree options object.\n */\n constructor(definition: string, private agent: Agent, private options: BehaviourTreeOptions = {}) {\n // The tree definition must be defined and a valid string.\n if (typeof definition !== \"string\") {\n throw new Error(\"the tree definition must be a string\");\n }\n\n // The agent must be defined and not null.\n if (typeof agent !== \"object\" || agent === null) {\n throw new Error(\"the agent must be defined and not null\");\n }\n\n // Parse the behaviour tree definition, create the populated tree of behaviour tree nodes, and get the root.\n this.rootNode = BehaviourTree._createRootNode(definition);\n }\n\n /**\n * Gets whether the tree is in the RUNNING state.\n * @returns true if the tree is in the RUNNING state, otherwise false.\n */\n isRunning() {\n return this.rootNode.getState() === State.RUNNING;\n }\n\n /**\n * Gets the current tree state of SUCCEEDED, FAILED, READY or RUNNING.\n * @returns The current tree state.\n */\n getState() {\n return this.rootNode.getState();\n }\n\n /**\n * Step the tree.\n * 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.\n * 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\n * 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.\n *\n * 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.\n */\n step() {\n // If the root node has already been stepped to completion then we need to reset it.\n if (this.rootNode.getState() === State.SUCCEEDED || this.rootNode.getState() === State.FAILED) {\n this.rootNode.reset();\n }\n\n try {\n this.rootNode.update(this.agent, this.options);\n } catch (exception) {\n throw new Error(`error stepping tree: ${(exception as Error).message}`);\n }\n }\n\n /**\n * Resets the tree from the root node outwards to each nested node, giving each a state of READY.\n */\n reset() {\n this.rootNode.reset();\n }\n\n /**\n * Gets the flattened details of every node in the tree.\n * @returns The flattened details of every node in the tree.\n */\n getFlattenedNodeDetails(): FlattenedTreeNode[] {\n // Create an empty flattened array of tree nodes.\n const flattenedTreeNodes: FlattenedTreeNode[] = [];\n\n /**\n * Helper function to process a node instance and push details into the flattened tree nodes array.\n * @param node The current node.\n * @param parentUid The UID of the node parent, or null if the node is the main root node.\n */\n const processNode = (node: Node, parentUid: string | null) => {\n // Get the guard and callback attribute details for this node.\n const guards = node\n .getAttributes()\n .filter((attribute) => attribute.isGuard())\n .map((attribute) => attribute.getDetails()) as GuardAttributeDetails[];\n const callbacks = node\n .getAttributes()\n .filter((attribute) => !attribute.isGuard())\n .map((attribute) => attribute.getDetails()) as CallbackAttributeDetails[];\n\n // Push the current node into the flattened nodes array.\n flattenedTreeNodes.push({\n id: node.getUid(),\n type: node.getType(),\n caption: node.getName(),\n state: node.getState(),\n guards,\n callbacks,\n args: node.getArguments(),\n parentId: parentUid\n });\n\n // Process each of the nodes children if it is not a leaf node.\n if (!node.isLeafNode()) {\n (node as Composite | Decorator)\n .getChildren()\n .forEach((child) => processNode(child, (node as Composite | Decorator).getUid()));\n }\n };\n\n // Convert the nested node structure into a flattened array of node details.\n processNode(this.rootNode, null);\n\n return flattenedTreeNodes;\n }\n\n /**\n * Registers the action/condition/guard/callback function or subtree with the given name.\n * @param name The name of the function or subtree to register.\n * @param value The function or subtree definition to register.\n */\n static register(name: string, value: GlobalFunction | string) {\n if (typeof value === \"function\") {\n // We are going to register a action/condition/guard/callback function.\n Lookup.setFunc(name, value);\n } else if (typeof value === \"string\") {\n // We are going to register a subtree.\n let rootASTNodes: RootAstNode[];\n\n try {\n // Try to create the behaviour tree AST based on the definition provided, this could fail if the definition is invalid.\n rootASTNodes = buildRootASTNodes(value);\n } catch (exception) {\n // There was an issue in trying to parse and build the tree definition.\n throw new Error(`error registering definition: ${(exception as Error).message}`);\n }\n\n // This function should only ever be called with a definition containing a single unnamed root node.\n if (rootASTNodes.length != 1 || rootASTNodes[0].name !== null) {\n throw new Error(\"error registering definition: expected a single unnamed root node\");\n }\n\n Lookup.setSubtree(name, rootASTNodes[0]);\n } else {\n throw new Error(\"unexpected value, expected string definition or function\");\n }\n }\n\n /**\n * Unregisters the registered action/condition/guard/callback function or subtree with the given name.\n * @param name The name of the registered action/condition/guard/callback function or subtree to unregister.\n */\n static unregister(name: string): void {\n Lookup.remove(name);\n }\n\n /**\n * Unregister all registered action/condition/guard/callback functions and subtrees.\n */\n static unregisterAll(): void {\n Lookup.empty();\n }\n\n /**\n * Parses a behaviour tree definition and creates a tree of behaviour tree nodes.\n * @param {string} definition The behaviour tree definition.\n * @returns The root behaviour tree node.\n */\n private static _createRootNode(definition: string): Root {\n // TODO Remove!\n try {\n //parseToJSON(definition);\n } catch (exception) {\n console.log(exception);\n }\n\n try {\n // Try to create the behaviour tree AST based on the definition provided, this could fail if the definition is invalid.\n const rootASTNodes = buildRootASTNodes(definition);\n\n // Create a symbol to use as the main root key in our root node mapping.\n const mainRootNodeKey = Symbol(\"__root__\");\n\n // Create a mapping of root node names to root AST tokens. The main root node will have a key of Symbol(\"__root__\").\n const rootNodeMap: { [key: string | symbol]: RootAstNode } = {};\n for (const rootASTNode of rootASTNodes) {\n rootNodeMap[rootASTNode.name === null ? mainRootNodeKey : rootASTNode.name!] = rootASTNode;\n }\n\n // Convert the AST to our actual tree and get the root node.\n const rootNode: Root = rootNodeMap[mainRootNodeKey].createNodeInstance(\n // Create a provider for named root nodes that are part of our definition or have been registered. Prioritising the former.\n (name: string): RootAstNode => (rootNodeMap[name] ? rootNodeMap[name] : Lookup.getSubtree(name)),\n []\n );\n\n // Set a guard path on every leaf of the tree to evaluate as part of its update.\n BehaviourTree._applyLeafNodeGuardPaths(rootNode);\n\n // Return the root node.\n return rootNode;\n } catch (exception) {\n // There was an issue in trying to parse and build the tree definition.\n throw new Error(`error parsing tree: ${(exception as Error).message}`);\n }\n }\n\n /**\n * Applies a guard path to every leaf of the tree to evaluate as part of each update.\n * @param rootNode The main root tree node.\n */\n private static _applyLeafNodeGuardPaths(rootNode: Root) {\n const nodePaths: Node[][] = [];\n\n const findLeafNodes = (path: Node[], node: Node) => {\n // Add the current node to the path.\n path = path.concat(node);\n\n // Check whether the current node is a leaf node.\n if (node.isLeafNode()) {\n nodePaths.push(path);\n } else {\n (node as Composite | Decorator).getChildren().forEach((child) => findLeafNodes(path, child));\n }\n };\n\n // Find all leaf node paths, starting from the root.\n findLeafNodes([], rootNode);\n\n nodePaths.forEach((path) => {\n // Each node in the current path will have to be assigned a guard path, working from the root outwards.\n for (let depth = 0; depth < path.length; depth++) {\n // Get the node in the path at the current depth.\n const currentNode = path[depth];\n\n // The node may already have been assigned a guard path, if so just skip it.\n if (currentNode.hasGuardPath()) {\n continue;\n }\n\n // Create the guard path for the current node.\n const guardPath = new GuardPath(\n path\n .slice(0, depth + 1)\n .map((node) => ({ node, guards: node.getGuardAttributes() }))\n .filter((details) => details.guards.length > 0)\n );\n\n // Assign the guard path to the current node.\n currentNode.setGuardPath(guardPath);\n }\n });\n }\n}\n"], + "mappings": "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", + "names": ["Participant", "Lotto", "createLotto", "State", "createLotto"] +} diff --git a/dist/nodes/Node.d.ts b/dist/nodes/Node.d.ts new file mode 100644 index 0000000..864bffc --- /dev/null +++ b/dist/nodes/Node.d.ts @@ -0,0 +1,111 @@ +import { Agent } from "../Agent"; +import Attribute from "../attributes/Attribute"; +import Entry from "../attributes/callbacks/Entry"; +import Exit from "../attributes/callbacks/Exit"; +import Step from "../attributes/callbacks/Step"; +import Guard from "../attributes/guards/Guard"; +import GuardPath from "../attributes/guards/GuardPath"; +import { BehaviourTreeOptions } from "../BehaviourTreeOptions"; +import { AnyArgument } from "../RootAstNodesBuilder"; +import { AnyState } from "../State"; +import Leaf from "./leaf/Leaf"; +/** + * A base node. + */ +export default abstract class Node { + private type; + private attributes; + private args; + /** + * The node uid. + */ + private readonly uid; + /** + * The node state. + */ + private state; + /** + * The guard path to evaluate as part of a node update. + */ + private guardPath; + /** + * @param type The node type. + * @param attributes The node attributes. + * @param args The node argument definitions. + */ + constructor(type: string, attributes: Attribute[], args: AnyArgument[]); + /** + * Called when the node is being updated. + * @param agent The agent. + * @param options The behaviour tree options object. + */ + protected abstract onUpdate(agent: Agent, options: BehaviourTreeOptions): void; + /** + * Gets the name of the node. + */ + abstract getName(): string; + /** + * Gets whether this node is a leaf node. + */ + abstract isLeafNode: () => this is Leaf; + /** + * Gets/Sets the state of the node. + */ + getState: () => AnyState; + setState: (value: AnyState) => void; + /** + * Gets the unique id of the node. + */ + getUid: () => string; + /** + * Gets the type of the node. + */ + getType: () => string; + /** + * Gets the node attributes. + */ + getAttributes: () => Attribute[]; + /** + * Gets the node arguments. + */ + getArguments: () => AnyArgument[]; + /** + * Gets the node attribute with the specified type, or null if it does not exist. + */ + getAttribute(type: "entry" | "ENTRY"): Entry; + getAttribute(type: "exit" | "EXIT"): Exit; + getAttribute(type: "step" | "STEP"): Step; + /** + * Gets the node attributes. + */ + getGuardAttributes: () => Guard[]; + /** + * Sets the guard path to evaluate as part of a node update. + */ + setGuardPath: (value: GuardPath) => GuardPath; + /** + * Gets whether a guard path is assigned to this node. + */ + hasGuardPath: () => boolean; + /** + * Gets whether this node is in the specified state. + * @param value The value to compare to the node state. + */ + is(value: AnyState): boolean; + /** + * Reset the state of the node. + */ + reset(): void; + /** + * Abort the running of this node. + * @param agent The agent. + */ + abort(agent: Agent): void; + /** + * Update the node. + * @param agent The agent. + * @param options The behaviour tree options object. + * @returns The result of the update. + */ + update(agent: Agent, options: BehaviourTreeOptions): void; +} diff --git a/dist/nodes/composite/Composite.d.ts b/dist/nodes/composite/Composite.d.ts new file mode 100644 index 0000000..51c075e --- /dev/null +++ b/dist/nodes/composite/Composite.d.ts @@ -0,0 +1,32 @@ +import Node from "../Node"; +import { Agent } from "../../Agent"; +import Attribute from "../../attributes/Attribute"; +/** + * A composite node that wraps child nodes. + */ +export default abstract class Composite extends Node { + protected children: Node[]; + /** + * @param type The node type. + * @param attributes The node attributes. + * @param children The child nodes. + */ + constructor(type: string, attributes: Attribute[], children: Node[]); + /** + * Gets whether this node is a leaf node. + */ + isLeafNode: () => boolean; + /** + * Gets the children of this node. + */ + getChildren: () => Node[]; + /** + * Reset the state of the node. + */ + reset: () => void; + /** + * Abort the running of this node. + * @param agent The agent. + */ + abort: (agent: Agent) => void; +} diff --git a/dist/nodes/composite/Lotto.d.ts b/dist/nodes/composite/Lotto.d.ts new file mode 100644 index 0000000..2a2a001 --- /dev/null +++ b/dist/nodes/composite/Lotto.d.ts @@ -0,0 +1,33 @@ +import Node from "../Node"; +import Composite from "./Composite"; +import { Agent } from "../../Agent"; +import Attribute from "../../attributes/Attribute"; +import { BehaviourTreeOptions } from "../../BehaviourTreeOptions"; +/** + * A LOTTO node. + * A winning child is picked on the initial update of this node, based on ticket weighting. + * The state of this node will match the state of the winning child. + */ +export default class Lotto extends Composite { + private tickets; + /** + * @param attributes The node attributes. + * @param tickets The child node tickets. + * @param children The child nodes. + */ + constructor(attributes: Attribute[], tickets: number[], children: Node[]); + /** + * The child node selected to be the active one. + */ + private selectedChild; + /** + * Called when the node is being updated. + * @param agent The agent. + * @param options The behaviour tree options object. + */ + protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void; + /** + * Gets the name of the node. + */ + getName: () => string; +} diff --git a/dist/nodes/composite/Parallel.d.ts b/dist/nodes/composite/Parallel.d.ts new file mode 100644 index 0000000..fe8e143 --- /dev/null +++ b/dist/nodes/composite/Parallel.d.ts @@ -0,0 +1,26 @@ +import Composite from "./Composite"; +import Node from "../Node"; +import { Agent } from "../../Agent"; +import Attribute from "../../attributes/Attribute"; +import { BehaviourTreeOptions } from "../../BehaviourTreeOptions"; +/** + * A PARALLEL node. + * The child nodes are executed concurrently until one fails or all succeed. + */ +export default class Parallel extends Composite { + /** + * @param attributes The node attributes. + * @param children The child nodes. + */ + constructor(attributes: Attribute[], children: Node[]); + /** + * Called when the node is being updated. + * @param agent The agent. + * @param options The behaviour tree options object. + */ + protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void; + /** + * Gets the name of the node. + */ + getName: () => string; +} diff --git a/dist/nodes/composite/Selector.d.ts b/dist/nodes/composite/Selector.d.ts new file mode 100644 index 0000000..da73717 --- /dev/null +++ b/dist/nodes/composite/Selector.d.ts @@ -0,0 +1,27 @@ +import Composite from "./Composite"; +import Node from "../Node"; +import { Agent } from "../../Agent"; +import Attribute from "../../attributes/Attribute"; +import { BehaviourTreeOptions } from "../../BehaviourTreeOptions"; +/** + * A SELECTOR node. + * The child nodes are executed in sequence until one succeeds or all fail. + */ +export default class Selector extends Composite { + protected children: Node[]; + /** + * @param attributes The node attributes. + * @param children The child nodes. + */ + constructor(attributes: Attribute[], children: Node[]); + /** + * Called when the node is being updated. + * @param agent The agent. + * @param options The behaviour tree options object. + */ + protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void; + /** + * Gets the name of the node. + */ + getName: () => string; +} diff --git a/dist/nodes/composite/Sequence.d.ts b/dist/nodes/composite/Sequence.d.ts new file mode 100644 index 0000000..31f13d5 --- /dev/null +++ b/dist/nodes/composite/Sequence.d.ts @@ -0,0 +1,27 @@ +import Composite from "./Composite"; +import Node from "../Node"; +import { Agent } from "../../Agent"; +import Attribute from "../../attributes/Attribute"; +import { BehaviourTreeOptions } from "../../BehaviourTreeOptions"; +/** + * A SEQUENCE node. + * The child nodes are executed in sequence until one fails or all succeed. + */ +export default class Sequence extends Composite { + protected children: Node[]; + /** + * @param attributes The node attributes. + * @param children The child nodes. + */ + constructor(attributes: Attribute[], children: Node[]); + /** + * Called when the node is being updated. + * @param agent The agent. + * @param options The behaviour tree options object. + */ + protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void; + /** + * Gets the name of the node. + */ + getName: () => string; +} diff --git a/dist/nodes/decorator/Decorator.d.ts b/dist/nodes/decorator/Decorator.d.ts new file mode 100644 index 0000000..e3c9f24 --- /dev/null +++ b/dist/nodes/decorator/Decorator.d.ts @@ -0,0 +1,32 @@ +import Node from "../Node"; +import { Agent } from "../../Agent"; +import Attribute from "../../attributes/Attribute"; +/** + * A decorator node that wraps a single child node. + */ +export default abstract class Decorator extends Node { + protected child: Node; + /** + * @param type The node type. + * @param attributes The node attributes. + * @param child The child node. + */ + constructor(type: string, attributes: Attribute[], child: Node); + /** + * Gets whether this node is a leaf node. + */ + isLeafNode: () => boolean; + /** + * Gets the children of this node. + */ + getChildren: () => Node[]; + /** + * Reset the state of the node. + */ + reset: () => void; + /** + * Abort the running of this node. + * @param agent The agent. + */ + abort: (agent: Agent) => void; +} diff --git a/dist/nodes/decorator/Fail.d.ts b/dist/nodes/decorator/Fail.d.ts new file mode 100644 index 0000000..9a790f7 --- /dev/null +++ b/dist/nodes/decorator/Fail.d.ts @@ -0,0 +1,26 @@ +import Node from "../Node"; +import Decorator from "./Decorator"; +import { Agent } from "../../Agent"; +import Attribute from "../../attributes/Attribute"; +import { BehaviourTreeOptions } from "../../BehaviourTreeOptions"; +/** + * A Fail node. + * This node wraps a single child and will always move to the 'FAILED' state when the child moves to a 'SUCCEEDED' or 'FAILED' state. + */ +export default class Fail extends Decorator { + /** + * @param attributes The node attributes. + * @param child The child node. + */ + constructor(attributes: Attribute[], child: Node); + /** + * Called when the node is being updated. + * @param agent The agent. + * @param options The behaviour tree options object. + */ + protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void; + /** + * Gets the name of the node. + */ + getName: () => string; +} diff --git a/dist/nodes/decorator/Flip.d.ts b/dist/nodes/decorator/Flip.d.ts new file mode 100644 index 0000000..6e14177 --- /dev/null +++ b/dist/nodes/decorator/Flip.d.ts @@ -0,0 +1,26 @@ +import Decorator from "./Decorator"; +import Node from "../Node"; +import { Agent } from "../../Agent"; +import Attribute from "../../attributes/Attribute"; +import { BehaviourTreeOptions } from "../../BehaviourTreeOptions"; +/** + * A Flip node. + * This node wraps a single child and will flip the state of the child state. + */ +export default class Flip extends Decorator { + /** + * @param attributes The node attributes. + * @param child The child node. + */ + constructor(attributes: Attribute[], child: Node); + /** + * Called when the node is being updated. + * @param agent The agent. + * @param options The behaviour tree options object. + */ + protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void; + /** + * Gets the name of the node. + */ + getName: () => string; +} diff --git a/dist/nodes/decorator/Repeat.d.ts b/dist/nodes/decorator/Repeat.d.ts new file mode 100644 index 0000000..8a99d2d --- /dev/null +++ b/dist/nodes/decorator/Repeat.d.ts @@ -0,0 +1,58 @@ +import Node from "../Node"; +import Decorator from "./Decorator"; +import { Agent } from "../../Agent"; +import Attribute from "../../attributes/Attribute"; +import { BehaviourTreeOptions } from "../../BehaviourTreeOptions"; +/** + * A REPEAT node. + * The node has a single child which can have: + * -- A number of iterations for which to repeat the child node. + * -- An infinite repeat loop if neither an iteration count or a condition function is defined. + * The REPEAT node will stop and have a 'FAILED' state if its child is ever in a 'FAILED' state after an update. + * The REPEAT node will attempt to move on to the next iteration if its child is ever in a 'SUCCEEDED' state. + */ +export default class Repeat extends Decorator { + private iterations; + private iterationsMin; + private iterationsMax; + /** + * @param attributes The node attributes. + * @param iterations The number of iterations to repeat the child node. + * @param iterationsMin The minimum possible number of iterations to repeat the child node. + * @param iterationsMax The maximum possible number of iterations to repeat the child node. + * @param child The child node. + */ + constructor(attributes: Attribute[], iterations: number | null, iterationsMin: number | null, iterationsMax: number | null, child: Node); + /** + * The number of target iterations to make. + */ + private targetIterationCount; + /** + * The current iteration count. + */ + private currentIterationCount; + /** + * Called when the node is being updated. + * @param agent The agent. + * @param options The behaviour tree options object. + */ + protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void; + /** + * Gets the name of the node. + */ + getName: () => string; + /** + * Reset the state of the node. + */ + reset: () => void; + /** + * Gets whether an iteration can be made. + * @returns Whether an iteration can be made. + */ + private canIterate; + /** + * Sets the target iteration count. + * @param options The behaviour tree options object. + */ + private setTargetIterationCount; +} diff --git a/dist/nodes/decorator/Retry.d.ts b/dist/nodes/decorator/Retry.d.ts new file mode 100644 index 0000000..fd4745a --- /dev/null +++ b/dist/nodes/decorator/Retry.d.ts @@ -0,0 +1,58 @@ +import Node from "../Node"; +import Decorator from "./Decorator"; +import { Agent } from "../../Agent"; +import Attribute from "../../attributes/Attribute"; +import { BehaviourTreeOptions } from "../../BehaviourTreeOptions"; +/** + * A RETRY node. + * The node has a single child which can have: + * -- A number of iterations for which to repeat the child node. + * -- An infinite repeat loop if neither an iteration count or a condition function is defined. + * The RETRY node will stop and have a 'SUCCEEDED' state if its child is ever in a 'SUCCEEDED' state after an update. + * The RETRY node will attempt to move on to the next iteration if its child is ever in a 'FAILED' state. + */ +export default class Retry extends Decorator { + private attempts; + private attemptsMin; + private attemptsMax; + /** + * @param attributes The node attributes. + * @param attempts The number of attempts to retry the child node. + * @param attemptsMin The minimum possible number of attempts to retry the child node. + * @param attemptsMax The maximum possible number of attempts to retry the child node. + * @param child The child node. + */ + constructor(attributes: Attribute[], attempts: number | null, attemptsMin: number | null, attemptsMax: number | null, child: Node); + /** + * The number of target attempts to make. + */ + private targetAttemptCount; + /** + * The current attempt count. + */ + private currentAttemptCount; + /** + * Called when the node is being updated. + * @param agent The agent. + * @param options The behaviour tree options object. + */ + protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void; + /** + * Gets the name of the node. + */ + getName: () => string; + /** + * Reset the state of the node. + */ + reset: () => void; + /** + * Gets whether an attempt can be made. + * @returns Whether an attempt can be made. + */ + canAttempt: () => boolean; + /** + * Sets the target attempt count. + * @param options The behaviour tree options object. + */ + setTargetAttemptCount: (options: BehaviourTreeOptions) => void; +} diff --git a/dist/nodes/decorator/Root.d.ts b/dist/nodes/decorator/Root.d.ts new file mode 100644 index 0000000..ebbceff --- /dev/null +++ b/dist/nodes/decorator/Root.d.ts @@ -0,0 +1,26 @@ +import Node from "../Node"; +import Decorator from "./Decorator"; +import { Agent } from "../../Agent"; +import Attribute from "../../attributes/Attribute"; +import { BehaviourTreeOptions } from "../../BehaviourTreeOptions"; +/** + * A Root node. + * The root node will have a single child. + */ +export default class Root extends Decorator { + /** + * @param attributes The node attributes. + * @param child The child node. + */ + constructor(attributes: Attribute[], child: Node); + /** + * Called when the node is being updated. + * @param agent The agent. + * @param options The behaviour tree options object. + */ + protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void; + /** + * Gets the name of the node. + */ + getName: () => string; +} diff --git a/dist/nodes/decorator/Succeed.d.ts b/dist/nodes/decorator/Succeed.d.ts new file mode 100644 index 0000000..67dc196 --- /dev/null +++ b/dist/nodes/decorator/Succeed.d.ts @@ -0,0 +1,26 @@ +import Node from "../Node"; +import Decorator from "./Decorator"; +import { Agent } from "../../Agent"; +import Attribute from "../../attributes/Attribute"; +import { BehaviourTreeOptions } from "../../BehaviourTreeOptions"; +/** + * A Succeed node. + * This node wraps a single child and will always move to the 'SUCCEEDED' state when the child moves to a 'SUCCEEDED' or 'FAILED' state. + */ +export default class Succeed extends Decorator { + /** + * @param attributes The node attributes. + * @param child The child node. + */ + constructor(attributes: Attribute[], child: Node); + /** + * Called when the node is being updated. + * @param agent The agent. + * @param options The behaviour tree options object. + */ + protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void; + /** + * Gets the name of the node. + */ + getName: () => string; +} diff --git a/dist/nodes/leaf/Action.d.ts b/dist/nodes/leaf/Action.d.ts new file mode 100644 index 0000000..3b889be --- /dev/null +++ b/dist/nodes/leaf/Action.d.ts @@ -0,0 +1,46 @@ +import Leaf from "./Leaf"; +import { Agent } from "../../Agent"; +import Attribute from "../../attributes/Attribute"; +import { AnyArgument } from "../../RootAstNodesBuilder"; +import { BehaviourTreeOptions } from "../../BehaviourTreeOptions"; +/** + * An Action leaf node. + * This represents an immediate or ongoing state of behaviour. + */ +export default class Action extends Leaf { + private actionName; + private actionArguments; + /** + * @param attributes The node attributes. + * @param actionName The action name. + * @param actionArguments The array of action argument definitions. + */ + constructor(attributes: Attribute[], actionName: string, actionArguments: AnyArgument[]); + /** + * Whether there is a pending update promise. + */ + private isUsingUpdatePromise; + /** + * The finished state result of an update promise. + */ + private updatePromiseStateResult; + /** + * Called when the node is being updated. + * @param agent The agent. + * @param options The behaviour tree options object. + */ + protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void; + /** + * Gets the name of the node. + */ + getName: () => string; + /** + * Reset the state of the node. + */ + reset: () => void; + /** + * Validate the result of an update function call. + * @param result The result of an update function call. + */ + private validateUpdateResult; +} diff --git a/dist/nodes/leaf/Condition.d.ts b/dist/nodes/leaf/Condition.d.ts new file mode 100644 index 0000000..e2f08bd --- /dev/null +++ b/dist/nodes/leaf/Condition.d.ts @@ -0,0 +1,29 @@ +import Leaf from "./Leaf"; +import { Agent } from "../../Agent"; +import Attribute from "../../attributes/Attribute"; +import { AnyArgument } from "../../RootAstNodesBuilder"; +import { BehaviourTreeOptions } from "../../BehaviourTreeOptions"; +/** + * A Condition leaf node. + * This will succeed or fail immediately based on an agent predicate, without moving to the 'RUNNING' state. + */ +export default class Condition extends Leaf { + private conditionName; + private conditionArguments; + /** + * @param attributes The node attributes. + * @param conditionName The name of the condition function. + * @param conditionArguments The array of condition argument definitions. + */ + constructor(attributes: Attribute[], conditionName: string, conditionArguments: AnyArgument[]); + /** + * Called when the node is being updated. + * @param agent The agent. + * @param options The behaviour tree options object. + */ + protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void; + /** + * Gets the name of the node. + */ + getName: () => string; +} diff --git a/dist/nodes/leaf/Leaf.d.ts b/dist/nodes/leaf/Leaf.d.ts new file mode 100644 index 0000000..c7e7109 --- /dev/null +++ b/dist/nodes/leaf/Leaf.d.ts @@ -0,0 +1,10 @@ +import Node from "../Node"; +/** + * A leaf node. + */ +export default abstract class Leaf extends Node { + /** + * Gets whether this node is a leaf node. + */ + isLeafNode: () => boolean; +} diff --git a/dist/nodes/leaf/Wait.d.ts b/dist/nodes/leaf/Wait.d.ts new file mode 100644 index 0000000..43d08f0 --- /dev/null +++ b/dist/nodes/leaf/Wait.d.ts @@ -0,0 +1,42 @@ +import Leaf from "./Leaf"; +import Attribute from "../../attributes/Attribute"; +import { Agent } from "../../Agent"; +import { BehaviourTreeOptions } from "../../BehaviourTreeOptions"; +/** + * A WAIT node. + * The state of this node will change to SUCCEEDED after a duration of time + */ +export default class Wait extends Leaf { + private duration; + private durationMin; + private durationMax; + /** + * @param attributes The node attributes. + * @param duration The duration that this node will wait to succeed in milliseconds. + * @param durationMin The minimum possible duration in milliseconds that this node will wait to succeed. + * @param durationMax The maximum possible duration in milliseconds that this node will wait to succeed. + */ + constructor(attributes: Attribute[], duration: number | null, durationMin: number | null, durationMax: number | null); + /** + * The time in milliseconds at which this node was first updated. + */ + private initialUpdateTime; + /** + * The total duration in milliseconds that this node will be waiting for. + */ + private totalDuration; + /** + * The duration in milliseconds that this node has been waiting for. + */ + private waitedDuration; + /** + * Called when the node is being updated. + * @param agent The agent. + * @param options The behaviour tree options object. + */ + protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void; + /** + * Gets the name of the node. + */ + getName: () => string; +} diff --git a/src/BehaviourTree.ts b/src/BehaviourTree.ts index 7314728..fefa9b3 100644 --- a/src/BehaviourTree.ts +++ b/src/BehaviourTree.ts @@ -203,7 +203,7 @@ export class BehaviourTree { private static _createRootNode(definition: string): Root { // TODO Remove! try { - parseToJSON(definition); + // parseToJSON(definition); } catch (exception) { console.log(exception); } diff --git a/src/dsl/DSLDefinitionParser.ts b/src/dsl/DSLDefinitionParser.ts index bcec8ac..cce1e0a 100644 --- a/src/dsl/DSLDefinitionParser.ts +++ b/src/dsl/DSLDefinitionParser.ts @@ -11,7 +11,7 @@ export type AgentFunctionArguments = (string | number | boolean | null | undefin export type GuardAttributeDefinition = { call: string; args?: AgentFunctionArguments; -} +}; /** * A callback attribute for a node. @@ -19,7 +19,7 @@ export type GuardAttributeDefinition = { export type CallbackAttributeDefinition = { call: string; args?: AgentFunctionArguments; -} +}; /** * A type defining a general node definition. @@ -31,21 +31,21 @@ export type NodeDefinition = { entry?: CallbackAttributeDefinition; exit?: CallbackAttributeDefinition; step?: CallbackAttributeDefinition; -} +}; /** * A composite node that can contain any number of child nodes. */ export type CompositeDefinition = NodeDefinition & { children: AnyChildNode[]; -} +}; /** * A decorator node, a composite with only a single child node. */ export type DecoratorDefinition = NodeDefinition & { child: AnyChildNode; -} +}; /** * A branch node. @@ -53,7 +53,7 @@ export type DecoratorDefinition = NodeDefinition & { export type BranchDefinition = NodeDefinition & { type: "branch"; ref: string; -} +}; /** * An action node. @@ -62,7 +62,7 @@ export type ActionDefinition = NodeDefinition & { type: "action"; call: string; args?: AgentFunctionArguments; -} +}; /** * A condition node. @@ -71,7 +71,7 @@ export type ConditionDefinition = NodeDefinition & { type: "condition"; call: string; args?: AgentFunctionArguments; -} +}; /** * A wait node. @@ -79,36 +79,36 @@ export type ConditionDefinition = NodeDefinition & { export type WaitDefinition = NodeDefinition & { type: "wait"; duration: number | [number, number]; -} +}; /** * A sequence node. */ export type SequenceDefinition = CompositeDefinition & { type: "sequence"; -} +}; /** * A selector node. */ export type SelectorDefinition = CompositeDefinition & { type: "selector"; -} +}; /** * A lotto node. */ export type LottoDefinition = CompositeDefinition & { type: "lotto"; - weights?: number[] -} + weights?: number[]; +}; /** * A parallel node. */ export type ParallelDefinition = CompositeDefinition & { type: "parallel"; -} +}; /** * A root node. @@ -116,7 +116,7 @@ export type ParallelDefinition = CompositeDefinition & { export type RootDefinition = DecoratorDefinition & { type: "root"; id?: string; -} +}; /** * A repeat node. @@ -124,7 +124,7 @@ export type RootDefinition = DecoratorDefinition & { export type RepeatDefinition = DecoratorDefinition & { type: "repeat"; iterations?: number | [number, number]; -} +}; /** * A retry node. @@ -132,34 +132,47 @@ export type RepeatDefinition = DecoratorDefinition & { export type RetryDefinition = DecoratorDefinition & { type: "retry"; attempts?: number | [number, number]; -} +}; /** * A flip node. */ export type FlipDefinition = DecoratorDefinition & { type: "flip"; -} +}; /** * A succeed node. */ export type SucceedDefinition = DecoratorDefinition & { type: "succeed"; -} +}; /** * A fail node. */ export type FailDefinition = DecoratorDefinition & { type: "fail"; -} +}; /** * A type defining any node type. */ -export type AnyNode = BranchDefinition | ActionDefinition | ConditionDefinition | WaitDefinition | SequenceDefinition | - SelectorDefinition | LottoDefinition | ParallelDefinition | RootDefinition | RepeatDefinition | RetryDefinition | FlipDefinition | SucceedDefinition | FailDefinition; +export type AnyNode = + | BranchDefinition + | ActionDefinition + | ConditionDefinition + | WaitDefinition + | SequenceDefinition + | SelectorDefinition + | LottoDefinition + | ParallelDefinition + | RootDefinition + | RepeatDefinition + | RetryDefinition + | FlipDefinition + | SucceedDefinition + | FailDefinition; /** * A type defining any node type that can be a child of composite parent node. @@ -204,7 +217,11 @@ export function parseToJSON(definition: string): RootDefinition[] { * @param placeholders The substituted string literal placeholders. * @returns The root node JSON definitions. */ -export function convertTokensToJSONDefinition(tokens: string[], placeholders: StringLiteralPlaceholders, processedDefinition: string): RootDefinition[] { +export function convertTokensToJSONDefinition( + tokens: string[], + placeholders: StringLiteralPlaceholders, + processedDefinition: string +): RootDefinition[] { // There must be at least 3 tokens for the tree definition to be valid. 'ROOT', '{' and '}'. if (tokens.length < 3) { throw new Error("invalid token count"); @@ -226,10 +243,10 @@ export function convertTokensToJSONDefinition(tokens: string[], placeholders: St // Add the root node definition to our array of all parsed root node definitions. rootNodes.push(rootNode); - // Add the root node definition to the root of a new tree stack. + // Add the root node definition to the root of a new tree stack. treeStacks.push([rootNode]); - } - + }; + // A helper function used to push non-root node definitions onto the stack. const pushNode = (node: AnyChildNode) => { // Get the current tree stack that we are populating. @@ -258,7 +275,7 @@ export function convertTokensToJSONDefinition(tokens: string[], placeholders: St bottomNode.child = node; } - // If the node we are adding is also a composite or decorator node, then we should push it + // If the node we are adding is also a composite or decorator node, then we should push it // onto the current tree stack, as subsequent nodes will be added as its child/children. if (!isLeafNode(node)) { currentTreeStack.push(node); @@ -275,7 +292,7 @@ export function convertTokensToJSONDefinition(tokens: string[], placeholders: St currentTreeStack.pop(); } - // We don't want any empty tree stacks in our stack of tree stacks. + // We don't want any empty tree stacks in our stack of tree stacks. if (!currentTreeStack.length) { treeStacks.pop(); } @@ -397,4 +414,4 @@ function parseTokensFromDefinition(definition: string): string[] { // Split the definition into raw token form and return it. return definition.replace(/\s+/g, " ").trim().split(" "); -} \ No newline at end of file +} diff --git a/src/dsl/DSLNodeArgumentParser.ts b/src/dsl/DSLNodeArgumentParser.ts index 7f93bd5..60874db 100644 --- a/src/dsl/DSLNodeArgumentParser.ts +++ b/src/dsl/DSLNodeArgumentParser.ts @@ -54,10 +54,10 @@ export function getArguments( const argumentList: AnyArgument[] = []; // If the next token is not a '[' or '(' then we have no arguments to parse. - if (!["[","("].includes(tokens[0])) { + if (!["[", "("].includes(tokens[0])) { return argumentList; - }; - + } + // Any lists of arguments will always be wrapped in '[]' for node arguments or '()' for attribute arguments. // We are looking for a '[' or '(' opener that wraps the argument tokens and the relevant closer. const closer = popAndCheck(tokens, ["[", "("]) === "[" ? "]" : ")"; @@ -149,4 +149,4 @@ function getArgumentDefinition(token: string, stringArgumentPlaceholders: Placeh value: token, type: "identifier" } as IdentifierArgument; -} \ No newline at end of file +} diff --git a/src/dsl/DSLUtilities.ts b/src/dsl/DSLUtilities.ts index d165555..f515a40 100644 --- a/src/dsl/DSLUtilities.ts +++ b/src/dsl/DSLUtilities.ts @@ -16,7 +16,7 @@ export function popAndCheck(tokens: string[], expected?: string | string[]): str // Do we have an expected token/tokens array? if (expected != undefined) { // Get an array of expected values, if the popped token matches any then we are all good. - const expectedValues = (typeof expected === "string") ? [expected] : expected; + const expectedValues = typeof expected === "string" ? [expected] : expected; // Check whether the popped token matches at least one of our expected items. var tokenMatchesExpectation = expectedValues.some((item) => popped.toUpperCase() === item.toUpperCase()); @@ -30,4 +30,4 @@ export function popAndCheck(tokens: string[], expected?: string | string[]): str // Return the popped token. return popped; -} \ No newline at end of file +} From 174c2029d68f28c0db6e5bd1ed2d686368ed4012 Mon Sep 17 00:00:00 2001 From: Nikolas Howard Date: Wed, 4 Oct 2023 17:37:12 +0100 Subject: [PATCH 08/48] working on MDSL parser --- dist/bundle.js.map | 4 +- dist/index.js.map | 4 +- dist/mdsl/MDSLDefinitionParser.d.ts | 7 + dist/mdsl/MDSLNodeArgumentParser.d.ts | 33 ++ dist/mdsl/MDSLNodeAttributeParser.d.ts | 20 + dist/mdsl/MDSLUtilities.d.ts | 47 ++ src/BehaviourTree.ts | 2 +- src/BehaviourTreeDefinition.d.ts | 176 ++++++++ src/RootAstNodesBuilder.ts | 10 +- src/dsl/DSLDefinitionParser.ts | 417 ------------------ src/dsl/DSLUtilities.ts | 33 -- src/mdsl/MDSLDefinitionParser.ts | 210 +++++++++ .../MDSLNodeArgumentParser.ts} | 33 +- src/mdsl/MDSLNodeAttributeParser.ts | 75 ++++ src/mdsl/MDSLUtilities.ts | 115 +++++ 15 files changed, 705 insertions(+), 481 deletions(-) create mode 100644 dist/mdsl/MDSLDefinitionParser.d.ts create mode 100644 dist/mdsl/MDSLNodeArgumentParser.d.ts create mode 100644 dist/mdsl/MDSLNodeAttributeParser.d.ts create mode 100644 dist/mdsl/MDSLUtilities.d.ts create mode 100644 src/BehaviourTreeDefinition.d.ts delete mode 100644 src/dsl/DSLDefinitionParser.ts delete mode 100644 src/dsl/DSLUtilities.ts create mode 100644 src/mdsl/MDSLDefinitionParser.ts rename src/{dsl/DSLNodeArgumentParser.ts => mdsl/MDSLNodeArgumentParser.ts} (82%) create mode 100644 src/mdsl/MDSLNodeAttributeParser.ts create mode 100644 src/mdsl/MDSLUtilities.ts diff --git a/dist/bundle.js.map b/dist/bundle.js.map index b76ce81..aa2b9e2 100644 --- a/dist/bundle.js.map +++ b/dist/bundle.js.map @@ -1,7 +1,7 @@ { "version": 3, "sources": ["../node_modules/lotto-draw/dist/Participant.js", "../node_modules/lotto-draw/dist/Utilities.js", "../node_modules/lotto-draw/dist/Lotto.js", "../node_modules/lotto-draw/dist/createLotto.js", "../node_modules/lotto-draw/dist/index.js", "../src/index.ts", "../src/attributes/guards/GuardUnsatisifedException.ts", "../src/attributes/guards/GuardPath.ts", "../src/State.ts", "../src/nodes/Node.ts", "../src/nodes/leaf/Leaf.ts", "../src/Lookup.ts", "../src/nodes/leaf/Action.ts", "../src/nodes/leaf/Condition.ts", "../src/nodes/leaf/Wait.ts", "../src/nodes/decorator/Decorator.ts", "../src/nodes/decorator/Root.ts", "../src/nodes/decorator/Repeat.ts", "../src/nodes/decorator/Retry.ts", "../src/nodes/decorator/Flip.ts", "../src/nodes/decorator/Succeed.ts", "../src/nodes/decorator/Fail.ts", "../src/nodes/composite/Lotto.ts", "../src/nodes/composite/Composite.ts", "../src/nodes/composite/Selector.ts", "../src/nodes/composite/Sequence.ts", "../src/nodes/composite/Parallel.ts", "../src/attributes/Attribute.ts", "../src/attributes/guards/Guard.ts", "../src/attributes/guards/While.ts", "../src/attributes/guards/Until.ts", "../src/attributes/callbacks/Callback.ts", "../src/attributes/callbacks/Entry.ts", "../src/attributes/callbacks/Exit.ts", "../src/attributes/callbacks/Step.ts", "../src/RootAstNodesBuilder.ts", "../src/BehaviourTree.ts"], - "sourcesContent": ["\"use strict\";\r\nObject.defineProperty(exports, \"__esModule\", { value: true });\r\nexports.Participant = void 0;\r\n/**\r\n * A participant that holds a number of tickets.\r\n */\r\nvar Participant = /** @class */ (function () {\r\n /**\r\n * Creates an instance of the Participant class.\r\n * @param participant The actual participant.\r\n * @param tickets The number of tickets held by the participant.\r\n */\r\n function Participant(participant, tickets) {\r\n if (tickets === void 0) { tickets = 1; }\r\n this._participant = participant;\r\n this._tickets = tickets;\r\n }\r\n Object.defineProperty(Participant.prototype, \"participant\", {\r\n /** Gets the actual participant. */\r\n get: function () {\r\n return this._participant;\r\n },\r\n enumerable: false,\r\n configurable: true\r\n });\r\n Object.defineProperty(Participant.prototype, \"tickets\", {\r\n /** Gets or sets the number of tickets held by the participant. */\r\n get: function () {\r\n return this._tickets;\r\n },\r\n set: function (value) {\r\n this._tickets = value;\r\n },\r\n enumerable: false,\r\n configurable: true\r\n });\r\n return Participant;\r\n}());\r\nexports.Participant = Participant;\r\n", "\"use strict\";\r\nObject.defineProperty(exports, \"__esModule\", { value: true });\r\nexports.isNaturalNumber = exports.isNullOrUndefined = void 0;\r\n/**\r\n * Gets whether the value provided is null or undefined.\r\n * @param value The value to check.\r\n * @returns Whether the value provided is null or undefined.\r\n */\r\nfunction isNullOrUndefined(value) {\r\n return value === null || value === undefined;\r\n}\r\nexports.isNullOrUndefined = isNullOrUndefined;\r\n/**\r\n * Gets whether the value provided is a natural number.\r\n * @param value The value to check.\r\n * @returns Whether the value provided is a natural number.\r\n */\r\nfunction isNaturalNumber(value) {\r\n return typeof value === \"number\" && value >= 1 && Math.floor(value) === value;\r\n}\r\nexports.isNaturalNumber = isNaturalNumber;\r\n", "\"use strict\";\r\nObject.defineProperty(exports, \"__esModule\", { value: true });\r\nexports.Lotto = void 0;\r\nvar Participant_1 = require(\"./Participant\");\r\nvar Utilities_1 = require(\"./Utilities\");\r\n/**\r\n * Represents a lotto consisting of a number of pickable ticket-holding participants.\r\n */\r\nvar Lotto = /** @class */ (function () {\r\n /**\r\n * Creates a new instance of Lotto.\r\n * @param customRandom The custom RNG to use in place of Math.random().\r\n */\r\n function Lotto(customRandom) {\r\n /** The array of participants that are holding tickets in the lotto. */\r\n this._participants = [];\r\n this._customRandom = customRandom;\r\n }\r\n /**\r\n * Adds a participant with the specified number of tickets, or adds to the participant ticket count if the participant already holds tickets.\r\n * @param participant The participant to add or to increase the ticket count for if they already hold tickets.\r\n * @param tickets The number of tickets, defaults to 1.\r\n * @returns The Lotto instance.\r\n */\r\n Lotto.prototype.add = function (participant, tickets) {\r\n if (tickets === void 0) { tickets = 1; }\r\n // Check that we have a valid ticket count.\r\n if (!(0, Utilities_1.isNaturalNumber)(tickets)) {\r\n throw new Error(\"tickets value must be a natural number\");\r\n }\r\n // Check whether this participant has already been added.\r\n var existingParticipant = this._participants.find(function (part) { return part.participant === participant; });\r\n if (existingParticipant) {\r\n // The participant has already been added to the lotto so just add to their ticket count.\r\n existingParticipant.tickets += tickets;\r\n }\r\n else {\r\n // The participant is not part of the lotto so we should add them.\r\n this._participants.push(new Participant_1.Participant(participant, tickets));\r\n }\r\n return this;\r\n };\r\n /**\r\n * Removes the specified number of tickets for the given participant from the draw, or all tickets if a ticket number is not defined.\r\n * @param participant The participant to remove tickets for.\r\n * @param tickets The number of tickets to remove, or undefined if all tickets are to be removed.\r\n * @returns The Lotto instance.\r\n */\r\n Lotto.prototype.remove = function (participant, tickets) {\r\n // Attempt to get the existing participant.\r\n var existingParticipant = this._participants.find(function (part) { return part.participant === participant; });\r\n // There is nothing to do if the specified participant isn't even part of the lotto.\r\n if (!existingParticipant) {\r\n return this;\r\n }\r\n // Check whether a tickets value was given.\r\n if (tickets !== undefined) {\r\n // Check that we have a valid ticket count.\r\n if (!(0, Utilities_1.isNaturalNumber)(tickets)) {\r\n throw new Error(\"tickets value must be a natural number\");\r\n }\r\n existingParticipant.tickets -= tickets;\r\n // If the participant no longer holds any tickets then they should be removed.\r\n if (existingParticipant.tickets < 1) {\r\n this._participants = this._participants.filter(function (part) { return part !== existingParticipant; });\r\n }\r\n }\r\n else {\r\n // We are removing all tickets for the participant so just remove them from the lotto.\r\n this._participants = this._participants.filter(function (part) { return part !== existingParticipant; });\r\n }\r\n return this;\r\n };\r\n /**\r\n * Draw a winning ticket and return the participant that holds the ticket.\r\n * @param options The draw options.\r\n * @returns The participant that holds the winning ticket.\r\n */\r\n Lotto.prototype.draw = function (options) {\r\n if (options === void 0) { options = {}; }\r\n // If we have no participants then just return null.\r\n if (this._participants.length === 0) {\r\n return null;\r\n }\r\n var redrawable = (0, Utilities_1.isNullOrUndefined)(options.redrawable) ? true : options.redrawable;\r\n var pickable = [];\r\n this._participants.forEach(function (_a) {\r\n var participant = _a.participant, tickets = _a.tickets;\r\n for (var ticketCount = 0; ticketCount < tickets; ticketCount++) {\r\n pickable.push(participant);\r\n }\r\n });\r\n var random;\r\n // We need a random floating-point number between 0 (inclusive) and 1 to scale up to pick our winner.\r\n // If a custom random function exists then we should use that or fall back to Math.random().\r\n if (this._customRandom) {\r\n // Call our custom random function to get a random floating-point number.\r\n random = this._customRandom();\r\n // Verify that the result of calling our custom random function is a number between 0 (inclusive) and 1.\r\n if (typeof random !== \"number\" || random < 0 || random >= 1) {\r\n throw new Error(\"the 'random' function provided did not return a number between 0 (inclusive) and 1\");\r\n }\r\n }\r\n else {\r\n // No custom random function was defined so just use good ol' Math.random().\r\n random = Math.random();\r\n }\r\n // Pick a winning participant.\r\n var winner = pickable[Math.floor(random * pickable.length)];\r\n // If the ticket isn't redrawable then we should remove a ticket from the winning participants ticket count.\r\n if (!redrawable) {\r\n this.remove(winner, 1);\r\n }\r\n // Return the winning participant.\r\n return winner;\r\n };\r\n /**\r\n * Draws multiple winning tickets and return an array of the participants that hold the winning tickets.\r\n * @param tickets The number of winning tickets to draw.\r\n * @param options The draw multiple options.\r\n * @returns An array of the participants that hold the winning tickets.\r\n */\r\n Lotto.prototype.drawMultiple = function (tickets, options) {\r\n if (options === void 0) { options = {}; }\r\n var uniqueResults = (0, Utilities_1.isNullOrUndefined)(options.unique) ? false : options.unique;\r\n // Handle cases where the user has asked for zero tickets (no idea why they would do this be we should trust them).\r\n if (tickets === 0) {\r\n return [];\r\n }\r\n // Now that we know out tickets value is not zero we should check that it is a valid natural number.\r\n if (!(0, Utilities_1.isNaturalNumber)(tickets)) {\r\n throw new Error(\"tickets value must be a natural number\");\r\n }\r\n var result = [];\r\n // Keep drawing tickets until we either reach the number of required tickets or we simply run out of tickets to draw.\r\n // We can run out of tickets to draw if 'options.redrawable' is explicity 'false' or we just had no participants when 'drawMultiple' was called.\r\n while (result.length < tickets && this._participants.length > 0) {\r\n result.push(this.draw(options));\r\n }\r\n // If the 'unique' draw option is set then we need to remove duplicates from the result list.\r\n if (uniqueResults) {\r\n // Create an array to store our unique results.\r\n var unique = [];\r\n // Iterate over all of our participants (with potential duplicates) and populate our array of unique values.\r\n for (var _i = 0, result_1 = result; _i < result_1.length; _i++) {\r\n var participant = result_1[_i];\r\n if (unique.indexOf(participant) === -1) {\r\n unique.push(participant);\r\n }\r\n }\r\n result = unique;\r\n }\r\n return result;\r\n };\r\n return Lotto;\r\n}());\r\nexports.Lotto = Lotto;\r\n", "\"use strict\";\r\nObject.defineProperty(exports, \"__esModule\", { value: true });\r\nexports.createLotto = void 0;\r\nvar Lotto_1 = require(\"./Lotto\");\r\n/**\r\n * A function that creates and returns a Lotto instance.\r\n * @param participantsOrOptions An array of initial participants or options relating to the creation of a Lotto instance.\r\n * @returns A new Lotto instance.\r\n */\r\nfunction createLotto(participantsOrOptions) {\r\n // If no initial participants or lotto options were provided as an argument then we can just return a new lotto instance now.\r\n if (!participantsOrOptions) {\r\n return new Lotto_1.Lotto();\r\n }\r\n // Check whether we were provided with an array of initial participants or a lotto options object.\r\n if (Array.isArray(participantsOrOptions)) {\r\n // We are dealing with a pre-defined array of participants.\r\n var participants = participantsOrOptions;\r\n var lotto_1 = new Lotto_1.Lotto();\r\n // If the lotto participants have been defined upfront then we will need to add them all to our lotto instance now.\r\n participants.forEach(function (_a) {\r\n var participant = _a[0], tokens = _a[1];\r\n return lotto_1.add(participant, tokens);\r\n });\r\n // Return the Lotto instance.\r\n return lotto_1;\r\n }\r\n else {\r\n // We are dealing with some lotto options.\r\n var random = participantsOrOptions.random, participants = participantsOrOptions.participants;\r\n // Create a Lotto instance passing the custom RNG function to use in place of Math.random() (which could be undefined).\r\n var lotto_2 = new Lotto_1.Lotto(random);\r\n // If the lotto participants have been defined upfront as part of the options then we will need to add them all to our lotto instance now.\r\n if (participants) {\r\n participants.forEach(function (_a) {\r\n var participant = _a[0], tokens = _a[1];\r\n return lotto_2.add(participant, tokens);\r\n });\r\n }\r\n // Return the Lotto instance.\r\n return lotto_2;\r\n }\r\n}\r\nexports.createLotto = createLotto;\r\n", "\"use strict\";\r\nObject.defineProperty(exports, \"__esModule\", { value: true });\r\nvar createLotto_1 = require(\"./createLotto\");\r\nexports.default = createLotto_1.createLotto;\r\n", "import { BehaviourTree, FlattenedTreeNode } from \"./BehaviourTree\";\nimport State from \"./State\";\n\nexport { BehaviourTree, State };\nexport type { FlattenedTreeNode };\n", "import Node from \"../../nodes/Node\";\n\n/**\n * An exception thrown when evaluating node guard path conditions and a conditions fails.\n */\nexport default class GuardUnsatisifedException extends Error {\n /**\n * @param source The node at which a guard condition failed.\n */\n constructor(private source: Node) {\n super(\"A guard path condition has failed\");\n }\n\n /**\n * Gets whether the specified node is the node at which a guard condition failed.\n * @param node The node to check against the source node.\n * @returns Whether the specified node is the node at which a guard condition failed.\n */\n isSourceNode = (node: Node) => node === this.source;\n}\n", "import { Agent } from \"../../Agent\";\nimport Guard from \"./Guard\";\nimport Node from \"../../nodes/Node\";\nimport GuardUnsatisifedException from \"./GuardUnsatisifedException\";\n\nexport type GuardPathPart = {\n node: Node;\n guards: Guard[];\n};\n\n/**\n * Represents a path of node guards along a root-to-leaf tree path.\n */\nexport default class GuardPath {\n /**\n * @param nodes An array of objects defining a node instance -> guard link, ordered by node depth.\n */\n constructor(private nodes: GuardPathPart[]) {}\n\n /**\n * Evaluate guard conditions for all guards in the tree path, moving outwards from the root.\n * @param agent The agent, required for guard evaluation.\n * @returns An evaluation results object.\n */\n evaluate = (agent: Agent) => {\n // We need to evaluate guard conditions for nodes up the tree, moving outwards from the root.\n for (const details of this.nodes) {\n // There can be multiple guards per node.\n for (const guard of details.guards) {\n // Check whether the guard condition passes, and throw an exception if not.\n if (!guard.isSatisfied(agent)) {\n throw new GuardUnsatisifedException(details.node);\n }\n }\n }\n };\n}\n", "/**\n * Enumeration of node state types.\n */\nexport enum State {\n READY = \"mistreevous.ready\",\n RUNNING = \"mistreevous.running\",\n SUCCEEDED = \"mistreevous.succeeded\",\n FAILED = \"mistreevous.failed\"\n}\n\nexport { State as default };\n\nexport type CompleteState = State.SUCCEEDED | State.FAILED;\nexport type AnyState = State.READY | State.RUNNING | CompleteState;\n", "import { Agent } from \"../Agent\";\nimport Attribute from \"../attributes/Attribute\";\nimport Entry from \"../attributes/callbacks/Entry\";\nimport Exit from \"../attributes/callbacks/Exit\";\nimport Step from \"../attributes/callbacks/Step\";\nimport Guard from \"../attributes/guards/Guard\";\nimport GuardPath from \"../attributes/guards/GuardPath\";\nimport GuardUnsatisifedException from \"../attributes/guards/GuardUnsatisifedException\";\nimport { BehaviourTreeOptions } from \"../BehaviourTreeOptions\";\nimport { AnyArgument } from \"../RootAstNodesBuilder\";\nimport State, { AnyState } from \"../State\";\nimport Leaf from \"./leaf/Leaf\";\n\n/**\n * A base node.\n */\nexport default abstract class Node {\n /**\n * The node uid.\n */\n private readonly uid: string = createNodeUid();\n /**\n * The node state.\n */\n private state: AnyState = State.READY;\n /**\n * The guard path to evaluate as part of a node update.\n */\n private guardPath: GuardPath | undefined;\n\n /**\n * @param type The node type.\n * @param attributes The node attributes.\n * @param args The node argument definitions.\n */\n constructor(private type: string, private attributes: Attribute[], private args: AnyArgument[]) {}\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected abstract onUpdate(agent: Agent, options: BehaviourTreeOptions): void;\n\n /**\n * Gets the name of the node.\n */\n public abstract getName(): string;\n\n /**\n * Gets whether this node is a leaf node.\n */\n public abstract isLeafNode: () => this is Leaf;\n\n /**\n * Gets/Sets the state of the node.\n */\n getState = (): AnyState => this.state;\n setState = (value: AnyState): void => {\n this.state = value;\n };\n\n /**\n * Gets the unique id of the node.\n */\n getUid = () => this.uid;\n\n /**\n * Gets the type of the node.\n */\n getType = () => this.type;\n\n /**\n * Gets the node attributes.\n */\n getAttributes = () => this.attributes;\n\n /**\n * Gets the node arguments.\n */\n getArguments = () => this.args;\n\n /**\n * Gets the node attribute with the specified type, or null if it does not exist.\n */\n getAttribute(type: \"entry\" | \"ENTRY\"): Entry;\n getAttribute(type: \"exit\" | \"EXIT\"): Exit;\n getAttribute(type: \"step\" | \"STEP\"): Step;\n getAttribute(type: string): Attribute {\n return (\n this.getAttributes().filter((decorator) => decorator.getType().toUpperCase() === type.toUpperCase())[0] ||\n null\n );\n }\n\n /**\n * Gets the node attributes.\n */\n getGuardAttributes = (): Guard[] => this.getAttributes().filter((decorator) => decorator.isGuard()) as Guard[];\n\n /**\n * Sets the guard path to evaluate as part of a node update.\n */\n setGuardPath = (value: GuardPath) => (this.guardPath = value);\n\n /**\n * Gets whether a guard path is assigned to this node.\n */\n hasGuardPath = () => !!this.guardPath;\n\n /**\n * Gets whether this node is in the specified state.\n * @param value The value to compare to the node state.\n */\n public is(value: AnyState): boolean {\n return this.state === value;\n }\n\n /**\n * Reset the state of the node.\n */\n public reset(): void {\n this.setState(State.READY);\n }\n\n /**\n * Abort the running of this node.\n * @param agent The agent.\n */\n public abort(agent: Agent): void {\n // There is nothing to do if this node is not in the running state.\n if (!this.is(State.RUNNING)) {\n return;\n }\n\n // Reset the state of this node.\n this.reset();\n\n this.getAttribute(\"exit\")?.callAgentFunction(agent, false, true);\n }\n\n /**\n * Update the node.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n * @returns The result of the update.\n */\n public update(agent: Agent, options: BehaviourTreeOptions): void {\n // If this node is already in a 'SUCCEEDED' or 'FAILED' state then there is nothing to do.\n if (this.is(State.SUCCEEDED) || this.is(State.FAILED)) {\n return;\n }\n\n try {\n // Evaluate all of the guard path conditions for the current tree path.\n this.guardPath!.evaluate(agent);\n\n // If this node is in the READY state then call the ENTRY for this node if it exists.\n if (this.is(State.READY)) {\n this.getAttribute(\"entry\")?.callAgentFunction(agent);\n }\n\n this.getAttribute(\"step\")?.callAgentFunction(agent);\n\n // Do the actual update.\n this.onUpdate(agent, options);\n\n // If this node is now in a 'SUCCEEDED' or 'FAILED' state then call the EXIT for this node if it exists.\n if (this.is(State.SUCCEEDED) || this.is(State.FAILED)) {\n this.getAttribute(\"exit\")?.callAgentFunction(agent, this.is(State.SUCCEEDED), false);\n }\n } catch (error) {\n // If the error is a GuardUnsatisfiedException then we need to determine if this node is the source.\n if (error instanceof GuardUnsatisifedException && error.isSourceNode(this)) {\n // Abort the current node.\n this.abort(agent);\n\n // Any node that is the source of an abort will be a failed node.\n this.setState(State.FAILED);\n } else {\n throw error;\n }\n }\n }\n}\n\n/**\n * Create a randomly generated node uid.\n * @returns A randomly generated node uid.\n */\nfunction createNodeUid(): string {\n var S4 = function () {\n return (((1 + Math.random()) * 0x10000) | 0).toString(16).substring(1);\n };\n return S4() + S4() + \"-\" + S4() + \"-\" + S4() + \"-\" + S4() + \"-\" + S4() + S4() + S4();\n}\n", "import Node from \"../Node\";\n\n/**\n * A leaf node.\n */\nexport default abstract class Leaf extends Node {\n /**\n * Gets whether this node is a leaf node.\n */\n isLeafNode = () => true;\n}\n", "import { ActionResult, Agent, ExitFunctionArg, FunctionArg, GlobalFunction } from \"./Agent\";\nimport { AnyArgument, RootAstNode } from \"./RootAstNodesBuilder\";\n\n// Exit callbacks receive their own special type of argument.\n// There's probably stricter ways to represent this but it feels overly complex right now.\ntype ExitResultArg = { value: ExitFunctionArg };\nexport type AnyExitArgument = AnyArgument | ExitResultArg;\n\nexport type InvokerFunction = (args: AnyExitArgument[]) => ActionResult;\n\n/**\n * A singleton used to store and lookup registered functions and subtrees.\n */\nexport default class Lookup {\n /**\n * The object holding any registered functions keyed on function name.\n */\n private static functionTable: { [key: string]: GlobalFunction } = {};\n /**\n * The object holding any registered sub-trees keyed on tree name.\n */\n private static subtreeTable: { [key: string]: RootAstNode } = {};\n\n /**\n * Gets the function with the specified name.\n * @param name The name of the function.\n * @returns The function with the specified name.\n */\n public static getFunc(name: string): GlobalFunction {\n return this.functionTable[name];\n }\n\n /**\n * Sets the function with the specified name for later lookup.\n * @param name The name of the function.\n * @param func The function.\n */\n public static setFunc(name: string, func: GlobalFunction): void {\n this.functionTable[name] = func;\n }\n\n /**\n * Gets the function invoker for the specified agent and function name.\n * If a function with the specified name exists on the agent object then it will\n * be returned, otherwise we will then check the registered functions for a match.\n * @param agent The agent instance that this behaviour tree is modelling behaviour for.\n * @param name The function name.\n * @returns The function invoker for the specified agent and function name.\n */\n static getFuncInvoker(agent: Agent, name: string): InvokerFunction | null {\n // Check whether the agent contains the specified function.\n const foundOnAgent = agent[name];\n if (foundOnAgent && typeof foundOnAgent === \"function\") {\n return (args: AnyExitArgument[]): boolean | ActionResult =>\n foundOnAgent.apply(\n agent,\n args.map((arg) => arg.value)\n );\n }\n\n // The agent does not contain the specified function but it may have been registered at some point.\n if (this.functionTable[name] && typeof this.functionTable[name] === \"function\") {\n return (args: AnyExitArgument[]) => this.functionTable[name](agent, ...args.map((arg) => arg.value));\n }\n\n // We have no function to invoke.\n return null;\n }\n\n /**\n * Gets the subtree with the specified name.\n * @param name The name of the subtree.\n * @returns The subtree with the specified name.\n */\n static getSubtree(name: string): RootAstNode {\n return this.subtreeTable[name];\n }\n\n /**\n * Sets the subtree with the specified name for later lookup.\n * @param name The name of the subtree.\n * @param subtree The subtree.\n */\n static setSubtree(name: string, subtree: RootAstNode) {\n this.subtreeTable[name] = subtree;\n }\n\n /**\n * Removes the registered function or subtree with the specified name.\n * @param name The name of the registered function or subtree.\n */\n static remove(name: string) {\n delete this.functionTable[name];\n delete this.subtreeTable[name];\n }\n\n /**\n * Remove all registered functions and subtrees.\n */\n static empty() {\n this.functionTable = {};\n this.subtreeTable = {};\n }\n}\n", "import Leaf from \"./Leaf\";\nimport State, { CompleteState } from \"../../State\";\nimport Lookup from \"../../Lookup\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { AnyArgument } from \"../../RootAstNodesBuilder\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * An Action leaf node.\n * This represents an immediate or ongoing state of behaviour.\n */\nexport default class Action extends Leaf {\n /**\n * @param attributes The node attributes.\n * @param actionName The action name.\n * @param actionArguments The array of action argument definitions.\n */\n constructor(attributes: Attribute[], private actionName: string, private actionArguments: AnyArgument[]) {\n super(\"action\", attributes, actionArguments);\n }\n\n /**\n * Whether there is a pending update promise.\n */\n private isUsingUpdatePromise = false;\n\n /**\n * The finished state result of an update promise.\n */\n private updatePromiseStateResult: CompleteState | null = null;\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // If the result of this action depends on an update promise then there is nothing to do until\n // it resolves, unless there has been a value set as a result of the update promise resolving.\n if (this.isUsingUpdatePromise) {\n // Check whether the update promise has resolved with a state value.\n if (this.updatePromiseStateResult) {\n // Set the state of this node to match the state returned by the promise.\n this.setState(this.updatePromiseStateResult);\n }\n\n return;\n }\n\n // Attempt to get the invoker for the action function.\n const actionFuncInvoker = Lookup.getFuncInvoker(agent, this.actionName);\n\n // The action function should be defined.\n if (actionFuncInvoker === null) {\n throw new Error(\n `cannot update action node as the action '${this.actionName}' function is not defined on the agent and has not been registered`\n );\n }\n\n // Call the action function, the result of which may be:\n // - The finished state of this action node.\n // - A promise to return a finished node state.\n // - Undefined if the node should remain in the running state.\n const updateResult = actionFuncInvoker(this.actionArguments) as CompleteState | Promise;\n\n if (updateResult instanceof Promise) {\n updateResult.then(\n (result) => {\n // If 'isUpdatePromisePending' is null then the promise was cleared as it was resolving, probably via an abort of reset.\n if (!this.isUsingUpdatePromise) {\n return;\n }\n\n // Check to make sure the result is a valid finished state.\n if (result !== State.SUCCEEDED && result !== State.FAILED) {\n throw new Error(\n \"action node promise resolved with an invalid value, expected a State.SUCCEEDED or State.FAILED value to be returned\"\n );\n }\n\n // Set pending update promise state result to be processed on next update.\n this.updatePromiseStateResult = result;\n },\n (reason) => {\n // If 'isUpdatePromisePending' is null then the promise was cleared as it was resolving, probably via an abort of reset.\n if (!this.isUsingUpdatePromise) {\n return;\n }\n\n // Just throw whatever was returned as the rejection argument.\n throw new Error(reason);\n }\n );\n\n // This node will be in the 'RUNNING' state until the update promise resolves.\n this.setState(State.RUNNING);\n\n // We are now waiting for the promise returned by the use to resolve before we know what state this node is in.\n this.isUsingUpdatePromise = true;\n } else {\n // Validate the returned value.\n this.validateUpdateResult(updateResult);\n\n // Set the state of this node, this may be undefined, which just means that the node is still in the 'RUNNING' state.\n this.setState(updateResult || State.RUNNING);\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => this.actionName;\n\n /**\n * Reset the state of the node.\n */\n reset = () => {\n // Reset the state of this node.\n this.setState(State.READY);\n\n // There is no longer an update promise that we care about.\n this.isUsingUpdatePromise = false;\n this.updatePromiseStateResult = null;\n };\n\n /**\n * Validate the result of an update function call.\n * @param result The result of an update function call.\n */\n private validateUpdateResult = (result: CompleteState | boolean) => {\n switch (result) {\n case State.SUCCEEDED:\n case State.FAILED:\n case undefined:\n return;\n default:\n throw new Error(\n `action '${this.actionName}' 'onUpdate' returned an invalid response, expected an optional State.SUCCEEDED or State.FAILED value to be returned`\n );\n }\n };\n}\n", "import Leaf from \"./Leaf\";\nimport State from \"../../State\";\nimport Lookup from \"../../Lookup\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { AnyArgument } from \"../../RootAstNodesBuilder\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A Condition leaf node.\n * This will succeed or fail immediately based on an agent predicate, without moving to the 'RUNNING' state.\n */\nexport default class Condition extends Leaf {\n /**\n * @param attributes The node attributes.\n * @param conditionName The name of the condition function.\n * @param conditionArguments The array of condition argument definitions.\n */\n constructor(attributes: Attribute[], private conditionName: string, private conditionArguments: AnyArgument[]) {\n super(\"condition\", attributes, conditionArguments);\n }\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // Attempt to get the invoker for the condition function.\n const conditionFuncInvoker = Lookup.getFuncInvoker(agent, this.conditionName);\n\n // The condition function should be defined.\n if (conditionFuncInvoker === null) {\n throw new Error(\n `cannot update condition node as the condition '${this.conditionName}' function is not defined on the agent and has not been registered`\n );\n }\n\n // Call the condition function to determine the state of this node.\n this.setState(!!conditionFuncInvoker(this.conditionArguments) ? State.SUCCEEDED : State.FAILED);\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => this.conditionName;\n}\n", "import Leaf from \"./Leaf\";\nimport State from \"../../State\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { Agent } from \"../../Agent\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A WAIT node.\n * The state of this node will change to SUCCEEDED after a duration of time\n */\nexport default class Wait extends Leaf {\n /**\n * @param attributes The node attributes.\n * @param duration The duration that this node will wait to succeed in milliseconds.\n * @param durationMin The minimum possible duration in milliseconds that this node will wait to succeed.\n * @param durationMax The maximum possible duration in milliseconds that this node will wait to succeed.\n */\n constructor(\n attributes: Attribute[],\n private duration: number | null,\n private durationMin: number | null,\n private durationMax: number | null\n ) {\n super(\"wait\", attributes, []);\n }\n\n /**\n * The time in milliseconds at which this node was first updated.\n */\n private initialUpdateTime: number = 0;\n\n /**\n * The total duration in milliseconds that this node will be waiting for.\n */\n private totalDuration: number | null = null;\n\n /**\n * The duration in milliseconds that this node has been waiting for.\n */\n private waitedDuration: number = 0;\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // If this node is in the READY state then we need to set the initial update time.\n if (this.is(State.READY)) {\n // Set the initial update time.\n this.initialUpdateTime = new Date().getTime();\n\n // Set the initial waited duration.\n this.waitedDuration = 0;\n\n // Are we dealing with an explicit duration or will we be randomly picking a duration between the min and max duration.\n if (this.duration !== null) {\n this.totalDuration = this.duration;\n } else if (this.durationMin !== null && this.durationMax !== null) {\n // We will be picking a random duration between a min and max duration, if the optional 'random' behaviour tree\n // function option is defined then we will be using that, otherwise we will fall back to using Math.random.\n const random = typeof options.random === \"function\" ? options.random : Math.random;\n\n // Pick a random duration between a min and max duration.\n this.totalDuration = Math.floor(\n random() * (this.durationMax - this.durationMin + 1) + this.durationMin\n );\n } else {\n this.totalDuration = null;\n }\n\n // The node is now running until we finish waiting.\n this.setState(State.RUNNING);\n }\n\n // If we have no total duration then this wait node will wait indefinitely until it is aborted.\n if (this.totalDuration === null) {\n return;\n }\n\n // If we have a 'getDeltaTime' function defined as part of our options then we will use it to figure out how long we have waited for.\n if (typeof options.getDeltaTime === \"function\") {\n // Get the delta time.\n const deltaTime = options.getDeltaTime();\n\n // Our delta time must be a valid number and cannot be NaN.\n if (typeof deltaTime !== \"number\" || isNaN(deltaTime)) {\n throw new Error(\"The delta time must be a valid number and not NaN.\");\n }\n\n // Update the amount of time that this node has been waiting for based on the delta time.\n this.waitedDuration += deltaTime * 1000;\n } else {\n // We are not using a delta time, so we will just work out hom much time has passed since the first update.\n this.waitedDuration = new Date().getTime() - this.initialUpdateTime;\n }\n\n // Have we waited long enough?\n if (this.waitedDuration >= this.totalDuration) {\n // We have finished waiting!\n this.setState(State.SUCCEEDED);\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => {\n if (this.duration !== null) {\n return `WAIT ${this.duration}ms`;\n } else if (this.durationMin !== null && this.durationMax !== null) {\n return `WAIT ${this.durationMin}ms-${this.durationMax}ms`;\n } else {\n return \"WAIT\";\n }\n };\n}\n", "import Node from \"../Node\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\n\n/**\n * A decorator node that wraps a single child node.\n */\nexport default abstract class Decorator extends Node {\n /**\n * @param type The node type.\n * @param attributes The node attributes.\n * @param child The child node.\n */\n constructor(type: string, attributes: Attribute[], protected child: Node) {\n super(type, attributes, []);\n }\n\n /**\n * Gets whether this node is a leaf node.\n */\n isLeafNode = () => false;\n\n /**\n * Gets the children of this node.\n */\n getChildren = () => [this.child];\n\n /**\n * Reset the state of the node.\n */\n reset = () => {\n // Reset the state of this node.\n this.setState(State.READY);\n\n // Reset the state of the child node.\n this.child.reset();\n };\n\n /**\n * Abort the running of this node.\n * @param agent The agent.\n */\n abort = (agent: Agent) => {\n // There is nothing to do if this node is not in the running state.\n if (!this.is(State.RUNNING)) {\n return;\n }\n\n // Abort the child node.\n this.child.abort(agent);\n\n // Reset the state of this node.\n this.reset();\n\n this.getAttribute(\"exit\")?.callAgentFunction(agent, false, true);\n };\n}\n", "import Node from \"../Node\";\nimport Decorator from \"./Decorator\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A Root node.\n * The root node will have a single child.\n */\nexport default class Root extends Decorator {\n /**\n * @param attributes The node attributes.\n * @param child The child node.\n */\n constructor(attributes: Attribute[], child: Node) {\n super(\"root\", attributes, child);\n }\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // If the child has never been updated or is running then we will need to update it now.\n if (this.child.getState() === State.READY || this.child.getState() === State.RUNNING) {\n // Update the child of this node.\n this.child.update(agent, options);\n }\n\n // The state of the root node is the state of its child.\n this.setState(this.child.getState());\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => \"ROOT\";\n}\n", "import Node from \"../Node\";\nimport Decorator from \"./Decorator\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A REPEAT node.\n * The node has a single child which can have:\n * -- A number of iterations for which to repeat the child node.\n * -- An infinite repeat loop if neither an iteration count or a condition function is defined.\n * The REPEAT node will stop and have a 'FAILED' state if its child is ever in a 'FAILED' state after an update.\n * The REPEAT node will attempt to move on to the next iteration if its child is ever in a 'SUCCEEDED' state.\n */\nexport default class Repeat extends Decorator {\n /**\n * @param attributes The node attributes.\n * @param iterations The number of iterations to repeat the child node.\n * @param iterationsMin The minimum possible number of iterations to repeat the child node.\n * @param iterationsMax The maximum possible number of iterations to repeat the child node.\n * @param child The child node.\n */\n constructor(\n attributes: Attribute[],\n private iterations: number | null,\n private iterationsMin: number | null,\n private iterationsMax: number | null,\n child: Node\n ) {\n super(\"repeat\", attributes, child);\n }\n\n /**\n * The number of target iterations to make.\n */\n private targetIterationCount: number | null = null;\n\n /**\n * The current iteration count.\n */\n private currentIterationCount: number = 0;\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // If this node is in the READY state then we need to reset the child and the target iteration count.\n if (this.is(State.READY)) {\n // Reset the child node.\n this.child.reset();\n\n // Reset the current iteration count.\n this.currentIterationCount = 0;\n\n // Set the target iteration count.\n this.setTargetIterationCount(options);\n }\n\n // Do a check to see if we can iterate. If we can then this node will move into the 'RUNNING' state.\n // If we cannot iterate then we have hit our target iteration count, which means that the node has succeeded.\n if (this.canIterate()) {\n // This node is in the running state and can do its initial iteration.\n this.setState(State.RUNNING);\n\n // We may have already completed an iteration, meaning that the child node will be in the SUCCEEDED state.\n // If this is the case then we will have to reset the child node now.\n if (this.child.getState() === State.SUCCEEDED) {\n this.child.reset();\n }\n\n // Update the child of this node.\n this.child.update(agent, options);\n\n // If the child moved into the FAILED state when we updated it then there is nothing left to do and this node has also failed.\n // If it has moved into the SUCCEEDED state then we have completed the current iteration.\n if (this.child.getState() === State.FAILED) {\n // The child has failed, meaning that this node has failed.\n this.setState(State.FAILED);\n\n return;\n } else if (this.child.getState() === State.SUCCEEDED) {\n // We have completed an iteration.\n this.currentIterationCount += 1;\n }\n } else {\n // This node is in the 'SUCCEEDED' state as we cannot iterate any more.\n this.setState(State.SUCCEEDED);\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => {\n if (this.iterations !== null) {\n return `REPEAT ${this.iterations}x`;\n } else if (this.iterationsMin !== null && this.iterationsMax !== null) {\n return `REPEAT ${this.iterationsMin}x-${this.iterationsMax}x`;\n } else {\n return \"REPEAT\";\n }\n };\n\n /**\n * Reset the state of the node.\n */\n reset = () => {\n // Reset the state of this node.\n this.setState(State.READY);\n\n // Reset the current iteration count.\n this.currentIterationCount = 0;\n\n // Reset the child node.\n this.child.reset();\n };\n\n /**\n * Gets whether an iteration can be made.\n * @returns Whether an iteration can be made.\n */\n private canIterate = () => {\n if (this.targetIterationCount !== null) {\n // We can iterate as long as we have not reached our target iteration count.\n return this.currentIterationCount < this.targetIterationCount;\n }\n\n // If neither an iteration count or a condition function were defined then we can iterate indefinitely.\n return true;\n };\n\n /**\n * Sets the target iteration count.\n * @param options The behaviour tree options object.\n */\n private setTargetIterationCount = (options: BehaviourTreeOptions) => {\n // Are we dealing with an explicit iteration count or will we be randomly picking a iteration count between the min and max iteration count.\n if (this.iterations !== null) {\n this.targetIterationCount = this.iterations;\n } else if (this.iterationsMin !== null && this.iterationsMax !== null) {\n // We will be picking a random iteration count between a min and max iteration count, if the optional 'random'\n // behaviour tree function option is defined then we will be using that, otherwise we will fall back to using Math.random.\n const random = typeof options.random === \"function\" ? options.random : Math.random;\n\n // Pick a random iteration count between a min and max iteration count.\n this.targetIterationCount = Math.floor(\n random() * (this.iterationsMax - this.iterationsMin + 1) + this.iterationsMin\n );\n } else {\n this.targetIterationCount = null;\n }\n };\n}\n", "import Node from \"../Node\";\nimport Decorator from \"./Decorator\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A RETRY node.\n * The node has a single child which can have:\n * -- A number of iterations for which to repeat the child node.\n * -- An infinite repeat loop if neither an iteration count or a condition function is defined.\n * The RETRY node will stop and have a 'SUCCEEDED' state if its child is ever in a 'SUCCEEDED' state after an update.\n * The RETRY node will attempt to move on to the next iteration if its child is ever in a 'FAILED' state.\n */\nexport default class Retry extends Decorator {\n /**\n * @param attributes The node attributes.\n * @param attempts The number of attempts to retry the child node.\n * @param attemptsMin The minimum possible number of attempts to retry the child node.\n * @param attemptsMax The maximum possible number of attempts to retry the child node.\n * @param child The child node.\n */\n constructor(\n attributes: Attribute[],\n private attempts: number | null,\n private attemptsMin: number | null,\n private attemptsMax: number | null,\n child: Node\n ) {\n super(\"retry\", attributes, child);\n }\n\n /**\n * The number of target attempts to make.\n */\n private targetAttemptCount: number | null = null;\n\n /**\n * The current attempt count.\n */\n private currentAttemptCount: number = 0;\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // If this node is in the READY state then we need to reset the child and the target attempt count.\n if (this.is(State.READY)) {\n // Reset the child node.\n this.child.reset();\n\n // Reset the current attempt count.\n this.currentAttemptCount = 0;\n\n // Set the target attempt count.\n this.setTargetAttemptCount(options);\n }\n\n // Do a check to see if we can attempt. If we can then this node will move into the 'RUNNING' state.\n // If we cannot attempt then we have hit our target attempt count, which means that the node has succeeded.\n if (this.canAttempt()) {\n // This node is in the running state and can do its initial attempt.\n this.setState(State.RUNNING);\n\n // We may have already completed an attempt, meaning that the child node will be in the FAILED state.\n // If this is the case then we will have to reset the child node now.\n if (this.child.getState() === State.FAILED) {\n this.child.reset();\n }\n\n // Update the child of this node.\n this.child.update(agent, options);\n\n // If the child moved into the SUCCEEDED state when we updated it then there is nothing left to do and this node has also succeeded.\n // If it has moved into the FAILED state then we have completed the current attempt.\n if (this.child.getState() === State.SUCCEEDED) {\n // The child has succeeded, meaning that this node has succeeded.\n this.setState(State.SUCCEEDED);\n\n return;\n } else if (this.child.getState() === State.FAILED) {\n // We have completed an attempt.\n this.currentAttemptCount += 1;\n }\n } else {\n // This node is in the 'FAILED' state as we cannot iterate any more.\n this.setState(State.FAILED);\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => {\n if (this.attempts !== null) {\n return `RETRY ${this.attempts}x`;\n } else if (this.attemptsMin !== null && this.attemptsMax !== null) {\n return `RETRY ${this.attemptsMin}x-${this.attemptsMax}x`;\n } else {\n return \"RETRY\";\n }\n };\n\n /**\n * Reset the state of the node.\n */\n reset = () => {\n // Reset the state of this node.\n this.setState(State.READY);\n\n // Reset the current attempt count.\n this.currentAttemptCount = 0;\n\n // Reset the child node.\n this.child.reset();\n };\n\n /**\n * Gets whether an attempt can be made.\n * @returns Whether an attempt can be made.\n */\n canAttempt = () => {\n if (this.targetAttemptCount !== null) {\n // We can attempt as long as we have not reached our target attempt count.\n return this.currentAttemptCount < this.targetAttemptCount;\n }\n\n // If neither an attempt count or a condition function were defined then we can attempt indefinitely.\n return true;\n };\n\n /**\n * Sets the target attempt count.\n * @param options The behaviour tree options object.\n */\n setTargetAttemptCount = (options: BehaviourTreeOptions) => {\n // Are we dealing with an explicit attempt count or will we be randomly picking an attempt count between the min and max attempt count.\n if (this.attempts !== null) {\n this.targetAttemptCount = this.attempts;\n } else if (this.attemptsMin !== null && this.attemptsMax !== null) {\n // We will be picking a random attempt count between a min and max attempt count, if the optional 'random'\n // behaviour tree function option is defined then we will be using that, otherwise we will fall back to using Math.random.\n const random = typeof options.random === \"function\" ? options.random : Math.random;\n\n // Pick a random attempt count between a min and max attempt count.\n this.targetAttemptCount = Math.floor(\n random() * (this.attemptsMax - this.attemptsMin + 1) + this.attemptsMin\n );\n } else {\n this.targetAttemptCount = null;\n }\n };\n}\n", "import Decorator from \"./Decorator\";\nimport State from \"../../State\";\nimport Node from \"../Node\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A Flip node.\n * This node wraps a single child and will flip the state of the child state.\n */\nexport default class Flip extends Decorator {\n /**\n * @param attributes The node attributes.\n * @param child The child node.\n */\n constructor(attributes: Attribute[], child: Node) {\n super(\"flip\", attributes, child);\n }\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // If the child has never been updated or is running then we will need to update it now.\n if (this.child.getState() === State.READY || this.child.getState() === State.RUNNING) {\n this.child.update(agent, options);\n }\n\n // The state of this node will depend in the state of its child.\n switch (this.child.getState()) {\n case State.RUNNING:\n this.setState(State.RUNNING);\n break;\n\n case State.SUCCEEDED:\n this.setState(State.FAILED);\n break;\n\n case State.FAILED:\n this.setState(State.SUCCEEDED);\n break;\n\n default:\n this.setState(State.READY);\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => \"FLIP\";\n}\n", "import Node from \"../Node\";\nimport Decorator from \"./Decorator\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A Succeed node.\n * This node wraps a single child and will always move to the 'SUCCEEDED' state when the child moves to a 'SUCCEEDED' or 'FAILED' state.\n */\nexport default class Succeed extends Decorator {\n /**\n * @param attributes The node attributes.\n * @param child The child node.\n */\n constructor(attributes: Attribute[], child: Node) {\n super(\"succeed\", attributes, child);\n }\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // If the child has never been updated or is running then we will need to update it now.\n if (this.child.getState() === State.READY || this.child.getState() === State.RUNNING) {\n this.child.update(agent, options);\n }\n\n // The state of this node will depend in the state of its child.\n switch (this.child.getState()) {\n case State.RUNNING:\n this.setState(State.RUNNING);\n break;\n\n case State.SUCCEEDED:\n case State.FAILED:\n this.setState(State.SUCCEEDED);\n break;\n\n default:\n this.setState(State.READY);\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => \"SUCCEED\";\n}\n", "import Node from \"../Node\";\nimport Decorator from \"./Decorator\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A Fail node.\n * This node wraps a single child and will always move to the 'FAILED' state when the child moves to a 'SUCCEEDED' or 'FAILED' state.\n */\nexport default class Fail extends Decorator {\n /**\n * @param attributes The node attributes.\n * @param child The child node.\n */\n constructor(attributes: Attribute[], child: Node) {\n super(\"fail\", attributes, child);\n }\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // If the child has never been updated or is running then we will need to update it now.\n if (this.child.getState() === State.READY || this.child.getState() === State.RUNNING) {\n this.child.update(agent, options);\n }\n\n // The state of this node will depend in the state of its child.\n switch (this.child.getState()) {\n case State.RUNNING:\n this.setState(State.RUNNING);\n break;\n\n case State.SUCCEEDED:\n case State.FAILED:\n this.setState(State.FAILED);\n break;\n\n default:\n this.setState(State.READY);\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => \"FAIL\";\n}\n", "import createLotto from \"lotto-draw\";\n\nimport Node from \"../Node\";\nimport Composite from \"./Composite\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A LOTTO node.\n * A winning child is picked on the initial update of this node, based on ticket weighting.\n * The state of this node will match the state of the winning child.\n */\nexport default class Lotto extends Composite {\n /**\n * @param attributes The node attributes.\n * @param tickets The child node tickets.\n * @param children The child nodes.\n */\n constructor(attributes: Attribute[], private tickets: number[], children: Node[]) {\n super(\"lotto\", attributes, children);\n }\n\n /**\n * The child node selected to be the active one.\n */\n private selectedChild: Node | undefined;\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // If this node is in the READY state then we need to pick a winning child node.\n if (this.is(State.READY)) {\n // Create a lotto draw with which to randomly pick a child node to become the active one.\n const lottoDraw = createLotto({\n // Hook up the optional 'random' behaviour tree function option to the one used by 'lotto-draw'.\n random: options.random,\n // Pass in each child node as a participant in the lotto draw with their respective ticket count.\n participants: this.children.map((child, index) => [child, this.tickets[index] || 1])\n });\n\n // Randomly pick a child based on ticket weighting, this will become the active child for this composite node.\n this.selectedChild = lottoDraw.draw() || undefined;\n }\n\n // If something went wrong and we don't have an active child then we should throw an error.\n if (!this.selectedChild) {\n throw new Error(\"failed to update lotto node as it has no active child\");\n }\n\n // If the selected child has never been updated or is running then we will need to update it now.\n if (this.selectedChild.getState() === State.READY || this.selectedChild.getState() === State.RUNNING) {\n this.selectedChild.update(agent, options);\n }\n\n // The state of the lotto node is the state of its selected child.\n this.setState(this.selectedChild.getState());\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => (this.tickets.length ? `LOTTO [${this.tickets.join(\",\")}]` : \"LOTTO\");\n}\n", "import Node from \"../Node\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\n\n/**\n * A composite node that wraps child nodes.\n */\nexport default abstract class Composite extends Node {\n /**\n * @param type The node type.\n * @param attributes The node attributes.\n * @param children The child nodes.\n */\n constructor(type: string, attributes: Attribute[], protected children: Node[]) {\n super(type, attributes, []);\n }\n\n /**\n * Gets whether this node is a leaf node.\n */\n isLeafNode = () => false;\n\n /**\n * Gets the children of this node.\n */\n getChildren = () => this.children;\n\n /**\n * Reset the state of the node.\n */\n reset = () => {\n // Reset the state of this node.\n this.setState(State.READY);\n\n // Reset the state of any child nodes.\n this.getChildren().forEach((child) => child.reset());\n };\n\n /**\n * Abort the running of this node.\n * @param agent The agent.\n */\n abort = (agent: Agent) => {\n // There is nothing to do if this node is not in the running state.\n if (!this.is(State.RUNNING)) {\n return;\n }\n\n // Abort any child nodes.\n this.getChildren().forEach((child) => child.abort(agent));\n\n // Reset the state of this node.\n this.reset();\n\n this.getAttribute(\"exit\")?.callAgentFunction(agent, false, true);\n };\n}\n", "import Composite from \"./Composite\";\nimport Node from \"../Node\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A SELECTOR node.\n * The child nodes are executed in sequence until one succeeds or all fail.\n */\nexport default class Selector extends Composite {\n /**\n * @param attributes The node attributes.\n * @param children The child nodes.\n */\n constructor(attributes: Attribute[], protected children: Node[]) {\n super(\"selector\", attributes, children);\n }\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // Iterate over all of the children of this node.\n for (const child of this.children) {\n // If the child has never been updated or is running then we will need to update it now.\n if (child.getState() === State.READY || child.getState() === State.RUNNING) {\n // Update the child of this node.\n child.update(agent, options);\n }\n\n // If the current child has a state of 'SUCCEEDED' then this node is also a 'SUCCEEDED' node.\n if (child.getState() === State.SUCCEEDED) {\n // This node is a 'SUCCEEDED' node.\n this.setState(State.SUCCEEDED);\n\n // There is no need to check the rest of the selector nodes.\n return;\n }\n\n // If the current child has a state of 'FAILED' then we should move on to the next child.\n if (child.getState() === State.FAILED) {\n // Find out if the current child is the last one in the selector.\n // If it is then this sequence node has also failed.\n if (this.children.indexOf(child) === this.children.length - 1) {\n // This node is a 'FAILED' node.\n this.setState(State.FAILED);\n\n // There is no need to check the rest of the selector as we have completed it.\n return;\n } else {\n // The child node failed, try the next one.\n continue;\n }\n }\n\n // The node should be in the 'RUNNING' state.\n if (child.getState() === State.RUNNING) {\n // This node is a 'RUNNING' node.\n this.setState(State.RUNNING);\n\n // There is no need to check the rest of the selector as the current child is still running.\n return;\n }\n\n // The child node was not in an expected state.\n throw new Error(\"child node was not in an expected state.\");\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => \"SELECTOR\";\n}\n", "import Composite from \"./Composite\";\nimport Node from \"../Node\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A SEQUENCE node.\n * The child nodes are executed in sequence until one fails or all succeed.\n */\nexport default class Sequence extends Composite {\n /**\n * @param attributes The node attributes.\n * @param children The child nodes.\n */\n constructor(attributes: Attribute[], protected children: Node[]) {\n super(\"sequence\", attributes, children);\n }\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // Iterate over all of the children of this node.\n for (const child of this.children) {\n // If the child has never been updated or is running then we will need to update it now.\n if (child.getState() === State.READY || child.getState() === State.RUNNING) {\n // Update the child of this node.\n child.update(agent, options);\n }\n\n // If the current child has a state of 'SUCCEEDED' then we should move on to the next child.\n if (child.getState() === State.SUCCEEDED) {\n // Find out if the current child is the last one in the sequence.\n // If it is then this sequence node has also succeeded.\n if (this.children.indexOf(child) === this.children.length - 1) {\n // This node is a 'SUCCEEDED' node.\n this.setState(State.SUCCEEDED);\n\n // There is no need to check the rest of the sequence as we have completed it.\n return;\n } else {\n // The child node succeeded, but we have not finished the sequence yet.\n continue;\n }\n }\n\n // If the current child has a state of 'FAILED' then this node is also a 'FAILED' node.\n if (child.getState() === State.FAILED) {\n // This node is a 'FAILED' node.\n this.setState(State.FAILED);\n\n // There is no need to check the rest of the sequence.\n return;\n }\n\n // The node should be in the 'RUNNING' state.\n if (child.getState() === State.RUNNING) {\n // This node is a 'RUNNING' node.\n this.setState(State.RUNNING);\n\n // There is no need to check the rest of the sequence as the current child is still running.\n return;\n }\n\n // The child node was not in an expected state.\n throw new Error(\"child node was not in an expected state.\");\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => \"SEQUENCE\";\n}\n", "import Composite from \"./Composite\";\nimport State from \"../../State\";\nimport Node from \"../Node\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A PARALLEL node.\n * The child nodes are executed concurrently until one fails or all succeed.\n */\nexport default class Parallel extends Composite {\n /**\n * @param attributes The node attributes.\n * @param children The child nodes.\n */\n constructor(attributes: Attribute[], children: Node[]) {\n super(\"parallel\", attributes, children);\n }\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // Keep a count of the number of succeeded child nodes.\n let succeededCount = 0;\n\n let hasChildFailed = false;\n\n // Iterate over all of the children of this node.\n for (const child of this.children) {\n // If the child has never been updated or is running then we will need to update it now.\n if (child.getState() === State.READY || child.getState() === State.RUNNING) {\n // Update the child of this node.\n child.update(agent, options);\n }\n\n // If the current child has a state of 'SUCCEEDED' then we should move on to the next child.\n if (child.getState() === State.SUCCEEDED) {\n // The child node has succeeded, keep track of this to determine if all children have.\n succeededCount++;\n\n // The child node succeeded, but we have not finished checking every child node yet.\n continue;\n }\n\n // If the current child has a state of 'FAILED' then this node is also a 'FAILED' node.\n if (child.getState() === State.FAILED) {\n hasChildFailed = true;\n\n // There is no need to check the rest of the children.\n break;\n }\n\n // The node should be in the 'RUNNING' state.\n if (child.getState() !== State.RUNNING) {\n // The child node was not in an expected state.\n throw new Error(\"child node was not in an expected state.\");\n }\n }\n\n if (hasChildFailed) {\n // This node is a 'FAILED' node.\n this.setState(State.FAILED);\n\n // Abort every running child.\n for (const child of this.children) {\n if (child.getState() === State.RUNNING) {\n child.abort(agent);\n }\n }\n } else {\n // If all children have succeeded then this node has also succeeded, otherwise it is still running.\n this.setState(succeededCount === this.children.length ? State.SUCCEEDED : State.RUNNING);\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => \"PARALLEL\";\n}\n", "import { AnyArgument } from \"../RootAstNodesBuilder\";\nimport Guard from \"./guards/Guard\";\n\nexport type AttributeDetails = {\n /** The attribute type. */\n type: string;\n\n /** The attribute arguments. */\n args: AnyArgument[];\n};\n\n/**\n * A base node attribute.\n */\nexport default abstract class Attribute {\n /**\n * @param type The node attribute type.\n * @param args The array of attribute argument definitions.\n */\n constructor(protected type: string, protected args: AnyArgument[]) {}\n\n /**\n * Gets the type of the attribute.\n */\n getType = () => this.type;\n\n /**\n * Gets the array of attribute argument definitions.\n */\n getArguments = () => this.args;\n\n /**\n * Gets the attribute details.\n */\n abstract getDetails(): TAttributeDetails;\n\n /**\n * Gets whether this attribute is a guard.\n */\n abstract isGuard: () => this is Guard;\n}\n", "import { Agent } from \"../../Agent\";\nimport { AnyArgument } from \"../../RootAstNodesBuilder\";\nimport Attribute, { AttributeDetails } from \"../Attribute\";\n\nexport type GuardAttributeDetails = {\n /** The name of the condition function that determines whether the guard is satisfied. */\n condition: string;\n} & AttributeDetails;\n\n/**\n * A base node guard attribute.\n */\nexport default abstract class Guard extends Attribute {\n /**\n * @param type The node attribute type.\n * @param args The array of decorator argument definitions.\n * @param condition The name of the condition function that determines whether the guard is satisfied.\n */\n constructor(type: string, args: AnyArgument[], private condition: string) {\n super(type, args);\n }\n\n /**\n * Gets the name of the condition function that determines whether the guard is satisfied.\n */\n getCondition = () => this.condition;\n\n /**\n * Gets whether this attribute is a guard.\n */\n isGuard = () => true;\n\n /**\n * Gets the attribute details.\n */\n getDetails(): GuardAttributeDetails {\n return {\n type: this.getType(),\n args: this.getArguments(),\n condition: this.getCondition()\n };\n }\n\n /**\n * Gets whether the guard is satisfied.\n * @param agent The agent.\n * @returns Whether the guard is satisfied.\n */\n abstract isSatisfied(agent: Agent): boolean;\n}\n", "import Guard from \"./Guard\";\nimport Lookup from \"../../Lookup\";\nimport { Agent } from \"../../Agent\";\nimport { AnyArgument } from \"../../RootAstNodesBuilder\";\n\n/**\n * A WHILE guard which is satisfied as long as the given condition remains true.\n */\nexport default class While extends Guard {\n /**\n * @param condition The name of the condition function that determines whether the guard is satisfied.\n * @param args The array of decorator argument definitions.\n */\n constructor(condition: string, args: AnyArgument[]) {\n super(\"while\", args, condition);\n }\n\n /**\n * Gets whether the guard is satisfied.\n * @param agent The agent.\n * @returns Whether the guard is satisfied.\n */\n isSatisfied = (agent: Agent) => {\n // Attempt to get the invoker for the condition function.\n const conditionFuncInvoker = Lookup.getFuncInvoker(agent, this.getCondition());\n\n // The condition function should be defined.\n if (conditionFuncInvoker === null) {\n throw new Error(\n `cannot evaluate node guard as the condition '${this.getCondition()}' function is not defined on the agent and has not been registered`\n );\n }\n\n // Call the condition function to determine whether this guard is satisfied.\n return !!conditionFuncInvoker(this.args);\n };\n}\n", "import Guard from \"./Guard\";\nimport Lookup from \"../../Lookup\";\nimport { Agent } from \"../../Agent\";\nimport { AnyArgument } from \"../../RootAstNodesBuilder\";\n\n/**\n * An UNTIL guard which is satisfied as long as the given condition remains false.\n */\nexport default class Until extends Guard {\n /**\n * @param condition The name of the condition function that determines whether the guard is satisfied.\n * @param args The array of decorator argument definitions.\n */\n constructor(condition: string, args: AnyArgument[]) {\n super(\"until\", args, condition);\n }\n\n /**\n * Gets whether the guard is satisfied.\n * @param agent The agent.\n * @returns Whether the guard is satisfied.\n */\n isSatisfied = (agent: Agent) => {\n // Attempt to get the invoker for the condition function.\n const conditionFuncInvoker = Lookup.getFuncInvoker(agent, this.getCondition());\n\n // The condition function should be defined.\n if (conditionFuncInvoker === null) {\n throw new Error(\n `cannot evaluate node guard as the condition '${this.getCondition()}' function is not defined on the agent and has not been registered`\n );\n }\n\n // Call the condition function to determine whether this guard is satisfied.\n return !!!conditionFuncInvoker(this.args);\n };\n}\n", "import { Agent } from \"../../Agent\";\nimport { AnyArgument } from \"../../RootAstNodesBuilder\";\nimport Attribute, { AttributeDetails } from \"../Attribute\";\n\nexport type CallbackAttributeDetails = {\n /** The name of the agent function that is called. */\n functionName: string;\n} & AttributeDetails;\n\n/**\n * A base node callback attribute.\n */\nexport default abstract class Callback extends Attribute {\n /**\n * @param type The node attribute type.\n * @param args The array of decorator argument definitions.\n * @param functionName The name of the agent function to call.\n */\n constructor(type: string, args: AnyArgument[], private functionName: string) {\n super(type, args);\n }\n\n /**\n * Gets the name of the agent function to call.\n */\n getFunctionName = () => this.functionName;\n\n /**\n * Gets whether this attribute is a guard.\n */\n isGuard = () => false;\n\n /**\n * Gets the attribute details.\n */\n getDetails(): CallbackAttributeDetails {\n return {\n type: this.getType(),\n args: this.getArguments(),\n functionName: this.getFunctionName()\n };\n }\n\n /**\n * Attempt to call the agent function that this callback refers to.\n * @param agent The agent.\n */\n abstract callAgentFunction: (agent: Agent, isSuccess: boolean, isAborted: boolean) => void;\n}\n", "import Callback from \"./Callback\";\nimport Lookup from \"../../Lookup\";\nimport { Agent } from \"../../Agent\";\nimport { AnyArgument } from \"../../RootAstNodesBuilder\";\n\n/**\n * An ENTRY callback which defines an agent function to call when the associated node is updated and moves out of running state.\n */\nexport default class Entry extends Callback {\n /**\n * @param functionName The name of the agent function to call.\n * @param args The array of callback argument definitions.\n */\n constructor(functionName: string, args: AnyArgument[]) {\n super(\"entry\", args, functionName);\n }\n\n /**\n * Attempt to call the agent function that this callback refers to.\n * @param agent The agent.\n */\n callAgentFunction = (agent: Agent) => {\n // Attempt to get the invoker for the callback function.\n const callbackFuncInvoker = Lookup.getFuncInvoker(agent, this.getFunctionName());\n\n // The callback function should be defined.\n if (callbackFuncInvoker === null) {\n throw new Error(\n `cannot call entry function '${this.getFunctionName()}' as is not defined on the agent and has not been registered`\n );\n }\n\n // Call the callback function.\n callbackFuncInvoker(this.args);\n };\n}\n", "import Callback from \"./Callback\";\nimport Lookup, { AnyExitArgument } from \"../../Lookup\";\nimport { Agent } from \"../../Agent\";\nimport { AnyArgument } from \"../../RootAstNodesBuilder\";\n\n/**\n * An EXIT callback which defines an agent function to call when the associated node is updated and moves to a finished state or is aborted.\n */\nexport default class Exit extends Callback {\n /**\n * @param functionName The name of the agent function to call.\n * @param args The array of callback argument definitions.\n */\n constructor(functionName: string, args: AnyArgument[]) {\n super(\"exit\", args, functionName);\n }\n\n /**\n * Attempt to call the agent function that this callback refers to.\n * @param agent The agent.\n * @param isSuccess Whether the decorated node was left with a success state.\n * @param isAborted Whether the decorated node was aborted.\n */\n callAgentFunction = (agent: Agent, isSuccess: boolean, isAborted: boolean) => {\n // Attempt to get the invoker for the callback function.\n const callbackFuncInvoker = Lookup.getFuncInvoker(agent, this.getFunctionName());\n\n // The callback function should be defined.\n if (callbackFuncInvoker === null) {\n throw new Error(\n `cannot call exit function '${this.getFunctionName()}' as is not defined on the agent and has not been registered`\n );\n }\n\n // Call the callback function\n callbackFuncInvoker([{ value: { succeeded: isSuccess, aborted: isAborted } }, ...this.args]);\n };\n}\n", "import Callback from \"./Callback\";\nimport Lookup from \"../../Lookup\";\nimport { Agent } from \"../../Agent\";\nimport { AnyArgument } from \"../../RootAstNodesBuilder\";\n\n/**\n * A STEP callback which defines an agent function to call when the associated node is updated.\n */\nexport default class Step extends Callback {\n /**\n * @param functionName The name of the agent function to call.\n * @param args The array of callback argument definitions.\n */\n constructor(functionName: string, args: AnyArgument[]) {\n super(\"step\", args, functionName);\n }\n\n /**\n * Attempt to call the agent function that this callback refers to.\n * @param agent The agent.\n */\n callAgentFunction = (agent: Agent) => {\n // Attempt to get the invoker for the callback function.\n const callbackFuncInvoker = Lookup.getFuncInvoker(agent, this.getFunctionName());\n\n // The callback function should be defined.\n if (callbackFuncInvoker === null) {\n throw new Error(\n `cannot call step function '${this.getFunctionName()}' as is not defined on the agent and has not been registered`\n );\n }\n\n // Call the callback function.\n callbackFuncInvoker(this.args);\n };\n}\n", "import Action from \"./nodes/leaf/Action\";\nimport Condition from \"./nodes/leaf/Condition\";\nimport Wait from \"./nodes/leaf/Wait\";\nimport Root from \"./nodes/decorator/Root\";\nimport Repeat from \"./nodes/decorator/Repeat\";\nimport Retry from \"./nodes/decorator/Retry\";\nimport Flip from \"./nodes/decorator/Flip\";\nimport Succeed from \"./nodes/decorator/Succeed\";\nimport Fail from \"./nodes/decorator/Fail\";\nimport Lotto from \"./nodes/composite/Lotto\";\nimport Selector from \"./nodes/composite/Selector\";\nimport Sequence from \"./nodes/composite/Sequence\";\nimport Parallel from \"./nodes/composite/Parallel\";\nimport Node from \"./nodes/Node\";\nimport While from \"./attributes/guards/While\";\nimport Until from \"./attributes/guards/Until\";\nimport Entry from \"./attributes/callbacks/Entry\";\nimport Exit from \"./attributes/callbacks/Exit\";\nimport Step from \"./attributes/callbacks/Step\";\nimport Callback from \"./attributes/callbacks/Callback\";\nimport Guard from \"./attributes/guards/Guard\";\nimport Attribute from \"./attributes/Attribute\";\nimport Composite from \"./nodes/composite/Composite\";\nimport Decorator from \"./nodes/decorator/Decorator\";\nimport Leaf from \"./nodes/leaf/Leaf\";\n\nexport type Argument = {\n value: T;\n type: string; // Used for validation.\n};\ntype NullArgument = Argument & {\n type: \"null\";\n};\ntype BooleanArgument = Argument & {\n type: \"boolean\";\n};\ntype NumberArgument = Argument & {\n type: \"number\";\n isInteger: boolean; // Used for validation.\n};\ntype StringPlaceholderArgument = Argument & {\n type: \"string\";\n};\ntype IdentifierArgument = Argument & {\n type: \"identifier\";\n};\nexport type AnyArgument =\n | NullArgument\n | BooleanArgument\n | NumberArgument\n | StringPlaceholderArgument\n | IdentifierArgument;\n\n/**\n * The node attribute factories.\n */\nconst AttributeFactories: {\n [key: string]: (functionName: string, attributeArguments: AnyArgument[]) => Callback | Guard;\n} = {\n WHILE: (condition: string, attributeArguments: AnyArgument[]) => new While(condition, attributeArguments),\n UNTIL: (condition: string, attributeArguments: AnyArgument[]) => new Until(condition, attributeArguments),\n ENTRY: (functionName: string, attributeArguments: AnyArgument[]) => new Entry(functionName, attributeArguments),\n EXIT: (functionName: string, attributeArguments: AnyArgument[]) => new Exit(functionName, attributeArguments),\n STEP: (functionName: string, attributeArguments: AnyArgument[]) => new Step(functionName, attributeArguments)\n};\n\ntype Validatable = {\n children?: AstNode[];\n validate: (depth: number) => void;\n};\n\ntype NodeInstanceCreator = (\n namedRootNodeProvider: (name: string) => RootAstNode,\n visitedBranches: string[]\n) => T;\n\nexport type AstNode = Validatable & {\n type: string;\n createNodeInstance: NodeInstanceCreator;\n};\n\nexport type LeafAstNode = AstNode & {\n type: \"action\" | \"condition\" | \"wait\";\n attributes: Attribute[];\n};\n\nexport type CompositeAstNode = AstNode & {\n type: \"lotto\" | \"parallel\" | \"selector\" | \"sequence\";\n attributes: Attribute[];\n children: AstNode[];\n};\n\nexport type DecoratorAstNode = AstNode & {\n type: \"fail\" | \"flip\" | \"repeat\" | \"retry\" | \"root\" | \"succeed\";\n attributes: Attribute[];\n children: AstNode[];\n};\n\nexport type BranchAstNode = AstNode & {\n type: \"branch\";\n branchName: \"\" | string;\n};\n\nexport type LottoAstNode = CompositeAstNode & {\n type: \"lotto\";\n tickets: number[];\n};\n\nexport type RootAstNode = DecoratorAstNode & {\n type: \"root\";\n name: null | string;\n};\n\nexport type RepeatAstNode = DecoratorAstNode & {\n type: \"repeat\";\n iterations: number | null;\n iterationsMin: number | null;\n iterationsMax: number | null;\n};\n\nexport type RetryAstNode = DecoratorAstNode & {\n type: \"retry\";\n attempts: number | null;\n attemptsMin: number | null;\n attemptsMax: number | null;\n};\n\nexport type ActionAstNode = LeafAstNode & {\n type: \"action\";\n actionName: string;\n actionArguments: AnyArgument[];\n};\n\nexport type ConditionAstNode = LeafAstNode & {\n type: \"condition\";\n conditionName: string;\n conditionArguments: AnyArgument[];\n};\n\nexport type WaitAstNode = LeafAstNode & {\n type: \"wait\";\n duration: number | null;\n durationMin: number | null;\n durationMax: number | null;\n};\n\nexport type AnyAstNode =\n | BranchAstNode\n | CompositeAstNode\n | LottoAstNode\n | DecoratorAstNode\n | RootAstNode\n | RepeatAstNode\n | RetryAstNode\n | LeafAstNode\n | ActionAstNode\n | ConditionAstNode\n | WaitAstNode;\n\n/**\n * The AST node factories.\n */\nconst ASTNodeFactories = {\n ROOT: (): RootAstNode => ({\n type: \"root\",\n attributes: [],\n name: null,\n children: [],\n validate(depth: number) {\n // A root node cannot be the child of another node.\n if (depth > 1) {\n throw new Error(\"a root node cannot be the child of another node\");\n }\n\n // A root node must have a single child node.\n if (this.children.length !== 1) {\n throw new Error(\"a root node must have a single child\");\n }\n },\n createNodeInstance(namedRootNodeProvider, visitedBranches) {\n return new Root(\n this.attributes,\n this.children![0].createNodeInstance(namedRootNodeProvider, visitedBranches.slice())\n );\n }\n }),\n BRANCH: (): BranchAstNode => ({\n type: \"branch\",\n branchName: \"\",\n validate() {},\n createNodeInstance(namedRootNodeProvider, visitedBranches) {\n // Try to find the root node with a matching branch name.\n const targetRootNode = namedRootNodeProvider(this.branchName);\n\n // If we have already visited this branch then we have a circular dependency.\n if (visitedBranches.indexOf(this.branchName) !== -1) {\n throw new Error(`circular dependency found in branch node references for branch '${this.branchName}'`);\n }\n\n // If we have a target root node, then the node instance we want will be the first and only child of the referenced root node.\n if (targetRootNode) {\n return targetRootNode\n .createNodeInstance(namedRootNodeProvider, visitedBranches.concat(this.branchName))\n .getChildren()[0];\n } else {\n throw new Error(`branch references root node '${this.branchName}' which has not been defined`);\n }\n }\n }),\n SELECTOR: (): CompositeAstNode => ({\n type: \"selector\",\n attributes: [],\n children: [],\n validate() {\n // A selector node must have at least a single node.\n if (this.children.length < 1) {\n throw new Error(\"a selector node must have at least a single child\");\n }\n },\n createNodeInstance(namedRootNodeProvider, visitedBranches) {\n return new Selector(\n this.attributes,\n this.children.map((child) => child.createNodeInstance(namedRootNodeProvider, visitedBranches.slice()))\n );\n }\n }),\n SEQUENCE: (): CompositeAstNode => ({\n type: \"sequence\",\n attributes: [],\n children: [],\n validate() {\n // A sequence node must have at least a single node.\n if (this.children.length < 1) {\n throw new Error(\"a sequence node must have at least a single child\");\n }\n },\n createNodeInstance(namedRootNodeProvider, visitedBranches) {\n return new Sequence(\n this.attributes,\n this.children.map((child) => child.createNodeInstance(namedRootNodeProvider, visitedBranches.slice()))\n );\n }\n }),\n PARALLEL: (): CompositeAstNode => ({\n type: \"parallel\",\n attributes: [],\n children: [],\n validate() {\n // A parallel node must have at least a single node.\n if (this.children.length < 1) {\n throw new Error(\"a parallel node must have at least a single child\");\n }\n },\n createNodeInstance(namedRootNodeProvider, visitedBranches) {\n return new Parallel(\n this.attributes,\n this.children.map((child) => child.createNodeInstance(namedRootNodeProvider, visitedBranches.slice()))\n );\n }\n }),\n LOTTO: (): LottoAstNode => ({\n type: \"lotto\",\n attributes: [],\n children: [],\n tickets: [],\n validate() {\n // A lotto node must have at least a single node.\n if (this.children!.length < 1) {\n throw new Error(\"a lotto node must have at least a single child\");\n }\n },\n createNodeInstance(namedRootNodeProvider, visitedBranches) {\n return new Lotto(\n this.attributes,\n this.tickets!,\n this.children!.map((child) => child.createNodeInstance(namedRootNodeProvider, visitedBranches.slice()))\n );\n }\n }),\n REPEAT: (): RepeatAstNode => ({\n type: \"repeat\",\n attributes: [],\n iterations: null,\n iterationsMin: null,\n iterationsMax: null,\n children: [],\n validate() {\n // A repeat node must have a single node.\n if (this.children!.length !== 1) {\n throw new Error(\"a repeat node must have a single child\");\n }\n\n if (this.iterations !== null) {\n // A repeat node must have a positive number of iterations if defined.\n if (this.iterations < 0) {\n throw new Error(\"a repeat node must have a positive number of iterations if defined\");\n }\n } else if (this.iterationsMin !== null && this.iterationsMax !== null) {\n // A repeat node must have a positive min and max iteration count if they are defined.\n if (this.iterationsMin < 0 || this.iterationsMax < 0) {\n throw new Error(\n \"a repeat node must have a positive minimum and maximum iteration count if defined\"\n );\n }\n\n // A repeat node must not have an minimum iteration count that exceeds the maximum iteration count.\n if (this.iterationsMin > this.iterationsMax) {\n throw new Error(\n \"a repeat node must not have a minimum iteration count that exceeds the maximum iteration count\"\n );\n }\n } else {\n // If we have no explicit iteration count or a minimum and maximum iteration count set then we are dealing with a repeat node that iterates indefinitely.\n }\n },\n createNodeInstance(namedRootNodeProvider, visitedBranches) {\n return new Repeat(\n this.attributes,\n this.iterations,\n this.iterationsMin,\n this.iterationsMax,\n this.children![0].createNodeInstance(namedRootNodeProvider, visitedBranches.slice())\n );\n }\n }),\n RETRY: (): RetryAstNode => ({\n type: \"retry\",\n attributes: [],\n attempts: null,\n attemptsMin: null,\n attemptsMax: null,\n children: [],\n validate() {\n // A retry node must have a single node.\n if (this.children!.length !== 1) {\n throw new Error(\"a retry node must have a single child\");\n }\n\n if (this.attempts !== null) {\n // A retry node must have a positive number of attempts if defined.\n if (this.attempts < 0) {\n throw new Error(\"a retry node must have a positive number of attempts if defined\");\n }\n } else if (this.attemptsMin !== null && this.attemptsMax !== null) {\n // A retry node must have a positive min and max attempts count if they are defined.\n if (this.attemptsMin < 0 || this.attemptsMax < 0) {\n throw new Error(\"a retry node must have a positive minimum and maximum attempt count if defined\");\n }\n\n // A retry node must not have a minimum attempt count that exceeds the maximum attempt count.\n if (this.attemptsMin > this.attemptsMax) {\n throw new Error(\n \"a retry node must not have a minimum attempt count that exceeds the maximum attempt count\"\n );\n }\n } else {\n // If we have no explicit attempt count or a minimum and maximum attempt count set then we are dealing with a retry node that attempts indefinitely.\n }\n },\n createNodeInstance(namedRootNodeProvider, visitedBranches) {\n return new Retry(\n this.attributes,\n this.attempts,\n this.attemptsMin,\n this.attemptsMax,\n this.children![0].createNodeInstance(namedRootNodeProvider, visitedBranches.slice())\n );\n }\n }),\n FLIP: (): DecoratorAstNode => ({\n type: \"flip\",\n attributes: [],\n children: [],\n validate() {\n // A flip node must have a single node.\n if (this.children!.length !== 1) {\n throw new Error(\"a flip node must have a single child\");\n }\n },\n createNodeInstance(namedRootNodeProvider, visitedBranches) {\n return new Flip(\n this.attributes,\n this.children![0].createNodeInstance(namedRootNodeProvider, visitedBranches.slice())\n );\n }\n }),\n SUCCEED: (): DecoratorAstNode => ({\n type: \"succeed\",\n attributes: [],\n children: [],\n validate() {\n // A succeed node must have a single node.\n if (this.children!.length !== 1) {\n throw new Error(\"a succeed node must have a single child\");\n }\n },\n createNodeInstance(namedRootNodeProvider, visitedBranches) {\n return new Succeed(\n this.attributes,\n this.children![0].createNodeInstance(namedRootNodeProvider, visitedBranches.slice())\n );\n }\n }),\n FAIL: (): DecoratorAstNode => ({\n type: \"fail\",\n attributes: [],\n children: [],\n validate() {\n // A fail node must have a single node.\n if (this.children!.length !== 1) {\n throw new Error(\"a fail node must have a single child\");\n }\n },\n createNodeInstance(namedRootNodeProvider, visitedBranches) {\n return new Fail(\n this.attributes,\n this.children![0].createNodeInstance(namedRootNodeProvider, visitedBranches.slice())\n );\n }\n }),\n WAIT: (): WaitAstNode => ({\n type: \"wait\",\n attributes: [],\n duration: null,\n durationMin: null,\n durationMax: null,\n validate() {\n if (this.duration !== null) {\n // If an explict duration was defined then it must be a positive number.\n if (this.duration < 0) {\n throw new Error(\"a wait node must have a positive duration\");\n }\n } else if (this.durationMin !== null && this.durationMax !== null) {\n // A wait node must have a positive min and max duration.\n if (this.durationMin < 0 || this.durationMax < 0) {\n throw new Error(\"a wait node must have a positive minimum and maximum duration\");\n }\n\n // A wait node must not have a minimum duration that exceeds the maximum duration.\n if (this.durationMin > this.durationMax) {\n throw new Error(\"a wait node must not have a minimum duration that exceeds the maximum duration\");\n }\n } else {\n // If we have no explicit duration or duration bounds set then we are dealing with a wait node that waits indefinitely.\n }\n },\n createNodeInstance() {\n return new Wait(this.attributes, this.duration, this.durationMin, this.durationMax);\n }\n }),\n ACTION: (): ActionAstNode => ({\n type: \"action\",\n attributes: [],\n actionName: \"\",\n actionArguments: [],\n validate() {},\n createNodeInstance() {\n return new Action(this.attributes, this.actionName!, this.actionArguments!);\n }\n }),\n CONDITION: (): ConditionAstNode => ({\n type: \"condition\",\n attributes: [],\n conditionName: \"\",\n conditionArguments: [],\n validate() {},\n createNodeInstance() {\n return new Condition(this.attributes, this.conditionName!, this.conditionArguments!);\n }\n })\n};\n\ntype OtherAstNodes = AstNode[];\n\n/**\n * Create an array of root AST nodes based on the given definition.\n * @param definition The definition to parse the AST nodes from.\n * @returns The base definition AST nodes.\n */\nexport default function buildRootASTNodes(definition: string): RootAstNode[] {\n // Swap out any node/attribute argument string literals with a placeholder and get a mapping of placeholders to original values as well as the processed definition.\n const { placeholders, processedDefinition } = substituteStringLiterals(definition);\n\n // Convert the processed definition (with substituted string literals) into an array of raw tokens.\n const tokens = parseTokensFromDefinition(processedDefinition);\n\n // There must be at least 3 tokens for the tree definition to be valid. 'ROOT', '{' and '}'.\n if (tokens.length < 3) {\n throw new Error(\"invalid token count\");\n }\n\n // We should have a matching number of '{' and '}' tokens. If not, then there are scopes that have not been properly closed.\n if (tokens.filter((token) => token === \"{\").length !== tokens.filter((token) => token === \"}\").length) {\n throw new Error(\"scope character mismatch\");\n }\n\n // Create a stack of node children arrays, starting with a definition scope.\n const stack: [RootAstNode[], ...OtherAstNodes[]] = [[]];\n const rootScope = stack[0];\n\n // We should keep processing the raw tokens until we run out of them.\n while (tokens.length) {\n // Grab the next token.\n const token = tokens.shift();\n\n const currentScope = stack[stack.length - 1] as OtherAstNodes;\n\n // How we create the next AST token depends on the current raw token value.\n switch (token!.toUpperCase()) {\n case \"ROOT\": {\n // Create a ROOT AST node.\n const node = ASTNodeFactories.ROOT();\n\n // Push the ROOT node into the current scope.\n rootScope.push(node);\n\n // We may have a root node name defined as an argument.\n if (tokens[0] === \"[\") {\n const rootArguments = getArguments(tokens, placeholders);\n\n // We should have only a single argument that is not an empty string for a root node, which is the root name identifier.\n if (rootArguments.length === 1 && rootArguments[0].type === \"identifier\") {\n // The root name will be the first and only node argument.\n node.name = rootArguments[0].value as string;\n } else {\n throw new Error(\"expected single root name argument\");\n }\n }\n\n // Try to pick any attributes off of the token stack.\n node.attributes = getAttributes(tokens, placeholders);\n\n popAndCheck(tokens, \"{\");\n\n // The new scope is that of the new ROOT nodes children.\n stack.push(node.children!);\n break;\n }\n\n case \"BRANCH\": {\n // Create a BRANCH AST node.\n const node = ASTNodeFactories.BRANCH();\n\n // Push the BRANCH node into the current scope.\n currentScope.push(node);\n\n // We must have arguments defined, as we require a branch name argument.\n if (tokens[0] !== \"[\") {\n throw new Error(\"expected single branch name argument\");\n }\n\n // The branch name will be defined as a node argument.\n const branchArguments = getArguments(tokens, placeholders);\n\n // We should have only a single identifer argument for a branch node, which is the branch name.\n if (branchArguments.length === 1 && branchArguments[0].type === \"identifier\") {\n // The branch name will be the first and only node argument.\n node.branchName = branchArguments[0].value as string;\n } else {\n throw new Error(\"expected single branch name argument\");\n }\n break;\n }\n\n case \"SELECTOR\": {\n // Create a SELECTOR AST node.\n const node = ASTNodeFactories.SELECTOR();\n\n // Push the SELECTOR node into the current scope.\n currentScope.push(node);\n\n // Try to pick any attributes off of the token stack.\n node.attributes = getAttributes(tokens, placeholders);\n\n popAndCheck(tokens, \"{\");\n\n // The new scope is that of the new SELECTOR nodes children.\n stack.push(node.children!);\n break;\n }\n\n case \"SEQUENCE\": {\n // Create a SEQUENCE AST node.\n const node = ASTNodeFactories.SEQUENCE();\n\n // Push the SEQUENCE node into the current scope.\n currentScope.push(node);\n\n // Try to pick any attributes off of the token stack.\n node.attributes = getAttributes(tokens, placeholders);\n\n popAndCheck(tokens, \"{\");\n\n // The new scope is that of the new SEQUENCE nodes children.\n stack.push(node.children!);\n break;\n }\n\n case \"PARALLEL\": {\n // Create a PARALLEL AST node.\n const node = ASTNodeFactories.PARALLEL();\n\n // Push the PARALLEL node into the current scope.\n currentScope.push(node);\n\n // Try to pick any attributes off of the token stack.\n node.attributes = getAttributes(tokens, placeholders);\n\n popAndCheck(tokens, \"{\");\n\n // The new scope is that of the new PARALLEL nodes children.\n stack.push(node.children!);\n break;\n }\n\n case \"LOTTO\": {\n // Create a LOTTO AST node.\n const node = ASTNodeFactories.LOTTO();\n\n // Push the LOTTO node into the current scope.\n currentScope.push(node);\n\n // If the next token is a '[' character then some ticket counts have been defined as arguments.\n if (tokens[0] === \"[\") {\n // Get the ticket count arguments, each argument must be a number.\n node.tickets = getArguments(\n tokens,\n placeholders,\n (arg) => arg.type === \"number\" && !!arg.isInteger,\n \"lotto node ticket counts must be integer values\"\n ).map((argument) => argument.value as number);\n }\n\n // Try to pick any attributes off of the token stack.\n node.attributes = getAttributes(tokens, placeholders);\n\n popAndCheck(tokens, \"{\");\n\n // The new scope is that of the new LOTTO nodes children.\n stack.push(node.children!);\n break;\n }\n\n case \"CONDITION\": {\n // Create a CONDITION AST node.\n const node = ASTNodeFactories.CONDITION();\n\n // Push the CONDITION node into the current scope.\n currentScope.push(node);\n\n // We must have arguments defined, as we require a condition function name argument.\n if (tokens[0] !== \"[\") {\n throw new Error(\"expected condition name identifier argument\");\n }\n\n // Grab the condition node arguments.\n const conditionArguments = getArguments(tokens, placeholders);\n\n // We should have at least a single identifier argument for a condition node, which is the condition function name.\n if (conditionArguments.length && conditionArguments[0].type === \"identifier\") {\n // The condition function name will be the first node argument.\n node.conditionName = conditionArguments.shift()!.value as string;\n } else {\n throw new Error(\"expected condition name identifier argument\");\n }\n\n // Only the first argument should have been an identifier, all following arguments must be string, number, boolean or null.\n conditionArguments\n .filter((arg) => arg.type === \"identifier\")\n .forEach((arg) => {\n throw new Error(\n \"invalid condition node argument value '\" +\n arg.value +\n \"', must be string, number, boolean or null\"\n );\n });\n\n // Any node arguments that follow the condition name identifier will be treated as condition function arguments.\n node.conditionArguments = conditionArguments;\n\n // Try to pick any attributes off of the token stack.\n node.attributes = getAttributes(tokens, placeholders);\n break;\n }\n\n case \"FLIP\": {\n // Create a FLIP AST node.\n const node = ASTNodeFactories.FLIP();\n\n // Push the Flip node into the current scope.\n currentScope.push(node);\n\n // Try to pick any attributes off of the token stack.\n node.attributes = getAttributes(tokens, placeholders);\n\n popAndCheck(tokens, \"{\");\n\n // The new scope is that of the new FLIP nodes children.\n stack.push(node.children!);\n break;\n }\n\n case \"SUCCEED\": {\n // Create a SUCCEED AST node.\n const node = ASTNodeFactories.SUCCEED();\n\n // Push the Succeed node into the current scope.\n currentScope.push(node);\n\n // Try to pick any attributes off of the token stack.\n node.attributes = getAttributes(tokens, placeholders);\n\n popAndCheck(tokens, \"{\");\n\n // The new scope is that of the new Succeed nodes children.\n stack.push(node.children!);\n break;\n }\n\n case \"FAIL\": {\n // Create a FAIL AST node.\n const node = ASTNodeFactories.FAIL();\n\n // Push the Fail node into the current scope.\n currentScope.push(node);\n\n // Try to pick any attributes off of the token stack.\n node.attributes = getAttributes(tokens, placeholders);\n\n popAndCheck(tokens, \"{\");\n\n // The new scope is that of the new Fail nodes children.\n stack.push(node.children!);\n break;\n }\n\n case \"WAIT\": {\n // Create a WAIT AST node.\n const node = ASTNodeFactories.WAIT();\n\n // Push the WAIT node into the current scope.\n currentScope.push(node);\n\n // The arguments of a wait node are optional. We may have:\n // - No node arguments, in which case the wait will be indefinite until it is aborted.\n // - One node argument which will be the explicit duration of the wait.\n // - Two node arguments which define the min and max duration bounds from which a random duration will be picked.\n if (tokens[0] === \"[\") {\n // Get the optional duration and longest duration of the wait.\n const nodeArguments = getArguments(\n tokens,\n placeholders,\n (arg) => arg.type === \"number\" && !!arg.isInteger,\n \"wait node durations must be integer values\"\n ).map((argument) => argument.value);\n\n // We may have:\n // - One node argument which will be the explicit duration of the wait.\n // - Two node arguments which define the min and max duration bounds from which a random duration will be picked.\n // - Too many arguments, which is not valid.\n if (nodeArguments.length === 1) {\n // An explicit duration was defined.\n node.duration = nodeArguments[0] as number;\n } else if (nodeArguments.length === 2) {\n // Min and max duration bounds were defined from which a random duration will be picked.\n node.durationMin = nodeArguments[0] as number;\n node.durationMax = nodeArguments[1] as number;\n } else if (nodeArguments.length > 2) {\n // An incorrect number of durations was defined.\n throw new Error(\"invalid number of wait node duration arguments defined\");\n }\n }\n\n // Try to pick any attributes off of the token stack.\n node.attributes = getAttributes(tokens, placeholders);\n break;\n }\n\n case \"REPEAT\": {\n // Create a REPEAT AST node.\n const node = ASTNodeFactories.REPEAT();\n\n // Push the REPEAT node into the current scope.\n currentScope.push(node);\n\n // The arguments of a repeat node are optional. We may have:\n // - No node arguments, in which case the repeat note will iterate indefinitely.\n // - One node argument which will be the explicit number of iterations to make.\n // - Two node arguments which define the min and max iteration bounds from which a random iteration count will be picked.\n if (tokens[0] === \"[\") {\n // An iteration count has been defined. Get the iteration and potential maximum iteration of the wait.\n const nodeArguments = getArguments(\n tokens,\n placeholders,\n (arg) => arg.type === \"number\" && !!arg.isInteger,\n \"repeat node iteration counts must be integer values\"\n ).map((argument) => argument.value);\n\n // We should have got one or two iteration counts.\n if (nodeArguments.length === 1) {\n // A static iteration count was defined.\n node.iterations = nodeArguments[0] as number;\n } else if (nodeArguments.length === 2) {\n // A minimum and maximum iteration count was defined.\n node.iterationsMin = nodeArguments[0] as number;\n node.iterationsMax = nodeArguments[1] as number;\n } else {\n // An incorrect number of iteration counts was defined.\n throw new Error(\"invalid number of repeat node iteration count arguments defined\");\n }\n }\n\n // Try to pick any attributes off of the token stack.\n node.attributes = getAttributes(tokens, placeholders);\n\n popAndCheck(tokens, \"{\");\n\n // The new scope is that of the new REPEAT nodes children.\n stack.push(node.children!);\n break;\n }\n\n case \"RETRY\": {\n // Create a RETRY AST node.\n const node = ASTNodeFactories.RETRY();\n\n // Push the RETRY node into the current scope.\n currentScope.push(node);\n\n // The arguments of a retry node are optional. We may have:\n // - No node arguments, in which case the retry note will attempt indefinitely.\n // - One node argument which will be the explicit number of attempts to make.\n // - Two node arguments which define the min and max attempt bounds from which a random attempt count will be picked.\n if (tokens[0] === \"[\") {\n // An attempt count has been defined. Get the attempt count and potential maximum attempt count of the wait.\n const nodeArguments = getArguments(\n tokens,\n placeholders,\n (arg) => arg.type === \"number\" && !!arg.isInteger,\n \"retry node attempt counts must be integer values\"\n ).map((argument) => argument.value);\n\n // We should have got one or two attempt counts.\n if (nodeArguments.length === 1) {\n // A static attempt count was defined.\n node.attempts = nodeArguments[0] as number;\n } else if (nodeArguments.length === 2) {\n // A minimum and maximum attempt count was defined.\n node.attemptsMin = nodeArguments[0] as number;\n node.attemptsMax = nodeArguments[1] as number;\n } else {\n // An incorrect number of attempt counts was defined.\n throw new Error(\"invalid number of retry node attempt count arguments defined\");\n }\n }\n\n // Try to pick any attributes off of the token stack.\n node.attributes = getAttributes(tokens, placeholders);\n\n popAndCheck(tokens, \"{\");\n\n // The new scope is that of the new RETRY nodes children.\n stack.push(node.children!);\n break;\n }\n\n case \"ACTION\": {\n // Create a ACTION AST node.\n const node = ASTNodeFactories.ACTION();\n\n // Push the ACTION node into the current scope.\n currentScope.push(node);\n\n // We must have arguments defined, as we require an action name argument.\n if (tokens[0] !== \"[\") {\n throw new Error(\"expected action name identifier argument\");\n }\n\n // The action name will be defined as a node argument.\n const actionArguments = getArguments(tokens, placeholders);\n\n // We should have at least one identifer argument for an action node, which is the action name.\n if (actionArguments.length && actionArguments[0].type === \"identifier\") {\n // The action name will be the first and only node argument.\n node.actionName = actionArguments.shift()!.value as string;\n } else {\n throw new Error(\"expected action name identifier argument\");\n }\n\n // Only the first argument should have been an identifier, all following arguments must be string, number, boolean or null.\n actionArguments\n .filter((arg) => arg.type === \"identifier\")\n .forEach((arg) => {\n throw new Error(\n \"invalid action node argument value '\" +\n arg.value +\n \"', must be string, number, boolean or null\"\n );\n });\n\n // Any node arguments that follow the action name identifier will be treated as action function arguments.\n node.actionArguments = actionArguments;\n\n // Try to pick any attributes off of the token stack.\n node.attributes = getAttributes(tokens, placeholders);\n break;\n }\n\n case \"}\": {\n // The '}' character closes the current scope.\n stack.pop();\n break;\n }\n\n default: {\n throw new Error(`unexpected token '${token}'`);\n }\n }\n }\n\n // A function to recursively validate each of the nodes in the AST.\n const validateASTNode = (node: Validatable, depth: number): void => {\n // Validate the node.\n node.validate(depth);\n\n // Validate each child of the node.\n (node.children || []).forEach((child) => validateASTNode(child, depth + 1));\n };\n\n // Start node validation from the definition root.\n validateASTNode(\n {\n children: stack[0] as RootAstNode[],\n validate(this: { children: RootAstNode[] }) {\n // We must have at least one node defined as the definition scope, which should be a root node.\n if (this.children.length === 0) {\n throw new Error(\"expected root node to have been defined\");\n }\n\n // Each node at the base of the definition scope MUST be a root node.\n for (const definitionLevelNode of this.children) {\n if (definitionLevelNode.type !== \"root\") {\n throw new Error(\"expected root node at base of definition\");\n }\n }\n\n // Exactly one root node must not have a name defined. This will be the main root, others will have to be referenced via branch nodes.\n if (this.children.filter((definitionLevelNode) => definitionLevelNode.name === null).length !== 1) {\n throw new Error(\"expected single unnamed root node at base of definition to act as main root\");\n }\n\n // No two named root nodes can have matching names.\n const rootNodeNames: string[] = [];\n for (const definitionLevelNode of this.children) {\n if (rootNodeNames.indexOf(definitionLevelNode.name!) !== -1) {\n throw new Error(`multiple root nodes found with duplicate name '${definitionLevelNode.name}'`);\n } else {\n rootNodeNames.push(definitionLevelNode.name!);\n }\n }\n }\n },\n 0\n );\n\n // Return the root AST nodes.\n return stack[0];\n}\n\n/**\n * Pop the next raw token off of the stack and throw an error if it wasn't the expected one.\n * @param tokens The array of remaining tokens.\n * @param expected An optional string or array or items, one of which must match the next popped token.\n * @returns The popped token.\n */\nfunction popAndCheck(tokens: string[], expected: string | string[]) {\n // Get and remove the next token.\n const popped = tokens.shift();\n\n // We were expecting another token.\n if (popped === undefined) {\n throw new Error(\"unexpected end of definition\");\n }\n\n // Do we have an expected token/tokens array?\n if (expected !== undefined) {\n // Check whether the popped token matches at least one of our expected items.\n var tokenMatchesExpectation = ([] as string[])\n .concat(expected)\n .some((item) => popped.toUpperCase() === item.toUpperCase());\n\n // Throw an error if the popped token didn't match any of our expected items.\n if (!tokenMatchesExpectation) {\n const expectationString = ([] as string[])\n .concat(expected)\n .map((item) => \"'\" + item + \"'\")\n .join(\" or \");\n\n throw new Error(`unexpected token found. Expected '${expectationString}' but got '${popped}'`);\n }\n }\n\n // Return the popped token.\n return popped;\n}\n\ntype Placeholders = { [key: string]: string };\n\n/**\n * Pull an argument definition list off of the token stack.\n * @param tokens The array of remaining tokens.\n * @param stringArgumentPlaceholders The mapping of string literal node argument placeholders to original values.\n * @param argumentValidator The argument validator function.\n * @param validationFailedMessage The exception message to throw if argument validation fails.\n * @returns The argument definition list.\n */\nfunction getArguments(\n tokens: string[],\n stringArgumentPlaceholders: Placeholders,\n argumentValidator?: (arg: AnyArgument) => boolean,\n validationFailedMessage?: string\n) {\n // Any lists of arguments will always be wrapped in '[]' for node arguments or '()' for attribute arguments.\n // We are looking for a '[' or '(' opener that wraps the argument tokens and the relevant closer.\n const closer = popAndCheck(tokens, [\"[\", \"(\"]) === \"[\" ? \"]\" : \")\";\n\n const argumentListTokens: string[] = [];\n const argumentList: AnyArgument[] = [];\n\n // Grab all tokens between the '[' and ']' or '(' and ')'.\n while (tokens.length && tokens[0] !== closer) {\n // The next token is part of our arguments list.\n argumentListTokens.push(tokens.shift()!);\n }\n\n // Validate the order of the argument tokens. Each token must either be a ',' or a single argument that satisfies the validator.\n argumentListTokens.forEach((token, index) => {\n // Get whether this token should be an actual argument.\n const shouldBeArgumentToken = !(index & 1);\n\n // If the current token should be an actual argument then validate it,otherwise it should be a ',' token.\n if (shouldBeArgumentToken) {\n // Get the argument definition.\n const argumentDefinition = getArgumentDefinition(token!, stringArgumentPlaceholders);\n\n // Try to validate the argument.\n if (argumentValidator && !argumentValidator(argumentDefinition)) {\n throw new Error(validationFailedMessage);\n }\n\n // This is a valid argument!\n argumentList.push(argumentDefinition);\n } else {\n // The current token should be a ',' token.\n if (token !== \",\") {\n throw new Error(`invalid argument list, expected ',' or ']' but got '${token}'`);\n }\n }\n });\n\n // The arguments list should terminate with a ']' or ')' token, depending on the opener.\n popAndCheck(tokens, closer);\n\n // Return the argument list.\n return argumentList;\n}\n\n/**\n * Gets an argument value definition.\n * @param token The argument token.\n * @param stringArgumentPlaceholders The mapping of string literal node argument placeholders to original values.\n * @returns An argument value definition.\n */\nfunction getArgumentDefinition(token: string, stringArgumentPlaceholders: Placeholders): AnyArgument {\n // Check whether the token represents a null value.\n if (token === \"null\") {\n return {\n value: null,\n type: \"null\"\n } as NullArgument;\n }\n\n // Check whether the token represents a boolean value.\n if (token === \"true\" || token === \"false\") {\n return {\n value: token === \"true\",\n type: \"boolean\"\n } as BooleanArgument;\n }\n\n // Check whether the token represents a number value.\n // TODO: Relies on broken isNaN - see MDN.\n // if (!Number.isNaN(token)) {\n if (!isNaN(token as any)) {\n return {\n value: parseFloat(token),\n isInteger: parseFloat(token) === parseInt(token, 10),\n type: \"number\"\n } as NumberArgument;\n }\n\n // Check whether the token is a placeholder (e.g. @@0@@) representing a string literal.\n if (token.match(/^@@\\d+@@$/g)) {\n return {\n value: stringArgumentPlaceholders[token].replace('\\\\\"', '\"'),\n type: \"string\"\n } as StringPlaceholderArgument;\n }\n\n // The only remaining option is that the argument value is an identifier.\n return {\n value: token,\n type: \"identifier\"\n } as IdentifierArgument;\n}\n\n/**\n * Pull any attributes off of the token stack.\n * @param tokens The array of remaining tokens.\n * @param stringArgumentPlaceholders The mapping of string literal node argument placeholders to original values.\n * @returns An array of attributes defined by any directly following tokens.\n */\nfunction getAttributes(tokens: string[], stringArgumentPlaceholders: Placeholders) {\n // Create an array to hold any attributes found.\n const attributes: Attribute[] = [];\n\n // Keep track of names of attribute that we have found on the token stack, as we cannot have duplicates.\n const attributesFound: string[] = [];\n\n // Try to get the attribute factory for the next token.\n let attributeFactory = AttributeFactories[(tokens[0] || \"\").toUpperCase()];\n\n // Pull attribute tokens off of the tokens stack until we have no more.\n while (attributeFactory) {\n // Check to make sure that we have not already created a attribute of this type for this node.\n if (attributesFound.indexOf(tokens[0].toUpperCase()) !== -1) {\n throw new Error(`duplicate attribute '${tokens[0].toUpperCase()}' found for node`);\n }\n\n // Add the current attribute type to our array of found attributes.\n attributesFound.push(tokens.shift()!.toUpperCase());\n\n // Grab any attribute arguments.\n const attributeArguments = getArguments(tokens, stringArgumentPlaceholders);\n\n // The first attribute argument has to be an identifer, this will reference an agent function.\n if (attributeArguments.length === 0 || attributeArguments[0].type !== \"identifier\") {\n throw new Error(\"expected agent function name identifier argument for attribute\");\n }\n\n // Grab the first attribute which is an identifier that will reference an agent function.\n const attributeFunctionName = attributeArguments.shift()! as IdentifierArgument;\n\n // Any remaining attribute arguments must have a type of string, number, boolean or null.\n attributeArguments\n .filter((arg) => arg.type === \"identifier\")\n .forEach((arg) => {\n throw new Error(\n \"invalid attribute argument value '\" + arg.value + \"', must be string, number, boolean or null\"\n );\n });\n\n // Create the attribute and add it to the array of attributes found.\n attributes.push(attributeFactory(attributeFunctionName.value, attributeArguments));\n\n // Try to get the next attribute name token, as there could be multiple.\n attributeFactory = AttributeFactories[(tokens[0] || \"\").toUpperCase()];\n }\n\n return attributes;\n}\n\n/**\n * Swaps out any node/attribute argument string literals with placeholders.\n * @param definition The definition.\n * @returns An object containing a mapping of placeholders to original string values as well as the processed definition string.\n */\nfunction substituteStringLiterals(definition: string): {\n placeholders: { [key: string]: string };\n processedDefinition: string;\n} {\n // Create an object to hold the mapping of placeholders to original string values.\n const placeholders: Placeholders = {};\n\n // Replace any string literals wrapped with double quotes in our definition with placeholders to be processed later.\n const processedDefinition = definition.replace(/\\\"(\\\\.|[^\"\\\\])*\\\"/g, (match) => {\n var strippedMatch = match.substring(1, match.length - 1);\n var placeholder = Object.keys(placeholders).find((key) => placeholders[key] === strippedMatch);\n\n // If we have no existing string literal match then create a new placeholder.\n if (!placeholder) {\n placeholder = `@@${Object.keys(placeholders).length}@@`;\n placeholders[placeholder] = strippedMatch;\n }\n\n return placeholder;\n });\n\n return { placeholders, processedDefinition };\n}\n\n/**\n * Parse the tree definition into an array of raw tokens.\n * @param definition The definition.\n * @returns An array of tokens parsed from the definition.\n */\nfunction parseTokensFromDefinition(definition: string): string[] {\n // Add some space around various important characters so that they can be plucked out easier as individual tokens.\n definition = definition.replace(/\\(/g, \" ( \");\n definition = definition.replace(/\\)/g, \" ) \");\n definition = definition.replace(/\\{/g, \" { \");\n definition = definition.replace(/\\}/g, \" } \");\n definition = definition.replace(/\\]/g, \" ] \");\n definition = definition.replace(/\\[/g, \" [ \");\n definition = definition.replace(/\\,/g, \" , \");\n\n // Split the definition into raw token form and return it.\n return definition.replace(/\\s+/g, \" \").trim().split(\" \");\n}\n", "import GuardPath, { GuardPathPart } from \"./attributes/guards/GuardPath\";\nimport buildRootASTNodes, { AnyArgument, RootAstNode } from \"./RootAstNodesBuilder\";\nimport State, { AnyState } from \"./State\";\nimport Lookup from \"./Lookup\";\nimport Node from \"./nodes/Node\";\nimport Root from \"./nodes/decorator/Root\";\nimport Composite from \"./nodes/composite/Composite\";\nimport Decorator from \"./nodes/decorator/Decorator\";\nimport { Agent, GlobalFunction } from \"./Agent\";\nimport { CallbackAttributeDetails } from \"./attributes/callbacks/Callback\";\nimport { GuardAttributeDetails } from \"./attributes/guards/Guard\";\nimport { BehaviourTreeOptions } from \"./BehaviourTreeOptions\";\nimport { parseToJSON } from \"./dsl/DSLDefinitionParser\";\n\n// Purely for outside inspection of the tree.\nexport type FlattenedTreeNode = {\n id: string;\n type: string;\n caption: string;\n state: AnyState;\n guards: GuardAttributeDetails[];\n callbacks: CallbackAttributeDetails[];\n args: AnyArgument[];\n parentId: string | null;\n};\n\n/**\n * A representation of a behaviour tree.\n */\nexport class BehaviourTree {\n /**\n * The main root tree node.\n */\n public readonly rootNode: Root;\n\n /**\n * Creates a new instance of the BehaviourTree class.\n * @param definition The behaviour tree definition.\n * @param agent The agent instance that this behaviour tree is modelling behaviour for.\n * @param options The behaviour tree options object.\n */\n constructor(definition: string, private agent: Agent, private options: BehaviourTreeOptions = {}) {\n // The tree definition must be defined and a valid string.\n if (typeof definition !== \"string\") {\n throw new Error(\"the tree definition must be a string\");\n }\n\n // The agent must be defined and not null.\n if (typeof agent !== \"object\" || agent === null) {\n throw new Error(\"the agent must be defined and not null\");\n }\n\n // Parse the behaviour tree definition, create the populated tree of behaviour tree nodes, and get the root.\n this.rootNode = BehaviourTree._createRootNode(definition);\n }\n\n /**\n * Gets whether the tree is in the RUNNING state.\n * @returns true if the tree is in the RUNNING state, otherwise false.\n */\n isRunning() {\n return this.rootNode.getState() === State.RUNNING;\n }\n\n /**\n * Gets the current tree state of SUCCEEDED, FAILED, READY or RUNNING.\n * @returns The current tree state.\n */\n getState() {\n return this.rootNode.getState();\n }\n\n /**\n * Step the tree.\n * 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.\n * 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\n * 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.\n *\n * 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.\n */\n step() {\n // If the root node has already been stepped to completion then we need to reset it.\n if (this.rootNode.getState() === State.SUCCEEDED || this.rootNode.getState() === State.FAILED) {\n this.rootNode.reset();\n }\n\n try {\n this.rootNode.update(this.agent, this.options);\n } catch (exception) {\n throw new Error(`error stepping tree: ${(exception as Error).message}`);\n }\n }\n\n /**\n * Resets the tree from the root node outwards to each nested node, giving each a state of READY.\n */\n reset() {\n this.rootNode.reset();\n }\n\n /**\n * Gets the flattened details of every node in the tree.\n * @returns The flattened details of every node in the tree.\n */\n getFlattenedNodeDetails(): FlattenedTreeNode[] {\n // Create an empty flattened array of tree nodes.\n const flattenedTreeNodes: FlattenedTreeNode[] = [];\n\n /**\n * Helper function to process a node instance and push details into the flattened tree nodes array.\n * @param node The current node.\n * @param parentUid The UID of the node parent, or null if the node is the main root node.\n */\n const processNode = (node: Node, parentUid: string | null) => {\n // Get the guard and callback attribute details for this node.\n const guards = node\n .getAttributes()\n .filter((attribute) => attribute.isGuard())\n .map((attribute) => attribute.getDetails()) as GuardAttributeDetails[];\n const callbacks = node\n .getAttributes()\n .filter((attribute) => !attribute.isGuard())\n .map((attribute) => attribute.getDetails()) as CallbackAttributeDetails[];\n\n // Push the current node into the flattened nodes array.\n flattenedTreeNodes.push({\n id: node.getUid(),\n type: node.getType(),\n caption: node.getName(),\n state: node.getState(),\n guards,\n callbacks,\n args: node.getArguments(),\n parentId: parentUid\n });\n\n // Process each of the nodes children if it is not a leaf node.\n if (!node.isLeafNode()) {\n (node as Composite | Decorator)\n .getChildren()\n .forEach((child) => processNode(child, (node as Composite | Decorator).getUid()));\n }\n };\n\n // Convert the nested node structure into a flattened array of node details.\n processNode(this.rootNode, null);\n\n return flattenedTreeNodes;\n }\n\n /**\n * Registers the action/condition/guard/callback function or subtree with the given name.\n * @param name The name of the function or subtree to register.\n * @param value The function or subtree definition to register.\n */\n static register(name: string, value: GlobalFunction | string) {\n if (typeof value === \"function\") {\n // We are going to register a action/condition/guard/callback function.\n Lookup.setFunc(name, value);\n } else if (typeof value === \"string\") {\n // We are going to register a subtree.\n let rootASTNodes: RootAstNode[];\n\n try {\n // Try to create the behaviour tree AST based on the definition provided, this could fail if the definition is invalid.\n rootASTNodes = buildRootASTNodes(value);\n } catch (exception) {\n // There was an issue in trying to parse and build the tree definition.\n throw new Error(`error registering definition: ${(exception as Error).message}`);\n }\n\n // This function should only ever be called with a definition containing a single unnamed root node.\n if (rootASTNodes.length != 1 || rootASTNodes[0].name !== null) {\n throw new Error(\"error registering definition: expected a single unnamed root node\");\n }\n\n Lookup.setSubtree(name, rootASTNodes[0]);\n } else {\n throw new Error(\"unexpected value, expected string definition or function\");\n }\n }\n\n /**\n * Unregisters the registered action/condition/guard/callback function or subtree with the given name.\n * @param name The name of the registered action/condition/guard/callback function or subtree to unregister.\n */\n static unregister(name: string): void {\n Lookup.remove(name);\n }\n\n /**\n * Unregister all registered action/condition/guard/callback functions and subtrees.\n */\n static unregisterAll(): void {\n Lookup.empty();\n }\n\n /**\n * Parses a behaviour tree definition and creates a tree of behaviour tree nodes.\n * @param {string} definition The behaviour tree definition.\n * @returns The root behaviour tree node.\n */\n private static _createRootNode(definition: string): Root {\n // TODO Remove!\n try {\n //parseToJSON(definition);\n } catch (exception) {\n console.log(exception);\n }\n\n try {\n // Try to create the behaviour tree AST based on the definition provided, this could fail if the definition is invalid.\n const rootASTNodes = buildRootASTNodes(definition);\n\n // Create a symbol to use as the main root key in our root node mapping.\n const mainRootNodeKey = Symbol(\"__root__\");\n\n // Create a mapping of root node names to root AST tokens. The main root node will have a key of Symbol(\"__root__\").\n const rootNodeMap: { [key: string | symbol]: RootAstNode } = {};\n for (const rootASTNode of rootASTNodes) {\n rootNodeMap[rootASTNode.name === null ? mainRootNodeKey : rootASTNode.name!] = rootASTNode;\n }\n\n // Convert the AST to our actual tree and get the root node.\n const rootNode: Root = rootNodeMap[mainRootNodeKey].createNodeInstance(\n // Create a provider for named root nodes that are part of our definition or have been registered. Prioritising the former.\n (name: string): RootAstNode => (rootNodeMap[name] ? rootNodeMap[name] : Lookup.getSubtree(name)),\n []\n );\n\n // Set a guard path on every leaf of the tree to evaluate as part of its update.\n BehaviourTree._applyLeafNodeGuardPaths(rootNode);\n\n // Return the root node.\n return rootNode;\n } catch (exception) {\n // There was an issue in trying to parse and build the tree definition.\n throw new Error(`error parsing tree: ${(exception as Error).message}`);\n }\n }\n\n /**\n * Applies a guard path to every leaf of the tree to evaluate as part of each update.\n * @param rootNode The main root tree node.\n */\n private static _applyLeafNodeGuardPaths(rootNode: Root) {\n const nodePaths: Node[][] = [];\n\n const findLeafNodes = (path: Node[], node: Node) => {\n // Add the current node to the path.\n path = path.concat(node);\n\n // Check whether the current node is a leaf node.\n if (node.isLeafNode()) {\n nodePaths.push(path);\n } else {\n (node as Composite | Decorator).getChildren().forEach((child) => findLeafNodes(path, child));\n }\n };\n\n // Find all leaf node paths, starting from the root.\n findLeafNodes([], rootNode);\n\n nodePaths.forEach((path) => {\n // Each node in the current path will have to be assigned a guard path, working from the root outwards.\n for (let depth = 0; depth < path.length; depth++) {\n // Get the node in the path at the current depth.\n const currentNode = path[depth];\n\n // The node may already have been assigned a guard path, if so just skip it.\n if (currentNode.hasGuardPath()) {\n continue;\n }\n\n // Create the guard path for the current node.\n const guardPath = new GuardPath(\n path\n .slice(0, depth + 1)\n .map((node) => ({ node, guards: node.getGuardAttributes() }))\n .filter((details) => details.guards.length > 0)\n );\n\n // Assign the guard path to the current node.\n currentNode.setGuardPath(guardPath);\n }\n });\n }\n}\n"], - "mappings": ";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AACA,aAAO,eAAe,SAAS,cAAc,EAAE,OAAO,KAAK,CAAC;AAC5D,cAAQ,cAAc;AAItB,UAAI,cAA6B,WAAY;AAMzC,iBAASA,aAAY,aAAa,SAAS;AACvC,cAAI,YAAY,QAAQ;AAAE,sBAAU;AAAA,UAAG;AACvC,eAAK,eAAe;AACpB,eAAK,WAAW;AAAA,QACpB;AACA,eAAO,eAAeA,aAAY,WAAW,eAAe;AAAA,UAExD,KAAK,WAAY;AACb,mBAAO,KAAK;AAAA,UAChB;AAAA,UACA,YAAY;AAAA,UACZ,cAAc;AAAA,QAClB,CAAC;AACD,eAAO,eAAeA,aAAY,WAAW,WAAW;AAAA,UAEpD,KAAK,WAAY;AACb,mBAAO,KAAK;AAAA,UAChB;AAAA,UACA,KAAK,SAAU,OAAO;AAClB,iBAAK,WAAW;AAAA,UACpB;AAAA,UACA,YAAY;AAAA,UACZ,cAAc;AAAA,QAClB,CAAC;AACD,eAAOA;AAAA,MACX,EAAE;AACF,cAAQ,cAAc;AAAA;AAAA;;;ACtCtB;AAAA;AAAA;AACA,aAAO,eAAe,SAAS,cAAc,EAAE,OAAO,KAAK,CAAC;AAC5D,cAAQ,kBAAkB,QAAQ,oBAAoB;AAMtD,eAAS,kBAAkB,OAAO;AAC9B,eAAO,UAAU,QAAQ,UAAU;AAAA,MACvC;AACA,cAAQ,oBAAoB;AAM5B,eAAS,gBAAgB,OAAO;AAC5B,eAAO,OAAO,UAAU,YAAY,SAAS,KAAK,KAAK,MAAM,KAAK,MAAM;AAAA,MAC5E;AACA,cAAQ,kBAAkB;AAAA;AAAA;;;ACpB1B;AAAA;AAAA;AACA,aAAO,eAAe,SAAS,cAAc,EAAE,OAAO,KAAK,CAAC;AAC5D,cAAQ,QAAQ;AAChB,UAAI,gBAAgB;AACpB,UAAI,cAAc;AAIlB,UAAIC,SAAuB,WAAY;AAKnC,iBAASA,OAAM,cAAc;AAEzB,eAAK,gBAAgB,CAAC;AACtB,eAAK,gBAAgB;AAAA,QACzB;AAOA,QAAAA,OAAM,UAAU,MAAM,SAAU,aAAa,SAAS;AAClD,cAAI,YAAY,QAAQ;AAAE,sBAAU;AAAA,UAAG;AAEvC,cAAI,EAAE,GAAG,YAAY,iBAAiB,OAAO,GAAG;AAC5C,kBAAM,IAAI,MAAM,wCAAwC;AAAA,UAC5D;AAEA,cAAI,sBAAsB,KAAK,cAAc,KAAK,SAAU,MAAM;AAAE,mBAAO,KAAK,gBAAgB;AAAA,UAAa,CAAC;AAC9G,cAAI,qBAAqB;AAErB,gCAAoB,WAAW;AAAA,UACnC,OACK;AAED,iBAAK,cAAc,KAAK,IAAI,cAAc,YAAY,aAAa,OAAO,CAAC;AAAA,UAC/E;AACA,iBAAO;AAAA,QACX;AAOA,QAAAA,OAAM,UAAU,SAAS,SAAU,aAAa,SAAS;AAErD,cAAI,sBAAsB,KAAK,cAAc,KAAK,SAAU,MAAM;AAAE,mBAAO,KAAK,gBAAgB;AAAA,UAAa,CAAC;AAE9G,cAAI,CAAC,qBAAqB;AACtB,mBAAO;AAAA,UACX;AAEA,cAAI,YAAY,QAAW;AAEvB,gBAAI,EAAE,GAAG,YAAY,iBAAiB,OAAO,GAAG;AAC5C,oBAAM,IAAI,MAAM,wCAAwC;AAAA,YAC5D;AACA,gCAAoB,WAAW;AAE/B,gBAAI,oBAAoB,UAAU,GAAG;AACjC,mBAAK,gBAAgB,KAAK,cAAc,OAAO,SAAU,MAAM;AAAE,uBAAO,SAAS;AAAA,cAAqB,CAAC;AAAA,YAC3G;AAAA,UACJ,OACK;AAED,iBAAK,gBAAgB,KAAK,cAAc,OAAO,SAAU,MAAM;AAAE,qBAAO,SAAS;AAAA,YAAqB,CAAC;AAAA,UAC3G;AACA,iBAAO;AAAA,QACX;AAMA,QAAAA,OAAM,UAAU,OAAO,SAAU,SAAS;AACtC,cAAI,YAAY,QAAQ;AAAE,sBAAU,CAAC;AAAA,UAAG;AAExC,cAAI,KAAK,cAAc,WAAW,GAAG;AACjC,mBAAO;AAAA,UACX;AACA,cAAI,cAAc,GAAG,YAAY,mBAAmB,QAAQ,UAAU,IAAI,OAAO,QAAQ;AACzF,cAAI,WAAW,CAAC;AAChB,eAAK,cAAc,QAAQ,SAAU,IAAI;AACrC,gBAAI,cAAc,GAAG,aAAa,UAAU,GAAG;AAC/C,qBAAS,cAAc,GAAG,cAAc,SAAS,eAAe;AAC5D,uBAAS,KAAK,WAAW;AAAA,YAC7B;AAAA,UACJ,CAAC;AACD,cAAI;AAGJ,cAAI,KAAK,eAAe;AAEpB,qBAAS,KAAK,cAAc;AAE5B,gBAAI,OAAO,WAAW,YAAY,SAAS,KAAK,UAAU,GAAG;AACzD,oBAAM,IAAI,MAAM,oFAAoF;AAAA,YACxG;AAAA,UACJ,OACK;AAED,qBAAS,KAAK,OAAO;AAAA,UACzB;AAEA,cAAI,SAAS,SAAS,KAAK,MAAM,SAAS,SAAS,MAAM;AAEzD,cAAI,CAAC,YAAY;AACb,iBAAK,OAAO,QAAQ,CAAC;AAAA,UACzB;AAEA,iBAAO;AAAA,QACX;AAOA,QAAAA,OAAM,UAAU,eAAe,SAAU,SAAS,SAAS;AACvD,cAAI,YAAY,QAAQ;AAAE,sBAAU,CAAC;AAAA,UAAG;AACxC,cAAI,iBAAiB,GAAG,YAAY,mBAAmB,QAAQ,MAAM,IAAI,QAAQ,QAAQ;AAEzF,cAAI,YAAY,GAAG;AACf,mBAAO,CAAC;AAAA,UACZ;AAEA,cAAI,EAAE,GAAG,YAAY,iBAAiB,OAAO,GAAG;AAC5C,kBAAM,IAAI,MAAM,wCAAwC;AAAA,UAC5D;AACA,cAAI,SAAS,CAAC;AAGd,iBAAO,OAAO,SAAS,WAAW,KAAK,cAAc,SAAS,GAAG;AAC7D,mBAAO,KAAK,KAAK,KAAK,OAAO,CAAC;AAAA,UAClC;AAEA,cAAI,eAAe;AAEf,gBAAI,SAAS,CAAC;AAEd,qBAAS,KAAK,GAAG,WAAW,QAAQ,KAAK,SAAS,QAAQ,MAAM;AAC5D,kBAAI,cAAc,SAAS;AAC3B,kBAAI,OAAO,QAAQ,WAAW,MAAM,IAAI;AACpC,uBAAO,KAAK,WAAW;AAAA,cAC3B;AAAA,YACJ;AACA,qBAAS;AAAA,UACb;AACA,iBAAO;AAAA,QACX;AACA,eAAOA;AAAA,MACX,EAAE;AACF,cAAQ,QAAQA;AAAA;AAAA;;;AC5JhB;AAAA;AAAA;AACA,aAAO,eAAe,SAAS,cAAc,EAAE,OAAO,KAAK,CAAC;AAC5D,cAAQ,cAAc;AACtB,UAAI,UAAU;AAMd,eAASC,aAAY,uBAAuB;AAExC,YAAI,CAAC,uBAAuB;AACxB,iBAAO,IAAI,QAAQ,MAAM;AAAA,QAC7B;AAEA,YAAI,MAAM,QAAQ,qBAAqB,GAAG;AAEtC,cAAI,eAAe;AACnB,cAAI,UAAU,IAAI,QAAQ,MAAM;AAEhC,uBAAa,QAAQ,SAAU,IAAI;AAC/B,gBAAI,cAAc,GAAG,IAAI,SAAS,GAAG;AACrC,mBAAO,QAAQ,IAAI,aAAa,MAAM;AAAA,UAC1C,CAAC;AAED,iBAAO;AAAA,QACX,OACK;AAED,cAAI,SAAS,sBAAsB,QAAQ,eAAe,sBAAsB;AAEhF,cAAI,UAAU,IAAI,QAAQ,MAAM,MAAM;AAEtC,cAAI,cAAc;AACd,yBAAa,QAAQ,SAAU,IAAI;AAC/B,kBAAI,cAAc,GAAG,IAAI,SAAS,GAAG;AACrC,qBAAO,QAAQ,IAAI,aAAa,MAAM;AAAA,YAC1C,CAAC;AAAA,UACL;AAEA,iBAAO;AAAA,QACX;AAAA,MACJ;AACA,cAAQ,cAAcA;AAAA;AAAA;;;AC3CtB;AAAA;AAAA;AACA,aAAO,eAAe,SAAS,cAAc,EAAE,OAAO,KAAK,CAAC;AAC5D,UAAI,gBAAgB;AACpB,cAAQ,UAAU,cAAc;AAAA;AAAA;;;ACHhC;AAAA;AAAA;AAAA;AAAA;;;ACKA,MAAqB,4BAArB,cAAuD,MAAM;AAAA,IAIzD,YAAoB,QAAc;AAC9B,YAAM,mCAAmC;AADzB;AAAA,IAEpB;AAAA,IAOA,eAAe,CAAC,SAAe,SAAS,KAAK;AAAA,EACjD;;;ACNA,MAAqB,YAArB,MAA+B;AAAA,IAI3B,YAAoB,OAAwB;AAAxB;AAAA,IAAyB;AAAA,IAO7C,WAAW,CAAC,UAAiB;AAEzB,iBAAW,WAAW,KAAK,OAAO;AAE9B,mBAAW,SAAS,QAAQ,QAAQ;AAEhC,cAAI,CAAC,MAAM,YAAY,KAAK,GAAG;AAC3B,kBAAM,IAAI,0BAA0B,QAAQ,IAAI;AAAA,UACpD;AAAA,QACJ;AAAA,MACJ;AAAA,IACJ;AAAA,EACJ;;;ACjCO,MAAK,QAAL,kBAAKC,WAAL;AACH,IAAAA,OAAA,WAAQ;AACR,IAAAA,OAAA,aAAU;AACV,IAAAA,OAAA,eAAY;AACZ,IAAAA,OAAA,YAAS;AAJD,WAAAA;AAAA,KAAA;;;ACaZ,MAA8B,OAA9B,MAAmC;AAAA,IAmB/B,YAAoB,MAAsB,YAAiC,MAAqB;AAA5E;AAAsB;AAAiC;AAAA,IAAsB;AAAA,IAfhF,MAAc,cAAc;AAAA,IAIrC;AAAA,IAIA;AAAA,IA6BR,WAAW,MAAgB,KAAK;AAAA,IAChC,WAAW,CAAC,UAA0B;AAClC,WAAK,QAAQ;AAAA,IACjB;AAAA,IAKA,SAAS,MAAM,KAAK;AAAA,IAKpB,UAAU,MAAM,KAAK;AAAA,IAKrB,gBAAgB,MAAM,KAAK;AAAA,IAK3B,eAAe,MAAM,KAAK;AAAA,IAQ1B,aAAa,MAAyB;AAClC,aACI,KAAK,cAAc,EAAE,OAAO,CAAC,cAAc,UAAU,QAAQ,EAAE,YAAY,MAAM,KAAK,YAAY,CAAC,EAAE,MACrG;AAAA,IAER;AAAA,IAKA,qBAAqB,MAAe,KAAK,cAAc,EAAE,OAAO,CAAC,cAAc,UAAU,QAAQ,CAAC;AAAA,IAKlG,eAAe,CAAC,UAAsB,KAAK,YAAY;AAAA,IAKvD,eAAe,MAAM,CAAC,CAAC,KAAK;AAAA,IAMrB,GAAG,OAA0B;AAChC,aAAO,KAAK,UAAU;AAAA,IAC1B;AAAA,IAKO,QAAc;AACjB,WAAK,wCAAoB;AAAA,IAC7B;AAAA,IAMO,MAAM,OAAoB;AAE7B,UAAI,CAAC,KAAK,sCAAgB,GAAG;AACzB;AAAA,MACJ;AAGA,WAAK,MAAM;AAEX,WAAK,aAAa,MAAM,GAAG,kBAAkB,OAAO,OAAO,IAAI;AAAA,IACnE;AAAA,IAQO,OAAO,OAAc,SAAqC;AAE7D,UAAI,KAAK,0CAAkB,KAAK,KAAK,oCAAe,GAAG;AACnD;AAAA,MACJ;AAEA,UAAI;AAEA,aAAK,UAAW,SAAS,KAAK;AAG9B,YAAI,KAAK,kCAAc,GAAG;AACtB,eAAK,aAAa,OAAO,GAAG,kBAAkB,KAAK;AAAA,QACvD;AAEA,aAAK,aAAa,MAAM,GAAG,kBAAkB,KAAK;AAGlD,aAAK,SAAS,OAAO,OAAO;AAG5B,YAAI,KAAK,0CAAkB,KAAK,KAAK,oCAAe,GAAG;AACnD,eAAK,aAAa,MAAM,GAAG,kBAAkB,OAAO,KAAK,0CAAkB,GAAG,KAAK;AAAA,QACvF;AAAA,MACJ,SAAS,OAAP;AAEE,YAAI,iBAAiB,6BAA6B,MAAM,aAAa,IAAI,GAAG;AAExE,eAAK,MAAM,KAAK;AAGhB,eAAK,0CAAqB;AAAA,QAC9B,OAAO;AACH,gBAAM;AAAA,QACV;AAAA,MACJ;AAAA,IACJ;AAAA,EACJ;AAMA,WAAS,gBAAwB;AAC7B,QAAI,KAAK,WAAY;AACjB,eAAU,IAAI,KAAK,OAAO,KAAK,QAAW,GAAG,SAAS,EAAE,EAAE,UAAU,CAAC;AAAA,IACzE;AACA,WAAO,GAAG,IAAI,GAAG,IAAI,MAAM,GAAG,IAAI,MAAM,GAAG,IAAI,MAAM,GAAG,IAAI,MAAM,GAAG,IAAI,GAAG,IAAI,GAAG;AAAA,EACvF;;;AC9LA,MAA8B,OAA9B,cAA2C,KAAK;AAAA,IAI5C,aAAa,MAAM;AAAA,EACvB;;;ACGA,MAAqB,SAArB,MAA4B;AAAA,IAexB,OAAc,QAAQ,MAA8B;AAChD,aAAO,KAAK,cAAc;AAAA,IAC9B;AAAA,IAOA,OAAc,QAAQ,MAAc,MAA4B;AAC5D,WAAK,cAAc,QAAQ;AAAA,IAC/B;AAAA,IAUA,OAAO,eAAe,OAAc,MAAsC;AAEtE,YAAM,eAAe,MAAM;AAC3B,UAAI,gBAAgB,OAAO,iBAAiB,YAAY;AACpD,eAAO,CAAC,SACJ,aAAa;AAAA,UACT;AAAA,UACA,KAAK,IAAI,CAAC,QAAQ,IAAI,KAAK;AAAA,QAC/B;AAAA,MACR;AAGA,UAAI,KAAK,cAAc,SAAS,OAAO,KAAK,cAAc,UAAU,YAAY;AAC5E,eAAO,CAAC,SAA4B,KAAK,cAAc,MAAM,OAAO,GAAG,KAAK,IAAI,CAAC,QAAQ,IAAI,KAAK,CAAC;AAAA,MACvG;AAGA,aAAO;AAAA,IACX;AAAA,IAOA,OAAO,WAAW,MAA2B;AACzC,aAAO,KAAK,aAAa;AAAA,IAC7B;AAAA,IAOA,OAAO,WAAW,MAAc,SAAsB;AAClD,WAAK,aAAa,QAAQ;AAAA,IAC9B;AAAA,IAMA,OAAO,OAAO,MAAc;AACxB,aAAO,KAAK,cAAc;AAC1B,aAAO,KAAK,aAAa;AAAA,IAC7B;AAAA,IAKA,OAAO,QAAQ;AACX,WAAK,gBAAgB,CAAC;AACtB,WAAK,eAAe,CAAC;AAAA,IACzB;AAAA,EACJ;AAtFI,gBAJiB,QAIF,iBAAmD,CAAC;AAInE,gBARiB,QAQF,gBAA+C,CAAC;;;ACTnE,MAAqB,SAArB,cAAoC,KAAK;AAAA,IAMrC,YAAY,YAAiC,YAA4B,iBAAgC;AACrG,YAAM,UAAU,YAAY,eAAe;AADF;AAA4B;AAAA,IAEzE;AAAA,IAKQ,uBAAuB;AAAA,IAKvB,2BAAiD;AAAA,IAO/C,SAAS,OAAc,SAAqC;AAGlE,UAAI,KAAK,sBAAsB;AAE3B,YAAI,KAAK,0BAA0B;AAE/B,eAAK,SAAS,KAAK,wBAAwB;AAAA,QAC/C;AAEA;AAAA,MACJ;AAGA,YAAM,oBAAoB,OAAO,eAAe,OAAO,KAAK,UAAU;AAGtE,UAAI,sBAAsB,MAAM;AAC5B,cAAM,IAAI;AAAA,UACN,4CAA4C,KAAK;AAAA,QACrD;AAAA,MACJ;AAMA,YAAM,eAAe,kBAAkB,KAAK,eAAe;AAE3D,UAAI,wBAAwB,SAAS;AACjC,qBAAa;AAAA,UACT,CAAC,WAAW;AAER,gBAAI,CAAC,KAAK,sBAAsB;AAC5B;AAAA,YACJ;AAGA,gBAAI,sDAA8B,8CAAyB;AACvD,oBAAM,IAAI;AAAA,gBACN;AAAA,cACJ;AAAA,YACJ;AAGA,iBAAK,2BAA2B;AAAA,UACpC;AAAA,UACA,CAAC,WAAW;AAER,gBAAI,CAAC,KAAK,sBAAsB;AAC5B;AAAA,YACJ;AAGA,kBAAM,IAAI,MAAM,MAAM;AAAA,UAC1B;AAAA,QACJ;AAGA,aAAK,4CAAsB;AAG3B,aAAK,uBAAuB;AAAA,MAChC,OAAO;AAEH,aAAK,qBAAqB,YAAY;AAGtC,aAAK,SAAS,mDAA6B;AAAA,MAC/C;AAAA,IACJ;AAAA,IAKA,UAAU,MAAM,KAAK;AAAA,IAKrB,QAAQ,MAAM;AAEV,WAAK,wCAAoB;AAGzB,WAAK,uBAAuB;AAC5B,WAAK,2BAA2B;AAAA,IACpC;AAAA,IAMQ,uBAAuB,CAAC,WAAoC;AAChE,cAAQ,QAAQ;AAAA,QACZ;AAAA,QACA;AAAA,QACA,KAAK;AACD;AAAA,QACJ;AACI,gBAAM,IAAI;AAAA,YACN,WAAW,KAAK;AAAA,UACpB;AAAA,MACR;AAAA,IACJ;AAAA,EACJ;;;AClIA,MAAqB,YAArB,cAAuC,KAAK;AAAA,IAMxC,YAAY,YAAiC,eAA+B,oBAAmC;AAC3G,YAAM,aAAa,YAAY,kBAAkB;AADR;AAA+B;AAAA,IAE5E;AAAA,IAOU,SAAS,OAAc,SAAqC;AAElE,YAAM,uBAAuB,OAAO,eAAe,OAAO,KAAK,aAAa;AAG5E,UAAI,yBAAyB,MAAM;AAC/B,cAAM,IAAI;AAAA,UACN,kDAAkD,KAAK;AAAA,QAC3D;AAAA,MACJ;AAGA,WAAK,SAAS,CAAC,CAAC,qBAAqB,KAAK,kBAAkB,+EAAkC;AAAA,IAClG;AAAA,IAKA,UAAU,MAAM,KAAK;AAAA,EACzB;;;ACpCA,MAAqB,OAArB,cAAkC,KAAK;AAAA,IAOnC,YACI,YACQ,UACA,aACA,aACV;AACE,YAAM,QAAQ,YAAY,CAAC,CAAC;AAJpB;AACA;AACA;AAAA,IAGZ;AAAA,IAKQ,oBAA4B;AAAA,IAK5B,gBAA+B;AAAA,IAK/B,iBAAyB;AAAA,IAOvB,SAAS,OAAc,SAAqC;AAElE,UAAI,KAAK,kCAAc,GAAG;AAEtB,aAAK,oBAAoB,IAAI,KAAK,EAAE,QAAQ;AAG5C,aAAK,iBAAiB;AAGtB,YAAI,KAAK,aAAa,MAAM;AACxB,eAAK,gBAAgB,KAAK;AAAA,QAC9B,WAAW,KAAK,gBAAgB,QAAQ,KAAK,gBAAgB,MAAM;AAG/D,gBAAM,SAAS,OAAO,QAAQ,WAAW,aAAa,QAAQ,SAAS,KAAK;AAG5E,eAAK,gBAAgB,KAAK;AAAA,YACtB,OAAO,KAAK,KAAK,cAAc,KAAK,cAAc,KAAK,KAAK;AAAA,UAChE;AAAA,QACJ,OAAO;AACH,eAAK,gBAAgB;AAAA,QACzB;AAGA,aAAK,4CAAsB;AAAA,MAC/B;AAGA,UAAI,KAAK,kBAAkB,MAAM;AAC7B;AAAA,MACJ;AAGA,UAAI,OAAO,QAAQ,iBAAiB,YAAY;AAE5C,cAAM,YAAY,QAAQ,aAAa;AAGvC,YAAI,OAAO,cAAc,YAAY,MAAM,SAAS,GAAG;AACnD,gBAAM,IAAI,MAAM,oDAAoD;AAAA,QACxE;AAGA,aAAK,kBAAkB,YAAY;AAAA,MACvC,OAAO;AAEH,aAAK,iBAAiB,IAAI,KAAK,EAAE,QAAQ,IAAI,KAAK;AAAA,MACtD;AAGA,UAAI,KAAK,kBAAkB,KAAK,eAAe;AAE3C,aAAK,gDAAwB;AAAA,MACjC;AAAA,IACJ;AAAA,IAKA,UAAU,MAAM;AACZ,UAAI,KAAK,aAAa,MAAM;AACxB,eAAO,QAAQ,KAAK;AAAA,MACxB,WAAW,KAAK,gBAAgB,QAAQ,KAAK,gBAAgB,MAAM;AAC/D,eAAO,QAAQ,KAAK,iBAAiB,KAAK;AAAA,MAC9C,OAAO;AACH,eAAO;AAAA,MACX;AAAA,IACJ;AAAA,EACJ;;;AC5GA,MAA8B,YAA9B,cAAgD,KAAK;AAAA,IAMjD,YAAY,MAAc,YAAmC,OAAa;AACtE,YAAM,MAAM,YAAY,CAAC,CAAC;AAD+B;AAAA,IAE7D;AAAA,IAKA,aAAa,MAAM;AAAA,IAKnB,cAAc,MAAM,CAAC,KAAK,KAAK;AAAA,IAK/B,QAAQ,MAAM;AAEV,WAAK,wCAAoB;AAGzB,WAAK,MAAM,MAAM;AAAA,IACrB;AAAA,IAMA,QAAQ,CAAC,UAAiB;AAEtB,UAAI,CAAC,KAAK,sCAAgB,GAAG;AACzB;AAAA,MACJ;AAGA,WAAK,MAAM,MAAM,KAAK;AAGtB,WAAK,MAAM;AAEX,WAAK,aAAa,MAAM,GAAG,kBAAkB,OAAO,OAAO,IAAI;AAAA,IACnE;AAAA,EACJ;;;AC9CA,MAAqB,OAArB,cAAkC,UAAU;AAAA,IAKxC,YAAY,YAAyB,OAAa;AAC9C,YAAM,QAAQ,YAAY,KAAK;AAAA,IACnC;AAAA,IAOU,SAAS,OAAc,SAAqC;AAElE,UAAI,KAAK,MAAM,SAAS,yCAAqB,KAAK,MAAM,SAAS,2CAAqB;AAElF,aAAK,MAAM,OAAO,OAAO,OAAO;AAAA,MACpC;AAGA,WAAK,SAAS,KAAK,MAAM,SAAS,CAAC;AAAA,IACvC;AAAA,IAKA,UAAU,MAAM;AAAA,EACpB;;;ACzBA,MAAqB,SAArB,cAAoC,UAAU;AAAA,IAQ1C,YACI,YACQ,YACA,eACA,eACR,OACF;AACE,YAAM,UAAU,YAAY,KAAK;AALzB;AACA;AACA;AAAA,IAIZ;AAAA,IAKQ,uBAAsC;AAAA,IAKtC,wBAAgC;AAAA,IAO9B,SAAS,OAAc,SAAqC;AAElE,UAAI,KAAK,kCAAc,GAAG;AAEtB,aAAK,MAAM,MAAM;AAGjB,aAAK,wBAAwB;AAG7B,aAAK,wBAAwB,OAAO;AAAA,MACxC;AAIA,UAAI,KAAK,WAAW,GAAG;AAEnB,aAAK,4CAAsB;AAI3B,YAAI,KAAK,MAAM,SAAS,+CAAuB;AAC3C,eAAK,MAAM,MAAM;AAAA,QACrB;AAGA,aAAK,MAAM,OAAO,OAAO,OAAO;AAIhC,YAAI,KAAK,MAAM,SAAS,yCAAoB;AAExC,eAAK,0CAAqB;AAE1B;AAAA,QACJ,WAAW,KAAK,MAAM,SAAS,+CAAuB;AAElD,eAAK,yBAAyB;AAAA,QAClC;AAAA,MACJ,OAAO;AAEH,aAAK,gDAAwB;AAAA,MACjC;AAAA,IACJ;AAAA,IAKA,UAAU,MAAM;AACZ,UAAI,KAAK,eAAe,MAAM;AAC1B,eAAO,UAAU,KAAK;AAAA,MAC1B,WAAW,KAAK,kBAAkB,QAAQ,KAAK,kBAAkB,MAAM;AACnE,eAAO,UAAU,KAAK,kBAAkB,KAAK;AAAA,MACjD,OAAO;AACH,eAAO;AAAA,MACX;AAAA,IACJ;AAAA,IAKA,QAAQ,MAAM;AAEV,WAAK,wCAAoB;AAGzB,WAAK,wBAAwB;AAG7B,WAAK,MAAM,MAAM;AAAA,IACrB;AAAA,IAMQ,aAAa,MAAM;AACvB,UAAI,KAAK,yBAAyB,MAAM;AAEpC,eAAO,KAAK,wBAAwB,KAAK;AAAA,MAC7C;AAGA,aAAO;AAAA,IACX;AAAA,IAMQ,0BAA0B,CAAC,YAAkC;AAEjE,UAAI,KAAK,eAAe,MAAM;AAC1B,aAAK,uBAAuB,KAAK;AAAA,MACrC,WAAW,KAAK,kBAAkB,QAAQ,KAAK,kBAAkB,MAAM;AAGnE,cAAM,SAAS,OAAO,QAAQ,WAAW,aAAa,QAAQ,SAAS,KAAK;AAG5E,aAAK,uBAAuB,KAAK;AAAA,UAC7B,OAAO,KAAK,KAAK,gBAAgB,KAAK,gBAAgB,KAAK,KAAK;AAAA,QACpE;AAAA,MACJ,OAAO;AACH,aAAK,uBAAuB;AAAA,MAChC;AAAA,IACJ;AAAA,EACJ;;;AC5IA,MAAqB,QAArB,cAAmC,UAAU;AAAA,IAQzC,YACI,YACQ,UACA,aACA,aACR,OACF;AACE,YAAM,SAAS,YAAY,KAAK;AALxB;AACA;AACA;AAAA,IAIZ;AAAA,IAKQ,qBAAoC;AAAA,IAKpC,sBAA8B;AAAA,IAO5B,SAAS,OAAc,SAAqC;AAElE,UAAI,KAAK,kCAAc,GAAG;AAEtB,aAAK,MAAM,MAAM;AAGjB,aAAK,sBAAsB;AAG3B,aAAK,sBAAsB,OAAO;AAAA,MACtC;AAIA,UAAI,KAAK,WAAW,GAAG;AAEnB,aAAK,4CAAsB;AAI3B,YAAI,KAAK,MAAM,SAAS,yCAAoB;AACxC,eAAK,MAAM,MAAM;AAAA,QACrB;AAGA,aAAK,MAAM,OAAO,OAAO,OAAO;AAIhC,YAAI,KAAK,MAAM,SAAS,+CAAuB;AAE3C,eAAK,gDAAwB;AAE7B;AAAA,QACJ,WAAW,KAAK,MAAM,SAAS,yCAAoB;AAE/C,eAAK,uBAAuB;AAAA,QAChC;AAAA,MACJ,OAAO;AAEH,aAAK,0CAAqB;AAAA,MAC9B;AAAA,IACJ;AAAA,IAKA,UAAU,MAAM;AACZ,UAAI,KAAK,aAAa,MAAM;AACxB,eAAO,SAAS,KAAK;AAAA,MACzB,WAAW,KAAK,gBAAgB,QAAQ,KAAK,gBAAgB,MAAM;AAC/D,eAAO,SAAS,KAAK,gBAAgB,KAAK;AAAA,MAC9C,OAAO;AACH,eAAO;AAAA,MACX;AAAA,IACJ;AAAA,IAKA,QAAQ,MAAM;AAEV,WAAK,wCAAoB;AAGzB,WAAK,sBAAsB;AAG3B,WAAK,MAAM,MAAM;AAAA,IACrB;AAAA,IAMA,aAAa,MAAM;AACf,UAAI,KAAK,uBAAuB,MAAM;AAElC,eAAO,KAAK,sBAAsB,KAAK;AAAA,MAC3C;AAGA,aAAO;AAAA,IACX;AAAA,IAMA,wBAAwB,CAAC,YAAkC;AAEvD,UAAI,KAAK,aAAa,MAAM;AACxB,aAAK,qBAAqB,KAAK;AAAA,MACnC,WAAW,KAAK,gBAAgB,QAAQ,KAAK,gBAAgB,MAAM;AAG/D,cAAM,SAAS,OAAO,QAAQ,WAAW,aAAa,QAAQ,SAAS,KAAK;AAG5E,aAAK,qBAAqB,KAAK;AAAA,UAC3B,OAAO,KAAK,KAAK,cAAc,KAAK,cAAc,KAAK,KAAK;AAAA,QAChE;AAAA,MACJ,OAAO;AACH,aAAK,qBAAqB;AAAA,MAC9B;AAAA,IACJ;AAAA,EACJ;;;AChJA,MAAqB,OAArB,cAAkC,UAAU;AAAA,IAKxC,YAAY,YAAyB,OAAa;AAC9C,YAAM,QAAQ,YAAY,KAAK;AAAA,IACnC;AAAA,IAOU,SAAS,OAAc,SAAqC;AAElE,UAAI,KAAK,MAAM,SAAS,yCAAqB,KAAK,MAAM,SAAS,2CAAqB;AAClF,aAAK,MAAM,OAAO,OAAO,OAAO;AAAA,MACpC;AAGA,cAAQ,KAAK,MAAM,SAAS,GAAG;AAAA,QAC3B;AACI,eAAK,4CAAsB;AAC3B;AAAA,QAEJ;AACI,eAAK,0CAAqB;AAC1B;AAAA,QAEJ;AACI,eAAK,gDAAwB;AAC7B;AAAA,QAEJ;AACI,eAAK,wCAAoB;AAAA,MACjC;AAAA,IACJ;AAAA,IAKA,UAAU,MAAM;AAAA,EACpB;;;AC3CA,MAAqB,UAArB,cAAqC,UAAU;AAAA,IAK3C,YAAY,YAAyB,OAAa;AAC9C,YAAM,WAAW,YAAY,KAAK;AAAA,IACtC;AAAA,IAOU,SAAS,OAAc,SAAqC;AAElE,UAAI,KAAK,MAAM,SAAS,yCAAqB,KAAK,MAAM,SAAS,2CAAqB;AAClF,aAAK,MAAM,OAAO,OAAO,OAAO;AAAA,MACpC;AAGA,cAAQ,KAAK,MAAM,SAAS,GAAG;AAAA,QAC3B;AACI,eAAK,4CAAsB;AAC3B;AAAA,QAEJ;AAAA,QACA;AACI,eAAK,gDAAwB;AAC7B;AAAA,QAEJ;AACI,eAAK,wCAAoB;AAAA,MACjC;AAAA,IACJ;AAAA,IAKA,UAAU,MAAM;AAAA,EACpB;;;ACxCA,MAAqB,OAArB,cAAkC,UAAU;AAAA,IAKxC,YAAY,YAAyB,OAAa;AAC9C,YAAM,QAAQ,YAAY,KAAK;AAAA,IACnC;AAAA,IAOU,SAAS,OAAc,SAAqC;AAElE,UAAI,KAAK,MAAM,SAAS,yCAAqB,KAAK,MAAM,SAAS,2CAAqB;AAClF,aAAK,MAAM,OAAO,OAAO,OAAO;AAAA,MACpC;AAGA,cAAQ,KAAK,MAAM,SAAS,GAAG;AAAA,QAC3B;AACI,eAAK,4CAAsB;AAC3B;AAAA,QAEJ;AAAA,QACA;AACI,eAAK,0CAAqB;AAC1B;AAAA,QAEJ;AACI,eAAK,wCAAoB;AAAA,MACjC;AAAA,IACJ;AAAA,IAKA,UAAU,MAAM;AAAA,EACpB;;;ACnDA,0BAAwB;;;ACQxB,MAA8B,YAA9B,cAAgD,KAAK;AAAA,IAMjD,YAAY,MAAc,YAAmC,UAAkB;AAC3E,YAAM,MAAM,YAAY,CAAC,CAAC;AAD+B;AAAA,IAE7D;AAAA,IAKA,aAAa,MAAM;AAAA,IAKnB,cAAc,MAAM,KAAK;AAAA,IAKzB,QAAQ,MAAM;AAEV,WAAK,wCAAoB;AAGzB,WAAK,YAAY,EAAE,QAAQ,CAAC,UAAU,MAAM,MAAM,CAAC;AAAA,IACvD;AAAA,IAMA,QAAQ,CAAC,UAAiB;AAEtB,UAAI,CAAC,KAAK,sCAAgB,GAAG;AACzB;AAAA,MACJ;AAGA,WAAK,YAAY,EAAE,QAAQ,CAAC,UAAU,MAAM,MAAM,KAAK,CAAC;AAGxD,WAAK,MAAM;AAEX,WAAK,aAAa,MAAM,GAAG,kBAAkB,OAAO,OAAO,IAAI;AAAA,IACnE;AAAA,EACJ;;;AD3CA,MAAqB,QAArB,cAAmC,UAAU;AAAA,IAMzC,YAAY,YAAiC,SAAmB,UAAkB;AAC9E,YAAM,SAAS,YAAY,QAAQ;AADM;AAAA,IAE7C;AAAA,IAKQ;AAAA,IAOE,SAAS,OAAc,SAAqC;AAElE,UAAI,KAAK,kCAAc,GAAG;AAEtB,cAAM,gBAAY,kBAAAC,SAAkB;AAAA,UAEhC,QAAQ,QAAQ;AAAA,UAEhB,cAAc,KAAK,SAAS,IAAI,CAAC,OAAO,UAAU,CAAC,OAAO,KAAK,QAAQ,UAAU,CAAC,CAAC;AAAA,QACvF,CAAC;AAGD,aAAK,gBAAgB,UAAU,KAAK,KAAK;AAAA,MAC7C;AAGA,UAAI,CAAC,KAAK,eAAe;AACrB,cAAM,IAAI,MAAM,uDAAuD;AAAA,MAC3E;AAGA,UAAI,KAAK,cAAc,SAAS,yCAAqB,KAAK,cAAc,SAAS,2CAAqB;AAClG,aAAK,cAAc,OAAO,OAAO,OAAO;AAAA,MAC5C;AAGA,WAAK,SAAS,KAAK,cAAc,SAAS,CAAC;AAAA,IAC/C;AAAA,IAKA,UAAU,MAAO,KAAK,QAAQ,SAAS,UAAU,KAAK,QAAQ,KAAK,GAAG,OAAO;AAAA,EACjF;;;AExDA,MAAqB,WAArB,cAAsC,UAAU;AAAA,IAK5C,YAAY,YAAmC,UAAkB;AAC7D,YAAM,YAAY,YAAY,QAAQ;AADK;AAAA,IAE/C;AAAA,IAOU,SAAS,OAAc,SAAqC;AAElE,iBAAW,SAAS,KAAK,UAAU;AAE/B,YAAI,MAAM,SAAS,yCAAqB,MAAM,SAAS,2CAAqB;AAExE,gBAAM,OAAO,OAAO,OAAO;AAAA,QAC/B;AAGA,YAAI,MAAM,SAAS,+CAAuB;AAEtC,eAAK,gDAAwB;AAG7B;AAAA,QACJ;AAGA,YAAI,MAAM,SAAS,yCAAoB;AAGnC,cAAI,KAAK,SAAS,QAAQ,KAAK,MAAM,KAAK,SAAS,SAAS,GAAG;AAE3D,iBAAK,0CAAqB;AAG1B;AAAA,UACJ,OAAO;AAEH;AAAA,UACJ;AAAA,QACJ;AAGA,YAAI,MAAM,SAAS,2CAAqB;AAEpC,eAAK,4CAAsB;AAG3B;AAAA,QACJ;AAGA,cAAM,IAAI,MAAM,0CAA0C;AAAA,MAC9D;AAAA,IACJ;AAAA,IAKA,UAAU,MAAM;AAAA,EACpB;;;AClEA,MAAqB,WAArB,cAAsC,UAAU;AAAA,IAK5C,YAAY,YAAmC,UAAkB;AAC7D,YAAM,YAAY,YAAY,QAAQ;AADK;AAAA,IAE/C;AAAA,IAOU,SAAS,OAAc,SAAqC;AAElE,iBAAW,SAAS,KAAK,UAAU;AAE/B,YAAI,MAAM,SAAS,yCAAqB,MAAM,SAAS,2CAAqB;AAExE,gBAAM,OAAO,OAAO,OAAO;AAAA,QAC/B;AAGA,YAAI,MAAM,SAAS,+CAAuB;AAGtC,cAAI,KAAK,SAAS,QAAQ,KAAK,MAAM,KAAK,SAAS,SAAS,GAAG;AAE3D,iBAAK,gDAAwB;AAG7B;AAAA,UACJ,OAAO;AAEH;AAAA,UACJ;AAAA,QACJ;AAGA,YAAI,MAAM,SAAS,yCAAoB;AAEnC,eAAK,0CAAqB;AAG1B;AAAA,QACJ;AAGA,YAAI,MAAM,SAAS,2CAAqB;AAEpC,eAAK,4CAAsB;AAG3B;AAAA,QACJ;AAGA,cAAM,IAAI,MAAM,0CAA0C;AAAA,MAC9D;AAAA,IACJ;AAAA,IAKA,UAAU,MAAM;AAAA,EACpB;;;AClEA,MAAqB,WAArB,cAAsC,UAAU;AAAA,IAK5C,YAAY,YAAyB,UAAkB;AACnD,YAAM,YAAY,YAAY,QAAQ;AAAA,IAC1C;AAAA,IAOU,SAAS,OAAc,SAAqC;AAElE,UAAI,iBAAiB;AAErB,UAAI,iBAAiB;AAGrB,iBAAW,SAAS,KAAK,UAAU;AAE/B,YAAI,MAAM,SAAS,yCAAqB,MAAM,SAAS,2CAAqB;AAExE,gBAAM,OAAO,OAAO,OAAO;AAAA,QAC/B;AAGA,YAAI,MAAM,SAAS,+CAAuB;AAEtC;AAGA;AAAA,QACJ;AAGA,YAAI,MAAM,SAAS,yCAAoB;AACnC,2BAAiB;AAGjB;AAAA,QACJ;AAGA,YAAI,MAAM,SAAS,2CAAqB;AAEpC,gBAAM,IAAI,MAAM,0CAA0C;AAAA,QAC9D;AAAA,MACJ;AAEA,UAAI,gBAAgB;AAEhB,aAAK,0CAAqB;AAG1B,mBAAW,SAAS,KAAK,UAAU;AAC/B,cAAI,MAAM,SAAS,2CAAqB;AACpC,kBAAM,MAAM,KAAK;AAAA,UACrB;AAAA,QACJ;AAAA,MACJ,OAAO;AAEH,aAAK,SAAS,mBAAmB,KAAK,SAAS,sFAAwC;AAAA,MAC3F;AAAA,IACJ;AAAA,IAKA,UAAU,MAAM;AAAA,EACpB;;;ACrEA,MAA8B,YAA9B,MAAuG;AAAA,IAKnG,YAAsB,MAAwB,MAAqB;AAA7C;AAAwB;AAAA,IAAsB;AAAA,IAKpE,UAAU,MAAM,KAAK;AAAA,IAKrB,eAAe,MAAM,KAAK;AAAA,EAW9B;;;AC5BA,MAA8B,QAA9B,cAA4C,UAAiC;AAAA,IAMzE,YAAY,MAAc,MAA6B,WAAmB;AACtE,YAAM,MAAM,IAAI;AADmC;AAAA,IAEvD;AAAA,IAKA,eAAe,MAAM,KAAK;AAAA,IAK1B,UAAU,MAAM;AAAA,IAKhB,aAAoC;AAChC,aAAO;AAAA,QACH,MAAM,KAAK,QAAQ;AAAA,QACnB,MAAM,KAAK,aAAa;AAAA,QACxB,WAAW,KAAK,aAAa;AAAA,MACjC;AAAA,IACJ;AAAA,EAQJ;;;ACzCA,MAAqB,QAArB,cAAmC,MAAM;AAAA,IAKrC,YAAY,WAAmB,MAAqB;AAChD,YAAM,SAAS,MAAM,SAAS;AAAA,IAClC;AAAA,IAOA,cAAc,CAAC,UAAiB;AAE5B,YAAM,uBAAuB,OAAO,eAAe,OAAO,KAAK,aAAa,CAAC;AAG7E,UAAI,yBAAyB,MAAM;AAC/B,cAAM,IAAI;AAAA,UACN,gDAAgD,KAAK,aAAa;AAAA,QACtE;AAAA,MACJ;AAGA,aAAO,CAAC,CAAC,qBAAqB,KAAK,IAAI;AAAA,IAC3C;AAAA,EACJ;;;AC5BA,MAAqB,QAArB,cAAmC,MAAM;AAAA,IAKrC,YAAY,WAAmB,MAAqB;AAChD,YAAM,SAAS,MAAM,SAAS;AAAA,IAClC;AAAA,IAOA,cAAc,CAAC,UAAiB;AAE5B,YAAM,uBAAuB,OAAO,eAAe,OAAO,KAAK,aAAa,CAAC;AAG7E,UAAI,yBAAyB,MAAM;AAC/B,cAAM,IAAI;AAAA,UACN,gDAAgD,KAAK,aAAa;AAAA,QACtE;AAAA,MACJ;AAGA,aAAO,CAAC,CAAC,CAAC,qBAAqB,KAAK,IAAI;AAAA,IAC5C;AAAA,EACJ;;;ACxBA,MAA8B,WAA9B,cAA+C,UAAoC;AAAA,IAM/E,YAAY,MAAc,MAA6B,cAAsB;AACzE,YAAM,MAAM,IAAI;AADmC;AAAA,IAEvD;AAAA,IAKA,kBAAkB,MAAM,KAAK;AAAA,IAK7B,UAAU,MAAM;AAAA,IAKhB,aAAuC;AACnC,aAAO;AAAA,QACH,MAAM,KAAK,QAAQ;AAAA,QACnB,MAAM,KAAK,aAAa;AAAA,QACxB,cAAc,KAAK,gBAAgB;AAAA,MACvC;AAAA,IACJ;AAAA,EAOJ;;;ACxCA,MAAqB,QAArB,cAAmC,SAAS;AAAA,IAKxC,YAAY,cAAsB,MAAqB;AACnD,YAAM,SAAS,MAAM,YAAY;AAAA,IACrC;AAAA,IAMA,oBAAoB,CAAC,UAAiB;AAElC,YAAM,sBAAsB,OAAO,eAAe,OAAO,KAAK,gBAAgB,CAAC;AAG/E,UAAI,wBAAwB,MAAM;AAC9B,cAAM,IAAI;AAAA,UACN,+BAA+B,KAAK,gBAAgB;AAAA,QACxD;AAAA,MACJ;AAGA,0BAAoB,KAAK,IAAI;AAAA,IACjC;AAAA,EACJ;;;AC3BA,MAAqB,OAArB,cAAkC,SAAS;AAAA,IAKvC,YAAY,cAAsB,MAAqB;AACnD,YAAM,QAAQ,MAAM,YAAY;AAAA,IACpC;AAAA,IAQA,oBAAoB,CAAC,OAAc,WAAoB,cAAuB;AAE1E,YAAM,sBAAsB,OAAO,eAAe,OAAO,KAAK,gBAAgB,CAAC;AAG/E,UAAI,wBAAwB,MAAM;AAC9B,cAAM,IAAI;AAAA,UACN,8BAA8B,KAAK,gBAAgB;AAAA,QACvD;AAAA,MACJ;AAGA,0BAAoB,CAAC,EAAE,OAAO,EAAE,WAAW,WAAW,SAAS,UAAU,EAAE,GAAG,GAAG,KAAK,IAAI,CAAC;AAAA,IAC/F;AAAA,EACJ;;;AC7BA,MAAqB,OAArB,cAAkC,SAAS;AAAA,IAKvC,YAAY,cAAsB,MAAqB;AACnD,YAAM,QAAQ,MAAM,YAAY;AAAA,IACpC;AAAA,IAMA,oBAAoB,CAAC,UAAiB;AAElC,YAAM,sBAAsB,OAAO,eAAe,OAAO,KAAK,gBAAgB,CAAC;AAG/E,UAAI,wBAAwB,MAAM;AAC9B,cAAM,IAAI;AAAA,UACN,8BAA8B,KAAK,gBAAgB;AAAA,QACvD;AAAA,MACJ;AAGA,0BAAoB,KAAK,IAAI;AAAA,IACjC;AAAA,EACJ;;;ACqBA,MAAM,qBAEF;AAAA,IACA,OAAO,CAAC,WAAmB,uBAAsC,IAAI,MAAM,WAAW,kBAAkB;AAAA,IACxG,OAAO,CAAC,WAAmB,uBAAsC,IAAI,MAAM,WAAW,kBAAkB;AAAA,IACxG,OAAO,CAAC,cAAsB,uBAAsC,IAAI,MAAM,cAAc,kBAAkB;AAAA,IAC9G,MAAM,CAAC,cAAsB,uBAAsC,IAAI,KAAK,cAAc,kBAAkB;AAAA,IAC5G,MAAM,CAAC,cAAsB,uBAAsC,IAAI,KAAK,cAAc,kBAAkB;AAAA,EAChH;AAkGA,MAAM,mBAAmB;AAAA,IACrB,MAAM,OAAoB;AAAA,MACtB,MAAM;AAAA,MACN,YAAY,CAAC;AAAA,MACb,MAAM;AAAA,MACN,UAAU,CAAC;AAAA,MACX,SAAS,OAAe;AAEpB,YAAI,QAAQ,GAAG;AACX,gBAAM,IAAI,MAAM,iDAAiD;AAAA,QACrE;AAGA,YAAI,KAAK,SAAS,WAAW,GAAG;AAC5B,gBAAM,IAAI,MAAM,sCAAsC;AAAA,QAC1D;AAAA,MACJ;AAAA,MACA,mBAAmB,uBAAuB,iBAAiB;AACvD,eAAO,IAAI;AAAA,UACP,KAAK;AAAA,UACL,KAAK,SAAU,GAAG,mBAAmB,uBAAuB,gBAAgB,MAAM,CAAC;AAAA,QACvF;AAAA,MACJ;AAAA,IACJ;AAAA,IACA,QAAQ,OAAsB;AAAA,MAC1B,MAAM;AAAA,MACN,YAAY;AAAA,MACZ,WAAW;AAAA,MAAC;AAAA,MACZ,mBAAmB,uBAAuB,iBAAiB;AAEvD,cAAM,iBAAiB,sBAAsB,KAAK,UAAU;AAG5D,YAAI,gBAAgB,QAAQ,KAAK,UAAU,MAAM,IAAI;AACjD,gBAAM,IAAI,MAAM,mEAAmE,KAAK,aAAa;AAAA,QACzG;AAGA,YAAI,gBAAgB;AAChB,iBAAO,eACF,mBAAmB,uBAAuB,gBAAgB,OAAO,KAAK,UAAU,CAAC,EACjF,YAAY,EAAE;AAAA,QACvB,OAAO;AACH,gBAAM,IAAI,MAAM,gCAAgC,KAAK,wCAAwC;AAAA,QACjG;AAAA,MACJ;AAAA,IACJ;AAAA,IACA,UAAU,OAAyB;AAAA,MAC/B,MAAM;AAAA,MACN,YAAY,CAAC;AAAA,MACb,UAAU,CAAC;AAAA,MACX,WAAW;AAEP,YAAI,KAAK,SAAS,SAAS,GAAG;AAC1B,gBAAM,IAAI,MAAM,mDAAmD;AAAA,QACvE;AAAA,MACJ;AAAA,MACA,mBAAmB,uBAAuB,iBAAiB;AACvD,eAAO,IAAI;AAAA,UACP,KAAK;AAAA,UACL,KAAK,SAAS,IAAI,CAAC,UAAU,MAAM,mBAAmB,uBAAuB,gBAAgB,MAAM,CAAC,CAAC;AAAA,QACzG;AAAA,MACJ;AAAA,IACJ;AAAA,IACA,UAAU,OAAyB;AAAA,MAC/B,MAAM;AAAA,MACN,YAAY,CAAC;AAAA,MACb,UAAU,CAAC;AAAA,MACX,WAAW;AAEP,YAAI,KAAK,SAAS,SAAS,GAAG;AAC1B,gBAAM,IAAI,MAAM,mDAAmD;AAAA,QACvE;AAAA,MACJ;AAAA,MACA,mBAAmB,uBAAuB,iBAAiB;AACvD,eAAO,IAAI;AAAA,UACP,KAAK;AAAA,UACL,KAAK,SAAS,IAAI,CAAC,UAAU,MAAM,mBAAmB,uBAAuB,gBAAgB,MAAM,CAAC,CAAC;AAAA,QACzG;AAAA,MACJ;AAAA,IACJ;AAAA,IACA,UAAU,OAAyB;AAAA,MAC/B,MAAM;AAAA,MACN,YAAY,CAAC;AAAA,MACb,UAAU,CAAC;AAAA,MACX,WAAW;AAEP,YAAI,KAAK,SAAS,SAAS,GAAG;AAC1B,gBAAM,IAAI,MAAM,mDAAmD;AAAA,QACvE;AAAA,MACJ;AAAA,MACA,mBAAmB,uBAAuB,iBAAiB;AACvD,eAAO,IAAI;AAAA,UACP,KAAK;AAAA,UACL,KAAK,SAAS,IAAI,CAAC,UAAU,MAAM,mBAAmB,uBAAuB,gBAAgB,MAAM,CAAC,CAAC;AAAA,QACzG;AAAA,MACJ;AAAA,IACJ;AAAA,IACA,OAAO,OAAqB;AAAA,MACxB,MAAM;AAAA,MACN,YAAY,CAAC;AAAA,MACb,UAAU,CAAC;AAAA,MACX,SAAS,CAAC;AAAA,MACV,WAAW;AAEP,YAAI,KAAK,SAAU,SAAS,GAAG;AAC3B,gBAAM,IAAI,MAAM,gDAAgD;AAAA,QACpE;AAAA,MACJ;AAAA,MACA,mBAAmB,uBAAuB,iBAAiB;AACvD,eAAO,IAAI;AAAA,UACP,KAAK;AAAA,UACL,KAAK;AAAA,UACL,KAAK,SAAU,IAAI,CAAC,UAAU,MAAM,mBAAmB,uBAAuB,gBAAgB,MAAM,CAAC,CAAC;AAAA,QAC1G;AAAA,MACJ;AAAA,IACJ;AAAA,IACA,QAAQ,OAAsB;AAAA,MAC1B,MAAM;AAAA,MACN,YAAY,CAAC;AAAA,MACb,YAAY;AAAA,MACZ,eAAe;AAAA,MACf,eAAe;AAAA,MACf,UAAU,CAAC;AAAA,MACX,WAAW;AAEP,YAAI,KAAK,SAAU,WAAW,GAAG;AAC7B,gBAAM,IAAI,MAAM,wCAAwC;AAAA,QAC5D;AAEA,YAAI,KAAK,eAAe,MAAM;AAE1B,cAAI,KAAK,aAAa,GAAG;AACrB,kBAAM,IAAI,MAAM,oEAAoE;AAAA,UACxF;AAAA,QACJ,WAAW,KAAK,kBAAkB,QAAQ,KAAK,kBAAkB,MAAM;AAEnE,cAAI,KAAK,gBAAgB,KAAK,KAAK,gBAAgB,GAAG;AAClD,kBAAM,IAAI;AAAA,cACN;AAAA,YACJ;AAAA,UACJ;AAGA,cAAI,KAAK,gBAAgB,KAAK,eAAe;AACzC,kBAAM,IAAI;AAAA,cACN;AAAA,YACJ;AAAA,UACJ;AAAA,QACJ,OAAO;AAAA,QAEP;AAAA,MACJ;AAAA,MACA,mBAAmB,uBAAuB,iBAAiB;AACvD,eAAO,IAAI;AAAA,UACP,KAAK;AAAA,UACL,KAAK;AAAA,UACL,KAAK;AAAA,UACL,KAAK;AAAA,UACL,KAAK,SAAU,GAAG,mBAAmB,uBAAuB,gBAAgB,MAAM,CAAC;AAAA,QACvF;AAAA,MACJ;AAAA,IACJ;AAAA,IACA,OAAO,OAAqB;AAAA,MACxB,MAAM;AAAA,MACN,YAAY,CAAC;AAAA,MACb,UAAU;AAAA,MACV,aAAa;AAAA,MACb,aAAa;AAAA,MACb,UAAU,CAAC;AAAA,MACX,WAAW;AAEP,YAAI,KAAK,SAAU,WAAW,GAAG;AAC7B,gBAAM,IAAI,MAAM,uCAAuC;AAAA,QAC3D;AAEA,YAAI,KAAK,aAAa,MAAM;AAExB,cAAI,KAAK,WAAW,GAAG;AACnB,kBAAM,IAAI,MAAM,iEAAiE;AAAA,UACrF;AAAA,QACJ,WAAW,KAAK,gBAAgB,QAAQ,KAAK,gBAAgB,MAAM;AAE/D,cAAI,KAAK,cAAc,KAAK,KAAK,cAAc,GAAG;AAC9C,kBAAM,IAAI,MAAM,gFAAgF;AAAA,UACpG;AAGA,cAAI,KAAK,cAAc,KAAK,aAAa;AACrC,kBAAM,IAAI;AAAA,cACN;AAAA,YACJ;AAAA,UACJ;AAAA,QACJ,OAAO;AAAA,QAEP;AAAA,MACJ;AAAA,MACA,mBAAmB,uBAAuB,iBAAiB;AACvD,eAAO,IAAI;AAAA,UACP,KAAK;AAAA,UACL,KAAK;AAAA,UACL,KAAK;AAAA,UACL,KAAK;AAAA,UACL,KAAK,SAAU,GAAG,mBAAmB,uBAAuB,gBAAgB,MAAM,CAAC;AAAA,QACvF;AAAA,MACJ;AAAA,IACJ;AAAA,IACA,MAAM,OAAyB;AAAA,MAC3B,MAAM;AAAA,MACN,YAAY,CAAC;AAAA,MACb,UAAU,CAAC;AAAA,MACX,WAAW;AAEP,YAAI,KAAK,SAAU,WAAW,GAAG;AAC7B,gBAAM,IAAI,MAAM,sCAAsC;AAAA,QAC1D;AAAA,MACJ;AAAA,MACA,mBAAmB,uBAAuB,iBAAiB;AACvD,eAAO,IAAI;AAAA,UACP,KAAK;AAAA,UACL,KAAK,SAAU,GAAG,mBAAmB,uBAAuB,gBAAgB,MAAM,CAAC;AAAA,QACvF;AAAA,MACJ;AAAA,IACJ;AAAA,IACA,SAAS,OAAyB;AAAA,MAC9B,MAAM;AAAA,MACN,YAAY,CAAC;AAAA,MACb,UAAU,CAAC;AAAA,MACX,WAAW;AAEP,YAAI,KAAK,SAAU,WAAW,GAAG;AAC7B,gBAAM,IAAI,MAAM,yCAAyC;AAAA,QAC7D;AAAA,MACJ;AAAA,MACA,mBAAmB,uBAAuB,iBAAiB;AACvD,eAAO,IAAI;AAAA,UACP,KAAK;AAAA,UACL,KAAK,SAAU,GAAG,mBAAmB,uBAAuB,gBAAgB,MAAM,CAAC;AAAA,QACvF;AAAA,MACJ;AAAA,IACJ;AAAA,IACA,MAAM,OAAyB;AAAA,MAC3B,MAAM;AAAA,MACN,YAAY,CAAC;AAAA,MACb,UAAU,CAAC;AAAA,MACX,WAAW;AAEP,YAAI,KAAK,SAAU,WAAW,GAAG;AAC7B,gBAAM,IAAI,MAAM,sCAAsC;AAAA,QAC1D;AAAA,MACJ;AAAA,MACA,mBAAmB,uBAAuB,iBAAiB;AACvD,eAAO,IAAI;AAAA,UACP,KAAK;AAAA,UACL,KAAK,SAAU,GAAG,mBAAmB,uBAAuB,gBAAgB,MAAM,CAAC;AAAA,QACvF;AAAA,MACJ;AAAA,IACJ;AAAA,IACA,MAAM,OAAoB;AAAA,MACtB,MAAM;AAAA,MACN,YAAY,CAAC;AAAA,MACb,UAAU;AAAA,MACV,aAAa;AAAA,MACb,aAAa;AAAA,MACb,WAAW;AACP,YAAI,KAAK,aAAa,MAAM;AAExB,cAAI,KAAK,WAAW,GAAG;AACnB,kBAAM,IAAI,MAAM,2CAA2C;AAAA,UAC/D;AAAA,QACJ,WAAW,KAAK,gBAAgB,QAAQ,KAAK,gBAAgB,MAAM;AAE/D,cAAI,KAAK,cAAc,KAAK,KAAK,cAAc,GAAG;AAC9C,kBAAM,IAAI,MAAM,+DAA+D;AAAA,UACnF;AAGA,cAAI,KAAK,cAAc,KAAK,aAAa;AACrC,kBAAM,IAAI,MAAM,gFAAgF;AAAA,UACpG;AAAA,QACJ,OAAO;AAAA,QAEP;AAAA,MACJ;AAAA,MACA,qBAAqB;AACjB,eAAO,IAAI,KAAK,KAAK,YAAY,KAAK,UAAU,KAAK,aAAa,KAAK,WAAW;AAAA,MACtF;AAAA,IACJ;AAAA,IACA,QAAQ,OAAsB;AAAA,MAC1B,MAAM;AAAA,MACN,YAAY,CAAC;AAAA,MACb,YAAY;AAAA,MACZ,iBAAiB,CAAC;AAAA,MAClB,WAAW;AAAA,MAAC;AAAA,MACZ,qBAAqB;AACjB,eAAO,IAAI,OAAO,KAAK,YAAY,KAAK,YAAa,KAAK,eAAgB;AAAA,MAC9E;AAAA,IACJ;AAAA,IACA,WAAW,OAAyB;AAAA,MAChC,MAAM;AAAA,MACN,YAAY,CAAC;AAAA,MACb,eAAe;AAAA,MACf,oBAAoB,CAAC;AAAA,MACrB,WAAW;AAAA,MAAC;AAAA,MACZ,qBAAqB;AACjB,eAAO,IAAI,UAAU,KAAK,YAAY,KAAK,eAAgB,KAAK,kBAAmB;AAAA,MACvF;AAAA,IACJ;AAAA,EACJ;AASe,WAAR,kBAAmC,YAAmC;AAEzE,UAAM,EAAE,cAAc,oBAAoB,IAAI,yBAAyB,UAAU;AAGjF,UAAM,SAAS,0BAA0B,mBAAmB;AAG5D,QAAI,OAAO,SAAS,GAAG;AACnB,YAAM,IAAI,MAAM,qBAAqB;AAAA,IACzC;AAGA,QAAI,OAAO,OAAO,CAAC,UAAU,UAAU,GAAG,EAAE,WAAW,OAAO,OAAO,CAAC,UAAU,UAAU,GAAG,EAAE,QAAQ;AACnG,YAAM,IAAI,MAAM,0BAA0B;AAAA,IAC9C;AAGA,UAAM,QAA6C,CAAC,CAAC,CAAC;AACtD,UAAM,YAAY,MAAM;AAGxB,WAAO,OAAO,QAAQ;AAElB,YAAM,QAAQ,OAAO,MAAM;AAE3B,YAAM,eAAe,MAAM,MAAM,SAAS;AAG1C,cAAQ,MAAO,YAAY,GAAG;AAAA,QAC1B,KAAK,QAAQ;AAET,gBAAM,OAAO,iBAAiB,KAAK;AAGnC,oBAAU,KAAK,IAAI;AAGnB,cAAI,OAAO,OAAO,KAAK;AACnB,kBAAM,gBAAgB,aAAa,QAAQ,YAAY;AAGvD,gBAAI,cAAc,WAAW,KAAK,cAAc,GAAG,SAAS,cAAc;AAEtE,mBAAK,OAAO,cAAc,GAAG;AAAA,YACjC,OAAO;AACH,oBAAM,IAAI,MAAM,oCAAoC;AAAA,YACxD;AAAA,UACJ;AAGA,eAAK,aAAa,cAAc,QAAQ,YAAY;AAEpD,sBAAY,QAAQ,GAAG;AAGvB,gBAAM,KAAK,KAAK,QAAS;AACzB;AAAA,QACJ;AAAA,QAEA,KAAK,UAAU;AAEX,gBAAM,OAAO,iBAAiB,OAAO;AAGrC,uBAAa,KAAK,IAAI;AAGtB,cAAI,OAAO,OAAO,KAAK;AACnB,kBAAM,IAAI,MAAM,sCAAsC;AAAA,UAC1D;AAGA,gBAAM,kBAAkB,aAAa,QAAQ,YAAY;AAGzD,cAAI,gBAAgB,WAAW,KAAK,gBAAgB,GAAG,SAAS,cAAc;AAE1E,iBAAK,aAAa,gBAAgB,GAAG;AAAA,UACzC,OAAO;AACH,kBAAM,IAAI,MAAM,sCAAsC;AAAA,UAC1D;AACA;AAAA,QACJ;AAAA,QAEA,KAAK,YAAY;AAEb,gBAAM,OAAO,iBAAiB,SAAS;AAGvC,uBAAa,KAAK,IAAI;AAGtB,eAAK,aAAa,cAAc,QAAQ,YAAY;AAEpD,sBAAY,QAAQ,GAAG;AAGvB,gBAAM,KAAK,KAAK,QAAS;AACzB;AAAA,QACJ;AAAA,QAEA,KAAK,YAAY;AAEb,gBAAM,OAAO,iBAAiB,SAAS;AAGvC,uBAAa,KAAK,IAAI;AAGtB,eAAK,aAAa,cAAc,QAAQ,YAAY;AAEpD,sBAAY,QAAQ,GAAG;AAGvB,gBAAM,KAAK,KAAK,QAAS;AACzB;AAAA,QACJ;AAAA,QAEA,KAAK,YAAY;AAEb,gBAAM,OAAO,iBAAiB,SAAS;AAGvC,uBAAa,KAAK,IAAI;AAGtB,eAAK,aAAa,cAAc,QAAQ,YAAY;AAEpD,sBAAY,QAAQ,GAAG;AAGvB,gBAAM,KAAK,KAAK,QAAS;AACzB;AAAA,QACJ;AAAA,QAEA,KAAK,SAAS;AAEV,gBAAM,OAAO,iBAAiB,MAAM;AAGpC,uBAAa,KAAK,IAAI;AAGtB,cAAI,OAAO,OAAO,KAAK;AAEnB,iBAAK,UAAU;AAAA,cACX;AAAA,cACA;AAAA,cACA,CAAC,QAAQ,IAAI,SAAS,YAAY,CAAC,CAAC,IAAI;AAAA,cACxC;AAAA,YACJ,EAAE,IAAI,CAAC,aAAa,SAAS,KAAe;AAAA,UAChD;AAGA,eAAK,aAAa,cAAc,QAAQ,YAAY;AAEpD,sBAAY,QAAQ,GAAG;AAGvB,gBAAM,KAAK,KAAK,QAAS;AACzB;AAAA,QACJ;AAAA,QAEA,KAAK,aAAa;AAEd,gBAAM,OAAO,iBAAiB,UAAU;AAGxC,uBAAa,KAAK,IAAI;AAGtB,cAAI,OAAO,OAAO,KAAK;AACnB,kBAAM,IAAI,MAAM,6CAA6C;AAAA,UACjE;AAGA,gBAAM,qBAAqB,aAAa,QAAQ,YAAY;AAG5D,cAAI,mBAAmB,UAAU,mBAAmB,GAAG,SAAS,cAAc;AAE1E,iBAAK,gBAAgB,mBAAmB,MAAM,EAAG;AAAA,UACrD,OAAO;AACH,kBAAM,IAAI,MAAM,6CAA6C;AAAA,UACjE;AAGA,6BACK,OAAO,CAAC,QAAQ,IAAI,SAAS,YAAY,EACzC,QAAQ,CAAC,QAAQ;AACd,kBAAM,IAAI;AAAA,cACN,4CACI,IAAI,QACJ;AAAA,YACR;AAAA,UACJ,CAAC;AAGL,eAAK,qBAAqB;AAG1B,eAAK,aAAa,cAAc,QAAQ,YAAY;AACpD;AAAA,QACJ;AAAA,QAEA,KAAK,QAAQ;AAET,gBAAM,OAAO,iBAAiB,KAAK;AAGnC,uBAAa,KAAK,IAAI;AAGtB,eAAK,aAAa,cAAc,QAAQ,YAAY;AAEpD,sBAAY,QAAQ,GAAG;AAGvB,gBAAM,KAAK,KAAK,QAAS;AACzB;AAAA,QACJ;AAAA,QAEA,KAAK,WAAW;AAEZ,gBAAM,OAAO,iBAAiB,QAAQ;AAGtC,uBAAa,KAAK,IAAI;AAGtB,eAAK,aAAa,cAAc,QAAQ,YAAY;AAEpD,sBAAY,QAAQ,GAAG;AAGvB,gBAAM,KAAK,KAAK,QAAS;AACzB;AAAA,QACJ;AAAA,QAEA,KAAK,QAAQ;AAET,gBAAM,OAAO,iBAAiB,KAAK;AAGnC,uBAAa,KAAK,IAAI;AAGtB,eAAK,aAAa,cAAc,QAAQ,YAAY;AAEpD,sBAAY,QAAQ,GAAG;AAGvB,gBAAM,KAAK,KAAK,QAAS;AACzB;AAAA,QACJ;AAAA,QAEA,KAAK,QAAQ;AAET,gBAAM,OAAO,iBAAiB,KAAK;AAGnC,uBAAa,KAAK,IAAI;AAMtB,cAAI,OAAO,OAAO,KAAK;AAEnB,kBAAM,gBAAgB;AAAA,cAClB;AAAA,cACA;AAAA,cACA,CAAC,QAAQ,IAAI,SAAS,YAAY,CAAC,CAAC,IAAI;AAAA,cACxC;AAAA,YACJ,EAAE,IAAI,CAAC,aAAa,SAAS,KAAK;AAMlC,gBAAI,cAAc,WAAW,GAAG;AAE5B,mBAAK,WAAW,cAAc;AAAA,YAClC,WAAW,cAAc,WAAW,GAAG;AAEnC,mBAAK,cAAc,cAAc;AACjC,mBAAK,cAAc,cAAc;AAAA,YACrC,WAAW,cAAc,SAAS,GAAG;AAEjC,oBAAM,IAAI,MAAM,wDAAwD;AAAA,YAC5E;AAAA,UACJ;AAGA,eAAK,aAAa,cAAc,QAAQ,YAAY;AACpD;AAAA,QACJ;AAAA,QAEA,KAAK,UAAU;AAEX,gBAAM,OAAO,iBAAiB,OAAO;AAGrC,uBAAa,KAAK,IAAI;AAMtB,cAAI,OAAO,OAAO,KAAK;AAEnB,kBAAM,gBAAgB;AAAA,cAClB;AAAA,cACA;AAAA,cACA,CAAC,QAAQ,IAAI,SAAS,YAAY,CAAC,CAAC,IAAI;AAAA,cACxC;AAAA,YACJ,EAAE,IAAI,CAAC,aAAa,SAAS,KAAK;AAGlC,gBAAI,cAAc,WAAW,GAAG;AAE5B,mBAAK,aAAa,cAAc;AAAA,YACpC,WAAW,cAAc,WAAW,GAAG;AAEnC,mBAAK,gBAAgB,cAAc;AACnC,mBAAK,gBAAgB,cAAc;AAAA,YACvC,OAAO;AAEH,oBAAM,IAAI,MAAM,iEAAiE;AAAA,YACrF;AAAA,UACJ;AAGA,eAAK,aAAa,cAAc,QAAQ,YAAY;AAEpD,sBAAY,QAAQ,GAAG;AAGvB,gBAAM,KAAK,KAAK,QAAS;AACzB;AAAA,QACJ;AAAA,QAEA,KAAK,SAAS;AAEV,gBAAM,OAAO,iBAAiB,MAAM;AAGpC,uBAAa,KAAK,IAAI;AAMtB,cAAI,OAAO,OAAO,KAAK;AAEnB,kBAAM,gBAAgB;AAAA,cAClB;AAAA,cACA;AAAA,cACA,CAAC,QAAQ,IAAI,SAAS,YAAY,CAAC,CAAC,IAAI;AAAA,cACxC;AAAA,YACJ,EAAE,IAAI,CAAC,aAAa,SAAS,KAAK;AAGlC,gBAAI,cAAc,WAAW,GAAG;AAE5B,mBAAK,WAAW,cAAc;AAAA,YAClC,WAAW,cAAc,WAAW,GAAG;AAEnC,mBAAK,cAAc,cAAc;AACjC,mBAAK,cAAc,cAAc;AAAA,YACrC,OAAO;AAEH,oBAAM,IAAI,MAAM,8DAA8D;AAAA,YAClF;AAAA,UACJ;AAGA,eAAK,aAAa,cAAc,QAAQ,YAAY;AAEpD,sBAAY,QAAQ,GAAG;AAGvB,gBAAM,KAAK,KAAK,QAAS;AACzB;AAAA,QACJ;AAAA,QAEA,KAAK,UAAU;AAEX,gBAAM,OAAO,iBAAiB,OAAO;AAGrC,uBAAa,KAAK,IAAI;AAGtB,cAAI,OAAO,OAAO,KAAK;AACnB,kBAAM,IAAI,MAAM,0CAA0C;AAAA,UAC9D;AAGA,gBAAM,kBAAkB,aAAa,QAAQ,YAAY;AAGzD,cAAI,gBAAgB,UAAU,gBAAgB,GAAG,SAAS,cAAc;AAEpE,iBAAK,aAAa,gBAAgB,MAAM,EAAG;AAAA,UAC/C,OAAO;AACH,kBAAM,IAAI,MAAM,0CAA0C;AAAA,UAC9D;AAGA,0BACK,OAAO,CAAC,QAAQ,IAAI,SAAS,YAAY,EACzC,QAAQ,CAAC,QAAQ;AACd,kBAAM,IAAI;AAAA,cACN,yCACI,IAAI,QACJ;AAAA,YACR;AAAA,UACJ,CAAC;AAGL,eAAK,kBAAkB;AAGvB,eAAK,aAAa,cAAc,QAAQ,YAAY;AACpD;AAAA,QACJ;AAAA,QAEA,KAAK,KAAK;AAEN,gBAAM,IAAI;AACV;AAAA,QACJ;AAAA,QAEA,SAAS;AACL,gBAAM,IAAI,MAAM,qBAAqB,QAAQ;AAAA,QACjD;AAAA,MACJ;AAAA,IACJ;AAGA,UAAM,kBAAkB,CAAC,MAAmB,UAAwB;AAEhE,WAAK,SAAS,KAAK;AAGnB,OAAC,KAAK,YAAY,CAAC,GAAG,QAAQ,CAAC,UAAU,gBAAgB,OAAO,QAAQ,CAAC,CAAC;AAAA,IAC9E;AAGA;AAAA,MACI;AAAA,QACI,UAAU,MAAM;AAAA,QAChB,WAA4C;AAExC,cAAI,KAAK,SAAS,WAAW,GAAG;AAC5B,kBAAM,IAAI,MAAM,yCAAyC;AAAA,UAC7D;AAGA,qBAAW,uBAAuB,KAAK,UAAU;AAC7C,gBAAI,oBAAoB,SAAS,QAAQ;AACrC,oBAAM,IAAI,MAAM,0CAA0C;AAAA,YAC9D;AAAA,UACJ;AAGA,cAAI,KAAK,SAAS,OAAO,CAAC,wBAAwB,oBAAoB,SAAS,IAAI,EAAE,WAAW,GAAG;AAC/F,kBAAM,IAAI,MAAM,6EAA6E;AAAA,UACjG;AAGA,gBAAM,gBAA0B,CAAC;AACjC,qBAAW,uBAAuB,KAAK,UAAU;AAC7C,gBAAI,cAAc,QAAQ,oBAAoB,IAAK,MAAM,IAAI;AACzD,oBAAM,IAAI,MAAM,kDAAkD,oBAAoB,OAAO;AAAA,YACjG,OAAO;AACH,4BAAc,KAAK,oBAAoB,IAAK;AAAA,YAChD;AAAA,UACJ;AAAA,QACJ;AAAA,MACJ;AAAA,MACA;AAAA,IACJ;AAGA,WAAO,MAAM;AAAA,EACjB;AAQA,WAAS,YAAY,QAAkB,UAA6B;AAEhE,UAAM,SAAS,OAAO,MAAM;AAG5B,QAAI,WAAW,QAAW;AACtB,YAAM,IAAI,MAAM,8BAA8B;AAAA,IAClD;AAGA,QAAI,aAAa,QAAW;AAExB,UAAI,0BAA2B,CAAC,EAC3B,OAAO,QAAQ,EACf,KAAK,CAAC,SAAS,OAAO,YAAY,MAAM,KAAK,YAAY,CAAC;AAG/D,UAAI,CAAC,yBAAyB;AAC1B,cAAM,oBAAqB,CAAC,EACvB,OAAO,QAAQ,EACf,IAAI,CAAC,SAAS,MAAM,OAAO,GAAG,EAC9B,KAAK,MAAM;AAEhB,cAAM,IAAI,MAAM,qCAAqC,+BAA+B,SAAS;AAAA,MACjG;AAAA,IACJ;AAGA,WAAO;AAAA,EACX;AAYA,WAAS,aACL,QACA,4BACA,mBACA,yBACF;AAGE,UAAM,SAAS,YAAY,QAAQ,CAAC,KAAK,GAAG,CAAC,MAAM,MAAM,MAAM;AAE/D,UAAM,qBAA+B,CAAC;AACtC,UAAM,eAA8B,CAAC;AAGrC,WAAO,OAAO,UAAU,OAAO,OAAO,QAAQ;AAE1C,yBAAmB,KAAK,OAAO,MAAM,CAAE;AAAA,IAC3C;AAGA,uBAAmB,QAAQ,CAAC,OAAO,UAAU;AAEzC,YAAM,wBAAwB,EAAE,QAAQ;AAGxC,UAAI,uBAAuB;AAEvB,cAAM,qBAAqB,sBAAsB,OAAQ,0BAA0B;AAGnF,YAAI,qBAAqB,CAAC,kBAAkB,kBAAkB,GAAG;AAC7D,gBAAM,IAAI,MAAM,uBAAuB;AAAA,QAC3C;AAGA,qBAAa,KAAK,kBAAkB;AAAA,MACxC,OAAO;AAEH,YAAI,UAAU,KAAK;AACf,gBAAM,IAAI,MAAM,uDAAuD,QAAQ;AAAA,QACnF;AAAA,MACJ;AAAA,IACJ,CAAC;AAGD,gBAAY,QAAQ,MAAM;AAG1B,WAAO;AAAA,EACX;AAQA,WAAS,sBAAsB,OAAe,4BAAuD;AAEjG,QAAI,UAAU,QAAQ;AAClB,aAAO;AAAA,QACH,OAAO;AAAA,QACP,MAAM;AAAA,MACV;AAAA,IACJ;AAGA,QAAI,UAAU,UAAU,UAAU,SAAS;AACvC,aAAO;AAAA,QACH,OAAO,UAAU;AAAA,QACjB,MAAM;AAAA,MACV;AAAA,IACJ;AAKA,QAAI,CAAC,MAAM,KAAY,GAAG;AACtB,aAAO;AAAA,QACH,OAAO,WAAW,KAAK;AAAA,QACvB,WAAW,WAAW,KAAK,MAAM,SAAS,OAAO,EAAE;AAAA,QACnD,MAAM;AAAA,MACV;AAAA,IACJ;AAGA,QAAI,MAAM,MAAM,YAAY,GAAG;AAC3B,aAAO;AAAA,QACH,OAAO,2BAA2B,OAAO,QAAQ,OAAO,GAAG;AAAA,QAC3D,MAAM;AAAA,MACV;AAAA,IACJ;AAGA,WAAO;AAAA,MACH,OAAO;AAAA,MACP,MAAM;AAAA,IACV;AAAA,EACJ;AAQA,WAAS,cAAc,QAAkB,4BAA0C;AAE/E,UAAM,aAA0B,CAAC;AAGjC,UAAM,kBAA4B,CAAC;AAGnC,QAAI,mBAAmB,oBAAoB,OAAO,MAAM,IAAI,YAAY;AAGxE,WAAO,kBAAkB;AAErB,UAAI,gBAAgB,QAAQ,OAAO,GAAG,YAAY,CAAC,MAAM,IAAI;AACzD,cAAM,IAAI,MAAM,wBAAwB,OAAO,GAAG,YAAY,mBAAmB;AAAA,MACrF;AAGA,sBAAgB,KAAK,OAAO,MAAM,EAAG,YAAY,CAAC;AAGlD,YAAM,qBAAqB,aAAa,QAAQ,0BAA0B;AAG1E,UAAI,mBAAmB,WAAW,KAAK,mBAAmB,GAAG,SAAS,cAAc;AAChF,cAAM,IAAI,MAAM,gEAAgE;AAAA,MACpF;AAGA,YAAM,wBAAwB,mBAAmB,MAAM;AAGvD,yBACK,OAAO,CAAC,QAAQ,IAAI,SAAS,YAAY,EACzC,QAAQ,CAAC,QAAQ;AACd,cAAM,IAAI;AAAA,UACN,uCAAuC,IAAI,QAAQ;AAAA,QACvD;AAAA,MACJ,CAAC;AAGL,iBAAW,KAAK,iBAAiB,sBAAsB,OAAO,kBAAkB,CAAC;AAGjF,yBAAmB,oBAAoB,OAAO,MAAM,IAAI,YAAY;AAAA,IACxE;AAEA,WAAO;AAAA,EACX;AAOA,WAAS,yBAAyB,YAGhC;AAEE,UAAM,eAA6B,CAAC;AAGpC,UAAM,sBAAsB,WAAW,QAAQ,sBAAsB,CAAC,UAAU;AAC5E,UAAI,gBAAgB,MAAM,UAAU,GAAG,MAAM,SAAS,CAAC;AACvD,UAAI,cAAc,OAAO,KAAK,YAAY,EAAE,KAAK,CAAC,QAAQ,aAAa,SAAS,aAAa;AAG7F,UAAI,CAAC,aAAa;AACd,sBAAc,KAAK,OAAO,KAAK,YAAY,EAAE;AAC7C,qBAAa,eAAe;AAAA,MAChC;AAEA,aAAO;AAAA,IACX,CAAC;AAED,WAAO,EAAE,cAAc,oBAAoB;AAAA,EAC/C;AAOA,WAAS,0BAA0B,YAA8B;AAE7D,iBAAa,WAAW,QAAQ,OAAO,KAAK;AAC5C,iBAAa,WAAW,QAAQ,OAAO,KAAK;AAC5C,iBAAa,WAAW,QAAQ,OAAO,KAAK;AAC5C,iBAAa,WAAW,QAAQ,OAAO,KAAK;AAC5C,iBAAa,WAAW,QAAQ,OAAO,KAAK;AAC5C,iBAAa,WAAW,QAAQ,OAAO,KAAK;AAC5C,iBAAa,WAAW,QAAQ,OAAO,KAAK;AAG5C,WAAO,WAAW,QAAQ,QAAQ,GAAG,EAAE,KAAK,EAAE,MAAM,GAAG;AAAA,EAC3D;;;ACrqCO,MAAM,gBAAN,MAAoB;AAAA,IAYvB,YAAY,YAA4B,OAAsB,UAAgC,CAAC,GAAG;AAA1D;AAAsB;AAE1D,UAAI,OAAO,eAAe,UAAU;AAChC,cAAM,IAAI,MAAM,sCAAsC;AAAA,MAC1D;AAGA,UAAI,OAAO,UAAU,YAAY,UAAU,MAAM;AAC7C,cAAM,IAAI,MAAM,wCAAwC;AAAA,MAC5D;AAGA,WAAK,WAAW,cAAc,gBAAgB,UAAU;AAAA,IAC5D;AAAA,IArBgB;AAAA,IA2BhB,YAAY;AACR,aAAO,KAAK,SAAS,SAAS;AAAA,IAClC;AAAA,IAMA,WAAW;AACP,aAAO,KAAK,SAAS,SAAS;AAAA,IAClC;AAAA,IAUA,OAAO;AAEH,UAAI,KAAK,SAAS,SAAS,iDAAyB,KAAK,SAAS,SAAS,yCAAoB;AAC3F,aAAK,SAAS,MAAM;AAAA,MACxB;AAEA,UAAI;AACA,aAAK,SAAS,OAAO,KAAK,OAAO,KAAK,OAAO;AAAA,MACjD,SAAS,WAAP;AACE,cAAM,IAAI,MAAM,wBAAyB,UAAoB,SAAS;AAAA,MAC1E;AAAA,IACJ;AAAA,IAKA,QAAQ;AACJ,WAAK,SAAS,MAAM;AAAA,IACxB;AAAA,IAMA,0BAA+C;AAE3C,YAAM,qBAA0C,CAAC;AAOjD,YAAM,cAAc,CAAC,MAAY,cAA6B;AAE1D,cAAM,SAAS,KACV,cAAc,EACd,OAAO,CAAC,cAAc,UAAU,QAAQ,CAAC,EACzC,IAAI,CAAC,cAAc,UAAU,WAAW,CAAC;AAC9C,cAAM,YAAY,KACb,cAAc,EACd,OAAO,CAAC,cAAc,CAAC,UAAU,QAAQ,CAAC,EAC1C,IAAI,CAAC,cAAc,UAAU,WAAW,CAAC;AAG9C,2BAAmB,KAAK;AAAA,UACpB,IAAI,KAAK,OAAO;AAAA,UAChB,MAAM,KAAK,QAAQ;AAAA,UACnB,SAAS,KAAK,QAAQ;AAAA,UACtB,OAAO,KAAK,SAAS;AAAA,UACrB;AAAA,UACA;AAAA,UACA,MAAM,KAAK,aAAa;AAAA,UACxB,UAAU;AAAA,QACd,CAAC;AAGD,YAAI,CAAC,KAAK,WAAW,GAAG;AACpB,UAAC,KACI,YAAY,EACZ,QAAQ,CAAC,UAAU,YAAY,OAAQ,KAA+B,OAAO,CAAC,CAAC;AAAA,QACxF;AAAA,MACJ;AAGA,kBAAY,KAAK,UAAU,IAAI;AAE/B,aAAO;AAAA,IACX;AAAA,IAOA,OAAO,SAAS,MAAc,OAAgC;AAC1D,UAAI,OAAO,UAAU,YAAY;AAE7B,eAAO,QAAQ,MAAM,KAAK;AAAA,MAC9B,WAAW,OAAO,UAAU,UAAU;AAElC,YAAI;AAEJ,YAAI;AAEA,yBAAe,kBAAkB,KAAK;AAAA,QAC1C,SAAS,WAAP;AAEE,gBAAM,IAAI,MAAM,iCAAkC,UAAoB,SAAS;AAAA,QACnF;AAGA,YAAI,aAAa,UAAU,KAAK,aAAa,GAAG,SAAS,MAAM;AAC3D,gBAAM,IAAI,MAAM,mEAAmE;AAAA,QACvF;AAEA,eAAO,WAAW,MAAM,aAAa,EAAE;AAAA,MAC3C,OAAO;AACH,cAAM,IAAI,MAAM,0DAA0D;AAAA,MAC9E;AAAA,IACJ;AAAA,IAMA,OAAO,WAAW,MAAoB;AAClC,aAAO,OAAO,IAAI;AAAA,IACtB;AAAA,IAKA,OAAO,gBAAsB;AACzB,aAAO,MAAM;AAAA,IACjB;AAAA,IAOA,OAAe,gBAAgB,YAA0B;AAErD,UAAI;AAAA,MAEJ,SAAS,WAAP;AACE,gBAAQ,IAAI,SAAS;AAAA,MACzB;AAEA,UAAI;AAEA,cAAM,eAAe,kBAAkB,UAAU;AAGjD,cAAM,kBAAkB,OAAO,UAAU;AAGzC,cAAM,cAAuD,CAAC;AAC9D,mBAAW,eAAe,cAAc;AACpC,sBAAY,YAAY,SAAS,OAAO,kBAAkB,YAAY,QAAS;AAAA,QACnF;AAGA,cAAM,WAAiB,YAAY,iBAAiB;AAAA,UAEhD,CAAC,SAA+B,YAAY,QAAQ,YAAY,QAAQ,OAAO,WAAW,IAAI;AAAA,UAC9F,CAAC;AAAA,QACL;AAGA,sBAAc,yBAAyB,QAAQ;AAG/C,eAAO;AAAA,MACX,SAAS,WAAP;AAEE,cAAM,IAAI,MAAM,uBAAwB,UAAoB,SAAS;AAAA,MACzE;AAAA,IACJ;AAAA,IAMA,OAAe,yBAAyB,UAAgB;AACpD,YAAM,YAAsB,CAAC;AAE7B,YAAM,gBAAgB,CAAC,MAAc,SAAe;AAEhD,eAAO,KAAK,OAAO,IAAI;AAGvB,YAAI,KAAK,WAAW,GAAG;AACnB,oBAAU,KAAK,IAAI;AAAA,QACvB,OAAO;AACH,UAAC,KAA+B,YAAY,EAAE,QAAQ,CAAC,UAAU,cAAc,MAAM,KAAK,CAAC;AAAA,QAC/F;AAAA,MACJ;AAGA,oBAAc,CAAC,GAAG,QAAQ;AAE1B,gBAAU,QAAQ,CAAC,SAAS;AAExB,iBAAS,QAAQ,GAAG,QAAQ,KAAK,QAAQ,SAAS;AAE9C,gBAAM,cAAc,KAAK;AAGzB,cAAI,YAAY,aAAa,GAAG;AAC5B;AAAA,UACJ;AAGA,gBAAM,YAAY,IAAI;AAAA,YAClB,KACK,MAAM,GAAG,QAAQ,CAAC,EAClB,IAAmB,CAAC,UAAU,EAAE,MAAM,QAAQ,KAAK,mBAAmB,EAAE,EAAE,EAC1E,OAAO,CAAC,YAAY,QAAQ,OAAO,SAAS,CAAC;AAAA,UACtD;AAGA,sBAAY,aAAa,SAAS;AAAA,QACtC;AAAA,MACJ,CAAC;AAAA,IACL;AAAA,EACJ;", + "sourcesContent": ["\"use strict\";\r\nObject.defineProperty(exports, \"__esModule\", { value: true });\r\nexports.Participant = void 0;\r\n/**\r\n * A participant that holds a number of tickets.\r\n */\r\nvar Participant = /** @class */ (function () {\r\n /**\r\n * Creates an instance of the Participant class.\r\n * @param participant The actual participant.\r\n * @param tickets The number of tickets held by the participant.\r\n */\r\n function Participant(participant, tickets) {\r\n if (tickets === void 0) { tickets = 1; }\r\n this._participant = participant;\r\n this._tickets = tickets;\r\n }\r\n Object.defineProperty(Participant.prototype, \"participant\", {\r\n /** Gets the actual participant. */\r\n get: function () {\r\n return this._participant;\r\n },\r\n enumerable: false,\r\n configurable: true\r\n });\r\n Object.defineProperty(Participant.prototype, \"tickets\", {\r\n /** Gets or sets the number of tickets held by the participant. */\r\n get: function () {\r\n return this._tickets;\r\n },\r\n set: function (value) {\r\n this._tickets = value;\r\n },\r\n enumerable: false,\r\n configurable: true\r\n });\r\n return Participant;\r\n}());\r\nexports.Participant = Participant;\r\n", "\"use strict\";\r\nObject.defineProperty(exports, \"__esModule\", { value: true });\r\nexports.isNaturalNumber = exports.isNullOrUndefined = void 0;\r\n/**\r\n * Gets whether the value provided is null or undefined.\r\n * @param value The value to check.\r\n * @returns Whether the value provided is null or undefined.\r\n */\r\nfunction isNullOrUndefined(value) {\r\n return value === null || value === undefined;\r\n}\r\nexports.isNullOrUndefined = isNullOrUndefined;\r\n/**\r\n * Gets whether the value provided is a natural number.\r\n * @param value The value to check.\r\n * @returns Whether the value provided is a natural number.\r\n */\r\nfunction isNaturalNumber(value) {\r\n return typeof value === \"number\" && value >= 1 && Math.floor(value) === value;\r\n}\r\nexports.isNaturalNumber = isNaturalNumber;\r\n", "\"use strict\";\r\nObject.defineProperty(exports, \"__esModule\", { value: true });\r\nexports.Lotto = void 0;\r\nvar Participant_1 = require(\"./Participant\");\r\nvar Utilities_1 = require(\"./Utilities\");\r\n/**\r\n * Represents a lotto consisting of a number of pickable ticket-holding participants.\r\n */\r\nvar Lotto = /** @class */ (function () {\r\n /**\r\n * Creates a new instance of Lotto.\r\n * @param customRandom The custom RNG to use in place of Math.random().\r\n */\r\n function Lotto(customRandom) {\r\n /** The array of participants that are holding tickets in the lotto. */\r\n this._participants = [];\r\n this._customRandom = customRandom;\r\n }\r\n /**\r\n * Adds a participant with the specified number of tickets, or adds to the participant ticket count if the participant already holds tickets.\r\n * @param participant The participant to add or to increase the ticket count for if they already hold tickets.\r\n * @param tickets The number of tickets, defaults to 1.\r\n * @returns The Lotto instance.\r\n */\r\n Lotto.prototype.add = function (participant, tickets) {\r\n if (tickets === void 0) { tickets = 1; }\r\n // Check that we have a valid ticket count.\r\n if (!(0, Utilities_1.isNaturalNumber)(tickets)) {\r\n throw new Error(\"tickets value must be a natural number\");\r\n }\r\n // Check whether this participant has already been added.\r\n var existingParticipant = this._participants.find(function (part) { return part.participant === participant; });\r\n if (existingParticipant) {\r\n // The participant has already been added to the lotto so just add to their ticket count.\r\n existingParticipant.tickets += tickets;\r\n }\r\n else {\r\n // The participant is not part of the lotto so we should add them.\r\n this._participants.push(new Participant_1.Participant(participant, tickets));\r\n }\r\n return this;\r\n };\r\n /**\r\n * Removes the specified number of tickets for the given participant from the draw, or all tickets if a ticket number is not defined.\r\n * @param participant The participant to remove tickets for.\r\n * @param tickets The number of tickets to remove, or undefined if all tickets are to be removed.\r\n * @returns The Lotto instance.\r\n */\r\n Lotto.prototype.remove = function (participant, tickets) {\r\n // Attempt to get the existing participant.\r\n var existingParticipant = this._participants.find(function (part) { return part.participant === participant; });\r\n // There is nothing to do if the specified participant isn't even part of the lotto.\r\n if (!existingParticipant) {\r\n return this;\r\n }\r\n // Check whether a tickets value was given.\r\n if (tickets !== undefined) {\r\n // Check that we have a valid ticket count.\r\n if (!(0, Utilities_1.isNaturalNumber)(tickets)) {\r\n throw new Error(\"tickets value must be a natural number\");\r\n }\r\n existingParticipant.tickets -= tickets;\r\n // If the participant no longer holds any tickets then they should be removed.\r\n if (existingParticipant.tickets < 1) {\r\n this._participants = this._participants.filter(function (part) { return part !== existingParticipant; });\r\n }\r\n }\r\n else {\r\n // We are removing all tickets for the participant so just remove them from the lotto.\r\n this._participants = this._participants.filter(function (part) { return part !== existingParticipant; });\r\n }\r\n return this;\r\n };\r\n /**\r\n * Draw a winning ticket and return the participant that holds the ticket.\r\n * @param options The draw options.\r\n * @returns The participant that holds the winning ticket.\r\n */\r\n Lotto.prototype.draw = function (options) {\r\n if (options === void 0) { options = {}; }\r\n // If we have no participants then just return null.\r\n if (this._participants.length === 0) {\r\n return null;\r\n }\r\n var redrawable = (0, Utilities_1.isNullOrUndefined)(options.redrawable) ? true : options.redrawable;\r\n var pickable = [];\r\n this._participants.forEach(function (_a) {\r\n var participant = _a.participant, tickets = _a.tickets;\r\n for (var ticketCount = 0; ticketCount < tickets; ticketCount++) {\r\n pickable.push(participant);\r\n }\r\n });\r\n var random;\r\n // We need a random floating-point number between 0 (inclusive) and 1 to scale up to pick our winner.\r\n // If a custom random function exists then we should use that or fall back to Math.random().\r\n if (this._customRandom) {\r\n // Call our custom random function to get a random floating-point number.\r\n random = this._customRandom();\r\n // Verify that the result of calling our custom random function is a number between 0 (inclusive) and 1.\r\n if (typeof random !== \"number\" || random < 0 || random >= 1) {\r\n throw new Error(\"the 'random' function provided did not return a number between 0 (inclusive) and 1\");\r\n }\r\n }\r\n else {\r\n // No custom random function was defined so just use good ol' Math.random().\r\n random = Math.random();\r\n }\r\n // Pick a winning participant.\r\n var winner = pickable[Math.floor(random * pickable.length)];\r\n // If the ticket isn't redrawable then we should remove a ticket from the winning participants ticket count.\r\n if (!redrawable) {\r\n this.remove(winner, 1);\r\n }\r\n // Return the winning participant.\r\n return winner;\r\n };\r\n /**\r\n * Draws multiple winning tickets and return an array of the participants that hold the winning tickets.\r\n * @param tickets The number of winning tickets to draw.\r\n * @param options The draw multiple options.\r\n * @returns An array of the participants that hold the winning tickets.\r\n */\r\n Lotto.prototype.drawMultiple = function (tickets, options) {\r\n if (options === void 0) { options = {}; }\r\n var uniqueResults = (0, Utilities_1.isNullOrUndefined)(options.unique) ? false : options.unique;\r\n // Handle cases where the user has asked for zero tickets (no idea why they would do this be we should trust them).\r\n if (tickets === 0) {\r\n return [];\r\n }\r\n // Now that we know out tickets value is not zero we should check that it is a valid natural number.\r\n if (!(0, Utilities_1.isNaturalNumber)(tickets)) {\r\n throw new Error(\"tickets value must be a natural number\");\r\n }\r\n var result = [];\r\n // Keep drawing tickets until we either reach the number of required tickets or we simply run out of tickets to draw.\r\n // We can run out of tickets to draw if 'options.redrawable' is explicity 'false' or we just had no participants when 'drawMultiple' was called.\r\n while (result.length < tickets && this._participants.length > 0) {\r\n result.push(this.draw(options));\r\n }\r\n // If the 'unique' draw option is set then we need to remove duplicates from the result list.\r\n if (uniqueResults) {\r\n // Create an array to store our unique results.\r\n var unique = [];\r\n // Iterate over all of our participants (with potential duplicates) and populate our array of unique values.\r\n for (var _i = 0, result_1 = result; _i < result_1.length; _i++) {\r\n var participant = result_1[_i];\r\n if (unique.indexOf(participant) === -1) {\r\n unique.push(participant);\r\n }\r\n }\r\n result = unique;\r\n }\r\n return result;\r\n };\r\n return Lotto;\r\n}());\r\nexports.Lotto = Lotto;\r\n", "\"use strict\";\r\nObject.defineProperty(exports, \"__esModule\", { value: true });\r\nexports.createLotto = void 0;\r\nvar Lotto_1 = require(\"./Lotto\");\r\n/**\r\n * A function that creates and returns a Lotto instance.\r\n * @param participantsOrOptions An array of initial participants or options relating to the creation of a Lotto instance.\r\n * @returns A new Lotto instance.\r\n */\r\nfunction createLotto(participantsOrOptions) {\r\n // If no initial participants or lotto options were provided as an argument then we can just return a new lotto instance now.\r\n if (!participantsOrOptions) {\r\n return new Lotto_1.Lotto();\r\n }\r\n // Check whether we were provided with an array of initial participants or a lotto options object.\r\n if (Array.isArray(participantsOrOptions)) {\r\n // We are dealing with a pre-defined array of participants.\r\n var participants = participantsOrOptions;\r\n var lotto_1 = new Lotto_1.Lotto();\r\n // If the lotto participants have been defined upfront then we will need to add them all to our lotto instance now.\r\n participants.forEach(function (_a) {\r\n var participant = _a[0], tokens = _a[1];\r\n return lotto_1.add(participant, tokens);\r\n });\r\n // Return the Lotto instance.\r\n return lotto_1;\r\n }\r\n else {\r\n // We are dealing with some lotto options.\r\n var random = participantsOrOptions.random, participants = participantsOrOptions.participants;\r\n // Create a Lotto instance passing the custom RNG function to use in place of Math.random() (which could be undefined).\r\n var lotto_2 = new Lotto_1.Lotto(random);\r\n // If the lotto participants have been defined upfront as part of the options then we will need to add them all to our lotto instance now.\r\n if (participants) {\r\n participants.forEach(function (_a) {\r\n var participant = _a[0], tokens = _a[1];\r\n return lotto_2.add(participant, tokens);\r\n });\r\n }\r\n // Return the Lotto instance.\r\n return lotto_2;\r\n }\r\n}\r\nexports.createLotto = createLotto;\r\n", "\"use strict\";\r\nObject.defineProperty(exports, \"__esModule\", { value: true });\r\nvar createLotto_1 = require(\"./createLotto\");\r\nexports.default = createLotto_1.createLotto;\r\n", "import { BehaviourTree, FlattenedTreeNode } from \"./BehaviourTree\";\nimport State from \"./State\";\n\nexport { BehaviourTree, State };\nexport type { FlattenedTreeNode };\n", "import Node from \"../../nodes/Node\";\n\n/**\n * An exception thrown when evaluating node guard path conditions and a conditions fails.\n */\nexport default class GuardUnsatisifedException extends Error {\n /**\n * @param source The node at which a guard condition failed.\n */\n constructor(private source: Node) {\n super(\"A guard path condition has failed\");\n }\n\n /**\n * Gets whether the specified node is the node at which a guard condition failed.\n * @param node The node to check against the source node.\n * @returns Whether the specified node is the node at which a guard condition failed.\n */\n isSourceNode = (node: Node) => node === this.source;\n}\n", "import { Agent } from \"../../Agent\";\nimport Guard from \"./Guard\";\nimport Node from \"../../nodes/Node\";\nimport GuardUnsatisifedException from \"./GuardUnsatisifedException\";\n\nexport type GuardPathPart = {\n node: Node;\n guards: Guard[];\n};\n\n/**\n * Represents a path of node guards along a root-to-leaf tree path.\n */\nexport default class GuardPath {\n /**\n * @param nodes An array of objects defining a node instance -> guard link, ordered by node depth.\n */\n constructor(private nodes: GuardPathPart[]) {}\n\n /**\n * Evaluate guard conditions for all guards in the tree path, moving outwards from the root.\n * @param agent The agent, required for guard evaluation.\n * @returns An evaluation results object.\n */\n evaluate = (agent: Agent) => {\n // We need to evaluate guard conditions for nodes up the tree, moving outwards from the root.\n for (const details of this.nodes) {\n // There can be multiple guards per node.\n for (const guard of details.guards) {\n // Check whether the guard condition passes, and throw an exception if not.\n if (!guard.isSatisfied(agent)) {\n throw new GuardUnsatisifedException(details.node);\n }\n }\n }\n };\n}\n", "/**\n * Enumeration of node state types.\n */\nexport enum State {\n READY = \"mistreevous.ready\",\n RUNNING = \"mistreevous.running\",\n SUCCEEDED = \"mistreevous.succeeded\",\n FAILED = \"mistreevous.failed\"\n}\n\nexport { State as default };\n\nexport type CompleteState = State.SUCCEEDED | State.FAILED;\nexport type AnyState = State.READY | State.RUNNING | CompleteState;\n", "import { Agent } from \"../Agent\";\nimport Attribute from \"../attributes/Attribute\";\nimport Entry from \"../attributes/callbacks/Entry\";\nimport Exit from \"../attributes/callbacks/Exit\";\nimport Step from \"../attributes/callbacks/Step\";\nimport Guard from \"../attributes/guards/Guard\";\nimport GuardPath from \"../attributes/guards/GuardPath\";\nimport GuardUnsatisifedException from \"../attributes/guards/GuardUnsatisifedException\";\nimport { BehaviourTreeOptions } from \"../BehaviourTreeOptions\";\nimport { AnyArgument } from \"../RootAstNodesBuilder\";\nimport State, { AnyState } from \"../State\";\nimport Leaf from \"./leaf/Leaf\";\n\n/**\n * A base node.\n */\nexport default abstract class Node {\n /**\n * The node uid.\n */\n private readonly uid: string = createNodeUid();\n /**\n * The node state.\n */\n private state: AnyState = State.READY;\n /**\n * The guard path to evaluate as part of a node update.\n */\n private guardPath: GuardPath | undefined;\n\n /**\n * @param type The node type.\n * @param attributes The node attributes.\n * @param args The node argument definitions.\n */\n constructor(private type: string, private attributes: Attribute[], private args: AnyArgument[]) {}\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected abstract onUpdate(agent: Agent, options: BehaviourTreeOptions): void;\n\n /**\n * Gets the name of the node.\n */\n public abstract getName(): string;\n\n /**\n * Gets whether this node is a leaf node.\n */\n public abstract isLeafNode: () => this is Leaf;\n\n /**\n * Gets/Sets the state of the node.\n */\n getState = (): AnyState => this.state;\n setState = (value: AnyState): void => {\n this.state = value;\n };\n\n /**\n * Gets the unique id of the node.\n */\n getUid = () => this.uid;\n\n /**\n * Gets the type of the node.\n */\n getType = () => this.type;\n\n /**\n * Gets the node attributes.\n */\n getAttributes = () => this.attributes;\n\n /**\n * Gets the node arguments.\n */\n getArguments = () => this.args;\n\n /**\n * Gets the node attribute with the specified type, or null if it does not exist.\n */\n getAttribute(type: \"entry\" | \"ENTRY\"): Entry;\n getAttribute(type: \"exit\" | \"EXIT\"): Exit;\n getAttribute(type: \"step\" | \"STEP\"): Step;\n getAttribute(type: string): Attribute {\n return (\n this.getAttributes().filter((decorator) => decorator.getType().toUpperCase() === type.toUpperCase())[0] ||\n null\n );\n }\n\n /**\n * Gets the node attributes.\n */\n getGuardAttributes = (): Guard[] => this.getAttributes().filter((decorator) => decorator.isGuard()) as Guard[];\n\n /**\n * Sets the guard path to evaluate as part of a node update.\n */\n setGuardPath = (value: GuardPath) => (this.guardPath = value);\n\n /**\n * Gets whether a guard path is assigned to this node.\n */\n hasGuardPath = () => !!this.guardPath;\n\n /**\n * Gets whether this node is in the specified state.\n * @param value The value to compare to the node state.\n */\n public is(value: AnyState): boolean {\n return this.state === value;\n }\n\n /**\n * Reset the state of the node.\n */\n public reset(): void {\n this.setState(State.READY);\n }\n\n /**\n * Abort the running of this node.\n * @param agent The agent.\n */\n public abort(agent: Agent): void {\n // There is nothing to do if this node is not in the running state.\n if (!this.is(State.RUNNING)) {\n return;\n }\n\n // Reset the state of this node.\n this.reset();\n\n this.getAttribute(\"exit\")?.callAgentFunction(agent, false, true);\n }\n\n /**\n * Update the node.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n * @returns The result of the update.\n */\n public update(agent: Agent, options: BehaviourTreeOptions): void {\n // If this node is already in a 'SUCCEEDED' or 'FAILED' state then there is nothing to do.\n if (this.is(State.SUCCEEDED) || this.is(State.FAILED)) {\n return;\n }\n\n try {\n // Evaluate all of the guard path conditions for the current tree path.\n this.guardPath!.evaluate(agent);\n\n // If this node is in the READY state then call the ENTRY for this node if it exists.\n if (this.is(State.READY)) {\n this.getAttribute(\"entry\")?.callAgentFunction(agent);\n }\n\n this.getAttribute(\"step\")?.callAgentFunction(agent);\n\n // Do the actual update.\n this.onUpdate(agent, options);\n\n // If this node is now in a 'SUCCEEDED' or 'FAILED' state then call the EXIT for this node if it exists.\n if (this.is(State.SUCCEEDED) || this.is(State.FAILED)) {\n this.getAttribute(\"exit\")?.callAgentFunction(agent, this.is(State.SUCCEEDED), false);\n }\n } catch (error) {\n // If the error is a GuardUnsatisfiedException then we need to determine if this node is the source.\n if (error instanceof GuardUnsatisifedException && error.isSourceNode(this)) {\n // Abort the current node.\n this.abort(agent);\n\n // Any node that is the source of an abort will be a failed node.\n this.setState(State.FAILED);\n } else {\n throw error;\n }\n }\n }\n}\n\n/**\n * Create a randomly generated node uid.\n * @returns A randomly generated node uid.\n */\nfunction createNodeUid(): string {\n var S4 = function () {\n return (((1 + Math.random()) * 0x10000) | 0).toString(16).substring(1);\n };\n return S4() + S4() + \"-\" + S4() + \"-\" + S4() + \"-\" + S4() + \"-\" + S4() + S4() + S4();\n}\n", "import Node from \"../Node\";\n\n/**\n * A leaf node.\n */\nexport default abstract class Leaf extends Node {\n /**\n * Gets whether this node is a leaf node.\n */\n isLeafNode = () => true;\n}\n", "import { ActionResult, Agent, ExitFunctionArg, FunctionArg, GlobalFunction } from \"./Agent\";\nimport { AnyArgument, RootAstNode } from \"./RootAstNodesBuilder\";\n\n// Exit callbacks receive their own special type of argument.\n// There's probably stricter ways to represent this but it feels overly complex right now.\ntype ExitResultArg = { value: ExitFunctionArg };\nexport type AnyExitArgument = AnyArgument | ExitResultArg;\n\nexport type InvokerFunction = (args: AnyExitArgument[]) => ActionResult;\n\n/**\n * A singleton used to store and lookup registered functions and subtrees.\n */\nexport default class Lookup {\n /**\n * The object holding any registered functions keyed on function name.\n */\n private static functionTable: { [key: string]: GlobalFunction } = {};\n /**\n * The object holding any registered sub-trees keyed on tree name.\n */\n private static subtreeTable: { [key: string]: RootAstNode } = {};\n\n /**\n * Gets the function with the specified name.\n * @param name The name of the function.\n * @returns The function with the specified name.\n */\n public static getFunc(name: string): GlobalFunction {\n return this.functionTable[name];\n }\n\n /**\n * Sets the function with the specified name for later lookup.\n * @param name The name of the function.\n * @param func The function.\n */\n public static setFunc(name: string, func: GlobalFunction): void {\n this.functionTable[name] = func;\n }\n\n /**\n * Gets the function invoker for the specified agent and function name.\n * If a function with the specified name exists on the agent object then it will\n * be returned, otherwise we will then check the registered functions for a match.\n * @param agent The agent instance that this behaviour tree is modelling behaviour for.\n * @param name The function name.\n * @returns The function invoker for the specified agent and function name.\n */\n static getFuncInvoker(agent: Agent, name: string): InvokerFunction | null {\n // Check whether the agent contains the specified function.\n const foundOnAgent = agent[name];\n if (foundOnAgent && typeof foundOnAgent === \"function\") {\n return (args: AnyExitArgument[]): boolean | ActionResult =>\n foundOnAgent.apply(\n agent,\n args.map((arg) => arg.value)\n );\n }\n\n // The agent does not contain the specified function but it may have been registered at some point.\n if (this.functionTable[name] && typeof this.functionTable[name] === \"function\") {\n return (args: AnyExitArgument[]) => this.functionTable[name](agent, ...args.map((arg) => arg.value));\n }\n\n // We have no function to invoke.\n return null;\n }\n\n /**\n * Gets the subtree with the specified name.\n * @param name The name of the subtree.\n * @returns The subtree with the specified name.\n */\n static getSubtree(name: string): RootAstNode {\n return this.subtreeTable[name];\n }\n\n /**\n * Sets the subtree with the specified name for later lookup.\n * @param name The name of the subtree.\n * @param subtree The subtree.\n */\n static setSubtree(name: string, subtree: RootAstNode) {\n this.subtreeTable[name] = subtree;\n }\n\n /**\n * Removes the registered function or subtree with the specified name.\n * @param name The name of the registered function or subtree.\n */\n static remove(name: string) {\n delete this.functionTable[name];\n delete this.subtreeTable[name];\n }\n\n /**\n * Remove all registered functions and subtrees.\n */\n static empty() {\n this.functionTable = {};\n this.subtreeTable = {};\n }\n}\n", "import Leaf from \"./Leaf\";\nimport State, { CompleteState } from \"../../State\";\nimport Lookup from \"../../Lookup\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { AnyArgument } from \"../../RootAstNodesBuilder\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * An Action leaf node.\n * This represents an immediate or ongoing state of behaviour.\n */\nexport default class Action extends Leaf {\n /**\n * @param attributes The node attributes.\n * @param actionName The action name.\n * @param actionArguments The array of action argument definitions.\n */\n constructor(attributes: Attribute[], private actionName: string, private actionArguments: AnyArgument[]) {\n super(\"action\", attributes, actionArguments);\n }\n\n /**\n * Whether there is a pending update promise.\n */\n private isUsingUpdatePromise = false;\n\n /**\n * The finished state result of an update promise.\n */\n private updatePromiseStateResult: CompleteState | null = null;\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // If the result of this action depends on an update promise then there is nothing to do until\n // it resolves, unless there has been a value set as a result of the update promise resolving.\n if (this.isUsingUpdatePromise) {\n // Check whether the update promise has resolved with a state value.\n if (this.updatePromiseStateResult) {\n // Set the state of this node to match the state returned by the promise.\n this.setState(this.updatePromiseStateResult);\n }\n\n return;\n }\n\n // Attempt to get the invoker for the action function.\n const actionFuncInvoker = Lookup.getFuncInvoker(agent, this.actionName);\n\n // The action function should be defined.\n if (actionFuncInvoker === null) {\n throw new Error(\n `cannot update action node as the action '${this.actionName}' function is not defined on the agent and has not been registered`\n );\n }\n\n // Call the action function, the result of which may be:\n // - The finished state of this action node.\n // - A promise to return a finished node state.\n // - Undefined if the node should remain in the running state.\n const updateResult = actionFuncInvoker(this.actionArguments) as CompleteState | Promise;\n\n if (updateResult instanceof Promise) {\n updateResult.then(\n (result) => {\n // If 'isUpdatePromisePending' is null then the promise was cleared as it was resolving, probably via an abort of reset.\n if (!this.isUsingUpdatePromise) {\n return;\n }\n\n // Check to make sure the result is a valid finished state.\n if (result !== State.SUCCEEDED && result !== State.FAILED) {\n throw new Error(\n \"action node promise resolved with an invalid value, expected a State.SUCCEEDED or State.FAILED value to be returned\"\n );\n }\n\n // Set pending update promise state result to be processed on next update.\n this.updatePromiseStateResult = result;\n },\n (reason) => {\n // If 'isUpdatePromisePending' is null then the promise was cleared as it was resolving, probably via an abort of reset.\n if (!this.isUsingUpdatePromise) {\n return;\n }\n\n // Just throw whatever was returned as the rejection argument.\n throw new Error(reason);\n }\n );\n\n // This node will be in the 'RUNNING' state until the update promise resolves.\n this.setState(State.RUNNING);\n\n // We are now waiting for the promise returned by the use to resolve before we know what state this node is in.\n this.isUsingUpdatePromise = true;\n } else {\n // Validate the returned value.\n this.validateUpdateResult(updateResult);\n\n // Set the state of this node, this may be undefined, which just means that the node is still in the 'RUNNING' state.\n this.setState(updateResult || State.RUNNING);\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => this.actionName;\n\n /**\n * Reset the state of the node.\n */\n reset = () => {\n // Reset the state of this node.\n this.setState(State.READY);\n\n // There is no longer an update promise that we care about.\n this.isUsingUpdatePromise = false;\n this.updatePromiseStateResult = null;\n };\n\n /**\n * Validate the result of an update function call.\n * @param result The result of an update function call.\n */\n private validateUpdateResult = (result: CompleteState | boolean) => {\n switch (result) {\n case State.SUCCEEDED:\n case State.FAILED:\n case undefined:\n return;\n default:\n throw new Error(\n `action '${this.actionName}' 'onUpdate' returned an invalid response, expected an optional State.SUCCEEDED or State.FAILED value to be returned`\n );\n }\n };\n}\n", "import Leaf from \"./Leaf\";\nimport State from \"../../State\";\nimport Lookup from \"../../Lookup\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { AnyArgument } from \"../../RootAstNodesBuilder\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A Condition leaf node.\n * This will succeed or fail immediately based on an agent predicate, without moving to the 'RUNNING' state.\n */\nexport default class Condition extends Leaf {\n /**\n * @param attributes The node attributes.\n * @param conditionName The name of the condition function.\n * @param conditionArguments The array of condition argument definitions.\n */\n constructor(attributes: Attribute[], private conditionName: string, private conditionArguments: AnyArgument[]) {\n super(\"condition\", attributes, conditionArguments);\n }\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // Attempt to get the invoker for the condition function.\n const conditionFuncInvoker = Lookup.getFuncInvoker(agent, this.conditionName);\n\n // The condition function should be defined.\n if (conditionFuncInvoker === null) {\n throw new Error(\n `cannot update condition node as the condition '${this.conditionName}' function is not defined on the agent and has not been registered`\n );\n }\n\n // Call the condition function to determine the state of this node.\n this.setState(!!conditionFuncInvoker(this.conditionArguments) ? State.SUCCEEDED : State.FAILED);\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => this.conditionName;\n}\n", "import Leaf from \"./Leaf\";\nimport State from \"../../State\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { Agent } from \"../../Agent\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A WAIT node.\n * The state of this node will change to SUCCEEDED after a duration of time\n */\nexport default class Wait extends Leaf {\n /**\n * @param attributes The node attributes.\n * @param duration The duration that this node will wait to succeed in milliseconds.\n * @param durationMin The minimum possible duration in milliseconds that this node will wait to succeed.\n * @param durationMax The maximum possible duration in milliseconds that this node will wait to succeed.\n */\n constructor(\n attributes: Attribute[],\n private duration: number | null,\n private durationMin: number | null,\n private durationMax: number | null\n ) {\n super(\"wait\", attributes, []);\n }\n\n /**\n * The time in milliseconds at which this node was first updated.\n */\n private initialUpdateTime: number = 0;\n\n /**\n * The total duration in milliseconds that this node will be waiting for.\n */\n private totalDuration: number | null = null;\n\n /**\n * The duration in milliseconds that this node has been waiting for.\n */\n private waitedDuration: number = 0;\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // If this node is in the READY state then we need to set the initial update time.\n if (this.is(State.READY)) {\n // Set the initial update time.\n this.initialUpdateTime = new Date().getTime();\n\n // Set the initial waited duration.\n this.waitedDuration = 0;\n\n // Are we dealing with an explicit duration or will we be randomly picking a duration between the min and max duration.\n if (this.duration !== null) {\n this.totalDuration = this.duration;\n } else if (this.durationMin !== null && this.durationMax !== null) {\n // We will be picking a random duration between a min and max duration, if the optional 'random' behaviour tree\n // function option is defined then we will be using that, otherwise we will fall back to using Math.random.\n const random = typeof options.random === \"function\" ? options.random : Math.random;\n\n // Pick a random duration between a min and max duration.\n this.totalDuration = Math.floor(\n random() * (this.durationMax - this.durationMin + 1) + this.durationMin\n );\n } else {\n this.totalDuration = null;\n }\n\n // The node is now running until we finish waiting.\n this.setState(State.RUNNING);\n }\n\n // If we have no total duration then this wait node will wait indefinitely until it is aborted.\n if (this.totalDuration === null) {\n return;\n }\n\n // If we have a 'getDeltaTime' function defined as part of our options then we will use it to figure out how long we have waited for.\n if (typeof options.getDeltaTime === \"function\") {\n // Get the delta time.\n const deltaTime = options.getDeltaTime();\n\n // Our delta time must be a valid number and cannot be NaN.\n if (typeof deltaTime !== \"number\" || isNaN(deltaTime)) {\n throw new Error(\"The delta time must be a valid number and not NaN.\");\n }\n\n // Update the amount of time that this node has been waiting for based on the delta time.\n this.waitedDuration += deltaTime * 1000;\n } else {\n // We are not using a delta time, so we will just work out hom much time has passed since the first update.\n this.waitedDuration = new Date().getTime() - this.initialUpdateTime;\n }\n\n // Have we waited long enough?\n if (this.waitedDuration >= this.totalDuration) {\n // We have finished waiting!\n this.setState(State.SUCCEEDED);\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => {\n if (this.duration !== null) {\n return `WAIT ${this.duration}ms`;\n } else if (this.durationMin !== null && this.durationMax !== null) {\n return `WAIT ${this.durationMin}ms-${this.durationMax}ms`;\n } else {\n return \"WAIT\";\n }\n };\n}\n", "import Node from \"../Node\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\n\n/**\n * A decorator node that wraps a single child node.\n */\nexport default abstract class Decorator extends Node {\n /**\n * @param type The node type.\n * @param attributes The node attributes.\n * @param child The child node.\n */\n constructor(type: string, attributes: Attribute[], protected child: Node) {\n super(type, attributes, []);\n }\n\n /**\n * Gets whether this node is a leaf node.\n */\n isLeafNode = () => false;\n\n /**\n * Gets the children of this node.\n */\n getChildren = () => [this.child];\n\n /**\n * Reset the state of the node.\n */\n reset = () => {\n // Reset the state of this node.\n this.setState(State.READY);\n\n // Reset the state of the child node.\n this.child.reset();\n };\n\n /**\n * Abort the running of this node.\n * @param agent The agent.\n */\n abort = (agent: Agent) => {\n // There is nothing to do if this node is not in the running state.\n if (!this.is(State.RUNNING)) {\n return;\n }\n\n // Abort the child node.\n this.child.abort(agent);\n\n // Reset the state of this node.\n this.reset();\n\n this.getAttribute(\"exit\")?.callAgentFunction(agent, false, true);\n };\n}\n", "import Node from \"../Node\";\nimport Decorator from \"./Decorator\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A Root node.\n * The root node will have a single child.\n */\nexport default class Root extends Decorator {\n /**\n * @param attributes The node attributes.\n * @param child The child node.\n */\n constructor(attributes: Attribute[], child: Node) {\n super(\"root\", attributes, child);\n }\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // If the child has never been updated or is running then we will need to update it now.\n if (this.child.getState() === State.READY || this.child.getState() === State.RUNNING) {\n // Update the child of this node.\n this.child.update(agent, options);\n }\n\n // The state of the root node is the state of its child.\n this.setState(this.child.getState());\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => \"ROOT\";\n}\n", "import Node from \"../Node\";\nimport Decorator from \"./Decorator\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A REPEAT node.\n * The node has a single child which can have:\n * -- A number of iterations for which to repeat the child node.\n * -- An infinite repeat loop if neither an iteration count or a condition function is defined.\n * The REPEAT node will stop and have a 'FAILED' state if its child is ever in a 'FAILED' state after an update.\n * The REPEAT node will attempt to move on to the next iteration if its child is ever in a 'SUCCEEDED' state.\n */\nexport default class Repeat extends Decorator {\n /**\n * @param attributes The node attributes.\n * @param iterations The number of iterations to repeat the child node.\n * @param iterationsMin The minimum possible number of iterations to repeat the child node.\n * @param iterationsMax The maximum possible number of iterations to repeat the child node.\n * @param child The child node.\n */\n constructor(\n attributes: Attribute[],\n private iterations: number | null,\n private iterationsMin: number | null,\n private iterationsMax: number | null,\n child: Node\n ) {\n super(\"repeat\", attributes, child);\n }\n\n /**\n * The number of target iterations to make.\n */\n private targetIterationCount: number | null = null;\n\n /**\n * The current iteration count.\n */\n private currentIterationCount: number = 0;\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // If this node is in the READY state then we need to reset the child and the target iteration count.\n if (this.is(State.READY)) {\n // Reset the child node.\n this.child.reset();\n\n // Reset the current iteration count.\n this.currentIterationCount = 0;\n\n // Set the target iteration count.\n this.setTargetIterationCount(options);\n }\n\n // Do a check to see if we can iterate. If we can then this node will move into the 'RUNNING' state.\n // If we cannot iterate then we have hit our target iteration count, which means that the node has succeeded.\n if (this.canIterate()) {\n // This node is in the running state and can do its initial iteration.\n this.setState(State.RUNNING);\n\n // We may have already completed an iteration, meaning that the child node will be in the SUCCEEDED state.\n // If this is the case then we will have to reset the child node now.\n if (this.child.getState() === State.SUCCEEDED) {\n this.child.reset();\n }\n\n // Update the child of this node.\n this.child.update(agent, options);\n\n // If the child moved into the FAILED state when we updated it then there is nothing left to do and this node has also failed.\n // If it has moved into the SUCCEEDED state then we have completed the current iteration.\n if (this.child.getState() === State.FAILED) {\n // The child has failed, meaning that this node has failed.\n this.setState(State.FAILED);\n\n return;\n } else if (this.child.getState() === State.SUCCEEDED) {\n // We have completed an iteration.\n this.currentIterationCount += 1;\n }\n } else {\n // This node is in the 'SUCCEEDED' state as we cannot iterate any more.\n this.setState(State.SUCCEEDED);\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => {\n if (this.iterations !== null) {\n return `REPEAT ${this.iterations}x`;\n } else if (this.iterationsMin !== null && this.iterationsMax !== null) {\n return `REPEAT ${this.iterationsMin}x-${this.iterationsMax}x`;\n } else {\n return \"REPEAT\";\n }\n };\n\n /**\n * Reset the state of the node.\n */\n reset = () => {\n // Reset the state of this node.\n this.setState(State.READY);\n\n // Reset the current iteration count.\n this.currentIterationCount = 0;\n\n // Reset the child node.\n this.child.reset();\n };\n\n /**\n * Gets whether an iteration can be made.\n * @returns Whether an iteration can be made.\n */\n private canIterate = () => {\n if (this.targetIterationCount !== null) {\n // We can iterate as long as we have not reached our target iteration count.\n return this.currentIterationCount < this.targetIterationCount;\n }\n\n // If neither an iteration count or a condition function were defined then we can iterate indefinitely.\n return true;\n };\n\n /**\n * Sets the target iteration count.\n * @param options The behaviour tree options object.\n */\n private setTargetIterationCount = (options: BehaviourTreeOptions) => {\n // Are we dealing with an explicit iteration count or will we be randomly picking a iteration count between the min and max iteration count.\n if (this.iterations !== null) {\n this.targetIterationCount = this.iterations;\n } else if (this.iterationsMin !== null && this.iterationsMax !== null) {\n // We will be picking a random iteration count between a min and max iteration count, if the optional 'random'\n // behaviour tree function option is defined then we will be using that, otherwise we will fall back to using Math.random.\n const random = typeof options.random === \"function\" ? options.random : Math.random;\n\n // Pick a random iteration count between a min and max iteration count.\n this.targetIterationCount = Math.floor(\n random() * (this.iterationsMax - this.iterationsMin + 1) + this.iterationsMin\n );\n } else {\n this.targetIterationCount = null;\n }\n };\n}\n", "import Node from \"../Node\";\nimport Decorator from \"./Decorator\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A RETRY node.\n * The node has a single child which can have:\n * -- A number of iterations for which to repeat the child node.\n * -- An infinite repeat loop if neither an iteration count or a condition function is defined.\n * The RETRY node will stop and have a 'SUCCEEDED' state if its child is ever in a 'SUCCEEDED' state after an update.\n * The RETRY node will attempt to move on to the next iteration if its child is ever in a 'FAILED' state.\n */\nexport default class Retry extends Decorator {\n /**\n * @param attributes The node attributes.\n * @param attempts The number of attempts to retry the child node.\n * @param attemptsMin The minimum possible number of attempts to retry the child node.\n * @param attemptsMax The maximum possible number of attempts to retry the child node.\n * @param child The child node.\n */\n constructor(\n attributes: Attribute[],\n private attempts: number | null,\n private attemptsMin: number | null,\n private attemptsMax: number | null,\n child: Node\n ) {\n super(\"retry\", attributes, child);\n }\n\n /**\n * The number of target attempts to make.\n */\n private targetAttemptCount: number | null = null;\n\n /**\n * The current attempt count.\n */\n private currentAttemptCount: number = 0;\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // If this node is in the READY state then we need to reset the child and the target attempt count.\n if (this.is(State.READY)) {\n // Reset the child node.\n this.child.reset();\n\n // Reset the current attempt count.\n this.currentAttemptCount = 0;\n\n // Set the target attempt count.\n this.setTargetAttemptCount(options);\n }\n\n // Do a check to see if we can attempt. If we can then this node will move into the 'RUNNING' state.\n // If we cannot attempt then we have hit our target attempt count, which means that the node has succeeded.\n if (this.canAttempt()) {\n // This node is in the running state and can do its initial attempt.\n this.setState(State.RUNNING);\n\n // We may have already completed an attempt, meaning that the child node will be in the FAILED state.\n // If this is the case then we will have to reset the child node now.\n if (this.child.getState() === State.FAILED) {\n this.child.reset();\n }\n\n // Update the child of this node.\n this.child.update(agent, options);\n\n // If the child moved into the SUCCEEDED state when we updated it then there is nothing left to do and this node has also succeeded.\n // If it has moved into the FAILED state then we have completed the current attempt.\n if (this.child.getState() === State.SUCCEEDED) {\n // The child has succeeded, meaning that this node has succeeded.\n this.setState(State.SUCCEEDED);\n\n return;\n } else if (this.child.getState() === State.FAILED) {\n // We have completed an attempt.\n this.currentAttemptCount += 1;\n }\n } else {\n // This node is in the 'FAILED' state as we cannot iterate any more.\n this.setState(State.FAILED);\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => {\n if (this.attempts !== null) {\n return `RETRY ${this.attempts}x`;\n } else if (this.attemptsMin !== null && this.attemptsMax !== null) {\n return `RETRY ${this.attemptsMin}x-${this.attemptsMax}x`;\n } else {\n return \"RETRY\";\n }\n };\n\n /**\n * Reset the state of the node.\n */\n reset = () => {\n // Reset the state of this node.\n this.setState(State.READY);\n\n // Reset the current attempt count.\n this.currentAttemptCount = 0;\n\n // Reset the child node.\n this.child.reset();\n };\n\n /**\n * Gets whether an attempt can be made.\n * @returns Whether an attempt can be made.\n */\n canAttempt = () => {\n if (this.targetAttemptCount !== null) {\n // We can attempt as long as we have not reached our target attempt count.\n return this.currentAttemptCount < this.targetAttemptCount;\n }\n\n // If neither an attempt count or a condition function were defined then we can attempt indefinitely.\n return true;\n };\n\n /**\n * Sets the target attempt count.\n * @param options The behaviour tree options object.\n */\n setTargetAttemptCount = (options: BehaviourTreeOptions) => {\n // Are we dealing with an explicit attempt count or will we be randomly picking an attempt count between the min and max attempt count.\n if (this.attempts !== null) {\n this.targetAttemptCount = this.attempts;\n } else if (this.attemptsMin !== null && this.attemptsMax !== null) {\n // We will be picking a random attempt count between a min and max attempt count, if the optional 'random'\n // behaviour tree function option is defined then we will be using that, otherwise we will fall back to using Math.random.\n const random = typeof options.random === \"function\" ? options.random : Math.random;\n\n // Pick a random attempt count between a min and max attempt count.\n this.targetAttemptCount = Math.floor(\n random() * (this.attemptsMax - this.attemptsMin + 1) + this.attemptsMin\n );\n } else {\n this.targetAttemptCount = null;\n }\n };\n}\n", "import Decorator from \"./Decorator\";\nimport State from \"../../State\";\nimport Node from \"../Node\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A Flip node.\n * This node wraps a single child and will flip the state of the child state.\n */\nexport default class Flip extends Decorator {\n /**\n * @param attributes The node attributes.\n * @param child The child node.\n */\n constructor(attributes: Attribute[], child: Node) {\n super(\"flip\", attributes, child);\n }\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // If the child has never been updated or is running then we will need to update it now.\n if (this.child.getState() === State.READY || this.child.getState() === State.RUNNING) {\n this.child.update(agent, options);\n }\n\n // The state of this node will depend in the state of its child.\n switch (this.child.getState()) {\n case State.RUNNING:\n this.setState(State.RUNNING);\n break;\n\n case State.SUCCEEDED:\n this.setState(State.FAILED);\n break;\n\n case State.FAILED:\n this.setState(State.SUCCEEDED);\n break;\n\n default:\n this.setState(State.READY);\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => \"FLIP\";\n}\n", "import Node from \"../Node\";\nimport Decorator from \"./Decorator\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A Succeed node.\n * This node wraps a single child and will always move to the 'SUCCEEDED' state when the child moves to a 'SUCCEEDED' or 'FAILED' state.\n */\nexport default class Succeed extends Decorator {\n /**\n * @param attributes The node attributes.\n * @param child The child node.\n */\n constructor(attributes: Attribute[], child: Node) {\n super(\"succeed\", attributes, child);\n }\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // If the child has never been updated or is running then we will need to update it now.\n if (this.child.getState() === State.READY || this.child.getState() === State.RUNNING) {\n this.child.update(agent, options);\n }\n\n // The state of this node will depend in the state of its child.\n switch (this.child.getState()) {\n case State.RUNNING:\n this.setState(State.RUNNING);\n break;\n\n case State.SUCCEEDED:\n case State.FAILED:\n this.setState(State.SUCCEEDED);\n break;\n\n default:\n this.setState(State.READY);\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => \"SUCCEED\";\n}\n", "import Node from \"../Node\";\nimport Decorator from \"./Decorator\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A Fail node.\n * This node wraps a single child and will always move to the 'FAILED' state when the child moves to a 'SUCCEEDED' or 'FAILED' state.\n */\nexport default class Fail extends Decorator {\n /**\n * @param attributes The node attributes.\n * @param child The child node.\n */\n constructor(attributes: Attribute[], child: Node) {\n super(\"fail\", attributes, child);\n }\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // If the child has never been updated or is running then we will need to update it now.\n if (this.child.getState() === State.READY || this.child.getState() === State.RUNNING) {\n this.child.update(agent, options);\n }\n\n // The state of this node will depend in the state of its child.\n switch (this.child.getState()) {\n case State.RUNNING:\n this.setState(State.RUNNING);\n break;\n\n case State.SUCCEEDED:\n case State.FAILED:\n this.setState(State.FAILED);\n break;\n\n default:\n this.setState(State.READY);\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => \"FAIL\";\n}\n", "import createLotto from \"lotto-draw\";\n\nimport Node from \"../Node\";\nimport Composite from \"./Composite\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A LOTTO node.\n * A winning child is picked on the initial update of this node, based on ticket weighting.\n * The state of this node will match the state of the winning child.\n */\nexport default class Lotto extends Composite {\n /**\n * @param attributes The node attributes.\n * @param tickets The child node tickets.\n * @param children The child nodes.\n */\n constructor(attributes: Attribute[], private tickets: number[], children: Node[]) {\n super(\"lotto\", attributes, children);\n }\n\n /**\n * The child node selected to be the active one.\n */\n private selectedChild: Node | undefined;\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // If this node is in the READY state then we need to pick a winning child node.\n if (this.is(State.READY)) {\n // Create a lotto draw with which to randomly pick a child node to become the active one.\n const lottoDraw = createLotto({\n // Hook up the optional 'random' behaviour tree function option to the one used by 'lotto-draw'.\n random: options.random,\n // Pass in each child node as a participant in the lotto draw with their respective ticket count.\n participants: this.children.map((child, index) => [child, this.tickets[index] || 1])\n });\n\n // Randomly pick a child based on ticket weighting, this will become the active child for this composite node.\n this.selectedChild = lottoDraw.draw() || undefined;\n }\n\n // If something went wrong and we don't have an active child then we should throw an error.\n if (!this.selectedChild) {\n throw new Error(\"failed to update lotto node as it has no active child\");\n }\n\n // If the selected child has never been updated or is running then we will need to update it now.\n if (this.selectedChild.getState() === State.READY || this.selectedChild.getState() === State.RUNNING) {\n this.selectedChild.update(agent, options);\n }\n\n // The state of the lotto node is the state of its selected child.\n this.setState(this.selectedChild.getState());\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => (this.tickets.length ? `LOTTO [${this.tickets.join(\",\")}]` : \"LOTTO\");\n}\n", "import Node from \"../Node\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\n\n/**\n * A composite node that wraps child nodes.\n */\nexport default abstract class Composite extends Node {\n /**\n * @param type The node type.\n * @param attributes The node attributes.\n * @param children The child nodes.\n */\n constructor(type: string, attributes: Attribute[], protected children: Node[]) {\n super(type, attributes, []);\n }\n\n /**\n * Gets whether this node is a leaf node.\n */\n isLeafNode = () => false;\n\n /**\n * Gets the children of this node.\n */\n getChildren = () => this.children;\n\n /**\n * Reset the state of the node.\n */\n reset = () => {\n // Reset the state of this node.\n this.setState(State.READY);\n\n // Reset the state of any child nodes.\n this.getChildren().forEach((child) => child.reset());\n };\n\n /**\n * Abort the running of this node.\n * @param agent The agent.\n */\n abort = (agent: Agent) => {\n // There is nothing to do if this node is not in the running state.\n if (!this.is(State.RUNNING)) {\n return;\n }\n\n // Abort any child nodes.\n this.getChildren().forEach((child) => child.abort(agent));\n\n // Reset the state of this node.\n this.reset();\n\n this.getAttribute(\"exit\")?.callAgentFunction(agent, false, true);\n };\n}\n", "import Composite from \"./Composite\";\nimport Node from \"../Node\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A SELECTOR node.\n * The child nodes are executed in sequence until one succeeds or all fail.\n */\nexport default class Selector extends Composite {\n /**\n * @param attributes The node attributes.\n * @param children The child nodes.\n */\n constructor(attributes: Attribute[], protected children: Node[]) {\n super(\"selector\", attributes, children);\n }\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // Iterate over all of the children of this node.\n for (const child of this.children) {\n // If the child has never been updated or is running then we will need to update it now.\n if (child.getState() === State.READY || child.getState() === State.RUNNING) {\n // Update the child of this node.\n child.update(agent, options);\n }\n\n // If the current child has a state of 'SUCCEEDED' then this node is also a 'SUCCEEDED' node.\n if (child.getState() === State.SUCCEEDED) {\n // This node is a 'SUCCEEDED' node.\n this.setState(State.SUCCEEDED);\n\n // There is no need to check the rest of the selector nodes.\n return;\n }\n\n // If the current child has a state of 'FAILED' then we should move on to the next child.\n if (child.getState() === State.FAILED) {\n // Find out if the current child is the last one in the selector.\n // If it is then this sequence node has also failed.\n if (this.children.indexOf(child) === this.children.length - 1) {\n // This node is a 'FAILED' node.\n this.setState(State.FAILED);\n\n // There is no need to check the rest of the selector as we have completed it.\n return;\n } else {\n // The child node failed, try the next one.\n continue;\n }\n }\n\n // The node should be in the 'RUNNING' state.\n if (child.getState() === State.RUNNING) {\n // This node is a 'RUNNING' node.\n this.setState(State.RUNNING);\n\n // There is no need to check the rest of the selector as the current child is still running.\n return;\n }\n\n // The child node was not in an expected state.\n throw new Error(\"child node was not in an expected state.\");\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => \"SELECTOR\";\n}\n", "import Composite from \"./Composite\";\nimport Node from \"../Node\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A SEQUENCE node.\n * The child nodes are executed in sequence until one fails or all succeed.\n */\nexport default class Sequence extends Composite {\n /**\n * @param attributes The node attributes.\n * @param children The child nodes.\n */\n constructor(attributes: Attribute[], protected children: Node[]) {\n super(\"sequence\", attributes, children);\n }\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // Iterate over all of the children of this node.\n for (const child of this.children) {\n // If the child has never been updated or is running then we will need to update it now.\n if (child.getState() === State.READY || child.getState() === State.RUNNING) {\n // Update the child of this node.\n child.update(agent, options);\n }\n\n // If the current child has a state of 'SUCCEEDED' then we should move on to the next child.\n if (child.getState() === State.SUCCEEDED) {\n // Find out if the current child is the last one in the sequence.\n // If it is then this sequence node has also succeeded.\n if (this.children.indexOf(child) === this.children.length - 1) {\n // This node is a 'SUCCEEDED' node.\n this.setState(State.SUCCEEDED);\n\n // There is no need to check the rest of the sequence as we have completed it.\n return;\n } else {\n // The child node succeeded, but we have not finished the sequence yet.\n continue;\n }\n }\n\n // If the current child has a state of 'FAILED' then this node is also a 'FAILED' node.\n if (child.getState() === State.FAILED) {\n // This node is a 'FAILED' node.\n this.setState(State.FAILED);\n\n // There is no need to check the rest of the sequence.\n return;\n }\n\n // The node should be in the 'RUNNING' state.\n if (child.getState() === State.RUNNING) {\n // This node is a 'RUNNING' node.\n this.setState(State.RUNNING);\n\n // There is no need to check the rest of the sequence as the current child is still running.\n return;\n }\n\n // The child node was not in an expected state.\n throw new Error(\"child node was not in an expected state.\");\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => \"SEQUENCE\";\n}\n", "import Composite from \"./Composite\";\nimport State from \"../../State\";\nimport Node from \"../Node\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A PARALLEL node.\n * The child nodes are executed concurrently until one fails or all succeed.\n */\nexport default class Parallel extends Composite {\n /**\n * @param attributes The node attributes.\n * @param children The child nodes.\n */\n constructor(attributes: Attribute[], children: Node[]) {\n super(\"parallel\", attributes, children);\n }\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // Keep a count of the number of succeeded child nodes.\n let succeededCount = 0;\n\n let hasChildFailed = false;\n\n // Iterate over all of the children of this node.\n for (const child of this.children) {\n // If the child has never been updated or is running then we will need to update it now.\n if (child.getState() === State.READY || child.getState() === State.RUNNING) {\n // Update the child of this node.\n child.update(agent, options);\n }\n\n // If the current child has a state of 'SUCCEEDED' then we should move on to the next child.\n if (child.getState() === State.SUCCEEDED) {\n // The child node has succeeded, keep track of this to determine if all children have.\n succeededCount++;\n\n // The child node succeeded, but we have not finished checking every child node yet.\n continue;\n }\n\n // If the current child has a state of 'FAILED' then this node is also a 'FAILED' node.\n if (child.getState() === State.FAILED) {\n hasChildFailed = true;\n\n // There is no need to check the rest of the children.\n break;\n }\n\n // The node should be in the 'RUNNING' state.\n if (child.getState() !== State.RUNNING) {\n // The child node was not in an expected state.\n throw new Error(\"child node was not in an expected state.\");\n }\n }\n\n if (hasChildFailed) {\n // This node is a 'FAILED' node.\n this.setState(State.FAILED);\n\n // Abort every running child.\n for (const child of this.children) {\n if (child.getState() === State.RUNNING) {\n child.abort(agent);\n }\n }\n } else {\n // If all children have succeeded then this node has also succeeded, otherwise it is still running.\n this.setState(succeededCount === this.children.length ? State.SUCCEEDED : State.RUNNING);\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => \"PARALLEL\";\n}\n", "import { AnyArgument } from \"../RootAstNodesBuilder\";\nimport Guard from \"./guards/Guard\";\n\nexport type AttributeDetails = {\n /** The attribute type. */\n type: string;\n\n /** The attribute arguments. */\n args: AnyArgument[];\n};\n\n/**\n * A base node attribute.\n */\nexport default abstract class Attribute {\n /**\n * @param type The node attribute type.\n * @param args The array of attribute argument definitions.\n */\n constructor(protected type: string, protected args: AnyArgument[]) {}\n\n /**\n * Gets the type of the attribute.\n */\n getType = () => this.type;\n\n /**\n * Gets the array of attribute argument definitions.\n */\n getArguments = () => this.args;\n\n /**\n * Gets the attribute details.\n */\n abstract getDetails(): TAttributeDetails;\n\n /**\n * Gets whether this attribute is a guard.\n */\n abstract isGuard: () => this is Guard;\n}\n", "import { Agent } from \"../../Agent\";\nimport { AnyArgument } from \"../../RootAstNodesBuilder\";\nimport Attribute, { AttributeDetails } from \"../Attribute\";\n\nexport type GuardAttributeDetails = {\n /** The name of the condition function that determines whether the guard is satisfied. */\n condition: string;\n} & AttributeDetails;\n\n/**\n * A base node guard attribute.\n */\nexport default abstract class Guard extends Attribute {\n /**\n * @param type The node attribute type.\n * @param args The array of decorator argument definitions.\n * @param condition The name of the condition function that determines whether the guard is satisfied.\n */\n constructor(type: string, args: AnyArgument[], private condition: string) {\n super(type, args);\n }\n\n /**\n * Gets the name of the condition function that determines whether the guard is satisfied.\n */\n getCondition = () => this.condition;\n\n /**\n * Gets whether this attribute is a guard.\n */\n isGuard = () => true;\n\n /**\n * Gets the attribute details.\n */\n getDetails(): GuardAttributeDetails {\n return {\n type: this.getType(),\n args: this.getArguments(),\n condition: this.getCondition()\n };\n }\n\n /**\n * Gets whether the guard is satisfied.\n * @param agent The agent.\n * @returns Whether the guard is satisfied.\n */\n abstract isSatisfied(agent: Agent): boolean;\n}\n", "import Guard from \"./Guard\";\nimport Lookup from \"../../Lookup\";\nimport { Agent } from \"../../Agent\";\nimport { AnyArgument } from \"../../RootAstNodesBuilder\";\n\n/**\n * A WHILE guard which is satisfied as long as the given condition remains true.\n */\nexport default class While extends Guard {\n /**\n * @param condition The name of the condition function that determines whether the guard is satisfied.\n * @param args The array of decorator argument definitions.\n */\n constructor(condition: string, args: AnyArgument[]) {\n super(\"while\", args, condition);\n }\n\n /**\n * Gets whether the guard is satisfied.\n * @param agent The agent.\n * @returns Whether the guard is satisfied.\n */\n isSatisfied = (agent: Agent) => {\n // Attempt to get the invoker for the condition function.\n const conditionFuncInvoker = Lookup.getFuncInvoker(agent, this.getCondition());\n\n // The condition function should be defined.\n if (conditionFuncInvoker === null) {\n throw new Error(\n `cannot evaluate node guard as the condition '${this.getCondition()}' function is not defined on the agent and has not been registered`\n );\n }\n\n // Call the condition function to determine whether this guard is satisfied.\n return !!conditionFuncInvoker(this.args);\n };\n}\n", "import Guard from \"./Guard\";\nimport Lookup from \"../../Lookup\";\nimport { Agent } from \"../../Agent\";\nimport { AnyArgument } from \"../../RootAstNodesBuilder\";\n\n/**\n * An UNTIL guard which is satisfied as long as the given condition remains false.\n */\nexport default class Until extends Guard {\n /**\n * @param condition The name of the condition function that determines whether the guard is satisfied.\n * @param args The array of decorator argument definitions.\n */\n constructor(condition: string, args: AnyArgument[]) {\n super(\"until\", args, condition);\n }\n\n /**\n * Gets whether the guard is satisfied.\n * @param agent The agent.\n * @returns Whether the guard is satisfied.\n */\n isSatisfied = (agent: Agent) => {\n // Attempt to get the invoker for the condition function.\n const conditionFuncInvoker = Lookup.getFuncInvoker(agent, this.getCondition());\n\n // The condition function should be defined.\n if (conditionFuncInvoker === null) {\n throw new Error(\n `cannot evaluate node guard as the condition '${this.getCondition()}' function is not defined on the agent and has not been registered`\n );\n }\n\n // Call the condition function to determine whether this guard is satisfied.\n return !!!conditionFuncInvoker(this.args);\n };\n}\n", "import { Agent } from \"../../Agent\";\nimport { AnyArgument } from \"../../RootAstNodesBuilder\";\nimport Attribute, { AttributeDetails } from \"../Attribute\";\n\nexport type CallbackAttributeDetails = {\n /** The name of the agent function that is called. */\n functionName: string;\n} & AttributeDetails;\n\n/**\n * A base node callback attribute.\n */\nexport default abstract class Callback extends Attribute {\n /**\n * @param type The node attribute type.\n * @param args The array of decorator argument definitions.\n * @param functionName The name of the agent function to call.\n */\n constructor(type: string, args: AnyArgument[], private functionName: string) {\n super(type, args);\n }\n\n /**\n * Gets the name of the agent function to call.\n */\n getFunctionName = () => this.functionName;\n\n /**\n * Gets whether this attribute is a guard.\n */\n isGuard = () => false;\n\n /**\n * Gets the attribute details.\n */\n getDetails(): CallbackAttributeDetails {\n return {\n type: this.getType(),\n args: this.getArguments(),\n functionName: this.getFunctionName()\n };\n }\n\n /**\n * Attempt to call the agent function that this callback refers to.\n * @param agent The agent.\n */\n abstract callAgentFunction: (agent: Agent, isSuccess: boolean, isAborted: boolean) => void;\n}\n", "import Callback from \"./Callback\";\nimport Lookup from \"../../Lookup\";\nimport { Agent } from \"../../Agent\";\nimport { AnyArgument } from \"../../RootAstNodesBuilder\";\n\n/**\n * An ENTRY callback which defines an agent function to call when the associated node is updated and moves out of running state.\n */\nexport default class Entry extends Callback {\n /**\n * @param functionName The name of the agent function to call.\n * @param args The array of callback argument definitions.\n */\n constructor(functionName: string, args: AnyArgument[]) {\n super(\"entry\", args, functionName);\n }\n\n /**\n * Attempt to call the agent function that this callback refers to.\n * @param agent The agent.\n */\n callAgentFunction = (agent: Agent) => {\n // Attempt to get the invoker for the callback function.\n const callbackFuncInvoker = Lookup.getFuncInvoker(agent, this.getFunctionName());\n\n // The callback function should be defined.\n if (callbackFuncInvoker === null) {\n throw new Error(\n `cannot call entry function '${this.getFunctionName()}' as is not defined on the agent and has not been registered`\n );\n }\n\n // Call the callback function.\n callbackFuncInvoker(this.args);\n };\n}\n", "import Callback from \"./Callback\";\nimport Lookup, { AnyExitArgument } from \"../../Lookup\";\nimport { Agent } from \"../../Agent\";\nimport { AnyArgument } from \"../../RootAstNodesBuilder\";\n\n/**\n * An EXIT callback which defines an agent function to call when the associated node is updated and moves to a finished state or is aborted.\n */\nexport default class Exit extends Callback {\n /**\n * @param functionName The name of the agent function to call.\n * @param args The array of callback argument definitions.\n */\n constructor(functionName: string, args: AnyArgument[]) {\n super(\"exit\", args, functionName);\n }\n\n /**\n * Attempt to call the agent function that this callback refers to.\n * @param agent The agent.\n * @param isSuccess Whether the decorated node was left with a success state.\n * @param isAborted Whether the decorated node was aborted.\n */\n callAgentFunction = (agent: Agent, isSuccess: boolean, isAborted: boolean) => {\n // Attempt to get the invoker for the callback function.\n const callbackFuncInvoker = Lookup.getFuncInvoker(agent, this.getFunctionName());\n\n // The callback function should be defined.\n if (callbackFuncInvoker === null) {\n throw new Error(\n `cannot call exit function '${this.getFunctionName()}' as is not defined on the agent and has not been registered`\n );\n }\n\n // Call the callback function\n callbackFuncInvoker([{ value: { succeeded: isSuccess, aborted: isAborted } }, ...this.args]);\n };\n}\n", "import Callback from \"./Callback\";\nimport Lookup from \"../../Lookup\";\nimport { Agent } from \"../../Agent\";\nimport { AnyArgument } from \"../../RootAstNodesBuilder\";\n\n/**\n * A STEP callback which defines an agent function to call when the associated node is updated.\n */\nexport default class Step extends Callback {\n /**\n * @param functionName The name of the agent function to call.\n * @param args The array of callback argument definitions.\n */\n constructor(functionName: string, args: AnyArgument[]) {\n super(\"step\", args, functionName);\n }\n\n /**\n * Attempt to call the agent function that this callback refers to.\n * @param agent The agent.\n */\n callAgentFunction = (agent: Agent) => {\n // Attempt to get the invoker for the callback function.\n const callbackFuncInvoker = Lookup.getFuncInvoker(agent, this.getFunctionName());\n\n // The callback function should be defined.\n if (callbackFuncInvoker === null) {\n throw new Error(\n `cannot call step function '${this.getFunctionName()}' as is not defined on the agent and has not been registered`\n );\n }\n\n // Call the callback function.\n callbackFuncInvoker(this.args);\n };\n}\n", "import Action from \"./nodes/leaf/Action\";\nimport Condition from \"./nodes/leaf/Condition\";\nimport Wait from \"./nodes/leaf/Wait\";\nimport Root from \"./nodes/decorator/Root\";\nimport Repeat from \"./nodes/decorator/Repeat\";\nimport Retry from \"./nodes/decorator/Retry\";\nimport Flip from \"./nodes/decorator/Flip\";\nimport Succeed from \"./nodes/decorator/Succeed\";\nimport Fail from \"./nodes/decorator/Fail\";\nimport Lotto from \"./nodes/composite/Lotto\";\nimport Selector from \"./nodes/composite/Selector\";\nimport Sequence from \"./nodes/composite/Sequence\";\nimport Parallel from \"./nodes/composite/Parallel\";\nimport Node from \"./nodes/Node\";\nimport While from \"./attributes/guards/While\";\nimport Until from \"./attributes/guards/Until\";\nimport Entry from \"./attributes/callbacks/Entry\";\nimport Exit from \"./attributes/callbacks/Exit\";\nimport Step from \"./attributes/callbacks/Step\";\nimport Callback from \"./attributes/callbacks/Callback\";\nimport Guard from \"./attributes/guards/Guard\";\nimport Attribute from \"./attributes/Attribute\";\nimport Composite from \"./nodes/composite/Composite\";\nimport Decorator from \"./nodes/decorator/Decorator\";\nimport Leaf from \"./nodes/leaf/Leaf\";\n\nexport type Argument = {\n value: T;\n type: string; // Used for validation.\n};\ntype NullArgument = Argument & {\n type: \"null\";\n};\ntype BooleanArgument = Argument & {\n type: \"boolean\";\n};\ntype NumberArgument = Argument & {\n type: \"number\";\n isInteger: boolean; // Used for validation.\n};\ntype StringPlaceholderArgument = Argument & {\n type: \"string\";\n};\ntype IdentifierArgument = Argument & {\n type: \"identifier\";\n};\nexport type AnyArgument =\n | NullArgument\n | BooleanArgument\n | NumberArgument\n | StringPlaceholderArgument\n | IdentifierArgument;\n\n/**\n * The node attribute factories.\n */\nconst AttributeFactories: {\n [key: string]: (functionName: string, attributeArguments: AnyArgument[]) => Callback | Guard;\n} = {\n WHILE: (condition: string, attributeArguments: AnyArgument[]) => new While(condition, attributeArguments),\n UNTIL: (condition: string, attributeArguments: AnyArgument[]) => new Until(condition, attributeArguments),\n ENTRY: (functionName: string, attributeArguments: AnyArgument[]) => new Entry(functionName, attributeArguments),\n EXIT: (functionName: string, attributeArguments: AnyArgument[]) => new Exit(functionName, attributeArguments),\n STEP: (functionName: string, attributeArguments: AnyArgument[]) => new Step(functionName, attributeArguments)\n};\n\ntype Validatable = {\n children?: AstNode[];\n validate: (depth: number) => void;\n};\n\ntype NodeInstanceCreator = (\n namedRootNodeProvider: (name: string) => RootAstNode,\n visitedBranches: string[]\n) => T;\n\nexport type AstNode = Validatable & {\n type: string;\n createNodeInstance: NodeInstanceCreator;\n};\n\nexport type LeafAstNode = AstNode & {\n type: \"action\" | \"condition\" | \"wait\";\n attributes: Attribute[];\n};\n\nexport type CompositeAstNode = AstNode & {\n type: \"lotto\" | \"parallel\" | \"selector\" | \"sequence\";\n attributes: Attribute[];\n children: AstNode[];\n};\n\nexport type DecoratorAstNode = AstNode & {\n type: \"fail\" | \"flip\" | \"repeat\" | \"retry\" | \"root\" | \"succeed\";\n attributes: Attribute[];\n children: AstNode[];\n};\n\nexport type BranchAstNode = AstNode & {\n type: \"branch\";\n branchName: \"\" | string;\n};\n\nexport type LottoAstNode = CompositeAstNode & {\n type: \"lotto\";\n tickets: number[];\n};\n\nexport type RootAstNode = DecoratorAstNode & {\n type: \"root\";\n name: null | string;\n};\n\nexport type RepeatAstNode = DecoratorAstNode & {\n type: \"repeat\";\n iterations: number | null;\n iterationsMin: number | null;\n iterationsMax: number | null;\n};\n\nexport type RetryAstNode = DecoratorAstNode & {\n type: \"retry\";\n attempts: number | null;\n attemptsMin: number | null;\n attemptsMax: number | null;\n};\n\nexport type ActionAstNode = LeafAstNode & {\n type: \"action\";\n actionName: string;\n actionArguments: AnyArgument[];\n};\n\nexport type ConditionAstNode = LeafAstNode & {\n type: \"condition\";\n conditionName: string;\n conditionArguments: AnyArgument[];\n};\n\nexport type WaitAstNode = LeafAstNode & {\n type: \"wait\";\n duration: number | null;\n durationMin: number | null;\n durationMax: number | null;\n};\n\nexport type AnyAstNode =\n | BranchAstNode\n | CompositeAstNode\n | LottoAstNode\n | DecoratorAstNode\n | RootAstNode\n | RepeatAstNode\n | RetryAstNode\n | LeafAstNode\n | ActionAstNode\n | ConditionAstNode\n | WaitAstNode;\n\n/**\n * The AST node factories.\n */\nconst ASTNodeFactories = {\n ROOT: (): RootAstNode => ({\n type: \"root\",\n attributes: [],\n name: null,\n children: [],\n validate(depth: number) {\n // A root node cannot be the child of another node.\n if (depth > 1) {\n throw new Error(\"a root node cannot be the child of another node\");\n }\n\n // A root node must have a single child node.\n if (this.children.length !== 1) {\n throw new Error(\"a root node must have a single child\");\n }\n },\n createNodeInstance(namedRootNodeProvider, visitedBranches) {\n return new Root(\n this.attributes,\n this.children![0].createNodeInstance(namedRootNodeProvider, visitedBranches.slice())\n );\n }\n }),\n BRANCH: (): BranchAstNode => ({\n type: \"branch\",\n branchName: \"\",\n validate() {},\n createNodeInstance(namedRootNodeProvider, visitedBranches) {\n // Try to find the root node with a matching branch name.\n const targetRootNode = namedRootNodeProvider(this.branchName);\n\n // If we have already visited this branch then we have a circular dependency.\n if (visitedBranches.indexOf(this.branchName) !== -1) {\n throw new Error(`circular dependency found in branch node references for branch '${this.branchName}'`);\n }\n\n // If we have a target root node, then the node instance we want will be the first and only child of the referenced root node.\n if (targetRootNode) {\n return targetRootNode\n .createNodeInstance(namedRootNodeProvider, visitedBranches.concat(this.branchName))\n .getChildren()[0];\n } else {\n throw new Error(`branch references root node '${this.branchName}' which has not been defined`);\n }\n }\n }),\n SELECTOR: (): CompositeAstNode => ({\n type: \"selector\",\n attributes: [],\n children: [],\n validate() {\n // A selector node must have at least a single node.\n if (this.children.length < 1) {\n throw new Error(\"a selector node must have at least a single child\");\n }\n },\n createNodeInstance(namedRootNodeProvider, visitedBranches) {\n return new Selector(\n this.attributes,\n this.children.map((child) => child.createNodeInstance(namedRootNodeProvider, visitedBranches.slice()))\n );\n }\n }),\n SEQUENCE: (): CompositeAstNode => ({\n type: \"sequence\",\n attributes: [],\n children: [],\n validate() {\n // A sequence node must have at least a single node.\n if (this.children.length < 1) {\n throw new Error(\"a sequence node must have at least a single child\");\n }\n },\n createNodeInstance(namedRootNodeProvider, visitedBranches) {\n return new Sequence(\n this.attributes,\n this.children.map((child) => child.createNodeInstance(namedRootNodeProvider, visitedBranches.slice()))\n );\n }\n }),\n PARALLEL: (): CompositeAstNode => ({\n type: \"parallel\",\n attributes: [],\n children: [],\n validate() {\n // A parallel node must have at least a single node.\n if (this.children.length < 1) {\n throw new Error(\"a parallel node must have at least a single child\");\n }\n },\n createNodeInstance(namedRootNodeProvider, visitedBranches) {\n return new Parallel(\n this.attributes,\n this.children.map((child) => child.createNodeInstance(namedRootNodeProvider, visitedBranches.slice()))\n );\n }\n }),\n LOTTO: (): LottoAstNode => ({\n type: \"lotto\",\n attributes: [],\n children: [],\n tickets: [],\n validate() {\n // A lotto node must have at least a single node.\n if (this.children!.length < 1) {\n throw new Error(\"a lotto node must have at least a single child\");\n }\n },\n createNodeInstance(namedRootNodeProvider, visitedBranches) {\n return new Lotto(\n this.attributes,\n this.tickets!,\n this.children!.map((child) => child.createNodeInstance(namedRootNodeProvider, visitedBranches.slice()))\n );\n }\n }),\n REPEAT: (): RepeatAstNode => ({\n type: \"repeat\",\n attributes: [],\n iterations: null,\n iterationsMin: null,\n iterationsMax: null,\n children: [],\n validate() {\n // A repeat node must have a single node.\n if (this.children!.length !== 1) {\n throw new Error(\"a repeat node must have a single child\");\n }\n\n if (this.iterations !== null) {\n // A repeat node must have a positive number of iterations if defined.\n if (this.iterations < 0) {\n throw new Error(\"a repeat node must have a positive number of iterations if defined\");\n }\n } else if (this.iterationsMin !== null && this.iterationsMax !== null) {\n // A repeat node must have a positive min and max iteration count if they are defined.\n if (this.iterationsMin < 0 || this.iterationsMax < 0) {\n throw new Error(\n \"a repeat node must have a positive minimum and maximum iteration count if defined\"\n );\n }\n\n // A repeat node must not have an minimum iteration count that exceeds the maximum iteration count.\n if (this.iterationsMin > this.iterationsMax) {\n throw new Error(\n \"a repeat node must not have a minimum iteration count that exceeds the maximum iteration count\"\n );\n }\n } else {\n // If we have no explicit iteration count or a minimum and maximum iteration count set then we are dealing with a repeat node that iterates indefinitely.\n }\n },\n createNodeInstance(namedRootNodeProvider, visitedBranches) {\n return new Repeat(\n this.attributes,\n this.iterations,\n this.iterationsMin,\n this.iterationsMax,\n this.children![0].createNodeInstance(namedRootNodeProvider, visitedBranches.slice())\n );\n }\n }),\n RETRY: (): RetryAstNode => ({\n type: \"retry\",\n attributes: [],\n attempts: null,\n attemptsMin: null,\n attemptsMax: null,\n children: [],\n validate() {\n // A retry node must have a single node.\n if (this.children!.length !== 1) {\n throw new Error(\"a retry node must have a single child\");\n }\n\n if (this.attempts !== null) {\n // A retry node must have a positive number of attempts if defined.\n if (this.attempts < 0) {\n throw new Error(\"a retry node must have a positive number of attempts if defined\");\n }\n } else if (this.attemptsMin !== null && this.attemptsMax !== null) {\n // A retry node must have a positive min and max attempts count if they are defined.\n if (this.attemptsMin < 0 || this.attemptsMax < 0) {\n throw new Error(\"a retry node must have a positive minimum and maximum attempt count if defined\");\n }\n\n // A retry node must not have a minimum attempt count that exceeds the maximum attempt count.\n if (this.attemptsMin > this.attemptsMax) {\n throw new Error(\n \"a retry node must not have a minimum attempt count that exceeds the maximum attempt count\"\n );\n }\n } else {\n // If we have no explicit attempt count or a minimum and maximum attempt count set then we are dealing with a retry node that attempts indefinitely.\n }\n },\n createNodeInstance(namedRootNodeProvider, visitedBranches) {\n return new Retry(\n this.attributes,\n this.attempts,\n this.attemptsMin,\n this.attemptsMax,\n this.children![0].createNodeInstance(namedRootNodeProvider, visitedBranches.slice())\n );\n }\n }),\n FLIP: (): DecoratorAstNode => ({\n type: \"flip\",\n attributes: [],\n children: [],\n validate() {\n // A flip node must have a single node.\n if (this.children!.length !== 1) {\n throw new Error(\"a flip node must have a single child\");\n }\n },\n createNodeInstance(namedRootNodeProvider, visitedBranches) {\n return new Flip(\n this.attributes,\n this.children![0].createNodeInstance(namedRootNodeProvider, visitedBranches.slice())\n );\n }\n }),\n SUCCEED: (): DecoratorAstNode => ({\n type: \"succeed\",\n attributes: [],\n children: [],\n validate() {\n // A succeed node must have a single node.\n if (this.children!.length !== 1) {\n throw new Error(\"a succeed node must have a single child\");\n }\n },\n createNodeInstance(namedRootNodeProvider, visitedBranches) {\n return new Succeed(\n this.attributes,\n this.children![0].createNodeInstance(namedRootNodeProvider, visitedBranches.slice())\n );\n }\n }),\n FAIL: (): DecoratorAstNode => ({\n type: \"fail\",\n attributes: [],\n children: [],\n validate() {\n // A fail node must have a single node.\n if (this.children!.length !== 1) {\n throw new Error(\"a fail node must have a single child\");\n }\n },\n createNodeInstance(namedRootNodeProvider, visitedBranches) {\n return new Fail(\n this.attributes,\n this.children![0].createNodeInstance(namedRootNodeProvider, visitedBranches.slice())\n );\n }\n }),\n WAIT: (): WaitAstNode => ({\n type: \"wait\",\n attributes: [],\n duration: null,\n durationMin: null,\n durationMax: null,\n validate() {\n if (this.duration !== null) {\n // If an explict duration was defined then it must be a positive number.\n if (this.duration < 0) {\n throw new Error(\"a wait node must have a positive duration\");\n }\n } else if (this.durationMin !== null && this.durationMax !== null) {\n // A wait node must have a positive min and max duration.\n if (this.durationMin < 0 || this.durationMax < 0) {\n throw new Error(\"a wait node must have a positive minimum and maximum duration\");\n }\n\n // A wait node must not have a minimum duration that exceeds the maximum duration.\n if (this.durationMin > this.durationMax) {\n throw new Error(\"a wait node must not have a minimum duration that exceeds the maximum duration\");\n }\n } else {\n // If we have no explicit duration or duration bounds set then we are dealing with a wait node that waits indefinitely.\n }\n },\n createNodeInstance() {\n return new Wait(this.attributes, this.duration, this.durationMin, this.durationMax);\n }\n }),\n ACTION: (): ActionAstNode => ({\n type: \"action\",\n attributes: [],\n actionName: \"\",\n actionArguments: [],\n validate() {},\n createNodeInstance() {\n return new Action(this.attributes, this.actionName!, this.actionArguments!);\n }\n }),\n CONDITION: (): ConditionAstNode => ({\n type: \"condition\",\n attributes: [],\n conditionName: \"\",\n conditionArguments: [],\n validate() {},\n createNodeInstance() {\n return new Condition(this.attributes, this.conditionName!, this.conditionArguments!);\n }\n })\n};\n\ntype OtherAstNodes = AstNode[];\n\n/**\n * Create an array of root AST nodes based on the given definition.\n * @param definition The definition to parse the AST nodes from.\n * @returns The base definition AST nodes.\n */\nexport default function buildRootASTNodes(definition: string): RootAstNode[] {\n // Swap out any node/attribute argument string literals with a placeholder and get a mapping of placeholders to original values as well as the processed definition.\n const { placeholders, processedDefinition } = substituteStringLiterals(definition);\n\n // Convert the processed definition (with substituted string literals) into an array of raw tokens.\n const tokens = parseTokensFromDefinition(processedDefinition);\n\n // There must be at least 3 tokens for the tree definition to be valid. 'ROOT', '{' and '}'.\n if (tokens.length < 3) {\n throw new Error(\"invalid token count\");\n }\n\n // We should have a matching number of '{' and '}' tokens. If not, then there are scopes that have not been properly closed.\n if (tokens.filter((token) => token === \"{\").length !== tokens.filter((token) => token === \"}\").length) {\n throw new Error(\"scope character mismatch\");\n }\n\n // Create a stack of node children arrays, starting with a definition scope.\n const stack: [RootAstNode[], ...OtherAstNodes[]] = [[]];\n const rootScope = stack[0];\n\n // We should keep processing the raw tokens until we run out of them.\n while (tokens.length) {\n // Grab the next token.\n const token = tokens.shift();\n\n const currentScope = stack[stack.length - 1] as OtherAstNodes;\n\n // How we create the next AST token depends on the current raw token value.\n switch (token!.toUpperCase()) {\n case \"ROOT\": {\n // Create a ROOT AST node.\n const node = ASTNodeFactories.ROOT();\n\n // Push the ROOT node into the current scope.\n rootScope.push(node);\n\n // We may have a root node name defined as an argument.\n if (tokens[0] === \"[\") {\n const rootArguments = getArguments(tokens, placeholders);\n\n // We should have only a single argument that is not an empty string for a root node, which is the root name identifier.\n if (rootArguments.length === 1 && rootArguments[0].type === \"identifier\") {\n // The root name will be the first and only node argument.\n node.name = rootArguments[0].value as string;\n } else {\n throw new Error(\"expected single root name argument\");\n }\n }\n\n // Try to pick any attributes off of the token stack.\n node.attributes = getAttributes(tokens, placeholders);\n\n popAndCheck(tokens, \"{\");\n\n // The new scope is that of the new ROOT nodes children.\n stack.push(node.children!);\n break;\n }\n\n case \"BRANCH\": {\n // Create a BRANCH AST node.\n const node = ASTNodeFactories.BRANCH();\n\n // Push the BRANCH node into the current scope.\n currentScope.push(node);\n\n // We must have arguments defined, as we require a branch name argument.\n if (tokens[0] !== \"[\") {\n throw new Error(\"expected single branch name argument\");\n }\n\n // The branch name will be defined as a node argument.\n const branchArguments = getArguments(tokens, placeholders);\n\n // We should have only a single identifer argument for a branch node, which is the branch name.\n if (branchArguments.length === 1 && branchArguments[0].type === \"identifier\") {\n // The branch name will be the first and only node argument.\n node.branchName = branchArguments[0].value as string;\n } else {\n throw new Error(\"expected single branch name argument\");\n }\n break;\n }\n\n case \"SELECTOR\": {\n // Create a SELECTOR AST node.\n const node = ASTNodeFactories.SELECTOR();\n\n // Push the SELECTOR node into the current scope.\n currentScope.push(node);\n\n // Try to pick any attributes off of the token stack.\n node.attributes = getAttributes(tokens, placeholders);\n\n popAndCheck(tokens, \"{\");\n\n // The new scope is that of the new SELECTOR nodes children.\n stack.push(node.children!);\n break;\n }\n\n case \"SEQUENCE\": {\n // Create a SEQUENCE AST node.\n const node = ASTNodeFactories.SEQUENCE();\n\n // Push the SEQUENCE node into the current scope.\n currentScope.push(node);\n\n // Try to pick any attributes off of the token stack.\n node.attributes = getAttributes(tokens, placeholders);\n\n popAndCheck(tokens, \"{\");\n\n // The new scope is that of the new SEQUENCE nodes children.\n stack.push(node.children!);\n break;\n }\n\n case \"PARALLEL\": {\n // Create a PARALLEL AST node.\n const node = ASTNodeFactories.PARALLEL();\n\n // Push the PARALLEL node into the current scope.\n currentScope.push(node);\n\n // Try to pick any attributes off of the token stack.\n node.attributes = getAttributes(tokens, placeholders);\n\n popAndCheck(tokens, \"{\");\n\n // The new scope is that of the new PARALLEL nodes children.\n stack.push(node.children!);\n break;\n }\n\n case \"LOTTO\": {\n // Create a LOTTO AST node.\n const node = ASTNodeFactories.LOTTO();\n\n // Push the LOTTO node into the current scope.\n currentScope.push(node);\n\n // If the next token is a '[' character then some ticket counts have been defined as arguments.\n if (tokens[0] === \"[\") {\n // Get the ticket count arguments, each argument must be a number.\n node.tickets = getArguments(\n tokens,\n placeholders,\n (arg) => arg.type === \"number\" && !!arg.isInteger,\n \"lotto node ticket counts must be integer values\"\n ).map((argument) => argument.value as number);\n }\n\n // Try to pick any attributes off of the token stack.\n node.attributes = getAttributes(tokens, placeholders);\n\n popAndCheck(tokens, \"{\");\n\n // The new scope is that of the new LOTTO nodes children.\n stack.push(node.children!);\n break;\n }\n\n case \"CONDITION\": {\n // Create a CONDITION AST node.\n const node = ASTNodeFactories.CONDITION();\n\n // Push the CONDITION node into the current scope.\n currentScope.push(node);\n\n // We must have arguments defined, as we require a condition function name argument.\n if (tokens[0] !== \"[\") {\n throw new Error(\"expected condition name identifier argument\");\n }\n\n // Grab the condition node arguments.\n const conditionArguments = getArguments(tokens, placeholders);\n\n // We should have at least a single identifier argument for a condition node, which is the condition function name.\n if (conditionArguments.length && conditionArguments[0].type === \"identifier\") {\n // The condition function name will be the first node argument.\n node.conditionName = conditionArguments.shift()!.value as string;\n } else {\n throw new Error(\"expected condition name identifier argument\");\n }\n\n // Only the first argument should have been an identifier, all following arguments must be string, number, boolean or null.\n conditionArguments\n .filter((arg) => arg.type === \"identifier\")\n .forEach((arg) => {\n throw new Error(\n \"invalid condition node argument value '\" +\n arg.value +\n \"', must be string, number, boolean or null\"\n );\n });\n\n // Any node arguments that follow the condition name identifier will be treated as condition function arguments.\n node.conditionArguments = conditionArguments;\n\n // Try to pick any attributes off of the token stack.\n node.attributes = getAttributes(tokens, placeholders);\n break;\n }\n\n case \"FLIP\": {\n // Create a FLIP AST node.\n const node = ASTNodeFactories.FLIP();\n\n // Push the Flip node into the current scope.\n currentScope.push(node);\n\n // Try to pick any attributes off of the token stack.\n node.attributes = getAttributes(tokens, placeholders);\n\n popAndCheck(tokens, \"{\");\n\n // The new scope is that of the new FLIP nodes children.\n stack.push(node.children!);\n break;\n }\n\n case \"SUCCEED\": {\n // Create a SUCCEED AST node.\n const node = ASTNodeFactories.SUCCEED();\n\n // Push the Succeed node into the current scope.\n currentScope.push(node);\n\n // Try to pick any attributes off of the token stack.\n node.attributes = getAttributes(tokens, placeholders);\n\n popAndCheck(tokens, \"{\");\n\n // The new scope is that of the new Succeed nodes children.\n stack.push(node.children!);\n break;\n }\n\n case \"FAIL\": {\n // Create a FAIL AST node.\n const node = ASTNodeFactories.FAIL();\n\n // Push the Fail node into the current scope.\n currentScope.push(node);\n\n // Try to pick any attributes off of the token stack.\n node.attributes = getAttributes(tokens, placeholders);\n\n popAndCheck(tokens, \"{\");\n\n // The new scope is that of the new Fail nodes children.\n stack.push(node.children!);\n break;\n }\n\n case \"WAIT\": {\n // Create a WAIT AST node.\n const node = ASTNodeFactories.WAIT();\n\n // Push the WAIT node into the current scope.\n currentScope.push(node);\n\n // The arguments of a wait node are optional. We may have:\n // - No node arguments, in which case the wait will be indefinite until it is aborted.\n // - One node argument which will be the explicit duration of the wait.\n // - Two node arguments which define the min and max duration bounds from which a random duration will be picked.\n if (tokens[0] === \"[\") {\n // Get the optional duration and longest duration of the wait.\n const nodeArguments = getArguments(\n tokens,\n placeholders,\n (arg) => arg.type === \"number\" && !!arg.isInteger,\n \"wait node durations must be integer values\"\n ).map((argument) => argument.value);\n\n // We may have:\n // - One node argument which will be the explicit duration of the wait.\n // - Two node arguments which define the min and max duration bounds from which a random duration will be picked.\n // - Too many arguments, which is not valid.\n if (nodeArguments.length === 1) {\n // An explicit duration was defined.\n node.duration = nodeArguments[0] as number;\n } else if (nodeArguments.length === 2) {\n // Min and max duration bounds were defined from which a random duration will be picked.\n node.durationMin = nodeArguments[0] as number;\n node.durationMax = nodeArguments[1] as number;\n } else if (nodeArguments.length > 2) {\n // An incorrect number of durations was defined.\n throw new Error(\"invalid number of wait node duration arguments defined\");\n }\n }\n\n // Try to pick any attributes off of the token stack.\n node.attributes = getAttributes(tokens, placeholders);\n break;\n }\n\n case \"REPEAT\": {\n // Create a REPEAT AST node.\n const node = ASTNodeFactories.REPEAT();\n\n // Push the REPEAT node into the current scope.\n currentScope.push(node);\n\n // The arguments of a repeat node are optional. We may have:\n // - No node arguments, in which case the repeat note will iterate indefinitely.\n // - One node argument which will be the explicit number of iterations to make.\n // - Two node arguments which define the min and max iteration bounds from which a random iteration count will be picked.\n if (tokens[0] === \"[\") {\n // An iteration count has been defined. Get the iteration and potential maximum iteration of the wait.\n const nodeArguments = getArguments(\n tokens,\n placeholders,\n (arg) => arg.type === \"number\" && !!arg.isInteger,\n \"repeat node iteration counts must be integer values\"\n ).map((argument) => argument.value);\n\n // We should have got one or two iteration counts.\n if (nodeArguments.length === 1) {\n // A static iteration count was defined.\n node.iterations = nodeArguments[0] as number;\n } else if (nodeArguments.length === 2) {\n // A minimum and maximum iteration count was defined.\n node.iterationsMin = nodeArguments[0] as number;\n node.iterationsMax = nodeArguments[1] as number;\n } else {\n // An incorrect number of iteration counts was defined.\n throw new Error(\"invalid number of repeat node iteration count arguments defined\");\n }\n }\n\n // Try to pick any attributes off of the token stack.\n node.attributes = getAttributes(tokens, placeholders);\n\n popAndCheck(tokens, \"{\");\n\n // The new scope is that of the new REPEAT nodes children.\n stack.push(node.children!);\n break;\n }\n\n case \"RETRY\": {\n // Create a RETRY AST node.\n const node = ASTNodeFactories.RETRY();\n\n // Push the RETRY node into the current scope.\n currentScope.push(node);\n\n // The arguments of a retry node are optional. We may have:\n // - No node arguments, in which case the retry note will attempt indefinitely.\n // - One node argument which will be the explicit number of attempts to make.\n // - Two node arguments which define the min and max attempt bounds from which a random attempt count will be picked.\n if (tokens[0] === \"[\") {\n // An attempt count has been defined. Get the attempt count and potential maximum attempt count of the wait.\n const nodeArguments = getArguments(\n tokens,\n placeholders,\n (arg) => arg.type === \"number\" && !!arg.isInteger,\n \"retry node attempt counts must be integer values\"\n ).map((argument) => argument.value);\n\n // We should have got one or two attempt counts.\n if (nodeArguments.length === 1) {\n // A static attempt count was defined.\n node.attempts = nodeArguments[0] as number;\n } else if (nodeArguments.length === 2) {\n // A minimum and maximum attempt count was defined.\n node.attemptsMin = nodeArguments[0] as number;\n node.attemptsMax = nodeArguments[1] as number;\n } else {\n // An incorrect number of attempt counts was defined.\n throw new Error(\"invalid number of retry node attempt count arguments defined\");\n }\n }\n\n // Try to pick any attributes off of the token stack.\n node.attributes = getAttributes(tokens, placeholders);\n\n popAndCheck(tokens, \"{\");\n\n // The new scope is that of the new RETRY nodes children.\n stack.push(node.children!);\n break;\n }\n\n case \"ACTION\": {\n // Create a ACTION AST node.\n const node = ASTNodeFactories.ACTION();\n\n // Push the ACTION node into the current scope.\n currentScope.push(node);\n\n // We must have arguments defined, as we require an action name argument.\n if (tokens[0] !== \"[\") {\n throw new Error(\"expected action name identifier argument\");\n }\n\n // The action name will be defined as a node argument.\n const actionArguments = getArguments(tokens, placeholders);\n\n // We should have at least one identifer argument for an action node, which is the action name.\n if (actionArguments.length && actionArguments[0].type === \"identifier\") {\n // The action name will be the first and only node argument.\n node.actionName = actionArguments.shift()!.value as string;\n } else {\n throw new Error(\"expected action name identifier argument\");\n }\n\n // Only the first argument should have been an identifier, all following arguments must be string, number, boolean or null.\n actionArguments\n .filter((arg) => arg.type === \"identifier\")\n .forEach((arg) => {\n throw new Error(\n \"invalid action node argument value '\" +\n arg.value +\n \"', must be string, number, boolean or null\"\n );\n });\n\n // Any node arguments that follow the action name identifier will be treated as action function arguments.\n node.actionArguments = actionArguments;\n\n // Try to pick any attributes off of the token stack.\n node.attributes = getAttributes(tokens, placeholders);\n break;\n }\n\n case \"}\": {\n // The '}' character closes the current scope.\n stack.pop();\n break;\n }\n\n default: {\n throw new Error(`unexpected token '${token}'`);\n }\n }\n }\n\n // A function to recursively validate each of the nodes in the AST.\n const validateASTNode = (node: Validatable, depth: number): void => {\n // Validate the node.\n node.validate(depth);\n\n // Validate each child of the node.\n (node.children || []).forEach((child) => validateASTNode(child, depth + 1));\n };\n\n // Start node validation from the definition root.\n validateASTNode(\n {\n children: stack[0] as RootAstNode[],\n validate(this: { children: RootAstNode[] }) {\n // We must have at least one node defined as the definition scope, which should be a root node.\n if (this.children.length === 0) {\n throw new Error(\"expected root node to have been defined\");\n }\n\n // Each node at the base of the definition scope MUST be a root node.\n for (const definitionLevelNode of this.children) {\n if (definitionLevelNode.type !== \"root\") {\n throw new Error(\"expected root node at base of definition\");\n }\n }\n\n // Exactly one root node must not have a name defined. This will be the main root, others will have to be referenced via branch nodes.\n if (this.children.filter((definitionLevelNode) => definitionLevelNode.name === null).length !== 1) {\n throw new Error(\"expected single unnamed root node at base of definition to act as main root\");\n }\n\n // No two named root nodes can have matching names.\n const rootNodeNames: string[] = [];\n for (const definitionLevelNode of this.children) {\n if (rootNodeNames.indexOf(definitionLevelNode.name!) !== -1) {\n throw new Error(`multiple root nodes found with duplicate name '${definitionLevelNode.name}'`);\n } else {\n rootNodeNames.push(definitionLevelNode.name!);\n }\n }\n }\n },\n 0\n );\n\n // Return the root AST nodes.\n return stack[0];\n}\n\n/**\n * Pop the next raw token off of the stack and throw an error if it wasn't the expected one.\n * @param tokens The array of remaining tokens.\n * @param expected An optional string or array or items, one of which must match the next popped token.\n * @returns The popped token.\n */\nfunction popAndCheck(tokens: string[], expected: string | string[]) {\n // Get and remove the next token.\n const popped = tokens.shift();\n\n // We were expecting another token.\n if (popped === undefined) {\n throw new Error(\"unexpected end of definition\");\n }\n\n // Do we have an expected token/tokens array?\n if (expected !== undefined) {\n // Check whether the popped token matches at least one of our expected items.\n var tokenMatchesExpectation = ([] as string[])\n .concat(expected)\n .some((item) => popped.toUpperCase() === item.toUpperCase());\n\n // Throw an error if the popped token didn't match any of our expected items.\n if (!tokenMatchesExpectation) {\n const expectationString = ([] as string[])\n .concat(expected)\n .map((item) => \"'\" + item + \"'\")\n .join(\" or \");\n\n throw new Error(`unexpected token found. Expected '${expectationString}' but got '${popped}'`);\n }\n }\n\n // Return the popped token.\n return popped;\n}\n\ntype StringPlaceholders = { [key: string]: string };\n\n/**\n * Pull an argument definition list off of the token stack.\n * @param tokens The array of remaining tokens.\n * @param stringArgumentPlaceholders The mapping of string literal node argument placeholders to original values.\n * @param argumentValidator The argument validator function.\n * @param validationFailedMessage The exception message to throw if argument validation fails.\n * @returns The argument definition list.\n */\nfunction getArguments(\n tokens: string[],\n stringArgumentPlaceholders: StringPlaceholders,\n argumentValidator?: (arg: AnyArgument) => boolean,\n validationFailedMessage?: string\n) {\n // Any lists of arguments will always be wrapped in '[]' for node arguments or '()' for attribute arguments.\n // We are looking for a '[' or '(' opener that wraps the argument tokens and the relevant closer.\n const closer = popAndCheck(tokens, [\"[\", \"(\"]) === \"[\" ? \"]\" : \")\";\n\n const argumentListTokens: string[] = [];\n const argumentList: AnyArgument[] = [];\n\n // Grab all tokens between the '[' and ']' or '(' and ')'.\n while (tokens.length && tokens[0] !== closer) {\n // The next token is part of our arguments list.\n argumentListTokens.push(tokens.shift()!);\n }\n\n // Validate the order of the argument tokens. Each token must either be a ',' or a single argument that satisfies the validator.\n argumentListTokens.forEach((token, index) => {\n // Get whether this token should be an actual argument.\n const shouldBeArgumentToken = !(index & 1);\n\n // If the current token should be an actual argument then validate it,otherwise it should be a ',' token.\n if (shouldBeArgumentToken) {\n // Get the argument definition.\n const argumentDefinition = getArgumentDefinition(token!, stringArgumentPlaceholders);\n\n // Try to validate the argument.\n if (argumentValidator && !argumentValidator(argumentDefinition)) {\n throw new Error(validationFailedMessage);\n }\n\n // This is a valid argument!\n argumentList.push(argumentDefinition);\n } else {\n // The current token should be a ',' token.\n if (token !== \",\") {\n throw new Error(`invalid argument list, expected ',' or ']' but got '${token}'`);\n }\n }\n });\n\n // The arguments list should terminate with a ']' or ')' token, depending on the opener.\n popAndCheck(tokens, closer);\n\n // Return the argument list.\n return argumentList;\n}\n\n/**\n * Gets an argument value definition.\n * @param token The argument token.\n * @param stringArgumentPlaceholders The mapping of string literal node argument placeholders to original values.\n * @returns An argument value definition.\n */\nfunction getArgumentDefinition(token: string, stringArgumentPlaceholders: StringPlaceholders): AnyArgument {\n // Check whether the token represents a null value.\n if (token === \"null\") {\n return {\n value: null,\n type: \"null\"\n } as NullArgument;\n }\n\n // Check whether the token represents a boolean value.\n if (token === \"true\" || token === \"false\") {\n return {\n value: token === \"true\",\n type: \"boolean\"\n } as BooleanArgument;\n }\n\n // Check whether the token represents a number value.\n // TODO: Relies on broken isNaN - see MDN.\n // if (!Number.isNaN(token)) {\n if (!isNaN(token as any)) {\n return {\n value: parseFloat(token),\n isInteger: parseFloat(token) === parseInt(token, 10),\n type: \"number\"\n } as NumberArgument;\n }\n\n // Check whether the token is a placeholder (e.g. @@0@@) representing a string literal.\n if (token.match(/^@@\\d+@@$/g)) {\n return {\n value: stringArgumentPlaceholders[token].replace('\\\\\"', '\"'),\n type: \"string\"\n } as StringPlaceholderArgument;\n }\n\n // The only remaining option is that the argument value is an identifier.\n return {\n value: token,\n type: \"identifier\"\n } as IdentifierArgument;\n}\n\n/**\n * Pull any attributes off of the token stack.\n * @param tokens The array of remaining tokens.\n * @param stringArgumentPlaceholders The mapping of string literal node argument placeholders to original values.\n * @returns An array of attributes defined by any directly following tokens.\n */\nfunction getAttributes(tokens: string[], stringArgumentPlaceholders: StringPlaceholders) {\n // Create an array to hold any attributes found.\n const attributes: Attribute[] = [];\n\n // Keep track of names of attribute that we have found on the token stack, as we cannot have duplicates.\n const attributesFound: string[] = [];\n\n // Try to get the attribute factory for the next token.\n let attributeFactory = AttributeFactories[(tokens[0] || \"\").toUpperCase()];\n\n // Pull attribute tokens off of the tokens stack until we have no more.\n while (attributeFactory) {\n // Check to make sure that we have not already created a attribute of this type for this node.\n if (attributesFound.indexOf(tokens[0].toUpperCase()) !== -1) {\n throw new Error(`duplicate attribute '${tokens[0].toUpperCase()}' found for node`);\n }\n\n // Add the current attribute type to our array of found attributes.\n attributesFound.push(tokens.shift()!.toUpperCase());\n\n // Grab any attribute arguments.\n const attributeArguments = getArguments(tokens, stringArgumentPlaceholders);\n\n // The first attribute argument has to be an identifer, this will reference an agent function.\n if (attributeArguments.length === 0 || attributeArguments[0].type !== \"identifier\") {\n throw new Error(\"expected agent function name identifier argument for attribute\");\n }\n\n // Grab the first attribute which is an identifier that will reference an agent function.\n const attributeFunctionName = attributeArguments.shift()! as IdentifierArgument;\n\n // Any remaining attribute arguments must have a type of string, number, boolean or null.\n attributeArguments\n .filter((arg) => arg.type === \"identifier\")\n .forEach((arg) => {\n throw new Error(\n \"invalid attribute argument value '\" + arg.value + \"', must be string, number, boolean or null\"\n );\n });\n\n // Create the attribute and add it to the array of attributes found.\n attributes.push(attributeFactory(attributeFunctionName.value, attributeArguments));\n\n // Try to get the next attribute name token, as there could be multiple.\n attributeFactory = AttributeFactories[(tokens[0] || \"\").toUpperCase()];\n }\n\n return attributes;\n}\n\n/**\n * Swaps out any node/attribute argument string literals with placeholders.\n * @param definition The definition.\n * @returns An object containing a mapping of placeholders to original string values as well as the processed definition string.\n */\nfunction substituteStringLiterals(definition: string): {\n placeholders: { [key: string]: string };\n processedDefinition: string;\n} {\n // Create an object to hold the mapping of placeholders to original string values.\n const placeholders: StringPlaceholders = {};\n\n // Replace any string literals wrapped with double quotes in our definition with placeholders to be processed later.\n const processedDefinition = definition.replace(/\\\"(\\\\.|[^\"\\\\])*\\\"/g, (match) => {\n var strippedMatch = match.substring(1, match.length - 1);\n var placeholder = Object.keys(placeholders).find((key) => placeholders[key] === strippedMatch);\n\n // If we have no existing string literal match then create a new placeholder.\n if (!placeholder) {\n placeholder = `@@${Object.keys(placeholders).length}@@`;\n placeholders[placeholder] = strippedMatch;\n }\n\n return placeholder;\n });\n\n return { placeholders, processedDefinition };\n}\n\n/**\n * Parse the tree definition into an array of raw tokens.\n * @param definition The definition.\n * @returns An array of tokens parsed from the definition.\n */\nfunction parseTokensFromDefinition(definition: string): string[] {\n // Add some space around various important characters so that they can be plucked out easier as individual tokens.\n definition = definition.replace(/\\(/g, \" ( \");\n definition = definition.replace(/\\)/g, \" ) \");\n definition = definition.replace(/\\{/g, \" { \");\n definition = definition.replace(/\\}/g, \" } \");\n definition = definition.replace(/\\]/g, \" ] \");\n definition = definition.replace(/\\[/g, \" [ \");\n definition = definition.replace(/\\,/g, \" , \");\n\n // Split the definition into raw token form and return it.\n return definition.replace(/\\s+/g, \" \").trim().split(\" \");\n}\n", "import GuardPath, { GuardPathPart } from \"./attributes/guards/GuardPath\";\nimport buildRootASTNodes, { AnyArgument, RootAstNode } from \"./RootAstNodesBuilder\";\nimport State, { AnyState } from \"./State\";\nimport Lookup from \"./Lookup\";\nimport Node from \"./nodes/Node\";\nimport Root from \"./nodes/decorator/Root\";\nimport Composite from \"./nodes/composite/Composite\";\nimport Decorator from \"./nodes/decorator/Decorator\";\nimport { Agent, GlobalFunction } from \"./Agent\";\nimport { CallbackAttributeDetails } from \"./attributes/callbacks/Callback\";\nimport { GuardAttributeDetails } from \"./attributes/guards/Guard\";\nimport { BehaviourTreeOptions } from \"./BehaviourTreeOptions\";\nimport { parseMDSLToJSON } from \"./mdsl/MDSLDefinitionParser\";\n\n// Purely for outside inspection of the tree.\nexport type FlattenedTreeNode = {\n id: string;\n type: string;\n caption: string;\n state: AnyState;\n guards: GuardAttributeDetails[];\n callbacks: CallbackAttributeDetails[];\n args: AnyArgument[];\n parentId: string | null;\n};\n\n/**\n * A representation of a behaviour tree.\n */\nexport class BehaviourTree {\n /**\n * The main root tree node.\n */\n public readonly rootNode: Root;\n\n /**\n * Creates a new instance of the BehaviourTree class.\n * @param definition The behaviour tree definition.\n * @param agent The agent instance that this behaviour tree is modelling behaviour for.\n * @param options The behaviour tree options object.\n */\n constructor(definition: string, private agent: Agent, private options: BehaviourTreeOptions = {}) {\n // The tree definition must be defined and a valid string.\n if (typeof definition !== \"string\") {\n throw new Error(\"the tree definition must be a string\");\n }\n\n // The agent must be defined and not null.\n if (typeof agent !== \"object\" || agent === null) {\n throw new Error(\"the agent must be defined and not null\");\n }\n\n // Parse the behaviour tree definition, create the populated tree of behaviour tree nodes, and get the root.\n this.rootNode = BehaviourTree._createRootNode(definition);\n }\n\n /**\n * Gets whether the tree is in the RUNNING state.\n * @returns true if the tree is in the RUNNING state, otherwise false.\n */\n isRunning() {\n return this.rootNode.getState() === State.RUNNING;\n }\n\n /**\n * Gets the current tree state of SUCCEEDED, FAILED, READY or RUNNING.\n * @returns The current tree state.\n */\n getState() {\n return this.rootNode.getState();\n }\n\n /**\n * Step the tree.\n * 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.\n * 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\n * 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.\n *\n * 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.\n */\n step() {\n // If the root node has already been stepped to completion then we need to reset it.\n if (this.rootNode.getState() === State.SUCCEEDED || this.rootNode.getState() === State.FAILED) {\n this.rootNode.reset();\n }\n\n try {\n this.rootNode.update(this.agent, this.options);\n } catch (exception) {\n throw new Error(`error stepping tree: ${(exception as Error).message}`);\n }\n }\n\n /**\n * Resets the tree from the root node outwards to each nested node, giving each a state of READY.\n */\n reset() {\n this.rootNode.reset();\n }\n\n /**\n * Gets the flattened details of every node in the tree.\n * @returns The flattened details of every node in the tree.\n */\n getFlattenedNodeDetails(): FlattenedTreeNode[] {\n // Create an empty flattened array of tree nodes.\n const flattenedTreeNodes: FlattenedTreeNode[] = [];\n\n /**\n * Helper function to process a node instance and push details into the flattened tree nodes array.\n * @param node The current node.\n * @param parentUid The UID of the node parent, or null if the node is the main root node.\n */\n const processNode = (node: Node, parentUid: string | null) => {\n // Get the guard and callback attribute details for this node.\n const guards = node\n .getAttributes()\n .filter((attribute) => attribute.isGuard())\n .map((attribute) => attribute.getDetails()) as GuardAttributeDetails[];\n const callbacks = node\n .getAttributes()\n .filter((attribute) => !attribute.isGuard())\n .map((attribute) => attribute.getDetails()) as CallbackAttributeDetails[];\n\n // Push the current node into the flattened nodes array.\n flattenedTreeNodes.push({\n id: node.getUid(),\n type: node.getType(),\n caption: node.getName(),\n state: node.getState(),\n guards,\n callbacks,\n args: node.getArguments(),\n parentId: parentUid\n });\n\n // Process each of the nodes children if it is not a leaf node.\n if (!node.isLeafNode()) {\n (node as Composite | Decorator)\n .getChildren()\n .forEach((child) => processNode(child, (node as Composite | Decorator).getUid()));\n }\n };\n\n // Convert the nested node structure into a flattened array of node details.\n processNode(this.rootNode, null);\n\n return flattenedTreeNodes;\n }\n\n /**\n * Registers the action/condition/guard/callback function or subtree with the given name.\n * @param name The name of the function or subtree to register.\n * @param value The function or subtree definition to register.\n */\n static register(name: string, value: GlobalFunction | string) {\n if (typeof value === \"function\") {\n // We are going to register a action/condition/guard/callback function.\n Lookup.setFunc(name, value);\n } else if (typeof value === \"string\") {\n // We are going to register a subtree.\n let rootASTNodes: RootAstNode[];\n\n try {\n // Try to create the behaviour tree AST based on the definition provided, this could fail if the definition is invalid.\n rootASTNodes = buildRootASTNodes(value);\n } catch (exception) {\n // There was an issue in trying to parse and build the tree definition.\n throw new Error(`error registering definition: ${(exception as Error).message}`);\n }\n\n // This function should only ever be called with a definition containing a single unnamed root node.\n if (rootASTNodes.length != 1 || rootASTNodes[0].name !== null) {\n throw new Error(\"error registering definition: expected a single unnamed root node\");\n }\n\n Lookup.setSubtree(name, rootASTNodes[0]);\n } else {\n throw new Error(\"unexpected value, expected string definition or function\");\n }\n }\n\n /**\n * Unregisters the registered action/condition/guard/callback function or subtree with the given name.\n * @param name The name of the registered action/condition/guard/callback function or subtree to unregister.\n */\n static unregister(name: string): void {\n Lookup.remove(name);\n }\n\n /**\n * Unregister all registered action/condition/guard/callback functions and subtrees.\n */\n static unregisterAll(): void {\n Lookup.empty();\n }\n\n /**\n * Parses a behaviour tree definition and creates a tree of behaviour tree nodes.\n * @param {string} definition The behaviour tree definition.\n * @returns The root behaviour tree node.\n */\n private static _createRootNode(definition: string): Root {\n // TODO Remove!\n try {\n // parseToJSON(definition);\n } catch (exception) {\n console.log(exception);\n }\n\n try {\n // Try to create the behaviour tree AST based on the definition provided, this could fail if the definition is invalid.\n const rootASTNodes = buildRootASTNodes(definition);\n\n // Create a symbol to use as the main root key in our root node mapping.\n const mainRootNodeKey = Symbol(\"__root__\");\n\n // Create a mapping of root node names to root AST tokens. The main root node will have a key of Symbol(\"__root__\").\n const rootNodeMap: { [key: string | symbol]: RootAstNode } = {};\n for (const rootASTNode of rootASTNodes) {\n rootNodeMap[rootASTNode.name === null ? mainRootNodeKey : rootASTNode.name!] = rootASTNode;\n }\n\n // Convert the AST to our actual tree and get the root node.\n const rootNode: Root = rootNodeMap[mainRootNodeKey].createNodeInstance(\n // Create a provider for named root nodes that are part of our definition or have been registered. Prioritising the former.\n (name: string): RootAstNode => (rootNodeMap[name] ? rootNodeMap[name] : Lookup.getSubtree(name)),\n []\n );\n\n // Set a guard path on every leaf of the tree to evaluate as part of its update.\n BehaviourTree._applyLeafNodeGuardPaths(rootNode);\n\n // Return the root node.\n return rootNode;\n } catch (exception) {\n // There was an issue in trying to parse and build the tree definition.\n throw new Error(`error parsing tree: ${(exception as Error).message}`);\n }\n }\n\n /**\n * Applies a guard path to every leaf of the tree to evaluate as part of each update.\n * @param rootNode The main root tree node.\n */\n private static _applyLeafNodeGuardPaths(rootNode: Root) {\n const nodePaths: Node[][] = [];\n\n const findLeafNodes = (path: Node[], node: Node) => {\n // Add the current node to the path.\n path = path.concat(node);\n\n // Check whether the current node is a leaf node.\n if (node.isLeafNode()) {\n nodePaths.push(path);\n } else {\n (node as Composite | Decorator).getChildren().forEach((child) => findLeafNodes(path, child));\n }\n };\n\n // Find all leaf node paths, starting from the root.\n findLeafNodes([], rootNode);\n\n nodePaths.forEach((path) => {\n // Each node in the current path will have to be assigned a guard path, working from the root outwards.\n for (let depth = 0; depth < path.length; depth++) {\n // Get the node in the path at the current depth.\n const currentNode = path[depth];\n\n // The node may already have been assigned a guard path, if so just skip it.\n if (currentNode.hasGuardPath()) {\n continue;\n }\n\n // Create the guard path for the current node.\n const guardPath = new GuardPath(\n path\n .slice(0, depth + 1)\n .map((node) => ({ node, guards: node.getGuardAttributes() }))\n .filter((details) => details.guards.length > 0)\n );\n\n // Assign the guard path to the current node.\n currentNode.setGuardPath(guardPath);\n }\n });\n }\n}\n"], + "mappings": ";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AACA,aAAO,eAAe,SAAS,cAAc,EAAE,OAAO,KAAK,CAAC;AAC5D,cAAQ,cAAc;AAItB,UAAI,cAA6B,WAAY;AAMzC,iBAASA,aAAY,aAAa,SAAS;AACvC,cAAI,YAAY,QAAQ;AAAE,sBAAU;AAAA,UAAG;AACvC,eAAK,eAAe;AACpB,eAAK,WAAW;AAAA,QACpB;AACA,eAAO,eAAeA,aAAY,WAAW,eAAe;AAAA,UAExD,KAAK,WAAY;AACb,mBAAO,KAAK;AAAA,UAChB;AAAA,UACA,YAAY;AAAA,UACZ,cAAc;AAAA,QAClB,CAAC;AACD,eAAO,eAAeA,aAAY,WAAW,WAAW;AAAA,UAEpD,KAAK,WAAY;AACb,mBAAO,KAAK;AAAA,UAChB;AAAA,UACA,KAAK,SAAU,OAAO;AAClB,iBAAK,WAAW;AAAA,UACpB;AAAA,UACA,YAAY;AAAA,UACZ,cAAc;AAAA,QAClB,CAAC;AACD,eAAOA;AAAA,MACX,EAAE;AACF,cAAQ,cAAc;AAAA;AAAA;;;ACtCtB;AAAA;AAAA;AACA,aAAO,eAAe,SAAS,cAAc,EAAE,OAAO,KAAK,CAAC;AAC5D,cAAQ,kBAAkB,QAAQ,oBAAoB;AAMtD,eAAS,kBAAkB,OAAO;AAC9B,eAAO,UAAU,QAAQ,UAAU;AAAA,MACvC;AACA,cAAQ,oBAAoB;AAM5B,eAAS,gBAAgB,OAAO;AAC5B,eAAO,OAAO,UAAU,YAAY,SAAS,KAAK,KAAK,MAAM,KAAK,MAAM;AAAA,MAC5E;AACA,cAAQ,kBAAkB;AAAA;AAAA;;;ACpB1B;AAAA;AAAA;AACA,aAAO,eAAe,SAAS,cAAc,EAAE,OAAO,KAAK,CAAC;AAC5D,cAAQ,QAAQ;AAChB,UAAI,gBAAgB;AACpB,UAAI,cAAc;AAIlB,UAAIC,SAAuB,WAAY;AAKnC,iBAASA,OAAM,cAAc;AAEzB,eAAK,gBAAgB,CAAC;AACtB,eAAK,gBAAgB;AAAA,QACzB;AAOA,QAAAA,OAAM,UAAU,MAAM,SAAU,aAAa,SAAS;AAClD,cAAI,YAAY,QAAQ;AAAE,sBAAU;AAAA,UAAG;AAEvC,cAAI,EAAE,GAAG,YAAY,iBAAiB,OAAO,GAAG;AAC5C,kBAAM,IAAI,MAAM,wCAAwC;AAAA,UAC5D;AAEA,cAAI,sBAAsB,KAAK,cAAc,KAAK,SAAU,MAAM;AAAE,mBAAO,KAAK,gBAAgB;AAAA,UAAa,CAAC;AAC9G,cAAI,qBAAqB;AAErB,gCAAoB,WAAW;AAAA,UACnC,OACK;AAED,iBAAK,cAAc,KAAK,IAAI,cAAc,YAAY,aAAa,OAAO,CAAC;AAAA,UAC/E;AACA,iBAAO;AAAA,QACX;AAOA,QAAAA,OAAM,UAAU,SAAS,SAAU,aAAa,SAAS;AAErD,cAAI,sBAAsB,KAAK,cAAc,KAAK,SAAU,MAAM;AAAE,mBAAO,KAAK,gBAAgB;AAAA,UAAa,CAAC;AAE9G,cAAI,CAAC,qBAAqB;AACtB,mBAAO;AAAA,UACX;AAEA,cAAI,YAAY,QAAW;AAEvB,gBAAI,EAAE,GAAG,YAAY,iBAAiB,OAAO,GAAG;AAC5C,oBAAM,IAAI,MAAM,wCAAwC;AAAA,YAC5D;AACA,gCAAoB,WAAW;AAE/B,gBAAI,oBAAoB,UAAU,GAAG;AACjC,mBAAK,gBAAgB,KAAK,cAAc,OAAO,SAAU,MAAM;AAAE,uBAAO,SAAS;AAAA,cAAqB,CAAC;AAAA,YAC3G;AAAA,UACJ,OACK;AAED,iBAAK,gBAAgB,KAAK,cAAc,OAAO,SAAU,MAAM;AAAE,qBAAO,SAAS;AAAA,YAAqB,CAAC;AAAA,UAC3G;AACA,iBAAO;AAAA,QACX;AAMA,QAAAA,OAAM,UAAU,OAAO,SAAU,SAAS;AACtC,cAAI,YAAY,QAAQ;AAAE,sBAAU,CAAC;AAAA,UAAG;AAExC,cAAI,KAAK,cAAc,WAAW,GAAG;AACjC,mBAAO;AAAA,UACX;AACA,cAAI,cAAc,GAAG,YAAY,mBAAmB,QAAQ,UAAU,IAAI,OAAO,QAAQ;AACzF,cAAI,WAAW,CAAC;AAChB,eAAK,cAAc,QAAQ,SAAU,IAAI;AACrC,gBAAI,cAAc,GAAG,aAAa,UAAU,GAAG;AAC/C,qBAAS,cAAc,GAAG,cAAc,SAAS,eAAe;AAC5D,uBAAS,KAAK,WAAW;AAAA,YAC7B;AAAA,UACJ,CAAC;AACD,cAAI;AAGJ,cAAI,KAAK,eAAe;AAEpB,qBAAS,KAAK,cAAc;AAE5B,gBAAI,OAAO,WAAW,YAAY,SAAS,KAAK,UAAU,GAAG;AACzD,oBAAM,IAAI,MAAM,oFAAoF;AAAA,YACxG;AAAA,UACJ,OACK;AAED,qBAAS,KAAK,OAAO;AAAA,UACzB;AAEA,cAAI,SAAS,SAAS,KAAK,MAAM,SAAS,SAAS,MAAM;AAEzD,cAAI,CAAC,YAAY;AACb,iBAAK,OAAO,QAAQ,CAAC;AAAA,UACzB;AAEA,iBAAO;AAAA,QACX;AAOA,QAAAA,OAAM,UAAU,eAAe,SAAU,SAAS,SAAS;AACvD,cAAI,YAAY,QAAQ;AAAE,sBAAU,CAAC;AAAA,UAAG;AACxC,cAAI,iBAAiB,GAAG,YAAY,mBAAmB,QAAQ,MAAM,IAAI,QAAQ,QAAQ;AAEzF,cAAI,YAAY,GAAG;AACf,mBAAO,CAAC;AAAA,UACZ;AAEA,cAAI,EAAE,GAAG,YAAY,iBAAiB,OAAO,GAAG;AAC5C,kBAAM,IAAI,MAAM,wCAAwC;AAAA,UAC5D;AACA,cAAI,SAAS,CAAC;AAGd,iBAAO,OAAO,SAAS,WAAW,KAAK,cAAc,SAAS,GAAG;AAC7D,mBAAO,KAAK,KAAK,KAAK,OAAO,CAAC;AAAA,UAClC;AAEA,cAAI,eAAe;AAEf,gBAAI,SAAS,CAAC;AAEd,qBAAS,KAAK,GAAG,WAAW,QAAQ,KAAK,SAAS,QAAQ,MAAM;AAC5D,kBAAI,cAAc,SAAS;AAC3B,kBAAI,OAAO,QAAQ,WAAW,MAAM,IAAI;AACpC,uBAAO,KAAK,WAAW;AAAA,cAC3B;AAAA,YACJ;AACA,qBAAS;AAAA,UACb;AACA,iBAAO;AAAA,QACX;AACA,eAAOA;AAAA,MACX,EAAE;AACF,cAAQ,QAAQA;AAAA;AAAA;;;AC5JhB;AAAA;AAAA;AACA,aAAO,eAAe,SAAS,cAAc,EAAE,OAAO,KAAK,CAAC;AAC5D,cAAQ,cAAc;AACtB,UAAI,UAAU;AAMd,eAASC,aAAY,uBAAuB;AAExC,YAAI,CAAC,uBAAuB;AACxB,iBAAO,IAAI,QAAQ,MAAM;AAAA,QAC7B;AAEA,YAAI,MAAM,QAAQ,qBAAqB,GAAG;AAEtC,cAAI,eAAe;AACnB,cAAI,UAAU,IAAI,QAAQ,MAAM;AAEhC,uBAAa,QAAQ,SAAU,IAAI;AAC/B,gBAAI,cAAc,GAAG,IAAI,SAAS,GAAG;AACrC,mBAAO,QAAQ,IAAI,aAAa,MAAM;AAAA,UAC1C,CAAC;AAED,iBAAO;AAAA,QACX,OACK;AAED,cAAI,SAAS,sBAAsB,QAAQ,eAAe,sBAAsB;AAEhF,cAAI,UAAU,IAAI,QAAQ,MAAM,MAAM;AAEtC,cAAI,cAAc;AACd,yBAAa,QAAQ,SAAU,IAAI;AAC/B,kBAAI,cAAc,GAAG,IAAI,SAAS,GAAG;AACrC,qBAAO,QAAQ,IAAI,aAAa,MAAM;AAAA,YAC1C,CAAC;AAAA,UACL;AAEA,iBAAO;AAAA,QACX;AAAA,MACJ;AACA,cAAQ,cAAcA;AAAA;AAAA;;;AC3CtB;AAAA;AAAA;AACA,aAAO,eAAe,SAAS,cAAc,EAAE,OAAO,KAAK,CAAC;AAC5D,UAAI,gBAAgB;AACpB,cAAQ,UAAU,cAAc;AAAA;AAAA;;;ACHhC;AAAA;AAAA;AAAA;AAAA;;;ACKA,MAAqB,4BAArB,cAAuD,MAAM;AAAA,IAIzD,YAAoB,QAAc;AAC9B,YAAM,mCAAmC;AADzB;AAAA,IAEpB;AAAA,IAOA,eAAe,CAAC,SAAe,SAAS,KAAK;AAAA,EACjD;;;ACNA,MAAqB,YAArB,MAA+B;AAAA,IAI3B,YAAoB,OAAwB;AAAxB;AAAA,IAAyB;AAAA,IAO7C,WAAW,CAAC,UAAiB;AAEzB,iBAAW,WAAW,KAAK,OAAO;AAE9B,mBAAW,SAAS,QAAQ,QAAQ;AAEhC,cAAI,CAAC,MAAM,YAAY,KAAK,GAAG;AAC3B,kBAAM,IAAI,0BAA0B,QAAQ,IAAI;AAAA,UACpD;AAAA,QACJ;AAAA,MACJ;AAAA,IACJ;AAAA,EACJ;;;ACjCO,MAAK,QAAL,kBAAKC,WAAL;AACH,IAAAA,OAAA,WAAQ;AACR,IAAAA,OAAA,aAAU;AACV,IAAAA,OAAA,eAAY;AACZ,IAAAA,OAAA,YAAS;AAJD,WAAAA;AAAA,KAAA;;;ACaZ,MAA8B,OAA9B,MAAmC;AAAA,IAmB/B,YAAoB,MAAsB,YAAiC,MAAqB;AAA5E;AAAsB;AAAiC;AAAA,IAAsB;AAAA,IAfhF,MAAc,cAAc;AAAA,IAIrC;AAAA,IAIA;AAAA,IA6BR,WAAW,MAAgB,KAAK;AAAA,IAChC,WAAW,CAAC,UAA0B;AAClC,WAAK,QAAQ;AAAA,IACjB;AAAA,IAKA,SAAS,MAAM,KAAK;AAAA,IAKpB,UAAU,MAAM,KAAK;AAAA,IAKrB,gBAAgB,MAAM,KAAK;AAAA,IAK3B,eAAe,MAAM,KAAK;AAAA,IAQ1B,aAAa,MAAyB;AAClC,aACI,KAAK,cAAc,EAAE,OAAO,CAAC,cAAc,UAAU,QAAQ,EAAE,YAAY,MAAM,KAAK,YAAY,CAAC,EAAE,MACrG;AAAA,IAER;AAAA,IAKA,qBAAqB,MAAe,KAAK,cAAc,EAAE,OAAO,CAAC,cAAc,UAAU,QAAQ,CAAC;AAAA,IAKlG,eAAe,CAAC,UAAsB,KAAK,YAAY;AAAA,IAKvD,eAAe,MAAM,CAAC,CAAC,KAAK;AAAA,IAMrB,GAAG,OAA0B;AAChC,aAAO,KAAK,UAAU;AAAA,IAC1B;AAAA,IAKO,QAAc;AACjB,WAAK,wCAAoB;AAAA,IAC7B;AAAA,IAMO,MAAM,OAAoB;AAE7B,UAAI,CAAC,KAAK,sCAAgB,GAAG;AACzB;AAAA,MACJ;AAGA,WAAK,MAAM;AAEX,WAAK,aAAa,MAAM,GAAG,kBAAkB,OAAO,OAAO,IAAI;AAAA,IACnE;AAAA,IAQO,OAAO,OAAc,SAAqC;AAE7D,UAAI,KAAK,0CAAkB,KAAK,KAAK,oCAAe,GAAG;AACnD;AAAA,MACJ;AAEA,UAAI;AAEA,aAAK,UAAW,SAAS,KAAK;AAG9B,YAAI,KAAK,kCAAc,GAAG;AACtB,eAAK,aAAa,OAAO,GAAG,kBAAkB,KAAK;AAAA,QACvD;AAEA,aAAK,aAAa,MAAM,GAAG,kBAAkB,KAAK;AAGlD,aAAK,SAAS,OAAO,OAAO;AAG5B,YAAI,KAAK,0CAAkB,KAAK,KAAK,oCAAe,GAAG;AACnD,eAAK,aAAa,MAAM,GAAG,kBAAkB,OAAO,KAAK,0CAAkB,GAAG,KAAK;AAAA,QACvF;AAAA,MACJ,SAAS,OAAP;AAEE,YAAI,iBAAiB,6BAA6B,MAAM,aAAa,IAAI,GAAG;AAExE,eAAK,MAAM,KAAK;AAGhB,eAAK,0CAAqB;AAAA,QAC9B,OAAO;AACH,gBAAM;AAAA,QACV;AAAA,MACJ;AAAA,IACJ;AAAA,EACJ;AAMA,WAAS,gBAAwB;AAC7B,QAAI,KAAK,WAAY;AACjB,eAAU,IAAI,KAAK,OAAO,KAAK,QAAW,GAAG,SAAS,EAAE,EAAE,UAAU,CAAC;AAAA,IACzE;AACA,WAAO,GAAG,IAAI,GAAG,IAAI,MAAM,GAAG,IAAI,MAAM,GAAG,IAAI,MAAM,GAAG,IAAI,MAAM,GAAG,IAAI,GAAG,IAAI,GAAG;AAAA,EACvF;;;AC9LA,MAA8B,OAA9B,cAA2C,KAAK;AAAA,IAI5C,aAAa,MAAM;AAAA,EACvB;;;ACGA,MAAqB,SAArB,MAA4B;AAAA,IAexB,OAAc,QAAQ,MAA8B;AAChD,aAAO,KAAK,cAAc;AAAA,IAC9B;AAAA,IAOA,OAAc,QAAQ,MAAc,MAA4B;AAC5D,WAAK,cAAc,QAAQ;AAAA,IAC/B;AAAA,IAUA,OAAO,eAAe,OAAc,MAAsC;AAEtE,YAAM,eAAe,MAAM;AAC3B,UAAI,gBAAgB,OAAO,iBAAiB,YAAY;AACpD,eAAO,CAAC,SACJ,aAAa;AAAA,UACT;AAAA,UACA,KAAK,IAAI,CAAC,QAAQ,IAAI,KAAK;AAAA,QAC/B;AAAA,MACR;AAGA,UAAI,KAAK,cAAc,SAAS,OAAO,KAAK,cAAc,UAAU,YAAY;AAC5E,eAAO,CAAC,SAA4B,KAAK,cAAc,MAAM,OAAO,GAAG,KAAK,IAAI,CAAC,QAAQ,IAAI,KAAK,CAAC;AAAA,MACvG;AAGA,aAAO;AAAA,IACX;AAAA,IAOA,OAAO,WAAW,MAA2B;AACzC,aAAO,KAAK,aAAa;AAAA,IAC7B;AAAA,IAOA,OAAO,WAAW,MAAc,SAAsB;AAClD,WAAK,aAAa,QAAQ;AAAA,IAC9B;AAAA,IAMA,OAAO,OAAO,MAAc;AACxB,aAAO,KAAK,cAAc;AAC1B,aAAO,KAAK,aAAa;AAAA,IAC7B;AAAA,IAKA,OAAO,QAAQ;AACX,WAAK,gBAAgB,CAAC;AACtB,WAAK,eAAe,CAAC;AAAA,IACzB;AAAA,EACJ;AAtFI,gBAJiB,QAIF,iBAAmD,CAAC;AAInE,gBARiB,QAQF,gBAA+C,CAAC;;;ACTnE,MAAqB,SAArB,cAAoC,KAAK;AAAA,IAMrC,YAAY,YAAiC,YAA4B,iBAAgC;AACrG,YAAM,UAAU,YAAY,eAAe;AADF;AAA4B;AAAA,IAEzE;AAAA,IAKQ,uBAAuB;AAAA,IAKvB,2BAAiD;AAAA,IAO/C,SAAS,OAAc,SAAqC;AAGlE,UAAI,KAAK,sBAAsB;AAE3B,YAAI,KAAK,0BAA0B;AAE/B,eAAK,SAAS,KAAK,wBAAwB;AAAA,QAC/C;AAEA;AAAA,MACJ;AAGA,YAAM,oBAAoB,OAAO,eAAe,OAAO,KAAK,UAAU;AAGtE,UAAI,sBAAsB,MAAM;AAC5B,cAAM,IAAI;AAAA,UACN,4CAA4C,KAAK;AAAA,QACrD;AAAA,MACJ;AAMA,YAAM,eAAe,kBAAkB,KAAK,eAAe;AAE3D,UAAI,wBAAwB,SAAS;AACjC,qBAAa;AAAA,UACT,CAAC,WAAW;AAER,gBAAI,CAAC,KAAK,sBAAsB;AAC5B;AAAA,YACJ;AAGA,gBAAI,sDAA8B,8CAAyB;AACvD,oBAAM,IAAI;AAAA,gBACN;AAAA,cACJ;AAAA,YACJ;AAGA,iBAAK,2BAA2B;AAAA,UACpC;AAAA,UACA,CAAC,WAAW;AAER,gBAAI,CAAC,KAAK,sBAAsB;AAC5B;AAAA,YACJ;AAGA,kBAAM,IAAI,MAAM,MAAM;AAAA,UAC1B;AAAA,QACJ;AAGA,aAAK,4CAAsB;AAG3B,aAAK,uBAAuB;AAAA,MAChC,OAAO;AAEH,aAAK,qBAAqB,YAAY;AAGtC,aAAK,SAAS,mDAA6B;AAAA,MAC/C;AAAA,IACJ;AAAA,IAKA,UAAU,MAAM,KAAK;AAAA,IAKrB,QAAQ,MAAM;AAEV,WAAK,wCAAoB;AAGzB,WAAK,uBAAuB;AAC5B,WAAK,2BAA2B;AAAA,IACpC;AAAA,IAMQ,uBAAuB,CAAC,WAAoC;AAChE,cAAQ,QAAQ;AAAA,QACZ;AAAA,QACA;AAAA,QACA,KAAK;AACD;AAAA,QACJ;AACI,gBAAM,IAAI;AAAA,YACN,WAAW,KAAK;AAAA,UACpB;AAAA,MACR;AAAA,IACJ;AAAA,EACJ;;;AClIA,MAAqB,YAArB,cAAuC,KAAK;AAAA,IAMxC,YAAY,YAAiC,eAA+B,oBAAmC;AAC3G,YAAM,aAAa,YAAY,kBAAkB;AADR;AAA+B;AAAA,IAE5E;AAAA,IAOU,SAAS,OAAc,SAAqC;AAElE,YAAM,uBAAuB,OAAO,eAAe,OAAO,KAAK,aAAa;AAG5E,UAAI,yBAAyB,MAAM;AAC/B,cAAM,IAAI;AAAA,UACN,kDAAkD,KAAK;AAAA,QAC3D;AAAA,MACJ;AAGA,WAAK,SAAS,CAAC,CAAC,qBAAqB,KAAK,kBAAkB,+EAAkC;AAAA,IAClG;AAAA,IAKA,UAAU,MAAM,KAAK;AAAA,EACzB;;;ACpCA,MAAqB,OAArB,cAAkC,KAAK;AAAA,IAOnC,YACI,YACQ,UACA,aACA,aACV;AACE,YAAM,QAAQ,YAAY,CAAC,CAAC;AAJpB;AACA;AACA;AAAA,IAGZ;AAAA,IAKQ,oBAA4B;AAAA,IAK5B,gBAA+B;AAAA,IAK/B,iBAAyB;AAAA,IAOvB,SAAS,OAAc,SAAqC;AAElE,UAAI,KAAK,kCAAc,GAAG;AAEtB,aAAK,oBAAoB,IAAI,KAAK,EAAE,QAAQ;AAG5C,aAAK,iBAAiB;AAGtB,YAAI,KAAK,aAAa,MAAM;AACxB,eAAK,gBAAgB,KAAK;AAAA,QAC9B,WAAW,KAAK,gBAAgB,QAAQ,KAAK,gBAAgB,MAAM;AAG/D,gBAAM,SAAS,OAAO,QAAQ,WAAW,aAAa,QAAQ,SAAS,KAAK;AAG5E,eAAK,gBAAgB,KAAK;AAAA,YACtB,OAAO,KAAK,KAAK,cAAc,KAAK,cAAc,KAAK,KAAK;AAAA,UAChE;AAAA,QACJ,OAAO;AACH,eAAK,gBAAgB;AAAA,QACzB;AAGA,aAAK,4CAAsB;AAAA,MAC/B;AAGA,UAAI,KAAK,kBAAkB,MAAM;AAC7B;AAAA,MACJ;AAGA,UAAI,OAAO,QAAQ,iBAAiB,YAAY;AAE5C,cAAM,YAAY,QAAQ,aAAa;AAGvC,YAAI,OAAO,cAAc,YAAY,MAAM,SAAS,GAAG;AACnD,gBAAM,IAAI,MAAM,oDAAoD;AAAA,QACxE;AAGA,aAAK,kBAAkB,YAAY;AAAA,MACvC,OAAO;AAEH,aAAK,iBAAiB,IAAI,KAAK,EAAE,QAAQ,IAAI,KAAK;AAAA,MACtD;AAGA,UAAI,KAAK,kBAAkB,KAAK,eAAe;AAE3C,aAAK,gDAAwB;AAAA,MACjC;AAAA,IACJ;AAAA,IAKA,UAAU,MAAM;AACZ,UAAI,KAAK,aAAa,MAAM;AACxB,eAAO,QAAQ,KAAK;AAAA,MACxB,WAAW,KAAK,gBAAgB,QAAQ,KAAK,gBAAgB,MAAM;AAC/D,eAAO,QAAQ,KAAK,iBAAiB,KAAK;AAAA,MAC9C,OAAO;AACH,eAAO;AAAA,MACX;AAAA,IACJ;AAAA,EACJ;;;AC5GA,MAA8B,YAA9B,cAAgD,KAAK;AAAA,IAMjD,YAAY,MAAc,YAAmC,OAAa;AACtE,YAAM,MAAM,YAAY,CAAC,CAAC;AAD+B;AAAA,IAE7D;AAAA,IAKA,aAAa,MAAM;AAAA,IAKnB,cAAc,MAAM,CAAC,KAAK,KAAK;AAAA,IAK/B,QAAQ,MAAM;AAEV,WAAK,wCAAoB;AAGzB,WAAK,MAAM,MAAM;AAAA,IACrB;AAAA,IAMA,QAAQ,CAAC,UAAiB;AAEtB,UAAI,CAAC,KAAK,sCAAgB,GAAG;AACzB;AAAA,MACJ;AAGA,WAAK,MAAM,MAAM,KAAK;AAGtB,WAAK,MAAM;AAEX,WAAK,aAAa,MAAM,GAAG,kBAAkB,OAAO,OAAO,IAAI;AAAA,IACnE;AAAA,EACJ;;;AC9CA,MAAqB,OAArB,cAAkC,UAAU;AAAA,IAKxC,YAAY,YAAyB,OAAa;AAC9C,YAAM,QAAQ,YAAY,KAAK;AAAA,IACnC;AAAA,IAOU,SAAS,OAAc,SAAqC;AAElE,UAAI,KAAK,MAAM,SAAS,yCAAqB,KAAK,MAAM,SAAS,2CAAqB;AAElF,aAAK,MAAM,OAAO,OAAO,OAAO;AAAA,MACpC;AAGA,WAAK,SAAS,KAAK,MAAM,SAAS,CAAC;AAAA,IACvC;AAAA,IAKA,UAAU,MAAM;AAAA,EACpB;;;ACzBA,MAAqB,SAArB,cAAoC,UAAU;AAAA,IAQ1C,YACI,YACQ,YACA,eACA,eACR,OACF;AACE,YAAM,UAAU,YAAY,KAAK;AALzB;AACA;AACA;AAAA,IAIZ;AAAA,IAKQ,uBAAsC;AAAA,IAKtC,wBAAgC;AAAA,IAO9B,SAAS,OAAc,SAAqC;AAElE,UAAI,KAAK,kCAAc,GAAG;AAEtB,aAAK,MAAM,MAAM;AAGjB,aAAK,wBAAwB;AAG7B,aAAK,wBAAwB,OAAO;AAAA,MACxC;AAIA,UAAI,KAAK,WAAW,GAAG;AAEnB,aAAK,4CAAsB;AAI3B,YAAI,KAAK,MAAM,SAAS,+CAAuB;AAC3C,eAAK,MAAM,MAAM;AAAA,QACrB;AAGA,aAAK,MAAM,OAAO,OAAO,OAAO;AAIhC,YAAI,KAAK,MAAM,SAAS,yCAAoB;AAExC,eAAK,0CAAqB;AAE1B;AAAA,QACJ,WAAW,KAAK,MAAM,SAAS,+CAAuB;AAElD,eAAK,yBAAyB;AAAA,QAClC;AAAA,MACJ,OAAO;AAEH,aAAK,gDAAwB;AAAA,MACjC;AAAA,IACJ;AAAA,IAKA,UAAU,MAAM;AACZ,UAAI,KAAK,eAAe,MAAM;AAC1B,eAAO,UAAU,KAAK;AAAA,MAC1B,WAAW,KAAK,kBAAkB,QAAQ,KAAK,kBAAkB,MAAM;AACnE,eAAO,UAAU,KAAK,kBAAkB,KAAK;AAAA,MACjD,OAAO;AACH,eAAO;AAAA,MACX;AAAA,IACJ;AAAA,IAKA,QAAQ,MAAM;AAEV,WAAK,wCAAoB;AAGzB,WAAK,wBAAwB;AAG7B,WAAK,MAAM,MAAM;AAAA,IACrB;AAAA,IAMQ,aAAa,MAAM;AACvB,UAAI,KAAK,yBAAyB,MAAM;AAEpC,eAAO,KAAK,wBAAwB,KAAK;AAAA,MAC7C;AAGA,aAAO;AAAA,IACX;AAAA,IAMQ,0BAA0B,CAAC,YAAkC;AAEjE,UAAI,KAAK,eAAe,MAAM;AAC1B,aAAK,uBAAuB,KAAK;AAAA,MACrC,WAAW,KAAK,kBAAkB,QAAQ,KAAK,kBAAkB,MAAM;AAGnE,cAAM,SAAS,OAAO,QAAQ,WAAW,aAAa,QAAQ,SAAS,KAAK;AAG5E,aAAK,uBAAuB,KAAK;AAAA,UAC7B,OAAO,KAAK,KAAK,gBAAgB,KAAK,gBAAgB,KAAK,KAAK;AAAA,QACpE;AAAA,MACJ,OAAO;AACH,aAAK,uBAAuB;AAAA,MAChC;AAAA,IACJ;AAAA,EACJ;;;AC5IA,MAAqB,QAArB,cAAmC,UAAU;AAAA,IAQzC,YACI,YACQ,UACA,aACA,aACR,OACF;AACE,YAAM,SAAS,YAAY,KAAK;AALxB;AACA;AACA;AAAA,IAIZ;AAAA,IAKQ,qBAAoC;AAAA,IAKpC,sBAA8B;AAAA,IAO5B,SAAS,OAAc,SAAqC;AAElE,UAAI,KAAK,kCAAc,GAAG;AAEtB,aAAK,MAAM,MAAM;AAGjB,aAAK,sBAAsB;AAG3B,aAAK,sBAAsB,OAAO;AAAA,MACtC;AAIA,UAAI,KAAK,WAAW,GAAG;AAEnB,aAAK,4CAAsB;AAI3B,YAAI,KAAK,MAAM,SAAS,yCAAoB;AACxC,eAAK,MAAM,MAAM;AAAA,QACrB;AAGA,aAAK,MAAM,OAAO,OAAO,OAAO;AAIhC,YAAI,KAAK,MAAM,SAAS,+CAAuB;AAE3C,eAAK,gDAAwB;AAE7B;AAAA,QACJ,WAAW,KAAK,MAAM,SAAS,yCAAoB;AAE/C,eAAK,uBAAuB;AAAA,QAChC;AAAA,MACJ,OAAO;AAEH,aAAK,0CAAqB;AAAA,MAC9B;AAAA,IACJ;AAAA,IAKA,UAAU,MAAM;AACZ,UAAI,KAAK,aAAa,MAAM;AACxB,eAAO,SAAS,KAAK;AAAA,MACzB,WAAW,KAAK,gBAAgB,QAAQ,KAAK,gBAAgB,MAAM;AAC/D,eAAO,SAAS,KAAK,gBAAgB,KAAK;AAAA,MAC9C,OAAO;AACH,eAAO;AAAA,MACX;AAAA,IACJ;AAAA,IAKA,QAAQ,MAAM;AAEV,WAAK,wCAAoB;AAGzB,WAAK,sBAAsB;AAG3B,WAAK,MAAM,MAAM;AAAA,IACrB;AAAA,IAMA,aAAa,MAAM;AACf,UAAI,KAAK,uBAAuB,MAAM;AAElC,eAAO,KAAK,sBAAsB,KAAK;AAAA,MAC3C;AAGA,aAAO;AAAA,IACX;AAAA,IAMA,wBAAwB,CAAC,YAAkC;AAEvD,UAAI,KAAK,aAAa,MAAM;AACxB,aAAK,qBAAqB,KAAK;AAAA,MACnC,WAAW,KAAK,gBAAgB,QAAQ,KAAK,gBAAgB,MAAM;AAG/D,cAAM,SAAS,OAAO,QAAQ,WAAW,aAAa,QAAQ,SAAS,KAAK;AAG5E,aAAK,qBAAqB,KAAK;AAAA,UAC3B,OAAO,KAAK,KAAK,cAAc,KAAK,cAAc,KAAK,KAAK;AAAA,QAChE;AAAA,MACJ,OAAO;AACH,aAAK,qBAAqB;AAAA,MAC9B;AAAA,IACJ;AAAA,EACJ;;;AChJA,MAAqB,OAArB,cAAkC,UAAU;AAAA,IAKxC,YAAY,YAAyB,OAAa;AAC9C,YAAM,QAAQ,YAAY,KAAK;AAAA,IACnC;AAAA,IAOU,SAAS,OAAc,SAAqC;AAElE,UAAI,KAAK,MAAM,SAAS,yCAAqB,KAAK,MAAM,SAAS,2CAAqB;AAClF,aAAK,MAAM,OAAO,OAAO,OAAO;AAAA,MACpC;AAGA,cAAQ,KAAK,MAAM,SAAS,GAAG;AAAA,QAC3B;AACI,eAAK,4CAAsB;AAC3B;AAAA,QAEJ;AACI,eAAK,0CAAqB;AAC1B;AAAA,QAEJ;AACI,eAAK,gDAAwB;AAC7B;AAAA,QAEJ;AACI,eAAK,wCAAoB;AAAA,MACjC;AAAA,IACJ;AAAA,IAKA,UAAU,MAAM;AAAA,EACpB;;;AC3CA,MAAqB,UAArB,cAAqC,UAAU;AAAA,IAK3C,YAAY,YAAyB,OAAa;AAC9C,YAAM,WAAW,YAAY,KAAK;AAAA,IACtC;AAAA,IAOU,SAAS,OAAc,SAAqC;AAElE,UAAI,KAAK,MAAM,SAAS,yCAAqB,KAAK,MAAM,SAAS,2CAAqB;AAClF,aAAK,MAAM,OAAO,OAAO,OAAO;AAAA,MACpC;AAGA,cAAQ,KAAK,MAAM,SAAS,GAAG;AAAA,QAC3B;AACI,eAAK,4CAAsB;AAC3B;AAAA,QAEJ;AAAA,QACA;AACI,eAAK,gDAAwB;AAC7B;AAAA,QAEJ;AACI,eAAK,wCAAoB;AAAA,MACjC;AAAA,IACJ;AAAA,IAKA,UAAU,MAAM;AAAA,EACpB;;;ACxCA,MAAqB,OAArB,cAAkC,UAAU;AAAA,IAKxC,YAAY,YAAyB,OAAa;AAC9C,YAAM,QAAQ,YAAY,KAAK;AAAA,IACnC;AAAA,IAOU,SAAS,OAAc,SAAqC;AAElE,UAAI,KAAK,MAAM,SAAS,yCAAqB,KAAK,MAAM,SAAS,2CAAqB;AAClF,aAAK,MAAM,OAAO,OAAO,OAAO;AAAA,MACpC;AAGA,cAAQ,KAAK,MAAM,SAAS,GAAG;AAAA,QAC3B;AACI,eAAK,4CAAsB;AAC3B;AAAA,QAEJ;AAAA,QACA;AACI,eAAK,0CAAqB;AAC1B;AAAA,QAEJ;AACI,eAAK,wCAAoB;AAAA,MACjC;AAAA,IACJ;AAAA,IAKA,UAAU,MAAM;AAAA,EACpB;;;ACnDA,0BAAwB;;;ACQxB,MAA8B,YAA9B,cAAgD,KAAK;AAAA,IAMjD,YAAY,MAAc,YAAmC,UAAkB;AAC3E,YAAM,MAAM,YAAY,CAAC,CAAC;AAD+B;AAAA,IAE7D;AAAA,IAKA,aAAa,MAAM;AAAA,IAKnB,cAAc,MAAM,KAAK;AAAA,IAKzB,QAAQ,MAAM;AAEV,WAAK,wCAAoB;AAGzB,WAAK,YAAY,EAAE,QAAQ,CAAC,UAAU,MAAM,MAAM,CAAC;AAAA,IACvD;AAAA,IAMA,QAAQ,CAAC,UAAiB;AAEtB,UAAI,CAAC,KAAK,sCAAgB,GAAG;AACzB;AAAA,MACJ;AAGA,WAAK,YAAY,EAAE,QAAQ,CAAC,UAAU,MAAM,MAAM,KAAK,CAAC;AAGxD,WAAK,MAAM;AAEX,WAAK,aAAa,MAAM,GAAG,kBAAkB,OAAO,OAAO,IAAI;AAAA,IACnE;AAAA,EACJ;;;AD3CA,MAAqB,QAArB,cAAmC,UAAU;AAAA,IAMzC,YAAY,YAAiC,SAAmB,UAAkB;AAC9E,YAAM,SAAS,YAAY,QAAQ;AADM;AAAA,IAE7C;AAAA,IAKQ;AAAA,IAOE,SAAS,OAAc,SAAqC;AAElE,UAAI,KAAK,kCAAc,GAAG;AAEtB,cAAM,gBAAY,kBAAAC,SAAkB;AAAA,UAEhC,QAAQ,QAAQ;AAAA,UAEhB,cAAc,KAAK,SAAS,IAAI,CAAC,OAAO,UAAU,CAAC,OAAO,KAAK,QAAQ,UAAU,CAAC,CAAC;AAAA,QACvF,CAAC;AAGD,aAAK,gBAAgB,UAAU,KAAK,KAAK;AAAA,MAC7C;AAGA,UAAI,CAAC,KAAK,eAAe;AACrB,cAAM,IAAI,MAAM,uDAAuD;AAAA,MAC3E;AAGA,UAAI,KAAK,cAAc,SAAS,yCAAqB,KAAK,cAAc,SAAS,2CAAqB;AAClG,aAAK,cAAc,OAAO,OAAO,OAAO;AAAA,MAC5C;AAGA,WAAK,SAAS,KAAK,cAAc,SAAS,CAAC;AAAA,IAC/C;AAAA,IAKA,UAAU,MAAO,KAAK,QAAQ,SAAS,UAAU,KAAK,QAAQ,KAAK,GAAG,OAAO;AAAA,EACjF;;;AExDA,MAAqB,WAArB,cAAsC,UAAU;AAAA,IAK5C,YAAY,YAAmC,UAAkB;AAC7D,YAAM,YAAY,YAAY,QAAQ;AADK;AAAA,IAE/C;AAAA,IAOU,SAAS,OAAc,SAAqC;AAElE,iBAAW,SAAS,KAAK,UAAU;AAE/B,YAAI,MAAM,SAAS,yCAAqB,MAAM,SAAS,2CAAqB;AAExE,gBAAM,OAAO,OAAO,OAAO;AAAA,QAC/B;AAGA,YAAI,MAAM,SAAS,+CAAuB;AAEtC,eAAK,gDAAwB;AAG7B;AAAA,QACJ;AAGA,YAAI,MAAM,SAAS,yCAAoB;AAGnC,cAAI,KAAK,SAAS,QAAQ,KAAK,MAAM,KAAK,SAAS,SAAS,GAAG;AAE3D,iBAAK,0CAAqB;AAG1B;AAAA,UACJ,OAAO;AAEH;AAAA,UACJ;AAAA,QACJ;AAGA,YAAI,MAAM,SAAS,2CAAqB;AAEpC,eAAK,4CAAsB;AAG3B;AAAA,QACJ;AAGA,cAAM,IAAI,MAAM,0CAA0C;AAAA,MAC9D;AAAA,IACJ;AAAA,IAKA,UAAU,MAAM;AAAA,EACpB;;;AClEA,MAAqB,WAArB,cAAsC,UAAU;AAAA,IAK5C,YAAY,YAAmC,UAAkB;AAC7D,YAAM,YAAY,YAAY,QAAQ;AADK;AAAA,IAE/C;AAAA,IAOU,SAAS,OAAc,SAAqC;AAElE,iBAAW,SAAS,KAAK,UAAU;AAE/B,YAAI,MAAM,SAAS,yCAAqB,MAAM,SAAS,2CAAqB;AAExE,gBAAM,OAAO,OAAO,OAAO;AAAA,QAC/B;AAGA,YAAI,MAAM,SAAS,+CAAuB;AAGtC,cAAI,KAAK,SAAS,QAAQ,KAAK,MAAM,KAAK,SAAS,SAAS,GAAG;AAE3D,iBAAK,gDAAwB;AAG7B;AAAA,UACJ,OAAO;AAEH;AAAA,UACJ;AAAA,QACJ;AAGA,YAAI,MAAM,SAAS,yCAAoB;AAEnC,eAAK,0CAAqB;AAG1B;AAAA,QACJ;AAGA,YAAI,MAAM,SAAS,2CAAqB;AAEpC,eAAK,4CAAsB;AAG3B;AAAA,QACJ;AAGA,cAAM,IAAI,MAAM,0CAA0C;AAAA,MAC9D;AAAA,IACJ;AAAA,IAKA,UAAU,MAAM;AAAA,EACpB;;;AClEA,MAAqB,WAArB,cAAsC,UAAU;AAAA,IAK5C,YAAY,YAAyB,UAAkB;AACnD,YAAM,YAAY,YAAY,QAAQ;AAAA,IAC1C;AAAA,IAOU,SAAS,OAAc,SAAqC;AAElE,UAAI,iBAAiB;AAErB,UAAI,iBAAiB;AAGrB,iBAAW,SAAS,KAAK,UAAU;AAE/B,YAAI,MAAM,SAAS,yCAAqB,MAAM,SAAS,2CAAqB;AAExE,gBAAM,OAAO,OAAO,OAAO;AAAA,QAC/B;AAGA,YAAI,MAAM,SAAS,+CAAuB;AAEtC;AAGA;AAAA,QACJ;AAGA,YAAI,MAAM,SAAS,yCAAoB;AACnC,2BAAiB;AAGjB;AAAA,QACJ;AAGA,YAAI,MAAM,SAAS,2CAAqB;AAEpC,gBAAM,IAAI,MAAM,0CAA0C;AAAA,QAC9D;AAAA,MACJ;AAEA,UAAI,gBAAgB;AAEhB,aAAK,0CAAqB;AAG1B,mBAAW,SAAS,KAAK,UAAU;AAC/B,cAAI,MAAM,SAAS,2CAAqB;AACpC,kBAAM,MAAM,KAAK;AAAA,UACrB;AAAA,QACJ;AAAA,MACJ,OAAO;AAEH,aAAK,SAAS,mBAAmB,KAAK,SAAS,sFAAwC;AAAA,MAC3F;AAAA,IACJ;AAAA,IAKA,UAAU,MAAM;AAAA,EACpB;;;ACrEA,MAA8B,YAA9B,MAAuG;AAAA,IAKnG,YAAsB,MAAwB,MAAqB;AAA7C;AAAwB;AAAA,IAAsB;AAAA,IAKpE,UAAU,MAAM,KAAK;AAAA,IAKrB,eAAe,MAAM,KAAK;AAAA,EAW9B;;;AC5BA,MAA8B,QAA9B,cAA4C,UAAiC;AAAA,IAMzE,YAAY,MAAc,MAA6B,WAAmB;AACtE,YAAM,MAAM,IAAI;AADmC;AAAA,IAEvD;AAAA,IAKA,eAAe,MAAM,KAAK;AAAA,IAK1B,UAAU,MAAM;AAAA,IAKhB,aAAoC;AAChC,aAAO;AAAA,QACH,MAAM,KAAK,QAAQ;AAAA,QACnB,MAAM,KAAK,aAAa;AAAA,QACxB,WAAW,KAAK,aAAa;AAAA,MACjC;AAAA,IACJ;AAAA,EAQJ;;;ACzCA,MAAqB,QAArB,cAAmC,MAAM;AAAA,IAKrC,YAAY,WAAmB,MAAqB;AAChD,YAAM,SAAS,MAAM,SAAS;AAAA,IAClC;AAAA,IAOA,cAAc,CAAC,UAAiB;AAE5B,YAAM,uBAAuB,OAAO,eAAe,OAAO,KAAK,aAAa,CAAC;AAG7E,UAAI,yBAAyB,MAAM;AAC/B,cAAM,IAAI;AAAA,UACN,gDAAgD,KAAK,aAAa;AAAA,QACtE;AAAA,MACJ;AAGA,aAAO,CAAC,CAAC,qBAAqB,KAAK,IAAI;AAAA,IAC3C;AAAA,EACJ;;;AC5BA,MAAqB,QAArB,cAAmC,MAAM;AAAA,IAKrC,YAAY,WAAmB,MAAqB;AAChD,YAAM,SAAS,MAAM,SAAS;AAAA,IAClC;AAAA,IAOA,cAAc,CAAC,UAAiB;AAE5B,YAAM,uBAAuB,OAAO,eAAe,OAAO,KAAK,aAAa,CAAC;AAG7E,UAAI,yBAAyB,MAAM;AAC/B,cAAM,IAAI;AAAA,UACN,gDAAgD,KAAK,aAAa;AAAA,QACtE;AAAA,MACJ;AAGA,aAAO,CAAC,CAAC,CAAC,qBAAqB,KAAK,IAAI;AAAA,IAC5C;AAAA,EACJ;;;ACxBA,MAA8B,WAA9B,cAA+C,UAAoC;AAAA,IAM/E,YAAY,MAAc,MAA6B,cAAsB;AACzE,YAAM,MAAM,IAAI;AADmC;AAAA,IAEvD;AAAA,IAKA,kBAAkB,MAAM,KAAK;AAAA,IAK7B,UAAU,MAAM;AAAA,IAKhB,aAAuC;AACnC,aAAO;AAAA,QACH,MAAM,KAAK,QAAQ;AAAA,QACnB,MAAM,KAAK,aAAa;AAAA,QACxB,cAAc,KAAK,gBAAgB;AAAA,MACvC;AAAA,IACJ;AAAA,EAOJ;;;ACxCA,MAAqB,QAArB,cAAmC,SAAS;AAAA,IAKxC,YAAY,cAAsB,MAAqB;AACnD,YAAM,SAAS,MAAM,YAAY;AAAA,IACrC;AAAA,IAMA,oBAAoB,CAAC,UAAiB;AAElC,YAAM,sBAAsB,OAAO,eAAe,OAAO,KAAK,gBAAgB,CAAC;AAG/E,UAAI,wBAAwB,MAAM;AAC9B,cAAM,IAAI;AAAA,UACN,+BAA+B,KAAK,gBAAgB;AAAA,QACxD;AAAA,MACJ;AAGA,0BAAoB,KAAK,IAAI;AAAA,IACjC;AAAA,EACJ;;;AC3BA,MAAqB,OAArB,cAAkC,SAAS;AAAA,IAKvC,YAAY,cAAsB,MAAqB;AACnD,YAAM,QAAQ,MAAM,YAAY;AAAA,IACpC;AAAA,IAQA,oBAAoB,CAAC,OAAc,WAAoB,cAAuB;AAE1E,YAAM,sBAAsB,OAAO,eAAe,OAAO,KAAK,gBAAgB,CAAC;AAG/E,UAAI,wBAAwB,MAAM;AAC9B,cAAM,IAAI;AAAA,UACN,8BAA8B,KAAK,gBAAgB;AAAA,QACvD;AAAA,MACJ;AAGA,0BAAoB,CAAC,EAAE,OAAO,EAAE,WAAW,WAAW,SAAS,UAAU,EAAE,GAAG,GAAG,KAAK,IAAI,CAAC;AAAA,IAC/F;AAAA,EACJ;;;AC7BA,MAAqB,OAArB,cAAkC,SAAS;AAAA,IAKvC,YAAY,cAAsB,MAAqB;AACnD,YAAM,QAAQ,MAAM,YAAY;AAAA,IACpC;AAAA,IAMA,oBAAoB,CAAC,UAAiB;AAElC,YAAM,sBAAsB,OAAO,eAAe,OAAO,KAAK,gBAAgB,CAAC;AAG/E,UAAI,wBAAwB,MAAM;AAC9B,cAAM,IAAI;AAAA,UACN,8BAA8B,KAAK,gBAAgB;AAAA,QACvD;AAAA,MACJ;AAGA,0BAAoB,KAAK,IAAI;AAAA,IACjC;AAAA,EACJ;;;ACqBA,MAAM,qBAEF;AAAA,IACA,OAAO,CAAC,WAAmB,uBAAsC,IAAI,MAAM,WAAW,kBAAkB;AAAA,IACxG,OAAO,CAAC,WAAmB,uBAAsC,IAAI,MAAM,WAAW,kBAAkB;AAAA,IACxG,OAAO,CAAC,cAAsB,uBAAsC,IAAI,MAAM,cAAc,kBAAkB;AAAA,IAC9G,MAAM,CAAC,cAAsB,uBAAsC,IAAI,KAAK,cAAc,kBAAkB;AAAA,IAC5G,MAAM,CAAC,cAAsB,uBAAsC,IAAI,KAAK,cAAc,kBAAkB;AAAA,EAChH;AAkGA,MAAM,mBAAmB;AAAA,IACrB,MAAM,OAAoB;AAAA,MACtB,MAAM;AAAA,MACN,YAAY,CAAC;AAAA,MACb,MAAM;AAAA,MACN,UAAU,CAAC;AAAA,MACX,SAAS,OAAe;AAEpB,YAAI,QAAQ,GAAG;AACX,gBAAM,IAAI,MAAM,iDAAiD;AAAA,QACrE;AAGA,YAAI,KAAK,SAAS,WAAW,GAAG;AAC5B,gBAAM,IAAI,MAAM,sCAAsC;AAAA,QAC1D;AAAA,MACJ;AAAA,MACA,mBAAmB,uBAAuB,iBAAiB;AACvD,eAAO,IAAI;AAAA,UACP,KAAK;AAAA,UACL,KAAK,SAAU,GAAG,mBAAmB,uBAAuB,gBAAgB,MAAM,CAAC;AAAA,QACvF;AAAA,MACJ;AAAA,IACJ;AAAA,IACA,QAAQ,OAAsB;AAAA,MAC1B,MAAM;AAAA,MACN,YAAY;AAAA,MACZ,WAAW;AAAA,MAAC;AAAA,MACZ,mBAAmB,uBAAuB,iBAAiB;AAEvD,cAAM,iBAAiB,sBAAsB,KAAK,UAAU;AAG5D,YAAI,gBAAgB,QAAQ,KAAK,UAAU,MAAM,IAAI;AACjD,gBAAM,IAAI,MAAM,mEAAmE,KAAK,aAAa;AAAA,QACzG;AAGA,YAAI,gBAAgB;AAChB,iBAAO,eACF,mBAAmB,uBAAuB,gBAAgB,OAAO,KAAK,UAAU,CAAC,EACjF,YAAY,EAAE;AAAA,QACvB,OAAO;AACH,gBAAM,IAAI,MAAM,gCAAgC,KAAK,wCAAwC;AAAA,QACjG;AAAA,MACJ;AAAA,IACJ;AAAA,IACA,UAAU,OAAyB;AAAA,MAC/B,MAAM;AAAA,MACN,YAAY,CAAC;AAAA,MACb,UAAU,CAAC;AAAA,MACX,WAAW;AAEP,YAAI,KAAK,SAAS,SAAS,GAAG;AAC1B,gBAAM,IAAI,MAAM,mDAAmD;AAAA,QACvE;AAAA,MACJ;AAAA,MACA,mBAAmB,uBAAuB,iBAAiB;AACvD,eAAO,IAAI;AAAA,UACP,KAAK;AAAA,UACL,KAAK,SAAS,IAAI,CAAC,UAAU,MAAM,mBAAmB,uBAAuB,gBAAgB,MAAM,CAAC,CAAC;AAAA,QACzG;AAAA,MACJ;AAAA,IACJ;AAAA,IACA,UAAU,OAAyB;AAAA,MAC/B,MAAM;AAAA,MACN,YAAY,CAAC;AAAA,MACb,UAAU,CAAC;AAAA,MACX,WAAW;AAEP,YAAI,KAAK,SAAS,SAAS,GAAG;AAC1B,gBAAM,IAAI,MAAM,mDAAmD;AAAA,QACvE;AAAA,MACJ;AAAA,MACA,mBAAmB,uBAAuB,iBAAiB;AACvD,eAAO,IAAI;AAAA,UACP,KAAK;AAAA,UACL,KAAK,SAAS,IAAI,CAAC,UAAU,MAAM,mBAAmB,uBAAuB,gBAAgB,MAAM,CAAC,CAAC;AAAA,QACzG;AAAA,MACJ;AAAA,IACJ;AAAA,IACA,UAAU,OAAyB;AAAA,MAC/B,MAAM;AAAA,MACN,YAAY,CAAC;AAAA,MACb,UAAU,CAAC;AAAA,MACX,WAAW;AAEP,YAAI,KAAK,SAAS,SAAS,GAAG;AAC1B,gBAAM,IAAI,MAAM,mDAAmD;AAAA,QACvE;AAAA,MACJ;AAAA,MACA,mBAAmB,uBAAuB,iBAAiB;AACvD,eAAO,IAAI;AAAA,UACP,KAAK;AAAA,UACL,KAAK,SAAS,IAAI,CAAC,UAAU,MAAM,mBAAmB,uBAAuB,gBAAgB,MAAM,CAAC,CAAC;AAAA,QACzG;AAAA,MACJ;AAAA,IACJ;AAAA,IACA,OAAO,OAAqB;AAAA,MACxB,MAAM;AAAA,MACN,YAAY,CAAC;AAAA,MACb,UAAU,CAAC;AAAA,MACX,SAAS,CAAC;AAAA,MACV,WAAW;AAEP,YAAI,KAAK,SAAU,SAAS,GAAG;AAC3B,gBAAM,IAAI,MAAM,gDAAgD;AAAA,QACpE;AAAA,MACJ;AAAA,MACA,mBAAmB,uBAAuB,iBAAiB;AACvD,eAAO,IAAI;AAAA,UACP,KAAK;AAAA,UACL,KAAK;AAAA,UACL,KAAK,SAAU,IAAI,CAAC,UAAU,MAAM,mBAAmB,uBAAuB,gBAAgB,MAAM,CAAC,CAAC;AAAA,QAC1G;AAAA,MACJ;AAAA,IACJ;AAAA,IACA,QAAQ,OAAsB;AAAA,MAC1B,MAAM;AAAA,MACN,YAAY,CAAC;AAAA,MACb,YAAY;AAAA,MACZ,eAAe;AAAA,MACf,eAAe;AAAA,MACf,UAAU,CAAC;AAAA,MACX,WAAW;AAEP,YAAI,KAAK,SAAU,WAAW,GAAG;AAC7B,gBAAM,IAAI,MAAM,wCAAwC;AAAA,QAC5D;AAEA,YAAI,KAAK,eAAe,MAAM;AAE1B,cAAI,KAAK,aAAa,GAAG;AACrB,kBAAM,IAAI,MAAM,oEAAoE;AAAA,UACxF;AAAA,QACJ,WAAW,KAAK,kBAAkB,QAAQ,KAAK,kBAAkB,MAAM;AAEnE,cAAI,KAAK,gBAAgB,KAAK,KAAK,gBAAgB,GAAG;AAClD,kBAAM,IAAI;AAAA,cACN;AAAA,YACJ;AAAA,UACJ;AAGA,cAAI,KAAK,gBAAgB,KAAK,eAAe;AACzC,kBAAM,IAAI;AAAA,cACN;AAAA,YACJ;AAAA,UACJ;AAAA,QACJ,OAAO;AAAA,QAEP;AAAA,MACJ;AAAA,MACA,mBAAmB,uBAAuB,iBAAiB;AACvD,eAAO,IAAI;AAAA,UACP,KAAK;AAAA,UACL,KAAK;AAAA,UACL,KAAK;AAAA,UACL,KAAK;AAAA,UACL,KAAK,SAAU,GAAG,mBAAmB,uBAAuB,gBAAgB,MAAM,CAAC;AAAA,QACvF;AAAA,MACJ;AAAA,IACJ;AAAA,IACA,OAAO,OAAqB;AAAA,MACxB,MAAM;AAAA,MACN,YAAY,CAAC;AAAA,MACb,UAAU;AAAA,MACV,aAAa;AAAA,MACb,aAAa;AAAA,MACb,UAAU,CAAC;AAAA,MACX,WAAW;AAEP,YAAI,KAAK,SAAU,WAAW,GAAG;AAC7B,gBAAM,IAAI,MAAM,uCAAuC;AAAA,QAC3D;AAEA,YAAI,KAAK,aAAa,MAAM;AAExB,cAAI,KAAK,WAAW,GAAG;AACnB,kBAAM,IAAI,MAAM,iEAAiE;AAAA,UACrF;AAAA,QACJ,WAAW,KAAK,gBAAgB,QAAQ,KAAK,gBAAgB,MAAM;AAE/D,cAAI,KAAK,cAAc,KAAK,KAAK,cAAc,GAAG;AAC9C,kBAAM,IAAI,MAAM,gFAAgF;AAAA,UACpG;AAGA,cAAI,KAAK,cAAc,KAAK,aAAa;AACrC,kBAAM,IAAI;AAAA,cACN;AAAA,YACJ;AAAA,UACJ;AAAA,QACJ,OAAO;AAAA,QAEP;AAAA,MACJ;AAAA,MACA,mBAAmB,uBAAuB,iBAAiB;AACvD,eAAO,IAAI;AAAA,UACP,KAAK;AAAA,UACL,KAAK;AAAA,UACL,KAAK;AAAA,UACL,KAAK;AAAA,UACL,KAAK,SAAU,GAAG,mBAAmB,uBAAuB,gBAAgB,MAAM,CAAC;AAAA,QACvF;AAAA,MACJ;AAAA,IACJ;AAAA,IACA,MAAM,OAAyB;AAAA,MAC3B,MAAM;AAAA,MACN,YAAY,CAAC;AAAA,MACb,UAAU,CAAC;AAAA,MACX,WAAW;AAEP,YAAI,KAAK,SAAU,WAAW,GAAG;AAC7B,gBAAM,IAAI,MAAM,sCAAsC;AAAA,QAC1D;AAAA,MACJ;AAAA,MACA,mBAAmB,uBAAuB,iBAAiB;AACvD,eAAO,IAAI;AAAA,UACP,KAAK;AAAA,UACL,KAAK,SAAU,GAAG,mBAAmB,uBAAuB,gBAAgB,MAAM,CAAC;AAAA,QACvF;AAAA,MACJ;AAAA,IACJ;AAAA,IACA,SAAS,OAAyB;AAAA,MAC9B,MAAM;AAAA,MACN,YAAY,CAAC;AAAA,MACb,UAAU,CAAC;AAAA,MACX,WAAW;AAEP,YAAI,KAAK,SAAU,WAAW,GAAG;AAC7B,gBAAM,IAAI,MAAM,yCAAyC;AAAA,QAC7D;AAAA,MACJ;AAAA,MACA,mBAAmB,uBAAuB,iBAAiB;AACvD,eAAO,IAAI;AAAA,UACP,KAAK;AAAA,UACL,KAAK,SAAU,GAAG,mBAAmB,uBAAuB,gBAAgB,MAAM,CAAC;AAAA,QACvF;AAAA,MACJ;AAAA,IACJ;AAAA,IACA,MAAM,OAAyB;AAAA,MAC3B,MAAM;AAAA,MACN,YAAY,CAAC;AAAA,MACb,UAAU,CAAC;AAAA,MACX,WAAW;AAEP,YAAI,KAAK,SAAU,WAAW,GAAG;AAC7B,gBAAM,IAAI,MAAM,sCAAsC;AAAA,QAC1D;AAAA,MACJ;AAAA,MACA,mBAAmB,uBAAuB,iBAAiB;AACvD,eAAO,IAAI;AAAA,UACP,KAAK;AAAA,UACL,KAAK,SAAU,GAAG,mBAAmB,uBAAuB,gBAAgB,MAAM,CAAC;AAAA,QACvF;AAAA,MACJ;AAAA,IACJ;AAAA,IACA,MAAM,OAAoB;AAAA,MACtB,MAAM;AAAA,MACN,YAAY,CAAC;AAAA,MACb,UAAU;AAAA,MACV,aAAa;AAAA,MACb,aAAa;AAAA,MACb,WAAW;AACP,YAAI,KAAK,aAAa,MAAM;AAExB,cAAI,KAAK,WAAW,GAAG;AACnB,kBAAM,IAAI,MAAM,2CAA2C;AAAA,UAC/D;AAAA,QACJ,WAAW,KAAK,gBAAgB,QAAQ,KAAK,gBAAgB,MAAM;AAE/D,cAAI,KAAK,cAAc,KAAK,KAAK,cAAc,GAAG;AAC9C,kBAAM,IAAI,MAAM,+DAA+D;AAAA,UACnF;AAGA,cAAI,KAAK,cAAc,KAAK,aAAa;AACrC,kBAAM,IAAI,MAAM,gFAAgF;AAAA,UACpG;AAAA,QACJ,OAAO;AAAA,QAEP;AAAA,MACJ;AAAA,MACA,qBAAqB;AACjB,eAAO,IAAI,KAAK,KAAK,YAAY,KAAK,UAAU,KAAK,aAAa,KAAK,WAAW;AAAA,MACtF;AAAA,IACJ;AAAA,IACA,QAAQ,OAAsB;AAAA,MAC1B,MAAM;AAAA,MACN,YAAY,CAAC;AAAA,MACb,YAAY;AAAA,MACZ,iBAAiB,CAAC;AAAA,MAClB,WAAW;AAAA,MAAC;AAAA,MACZ,qBAAqB;AACjB,eAAO,IAAI,OAAO,KAAK,YAAY,KAAK,YAAa,KAAK,eAAgB;AAAA,MAC9E;AAAA,IACJ;AAAA,IACA,WAAW,OAAyB;AAAA,MAChC,MAAM;AAAA,MACN,YAAY,CAAC;AAAA,MACb,eAAe;AAAA,MACf,oBAAoB,CAAC;AAAA,MACrB,WAAW;AAAA,MAAC;AAAA,MACZ,qBAAqB;AACjB,eAAO,IAAI,UAAU,KAAK,YAAY,KAAK,eAAgB,KAAK,kBAAmB;AAAA,MACvF;AAAA,IACJ;AAAA,EACJ;AASe,WAAR,kBAAmC,YAAmC;AAEzE,UAAM,EAAE,cAAc,oBAAoB,IAAI,yBAAyB,UAAU;AAGjF,UAAM,SAAS,0BAA0B,mBAAmB;AAG5D,QAAI,OAAO,SAAS,GAAG;AACnB,YAAM,IAAI,MAAM,qBAAqB;AAAA,IACzC;AAGA,QAAI,OAAO,OAAO,CAAC,UAAU,UAAU,GAAG,EAAE,WAAW,OAAO,OAAO,CAAC,UAAU,UAAU,GAAG,EAAE,QAAQ;AACnG,YAAM,IAAI,MAAM,0BAA0B;AAAA,IAC9C;AAGA,UAAM,QAA6C,CAAC,CAAC,CAAC;AACtD,UAAM,YAAY,MAAM;AAGxB,WAAO,OAAO,QAAQ;AAElB,YAAM,QAAQ,OAAO,MAAM;AAE3B,YAAM,eAAe,MAAM,MAAM,SAAS;AAG1C,cAAQ,MAAO,YAAY,GAAG;AAAA,QAC1B,KAAK,QAAQ;AAET,gBAAM,OAAO,iBAAiB,KAAK;AAGnC,oBAAU,KAAK,IAAI;AAGnB,cAAI,OAAO,OAAO,KAAK;AACnB,kBAAM,gBAAgB,aAAa,QAAQ,YAAY;AAGvD,gBAAI,cAAc,WAAW,KAAK,cAAc,GAAG,SAAS,cAAc;AAEtE,mBAAK,OAAO,cAAc,GAAG;AAAA,YACjC,OAAO;AACH,oBAAM,IAAI,MAAM,oCAAoC;AAAA,YACxD;AAAA,UACJ;AAGA,eAAK,aAAa,cAAc,QAAQ,YAAY;AAEpD,sBAAY,QAAQ,GAAG;AAGvB,gBAAM,KAAK,KAAK,QAAS;AACzB;AAAA,QACJ;AAAA,QAEA,KAAK,UAAU;AAEX,gBAAM,OAAO,iBAAiB,OAAO;AAGrC,uBAAa,KAAK,IAAI;AAGtB,cAAI,OAAO,OAAO,KAAK;AACnB,kBAAM,IAAI,MAAM,sCAAsC;AAAA,UAC1D;AAGA,gBAAM,kBAAkB,aAAa,QAAQ,YAAY;AAGzD,cAAI,gBAAgB,WAAW,KAAK,gBAAgB,GAAG,SAAS,cAAc;AAE1E,iBAAK,aAAa,gBAAgB,GAAG;AAAA,UACzC,OAAO;AACH,kBAAM,IAAI,MAAM,sCAAsC;AAAA,UAC1D;AACA;AAAA,QACJ;AAAA,QAEA,KAAK,YAAY;AAEb,gBAAM,OAAO,iBAAiB,SAAS;AAGvC,uBAAa,KAAK,IAAI;AAGtB,eAAK,aAAa,cAAc,QAAQ,YAAY;AAEpD,sBAAY,QAAQ,GAAG;AAGvB,gBAAM,KAAK,KAAK,QAAS;AACzB;AAAA,QACJ;AAAA,QAEA,KAAK,YAAY;AAEb,gBAAM,OAAO,iBAAiB,SAAS;AAGvC,uBAAa,KAAK,IAAI;AAGtB,eAAK,aAAa,cAAc,QAAQ,YAAY;AAEpD,sBAAY,QAAQ,GAAG;AAGvB,gBAAM,KAAK,KAAK,QAAS;AACzB;AAAA,QACJ;AAAA,QAEA,KAAK,YAAY;AAEb,gBAAM,OAAO,iBAAiB,SAAS;AAGvC,uBAAa,KAAK,IAAI;AAGtB,eAAK,aAAa,cAAc,QAAQ,YAAY;AAEpD,sBAAY,QAAQ,GAAG;AAGvB,gBAAM,KAAK,KAAK,QAAS;AACzB;AAAA,QACJ;AAAA,QAEA,KAAK,SAAS;AAEV,gBAAM,OAAO,iBAAiB,MAAM;AAGpC,uBAAa,KAAK,IAAI;AAGtB,cAAI,OAAO,OAAO,KAAK;AAEnB,iBAAK,UAAU;AAAA,cACX;AAAA,cACA;AAAA,cACA,CAAC,QAAQ,IAAI,SAAS,YAAY,CAAC,CAAC,IAAI;AAAA,cACxC;AAAA,YACJ,EAAE,IAAI,CAAC,aAAa,SAAS,KAAe;AAAA,UAChD;AAGA,eAAK,aAAa,cAAc,QAAQ,YAAY;AAEpD,sBAAY,QAAQ,GAAG;AAGvB,gBAAM,KAAK,KAAK,QAAS;AACzB;AAAA,QACJ;AAAA,QAEA,KAAK,aAAa;AAEd,gBAAM,OAAO,iBAAiB,UAAU;AAGxC,uBAAa,KAAK,IAAI;AAGtB,cAAI,OAAO,OAAO,KAAK;AACnB,kBAAM,IAAI,MAAM,6CAA6C;AAAA,UACjE;AAGA,gBAAM,qBAAqB,aAAa,QAAQ,YAAY;AAG5D,cAAI,mBAAmB,UAAU,mBAAmB,GAAG,SAAS,cAAc;AAE1E,iBAAK,gBAAgB,mBAAmB,MAAM,EAAG;AAAA,UACrD,OAAO;AACH,kBAAM,IAAI,MAAM,6CAA6C;AAAA,UACjE;AAGA,6BACK,OAAO,CAAC,QAAQ,IAAI,SAAS,YAAY,EACzC,QAAQ,CAAC,QAAQ;AACd,kBAAM,IAAI;AAAA,cACN,4CACI,IAAI,QACJ;AAAA,YACR;AAAA,UACJ,CAAC;AAGL,eAAK,qBAAqB;AAG1B,eAAK,aAAa,cAAc,QAAQ,YAAY;AACpD;AAAA,QACJ;AAAA,QAEA,KAAK,QAAQ;AAET,gBAAM,OAAO,iBAAiB,KAAK;AAGnC,uBAAa,KAAK,IAAI;AAGtB,eAAK,aAAa,cAAc,QAAQ,YAAY;AAEpD,sBAAY,QAAQ,GAAG;AAGvB,gBAAM,KAAK,KAAK,QAAS;AACzB;AAAA,QACJ;AAAA,QAEA,KAAK,WAAW;AAEZ,gBAAM,OAAO,iBAAiB,QAAQ;AAGtC,uBAAa,KAAK,IAAI;AAGtB,eAAK,aAAa,cAAc,QAAQ,YAAY;AAEpD,sBAAY,QAAQ,GAAG;AAGvB,gBAAM,KAAK,KAAK,QAAS;AACzB;AAAA,QACJ;AAAA,QAEA,KAAK,QAAQ;AAET,gBAAM,OAAO,iBAAiB,KAAK;AAGnC,uBAAa,KAAK,IAAI;AAGtB,eAAK,aAAa,cAAc,QAAQ,YAAY;AAEpD,sBAAY,QAAQ,GAAG;AAGvB,gBAAM,KAAK,KAAK,QAAS;AACzB;AAAA,QACJ;AAAA,QAEA,KAAK,QAAQ;AAET,gBAAM,OAAO,iBAAiB,KAAK;AAGnC,uBAAa,KAAK,IAAI;AAMtB,cAAI,OAAO,OAAO,KAAK;AAEnB,kBAAM,gBAAgB;AAAA,cAClB;AAAA,cACA;AAAA,cACA,CAAC,QAAQ,IAAI,SAAS,YAAY,CAAC,CAAC,IAAI;AAAA,cACxC;AAAA,YACJ,EAAE,IAAI,CAAC,aAAa,SAAS,KAAK;AAMlC,gBAAI,cAAc,WAAW,GAAG;AAE5B,mBAAK,WAAW,cAAc;AAAA,YAClC,WAAW,cAAc,WAAW,GAAG;AAEnC,mBAAK,cAAc,cAAc;AACjC,mBAAK,cAAc,cAAc;AAAA,YACrC,WAAW,cAAc,SAAS,GAAG;AAEjC,oBAAM,IAAI,MAAM,wDAAwD;AAAA,YAC5E;AAAA,UACJ;AAGA,eAAK,aAAa,cAAc,QAAQ,YAAY;AACpD;AAAA,QACJ;AAAA,QAEA,KAAK,UAAU;AAEX,gBAAM,OAAO,iBAAiB,OAAO;AAGrC,uBAAa,KAAK,IAAI;AAMtB,cAAI,OAAO,OAAO,KAAK;AAEnB,kBAAM,gBAAgB;AAAA,cAClB;AAAA,cACA;AAAA,cACA,CAAC,QAAQ,IAAI,SAAS,YAAY,CAAC,CAAC,IAAI;AAAA,cACxC;AAAA,YACJ,EAAE,IAAI,CAAC,aAAa,SAAS,KAAK;AAGlC,gBAAI,cAAc,WAAW,GAAG;AAE5B,mBAAK,aAAa,cAAc;AAAA,YACpC,WAAW,cAAc,WAAW,GAAG;AAEnC,mBAAK,gBAAgB,cAAc;AACnC,mBAAK,gBAAgB,cAAc;AAAA,YACvC,OAAO;AAEH,oBAAM,IAAI,MAAM,iEAAiE;AAAA,YACrF;AAAA,UACJ;AAGA,eAAK,aAAa,cAAc,QAAQ,YAAY;AAEpD,sBAAY,QAAQ,GAAG;AAGvB,gBAAM,KAAK,KAAK,QAAS;AACzB;AAAA,QACJ;AAAA,QAEA,KAAK,SAAS;AAEV,gBAAM,OAAO,iBAAiB,MAAM;AAGpC,uBAAa,KAAK,IAAI;AAMtB,cAAI,OAAO,OAAO,KAAK;AAEnB,kBAAM,gBAAgB;AAAA,cAClB;AAAA,cACA;AAAA,cACA,CAAC,QAAQ,IAAI,SAAS,YAAY,CAAC,CAAC,IAAI;AAAA,cACxC;AAAA,YACJ,EAAE,IAAI,CAAC,aAAa,SAAS,KAAK;AAGlC,gBAAI,cAAc,WAAW,GAAG;AAE5B,mBAAK,WAAW,cAAc;AAAA,YAClC,WAAW,cAAc,WAAW,GAAG;AAEnC,mBAAK,cAAc,cAAc;AACjC,mBAAK,cAAc,cAAc;AAAA,YACrC,OAAO;AAEH,oBAAM,IAAI,MAAM,8DAA8D;AAAA,YAClF;AAAA,UACJ;AAGA,eAAK,aAAa,cAAc,QAAQ,YAAY;AAEpD,sBAAY,QAAQ,GAAG;AAGvB,gBAAM,KAAK,KAAK,QAAS;AACzB;AAAA,QACJ;AAAA,QAEA,KAAK,UAAU;AAEX,gBAAM,OAAO,iBAAiB,OAAO;AAGrC,uBAAa,KAAK,IAAI;AAGtB,cAAI,OAAO,OAAO,KAAK;AACnB,kBAAM,IAAI,MAAM,0CAA0C;AAAA,UAC9D;AAGA,gBAAM,kBAAkB,aAAa,QAAQ,YAAY;AAGzD,cAAI,gBAAgB,UAAU,gBAAgB,GAAG,SAAS,cAAc;AAEpE,iBAAK,aAAa,gBAAgB,MAAM,EAAG;AAAA,UAC/C,OAAO;AACH,kBAAM,IAAI,MAAM,0CAA0C;AAAA,UAC9D;AAGA,0BACK,OAAO,CAAC,QAAQ,IAAI,SAAS,YAAY,EACzC,QAAQ,CAAC,QAAQ;AACd,kBAAM,IAAI;AAAA,cACN,yCACI,IAAI,QACJ;AAAA,YACR;AAAA,UACJ,CAAC;AAGL,eAAK,kBAAkB;AAGvB,eAAK,aAAa,cAAc,QAAQ,YAAY;AACpD;AAAA,QACJ;AAAA,QAEA,KAAK,KAAK;AAEN,gBAAM,IAAI;AACV;AAAA,QACJ;AAAA,QAEA,SAAS;AACL,gBAAM,IAAI,MAAM,qBAAqB,QAAQ;AAAA,QACjD;AAAA,MACJ;AAAA,IACJ;AAGA,UAAM,kBAAkB,CAAC,MAAmB,UAAwB;AAEhE,WAAK,SAAS,KAAK;AAGnB,OAAC,KAAK,YAAY,CAAC,GAAG,QAAQ,CAAC,UAAU,gBAAgB,OAAO,QAAQ,CAAC,CAAC;AAAA,IAC9E;AAGA;AAAA,MACI;AAAA,QACI,UAAU,MAAM;AAAA,QAChB,WAA4C;AAExC,cAAI,KAAK,SAAS,WAAW,GAAG;AAC5B,kBAAM,IAAI,MAAM,yCAAyC;AAAA,UAC7D;AAGA,qBAAW,uBAAuB,KAAK,UAAU;AAC7C,gBAAI,oBAAoB,SAAS,QAAQ;AACrC,oBAAM,IAAI,MAAM,0CAA0C;AAAA,YAC9D;AAAA,UACJ;AAGA,cAAI,KAAK,SAAS,OAAO,CAAC,wBAAwB,oBAAoB,SAAS,IAAI,EAAE,WAAW,GAAG;AAC/F,kBAAM,IAAI,MAAM,6EAA6E;AAAA,UACjG;AAGA,gBAAM,gBAA0B,CAAC;AACjC,qBAAW,uBAAuB,KAAK,UAAU;AAC7C,gBAAI,cAAc,QAAQ,oBAAoB,IAAK,MAAM,IAAI;AACzD,oBAAM,IAAI,MAAM,kDAAkD,oBAAoB,OAAO;AAAA,YACjG,OAAO;AACH,4BAAc,KAAK,oBAAoB,IAAK;AAAA,YAChD;AAAA,UACJ;AAAA,QACJ;AAAA,MACJ;AAAA,MACA;AAAA,IACJ;AAGA,WAAO,MAAM;AAAA,EACjB;AAQA,WAAS,YAAY,QAAkB,UAA6B;AAEhE,UAAM,SAAS,OAAO,MAAM;AAG5B,QAAI,WAAW,QAAW;AACtB,YAAM,IAAI,MAAM,8BAA8B;AAAA,IAClD;AAGA,QAAI,aAAa,QAAW;AAExB,UAAI,0BAA2B,CAAC,EAC3B,OAAO,QAAQ,EACf,KAAK,CAAC,SAAS,OAAO,YAAY,MAAM,KAAK,YAAY,CAAC;AAG/D,UAAI,CAAC,yBAAyB;AAC1B,cAAM,oBAAqB,CAAC,EACvB,OAAO,QAAQ,EACf,IAAI,CAAC,SAAS,MAAM,OAAO,GAAG,EAC9B,KAAK,MAAM;AAEhB,cAAM,IAAI,MAAM,qCAAqC,+BAA+B,SAAS;AAAA,MACjG;AAAA,IACJ;AAGA,WAAO;AAAA,EACX;AAYA,WAAS,aACL,QACA,4BACA,mBACA,yBACF;AAGE,UAAM,SAAS,YAAY,QAAQ,CAAC,KAAK,GAAG,CAAC,MAAM,MAAM,MAAM;AAE/D,UAAM,qBAA+B,CAAC;AACtC,UAAM,eAA8B,CAAC;AAGrC,WAAO,OAAO,UAAU,OAAO,OAAO,QAAQ;AAE1C,yBAAmB,KAAK,OAAO,MAAM,CAAE;AAAA,IAC3C;AAGA,uBAAmB,QAAQ,CAAC,OAAO,UAAU;AAEzC,YAAM,wBAAwB,EAAE,QAAQ;AAGxC,UAAI,uBAAuB;AAEvB,cAAM,qBAAqB,sBAAsB,OAAQ,0BAA0B;AAGnF,YAAI,qBAAqB,CAAC,kBAAkB,kBAAkB,GAAG;AAC7D,gBAAM,IAAI,MAAM,uBAAuB;AAAA,QAC3C;AAGA,qBAAa,KAAK,kBAAkB;AAAA,MACxC,OAAO;AAEH,YAAI,UAAU,KAAK;AACf,gBAAM,IAAI,MAAM,uDAAuD,QAAQ;AAAA,QACnF;AAAA,MACJ;AAAA,IACJ,CAAC;AAGD,gBAAY,QAAQ,MAAM;AAG1B,WAAO;AAAA,EACX;AAQA,WAAS,sBAAsB,OAAe,4BAA6D;AAEvG,QAAI,UAAU,QAAQ;AAClB,aAAO;AAAA,QACH,OAAO;AAAA,QACP,MAAM;AAAA,MACV;AAAA,IACJ;AAGA,QAAI,UAAU,UAAU,UAAU,SAAS;AACvC,aAAO;AAAA,QACH,OAAO,UAAU;AAAA,QACjB,MAAM;AAAA,MACV;AAAA,IACJ;AAKA,QAAI,CAAC,MAAM,KAAY,GAAG;AACtB,aAAO;AAAA,QACH,OAAO,WAAW,KAAK;AAAA,QACvB,WAAW,WAAW,KAAK,MAAM,SAAS,OAAO,EAAE;AAAA,QACnD,MAAM;AAAA,MACV;AAAA,IACJ;AAGA,QAAI,MAAM,MAAM,YAAY,GAAG;AAC3B,aAAO;AAAA,QACH,OAAO,2BAA2B,OAAO,QAAQ,OAAO,GAAG;AAAA,QAC3D,MAAM;AAAA,MACV;AAAA,IACJ;AAGA,WAAO;AAAA,MACH,OAAO;AAAA,MACP,MAAM;AAAA,IACV;AAAA,EACJ;AAQA,WAAS,cAAc,QAAkB,4BAAgD;AAErF,UAAM,aAA0B,CAAC;AAGjC,UAAM,kBAA4B,CAAC;AAGnC,QAAI,mBAAmB,oBAAoB,OAAO,MAAM,IAAI,YAAY;AAGxE,WAAO,kBAAkB;AAErB,UAAI,gBAAgB,QAAQ,OAAO,GAAG,YAAY,CAAC,MAAM,IAAI;AACzD,cAAM,IAAI,MAAM,wBAAwB,OAAO,GAAG,YAAY,mBAAmB;AAAA,MACrF;AAGA,sBAAgB,KAAK,OAAO,MAAM,EAAG,YAAY,CAAC;AAGlD,YAAM,qBAAqB,aAAa,QAAQ,0BAA0B;AAG1E,UAAI,mBAAmB,WAAW,KAAK,mBAAmB,GAAG,SAAS,cAAc;AAChF,cAAM,IAAI,MAAM,gEAAgE;AAAA,MACpF;AAGA,YAAM,wBAAwB,mBAAmB,MAAM;AAGvD,yBACK,OAAO,CAAC,QAAQ,IAAI,SAAS,YAAY,EACzC,QAAQ,CAAC,QAAQ;AACd,cAAM,IAAI;AAAA,UACN,uCAAuC,IAAI,QAAQ;AAAA,QACvD;AAAA,MACJ,CAAC;AAGL,iBAAW,KAAK,iBAAiB,sBAAsB,OAAO,kBAAkB,CAAC;AAGjF,yBAAmB,oBAAoB,OAAO,MAAM,IAAI,YAAY;AAAA,IACxE;AAEA,WAAO;AAAA,EACX;AAOA,WAAS,yBAAyB,YAGhC;AAEE,UAAM,eAAmC,CAAC;AAG1C,UAAM,sBAAsB,WAAW,QAAQ,sBAAsB,CAAC,UAAU;AAC5E,UAAI,gBAAgB,MAAM,UAAU,GAAG,MAAM,SAAS,CAAC;AACvD,UAAI,cAAc,OAAO,KAAK,YAAY,EAAE,KAAK,CAAC,QAAQ,aAAa,SAAS,aAAa;AAG7F,UAAI,CAAC,aAAa;AACd,sBAAc,KAAK,OAAO,KAAK,YAAY,EAAE;AAC7C,qBAAa,eAAe;AAAA,MAChC;AAEA,aAAO;AAAA,IACX,CAAC;AAED,WAAO,EAAE,cAAc,oBAAoB;AAAA,EAC/C;AAOA,WAAS,0BAA0B,YAA8B;AAE7D,iBAAa,WAAW,QAAQ,OAAO,KAAK;AAC5C,iBAAa,WAAW,QAAQ,OAAO,KAAK;AAC5C,iBAAa,WAAW,QAAQ,OAAO,KAAK;AAC5C,iBAAa,WAAW,QAAQ,OAAO,KAAK;AAC5C,iBAAa,WAAW,QAAQ,OAAO,KAAK;AAC5C,iBAAa,WAAW,QAAQ,OAAO,KAAK;AAC5C,iBAAa,WAAW,QAAQ,OAAO,KAAK;AAG5C,WAAO,WAAW,QAAQ,QAAQ,GAAG,EAAE,KAAK,EAAE,MAAM,GAAG;AAAA,EAC3D;;;ACrqCO,MAAM,gBAAN,MAAoB;AAAA,IAYvB,YAAY,YAA4B,OAAsB,UAAgC,CAAC,GAAG;AAA1D;AAAsB;AAE1D,UAAI,OAAO,eAAe,UAAU;AAChC,cAAM,IAAI,MAAM,sCAAsC;AAAA,MAC1D;AAGA,UAAI,OAAO,UAAU,YAAY,UAAU,MAAM;AAC7C,cAAM,IAAI,MAAM,wCAAwC;AAAA,MAC5D;AAGA,WAAK,WAAW,cAAc,gBAAgB,UAAU;AAAA,IAC5D;AAAA,IArBgB;AAAA,IA2BhB,YAAY;AACR,aAAO,KAAK,SAAS,SAAS;AAAA,IAClC;AAAA,IAMA,WAAW;AACP,aAAO,KAAK,SAAS,SAAS;AAAA,IAClC;AAAA,IAUA,OAAO;AAEH,UAAI,KAAK,SAAS,SAAS,iDAAyB,KAAK,SAAS,SAAS,yCAAoB;AAC3F,aAAK,SAAS,MAAM;AAAA,MACxB;AAEA,UAAI;AACA,aAAK,SAAS,OAAO,KAAK,OAAO,KAAK,OAAO;AAAA,MACjD,SAAS,WAAP;AACE,cAAM,IAAI,MAAM,wBAAyB,UAAoB,SAAS;AAAA,MAC1E;AAAA,IACJ;AAAA,IAKA,QAAQ;AACJ,WAAK,SAAS,MAAM;AAAA,IACxB;AAAA,IAMA,0BAA+C;AAE3C,YAAM,qBAA0C,CAAC;AAOjD,YAAM,cAAc,CAAC,MAAY,cAA6B;AAE1D,cAAM,SAAS,KACV,cAAc,EACd,OAAO,CAAC,cAAc,UAAU,QAAQ,CAAC,EACzC,IAAI,CAAC,cAAc,UAAU,WAAW,CAAC;AAC9C,cAAM,YAAY,KACb,cAAc,EACd,OAAO,CAAC,cAAc,CAAC,UAAU,QAAQ,CAAC,EAC1C,IAAI,CAAC,cAAc,UAAU,WAAW,CAAC;AAG9C,2BAAmB,KAAK;AAAA,UACpB,IAAI,KAAK,OAAO;AAAA,UAChB,MAAM,KAAK,QAAQ;AAAA,UACnB,SAAS,KAAK,QAAQ;AAAA,UACtB,OAAO,KAAK,SAAS;AAAA,UACrB;AAAA,UACA;AAAA,UACA,MAAM,KAAK,aAAa;AAAA,UACxB,UAAU;AAAA,QACd,CAAC;AAGD,YAAI,CAAC,KAAK,WAAW,GAAG;AACpB,UAAC,KACI,YAAY,EACZ,QAAQ,CAAC,UAAU,YAAY,OAAQ,KAA+B,OAAO,CAAC,CAAC;AAAA,QACxF;AAAA,MACJ;AAGA,kBAAY,KAAK,UAAU,IAAI;AAE/B,aAAO;AAAA,IACX;AAAA,IAOA,OAAO,SAAS,MAAc,OAAgC;AAC1D,UAAI,OAAO,UAAU,YAAY;AAE7B,eAAO,QAAQ,MAAM,KAAK;AAAA,MAC9B,WAAW,OAAO,UAAU,UAAU;AAElC,YAAI;AAEJ,YAAI;AAEA,yBAAe,kBAAkB,KAAK;AAAA,QAC1C,SAAS,WAAP;AAEE,gBAAM,IAAI,MAAM,iCAAkC,UAAoB,SAAS;AAAA,QACnF;AAGA,YAAI,aAAa,UAAU,KAAK,aAAa,GAAG,SAAS,MAAM;AAC3D,gBAAM,IAAI,MAAM,mEAAmE;AAAA,QACvF;AAEA,eAAO,WAAW,MAAM,aAAa,EAAE;AAAA,MAC3C,OAAO;AACH,cAAM,IAAI,MAAM,0DAA0D;AAAA,MAC9E;AAAA,IACJ;AAAA,IAMA,OAAO,WAAW,MAAoB;AAClC,aAAO,OAAO,IAAI;AAAA,IACtB;AAAA,IAKA,OAAO,gBAAsB;AACzB,aAAO,MAAM;AAAA,IACjB;AAAA,IAOA,OAAe,gBAAgB,YAA0B;AAErD,UAAI;AAAA,MAEJ,SAAS,WAAP;AACE,gBAAQ,IAAI,SAAS;AAAA,MACzB;AAEA,UAAI;AAEA,cAAM,eAAe,kBAAkB,UAAU;AAGjD,cAAM,kBAAkB,OAAO,UAAU;AAGzC,cAAM,cAAuD,CAAC;AAC9D,mBAAW,eAAe,cAAc;AACpC,sBAAY,YAAY,SAAS,OAAO,kBAAkB,YAAY,QAAS;AAAA,QACnF;AAGA,cAAM,WAAiB,YAAY,iBAAiB;AAAA,UAEhD,CAAC,SAA+B,YAAY,QAAQ,YAAY,QAAQ,OAAO,WAAW,IAAI;AAAA,UAC9F,CAAC;AAAA,QACL;AAGA,sBAAc,yBAAyB,QAAQ;AAG/C,eAAO;AAAA,MACX,SAAS,WAAP;AAEE,cAAM,IAAI,MAAM,uBAAwB,UAAoB,SAAS;AAAA,MACzE;AAAA,IACJ;AAAA,IAMA,OAAe,yBAAyB,UAAgB;AACpD,YAAM,YAAsB,CAAC;AAE7B,YAAM,gBAAgB,CAAC,MAAc,SAAe;AAEhD,eAAO,KAAK,OAAO,IAAI;AAGvB,YAAI,KAAK,WAAW,GAAG;AACnB,oBAAU,KAAK,IAAI;AAAA,QACvB,OAAO;AACH,UAAC,KAA+B,YAAY,EAAE,QAAQ,CAAC,UAAU,cAAc,MAAM,KAAK,CAAC;AAAA,QAC/F;AAAA,MACJ;AAGA,oBAAc,CAAC,GAAG,QAAQ;AAE1B,gBAAU,QAAQ,CAAC,SAAS;AAExB,iBAAS,QAAQ,GAAG,QAAQ,KAAK,QAAQ,SAAS;AAE9C,gBAAM,cAAc,KAAK;AAGzB,cAAI,YAAY,aAAa,GAAG;AAC5B;AAAA,UACJ;AAGA,gBAAM,YAAY,IAAI;AAAA,YAClB,KACK,MAAM,GAAG,QAAQ,CAAC,EAClB,IAAmB,CAAC,UAAU,EAAE,MAAM,QAAQ,KAAK,mBAAmB,EAAE,EAAE,EAC1E,OAAO,CAAC,YAAY,QAAQ,OAAO,SAAS,CAAC;AAAA,UACtD;AAGA,sBAAY,aAAa,SAAS;AAAA,QACtC;AAAA,MACJ,CAAC;AAAA,IACL;AAAA,EACJ;", "names": ["Participant", "Lotto", "createLotto", "State", "createLotto"] } diff --git a/dist/index.js.map b/dist/index.js.map index 4f0aab2..0ac0b53 100644 --- a/dist/index.js.map +++ b/dist/index.js.map @@ -1,7 +1,7 @@ { "version": 3, "sources": ["../node_modules/lotto-draw/dist/Participant.js", "../node_modules/lotto-draw/dist/Utilities.js", "../node_modules/lotto-draw/dist/Lotto.js", "../node_modules/lotto-draw/dist/createLotto.js", "../node_modules/lotto-draw/dist/index.js", "../src/index.ts", "../src/attributes/guards/GuardUnsatisifedException.ts", "../src/attributes/guards/GuardPath.ts", "../src/State.ts", "../src/nodes/Node.ts", "../src/nodes/leaf/Leaf.ts", "../src/Lookup.ts", "../src/nodes/leaf/Action.ts", "../src/nodes/leaf/Condition.ts", "../src/nodes/leaf/Wait.ts", "../src/nodes/decorator/Decorator.ts", "../src/nodes/decorator/Root.ts", "../src/nodes/decorator/Repeat.ts", "../src/nodes/decorator/Retry.ts", "../src/nodes/decorator/Flip.ts", "../src/nodes/decorator/Succeed.ts", "../src/nodes/decorator/Fail.ts", "../src/nodes/composite/Lotto.ts", "../src/nodes/composite/Composite.ts", "../src/nodes/composite/Selector.ts", "../src/nodes/composite/Sequence.ts", "../src/nodes/composite/Parallel.ts", "../src/attributes/Attribute.ts", "../src/attributes/guards/Guard.ts", "../src/attributes/guards/While.ts", "../src/attributes/guards/Until.ts", "../src/attributes/callbacks/Callback.ts", "../src/attributes/callbacks/Entry.ts", "../src/attributes/callbacks/Exit.ts", "../src/attributes/callbacks/Step.ts", "../src/RootAstNodesBuilder.ts", "../src/BehaviourTree.ts"], - "sourcesContent": ["\"use strict\";\r\nObject.defineProperty(exports, \"__esModule\", { value: true });\r\nexports.Participant = void 0;\r\n/**\r\n * A participant that holds a number of tickets.\r\n */\r\nvar Participant = /** @class */ (function () {\r\n /**\r\n * Creates an instance of the Participant class.\r\n * @param participant The actual participant.\r\n * @param tickets The number of tickets held by the participant.\r\n */\r\n function Participant(participant, tickets) {\r\n if (tickets === void 0) { tickets = 1; }\r\n this._participant = participant;\r\n this._tickets = tickets;\r\n }\r\n Object.defineProperty(Participant.prototype, \"participant\", {\r\n /** Gets the actual participant. */\r\n get: function () {\r\n return this._participant;\r\n },\r\n enumerable: false,\r\n configurable: true\r\n });\r\n Object.defineProperty(Participant.prototype, \"tickets\", {\r\n /** Gets or sets the number of tickets held by the participant. */\r\n get: function () {\r\n return this._tickets;\r\n },\r\n set: function (value) {\r\n this._tickets = value;\r\n },\r\n enumerable: false,\r\n configurable: true\r\n });\r\n return Participant;\r\n}());\r\nexports.Participant = Participant;\r\n", "\"use strict\";\r\nObject.defineProperty(exports, \"__esModule\", { value: true });\r\nexports.isNaturalNumber = exports.isNullOrUndefined = void 0;\r\n/**\r\n * Gets whether the value provided is null or undefined.\r\n * @param value The value to check.\r\n * @returns Whether the value provided is null or undefined.\r\n */\r\nfunction isNullOrUndefined(value) {\r\n return value === null || value === undefined;\r\n}\r\nexports.isNullOrUndefined = isNullOrUndefined;\r\n/**\r\n * Gets whether the value provided is a natural number.\r\n * @param value The value to check.\r\n * @returns Whether the value provided is a natural number.\r\n */\r\nfunction isNaturalNumber(value) {\r\n return typeof value === \"number\" && value >= 1 && Math.floor(value) === value;\r\n}\r\nexports.isNaturalNumber = isNaturalNumber;\r\n", "\"use strict\";\r\nObject.defineProperty(exports, \"__esModule\", { value: true });\r\nexports.Lotto = void 0;\r\nvar Participant_1 = require(\"./Participant\");\r\nvar Utilities_1 = require(\"./Utilities\");\r\n/**\r\n * Represents a lotto consisting of a number of pickable ticket-holding participants.\r\n */\r\nvar Lotto = /** @class */ (function () {\r\n /**\r\n * Creates a new instance of Lotto.\r\n * @param customRandom The custom RNG to use in place of Math.random().\r\n */\r\n function Lotto(customRandom) {\r\n /** The array of participants that are holding tickets in the lotto. */\r\n this._participants = [];\r\n this._customRandom = customRandom;\r\n }\r\n /**\r\n * Adds a participant with the specified number of tickets, or adds to the participant ticket count if the participant already holds tickets.\r\n * @param participant The participant to add or to increase the ticket count for if they already hold tickets.\r\n * @param tickets The number of tickets, defaults to 1.\r\n * @returns The Lotto instance.\r\n */\r\n Lotto.prototype.add = function (participant, tickets) {\r\n if (tickets === void 0) { tickets = 1; }\r\n // Check that we have a valid ticket count.\r\n if (!(0, Utilities_1.isNaturalNumber)(tickets)) {\r\n throw new Error(\"tickets value must be a natural number\");\r\n }\r\n // Check whether this participant has already been added.\r\n var existingParticipant = this._participants.find(function (part) { return part.participant === participant; });\r\n if (existingParticipant) {\r\n // The participant has already been added to the lotto so just add to their ticket count.\r\n existingParticipant.tickets += tickets;\r\n }\r\n else {\r\n // The participant is not part of the lotto so we should add them.\r\n this._participants.push(new Participant_1.Participant(participant, tickets));\r\n }\r\n return this;\r\n };\r\n /**\r\n * Removes the specified number of tickets for the given participant from the draw, or all tickets if a ticket number is not defined.\r\n * @param participant The participant to remove tickets for.\r\n * @param tickets The number of tickets to remove, or undefined if all tickets are to be removed.\r\n * @returns The Lotto instance.\r\n */\r\n Lotto.prototype.remove = function (participant, tickets) {\r\n // Attempt to get the existing participant.\r\n var existingParticipant = this._participants.find(function (part) { return part.participant === participant; });\r\n // There is nothing to do if the specified participant isn't even part of the lotto.\r\n if (!existingParticipant) {\r\n return this;\r\n }\r\n // Check whether a tickets value was given.\r\n if (tickets !== undefined) {\r\n // Check that we have a valid ticket count.\r\n if (!(0, Utilities_1.isNaturalNumber)(tickets)) {\r\n throw new Error(\"tickets value must be a natural number\");\r\n }\r\n existingParticipant.tickets -= tickets;\r\n // If the participant no longer holds any tickets then they should be removed.\r\n if (existingParticipant.tickets < 1) {\r\n this._participants = this._participants.filter(function (part) { return part !== existingParticipant; });\r\n }\r\n }\r\n else {\r\n // We are removing all tickets for the participant so just remove them from the lotto.\r\n this._participants = this._participants.filter(function (part) { return part !== existingParticipant; });\r\n }\r\n return this;\r\n };\r\n /**\r\n * Draw a winning ticket and return the participant that holds the ticket.\r\n * @param options The draw options.\r\n * @returns The participant that holds the winning ticket.\r\n */\r\n Lotto.prototype.draw = function (options) {\r\n if (options === void 0) { options = {}; }\r\n // If we have no participants then just return null.\r\n if (this._participants.length === 0) {\r\n return null;\r\n }\r\n var redrawable = (0, Utilities_1.isNullOrUndefined)(options.redrawable) ? true : options.redrawable;\r\n var pickable = [];\r\n this._participants.forEach(function (_a) {\r\n var participant = _a.participant, tickets = _a.tickets;\r\n for (var ticketCount = 0; ticketCount < tickets; ticketCount++) {\r\n pickable.push(participant);\r\n }\r\n });\r\n var random;\r\n // We need a random floating-point number between 0 (inclusive) and 1 to scale up to pick our winner.\r\n // If a custom random function exists then we should use that or fall back to Math.random().\r\n if (this._customRandom) {\r\n // Call our custom random function to get a random floating-point number.\r\n random = this._customRandom();\r\n // Verify that the result of calling our custom random function is a number between 0 (inclusive) and 1.\r\n if (typeof random !== \"number\" || random < 0 || random >= 1) {\r\n throw new Error(\"the 'random' function provided did not return a number between 0 (inclusive) and 1\");\r\n }\r\n }\r\n else {\r\n // No custom random function was defined so just use good ol' Math.random().\r\n random = Math.random();\r\n }\r\n // Pick a winning participant.\r\n var winner = pickable[Math.floor(random * pickable.length)];\r\n // If the ticket isn't redrawable then we should remove a ticket from the winning participants ticket count.\r\n if (!redrawable) {\r\n this.remove(winner, 1);\r\n }\r\n // Return the winning participant.\r\n return winner;\r\n };\r\n /**\r\n * Draws multiple winning tickets and return an array of the participants that hold the winning tickets.\r\n * @param tickets The number of winning tickets to draw.\r\n * @param options The draw multiple options.\r\n * @returns An array of the participants that hold the winning tickets.\r\n */\r\n Lotto.prototype.drawMultiple = function (tickets, options) {\r\n if (options === void 0) { options = {}; }\r\n var uniqueResults = (0, Utilities_1.isNullOrUndefined)(options.unique) ? false : options.unique;\r\n // Handle cases where the user has asked for zero tickets (no idea why they would do this be we should trust them).\r\n if (tickets === 0) {\r\n return [];\r\n }\r\n // Now that we know out tickets value is not zero we should check that it is a valid natural number.\r\n if (!(0, Utilities_1.isNaturalNumber)(tickets)) {\r\n throw new Error(\"tickets value must be a natural number\");\r\n }\r\n var result = [];\r\n // Keep drawing tickets until we either reach the number of required tickets or we simply run out of tickets to draw.\r\n // We can run out of tickets to draw if 'options.redrawable' is explicity 'false' or we just had no participants when 'drawMultiple' was called.\r\n while (result.length < tickets && this._participants.length > 0) {\r\n result.push(this.draw(options));\r\n }\r\n // If the 'unique' draw option is set then we need to remove duplicates from the result list.\r\n if (uniqueResults) {\r\n // Create an array to store our unique results.\r\n var unique = [];\r\n // Iterate over all of our participants (with potential duplicates) and populate our array of unique values.\r\n for (var _i = 0, result_1 = result; _i < result_1.length; _i++) {\r\n var participant = result_1[_i];\r\n if (unique.indexOf(participant) === -1) {\r\n unique.push(participant);\r\n }\r\n }\r\n result = unique;\r\n }\r\n return result;\r\n };\r\n return Lotto;\r\n}());\r\nexports.Lotto = Lotto;\r\n", "\"use strict\";\r\nObject.defineProperty(exports, \"__esModule\", { value: true });\r\nexports.createLotto = void 0;\r\nvar Lotto_1 = require(\"./Lotto\");\r\n/**\r\n * A function that creates and returns a Lotto instance.\r\n * @param participantsOrOptions An array of initial participants or options relating to the creation of a Lotto instance.\r\n * @returns A new Lotto instance.\r\n */\r\nfunction createLotto(participantsOrOptions) {\r\n // If no initial participants or lotto options were provided as an argument then we can just return a new lotto instance now.\r\n if (!participantsOrOptions) {\r\n return new Lotto_1.Lotto();\r\n }\r\n // Check whether we were provided with an array of initial participants or a lotto options object.\r\n if (Array.isArray(participantsOrOptions)) {\r\n // We are dealing with a pre-defined array of participants.\r\n var participants = participantsOrOptions;\r\n var lotto_1 = new Lotto_1.Lotto();\r\n // If the lotto participants have been defined upfront then we will need to add them all to our lotto instance now.\r\n participants.forEach(function (_a) {\r\n var participant = _a[0], tokens = _a[1];\r\n return lotto_1.add(participant, tokens);\r\n });\r\n // Return the Lotto instance.\r\n return lotto_1;\r\n }\r\n else {\r\n // We are dealing with some lotto options.\r\n var random = participantsOrOptions.random, participants = participantsOrOptions.participants;\r\n // Create a Lotto instance passing the custom RNG function to use in place of Math.random() (which could be undefined).\r\n var lotto_2 = new Lotto_1.Lotto(random);\r\n // If the lotto participants have been defined upfront as part of the options then we will need to add them all to our lotto instance now.\r\n if (participants) {\r\n participants.forEach(function (_a) {\r\n var participant = _a[0], tokens = _a[1];\r\n return lotto_2.add(participant, tokens);\r\n });\r\n }\r\n // Return the Lotto instance.\r\n return lotto_2;\r\n }\r\n}\r\nexports.createLotto = createLotto;\r\n", "\"use strict\";\r\nObject.defineProperty(exports, \"__esModule\", { value: true });\r\nvar createLotto_1 = require(\"./createLotto\");\r\nexports.default = createLotto_1.createLotto;\r\n", "import { BehaviourTree, FlattenedTreeNode } from \"./BehaviourTree\";\nimport State from \"./State\";\n\nexport { BehaviourTree, State };\nexport type { FlattenedTreeNode };\n", "import Node from \"../../nodes/Node\";\n\n/**\n * An exception thrown when evaluating node guard path conditions and a conditions fails.\n */\nexport default class GuardUnsatisifedException extends Error {\n /**\n * @param source The node at which a guard condition failed.\n */\n constructor(private source: Node) {\n super(\"A guard path condition has failed\");\n }\n\n /**\n * Gets whether the specified node is the node at which a guard condition failed.\n * @param node The node to check against the source node.\n * @returns Whether the specified node is the node at which a guard condition failed.\n */\n isSourceNode = (node: Node) => node === this.source;\n}\n", "import { Agent } from \"../../Agent\";\nimport Guard from \"./Guard\";\nimport Node from \"../../nodes/Node\";\nimport GuardUnsatisifedException from \"./GuardUnsatisifedException\";\n\nexport type GuardPathPart = {\n node: Node;\n guards: Guard[];\n};\n\n/**\n * Represents a path of node guards along a root-to-leaf tree path.\n */\nexport default class GuardPath {\n /**\n * @param nodes An array of objects defining a node instance -> guard link, ordered by node depth.\n */\n constructor(private nodes: GuardPathPart[]) {}\n\n /**\n * Evaluate guard conditions for all guards in the tree path, moving outwards from the root.\n * @param agent The agent, required for guard evaluation.\n * @returns An evaluation results object.\n */\n evaluate = (agent: Agent) => {\n // We need to evaluate guard conditions for nodes up the tree, moving outwards from the root.\n for (const details of this.nodes) {\n // There can be multiple guards per node.\n for (const guard of details.guards) {\n // Check whether the guard condition passes, and throw an exception if not.\n if (!guard.isSatisfied(agent)) {\n throw new GuardUnsatisifedException(details.node);\n }\n }\n }\n };\n}\n", "/**\n * Enumeration of node state types.\n */\nexport enum State {\n READY = \"mistreevous.ready\",\n RUNNING = \"mistreevous.running\",\n SUCCEEDED = \"mistreevous.succeeded\",\n FAILED = \"mistreevous.failed\"\n}\n\nexport { State as default };\n\nexport type CompleteState = State.SUCCEEDED | State.FAILED;\nexport type AnyState = State.READY | State.RUNNING | CompleteState;\n", "import { Agent } from \"../Agent\";\nimport Attribute from \"../attributes/Attribute\";\nimport Entry from \"../attributes/callbacks/Entry\";\nimport Exit from \"../attributes/callbacks/Exit\";\nimport Step from \"../attributes/callbacks/Step\";\nimport Guard from \"../attributes/guards/Guard\";\nimport GuardPath from \"../attributes/guards/GuardPath\";\nimport GuardUnsatisifedException from \"../attributes/guards/GuardUnsatisifedException\";\nimport { BehaviourTreeOptions } from \"../BehaviourTreeOptions\";\nimport { AnyArgument } from \"../RootAstNodesBuilder\";\nimport State, { AnyState } from \"../State\";\nimport Leaf from \"./leaf/Leaf\";\n\n/**\n * A base node.\n */\nexport default abstract class Node {\n /**\n * The node uid.\n */\n private readonly uid: string = createNodeUid();\n /**\n * The node state.\n */\n private state: AnyState = State.READY;\n /**\n * The guard path to evaluate as part of a node update.\n */\n private guardPath: GuardPath | undefined;\n\n /**\n * @param type The node type.\n * @param attributes The node attributes.\n * @param args The node argument definitions.\n */\n constructor(private type: string, private attributes: Attribute[], private args: AnyArgument[]) {}\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected abstract onUpdate(agent: Agent, options: BehaviourTreeOptions): void;\n\n /**\n * Gets the name of the node.\n */\n public abstract getName(): string;\n\n /**\n * Gets whether this node is a leaf node.\n */\n public abstract isLeafNode: () => this is Leaf;\n\n /**\n * Gets/Sets the state of the node.\n */\n getState = (): AnyState => this.state;\n setState = (value: AnyState): void => {\n this.state = value;\n };\n\n /**\n * Gets the unique id of the node.\n */\n getUid = () => this.uid;\n\n /**\n * Gets the type of the node.\n */\n getType = () => this.type;\n\n /**\n * Gets the node attributes.\n */\n getAttributes = () => this.attributes;\n\n /**\n * Gets the node arguments.\n */\n getArguments = () => this.args;\n\n /**\n * Gets the node attribute with the specified type, or null if it does not exist.\n */\n getAttribute(type: \"entry\" | \"ENTRY\"): Entry;\n getAttribute(type: \"exit\" | \"EXIT\"): Exit;\n getAttribute(type: \"step\" | \"STEP\"): Step;\n getAttribute(type: string): Attribute {\n return (\n this.getAttributes().filter((decorator) => decorator.getType().toUpperCase() === type.toUpperCase())[0] ||\n null\n );\n }\n\n /**\n * Gets the node attributes.\n */\n getGuardAttributes = (): Guard[] => this.getAttributes().filter((decorator) => decorator.isGuard()) as Guard[];\n\n /**\n * Sets the guard path to evaluate as part of a node update.\n */\n setGuardPath = (value: GuardPath) => (this.guardPath = value);\n\n /**\n * Gets whether a guard path is assigned to this node.\n */\n hasGuardPath = () => !!this.guardPath;\n\n /**\n * Gets whether this node is in the specified state.\n * @param value The value to compare to the node state.\n */\n public is(value: AnyState): boolean {\n return this.state === value;\n }\n\n /**\n * Reset the state of the node.\n */\n public reset(): void {\n this.setState(State.READY);\n }\n\n /**\n * Abort the running of this node.\n * @param agent The agent.\n */\n public abort(agent: Agent): void {\n // There is nothing to do if this node is not in the running state.\n if (!this.is(State.RUNNING)) {\n return;\n }\n\n // Reset the state of this node.\n this.reset();\n\n this.getAttribute(\"exit\")?.callAgentFunction(agent, false, true);\n }\n\n /**\n * Update the node.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n * @returns The result of the update.\n */\n public update(agent: Agent, options: BehaviourTreeOptions): void {\n // If this node is already in a 'SUCCEEDED' or 'FAILED' state then there is nothing to do.\n if (this.is(State.SUCCEEDED) || this.is(State.FAILED)) {\n return;\n }\n\n try {\n // Evaluate all of the guard path conditions for the current tree path.\n this.guardPath!.evaluate(agent);\n\n // If this node is in the READY state then call the ENTRY for this node if it exists.\n if (this.is(State.READY)) {\n this.getAttribute(\"entry\")?.callAgentFunction(agent);\n }\n\n this.getAttribute(\"step\")?.callAgentFunction(agent);\n\n // Do the actual update.\n this.onUpdate(agent, options);\n\n // If this node is now in a 'SUCCEEDED' or 'FAILED' state then call the EXIT for this node if it exists.\n if (this.is(State.SUCCEEDED) || this.is(State.FAILED)) {\n this.getAttribute(\"exit\")?.callAgentFunction(agent, this.is(State.SUCCEEDED), false);\n }\n } catch (error) {\n // If the error is a GuardUnsatisfiedException then we need to determine if this node is the source.\n if (error instanceof GuardUnsatisifedException && error.isSourceNode(this)) {\n // Abort the current node.\n this.abort(agent);\n\n // Any node that is the source of an abort will be a failed node.\n this.setState(State.FAILED);\n } else {\n throw error;\n }\n }\n }\n}\n\n/**\n * Create a randomly generated node uid.\n * @returns A randomly generated node uid.\n */\nfunction createNodeUid(): string {\n var S4 = function () {\n return (((1 + Math.random()) * 0x10000) | 0).toString(16).substring(1);\n };\n return S4() + S4() + \"-\" + S4() + \"-\" + S4() + \"-\" + S4() + \"-\" + S4() + S4() + S4();\n}\n", "import Node from \"../Node\";\n\n/**\n * A leaf node.\n */\nexport default abstract class Leaf extends Node {\n /**\n * Gets whether this node is a leaf node.\n */\n isLeafNode = () => true;\n}\n", "import { ActionResult, Agent, ExitFunctionArg, FunctionArg, GlobalFunction } from \"./Agent\";\nimport { AnyArgument, RootAstNode } from \"./RootAstNodesBuilder\";\n\n// Exit callbacks receive their own special type of argument.\n// There's probably stricter ways to represent this but it feels overly complex right now.\ntype ExitResultArg = { value: ExitFunctionArg };\nexport type AnyExitArgument = AnyArgument | ExitResultArg;\n\nexport type InvokerFunction = (args: AnyExitArgument[]) => ActionResult;\n\n/**\n * A singleton used to store and lookup registered functions and subtrees.\n */\nexport default class Lookup {\n /**\n * The object holding any registered functions keyed on function name.\n */\n private static functionTable: { [key: string]: GlobalFunction } = {};\n /**\n * The object holding any registered sub-trees keyed on tree name.\n */\n private static subtreeTable: { [key: string]: RootAstNode } = {};\n\n /**\n * Gets the function with the specified name.\n * @param name The name of the function.\n * @returns The function with the specified name.\n */\n public static getFunc(name: string): GlobalFunction {\n return this.functionTable[name];\n }\n\n /**\n * Sets the function with the specified name for later lookup.\n * @param name The name of the function.\n * @param func The function.\n */\n public static setFunc(name: string, func: GlobalFunction): void {\n this.functionTable[name] = func;\n }\n\n /**\n * Gets the function invoker for the specified agent and function name.\n * If a function with the specified name exists on the agent object then it will\n * be returned, otherwise we will then check the registered functions for a match.\n * @param agent The agent instance that this behaviour tree is modelling behaviour for.\n * @param name The function name.\n * @returns The function invoker for the specified agent and function name.\n */\n static getFuncInvoker(agent: Agent, name: string): InvokerFunction | null {\n // Check whether the agent contains the specified function.\n const foundOnAgent = agent[name];\n if (foundOnAgent && typeof foundOnAgent === \"function\") {\n return (args: AnyExitArgument[]): boolean | ActionResult =>\n foundOnAgent.apply(\n agent,\n args.map((arg) => arg.value)\n );\n }\n\n // The agent does not contain the specified function but it may have been registered at some point.\n if (this.functionTable[name] && typeof this.functionTable[name] === \"function\") {\n return (args: AnyExitArgument[]) => this.functionTable[name](agent, ...args.map((arg) => arg.value));\n }\n\n // We have no function to invoke.\n return null;\n }\n\n /**\n * Gets the subtree with the specified name.\n * @param name The name of the subtree.\n * @returns The subtree with the specified name.\n */\n static getSubtree(name: string): RootAstNode {\n return this.subtreeTable[name];\n }\n\n /**\n * Sets the subtree with the specified name for later lookup.\n * @param name The name of the subtree.\n * @param subtree The subtree.\n */\n static setSubtree(name: string, subtree: RootAstNode) {\n this.subtreeTable[name] = subtree;\n }\n\n /**\n * Removes the registered function or subtree with the specified name.\n * @param name The name of the registered function or subtree.\n */\n static remove(name: string) {\n delete this.functionTable[name];\n delete this.subtreeTable[name];\n }\n\n /**\n * Remove all registered functions and subtrees.\n */\n static empty() {\n this.functionTable = {};\n this.subtreeTable = {};\n }\n}\n", "import Leaf from \"./Leaf\";\nimport State, { CompleteState } from \"../../State\";\nimport Lookup from \"../../Lookup\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { AnyArgument } from \"../../RootAstNodesBuilder\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * An Action leaf node.\n * This represents an immediate or ongoing state of behaviour.\n */\nexport default class Action extends Leaf {\n /**\n * @param attributes The node attributes.\n * @param actionName The action name.\n * @param actionArguments The array of action argument definitions.\n */\n constructor(attributes: Attribute[], private actionName: string, private actionArguments: AnyArgument[]) {\n super(\"action\", attributes, actionArguments);\n }\n\n /**\n * Whether there is a pending update promise.\n */\n private isUsingUpdatePromise = false;\n\n /**\n * The finished state result of an update promise.\n */\n private updatePromiseStateResult: CompleteState | null = null;\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // If the result of this action depends on an update promise then there is nothing to do until\n // it resolves, unless there has been a value set as a result of the update promise resolving.\n if (this.isUsingUpdatePromise) {\n // Check whether the update promise has resolved with a state value.\n if (this.updatePromiseStateResult) {\n // Set the state of this node to match the state returned by the promise.\n this.setState(this.updatePromiseStateResult);\n }\n\n return;\n }\n\n // Attempt to get the invoker for the action function.\n const actionFuncInvoker = Lookup.getFuncInvoker(agent, this.actionName);\n\n // The action function should be defined.\n if (actionFuncInvoker === null) {\n throw new Error(\n `cannot update action node as the action '${this.actionName}' function is not defined on the agent and has not been registered`\n );\n }\n\n // Call the action function, the result of which may be:\n // - The finished state of this action node.\n // - A promise to return a finished node state.\n // - Undefined if the node should remain in the running state.\n const updateResult = actionFuncInvoker(this.actionArguments) as CompleteState | Promise;\n\n if (updateResult instanceof Promise) {\n updateResult.then(\n (result) => {\n // If 'isUpdatePromisePending' is null then the promise was cleared as it was resolving, probably via an abort of reset.\n if (!this.isUsingUpdatePromise) {\n return;\n }\n\n // Check to make sure the result is a valid finished state.\n if (result !== State.SUCCEEDED && result !== State.FAILED) {\n throw new Error(\n \"action node promise resolved with an invalid value, expected a State.SUCCEEDED or State.FAILED value to be returned\"\n );\n }\n\n // Set pending update promise state result to be processed on next update.\n this.updatePromiseStateResult = result;\n },\n (reason) => {\n // If 'isUpdatePromisePending' is null then the promise was cleared as it was resolving, probably via an abort of reset.\n if (!this.isUsingUpdatePromise) {\n return;\n }\n\n // Just throw whatever was returned as the rejection argument.\n throw new Error(reason);\n }\n );\n\n // This node will be in the 'RUNNING' state until the update promise resolves.\n this.setState(State.RUNNING);\n\n // We are now waiting for the promise returned by the use to resolve before we know what state this node is in.\n this.isUsingUpdatePromise = true;\n } else {\n // Validate the returned value.\n this.validateUpdateResult(updateResult);\n\n // Set the state of this node, this may be undefined, which just means that the node is still in the 'RUNNING' state.\n this.setState(updateResult || State.RUNNING);\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => this.actionName;\n\n /**\n * Reset the state of the node.\n */\n reset = () => {\n // Reset the state of this node.\n this.setState(State.READY);\n\n // There is no longer an update promise that we care about.\n this.isUsingUpdatePromise = false;\n this.updatePromiseStateResult = null;\n };\n\n /**\n * Validate the result of an update function call.\n * @param result The result of an update function call.\n */\n private validateUpdateResult = (result: CompleteState | boolean) => {\n switch (result) {\n case State.SUCCEEDED:\n case State.FAILED:\n case undefined:\n return;\n default:\n throw new Error(\n `action '${this.actionName}' 'onUpdate' returned an invalid response, expected an optional State.SUCCEEDED or State.FAILED value to be returned`\n );\n }\n };\n}\n", "import Leaf from \"./Leaf\";\nimport State from \"../../State\";\nimport Lookup from \"../../Lookup\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { AnyArgument } from \"../../RootAstNodesBuilder\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A Condition leaf node.\n * This will succeed or fail immediately based on an agent predicate, without moving to the 'RUNNING' state.\n */\nexport default class Condition extends Leaf {\n /**\n * @param attributes The node attributes.\n * @param conditionName The name of the condition function.\n * @param conditionArguments The array of condition argument definitions.\n */\n constructor(attributes: Attribute[], private conditionName: string, private conditionArguments: AnyArgument[]) {\n super(\"condition\", attributes, conditionArguments);\n }\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // Attempt to get the invoker for the condition function.\n const conditionFuncInvoker = Lookup.getFuncInvoker(agent, this.conditionName);\n\n // The condition function should be defined.\n if (conditionFuncInvoker === null) {\n throw new Error(\n `cannot update condition node as the condition '${this.conditionName}' function is not defined on the agent and has not been registered`\n );\n }\n\n // Call the condition function to determine the state of this node.\n this.setState(!!conditionFuncInvoker(this.conditionArguments) ? State.SUCCEEDED : State.FAILED);\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => this.conditionName;\n}\n", "import Leaf from \"./Leaf\";\nimport State from \"../../State\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { Agent } from \"../../Agent\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A WAIT node.\n * The state of this node will change to SUCCEEDED after a duration of time\n */\nexport default class Wait extends Leaf {\n /**\n * @param attributes The node attributes.\n * @param duration The duration that this node will wait to succeed in milliseconds.\n * @param durationMin The minimum possible duration in milliseconds that this node will wait to succeed.\n * @param durationMax The maximum possible duration in milliseconds that this node will wait to succeed.\n */\n constructor(\n attributes: Attribute[],\n private duration: number | null,\n private durationMin: number | null,\n private durationMax: number | null\n ) {\n super(\"wait\", attributes, []);\n }\n\n /**\n * The time in milliseconds at which this node was first updated.\n */\n private initialUpdateTime: number = 0;\n\n /**\n * The total duration in milliseconds that this node will be waiting for.\n */\n private totalDuration: number | null = null;\n\n /**\n * The duration in milliseconds that this node has been waiting for.\n */\n private waitedDuration: number = 0;\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // If this node is in the READY state then we need to set the initial update time.\n if (this.is(State.READY)) {\n // Set the initial update time.\n this.initialUpdateTime = new Date().getTime();\n\n // Set the initial waited duration.\n this.waitedDuration = 0;\n\n // Are we dealing with an explicit duration or will we be randomly picking a duration between the min and max duration.\n if (this.duration !== null) {\n this.totalDuration = this.duration;\n } else if (this.durationMin !== null && this.durationMax !== null) {\n // We will be picking a random duration between a min and max duration, if the optional 'random' behaviour tree\n // function option is defined then we will be using that, otherwise we will fall back to using Math.random.\n const random = typeof options.random === \"function\" ? options.random : Math.random;\n\n // Pick a random duration between a min and max duration.\n this.totalDuration = Math.floor(\n random() * (this.durationMax - this.durationMin + 1) + this.durationMin\n );\n } else {\n this.totalDuration = null;\n }\n\n // The node is now running until we finish waiting.\n this.setState(State.RUNNING);\n }\n\n // If we have no total duration then this wait node will wait indefinitely until it is aborted.\n if (this.totalDuration === null) {\n return;\n }\n\n // If we have a 'getDeltaTime' function defined as part of our options then we will use it to figure out how long we have waited for.\n if (typeof options.getDeltaTime === \"function\") {\n // Get the delta time.\n const deltaTime = options.getDeltaTime();\n\n // Our delta time must be a valid number and cannot be NaN.\n if (typeof deltaTime !== \"number\" || isNaN(deltaTime)) {\n throw new Error(\"The delta time must be a valid number and not NaN.\");\n }\n\n // Update the amount of time that this node has been waiting for based on the delta time.\n this.waitedDuration += deltaTime * 1000;\n } else {\n // We are not using a delta time, so we will just work out hom much time has passed since the first update.\n this.waitedDuration = new Date().getTime() - this.initialUpdateTime;\n }\n\n // Have we waited long enough?\n if (this.waitedDuration >= this.totalDuration) {\n // We have finished waiting!\n this.setState(State.SUCCEEDED);\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => {\n if (this.duration !== null) {\n return `WAIT ${this.duration}ms`;\n } else if (this.durationMin !== null && this.durationMax !== null) {\n return `WAIT ${this.durationMin}ms-${this.durationMax}ms`;\n } else {\n return \"WAIT\";\n }\n };\n}\n", "import Node from \"../Node\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\n\n/**\n * A decorator node that wraps a single child node.\n */\nexport default abstract class Decorator extends Node {\n /**\n * @param type The node type.\n * @param attributes The node attributes.\n * @param child The child node.\n */\n constructor(type: string, attributes: Attribute[], protected child: Node) {\n super(type, attributes, []);\n }\n\n /**\n * Gets whether this node is a leaf node.\n */\n isLeafNode = () => false;\n\n /**\n * Gets the children of this node.\n */\n getChildren = () => [this.child];\n\n /**\n * Reset the state of the node.\n */\n reset = () => {\n // Reset the state of this node.\n this.setState(State.READY);\n\n // Reset the state of the child node.\n this.child.reset();\n };\n\n /**\n * Abort the running of this node.\n * @param agent The agent.\n */\n abort = (agent: Agent) => {\n // There is nothing to do if this node is not in the running state.\n if (!this.is(State.RUNNING)) {\n return;\n }\n\n // Abort the child node.\n this.child.abort(agent);\n\n // Reset the state of this node.\n this.reset();\n\n this.getAttribute(\"exit\")?.callAgentFunction(agent, false, true);\n };\n}\n", "import Node from \"../Node\";\nimport Decorator from \"./Decorator\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A Root node.\n * The root node will have a single child.\n */\nexport default class Root extends Decorator {\n /**\n * @param attributes The node attributes.\n * @param child The child node.\n */\n constructor(attributes: Attribute[], child: Node) {\n super(\"root\", attributes, child);\n }\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // If the child has never been updated or is running then we will need to update it now.\n if (this.child.getState() === State.READY || this.child.getState() === State.RUNNING) {\n // Update the child of this node.\n this.child.update(agent, options);\n }\n\n // The state of the root node is the state of its child.\n this.setState(this.child.getState());\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => \"ROOT\";\n}\n", "import Node from \"../Node\";\nimport Decorator from \"./Decorator\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A REPEAT node.\n * The node has a single child which can have:\n * -- A number of iterations for which to repeat the child node.\n * -- An infinite repeat loop if neither an iteration count or a condition function is defined.\n * The REPEAT node will stop and have a 'FAILED' state if its child is ever in a 'FAILED' state after an update.\n * The REPEAT node will attempt to move on to the next iteration if its child is ever in a 'SUCCEEDED' state.\n */\nexport default class Repeat extends Decorator {\n /**\n * @param attributes The node attributes.\n * @param iterations The number of iterations to repeat the child node.\n * @param iterationsMin The minimum possible number of iterations to repeat the child node.\n * @param iterationsMax The maximum possible number of iterations to repeat the child node.\n * @param child The child node.\n */\n constructor(\n attributes: Attribute[],\n private iterations: number | null,\n private iterationsMin: number | null,\n private iterationsMax: number | null,\n child: Node\n ) {\n super(\"repeat\", attributes, child);\n }\n\n /**\n * The number of target iterations to make.\n */\n private targetIterationCount: number | null = null;\n\n /**\n * The current iteration count.\n */\n private currentIterationCount: number = 0;\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // If this node is in the READY state then we need to reset the child and the target iteration count.\n if (this.is(State.READY)) {\n // Reset the child node.\n this.child.reset();\n\n // Reset the current iteration count.\n this.currentIterationCount = 0;\n\n // Set the target iteration count.\n this.setTargetIterationCount(options);\n }\n\n // Do a check to see if we can iterate. If we can then this node will move into the 'RUNNING' state.\n // If we cannot iterate then we have hit our target iteration count, which means that the node has succeeded.\n if (this.canIterate()) {\n // This node is in the running state and can do its initial iteration.\n this.setState(State.RUNNING);\n\n // We may have already completed an iteration, meaning that the child node will be in the SUCCEEDED state.\n // If this is the case then we will have to reset the child node now.\n if (this.child.getState() === State.SUCCEEDED) {\n this.child.reset();\n }\n\n // Update the child of this node.\n this.child.update(agent, options);\n\n // If the child moved into the FAILED state when we updated it then there is nothing left to do and this node has also failed.\n // If it has moved into the SUCCEEDED state then we have completed the current iteration.\n if (this.child.getState() === State.FAILED) {\n // The child has failed, meaning that this node has failed.\n this.setState(State.FAILED);\n\n return;\n } else if (this.child.getState() === State.SUCCEEDED) {\n // We have completed an iteration.\n this.currentIterationCount += 1;\n }\n } else {\n // This node is in the 'SUCCEEDED' state as we cannot iterate any more.\n this.setState(State.SUCCEEDED);\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => {\n if (this.iterations !== null) {\n return `REPEAT ${this.iterations}x`;\n } else if (this.iterationsMin !== null && this.iterationsMax !== null) {\n return `REPEAT ${this.iterationsMin}x-${this.iterationsMax}x`;\n } else {\n return \"REPEAT\";\n }\n };\n\n /**\n * Reset the state of the node.\n */\n reset = () => {\n // Reset the state of this node.\n this.setState(State.READY);\n\n // Reset the current iteration count.\n this.currentIterationCount = 0;\n\n // Reset the child node.\n this.child.reset();\n };\n\n /**\n * Gets whether an iteration can be made.\n * @returns Whether an iteration can be made.\n */\n private canIterate = () => {\n if (this.targetIterationCount !== null) {\n // We can iterate as long as we have not reached our target iteration count.\n return this.currentIterationCount < this.targetIterationCount;\n }\n\n // If neither an iteration count or a condition function were defined then we can iterate indefinitely.\n return true;\n };\n\n /**\n * Sets the target iteration count.\n * @param options The behaviour tree options object.\n */\n private setTargetIterationCount = (options: BehaviourTreeOptions) => {\n // Are we dealing with an explicit iteration count or will we be randomly picking a iteration count between the min and max iteration count.\n if (this.iterations !== null) {\n this.targetIterationCount = this.iterations;\n } else if (this.iterationsMin !== null && this.iterationsMax !== null) {\n // We will be picking a random iteration count between a min and max iteration count, if the optional 'random'\n // behaviour tree function option is defined then we will be using that, otherwise we will fall back to using Math.random.\n const random = typeof options.random === \"function\" ? options.random : Math.random;\n\n // Pick a random iteration count between a min and max iteration count.\n this.targetIterationCount = Math.floor(\n random() * (this.iterationsMax - this.iterationsMin + 1) + this.iterationsMin\n );\n } else {\n this.targetIterationCount = null;\n }\n };\n}\n", "import Node from \"../Node\";\nimport Decorator from \"./Decorator\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A RETRY node.\n * The node has a single child which can have:\n * -- A number of iterations for which to repeat the child node.\n * -- An infinite repeat loop if neither an iteration count or a condition function is defined.\n * The RETRY node will stop and have a 'SUCCEEDED' state if its child is ever in a 'SUCCEEDED' state after an update.\n * The RETRY node will attempt to move on to the next iteration if its child is ever in a 'FAILED' state.\n */\nexport default class Retry extends Decorator {\n /**\n * @param attributes The node attributes.\n * @param attempts The number of attempts to retry the child node.\n * @param attemptsMin The minimum possible number of attempts to retry the child node.\n * @param attemptsMax The maximum possible number of attempts to retry the child node.\n * @param child The child node.\n */\n constructor(\n attributes: Attribute[],\n private attempts: number | null,\n private attemptsMin: number | null,\n private attemptsMax: number | null,\n child: Node\n ) {\n super(\"retry\", attributes, child);\n }\n\n /**\n * The number of target attempts to make.\n */\n private targetAttemptCount: number | null = null;\n\n /**\n * The current attempt count.\n */\n private currentAttemptCount: number = 0;\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // If this node is in the READY state then we need to reset the child and the target attempt count.\n if (this.is(State.READY)) {\n // Reset the child node.\n this.child.reset();\n\n // Reset the current attempt count.\n this.currentAttemptCount = 0;\n\n // Set the target attempt count.\n this.setTargetAttemptCount(options);\n }\n\n // Do a check to see if we can attempt. If we can then this node will move into the 'RUNNING' state.\n // If we cannot attempt then we have hit our target attempt count, which means that the node has succeeded.\n if (this.canAttempt()) {\n // This node is in the running state and can do its initial attempt.\n this.setState(State.RUNNING);\n\n // We may have already completed an attempt, meaning that the child node will be in the FAILED state.\n // If this is the case then we will have to reset the child node now.\n if (this.child.getState() === State.FAILED) {\n this.child.reset();\n }\n\n // Update the child of this node.\n this.child.update(agent, options);\n\n // If the child moved into the SUCCEEDED state when we updated it then there is nothing left to do and this node has also succeeded.\n // If it has moved into the FAILED state then we have completed the current attempt.\n if (this.child.getState() === State.SUCCEEDED) {\n // The child has succeeded, meaning that this node has succeeded.\n this.setState(State.SUCCEEDED);\n\n return;\n } else if (this.child.getState() === State.FAILED) {\n // We have completed an attempt.\n this.currentAttemptCount += 1;\n }\n } else {\n // This node is in the 'FAILED' state as we cannot iterate any more.\n this.setState(State.FAILED);\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => {\n if (this.attempts !== null) {\n return `RETRY ${this.attempts}x`;\n } else if (this.attemptsMin !== null && this.attemptsMax !== null) {\n return `RETRY ${this.attemptsMin}x-${this.attemptsMax}x`;\n } else {\n return \"RETRY\";\n }\n };\n\n /**\n * Reset the state of the node.\n */\n reset = () => {\n // Reset the state of this node.\n this.setState(State.READY);\n\n // Reset the current attempt count.\n this.currentAttemptCount = 0;\n\n // Reset the child node.\n this.child.reset();\n };\n\n /**\n * Gets whether an attempt can be made.\n * @returns Whether an attempt can be made.\n */\n canAttempt = () => {\n if (this.targetAttemptCount !== null) {\n // We can attempt as long as we have not reached our target attempt count.\n return this.currentAttemptCount < this.targetAttemptCount;\n }\n\n // If neither an attempt count or a condition function were defined then we can attempt indefinitely.\n return true;\n };\n\n /**\n * Sets the target attempt count.\n * @param options The behaviour tree options object.\n */\n setTargetAttemptCount = (options: BehaviourTreeOptions) => {\n // Are we dealing with an explicit attempt count or will we be randomly picking an attempt count between the min and max attempt count.\n if (this.attempts !== null) {\n this.targetAttemptCount = this.attempts;\n } else if (this.attemptsMin !== null && this.attemptsMax !== null) {\n // We will be picking a random attempt count between a min and max attempt count, if the optional 'random'\n // behaviour tree function option is defined then we will be using that, otherwise we will fall back to using Math.random.\n const random = typeof options.random === \"function\" ? options.random : Math.random;\n\n // Pick a random attempt count between a min and max attempt count.\n this.targetAttemptCount = Math.floor(\n random() * (this.attemptsMax - this.attemptsMin + 1) + this.attemptsMin\n );\n } else {\n this.targetAttemptCount = null;\n }\n };\n}\n", "import Decorator from \"./Decorator\";\nimport State from \"../../State\";\nimport Node from \"../Node\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A Flip node.\n * This node wraps a single child and will flip the state of the child state.\n */\nexport default class Flip extends Decorator {\n /**\n * @param attributes The node attributes.\n * @param child The child node.\n */\n constructor(attributes: Attribute[], child: Node) {\n super(\"flip\", attributes, child);\n }\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // If the child has never been updated or is running then we will need to update it now.\n if (this.child.getState() === State.READY || this.child.getState() === State.RUNNING) {\n this.child.update(agent, options);\n }\n\n // The state of this node will depend in the state of its child.\n switch (this.child.getState()) {\n case State.RUNNING:\n this.setState(State.RUNNING);\n break;\n\n case State.SUCCEEDED:\n this.setState(State.FAILED);\n break;\n\n case State.FAILED:\n this.setState(State.SUCCEEDED);\n break;\n\n default:\n this.setState(State.READY);\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => \"FLIP\";\n}\n", "import Node from \"../Node\";\nimport Decorator from \"./Decorator\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A Succeed node.\n * This node wraps a single child and will always move to the 'SUCCEEDED' state when the child moves to a 'SUCCEEDED' or 'FAILED' state.\n */\nexport default class Succeed extends Decorator {\n /**\n * @param attributes The node attributes.\n * @param child The child node.\n */\n constructor(attributes: Attribute[], child: Node) {\n super(\"succeed\", attributes, child);\n }\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // If the child has never been updated or is running then we will need to update it now.\n if (this.child.getState() === State.READY || this.child.getState() === State.RUNNING) {\n this.child.update(agent, options);\n }\n\n // The state of this node will depend in the state of its child.\n switch (this.child.getState()) {\n case State.RUNNING:\n this.setState(State.RUNNING);\n break;\n\n case State.SUCCEEDED:\n case State.FAILED:\n this.setState(State.SUCCEEDED);\n break;\n\n default:\n this.setState(State.READY);\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => \"SUCCEED\";\n}\n", "import Node from \"../Node\";\nimport Decorator from \"./Decorator\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A Fail node.\n * This node wraps a single child and will always move to the 'FAILED' state when the child moves to a 'SUCCEEDED' or 'FAILED' state.\n */\nexport default class Fail extends Decorator {\n /**\n * @param attributes The node attributes.\n * @param child The child node.\n */\n constructor(attributes: Attribute[], child: Node) {\n super(\"fail\", attributes, child);\n }\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // If the child has never been updated or is running then we will need to update it now.\n if (this.child.getState() === State.READY || this.child.getState() === State.RUNNING) {\n this.child.update(agent, options);\n }\n\n // The state of this node will depend in the state of its child.\n switch (this.child.getState()) {\n case State.RUNNING:\n this.setState(State.RUNNING);\n break;\n\n case State.SUCCEEDED:\n case State.FAILED:\n this.setState(State.FAILED);\n break;\n\n default:\n this.setState(State.READY);\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => \"FAIL\";\n}\n", "import createLotto from \"lotto-draw\";\n\nimport Node from \"../Node\";\nimport Composite from \"./Composite\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A LOTTO node.\n * A winning child is picked on the initial update of this node, based on ticket weighting.\n * The state of this node will match the state of the winning child.\n */\nexport default class Lotto extends Composite {\n /**\n * @param attributes The node attributes.\n * @param tickets The child node tickets.\n * @param children The child nodes.\n */\n constructor(attributes: Attribute[], private tickets: number[], children: Node[]) {\n super(\"lotto\", attributes, children);\n }\n\n /**\n * The child node selected to be the active one.\n */\n private selectedChild: Node | undefined;\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // If this node is in the READY state then we need to pick a winning child node.\n if (this.is(State.READY)) {\n // Create a lotto draw with which to randomly pick a child node to become the active one.\n const lottoDraw = createLotto({\n // Hook up the optional 'random' behaviour tree function option to the one used by 'lotto-draw'.\n random: options.random,\n // Pass in each child node as a participant in the lotto draw with their respective ticket count.\n participants: this.children.map((child, index) => [child, this.tickets[index] || 1])\n });\n\n // Randomly pick a child based on ticket weighting, this will become the active child for this composite node.\n this.selectedChild = lottoDraw.draw() || undefined;\n }\n\n // If something went wrong and we don't have an active child then we should throw an error.\n if (!this.selectedChild) {\n throw new Error(\"failed to update lotto node as it has no active child\");\n }\n\n // If the selected child has never been updated or is running then we will need to update it now.\n if (this.selectedChild.getState() === State.READY || this.selectedChild.getState() === State.RUNNING) {\n this.selectedChild.update(agent, options);\n }\n\n // The state of the lotto node is the state of its selected child.\n this.setState(this.selectedChild.getState());\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => (this.tickets.length ? `LOTTO [${this.tickets.join(\",\")}]` : \"LOTTO\");\n}\n", "import Node from \"../Node\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\n\n/**\n * A composite node that wraps child nodes.\n */\nexport default abstract class Composite extends Node {\n /**\n * @param type The node type.\n * @param attributes The node attributes.\n * @param children The child nodes.\n */\n constructor(type: string, attributes: Attribute[], protected children: Node[]) {\n super(type, attributes, []);\n }\n\n /**\n * Gets whether this node is a leaf node.\n */\n isLeafNode = () => false;\n\n /**\n * Gets the children of this node.\n */\n getChildren = () => this.children;\n\n /**\n * Reset the state of the node.\n */\n reset = () => {\n // Reset the state of this node.\n this.setState(State.READY);\n\n // Reset the state of any child nodes.\n this.getChildren().forEach((child) => child.reset());\n };\n\n /**\n * Abort the running of this node.\n * @param agent The agent.\n */\n abort = (agent: Agent) => {\n // There is nothing to do if this node is not in the running state.\n if (!this.is(State.RUNNING)) {\n return;\n }\n\n // Abort any child nodes.\n this.getChildren().forEach((child) => child.abort(agent));\n\n // Reset the state of this node.\n this.reset();\n\n this.getAttribute(\"exit\")?.callAgentFunction(agent, false, true);\n };\n}\n", "import Composite from \"./Composite\";\nimport Node from \"../Node\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A SELECTOR node.\n * The child nodes are executed in sequence until one succeeds or all fail.\n */\nexport default class Selector extends Composite {\n /**\n * @param attributes The node attributes.\n * @param children The child nodes.\n */\n constructor(attributes: Attribute[], protected children: Node[]) {\n super(\"selector\", attributes, children);\n }\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // Iterate over all of the children of this node.\n for (const child of this.children) {\n // If the child has never been updated or is running then we will need to update it now.\n if (child.getState() === State.READY || child.getState() === State.RUNNING) {\n // Update the child of this node.\n child.update(agent, options);\n }\n\n // If the current child has a state of 'SUCCEEDED' then this node is also a 'SUCCEEDED' node.\n if (child.getState() === State.SUCCEEDED) {\n // This node is a 'SUCCEEDED' node.\n this.setState(State.SUCCEEDED);\n\n // There is no need to check the rest of the selector nodes.\n return;\n }\n\n // If the current child has a state of 'FAILED' then we should move on to the next child.\n if (child.getState() === State.FAILED) {\n // Find out if the current child is the last one in the selector.\n // If it is then this sequence node has also failed.\n if (this.children.indexOf(child) === this.children.length - 1) {\n // This node is a 'FAILED' node.\n this.setState(State.FAILED);\n\n // There is no need to check the rest of the selector as we have completed it.\n return;\n } else {\n // The child node failed, try the next one.\n continue;\n }\n }\n\n // The node should be in the 'RUNNING' state.\n if (child.getState() === State.RUNNING) {\n // This node is a 'RUNNING' node.\n this.setState(State.RUNNING);\n\n // There is no need to check the rest of the selector as the current child is still running.\n return;\n }\n\n // The child node was not in an expected state.\n throw new Error(\"child node was not in an expected state.\");\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => \"SELECTOR\";\n}\n", "import Composite from \"./Composite\";\nimport Node from \"../Node\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A SEQUENCE node.\n * The child nodes are executed in sequence until one fails or all succeed.\n */\nexport default class Sequence extends Composite {\n /**\n * @param attributes The node attributes.\n * @param children The child nodes.\n */\n constructor(attributes: Attribute[], protected children: Node[]) {\n super(\"sequence\", attributes, children);\n }\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // Iterate over all of the children of this node.\n for (const child of this.children) {\n // If the child has never been updated or is running then we will need to update it now.\n if (child.getState() === State.READY || child.getState() === State.RUNNING) {\n // Update the child of this node.\n child.update(agent, options);\n }\n\n // If the current child has a state of 'SUCCEEDED' then we should move on to the next child.\n if (child.getState() === State.SUCCEEDED) {\n // Find out if the current child is the last one in the sequence.\n // If it is then this sequence node has also succeeded.\n if (this.children.indexOf(child) === this.children.length - 1) {\n // This node is a 'SUCCEEDED' node.\n this.setState(State.SUCCEEDED);\n\n // There is no need to check the rest of the sequence as we have completed it.\n return;\n } else {\n // The child node succeeded, but we have not finished the sequence yet.\n continue;\n }\n }\n\n // If the current child has a state of 'FAILED' then this node is also a 'FAILED' node.\n if (child.getState() === State.FAILED) {\n // This node is a 'FAILED' node.\n this.setState(State.FAILED);\n\n // There is no need to check the rest of the sequence.\n return;\n }\n\n // The node should be in the 'RUNNING' state.\n if (child.getState() === State.RUNNING) {\n // This node is a 'RUNNING' node.\n this.setState(State.RUNNING);\n\n // There is no need to check the rest of the sequence as the current child is still running.\n return;\n }\n\n // The child node was not in an expected state.\n throw new Error(\"child node was not in an expected state.\");\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => \"SEQUENCE\";\n}\n", "import Composite from \"./Composite\";\nimport State from \"../../State\";\nimport Node from \"../Node\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A PARALLEL node.\n * The child nodes are executed concurrently until one fails or all succeed.\n */\nexport default class Parallel extends Composite {\n /**\n * @param attributes The node attributes.\n * @param children The child nodes.\n */\n constructor(attributes: Attribute[], children: Node[]) {\n super(\"parallel\", attributes, children);\n }\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // Keep a count of the number of succeeded child nodes.\n let succeededCount = 0;\n\n let hasChildFailed = false;\n\n // Iterate over all of the children of this node.\n for (const child of this.children) {\n // If the child has never been updated or is running then we will need to update it now.\n if (child.getState() === State.READY || child.getState() === State.RUNNING) {\n // Update the child of this node.\n child.update(agent, options);\n }\n\n // If the current child has a state of 'SUCCEEDED' then we should move on to the next child.\n if (child.getState() === State.SUCCEEDED) {\n // The child node has succeeded, keep track of this to determine if all children have.\n succeededCount++;\n\n // The child node succeeded, but we have not finished checking every child node yet.\n continue;\n }\n\n // If the current child has a state of 'FAILED' then this node is also a 'FAILED' node.\n if (child.getState() === State.FAILED) {\n hasChildFailed = true;\n\n // There is no need to check the rest of the children.\n break;\n }\n\n // The node should be in the 'RUNNING' state.\n if (child.getState() !== State.RUNNING) {\n // The child node was not in an expected state.\n throw new Error(\"child node was not in an expected state.\");\n }\n }\n\n if (hasChildFailed) {\n // This node is a 'FAILED' node.\n this.setState(State.FAILED);\n\n // Abort every running child.\n for (const child of this.children) {\n if (child.getState() === State.RUNNING) {\n child.abort(agent);\n }\n }\n } else {\n // If all children have succeeded then this node has also succeeded, otherwise it is still running.\n this.setState(succeededCount === this.children.length ? State.SUCCEEDED : State.RUNNING);\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => \"PARALLEL\";\n}\n", "import { AnyArgument } from \"../RootAstNodesBuilder\";\nimport Guard from \"./guards/Guard\";\n\nexport type AttributeDetails = {\n /** The attribute type. */\n type: string;\n\n /** The attribute arguments. */\n args: AnyArgument[];\n};\n\n/**\n * A base node attribute.\n */\nexport default abstract class Attribute {\n /**\n * @param type The node attribute type.\n * @param args The array of attribute argument definitions.\n */\n constructor(protected type: string, protected args: AnyArgument[]) {}\n\n /**\n * Gets the type of the attribute.\n */\n getType = () => this.type;\n\n /**\n * Gets the array of attribute argument definitions.\n */\n getArguments = () => this.args;\n\n /**\n * Gets the attribute details.\n */\n abstract getDetails(): TAttributeDetails;\n\n /**\n * Gets whether this attribute is a guard.\n */\n abstract isGuard: () => this is Guard;\n}\n", "import { Agent } from \"../../Agent\";\nimport { AnyArgument } from \"../../RootAstNodesBuilder\";\nimport Attribute, { AttributeDetails } from \"../Attribute\";\n\nexport type GuardAttributeDetails = {\n /** The name of the condition function that determines whether the guard is satisfied. */\n condition: string;\n} & AttributeDetails;\n\n/**\n * A base node guard attribute.\n */\nexport default abstract class Guard extends Attribute {\n /**\n * @param type The node attribute type.\n * @param args The array of decorator argument definitions.\n * @param condition The name of the condition function that determines whether the guard is satisfied.\n */\n constructor(type: string, args: AnyArgument[], private condition: string) {\n super(type, args);\n }\n\n /**\n * Gets the name of the condition function that determines whether the guard is satisfied.\n */\n getCondition = () => this.condition;\n\n /**\n * Gets whether this attribute is a guard.\n */\n isGuard = () => true;\n\n /**\n * Gets the attribute details.\n */\n getDetails(): GuardAttributeDetails {\n return {\n type: this.getType(),\n args: this.getArguments(),\n condition: this.getCondition()\n };\n }\n\n /**\n * Gets whether the guard is satisfied.\n * @param agent The agent.\n * @returns Whether the guard is satisfied.\n */\n abstract isSatisfied(agent: Agent): boolean;\n}\n", "import Guard from \"./Guard\";\nimport Lookup from \"../../Lookup\";\nimport { Agent } from \"../../Agent\";\nimport { AnyArgument } from \"../../RootAstNodesBuilder\";\n\n/**\n * A WHILE guard which is satisfied as long as the given condition remains true.\n */\nexport default class While extends Guard {\n /**\n * @param condition The name of the condition function that determines whether the guard is satisfied.\n * @param args The array of decorator argument definitions.\n */\n constructor(condition: string, args: AnyArgument[]) {\n super(\"while\", args, condition);\n }\n\n /**\n * Gets whether the guard is satisfied.\n * @param agent The agent.\n * @returns Whether the guard is satisfied.\n */\n isSatisfied = (agent: Agent) => {\n // Attempt to get the invoker for the condition function.\n const conditionFuncInvoker = Lookup.getFuncInvoker(agent, this.getCondition());\n\n // The condition function should be defined.\n if (conditionFuncInvoker === null) {\n throw new Error(\n `cannot evaluate node guard as the condition '${this.getCondition()}' function is not defined on the agent and has not been registered`\n );\n }\n\n // Call the condition function to determine whether this guard is satisfied.\n return !!conditionFuncInvoker(this.args);\n };\n}\n", "import Guard from \"./Guard\";\nimport Lookup from \"../../Lookup\";\nimport { Agent } from \"../../Agent\";\nimport { AnyArgument } from \"../../RootAstNodesBuilder\";\n\n/**\n * An UNTIL guard which is satisfied as long as the given condition remains false.\n */\nexport default class Until extends Guard {\n /**\n * @param condition The name of the condition function that determines whether the guard is satisfied.\n * @param args The array of decorator argument definitions.\n */\n constructor(condition: string, args: AnyArgument[]) {\n super(\"until\", args, condition);\n }\n\n /**\n * Gets whether the guard is satisfied.\n * @param agent The agent.\n * @returns Whether the guard is satisfied.\n */\n isSatisfied = (agent: Agent) => {\n // Attempt to get the invoker for the condition function.\n const conditionFuncInvoker = Lookup.getFuncInvoker(agent, this.getCondition());\n\n // The condition function should be defined.\n if (conditionFuncInvoker === null) {\n throw new Error(\n `cannot evaluate node guard as the condition '${this.getCondition()}' function is not defined on the agent and has not been registered`\n );\n }\n\n // Call the condition function to determine whether this guard is satisfied.\n return !!!conditionFuncInvoker(this.args);\n };\n}\n", "import { Agent } from \"../../Agent\";\nimport { AnyArgument } from \"../../RootAstNodesBuilder\";\nimport Attribute, { AttributeDetails } from \"../Attribute\";\n\nexport type CallbackAttributeDetails = {\n /** The name of the agent function that is called. */\n functionName: string;\n} & AttributeDetails;\n\n/**\n * A base node callback attribute.\n */\nexport default abstract class Callback extends Attribute {\n /**\n * @param type The node attribute type.\n * @param args The array of decorator argument definitions.\n * @param functionName The name of the agent function to call.\n */\n constructor(type: string, args: AnyArgument[], private functionName: string) {\n super(type, args);\n }\n\n /**\n * Gets the name of the agent function to call.\n */\n getFunctionName = () => this.functionName;\n\n /**\n * Gets whether this attribute is a guard.\n */\n isGuard = () => false;\n\n /**\n * Gets the attribute details.\n */\n getDetails(): CallbackAttributeDetails {\n return {\n type: this.getType(),\n args: this.getArguments(),\n functionName: this.getFunctionName()\n };\n }\n\n /**\n * Attempt to call the agent function that this callback refers to.\n * @param agent The agent.\n */\n abstract callAgentFunction: (agent: Agent, isSuccess: boolean, isAborted: boolean) => void;\n}\n", "import Callback from \"./Callback\";\nimport Lookup from \"../../Lookup\";\nimport { Agent } from \"../../Agent\";\nimport { AnyArgument } from \"../../RootAstNodesBuilder\";\n\n/**\n * An ENTRY callback which defines an agent function to call when the associated node is updated and moves out of running state.\n */\nexport default class Entry extends Callback {\n /**\n * @param functionName The name of the agent function to call.\n * @param args The array of callback argument definitions.\n */\n constructor(functionName: string, args: AnyArgument[]) {\n super(\"entry\", args, functionName);\n }\n\n /**\n * Attempt to call the agent function that this callback refers to.\n * @param agent The agent.\n */\n callAgentFunction = (agent: Agent) => {\n // Attempt to get the invoker for the callback function.\n const callbackFuncInvoker = Lookup.getFuncInvoker(agent, this.getFunctionName());\n\n // The callback function should be defined.\n if (callbackFuncInvoker === null) {\n throw new Error(\n `cannot call entry function '${this.getFunctionName()}' as is not defined on the agent and has not been registered`\n );\n }\n\n // Call the callback function.\n callbackFuncInvoker(this.args);\n };\n}\n", "import Callback from \"./Callback\";\nimport Lookup, { AnyExitArgument } from \"../../Lookup\";\nimport { Agent } from \"../../Agent\";\nimport { AnyArgument } from \"../../RootAstNodesBuilder\";\n\n/**\n * An EXIT callback which defines an agent function to call when the associated node is updated and moves to a finished state or is aborted.\n */\nexport default class Exit extends Callback {\n /**\n * @param functionName The name of the agent function to call.\n * @param args The array of callback argument definitions.\n */\n constructor(functionName: string, args: AnyArgument[]) {\n super(\"exit\", args, functionName);\n }\n\n /**\n * Attempt to call the agent function that this callback refers to.\n * @param agent The agent.\n * @param isSuccess Whether the decorated node was left with a success state.\n * @param isAborted Whether the decorated node was aborted.\n */\n callAgentFunction = (agent: Agent, isSuccess: boolean, isAborted: boolean) => {\n // Attempt to get the invoker for the callback function.\n const callbackFuncInvoker = Lookup.getFuncInvoker(agent, this.getFunctionName());\n\n // The callback function should be defined.\n if (callbackFuncInvoker === null) {\n throw new Error(\n `cannot call exit function '${this.getFunctionName()}' as is not defined on the agent and has not been registered`\n );\n }\n\n // Call the callback function\n callbackFuncInvoker([{ value: { succeeded: isSuccess, aborted: isAborted } }, ...this.args]);\n };\n}\n", "import Callback from \"./Callback\";\nimport Lookup from \"../../Lookup\";\nimport { Agent } from \"../../Agent\";\nimport { AnyArgument } from \"../../RootAstNodesBuilder\";\n\n/**\n * A STEP callback which defines an agent function to call when the associated node is updated.\n */\nexport default class Step extends Callback {\n /**\n * @param functionName The name of the agent function to call.\n * @param args The array of callback argument definitions.\n */\n constructor(functionName: string, args: AnyArgument[]) {\n super(\"step\", args, functionName);\n }\n\n /**\n * Attempt to call the agent function that this callback refers to.\n * @param agent The agent.\n */\n callAgentFunction = (agent: Agent) => {\n // Attempt to get the invoker for the callback function.\n const callbackFuncInvoker = Lookup.getFuncInvoker(agent, this.getFunctionName());\n\n // The callback function should be defined.\n if (callbackFuncInvoker === null) {\n throw new Error(\n `cannot call step function '${this.getFunctionName()}' as is not defined on the agent and has not been registered`\n );\n }\n\n // Call the callback function.\n callbackFuncInvoker(this.args);\n };\n}\n", "import Action from \"./nodes/leaf/Action\";\nimport Condition from \"./nodes/leaf/Condition\";\nimport Wait from \"./nodes/leaf/Wait\";\nimport Root from \"./nodes/decorator/Root\";\nimport Repeat from \"./nodes/decorator/Repeat\";\nimport Retry from \"./nodes/decorator/Retry\";\nimport Flip from \"./nodes/decorator/Flip\";\nimport Succeed from \"./nodes/decorator/Succeed\";\nimport Fail from \"./nodes/decorator/Fail\";\nimport Lotto from \"./nodes/composite/Lotto\";\nimport Selector from \"./nodes/composite/Selector\";\nimport Sequence from \"./nodes/composite/Sequence\";\nimport Parallel from \"./nodes/composite/Parallel\";\nimport Node from \"./nodes/Node\";\nimport While from \"./attributes/guards/While\";\nimport Until from \"./attributes/guards/Until\";\nimport Entry from \"./attributes/callbacks/Entry\";\nimport Exit from \"./attributes/callbacks/Exit\";\nimport Step from \"./attributes/callbacks/Step\";\nimport Callback from \"./attributes/callbacks/Callback\";\nimport Guard from \"./attributes/guards/Guard\";\nimport Attribute from \"./attributes/Attribute\";\nimport Composite from \"./nodes/composite/Composite\";\nimport Decorator from \"./nodes/decorator/Decorator\";\nimport Leaf from \"./nodes/leaf/Leaf\";\n\nexport type Argument = {\n value: T;\n type: string; // Used for validation.\n};\ntype NullArgument = Argument & {\n type: \"null\";\n};\ntype BooleanArgument = Argument & {\n type: \"boolean\";\n};\ntype NumberArgument = Argument & {\n type: \"number\";\n isInteger: boolean; // Used for validation.\n};\ntype StringPlaceholderArgument = Argument & {\n type: \"string\";\n};\ntype IdentifierArgument = Argument & {\n type: \"identifier\";\n};\nexport type AnyArgument =\n | NullArgument\n | BooleanArgument\n | NumberArgument\n | StringPlaceholderArgument\n | IdentifierArgument;\n\n/**\n * The node attribute factories.\n */\nconst AttributeFactories: {\n [key: string]: (functionName: string, attributeArguments: AnyArgument[]) => Callback | Guard;\n} = {\n WHILE: (condition: string, attributeArguments: AnyArgument[]) => new While(condition, attributeArguments),\n UNTIL: (condition: string, attributeArguments: AnyArgument[]) => new Until(condition, attributeArguments),\n ENTRY: (functionName: string, attributeArguments: AnyArgument[]) => new Entry(functionName, attributeArguments),\n EXIT: (functionName: string, attributeArguments: AnyArgument[]) => new Exit(functionName, attributeArguments),\n STEP: (functionName: string, attributeArguments: AnyArgument[]) => new Step(functionName, attributeArguments)\n};\n\ntype Validatable = {\n children?: AstNode[];\n validate: (depth: number) => void;\n};\n\ntype NodeInstanceCreator = (\n namedRootNodeProvider: (name: string) => RootAstNode,\n visitedBranches: string[]\n) => T;\n\nexport type AstNode = Validatable & {\n type: string;\n createNodeInstance: NodeInstanceCreator;\n};\n\nexport type LeafAstNode = AstNode & {\n type: \"action\" | \"condition\" | \"wait\";\n attributes: Attribute[];\n};\n\nexport type CompositeAstNode = AstNode & {\n type: \"lotto\" | \"parallel\" | \"selector\" | \"sequence\";\n attributes: Attribute[];\n children: AstNode[];\n};\n\nexport type DecoratorAstNode = AstNode & {\n type: \"fail\" | \"flip\" | \"repeat\" | \"retry\" | \"root\" | \"succeed\";\n attributes: Attribute[];\n children: AstNode[];\n};\n\nexport type BranchAstNode = AstNode & {\n type: \"branch\";\n branchName: \"\" | string;\n};\n\nexport type LottoAstNode = CompositeAstNode & {\n type: \"lotto\";\n tickets: number[];\n};\n\nexport type RootAstNode = DecoratorAstNode & {\n type: \"root\";\n name: null | string;\n};\n\nexport type RepeatAstNode = DecoratorAstNode & {\n type: \"repeat\";\n iterations: number | null;\n iterationsMin: number | null;\n iterationsMax: number | null;\n};\n\nexport type RetryAstNode = DecoratorAstNode & {\n type: \"retry\";\n attempts: number | null;\n attemptsMin: number | null;\n attemptsMax: number | null;\n};\n\nexport type ActionAstNode = LeafAstNode & {\n type: \"action\";\n actionName: string;\n actionArguments: AnyArgument[];\n};\n\nexport type ConditionAstNode = LeafAstNode & {\n type: \"condition\";\n conditionName: string;\n conditionArguments: AnyArgument[];\n};\n\nexport type WaitAstNode = LeafAstNode & {\n type: \"wait\";\n duration: number | null;\n durationMin: number | null;\n durationMax: number | null;\n};\n\nexport type AnyAstNode =\n | BranchAstNode\n | CompositeAstNode\n | LottoAstNode\n | DecoratorAstNode\n | RootAstNode\n | RepeatAstNode\n | RetryAstNode\n | LeafAstNode\n | ActionAstNode\n | ConditionAstNode\n | WaitAstNode;\n\n/**\n * The AST node factories.\n */\nconst ASTNodeFactories = {\n ROOT: (): RootAstNode => ({\n type: \"root\",\n attributes: [],\n name: null,\n children: [],\n validate(depth: number) {\n // A root node cannot be the child of another node.\n if (depth > 1) {\n throw new Error(\"a root node cannot be the child of another node\");\n }\n\n // A root node must have a single child node.\n if (this.children.length !== 1) {\n throw new Error(\"a root node must have a single child\");\n }\n },\n createNodeInstance(namedRootNodeProvider, visitedBranches) {\n return new Root(\n this.attributes,\n this.children![0].createNodeInstance(namedRootNodeProvider, visitedBranches.slice())\n );\n }\n }),\n BRANCH: (): BranchAstNode => ({\n type: \"branch\",\n branchName: \"\",\n validate() {},\n createNodeInstance(namedRootNodeProvider, visitedBranches) {\n // Try to find the root node with a matching branch name.\n const targetRootNode = namedRootNodeProvider(this.branchName);\n\n // If we have already visited this branch then we have a circular dependency.\n if (visitedBranches.indexOf(this.branchName) !== -1) {\n throw new Error(`circular dependency found in branch node references for branch '${this.branchName}'`);\n }\n\n // If we have a target root node, then the node instance we want will be the first and only child of the referenced root node.\n if (targetRootNode) {\n return targetRootNode\n .createNodeInstance(namedRootNodeProvider, visitedBranches.concat(this.branchName))\n .getChildren()[0];\n } else {\n throw new Error(`branch references root node '${this.branchName}' which has not been defined`);\n }\n }\n }),\n SELECTOR: (): CompositeAstNode => ({\n type: \"selector\",\n attributes: [],\n children: [],\n validate() {\n // A selector node must have at least a single node.\n if (this.children.length < 1) {\n throw new Error(\"a selector node must have at least a single child\");\n }\n },\n createNodeInstance(namedRootNodeProvider, visitedBranches) {\n return new Selector(\n this.attributes,\n this.children.map((child) => child.createNodeInstance(namedRootNodeProvider, visitedBranches.slice()))\n );\n }\n }),\n SEQUENCE: (): CompositeAstNode => ({\n type: \"sequence\",\n attributes: [],\n children: [],\n validate() {\n // A sequence node must have at least a single node.\n if (this.children.length < 1) {\n throw new Error(\"a sequence node must have at least a single child\");\n }\n },\n createNodeInstance(namedRootNodeProvider, visitedBranches) {\n return new Sequence(\n this.attributes,\n this.children.map((child) => child.createNodeInstance(namedRootNodeProvider, visitedBranches.slice()))\n );\n }\n }),\n PARALLEL: (): CompositeAstNode => ({\n type: \"parallel\",\n attributes: [],\n children: [],\n validate() {\n // A parallel node must have at least a single node.\n if (this.children.length < 1) {\n throw new Error(\"a parallel node must have at least a single child\");\n }\n },\n createNodeInstance(namedRootNodeProvider, visitedBranches) {\n return new Parallel(\n this.attributes,\n this.children.map((child) => child.createNodeInstance(namedRootNodeProvider, visitedBranches.slice()))\n );\n }\n }),\n LOTTO: (): LottoAstNode => ({\n type: \"lotto\",\n attributes: [],\n children: [],\n tickets: [],\n validate() {\n // A lotto node must have at least a single node.\n if (this.children!.length < 1) {\n throw new Error(\"a lotto node must have at least a single child\");\n }\n },\n createNodeInstance(namedRootNodeProvider, visitedBranches) {\n return new Lotto(\n this.attributes,\n this.tickets!,\n this.children!.map((child) => child.createNodeInstance(namedRootNodeProvider, visitedBranches.slice()))\n );\n }\n }),\n REPEAT: (): RepeatAstNode => ({\n type: \"repeat\",\n attributes: [],\n iterations: null,\n iterationsMin: null,\n iterationsMax: null,\n children: [],\n validate() {\n // A repeat node must have a single node.\n if (this.children!.length !== 1) {\n throw new Error(\"a repeat node must have a single child\");\n }\n\n if (this.iterations !== null) {\n // A repeat node must have a positive number of iterations if defined.\n if (this.iterations < 0) {\n throw new Error(\"a repeat node must have a positive number of iterations if defined\");\n }\n } else if (this.iterationsMin !== null && this.iterationsMax !== null) {\n // A repeat node must have a positive min and max iteration count if they are defined.\n if (this.iterationsMin < 0 || this.iterationsMax < 0) {\n throw new Error(\n \"a repeat node must have a positive minimum and maximum iteration count if defined\"\n );\n }\n\n // A repeat node must not have an minimum iteration count that exceeds the maximum iteration count.\n if (this.iterationsMin > this.iterationsMax) {\n throw new Error(\n \"a repeat node must not have a minimum iteration count that exceeds the maximum iteration count\"\n );\n }\n } else {\n // If we have no explicit iteration count or a minimum and maximum iteration count set then we are dealing with a repeat node that iterates indefinitely.\n }\n },\n createNodeInstance(namedRootNodeProvider, visitedBranches) {\n return new Repeat(\n this.attributes,\n this.iterations,\n this.iterationsMin,\n this.iterationsMax,\n this.children![0].createNodeInstance(namedRootNodeProvider, visitedBranches.slice())\n );\n }\n }),\n RETRY: (): RetryAstNode => ({\n type: \"retry\",\n attributes: [],\n attempts: null,\n attemptsMin: null,\n attemptsMax: null,\n children: [],\n validate() {\n // A retry node must have a single node.\n if (this.children!.length !== 1) {\n throw new Error(\"a retry node must have a single child\");\n }\n\n if (this.attempts !== null) {\n // A retry node must have a positive number of attempts if defined.\n if (this.attempts < 0) {\n throw new Error(\"a retry node must have a positive number of attempts if defined\");\n }\n } else if (this.attemptsMin !== null && this.attemptsMax !== null) {\n // A retry node must have a positive min and max attempts count if they are defined.\n if (this.attemptsMin < 0 || this.attemptsMax < 0) {\n throw new Error(\"a retry node must have a positive minimum and maximum attempt count if defined\");\n }\n\n // A retry node must not have a minimum attempt count that exceeds the maximum attempt count.\n if (this.attemptsMin > this.attemptsMax) {\n throw new Error(\n \"a retry node must not have a minimum attempt count that exceeds the maximum attempt count\"\n );\n }\n } else {\n // If we have no explicit attempt count or a minimum and maximum attempt count set then we are dealing with a retry node that attempts indefinitely.\n }\n },\n createNodeInstance(namedRootNodeProvider, visitedBranches) {\n return new Retry(\n this.attributes,\n this.attempts,\n this.attemptsMin,\n this.attemptsMax,\n this.children![0].createNodeInstance(namedRootNodeProvider, visitedBranches.slice())\n );\n }\n }),\n FLIP: (): DecoratorAstNode => ({\n type: \"flip\",\n attributes: [],\n children: [],\n validate() {\n // A flip node must have a single node.\n if (this.children!.length !== 1) {\n throw new Error(\"a flip node must have a single child\");\n }\n },\n createNodeInstance(namedRootNodeProvider, visitedBranches) {\n return new Flip(\n this.attributes,\n this.children![0].createNodeInstance(namedRootNodeProvider, visitedBranches.slice())\n );\n }\n }),\n SUCCEED: (): DecoratorAstNode => ({\n type: \"succeed\",\n attributes: [],\n children: [],\n validate() {\n // A succeed node must have a single node.\n if (this.children!.length !== 1) {\n throw new Error(\"a succeed node must have a single child\");\n }\n },\n createNodeInstance(namedRootNodeProvider, visitedBranches) {\n return new Succeed(\n this.attributes,\n this.children![0].createNodeInstance(namedRootNodeProvider, visitedBranches.slice())\n );\n }\n }),\n FAIL: (): DecoratorAstNode => ({\n type: \"fail\",\n attributes: [],\n children: [],\n validate() {\n // A fail node must have a single node.\n if (this.children!.length !== 1) {\n throw new Error(\"a fail node must have a single child\");\n }\n },\n createNodeInstance(namedRootNodeProvider, visitedBranches) {\n return new Fail(\n this.attributes,\n this.children![0].createNodeInstance(namedRootNodeProvider, visitedBranches.slice())\n );\n }\n }),\n WAIT: (): WaitAstNode => ({\n type: \"wait\",\n attributes: [],\n duration: null,\n durationMin: null,\n durationMax: null,\n validate() {\n if (this.duration !== null) {\n // If an explict duration was defined then it must be a positive number.\n if (this.duration < 0) {\n throw new Error(\"a wait node must have a positive duration\");\n }\n } else if (this.durationMin !== null && this.durationMax !== null) {\n // A wait node must have a positive min and max duration.\n if (this.durationMin < 0 || this.durationMax < 0) {\n throw new Error(\"a wait node must have a positive minimum and maximum duration\");\n }\n\n // A wait node must not have a minimum duration that exceeds the maximum duration.\n if (this.durationMin > this.durationMax) {\n throw new Error(\"a wait node must not have a minimum duration that exceeds the maximum duration\");\n }\n } else {\n // If we have no explicit duration or duration bounds set then we are dealing with a wait node that waits indefinitely.\n }\n },\n createNodeInstance() {\n return new Wait(this.attributes, this.duration, this.durationMin, this.durationMax);\n }\n }),\n ACTION: (): ActionAstNode => ({\n type: \"action\",\n attributes: [],\n actionName: \"\",\n actionArguments: [],\n validate() {},\n createNodeInstance() {\n return new Action(this.attributes, this.actionName!, this.actionArguments!);\n }\n }),\n CONDITION: (): ConditionAstNode => ({\n type: \"condition\",\n attributes: [],\n conditionName: \"\",\n conditionArguments: [],\n validate() {},\n createNodeInstance() {\n return new Condition(this.attributes, this.conditionName!, this.conditionArguments!);\n }\n })\n};\n\ntype OtherAstNodes = AstNode[];\n\n/**\n * Create an array of root AST nodes based on the given definition.\n * @param definition The definition to parse the AST nodes from.\n * @returns The base definition AST nodes.\n */\nexport default function buildRootASTNodes(definition: string): RootAstNode[] {\n // Swap out any node/attribute argument string literals with a placeholder and get a mapping of placeholders to original values as well as the processed definition.\n const { placeholders, processedDefinition } = substituteStringLiterals(definition);\n\n // Convert the processed definition (with substituted string literals) into an array of raw tokens.\n const tokens = parseTokensFromDefinition(processedDefinition);\n\n // There must be at least 3 tokens for the tree definition to be valid. 'ROOT', '{' and '}'.\n if (tokens.length < 3) {\n throw new Error(\"invalid token count\");\n }\n\n // We should have a matching number of '{' and '}' tokens. If not, then there are scopes that have not been properly closed.\n if (tokens.filter((token) => token === \"{\").length !== tokens.filter((token) => token === \"}\").length) {\n throw new Error(\"scope character mismatch\");\n }\n\n // Create a stack of node children arrays, starting with a definition scope.\n const stack: [RootAstNode[], ...OtherAstNodes[]] = [[]];\n const rootScope = stack[0];\n\n // We should keep processing the raw tokens until we run out of them.\n while (tokens.length) {\n // Grab the next token.\n const token = tokens.shift();\n\n const currentScope = stack[stack.length - 1] as OtherAstNodes;\n\n // How we create the next AST token depends on the current raw token value.\n switch (token!.toUpperCase()) {\n case \"ROOT\": {\n // Create a ROOT AST node.\n const node = ASTNodeFactories.ROOT();\n\n // Push the ROOT node into the current scope.\n rootScope.push(node);\n\n // We may have a root node name defined as an argument.\n if (tokens[0] === \"[\") {\n const rootArguments = getArguments(tokens, placeholders);\n\n // We should have only a single argument that is not an empty string for a root node, which is the root name identifier.\n if (rootArguments.length === 1 && rootArguments[0].type === \"identifier\") {\n // The root name will be the first and only node argument.\n node.name = rootArguments[0].value as string;\n } else {\n throw new Error(\"expected single root name argument\");\n }\n }\n\n // Try to pick any attributes off of the token stack.\n node.attributes = getAttributes(tokens, placeholders);\n\n popAndCheck(tokens, \"{\");\n\n // The new scope is that of the new ROOT nodes children.\n stack.push(node.children!);\n break;\n }\n\n case \"BRANCH\": {\n // Create a BRANCH AST node.\n const node = ASTNodeFactories.BRANCH();\n\n // Push the BRANCH node into the current scope.\n currentScope.push(node);\n\n // We must have arguments defined, as we require a branch name argument.\n if (tokens[0] !== \"[\") {\n throw new Error(\"expected single branch name argument\");\n }\n\n // The branch name will be defined as a node argument.\n const branchArguments = getArguments(tokens, placeholders);\n\n // We should have only a single identifer argument for a branch node, which is the branch name.\n if (branchArguments.length === 1 && branchArguments[0].type === \"identifier\") {\n // The branch name will be the first and only node argument.\n node.branchName = branchArguments[0].value as string;\n } else {\n throw new Error(\"expected single branch name argument\");\n }\n break;\n }\n\n case \"SELECTOR\": {\n // Create a SELECTOR AST node.\n const node = ASTNodeFactories.SELECTOR();\n\n // Push the SELECTOR node into the current scope.\n currentScope.push(node);\n\n // Try to pick any attributes off of the token stack.\n node.attributes = getAttributes(tokens, placeholders);\n\n popAndCheck(tokens, \"{\");\n\n // The new scope is that of the new SELECTOR nodes children.\n stack.push(node.children!);\n break;\n }\n\n case \"SEQUENCE\": {\n // Create a SEQUENCE AST node.\n const node = ASTNodeFactories.SEQUENCE();\n\n // Push the SEQUENCE node into the current scope.\n currentScope.push(node);\n\n // Try to pick any attributes off of the token stack.\n node.attributes = getAttributes(tokens, placeholders);\n\n popAndCheck(tokens, \"{\");\n\n // The new scope is that of the new SEQUENCE nodes children.\n stack.push(node.children!);\n break;\n }\n\n case \"PARALLEL\": {\n // Create a PARALLEL AST node.\n const node = ASTNodeFactories.PARALLEL();\n\n // Push the PARALLEL node into the current scope.\n currentScope.push(node);\n\n // Try to pick any attributes off of the token stack.\n node.attributes = getAttributes(tokens, placeholders);\n\n popAndCheck(tokens, \"{\");\n\n // The new scope is that of the new PARALLEL nodes children.\n stack.push(node.children!);\n break;\n }\n\n case \"LOTTO\": {\n // Create a LOTTO AST node.\n const node = ASTNodeFactories.LOTTO();\n\n // Push the LOTTO node into the current scope.\n currentScope.push(node);\n\n // If the next token is a '[' character then some ticket counts have been defined as arguments.\n if (tokens[0] === \"[\") {\n // Get the ticket count arguments, each argument must be a number.\n node.tickets = getArguments(\n tokens,\n placeholders,\n (arg) => arg.type === \"number\" && !!arg.isInteger,\n \"lotto node ticket counts must be integer values\"\n ).map((argument) => argument.value as number);\n }\n\n // Try to pick any attributes off of the token stack.\n node.attributes = getAttributes(tokens, placeholders);\n\n popAndCheck(tokens, \"{\");\n\n // The new scope is that of the new LOTTO nodes children.\n stack.push(node.children!);\n break;\n }\n\n case \"CONDITION\": {\n // Create a CONDITION AST node.\n const node = ASTNodeFactories.CONDITION();\n\n // Push the CONDITION node into the current scope.\n currentScope.push(node);\n\n // We must have arguments defined, as we require a condition function name argument.\n if (tokens[0] !== \"[\") {\n throw new Error(\"expected condition name identifier argument\");\n }\n\n // Grab the condition node arguments.\n const conditionArguments = getArguments(tokens, placeholders);\n\n // We should have at least a single identifier argument for a condition node, which is the condition function name.\n if (conditionArguments.length && conditionArguments[0].type === \"identifier\") {\n // The condition function name will be the first node argument.\n node.conditionName = conditionArguments.shift()!.value as string;\n } else {\n throw new Error(\"expected condition name identifier argument\");\n }\n\n // Only the first argument should have been an identifier, all following arguments must be string, number, boolean or null.\n conditionArguments\n .filter((arg) => arg.type === \"identifier\")\n .forEach((arg) => {\n throw new Error(\n \"invalid condition node argument value '\" +\n arg.value +\n \"', must be string, number, boolean or null\"\n );\n });\n\n // Any node arguments that follow the condition name identifier will be treated as condition function arguments.\n node.conditionArguments = conditionArguments;\n\n // Try to pick any attributes off of the token stack.\n node.attributes = getAttributes(tokens, placeholders);\n break;\n }\n\n case \"FLIP\": {\n // Create a FLIP AST node.\n const node = ASTNodeFactories.FLIP();\n\n // Push the Flip node into the current scope.\n currentScope.push(node);\n\n // Try to pick any attributes off of the token stack.\n node.attributes = getAttributes(tokens, placeholders);\n\n popAndCheck(tokens, \"{\");\n\n // The new scope is that of the new FLIP nodes children.\n stack.push(node.children!);\n break;\n }\n\n case \"SUCCEED\": {\n // Create a SUCCEED AST node.\n const node = ASTNodeFactories.SUCCEED();\n\n // Push the Succeed node into the current scope.\n currentScope.push(node);\n\n // Try to pick any attributes off of the token stack.\n node.attributes = getAttributes(tokens, placeholders);\n\n popAndCheck(tokens, \"{\");\n\n // The new scope is that of the new Succeed nodes children.\n stack.push(node.children!);\n break;\n }\n\n case \"FAIL\": {\n // Create a FAIL AST node.\n const node = ASTNodeFactories.FAIL();\n\n // Push the Fail node into the current scope.\n currentScope.push(node);\n\n // Try to pick any attributes off of the token stack.\n node.attributes = getAttributes(tokens, placeholders);\n\n popAndCheck(tokens, \"{\");\n\n // The new scope is that of the new Fail nodes children.\n stack.push(node.children!);\n break;\n }\n\n case \"WAIT\": {\n // Create a WAIT AST node.\n const node = ASTNodeFactories.WAIT();\n\n // Push the WAIT node into the current scope.\n currentScope.push(node);\n\n // The arguments of a wait node are optional. We may have:\n // - No node arguments, in which case the wait will be indefinite until it is aborted.\n // - One node argument which will be the explicit duration of the wait.\n // - Two node arguments which define the min and max duration bounds from which a random duration will be picked.\n if (tokens[0] === \"[\") {\n // Get the optional duration and longest duration of the wait.\n const nodeArguments = getArguments(\n tokens,\n placeholders,\n (arg) => arg.type === \"number\" && !!arg.isInteger,\n \"wait node durations must be integer values\"\n ).map((argument) => argument.value);\n\n // We may have:\n // - One node argument which will be the explicit duration of the wait.\n // - Two node arguments which define the min and max duration bounds from which a random duration will be picked.\n // - Too many arguments, which is not valid.\n if (nodeArguments.length === 1) {\n // An explicit duration was defined.\n node.duration = nodeArguments[0] as number;\n } else if (nodeArguments.length === 2) {\n // Min and max duration bounds were defined from which a random duration will be picked.\n node.durationMin = nodeArguments[0] as number;\n node.durationMax = nodeArguments[1] as number;\n } else if (nodeArguments.length > 2) {\n // An incorrect number of durations was defined.\n throw new Error(\"invalid number of wait node duration arguments defined\");\n }\n }\n\n // Try to pick any attributes off of the token stack.\n node.attributes = getAttributes(tokens, placeholders);\n break;\n }\n\n case \"REPEAT\": {\n // Create a REPEAT AST node.\n const node = ASTNodeFactories.REPEAT();\n\n // Push the REPEAT node into the current scope.\n currentScope.push(node);\n\n // The arguments of a repeat node are optional. We may have:\n // - No node arguments, in which case the repeat note will iterate indefinitely.\n // - One node argument which will be the explicit number of iterations to make.\n // - Two node arguments which define the min and max iteration bounds from which a random iteration count will be picked.\n if (tokens[0] === \"[\") {\n // An iteration count has been defined. Get the iteration and potential maximum iteration of the wait.\n const nodeArguments = getArguments(\n tokens,\n placeholders,\n (arg) => arg.type === \"number\" && !!arg.isInteger,\n \"repeat node iteration counts must be integer values\"\n ).map((argument) => argument.value);\n\n // We should have got one or two iteration counts.\n if (nodeArguments.length === 1) {\n // A static iteration count was defined.\n node.iterations = nodeArguments[0] as number;\n } else if (nodeArguments.length === 2) {\n // A minimum and maximum iteration count was defined.\n node.iterationsMin = nodeArguments[0] as number;\n node.iterationsMax = nodeArguments[1] as number;\n } else {\n // An incorrect number of iteration counts was defined.\n throw new Error(\"invalid number of repeat node iteration count arguments defined\");\n }\n }\n\n // Try to pick any attributes off of the token stack.\n node.attributes = getAttributes(tokens, placeholders);\n\n popAndCheck(tokens, \"{\");\n\n // The new scope is that of the new REPEAT nodes children.\n stack.push(node.children!);\n break;\n }\n\n case \"RETRY\": {\n // Create a RETRY AST node.\n const node = ASTNodeFactories.RETRY();\n\n // Push the RETRY node into the current scope.\n currentScope.push(node);\n\n // The arguments of a retry node are optional. We may have:\n // - No node arguments, in which case the retry note will attempt indefinitely.\n // - One node argument which will be the explicit number of attempts to make.\n // - Two node arguments which define the min and max attempt bounds from which a random attempt count will be picked.\n if (tokens[0] === \"[\") {\n // An attempt count has been defined. Get the attempt count and potential maximum attempt count of the wait.\n const nodeArguments = getArguments(\n tokens,\n placeholders,\n (arg) => arg.type === \"number\" && !!arg.isInteger,\n \"retry node attempt counts must be integer values\"\n ).map((argument) => argument.value);\n\n // We should have got one or two attempt counts.\n if (nodeArguments.length === 1) {\n // A static attempt count was defined.\n node.attempts = nodeArguments[0] as number;\n } else if (nodeArguments.length === 2) {\n // A minimum and maximum attempt count was defined.\n node.attemptsMin = nodeArguments[0] as number;\n node.attemptsMax = nodeArguments[1] as number;\n } else {\n // An incorrect number of attempt counts was defined.\n throw new Error(\"invalid number of retry node attempt count arguments defined\");\n }\n }\n\n // Try to pick any attributes off of the token stack.\n node.attributes = getAttributes(tokens, placeholders);\n\n popAndCheck(tokens, \"{\");\n\n // The new scope is that of the new RETRY nodes children.\n stack.push(node.children!);\n break;\n }\n\n case \"ACTION\": {\n // Create a ACTION AST node.\n const node = ASTNodeFactories.ACTION();\n\n // Push the ACTION node into the current scope.\n currentScope.push(node);\n\n // We must have arguments defined, as we require an action name argument.\n if (tokens[0] !== \"[\") {\n throw new Error(\"expected action name identifier argument\");\n }\n\n // The action name will be defined as a node argument.\n const actionArguments = getArguments(tokens, placeholders);\n\n // We should have at least one identifer argument for an action node, which is the action name.\n if (actionArguments.length && actionArguments[0].type === \"identifier\") {\n // The action name will be the first and only node argument.\n node.actionName = actionArguments.shift()!.value as string;\n } else {\n throw new Error(\"expected action name identifier argument\");\n }\n\n // Only the first argument should have been an identifier, all following arguments must be string, number, boolean or null.\n actionArguments\n .filter((arg) => arg.type === \"identifier\")\n .forEach((arg) => {\n throw new Error(\n \"invalid action node argument value '\" +\n arg.value +\n \"', must be string, number, boolean or null\"\n );\n });\n\n // Any node arguments that follow the action name identifier will be treated as action function arguments.\n node.actionArguments = actionArguments;\n\n // Try to pick any attributes off of the token stack.\n node.attributes = getAttributes(tokens, placeholders);\n break;\n }\n\n case \"}\": {\n // The '}' character closes the current scope.\n stack.pop();\n break;\n }\n\n default: {\n throw new Error(`unexpected token '${token}'`);\n }\n }\n }\n\n // A function to recursively validate each of the nodes in the AST.\n const validateASTNode = (node: Validatable, depth: number): void => {\n // Validate the node.\n node.validate(depth);\n\n // Validate each child of the node.\n (node.children || []).forEach((child) => validateASTNode(child, depth + 1));\n };\n\n // Start node validation from the definition root.\n validateASTNode(\n {\n children: stack[0] as RootAstNode[],\n validate(this: { children: RootAstNode[] }) {\n // We must have at least one node defined as the definition scope, which should be a root node.\n if (this.children.length === 0) {\n throw new Error(\"expected root node to have been defined\");\n }\n\n // Each node at the base of the definition scope MUST be a root node.\n for (const definitionLevelNode of this.children) {\n if (definitionLevelNode.type !== \"root\") {\n throw new Error(\"expected root node at base of definition\");\n }\n }\n\n // Exactly one root node must not have a name defined. This will be the main root, others will have to be referenced via branch nodes.\n if (this.children.filter((definitionLevelNode) => definitionLevelNode.name === null).length !== 1) {\n throw new Error(\"expected single unnamed root node at base of definition to act as main root\");\n }\n\n // No two named root nodes can have matching names.\n const rootNodeNames: string[] = [];\n for (const definitionLevelNode of this.children) {\n if (rootNodeNames.indexOf(definitionLevelNode.name!) !== -1) {\n throw new Error(`multiple root nodes found with duplicate name '${definitionLevelNode.name}'`);\n } else {\n rootNodeNames.push(definitionLevelNode.name!);\n }\n }\n }\n },\n 0\n );\n\n // Return the root AST nodes.\n return stack[0];\n}\n\n/**\n * Pop the next raw token off of the stack and throw an error if it wasn't the expected one.\n * @param tokens The array of remaining tokens.\n * @param expected An optional string or array or items, one of which must match the next popped token.\n * @returns The popped token.\n */\nfunction popAndCheck(tokens: string[], expected: string | string[]) {\n // Get and remove the next token.\n const popped = tokens.shift();\n\n // We were expecting another token.\n if (popped === undefined) {\n throw new Error(\"unexpected end of definition\");\n }\n\n // Do we have an expected token/tokens array?\n if (expected !== undefined) {\n // Check whether the popped token matches at least one of our expected items.\n var tokenMatchesExpectation = ([] as string[])\n .concat(expected)\n .some((item) => popped.toUpperCase() === item.toUpperCase());\n\n // Throw an error if the popped token didn't match any of our expected items.\n if (!tokenMatchesExpectation) {\n const expectationString = ([] as string[])\n .concat(expected)\n .map((item) => \"'\" + item + \"'\")\n .join(\" or \");\n\n throw new Error(`unexpected token found. Expected '${expectationString}' but got '${popped}'`);\n }\n }\n\n // Return the popped token.\n return popped;\n}\n\ntype Placeholders = { [key: string]: string };\n\n/**\n * Pull an argument definition list off of the token stack.\n * @param tokens The array of remaining tokens.\n * @param stringArgumentPlaceholders The mapping of string literal node argument placeholders to original values.\n * @param argumentValidator The argument validator function.\n * @param validationFailedMessage The exception message to throw if argument validation fails.\n * @returns The argument definition list.\n */\nfunction getArguments(\n tokens: string[],\n stringArgumentPlaceholders: Placeholders,\n argumentValidator?: (arg: AnyArgument) => boolean,\n validationFailedMessage?: string\n) {\n // Any lists of arguments will always be wrapped in '[]' for node arguments or '()' for attribute arguments.\n // We are looking for a '[' or '(' opener that wraps the argument tokens and the relevant closer.\n const closer = popAndCheck(tokens, [\"[\", \"(\"]) === \"[\" ? \"]\" : \")\";\n\n const argumentListTokens: string[] = [];\n const argumentList: AnyArgument[] = [];\n\n // Grab all tokens between the '[' and ']' or '(' and ')'.\n while (tokens.length && tokens[0] !== closer) {\n // The next token is part of our arguments list.\n argumentListTokens.push(tokens.shift()!);\n }\n\n // Validate the order of the argument tokens. Each token must either be a ',' or a single argument that satisfies the validator.\n argumentListTokens.forEach((token, index) => {\n // Get whether this token should be an actual argument.\n const shouldBeArgumentToken = !(index & 1);\n\n // If the current token should be an actual argument then validate it,otherwise it should be a ',' token.\n if (shouldBeArgumentToken) {\n // Get the argument definition.\n const argumentDefinition = getArgumentDefinition(token!, stringArgumentPlaceholders);\n\n // Try to validate the argument.\n if (argumentValidator && !argumentValidator(argumentDefinition)) {\n throw new Error(validationFailedMessage);\n }\n\n // This is a valid argument!\n argumentList.push(argumentDefinition);\n } else {\n // The current token should be a ',' token.\n if (token !== \",\") {\n throw new Error(`invalid argument list, expected ',' or ']' but got '${token}'`);\n }\n }\n });\n\n // The arguments list should terminate with a ']' or ')' token, depending on the opener.\n popAndCheck(tokens, closer);\n\n // Return the argument list.\n return argumentList;\n}\n\n/**\n * Gets an argument value definition.\n * @param token The argument token.\n * @param stringArgumentPlaceholders The mapping of string literal node argument placeholders to original values.\n * @returns An argument value definition.\n */\nfunction getArgumentDefinition(token: string, stringArgumentPlaceholders: Placeholders): AnyArgument {\n // Check whether the token represents a null value.\n if (token === \"null\") {\n return {\n value: null,\n type: \"null\"\n } as NullArgument;\n }\n\n // Check whether the token represents a boolean value.\n if (token === \"true\" || token === \"false\") {\n return {\n value: token === \"true\",\n type: \"boolean\"\n } as BooleanArgument;\n }\n\n // Check whether the token represents a number value.\n // TODO: Relies on broken isNaN - see MDN.\n // if (!Number.isNaN(token)) {\n if (!isNaN(token as any)) {\n return {\n value: parseFloat(token),\n isInteger: parseFloat(token) === parseInt(token, 10),\n type: \"number\"\n } as NumberArgument;\n }\n\n // Check whether the token is a placeholder (e.g. @@0@@) representing a string literal.\n if (token.match(/^@@\\d+@@$/g)) {\n return {\n value: stringArgumentPlaceholders[token].replace('\\\\\"', '\"'),\n type: \"string\"\n } as StringPlaceholderArgument;\n }\n\n // The only remaining option is that the argument value is an identifier.\n return {\n value: token,\n type: \"identifier\"\n } as IdentifierArgument;\n}\n\n/**\n * Pull any attributes off of the token stack.\n * @param tokens The array of remaining tokens.\n * @param stringArgumentPlaceholders The mapping of string literal node argument placeholders to original values.\n * @returns An array of attributes defined by any directly following tokens.\n */\nfunction getAttributes(tokens: string[], stringArgumentPlaceholders: Placeholders) {\n // Create an array to hold any attributes found.\n const attributes: Attribute[] = [];\n\n // Keep track of names of attribute that we have found on the token stack, as we cannot have duplicates.\n const attributesFound: string[] = [];\n\n // Try to get the attribute factory for the next token.\n let attributeFactory = AttributeFactories[(tokens[0] || \"\").toUpperCase()];\n\n // Pull attribute tokens off of the tokens stack until we have no more.\n while (attributeFactory) {\n // Check to make sure that we have not already created a attribute of this type for this node.\n if (attributesFound.indexOf(tokens[0].toUpperCase()) !== -1) {\n throw new Error(`duplicate attribute '${tokens[0].toUpperCase()}' found for node`);\n }\n\n // Add the current attribute type to our array of found attributes.\n attributesFound.push(tokens.shift()!.toUpperCase());\n\n // Grab any attribute arguments.\n const attributeArguments = getArguments(tokens, stringArgumentPlaceholders);\n\n // The first attribute argument has to be an identifer, this will reference an agent function.\n if (attributeArguments.length === 0 || attributeArguments[0].type !== \"identifier\") {\n throw new Error(\"expected agent function name identifier argument for attribute\");\n }\n\n // Grab the first attribute which is an identifier that will reference an agent function.\n const attributeFunctionName = attributeArguments.shift()! as IdentifierArgument;\n\n // Any remaining attribute arguments must have a type of string, number, boolean or null.\n attributeArguments\n .filter((arg) => arg.type === \"identifier\")\n .forEach((arg) => {\n throw new Error(\n \"invalid attribute argument value '\" + arg.value + \"', must be string, number, boolean or null\"\n );\n });\n\n // Create the attribute and add it to the array of attributes found.\n attributes.push(attributeFactory(attributeFunctionName.value, attributeArguments));\n\n // Try to get the next attribute name token, as there could be multiple.\n attributeFactory = AttributeFactories[(tokens[0] || \"\").toUpperCase()];\n }\n\n return attributes;\n}\n\n/**\n * Swaps out any node/attribute argument string literals with placeholders.\n * @param definition The definition.\n * @returns An object containing a mapping of placeholders to original string values as well as the processed definition string.\n */\nfunction substituteStringLiterals(definition: string): {\n placeholders: { [key: string]: string };\n processedDefinition: string;\n} {\n // Create an object to hold the mapping of placeholders to original string values.\n const placeholders: Placeholders = {};\n\n // Replace any string literals wrapped with double quotes in our definition with placeholders to be processed later.\n const processedDefinition = definition.replace(/\\\"(\\\\.|[^\"\\\\])*\\\"/g, (match) => {\n var strippedMatch = match.substring(1, match.length - 1);\n var placeholder = Object.keys(placeholders).find((key) => placeholders[key] === strippedMatch);\n\n // If we have no existing string literal match then create a new placeholder.\n if (!placeholder) {\n placeholder = `@@${Object.keys(placeholders).length}@@`;\n placeholders[placeholder] = strippedMatch;\n }\n\n return placeholder;\n });\n\n return { placeholders, processedDefinition };\n}\n\n/**\n * Parse the tree definition into an array of raw tokens.\n * @param definition The definition.\n * @returns An array of tokens parsed from the definition.\n */\nfunction parseTokensFromDefinition(definition: string): string[] {\n // Add some space around various important characters so that they can be plucked out easier as individual tokens.\n definition = definition.replace(/\\(/g, \" ( \");\n definition = definition.replace(/\\)/g, \" ) \");\n definition = definition.replace(/\\{/g, \" { \");\n definition = definition.replace(/\\}/g, \" } \");\n definition = definition.replace(/\\]/g, \" ] \");\n definition = definition.replace(/\\[/g, \" [ \");\n definition = definition.replace(/\\,/g, \" , \");\n\n // Split the definition into raw token form and return it.\n return definition.replace(/\\s+/g, \" \").trim().split(\" \");\n}\n", "import GuardPath, { GuardPathPart } from \"./attributes/guards/GuardPath\";\nimport buildRootASTNodes, { AnyArgument, RootAstNode } from \"./RootAstNodesBuilder\";\nimport State, { AnyState } from \"./State\";\nimport Lookup from \"./Lookup\";\nimport Node from \"./nodes/Node\";\nimport Root from \"./nodes/decorator/Root\";\nimport Composite from \"./nodes/composite/Composite\";\nimport Decorator from \"./nodes/decorator/Decorator\";\nimport { Agent, GlobalFunction } from \"./Agent\";\nimport { CallbackAttributeDetails } from \"./attributes/callbacks/Callback\";\nimport { GuardAttributeDetails } from \"./attributes/guards/Guard\";\nimport { BehaviourTreeOptions } from \"./BehaviourTreeOptions\";\nimport { parseToJSON } from \"./dsl/DSLDefinitionParser\";\n\n// Purely for outside inspection of the tree.\nexport type FlattenedTreeNode = {\n id: string;\n type: string;\n caption: string;\n state: AnyState;\n guards: GuardAttributeDetails[];\n callbacks: CallbackAttributeDetails[];\n args: AnyArgument[];\n parentId: string | null;\n};\n\n/**\n * A representation of a behaviour tree.\n */\nexport class BehaviourTree {\n /**\n * The main root tree node.\n */\n public readonly rootNode: Root;\n\n /**\n * Creates a new instance of the BehaviourTree class.\n * @param definition The behaviour tree definition.\n * @param agent The agent instance that this behaviour tree is modelling behaviour for.\n * @param options The behaviour tree options object.\n */\n constructor(definition: string, private agent: Agent, private options: BehaviourTreeOptions = {}) {\n // The tree definition must be defined and a valid string.\n if (typeof definition !== \"string\") {\n throw new Error(\"the tree definition must be a string\");\n }\n\n // The agent must be defined and not null.\n if (typeof agent !== \"object\" || agent === null) {\n throw new Error(\"the agent must be defined and not null\");\n }\n\n // Parse the behaviour tree definition, create the populated tree of behaviour tree nodes, and get the root.\n this.rootNode = BehaviourTree._createRootNode(definition);\n }\n\n /**\n * Gets whether the tree is in the RUNNING state.\n * @returns true if the tree is in the RUNNING state, otherwise false.\n */\n isRunning() {\n return this.rootNode.getState() === State.RUNNING;\n }\n\n /**\n * Gets the current tree state of SUCCEEDED, FAILED, READY or RUNNING.\n * @returns The current tree state.\n */\n getState() {\n return this.rootNode.getState();\n }\n\n /**\n * Step the tree.\n * 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.\n * 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\n * 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.\n *\n * 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.\n */\n step() {\n // If the root node has already been stepped to completion then we need to reset it.\n if (this.rootNode.getState() === State.SUCCEEDED || this.rootNode.getState() === State.FAILED) {\n this.rootNode.reset();\n }\n\n try {\n this.rootNode.update(this.agent, this.options);\n } catch (exception) {\n throw new Error(`error stepping tree: ${(exception as Error).message}`);\n }\n }\n\n /**\n * Resets the tree from the root node outwards to each nested node, giving each a state of READY.\n */\n reset() {\n this.rootNode.reset();\n }\n\n /**\n * Gets the flattened details of every node in the tree.\n * @returns The flattened details of every node in the tree.\n */\n getFlattenedNodeDetails(): FlattenedTreeNode[] {\n // Create an empty flattened array of tree nodes.\n const flattenedTreeNodes: FlattenedTreeNode[] = [];\n\n /**\n * Helper function to process a node instance and push details into the flattened tree nodes array.\n * @param node The current node.\n * @param parentUid The UID of the node parent, or null if the node is the main root node.\n */\n const processNode = (node: Node, parentUid: string | null) => {\n // Get the guard and callback attribute details for this node.\n const guards = node\n .getAttributes()\n .filter((attribute) => attribute.isGuard())\n .map((attribute) => attribute.getDetails()) as GuardAttributeDetails[];\n const callbacks = node\n .getAttributes()\n .filter((attribute) => !attribute.isGuard())\n .map((attribute) => attribute.getDetails()) as CallbackAttributeDetails[];\n\n // Push the current node into the flattened nodes array.\n flattenedTreeNodes.push({\n id: node.getUid(),\n type: node.getType(),\n caption: node.getName(),\n state: node.getState(),\n guards,\n callbacks,\n args: node.getArguments(),\n parentId: parentUid\n });\n\n // Process each of the nodes children if it is not a leaf node.\n if (!node.isLeafNode()) {\n (node as Composite | Decorator)\n .getChildren()\n .forEach((child) => processNode(child, (node as Composite | Decorator).getUid()));\n }\n };\n\n // Convert the nested node structure into a flattened array of node details.\n processNode(this.rootNode, null);\n\n return flattenedTreeNodes;\n }\n\n /**\n * Registers the action/condition/guard/callback function or subtree with the given name.\n * @param name The name of the function or subtree to register.\n * @param value The function or subtree definition to register.\n */\n static register(name: string, value: GlobalFunction | string) {\n if (typeof value === \"function\") {\n // We are going to register a action/condition/guard/callback function.\n Lookup.setFunc(name, value);\n } else if (typeof value === \"string\") {\n // We are going to register a subtree.\n let rootASTNodes: RootAstNode[];\n\n try {\n // Try to create the behaviour tree AST based on the definition provided, this could fail if the definition is invalid.\n rootASTNodes = buildRootASTNodes(value);\n } catch (exception) {\n // There was an issue in trying to parse and build the tree definition.\n throw new Error(`error registering definition: ${(exception as Error).message}`);\n }\n\n // This function should only ever be called with a definition containing a single unnamed root node.\n if (rootASTNodes.length != 1 || rootASTNodes[0].name !== null) {\n throw new Error(\"error registering definition: expected a single unnamed root node\");\n }\n\n Lookup.setSubtree(name, rootASTNodes[0]);\n } else {\n throw new Error(\"unexpected value, expected string definition or function\");\n }\n }\n\n /**\n * Unregisters the registered action/condition/guard/callback function or subtree with the given name.\n * @param name The name of the registered action/condition/guard/callback function or subtree to unregister.\n */\n static unregister(name: string): void {\n Lookup.remove(name);\n }\n\n /**\n * Unregister all registered action/condition/guard/callback functions and subtrees.\n */\n static unregisterAll(): void {\n Lookup.empty();\n }\n\n /**\n * Parses a behaviour tree definition and creates a tree of behaviour tree nodes.\n * @param {string} definition The behaviour tree definition.\n * @returns The root behaviour tree node.\n */\n private static _createRootNode(definition: string): Root {\n // TODO Remove!\n try {\n //parseToJSON(definition);\n } catch (exception) {\n console.log(exception);\n }\n\n try {\n // Try to create the behaviour tree AST based on the definition provided, this could fail if the definition is invalid.\n const rootASTNodes = buildRootASTNodes(definition);\n\n // Create a symbol to use as the main root key in our root node mapping.\n const mainRootNodeKey = Symbol(\"__root__\");\n\n // Create a mapping of root node names to root AST tokens. The main root node will have a key of Symbol(\"__root__\").\n const rootNodeMap: { [key: string | symbol]: RootAstNode } = {};\n for (const rootASTNode of rootASTNodes) {\n rootNodeMap[rootASTNode.name === null ? mainRootNodeKey : rootASTNode.name!] = rootASTNode;\n }\n\n // Convert the AST to our actual tree and get the root node.\n const rootNode: Root = rootNodeMap[mainRootNodeKey].createNodeInstance(\n // Create a provider for named root nodes that are part of our definition or have been registered. Prioritising the former.\n (name: string): RootAstNode => (rootNodeMap[name] ? rootNodeMap[name] : Lookup.getSubtree(name)),\n []\n );\n\n // Set a guard path on every leaf of the tree to evaluate as part of its update.\n BehaviourTree._applyLeafNodeGuardPaths(rootNode);\n\n // Return the root node.\n return rootNode;\n } catch (exception) {\n // There was an issue in trying to parse and build the tree definition.\n throw new Error(`error parsing tree: ${(exception as Error).message}`);\n }\n }\n\n /**\n * Applies a guard path to every leaf of the tree to evaluate as part of each update.\n * @param rootNode The main root tree node.\n */\n private static _applyLeafNodeGuardPaths(rootNode: Root) {\n const nodePaths: Node[][] = [];\n\n const findLeafNodes = (path: Node[], node: Node) => {\n // Add the current node to the path.\n path = path.concat(node);\n\n // Check whether the current node is a leaf node.\n if (node.isLeafNode()) {\n nodePaths.push(path);\n } else {\n (node as Composite | Decorator).getChildren().forEach((child) => findLeafNodes(path, child));\n }\n };\n\n // Find all leaf node paths, starting from the root.\n findLeafNodes([], rootNode);\n\n nodePaths.forEach((path) => {\n // Each node in the current path will have to be assigned a guard path, working from the root outwards.\n for (let depth = 0; depth < path.length; depth++) {\n // Get the node in the path at the current depth.\n const currentNode = path[depth];\n\n // The node may already have been assigned a guard path, if so just skip it.\n if (currentNode.hasGuardPath()) {\n continue;\n }\n\n // Create the guard path for the current node.\n const guardPath = new GuardPath(\n path\n .slice(0, depth + 1)\n .map((node) => ({ node, guards: node.getGuardAttributes() }))\n .filter((details) => details.guards.length > 0)\n );\n\n // Assign the guard path to the current node.\n currentNode.setGuardPath(guardPath);\n }\n });\n }\n}\n"], - "mappings": "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", + "sourcesContent": ["\"use strict\";\r\nObject.defineProperty(exports, \"__esModule\", { value: true });\r\nexports.Participant = void 0;\r\n/**\r\n * A participant that holds a number of tickets.\r\n */\r\nvar Participant = /** @class */ (function () {\r\n /**\r\n * Creates an instance of the Participant class.\r\n * @param participant The actual participant.\r\n * @param tickets The number of tickets held by the participant.\r\n */\r\n function Participant(participant, tickets) {\r\n if (tickets === void 0) { tickets = 1; }\r\n this._participant = participant;\r\n this._tickets = tickets;\r\n }\r\n Object.defineProperty(Participant.prototype, \"participant\", {\r\n /** Gets the actual participant. */\r\n get: function () {\r\n return this._participant;\r\n },\r\n enumerable: false,\r\n configurable: true\r\n });\r\n Object.defineProperty(Participant.prototype, \"tickets\", {\r\n /** Gets or sets the number of tickets held by the participant. */\r\n get: function () {\r\n return this._tickets;\r\n },\r\n set: function (value) {\r\n this._tickets = value;\r\n },\r\n enumerable: false,\r\n configurable: true\r\n });\r\n return Participant;\r\n}());\r\nexports.Participant = Participant;\r\n", "\"use strict\";\r\nObject.defineProperty(exports, \"__esModule\", { value: true });\r\nexports.isNaturalNumber = exports.isNullOrUndefined = void 0;\r\n/**\r\n * Gets whether the value provided is null or undefined.\r\n * @param value The value to check.\r\n * @returns Whether the value provided is null or undefined.\r\n */\r\nfunction isNullOrUndefined(value) {\r\n return value === null || value === undefined;\r\n}\r\nexports.isNullOrUndefined = isNullOrUndefined;\r\n/**\r\n * Gets whether the value provided is a natural number.\r\n * @param value The value to check.\r\n * @returns Whether the value provided is a natural number.\r\n */\r\nfunction isNaturalNumber(value) {\r\n return typeof value === \"number\" && value >= 1 && Math.floor(value) === value;\r\n}\r\nexports.isNaturalNumber = isNaturalNumber;\r\n", "\"use strict\";\r\nObject.defineProperty(exports, \"__esModule\", { value: true });\r\nexports.Lotto = void 0;\r\nvar Participant_1 = require(\"./Participant\");\r\nvar Utilities_1 = require(\"./Utilities\");\r\n/**\r\n * Represents a lotto consisting of a number of pickable ticket-holding participants.\r\n */\r\nvar Lotto = /** @class */ (function () {\r\n /**\r\n * Creates a new instance of Lotto.\r\n * @param customRandom The custom RNG to use in place of Math.random().\r\n */\r\n function Lotto(customRandom) {\r\n /** The array of participants that are holding tickets in the lotto. */\r\n this._participants = [];\r\n this._customRandom = customRandom;\r\n }\r\n /**\r\n * Adds a participant with the specified number of tickets, or adds to the participant ticket count if the participant already holds tickets.\r\n * @param participant The participant to add or to increase the ticket count for if they already hold tickets.\r\n * @param tickets The number of tickets, defaults to 1.\r\n * @returns The Lotto instance.\r\n */\r\n Lotto.prototype.add = function (participant, tickets) {\r\n if (tickets === void 0) { tickets = 1; }\r\n // Check that we have a valid ticket count.\r\n if (!(0, Utilities_1.isNaturalNumber)(tickets)) {\r\n throw new Error(\"tickets value must be a natural number\");\r\n }\r\n // Check whether this participant has already been added.\r\n var existingParticipant = this._participants.find(function (part) { return part.participant === participant; });\r\n if (existingParticipant) {\r\n // The participant has already been added to the lotto so just add to their ticket count.\r\n existingParticipant.tickets += tickets;\r\n }\r\n else {\r\n // The participant is not part of the lotto so we should add them.\r\n this._participants.push(new Participant_1.Participant(participant, tickets));\r\n }\r\n return this;\r\n };\r\n /**\r\n * Removes the specified number of tickets for the given participant from the draw, or all tickets if a ticket number is not defined.\r\n * @param participant The participant to remove tickets for.\r\n * @param tickets The number of tickets to remove, or undefined if all tickets are to be removed.\r\n * @returns The Lotto instance.\r\n */\r\n Lotto.prototype.remove = function (participant, tickets) {\r\n // Attempt to get the existing participant.\r\n var existingParticipant = this._participants.find(function (part) { return part.participant === participant; });\r\n // There is nothing to do if the specified participant isn't even part of the lotto.\r\n if (!existingParticipant) {\r\n return this;\r\n }\r\n // Check whether a tickets value was given.\r\n if (tickets !== undefined) {\r\n // Check that we have a valid ticket count.\r\n if (!(0, Utilities_1.isNaturalNumber)(tickets)) {\r\n throw new Error(\"tickets value must be a natural number\");\r\n }\r\n existingParticipant.tickets -= tickets;\r\n // If the participant no longer holds any tickets then they should be removed.\r\n if (existingParticipant.tickets < 1) {\r\n this._participants = this._participants.filter(function (part) { return part !== existingParticipant; });\r\n }\r\n }\r\n else {\r\n // We are removing all tickets for the participant so just remove them from the lotto.\r\n this._participants = this._participants.filter(function (part) { return part !== existingParticipant; });\r\n }\r\n return this;\r\n };\r\n /**\r\n * Draw a winning ticket and return the participant that holds the ticket.\r\n * @param options The draw options.\r\n * @returns The participant that holds the winning ticket.\r\n */\r\n Lotto.prototype.draw = function (options) {\r\n if (options === void 0) { options = {}; }\r\n // If we have no participants then just return null.\r\n if (this._participants.length === 0) {\r\n return null;\r\n }\r\n var redrawable = (0, Utilities_1.isNullOrUndefined)(options.redrawable) ? true : options.redrawable;\r\n var pickable = [];\r\n this._participants.forEach(function (_a) {\r\n var participant = _a.participant, tickets = _a.tickets;\r\n for (var ticketCount = 0; ticketCount < tickets; ticketCount++) {\r\n pickable.push(participant);\r\n }\r\n });\r\n var random;\r\n // We need a random floating-point number between 0 (inclusive) and 1 to scale up to pick our winner.\r\n // If a custom random function exists then we should use that or fall back to Math.random().\r\n if (this._customRandom) {\r\n // Call our custom random function to get a random floating-point number.\r\n random = this._customRandom();\r\n // Verify that the result of calling our custom random function is a number between 0 (inclusive) and 1.\r\n if (typeof random !== \"number\" || random < 0 || random >= 1) {\r\n throw new Error(\"the 'random' function provided did not return a number between 0 (inclusive) and 1\");\r\n }\r\n }\r\n else {\r\n // No custom random function was defined so just use good ol' Math.random().\r\n random = Math.random();\r\n }\r\n // Pick a winning participant.\r\n var winner = pickable[Math.floor(random * pickable.length)];\r\n // If the ticket isn't redrawable then we should remove a ticket from the winning participants ticket count.\r\n if (!redrawable) {\r\n this.remove(winner, 1);\r\n }\r\n // Return the winning participant.\r\n return winner;\r\n };\r\n /**\r\n * Draws multiple winning tickets and return an array of the participants that hold the winning tickets.\r\n * @param tickets The number of winning tickets to draw.\r\n * @param options The draw multiple options.\r\n * @returns An array of the participants that hold the winning tickets.\r\n */\r\n Lotto.prototype.drawMultiple = function (tickets, options) {\r\n if (options === void 0) { options = {}; }\r\n var uniqueResults = (0, Utilities_1.isNullOrUndefined)(options.unique) ? false : options.unique;\r\n // Handle cases where the user has asked for zero tickets (no idea why they would do this be we should trust them).\r\n if (tickets === 0) {\r\n return [];\r\n }\r\n // Now that we know out tickets value is not zero we should check that it is a valid natural number.\r\n if (!(0, Utilities_1.isNaturalNumber)(tickets)) {\r\n throw new Error(\"tickets value must be a natural number\");\r\n }\r\n var result = [];\r\n // Keep drawing tickets until we either reach the number of required tickets or we simply run out of tickets to draw.\r\n // We can run out of tickets to draw if 'options.redrawable' is explicity 'false' or we just had no participants when 'drawMultiple' was called.\r\n while (result.length < tickets && this._participants.length > 0) {\r\n result.push(this.draw(options));\r\n }\r\n // If the 'unique' draw option is set then we need to remove duplicates from the result list.\r\n if (uniqueResults) {\r\n // Create an array to store our unique results.\r\n var unique = [];\r\n // Iterate over all of our participants (with potential duplicates) and populate our array of unique values.\r\n for (var _i = 0, result_1 = result; _i < result_1.length; _i++) {\r\n var participant = result_1[_i];\r\n if (unique.indexOf(participant) === -1) {\r\n unique.push(participant);\r\n }\r\n }\r\n result = unique;\r\n }\r\n return result;\r\n };\r\n return Lotto;\r\n}());\r\nexports.Lotto = Lotto;\r\n", "\"use strict\";\r\nObject.defineProperty(exports, \"__esModule\", { value: true });\r\nexports.createLotto = void 0;\r\nvar Lotto_1 = require(\"./Lotto\");\r\n/**\r\n * A function that creates and returns a Lotto instance.\r\n * @param participantsOrOptions An array of initial participants or options relating to the creation of a Lotto instance.\r\n * @returns A new Lotto instance.\r\n */\r\nfunction createLotto(participantsOrOptions) {\r\n // If no initial participants or lotto options were provided as an argument then we can just return a new lotto instance now.\r\n if (!participantsOrOptions) {\r\n return new Lotto_1.Lotto();\r\n }\r\n // Check whether we were provided with an array of initial participants or a lotto options object.\r\n if (Array.isArray(participantsOrOptions)) {\r\n // We are dealing with a pre-defined array of participants.\r\n var participants = participantsOrOptions;\r\n var lotto_1 = new Lotto_1.Lotto();\r\n // If the lotto participants have been defined upfront then we will need to add them all to our lotto instance now.\r\n participants.forEach(function (_a) {\r\n var participant = _a[0], tokens = _a[1];\r\n return lotto_1.add(participant, tokens);\r\n });\r\n // Return the Lotto instance.\r\n return lotto_1;\r\n }\r\n else {\r\n // We are dealing with some lotto options.\r\n var random = participantsOrOptions.random, participants = participantsOrOptions.participants;\r\n // Create a Lotto instance passing the custom RNG function to use in place of Math.random() (which could be undefined).\r\n var lotto_2 = new Lotto_1.Lotto(random);\r\n // If the lotto participants have been defined upfront as part of the options then we will need to add them all to our lotto instance now.\r\n if (participants) {\r\n participants.forEach(function (_a) {\r\n var participant = _a[0], tokens = _a[1];\r\n return lotto_2.add(participant, tokens);\r\n });\r\n }\r\n // Return the Lotto instance.\r\n return lotto_2;\r\n }\r\n}\r\nexports.createLotto = createLotto;\r\n", "\"use strict\";\r\nObject.defineProperty(exports, \"__esModule\", { value: true });\r\nvar createLotto_1 = require(\"./createLotto\");\r\nexports.default = createLotto_1.createLotto;\r\n", "import { BehaviourTree, FlattenedTreeNode } from \"./BehaviourTree\";\nimport State from \"./State\";\n\nexport { BehaviourTree, State };\nexport type { FlattenedTreeNode };\n", "import Node from \"../../nodes/Node\";\n\n/**\n * An exception thrown when evaluating node guard path conditions and a conditions fails.\n */\nexport default class GuardUnsatisifedException extends Error {\n /**\n * @param source The node at which a guard condition failed.\n */\n constructor(private source: Node) {\n super(\"A guard path condition has failed\");\n }\n\n /**\n * Gets whether the specified node is the node at which a guard condition failed.\n * @param node The node to check against the source node.\n * @returns Whether the specified node is the node at which a guard condition failed.\n */\n isSourceNode = (node: Node) => node === this.source;\n}\n", "import { Agent } from \"../../Agent\";\nimport Guard from \"./Guard\";\nimport Node from \"../../nodes/Node\";\nimport GuardUnsatisifedException from \"./GuardUnsatisifedException\";\n\nexport type GuardPathPart = {\n node: Node;\n guards: Guard[];\n};\n\n/**\n * Represents a path of node guards along a root-to-leaf tree path.\n */\nexport default class GuardPath {\n /**\n * @param nodes An array of objects defining a node instance -> guard link, ordered by node depth.\n */\n constructor(private nodes: GuardPathPart[]) {}\n\n /**\n * Evaluate guard conditions for all guards in the tree path, moving outwards from the root.\n * @param agent The agent, required for guard evaluation.\n * @returns An evaluation results object.\n */\n evaluate = (agent: Agent) => {\n // We need to evaluate guard conditions for nodes up the tree, moving outwards from the root.\n for (const details of this.nodes) {\n // There can be multiple guards per node.\n for (const guard of details.guards) {\n // Check whether the guard condition passes, and throw an exception if not.\n if (!guard.isSatisfied(agent)) {\n throw new GuardUnsatisifedException(details.node);\n }\n }\n }\n };\n}\n", "/**\n * Enumeration of node state types.\n */\nexport enum State {\n READY = \"mistreevous.ready\",\n RUNNING = \"mistreevous.running\",\n SUCCEEDED = \"mistreevous.succeeded\",\n FAILED = \"mistreevous.failed\"\n}\n\nexport { State as default };\n\nexport type CompleteState = State.SUCCEEDED | State.FAILED;\nexport type AnyState = State.READY | State.RUNNING | CompleteState;\n", "import { Agent } from \"../Agent\";\nimport Attribute from \"../attributes/Attribute\";\nimport Entry from \"../attributes/callbacks/Entry\";\nimport Exit from \"../attributes/callbacks/Exit\";\nimport Step from \"../attributes/callbacks/Step\";\nimport Guard from \"../attributes/guards/Guard\";\nimport GuardPath from \"../attributes/guards/GuardPath\";\nimport GuardUnsatisifedException from \"../attributes/guards/GuardUnsatisifedException\";\nimport { BehaviourTreeOptions } from \"../BehaviourTreeOptions\";\nimport { AnyArgument } from \"../RootAstNodesBuilder\";\nimport State, { AnyState } from \"../State\";\nimport Leaf from \"./leaf/Leaf\";\n\n/**\n * A base node.\n */\nexport default abstract class Node {\n /**\n * The node uid.\n */\n private readonly uid: string = createNodeUid();\n /**\n * The node state.\n */\n private state: AnyState = State.READY;\n /**\n * The guard path to evaluate as part of a node update.\n */\n private guardPath: GuardPath | undefined;\n\n /**\n * @param type The node type.\n * @param attributes The node attributes.\n * @param args The node argument definitions.\n */\n constructor(private type: string, private attributes: Attribute[], private args: AnyArgument[]) {}\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected abstract onUpdate(agent: Agent, options: BehaviourTreeOptions): void;\n\n /**\n * Gets the name of the node.\n */\n public abstract getName(): string;\n\n /**\n * Gets whether this node is a leaf node.\n */\n public abstract isLeafNode: () => this is Leaf;\n\n /**\n * Gets/Sets the state of the node.\n */\n getState = (): AnyState => this.state;\n setState = (value: AnyState): void => {\n this.state = value;\n };\n\n /**\n * Gets the unique id of the node.\n */\n getUid = () => this.uid;\n\n /**\n * Gets the type of the node.\n */\n getType = () => this.type;\n\n /**\n * Gets the node attributes.\n */\n getAttributes = () => this.attributes;\n\n /**\n * Gets the node arguments.\n */\n getArguments = () => this.args;\n\n /**\n * Gets the node attribute with the specified type, or null if it does not exist.\n */\n getAttribute(type: \"entry\" | \"ENTRY\"): Entry;\n getAttribute(type: \"exit\" | \"EXIT\"): Exit;\n getAttribute(type: \"step\" | \"STEP\"): Step;\n getAttribute(type: string): Attribute {\n return (\n this.getAttributes().filter((decorator) => decorator.getType().toUpperCase() === type.toUpperCase())[0] ||\n null\n );\n }\n\n /**\n * Gets the node attributes.\n */\n getGuardAttributes = (): Guard[] => this.getAttributes().filter((decorator) => decorator.isGuard()) as Guard[];\n\n /**\n * Sets the guard path to evaluate as part of a node update.\n */\n setGuardPath = (value: GuardPath) => (this.guardPath = value);\n\n /**\n * Gets whether a guard path is assigned to this node.\n */\n hasGuardPath = () => !!this.guardPath;\n\n /**\n * Gets whether this node is in the specified state.\n * @param value The value to compare to the node state.\n */\n public is(value: AnyState): boolean {\n return this.state === value;\n }\n\n /**\n * Reset the state of the node.\n */\n public reset(): void {\n this.setState(State.READY);\n }\n\n /**\n * Abort the running of this node.\n * @param agent The agent.\n */\n public abort(agent: Agent): void {\n // There is nothing to do if this node is not in the running state.\n if (!this.is(State.RUNNING)) {\n return;\n }\n\n // Reset the state of this node.\n this.reset();\n\n this.getAttribute(\"exit\")?.callAgentFunction(agent, false, true);\n }\n\n /**\n * Update the node.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n * @returns The result of the update.\n */\n public update(agent: Agent, options: BehaviourTreeOptions): void {\n // If this node is already in a 'SUCCEEDED' or 'FAILED' state then there is nothing to do.\n if (this.is(State.SUCCEEDED) || this.is(State.FAILED)) {\n return;\n }\n\n try {\n // Evaluate all of the guard path conditions for the current tree path.\n this.guardPath!.evaluate(agent);\n\n // If this node is in the READY state then call the ENTRY for this node if it exists.\n if (this.is(State.READY)) {\n this.getAttribute(\"entry\")?.callAgentFunction(agent);\n }\n\n this.getAttribute(\"step\")?.callAgentFunction(agent);\n\n // Do the actual update.\n this.onUpdate(agent, options);\n\n // If this node is now in a 'SUCCEEDED' or 'FAILED' state then call the EXIT for this node if it exists.\n if (this.is(State.SUCCEEDED) || this.is(State.FAILED)) {\n this.getAttribute(\"exit\")?.callAgentFunction(agent, this.is(State.SUCCEEDED), false);\n }\n } catch (error) {\n // If the error is a GuardUnsatisfiedException then we need to determine if this node is the source.\n if (error instanceof GuardUnsatisifedException && error.isSourceNode(this)) {\n // Abort the current node.\n this.abort(agent);\n\n // Any node that is the source of an abort will be a failed node.\n this.setState(State.FAILED);\n } else {\n throw error;\n }\n }\n }\n}\n\n/**\n * Create a randomly generated node uid.\n * @returns A randomly generated node uid.\n */\nfunction createNodeUid(): string {\n var S4 = function () {\n return (((1 + Math.random()) * 0x10000) | 0).toString(16).substring(1);\n };\n return S4() + S4() + \"-\" + S4() + \"-\" + S4() + \"-\" + S4() + \"-\" + S4() + S4() + S4();\n}\n", "import Node from \"../Node\";\n\n/**\n * A leaf node.\n */\nexport default abstract class Leaf extends Node {\n /**\n * Gets whether this node is a leaf node.\n */\n isLeafNode = () => true;\n}\n", "import { ActionResult, Agent, ExitFunctionArg, FunctionArg, GlobalFunction } from \"./Agent\";\nimport { AnyArgument, RootAstNode } from \"./RootAstNodesBuilder\";\n\n// Exit callbacks receive their own special type of argument.\n// There's probably stricter ways to represent this but it feels overly complex right now.\ntype ExitResultArg = { value: ExitFunctionArg };\nexport type AnyExitArgument = AnyArgument | ExitResultArg;\n\nexport type InvokerFunction = (args: AnyExitArgument[]) => ActionResult;\n\n/**\n * A singleton used to store and lookup registered functions and subtrees.\n */\nexport default class Lookup {\n /**\n * The object holding any registered functions keyed on function name.\n */\n private static functionTable: { [key: string]: GlobalFunction } = {};\n /**\n * The object holding any registered sub-trees keyed on tree name.\n */\n private static subtreeTable: { [key: string]: RootAstNode } = {};\n\n /**\n * Gets the function with the specified name.\n * @param name The name of the function.\n * @returns The function with the specified name.\n */\n public static getFunc(name: string): GlobalFunction {\n return this.functionTable[name];\n }\n\n /**\n * Sets the function with the specified name for later lookup.\n * @param name The name of the function.\n * @param func The function.\n */\n public static setFunc(name: string, func: GlobalFunction): void {\n this.functionTable[name] = func;\n }\n\n /**\n * Gets the function invoker for the specified agent and function name.\n * If a function with the specified name exists on the agent object then it will\n * be returned, otherwise we will then check the registered functions for a match.\n * @param agent The agent instance that this behaviour tree is modelling behaviour for.\n * @param name The function name.\n * @returns The function invoker for the specified agent and function name.\n */\n static getFuncInvoker(agent: Agent, name: string): InvokerFunction | null {\n // Check whether the agent contains the specified function.\n const foundOnAgent = agent[name];\n if (foundOnAgent && typeof foundOnAgent === \"function\") {\n return (args: AnyExitArgument[]): boolean | ActionResult =>\n foundOnAgent.apply(\n agent,\n args.map((arg) => arg.value)\n );\n }\n\n // The agent does not contain the specified function but it may have been registered at some point.\n if (this.functionTable[name] && typeof this.functionTable[name] === \"function\") {\n return (args: AnyExitArgument[]) => this.functionTable[name](agent, ...args.map((arg) => arg.value));\n }\n\n // We have no function to invoke.\n return null;\n }\n\n /**\n * Gets the subtree with the specified name.\n * @param name The name of the subtree.\n * @returns The subtree with the specified name.\n */\n static getSubtree(name: string): RootAstNode {\n return this.subtreeTable[name];\n }\n\n /**\n * Sets the subtree with the specified name for later lookup.\n * @param name The name of the subtree.\n * @param subtree The subtree.\n */\n static setSubtree(name: string, subtree: RootAstNode) {\n this.subtreeTable[name] = subtree;\n }\n\n /**\n * Removes the registered function or subtree with the specified name.\n * @param name The name of the registered function or subtree.\n */\n static remove(name: string) {\n delete this.functionTable[name];\n delete this.subtreeTable[name];\n }\n\n /**\n * Remove all registered functions and subtrees.\n */\n static empty() {\n this.functionTable = {};\n this.subtreeTable = {};\n }\n}\n", "import Leaf from \"./Leaf\";\nimport State, { CompleteState } from \"../../State\";\nimport Lookup from \"../../Lookup\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { AnyArgument } from \"../../RootAstNodesBuilder\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * An Action leaf node.\n * This represents an immediate or ongoing state of behaviour.\n */\nexport default class Action extends Leaf {\n /**\n * @param attributes The node attributes.\n * @param actionName The action name.\n * @param actionArguments The array of action argument definitions.\n */\n constructor(attributes: Attribute[], private actionName: string, private actionArguments: AnyArgument[]) {\n super(\"action\", attributes, actionArguments);\n }\n\n /**\n * Whether there is a pending update promise.\n */\n private isUsingUpdatePromise = false;\n\n /**\n * The finished state result of an update promise.\n */\n private updatePromiseStateResult: CompleteState | null = null;\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // If the result of this action depends on an update promise then there is nothing to do until\n // it resolves, unless there has been a value set as a result of the update promise resolving.\n if (this.isUsingUpdatePromise) {\n // Check whether the update promise has resolved with a state value.\n if (this.updatePromiseStateResult) {\n // Set the state of this node to match the state returned by the promise.\n this.setState(this.updatePromiseStateResult);\n }\n\n return;\n }\n\n // Attempt to get the invoker for the action function.\n const actionFuncInvoker = Lookup.getFuncInvoker(agent, this.actionName);\n\n // The action function should be defined.\n if (actionFuncInvoker === null) {\n throw new Error(\n `cannot update action node as the action '${this.actionName}' function is not defined on the agent and has not been registered`\n );\n }\n\n // Call the action function, the result of which may be:\n // - The finished state of this action node.\n // - A promise to return a finished node state.\n // - Undefined if the node should remain in the running state.\n const updateResult = actionFuncInvoker(this.actionArguments) as CompleteState | Promise;\n\n if (updateResult instanceof Promise) {\n updateResult.then(\n (result) => {\n // If 'isUpdatePromisePending' is null then the promise was cleared as it was resolving, probably via an abort of reset.\n if (!this.isUsingUpdatePromise) {\n return;\n }\n\n // Check to make sure the result is a valid finished state.\n if (result !== State.SUCCEEDED && result !== State.FAILED) {\n throw new Error(\n \"action node promise resolved with an invalid value, expected a State.SUCCEEDED or State.FAILED value to be returned\"\n );\n }\n\n // Set pending update promise state result to be processed on next update.\n this.updatePromiseStateResult = result;\n },\n (reason) => {\n // If 'isUpdatePromisePending' is null then the promise was cleared as it was resolving, probably via an abort of reset.\n if (!this.isUsingUpdatePromise) {\n return;\n }\n\n // Just throw whatever was returned as the rejection argument.\n throw new Error(reason);\n }\n );\n\n // This node will be in the 'RUNNING' state until the update promise resolves.\n this.setState(State.RUNNING);\n\n // We are now waiting for the promise returned by the use to resolve before we know what state this node is in.\n this.isUsingUpdatePromise = true;\n } else {\n // Validate the returned value.\n this.validateUpdateResult(updateResult);\n\n // Set the state of this node, this may be undefined, which just means that the node is still in the 'RUNNING' state.\n this.setState(updateResult || State.RUNNING);\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => this.actionName;\n\n /**\n * Reset the state of the node.\n */\n reset = () => {\n // Reset the state of this node.\n this.setState(State.READY);\n\n // There is no longer an update promise that we care about.\n this.isUsingUpdatePromise = false;\n this.updatePromiseStateResult = null;\n };\n\n /**\n * Validate the result of an update function call.\n * @param result The result of an update function call.\n */\n private validateUpdateResult = (result: CompleteState | boolean) => {\n switch (result) {\n case State.SUCCEEDED:\n case State.FAILED:\n case undefined:\n return;\n default:\n throw new Error(\n `action '${this.actionName}' 'onUpdate' returned an invalid response, expected an optional State.SUCCEEDED or State.FAILED value to be returned`\n );\n }\n };\n}\n", "import Leaf from \"./Leaf\";\nimport State from \"../../State\";\nimport Lookup from \"../../Lookup\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { AnyArgument } from \"../../RootAstNodesBuilder\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A Condition leaf node.\n * This will succeed or fail immediately based on an agent predicate, without moving to the 'RUNNING' state.\n */\nexport default class Condition extends Leaf {\n /**\n * @param attributes The node attributes.\n * @param conditionName The name of the condition function.\n * @param conditionArguments The array of condition argument definitions.\n */\n constructor(attributes: Attribute[], private conditionName: string, private conditionArguments: AnyArgument[]) {\n super(\"condition\", attributes, conditionArguments);\n }\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // Attempt to get the invoker for the condition function.\n const conditionFuncInvoker = Lookup.getFuncInvoker(agent, this.conditionName);\n\n // The condition function should be defined.\n if (conditionFuncInvoker === null) {\n throw new Error(\n `cannot update condition node as the condition '${this.conditionName}' function is not defined on the agent and has not been registered`\n );\n }\n\n // Call the condition function to determine the state of this node.\n this.setState(!!conditionFuncInvoker(this.conditionArguments) ? State.SUCCEEDED : State.FAILED);\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => this.conditionName;\n}\n", "import Leaf from \"./Leaf\";\nimport State from \"../../State\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { Agent } from \"../../Agent\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A WAIT node.\n * The state of this node will change to SUCCEEDED after a duration of time\n */\nexport default class Wait extends Leaf {\n /**\n * @param attributes The node attributes.\n * @param duration The duration that this node will wait to succeed in milliseconds.\n * @param durationMin The minimum possible duration in milliseconds that this node will wait to succeed.\n * @param durationMax The maximum possible duration in milliseconds that this node will wait to succeed.\n */\n constructor(\n attributes: Attribute[],\n private duration: number | null,\n private durationMin: number | null,\n private durationMax: number | null\n ) {\n super(\"wait\", attributes, []);\n }\n\n /**\n * The time in milliseconds at which this node was first updated.\n */\n private initialUpdateTime: number = 0;\n\n /**\n * The total duration in milliseconds that this node will be waiting for.\n */\n private totalDuration: number | null = null;\n\n /**\n * The duration in milliseconds that this node has been waiting for.\n */\n private waitedDuration: number = 0;\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // If this node is in the READY state then we need to set the initial update time.\n if (this.is(State.READY)) {\n // Set the initial update time.\n this.initialUpdateTime = new Date().getTime();\n\n // Set the initial waited duration.\n this.waitedDuration = 0;\n\n // Are we dealing with an explicit duration or will we be randomly picking a duration between the min and max duration.\n if (this.duration !== null) {\n this.totalDuration = this.duration;\n } else if (this.durationMin !== null && this.durationMax !== null) {\n // We will be picking a random duration between a min and max duration, if the optional 'random' behaviour tree\n // function option is defined then we will be using that, otherwise we will fall back to using Math.random.\n const random = typeof options.random === \"function\" ? options.random : Math.random;\n\n // Pick a random duration between a min and max duration.\n this.totalDuration = Math.floor(\n random() * (this.durationMax - this.durationMin + 1) + this.durationMin\n );\n } else {\n this.totalDuration = null;\n }\n\n // The node is now running until we finish waiting.\n this.setState(State.RUNNING);\n }\n\n // If we have no total duration then this wait node will wait indefinitely until it is aborted.\n if (this.totalDuration === null) {\n return;\n }\n\n // If we have a 'getDeltaTime' function defined as part of our options then we will use it to figure out how long we have waited for.\n if (typeof options.getDeltaTime === \"function\") {\n // Get the delta time.\n const deltaTime = options.getDeltaTime();\n\n // Our delta time must be a valid number and cannot be NaN.\n if (typeof deltaTime !== \"number\" || isNaN(deltaTime)) {\n throw new Error(\"The delta time must be a valid number and not NaN.\");\n }\n\n // Update the amount of time that this node has been waiting for based on the delta time.\n this.waitedDuration += deltaTime * 1000;\n } else {\n // We are not using a delta time, so we will just work out hom much time has passed since the first update.\n this.waitedDuration = new Date().getTime() - this.initialUpdateTime;\n }\n\n // Have we waited long enough?\n if (this.waitedDuration >= this.totalDuration) {\n // We have finished waiting!\n this.setState(State.SUCCEEDED);\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => {\n if (this.duration !== null) {\n return `WAIT ${this.duration}ms`;\n } else if (this.durationMin !== null && this.durationMax !== null) {\n return `WAIT ${this.durationMin}ms-${this.durationMax}ms`;\n } else {\n return \"WAIT\";\n }\n };\n}\n", "import Node from \"../Node\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\n\n/**\n * A decorator node that wraps a single child node.\n */\nexport default abstract class Decorator extends Node {\n /**\n * @param type The node type.\n * @param attributes The node attributes.\n * @param child The child node.\n */\n constructor(type: string, attributes: Attribute[], protected child: Node) {\n super(type, attributes, []);\n }\n\n /**\n * Gets whether this node is a leaf node.\n */\n isLeafNode = () => false;\n\n /**\n * Gets the children of this node.\n */\n getChildren = () => [this.child];\n\n /**\n * Reset the state of the node.\n */\n reset = () => {\n // Reset the state of this node.\n this.setState(State.READY);\n\n // Reset the state of the child node.\n this.child.reset();\n };\n\n /**\n * Abort the running of this node.\n * @param agent The agent.\n */\n abort = (agent: Agent) => {\n // There is nothing to do if this node is not in the running state.\n if (!this.is(State.RUNNING)) {\n return;\n }\n\n // Abort the child node.\n this.child.abort(agent);\n\n // Reset the state of this node.\n this.reset();\n\n this.getAttribute(\"exit\")?.callAgentFunction(agent, false, true);\n };\n}\n", "import Node from \"../Node\";\nimport Decorator from \"./Decorator\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A Root node.\n * The root node will have a single child.\n */\nexport default class Root extends Decorator {\n /**\n * @param attributes The node attributes.\n * @param child The child node.\n */\n constructor(attributes: Attribute[], child: Node) {\n super(\"root\", attributes, child);\n }\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // If the child has never been updated or is running then we will need to update it now.\n if (this.child.getState() === State.READY || this.child.getState() === State.RUNNING) {\n // Update the child of this node.\n this.child.update(agent, options);\n }\n\n // The state of the root node is the state of its child.\n this.setState(this.child.getState());\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => \"ROOT\";\n}\n", "import Node from \"../Node\";\nimport Decorator from \"./Decorator\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A REPEAT node.\n * The node has a single child which can have:\n * -- A number of iterations for which to repeat the child node.\n * -- An infinite repeat loop if neither an iteration count or a condition function is defined.\n * The REPEAT node will stop and have a 'FAILED' state if its child is ever in a 'FAILED' state after an update.\n * The REPEAT node will attempt to move on to the next iteration if its child is ever in a 'SUCCEEDED' state.\n */\nexport default class Repeat extends Decorator {\n /**\n * @param attributes The node attributes.\n * @param iterations The number of iterations to repeat the child node.\n * @param iterationsMin The minimum possible number of iterations to repeat the child node.\n * @param iterationsMax The maximum possible number of iterations to repeat the child node.\n * @param child The child node.\n */\n constructor(\n attributes: Attribute[],\n private iterations: number | null,\n private iterationsMin: number | null,\n private iterationsMax: number | null,\n child: Node\n ) {\n super(\"repeat\", attributes, child);\n }\n\n /**\n * The number of target iterations to make.\n */\n private targetIterationCount: number | null = null;\n\n /**\n * The current iteration count.\n */\n private currentIterationCount: number = 0;\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // If this node is in the READY state then we need to reset the child and the target iteration count.\n if (this.is(State.READY)) {\n // Reset the child node.\n this.child.reset();\n\n // Reset the current iteration count.\n this.currentIterationCount = 0;\n\n // Set the target iteration count.\n this.setTargetIterationCount(options);\n }\n\n // Do a check to see if we can iterate. If we can then this node will move into the 'RUNNING' state.\n // If we cannot iterate then we have hit our target iteration count, which means that the node has succeeded.\n if (this.canIterate()) {\n // This node is in the running state and can do its initial iteration.\n this.setState(State.RUNNING);\n\n // We may have already completed an iteration, meaning that the child node will be in the SUCCEEDED state.\n // If this is the case then we will have to reset the child node now.\n if (this.child.getState() === State.SUCCEEDED) {\n this.child.reset();\n }\n\n // Update the child of this node.\n this.child.update(agent, options);\n\n // If the child moved into the FAILED state when we updated it then there is nothing left to do and this node has also failed.\n // If it has moved into the SUCCEEDED state then we have completed the current iteration.\n if (this.child.getState() === State.FAILED) {\n // The child has failed, meaning that this node has failed.\n this.setState(State.FAILED);\n\n return;\n } else if (this.child.getState() === State.SUCCEEDED) {\n // We have completed an iteration.\n this.currentIterationCount += 1;\n }\n } else {\n // This node is in the 'SUCCEEDED' state as we cannot iterate any more.\n this.setState(State.SUCCEEDED);\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => {\n if (this.iterations !== null) {\n return `REPEAT ${this.iterations}x`;\n } else if (this.iterationsMin !== null && this.iterationsMax !== null) {\n return `REPEAT ${this.iterationsMin}x-${this.iterationsMax}x`;\n } else {\n return \"REPEAT\";\n }\n };\n\n /**\n * Reset the state of the node.\n */\n reset = () => {\n // Reset the state of this node.\n this.setState(State.READY);\n\n // Reset the current iteration count.\n this.currentIterationCount = 0;\n\n // Reset the child node.\n this.child.reset();\n };\n\n /**\n * Gets whether an iteration can be made.\n * @returns Whether an iteration can be made.\n */\n private canIterate = () => {\n if (this.targetIterationCount !== null) {\n // We can iterate as long as we have not reached our target iteration count.\n return this.currentIterationCount < this.targetIterationCount;\n }\n\n // If neither an iteration count or a condition function were defined then we can iterate indefinitely.\n return true;\n };\n\n /**\n * Sets the target iteration count.\n * @param options The behaviour tree options object.\n */\n private setTargetIterationCount = (options: BehaviourTreeOptions) => {\n // Are we dealing with an explicit iteration count or will we be randomly picking a iteration count between the min and max iteration count.\n if (this.iterations !== null) {\n this.targetIterationCount = this.iterations;\n } else if (this.iterationsMin !== null && this.iterationsMax !== null) {\n // We will be picking a random iteration count between a min and max iteration count, if the optional 'random'\n // behaviour tree function option is defined then we will be using that, otherwise we will fall back to using Math.random.\n const random = typeof options.random === \"function\" ? options.random : Math.random;\n\n // Pick a random iteration count between a min and max iteration count.\n this.targetIterationCount = Math.floor(\n random() * (this.iterationsMax - this.iterationsMin + 1) + this.iterationsMin\n );\n } else {\n this.targetIterationCount = null;\n }\n };\n}\n", "import Node from \"../Node\";\nimport Decorator from \"./Decorator\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A RETRY node.\n * The node has a single child which can have:\n * -- A number of iterations for which to repeat the child node.\n * -- An infinite repeat loop if neither an iteration count or a condition function is defined.\n * The RETRY node will stop and have a 'SUCCEEDED' state if its child is ever in a 'SUCCEEDED' state after an update.\n * The RETRY node will attempt to move on to the next iteration if its child is ever in a 'FAILED' state.\n */\nexport default class Retry extends Decorator {\n /**\n * @param attributes The node attributes.\n * @param attempts The number of attempts to retry the child node.\n * @param attemptsMin The minimum possible number of attempts to retry the child node.\n * @param attemptsMax The maximum possible number of attempts to retry the child node.\n * @param child The child node.\n */\n constructor(\n attributes: Attribute[],\n private attempts: number | null,\n private attemptsMin: number | null,\n private attemptsMax: number | null,\n child: Node\n ) {\n super(\"retry\", attributes, child);\n }\n\n /**\n * The number of target attempts to make.\n */\n private targetAttemptCount: number | null = null;\n\n /**\n * The current attempt count.\n */\n private currentAttemptCount: number = 0;\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // If this node is in the READY state then we need to reset the child and the target attempt count.\n if (this.is(State.READY)) {\n // Reset the child node.\n this.child.reset();\n\n // Reset the current attempt count.\n this.currentAttemptCount = 0;\n\n // Set the target attempt count.\n this.setTargetAttemptCount(options);\n }\n\n // Do a check to see if we can attempt. If we can then this node will move into the 'RUNNING' state.\n // If we cannot attempt then we have hit our target attempt count, which means that the node has succeeded.\n if (this.canAttempt()) {\n // This node is in the running state and can do its initial attempt.\n this.setState(State.RUNNING);\n\n // We may have already completed an attempt, meaning that the child node will be in the FAILED state.\n // If this is the case then we will have to reset the child node now.\n if (this.child.getState() === State.FAILED) {\n this.child.reset();\n }\n\n // Update the child of this node.\n this.child.update(agent, options);\n\n // If the child moved into the SUCCEEDED state when we updated it then there is nothing left to do and this node has also succeeded.\n // If it has moved into the FAILED state then we have completed the current attempt.\n if (this.child.getState() === State.SUCCEEDED) {\n // The child has succeeded, meaning that this node has succeeded.\n this.setState(State.SUCCEEDED);\n\n return;\n } else if (this.child.getState() === State.FAILED) {\n // We have completed an attempt.\n this.currentAttemptCount += 1;\n }\n } else {\n // This node is in the 'FAILED' state as we cannot iterate any more.\n this.setState(State.FAILED);\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => {\n if (this.attempts !== null) {\n return `RETRY ${this.attempts}x`;\n } else if (this.attemptsMin !== null && this.attemptsMax !== null) {\n return `RETRY ${this.attemptsMin}x-${this.attemptsMax}x`;\n } else {\n return \"RETRY\";\n }\n };\n\n /**\n * Reset the state of the node.\n */\n reset = () => {\n // Reset the state of this node.\n this.setState(State.READY);\n\n // Reset the current attempt count.\n this.currentAttemptCount = 0;\n\n // Reset the child node.\n this.child.reset();\n };\n\n /**\n * Gets whether an attempt can be made.\n * @returns Whether an attempt can be made.\n */\n canAttempt = () => {\n if (this.targetAttemptCount !== null) {\n // We can attempt as long as we have not reached our target attempt count.\n return this.currentAttemptCount < this.targetAttemptCount;\n }\n\n // If neither an attempt count or a condition function were defined then we can attempt indefinitely.\n return true;\n };\n\n /**\n * Sets the target attempt count.\n * @param options The behaviour tree options object.\n */\n setTargetAttemptCount = (options: BehaviourTreeOptions) => {\n // Are we dealing with an explicit attempt count or will we be randomly picking an attempt count between the min and max attempt count.\n if (this.attempts !== null) {\n this.targetAttemptCount = this.attempts;\n } else if (this.attemptsMin !== null && this.attemptsMax !== null) {\n // We will be picking a random attempt count between a min and max attempt count, if the optional 'random'\n // behaviour tree function option is defined then we will be using that, otherwise we will fall back to using Math.random.\n const random = typeof options.random === \"function\" ? options.random : Math.random;\n\n // Pick a random attempt count between a min and max attempt count.\n this.targetAttemptCount = Math.floor(\n random() * (this.attemptsMax - this.attemptsMin + 1) + this.attemptsMin\n );\n } else {\n this.targetAttemptCount = null;\n }\n };\n}\n", "import Decorator from \"./Decorator\";\nimport State from \"../../State\";\nimport Node from \"../Node\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A Flip node.\n * This node wraps a single child and will flip the state of the child state.\n */\nexport default class Flip extends Decorator {\n /**\n * @param attributes The node attributes.\n * @param child The child node.\n */\n constructor(attributes: Attribute[], child: Node) {\n super(\"flip\", attributes, child);\n }\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // If the child has never been updated or is running then we will need to update it now.\n if (this.child.getState() === State.READY || this.child.getState() === State.RUNNING) {\n this.child.update(agent, options);\n }\n\n // The state of this node will depend in the state of its child.\n switch (this.child.getState()) {\n case State.RUNNING:\n this.setState(State.RUNNING);\n break;\n\n case State.SUCCEEDED:\n this.setState(State.FAILED);\n break;\n\n case State.FAILED:\n this.setState(State.SUCCEEDED);\n break;\n\n default:\n this.setState(State.READY);\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => \"FLIP\";\n}\n", "import Node from \"../Node\";\nimport Decorator from \"./Decorator\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A Succeed node.\n * This node wraps a single child and will always move to the 'SUCCEEDED' state when the child moves to a 'SUCCEEDED' or 'FAILED' state.\n */\nexport default class Succeed extends Decorator {\n /**\n * @param attributes The node attributes.\n * @param child The child node.\n */\n constructor(attributes: Attribute[], child: Node) {\n super(\"succeed\", attributes, child);\n }\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // If the child has never been updated or is running then we will need to update it now.\n if (this.child.getState() === State.READY || this.child.getState() === State.RUNNING) {\n this.child.update(agent, options);\n }\n\n // The state of this node will depend in the state of its child.\n switch (this.child.getState()) {\n case State.RUNNING:\n this.setState(State.RUNNING);\n break;\n\n case State.SUCCEEDED:\n case State.FAILED:\n this.setState(State.SUCCEEDED);\n break;\n\n default:\n this.setState(State.READY);\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => \"SUCCEED\";\n}\n", "import Node from \"../Node\";\nimport Decorator from \"./Decorator\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A Fail node.\n * This node wraps a single child and will always move to the 'FAILED' state when the child moves to a 'SUCCEEDED' or 'FAILED' state.\n */\nexport default class Fail extends Decorator {\n /**\n * @param attributes The node attributes.\n * @param child The child node.\n */\n constructor(attributes: Attribute[], child: Node) {\n super(\"fail\", attributes, child);\n }\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // If the child has never been updated or is running then we will need to update it now.\n if (this.child.getState() === State.READY || this.child.getState() === State.RUNNING) {\n this.child.update(agent, options);\n }\n\n // The state of this node will depend in the state of its child.\n switch (this.child.getState()) {\n case State.RUNNING:\n this.setState(State.RUNNING);\n break;\n\n case State.SUCCEEDED:\n case State.FAILED:\n this.setState(State.FAILED);\n break;\n\n default:\n this.setState(State.READY);\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => \"FAIL\";\n}\n", "import createLotto from \"lotto-draw\";\n\nimport Node from \"../Node\";\nimport Composite from \"./Composite\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A LOTTO node.\n * A winning child is picked on the initial update of this node, based on ticket weighting.\n * The state of this node will match the state of the winning child.\n */\nexport default class Lotto extends Composite {\n /**\n * @param attributes The node attributes.\n * @param tickets The child node tickets.\n * @param children The child nodes.\n */\n constructor(attributes: Attribute[], private tickets: number[], children: Node[]) {\n super(\"lotto\", attributes, children);\n }\n\n /**\n * The child node selected to be the active one.\n */\n private selectedChild: Node | undefined;\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // If this node is in the READY state then we need to pick a winning child node.\n if (this.is(State.READY)) {\n // Create a lotto draw with which to randomly pick a child node to become the active one.\n const lottoDraw = createLotto({\n // Hook up the optional 'random' behaviour tree function option to the one used by 'lotto-draw'.\n random: options.random,\n // Pass in each child node as a participant in the lotto draw with their respective ticket count.\n participants: this.children.map((child, index) => [child, this.tickets[index] || 1])\n });\n\n // Randomly pick a child based on ticket weighting, this will become the active child for this composite node.\n this.selectedChild = lottoDraw.draw() || undefined;\n }\n\n // If something went wrong and we don't have an active child then we should throw an error.\n if (!this.selectedChild) {\n throw new Error(\"failed to update lotto node as it has no active child\");\n }\n\n // If the selected child has never been updated or is running then we will need to update it now.\n if (this.selectedChild.getState() === State.READY || this.selectedChild.getState() === State.RUNNING) {\n this.selectedChild.update(agent, options);\n }\n\n // The state of the lotto node is the state of its selected child.\n this.setState(this.selectedChild.getState());\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => (this.tickets.length ? `LOTTO [${this.tickets.join(\",\")}]` : \"LOTTO\");\n}\n", "import Node from \"../Node\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\n\n/**\n * A composite node that wraps child nodes.\n */\nexport default abstract class Composite extends Node {\n /**\n * @param type The node type.\n * @param attributes The node attributes.\n * @param children The child nodes.\n */\n constructor(type: string, attributes: Attribute[], protected children: Node[]) {\n super(type, attributes, []);\n }\n\n /**\n * Gets whether this node is a leaf node.\n */\n isLeafNode = () => false;\n\n /**\n * Gets the children of this node.\n */\n getChildren = () => this.children;\n\n /**\n * Reset the state of the node.\n */\n reset = () => {\n // Reset the state of this node.\n this.setState(State.READY);\n\n // Reset the state of any child nodes.\n this.getChildren().forEach((child) => child.reset());\n };\n\n /**\n * Abort the running of this node.\n * @param agent The agent.\n */\n abort = (agent: Agent) => {\n // There is nothing to do if this node is not in the running state.\n if (!this.is(State.RUNNING)) {\n return;\n }\n\n // Abort any child nodes.\n this.getChildren().forEach((child) => child.abort(agent));\n\n // Reset the state of this node.\n this.reset();\n\n this.getAttribute(\"exit\")?.callAgentFunction(agent, false, true);\n };\n}\n", "import Composite from \"./Composite\";\nimport Node from \"../Node\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A SELECTOR node.\n * The child nodes are executed in sequence until one succeeds or all fail.\n */\nexport default class Selector extends Composite {\n /**\n * @param attributes The node attributes.\n * @param children The child nodes.\n */\n constructor(attributes: Attribute[], protected children: Node[]) {\n super(\"selector\", attributes, children);\n }\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // Iterate over all of the children of this node.\n for (const child of this.children) {\n // If the child has never been updated or is running then we will need to update it now.\n if (child.getState() === State.READY || child.getState() === State.RUNNING) {\n // Update the child of this node.\n child.update(agent, options);\n }\n\n // If the current child has a state of 'SUCCEEDED' then this node is also a 'SUCCEEDED' node.\n if (child.getState() === State.SUCCEEDED) {\n // This node is a 'SUCCEEDED' node.\n this.setState(State.SUCCEEDED);\n\n // There is no need to check the rest of the selector nodes.\n return;\n }\n\n // If the current child has a state of 'FAILED' then we should move on to the next child.\n if (child.getState() === State.FAILED) {\n // Find out if the current child is the last one in the selector.\n // If it is then this sequence node has also failed.\n if (this.children.indexOf(child) === this.children.length - 1) {\n // This node is a 'FAILED' node.\n this.setState(State.FAILED);\n\n // There is no need to check the rest of the selector as we have completed it.\n return;\n } else {\n // The child node failed, try the next one.\n continue;\n }\n }\n\n // The node should be in the 'RUNNING' state.\n if (child.getState() === State.RUNNING) {\n // This node is a 'RUNNING' node.\n this.setState(State.RUNNING);\n\n // There is no need to check the rest of the selector as the current child is still running.\n return;\n }\n\n // The child node was not in an expected state.\n throw new Error(\"child node was not in an expected state.\");\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => \"SELECTOR\";\n}\n", "import Composite from \"./Composite\";\nimport Node from \"../Node\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A SEQUENCE node.\n * The child nodes are executed in sequence until one fails or all succeed.\n */\nexport default class Sequence extends Composite {\n /**\n * @param attributes The node attributes.\n * @param children The child nodes.\n */\n constructor(attributes: Attribute[], protected children: Node[]) {\n super(\"sequence\", attributes, children);\n }\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // Iterate over all of the children of this node.\n for (const child of this.children) {\n // If the child has never been updated or is running then we will need to update it now.\n if (child.getState() === State.READY || child.getState() === State.RUNNING) {\n // Update the child of this node.\n child.update(agent, options);\n }\n\n // If the current child has a state of 'SUCCEEDED' then we should move on to the next child.\n if (child.getState() === State.SUCCEEDED) {\n // Find out if the current child is the last one in the sequence.\n // If it is then this sequence node has also succeeded.\n if (this.children.indexOf(child) === this.children.length - 1) {\n // This node is a 'SUCCEEDED' node.\n this.setState(State.SUCCEEDED);\n\n // There is no need to check the rest of the sequence as we have completed it.\n return;\n } else {\n // The child node succeeded, but we have not finished the sequence yet.\n continue;\n }\n }\n\n // If the current child has a state of 'FAILED' then this node is also a 'FAILED' node.\n if (child.getState() === State.FAILED) {\n // This node is a 'FAILED' node.\n this.setState(State.FAILED);\n\n // There is no need to check the rest of the sequence.\n return;\n }\n\n // The node should be in the 'RUNNING' state.\n if (child.getState() === State.RUNNING) {\n // This node is a 'RUNNING' node.\n this.setState(State.RUNNING);\n\n // There is no need to check the rest of the sequence as the current child is still running.\n return;\n }\n\n // The child node was not in an expected state.\n throw new Error(\"child node was not in an expected state.\");\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => \"SEQUENCE\";\n}\n", "import Composite from \"./Composite\";\nimport State from \"../../State\";\nimport Node from \"../Node\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A PARALLEL node.\n * The child nodes are executed concurrently until one fails or all succeed.\n */\nexport default class Parallel extends Composite {\n /**\n * @param attributes The node attributes.\n * @param children The child nodes.\n */\n constructor(attributes: Attribute[], children: Node[]) {\n super(\"parallel\", attributes, children);\n }\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // Keep a count of the number of succeeded child nodes.\n let succeededCount = 0;\n\n let hasChildFailed = false;\n\n // Iterate over all of the children of this node.\n for (const child of this.children) {\n // If the child has never been updated or is running then we will need to update it now.\n if (child.getState() === State.READY || child.getState() === State.RUNNING) {\n // Update the child of this node.\n child.update(agent, options);\n }\n\n // If the current child has a state of 'SUCCEEDED' then we should move on to the next child.\n if (child.getState() === State.SUCCEEDED) {\n // The child node has succeeded, keep track of this to determine if all children have.\n succeededCount++;\n\n // The child node succeeded, but we have not finished checking every child node yet.\n continue;\n }\n\n // If the current child has a state of 'FAILED' then this node is also a 'FAILED' node.\n if (child.getState() === State.FAILED) {\n hasChildFailed = true;\n\n // There is no need to check the rest of the children.\n break;\n }\n\n // The node should be in the 'RUNNING' state.\n if (child.getState() !== State.RUNNING) {\n // The child node was not in an expected state.\n throw new Error(\"child node was not in an expected state.\");\n }\n }\n\n if (hasChildFailed) {\n // This node is a 'FAILED' node.\n this.setState(State.FAILED);\n\n // Abort every running child.\n for (const child of this.children) {\n if (child.getState() === State.RUNNING) {\n child.abort(agent);\n }\n }\n } else {\n // If all children have succeeded then this node has also succeeded, otherwise it is still running.\n this.setState(succeededCount === this.children.length ? State.SUCCEEDED : State.RUNNING);\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => \"PARALLEL\";\n}\n", "import { AnyArgument } from \"../RootAstNodesBuilder\";\nimport Guard from \"./guards/Guard\";\n\nexport type AttributeDetails = {\n /** The attribute type. */\n type: string;\n\n /** The attribute arguments. */\n args: AnyArgument[];\n};\n\n/**\n * A base node attribute.\n */\nexport default abstract class Attribute {\n /**\n * @param type The node attribute type.\n * @param args The array of attribute argument definitions.\n */\n constructor(protected type: string, protected args: AnyArgument[]) {}\n\n /**\n * Gets the type of the attribute.\n */\n getType = () => this.type;\n\n /**\n * Gets the array of attribute argument definitions.\n */\n getArguments = () => this.args;\n\n /**\n * Gets the attribute details.\n */\n abstract getDetails(): TAttributeDetails;\n\n /**\n * Gets whether this attribute is a guard.\n */\n abstract isGuard: () => this is Guard;\n}\n", "import { Agent } from \"../../Agent\";\nimport { AnyArgument } from \"../../RootAstNodesBuilder\";\nimport Attribute, { AttributeDetails } from \"../Attribute\";\n\nexport type GuardAttributeDetails = {\n /** The name of the condition function that determines whether the guard is satisfied. */\n condition: string;\n} & AttributeDetails;\n\n/**\n * A base node guard attribute.\n */\nexport default abstract class Guard extends Attribute {\n /**\n * @param type The node attribute type.\n * @param args The array of decorator argument definitions.\n * @param condition The name of the condition function that determines whether the guard is satisfied.\n */\n constructor(type: string, args: AnyArgument[], private condition: string) {\n super(type, args);\n }\n\n /**\n * Gets the name of the condition function that determines whether the guard is satisfied.\n */\n getCondition = () => this.condition;\n\n /**\n * Gets whether this attribute is a guard.\n */\n isGuard = () => true;\n\n /**\n * Gets the attribute details.\n */\n getDetails(): GuardAttributeDetails {\n return {\n type: this.getType(),\n args: this.getArguments(),\n condition: this.getCondition()\n };\n }\n\n /**\n * Gets whether the guard is satisfied.\n * @param agent The agent.\n * @returns Whether the guard is satisfied.\n */\n abstract isSatisfied(agent: Agent): boolean;\n}\n", "import Guard from \"./Guard\";\nimport Lookup from \"../../Lookup\";\nimport { Agent } from \"../../Agent\";\nimport { AnyArgument } from \"../../RootAstNodesBuilder\";\n\n/**\n * A WHILE guard which is satisfied as long as the given condition remains true.\n */\nexport default class While extends Guard {\n /**\n * @param condition The name of the condition function that determines whether the guard is satisfied.\n * @param args The array of decorator argument definitions.\n */\n constructor(condition: string, args: AnyArgument[]) {\n super(\"while\", args, condition);\n }\n\n /**\n * Gets whether the guard is satisfied.\n * @param agent The agent.\n * @returns Whether the guard is satisfied.\n */\n isSatisfied = (agent: Agent) => {\n // Attempt to get the invoker for the condition function.\n const conditionFuncInvoker = Lookup.getFuncInvoker(agent, this.getCondition());\n\n // The condition function should be defined.\n if (conditionFuncInvoker === null) {\n throw new Error(\n `cannot evaluate node guard as the condition '${this.getCondition()}' function is not defined on the agent and has not been registered`\n );\n }\n\n // Call the condition function to determine whether this guard is satisfied.\n return !!conditionFuncInvoker(this.args);\n };\n}\n", "import Guard from \"./Guard\";\nimport Lookup from \"../../Lookup\";\nimport { Agent } from \"../../Agent\";\nimport { AnyArgument } from \"../../RootAstNodesBuilder\";\n\n/**\n * An UNTIL guard which is satisfied as long as the given condition remains false.\n */\nexport default class Until extends Guard {\n /**\n * @param condition The name of the condition function that determines whether the guard is satisfied.\n * @param args The array of decorator argument definitions.\n */\n constructor(condition: string, args: AnyArgument[]) {\n super(\"until\", args, condition);\n }\n\n /**\n * Gets whether the guard is satisfied.\n * @param agent The agent.\n * @returns Whether the guard is satisfied.\n */\n isSatisfied = (agent: Agent) => {\n // Attempt to get the invoker for the condition function.\n const conditionFuncInvoker = Lookup.getFuncInvoker(agent, this.getCondition());\n\n // The condition function should be defined.\n if (conditionFuncInvoker === null) {\n throw new Error(\n `cannot evaluate node guard as the condition '${this.getCondition()}' function is not defined on the agent and has not been registered`\n );\n }\n\n // Call the condition function to determine whether this guard is satisfied.\n return !!!conditionFuncInvoker(this.args);\n };\n}\n", "import { Agent } from \"../../Agent\";\nimport { AnyArgument } from \"../../RootAstNodesBuilder\";\nimport Attribute, { AttributeDetails } from \"../Attribute\";\n\nexport type CallbackAttributeDetails = {\n /** The name of the agent function that is called. */\n functionName: string;\n} & AttributeDetails;\n\n/**\n * A base node callback attribute.\n */\nexport default abstract class Callback extends Attribute {\n /**\n * @param type The node attribute type.\n * @param args The array of decorator argument definitions.\n * @param functionName The name of the agent function to call.\n */\n constructor(type: string, args: AnyArgument[], private functionName: string) {\n super(type, args);\n }\n\n /**\n * Gets the name of the agent function to call.\n */\n getFunctionName = () => this.functionName;\n\n /**\n * Gets whether this attribute is a guard.\n */\n isGuard = () => false;\n\n /**\n * Gets the attribute details.\n */\n getDetails(): CallbackAttributeDetails {\n return {\n type: this.getType(),\n args: this.getArguments(),\n functionName: this.getFunctionName()\n };\n }\n\n /**\n * Attempt to call the agent function that this callback refers to.\n * @param agent The agent.\n */\n abstract callAgentFunction: (agent: Agent, isSuccess: boolean, isAborted: boolean) => void;\n}\n", "import Callback from \"./Callback\";\nimport Lookup from \"../../Lookup\";\nimport { Agent } from \"../../Agent\";\nimport { AnyArgument } from \"../../RootAstNodesBuilder\";\n\n/**\n * An ENTRY callback which defines an agent function to call when the associated node is updated and moves out of running state.\n */\nexport default class Entry extends Callback {\n /**\n * @param functionName The name of the agent function to call.\n * @param args The array of callback argument definitions.\n */\n constructor(functionName: string, args: AnyArgument[]) {\n super(\"entry\", args, functionName);\n }\n\n /**\n * Attempt to call the agent function that this callback refers to.\n * @param agent The agent.\n */\n callAgentFunction = (agent: Agent) => {\n // Attempt to get the invoker for the callback function.\n const callbackFuncInvoker = Lookup.getFuncInvoker(agent, this.getFunctionName());\n\n // The callback function should be defined.\n if (callbackFuncInvoker === null) {\n throw new Error(\n `cannot call entry function '${this.getFunctionName()}' as is not defined on the agent and has not been registered`\n );\n }\n\n // Call the callback function.\n callbackFuncInvoker(this.args);\n };\n}\n", "import Callback from \"./Callback\";\nimport Lookup, { AnyExitArgument } from \"../../Lookup\";\nimport { Agent } from \"../../Agent\";\nimport { AnyArgument } from \"../../RootAstNodesBuilder\";\n\n/**\n * An EXIT callback which defines an agent function to call when the associated node is updated and moves to a finished state or is aborted.\n */\nexport default class Exit extends Callback {\n /**\n * @param functionName The name of the agent function to call.\n * @param args The array of callback argument definitions.\n */\n constructor(functionName: string, args: AnyArgument[]) {\n super(\"exit\", args, functionName);\n }\n\n /**\n * Attempt to call the agent function that this callback refers to.\n * @param agent The agent.\n * @param isSuccess Whether the decorated node was left with a success state.\n * @param isAborted Whether the decorated node was aborted.\n */\n callAgentFunction = (agent: Agent, isSuccess: boolean, isAborted: boolean) => {\n // Attempt to get the invoker for the callback function.\n const callbackFuncInvoker = Lookup.getFuncInvoker(agent, this.getFunctionName());\n\n // The callback function should be defined.\n if (callbackFuncInvoker === null) {\n throw new Error(\n `cannot call exit function '${this.getFunctionName()}' as is not defined on the agent and has not been registered`\n );\n }\n\n // Call the callback function\n callbackFuncInvoker([{ value: { succeeded: isSuccess, aborted: isAborted } }, ...this.args]);\n };\n}\n", "import Callback from \"./Callback\";\nimport Lookup from \"../../Lookup\";\nimport { Agent } from \"../../Agent\";\nimport { AnyArgument } from \"../../RootAstNodesBuilder\";\n\n/**\n * A STEP callback which defines an agent function to call when the associated node is updated.\n */\nexport default class Step extends Callback {\n /**\n * @param functionName The name of the agent function to call.\n * @param args The array of callback argument definitions.\n */\n constructor(functionName: string, args: AnyArgument[]) {\n super(\"step\", args, functionName);\n }\n\n /**\n * Attempt to call the agent function that this callback refers to.\n * @param agent The agent.\n */\n callAgentFunction = (agent: Agent) => {\n // Attempt to get the invoker for the callback function.\n const callbackFuncInvoker = Lookup.getFuncInvoker(agent, this.getFunctionName());\n\n // The callback function should be defined.\n if (callbackFuncInvoker === null) {\n throw new Error(\n `cannot call step function '${this.getFunctionName()}' as is not defined on the agent and has not been registered`\n );\n }\n\n // Call the callback function.\n callbackFuncInvoker(this.args);\n };\n}\n", "import Action from \"./nodes/leaf/Action\";\nimport Condition from \"./nodes/leaf/Condition\";\nimport Wait from \"./nodes/leaf/Wait\";\nimport Root from \"./nodes/decorator/Root\";\nimport Repeat from \"./nodes/decorator/Repeat\";\nimport Retry from \"./nodes/decorator/Retry\";\nimport Flip from \"./nodes/decorator/Flip\";\nimport Succeed from \"./nodes/decorator/Succeed\";\nimport Fail from \"./nodes/decorator/Fail\";\nimport Lotto from \"./nodes/composite/Lotto\";\nimport Selector from \"./nodes/composite/Selector\";\nimport Sequence from \"./nodes/composite/Sequence\";\nimport Parallel from \"./nodes/composite/Parallel\";\nimport Node from \"./nodes/Node\";\nimport While from \"./attributes/guards/While\";\nimport Until from \"./attributes/guards/Until\";\nimport Entry from \"./attributes/callbacks/Entry\";\nimport Exit from \"./attributes/callbacks/Exit\";\nimport Step from \"./attributes/callbacks/Step\";\nimport Callback from \"./attributes/callbacks/Callback\";\nimport Guard from \"./attributes/guards/Guard\";\nimport Attribute from \"./attributes/Attribute\";\nimport Composite from \"./nodes/composite/Composite\";\nimport Decorator from \"./nodes/decorator/Decorator\";\nimport Leaf from \"./nodes/leaf/Leaf\";\n\nexport type Argument = {\n value: T;\n type: string; // Used for validation.\n};\ntype NullArgument = Argument & {\n type: \"null\";\n};\ntype BooleanArgument = Argument & {\n type: \"boolean\";\n};\ntype NumberArgument = Argument & {\n type: \"number\";\n isInteger: boolean; // Used for validation.\n};\ntype StringPlaceholderArgument = Argument & {\n type: \"string\";\n};\ntype IdentifierArgument = Argument & {\n type: \"identifier\";\n};\nexport type AnyArgument =\n | NullArgument\n | BooleanArgument\n | NumberArgument\n | StringPlaceholderArgument\n | IdentifierArgument;\n\n/**\n * The node attribute factories.\n */\nconst AttributeFactories: {\n [key: string]: (functionName: string, attributeArguments: AnyArgument[]) => Callback | Guard;\n} = {\n WHILE: (condition: string, attributeArguments: AnyArgument[]) => new While(condition, attributeArguments),\n UNTIL: (condition: string, attributeArguments: AnyArgument[]) => new Until(condition, attributeArguments),\n ENTRY: (functionName: string, attributeArguments: AnyArgument[]) => new Entry(functionName, attributeArguments),\n EXIT: (functionName: string, attributeArguments: AnyArgument[]) => new Exit(functionName, attributeArguments),\n STEP: (functionName: string, attributeArguments: AnyArgument[]) => new Step(functionName, attributeArguments)\n};\n\ntype Validatable = {\n children?: AstNode[];\n validate: (depth: number) => void;\n};\n\ntype NodeInstanceCreator = (\n namedRootNodeProvider: (name: string) => RootAstNode,\n visitedBranches: string[]\n) => T;\n\nexport type AstNode = Validatable & {\n type: string;\n createNodeInstance: NodeInstanceCreator;\n};\n\nexport type LeafAstNode = AstNode & {\n type: \"action\" | \"condition\" | \"wait\";\n attributes: Attribute[];\n};\n\nexport type CompositeAstNode = AstNode & {\n type: \"lotto\" | \"parallel\" | \"selector\" | \"sequence\";\n attributes: Attribute[];\n children: AstNode[];\n};\n\nexport type DecoratorAstNode = AstNode & {\n type: \"fail\" | \"flip\" | \"repeat\" | \"retry\" | \"root\" | \"succeed\";\n attributes: Attribute[];\n children: AstNode[];\n};\n\nexport type BranchAstNode = AstNode & {\n type: \"branch\";\n branchName: \"\" | string;\n};\n\nexport type LottoAstNode = CompositeAstNode & {\n type: \"lotto\";\n tickets: number[];\n};\n\nexport type RootAstNode = DecoratorAstNode & {\n type: \"root\";\n name: null | string;\n};\n\nexport type RepeatAstNode = DecoratorAstNode & {\n type: \"repeat\";\n iterations: number | null;\n iterationsMin: number | null;\n iterationsMax: number | null;\n};\n\nexport type RetryAstNode = DecoratorAstNode & {\n type: \"retry\";\n attempts: number | null;\n attemptsMin: number | null;\n attemptsMax: number | null;\n};\n\nexport type ActionAstNode = LeafAstNode & {\n type: \"action\";\n actionName: string;\n actionArguments: AnyArgument[];\n};\n\nexport type ConditionAstNode = LeafAstNode & {\n type: \"condition\";\n conditionName: string;\n conditionArguments: AnyArgument[];\n};\n\nexport type WaitAstNode = LeafAstNode & {\n type: \"wait\";\n duration: number | null;\n durationMin: number | null;\n durationMax: number | null;\n};\n\nexport type AnyAstNode =\n | BranchAstNode\n | CompositeAstNode\n | LottoAstNode\n | DecoratorAstNode\n | RootAstNode\n | RepeatAstNode\n | RetryAstNode\n | LeafAstNode\n | ActionAstNode\n | ConditionAstNode\n | WaitAstNode;\n\n/**\n * The AST node factories.\n */\nconst ASTNodeFactories = {\n ROOT: (): RootAstNode => ({\n type: \"root\",\n attributes: [],\n name: null,\n children: [],\n validate(depth: number) {\n // A root node cannot be the child of another node.\n if (depth > 1) {\n throw new Error(\"a root node cannot be the child of another node\");\n }\n\n // A root node must have a single child node.\n if (this.children.length !== 1) {\n throw new Error(\"a root node must have a single child\");\n }\n },\n createNodeInstance(namedRootNodeProvider, visitedBranches) {\n return new Root(\n this.attributes,\n this.children![0].createNodeInstance(namedRootNodeProvider, visitedBranches.slice())\n );\n }\n }),\n BRANCH: (): BranchAstNode => ({\n type: \"branch\",\n branchName: \"\",\n validate() {},\n createNodeInstance(namedRootNodeProvider, visitedBranches) {\n // Try to find the root node with a matching branch name.\n const targetRootNode = namedRootNodeProvider(this.branchName);\n\n // If we have already visited this branch then we have a circular dependency.\n if (visitedBranches.indexOf(this.branchName) !== -1) {\n throw new Error(`circular dependency found in branch node references for branch '${this.branchName}'`);\n }\n\n // If we have a target root node, then the node instance we want will be the first and only child of the referenced root node.\n if (targetRootNode) {\n return targetRootNode\n .createNodeInstance(namedRootNodeProvider, visitedBranches.concat(this.branchName))\n .getChildren()[0];\n } else {\n throw new Error(`branch references root node '${this.branchName}' which has not been defined`);\n }\n }\n }),\n SELECTOR: (): CompositeAstNode => ({\n type: \"selector\",\n attributes: [],\n children: [],\n validate() {\n // A selector node must have at least a single node.\n if (this.children.length < 1) {\n throw new Error(\"a selector node must have at least a single child\");\n }\n },\n createNodeInstance(namedRootNodeProvider, visitedBranches) {\n return new Selector(\n this.attributes,\n this.children.map((child) => child.createNodeInstance(namedRootNodeProvider, visitedBranches.slice()))\n );\n }\n }),\n SEQUENCE: (): CompositeAstNode => ({\n type: \"sequence\",\n attributes: [],\n children: [],\n validate() {\n // A sequence node must have at least a single node.\n if (this.children.length < 1) {\n throw new Error(\"a sequence node must have at least a single child\");\n }\n },\n createNodeInstance(namedRootNodeProvider, visitedBranches) {\n return new Sequence(\n this.attributes,\n this.children.map((child) => child.createNodeInstance(namedRootNodeProvider, visitedBranches.slice()))\n );\n }\n }),\n PARALLEL: (): CompositeAstNode => ({\n type: \"parallel\",\n attributes: [],\n children: [],\n validate() {\n // A parallel node must have at least a single node.\n if (this.children.length < 1) {\n throw new Error(\"a parallel node must have at least a single child\");\n }\n },\n createNodeInstance(namedRootNodeProvider, visitedBranches) {\n return new Parallel(\n this.attributes,\n this.children.map((child) => child.createNodeInstance(namedRootNodeProvider, visitedBranches.slice()))\n );\n }\n }),\n LOTTO: (): LottoAstNode => ({\n type: \"lotto\",\n attributes: [],\n children: [],\n tickets: [],\n validate() {\n // A lotto node must have at least a single node.\n if (this.children!.length < 1) {\n throw new Error(\"a lotto node must have at least a single child\");\n }\n },\n createNodeInstance(namedRootNodeProvider, visitedBranches) {\n return new Lotto(\n this.attributes,\n this.tickets!,\n this.children!.map((child) => child.createNodeInstance(namedRootNodeProvider, visitedBranches.slice()))\n );\n }\n }),\n REPEAT: (): RepeatAstNode => ({\n type: \"repeat\",\n attributes: [],\n iterations: null,\n iterationsMin: null,\n iterationsMax: null,\n children: [],\n validate() {\n // A repeat node must have a single node.\n if (this.children!.length !== 1) {\n throw new Error(\"a repeat node must have a single child\");\n }\n\n if (this.iterations !== null) {\n // A repeat node must have a positive number of iterations if defined.\n if (this.iterations < 0) {\n throw new Error(\"a repeat node must have a positive number of iterations if defined\");\n }\n } else if (this.iterationsMin !== null && this.iterationsMax !== null) {\n // A repeat node must have a positive min and max iteration count if they are defined.\n if (this.iterationsMin < 0 || this.iterationsMax < 0) {\n throw new Error(\n \"a repeat node must have a positive minimum and maximum iteration count if defined\"\n );\n }\n\n // A repeat node must not have an minimum iteration count that exceeds the maximum iteration count.\n if (this.iterationsMin > this.iterationsMax) {\n throw new Error(\n \"a repeat node must not have a minimum iteration count that exceeds the maximum iteration count\"\n );\n }\n } else {\n // If we have no explicit iteration count or a minimum and maximum iteration count set then we are dealing with a repeat node that iterates indefinitely.\n }\n },\n createNodeInstance(namedRootNodeProvider, visitedBranches) {\n return new Repeat(\n this.attributes,\n this.iterations,\n this.iterationsMin,\n this.iterationsMax,\n this.children![0].createNodeInstance(namedRootNodeProvider, visitedBranches.slice())\n );\n }\n }),\n RETRY: (): RetryAstNode => ({\n type: \"retry\",\n attributes: [],\n attempts: null,\n attemptsMin: null,\n attemptsMax: null,\n children: [],\n validate() {\n // A retry node must have a single node.\n if (this.children!.length !== 1) {\n throw new Error(\"a retry node must have a single child\");\n }\n\n if (this.attempts !== null) {\n // A retry node must have a positive number of attempts if defined.\n if (this.attempts < 0) {\n throw new Error(\"a retry node must have a positive number of attempts if defined\");\n }\n } else if (this.attemptsMin !== null && this.attemptsMax !== null) {\n // A retry node must have a positive min and max attempts count if they are defined.\n if (this.attemptsMin < 0 || this.attemptsMax < 0) {\n throw new Error(\"a retry node must have a positive minimum and maximum attempt count if defined\");\n }\n\n // A retry node must not have a minimum attempt count that exceeds the maximum attempt count.\n if (this.attemptsMin > this.attemptsMax) {\n throw new Error(\n \"a retry node must not have a minimum attempt count that exceeds the maximum attempt count\"\n );\n }\n } else {\n // If we have no explicit attempt count or a minimum and maximum attempt count set then we are dealing with a retry node that attempts indefinitely.\n }\n },\n createNodeInstance(namedRootNodeProvider, visitedBranches) {\n return new Retry(\n this.attributes,\n this.attempts,\n this.attemptsMin,\n this.attemptsMax,\n this.children![0].createNodeInstance(namedRootNodeProvider, visitedBranches.slice())\n );\n }\n }),\n FLIP: (): DecoratorAstNode => ({\n type: \"flip\",\n attributes: [],\n children: [],\n validate() {\n // A flip node must have a single node.\n if (this.children!.length !== 1) {\n throw new Error(\"a flip node must have a single child\");\n }\n },\n createNodeInstance(namedRootNodeProvider, visitedBranches) {\n return new Flip(\n this.attributes,\n this.children![0].createNodeInstance(namedRootNodeProvider, visitedBranches.slice())\n );\n }\n }),\n SUCCEED: (): DecoratorAstNode => ({\n type: \"succeed\",\n attributes: [],\n children: [],\n validate() {\n // A succeed node must have a single node.\n if (this.children!.length !== 1) {\n throw new Error(\"a succeed node must have a single child\");\n }\n },\n createNodeInstance(namedRootNodeProvider, visitedBranches) {\n return new Succeed(\n this.attributes,\n this.children![0].createNodeInstance(namedRootNodeProvider, visitedBranches.slice())\n );\n }\n }),\n FAIL: (): DecoratorAstNode => ({\n type: \"fail\",\n attributes: [],\n children: [],\n validate() {\n // A fail node must have a single node.\n if (this.children!.length !== 1) {\n throw new Error(\"a fail node must have a single child\");\n }\n },\n createNodeInstance(namedRootNodeProvider, visitedBranches) {\n return new Fail(\n this.attributes,\n this.children![0].createNodeInstance(namedRootNodeProvider, visitedBranches.slice())\n );\n }\n }),\n WAIT: (): WaitAstNode => ({\n type: \"wait\",\n attributes: [],\n duration: null,\n durationMin: null,\n durationMax: null,\n validate() {\n if (this.duration !== null) {\n // If an explict duration was defined then it must be a positive number.\n if (this.duration < 0) {\n throw new Error(\"a wait node must have a positive duration\");\n }\n } else if (this.durationMin !== null && this.durationMax !== null) {\n // A wait node must have a positive min and max duration.\n if (this.durationMin < 0 || this.durationMax < 0) {\n throw new Error(\"a wait node must have a positive minimum and maximum duration\");\n }\n\n // A wait node must not have a minimum duration that exceeds the maximum duration.\n if (this.durationMin > this.durationMax) {\n throw new Error(\"a wait node must not have a minimum duration that exceeds the maximum duration\");\n }\n } else {\n // If we have no explicit duration or duration bounds set then we are dealing with a wait node that waits indefinitely.\n }\n },\n createNodeInstance() {\n return new Wait(this.attributes, this.duration, this.durationMin, this.durationMax);\n }\n }),\n ACTION: (): ActionAstNode => ({\n type: \"action\",\n attributes: [],\n actionName: \"\",\n actionArguments: [],\n validate() {},\n createNodeInstance() {\n return new Action(this.attributes, this.actionName!, this.actionArguments!);\n }\n }),\n CONDITION: (): ConditionAstNode => ({\n type: \"condition\",\n attributes: [],\n conditionName: \"\",\n conditionArguments: [],\n validate() {},\n createNodeInstance() {\n return new Condition(this.attributes, this.conditionName!, this.conditionArguments!);\n }\n })\n};\n\ntype OtherAstNodes = AstNode[];\n\n/**\n * Create an array of root AST nodes based on the given definition.\n * @param definition The definition to parse the AST nodes from.\n * @returns The base definition AST nodes.\n */\nexport default function buildRootASTNodes(definition: string): RootAstNode[] {\n // Swap out any node/attribute argument string literals with a placeholder and get a mapping of placeholders to original values as well as the processed definition.\n const { placeholders, processedDefinition } = substituteStringLiterals(definition);\n\n // Convert the processed definition (with substituted string literals) into an array of raw tokens.\n const tokens = parseTokensFromDefinition(processedDefinition);\n\n // There must be at least 3 tokens for the tree definition to be valid. 'ROOT', '{' and '}'.\n if (tokens.length < 3) {\n throw new Error(\"invalid token count\");\n }\n\n // We should have a matching number of '{' and '}' tokens. If not, then there are scopes that have not been properly closed.\n if (tokens.filter((token) => token === \"{\").length !== tokens.filter((token) => token === \"}\").length) {\n throw new Error(\"scope character mismatch\");\n }\n\n // Create a stack of node children arrays, starting with a definition scope.\n const stack: [RootAstNode[], ...OtherAstNodes[]] = [[]];\n const rootScope = stack[0];\n\n // We should keep processing the raw tokens until we run out of them.\n while (tokens.length) {\n // Grab the next token.\n const token = tokens.shift();\n\n const currentScope = stack[stack.length - 1] as OtherAstNodes;\n\n // How we create the next AST token depends on the current raw token value.\n switch (token!.toUpperCase()) {\n case \"ROOT\": {\n // Create a ROOT AST node.\n const node = ASTNodeFactories.ROOT();\n\n // Push the ROOT node into the current scope.\n rootScope.push(node);\n\n // We may have a root node name defined as an argument.\n if (tokens[0] === \"[\") {\n const rootArguments = getArguments(tokens, placeholders);\n\n // We should have only a single argument that is not an empty string for a root node, which is the root name identifier.\n if (rootArguments.length === 1 && rootArguments[0].type === \"identifier\") {\n // The root name will be the first and only node argument.\n node.name = rootArguments[0].value as string;\n } else {\n throw new Error(\"expected single root name argument\");\n }\n }\n\n // Try to pick any attributes off of the token stack.\n node.attributes = getAttributes(tokens, placeholders);\n\n popAndCheck(tokens, \"{\");\n\n // The new scope is that of the new ROOT nodes children.\n stack.push(node.children!);\n break;\n }\n\n case \"BRANCH\": {\n // Create a BRANCH AST node.\n const node = ASTNodeFactories.BRANCH();\n\n // Push the BRANCH node into the current scope.\n currentScope.push(node);\n\n // We must have arguments defined, as we require a branch name argument.\n if (tokens[0] !== \"[\") {\n throw new Error(\"expected single branch name argument\");\n }\n\n // The branch name will be defined as a node argument.\n const branchArguments = getArguments(tokens, placeholders);\n\n // We should have only a single identifer argument for a branch node, which is the branch name.\n if (branchArguments.length === 1 && branchArguments[0].type === \"identifier\") {\n // The branch name will be the first and only node argument.\n node.branchName = branchArguments[0].value as string;\n } else {\n throw new Error(\"expected single branch name argument\");\n }\n break;\n }\n\n case \"SELECTOR\": {\n // Create a SELECTOR AST node.\n const node = ASTNodeFactories.SELECTOR();\n\n // Push the SELECTOR node into the current scope.\n currentScope.push(node);\n\n // Try to pick any attributes off of the token stack.\n node.attributes = getAttributes(tokens, placeholders);\n\n popAndCheck(tokens, \"{\");\n\n // The new scope is that of the new SELECTOR nodes children.\n stack.push(node.children!);\n break;\n }\n\n case \"SEQUENCE\": {\n // Create a SEQUENCE AST node.\n const node = ASTNodeFactories.SEQUENCE();\n\n // Push the SEQUENCE node into the current scope.\n currentScope.push(node);\n\n // Try to pick any attributes off of the token stack.\n node.attributes = getAttributes(tokens, placeholders);\n\n popAndCheck(tokens, \"{\");\n\n // The new scope is that of the new SEQUENCE nodes children.\n stack.push(node.children!);\n break;\n }\n\n case \"PARALLEL\": {\n // Create a PARALLEL AST node.\n const node = ASTNodeFactories.PARALLEL();\n\n // Push the PARALLEL node into the current scope.\n currentScope.push(node);\n\n // Try to pick any attributes off of the token stack.\n node.attributes = getAttributes(tokens, placeholders);\n\n popAndCheck(tokens, \"{\");\n\n // The new scope is that of the new PARALLEL nodes children.\n stack.push(node.children!);\n break;\n }\n\n case \"LOTTO\": {\n // Create a LOTTO AST node.\n const node = ASTNodeFactories.LOTTO();\n\n // Push the LOTTO node into the current scope.\n currentScope.push(node);\n\n // If the next token is a '[' character then some ticket counts have been defined as arguments.\n if (tokens[0] === \"[\") {\n // Get the ticket count arguments, each argument must be a number.\n node.tickets = getArguments(\n tokens,\n placeholders,\n (arg) => arg.type === \"number\" && !!arg.isInteger,\n \"lotto node ticket counts must be integer values\"\n ).map((argument) => argument.value as number);\n }\n\n // Try to pick any attributes off of the token stack.\n node.attributes = getAttributes(tokens, placeholders);\n\n popAndCheck(tokens, \"{\");\n\n // The new scope is that of the new LOTTO nodes children.\n stack.push(node.children!);\n break;\n }\n\n case \"CONDITION\": {\n // Create a CONDITION AST node.\n const node = ASTNodeFactories.CONDITION();\n\n // Push the CONDITION node into the current scope.\n currentScope.push(node);\n\n // We must have arguments defined, as we require a condition function name argument.\n if (tokens[0] !== \"[\") {\n throw new Error(\"expected condition name identifier argument\");\n }\n\n // Grab the condition node arguments.\n const conditionArguments = getArguments(tokens, placeholders);\n\n // We should have at least a single identifier argument for a condition node, which is the condition function name.\n if (conditionArguments.length && conditionArguments[0].type === \"identifier\") {\n // The condition function name will be the first node argument.\n node.conditionName = conditionArguments.shift()!.value as string;\n } else {\n throw new Error(\"expected condition name identifier argument\");\n }\n\n // Only the first argument should have been an identifier, all following arguments must be string, number, boolean or null.\n conditionArguments\n .filter((arg) => arg.type === \"identifier\")\n .forEach((arg) => {\n throw new Error(\n \"invalid condition node argument value '\" +\n arg.value +\n \"', must be string, number, boolean or null\"\n );\n });\n\n // Any node arguments that follow the condition name identifier will be treated as condition function arguments.\n node.conditionArguments = conditionArguments;\n\n // Try to pick any attributes off of the token stack.\n node.attributes = getAttributes(tokens, placeholders);\n break;\n }\n\n case \"FLIP\": {\n // Create a FLIP AST node.\n const node = ASTNodeFactories.FLIP();\n\n // Push the Flip node into the current scope.\n currentScope.push(node);\n\n // Try to pick any attributes off of the token stack.\n node.attributes = getAttributes(tokens, placeholders);\n\n popAndCheck(tokens, \"{\");\n\n // The new scope is that of the new FLIP nodes children.\n stack.push(node.children!);\n break;\n }\n\n case \"SUCCEED\": {\n // Create a SUCCEED AST node.\n const node = ASTNodeFactories.SUCCEED();\n\n // Push the Succeed node into the current scope.\n currentScope.push(node);\n\n // Try to pick any attributes off of the token stack.\n node.attributes = getAttributes(tokens, placeholders);\n\n popAndCheck(tokens, \"{\");\n\n // The new scope is that of the new Succeed nodes children.\n stack.push(node.children!);\n break;\n }\n\n case \"FAIL\": {\n // Create a FAIL AST node.\n const node = ASTNodeFactories.FAIL();\n\n // Push the Fail node into the current scope.\n currentScope.push(node);\n\n // Try to pick any attributes off of the token stack.\n node.attributes = getAttributes(tokens, placeholders);\n\n popAndCheck(tokens, \"{\");\n\n // The new scope is that of the new Fail nodes children.\n stack.push(node.children!);\n break;\n }\n\n case \"WAIT\": {\n // Create a WAIT AST node.\n const node = ASTNodeFactories.WAIT();\n\n // Push the WAIT node into the current scope.\n currentScope.push(node);\n\n // The arguments of a wait node are optional. We may have:\n // - No node arguments, in which case the wait will be indefinite until it is aborted.\n // - One node argument which will be the explicit duration of the wait.\n // - Two node arguments which define the min and max duration bounds from which a random duration will be picked.\n if (tokens[0] === \"[\") {\n // Get the optional duration and longest duration of the wait.\n const nodeArguments = getArguments(\n tokens,\n placeholders,\n (arg) => arg.type === \"number\" && !!arg.isInteger,\n \"wait node durations must be integer values\"\n ).map((argument) => argument.value);\n\n // We may have:\n // - One node argument which will be the explicit duration of the wait.\n // - Two node arguments which define the min and max duration bounds from which a random duration will be picked.\n // - Too many arguments, which is not valid.\n if (nodeArguments.length === 1) {\n // An explicit duration was defined.\n node.duration = nodeArguments[0] as number;\n } else if (nodeArguments.length === 2) {\n // Min and max duration bounds were defined from which a random duration will be picked.\n node.durationMin = nodeArguments[0] as number;\n node.durationMax = nodeArguments[1] as number;\n } else if (nodeArguments.length > 2) {\n // An incorrect number of durations was defined.\n throw new Error(\"invalid number of wait node duration arguments defined\");\n }\n }\n\n // Try to pick any attributes off of the token stack.\n node.attributes = getAttributes(tokens, placeholders);\n break;\n }\n\n case \"REPEAT\": {\n // Create a REPEAT AST node.\n const node = ASTNodeFactories.REPEAT();\n\n // Push the REPEAT node into the current scope.\n currentScope.push(node);\n\n // The arguments of a repeat node are optional. We may have:\n // - No node arguments, in which case the repeat note will iterate indefinitely.\n // - One node argument which will be the explicit number of iterations to make.\n // - Two node arguments which define the min and max iteration bounds from which a random iteration count will be picked.\n if (tokens[0] === \"[\") {\n // An iteration count has been defined. Get the iteration and potential maximum iteration of the wait.\n const nodeArguments = getArguments(\n tokens,\n placeholders,\n (arg) => arg.type === \"number\" && !!arg.isInteger,\n \"repeat node iteration counts must be integer values\"\n ).map((argument) => argument.value);\n\n // We should have got one or two iteration counts.\n if (nodeArguments.length === 1) {\n // A static iteration count was defined.\n node.iterations = nodeArguments[0] as number;\n } else if (nodeArguments.length === 2) {\n // A minimum and maximum iteration count was defined.\n node.iterationsMin = nodeArguments[0] as number;\n node.iterationsMax = nodeArguments[1] as number;\n } else {\n // An incorrect number of iteration counts was defined.\n throw new Error(\"invalid number of repeat node iteration count arguments defined\");\n }\n }\n\n // Try to pick any attributes off of the token stack.\n node.attributes = getAttributes(tokens, placeholders);\n\n popAndCheck(tokens, \"{\");\n\n // The new scope is that of the new REPEAT nodes children.\n stack.push(node.children!);\n break;\n }\n\n case \"RETRY\": {\n // Create a RETRY AST node.\n const node = ASTNodeFactories.RETRY();\n\n // Push the RETRY node into the current scope.\n currentScope.push(node);\n\n // The arguments of a retry node are optional. We may have:\n // - No node arguments, in which case the retry note will attempt indefinitely.\n // - One node argument which will be the explicit number of attempts to make.\n // - Two node arguments which define the min and max attempt bounds from which a random attempt count will be picked.\n if (tokens[0] === \"[\") {\n // An attempt count has been defined. Get the attempt count and potential maximum attempt count of the wait.\n const nodeArguments = getArguments(\n tokens,\n placeholders,\n (arg) => arg.type === \"number\" && !!arg.isInteger,\n \"retry node attempt counts must be integer values\"\n ).map((argument) => argument.value);\n\n // We should have got one or two attempt counts.\n if (nodeArguments.length === 1) {\n // A static attempt count was defined.\n node.attempts = nodeArguments[0] as number;\n } else if (nodeArguments.length === 2) {\n // A minimum and maximum attempt count was defined.\n node.attemptsMin = nodeArguments[0] as number;\n node.attemptsMax = nodeArguments[1] as number;\n } else {\n // An incorrect number of attempt counts was defined.\n throw new Error(\"invalid number of retry node attempt count arguments defined\");\n }\n }\n\n // Try to pick any attributes off of the token stack.\n node.attributes = getAttributes(tokens, placeholders);\n\n popAndCheck(tokens, \"{\");\n\n // The new scope is that of the new RETRY nodes children.\n stack.push(node.children!);\n break;\n }\n\n case \"ACTION\": {\n // Create a ACTION AST node.\n const node = ASTNodeFactories.ACTION();\n\n // Push the ACTION node into the current scope.\n currentScope.push(node);\n\n // We must have arguments defined, as we require an action name argument.\n if (tokens[0] !== \"[\") {\n throw new Error(\"expected action name identifier argument\");\n }\n\n // The action name will be defined as a node argument.\n const actionArguments = getArguments(tokens, placeholders);\n\n // We should have at least one identifer argument for an action node, which is the action name.\n if (actionArguments.length && actionArguments[0].type === \"identifier\") {\n // The action name will be the first and only node argument.\n node.actionName = actionArguments.shift()!.value as string;\n } else {\n throw new Error(\"expected action name identifier argument\");\n }\n\n // Only the first argument should have been an identifier, all following arguments must be string, number, boolean or null.\n actionArguments\n .filter((arg) => arg.type === \"identifier\")\n .forEach((arg) => {\n throw new Error(\n \"invalid action node argument value '\" +\n arg.value +\n \"', must be string, number, boolean or null\"\n );\n });\n\n // Any node arguments that follow the action name identifier will be treated as action function arguments.\n node.actionArguments = actionArguments;\n\n // Try to pick any attributes off of the token stack.\n node.attributes = getAttributes(tokens, placeholders);\n break;\n }\n\n case \"}\": {\n // The '}' character closes the current scope.\n stack.pop();\n break;\n }\n\n default: {\n throw new Error(`unexpected token '${token}'`);\n }\n }\n }\n\n // A function to recursively validate each of the nodes in the AST.\n const validateASTNode = (node: Validatable, depth: number): void => {\n // Validate the node.\n node.validate(depth);\n\n // Validate each child of the node.\n (node.children || []).forEach((child) => validateASTNode(child, depth + 1));\n };\n\n // Start node validation from the definition root.\n validateASTNode(\n {\n children: stack[0] as RootAstNode[],\n validate(this: { children: RootAstNode[] }) {\n // We must have at least one node defined as the definition scope, which should be a root node.\n if (this.children.length === 0) {\n throw new Error(\"expected root node to have been defined\");\n }\n\n // Each node at the base of the definition scope MUST be a root node.\n for (const definitionLevelNode of this.children) {\n if (definitionLevelNode.type !== \"root\") {\n throw new Error(\"expected root node at base of definition\");\n }\n }\n\n // Exactly one root node must not have a name defined. This will be the main root, others will have to be referenced via branch nodes.\n if (this.children.filter((definitionLevelNode) => definitionLevelNode.name === null).length !== 1) {\n throw new Error(\"expected single unnamed root node at base of definition to act as main root\");\n }\n\n // No two named root nodes can have matching names.\n const rootNodeNames: string[] = [];\n for (const definitionLevelNode of this.children) {\n if (rootNodeNames.indexOf(definitionLevelNode.name!) !== -1) {\n throw new Error(`multiple root nodes found with duplicate name '${definitionLevelNode.name}'`);\n } else {\n rootNodeNames.push(definitionLevelNode.name!);\n }\n }\n }\n },\n 0\n );\n\n // Return the root AST nodes.\n return stack[0];\n}\n\n/**\n * Pop the next raw token off of the stack and throw an error if it wasn't the expected one.\n * @param tokens The array of remaining tokens.\n * @param expected An optional string or array or items, one of which must match the next popped token.\n * @returns The popped token.\n */\nfunction popAndCheck(tokens: string[], expected: string | string[]) {\n // Get and remove the next token.\n const popped = tokens.shift();\n\n // We were expecting another token.\n if (popped === undefined) {\n throw new Error(\"unexpected end of definition\");\n }\n\n // Do we have an expected token/tokens array?\n if (expected !== undefined) {\n // Check whether the popped token matches at least one of our expected items.\n var tokenMatchesExpectation = ([] as string[])\n .concat(expected)\n .some((item) => popped.toUpperCase() === item.toUpperCase());\n\n // Throw an error if the popped token didn't match any of our expected items.\n if (!tokenMatchesExpectation) {\n const expectationString = ([] as string[])\n .concat(expected)\n .map((item) => \"'\" + item + \"'\")\n .join(\" or \");\n\n throw new Error(`unexpected token found. Expected '${expectationString}' but got '${popped}'`);\n }\n }\n\n // Return the popped token.\n return popped;\n}\n\ntype StringPlaceholders = { [key: string]: string };\n\n/**\n * Pull an argument definition list off of the token stack.\n * @param tokens The array of remaining tokens.\n * @param stringArgumentPlaceholders The mapping of string literal node argument placeholders to original values.\n * @param argumentValidator The argument validator function.\n * @param validationFailedMessage The exception message to throw if argument validation fails.\n * @returns The argument definition list.\n */\nfunction getArguments(\n tokens: string[],\n stringArgumentPlaceholders: StringPlaceholders,\n argumentValidator?: (arg: AnyArgument) => boolean,\n validationFailedMessage?: string\n) {\n // Any lists of arguments will always be wrapped in '[]' for node arguments or '()' for attribute arguments.\n // We are looking for a '[' or '(' opener that wraps the argument tokens and the relevant closer.\n const closer = popAndCheck(tokens, [\"[\", \"(\"]) === \"[\" ? \"]\" : \")\";\n\n const argumentListTokens: string[] = [];\n const argumentList: AnyArgument[] = [];\n\n // Grab all tokens between the '[' and ']' or '(' and ')'.\n while (tokens.length && tokens[0] !== closer) {\n // The next token is part of our arguments list.\n argumentListTokens.push(tokens.shift()!);\n }\n\n // Validate the order of the argument tokens. Each token must either be a ',' or a single argument that satisfies the validator.\n argumentListTokens.forEach((token, index) => {\n // Get whether this token should be an actual argument.\n const shouldBeArgumentToken = !(index & 1);\n\n // If the current token should be an actual argument then validate it,otherwise it should be a ',' token.\n if (shouldBeArgumentToken) {\n // Get the argument definition.\n const argumentDefinition = getArgumentDefinition(token!, stringArgumentPlaceholders);\n\n // Try to validate the argument.\n if (argumentValidator && !argumentValidator(argumentDefinition)) {\n throw new Error(validationFailedMessage);\n }\n\n // This is a valid argument!\n argumentList.push(argumentDefinition);\n } else {\n // The current token should be a ',' token.\n if (token !== \",\") {\n throw new Error(`invalid argument list, expected ',' or ']' but got '${token}'`);\n }\n }\n });\n\n // The arguments list should terminate with a ']' or ')' token, depending on the opener.\n popAndCheck(tokens, closer);\n\n // Return the argument list.\n return argumentList;\n}\n\n/**\n * Gets an argument value definition.\n * @param token The argument token.\n * @param stringArgumentPlaceholders The mapping of string literal node argument placeholders to original values.\n * @returns An argument value definition.\n */\nfunction getArgumentDefinition(token: string, stringArgumentPlaceholders: StringPlaceholders): AnyArgument {\n // Check whether the token represents a null value.\n if (token === \"null\") {\n return {\n value: null,\n type: \"null\"\n } as NullArgument;\n }\n\n // Check whether the token represents a boolean value.\n if (token === \"true\" || token === \"false\") {\n return {\n value: token === \"true\",\n type: \"boolean\"\n } as BooleanArgument;\n }\n\n // Check whether the token represents a number value.\n // TODO: Relies on broken isNaN - see MDN.\n // if (!Number.isNaN(token)) {\n if (!isNaN(token as any)) {\n return {\n value: parseFloat(token),\n isInteger: parseFloat(token) === parseInt(token, 10),\n type: \"number\"\n } as NumberArgument;\n }\n\n // Check whether the token is a placeholder (e.g. @@0@@) representing a string literal.\n if (token.match(/^@@\\d+@@$/g)) {\n return {\n value: stringArgumentPlaceholders[token].replace('\\\\\"', '\"'),\n type: \"string\"\n } as StringPlaceholderArgument;\n }\n\n // The only remaining option is that the argument value is an identifier.\n return {\n value: token,\n type: \"identifier\"\n } as IdentifierArgument;\n}\n\n/**\n * Pull any attributes off of the token stack.\n * @param tokens The array of remaining tokens.\n * @param stringArgumentPlaceholders The mapping of string literal node argument placeholders to original values.\n * @returns An array of attributes defined by any directly following tokens.\n */\nfunction getAttributes(tokens: string[], stringArgumentPlaceholders: StringPlaceholders) {\n // Create an array to hold any attributes found.\n const attributes: Attribute[] = [];\n\n // Keep track of names of attribute that we have found on the token stack, as we cannot have duplicates.\n const attributesFound: string[] = [];\n\n // Try to get the attribute factory for the next token.\n let attributeFactory = AttributeFactories[(tokens[0] || \"\").toUpperCase()];\n\n // Pull attribute tokens off of the tokens stack until we have no more.\n while (attributeFactory) {\n // Check to make sure that we have not already created a attribute of this type for this node.\n if (attributesFound.indexOf(tokens[0].toUpperCase()) !== -1) {\n throw new Error(`duplicate attribute '${tokens[0].toUpperCase()}' found for node`);\n }\n\n // Add the current attribute type to our array of found attributes.\n attributesFound.push(tokens.shift()!.toUpperCase());\n\n // Grab any attribute arguments.\n const attributeArguments = getArguments(tokens, stringArgumentPlaceholders);\n\n // The first attribute argument has to be an identifer, this will reference an agent function.\n if (attributeArguments.length === 0 || attributeArguments[0].type !== \"identifier\") {\n throw new Error(\"expected agent function name identifier argument for attribute\");\n }\n\n // Grab the first attribute which is an identifier that will reference an agent function.\n const attributeFunctionName = attributeArguments.shift()! as IdentifierArgument;\n\n // Any remaining attribute arguments must have a type of string, number, boolean or null.\n attributeArguments\n .filter((arg) => arg.type === \"identifier\")\n .forEach((arg) => {\n throw new Error(\n \"invalid attribute argument value '\" + arg.value + \"', must be string, number, boolean or null\"\n );\n });\n\n // Create the attribute and add it to the array of attributes found.\n attributes.push(attributeFactory(attributeFunctionName.value, attributeArguments));\n\n // Try to get the next attribute name token, as there could be multiple.\n attributeFactory = AttributeFactories[(tokens[0] || \"\").toUpperCase()];\n }\n\n return attributes;\n}\n\n/**\n * Swaps out any node/attribute argument string literals with placeholders.\n * @param definition The definition.\n * @returns An object containing a mapping of placeholders to original string values as well as the processed definition string.\n */\nfunction substituteStringLiterals(definition: string): {\n placeholders: { [key: string]: string };\n processedDefinition: string;\n} {\n // Create an object to hold the mapping of placeholders to original string values.\n const placeholders: StringPlaceholders = {};\n\n // Replace any string literals wrapped with double quotes in our definition with placeholders to be processed later.\n const processedDefinition = definition.replace(/\\\"(\\\\.|[^\"\\\\])*\\\"/g, (match) => {\n var strippedMatch = match.substring(1, match.length - 1);\n var placeholder = Object.keys(placeholders).find((key) => placeholders[key] === strippedMatch);\n\n // If we have no existing string literal match then create a new placeholder.\n if (!placeholder) {\n placeholder = `@@${Object.keys(placeholders).length}@@`;\n placeholders[placeholder] = strippedMatch;\n }\n\n return placeholder;\n });\n\n return { placeholders, processedDefinition };\n}\n\n/**\n * Parse the tree definition into an array of raw tokens.\n * @param definition The definition.\n * @returns An array of tokens parsed from the definition.\n */\nfunction parseTokensFromDefinition(definition: string): string[] {\n // Add some space around various important characters so that they can be plucked out easier as individual tokens.\n definition = definition.replace(/\\(/g, \" ( \");\n definition = definition.replace(/\\)/g, \" ) \");\n definition = definition.replace(/\\{/g, \" { \");\n definition = definition.replace(/\\}/g, \" } \");\n definition = definition.replace(/\\]/g, \" ] \");\n definition = definition.replace(/\\[/g, \" [ \");\n definition = definition.replace(/\\,/g, \" , \");\n\n // Split the definition into raw token form and return it.\n return definition.replace(/\\s+/g, \" \").trim().split(\" \");\n}\n", "import GuardPath, { GuardPathPart } from \"./attributes/guards/GuardPath\";\nimport buildRootASTNodes, { AnyArgument, RootAstNode } from \"./RootAstNodesBuilder\";\nimport State, { AnyState } from \"./State\";\nimport Lookup from \"./Lookup\";\nimport Node from \"./nodes/Node\";\nimport Root from \"./nodes/decorator/Root\";\nimport Composite from \"./nodes/composite/Composite\";\nimport Decorator from \"./nodes/decorator/Decorator\";\nimport { Agent, GlobalFunction } from \"./Agent\";\nimport { CallbackAttributeDetails } from \"./attributes/callbacks/Callback\";\nimport { GuardAttributeDetails } from \"./attributes/guards/Guard\";\nimport { BehaviourTreeOptions } from \"./BehaviourTreeOptions\";\nimport { parseMDSLToJSON } from \"./mdsl/MDSLDefinitionParser\";\n\n// Purely for outside inspection of the tree.\nexport type FlattenedTreeNode = {\n id: string;\n type: string;\n caption: string;\n state: AnyState;\n guards: GuardAttributeDetails[];\n callbacks: CallbackAttributeDetails[];\n args: AnyArgument[];\n parentId: string | null;\n};\n\n/**\n * A representation of a behaviour tree.\n */\nexport class BehaviourTree {\n /**\n * The main root tree node.\n */\n public readonly rootNode: Root;\n\n /**\n * Creates a new instance of the BehaviourTree class.\n * @param definition The behaviour tree definition.\n * @param agent The agent instance that this behaviour tree is modelling behaviour for.\n * @param options The behaviour tree options object.\n */\n constructor(definition: string, private agent: Agent, private options: BehaviourTreeOptions = {}) {\n // The tree definition must be defined and a valid string.\n if (typeof definition !== \"string\") {\n throw new Error(\"the tree definition must be a string\");\n }\n\n // The agent must be defined and not null.\n if (typeof agent !== \"object\" || agent === null) {\n throw new Error(\"the agent must be defined and not null\");\n }\n\n // Parse the behaviour tree definition, create the populated tree of behaviour tree nodes, and get the root.\n this.rootNode = BehaviourTree._createRootNode(definition);\n }\n\n /**\n * Gets whether the tree is in the RUNNING state.\n * @returns true if the tree is in the RUNNING state, otherwise false.\n */\n isRunning() {\n return this.rootNode.getState() === State.RUNNING;\n }\n\n /**\n * Gets the current tree state of SUCCEEDED, FAILED, READY or RUNNING.\n * @returns The current tree state.\n */\n getState() {\n return this.rootNode.getState();\n }\n\n /**\n * Step the tree.\n * 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.\n * 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\n * 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.\n *\n * 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.\n */\n step() {\n // If the root node has already been stepped to completion then we need to reset it.\n if (this.rootNode.getState() === State.SUCCEEDED || this.rootNode.getState() === State.FAILED) {\n this.rootNode.reset();\n }\n\n try {\n this.rootNode.update(this.agent, this.options);\n } catch (exception) {\n throw new Error(`error stepping tree: ${(exception as Error).message}`);\n }\n }\n\n /**\n * Resets the tree from the root node outwards to each nested node, giving each a state of READY.\n */\n reset() {\n this.rootNode.reset();\n }\n\n /**\n * Gets the flattened details of every node in the tree.\n * @returns The flattened details of every node in the tree.\n */\n getFlattenedNodeDetails(): FlattenedTreeNode[] {\n // Create an empty flattened array of tree nodes.\n const flattenedTreeNodes: FlattenedTreeNode[] = [];\n\n /**\n * Helper function to process a node instance and push details into the flattened tree nodes array.\n * @param node The current node.\n * @param parentUid The UID of the node parent, or null if the node is the main root node.\n */\n const processNode = (node: Node, parentUid: string | null) => {\n // Get the guard and callback attribute details for this node.\n const guards = node\n .getAttributes()\n .filter((attribute) => attribute.isGuard())\n .map((attribute) => attribute.getDetails()) as GuardAttributeDetails[];\n const callbacks = node\n .getAttributes()\n .filter((attribute) => !attribute.isGuard())\n .map((attribute) => attribute.getDetails()) as CallbackAttributeDetails[];\n\n // Push the current node into the flattened nodes array.\n flattenedTreeNodes.push({\n id: node.getUid(),\n type: node.getType(),\n caption: node.getName(),\n state: node.getState(),\n guards,\n callbacks,\n args: node.getArguments(),\n parentId: parentUid\n });\n\n // Process each of the nodes children if it is not a leaf node.\n if (!node.isLeafNode()) {\n (node as Composite | Decorator)\n .getChildren()\n .forEach((child) => processNode(child, (node as Composite | Decorator).getUid()));\n }\n };\n\n // Convert the nested node structure into a flattened array of node details.\n processNode(this.rootNode, null);\n\n return flattenedTreeNodes;\n }\n\n /**\n * Registers the action/condition/guard/callback function or subtree with the given name.\n * @param name The name of the function or subtree to register.\n * @param value The function or subtree definition to register.\n */\n static register(name: string, value: GlobalFunction | string) {\n if (typeof value === \"function\") {\n // We are going to register a action/condition/guard/callback function.\n Lookup.setFunc(name, value);\n } else if (typeof value === \"string\") {\n // We are going to register a subtree.\n let rootASTNodes: RootAstNode[];\n\n try {\n // Try to create the behaviour tree AST based on the definition provided, this could fail if the definition is invalid.\n rootASTNodes = buildRootASTNodes(value);\n } catch (exception) {\n // There was an issue in trying to parse and build the tree definition.\n throw new Error(`error registering definition: ${(exception as Error).message}`);\n }\n\n // This function should only ever be called with a definition containing a single unnamed root node.\n if (rootASTNodes.length != 1 || rootASTNodes[0].name !== null) {\n throw new Error(\"error registering definition: expected a single unnamed root node\");\n }\n\n Lookup.setSubtree(name, rootASTNodes[0]);\n } else {\n throw new Error(\"unexpected value, expected string definition or function\");\n }\n }\n\n /**\n * Unregisters the registered action/condition/guard/callback function or subtree with the given name.\n * @param name The name of the registered action/condition/guard/callback function or subtree to unregister.\n */\n static unregister(name: string): void {\n Lookup.remove(name);\n }\n\n /**\n * Unregister all registered action/condition/guard/callback functions and subtrees.\n */\n static unregisterAll(): void {\n Lookup.empty();\n }\n\n /**\n * Parses a behaviour tree definition and creates a tree of behaviour tree nodes.\n * @param {string} definition The behaviour tree definition.\n * @returns The root behaviour tree node.\n */\n private static _createRootNode(definition: string): Root {\n // TODO Remove!\n try {\n // parseToJSON(definition);\n } catch (exception) {\n console.log(exception);\n }\n\n try {\n // Try to create the behaviour tree AST based on the definition provided, this could fail if the definition is invalid.\n const rootASTNodes = buildRootASTNodes(definition);\n\n // Create a symbol to use as the main root key in our root node mapping.\n const mainRootNodeKey = Symbol(\"__root__\");\n\n // Create a mapping of root node names to root AST tokens. The main root node will have a key of Symbol(\"__root__\").\n const rootNodeMap: { [key: string | symbol]: RootAstNode } = {};\n for (const rootASTNode of rootASTNodes) {\n rootNodeMap[rootASTNode.name === null ? mainRootNodeKey : rootASTNode.name!] = rootASTNode;\n }\n\n // Convert the AST to our actual tree and get the root node.\n const rootNode: Root = rootNodeMap[mainRootNodeKey].createNodeInstance(\n // Create a provider for named root nodes that are part of our definition or have been registered. Prioritising the former.\n (name: string): RootAstNode => (rootNodeMap[name] ? rootNodeMap[name] : Lookup.getSubtree(name)),\n []\n );\n\n // Set a guard path on every leaf of the tree to evaluate as part of its update.\n BehaviourTree._applyLeafNodeGuardPaths(rootNode);\n\n // Return the root node.\n return rootNode;\n } catch (exception) {\n // There was an issue in trying to parse and build the tree definition.\n throw new Error(`error parsing tree: ${(exception as Error).message}`);\n }\n }\n\n /**\n * Applies a guard path to every leaf of the tree to evaluate as part of each update.\n * @param rootNode The main root tree node.\n */\n private static _applyLeafNodeGuardPaths(rootNode: Root) {\n const nodePaths: Node[][] = [];\n\n const findLeafNodes = (path: Node[], node: Node) => {\n // Add the current node to the path.\n path = path.concat(node);\n\n // Check whether the current node is a leaf node.\n if (node.isLeafNode()) {\n nodePaths.push(path);\n } else {\n (node as Composite | Decorator).getChildren().forEach((child) => findLeafNodes(path, child));\n }\n };\n\n // Find all leaf node paths, starting from the root.\n findLeafNodes([], rootNode);\n\n nodePaths.forEach((path) => {\n // Each node in the current path will have to be assigned a guard path, working from the root outwards.\n for (let depth = 0; depth < path.length; depth++) {\n // Get the node in the path at the current depth.\n const currentNode = path[depth];\n\n // The node may already have been assigned a guard path, if so just skip it.\n if (currentNode.hasGuardPath()) {\n continue;\n }\n\n // Create the guard path for the current node.\n const guardPath = new GuardPath(\n path\n .slice(0, depth + 1)\n .map((node) => ({ node, guards: node.getGuardAttributes() }))\n .filter((details) => details.guards.length > 0)\n );\n\n // Assign the guard path to the current node.\n currentNode.setGuardPath(guardPath);\n }\n });\n }\n}\n"], + "mappings": "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", "names": ["Participant", "Lotto", "createLotto", "State", "createLotto"] } diff --git a/dist/mdsl/MDSLDefinitionParser.d.ts b/dist/mdsl/MDSLDefinitionParser.d.ts new file mode 100644 index 0000000..84024e7 --- /dev/null +++ b/dist/mdsl/MDSLDefinitionParser.d.ts @@ -0,0 +1,7 @@ +import { RootDefinition } from "../BehaviourTreeDefinition"; +/** + * Parse the MDSL tree definition string into an equivalent JSON definition. + * @param definition The tree definition string as MDSL. + * @returns The root node JSON definitions. + */ +export declare function parseMDSLToJSON(definition: string): RootDefinition[]; diff --git a/dist/mdsl/MDSLNodeArgumentParser.d.ts b/dist/mdsl/MDSLNodeArgumentParser.d.ts new file mode 100644 index 0000000..23d1a89 --- /dev/null +++ b/dist/mdsl/MDSLNodeArgumentParser.d.ts @@ -0,0 +1,33 @@ +import { StringLiteralPlaceholders } from "./MDSLUtilities"; +export type Argument = { + /** The argument value. */ + value: T; + /** The argument type, used for validation. */ + type: string; +}; +export type NullArgument = Argument & { + type: "null"; +}; +export type BooleanArgument = Argument & { + type: "boolean"; +}; +export type NumberArgument = Argument & { + type: "number"; + isInteger: boolean; +}; +export type StringPlaceholderArgument = Argument & { + type: "string"; +}; +export type IdentifierArgument = Argument & { + type: "identifier"; +}; +export type AnyArgument = NullArgument | BooleanArgument | NumberArgument | StringPlaceholderArgument | IdentifierArgument; +/** + * Parse an array of argument definitions from the specified tokens array. + * @param tokens The array tokens to parse the argument definitions from. + * @param stringArgumentPlaceholders The mapping of string literal node argument placeholders to original values. + * @param argumentValidator The argument validator function. + * @param validationFailedMessage The exception message to throw if argument validation fails. + * @returns An array of argument definitions parsed from the specified tokens array. + */ +export declare function parseArgumentTokens(tokens: string[], stringArgumentPlaceholders: StringLiteralPlaceholders): AnyArgument[]; diff --git a/dist/mdsl/MDSLNodeAttributeParser.d.ts b/dist/mdsl/MDSLNodeAttributeParser.d.ts new file mode 100644 index 0000000..f9530e3 --- /dev/null +++ b/dist/mdsl/MDSLNodeAttributeParser.d.ts @@ -0,0 +1,20 @@ +import { NodeAttributeDefinition } from "../BehaviourTreeDefinition"; +import { StringLiteralPlaceholders } from "./MDSLUtilities"; +/** + * A type defining the attribute definitions of a node. + */ +type NodeAttributes = { + while?: NodeAttributeDefinition; + until?: NodeAttributeDefinition; + entry?: NodeAttributeDefinition; + exit?: NodeAttributeDefinition; + step?: NodeAttributeDefinition; +}; +/** + * Parse any node attribute definitions from the specified tokens array. + * @param tokens The array of remaining tokens. + * @param stringArgumentPlaceholders The mapping of string literal node argument placeholders to original values. + * @returns An object of attribute definitions defined by any directly following tokens. + */ +export declare function parseAttributeTokens(tokens: string[], stringArgumentPlaceholders: StringLiteralPlaceholders): NodeAttributes; +export {}; diff --git a/dist/mdsl/MDSLUtilities.d.ts b/dist/mdsl/MDSLUtilities.d.ts new file mode 100644 index 0000000..f358647 --- /dev/null +++ b/dist/mdsl/MDSLUtilities.d.ts @@ -0,0 +1,47 @@ +import { CompositeDefinition, DecoratorDefinition, NodeDefinition } from "../BehaviourTreeDefinition"; +/** + * A type defining an object that holds a reference to substitued string literals parsed from the definition. + */ +export type StringLiteralPlaceholders = { + [key: string]: string; +}; +/** + * A type guard function that returns true if the specified node satisfies the NodeDefinition type. + * @param node The node. + * @returns A value of true if the specified node satisfies the NodeDefinition type. + */ +export declare function isLeafNode(node: NodeDefinition): node is NodeDefinition; +/** + * A type guard function that returns true if the specified node satisfies the DecoratorDefinition type. + * @param node The node. + * @returns A value of true if the specified node satisfies the DecoratorDefinition type. + */ +export declare function isDecoratorNode(node: NodeDefinition): node is DecoratorDefinition; +/** + * A type guard function that returns true if the specified node satisfies the CompositeDefinition type. + * @param node The node. + * @returns A value of true if the specified node satisfies the CompositeDefinition type. + */ +export declare function isCompositeNode(node: NodeDefinition): node is CompositeDefinition; +/** + * Pop the next raw token from the specified array of tokens and throw an error if it wasn't the expected one. + * @param tokens The array of tokens. + * @param expected An optional string or array or items, one of which must match the next popped token. + * @returns The popped token. + */ +export declare function popAndCheck(tokens: string[], expected?: string | string[]): string; +/** + * Swaps out any node/attribute argument string literals with placeholders. + * @param definition The definition. + * @returns An object containing a mapping of placeholders to original string values as well as the processed definition string. + */ +export declare function substituteStringLiterals(definition: string): { + placeholders: StringLiteralPlaceholders; + processedDefinition: string; +}; +/** + * Parse the tree definition into an array of raw tokens. + * @param definition The definition. + * @returns An array of tokens parsed from the definition. + */ +export declare function parseTokensFromDefinition(definition: string): string[]; diff --git a/src/BehaviourTree.ts b/src/BehaviourTree.ts index fefa9b3..7713ea1 100644 --- a/src/BehaviourTree.ts +++ b/src/BehaviourTree.ts @@ -10,7 +10,7 @@ import { Agent, GlobalFunction } from "./Agent"; import { CallbackAttributeDetails } from "./attributes/callbacks/Callback"; import { GuardAttributeDetails } from "./attributes/guards/Guard"; import { BehaviourTreeOptions } from "./BehaviourTreeOptions"; -import { parseToJSON } from "./dsl/DSLDefinitionParser"; +import { parseMDSLToJSON } from "./mdsl/MDSLDefinitionParser"; // Purely for outside inspection of the tree. export type FlattenedTreeNode = { diff --git a/src/BehaviourTreeDefinition.d.ts b/src/BehaviourTreeDefinition.d.ts new file mode 100644 index 0000000..ba10d94 --- /dev/null +++ b/src/BehaviourTreeDefinition.d.ts @@ -0,0 +1,176 @@ +/** + * A type defining the an argument that can be passed to an agent function. + */ +export type AgentFunctionArgument = string | number | boolean | null | undefined; + +/** + * An attribute for a node. + */ +export interface NodeAttributeDefinition { + /** + * The name of the agent function to invoke. + */ + call: string; + /** + * An array of arguments to pass when invoking the agent function. + */ + args?: AgentFunctionArgument[]; +} + +/** + * A type defining a general node definition. + */ +export interface NodeDefinition { + type: string; + while?: NodeAttributeDefinition; + until?: NodeAttributeDefinition; + entry?: NodeAttributeDefinition; + exit?: NodeAttributeDefinition; + step?: NodeAttributeDefinition; +} + +/** + * A composite node that can contain any number of child nodes. + */ +export interface CompositeDefinition extends NodeDefinition { + children: AnyChildNode[]; +} + +/** + * A decorator node, a composite with only a single child node. + */ +export interface DecoratorDefinition extends NodeDefinition { + child: AnyChildNode; +} + +/** + * A branch node. + */ +export interface BranchDefinition extends NodeDefinition { + type: "branch"; + ref: string; +} + +/** + * An action node. + */ +export interface ActionDefinition extends NodeDefinition { + type: "action"; + call: string; + args?: AgentFunctionArgument[]; +} + +/** + * A condition node. + */ +export interface ConditionDefinition extends NodeDefinition { + type: "condition"; + call: string; + args?: AgentFunctionArgument[]; +} + +/** + * A wait node. + */ +export interface WaitDefinition extends NodeDefinition { + type: "wait"; + duration: number | [number, number]; +} + +/** + * A sequence node. + */ +export interface SequenceDefinition extends CompositeDefinition { + type: "sequence"; +} + +/** + * A selector node. + */ +export interface SelectorDefinition extends CompositeDefinition { + type: "selector"; +} + +/** + * A lotto node. + */ +export interface LottoDefinition extends CompositeDefinition { + type: "lotto"; + weights?: number[]; +} + +/** + * A parallel node. + */ +export interface ParallelDefinition extends CompositeDefinition { + type: "parallel"; +} + +/** + * A root node. + */ +export interface RootDefinition extends DecoratorDefinition { + type: "root"; + id?: string; +} + +/** + * A repeat node. + */ +export interface RepeatDefinition extends DecoratorDefinition { + type: "repeat"; + iterations?: number | [number, number]; +} + +/** + * A retry node. + */ +export interface RetryDefinition extends DecoratorDefinition { + type: "retry"; + attempts?: number | [number, number]; +} + +/** + * A flip node. + */ +export interface FlipDefinition extends DecoratorDefinition { + type: "flip"; +} + +/** + * A succeed node. + */ +export interface SucceedDefinition extends DecoratorDefinition { + type: "succeed"; +} + +/** + * A fail node. + */ +export interface FailDefinition extends DecoratorDefinition { + type: "fail"; +} + +/** + * A type defining any node type. + */ +export type AnyNode = + | BranchDefinition + | ActionDefinition + | ConditionDefinition + | WaitDefinition + | SequenceDefinition + | SelectorDefinition + | LottoDefinition + | ParallelDefinition + | RootDefinition + | RepeatDefinition + | RetryDefinition + | FlipDefinition + | SucceedDefinition + | FailDefinition; + +/** + * A type defining any node type that can be a child of composite parent node. + */ +export type AnyChildNode = Exclude; diff --git a/src/RootAstNodesBuilder.ts b/src/RootAstNodesBuilder.ts index 24e74dc..d8f875e 100644 --- a/src/RootAstNodesBuilder.ts +++ b/src/RootAstNodesBuilder.ts @@ -1004,7 +1004,7 @@ function popAndCheck(tokens: string[], expected: string | string[]) { return popped; } -type Placeholders = { [key: string]: string }; +type StringPlaceholders = { [key: string]: string }; /** * Pull an argument definition list off of the token stack. @@ -1016,7 +1016,7 @@ type Placeholders = { [key: string]: string }; */ function getArguments( tokens: string[], - stringArgumentPlaceholders: Placeholders, + stringArgumentPlaceholders: StringPlaceholders, argumentValidator?: (arg: AnyArgument) => boolean, validationFailedMessage?: string ) { @@ -1071,7 +1071,7 @@ function getArguments( * @param stringArgumentPlaceholders The mapping of string literal node argument placeholders to original values. * @returns An argument value definition. */ -function getArgumentDefinition(token: string, stringArgumentPlaceholders: Placeholders): AnyArgument { +function getArgumentDefinition(token: string, stringArgumentPlaceholders: StringPlaceholders): AnyArgument { // Check whether the token represents a null value. if (token === "null") { return { @@ -1120,7 +1120,7 @@ function getArgumentDefinition(token: string, stringArgumentPlaceholders: Placeh * @param stringArgumentPlaceholders The mapping of string literal node argument placeholders to original values. * @returns An array of attributes defined by any directly following tokens. */ -function getAttributes(tokens: string[], stringArgumentPlaceholders: Placeholders) { +function getAttributes(tokens: string[], stringArgumentPlaceholders: StringPlaceholders) { // Create an array to hold any attributes found. const attributes: Attribute[] = []; @@ -1180,7 +1180,7 @@ function substituteStringLiterals(definition: string): { processedDefinition: string; } { // Create an object to hold the mapping of placeholders to original string values. - const placeholders: Placeholders = {}; + const placeholders: StringPlaceholders = {}; // Replace any string literals wrapped with double quotes in our definition with placeholders to be processed later. const processedDefinition = definition.replace(/\"(\\.|[^"\\])*\"/g, (match) => { diff --git a/src/dsl/DSLDefinitionParser.ts b/src/dsl/DSLDefinitionParser.ts deleted file mode 100644 index cce1e0a..0000000 --- a/src/dsl/DSLDefinitionParser.ts +++ /dev/null @@ -1,417 +0,0 @@ -import { popAndCheck } from "./DSLUtilities"; - -/** - * A type defining the arguments that can be passed to an agent function. - */ -export type AgentFunctionArguments = (string | number | boolean | null | undefined)[]; - -/** - * A guard attribute for a node. - */ -export type GuardAttributeDefinition = { - call: string; - args?: AgentFunctionArguments; -}; - -/** - * A callback attribute for a node. - */ -export type CallbackAttributeDefinition = { - call: string; - args?: AgentFunctionArguments; -}; - -/** - * A type defining a general node definition. - */ -export type NodeDefinition = { - type: string; - while?: GuardAttributeDefinition; - until?: GuardAttributeDefinition; - entry?: CallbackAttributeDefinition; - exit?: CallbackAttributeDefinition; - step?: CallbackAttributeDefinition; -}; - -/** - * A composite node that can contain any number of child nodes. - */ -export type CompositeDefinition = NodeDefinition & { - children: AnyChildNode[]; -}; - -/** - * A decorator node, a composite with only a single child node. - */ -export type DecoratorDefinition = NodeDefinition & { - child: AnyChildNode; -}; - -/** - * A branch node. - */ -export type BranchDefinition = NodeDefinition & { - type: "branch"; - ref: string; -}; - -/** - * An action node. - */ -export type ActionDefinition = NodeDefinition & { - type: "action"; - call: string; - args?: AgentFunctionArguments; -}; - -/** - * A condition node. - */ -export type ConditionDefinition = NodeDefinition & { - type: "condition"; - call: string; - args?: AgentFunctionArguments; -}; - -/** - * A wait node. - */ -export type WaitDefinition = NodeDefinition & { - type: "wait"; - duration: number | [number, number]; -}; - -/** - * A sequence node. - */ -export type SequenceDefinition = CompositeDefinition & { - type: "sequence"; -}; - -/** - * A selector node. - */ -export type SelectorDefinition = CompositeDefinition & { - type: "selector"; -}; - -/** - * A lotto node. - */ -export type LottoDefinition = CompositeDefinition & { - type: "lotto"; - weights?: number[]; -}; - -/** - * A parallel node. - */ -export type ParallelDefinition = CompositeDefinition & { - type: "parallel"; -}; - -/** - * A root node. - */ -export type RootDefinition = DecoratorDefinition & { - type: "root"; - id?: string; -}; - -/** - * A repeat node. - */ -export type RepeatDefinition = DecoratorDefinition & { - type: "repeat"; - iterations?: number | [number, number]; -}; - -/** - * A retry node. - */ -export type RetryDefinition = DecoratorDefinition & { - type: "retry"; - attempts?: number | [number, number]; -}; - -/** - * A flip node. - */ -export type FlipDefinition = DecoratorDefinition & { - type: "flip"; -}; - -/** - * A succeed node. - */ -export type SucceedDefinition = DecoratorDefinition & { - type: "succeed"; -}; - -/** - * A fail node. - */ -export type FailDefinition = DecoratorDefinition & { - type: "fail"; -}; - -/** - * A type defining any node type. - */ -export type AnyNode = - | BranchDefinition - | ActionDefinition - | ConditionDefinition - | WaitDefinition - | SequenceDefinition - | SelectorDefinition - | LottoDefinition - | ParallelDefinition - | RootDefinition - | RepeatDefinition - | RetryDefinition - | FlipDefinition - | SucceedDefinition - | FailDefinition; - -/** - * A type defining any node type that can be a child of composite parent node. - */ -export type AnyChildNode = Exclude; - -/** - * A type defining an object that holds a reference to substitued string literals parsed from the definition. - */ -type StringLiteralPlaceholders = { [key: string]: string }; - -function isLeafNode(node: NodeDefinition): node is NodeDefinition { - return ["branch", "action", "condition", "wait"].includes(node.type); -} - -function isDecoratorNode(node: NodeDefinition): node is DecoratorDefinition { - return ["root", "repeat", "retry", "flip", "succeed", "fail"].includes(node.type); -} - -function isCompositeNode(node: NodeDefinition): node is CompositeDefinition { - return ["sequence", "selector", "lotto", "parallel"].includes(node.type); -} - -/** - * Parse the tree definition string into a JSON definition. - * @param definition The tree definition string. - * @returns The root node JSON definitions. - */ -export function parseToJSON(definition: string): RootDefinition[] { - // Swap out any node/attribute argument string literals with a placeholder and get a mapping of placeholders to original values as well as the processed definition. - const { placeholders, processedDefinition } = substituteStringLiterals(definition); - - // Parse our definition definition string into an array of raw tokens. - const tokens = parseTokensFromDefinition(definition); - - return convertTokensToJSONDefinition(tokens, placeholders, processedDefinition); -} - -/** - * Converts the specified tree definition tokens into a JSON definition. - * @param tokens The tree definition tokens. - * @param placeholders The substituted string literal placeholders. - * @returns The root node JSON definitions. - */ -export function convertTokensToJSONDefinition( - tokens: string[], - placeholders: StringLiteralPlaceholders, - processedDefinition: string -): RootDefinition[] { - // There must be at least 3 tokens for the tree definition to be valid. 'ROOT', '{' and '}'. - if (tokens.length < 3) { - throw new Error("invalid token count"); - } - - // We should have a matching number of '{' and '}' tokens. If not, then there are scopes that have not been properly closed. - if (tokens.filter((token) => token === "{").length !== tokens.filter((token) => token === "}").length) { - throw new Error("scope character mismatch"); - } - - // Create a stack of tree stack arrays where root nodes will always be at the root. - const treeStacks: [Partial, ...Partial[]][] = []; - - // Create an array of all root node definitions that we create. - const rootNodes: Partial[] = []; - - // A helper function used to push root node definitions onto the stack. - const pushRootNode = (rootNode: RootDefinition) => { - // Add the root node definition to our array of all parsed root node definitions. - rootNodes.push(rootNode); - - // Add the root node definition to the root of a new tree stack. - treeStacks.push([rootNode]); - }; - - // A helper function used to push non-root node definitions onto the stack. - const pushNode = (node: AnyChildNode) => { - // Get the current tree stack that we are populating. - const currentTreeStack = treeStacks[treeStacks.length - 1]; - - // TODO Handle cases where we may not have a current root stack. - // This may happen if a root node is not the initially defined one? - - // Get the bottom-most node in the current tree stack. - const bottomNode = currentTreeStack[currentTreeStack.length - 1] as AnyNode; - - // TODO Handle cases where we may not have a bottom-most node. - // Also a potential issue with a badly defined tree. - - // If the bottom-most node in the current root stack is a composite or decorator - // node then the current node should be added as a child of the bottom-most node. - if (isCompositeNode(bottomNode)) { - bottomNode.children = bottomNode.children || []; - bottomNode.children.push(node); - } else if (isDecoratorNode(bottomNode)) { - // If the bottom node already has a chld node set then throw an error as a decorator should only have a single child. - if (bottomNode.child) { - throw new Error("a decorator node must only have a single child node"); - } - - bottomNode.child = node; - } - - // If the node we are adding is also a composite or decorator node, then we should push it - // onto the current tree stack, as subsequent nodes will be added as its child/children. - if (!isLeafNode(node)) { - currentTreeStack.push(node); - } - }; - - // A helper function used to pop node definitions off of the stack. - const popNode = () => { - // Get the current tree stack that we are populating. - const currentTreeStack = treeStacks[treeStacks.length - 1]; - - // Pop the top-most node in the current tree stack if there is one. - if (currentTreeStack.length) { - currentTreeStack.pop(); - } - - // We don't want any empty tree stacks in our stack of tree stacks. - if (!currentTreeStack.length) { - treeStacks.pop(); - } - }; - - // We should keep processing the raw tokens until we run out of them. - while (tokens.length) { - // Grab the next token. - const token = tokens.shift()!; - - // How we create the next node depends on the current raw token value. - switch (token.toUpperCase()) { - case "ROOT": { - // A root node will always be the base of a new root stack. - pushRootNode(createRootNode(tokens)); - break; - } - - case "SEQUENCE": { - pushNode(createSequenceNode(tokens)); - break; - } - - case "ACTION": { - pushNode(createActionNode(tokens)); - break; - } - - case "}": { - // The '}' character closes the current scope and means that we have to pop a node off of the current stack. - popNode(); - break; - } - - default: { - throw new Error("unexpected token: " + token); - } - } - } - - return rootNodes as RootDefinition[]; -} - -function createRootNode(tokens: string[]): RootDefinition { - // Create the root node definition. - const node = { type: "root" } as RootDefinition; - - // TODO Grab 'id' if defined as a node argument. - // TODO Grab attributes. - - // This is a decorator node, so we expect an opening '{'. - popAndCheck(tokens, "{"); - - return node; -} - -function createSequenceNode(tokens: string[]): SequenceDefinition { - const node = { type: "sequence" } as SequenceDefinition; - - // TODO Grab attributes. - - // This is a composite node, so we expect an opening '{'. - popAndCheck(tokens, "{"); - - return node; -} - -function createActionNode(tokens: string[]): ActionDefinition { - const node = { type: "action" } as ActionDefinition; - - // TODO Grab attributes. - - return node; -} - -/** - * Swaps out any node/attribute argument string literals with placeholders. - * @param definition The definition. - * @returns An object containing a mapping of placeholders to original string values as well as the processed definition string. - */ -function substituteStringLiterals(definition: string): { - placeholders: StringLiteralPlaceholders; - processedDefinition: string; -} { - // Create an object to hold the mapping of placeholders to original string values. - const placeholders: StringLiteralPlaceholders = {}; - - // Replace any string literals wrapped with double quotes in our definition with placeholders to be processed later. - const processedDefinition = definition.replace(/\"(\\.|[^"\\])*\"/g, (match) => { - var strippedMatch = match.substring(1, match.length - 1); - var placeholder = Object.keys(placeholders).find((key) => placeholders[key] === strippedMatch); - - // If we have no existing string literal match then create a new placeholder. - if (!placeholder) { - placeholder = `@@${Object.keys(placeholders).length}@@`; - placeholders[placeholder] = strippedMatch; - } - - return placeholder; - }); - - return { placeholders, processedDefinition }; -} - -/** - * Parse the tree definition into an array of raw tokens. - * @param definition The definition. - * @returns An array of tokens parsed from the definition. - */ -function parseTokensFromDefinition(definition: string): string[] { - // Add some space around various important characters so that they can be plucked out easier as individual tokens. - definition = definition.replace(/\(/g, " ( "); - definition = definition.replace(/\)/g, " ) "); - definition = definition.replace(/\{/g, " { "); - definition = definition.replace(/\}/g, " } "); - definition = definition.replace(/\]/g, " ] "); - definition = definition.replace(/\[/g, " [ "); - definition = definition.replace(/\,/g, " , "); - - // Split the definition into raw token form and return it. - return definition.replace(/\s+/g, " ").trim().split(" "); -} diff --git a/src/dsl/DSLUtilities.ts b/src/dsl/DSLUtilities.ts deleted file mode 100644 index f515a40..0000000 --- a/src/dsl/DSLUtilities.ts +++ /dev/null @@ -1,33 +0,0 @@ -/** - * Pop the next raw token from the specified array of tokens and throw an error if it wasn't the expected one. - * @param tokens The array of tokens. - * @param expected An optional string or array or items, one of which must match the next popped token. - * @returns The popped token. - */ -export function popAndCheck(tokens: string[], expected?: string | string[]): string { - // Get and remove the next token. - const popped = tokens.shift(); - - // We were expecting another token but there aren't any. - if (popped === undefined) { - throw new Error("unexpected end of definition"); - } - - // Do we have an expected token/tokens array? - if (expected != undefined) { - // Get an array of expected values, if the popped token matches any then we are all good. - const expectedValues = typeof expected === "string" ? [expected] : expected; - - // Check whether the popped token matches at least one of our expected items. - var tokenMatchesExpectation = expectedValues.some((item) => popped.toUpperCase() === item.toUpperCase()); - - // Throw an error if the popped token didn't match any of our expected items. - if (!tokenMatchesExpectation) { - const expectationString = expectedValues.map((item) => "'" + item + "'").join(" or "); - throw new Error("unexpected token found. Expected " + expectationString + " but got '" + popped + "'"); - } - } - - // Return the popped token. - return popped; -} diff --git a/src/mdsl/MDSLDefinitionParser.ts b/src/mdsl/MDSLDefinitionParser.ts new file mode 100644 index 0000000..128a9cc --- /dev/null +++ b/src/mdsl/MDSLDefinitionParser.ts @@ -0,0 +1,210 @@ +import { + RootDefinition, + AnyChildNode, + AnyNode, + SequenceDefinition, + ActionDefinition +} from "../BehaviourTreeDefinition"; +import { parseArgumentTokens } from "./MDSLNodeArgumentParser"; +import { parseAttributeTokens } from "./MDSLNodeAttributeParser"; +import { + StringLiteralPlaceholders, + isCompositeNode, + isDecoratorNode, + isLeafNode, + parseTokensFromDefinition, + popAndCheck, + substituteStringLiterals +} from "./MDSLUtilities"; + +/** + * Parse the MDSL tree definition string into an equivalent JSON definition. + * @param definition The tree definition string as MDSL. + * @returns The root node JSON definitions. + */ +export function parseMDSLToJSON(definition: string): RootDefinition[] { + // Swap out any node/attribute argument string literals with a placeholder and get a mapping of placeholders to original values as well as the processed definition. + const { placeholders, processedDefinition } = substituteStringLiterals(definition); + + // Parse our definition definition string into an array of raw tokens. + const tokens = parseTokensFromDefinition(processedDefinition); + + return convertTokensToJSONDefinition(tokens, placeholders); +} + +/** + * Converts the specified tree definition tokens into a JSON definition. + * @param tokens The tree definition tokens. + * @param stringLiteralPlaceholders The substituted string literal placeholders. + * @returns The root node JSON definitions. + */ +function convertTokensToJSONDefinition( + tokens: string[], + stringLiteralPlaceholders: StringLiteralPlaceholders +): RootDefinition[] { + // There must be at least 3 tokens for the tree definition to be valid. 'ROOT', '{' and '}'. + if (tokens.length < 3) { + throw new Error("invalid token count"); + } + + // We should have a matching number of '{' and '}' tokens. If not, then there are scopes that have not been properly closed. + if (tokens.filter((token) => token === "{").length !== tokens.filter((token) => token === "}").length) { + throw new Error("scope character mismatch"); + } + + // Create a stack of tree stack arrays where root nodes will always be at the root. + const treeStacks: [Partial, ...Partial[]][] = []; + + // Create an array of all root node definitions that we create. + const rootNodes: Partial[] = []; + + // A helper function used to push root node definitions onto the stack. + const pushRootNode = (rootNode: RootDefinition) => { + // Add the root node definition to our array of all parsed root node definitions. + rootNodes.push(rootNode); + + // Add the root node definition to the root of a new tree stack. + treeStacks.push([rootNode]); + }; + + // A helper function used to push non-root node definitions onto the stack. + const pushNode = (node: AnyChildNode) => { + // Get the current tree stack that we are populating. + const currentTreeStack = treeStacks[treeStacks.length - 1]; + + // TODO Handle cases where we may not have a current root stack. + // This may happen if a root node is not the initially defined one? + + // Get the bottom-most node in the current tree stack. + const bottomNode = currentTreeStack[currentTreeStack.length - 1] as AnyNode; + + // TODO Handle cases where we may not have a bottom-most node. + // Also a potential issue with a badly defined tree. + + // If the bottom-most node in the current root stack is a composite or decorator + // node then the current node should be added as a child of the bottom-most node. + if (isCompositeNode(bottomNode)) { + bottomNode.children = bottomNode.children || []; + bottomNode.children.push(node); + } else if (isDecoratorNode(bottomNode)) { + // If the bottom node already has a child node set then throw an error as a decorator should only have a single child. + if (bottomNode.child) { + throw new Error("a decorator node must only have a single child node"); + } + + bottomNode.child = node; + } + + // If the node we are adding is also a composite or decorator node, then we should push it + // onto the current tree stack, as subsequent nodes will be added as its child/children. + if (!isLeafNode(node)) { + currentTreeStack.push(node); + } + }; + + // A helper function used to pop node definitions off of the stack. + const popNode = () => { + // Get the current tree stack that we are populating. + const currentTreeStack = treeStacks[treeStacks.length - 1]; + + // Pop the top-most node in the current tree stack if there is one. + if (currentTreeStack.length) { + currentTreeStack.pop(); + } + + // We don't want any empty tree stacks in our stack of tree stacks. + if (!currentTreeStack.length) { + treeStacks.pop(); + } + }; + + // We should keep processing the raw tokens until we run out of them. + while (tokens.length) { + // Grab the next token. + const token = tokens.shift()!; + + // How we create the next node depends on the current raw token value. + switch (token.toUpperCase()) { + case "ROOT": { + // A root node will always be the base of a new root stack. + pushRootNode(createRootNode(tokens, stringLiteralPlaceholders)); + break; + } + + case "SEQUENCE": { + pushNode(createSequenceNode(tokens, stringLiteralPlaceholders)); + break; + } + + case "ACTION": { + pushNode(createActionNode(tokens, stringLiteralPlaceholders)); + break; + } + + case "}": { + // The '}' character closes the current scope and means that we have to pop a node off of the current stack. + popNode(); + break; + } + + default: { + throw new Error("unexpected token: " + token); + } + } + } + + return rootNodes as RootDefinition[]; +} + +function createRootNode(tokens: string[], stringLiteralPlaceholders: StringLiteralPlaceholders): RootDefinition { + // Create the root node definition. + let node = { + type: "root", + id: undefined + } as RootDefinition; + + // Parse any node arguments, we should only have one if any with will be an identifier argument for the root identifier. + const nodeArguments = parseArgumentTokens(tokens, stringLiteralPlaceholders); + + // Check whether any node arguments were defined. + if (nodeArguments.length) { + // We should only have one argument, if any, which will be an identifier argument for the root identifier. + if (nodeArguments.length === 1 && nodeArguments[0].type === "identifier") { + // The root node identifier will be the first and only node argument value. + node.id = nodeArguments[0].value as string; + } else { + throw new Error("expected single root name argument"); + } + } + + // Grab any node attribute definitions and spread them into the node definition. + node = { ...node, ...parseAttributeTokens(tokens, stringLiteralPlaceholders) }; + + // This is a decorator node, so we expect an opening '{'. + popAndCheck(tokens, "{"); + + return node; +} + +function createSequenceNode( + tokens: string[], + stringLiteralPlaceholders: StringLiteralPlaceholders +): SequenceDefinition { + const node = { + type: "sequence", + ...parseAttributeTokens(tokens, stringLiteralPlaceholders) + } as SequenceDefinition; + + // This is a composite node, so we expect an opening '{'. + popAndCheck(tokens, "{"); + + return node; +} + +function createActionNode(tokens: string[], stringLiteralPlaceholders: StringLiteralPlaceholders): ActionDefinition { + const node = { type: "action" } as ActionDefinition; + + // TODO Grab attributes. + + return node; +} diff --git a/src/dsl/DSLNodeArgumentParser.ts b/src/mdsl/MDSLNodeArgumentParser.ts similarity index 82% rename from src/dsl/DSLNodeArgumentParser.ts rename to src/mdsl/MDSLNodeArgumentParser.ts index 60874db..2c700e2 100644 --- a/src/dsl/DSLNodeArgumentParser.ts +++ b/src/mdsl/MDSLNodeArgumentParser.ts @@ -1,6 +1,4 @@ -import { popAndCheck } from "./DSLUtilities"; - -type Placeholders = { [key: string]: string }; +import { StringLiteralPlaceholders, popAndCheck } from "./MDSLUtilities"; export type Argument = { /** The argument value. */ @@ -9,24 +7,24 @@ export type Argument = { type: string; }; -type NullArgument = Argument & { +export type NullArgument = Argument & { type: "null"; }; -type BooleanArgument = Argument & { +export type BooleanArgument = Argument & { type: "boolean"; }; -type NumberArgument = Argument & { +export type NumberArgument = Argument & { type: "number"; isInteger: boolean; // Used for validation. }; -type StringPlaceholderArgument = Argument & { +export type StringPlaceholderArgument = Argument & { type: "string"; }; -type IdentifierArgument = Argument & { +export type IdentifierArgument = Argument & { type: "identifier"; }; @@ -45,11 +43,9 @@ export type AnyArgument = * @param validationFailedMessage The exception message to throw if argument validation fails. * @returns An array of argument definitions parsed from the specified tokens array. */ -export function getArguments( +export function parseArgumentTokens( tokens: string[], - stringArgumentPlaceholders: Placeholders, - argumentValidator?: (arg: AnyArgument) => boolean, - validationFailedMessage?: string + stringArgumentPlaceholders: StringLiteralPlaceholders ): AnyArgument[] { const argumentList: AnyArgument[] = []; @@ -60,12 +56,12 @@ export function getArguments( // Any lists of arguments will always be wrapped in '[]' for node arguments or '()' for attribute arguments. // We are looking for a '[' or '(' opener that wraps the argument tokens and the relevant closer. - const closer = popAndCheck(tokens, ["[", "("]) === "[" ? "]" : ")"; + const closingToken = popAndCheck(tokens, ["[", "("]) === "[" ? "]" : ")"; const argumentListTokens: string[] = []; // Grab all tokens between the '[' and ']' or '(' and ')'. - while (tokens.length && tokens[0] !== closer) { + while (tokens.length && tokens[0] !== closingToken) { // The next token is part of our arguments list. argumentListTokens.push(tokens.shift()!); } @@ -80,11 +76,6 @@ export function getArguments( // Get the argument definition. const argumentDefinition = getArgumentDefinition(token, stringArgumentPlaceholders); - // Try to validate the argument. - if (argumentValidator && !argumentValidator(argumentDefinition)) { - throw new Error(validationFailedMessage); - } - // This is a valid argument! argumentList.push(argumentDefinition); } else { @@ -96,7 +87,7 @@ export function getArguments( }); // The arguments list should terminate with a ']' or ')' token, depending on the opener. - popAndCheck(tokens, closer); + popAndCheck(tokens, closingToken); // Return the arguments. return argumentList; @@ -108,7 +99,7 @@ export function getArguments( * @param stringArgumentPlaceholders The mapping of string literal node argument placeholders to original values. * @returns An argument value definition. */ -function getArgumentDefinition(token: string, stringArgumentPlaceholders: Placeholders): AnyArgument { +function getArgumentDefinition(token: string, stringArgumentPlaceholders: StringLiteralPlaceholders): AnyArgument { // Check whether the token represents a null value. if (token === "null") { return { diff --git a/src/mdsl/MDSLNodeAttributeParser.ts b/src/mdsl/MDSLNodeAttributeParser.ts new file mode 100644 index 0000000..42f44b1 --- /dev/null +++ b/src/mdsl/MDSLNodeAttributeParser.ts @@ -0,0 +1,75 @@ +import { NodeAttributeDefinition } from "../BehaviourTreeDefinition"; +import { parseArgumentTokens } from "./MDSLNodeArgumentParser"; +import { StringLiteralPlaceholders } from "./MDSLUtilities"; + +/** + * A type defining the attribute definitions of a node. + */ +type NodeAttributes = { + while?: NodeAttributeDefinition; + until?: NodeAttributeDefinition; + entry?: NodeAttributeDefinition; + exit?: NodeAttributeDefinition; + step?: NodeAttributeDefinition; +}; + +/** + * Parse any node attribute definitions from the specified tokens array. + * @param tokens The array of remaining tokens. + * @param stringArgumentPlaceholders The mapping of string literal node argument placeholders to original values. + * @returns An object of attribute definitions defined by any directly following tokens. + */ +export function parseAttributeTokens( + tokens: string[], + stringArgumentPlaceholders: StringLiteralPlaceholders +): NodeAttributes { + const nodeAttributeNames: (keyof NodeAttributes)[] = ["while", "until", "entry", "exit", "step"]; + + // Create an object to hold any attributes found. + const attributes: NodeAttributes = {}; + + // Try to get the name of the attribute for the next token. + let nextAttributeName = tokens[0]?.toLowerCase() as keyof NodeAttributes; + + // Pull attribute tokens as well as their arguments off of the tokens stack until we have no more. + while (nodeAttributeNames.includes(nextAttributeName)) { + // Check to make sure that we have not already created an attribute definition of this type. + if (attributes[nextAttributeName]) { + throw new Error(`duplicate attribute '${tokens[0].toUpperCase()}' found for node`); + } + + // Remove the attribute name token from the array of tokens. + tokens.shift(); + + // Grab the attribute arguments, assuming the first to be an identifier. + const [attributeCallIdentifier, ...attributeArguments] = parseArgumentTokens( + tokens, + stringArgumentPlaceholders + ); + + // The first attribute argument has to be an identifer, this will reference an agent function. + if (attributeCallIdentifier?.type !== "identifier") { + throw new Error("expected agent function name identifier argument for attribute"); + } + + // Any attribute arguments (other than the expected call identifier) must have a type of string, number, boolean or null. + attributeArguments + .filter((arg) => arg.type === "identifier") + .forEach((arg) => { + throw new Error( + "invalid attribute argument value '" + arg.value + "', must be string, number, boolean or null" + ); + }); + + // Create the attribute definition and add it to the object of attribute definitions found. + attributes[nextAttributeName] = { + call: attributeCallIdentifier.value, + args: attributeArguments.map(({ value }) => value) + }; + + // Try to get the next attribute name token, as there could be multiple. + nextAttributeName = tokens[0]?.toLowerCase() as keyof NodeAttributes; + } + + return attributes; +} diff --git a/src/mdsl/MDSLUtilities.ts b/src/mdsl/MDSLUtilities.ts new file mode 100644 index 0000000..122bf43 --- /dev/null +++ b/src/mdsl/MDSLUtilities.ts @@ -0,0 +1,115 @@ +import { CompositeDefinition, DecoratorDefinition, NodeDefinition } from "../BehaviourTreeDefinition"; + +/** + * A type defining an object that holds a reference to substitued string literals parsed from the definition. + */ +export type StringLiteralPlaceholders = { [key: string]: string }; + +/** + * A type guard function that returns true if the specified node satisfies the NodeDefinition type. + * @param node The node. + * @returns A value of true if the specified node satisfies the NodeDefinition type. + */ +export function isLeafNode(node: NodeDefinition): node is NodeDefinition { + return ["branch", "action", "condition", "wait"].includes(node.type); +} + +/** + * A type guard function that returns true if the specified node satisfies the DecoratorDefinition type. + * @param node The node. + * @returns A value of true if the specified node satisfies the DecoratorDefinition type. + */ +export function isDecoratorNode(node: NodeDefinition): node is DecoratorDefinition { + return ["root", "repeat", "retry", "flip", "succeed", "fail"].includes(node.type); +} + +/** + * A type guard function that returns true if the specified node satisfies the CompositeDefinition type. + * @param node The node. + * @returns A value of true if the specified node satisfies the CompositeDefinition type. + */ +export function isCompositeNode(node: NodeDefinition): node is CompositeDefinition { + return ["sequence", "selector", "lotto", "parallel"].includes(node.type); +} + +/** + * Pop the next raw token from the specified array of tokens and throw an error if it wasn't the expected one. + * @param tokens The array of tokens. + * @param expected An optional string or array or items, one of which must match the next popped token. + * @returns The popped token. + */ +export function popAndCheck(tokens: string[], expected?: string | string[]): string { + // Get and remove the next token. + const popped = tokens.shift(); + + // We were expecting another token but there aren't any. + if (popped === undefined) { + throw new Error("unexpected end of definition"); + } + + // Do we have an expected token/tokens array? + if (expected != undefined) { + // Get an array of expected values, if the popped token matches any then we are all good. + const expectedValues = typeof expected === "string" ? [expected] : expected; + + // Check whether the popped token matches at least one of our expected items. + var tokenMatchesExpectation = expectedValues.some((item) => popped.toUpperCase() === item.toUpperCase()); + + // Throw an error if the popped token didn't match any of our expected items. + if (!tokenMatchesExpectation) { + const expectationString = expectedValues.map((item) => "'" + item + "'").join(" or "); + throw new Error("unexpected token found. Expected " + expectationString + " but got '" + popped + "'"); + } + } + + // Return the popped token. + return popped; +} + +/** + * Swaps out any node/attribute argument string literals with placeholders. + * @param definition The definition. + * @returns An object containing a mapping of placeholders to original string values as well as the processed definition string. + */ +export function substituteStringLiterals(definition: string): { + placeholders: StringLiteralPlaceholders; + processedDefinition: string; +} { + // Create an object to hold the mapping of placeholders to original string values. + const placeholders: StringLiteralPlaceholders = {}; + + // Replace any string literals wrapped with double quotes in our definition with placeholders to be processed later. + const processedDefinition = definition.replace(/\"(\\.|[^"\\])*\"/g, (match) => { + var strippedMatch = match.substring(1, match.length - 1); + var placeholder = Object.keys(placeholders).find((key) => placeholders[key] === strippedMatch); + + // If we have no existing string literal match then create a new placeholder. + if (!placeholder) { + placeholder = `@@${Object.keys(placeholders).length}@@`; + placeholders[placeholder] = strippedMatch; + } + + return placeholder; + }); + + return { placeholders, processedDefinition }; +} + +/** + * Parse the tree definition into an array of raw tokens. + * @param definition The definition. + * @returns An array of tokens parsed from the definition. + */ +export function parseTokensFromDefinition(definition: string): string[] { + // Add some space around various important characters so that they can be plucked out easier as individual tokens. + definition = definition.replace(/\(/g, " ( "); + definition = definition.replace(/\)/g, " ) "); + definition = definition.replace(/\{/g, " { "); + definition = definition.replace(/\}/g, " } "); + definition = definition.replace(/\]/g, " ] "); + definition = definition.replace(/\[/g, " [ "); + definition = definition.replace(/\,/g, " , "); + + // Split the definition into raw token form and return it. + return definition.replace(/\s+/g, " ").trim().split(" "); +} From 67d4c7f13f7f77f722686a9d7477f2fc213a0a09 Mon Sep 17 00:00:00 2001 From: Nikolas Howard Date: Thu, 5 Oct 2023 17:37:13 +0100 Subject: [PATCH 09/48] working on MDSLDefinitionParser --- dist/mdsl/MDSLDefinitionParser.d.ts | 4 +- dist/mdsl/MDSLUtilities.d.ts | 20 ++-- src/BehaviourTreeDefinition.d.ts | 62 +++++------ src/mdsl/MDSLDefinitionParser.ts | 158 ++++++++++++++++++---------- src/mdsl/MDSLNodeAttributeParser.ts | 2 +- src/mdsl/MDSLUtilities.ts | 28 +++-- 6 files changed, 172 insertions(+), 102 deletions(-) diff --git a/dist/mdsl/MDSLDefinitionParser.d.ts b/dist/mdsl/MDSLDefinitionParser.d.ts index 84024e7..a873221 100644 --- a/dist/mdsl/MDSLDefinitionParser.d.ts +++ b/dist/mdsl/MDSLDefinitionParser.d.ts @@ -1,7 +1,7 @@ -import { RootDefinition } from "../BehaviourTreeDefinition"; +import { RootNodeDefinition } from "../BehaviourTreeDefinition"; /** * Parse the MDSL tree definition string into an equivalent JSON definition. * @param definition The tree definition string as MDSL. * @returns The root node JSON definitions. */ -export declare function parseMDSLToJSON(definition: string): RootDefinition[]; +export declare function parseMDSLToJSON(definition: string): RootNodeDefinition[]; diff --git a/dist/mdsl/MDSLUtilities.d.ts b/dist/mdsl/MDSLUtilities.d.ts index f358647..6e9acac 100644 --- a/dist/mdsl/MDSLUtilities.d.ts +++ b/dist/mdsl/MDSLUtilities.d.ts @@ -1,10 +1,16 @@ -import { CompositeDefinition, DecoratorDefinition, NodeDefinition } from "../BehaviourTreeDefinition"; +import { CompositeNodeDefinition, DecoratorNodeDefinition, NodeDefinition, RootNodeDefinition } from "../BehaviourTreeDefinition"; /** * A type defining an object that holds a reference to substitued string literals parsed from the definition. */ export type StringLiteralPlaceholders = { [key: string]: string; }; +/** + * A type guard function that returns true if the specified node satisfies the RootNodeDefinition type. + * @param node The node. + * @returns A value of true if the specified node satisfies the RootNodeDefinition type. + */ +export declare function isRootNode(node: NodeDefinition): node is RootNodeDefinition; /** * A type guard function that returns true if the specified node satisfies the NodeDefinition type. * @param node The node. @@ -12,17 +18,17 @@ export type StringLiteralPlaceholders = { */ export declare function isLeafNode(node: NodeDefinition): node is NodeDefinition; /** - * A type guard function that returns true if the specified node satisfies the DecoratorDefinition type. + * A type guard function that returns true if the specified node satisfies the DecoratorNodeDefinition type. * @param node The node. - * @returns A value of true if the specified node satisfies the DecoratorDefinition type. + * @returns A value of true if the specified node satisfies the DecoratorNodeDefinition type. */ -export declare function isDecoratorNode(node: NodeDefinition): node is DecoratorDefinition; +export declare function isDecoratorNode(node: NodeDefinition): node is DecoratorNodeDefinition; /** - * A type guard function that returns true if the specified node satisfies the CompositeDefinition type. + * A type guard function that returns true if the specified node satisfies the CompositeNodeDefinition type. * @param node The node. - * @returns A value of true if the specified node satisfies the CompositeDefinition type. + * @returns A value of true if the specified node satisfies the CompositeNodeDefinition type. */ -export declare function isCompositeNode(node: NodeDefinition): node is CompositeDefinition; +export declare function isCompositeNode(node: NodeDefinition): node is CompositeNodeDefinition; /** * Pop the next raw token from the specified array of tokens and throw an error if it wasn't the expected one. * @param tokens The array of tokens. diff --git a/src/BehaviourTreeDefinition.d.ts b/src/BehaviourTreeDefinition.d.ts index ba10d94..a26c064 100644 --- a/src/BehaviourTreeDefinition.d.ts +++ b/src/BehaviourTreeDefinition.d.ts @@ -32,21 +32,21 @@ export interface NodeDefinition { /** * A composite node that can contain any number of child nodes. */ -export interface CompositeDefinition extends NodeDefinition { +export interface CompositeNodeDefinition extends NodeDefinition { children: AnyChildNode[]; } /** * A decorator node, a composite with only a single child node. */ -export interface DecoratorDefinition extends NodeDefinition { +export interface DecoratorNodeDefinition extends NodeDefinition { child: AnyChildNode; } /** * A branch node. */ -export interface BranchDefinition extends NodeDefinition { +export interface BranchNodeDefinition extends NodeDefinition { type: "branch"; ref: string; } @@ -54,7 +54,7 @@ export interface BranchDefinition extends NodeDefinition { /** * An action node. */ -export interface ActionDefinition extends NodeDefinition { +export interface ActionNodeDefinition extends NodeDefinition { type: "action"; call: string; args?: AgentFunctionArgument[]; @@ -63,7 +63,7 @@ export interface ActionDefinition extends NodeDefinition { /** * A condition node. */ -export interface ConditionDefinition extends NodeDefinition { +export interface ConditionNodeDefinition extends NodeDefinition { type: "condition"; call: string; args?: AgentFunctionArgument[]; @@ -72,7 +72,7 @@ export interface ConditionDefinition extends NodeDefinition { /** * A wait node. */ -export interface WaitDefinition extends NodeDefinition { +export interface WaitNodeDefinition extends NodeDefinition { type: "wait"; duration: number | [number, number]; } @@ -80,21 +80,21 @@ export interface WaitDefinition extends NodeDefinition { /** * A sequence node. */ -export interface SequenceDefinition extends CompositeDefinition { +export interface SequenceNodeDefinition extends CompositeNodeDefinition { type: "sequence"; } /** * A selector node. */ -export interface SelectorDefinition extends CompositeDefinition { +export interface SelectorNodeDefinition extends CompositeNodeDefinition { type: "selector"; } /** * A lotto node. */ -export interface LottoDefinition extends CompositeDefinition { +export interface LottoNodeDefinition extends CompositeNodeDefinition { type: "lotto"; weights?: number[]; } @@ -102,14 +102,14 @@ export interface LottoDefinition extends CompositeDefinition { /** * A parallel node. */ -export interface ParallelDefinition extends CompositeDefinition { +export interface ParallelNodeDefinition extends CompositeNodeDefinition { type: "parallel"; } /** * A root node. */ -export interface RootDefinition extends DecoratorDefinition { +export interface RootNodeDefinition extends DecoratorNodeDefinition { type: "root"; id?: string; } @@ -117,7 +117,7 @@ export interface RootDefinition extends DecoratorDefinition { /** * A repeat node. */ -export interface RepeatDefinition extends DecoratorDefinition { +export interface RepeatNodeDefinition extends DecoratorNodeDefinition { type: "repeat"; iterations?: number | [number, number]; } @@ -125,7 +125,7 @@ export interface RepeatDefinition extends DecoratorDefinition { /** * A retry node. */ -export interface RetryDefinition extends DecoratorDefinition { +export interface RetryNodeDefinition extends DecoratorNodeDefinition { type: "retry"; attempts?: number | [number, number]; } @@ -133,21 +133,21 @@ export interface RetryDefinition extends DecoratorDefinition { /** * A flip node. */ -export interface FlipDefinition extends DecoratorDefinition { +export interface FlipNodeDefinition extends DecoratorNodeDefinition { type: "flip"; } /** * A succeed node. */ -export interface SucceedDefinition extends DecoratorDefinition { +export interface SucceedNodeDefinition extends DecoratorNodeDefinition { type: "succeed"; } /** * A fail node. */ -export interface FailDefinition extends DecoratorDefinition { +export interface FailNodeDefinition extends DecoratorNodeDefinition { type: "fail"; } @@ -155,22 +155,22 @@ export interface FailDefinition extends DecoratorDefinition { * A type defining any node type. */ export type AnyNode = - | BranchDefinition - | ActionDefinition - | ConditionDefinition - | WaitDefinition - | SequenceDefinition - | SelectorDefinition - | LottoDefinition - | ParallelDefinition - | RootDefinition - | RepeatDefinition - | RetryDefinition - | FlipDefinition - | SucceedDefinition - | FailDefinition; + | BranchNodeDefinition + | ActionNodeDefinition + | ConditionNodeDefinition + | WaitNodeDefinition + | SequenceNodeDefinition + | SelectorNodeDefinition + | LottoNodeDefinition + | ParallelNodeDefinition + | RootNodeDefinition + | RepeatNodeDefinition + | RetryNodeDefinition + | FlipNodeDefinition + | SucceedNodeDefinition + | FailNodeDefinition; /** * A type defining any node type that can be a child of composite parent node. */ -export type AnyChildNode = Exclude; +export type AnyChildNode = Exclude; diff --git a/src/mdsl/MDSLDefinitionParser.ts b/src/mdsl/MDSLDefinitionParser.ts index 128a9cc..d23d8a4 100644 --- a/src/mdsl/MDSLDefinitionParser.ts +++ b/src/mdsl/MDSLDefinitionParser.ts @@ -1,9 +1,9 @@ import { - RootDefinition, + RootNodeDefinition, AnyChildNode, AnyNode, - SequenceDefinition, - ActionDefinition + SequenceNodeDefinition, + ActionNodeDefinition } from "../BehaviourTreeDefinition"; import { parseArgumentTokens } from "./MDSLNodeArgumentParser"; import { parseAttributeTokens } from "./MDSLNodeAttributeParser"; @@ -12,6 +12,7 @@ import { isCompositeNode, isDecoratorNode, isLeafNode, + isRootNode, parseTokensFromDefinition, popAndCheck, substituteStringLiterals @@ -22,7 +23,7 @@ import { * @param definition The tree definition string as MDSL. * @returns The root node JSON definitions. */ -export function parseMDSLToJSON(definition: string): RootDefinition[] { +export function parseMDSLToJSON(definition: string): RootNodeDefinition[] { // Swap out any node/attribute argument string literals with a placeholder and get a mapping of placeholders to original values as well as the processed definition. const { placeholders, processedDefinition } = substituteStringLiterals(definition); @@ -41,7 +42,7 @@ export function parseMDSLToJSON(definition: string): RootDefinition[] { function convertTokensToJSONDefinition( tokens: string[], stringLiteralPlaceholders: StringLiteralPlaceholders -): RootDefinition[] { +): RootNodeDefinition[] { // There must be at least 3 tokens for the tree definition to be valid. 'ROOT', '{' and '}'. if (tokens.length < 3) { throw new Error("invalid token count"); @@ -52,68 +53,77 @@ function convertTokensToJSONDefinition( throw new Error("scope character mismatch"); } - // Create a stack of tree stack arrays where root nodes will always be at the root. - const treeStacks: [Partial, ...Partial[]][] = []; + // Create an array of tree stack arrays where root nodes will always be at the botton and the current composite/decorator node at the top. + // There should be an element in this array for every root node defined and every element should be an array with a root note as the first element. + // E.g. A definition with two root nodes defined: + // [ + // [root, lotto, sequence], + // [root, selector] + // ] + const treeStacks: [Partial, ...Partial[]][] = []; // Create an array of all root node definitions that we create. - const rootNodes: Partial[] = []; + const rootNodes: Partial[] = []; - // A helper function used to push root node definitions onto the stack. - const pushRootNode = (rootNode: RootDefinition) => { - // Add the root node definition to our array of all parsed root node definitions. - rootNodes.push(rootNode); + // A helper function used to push node definitions onto the tree stack. + const pushNode = (node: AnyNode) => { + // If the node is a root node then we need to create a new tree stack array with the root node at the root. + if (isRootNode(node)) { + // Add the root node definition to our array of all parsed root node definitions. + rootNodes.push(node); - // Add the root node definition to the root of a new tree stack. - treeStacks.push([rootNode]); - }; - - // A helper function used to push non-root node definitions onto the stack. - const pushNode = (node: AnyChildNode) => { - // Get the current tree stack that we are populating. - const currentTreeStack = treeStacks[treeStacks.length - 1]; - - // TODO Handle cases where we may not have a current root stack. - // This may happen if a root node is not the initially defined one? + // Add the root node definition to the root of a new tree stack. + treeStacks.push([node]); - // Get the bottom-most node in the current tree stack. - const bottomNode = currentTreeStack[currentTreeStack.length - 1] as AnyNode; + return; + } - // TODO Handle cases where we may not have a bottom-most node. - // Also a potential issue with a badly defined tree. + // All non-root nodes should be pushed after their root nodes so handle cases + // where we may not have any tree stacks or our top-most tree stack is empty. + if (!treeStacks.length || !treeStacks[treeStacks.length - 1].length) { + throw new Error("expected root node at base of definition"); + } - // If the bottom-most node in the current root stack is a composite or decorator - // node then the current node should be added as a child of the bottom-most node. - if (isCompositeNode(bottomNode)) { - bottomNode.children = bottomNode.children || []; - bottomNode.children.push(node); - } else if (isDecoratorNode(bottomNode)) { - // If the bottom node already has a child node set then throw an error as a decorator should only have a single child. - if (bottomNode.child) { + // Get the current tree stack that we are populating. + const topTreeStack = treeStacks[treeStacks.length - 1]; + + // Get the top-most node in the current tree stack, this will be a composite/decorator node + // for which we will populate its children array if composite or setting its child if a decorator. + const topTreeStackTopNode = topTreeStack[topTreeStack.length - 1] as AnyNode; + + // If the top-most node in the current root stack is a composite or decorator + // node then the current node should be added as a child of the top-most node. + if (isCompositeNode(topTreeStackTopNode)) { + topTreeStackTopNode.children = topTreeStackTopNode.children || []; + topTreeStackTopNode.children.push(node); + } else if (isDecoratorNode(topTreeStackTopNode)) { + // If the top node already has a child node set then throw an error as a decorator should only have a single child. + if (topTreeStackTopNode.child) { throw new Error("a decorator node must only have a single child node"); } - bottomNode.child = node; + topTreeStackTopNode.child = node; } // If the node we are adding is also a composite or decorator node, then we should push it // onto the current tree stack, as subsequent nodes will be added as its child/children. if (!isLeafNode(node)) { - currentTreeStack.push(node); + topTreeStack.push(node); } }; // A helper function used to pop node definitions off of the stack. const popNode = () => { // Get the current tree stack that we are populating. - const currentTreeStack = treeStacks[treeStacks.length - 1]; + const topTreeStack = treeStacks[treeStacks.length - 1]; // Pop the top-most node in the current tree stack if there is one. - if (currentTreeStack.length) { - currentTreeStack.pop(); + if (topTreeStack.length) { + topTreeStack.pop(); } // We don't want any empty tree stacks in our stack of tree stacks. - if (!currentTreeStack.length) { + if (!topTreeStack.length) { treeStacks.pop(); } }; @@ -126,8 +136,7 @@ function convertTokensToJSONDefinition( // How we create the next node depends on the current raw token value. switch (token.toUpperCase()) { case "ROOT": { - // A root node will always be the base of a new root stack. - pushRootNode(createRootNode(tokens, stringLiteralPlaceholders)); + pushNode(createRootNode(tokens, stringLiteralPlaceholders)); break; } @@ -153,17 +162,23 @@ function convertTokensToJSONDefinition( } } - return rootNodes as RootDefinition[]; + return rootNodes as RootNodeDefinition[]; } -function createRootNode(tokens: string[], stringLiteralPlaceholders: StringLiteralPlaceholders): RootDefinition { +/** + * Creates a root node JSON definition. + * @param tokens The tree definition tokens. + * @param stringLiteralPlaceholders The substituted string literal placeholders. + * @returns The root node JSON definition. + */ +function createRootNode(tokens: string[], stringLiteralPlaceholders: StringLiteralPlaceholders): RootNodeDefinition { // Create the root node definition. let node = { type: "root", id: undefined - } as RootDefinition; + } as RootNodeDefinition; - // Parse any node arguments, we should only have one if any with will be an identifier argument for the root identifier. + // Parse any node arguments, we should only have one if any which will be an identifier argument for the root identifier. const nodeArguments = parseArgumentTokens(tokens, stringLiteralPlaceholders); // Check whether any node arguments were defined. @@ -186,14 +201,20 @@ function createRootNode(tokens: string[], stringLiteralPlaceholders: StringLiter return node; } +/** + * Creates a sequence node JSON definition. + * @param tokens The tree definition tokens. + * @param stringLiteralPlaceholders The substituted string literal placeholders. + * @returns The sequence node JSON definition. + */ function createSequenceNode( tokens: string[], stringLiteralPlaceholders: StringLiteralPlaceholders -): SequenceDefinition { +): SequenceNodeDefinition { const node = { type: "sequence", ...parseAttributeTokens(tokens, stringLiteralPlaceholders) - } as SequenceDefinition; + } as SequenceNodeDefinition; // This is a composite node, so we expect an opening '{'. popAndCheck(tokens, "{"); @@ -201,10 +222,39 @@ function createSequenceNode( return node; } -function createActionNode(tokens: string[], stringLiteralPlaceholders: StringLiteralPlaceholders): ActionDefinition { - const node = { type: "action" } as ActionDefinition; - - // TODO Grab attributes. +/** + * Creates an action node JSON definition. + * @param tokens The tree definition tokens. + * @param stringLiteralPlaceholders The substituted string literal placeholders. + * @returns The action node JSON definition. + */ +function createActionNode( + tokens: string[], + stringLiteralPlaceholders: StringLiteralPlaceholders +): ActionNodeDefinition { + // Parse any node arguments, we should have at least one which will be an identifier argument for the action name + // and agent function to invoke for the action, all other arguments are to be passed as arguments to that function. + const [actionNameIdentifier, ...agentFunctionArgs] = parseArgumentTokens(tokens, stringLiteralPlaceholders); + + // Our first argument MUST be defined and be an identifier as we require an action name argument. + if (actionNameIdentifier?.type !== "identifier") { + throw new Error("expected action name identifier argument"); + } - return node; + // Only the first argument should have been an identifier, all agent function arguments must be string, number, boolean or null. + agentFunctionArgs + .filter((arg) => arg.type === "identifier") + .forEach((arg) => { + throw new Error( + `invalid action node argument value '${arg.value}', must be string, number, boolean or null` + ); + }); + + // Return the action node definition. + return { + type: "action", + call: actionNameIdentifier.value, + args: agentFunctionArgs.map(({ value }) => value), + ...parseAttributeTokens(tokens, stringLiteralPlaceholders) + } as ActionNodeDefinition; } diff --git a/src/mdsl/MDSLNodeAttributeParser.ts b/src/mdsl/MDSLNodeAttributeParser.ts index 42f44b1..ee2ab01 100644 --- a/src/mdsl/MDSLNodeAttributeParser.ts +++ b/src/mdsl/MDSLNodeAttributeParser.ts @@ -57,7 +57,7 @@ export function parseAttributeTokens( .filter((arg) => arg.type === "identifier") .forEach((arg) => { throw new Error( - "invalid attribute argument value '" + arg.value + "', must be string, number, boolean or null" + `invalid attribute argument value '${arg.value}', must be string, number, boolean or null` ); }); diff --git a/src/mdsl/MDSLUtilities.ts b/src/mdsl/MDSLUtilities.ts index 122bf43..67cd847 100644 --- a/src/mdsl/MDSLUtilities.ts +++ b/src/mdsl/MDSLUtilities.ts @@ -1,10 +1,24 @@ -import { CompositeDefinition, DecoratorDefinition, NodeDefinition } from "../BehaviourTreeDefinition"; +import { + CompositeNodeDefinition, + DecoratorNodeDefinition, + NodeDefinition, + RootNodeDefinition +} from "../BehaviourTreeDefinition"; /** * A type defining an object that holds a reference to substitued string literals parsed from the definition. */ export type StringLiteralPlaceholders = { [key: string]: string }; +/** + * A type guard function that returns true if the specified node satisfies the RootNodeDefinition type. + * @param node The node. + * @returns A value of true if the specified node satisfies the RootNodeDefinition type. + */ +export function isRootNode(node: NodeDefinition): node is RootNodeDefinition { + return node.type === "root"; +} + /** * A type guard function that returns true if the specified node satisfies the NodeDefinition type. * @param node The node. @@ -15,20 +29,20 @@ export function isLeafNode(node: NodeDefinition): node is NodeDefinition { } /** - * A type guard function that returns true if the specified node satisfies the DecoratorDefinition type. + * A type guard function that returns true if the specified node satisfies the DecoratorNodeDefinition type. * @param node The node. - * @returns A value of true if the specified node satisfies the DecoratorDefinition type. + * @returns A value of true if the specified node satisfies the DecoratorNodeDefinition type. */ -export function isDecoratorNode(node: NodeDefinition): node is DecoratorDefinition { +export function isDecoratorNode(node: NodeDefinition): node is DecoratorNodeDefinition { return ["root", "repeat", "retry", "flip", "succeed", "fail"].includes(node.type); } /** - * A type guard function that returns true if the specified node satisfies the CompositeDefinition type. + * A type guard function that returns true if the specified node satisfies the CompositeNodeDefinition type. * @param node The node. - * @returns A value of true if the specified node satisfies the CompositeDefinition type. + * @returns A value of true if the specified node satisfies the CompositeNodeDefinition type. */ -export function isCompositeNode(node: NodeDefinition): node is CompositeDefinition { +export function isCompositeNode(node: NodeDefinition): node is CompositeNodeDefinition { return ["sequence", "selector", "lotto", "parallel"].includes(node.type); } From 4c1f074f6e84aeeb29bb02fa72d46c27a9a491bb Mon Sep 17 00:00:00 2001 From: Nikolas Howard Date: Mon, 9 Oct 2023 17:37:38 +0100 Subject: [PATCH 10/48] finished parser but needs testing --- dist/BehaviourTreeDefinition.d.ts | 211 +++++++++ dist/bundle.js | 436 ++++++++++++++++- dist/bundle.js.map | 8 +- dist/dsl/DSLDefinitionParser.d.ts | 163 ------- dist/dsl/DSLNodeArgumentParser.d.ts | 36 -- dist/dsl/DSLUtilities.d.ts | 7 - dist/index.d.ts | 3 +- dist/index.js | 439 +++++++++++++++++- dist/index.js.map | 8 +- ...nition.d.ts => BehaviourTreeDefinition.ts} | 69 +++ src/index.ts | 3 +- src/mdsl/MDSLDefinitionParser.ts | 410 +++++++++++++++- test/mdsl/MDSLDefinitionParser.test.js | 10 + 13 files changed, 1580 insertions(+), 223 deletions(-) create mode 100644 dist/BehaviourTreeDefinition.d.ts delete mode 100644 dist/dsl/DSLDefinitionParser.d.ts delete mode 100644 dist/dsl/DSLNodeArgumentParser.d.ts delete mode 100644 dist/dsl/DSLUtilities.d.ts rename src/{BehaviourTreeDefinition.d.ts => BehaviourTreeDefinition.ts} (76%) create mode 100644 test/mdsl/MDSLDefinitionParser.test.js diff --git a/dist/BehaviourTreeDefinition.d.ts b/dist/BehaviourTreeDefinition.d.ts new file mode 100644 index 0000000..5b7be08 --- /dev/null +++ b/dist/BehaviourTreeDefinition.d.ts @@ -0,0 +1,211 @@ +/** + * A type defining the an argument that can be passed to an agent function. + */ +export type AgentFunctionArgument = string | number | boolean | null | undefined; +/** + * An attribute for a node. + */ +export interface NodeAttributeDefinition { + /** + * The name of the agent function to invoke. + */ + call: string; + /** + * An array of arguments to pass when invoking the agent function. + */ + args?: AgentFunctionArgument[]; +} +/** + * A type defining a general node definition. + */ +export interface NodeDefinition { + /** + * The node type. + */ + type: string; + /** + * The 'while' node attribute definition. + */ + while?: NodeAttributeDefinition; + /** + * The 'until' node attribute definition. + */ + until?: NodeAttributeDefinition; + /** + * The 'entry' node attribute definition. + */ + entry?: NodeAttributeDefinition; + /** + * The 'exit' node attribute definition. + */ + exit?: NodeAttributeDefinition; + /** + * The 'step' node attribute definition. + */ + step?: NodeAttributeDefinition; +} +/** + * A composite node that can contain any number of child nodes. + */ +export interface CompositeNodeDefinition extends NodeDefinition { + /** + * The child nodes of this composite node. + */ + children: AnyChildNode[]; +} +/** + * A decorator node, a composite with only a single child node. + */ +export interface DecoratorNodeDefinition extends NodeDefinition { + /** + * The child node of this decorator node. + */ + child: AnyChildNode; +} +/** + * A branch node. + */ +export interface BranchNodeDefinition extends NodeDefinition { + /** + * The node type. + */ + type: "branch"; + ref: string; +} +/** + * An action node. + */ +export interface ActionNodeDefinition extends NodeDefinition { + /** + * The node type. + */ + type: "action"; + call: string; + args?: AgentFunctionArgument[]; +} +/** + * A condition node. + */ +export interface ConditionNodeDefinition extends NodeDefinition { + /** + * The node type. + */ + type: "condition"; + call: string; + args?: AgentFunctionArgument[]; +} +/** + * A wait node. + */ +export interface WaitNodeDefinition extends NodeDefinition { + /** + * The node type. + */ + type: "wait"; + duration: number | [number, number]; +} +/** + * A sequence node. + */ +export interface SequenceNodeDefinition extends CompositeNodeDefinition { + /** + * The node type. + */ + type: "sequence"; +} +/** + * A selector node. + */ +export interface SelectorNodeDefinition extends CompositeNodeDefinition { + /** + * The node type. + */ + type: "selector"; +} +/** + * A lotto node. + */ +export interface LottoNodeDefinition extends CompositeNodeDefinition { + /** + * The node type. + */ + type: "lotto"; + /** + * The selection weights for child nodes that correspond to the child node position. + */ + weights?: number[]; +} +/** + * A parallel node. + */ +export interface ParallelNodeDefinition extends CompositeNodeDefinition { + /** + * The node type. + */ + type: "parallel"; +} +/** + * A root node. + */ +export interface RootNodeDefinition extends DecoratorNodeDefinition { + /** + * The node type. + */ + type: "root"; + id?: string; +} +/** + * A repeat node. + */ +export interface RepeatNodeDefinition extends DecoratorNodeDefinition { + /** + * The node type. + */ + type: "repeat"; + iterations?: number | [number, number]; +} +/** + * A retry node. + */ +export interface RetryNodeDefinition extends DecoratorNodeDefinition { + /** + * The node type. + */ + type: "retry"; + attempts?: number | [number, number]; +} +/** + * A flip node. + */ +export interface FlipNodeDefinition extends DecoratorNodeDefinition { + /** + * The node type. + */ + type: "flip"; +} +/** + * A succeed node. + */ +export interface SucceedNodeDefinition extends DecoratorNodeDefinition { + /** + * The node type. + */ + type: "succeed"; +} +/** + * A fail node. + */ +export interface FailNodeDefinition extends DecoratorNodeDefinition { + /** + * The node type. + */ + type: "fail"; +} +/** + * A type defining any node type. + */ +export type AnyNode = BranchNodeDefinition | ActionNodeDefinition | ConditionNodeDefinition | WaitNodeDefinition | SequenceNodeDefinition | SelectorNodeDefinition | LottoNodeDefinition | ParallelNodeDefinition | RootNodeDefinition | RepeatNodeDefinition | RetryNodeDefinition | FlipNodeDefinition | SucceedNodeDefinition | FailNodeDefinition; +/** + * A type defining any node type that can be a child of composite parent node. + */ +export type AnyChildNode = Exclude; diff --git a/dist/bundle.js b/dist/bundle.js index 12265f3..3f1937b 100644 --- a/dist/bundle.js +++ b/dist/bundle.js @@ -252,7 +252,8 @@ var mistreevous = (() => { var src_exports = {}; __export(src_exports, { BehaviourTree: () => BehaviourTree, - State: () => State + State: () => State, + parseMDSLToJSON: () => parseMDSLToJSON }); // src/attributes/guards/GuardUnsatisifedException.ts @@ -1855,6 +1856,439 @@ var mistreevous = (() => { }); } }; + + // src/mdsl/MDSLUtilities.ts + function isRootNode(node) { + return node.type === "root"; + } + function isLeafNode(node) { + return ["branch", "action", "condition", "wait"].includes(node.type); + } + function isDecoratorNode(node) { + return ["root", "repeat", "retry", "flip", "succeed", "fail"].includes(node.type); + } + function isCompositeNode(node) { + return ["sequence", "selector", "lotto", "parallel"].includes(node.type); + } + function popAndCheck2(tokens, expected) { + const popped = tokens.shift(); + if (popped === void 0) { + throw new Error("unexpected end of definition"); + } + if (expected != void 0) { + const expectedValues = typeof expected === "string" ? [expected] : expected; + var tokenMatchesExpectation = expectedValues.some((item) => popped.toUpperCase() === item.toUpperCase()); + if (!tokenMatchesExpectation) { + const expectationString = expectedValues.map((item) => "'" + item + "'").join(" or "); + throw new Error("unexpected token found. Expected " + expectationString + " but got '" + popped + "'"); + } + } + return popped; + } + function substituteStringLiterals2(definition) { + const placeholders = {}; + const processedDefinition = definition.replace(/\"(\\.|[^"\\])*\"/g, (match) => { + var strippedMatch = match.substring(1, match.length - 1); + var placeholder = Object.keys(placeholders).find((key) => placeholders[key] === strippedMatch); + if (!placeholder) { + placeholder = `@@${Object.keys(placeholders).length}@@`; + placeholders[placeholder] = strippedMatch; + } + return placeholder; + }); + return { placeholders, processedDefinition }; + } + function parseTokensFromDefinition2(definition) { + definition = definition.replace(/\(/g, " ( "); + definition = definition.replace(/\)/g, " ) "); + definition = definition.replace(/\{/g, " { "); + definition = definition.replace(/\}/g, " } "); + definition = definition.replace(/\]/g, " ] "); + definition = definition.replace(/\[/g, " [ "); + definition = definition.replace(/\,/g, " , "); + return definition.replace(/\s+/g, " ").trim().split(" "); + } + + // src/mdsl/MDSLNodeArgumentParser.ts + function parseArgumentTokens(tokens, stringArgumentPlaceholders) { + const argumentList = []; + if (!["[", "("].includes(tokens[0])) { + return argumentList; + } + const closingToken = popAndCheck2(tokens, ["[", "("]) === "[" ? "]" : ")"; + const argumentListTokens = []; + while (tokens.length && tokens[0] !== closingToken) { + argumentListTokens.push(tokens.shift()); + } + argumentListTokens.forEach((token, index) => { + const shouldBeArgumentToken = !(index & 1); + if (shouldBeArgumentToken) { + const argumentDefinition = getArgumentDefinition2(token, stringArgumentPlaceholders); + argumentList.push(argumentDefinition); + } else { + if (token !== ",") { + throw new Error(`invalid argument list, expected ',' or ']' but got '${token}'`); + } + } + }); + popAndCheck2(tokens, closingToken); + return argumentList; + } + function getArgumentDefinition2(token, stringArgumentPlaceholders) { + if (token === "null") { + return { + value: null, + type: "null" + }; + } + if (token === "true" || token === "false") { + return { + value: token === "true", + type: "boolean" + }; + } + if (!isNaN(token)) { + return { + value: parseFloat(token), + isInteger: parseFloat(token) === parseInt(token, 10), + type: "number" + }; + } + if (token.match(/^@@\d+@@$/g)) { + return { + value: stringArgumentPlaceholders[token].replace('\\"', '"'), + type: "string" + }; + } + return { + value: token, + type: "identifier" + }; + } + + // src/mdsl/MDSLNodeAttributeParser.ts + function parseAttributeTokens(tokens, stringArgumentPlaceholders) { + const nodeAttributeNames = ["while", "until", "entry", "exit", "step"]; + const attributes = {}; + let nextAttributeName = tokens[0]?.toLowerCase(); + while (nodeAttributeNames.includes(nextAttributeName)) { + if (attributes[nextAttributeName]) { + throw new Error(`duplicate attribute '${tokens[0].toUpperCase()}' found for node`); + } + tokens.shift(); + const [attributeCallIdentifier, ...attributeArguments] = parseArgumentTokens( + tokens, + stringArgumentPlaceholders + ); + if (attributeCallIdentifier?.type !== "identifier") { + throw new Error("expected agent function name identifier argument for attribute"); + } + attributeArguments.filter((arg) => arg.type === "identifier").forEach((arg) => { + throw new Error( + `invalid attribute argument value '${arg.value}', must be string, number, boolean or null` + ); + }); + attributes[nextAttributeName] = { + call: attributeCallIdentifier.value, + args: attributeArguments.map(({ value }) => value) + }; + nextAttributeName = tokens[0]?.toLowerCase(); + } + return attributes; + } + + // src/mdsl/MDSLDefinitionParser.ts + function parseMDSLToJSON(definition) { + const { placeholders, processedDefinition } = substituteStringLiterals2(definition); + const tokens = parseTokensFromDefinition2(processedDefinition); + return convertTokensToJSONDefinition(tokens, placeholders); + } + function convertTokensToJSONDefinition(tokens, stringLiteralPlaceholders) { + if (tokens.length < 3) { + throw new Error("invalid token count"); + } + if (tokens.filter((token) => token === "{").length !== tokens.filter((token) => token === "}").length) { + throw new Error("scope character mismatch"); + } + const treeStacks = []; + const rootNodes = []; + const pushNode = (node) => { + if (isRootNode(node)) { + rootNodes.push(node); + treeStacks.push([node]); + return; + } + if (!treeStacks.length || !treeStacks[treeStacks.length - 1].length) { + throw new Error("expected root node at base of definition"); + } + const topTreeStack = treeStacks[treeStacks.length - 1]; + const topTreeStackTopNode = topTreeStack[topTreeStack.length - 1]; + if (isCompositeNode(topTreeStackTopNode)) { + topTreeStackTopNode.children = topTreeStackTopNode.children || []; + topTreeStackTopNode.children.push(node); + } else if (isDecoratorNode(topTreeStackTopNode)) { + if (topTreeStackTopNode.child) { + throw new Error("a decorator node must only have a single child node"); + } + topTreeStackTopNode.child = node; + } + if (!isLeafNode(node)) { + topTreeStack.push(node); + } + }; + const popNode = () => { + const topTreeStack = treeStacks[treeStacks.length - 1]; + if (topTreeStack.length) { + topTreeStack.pop(); + } + if (!topTreeStack.length) { + treeStacks.pop(); + } + }; + while (tokens.length) { + const token = tokens.shift(); + switch (token.toUpperCase()) { + case "ROOT": { + pushNode(createRootNode(tokens, stringLiteralPlaceholders)); + break; + } + case "SUCCEED": { + pushNode(createSucceedNode(tokens, stringLiteralPlaceholders)); + break; + } + case "FAIL": { + pushNode(createFailNode(tokens, stringLiteralPlaceholders)); + break; + } + case "FLIP": { + pushNode(createFlipNode(tokens, stringLiteralPlaceholders)); + break; + } + case "REPEAT": { + pushNode(createRepeatNode(tokens, stringLiteralPlaceholders)); + break; + } + case "RETRY": { + pushNode(createRetryNode(tokens, stringLiteralPlaceholders)); + break; + } + case "SEQUENCE": { + pushNode(createSequenceNode(tokens, stringLiteralPlaceholders)); + break; + } + case "SELECTOR": { + pushNode(createSelectorNode(tokens, stringLiteralPlaceholders)); + break; + } + case "PARALLEL": { + pushNode(createParallelNode(tokens, stringLiteralPlaceholders)); + break; + } + case "LOTTO": { + pushNode(createLottoNode(tokens, stringLiteralPlaceholders)); + break; + } + case "ACTION": { + pushNode(createActionNode(tokens, stringLiteralPlaceholders)); + break; + } + case "CONDITION": { + pushNode(createConditionNode(tokens, stringLiteralPlaceholders)); + break; + } + case "WAIT": { + pushNode(createWaitNode(tokens, stringLiteralPlaceholders)); + break; + } + case "BRANCH": { + pushNode(createBranchNode(tokens, stringLiteralPlaceholders)); + break; + } + case "}": { + popNode(); + break; + } + default: { + throw new Error(`unexpected token: ${token}`); + } + } + } + return rootNodes; + } + function createRootNode(tokens, stringLiteralPlaceholders) { + let node = { + type: "root", + id: void 0 + }; + const nodeArguments = parseArgumentTokens(tokens, stringLiteralPlaceholders); + if (nodeArguments.length) { + if (nodeArguments.length === 1 && nodeArguments[0].type === "identifier") { + node.id = nodeArguments[0].value; + } else { + throw new Error("expected single root name argument"); + } + } + node = { ...node, ...parseAttributeTokens(tokens, stringLiteralPlaceholders) }; + popAndCheck2(tokens, "{"); + return node; + } + function createSucceedNode(tokens, stringLiteralPlaceholders) { + const node = { + type: "succeed", + ...parseAttributeTokens(tokens, stringLiteralPlaceholders) + }; + popAndCheck2(tokens, "{"); + return node; + } + function createFailNode(tokens, stringLiteralPlaceholders) { + const node = { + type: "fail", + ...parseAttributeTokens(tokens, stringLiteralPlaceholders) + }; + popAndCheck2(tokens, "{"); + return node; + } + function createFlipNode(tokens, stringLiteralPlaceholders) { + const node = { + type: "flip", + ...parseAttributeTokens(tokens, stringLiteralPlaceholders) + }; + popAndCheck2(tokens, "{"); + return node; + } + function createRepeatNode(tokens, stringLiteralPlaceholders) { + let node = { type: "repeat" }; + const nodeArguments = parseArgumentTokens(tokens, stringLiteralPlaceholders); + if (nodeArguments.length) { + nodeArguments.filter((arg) => arg.type !== "number" || !arg.isInteger).forEach(() => { + throw new Error(`repeat node iteration counts must be integer values`); + }); + if (nodeArguments.length === 1) { + node.iterations = nodeArguments[0].value; + } else if (nodeArguments.length === 2) { + node.iterations = [nodeArguments[0].value, nodeArguments[1].value]; + } else { + throw new Error("invalid number of repeat node iteration count arguments defined"); + } + } + node = { ...node, ...parseAttributeTokens(tokens, stringLiteralPlaceholders) }; + popAndCheck2(tokens, "{"); + return node; + } + function createRetryNode(tokens, stringLiteralPlaceholders) { + let node = { type: "retry" }; + const nodeArguments = parseArgumentTokens(tokens, stringLiteralPlaceholders); + if (nodeArguments.length) { + nodeArguments.filter((arg) => arg.type !== "number" || !arg.isInteger).forEach(() => { + throw new Error(`retry node attempt counts must be integer values`); + }); + if (nodeArguments.length === 1) { + node.attempts = nodeArguments[0].value; + } else if (nodeArguments.length === 2) { + node.attempts = [nodeArguments[0].value, nodeArguments[1].value]; + } else { + throw new Error("invalid number of retry node attempt count arguments defined"); + } + } + node = { ...node, ...parseAttributeTokens(tokens, stringLiteralPlaceholders) }; + popAndCheck2(tokens, "{"); + return node; + } + function createSequenceNode(tokens, stringLiteralPlaceholders) { + const node = { + type: "sequence", + ...parseAttributeTokens(tokens, stringLiteralPlaceholders) + }; + popAndCheck2(tokens, "{"); + return node; + } + function createSelectorNode(tokens, stringLiteralPlaceholders) { + const node = { + type: "selector", + ...parseAttributeTokens(tokens, stringLiteralPlaceholders) + }; + popAndCheck2(tokens, "{"); + return node; + } + function createParallelNode(tokens, stringLiteralPlaceholders) { + const node = { + type: "parallel", + ...parseAttributeTokens(tokens, stringLiteralPlaceholders) + }; + popAndCheck2(tokens, "{"); + return node; + } + function createLottoNode(tokens, stringLiteralPlaceholders) { + const nodeArguments = parseArgumentTokens(tokens, stringLiteralPlaceholders); + nodeArguments.filter((arg) => arg.type !== "number" || !arg.isInteger).forEach(() => { + throw new Error(`lotto node weight arguments must be integer values`); + }); + const node = { + type: "lotto", + weights: nodeArguments.map(({ value }) => value), + ...parseAttributeTokens(tokens, stringLiteralPlaceholders) + }; + popAndCheck2(tokens, "{"); + return node; + } + function createActionNode(tokens, stringLiteralPlaceholders) { + const [actionNameIdentifier, ...agentFunctionArgs] = parseArgumentTokens(tokens, stringLiteralPlaceholders); + if (actionNameIdentifier?.type !== "identifier") { + throw new Error("expected action name identifier argument"); + } + agentFunctionArgs.filter((arg) => arg.type === "identifier").forEach((arg) => { + throw new Error( + `invalid action node argument value '${arg.value}', must be string, number, boolean or null` + ); + }); + return { + type: "action", + call: actionNameIdentifier.value, + args: agentFunctionArgs.map(({ value }) => value), + ...parseAttributeTokens(tokens, stringLiteralPlaceholders) + }; + } + function createConditionNode(tokens, stringLiteralPlaceholders) { + const [conditionNameIdentifier, ...agentFunctionArgs] = parseArgumentTokens(tokens, stringLiteralPlaceholders); + if (conditionNameIdentifier?.type !== "identifier") { + throw new Error("expected condition name identifier argument"); + } + agentFunctionArgs.filter((arg) => arg.type === "identifier").forEach((arg) => { + throw new Error( + `invalid condition node argument value '${arg.value}', must be string, number, boolean or null` + ); + }); + return { + type: "condition", + call: conditionNameIdentifier.value, + args: agentFunctionArgs.map(({ value }) => value), + ...parseAttributeTokens(tokens, stringLiteralPlaceholders) + }; + } + function createWaitNode(tokens, stringLiteralPlaceholders) { + let node = { type: "wait" }; + const nodeArguments = parseArgumentTokens(tokens, stringLiteralPlaceholders); + if (nodeArguments.length) { + nodeArguments.filter((arg) => arg.type !== "number" || !arg.isInteger).forEach(() => { + throw new Error(`wait node duration arguments must be integer values`); + }); + if (nodeArguments.length === 1) { + node.duration = nodeArguments[0].value; + } else if (nodeArguments.length === 2) { + node.duration = [nodeArguments[0].value, nodeArguments[1].value]; + } else if (nodeArguments.length > 2) { + throw new Error("invalid number of wait node duration arguments defined"); + } + } + return { ...node, ...parseAttributeTokens(tokens, stringLiteralPlaceholders) }; + } + function createBranchNode(tokens, stringLiteralPlaceholders) { + const nodeArguments = parseArgumentTokens(tokens, stringLiteralPlaceholders); + if (nodeArguments.length !== 1 || nodeArguments[0].type !== "identifier") { + throw new Error("expected single branch name argument"); + } + return { type: "branch", ref: nodeArguments[0].value }; + } return __toCommonJS(src_exports); })(); //# sourceMappingURL=bundle.js.map diff --git a/dist/bundle.js.map b/dist/bundle.js.map index aa2b9e2..161ca40 100644 --- a/dist/bundle.js.map +++ b/dist/bundle.js.map @@ -1,7 +1,7 @@ { "version": 3, - "sources": ["../node_modules/lotto-draw/dist/Participant.js", "../node_modules/lotto-draw/dist/Utilities.js", "../node_modules/lotto-draw/dist/Lotto.js", "../node_modules/lotto-draw/dist/createLotto.js", "../node_modules/lotto-draw/dist/index.js", "../src/index.ts", "../src/attributes/guards/GuardUnsatisifedException.ts", "../src/attributes/guards/GuardPath.ts", "../src/State.ts", "../src/nodes/Node.ts", "../src/nodes/leaf/Leaf.ts", "../src/Lookup.ts", "../src/nodes/leaf/Action.ts", "../src/nodes/leaf/Condition.ts", "../src/nodes/leaf/Wait.ts", "../src/nodes/decorator/Decorator.ts", "../src/nodes/decorator/Root.ts", "../src/nodes/decorator/Repeat.ts", "../src/nodes/decorator/Retry.ts", "../src/nodes/decorator/Flip.ts", "../src/nodes/decorator/Succeed.ts", "../src/nodes/decorator/Fail.ts", "../src/nodes/composite/Lotto.ts", "../src/nodes/composite/Composite.ts", "../src/nodes/composite/Selector.ts", "../src/nodes/composite/Sequence.ts", "../src/nodes/composite/Parallel.ts", "../src/attributes/Attribute.ts", "../src/attributes/guards/Guard.ts", "../src/attributes/guards/While.ts", "../src/attributes/guards/Until.ts", "../src/attributes/callbacks/Callback.ts", "../src/attributes/callbacks/Entry.ts", "../src/attributes/callbacks/Exit.ts", "../src/attributes/callbacks/Step.ts", "../src/RootAstNodesBuilder.ts", "../src/BehaviourTree.ts"], - "sourcesContent": ["\"use strict\";\r\nObject.defineProperty(exports, \"__esModule\", { value: true });\r\nexports.Participant = void 0;\r\n/**\r\n * A participant that holds a number of tickets.\r\n */\r\nvar Participant = /** @class */ (function () {\r\n /**\r\n * Creates an instance of the Participant class.\r\n * @param participant The actual participant.\r\n * @param tickets The number of tickets held by the participant.\r\n */\r\n function Participant(participant, tickets) {\r\n if (tickets === void 0) { tickets = 1; }\r\n this._participant = participant;\r\n this._tickets = tickets;\r\n }\r\n Object.defineProperty(Participant.prototype, \"participant\", {\r\n /** Gets the actual participant. */\r\n get: function () {\r\n return this._participant;\r\n },\r\n enumerable: false,\r\n configurable: true\r\n });\r\n Object.defineProperty(Participant.prototype, \"tickets\", {\r\n /** Gets or sets the number of tickets held by the participant. */\r\n get: function () {\r\n return this._tickets;\r\n },\r\n set: function (value) {\r\n this._tickets = value;\r\n },\r\n enumerable: false,\r\n configurable: true\r\n });\r\n return Participant;\r\n}());\r\nexports.Participant = Participant;\r\n", "\"use strict\";\r\nObject.defineProperty(exports, \"__esModule\", { value: true });\r\nexports.isNaturalNumber = exports.isNullOrUndefined = void 0;\r\n/**\r\n * Gets whether the value provided is null or undefined.\r\n * @param value The value to check.\r\n * @returns Whether the value provided is null or undefined.\r\n */\r\nfunction isNullOrUndefined(value) {\r\n return value === null || value === undefined;\r\n}\r\nexports.isNullOrUndefined = isNullOrUndefined;\r\n/**\r\n * Gets whether the value provided is a natural number.\r\n * @param value The value to check.\r\n * @returns Whether the value provided is a natural number.\r\n */\r\nfunction isNaturalNumber(value) {\r\n return typeof value === \"number\" && value >= 1 && Math.floor(value) === value;\r\n}\r\nexports.isNaturalNumber = isNaturalNumber;\r\n", "\"use strict\";\r\nObject.defineProperty(exports, \"__esModule\", { value: true });\r\nexports.Lotto = void 0;\r\nvar Participant_1 = require(\"./Participant\");\r\nvar Utilities_1 = require(\"./Utilities\");\r\n/**\r\n * Represents a lotto consisting of a number of pickable ticket-holding participants.\r\n */\r\nvar Lotto = /** @class */ (function () {\r\n /**\r\n * Creates a new instance of Lotto.\r\n * @param customRandom The custom RNG to use in place of Math.random().\r\n */\r\n function Lotto(customRandom) {\r\n /** The array of participants that are holding tickets in the lotto. */\r\n this._participants = [];\r\n this._customRandom = customRandom;\r\n }\r\n /**\r\n * Adds a participant with the specified number of tickets, or adds to the participant ticket count if the participant already holds tickets.\r\n * @param participant The participant to add or to increase the ticket count for if they already hold tickets.\r\n * @param tickets The number of tickets, defaults to 1.\r\n * @returns The Lotto instance.\r\n */\r\n Lotto.prototype.add = function (participant, tickets) {\r\n if (tickets === void 0) { tickets = 1; }\r\n // Check that we have a valid ticket count.\r\n if (!(0, Utilities_1.isNaturalNumber)(tickets)) {\r\n throw new Error(\"tickets value must be a natural number\");\r\n }\r\n // Check whether this participant has already been added.\r\n var existingParticipant = this._participants.find(function (part) { return part.participant === participant; });\r\n if (existingParticipant) {\r\n // The participant has already been added to the lotto so just add to their ticket count.\r\n existingParticipant.tickets += tickets;\r\n }\r\n else {\r\n // The participant is not part of the lotto so we should add them.\r\n this._participants.push(new Participant_1.Participant(participant, tickets));\r\n }\r\n return this;\r\n };\r\n /**\r\n * Removes the specified number of tickets for the given participant from the draw, or all tickets if a ticket number is not defined.\r\n * @param participant The participant to remove tickets for.\r\n * @param tickets The number of tickets to remove, or undefined if all tickets are to be removed.\r\n * @returns The Lotto instance.\r\n */\r\n Lotto.prototype.remove = function (participant, tickets) {\r\n // Attempt to get the existing participant.\r\n var existingParticipant = this._participants.find(function (part) { return part.participant === participant; });\r\n // There is nothing to do if the specified participant isn't even part of the lotto.\r\n if (!existingParticipant) {\r\n return this;\r\n }\r\n // Check whether a tickets value was given.\r\n if (tickets !== undefined) {\r\n // Check that we have a valid ticket count.\r\n if (!(0, Utilities_1.isNaturalNumber)(tickets)) {\r\n throw new Error(\"tickets value must be a natural number\");\r\n }\r\n existingParticipant.tickets -= tickets;\r\n // If the participant no longer holds any tickets then they should be removed.\r\n if (existingParticipant.tickets < 1) {\r\n this._participants = this._participants.filter(function (part) { return part !== existingParticipant; });\r\n }\r\n }\r\n else {\r\n // We are removing all tickets for the participant so just remove them from the lotto.\r\n this._participants = this._participants.filter(function (part) { return part !== existingParticipant; });\r\n }\r\n return this;\r\n };\r\n /**\r\n * Draw a winning ticket and return the participant that holds the ticket.\r\n * @param options The draw options.\r\n * @returns The participant that holds the winning ticket.\r\n */\r\n Lotto.prototype.draw = function (options) {\r\n if (options === void 0) { options = {}; }\r\n // If we have no participants then just return null.\r\n if (this._participants.length === 0) {\r\n return null;\r\n }\r\n var redrawable = (0, Utilities_1.isNullOrUndefined)(options.redrawable) ? true : options.redrawable;\r\n var pickable = [];\r\n this._participants.forEach(function (_a) {\r\n var participant = _a.participant, tickets = _a.tickets;\r\n for (var ticketCount = 0; ticketCount < tickets; ticketCount++) {\r\n pickable.push(participant);\r\n }\r\n });\r\n var random;\r\n // We need a random floating-point number between 0 (inclusive) and 1 to scale up to pick our winner.\r\n // If a custom random function exists then we should use that or fall back to Math.random().\r\n if (this._customRandom) {\r\n // Call our custom random function to get a random floating-point number.\r\n random = this._customRandom();\r\n // Verify that the result of calling our custom random function is a number between 0 (inclusive) and 1.\r\n if (typeof random !== \"number\" || random < 0 || random >= 1) {\r\n throw new Error(\"the 'random' function provided did not return a number between 0 (inclusive) and 1\");\r\n }\r\n }\r\n else {\r\n // No custom random function was defined so just use good ol' Math.random().\r\n random = Math.random();\r\n }\r\n // Pick a winning participant.\r\n var winner = pickable[Math.floor(random * pickable.length)];\r\n // If the ticket isn't redrawable then we should remove a ticket from the winning participants ticket count.\r\n if (!redrawable) {\r\n this.remove(winner, 1);\r\n }\r\n // Return the winning participant.\r\n return winner;\r\n };\r\n /**\r\n * Draws multiple winning tickets and return an array of the participants that hold the winning tickets.\r\n * @param tickets The number of winning tickets to draw.\r\n * @param options The draw multiple options.\r\n * @returns An array of the participants that hold the winning tickets.\r\n */\r\n Lotto.prototype.drawMultiple = function (tickets, options) {\r\n if (options === void 0) { options = {}; }\r\n var uniqueResults = (0, Utilities_1.isNullOrUndefined)(options.unique) ? false : options.unique;\r\n // Handle cases where the user has asked for zero tickets (no idea why they would do this be we should trust them).\r\n if (tickets === 0) {\r\n return [];\r\n }\r\n // Now that we know out tickets value is not zero we should check that it is a valid natural number.\r\n if (!(0, Utilities_1.isNaturalNumber)(tickets)) {\r\n throw new Error(\"tickets value must be a natural number\");\r\n }\r\n var result = [];\r\n // Keep drawing tickets until we either reach the number of required tickets or we simply run out of tickets to draw.\r\n // We can run out of tickets to draw if 'options.redrawable' is explicity 'false' or we just had no participants when 'drawMultiple' was called.\r\n while (result.length < tickets && this._participants.length > 0) {\r\n result.push(this.draw(options));\r\n }\r\n // If the 'unique' draw option is set then we need to remove duplicates from the result list.\r\n if (uniqueResults) {\r\n // Create an array to store our unique results.\r\n var unique = [];\r\n // Iterate over all of our participants (with potential duplicates) and populate our array of unique values.\r\n for (var _i = 0, result_1 = result; _i < result_1.length; _i++) {\r\n var participant = result_1[_i];\r\n if (unique.indexOf(participant) === -1) {\r\n unique.push(participant);\r\n }\r\n }\r\n result = unique;\r\n }\r\n return result;\r\n };\r\n return Lotto;\r\n}());\r\nexports.Lotto = Lotto;\r\n", "\"use strict\";\r\nObject.defineProperty(exports, \"__esModule\", { value: true });\r\nexports.createLotto = void 0;\r\nvar Lotto_1 = require(\"./Lotto\");\r\n/**\r\n * A function that creates and returns a Lotto instance.\r\n * @param participantsOrOptions An array of initial participants or options relating to the creation of a Lotto instance.\r\n * @returns A new Lotto instance.\r\n */\r\nfunction createLotto(participantsOrOptions) {\r\n // If no initial participants or lotto options were provided as an argument then we can just return a new lotto instance now.\r\n if (!participantsOrOptions) {\r\n return new Lotto_1.Lotto();\r\n }\r\n // Check whether we were provided with an array of initial participants or a lotto options object.\r\n if (Array.isArray(participantsOrOptions)) {\r\n // We are dealing with a pre-defined array of participants.\r\n var participants = participantsOrOptions;\r\n var lotto_1 = new Lotto_1.Lotto();\r\n // If the lotto participants have been defined upfront then we will need to add them all to our lotto instance now.\r\n participants.forEach(function (_a) {\r\n var participant = _a[0], tokens = _a[1];\r\n return lotto_1.add(participant, tokens);\r\n });\r\n // Return the Lotto instance.\r\n return lotto_1;\r\n }\r\n else {\r\n // We are dealing with some lotto options.\r\n var random = participantsOrOptions.random, participants = participantsOrOptions.participants;\r\n // Create a Lotto instance passing the custom RNG function to use in place of Math.random() (which could be undefined).\r\n var lotto_2 = new Lotto_1.Lotto(random);\r\n // If the lotto participants have been defined upfront as part of the options then we will need to add them all to our lotto instance now.\r\n if (participants) {\r\n participants.forEach(function (_a) {\r\n var participant = _a[0], tokens = _a[1];\r\n return lotto_2.add(participant, tokens);\r\n });\r\n }\r\n // Return the Lotto instance.\r\n return lotto_2;\r\n }\r\n}\r\nexports.createLotto = createLotto;\r\n", "\"use strict\";\r\nObject.defineProperty(exports, \"__esModule\", { value: true });\r\nvar createLotto_1 = require(\"./createLotto\");\r\nexports.default = createLotto_1.createLotto;\r\n", "import { BehaviourTree, FlattenedTreeNode } from \"./BehaviourTree\";\nimport State from \"./State\";\n\nexport { BehaviourTree, State };\nexport type { FlattenedTreeNode };\n", "import Node from \"../../nodes/Node\";\n\n/**\n * An exception thrown when evaluating node guard path conditions and a conditions fails.\n */\nexport default class GuardUnsatisifedException extends Error {\n /**\n * @param source The node at which a guard condition failed.\n */\n constructor(private source: Node) {\n super(\"A guard path condition has failed\");\n }\n\n /**\n * Gets whether the specified node is the node at which a guard condition failed.\n * @param node The node to check against the source node.\n * @returns Whether the specified node is the node at which a guard condition failed.\n */\n isSourceNode = (node: Node) => node === this.source;\n}\n", "import { Agent } from \"../../Agent\";\nimport Guard from \"./Guard\";\nimport Node from \"../../nodes/Node\";\nimport GuardUnsatisifedException from \"./GuardUnsatisifedException\";\n\nexport type GuardPathPart = {\n node: Node;\n guards: Guard[];\n};\n\n/**\n * Represents a path of node guards along a root-to-leaf tree path.\n */\nexport default class GuardPath {\n /**\n * @param nodes An array of objects defining a node instance -> guard link, ordered by node depth.\n */\n constructor(private nodes: GuardPathPart[]) {}\n\n /**\n * Evaluate guard conditions for all guards in the tree path, moving outwards from the root.\n * @param agent The agent, required for guard evaluation.\n * @returns An evaluation results object.\n */\n evaluate = (agent: Agent) => {\n // We need to evaluate guard conditions for nodes up the tree, moving outwards from the root.\n for (const details of this.nodes) {\n // There can be multiple guards per node.\n for (const guard of details.guards) {\n // Check whether the guard condition passes, and throw an exception if not.\n if (!guard.isSatisfied(agent)) {\n throw new GuardUnsatisifedException(details.node);\n }\n }\n }\n };\n}\n", "/**\n * Enumeration of node state types.\n */\nexport enum State {\n READY = \"mistreevous.ready\",\n RUNNING = \"mistreevous.running\",\n SUCCEEDED = \"mistreevous.succeeded\",\n FAILED = \"mistreevous.failed\"\n}\n\nexport { State as default };\n\nexport type CompleteState = State.SUCCEEDED | State.FAILED;\nexport type AnyState = State.READY | State.RUNNING | CompleteState;\n", "import { Agent } from \"../Agent\";\nimport Attribute from \"../attributes/Attribute\";\nimport Entry from \"../attributes/callbacks/Entry\";\nimport Exit from \"../attributes/callbacks/Exit\";\nimport Step from \"../attributes/callbacks/Step\";\nimport Guard from \"../attributes/guards/Guard\";\nimport GuardPath from \"../attributes/guards/GuardPath\";\nimport GuardUnsatisifedException from \"../attributes/guards/GuardUnsatisifedException\";\nimport { BehaviourTreeOptions } from \"../BehaviourTreeOptions\";\nimport { AnyArgument } from \"../RootAstNodesBuilder\";\nimport State, { AnyState } from \"../State\";\nimport Leaf from \"./leaf/Leaf\";\n\n/**\n * A base node.\n */\nexport default abstract class Node {\n /**\n * The node uid.\n */\n private readonly uid: string = createNodeUid();\n /**\n * The node state.\n */\n private state: AnyState = State.READY;\n /**\n * The guard path to evaluate as part of a node update.\n */\n private guardPath: GuardPath | undefined;\n\n /**\n * @param type The node type.\n * @param attributes The node attributes.\n * @param args The node argument definitions.\n */\n constructor(private type: string, private attributes: Attribute[], private args: AnyArgument[]) {}\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected abstract onUpdate(agent: Agent, options: BehaviourTreeOptions): void;\n\n /**\n * Gets the name of the node.\n */\n public abstract getName(): string;\n\n /**\n * Gets whether this node is a leaf node.\n */\n public abstract isLeafNode: () => this is Leaf;\n\n /**\n * Gets/Sets the state of the node.\n */\n getState = (): AnyState => this.state;\n setState = (value: AnyState): void => {\n this.state = value;\n };\n\n /**\n * Gets the unique id of the node.\n */\n getUid = () => this.uid;\n\n /**\n * Gets the type of the node.\n */\n getType = () => this.type;\n\n /**\n * Gets the node attributes.\n */\n getAttributes = () => this.attributes;\n\n /**\n * Gets the node arguments.\n */\n getArguments = () => this.args;\n\n /**\n * Gets the node attribute with the specified type, or null if it does not exist.\n */\n getAttribute(type: \"entry\" | \"ENTRY\"): Entry;\n getAttribute(type: \"exit\" | \"EXIT\"): Exit;\n getAttribute(type: \"step\" | \"STEP\"): Step;\n getAttribute(type: string): Attribute {\n return (\n this.getAttributes().filter((decorator) => decorator.getType().toUpperCase() === type.toUpperCase())[0] ||\n null\n );\n }\n\n /**\n * Gets the node attributes.\n */\n getGuardAttributes = (): Guard[] => this.getAttributes().filter((decorator) => decorator.isGuard()) as Guard[];\n\n /**\n * Sets the guard path to evaluate as part of a node update.\n */\n setGuardPath = (value: GuardPath) => (this.guardPath = value);\n\n /**\n * Gets whether a guard path is assigned to this node.\n */\n hasGuardPath = () => !!this.guardPath;\n\n /**\n * Gets whether this node is in the specified state.\n * @param value The value to compare to the node state.\n */\n public is(value: AnyState): boolean {\n return this.state === value;\n }\n\n /**\n * Reset the state of the node.\n */\n public reset(): void {\n this.setState(State.READY);\n }\n\n /**\n * Abort the running of this node.\n * @param agent The agent.\n */\n public abort(agent: Agent): void {\n // There is nothing to do if this node is not in the running state.\n if (!this.is(State.RUNNING)) {\n return;\n }\n\n // Reset the state of this node.\n this.reset();\n\n this.getAttribute(\"exit\")?.callAgentFunction(agent, false, true);\n }\n\n /**\n * Update the node.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n * @returns The result of the update.\n */\n public update(agent: Agent, options: BehaviourTreeOptions): void {\n // If this node is already in a 'SUCCEEDED' or 'FAILED' state then there is nothing to do.\n if (this.is(State.SUCCEEDED) || this.is(State.FAILED)) {\n return;\n }\n\n try {\n // Evaluate all of the guard path conditions for the current tree path.\n this.guardPath!.evaluate(agent);\n\n // If this node is in the READY state then call the ENTRY for this node if it exists.\n if (this.is(State.READY)) {\n this.getAttribute(\"entry\")?.callAgentFunction(agent);\n }\n\n this.getAttribute(\"step\")?.callAgentFunction(agent);\n\n // Do the actual update.\n this.onUpdate(agent, options);\n\n // If this node is now in a 'SUCCEEDED' or 'FAILED' state then call the EXIT for this node if it exists.\n if (this.is(State.SUCCEEDED) || this.is(State.FAILED)) {\n this.getAttribute(\"exit\")?.callAgentFunction(agent, this.is(State.SUCCEEDED), false);\n }\n } catch (error) {\n // If the error is a GuardUnsatisfiedException then we need to determine if this node is the source.\n if (error instanceof GuardUnsatisifedException && error.isSourceNode(this)) {\n // Abort the current node.\n this.abort(agent);\n\n // Any node that is the source of an abort will be a failed node.\n this.setState(State.FAILED);\n } else {\n throw error;\n }\n }\n }\n}\n\n/**\n * Create a randomly generated node uid.\n * @returns A randomly generated node uid.\n */\nfunction createNodeUid(): string {\n var S4 = function () {\n return (((1 + Math.random()) * 0x10000) | 0).toString(16).substring(1);\n };\n return S4() + S4() + \"-\" + S4() + \"-\" + S4() + \"-\" + S4() + \"-\" + S4() + S4() + S4();\n}\n", "import Node from \"../Node\";\n\n/**\n * A leaf node.\n */\nexport default abstract class Leaf extends Node {\n /**\n * Gets whether this node is a leaf node.\n */\n isLeafNode = () => true;\n}\n", "import { ActionResult, Agent, ExitFunctionArg, FunctionArg, GlobalFunction } from \"./Agent\";\nimport { AnyArgument, RootAstNode } from \"./RootAstNodesBuilder\";\n\n// Exit callbacks receive their own special type of argument.\n// There's probably stricter ways to represent this but it feels overly complex right now.\ntype ExitResultArg = { value: ExitFunctionArg };\nexport type AnyExitArgument = AnyArgument | ExitResultArg;\n\nexport type InvokerFunction = (args: AnyExitArgument[]) => ActionResult;\n\n/**\n * A singleton used to store and lookup registered functions and subtrees.\n */\nexport default class Lookup {\n /**\n * The object holding any registered functions keyed on function name.\n */\n private static functionTable: { [key: string]: GlobalFunction } = {};\n /**\n * The object holding any registered sub-trees keyed on tree name.\n */\n private static subtreeTable: { [key: string]: RootAstNode } = {};\n\n /**\n * Gets the function with the specified name.\n * @param name The name of the function.\n * @returns The function with the specified name.\n */\n public static getFunc(name: string): GlobalFunction {\n return this.functionTable[name];\n }\n\n /**\n * Sets the function with the specified name for later lookup.\n * @param name The name of the function.\n * @param func The function.\n */\n public static setFunc(name: string, func: GlobalFunction): void {\n this.functionTable[name] = func;\n }\n\n /**\n * Gets the function invoker for the specified agent and function name.\n * If a function with the specified name exists on the agent object then it will\n * be returned, otherwise we will then check the registered functions for a match.\n * @param agent The agent instance that this behaviour tree is modelling behaviour for.\n * @param name The function name.\n * @returns The function invoker for the specified agent and function name.\n */\n static getFuncInvoker(agent: Agent, name: string): InvokerFunction | null {\n // Check whether the agent contains the specified function.\n const foundOnAgent = agent[name];\n if (foundOnAgent && typeof foundOnAgent === \"function\") {\n return (args: AnyExitArgument[]): boolean | ActionResult =>\n foundOnAgent.apply(\n agent,\n args.map((arg) => arg.value)\n );\n }\n\n // The agent does not contain the specified function but it may have been registered at some point.\n if (this.functionTable[name] && typeof this.functionTable[name] === \"function\") {\n return (args: AnyExitArgument[]) => this.functionTable[name](agent, ...args.map((arg) => arg.value));\n }\n\n // We have no function to invoke.\n return null;\n }\n\n /**\n * Gets the subtree with the specified name.\n * @param name The name of the subtree.\n * @returns The subtree with the specified name.\n */\n static getSubtree(name: string): RootAstNode {\n return this.subtreeTable[name];\n }\n\n /**\n * Sets the subtree with the specified name for later lookup.\n * @param name The name of the subtree.\n * @param subtree The subtree.\n */\n static setSubtree(name: string, subtree: RootAstNode) {\n this.subtreeTable[name] = subtree;\n }\n\n /**\n * Removes the registered function or subtree with the specified name.\n * @param name The name of the registered function or subtree.\n */\n static remove(name: string) {\n delete this.functionTable[name];\n delete this.subtreeTable[name];\n }\n\n /**\n * Remove all registered functions and subtrees.\n */\n static empty() {\n this.functionTable = {};\n this.subtreeTable = {};\n }\n}\n", "import Leaf from \"./Leaf\";\nimport State, { CompleteState } from \"../../State\";\nimport Lookup from \"../../Lookup\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { AnyArgument } from \"../../RootAstNodesBuilder\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * An Action leaf node.\n * This represents an immediate or ongoing state of behaviour.\n */\nexport default class Action extends Leaf {\n /**\n * @param attributes The node attributes.\n * @param actionName The action name.\n * @param actionArguments The array of action argument definitions.\n */\n constructor(attributes: Attribute[], private actionName: string, private actionArguments: AnyArgument[]) {\n super(\"action\", attributes, actionArguments);\n }\n\n /**\n * Whether there is a pending update promise.\n */\n private isUsingUpdatePromise = false;\n\n /**\n * The finished state result of an update promise.\n */\n private updatePromiseStateResult: CompleteState | null = null;\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // If the result of this action depends on an update promise then there is nothing to do until\n // it resolves, unless there has been a value set as a result of the update promise resolving.\n if (this.isUsingUpdatePromise) {\n // Check whether the update promise has resolved with a state value.\n if (this.updatePromiseStateResult) {\n // Set the state of this node to match the state returned by the promise.\n this.setState(this.updatePromiseStateResult);\n }\n\n return;\n }\n\n // Attempt to get the invoker for the action function.\n const actionFuncInvoker = Lookup.getFuncInvoker(agent, this.actionName);\n\n // The action function should be defined.\n if (actionFuncInvoker === null) {\n throw new Error(\n `cannot update action node as the action '${this.actionName}' function is not defined on the agent and has not been registered`\n );\n }\n\n // Call the action function, the result of which may be:\n // - The finished state of this action node.\n // - A promise to return a finished node state.\n // - Undefined if the node should remain in the running state.\n const updateResult = actionFuncInvoker(this.actionArguments) as CompleteState | Promise;\n\n if (updateResult instanceof Promise) {\n updateResult.then(\n (result) => {\n // If 'isUpdatePromisePending' is null then the promise was cleared as it was resolving, probably via an abort of reset.\n if (!this.isUsingUpdatePromise) {\n return;\n }\n\n // Check to make sure the result is a valid finished state.\n if (result !== State.SUCCEEDED && result !== State.FAILED) {\n throw new Error(\n \"action node promise resolved with an invalid value, expected a State.SUCCEEDED or State.FAILED value to be returned\"\n );\n }\n\n // Set pending update promise state result to be processed on next update.\n this.updatePromiseStateResult = result;\n },\n (reason) => {\n // If 'isUpdatePromisePending' is null then the promise was cleared as it was resolving, probably via an abort of reset.\n if (!this.isUsingUpdatePromise) {\n return;\n }\n\n // Just throw whatever was returned as the rejection argument.\n throw new Error(reason);\n }\n );\n\n // This node will be in the 'RUNNING' state until the update promise resolves.\n this.setState(State.RUNNING);\n\n // We are now waiting for the promise returned by the use to resolve before we know what state this node is in.\n this.isUsingUpdatePromise = true;\n } else {\n // Validate the returned value.\n this.validateUpdateResult(updateResult);\n\n // Set the state of this node, this may be undefined, which just means that the node is still in the 'RUNNING' state.\n this.setState(updateResult || State.RUNNING);\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => this.actionName;\n\n /**\n * Reset the state of the node.\n */\n reset = () => {\n // Reset the state of this node.\n this.setState(State.READY);\n\n // There is no longer an update promise that we care about.\n this.isUsingUpdatePromise = false;\n this.updatePromiseStateResult = null;\n };\n\n /**\n * Validate the result of an update function call.\n * @param result The result of an update function call.\n */\n private validateUpdateResult = (result: CompleteState | boolean) => {\n switch (result) {\n case State.SUCCEEDED:\n case State.FAILED:\n case undefined:\n return;\n default:\n throw new Error(\n `action '${this.actionName}' 'onUpdate' returned an invalid response, expected an optional State.SUCCEEDED or State.FAILED value to be returned`\n );\n }\n };\n}\n", "import Leaf from \"./Leaf\";\nimport State from \"../../State\";\nimport Lookup from \"../../Lookup\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { AnyArgument } from \"../../RootAstNodesBuilder\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A Condition leaf node.\n * This will succeed or fail immediately based on an agent predicate, without moving to the 'RUNNING' state.\n */\nexport default class Condition extends Leaf {\n /**\n * @param attributes The node attributes.\n * @param conditionName The name of the condition function.\n * @param conditionArguments The array of condition argument definitions.\n */\n constructor(attributes: Attribute[], private conditionName: string, private conditionArguments: AnyArgument[]) {\n super(\"condition\", attributes, conditionArguments);\n }\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // Attempt to get the invoker for the condition function.\n const conditionFuncInvoker = Lookup.getFuncInvoker(agent, this.conditionName);\n\n // The condition function should be defined.\n if (conditionFuncInvoker === null) {\n throw new Error(\n `cannot update condition node as the condition '${this.conditionName}' function is not defined on the agent and has not been registered`\n );\n }\n\n // Call the condition function to determine the state of this node.\n this.setState(!!conditionFuncInvoker(this.conditionArguments) ? State.SUCCEEDED : State.FAILED);\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => this.conditionName;\n}\n", "import Leaf from \"./Leaf\";\nimport State from \"../../State\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { Agent } from \"../../Agent\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A WAIT node.\n * The state of this node will change to SUCCEEDED after a duration of time\n */\nexport default class Wait extends Leaf {\n /**\n * @param attributes The node attributes.\n * @param duration The duration that this node will wait to succeed in milliseconds.\n * @param durationMin The minimum possible duration in milliseconds that this node will wait to succeed.\n * @param durationMax The maximum possible duration in milliseconds that this node will wait to succeed.\n */\n constructor(\n attributes: Attribute[],\n private duration: number | null,\n private durationMin: number | null,\n private durationMax: number | null\n ) {\n super(\"wait\", attributes, []);\n }\n\n /**\n * The time in milliseconds at which this node was first updated.\n */\n private initialUpdateTime: number = 0;\n\n /**\n * The total duration in milliseconds that this node will be waiting for.\n */\n private totalDuration: number | null = null;\n\n /**\n * The duration in milliseconds that this node has been waiting for.\n */\n private waitedDuration: number = 0;\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // If this node is in the READY state then we need to set the initial update time.\n if (this.is(State.READY)) {\n // Set the initial update time.\n this.initialUpdateTime = new Date().getTime();\n\n // Set the initial waited duration.\n this.waitedDuration = 0;\n\n // Are we dealing with an explicit duration or will we be randomly picking a duration between the min and max duration.\n if (this.duration !== null) {\n this.totalDuration = this.duration;\n } else if (this.durationMin !== null && this.durationMax !== null) {\n // We will be picking a random duration between a min and max duration, if the optional 'random' behaviour tree\n // function option is defined then we will be using that, otherwise we will fall back to using Math.random.\n const random = typeof options.random === \"function\" ? options.random : Math.random;\n\n // Pick a random duration between a min and max duration.\n this.totalDuration = Math.floor(\n random() * (this.durationMax - this.durationMin + 1) + this.durationMin\n );\n } else {\n this.totalDuration = null;\n }\n\n // The node is now running until we finish waiting.\n this.setState(State.RUNNING);\n }\n\n // If we have no total duration then this wait node will wait indefinitely until it is aborted.\n if (this.totalDuration === null) {\n return;\n }\n\n // If we have a 'getDeltaTime' function defined as part of our options then we will use it to figure out how long we have waited for.\n if (typeof options.getDeltaTime === \"function\") {\n // Get the delta time.\n const deltaTime = options.getDeltaTime();\n\n // Our delta time must be a valid number and cannot be NaN.\n if (typeof deltaTime !== \"number\" || isNaN(deltaTime)) {\n throw new Error(\"The delta time must be a valid number and not NaN.\");\n }\n\n // Update the amount of time that this node has been waiting for based on the delta time.\n this.waitedDuration += deltaTime * 1000;\n } else {\n // We are not using a delta time, so we will just work out hom much time has passed since the first update.\n this.waitedDuration = new Date().getTime() - this.initialUpdateTime;\n }\n\n // Have we waited long enough?\n if (this.waitedDuration >= this.totalDuration) {\n // We have finished waiting!\n this.setState(State.SUCCEEDED);\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => {\n if (this.duration !== null) {\n return `WAIT ${this.duration}ms`;\n } else if (this.durationMin !== null && this.durationMax !== null) {\n return `WAIT ${this.durationMin}ms-${this.durationMax}ms`;\n } else {\n return \"WAIT\";\n }\n };\n}\n", "import Node from \"../Node\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\n\n/**\n * A decorator node that wraps a single child node.\n */\nexport default abstract class Decorator extends Node {\n /**\n * @param type The node type.\n * @param attributes The node attributes.\n * @param child The child node.\n */\n constructor(type: string, attributes: Attribute[], protected child: Node) {\n super(type, attributes, []);\n }\n\n /**\n * Gets whether this node is a leaf node.\n */\n isLeafNode = () => false;\n\n /**\n * Gets the children of this node.\n */\n getChildren = () => [this.child];\n\n /**\n * Reset the state of the node.\n */\n reset = () => {\n // Reset the state of this node.\n this.setState(State.READY);\n\n // Reset the state of the child node.\n this.child.reset();\n };\n\n /**\n * Abort the running of this node.\n * @param agent The agent.\n */\n abort = (agent: Agent) => {\n // There is nothing to do if this node is not in the running state.\n if (!this.is(State.RUNNING)) {\n return;\n }\n\n // Abort the child node.\n this.child.abort(agent);\n\n // Reset the state of this node.\n this.reset();\n\n this.getAttribute(\"exit\")?.callAgentFunction(agent, false, true);\n };\n}\n", "import Node from \"../Node\";\nimport Decorator from \"./Decorator\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A Root node.\n * The root node will have a single child.\n */\nexport default class Root extends Decorator {\n /**\n * @param attributes The node attributes.\n * @param child The child node.\n */\n constructor(attributes: Attribute[], child: Node) {\n super(\"root\", attributes, child);\n }\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // If the child has never been updated or is running then we will need to update it now.\n if (this.child.getState() === State.READY || this.child.getState() === State.RUNNING) {\n // Update the child of this node.\n this.child.update(agent, options);\n }\n\n // The state of the root node is the state of its child.\n this.setState(this.child.getState());\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => \"ROOT\";\n}\n", "import Node from \"../Node\";\nimport Decorator from \"./Decorator\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A REPEAT node.\n * The node has a single child which can have:\n * -- A number of iterations for which to repeat the child node.\n * -- An infinite repeat loop if neither an iteration count or a condition function is defined.\n * The REPEAT node will stop and have a 'FAILED' state if its child is ever in a 'FAILED' state after an update.\n * The REPEAT node will attempt to move on to the next iteration if its child is ever in a 'SUCCEEDED' state.\n */\nexport default class Repeat extends Decorator {\n /**\n * @param attributes The node attributes.\n * @param iterations The number of iterations to repeat the child node.\n * @param iterationsMin The minimum possible number of iterations to repeat the child node.\n * @param iterationsMax The maximum possible number of iterations to repeat the child node.\n * @param child The child node.\n */\n constructor(\n attributes: Attribute[],\n private iterations: number | null,\n private iterationsMin: number | null,\n private iterationsMax: number | null,\n child: Node\n ) {\n super(\"repeat\", attributes, child);\n }\n\n /**\n * The number of target iterations to make.\n */\n private targetIterationCount: number | null = null;\n\n /**\n * The current iteration count.\n */\n private currentIterationCount: number = 0;\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // If this node is in the READY state then we need to reset the child and the target iteration count.\n if (this.is(State.READY)) {\n // Reset the child node.\n this.child.reset();\n\n // Reset the current iteration count.\n this.currentIterationCount = 0;\n\n // Set the target iteration count.\n this.setTargetIterationCount(options);\n }\n\n // Do a check to see if we can iterate. If we can then this node will move into the 'RUNNING' state.\n // If we cannot iterate then we have hit our target iteration count, which means that the node has succeeded.\n if (this.canIterate()) {\n // This node is in the running state and can do its initial iteration.\n this.setState(State.RUNNING);\n\n // We may have already completed an iteration, meaning that the child node will be in the SUCCEEDED state.\n // If this is the case then we will have to reset the child node now.\n if (this.child.getState() === State.SUCCEEDED) {\n this.child.reset();\n }\n\n // Update the child of this node.\n this.child.update(agent, options);\n\n // If the child moved into the FAILED state when we updated it then there is nothing left to do and this node has also failed.\n // If it has moved into the SUCCEEDED state then we have completed the current iteration.\n if (this.child.getState() === State.FAILED) {\n // The child has failed, meaning that this node has failed.\n this.setState(State.FAILED);\n\n return;\n } else if (this.child.getState() === State.SUCCEEDED) {\n // We have completed an iteration.\n this.currentIterationCount += 1;\n }\n } else {\n // This node is in the 'SUCCEEDED' state as we cannot iterate any more.\n this.setState(State.SUCCEEDED);\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => {\n if (this.iterations !== null) {\n return `REPEAT ${this.iterations}x`;\n } else if (this.iterationsMin !== null && this.iterationsMax !== null) {\n return `REPEAT ${this.iterationsMin}x-${this.iterationsMax}x`;\n } else {\n return \"REPEAT\";\n }\n };\n\n /**\n * Reset the state of the node.\n */\n reset = () => {\n // Reset the state of this node.\n this.setState(State.READY);\n\n // Reset the current iteration count.\n this.currentIterationCount = 0;\n\n // Reset the child node.\n this.child.reset();\n };\n\n /**\n * Gets whether an iteration can be made.\n * @returns Whether an iteration can be made.\n */\n private canIterate = () => {\n if (this.targetIterationCount !== null) {\n // We can iterate as long as we have not reached our target iteration count.\n return this.currentIterationCount < this.targetIterationCount;\n }\n\n // If neither an iteration count or a condition function were defined then we can iterate indefinitely.\n return true;\n };\n\n /**\n * Sets the target iteration count.\n * @param options The behaviour tree options object.\n */\n private setTargetIterationCount = (options: BehaviourTreeOptions) => {\n // Are we dealing with an explicit iteration count or will we be randomly picking a iteration count between the min and max iteration count.\n if (this.iterations !== null) {\n this.targetIterationCount = this.iterations;\n } else if (this.iterationsMin !== null && this.iterationsMax !== null) {\n // We will be picking a random iteration count between a min and max iteration count, if the optional 'random'\n // behaviour tree function option is defined then we will be using that, otherwise we will fall back to using Math.random.\n const random = typeof options.random === \"function\" ? options.random : Math.random;\n\n // Pick a random iteration count between a min and max iteration count.\n this.targetIterationCount = Math.floor(\n random() * (this.iterationsMax - this.iterationsMin + 1) + this.iterationsMin\n );\n } else {\n this.targetIterationCount = null;\n }\n };\n}\n", "import Node from \"../Node\";\nimport Decorator from \"./Decorator\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A RETRY node.\n * The node has a single child which can have:\n * -- A number of iterations for which to repeat the child node.\n * -- An infinite repeat loop if neither an iteration count or a condition function is defined.\n * The RETRY node will stop and have a 'SUCCEEDED' state if its child is ever in a 'SUCCEEDED' state after an update.\n * The RETRY node will attempt to move on to the next iteration if its child is ever in a 'FAILED' state.\n */\nexport default class Retry extends Decorator {\n /**\n * @param attributes The node attributes.\n * @param attempts The number of attempts to retry the child node.\n * @param attemptsMin The minimum possible number of attempts to retry the child node.\n * @param attemptsMax The maximum possible number of attempts to retry the child node.\n * @param child The child node.\n */\n constructor(\n attributes: Attribute[],\n private attempts: number | null,\n private attemptsMin: number | null,\n private attemptsMax: number | null,\n child: Node\n ) {\n super(\"retry\", attributes, child);\n }\n\n /**\n * The number of target attempts to make.\n */\n private targetAttemptCount: number | null = null;\n\n /**\n * The current attempt count.\n */\n private currentAttemptCount: number = 0;\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // If this node is in the READY state then we need to reset the child and the target attempt count.\n if (this.is(State.READY)) {\n // Reset the child node.\n this.child.reset();\n\n // Reset the current attempt count.\n this.currentAttemptCount = 0;\n\n // Set the target attempt count.\n this.setTargetAttemptCount(options);\n }\n\n // Do a check to see if we can attempt. If we can then this node will move into the 'RUNNING' state.\n // If we cannot attempt then we have hit our target attempt count, which means that the node has succeeded.\n if (this.canAttempt()) {\n // This node is in the running state and can do its initial attempt.\n this.setState(State.RUNNING);\n\n // We may have already completed an attempt, meaning that the child node will be in the FAILED state.\n // If this is the case then we will have to reset the child node now.\n if (this.child.getState() === State.FAILED) {\n this.child.reset();\n }\n\n // Update the child of this node.\n this.child.update(agent, options);\n\n // If the child moved into the SUCCEEDED state when we updated it then there is nothing left to do and this node has also succeeded.\n // If it has moved into the FAILED state then we have completed the current attempt.\n if (this.child.getState() === State.SUCCEEDED) {\n // The child has succeeded, meaning that this node has succeeded.\n this.setState(State.SUCCEEDED);\n\n return;\n } else if (this.child.getState() === State.FAILED) {\n // We have completed an attempt.\n this.currentAttemptCount += 1;\n }\n } else {\n // This node is in the 'FAILED' state as we cannot iterate any more.\n this.setState(State.FAILED);\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => {\n if (this.attempts !== null) {\n return `RETRY ${this.attempts}x`;\n } else if (this.attemptsMin !== null && this.attemptsMax !== null) {\n return `RETRY ${this.attemptsMin}x-${this.attemptsMax}x`;\n } else {\n return \"RETRY\";\n }\n };\n\n /**\n * Reset the state of the node.\n */\n reset = () => {\n // Reset the state of this node.\n this.setState(State.READY);\n\n // Reset the current attempt count.\n this.currentAttemptCount = 0;\n\n // Reset the child node.\n this.child.reset();\n };\n\n /**\n * Gets whether an attempt can be made.\n * @returns Whether an attempt can be made.\n */\n canAttempt = () => {\n if (this.targetAttemptCount !== null) {\n // We can attempt as long as we have not reached our target attempt count.\n return this.currentAttemptCount < this.targetAttemptCount;\n }\n\n // If neither an attempt count or a condition function were defined then we can attempt indefinitely.\n return true;\n };\n\n /**\n * Sets the target attempt count.\n * @param options The behaviour tree options object.\n */\n setTargetAttemptCount = (options: BehaviourTreeOptions) => {\n // Are we dealing with an explicit attempt count or will we be randomly picking an attempt count between the min and max attempt count.\n if (this.attempts !== null) {\n this.targetAttemptCount = this.attempts;\n } else if (this.attemptsMin !== null && this.attemptsMax !== null) {\n // We will be picking a random attempt count between a min and max attempt count, if the optional 'random'\n // behaviour tree function option is defined then we will be using that, otherwise we will fall back to using Math.random.\n const random = typeof options.random === \"function\" ? options.random : Math.random;\n\n // Pick a random attempt count between a min and max attempt count.\n this.targetAttemptCount = Math.floor(\n random() * (this.attemptsMax - this.attemptsMin + 1) + this.attemptsMin\n );\n } else {\n this.targetAttemptCount = null;\n }\n };\n}\n", "import Decorator from \"./Decorator\";\nimport State from \"../../State\";\nimport Node from \"../Node\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A Flip node.\n * This node wraps a single child and will flip the state of the child state.\n */\nexport default class Flip extends Decorator {\n /**\n * @param attributes The node attributes.\n * @param child The child node.\n */\n constructor(attributes: Attribute[], child: Node) {\n super(\"flip\", attributes, child);\n }\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // If the child has never been updated or is running then we will need to update it now.\n if (this.child.getState() === State.READY || this.child.getState() === State.RUNNING) {\n this.child.update(agent, options);\n }\n\n // The state of this node will depend in the state of its child.\n switch (this.child.getState()) {\n case State.RUNNING:\n this.setState(State.RUNNING);\n break;\n\n case State.SUCCEEDED:\n this.setState(State.FAILED);\n break;\n\n case State.FAILED:\n this.setState(State.SUCCEEDED);\n break;\n\n default:\n this.setState(State.READY);\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => \"FLIP\";\n}\n", "import Node from \"../Node\";\nimport Decorator from \"./Decorator\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A Succeed node.\n * This node wraps a single child and will always move to the 'SUCCEEDED' state when the child moves to a 'SUCCEEDED' or 'FAILED' state.\n */\nexport default class Succeed extends Decorator {\n /**\n * @param attributes The node attributes.\n * @param child The child node.\n */\n constructor(attributes: Attribute[], child: Node) {\n super(\"succeed\", attributes, child);\n }\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // If the child has never been updated or is running then we will need to update it now.\n if (this.child.getState() === State.READY || this.child.getState() === State.RUNNING) {\n this.child.update(agent, options);\n }\n\n // The state of this node will depend in the state of its child.\n switch (this.child.getState()) {\n case State.RUNNING:\n this.setState(State.RUNNING);\n break;\n\n case State.SUCCEEDED:\n case State.FAILED:\n this.setState(State.SUCCEEDED);\n break;\n\n default:\n this.setState(State.READY);\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => \"SUCCEED\";\n}\n", "import Node from \"../Node\";\nimport Decorator from \"./Decorator\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A Fail node.\n * This node wraps a single child and will always move to the 'FAILED' state when the child moves to a 'SUCCEEDED' or 'FAILED' state.\n */\nexport default class Fail extends Decorator {\n /**\n * @param attributes The node attributes.\n * @param child The child node.\n */\n constructor(attributes: Attribute[], child: Node) {\n super(\"fail\", attributes, child);\n }\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // If the child has never been updated or is running then we will need to update it now.\n if (this.child.getState() === State.READY || this.child.getState() === State.RUNNING) {\n this.child.update(agent, options);\n }\n\n // The state of this node will depend in the state of its child.\n switch (this.child.getState()) {\n case State.RUNNING:\n this.setState(State.RUNNING);\n break;\n\n case State.SUCCEEDED:\n case State.FAILED:\n this.setState(State.FAILED);\n break;\n\n default:\n this.setState(State.READY);\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => \"FAIL\";\n}\n", "import createLotto from \"lotto-draw\";\n\nimport Node from \"../Node\";\nimport Composite from \"./Composite\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A LOTTO node.\n * A winning child is picked on the initial update of this node, based on ticket weighting.\n * The state of this node will match the state of the winning child.\n */\nexport default class Lotto extends Composite {\n /**\n * @param attributes The node attributes.\n * @param tickets The child node tickets.\n * @param children The child nodes.\n */\n constructor(attributes: Attribute[], private tickets: number[], children: Node[]) {\n super(\"lotto\", attributes, children);\n }\n\n /**\n * The child node selected to be the active one.\n */\n private selectedChild: Node | undefined;\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // If this node is in the READY state then we need to pick a winning child node.\n if (this.is(State.READY)) {\n // Create a lotto draw with which to randomly pick a child node to become the active one.\n const lottoDraw = createLotto({\n // Hook up the optional 'random' behaviour tree function option to the one used by 'lotto-draw'.\n random: options.random,\n // Pass in each child node as a participant in the lotto draw with their respective ticket count.\n participants: this.children.map((child, index) => [child, this.tickets[index] || 1])\n });\n\n // Randomly pick a child based on ticket weighting, this will become the active child for this composite node.\n this.selectedChild = lottoDraw.draw() || undefined;\n }\n\n // If something went wrong and we don't have an active child then we should throw an error.\n if (!this.selectedChild) {\n throw new Error(\"failed to update lotto node as it has no active child\");\n }\n\n // If the selected child has never been updated or is running then we will need to update it now.\n if (this.selectedChild.getState() === State.READY || this.selectedChild.getState() === State.RUNNING) {\n this.selectedChild.update(agent, options);\n }\n\n // The state of the lotto node is the state of its selected child.\n this.setState(this.selectedChild.getState());\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => (this.tickets.length ? `LOTTO [${this.tickets.join(\",\")}]` : \"LOTTO\");\n}\n", "import Node from \"../Node\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\n\n/**\n * A composite node that wraps child nodes.\n */\nexport default abstract class Composite extends Node {\n /**\n * @param type The node type.\n * @param attributes The node attributes.\n * @param children The child nodes.\n */\n constructor(type: string, attributes: Attribute[], protected children: Node[]) {\n super(type, attributes, []);\n }\n\n /**\n * Gets whether this node is a leaf node.\n */\n isLeafNode = () => false;\n\n /**\n * Gets the children of this node.\n */\n getChildren = () => this.children;\n\n /**\n * Reset the state of the node.\n */\n reset = () => {\n // Reset the state of this node.\n this.setState(State.READY);\n\n // Reset the state of any child nodes.\n this.getChildren().forEach((child) => child.reset());\n };\n\n /**\n * Abort the running of this node.\n * @param agent The agent.\n */\n abort = (agent: Agent) => {\n // There is nothing to do if this node is not in the running state.\n if (!this.is(State.RUNNING)) {\n return;\n }\n\n // Abort any child nodes.\n this.getChildren().forEach((child) => child.abort(agent));\n\n // Reset the state of this node.\n this.reset();\n\n this.getAttribute(\"exit\")?.callAgentFunction(agent, false, true);\n };\n}\n", "import Composite from \"./Composite\";\nimport Node from \"../Node\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A SELECTOR node.\n * The child nodes are executed in sequence until one succeeds or all fail.\n */\nexport default class Selector extends Composite {\n /**\n * @param attributes The node attributes.\n * @param children The child nodes.\n */\n constructor(attributes: Attribute[], protected children: Node[]) {\n super(\"selector\", attributes, children);\n }\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // Iterate over all of the children of this node.\n for (const child of this.children) {\n // If the child has never been updated or is running then we will need to update it now.\n if (child.getState() === State.READY || child.getState() === State.RUNNING) {\n // Update the child of this node.\n child.update(agent, options);\n }\n\n // If the current child has a state of 'SUCCEEDED' then this node is also a 'SUCCEEDED' node.\n if (child.getState() === State.SUCCEEDED) {\n // This node is a 'SUCCEEDED' node.\n this.setState(State.SUCCEEDED);\n\n // There is no need to check the rest of the selector nodes.\n return;\n }\n\n // If the current child has a state of 'FAILED' then we should move on to the next child.\n if (child.getState() === State.FAILED) {\n // Find out if the current child is the last one in the selector.\n // If it is then this sequence node has also failed.\n if (this.children.indexOf(child) === this.children.length - 1) {\n // This node is a 'FAILED' node.\n this.setState(State.FAILED);\n\n // There is no need to check the rest of the selector as we have completed it.\n return;\n } else {\n // The child node failed, try the next one.\n continue;\n }\n }\n\n // The node should be in the 'RUNNING' state.\n if (child.getState() === State.RUNNING) {\n // This node is a 'RUNNING' node.\n this.setState(State.RUNNING);\n\n // There is no need to check the rest of the selector as the current child is still running.\n return;\n }\n\n // The child node was not in an expected state.\n throw new Error(\"child node was not in an expected state.\");\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => \"SELECTOR\";\n}\n", "import Composite from \"./Composite\";\nimport Node from \"../Node\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A SEQUENCE node.\n * The child nodes are executed in sequence until one fails or all succeed.\n */\nexport default class Sequence extends Composite {\n /**\n * @param attributes The node attributes.\n * @param children The child nodes.\n */\n constructor(attributes: Attribute[], protected children: Node[]) {\n super(\"sequence\", attributes, children);\n }\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // Iterate over all of the children of this node.\n for (const child of this.children) {\n // If the child has never been updated or is running then we will need to update it now.\n if (child.getState() === State.READY || child.getState() === State.RUNNING) {\n // Update the child of this node.\n child.update(agent, options);\n }\n\n // If the current child has a state of 'SUCCEEDED' then we should move on to the next child.\n if (child.getState() === State.SUCCEEDED) {\n // Find out if the current child is the last one in the sequence.\n // If it is then this sequence node has also succeeded.\n if (this.children.indexOf(child) === this.children.length - 1) {\n // This node is a 'SUCCEEDED' node.\n this.setState(State.SUCCEEDED);\n\n // There is no need to check the rest of the sequence as we have completed it.\n return;\n } else {\n // The child node succeeded, but we have not finished the sequence yet.\n continue;\n }\n }\n\n // If the current child has a state of 'FAILED' then this node is also a 'FAILED' node.\n if (child.getState() === State.FAILED) {\n // This node is a 'FAILED' node.\n this.setState(State.FAILED);\n\n // There is no need to check the rest of the sequence.\n return;\n }\n\n // The node should be in the 'RUNNING' state.\n if (child.getState() === State.RUNNING) {\n // This node is a 'RUNNING' node.\n this.setState(State.RUNNING);\n\n // There is no need to check the rest of the sequence as the current child is still running.\n return;\n }\n\n // The child node was not in an expected state.\n throw new Error(\"child node was not in an expected state.\");\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => \"SEQUENCE\";\n}\n", "import Composite from \"./Composite\";\nimport State from \"../../State\";\nimport Node from \"../Node\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A PARALLEL node.\n * The child nodes are executed concurrently until one fails or all succeed.\n */\nexport default class Parallel extends Composite {\n /**\n * @param attributes The node attributes.\n * @param children The child nodes.\n */\n constructor(attributes: Attribute[], children: Node[]) {\n super(\"parallel\", attributes, children);\n }\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // Keep a count of the number of succeeded child nodes.\n let succeededCount = 0;\n\n let hasChildFailed = false;\n\n // Iterate over all of the children of this node.\n for (const child of this.children) {\n // If the child has never been updated or is running then we will need to update it now.\n if (child.getState() === State.READY || child.getState() === State.RUNNING) {\n // Update the child of this node.\n child.update(agent, options);\n }\n\n // If the current child has a state of 'SUCCEEDED' then we should move on to the next child.\n if (child.getState() === State.SUCCEEDED) {\n // The child node has succeeded, keep track of this to determine if all children have.\n succeededCount++;\n\n // The child node succeeded, but we have not finished checking every child node yet.\n continue;\n }\n\n // If the current child has a state of 'FAILED' then this node is also a 'FAILED' node.\n if (child.getState() === State.FAILED) {\n hasChildFailed = true;\n\n // There is no need to check the rest of the children.\n break;\n }\n\n // The node should be in the 'RUNNING' state.\n if (child.getState() !== State.RUNNING) {\n // The child node was not in an expected state.\n throw new Error(\"child node was not in an expected state.\");\n }\n }\n\n if (hasChildFailed) {\n // This node is a 'FAILED' node.\n this.setState(State.FAILED);\n\n // Abort every running child.\n for (const child of this.children) {\n if (child.getState() === State.RUNNING) {\n child.abort(agent);\n }\n }\n } else {\n // If all children have succeeded then this node has also succeeded, otherwise it is still running.\n this.setState(succeededCount === this.children.length ? State.SUCCEEDED : State.RUNNING);\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => \"PARALLEL\";\n}\n", "import { AnyArgument } from \"../RootAstNodesBuilder\";\nimport Guard from \"./guards/Guard\";\n\nexport type AttributeDetails = {\n /** The attribute type. */\n type: string;\n\n /** The attribute arguments. */\n args: AnyArgument[];\n};\n\n/**\n * A base node attribute.\n */\nexport default abstract class Attribute {\n /**\n * @param type The node attribute type.\n * @param args The array of attribute argument definitions.\n */\n constructor(protected type: string, protected args: AnyArgument[]) {}\n\n /**\n * Gets the type of the attribute.\n */\n getType = () => this.type;\n\n /**\n * Gets the array of attribute argument definitions.\n */\n getArguments = () => this.args;\n\n /**\n * Gets the attribute details.\n */\n abstract getDetails(): TAttributeDetails;\n\n /**\n * Gets whether this attribute is a guard.\n */\n abstract isGuard: () => this is Guard;\n}\n", "import { Agent } from \"../../Agent\";\nimport { AnyArgument } from \"../../RootAstNodesBuilder\";\nimport Attribute, { AttributeDetails } from \"../Attribute\";\n\nexport type GuardAttributeDetails = {\n /** The name of the condition function that determines whether the guard is satisfied. */\n condition: string;\n} & AttributeDetails;\n\n/**\n * A base node guard attribute.\n */\nexport default abstract class Guard extends Attribute {\n /**\n * @param type The node attribute type.\n * @param args The array of decorator argument definitions.\n * @param condition The name of the condition function that determines whether the guard is satisfied.\n */\n constructor(type: string, args: AnyArgument[], private condition: string) {\n super(type, args);\n }\n\n /**\n * Gets the name of the condition function that determines whether the guard is satisfied.\n */\n getCondition = () => this.condition;\n\n /**\n * Gets whether this attribute is a guard.\n */\n isGuard = () => true;\n\n /**\n * Gets the attribute details.\n */\n getDetails(): GuardAttributeDetails {\n return {\n type: this.getType(),\n args: this.getArguments(),\n condition: this.getCondition()\n };\n }\n\n /**\n * Gets whether the guard is satisfied.\n * @param agent The agent.\n * @returns Whether the guard is satisfied.\n */\n abstract isSatisfied(agent: Agent): boolean;\n}\n", "import Guard from \"./Guard\";\nimport Lookup from \"../../Lookup\";\nimport { Agent } from \"../../Agent\";\nimport { AnyArgument } from \"../../RootAstNodesBuilder\";\n\n/**\n * A WHILE guard which is satisfied as long as the given condition remains true.\n */\nexport default class While extends Guard {\n /**\n * @param condition The name of the condition function that determines whether the guard is satisfied.\n * @param args The array of decorator argument definitions.\n */\n constructor(condition: string, args: AnyArgument[]) {\n super(\"while\", args, condition);\n }\n\n /**\n * Gets whether the guard is satisfied.\n * @param agent The agent.\n * @returns Whether the guard is satisfied.\n */\n isSatisfied = (agent: Agent) => {\n // Attempt to get the invoker for the condition function.\n const conditionFuncInvoker = Lookup.getFuncInvoker(agent, this.getCondition());\n\n // The condition function should be defined.\n if (conditionFuncInvoker === null) {\n throw new Error(\n `cannot evaluate node guard as the condition '${this.getCondition()}' function is not defined on the agent and has not been registered`\n );\n }\n\n // Call the condition function to determine whether this guard is satisfied.\n return !!conditionFuncInvoker(this.args);\n };\n}\n", "import Guard from \"./Guard\";\nimport Lookup from \"../../Lookup\";\nimport { Agent } from \"../../Agent\";\nimport { AnyArgument } from \"../../RootAstNodesBuilder\";\n\n/**\n * An UNTIL guard which is satisfied as long as the given condition remains false.\n */\nexport default class Until extends Guard {\n /**\n * @param condition The name of the condition function that determines whether the guard is satisfied.\n * @param args The array of decorator argument definitions.\n */\n constructor(condition: string, args: AnyArgument[]) {\n super(\"until\", args, condition);\n }\n\n /**\n * Gets whether the guard is satisfied.\n * @param agent The agent.\n * @returns Whether the guard is satisfied.\n */\n isSatisfied = (agent: Agent) => {\n // Attempt to get the invoker for the condition function.\n const conditionFuncInvoker = Lookup.getFuncInvoker(agent, this.getCondition());\n\n // The condition function should be defined.\n if (conditionFuncInvoker === null) {\n throw new Error(\n `cannot evaluate node guard as the condition '${this.getCondition()}' function is not defined on the agent and has not been registered`\n );\n }\n\n // Call the condition function to determine whether this guard is satisfied.\n return !!!conditionFuncInvoker(this.args);\n };\n}\n", "import { Agent } from \"../../Agent\";\nimport { AnyArgument } from \"../../RootAstNodesBuilder\";\nimport Attribute, { AttributeDetails } from \"../Attribute\";\n\nexport type CallbackAttributeDetails = {\n /** The name of the agent function that is called. */\n functionName: string;\n} & AttributeDetails;\n\n/**\n * A base node callback attribute.\n */\nexport default abstract class Callback extends Attribute {\n /**\n * @param type The node attribute type.\n * @param args The array of decorator argument definitions.\n * @param functionName The name of the agent function to call.\n */\n constructor(type: string, args: AnyArgument[], private functionName: string) {\n super(type, args);\n }\n\n /**\n * Gets the name of the agent function to call.\n */\n getFunctionName = () => this.functionName;\n\n /**\n * Gets whether this attribute is a guard.\n */\n isGuard = () => false;\n\n /**\n * Gets the attribute details.\n */\n getDetails(): CallbackAttributeDetails {\n return {\n type: this.getType(),\n args: this.getArguments(),\n functionName: this.getFunctionName()\n };\n }\n\n /**\n * Attempt to call the agent function that this callback refers to.\n * @param agent The agent.\n */\n abstract callAgentFunction: (agent: Agent, isSuccess: boolean, isAborted: boolean) => void;\n}\n", "import Callback from \"./Callback\";\nimport Lookup from \"../../Lookup\";\nimport { Agent } from \"../../Agent\";\nimport { AnyArgument } from \"../../RootAstNodesBuilder\";\n\n/**\n * An ENTRY callback which defines an agent function to call when the associated node is updated and moves out of running state.\n */\nexport default class Entry extends Callback {\n /**\n * @param functionName The name of the agent function to call.\n * @param args The array of callback argument definitions.\n */\n constructor(functionName: string, args: AnyArgument[]) {\n super(\"entry\", args, functionName);\n }\n\n /**\n * Attempt to call the agent function that this callback refers to.\n * @param agent The agent.\n */\n callAgentFunction = (agent: Agent) => {\n // Attempt to get the invoker for the callback function.\n const callbackFuncInvoker = Lookup.getFuncInvoker(agent, this.getFunctionName());\n\n // The callback function should be defined.\n if (callbackFuncInvoker === null) {\n throw new Error(\n `cannot call entry function '${this.getFunctionName()}' as is not defined on the agent and has not been registered`\n );\n }\n\n // Call the callback function.\n callbackFuncInvoker(this.args);\n };\n}\n", "import Callback from \"./Callback\";\nimport Lookup, { AnyExitArgument } from \"../../Lookup\";\nimport { Agent } from \"../../Agent\";\nimport { AnyArgument } from \"../../RootAstNodesBuilder\";\n\n/**\n * An EXIT callback which defines an agent function to call when the associated node is updated and moves to a finished state or is aborted.\n */\nexport default class Exit extends Callback {\n /**\n * @param functionName The name of the agent function to call.\n * @param args The array of callback argument definitions.\n */\n constructor(functionName: string, args: AnyArgument[]) {\n super(\"exit\", args, functionName);\n }\n\n /**\n * Attempt to call the agent function that this callback refers to.\n * @param agent The agent.\n * @param isSuccess Whether the decorated node was left with a success state.\n * @param isAborted Whether the decorated node was aborted.\n */\n callAgentFunction = (agent: Agent, isSuccess: boolean, isAborted: boolean) => {\n // Attempt to get the invoker for the callback function.\n const callbackFuncInvoker = Lookup.getFuncInvoker(agent, this.getFunctionName());\n\n // The callback function should be defined.\n if (callbackFuncInvoker === null) {\n throw new Error(\n `cannot call exit function '${this.getFunctionName()}' as is not defined on the agent and has not been registered`\n );\n }\n\n // Call the callback function\n callbackFuncInvoker([{ value: { succeeded: isSuccess, aborted: isAborted } }, ...this.args]);\n };\n}\n", "import Callback from \"./Callback\";\nimport Lookup from \"../../Lookup\";\nimport { Agent } from \"../../Agent\";\nimport { AnyArgument } from \"../../RootAstNodesBuilder\";\n\n/**\n * A STEP callback which defines an agent function to call when the associated node is updated.\n */\nexport default class Step extends Callback {\n /**\n * @param functionName The name of the agent function to call.\n * @param args The array of callback argument definitions.\n */\n constructor(functionName: string, args: AnyArgument[]) {\n super(\"step\", args, functionName);\n }\n\n /**\n * Attempt to call the agent function that this callback refers to.\n * @param agent The agent.\n */\n callAgentFunction = (agent: Agent) => {\n // Attempt to get the invoker for the callback function.\n const callbackFuncInvoker = Lookup.getFuncInvoker(agent, this.getFunctionName());\n\n // The callback function should be defined.\n if (callbackFuncInvoker === null) {\n throw new Error(\n `cannot call step function '${this.getFunctionName()}' as is not defined on the agent and has not been registered`\n );\n }\n\n // Call the callback function.\n callbackFuncInvoker(this.args);\n };\n}\n", "import Action from \"./nodes/leaf/Action\";\nimport Condition from \"./nodes/leaf/Condition\";\nimport Wait from \"./nodes/leaf/Wait\";\nimport Root from \"./nodes/decorator/Root\";\nimport Repeat from \"./nodes/decorator/Repeat\";\nimport Retry from \"./nodes/decorator/Retry\";\nimport Flip from \"./nodes/decorator/Flip\";\nimport Succeed from \"./nodes/decorator/Succeed\";\nimport Fail from \"./nodes/decorator/Fail\";\nimport Lotto from \"./nodes/composite/Lotto\";\nimport Selector from \"./nodes/composite/Selector\";\nimport Sequence from \"./nodes/composite/Sequence\";\nimport Parallel from \"./nodes/composite/Parallel\";\nimport Node from \"./nodes/Node\";\nimport While from \"./attributes/guards/While\";\nimport Until from \"./attributes/guards/Until\";\nimport Entry from \"./attributes/callbacks/Entry\";\nimport Exit from \"./attributes/callbacks/Exit\";\nimport Step from \"./attributes/callbacks/Step\";\nimport Callback from \"./attributes/callbacks/Callback\";\nimport Guard from \"./attributes/guards/Guard\";\nimport Attribute from \"./attributes/Attribute\";\nimport Composite from \"./nodes/composite/Composite\";\nimport Decorator from \"./nodes/decorator/Decorator\";\nimport Leaf from \"./nodes/leaf/Leaf\";\n\nexport type Argument = {\n value: T;\n type: string; // Used for validation.\n};\ntype NullArgument = Argument & {\n type: \"null\";\n};\ntype BooleanArgument = Argument & {\n type: \"boolean\";\n};\ntype NumberArgument = Argument & {\n type: \"number\";\n isInteger: boolean; // Used for validation.\n};\ntype StringPlaceholderArgument = Argument & {\n type: \"string\";\n};\ntype IdentifierArgument = Argument & {\n type: \"identifier\";\n};\nexport type AnyArgument =\n | NullArgument\n | BooleanArgument\n | NumberArgument\n | StringPlaceholderArgument\n | IdentifierArgument;\n\n/**\n * The node attribute factories.\n */\nconst AttributeFactories: {\n [key: string]: (functionName: string, attributeArguments: AnyArgument[]) => Callback | Guard;\n} = {\n WHILE: (condition: string, attributeArguments: AnyArgument[]) => new While(condition, attributeArguments),\n UNTIL: (condition: string, attributeArguments: AnyArgument[]) => new Until(condition, attributeArguments),\n ENTRY: (functionName: string, attributeArguments: AnyArgument[]) => new Entry(functionName, attributeArguments),\n EXIT: (functionName: string, attributeArguments: AnyArgument[]) => new Exit(functionName, attributeArguments),\n STEP: (functionName: string, attributeArguments: AnyArgument[]) => new Step(functionName, attributeArguments)\n};\n\ntype Validatable = {\n children?: AstNode[];\n validate: (depth: number) => void;\n};\n\ntype NodeInstanceCreator = (\n namedRootNodeProvider: (name: string) => RootAstNode,\n visitedBranches: string[]\n) => T;\n\nexport type AstNode = Validatable & {\n type: string;\n createNodeInstance: NodeInstanceCreator;\n};\n\nexport type LeafAstNode = AstNode & {\n type: \"action\" | \"condition\" | \"wait\";\n attributes: Attribute[];\n};\n\nexport type CompositeAstNode = AstNode & {\n type: \"lotto\" | \"parallel\" | \"selector\" | \"sequence\";\n attributes: Attribute[];\n children: AstNode[];\n};\n\nexport type DecoratorAstNode = AstNode & {\n type: \"fail\" | \"flip\" | \"repeat\" | \"retry\" | \"root\" | \"succeed\";\n attributes: Attribute[];\n children: AstNode[];\n};\n\nexport type BranchAstNode = AstNode & {\n type: \"branch\";\n branchName: \"\" | string;\n};\n\nexport type LottoAstNode = CompositeAstNode & {\n type: \"lotto\";\n tickets: number[];\n};\n\nexport type RootAstNode = DecoratorAstNode & {\n type: \"root\";\n name: null | string;\n};\n\nexport type RepeatAstNode = DecoratorAstNode & {\n type: \"repeat\";\n iterations: number | null;\n iterationsMin: number | null;\n iterationsMax: number | null;\n};\n\nexport type RetryAstNode = DecoratorAstNode & {\n type: \"retry\";\n attempts: number | null;\n attemptsMin: number | null;\n attemptsMax: number | null;\n};\n\nexport type ActionAstNode = LeafAstNode & {\n type: \"action\";\n actionName: string;\n actionArguments: AnyArgument[];\n};\n\nexport type ConditionAstNode = LeafAstNode & {\n type: \"condition\";\n conditionName: string;\n conditionArguments: AnyArgument[];\n};\n\nexport type WaitAstNode = LeafAstNode & {\n type: \"wait\";\n duration: number | null;\n durationMin: number | null;\n durationMax: number | null;\n};\n\nexport type AnyAstNode =\n | BranchAstNode\n | CompositeAstNode\n | LottoAstNode\n | DecoratorAstNode\n | RootAstNode\n | RepeatAstNode\n | RetryAstNode\n | LeafAstNode\n | ActionAstNode\n | ConditionAstNode\n | WaitAstNode;\n\n/**\n * The AST node factories.\n */\nconst ASTNodeFactories = {\n ROOT: (): RootAstNode => ({\n type: \"root\",\n attributes: [],\n name: null,\n children: [],\n validate(depth: number) {\n // A root node cannot be the child of another node.\n if (depth > 1) {\n throw new Error(\"a root node cannot be the child of another node\");\n }\n\n // A root node must have a single child node.\n if (this.children.length !== 1) {\n throw new Error(\"a root node must have a single child\");\n }\n },\n createNodeInstance(namedRootNodeProvider, visitedBranches) {\n return new Root(\n this.attributes,\n this.children![0].createNodeInstance(namedRootNodeProvider, visitedBranches.slice())\n );\n }\n }),\n BRANCH: (): BranchAstNode => ({\n type: \"branch\",\n branchName: \"\",\n validate() {},\n createNodeInstance(namedRootNodeProvider, visitedBranches) {\n // Try to find the root node with a matching branch name.\n const targetRootNode = namedRootNodeProvider(this.branchName);\n\n // If we have already visited this branch then we have a circular dependency.\n if (visitedBranches.indexOf(this.branchName) !== -1) {\n throw new Error(`circular dependency found in branch node references for branch '${this.branchName}'`);\n }\n\n // If we have a target root node, then the node instance we want will be the first and only child of the referenced root node.\n if (targetRootNode) {\n return targetRootNode\n .createNodeInstance(namedRootNodeProvider, visitedBranches.concat(this.branchName))\n .getChildren()[0];\n } else {\n throw new Error(`branch references root node '${this.branchName}' which has not been defined`);\n }\n }\n }),\n SELECTOR: (): CompositeAstNode => ({\n type: \"selector\",\n attributes: [],\n children: [],\n validate() {\n // A selector node must have at least a single node.\n if (this.children.length < 1) {\n throw new Error(\"a selector node must have at least a single child\");\n }\n },\n createNodeInstance(namedRootNodeProvider, visitedBranches) {\n return new Selector(\n this.attributes,\n this.children.map((child) => child.createNodeInstance(namedRootNodeProvider, visitedBranches.slice()))\n );\n }\n }),\n SEQUENCE: (): CompositeAstNode => ({\n type: \"sequence\",\n attributes: [],\n children: [],\n validate() {\n // A sequence node must have at least a single node.\n if (this.children.length < 1) {\n throw new Error(\"a sequence node must have at least a single child\");\n }\n },\n createNodeInstance(namedRootNodeProvider, visitedBranches) {\n return new Sequence(\n this.attributes,\n this.children.map((child) => child.createNodeInstance(namedRootNodeProvider, visitedBranches.slice()))\n );\n }\n }),\n PARALLEL: (): CompositeAstNode => ({\n type: \"parallel\",\n attributes: [],\n children: [],\n validate() {\n // A parallel node must have at least a single node.\n if (this.children.length < 1) {\n throw new Error(\"a parallel node must have at least a single child\");\n }\n },\n createNodeInstance(namedRootNodeProvider, visitedBranches) {\n return new Parallel(\n this.attributes,\n this.children.map((child) => child.createNodeInstance(namedRootNodeProvider, visitedBranches.slice()))\n );\n }\n }),\n LOTTO: (): LottoAstNode => ({\n type: \"lotto\",\n attributes: [],\n children: [],\n tickets: [],\n validate() {\n // A lotto node must have at least a single node.\n if (this.children!.length < 1) {\n throw new Error(\"a lotto node must have at least a single child\");\n }\n },\n createNodeInstance(namedRootNodeProvider, visitedBranches) {\n return new Lotto(\n this.attributes,\n this.tickets!,\n this.children!.map((child) => child.createNodeInstance(namedRootNodeProvider, visitedBranches.slice()))\n );\n }\n }),\n REPEAT: (): RepeatAstNode => ({\n type: \"repeat\",\n attributes: [],\n iterations: null,\n iterationsMin: null,\n iterationsMax: null,\n children: [],\n validate() {\n // A repeat node must have a single node.\n if (this.children!.length !== 1) {\n throw new Error(\"a repeat node must have a single child\");\n }\n\n if (this.iterations !== null) {\n // A repeat node must have a positive number of iterations if defined.\n if (this.iterations < 0) {\n throw new Error(\"a repeat node must have a positive number of iterations if defined\");\n }\n } else if (this.iterationsMin !== null && this.iterationsMax !== null) {\n // A repeat node must have a positive min and max iteration count if they are defined.\n if (this.iterationsMin < 0 || this.iterationsMax < 0) {\n throw new Error(\n \"a repeat node must have a positive minimum and maximum iteration count if defined\"\n );\n }\n\n // A repeat node must not have an minimum iteration count that exceeds the maximum iteration count.\n if (this.iterationsMin > this.iterationsMax) {\n throw new Error(\n \"a repeat node must not have a minimum iteration count that exceeds the maximum iteration count\"\n );\n }\n } else {\n // If we have no explicit iteration count or a minimum and maximum iteration count set then we are dealing with a repeat node that iterates indefinitely.\n }\n },\n createNodeInstance(namedRootNodeProvider, visitedBranches) {\n return new Repeat(\n this.attributes,\n this.iterations,\n this.iterationsMin,\n this.iterationsMax,\n this.children![0].createNodeInstance(namedRootNodeProvider, visitedBranches.slice())\n );\n }\n }),\n RETRY: (): RetryAstNode => ({\n type: \"retry\",\n attributes: [],\n attempts: null,\n attemptsMin: null,\n attemptsMax: null,\n children: [],\n validate() {\n // A retry node must have a single node.\n if (this.children!.length !== 1) {\n throw new Error(\"a retry node must have a single child\");\n }\n\n if (this.attempts !== null) {\n // A retry node must have a positive number of attempts if defined.\n if (this.attempts < 0) {\n throw new Error(\"a retry node must have a positive number of attempts if defined\");\n }\n } else if (this.attemptsMin !== null && this.attemptsMax !== null) {\n // A retry node must have a positive min and max attempts count if they are defined.\n if (this.attemptsMin < 0 || this.attemptsMax < 0) {\n throw new Error(\"a retry node must have a positive minimum and maximum attempt count if defined\");\n }\n\n // A retry node must not have a minimum attempt count that exceeds the maximum attempt count.\n if (this.attemptsMin > this.attemptsMax) {\n throw new Error(\n \"a retry node must not have a minimum attempt count that exceeds the maximum attempt count\"\n );\n }\n } else {\n // If we have no explicit attempt count or a minimum and maximum attempt count set then we are dealing with a retry node that attempts indefinitely.\n }\n },\n createNodeInstance(namedRootNodeProvider, visitedBranches) {\n return new Retry(\n this.attributes,\n this.attempts,\n this.attemptsMin,\n this.attemptsMax,\n this.children![0].createNodeInstance(namedRootNodeProvider, visitedBranches.slice())\n );\n }\n }),\n FLIP: (): DecoratorAstNode => ({\n type: \"flip\",\n attributes: [],\n children: [],\n validate() {\n // A flip node must have a single node.\n if (this.children!.length !== 1) {\n throw new Error(\"a flip node must have a single child\");\n }\n },\n createNodeInstance(namedRootNodeProvider, visitedBranches) {\n return new Flip(\n this.attributes,\n this.children![0].createNodeInstance(namedRootNodeProvider, visitedBranches.slice())\n );\n }\n }),\n SUCCEED: (): DecoratorAstNode => ({\n type: \"succeed\",\n attributes: [],\n children: [],\n validate() {\n // A succeed node must have a single node.\n if (this.children!.length !== 1) {\n throw new Error(\"a succeed node must have a single child\");\n }\n },\n createNodeInstance(namedRootNodeProvider, visitedBranches) {\n return new Succeed(\n this.attributes,\n this.children![0].createNodeInstance(namedRootNodeProvider, visitedBranches.slice())\n );\n }\n }),\n FAIL: (): DecoratorAstNode => ({\n type: \"fail\",\n attributes: [],\n children: [],\n validate() {\n // A fail node must have a single node.\n if (this.children!.length !== 1) {\n throw new Error(\"a fail node must have a single child\");\n }\n },\n createNodeInstance(namedRootNodeProvider, visitedBranches) {\n return new Fail(\n this.attributes,\n this.children![0].createNodeInstance(namedRootNodeProvider, visitedBranches.slice())\n );\n }\n }),\n WAIT: (): WaitAstNode => ({\n type: \"wait\",\n attributes: [],\n duration: null,\n durationMin: null,\n durationMax: null,\n validate() {\n if (this.duration !== null) {\n // If an explict duration was defined then it must be a positive number.\n if (this.duration < 0) {\n throw new Error(\"a wait node must have a positive duration\");\n }\n } else if (this.durationMin !== null && this.durationMax !== null) {\n // A wait node must have a positive min and max duration.\n if (this.durationMin < 0 || this.durationMax < 0) {\n throw new Error(\"a wait node must have a positive minimum and maximum duration\");\n }\n\n // A wait node must not have a minimum duration that exceeds the maximum duration.\n if (this.durationMin > this.durationMax) {\n throw new Error(\"a wait node must not have a minimum duration that exceeds the maximum duration\");\n }\n } else {\n // If we have no explicit duration or duration bounds set then we are dealing with a wait node that waits indefinitely.\n }\n },\n createNodeInstance() {\n return new Wait(this.attributes, this.duration, this.durationMin, this.durationMax);\n }\n }),\n ACTION: (): ActionAstNode => ({\n type: \"action\",\n attributes: [],\n actionName: \"\",\n actionArguments: [],\n validate() {},\n createNodeInstance() {\n return new Action(this.attributes, this.actionName!, this.actionArguments!);\n }\n }),\n CONDITION: (): ConditionAstNode => ({\n type: \"condition\",\n attributes: [],\n conditionName: \"\",\n conditionArguments: [],\n validate() {},\n createNodeInstance() {\n return new Condition(this.attributes, this.conditionName!, this.conditionArguments!);\n }\n })\n};\n\ntype OtherAstNodes = AstNode[];\n\n/**\n * Create an array of root AST nodes based on the given definition.\n * @param definition The definition to parse the AST nodes from.\n * @returns The base definition AST nodes.\n */\nexport default function buildRootASTNodes(definition: string): RootAstNode[] {\n // Swap out any node/attribute argument string literals with a placeholder and get a mapping of placeholders to original values as well as the processed definition.\n const { placeholders, processedDefinition } = substituteStringLiterals(definition);\n\n // Convert the processed definition (with substituted string literals) into an array of raw tokens.\n const tokens = parseTokensFromDefinition(processedDefinition);\n\n // There must be at least 3 tokens for the tree definition to be valid. 'ROOT', '{' and '}'.\n if (tokens.length < 3) {\n throw new Error(\"invalid token count\");\n }\n\n // We should have a matching number of '{' and '}' tokens. If not, then there are scopes that have not been properly closed.\n if (tokens.filter((token) => token === \"{\").length !== tokens.filter((token) => token === \"}\").length) {\n throw new Error(\"scope character mismatch\");\n }\n\n // Create a stack of node children arrays, starting with a definition scope.\n const stack: [RootAstNode[], ...OtherAstNodes[]] = [[]];\n const rootScope = stack[0];\n\n // We should keep processing the raw tokens until we run out of them.\n while (tokens.length) {\n // Grab the next token.\n const token = tokens.shift();\n\n const currentScope = stack[stack.length - 1] as OtherAstNodes;\n\n // How we create the next AST token depends on the current raw token value.\n switch (token!.toUpperCase()) {\n case \"ROOT\": {\n // Create a ROOT AST node.\n const node = ASTNodeFactories.ROOT();\n\n // Push the ROOT node into the current scope.\n rootScope.push(node);\n\n // We may have a root node name defined as an argument.\n if (tokens[0] === \"[\") {\n const rootArguments = getArguments(tokens, placeholders);\n\n // We should have only a single argument that is not an empty string for a root node, which is the root name identifier.\n if (rootArguments.length === 1 && rootArguments[0].type === \"identifier\") {\n // The root name will be the first and only node argument.\n node.name = rootArguments[0].value as string;\n } else {\n throw new Error(\"expected single root name argument\");\n }\n }\n\n // Try to pick any attributes off of the token stack.\n node.attributes = getAttributes(tokens, placeholders);\n\n popAndCheck(tokens, \"{\");\n\n // The new scope is that of the new ROOT nodes children.\n stack.push(node.children!);\n break;\n }\n\n case \"BRANCH\": {\n // Create a BRANCH AST node.\n const node = ASTNodeFactories.BRANCH();\n\n // Push the BRANCH node into the current scope.\n currentScope.push(node);\n\n // We must have arguments defined, as we require a branch name argument.\n if (tokens[0] !== \"[\") {\n throw new Error(\"expected single branch name argument\");\n }\n\n // The branch name will be defined as a node argument.\n const branchArguments = getArguments(tokens, placeholders);\n\n // We should have only a single identifer argument for a branch node, which is the branch name.\n if (branchArguments.length === 1 && branchArguments[0].type === \"identifier\") {\n // The branch name will be the first and only node argument.\n node.branchName = branchArguments[0].value as string;\n } else {\n throw new Error(\"expected single branch name argument\");\n }\n break;\n }\n\n case \"SELECTOR\": {\n // Create a SELECTOR AST node.\n const node = ASTNodeFactories.SELECTOR();\n\n // Push the SELECTOR node into the current scope.\n currentScope.push(node);\n\n // Try to pick any attributes off of the token stack.\n node.attributes = getAttributes(tokens, placeholders);\n\n popAndCheck(tokens, \"{\");\n\n // The new scope is that of the new SELECTOR nodes children.\n stack.push(node.children!);\n break;\n }\n\n case \"SEQUENCE\": {\n // Create a SEQUENCE AST node.\n const node = ASTNodeFactories.SEQUENCE();\n\n // Push the SEQUENCE node into the current scope.\n currentScope.push(node);\n\n // Try to pick any attributes off of the token stack.\n node.attributes = getAttributes(tokens, placeholders);\n\n popAndCheck(tokens, \"{\");\n\n // The new scope is that of the new SEQUENCE nodes children.\n stack.push(node.children!);\n break;\n }\n\n case \"PARALLEL\": {\n // Create a PARALLEL AST node.\n const node = ASTNodeFactories.PARALLEL();\n\n // Push the PARALLEL node into the current scope.\n currentScope.push(node);\n\n // Try to pick any attributes off of the token stack.\n node.attributes = getAttributes(tokens, placeholders);\n\n popAndCheck(tokens, \"{\");\n\n // The new scope is that of the new PARALLEL nodes children.\n stack.push(node.children!);\n break;\n }\n\n case \"LOTTO\": {\n // Create a LOTTO AST node.\n const node = ASTNodeFactories.LOTTO();\n\n // Push the LOTTO node into the current scope.\n currentScope.push(node);\n\n // If the next token is a '[' character then some ticket counts have been defined as arguments.\n if (tokens[0] === \"[\") {\n // Get the ticket count arguments, each argument must be a number.\n node.tickets = getArguments(\n tokens,\n placeholders,\n (arg) => arg.type === \"number\" && !!arg.isInteger,\n \"lotto node ticket counts must be integer values\"\n ).map((argument) => argument.value as number);\n }\n\n // Try to pick any attributes off of the token stack.\n node.attributes = getAttributes(tokens, placeholders);\n\n popAndCheck(tokens, \"{\");\n\n // The new scope is that of the new LOTTO nodes children.\n stack.push(node.children!);\n break;\n }\n\n case \"CONDITION\": {\n // Create a CONDITION AST node.\n const node = ASTNodeFactories.CONDITION();\n\n // Push the CONDITION node into the current scope.\n currentScope.push(node);\n\n // We must have arguments defined, as we require a condition function name argument.\n if (tokens[0] !== \"[\") {\n throw new Error(\"expected condition name identifier argument\");\n }\n\n // Grab the condition node arguments.\n const conditionArguments = getArguments(tokens, placeholders);\n\n // We should have at least a single identifier argument for a condition node, which is the condition function name.\n if (conditionArguments.length && conditionArguments[0].type === \"identifier\") {\n // The condition function name will be the first node argument.\n node.conditionName = conditionArguments.shift()!.value as string;\n } else {\n throw new Error(\"expected condition name identifier argument\");\n }\n\n // Only the first argument should have been an identifier, all following arguments must be string, number, boolean or null.\n conditionArguments\n .filter((arg) => arg.type === \"identifier\")\n .forEach((arg) => {\n throw new Error(\n \"invalid condition node argument value '\" +\n arg.value +\n \"', must be string, number, boolean or null\"\n );\n });\n\n // Any node arguments that follow the condition name identifier will be treated as condition function arguments.\n node.conditionArguments = conditionArguments;\n\n // Try to pick any attributes off of the token stack.\n node.attributes = getAttributes(tokens, placeholders);\n break;\n }\n\n case \"FLIP\": {\n // Create a FLIP AST node.\n const node = ASTNodeFactories.FLIP();\n\n // Push the Flip node into the current scope.\n currentScope.push(node);\n\n // Try to pick any attributes off of the token stack.\n node.attributes = getAttributes(tokens, placeholders);\n\n popAndCheck(tokens, \"{\");\n\n // The new scope is that of the new FLIP nodes children.\n stack.push(node.children!);\n break;\n }\n\n case \"SUCCEED\": {\n // Create a SUCCEED AST node.\n const node = ASTNodeFactories.SUCCEED();\n\n // Push the Succeed node into the current scope.\n currentScope.push(node);\n\n // Try to pick any attributes off of the token stack.\n node.attributes = getAttributes(tokens, placeholders);\n\n popAndCheck(tokens, \"{\");\n\n // The new scope is that of the new Succeed nodes children.\n stack.push(node.children!);\n break;\n }\n\n case \"FAIL\": {\n // Create a FAIL AST node.\n const node = ASTNodeFactories.FAIL();\n\n // Push the Fail node into the current scope.\n currentScope.push(node);\n\n // Try to pick any attributes off of the token stack.\n node.attributes = getAttributes(tokens, placeholders);\n\n popAndCheck(tokens, \"{\");\n\n // The new scope is that of the new Fail nodes children.\n stack.push(node.children!);\n break;\n }\n\n case \"WAIT\": {\n // Create a WAIT AST node.\n const node = ASTNodeFactories.WAIT();\n\n // Push the WAIT node into the current scope.\n currentScope.push(node);\n\n // The arguments of a wait node are optional. We may have:\n // - No node arguments, in which case the wait will be indefinite until it is aborted.\n // - One node argument which will be the explicit duration of the wait.\n // - Two node arguments which define the min and max duration bounds from which a random duration will be picked.\n if (tokens[0] === \"[\") {\n // Get the optional duration and longest duration of the wait.\n const nodeArguments = getArguments(\n tokens,\n placeholders,\n (arg) => arg.type === \"number\" && !!arg.isInteger,\n \"wait node durations must be integer values\"\n ).map((argument) => argument.value);\n\n // We may have:\n // - One node argument which will be the explicit duration of the wait.\n // - Two node arguments which define the min and max duration bounds from which a random duration will be picked.\n // - Too many arguments, which is not valid.\n if (nodeArguments.length === 1) {\n // An explicit duration was defined.\n node.duration = nodeArguments[0] as number;\n } else if (nodeArguments.length === 2) {\n // Min and max duration bounds were defined from which a random duration will be picked.\n node.durationMin = nodeArguments[0] as number;\n node.durationMax = nodeArguments[1] as number;\n } else if (nodeArguments.length > 2) {\n // An incorrect number of durations was defined.\n throw new Error(\"invalid number of wait node duration arguments defined\");\n }\n }\n\n // Try to pick any attributes off of the token stack.\n node.attributes = getAttributes(tokens, placeholders);\n break;\n }\n\n case \"REPEAT\": {\n // Create a REPEAT AST node.\n const node = ASTNodeFactories.REPEAT();\n\n // Push the REPEAT node into the current scope.\n currentScope.push(node);\n\n // The arguments of a repeat node are optional. We may have:\n // - No node arguments, in which case the repeat note will iterate indefinitely.\n // - One node argument which will be the explicit number of iterations to make.\n // - Two node arguments which define the min and max iteration bounds from which a random iteration count will be picked.\n if (tokens[0] === \"[\") {\n // An iteration count has been defined. Get the iteration and potential maximum iteration of the wait.\n const nodeArguments = getArguments(\n tokens,\n placeholders,\n (arg) => arg.type === \"number\" && !!arg.isInteger,\n \"repeat node iteration counts must be integer values\"\n ).map((argument) => argument.value);\n\n // We should have got one or two iteration counts.\n if (nodeArguments.length === 1) {\n // A static iteration count was defined.\n node.iterations = nodeArguments[0] as number;\n } else if (nodeArguments.length === 2) {\n // A minimum and maximum iteration count was defined.\n node.iterationsMin = nodeArguments[0] as number;\n node.iterationsMax = nodeArguments[1] as number;\n } else {\n // An incorrect number of iteration counts was defined.\n throw new Error(\"invalid number of repeat node iteration count arguments defined\");\n }\n }\n\n // Try to pick any attributes off of the token stack.\n node.attributes = getAttributes(tokens, placeholders);\n\n popAndCheck(tokens, \"{\");\n\n // The new scope is that of the new REPEAT nodes children.\n stack.push(node.children!);\n break;\n }\n\n case \"RETRY\": {\n // Create a RETRY AST node.\n const node = ASTNodeFactories.RETRY();\n\n // Push the RETRY node into the current scope.\n currentScope.push(node);\n\n // The arguments of a retry node are optional. We may have:\n // - No node arguments, in which case the retry note will attempt indefinitely.\n // - One node argument which will be the explicit number of attempts to make.\n // - Two node arguments which define the min and max attempt bounds from which a random attempt count will be picked.\n if (tokens[0] === \"[\") {\n // An attempt count has been defined. Get the attempt count and potential maximum attempt count of the wait.\n const nodeArguments = getArguments(\n tokens,\n placeholders,\n (arg) => arg.type === \"number\" && !!arg.isInteger,\n \"retry node attempt counts must be integer values\"\n ).map((argument) => argument.value);\n\n // We should have got one or two attempt counts.\n if (nodeArguments.length === 1) {\n // A static attempt count was defined.\n node.attempts = nodeArguments[0] as number;\n } else if (nodeArguments.length === 2) {\n // A minimum and maximum attempt count was defined.\n node.attemptsMin = nodeArguments[0] as number;\n node.attemptsMax = nodeArguments[1] as number;\n } else {\n // An incorrect number of attempt counts was defined.\n throw new Error(\"invalid number of retry node attempt count arguments defined\");\n }\n }\n\n // Try to pick any attributes off of the token stack.\n node.attributes = getAttributes(tokens, placeholders);\n\n popAndCheck(tokens, \"{\");\n\n // The new scope is that of the new RETRY nodes children.\n stack.push(node.children!);\n break;\n }\n\n case \"ACTION\": {\n // Create a ACTION AST node.\n const node = ASTNodeFactories.ACTION();\n\n // Push the ACTION node into the current scope.\n currentScope.push(node);\n\n // We must have arguments defined, as we require an action name argument.\n if (tokens[0] !== \"[\") {\n throw new Error(\"expected action name identifier argument\");\n }\n\n // The action name will be defined as a node argument.\n const actionArguments = getArguments(tokens, placeholders);\n\n // We should have at least one identifer argument for an action node, which is the action name.\n if (actionArguments.length && actionArguments[0].type === \"identifier\") {\n // The action name will be the first and only node argument.\n node.actionName = actionArguments.shift()!.value as string;\n } else {\n throw new Error(\"expected action name identifier argument\");\n }\n\n // Only the first argument should have been an identifier, all following arguments must be string, number, boolean or null.\n actionArguments\n .filter((arg) => arg.type === \"identifier\")\n .forEach((arg) => {\n throw new Error(\n \"invalid action node argument value '\" +\n arg.value +\n \"', must be string, number, boolean or null\"\n );\n });\n\n // Any node arguments that follow the action name identifier will be treated as action function arguments.\n node.actionArguments = actionArguments;\n\n // Try to pick any attributes off of the token stack.\n node.attributes = getAttributes(tokens, placeholders);\n break;\n }\n\n case \"}\": {\n // The '}' character closes the current scope.\n stack.pop();\n break;\n }\n\n default: {\n throw new Error(`unexpected token '${token}'`);\n }\n }\n }\n\n // A function to recursively validate each of the nodes in the AST.\n const validateASTNode = (node: Validatable, depth: number): void => {\n // Validate the node.\n node.validate(depth);\n\n // Validate each child of the node.\n (node.children || []).forEach((child) => validateASTNode(child, depth + 1));\n };\n\n // Start node validation from the definition root.\n validateASTNode(\n {\n children: stack[0] as RootAstNode[],\n validate(this: { children: RootAstNode[] }) {\n // We must have at least one node defined as the definition scope, which should be a root node.\n if (this.children.length === 0) {\n throw new Error(\"expected root node to have been defined\");\n }\n\n // Each node at the base of the definition scope MUST be a root node.\n for (const definitionLevelNode of this.children) {\n if (definitionLevelNode.type !== \"root\") {\n throw new Error(\"expected root node at base of definition\");\n }\n }\n\n // Exactly one root node must not have a name defined. This will be the main root, others will have to be referenced via branch nodes.\n if (this.children.filter((definitionLevelNode) => definitionLevelNode.name === null).length !== 1) {\n throw new Error(\"expected single unnamed root node at base of definition to act as main root\");\n }\n\n // No two named root nodes can have matching names.\n const rootNodeNames: string[] = [];\n for (const definitionLevelNode of this.children) {\n if (rootNodeNames.indexOf(definitionLevelNode.name!) !== -1) {\n throw new Error(`multiple root nodes found with duplicate name '${definitionLevelNode.name}'`);\n } else {\n rootNodeNames.push(definitionLevelNode.name!);\n }\n }\n }\n },\n 0\n );\n\n // Return the root AST nodes.\n return stack[0];\n}\n\n/**\n * Pop the next raw token off of the stack and throw an error if it wasn't the expected one.\n * @param tokens The array of remaining tokens.\n * @param expected An optional string or array or items, one of which must match the next popped token.\n * @returns The popped token.\n */\nfunction popAndCheck(tokens: string[], expected: string | string[]) {\n // Get and remove the next token.\n const popped = tokens.shift();\n\n // We were expecting another token.\n if (popped === undefined) {\n throw new Error(\"unexpected end of definition\");\n }\n\n // Do we have an expected token/tokens array?\n if (expected !== undefined) {\n // Check whether the popped token matches at least one of our expected items.\n var tokenMatchesExpectation = ([] as string[])\n .concat(expected)\n .some((item) => popped.toUpperCase() === item.toUpperCase());\n\n // Throw an error if the popped token didn't match any of our expected items.\n if (!tokenMatchesExpectation) {\n const expectationString = ([] as string[])\n .concat(expected)\n .map((item) => \"'\" + item + \"'\")\n .join(\" or \");\n\n throw new Error(`unexpected token found. Expected '${expectationString}' but got '${popped}'`);\n }\n }\n\n // Return the popped token.\n return popped;\n}\n\ntype StringPlaceholders = { [key: string]: string };\n\n/**\n * Pull an argument definition list off of the token stack.\n * @param tokens The array of remaining tokens.\n * @param stringArgumentPlaceholders The mapping of string literal node argument placeholders to original values.\n * @param argumentValidator The argument validator function.\n * @param validationFailedMessage The exception message to throw if argument validation fails.\n * @returns The argument definition list.\n */\nfunction getArguments(\n tokens: string[],\n stringArgumentPlaceholders: StringPlaceholders,\n argumentValidator?: (arg: AnyArgument) => boolean,\n validationFailedMessage?: string\n) {\n // Any lists of arguments will always be wrapped in '[]' for node arguments or '()' for attribute arguments.\n // We are looking for a '[' or '(' opener that wraps the argument tokens and the relevant closer.\n const closer = popAndCheck(tokens, [\"[\", \"(\"]) === \"[\" ? \"]\" : \")\";\n\n const argumentListTokens: string[] = [];\n const argumentList: AnyArgument[] = [];\n\n // Grab all tokens between the '[' and ']' or '(' and ')'.\n while (tokens.length && tokens[0] !== closer) {\n // The next token is part of our arguments list.\n argumentListTokens.push(tokens.shift()!);\n }\n\n // Validate the order of the argument tokens. Each token must either be a ',' or a single argument that satisfies the validator.\n argumentListTokens.forEach((token, index) => {\n // Get whether this token should be an actual argument.\n const shouldBeArgumentToken = !(index & 1);\n\n // If the current token should be an actual argument then validate it,otherwise it should be a ',' token.\n if (shouldBeArgumentToken) {\n // Get the argument definition.\n const argumentDefinition = getArgumentDefinition(token!, stringArgumentPlaceholders);\n\n // Try to validate the argument.\n if (argumentValidator && !argumentValidator(argumentDefinition)) {\n throw new Error(validationFailedMessage);\n }\n\n // This is a valid argument!\n argumentList.push(argumentDefinition);\n } else {\n // The current token should be a ',' token.\n if (token !== \",\") {\n throw new Error(`invalid argument list, expected ',' or ']' but got '${token}'`);\n }\n }\n });\n\n // The arguments list should terminate with a ']' or ')' token, depending on the opener.\n popAndCheck(tokens, closer);\n\n // Return the argument list.\n return argumentList;\n}\n\n/**\n * Gets an argument value definition.\n * @param token The argument token.\n * @param stringArgumentPlaceholders The mapping of string literal node argument placeholders to original values.\n * @returns An argument value definition.\n */\nfunction getArgumentDefinition(token: string, stringArgumentPlaceholders: StringPlaceholders): AnyArgument {\n // Check whether the token represents a null value.\n if (token === \"null\") {\n return {\n value: null,\n type: \"null\"\n } as NullArgument;\n }\n\n // Check whether the token represents a boolean value.\n if (token === \"true\" || token === \"false\") {\n return {\n value: token === \"true\",\n type: \"boolean\"\n } as BooleanArgument;\n }\n\n // Check whether the token represents a number value.\n // TODO: Relies on broken isNaN - see MDN.\n // if (!Number.isNaN(token)) {\n if (!isNaN(token as any)) {\n return {\n value: parseFloat(token),\n isInteger: parseFloat(token) === parseInt(token, 10),\n type: \"number\"\n } as NumberArgument;\n }\n\n // Check whether the token is a placeholder (e.g. @@0@@) representing a string literal.\n if (token.match(/^@@\\d+@@$/g)) {\n return {\n value: stringArgumentPlaceholders[token].replace('\\\\\"', '\"'),\n type: \"string\"\n } as StringPlaceholderArgument;\n }\n\n // The only remaining option is that the argument value is an identifier.\n return {\n value: token,\n type: \"identifier\"\n } as IdentifierArgument;\n}\n\n/**\n * Pull any attributes off of the token stack.\n * @param tokens The array of remaining tokens.\n * @param stringArgumentPlaceholders The mapping of string literal node argument placeholders to original values.\n * @returns An array of attributes defined by any directly following tokens.\n */\nfunction getAttributes(tokens: string[], stringArgumentPlaceholders: StringPlaceholders) {\n // Create an array to hold any attributes found.\n const attributes: Attribute[] = [];\n\n // Keep track of names of attribute that we have found on the token stack, as we cannot have duplicates.\n const attributesFound: string[] = [];\n\n // Try to get the attribute factory for the next token.\n let attributeFactory = AttributeFactories[(tokens[0] || \"\").toUpperCase()];\n\n // Pull attribute tokens off of the tokens stack until we have no more.\n while (attributeFactory) {\n // Check to make sure that we have not already created a attribute of this type for this node.\n if (attributesFound.indexOf(tokens[0].toUpperCase()) !== -1) {\n throw new Error(`duplicate attribute '${tokens[0].toUpperCase()}' found for node`);\n }\n\n // Add the current attribute type to our array of found attributes.\n attributesFound.push(tokens.shift()!.toUpperCase());\n\n // Grab any attribute arguments.\n const attributeArguments = getArguments(tokens, stringArgumentPlaceholders);\n\n // The first attribute argument has to be an identifer, this will reference an agent function.\n if (attributeArguments.length === 0 || attributeArguments[0].type !== \"identifier\") {\n throw new Error(\"expected agent function name identifier argument for attribute\");\n }\n\n // Grab the first attribute which is an identifier that will reference an agent function.\n const attributeFunctionName = attributeArguments.shift()! as IdentifierArgument;\n\n // Any remaining attribute arguments must have a type of string, number, boolean or null.\n attributeArguments\n .filter((arg) => arg.type === \"identifier\")\n .forEach((arg) => {\n throw new Error(\n \"invalid attribute argument value '\" + arg.value + \"', must be string, number, boolean or null\"\n );\n });\n\n // Create the attribute and add it to the array of attributes found.\n attributes.push(attributeFactory(attributeFunctionName.value, attributeArguments));\n\n // Try to get the next attribute name token, as there could be multiple.\n attributeFactory = AttributeFactories[(tokens[0] || \"\").toUpperCase()];\n }\n\n return attributes;\n}\n\n/**\n * Swaps out any node/attribute argument string literals with placeholders.\n * @param definition The definition.\n * @returns An object containing a mapping of placeholders to original string values as well as the processed definition string.\n */\nfunction substituteStringLiterals(definition: string): {\n placeholders: { [key: string]: string };\n processedDefinition: string;\n} {\n // Create an object to hold the mapping of placeholders to original string values.\n const placeholders: StringPlaceholders = {};\n\n // Replace any string literals wrapped with double quotes in our definition with placeholders to be processed later.\n const processedDefinition = definition.replace(/\\\"(\\\\.|[^\"\\\\])*\\\"/g, (match) => {\n var strippedMatch = match.substring(1, match.length - 1);\n var placeholder = Object.keys(placeholders).find((key) => placeholders[key] === strippedMatch);\n\n // If we have no existing string literal match then create a new placeholder.\n if (!placeholder) {\n placeholder = `@@${Object.keys(placeholders).length}@@`;\n placeholders[placeholder] = strippedMatch;\n }\n\n return placeholder;\n });\n\n return { placeholders, processedDefinition };\n}\n\n/**\n * Parse the tree definition into an array of raw tokens.\n * @param definition The definition.\n * @returns An array of tokens parsed from the definition.\n */\nfunction parseTokensFromDefinition(definition: string): string[] {\n // Add some space around various important characters so that they can be plucked out easier as individual tokens.\n definition = definition.replace(/\\(/g, \" ( \");\n definition = definition.replace(/\\)/g, \" ) \");\n definition = definition.replace(/\\{/g, \" { \");\n definition = definition.replace(/\\}/g, \" } \");\n definition = definition.replace(/\\]/g, \" ] \");\n definition = definition.replace(/\\[/g, \" [ \");\n definition = definition.replace(/\\,/g, \" , \");\n\n // Split the definition into raw token form and return it.\n return definition.replace(/\\s+/g, \" \").trim().split(\" \");\n}\n", "import GuardPath, { GuardPathPart } from \"./attributes/guards/GuardPath\";\nimport buildRootASTNodes, { AnyArgument, RootAstNode } from \"./RootAstNodesBuilder\";\nimport State, { AnyState } from \"./State\";\nimport Lookup from \"./Lookup\";\nimport Node from \"./nodes/Node\";\nimport Root from \"./nodes/decorator/Root\";\nimport Composite from \"./nodes/composite/Composite\";\nimport Decorator from \"./nodes/decorator/Decorator\";\nimport { Agent, GlobalFunction } from \"./Agent\";\nimport { CallbackAttributeDetails } from \"./attributes/callbacks/Callback\";\nimport { GuardAttributeDetails } from \"./attributes/guards/Guard\";\nimport { BehaviourTreeOptions } from \"./BehaviourTreeOptions\";\nimport { parseMDSLToJSON } from \"./mdsl/MDSLDefinitionParser\";\n\n// Purely for outside inspection of the tree.\nexport type FlattenedTreeNode = {\n id: string;\n type: string;\n caption: string;\n state: AnyState;\n guards: GuardAttributeDetails[];\n callbacks: CallbackAttributeDetails[];\n args: AnyArgument[];\n parentId: string | null;\n};\n\n/**\n * A representation of a behaviour tree.\n */\nexport class BehaviourTree {\n /**\n * The main root tree node.\n */\n public readonly rootNode: Root;\n\n /**\n * Creates a new instance of the BehaviourTree class.\n * @param definition The behaviour tree definition.\n * @param agent The agent instance that this behaviour tree is modelling behaviour for.\n * @param options The behaviour tree options object.\n */\n constructor(definition: string, private agent: Agent, private options: BehaviourTreeOptions = {}) {\n // The tree definition must be defined and a valid string.\n if (typeof definition !== \"string\") {\n throw new Error(\"the tree definition must be a string\");\n }\n\n // The agent must be defined and not null.\n if (typeof agent !== \"object\" || agent === null) {\n throw new Error(\"the agent must be defined and not null\");\n }\n\n // Parse the behaviour tree definition, create the populated tree of behaviour tree nodes, and get the root.\n this.rootNode = BehaviourTree._createRootNode(definition);\n }\n\n /**\n * Gets whether the tree is in the RUNNING state.\n * @returns true if the tree is in the RUNNING state, otherwise false.\n */\n isRunning() {\n return this.rootNode.getState() === State.RUNNING;\n }\n\n /**\n * Gets the current tree state of SUCCEEDED, FAILED, READY or RUNNING.\n * @returns The current tree state.\n */\n getState() {\n return this.rootNode.getState();\n }\n\n /**\n * Step the tree.\n * 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.\n * 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\n * 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.\n *\n * 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.\n */\n step() {\n // If the root node has already been stepped to completion then we need to reset it.\n if (this.rootNode.getState() === State.SUCCEEDED || this.rootNode.getState() === State.FAILED) {\n this.rootNode.reset();\n }\n\n try {\n this.rootNode.update(this.agent, this.options);\n } catch (exception) {\n throw new Error(`error stepping tree: ${(exception as Error).message}`);\n }\n }\n\n /**\n * Resets the tree from the root node outwards to each nested node, giving each a state of READY.\n */\n reset() {\n this.rootNode.reset();\n }\n\n /**\n * Gets the flattened details of every node in the tree.\n * @returns The flattened details of every node in the tree.\n */\n getFlattenedNodeDetails(): FlattenedTreeNode[] {\n // Create an empty flattened array of tree nodes.\n const flattenedTreeNodes: FlattenedTreeNode[] = [];\n\n /**\n * Helper function to process a node instance and push details into the flattened tree nodes array.\n * @param node The current node.\n * @param parentUid The UID of the node parent, or null if the node is the main root node.\n */\n const processNode = (node: Node, parentUid: string | null) => {\n // Get the guard and callback attribute details for this node.\n const guards = node\n .getAttributes()\n .filter((attribute) => attribute.isGuard())\n .map((attribute) => attribute.getDetails()) as GuardAttributeDetails[];\n const callbacks = node\n .getAttributes()\n .filter((attribute) => !attribute.isGuard())\n .map((attribute) => attribute.getDetails()) as CallbackAttributeDetails[];\n\n // Push the current node into the flattened nodes array.\n flattenedTreeNodes.push({\n id: node.getUid(),\n type: node.getType(),\n caption: node.getName(),\n state: node.getState(),\n guards,\n callbacks,\n args: node.getArguments(),\n parentId: parentUid\n });\n\n // Process each of the nodes children if it is not a leaf node.\n if (!node.isLeafNode()) {\n (node as Composite | Decorator)\n .getChildren()\n .forEach((child) => processNode(child, (node as Composite | Decorator).getUid()));\n }\n };\n\n // Convert the nested node structure into a flattened array of node details.\n processNode(this.rootNode, null);\n\n return flattenedTreeNodes;\n }\n\n /**\n * Registers the action/condition/guard/callback function or subtree with the given name.\n * @param name The name of the function or subtree to register.\n * @param value The function or subtree definition to register.\n */\n static register(name: string, value: GlobalFunction | string) {\n if (typeof value === \"function\") {\n // We are going to register a action/condition/guard/callback function.\n Lookup.setFunc(name, value);\n } else if (typeof value === \"string\") {\n // We are going to register a subtree.\n let rootASTNodes: RootAstNode[];\n\n try {\n // Try to create the behaviour tree AST based on the definition provided, this could fail if the definition is invalid.\n rootASTNodes = buildRootASTNodes(value);\n } catch (exception) {\n // There was an issue in trying to parse and build the tree definition.\n throw new Error(`error registering definition: ${(exception as Error).message}`);\n }\n\n // This function should only ever be called with a definition containing a single unnamed root node.\n if (rootASTNodes.length != 1 || rootASTNodes[0].name !== null) {\n throw new Error(\"error registering definition: expected a single unnamed root node\");\n }\n\n Lookup.setSubtree(name, rootASTNodes[0]);\n } else {\n throw new Error(\"unexpected value, expected string definition or function\");\n }\n }\n\n /**\n * Unregisters the registered action/condition/guard/callback function or subtree with the given name.\n * @param name The name of the registered action/condition/guard/callback function or subtree to unregister.\n */\n static unregister(name: string): void {\n Lookup.remove(name);\n }\n\n /**\n * Unregister all registered action/condition/guard/callback functions and subtrees.\n */\n static unregisterAll(): void {\n Lookup.empty();\n }\n\n /**\n * Parses a behaviour tree definition and creates a tree of behaviour tree nodes.\n * @param {string} definition The behaviour tree definition.\n * @returns The root behaviour tree node.\n */\n private static _createRootNode(definition: string): Root {\n // TODO Remove!\n try {\n // parseToJSON(definition);\n } catch (exception) {\n console.log(exception);\n }\n\n try {\n // Try to create the behaviour tree AST based on the definition provided, this could fail if the definition is invalid.\n const rootASTNodes = buildRootASTNodes(definition);\n\n // Create a symbol to use as the main root key in our root node mapping.\n const mainRootNodeKey = Symbol(\"__root__\");\n\n // Create a mapping of root node names to root AST tokens. The main root node will have a key of Symbol(\"__root__\").\n const rootNodeMap: { [key: string | symbol]: RootAstNode } = {};\n for (const rootASTNode of rootASTNodes) {\n rootNodeMap[rootASTNode.name === null ? mainRootNodeKey : rootASTNode.name!] = rootASTNode;\n }\n\n // Convert the AST to our actual tree and get the root node.\n const rootNode: Root = rootNodeMap[mainRootNodeKey].createNodeInstance(\n // Create a provider for named root nodes that are part of our definition or have been registered. Prioritising the former.\n (name: string): RootAstNode => (rootNodeMap[name] ? rootNodeMap[name] : Lookup.getSubtree(name)),\n []\n );\n\n // Set a guard path on every leaf of the tree to evaluate as part of its update.\n BehaviourTree._applyLeafNodeGuardPaths(rootNode);\n\n // Return the root node.\n return rootNode;\n } catch (exception) {\n // There was an issue in trying to parse and build the tree definition.\n throw new Error(`error parsing tree: ${(exception as Error).message}`);\n }\n }\n\n /**\n * Applies a guard path to every leaf of the tree to evaluate as part of each update.\n * @param rootNode The main root tree node.\n */\n private static _applyLeafNodeGuardPaths(rootNode: Root) {\n const nodePaths: Node[][] = [];\n\n const findLeafNodes = (path: Node[], node: Node) => {\n // Add the current node to the path.\n path = path.concat(node);\n\n // Check whether the current node is a leaf node.\n if (node.isLeafNode()) {\n nodePaths.push(path);\n } else {\n (node as Composite | Decorator).getChildren().forEach((child) => findLeafNodes(path, child));\n }\n };\n\n // Find all leaf node paths, starting from the root.\n findLeafNodes([], rootNode);\n\n nodePaths.forEach((path) => {\n // Each node in the current path will have to be assigned a guard path, working from the root outwards.\n for (let depth = 0; depth < path.length; depth++) {\n // Get the node in the path at the current depth.\n const currentNode = path[depth];\n\n // The node may already have been assigned a guard path, if so just skip it.\n if (currentNode.hasGuardPath()) {\n continue;\n }\n\n // Create the guard path for the current node.\n const guardPath = new GuardPath(\n path\n .slice(0, depth + 1)\n .map((node) => ({ node, guards: node.getGuardAttributes() }))\n .filter((details) => details.guards.length > 0)\n );\n\n // Assign the guard path to the current node.\n currentNode.setGuardPath(guardPath);\n }\n });\n }\n}\n"], - "mappings": "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", - "names": ["Participant", "Lotto", "createLotto", "State", "createLotto"] + "sources": ["../node_modules/lotto-draw/dist/Participant.js", "../node_modules/lotto-draw/dist/Utilities.js", "../node_modules/lotto-draw/dist/Lotto.js", "../node_modules/lotto-draw/dist/createLotto.js", "../node_modules/lotto-draw/dist/index.js", "../src/index.ts", "../src/attributes/guards/GuardUnsatisifedException.ts", "../src/attributes/guards/GuardPath.ts", "../src/State.ts", "../src/nodes/Node.ts", "../src/nodes/leaf/Leaf.ts", "../src/Lookup.ts", "../src/nodes/leaf/Action.ts", "../src/nodes/leaf/Condition.ts", "../src/nodes/leaf/Wait.ts", "../src/nodes/decorator/Decorator.ts", "../src/nodes/decorator/Root.ts", "../src/nodes/decorator/Repeat.ts", "../src/nodes/decorator/Retry.ts", "../src/nodes/decorator/Flip.ts", "../src/nodes/decorator/Succeed.ts", "../src/nodes/decorator/Fail.ts", "../src/nodes/composite/Lotto.ts", "../src/nodes/composite/Composite.ts", "../src/nodes/composite/Selector.ts", "../src/nodes/composite/Sequence.ts", "../src/nodes/composite/Parallel.ts", "../src/attributes/Attribute.ts", "../src/attributes/guards/Guard.ts", "../src/attributes/guards/While.ts", "../src/attributes/guards/Until.ts", "../src/attributes/callbacks/Callback.ts", "../src/attributes/callbacks/Entry.ts", "../src/attributes/callbacks/Exit.ts", "../src/attributes/callbacks/Step.ts", "../src/RootAstNodesBuilder.ts", "../src/BehaviourTree.ts", "../src/mdsl/MDSLUtilities.ts", "../src/mdsl/MDSLNodeArgumentParser.ts", "../src/mdsl/MDSLNodeAttributeParser.ts", "../src/mdsl/MDSLDefinitionParser.ts"], + "sourcesContent": ["\"use strict\";\r\nObject.defineProperty(exports, \"__esModule\", { value: true });\r\nexports.Participant = void 0;\r\n/**\r\n * A participant that holds a number of tickets.\r\n */\r\nvar Participant = /** @class */ (function () {\r\n /**\r\n * Creates an instance of the Participant class.\r\n * @param participant The actual participant.\r\n * @param tickets The number of tickets held by the participant.\r\n */\r\n function Participant(participant, tickets) {\r\n if (tickets === void 0) { tickets = 1; }\r\n this._participant = participant;\r\n this._tickets = tickets;\r\n }\r\n Object.defineProperty(Participant.prototype, \"participant\", {\r\n /** Gets the actual participant. */\r\n get: function () {\r\n return this._participant;\r\n },\r\n enumerable: false,\r\n configurable: true\r\n });\r\n Object.defineProperty(Participant.prototype, \"tickets\", {\r\n /** Gets or sets the number of tickets held by the participant. */\r\n get: function () {\r\n return this._tickets;\r\n },\r\n set: function (value) {\r\n this._tickets = value;\r\n },\r\n enumerable: false,\r\n configurable: true\r\n });\r\n return Participant;\r\n}());\r\nexports.Participant = Participant;\r\n", "\"use strict\";\r\nObject.defineProperty(exports, \"__esModule\", { value: true });\r\nexports.isNaturalNumber = exports.isNullOrUndefined = void 0;\r\n/**\r\n * Gets whether the value provided is null or undefined.\r\n * @param value The value to check.\r\n * @returns Whether the value provided is null or undefined.\r\n */\r\nfunction isNullOrUndefined(value) {\r\n return value === null || value === undefined;\r\n}\r\nexports.isNullOrUndefined = isNullOrUndefined;\r\n/**\r\n * Gets whether the value provided is a natural number.\r\n * @param value The value to check.\r\n * @returns Whether the value provided is a natural number.\r\n */\r\nfunction isNaturalNumber(value) {\r\n return typeof value === \"number\" && value >= 1 && Math.floor(value) === value;\r\n}\r\nexports.isNaturalNumber = isNaturalNumber;\r\n", "\"use strict\";\r\nObject.defineProperty(exports, \"__esModule\", { value: true });\r\nexports.Lotto = void 0;\r\nvar Participant_1 = require(\"./Participant\");\r\nvar Utilities_1 = require(\"./Utilities\");\r\n/**\r\n * Represents a lotto consisting of a number of pickable ticket-holding participants.\r\n */\r\nvar Lotto = /** @class */ (function () {\r\n /**\r\n * Creates a new instance of Lotto.\r\n * @param customRandom The custom RNG to use in place of Math.random().\r\n */\r\n function Lotto(customRandom) {\r\n /** The array of participants that are holding tickets in the lotto. */\r\n this._participants = [];\r\n this._customRandom = customRandom;\r\n }\r\n /**\r\n * Adds a participant with the specified number of tickets, or adds to the participant ticket count if the participant already holds tickets.\r\n * @param participant The participant to add or to increase the ticket count for if they already hold tickets.\r\n * @param tickets The number of tickets, defaults to 1.\r\n * @returns The Lotto instance.\r\n */\r\n Lotto.prototype.add = function (participant, tickets) {\r\n if (tickets === void 0) { tickets = 1; }\r\n // Check that we have a valid ticket count.\r\n if (!(0, Utilities_1.isNaturalNumber)(tickets)) {\r\n throw new Error(\"tickets value must be a natural number\");\r\n }\r\n // Check whether this participant has already been added.\r\n var existingParticipant = this._participants.find(function (part) { return part.participant === participant; });\r\n if (existingParticipant) {\r\n // The participant has already been added to the lotto so just add to their ticket count.\r\n existingParticipant.tickets += tickets;\r\n }\r\n else {\r\n // The participant is not part of the lotto so we should add them.\r\n this._participants.push(new Participant_1.Participant(participant, tickets));\r\n }\r\n return this;\r\n };\r\n /**\r\n * Removes the specified number of tickets for the given participant from the draw, or all tickets if a ticket number is not defined.\r\n * @param participant The participant to remove tickets for.\r\n * @param tickets The number of tickets to remove, or undefined if all tickets are to be removed.\r\n * @returns The Lotto instance.\r\n */\r\n Lotto.prototype.remove = function (participant, tickets) {\r\n // Attempt to get the existing participant.\r\n var existingParticipant = this._participants.find(function (part) { return part.participant === participant; });\r\n // There is nothing to do if the specified participant isn't even part of the lotto.\r\n if (!existingParticipant) {\r\n return this;\r\n }\r\n // Check whether a tickets value was given.\r\n if (tickets !== undefined) {\r\n // Check that we have a valid ticket count.\r\n if (!(0, Utilities_1.isNaturalNumber)(tickets)) {\r\n throw new Error(\"tickets value must be a natural number\");\r\n }\r\n existingParticipant.tickets -= tickets;\r\n // If the participant no longer holds any tickets then they should be removed.\r\n if (existingParticipant.tickets < 1) {\r\n this._participants = this._participants.filter(function (part) { return part !== existingParticipant; });\r\n }\r\n }\r\n else {\r\n // We are removing all tickets for the participant so just remove them from the lotto.\r\n this._participants = this._participants.filter(function (part) { return part !== existingParticipant; });\r\n }\r\n return this;\r\n };\r\n /**\r\n * Draw a winning ticket and return the participant that holds the ticket.\r\n * @param options The draw options.\r\n * @returns The participant that holds the winning ticket.\r\n */\r\n Lotto.prototype.draw = function (options) {\r\n if (options === void 0) { options = {}; }\r\n // If we have no participants then just return null.\r\n if (this._participants.length === 0) {\r\n return null;\r\n }\r\n var redrawable = (0, Utilities_1.isNullOrUndefined)(options.redrawable) ? true : options.redrawable;\r\n var pickable = [];\r\n this._participants.forEach(function (_a) {\r\n var participant = _a.participant, tickets = _a.tickets;\r\n for (var ticketCount = 0; ticketCount < tickets; ticketCount++) {\r\n pickable.push(participant);\r\n }\r\n });\r\n var random;\r\n // We need a random floating-point number between 0 (inclusive) and 1 to scale up to pick our winner.\r\n // If a custom random function exists then we should use that or fall back to Math.random().\r\n if (this._customRandom) {\r\n // Call our custom random function to get a random floating-point number.\r\n random = this._customRandom();\r\n // Verify that the result of calling our custom random function is a number between 0 (inclusive) and 1.\r\n if (typeof random !== \"number\" || random < 0 || random >= 1) {\r\n throw new Error(\"the 'random' function provided did not return a number between 0 (inclusive) and 1\");\r\n }\r\n }\r\n else {\r\n // No custom random function was defined so just use good ol' Math.random().\r\n random = Math.random();\r\n }\r\n // Pick a winning participant.\r\n var winner = pickable[Math.floor(random * pickable.length)];\r\n // If the ticket isn't redrawable then we should remove a ticket from the winning participants ticket count.\r\n if (!redrawable) {\r\n this.remove(winner, 1);\r\n }\r\n // Return the winning participant.\r\n return winner;\r\n };\r\n /**\r\n * Draws multiple winning tickets and return an array of the participants that hold the winning tickets.\r\n * @param tickets The number of winning tickets to draw.\r\n * @param options The draw multiple options.\r\n * @returns An array of the participants that hold the winning tickets.\r\n */\r\n Lotto.prototype.drawMultiple = function (tickets, options) {\r\n if (options === void 0) { options = {}; }\r\n var uniqueResults = (0, Utilities_1.isNullOrUndefined)(options.unique) ? false : options.unique;\r\n // Handle cases where the user has asked for zero tickets (no idea why they would do this be we should trust them).\r\n if (tickets === 0) {\r\n return [];\r\n }\r\n // Now that we know out tickets value is not zero we should check that it is a valid natural number.\r\n if (!(0, Utilities_1.isNaturalNumber)(tickets)) {\r\n throw new Error(\"tickets value must be a natural number\");\r\n }\r\n var result = [];\r\n // Keep drawing tickets until we either reach the number of required tickets or we simply run out of tickets to draw.\r\n // We can run out of tickets to draw if 'options.redrawable' is explicity 'false' or we just had no participants when 'drawMultiple' was called.\r\n while (result.length < tickets && this._participants.length > 0) {\r\n result.push(this.draw(options));\r\n }\r\n // If the 'unique' draw option is set then we need to remove duplicates from the result list.\r\n if (uniqueResults) {\r\n // Create an array to store our unique results.\r\n var unique = [];\r\n // Iterate over all of our participants (with potential duplicates) and populate our array of unique values.\r\n for (var _i = 0, result_1 = result; _i < result_1.length; _i++) {\r\n var participant = result_1[_i];\r\n if (unique.indexOf(participant) === -1) {\r\n unique.push(participant);\r\n }\r\n }\r\n result = unique;\r\n }\r\n return result;\r\n };\r\n return Lotto;\r\n}());\r\nexports.Lotto = Lotto;\r\n", "\"use strict\";\r\nObject.defineProperty(exports, \"__esModule\", { value: true });\r\nexports.createLotto = void 0;\r\nvar Lotto_1 = require(\"./Lotto\");\r\n/**\r\n * A function that creates and returns a Lotto instance.\r\n * @param participantsOrOptions An array of initial participants or options relating to the creation of a Lotto instance.\r\n * @returns A new Lotto instance.\r\n */\r\nfunction createLotto(participantsOrOptions) {\r\n // If no initial participants or lotto options were provided as an argument then we can just return a new lotto instance now.\r\n if (!participantsOrOptions) {\r\n return new Lotto_1.Lotto();\r\n }\r\n // Check whether we were provided with an array of initial participants or a lotto options object.\r\n if (Array.isArray(participantsOrOptions)) {\r\n // We are dealing with a pre-defined array of participants.\r\n var participants = participantsOrOptions;\r\n var lotto_1 = new Lotto_1.Lotto();\r\n // If the lotto participants have been defined upfront then we will need to add them all to our lotto instance now.\r\n participants.forEach(function (_a) {\r\n var participant = _a[0], tokens = _a[1];\r\n return lotto_1.add(participant, tokens);\r\n });\r\n // Return the Lotto instance.\r\n return lotto_1;\r\n }\r\n else {\r\n // We are dealing with some lotto options.\r\n var random = participantsOrOptions.random, participants = participantsOrOptions.participants;\r\n // Create a Lotto instance passing the custom RNG function to use in place of Math.random() (which could be undefined).\r\n var lotto_2 = new Lotto_1.Lotto(random);\r\n // If the lotto participants have been defined upfront as part of the options then we will need to add them all to our lotto instance now.\r\n if (participants) {\r\n participants.forEach(function (_a) {\r\n var participant = _a[0], tokens = _a[1];\r\n return lotto_2.add(participant, tokens);\r\n });\r\n }\r\n // Return the Lotto instance.\r\n return lotto_2;\r\n }\r\n}\r\nexports.createLotto = createLotto;\r\n", "\"use strict\";\r\nObject.defineProperty(exports, \"__esModule\", { value: true });\r\nvar createLotto_1 = require(\"./createLotto\");\r\nexports.default = createLotto_1.createLotto;\r\n", "import { BehaviourTree, FlattenedTreeNode } from \"./BehaviourTree\";\nimport State from \"./State\";\nimport { parseMDSLToJSON } from \"./mdsl/MDSLDefinitionParser\";\n\nexport { BehaviourTree, State, parseMDSLToJSON };\nexport type { FlattenedTreeNode };\n", "import Node from \"../../nodes/Node\";\n\n/**\n * An exception thrown when evaluating node guard path conditions and a conditions fails.\n */\nexport default class GuardUnsatisifedException extends Error {\n /**\n * @param source The node at which a guard condition failed.\n */\n constructor(private source: Node) {\n super(\"A guard path condition has failed\");\n }\n\n /**\n * Gets whether the specified node is the node at which a guard condition failed.\n * @param node The node to check against the source node.\n * @returns Whether the specified node is the node at which a guard condition failed.\n */\n isSourceNode = (node: Node) => node === this.source;\n}\n", "import { Agent } from \"../../Agent\";\nimport Guard from \"./Guard\";\nimport Node from \"../../nodes/Node\";\nimport GuardUnsatisifedException from \"./GuardUnsatisifedException\";\n\nexport type GuardPathPart = {\n node: Node;\n guards: Guard[];\n};\n\n/**\n * Represents a path of node guards along a root-to-leaf tree path.\n */\nexport default class GuardPath {\n /**\n * @param nodes An array of objects defining a node instance -> guard link, ordered by node depth.\n */\n constructor(private nodes: GuardPathPart[]) {}\n\n /**\n * Evaluate guard conditions for all guards in the tree path, moving outwards from the root.\n * @param agent The agent, required for guard evaluation.\n * @returns An evaluation results object.\n */\n evaluate = (agent: Agent) => {\n // We need to evaluate guard conditions for nodes up the tree, moving outwards from the root.\n for (const details of this.nodes) {\n // There can be multiple guards per node.\n for (const guard of details.guards) {\n // Check whether the guard condition passes, and throw an exception if not.\n if (!guard.isSatisfied(agent)) {\n throw new GuardUnsatisifedException(details.node);\n }\n }\n }\n };\n}\n", "/**\n * Enumeration of node state types.\n */\nexport enum State {\n READY = \"mistreevous.ready\",\n RUNNING = \"mistreevous.running\",\n SUCCEEDED = \"mistreevous.succeeded\",\n FAILED = \"mistreevous.failed\"\n}\n\nexport { State as default };\n\nexport type CompleteState = State.SUCCEEDED | State.FAILED;\nexport type AnyState = State.READY | State.RUNNING | CompleteState;\n", "import { Agent } from \"../Agent\";\nimport Attribute from \"../attributes/Attribute\";\nimport Entry from \"../attributes/callbacks/Entry\";\nimport Exit from \"../attributes/callbacks/Exit\";\nimport Step from \"../attributes/callbacks/Step\";\nimport Guard from \"../attributes/guards/Guard\";\nimport GuardPath from \"../attributes/guards/GuardPath\";\nimport GuardUnsatisifedException from \"../attributes/guards/GuardUnsatisifedException\";\nimport { BehaviourTreeOptions } from \"../BehaviourTreeOptions\";\nimport { AnyArgument } from \"../RootAstNodesBuilder\";\nimport State, { AnyState } from \"../State\";\nimport Leaf from \"./leaf/Leaf\";\n\n/**\n * A base node.\n */\nexport default abstract class Node {\n /**\n * The node uid.\n */\n private readonly uid: string = createNodeUid();\n /**\n * The node state.\n */\n private state: AnyState = State.READY;\n /**\n * The guard path to evaluate as part of a node update.\n */\n private guardPath: GuardPath | undefined;\n\n /**\n * @param type The node type.\n * @param attributes The node attributes.\n * @param args The node argument definitions.\n */\n constructor(private type: string, private attributes: Attribute[], private args: AnyArgument[]) {}\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected abstract onUpdate(agent: Agent, options: BehaviourTreeOptions): void;\n\n /**\n * Gets the name of the node.\n */\n public abstract getName(): string;\n\n /**\n * Gets whether this node is a leaf node.\n */\n public abstract isLeafNode: () => this is Leaf;\n\n /**\n * Gets/Sets the state of the node.\n */\n getState = (): AnyState => this.state;\n setState = (value: AnyState): void => {\n this.state = value;\n };\n\n /**\n * Gets the unique id of the node.\n */\n getUid = () => this.uid;\n\n /**\n * Gets the type of the node.\n */\n getType = () => this.type;\n\n /**\n * Gets the node attributes.\n */\n getAttributes = () => this.attributes;\n\n /**\n * Gets the node arguments.\n */\n getArguments = () => this.args;\n\n /**\n * Gets the node attribute with the specified type, or null if it does not exist.\n */\n getAttribute(type: \"entry\" | \"ENTRY\"): Entry;\n getAttribute(type: \"exit\" | \"EXIT\"): Exit;\n getAttribute(type: \"step\" | \"STEP\"): Step;\n getAttribute(type: string): Attribute {\n return (\n this.getAttributes().filter((decorator) => decorator.getType().toUpperCase() === type.toUpperCase())[0] ||\n null\n );\n }\n\n /**\n * Gets the node attributes.\n */\n getGuardAttributes = (): Guard[] => this.getAttributes().filter((decorator) => decorator.isGuard()) as Guard[];\n\n /**\n * Sets the guard path to evaluate as part of a node update.\n */\n setGuardPath = (value: GuardPath) => (this.guardPath = value);\n\n /**\n * Gets whether a guard path is assigned to this node.\n */\n hasGuardPath = () => !!this.guardPath;\n\n /**\n * Gets whether this node is in the specified state.\n * @param value The value to compare to the node state.\n */\n public is(value: AnyState): boolean {\n return this.state === value;\n }\n\n /**\n * Reset the state of the node.\n */\n public reset(): void {\n this.setState(State.READY);\n }\n\n /**\n * Abort the running of this node.\n * @param agent The agent.\n */\n public abort(agent: Agent): void {\n // There is nothing to do if this node is not in the running state.\n if (!this.is(State.RUNNING)) {\n return;\n }\n\n // Reset the state of this node.\n this.reset();\n\n this.getAttribute(\"exit\")?.callAgentFunction(agent, false, true);\n }\n\n /**\n * Update the node.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n * @returns The result of the update.\n */\n public update(agent: Agent, options: BehaviourTreeOptions): void {\n // If this node is already in a 'SUCCEEDED' or 'FAILED' state then there is nothing to do.\n if (this.is(State.SUCCEEDED) || this.is(State.FAILED)) {\n return;\n }\n\n try {\n // Evaluate all of the guard path conditions for the current tree path.\n this.guardPath!.evaluate(agent);\n\n // If this node is in the READY state then call the ENTRY for this node if it exists.\n if (this.is(State.READY)) {\n this.getAttribute(\"entry\")?.callAgentFunction(agent);\n }\n\n this.getAttribute(\"step\")?.callAgentFunction(agent);\n\n // Do the actual update.\n this.onUpdate(agent, options);\n\n // If this node is now in a 'SUCCEEDED' or 'FAILED' state then call the EXIT for this node if it exists.\n if (this.is(State.SUCCEEDED) || this.is(State.FAILED)) {\n this.getAttribute(\"exit\")?.callAgentFunction(agent, this.is(State.SUCCEEDED), false);\n }\n } catch (error) {\n // If the error is a GuardUnsatisfiedException then we need to determine if this node is the source.\n if (error instanceof GuardUnsatisifedException && error.isSourceNode(this)) {\n // Abort the current node.\n this.abort(agent);\n\n // Any node that is the source of an abort will be a failed node.\n this.setState(State.FAILED);\n } else {\n throw error;\n }\n }\n }\n}\n\n/**\n * Create a randomly generated node uid.\n * @returns A randomly generated node uid.\n */\nfunction createNodeUid(): string {\n var S4 = function () {\n return (((1 + Math.random()) * 0x10000) | 0).toString(16).substring(1);\n };\n return S4() + S4() + \"-\" + S4() + \"-\" + S4() + \"-\" + S4() + \"-\" + S4() + S4() + S4();\n}\n", "import Node from \"../Node\";\n\n/**\n * A leaf node.\n */\nexport default abstract class Leaf extends Node {\n /**\n * Gets whether this node is a leaf node.\n */\n isLeafNode = () => true;\n}\n", "import { ActionResult, Agent, ExitFunctionArg, FunctionArg, GlobalFunction } from \"./Agent\";\nimport { AnyArgument, RootAstNode } from \"./RootAstNodesBuilder\";\n\n// Exit callbacks receive their own special type of argument.\n// There's probably stricter ways to represent this but it feels overly complex right now.\ntype ExitResultArg = { value: ExitFunctionArg };\nexport type AnyExitArgument = AnyArgument | ExitResultArg;\n\nexport type InvokerFunction = (args: AnyExitArgument[]) => ActionResult;\n\n/**\n * A singleton used to store and lookup registered functions and subtrees.\n */\nexport default class Lookup {\n /**\n * The object holding any registered functions keyed on function name.\n */\n private static functionTable: { [key: string]: GlobalFunction } = {};\n /**\n * The object holding any registered sub-trees keyed on tree name.\n */\n private static subtreeTable: { [key: string]: RootAstNode } = {};\n\n /**\n * Gets the function with the specified name.\n * @param name The name of the function.\n * @returns The function with the specified name.\n */\n public static getFunc(name: string): GlobalFunction {\n return this.functionTable[name];\n }\n\n /**\n * Sets the function with the specified name for later lookup.\n * @param name The name of the function.\n * @param func The function.\n */\n public static setFunc(name: string, func: GlobalFunction): void {\n this.functionTable[name] = func;\n }\n\n /**\n * Gets the function invoker for the specified agent and function name.\n * If a function with the specified name exists on the agent object then it will\n * be returned, otherwise we will then check the registered functions for a match.\n * @param agent The agent instance that this behaviour tree is modelling behaviour for.\n * @param name The function name.\n * @returns The function invoker for the specified agent and function name.\n */\n static getFuncInvoker(agent: Agent, name: string): InvokerFunction | null {\n // Check whether the agent contains the specified function.\n const foundOnAgent = agent[name];\n if (foundOnAgent && typeof foundOnAgent === \"function\") {\n return (args: AnyExitArgument[]): boolean | ActionResult =>\n foundOnAgent.apply(\n agent,\n args.map((arg) => arg.value)\n );\n }\n\n // The agent does not contain the specified function but it may have been registered at some point.\n if (this.functionTable[name] && typeof this.functionTable[name] === \"function\") {\n return (args: AnyExitArgument[]) => this.functionTable[name](agent, ...args.map((arg) => arg.value));\n }\n\n // We have no function to invoke.\n return null;\n }\n\n /**\n * Gets the subtree with the specified name.\n * @param name The name of the subtree.\n * @returns The subtree with the specified name.\n */\n static getSubtree(name: string): RootAstNode {\n return this.subtreeTable[name];\n }\n\n /**\n * Sets the subtree with the specified name for later lookup.\n * @param name The name of the subtree.\n * @param subtree The subtree.\n */\n static setSubtree(name: string, subtree: RootAstNode) {\n this.subtreeTable[name] = subtree;\n }\n\n /**\n * Removes the registered function or subtree with the specified name.\n * @param name The name of the registered function or subtree.\n */\n static remove(name: string) {\n delete this.functionTable[name];\n delete this.subtreeTable[name];\n }\n\n /**\n * Remove all registered functions and subtrees.\n */\n static empty() {\n this.functionTable = {};\n this.subtreeTable = {};\n }\n}\n", "import Leaf from \"./Leaf\";\nimport State, { CompleteState } from \"../../State\";\nimport Lookup from \"../../Lookup\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { AnyArgument } from \"../../RootAstNodesBuilder\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * An Action leaf node.\n * This represents an immediate or ongoing state of behaviour.\n */\nexport default class Action extends Leaf {\n /**\n * @param attributes The node attributes.\n * @param actionName The action name.\n * @param actionArguments The array of action argument definitions.\n */\n constructor(attributes: Attribute[], private actionName: string, private actionArguments: AnyArgument[]) {\n super(\"action\", attributes, actionArguments);\n }\n\n /**\n * Whether there is a pending update promise.\n */\n private isUsingUpdatePromise = false;\n\n /**\n * The finished state result of an update promise.\n */\n private updatePromiseStateResult: CompleteState | null = null;\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // If the result of this action depends on an update promise then there is nothing to do until\n // it resolves, unless there has been a value set as a result of the update promise resolving.\n if (this.isUsingUpdatePromise) {\n // Check whether the update promise has resolved with a state value.\n if (this.updatePromiseStateResult) {\n // Set the state of this node to match the state returned by the promise.\n this.setState(this.updatePromiseStateResult);\n }\n\n return;\n }\n\n // Attempt to get the invoker for the action function.\n const actionFuncInvoker = Lookup.getFuncInvoker(agent, this.actionName);\n\n // The action function should be defined.\n if (actionFuncInvoker === null) {\n throw new Error(\n `cannot update action node as the action '${this.actionName}' function is not defined on the agent and has not been registered`\n );\n }\n\n // Call the action function, the result of which may be:\n // - The finished state of this action node.\n // - A promise to return a finished node state.\n // - Undefined if the node should remain in the running state.\n const updateResult = actionFuncInvoker(this.actionArguments) as CompleteState | Promise;\n\n if (updateResult instanceof Promise) {\n updateResult.then(\n (result) => {\n // If 'isUpdatePromisePending' is null then the promise was cleared as it was resolving, probably via an abort of reset.\n if (!this.isUsingUpdatePromise) {\n return;\n }\n\n // Check to make sure the result is a valid finished state.\n if (result !== State.SUCCEEDED && result !== State.FAILED) {\n throw new Error(\n \"action node promise resolved with an invalid value, expected a State.SUCCEEDED or State.FAILED value to be returned\"\n );\n }\n\n // Set pending update promise state result to be processed on next update.\n this.updatePromiseStateResult = result;\n },\n (reason) => {\n // If 'isUpdatePromisePending' is null then the promise was cleared as it was resolving, probably via an abort of reset.\n if (!this.isUsingUpdatePromise) {\n return;\n }\n\n // Just throw whatever was returned as the rejection argument.\n throw new Error(reason);\n }\n );\n\n // This node will be in the 'RUNNING' state until the update promise resolves.\n this.setState(State.RUNNING);\n\n // We are now waiting for the promise returned by the use to resolve before we know what state this node is in.\n this.isUsingUpdatePromise = true;\n } else {\n // Validate the returned value.\n this.validateUpdateResult(updateResult);\n\n // Set the state of this node, this may be undefined, which just means that the node is still in the 'RUNNING' state.\n this.setState(updateResult || State.RUNNING);\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => this.actionName;\n\n /**\n * Reset the state of the node.\n */\n reset = () => {\n // Reset the state of this node.\n this.setState(State.READY);\n\n // There is no longer an update promise that we care about.\n this.isUsingUpdatePromise = false;\n this.updatePromiseStateResult = null;\n };\n\n /**\n * Validate the result of an update function call.\n * @param result The result of an update function call.\n */\n private validateUpdateResult = (result: CompleteState | boolean) => {\n switch (result) {\n case State.SUCCEEDED:\n case State.FAILED:\n case undefined:\n return;\n default:\n throw new Error(\n `action '${this.actionName}' 'onUpdate' returned an invalid response, expected an optional State.SUCCEEDED or State.FAILED value to be returned`\n );\n }\n };\n}\n", "import Leaf from \"./Leaf\";\nimport State from \"../../State\";\nimport Lookup from \"../../Lookup\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { AnyArgument } from \"../../RootAstNodesBuilder\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A Condition leaf node.\n * This will succeed or fail immediately based on an agent predicate, without moving to the 'RUNNING' state.\n */\nexport default class Condition extends Leaf {\n /**\n * @param attributes The node attributes.\n * @param conditionName The name of the condition function.\n * @param conditionArguments The array of condition argument definitions.\n */\n constructor(attributes: Attribute[], private conditionName: string, private conditionArguments: AnyArgument[]) {\n super(\"condition\", attributes, conditionArguments);\n }\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // Attempt to get the invoker for the condition function.\n const conditionFuncInvoker = Lookup.getFuncInvoker(agent, this.conditionName);\n\n // The condition function should be defined.\n if (conditionFuncInvoker === null) {\n throw new Error(\n `cannot update condition node as the condition '${this.conditionName}' function is not defined on the agent and has not been registered`\n );\n }\n\n // Call the condition function to determine the state of this node.\n this.setState(!!conditionFuncInvoker(this.conditionArguments) ? State.SUCCEEDED : State.FAILED);\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => this.conditionName;\n}\n", "import Leaf from \"./Leaf\";\nimport State from \"../../State\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { Agent } from \"../../Agent\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A WAIT node.\n * The state of this node will change to SUCCEEDED after a duration of time\n */\nexport default class Wait extends Leaf {\n /**\n * @param attributes The node attributes.\n * @param duration The duration that this node will wait to succeed in milliseconds.\n * @param durationMin The minimum possible duration in milliseconds that this node will wait to succeed.\n * @param durationMax The maximum possible duration in milliseconds that this node will wait to succeed.\n */\n constructor(\n attributes: Attribute[],\n private duration: number | null,\n private durationMin: number | null,\n private durationMax: number | null\n ) {\n super(\"wait\", attributes, []);\n }\n\n /**\n * The time in milliseconds at which this node was first updated.\n */\n private initialUpdateTime: number = 0;\n\n /**\n * The total duration in milliseconds that this node will be waiting for.\n */\n private totalDuration: number | null = null;\n\n /**\n * The duration in milliseconds that this node has been waiting for.\n */\n private waitedDuration: number = 0;\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // If this node is in the READY state then we need to set the initial update time.\n if (this.is(State.READY)) {\n // Set the initial update time.\n this.initialUpdateTime = new Date().getTime();\n\n // Set the initial waited duration.\n this.waitedDuration = 0;\n\n // Are we dealing with an explicit duration or will we be randomly picking a duration between the min and max duration.\n if (this.duration !== null) {\n this.totalDuration = this.duration;\n } else if (this.durationMin !== null && this.durationMax !== null) {\n // We will be picking a random duration between a min and max duration, if the optional 'random' behaviour tree\n // function option is defined then we will be using that, otherwise we will fall back to using Math.random.\n const random = typeof options.random === \"function\" ? options.random : Math.random;\n\n // Pick a random duration between a min and max duration.\n this.totalDuration = Math.floor(\n random() * (this.durationMax - this.durationMin + 1) + this.durationMin\n );\n } else {\n this.totalDuration = null;\n }\n\n // The node is now running until we finish waiting.\n this.setState(State.RUNNING);\n }\n\n // If we have no total duration then this wait node will wait indefinitely until it is aborted.\n if (this.totalDuration === null) {\n return;\n }\n\n // If we have a 'getDeltaTime' function defined as part of our options then we will use it to figure out how long we have waited for.\n if (typeof options.getDeltaTime === \"function\") {\n // Get the delta time.\n const deltaTime = options.getDeltaTime();\n\n // Our delta time must be a valid number and cannot be NaN.\n if (typeof deltaTime !== \"number\" || isNaN(deltaTime)) {\n throw new Error(\"The delta time must be a valid number and not NaN.\");\n }\n\n // Update the amount of time that this node has been waiting for based on the delta time.\n this.waitedDuration += deltaTime * 1000;\n } else {\n // We are not using a delta time, so we will just work out hom much time has passed since the first update.\n this.waitedDuration = new Date().getTime() - this.initialUpdateTime;\n }\n\n // Have we waited long enough?\n if (this.waitedDuration >= this.totalDuration) {\n // We have finished waiting!\n this.setState(State.SUCCEEDED);\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => {\n if (this.duration !== null) {\n return `WAIT ${this.duration}ms`;\n } else if (this.durationMin !== null && this.durationMax !== null) {\n return `WAIT ${this.durationMin}ms-${this.durationMax}ms`;\n } else {\n return \"WAIT\";\n }\n };\n}\n", "import Node from \"../Node\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\n\n/**\n * A decorator node that wraps a single child node.\n */\nexport default abstract class Decorator extends Node {\n /**\n * @param type The node type.\n * @param attributes The node attributes.\n * @param child The child node.\n */\n constructor(type: string, attributes: Attribute[], protected child: Node) {\n super(type, attributes, []);\n }\n\n /**\n * Gets whether this node is a leaf node.\n */\n isLeafNode = () => false;\n\n /**\n * Gets the children of this node.\n */\n getChildren = () => [this.child];\n\n /**\n * Reset the state of the node.\n */\n reset = () => {\n // Reset the state of this node.\n this.setState(State.READY);\n\n // Reset the state of the child node.\n this.child.reset();\n };\n\n /**\n * Abort the running of this node.\n * @param agent The agent.\n */\n abort = (agent: Agent) => {\n // There is nothing to do if this node is not in the running state.\n if (!this.is(State.RUNNING)) {\n return;\n }\n\n // Abort the child node.\n this.child.abort(agent);\n\n // Reset the state of this node.\n this.reset();\n\n this.getAttribute(\"exit\")?.callAgentFunction(agent, false, true);\n };\n}\n", "import Node from \"../Node\";\nimport Decorator from \"./Decorator\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A Root node.\n * The root node will have a single child.\n */\nexport default class Root extends Decorator {\n /**\n * @param attributes The node attributes.\n * @param child The child node.\n */\n constructor(attributes: Attribute[], child: Node) {\n super(\"root\", attributes, child);\n }\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // If the child has never been updated or is running then we will need to update it now.\n if (this.child.getState() === State.READY || this.child.getState() === State.RUNNING) {\n // Update the child of this node.\n this.child.update(agent, options);\n }\n\n // The state of the root node is the state of its child.\n this.setState(this.child.getState());\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => \"ROOT\";\n}\n", "import Node from \"../Node\";\nimport Decorator from \"./Decorator\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A REPEAT node.\n * The node has a single child which can have:\n * -- A number of iterations for which to repeat the child node.\n * -- An infinite repeat loop if neither an iteration count or a condition function is defined.\n * The REPEAT node will stop and have a 'FAILED' state if its child is ever in a 'FAILED' state after an update.\n * The REPEAT node will attempt to move on to the next iteration if its child is ever in a 'SUCCEEDED' state.\n */\nexport default class Repeat extends Decorator {\n /**\n * @param attributes The node attributes.\n * @param iterations The number of iterations to repeat the child node.\n * @param iterationsMin The minimum possible number of iterations to repeat the child node.\n * @param iterationsMax The maximum possible number of iterations to repeat the child node.\n * @param child The child node.\n */\n constructor(\n attributes: Attribute[],\n private iterations: number | null,\n private iterationsMin: number | null,\n private iterationsMax: number | null,\n child: Node\n ) {\n super(\"repeat\", attributes, child);\n }\n\n /**\n * The number of target iterations to make.\n */\n private targetIterationCount: number | null = null;\n\n /**\n * The current iteration count.\n */\n private currentIterationCount: number = 0;\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // If this node is in the READY state then we need to reset the child and the target iteration count.\n if (this.is(State.READY)) {\n // Reset the child node.\n this.child.reset();\n\n // Reset the current iteration count.\n this.currentIterationCount = 0;\n\n // Set the target iteration count.\n this.setTargetIterationCount(options);\n }\n\n // Do a check to see if we can iterate. If we can then this node will move into the 'RUNNING' state.\n // If we cannot iterate then we have hit our target iteration count, which means that the node has succeeded.\n if (this.canIterate()) {\n // This node is in the running state and can do its initial iteration.\n this.setState(State.RUNNING);\n\n // We may have already completed an iteration, meaning that the child node will be in the SUCCEEDED state.\n // If this is the case then we will have to reset the child node now.\n if (this.child.getState() === State.SUCCEEDED) {\n this.child.reset();\n }\n\n // Update the child of this node.\n this.child.update(agent, options);\n\n // If the child moved into the FAILED state when we updated it then there is nothing left to do and this node has also failed.\n // If it has moved into the SUCCEEDED state then we have completed the current iteration.\n if (this.child.getState() === State.FAILED) {\n // The child has failed, meaning that this node has failed.\n this.setState(State.FAILED);\n\n return;\n } else if (this.child.getState() === State.SUCCEEDED) {\n // We have completed an iteration.\n this.currentIterationCount += 1;\n }\n } else {\n // This node is in the 'SUCCEEDED' state as we cannot iterate any more.\n this.setState(State.SUCCEEDED);\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => {\n if (this.iterations !== null) {\n return `REPEAT ${this.iterations}x`;\n } else if (this.iterationsMin !== null && this.iterationsMax !== null) {\n return `REPEAT ${this.iterationsMin}x-${this.iterationsMax}x`;\n } else {\n return \"REPEAT\";\n }\n };\n\n /**\n * Reset the state of the node.\n */\n reset = () => {\n // Reset the state of this node.\n this.setState(State.READY);\n\n // Reset the current iteration count.\n this.currentIterationCount = 0;\n\n // Reset the child node.\n this.child.reset();\n };\n\n /**\n * Gets whether an iteration can be made.\n * @returns Whether an iteration can be made.\n */\n private canIterate = () => {\n if (this.targetIterationCount !== null) {\n // We can iterate as long as we have not reached our target iteration count.\n return this.currentIterationCount < this.targetIterationCount;\n }\n\n // If neither an iteration count or a condition function were defined then we can iterate indefinitely.\n return true;\n };\n\n /**\n * Sets the target iteration count.\n * @param options The behaviour tree options object.\n */\n private setTargetIterationCount = (options: BehaviourTreeOptions) => {\n // Are we dealing with an explicit iteration count or will we be randomly picking a iteration count between the min and max iteration count.\n if (this.iterations !== null) {\n this.targetIterationCount = this.iterations;\n } else if (this.iterationsMin !== null && this.iterationsMax !== null) {\n // We will be picking a random iteration count between a min and max iteration count, if the optional 'random'\n // behaviour tree function option is defined then we will be using that, otherwise we will fall back to using Math.random.\n const random = typeof options.random === \"function\" ? options.random : Math.random;\n\n // Pick a random iteration count between a min and max iteration count.\n this.targetIterationCount = Math.floor(\n random() * (this.iterationsMax - this.iterationsMin + 1) + this.iterationsMin\n );\n } else {\n this.targetIterationCount = null;\n }\n };\n}\n", "import Node from \"../Node\";\nimport Decorator from \"./Decorator\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A RETRY node.\n * The node has a single child which can have:\n * -- A number of iterations for which to repeat the child node.\n * -- An infinite repeat loop if neither an iteration count or a condition function is defined.\n * The RETRY node will stop and have a 'SUCCEEDED' state if its child is ever in a 'SUCCEEDED' state after an update.\n * The RETRY node will attempt to move on to the next iteration if its child is ever in a 'FAILED' state.\n */\nexport default class Retry extends Decorator {\n /**\n * @param attributes The node attributes.\n * @param attempts The number of attempts to retry the child node.\n * @param attemptsMin The minimum possible number of attempts to retry the child node.\n * @param attemptsMax The maximum possible number of attempts to retry the child node.\n * @param child The child node.\n */\n constructor(\n attributes: Attribute[],\n private attempts: number | null,\n private attemptsMin: number | null,\n private attemptsMax: number | null,\n child: Node\n ) {\n super(\"retry\", attributes, child);\n }\n\n /**\n * The number of target attempts to make.\n */\n private targetAttemptCount: number | null = null;\n\n /**\n * The current attempt count.\n */\n private currentAttemptCount: number = 0;\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // If this node is in the READY state then we need to reset the child and the target attempt count.\n if (this.is(State.READY)) {\n // Reset the child node.\n this.child.reset();\n\n // Reset the current attempt count.\n this.currentAttemptCount = 0;\n\n // Set the target attempt count.\n this.setTargetAttemptCount(options);\n }\n\n // Do a check to see if we can attempt. If we can then this node will move into the 'RUNNING' state.\n // If we cannot attempt then we have hit our target attempt count, which means that the node has succeeded.\n if (this.canAttempt()) {\n // This node is in the running state and can do its initial attempt.\n this.setState(State.RUNNING);\n\n // We may have already completed an attempt, meaning that the child node will be in the FAILED state.\n // If this is the case then we will have to reset the child node now.\n if (this.child.getState() === State.FAILED) {\n this.child.reset();\n }\n\n // Update the child of this node.\n this.child.update(agent, options);\n\n // If the child moved into the SUCCEEDED state when we updated it then there is nothing left to do and this node has also succeeded.\n // If it has moved into the FAILED state then we have completed the current attempt.\n if (this.child.getState() === State.SUCCEEDED) {\n // The child has succeeded, meaning that this node has succeeded.\n this.setState(State.SUCCEEDED);\n\n return;\n } else if (this.child.getState() === State.FAILED) {\n // We have completed an attempt.\n this.currentAttemptCount += 1;\n }\n } else {\n // This node is in the 'FAILED' state as we cannot iterate any more.\n this.setState(State.FAILED);\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => {\n if (this.attempts !== null) {\n return `RETRY ${this.attempts}x`;\n } else if (this.attemptsMin !== null && this.attemptsMax !== null) {\n return `RETRY ${this.attemptsMin}x-${this.attemptsMax}x`;\n } else {\n return \"RETRY\";\n }\n };\n\n /**\n * Reset the state of the node.\n */\n reset = () => {\n // Reset the state of this node.\n this.setState(State.READY);\n\n // Reset the current attempt count.\n this.currentAttemptCount = 0;\n\n // Reset the child node.\n this.child.reset();\n };\n\n /**\n * Gets whether an attempt can be made.\n * @returns Whether an attempt can be made.\n */\n canAttempt = () => {\n if (this.targetAttemptCount !== null) {\n // We can attempt as long as we have not reached our target attempt count.\n return this.currentAttemptCount < this.targetAttemptCount;\n }\n\n // If neither an attempt count or a condition function were defined then we can attempt indefinitely.\n return true;\n };\n\n /**\n * Sets the target attempt count.\n * @param options The behaviour tree options object.\n */\n setTargetAttemptCount = (options: BehaviourTreeOptions) => {\n // Are we dealing with an explicit attempt count or will we be randomly picking an attempt count between the min and max attempt count.\n if (this.attempts !== null) {\n this.targetAttemptCount = this.attempts;\n } else if (this.attemptsMin !== null && this.attemptsMax !== null) {\n // We will be picking a random attempt count between a min and max attempt count, if the optional 'random'\n // behaviour tree function option is defined then we will be using that, otherwise we will fall back to using Math.random.\n const random = typeof options.random === \"function\" ? options.random : Math.random;\n\n // Pick a random attempt count between a min and max attempt count.\n this.targetAttemptCount = Math.floor(\n random() * (this.attemptsMax - this.attemptsMin + 1) + this.attemptsMin\n );\n } else {\n this.targetAttemptCount = null;\n }\n };\n}\n", "import Decorator from \"./Decorator\";\nimport State from \"../../State\";\nimport Node from \"../Node\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A Flip node.\n * This node wraps a single child and will flip the state of the child state.\n */\nexport default class Flip extends Decorator {\n /**\n * @param attributes The node attributes.\n * @param child The child node.\n */\n constructor(attributes: Attribute[], child: Node) {\n super(\"flip\", attributes, child);\n }\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // If the child has never been updated or is running then we will need to update it now.\n if (this.child.getState() === State.READY || this.child.getState() === State.RUNNING) {\n this.child.update(agent, options);\n }\n\n // The state of this node will depend in the state of its child.\n switch (this.child.getState()) {\n case State.RUNNING:\n this.setState(State.RUNNING);\n break;\n\n case State.SUCCEEDED:\n this.setState(State.FAILED);\n break;\n\n case State.FAILED:\n this.setState(State.SUCCEEDED);\n break;\n\n default:\n this.setState(State.READY);\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => \"FLIP\";\n}\n", "import Node from \"../Node\";\nimport Decorator from \"./Decorator\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A Succeed node.\n * This node wraps a single child and will always move to the 'SUCCEEDED' state when the child moves to a 'SUCCEEDED' or 'FAILED' state.\n */\nexport default class Succeed extends Decorator {\n /**\n * @param attributes The node attributes.\n * @param child The child node.\n */\n constructor(attributes: Attribute[], child: Node) {\n super(\"succeed\", attributes, child);\n }\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // If the child has never been updated or is running then we will need to update it now.\n if (this.child.getState() === State.READY || this.child.getState() === State.RUNNING) {\n this.child.update(agent, options);\n }\n\n // The state of this node will depend in the state of its child.\n switch (this.child.getState()) {\n case State.RUNNING:\n this.setState(State.RUNNING);\n break;\n\n case State.SUCCEEDED:\n case State.FAILED:\n this.setState(State.SUCCEEDED);\n break;\n\n default:\n this.setState(State.READY);\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => \"SUCCEED\";\n}\n", "import Node from \"../Node\";\nimport Decorator from \"./Decorator\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A Fail node.\n * This node wraps a single child and will always move to the 'FAILED' state when the child moves to a 'SUCCEEDED' or 'FAILED' state.\n */\nexport default class Fail extends Decorator {\n /**\n * @param attributes The node attributes.\n * @param child The child node.\n */\n constructor(attributes: Attribute[], child: Node) {\n super(\"fail\", attributes, child);\n }\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // If the child has never been updated or is running then we will need to update it now.\n if (this.child.getState() === State.READY || this.child.getState() === State.RUNNING) {\n this.child.update(agent, options);\n }\n\n // The state of this node will depend in the state of its child.\n switch (this.child.getState()) {\n case State.RUNNING:\n this.setState(State.RUNNING);\n break;\n\n case State.SUCCEEDED:\n case State.FAILED:\n this.setState(State.FAILED);\n break;\n\n default:\n this.setState(State.READY);\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => \"FAIL\";\n}\n", "import createLotto from \"lotto-draw\";\n\nimport Node from \"../Node\";\nimport Composite from \"./Composite\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A LOTTO node.\n * A winning child is picked on the initial update of this node, based on ticket weighting.\n * The state of this node will match the state of the winning child.\n */\nexport default class Lotto extends Composite {\n /**\n * @param attributes The node attributes.\n * @param tickets The child node tickets.\n * @param children The child nodes.\n */\n constructor(attributes: Attribute[], private tickets: number[], children: Node[]) {\n super(\"lotto\", attributes, children);\n }\n\n /**\n * The child node selected to be the active one.\n */\n private selectedChild: Node | undefined;\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // If this node is in the READY state then we need to pick a winning child node.\n if (this.is(State.READY)) {\n // Create a lotto draw with which to randomly pick a child node to become the active one.\n const lottoDraw = createLotto({\n // Hook up the optional 'random' behaviour tree function option to the one used by 'lotto-draw'.\n random: options.random,\n // Pass in each child node as a participant in the lotto draw with their respective ticket count.\n participants: this.children.map((child, index) => [child, this.tickets[index] || 1])\n });\n\n // Randomly pick a child based on ticket weighting, this will become the active child for this composite node.\n this.selectedChild = lottoDraw.draw() || undefined;\n }\n\n // If something went wrong and we don't have an active child then we should throw an error.\n if (!this.selectedChild) {\n throw new Error(\"failed to update lotto node as it has no active child\");\n }\n\n // If the selected child has never been updated or is running then we will need to update it now.\n if (this.selectedChild.getState() === State.READY || this.selectedChild.getState() === State.RUNNING) {\n this.selectedChild.update(agent, options);\n }\n\n // The state of the lotto node is the state of its selected child.\n this.setState(this.selectedChild.getState());\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => (this.tickets.length ? `LOTTO [${this.tickets.join(\",\")}]` : \"LOTTO\");\n}\n", "import Node from \"../Node\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\n\n/**\n * A composite node that wraps child nodes.\n */\nexport default abstract class Composite extends Node {\n /**\n * @param type The node type.\n * @param attributes The node attributes.\n * @param children The child nodes.\n */\n constructor(type: string, attributes: Attribute[], protected children: Node[]) {\n super(type, attributes, []);\n }\n\n /**\n * Gets whether this node is a leaf node.\n */\n isLeafNode = () => false;\n\n /**\n * Gets the children of this node.\n */\n getChildren = () => this.children;\n\n /**\n * Reset the state of the node.\n */\n reset = () => {\n // Reset the state of this node.\n this.setState(State.READY);\n\n // Reset the state of any child nodes.\n this.getChildren().forEach((child) => child.reset());\n };\n\n /**\n * Abort the running of this node.\n * @param agent The agent.\n */\n abort = (agent: Agent) => {\n // There is nothing to do if this node is not in the running state.\n if (!this.is(State.RUNNING)) {\n return;\n }\n\n // Abort any child nodes.\n this.getChildren().forEach((child) => child.abort(agent));\n\n // Reset the state of this node.\n this.reset();\n\n this.getAttribute(\"exit\")?.callAgentFunction(agent, false, true);\n };\n}\n", "import Composite from \"./Composite\";\nimport Node from \"../Node\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A SELECTOR node.\n * The child nodes are executed in sequence until one succeeds or all fail.\n */\nexport default class Selector extends Composite {\n /**\n * @param attributes The node attributes.\n * @param children The child nodes.\n */\n constructor(attributes: Attribute[], protected children: Node[]) {\n super(\"selector\", attributes, children);\n }\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // Iterate over all of the children of this node.\n for (const child of this.children) {\n // If the child has never been updated or is running then we will need to update it now.\n if (child.getState() === State.READY || child.getState() === State.RUNNING) {\n // Update the child of this node.\n child.update(agent, options);\n }\n\n // If the current child has a state of 'SUCCEEDED' then this node is also a 'SUCCEEDED' node.\n if (child.getState() === State.SUCCEEDED) {\n // This node is a 'SUCCEEDED' node.\n this.setState(State.SUCCEEDED);\n\n // There is no need to check the rest of the selector nodes.\n return;\n }\n\n // If the current child has a state of 'FAILED' then we should move on to the next child.\n if (child.getState() === State.FAILED) {\n // Find out if the current child is the last one in the selector.\n // If it is then this sequence node has also failed.\n if (this.children.indexOf(child) === this.children.length - 1) {\n // This node is a 'FAILED' node.\n this.setState(State.FAILED);\n\n // There is no need to check the rest of the selector as we have completed it.\n return;\n } else {\n // The child node failed, try the next one.\n continue;\n }\n }\n\n // The node should be in the 'RUNNING' state.\n if (child.getState() === State.RUNNING) {\n // This node is a 'RUNNING' node.\n this.setState(State.RUNNING);\n\n // There is no need to check the rest of the selector as the current child is still running.\n return;\n }\n\n // The child node was not in an expected state.\n throw new Error(\"child node was not in an expected state.\");\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => \"SELECTOR\";\n}\n", "import Composite from \"./Composite\";\nimport Node from \"../Node\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A SEQUENCE node.\n * The child nodes are executed in sequence until one fails or all succeed.\n */\nexport default class Sequence extends Composite {\n /**\n * @param attributes The node attributes.\n * @param children The child nodes.\n */\n constructor(attributes: Attribute[], protected children: Node[]) {\n super(\"sequence\", attributes, children);\n }\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // Iterate over all of the children of this node.\n for (const child of this.children) {\n // If the child has never been updated or is running then we will need to update it now.\n if (child.getState() === State.READY || child.getState() === State.RUNNING) {\n // Update the child of this node.\n child.update(agent, options);\n }\n\n // If the current child has a state of 'SUCCEEDED' then we should move on to the next child.\n if (child.getState() === State.SUCCEEDED) {\n // Find out if the current child is the last one in the sequence.\n // If it is then this sequence node has also succeeded.\n if (this.children.indexOf(child) === this.children.length - 1) {\n // This node is a 'SUCCEEDED' node.\n this.setState(State.SUCCEEDED);\n\n // There is no need to check the rest of the sequence as we have completed it.\n return;\n } else {\n // The child node succeeded, but we have not finished the sequence yet.\n continue;\n }\n }\n\n // If the current child has a state of 'FAILED' then this node is also a 'FAILED' node.\n if (child.getState() === State.FAILED) {\n // This node is a 'FAILED' node.\n this.setState(State.FAILED);\n\n // There is no need to check the rest of the sequence.\n return;\n }\n\n // The node should be in the 'RUNNING' state.\n if (child.getState() === State.RUNNING) {\n // This node is a 'RUNNING' node.\n this.setState(State.RUNNING);\n\n // There is no need to check the rest of the sequence as the current child is still running.\n return;\n }\n\n // The child node was not in an expected state.\n throw new Error(\"child node was not in an expected state.\");\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => \"SEQUENCE\";\n}\n", "import Composite from \"./Composite\";\nimport State from \"../../State\";\nimport Node from \"../Node\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A PARALLEL node.\n * The child nodes are executed concurrently until one fails or all succeed.\n */\nexport default class Parallel extends Composite {\n /**\n * @param attributes The node attributes.\n * @param children The child nodes.\n */\n constructor(attributes: Attribute[], children: Node[]) {\n super(\"parallel\", attributes, children);\n }\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // Keep a count of the number of succeeded child nodes.\n let succeededCount = 0;\n\n let hasChildFailed = false;\n\n // Iterate over all of the children of this node.\n for (const child of this.children) {\n // If the child has never been updated or is running then we will need to update it now.\n if (child.getState() === State.READY || child.getState() === State.RUNNING) {\n // Update the child of this node.\n child.update(agent, options);\n }\n\n // If the current child has a state of 'SUCCEEDED' then we should move on to the next child.\n if (child.getState() === State.SUCCEEDED) {\n // The child node has succeeded, keep track of this to determine if all children have.\n succeededCount++;\n\n // The child node succeeded, but we have not finished checking every child node yet.\n continue;\n }\n\n // If the current child has a state of 'FAILED' then this node is also a 'FAILED' node.\n if (child.getState() === State.FAILED) {\n hasChildFailed = true;\n\n // There is no need to check the rest of the children.\n break;\n }\n\n // The node should be in the 'RUNNING' state.\n if (child.getState() !== State.RUNNING) {\n // The child node was not in an expected state.\n throw new Error(\"child node was not in an expected state.\");\n }\n }\n\n if (hasChildFailed) {\n // This node is a 'FAILED' node.\n this.setState(State.FAILED);\n\n // Abort every running child.\n for (const child of this.children) {\n if (child.getState() === State.RUNNING) {\n child.abort(agent);\n }\n }\n } else {\n // If all children have succeeded then this node has also succeeded, otherwise it is still running.\n this.setState(succeededCount === this.children.length ? State.SUCCEEDED : State.RUNNING);\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => \"PARALLEL\";\n}\n", "import { AnyArgument } from \"../RootAstNodesBuilder\";\nimport Guard from \"./guards/Guard\";\n\nexport type AttributeDetails = {\n /** The attribute type. */\n type: string;\n\n /** The attribute arguments. */\n args: AnyArgument[];\n};\n\n/**\n * A base node attribute.\n */\nexport default abstract class Attribute {\n /**\n * @param type The node attribute type.\n * @param args The array of attribute argument definitions.\n */\n constructor(protected type: string, protected args: AnyArgument[]) {}\n\n /**\n * Gets the type of the attribute.\n */\n getType = () => this.type;\n\n /**\n * Gets the array of attribute argument definitions.\n */\n getArguments = () => this.args;\n\n /**\n * Gets the attribute details.\n */\n abstract getDetails(): TAttributeDetails;\n\n /**\n * Gets whether this attribute is a guard.\n */\n abstract isGuard: () => this is Guard;\n}\n", "import { Agent } from \"../../Agent\";\nimport { AnyArgument } from \"../../RootAstNodesBuilder\";\nimport Attribute, { AttributeDetails } from \"../Attribute\";\n\nexport type GuardAttributeDetails = {\n /** The name of the condition function that determines whether the guard is satisfied. */\n condition: string;\n} & AttributeDetails;\n\n/**\n * A base node guard attribute.\n */\nexport default abstract class Guard extends Attribute {\n /**\n * @param type The node attribute type.\n * @param args The array of decorator argument definitions.\n * @param condition The name of the condition function that determines whether the guard is satisfied.\n */\n constructor(type: string, args: AnyArgument[], private condition: string) {\n super(type, args);\n }\n\n /**\n * Gets the name of the condition function that determines whether the guard is satisfied.\n */\n getCondition = () => this.condition;\n\n /**\n * Gets whether this attribute is a guard.\n */\n isGuard = () => true;\n\n /**\n * Gets the attribute details.\n */\n getDetails(): GuardAttributeDetails {\n return {\n type: this.getType(),\n args: this.getArguments(),\n condition: this.getCondition()\n };\n }\n\n /**\n * Gets whether the guard is satisfied.\n * @param agent The agent.\n * @returns Whether the guard is satisfied.\n */\n abstract isSatisfied(agent: Agent): boolean;\n}\n", "import Guard from \"./Guard\";\nimport Lookup from \"../../Lookup\";\nimport { Agent } from \"../../Agent\";\nimport { AnyArgument } from \"../../RootAstNodesBuilder\";\n\n/**\n * A WHILE guard which is satisfied as long as the given condition remains true.\n */\nexport default class While extends Guard {\n /**\n * @param condition The name of the condition function that determines whether the guard is satisfied.\n * @param args The array of decorator argument definitions.\n */\n constructor(condition: string, args: AnyArgument[]) {\n super(\"while\", args, condition);\n }\n\n /**\n * Gets whether the guard is satisfied.\n * @param agent The agent.\n * @returns Whether the guard is satisfied.\n */\n isSatisfied = (agent: Agent) => {\n // Attempt to get the invoker for the condition function.\n const conditionFuncInvoker = Lookup.getFuncInvoker(agent, this.getCondition());\n\n // The condition function should be defined.\n if (conditionFuncInvoker === null) {\n throw new Error(\n `cannot evaluate node guard as the condition '${this.getCondition()}' function is not defined on the agent and has not been registered`\n );\n }\n\n // Call the condition function to determine whether this guard is satisfied.\n return !!conditionFuncInvoker(this.args);\n };\n}\n", "import Guard from \"./Guard\";\nimport Lookup from \"../../Lookup\";\nimport { Agent } from \"../../Agent\";\nimport { AnyArgument } from \"../../RootAstNodesBuilder\";\n\n/**\n * An UNTIL guard which is satisfied as long as the given condition remains false.\n */\nexport default class Until extends Guard {\n /**\n * @param condition The name of the condition function that determines whether the guard is satisfied.\n * @param args The array of decorator argument definitions.\n */\n constructor(condition: string, args: AnyArgument[]) {\n super(\"until\", args, condition);\n }\n\n /**\n * Gets whether the guard is satisfied.\n * @param agent The agent.\n * @returns Whether the guard is satisfied.\n */\n isSatisfied = (agent: Agent) => {\n // Attempt to get the invoker for the condition function.\n const conditionFuncInvoker = Lookup.getFuncInvoker(agent, this.getCondition());\n\n // The condition function should be defined.\n if (conditionFuncInvoker === null) {\n throw new Error(\n `cannot evaluate node guard as the condition '${this.getCondition()}' function is not defined on the agent and has not been registered`\n );\n }\n\n // Call the condition function to determine whether this guard is satisfied.\n return !!!conditionFuncInvoker(this.args);\n };\n}\n", "import { Agent } from \"../../Agent\";\nimport { AnyArgument } from \"../../RootAstNodesBuilder\";\nimport Attribute, { AttributeDetails } from \"../Attribute\";\n\nexport type CallbackAttributeDetails = {\n /** The name of the agent function that is called. */\n functionName: string;\n} & AttributeDetails;\n\n/**\n * A base node callback attribute.\n */\nexport default abstract class Callback extends Attribute {\n /**\n * @param type The node attribute type.\n * @param args The array of decorator argument definitions.\n * @param functionName The name of the agent function to call.\n */\n constructor(type: string, args: AnyArgument[], private functionName: string) {\n super(type, args);\n }\n\n /**\n * Gets the name of the agent function to call.\n */\n getFunctionName = () => this.functionName;\n\n /**\n * Gets whether this attribute is a guard.\n */\n isGuard = () => false;\n\n /**\n * Gets the attribute details.\n */\n getDetails(): CallbackAttributeDetails {\n return {\n type: this.getType(),\n args: this.getArguments(),\n functionName: this.getFunctionName()\n };\n }\n\n /**\n * Attempt to call the agent function that this callback refers to.\n * @param agent The agent.\n */\n abstract callAgentFunction: (agent: Agent, isSuccess: boolean, isAborted: boolean) => void;\n}\n", "import Callback from \"./Callback\";\nimport Lookup from \"../../Lookup\";\nimport { Agent } from \"../../Agent\";\nimport { AnyArgument } from \"../../RootAstNodesBuilder\";\n\n/**\n * An ENTRY callback which defines an agent function to call when the associated node is updated and moves out of running state.\n */\nexport default class Entry extends Callback {\n /**\n * @param functionName The name of the agent function to call.\n * @param args The array of callback argument definitions.\n */\n constructor(functionName: string, args: AnyArgument[]) {\n super(\"entry\", args, functionName);\n }\n\n /**\n * Attempt to call the agent function that this callback refers to.\n * @param agent The agent.\n */\n callAgentFunction = (agent: Agent) => {\n // Attempt to get the invoker for the callback function.\n const callbackFuncInvoker = Lookup.getFuncInvoker(agent, this.getFunctionName());\n\n // The callback function should be defined.\n if (callbackFuncInvoker === null) {\n throw new Error(\n `cannot call entry function '${this.getFunctionName()}' as is not defined on the agent and has not been registered`\n );\n }\n\n // Call the callback function.\n callbackFuncInvoker(this.args);\n };\n}\n", "import Callback from \"./Callback\";\nimport Lookup, { AnyExitArgument } from \"../../Lookup\";\nimport { Agent } from \"../../Agent\";\nimport { AnyArgument } from \"../../RootAstNodesBuilder\";\n\n/**\n * An EXIT callback which defines an agent function to call when the associated node is updated and moves to a finished state or is aborted.\n */\nexport default class Exit extends Callback {\n /**\n * @param functionName The name of the agent function to call.\n * @param args The array of callback argument definitions.\n */\n constructor(functionName: string, args: AnyArgument[]) {\n super(\"exit\", args, functionName);\n }\n\n /**\n * Attempt to call the agent function that this callback refers to.\n * @param agent The agent.\n * @param isSuccess Whether the decorated node was left with a success state.\n * @param isAborted Whether the decorated node was aborted.\n */\n callAgentFunction = (agent: Agent, isSuccess: boolean, isAborted: boolean) => {\n // Attempt to get the invoker for the callback function.\n const callbackFuncInvoker = Lookup.getFuncInvoker(agent, this.getFunctionName());\n\n // The callback function should be defined.\n if (callbackFuncInvoker === null) {\n throw new Error(\n `cannot call exit function '${this.getFunctionName()}' as is not defined on the agent and has not been registered`\n );\n }\n\n // Call the callback function\n callbackFuncInvoker([{ value: { succeeded: isSuccess, aborted: isAborted } }, ...this.args]);\n };\n}\n", "import Callback from \"./Callback\";\nimport Lookup from \"../../Lookup\";\nimport { Agent } from \"../../Agent\";\nimport { AnyArgument } from \"../../RootAstNodesBuilder\";\n\n/**\n * A STEP callback which defines an agent function to call when the associated node is updated.\n */\nexport default class Step extends Callback {\n /**\n * @param functionName The name of the agent function to call.\n * @param args The array of callback argument definitions.\n */\n constructor(functionName: string, args: AnyArgument[]) {\n super(\"step\", args, functionName);\n }\n\n /**\n * Attempt to call the agent function that this callback refers to.\n * @param agent The agent.\n */\n callAgentFunction = (agent: Agent) => {\n // Attempt to get the invoker for the callback function.\n const callbackFuncInvoker = Lookup.getFuncInvoker(agent, this.getFunctionName());\n\n // The callback function should be defined.\n if (callbackFuncInvoker === null) {\n throw new Error(\n `cannot call step function '${this.getFunctionName()}' as is not defined on the agent and has not been registered`\n );\n }\n\n // Call the callback function.\n callbackFuncInvoker(this.args);\n };\n}\n", "import Action from \"./nodes/leaf/Action\";\nimport Condition from \"./nodes/leaf/Condition\";\nimport Wait from \"./nodes/leaf/Wait\";\nimport Root from \"./nodes/decorator/Root\";\nimport Repeat from \"./nodes/decorator/Repeat\";\nimport Retry from \"./nodes/decorator/Retry\";\nimport Flip from \"./nodes/decorator/Flip\";\nimport Succeed from \"./nodes/decorator/Succeed\";\nimport Fail from \"./nodes/decorator/Fail\";\nimport Lotto from \"./nodes/composite/Lotto\";\nimport Selector from \"./nodes/composite/Selector\";\nimport Sequence from \"./nodes/composite/Sequence\";\nimport Parallel from \"./nodes/composite/Parallel\";\nimport Node from \"./nodes/Node\";\nimport While from \"./attributes/guards/While\";\nimport Until from \"./attributes/guards/Until\";\nimport Entry from \"./attributes/callbacks/Entry\";\nimport Exit from \"./attributes/callbacks/Exit\";\nimport Step from \"./attributes/callbacks/Step\";\nimport Callback from \"./attributes/callbacks/Callback\";\nimport Guard from \"./attributes/guards/Guard\";\nimport Attribute from \"./attributes/Attribute\";\nimport Composite from \"./nodes/composite/Composite\";\nimport Decorator from \"./nodes/decorator/Decorator\";\nimport Leaf from \"./nodes/leaf/Leaf\";\n\nexport type Argument = {\n value: T;\n type: string; // Used for validation.\n};\ntype NullArgument = Argument & {\n type: \"null\";\n};\ntype BooleanArgument = Argument & {\n type: \"boolean\";\n};\ntype NumberArgument = Argument & {\n type: \"number\";\n isInteger: boolean; // Used for validation.\n};\ntype StringPlaceholderArgument = Argument & {\n type: \"string\";\n};\ntype IdentifierArgument = Argument & {\n type: \"identifier\";\n};\nexport type AnyArgument =\n | NullArgument\n | BooleanArgument\n | NumberArgument\n | StringPlaceholderArgument\n | IdentifierArgument;\n\n/**\n * The node attribute factories.\n */\nconst AttributeFactories: {\n [key: string]: (functionName: string, attributeArguments: AnyArgument[]) => Callback | Guard;\n} = {\n WHILE: (condition: string, attributeArguments: AnyArgument[]) => new While(condition, attributeArguments),\n UNTIL: (condition: string, attributeArguments: AnyArgument[]) => new Until(condition, attributeArguments),\n ENTRY: (functionName: string, attributeArguments: AnyArgument[]) => new Entry(functionName, attributeArguments),\n EXIT: (functionName: string, attributeArguments: AnyArgument[]) => new Exit(functionName, attributeArguments),\n STEP: (functionName: string, attributeArguments: AnyArgument[]) => new Step(functionName, attributeArguments)\n};\n\ntype Validatable = {\n children?: AstNode[];\n validate: (depth: number) => void;\n};\n\ntype NodeInstanceCreator = (\n namedRootNodeProvider: (name: string) => RootAstNode,\n visitedBranches: string[]\n) => T;\n\nexport type AstNode = Validatable & {\n type: string;\n createNodeInstance: NodeInstanceCreator;\n};\n\nexport type LeafAstNode = AstNode & {\n type: \"action\" | \"condition\" | \"wait\";\n attributes: Attribute[];\n};\n\nexport type CompositeAstNode = AstNode & {\n type: \"lotto\" | \"parallel\" | \"selector\" | \"sequence\";\n attributes: Attribute[];\n children: AstNode[];\n};\n\nexport type DecoratorAstNode = AstNode & {\n type: \"fail\" | \"flip\" | \"repeat\" | \"retry\" | \"root\" | \"succeed\";\n attributes: Attribute[];\n children: AstNode[];\n};\n\nexport type BranchAstNode = AstNode & {\n type: \"branch\";\n branchName: \"\" | string;\n};\n\nexport type LottoAstNode = CompositeAstNode & {\n type: \"lotto\";\n tickets: number[];\n};\n\nexport type RootAstNode = DecoratorAstNode & {\n type: \"root\";\n name: null | string;\n};\n\nexport type RepeatAstNode = DecoratorAstNode & {\n type: \"repeat\";\n iterations: number | null;\n iterationsMin: number | null;\n iterationsMax: number | null;\n};\n\nexport type RetryAstNode = DecoratorAstNode & {\n type: \"retry\";\n attempts: number | null;\n attemptsMin: number | null;\n attemptsMax: number | null;\n};\n\nexport type ActionAstNode = LeafAstNode & {\n type: \"action\";\n actionName: string;\n actionArguments: AnyArgument[];\n};\n\nexport type ConditionAstNode = LeafAstNode & {\n type: \"condition\";\n conditionName: string;\n conditionArguments: AnyArgument[];\n};\n\nexport type WaitAstNode = LeafAstNode & {\n type: \"wait\";\n duration: number | null;\n durationMin: number | null;\n durationMax: number | null;\n};\n\nexport type AnyAstNode =\n | BranchAstNode\n | CompositeAstNode\n | LottoAstNode\n | DecoratorAstNode\n | RootAstNode\n | RepeatAstNode\n | RetryAstNode\n | LeafAstNode\n | ActionAstNode\n | ConditionAstNode\n | WaitAstNode;\n\n/**\n * The AST node factories.\n */\nconst ASTNodeFactories = {\n ROOT: (): RootAstNode => ({\n type: \"root\",\n attributes: [],\n name: null,\n children: [],\n validate(depth: number) {\n // A root node cannot be the child of another node.\n if (depth > 1) {\n throw new Error(\"a root node cannot be the child of another node\");\n }\n\n // A root node must have a single child node.\n if (this.children.length !== 1) {\n throw new Error(\"a root node must have a single child\");\n }\n },\n createNodeInstance(namedRootNodeProvider, visitedBranches) {\n return new Root(\n this.attributes,\n this.children![0].createNodeInstance(namedRootNodeProvider, visitedBranches.slice())\n );\n }\n }),\n BRANCH: (): BranchAstNode => ({\n type: \"branch\",\n branchName: \"\",\n validate() {},\n createNodeInstance(namedRootNodeProvider, visitedBranches) {\n // Try to find the root node with a matching branch name.\n const targetRootNode = namedRootNodeProvider(this.branchName);\n\n // If we have already visited this branch then we have a circular dependency.\n if (visitedBranches.indexOf(this.branchName) !== -1) {\n throw new Error(`circular dependency found in branch node references for branch '${this.branchName}'`);\n }\n\n // If we have a target root node, then the node instance we want will be the first and only child of the referenced root node.\n if (targetRootNode) {\n return targetRootNode\n .createNodeInstance(namedRootNodeProvider, visitedBranches.concat(this.branchName))\n .getChildren()[0];\n } else {\n throw new Error(`branch references root node '${this.branchName}' which has not been defined`);\n }\n }\n }),\n SELECTOR: (): CompositeAstNode => ({\n type: \"selector\",\n attributes: [],\n children: [],\n validate() {\n // A selector node must have at least a single node.\n if (this.children.length < 1) {\n throw new Error(\"a selector node must have at least a single child\");\n }\n },\n createNodeInstance(namedRootNodeProvider, visitedBranches) {\n return new Selector(\n this.attributes,\n this.children.map((child) => child.createNodeInstance(namedRootNodeProvider, visitedBranches.slice()))\n );\n }\n }),\n SEQUENCE: (): CompositeAstNode => ({\n type: \"sequence\",\n attributes: [],\n children: [],\n validate() {\n // A sequence node must have at least a single node.\n if (this.children.length < 1) {\n throw new Error(\"a sequence node must have at least a single child\");\n }\n },\n createNodeInstance(namedRootNodeProvider, visitedBranches) {\n return new Sequence(\n this.attributes,\n this.children.map((child) => child.createNodeInstance(namedRootNodeProvider, visitedBranches.slice()))\n );\n }\n }),\n PARALLEL: (): CompositeAstNode => ({\n type: \"parallel\",\n attributes: [],\n children: [],\n validate() {\n // A parallel node must have at least a single node.\n if (this.children.length < 1) {\n throw new Error(\"a parallel node must have at least a single child\");\n }\n },\n createNodeInstance(namedRootNodeProvider, visitedBranches) {\n return new Parallel(\n this.attributes,\n this.children.map((child) => child.createNodeInstance(namedRootNodeProvider, visitedBranches.slice()))\n );\n }\n }),\n LOTTO: (): LottoAstNode => ({\n type: \"lotto\",\n attributes: [],\n children: [],\n tickets: [],\n validate() {\n // A lotto node must have at least a single node.\n if (this.children!.length < 1) {\n throw new Error(\"a lotto node must have at least a single child\");\n }\n },\n createNodeInstance(namedRootNodeProvider, visitedBranches) {\n return new Lotto(\n this.attributes,\n this.tickets!,\n this.children!.map((child) => child.createNodeInstance(namedRootNodeProvider, visitedBranches.slice()))\n );\n }\n }),\n REPEAT: (): RepeatAstNode => ({\n type: \"repeat\",\n attributes: [],\n iterations: null,\n iterationsMin: null,\n iterationsMax: null,\n children: [],\n validate() {\n // A repeat node must have a single node.\n if (this.children!.length !== 1) {\n throw new Error(\"a repeat node must have a single child\");\n }\n\n if (this.iterations !== null) {\n // A repeat node must have a positive number of iterations if defined.\n if (this.iterations < 0) {\n throw new Error(\"a repeat node must have a positive number of iterations if defined\");\n }\n } else if (this.iterationsMin !== null && this.iterationsMax !== null) {\n // A repeat node must have a positive min and max iteration count if they are defined.\n if (this.iterationsMin < 0 || this.iterationsMax < 0) {\n throw new Error(\n \"a repeat node must have a positive minimum and maximum iteration count if defined\"\n );\n }\n\n // A repeat node must not have an minimum iteration count that exceeds the maximum iteration count.\n if (this.iterationsMin > this.iterationsMax) {\n throw new Error(\n \"a repeat node must not have a minimum iteration count that exceeds the maximum iteration count\"\n );\n }\n } else {\n // If we have no explicit iteration count or a minimum and maximum iteration count set then we are dealing with a repeat node that iterates indefinitely.\n }\n },\n createNodeInstance(namedRootNodeProvider, visitedBranches) {\n return new Repeat(\n this.attributes,\n this.iterations,\n this.iterationsMin,\n this.iterationsMax,\n this.children![0].createNodeInstance(namedRootNodeProvider, visitedBranches.slice())\n );\n }\n }),\n RETRY: (): RetryAstNode => ({\n type: \"retry\",\n attributes: [],\n attempts: null,\n attemptsMin: null,\n attemptsMax: null,\n children: [],\n validate() {\n // A retry node must have a single node.\n if (this.children!.length !== 1) {\n throw new Error(\"a retry node must have a single child\");\n }\n\n if (this.attempts !== null) {\n // A retry node must have a positive number of attempts if defined.\n if (this.attempts < 0) {\n throw new Error(\"a retry node must have a positive number of attempts if defined\");\n }\n } else if (this.attemptsMin !== null && this.attemptsMax !== null) {\n // A retry node must have a positive min and max attempts count if they are defined.\n if (this.attemptsMin < 0 || this.attemptsMax < 0) {\n throw new Error(\"a retry node must have a positive minimum and maximum attempt count if defined\");\n }\n\n // A retry node must not have a minimum attempt count that exceeds the maximum attempt count.\n if (this.attemptsMin > this.attemptsMax) {\n throw new Error(\n \"a retry node must not have a minimum attempt count that exceeds the maximum attempt count\"\n );\n }\n } else {\n // If we have no explicit attempt count or a minimum and maximum attempt count set then we are dealing with a retry node that attempts indefinitely.\n }\n },\n createNodeInstance(namedRootNodeProvider, visitedBranches) {\n return new Retry(\n this.attributes,\n this.attempts,\n this.attemptsMin,\n this.attemptsMax,\n this.children![0].createNodeInstance(namedRootNodeProvider, visitedBranches.slice())\n );\n }\n }),\n FLIP: (): DecoratorAstNode => ({\n type: \"flip\",\n attributes: [],\n children: [],\n validate() {\n // A flip node must have a single node.\n if (this.children!.length !== 1) {\n throw new Error(\"a flip node must have a single child\");\n }\n },\n createNodeInstance(namedRootNodeProvider, visitedBranches) {\n return new Flip(\n this.attributes,\n this.children![0].createNodeInstance(namedRootNodeProvider, visitedBranches.slice())\n );\n }\n }),\n SUCCEED: (): DecoratorAstNode => ({\n type: \"succeed\",\n attributes: [],\n children: [],\n validate() {\n // A succeed node must have a single node.\n if (this.children!.length !== 1) {\n throw new Error(\"a succeed node must have a single child\");\n }\n },\n createNodeInstance(namedRootNodeProvider, visitedBranches) {\n return new Succeed(\n this.attributes,\n this.children![0].createNodeInstance(namedRootNodeProvider, visitedBranches.slice())\n );\n }\n }),\n FAIL: (): DecoratorAstNode => ({\n type: \"fail\",\n attributes: [],\n children: [],\n validate() {\n // A fail node must have a single node.\n if (this.children!.length !== 1) {\n throw new Error(\"a fail node must have a single child\");\n }\n },\n createNodeInstance(namedRootNodeProvider, visitedBranches) {\n return new Fail(\n this.attributes,\n this.children![0].createNodeInstance(namedRootNodeProvider, visitedBranches.slice())\n );\n }\n }),\n WAIT: (): WaitAstNode => ({\n type: \"wait\",\n attributes: [],\n duration: null,\n durationMin: null,\n durationMax: null,\n validate() {\n if (this.duration !== null) {\n // If an explict duration was defined then it must be a positive number.\n if (this.duration < 0) {\n throw new Error(\"a wait node must have a positive duration\");\n }\n } else if (this.durationMin !== null && this.durationMax !== null) {\n // A wait node must have a positive min and max duration.\n if (this.durationMin < 0 || this.durationMax < 0) {\n throw new Error(\"a wait node must have a positive minimum and maximum duration\");\n }\n\n // A wait node must not have a minimum duration that exceeds the maximum duration.\n if (this.durationMin > this.durationMax) {\n throw new Error(\"a wait node must not have a minimum duration that exceeds the maximum duration\");\n }\n } else {\n // If we have no explicit duration or duration bounds set then we are dealing with a wait node that waits indefinitely.\n }\n },\n createNodeInstance() {\n return new Wait(this.attributes, this.duration, this.durationMin, this.durationMax);\n }\n }),\n ACTION: (): ActionAstNode => ({\n type: \"action\",\n attributes: [],\n actionName: \"\",\n actionArguments: [],\n validate() {},\n createNodeInstance() {\n return new Action(this.attributes, this.actionName!, this.actionArguments!);\n }\n }),\n CONDITION: (): ConditionAstNode => ({\n type: \"condition\",\n attributes: [],\n conditionName: \"\",\n conditionArguments: [],\n validate() {},\n createNodeInstance() {\n return new Condition(this.attributes, this.conditionName!, this.conditionArguments!);\n }\n })\n};\n\ntype OtherAstNodes = AstNode[];\n\n/**\n * Create an array of root AST nodes based on the given definition.\n * @param definition The definition to parse the AST nodes from.\n * @returns The base definition AST nodes.\n */\nexport default function buildRootASTNodes(definition: string): RootAstNode[] {\n // Swap out any node/attribute argument string literals with a placeholder and get a mapping of placeholders to original values as well as the processed definition.\n const { placeholders, processedDefinition } = substituteStringLiterals(definition);\n\n // Convert the processed definition (with substituted string literals) into an array of raw tokens.\n const tokens = parseTokensFromDefinition(processedDefinition);\n\n // There must be at least 3 tokens for the tree definition to be valid. 'ROOT', '{' and '}'.\n if (tokens.length < 3) {\n throw new Error(\"invalid token count\");\n }\n\n // We should have a matching number of '{' and '}' tokens. If not, then there are scopes that have not been properly closed.\n if (tokens.filter((token) => token === \"{\").length !== tokens.filter((token) => token === \"}\").length) {\n throw new Error(\"scope character mismatch\");\n }\n\n // Create a stack of node children arrays, starting with a definition scope.\n const stack: [RootAstNode[], ...OtherAstNodes[]] = [[]];\n const rootScope = stack[0];\n\n // We should keep processing the raw tokens until we run out of them.\n while (tokens.length) {\n // Grab the next token.\n const token = tokens.shift();\n\n const currentScope = stack[stack.length - 1] as OtherAstNodes;\n\n // How we create the next AST token depends on the current raw token value.\n switch (token!.toUpperCase()) {\n case \"ROOT\": {\n // Create a ROOT AST node.\n const node = ASTNodeFactories.ROOT();\n\n // Push the ROOT node into the current scope.\n rootScope.push(node);\n\n // We may have a root node name defined as an argument.\n if (tokens[0] === \"[\") {\n const rootArguments = getArguments(tokens, placeholders);\n\n // We should have only a single argument that is not an empty string for a root node, which is the root name identifier.\n if (rootArguments.length === 1 && rootArguments[0].type === \"identifier\") {\n // The root name will be the first and only node argument.\n node.name = rootArguments[0].value as string;\n } else {\n throw new Error(\"expected single root name argument\");\n }\n }\n\n // Try to pick any attributes off of the token stack.\n node.attributes = getAttributes(tokens, placeholders);\n\n popAndCheck(tokens, \"{\");\n\n // The new scope is that of the new ROOT nodes children.\n stack.push(node.children!);\n break;\n }\n\n case \"BRANCH\": {\n // Create a BRANCH AST node.\n const node = ASTNodeFactories.BRANCH();\n\n // Push the BRANCH node into the current scope.\n currentScope.push(node);\n\n // We must have arguments defined, as we require a branch name argument.\n if (tokens[0] !== \"[\") {\n throw new Error(\"expected single branch name argument\");\n }\n\n // The branch name will be defined as a node argument.\n const branchArguments = getArguments(tokens, placeholders);\n\n // We should have only a single identifer argument for a branch node, which is the branch name.\n if (branchArguments.length === 1 && branchArguments[0].type === \"identifier\") {\n // The branch name will be the first and only node argument.\n node.branchName = branchArguments[0].value as string;\n } else {\n throw new Error(\"expected single branch name argument\");\n }\n break;\n }\n\n case \"SELECTOR\": {\n // Create a SELECTOR AST node.\n const node = ASTNodeFactories.SELECTOR();\n\n // Push the SELECTOR node into the current scope.\n currentScope.push(node);\n\n // Try to pick any attributes off of the token stack.\n node.attributes = getAttributes(tokens, placeholders);\n\n popAndCheck(tokens, \"{\");\n\n // The new scope is that of the new SELECTOR nodes children.\n stack.push(node.children!);\n break;\n }\n\n case \"SEQUENCE\": {\n // Create a SEQUENCE AST node.\n const node = ASTNodeFactories.SEQUENCE();\n\n // Push the SEQUENCE node into the current scope.\n currentScope.push(node);\n\n // Try to pick any attributes off of the token stack.\n node.attributes = getAttributes(tokens, placeholders);\n\n popAndCheck(tokens, \"{\");\n\n // The new scope is that of the new SEQUENCE nodes children.\n stack.push(node.children!);\n break;\n }\n\n case \"PARALLEL\": {\n // Create a PARALLEL AST node.\n const node = ASTNodeFactories.PARALLEL();\n\n // Push the PARALLEL node into the current scope.\n currentScope.push(node);\n\n // Try to pick any attributes off of the token stack.\n node.attributes = getAttributes(tokens, placeholders);\n\n popAndCheck(tokens, \"{\");\n\n // The new scope is that of the new PARALLEL nodes children.\n stack.push(node.children!);\n break;\n }\n\n case \"LOTTO\": {\n // Create a LOTTO AST node.\n const node = ASTNodeFactories.LOTTO();\n\n // Push the LOTTO node into the current scope.\n currentScope.push(node);\n\n // If the next token is a '[' character then some ticket counts have been defined as arguments.\n if (tokens[0] === \"[\") {\n // Get the ticket count arguments, each argument must be a number.\n node.tickets = getArguments(\n tokens,\n placeholders,\n (arg) => arg.type === \"number\" && !!arg.isInteger,\n \"lotto node ticket counts must be integer values\"\n ).map((argument) => argument.value as number);\n }\n\n // Try to pick any attributes off of the token stack.\n node.attributes = getAttributes(tokens, placeholders);\n\n popAndCheck(tokens, \"{\");\n\n // The new scope is that of the new LOTTO nodes children.\n stack.push(node.children!);\n break;\n }\n\n case \"CONDITION\": {\n // Create a CONDITION AST node.\n const node = ASTNodeFactories.CONDITION();\n\n // Push the CONDITION node into the current scope.\n currentScope.push(node);\n\n // We must have arguments defined, as we require a condition function name argument.\n if (tokens[0] !== \"[\") {\n throw new Error(\"expected condition name identifier argument\");\n }\n\n // Grab the condition node arguments.\n const conditionArguments = getArguments(tokens, placeholders);\n\n // We should have at least a single identifier argument for a condition node, which is the condition function name.\n if (conditionArguments.length && conditionArguments[0].type === \"identifier\") {\n // The condition function name will be the first node argument.\n node.conditionName = conditionArguments.shift()!.value as string;\n } else {\n throw new Error(\"expected condition name identifier argument\");\n }\n\n // Only the first argument should have been an identifier, all following arguments must be string, number, boolean or null.\n conditionArguments\n .filter((arg) => arg.type === \"identifier\")\n .forEach((arg) => {\n throw new Error(\n \"invalid condition node argument value '\" +\n arg.value +\n \"', must be string, number, boolean or null\"\n );\n });\n\n // Any node arguments that follow the condition name identifier will be treated as condition function arguments.\n node.conditionArguments = conditionArguments;\n\n // Try to pick any attributes off of the token stack.\n node.attributes = getAttributes(tokens, placeholders);\n break;\n }\n\n case \"FLIP\": {\n // Create a FLIP AST node.\n const node = ASTNodeFactories.FLIP();\n\n // Push the Flip node into the current scope.\n currentScope.push(node);\n\n // Try to pick any attributes off of the token stack.\n node.attributes = getAttributes(tokens, placeholders);\n\n popAndCheck(tokens, \"{\");\n\n // The new scope is that of the new FLIP nodes children.\n stack.push(node.children!);\n break;\n }\n\n case \"SUCCEED\": {\n // Create a SUCCEED AST node.\n const node = ASTNodeFactories.SUCCEED();\n\n // Push the Succeed node into the current scope.\n currentScope.push(node);\n\n // Try to pick any attributes off of the token stack.\n node.attributes = getAttributes(tokens, placeholders);\n\n popAndCheck(tokens, \"{\");\n\n // The new scope is that of the new Succeed nodes children.\n stack.push(node.children!);\n break;\n }\n\n case \"FAIL\": {\n // Create a FAIL AST node.\n const node = ASTNodeFactories.FAIL();\n\n // Push the Fail node into the current scope.\n currentScope.push(node);\n\n // Try to pick any attributes off of the token stack.\n node.attributes = getAttributes(tokens, placeholders);\n\n popAndCheck(tokens, \"{\");\n\n // The new scope is that of the new Fail nodes children.\n stack.push(node.children!);\n break;\n }\n\n case \"WAIT\": {\n // Create a WAIT AST node.\n const node = ASTNodeFactories.WAIT();\n\n // Push the WAIT node into the current scope.\n currentScope.push(node);\n\n // The arguments of a wait node are optional. We may have:\n // - No node arguments, in which case the wait will be indefinite until it is aborted.\n // - One node argument which will be the explicit duration of the wait.\n // - Two node arguments which define the min and max duration bounds from which a random duration will be picked.\n if (tokens[0] === \"[\") {\n // Get the optional duration and longest duration of the wait.\n const nodeArguments = getArguments(\n tokens,\n placeholders,\n (arg) => arg.type === \"number\" && !!arg.isInteger,\n \"wait node durations must be integer values\"\n ).map((argument) => argument.value);\n\n // We may have:\n // - One node argument which will be the explicit duration of the wait.\n // - Two node arguments which define the min and max duration bounds from which a random duration will be picked.\n // - Too many arguments, which is not valid.\n if (nodeArguments.length === 1) {\n // An explicit duration was defined.\n node.duration = nodeArguments[0] as number;\n } else if (nodeArguments.length === 2) {\n // Min and max duration bounds were defined from which a random duration will be picked.\n node.durationMin = nodeArguments[0] as number;\n node.durationMax = nodeArguments[1] as number;\n } else if (nodeArguments.length > 2) {\n // An incorrect number of durations was defined.\n throw new Error(\"invalid number of wait node duration arguments defined\");\n }\n }\n\n // Try to pick any attributes off of the token stack.\n node.attributes = getAttributes(tokens, placeholders);\n break;\n }\n\n case \"REPEAT\": {\n // Create a REPEAT AST node.\n const node = ASTNodeFactories.REPEAT();\n\n // Push the REPEAT node into the current scope.\n currentScope.push(node);\n\n // The arguments of a repeat node are optional. We may have:\n // - No node arguments, in which case the repeat note will iterate indefinitely.\n // - One node argument which will be the explicit number of iterations to make.\n // - Two node arguments which define the min and max iteration bounds from which a random iteration count will be picked.\n if (tokens[0] === \"[\") {\n // An iteration count has been defined. Get the iteration and potential maximum iteration of the wait.\n const nodeArguments = getArguments(\n tokens,\n placeholders,\n (arg) => arg.type === \"number\" && !!arg.isInteger,\n \"repeat node iteration counts must be integer values\"\n ).map((argument) => argument.value);\n\n // We should have got one or two iteration counts.\n if (nodeArguments.length === 1) {\n // A static iteration count was defined.\n node.iterations = nodeArguments[0] as number;\n } else if (nodeArguments.length === 2) {\n // A minimum and maximum iteration count was defined.\n node.iterationsMin = nodeArguments[0] as number;\n node.iterationsMax = nodeArguments[1] as number;\n } else {\n // An incorrect number of iteration counts was defined.\n throw new Error(\"invalid number of repeat node iteration count arguments defined\");\n }\n }\n\n // Try to pick any attributes off of the token stack.\n node.attributes = getAttributes(tokens, placeholders);\n\n popAndCheck(tokens, \"{\");\n\n // The new scope is that of the new REPEAT nodes children.\n stack.push(node.children!);\n break;\n }\n\n case \"RETRY\": {\n // Create a RETRY AST node.\n const node = ASTNodeFactories.RETRY();\n\n // Push the RETRY node into the current scope.\n currentScope.push(node);\n\n // The arguments of a retry node are optional. We may have:\n // - No node arguments, in which case the retry note will attempt indefinitely.\n // - One node argument which will be the explicit number of attempts to make.\n // - Two node arguments which define the min and max attempt bounds from which a random attempt count will be picked.\n if (tokens[0] === \"[\") {\n // An attempt count has been defined. Get the attempt count and potential maximum attempt count of the wait.\n const nodeArguments = getArguments(\n tokens,\n placeholders,\n (arg) => arg.type === \"number\" && !!arg.isInteger,\n \"retry node attempt counts must be integer values\"\n ).map((argument) => argument.value);\n\n // We should have got one or two attempt counts.\n if (nodeArguments.length === 1) {\n // A static attempt count was defined.\n node.attempts = nodeArguments[0] as number;\n } else if (nodeArguments.length === 2) {\n // A minimum and maximum attempt count was defined.\n node.attemptsMin = nodeArguments[0] as number;\n node.attemptsMax = nodeArguments[1] as number;\n } else {\n // An incorrect number of attempt counts was defined.\n throw new Error(\"invalid number of retry node attempt count arguments defined\");\n }\n }\n\n // Try to pick any attributes off of the token stack.\n node.attributes = getAttributes(tokens, placeholders);\n\n popAndCheck(tokens, \"{\");\n\n // The new scope is that of the new RETRY nodes children.\n stack.push(node.children!);\n break;\n }\n\n case \"ACTION\": {\n // Create a ACTION AST node.\n const node = ASTNodeFactories.ACTION();\n\n // Push the ACTION node into the current scope.\n currentScope.push(node);\n\n // We must have arguments defined, as we require an action name argument.\n if (tokens[0] !== \"[\") {\n throw new Error(\"expected action name identifier argument\");\n }\n\n // The action name will be defined as a node argument.\n const actionArguments = getArguments(tokens, placeholders);\n\n // We should have at least one identifer argument for an action node, which is the action name.\n if (actionArguments.length && actionArguments[0].type === \"identifier\") {\n // The action name will be the first and only node argument.\n node.actionName = actionArguments.shift()!.value as string;\n } else {\n throw new Error(\"expected action name identifier argument\");\n }\n\n // Only the first argument should have been an identifier, all following arguments must be string, number, boolean or null.\n actionArguments\n .filter((arg) => arg.type === \"identifier\")\n .forEach((arg) => {\n throw new Error(\n \"invalid action node argument value '\" +\n arg.value +\n \"', must be string, number, boolean or null\"\n );\n });\n\n // Any node arguments that follow the action name identifier will be treated as action function arguments.\n node.actionArguments = actionArguments;\n\n // Try to pick any attributes off of the token stack.\n node.attributes = getAttributes(tokens, placeholders);\n break;\n }\n\n case \"}\": {\n // The '}' character closes the current scope.\n stack.pop();\n break;\n }\n\n default: {\n throw new Error(`unexpected token '${token}'`);\n }\n }\n }\n\n // A function to recursively validate each of the nodes in the AST.\n const validateASTNode = (node: Validatable, depth: number): void => {\n // Validate the node.\n node.validate(depth);\n\n // Validate each child of the node.\n (node.children || []).forEach((child) => validateASTNode(child, depth + 1));\n };\n\n // Start node validation from the definition root.\n validateASTNode(\n {\n children: stack[0] as RootAstNode[],\n validate(this: { children: RootAstNode[] }) {\n // We must have at least one node defined as the definition scope, which should be a root node.\n if (this.children.length === 0) {\n throw new Error(\"expected root node to have been defined\");\n }\n\n // Each node at the base of the definition scope MUST be a root node.\n for (const definitionLevelNode of this.children) {\n if (definitionLevelNode.type !== \"root\") {\n throw new Error(\"expected root node at base of definition\");\n }\n }\n\n // Exactly one root node must not have a name defined. This will be the main root, others will have to be referenced via branch nodes.\n if (this.children.filter((definitionLevelNode) => definitionLevelNode.name === null).length !== 1) {\n throw new Error(\"expected single unnamed root node at base of definition to act as main root\");\n }\n\n // No two named root nodes can have matching names.\n const rootNodeNames: string[] = [];\n for (const definitionLevelNode of this.children) {\n if (rootNodeNames.indexOf(definitionLevelNode.name!) !== -1) {\n throw new Error(`multiple root nodes found with duplicate name '${definitionLevelNode.name}'`);\n } else {\n rootNodeNames.push(definitionLevelNode.name!);\n }\n }\n }\n },\n 0\n );\n\n // Return the root AST nodes.\n return stack[0];\n}\n\n/**\n * Pop the next raw token off of the stack and throw an error if it wasn't the expected one.\n * @param tokens The array of remaining tokens.\n * @param expected An optional string or array or items, one of which must match the next popped token.\n * @returns The popped token.\n */\nfunction popAndCheck(tokens: string[], expected: string | string[]) {\n // Get and remove the next token.\n const popped = tokens.shift();\n\n // We were expecting another token.\n if (popped === undefined) {\n throw new Error(\"unexpected end of definition\");\n }\n\n // Do we have an expected token/tokens array?\n if (expected !== undefined) {\n // Check whether the popped token matches at least one of our expected items.\n var tokenMatchesExpectation = ([] as string[])\n .concat(expected)\n .some((item) => popped.toUpperCase() === item.toUpperCase());\n\n // Throw an error if the popped token didn't match any of our expected items.\n if (!tokenMatchesExpectation) {\n const expectationString = ([] as string[])\n .concat(expected)\n .map((item) => \"'\" + item + \"'\")\n .join(\" or \");\n\n throw new Error(`unexpected token found. Expected '${expectationString}' but got '${popped}'`);\n }\n }\n\n // Return the popped token.\n return popped;\n}\n\ntype StringPlaceholders = { [key: string]: string };\n\n/**\n * Pull an argument definition list off of the token stack.\n * @param tokens The array of remaining tokens.\n * @param stringArgumentPlaceholders The mapping of string literal node argument placeholders to original values.\n * @param argumentValidator The argument validator function.\n * @param validationFailedMessage The exception message to throw if argument validation fails.\n * @returns The argument definition list.\n */\nfunction getArguments(\n tokens: string[],\n stringArgumentPlaceholders: StringPlaceholders,\n argumentValidator?: (arg: AnyArgument) => boolean,\n validationFailedMessage?: string\n) {\n // Any lists of arguments will always be wrapped in '[]' for node arguments or '()' for attribute arguments.\n // We are looking for a '[' or '(' opener that wraps the argument tokens and the relevant closer.\n const closer = popAndCheck(tokens, [\"[\", \"(\"]) === \"[\" ? \"]\" : \")\";\n\n const argumentListTokens: string[] = [];\n const argumentList: AnyArgument[] = [];\n\n // Grab all tokens between the '[' and ']' or '(' and ')'.\n while (tokens.length && tokens[0] !== closer) {\n // The next token is part of our arguments list.\n argumentListTokens.push(tokens.shift()!);\n }\n\n // Validate the order of the argument tokens. Each token must either be a ',' or a single argument that satisfies the validator.\n argumentListTokens.forEach((token, index) => {\n // Get whether this token should be an actual argument.\n const shouldBeArgumentToken = !(index & 1);\n\n // If the current token should be an actual argument then validate it,otherwise it should be a ',' token.\n if (shouldBeArgumentToken) {\n // Get the argument definition.\n const argumentDefinition = getArgumentDefinition(token!, stringArgumentPlaceholders);\n\n // Try to validate the argument.\n if (argumentValidator && !argumentValidator(argumentDefinition)) {\n throw new Error(validationFailedMessage);\n }\n\n // This is a valid argument!\n argumentList.push(argumentDefinition);\n } else {\n // The current token should be a ',' token.\n if (token !== \",\") {\n throw new Error(`invalid argument list, expected ',' or ']' but got '${token}'`);\n }\n }\n });\n\n // The arguments list should terminate with a ']' or ')' token, depending on the opener.\n popAndCheck(tokens, closer);\n\n // Return the argument list.\n return argumentList;\n}\n\n/**\n * Gets an argument value definition.\n * @param token The argument token.\n * @param stringArgumentPlaceholders The mapping of string literal node argument placeholders to original values.\n * @returns An argument value definition.\n */\nfunction getArgumentDefinition(token: string, stringArgumentPlaceholders: StringPlaceholders): AnyArgument {\n // Check whether the token represents a null value.\n if (token === \"null\") {\n return {\n value: null,\n type: \"null\"\n } as NullArgument;\n }\n\n // Check whether the token represents a boolean value.\n if (token === \"true\" || token === \"false\") {\n return {\n value: token === \"true\",\n type: \"boolean\"\n } as BooleanArgument;\n }\n\n // Check whether the token represents a number value.\n // TODO: Relies on broken isNaN - see MDN.\n // if (!Number.isNaN(token)) {\n if (!isNaN(token as any)) {\n return {\n value: parseFloat(token),\n isInteger: parseFloat(token) === parseInt(token, 10),\n type: \"number\"\n } as NumberArgument;\n }\n\n // Check whether the token is a placeholder (e.g. @@0@@) representing a string literal.\n if (token.match(/^@@\\d+@@$/g)) {\n return {\n value: stringArgumentPlaceholders[token].replace('\\\\\"', '\"'),\n type: \"string\"\n } as StringPlaceholderArgument;\n }\n\n // The only remaining option is that the argument value is an identifier.\n return {\n value: token,\n type: \"identifier\"\n } as IdentifierArgument;\n}\n\n/**\n * Pull any attributes off of the token stack.\n * @param tokens The array of remaining tokens.\n * @param stringArgumentPlaceholders The mapping of string literal node argument placeholders to original values.\n * @returns An array of attributes defined by any directly following tokens.\n */\nfunction getAttributes(tokens: string[], stringArgumentPlaceholders: StringPlaceholders) {\n // Create an array to hold any attributes found.\n const attributes: Attribute[] = [];\n\n // Keep track of names of attribute that we have found on the token stack, as we cannot have duplicates.\n const attributesFound: string[] = [];\n\n // Try to get the attribute factory for the next token.\n let attributeFactory = AttributeFactories[(tokens[0] || \"\").toUpperCase()];\n\n // Pull attribute tokens off of the tokens stack until we have no more.\n while (attributeFactory) {\n // Check to make sure that we have not already created a attribute of this type for this node.\n if (attributesFound.indexOf(tokens[0].toUpperCase()) !== -1) {\n throw new Error(`duplicate attribute '${tokens[0].toUpperCase()}' found for node`);\n }\n\n // Add the current attribute type to our array of found attributes.\n attributesFound.push(tokens.shift()!.toUpperCase());\n\n // Grab any attribute arguments.\n const attributeArguments = getArguments(tokens, stringArgumentPlaceholders);\n\n // The first attribute argument has to be an identifer, this will reference an agent function.\n if (attributeArguments.length === 0 || attributeArguments[0].type !== \"identifier\") {\n throw new Error(\"expected agent function name identifier argument for attribute\");\n }\n\n // Grab the first attribute which is an identifier that will reference an agent function.\n const attributeFunctionName = attributeArguments.shift()! as IdentifierArgument;\n\n // Any remaining attribute arguments must have a type of string, number, boolean or null.\n attributeArguments\n .filter((arg) => arg.type === \"identifier\")\n .forEach((arg) => {\n throw new Error(\n \"invalid attribute argument value '\" + arg.value + \"', must be string, number, boolean or null\"\n );\n });\n\n // Create the attribute and add it to the array of attributes found.\n attributes.push(attributeFactory(attributeFunctionName.value, attributeArguments));\n\n // Try to get the next attribute name token, as there could be multiple.\n attributeFactory = AttributeFactories[(tokens[0] || \"\").toUpperCase()];\n }\n\n return attributes;\n}\n\n/**\n * Swaps out any node/attribute argument string literals with placeholders.\n * @param definition The definition.\n * @returns An object containing a mapping of placeholders to original string values as well as the processed definition string.\n */\nfunction substituteStringLiterals(definition: string): {\n placeholders: { [key: string]: string };\n processedDefinition: string;\n} {\n // Create an object to hold the mapping of placeholders to original string values.\n const placeholders: StringPlaceholders = {};\n\n // Replace any string literals wrapped with double quotes in our definition with placeholders to be processed later.\n const processedDefinition = definition.replace(/\\\"(\\\\.|[^\"\\\\])*\\\"/g, (match) => {\n var strippedMatch = match.substring(1, match.length - 1);\n var placeholder = Object.keys(placeholders).find((key) => placeholders[key] === strippedMatch);\n\n // If we have no existing string literal match then create a new placeholder.\n if (!placeholder) {\n placeholder = `@@${Object.keys(placeholders).length}@@`;\n placeholders[placeholder] = strippedMatch;\n }\n\n return placeholder;\n });\n\n return { placeholders, processedDefinition };\n}\n\n/**\n * Parse the tree definition into an array of raw tokens.\n * @param definition The definition.\n * @returns An array of tokens parsed from the definition.\n */\nfunction parseTokensFromDefinition(definition: string): string[] {\n // Add some space around various important characters so that they can be plucked out easier as individual tokens.\n definition = definition.replace(/\\(/g, \" ( \");\n definition = definition.replace(/\\)/g, \" ) \");\n definition = definition.replace(/\\{/g, \" { \");\n definition = definition.replace(/\\}/g, \" } \");\n definition = definition.replace(/\\]/g, \" ] \");\n definition = definition.replace(/\\[/g, \" [ \");\n definition = definition.replace(/\\,/g, \" , \");\n\n // Split the definition into raw token form and return it.\n return definition.replace(/\\s+/g, \" \").trim().split(\" \");\n}\n", "import GuardPath, { GuardPathPart } from \"./attributes/guards/GuardPath\";\nimport buildRootASTNodes, { AnyArgument, RootAstNode } from \"./RootAstNodesBuilder\";\nimport State, { AnyState } from \"./State\";\nimport Lookup from \"./Lookup\";\nimport Node from \"./nodes/Node\";\nimport Root from \"./nodes/decorator/Root\";\nimport Composite from \"./nodes/composite/Composite\";\nimport Decorator from \"./nodes/decorator/Decorator\";\nimport { Agent, GlobalFunction } from \"./Agent\";\nimport { CallbackAttributeDetails } from \"./attributes/callbacks/Callback\";\nimport { GuardAttributeDetails } from \"./attributes/guards/Guard\";\nimport { BehaviourTreeOptions } from \"./BehaviourTreeOptions\";\nimport { parseMDSLToJSON } from \"./mdsl/MDSLDefinitionParser\";\n\n// Purely for outside inspection of the tree.\nexport type FlattenedTreeNode = {\n id: string;\n type: string;\n caption: string;\n state: AnyState;\n guards: GuardAttributeDetails[];\n callbacks: CallbackAttributeDetails[];\n args: AnyArgument[];\n parentId: string | null;\n};\n\n/**\n * A representation of a behaviour tree.\n */\nexport class BehaviourTree {\n /**\n * The main root tree node.\n */\n public readonly rootNode: Root;\n\n /**\n * Creates a new instance of the BehaviourTree class.\n * @param definition The behaviour tree definition.\n * @param agent The agent instance that this behaviour tree is modelling behaviour for.\n * @param options The behaviour tree options object.\n */\n constructor(definition: string, private agent: Agent, private options: BehaviourTreeOptions = {}) {\n // The tree definition must be defined and a valid string.\n if (typeof definition !== \"string\") {\n throw new Error(\"the tree definition must be a string\");\n }\n\n // The agent must be defined and not null.\n if (typeof agent !== \"object\" || agent === null) {\n throw new Error(\"the agent must be defined and not null\");\n }\n\n // Parse the behaviour tree definition, create the populated tree of behaviour tree nodes, and get the root.\n this.rootNode = BehaviourTree._createRootNode(definition);\n }\n\n /**\n * Gets whether the tree is in the RUNNING state.\n * @returns true if the tree is in the RUNNING state, otherwise false.\n */\n isRunning() {\n return this.rootNode.getState() === State.RUNNING;\n }\n\n /**\n * Gets the current tree state of SUCCEEDED, FAILED, READY or RUNNING.\n * @returns The current tree state.\n */\n getState() {\n return this.rootNode.getState();\n }\n\n /**\n * Step the tree.\n * 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.\n * 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\n * 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.\n *\n * 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.\n */\n step() {\n // If the root node has already been stepped to completion then we need to reset it.\n if (this.rootNode.getState() === State.SUCCEEDED || this.rootNode.getState() === State.FAILED) {\n this.rootNode.reset();\n }\n\n try {\n this.rootNode.update(this.agent, this.options);\n } catch (exception) {\n throw new Error(`error stepping tree: ${(exception as Error).message}`);\n }\n }\n\n /**\n * Resets the tree from the root node outwards to each nested node, giving each a state of READY.\n */\n reset() {\n this.rootNode.reset();\n }\n\n /**\n * Gets the flattened details of every node in the tree.\n * @returns The flattened details of every node in the tree.\n */\n getFlattenedNodeDetails(): FlattenedTreeNode[] {\n // Create an empty flattened array of tree nodes.\n const flattenedTreeNodes: FlattenedTreeNode[] = [];\n\n /**\n * Helper function to process a node instance and push details into the flattened tree nodes array.\n * @param node The current node.\n * @param parentUid The UID of the node parent, or null if the node is the main root node.\n */\n const processNode = (node: Node, parentUid: string | null) => {\n // Get the guard and callback attribute details for this node.\n const guards = node\n .getAttributes()\n .filter((attribute) => attribute.isGuard())\n .map((attribute) => attribute.getDetails()) as GuardAttributeDetails[];\n const callbacks = node\n .getAttributes()\n .filter((attribute) => !attribute.isGuard())\n .map((attribute) => attribute.getDetails()) as CallbackAttributeDetails[];\n\n // Push the current node into the flattened nodes array.\n flattenedTreeNodes.push({\n id: node.getUid(),\n type: node.getType(),\n caption: node.getName(),\n state: node.getState(),\n guards,\n callbacks,\n args: node.getArguments(),\n parentId: parentUid\n });\n\n // Process each of the nodes children if it is not a leaf node.\n if (!node.isLeafNode()) {\n (node as Composite | Decorator)\n .getChildren()\n .forEach((child) => processNode(child, (node as Composite | Decorator).getUid()));\n }\n };\n\n // Convert the nested node structure into a flattened array of node details.\n processNode(this.rootNode, null);\n\n return flattenedTreeNodes;\n }\n\n /**\n * Registers the action/condition/guard/callback function or subtree with the given name.\n * @param name The name of the function or subtree to register.\n * @param value The function or subtree definition to register.\n */\n static register(name: string, value: GlobalFunction | string) {\n if (typeof value === \"function\") {\n // We are going to register a action/condition/guard/callback function.\n Lookup.setFunc(name, value);\n } else if (typeof value === \"string\") {\n // We are going to register a subtree.\n let rootASTNodes: RootAstNode[];\n\n try {\n // Try to create the behaviour tree AST based on the definition provided, this could fail if the definition is invalid.\n rootASTNodes = buildRootASTNodes(value);\n } catch (exception) {\n // There was an issue in trying to parse and build the tree definition.\n throw new Error(`error registering definition: ${(exception as Error).message}`);\n }\n\n // This function should only ever be called with a definition containing a single unnamed root node.\n if (rootASTNodes.length != 1 || rootASTNodes[0].name !== null) {\n throw new Error(\"error registering definition: expected a single unnamed root node\");\n }\n\n Lookup.setSubtree(name, rootASTNodes[0]);\n } else {\n throw new Error(\"unexpected value, expected string definition or function\");\n }\n }\n\n /**\n * Unregisters the registered action/condition/guard/callback function or subtree with the given name.\n * @param name The name of the registered action/condition/guard/callback function or subtree to unregister.\n */\n static unregister(name: string): void {\n Lookup.remove(name);\n }\n\n /**\n * Unregister all registered action/condition/guard/callback functions and subtrees.\n */\n static unregisterAll(): void {\n Lookup.empty();\n }\n\n /**\n * Parses a behaviour tree definition and creates a tree of behaviour tree nodes.\n * @param {string} definition The behaviour tree definition.\n * @returns The root behaviour tree node.\n */\n private static _createRootNode(definition: string): Root {\n // TODO Remove!\n try {\n // parseToJSON(definition);\n } catch (exception) {\n console.log(exception);\n }\n\n try {\n // Try to create the behaviour tree AST based on the definition provided, this could fail if the definition is invalid.\n const rootASTNodes = buildRootASTNodes(definition);\n\n // Create a symbol to use as the main root key in our root node mapping.\n const mainRootNodeKey = Symbol(\"__root__\");\n\n // Create a mapping of root node names to root AST tokens. The main root node will have a key of Symbol(\"__root__\").\n const rootNodeMap: { [key: string | symbol]: RootAstNode } = {};\n for (const rootASTNode of rootASTNodes) {\n rootNodeMap[rootASTNode.name === null ? mainRootNodeKey : rootASTNode.name!] = rootASTNode;\n }\n\n // Convert the AST to our actual tree and get the root node.\n const rootNode: Root = rootNodeMap[mainRootNodeKey].createNodeInstance(\n // Create a provider for named root nodes that are part of our definition or have been registered. Prioritising the former.\n (name: string): RootAstNode => (rootNodeMap[name] ? rootNodeMap[name] : Lookup.getSubtree(name)),\n []\n );\n\n // Set a guard path on every leaf of the tree to evaluate as part of its update.\n BehaviourTree._applyLeafNodeGuardPaths(rootNode);\n\n // Return the root node.\n return rootNode;\n } catch (exception) {\n // There was an issue in trying to parse and build the tree definition.\n throw new Error(`error parsing tree: ${(exception as Error).message}`);\n }\n }\n\n /**\n * Applies a guard path to every leaf of the tree to evaluate as part of each update.\n * @param rootNode The main root tree node.\n */\n private static _applyLeafNodeGuardPaths(rootNode: Root) {\n const nodePaths: Node[][] = [];\n\n const findLeafNodes = (path: Node[], node: Node) => {\n // Add the current node to the path.\n path = path.concat(node);\n\n // Check whether the current node is a leaf node.\n if (node.isLeafNode()) {\n nodePaths.push(path);\n } else {\n (node as Composite | Decorator).getChildren().forEach((child) => findLeafNodes(path, child));\n }\n };\n\n // Find all leaf node paths, starting from the root.\n findLeafNodes([], rootNode);\n\n nodePaths.forEach((path) => {\n // Each node in the current path will have to be assigned a guard path, working from the root outwards.\n for (let depth = 0; depth < path.length; depth++) {\n // Get the node in the path at the current depth.\n const currentNode = path[depth];\n\n // The node may already have been assigned a guard path, if so just skip it.\n if (currentNode.hasGuardPath()) {\n continue;\n }\n\n // Create the guard path for the current node.\n const guardPath = new GuardPath(\n path\n .slice(0, depth + 1)\n .map((node) => ({ node, guards: node.getGuardAttributes() }))\n .filter((details) => details.guards.length > 0)\n );\n\n // Assign the guard path to the current node.\n currentNode.setGuardPath(guardPath);\n }\n });\n }\n}\n", "import {\n CompositeNodeDefinition,\n DecoratorNodeDefinition,\n NodeDefinition,\n RootNodeDefinition\n} from \"../BehaviourTreeDefinition\";\n\n/**\n * A type defining an object that holds a reference to substitued string literals parsed from the definition.\n */\nexport type StringLiteralPlaceholders = { [key: string]: string };\n\n/**\n * A type guard function that returns true if the specified node satisfies the RootNodeDefinition type.\n * @param node The node.\n * @returns A value of true if the specified node satisfies the RootNodeDefinition type.\n */\nexport function isRootNode(node: NodeDefinition): node is RootNodeDefinition {\n return node.type === \"root\";\n}\n\n/**\n * A type guard function that returns true if the specified node satisfies the NodeDefinition type.\n * @param node The node.\n * @returns A value of true if the specified node satisfies the NodeDefinition type.\n */\nexport function isLeafNode(node: NodeDefinition): node is NodeDefinition {\n return [\"branch\", \"action\", \"condition\", \"wait\"].includes(node.type);\n}\n\n/**\n * A type guard function that returns true if the specified node satisfies the DecoratorNodeDefinition type.\n * @param node The node.\n * @returns A value of true if the specified node satisfies the DecoratorNodeDefinition type.\n */\nexport function isDecoratorNode(node: NodeDefinition): node is DecoratorNodeDefinition {\n return [\"root\", \"repeat\", \"retry\", \"flip\", \"succeed\", \"fail\"].includes(node.type);\n}\n\n/**\n * A type guard function that returns true if the specified node satisfies the CompositeNodeDefinition type.\n * @param node The node.\n * @returns A value of true if the specified node satisfies the CompositeNodeDefinition type.\n */\nexport function isCompositeNode(node: NodeDefinition): node is CompositeNodeDefinition {\n return [\"sequence\", \"selector\", \"lotto\", \"parallel\"].includes(node.type);\n}\n\n/**\n * Pop the next raw token from the specified array of tokens and throw an error if it wasn't the expected one.\n * @param tokens The array of tokens.\n * @param expected An optional string or array or items, one of which must match the next popped token.\n * @returns The popped token.\n */\nexport function popAndCheck(tokens: string[], expected?: string | string[]): string {\n // Get and remove the next token.\n const popped = tokens.shift();\n\n // We were expecting another token but there aren't any.\n if (popped === undefined) {\n throw new Error(\"unexpected end of definition\");\n }\n\n // Do we have an expected token/tokens array?\n if (expected != undefined) {\n // Get an array of expected values, if the popped token matches any then we are all good.\n const expectedValues = typeof expected === \"string\" ? [expected] : expected;\n\n // Check whether the popped token matches at least one of our expected items.\n var tokenMatchesExpectation = expectedValues.some((item) => popped.toUpperCase() === item.toUpperCase());\n\n // Throw an error if the popped token didn't match any of our expected items.\n if (!tokenMatchesExpectation) {\n const expectationString = expectedValues.map((item) => \"'\" + item + \"'\").join(\" or \");\n throw new Error(\"unexpected token found. Expected \" + expectationString + \" but got '\" + popped + \"'\");\n }\n }\n\n // Return the popped token.\n return popped;\n}\n\n/**\n * Swaps out any node/attribute argument string literals with placeholders.\n * @param definition The definition.\n * @returns An object containing a mapping of placeholders to original string values as well as the processed definition string.\n */\nexport function substituteStringLiterals(definition: string): {\n placeholders: StringLiteralPlaceholders;\n processedDefinition: string;\n} {\n // Create an object to hold the mapping of placeholders to original string values.\n const placeholders: StringLiteralPlaceholders = {};\n\n // Replace any string literals wrapped with double quotes in our definition with placeholders to be processed later.\n const processedDefinition = definition.replace(/\\\"(\\\\.|[^\"\\\\])*\\\"/g, (match) => {\n var strippedMatch = match.substring(1, match.length - 1);\n var placeholder = Object.keys(placeholders).find((key) => placeholders[key] === strippedMatch);\n\n // If we have no existing string literal match then create a new placeholder.\n if (!placeholder) {\n placeholder = `@@${Object.keys(placeholders).length}@@`;\n placeholders[placeholder] = strippedMatch;\n }\n\n return placeholder;\n });\n\n return { placeholders, processedDefinition };\n}\n\n/**\n * Parse the tree definition into an array of raw tokens.\n * @param definition The definition.\n * @returns An array of tokens parsed from the definition.\n */\nexport function parseTokensFromDefinition(definition: string): string[] {\n // Add some space around various important characters so that they can be plucked out easier as individual tokens.\n definition = definition.replace(/\\(/g, \" ( \");\n definition = definition.replace(/\\)/g, \" ) \");\n definition = definition.replace(/\\{/g, \" { \");\n definition = definition.replace(/\\}/g, \" } \");\n definition = definition.replace(/\\]/g, \" ] \");\n definition = definition.replace(/\\[/g, \" [ \");\n definition = definition.replace(/\\,/g, \" , \");\n\n // Split the definition into raw token form and return it.\n return definition.replace(/\\s+/g, \" \").trim().split(\" \");\n}\n", "import { StringLiteralPlaceholders, popAndCheck } from \"./MDSLUtilities\";\n\nexport type Argument = {\n /** The argument value. */\n value: T;\n /** The argument type, used for validation. */\n type: string;\n};\n\nexport type NullArgument = Argument & {\n type: \"null\";\n};\n\nexport type BooleanArgument = Argument & {\n type: \"boolean\";\n};\n\nexport type NumberArgument = Argument & {\n type: \"number\";\n isInteger: boolean; // Used for validation.\n};\n\nexport type StringPlaceholderArgument = Argument & {\n type: \"string\";\n};\n\nexport type IdentifierArgument = Argument & {\n type: \"identifier\";\n};\n\nexport type AnyArgument =\n | NullArgument\n | BooleanArgument\n | NumberArgument\n | StringPlaceholderArgument\n | IdentifierArgument;\n\n/**\n * Parse an array of argument definitions from the specified tokens array.\n * @param tokens The array tokens to parse the argument definitions from.\n * @param stringArgumentPlaceholders The mapping of string literal node argument placeholders to original values.\n * @param argumentValidator The argument validator function.\n * @param validationFailedMessage The exception message to throw if argument validation fails.\n * @returns An array of argument definitions parsed from the specified tokens array.\n */\nexport function parseArgumentTokens(\n tokens: string[],\n stringArgumentPlaceholders: StringLiteralPlaceholders\n): AnyArgument[] {\n const argumentList: AnyArgument[] = [];\n\n // If the next token is not a '[' or '(' then we have no arguments to parse.\n if (![\"[\", \"(\"].includes(tokens[0])) {\n return argumentList;\n }\n\n // Any lists of arguments will always be wrapped in '[]' for node arguments or '()' for attribute arguments.\n // We are looking for a '[' or '(' opener that wraps the argument tokens and the relevant closer.\n const closingToken = popAndCheck(tokens, [\"[\", \"(\"]) === \"[\" ? \"]\" : \")\";\n\n const argumentListTokens: string[] = [];\n\n // Grab all tokens between the '[' and ']' or '(' and ')'.\n while (tokens.length && tokens[0] !== closingToken) {\n // The next token is part of our arguments list.\n argumentListTokens.push(tokens.shift()!);\n }\n\n // Validate the order of the argument tokens. Each token must either be a ',' or a single argument that satisfies the validator.\n argumentListTokens.forEach((token, index) => {\n // Get whether this token should be an actual argument.\n const shouldBeArgumentToken = !(index & 1);\n\n // If the current token should be an actual argument then validate it, otherwise it should be a ',' token.\n if (shouldBeArgumentToken) {\n // Get the argument definition.\n const argumentDefinition = getArgumentDefinition(token, stringArgumentPlaceholders);\n\n // This is a valid argument!\n argumentList.push(argumentDefinition);\n } else {\n // The current token should be a ',' token.\n if (token !== \",\") {\n throw new Error(`invalid argument list, expected ',' or ']' but got '${token}'`);\n }\n }\n });\n\n // The arguments list should terminate with a ']' or ')' token, depending on the opener.\n popAndCheck(tokens, closingToken);\n\n // Return the arguments.\n return argumentList;\n}\n\n/**\n * Gets an argument value definition.\n * @param token The argument token.\n * @param stringArgumentPlaceholders The mapping of string literal node argument placeholders to original values.\n * @returns An argument value definition.\n */\nfunction getArgumentDefinition(token: string, stringArgumentPlaceholders: StringLiteralPlaceholders): AnyArgument {\n // Check whether the token represents a null value.\n if (token === \"null\") {\n return {\n value: null,\n type: \"null\"\n } as NullArgument;\n }\n\n // Check whether the token represents a boolean value.\n if (token === \"true\" || token === \"false\") {\n return {\n value: token === \"true\",\n type: \"boolean\"\n } as BooleanArgument;\n }\n\n // Check whether the token represents a number value.\n // TODO: Relies on broken isNaN - see MDN.\n // if (!Number.isNaN(token)) {\n if (!isNaN(token as any)) {\n return {\n value: parseFloat(token),\n isInteger: parseFloat(token) === parseInt(token, 10),\n type: \"number\"\n } as NumberArgument;\n }\n\n // Check whether the token is a placeholder (e.g. @@0@@) representing a string literal.\n if (token.match(/^@@\\d+@@$/g)) {\n return {\n value: stringArgumentPlaceholders[token].replace('\\\\\"', '\"'),\n type: \"string\"\n } as StringPlaceholderArgument;\n }\n\n // The only remaining option is that the argument value is an identifier.\n return {\n value: token,\n type: \"identifier\"\n } as IdentifierArgument;\n}\n", "import { NodeAttributeDefinition } from \"../BehaviourTreeDefinition\";\nimport { parseArgumentTokens } from \"./MDSLNodeArgumentParser\";\nimport { StringLiteralPlaceholders } from \"./MDSLUtilities\";\n\n/**\n * A type defining the attribute definitions of a node.\n */\ntype NodeAttributes = {\n while?: NodeAttributeDefinition;\n until?: NodeAttributeDefinition;\n entry?: NodeAttributeDefinition;\n exit?: NodeAttributeDefinition;\n step?: NodeAttributeDefinition;\n};\n\n/**\n * Parse any node attribute definitions from the specified tokens array.\n * @param tokens The array of remaining tokens.\n * @param stringArgumentPlaceholders The mapping of string literal node argument placeholders to original values.\n * @returns An object of attribute definitions defined by any directly following tokens.\n */\nexport function parseAttributeTokens(\n tokens: string[],\n stringArgumentPlaceholders: StringLiteralPlaceholders\n): NodeAttributes {\n const nodeAttributeNames: (keyof NodeAttributes)[] = [\"while\", \"until\", \"entry\", \"exit\", \"step\"];\n\n // Create an object to hold any attributes found.\n const attributes: NodeAttributes = {};\n\n // Try to get the name of the attribute for the next token.\n let nextAttributeName = tokens[0]?.toLowerCase() as keyof NodeAttributes;\n\n // Pull attribute tokens as well as their arguments off of the tokens stack until we have no more.\n while (nodeAttributeNames.includes(nextAttributeName)) {\n // Check to make sure that we have not already created an attribute definition of this type.\n if (attributes[nextAttributeName]) {\n throw new Error(`duplicate attribute '${tokens[0].toUpperCase()}' found for node`);\n }\n\n // Remove the attribute name token from the array of tokens.\n tokens.shift();\n\n // Grab the attribute arguments, assuming the first to be an identifier.\n const [attributeCallIdentifier, ...attributeArguments] = parseArgumentTokens(\n tokens,\n stringArgumentPlaceholders\n );\n\n // The first attribute argument has to be an identifer, this will reference an agent function.\n if (attributeCallIdentifier?.type !== \"identifier\") {\n throw new Error(\"expected agent function name identifier argument for attribute\");\n }\n\n // Any attribute arguments (other than the expected call identifier) must have a type of string, number, boolean or null.\n attributeArguments\n .filter((arg) => arg.type === \"identifier\")\n .forEach((arg) => {\n throw new Error(\n `invalid attribute argument value '${arg.value}', must be string, number, boolean or null`\n );\n });\n\n // Create the attribute definition and add it to the object of attribute definitions found.\n attributes[nextAttributeName] = {\n call: attributeCallIdentifier.value,\n args: attributeArguments.map(({ value }) => value)\n };\n\n // Try to get the next attribute name token, as there could be multiple.\n nextAttributeName = tokens[0]?.toLowerCase() as keyof NodeAttributes;\n }\n\n return attributes;\n}\n", "import {\n ActionNodeDefinition,\n AnyChildNode,\n AnyNode,\n BranchNodeDefinition,\n ConditionNodeDefinition,\n FailNodeDefinition,\n FlipNodeDefinition,\n LottoNodeDefinition,\n ParallelNodeDefinition,\n RepeatNodeDefinition,\n RetryNodeDefinition,\n RootNodeDefinition,\n SelectorNodeDefinition,\n SequenceNodeDefinition,\n SucceedNodeDefinition,\n WaitNodeDefinition\n} from \"../BehaviourTreeDefinition\";\nimport { parseArgumentTokens } from \"./MDSLNodeArgumentParser\";\nimport { parseAttributeTokens } from \"./MDSLNodeAttributeParser\";\nimport {\n StringLiteralPlaceholders,\n isCompositeNode,\n isDecoratorNode,\n isLeafNode,\n isRootNode,\n parseTokensFromDefinition,\n popAndCheck,\n substituteStringLiterals\n} from \"./MDSLUtilities\";\n\n/**\n * Parse the MDSL tree definition string into an equivalent JSON definition.\n * @param definition The tree definition string as MDSL.\n * @returns The root node JSON definitions.\n */\nexport function parseMDSLToJSON(definition: string): RootNodeDefinition[] {\n // Swap out any node/attribute argument string literals with a placeholder and get a mapping of placeholders to original values as well as the processed definition.\n const { placeholders, processedDefinition } = substituteStringLiterals(definition);\n\n // Parse our definition definition string into an array of raw tokens.\n const tokens = parseTokensFromDefinition(processedDefinition);\n\n return convertTokensToJSONDefinition(tokens, placeholders);\n}\n\n/**\n * Converts the specified tree definition tokens into a JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The root node JSON definitions.\n */\nfunction convertTokensToJSONDefinition(\n tokens: string[],\n stringLiteralPlaceholders: StringLiteralPlaceholders\n): RootNodeDefinition[] {\n // There must be at least 3 tokens for the tree definition to be valid. 'ROOT', '{' and '}'.\n if (tokens.length < 3) {\n throw new Error(\"invalid token count\");\n }\n\n // We should have a matching number of '{' and '}' tokens. If not, then there are scopes that have not been properly closed.\n if (tokens.filter((token) => token === \"{\").length !== tokens.filter((token) => token === \"}\").length) {\n throw new Error(\"scope character mismatch\");\n }\n\n // Create an array of tree stack arrays where root nodes will always be at the botton and the current composite/decorator node at the top.\n // There should be an element in this array for every root node defined and every element should be an array with a root note as the first element.\n // E.g. A definition with two root nodes defined:\n // [\n // [root, lotto, sequence],\n // [root, selector]\n // ]\n const treeStacks: [Partial, ...Partial[]][] = [];\n\n // Create an array of all root node definitions that we create.\n const rootNodes: Partial[] = [];\n\n // A helper function used to push node definitions onto the tree stack.\n const pushNode = (node: AnyNode) => {\n // If the node is a root node then we need to create a new tree stack array with the root node at the root.\n if (isRootNode(node)) {\n // Add the root node definition to our array of all parsed root node definitions.\n rootNodes.push(node);\n\n // Add the root node definition to the root of a new tree stack.\n treeStacks.push([node]);\n\n return;\n }\n\n // All non-root nodes should be pushed after their root nodes so handle cases\n // where we may not have any tree stacks or our top-most tree stack is empty.\n if (!treeStacks.length || !treeStacks[treeStacks.length - 1].length) {\n throw new Error(\"expected root node at base of definition\");\n }\n\n // Get the current tree stack that we are populating.\n const topTreeStack = treeStacks[treeStacks.length - 1];\n\n // Get the top-most node in the current tree stack, this will be a composite/decorator node\n // for which we will populate its children array if composite or setting its child if a decorator.\n const topTreeStackTopNode = topTreeStack[topTreeStack.length - 1] as AnyNode;\n\n // If the top-most node in the current root stack is a composite or decorator\n // node then the current node should be added as a child of the top-most node.\n if (isCompositeNode(topTreeStackTopNode)) {\n topTreeStackTopNode.children = topTreeStackTopNode.children || [];\n topTreeStackTopNode.children.push(node);\n } else if (isDecoratorNode(topTreeStackTopNode)) {\n // If the top node already has a child node set then throw an error as a decorator should only have a single child.\n if (topTreeStackTopNode.child) {\n throw new Error(\"a decorator node must only have a single child node\");\n }\n\n topTreeStackTopNode.child = node;\n }\n\n // If the node we are adding is also a composite or decorator node, then we should push it\n // onto the current tree stack, as subsequent nodes will be added as its child/children.\n if (!isLeafNode(node)) {\n topTreeStack.push(node);\n }\n };\n\n // A helper function used to pop node definitions off of the stack.\n const popNode = () => {\n // Get the current tree stack that we are populating.\n const topTreeStack = treeStacks[treeStacks.length - 1];\n\n // Pop the top-most node in the current tree stack if there is one.\n if (topTreeStack.length) {\n topTreeStack.pop();\n }\n\n // We don't want any empty tree stacks in our stack of tree stacks.\n if (!topTreeStack.length) {\n treeStacks.pop();\n }\n };\n\n // We should keep processing the raw tokens until we run out of them.\n while (tokens.length) {\n // Grab the next token.\n const token = tokens.shift()!;\n\n // How we create the next node depends on the current raw token value.\n switch (token.toUpperCase()) {\n case \"ROOT\": {\n pushNode(createRootNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"SUCCEED\": {\n pushNode(createSucceedNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"FAIL\": {\n pushNode(createFailNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"FLIP\": {\n pushNode(createFlipNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"REPEAT\": {\n pushNode(createRepeatNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"RETRY\": {\n pushNode(createRetryNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"SEQUENCE\": {\n pushNode(createSequenceNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"SELECTOR\": {\n pushNode(createSelectorNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"PARALLEL\": {\n pushNode(createParallelNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"LOTTO\": {\n pushNode(createLottoNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"ACTION\": {\n pushNode(createActionNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"CONDITION\": {\n pushNode(createConditionNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"WAIT\": {\n pushNode(createWaitNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"BRANCH\": {\n pushNode(createBranchNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"}\": {\n // The '}' character closes the current scope and means that we have to pop a node off of the current stack.\n popNode();\n break;\n }\n\n default: {\n throw new Error(`unexpected token: ${token}`);\n }\n }\n }\n\n return rootNodes as RootNodeDefinition[];\n}\n\n/**\n * Creates a root node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The root node JSON definition.\n */\nfunction createRootNode(tokens: string[], stringLiteralPlaceholders: StringLiteralPlaceholders): RootNodeDefinition {\n // Create the root node definition.\n let node = {\n type: \"root\",\n id: undefined\n } as RootNodeDefinition;\n\n // Parse any node arguments, we should only have one if any which will be an identifier argument for the root identifier.\n const nodeArguments = parseArgumentTokens(tokens, stringLiteralPlaceholders);\n\n // Check whether any node arguments were defined.\n if (nodeArguments.length) {\n // We should only have one argument, if any, which will be an identifier argument for the root identifier.\n if (nodeArguments.length === 1 && nodeArguments[0].type === \"identifier\") {\n // The root node identifier will be the first and only node argument value.\n node.id = nodeArguments[0].value as string;\n } else {\n throw new Error(\"expected single root name argument\");\n }\n }\n\n // Grab any node attribute definitions and spread them into the node definition.\n node = { ...node, ...parseAttributeTokens(tokens, stringLiteralPlaceholders) };\n\n // This is a decorator node, so we expect an opening '{'.\n popAndCheck(tokens, \"{\");\n\n // Return the root node definition.\n return node;\n}\n\n/**\n * Creates a succeed node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The succeed node JSON definition.\n */\nfunction createSucceedNode(\n tokens: string[],\n stringLiteralPlaceholders: StringLiteralPlaceholders\n): SucceedNodeDefinition {\n const node = {\n type: \"succeed\",\n ...parseAttributeTokens(tokens, stringLiteralPlaceholders)\n } as SucceedNodeDefinition;\n\n // This is a decorator node, so we expect an opening '{'.\n popAndCheck(tokens, \"{\");\n\n // Return the succeed node definition.\n return node;\n}\n\n/**\n * Creates a fail node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The fail node JSON definition.\n */\nfunction createFailNode(tokens: string[], stringLiteralPlaceholders: StringLiteralPlaceholders): FailNodeDefinition {\n const node = {\n type: \"fail\",\n ...parseAttributeTokens(tokens, stringLiteralPlaceholders)\n } as FailNodeDefinition;\n\n // This is a decorator node, so we expect an opening '{'.\n popAndCheck(tokens, \"{\");\n\n // Return the fail node definition.\n return node;\n}\n\n/**\n * Creates a flip node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The flip node JSON definition.\n */\nfunction createFlipNode(tokens: string[], stringLiteralPlaceholders: StringLiteralPlaceholders): FlipNodeDefinition {\n const node = {\n type: \"flip\",\n ...parseAttributeTokens(tokens, stringLiteralPlaceholders)\n } as FlipNodeDefinition;\n\n // This is a decorator node, so we expect an opening '{'.\n popAndCheck(tokens, \"{\");\n\n // Return the flip node definition.\n return node;\n}\n\n/**\n * Creates a repeat node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The repeat node JSON definition.\n */\nfunction createRepeatNode(\n tokens: string[],\n stringLiteralPlaceholders: StringLiteralPlaceholders\n): RepeatNodeDefinition {\n let node = { type: \"repeat\" } as RepeatNodeDefinition;\n\n // Get the node arguments.\n const nodeArguments = parseArgumentTokens(tokens, stringLiteralPlaceholders);\n\n // The arguments of a repeat node are optional. We may have:\n // - No node arguments, in which case the repeat note will iterate indefinitely.\n // - One node argument which will be the explicit number of iterations to make.\n // - Two node arguments which define the min and max iteration bounds from which a random iteration count will be picked.\n if (nodeArguments.length) {\n // All repeat node arguments MUST be of type number and must be integer.\n nodeArguments\n .filter((arg) => arg.type !== \"number\" || !arg.isInteger)\n .forEach(() => {\n throw new Error(`repeat node iteration counts must be integer values`);\n });\n\n // We should have got one or two iteration counts.\n if (nodeArguments.length === 1) {\n // A static iteration count was defined.\n node.iterations = nodeArguments[0].value as number;\n } else if (nodeArguments.length === 2) {\n // A minimum and maximum iteration count was defined.\n node.iterations = [nodeArguments[0].value as number, nodeArguments[1].value as number];\n } else {\n // An incorrect number of iteration counts was defined.\n throw new Error(\"invalid number of repeat node iteration count arguments defined\");\n }\n }\n\n // Grab any node attribute definitions and spread them into the node definition.\n node = { ...node, ...parseAttributeTokens(tokens, stringLiteralPlaceholders) };\n\n // This is a decorator node, so we expect an opening '{'.\n popAndCheck(tokens, \"{\");\n\n // Return the repeat node definition.\n return node;\n}\n\n/**\n * Creates a retry node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The retry node JSON definition.\n */\nfunction createRetryNode(tokens: string[], stringLiteralPlaceholders: StringLiteralPlaceholders): RetryNodeDefinition {\n let node = { type: \"retry\" } as RetryNodeDefinition;\n\n // Get the node arguments.\n const nodeArguments = parseArgumentTokens(tokens, stringLiteralPlaceholders);\n\n // The arguments of a retry node are optional. We may have:\n // - No node arguments, in which case the retry note will attempt indefinitely.\n // - One node argument which will be the explicit number of attempts to make.\n // - Two node arguments which define the min and max attempt bounds from which a random attempt count will be picked.\n if (nodeArguments.length) {\n // All retry node arguments MUST be of type number and must be integer.\n nodeArguments\n .filter((arg) => arg.type !== \"number\" || !arg.isInteger)\n .forEach(() => {\n throw new Error(`retry node attempt counts must be integer values`);\n });\n\n // We should have got one or two attempt counts.\n if (nodeArguments.length === 1) {\n // A static attempt count was defined.\n node.attempts = nodeArguments[0].value as number;\n } else if (nodeArguments.length === 2) {\n // A minimum and maximum attempt count was defined.\n node.attempts = [nodeArguments[0].value as number, nodeArguments[1].value as number];\n } else {\n // An incorrect number of attempt counts was defined.\n throw new Error(\"invalid number of retry node attempt count arguments defined\");\n }\n }\n\n // Grab any node attribute definitions and spread them into the node definition.\n node = { ...node, ...parseAttributeTokens(tokens, stringLiteralPlaceholders) };\n\n // This is a decorator node, so we expect an opening '{'.\n popAndCheck(tokens, \"{\");\n\n // Return the retry node definition.\n return node;\n}\n\n/**\n * Creates a sequence node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The sequence node JSON definition.\n */\nfunction createSequenceNode(\n tokens: string[],\n stringLiteralPlaceholders: StringLiteralPlaceholders\n): SequenceNodeDefinition {\n const node = {\n type: \"sequence\",\n ...parseAttributeTokens(tokens, stringLiteralPlaceholders)\n } as SequenceNodeDefinition;\n\n // This is a composite node, so we expect an opening '{'.\n popAndCheck(tokens, \"{\");\n\n // Return the sequence node definition.\n return node;\n}\n\n/**\n * Creates a selector node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The selector node JSON definition.\n */\nfunction createSelectorNode(\n tokens: string[],\n stringLiteralPlaceholders: StringLiteralPlaceholders\n): SelectorNodeDefinition {\n const node = {\n type: \"selector\",\n ...parseAttributeTokens(tokens, stringLiteralPlaceholders)\n } as SelectorNodeDefinition;\n\n // This is a composite node, so we expect an opening '{'.\n popAndCheck(tokens, \"{\");\n\n // Return the selector node definition.\n return node;\n}\n\n/**\n * Creates a parallel node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The parallel node JSON definition.\n */\nfunction createParallelNode(\n tokens: string[],\n stringLiteralPlaceholders: StringLiteralPlaceholders\n): ParallelNodeDefinition {\n const node = {\n type: \"parallel\",\n ...parseAttributeTokens(tokens, stringLiteralPlaceholders)\n } as ParallelNodeDefinition;\n\n // This is a composite node, so we expect an opening '{'.\n popAndCheck(tokens, \"{\");\n\n // Return the parallel node definition.\n return node;\n}\n\n/**\n * Creates a lotto node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The lotto node JSON definition.\n */\nfunction createLottoNode(tokens: string[], stringLiteralPlaceholders: StringLiteralPlaceholders): LottoNodeDefinition {\n // If any node arguments have been defined then they must be our weights.\n const nodeArguments = parseArgumentTokens(tokens, stringLiteralPlaceholders);\n\n // All lotto node arguments MUST be of type number and must be integer.\n nodeArguments\n .filter((arg) => arg.type !== \"number\" || !arg.isInteger)\n .forEach(() => {\n throw new Error(`lotto node weight arguments must be integer values`);\n });\n\n const node = {\n type: \"lotto\",\n weights: nodeArguments.map(({ value }) => value),\n ...parseAttributeTokens(tokens, stringLiteralPlaceholders)\n } as LottoNodeDefinition;\n\n // This is a composite node, so we expect an opening '{'.\n popAndCheck(tokens, \"{\");\n\n // Return the lotto node definition.\n return node;\n}\n\n/**\n * Creates an action node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The action node JSON definition.\n */\nfunction createActionNode(\n tokens: string[],\n stringLiteralPlaceholders: StringLiteralPlaceholders\n): ActionNodeDefinition {\n // Parse any node arguments, we should have at least one which will be an identifier argument for the action name\n // and agent function to invoke for the action, all other arguments are to be passed as arguments to that function.\n const [actionNameIdentifier, ...agentFunctionArgs] = parseArgumentTokens(tokens, stringLiteralPlaceholders);\n\n // Our first argument MUST be defined and be an identifier as we require an action name argument.\n if (actionNameIdentifier?.type !== \"identifier\") {\n throw new Error(\"expected action name identifier argument\");\n }\n\n // Only the first argument should have been an identifier, all agent function arguments must be string, number, boolean or null.\n agentFunctionArgs\n .filter((arg) => arg.type === \"identifier\")\n .forEach((arg) => {\n throw new Error(\n `invalid action node argument value '${arg.value}', must be string, number, boolean or null`\n );\n });\n\n // Return the action node definition.\n return {\n type: \"action\",\n call: actionNameIdentifier.value,\n args: agentFunctionArgs.map(({ value }) => value),\n ...parseAttributeTokens(tokens, stringLiteralPlaceholders)\n };\n}\n\n/**\n * Creates a condition node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The condition node JSON definition.\n */\nfunction createConditionNode(\n tokens: string[],\n stringLiteralPlaceholders: StringLiteralPlaceholders\n): ConditionNodeDefinition {\n // Parse any node arguments, we should have at least one which will be an identifier argument for the condition name\n // and agent function to invoke for the condition, all other arguments are to be passed as arguments to that function.\n const [conditionNameIdentifier, ...agentFunctionArgs] = parseArgumentTokens(tokens, stringLiteralPlaceholders);\n\n // Our first argument MUST be defined and be an identifier as we require a condition name argument.\n if (conditionNameIdentifier?.type !== \"identifier\") {\n throw new Error(\"expected condition name identifier argument\");\n }\n\n // Only the first argument should have been an identifier, all agent function arguments must be string, number, boolean or null.\n agentFunctionArgs\n .filter((arg) => arg.type === \"identifier\")\n .forEach((arg) => {\n throw new Error(\n `invalid condition node argument value '${arg.value}', must be string, number, boolean or null`\n );\n });\n\n // Return the condition node definition.\n return {\n type: \"condition\",\n call: conditionNameIdentifier.value,\n args: agentFunctionArgs.map(({ value }) => value),\n ...parseAttributeTokens(tokens, stringLiteralPlaceholders)\n };\n}\n\n/**\n * Creates a wait node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The wait node JSON definition.\n */\nfunction createWaitNode(tokens: string[], stringLiteralPlaceholders: StringLiteralPlaceholders): WaitNodeDefinition {\n let node = { type: \"wait\" } as WaitNodeDefinition;\n\n // Get the node arguments.\n const nodeArguments = parseArgumentTokens(tokens, stringLiteralPlaceholders);\n\n // The arguments of a wait node are optional. We may have:\n // - No node arguments, in which case the wait will be indefinite until it is aborted.\n // - One node argument which will be the explicit duration of the wait.\n // - Two node arguments which define the min and max duration bounds from which a random duration will be picked.\n if (nodeArguments.length) {\n // All wait node arguments MUST be of type number and must be integer.\n nodeArguments\n .filter((arg) => arg.type !== \"number\" || !arg.isInteger)\n .forEach(() => {\n throw new Error(`wait node duration arguments must be integer values`);\n });\n\n // We may have:\n // - One node argument which will be the explicit duration of the wait.\n // - Two node arguments which define the min and max duration bounds from which a random duration will be picked.\n // - Too many arguments, which is not valid.\n if (nodeArguments.length === 1) {\n // An explicit duration was defined.\n node.duration = nodeArguments[0].value as number;\n } else if (nodeArguments.length === 2) {\n // Min and max duration bounds were defined from which a random duration will be picked.\n node.duration = [nodeArguments[0].value as number, nodeArguments[1].value as number];\n } else if (nodeArguments.length > 2) {\n // An incorrect number of duration arguments were defined.\n throw new Error(\"invalid number of wait node duration arguments defined\");\n }\n }\n\n // Return the wait node definition.\n return { ...node, ...parseAttributeTokens(tokens, stringLiteralPlaceholders) };\n}\n\n/**\n * Creates a branch node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The branch node JSON definition.\n */\nfunction createBranchNode(\n tokens: string[],\n stringLiteralPlaceholders: StringLiteralPlaceholders\n): BranchNodeDefinition {\n // Parse any node arguments, we should have one which will be an identifier argument for the root ref.\n const nodeArguments = parseArgumentTokens(tokens, stringLiteralPlaceholders);\n\n // We should have only a single identifer argument for a branch node, which is the root ref.\n if (nodeArguments.length !== 1 || nodeArguments[0].type !== \"identifier\") {\n throw new Error(\"expected single branch name argument\");\n }\n\n // Return the branch node definition.\n return { type: \"branch\", ref: nodeArguments[0].value };\n}\n"], + "mappings": "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", + "names": ["Participant", "Lotto", "createLotto", "State", "createLotto", "popAndCheck", "substituteStringLiterals", "parseTokensFromDefinition", "popAndCheck", "getArgumentDefinition", "substituteStringLiterals", "parseTokensFromDefinition", "popAndCheck"] } diff --git a/dist/dsl/DSLDefinitionParser.d.ts b/dist/dsl/DSLDefinitionParser.d.ts deleted file mode 100644 index 023bdfe..0000000 --- a/dist/dsl/DSLDefinitionParser.d.ts +++ /dev/null @@ -1,163 +0,0 @@ -/** - * A type defining the arguments that can be passed to an agent function. - */ -export type AgentFunctionArguments = (string | number | boolean | null | undefined)[]; -/** - * A guard attribute for a node. - */ -export type GuardAttributeDefinition = { - call: string; - args?: AgentFunctionArguments; -}; -/** - * A callback attribute for a node. - */ -export type CallbackAttributeDefinition = { - call: string; - args?: AgentFunctionArguments; -}; -/** - * A type defining a general node definition. - */ -export type NodeDefinition = { - type: string; - while?: GuardAttributeDefinition; - until?: GuardAttributeDefinition; - entry?: CallbackAttributeDefinition; - exit?: CallbackAttributeDefinition; - step?: CallbackAttributeDefinition; -}; -/** - * A composite node that can contain any number of child nodes. - */ -export type CompositeDefinition = NodeDefinition & { - children: AnyChildNode[]; -}; -/** - * A decorator node, a composite with only a single child node. - */ -export type DecoratorDefinition = NodeDefinition & { - child: AnyChildNode; -}; -/** - * A branch node. - */ -export type BranchDefinition = NodeDefinition & { - type: "branch"; - ref: string; -}; -/** - * An action node. - */ -export type ActionDefinition = NodeDefinition & { - type: "action"; - call: string; - args?: AgentFunctionArguments; -}; -/** - * A condition node. - */ -export type ConditionDefinition = NodeDefinition & { - type: "condition"; - call: string; - args?: AgentFunctionArguments; -}; -/** - * A wait node. - */ -export type WaitDefinition = NodeDefinition & { - type: "wait"; - duration: number | [number, number]; -}; -/** - * A sequence node. - */ -export type SequenceDefinition = CompositeDefinition & { - type: "sequence"; -}; -/** - * A selector node. - */ -export type SelectorDefinition = CompositeDefinition & { - type: "selector"; -}; -/** - * A lotto node. - */ -export type LottoDefinition = CompositeDefinition & { - type: "lotto"; - weights?: number[]; -}; -/** - * A parallel node. - */ -export type ParallelDefinition = CompositeDefinition & { - type: "parallel"; -}; -/** - * A root node. - */ -export type RootDefinition = DecoratorDefinition & { - type: "root"; - id?: string; -}; -/** - * A repeat node. - */ -export type RepeatDefinition = DecoratorDefinition & { - type: "repeat"; - iterations?: number | [number, number]; -}; -/** - * A retry node. - */ -export type RetryDefinition = DecoratorDefinition & { - type: "retry"; - attempts?: number | [number, number]; -}; -/** - * A flip node. - */ -export type FlipDefinition = DecoratorDefinition & { - type: "flip"; -}; -/** - * A succeed node. - */ -export type SucceedDefinition = DecoratorDefinition & { - type: "succeed"; -}; -/** - * A fail node. - */ -export type FailDefinition = DecoratorDefinition & { - type: "fail"; -}; -/** - * A type defining any node type. - */ -export type AnyNode = BranchDefinition | ActionDefinition | ConditionDefinition | WaitDefinition | SequenceDefinition | SelectorDefinition | LottoDefinition | ParallelDefinition | RootDefinition | RepeatDefinition | RetryDefinition | FlipDefinition | SucceedDefinition | FailDefinition; -/** - * A type defining any node type that can be a child of composite parent node. - */ -export type AnyChildNode = Exclude; -/** - * A type defining an object that holds a reference to substitued string literals parsed from the definition. - */ -type StringLiteralPlaceholders = { - [key: string]: string; -}; -/** - * Parse the tree definition string into a JSON definition. - * @param definition The tree definition string. - * @returns The root node JSON definitions. - */ -export declare function parseToJSON(definition: string): RootDefinition[]; -/** - * Converts the specified tree definition tokens into a JSON definition. - * @param tokens The tree definition tokens. - * @param placeholders The substituted string literal placeholders. - * @returns The root node JSON definitions. - */ -export declare function convertTokensToJSONDefinition(tokens: string[], placeholders: StringLiteralPlaceholders, processedDefinition: string): RootDefinition[]; -export {}; diff --git a/dist/dsl/DSLNodeArgumentParser.d.ts b/dist/dsl/DSLNodeArgumentParser.d.ts deleted file mode 100644 index d9a29b1..0000000 --- a/dist/dsl/DSLNodeArgumentParser.d.ts +++ /dev/null @@ -1,36 +0,0 @@ -type Placeholders = { - [key: string]: string; -}; -export type Argument = { - /** The argument value. */ - value: T; - /** The argument type, used for validation. */ - type: string; -}; -type NullArgument = Argument & { - type: "null"; -}; -type BooleanArgument = Argument & { - type: "boolean"; -}; -type NumberArgument = Argument & { - type: "number"; - isInteger: boolean; -}; -type StringPlaceholderArgument = Argument & { - type: "string"; -}; -type IdentifierArgument = Argument & { - type: "identifier"; -}; -export type AnyArgument = NullArgument | BooleanArgument | NumberArgument | StringPlaceholderArgument | IdentifierArgument; -/** - * Parse an array of argument definitions from the specified tokens array. - * @param tokens The array tokens to parse the argument definitions from. - * @param stringArgumentPlaceholders The mapping of string literal node argument placeholders to original values. - * @param argumentValidator The argument validator function. - * @param validationFailedMessage The exception message to throw if argument validation fails. - * @returns An array of argument definitions parsed from the specified tokens array. - */ -export declare function getArguments(tokens: string[], stringArgumentPlaceholders: Placeholders, argumentValidator?: (arg: AnyArgument) => boolean, validationFailedMessage?: string): AnyArgument[]; -export {}; diff --git a/dist/dsl/DSLUtilities.d.ts b/dist/dsl/DSLUtilities.d.ts deleted file mode 100644 index cdd7220..0000000 --- a/dist/dsl/DSLUtilities.d.ts +++ /dev/null @@ -1,7 +0,0 @@ -/** - * Pop the next raw token from the specified array of tokens and throw an error if it wasn't the expected one. - * @param tokens The array of tokens. - * @param expected An optional string or array or items, one of which must match the next popped token. - * @returns The popped token. - */ -export declare function popAndCheck(tokens: string[], expected?: string | string[]): string; diff --git a/dist/index.d.ts b/dist/index.d.ts index 6adc674..124b691 100644 --- a/dist/index.d.ts +++ b/dist/index.d.ts @@ -1,4 +1,5 @@ import { BehaviourTree, FlattenedTreeNode } from "./BehaviourTree"; import State from "./State"; -export { BehaviourTree, State }; +import { parseMDSLToJSON } from "./mdsl/MDSLDefinitionParser"; +export { BehaviourTree, State, parseMDSLToJSON }; export type { FlattenedTreeNode }; diff --git a/dist/index.js b/dist/index.js index 4b59440..183a080 100644 --- a/dist/index.js +++ b/dist/index.js @@ -251,7 +251,8 @@ var require_dist = __commonJS({ var src_exports = {}; __export(src_exports, { BehaviourTree: () => BehaviourTree, - State: () => State + State: () => State, + parseMDSLToJSON: () => parseMDSLToJSON }); module.exports = __toCommonJS(src_exports); @@ -1855,9 +1856,443 @@ var BehaviourTree = class { }); } }; + +// src/mdsl/MDSLUtilities.ts +function isRootNode(node) { + return node.type === "root"; +} +function isLeafNode(node) { + return ["branch", "action", "condition", "wait"].includes(node.type); +} +function isDecoratorNode(node) { + return ["root", "repeat", "retry", "flip", "succeed", "fail"].includes(node.type); +} +function isCompositeNode(node) { + return ["sequence", "selector", "lotto", "parallel"].includes(node.type); +} +function popAndCheck2(tokens, expected) { + const popped = tokens.shift(); + if (popped === void 0) { + throw new Error("unexpected end of definition"); + } + if (expected != void 0) { + const expectedValues = typeof expected === "string" ? [expected] : expected; + var tokenMatchesExpectation = expectedValues.some((item) => popped.toUpperCase() === item.toUpperCase()); + if (!tokenMatchesExpectation) { + const expectationString = expectedValues.map((item) => "'" + item + "'").join(" or "); + throw new Error("unexpected token found. Expected " + expectationString + " but got '" + popped + "'"); + } + } + return popped; +} +function substituteStringLiterals2(definition) { + const placeholders = {}; + const processedDefinition = definition.replace(/\"(\\.|[^"\\])*\"/g, (match) => { + var strippedMatch = match.substring(1, match.length - 1); + var placeholder = Object.keys(placeholders).find((key) => placeholders[key] === strippedMatch); + if (!placeholder) { + placeholder = `@@${Object.keys(placeholders).length}@@`; + placeholders[placeholder] = strippedMatch; + } + return placeholder; + }); + return { placeholders, processedDefinition }; +} +function parseTokensFromDefinition2(definition) { + definition = definition.replace(/\(/g, " ( "); + definition = definition.replace(/\)/g, " ) "); + definition = definition.replace(/\{/g, " { "); + definition = definition.replace(/\}/g, " } "); + definition = definition.replace(/\]/g, " ] "); + definition = definition.replace(/\[/g, " [ "); + definition = definition.replace(/\,/g, " , "); + return definition.replace(/\s+/g, " ").trim().split(" "); +} + +// src/mdsl/MDSLNodeArgumentParser.ts +function parseArgumentTokens(tokens, stringArgumentPlaceholders) { + const argumentList = []; + if (!["[", "("].includes(tokens[0])) { + return argumentList; + } + const closingToken = popAndCheck2(tokens, ["[", "("]) === "[" ? "]" : ")"; + const argumentListTokens = []; + while (tokens.length && tokens[0] !== closingToken) { + argumentListTokens.push(tokens.shift()); + } + argumentListTokens.forEach((token, index) => { + const shouldBeArgumentToken = !(index & 1); + if (shouldBeArgumentToken) { + const argumentDefinition = getArgumentDefinition2(token, stringArgumentPlaceholders); + argumentList.push(argumentDefinition); + } else { + if (token !== ",") { + throw new Error(`invalid argument list, expected ',' or ']' but got '${token}'`); + } + } + }); + popAndCheck2(tokens, closingToken); + return argumentList; +} +function getArgumentDefinition2(token, stringArgumentPlaceholders) { + if (token === "null") { + return { + value: null, + type: "null" + }; + } + if (token === "true" || token === "false") { + return { + value: token === "true", + type: "boolean" + }; + } + if (!isNaN(token)) { + return { + value: parseFloat(token), + isInteger: parseFloat(token) === parseInt(token, 10), + type: "number" + }; + } + if (token.match(/^@@\d+@@$/g)) { + return { + value: stringArgumentPlaceholders[token].replace('\\"', '"'), + type: "string" + }; + } + return { + value: token, + type: "identifier" + }; +} + +// src/mdsl/MDSLNodeAttributeParser.ts +function parseAttributeTokens(tokens, stringArgumentPlaceholders) { + const nodeAttributeNames = ["while", "until", "entry", "exit", "step"]; + const attributes = {}; + let nextAttributeName = tokens[0]?.toLowerCase(); + while (nodeAttributeNames.includes(nextAttributeName)) { + if (attributes[nextAttributeName]) { + throw new Error(`duplicate attribute '${tokens[0].toUpperCase()}' found for node`); + } + tokens.shift(); + const [attributeCallIdentifier, ...attributeArguments] = parseArgumentTokens( + tokens, + stringArgumentPlaceholders + ); + if (attributeCallIdentifier?.type !== "identifier") { + throw new Error("expected agent function name identifier argument for attribute"); + } + attributeArguments.filter((arg) => arg.type === "identifier").forEach((arg) => { + throw new Error( + `invalid attribute argument value '${arg.value}', must be string, number, boolean or null` + ); + }); + attributes[nextAttributeName] = { + call: attributeCallIdentifier.value, + args: attributeArguments.map(({ value }) => value) + }; + nextAttributeName = tokens[0]?.toLowerCase(); + } + return attributes; +} + +// src/mdsl/MDSLDefinitionParser.ts +function parseMDSLToJSON(definition) { + const { placeholders, processedDefinition } = substituteStringLiterals2(definition); + const tokens = parseTokensFromDefinition2(processedDefinition); + return convertTokensToJSONDefinition(tokens, placeholders); +} +function convertTokensToJSONDefinition(tokens, stringLiteralPlaceholders) { + if (tokens.length < 3) { + throw new Error("invalid token count"); + } + if (tokens.filter((token) => token === "{").length !== tokens.filter((token) => token === "}").length) { + throw new Error("scope character mismatch"); + } + const treeStacks = []; + const rootNodes = []; + const pushNode = (node) => { + if (isRootNode(node)) { + rootNodes.push(node); + treeStacks.push([node]); + return; + } + if (!treeStacks.length || !treeStacks[treeStacks.length - 1].length) { + throw new Error("expected root node at base of definition"); + } + const topTreeStack = treeStacks[treeStacks.length - 1]; + const topTreeStackTopNode = topTreeStack[topTreeStack.length - 1]; + if (isCompositeNode(topTreeStackTopNode)) { + topTreeStackTopNode.children = topTreeStackTopNode.children || []; + topTreeStackTopNode.children.push(node); + } else if (isDecoratorNode(topTreeStackTopNode)) { + if (topTreeStackTopNode.child) { + throw new Error("a decorator node must only have a single child node"); + } + topTreeStackTopNode.child = node; + } + if (!isLeafNode(node)) { + topTreeStack.push(node); + } + }; + const popNode = () => { + const topTreeStack = treeStacks[treeStacks.length - 1]; + if (topTreeStack.length) { + topTreeStack.pop(); + } + if (!topTreeStack.length) { + treeStacks.pop(); + } + }; + while (tokens.length) { + const token = tokens.shift(); + switch (token.toUpperCase()) { + case "ROOT": { + pushNode(createRootNode(tokens, stringLiteralPlaceholders)); + break; + } + case "SUCCEED": { + pushNode(createSucceedNode(tokens, stringLiteralPlaceholders)); + break; + } + case "FAIL": { + pushNode(createFailNode(tokens, stringLiteralPlaceholders)); + break; + } + case "FLIP": { + pushNode(createFlipNode(tokens, stringLiteralPlaceholders)); + break; + } + case "REPEAT": { + pushNode(createRepeatNode(tokens, stringLiteralPlaceholders)); + break; + } + case "RETRY": { + pushNode(createRetryNode(tokens, stringLiteralPlaceholders)); + break; + } + case "SEQUENCE": { + pushNode(createSequenceNode(tokens, stringLiteralPlaceholders)); + break; + } + case "SELECTOR": { + pushNode(createSelectorNode(tokens, stringLiteralPlaceholders)); + break; + } + case "PARALLEL": { + pushNode(createParallelNode(tokens, stringLiteralPlaceholders)); + break; + } + case "LOTTO": { + pushNode(createLottoNode(tokens, stringLiteralPlaceholders)); + break; + } + case "ACTION": { + pushNode(createActionNode(tokens, stringLiteralPlaceholders)); + break; + } + case "CONDITION": { + pushNode(createConditionNode(tokens, stringLiteralPlaceholders)); + break; + } + case "WAIT": { + pushNode(createWaitNode(tokens, stringLiteralPlaceholders)); + break; + } + case "BRANCH": { + pushNode(createBranchNode(tokens, stringLiteralPlaceholders)); + break; + } + case "}": { + popNode(); + break; + } + default: { + throw new Error(`unexpected token: ${token}`); + } + } + } + return rootNodes; +} +function createRootNode(tokens, stringLiteralPlaceholders) { + let node = { + type: "root", + id: void 0 + }; + const nodeArguments = parseArgumentTokens(tokens, stringLiteralPlaceholders); + if (nodeArguments.length) { + if (nodeArguments.length === 1 && nodeArguments[0].type === "identifier") { + node.id = nodeArguments[0].value; + } else { + throw new Error("expected single root name argument"); + } + } + node = { ...node, ...parseAttributeTokens(tokens, stringLiteralPlaceholders) }; + popAndCheck2(tokens, "{"); + return node; +} +function createSucceedNode(tokens, stringLiteralPlaceholders) { + const node = { + type: "succeed", + ...parseAttributeTokens(tokens, stringLiteralPlaceholders) + }; + popAndCheck2(tokens, "{"); + return node; +} +function createFailNode(tokens, stringLiteralPlaceholders) { + const node = { + type: "fail", + ...parseAttributeTokens(tokens, stringLiteralPlaceholders) + }; + popAndCheck2(tokens, "{"); + return node; +} +function createFlipNode(tokens, stringLiteralPlaceholders) { + const node = { + type: "flip", + ...parseAttributeTokens(tokens, stringLiteralPlaceholders) + }; + popAndCheck2(tokens, "{"); + return node; +} +function createRepeatNode(tokens, stringLiteralPlaceholders) { + let node = { type: "repeat" }; + const nodeArguments = parseArgumentTokens(tokens, stringLiteralPlaceholders); + if (nodeArguments.length) { + nodeArguments.filter((arg) => arg.type !== "number" || !arg.isInteger).forEach(() => { + throw new Error(`repeat node iteration counts must be integer values`); + }); + if (nodeArguments.length === 1) { + node.iterations = nodeArguments[0].value; + } else if (nodeArguments.length === 2) { + node.iterations = [nodeArguments[0].value, nodeArguments[1].value]; + } else { + throw new Error("invalid number of repeat node iteration count arguments defined"); + } + } + node = { ...node, ...parseAttributeTokens(tokens, stringLiteralPlaceholders) }; + popAndCheck2(tokens, "{"); + return node; +} +function createRetryNode(tokens, stringLiteralPlaceholders) { + let node = { type: "retry" }; + const nodeArguments = parseArgumentTokens(tokens, stringLiteralPlaceholders); + if (nodeArguments.length) { + nodeArguments.filter((arg) => arg.type !== "number" || !arg.isInteger).forEach(() => { + throw new Error(`retry node attempt counts must be integer values`); + }); + if (nodeArguments.length === 1) { + node.attempts = nodeArguments[0].value; + } else if (nodeArguments.length === 2) { + node.attempts = [nodeArguments[0].value, nodeArguments[1].value]; + } else { + throw new Error("invalid number of retry node attempt count arguments defined"); + } + } + node = { ...node, ...parseAttributeTokens(tokens, stringLiteralPlaceholders) }; + popAndCheck2(tokens, "{"); + return node; +} +function createSequenceNode(tokens, stringLiteralPlaceholders) { + const node = { + type: "sequence", + ...parseAttributeTokens(tokens, stringLiteralPlaceholders) + }; + popAndCheck2(tokens, "{"); + return node; +} +function createSelectorNode(tokens, stringLiteralPlaceholders) { + const node = { + type: "selector", + ...parseAttributeTokens(tokens, stringLiteralPlaceholders) + }; + popAndCheck2(tokens, "{"); + return node; +} +function createParallelNode(tokens, stringLiteralPlaceholders) { + const node = { + type: "parallel", + ...parseAttributeTokens(tokens, stringLiteralPlaceholders) + }; + popAndCheck2(tokens, "{"); + return node; +} +function createLottoNode(tokens, stringLiteralPlaceholders) { + const nodeArguments = parseArgumentTokens(tokens, stringLiteralPlaceholders); + nodeArguments.filter((arg) => arg.type !== "number" || !arg.isInteger).forEach(() => { + throw new Error(`lotto node weight arguments must be integer values`); + }); + const node = { + type: "lotto", + weights: nodeArguments.map(({ value }) => value), + ...parseAttributeTokens(tokens, stringLiteralPlaceholders) + }; + popAndCheck2(tokens, "{"); + return node; +} +function createActionNode(tokens, stringLiteralPlaceholders) { + const [actionNameIdentifier, ...agentFunctionArgs] = parseArgumentTokens(tokens, stringLiteralPlaceholders); + if (actionNameIdentifier?.type !== "identifier") { + throw new Error("expected action name identifier argument"); + } + agentFunctionArgs.filter((arg) => arg.type === "identifier").forEach((arg) => { + throw new Error( + `invalid action node argument value '${arg.value}', must be string, number, boolean or null` + ); + }); + return { + type: "action", + call: actionNameIdentifier.value, + args: agentFunctionArgs.map(({ value }) => value), + ...parseAttributeTokens(tokens, stringLiteralPlaceholders) + }; +} +function createConditionNode(tokens, stringLiteralPlaceholders) { + const [conditionNameIdentifier, ...agentFunctionArgs] = parseArgumentTokens(tokens, stringLiteralPlaceholders); + if (conditionNameIdentifier?.type !== "identifier") { + throw new Error("expected condition name identifier argument"); + } + agentFunctionArgs.filter((arg) => arg.type === "identifier").forEach((arg) => { + throw new Error( + `invalid condition node argument value '${arg.value}', must be string, number, boolean or null` + ); + }); + return { + type: "condition", + call: conditionNameIdentifier.value, + args: agentFunctionArgs.map(({ value }) => value), + ...parseAttributeTokens(tokens, stringLiteralPlaceholders) + }; +} +function createWaitNode(tokens, stringLiteralPlaceholders) { + let node = { type: "wait" }; + const nodeArguments = parseArgumentTokens(tokens, stringLiteralPlaceholders); + if (nodeArguments.length) { + nodeArguments.filter((arg) => arg.type !== "number" || !arg.isInteger).forEach(() => { + throw new Error(`wait node duration arguments must be integer values`); + }); + if (nodeArguments.length === 1) { + node.duration = nodeArguments[0].value; + } else if (nodeArguments.length === 2) { + node.duration = [nodeArguments[0].value, nodeArguments[1].value]; + } else if (nodeArguments.length > 2) { + throw new Error("invalid number of wait node duration arguments defined"); + } + } + return { ...node, ...parseAttributeTokens(tokens, stringLiteralPlaceholders) }; +} +function createBranchNode(tokens, stringLiteralPlaceholders) { + const nodeArguments = parseArgumentTokens(tokens, stringLiteralPlaceholders); + if (nodeArguments.length !== 1 || nodeArguments[0].type !== "identifier") { + throw new Error("expected single branch name argument"); + } + return { type: "branch", ref: nodeArguments[0].value }; +} // Annotate the CommonJS export names for ESM import in node: 0 && (module.exports = { BehaviourTree, - State + State, + parseMDSLToJSON }); //# sourceMappingURL=index.js.map diff --git a/dist/index.js.map b/dist/index.js.map index 0ac0b53..603dc50 100644 --- a/dist/index.js.map +++ b/dist/index.js.map @@ -1,7 +1,7 @@ { "version": 3, - "sources": ["../node_modules/lotto-draw/dist/Participant.js", "../node_modules/lotto-draw/dist/Utilities.js", "../node_modules/lotto-draw/dist/Lotto.js", "../node_modules/lotto-draw/dist/createLotto.js", "../node_modules/lotto-draw/dist/index.js", "../src/index.ts", "../src/attributes/guards/GuardUnsatisifedException.ts", "../src/attributes/guards/GuardPath.ts", "../src/State.ts", "../src/nodes/Node.ts", "../src/nodes/leaf/Leaf.ts", "../src/Lookup.ts", "../src/nodes/leaf/Action.ts", "../src/nodes/leaf/Condition.ts", "../src/nodes/leaf/Wait.ts", "../src/nodes/decorator/Decorator.ts", "../src/nodes/decorator/Root.ts", "../src/nodes/decorator/Repeat.ts", "../src/nodes/decorator/Retry.ts", "../src/nodes/decorator/Flip.ts", "../src/nodes/decorator/Succeed.ts", "../src/nodes/decorator/Fail.ts", "../src/nodes/composite/Lotto.ts", "../src/nodes/composite/Composite.ts", "../src/nodes/composite/Selector.ts", "../src/nodes/composite/Sequence.ts", "../src/nodes/composite/Parallel.ts", "../src/attributes/Attribute.ts", "../src/attributes/guards/Guard.ts", "../src/attributes/guards/While.ts", "../src/attributes/guards/Until.ts", "../src/attributes/callbacks/Callback.ts", "../src/attributes/callbacks/Entry.ts", "../src/attributes/callbacks/Exit.ts", "../src/attributes/callbacks/Step.ts", "../src/RootAstNodesBuilder.ts", "../src/BehaviourTree.ts"], - "sourcesContent": ["\"use strict\";\r\nObject.defineProperty(exports, \"__esModule\", { value: true });\r\nexports.Participant = void 0;\r\n/**\r\n * A participant that holds a number of tickets.\r\n */\r\nvar Participant = /** @class */ (function () {\r\n /**\r\n * Creates an instance of the Participant class.\r\n * @param participant The actual participant.\r\n * @param tickets The number of tickets held by the participant.\r\n */\r\n function Participant(participant, tickets) {\r\n if (tickets === void 0) { tickets = 1; }\r\n this._participant = participant;\r\n this._tickets = tickets;\r\n }\r\n Object.defineProperty(Participant.prototype, \"participant\", {\r\n /** Gets the actual participant. */\r\n get: function () {\r\n return this._participant;\r\n },\r\n enumerable: false,\r\n configurable: true\r\n });\r\n Object.defineProperty(Participant.prototype, \"tickets\", {\r\n /** Gets or sets the number of tickets held by the participant. */\r\n get: function () {\r\n return this._tickets;\r\n },\r\n set: function (value) {\r\n this._tickets = value;\r\n },\r\n enumerable: false,\r\n configurable: true\r\n });\r\n return Participant;\r\n}());\r\nexports.Participant = Participant;\r\n", "\"use strict\";\r\nObject.defineProperty(exports, \"__esModule\", { value: true });\r\nexports.isNaturalNumber = exports.isNullOrUndefined = void 0;\r\n/**\r\n * Gets whether the value provided is null or undefined.\r\n * @param value The value to check.\r\n * @returns Whether the value provided is null or undefined.\r\n */\r\nfunction isNullOrUndefined(value) {\r\n return value === null || value === undefined;\r\n}\r\nexports.isNullOrUndefined = isNullOrUndefined;\r\n/**\r\n * Gets whether the value provided is a natural number.\r\n * @param value The value to check.\r\n * @returns Whether the value provided is a natural number.\r\n */\r\nfunction isNaturalNumber(value) {\r\n return typeof value === \"number\" && value >= 1 && Math.floor(value) === value;\r\n}\r\nexports.isNaturalNumber = isNaturalNumber;\r\n", "\"use strict\";\r\nObject.defineProperty(exports, \"__esModule\", { value: true });\r\nexports.Lotto = void 0;\r\nvar Participant_1 = require(\"./Participant\");\r\nvar Utilities_1 = require(\"./Utilities\");\r\n/**\r\n * Represents a lotto consisting of a number of pickable ticket-holding participants.\r\n */\r\nvar Lotto = /** @class */ (function () {\r\n /**\r\n * Creates a new instance of Lotto.\r\n * @param customRandom The custom RNG to use in place of Math.random().\r\n */\r\n function Lotto(customRandom) {\r\n /** The array of participants that are holding tickets in the lotto. */\r\n this._participants = [];\r\n this._customRandom = customRandom;\r\n }\r\n /**\r\n * Adds a participant with the specified number of tickets, or adds to the participant ticket count if the participant already holds tickets.\r\n * @param participant The participant to add or to increase the ticket count for if they already hold tickets.\r\n * @param tickets The number of tickets, defaults to 1.\r\n * @returns The Lotto instance.\r\n */\r\n Lotto.prototype.add = function (participant, tickets) {\r\n if (tickets === void 0) { tickets = 1; }\r\n // Check that we have a valid ticket count.\r\n if (!(0, Utilities_1.isNaturalNumber)(tickets)) {\r\n throw new Error(\"tickets value must be a natural number\");\r\n }\r\n // Check whether this participant has already been added.\r\n var existingParticipant = this._participants.find(function (part) { return part.participant === participant; });\r\n if (existingParticipant) {\r\n // The participant has already been added to the lotto so just add to their ticket count.\r\n existingParticipant.tickets += tickets;\r\n }\r\n else {\r\n // The participant is not part of the lotto so we should add them.\r\n this._participants.push(new Participant_1.Participant(participant, tickets));\r\n }\r\n return this;\r\n };\r\n /**\r\n * Removes the specified number of tickets for the given participant from the draw, or all tickets if a ticket number is not defined.\r\n * @param participant The participant to remove tickets for.\r\n * @param tickets The number of tickets to remove, or undefined if all tickets are to be removed.\r\n * @returns The Lotto instance.\r\n */\r\n Lotto.prototype.remove = function (participant, tickets) {\r\n // Attempt to get the existing participant.\r\n var existingParticipant = this._participants.find(function (part) { return part.participant === participant; });\r\n // There is nothing to do if the specified participant isn't even part of the lotto.\r\n if (!existingParticipant) {\r\n return this;\r\n }\r\n // Check whether a tickets value was given.\r\n if (tickets !== undefined) {\r\n // Check that we have a valid ticket count.\r\n if (!(0, Utilities_1.isNaturalNumber)(tickets)) {\r\n throw new Error(\"tickets value must be a natural number\");\r\n }\r\n existingParticipant.tickets -= tickets;\r\n // If the participant no longer holds any tickets then they should be removed.\r\n if (existingParticipant.tickets < 1) {\r\n this._participants = this._participants.filter(function (part) { return part !== existingParticipant; });\r\n }\r\n }\r\n else {\r\n // We are removing all tickets for the participant so just remove them from the lotto.\r\n this._participants = this._participants.filter(function (part) { return part !== existingParticipant; });\r\n }\r\n return this;\r\n };\r\n /**\r\n * Draw a winning ticket and return the participant that holds the ticket.\r\n * @param options The draw options.\r\n * @returns The participant that holds the winning ticket.\r\n */\r\n Lotto.prototype.draw = function (options) {\r\n if (options === void 0) { options = {}; }\r\n // If we have no participants then just return null.\r\n if (this._participants.length === 0) {\r\n return null;\r\n }\r\n var redrawable = (0, Utilities_1.isNullOrUndefined)(options.redrawable) ? true : options.redrawable;\r\n var pickable = [];\r\n this._participants.forEach(function (_a) {\r\n var participant = _a.participant, tickets = _a.tickets;\r\n for (var ticketCount = 0; ticketCount < tickets; ticketCount++) {\r\n pickable.push(participant);\r\n }\r\n });\r\n var random;\r\n // We need a random floating-point number between 0 (inclusive) and 1 to scale up to pick our winner.\r\n // If a custom random function exists then we should use that or fall back to Math.random().\r\n if (this._customRandom) {\r\n // Call our custom random function to get a random floating-point number.\r\n random = this._customRandom();\r\n // Verify that the result of calling our custom random function is a number between 0 (inclusive) and 1.\r\n if (typeof random !== \"number\" || random < 0 || random >= 1) {\r\n throw new Error(\"the 'random' function provided did not return a number between 0 (inclusive) and 1\");\r\n }\r\n }\r\n else {\r\n // No custom random function was defined so just use good ol' Math.random().\r\n random = Math.random();\r\n }\r\n // Pick a winning participant.\r\n var winner = pickable[Math.floor(random * pickable.length)];\r\n // If the ticket isn't redrawable then we should remove a ticket from the winning participants ticket count.\r\n if (!redrawable) {\r\n this.remove(winner, 1);\r\n }\r\n // Return the winning participant.\r\n return winner;\r\n };\r\n /**\r\n * Draws multiple winning tickets and return an array of the participants that hold the winning tickets.\r\n * @param tickets The number of winning tickets to draw.\r\n * @param options The draw multiple options.\r\n * @returns An array of the participants that hold the winning tickets.\r\n */\r\n Lotto.prototype.drawMultiple = function (tickets, options) {\r\n if (options === void 0) { options = {}; }\r\n var uniqueResults = (0, Utilities_1.isNullOrUndefined)(options.unique) ? false : options.unique;\r\n // Handle cases where the user has asked for zero tickets (no idea why they would do this be we should trust them).\r\n if (tickets === 0) {\r\n return [];\r\n }\r\n // Now that we know out tickets value is not zero we should check that it is a valid natural number.\r\n if (!(0, Utilities_1.isNaturalNumber)(tickets)) {\r\n throw new Error(\"tickets value must be a natural number\");\r\n }\r\n var result = [];\r\n // Keep drawing tickets until we either reach the number of required tickets or we simply run out of tickets to draw.\r\n // We can run out of tickets to draw if 'options.redrawable' is explicity 'false' or we just had no participants when 'drawMultiple' was called.\r\n while (result.length < tickets && this._participants.length > 0) {\r\n result.push(this.draw(options));\r\n }\r\n // If the 'unique' draw option is set then we need to remove duplicates from the result list.\r\n if (uniqueResults) {\r\n // Create an array to store our unique results.\r\n var unique = [];\r\n // Iterate over all of our participants (with potential duplicates) and populate our array of unique values.\r\n for (var _i = 0, result_1 = result; _i < result_1.length; _i++) {\r\n var participant = result_1[_i];\r\n if (unique.indexOf(participant) === -1) {\r\n unique.push(participant);\r\n }\r\n }\r\n result = unique;\r\n }\r\n return result;\r\n };\r\n return Lotto;\r\n}());\r\nexports.Lotto = Lotto;\r\n", "\"use strict\";\r\nObject.defineProperty(exports, \"__esModule\", { value: true });\r\nexports.createLotto = void 0;\r\nvar Lotto_1 = require(\"./Lotto\");\r\n/**\r\n * A function that creates and returns a Lotto instance.\r\n * @param participantsOrOptions An array of initial participants or options relating to the creation of a Lotto instance.\r\n * @returns A new Lotto instance.\r\n */\r\nfunction createLotto(participantsOrOptions) {\r\n // If no initial participants or lotto options were provided as an argument then we can just return a new lotto instance now.\r\n if (!participantsOrOptions) {\r\n return new Lotto_1.Lotto();\r\n }\r\n // Check whether we were provided with an array of initial participants or a lotto options object.\r\n if (Array.isArray(participantsOrOptions)) {\r\n // We are dealing with a pre-defined array of participants.\r\n var participants = participantsOrOptions;\r\n var lotto_1 = new Lotto_1.Lotto();\r\n // If the lotto participants have been defined upfront then we will need to add them all to our lotto instance now.\r\n participants.forEach(function (_a) {\r\n var participant = _a[0], tokens = _a[1];\r\n return lotto_1.add(participant, tokens);\r\n });\r\n // Return the Lotto instance.\r\n return lotto_1;\r\n }\r\n else {\r\n // We are dealing with some lotto options.\r\n var random = participantsOrOptions.random, participants = participantsOrOptions.participants;\r\n // Create a Lotto instance passing the custom RNG function to use in place of Math.random() (which could be undefined).\r\n var lotto_2 = new Lotto_1.Lotto(random);\r\n // If the lotto participants have been defined upfront as part of the options then we will need to add them all to our lotto instance now.\r\n if (participants) {\r\n participants.forEach(function (_a) {\r\n var participant = _a[0], tokens = _a[1];\r\n return lotto_2.add(participant, tokens);\r\n });\r\n }\r\n // Return the Lotto instance.\r\n return lotto_2;\r\n }\r\n}\r\nexports.createLotto = createLotto;\r\n", "\"use strict\";\r\nObject.defineProperty(exports, \"__esModule\", { value: true });\r\nvar createLotto_1 = require(\"./createLotto\");\r\nexports.default = createLotto_1.createLotto;\r\n", "import { BehaviourTree, FlattenedTreeNode } from \"./BehaviourTree\";\nimport State from \"./State\";\n\nexport { BehaviourTree, State };\nexport type { FlattenedTreeNode };\n", "import Node from \"../../nodes/Node\";\n\n/**\n * An exception thrown when evaluating node guard path conditions and a conditions fails.\n */\nexport default class GuardUnsatisifedException extends Error {\n /**\n * @param source The node at which a guard condition failed.\n */\n constructor(private source: Node) {\n super(\"A guard path condition has failed\");\n }\n\n /**\n * Gets whether the specified node is the node at which a guard condition failed.\n * @param node The node to check against the source node.\n * @returns Whether the specified node is the node at which a guard condition failed.\n */\n isSourceNode = (node: Node) => node === this.source;\n}\n", "import { Agent } from \"../../Agent\";\nimport Guard from \"./Guard\";\nimport Node from \"../../nodes/Node\";\nimport GuardUnsatisifedException from \"./GuardUnsatisifedException\";\n\nexport type GuardPathPart = {\n node: Node;\n guards: Guard[];\n};\n\n/**\n * Represents a path of node guards along a root-to-leaf tree path.\n */\nexport default class GuardPath {\n /**\n * @param nodes An array of objects defining a node instance -> guard link, ordered by node depth.\n */\n constructor(private nodes: GuardPathPart[]) {}\n\n /**\n * Evaluate guard conditions for all guards in the tree path, moving outwards from the root.\n * @param agent The agent, required for guard evaluation.\n * @returns An evaluation results object.\n */\n evaluate = (agent: Agent) => {\n // We need to evaluate guard conditions for nodes up the tree, moving outwards from the root.\n for (const details of this.nodes) {\n // There can be multiple guards per node.\n for (const guard of details.guards) {\n // Check whether the guard condition passes, and throw an exception if not.\n if (!guard.isSatisfied(agent)) {\n throw new GuardUnsatisifedException(details.node);\n }\n }\n }\n };\n}\n", "/**\n * Enumeration of node state types.\n */\nexport enum State {\n READY = \"mistreevous.ready\",\n RUNNING = \"mistreevous.running\",\n SUCCEEDED = \"mistreevous.succeeded\",\n FAILED = \"mistreevous.failed\"\n}\n\nexport { State as default };\n\nexport type CompleteState = State.SUCCEEDED | State.FAILED;\nexport type AnyState = State.READY | State.RUNNING | CompleteState;\n", "import { Agent } from \"../Agent\";\nimport Attribute from \"../attributes/Attribute\";\nimport Entry from \"../attributes/callbacks/Entry\";\nimport Exit from \"../attributes/callbacks/Exit\";\nimport Step from \"../attributes/callbacks/Step\";\nimport Guard from \"../attributes/guards/Guard\";\nimport GuardPath from \"../attributes/guards/GuardPath\";\nimport GuardUnsatisifedException from \"../attributes/guards/GuardUnsatisifedException\";\nimport { BehaviourTreeOptions } from \"../BehaviourTreeOptions\";\nimport { AnyArgument } from \"../RootAstNodesBuilder\";\nimport State, { AnyState } from \"../State\";\nimport Leaf from \"./leaf/Leaf\";\n\n/**\n * A base node.\n */\nexport default abstract class Node {\n /**\n * The node uid.\n */\n private readonly uid: string = createNodeUid();\n /**\n * The node state.\n */\n private state: AnyState = State.READY;\n /**\n * The guard path to evaluate as part of a node update.\n */\n private guardPath: GuardPath | undefined;\n\n /**\n * @param type The node type.\n * @param attributes The node attributes.\n * @param args The node argument definitions.\n */\n constructor(private type: string, private attributes: Attribute[], private args: AnyArgument[]) {}\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected abstract onUpdate(agent: Agent, options: BehaviourTreeOptions): void;\n\n /**\n * Gets the name of the node.\n */\n public abstract getName(): string;\n\n /**\n * Gets whether this node is a leaf node.\n */\n public abstract isLeafNode: () => this is Leaf;\n\n /**\n * Gets/Sets the state of the node.\n */\n getState = (): AnyState => this.state;\n setState = (value: AnyState): void => {\n this.state = value;\n };\n\n /**\n * Gets the unique id of the node.\n */\n getUid = () => this.uid;\n\n /**\n * Gets the type of the node.\n */\n getType = () => this.type;\n\n /**\n * Gets the node attributes.\n */\n getAttributes = () => this.attributes;\n\n /**\n * Gets the node arguments.\n */\n getArguments = () => this.args;\n\n /**\n * Gets the node attribute with the specified type, or null if it does not exist.\n */\n getAttribute(type: \"entry\" | \"ENTRY\"): Entry;\n getAttribute(type: \"exit\" | \"EXIT\"): Exit;\n getAttribute(type: \"step\" | \"STEP\"): Step;\n getAttribute(type: string): Attribute {\n return (\n this.getAttributes().filter((decorator) => decorator.getType().toUpperCase() === type.toUpperCase())[0] ||\n null\n );\n }\n\n /**\n * Gets the node attributes.\n */\n getGuardAttributes = (): Guard[] => this.getAttributes().filter((decorator) => decorator.isGuard()) as Guard[];\n\n /**\n * Sets the guard path to evaluate as part of a node update.\n */\n setGuardPath = (value: GuardPath) => (this.guardPath = value);\n\n /**\n * Gets whether a guard path is assigned to this node.\n */\n hasGuardPath = () => !!this.guardPath;\n\n /**\n * Gets whether this node is in the specified state.\n * @param value The value to compare to the node state.\n */\n public is(value: AnyState): boolean {\n return this.state === value;\n }\n\n /**\n * Reset the state of the node.\n */\n public reset(): void {\n this.setState(State.READY);\n }\n\n /**\n * Abort the running of this node.\n * @param agent The agent.\n */\n public abort(agent: Agent): void {\n // There is nothing to do if this node is not in the running state.\n if (!this.is(State.RUNNING)) {\n return;\n }\n\n // Reset the state of this node.\n this.reset();\n\n this.getAttribute(\"exit\")?.callAgentFunction(agent, false, true);\n }\n\n /**\n * Update the node.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n * @returns The result of the update.\n */\n public update(agent: Agent, options: BehaviourTreeOptions): void {\n // If this node is already in a 'SUCCEEDED' or 'FAILED' state then there is nothing to do.\n if (this.is(State.SUCCEEDED) || this.is(State.FAILED)) {\n return;\n }\n\n try {\n // Evaluate all of the guard path conditions for the current tree path.\n this.guardPath!.evaluate(agent);\n\n // If this node is in the READY state then call the ENTRY for this node if it exists.\n if (this.is(State.READY)) {\n this.getAttribute(\"entry\")?.callAgentFunction(agent);\n }\n\n this.getAttribute(\"step\")?.callAgentFunction(agent);\n\n // Do the actual update.\n this.onUpdate(agent, options);\n\n // If this node is now in a 'SUCCEEDED' or 'FAILED' state then call the EXIT for this node if it exists.\n if (this.is(State.SUCCEEDED) || this.is(State.FAILED)) {\n this.getAttribute(\"exit\")?.callAgentFunction(agent, this.is(State.SUCCEEDED), false);\n }\n } catch (error) {\n // If the error is a GuardUnsatisfiedException then we need to determine if this node is the source.\n if (error instanceof GuardUnsatisifedException && error.isSourceNode(this)) {\n // Abort the current node.\n this.abort(agent);\n\n // Any node that is the source of an abort will be a failed node.\n this.setState(State.FAILED);\n } else {\n throw error;\n }\n }\n }\n}\n\n/**\n * Create a randomly generated node uid.\n * @returns A randomly generated node uid.\n */\nfunction createNodeUid(): string {\n var S4 = function () {\n return (((1 + Math.random()) * 0x10000) | 0).toString(16).substring(1);\n };\n return S4() + S4() + \"-\" + S4() + \"-\" + S4() + \"-\" + S4() + \"-\" + S4() + S4() + S4();\n}\n", "import Node from \"../Node\";\n\n/**\n * A leaf node.\n */\nexport default abstract class Leaf extends Node {\n /**\n * Gets whether this node is a leaf node.\n */\n isLeafNode = () => true;\n}\n", "import { ActionResult, Agent, ExitFunctionArg, FunctionArg, GlobalFunction } from \"./Agent\";\nimport { AnyArgument, RootAstNode } from \"./RootAstNodesBuilder\";\n\n// Exit callbacks receive their own special type of argument.\n// There's probably stricter ways to represent this but it feels overly complex right now.\ntype ExitResultArg = { value: ExitFunctionArg };\nexport type AnyExitArgument = AnyArgument | ExitResultArg;\n\nexport type InvokerFunction = (args: AnyExitArgument[]) => ActionResult;\n\n/**\n * A singleton used to store and lookup registered functions and subtrees.\n */\nexport default class Lookup {\n /**\n * The object holding any registered functions keyed on function name.\n */\n private static functionTable: { [key: string]: GlobalFunction } = {};\n /**\n * The object holding any registered sub-trees keyed on tree name.\n */\n private static subtreeTable: { [key: string]: RootAstNode } = {};\n\n /**\n * Gets the function with the specified name.\n * @param name The name of the function.\n * @returns The function with the specified name.\n */\n public static getFunc(name: string): GlobalFunction {\n return this.functionTable[name];\n }\n\n /**\n * Sets the function with the specified name for later lookup.\n * @param name The name of the function.\n * @param func The function.\n */\n public static setFunc(name: string, func: GlobalFunction): void {\n this.functionTable[name] = func;\n }\n\n /**\n * Gets the function invoker for the specified agent and function name.\n * If a function with the specified name exists on the agent object then it will\n * be returned, otherwise we will then check the registered functions for a match.\n * @param agent The agent instance that this behaviour tree is modelling behaviour for.\n * @param name The function name.\n * @returns The function invoker for the specified agent and function name.\n */\n static getFuncInvoker(agent: Agent, name: string): InvokerFunction | null {\n // Check whether the agent contains the specified function.\n const foundOnAgent = agent[name];\n if (foundOnAgent && typeof foundOnAgent === \"function\") {\n return (args: AnyExitArgument[]): boolean | ActionResult =>\n foundOnAgent.apply(\n agent,\n args.map((arg) => arg.value)\n );\n }\n\n // The agent does not contain the specified function but it may have been registered at some point.\n if (this.functionTable[name] && typeof this.functionTable[name] === \"function\") {\n return (args: AnyExitArgument[]) => this.functionTable[name](agent, ...args.map((arg) => arg.value));\n }\n\n // We have no function to invoke.\n return null;\n }\n\n /**\n * Gets the subtree with the specified name.\n * @param name The name of the subtree.\n * @returns The subtree with the specified name.\n */\n static getSubtree(name: string): RootAstNode {\n return this.subtreeTable[name];\n }\n\n /**\n * Sets the subtree with the specified name for later lookup.\n * @param name The name of the subtree.\n * @param subtree The subtree.\n */\n static setSubtree(name: string, subtree: RootAstNode) {\n this.subtreeTable[name] = subtree;\n }\n\n /**\n * Removes the registered function or subtree with the specified name.\n * @param name The name of the registered function or subtree.\n */\n static remove(name: string) {\n delete this.functionTable[name];\n delete this.subtreeTable[name];\n }\n\n /**\n * Remove all registered functions and subtrees.\n */\n static empty() {\n this.functionTable = {};\n this.subtreeTable = {};\n }\n}\n", "import Leaf from \"./Leaf\";\nimport State, { CompleteState } from \"../../State\";\nimport Lookup from \"../../Lookup\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { AnyArgument } from \"../../RootAstNodesBuilder\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * An Action leaf node.\n * This represents an immediate or ongoing state of behaviour.\n */\nexport default class Action extends Leaf {\n /**\n * @param attributes The node attributes.\n * @param actionName The action name.\n * @param actionArguments The array of action argument definitions.\n */\n constructor(attributes: Attribute[], private actionName: string, private actionArguments: AnyArgument[]) {\n super(\"action\", attributes, actionArguments);\n }\n\n /**\n * Whether there is a pending update promise.\n */\n private isUsingUpdatePromise = false;\n\n /**\n * The finished state result of an update promise.\n */\n private updatePromiseStateResult: CompleteState | null = null;\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // If the result of this action depends on an update promise then there is nothing to do until\n // it resolves, unless there has been a value set as a result of the update promise resolving.\n if (this.isUsingUpdatePromise) {\n // Check whether the update promise has resolved with a state value.\n if (this.updatePromiseStateResult) {\n // Set the state of this node to match the state returned by the promise.\n this.setState(this.updatePromiseStateResult);\n }\n\n return;\n }\n\n // Attempt to get the invoker for the action function.\n const actionFuncInvoker = Lookup.getFuncInvoker(agent, this.actionName);\n\n // The action function should be defined.\n if (actionFuncInvoker === null) {\n throw new Error(\n `cannot update action node as the action '${this.actionName}' function is not defined on the agent and has not been registered`\n );\n }\n\n // Call the action function, the result of which may be:\n // - The finished state of this action node.\n // - A promise to return a finished node state.\n // - Undefined if the node should remain in the running state.\n const updateResult = actionFuncInvoker(this.actionArguments) as CompleteState | Promise;\n\n if (updateResult instanceof Promise) {\n updateResult.then(\n (result) => {\n // If 'isUpdatePromisePending' is null then the promise was cleared as it was resolving, probably via an abort of reset.\n if (!this.isUsingUpdatePromise) {\n return;\n }\n\n // Check to make sure the result is a valid finished state.\n if (result !== State.SUCCEEDED && result !== State.FAILED) {\n throw new Error(\n \"action node promise resolved with an invalid value, expected a State.SUCCEEDED or State.FAILED value to be returned\"\n );\n }\n\n // Set pending update promise state result to be processed on next update.\n this.updatePromiseStateResult = result;\n },\n (reason) => {\n // If 'isUpdatePromisePending' is null then the promise was cleared as it was resolving, probably via an abort of reset.\n if (!this.isUsingUpdatePromise) {\n return;\n }\n\n // Just throw whatever was returned as the rejection argument.\n throw new Error(reason);\n }\n );\n\n // This node will be in the 'RUNNING' state until the update promise resolves.\n this.setState(State.RUNNING);\n\n // We are now waiting for the promise returned by the use to resolve before we know what state this node is in.\n this.isUsingUpdatePromise = true;\n } else {\n // Validate the returned value.\n this.validateUpdateResult(updateResult);\n\n // Set the state of this node, this may be undefined, which just means that the node is still in the 'RUNNING' state.\n this.setState(updateResult || State.RUNNING);\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => this.actionName;\n\n /**\n * Reset the state of the node.\n */\n reset = () => {\n // Reset the state of this node.\n this.setState(State.READY);\n\n // There is no longer an update promise that we care about.\n this.isUsingUpdatePromise = false;\n this.updatePromiseStateResult = null;\n };\n\n /**\n * Validate the result of an update function call.\n * @param result The result of an update function call.\n */\n private validateUpdateResult = (result: CompleteState | boolean) => {\n switch (result) {\n case State.SUCCEEDED:\n case State.FAILED:\n case undefined:\n return;\n default:\n throw new Error(\n `action '${this.actionName}' 'onUpdate' returned an invalid response, expected an optional State.SUCCEEDED or State.FAILED value to be returned`\n );\n }\n };\n}\n", "import Leaf from \"./Leaf\";\nimport State from \"../../State\";\nimport Lookup from \"../../Lookup\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { AnyArgument } from \"../../RootAstNodesBuilder\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A Condition leaf node.\n * This will succeed or fail immediately based on an agent predicate, without moving to the 'RUNNING' state.\n */\nexport default class Condition extends Leaf {\n /**\n * @param attributes The node attributes.\n * @param conditionName The name of the condition function.\n * @param conditionArguments The array of condition argument definitions.\n */\n constructor(attributes: Attribute[], private conditionName: string, private conditionArguments: AnyArgument[]) {\n super(\"condition\", attributes, conditionArguments);\n }\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // Attempt to get the invoker for the condition function.\n const conditionFuncInvoker = Lookup.getFuncInvoker(agent, this.conditionName);\n\n // The condition function should be defined.\n if (conditionFuncInvoker === null) {\n throw new Error(\n `cannot update condition node as the condition '${this.conditionName}' function is not defined on the agent and has not been registered`\n );\n }\n\n // Call the condition function to determine the state of this node.\n this.setState(!!conditionFuncInvoker(this.conditionArguments) ? State.SUCCEEDED : State.FAILED);\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => this.conditionName;\n}\n", "import Leaf from \"./Leaf\";\nimport State from \"../../State\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { Agent } from \"../../Agent\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A WAIT node.\n * The state of this node will change to SUCCEEDED after a duration of time\n */\nexport default class Wait extends Leaf {\n /**\n * @param attributes The node attributes.\n * @param duration The duration that this node will wait to succeed in milliseconds.\n * @param durationMin The minimum possible duration in milliseconds that this node will wait to succeed.\n * @param durationMax The maximum possible duration in milliseconds that this node will wait to succeed.\n */\n constructor(\n attributes: Attribute[],\n private duration: number | null,\n private durationMin: number | null,\n private durationMax: number | null\n ) {\n super(\"wait\", attributes, []);\n }\n\n /**\n * The time in milliseconds at which this node was first updated.\n */\n private initialUpdateTime: number = 0;\n\n /**\n * The total duration in milliseconds that this node will be waiting for.\n */\n private totalDuration: number | null = null;\n\n /**\n * The duration in milliseconds that this node has been waiting for.\n */\n private waitedDuration: number = 0;\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // If this node is in the READY state then we need to set the initial update time.\n if (this.is(State.READY)) {\n // Set the initial update time.\n this.initialUpdateTime = new Date().getTime();\n\n // Set the initial waited duration.\n this.waitedDuration = 0;\n\n // Are we dealing with an explicit duration or will we be randomly picking a duration between the min and max duration.\n if (this.duration !== null) {\n this.totalDuration = this.duration;\n } else if (this.durationMin !== null && this.durationMax !== null) {\n // We will be picking a random duration between a min and max duration, if the optional 'random' behaviour tree\n // function option is defined then we will be using that, otherwise we will fall back to using Math.random.\n const random = typeof options.random === \"function\" ? options.random : Math.random;\n\n // Pick a random duration between a min and max duration.\n this.totalDuration = Math.floor(\n random() * (this.durationMax - this.durationMin + 1) + this.durationMin\n );\n } else {\n this.totalDuration = null;\n }\n\n // The node is now running until we finish waiting.\n this.setState(State.RUNNING);\n }\n\n // If we have no total duration then this wait node will wait indefinitely until it is aborted.\n if (this.totalDuration === null) {\n return;\n }\n\n // If we have a 'getDeltaTime' function defined as part of our options then we will use it to figure out how long we have waited for.\n if (typeof options.getDeltaTime === \"function\") {\n // Get the delta time.\n const deltaTime = options.getDeltaTime();\n\n // Our delta time must be a valid number and cannot be NaN.\n if (typeof deltaTime !== \"number\" || isNaN(deltaTime)) {\n throw new Error(\"The delta time must be a valid number and not NaN.\");\n }\n\n // Update the amount of time that this node has been waiting for based on the delta time.\n this.waitedDuration += deltaTime * 1000;\n } else {\n // We are not using a delta time, so we will just work out hom much time has passed since the first update.\n this.waitedDuration = new Date().getTime() - this.initialUpdateTime;\n }\n\n // Have we waited long enough?\n if (this.waitedDuration >= this.totalDuration) {\n // We have finished waiting!\n this.setState(State.SUCCEEDED);\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => {\n if (this.duration !== null) {\n return `WAIT ${this.duration}ms`;\n } else if (this.durationMin !== null && this.durationMax !== null) {\n return `WAIT ${this.durationMin}ms-${this.durationMax}ms`;\n } else {\n return \"WAIT\";\n }\n };\n}\n", "import Node from \"../Node\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\n\n/**\n * A decorator node that wraps a single child node.\n */\nexport default abstract class Decorator extends Node {\n /**\n * @param type The node type.\n * @param attributes The node attributes.\n * @param child The child node.\n */\n constructor(type: string, attributes: Attribute[], protected child: Node) {\n super(type, attributes, []);\n }\n\n /**\n * Gets whether this node is a leaf node.\n */\n isLeafNode = () => false;\n\n /**\n * Gets the children of this node.\n */\n getChildren = () => [this.child];\n\n /**\n * Reset the state of the node.\n */\n reset = () => {\n // Reset the state of this node.\n this.setState(State.READY);\n\n // Reset the state of the child node.\n this.child.reset();\n };\n\n /**\n * Abort the running of this node.\n * @param agent The agent.\n */\n abort = (agent: Agent) => {\n // There is nothing to do if this node is not in the running state.\n if (!this.is(State.RUNNING)) {\n return;\n }\n\n // Abort the child node.\n this.child.abort(agent);\n\n // Reset the state of this node.\n this.reset();\n\n this.getAttribute(\"exit\")?.callAgentFunction(agent, false, true);\n };\n}\n", "import Node from \"../Node\";\nimport Decorator from \"./Decorator\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A Root node.\n * The root node will have a single child.\n */\nexport default class Root extends Decorator {\n /**\n * @param attributes The node attributes.\n * @param child The child node.\n */\n constructor(attributes: Attribute[], child: Node) {\n super(\"root\", attributes, child);\n }\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // If the child has never been updated or is running then we will need to update it now.\n if (this.child.getState() === State.READY || this.child.getState() === State.RUNNING) {\n // Update the child of this node.\n this.child.update(agent, options);\n }\n\n // The state of the root node is the state of its child.\n this.setState(this.child.getState());\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => \"ROOT\";\n}\n", "import Node from \"../Node\";\nimport Decorator from \"./Decorator\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A REPEAT node.\n * The node has a single child which can have:\n * -- A number of iterations for which to repeat the child node.\n * -- An infinite repeat loop if neither an iteration count or a condition function is defined.\n * The REPEAT node will stop and have a 'FAILED' state if its child is ever in a 'FAILED' state after an update.\n * The REPEAT node will attempt to move on to the next iteration if its child is ever in a 'SUCCEEDED' state.\n */\nexport default class Repeat extends Decorator {\n /**\n * @param attributes The node attributes.\n * @param iterations The number of iterations to repeat the child node.\n * @param iterationsMin The minimum possible number of iterations to repeat the child node.\n * @param iterationsMax The maximum possible number of iterations to repeat the child node.\n * @param child The child node.\n */\n constructor(\n attributes: Attribute[],\n private iterations: number | null,\n private iterationsMin: number | null,\n private iterationsMax: number | null,\n child: Node\n ) {\n super(\"repeat\", attributes, child);\n }\n\n /**\n * The number of target iterations to make.\n */\n private targetIterationCount: number | null = null;\n\n /**\n * The current iteration count.\n */\n private currentIterationCount: number = 0;\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // If this node is in the READY state then we need to reset the child and the target iteration count.\n if (this.is(State.READY)) {\n // Reset the child node.\n this.child.reset();\n\n // Reset the current iteration count.\n this.currentIterationCount = 0;\n\n // Set the target iteration count.\n this.setTargetIterationCount(options);\n }\n\n // Do a check to see if we can iterate. If we can then this node will move into the 'RUNNING' state.\n // If we cannot iterate then we have hit our target iteration count, which means that the node has succeeded.\n if (this.canIterate()) {\n // This node is in the running state and can do its initial iteration.\n this.setState(State.RUNNING);\n\n // We may have already completed an iteration, meaning that the child node will be in the SUCCEEDED state.\n // If this is the case then we will have to reset the child node now.\n if (this.child.getState() === State.SUCCEEDED) {\n this.child.reset();\n }\n\n // Update the child of this node.\n this.child.update(agent, options);\n\n // If the child moved into the FAILED state when we updated it then there is nothing left to do and this node has also failed.\n // If it has moved into the SUCCEEDED state then we have completed the current iteration.\n if (this.child.getState() === State.FAILED) {\n // The child has failed, meaning that this node has failed.\n this.setState(State.FAILED);\n\n return;\n } else if (this.child.getState() === State.SUCCEEDED) {\n // We have completed an iteration.\n this.currentIterationCount += 1;\n }\n } else {\n // This node is in the 'SUCCEEDED' state as we cannot iterate any more.\n this.setState(State.SUCCEEDED);\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => {\n if (this.iterations !== null) {\n return `REPEAT ${this.iterations}x`;\n } else if (this.iterationsMin !== null && this.iterationsMax !== null) {\n return `REPEAT ${this.iterationsMin}x-${this.iterationsMax}x`;\n } else {\n return \"REPEAT\";\n }\n };\n\n /**\n * Reset the state of the node.\n */\n reset = () => {\n // Reset the state of this node.\n this.setState(State.READY);\n\n // Reset the current iteration count.\n this.currentIterationCount = 0;\n\n // Reset the child node.\n this.child.reset();\n };\n\n /**\n * Gets whether an iteration can be made.\n * @returns Whether an iteration can be made.\n */\n private canIterate = () => {\n if (this.targetIterationCount !== null) {\n // We can iterate as long as we have not reached our target iteration count.\n return this.currentIterationCount < this.targetIterationCount;\n }\n\n // If neither an iteration count or a condition function were defined then we can iterate indefinitely.\n return true;\n };\n\n /**\n * Sets the target iteration count.\n * @param options The behaviour tree options object.\n */\n private setTargetIterationCount = (options: BehaviourTreeOptions) => {\n // Are we dealing with an explicit iteration count or will we be randomly picking a iteration count between the min and max iteration count.\n if (this.iterations !== null) {\n this.targetIterationCount = this.iterations;\n } else if (this.iterationsMin !== null && this.iterationsMax !== null) {\n // We will be picking a random iteration count between a min and max iteration count, if the optional 'random'\n // behaviour tree function option is defined then we will be using that, otherwise we will fall back to using Math.random.\n const random = typeof options.random === \"function\" ? options.random : Math.random;\n\n // Pick a random iteration count between a min and max iteration count.\n this.targetIterationCount = Math.floor(\n random() * (this.iterationsMax - this.iterationsMin + 1) + this.iterationsMin\n );\n } else {\n this.targetIterationCount = null;\n }\n };\n}\n", "import Node from \"../Node\";\nimport Decorator from \"./Decorator\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A RETRY node.\n * The node has a single child which can have:\n * -- A number of iterations for which to repeat the child node.\n * -- An infinite repeat loop if neither an iteration count or a condition function is defined.\n * The RETRY node will stop and have a 'SUCCEEDED' state if its child is ever in a 'SUCCEEDED' state after an update.\n * The RETRY node will attempt to move on to the next iteration if its child is ever in a 'FAILED' state.\n */\nexport default class Retry extends Decorator {\n /**\n * @param attributes The node attributes.\n * @param attempts The number of attempts to retry the child node.\n * @param attemptsMin The minimum possible number of attempts to retry the child node.\n * @param attemptsMax The maximum possible number of attempts to retry the child node.\n * @param child The child node.\n */\n constructor(\n attributes: Attribute[],\n private attempts: number | null,\n private attemptsMin: number | null,\n private attemptsMax: number | null,\n child: Node\n ) {\n super(\"retry\", attributes, child);\n }\n\n /**\n * The number of target attempts to make.\n */\n private targetAttemptCount: number | null = null;\n\n /**\n * The current attempt count.\n */\n private currentAttemptCount: number = 0;\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // If this node is in the READY state then we need to reset the child and the target attempt count.\n if (this.is(State.READY)) {\n // Reset the child node.\n this.child.reset();\n\n // Reset the current attempt count.\n this.currentAttemptCount = 0;\n\n // Set the target attempt count.\n this.setTargetAttemptCount(options);\n }\n\n // Do a check to see if we can attempt. If we can then this node will move into the 'RUNNING' state.\n // If we cannot attempt then we have hit our target attempt count, which means that the node has succeeded.\n if (this.canAttempt()) {\n // This node is in the running state and can do its initial attempt.\n this.setState(State.RUNNING);\n\n // We may have already completed an attempt, meaning that the child node will be in the FAILED state.\n // If this is the case then we will have to reset the child node now.\n if (this.child.getState() === State.FAILED) {\n this.child.reset();\n }\n\n // Update the child of this node.\n this.child.update(agent, options);\n\n // If the child moved into the SUCCEEDED state when we updated it then there is nothing left to do and this node has also succeeded.\n // If it has moved into the FAILED state then we have completed the current attempt.\n if (this.child.getState() === State.SUCCEEDED) {\n // The child has succeeded, meaning that this node has succeeded.\n this.setState(State.SUCCEEDED);\n\n return;\n } else if (this.child.getState() === State.FAILED) {\n // We have completed an attempt.\n this.currentAttemptCount += 1;\n }\n } else {\n // This node is in the 'FAILED' state as we cannot iterate any more.\n this.setState(State.FAILED);\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => {\n if (this.attempts !== null) {\n return `RETRY ${this.attempts}x`;\n } else if (this.attemptsMin !== null && this.attemptsMax !== null) {\n return `RETRY ${this.attemptsMin}x-${this.attemptsMax}x`;\n } else {\n return \"RETRY\";\n }\n };\n\n /**\n * Reset the state of the node.\n */\n reset = () => {\n // Reset the state of this node.\n this.setState(State.READY);\n\n // Reset the current attempt count.\n this.currentAttemptCount = 0;\n\n // Reset the child node.\n this.child.reset();\n };\n\n /**\n * Gets whether an attempt can be made.\n * @returns Whether an attempt can be made.\n */\n canAttempt = () => {\n if (this.targetAttemptCount !== null) {\n // We can attempt as long as we have not reached our target attempt count.\n return this.currentAttemptCount < this.targetAttemptCount;\n }\n\n // If neither an attempt count or a condition function were defined then we can attempt indefinitely.\n return true;\n };\n\n /**\n * Sets the target attempt count.\n * @param options The behaviour tree options object.\n */\n setTargetAttemptCount = (options: BehaviourTreeOptions) => {\n // Are we dealing with an explicit attempt count or will we be randomly picking an attempt count between the min and max attempt count.\n if (this.attempts !== null) {\n this.targetAttemptCount = this.attempts;\n } else if (this.attemptsMin !== null && this.attemptsMax !== null) {\n // We will be picking a random attempt count between a min and max attempt count, if the optional 'random'\n // behaviour tree function option is defined then we will be using that, otherwise we will fall back to using Math.random.\n const random = typeof options.random === \"function\" ? options.random : Math.random;\n\n // Pick a random attempt count between a min and max attempt count.\n this.targetAttemptCount = Math.floor(\n random() * (this.attemptsMax - this.attemptsMin + 1) + this.attemptsMin\n );\n } else {\n this.targetAttemptCount = null;\n }\n };\n}\n", "import Decorator from \"./Decorator\";\nimport State from \"../../State\";\nimport Node from \"../Node\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A Flip node.\n * This node wraps a single child and will flip the state of the child state.\n */\nexport default class Flip extends Decorator {\n /**\n * @param attributes The node attributes.\n * @param child The child node.\n */\n constructor(attributes: Attribute[], child: Node) {\n super(\"flip\", attributes, child);\n }\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // If the child has never been updated or is running then we will need to update it now.\n if (this.child.getState() === State.READY || this.child.getState() === State.RUNNING) {\n this.child.update(agent, options);\n }\n\n // The state of this node will depend in the state of its child.\n switch (this.child.getState()) {\n case State.RUNNING:\n this.setState(State.RUNNING);\n break;\n\n case State.SUCCEEDED:\n this.setState(State.FAILED);\n break;\n\n case State.FAILED:\n this.setState(State.SUCCEEDED);\n break;\n\n default:\n this.setState(State.READY);\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => \"FLIP\";\n}\n", "import Node from \"../Node\";\nimport Decorator from \"./Decorator\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A Succeed node.\n * This node wraps a single child and will always move to the 'SUCCEEDED' state when the child moves to a 'SUCCEEDED' or 'FAILED' state.\n */\nexport default class Succeed extends Decorator {\n /**\n * @param attributes The node attributes.\n * @param child The child node.\n */\n constructor(attributes: Attribute[], child: Node) {\n super(\"succeed\", attributes, child);\n }\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // If the child has never been updated or is running then we will need to update it now.\n if (this.child.getState() === State.READY || this.child.getState() === State.RUNNING) {\n this.child.update(agent, options);\n }\n\n // The state of this node will depend in the state of its child.\n switch (this.child.getState()) {\n case State.RUNNING:\n this.setState(State.RUNNING);\n break;\n\n case State.SUCCEEDED:\n case State.FAILED:\n this.setState(State.SUCCEEDED);\n break;\n\n default:\n this.setState(State.READY);\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => \"SUCCEED\";\n}\n", "import Node from \"../Node\";\nimport Decorator from \"./Decorator\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A Fail node.\n * This node wraps a single child and will always move to the 'FAILED' state when the child moves to a 'SUCCEEDED' or 'FAILED' state.\n */\nexport default class Fail extends Decorator {\n /**\n * @param attributes The node attributes.\n * @param child The child node.\n */\n constructor(attributes: Attribute[], child: Node) {\n super(\"fail\", attributes, child);\n }\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // If the child has never been updated or is running then we will need to update it now.\n if (this.child.getState() === State.READY || this.child.getState() === State.RUNNING) {\n this.child.update(agent, options);\n }\n\n // The state of this node will depend in the state of its child.\n switch (this.child.getState()) {\n case State.RUNNING:\n this.setState(State.RUNNING);\n break;\n\n case State.SUCCEEDED:\n case State.FAILED:\n this.setState(State.FAILED);\n break;\n\n default:\n this.setState(State.READY);\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => \"FAIL\";\n}\n", "import createLotto from \"lotto-draw\";\n\nimport Node from \"../Node\";\nimport Composite from \"./Composite\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A LOTTO node.\n * A winning child is picked on the initial update of this node, based on ticket weighting.\n * The state of this node will match the state of the winning child.\n */\nexport default class Lotto extends Composite {\n /**\n * @param attributes The node attributes.\n * @param tickets The child node tickets.\n * @param children The child nodes.\n */\n constructor(attributes: Attribute[], private tickets: number[], children: Node[]) {\n super(\"lotto\", attributes, children);\n }\n\n /**\n * The child node selected to be the active one.\n */\n private selectedChild: Node | undefined;\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // If this node is in the READY state then we need to pick a winning child node.\n if (this.is(State.READY)) {\n // Create a lotto draw with which to randomly pick a child node to become the active one.\n const lottoDraw = createLotto({\n // Hook up the optional 'random' behaviour tree function option to the one used by 'lotto-draw'.\n random: options.random,\n // Pass in each child node as a participant in the lotto draw with their respective ticket count.\n participants: this.children.map((child, index) => [child, this.tickets[index] || 1])\n });\n\n // Randomly pick a child based on ticket weighting, this will become the active child for this composite node.\n this.selectedChild = lottoDraw.draw() || undefined;\n }\n\n // If something went wrong and we don't have an active child then we should throw an error.\n if (!this.selectedChild) {\n throw new Error(\"failed to update lotto node as it has no active child\");\n }\n\n // If the selected child has never been updated or is running then we will need to update it now.\n if (this.selectedChild.getState() === State.READY || this.selectedChild.getState() === State.RUNNING) {\n this.selectedChild.update(agent, options);\n }\n\n // The state of the lotto node is the state of its selected child.\n this.setState(this.selectedChild.getState());\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => (this.tickets.length ? `LOTTO [${this.tickets.join(\",\")}]` : \"LOTTO\");\n}\n", "import Node from \"../Node\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\n\n/**\n * A composite node that wraps child nodes.\n */\nexport default abstract class Composite extends Node {\n /**\n * @param type The node type.\n * @param attributes The node attributes.\n * @param children The child nodes.\n */\n constructor(type: string, attributes: Attribute[], protected children: Node[]) {\n super(type, attributes, []);\n }\n\n /**\n * Gets whether this node is a leaf node.\n */\n isLeafNode = () => false;\n\n /**\n * Gets the children of this node.\n */\n getChildren = () => this.children;\n\n /**\n * Reset the state of the node.\n */\n reset = () => {\n // Reset the state of this node.\n this.setState(State.READY);\n\n // Reset the state of any child nodes.\n this.getChildren().forEach((child) => child.reset());\n };\n\n /**\n * Abort the running of this node.\n * @param agent The agent.\n */\n abort = (agent: Agent) => {\n // There is nothing to do if this node is not in the running state.\n if (!this.is(State.RUNNING)) {\n return;\n }\n\n // Abort any child nodes.\n this.getChildren().forEach((child) => child.abort(agent));\n\n // Reset the state of this node.\n this.reset();\n\n this.getAttribute(\"exit\")?.callAgentFunction(agent, false, true);\n };\n}\n", "import Composite from \"./Composite\";\nimport Node from \"../Node\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A SELECTOR node.\n * The child nodes are executed in sequence until one succeeds or all fail.\n */\nexport default class Selector extends Composite {\n /**\n * @param attributes The node attributes.\n * @param children The child nodes.\n */\n constructor(attributes: Attribute[], protected children: Node[]) {\n super(\"selector\", attributes, children);\n }\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // Iterate over all of the children of this node.\n for (const child of this.children) {\n // If the child has never been updated or is running then we will need to update it now.\n if (child.getState() === State.READY || child.getState() === State.RUNNING) {\n // Update the child of this node.\n child.update(agent, options);\n }\n\n // If the current child has a state of 'SUCCEEDED' then this node is also a 'SUCCEEDED' node.\n if (child.getState() === State.SUCCEEDED) {\n // This node is a 'SUCCEEDED' node.\n this.setState(State.SUCCEEDED);\n\n // There is no need to check the rest of the selector nodes.\n return;\n }\n\n // If the current child has a state of 'FAILED' then we should move on to the next child.\n if (child.getState() === State.FAILED) {\n // Find out if the current child is the last one in the selector.\n // If it is then this sequence node has also failed.\n if (this.children.indexOf(child) === this.children.length - 1) {\n // This node is a 'FAILED' node.\n this.setState(State.FAILED);\n\n // There is no need to check the rest of the selector as we have completed it.\n return;\n } else {\n // The child node failed, try the next one.\n continue;\n }\n }\n\n // The node should be in the 'RUNNING' state.\n if (child.getState() === State.RUNNING) {\n // This node is a 'RUNNING' node.\n this.setState(State.RUNNING);\n\n // There is no need to check the rest of the selector as the current child is still running.\n return;\n }\n\n // The child node was not in an expected state.\n throw new Error(\"child node was not in an expected state.\");\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => \"SELECTOR\";\n}\n", "import Composite from \"./Composite\";\nimport Node from \"../Node\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A SEQUENCE node.\n * The child nodes are executed in sequence until one fails or all succeed.\n */\nexport default class Sequence extends Composite {\n /**\n * @param attributes The node attributes.\n * @param children The child nodes.\n */\n constructor(attributes: Attribute[], protected children: Node[]) {\n super(\"sequence\", attributes, children);\n }\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // Iterate over all of the children of this node.\n for (const child of this.children) {\n // If the child has never been updated or is running then we will need to update it now.\n if (child.getState() === State.READY || child.getState() === State.RUNNING) {\n // Update the child of this node.\n child.update(agent, options);\n }\n\n // If the current child has a state of 'SUCCEEDED' then we should move on to the next child.\n if (child.getState() === State.SUCCEEDED) {\n // Find out if the current child is the last one in the sequence.\n // If it is then this sequence node has also succeeded.\n if (this.children.indexOf(child) === this.children.length - 1) {\n // This node is a 'SUCCEEDED' node.\n this.setState(State.SUCCEEDED);\n\n // There is no need to check the rest of the sequence as we have completed it.\n return;\n } else {\n // The child node succeeded, but we have not finished the sequence yet.\n continue;\n }\n }\n\n // If the current child has a state of 'FAILED' then this node is also a 'FAILED' node.\n if (child.getState() === State.FAILED) {\n // This node is a 'FAILED' node.\n this.setState(State.FAILED);\n\n // There is no need to check the rest of the sequence.\n return;\n }\n\n // The node should be in the 'RUNNING' state.\n if (child.getState() === State.RUNNING) {\n // This node is a 'RUNNING' node.\n this.setState(State.RUNNING);\n\n // There is no need to check the rest of the sequence as the current child is still running.\n return;\n }\n\n // The child node was not in an expected state.\n throw new Error(\"child node was not in an expected state.\");\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => \"SEQUENCE\";\n}\n", "import Composite from \"./Composite\";\nimport State from \"../../State\";\nimport Node from \"../Node\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A PARALLEL node.\n * The child nodes are executed concurrently until one fails or all succeed.\n */\nexport default class Parallel extends Composite {\n /**\n * @param attributes The node attributes.\n * @param children The child nodes.\n */\n constructor(attributes: Attribute[], children: Node[]) {\n super(\"parallel\", attributes, children);\n }\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // Keep a count of the number of succeeded child nodes.\n let succeededCount = 0;\n\n let hasChildFailed = false;\n\n // Iterate over all of the children of this node.\n for (const child of this.children) {\n // If the child has never been updated or is running then we will need to update it now.\n if (child.getState() === State.READY || child.getState() === State.RUNNING) {\n // Update the child of this node.\n child.update(agent, options);\n }\n\n // If the current child has a state of 'SUCCEEDED' then we should move on to the next child.\n if (child.getState() === State.SUCCEEDED) {\n // The child node has succeeded, keep track of this to determine if all children have.\n succeededCount++;\n\n // The child node succeeded, but we have not finished checking every child node yet.\n continue;\n }\n\n // If the current child has a state of 'FAILED' then this node is also a 'FAILED' node.\n if (child.getState() === State.FAILED) {\n hasChildFailed = true;\n\n // There is no need to check the rest of the children.\n break;\n }\n\n // The node should be in the 'RUNNING' state.\n if (child.getState() !== State.RUNNING) {\n // The child node was not in an expected state.\n throw new Error(\"child node was not in an expected state.\");\n }\n }\n\n if (hasChildFailed) {\n // This node is a 'FAILED' node.\n this.setState(State.FAILED);\n\n // Abort every running child.\n for (const child of this.children) {\n if (child.getState() === State.RUNNING) {\n child.abort(agent);\n }\n }\n } else {\n // If all children have succeeded then this node has also succeeded, otherwise it is still running.\n this.setState(succeededCount === this.children.length ? State.SUCCEEDED : State.RUNNING);\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => \"PARALLEL\";\n}\n", "import { AnyArgument } from \"../RootAstNodesBuilder\";\nimport Guard from \"./guards/Guard\";\n\nexport type AttributeDetails = {\n /** The attribute type. */\n type: string;\n\n /** The attribute arguments. */\n args: AnyArgument[];\n};\n\n/**\n * A base node attribute.\n */\nexport default abstract class Attribute {\n /**\n * @param type The node attribute type.\n * @param args The array of attribute argument definitions.\n */\n constructor(protected type: string, protected args: AnyArgument[]) {}\n\n /**\n * Gets the type of the attribute.\n */\n getType = () => this.type;\n\n /**\n * Gets the array of attribute argument definitions.\n */\n getArguments = () => this.args;\n\n /**\n * Gets the attribute details.\n */\n abstract getDetails(): TAttributeDetails;\n\n /**\n * Gets whether this attribute is a guard.\n */\n abstract isGuard: () => this is Guard;\n}\n", "import { Agent } from \"../../Agent\";\nimport { AnyArgument } from \"../../RootAstNodesBuilder\";\nimport Attribute, { AttributeDetails } from \"../Attribute\";\n\nexport type GuardAttributeDetails = {\n /** The name of the condition function that determines whether the guard is satisfied. */\n condition: string;\n} & AttributeDetails;\n\n/**\n * A base node guard attribute.\n */\nexport default abstract class Guard extends Attribute {\n /**\n * @param type The node attribute type.\n * @param args The array of decorator argument definitions.\n * @param condition The name of the condition function that determines whether the guard is satisfied.\n */\n constructor(type: string, args: AnyArgument[], private condition: string) {\n super(type, args);\n }\n\n /**\n * Gets the name of the condition function that determines whether the guard is satisfied.\n */\n getCondition = () => this.condition;\n\n /**\n * Gets whether this attribute is a guard.\n */\n isGuard = () => true;\n\n /**\n * Gets the attribute details.\n */\n getDetails(): GuardAttributeDetails {\n return {\n type: this.getType(),\n args: this.getArguments(),\n condition: this.getCondition()\n };\n }\n\n /**\n * Gets whether the guard is satisfied.\n * @param agent The agent.\n * @returns Whether the guard is satisfied.\n */\n abstract isSatisfied(agent: Agent): boolean;\n}\n", "import Guard from \"./Guard\";\nimport Lookup from \"../../Lookup\";\nimport { Agent } from \"../../Agent\";\nimport { AnyArgument } from \"../../RootAstNodesBuilder\";\n\n/**\n * A WHILE guard which is satisfied as long as the given condition remains true.\n */\nexport default class While extends Guard {\n /**\n * @param condition The name of the condition function that determines whether the guard is satisfied.\n * @param args The array of decorator argument definitions.\n */\n constructor(condition: string, args: AnyArgument[]) {\n super(\"while\", args, condition);\n }\n\n /**\n * Gets whether the guard is satisfied.\n * @param agent The agent.\n * @returns Whether the guard is satisfied.\n */\n isSatisfied = (agent: Agent) => {\n // Attempt to get the invoker for the condition function.\n const conditionFuncInvoker = Lookup.getFuncInvoker(agent, this.getCondition());\n\n // The condition function should be defined.\n if (conditionFuncInvoker === null) {\n throw new Error(\n `cannot evaluate node guard as the condition '${this.getCondition()}' function is not defined on the agent and has not been registered`\n );\n }\n\n // Call the condition function to determine whether this guard is satisfied.\n return !!conditionFuncInvoker(this.args);\n };\n}\n", "import Guard from \"./Guard\";\nimport Lookup from \"../../Lookup\";\nimport { Agent } from \"../../Agent\";\nimport { AnyArgument } from \"../../RootAstNodesBuilder\";\n\n/**\n * An UNTIL guard which is satisfied as long as the given condition remains false.\n */\nexport default class Until extends Guard {\n /**\n * @param condition The name of the condition function that determines whether the guard is satisfied.\n * @param args The array of decorator argument definitions.\n */\n constructor(condition: string, args: AnyArgument[]) {\n super(\"until\", args, condition);\n }\n\n /**\n * Gets whether the guard is satisfied.\n * @param agent The agent.\n * @returns Whether the guard is satisfied.\n */\n isSatisfied = (agent: Agent) => {\n // Attempt to get the invoker for the condition function.\n const conditionFuncInvoker = Lookup.getFuncInvoker(agent, this.getCondition());\n\n // The condition function should be defined.\n if (conditionFuncInvoker === null) {\n throw new Error(\n `cannot evaluate node guard as the condition '${this.getCondition()}' function is not defined on the agent and has not been registered`\n );\n }\n\n // Call the condition function to determine whether this guard is satisfied.\n return !!!conditionFuncInvoker(this.args);\n };\n}\n", "import { Agent } from \"../../Agent\";\nimport { AnyArgument } from \"../../RootAstNodesBuilder\";\nimport Attribute, { AttributeDetails } from \"../Attribute\";\n\nexport type CallbackAttributeDetails = {\n /** The name of the agent function that is called. */\n functionName: string;\n} & AttributeDetails;\n\n/**\n * A base node callback attribute.\n */\nexport default abstract class Callback extends Attribute {\n /**\n * @param type The node attribute type.\n * @param args The array of decorator argument definitions.\n * @param functionName The name of the agent function to call.\n */\n constructor(type: string, args: AnyArgument[], private functionName: string) {\n super(type, args);\n }\n\n /**\n * Gets the name of the agent function to call.\n */\n getFunctionName = () => this.functionName;\n\n /**\n * Gets whether this attribute is a guard.\n */\n isGuard = () => false;\n\n /**\n * Gets the attribute details.\n */\n getDetails(): CallbackAttributeDetails {\n return {\n type: this.getType(),\n args: this.getArguments(),\n functionName: this.getFunctionName()\n };\n }\n\n /**\n * Attempt to call the agent function that this callback refers to.\n * @param agent The agent.\n */\n abstract callAgentFunction: (agent: Agent, isSuccess: boolean, isAborted: boolean) => void;\n}\n", "import Callback from \"./Callback\";\nimport Lookup from \"../../Lookup\";\nimport { Agent } from \"../../Agent\";\nimport { AnyArgument } from \"../../RootAstNodesBuilder\";\n\n/**\n * An ENTRY callback which defines an agent function to call when the associated node is updated and moves out of running state.\n */\nexport default class Entry extends Callback {\n /**\n * @param functionName The name of the agent function to call.\n * @param args The array of callback argument definitions.\n */\n constructor(functionName: string, args: AnyArgument[]) {\n super(\"entry\", args, functionName);\n }\n\n /**\n * Attempt to call the agent function that this callback refers to.\n * @param agent The agent.\n */\n callAgentFunction = (agent: Agent) => {\n // Attempt to get the invoker for the callback function.\n const callbackFuncInvoker = Lookup.getFuncInvoker(agent, this.getFunctionName());\n\n // The callback function should be defined.\n if (callbackFuncInvoker === null) {\n throw new Error(\n `cannot call entry function '${this.getFunctionName()}' as is not defined on the agent and has not been registered`\n );\n }\n\n // Call the callback function.\n callbackFuncInvoker(this.args);\n };\n}\n", "import Callback from \"./Callback\";\nimport Lookup, { AnyExitArgument } from \"../../Lookup\";\nimport { Agent } from \"../../Agent\";\nimport { AnyArgument } from \"../../RootAstNodesBuilder\";\n\n/**\n * An EXIT callback which defines an agent function to call when the associated node is updated and moves to a finished state or is aborted.\n */\nexport default class Exit extends Callback {\n /**\n * @param functionName The name of the agent function to call.\n * @param args The array of callback argument definitions.\n */\n constructor(functionName: string, args: AnyArgument[]) {\n super(\"exit\", args, functionName);\n }\n\n /**\n * Attempt to call the agent function that this callback refers to.\n * @param agent The agent.\n * @param isSuccess Whether the decorated node was left with a success state.\n * @param isAborted Whether the decorated node was aborted.\n */\n callAgentFunction = (agent: Agent, isSuccess: boolean, isAborted: boolean) => {\n // Attempt to get the invoker for the callback function.\n const callbackFuncInvoker = Lookup.getFuncInvoker(agent, this.getFunctionName());\n\n // The callback function should be defined.\n if (callbackFuncInvoker === null) {\n throw new Error(\n `cannot call exit function '${this.getFunctionName()}' as is not defined on the agent and has not been registered`\n );\n }\n\n // Call the callback function\n callbackFuncInvoker([{ value: { succeeded: isSuccess, aborted: isAborted } }, ...this.args]);\n };\n}\n", "import Callback from \"./Callback\";\nimport Lookup from \"../../Lookup\";\nimport { Agent } from \"../../Agent\";\nimport { AnyArgument } from \"../../RootAstNodesBuilder\";\n\n/**\n * A STEP callback which defines an agent function to call when the associated node is updated.\n */\nexport default class Step extends Callback {\n /**\n * @param functionName The name of the agent function to call.\n * @param args The array of callback argument definitions.\n */\n constructor(functionName: string, args: AnyArgument[]) {\n super(\"step\", args, functionName);\n }\n\n /**\n * Attempt to call the agent function that this callback refers to.\n * @param agent The agent.\n */\n callAgentFunction = (agent: Agent) => {\n // Attempt to get the invoker for the callback function.\n const callbackFuncInvoker = Lookup.getFuncInvoker(agent, this.getFunctionName());\n\n // The callback function should be defined.\n if (callbackFuncInvoker === null) {\n throw new Error(\n `cannot call step function '${this.getFunctionName()}' as is not defined on the agent and has not been registered`\n );\n }\n\n // Call the callback function.\n callbackFuncInvoker(this.args);\n };\n}\n", "import Action from \"./nodes/leaf/Action\";\nimport Condition from \"./nodes/leaf/Condition\";\nimport Wait from \"./nodes/leaf/Wait\";\nimport Root from \"./nodes/decorator/Root\";\nimport Repeat from \"./nodes/decorator/Repeat\";\nimport Retry from \"./nodes/decorator/Retry\";\nimport Flip from \"./nodes/decorator/Flip\";\nimport Succeed from \"./nodes/decorator/Succeed\";\nimport Fail from \"./nodes/decorator/Fail\";\nimport Lotto from \"./nodes/composite/Lotto\";\nimport Selector from \"./nodes/composite/Selector\";\nimport Sequence from \"./nodes/composite/Sequence\";\nimport Parallel from \"./nodes/composite/Parallel\";\nimport Node from \"./nodes/Node\";\nimport While from \"./attributes/guards/While\";\nimport Until from \"./attributes/guards/Until\";\nimport Entry from \"./attributes/callbacks/Entry\";\nimport Exit from \"./attributes/callbacks/Exit\";\nimport Step from \"./attributes/callbacks/Step\";\nimport Callback from \"./attributes/callbacks/Callback\";\nimport Guard from \"./attributes/guards/Guard\";\nimport Attribute from \"./attributes/Attribute\";\nimport Composite from \"./nodes/composite/Composite\";\nimport Decorator from \"./nodes/decorator/Decorator\";\nimport Leaf from \"./nodes/leaf/Leaf\";\n\nexport type Argument = {\n value: T;\n type: string; // Used for validation.\n};\ntype NullArgument = Argument & {\n type: \"null\";\n};\ntype BooleanArgument = Argument & {\n type: \"boolean\";\n};\ntype NumberArgument = Argument & {\n type: \"number\";\n isInteger: boolean; // Used for validation.\n};\ntype StringPlaceholderArgument = Argument & {\n type: \"string\";\n};\ntype IdentifierArgument = Argument & {\n type: \"identifier\";\n};\nexport type AnyArgument =\n | NullArgument\n | BooleanArgument\n | NumberArgument\n | StringPlaceholderArgument\n | IdentifierArgument;\n\n/**\n * The node attribute factories.\n */\nconst AttributeFactories: {\n [key: string]: (functionName: string, attributeArguments: AnyArgument[]) => Callback | Guard;\n} = {\n WHILE: (condition: string, attributeArguments: AnyArgument[]) => new While(condition, attributeArguments),\n UNTIL: (condition: string, attributeArguments: AnyArgument[]) => new Until(condition, attributeArguments),\n ENTRY: (functionName: string, attributeArguments: AnyArgument[]) => new Entry(functionName, attributeArguments),\n EXIT: (functionName: string, attributeArguments: AnyArgument[]) => new Exit(functionName, attributeArguments),\n STEP: (functionName: string, attributeArguments: AnyArgument[]) => new Step(functionName, attributeArguments)\n};\n\ntype Validatable = {\n children?: AstNode[];\n validate: (depth: number) => void;\n};\n\ntype NodeInstanceCreator = (\n namedRootNodeProvider: (name: string) => RootAstNode,\n visitedBranches: string[]\n) => T;\n\nexport type AstNode = Validatable & {\n type: string;\n createNodeInstance: NodeInstanceCreator;\n};\n\nexport type LeafAstNode = AstNode & {\n type: \"action\" | \"condition\" | \"wait\";\n attributes: Attribute[];\n};\n\nexport type CompositeAstNode = AstNode & {\n type: \"lotto\" | \"parallel\" | \"selector\" | \"sequence\";\n attributes: Attribute[];\n children: AstNode[];\n};\n\nexport type DecoratorAstNode = AstNode & {\n type: \"fail\" | \"flip\" | \"repeat\" | \"retry\" | \"root\" | \"succeed\";\n attributes: Attribute[];\n children: AstNode[];\n};\n\nexport type BranchAstNode = AstNode & {\n type: \"branch\";\n branchName: \"\" | string;\n};\n\nexport type LottoAstNode = CompositeAstNode & {\n type: \"lotto\";\n tickets: number[];\n};\n\nexport type RootAstNode = DecoratorAstNode & {\n type: \"root\";\n name: null | string;\n};\n\nexport type RepeatAstNode = DecoratorAstNode & {\n type: \"repeat\";\n iterations: number | null;\n iterationsMin: number | null;\n iterationsMax: number | null;\n};\n\nexport type RetryAstNode = DecoratorAstNode & {\n type: \"retry\";\n attempts: number | null;\n attemptsMin: number | null;\n attemptsMax: number | null;\n};\n\nexport type ActionAstNode = LeafAstNode & {\n type: \"action\";\n actionName: string;\n actionArguments: AnyArgument[];\n};\n\nexport type ConditionAstNode = LeafAstNode & {\n type: \"condition\";\n conditionName: string;\n conditionArguments: AnyArgument[];\n};\n\nexport type WaitAstNode = LeafAstNode & {\n type: \"wait\";\n duration: number | null;\n durationMin: number | null;\n durationMax: number | null;\n};\n\nexport type AnyAstNode =\n | BranchAstNode\n | CompositeAstNode\n | LottoAstNode\n | DecoratorAstNode\n | RootAstNode\n | RepeatAstNode\n | RetryAstNode\n | LeafAstNode\n | ActionAstNode\n | ConditionAstNode\n | WaitAstNode;\n\n/**\n * The AST node factories.\n */\nconst ASTNodeFactories = {\n ROOT: (): RootAstNode => ({\n type: \"root\",\n attributes: [],\n name: null,\n children: [],\n validate(depth: number) {\n // A root node cannot be the child of another node.\n if (depth > 1) {\n throw new Error(\"a root node cannot be the child of another node\");\n }\n\n // A root node must have a single child node.\n if (this.children.length !== 1) {\n throw new Error(\"a root node must have a single child\");\n }\n },\n createNodeInstance(namedRootNodeProvider, visitedBranches) {\n return new Root(\n this.attributes,\n this.children![0].createNodeInstance(namedRootNodeProvider, visitedBranches.slice())\n );\n }\n }),\n BRANCH: (): BranchAstNode => ({\n type: \"branch\",\n branchName: \"\",\n validate() {},\n createNodeInstance(namedRootNodeProvider, visitedBranches) {\n // Try to find the root node with a matching branch name.\n const targetRootNode = namedRootNodeProvider(this.branchName);\n\n // If we have already visited this branch then we have a circular dependency.\n if (visitedBranches.indexOf(this.branchName) !== -1) {\n throw new Error(`circular dependency found in branch node references for branch '${this.branchName}'`);\n }\n\n // If we have a target root node, then the node instance we want will be the first and only child of the referenced root node.\n if (targetRootNode) {\n return targetRootNode\n .createNodeInstance(namedRootNodeProvider, visitedBranches.concat(this.branchName))\n .getChildren()[0];\n } else {\n throw new Error(`branch references root node '${this.branchName}' which has not been defined`);\n }\n }\n }),\n SELECTOR: (): CompositeAstNode => ({\n type: \"selector\",\n attributes: [],\n children: [],\n validate() {\n // A selector node must have at least a single node.\n if (this.children.length < 1) {\n throw new Error(\"a selector node must have at least a single child\");\n }\n },\n createNodeInstance(namedRootNodeProvider, visitedBranches) {\n return new Selector(\n this.attributes,\n this.children.map((child) => child.createNodeInstance(namedRootNodeProvider, visitedBranches.slice()))\n );\n }\n }),\n SEQUENCE: (): CompositeAstNode => ({\n type: \"sequence\",\n attributes: [],\n children: [],\n validate() {\n // A sequence node must have at least a single node.\n if (this.children.length < 1) {\n throw new Error(\"a sequence node must have at least a single child\");\n }\n },\n createNodeInstance(namedRootNodeProvider, visitedBranches) {\n return new Sequence(\n this.attributes,\n this.children.map((child) => child.createNodeInstance(namedRootNodeProvider, visitedBranches.slice()))\n );\n }\n }),\n PARALLEL: (): CompositeAstNode => ({\n type: \"parallel\",\n attributes: [],\n children: [],\n validate() {\n // A parallel node must have at least a single node.\n if (this.children.length < 1) {\n throw new Error(\"a parallel node must have at least a single child\");\n }\n },\n createNodeInstance(namedRootNodeProvider, visitedBranches) {\n return new Parallel(\n this.attributes,\n this.children.map((child) => child.createNodeInstance(namedRootNodeProvider, visitedBranches.slice()))\n );\n }\n }),\n LOTTO: (): LottoAstNode => ({\n type: \"lotto\",\n attributes: [],\n children: [],\n tickets: [],\n validate() {\n // A lotto node must have at least a single node.\n if (this.children!.length < 1) {\n throw new Error(\"a lotto node must have at least a single child\");\n }\n },\n createNodeInstance(namedRootNodeProvider, visitedBranches) {\n return new Lotto(\n this.attributes,\n this.tickets!,\n this.children!.map((child) => child.createNodeInstance(namedRootNodeProvider, visitedBranches.slice()))\n );\n }\n }),\n REPEAT: (): RepeatAstNode => ({\n type: \"repeat\",\n attributes: [],\n iterations: null,\n iterationsMin: null,\n iterationsMax: null,\n children: [],\n validate() {\n // A repeat node must have a single node.\n if (this.children!.length !== 1) {\n throw new Error(\"a repeat node must have a single child\");\n }\n\n if (this.iterations !== null) {\n // A repeat node must have a positive number of iterations if defined.\n if (this.iterations < 0) {\n throw new Error(\"a repeat node must have a positive number of iterations if defined\");\n }\n } else if (this.iterationsMin !== null && this.iterationsMax !== null) {\n // A repeat node must have a positive min and max iteration count if they are defined.\n if (this.iterationsMin < 0 || this.iterationsMax < 0) {\n throw new Error(\n \"a repeat node must have a positive minimum and maximum iteration count if defined\"\n );\n }\n\n // A repeat node must not have an minimum iteration count that exceeds the maximum iteration count.\n if (this.iterationsMin > this.iterationsMax) {\n throw new Error(\n \"a repeat node must not have a minimum iteration count that exceeds the maximum iteration count\"\n );\n }\n } else {\n // If we have no explicit iteration count or a minimum and maximum iteration count set then we are dealing with a repeat node that iterates indefinitely.\n }\n },\n createNodeInstance(namedRootNodeProvider, visitedBranches) {\n return new Repeat(\n this.attributes,\n this.iterations,\n this.iterationsMin,\n this.iterationsMax,\n this.children![0].createNodeInstance(namedRootNodeProvider, visitedBranches.slice())\n );\n }\n }),\n RETRY: (): RetryAstNode => ({\n type: \"retry\",\n attributes: [],\n attempts: null,\n attemptsMin: null,\n attemptsMax: null,\n children: [],\n validate() {\n // A retry node must have a single node.\n if (this.children!.length !== 1) {\n throw new Error(\"a retry node must have a single child\");\n }\n\n if (this.attempts !== null) {\n // A retry node must have a positive number of attempts if defined.\n if (this.attempts < 0) {\n throw new Error(\"a retry node must have a positive number of attempts if defined\");\n }\n } else if (this.attemptsMin !== null && this.attemptsMax !== null) {\n // A retry node must have a positive min and max attempts count if they are defined.\n if (this.attemptsMin < 0 || this.attemptsMax < 0) {\n throw new Error(\"a retry node must have a positive minimum and maximum attempt count if defined\");\n }\n\n // A retry node must not have a minimum attempt count that exceeds the maximum attempt count.\n if (this.attemptsMin > this.attemptsMax) {\n throw new Error(\n \"a retry node must not have a minimum attempt count that exceeds the maximum attempt count\"\n );\n }\n } else {\n // If we have no explicit attempt count or a minimum and maximum attempt count set then we are dealing with a retry node that attempts indefinitely.\n }\n },\n createNodeInstance(namedRootNodeProvider, visitedBranches) {\n return new Retry(\n this.attributes,\n this.attempts,\n this.attemptsMin,\n this.attemptsMax,\n this.children![0].createNodeInstance(namedRootNodeProvider, visitedBranches.slice())\n );\n }\n }),\n FLIP: (): DecoratorAstNode => ({\n type: \"flip\",\n attributes: [],\n children: [],\n validate() {\n // A flip node must have a single node.\n if (this.children!.length !== 1) {\n throw new Error(\"a flip node must have a single child\");\n }\n },\n createNodeInstance(namedRootNodeProvider, visitedBranches) {\n return new Flip(\n this.attributes,\n this.children![0].createNodeInstance(namedRootNodeProvider, visitedBranches.slice())\n );\n }\n }),\n SUCCEED: (): DecoratorAstNode => ({\n type: \"succeed\",\n attributes: [],\n children: [],\n validate() {\n // A succeed node must have a single node.\n if (this.children!.length !== 1) {\n throw new Error(\"a succeed node must have a single child\");\n }\n },\n createNodeInstance(namedRootNodeProvider, visitedBranches) {\n return new Succeed(\n this.attributes,\n this.children![0].createNodeInstance(namedRootNodeProvider, visitedBranches.slice())\n );\n }\n }),\n FAIL: (): DecoratorAstNode => ({\n type: \"fail\",\n attributes: [],\n children: [],\n validate() {\n // A fail node must have a single node.\n if (this.children!.length !== 1) {\n throw new Error(\"a fail node must have a single child\");\n }\n },\n createNodeInstance(namedRootNodeProvider, visitedBranches) {\n return new Fail(\n this.attributes,\n this.children![0].createNodeInstance(namedRootNodeProvider, visitedBranches.slice())\n );\n }\n }),\n WAIT: (): WaitAstNode => ({\n type: \"wait\",\n attributes: [],\n duration: null,\n durationMin: null,\n durationMax: null,\n validate() {\n if (this.duration !== null) {\n // If an explict duration was defined then it must be a positive number.\n if (this.duration < 0) {\n throw new Error(\"a wait node must have a positive duration\");\n }\n } else if (this.durationMin !== null && this.durationMax !== null) {\n // A wait node must have a positive min and max duration.\n if (this.durationMin < 0 || this.durationMax < 0) {\n throw new Error(\"a wait node must have a positive minimum and maximum duration\");\n }\n\n // A wait node must not have a minimum duration that exceeds the maximum duration.\n if (this.durationMin > this.durationMax) {\n throw new Error(\"a wait node must not have a minimum duration that exceeds the maximum duration\");\n }\n } else {\n // If we have no explicit duration or duration bounds set then we are dealing with a wait node that waits indefinitely.\n }\n },\n createNodeInstance() {\n return new Wait(this.attributes, this.duration, this.durationMin, this.durationMax);\n }\n }),\n ACTION: (): ActionAstNode => ({\n type: \"action\",\n attributes: [],\n actionName: \"\",\n actionArguments: [],\n validate() {},\n createNodeInstance() {\n return new Action(this.attributes, this.actionName!, this.actionArguments!);\n }\n }),\n CONDITION: (): ConditionAstNode => ({\n type: \"condition\",\n attributes: [],\n conditionName: \"\",\n conditionArguments: [],\n validate() {},\n createNodeInstance() {\n return new Condition(this.attributes, this.conditionName!, this.conditionArguments!);\n }\n })\n};\n\ntype OtherAstNodes = AstNode[];\n\n/**\n * Create an array of root AST nodes based on the given definition.\n * @param definition The definition to parse the AST nodes from.\n * @returns The base definition AST nodes.\n */\nexport default function buildRootASTNodes(definition: string): RootAstNode[] {\n // Swap out any node/attribute argument string literals with a placeholder and get a mapping of placeholders to original values as well as the processed definition.\n const { placeholders, processedDefinition } = substituteStringLiterals(definition);\n\n // Convert the processed definition (with substituted string literals) into an array of raw tokens.\n const tokens = parseTokensFromDefinition(processedDefinition);\n\n // There must be at least 3 tokens for the tree definition to be valid. 'ROOT', '{' and '}'.\n if (tokens.length < 3) {\n throw new Error(\"invalid token count\");\n }\n\n // We should have a matching number of '{' and '}' tokens. If not, then there are scopes that have not been properly closed.\n if (tokens.filter((token) => token === \"{\").length !== tokens.filter((token) => token === \"}\").length) {\n throw new Error(\"scope character mismatch\");\n }\n\n // Create a stack of node children arrays, starting with a definition scope.\n const stack: [RootAstNode[], ...OtherAstNodes[]] = [[]];\n const rootScope = stack[0];\n\n // We should keep processing the raw tokens until we run out of them.\n while (tokens.length) {\n // Grab the next token.\n const token = tokens.shift();\n\n const currentScope = stack[stack.length - 1] as OtherAstNodes;\n\n // How we create the next AST token depends on the current raw token value.\n switch (token!.toUpperCase()) {\n case \"ROOT\": {\n // Create a ROOT AST node.\n const node = ASTNodeFactories.ROOT();\n\n // Push the ROOT node into the current scope.\n rootScope.push(node);\n\n // We may have a root node name defined as an argument.\n if (tokens[0] === \"[\") {\n const rootArguments = getArguments(tokens, placeholders);\n\n // We should have only a single argument that is not an empty string for a root node, which is the root name identifier.\n if (rootArguments.length === 1 && rootArguments[0].type === \"identifier\") {\n // The root name will be the first and only node argument.\n node.name = rootArguments[0].value as string;\n } else {\n throw new Error(\"expected single root name argument\");\n }\n }\n\n // Try to pick any attributes off of the token stack.\n node.attributes = getAttributes(tokens, placeholders);\n\n popAndCheck(tokens, \"{\");\n\n // The new scope is that of the new ROOT nodes children.\n stack.push(node.children!);\n break;\n }\n\n case \"BRANCH\": {\n // Create a BRANCH AST node.\n const node = ASTNodeFactories.BRANCH();\n\n // Push the BRANCH node into the current scope.\n currentScope.push(node);\n\n // We must have arguments defined, as we require a branch name argument.\n if (tokens[0] !== \"[\") {\n throw new Error(\"expected single branch name argument\");\n }\n\n // The branch name will be defined as a node argument.\n const branchArguments = getArguments(tokens, placeholders);\n\n // We should have only a single identifer argument for a branch node, which is the branch name.\n if (branchArguments.length === 1 && branchArguments[0].type === \"identifier\") {\n // The branch name will be the first and only node argument.\n node.branchName = branchArguments[0].value as string;\n } else {\n throw new Error(\"expected single branch name argument\");\n }\n break;\n }\n\n case \"SELECTOR\": {\n // Create a SELECTOR AST node.\n const node = ASTNodeFactories.SELECTOR();\n\n // Push the SELECTOR node into the current scope.\n currentScope.push(node);\n\n // Try to pick any attributes off of the token stack.\n node.attributes = getAttributes(tokens, placeholders);\n\n popAndCheck(tokens, \"{\");\n\n // The new scope is that of the new SELECTOR nodes children.\n stack.push(node.children!);\n break;\n }\n\n case \"SEQUENCE\": {\n // Create a SEQUENCE AST node.\n const node = ASTNodeFactories.SEQUENCE();\n\n // Push the SEQUENCE node into the current scope.\n currentScope.push(node);\n\n // Try to pick any attributes off of the token stack.\n node.attributes = getAttributes(tokens, placeholders);\n\n popAndCheck(tokens, \"{\");\n\n // The new scope is that of the new SEQUENCE nodes children.\n stack.push(node.children!);\n break;\n }\n\n case \"PARALLEL\": {\n // Create a PARALLEL AST node.\n const node = ASTNodeFactories.PARALLEL();\n\n // Push the PARALLEL node into the current scope.\n currentScope.push(node);\n\n // Try to pick any attributes off of the token stack.\n node.attributes = getAttributes(tokens, placeholders);\n\n popAndCheck(tokens, \"{\");\n\n // The new scope is that of the new PARALLEL nodes children.\n stack.push(node.children!);\n break;\n }\n\n case \"LOTTO\": {\n // Create a LOTTO AST node.\n const node = ASTNodeFactories.LOTTO();\n\n // Push the LOTTO node into the current scope.\n currentScope.push(node);\n\n // If the next token is a '[' character then some ticket counts have been defined as arguments.\n if (tokens[0] === \"[\") {\n // Get the ticket count arguments, each argument must be a number.\n node.tickets = getArguments(\n tokens,\n placeholders,\n (arg) => arg.type === \"number\" && !!arg.isInteger,\n \"lotto node ticket counts must be integer values\"\n ).map((argument) => argument.value as number);\n }\n\n // Try to pick any attributes off of the token stack.\n node.attributes = getAttributes(tokens, placeholders);\n\n popAndCheck(tokens, \"{\");\n\n // The new scope is that of the new LOTTO nodes children.\n stack.push(node.children!);\n break;\n }\n\n case \"CONDITION\": {\n // Create a CONDITION AST node.\n const node = ASTNodeFactories.CONDITION();\n\n // Push the CONDITION node into the current scope.\n currentScope.push(node);\n\n // We must have arguments defined, as we require a condition function name argument.\n if (tokens[0] !== \"[\") {\n throw new Error(\"expected condition name identifier argument\");\n }\n\n // Grab the condition node arguments.\n const conditionArguments = getArguments(tokens, placeholders);\n\n // We should have at least a single identifier argument for a condition node, which is the condition function name.\n if (conditionArguments.length && conditionArguments[0].type === \"identifier\") {\n // The condition function name will be the first node argument.\n node.conditionName = conditionArguments.shift()!.value as string;\n } else {\n throw new Error(\"expected condition name identifier argument\");\n }\n\n // Only the first argument should have been an identifier, all following arguments must be string, number, boolean or null.\n conditionArguments\n .filter((arg) => arg.type === \"identifier\")\n .forEach((arg) => {\n throw new Error(\n \"invalid condition node argument value '\" +\n arg.value +\n \"', must be string, number, boolean or null\"\n );\n });\n\n // Any node arguments that follow the condition name identifier will be treated as condition function arguments.\n node.conditionArguments = conditionArguments;\n\n // Try to pick any attributes off of the token stack.\n node.attributes = getAttributes(tokens, placeholders);\n break;\n }\n\n case \"FLIP\": {\n // Create a FLIP AST node.\n const node = ASTNodeFactories.FLIP();\n\n // Push the Flip node into the current scope.\n currentScope.push(node);\n\n // Try to pick any attributes off of the token stack.\n node.attributes = getAttributes(tokens, placeholders);\n\n popAndCheck(tokens, \"{\");\n\n // The new scope is that of the new FLIP nodes children.\n stack.push(node.children!);\n break;\n }\n\n case \"SUCCEED\": {\n // Create a SUCCEED AST node.\n const node = ASTNodeFactories.SUCCEED();\n\n // Push the Succeed node into the current scope.\n currentScope.push(node);\n\n // Try to pick any attributes off of the token stack.\n node.attributes = getAttributes(tokens, placeholders);\n\n popAndCheck(tokens, \"{\");\n\n // The new scope is that of the new Succeed nodes children.\n stack.push(node.children!);\n break;\n }\n\n case \"FAIL\": {\n // Create a FAIL AST node.\n const node = ASTNodeFactories.FAIL();\n\n // Push the Fail node into the current scope.\n currentScope.push(node);\n\n // Try to pick any attributes off of the token stack.\n node.attributes = getAttributes(tokens, placeholders);\n\n popAndCheck(tokens, \"{\");\n\n // The new scope is that of the new Fail nodes children.\n stack.push(node.children!);\n break;\n }\n\n case \"WAIT\": {\n // Create a WAIT AST node.\n const node = ASTNodeFactories.WAIT();\n\n // Push the WAIT node into the current scope.\n currentScope.push(node);\n\n // The arguments of a wait node are optional. We may have:\n // - No node arguments, in which case the wait will be indefinite until it is aborted.\n // - One node argument which will be the explicit duration of the wait.\n // - Two node arguments which define the min and max duration bounds from which a random duration will be picked.\n if (tokens[0] === \"[\") {\n // Get the optional duration and longest duration of the wait.\n const nodeArguments = getArguments(\n tokens,\n placeholders,\n (arg) => arg.type === \"number\" && !!arg.isInteger,\n \"wait node durations must be integer values\"\n ).map((argument) => argument.value);\n\n // We may have:\n // - One node argument which will be the explicit duration of the wait.\n // - Two node arguments which define the min and max duration bounds from which a random duration will be picked.\n // - Too many arguments, which is not valid.\n if (nodeArguments.length === 1) {\n // An explicit duration was defined.\n node.duration = nodeArguments[0] as number;\n } else if (nodeArguments.length === 2) {\n // Min and max duration bounds were defined from which a random duration will be picked.\n node.durationMin = nodeArguments[0] as number;\n node.durationMax = nodeArguments[1] as number;\n } else if (nodeArguments.length > 2) {\n // An incorrect number of durations was defined.\n throw new Error(\"invalid number of wait node duration arguments defined\");\n }\n }\n\n // Try to pick any attributes off of the token stack.\n node.attributes = getAttributes(tokens, placeholders);\n break;\n }\n\n case \"REPEAT\": {\n // Create a REPEAT AST node.\n const node = ASTNodeFactories.REPEAT();\n\n // Push the REPEAT node into the current scope.\n currentScope.push(node);\n\n // The arguments of a repeat node are optional. We may have:\n // - No node arguments, in which case the repeat note will iterate indefinitely.\n // - One node argument which will be the explicit number of iterations to make.\n // - Two node arguments which define the min and max iteration bounds from which a random iteration count will be picked.\n if (tokens[0] === \"[\") {\n // An iteration count has been defined. Get the iteration and potential maximum iteration of the wait.\n const nodeArguments = getArguments(\n tokens,\n placeholders,\n (arg) => arg.type === \"number\" && !!arg.isInteger,\n \"repeat node iteration counts must be integer values\"\n ).map((argument) => argument.value);\n\n // We should have got one or two iteration counts.\n if (nodeArguments.length === 1) {\n // A static iteration count was defined.\n node.iterations = nodeArguments[0] as number;\n } else if (nodeArguments.length === 2) {\n // A minimum and maximum iteration count was defined.\n node.iterationsMin = nodeArguments[0] as number;\n node.iterationsMax = nodeArguments[1] as number;\n } else {\n // An incorrect number of iteration counts was defined.\n throw new Error(\"invalid number of repeat node iteration count arguments defined\");\n }\n }\n\n // Try to pick any attributes off of the token stack.\n node.attributes = getAttributes(tokens, placeholders);\n\n popAndCheck(tokens, \"{\");\n\n // The new scope is that of the new REPEAT nodes children.\n stack.push(node.children!);\n break;\n }\n\n case \"RETRY\": {\n // Create a RETRY AST node.\n const node = ASTNodeFactories.RETRY();\n\n // Push the RETRY node into the current scope.\n currentScope.push(node);\n\n // The arguments of a retry node are optional. We may have:\n // - No node arguments, in which case the retry note will attempt indefinitely.\n // - One node argument which will be the explicit number of attempts to make.\n // - Two node arguments which define the min and max attempt bounds from which a random attempt count will be picked.\n if (tokens[0] === \"[\") {\n // An attempt count has been defined. Get the attempt count and potential maximum attempt count of the wait.\n const nodeArguments = getArguments(\n tokens,\n placeholders,\n (arg) => arg.type === \"number\" && !!arg.isInteger,\n \"retry node attempt counts must be integer values\"\n ).map((argument) => argument.value);\n\n // We should have got one or two attempt counts.\n if (nodeArguments.length === 1) {\n // A static attempt count was defined.\n node.attempts = nodeArguments[0] as number;\n } else if (nodeArguments.length === 2) {\n // A minimum and maximum attempt count was defined.\n node.attemptsMin = nodeArguments[0] as number;\n node.attemptsMax = nodeArguments[1] as number;\n } else {\n // An incorrect number of attempt counts was defined.\n throw new Error(\"invalid number of retry node attempt count arguments defined\");\n }\n }\n\n // Try to pick any attributes off of the token stack.\n node.attributes = getAttributes(tokens, placeholders);\n\n popAndCheck(tokens, \"{\");\n\n // The new scope is that of the new RETRY nodes children.\n stack.push(node.children!);\n break;\n }\n\n case \"ACTION\": {\n // Create a ACTION AST node.\n const node = ASTNodeFactories.ACTION();\n\n // Push the ACTION node into the current scope.\n currentScope.push(node);\n\n // We must have arguments defined, as we require an action name argument.\n if (tokens[0] !== \"[\") {\n throw new Error(\"expected action name identifier argument\");\n }\n\n // The action name will be defined as a node argument.\n const actionArguments = getArguments(tokens, placeholders);\n\n // We should have at least one identifer argument for an action node, which is the action name.\n if (actionArguments.length && actionArguments[0].type === \"identifier\") {\n // The action name will be the first and only node argument.\n node.actionName = actionArguments.shift()!.value as string;\n } else {\n throw new Error(\"expected action name identifier argument\");\n }\n\n // Only the first argument should have been an identifier, all following arguments must be string, number, boolean or null.\n actionArguments\n .filter((arg) => arg.type === \"identifier\")\n .forEach((arg) => {\n throw new Error(\n \"invalid action node argument value '\" +\n arg.value +\n \"', must be string, number, boolean or null\"\n );\n });\n\n // Any node arguments that follow the action name identifier will be treated as action function arguments.\n node.actionArguments = actionArguments;\n\n // Try to pick any attributes off of the token stack.\n node.attributes = getAttributes(tokens, placeholders);\n break;\n }\n\n case \"}\": {\n // The '}' character closes the current scope.\n stack.pop();\n break;\n }\n\n default: {\n throw new Error(`unexpected token '${token}'`);\n }\n }\n }\n\n // A function to recursively validate each of the nodes in the AST.\n const validateASTNode = (node: Validatable, depth: number): void => {\n // Validate the node.\n node.validate(depth);\n\n // Validate each child of the node.\n (node.children || []).forEach((child) => validateASTNode(child, depth + 1));\n };\n\n // Start node validation from the definition root.\n validateASTNode(\n {\n children: stack[0] as RootAstNode[],\n validate(this: { children: RootAstNode[] }) {\n // We must have at least one node defined as the definition scope, which should be a root node.\n if (this.children.length === 0) {\n throw new Error(\"expected root node to have been defined\");\n }\n\n // Each node at the base of the definition scope MUST be a root node.\n for (const definitionLevelNode of this.children) {\n if (definitionLevelNode.type !== \"root\") {\n throw new Error(\"expected root node at base of definition\");\n }\n }\n\n // Exactly one root node must not have a name defined. This will be the main root, others will have to be referenced via branch nodes.\n if (this.children.filter((definitionLevelNode) => definitionLevelNode.name === null).length !== 1) {\n throw new Error(\"expected single unnamed root node at base of definition to act as main root\");\n }\n\n // No two named root nodes can have matching names.\n const rootNodeNames: string[] = [];\n for (const definitionLevelNode of this.children) {\n if (rootNodeNames.indexOf(definitionLevelNode.name!) !== -1) {\n throw new Error(`multiple root nodes found with duplicate name '${definitionLevelNode.name}'`);\n } else {\n rootNodeNames.push(definitionLevelNode.name!);\n }\n }\n }\n },\n 0\n );\n\n // Return the root AST nodes.\n return stack[0];\n}\n\n/**\n * Pop the next raw token off of the stack and throw an error if it wasn't the expected one.\n * @param tokens The array of remaining tokens.\n * @param expected An optional string or array or items, one of which must match the next popped token.\n * @returns The popped token.\n */\nfunction popAndCheck(tokens: string[], expected: string | string[]) {\n // Get and remove the next token.\n const popped = tokens.shift();\n\n // We were expecting another token.\n if (popped === undefined) {\n throw new Error(\"unexpected end of definition\");\n }\n\n // Do we have an expected token/tokens array?\n if (expected !== undefined) {\n // Check whether the popped token matches at least one of our expected items.\n var tokenMatchesExpectation = ([] as string[])\n .concat(expected)\n .some((item) => popped.toUpperCase() === item.toUpperCase());\n\n // Throw an error if the popped token didn't match any of our expected items.\n if (!tokenMatchesExpectation) {\n const expectationString = ([] as string[])\n .concat(expected)\n .map((item) => \"'\" + item + \"'\")\n .join(\" or \");\n\n throw new Error(`unexpected token found. Expected '${expectationString}' but got '${popped}'`);\n }\n }\n\n // Return the popped token.\n return popped;\n}\n\ntype StringPlaceholders = { [key: string]: string };\n\n/**\n * Pull an argument definition list off of the token stack.\n * @param tokens The array of remaining tokens.\n * @param stringArgumentPlaceholders The mapping of string literal node argument placeholders to original values.\n * @param argumentValidator The argument validator function.\n * @param validationFailedMessage The exception message to throw if argument validation fails.\n * @returns The argument definition list.\n */\nfunction getArguments(\n tokens: string[],\n stringArgumentPlaceholders: StringPlaceholders,\n argumentValidator?: (arg: AnyArgument) => boolean,\n validationFailedMessage?: string\n) {\n // Any lists of arguments will always be wrapped in '[]' for node arguments or '()' for attribute arguments.\n // We are looking for a '[' or '(' opener that wraps the argument tokens and the relevant closer.\n const closer = popAndCheck(tokens, [\"[\", \"(\"]) === \"[\" ? \"]\" : \")\";\n\n const argumentListTokens: string[] = [];\n const argumentList: AnyArgument[] = [];\n\n // Grab all tokens between the '[' and ']' or '(' and ')'.\n while (tokens.length && tokens[0] !== closer) {\n // The next token is part of our arguments list.\n argumentListTokens.push(tokens.shift()!);\n }\n\n // Validate the order of the argument tokens. Each token must either be a ',' or a single argument that satisfies the validator.\n argumentListTokens.forEach((token, index) => {\n // Get whether this token should be an actual argument.\n const shouldBeArgumentToken = !(index & 1);\n\n // If the current token should be an actual argument then validate it,otherwise it should be a ',' token.\n if (shouldBeArgumentToken) {\n // Get the argument definition.\n const argumentDefinition = getArgumentDefinition(token!, stringArgumentPlaceholders);\n\n // Try to validate the argument.\n if (argumentValidator && !argumentValidator(argumentDefinition)) {\n throw new Error(validationFailedMessage);\n }\n\n // This is a valid argument!\n argumentList.push(argumentDefinition);\n } else {\n // The current token should be a ',' token.\n if (token !== \",\") {\n throw new Error(`invalid argument list, expected ',' or ']' but got '${token}'`);\n }\n }\n });\n\n // The arguments list should terminate with a ']' or ')' token, depending on the opener.\n popAndCheck(tokens, closer);\n\n // Return the argument list.\n return argumentList;\n}\n\n/**\n * Gets an argument value definition.\n * @param token The argument token.\n * @param stringArgumentPlaceholders The mapping of string literal node argument placeholders to original values.\n * @returns An argument value definition.\n */\nfunction getArgumentDefinition(token: string, stringArgumentPlaceholders: StringPlaceholders): AnyArgument {\n // Check whether the token represents a null value.\n if (token === \"null\") {\n return {\n value: null,\n type: \"null\"\n } as NullArgument;\n }\n\n // Check whether the token represents a boolean value.\n if (token === \"true\" || token === \"false\") {\n return {\n value: token === \"true\",\n type: \"boolean\"\n } as BooleanArgument;\n }\n\n // Check whether the token represents a number value.\n // TODO: Relies on broken isNaN - see MDN.\n // if (!Number.isNaN(token)) {\n if (!isNaN(token as any)) {\n return {\n value: parseFloat(token),\n isInteger: parseFloat(token) === parseInt(token, 10),\n type: \"number\"\n } as NumberArgument;\n }\n\n // Check whether the token is a placeholder (e.g. @@0@@) representing a string literal.\n if (token.match(/^@@\\d+@@$/g)) {\n return {\n value: stringArgumentPlaceholders[token].replace('\\\\\"', '\"'),\n type: \"string\"\n } as StringPlaceholderArgument;\n }\n\n // The only remaining option is that the argument value is an identifier.\n return {\n value: token,\n type: \"identifier\"\n } as IdentifierArgument;\n}\n\n/**\n * Pull any attributes off of the token stack.\n * @param tokens The array of remaining tokens.\n * @param stringArgumentPlaceholders The mapping of string literal node argument placeholders to original values.\n * @returns An array of attributes defined by any directly following tokens.\n */\nfunction getAttributes(tokens: string[], stringArgumentPlaceholders: StringPlaceholders) {\n // Create an array to hold any attributes found.\n const attributes: Attribute[] = [];\n\n // Keep track of names of attribute that we have found on the token stack, as we cannot have duplicates.\n const attributesFound: string[] = [];\n\n // Try to get the attribute factory for the next token.\n let attributeFactory = AttributeFactories[(tokens[0] || \"\").toUpperCase()];\n\n // Pull attribute tokens off of the tokens stack until we have no more.\n while (attributeFactory) {\n // Check to make sure that we have not already created a attribute of this type for this node.\n if (attributesFound.indexOf(tokens[0].toUpperCase()) !== -1) {\n throw new Error(`duplicate attribute '${tokens[0].toUpperCase()}' found for node`);\n }\n\n // Add the current attribute type to our array of found attributes.\n attributesFound.push(tokens.shift()!.toUpperCase());\n\n // Grab any attribute arguments.\n const attributeArguments = getArguments(tokens, stringArgumentPlaceholders);\n\n // The first attribute argument has to be an identifer, this will reference an agent function.\n if (attributeArguments.length === 0 || attributeArguments[0].type !== \"identifier\") {\n throw new Error(\"expected agent function name identifier argument for attribute\");\n }\n\n // Grab the first attribute which is an identifier that will reference an agent function.\n const attributeFunctionName = attributeArguments.shift()! as IdentifierArgument;\n\n // Any remaining attribute arguments must have a type of string, number, boolean or null.\n attributeArguments\n .filter((arg) => arg.type === \"identifier\")\n .forEach((arg) => {\n throw new Error(\n \"invalid attribute argument value '\" + arg.value + \"', must be string, number, boolean or null\"\n );\n });\n\n // Create the attribute and add it to the array of attributes found.\n attributes.push(attributeFactory(attributeFunctionName.value, attributeArguments));\n\n // Try to get the next attribute name token, as there could be multiple.\n attributeFactory = AttributeFactories[(tokens[0] || \"\").toUpperCase()];\n }\n\n return attributes;\n}\n\n/**\n * Swaps out any node/attribute argument string literals with placeholders.\n * @param definition The definition.\n * @returns An object containing a mapping of placeholders to original string values as well as the processed definition string.\n */\nfunction substituteStringLiterals(definition: string): {\n placeholders: { [key: string]: string };\n processedDefinition: string;\n} {\n // Create an object to hold the mapping of placeholders to original string values.\n const placeholders: StringPlaceholders = {};\n\n // Replace any string literals wrapped with double quotes in our definition with placeholders to be processed later.\n const processedDefinition = definition.replace(/\\\"(\\\\.|[^\"\\\\])*\\\"/g, (match) => {\n var strippedMatch = match.substring(1, match.length - 1);\n var placeholder = Object.keys(placeholders).find((key) => placeholders[key] === strippedMatch);\n\n // If we have no existing string literal match then create a new placeholder.\n if (!placeholder) {\n placeholder = `@@${Object.keys(placeholders).length}@@`;\n placeholders[placeholder] = strippedMatch;\n }\n\n return placeholder;\n });\n\n return { placeholders, processedDefinition };\n}\n\n/**\n * Parse the tree definition into an array of raw tokens.\n * @param definition The definition.\n * @returns An array of tokens parsed from the definition.\n */\nfunction parseTokensFromDefinition(definition: string): string[] {\n // Add some space around various important characters so that they can be plucked out easier as individual tokens.\n definition = definition.replace(/\\(/g, \" ( \");\n definition = definition.replace(/\\)/g, \" ) \");\n definition = definition.replace(/\\{/g, \" { \");\n definition = definition.replace(/\\}/g, \" } \");\n definition = definition.replace(/\\]/g, \" ] \");\n definition = definition.replace(/\\[/g, \" [ \");\n definition = definition.replace(/\\,/g, \" , \");\n\n // Split the definition into raw token form and return it.\n return definition.replace(/\\s+/g, \" \").trim().split(\" \");\n}\n", "import GuardPath, { GuardPathPart } from \"./attributes/guards/GuardPath\";\nimport buildRootASTNodes, { AnyArgument, RootAstNode } from \"./RootAstNodesBuilder\";\nimport State, { AnyState } from \"./State\";\nimport Lookup from \"./Lookup\";\nimport Node from \"./nodes/Node\";\nimport Root from \"./nodes/decorator/Root\";\nimport Composite from \"./nodes/composite/Composite\";\nimport Decorator from \"./nodes/decorator/Decorator\";\nimport { Agent, GlobalFunction } from \"./Agent\";\nimport { CallbackAttributeDetails } from \"./attributes/callbacks/Callback\";\nimport { GuardAttributeDetails } from \"./attributes/guards/Guard\";\nimport { BehaviourTreeOptions } from \"./BehaviourTreeOptions\";\nimport { parseMDSLToJSON } from \"./mdsl/MDSLDefinitionParser\";\n\n// Purely for outside inspection of the tree.\nexport type FlattenedTreeNode = {\n id: string;\n type: string;\n caption: string;\n state: AnyState;\n guards: GuardAttributeDetails[];\n callbacks: CallbackAttributeDetails[];\n args: AnyArgument[];\n parentId: string | null;\n};\n\n/**\n * A representation of a behaviour tree.\n */\nexport class BehaviourTree {\n /**\n * The main root tree node.\n */\n public readonly rootNode: Root;\n\n /**\n * Creates a new instance of the BehaviourTree class.\n * @param definition The behaviour tree definition.\n * @param agent The agent instance that this behaviour tree is modelling behaviour for.\n * @param options The behaviour tree options object.\n */\n constructor(definition: string, private agent: Agent, private options: BehaviourTreeOptions = {}) {\n // The tree definition must be defined and a valid string.\n if (typeof definition !== \"string\") {\n throw new Error(\"the tree definition must be a string\");\n }\n\n // The agent must be defined and not null.\n if (typeof agent !== \"object\" || agent === null) {\n throw new Error(\"the agent must be defined and not null\");\n }\n\n // Parse the behaviour tree definition, create the populated tree of behaviour tree nodes, and get the root.\n this.rootNode = BehaviourTree._createRootNode(definition);\n }\n\n /**\n * Gets whether the tree is in the RUNNING state.\n * @returns true if the tree is in the RUNNING state, otherwise false.\n */\n isRunning() {\n return this.rootNode.getState() === State.RUNNING;\n }\n\n /**\n * Gets the current tree state of SUCCEEDED, FAILED, READY or RUNNING.\n * @returns The current tree state.\n */\n getState() {\n return this.rootNode.getState();\n }\n\n /**\n * Step the tree.\n * 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.\n * 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\n * 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.\n *\n * 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.\n */\n step() {\n // If the root node has already been stepped to completion then we need to reset it.\n if (this.rootNode.getState() === State.SUCCEEDED || this.rootNode.getState() === State.FAILED) {\n this.rootNode.reset();\n }\n\n try {\n this.rootNode.update(this.agent, this.options);\n } catch (exception) {\n throw new Error(`error stepping tree: ${(exception as Error).message}`);\n }\n }\n\n /**\n * Resets the tree from the root node outwards to each nested node, giving each a state of READY.\n */\n reset() {\n this.rootNode.reset();\n }\n\n /**\n * Gets the flattened details of every node in the tree.\n * @returns The flattened details of every node in the tree.\n */\n getFlattenedNodeDetails(): FlattenedTreeNode[] {\n // Create an empty flattened array of tree nodes.\n const flattenedTreeNodes: FlattenedTreeNode[] = [];\n\n /**\n * Helper function to process a node instance and push details into the flattened tree nodes array.\n * @param node The current node.\n * @param parentUid The UID of the node parent, or null if the node is the main root node.\n */\n const processNode = (node: Node, parentUid: string | null) => {\n // Get the guard and callback attribute details for this node.\n const guards = node\n .getAttributes()\n .filter((attribute) => attribute.isGuard())\n .map((attribute) => attribute.getDetails()) as GuardAttributeDetails[];\n const callbacks = node\n .getAttributes()\n .filter((attribute) => !attribute.isGuard())\n .map((attribute) => attribute.getDetails()) as CallbackAttributeDetails[];\n\n // Push the current node into the flattened nodes array.\n flattenedTreeNodes.push({\n id: node.getUid(),\n type: node.getType(),\n caption: node.getName(),\n state: node.getState(),\n guards,\n callbacks,\n args: node.getArguments(),\n parentId: parentUid\n });\n\n // Process each of the nodes children if it is not a leaf node.\n if (!node.isLeafNode()) {\n (node as Composite | Decorator)\n .getChildren()\n .forEach((child) => processNode(child, (node as Composite | Decorator).getUid()));\n }\n };\n\n // Convert the nested node structure into a flattened array of node details.\n processNode(this.rootNode, null);\n\n return flattenedTreeNodes;\n }\n\n /**\n * Registers the action/condition/guard/callback function or subtree with the given name.\n * @param name The name of the function or subtree to register.\n * @param value The function or subtree definition to register.\n */\n static register(name: string, value: GlobalFunction | string) {\n if (typeof value === \"function\") {\n // We are going to register a action/condition/guard/callback function.\n Lookup.setFunc(name, value);\n } else if (typeof value === \"string\") {\n // We are going to register a subtree.\n let rootASTNodes: RootAstNode[];\n\n try {\n // Try to create the behaviour tree AST based on the definition provided, this could fail if the definition is invalid.\n rootASTNodes = buildRootASTNodes(value);\n } catch (exception) {\n // There was an issue in trying to parse and build the tree definition.\n throw new Error(`error registering definition: ${(exception as Error).message}`);\n }\n\n // This function should only ever be called with a definition containing a single unnamed root node.\n if (rootASTNodes.length != 1 || rootASTNodes[0].name !== null) {\n throw new Error(\"error registering definition: expected a single unnamed root node\");\n }\n\n Lookup.setSubtree(name, rootASTNodes[0]);\n } else {\n throw new Error(\"unexpected value, expected string definition or function\");\n }\n }\n\n /**\n * Unregisters the registered action/condition/guard/callback function or subtree with the given name.\n * @param name The name of the registered action/condition/guard/callback function or subtree to unregister.\n */\n static unregister(name: string): void {\n Lookup.remove(name);\n }\n\n /**\n * Unregister all registered action/condition/guard/callback functions and subtrees.\n */\n static unregisterAll(): void {\n Lookup.empty();\n }\n\n /**\n * Parses a behaviour tree definition and creates a tree of behaviour tree nodes.\n * @param {string} definition The behaviour tree definition.\n * @returns The root behaviour tree node.\n */\n private static _createRootNode(definition: string): Root {\n // TODO Remove!\n try {\n // parseToJSON(definition);\n } catch (exception) {\n console.log(exception);\n }\n\n try {\n // Try to create the behaviour tree AST based on the definition provided, this could fail if the definition is invalid.\n const rootASTNodes = buildRootASTNodes(definition);\n\n // Create a symbol to use as the main root key in our root node mapping.\n const mainRootNodeKey = Symbol(\"__root__\");\n\n // Create a mapping of root node names to root AST tokens. The main root node will have a key of Symbol(\"__root__\").\n const rootNodeMap: { [key: string | symbol]: RootAstNode } = {};\n for (const rootASTNode of rootASTNodes) {\n rootNodeMap[rootASTNode.name === null ? mainRootNodeKey : rootASTNode.name!] = rootASTNode;\n }\n\n // Convert the AST to our actual tree and get the root node.\n const rootNode: Root = rootNodeMap[mainRootNodeKey].createNodeInstance(\n // Create a provider for named root nodes that are part of our definition or have been registered. Prioritising the former.\n (name: string): RootAstNode => (rootNodeMap[name] ? rootNodeMap[name] : Lookup.getSubtree(name)),\n []\n );\n\n // Set a guard path on every leaf of the tree to evaluate as part of its update.\n BehaviourTree._applyLeafNodeGuardPaths(rootNode);\n\n // Return the root node.\n return rootNode;\n } catch (exception) {\n // There was an issue in trying to parse and build the tree definition.\n throw new Error(`error parsing tree: ${(exception as Error).message}`);\n }\n }\n\n /**\n * Applies a guard path to every leaf of the tree to evaluate as part of each update.\n * @param rootNode The main root tree node.\n */\n private static _applyLeafNodeGuardPaths(rootNode: Root) {\n const nodePaths: Node[][] = [];\n\n const findLeafNodes = (path: Node[], node: Node) => {\n // Add the current node to the path.\n path = path.concat(node);\n\n // Check whether the current node is a leaf node.\n if (node.isLeafNode()) {\n nodePaths.push(path);\n } else {\n (node as Composite | Decorator).getChildren().forEach((child) => findLeafNodes(path, child));\n }\n };\n\n // Find all leaf node paths, starting from the root.\n findLeafNodes([], rootNode);\n\n nodePaths.forEach((path) => {\n // Each node in the current path will have to be assigned a guard path, working from the root outwards.\n for (let depth = 0; depth < path.length; depth++) {\n // Get the node in the path at the current depth.\n const currentNode = path[depth];\n\n // The node may already have been assigned a guard path, if so just skip it.\n if (currentNode.hasGuardPath()) {\n continue;\n }\n\n // Create the guard path for the current node.\n const guardPath = new GuardPath(\n path\n .slice(0, depth + 1)\n .map((node) => ({ node, guards: node.getGuardAttributes() }))\n .filter((details) => details.guards.length > 0)\n );\n\n // Assign the guard path to the current node.\n currentNode.setGuardPath(guardPath);\n }\n });\n }\n}\n"], - "mappings": "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", - "names": ["Participant", "Lotto", "createLotto", "State", "createLotto"] + "sources": ["../node_modules/lotto-draw/dist/Participant.js", "../node_modules/lotto-draw/dist/Utilities.js", "../node_modules/lotto-draw/dist/Lotto.js", "../node_modules/lotto-draw/dist/createLotto.js", "../node_modules/lotto-draw/dist/index.js", "../src/index.ts", "../src/attributes/guards/GuardUnsatisifedException.ts", "../src/attributes/guards/GuardPath.ts", "../src/State.ts", "../src/nodes/Node.ts", "../src/nodes/leaf/Leaf.ts", "../src/Lookup.ts", "../src/nodes/leaf/Action.ts", "../src/nodes/leaf/Condition.ts", "../src/nodes/leaf/Wait.ts", "../src/nodes/decorator/Decorator.ts", "../src/nodes/decorator/Root.ts", "../src/nodes/decorator/Repeat.ts", "../src/nodes/decorator/Retry.ts", "../src/nodes/decorator/Flip.ts", "../src/nodes/decorator/Succeed.ts", "../src/nodes/decorator/Fail.ts", "../src/nodes/composite/Lotto.ts", "../src/nodes/composite/Composite.ts", "../src/nodes/composite/Selector.ts", "../src/nodes/composite/Sequence.ts", "../src/nodes/composite/Parallel.ts", "../src/attributes/Attribute.ts", "../src/attributes/guards/Guard.ts", "../src/attributes/guards/While.ts", "../src/attributes/guards/Until.ts", "../src/attributes/callbacks/Callback.ts", "../src/attributes/callbacks/Entry.ts", "../src/attributes/callbacks/Exit.ts", "../src/attributes/callbacks/Step.ts", "../src/RootAstNodesBuilder.ts", "../src/BehaviourTree.ts", "../src/mdsl/MDSLUtilities.ts", "../src/mdsl/MDSLNodeArgumentParser.ts", "../src/mdsl/MDSLNodeAttributeParser.ts", "../src/mdsl/MDSLDefinitionParser.ts"], + "sourcesContent": ["\"use strict\";\r\nObject.defineProperty(exports, \"__esModule\", { value: true });\r\nexports.Participant = void 0;\r\n/**\r\n * A participant that holds a number of tickets.\r\n */\r\nvar Participant = /** @class */ (function () {\r\n /**\r\n * Creates an instance of the Participant class.\r\n * @param participant The actual participant.\r\n * @param tickets The number of tickets held by the participant.\r\n */\r\n function Participant(participant, tickets) {\r\n if (tickets === void 0) { tickets = 1; }\r\n this._participant = participant;\r\n this._tickets = tickets;\r\n }\r\n Object.defineProperty(Participant.prototype, \"participant\", {\r\n /** Gets the actual participant. */\r\n get: function () {\r\n return this._participant;\r\n },\r\n enumerable: false,\r\n configurable: true\r\n });\r\n Object.defineProperty(Participant.prototype, \"tickets\", {\r\n /** Gets or sets the number of tickets held by the participant. */\r\n get: function () {\r\n return this._tickets;\r\n },\r\n set: function (value) {\r\n this._tickets = value;\r\n },\r\n enumerable: false,\r\n configurable: true\r\n });\r\n return Participant;\r\n}());\r\nexports.Participant = Participant;\r\n", "\"use strict\";\r\nObject.defineProperty(exports, \"__esModule\", { value: true });\r\nexports.isNaturalNumber = exports.isNullOrUndefined = void 0;\r\n/**\r\n * Gets whether the value provided is null or undefined.\r\n * @param value The value to check.\r\n * @returns Whether the value provided is null or undefined.\r\n */\r\nfunction isNullOrUndefined(value) {\r\n return value === null || value === undefined;\r\n}\r\nexports.isNullOrUndefined = isNullOrUndefined;\r\n/**\r\n * Gets whether the value provided is a natural number.\r\n * @param value The value to check.\r\n * @returns Whether the value provided is a natural number.\r\n */\r\nfunction isNaturalNumber(value) {\r\n return typeof value === \"number\" && value >= 1 && Math.floor(value) === value;\r\n}\r\nexports.isNaturalNumber = isNaturalNumber;\r\n", "\"use strict\";\r\nObject.defineProperty(exports, \"__esModule\", { value: true });\r\nexports.Lotto = void 0;\r\nvar Participant_1 = require(\"./Participant\");\r\nvar Utilities_1 = require(\"./Utilities\");\r\n/**\r\n * Represents a lotto consisting of a number of pickable ticket-holding participants.\r\n */\r\nvar Lotto = /** @class */ (function () {\r\n /**\r\n * Creates a new instance of Lotto.\r\n * @param customRandom The custom RNG to use in place of Math.random().\r\n */\r\n function Lotto(customRandom) {\r\n /** The array of participants that are holding tickets in the lotto. */\r\n this._participants = [];\r\n this._customRandom = customRandom;\r\n }\r\n /**\r\n * Adds a participant with the specified number of tickets, or adds to the participant ticket count if the participant already holds tickets.\r\n * @param participant The participant to add or to increase the ticket count for if they already hold tickets.\r\n * @param tickets The number of tickets, defaults to 1.\r\n * @returns The Lotto instance.\r\n */\r\n Lotto.prototype.add = function (participant, tickets) {\r\n if (tickets === void 0) { tickets = 1; }\r\n // Check that we have a valid ticket count.\r\n if (!(0, Utilities_1.isNaturalNumber)(tickets)) {\r\n throw new Error(\"tickets value must be a natural number\");\r\n }\r\n // Check whether this participant has already been added.\r\n var existingParticipant = this._participants.find(function (part) { return part.participant === participant; });\r\n if (existingParticipant) {\r\n // The participant has already been added to the lotto so just add to their ticket count.\r\n existingParticipant.tickets += tickets;\r\n }\r\n else {\r\n // The participant is not part of the lotto so we should add them.\r\n this._participants.push(new Participant_1.Participant(participant, tickets));\r\n }\r\n return this;\r\n };\r\n /**\r\n * Removes the specified number of tickets for the given participant from the draw, or all tickets if a ticket number is not defined.\r\n * @param participant The participant to remove tickets for.\r\n * @param tickets The number of tickets to remove, or undefined if all tickets are to be removed.\r\n * @returns The Lotto instance.\r\n */\r\n Lotto.prototype.remove = function (participant, tickets) {\r\n // Attempt to get the existing participant.\r\n var existingParticipant = this._participants.find(function (part) { return part.participant === participant; });\r\n // There is nothing to do if the specified participant isn't even part of the lotto.\r\n if (!existingParticipant) {\r\n return this;\r\n }\r\n // Check whether a tickets value was given.\r\n if (tickets !== undefined) {\r\n // Check that we have a valid ticket count.\r\n if (!(0, Utilities_1.isNaturalNumber)(tickets)) {\r\n throw new Error(\"tickets value must be a natural number\");\r\n }\r\n existingParticipant.tickets -= tickets;\r\n // If the participant no longer holds any tickets then they should be removed.\r\n if (existingParticipant.tickets < 1) {\r\n this._participants = this._participants.filter(function (part) { return part !== existingParticipant; });\r\n }\r\n }\r\n else {\r\n // We are removing all tickets for the participant so just remove them from the lotto.\r\n this._participants = this._participants.filter(function (part) { return part !== existingParticipant; });\r\n }\r\n return this;\r\n };\r\n /**\r\n * Draw a winning ticket and return the participant that holds the ticket.\r\n * @param options The draw options.\r\n * @returns The participant that holds the winning ticket.\r\n */\r\n Lotto.prototype.draw = function (options) {\r\n if (options === void 0) { options = {}; }\r\n // If we have no participants then just return null.\r\n if (this._participants.length === 0) {\r\n return null;\r\n }\r\n var redrawable = (0, Utilities_1.isNullOrUndefined)(options.redrawable) ? true : options.redrawable;\r\n var pickable = [];\r\n this._participants.forEach(function (_a) {\r\n var participant = _a.participant, tickets = _a.tickets;\r\n for (var ticketCount = 0; ticketCount < tickets; ticketCount++) {\r\n pickable.push(participant);\r\n }\r\n });\r\n var random;\r\n // We need a random floating-point number between 0 (inclusive) and 1 to scale up to pick our winner.\r\n // If a custom random function exists then we should use that or fall back to Math.random().\r\n if (this._customRandom) {\r\n // Call our custom random function to get a random floating-point number.\r\n random = this._customRandom();\r\n // Verify that the result of calling our custom random function is a number between 0 (inclusive) and 1.\r\n if (typeof random !== \"number\" || random < 0 || random >= 1) {\r\n throw new Error(\"the 'random' function provided did not return a number between 0 (inclusive) and 1\");\r\n }\r\n }\r\n else {\r\n // No custom random function was defined so just use good ol' Math.random().\r\n random = Math.random();\r\n }\r\n // Pick a winning participant.\r\n var winner = pickable[Math.floor(random * pickable.length)];\r\n // If the ticket isn't redrawable then we should remove a ticket from the winning participants ticket count.\r\n if (!redrawable) {\r\n this.remove(winner, 1);\r\n }\r\n // Return the winning participant.\r\n return winner;\r\n };\r\n /**\r\n * Draws multiple winning tickets and return an array of the participants that hold the winning tickets.\r\n * @param tickets The number of winning tickets to draw.\r\n * @param options The draw multiple options.\r\n * @returns An array of the participants that hold the winning tickets.\r\n */\r\n Lotto.prototype.drawMultiple = function (tickets, options) {\r\n if (options === void 0) { options = {}; }\r\n var uniqueResults = (0, Utilities_1.isNullOrUndefined)(options.unique) ? false : options.unique;\r\n // Handle cases where the user has asked for zero tickets (no idea why they would do this be we should trust them).\r\n if (tickets === 0) {\r\n return [];\r\n }\r\n // Now that we know out tickets value is not zero we should check that it is a valid natural number.\r\n if (!(0, Utilities_1.isNaturalNumber)(tickets)) {\r\n throw new Error(\"tickets value must be a natural number\");\r\n }\r\n var result = [];\r\n // Keep drawing tickets until we either reach the number of required tickets or we simply run out of tickets to draw.\r\n // We can run out of tickets to draw if 'options.redrawable' is explicity 'false' or we just had no participants when 'drawMultiple' was called.\r\n while (result.length < tickets && this._participants.length > 0) {\r\n result.push(this.draw(options));\r\n }\r\n // If the 'unique' draw option is set then we need to remove duplicates from the result list.\r\n if (uniqueResults) {\r\n // Create an array to store our unique results.\r\n var unique = [];\r\n // Iterate over all of our participants (with potential duplicates) and populate our array of unique values.\r\n for (var _i = 0, result_1 = result; _i < result_1.length; _i++) {\r\n var participant = result_1[_i];\r\n if (unique.indexOf(participant) === -1) {\r\n unique.push(participant);\r\n }\r\n }\r\n result = unique;\r\n }\r\n return result;\r\n };\r\n return Lotto;\r\n}());\r\nexports.Lotto = Lotto;\r\n", "\"use strict\";\r\nObject.defineProperty(exports, \"__esModule\", { value: true });\r\nexports.createLotto = void 0;\r\nvar Lotto_1 = require(\"./Lotto\");\r\n/**\r\n * A function that creates and returns a Lotto instance.\r\n * @param participantsOrOptions An array of initial participants or options relating to the creation of a Lotto instance.\r\n * @returns A new Lotto instance.\r\n */\r\nfunction createLotto(participantsOrOptions) {\r\n // If no initial participants or lotto options were provided as an argument then we can just return a new lotto instance now.\r\n if (!participantsOrOptions) {\r\n return new Lotto_1.Lotto();\r\n }\r\n // Check whether we were provided with an array of initial participants or a lotto options object.\r\n if (Array.isArray(participantsOrOptions)) {\r\n // We are dealing with a pre-defined array of participants.\r\n var participants = participantsOrOptions;\r\n var lotto_1 = new Lotto_1.Lotto();\r\n // If the lotto participants have been defined upfront then we will need to add them all to our lotto instance now.\r\n participants.forEach(function (_a) {\r\n var participant = _a[0], tokens = _a[1];\r\n return lotto_1.add(participant, tokens);\r\n });\r\n // Return the Lotto instance.\r\n return lotto_1;\r\n }\r\n else {\r\n // We are dealing with some lotto options.\r\n var random = participantsOrOptions.random, participants = participantsOrOptions.participants;\r\n // Create a Lotto instance passing the custom RNG function to use in place of Math.random() (which could be undefined).\r\n var lotto_2 = new Lotto_1.Lotto(random);\r\n // If the lotto participants have been defined upfront as part of the options then we will need to add them all to our lotto instance now.\r\n if (participants) {\r\n participants.forEach(function (_a) {\r\n var participant = _a[0], tokens = _a[1];\r\n return lotto_2.add(participant, tokens);\r\n });\r\n }\r\n // Return the Lotto instance.\r\n return lotto_2;\r\n }\r\n}\r\nexports.createLotto = createLotto;\r\n", "\"use strict\";\r\nObject.defineProperty(exports, \"__esModule\", { value: true });\r\nvar createLotto_1 = require(\"./createLotto\");\r\nexports.default = createLotto_1.createLotto;\r\n", "import { BehaviourTree, FlattenedTreeNode } from \"./BehaviourTree\";\nimport State from \"./State\";\nimport { parseMDSLToJSON } from \"./mdsl/MDSLDefinitionParser\";\n\nexport { BehaviourTree, State, parseMDSLToJSON };\nexport type { FlattenedTreeNode };\n", "import Node from \"../../nodes/Node\";\n\n/**\n * An exception thrown when evaluating node guard path conditions and a conditions fails.\n */\nexport default class GuardUnsatisifedException extends Error {\n /**\n * @param source The node at which a guard condition failed.\n */\n constructor(private source: Node) {\n super(\"A guard path condition has failed\");\n }\n\n /**\n * Gets whether the specified node is the node at which a guard condition failed.\n * @param node The node to check against the source node.\n * @returns Whether the specified node is the node at which a guard condition failed.\n */\n isSourceNode = (node: Node) => node === this.source;\n}\n", "import { Agent } from \"../../Agent\";\nimport Guard from \"./Guard\";\nimport Node from \"../../nodes/Node\";\nimport GuardUnsatisifedException from \"./GuardUnsatisifedException\";\n\nexport type GuardPathPart = {\n node: Node;\n guards: Guard[];\n};\n\n/**\n * Represents a path of node guards along a root-to-leaf tree path.\n */\nexport default class GuardPath {\n /**\n * @param nodes An array of objects defining a node instance -> guard link, ordered by node depth.\n */\n constructor(private nodes: GuardPathPart[]) {}\n\n /**\n * Evaluate guard conditions for all guards in the tree path, moving outwards from the root.\n * @param agent The agent, required for guard evaluation.\n * @returns An evaluation results object.\n */\n evaluate = (agent: Agent) => {\n // We need to evaluate guard conditions for nodes up the tree, moving outwards from the root.\n for (const details of this.nodes) {\n // There can be multiple guards per node.\n for (const guard of details.guards) {\n // Check whether the guard condition passes, and throw an exception if not.\n if (!guard.isSatisfied(agent)) {\n throw new GuardUnsatisifedException(details.node);\n }\n }\n }\n };\n}\n", "/**\n * Enumeration of node state types.\n */\nexport enum State {\n READY = \"mistreevous.ready\",\n RUNNING = \"mistreevous.running\",\n SUCCEEDED = \"mistreevous.succeeded\",\n FAILED = \"mistreevous.failed\"\n}\n\nexport { State as default };\n\nexport type CompleteState = State.SUCCEEDED | State.FAILED;\nexport type AnyState = State.READY | State.RUNNING | CompleteState;\n", "import { Agent } from \"../Agent\";\nimport Attribute from \"../attributes/Attribute\";\nimport Entry from \"../attributes/callbacks/Entry\";\nimport Exit from \"../attributes/callbacks/Exit\";\nimport Step from \"../attributes/callbacks/Step\";\nimport Guard from \"../attributes/guards/Guard\";\nimport GuardPath from \"../attributes/guards/GuardPath\";\nimport GuardUnsatisifedException from \"../attributes/guards/GuardUnsatisifedException\";\nimport { BehaviourTreeOptions } from \"../BehaviourTreeOptions\";\nimport { AnyArgument } from \"../RootAstNodesBuilder\";\nimport State, { AnyState } from \"../State\";\nimport Leaf from \"./leaf/Leaf\";\n\n/**\n * A base node.\n */\nexport default abstract class Node {\n /**\n * The node uid.\n */\n private readonly uid: string = createNodeUid();\n /**\n * The node state.\n */\n private state: AnyState = State.READY;\n /**\n * The guard path to evaluate as part of a node update.\n */\n private guardPath: GuardPath | undefined;\n\n /**\n * @param type The node type.\n * @param attributes The node attributes.\n * @param args The node argument definitions.\n */\n constructor(private type: string, private attributes: Attribute[], private args: AnyArgument[]) {}\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected abstract onUpdate(agent: Agent, options: BehaviourTreeOptions): void;\n\n /**\n * Gets the name of the node.\n */\n public abstract getName(): string;\n\n /**\n * Gets whether this node is a leaf node.\n */\n public abstract isLeafNode: () => this is Leaf;\n\n /**\n * Gets/Sets the state of the node.\n */\n getState = (): AnyState => this.state;\n setState = (value: AnyState): void => {\n this.state = value;\n };\n\n /**\n * Gets the unique id of the node.\n */\n getUid = () => this.uid;\n\n /**\n * Gets the type of the node.\n */\n getType = () => this.type;\n\n /**\n * Gets the node attributes.\n */\n getAttributes = () => this.attributes;\n\n /**\n * Gets the node arguments.\n */\n getArguments = () => this.args;\n\n /**\n * Gets the node attribute with the specified type, or null if it does not exist.\n */\n getAttribute(type: \"entry\" | \"ENTRY\"): Entry;\n getAttribute(type: \"exit\" | \"EXIT\"): Exit;\n getAttribute(type: \"step\" | \"STEP\"): Step;\n getAttribute(type: string): Attribute {\n return (\n this.getAttributes().filter((decorator) => decorator.getType().toUpperCase() === type.toUpperCase())[0] ||\n null\n );\n }\n\n /**\n * Gets the node attributes.\n */\n getGuardAttributes = (): Guard[] => this.getAttributes().filter((decorator) => decorator.isGuard()) as Guard[];\n\n /**\n * Sets the guard path to evaluate as part of a node update.\n */\n setGuardPath = (value: GuardPath) => (this.guardPath = value);\n\n /**\n * Gets whether a guard path is assigned to this node.\n */\n hasGuardPath = () => !!this.guardPath;\n\n /**\n * Gets whether this node is in the specified state.\n * @param value The value to compare to the node state.\n */\n public is(value: AnyState): boolean {\n return this.state === value;\n }\n\n /**\n * Reset the state of the node.\n */\n public reset(): void {\n this.setState(State.READY);\n }\n\n /**\n * Abort the running of this node.\n * @param agent The agent.\n */\n public abort(agent: Agent): void {\n // There is nothing to do if this node is not in the running state.\n if (!this.is(State.RUNNING)) {\n return;\n }\n\n // Reset the state of this node.\n this.reset();\n\n this.getAttribute(\"exit\")?.callAgentFunction(agent, false, true);\n }\n\n /**\n * Update the node.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n * @returns The result of the update.\n */\n public update(agent: Agent, options: BehaviourTreeOptions): void {\n // If this node is already in a 'SUCCEEDED' or 'FAILED' state then there is nothing to do.\n if (this.is(State.SUCCEEDED) || this.is(State.FAILED)) {\n return;\n }\n\n try {\n // Evaluate all of the guard path conditions for the current tree path.\n this.guardPath!.evaluate(agent);\n\n // If this node is in the READY state then call the ENTRY for this node if it exists.\n if (this.is(State.READY)) {\n this.getAttribute(\"entry\")?.callAgentFunction(agent);\n }\n\n this.getAttribute(\"step\")?.callAgentFunction(agent);\n\n // Do the actual update.\n this.onUpdate(agent, options);\n\n // If this node is now in a 'SUCCEEDED' or 'FAILED' state then call the EXIT for this node if it exists.\n if (this.is(State.SUCCEEDED) || this.is(State.FAILED)) {\n this.getAttribute(\"exit\")?.callAgentFunction(agent, this.is(State.SUCCEEDED), false);\n }\n } catch (error) {\n // If the error is a GuardUnsatisfiedException then we need to determine if this node is the source.\n if (error instanceof GuardUnsatisifedException && error.isSourceNode(this)) {\n // Abort the current node.\n this.abort(agent);\n\n // Any node that is the source of an abort will be a failed node.\n this.setState(State.FAILED);\n } else {\n throw error;\n }\n }\n }\n}\n\n/**\n * Create a randomly generated node uid.\n * @returns A randomly generated node uid.\n */\nfunction createNodeUid(): string {\n var S4 = function () {\n return (((1 + Math.random()) * 0x10000) | 0).toString(16).substring(1);\n };\n return S4() + S4() + \"-\" + S4() + \"-\" + S4() + \"-\" + S4() + \"-\" + S4() + S4() + S4();\n}\n", "import Node from \"../Node\";\n\n/**\n * A leaf node.\n */\nexport default abstract class Leaf extends Node {\n /**\n * Gets whether this node is a leaf node.\n */\n isLeafNode = () => true;\n}\n", "import { ActionResult, Agent, ExitFunctionArg, FunctionArg, GlobalFunction } from \"./Agent\";\nimport { AnyArgument, RootAstNode } from \"./RootAstNodesBuilder\";\n\n// Exit callbacks receive their own special type of argument.\n// There's probably stricter ways to represent this but it feels overly complex right now.\ntype ExitResultArg = { value: ExitFunctionArg };\nexport type AnyExitArgument = AnyArgument | ExitResultArg;\n\nexport type InvokerFunction = (args: AnyExitArgument[]) => ActionResult;\n\n/**\n * A singleton used to store and lookup registered functions and subtrees.\n */\nexport default class Lookup {\n /**\n * The object holding any registered functions keyed on function name.\n */\n private static functionTable: { [key: string]: GlobalFunction } = {};\n /**\n * The object holding any registered sub-trees keyed on tree name.\n */\n private static subtreeTable: { [key: string]: RootAstNode } = {};\n\n /**\n * Gets the function with the specified name.\n * @param name The name of the function.\n * @returns The function with the specified name.\n */\n public static getFunc(name: string): GlobalFunction {\n return this.functionTable[name];\n }\n\n /**\n * Sets the function with the specified name for later lookup.\n * @param name The name of the function.\n * @param func The function.\n */\n public static setFunc(name: string, func: GlobalFunction): void {\n this.functionTable[name] = func;\n }\n\n /**\n * Gets the function invoker for the specified agent and function name.\n * If a function with the specified name exists on the agent object then it will\n * be returned, otherwise we will then check the registered functions for a match.\n * @param agent The agent instance that this behaviour tree is modelling behaviour for.\n * @param name The function name.\n * @returns The function invoker for the specified agent and function name.\n */\n static getFuncInvoker(agent: Agent, name: string): InvokerFunction | null {\n // Check whether the agent contains the specified function.\n const foundOnAgent = agent[name];\n if (foundOnAgent && typeof foundOnAgent === \"function\") {\n return (args: AnyExitArgument[]): boolean | ActionResult =>\n foundOnAgent.apply(\n agent,\n args.map((arg) => arg.value)\n );\n }\n\n // The agent does not contain the specified function but it may have been registered at some point.\n if (this.functionTable[name] && typeof this.functionTable[name] === \"function\") {\n return (args: AnyExitArgument[]) => this.functionTable[name](agent, ...args.map((arg) => arg.value));\n }\n\n // We have no function to invoke.\n return null;\n }\n\n /**\n * Gets the subtree with the specified name.\n * @param name The name of the subtree.\n * @returns The subtree with the specified name.\n */\n static getSubtree(name: string): RootAstNode {\n return this.subtreeTable[name];\n }\n\n /**\n * Sets the subtree with the specified name for later lookup.\n * @param name The name of the subtree.\n * @param subtree The subtree.\n */\n static setSubtree(name: string, subtree: RootAstNode) {\n this.subtreeTable[name] = subtree;\n }\n\n /**\n * Removes the registered function or subtree with the specified name.\n * @param name The name of the registered function or subtree.\n */\n static remove(name: string) {\n delete this.functionTable[name];\n delete this.subtreeTable[name];\n }\n\n /**\n * Remove all registered functions and subtrees.\n */\n static empty() {\n this.functionTable = {};\n this.subtreeTable = {};\n }\n}\n", "import Leaf from \"./Leaf\";\nimport State, { CompleteState } from \"../../State\";\nimport Lookup from \"../../Lookup\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { AnyArgument } from \"../../RootAstNodesBuilder\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * An Action leaf node.\n * This represents an immediate or ongoing state of behaviour.\n */\nexport default class Action extends Leaf {\n /**\n * @param attributes The node attributes.\n * @param actionName The action name.\n * @param actionArguments The array of action argument definitions.\n */\n constructor(attributes: Attribute[], private actionName: string, private actionArguments: AnyArgument[]) {\n super(\"action\", attributes, actionArguments);\n }\n\n /**\n * Whether there is a pending update promise.\n */\n private isUsingUpdatePromise = false;\n\n /**\n * The finished state result of an update promise.\n */\n private updatePromiseStateResult: CompleteState | null = null;\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // If the result of this action depends on an update promise then there is nothing to do until\n // it resolves, unless there has been a value set as a result of the update promise resolving.\n if (this.isUsingUpdatePromise) {\n // Check whether the update promise has resolved with a state value.\n if (this.updatePromiseStateResult) {\n // Set the state of this node to match the state returned by the promise.\n this.setState(this.updatePromiseStateResult);\n }\n\n return;\n }\n\n // Attempt to get the invoker for the action function.\n const actionFuncInvoker = Lookup.getFuncInvoker(agent, this.actionName);\n\n // The action function should be defined.\n if (actionFuncInvoker === null) {\n throw new Error(\n `cannot update action node as the action '${this.actionName}' function is not defined on the agent and has not been registered`\n );\n }\n\n // Call the action function, the result of which may be:\n // - The finished state of this action node.\n // - A promise to return a finished node state.\n // - Undefined if the node should remain in the running state.\n const updateResult = actionFuncInvoker(this.actionArguments) as CompleteState | Promise;\n\n if (updateResult instanceof Promise) {\n updateResult.then(\n (result) => {\n // If 'isUpdatePromisePending' is null then the promise was cleared as it was resolving, probably via an abort of reset.\n if (!this.isUsingUpdatePromise) {\n return;\n }\n\n // Check to make sure the result is a valid finished state.\n if (result !== State.SUCCEEDED && result !== State.FAILED) {\n throw new Error(\n \"action node promise resolved with an invalid value, expected a State.SUCCEEDED or State.FAILED value to be returned\"\n );\n }\n\n // Set pending update promise state result to be processed on next update.\n this.updatePromiseStateResult = result;\n },\n (reason) => {\n // If 'isUpdatePromisePending' is null then the promise was cleared as it was resolving, probably via an abort of reset.\n if (!this.isUsingUpdatePromise) {\n return;\n }\n\n // Just throw whatever was returned as the rejection argument.\n throw new Error(reason);\n }\n );\n\n // This node will be in the 'RUNNING' state until the update promise resolves.\n this.setState(State.RUNNING);\n\n // We are now waiting for the promise returned by the use to resolve before we know what state this node is in.\n this.isUsingUpdatePromise = true;\n } else {\n // Validate the returned value.\n this.validateUpdateResult(updateResult);\n\n // Set the state of this node, this may be undefined, which just means that the node is still in the 'RUNNING' state.\n this.setState(updateResult || State.RUNNING);\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => this.actionName;\n\n /**\n * Reset the state of the node.\n */\n reset = () => {\n // Reset the state of this node.\n this.setState(State.READY);\n\n // There is no longer an update promise that we care about.\n this.isUsingUpdatePromise = false;\n this.updatePromiseStateResult = null;\n };\n\n /**\n * Validate the result of an update function call.\n * @param result The result of an update function call.\n */\n private validateUpdateResult = (result: CompleteState | boolean) => {\n switch (result) {\n case State.SUCCEEDED:\n case State.FAILED:\n case undefined:\n return;\n default:\n throw new Error(\n `action '${this.actionName}' 'onUpdate' returned an invalid response, expected an optional State.SUCCEEDED or State.FAILED value to be returned`\n );\n }\n };\n}\n", "import Leaf from \"./Leaf\";\nimport State from \"../../State\";\nimport Lookup from \"../../Lookup\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { AnyArgument } from \"../../RootAstNodesBuilder\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A Condition leaf node.\n * This will succeed or fail immediately based on an agent predicate, without moving to the 'RUNNING' state.\n */\nexport default class Condition extends Leaf {\n /**\n * @param attributes The node attributes.\n * @param conditionName The name of the condition function.\n * @param conditionArguments The array of condition argument definitions.\n */\n constructor(attributes: Attribute[], private conditionName: string, private conditionArguments: AnyArgument[]) {\n super(\"condition\", attributes, conditionArguments);\n }\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // Attempt to get the invoker for the condition function.\n const conditionFuncInvoker = Lookup.getFuncInvoker(agent, this.conditionName);\n\n // The condition function should be defined.\n if (conditionFuncInvoker === null) {\n throw new Error(\n `cannot update condition node as the condition '${this.conditionName}' function is not defined on the agent and has not been registered`\n );\n }\n\n // Call the condition function to determine the state of this node.\n this.setState(!!conditionFuncInvoker(this.conditionArguments) ? State.SUCCEEDED : State.FAILED);\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => this.conditionName;\n}\n", "import Leaf from \"./Leaf\";\nimport State from \"../../State\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { Agent } from \"../../Agent\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A WAIT node.\n * The state of this node will change to SUCCEEDED after a duration of time\n */\nexport default class Wait extends Leaf {\n /**\n * @param attributes The node attributes.\n * @param duration The duration that this node will wait to succeed in milliseconds.\n * @param durationMin The minimum possible duration in milliseconds that this node will wait to succeed.\n * @param durationMax The maximum possible duration in milliseconds that this node will wait to succeed.\n */\n constructor(\n attributes: Attribute[],\n private duration: number | null,\n private durationMin: number | null,\n private durationMax: number | null\n ) {\n super(\"wait\", attributes, []);\n }\n\n /**\n * The time in milliseconds at which this node was first updated.\n */\n private initialUpdateTime: number = 0;\n\n /**\n * The total duration in milliseconds that this node will be waiting for.\n */\n private totalDuration: number | null = null;\n\n /**\n * The duration in milliseconds that this node has been waiting for.\n */\n private waitedDuration: number = 0;\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // If this node is in the READY state then we need to set the initial update time.\n if (this.is(State.READY)) {\n // Set the initial update time.\n this.initialUpdateTime = new Date().getTime();\n\n // Set the initial waited duration.\n this.waitedDuration = 0;\n\n // Are we dealing with an explicit duration or will we be randomly picking a duration between the min and max duration.\n if (this.duration !== null) {\n this.totalDuration = this.duration;\n } else if (this.durationMin !== null && this.durationMax !== null) {\n // We will be picking a random duration between a min and max duration, if the optional 'random' behaviour tree\n // function option is defined then we will be using that, otherwise we will fall back to using Math.random.\n const random = typeof options.random === \"function\" ? options.random : Math.random;\n\n // Pick a random duration between a min and max duration.\n this.totalDuration = Math.floor(\n random() * (this.durationMax - this.durationMin + 1) + this.durationMin\n );\n } else {\n this.totalDuration = null;\n }\n\n // The node is now running until we finish waiting.\n this.setState(State.RUNNING);\n }\n\n // If we have no total duration then this wait node will wait indefinitely until it is aborted.\n if (this.totalDuration === null) {\n return;\n }\n\n // If we have a 'getDeltaTime' function defined as part of our options then we will use it to figure out how long we have waited for.\n if (typeof options.getDeltaTime === \"function\") {\n // Get the delta time.\n const deltaTime = options.getDeltaTime();\n\n // Our delta time must be a valid number and cannot be NaN.\n if (typeof deltaTime !== \"number\" || isNaN(deltaTime)) {\n throw new Error(\"The delta time must be a valid number and not NaN.\");\n }\n\n // Update the amount of time that this node has been waiting for based on the delta time.\n this.waitedDuration += deltaTime * 1000;\n } else {\n // We are not using a delta time, so we will just work out hom much time has passed since the first update.\n this.waitedDuration = new Date().getTime() - this.initialUpdateTime;\n }\n\n // Have we waited long enough?\n if (this.waitedDuration >= this.totalDuration) {\n // We have finished waiting!\n this.setState(State.SUCCEEDED);\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => {\n if (this.duration !== null) {\n return `WAIT ${this.duration}ms`;\n } else if (this.durationMin !== null && this.durationMax !== null) {\n return `WAIT ${this.durationMin}ms-${this.durationMax}ms`;\n } else {\n return \"WAIT\";\n }\n };\n}\n", "import Node from \"../Node\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\n\n/**\n * A decorator node that wraps a single child node.\n */\nexport default abstract class Decorator extends Node {\n /**\n * @param type The node type.\n * @param attributes The node attributes.\n * @param child The child node.\n */\n constructor(type: string, attributes: Attribute[], protected child: Node) {\n super(type, attributes, []);\n }\n\n /**\n * Gets whether this node is a leaf node.\n */\n isLeafNode = () => false;\n\n /**\n * Gets the children of this node.\n */\n getChildren = () => [this.child];\n\n /**\n * Reset the state of the node.\n */\n reset = () => {\n // Reset the state of this node.\n this.setState(State.READY);\n\n // Reset the state of the child node.\n this.child.reset();\n };\n\n /**\n * Abort the running of this node.\n * @param agent The agent.\n */\n abort = (agent: Agent) => {\n // There is nothing to do if this node is not in the running state.\n if (!this.is(State.RUNNING)) {\n return;\n }\n\n // Abort the child node.\n this.child.abort(agent);\n\n // Reset the state of this node.\n this.reset();\n\n this.getAttribute(\"exit\")?.callAgentFunction(agent, false, true);\n };\n}\n", "import Node from \"../Node\";\nimport Decorator from \"./Decorator\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A Root node.\n * The root node will have a single child.\n */\nexport default class Root extends Decorator {\n /**\n * @param attributes The node attributes.\n * @param child The child node.\n */\n constructor(attributes: Attribute[], child: Node) {\n super(\"root\", attributes, child);\n }\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // If the child has never been updated or is running then we will need to update it now.\n if (this.child.getState() === State.READY || this.child.getState() === State.RUNNING) {\n // Update the child of this node.\n this.child.update(agent, options);\n }\n\n // The state of the root node is the state of its child.\n this.setState(this.child.getState());\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => \"ROOT\";\n}\n", "import Node from \"../Node\";\nimport Decorator from \"./Decorator\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A REPEAT node.\n * The node has a single child which can have:\n * -- A number of iterations for which to repeat the child node.\n * -- An infinite repeat loop if neither an iteration count or a condition function is defined.\n * The REPEAT node will stop and have a 'FAILED' state if its child is ever in a 'FAILED' state after an update.\n * The REPEAT node will attempt to move on to the next iteration if its child is ever in a 'SUCCEEDED' state.\n */\nexport default class Repeat extends Decorator {\n /**\n * @param attributes The node attributes.\n * @param iterations The number of iterations to repeat the child node.\n * @param iterationsMin The minimum possible number of iterations to repeat the child node.\n * @param iterationsMax The maximum possible number of iterations to repeat the child node.\n * @param child The child node.\n */\n constructor(\n attributes: Attribute[],\n private iterations: number | null,\n private iterationsMin: number | null,\n private iterationsMax: number | null,\n child: Node\n ) {\n super(\"repeat\", attributes, child);\n }\n\n /**\n * The number of target iterations to make.\n */\n private targetIterationCount: number | null = null;\n\n /**\n * The current iteration count.\n */\n private currentIterationCount: number = 0;\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // If this node is in the READY state then we need to reset the child and the target iteration count.\n if (this.is(State.READY)) {\n // Reset the child node.\n this.child.reset();\n\n // Reset the current iteration count.\n this.currentIterationCount = 0;\n\n // Set the target iteration count.\n this.setTargetIterationCount(options);\n }\n\n // Do a check to see if we can iterate. If we can then this node will move into the 'RUNNING' state.\n // If we cannot iterate then we have hit our target iteration count, which means that the node has succeeded.\n if (this.canIterate()) {\n // This node is in the running state and can do its initial iteration.\n this.setState(State.RUNNING);\n\n // We may have already completed an iteration, meaning that the child node will be in the SUCCEEDED state.\n // If this is the case then we will have to reset the child node now.\n if (this.child.getState() === State.SUCCEEDED) {\n this.child.reset();\n }\n\n // Update the child of this node.\n this.child.update(agent, options);\n\n // If the child moved into the FAILED state when we updated it then there is nothing left to do and this node has also failed.\n // If it has moved into the SUCCEEDED state then we have completed the current iteration.\n if (this.child.getState() === State.FAILED) {\n // The child has failed, meaning that this node has failed.\n this.setState(State.FAILED);\n\n return;\n } else if (this.child.getState() === State.SUCCEEDED) {\n // We have completed an iteration.\n this.currentIterationCount += 1;\n }\n } else {\n // This node is in the 'SUCCEEDED' state as we cannot iterate any more.\n this.setState(State.SUCCEEDED);\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => {\n if (this.iterations !== null) {\n return `REPEAT ${this.iterations}x`;\n } else if (this.iterationsMin !== null && this.iterationsMax !== null) {\n return `REPEAT ${this.iterationsMin}x-${this.iterationsMax}x`;\n } else {\n return \"REPEAT\";\n }\n };\n\n /**\n * Reset the state of the node.\n */\n reset = () => {\n // Reset the state of this node.\n this.setState(State.READY);\n\n // Reset the current iteration count.\n this.currentIterationCount = 0;\n\n // Reset the child node.\n this.child.reset();\n };\n\n /**\n * Gets whether an iteration can be made.\n * @returns Whether an iteration can be made.\n */\n private canIterate = () => {\n if (this.targetIterationCount !== null) {\n // We can iterate as long as we have not reached our target iteration count.\n return this.currentIterationCount < this.targetIterationCount;\n }\n\n // If neither an iteration count or a condition function were defined then we can iterate indefinitely.\n return true;\n };\n\n /**\n * Sets the target iteration count.\n * @param options The behaviour tree options object.\n */\n private setTargetIterationCount = (options: BehaviourTreeOptions) => {\n // Are we dealing with an explicit iteration count or will we be randomly picking a iteration count between the min and max iteration count.\n if (this.iterations !== null) {\n this.targetIterationCount = this.iterations;\n } else if (this.iterationsMin !== null && this.iterationsMax !== null) {\n // We will be picking a random iteration count between a min and max iteration count, if the optional 'random'\n // behaviour tree function option is defined then we will be using that, otherwise we will fall back to using Math.random.\n const random = typeof options.random === \"function\" ? options.random : Math.random;\n\n // Pick a random iteration count between a min and max iteration count.\n this.targetIterationCount = Math.floor(\n random() * (this.iterationsMax - this.iterationsMin + 1) + this.iterationsMin\n );\n } else {\n this.targetIterationCount = null;\n }\n };\n}\n", "import Node from \"../Node\";\nimport Decorator from \"./Decorator\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A RETRY node.\n * The node has a single child which can have:\n * -- A number of iterations for which to repeat the child node.\n * -- An infinite repeat loop if neither an iteration count or a condition function is defined.\n * The RETRY node will stop and have a 'SUCCEEDED' state if its child is ever in a 'SUCCEEDED' state after an update.\n * The RETRY node will attempt to move on to the next iteration if its child is ever in a 'FAILED' state.\n */\nexport default class Retry extends Decorator {\n /**\n * @param attributes The node attributes.\n * @param attempts The number of attempts to retry the child node.\n * @param attemptsMin The minimum possible number of attempts to retry the child node.\n * @param attemptsMax The maximum possible number of attempts to retry the child node.\n * @param child The child node.\n */\n constructor(\n attributes: Attribute[],\n private attempts: number | null,\n private attemptsMin: number | null,\n private attemptsMax: number | null,\n child: Node\n ) {\n super(\"retry\", attributes, child);\n }\n\n /**\n * The number of target attempts to make.\n */\n private targetAttemptCount: number | null = null;\n\n /**\n * The current attempt count.\n */\n private currentAttemptCount: number = 0;\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // If this node is in the READY state then we need to reset the child and the target attempt count.\n if (this.is(State.READY)) {\n // Reset the child node.\n this.child.reset();\n\n // Reset the current attempt count.\n this.currentAttemptCount = 0;\n\n // Set the target attempt count.\n this.setTargetAttemptCount(options);\n }\n\n // Do a check to see if we can attempt. If we can then this node will move into the 'RUNNING' state.\n // If we cannot attempt then we have hit our target attempt count, which means that the node has succeeded.\n if (this.canAttempt()) {\n // This node is in the running state and can do its initial attempt.\n this.setState(State.RUNNING);\n\n // We may have already completed an attempt, meaning that the child node will be in the FAILED state.\n // If this is the case then we will have to reset the child node now.\n if (this.child.getState() === State.FAILED) {\n this.child.reset();\n }\n\n // Update the child of this node.\n this.child.update(agent, options);\n\n // If the child moved into the SUCCEEDED state when we updated it then there is nothing left to do and this node has also succeeded.\n // If it has moved into the FAILED state then we have completed the current attempt.\n if (this.child.getState() === State.SUCCEEDED) {\n // The child has succeeded, meaning that this node has succeeded.\n this.setState(State.SUCCEEDED);\n\n return;\n } else if (this.child.getState() === State.FAILED) {\n // We have completed an attempt.\n this.currentAttemptCount += 1;\n }\n } else {\n // This node is in the 'FAILED' state as we cannot iterate any more.\n this.setState(State.FAILED);\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => {\n if (this.attempts !== null) {\n return `RETRY ${this.attempts}x`;\n } else if (this.attemptsMin !== null && this.attemptsMax !== null) {\n return `RETRY ${this.attemptsMin}x-${this.attemptsMax}x`;\n } else {\n return \"RETRY\";\n }\n };\n\n /**\n * Reset the state of the node.\n */\n reset = () => {\n // Reset the state of this node.\n this.setState(State.READY);\n\n // Reset the current attempt count.\n this.currentAttemptCount = 0;\n\n // Reset the child node.\n this.child.reset();\n };\n\n /**\n * Gets whether an attempt can be made.\n * @returns Whether an attempt can be made.\n */\n canAttempt = () => {\n if (this.targetAttemptCount !== null) {\n // We can attempt as long as we have not reached our target attempt count.\n return this.currentAttemptCount < this.targetAttemptCount;\n }\n\n // If neither an attempt count or a condition function were defined then we can attempt indefinitely.\n return true;\n };\n\n /**\n * Sets the target attempt count.\n * @param options The behaviour tree options object.\n */\n setTargetAttemptCount = (options: BehaviourTreeOptions) => {\n // Are we dealing with an explicit attempt count or will we be randomly picking an attempt count between the min and max attempt count.\n if (this.attempts !== null) {\n this.targetAttemptCount = this.attempts;\n } else if (this.attemptsMin !== null && this.attemptsMax !== null) {\n // We will be picking a random attempt count between a min and max attempt count, if the optional 'random'\n // behaviour tree function option is defined then we will be using that, otherwise we will fall back to using Math.random.\n const random = typeof options.random === \"function\" ? options.random : Math.random;\n\n // Pick a random attempt count between a min and max attempt count.\n this.targetAttemptCount = Math.floor(\n random() * (this.attemptsMax - this.attemptsMin + 1) + this.attemptsMin\n );\n } else {\n this.targetAttemptCount = null;\n }\n };\n}\n", "import Decorator from \"./Decorator\";\nimport State from \"../../State\";\nimport Node from \"../Node\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A Flip node.\n * This node wraps a single child and will flip the state of the child state.\n */\nexport default class Flip extends Decorator {\n /**\n * @param attributes The node attributes.\n * @param child The child node.\n */\n constructor(attributes: Attribute[], child: Node) {\n super(\"flip\", attributes, child);\n }\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // If the child has never been updated or is running then we will need to update it now.\n if (this.child.getState() === State.READY || this.child.getState() === State.RUNNING) {\n this.child.update(agent, options);\n }\n\n // The state of this node will depend in the state of its child.\n switch (this.child.getState()) {\n case State.RUNNING:\n this.setState(State.RUNNING);\n break;\n\n case State.SUCCEEDED:\n this.setState(State.FAILED);\n break;\n\n case State.FAILED:\n this.setState(State.SUCCEEDED);\n break;\n\n default:\n this.setState(State.READY);\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => \"FLIP\";\n}\n", "import Node from \"../Node\";\nimport Decorator from \"./Decorator\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A Succeed node.\n * This node wraps a single child and will always move to the 'SUCCEEDED' state when the child moves to a 'SUCCEEDED' or 'FAILED' state.\n */\nexport default class Succeed extends Decorator {\n /**\n * @param attributes The node attributes.\n * @param child The child node.\n */\n constructor(attributes: Attribute[], child: Node) {\n super(\"succeed\", attributes, child);\n }\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // If the child has never been updated or is running then we will need to update it now.\n if (this.child.getState() === State.READY || this.child.getState() === State.RUNNING) {\n this.child.update(agent, options);\n }\n\n // The state of this node will depend in the state of its child.\n switch (this.child.getState()) {\n case State.RUNNING:\n this.setState(State.RUNNING);\n break;\n\n case State.SUCCEEDED:\n case State.FAILED:\n this.setState(State.SUCCEEDED);\n break;\n\n default:\n this.setState(State.READY);\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => \"SUCCEED\";\n}\n", "import Node from \"../Node\";\nimport Decorator from \"./Decorator\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A Fail node.\n * This node wraps a single child and will always move to the 'FAILED' state when the child moves to a 'SUCCEEDED' or 'FAILED' state.\n */\nexport default class Fail extends Decorator {\n /**\n * @param attributes The node attributes.\n * @param child The child node.\n */\n constructor(attributes: Attribute[], child: Node) {\n super(\"fail\", attributes, child);\n }\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // If the child has never been updated or is running then we will need to update it now.\n if (this.child.getState() === State.READY || this.child.getState() === State.RUNNING) {\n this.child.update(agent, options);\n }\n\n // The state of this node will depend in the state of its child.\n switch (this.child.getState()) {\n case State.RUNNING:\n this.setState(State.RUNNING);\n break;\n\n case State.SUCCEEDED:\n case State.FAILED:\n this.setState(State.FAILED);\n break;\n\n default:\n this.setState(State.READY);\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => \"FAIL\";\n}\n", "import createLotto from \"lotto-draw\";\n\nimport Node from \"../Node\";\nimport Composite from \"./Composite\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A LOTTO node.\n * A winning child is picked on the initial update of this node, based on ticket weighting.\n * The state of this node will match the state of the winning child.\n */\nexport default class Lotto extends Composite {\n /**\n * @param attributes The node attributes.\n * @param tickets The child node tickets.\n * @param children The child nodes.\n */\n constructor(attributes: Attribute[], private tickets: number[], children: Node[]) {\n super(\"lotto\", attributes, children);\n }\n\n /**\n * The child node selected to be the active one.\n */\n private selectedChild: Node | undefined;\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // If this node is in the READY state then we need to pick a winning child node.\n if (this.is(State.READY)) {\n // Create a lotto draw with which to randomly pick a child node to become the active one.\n const lottoDraw = createLotto({\n // Hook up the optional 'random' behaviour tree function option to the one used by 'lotto-draw'.\n random: options.random,\n // Pass in each child node as a participant in the lotto draw with their respective ticket count.\n participants: this.children.map((child, index) => [child, this.tickets[index] || 1])\n });\n\n // Randomly pick a child based on ticket weighting, this will become the active child for this composite node.\n this.selectedChild = lottoDraw.draw() || undefined;\n }\n\n // If something went wrong and we don't have an active child then we should throw an error.\n if (!this.selectedChild) {\n throw new Error(\"failed to update lotto node as it has no active child\");\n }\n\n // If the selected child has never been updated or is running then we will need to update it now.\n if (this.selectedChild.getState() === State.READY || this.selectedChild.getState() === State.RUNNING) {\n this.selectedChild.update(agent, options);\n }\n\n // The state of the lotto node is the state of its selected child.\n this.setState(this.selectedChild.getState());\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => (this.tickets.length ? `LOTTO [${this.tickets.join(\",\")}]` : \"LOTTO\");\n}\n", "import Node from \"../Node\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\n\n/**\n * A composite node that wraps child nodes.\n */\nexport default abstract class Composite extends Node {\n /**\n * @param type The node type.\n * @param attributes The node attributes.\n * @param children The child nodes.\n */\n constructor(type: string, attributes: Attribute[], protected children: Node[]) {\n super(type, attributes, []);\n }\n\n /**\n * Gets whether this node is a leaf node.\n */\n isLeafNode = () => false;\n\n /**\n * Gets the children of this node.\n */\n getChildren = () => this.children;\n\n /**\n * Reset the state of the node.\n */\n reset = () => {\n // Reset the state of this node.\n this.setState(State.READY);\n\n // Reset the state of any child nodes.\n this.getChildren().forEach((child) => child.reset());\n };\n\n /**\n * Abort the running of this node.\n * @param agent The agent.\n */\n abort = (agent: Agent) => {\n // There is nothing to do if this node is not in the running state.\n if (!this.is(State.RUNNING)) {\n return;\n }\n\n // Abort any child nodes.\n this.getChildren().forEach((child) => child.abort(agent));\n\n // Reset the state of this node.\n this.reset();\n\n this.getAttribute(\"exit\")?.callAgentFunction(agent, false, true);\n };\n}\n", "import Composite from \"./Composite\";\nimport Node from \"../Node\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A SELECTOR node.\n * The child nodes are executed in sequence until one succeeds or all fail.\n */\nexport default class Selector extends Composite {\n /**\n * @param attributes The node attributes.\n * @param children The child nodes.\n */\n constructor(attributes: Attribute[], protected children: Node[]) {\n super(\"selector\", attributes, children);\n }\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // Iterate over all of the children of this node.\n for (const child of this.children) {\n // If the child has never been updated or is running then we will need to update it now.\n if (child.getState() === State.READY || child.getState() === State.RUNNING) {\n // Update the child of this node.\n child.update(agent, options);\n }\n\n // If the current child has a state of 'SUCCEEDED' then this node is also a 'SUCCEEDED' node.\n if (child.getState() === State.SUCCEEDED) {\n // This node is a 'SUCCEEDED' node.\n this.setState(State.SUCCEEDED);\n\n // There is no need to check the rest of the selector nodes.\n return;\n }\n\n // If the current child has a state of 'FAILED' then we should move on to the next child.\n if (child.getState() === State.FAILED) {\n // Find out if the current child is the last one in the selector.\n // If it is then this sequence node has also failed.\n if (this.children.indexOf(child) === this.children.length - 1) {\n // This node is a 'FAILED' node.\n this.setState(State.FAILED);\n\n // There is no need to check the rest of the selector as we have completed it.\n return;\n } else {\n // The child node failed, try the next one.\n continue;\n }\n }\n\n // The node should be in the 'RUNNING' state.\n if (child.getState() === State.RUNNING) {\n // This node is a 'RUNNING' node.\n this.setState(State.RUNNING);\n\n // There is no need to check the rest of the selector as the current child is still running.\n return;\n }\n\n // The child node was not in an expected state.\n throw new Error(\"child node was not in an expected state.\");\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => \"SELECTOR\";\n}\n", "import Composite from \"./Composite\";\nimport Node from \"../Node\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A SEQUENCE node.\n * The child nodes are executed in sequence until one fails or all succeed.\n */\nexport default class Sequence extends Composite {\n /**\n * @param attributes The node attributes.\n * @param children The child nodes.\n */\n constructor(attributes: Attribute[], protected children: Node[]) {\n super(\"sequence\", attributes, children);\n }\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // Iterate over all of the children of this node.\n for (const child of this.children) {\n // If the child has never been updated or is running then we will need to update it now.\n if (child.getState() === State.READY || child.getState() === State.RUNNING) {\n // Update the child of this node.\n child.update(agent, options);\n }\n\n // If the current child has a state of 'SUCCEEDED' then we should move on to the next child.\n if (child.getState() === State.SUCCEEDED) {\n // Find out if the current child is the last one in the sequence.\n // If it is then this sequence node has also succeeded.\n if (this.children.indexOf(child) === this.children.length - 1) {\n // This node is a 'SUCCEEDED' node.\n this.setState(State.SUCCEEDED);\n\n // There is no need to check the rest of the sequence as we have completed it.\n return;\n } else {\n // The child node succeeded, but we have not finished the sequence yet.\n continue;\n }\n }\n\n // If the current child has a state of 'FAILED' then this node is also a 'FAILED' node.\n if (child.getState() === State.FAILED) {\n // This node is a 'FAILED' node.\n this.setState(State.FAILED);\n\n // There is no need to check the rest of the sequence.\n return;\n }\n\n // The node should be in the 'RUNNING' state.\n if (child.getState() === State.RUNNING) {\n // This node is a 'RUNNING' node.\n this.setState(State.RUNNING);\n\n // There is no need to check the rest of the sequence as the current child is still running.\n return;\n }\n\n // The child node was not in an expected state.\n throw new Error(\"child node was not in an expected state.\");\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => \"SEQUENCE\";\n}\n", "import Composite from \"./Composite\";\nimport State from \"../../State\";\nimport Node from \"../Node\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A PARALLEL node.\n * The child nodes are executed concurrently until one fails or all succeed.\n */\nexport default class Parallel extends Composite {\n /**\n * @param attributes The node attributes.\n * @param children The child nodes.\n */\n constructor(attributes: Attribute[], children: Node[]) {\n super(\"parallel\", attributes, children);\n }\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // Keep a count of the number of succeeded child nodes.\n let succeededCount = 0;\n\n let hasChildFailed = false;\n\n // Iterate over all of the children of this node.\n for (const child of this.children) {\n // If the child has never been updated or is running then we will need to update it now.\n if (child.getState() === State.READY || child.getState() === State.RUNNING) {\n // Update the child of this node.\n child.update(agent, options);\n }\n\n // If the current child has a state of 'SUCCEEDED' then we should move on to the next child.\n if (child.getState() === State.SUCCEEDED) {\n // The child node has succeeded, keep track of this to determine if all children have.\n succeededCount++;\n\n // The child node succeeded, but we have not finished checking every child node yet.\n continue;\n }\n\n // If the current child has a state of 'FAILED' then this node is also a 'FAILED' node.\n if (child.getState() === State.FAILED) {\n hasChildFailed = true;\n\n // There is no need to check the rest of the children.\n break;\n }\n\n // The node should be in the 'RUNNING' state.\n if (child.getState() !== State.RUNNING) {\n // The child node was not in an expected state.\n throw new Error(\"child node was not in an expected state.\");\n }\n }\n\n if (hasChildFailed) {\n // This node is a 'FAILED' node.\n this.setState(State.FAILED);\n\n // Abort every running child.\n for (const child of this.children) {\n if (child.getState() === State.RUNNING) {\n child.abort(agent);\n }\n }\n } else {\n // If all children have succeeded then this node has also succeeded, otherwise it is still running.\n this.setState(succeededCount === this.children.length ? State.SUCCEEDED : State.RUNNING);\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => \"PARALLEL\";\n}\n", "import { AnyArgument } from \"../RootAstNodesBuilder\";\nimport Guard from \"./guards/Guard\";\n\nexport type AttributeDetails = {\n /** The attribute type. */\n type: string;\n\n /** The attribute arguments. */\n args: AnyArgument[];\n};\n\n/**\n * A base node attribute.\n */\nexport default abstract class Attribute {\n /**\n * @param type The node attribute type.\n * @param args The array of attribute argument definitions.\n */\n constructor(protected type: string, protected args: AnyArgument[]) {}\n\n /**\n * Gets the type of the attribute.\n */\n getType = () => this.type;\n\n /**\n * Gets the array of attribute argument definitions.\n */\n getArguments = () => this.args;\n\n /**\n * Gets the attribute details.\n */\n abstract getDetails(): TAttributeDetails;\n\n /**\n * Gets whether this attribute is a guard.\n */\n abstract isGuard: () => this is Guard;\n}\n", "import { Agent } from \"../../Agent\";\nimport { AnyArgument } from \"../../RootAstNodesBuilder\";\nimport Attribute, { AttributeDetails } from \"../Attribute\";\n\nexport type GuardAttributeDetails = {\n /** The name of the condition function that determines whether the guard is satisfied. */\n condition: string;\n} & AttributeDetails;\n\n/**\n * A base node guard attribute.\n */\nexport default abstract class Guard extends Attribute {\n /**\n * @param type The node attribute type.\n * @param args The array of decorator argument definitions.\n * @param condition The name of the condition function that determines whether the guard is satisfied.\n */\n constructor(type: string, args: AnyArgument[], private condition: string) {\n super(type, args);\n }\n\n /**\n * Gets the name of the condition function that determines whether the guard is satisfied.\n */\n getCondition = () => this.condition;\n\n /**\n * Gets whether this attribute is a guard.\n */\n isGuard = () => true;\n\n /**\n * Gets the attribute details.\n */\n getDetails(): GuardAttributeDetails {\n return {\n type: this.getType(),\n args: this.getArguments(),\n condition: this.getCondition()\n };\n }\n\n /**\n * Gets whether the guard is satisfied.\n * @param agent The agent.\n * @returns Whether the guard is satisfied.\n */\n abstract isSatisfied(agent: Agent): boolean;\n}\n", "import Guard from \"./Guard\";\nimport Lookup from \"../../Lookup\";\nimport { Agent } from \"../../Agent\";\nimport { AnyArgument } from \"../../RootAstNodesBuilder\";\n\n/**\n * A WHILE guard which is satisfied as long as the given condition remains true.\n */\nexport default class While extends Guard {\n /**\n * @param condition The name of the condition function that determines whether the guard is satisfied.\n * @param args The array of decorator argument definitions.\n */\n constructor(condition: string, args: AnyArgument[]) {\n super(\"while\", args, condition);\n }\n\n /**\n * Gets whether the guard is satisfied.\n * @param agent The agent.\n * @returns Whether the guard is satisfied.\n */\n isSatisfied = (agent: Agent) => {\n // Attempt to get the invoker for the condition function.\n const conditionFuncInvoker = Lookup.getFuncInvoker(agent, this.getCondition());\n\n // The condition function should be defined.\n if (conditionFuncInvoker === null) {\n throw new Error(\n `cannot evaluate node guard as the condition '${this.getCondition()}' function is not defined on the agent and has not been registered`\n );\n }\n\n // Call the condition function to determine whether this guard is satisfied.\n return !!conditionFuncInvoker(this.args);\n };\n}\n", "import Guard from \"./Guard\";\nimport Lookup from \"../../Lookup\";\nimport { Agent } from \"../../Agent\";\nimport { AnyArgument } from \"../../RootAstNodesBuilder\";\n\n/**\n * An UNTIL guard which is satisfied as long as the given condition remains false.\n */\nexport default class Until extends Guard {\n /**\n * @param condition The name of the condition function that determines whether the guard is satisfied.\n * @param args The array of decorator argument definitions.\n */\n constructor(condition: string, args: AnyArgument[]) {\n super(\"until\", args, condition);\n }\n\n /**\n * Gets whether the guard is satisfied.\n * @param agent The agent.\n * @returns Whether the guard is satisfied.\n */\n isSatisfied = (agent: Agent) => {\n // Attempt to get the invoker for the condition function.\n const conditionFuncInvoker = Lookup.getFuncInvoker(agent, this.getCondition());\n\n // The condition function should be defined.\n if (conditionFuncInvoker === null) {\n throw new Error(\n `cannot evaluate node guard as the condition '${this.getCondition()}' function is not defined on the agent and has not been registered`\n );\n }\n\n // Call the condition function to determine whether this guard is satisfied.\n return !!!conditionFuncInvoker(this.args);\n };\n}\n", "import { Agent } from \"../../Agent\";\nimport { AnyArgument } from \"../../RootAstNodesBuilder\";\nimport Attribute, { AttributeDetails } from \"../Attribute\";\n\nexport type CallbackAttributeDetails = {\n /** The name of the agent function that is called. */\n functionName: string;\n} & AttributeDetails;\n\n/**\n * A base node callback attribute.\n */\nexport default abstract class Callback extends Attribute {\n /**\n * @param type The node attribute type.\n * @param args The array of decorator argument definitions.\n * @param functionName The name of the agent function to call.\n */\n constructor(type: string, args: AnyArgument[], private functionName: string) {\n super(type, args);\n }\n\n /**\n * Gets the name of the agent function to call.\n */\n getFunctionName = () => this.functionName;\n\n /**\n * Gets whether this attribute is a guard.\n */\n isGuard = () => false;\n\n /**\n * Gets the attribute details.\n */\n getDetails(): CallbackAttributeDetails {\n return {\n type: this.getType(),\n args: this.getArguments(),\n functionName: this.getFunctionName()\n };\n }\n\n /**\n * Attempt to call the agent function that this callback refers to.\n * @param agent The agent.\n */\n abstract callAgentFunction: (agent: Agent, isSuccess: boolean, isAborted: boolean) => void;\n}\n", "import Callback from \"./Callback\";\nimport Lookup from \"../../Lookup\";\nimport { Agent } from \"../../Agent\";\nimport { AnyArgument } from \"../../RootAstNodesBuilder\";\n\n/**\n * An ENTRY callback which defines an agent function to call when the associated node is updated and moves out of running state.\n */\nexport default class Entry extends Callback {\n /**\n * @param functionName The name of the agent function to call.\n * @param args The array of callback argument definitions.\n */\n constructor(functionName: string, args: AnyArgument[]) {\n super(\"entry\", args, functionName);\n }\n\n /**\n * Attempt to call the agent function that this callback refers to.\n * @param agent The agent.\n */\n callAgentFunction = (agent: Agent) => {\n // Attempt to get the invoker for the callback function.\n const callbackFuncInvoker = Lookup.getFuncInvoker(agent, this.getFunctionName());\n\n // The callback function should be defined.\n if (callbackFuncInvoker === null) {\n throw new Error(\n `cannot call entry function '${this.getFunctionName()}' as is not defined on the agent and has not been registered`\n );\n }\n\n // Call the callback function.\n callbackFuncInvoker(this.args);\n };\n}\n", "import Callback from \"./Callback\";\nimport Lookup, { AnyExitArgument } from \"../../Lookup\";\nimport { Agent } from \"../../Agent\";\nimport { AnyArgument } from \"../../RootAstNodesBuilder\";\n\n/**\n * An EXIT callback which defines an agent function to call when the associated node is updated and moves to a finished state or is aborted.\n */\nexport default class Exit extends Callback {\n /**\n * @param functionName The name of the agent function to call.\n * @param args The array of callback argument definitions.\n */\n constructor(functionName: string, args: AnyArgument[]) {\n super(\"exit\", args, functionName);\n }\n\n /**\n * Attempt to call the agent function that this callback refers to.\n * @param agent The agent.\n * @param isSuccess Whether the decorated node was left with a success state.\n * @param isAborted Whether the decorated node was aborted.\n */\n callAgentFunction = (agent: Agent, isSuccess: boolean, isAborted: boolean) => {\n // Attempt to get the invoker for the callback function.\n const callbackFuncInvoker = Lookup.getFuncInvoker(agent, this.getFunctionName());\n\n // The callback function should be defined.\n if (callbackFuncInvoker === null) {\n throw new Error(\n `cannot call exit function '${this.getFunctionName()}' as is not defined on the agent and has not been registered`\n );\n }\n\n // Call the callback function\n callbackFuncInvoker([{ value: { succeeded: isSuccess, aborted: isAborted } }, ...this.args]);\n };\n}\n", "import Callback from \"./Callback\";\nimport Lookup from \"../../Lookup\";\nimport { Agent } from \"../../Agent\";\nimport { AnyArgument } from \"../../RootAstNodesBuilder\";\n\n/**\n * A STEP callback which defines an agent function to call when the associated node is updated.\n */\nexport default class Step extends Callback {\n /**\n * @param functionName The name of the agent function to call.\n * @param args The array of callback argument definitions.\n */\n constructor(functionName: string, args: AnyArgument[]) {\n super(\"step\", args, functionName);\n }\n\n /**\n * Attempt to call the agent function that this callback refers to.\n * @param agent The agent.\n */\n callAgentFunction = (agent: Agent) => {\n // Attempt to get the invoker for the callback function.\n const callbackFuncInvoker = Lookup.getFuncInvoker(agent, this.getFunctionName());\n\n // The callback function should be defined.\n if (callbackFuncInvoker === null) {\n throw new Error(\n `cannot call step function '${this.getFunctionName()}' as is not defined on the agent and has not been registered`\n );\n }\n\n // Call the callback function.\n callbackFuncInvoker(this.args);\n };\n}\n", "import Action from \"./nodes/leaf/Action\";\nimport Condition from \"./nodes/leaf/Condition\";\nimport Wait from \"./nodes/leaf/Wait\";\nimport Root from \"./nodes/decorator/Root\";\nimport Repeat from \"./nodes/decorator/Repeat\";\nimport Retry from \"./nodes/decorator/Retry\";\nimport Flip from \"./nodes/decorator/Flip\";\nimport Succeed from \"./nodes/decorator/Succeed\";\nimport Fail from \"./nodes/decorator/Fail\";\nimport Lotto from \"./nodes/composite/Lotto\";\nimport Selector from \"./nodes/composite/Selector\";\nimport Sequence from \"./nodes/composite/Sequence\";\nimport Parallel from \"./nodes/composite/Parallel\";\nimport Node from \"./nodes/Node\";\nimport While from \"./attributes/guards/While\";\nimport Until from \"./attributes/guards/Until\";\nimport Entry from \"./attributes/callbacks/Entry\";\nimport Exit from \"./attributes/callbacks/Exit\";\nimport Step from \"./attributes/callbacks/Step\";\nimport Callback from \"./attributes/callbacks/Callback\";\nimport Guard from \"./attributes/guards/Guard\";\nimport Attribute from \"./attributes/Attribute\";\nimport Composite from \"./nodes/composite/Composite\";\nimport Decorator from \"./nodes/decorator/Decorator\";\nimport Leaf from \"./nodes/leaf/Leaf\";\n\nexport type Argument = {\n value: T;\n type: string; // Used for validation.\n};\ntype NullArgument = Argument & {\n type: \"null\";\n};\ntype BooleanArgument = Argument & {\n type: \"boolean\";\n};\ntype NumberArgument = Argument & {\n type: \"number\";\n isInteger: boolean; // Used for validation.\n};\ntype StringPlaceholderArgument = Argument & {\n type: \"string\";\n};\ntype IdentifierArgument = Argument & {\n type: \"identifier\";\n};\nexport type AnyArgument =\n | NullArgument\n | BooleanArgument\n | NumberArgument\n | StringPlaceholderArgument\n | IdentifierArgument;\n\n/**\n * The node attribute factories.\n */\nconst AttributeFactories: {\n [key: string]: (functionName: string, attributeArguments: AnyArgument[]) => Callback | Guard;\n} = {\n WHILE: (condition: string, attributeArguments: AnyArgument[]) => new While(condition, attributeArguments),\n UNTIL: (condition: string, attributeArguments: AnyArgument[]) => new Until(condition, attributeArguments),\n ENTRY: (functionName: string, attributeArguments: AnyArgument[]) => new Entry(functionName, attributeArguments),\n EXIT: (functionName: string, attributeArguments: AnyArgument[]) => new Exit(functionName, attributeArguments),\n STEP: (functionName: string, attributeArguments: AnyArgument[]) => new Step(functionName, attributeArguments)\n};\n\ntype Validatable = {\n children?: AstNode[];\n validate: (depth: number) => void;\n};\n\ntype NodeInstanceCreator = (\n namedRootNodeProvider: (name: string) => RootAstNode,\n visitedBranches: string[]\n) => T;\n\nexport type AstNode = Validatable & {\n type: string;\n createNodeInstance: NodeInstanceCreator;\n};\n\nexport type LeafAstNode = AstNode & {\n type: \"action\" | \"condition\" | \"wait\";\n attributes: Attribute[];\n};\n\nexport type CompositeAstNode = AstNode & {\n type: \"lotto\" | \"parallel\" | \"selector\" | \"sequence\";\n attributes: Attribute[];\n children: AstNode[];\n};\n\nexport type DecoratorAstNode = AstNode & {\n type: \"fail\" | \"flip\" | \"repeat\" | \"retry\" | \"root\" | \"succeed\";\n attributes: Attribute[];\n children: AstNode[];\n};\n\nexport type BranchAstNode = AstNode & {\n type: \"branch\";\n branchName: \"\" | string;\n};\n\nexport type LottoAstNode = CompositeAstNode & {\n type: \"lotto\";\n tickets: number[];\n};\n\nexport type RootAstNode = DecoratorAstNode & {\n type: \"root\";\n name: null | string;\n};\n\nexport type RepeatAstNode = DecoratorAstNode & {\n type: \"repeat\";\n iterations: number | null;\n iterationsMin: number | null;\n iterationsMax: number | null;\n};\n\nexport type RetryAstNode = DecoratorAstNode & {\n type: \"retry\";\n attempts: number | null;\n attemptsMin: number | null;\n attemptsMax: number | null;\n};\n\nexport type ActionAstNode = LeafAstNode & {\n type: \"action\";\n actionName: string;\n actionArguments: AnyArgument[];\n};\n\nexport type ConditionAstNode = LeafAstNode & {\n type: \"condition\";\n conditionName: string;\n conditionArguments: AnyArgument[];\n};\n\nexport type WaitAstNode = LeafAstNode & {\n type: \"wait\";\n duration: number | null;\n durationMin: number | null;\n durationMax: number | null;\n};\n\nexport type AnyAstNode =\n | BranchAstNode\n | CompositeAstNode\n | LottoAstNode\n | DecoratorAstNode\n | RootAstNode\n | RepeatAstNode\n | RetryAstNode\n | LeafAstNode\n | ActionAstNode\n | ConditionAstNode\n | WaitAstNode;\n\n/**\n * The AST node factories.\n */\nconst ASTNodeFactories = {\n ROOT: (): RootAstNode => ({\n type: \"root\",\n attributes: [],\n name: null,\n children: [],\n validate(depth: number) {\n // A root node cannot be the child of another node.\n if (depth > 1) {\n throw new Error(\"a root node cannot be the child of another node\");\n }\n\n // A root node must have a single child node.\n if (this.children.length !== 1) {\n throw new Error(\"a root node must have a single child\");\n }\n },\n createNodeInstance(namedRootNodeProvider, visitedBranches) {\n return new Root(\n this.attributes,\n this.children![0].createNodeInstance(namedRootNodeProvider, visitedBranches.slice())\n );\n }\n }),\n BRANCH: (): BranchAstNode => ({\n type: \"branch\",\n branchName: \"\",\n validate() {},\n createNodeInstance(namedRootNodeProvider, visitedBranches) {\n // Try to find the root node with a matching branch name.\n const targetRootNode = namedRootNodeProvider(this.branchName);\n\n // If we have already visited this branch then we have a circular dependency.\n if (visitedBranches.indexOf(this.branchName) !== -1) {\n throw new Error(`circular dependency found in branch node references for branch '${this.branchName}'`);\n }\n\n // If we have a target root node, then the node instance we want will be the first and only child of the referenced root node.\n if (targetRootNode) {\n return targetRootNode\n .createNodeInstance(namedRootNodeProvider, visitedBranches.concat(this.branchName))\n .getChildren()[0];\n } else {\n throw new Error(`branch references root node '${this.branchName}' which has not been defined`);\n }\n }\n }),\n SELECTOR: (): CompositeAstNode => ({\n type: \"selector\",\n attributes: [],\n children: [],\n validate() {\n // A selector node must have at least a single node.\n if (this.children.length < 1) {\n throw new Error(\"a selector node must have at least a single child\");\n }\n },\n createNodeInstance(namedRootNodeProvider, visitedBranches) {\n return new Selector(\n this.attributes,\n this.children.map((child) => child.createNodeInstance(namedRootNodeProvider, visitedBranches.slice()))\n );\n }\n }),\n SEQUENCE: (): CompositeAstNode => ({\n type: \"sequence\",\n attributes: [],\n children: [],\n validate() {\n // A sequence node must have at least a single node.\n if (this.children.length < 1) {\n throw new Error(\"a sequence node must have at least a single child\");\n }\n },\n createNodeInstance(namedRootNodeProvider, visitedBranches) {\n return new Sequence(\n this.attributes,\n this.children.map((child) => child.createNodeInstance(namedRootNodeProvider, visitedBranches.slice()))\n );\n }\n }),\n PARALLEL: (): CompositeAstNode => ({\n type: \"parallel\",\n attributes: [],\n children: [],\n validate() {\n // A parallel node must have at least a single node.\n if (this.children.length < 1) {\n throw new Error(\"a parallel node must have at least a single child\");\n }\n },\n createNodeInstance(namedRootNodeProvider, visitedBranches) {\n return new Parallel(\n this.attributes,\n this.children.map((child) => child.createNodeInstance(namedRootNodeProvider, visitedBranches.slice()))\n );\n }\n }),\n LOTTO: (): LottoAstNode => ({\n type: \"lotto\",\n attributes: [],\n children: [],\n tickets: [],\n validate() {\n // A lotto node must have at least a single node.\n if (this.children!.length < 1) {\n throw new Error(\"a lotto node must have at least a single child\");\n }\n },\n createNodeInstance(namedRootNodeProvider, visitedBranches) {\n return new Lotto(\n this.attributes,\n this.tickets!,\n this.children!.map((child) => child.createNodeInstance(namedRootNodeProvider, visitedBranches.slice()))\n );\n }\n }),\n REPEAT: (): RepeatAstNode => ({\n type: \"repeat\",\n attributes: [],\n iterations: null,\n iterationsMin: null,\n iterationsMax: null,\n children: [],\n validate() {\n // A repeat node must have a single node.\n if (this.children!.length !== 1) {\n throw new Error(\"a repeat node must have a single child\");\n }\n\n if (this.iterations !== null) {\n // A repeat node must have a positive number of iterations if defined.\n if (this.iterations < 0) {\n throw new Error(\"a repeat node must have a positive number of iterations if defined\");\n }\n } else if (this.iterationsMin !== null && this.iterationsMax !== null) {\n // A repeat node must have a positive min and max iteration count if they are defined.\n if (this.iterationsMin < 0 || this.iterationsMax < 0) {\n throw new Error(\n \"a repeat node must have a positive minimum and maximum iteration count if defined\"\n );\n }\n\n // A repeat node must not have an minimum iteration count that exceeds the maximum iteration count.\n if (this.iterationsMin > this.iterationsMax) {\n throw new Error(\n \"a repeat node must not have a minimum iteration count that exceeds the maximum iteration count\"\n );\n }\n } else {\n // If we have no explicit iteration count or a minimum and maximum iteration count set then we are dealing with a repeat node that iterates indefinitely.\n }\n },\n createNodeInstance(namedRootNodeProvider, visitedBranches) {\n return new Repeat(\n this.attributes,\n this.iterations,\n this.iterationsMin,\n this.iterationsMax,\n this.children![0].createNodeInstance(namedRootNodeProvider, visitedBranches.slice())\n );\n }\n }),\n RETRY: (): RetryAstNode => ({\n type: \"retry\",\n attributes: [],\n attempts: null,\n attemptsMin: null,\n attemptsMax: null,\n children: [],\n validate() {\n // A retry node must have a single node.\n if (this.children!.length !== 1) {\n throw new Error(\"a retry node must have a single child\");\n }\n\n if (this.attempts !== null) {\n // A retry node must have a positive number of attempts if defined.\n if (this.attempts < 0) {\n throw new Error(\"a retry node must have a positive number of attempts if defined\");\n }\n } else if (this.attemptsMin !== null && this.attemptsMax !== null) {\n // A retry node must have a positive min and max attempts count if they are defined.\n if (this.attemptsMin < 0 || this.attemptsMax < 0) {\n throw new Error(\"a retry node must have a positive minimum and maximum attempt count if defined\");\n }\n\n // A retry node must not have a minimum attempt count that exceeds the maximum attempt count.\n if (this.attemptsMin > this.attemptsMax) {\n throw new Error(\n \"a retry node must not have a minimum attempt count that exceeds the maximum attempt count\"\n );\n }\n } else {\n // If we have no explicit attempt count or a minimum and maximum attempt count set then we are dealing with a retry node that attempts indefinitely.\n }\n },\n createNodeInstance(namedRootNodeProvider, visitedBranches) {\n return new Retry(\n this.attributes,\n this.attempts,\n this.attemptsMin,\n this.attemptsMax,\n this.children![0].createNodeInstance(namedRootNodeProvider, visitedBranches.slice())\n );\n }\n }),\n FLIP: (): DecoratorAstNode => ({\n type: \"flip\",\n attributes: [],\n children: [],\n validate() {\n // A flip node must have a single node.\n if (this.children!.length !== 1) {\n throw new Error(\"a flip node must have a single child\");\n }\n },\n createNodeInstance(namedRootNodeProvider, visitedBranches) {\n return new Flip(\n this.attributes,\n this.children![0].createNodeInstance(namedRootNodeProvider, visitedBranches.slice())\n );\n }\n }),\n SUCCEED: (): DecoratorAstNode => ({\n type: \"succeed\",\n attributes: [],\n children: [],\n validate() {\n // A succeed node must have a single node.\n if (this.children!.length !== 1) {\n throw new Error(\"a succeed node must have a single child\");\n }\n },\n createNodeInstance(namedRootNodeProvider, visitedBranches) {\n return new Succeed(\n this.attributes,\n this.children![0].createNodeInstance(namedRootNodeProvider, visitedBranches.slice())\n );\n }\n }),\n FAIL: (): DecoratorAstNode => ({\n type: \"fail\",\n attributes: [],\n children: [],\n validate() {\n // A fail node must have a single node.\n if (this.children!.length !== 1) {\n throw new Error(\"a fail node must have a single child\");\n }\n },\n createNodeInstance(namedRootNodeProvider, visitedBranches) {\n return new Fail(\n this.attributes,\n this.children![0].createNodeInstance(namedRootNodeProvider, visitedBranches.slice())\n );\n }\n }),\n WAIT: (): WaitAstNode => ({\n type: \"wait\",\n attributes: [],\n duration: null,\n durationMin: null,\n durationMax: null,\n validate() {\n if (this.duration !== null) {\n // If an explict duration was defined then it must be a positive number.\n if (this.duration < 0) {\n throw new Error(\"a wait node must have a positive duration\");\n }\n } else if (this.durationMin !== null && this.durationMax !== null) {\n // A wait node must have a positive min and max duration.\n if (this.durationMin < 0 || this.durationMax < 0) {\n throw new Error(\"a wait node must have a positive minimum and maximum duration\");\n }\n\n // A wait node must not have a minimum duration that exceeds the maximum duration.\n if (this.durationMin > this.durationMax) {\n throw new Error(\"a wait node must not have a minimum duration that exceeds the maximum duration\");\n }\n } else {\n // If we have no explicit duration or duration bounds set then we are dealing with a wait node that waits indefinitely.\n }\n },\n createNodeInstance() {\n return new Wait(this.attributes, this.duration, this.durationMin, this.durationMax);\n }\n }),\n ACTION: (): ActionAstNode => ({\n type: \"action\",\n attributes: [],\n actionName: \"\",\n actionArguments: [],\n validate() {},\n createNodeInstance() {\n return new Action(this.attributes, this.actionName!, this.actionArguments!);\n }\n }),\n CONDITION: (): ConditionAstNode => ({\n type: \"condition\",\n attributes: [],\n conditionName: \"\",\n conditionArguments: [],\n validate() {},\n createNodeInstance() {\n return new Condition(this.attributes, this.conditionName!, this.conditionArguments!);\n }\n })\n};\n\ntype OtherAstNodes = AstNode[];\n\n/**\n * Create an array of root AST nodes based on the given definition.\n * @param definition The definition to parse the AST nodes from.\n * @returns The base definition AST nodes.\n */\nexport default function buildRootASTNodes(definition: string): RootAstNode[] {\n // Swap out any node/attribute argument string literals with a placeholder and get a mapping of placeholders to original values as well as the processed definition.\n const { placeholders, processedDefinition } = substituteStringLiterals(definition);\n\n // Convert the processed definition (with substituted string literals) into an array of raw tokens.\n const tokens = parseTokensFromDefinition(processedDefinition);\n\n // There must be at least 3 tokens for the tree definition to be valid. 'ROOT', '{' and '}'.\n if (tokens.length < 3) {\n throw new Error(\"invalid token count\");\n }\n\n // We should have a matching number of '{' and '}' tokens. If not, then there are scopes that have not been properly closed.\n if (tokens.filter((token) => token === \"{\").length !== tokens.filter((token) => token === \"}\").length) {\n throw new Error(\"scope character mismatch\");\n }\n\n // Create a stack of node children arrays, starting with a definition scope.\n const stack: [RootAstNode[], ...OtherAstNodes[]] = [[]];\n const rootScope = stack[0];\n\n // We should keep processing the raw tokens until we run out of them.\n while (tokens.length) {\n // Grab the next token.\n const token = tokens.shift();\n\n const currentScope = stack[stack.length - 1] as OtherAstNodes;\n\n // How we create the next AST token depends on the current raw token value.\n switch (token!.toUpperCase()) {\n case \"ROOT\": {\n // Create a ROOT AST node.\n const node = ASTNodeFactories.ROOT();\n\n // Push the ROOT node into the current scope.\n rootScope.push(node);\n\n // We may have a root node name defined as an argument.\n if (tokens[0] === \"[\") {\n const rootArguments = getArguments(tokens, placeholders);\n\n // We should have only a single argument that is not an empty string for a root node, which is the root name identifier.\n if (rootArguments.length === 1 && rootArguments[0].type === \"identifier\") {\n // The root name will be the first and only node argument.\n node.name = rootArguments[0].value as string;\n } else {\n throw new Error(\"expected single root name argument\");\n }\n }\n\n // Try to pick any attributes off of the token stack.\n node.attributes = getAttributes(tokens, placeholders);\n\n popAndCheck(tokens, \"{\");\n\n // The new scope is that of the new ROOT nodes children.\n stack.push(node.children!);\n break;\n }\n\n case \"BRANCH\": {\n // Create a BRANCH AST node.\n const node = ASTNodeFactories.BRANCH();\n\n // Push the BRANCH node into the current scope.\n currentScope.push(node);\n\n // We must have arguments defined, as we require a branch name argument.\n if (tokens[0] !== \"[\") {\n throw new Error(\"expected single branch name argument\");\n }\n\n // The branch name will be defined as a node argument.\n const branchArguments = getArguments(tokens, placeholders);\n\n // We should have only a single identifer argument for a branch node, which is the branch name.\n if (branchArguments.length === 1 && branchArguments[0].type === \"identifier\") {\n // The branch name will be the first and only node argument.\n node.branchName = branchArguments[0].value as string;\n } else {\n throw new Error(\"expected single branch name argument\");\n }\n break;\n }\n\n case \"SELECTOR\": {\n // Create a SELECTOR AST node.\n const node = ASTNodeFactories.SELECTOR();\n\n // Push the SELECTOR node into the current scope.\n currentScope.push(node);\n\n // Try to pick any attributes off of the token stack.\n node.attributes = getAttributes(tokens, placeholders);\n\n popAndCheck(tokens, \"{\");\n\n // The new scope is that of the new SELECTOR nodes children.\n stack.push(node.children!);\n break;\n }\n\n case \"SEQUENCE\": {\n // Create a SEQUENCE AST node.\n const node = ASTNodeFactories.SEQUENCE();\n\n // Push the SEQUENCE node into the current scope.\n currentScope.push(node);\n\n // Try to pick any attributes off of the token stack.\n node.attributes = getAttributes(tokens, placeholders);\n\n popAndCheck(tokens, \"{\");\n\n // The new scope is that of the new SEQUENCE nodes children.\n stack.push(node.children!);\n break;\n }\n\n case \"PARALLEL\": {\n // Create a PARALLEL AST node.\n const node = ASTNodeFactories.PARALLEL();\n\n // Push the PARALLEL node into the current scope.\n currentScope.push(node);\n\n // Try to pick any attributes off of the token stack.\n node.attributes = getAttributes(tokens, placeholders);\n\n popAndCheck(tokens, \"{\");\n\n // The new scope is that of the new PARALLEL nodes children.\n stack.push(node.children!);\n break;\n }\n\n case \"LOTTO\": {\n // Create a LOTTO AST node.\n const node = ASTNodeFactories.LOTTO();\n\n // Push the LOTTO node into the current scope.\n currentScope.push(node);\n\n // If the next token is a '[' character then some ticket counts have been defined as arguments.\n if (tokens[0] === \"[\") {\n // Get the ticket count arguments, each argument must be a number.\n node.tickets = getArguments(\n tokens,\n placeholders,\n (arg) => arg.type === \"number\" && !!arg.isInteger,\n \"lotto node ticket counts must be integer values\"\n ).map((argument) => argument.value as number);\n }\n\n // Try to pick any attributes off of the token stack.\n node.attributes = getAttributes(tokens, placeholders);\n\n popAndCheck(tokens, \"{\");\n\n // The new scope is that of the new LOTTO nodes children.\n stack.push(node.children!);\n break;\n }\n\n case \"CONDITION\": {\n // Create a CONDITION AST node.\n const node = ASTNodeFactories.CONDITION();\n\n // Push the CONDITION node into the current scope.\n currentScope.push(node);\n\n // We must have arguments defined, as we require a condition function name argument.\n if (tokens[0] !== \"[\") {\n throw new Error(\"expected condition name identifier argument\");\n }\n\n // Grab the condition node arguments.\n const conditionArguments = getArguments(tokens, placeholders);\n\n // We should have at least a single identifier argument for a condition node, which is the condition function name.\n if (conditionArguments.length && conditionArguments[0].type === \"identifier\") {\n // The condition function name will be the first node argument.\n node.conditionName = conditionArguments.shift()!.value as string;\n } else {\n throw new Error(\"expected condition name identifier argument\");\n }\n\n // Only the first argument should have been an identifier, all following arguments must be string, number, boolean or null.\n conditionArguments\n .filter((arg) => arg.type === \"identifier\")\n .forEach((arg) => {\n throw new Error(\n \"invalid condition node argument value '\" +\n arg.value +\n \"', must be string, number, boolean or null\"\n );\n });\n\n // Any node arguments that follow the condition name identifier will be treated as condition function arguments.\n node.conditionArguments = conditionArguments;\n\n // Try to pick any attributes off of the token stack.\n node.attributes = getAttributes(tokens, placeholders);\n break;\n }\n\n case \"FLIP\": {\n // Create a FLIP AST node.\n const node = ASTNodeFactories.FLIP();\n\n // Push the Flip node into the current scope.\n currentScope.push(node);\n\n // Try to pick any attributes off of the token stack.\n node.attributes = getAttributes(tokens, placeholders);\n\n popAndCheck(tokens, \"{\");\n\n // The new scope is that of the new FLIP nodes children.\n stack.push(node.children!);\n break;\n }\n\n case \"SUCCEED\": {\n // Create a SUCCEED AST node.\n const node = ASTNodeFactories.SUCCEED();\n\n // Push the Succeed node into the current scope.\n currentScope.push(node);\n\n // Try to pick any attributes off of the token stack.\n node.attributes = getAttributes(tokens, placeholders);\n\n popAndCheck(tokens, \"{\");\n\n // The new scope is that of the new Succeed nodes children.\n stack.push(node.children!);\n break;\n }\n\n case \"FAIL\": {\n // Create a FAIL AST node.\n const node = ASTNodeFactories.FAIL();\n\n // Push the Fail node into the current scope.\n currentScope.push(node);\n\n // Try to pick any attributes off of the token stack.\n node.attributes = getAttributes(tokens, placeholders);\n\n popAndCheck(tokens, \"{\");\n\n // The new scope is that of the new Fail nodes children.\n stack.push(node.children!);\n break;\n }\n\n case \"WAIT\": {\n // Create a WAIT AST node.\n const node = ASTNodeFactories.WAIT();\n\n // Push the WAIT node into the current scope.\n currentScope.push(node);\n\n // The arguments of a wait node are optional. We may have:\n // - No node arguments, in which case the wait will be indefinite until it is aborted.\n // - One node argument which will be the explicit duration of the wait.\n // - Two node arguments which define the min and max duration bounds from which a random duration will be picked.\n if (tokens[0] === \"[\") {\n // Get the optional duration and longest duration of the wait.\n const nodeArguments = getArguments(\n tokens,\n placeholders,\n (arg) => arg.type === \"number\" && !!arg.isInteger,\n \"wait node durations must be integer values\"\n ).map((argument) => argument.value);\n\n // We may have:\n // - One node argument which will be the explicit duration of the wait.\n // - Two node arguments which define the min and max duration bounds from which a random duration will be picked.\n // - Too many arguments, which is not valid.\n if (nodeArguments.length === 1) {\n // An explicit duration was defined.\n node.duration = nodeArguments[0] as number;\n } else if (nodeArguments.length === 2) {\n // Min and max duration bounds were defined from which a random duration will be picked.\n node.durationMin = nodeArguments[0] as number;\n node.durationMax = nodeArguments[1] as number;\n } else if (nodeArguments.length > 2) {\n // An incorrect number of durations was defined.\n throw new Error(\"invalid number of wait node duration arguments defined\");\n }\n }\n\n // Try to pick any attributes off of the token stack.\n node.attributes = getAttributes(tokens, placeholders);\n break;\n }\n\n case \"REPEAT\": {\n // Create a REPEAT AST node.\n const node = ASTNodeFactories.REPEAT();\n\n // Push the REPEAT node into the current scope.\n currentScope.push(node);\n\n // The arguments of a repeat node are optional. We may have:\n // - No node arguments, in which case the repeat note will iterate indefinitely.\n // - One node argument which will be the explicit number of iterations to make.\n // - Two node arguments which define the min and max iteration bounds from which a random iteration count will be picked.\n if (tokens[0] === \"[\") {\n // An iteration count has been defined. Get the iteration and potential maximum iteration of the wait.\n const nodeArguments = getArguments(\n tokens,\n placeholders,\n (arg) => arg.type === \"number\" && !!arg.isInteger,\n \"repeat node iteration counts must be integer values\"\n ).map((argument) => argument.value);\n\n // We should have got one or two iteration counts.\n if (nodeArguments.length === 1) {\n // A static iteration count was defined.\n node.iterations = nodeArguments[0] as number;\n } else if (nodeArguments.length === 2) {\n // A minimum and maximum iteration count was defined.\n node.iterationsMin = nodeArguments[0] as number;\n node.iterationsMax = nodeArguments[1] as number;\n } else {\n // An incorrect number of iteration counts was defined.\n throw new Error(\"invalid number of repeat node iteration count arguments defined\");\n }\n }\n\n // Try to pick any attributes off of the token stack.\n node.attributes = getAttributes(tokens, placeholders);\n\n popAndCheck(tokens, \"{\");\n\n // The new scope is that of the new REPEAT nodes children.\n stack.push(node.children!);\n break;\n }\n\n case \"RETRY\": {\n // Create a RETRY AST node.\n const node = ASTNodeFactories.RETRY();\n\n // Push the RETRY node into the current scope.\n currentScope.push(node);\n\n // The arguments of a retry node are optional. We may have:\n // - No node arguments, in which case the retry note will attempt indefinitely.\n // - One node argument which will be the explicit number of attempts to make.\n // - Two node arguments which define the min and max attempt bounds from which a random attempt count will be picked.\n if (tokens[0] === \"[\") {\n // An attempt count has been defined. Get the attempt count and potential maximum attempt count of the wait.\n const nodeArguments = getArguments(\n tokens,\n placeholders,\n (arg) => arg.type === \"number\" && !!arg.isInteger,\n \"retry node attempt counts must be integer values\"\n ).map((argument) => argument.value);\n\n // We should have got one or two attempt counts.\n if (nodeArguments.length === 1) {\n // A static attempt count was defined.\n node.attempts = nodeArguments[0] as number;\n } else if (nodeArguments.length === 2) {\n // A minimum and maximum attempt count was defined.\n node.attemptsMin = nodeArguments[0] as number;\n node.attemptsMax = nodeArguments[1] as number;\n } else {\n // An incorrect number of attempt counts was defined.\n throw new Error(\"invalid number of retry node attempt count arguments defined\");\n }\n }\n\n // Try to pick any attributes off of the token stack.\n node.attributes = getAttributes(tokens, placeholders);\n\n popAndCheck(tokens, \"{\");\n\n // The new scope is that of the new RETRY nodes children.\n stack.push(node.children!);\n break;\n }\n\n case \"ACTION\": {\n // Create a ACTION AST node.\n const node = ASTNodeFactories.ACTION();\n\n // Push the ACTION node into the current scope.\n currentScope.push(node);\n\n // We must have arguments defined, as we require an action name argument.\n if (tokens[0] !== \"[\") {\n throw new Error(\"expected action name identifier argument\");\n }\n\n // The action name will be defined as a node argument.\n const actionArguments = getArguments(tokens, placeholders);\n\n // We should have at least one identifer argument for an action node, which is the action name.\n if (actionArguments.length && actionArguments[0].type === \"identifier\") {\n // The action name will be the first and only node argument.\n node.actionName = actionArguments.shift()!.value as string;\n } else {\n throw new Error(\"expected action name identifier argument\");\n }\n\n // Only the first argument should have been an identifier, all following arguments must be string, number, boolean or null.\n actionArguments\n .filter((arg) => arg.type === \"identifier\")\n .forEach((arg) => {\n throw new Error(\n \"invalid action node argument value '\" +\n arg.value +\n \"', must be string, number, boolean or null\"\n );\n });\n\n // Any node arguments that follow the action name identifier will be treated as action function arguments.\n node.actionArguments = actionArguments;\n\n // Try to pick any attributes off of the token stack.\n node.attributes = getAttributes(tokens, placeholders);\n break;\n }\n\n case \"}\": {\n // The '}' character closes the current scope.\n stack.pop();\n break;\n }\n\n default: {\n throw new Error(`unexpected token '${token}'`);\n }\n }\n }\n\n // A function to recursively validate each of the nodes in the AST.\n const validateASTNode = (node: Validatable, depth: number): void => {\n // Validate the node.\n node.validate(depth);\n\n // Validate each child of the node.\n (node.children || []).forEach((child) => validateASTNode(child, depth + 1));\n };\n\n // Start node validation from the definition root.\n validateASTNode(\n {\n children: stack[0] as RootAstNode[],\n validate(this: { children: RootAstNode[] }) {\n // We must have at least one node defined as the definition scope, which should be a root node.\n if (this.children.length === 0) {\n throw new Error(\"expected root node to have been defined\");\n }\n\n // Each node at the base of the definition scope MUST be a root node.\n for (const definitionLevelNode of this.children) {\n if (definitionLevelNode.type !== \"root\") {\n throw new Error(\"expected root node at base of definition\");\n }\n }\n\n // Exactly one root node must not have a name defined. This will be the main root, others will have to be referenced via branch nodes.\n if (this.children.filter((definitionLevelNode) => definitionLevelNode.name === null).length !== 1) {\n throw new Error(\"expected single unnamed root node at base of definition to act as main root\");\n }\n\n // No two named root nodes can have matching names.\n const rootNodeNames: string[] = [];\n for (const definitionLevelNode of this.children) {\n if (rootNodeNames.indexOf(definitionLevelNode.name!) !== -1) {\n throw new Error(`multiple root nodes found with duplicate name '${definitionLevelNode.name}'`);\n } else {\n rootNodeNames.push(definitionLevelNode.name!);\n }\n }\n }\n },\n 0\n );\n\n // Return the root AST nodes.\n return stack[0];\n}\n\n/**\n * Pop the next raw token off of the stack and throw an error if it wasn't the expected one.\n * @param tokens The array of remaining tokens.\n * @param expected An optional string or array or items, one of which must match the next popped token.\n * @returns The popped token.\n */\nfunction popAndCheck(tokens: string[], expected: string | string[]) {\n // Get and remove the next token.\n const popped = tokens.shift();\n\n // We were expecting another token.\n if (popped === undefined) {\n throw new Error(\"unexpected end of definition\");\n }\n\n // Do we have an expected token/tokens array?\n if (expected !== undefined) {\n // Check whether the popped token matches at least one of our expected items.\n var tokenMatchesExpectation = ([] as string[])\n .concat(expected)\n .some((item) => popped.toUpperCase() === item.toUpperCase());\n\n // Throw an error if the popped token didn't match any of our expected items.\n if (!tokenMatchesExpectation) {\n const expectationString = ([] as string[])\n .concat(expected)\n .map((item) => \"'\" + item + \"'\")\n .join(\" or \");\n\n throw new Error(`unexpected token found. Expected '${expectationString}' but got '${popped}'`);\n }\n }\n\n // Return the popped token.\n return popped;\n}\n\ntype StringPlaceholders = { [key: string]: string };\n\n/**\n * Pull an argument definition list off of the token stack.\n * @param tokens The array of remaining tokens.\n * @param stringArgumentPlaceholders The mapping of string literal node argument placeholders to original values.\n * @param argumentValidator The argument validator function.\n * @param validationFailedMessage The exception message to throw if argument validation fails.\n * @returns The argument definition list.\n */\nfunction getArguments(\n tokens: string[],\n stringArgumentPlaceholders: StringPlaceholders,\n argumentValidator?: (arg: AnyArgument) => boolean,\n validationFailedMessage?: string\n) {\n // Any lists of arguments will always be wrapped in '[]' for node arguments or '()' for attribute arguments.\n // We are looking for a '[' or '(' opener that wraps the argument tokens and the relevant closer.\n const closer = popAndCheck(tokens, [\"[\", \"(\"]) === \"[\" ? \"]\" : \")\";\n\n const argumentListTokens: string[] = [];\n const argumentList: AnyArgument[] = [];\n\n // Grab all tokens between the '[' and ']' or '(' and ')'.\n while (tokens.length && tokens[0] !== closer) {\n // The next token is part of our arguments list.\n argumentListTokens.push(tokens.shift()!);\n }\n\n // Validate the order of the argument tokens. Each token must either be a ',' or a single argument that satisfies the validator.\n argumentListTokens.forEach((token, index) => {\n // Get whether this token should be an actual argument.\n const shouldBeArgumentToken = !(index & 1);\n\n // If the current token should be an actual argument then validate it,otherwise it should be a ',' token.\n if (shouldBeArgumentToken) {\n // Get the argument definition.\n const argumentDefinition = getArgumentDefinition(token!, stringArgumentPlaceholders);\n\n // Try to validate the argument.\n if (argumentValidator && !argumentValidator(argumentDefinition)) {\n throw new Error(validationFailedMessage);\n }\n\n // This is a valid argument!\n argumentList.push(argumentDefinition);\n } else {\n // The current token should be a ',' token.\n if (token !== \",\") {\n throw new Error(`invalid argument list, expected ',' or ']' but got '${token}'`);\n }\n }\n });\n\n // The arguments list should terminate with a ']' or ')' token, depending on the opener.\n popAndCheck(tokens, closer);\n\n // Return the argument list.\n return argumentList;\n}\n\n/**\n * Gets an argument value definition.\n * @param token The argument token.\n * @param stringArgumentPlaceholders The mapping of string literal node argument placeholders to original values.\n * @returns An argument value definition.\n */\nfunction getArgumentDefinition(token: string, stringArgumentPlaceholders: StringPlaceholders): AnyArgument {\n // Check whether the token represents a null value.\n if (token === \"null\") {\n return {\n value: null,\n type: \"null\"\n } as NullArgument;\n }\n\n // Check whether the token represents a boolean value.\n if (token === \"true\" || token === \"false\") {\n return {\n value: token === \"true\",\n type: \"boolean\"\n } as BooleanArgument;\n }\n\n // Check whether the token represents a number value.\n // TODO: Relies on broken isNaN - see MDN.\n // if (!Number.isNaN(token)) {\n if (!isNaN(token as any)) {\n return {\n value: parseFloat(token),\n isInteger: parseFloat(token) === parseInt(token, 10),\n type: \"number\"\n } as NumberArgument;\n }\n\n // Check whether the token is a placeholder (e.g. @@0@@) representing a string literal.\n if (token.match(/^@@\\d+@@$/g)) {\n return {\n value: stringArgumentPlaceholders[token].replace('\\\\\"', '\"'),\n type: \"string\"\n } as StringPlaceholderArgument;\n }\n\n // The only remaining option is that the argument value is an identifier.\n return {\n value: token,\n type: \"identifier\"\n } as IdentifierArgument;\n}\n\n/**\n * Pull any attributes off of the token stack.\n * @param tokens The array of remaining tokens.\n * @param stringArgumentPlaceholders The mapping of string literal node argument placeholders to original values.\n * @returns An array of attributes defined by any directly following tokens.\n */\nfunction getAttributes(tokens: string[], stringArgumentPlaceholders: StringPlaceholders) {\n // Create an array to hold any attributes found.\n const attributes: Attribute[] = [];\n\n // Keep track of names of attribute that we have found on the token stack, as we cannot have duplicates.\n const attributesFound: string[] = [];\n\n // Try to get the attribute factory for the next token.\n let attributeFactory = AttributeFactories[(tokens[0] || \"\").toUpperCase()];\n\n // Pull attribute tokens off of the tokens stack until we have no more.\n while (attributeFactory) {\n // Check to make sure that we have not already created a attribute of this type for this node.\n if (attributesFound.indexOf(tokens[0].toUpperCase()) !== -1) {\n throw new Error(`duplicate attribute '${tokens[0].toUpperCase()}' found for node`);\n }\n\n // Add the current attribute type to our array of found attributes.\n attributesFound.push(tokens.shift()!.toUpperCase());\n\n // Grab any attribute arguments.\n const attributeArguments = getArguments(tokens, stringArgumentPlaceholders);\n\n // The first attribute argument has to be an identifer, this will reference an agent function.\n if (attributeArguments.length === 0 || attributeArguments[0].type !== \"identifier\") {\n throw new Error(\"expected agent function name identifier argument for attribute\");\n }\n\n // Grab the first attribute which is an identifier that will reference an agent function.\n const attributeFunctionName = attributeArguments.shift()! as IdentifierArgument;\n\n // Any remaining attribute arguments must have a type of string, number, boolean or null.\n attributeArguments\n .filter((arg) => arg.type === \"identifier\")\n .forEach((arg) => {\n throw new Error(\n \"invalid attribute argument value '\" + arg.value + \"', must be string, number, boolean or null\"\n );\n });\n\n // Create the attribute and add it to the array of attributes found.\n attributes.push(attributeFactory(attributeFunctionName.value, attributeArguments));\n\n // Try to get the next attribute name token, as there could be multiple.\n attributeFactory = AttributeFactories[(tokens[0] || \"\").toUpperCase()];\n }\n\n return attributes;\n}\n\n/**\n * Swaps out any node/attribute argument string literals with placeholders.\n * @param definition The definition.\n * @returns An object containing a mapping of placeholders to original string values as well as the processed definition string.\n */\nfunction substituteStringLiterals(definition: string): {\n placeholders: { [key: string]: string };\n processedDefinition: string;\n} {\n // Create an object to hold the mapping of placeholders to original string values.\n const placeholders: StringPlaceholders = {};\n\n // Replace any string literals wrapped with double quotes in our definition with placeholders to be processed later.\n const processedDefinition = definition.replace(/\\\"(\\\\.|[^\"\\\\])*\\\"/g, (match) => {\n var strippedMatch = match.substring(1, match.length - 1);\n var placeholder = Object.keys(placeholders).find((key) => placeholders[key] === strippedMatch);\n\n // If we have no existing string literal match then create a new placeholder.\n if (!placeholder) {\n placeholder = `@@${Object.keys(placeholders).length}@@`;\n placeholders[placeholder] = strippedMatch;\n }\n\n return placeholder;\n });\n\n return { placeholders, processedDefinition };\n}\n\n/**\n * Parse the tree definition into an array of raw tokens.\n * @param definition The definition.\n * @returns An array of tokens parsed from the definition.\n */\nfunction parseTokensFromDefinition(definition: string): string[] {\n // Add some space around various important characters so that they can be plucked out easier as individual tokens.\n definition = definition.replace(/\\(/g, \" ( \");\n definition = definition.replace(/\\)/g, \" ) \");\n definition = definition.replace(/\\{/g, \" { \");\n definition = definition.replace(/\\}/g, \" } \");\n definition = definition.replace(/\\]/g, \" ] \");\n definition = definition.replace(/\\[/g, \" [ \");\n definition = definition.replace(/\\,/g, \" , \");\n\n // Split the definition into raw token form and return it.\n return definition.replace(/\\s+/g, \" \").trim().split(\" \");\n}\n", "import GuardPath, { GuardPathPart } from \"./attributes/guards/GuardPath\";\nimport buildRootASTNodes, { AnyArgument, RootAstNode } from \"./RootAstNodesBuilder\";\nimport State, { AnyState } from \"./State\";\nimport Lookup from \"./Lookup\";\nimport Node from \"./nodes/Node\";\nimport Root from \"./nodes/decorator/Root\";\nimport Composite from \"./nodes/composite/Composite\";\nimport Decorator from \"./nodes/decorator/Decorator\";\nimport { Agent, GlobalFunction } from \"./Agent\";\nimport { CallbackAttributeDetails } from \"./attributes/callbacks/Callback\";\nimport { GuardAttributeDetails } from \"./attributes/guards/Guard\";\nimport { BehaviourTreeOptions } from \"./BehaviourTreeOptions\";\nimport { parseMDSLToJSON } from \"./mdsl/MDSLDefinitionParser\";\n\n// Purely for outside inspection of the tree.\nexport type FlattenedTreeNode = {\n id: string;\n type: string;\n caption: string;\n state: AnyState;\n guards: GuardAttributeDetails[];\n callbacks: CallbackAttributeDetails[];\n args: AnyArgument[];\n parentId: string | null;\n};\n\n/**\n * A representation of a behaviour tree.\n */\nexport class BehaviourTree {\n /**\n * The main root tree node.\n */\n public readonly rootNode: Root;\n\n /**\n * Creates a new instance of the BehaviourTree class.\n * @param definition The behaviour tree definition.\n * @param agent The agent instance that this behaviour tree is modelling behaviour for.\n * @param options The behaviour tree options object.\n */\n constructor(definition: string, private agent: Agent, private options: BehaviourTreeOptions = {}) {\n // The tree definition must be defined and a valid string.\n if (typeof definition !== \"string\") {\n throw new Error(\"the tree definition must be a string\");\n }\n\n // The agent must be defined and not null.\n if (typeof agent !== \"object\" || agent === null) {\n throw new Error(\"the agent must be defined and not null\");\n }\n\n // Parse the behaviour tree definition, create the populated tree of behaviour tree nodes, and get the root.\n this.rootNode = BehaviourTree._createRootNode(definition);\n }\n\n /**\n * Gets whether the tree is in the RUNNING state.\n * @returns true if the tree is in the RUNNING state, otherwise false.\n */\n isRunning() {\n return this.rootNode.getState() === State.RUNNING;\n }\n\n /**\n * Gets the current tree state of SUCCEEDED, FAILED, READY or RUNNING.\n * @returns The current tree state.\n */\n getState() {\n return this.rootNode.getState();\n }\n\n /**\n * Step the tree.\n * 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.\n * 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\n * 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.\n *\n * 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.\n */\n step() {\n // If the root node has already been stepped to completion then we need to reset it.\n if (this.rootNode.getState() === State.SUCCEEDED || this.rootNode.getState() === State.FAILED) {\n this.rootNode.reset();\n }\n\n try {\n this.rootNode.update(this.agent, this.options);\n } catch (exception) {\n throw new Error(`error stepping tree: ${(exception as Error).message}`);\n }\n }\n\n /**\n * Resets the tree from the root node outwards to each nested node, giving each a state of READY.\n */\n reset() {\n this.rootNode.reset();\n }\n\n /**\n * Gets the flattened details of every node in the tree.\n * @returns The flattened details of every node in the tree.\n */\n getFlattenedNodeDetails(): FlattenedTreeNode[] {\n // Create an empty flattened array of tree nodes.\n const flattenedTreeNodes: FlattenedTreeNode[] = [];\n\n /**\n * Helper function to process a node instance and push details into the flattened tree nodes array.\n * @param node The current node.\n * @param parentUid The UID of the node parent, or null if the node is the main root node.\n */\n const processNode = (node: Node, parentUid: string | null) => {\n // Get the guard and callback attribute details for this node.\n const guards = node\n .getAttributes()\n .filter((attribute) => attribute.isGuard())\n .map((attribute) => attribute.getDetails()) as GuardAttributeDetails[];\n const callbacks = node\n .getAttributes()\n .filter((attribute) => !attribute.isGuard())\n .map((attribute) => attribute.getDetails()) as CallbackAttributeDetails[];\n\n // Push the current node into the flattened nodes array.\n flattenedTreeNodes.push({\n id: node.getUid(),\n type: node.getType(),\n caption: node.getName(),\n state: node.getState(),\n guards,\n callbacks,\n args: node.getArguments(),\n parentId: parentUid\n });\n\n // Process each of the nodes children if it is not a leaf node.\n if (!node.isLeafNode()) {\n (node as Composite | Decorator)\n .getChildren()\n .forEach((child) => processNode(child, (node as Composite | Decorator).getUid()));\n }\n };\n\n // Convert the nested node structure into a flattened array of node details.\n processNode(this.rootNode, null);\n\n return flattenedTreeNodes;\n }\n\n /**\n * Registers the action/condition/guard/callback function or subtree with the given name.\n * @param name The name of the function or subtree to register.\n * @param value The function or subtree definition to register.\n */\n static register(name: string, value: GlobalFunction | string) {\n if (typeof value === \"function\") {\n // We are going to register a action/condition/guard/callback function.\n Lookup.setFunc(name, value);\n } else if (typeof value === \"string\") {\n // We are going to register a subtree.\n let rootASTNodes: RootAstNode[];\n\n try {\n // Try to create the behaviour tree AST based on the definition provided, this could fail if the definition is invalid.\n rootASTNodes = buildRootASTNodes(value);\n } catch (exception) {\n // There was an issue in trying to parse and build the tree definition.\n throw new Error(`error registering definition: ${(exception as Error).message}`);\n }\n\n // This function should only ever be called with a definition containing a single unnamed root node.\n if (rootASTNodes.length != 1 || rootASTNodes[0].name !== null) {\n throw new Error(\"error registering definition: expected a single unnamed root node\");\n }\n\n Lookup.setSubtree(name, rootASTNodes[0]);\n } else {\n throw new Error(\"unexpected value, expected string definition or function\");\n }\n }\n\n /**\n * Unregisters the registered action/condition/guard/callback function or subtree with the given name.\n * @param name The name of the registered action/condition/guard/callback function or subtree to unregister.\n */\n static unregister(name: string): void {\n Lookup.remove(name);\n }\n\n /**\n * Unregister all registered action/condition/guard/callback functions and subtrees.\n */\n static unregisterAll(): void {\n Lookup.empty();\n }\n\n /**\n * Parses a behaviour tree definition and creates a tree of behaviour tree nodes.\n * @param {string} definition The behaviour tree definition.\n * @returns The root behaviour tree node.\n */\n private static _createRootNode(definition: string): Root {\n // TODO Remove!\n try {\n // parseToJSON(definition);\n } catch (exception) {\n console.log(exception);\n }\n\n try {\n // Try to create the behaviour tree AST based on the definition provided, this could fail if the definition is invalid.\n const rootASTNodes = buildRootASTNodes(definition);\n\n // Create a symbol to use as the main root key in our root node mapping.\n const mainRootNodeKey = Symbol(\"__root__\");\n\n // Create a mapping of root node names to root AST tokens. The main root node will have a key of Symbol(\"__root__\").\n const rootNodeMap: { [key: string | symbol]: RootAstNode } = {};\n for (const rootASTNode of rootASTNodes) {\n rootNodeMap[rootASTNode.name === null ? mainRootNodeKey : rootASTNode.name!] = rootASTNode;\n }\n\n // Convert the AST to our actual tree and get the root node.\n const rootNode: Root = rootNodeMap[mainRootNodeKey].createNodeInstance(\n // Create a provider for named root nodes that are part of our definition or have been registered. Prioritising the former.\n (name: string): RootAstNode => (rootNodeMap[name] ? rootNodeMap[name] : Lookup.getSubtree(name)),\n []\n );\n\n // Set a guard path on every leaf of the tree to evaluate as part of its update.\n BehaviourTree._applyLeafNodeGuardPaths(rootNode);\n\n // Return the root node.\n return rootNode;\n } catch (exception) {\n // There was an issue in trying to parse and build the tree definition.\n throw new Error(`error parsing tree: ${(exception as Error).message}`);\n }\n }\n\n /**\n * Applies a guard path to every leaf of the tree to evaluate as part of each update.\n * @param rootNode The main root tree node.\n */\n private static _applyLeafNodeGuardPaths(rootNode: Root) {\n const nodePaths: Node[][] = [];\n\n const findLeafNodes = (path: Node[], node: Node) => {\n // Add the current node to the path.\n path = path.concat(node);\n\n // Check whether the current node is a leaf node.\n if (node.isLeafNode()) {\n nodePaths.push(path);\n } else {\n (node as Composite | Decorator).getChildren().forEach((child) => findLeafNodes(path, child));\n }\n };\n\n // Find all leaf node paths, starting from the root.\n findLeafNodes([], rootNode);\n\n nodePaths.forEach((path) => {\n // Each node in the current path will have to be assigned a guard path, working from the root outwards.\n for (let depth = 0; depth < path.length; depth++) {\n // Get the node in the path at the current depth.\n const currentNode = path[depth];\n\n // The node may already have been assigned a guard path, if so just skip it.\n if (currentNode.hasGuardPath()) {\n continue;\n }\n\n // Create the guard path for the current node.\n const guardPath = new GuardPath(\n path\n .slice(0, depth + 1)\n .map((node) => ({ node, guards: node.getGuardAttributes() }))\n .filter((details) => details.guards.length > 0)\n );\n\n // Assign the guard path to the current node.\n currentNode.setGuardPath(guardPath);\n }\n });\n }\n}\n", "import {\n CompositeNodeDefinition,\n DecoratorNodeDefinition,\n NodeDefinition,\n RootNodeDefinition\n} from \"../BehaviourTreeDefinition\";\n\n/**\n * A type defining an object that holds a reference to substitued string literals parsed from the definition.\n */\nexport type StringLiteralPlaceholders = { [key: string]: string };\n\n/**\n * A type guard function that returns true if the specified node satisfies the RootNodeDefinition type.\n * @param node The node.\n * @returns A value of true if the specified node satisfies the RootNodeDefinition type.\n */\nexport function isRootNode(node: NodeDefinition): node is RootNodeDefinition {\n return node.type === \"root\";\n}\n\n/**\n * A type guard function that returns true if the specified node satisfies the NodeDefinition type.\n * @param node The node.\n * @returns A value of true if the specified node satisfies the NodeDefinition type.\n */\nexport function isLeafNode(node: NodeDefinition): node is NodeDefinition {\n return [\"branch\", \"action\", \"condition\", \"wait\"].includes(node.type);\n}\n\n/**\n * A type guard function that returns true if the specified node satisfies the DecoratorNodeDefinition type.\n * @param node The node.\n * @returns A value of true if the specified node satisfies the DecoratorNodeDefinition type.\n */\nexport function isDecoratorNode(node: NodeDefinition): node is DecoratorNodeDefinition {\n return [\"root\", \"repeat\", \"retry\", \"flip\", \"succeed\", \"fail\"].includes(node.type);\n}\n\n/**\n * A type guard function that returns true if the specified node satisfies the CompositeNodeDefinition type.\n * @param node The node.\n * @returns A value of true if the specified node satisfies the CompositeNodeDefinition type.\n */\nexport function isCompositeNode(node: NodeDefinition): node is CompositeNodeDefinition {\n return [\"sequence\", \"selector\", \"lotto\", \"parallel\"].includes(node.type);\n}\n\n/**\n * Pop the next raw token from the specified array of tokens and throw an error if it wasn't the expected one.\n * @param tokens The array of tokens.\n * @param expected An optional string or array or items, one of which must match the next popped token.\n * @returns The popped token.\n */\nexport function popAndCheck(tokens: string[], expected?: string | string[]): string {\n // Get and remove the next token.\n const popped = tokens.shift();\n\n // We were expecting another token but there aren't any.\n if (popped === undefined) {\n throw new Error(\"unexpected end of definition\");\n }\n\n // Do we have an expected token/tokens array?\n if (expected != undefined) {\n // Get an array of expected values, if the popped token matches any then we are all good.\n const expectedValues = typeof expected === \"string\" ? [expected] : expected;\n\n // Check whether the popped token matches at least one of our expected items.\n var tokenMatchesExpectation = expectedValues.some((item) => popped.toUpperCase() === item.toUpperCase());\n\n // Throw an error if the popped token didn't match any of our expected items.\n if (!tokenMatchesExpectation) {\n const expectationString = expectedValues.map((item) => \"'\" + item + \"'\").join(\" or \");\n throw new Error(\"unexpected token found. Expected \" + expectationString + \" but got '\" + popped + \"'\");\n }\n }\n\n // Return the popped token.\n return popped;\n}\n\n/**\n * Swaps out any node/attribute argument string literals with placeholders.\n * @param definition The definition.\n * @returns An object containing a mapping of placeholders to original string values as well as the processed definition string.\n */\nexport function substituteStringLiterals(definition: string): {\n placeholders: StringLiteralPlaceholders;\n processedDefinition: string;\n} {\n // Create an object to hold the mapping of placeholders to original string values.\n const placeholders: StringLiteralPlaceholders = {};\n\n // Replace any string literals wrapped with double quotes in our definition with placeholders to be processed later.\n const processedDefinition = definition.replace(/\\\"(\\\\.|[^\"\\\\])*\\\"/g, (match) => {\n var strippedMatch = match.substring(1, match.length - 1);\n var placeholder = Object.keys(placeholders).find((key) => placeholders[key] === strippedMatch);\n\n // If we have no existing string literal match then create a new placeholder.\n if (!placeholder) {\n placeholder = `@@${Object.keys(placeholders).length}@@`;\n placeholders[placeholder] = strippedMatch;\n }\n\n return placeholder;\n });\n\n return { placeholders, processedDefinition };\n}\n\n/**\n * Parse the tree definition into an array of raw tokens.\n * @param definition The definition.\n * @returns An array of tokens parsed from the definition.\n */\nexport function parseTokensFromDefinition(definition: string): string[] {\n // Add some space around various important characters so that they can be plucked out easier as individual tokens.\n definition = definition.replace(/\\(/g, \" ( \");\n definition = definition.replace(/\\)/g, \" ) \");\n definition = definition.replace(/\\{/g, \" { \");\n definition = definition.replace(/\\}/g, \" } \");\n definition = definition.replace(/\\]/g, \" ] \");\n definition = definition.replace(/\\[/g, \" [ \");\n definition = definition.replace(/\\,/g, \" , \");\n\n // Split the definition into raw token form and return it.\n return definition.replace(/\\s+/g, \" \").trim().split(\" \");\n}\n", "import { StringLiteralPlaceholders, popAndCheck } from \"./MDSLUtilities\";\n\nexport type Argument = {\n /** The argument value. */\n value: T;\n /** The argument type, used for validation. */\n type: string;\n};\n\nexport type NullArgument = Argument & {\n type: \"null\";\n};\n\nexport type BooleanArgument = Argument & {\n type: \"boolean\";\n};\n\nexport type NumberArgument = Argument & {\n type: \"number\";\n isInteger: boolean; // Used for validation.\n};\n\nexport type StringPlaceholderArgument = Argument & {\n type: \"string\";\n};\n\nexport type IdentifierArgument = Argument & {\n type: \"identifier\";\n};\n\nexport type AnyArgument =\n | NullArgument\n | BooleanArgument\n | NumberArgument\n | StringPlaceholderArgument\n | IdentifierArgument;\n\n/**\n * Parse an array of argument definitions from the specified tokens array.\n * @param tokens The array tokens to parse the argument definitions from.\n * @param stringArgumentPlaceholders The mapping of string literal node argument placeholders to original values.\n * @param argumentValidator The argument validator function.\n * @param validationFailedMessage The exception message to throw if argument validation fails.\n * @returns An array of argument definitions parsed from the specified tokens array.\n */\nexport function parseArgumentTokens(\n tokens: string[],\n stringArgumentPlaceholders: StringLiteralPlaceholders\n): AnyArgument[] {\n const argumentList: AnyArgument[] = [];\n\n // If the next token is not a '[' or '(' then we have no arguments to parse.\n if (![\"[\", \"(\"].includes(tokens[0])) {\n return argumentList;\n }\n\n // Any lists of arguments will always be wrapped in '[]' for node arguments or '()' for attribute arguments.\n // We are looking for a '[' or '(' opener that wraps the argument tokens and the relevant closer.\n const closingToken = popAndCheck(tokens, [\"[\", \"(\"]) === \"[\" ? \"]\" : \")\";\n\n const argumentListTokens: string[] = [];\n\n // Grab all tokens between the '[' and ']' or '(' and ')'.\n while (tokens.length && tokens[0] !== closingToken) {\n // The next token is part of our arguments list.\n argumentListTokens.push(tokens.shift()!);\n }\n\n // Validate the order of the argument tokens. Each token must either be a ',' or a single argument that satisfies the validator.\n argumentListTokens.forEach((token, index) => {\n // Get whether this token should be an actual argument.\n const shouldBeArgumentToken = !(index & 1);\n\n // If the current token should be an actual argument then validate it, otherwise it should be a ',' token.\n if (shouldBeArgumentToken) {\n // Get the argument definition.\n const argumentDefinition = getArgumentDefinition(token, stringArgumentPlaceholders);\n\n // This is a valid argument!\n argumentList.push(argumentDefinition);\n } else {\n // The current token should be a ',' token.\n if (token !== \",\") {\n throw new Error(`invalid argument list, expected ',' or ']' but got '${token}'`);\n }\n }\n });\n\n // The arguments list should terminate with a ']' or ')' token, depending on the opener.\n popAndCheck(tokens, closingToken);\n\n // Return the arguments.\n return argumentList;\n}\n\n/**\n * Gets an argument value definition.\n * @param token The argument token.\n * @param stringArgumentPlaceholders The mapping of string literal node argument placeholders to original values.\n * @returns An argument value definition.\n */\nfunction getArgumentDefinition(token: string, stringArgumentPlaceholders: StringLiteralPlaceholders): AnyArgument {\n // Check whether the token represents a null value.\n if (token === \"null\") {\n return {\n value: null,\n type: \"null\"\n } as NullArgument;\n }\n\n // Check whether the token represents a boolean value.\n if (token === \"true\" || token === \"false\") {\n return {\n value: token === \"true\",\n type: \"boolean\"\n } as BooleanArgument;\n }\n\n // Check whether the token represents a number value.\n // TODO: Relies on broken isNaN - see MDN.\n // if (!Number.isNaN(token)) {\n if (!isNaN(token as any)) {\n return {\n value: parseFloat(token),\n isInteger: parseFloat(token) === parseInt(token, 10),\n type: \"number\"\n } as NumberArgument;\n }\n\n // Check whether the token is a placeholder (e.g. @@0@@) representing a string literal.\n if (token.match(/^@@\\d+@@$/g)) {\n return {\n value: stringArgumentPlaceholders[token].replace('\\\\\"', '\"'),\n type: \"string\"\n } as StringPlaceholderArgument;\n }\n\n // The only remaining option is that the argument value is an identifier.\n return {\n value: token,\n type: \"identifier\"\n } as IdentifierArgument;\n}\n", "import { NodeAttributeDefinition } from \"../BehaviourTreeDefinition\";\nimport { parseArgumentTokens } from \"./MDSLNodeArgumentParser\";\nimport { StringLiteralPlaceholders } from \"./MDSLUtilities\";\n\n/**\n * A type defining the attribute definitions of a node.\n */\ntype NodeAttributes = {\n while?: NodeAttributeDefinition;\n until?: NodeAttributeDefinition;\n entry?: NodeAttributeDefinition;\n exit?: NodeAttributeDefinition;\n step?: NodeAttributeDefinition;\n};\n\n/**\n * Parse any node attribute definitions from the specified tokens array.\n * @param tokens The array of remaining tokens.\n * @param stringArgumentPlaceholders The mapping of string literal node argument placeholders to original values.\n * @returns An object of attribute definitions defined by any directly following tokens.\n */\nexport function parseAttributeTokens(\n tokens: string[],\n stringArgumentPlaceholders: StringLiteralPlaceholders\n): NodeAttributes {\n const nodeAttributeNames: (keyof NodeAttributes)[] = [\"while\", \"until\", \"entry\", \"exit\", \"step\"];\n\n // Create an object to hold any attributes found.\n const attributes: NodeAttributes = {};\n\n // Try to get the name of the attribute for the next token.\n let nextAttributeName = tokens[0]?.toLowerCase() as keyof NodeAttributes;\n\n // Pull attribute tokens as well as their arguments off of the tokens stack until we have no more.\n while (nodeAttributeNames.includes(nextAttributeName)) {\n // Check to make sure that we have not already created an attribute definition of this type.\n if (attributes[nextAttributeName]) {\n throw new Error(`duplicate attribute '${tokens[0].toUpperCase()}' found for node`);\n }\n\n // Remove the attribute name token from the array of tokens.\n tokens.shift();\n\n // Grab the attribute arguments, assuming the first to be an identifier.\n const [attributeCallIdentifier, ...attributeArguments] = parseArgumentTokens(\n tokens,\n stringArgumentPlaceholders\n );\n\n // The first attribute argument has to be an identifer, this will reference an agent function.\n if (attributeCallIdentifier?.type !== \"identifier\") {\n throw new Error(\"expected agent function name identifier argument for attribute\");\n }\n\n // Any attribute arguments (other than the expected call identifier) must have a type of string, number, boolean or null.\n attributeArguments\n .filter((arg) => arg.type === \"identifier\")\n .forEach((arg) => {\n throw new Error(\n `invalid attribute argument value '${arg.value}', must be string, number, boolean or null`\n );\n });\n\n // Create the attribute definition and add it to the object of attribute definitions found.\n attributes[nextAttributeName] = {\n call: attributeCallIdentifier.value,\n args: attributeArguments.map(({ value }) => value)\n };\n\n // Try to get the next attribute name token, as there could be multiple.\n nextAttributeName = tokens[0]?.toLowerCase() as keyof NodeAttributes;\n }\n\n return attributes;\n}\n", "import {\n ActionNodeDefinition,\n AnyChildNode,\n AnyNode,\n BranchNodeDefinition,\n ConditionNodeDefinition,\n FailNodeDefinition,\n FlipNodeDefinition,\n LottoNodeDefinition,\n ParallelNodeDefinition,\n RepeatNodeDefinition,\n RetryNodeDefinition,\n RootNodeDefinition,\n SelectorNodeDefinition,\n SequenceNodeDefinition,\n SucceedNodeDefinition,\n WaitNodeDefinition\n} from \"../BehaviourTreeDefinition\";\nimport { parseArgumentTokens } from \"./MDSLNodeArgumentParser\";\nimport { parseAttributeTokens } from \"./MDSLNodeAttributeParser\";\nimport {\n StringLiteralPlaceholders,\n isCompositeNode,\n isDecoratorNode,\n isLeafNode,\n isRootNode,\n parseTokensFromDefinition,\n popAndCheck,\n substituteStringLiterals\n} from \"./MDSLUtilities\";\n\n/**\n * Parse the MDSL tree definition string into an equivalent JSON definition.\n * @param definition The tree definition string as MDSL.\n * @returns The root node JSON definitions.\n */\nexport function parseMDSLToJSON(definition: string): RootNodeDefinition[] {\n // Swap out any node/attribute argument string literals with a placeholder and get a mapping of placeholders to original values as well as the processed definition.\n const { placeholders, processedDefinition } = substituteStringLiterals(definition);\n\n // Parse our definition definition string into an array of raw tokens.\n const tokens = parseTokensFromDefinition(processedDefinition);\n\n return convertTokensToJSONDefinition(tokens, placeholders);\n}\n\n/**\n * Converts the specified tree definition tokens into a JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The root node JSON definitions.\n */\nfunction convertTokensToJSONDefinition(\n tokens: string[],\n stringLiteralPlaceholders: StringLiteralPlaceholders\n): RootNodeDefinition[] {\n // There must be at least 3 tokens for the tree definition to be valid. 'ROOT', '{' and '}'.\n if (tokens.length < 3) {\n throw new Error(\"invalid token count\");\n }\n\n // We should have a matching number of '{' and '}' tokens. If not, then there are scopes that have not been properly closed.\n if (tokens.filter((token) => token === \"{\").length !== tokens.filter((token) => token === \"}\").length) {\n throw new Error(\"scope character mismatch\");\n }\n\n // Create an array of tree stack arrays where root nodes will always be at the botton and the current composite/decorator node at the top.\n // There should be an element in this array for every root node defined and every element should be an array with a root note as the first element.\n // E.g. A definition with two root nodes defined:\n // [\n // [root, lotto, sequence],\n // [root, selector]\n // ]\n const treeStacks: [Partial, ...Partial[]][] = [];\n\n // Create an array of all root node definitions that we create.\n const rootNodes: Partial[] = [];\n\n // A helper function used to push node definitions onto the tree stack.\n const pushNode = (node: AnyNode) => {\n // If the node is a root node then we need to create a new tree stack array with the root node at the root.\n if (isRootNode(node)) {\n // Add the root node definition to our array of all parsed root node definitions.\n rootNodes.push(node);\n\n // Add the root node definition to the root of a new tree stack.\n treeStacks.push([node]);\n\n return;\n }\n\n // All non-root nodes should be pushed after their root nodes so handle cases\n // where we may not have any tree stacks or our top-most tree stack is empty.\n if (!treeStacks.length || !treeStacks[treeStacks.length - 1].length) {\n throw new Error(\"expected root node at base of definition\");\n }\n\n // Get the current tree stack that we are populating.\n const topTreeStack = treeStacks[treeStacks.length - 1];\n\n // Get the top-most node in the current tree stack, this will be a composite/decorator node\n // for which we will populate its children array if composite or setting its child if a decorator.\n const topTreeStackTopNode = topTreeStack[topTreeStack.length - 1] as AnyNode;\n\n // If the top-most node in the current root stack is a composite or decorator\n // node then the current node should be added as a child of the top-most node.\n if (isCompositeNode(topTreeStackTopNode)) {\n topTreeStackTopNode.children = topTreeStackTopNode.children || [];\n topTreeStackTopNode.children.push(node);\n } else if (isDecoratorNode(topTreeStackTopNode)) {\n // If the top node already has a child node set then throw an error as a decorator should only have a single child.\n if (topTreeStackTopNode.child) {\n throw new Error(\"a decorator node must only have a single child node\");\n }\n\n topTreeStackTopNode.child = node;\n }\n\n // If the node we are adding is also a composite or decorator node, then we should push it\n // onto the current tree stack, as subsequent nodes will be added as its child/children.\n if (!isLeafNode(node)) {\n topTreeStack.push(node);\n }\n };\n\n // A helper function used to pop node definitions off of the stack.\n const popNode = () => {\n // Get the current tree stack that we are populating.\n const topTreeStack = treeStacks[treeStacks.length - 1];\n\n // Pop the top-most node in the current tree stack if there is one.\n if (topTreeStack.length) {\n topTreeStack.pop();\n }\n\n // We don't want any empty tree stacks in our stack of tree stacks.\n if (!topTreeStack.length) {\n treeStacks.pop();\n }\n };\n\n // We should keep processing the raw tokens until we run out of them.\n while (tokens.length) {\n // Grab the next token.\n const token = tokens.shift()!;\n\n // How we create the next node depends on the current raw token value.\n switch (token.toUpperCase()) {\n case \"ROOT\": {\n pushNode(createRootNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"SUCCEED\": {\n pushNode(createSucceedNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"FAIL\": {\n pushNode(createFailNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"FLIP\": {\n pushNode(createFlipNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"REPEAT\": {\n pushNode(createRepeatNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"RETRY\": {\n pushNode(createRetryNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"SEQUENCE\": {\n pushNode(createSequenceNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"SELECTOR\": {\n pushNode(createSelectorNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"PARALLEL\": {\n pushNode(createParallelNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"LOTTO\": {\n pushNode(createLottoNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"ACTION\": {\n pushNode(createActionNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"CONDITION\": {\n pushNode(createConditionNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"WAIT\": {\n pushNode(createWaitNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"BRANCH\": {\n pushNode(createBranchNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"}\": {\n // The '}' character closes the current scope and means that we have to pop a node off of the current stack.\n popNode();\n break;\n }\n\n default: {\n throw new Error(`unexpected token: ${token}`);\n }\n }\n }\n\n return rootNodes as RootNodeDefinition[];\n}\n\n/**\n * Creates a root node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The root node JSON definition.\n */\nfunction createRootNode(tokens: string[], stringLiteralPlaceholders: StringLiteralPlaceholders): RootNodeDefinition {\n // Create the root node definition.\n let node = {\n type: \"root\",\n id: undefined\n } as RootNodeDefinition;\n\n // Parse any node arguments, we should only have one if any which will be an identifier argument for the root identifier.\n const nodeArguments = parseArgumentTokens(tokens, stringLiteralPlaceholders);\n\n // Check whether any node arguments were defined.\n if (nodeArguments.length) {\n // We should only have one argument, if any, which will be an identifier argument for the root identifier.\n if (nodeArguments.length === 1 && nodeArguments[0].type === \"identifier\") {\n // The root node identifier will be the first and only node argument value.\n node.id = nodeArguments[0].value as string;\n } else {\n throw new Error(\"expected single root name argument\");\n }\n }\n\n // Grab any node attribute definitions and spread them into the node definition.\n node = { ...node, ...parseAttributeTokens(tokens, stringLiteralPlaceholders) };\n\n // This is a decorator node, so we expect an opening '{'.\n popAndCheck(tokens, \"{\");\n\n // Return the root node definition.\n return node;\n}\n\n/**\n * Creates a succeed node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The succeed node JSON definition.\n */\nfunction createSucceedNode(\n tokens: string[],\n stringLiteralPlaceholders: StringLiteralPlaceholders\n): SucceedNodeDefinition {\n const node = {\n type: \"succeed\",\n ...parseAttributeTokens(tokens, stringLiteralPlaceholders)\n } as SucceedNodeDefinition;\n\n // This is a decorator node, so we expect an opening '{'.\n popAndCheck(tokens, \"{\");\n\n // Return the succeed node definition.\n return node;\n}\n\n/**\n * Creates a fail node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The fail node JSON definition.\n */\nfunction createFailNode(tokens: string[], stringLiteralPlaceholders: StringLiteralPlaceholders): FailNodeDefinition {\n const node = {\n type: \"fail\",\n ...parseAttributeTokens(tokens, stringLiteralPlaceholders)\n } as FailNodeDefinition;\n\n // This is a decorator node, so we expect an opening '{'.\n popAndCheck(tokens, \"{\");\n\n // Return the fail node definition.\n return node;\n}\n\n/**\n * Creates a flip node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The flip node JSON definition.\n */\nfunction createFlipNode(tokens: string[], stringLiteralPlaceholders: StringLiteralPlaceholders): FlipNodeDefinition {\n const node = {\n type: \"flip\",\n ...parseAttributeTokens(tokens, stringLiteralPlaceholders)\n } as FlipNodeDefinition;\n\n // This is a decorator node, so we expect an opening '{'.\n popAndCheck(tokens, \"{\");\n\n // Return the flip node definition.\n return node;\n}\n\n/**\n * Creates a repeat node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The repeat node JSON definition.\n */\nfunction createRepeatNode(\n tokens: string[],\n stringLiteralPlaceholders: StringLiteralPlaceholders\n): RepeatNodeDefinition {\n let node = { type: \"repeat\" } as RepeatNodeDefinition;\n\n // Get the node arguments.\n const nodeArguments = parseArgumentTokens(tokens, stringLiteralPlaceholders);\n\n // The arguments of a repeat node are optional. We may have:\n // - No node arguments, in which case the repeat note will iterate indefinitely.\n // - One node argument which will be the explicit number of iterations to make.\n // - Two node arguments which define the min and max iteration bounds from which a random iteration count will be picked.\n if (nodeArguments.length) {\n // All repeat node arguments MUST be of type number and must be integer.\n nodeArguments\n .filter((arg) => arg.type !== \"number\" || !arg.isInteger)\n .forEach(() => {\n throw new Error(`repeat node iteration counts must be integer values`);\n });\n\n // We should have got one or two iteration counts.\n if (nodeArguments.length === 1) {\n // A static iteration count was defined.\n node.iterations = nodeArguments[0].value as number;\n } else if (nodeArguments.length === 2) {\n // A minimum and maximum iteration count was defined.\n node.iterations = [nodeArguments[0].value as number, nodeArguments[1].value as number];\n } else {\n // An incorrect number of iteration counts was defined.\n throw new Error(\"invalid number of repeat node iteration count arguments defined\");\n }\n }\n\n // Grab any node attribute definitions and spread them into the node definition.\n node = { ...node, ...parseAttributeTokens(tokens, stringLiteralPlaceholders) };\n\n // This is a decorator node, so we expect an opening '{'.\n popAndCheck(tokens, \"{\");\n\n // Return the repeat node definition.\n return node;\n}\n\n/**\n * Creates a retry node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The retry node JSON definition.\n */\nfunction createRetryNode(tokens: string[], stringLiteralPlaceholders: StringLiteralPlaceholders): RetryNodeDefinition {\n let node = { type: \"retry\" } as RetryNodeDefinition;\n\n // Get the node arguments.\n const nodeArguments = parseArgumentTokens(tokens, stringLiteralPlaceholders);\n\n // The arguments of a retry node are optional. We may have:\n // - No node arguments, in which case the retry note will attempt indefinitely.\n // - One node argument which will be the explicit number of attempts to make.\n // - Two node arguments which define the min and max attempt bounds from which a random attempt count will be picked.\n if (nodeArguments.length) {\n // All retry node arguments MUST be of type number and must be integer.\n nodeArguments\n .filter((arg) => arg.type !== \"number\" || !arg.isInteger)\n .forEach(() => {\n throw new Error(`retry node attempt counts must be integer values`);\n });\n\n // We should have got one or two attempt counts.\n if (nodeArguments.length === 1) {\n // A static attempt count was defined.\n node.attempts = nodeArguments[0].value as number;\n } else if (nodeArguments.length === 2) {\n // A minimum and maximum attempt count was defined.\n node.attempts = [nodeArguments[0].value as number, nodeArguments[1].value as number];\n } else {\n // An incorrect number of attempt counts was defined.\n throw new Error(\"invalid number of retry node attempt count arguments defined\");\n }\n }\n\n // Grab any node attribute definitions and spread them into the node definition.\n node = { ...node, ...parseAttributeTokens(tokens, stringLiteralPlaceholders) };\n\n // This is a decorator node, so we expect an opening '{'.\n popAndCheck(tokens, \"{\");\n\n // Return the retry node definition.\n return node;\n}\n\n/**\n * Creates a sequence node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The sequence node JSON definition.\n */\nfunction createSequenceNode(\n tokens: string[],\n stringLiteralPlaceholders: StringLiteralPlaceholders\n): SequenceNodeDefinition {\n const node = {\n type: \"sequence\",\n ...parseAttributeTokens(tokens, stringLiteralPlaceholders)\n } as SequenceNodeDefinition;\n\n // This is a composite node, so we expect an opening '{'.\n popAndCheck(tokens, \"{\");\n\n // Return the sequence node definition.\n return node;\n}\n\n/**\n * Creates a selector node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The selector node JSON definition.\n */\nfunction createSelectorNode(\n tokens: string[],\n stringLiteralPlaceholders: StringLiteralPlaceholders\n): SelectorNodeDefinition {\n const node = {\n type: \"selector\",\n ...parseAttributeTokens(tokens, stringLiteralPlaceholders)\n } as SelectorNodeDefinition;\n\n // This is a composite node, so we expect an opening '{'.\n popAndCheck(tokens, \"{\");\n\n // Return the selector node definition.\n return node;\n}\n\n/**\n * Creates a parallel node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The parallel node JSON definition.\n */\nfunction createParallelNode(\n tokens: string[],\n stringLiteralPlaceholders: StringLiteralPlaceholders\n): ParallelNodeDefinition {\n const node = {\n type: \"parallel\",\n ...parseAttributeTokens(tokens, stringLiteralPlaceholders)\n } as ParallelNodeDefinition;\n\n // This is a composite node, so we expect an opening '{'.\n popAndCheck(tokens, \"{\");\n\n // Return the parallel node definition.\n return node;\n}\n\n/**\n * Creates a lotto node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The lotto node JSON definition.\n */\nfunction createLottoNode(tokens: string[], stringLiteralPlaceholders: StringLiteralPlaceholders): LottoNodeDefinition {\n // If any node arguments have been defined then they must be our weights.\n const nodeArguments = parseArgumentTokens(tokens, stringLiteralPlaceholders);\n\n // All lotto node arguments MUST be of type number and must be integer.\n nodeArguments\n .filter((arg) => arg.type !== \"number\" || !arg.isInteger)\n .forEach(() => {\n throw new Error(`lotto node weight arguments must be integer values`);\n });\n\n const node = {\n type: \"lotto\",\n weights: nodeArguments.map(({ value }) => value),\n ...parseAttributeTokens(tokens, stringLiteralPlaceholders)\n } as LottoNodeDefinition;\n\n // This is a composite node, so we expect an opening '{'.\n popAndCheck(tokens, \"{\");\n\n // Return the lotto node definition.\n return node;\n}\n\n/**\n * Creates an action node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The action node JSON definition.\n */\nfunction createActionNode(\n tokens: string[],\n stringLiteralPlaceholders: StringLiteralPlaceholders\n): ActionNodeDefinition {\n // Parse any node arguments, we should have at least one which will be an identifier argument for the action name\n // and agent function to invoke for the action, all other arguments are to be passed as arguments to that function.\n const [actionNameIdentifier, ...agentFunctionArgs] = parseArgumentTokens(tokens, stringLiteralPlaceholders);\n\n // Our first argument MUST be defined and be an identifier as we require an action name argument.\n if (actionNameIdentifier?.type !== \"identifier\") {\n throw new Error(\"expected action name identifier argument\");\n }\n\n // Only the first argument should have been an identifier, all agent function arguments must be string, number, boolean or null.\n agentFunctionArgs\n .filter((arg) => arg.type === \"identifier\")\n .forEach((arg) => {\n throw new Error(\n `invalid action node argument value '${arg.value}', must be string, number, boolean or null`\n );\n });\n\n // Return the action node definition.\n return {\n type: \"action\",\n call: actionNameIdentifier.value,\n args: agentFunctionArgs.map(({ value }) => value),\n ...parseAttributeTokens(tokens, stringLiteralPlaceholders)\n };\n}\n\n/**\n * Creates a condition node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The condition node JSON definition.\n */\nfunction createConditionNode(\n tokens: string[],\n stringLiteralPlaceholders: StringLiteralPlaceholders\n): ConditionNodeDefinition {\n // Parse any node arguments, we should have at least one which will be an identifier argument for the condition name\n // and agent function to invoke for the condition, all other arguments are to be passed as arguments to that function.\n const [conditionNameIdentifier, ...agentFunctionArgs] = parseArgumentTokens(tokens, stringLiteralPlaceholders);\n\n // Our first argument MUST be defined and be an identifier as we require a condition name argument.\n if (conditionNameIdentifier?.type !== \"identifier\") {\n throw new Error(\"expected condition name identifier argument\");\n }\n\n // Only the first argument should have been an identifier, all agent function arguments must be string, number, boolean or null.\n agentFunctionArgs\n .filter((arg) => arg.type === \"identifier\")\n .forEach((arg) => {\n throw new Error(\n `invalid condition node argument value '${arg.value}', must be string, number, boolean or null`\n );\n });\n\n // Return the condition node definition.\n return {\n type: \"condition\",\n call: conditionNameIdentifier.value,\n args: agentFunctionArgs.map(({ value }) => value),\n ...parseAttributeTokens(tokens, stringLiteralPlaceholders)\n };\n}\n\n/**\n * Creates a wait node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The wait node JSON definition.\n */\nfunction createWaitNode(tokens: string[], stringLiteralPlaceholders: StringLiteralPlaceholders): WaitNodeDefinition {\n let node = { type: \"wait\" } as WaitNodeDefinition;\n\n // Get the node arguments.\n const nodeArguments = parseArgumentTokens(tokens, stringLiteralPlaceholders);\n\n // The arguments of a wait node are optional. We may have:\n // - No node arguments, in which case the wait will be indefinite until it is aborted.\n // - One node argument which will be the explicit duration of the wait.\n // - Two node arguments which define the min and max duration bounds from which a random duration will be picked.\n if (nodeArguments.length) {\n // All wait node arguments MUST be of type number and must be integer.\n nodeArguments\n .filter((arg) => arg.type !== \"number\" || !arg.isInteger)\n .forEach(() => {\n throw new Error(`wait node duration arguments must be integer values`);\n });\n\n // We may have:\n // - One node argument which will be the explicit duration of the wait.\n // - Two node arguments which define the min and max duration bounds from which a random duration will be picked.\n // - Too many arguments, which is not valid.\n if (nodeArguments.length === 1) {\n // An explicit duration was defined.\n node.duration = nodeArguments[0].value as number;\n } else if (nodeArguments.length === 2) {\n // Min and max duration bounds were defined from which a random duration will be picked.\n node.duration = [nodeArguments[0].value as number, nodeArguments[1].value as number];\n } else if (nodeArguments.length > 2) {\n // An incorrect number of duration arguments were defined.\n throw new Error(\"invalid number of wait node duration arguments defined\");\n }\n }\n\n // Return the wait node definition.\n return { ...node, ...parseAttributeTokens(tokens, stringLiteralPlaceholders) };\n}\n\n/**\n * Creates a branch node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The branch node JSON definition.\n */\nfunction createBranchNode(\n tokens: string[],\n stringLiteralPlaceholders: StringLiteralPlaceholders\n): BranchNodeDefinition {\n // Parse any node arguments, we should have one which will be an identifier argument for the root ref.\n const nodeArguments = parseArgumentTokens(tokens, stringLiteralPlaceholders);\n\n // We should have only a single identifer argument for a branch node, which is the root ref.\n if (nodeArguments.length !== 1 || nodeArguments[0].type !== \"identifier\") {\n throw new Error(\"expected single branch name argument\");\n }\n\n // Return the branch node definition.\n return { type: \"branch\", ref: nodeArguments[0].value };\n}\n"], + "mappings": "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", + "names": ["Participant", "Lotto", "createLotto", "State", "createLotto", "popAndCheck", "substituteStringLiterals", "parseTokensFromDefinition", "popAndCheck", "getArgumentDefinition", "substituteStringLiterals", "parseTokensFromDefinition", "popAndCheck"] } diff --git a/src/BehaviourTreeDefinition.d.ts b/src/BehaviourTreeDefinition.ts similarity index 76% rename from src/BehaviourTreeDefinition.d.ts rename to src/BehaviourTreeDefinition.ts index a26c064..6cf4fba 100644 --- a/src/BehaviourTreeDefinition.d.ts +++ b/src/BehaviourTreeDefinition.ts @@ -21,11 +21,29 @@ export interface NodeAttributeDefinition { * A type defining a general node definition. */ export interface NodeDefinition { + /** + * The node type. + */ type: string; + /** + * The 'while' node attribute definition. + */ while?: NodeAttributeDefinition; + /** + * The 'until' node attribute definition. + */ until?: NodeAttributeDefinition; + /** + * The 'entry' node attribute definition. + */ entry?: NodeAttributeDefinition; + /** + * The 'exit' node attribute definition. + */ exit?: NodeAttributeDefinition; + /** + * The 'step' node attribute definition. + */ step?: NodeAttributeDefinition; } @@ -33,6 +51,9 @@ export interface NodeDefinition { * A composite node that can contain any number of child nodes. */ export interface CompositeNodeDefinition extends NodeDefinition { + /** + * The child nodes of this composite node. + */ children: AnyChildNode[]; } @@ -40,6 +61,9 @@ export interface CompositeNodeDefinition extends NodeDefinition { * A decorator node, a composite with only a single child node. */ export interface DecoratorNodeDefinition extends NodeDefinition { + /** + * The child node of this decorator node. + */ child: AnyChildNode; } @@ -47,6 +71,9 @@ export interface DecoratorNodeDefinition extends NodeDefinition { * A branch node. */ export interface BranchNodeDefinition extends NodeDefinition { + /** + * The node type. + */ type: "branch"; ref: string; } @@ -55,6 +82,9 @@ export interface BranchNodeDefinition extends NodeDefinition { * An action node. */ export interface ActionNodeDefinition extends NodeDefinition { + /** + * The node type. + */ type: "action"; call: string; args?: AgentFunctionArgument[]; @@ -64,6 +94,9 @@ export interface ActionNodeDefinition extends NodeDefinition { * A condition node. */ export interface ConditionNodeDefinition extends NodeDefinition { + /** + * The node type. + */ type: "condition"; call: string; args?: AgentFunctionArgument[]; @@ -73,6 +106,9 @@ export interface ConditionNodeDefinition extends NodeDefinition { * A wait node. */ export interface WaitNodeDefinition extends NodeDefinition { + /** + * The node type. + */ type: "wait"; duration: number | [number, number]; } @@ -81,6 +117,9 @@ export interface WaitNodeDefinition extends NodeDefinition { * A sequence node. */ export interface SequenceNodeDefinition extends CompositeNodeDefinition { + /** + * The node type. + */ type: "sequence"; } @@ -88,6 +127,9 @@ export interface SequenceNodeDefinition extends CompositeNodeDefinition { * A selector node. */ export interface SelectorNodeDefinition extends CompositeNodeDefinition { + /** + * The node type. + */ type: "selector"; } @@ -95,7 +137,13 @@ export interface SelectorNodeDefinition extends CompositeNodeDefinition { * A lotto node. */ export interface LottoNodeDefinition extends CompositeNodeDefinition { + /** + * The node type. + */ type: "lotto"; + /** + * The selection weights for child nodes that correspond to the child node position. + */ weights?: number[]; } @@ -103,6 +151,9 @@ export interface LottoNodeDefinition extends CompositeNodeDefinition { * A parallel node. */ export interface ParallelNodeDefinition extends CompositeNodeDefinition { + /** + * The node type. + */ type: "parallel"; } @@ -110,6 +161,9 @@ export interface ParallelNodeDefinition extends CompositeNodeDefinition { * A root node. */ export interface RootNodeDefinition extends DecoratorNodeDefinition { + /** + * The node type. + */ type: "root"; id?: string; } @@ -118,6 +172,9 @@ export interface RootNodeDefinition extends DecoratorNodeDefinition { * A repeat node. */ export interface RepeatNodeDefinition extends DecoratorNodeDefinition { + /** + * The node type. + */ type: "repeat"; iterations?: number | [number, number]; } @@ -126,6 +183,9 @@ export interface RepeatNodeDefinition extends DecoratorNodeDefinition { * A retry node. */ export interface RetryNodeDefinition extends DecoratorNodeDefinition { + /** + * The node type. + */ type: "retry"; attempts?: number | [number, number]; } @@ -134,6 +194,9 @@ export interface RetryNodeDefinition extends DecoratorNodeDefinition { * A flip node. */ export interface FlipNodeDefinition extends DecoratorNodeDefinition { + /** + * The node type. + */ type: "flip"; } @@ -141,6 +204,9 @@ export interface FlipNodeDefinition extends DecoratorNodeDefinition { * A succeed node. */ export interface SucceedNodeDefinition extends DecoratorNodeDefinition { + /** + * The node type. + */ type: "succeed"; } @@ -148,6 +214,9 @@ export interface SucceedNodeDefinition extends DecoratorNodeDefinition { * A fail node. */ export interface FailNodeDefinition extends DecoratorNodeDefinition { + /** + * The node type. + */ type: "fail"; } diff --git a/src/index.ts b/src/index.ts index d0e1068..a02e59b 100644 --- a/src/index.ts +++ b/src/index.ts @@ -1,5 +1,6 @@ import { BehaviourTree, FlattenedTreeNode } from "./BehaviourTree"; import State from "./State"; +import { parseMDSLToJSON } from "./mdsl/MDSLDefinitionParser"; -export { BehaviourTree, State }; +export { BehaviourTree, State, parseMDSLToJSON }; export type { FlattenedTreeNode }; diff --git a/src/mdsl/MDSLDefinitionParser.ts b/src/mdsl/MDSLDefinitionParser.ts index d23d8a4..2992ac0 100644 --- a/src/mdsl/MDSLDefinitionParser.ts +++ b/src/mdsl/MDSLDefinitionParser.ts @@ -1,9 +1,20 @@ import { - RootNodeDefinition, + ActionNodeDefinition, AnyChildNode, AnyNode, + BranchNodeDefinition, + ConditionNodeDefinition, + FailNodeDefinition, + FlipNodeDefinition, + LottoNodeDefinition, + ParallelNodeDefinition, + RepeatNodeDefinition, + RetryNodeDefinition, + RootNodeDefinition, + SelectorNodeDefinition, SequenceNodeDefinition, - ActionNodeDefinition + SucceedNodeDefinition, + WaitNodeDefinition } from "../BehaviourTreeDefinition"; import { parseArgumentTokens } from "./MDSLNodeArgumentParser"; import { parseAttributeTokens } from "./MDSLNodeAttributeParser"; @@ -140,16 +151,71 @@ function convertTokensToJSONDefinition( break; } + case "SUCCEED": { + pushNode(createSucceedNode(tokens, stringLiteralPlaceholders)); + break; + } + + case "FAIL": { + pushNode(createFailNode(tokens, stringLiteralPlaceholders)); + break; + } + + case "FLIP": { + pushNode(createFlipNode(tokens, stringLiteralPlaceholders)); + break; + } + + case "REPEAT": { + pushNode(createRepeatNode(tokens, stringLiteralPlaceholders)); + break; + } + + case "RETRY": { + pushNode(createRetryNode(tokens, stringLiteralPlaceholders)); + break; + } + case "SEQUENCE": { pushNode(createSequenceNode(tokens, stringLiteralPlaceholders)); break; } + case "SELECTOR": { + pushNode(createSelectorNode(tokens, stringLiteralPlaceholders)); + break; + } + + case "PARALLEL": { + pushNode(createParallelNode(tokens, stringLiteralPlaceholders)); + break; + } + + case "LOTTO": { + pushNode(createLottoNode(tokens, stringLiteralPlaceholders)); + break; + } + case "ACTION": { pushNode(createActionNode(tokens, stringLiteralPlaceholders)); break; } + case "CONDITION": { + pushNode(createConditionNode(tokens, stringLiteralPlaceholders)); + break; + } + + case "WAIT": { + pushNode(createWaitNode(tokens, stringLiteralPlaceholders)); + break; + } + + case "BRANCH": { + pushNode(createBranchNode(tokens, stringLiteralPlaceholders)); + break; + } + case "}": { // The '}' character closes the current scope and means that we have to pop a node off of the current stack. popNode(); @@ -157,7 +223,7 @@ function convertTokensToJSONDefinition( } default: { - throw new Error("unexpected token: " + token); + throw new Error(`unexpected token: ${token}`); } } } @@ -198,6 +264,164 @@ function createRootNode(tokens: string[], stringLiteralPlaceholders: StringLiter // This is a decorator node, so we expect an opening '{'. popAndCheck(tokens, "{"); + // Return the root node definition. + return node; +} + +/** + * Creates a succeed node JSON definition. + * @param tokens The tree definition tokens. + * @param stringLiteralPlaceholders The substituted string literal placeholders. + * @returns The succeed node JSON definition. + */ +function createSucceedNode( + tokens: string[], + stringLiteralPlaceholders: StringLiteralPlaceholders +): SucceedNodeDefinition { + const node = { + type: "succeed", + ...parseAttributeTokens(tokens, stringLiteralPlaceholders) + } as SucceedNodeDefinition; + + // This is a decorator node, so we expect an opening '{'. + popAndCheck(tokens, "{"); + + // Return the succeed node definition. + return node; +} + +/** + * Creates a fail node JSON definition. + * @param tokens The tree definition tokens. + * @param stringLiteralPlaceholders The substituted string literal placeholders. + * @returns The fail node JSON definition. + */ +function createFailNode(tokens: string[], stringLiteralPlaceholders: StringLiteralPlaceholders): FailNodeDefinition { + const node = { + type: "fail", + ...parseAttributeTokens(tokens, stringLiteralPlaceholders) + } as FailNodeDefinition; + + // This is a decorator node, so we expect an opening '{'. + popAndCheck(tokens, "{"); + + // Return the fail node definition. + return node; +} + +/** + * Creates a flip node JSON definition. + * @param tokens The tree definition tokens. + * @param stringLiteralPlaceholders The substituted string literal placeholders. + * @returns The flip node JSON definition. + */ +function createFlipNode(tokens: string[], stringLiteralPlaceholders: StringLiteralPlaceholders): FlipNodeDefinition { + const node = { + type: "flip", + ...parseAttributeTokens(tokens, stringLiteralPlaceholders) + } as FlipNodeDefinition; + + // This is a decorator node, so we expect an opening '{'. + popAndCheck(tokens, "{"); + + // Return the flip node definition. + return node; +} + +/** + * Creates a repeat node JSON definition. + * @param tokens The tree definition tokens. + * @param stringLiteralPlaceholders The substituted string literal placeholders. + * @returns The repeat node JSON definition. + */ +function createRepeatNode( + tokens: string[], + stringLiteralPlaceholders: StringLiteralPlaceholders +): RepeatNodeDefinition { + let node = { type: "repeat" } as RepeatNodeDefinition; + + // Get the node arguments. + const nodeArguments = parseArgumentTokens(tokens, stringLiteralPlaceholders); + + // The arguments of a repeat node are optional. We may have: + // - No node arguments, in which case the repeat note will iterate indefinitely. + // - One node argument which will be the explicit number of iterations to make. + // - Two node arguments which define the min and max iteration bounds from which a random iteration count will be picked. + if (nodeArguments.length) { + // All repeat node arguments MUST be of type number and must be integer. + nodeArguments + .filter((arg) => arg.type !== "number" || !arg.isInteger) + .forEach(() => { + throw new Error(`repeat node iteration counts must be integer values`); + }); + + // We should have got one or two iteration counts. + if (nodeArguments.length === 1) { + // A static iteration count was defined. + node.iterations = nodeArguments[0].value as number; + } else if (nodeArguments.length === 2) { + // A minimum and maximum iteration count was defined. + node.iterations = [nodeArguments[0].value as number, nodeArguments[1].value as number]; + } else { + // An incorrect number of iteration counts was defined. + throw new Error("invalid number of repeat node iteration count arguments defined"); + } + } + + // Grab any node attribute definitions and spread them into the node definition. + node = { ...node, ...parseAttributeTokens(tokens, stringLiteralPlaceholders) }; + + // This is a decorator node, so we expect an opening '{'. + popAndCheck(tokens, "{"); + + // Return the repeat node definition. + return node; +} + +/** + * Creates a retry node JSON definition. + * @param tokens The tree definition tokens. + * @param stringLiteralPlaceholders The substituted string literal placeholders. + * @returns The retry node JSON definition. + */ +function createRetryNode(tokens: string[], stringLiteralPlaceholders: StringLiteralPlaceholders): RetryNodeDefinition { + let node = { type: "retry" } as RetryNodeDefinition; + + // Get the node arguments. + const nodeArguments = parseArgumentTokens(tokens, stringLiteralPlaceholders); + + // The arguments of a retry node are optional. We may have: + // - No node arguments, in which case the retry note will attempt indefinitely. + // - One node argument which will be the explicit number of attempts to make. + // - Two node arguments which define the min and max attempt bounds from which a random attempt count will be picked. + if (nodeArguments.length) { + // All retry node arguments MUST be of type number and must be integer. + nodeArguments + .filter((arg) => arg.type !== "number" || !arg.isInteger) + .forEach(() => { + throw new Error(`retry node attempt counts must be integer values`); + }); + + // We should have got one or two attempt counts. + if (nodeArguments.length === 1) { + // A static attempt count was defined. + node.attempts = nodeArguments[0].value as number; + } else if (nodeArguments.length === 2) { + // A minimum and maximum attempt count was defined. + node.attempts = [nodeArguments[0].value as number, nodeArguments[1].value as number]; + } else { + // An incorrect number of attempt counts was defined. + throw new Error("invalid number of retry node attempt count arguments defined"); + } + } + + // Grab any node attribute definitions and spread them into the node definition. + node = { ...node, ...parseAttributeTokens(tokens, stringLiteralPlaceholders) }; + + // This is a decorator node, so we expect an opening '{'. + popAndCheck(tokens, "{"); + + // Return the retry node definition. return node; } @@ -219,6 +443,81 @@ function createSequenceNode( // This is a composite node, so we expect an opening '{'. popAndCheck(tokens, "{"); + // Return the sequence node definition. + return node; +} + +/** + * Creates a selector node JSON definition. + * @param tokens The tree definition tokens. + * @param stringLiteralPlaceholders The substituted string literal placeholders. + * @returns The selector node JSON definition. + */ +function createSelectorNode( + tokens: string[], + stringLiteralPlaceholders: StringLiteralPlaceholders +): SelectorNodeDefinition { + const node = { + type: "selector", + ...parseAttributeTokens(tokens, stringLiteralPlaceholders) + } as SelectorNodeDefinition; + + // This is a composite node, so we expect an opening '{'. + popAndCheck(tokens, "{"); + + // Return the selector node definition. + return node; +} + +/** + * Creates a parallel node JSON definition. + * @param tokens The tree definition tokens. + * @param stringLiteralPlaceholders The substituted string literal placeholders. + * @returns The parallel node JSON definition. + */ +function createParallelNode( + tokens: string[], + stringLiteralPlaceholders: StringLiteralPlaceholders +): ParallelNodeDefinition { + const node = { + type: "parallel", + ...parseAttributeTokens(tokens, stringLiteralPlaceholders) + } as ParallelNodeDefinition; + + // This is a composite node, so we expect an opening '{'. + popAndCheck(tokens, "{"); + + // Return the parallel node definition. + return node; +} + +/** + * Creates a lotto node JSON definition. + * @param tokens The tree definition tokens. + * @param stringLiteralPlaceholders The substituted string literal placeholders. + * @returns The lotto node JSON definition. + */ +function createLottoNode(tokens: string[], stringLiteralPlaceholders: StringLiteralPlaceholders): LottoNodeDefinition { + // If any node arguments have been defined then they must be our weights. + const nodeArguments = parseArgumentTokens(tokens, stringLiteralPlaceholders); + + // All lotto node arguments MUST be of type number and must be integer. + nodeArguments + .filter((arg) => arg.type !== "number" || !arg.isInteger) + .forEach(() => { + throw new Error(`lotto node weight arguments must be integer values`); + }); + + const node = { + type: "lotto", + weights: nodeArguments.map(({ value }) => value), + ...parseAttributeTokens(tokens, stringLiteralPlaceholders) + } as LottoNodeDefinition; + + // This is a composite node, so we expect an opening '{'. + popAndCheck(tokens, "{"); + + // Return the lotto node definition. return node; } @@ -256,5 +555,108 @@ function createActionNode( call: actionNameIdentifier.value, args: agentFunctionArgs.map(({ value }) => value), ...parseAttributeTokens(tokens, stringLiteralPlaceholders) - } as ActionNodeDefinition; + }; +} + +/** + * Creates a condition node JSON definition. + * @param tokens The tree definition tokens. + * @param stringLiteralPlaceholders The substituted string literal placeholders. + * @returns The condition node JSON definition. + */ +function createConditionNode( + tokens: string[], + stringLiteralPlaceholders: StringLiteralPlaceholders +): ConditionNodeDefinition { + // Parse any node arguments, we should have at least one which will be an identifier argument for the condition name + // and agent function to invoke for the condition, all other arguments are to be passed as arguments to that function. + const [conditionNameIdentifier, ...agentFunctionArgs] = parseArgumentTokens(tokens, stringLiteralPlaceholders); + + // Our first argument MUST be defined and be an identifier as we require a condition name argument. + if (conditionNameIdentifier?.type !== "identifier") { + throw new Error("expected condition name identifier argument"); + } + + // Only the first argument should have been an identifier, all agent function arguments must be string, number, boolean or null. + agentFunctionArgs + .filter((arg) => arg.type === "identifier") + .forEach((arg) => { + throw new Error( + `invalid condition node argument value '${arg.value}', must be string, number, boolean or null` + ); + }); + + // Return the condition node definition. + return { + type: "condition", + call: conditionNameIdentifier.value, + args: agentFunctionArgs.map(({ value }) => value), + ...parseAttributeTokens(tokens, stringLiteralPlaceholders) + }; +} + +/** + * Creates a wait node JSON definition. + * @param tokens The tree definition tokens. + * @param stringLiteralPlaceholders The substituted string literal placeholders. + * @returns The wait node JSON definition. + */ +function createWaitNode(tokens: string[], stringLiteralPlaceholders: StringLiteralPlaceholders): WaitNodeDefinition { + let node = { type: "wait" } as WaitNodeDefinition; + + // Get the node arguments. + const nodeArguments = parseArgumentTokens(tokens, stringLiteralPlaceholders); + + // The arguments of a wait node are optional. We may have: + // - No node arguments, in which case the wait will be indefinite until it is aborted. + // - One node argument which will be the explicit duration of the wait. + // - Two node arguments which define the min and max duration bounds from which a random duration will be picked. + if (nodeArguments.length) { + // All wait node arguments MUST be of type number and must be integer. + nodeArguments + .filter((arg) => arg.type !== "number" || !arg.isInteger) + .forEach(() => { + throw new Error(`wait node duration arguments must be integer values`); + }); + + // We may have: + // - One node argument which will be the explicit duration of the wait. + // - Two node arguments which define the min and max duration bounds from which a random duration will be picked. + // - Too many arguments, which is not valid. + if (nodeArguments.length === 1) { + // An explicit duration was defined. + node.duration = nodeArguments[0].value as number; + } else if (nodeArguments.length === 2) { + // Min and max duration bounds were defined from which a random duration will be picked. + node.duration = [nodeArguments[0].value as number, nodeArguments[1].value as number]; + } else if (nodeArguments.length > 2) { + // An incorrect number of duration arguments were defined. + throw new Error("invalid number of wait node duration arguments defined"); + } + } + + // Return the wait node definition. + return { ...node, ...parseAttributeTokens(tokens, stringLiteralPlaceholders) }; +} + +/** + * Creates a branch node JSON definition. + * @param tokens The tree definition tokens. + * @param stringLiteralPlaceholders The substituted string literal placeholders. + * @returns The branch node JSON definition. + */ +function createBranchNode( + tokens: string[], + stringLiteralPlaceholders: StringLiteralPlaceholders +): BranchNodeDefinition { + // Parse any node arguments, we should have one which will be an identifier argument for the root ref. + const nodeArguments = parseArgumentTokens(tokens, stringLiteralPlaceholders); + + // We should have only a single identifer argument for a branch node, which is the root ref. + if (nodeArguments.length !== 1 || nodeArguments[0].type !== "identifier") { + throw new Error("expected single branch name argument"); + } + + // Return the branch node definition. + return { type: "branch", ref: nodeArguments[0].value }; } diff --git a/test/mdsl/MDSLDefinitionParser.test.js b/test/mdsl/MDSLDefinitionParser.test.js new file mode 100644 index 0000000..98ac4ee --- /dev/null +++ b/test/mdsl/MDSLDefinitionParser.test.js @@ -0,0 +1,10 @@ +const mistreevous = require("../../dist/index"); +const chai = require("chai"); + +var assert = chai.assert; + +describe("The parseMDSLToJSON function", () => { + it("does stuff", () => { + assert.strictEqual(mistreevous.parseMDSLToJSON("root {}"), JSON.stringify([{ type: "root" }])); + }); +}); From 4e175f18537d506c0a874011c62180e6dc917245 Mon Sep 17 00:00:00 2001 From: Nikolas Howard Date: Thu, 12 Oct 2023 17:55:23 +0100 Subject: [PATCH 11/48] working on definition validation --- src/BehaviourTreeDefinition.ts | 11 +- src/BehaviourTreeDefinitionValidator.ts | 157 ++++++++++++++++++++++++ 2 files changed, 160 insertions(+), 8 deletions(-) create mode 100644 src/BehaviourTreeDefinitionValidator.ts diff --git a/src/BehaviourTreeDefinition.ts b/src/BehaviourTreeDefinition.ts index 6cf4fba..7e6150d 100644 --- a/src/BehaviourTreeDefinition.ts +++ b/src/BehaviourTreeDefinition.ts @@ -1,8 +1,3 @@ -/** - * A type defining the an argument that can be passed to an agent function. - */ -export type AgentFunctionArgument = string | number | boolean | null | undefined; - /** * An attribute for a node. */ @@ -14,7 +9,7 @@ export interface NodeAttributeDefinition { /** * An array of arguments to pass when invoking the agent function. */ - args?: AgentFunctionArgument[]; + args?: any[]; } /** @@ -87,7 +82,7 @@ export interface ActionNodeDefinition extends NodeDefinition { */ type: "action"; call: string; - args?: AgentFunctionArgument[]; + args?: any[]; } /** @@ -99,7 +94,7 @@ export interface ConditionNodeDefinition extends NodeDefinition { */ type: "condition"; call: string; - args?: AgentFunctionArgument[]; + args?: any[]; } /** diff --git a/src/BehaviourTreeDefinitionValidator.ts b/src/BehaviourTreeDefinitionValidator.ts new file mode 100644 index 0000000..e1f9a68 --- /dev/null +++ b/src/BehaviourTreeDefinitionValidator.ts @@ -0,0 +1,157 @@ +import { parseMDSLToJSON } from "./mdsl/MDSLDefinitionParser"; + +/** + * An object representing the result of validating a tree definition. + */ +export type DefinitionValidationResult = { + /** + * A flag defining whether validation succeeded. + */ + succeeded: boolean; + /** + * A string containing the error message if validation did not succeed. + */ + errorMessage?: string; +}; + +export function validateDefinition(definition: any): DefinitionValidationResult { + // The definition must be defined. + if (definition === null || typeof definition === "undefined") { + throw new Error(`definition is null or undefined`); + } + + let rootNodeDefinitions: any[]; + + // We are expecting a definition in one of three different forms: + // - A string which we will assume is mdsl and we will parse this to JSON before validation. + // - An array which we will assume is an array of root node definitions with at least one being the primary root node (no 'id' property) + // - An object which we will assume is the primary root node and should not have an 'id' property. + if (typeof definition === "string") { + try { + // The definition is a string which we can assume is mdsl, so attempt to parse it to a JSON definition in the form of an array of root node definitions. + rootNodeDefinitions = parseMDSLToJSON(definition); + } catch (error) { + // We failed to parse the JSON from the mdsl, this is likely to be the result of it not being a valid mdsl string. + return { + succeeded: false, + errorMessage: `invalid mdsl: ${definition}` + }; + } + } else if (typeof definition === "object") { + // The definition will either be an array (of root node definitions) or an object (the single primary root node definition). + // If our definition is an array, we should verify that each of the elements within it are objects (potential root node definitions). + if (Array.isArray(definition)) { + // Find any invalid node definitions in our definition array, not full validation just a check that each is a valid object. + const invalidDefinitionElements = definition.filter((element) => { + // Each element isn't valid unless it is an object that isn't also an array and isn't null. + return typeof element !== "object" || Array.isArray(element) || element === null; + }); + + // If we have any invalid node definitions then validation has failed. + if (invalidDefinitionElements.length) { + return { + succeeded: false, + errorMessage: "invalid elements in definition array, each must be an root node definition object" + }; + } + + // Our definition is already an array of root node definition objects. + rootNodeDefinitions = definition; + } else { + // Our definition is an object, but we want an array of root node definitions. + rootNodeDefinitions = [definition]; + } + } else { + throw new Error(`unexpected definition type of '${typeof definition}'`); + } + + // The definition could be an object (our single root node) or an array (multiple root nodes with one that has no id and the rest must have an id) + // Check that all elements in 'definition' ONE has no id AND there are no duplicate ids + // Get a list of all root nodes, we will need this to validate that all branch nodes refer to real root nodes. + // Check for circular dependencies in root node references via branches. + + // Iterate over our array of root nodes and call validateNode for each, passing an initial depth of 0, wrapped in a try catch to handle validation failures. + + // Our definition was valid! + return { succeeded: true }; +} + +function validateNode(definition: any, depth: number): void { + // Every node must be valid object and have a non-empty 'type' string property. + if (typeof definition !== "object" || typeof definition.type !== "string" || definition.type.length === 0) { + throw new Error(`node definition is not an object or 'type' property is not a non-empty string at depth '${depth}'`); + } + + // How we validate this node will depend on its type. + switch (definition.type) { + case "root": + validateRootNode(definition, depth); + break; + + // TODO Add cases for all other nodes. + + default: + throw new Error(`unexpected node type of '${definition.type}' at depth '${depth}'`); + } +} + +function validateNodeAttributes(definition: any, depth: number): void { + // Validate each of the attribute types for this node. + ["while", "until", "entry", "exit", "step"].forEach((attributeName) => { + // Attempt to grab the definition for the current attribute from the node definition. + const attributeDefinition = definition[attributeName]; + + // All node attributes are optional, so there is nothing to do if the current attribute is not defined. + if (typeof attributeDefinition === "undefined") { + return; + } + + // The attribute definition must be an object. + if (typeof attributeDefinition !== "object") { + throw new Error(`expected attribute '${attributeName}' to be an object for '${definition.type}' node at depth '${depth}'`); + } + + // The 'call' property must be defined for any attribute definition. + if (typeof attributeDefinition.call !== "string" || attributeDefinition.call.length === 0) { + throw new Error(`expected 'call' property for attribute '${attributeName}' to be a non-empty string for '${definition.type}' node at depth '${depth}'`); + } + + // If any node attribute arguments have been defined then they must have been defined in an array. + if (typeof attributeDefinition.args !== "undefined" && !Array.isArray(attributeDefinition.args)) { + throw new Error(`expected 'args' property for attribute '${attributeName}' to be an array for '${definition.type}' node at depth '${depth}'`); + } + }); +} + +/** + * Validate an object that we expect to be a root node definition. + * @param definition An object that we expect to be a root node definition. + * @param depth The depth of the node in the definition tree. + */ +function validateRootNode(definition: any, depth: number): void { + // Check that the node type is correct. + if (definition.type !== "root") { + throw new Error("expected node type of 'root' for root node"); + } + + // A root node cannot be the child of another node. + if (depth > 0) { + throw new Error("a root node cannot be the child of another node"); + } + + // Check that, if the root node 'id' property is defined, it is a non-empty string. + if (typeof definition.id !== "undefined" && (typeof definition.id !== "string" || definition.id.length === 0)) { + throw new Error("expected non-empty string for 'id' property if defined for root node"); + } + + // A root node is a decorator node, so must have a child node defined. + if (typeof definition.child === "undefined") { + throw new Error("expected property 'child' to be defined for root node"); + } + + // Validate the node attributes. + validateNodeAttributes(definition, depth); + + // Validate the child node of this decorator node. + validateNode(definition.child, depth + 1); +} \ No newline at end of file From e3f0e40e59f35ef8b35f72be60036246286038cd Mon Sep 17 00:00:00 2001 From: Nikolas Howard Date: Thu, 19 Oct 2023 17:35:05 +0100 Subject: [PATCH 12/48] stuff --- src/BehaviourTreeDefinitionValidator.ts | 42 ++++++++++++++++++++----- 1 file changed, 35 insertions(+), 7 deletions(-) diff --git a/src/BehaviourTreeDefinitionValidator.ts b/src/BehaviourTreeDefinitionValidator.ts index e1f9a68..236bd0e 100644 --- a/src/BehaviourTreeDefinitionValidator.ts +++ b/src/BehaviourTreeDefinitionValidator.ts @@ -62,15 +62,43 @@ export function validateDefinition(definition: any): DefinitionValidationResult rootNodeDefinitions = [definition]; } } else { - throw new Error(`unexpected definition type of '${typeof definition}'`); + return { + succeeded: false, + errorMessage: `unexpected definition type of '${typeof definition}'` + }; } - - // The definition could be an object (our single root node) or an array (multiple root nodes with one that has no id and the rest must have an id) - // Check that all elements in 'definition' ONE has no id AND there are no duplicate ids - // Get a list of all root nodes, we will need this to validate that all branch nodes refer to real root nodes. - // Check for circular dependencies in root node references via branches. - // Iterate over our array of root nodes and call validateNode for each, passing an initial depth of 0, wrapped in a try catch to handle validation failures. + // TODO Iterate over our array of root nodes and call validateNode for each, passing an initial depth of 0, wrapped in a try catch to handle validation failures. + + // Unpack all of the root node definitions into arrays of main (no 'id' defined) and sub ('id' defined) root node definitions. + const mainRootNodeDefinitions = rootNodeDefinitions.filter(({ id }) => typeof id === "undefined"); + const subRootNodeDefinitions = rootNodeDefinitions.filter(({ id }) => typeof id === "string" && id.length > 0); + + // We should ALWAYS have exactly one root node definition without an 'id' property defined, which is out main root node definition. + if (mainRootNodeDefinitions.length !== 1) { + return { + succeeded: false, + errorMessage: "expected single root node without 'id' property defined to act as main root" + }; + } + + // We should never have duplicate 'id' properties across our sub root node definitions. + const subRootNodeIdenitifers: string[] = []; + for (const { id } of subRootNodeDefinitions) { + // Have we already come across this 'id' property value? + if (subRootNodeIdenitifers.includes(id)) { + return { + succeeded: false, + errorMessage: `multiple root nodes found with duplicate 'id' property value of '${id}'` + }; + } + + subRootNodeIdenitifers.push(id); + } + + // TODO Check for any root node circular depedencies. + + // TODO How do we handle globally defined root nodes? // Our definition was valid! return { succeeded: true }; From b1da1ebd4295b2b3fdf4120b32af8ef32ff667fa Mon Sep 17 00:00:00 2001 From: Nikolas Howard Date: Fri, 27 Oct 2023 08:46:48 +0100 Subject: [PATCH 13/48] Tidying up some of our utilities --- src/BehaviourTreeDefinitionUtilities.ts | 69 +++++++++++++++++++++++++ src/BehaviourTreeDefinitionValidator.ts | 63 +++++++++++++--------- src/mdsl/MDSLDefinitionParser.ts | 5 +- src/mdsl/MDSLUtilities.ts | 43 --------------- 4 files changed, 110 insertions(+), 70 deletions(-) create mode 100644 src/BehaviourTreeDefinitionUtilities.ts diff --git a/src/BehaviourTreeDefinitionUtilities.ts b/src/BehaviourTreeDefinitionUtilities.ts new file mode 100644 index 0000000..c78714f --- /dev/null +++ b/src/BehaviourTreeDefinitionUtilities.ts @@ -0,0 +1,69 @@ +import { NodeDefinition, RootNodeDefinition, DecoratorNodeDefinition, CompositeNodeDefinition, AnyNode, BranchNodeDefinition } from "./BehaviourTreeDefinition"; + +/** + * A type guard function that returns true if the specified node satisfies the RootNodeDefinition type. + * @param node The node. + * @returns A value of true if the specified node satisfies the RootNodeDefinition type. + */ +export function isRootNode(node: NodeDefinition): node is RootNodeDefinition { + return node.type === "root"; +} + +/** + * A type guard function that returns true if the specified node satisfies the BranchNodeDefinition type. + * @param node The node. + * @returns A value of true if the specified node satisfies the BranchNodeDefinition type. + */ +export function isBranchNode(node: NodeDefinition): node is BranchNodeDefinition { + return node.type === "branch"; +} + +/** + * A type guard function that returns true if the specified node satisfies the NodeDefinition type. + * @param node The node. + * @returns A value of true if the specified node satisfies the NodeDefinition type. + */ +export function isLeafNode(node: NodeDefinition): node is NodeDefinition { + return ["branch", "action", "condition", "wait"].includes(node.type); +} + +/** + * A type guard function that returns true if the specified node satisfies the DecoratorNodeDefinition type. + * @param node The node. + * @returns A value of true if the specified node satisfies the DecoratorNodeDefinition type. + */ +export function isDecoratorNode(node: NodeDefinition): node is DecoratorNodeDefinition { + return ["root", "repeat", "retry", "flip", "succeed", "fail"].includes(node.type); +} + +/** + * A type guard function that returns true if the specified node satisfies the CompositeNodeDefinition type. + * @param node The node. + * @returns A value of true if the specified node satisfies the CompositeNodeDefinition type. + */ +export function isCompositeNode(node: NodeDefinition): node is CompositeNodeDefinition { + return ["sequence", "selector", "lotto", "parallel"].includes(node.type); +} + +/** + * Flatten a node definition into an array of all of its nested node definitions. + * @param nodeDefinition The node definition to flatten. + * @returns An array of all of nested node definitions. + */ +export function flattenDefinition(nodeDefinition: AnyNode): AnyNode[] { + const nodes: AnyNode[] = []; + + const processNode = (currentNodeDefinition: AnyNode) => { + nodes.push(currentNodeDefinition); + + if (isCompositeNode(currentNodeDefinition)) { + currentNodeDefinition.children.forEach(processNode); + } else if (isDecoratorNode(currentNodeDefinition)) { + processNode(currentNodeDefinition.child); + } + }; + + processNode(nodeDefinition); + + return nodes; +} diff --git a/src/BehaviourTreeDefinitionValidator.ts b/src/BehaviourTreeDefinitionValidator.ts index 236bd0e..66e5d12 100644 --- a/src/BehaviourTreeDefinitionValidator.ts +++ b/src/BehaviourTreeDefinitionValidator.ts @@ -1,3 +1,5 @@ +import { RootNodeDefinition } from "./BehaviourTreeDefinition"; +import { flattenDefinition, isBranchNode } from "./BehaviourTreeDefinitionUtilities"; import { parseMDSLToJSON } from "./mdsl/MDSLDefinitionParser"; /** @@ -14,10 +16,18 @@ export type DefinitionValidationResult = { errorMessage?: string; }; +/** + * Validates the specified behaviour tree definition in the form of JSON or MDSL. + * @param definition The behaviour tree definition in the form of JSON or MDSL. + * @returns An object representing the result of validating the given tree definition. + */ export function validateDefinition(definition: any): DefinitionValidationResult { + // A helper function to create a failure validation result with the given error message. + const createFailureResult = (errorMessage: string) => ({ succeeded: false, errorMessage }); + // The definition must be defined. if (definition === null || typeof definition === "undefined") { - throw new Error(`definition is null or undefined`); + return createFailureResult("definition is null or undefined"); } let rootNodeDefinitions: any[]; @@ -32,10 +42,7 @@ export function validateDefinition(definition: any): DefinitionValidationResult rootNodeDefinitions = parseMDSLToJSON(definition); } catch (error) { // We failed to parse the JSON from the mdsl, this is likely to be the result of it not being a valid mdsl string. - return { - succeeded: false, - errorMessage: `invalid mdsl: ${definition}` - }; + return createFailureResult(`invalid mdsl: ${definition}`); } } else if (typeof definition === "object") { // The definition will either be an array (of root node definitions) or an object (the single primary root node definition). @@ -49,10 +56,7 @@ export function validateDefinition(definition: any): DefinitionValidationResult // If we have any invalid node definitions then validation has failed. if (invalidDefinitionElements.length) { - return { - succeeded: false, - errorMessage: "invalid elements in definition array, each must be an root node definition object" - }; + return createFailureResult("invalid elements in definition array, each must be an root node definition object"); } // Our definition is already an array of root node definition objects. @@ -62,24 +66,18 @@ export function validateDefinition(definition: any): DefinitionValidationResult rootNodeDefinitions = [definition]; } } else { - return { - succeeded: false, - errorMessage: `unexpected definition type of '${typeof definition}'` - }; + return createFailureResult(`unexpected definition type of '${typeof definition}'`); } // TODO Iterate over our array of root nodes and call validateNode for each, passing an initial depth of 0, wrapped in a try catch to handle validation failures. - // Unpack all of the root node definitions into arrays of main (no 'id' defined) and sub ('id' defined) root node definitions. + // Unpack all of the root node definitions into arrays of main ('id' defined) and sub ('id' not defined) root node definitions. const mainRootNodeDefinitions = rootNodeDefinitions.filter(({ id }) => typeof id === "undefined"); const subRootNodeDefinitions = rootNodeDefinitions.filter(({ id }) => typeof id === "string" && id.length > 0); // We should ALWAYS have exactly one root node definition without an 'id' property defined, which is out main root node definition. if (mainRootNodeDefinitions.length !== 1) { - return { - succeeded: false, - errorMessage: "expected single root node without 'id' property defined to act as main root" - }; + return createFailureResult("expected single root node without 'id' property defined to act as main root"); } // We should never have duplicate 'id' properties across our sub root node definitions. @@ -87,16 +85,14 @@ export function validateDefinition(definition: any): DefinitionValidationResult for (const { id } of subRootNodeDefinitions) { // Have we already come across this 'id' property value? if (subRootNodeIdenitifers.includes(id)) { - return { - succeeded: false, - errorMessage: `multiple root nodes found with duplicate 'id' property value of '${id}'` - }; + return createFailureResult(`multiple root nodes found with duplicate 'id' property value of '${id}'`); } subRootNodeIdenitifers.push(id); } - // TODO Check for any root node circular depedencies. + // TODO Check for any root node circular depedencies. This will not include any globally registered subtrees. + // TODO How do we handle globally defined root nodes? @@ -104,6 +100,22 @@ export function validateDefinition(definition: any): DefinitionValidationResult return { succeeded: true }; } +function _checkForRootNodeCircularDependencies(rootNodeDefinitions: RootNodeDefinition[]): void { + // Create a mapping of root node id's to other root nodes that they reference via branch nodes. + const rootNodeMappings: { id: string | undefined, refs: string[] }[] = rootNodeDefinitions + .map((rootNodeDefinition) => ({ + id: rootNodeDefinition.id, + refs: flattenDefinition(rootNodeDefinition).filter(isBranchNode).map(({ ref }) => ref) + })); + + // TODO Create a recursive function to walk through the mappings, keeing track of which root nodes we have visited. +} + +/** + * Validate an object that we expect to be a node definition. + * @param definition An object that we expect to be a node definition. + * @param depth The depth of the node in the definition tree. + */ function validateNode(definition: any, depth: number): void { // Every node must be valid object and have a non-empty 'type' string property. if (typeof definition !== "object" || typeof definition.type !== "string" || definition.type.length === 0) { @@ -123,6 +135,11 @@ function validateNode(definition: any, depth: number): void { } } +/** + * Validate any attributes for a given node definition. + * @param definition The node definition. + * @param depth The depth of the node in the behaviour tree definition. + */ function validateNodeAttributes(definition: any, depth: number): void { // Validate each of the attribute types for this node. ["while", "until", "entry", "exit", "step"].forEach((attributeName) => { diff --git a/src/mdsl/MDSLDefinitionParser.ts b/src/mdsl/MDSLDefinitionParser.ts index 2992ac0..aa04e59 100644 --- a/src/mdsl/MDSLDefinitionParser.ts +++ b/src/mdsl/MDSLDefinitionParser.ts @@ -16,14 +16,11 @@ import { SucceedNodeDefinition, WaitNodeDefinition } from "../BehaviourTreeDefinition"; +import { isCompositeNode, isDecoratorNode, isLeafNode, isRootNode } from "../BehaviourTreeDefinitionUtilities"; import { parseArgumentTokens } from "./MDSLNodeArgumentParser"; import { parseAttributeTokens } from "./MDSLNodeAttributeParser"; import { StringLiteralPlaceholders, - isCompositeNode, - isDecoratorNode, - isLeafNode, - isRootNode, parseTokensFromDefinition, popAndCheck, substituteStringLiterals diff --git a/src/mdsl/MDSLUtilities.ts b/src/mdsl/MDSLUtilities.ts index 67cd847..036d61f 100644 --- a/src/mdsl/MDSLUtilities.ts +++ b/src/mdsl/MDSLUtilities.ts @@ -1,51 +1,8 @@ -import { - CompositeNodeDefinition, - DecoratorNodeDefinition, - NodeDefinition, - RootNodeDefinition -} from "../BehaviourTreeDefinition"; - /** * A type defining an object that holds a reference to substitued string literals parsed from the definition. */ export type StringLiteralPlaceholders = { [key: string]: string }; -/** - * A type guard function that returns true if the specified node satisfies the RootNodeDefinition type. - * @param node The node. - * @returns A value of true if the specified node satisfies the RootNodeDefinition type. - */ -export function isRootNode(node: NodeDefinition): node is RootNodeDefinition { - return node.type === "root"; -} - -/** - * A type guard function that returns true if the specified node satisfies the NodeDefinition type. - * @param node The node. - * @returns A value of true if the specified node satisfies the NodeDefinition type. - */ -export function isLeafNode(node: NodeDefinition): node is NodeDefinition { - return ["branch", "action", "condition", "wait"].includes(node.type); -} - -/** - * A type guard function that returns true if the specified node satisfies the DecoratorNodeDefinition type. - * @param node The node. - * @returns A value of true if the specified node satisfies the DecoratorNodeDefinition type. - */ -export function isDecoratorNode(node: NodeDefinition): node is DecoratorNodeDefinition { - return ["root", "repeat", "retry", "flip", "succeed", "fail"].includes(node.type); -} - -/** - * A type guard function that returns true if the specified node satisfies the CompositeNodeDefinition type. - * @param node The node. - * @returns A value of true if the specified node satisfies the CompositeNodeDefinition type. - */ -export function isCompositeNode(node: NodeDefinition): node is CompositeNodeDefinition { - return ["sequence", "selector", "lotto", "parallel"].includes(node.type); -} - /** * Pop the next raw token from the specified array of tokens and throw an error if it wasn't the expected one. * @param tokens The array of tokens. From aeafce0f9de4fcc03995db51e7cff696a2f576d8 Mon Sep 17 00:00:00 2001 From: Nikolas Howard Date: Wed, 1 Nov 2023 17:29:42 +0000 Subject: [PATCH 14/48] working on tree validator --- src/BehaviourTreeDefinitionValidator.ts | 224 +++++++++++++++++++++++- 1 file changed, 218 insertions(+), 6 deletions(-) diff --git a/src/BehaviourTreeDefinitionValidator.ts b/src/BehaviourTreeDefinitionValidator.ts index 66e5d12..e37f91f 100644 --- a/src/BehaviourTreeDefinitionValidator.ts +++ b/src/BehaviourTreeDefinitionValidator.ts @@ -91,24 +91,62 @@ export function validateDefinition(definition: any): DefinitionValidationResult subRootNodeIdenitifers.push(id); } - // TODO Check for any root node circular depedencies. This will not include any globally registered subtrees. + // Check for any branch node circular depedencies. This will not include any globally registered subtrees. + const circularDependencyPath = findBranchCircularDependencyPath(rootNodeDefinitions); - - // TODO How do we handle globally defined root nodes? + // If we found a circular dependency in our root node and branch node definitions then the definition is definitely not valid. + if (circularDependencyPath) { + return createFailureResult(`circular dependency found in branch node references: ${circularDependencyPath}`); + } // Our definition was valid! return { succeeded: true }; } -function _checkForRootNodeCircularDependencies(rootNodeDefinitions: RootNodeDefinition[]): void { - // Create a mapping of root node id's to other root nodes that they reference via branch nodes. +/** + * Find the first circular depdendency path present in the array of root node definitions, or null if one doesn't exist. + * This will not consider branch nodes that reference any globally registered subtrees. + * @param rootNodeDefinitions The array of root node definitions. + * @returns The first circular depdendency path present in the array of root node definitions as string, or null if one doesn't exist. + */ +function findBranchCircularDependencyPath(rootNodeDefinitions: RootNodeDefinition[]): string | null { + // Create a mapping of root node identifiers to other root nodes that they reference via branch nodes. + // Below is an example of a mapping that includes a circular dependency (root => a => b => c => a) + // [{ refs: ["a", "b"] }, { id: "a", refs: ["b"] }, { id: "b", refs: ["c"] }, { id: "c", refs: ["a"] }] const rootNodeMappings: { id: string | undefined, refs: string[] }[] = rootNodeDefinitions .map((rootNodeDefinition) => ({ id: rootNodeDefinition.id, refs: flattenDefinition(rootNodeDefinition).filter(isBranchNode).map(({ ref }) => ref) })); - // TODO Create a recursive function to walk through the mappings, keeing track of which root nodes we have visited. + let badPathFormatted: string | null = null; + + // A recursive function to walk through the mappings, keeping track of which root nodes we have visited in the form of a path of root node identifiers. + const followRefs = (mapping: { id: string | undefined, refs: string[] }, path: (string | undefined)[] = []) => { + // Have we found a circular dependency? + if(path.includes(mapping.id)) { + // We found a circular dependency! Get the bad path of root node identifiers. + const badPath = [...path, mapping.id]; + + // Set the formatted path value. [undefined, "a", "b", "c", "a"] would be formatted as "a -> b -> c -> a". + badPathFormatted = badPath.map((element) => !!element).join(" => "); + + // No need to continue, we found a circular dependency. + return; + } + + for (const ref of mapping.refs) { + // Find the mapping for the root node with an identifer matching the current ref. + const subMapping = rootNodeMappings.find(({ id }) => id === ref); + + // We may not have a mapping for this ref, which will happen if this ref is for a globally registered subtree. + if (subMapping) { + followRefs(subMapping, [...path, mapping.id]); + } + } + } + + return badPathFormatted; } /** @@ -128,6 +166,30 @@ function validateNode(definition: any, depth: number): void { validateRootNode(definition, depth); break; + case "branch": + validateBranchNode(definition, depth); + break; + + case "action": + validateActionNode(definition, depth); + break; + + case "condition": + validateConditionNode(definition, depth); + break; + + case "sequence": + validateSequenceNode(definition, depth); + break; + + case "selector": + validateSelectorNode(definition, depth); + break; + + case "parallel": + validateParallelNode(definition, depth); + break; + // TODO Add cases for all other nodes. default: @@ -199,4 +261,154 @@ function validateRootNode(definition: any, depth: number): void { // Validate the child node of this decorator node. validateNode(definition.child, depth + 1); +} + +/** + * Validate an object that we expect to be a branch node definition. + * @param definition An object that we expect to be a branch node definition. + * @param depth The depth of the node in the definition tree. + */ +function validateBranchNode(definition: any, depth: number): void { + // Check that the node type is correct. + if (definition.type !== "branch") { + throw new Error(`expected node type of 'branch' for branch node at depth '${depth}'`); + } + + // Check that the branch node 'ref' property is defined and is a non-empty string. + if (typeof definition.ref !== "string" || definition.ref.length === 0) { + throw new Error(`expected non-empty string for 'ref' property for branch node at depth '${depth}'`); + } + + // It is invalid to define guard attributes for a branch node as they should be defined on the referenced root node. + ["while", "until"].forEach((attributeName) => { + if (typeof definition[attributeName] !== "undefined") { + throw new Error(`guards should not be defined for branch nodes but guard '${attributeName}' was defined for branch node at depth '${depth}'`); + } + }); + + // It is invalid to define callback attributes for a branch node as they should be defined on the referenced root node. + ["entry", "exit", "step"].forEach((attributeName) => { + if (typeof definition[attributeName] !== "undefined") { + throw new Error(`callbacks should not be defined for branch nodes but callback '${attributeName}' was defined for branch node at depth '${depth}'`); + } + }); +} + +/** + * Validate an object that we expect to be a action node definition. + * @param definition An object that we expect to be a action node definition. + * @param depth The depth of the node in the definition tree. + */ +function validateActionNode(definition: any, depth: number): void { + // Check that the node type is correct. + if (definition.type !== "action") { + throw new Error(`expected node type of 'action' for action node at depth '${depth}'`); + } + + // The 'call' property must be defined for a action node definition. + if (typeof definition.call !== "string" || definition.call.length === 0) { + throw new Error(`expected non-empty string for 'call' property of action node at depth '${depth}'`); + } + + // If any action function arguments have been defined then they must have been defined in an array. + if (typeof definition.args !== "undefined" && !Array.isArray(definition.args)) { + throw new Error(`expected array for 'args' property if defined for action node at depth '${depth}'`); + } + + // Validate the node attributes. + validateNodeAttributes(definition, depth); +} + +/** + * Validate an object that we expect to be a condition node definition. + * @param definition An object that we expect to be a condition node definition. + * @param depth The depth of the node in the definition tree. + */ +function validateConditionNode(definition: any, depth: number): void { + // Check that the node type is correct. + if (definition.type !== "condition") { + throw new Error(`expected node type of 'condition' for condition node at depth '${depth}'`); + } + + // The 'call' property must be defined for a condition node definition. + if (typeof definition.call !== "string" || definition.call.length === 0) { + throw new Error(`expected non-empty string for 'call' property of condition node at depth '${depth}'`); + } + + // If any condition function arguments have been defined then they must have been defined in an array. + if (typeof definition.args !== "undefined" && !Array.isArray(definition.args)) { + throw new Error(`expected array for 'args' property if defined for condition node at depth '${depth}'`); + } + + // Validate the node attributes. + validateNodeAttributes(definition, depth); +} + +/** + * Validate an object that we expect to be a sequence node definition. + * @param definition An object that we expect to be a sequence node definition. + * @param depth The depth of the node in the definition tree. + */ +function validateSequenceNode(definition: any, depth: number): void { + // Check that the node type is correct. + if (definition.type !== "sequence") { + throw new Error(`expected node type of 'sequence' for sequence node at depth '${depth}'`); + } + + // A sequence node is a composite node, so must have a children nodes array defined. + if (!Array.isArray(definition.children) || definition.children.length === 0) { + throw new Error(`expected non-empty 'children' array to be defined for sequence node at depth '${depth}'`); + } + + // Validate the node attributes. + validateNodeAttributes(definition, depth); + + // Validate the child nodes of this composite node. + definition.children.forEach((child: any) => validateNode(child, depth + 1)); +} + +/** + * Validate an object that we expect to be a selector node definition. + * @param definition An object that we expect to be a selector node definition. + * @param depth The depth of the node in the definition tree. + */ +function validateSelectorNode(definition: any, depth: number): void { + // Check that the node type is correct. + if (definition.type !== "selector") { + throw new Error(`expected node type of 'selector' for selector node at depth '${depth}'`); + } + + // A selector node is a composite node, so must have a children nodes array defined. + if (!Array.isArray(definition.children) || definition.children.length === 0) { + throw new Error(`expected non-empty 'children' array to be defined for selector node at depth '${depth}'`); + } + + // Validate the node attributes. + validateNodeAttributes(definition, depth); + + // Validate the child nodes of this composite node. + definition.children.forEach((child: any) => validateNode(child, depth + 1)); +} + +/** + * Validate an object that we expect to be a parallel node definition. + * @param definition An object that we expect to be a parallel node definition. + * @param depth The depth of the node in the definition tree. + */ +function validateParallelNode(definition: any, depth: number): void { + // Check that the node type is correct. + if (definition.type !== "parallel") { + throw new Error(`expected node type of 'parallel' for parallel node at depth '${depth}'`); + } + + // A parallel node is a composite node, so must have a children nodes array defined. + if (!Array.isArray(definition.children) || definition.children.length === 0) { + throw new Error(`expected non-empty 'children' array to be defined for parallel node at depth '${depth}'`); + } + + // Validate the node attributes. + validateNodeAttributes(definition, depth); + + // Validate the child nodes of this composite node. + definition.children.forEach((child: any) => validateNode(child, depth + 1)); } \ No newline at end of file From 159a5f3e031e782fd21341dbc2f201fe13643a92 Mon Sep 17 00:00:00 2001 From: Nikolas Howard Date: Wed, 8 Nov 2023 17:34:46 +0000 Subject: [PATCH 15/48] more work on validator --- src/BehaviourTreeDefinition.ts | 20 +++- src/BehaviourTreeDefinitionUtilities.ts | 9 ++ src/BehaviourTreeDefinitionValidator.ts | 131 ++++++++++++++++++++++-- 3 files changed, 151 insertions(+), 9 deletions(-) diff --git a/src/BehaviourTreeDefinition.ts b/src/BehaviourTreeDefinition.ts index 7e6150d..886cd34 100644 --- a/src/BehaviourTreeDefinition.ts +++ b/src/BehaviourTreeDefinition.ts @@ -70,6 +70,9 @@ export interface BranchNodeDefinition extends NodeDefinition { * The node type. */ type: "branch"; + /** + * The reference matching a root node identifier. + */ ref: string; } @@ -81,7 +84,13 @@ export interface ActionNodeDefinition extends NodeDefinition { * The node type. */ type: "action"; + /** + * The name of the agent function to invoke. + */ call: string; + /** + * An array of arguments to pass when invoking the agent function. + */ args?: any[]; } @@ -93,7 +102,13 @@ export interface ConditionNodeDefinition extends NodeDefinition { * The node type. */ type: "condition"; + /** + * The name of the agent function to invoke. + */ call: string; + /** + * An array of arguments to pass when invoking the agent function. + */ args?: any[]; } @@ -105,7 +120,7 @@ export interface WaitNodeDefinition extends NodeDefinition { * The node type. */ type: "wait"; - duration: number | [number, number]; + duration?: number | [number, number]; } /** @@ -160,6 +175,9 @@ export interface RootNodeDefinition extends DecoratorNodeDefinition { * The node type. */ type: "root"; + /** + * The unique root node identifier. + */ id?: string; } diff --git a/src/BehaviourTreeDefinitionUtilities.ts b/src/BehaviourTreeDefinitionUtilities.ts index c78714f..87cab25 100644 --- a/src/BehaviourTreeDefinitionUtilities.ts +++ b/src/BehaviourTreeDefinitionUtilities.ts @@ -67,3 +67,12 @@ export function flattenDefinition(nodeDefinition: AnyNode): AnyNode[] { return nodes; } + +/** + * Determines whether the passed value is an integer. + * @param value The value to check. + * @returns Whether the passed value is an integer. + */ +export function isInteger(value: unknown): boolean { + return typeof value === "number" && Math.floor(value) === value; +} diff --git a/src/BehaviourTreeDefinitionValidator.ts b/src/BehaviourTreeDefinitionValidator.ts index e37f91f..26bc517 100644 --- a/src/BehaviourTreeDefinitionValidator.ts +++ b/src/BehaviourTreeDefinitionValidator.ts @@ -1,5 +1,5 @@ import { RootNodeDefinition } from "./BehaviourTreeDefinition"; -import { flattenDefinition, isBranchNode } from "./BehaviourTreeDefinitionUtilities"; +import { flattenDefinition, isBranchNode, isInteger } from "./BehaviourTreeDefinitionUtilities"; import { parseMDSLToJSON } from "./mdsl/MDSLDefinitionParser"; /** @@ -160,22 +160,38 @@ function validateNode(definition: any, depth: number): void { throw new Error(`node definition is not an object or 'type' property is not a non-empty string at depth '${depth}'`); } - // How we validate this node will depend on its type. + // How we validate this node definition will depend on its type. switch (definition.type) { - case "root": - validateRootNode(definition, depth); + case "action": + validateActionNode(definition, depth); break; + case "condition": + validateConditionNode(definition, depth); + break; + + case "wait": + validateWaitNode(definition, depth); + break; + case "branch": validateBranchNode(definition, depth); break; - case "action": - validateActionNode(definition, depth); + case "root": + validateRootNode(definition, depth); break; - case "condition": - validateConditionNode(definition, depth); + case "success": + validateSuccessNode(definition, depth); + break; + + case "fail": + validateFailNode(definition, depth); + break; + + case "flip": + validateFlipNode(definition, depth); break; case "sequence": @@ -263,6 +279,75 @@ function validateRootNode(definition: any, depth: number): void { validateNode(definition.child, depth + 1); } +/** + * Validate an object that we expect to be a success node definition. + * @param definition An object that we expect to be a success node definition. + * @param depth The depth of the node in the definition tree. + */ +function validateSuccessNode(definition: any, depth: number): void { + // Check that the node type is correct. + if (definition.type !== "success") { + throw new Error(`expected node type of 'success' for success node at depth '${depth}'`); + } + + // A success node is a decorator node, so must have a child node defined. + if (typeof definition.child === "undefined") { + throw new Error(`expected property 'child' to be defined for success node at depth '${depth}'`); + } + + // Validate the node attributes. + validateNodeAttributes(definition, depth); + + // Validate the child node of this decorator node. + validateNode(definition.child, depth + 1); +} + +/** + * Validate an object that we expect to be a fail node definition. + * @param definition An object that we expect to be a fail node definition. + * @param depth The depth of the node in the definition tree. + */ +function validateFailNode(definition: any, depth: number): void { + // Check that the node type is correct. + if (definition.type !== "fail") { + throw new Error(`expected node type of 'fail' for fail node at depth '${depth}'`); + } + + // A fail node is a decorator node, so must have a child node defined. + if (typeof definition.child === "undefined") { + throw new Error(`expected property 'child' to be defined for fail node at depth '${depth}'`); + } + + // Validate the node attributes. + validateNodeAttributes(definition, depth); + + // Validate the child node of this decorator node. + validateNode(definition.child, depth + 1); +} + +/** + * Validate an object that we expect to be a flip node definition. + * @param definition An object that we expect to be a flip node definition. + * @param depth The depth of the node in the definition tree. + */ +function validateFlipNode(definition: any, depth: number): void { + // Check that the node type is correct. + if (definition.type !== "flip") { + throw new Error(`expected node type of 'flip' for flip node at depth '${depth}'`); + } + + // A flip node is a decorator node, so must have a child node defined. + if (typeof definition.child === "undefined") { + throw new Error(`expected property 'child' to be defined for flip node at depth '${depth}'`); + } + + // Validate the node attributes. + validateNodeAttributes(definition, depth); + + // Validate the child node of this decorator node. + validateNode(definition.child, depth + 1); +} + /** * Validate an object that we expect to be a branch node definition. * @param definition An object that we expect to be a branch node definition. @@ -344,6 +429,36 @@ function validateConditionNode(definition: any, depth: number): void { validateNodeAttributes(definition, depth); } +/** + * Validate an object that we expect to be a wait node definition. + * @param definition An object that we expect to be a wait node definition. + * @param depth The depth of the node in the definition tree. + */ +function validateWaitNode(definition: any, depth: number): void { + // Check that the node type is correct. + if (definition.type !== "wait") { + throw new Error(`expected node type of 'wait' for wait node at depth '${depth}'`); + } + + // Check whether a 'duration' property has been defined, it may not have been if this node is to wait indefinitely. + if (typeof definition.duration !== "undefined") { + if (Array.isArray(definition.duration)) { + // Check whether any elements of the array are not integer values. + const containsNonInteger = !!definition.duration.find((value: unknown) => !isInteger(value)); + + // If the 'duration' property is an array then it MUST contain two integer values. + if (definition.duration.length !== 2 || containsNonInteger) { + throw new Error(`expected array containing two integer values for 'duration' property if defined for wait node at depth '${depth}'`); + } + } else if (!isInteger(definition.duration)) { + throw new Error(`expected integer value or array containing two integer values for 'duration' property if defined for wait node at depth '${depth}'`); + } + } + + // Validate the node attributes. + validateNodeAttributes(definition, depth); +} + /** * Validate an object that we expect to be a sequence node definition. * @param definition An object that we expect to be a sequence node definition. From be1d946b07ef2490d13265519fb2e529448597b9 Mon Sep 17 00:00:00 2001 From: Nikolas Howard Date: Wed, 15 Nov 2023 17:34:32 +0000 Subject: [PATCH 16/48] Finished validator but needs tests --- .vscode/settings.json | 2 + dist/BehaviourTreeDefinition.d.ts | 30 +- dist/BehaviourTreeDefinitionUtilities.d.ts | 43 + dist/BehaviourTreeDefinitionValidator.d.ts | 19 + dist/bundle.js | 3943 ++++++++-------- dist/bundle.js.map | 8 +- dist/index.d.ts | 7 +- dist/index.js | 3946 +++++++++-------- dist/index.js.map | 8 +- dist/mdsl/MDSLDefinitionParser.d.ts | 4 +- dist/mdsl/MDSLUtilities.d.ts | 25 - src/BehaviourTree.ts | 2 +- src/BehaviourTreeDefinitionUtilities.ts | 9 +- src/BehaviourTreeDefinitionValidator.ts | 182 +- src/index.ts | 7 +- src/mdsl/MDSLDefinitionParser.ts | 4 +- test/BehaviourTreeDefinitionValidator.test.js | 10 + test/mdsl/MDSLDefinitionParser.test.js | 4 +- 18 files changed, 4589 insertions(+), 3664 deletions(-) create mode 100644 .vscode/settings.json create mode 100644 dist/BehaviourTreeDefinitionUtilities.d.ts create mode 100644 dist/BehaviourTreeDefinitionValidator.d.ts create mode 100644 test/BehaviourTreeDefinitionValidator.test.js diff --git a/.vscode/settings.json b/.vscode/settings.json new file mode 100644 index 0000000..7a73a41 --- /dev/null +++ b/.vscode/settings.json @@ -0,0 +1,2 @@ +{ +} \ No newline at end of file diff --git a/dist/BehaviourTreeDefinition.d.ts b/dist/BehaviourTreeDefinition.d.ts index 5b7be08..10005c8 100644 --- a/dist/BehaviourTreeDefinition.d.ts +++ b/dist/BehaviourTreeDefinition.d.ts @@ -1,7 +1,3 @@ -/** - * A type defining the an argument that can be passed to an agent function. - */ -export type AgentFunctionArgument = string | number | boolean | null | undefined; /** * An attribute for a node. */ @@ -13,7 +9,7 @@ export interface NodeAttributeDefinition { /** * An array of arguments to pass when invoking the agent function. */ - args?: AgentFunctionArgument[]; + args?: any[]; } /** * A type defining a general node definition. @@ -70,6 +66,9 @@ export interface BranchNodeDefinition extends NodeDefinition { * The node type. */ type: "branch"; + /** + * The reference matching a root node identifier. + */ ref: string; } /** @@ -80,8 +79,14 @@ export interface ActionNodeDefinition extends NodeDefinition { * The node type. */ type: "action"; + /** + * The name of the agent function to invoke. + */ call: string; - args?: AgentFunctionArgument[]; + /** + * An array of arguments to pass when invoking the agent function. + */ + args?: any[]; } /** * A condition node. @@ -91,8 +96,14 @@ export interface ConditionNodeDefinition extends NodeDefinition { * The node type. */ type: "condition"; + /** + * The name of the agent function to invoke. + */ call: string; - args?: AgentFunctionArgument[]; + /** + * An array of arguments to pass when invoking the agent function. + */ + args?: any[]; } /** * A wait node. @@ -102,7 +113,7 @@ export interface WaitNodeDefinition extends NodeDefinition { * The node type. */ type: "wait"; - duration: number | [number, number]; + duration?: number | [number, number]; } /** * A sequence node. @@ -152,6 +163,9 @@ export interface RootNodeDefinition extends DecoratorNodeDefinition { * The node type. */ type: "root"; + /** + * The unique root node identifier. + */ id?: string; } /** diff --git a/dist/BehaviourTreeDefinitionUtilities.d.ts b/dist/BehaviourTreeDefinitionUtilities.d.ts new file mode 100644 index 0000000..46096da --- /dev/null +++ b/dist/BehaviourTreeDefinitionUtilities.d.ts @@ -0,0 +1,43 @@ +import { NodeDefinition, RootNodeDefinition, DecoratorNodeDefinition, CompositeNodeDefinition, AnyNode, BranchNodeDefinition } from "./BehaviourTreeDefinition"; +/** + * A type guard function that returns true if the specified node satisfies the RootNodeDefinition type. + * @param node The node. + * @returns A value of true if the specified node satisfies the RootNodeDefinition type. + */ +export declare function isRootNode(node: NodeDefinition): node is RootNodeDefinition; +/** + * A type guard function that returns true if the specified node satisfies the BranchNodeDefinition type. + * @param node The node. + * @returns A value of true if the specified node satisfies the BranchNodeDefinition type. + */ +export declare function isBranchNode(node: NodeDefinition): node is BranchNodeDefinition; +/** + * A type guard function that returns true if the specified node satisfies the NodeDefinition type. + * @param node The node. + * @returns A value of true if the specified node satisfies the NodeDefinition type. + */ +export declare function isLeafNode(node: NodeDefinition): node is NodeDefinition; +/** + * A type guard function that returns true if the specified node satisfies the DecoratorNodeDefinition type. + * @param node The node. + * @returns A value of true if the specified node satisfies the DecoratorNodeDefinition type. + */ +export declare function isDecoratorNode(node: NodeDefinition): node is DecoratorNodeDefinition; +/** + * A type guard function that returns true if the specified node satisfies the CompositeNodeDefinition type. + * @param node The node. + * @returns A value of true if the specified node satisfies the CompositeNodeDefinition type. + */ +export declare function isCompositeNode(node: NodeDefinition): node is CompositeNodeDefinition; +/** + * Flatten a node definition into an array of all of its nested node definitions. + * @param nodeDefinition The node definition to flatten. + * @returns An array of all of nested node definitions. + */ +export declare function flattenDefinition(nodeDefinition: AnyNode): AnyNode[]; +/** + * Determines whether the passed value is an integer. + * @param value The value to check. + * @returns Whether the passed value is an integer. + */ +export declare function isInteger(value: unknown): boolean; diff --git a/dist/BehaviourTreeDefinitionValidator.d.ts b/dist/BehaviourTreeDefinitionValidator.d.ts new file mode 100644 index 0000000..4c812e5 --- /dev/null +++ b/dist/BehaviourTreeDefinitionValidator.d.ts @@ -0,0 +1,19 @@ +/** + * An object representing the result of validating a tree definition. + */ +export type DefinitionValidationResult = { + /** + * A flag defining whether validation succeeded. + */ + succeeded: boolean; + /** + * A string containing the error message if validation did not succeed. + */ + errorMessage?: string; +}; +/** + * Validates the specified behaviour tree definition in the form of JSON or MDSL. + * @param definition The behaviour tree definition in the form of JSON or MDSL. + * @returns An object representing the result of validating the given tree definition. + */ +export declare function validateDefinition(definition: any): DefinitionValidationResult; diff --git a/dist/bundle.js b/dist/bundle.js index 3f1937b..ab89b14 100644 --- a/dist/bundle.js +++ b/dist/bundle.js @@ -253,34 +253,10 @@ var mistreevous = (() => { __export(src_exports, { BehaviourTree: () => BehaviourTree, State: () => State, - parseMDSLToJSON: () => parseMDSLToJSON + convertMDSLToJSON: () => convertMDSLToJSON, + validateDefinition: () => validateDefinition }); - // src/attributes/guards/GuardUnsatisifedException.ts - var GuardUnsatisifedException = class extends Error { - constructor(source) { - super("A guard path condition has failed"); - this.source = source; - } - isSourceNode = (node) => node === this.source; - }; - - // src/attributes/guards/GuardPath.ts - var GuardPath = class { - constructor(nodes) { - this.nodes = nodes; - } - evaluate = (agent) => { - for (const details of this.nodes) { - for (const guard of details.guards) { - if (!guard.isSatisfied(agent)) { - throw new GuardUnsatisifedException(details.node); - } - } - } - }; - }; - // src/State.ts var State = /* @__PURE__ */ ((State2) => { State2["READY"] = "mistreevous.ready"; @@ -290,2005 +266,2394 @@ var mistreevous = (() => { return State2; })(State || {}); - // src/nodes/Node.ts - var Node = class { - constructor(type, attributes, args) { - this.type = type; - this.attributes = attributes; - this.args = args; - } - uid = createNodeUid(); - state = "mistreevous.ready" /* READY */; - guardPath; - getState = () => this.state; - setState = (value) => { - this.state = value; + // src/BehaviourTreeDefinitionUtilities.ts + function isRootNode(node) { + return node.type === "root"; + } + function isBranchNode(node) { + return node.type === "branch"; + } + function isLeafNode(node) { + return ["branch", "action", "condition", "wait"].includes(node.type); + } + function isDecoratorNode(node) { + return ["root", "repeat", "retry", "flip", "succeed", "fail"].includes(node.type); + } + function isCompositeNode(node) { + return ["sequence", "selector", "lotto", "parallel"].includes(node.type); + } + function flattenDefinition(nodeDefinition) { + const nodes = []; + const processNode = (currentNodeDefinition) => { + nodes.push(currentNodeDefinition); + if (isCompositeNode(currentNodeDefinition)) { + currentNodeDefinition.children.forEach(processNode); + } else if (isDecoratorNode(currentNodeDefinition)) { + processNode(currentNodeDefinition.child); + } }; - getUid = () => this.uid; - getType = () => this.type; - getAttributes = () => this.attributes; - getArguments = () => this.args; - getAttribute(type) { - return this.getAttributes().filter((decorator) => decorator.getType().toUpperCase() === type.toUpperCase())[0] || null; - } - getGuardAttributes = () => this.getAttributes().filter((decorator) => decorator.isGuard()); - setGuardPath = (value) => this.guardPath = value; - hasGuardPath = () => !!this.guardPath; - is(value) { - return this.state === value; - } - reset() { - this.setState("mistreevous.ready" /* READY */); + processNode(nodeDefinition); + return nodes; + } + function isInteger(value) { + return typeof value === "number" && Math.floor(value) === value; + } + + // src/mdsl/MDSLUtilities.ts + function popAndCheck(tokens, expected) { + const popped = tokens.shift(); + if (popped === void 0) { + throw new Error("unexpected end of definition"); } - abort(agent) { - if (!this.is("mistreevous.running" /* RUNNING */)) { - return; + if (expected != void 0) { + const expectedValues = typeof expected === "string" ? [expected] : expected; + var tokenMatchesExpectation = expectedValues.some((item) => popped.toUpperCase() === item.toUpperCase()); + if (!tokenMatchesExpectation) { + const expectationString = expectedValues.map((item) => "'" + item + "'").join(" or "); + throw new Error("unexpected token found. Expected " + expectationString + " but got '" + popped + "'"); } - this.reset(); - this.getAttribute("exit")?.callAgentFunction(agent, false, true); } - update(agent, options) { - if (this.is("mistreevous.succeeded" /* SUCCEEDED */) || this.is("mistreevous.failed" /* FAILED */)) { - return; - } - try { - this.guardPath.evaluate(agent); - if (this.is("mistreevous.ready" /* READY */)) { - this.getAttribute("entry")?.callAgentFunction(agent); - } - this.getAttribute("step")?.callAgentFunction(agent); - this.onUpdate(agent, options); - if (this.is("mistreevous.succeeded" /* SUCCEEDED */) || this.is("mistreevous.failed" /* FAILED */)) { - this.getAttribute("exit")?.callAgentFunction(agent, this.is("mistreevous.succeeded" /* SUCCEEDED */), false); - } - } catch (error) { - if (error instanceof GuardUnsatisifedException && error.isSourceNode(this)) { - this.abort(agent); - this.setState("mistreevous.failed" /* FAILED */); - } else { - throw error; - } + return popped; + } + function substituteStringLiterals(definition) { + const placeholders = {}; + const processedDefinition = definition.replace(/\"(\\.|[^"\\])*\"/g, (match) => { + var strippedMatch = match.substring(1, match.length - 1); + var placeholder = Object.keys(placeholders).find((key) => placeholders[key] === strippedMatch); + if (!placeholder) { + placeholder = `@@${Object.keys(placeholders).length}@@`; + placeholders[placeholder] = strippedMatch; } - } - }; - function createNodeUid() { - var S4 = function() { - return ((1 + Math.random()) * 65536 | 0).toString(16).substring(1); - }; - return S4() + S4() + "-" + S4() + "-" + S4() + "-" + S4() + "-" + S4() + S4() + S4(); + return placeholder; + }); + return { placeholders, processedDefinition }; + } + function parseTokensFromDefinition(definition) { + definition = definition.replace(/\(/g, " ( "); + definition = definition.replace(/\)/g, " ) "); + definition = definition.replace(/\{/g, " { "); + definition = definition.replace(/\}/g, " } "); + definition = definition.replace(/\]/g, " ] "); + definition = definition.replace(/\[/g, " [ "); + definition = definition.replace(/\,/g, " , "); + return definition.replace(/\s+/g, " ").trim().split(" "); } - // src/nodes/leaf/Leaf.ts - var Leaf = class extends Node { - isLeafNode = () => true; - }; - - // src/Lookup.ts - var Lookup = class { - static getFunc(name) { - return this.functionTable[name]; + // src/mdsl/MDSLNodeArgumentParser.ts + function parseArgumentTokens(tokens, stringArgumentPlaceholders) { + const argumentList = []; + if (!["[", "("].includes(tokens[0])) { + return argumentList; } - static setFunc(name, func) { - this.functionTable[name] = func; + const closingToken = popAndCheck(tokens, ["[", "("]) === "[" ? "]" : ")"; + const argumentListTokens = []; + while (tokens.length && tokens[0] !== closingToken) { + argumentListTokens.push(tokens.shift()); } - static getFuncInvoker(agent, name) { - const foundOnAgent = agent[name]; - if (foundOnAgent && typeof foundOnAgent === "function") { - return (args) => foundOnAgent.apply( - agent, - args.map((arg) => arg.value) - ); - } - if (this.functionTable[name] && typeof this.functionTable[name] === "function") { - return (args) => this.functionTable[name](agent, ...args.map((arg) => arg.value)); + argumentListTokens.forEach((token, index) => { + const shouldBeArgumentToken = !(index & 1); + if (shouldBeArgumentToken) { + const argumentDefinition = getArgumentDefinition(token, stringArgumentPlaceholders); + argumentList.push(argumentDefinition); + } else { + if (token !== ",") { + throw new Error(`invalid argument list, expected ',' or ']' but got '${token}'`); + } } - return null; - } - static getSubtree(name) { - return this.subtreeTable[name]; + }); + popAndCheck(tokens, closingToken); + return argumentList; + } + function getArgumentDefinition(token, stringArgumentPlaceholders) { + if (token === "null") { + return { + value: null, + type: "null" + }; } - static setSubtree(name, subtree) { - this.subtreeTable[name] = subtree; + if (token === "true" || token === "false") { + return { + value: token === "true", + type: "boolean" + }; } - static remove(name) { - delete this.functionTable[name]; - delete this.subtreeTable[name]; + if (!isNaN(token)) { + return { + value: parseFloat(token), + isInteger: parseFloat(token) === parseInt(token, 10), + type: "number" + }; } - static empty() { - this.functionTable = {}; - this.subtreeTable = {}; + if (token.match(/^@@\d+@@$/g)) { + return { + value: stringArgumentPlaceholders[token].replace('\\"', '"'), + type: "string" + }; } - }; - __publicField(Lookup, "functionTable", {}); - __publicField(Lookup, "subtreeTable", {}); + return { + value: token, + type: "identifier" + }; + } - // src/nodes/leaf/Action.ts - var Action = class extends Leaf { - constructor(attributes, actionName, actionArguments) { - super("action", attributes, actionArguments); - this.actionName = actionName; - this.actionArguments = actionArguments; - } - isUsingUpdatePromise = false; - updatePromiseStateResult = null; - onUpdate(agent, options) { - if (this.isUsingUpdatePromise) { - if (this.updatePromiseStateResult) { - this.setState(this.updatePromiseStateResult); - } - return; + // src/mdsl/MDSLNodeAttributeParser.ts + function parseAttributeTokens(tokens, stringArgumentPlaceholders) { + const nodeAttributeNames = ["while", "until", "entry", "exit", "step"]; + const attributes = {}; + let nextAttributeName = tokens[0]?.toLowerCase(); + while (nodeAttributeNames.includes(nextAttributeName)) { + if (attributes[nextAttributeName]) { + throw new Error(`duplicate attribute '${tokens[0].toUpperCase()}' found for node`); } - const actionFuncInvoker = Lookup.getFuncInvoker(agent, this.actionName); - if (actionFuncInvoker === null) { + tokens.shift(); + const [attributeCallIdentifier, ...attributeArguments] = parseArgumentTokens( + tokens, + stringArgumentPlaceholders + ); + if (attributeCallIdentifier?.type !== "identifier") { + throw new Error("expected agent function name identifier argument for attribute"); + } + attributeArguments.filter((arg) => arg.type === "identifier").forEach((arg) => { throw new Error( - `cannot update action node as the action '${this.actionName}' function is not defined on the agent and has not been registered` + `invalid attribute argument value '${arg.value}', must be string, number, boolean or null` ); - } - const updateResult = actionFuncInvoker(this.actionArguments); - if (updateResult instanceof Promise) { - updateResult.then( - (result) => { - if (!this.isUsingUpdatePromise) { - return; - } - if (result !== "mistreevous.succeeded" /* SUCCEEDED */ && result !== "mistreevous.failed" /* FAILED */) { - throw new Error( - "action node promise resolved with an invalid value, expected a State.SUCCEEDED or State.FAILED value to be returned" - ); - } - this.updatePromiseStateResult = result; - }, - (reason) => { - if (!this.isUsingUpdatePromise) { - return; - } - throw new Error(reason); - } - ); - this.setState("mistreevous.running" /* RUNNING */); - this.isUsingUpdatePromise = true; - } else { - this.validateUpdateResult(updateResult); - this.setState(updateResult || "mistreevous.running" /* RUNNING */); - } - } - getName = () => this.actionName; - reset = () => { - this.setState("mistreevous.ready" /* READY */); - this.isUsingUpdatePromise = false; - this.updatePromiseStateResult = null; - }; - validateUpdateResult = (result) => { - switch (result) { - case "mistreevous.succeeded" /* SUCCEEDED */: - case "mistreevous.failed" /* FAILED */: - case void 0: - return; - default: - throw new Error( - `action '${this.actionName}' 'onUpdate' returned an invalid response, expected an optional State.SUCCEEDED or State.FAILED value to be returned` - ); - } - }; - }; - - // src/nodes/leaf/Condition.ts - var Condition = class extends Leaf { - constructor(attributes, conditionName, conditionArguments) { - super("condition", attributes, conditionArguments); - this.conditionName = conditionName; - this.conditionArguments = conditionArguments; - } - onUpdate(agent, options) { - const conditionFuncInvoker = Lookup.getFuncInvoker(agent, this.conditionName); - if (conditionFuncInvoker === null) { - throw new Error( - `cannot update condition node as the condition '${this.conditionName}' function is not defined on the agent and has not been registered` - ); - } - this.setState(!!conditionFuncInvoker(this.conditionArguments) ? "mistreevous.succeeded" /* SUCCEEDED */ : "mistreevous.failed" /* FAILED */); + }); + attributes[nextAttributeName] = { + call: attributeCallIdentifier.value, + args: attributeArguments.map(({ value }) => value) + }; + nextAttributeName = tokens[0]?.toLowerCase(); } - getName = () => this.conditionName; - }; + return attributes; + } - // src/nodes/leaf/Wait.ts - var Wait = class extends Leaf { - constructor(attributes, duration, durationMin, durationMax) { - super("wait", attributes, []); - this.duration = duration; - this.durationMin = durationMin; - this.durationMax = durationMax; - } - initialUpdateTime = 0; - totalDuration = null; - waitedDuration = 0; - onUpdate(agent, options) { - if (this.is("mistreevous.ready" /* READY */)) { - this.initialUpdateTime = new Date().getTime(); - this.waitedDuration = 0; - if (this.duration !== null) { - this.totalDuration = this.duration; - } else if (this.durationMin !== null && this.durationMax !== null) { - const random = typeof options.random === "function" ? options.random : Math.random; - this.totalDuration = Math.floor( - random() * (this.durationMax - this.durationMin + 1) + this.durationMin - ); - } else { - this.totalDuration = null; - } - this.setState("mistreevous.running" /* RUNNING */); - } - if (this.totalDuration === null) { - return; - } - if (typeof options.getDeltaTime === "function") { - const deltaTime = options.getDeltaTime(); - if (typeof deltaTime !== "number" || isNaN(deltaTime)) { - throw new Error("The delta time must be a valid number and not NaN."); - } - this.waitedDuration += deltaTime * 1e3; - } else { - this.waitedDuration = new Date().getTime() - this.initialUpdateTime; - } - if (this.waitedDuration >= this.totalDuration) { - this.setState("mistreevous.succeeded" /* SUCCEEDED */); - } + // src/mdsl/MDSLDefinitionParser.ts + function convertMDSLToJSON(definition) { + const { placeholders, processedDefinition } = substituteStringLiterals(definition); + const tokens = parseTokensFromDefinition(processedDefinition); + return convertTokensToJSONDefinition(tokens, placeholders); + } + function convertTokensToJSONDefinition(tokens, stringLiteralPlaceholders) { + if (tokens.length < 3) { + throw new Error("invalid token count"); } - getName = () => { - if (this.duration !== null) { - return `WAIT ${this.duration}ms`; - } else if (this.durationMin !== null && this.durationMax !== null) { - return `WAIT ${this.durationMin}ms-${this.durationMax}ms`; - } else { - return "WAIT"; - } - }; - }; - - // src/nodes/decorator/Decorator.ts - var Decorator = class extends Node { - constructor(type, attributes, child) { - super(type, attributes, []); - this.child = child; + if (tokens.filter((token) => token === "{").length !== tokens.filter((token) => token === "}").length) { + throw new Error("scope character mismatch"); } - isLeafNode = () => false; - getChildren = () => [this.child]; - reset = () => { - this.setState("mistreevous.ready" /* READY */); - this.child.reset(); - }; - abort = (agent) => { - if (!this.is("mistreevous.running" /* RUNNING */)) { + const treeStacks = []; + const rootNodes = []; + const pushNode = (node) => { + if (isRootNode(node)) { + rootNodes.push(node); + treeStacks.push([node]); return; } - this.child.abort(agent); - this.reset(); - this.getAttribute("exit")?.callAgentFunction(agent, false, true); - }; - }; - - // src/nodes/decorator/Root.ts - var Root = class extends Decorator { - constructor(attributes, child) { - super("root", attributes, child); - } - onUpdate(agent, options) { - if (this.child.getState() === "mistreevous.ready" /* READY */ || this.child.getState() === "mistreevous.running" /* RUNNING */) { - this.child.update(agent, options); - } - this.setState(this.child.getState()); - } - getName = () => "ROOT"; - }; - - // src/nodes/decorator/Repeat.ts - var Repeat = class extends Decorator { - constructor(attributes, iterations, iterationsMin, iterationsMax, child) { - super("repeat", attributes, child); - this.iterations = iterations; - this.iterationsMin = iterationsMin; - this.iterationsMax = iterationsMax; - } - targetIterationCount = null; - currentIterationCount = 0; - onUpdate(agent, options) { - if (this.is("mistreevous.ready" /* READY */)) { - this.child.reset(); - this.currentIterationCount = 0; - this.setTargetIterationCount(options); + if (!treeStacks.length || !treeStacks[treeStacks.length - 1].length) { + throw new Error("expected root node at base of definition"); } - if (this.canIterate()) { - this.setState("mistreevous.running" /* RUNNING */); - if (this.child.getState() === "mistreevous.succeeded" /* SUCCEEDED */) { - this.child.reset(); - } - this.child.update(agent, options); - if (this.child.getState() === "mistreevous.failed" /* FAILED */) { - this.setState("mistreevous.failed" /* FAILED */); - return; - } else if (this.child.getState() === "mistreevous.succeeded" /* SUCCEEDED */) { - this.currentIterationCount += 1; + const topTreeStack = treeStacks[treeStacks.length - 1]; + const topTreeStackTopNode = topTreeStack[topTreeStack.length - 1]; + if (isCompositeNode(topTreeStackTopNode)) { + topTreeStackTopNode.children = topTreeStackTopNode.children || []; + topTreeStackTopNode.children.push(node); + } else if (isDecoratorNode(topTreeStackTopNode)) { + if (topTreeStackTopNode.child) { + throw new Error("a decorator node must only have a single child node"); } - } else { - this.setState("mistreevous.succeeded" /* SUCCEEDED */); + topTreeStackTopNode.child = node; } - } - getName = () => { - if (this.iterations !== null) { - return `REPEAT ${this.iterations}x`; - } else if (this.iterationsMin !== null && this.iterationsMax !== null) { - return `REPEAT ${this.iterationsMin}x-${this.iterationsMax}x`; - } else { - return "REPEAT"; + if (!isLeafNode(node)) { + topTreeStack.push(node); } }; - reset = () => { - this.setState("mistreevous.ready" /* READY */); - this.currentIterationCount = 0; - this.child.reset(); - }; - canIterate = () => { - if (this.targetIterationCount !== null) { - return this.currentIterationCount < this.targetIterationCount; + const popNode = () => { + const topTreeStack = treeStacks[treeStacks.length - 1]; + if (topTreeStack.length) { + topTreeStack.pop(); } - return true; - }; - setTargetIterationCount = (options) => { - if (this.iterations !== null) { - this.targetIterationCount = this.iterations; - } else if (this.iterationsMin !== null && this.iterationsMax !== null) { - const random = typeof options.random === "function" ? options.random : Math.random; - this.targetIterationCount = Math.floor( - random() * (this.iterationsMax - this.iterationsMin + 1) + this.iterationsMin - ); - } else { - this.targetIterationCount = null; + if (!topTreeStack.length) { + treeStacks.pop(); } }; - }; - - // src/nodes/decorator/Retry.ts - var Retry = class extends Decorator { - constructor(attributes, attempts, attemptsMin, attemptsMax, child) { - super("retry", attributes, child); - this.attempts = attempts; - this.attemptsMin = attemptsMin; - this.attemptsMax = attemptsMax; - } - targetAttemptCount = null; - currentAttemptCount = 0; - onUpdate(agent, options) { - if (this.is("mistreevous.ready" /* READY */)) { - this.child.reset(); - this.currentAttemptCount = 0; - this.setTargetAttemptCount(options); - } - if (this.canAttempt()) { - this.setState("mistreevous.running" /* RUNNING */); - if (this.child.getState() === "mistreevous.failed" /* FAILED */) { - this.child.reset(); + while (tokens.length) { + const token = tokens.shift(); + switch (token.toUpperCase()) { + case "ROOT": { + pushNode(createRootNode(tokens, stringLiteralPlaceholders)); + break; } - this.child.update(agent, options); - if (this.child.getState() === "mistreevous.succeeded" /* SUCCEEDED */) { - this.setState("mistreevous.succeeded" /* SUCCEEDED */); - return; - } else if (this.child.getState() === "mistreevous.failed" /* FAILED */) { - this.currentAttemptCount += 1; + case "SUCCEED": { + pushNode(createSucceedNode(tokens, stringLiteralPlaceholders)); + break; } - } else { - this.setState("mistreevous.failed" /* FAILED */); - } - } - getName = () => { - if (this.attempts !== null) { - return `RETRY ${this.attempts}x`; - } else if (this.attemptsMin !== null && this.attemptsMax !== null) { - return `RETRY ${this.attemptsMin}x-${this.attemptsMax}x`; - } else { - return "RETRY"; - } - }; - reset = () => { - this.setState("mistreevous.ready" /* READY */); - this.currentAttemptCount = 0; - this.child.reset(); - }; - canAttempt = () => { - if (this.targetAttemptCount !== null) { - return this.currentAttemptCount < this.targetAttemptCount; - } - return true; - }; - setTargetAttemptCount = (options) => { - if (this.attempts !== null) { - this.targetAttemptCount = this.attempts; - } else if (this.attemptsMin !== null && this.attemptsMax !== null) { - const random = typeof options.random === "function" ? options.random : Math.random; - this.targetAttemptCount = Math.floor( - random() * (this.attemptsMax - this.attemptsMin + 1) + this.attemptsMin - ); - } else { - this.targetAttemptCount = null; - } - }; - }; - - // src/nodes/decorator/Flip.ts - var Flip = class extends Decorator { - constructor(attributes, child) { - super("flip", attributes, child); - } - onUpdate(agent, options) { - if (this.child.getState() === "mistreevous.ready" /* READY */ || this.child.getState() === "mistreevous.running" /* RUNNING */) { - this.child.update(agent, options); - } - switch (this.child.getState()) { - case "mistreevous.running" /* RUNNING */: - this.setState("mistreevous.running" /* RUNNING */); + case "FAIL": { + pushNode(createFailNode(tokens, stringLiteralPlaceholders)); break; - case "mistreevous.succeeded" /* SUCCEEDED */: - this.setState("mistreevous.failed" /* FAILED */); + } + case "FLIP": { + pushNode(createFlipNode(tokens, stringLiteralPlaceholders)); break; - case "mistreevous.failed" /* FAILED */: - this.setState("mistreevous.succeeded" /* SUCCEEDED */); + } + case "REPEAT": { + pushNode(createRepeatNode(tokens, stringLiteralPlaceholders)); break; - default: - this.setState("mistreevous.ready" /* READY */); - } - } - getName = () => "FLIP"; - }; - - // src/nodes/decorator/Succeed.ts - var Succeed = class extends Decorator { - constructor(attributes, child) { - super("succeed", attributes, child); - } - onUpdate(agent, options) { - if (this.child.getState() === "mistreevous.ready" /* READY */ || this.child.getState() === "mistreevous.running" /* RUNNING */) { - this.child.update(agent, options); - } - switch (this.child.getState()) { - case "mistreevous.running" /* RUNNING */: - this.setState("mistreevous.running" /* RUNNING */); + } + case "RETRY": { + pushNode(createRetryNode(tokens, stringLiteralPlaceholders)); break; - case "mistreevous.succeeded" /* SUCCEEDED */: - case "mistreevous.failed" /* FAILED */: - this.setState("mistreevous.succeeded" /* SUCCEEDED */); + } + case "SEQUENCE": { + pushNode(createSequenceNode(tokens, stringLiteralPlaceholders)); break; - default: - this.setState("mistreevous.ready" /* READY */); - } - } - getName = () => "SUCCEED"; - }; - - // src/nodes/decorator/Fail.ts - var Fail = class extends Decorator { - constructor(attributes, child) { - super("fail", attributes, child); - } - onUpdate(agent, options) { - if (this.child.getState() === "mistreevous.ready" /* READY */ || this.child.getState() === "mistreevous.running" /* RUNNING */) { - this.child.update(agent, options); - } - switch (this.child.getState()) { - case "mistreevous.running" /* RUNNING */: - this.setState("mistreevous.running" /* RUNNING */); + } + case "SELECTOR": { + pushNode(createSelectorNode(tokens, stringLiteralPlaceholders)); break; - case "mistreevous.succeeded" /* SUCCEEDED */: - case "mistreevous.failed" /* FAILED */: - this.setState("mistreevous.failed" /* FAILED */); + } + case "PARALLEL": { + pushNode(createParallelNode(tokens, stringLiteralPlaceholders)); break; - default: - this.setState("mistreevous.ready" /* READY */); - } - } - getName = () => "FAIL"; - }; - - // src/nodes/composite/Lotto.ts - var import_lotto_draw = __toESM(require_dist()); - - // src/nodes/composite/Composite.ts - var Composite = class extends Node { - constructor(type, attributes, children) { - super(type, attributes, []); - this.children = children; - } - isLeafNode = () => false; - getChildren = () => this.children; - reset = () => { - this.setState("mistreevous.ready" /* READY */); - this.getChildren().forEach((child) => child.reset()); - }; - abort = (agent) => { - if (!this.is("mistreevous.running" /* RUNNING */)) { - return; - } - this.getChildren().forEach((child) => child.abort(agent)); - this.reset(); - this.getAttribute("exit")?.callAgentFunction(agent, false, true); - }; - }; - - // src/nodes/composite/Lotto.ts - var Lotto = class extends Composite { - constructor(attributes, tickets, children) { - super("lotto", attributes, children); - this.tickets = tickets; - } - selectedChild; - onUpdate(agent, options) { - if (this.is("mistreevous.ready" /* READY */)) { - const lottoDraw = (0, import_lotto_draw.default)({ - random: options.random, - participants: this.children.map((child, index) => [child, this.tickets[index] || 1]) - }); - this.selectedChild = lottoDraw.draw() || void 0; - } - if (!this.selectedChild) { - throw new Error("failed to update lotto node as it has no active child"); - } - if (this.selectedChild.getState() === "mistreevous.ready" /* READY */ || this.selectedChild.getState() === "mistreevous.running" /* RUNNING */) { - this.selectedChild.update(agent, options); - } - this.setState(this.selectedChild.getState()); - } - getName = () => this.tickets.length ? `LOTTO [${this.tickets.join(",")}]` : "LOTTO"; - }; - - // src/nodes/composite/Selector.ts - var Selector = class extends Composite { - constructor(attributes, children) { - super("selector", attributes, children); - this.children = children; - } - onUpdate(agent, options) { - for (const child of this.children) { - if (child.getState() === "mistreevous.ready" /* READY */ || child.getState() === "mistreevous.running" /* RUNNING */) { - child.update(agent, options); } - if (child.getState() === "mistreevous.succeeded" /* SUCCEEDED */) { - this.setState("mistreevous.succeeded" /* SUCCEEDED */); - return; + case "LOTTO": { + pushNode(createLottoNode(tokens, stringLiteralPlaceholders)); + break; } - if (child.getState() === "mistreevous.failed" /* FAILED */) { - if (this.children.indexOf(child) === this.children.length - 1) { - this.setState("mistreevous.failed" /* FAILED */); - return; - } else { - continue; - } + case "ACTION": { + pushNode(createActionNode(tokens, stringLiteralPlaceholders)); + break; } - if (child.getState() === "mistreevous.running" /* RUNNING */) { - this.setState("mistreevous.running" /* RUNNING */); - return; + case "CONDITION": { + pushNode(createConditionNode(tokens, stringLiteralPlaceholders)); + break; + } + case "WAIT": { + pushNode(createWaitNode(tokens, stringLiteralPlaceholders)); + break; + } + case "BRANCH": { + pushNode(createBranchNode(tokens, stringLiteralPlaceholders)); + break; + } + case "}": { + popNode(); + break; + } + default: { + throw new Error(`unexpected token: ${token}`); } - throw new Error("child node was not in an expected state."); } } - getName = () => "SELECTOR"; - }; - - // src/nodes/composite/Sequence.ts - var Sequence = class extends Composite { - constructor(attributes, children) { - super("sequence", attributes, children); - this.children = children; + return rootNodes; + } + function createRootNode(tokens, stringLiteralPlaceholders) { + let node = { + type: "root", + id: void 0 + }; + const nodeArguments = parseArgumentTokens(tokens, stringLiteralPlaceholders); + if (nodeArguments.length) { + if (nodeArguments.length === 1 && nodeArguments[0].type === "identifier") { + node.id = nodeArguments[0].value; + } else { + throw new Error("expected single root name argument"); + } } - onUpdate(agent, options) { - for (const child of this.children) { - if (child.getState() === "mistreevous.ready" /* READY */ || child.getState() === "mistreevous.running" /* RUNNING */) { - child.update(agent, options); - } - if (child.getState() === "mistreevous.succeeded" /* SUCCEEDED */) { - if (this.children.indexOf(child) === this.children.length - 1) { - this.setState("mistreevous.succeeded" /* SUCCEEDED */); - return; - } else { - continue; - } - } - if (child.getState() === "mistreevous.failed" /* FAILED */) { - this.setState("mistreevous.failed" /* FAILED */); - return; - } - if (child.getState() === "mistreevous.running" /* RUNNING */) { - this.setState("mistreevous.running" /* RUNNING */); - return; - } - throw new Error("child node was not in an expected state."); + node = { ...node, ...parseAttributeTokens(tokens, stringLiteralPlaceholders) }; + popAndCheck(tokens, "{"); + return node; + } + function createSucceedNode(tokens, stringLiteralPlaceholders) { + const node = { + type: "succeed", + ...parseAttributeTokens(tokens, stringLiteralPlaceholders) + }; + popAndCheck(tokens, "{"); + return node; + } + function createFailNode(tokens, stringLiteralPlaceholders) { + const node = { + type: "fail", + ...parseAttributeTokens(tokens, stringLiteralPlaceholders) + }; + popAndCheck(tokens, "{"); + return node; + } + function createFlipNode(tokens, stringLiteralPlaceholders) { + const node = { + type: "flip", + ...parseAttributeTokens(tokens, stringLiteralPlaceholders) + }; + popAndCheck(tokens, "{"); + return node; + } + function createRepeatNode(tokens, stringLiteralPlaceholders) { + let node = { type: "repeat" }; + const nodeArguments = parseArgumentTokens(tokens, stringLiteralPlaceholders); + if (nodeArguments.length) { + nodeArguments.filter((arg) => arg.type !== "number" || !arg.isInteger).forEach(() => { + throw new Error(`repeat node iteration counts must be integer values`); + }); + if (nodeArguments.length === 1) { + node.iterations = nodeArguments[0].value; + } else if (nodeArguments.length === 2) { + node.iterations = [nodeArguments[0].value, nodeArguments[1].value]; + } else { + throw new Error("invalid number of repeat node iteration count arguments defined"); } } - getName = () => "SEQUENCE"; - }; - - // src/nodes/composite/Parallel.ts - var Parallel = class extends Composite { - constructor(attributes, children) { - super("parallel", attributes, children); + node = { ...node, ...parseAttributeTokens(tokens, stringLiteralPlaceholders) }; + popAndCheck(tokens, "{"); + return node; + } + function createRetryNode(tokens, stringLiteralPlaceholders) { + let node = { type: "retry" }; + const nodeArguments = parseArgumentTokens(tokens, stringLiteralPlaceholders); + if (nodeArguments.length) { + nodeArguments.filter((arg) => arg.type !== "number" || !arg.isInteger).forEach(() => { + throw new Error(`retry node attempt counts must be integer values`); + }); + if (nodeArguments.length === 1) { + node.attempts = nodeArguments[0].value; + } else if (nodeArguments.length === 2) { + node.attempts = [nodeArguments[0].value, nodeArguments[1].value]; + } else { + throw new Error("invalid number of retry node attempt count arguments defined"); + } } - onUpdate(agent, options) { - let succeededCount = 0; - let hasChildFailed = false; - for (const child of this.children) { - if (child.getState() === "mistreevous.ready" /* READY */ || child.getState() === "mistreevous.running" /* RUNNING */) { - child.update(agent, options); - } - if (child.getState() === "mistreevous.succeeded" /* SUCCEEDED */) { - succeededCount++; - continue; - } - if (child.getState() === "mistreevous.failed" /* FAILED */) { - hasChildFailed = true; - break; - } - if (child.getState() !== "mistreevous.running" /* RUNNING */) { - throw new Error("child node was not in an expected state."); - } + node = { ...node, ...parseAttributeTokens(tokens, stringLiteralPlaceholders) }; + popAndCheck(tokens, "{"); + return node; + } + function createSequenceNode(tokens, stringLiteralPlaceholders) { + const node = { + type: "sequence", + ...parseAttributeTokens(tokens, stringLiteralPlaceholders) + }; + popAndCheck(tokens, "{"); + return node; + } + function createSelectorNode(tokens, stringLiteralPlaceholders) { + const node = { + type: "selector", + ...parseAttributeTokens(tokens, stringLiteralPlaceholders) + }; + popAndCheck(tokens, "{"); + return node; + } + function createParallelNode(tokens, stringLiteralPlaceholders) { + const node = { + type: "parallel", + ...parseAttributeTokens(tokens, stringLiteralPlaceholders) + }; + popAndCheck(tokens, "{"); + return node; + } + function createLottoNode(tokens, stringLiteralPlaceholders) { + const nodeArguments = parseArgumentTokens(tokens, stringLiteralPlaceholders); + nodeArguments.filter((arg) => arg.type !== "number" || !arg.isInteger).forEach(() => { + throw new Error(`lotto node weight arguments must be integer values`); + }); + const node = { + type: "lotto", + weights: nodeArguments.map(({ value }) => value), + ...parseAttributeTokens(tokens, stringLiteralPlaceholders) + }; + popAndCheck(tokens, "{"); + return node; + } + function createActionNode(tokens, stringLiteralPlaceholders) { + const [actionNameIdentifier, ...agentFunctionArgs] = parseArgumentTokens(tokens, stringLiteralPlaceholders); + if (actionNameIdentifier?.type !== "identifier") { + throw new Error("expected action name identifier argument"); + } + agentFunctionArgs.filter((arg) => arg.type === "identifier").forEach((arg) => { + throw new Error( + `invalid action node argument value '${arg.value}', must be string, number, boolean or null` + ); + }); + return { + type: "action", + call: actionNameIdentifier.value, + args: agentFunctionArgs.map(({ value }) => value), + ...parseAttributeTokens(tokens, stringLiteralPlaceholders) + }; + } + function createConditionNode(tokens, stringLiteralPlaceholders) { + const [conditionNameIdentifier, ...agentFunctionArgs] = parseArgumentTokens(tokens, stringLiteralPlaceholders); + if (conditionNameIdentifier?.type !== "identifier") { + throw new Error("expected condition name identifier argument"); + } + agentFunctionArgs.filter((arg) => arg.type === "identifier").forEach((arg) => { + throw new Error( + `invalid condition node argument value '${arg.value}', must be string, number, boolean or null` + ); + }); + return { + type: "condition", + call: conditionNameIdentifier.value, + args: agentFunctionArgs.map(({ value }) => value), + ...parseAttributeTokens(tokens, stringLiteralPlaceholders) + }; + } + function createWaitNode(tokens, stringLiteralPlaceholders) { + let node = { type: "wait" }; + const nodeArguments = parseArgumentTokens(tokens, stringLiteralPlaceholders); + if (nodeArguments.length) { + nodeArguments.filter((arg) => arg.type !== "number" || !arg.isInteger).forEach(() => { + throw new Error(`wait node duration arguments must be integer values`); + }); + if (nodeArguments.length === 1) { + node.duration = nodeArguments[0].value; + } else if (nodeArguments.length === 2) { + node.duration = [nodeArguments[0].value, nodeArguments[1].value]; + } else if (nodeArguments.length > 2) { + throw new Error("invalid number of wait node duration arguments defined"); } - if (hasChildFailed) { - this.setState("mistreevous.failed" /* FAILED */); - for (const child of this.children) { - if (child.getState() === "mistreevous.running" /* RUNNING */) { - child.abort(agent); - } + } + return { ...node, ...parseAttributeTokens(tokens, stringLiteralPlaceholders) }; + } + function createBranchNode(tokens, stringLiteralPlaceholders) { + const nodeArguments = parseArgumentTokens(tokens, stringLiteralPlaceholders); + if (nodeArguments.length !== 1 || nodeArguments[0].type !== "identifier") { + throw new Error("expected single branch name argument"); + } + return { type: "branch", ref: nodeArguments[0].value }; + } + + // src/BehaviourTreeDefinitionValidator.ts + function validateDefinition(definition) { + const createFailureResult = (errorMessage) => ({ succeeded: false, errorMessage }); + if (definition === null || typeof definition === "undefined") { + return createFailureResult("definition is null or undefined"); + } + let rootNodeDefinitions; + if (typeof definition === "string") { + try { + rootNodeDefinitions = convertMDSLToJSON(definition); + } catch (error) { + return createFailureResult(`invalid mdsl: ${definition}`); + } + } else if (typeof definition === "object") { + if (Array.isArray(definition)) { + const invalidDefinitionElements = definition.filter((element) => { + return typeof element !== "object" || Array.isArray(element) || element === null; + }); + if (invalidDefinitionElements.length) { + return createFailureResult( + "invalid elements in definition array, each must be an root node definition object" + ); } + rootNodeDefinitions = definition; } else { - this.setState(succeededCount === this.children.length ? "mistreevous.succeeded" /* SUCCEEDED */ : "mistreevous.running" /* RUNNING */); + rootNodeDefinitions = [definition]; } + } else { + return createFailureResult(`unexpected definition type of '${typeof definition}'`); } - getName = () => "PARALLEL"; - }; - - // src/attributes/Attribute.ts - var Attribute = class { - constructor(type, args) { - this.type = type; - this.args = args; + try { + rootNodeDefinitions.forEach((rootNodeDefinition) => validateNode(rootNodeDefinition, 0)); + } catch (error) { + if (error instanceof Error) { + return createFailureResult(error.message); + } + return createFailureResult(`unexpected error: ${error}`); } - getType = () => this.type; - getArguments = () => this.args; - }; - - // src/attributes/guards/Guard.ts - var Guard = class extends Attribute { - constructor(type, args, condition) { - super(type, args); - this.condition = condition; + const mainRootNodeDefinitions = rootNodeDefinitions.filter(({ id }) => typeof id === "undefined"); + const subRootNodeDefinitions = rootNodeDefinitions.filter(({ id }) => typeof id === "string" && id.length > 0); + if (mainRootNodeDefinitions.length !== 1) { + return createFailureResult("expected single root node without 'id' property defined to act as main root"); } - getCondition = () => this.condition; - isGuard = () => true; - getDetails() { - return { - type: this.getType(), - args: this.getArguments(), - condition: this.getCondition() - }; + const subRootNodeIdenitifers = []; + for (const { id } of subRootNodeDefinitions) { + if (subRootNodeIdenitifers.includes(id)) { + return createFailureResult(`multiple root nodes found with duplicate 'id' property value of '${id}'`); + } + subRootNodeIdenitifers.push(id); } - }; - - // src/attributes/guards/While.ts - var While = class extends Guard { - constructor(condition, args) { - super("while", args, condition); + const circularDependencyPath = findBranchCircularDependencyPath(rootNodeDefinitions); + if (circularDependencyPath) { + return createFailureResult(`circular dependency found in branch node references: ${circularDependencyPath}`); } - isSatisfied = (agent) => { - const conditionFuncInvoker = Lookup.getFuncInvoker(agent, this.getCondition()); - if (conditionFuncInvoker === null) { - throw new Error( - `cannot evaluate node guard as the condition '${this.getCondition()}' function is not defined on the agent and has not been registered` - ); + return { succeeded: true }; + } + function findBranchCircularDependencyPath(rootNodeDefinitions) { + const rootNodeMappings = rootNodeDefinitions.map( + (rootNodeDefinition) => ({ + id: rootNodeDefinition.id, + refs: flattenDefinition(rootNodeDefinition).filter(isBranchNode).map(({ ref }) => ref) + }) + ); + let badPathFormatted = null; + const followRefs = (mapping, path = []) => { + if (path.includes(mapping.id)) { + const badPath = [...path, mapping.id]; + badPathFormatted = badPath.map((element) => !!element).join(" => "); + return; } - return !!conditionFuncInvoker(this.args); - }; - }; - - // src/attributes/guards/Until.ts - var Until = class extends Guard { - constructor(condition, args) { - super("until", args, condition); - } - isSatisfied = (agent) => { - const conditionFuncInvoker = Lookup.getFuncInvoker(agent, this.getCondition()); - if (conditionFuncInvoker === null) { - throw new Error( - `cannot evaluate node guard as the condition '${this.getCondition()}' function is not defined on the agent and has not been registered` - ); + for (const ref of mapping.refs) { + const subMapping = rootNodeMappings.find(({ id }) => id === ref); + if (subMapping) { + followRefs(subMapping, [...path, mapping.id]); + } } - return !!!conditionFuncInvoker(this.args); }; - }; - - // src/attributes/callbacks/Callback.ts - var Callback = class extends Attribute { - constructor(type, args, functionName) { - super(type, args); - this.functionName = functionName; - } - getFunctionName = () => this.functionName; - isGuard = () => false; - getDetails() { - return { - type: this.getType(), - args: this.getArguments(), - functionName: this.getFunctionName() - }; + return badPathFormatted; + } + function validateNode(definition, depth) { + if (typeof definition !== "object" || typeof definition.type !== "string" || definition.type.length === 0) { + throw new Error( + `node definition is not an object or 'type' property is not a non-empty string at depth '${depth}'` + ); } - }; - - // src/attributes/callbacks/Entry.ts - var Entry = class extends Callback { - constructor(functionName, args) { - super("entry", args, functionName); + switch (definition.type) { + case "action": + validateActionNode(definition, depth); + break; + case "condition": + validateConditionNode(definition, depth); + break; + case "wait": + validateWaitNode(definition, depth); + break; + case "branch": + validateBranchNode(definition, depth); + break; + case "root": + validateRootNode(definition, depth); + break; + case "success": + validateSuccessNode(definition, depth); + break; + case "fail": + validateFailNode(definition, depth); + break; + case "flip": + validateFlipNode(definition, depth); + break; + case "repeat": + validateRepeatNode(definition, depth); + break; + case "retry": + validateRetryNode(definition, depth); + break; + case "sequence": + validateSequenceNode(definition, depth); + break; + case "selector": + validateSelectorNode(definition, depth); + break; + case "parallel": + validateParallelNode(definition, depth); + break; + default: + throw new Error(`unexpected node type of '${definition.type}' at depth '${depth}'`); } - callAgentFunction = (agent) => { - const callbackFuncInvoker = Lookup.getFuncInvoker(agent, this.getFunctionName()); - if (callbackFuncInvoker === null) { + } + function validateNodeAttributes(definition, depth) { + ["while", "until", "entry", "exit", "step"].forEach((attributeName) => { + const attributeDefinition = definition[attributeName]; + if (typeof attributeDefinition === "undefined") { + return; + } + if (typeof attributeDefinition !== "object") { throw new Error( - `cannot call entry function '${this.getFunctionName()}' as is not defined on the agent and has not been registered` + `expected attribute '${attributeName}' to be an object for '${definition.type}' node at depth '${depth}'` ); } - callbackFuncInvoker(this.args); - }; - }; - - // src/attributes/callbacks/Exit.ts - var Exit = class extends Callback { - constructor(functionName, args) { - super("exit", args, functionName); - } - callAgentFunction = (agent, isSuccess, isAborted) => { - const callbackFuncInvoker = Lookup.getFuncInvoker(agent, this.getFunctionName()); - if (callbackFuncInvoker === null) { + if (typeof attributeDefinition.call !== "string" || attributeDefinition.call.length === 0) { throw new Error( - `cannot call exit function '${this.getFunctionName()}' as is not defined on the agent and has not been registered` + `expected 'call' property for attribute '${attributeName}' to be a non-empty string for '${definition.type}' node at depth '${depth}'` ); } - callbackFuncInvoker([{ value: { succeeded: isSuccess, aborted: isAborted } }, ...this.args]); - }; - }; - - // src/attributes/callbacks/Step.ts - var Step = class extends Callback { - constructor(functionName, args) { - super("step", args, functionName); - } - callAgentFunction = (agent) => { - const callbackFuncInvoker = Lookup.getFuncInvoker(agent, this.getFunctionName()); - if (callbackFuncInvoker === null) { + if (typeof attributeDefinition.args !== "undefined" && !Array.isArray(attributeDefinition.args)) { throw new Error( - `cannot call step function '${this.getFunctionName()}' as is not defined on the agent and has not been registered` + `expected 'args' property for attribute '${attributeName}' to be an array for '${definition.type}' node at depth '${depth}'` ); } - callbackFuncInvoker(this.args); - }; - }; - - // src/RootAstNodesBuilder.ts - var AttributeFactories = { - WHILE: (condition, attributeArguments) => new While(condition, attributeArguments), - UNTIL: (condition, attributeArguments) => new Until(condition, attributeArguments), - ENTRY: (functionName, attributeArguments) => new Entry(functionName, attributeArguments), - EXIT: (functionName, attributeArguments) => new Exit(functionName, attributeArguments), - STEP: (functionName, attributeArguments) => new Step(functionName, attributeArguments) - }; - var ASTNodeFactories = { - ROOT: () => ({ - type: "root", - attributes: [], - name: null, - children: [], - validate(depth) { - if (depth > 1) { - throw new Error("a root node cannot be the child of another node"); - } - if (this.children.length !== 1) { - throw new Error("a root node must have a single child"); + }); + } + function validateRootNode(definition, depth) { + if (definition.type !== "root") { + throw new Error("expected node type of 'root' for root node"); + } + if (depth > 0) { + throw new Error("a root node cannot be the child of another node"); + } + if (typeof definition.id !== "undefined" && (typeof definition.id !== "string" || definition.id.length === 0)) { + throw new Error("expected non-empty string for 'id' property if defined for root node"); + } + if (typeof definition.child === "undefined") { + throw new Error("expected property 'child' to be defined for root node"); + } + validateNodeAttributes(definition, depth); + validateNode(definition.child, depth + 1); + } + function validateSuccessNode(definition, depth) { + if (definition.type !== "success") { + throw new Error(`expected node type of 'success' for success node at depth '${depth}'`); + } + if (typeof definition.child === "undefined") { + throw new Error(`expected property 'child' to be defined for success node at depth '${depth}'`); + } + validateNodeAttributes(definition, depth); + validateNode(definition.child, depth + 1); + } + function validateFailNode(definition, depth) { + if (definition.type !== "fail") { + throw new Error(`expected node type of 'fail' for fail node at depth '${depth}'`); + } + if (typeof definition.child === "undefined") { + throw new Error(`expected property 'child' to be defined for fail node at depth '${depth}'`); + } + validateNodeAttributes(definition, depth); + validateNode(definition.child, depth + 1); + } + function validateFlipNode(definition, depth) { + if (definition.type !== "flip") { + throw new Error(`expected node type of 'flip' for flip node at depth '${depth}'`); + } + if (typeof definition.child === "undefined") { + throw new Error(`expected property 'child' to be defined for flip node at depth '${depth}'`); + } + validateNodeAttributes(definition, depth); + validateNode(definition.child, depth + 1); + } + function validateRepeatNode(definition, depth) { + if (definition.type !== "repeat") { + throw new Error(`expected node type of 'repeat' for repeat node at depth '${depth}'`); + } + if (typeof definition.child === "undefined") { + throw new Error(`expected property 'child' to be defined for repeat node at depth '${depth}'`); + } + if (typeof definition.iterations !== "undefined") { + if (Array.isArray(definition.iterations)) { + const containsNonInteger = !!definition.iterations.find((value) => !isInteger(value)); + if (definition.iterations.length !== 2 || containsNonInteger) { + throw new Error( + `expected array containing two integer values for 'iterations' property if defined for repeat node at depth '${depth}'` + ); } - }, - createNodeInstance(namedRootNodeProvider, visitedBranches) { - return new Root( - this.attributes, - this.children[0].createNodeInstance(namedRootNodeProvider, visitedBranches.slice()) + } else if (!isInteger(definition.iterations)) { + throw new Error( + `expected integer value or array containing two integer values for 'iterations' property if defined for repeat node at depth '${depth}'` ); } - }), - BRANCH: () => ({ - type: "branch", - branchName: "", - validate() { - }, - createNodeInstance(namedRootNodeProvider, visitedBranches) { - const targetRootNode = namedRootNodeProvider(this.branchName); - if (visitedBranches.indexOf(this.branchName) !== -1) { - throw new Error(`circular dependency found in branch node references for branch '${this.branchName}'`); - } - if (targetRootNode) { - return targetRootNode.createNodeInstance(namedRootNodeProvider, visitedBranches.concat(this.branchName)).getChildren()[0]; - } else { - throw new Error(`branch references root node '${this.branchName}' which has not been defined`); - } - } - }), - SELECTOR: () => ({ - type: "selector", - attributes: [], - children: [], - validate() { - if (this.children.length < 1) { - throw new Error("a selector node must have at least a single child"); + } + validateNodeAttributes(definition, depth); + validateNode(definition.child, depth + 1); + } + function validateRetryNode(definition, depth) { + if (definition.type !== "retry") { + throw new Error(`expected node type of 'retry' for retry node at depth '${depth}'`); + } + if (typeof definition.child === "undefined") { + throw new Error(`expected property 'child' to be defined for retry node at depth '${depth}'`); + } + if (typeof definition.attempts !== "undefined") { + if (Array.isArray(definition.attempts)) { + const containsNonInteger = !!definition.attempts.find((value) => !isInteger(value)); + if (definition.attempts.length !== 2 || containsNonInteger) { + throw new Error( + `expected array containing two integer values for 'attempts' property if defined for retry node at depth '${depth}'` + ); } - }, - createNodeInstance(namedRootNodeProvider, visitedBranches) { - return new Selector( - this.attributes, - this.children.map((child) => child.createNodeInstance(namedRootNodeProvider, visitedBranches.slice())) + } else if (!isInteger(definition.attempts)) { + throw new Error( + `expected integer value or array containing two integer values for 'attempts' property if defined for retry node at depth '${depth}'` ); } - }), - SEQUENCE: () => ({ - type: "sequence", - attributes: [], - children: [], - validate() { - if (this.children.length < 1) { - throw new Error("a sequence node must have at least a single child"); - } - }, - createNodeInstance(namedRootNodeProvider, visitedBranches) { - return new Sequence( - this.attributes, - this.children.map((child) => child.createNodeInstance(namedRootNodeProvider, visitedBranches.slice())) + } + validateNodeAttributes(definition, depth); + validateNode(definition.child, depth + 1); + } + function validateBranchNode(definition, depth) { + if (definition.type !== "branch") { + throw new Error(`expected node type of 'branch' for branch node at depth '${depth}'`); + } + if (typeof definition.ref !== "string" || definition.ref.length === 0) { + throw new Error(`expected non-empty string for 'ref' property for branch node at depth '${depth}'`); + } + ["while", "until"].forEach((attributeName) => { + if (typeof definition[attributeName] !== "undefined") { + throw new Error( + `guards should not be defined for branch nodes but guard '${attributeName}' was defined for branch node at depth '${depth}'` ); } - }), - PARALLEL: () => ({ - type: "parallel", - attributes: [], - children: [], - validate() { - if (this.children.length < 1) { - throw new Error("a parallel node must have at least a single child"); - } - }, - createNodeInstance(namedRootNodeProvider, visitedBranches) { - return new Parallel( - this.attributes, - this.children.map((child) => child.createNodeInstance(namedRootNodeProvider, visitedBranches.slice())) + }); + ["entry", "exit", "step"].forEach((attributeName) => { + if (typeof definition[attributeName] !== "undefined") { + throw new Error( + `callbacks should not be defined for branch nodes but callback '${attributeName}' was defined for branch node at depth '${depth}'` ); } - }), - LOTTO: () => ({ - type: "lotto", - attributes: [], - children: [], - tickets: [], - validate() { - if (this.children.length < 1) { - throw new Error("a lotto node must have at least a single child"); + }); + } + function validateActionNode(definition, depth) { + if (definition.type !== "action") { + throw new Error(`expected node type of 'action' for action node at depth '${depth}'`); + } + if (typeof definition.call !== "string" || definition.call.length === 0) { + throw new Error(`expected non-empty string for 'call' property of action node at depth '${depth}'`); + } + if (typeof definition.args !== "undefined" && !Array.isArray(definition.args)) { + throw new Error(`expected array for 'args' property if defined for action node at depth '${depth}'`); + } + validateNodeAttributes(definition, depth); + } + function validateConditionNode(definition, depth) { + if (definition.type !== "condition") { + throw new Error(`expected node type of 'condition' for condition node at depth '${depth}'`); + } + if (typeof definition.call !== "string" || definition.call.length === 0) { + throw new Error(`expected non-empty string for 'call' property of condition node at depth '${depth}'`); + } + if (typeof definition.args !== "undefined" && !Array.isArray(definition.args)) { + throw new Error(`expected array for 'args' property if defined for condition node at depth '${depth}'`); + } + validateNodeAttributes(definition, depth); + } + function validateWaitNode(definition, depth) { + if (definition.type !== "wait") { + throw new Error(`expected node type of 'wait' for wait node at depth '${depth}'`); + } + if (typeof definition.duration !== "undefined") { + if (Array.isArray(definition.duration)) { + const containsNonInteger = !!definition.duration.find((value) => !isInteger(value)); + if (definition.duration.length !== 2 || containsNonInteger) { + throw new Error( + `expected array containing two integer values for 'duration' property if defined for wait node at depth '${depth}'` + ); } - }, - createNodeInstance(namedRootNodeProvider, visitedBranches) { - return new Lotto( - this.attributes, - this.tickets, - this.children.map((child) => child.createNodeInstance(namedRootNodeProvider, visitedBranches.slice())) + } else if (!isInteger(definition.duration)) { + throw new Error( + `expected integer value or array containing two integer values for 'duration' property if defined for wait node at depth '${depth}'` ); } - }), - REPEAT: () => ({ - type: "repeat", - attributes: [], - iterations: null, - iterationsMin: null, - iterationsMax: null, - children: [], - validate() { - if (this.children.length !== 1) { - throw new Error("a repeat node must have a single child"); - } - if (this.iterations !== null) { - if (this.iterations < 0) { - throw new Error("a repeat node must have a positive number of iterations if defined"); - } - } else if (this.iterationsMin !== null && this.iterationsMax !== null) { - if (this.iterationsMin < 0 || this.iterationsMax < 0) { - throw new Error( - "a repeat node must have a positive minimum and maximum iteration count if defined" - ); - } - if (this.iterationsMin > this.iterationsMax) { - throw new Error( - "a repeat node must not have a minimum iteration count that exceeds the maximum iteration count" - ); + } + validateNodeAttributes(definition, depth); + } + function validateSequenceNode(definition, depth) { + if (definition.type !== "sequence") { + throw new Error(`expected node type of 'sequence' for sequence node at depth '${depth}'`); + } + if (!Array.isArray(definition.children) || definition.children.length === 0) { + throw new Error(`expected non-empty 'children' array to be defined for sequence node at depth '${depth}'`); + } + validateNodeAttributes(definition, depth); + definition.children.forEach((child) => validateNode(child, depth + 1)); + } + function validateSelectorNode(definition, depth) { + if (definition.type !== "selector") { + throw new Error(`expected node type of 'selector' for selector node at depth '${depth}'`); + } + if (!Array.isArray(definition.children) || definition.children.length === 0) { + throw new Error(`expected non-empty 'children' array to be defined for selector node at depth '${depth}'`); + } + validateNodeAttributes(definition, depth); + definition.children.forEach((child) => validateNode(child, depth + 1)); + } + function validateParallelNode(definition, depth) { + if (definition.type !== "parallel") { + throw new Error(`expected node type of 'parallel' for parallel node at depth '${depth}'`); + } + if (!Array.isArray(definition.children) || definition.children.length === 0) { + throw new Error(`expected non-empty 'children' array to be defined for parallel node at depth '${depth}'`); + } + validateNodeAttributes(definition, depth); + definition.children.forEach((child) => validateNode(child, depth + 1)); + } + + // src/attributes/guards/GuardUnsatisifedException.ts + var GuardUnsatisifedException = class extends Error { + constructor(source) { + super("A guard path condition has failed"); + this.source = source; + } + isSourceNode = (node) => node === this.source; + }; + + // src/attributes/guards/GuardPath.ts + var GuardPath = class { + constructor(nodes) { + this.nodes = nodes; + } + evaluate = (agent) => { + for (const details of this.nodes) { + for (const guard of details.guards) { + if (!guard.isSatisfied(agent)) { + throw new GuardUnsatisifedException(details.node); } - } else { } - }, - createNodeInstance(namedRootNodeProvider, visitedBranches) { - return new Repeat( - this.attributes, - this.iterations, - this.iterationsMin, - this.iterationsMax, - this.children[0].createNodeInstance(namedRootNodeProvider, visitedBranches.slice()) - ); } - }), - RETRY: () => ({ - type: "retry", - attributes: [], - attempts: null, - attemptsMin: null, - attemptsMax: null, - children: [], - validate() { - if (this.children.length !== 1) { - throw new Error("a retry node must have a single child"); + }; + }; + + // src/nodes/Node.ts + var Node = class { + constructor(type, attributes, args) { + this.type = type; + this.attributes = attributes; + this.args = args; + } + uid = createNodeUid(); + state = "mistreevous.ready" /* READY */; + guardPath; + getState = () => this.state; + setState = (value) => { + this.state = value; + }; + getUid = () => this.uid; + getType = () => this.type; + getAttributes = () => this.attributes; + getArguments = () => this.args; + getAttribute(type) { + return this.getAttributes().filter((decorator) => decorator.getType().toUpperCase() === type.toUpperCase())[0] || null; + } + getGuardAttributes = () => this.getAttributes().filter((decorator) => decorator.isGuard()); + setGuardPath = (value) => this.guardPath = value; + hasGuardPath = () => !!this.guardPath; + is(value) { + return this.state === value; + } + reset() { + this.setState("mistreevous.ready" /* READY */); + } + abort(agent) { + if (!this.is("mistreevous.running" /* RUNNING */)) { + return; + } + this.reset(); + this.getAttribute("exit")?.callAgentFunction(agent, false, true); + } + update(agent, options) { + if (this.is("mistreevous.succeeded" /* SUCCEEDED */) || this.is("mistreevous.failed" /* FAILED */)) { + return; + } + try { + this.guardPath.evaluate(agent); + if (this.is("mistreevous.ready" /* READY */)) { + this.getAttribute("entry")?.callAgentFunction(agent); } - if (this.attempts !== null) { - if (this.attempts < 0) { - throw new Error("a retry node must have a positive number of attempts if defined"); - } - } else if (this.attemptsMin !== null && this.attemptsMax !== null) { - if (this.attemptsMin < 0 || this.attemptsMax < 0) { - throw new Error("a retry node must have a positive minimum and maximum attempt count if defined"); - } - if (this.attemptsMin > this.attemptsMax) { - throw new Error( - "a retry node must not have a minimum attempt count that exceeds the maximum attempt count" - ); - } + this.getAttribute("step")?.callAgentFunction(agent); + this.onUpdate(agent, options); + if (this.is("mistreevous.succeeded" /* SUCCEEDED */) || this.is("mistreevous.failed" /* FAILED */)) { + this.getAttribute("exit")?.callAgentFunction(agent, this.is("mistreevous.succeeded" /* SUCCEEDED */), false); + } + } catch (error) { + if (error instanceof GuardUnsatisifedException && error.isSourceNode(this)) { + this.abort(agent); + this.setState("mistreevous.failed" /* FAILED */); } else { + throw error; } - }, - createNodeInstance(namedRootNodeProvider, visitedBranches) { - return new Retry( - this.attributes, - this.attempts, - this.attemptsMin, - this.attemptsMax, - this.children[0].createNodeInstance(namedRootNodeProvider, visitedBranches.slice()) - ); } - }), - FLIP: () => ({ - type: "flip", - attributes: [], - children: [], - validate() { - if (this.children.length !== 1) { - throw new Error("a flip node must have a single child"); - } - }, - createNodeInstance(namedRootNodeProvider, visitedBranches) { - return new Flip( - this.attributes, - this.children[0].createNodeInstance(namedRootNodeProvider, visitedBranches.slice()) + } + }; + function createNodeUid() { + var S4 = function() { + return ((1 + Math.random()) * 65536 | 0).toString(16).substring(1); + }; + return S4() + S4() + "-" + S4() + "-" + S4() + "-" + S4() + "-" + S4() + S4() + S4(); + } + + // src/nodes/leaf/Leaf.ts + var Leaf = class extends Node { + isLeafNode = () => true; + }; + + // src/Lookup.ts + var Lookup = class { + static getFunc(name) { + return this.functionTable[name]; + } + static setFunc(name, func) { + this.functionTable[name] = func; + } + static getFuncInvoker(agent, name) { + const foundOnAgent = agent[name]; + if (foundOnAgent && typeof foundOnAgent === "function") { + return (args) => foundOnAgent.apply( + agent, + args.map((arg) => arg.value) ); } - }), - SUCCEED: () => ({ - type: "succeed", - attributes: [], - children: [], - validate() { - if (this.children.length !== 1) { - throw new Error("a succeed node must have a single child"); - } - }, - createNodeInstance(namedRootNodeProvider, visitedBranches) { - return new Succeed( - this.attributes, - this.children[0].createNodeInstance(namedRootNodeProvider, visitedBranches.slice()) - ); + if (this.functionTable[name] && typeof this.functionTable[name] === "function") { + return (args) => this.functionTable[name](agent, ...args.map((arg) => arg.value)); } - }), - FAIL: () => ({ - type: "fail", - attributes: [], - children: [], - validate() { - if (this.children.length !== 1) { - throw new Error("a fail node must have a single child"); + return null; + } + static getSubtree(name) { + return this.subtreeTable[name]; + } + static setSubtree(name, subtree) { + this.subtreeTable[name] = subtree; + } + static remove(name) { + delete this.functionTable[name]; + delete this.subtreeTable[name]; + } + static empty() { + this.functionTable = {}; + this.subtreeTable = {}; + } + }; + __publicField(Lookup, "functionTable", {}); + __publicField(Lookup, "subtreeTable", {}); + + // src/nodes/leaf/Action.ts + var Action = class extends Leaf { + constructor(attributes, actionName, actionArguments) { + super("action", attributes, actionArguments); + this.actionName = actionName; + this.actionArguments = actionArguments; + } + isUsingUpdatePromise = false; + updatePromiseStateResult = null; + onUpdate(agent, options) { + if (this.isUsingUpdatePromise) { + if (this.updatePromiseStateResult) { + this.setState(this.updatePromiseStateResult); } - }, - createNodeInstance(namedRootNodeProvider, visitedBranches) { - return new Fail( - this.attributes, - this.children[0].createNodeInstance(namedRootNodeProvider, visitedBranches.slice()) + return; + } + const actionFuncInvoker = Lookup.getFuncInvoker(agent, this.actionName); + if (actionFuncInvoker === null) { + throw new Error( + `cannot update action node as the action '${this.actionName}' function is not defined on the agent and has not been registered` ); } - }), - WAIT: () => ({ - type: "wait", - attributes: [], - duration: null, - durationMin: null, - durationMax: null, - validate() { - if (this.duration !== null) { - if (this.duration < 0) { - throw new Error("a wait node must have a positive duration"); + const updateResult = actionFuncInvoker(this.actionArguments); + if (updateResult instanceof Promise) { + updateResult.then( + (result) => { + if (!this.isUsingUpdatePromise) { + return; + } + if (result !== "mistreevous.succeeded" /* SUCCEEDED */ && result !== "mistreevous.failed" /* FAILED */) { + throw new Error( + "action node promise resolved with an invalid value, expected a State.SUCCEEDED or State.FAILED value to be returned" + ); + } + this.updatePromiseStateResult = result; + }, + (reason) => { + if (!this.isUsingUpdatePromise) { + return; + } + throw new Error(reason); } + ); + this.setState("mistreevous.running" /* RUNNING */); + this.isUsingUpdatePromise = true; + } else { + this.validateUpdateResult(updateResult); + this.setState(updateResult || "mistreevous.running" /* RUNNING */); + } + } + getName = () => this.actionName; + reset = () => { + this.setState("mistreevous.ready" /* READY */); + this.isUsingUpdatePromise = false; + this.updatePromiseStateResult = null; + }; + validateUpdateResult = (result) => { + switch (result) { + case "mistreevous.succeeded" /* SUCCEEDED */: + case "mistreevous.failed" /* FAILED */: + case void 0: + return; + default: + throw new Error( + `action '${this.actionName}' 'onUpdate' returned an invalid response, expected an optional State.SUCCEEDED or State.FAILED value to be returned` + ); + } + }; + }; + + // src/nodes/leaf/Condition.ts + var Condition = class extends Leaf { + constructor(attributes, conditionName, conditionArguments) { + super("condition", attributes, conditionArguments); + this.conditionName = conditionName; + this.conditionArguments = conditionArguments; + } + onUpdate(agent, options) { + const conditionFuncInvoker = Lookup.getFuncInvoker(agent, this.conditionName); + if (conditionFuncInvoker === null) { + throw new Error( + `cannot update condition node as the condition '${this.conditionName}' function is not defined on the agent and has not been registered` + ); + } + this.setState(!!conditionFuncInvoker(this.conditionArguments) ? "mistreevous.succeeded" /* SUCCEEDED */ : "mistreevous.failed" /* FAILED */); + } + getName = () => this.conditionName; + }; + + // src/nodes/leaf/Wait.ts + var Wait = class extends Leaf { + constructor(attributes, duration, durationMin, durationMax) { + super("wait", attributes, []); + this.duration = duration; + this.durationMin = durationMin; + this.durationMax = durationMax; + } + initialUpdateTime = 0; + totalDuration = null; + waitedDuration = 0; + onUpdate(agent, options) { + if (this.is("mistreevous.ready" /* READY */)) { + this.initialUpdateTime = new Date().getTime(); + this.waitedDuration = 0; + if (this.duration !== null) { + this.totalDuration = this.duration; } else if (this.durationMin !== null && this.durationMax !== null) { - if (this.durationMin < 0 || this.durationMax < 0) { - throw new Error("a wait node must have a positive minimum and maximum duration"); - } - if (this.durationMin > this.durationMax) { - throw new Error("a wait node must not have a minimum duration that exceeds the maximum duration"); - } + const random = typeof options.random === "function" ? options.random : Math.random; + this.totalDuration = Math.floor( + random() * (this.durationMax - this.durationMin + 1) + this.durationMin + ); } else { + this.totalDuration = null; } - }, - createNodeInstance() { - return new Wait(this.attributes, this.duration, this.durationMin, this.durationMax); + this.setState("mistreevous.running" /* RUNNING */); } - }), - ACTION: () => ({ - type: "action", - attributes: [], - actionName: "", - actionArguments: [], - validate() { - }, - createNodeInstance() { - return new Action(this.attributes, this.actionName, this.actionArguments); + if (this.totalDuration === null) { + return; } - }), - CONDITION: () => ({ - type: "condition", - attributes: [], - conditionName: "", - conditionArguments: [], - validate() { - }, - createNodeInstance() { - return new Condition(this.attributes, this.conditionName, this.conditionArguments); + if (typeof options.getDeltaTime === "function") { + const deltaTime = options.getDeltaTime(); + if (typeof deltaTime !== "number" || isNaN(deltaTime)) { + throw new Error("The delta time must be a valid number and not NaN."); + } + this.waitedDuration += deltaTime * 1e3; + } else { + this.waitedDuration = new Date().getTime() - this.initialUpdateTime; } - }) + if (this.waitedDuration >= this.totalDuration) { + this.setState("mistreevous.succeeded" /* SUCCEEDED */); + } + } + getName = () => { + if (this.duration !== null) { + return `WAIT ${this.duration}ms`; + } else if (this.durationMin !== null && this.durationMax !== null) { + return `WAIT ${this.durationMin}ms-${this.durationMax}ms`; + } else { + return "WAIT"; + } + }; }; - function buildRootASTNodes(definition) { - const { placeholders, processedDefinition } = substituteStringLiterals(definition); - const tokens = parseTokensFromDefinition(processedDefinition); - if (tokens.length < 3) { - throw new Error("invalid token count"); + + // src/nodes/decorator/Decorator.ts + var Decorator = class extends Node { + constructor(type, attributes, child) { + super(type, attributes, []); + this.child = child; } - if (tokens.filter((token) => token === "{").length !== tokens.filter((token) => token === "}").length) { - throw new Error("scope character mismatch"); + isLeafNode = () => false; + getChildren = () => [this.child]; + reset = () => { + this.setState("mistreevous.ready" /* READY */); + this.child.reset(); + }; + abort = (agent) => { + if (!this.is("mistreevous.running" /* RUNNING */)) { + return; + } + this.child.abort(agent); + this.reset(); + this.getAttribute("exit")?.callAgentFunction(agent, false, true); + }; + }; + + // src/nodes/decorator/Root.ts + var Root = class extends Decorator { + constructor(attributes, child) { + super("root", attributes, child); } - const stack = [[]]; - const rootScope = stack[0]; - while (tokens.length) { - const token = tokens.shift(); - const currentScope = stack[stack.length - 1]; - switch (token.toUpperCase()) { - case "ROOT": { - const node = ASTNodeFactories.ROOT(); - rootScope.push(node); - if (tokens[0] === "[") { - const rootArguments = getArguments(tokens, placeholders); - if (rootArguments.length === 1 && rootArguments[0].type === "identifier") { - node.name = rootArguments[0].value; - } else { - throw new Error("expected single root name argument"); - } - } - node.attributes = getAttributes(tokens, placeholders); - popAndCheck(tokens, "{"); - stack.push(node.children); - break; + onUpdate(agent, options) { + if (this.child.getState() === "mistreevous.ready" /* READY */ || this.child.getState() === "mistreevous.running" /* RUNNING */) { + this.child.update(agent, options); + } + this.setState(this.child.getState()); + } + getName = () => "ROOT"; + }; + + // src/nodes/decorator/Repeat.ts + var Repeat = class extends Decorator { + constructor(attributes, iterations, iterationsMin, iterationsMax, child) { + super("repeat", attributes, child); + this.iterations = iterations; + this.iterationsMin = iterationsMin; + this.iterationsMax = iterationsMax; + } + targetIterationCount = null; + currentIterationCount = 0; + onUpdate(agent, options) { + if (this.is("mistreevous.ready" /* READY */)) { + this.child.reset(); + this.currentIterationCount = 0; + this.setTargetIterationCount(options); + } + if (this.canIterate()) { + this.setState("mistreevous.running" /* RUNNING */); + if (this.child.getState() === "mistreevous.succeeded" /* SUCCEEDED */) { + this.child.reset(); } - case "BRANCH": { - const node = ASTNodeFactories.BRANCH(); - currentScope.push(node); - if (tokens[0] !== "[") { - throw new Error("expected single branch name argument"); - } - const branchArguments = getArguments(tokens, placeholders); - if (branchArguments.length === 1 && branchArguments[0].type === "identifier") { - node.branchName = branchArguments[0].value; - } else { - throw new Error("expected single branch name argument"); - } - break; + this.child.update(agent, options); + if (this.child.getState() === "mistreevous.failed" /* FAILED */) { + this.setState("mistreevous.failed" /* FAILED */); + return; + } else if (this.child.getState() === "mistreevous.succeeded" /* SUCCEEDED */) { + this.currentIterationCount += 1; } - case "SELECTOR": { - const node = ASTNodeFactories.SELECTOR(); - currentScope.push(node); - node.attributes = getAttributes(tokens, placeholders); - popAndCheck(tokens, "{"); - stack.push(node.children); - break; - } - case "SEQUENCE": { - const node = ASTNodeFactories.SEQUENCE(); - currentScope.push(node); - node.attributes = getAttributes(tokens, placeholders); - popAndCheck(tokens, "{"); - stack.push(node.children); - break; + } else { + this.setState("mistreevous.succeeded" /* SUCCEEDED */); + } + } + getName = () => { + if (this.iterations !== null) { + return `REPEAT ${this.iterations}x`; + } else if (this.iterationsMin !== null && this.iterationsMax !== null) { + return `REPEAT ${this.iterationsMin}x-${this.iterationsMax}x`; + } else { + return "REPEAT"; + } + }; + reset = () => { + this.setState("mistreevous.ready" /* READY */); + this.currentIterationCount = 0; + this.child.reset(); + }; + canIterate = () => { + if (this.targetIterationCount !== null) { + return this.currentIterationCount < this.targetIterationCount; + } + return true; + }; + setTargetIterationCount = (options) => { + if (this.iterations !== null) { + this.targetIterationCount = this.iterations; + } else if (this.iterationsMin !== null && this.iterationsMax !== null) { + const random = typeof options.random === "function" ? options.random : Math.random; + this.targetIterationCount = Math.floor( + random() * (this.iterationsMax - this.iterationsMin + 1) + this.iterationsMin + ); + } else { + this.targetIterationCount = null; + } + }; + }; + + // src/nodes/decorator/Retry.ts + var Retry = class extends Decorator { + constructor(attributes, attempts, attemptsMin, attemptsMax, child) { + super("retry", attributes, child); + this.attempts = attempts; + this.attemptsMin = attemptsMin; + this.attemptsMax = attemptsMax; + } + targetAttemptCount = null; + currentAttemptCount = 0; + onUpdate(agent, options) { + if (this.is("mistreevous.ready" /* READY */)) { + this.child.reset(); + this.currentAttemptCount = 0; + this.setTargetAttemptCount(options); + } + if (this.canAttempt()) { + this.setState("mistreevous.running" /* RUNNING */); + if (this.child.getState() === "mistreevous.failed" /* FAILED */) { + this.child.reset(); } - case "PARALLEL": { - const node = ASTNodeFactories.PARALLEL(); - currentScope.push(node); - node.attributes = getAttributes(tokens, placeholders); - popAndCheck(tokens, "{"); - stack.push(node.children); - break; + this.child.update(agent, options); + if (this.child.getState() === "mistreevous.succeeded" /* SUCCEEDED */) { + this.setState("mistreevous.succeeded" /* SUCCEEDED */); + return; + } else if (this.child.getState() === "mistreevous.failed" /* FAILED */) { + this.currentAttemptCount += 1; } - case "LOTTO": { - const node = ASTNodeFactories.LOTTO(); - currentScope.push(node); - if (tokens[0] === "[") { - node.tickets = getArguments( - tokens, - placeholders, - (arg) => arg.type === "number" && !!arg.isInteger, - "lotto node ticket counts must be integer values" - ).map((argument) => argument.value); - } - node.attributes = getAttributes(tokens, placeholders); - popAndCheck(tokens, "{"); - stack.push(node.children); + } else { + this.setState("mistreevous.failed" /* FAILED */); + } + } + getName = () => { + if (this.attempts !== null) { + return `RETRY ${this.attempts}x`; + } else if (this.attemptsMin !== null && this.attemptsMax !== null) { + return `RETRY ${this.attemptsMin}x-${this.attemptsMax}x`; + } else { + return "RETRY"; + } + }; + reset = () => { + this.setState("mistreevous.ready" /* READY */); + this.currentAttemptCount = 0; + this.child.reset(); + }; + canAttempt = () => { + if (this.targetAttemptCount !== null) { + return this.currentAttemptCount < this.targetAttemptCount; + } + return true; + }; + setTargetAttemptCount = (options) => { + if (this.attempts !== null) { + this.targetAttemptCount = this.attempts; + } else if (this.attemptsMin !== null && this.attemptsMax !== null) { + const random = typeof options.random === "function" ? options.random : Math.random; + this.targetAttemptCount = Math.floor( + random() * (this.attemptsMax - this.attemptsMin + 1) + this.attemptsMin + ); + } else { + this.targetAttemptCount = null; + } + }; + }; + + // src/nodes/decorator/Flip.ts + var Flip = class extends Decorator { + constructor(attributes, child) { + super("flip", attributes, child); + } + onUpdate(agent, options) { + if (this.child.getState() === "mistreevous.ready" /* READY */ || this.child.getState() === "mistreevous.running" /* RUNNING */) { + this.child.update(agent, options); + } + switch (this.child.getState()) { + case "mistreevous.running" /* RUNNING */: + this.setState("mistreevous.running" /* RUNNING */); break; - } - case "CONDITION": { - const node = ASTNodeFactories.CONDITION(); - currentScope.push(node); - if (tokens[0] !== "[") { - throw new Error("expected condition name identifier argument"); - } - const conditionArguments = getArguments(tokens, placeholders); - if (conditionArguments.length && conditionArguments[0].type === "identifier") { - node.conditionName = conditionArguments.shift().value; - } else { - throw new Error("expected condition name identifier argument"); - } - conditionArguments.filter((arg) => arg.type === "identifier").forEach((arg) => { - throw new Error( - "invalid condition node argument value '" + arg.value + "', must be string, number, boolean or null" - ); - }); - node.conditionArguments = conditionArguments; - node.attributes = getAttributes(tokens, placeholders); + case "mistreevous.succeeded" /* SUCCEEDED */: + this.setState("mistreevous.failed" /* FAILED */); break; - } - case "FLIP": { - const node = ASTNodeFactories.FLIP(); - currentScope.push(node); - node.attributes = getAttributes(tokens, placeholders); - popAndCheck(tokens, "{"); - stack.push(node.children); + case "mistreevous.failed" /* FAILED */: + this.setState("mistreevous.succeeded" /* SUCCEEDED */); break; - } - case "SUCCEED": { - const node = ASTNodeFactories.SUCCEED(); - currentScope.push(node); - node.attributes = getAttributes(tokens, placeholders); - popAndCheck(tokens, "{"); - stack.push(node.children); + default: + this.setState("mistreevous.ready" /* READY */); + } + } + getName = () => "FLIP"; + }; + + // src/nodes/decorator/Succeed.ts + var Succeed = class extends Decorator { + constructor(attributes, child) { + super("succeed", attributes, child); + } + onUpdate(agent, options) { + if (this.child.getState() === "mistreevous.ready" /* READY */ || this.child.getState() === "mistreevous.running" /* RUNNING */) { + this.child.update(agent, options); + } + switch (this.child.getState()) { + case "mistreevous.running" /* RUNNING */: + this.setState("mistreevous.running" /* RUNNING */); break; - } - case "FAIL": { - const node = ASTNodeFactories.FAIL(); - currentScope.push(node); - node.attributes = getAttributes(tokens, placeholders); - popAndCheck(tokens, "{"); - stack.push(node.children); + case "mistreevous.succeeded" /* SUCCEEDED */: + case "mistreevous.failed" /* FAILED */: + this.setState("mistreevous.succeeded" /* SUCCEEDED */); break; - } - case "WAIT": { - const node = ASTNodeFactories.WAIT(); - currentScope.push(node); - if (tokens[0] === "[") { - const nodeArguments = getArguments( - tokens, - placeholders, - (arg) => arg.type === "number" && !!arg.isInteger, - "wait node durations must be integer values" - ).map((argument) => argument.value); - if (nodeArguments.length === 1) { - node.duration = nodeArguments[0]; - } else if (nodeArguments.length === 2) { - node.durationMin = nodeArguments[0]; - node.durationMax = nodeArguments[1]; - } else if (nodeArguments.length > 2) { - throw new Error("invalid number of wait node duration arguments defined"); - } - } - node.attributes = getAttributes(tokens, placeholders); + default: + this.setState("mistreevous.ready" /* READY */); + } + } + getName = () => "SUCCEED"; + }; + + // src/nodes/decorator/Fail.ts + var Fail = class extends Decorator { + constructor(attributes, child) { + super("fail", attributes, child); + } + onUpdate(agent, options) { + if (this.child.getState() === "mistreevous.ready" /* READY */ || this.child.getState() === "mistreevous.running" /* RUNNING */) { + this.child.update(agent, options); + } + switch (this.child.getState()) { + case "mistreevous.running" /* RUNNING */: + this.setState("mistreevous.running" /* RUNNING */); break; - } - case "REPEAT": { - const node = ASTNodeFactories.REPEAT(); - currentScope.push(node); - if (tokens[0] === "[") { - const nodeArguments = getArguments( - tokens, - placeholders, - (arg) => arg.type === "number" && !!arg.isInteger, - "repeat node iteration counts must be integer values" - ).map((argument) => argument.value); - if (nodeArguments.length === 1) { - node.iterations = nodeArguments[0]; - } else if (nodeArguments.length === 2) { - node.iterationsMin = nodeArguments[0]; - node.iterationsMax = nodeArguments[1]; - } else { - throw new Error("invalid number of repeat node iteration count arguments defined"); - } - } - node.attributes = getAttributes(tokens, placeholders); - popAndCheck(tokens, "{"); - stack.push(node.children); + case "mistreevous.succeeded" /* SUCCEEDED */: + case "mistreevous.failed" /* FAILED */: + this.setState("mistreevous.failed" /* FAILED */); break; + default: + this.setState("mistreevous.ready" /* READY */); + } + } + getName = () => "FAIL"; + }; + + // src/nodes/composite/Lotto.ts + var import_lotto_draw = __toESM(require_dist()); + + // src/nodes/composite/Composite.ts + var Composite = class extends Node { + constructor(type, attributes, children) { + super(type, attributes, []); + this.children = children; + } + isLeafNode = () => false; + getChildren = () => this.children; + reset = () => { + this.setState("mistreevous.ready" /* READY */); + this.getChildren().forEach((child) => child.reset()); + }; + abort = (agent) => { + if (!this.is("mistreevous.running" /* RUNNING */)) { + return; + } + this.getChildren().forEach((child) => child.abort(agent)); + this.reset(); + this.getAttribute("exit")?.callAgentFunction(agent, false, true); + }; + }; + + // src/nodes/composite/Lotto.ts + var Lotto = class extends Composite { + constructor(attributes, tickets, children) { + super("lotto", attributes, children); + this.tickets = tickets; + } + selectedChild; + onUpdate(agent, options) { + if (this.is("mistreevous.ready" /* READY */)) { + const lottoDraw = (0, import_lotto_draw.default)({ + random: options.random, + participants: this.children.map((child, index) => [child, this.tickets[index] || 1]) + }); + this.selectedChild = lottoDraw.draw() || void 0; + } + if (!this.selectedChild) { + throw new Error("failed to update lotto node as it has no active child"); + } + if (this.selectedChild.getState() === "mistreevous.ready" /* READY */ || this.selectedChild.getState() === "mistreevous.running" /* RUNNING */) { + this.selectedChild.update(agent, options); + } + this.setState(this.selectedChild.getState()); + } + getName = () => this.tickets.length ? `LOTTO [${this.tickets.join(",")}]` : "LOTTO"; + }; + + // src/nodes/composite/Selector.ts + var Selector = class extends Composite { + constructor(attributes, children) { + super("selector", attributes, children); + this.children = children; + } + onUpdate(agent, options) { + for (const child of this.children) { + if (child.getState() === "mistreevous.ready" /* READY */ || child.getState() === "mistreevous.running" /* RUNNING */) { + child.update(agent, options); } - case "RETRY": { - const node = ASTNodeFactories.RETRY(); - currentScope.push(node); - if (tokens[0] === "[") { - const nodeArguments = getArguments( - tokens, - placeholders, - (arg) => arg.type === "number" && !!arg.isInteger, - "retry node attempt counts must be integer values" - ).map((argument) => argument.value); - if (nodeArguments.length === 1) { - node.attempts = nodeArguments[0]; - } else if (nodeArguments.length === 2) { - node.attemptsMin = nodeArguments[0]; - node.attemptsMax = nodeArguments[1]; - } else { - throw new Error("invalid number of retry node attempt count arguments defined"); - } - } - node.attributes = getAttributes(tokens, placeholders); - popAndCheck(tokens, "{"); - stack.push(node.children); - break; + if (child.getState() === "mistreevous.succeeded" /* SUCCEEDED */) { + this.setState("mistreevous.succeeded" /* SUCCEEDED */); + return; } - case "ACTION": { - const node = ASTNodeFactories.ACTION(); - currentScope.push(node); - if (tokens[0] !== "[") { - throw new Error("expected action name identifier argument"); - } - const actionArguments = getArguments(tokens, placeholders); - if (actionArguments.length && actionArguments[0].type === "identifier") { - node.actionName = actionArguments.shift().value; + if (child.getState() === "mistreevous.failed" /* FAILED */) { + if (this.children.indexOf(child) === this.children.length - 1) { + this.setState("mistreevous.failed" /* FAILED */); + return; } else { - throw new Error("expected action name identifier argument"); + continue; } - actionArguments.filter((arg) => arg.type === "identifier").forEach((arg) => { - throw new Error( - "invalid action node argument value '" + arg.value + "', must be string, number, boolean or null" - ); - }); - node.actionArguments = actionArguments; - node.attributes = getAttributes(tokens, placeholders); - break; - } - case "}": { - stack.pop(); - break; } - default: { - throw new Error(`unexpected token '${token}'`); + if (child.getState() === "mistreevous.running" /* RUNNING */) { + this.setState("mistreevous.running" /* RUNNING */); + return; } + throw new Error("child node was not in an expected state."); } } - const validateASTNode = (node, depth) => { - node.validate(depth); - (node.children || []).forEach((child) => validateASTNode(child, depth + 1)); - }; - validateASTNode( - { - children: stack[0], - validate() { - if (this.children.length === 0) { - throw new Error("expected root node to have been defined"); - } - for (const definitionLevelNode of this.children) { - if (definitionLevelNode.type !== "root") { - throw new Error("expected root node at base of definition"); - } - } - if (this.children.filter((definitionLevelNode) => definitionLevelNode.name === null).length !== 1) { - throw new Error("expected single unnamed root node at base of definition to act as main root"); - } - const rootNodeNames = []; - for (const definitionLevelNode of this.children) { - if (rootNodeNames.indexOf(definitionLevelNode.name) !== -1) { - throw new Error(`multiple root nodes found with duplicate name '${definitionLevelNode.name}'`); - } else { - rootNodeNames.push(definitionLevelNode.name); - } + getName = () => "SELECTOR"; + }; + + // src/nodes/composite/Sequence.ts + var Sequence = class extends Composite { + constructor(attributes, children) { + super("sequence", attributes, children); + this.children = children; + } + onUpdate(agent, options) { + for (const child of this.children) { + if (child.getState() === "mistreevous.ready" /* READY */ || child.getState() === "mistreevous.running" /* RUNNING */) { + child.update(agent, options); + } + if (child.getState() === "mistreevous.succeeded" /* SUCCEEDED */) { + if (this.children.indexOf(child) === this.children.length - 1) { + this.setState("mistreevous.succeeded" /* SUCCEEDED */); + return; + } else { + continue; } } - }, - 0 - ); - return stack[0]; - } - function popAndCheck(tokens, expected) { - const popped = tokens.shift(); - if (popped === void 0) { - throw new Error("unexpected end of definition"); - } - if (expected !== void 0) { - var tokenMatchesExpectation = [].concat(expected).some((item) => popped.toUpperCase() === item.toUpperCase()); - if (!tokenMatchesExpectation) { - const expectationString = [].concat(expected).map((item) => "'" + item + "'").join(" or "); - throw new Error(`unexpected token found. Expected '${expectationString}' but got '${popped}'`); + if (child.getState() === "mistreevous.failed" /* FAILED */) { + this.setState("mistreevous.failed" /* FAILED */); + return; + } + if (child.getState() === "mistreevous.running" /* RUNNING */) { + this.setState("mistreevous.running" /* RUNNING */); + return; + } + throw new Error("child node was not in an expected state."); } } - return popped; - } - function getArguments(tokens, stringArgumentPlaceholders, argumentValidator, validationFailedMessage) { - const closer = popAndCheck(tokens, ["[", "("]) === "[" ? "]" : ")"; - const argumentListTokens = []; - const argumentList = []; - while (tokens.length && tokens[0] !== closer) { - argumentListTokens.push(tokens.shift()); + getName = () => "SEQUENCE"; + }; + + // src/nodes/composite/Parallel.ts + var Parallel = class extends Composite { + constructor(attributes, children) { + super("parallel", attributes, children); } - argumentListTokens.forEach((token, index) => { - const shouldBeArgumentToken = !(index & 1); - if (shouldBeArgumentToken) { - const argumentDefinition = getArgumentDefinition(token, stringArgumentPlaceholders); - if (argumentValidator && !argumentValidator(argumentDefinition)) { - throw new Error(validationFailedMessage); + onUpdate(agent, options) { + let succeededCount = 0; + let hasChildFailed = false; + for (const child of this.children) { + if (child.getState() === "mistreevous.ready" /* READY */ || child.getState() === "mistreevous.running" /* RUNNING */) { + child.update(agent, options); } - argumentList.push(argumentDefinition); - } else { - if (token !== ",") { - throw new Error(`invalid argument list, expected ',' or ']' but got '${token}'`); + if (child.getState() === "mistreevous.succeeded" /* SUCCEEDED */) { + succeededCount++; + continue; + } + if (child.getState() === "mistreevous.failed" /* FAILED */) { + hasChildFailed = true; + break; + } + if (child.getState() !== "mistreevous.running" /* RUNNING */) { + throw new Error("child node was not in an expected state."); } } - }); - popAndCheck(tokens, closer); - return argumentList; - } - function getArgumentDefinition(token, stringArgumentPlaceholders) { - if (token === "null") { + if (hasChildFailed) { + this.setState("mistreevous.failed" /* FAILED */); + for (const child of this.children) { + if (child.getState() === "mistreevous.running" /* RUNNING */) { + child.abort(agent); + } + } + } else { + this.setState(succeededCount === this.children.length ? "mistreevous.succeeded" /* SUCCEEDED */ : "mistreevous.running" /* RUNNING */); + } + } + getName = () => "PARALLEL"; + }; + + // src/attributes/Attribute.ts + var Attribute = class { + constructor(type, args) { + this.type = type; + this.args = args; + } + getType = () => this.type; + getArguments = () => this.args; + }; + + // src/attributes/guards/Guard.ts + var Guard = class extends Attribute { + constructor(type, args, condition) { + super(type, args); + this.condition = condition; + } + getCondition = () => this.condition; + isGuard = () => true; + getDetails() { return { - value: null, - type: "null" + type: this.getType(), + args: this.getArguments(), + condition: this.getCondition() }; } - if (token === "true" || token === "false") { - return { - value: token === "true", - type: "boolean" - }; + }; + + // src/attributes/guards/While.ts + var While = class extends Guard { + constructor(condition, args) { + super("while", args, condition); + } + isSatisfied = (agent) => { + const conditionFuncInvoker = Lookup.getFuncInvoker(agent, this.getCondition()); + if (conditionFuncInvoker === null) { + throw new Error( + `cannot evaluate node guard as the condition '${this.getCondition()}' function is not defined on the agent and has not been registered` + ); + } + return !!conditionFuncInvoker(this.args); + }; + }; + + // src/attributes/guards/Until.ts + var Until = class extends Guard { + constructor(condition, args) { + super("until", args, condition); + } + isSatisfied = (agent) => { + const conditionFuncInvoker = Lookup.getFuncInvoker(agent, this.getCondition()); + if (conditionFuncInvoker === null) { + throw new Error( + `cannot evaluate node guard as the condition '${this.getCondition()}' function is not defined on the agent and has not been registered` + ); + } + return !!!conditionFuncInvoker(this.args); + }; + }; + + // src/attributes/callbacks/Callback.ts + var Callback = class extends Attribute { + constructor(type, args, functionName) { + super(type, args); + this.functionName = functionName; } - if (!isNaN(token)) { + getFunctionName = () => this.functionName; + isGuard = () => false; + getDetails() { return { - value: parseFloat(token), - isInteger: parseFloat(token) === parseInt(token, 10), - type: "number" + type: this.getType(), + args: this.getArguments(), + functionName: this.getFunctionName() }; } - if (token.match(/^@@\d+@@$/g)) { - return { - value: stringArgumentPlaceholders[token].replace('\\"', '"'), - type: "string" - }; + }; + + // src/attributes/callbacks/Entry.ts + var Entry = class extends Callback { + constructor(functionName, args) { + super("entry", args, functionName); } - return { - value: token, - type: "identifier" - }; - } - function getAttributes(tokens, stringArgumentPlaceholders) { - const attributes = []; - const attributesFound = []; - let attributeFactory = AttributeFactories[(tokens[0] || "").toUpperCase()]; - while (attributeFactory) { - if (attributesFound.indexOf(tokens[0].toUpperCase()) !== -1) { - throw new Error(`duplicate attribute '${tokens[0].toUpperCase()}' found for node`); - } - attributesFound.push(tokens.shift().toUpperCase()); - const attributeArguments = getArguments(tokens, stringArgumentPlaceholders); - if (attributeArguments.length === 0 || attributeArguments[0].type !== "identifier") { - throw new Error("expected agent function name identifier argument for attribute"); - } - const attributeFunctionName = attributeArguments.shift(); - attributeArguments.filter((arg) => arg.type === "identifier").forEach((arg) => { + callAgentFunction = (agent) => { + const callbackFuncInvoker = Lookup.getFuncInvoker(agent, this.getFunctionName()); + if (callbackFuncInvoker === null) { throw new Error( - "invalid attribute argument value '" + arg.value + "', must be string, number, boolean or null" + `cannot call entry function '${this.getFunctionName()}' as is not defined on the agent and has not been registered` ); - }); - attributes.push(attributeFactory(attributeFunctionName.value, attributeArguments)); - attributeFactory = AttributeFactories[(tokens[0] || "").toUpperCase()]; - } - return attributes; - } - function substituteStringLiterals(definition) { - const placeholders = {}; - const processedDefinition = definition.replace(/\"(\\.|[^"\\])*\"/g, (match) => { - var strippedMatch = match.substring(1, match.length - 1); - var placeholder = Object.keys(placeholders).find((key) => placeholders[key] === strippedMatch); - if (!placeholder) { - placeholder = `@@${Object.keys(placeholders).length}@@`; - placeholders[placeholder] = strippedMatch; } - return placeholder; - }); - return { placeholders, processedDefinition }; - } - function parseTokensFromDefinition(definition) { - definition = definition.replace(/\(/g, " ( "); - definition = definition.replace(/\)/g, " ) "); - definition = definition.replace(/\{/g, " { "); - definition = definition.replace(/\}/g, " } "); - definition = definition.replace(/\]/g, " ] "); - definition = definition.replace(/\[/g, " [ "); - definition = definition.replace(/\,/g, " , "); - return definition.replace(/\s+/g, " ").trim().split(" "); - } + callbackFuncInvoker(this.args); + }; + }; - // src/BehaviourTree.ts - var BehaviourTree = class { - constructor(definition, agent, options = {}) { - this.agent = agent; - this.options = options; - if (typeof definition !== "string") { - throw new Error("the tree definition must be a string"); - } - if (typeof agent !== "object" || agent === null) { - throw new Error("the agent must be defined and not null"); - } - this.rootNode = BehaviourTree._createRootNode(definition); - } - rootNode; - isRunning() { - return this.rootNode.getState() === "mistreevous.running" /* RUNNING */; + // src/attributes/callbacks/Exit.ts + var Exit = class extends Callback { + constructor(functionName, args) { + super("exit", args, functionName); } - getState() { - return this.rootNode.getState(); + callAgentFunction = (agent, isSuccess, isAborted) => { + const callbackFuncInvoker = Lookup.getFuncInvoker(agent, this.getFunctionName()); + if (callbackFuncInvoker === null) { + throw new Error( + `cannot call exit function '${this.getFunctionName()}' as is not defined on the agent and has not been registered` + ); + } + callbackFuncInvoker([{ value: { succeeded: isSuccess, aborted: isAborted } }, ...this.args]); + }; + }; + + // src/attributes/callbacks/Step.ts + var Step = class extends Callback { + constructor(functionName, args) { + super("step", args, functionName); } - step() { - if (this.rootNode.getState() === "mistreevous.succeeded" /* SUCCEEDED */ || this.rootNode.getState() === "mistreevous.failed" /* FAILED */) { - this.rootNode.reset(); + callAgentFunction = (agent) => { + const callbackFuncInvoker = Lookup.getFuncInvoker(agent, this.getFunctionName()); + if (callbackFuncInvoker === null) { + throw new Error( + `cannot call step function '${this.getFunctionName()}' as is not defined on the agent and has not been registered` + ); } - try { - this.rootNode.update(this.agent, this.options); - } catch (exception) { - throw new Error(`error stepping tree: ${exception.message}`); + callbackFuncInvoker(this.args); + }; + }; + + // src/RootAstNodesBuilder.ts + var AttributeFactories = { + WHILE: (condition, attributeArguments) => new While(condition, attributeArguments), + UNTIL: (condition, attributeArguments) => new Until(condition, attributeArguments), + ENTRY: (functionName, attributeArguments) => new Entry(functionName, attributeArguments), + EXIT: (functionName, attributeArguments) => new Exit(functionName, attributeArguments), + STEP: (functionName, attributeArguments) => new Step(functionName, attributeArguments) + }; + var ASTNodeFactories = { + ROOT: () => ({ + type: "root", + attributes: [], + name: null, + children: [], + validate(depth) { + if (depth > 1) { + throw new Error("a root node cannot be the child of another node"); + } + if (this.children.length !== 1) { + throw new Error("a root node must have a single child"); + } + }, + createNodeInstance(namedRootNodeProvider, visitedBranches) { + return new Root( + this.attributes, + this.children[0].createNodeInstance(namedRootNodeProvider, visitedBranches.slice()) + ); } - } - reset() { - this.rootNode.reset(); - } - getFlattenedNodeDetails() { - const flattenedTreeNodes = []; - const processNode = (node, parentUid) => { - const guards = node.getAttributes().filter((attribute) => attribute.isGuard()).map((attribute) => attribute.getDetails()); - const callbacks = node.getAttributes().filter((attribute) => !attribute.isGuard()).map((attribute) => attribute.getDetails()); - flattenedTreeNodes.push({ - id: node.getUid(), - type: node.getType(), - caption: node.getName(), - state: node.getState(), - guards, - callbacks, - args: node.getArguments(), - parentId: parentUid - }); - if (!node.isLeafNode()) { - node.getChildren().forEach((child) => processNode(child, node.getUid())); + }), + BRANCH: () => ({ + type: "branch", + branchName: "", + validate() { + }, + createNodeInstance(namedRootNodeProvider, visitedBranches) { + const targetRootNode = namedRootNodeProvider(this.branchName); + if (visitedBranches.indexOf(this.branchName) !== -1) { + throw new Error(`circular dependency found in branch node references for branch '${this.branchName}'`); } - }; - processNode(this.rootNode, null); - return flattenedTreeNodes; - } - static register(name, value) { - if (typeof value === "function") { - Lookup.setFunc(name, value); - } else if (typeof value === "string") { - let rootASTNodes; - try { - rootASTNodes = buildRootASTNodes(value); - } catch (exception) { - throw new Error(`error registering definition: ${exception.message}`); + if (targetRootNode) { + return targetRootNode.createNodeInstance(namedRootNodeProvider, visitedBranches.concat(this.branchName)).getChildren()[0]; + } else { + throw new Error(`branch references root node '${this.branchName}' which has not been defined`); } - if (rootASTNodes.length != 1 || rootASTNodes[0].name !== null) { - throw new Error("error registering definition: expected a single unnamed root node"); + } + }), + SELECTOR: () => ({ + type: "selector", + attributes: [], + children: [], + validate() { + if (this.children.length < 1) { + throw new Error("a selector node must have at least a single child"); } - Lookup.setSubtree(name, rootASTNodes[0]); - } else { - throw new Error("unexpected value, expected string definition or function"); + }, + createNodeInstance(namedRootNodeProvider, visitedBranches) { + return new Selector( + this.attributes, + this.children.map((child) => child.createNodeInstance(namedRootNodeProvider, visitedBranches.slice())) + ); + } + }), + SEQUENCE: () => ({ + type: "sequence", + attributes: [], + children: [], + validate() { + if (this.children.length < 1) { + throw new Error("a sequence node must have at least a single child"); + } + }, + createNodeInstance(namedRootNodeProvider, visitedBranches) { + return new Sequence( + this.attributes, + this.children.map((child) => child.createNodeInstance(namedRootNodeProvider, visitedBranches.slice())) + ); } - } - static unregister(name) { - Lookup.remove(name); - } - static unregisterAll() { - Lookup.empty(); - } - static _createRootNode(definition) { - try { - } catch (exception) { - console.log(exception); + }), + PARALLEL: () => ({ + type: "parallel", + attributes: [], + children: [], + validate() { + if (this.children.length < 1) { + throw new Error("a parallel node must have at least a single child"); + } + }, + createNodeInstance(namedRootNodeProvider, visitedBranches) { + return new Parallel( + this.attributes, + this.children.map((child) => child.createNodeInstance(namedRootNodeProvider, visitedBranches.slice())) + ); } - try { - const rootASTNodes = buildRootASTNodes(definition); - const mainRootNodeKey = Symbol("__root__"); - const rootNodeMap = {}; - for (const rootASTNode of rootASTNodes) { - rootNodeMap[rootASTNode.name === null ? mainRootNodeKey : rootASTNode.name] = rootASTNode; + }), + LOTTO: () => ({ + type: "lotto", + attributes: [], + children: [], + tickets: [], + validate() { + if (this.children.length < 1) { + throw new Error("a lotto node must have at least a single child"); } - const rootNode = rootNodeMap[mainRootNodeKey].createNodeInstance( - (name) => rootNodeMap[name] ? rootNodeMap[name] : Lookup.getSubtree(name), - [] + }, + createNodeInstance(namedRootNodeProvider, visitedBranches) { + return new Lotto( + this.attributes, + this.tickets, + this.children.map((child) => child.createNodeInstance(namedRootNodeProvider, visitedBranches.slice())) ); - BehaviourTree._applyLeafNodeGuardPaths(rootNode); - return rootNode; - } catch (exception) { - throw new Error(`error parsing tree: ${exception.message}`); } - } - static _applyLeafNodeGuardPaths(rootNode) { - const nodePaths = []; - const findLeafNodes = (path, node) => { - path = path.concat(node); - if (node.isLeafNode()) { - nodePaths.push(path); + }), + REPEAT: () => ({ + type: "repeat", + attributes: [], + iterations: null, + iterationsMin: null, + iterationsMax: null, + children: [], + validate() { + if (this.children.length !== 1) { + throw new Error("a repeat node must have a single child"); + } + if (this.iterations !== null) { + if (this.iterations < 0) { + throw new Error("a repeat node must have a positive number of iterations if defined"); + } + } else if (this.iterationsMin !== null && this.iterationsMax !== null) { + if (this.iterationsMin < 0 || this.iterationsMax < 0) { + throw new Error( + "a repeat node must have a positive minimum and maximum iteration count if defined" + ); + } + if (this.iterationsMin > this.iterationsMax) { + throw new Error( + "a repeat node must not have a minimum iteration count that exceeds the maximum iteration count" + ); + } } else { - node.getChildren().forEach((child) => findLeafNodes(path, child)); } - }; - findLeafNodes([], rootNode); - nodePaths.forEach((path) => { - for (let depth = 0; depth < path.length; depth++) { - const currentNode = path[depth]; - if (currentNode.hasGuardPath()) { - continue; + }, + createNodeInstance(namedRootNodeProvider, visitedBranches) { + return new Repeat( + this.attributes, + this.iterations, + this.iterationsMin, + this.iterationsMax, + this.children[0].createNodeInstance(namedRootNodeProvider, visitedBranches.slice()) + ); + } + }), + RETRY: () => ({ + type: "retry", + attributes: [], + attempts: null, + attemptsMin: null, + attemptsMax: null, + children: [], + validate() { + if (this.children.length !== 1) { + throw new Error("a retry node must have a single child"); + } + if (this.attempts !== null) { + if (this.attempts < 0) { + throw new Error("a retry node must have a positive number of attempts if defined"); } - const guardPath = new GuardPath( - path.slice(0, depth + 1).map((node) => ({ node, guards: node.getGuardAttributes() })).filter((details) => details.guards.length > 0) - ); - currentNode.setGuardPath(guardPath); + } else if (this.attemptsMin !== null && this.attemptsMax !== null) { + if (this.attemptsMin < 0 || this.attemptsMax < 0) { + throw new Error("a retry node must have a positive minimum and maximum attempt count if defined"); + } + if (this.attemptsMin > this.attemptsMax) { + throw new Error( + "a retry node must not have a minimum attempt count that exceeds the maximum attempt count" + ); + } + } else { } - }); - } - }; - - // src/mdsl/MDSLUtilities.ts - function isRootNode(node) { - return node.type === "root"; - } - function isLeafNode(node) { - return ["branch", "action", "condition", "wait"].includes(node.type); - } - function isDecoratorNode(node) { - return ["root", "repeat", "retry", "flip", "succeed", "fail"].includes(node.type); - } - function isCompositeNode(node) { - return ["sequence", "selector", "lotto", "parallel"].includes(node.type); - } - function popAndCheck2(tokens, expected) { - const popped = tokens.shift(); - if (popped === void 0) { - throw new Error("unexpected end of definition"); - } - if (expected != void 0) { - const expectedValues = typeof expected === "string" ? [expected] : expected; - var tokenMatchesExpectation = expectedValues.some((item) => popped.toUpperCase() === item.toUpperCase()); - if (!tokenMatchesExpectation) { - const expectationString = expectedValues.map((item) => "'" + item + "'").join(" or "); - throw new Error("unexpected token found. Expected " + expectationString + " but got '" + popped + "'"); + }, + createNodeInstance(namedRootNodeProvider, visitedBranches) { + return new Retry( + this.attributes, + this.attempts, + this.attemptsMin, + this.attemptsMax, + this.children[0].createNodeInstance(namedRootNodeProvider, visitedBranches.slice()) + ); } - } - return popped; - } - function substituteStringLiterals2(definition) { - const placeholders = {}; - const processedDefinition = definition.replace(/\"(\\.|[^"\\])*\"/g, (match) => { - var strippedMatch = match.substring(1, match.length - 1); - var placeholder = Object.keys(placeholders).find((key) => placeholders[key] === strippedMatch); - if (!placeholder) { - placeholder = `@@${Object.keys(placeholders).length}@@`; - placeholders[placeholder] = strippedMatch; + }), + FLIP: () => ({ + type: "flip", + attributes: [], + children: [], + validate() { + if (this.children.length !== 1) { + throw new Error("a flip node must have a single child"); + } + }, + createNodeInstance(namedRootNodeProvider, visitedBranches) { + return new Flip( + this.attributes, + this.children[0].createNodeInstance(namedRootNodeProvider, visitedBranches.slice()) + ); } - return placeholder; - }); - return { placeholders, processedDefinition }; - } - function parseTokensFromDefinition2(definition) { - definition = definition.replace(/\(/g, " ( "); - definition = definition.replace(/\)/g, " ) "); - definition = definition.replace(/\{/g, " { "); - definition = definition.replace(/\}/g, " } "); - definition = definition.replace(/\]/g, " ] "); - definition = definition.replace(/\[/g, " [ "); - definition = definition.replace(/\,/g, " , "); - return definition.replace(/\s+/g, " ").trim().split(" "); - } - - // src/mdsl/MDSLNodeArgumentParser.ts - function parseArgumentTokens(tokens, stringArgumentPlaceholders) { - const argumentList = []; - if (!["[", "("].includes(tokens[0])) { - return argumentList; - } - const closingToken = popAndCheck2(tokens, ["[", "("]) === "[" ? "]" : ")"; - const argumentListTokens = []; - while (tokens.length && tokens[0] !== closingToken) { - argumentListTokens.push(tokens.shift()); - } - argumentListTokens.forEach((token, index) => { - const shouldBeArgumentToken = !(index & 1); - if (shouldBeArgumentToken) { - const argumentDefinition = getArgumentDefinition2(token, stringArgumentPlaceholders); - argumentList.push(argumentDefinition); - } else { - if (token !== ",") { - throw new Error(`invalid argument list, expected ',' or ']' but got '${token}'`); + }), + SUCCEED: () => ({ + type: "succeed", + attributes: [], + children: [], + validate() { + if (this.children.length !== 1) { + throw new Error("a succeed node must have a single child"); + } + }, + createNodeInstance(namedRootNodeProvider, visitedBranches) { + return new Succeed( + this.attributes, + this.children[0].createNodeInstance(namedRootNodeProvider, visitedBranches.slice()) + ); + } + }), + FAIL: () => ({ + type: "fail", + attributes: [], + children: [], + validate() { + if (this.children.length !== 1) { + throw new Error("a fail node must have a single child"); } + }, + createNodeInstance(namedRootNodeProvider, visitedBranches) { + return new Fail( + this.attributes, + this.children[0].createNodeInstance(namedRootNodeProvider, visitedBranches.slice()) + ); } - }); - popAndCheck2(tokens, closingToken); - return argumentList; - } - function getArgumentDefinition2(token, stringArgumentPlaceholders) { - if (token === "null") { - return { - value: null, - type: "null" - }; - } - if (token === "true" || token === "false") { - return { - value: token === "true", - type: "boolean" - }; - } - if (!isNaN(token)) { - return { - value: parseFloat(token), - isInteger: parseFloat(token) === parseInt(token, 10), - type: "number" - }; - } - if (token.match(/^@@\d+@@$/g)) { - return { - value: stringArgumentPlaceholders[token].replace('\\"', '"'), - type: "string" - }; - } - return { - value: token, - type: "identifier" - }; - } - - // src/mdsl/MDSLNodeAttributeParser.ts - function parseAttributeTokens(tokens, stringArgumentPlaceholders) { - const nodeAttributeNames = ["while", "until", "entry", "exit", "step"]; - const attributes = {}; - let nextAttributeName = tokens[0]?.toLowerCase(); - while (nodeAttributeNames.includes(nextAttributeName)) { - if (attributes[nextAttributeName]) { - throw new Error(`duplicate attribute '${tokens[0].toUpperCase()}' found for node`); + }), + WAIT: () => ({ + type: "wait", + attributes: [], + duration: null, + durationMin: null, + durationMax: null, + validate() { + if (this.duration !== null) { + if (this.duration < 0) { + throw new Error("a wait node must have a positive duration"); + } + } else if (this.durationMin !== null && this.durationMax !== null) { + if (this.durationMin < 0 || this.durationMax < 0) { + throw new Error("a wait node must have a positive minimum and maximum duration"); + } + if (this.durationMin > this.durationMax) { + throw new Error("a wait node must not have a minimum duration that exceeds the maximum duration"); + } + } else { + } + }, + createNodeInstance() { + return new Wait(this.attributes, this.duration, this.durationMin, this.durationMax); } - tokens.shift(); - const [attributeCallIdentifier, ...attributeArguments] = parseArgumentTokens( - tokens, - stringArgumentPlaceholders - ); - if (attributeCallIdentifier?.type !== "identifier") { - throw new Error("expected agent function name identifier argument for attribute"); + }), + ACTION: () => ({ + type: "action", + attributes: [], + actionName: "", + actionArguments: [], + validate() { + }, + createNodeInstance() { + return new Action(this.attributes, this.actionName, this.actionArguments); } - attributeArguments.filter((arg) => arg.type === "identifier").forEach((arg) => { - throw new Error( - `invalid attribute argument value '${arg.value}', must be string, number, boolean or null` - ); - }); - attributes[nextAttributeName] = { - call: attributeCallIdentifier.value, - args: attributeArguments.map(({ value }) => value) - }; - nextAttributeName = tokens[0]?.toLowerCase(); - } - return attributes; - } - - // src/mdsl/MDSLDefinitionParser.ts - function parseMDSLToJSON(definition) { + }), + CONDITION: () => ({ + type: "condition", + attributes: [], + conditionName: "", + conditionArguments: [], + validate() { + }, + createNodeInstance() { + return new Condition(this.attributes, this.conditionName, this.conditionArguments); + } + }) + }; + function buildRootASTNodes(definition) { const { placeholders, processedDefinition } = substituteStringLiterals2(definition); const tokens = parseTokensFromDefinition2(processedDefinition); - return convertTokensToJSONDefinition(tokens, placeholders); - } - function convertTokensToJSONDefinition(tokens, stringLiteralPlaceholders) { if (tokens.length < 3) { throw new Error("invalid token count"); } if (tokens.filter((token) => token === "{").length !== tokens.filter((token) => token === "}").length) { throw new Error("scope character mismatch"); } - const treeStacks = []; - const rootNodes = []; - const pushNode = (node) => { - if (isRootNode(node)) { - rootNodes.push(node); - treeStacks.push([node]); - return; - } - if (!treeStacks.length || !treeStacks[treeStacks.length - 1].length) { - throw new Error("expected root node at base of definition"); - } - const topTreeStack = treeStacks[treeStacks.length - 1]; - const topTreeStackTopNode = topTreeStack[topTreeStack.length - 1]; - if (isCompositeNode(topTreeStackTopNode)) { - topTreeStackTopNode.children = topTreeStackTopNode.children || []; - topTreeStackTopNode.children.push(node); - } else if (isDecoratorNode(topTreeStackTopNode)) { - if (topTreeStackTopNode.child) { - throw new Error("a decorator node must only have a single child node"); - } - topTreeStackTopNode.child = node; - } - if (!isLeafNode(node)) { - topTreeStack.push(node); - } - }; - const popNode = () => { - const topTreeStack = treeStacks[treeStacks.length - 1]; - if (topTreeStack.length) { - topTreeStack.pop(); - } - if (!topTreeStack.length) { - treeStacks.pop(); - } - }; + const stack = [[]]; + const rootScope = stack[0]; while (tokens.length) { const token = tokens.shift(); + const currentScope = stack[stack.length - 1]; switch (token.toUpperCase()) { case "ROOT": { - pushNode(createRootNode(tokens, stringLiteralPlaceholders)); + const node = ASTNodeFactories.ROOT(); + rootScope.push(node); + if (tokens[0] === "[") { + const rootArguments = getArguments(tokens, placeholders); + if (rootArguments.length === 1 && rootArguments[0].type === "identifier") { + node.name = rootArguments[0].value; + } else { + throw new Error("expected single root name argument"); + } + } + node.attributes = getAttributes(tokens, placeholders); + popAndCheck2(tokens, "{"); + stack.push(node.children); break; } - case "SUCCEED": { - pushNode(createSucceedNode(tokens, stringLiteralPlaceholders)); + case "BRANCH": { + const node = ASTNodeFactories.BRANCH(); + currentScope.push(node); + if (tokens[0] !== "[") { + throw new Error("expected single branch name argument"); + } + const branchArguments = getArguments(tokens, placeholders); + if (branchArguments.length === 1 && branchArguments[0].type === "identifier") { + node.branchName = branchArguments[0].value; + } else { + throw new Error("expected single branch name argument"); + } break; } - case "FAIL": { - pushNode(createFailNode(tokens, stringLiteralPlaceholders)); + case "SELECTOR": { + const node = ASTNodeFactories.SELECTOR(); + currentScope.push(node); + node.attributes = getAttributes(tokens, placeholders); + popAndCheck2(tokens, "{"); + stack.push(node.children); break; } - case "FLIP": { - pushNode(createFlipNode(tokens, stringLiteralPlaceholders)); + case "SEQUENCE": { + const node = ASTNodeFactories.SEQUENCE(); + currentScope.push(node); + node.attributes = getAttributes(tokens, placeholders); + popAndCheck2(tokens, "{"); + stack.push(node.children); break; } - case "REPEAT": { - pushNode(createRepeatNode(tokens, stringLiteralPlaceholders)); + case "PARALLEL": { + const node = ASTNodeFactories.PARALLEL(); + currentScope.push(node); + node.attributes = getAttributes(tokens, placeholders); + popAndCheck2(tokens, "{"); + stack.push(node.children); break; } - case "RETRY": { - pushNode(createRetryNode(tokens, stringLiteralPlaceholders)); + case "LOTTO": { + const node = ASTNodeFactories.LOTTO(); + currentScope.push(node); + if (tokens[0] === "[") { + node.tickets = getArguments( + tokens, + placeholders, + (arg) => arg.type === "number" && !!arg.isInteger, + "lotto node ticket counts must be integer values" + ).map((argument) => argument.value); + } + node.attributes = getAttributes(tokens, placeholders); + popAndCheck2(tokens, "{"); + stack.push(node.children); break; } - case "SEQUENCE": { - pushNode(createSequenceNode(tokens, stringLiteralPlaceholders)); + case "CONDITION": { + const node = ASTNodeFactories.CONDITION(); + currentScope.push(node); + if (tokens[0] !== "[") { + throw new Error("expected condition name identifier argument"); + } + const conditionArguments = getArguments(tokens, placeholders); + if (conditionArguments.length && conditionArguments[0].type === "identifier") { + node.conditionName = conditionArguments.shift().value; + } else { + throw new Error("expected condition name identifier argument"); + } + conditionArguments.filter((arg) => arg.type === "identifier").forEach((arg) => { + throw new Error( + "invalid condition node argument value '" + arg.value + "', must be string, number, boolean or null" + ); + }); + node.conditionArguments = conditionArguments; + node.attributes = getAttributes(tokens, placeholders); break; } - case "SELECTOR": { - pushNode(createSelectorNode(tokens, stringLiteralPlaceholders)); + case "FLIP": { + const node = ASTNodeFactories.FLIP(); + currentScope.push(node); + node.attributes = getAttributes(tokens, placeholders); + popAndCheck2(tokens, "{"); + stack.push(node.children); break; } - case "PARALLEL": { - pushNode(createParallelNode(tokens, stringLiteralPlaceholders)); + case "SUCCEED": { + const node = ASTNodeFactories.SUCCEED(); + currentScope.push(node); + node.attributes = getAttributes(tokens, placeholders); + popAndCheck2(tokens, "{"); + stack.push(node.children); break; } - case "LOTTO": { - pushNode(createLottoNode(tokens, stringLiteralPlaceholders)); + case "FAIL": { + const node = ASTNodeFactories.FAIL(); + currentScope.push(node); + node.attributes = getAttributes(tokens, placeholders); + popAndCheck2(tokens, "{"); + stack.push(node.children); break; } - case "ACTION": { - pushNode(createActionNode(tokens, stringLiteralPlaceholders)); + case "WAIT": { + const node = ASTNodeFactories.WAIT(); + currentScope.push(node); + if (tokens[0] === "[") { + const nodeArguments = getArguments( + tokens, + placeholders, + (arg) => arg.type === "number" && !!arg.isInteger, + "wait node durations must be integer values" + ).map((argument) => argument.value); + if (nodeArguments.length === 1) { + node.duration = nodeArguments[0]; + } else if (nodeArguments.length === 2) { + node.durationMin = nodeArguments[0]; + node.durationMax = nodeArguments[1]; + } else if (nodeArguments.length > 2) { + throw new Error("invalid number of wait node duration arguments defined"); + } + } + node.attributes = getAttributes(tokens, placeholders); break; } - case "CONDITION": { - pushNode(createConditionNode(tokens, stringLiteralPlaceholders)); + case "REPEAT": { + const node = ASTNodeFactories.REPEAT(); + currentScope.push(node); + if (tokens[0] === "[") { + const nodeArguments = getArguments( + tokens, + placeholders, + (arg) => arg.type === "number" && !!arg.isInteger, + "repeat node iteration counts must be integer values" + ).map((argument) => argument.value); + if (nodeArguments.length === 1) { + node.iterations = nodeArguments[0]; + } else if (nodeArguments.length === 2) { + node.iterationsMin = nodeArguments[0]; + node.iterationsMax = nodeArguments[1]; + } else { + throw new Error("invalid number of repeat node iteration count arguments defined"); + } + } + node.attributes = getAttributes(tokens, placeholders); + popAndCheck2(tokens, "{"); + stack.push(node.children); break; } - case "WAIT": { - pushNode(createWaitNode(tokens, stringLiteralPlaceholders)); + case "RETRY": { + const node = ASTNodeFactories.RETRY(); + currentScope.push(node); + if (tokens[0] === "[") { + const nodeArguments = getArguments( + tokens, + placeholders, + (arg) => arg.type === "number" && !!arg.isInteger, + "retry node attempt counts must be integer values" + ).map((argument) => argument.value); + if (nodeArguments.length === 1) { + node.attempts = nodeArguments[0]; + } else if (nodeArguments.length === 2) { + node.attemptsMin = nodeArguments[0]; + node.attemptsMax = nodeArguments[1]; + } else { + throw new Error("invalid number of retry node attempt count arguments defined"); + } + } + node.attributes = getAttributes(tokens, placeholders); + popAndCheck2(tokens, "{"); + stack.push(node.children); break; } - case "BRANCH": { - pushNode(createBranchNode(tokens, stringLiteralPlaceholders)); + case "ACTION": { + const node = ASTNodeFactories.ACTION(); + currentScope.push(node); + if (tokens[0] !== "[") { + throw new Error("expected action name identifier argument"); + } + const actionArguments = getArguments(tokens, placeholders); + if (actionArguments.length && actionArguments[0].type === "identifier") { + node.actionName = actionArguments.shift().value; + } else { + throw new Error("expected action name identifier argument"); + } + actionArguments.filter((arg) => arg.type === "identifier").forEach((arg) => { + throw new Error( + "invalid action node argument value '" + arg.value + "', must be string, number, boolean or null" + ); + }); + node.actionArguments = actionArguments; + node.attributes = getAttributes(tokens, placeholders); break; } case "}": { - popNode(); + stack.pop(); break; } default: { - throw new Error(`unexpected token: ${token}`); + throw new Error(`unexpected token '${token}'`); } } } - return rootNodes; - } - function createRootNode(tokens, stringLiteralPlaceholders) { - let node = { - type: "root", - id: void 0 - }; - const nodeArguments = parseArgumentTokens(tokens, stringLiteralPlaceholders); - if (nodeArguments.length) { - if (nodeArguments.length === 1 && nodeArguments[0].type === "identifier") { - node.id = nodeArguments[0].value; - } else { - throw new Error("expected single root name argument"); - } - } - node = { ...node, ...parseAttributeTokens(tokens, stringLiteralPlaceholders) }; - popAndCheck2(tokens, "{"); - return node; - } - function createSucceedNode(tokens, stringLiteralPlaceholders) { - const node = { - type: "succeed", - ...parseAttributeTokens(tokens, stringLiteralPlaceholders) - }; - popAndCheck2(tokens, "{"); - return node; - } - function createFailNode(tokens, stringLiteralPlaceholders) { - const node = { - type: "fail", - ...parseAttributeTokens(tokens, stringLiteralPlaceholders) - }; - popAndCheck2(tokens, "{"); - return node; - } - function createFlipNode(tokens, stringLiteralPlaceholders) { - const node = { - type: "flip", - ...parseAttributeTokens(tokens, stringLiteralPlaceholders) + const validateASTNode = (node, depth) => { + node.validate(depth); + (node.children || []).forEach((child) => validateASTNode(child, depth + 1)); }; - popAndCheck2(tokens, "{"); - return node; + validateASTNode( + { + children: stack[0], + validate() { + if (this.children.length === 0) { + throw new Error("expected root node to have been defined"); + } + for (const definitionLevelNode of this.children) { + if (definitionLevelNode.type !== "root") { + throw new Error("expected root node at base of definition"); + } + } + if (this.children.filter((definitionLevelNode) => definitionLevelNode.name === null).length !== 1) { + throw new Error("expected single unnamed root node at base of definition to act as main root"); + } + const rootNodeNames = []; + for (const definitionLevelNode of this.children) { + if (rootNodeNames.indexOf(definitionLevelNode.name) !== -1) { + throw new Error(`multiple root nodes found with duplicate name '${definitionLevelNode.name}'`); + } else { + rootNodeNames.push(definitionLevelNode.name); + } + } + } + }, + 0 + ); + return stack[0]; } - function createRepeatNode(tokens, stringLiteralPlaceholders) { - let node = { type: "repeat" }; - const nodeArguments = parseArgumentTokens(tokens, stringLiteralPlaceholders); - if (nodeArguments.length) { - nodeArguments.filter((arg) => arg.type !== "number" || !arg.isInteger).forEach(() => { - throw new Error(`repeat node iteration counts must be integer values`); - }); - if (nodeArguments.length === 1) { - node.iterations = nodeArguments[0].value; - } else if (nodeArguments.length === 2) { - node.iterations = [nodeArguments[0].value, nodeArguments[1].value]; - } else { - throw new Error("invalid number of repeat node iteration count arguments defined"); - } + function popAndCheck2(tokens, expected) { + const popped = tokens.shift(); + if (popped === void 0) { + throw new Error("unexpected end of definition"); } - node = { ...node, ...parseAttributeTokens(tokens, stringLiteralPlaceholders) }; - popAndCheck2(tokens, "{"); - return node; - } - function createRetryNode(tokens, stringLiteralPlaceholders) { - let node = { type: "retry" }; - const nodeArguments = parseArgumentTokens(tokens, stringLiteralPlaceholders); - if (nodeArguments.length) { - nodeArguments.filter((arg) => arg.type !== "number" || !arg.isInteger).forEach(() => { - throw new Error(`retry node attempt counts must be integer values`); - }); - if (nodeArguments.length === 1) { - node.attempts = nodeArguments[0].value; - } else if (nodeArguments.length === 2) { - node.attempts = [nodeArguments[0].value, nodeArguments[1].value]; - } else { - throw new Error("invalid number of retry node attempt count arguments defined"); + if (expected !== void 0) { + var tokenMatchesExpectation = [].concat(expected).some((item) => popped.toUpperCase() === item.toUpperCase()); + if (!tokenMatchesExpectation) { + const expectationString = [].concat(expected).map((item) => "'" + item + "'").join(" or "); + throw new Error(`unexpected token found. Expected '${expectationString}' but got '${popped}'`); } } - node = { ...node, ...parseAttributeTokens(tokens, stringLiteralPlaceholders) }; - popAndCheck2(tokens, "{"); - return node; - } - function createSequenceNode(tokens, stringLiteralPlaceholders) { - const node = { - type: "sequence", - ...parseAttributeTokens(tokens, stringLiteralPlaceholders) - }; - popAndCheck2(tokens, "{"); - return node; - } - function createSelectorNode(tokens, stringLiteralPlaceholders) { - const node = { - type: "selector", - ...parseAttributeTokens(tokens, stringLiteralPlaceholders) - }; - popAndCheck2(tokens, "{"); - return node; - } - function createParallelNode(tokens, stringLiteralPlaceholders) { - const node = { - type: "parallel", - ...parseAttributeTokens(tokens, stringLiteralPlaceholders) - }; - popAndCheck2(tokens, "{"); - return node; + return popped; } - function createLottoNode(tokens, stringLiteralPlaceholders) { - const nodeArguments = parseArgumentTokens(tokens, stringLiteralPlaceholders); - nodeArguments.filter((arg) => arg.type !== "number" || !arg.isInteger).forEach(() => { - throw new Error(`lotto node weight arguments must be integer values`); + function getArguments(tokens, stringArgumentPlaceholders, argumentValidator, validationFailedMessage) { + const closer = popAndCheck2(tokens, ["[", "("]) === "[" ? "]" : ")"; + const argumentListTokens = []; + const argumentList = []; + while (tokens.length && tokens[0] !== closer) { + argumentListTokens.push(tokens.shift()); + } + argumentListTokens.forEach((token, index) => { + const shouldBeArgumentToken = !(index & 1); + if (shouldBeArgumentToken) { + const argumentDefinition = getArgumentDefinition2(token, stringArgumentPlaceholders); + if (argumentValidator && !argumentValidator(argumentDefinition)) { + throw new Error(validationFailedMessage); + } + argumentList.push(argumentDefinition); + } else { + if (token !== ",") { + throw new Error(`invalid argument list, expected ',' or ']' but got '${token}'`); + } + } }); - const node = { - type: "lotto", - weights: nodeArguments.map(({ value }) => value), - ...parseAttributeTokens(tokens, stringLiteralPlaceholders) - }; - popAndCheck2(tokens, "{"); - return node; + popAndCheck2(tokens, closer); + return argumentList; } - function createActionNode(tokens, stringLiteralPlaceholders) { - const [actionNameIdentifier, ...agentFunctionArgs] = parseArgumentTokens(tokens, stringLiteralPlaceholders); - if (actionNameIdentifier?.type !== "identifier") { - throw new Error("expected action name identifier argument"); + function getArgumentDefinition2(token, stringArgumentPlaceholders) { + if (token === "null") { + return { + value: null, + type: "null" + }; + } + if (token === "true" || token === "false") { + return { + value: token === "true", + type: "boolean" + }; + } + if (!isNaN(token)) { + return { + value: parseFloat(token), + isInteger: parseFloat(token) === parseInt(token, 10), + type: "number" + }; + } + if (token.match(/^@@\d+@@$/g)) { + return { + value: stringArgumentPlaceholders[token].replace('\\"', '"'), + type: "string" + }; } - agentFunctionArgs.filter((arg) => arg.type === "identifier").forEach((arg) => { - throw new Error( - `invalid action node argument value '${arg.value}', must be string, number, boolean or null` - ); - }); return { - type: "action", - call: actionNameIdentifier.value, - args: agentFunctionArgs.map(({ value }) => value), - ...parseAttributeTokens(tokens, stringLiteralPlaceholders) + value: token, + type: "identifier" }; } - function createConditionNode(tokens, stringLiteralPlaceholders) { - const [conditionNameIdentifier, ...agentFunctionArgs] = parseArgumentTokens(tokens, stringLiteralPlaceholders); - if (conditionNameIdentifier?.type !== "identifier") { - throw new Error("expected condition name identifier argument"); + function getAttributes(tokens, stringArgumentPlaceholders) { + const attributes = []; + const attributesFound = []; + let attributeFactory = AttributeFactories[(tokens[0] || "").toUpperCase()]; + while (attributeFactory) { + if (attributesFound.indexOf(tokens[0].toUpperCase()) !== -1) { + throw new Error(`duplicate attribute '${tokens[0].toUpperCase()}' found for node`); + } + attributesFound.push(tokens.shift().toUpperCase()); + const attributeArguments = getArguments(tokens, stringArgumentPlaceholders); + if (attributeArguments.length === 0 || attributeArguments[0].type !== "identifier") { + throw new Error("expected agent function name identifier argument for attribute"); + } + const attributeFunctionName = attributeArguments.shift(); + attributeArguments.filter((arg) => arg.type === "identifier").forEach((arg) => { + throw new Error( + "invalid attribute argument value '" + arg.value + "', must be string, number, boolean or null" + ); + }); + attributes.push(attributeFactory(attributeFunctionName.value, attributeArguments)); + attributeFactory = AttributeFactories[(tokens[0] || "").toUpperCase()]; } - agentFunctionArgs.filter((arg) => arg.type === "identifier").forEach((arg) => { - throw new Error( - `invalid condition node argument value '${arg.value}', must be string, number, boolean or null` - ); + return attributes; + } + function substituteStringLiterals2(definition) { + const placeholders = {}; + const processedDefinition = definition.replace(/\"(\\.|[^"\\])*\"/g, (match) => { + var strippedMatch = match.substring(1, match.length - 1); + var placeholder = Object.keys(placeholders).find((key) => placeholders[key] === strippedMatch); + if (!placeholder) { + placeholder = `@@${Object.keys(placeholders).length}@@`; + placeholders[placeholder] = strippedMatch; + } + return placeholder; }); - return { - type: "condition", - call: conditionNameIdentifier.value, - args: agentFunctionArgs.map(({ value }) => value), - ...parseAttributeTokens(tokens, stringLiteralPlaceholders) - }; + return { placeholders, processedDefinition }; } - function createWaitNode(tokens, stringLiteralPlaceholders) { - let node = { type: "wait" }; - const nodeArguments = parseArgumentTokens(tokens, stringLiteralPlaceholders); - if (nodeArguments.length) { - nodeArguments.filter((arg) => arg.type !== "number" || !arg.isInteger).forEach(() => { - throw new Error(`wait node duration arguments must be integer values`); - }); - if (nodeArguments.length === 1) { - node.duration = nodeArguments[0].value; - } else if (nodeArguments.length === 2) { - node.duration = [nodeArguments[0].value, nodeArguments[1].value]; - } else if (nodeArguments.length > 2) { - throw new Error("invalid number of wait node duration arguments defined"); + function parseTokensFromDefinition2(definition) { + definition = definition.replace(/\(/g, " ( "); + definition = definition.replace(/\)/g, " ) "); + definition = definition.replace(/\{/g, " { "); + definition = definition.replace(/\}/g, " } "); + definition = definition.replace(/\]/g, " ] "); + definition = definition.replace(/\[/g, " [ "); + definition = definition.replace(/\,/g, " , "); + return definition.replace(/\s+/g, " ").trim().split(" "); + } + + // src/BehaviourTree.ts + var BehaviourTree = class { + constructor(definition, agent, options = {}) { + this.agent = agent; + this.options = options; + if (typeof definition !== "string") { + throw new Error("the tree definition must be a string"); } + if (typeof agent !== "object" || agent === null) { + throw new Error("the agent must be defined and not null"); + } + this.rootNode = BehaviourTree._createRootNode(definition); } - return { ...node, ...parseAttributeTokens(tokens, stringLiteralPlaceholders) }; - } - function createBranchNode(tokens, stringLiteralPlaceholders) { - const nodeArguments = parseArgumentTokens(tokens, stringLiteralPlaceholders); - if (nodeArguments.length !== 1 || nodeArguments[0].type !== "identifier") { - throw new Error("expected single branch name argument"); + rootNode; + isRunning() { + return this.rootNode.getState() === "mistreevous.running" /* RUNNING */; } - return { type: "branch", ref: nodeArguments[0].value }; - } + getState() { + return this.rootNode.getState(); + } + step() { + if (this.rootNode.getState() === "mistreevous.succeeded" /* SUCCEEDED */ || this.rootNode.getState() === "mistreevous.failed" /* FAILED */) { + this.rootNode.reset(); + } + try { + this.rootNode.update(this.agent, this.options); + } catch (exception) { + throw new Error(`error stepping tree: ${exception.message}`); + } + } + reset() { + this.rootNode.reset(); + } + getFlattenedNodeDetails() { + const flattenedTreeNodes = []; + const processNode = (node, parentUid) => { + const guards = node.getAttributes().filter((attribute) => attribute.isGuard()).map((attribute) => attribute.getDetails()); + const callbacks = node.getAttributes().filter((attribute) => !attribute.isGuard()).map((attribute) => attribute.getDetails()); + flattenedTreeNodes.push({ + id: node.getUid(), + type: node.getType(), + caption: node.getName(), + state: node.getState(), + guards, + callbacks, + args: node.getArguments(), + parentId: parentUid + }); + if (!node.isLeafNode()) { + node.getChildren().forEach((child) => processNode(child, node.getUid())); + } + }; + processNode(this.rootNode, null); + return flattenedTreeNodes; + } + static register(name, value) { + if (typeof value === "function") { + Lookup.setFunc(name, value); + } else if (typeof value === "string") { + let rootASTNodes; + try { + rootASTNodes = buildRootASTNodes(value); + } catch (exception) { + throw new Error(`error registering definition: ${exception.message}`); + } + if (rootASTNodes.length != 1 || rootASTNodes[0].name !== null) { + throw new Error("error registering definition: expected a single unnamed root node"); + } + Lookup.setSubtree(name, rootASTNodes[0]); + } else { + throw new Error("unexpected value, expected string definition or function"); + } + } + static unregister(name) { + Lookup.remove(name); + } + static unregisterAll() { + Lookup.empty(); + } + static _createRootNode(definition) { + try { + } catch (exception) { + console.log(exception); + } + try { + const rootASTNodes = buildRootASTNodes(definition); + const mainRootNodeKey = Symbol("__root__"); + const rootNodeMap = {}; + for (const rootASTNode of rootASTNodes) { + rootNodeMap[rootASTNode.name === null ? mainRootNodeKey : rootASTNode.name] = rootASTNode; + } + const rootNode = rootNodeMap[mainRootNodeKey].createNodeInstance( + (name) => rootNodeMap[name] ? rootNodeMap[name] : Lookup.getSubtree(name), + [] + ); + BehaviourTree._applyLeafNodeGuardPaths(rootNode); + return rootNode; + } catch (exception) { + throw new Error(`error parsing tree: ${exception.message}`); + } + } + static _applyLeafNodeGuardPaths(rootNode) { + const nodePaths = []; + const findLeafNodes = (path, node) => { + path = path.concat(node); + if (node.isLeafNode()) { + nodePaths.push(path); + } else { + node.getChildren().forEach((child) => findLeafNodes(path, child)); + } + }; + findLeafNodes([], rootNode); + nodePaths.forEach((path) => { + for (let depth = 0; depth < path.length; depth++) { + const currentNode = path[depth]; + if (currentNode.hasGuardPath()) { + continue; + } + const guardPath = new GuardPath( + path.slice(0, depth + 1).map((node) => ({ node, guards: node.getGuardAttributes() })).filter((details) => details.guards.length > 0) + ); + currentNode.setGuardPath(guardPath); + } + }); + } + }; return __toCommonJS(src_exports); })(); //# sourceMappingURL=bundle.js.map diff --git a/dist/bundle.js.map b/dist/bundle.js.map index 161ca40..e1708a1 100644 --- a/dist/bundle.js.map +++ b/dist/bundle.js.map @@ -1,7 +1,7 @@ { "version": 3, - "sources": ["../node_modules/lotto-draw/dist/Participant.js", "../node_modules/lotto-draw/dist/Utilities.js", "../node_modules/lotto-draw/dist/Lotto.js", "../node_modules/lotto-draw/dist/createLotto.js", "../node_modules/lotto-draw/dist/index.js", "../src/index.ts", "../src/attributes/guards/GuardUnsatisifedException.ts", "../src/attributes/guards/GuardPath.ts", "../src/State.ts", "../src/nodes/Node.ts", "../src/nodes/leaf/Leaf.ts", "../src/Lookup.ts", "../src/nodes/leaf/Action.ts", "../src/nodes/leaf/Condition.ts", "../src/nodes/leaf/Wait.ts", "../src/nodes/decorator/Decorator.ts", "../src/nodes/decorator/Root.ts", "../src/nodes/decorator/Repeat.ts", "../src/nodes/decorator/Retry.ts", "../src/nodes/decorator/Flip.ts", "../src/nodes/decorator/Succeed.ts", "../src/nodes/decorator/Fail.ts", "../src/nodes/composite/Lotto.ts", "../src/nodes/composite/Composite.ts", "../src/nodes/composite/Selector.ts", "../src/nodes/composite/Sequence.ts", "../src/nodes/composite/Parallel.ts", "../src/attributes/Attribute.ts", "../src/attributes/guards/Guard.ts", "../src/attributes/guards/While.ts", "../src/attributes/guards/Until.ts", "../src/attributes/callbacks/Callback.ts", "../src/attributes/callbacks/Entry.ts", "../src/attributes/callbacks/Exit.ts", "../src/attributes/callbacks/Step.ts", "../src/RootAstNodesBuilder.ts", "../src/BehaviourTree.ts", "../src/mdsl/MDSLUtilities.ts", "../src/mdsl/MDSLNodeArgumentParser.ts", "../src/mdsl/MDSLNodeAttributeParser.ts", "../src/mdsl/MDSLDefinitionParser.ts"], - "sourcesContent": ["\"use strict\";\r\nObject.defineProperty(exports, \"__esModule\", { value: true });\r\nexports.Participant = void 0;\r\n/**\r\n * A participant that holds a number of tickets.\r\n */\r\nvar Participant = /** @class */ (function () {\r\n /**\r\n * Creates an instance of the Participant class.\r\n * @param participant The actual participant.\r\n * @param tickets The number of tickets held by the participant.\r\n */\r\n function Participant(participant, tickets) {\r\n if (tickets === void 0) { tickets = 1; }\r\n this._participant = participant;\r\n this._tickets = tickets;\r\n }\r\n Object.defineProperty(Participant.prototype, \"participant\", {\r\n /** Gets the actual participant. */\r\n get: function () {\r\n return this._participant;\r\n },\r\n enumerable: false,\r\n configurable: true\r\n });\r\n Object.defineProperty(Participant.prototype, \"tickets\", {\r\n /** Gets or sets the number of tickets held by the participant. */\r\n get: function () {\r\n return this._tickets;\r\n },\r\n set: function (value) {\r\n this._tickets = value;\r\n },\r\n enumerable: false,\r\n configurable: true\r\n });\r\n return Participant;\r\n}());\r\nexports.Participant = Participant;\r\n", "\"use strict\";\r\nObject.defineProperty(exports, \"__esModule\", { value: true });\r\nexports.isNaturalNumber = exports.isNullOrUndefined = void 0;\r\n/**\r\n * Gets whether the value provided is null or undefined.\r\n * @param value The value to check.\r\n * @returns Whether the value provided is null or undefined.\r\n */\r\nfunction isNullOrUndefined(value) {\r\n return value === null || value === undefined;\r\n}\r\nexports.isNullOrUndefined = isNullOrUndefined;\r\n/**\r\n * Gets whether the value provided is a natural number.\r\n * @param value The value to check.\r\n * @returns Whether the value provided is a natural number.\r\n */\r\nfunction isNaturalNumber(value) {\r\n return typeof value === \"number\" && value >= 1 && Math.floor(value) === value;\r\n}\r\nexports.isNaturalNumber = isNaturalNumber;\r\n", "\"use strict\";\r\nObject.defineProperty(exports, \"__esModule\", { value: true });\r\nexports.Lotto = void 0;\r\nvar Participant_1 = require(\"./Participant\");\r\nvar Utilities_1 = require(\"./Utilities\");\r\n/**\r\n * Represents a lotto consisting of a number of pickable ticket-holding participants.\r\n */\r\nvar Lotto = /** @class */ (function () {\r\n /**\r\n * Creates a new instance of Lotto.\r\n * @param customRandom The custom RNG to use in place of Math.random().\r\n */\r\n function Lotto(customRandom) {\r\n /** The array of participants that are holding tickets in the lotto. */\r\n this._participants = [];\r\n this._customRandom = customRandom;\r\n }\r\n /**\r\n * Adds a participant with the specified number of tickets, or adds to the participant ticket count if the participant already holds tickets.\r\n * @param participant The participant to add or to increase the ticket count for if they already hold tickets.\r\n * @param tickets The number of tickets, defaults to 1.\r\n * @returns The Lotto instance.\r\n */\r\n Lotto.prototype.add = function (participant, tickets) {\r\n if (tickets === void 0) { tickets = 1; }\r\n // Check that we have a valid ticket count.\r\n if (!(0, Utilities_1.isNaturalNumber)(tickets)) {\r\n throw new Error(\"tickets value must be a natural number\");\r\n }\r\n // Check whether this participant has already been added.\r\n var existingParticipant = this._participants.find(function (part) { return part.participant === participant; });\r\n if (existingParticipant) {\r\n // The participant has already been added to the lotto so just add to their ticket count.\r\n existingParticipant.tickets += tickets;\r\n }\r\n else {\r\n // The participant is not part of the lotto so we should add them.\r\n this._participants.push(new Participant_1.Participant(participant, tickets));\r\n }\r\n return this;\r\n };\r\n /**\r\n * Removes the specified number of tickets for the given participant from the draw, or all tickets if a ticket number is not defined.\r\n * @param participant The participant to remove tickets for.\r\n * @param tickets The number of tickets to remove, or undefined if all tickets are to be removed.\r\n * @returns The Lotto instance.\r\n */\r\n Lotto.prototype.remove = function (participant, tickets) {\r\n // Attempt to get the existing participant.\r\n var existingParticipant = this._participants.find(function (part) { return part.participant === participant; });\r\n // There is nothing to do if the specified participant isn't even part of the lotto.\r\n if (!existingParticipant) {\r\n return this;\r\n }\r\n // Check whether a tickets value was given.\r\n if (tickets !== undefined) {\r\n // Check that we have a valid ticket count.\r\n if (!(0, Utilities_1.isNaturalNumber)(tickets)) {\r\n throw new Error(\"tickets value must be a natural number\");\r\n }\r\n existingParticipant.tickets -= tickets;\r\n // If the participant no longer holds any tickets then they should be removed.\r\n if (existingParticipant.tickets < 1) {\r\n this._participants = this._participants.filter(function (part) { return part !== existingParticipant; });\r\n }\r\n }\r\n else {\r\n // We are removing all tickets for the participant so just remove them from the lotto.\r\n this._participants = this._participants.filter(function (part) { return part !== existingParticipant; });\r\n }\r\n return this;\r\n };\r\n /**\r\n * Draw a winning ticket and return the participant that holds the ticket.\r\n * @param options The draw options.\r\n * @returns The participant that holds the winning ticket.\r\n */\r\n Lotto.prototype.draw = function (options) {\r\n if (options === void 0) { options = {}; }\r\n // If we have no participants then just return null.\r\n if (this._participants.length === 0) {\r\n return null;\r\n }\r\n var redrawable = (0, Utilities_1.isNullOrUndefined)(options.redrawable) ? true : options.redrawable;\r\n var pickable = [];\r\n this._participants.forEach(function (_a) {\r\n var participant = _a.participant, tickets = _a.tickets;\r\n for (var ticketCount = 0; ticketCount < tickets; ticketCount++) {\r\n pickable.push(participant);\r\n }\r\n });\r\n var random;\r\n // We need a random floating-point number between 0 (inclusive) and 1 to scale up to pick our winner.\r\n // If a custom random function exists then we should use that or fall back to Math.random().\r\n if (this._customRandom) {\r\n // Call our custom random function to get a random floating-point number.\r\n random = this._customRandom();\r\n // Verify that the result of calling our custom random function is a number between 0 (inclusive) and 1.\r\n if (typeof random !== \"number\" || random < 0 || random >= 1) {\r\n throw new Error(\"the 'random' function provided did not return a number between 0 (inclusive) and 1\");\r\n }\r\n }\r\n else {\r\n // No custom random function was defined so just use good ol' Math.random().\r\n random = Math.random();\r\n }\r\n // Pick a winning participant.\r\n var winner = pickable[Math.floor(random * pickable.length)];\r\n // If the ticket isn't redrawable then we should remove a ticket from the winning participants ticket count.\r\n if (!redrawable) {\r\n this.remove(winner, 1);\r\n }\r\n // Return the winning participant.\r\n return winner;\r\n };\r\n /**\r\n * Draws multiple winning tickets and return an array of the participants that hold the winning tickets.\r\n * @param tickets The number of winning tickets to draw.\r\n * @param options The draw multiple options.\r\n * @returns An array of the participants that hold the winning tickets.\r\n */\r\n Lotto.prototype.drawMultiple = function (tickets, options) {\r\n if (options === void 0) { options = {}; }\r\n var uniqueResults = (0, Utilities_1.isNullOrUndefined)(options.unique) ? false : options.unique;\r\n // Handle cases where the user has asked for zero tickets (no idea why they would do this be we should trust them).\r\n if (tickets === 0) {\r\n return [];\r\n }\r\n // Now that we know out tickets value is not zero we should check that it is a valid natural number.\r\n if (!(0, Utilities_1.isNaturalNumber)(tickets)) {\r\n throw new Error(\"tickets value must be a natural number\");\r\n }\r\n var result = [];\r\n // Keep drawing tickets until we either reach the number of required tickets or we simply run out of tickets to draw.\r\n // We can run out of tickets to draw if 'options.redrawable' is explicity 'false' or we just had no participants when 'drawMultiple' was called.\r\n while (result.length < tickets && this._participants.length > 0) {\r\n result.push(this.draw(options));\r\n }\r\n // If the 'unique' draw option is set then we need to remove duplicates from the result list.\r\n if (uniqueResults) {\r\n // Create an array to store our unique results.\r\n var unique = [];\r\n // Iterate over all of our participants (with potential duplicates) and populate our array of unique values.\r\n for (var _i = 0, result_1 = result; _i < result_1.length; _i++) {\r\n var participant = result_1[_i];\r\n if (unique.indexOf(participant) === -1) {\r\n unique.push(participant);\r\n }\r\n }\r\n result = unique;\r\n }\r\n return result;\r\n };\r\n return Lotto;\r\n}());\r\nexports.Lotto = Lotto;\r\n", "\"use strict\";\r\nObject.defineProperty(exports, \"__esModule\", { value: true });\r\nexports.createLotto = void 0;\r\nvar Lotto_1 = require(\"./Lotto\");\r\n/**\r\n * A function that creates and returns a Lotto instance.\r\n * @param participantsOrOptions An array of initial participants or options relating to the creation of a Lotto instance.\r\n * @returns A new Lotto instance.\r\n */\r\nfunction createLotto(participantsOrOptions) {\r\n // If no initial participants or lotto options were provided as an argument then we can just return a new lotto instance now.\r\n if (!participantsOrOptions) {\r\n return new Lotto_1.Lotto();\r\n }\r\n // Check whether we were provided with an array of initial participants or a lotto options object.\r\n if (Array.isArray(participantsOrOptions)) {\r\n // We are dealing with a pre-defined array of participants.\r\n var participants = participantsOrOptions;\r\n var lotto_1 = new Lotto_1.Lotto();\r\n // If the lotto participants have been defined upfront then we will need to add them all to our lotto instance now.\r\n participants.forEach(function (_a) {\r\n var participant = _a[0], tokens = _a[1];\r\n return lotto_1.add(participant, tokens);\r\n });\r\n // Return the Lotto instance.\r\n return lotto_1;\r\n }\r\n else {\r\n // We are dealing with some lotto options.\r\n var random = participantsOrOptions.random, participants = participantsOrOptions.participants;\r\n // Create a Lotto instance passing the custom RNG function to use in place of Math.random() (which could be undefined).\r\n var lotto_2 = new Lotto_1.Lotto(random);\r\n // If the lotto participants have been defined upfront as part of the options then we will need to add them all to our lotto instance now.\r\n if (participants) {\r\n participants.forEach(function (_a) {\r\n var participant = _a[0], tokens = _a[1];\r\n return lotto_2.add(participant, tokens);\r\n });\r\n }\r\n // Return the Lotto instance.\r\n return lotto_2;\r\n }\r\n}\r\nexports.createLotto = createLotto;\r\n", "\"use strict\";\r\nObject.defineProperty(exports, \"__esModule\", { value: true });\r\nvar createLotto_1 = require(\"./createLotto\");\r\nexports.default = createLotto_1.createLotto;\r\n", "import { BehaviourTree, FlattenedTreeNode } from \"./BehaviourTree\";\nimport State from \"./State\";\nimport { parseMDSLToJSON } from \"./mdsl/MDSLDefinitionParser\";\n\nexport { BehaviourTree, State, parseMDSLToJSON };\nexport type { FlattenedTreeNode };\n", "import Node from \"../../nodes/Node\";\n\n/**\n * An exception thrown when evaluating node guard path conditions and a conditions fails.\n */\nexport default class GuardUnsatisifedException extends Error {\n /**\n * @param source The node at which a guard condition failed.\n */\n constructor(private source: Node) {\n super(\"A guard path condition has failed\");\n }\n\n /**\n * Gets whether the specified node is the node at which a guard condition failed.\n * @param node The node to check against the source node.\n * @returns Whether the specified node is the node at which a guard condition failed.\n */\n isSourceNode = (node: Node) => node === this.source;\n}\n", "import { Agent } from \"../../Agent\";\nimport Guard from \"./Guard\";\nimport Node from \"../../nodes/Node\";\nimport GuardUnsatisifedException from \"./GuardUnsatisifedException\";\n\nexport type GuardPathPart = {\n node: Node;\n guards: Guard[];\n};\n\n/**\n * Represents a path of node guards along a root-to-leaf tree path.\n */\nexport default class GuardPath {\n /**\n * @param nodes An array of objects defining a node instance -> guard link, ordered by node depth.\n */\n constructor(private nodes: GuardPathPart[]) {}\n\n /**\n * Evaluate guard conditions for all guards in the tree path, moving outwards from the root.\n * @param agent The agent, required for guard evaluation.\n * @returns An evaluation results object.\n */\n evaluate = (agent: Agent) => {\n // We need to evaluate guard conditions for nodes up the tree, moving outwards from the root.\n for (const details of this.nodes) {\n // There can be multiple guards per node.\n for (const guard of details.guards) {\n // Check whether the guard condition passes, and throw an exception if not.\n if (!guard.isSatisfied(agent)) {\n throw new GuardUnsatisifedException(details.node);\n }\n }\n }\n };\n}\n", "/**\n * Enumeration of node state types.\n */\nexport enum State {\n READY = \"mistreevous.ready\",\n RUNNING = \"mistreevous.running\",\n SUCCEEDED = \"mistreevous.succeeded\",\n FAILED = \"mistreevous.failed\"\n}\n\nexport { State as default };\n\nexport type CompleteState = State.SUCCEEDED | State.FAILED;\nexport type AnyState = State.READY | State.RUNNING | CompleteState;\n", "import { Agent } from \"../Agent\";\nimport Attribute from \"../attributes/Attribute\";\nimport Entry from \"../attributes/callbacks/Entry\";\nimport Exit from \"../attributes/callbacks/Exit\";\nimport Step from \"../attributes/callbacks/Step\";\nimport Guard from \"../attributes/guards/Guard\";\nimport GuardPath from \"../attributes/guards/GuardPath\";\nimport GuardUnsatisifedException from \"../attributes/guards/GuardUnsatisifedException\";\nimport { BehaviourTreeOptions } from \"../BehaviourTreeOptions\";\nimport { AnyArgument } from \"../RootAstNodesBuilder\";\nimport State, { AnyState } from \"../State\";\nimport Leaf from \"./leaf/Leaf\";\n\n/**\n * A base node.\n */\nexport default abstract class Node {\n /**\n * The node uid.\n */\n private readonly uid: string = createNodeUid();\n /**\n * The node state.\n */\n private state: AnyState = State.READY;\n /**\n * The guard path to evaluate as part of a node update.\n */\n private guardPath: GuardPath | undefined;\n\n /**\n * @param type The node type.\n * @param attributes The node attributes.\n * @param args The node argument definitions.\n */\n constructor(private type: string, private attributes: Attribute[], private args: AnyArgument[]) {}\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected abstract onUpdate(agent: Agent, options: BehaviourTreeOptions): void;\n\n /**\n * Gets the name of the node.\n */\n public abstract getName(): string;\n\n /**\n * Gets whether this node is a leaf node.\n */\n public abstract isLeafNode: () => this is Leaf;\n\n /**\n * Gets/Sets the state of the node.\n */\n getState = (): AnyState => this.state;\n setState = (value: AnyState): void => {\n this.state = value;\n };\n\n /**\n * Gets the unique id of the node.\n */\n getUid = () => this.uid;\n\n /**\n * Gets the type of the node.\n */\n getType = () => this.type;\n\n /**\n * Gets the node attributes.\n */\n getAttributes = () => this.attributes;\n\n /**\n * Gets the node arguments.\n */\n getArguments = () => this.args;\n\n /**\n * Gets the node attribute with the specified type, or null if it does not exist.\n */\n getAttribute(type: \"entry\" | \"ENTRY\"): Entry;\n getAttribute(type: \"exit\" | \"EXIT\"): Exit;\n getAttribute(type: \"step\" | \"STEP\"): Step;\n getAttribute(type: string): Attribute {\n return (\n this.getAttributes().filter((decorator) => decorator.getType().toUpperCase() === type.toUpperCase())[0] ||\n null\n );\n }\n\n /**\n * Gets the node attributes.\n */\n getGuardAttributes = (): Guard[] => this.getAttributes().filter((decorator) => decorator.isGuard()) as Guard[];\n\n /**\n * Sets the guard path to evaluate as part of a node update.\n */\n setGuardPath = (value: GuardPath) => (this.guardPath = value);\n\n /**\n * Gets whether a guard path is assigned to this node.\n */\n hasGuardPath = () => !!this.guardPath;\n\n /**\n * Gets whether this node is in the specified state.\n * @param value The value to compare to the node state.\n */\n public is(value: AnyState): boolean {\n return this.state === value;\n }\n\n /**\n * Reset the state of the node.\n */\n public reset(): void {\n this.setState(State.READY);\n }\n\n /**\n * Abort the running of this node.\n * @param agent The agent.\n */\n public abort(agent: Agent): void {\n // There is nothing to do if this node is not in the running state.\n if (!this.is(State.RUNNING)) {\n return;\n }\n\n // Reset the state of this node.\n this.reset();\n\n this.getAttribute(\"exit\")?.callAgentFunction(agent, false, true);\n }\n\n /**\n * Update the node.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n * @returns The result of the update.\n */\n public update(agent: Agent, options: BehaviourTreeOptions): void {\n // If this node is already in a 'SUCCEEDED' or 'FAILED' state then there is nothing to do.\n if (this.is(State.SUCCEEDED) || this.is(State.FAILED)) {\n return;\n }\n\n try {\n // Evaluate all of the guard path conditions for the current tree path.\n this.guardPath!.evaluate(agent);\n\n // If this node is in the READY state then call the ENTRY for this node if it exists.\n if (this.is(State.READY)) {\n this.getAttribute(\"entry\")?.callAgentFunction(agent);\n }\n\n this.getAttribute(\"step\")?.callAgentFunction(agent);\n\n // Do the actual update.\n this.onUpdate(agent, options);\n\n // If this node is now in a 'SUCCEEDED' or 'FAILED' state then call the EXIT for this node if it exists.\n if (this.is(State.SUCCEEDED) || this.is(State.FAILED)) {\n this.getAttribute(\"exit\")?.callAgentFunction(agent, this.is(State.SUCCEEDED), false);\n }\n } catch (error) {\n // If the error is a GuardUnsatisfiedException then we need to determine if this node is the source.\n if (error instanceof GuardUnsatisifedException && error.isSourceNode(this)) {\n // Abort the current node.\n this.abort(agent);\n\n // Any node that is the source of an abort will be a failed node.\n this.setState(State.FAILED);\n } else {\n throw error;\n }\n }\n }\n}\n\n/**\n * Create a randomly generated node uid.\n * @returns A randomly generated node uid.\n */\nfunction createNodeUid(): string {\n var S4 = function () {\n return (((1 + Math.random()) * 0x10000) | 0).toString(16).substring(1);\n };\n return S4() + S4() + \"-\" + S4() + \"-\" + S4() + \"-\" + S4() + \"-\" + S4() + S4() + S4();\n}\n", "import Node from \"../Node\";\n\n/**\n * A leaf node.\n */\nexport default abstract class Leaf extends Node {\n /**\n * Gets whether this node is a leaf node.\n */\n isLeafNode = () => true;\n}\n", "import { ActionResult, Agent, ExitFunctionArg, FunctionArg, GlobalFunction } from \"./Agent\";\nimport { AnyArgument, RootAstNode } from \"./RootAstNodesBuilder\";\n\n// Exit callbacks receive their own special type of argument.\n// There's probably stricter ways to represent this but it feels overly complex right now.\ntype ExitResultArg = { value: ExitFunctionArg };\nexport type AnyExitArgument = AnyArgument | ExitResultArg;\n\nexport type InvokerFunction = (args: AnyExitArgument[]) => ActionResult;\n\n/**\n * A singleton used to store and lookup registered functions and subtrees.\n */\nexport default class Lookup {\n /**\n * The object holding any registered functions keyed on function name.\n */\n private static functionTable: { [key: string]: GlobalFunction } = {};\n /**\n * The object holding any registered sub-trees keyed on tree name.\n */\n private static subtreeTable: { [key: string]: RootAstNode } = {};\n\n /**\n * Gets the function with the specified name.\n * @param name The name of the function.\n * @returns The function with the specified name.\n */\n public static getFunc(name: string): GlobalFunction {\n return this.functionTable[name];\n }\n\n /**\n * Sets the function with the specified name for later lookup.\n * @param name The name of the function.\n * @param func The function.\n */\n public static setFunc(name: string, func: GlobalFunction): void {\n this.functionTable[name] = func;\n }\n\n /**\n * Gets the function invoker for the specified agent and function name.\n * If a function with the specified name exists on the agent object then it will\n * be returned, otherwise we will then check the registered functions for a match.\n * @param agent The agent instance that this behaviour tree is modelling behaviour for.\n * @param name The function name.\n * @returns The function invoker for the specified agent and function name.\n */\n static getFuncInvoker(agent: Agent, name: string): InvokerFunction | null {\n // Check whether the agent contains the specified function.\n const foundOnAgent = agent[name];\n if (foundOnAgent && typeof foundOnAgent === \"function\") {\n return (args: AnyExitArgument[]): boolean | ActionResult =>\n foundOnAgent.apply(\n agent,\n args.map((arg) => arg.value)\n );\n }\n\n // The agent does not contain the specified function but it may have been registered at some point.\n if (this.functionTable[name] && typeof this.functionTable[name] === \"function\") {\n return (args: AnyExitArgument[]) => this.functionTable[name](agent, ...args.map((arg) => arg.value));\n }\n\n // We have no function to invoke.\n return null;\n }\n\n /**\n * Gets the subtree with the specified name.\n * @param name The name of the subtree.\n * @returns The subtree with the specified name.\n */\n static getSubtree(name: string): RootAstNode {\n return this.subtreeTable[name];\n }\n\n /**\n * Sets the subtree with the specified name for later lookup.\n * @param name The name of the subtree.\n * @param subtree The subtree.\n */\n static setSubtree(name: string, subtree: RootAstNode) {\n this.subtreeTable[name] = subtree;\n }\n\n /**\n * Removes the registered function or subtree with the specified name.\n * @param name The name of the registered function or subtree.\n */\n static remove(name: string) {\n delete this.functionTable[name];\n delete this.subtreeTable[name];\n }\n\n /**\n * Remove all registered functions and subtrees.\n */\n static empty() {\n this.functionTable = {};\n this.subtreeTable = {};\n }\n}\n", "import Leaf from \"./Leaf\";\nimport State, { CompleteState } from \"../../State\";\nimport Lookup from \"../../Lookup\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { AnyArgument } from \"../../RootAstNodesBuilder\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * An Action leaf node.\n * This represents an immediate or ongoing state of behaviour.\n */\nexport default class Action extends Leaf {\n /**\n * @param attributes The node attributes.\n * @param actionName The action name.\n * @param actionArguments The array of action argument definitions.\n */\n constructor(attributes: Attribute[], private actionName: string, private actionArguments: AnyArgument[]) {\n super(\"action\", attributes, actionArguments);\n }\n\n /**\n * Whether there is a pending update promise.\n */\n private isUsingUpdatePromise = false;\n\n /**\n * The finished state result of an update promise.\n */\n private updatePromiseStateResult: CompleteState | null = null;\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // If the result of this action depends on an update promise then there is nothing to do until\n // it resolves, unless there has been a value set as a result of the update promise resolving.\n if (this.isUsingUpdatePromise) {\n // Check whether the update promise has resolved with a state value.\n if (this.updatePromiseStateResult) {\n // Set the state of this node to match the state returned by the promise.\n this.setState(this.updatePromiseStateResult);\n }\n\n return;\n }\n\n // Attempt to get the invoker for the action function.\n const actionFuncInvoker = Lookup.getFuncInvoker(agent, this.actionName);\n\n // The action function should be defined.\n if (actionFuncInvoker === null) {\n throw new Error(\n `cannot update action node as the action '${this.actionName}' function is not defined on the agent and has not been registered`\n );\n }\n\n // Call the action function, the result of which may be:\n // - The finished state of this action node.\n // - A promise to return a finished node state.\n // - Undefined if the node should remain in the running state.\n const updateResult = actionFuncInvoker(this.actionArguments) as CompleteState | Promise;\n\n if (updateResult instanceof Promise) {\n updateResult.then(\n (result) => {\n // If 'isUpdatePromisePending' is null then the promise was cleared as it was resolving, probably via an abort of reset.\n if (!this.isUsingUpdatePromise) {\n return;\n }\n\n // Check to make sure the result is a valid finished state.\n if (result !== State.SUCCEEDED && result !== State.FAILED) {\n throw new Error(\n \"action node promise resolved with an invalid value, expected a State.SUCCEEDED or State.FAILED value to be returned\"\n );\n }\n\n // Set pending update promise state result to be processed on next update.\n this.updatePromiseStateResult = result;\n },\n (reason) => {\n // If 'isUpdatePromisePending' is null then the promise was cleared as it was resolving, probably via an abort of reset.\n if (!this.isUsingUpdatePromise) {\n return;\n }\n\n // Just throw whatever was returned as the rejection argument.\n throw new Error(reason);\n }\n );\n\n // This node will be in the 'RUNNING' state until the update promise resolves.\n this.setState(State.RUNNING);\n\n // We are now waiting for the promise returned by the use to resolve before we know what state this node is in.\n this.isUsingUpdatePromise = true;\n } else {\n // Validate the returned value.\n this.validateUpdateResult(updateResult);\n\n // Set the state of this node, this may be undefined, which just means that the node is still in the 'RUNNING' state.\n this.setState(updateResult || State.RUNNING);\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => this.actionName;\n\n /**\n * Reset the state of the node.\n */\n reset = () => {\n // Reset the state of this node.\n this.setState(State.READY);\n\n // There is no longer an update promise that we care about.\n this.isUsingUpdatePromise = false;\n this.updatePromiseStateResult = null;\n };\n\n /**\n * Validate the result of an update function call.\n * @param result The result of an update function call.\n */\n private validateUpdateResult = (result: CompleteState | boolean) => {\n switch (result) {\n case State.SUCCEEDED:\n case State.FAILED:\n case undefined:\n return;\n default:\n throw new Error(\n `action '${this.actionName}' 'onUpdate' returned an invalid response, expected an optional State.SUCCEEDED or State.FAILED value to be returned`\n );\n }\n };\n}\n", "import Leaf from \"./Leaf\";\nimport State from \"../../State\";\nimport Lookup from \"../../Lookup\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { AnyArgument } from \"../../RootAstNodesBuilder\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A Condition leaf node.\n * This will succeed or fail immediately based on an agent predicate, without moving to the 'RUNNING' state.\n */\nexport default class Condition extends Leaf {\n /**\n * @param attributes The node attributes.\n * @param conditionName The name of the condition function.\n * @param conditionArguments The array of condition argument definitions.\n */\n constructor(attributes: Attribute[], private conditionName: string, private conditionArguments: AnyArgument[]) {\n super(\"condition\", attributes, conditionArguments);\n }\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // Attempt to get the invoker for the condition function.\n const conditionFuncInvoker = Lookup.getFuncInvoker(agent, this.conditionName);\n\n // The condition function should be defined.\n if (conditionFuncInvoker === null) {\n throw new Error(\n `cannot update condition node as the condition '${this.conditionName}' function is not defined on the agent and has not been registered`\n );\n }\n\n // Call the condition function to determine the state of this node.\n this.setState(!!conditionFuncInvoker(this.conditionArguments) ? State.SUCCEEDED : State.FAILED);\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => this.conditionName;\n}\n", "import Leaf from \"./Leaf\";\nimport State from \"../../State\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { Agent } from \"../../Agent\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A WAIT node.\n * The state of this node will change to SUCCEEDED after a duration of time\n */\nexport default class Wait extends Leaf {\n /**\n * @param attributes The node attributes.\n * @param duration The duration that this node will wait to succeed in milliseconds.\n * @param durationMin The minimum possible duration in milliseconds that this node will wait to succeed.\n * @param durationMax The maximum possible duration in milliseconds that this node will wait to succeed.\n */\n constructor(\n attributes: Attribute[],\n private duration: number | null,\n private durationMin: number | null,\n private durationMax: number | null\n ) {\n super(\"wait\", attributes, []);\n }\n\n /**\n * The time in milliseconds at which this node was first updated.\n */\n private initialUpdateTime: number = 0;\n\n /**\n * The total duration in milliseconds that this node will be waiting for.\n */\n private totalDuration: number | null = null;\n\n /**\n * The duration in milliseconds that this node has been waiting for.\n */\n private waitedDuration: number = 0;\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // If this node is in the READY state then we need to set the initial update time.\n if (this.is(State.READY)) {\n // Set the initial update time.\n this.initialUpdateTime = new Date().getTime();\n\n // Set the initial waited duration.\n this.waitedDuration = 0;\n\n // Are we dealing with an explicit duration or will we be randomly picking a duration between the min and max duration.\n if (this.duration !== null) {\n this.totalDuration = this.duration;\n } else if (this.durationMin !== null && this.durationMax !== null) {\n // We will be picking a random duration between a min and max duration, if the optional 'random' behaviour tree\n // function option is defined then we will be using that, otherwise we will fall back to using Math.random.\n const random = typeof options.random === \"function\" ? options.random : Math.random;\n\n // Pick a random duration between a min and max duration.\n this.totalDuration = Math.floor(\n random() * (this.durationMax - this.durationMin + 1) + this.durationMin\n );\n } else {\n this.totalDuration = null;\n }\n\n // The node is now running until we finish waiting.\n this.setState(State.RUNNING);\n }\n\n // If we have no total duration then this wait node will wait indefinitely until it is aborted.\n if (this.totalDuration === null) {\n return;\n }\n\n // If we have a 'getDeltaTime' function defined as part of our options then we will use it to figure out how long we have waited for.\n if (typeof options.getDeltaTime === \"function\") {\n // Get the delta time.\n const deltaTime = options.getDeltaTime();\n\n // Our delta time must be a valid number and cannot be NaN.\n if (typeof deltaTime !== \"number\" || isNaN(deltaTime)) {\n throw new Error(\"The delta time must be a valid number and not NaN.\");\n }\n\n // Update the amount of time that this node has been waiting for based on the delta time.\n this.waitedDuration += deltaTime * 1000;\n } else {\n // We are not using a delta time, so we will just work out hom much time has passed since the first update.\n this.waitedDuration = new Date().getTime() - this.initialUpdateTime;\n }\n\n // Have we waited long enough?\n if (this.waitedDuration >= this.totalDuration) {\n // We have finished waiting!\n this.setState(State.SUCCEEDED);\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => {\n if (this.duration !== null) {\n return `WAIT ${this.duration}ms`;\n } else if (this.durationMin !== null && this.durationMax !== null) {\n return `WAIT ${this.durationMin}ms-${this.durationMax}ms`;\n } else {\n return \"WAIT\";\n }\n };\n}\n", "import Node from \"../Node\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\n\n/**\n * A decorator node that wraps a single child node.\n */\nexport default abstract class Decorator extends Node {\n /**\n * @param type The node type.\n * @param attributes The node attributes.\n * @param child The child node.\n */\n constructor(type: string, attributes: Attribute[], protected child: Node) {\n super(type, attributes, []);\n }\n\n /**\n * Gets whether this node is a leaf node.\n */\n isLeafNode = () => false;\n\n /**\n * Gets the children of this node.\n */\n getChildren = () => [this.child];\n\n /**\n * Reset the state of the node.\n */\n reset = () => {\n // Reset the state of this node.\n this.setState(State.READY);\n\n // Reset the state of the child node.\n this.child.reset();\n };\n\n /**\n * Abort the running of this node.\n * @param agent The agent.\n */\n abort = (agent: Agent) => {\n // There is nothing to do if this node is not in the running state.\n if (!this.is(State.RUNNING)) {\n return;\n }\n\n // Abort the child node.\n this.child.abort(agent);\n\n // Reset the state of this node.\n this.reset();\n\n this.getAttribute(\"exit\")?.callAgentFunction(agent, false, true);\n };\n}\n", "import Node from \"../Node\";\nimport Decorator from \"./Decorator\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A Root node.\n * The root node will have a single child.\n */\nexport default class Root extends Decorator {\n /**\n * @param attributes The node attributes.\n * @param child The child node.\n */\n constructor(attributes: Attribute[], child: Node) {\n super(\"root\", attributes, child);\n }\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // If the child has never been updated or is running then we will need to update it now.\n if (this.child.getState() === State.READY || this.child.getState() === State.RUNNING) {\n // Update the child of this node.\n this.child.update(agent, options);\n }\n\n // The state of the root node is the state of its child.\n this.setState(this.child.getState());\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => \"ROOT\";\n}\n", "import Node from \"../Node\";\nimport Decorator from \"./Decorator\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A REPEAT node.\n * The node has a single child which can have:\n * -- A number of iterations for which to repeat the child node.\n * -- An infinite repeat loop if neither an iteration count or a condition function is defined.\n * The REPEAT node will stop and have a 'FAILED' state if its child is ever in a 'FAILED' state after an update.\n * The REPEAT node will attempt to move on to the next iteration if its child is ever in a 'SUCCEEDED' state.\n */\nexport default class Repeat extends Decorator {\n /**\n * @param attributes The node attributes.\n * @param iterations The number of iterations to repeat the child node.\n * @param iterationsMin The minimum possible number of iterations to repeat the child node.\n * @param iterationsMax The maximum possible number of iterations to repeat the child node.\n * @param child The child node.\n */\n constructor(\n attributes: Attribute[],\n private iterations: number | null,\n private iterationsMin: number | null,\n private iterationsMax: number | null,\n child: Node\n ) {\n super(\"repeat\", attributes, child);\n }\n\n /**\n * The number of target iterations to make.\n */\n private targetIterationCount: number | null = null;\n\n /**\n * The current iteration count.\n */\n private currentIterationCount: number = 0;\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // If this node is in the READY state then we need to reset the child and the target iteration count.\n if (this.is(State.READY)) {\n // Reset the child node.\n this.child.reset();\n\n // Reset the current iteration count.\n this.currentIterationCount = 0;\n\n // Set the target iteration count.\n this.setTargetIterationCount(options);\n }\n\n // Do a check to see if we can iterate. If we can then this node will move into the 'RUNNING' state.\n // If we cannot iterate then we have hit our target iteration count, which means that the node has succeeded.\n if (this.canIterate()) {\n // This node is in the running state and can do its initial iteration.\n this.setState(State.RUNNING);\n\n // We may have already completed an iteration, meaning that the child node will be in the SUCCEEDED state.\n // If this is the case then we will have to reset the child node now.\n if (this.child.getState() === State.SUCCEEDED) {\n this.child.reset();\n }\n\n // Update the child of this node.\n this.child.update(agent, options);\n\n // If the child moved into the FAILED state when we updated it then there is nothing left to do and this node has also failed.\n // If it has moved into the SUCCEEDED state then we have completed the current iteration.\n if (this.child.getState() === State.FAILED) {\n // The child has failed, meaning that this node has failed.\n this.setState(State.FAILED);\n\n return;\n } else if (this.child.getState() === State.SUCCEEDED) {\n // We have completed an iteration.\n this.currentIterationCount += 1;\n }\n } else {\n // This node is in the 'SUCCEEDED' state as we cannot iterate any more.\n this.setState(State.SUCCEEDED);\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => {\n if (this.iterations !== null) {\n return `REPEAT ${this.iterations}x`;\n } else if (this.iterationsMin !== null && this.iterationsMax !== null) {\n return `REPEAT ${this.iterationsMin}x-${this.iterationsMax}x`;\n } else {\n return \"REPEAT\";\n }\n };\n\n /**\n * Reset the state of the node.\n */\n reset = () => {\n // Reset the state of this node.\n this.setState(State.READY);\n\n // Reset the current iteration count.\n this.currentIterationCount = 0;\n\n // Reset the child node.\n this.child.reset();\n };\n\n /**\n * Gets whether an iteration can be made.\n * @returns Whether an iteration can be made.\n */\n private canIterate = () => {\n if (this.targetIterationCount !== null) {\n // We can iterate as long as we have not reached our target iteration count.\n return this.currentIterationCount < this.targetIterationCount;\n }\n\n // If neither an iteration count or a condition function were defined then we can iterate indefinitely.\n return true;\n };\n\n /**\n * Sets the target iteration count.\n * @param options The behaviour tree options object.\n */\n private setTargetIterationCount = (options: BehaviourTreeOptions) => {\n // Are we dealing with an explicit iteration count or will we be randomly picking a iteration count between the min and max iteration count.\n if (this.iterations !== null) {\n this.targetIterationCount = this.iterations;\n } else if (this.iterationsMin !== null && this.iterationsMax !== null) {\n // We will be picking a random iteration count between a min and max iteration count, if the optional 'random'\n // behaviour tree function option is defined then we will be using that, otherwise we will fall back to using Math.random.\n const random = typeof options.random === \"function\" ? options.random : Math.random;\n\n // Pick a random iteration count between a min and max iteration count.\n this.targetIterationCount = Math.floor(\n random() * (this.iterationsMax - this.iterationsMin + 1) + this.iterationsMin\n );\n } else {\n this.targetIterationCount = null;\n }\n };\n}\n", "import Node from \"../Node\";\nimport Decorator from \"./Decorator\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A RETRY node.\n * The node has a single child which can have:\n * -- A number of iterations for which to repeat the child node.\n * -- An infinite repeat loop if neither an iteration count or a condition function is defined.\n * The RETRY node will stop and have a 'SUCCEEDED' state if its child is ever in a 'SUCCEEDED' state after an update.\n * The RETRY node will attempt to move on to the next iteration if its child is ever in a 'FAILED' state.\n */\nexport default class Retry extends Decorator {\n /**\n * @param attributes The node attributes.\n * @param attempts The number of attempts to retry the child node.\n * @param attemptsMin The minimum possible number of attempts to retry the child node.\n * @param attemptsMax The maximum possible number of attempts to retry the child node.\n * @param child The child node.\n */\n constructor(\n attributes: Attribute[],\n private attempts: number | null,\n private attemptsMin: number | null,\n private attemptsMax: number | null,\n child: Node\n ) {\n super(\"retry\", attributes, child);\n }\n\n /**\n * The number of target attempts to make.\n */\n private targetAttemptCount: number | null = null;\n\n /**\n * The current attempt count.\n */\n private currentAttemptCount: number = 0;\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // If this node is in the READY state then we need to reset the child and the target attempt count.\n if (this.is(State.READY)) {\n // Reset the child node.\n this.child.reset();\n\n // Reset the current attempt count.\n this.currentAttemptCount = 0;\n\n // Set the target attempt count.\n this.setTargetAttemptCount(options);\n }\n\n // Do a check to see if we can attempt. If we can then this node will move into the 'RUNNING' state.\n // If we cannot attempt then we have hit our target attempt count, which means that the node has succeeded.\n if (this.canAttempt()) {\n // This node is in the running state and can do its initial attempt.\n this.setState(State.RUNNING);\n\n // We may have already completed an attempt, meaning that the child node will be in the FAILED state.\n // If this is the case then we will have to reset the child node now.\n if (this.child.getState() === State.FAILED) {\n this.child.reset();\n }\n\n // Update the child of this node.\n this.child.update(agent, options);\n\n // If the child moved into the SUCCEEDED state when we updated it then there is nothing left to do and this node has also succeeded.\n // If it has moved into the FAILED state then we have completed the current attempt.\n if (this.child.getState() === State.SUCCEEDED) {\n // The child has succeeded, meaning that this node has succeeded.\n this.setState(State.SUCCEEDED);\n\n return;\n } else if (this.child.getState() === State.FAILED) {\n // We have completed an attempt.\n this.currentAttemptCount += 1;\n }\n } else {\n // This node is in the 'FAILED' state as we cannot iterate any more.\n this.setState(State.FAILED);\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => {\n if (this.attempts !== null) {\n return `RETRY ${this.attempts}x`;\n } else if (this.attemptsMin !== null && this.attemptsMax !== null) {\n return `RETRY ${this.attemptsMin}x-${this.attemptsMax}x`;\n } else {\n return \"RETRY\";\n }\n };\n\n /**\n * Reset the state of the node.\n */\n reset = () => {\n // Reset the state of this node.\n this.setState(State.READY);\n\n // Reset the current attempt count.\n this.currentAttemptCount = 0;\n\n // Reset the child node.\n this.child.reset();\n };\n\n /**\n * Gets whether an attempt can be made.\n * @returns Whether an attempt can be made.\n */\n canAttempt = () => {\n if (this.targetAttemptCount !== null) {\n // We can attempt as long as we have not reached our target attempt count.\n return this.currentAttemptCount < this.targetAttemptCount;\n }\n\n // If neither an attempt count or a condition function were defined then we can attempt indefinitely.\n return true;\n };\n\n /**\n * Sets the target attempt count.\n * @param options The behaviour tree options object.\n */\n setTargetAttemptCount = (options: BehaviourTreeOptions) => {\n // Are we dealing with an explicit attempt count or will we be randomly picking an attempt count between the min and max attempt count.\n if (this.attempts !== null) {\n this.targetAttemptCount = this.attempts;\n } else if (this.attemptsMin !== null && this.attemptsMax !== null) {\n // We will be picking a random attempt count between a min and max attempt count, if the optional 'random'\n // behaviour tree function option is defined then we will be using that, otherwise we will fall back to using Math.random.\n const random = typeof options.random === \"function\" ? options.random : Math.random;\n\n // Pick a random attempt count between a min and max attempt count.\n this.targetAttemptCount = Math.floor(\n random() * (this.attemptsMax - this.attemptsMin + 1) + this.attemptsMin\n );\n } else {\n this.targetAttemptCount = null;\n }\n };\n}\n", "import Decorator from \"./Decorator\";\nimport State from \"../../State\";\nimport Node from \"../Node\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A Flip node.\n * This node wraps a single child and will flip the state of the child state.\n */\nexport default class Flip extends Decorator {\n /**\n * @param attributes The node attributes.\n * @param child The child node.\n */\n constructor(attributes: Attribute[], child: Node) {\n super(\"flip\", attributes, child);\n }\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // If the child has never been updated or is running then we will need to update it now.\n if (this.child.getState() === State.READY || this.child.getState() === State.RUNNING) {\n this.child.update(agent, options);\n }\n\n // The state of this node will depend in the state of its child.\n switch (this.child.getState()) {\n case State.RUNNING:\n this.setState(State.RUNNING);\n break;\n\n case State.SUCCEEDED:\n this.setState(State.FAILED);\n break;\n\n case State.FAILED:\n this.setState(State.SUCCEEDED);\n break;\n\n default:\n this.setState(State.READY);\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => \"FLIP\";\n}\n", "import Node from \"../Node\";\nimport Decorator from \"./Decorator\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A Succeed node.\n * This node wraps a single child and will always move to the 'SUCCEEDED' state when the child moves to a 'SUCCEEDED' or 'FAILED' state.\n */\nexport default class Succeed extends Decorator {\n /**\n * @param attributes The node attributes.\n * @param child The child node.\n */\n constructor(attributes: Attribute[], child: Node) {\n super(\"succeed\", attributes, child);\n }\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // If the child has never been updated or is running then we will need to update it now.\n if (this.child.getState() === State.READY || this.child.getState() === State.RUNNING) {\n this.child.update(agent, options);\n }\n\n // The state of this node will depend in the state of its child.\n switch (this.child.getState()) {\n case State.RUNNING:\n this.setState(State.RUNNING);\n break;\n\n case State.SUCCEEDED:\n case State.FAILED:\n this.setState(State.SUCCEEDED);\n break;\n\n default:\n this.setState(State.READY);\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => \"SUCCEED\";\n}\n", "import Node from \"../Node\";\nimport Decorator from \"./Decorator\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A Fail node.\n * This node wraps a single child and will always move to the 'FAILED' state when the child moves to a 'SUCCEEDED' or 'FAILED' state.\n */\nexport default class Fail extends Decorator {\n /**\n * @param attributes The node attributes.\n * @param child The child node.\n */\n constructor(attributes: Attribute[], child: Node) {\n super(\"fail\", attributes, child);\n }\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // If the child has never been updated or is running then we will need to update it now.\n if (this.child.getState() === State.READY || this.child.getState() === State.RUNNING) {\n this.child.update(agent, options);\n }\n\n // The state of this node will depend in the state of its child.\n switch (this.child.getState()) {\n case State.RUNNING:\n this.setState(State.RUNNING);\n break;\n\n case State.SUCCEEDED:\n case State.FAILED:\n this.setState(State.FAILED);\n break;\n\n default:\n this.setState(State.READY);\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => \"FAIL\";\n}\n", "import createLotto from \"lotto-draw\";\n\nimport Node from \"../Node\";\nimport Composite from \"./Composite\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A LOTTO node.\n * A winning child is picked on the initial update of this node, based on ticket weighting.\n * The state of this node will match the state of the winning child.\n */\nexport default class Lotto extends Composite {\n /**\n * @param attributes The node attributes.\n * @param tickets The child node tickets.\n * @param children The child nodes.\n */\n constructor(attributes: Attribute[], private tickets: number[], children: Node[]) {\n super(\"lotto\", attributes, children);\n }\n\n /**\n * The child node selected to be the active one.\n */\n private selectedChild: Node | undefined;\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // If this node is in the READY state then we need to pick a winning child node.\n if (this.is(State.READY)) {\n // Create a lotto draw with which to randomly pick a child node to become the active one.\n const lottoDraw = createLotto({\n // Hook up the optional 'random' behaviour tree function option to the one used by 'lotto-draw'.\n random: options.random,\n // Pass in each child node as a participant in the lotto draw with their respective ticket count.\n participants: this.children.map((child, index) => [child, this.tickets[index] || 1])\n });\n\n // Randomly pick a child based on ticket weighting, this will become the active child for this composite node.\n this.selectedChild = lottoDraw.draw() || undefined;\n }\n\n // If something went wrong and we don't have an active child then we should throw an error.\n if (!this.selectedChild) {\n throw new Error(\"failed to update lotto node as it has no active child\");\n }\n\n // If the selected child has never been updated or is running then we will need to update it now.\n if (this.selectedChild.getState() === State.READY || this.selectedChild.getState() === State.RUNNING) {\n this.selectedChild.update(agent, options);\n }\n\n // The state of the lotto node is the state of its selected child.\n this.setState(this.selectedChild.getState());\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => (this.tickets.length ? `LOTTO [${this.tickets.join(\",\")}]` : \"LOTTO\");\n}\n", "import Node from \"../Node\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\n\n/**\n * A composite node that wraps child nodes.\n */\nexport default abstract class Composite extends Node {\n /**\n * @param type The node type.\n * @param attributes The node attributes.\n * @param children The child nodes.\n */\n constructor(type: string, attributes: Attribute[], protected children: Node[]) {\n super(type, attributes, []);\n }\n\n /**\n * Gets whether this node is a leaf node.\n */\n isLeafNode = () => false;\n\n /**\n * Gets the children of this node.\n */\n getChildren = () => this.children;\n\n /**\n * Reset the state of the node.\n */\n reset = () => {\n // Reset the state of this node.\n this.setState(State.READY);\n\n // Reset the state of any child nodes.\n this.getChildren().forEach((child) => child.reset());\n };\n\n /**\n * Abort the running of this node.\n * @param agent The agent.\n */\n abort = (agent: Agent) => {\n // There is nothing to do if this node is not in the running state.\n if (!this.is(State.RUNNING)) {\n return;\n }\n\n // Abort any child nodes.\n this.getChildren().forEach((child) => child.abort(agent));\n\n // Reset the state of this node.\n this.reset();\n\n this.getAttribute(\"exit\")?.callAgentFunction(agent, false, true);\n };\n}\n", "import Composite from \"./Composite\";\nimport Node from \"../Node\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A SELECTOR node.\n * The child nodes are executed in sequence until one succeeds or all fail.\n */\nexport default class Selector extends Composite {\n /**\n * @param attributes The node attributes.\n * @param children The child nodes.\n */\n constructor(attributes: Attribute[], protected children: Node[]) {\n super(\"selector\", attributes, children);\n }\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // Iterate over all of the children of this node.\n for (const child of this.children) {\n // If the child has never been updated or is running then we will need to update it now.\n if (child.getState() === State.READY || child.getState() === State.RUNNING) {\n // Update the child of this node.\n child.update(agent, options);\n }\n\n // If the current child has a state of 'SUCCEEDED' then this node is also a 'SUCCEEDED' node.\n if (child.getState() === State.SUCCEEDED) {\n // This node is a 'SUCCEEDED' node.\n this.setState(State.SUCCEEDED);\n\n // There is no need to check the rest of the selector nodes.\n return;\n }\n\n // If the current child has a state of 'FAILED' then we should move on to the next child.\n if (child.getState() === State.FAILED) {\n // Find out if the current child is the last one in the selector.\n // If it is then this sequence node has also failed.\n if (this.children.indexOf(child) === this.children.length - 1) {\n // This node is a 'FAILED' node.\n this.setState(State.FAILED);\n\n // There is no need to check the rest of the selector as we have completed it.\n return;\n } else {\n // The child node failed, try the next one.\n continue;\n }\n }\n\n // The node should be in the 'RUNNING' state.\n if (child.getState() === State.RUNNING) {\n // This node is a 'RUNNING' node.\n this.setState(State.RUNNING);\n\n // There is no need to check the rest of the selector as the current child is still running.\n return;\n }\n\n // The child node was not in an expected state.\n throw new Error(\"child node was not in an expected state.\");\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => \"SELECTOR\";\n}\n", "import Composite from \"./Composite\";\nimport Node from \"../Node\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A SEQUENCE node.\n * The child nodes are executed in sequence until one fails or all succeed.\n */\nexport default class Sequence extends Composite {\n /**\n * @param attributes The node attributes.\n * @param children The child nodes.\n */\n constructor(attributes: Attribute[], protected children: Node[]) {\n super(\"sequence\", attributes, children);\n }\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // Iterate over all of the children of this node.\n for (const child of this.children) {\n // If the child has never been updated or is running then we will need to update it now.\n if (child.getState() === State.READY || child.getState() === State.RUNNING) {\n // Update the child of this node.\n child.update(agent, options);\n }\n\n // If the current child has a state of 'SUCCEEDED' then we should move on to the next child.\n if (child.getState() === State.SUCCEEDED) {\n // Find out if the current child is the last one in the sequence.\n // If it is then this sequence node has also succeeded.\n if (this.children.indexOf(child) === this.children.length - 1) {\n // This node is a 'SUCCEEDED' node.\n this.setState(State.SUCCEEDED);\n\n // There is no need to check the rest of the sequence as we have completed it.\n return;\n } else {\n // The child node succeeded, but we have not finished the sequence yet.\n continue;\n }\n }\n\n // If the current child has a state of 'FAILED' then this node is also a 'FAILED' node.\n if (child.getState() === State.FAILED) {\n // This node is a 'FAILED' node.\n this.setState(State.FAILED);\n\n // There is no need to check the rest of the sequence.\n return;\n }\n\n // The node should be in the 'RUNNING' state.\n if (child.getState() === State.RUNNING) {\n // This node is a 'RUNNING' node.\n this.setState(State.RUNNING);\n\n // There is no need to check the rest of the sequence as the current child is still running.\n return;\n }\n\n // The child node was not in an expected state.\n throw new Error(\"child node was not in an expected state.\");\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => \"SEQUENCE\";\n}\n", "import Composite from \"./Composite\";\nimport State from \"../../State\";\nimport Node from \"../Node\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A PARALLEL node.\n * The child nodes are executed concurrently until one fails or all succeed.\n */\nexport default class Parallel extends Composite {\n /**\n * @param attributes The node attributes.\n * @param children The child nodes.\n */\n constructor(attributes: Attribute[], children: Node[]) {\n super(\"parallel\", attributes, children);\n }\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // Keep a count of the number of succeeded child nodes.\n let succeededCount = 0;\n\n let hasChildFailed = false;\n\n // Iterate over all of the children of this node.\n for (const child of this.children) {\n // If the child has never been updated or is running then we will need to update it now.\n if (child.getState() === State.READY || child.getState() === State.RUNNING) {\n // Update the child of this node.\n child.update(agent, options);\n }\n\n // If the current child has a state of 'SUCCEEDED' then we should move on to the next child.\n if (child.getState() === State.SUCCEEDED) {\n // The child node has succeeded, keep track of this to determine if all children have.\n succeededCount++;\n\n // The child node succeeded, but we have not finished checking every child node yet.\n continue;\n }\n\n // If the current child has a state of 'FAILED' then this node is also a 'FAILED' node.\n if (child.getState() === State.FAILED) {\n hasChildFailed = true;\n\n // There is no need to check the rest of the children.\n break;\n }\n\n // The node should be in the 'RUNNING' state.\n if (child.getState() !== State.RUNNING) {\n // The child node was not in an expected state.\n throw new Error(\"child node was not in an expected state.\");\n }\n }\n\n if (hasChildFailed) {\n // This node is a 'FAILED' node.\n this.setState(State.FAILED);\n\n // Abort every running child.\n for (const child of this.children) {\n if (child.getState() === State.RUNNING) {\n child.abort(agent);\n }\n }\n } else {\n // If all children have succeeded then this node has also succeeded, otherwise it is still running.\n this.setState(succeededCount === this.children.length ? State.SUCCEEDED : State.RUNNING);\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => \"PARALLEL\";\n}\n", "import { AnyArgument } from \"../RootAstNodesBuilder\";\nimport Guard from \"./guards/Guard\";\n\nexport type AttributeDetails = {\n /** The attribute type. */\n type: string;\n\n /** The attribute arguments. */\n args: AnyArgument[];\n};\n\n/**\n * A base node attribute.\n */\nexport default abstract class Attribute {\n /**\n * @param type The node attribute type.\n * @param args The array of attribute argument definitions.\n */\n constructor(protected type: string, protected args: AnyArgument[]) {}\n\n /**\n * Gets the type of the attribute.\n */\n getType = () => this.type;\n\n /**\n * Gets the array of attribute argument definitions.\n */\n getArguments = () => this.args;\n\n /**\n * Gets the attribute details.\n */\n abstract getDetails(): TAttributeDetails;\n\n /**\n * Gets whether this attribute is a guard.\n */\n abstract isGuard: () => this is Guard;\n}\n", "import { Agent } from \"../../Agent\";\nimport { AnyArgument } from \"../../RootAstNodesBuilder\";\nimport Attribute, { AttributeDetails } from \"../Attribute\";\n\nexport type GuardAttributeDetails = {\n /** The name of the condition function that determines whether the guard is satisfied. */\n condition: string;\n} & AttributeDetails;\n\n/**\n * A base node guard attribute.\n */\nexport default abstract class Guard extends Attribute {\n /**\n * @param type The node attribute type.\n * @param args The array of decorator argument definitions.\n * @param condition The name of the condition function that determines whether the guard is satisfied.\n */\n constructor(type: string, args: AnyArgument[], private condition: string) {\n super(type, args);\n }\n\n /**\n * Gets the name of the condition function that determines whether the guard is satisfied.\n */\n getCondition = () => this.condition;\n\n /**\n * Gets whether this attribute is a guard.\n */\n isGuard = () => true;\n\n /**\n * Gets the attribute details.\n */\n getDetails(): GuardAttributeDetails {\n return {\n type: this.getType(),\n args: this.getArguments(),\n condition: this.getCondition()\n };\n }\n\n /**\n * Gets whether the guard is satisfied.\n * @param agent The agent.\n * @returns Whether the guard is satisfied.\n */\n abstract isSatisfied(agent: Agent): boolean;\n}\n", "import Guard from \"./Guard\";\nimport Lookup from \"../../Lookup\";\nimport { Agent } from \"../../Agent\";\nimport { AnyArgument } from \"../../RootAstNodesBuilder\";\n\n/**\n * A WHILE guard which is satisfied as long as the given condition remains true.\n */\nexport default class While extends Guard {\n /**\n * @param condition The name of the condition function that determines whether the guard is satisfied.\n * @param args The array of decorator argument definitions.\n */\n constructor(condition: string, args: AnyArgument[]) {\n super(\"while\", args, condition);\n }\n\n /**\n * Gets whether the guard is satisfied.\n * @param agent The agent.\n * @returns Whether the guard is satisfied.\n */\n isSatisfied = (agent: Agent) => {\n // Attempt to get the invoker for the condition function.\n const conditionFuncInvoker = Lookup.getFuncInvoker(agent, this.getCondition());\n\n // The condition function should be defined.\n if (conditionFuncInvoker === null) {\n throw new Error(\n `cannot evaluate node guard as the condition '${this.getCondition()}' function is not defined on the agent and has not been registered`\n );\n }\n\n // Call the condition function to determine whether this guard is satisfied.\n return !!conditionFuncInvoker(this.args);\n };\n}\n", "import Guard from \"./Guard\";\nimport Lookup from \"../../Lookup\";\nimport { Agent } from \"../../Agent\";\nimport { AnyArgument } from \"../../RootAstNodesBuilder\";\n\n/**\n * An UNTIL guard which is satisfied as long as the given condition remains false.\n */\nexport default class Until extends Guard {\n /**\n * @param condition The name of the condition function that determines whether the guard is satisfied.\n * @param args The array of decorator argument definitions.\n */\n constructor(condition: string, args: AnyArgument[]) {\n super(\"until\", args, condition);\n }\n\n /**\n * Gets whether the guard is satisfied.\n * @param agent The agent.\n * @returns Whether the guard is satisfied.\n */\n isSatisfied = (agent: Agent) => {\n // Attempt to get the invoker for the condition function.\n const conditionFuncInvoker = Lookup.getFuncInvoker(agent, this.getCondition());\n\n // The condition function should be defined.\n if (conditionFuncInvoker === null) {\n throw new Error(\n `cannot evaluate node guard as the condition '${this.getCondition()}' function is not defined on the agent and has not been registered`\n );\n }\n\n // Call the condition function to determine whether this guard is satisfied.\n return !!!conditionFuncInvoker(this.args);\n };\n}\n", "import { Agent } from \"../../Agent\";\nimport { AnyArgument } from \"../../RootAstNodesBuilder\";\nimport Attribute, { AttributeDetails } from \"../Attribute\";\n\nexport type CallbackAttributeDetails = {\n /** The name of the agent function that is called. */\n functionName: string;\n} & AttributeDetails;\n\n/**\n * A base node callback attribute.\n */\nexport default abstract class Callback extends Attribute {\n /**\n * @param type The node attribute type.\n * @param args The array of decorator argument definitions.\n * @param functionName The name of the agent function to call.\n */\n constructor(type: string, args: AnyArgument[], private functionName: string) {\n super(type, args);\n }\n\n /**\n * Gets the name of the agent function to call.\n */\n getFunctionName = () => this.functionName;\n\n /**\n * Gets whether this attribute is a guard.\n */\n isGuard = () => false;\n\n /**\n * Gets the attribute details.\n */\n getDetails(): CallbackAttributeDetails {\n return {\n type: this.getType(),\n args: this.getArguments(),\n functionName: this.getFunctionName()\n };\n }\n\n /**\n * Attempt to call the agent function that this callback refers to.\n * @param agent The agent.\n */\n abstract callAgentFunction: (agent: Agent, isSuccess: boolean, isAborted: boolean) => void;\n}\n", "import Callback from \"./Callback\";\nimport Lookup from \"../../Lookup\";\nimport { Agent } from \"../../Agent\";\nimport { AnyArgument } from \"../../RootAstNodesBuilder\";\n\n/**\n * An ENTRY callback which defines an agent function to call when the associated node is updated and moves out of running state.\n */\nexport default class Entry extends Callback {\n /**\n * @param functionName The name of the agent function to call.\n * @param args The array of callback argument definitions.\n */\n constructor(functionName: string, args: AnyArgument[]) {\n super(\"entry\", args, functionName);\n }\n\n /**\n * Attempt to call the agent function that this callback refers to.\n * @param agent The agent.\n */\n callAgentFunction = (agent: Agent) => {\n // Attempt to get the invoker for the callback function.\n const callbackFuncInvoker = Lookup.getFuncInvoker(agent, this.getFunctionName());\n\n // The callback function should be defined.\n if (callbackFuncInvoker === null) {\n throw new Error(\n `cannot call entry function '${this.getFunctionName()}' as is not defined on the agent and has not been registered`\n );\n }\n\n // Call the callback function.\n callbackFuncInvoker(this.args);\n };\n}\n", "import Callback from \"./Callback\";\nimport Lookup, { AnyExitArgument } from \"../../Lookup\";\nimport { Agent } from \"../../Agent\";\nimport { AnyArgument } from \"../../RootAstNodesBuilder\";\n\n/**\n * An EXIT callback which defines an agent function to call when the associated node is updated and moves to a finished state or is aborted.\n */\nexport default class Exit extends Callback {\n /**\n * @param functionName The name of the agent function to call.\n * @param args The array of callback argument definitions.\n */\n constructor(functionName: string, args: AnyArgument[]) {\n super(\"exit\", args, functionName);\n }\n\n /**\n * Attempt to call the agent function that this callback refers to.\n * @param agent The agent.\n * @param isSuccess Whether the decorated node was left with a success state.\n * @param isAborted Whether the decorated node was aborted.\n */\n callAgentFunction = (agent: Agent, isSuccess: boolean, isAborted: boolean) => {\n // Attempt to get the invoker for the callback function.\n const callbackFuncInvoker = Lookup.getFuncInvoker(agent, this.getFunctionName());\n\n // The callback function should be defined.\n if (callbackFuncInvoker === null) {\n throw new Error(\n `cannot call exit function '${this.getFunctionName()}' as is not defined on the agent and has not been registered`\n );\n }\n\n // Call the callback function\n callbackFuncInvoker([{ value: { succeeded: isSuccess, aborted: isAborted } }, ...this.args]);\n };\n}\n", "import Callback from \"./Callback\";\nimport Lookup from \"../../Lookup\";\nimport { Agent } from \"../../Agent\";\nimport { AnyArgument } from \"../../RootAstNodesBuilder\";\n\n/**\n * A STEP callback which defines an agent function to call when the associated node is updated.\n */\nexport default class Step extends Callback {\n /**\n * @param functionName The name of the agent function to call.\n * @param args The array of callback argument definitions.\n */\n constructor(functionName: string, args: AnyArgument[]) {\n super(\"step\", args, functionName);\n }\n\n /**\n * Attempt to call the agent function that this callback refers to.\n * @param agent The agent.\n */\n callAgentFunction = (agent: Agent) => {\n // Attempt to get the invoker for the callback function.\n const callbackFuncInvoker = Lookup.getFuncInvoker(agent, this.getFunctionName());\n\n // The callback function should be defined.\n if (callbackFuncInvoker === null) {\n throw new Error(\n `cannot call step function '${this.getFunctionName()}' as is not defined on the agent and has not been registered`\n );\n }\n\n // Call the callback function.\n callbackFuncInvoker(this.args);\n };\n}\n", "import Action from \"./nodes/leaf/Action\";\nimport Condition from \"./nodes/leaf/Condition\";\nimport Wait from \"./nodes/leaf/Wait\";\nimport Root from \"./nodes/decorator/Root\";\nimport Repeat from \"./nodes/decorator/Repeat\";\nimport Retry from \"./nodes/decorator/Retry\";\nimport Flip from \"./nodes/decorator/Flip\";\nimport Succeed from \"./nodes/decorator/Succeed\";\nimport Fail from \"./nodes/decorator/Fail\";\nimport Lotto from \"./nodes/composite/Lotto\";\nimport Selector from \"./nodes/composite/Selector\";\nimport Sequence from \"./nodes/composite/Sequence\";\nimport Parallel from \"./nodes/composite/Parallel\";\nimport Node from \"./nodes/Node\";\nimport While from \"./attributes/guards/While\";\nimport Until from \"./attributes/guards/Until\";\nimport Entry from \"./attributes/callbacks/Entry\";\nimport Exit from \"./attributes/callbacks/Exit\";\nimport Step from \"./attributes/callbacks/Step\";\nimport Callback from \"./attributes/callbacks/Callback\";\nimport Guard from \"./attributes/guards/Guard\";\nimport Attribute from \"./attributes/Attribute\";\nimport Composite from \"./nodes/composite/Composite\";\nimport Decorator from \"./nodes/decorator/Decorator\";\nimport Leaf from \"./nodes/leaf/Leaf\";\n\nexport type Argument = {\n value: T;\n type: string; // Used for validation.\n};\ntype NullArgument = Argument & {\n type: \"null\";\n};\ntype BooleanArgument = Argument & {\n type: \"boolean\";\n};\ntype NumberArgument = Argument & {\n type: \"number\";\n isInteger: boolean; // Used for validation.\n};\ntype StringPlaceholderArgument = Argument & {\n type: \"string\";\n};\ntype IdentifierArgument = Argument & {\n type: \"identifier\";\n};\nexport type AnyArgument =\n | NullArgument\n | BooleanArgument\n | NumberArgument\n | StringPlaceholderArgument\n | IdentifierArgument;\n\n/**\n * The node attribute factories.\n */\nconst AttributeFactories: {\n [key: string]: (functionName: string, attributeArguments: AnyArgument[]) => Callback | Guard;\n} = {\n WHILE: (condition: string, attributeArguments: AnyArgument[]) => new While(condition, attributeArguments),\n UNTIL: (condition: string, attributeArguments: AnyArgument[]) => new Until(condition, attributeArguments),\n ENTRY: (functionName: string, attributeArguments: AnyArgument[]) => new Entry(functionName, attributeArguments),\n EXIT: (functionName: string, attributeArguments: AnyArgument[]) => new Exit(functionName, attributeArguments),\n STEP: (functionName: string, attributeArguments: AnyArgument[]) => new Step(functionName, attributeArguments)\n};\n\ntype Validatable = {\n children?: AstNode[];\n validate: (depth: number) => void;\n};\n\ntype NodeInstanceCreator = (\n namedRootNodeProvider: (name: string) => RootAstNode,\n visitedBranches: string[]\n) => T;\n\nexport type AstNode = Validatable & {\n type: string;\n createNodeInstance: NodeInstanceCreator;\n};\n\nexport type LeafAstNode = AstNode & {\n type: \"action\" | \"condition\" | \"wait\";\n attributes: Attribute[];\n};\n\nexport type CompositeAstNode = AstNode & {\n type: \"lotto\" | \"parallel\" | \"selector\" | \"sequence\";\n attributes: Attribute[];\n children: AstNode[];\n};\n\nexport type DecoratorAstNode = AstNode & {\n type: \"fail\" | \"flip\" | \"repeat\" | \"retry\" | \"root\" | \"succeed\";\n attributes: Attribute[];\n children: AstNode[];\n};\n\nexport type BranchAstNode = AstNode & {\n type: \"branch\";\n branchName: \"\" | string;\n};\n\nexport type LottoAstNode = CompositeAstNode & {\n type: \"lotto\";\n tickets: number[];\n};\n\nexport type RootAstNode = DecoratorAstNode & {\n type: \"root\";\n name: null | string;\n};\n\nexport type RepeatAstNode = DecoratorAstNode & {\n type: \"repeat\";\n iterations: number | null;\n iterationsMin: number | null;\n iterationsMax: number | null;\n};\n\nexport type RetryAstNode = DecoratorAstNode & {\n type: \"retry\";\n attempts: number | null;\n attemptsMin: number | null;\n attemptsMax: number | null;\n};\n\nexport type ActionAstNode = LeafAstNode & {\n type: \"action\";\n actionName: string;\n actionArguments: AnyArgument[];\n};\n\nexport type ConditionAstNode = LeafAstNode & {\n type: \"condition\";\n conditionName: string;\n conditionArguments: AnyArgument[];\n};\n\nexport type WaitAstNode = LeafAstNode & {\n type: \"wait\";\n duration: number | null;\n durationMin: number | null;\n durationMax: number | null;\n};\n\nexport type AnyAstNode =\n | BranchAstNode\n | CompositeAstNode\n | LottoAstNode\n | DecoratorAstNode\n | RootAstNode\n | RepeatAstNode\n | RetryAstNode\n | LeafAstNode\n | ActionAstNode\n | ConditionAstNode\n | WaitAstNode;\n\n/**\n * The AST node factories.\n */\nconst ASTNodeFactories = {\n ROOT: (): RootAstNode => ({\n type: \"root\",\n attributes: [],\n name: null,\n children: [],\n validate(depth: number) {\n // A root node cannot be the child of another node.\n if (depth > 1) {\n throw new Error(\"a root node cannot be the child of another node\");\n }\n\n // A root node must have a single child node.\n if (this.children.length !== 1) {\n throw new Error(\"a root node must have a single child\");\n }\n },\n createNodeInstance(namedRootNodeProvider, visitedBranches) {\n return new Root(\n this.attributes,\n this.children![0].createNodeInstance(namedRootNodeProvider, visitedBranches.slice())\n );\n }\n }),\n BRANCH: (): BranchAstNode => ({\n type: \"branch\",\n branchName: \"\",\n validate() {},\n createNodeInstance(namedRootNodeProvider, visitedBranches) {\n // Try to find the root node with a matching branch name.\n const targetRootNode = namedRootNodeProvider(this.branchName);\n\n // If we have already visited this branch then we have a circular dependency.\n if (visitedBranches.indexOf(this.branchName) !== -1) {\n throw new Error(`circular dependency found in branch node references for branch '${this.branchName}'`);\n }\n\n // If we have a target root node, then the node instance we want will be the first and only child of the referenced root node.\n if (targetRootNode) {\n return targetRootNode\n .createNodeInstance(namedRootNodeProvider, visitedBranches.concat(this.branchName))\n .getChildren()[0];\n } else {\n throw new Error(`branch references root node '${this.branchName}' which has not been defined`);\n }\n }\n }),\n SELECTOR: (): CompositeAstNode => ({\n type: \"selector\",\n attributes: [],\n children: [],\n validate() {\n // A selector node must have at least a single node.\n if (this.children.length < 1) {\n throw new Error(\"a selector node must have at least a single child\");\n }\n },\n createNodeInstance(namedRootNodeProvider, visitedBranches) {\n return new Selector(\n this.attributes,\n this.children.map((child) => child.createNodeInstance(namedRootNodeProvider, visitedBranches.slice()))\n );\n }\n }),\n SEQUENCE: (): CompositeAstNode => ({\n type: \"sequence\",\n attributes: [],\n children: [],\n validate() {\n // A sequence node must have at least a single node.\n if (this.children.length < 1) {\n throw new Error(\"a sequence node must have at least a single child\");\n }\n },\n createNodeInstance(namedRootNodeProvider, visitedBranches) {\n return new Sequence(\n this.attributes,\n this.children.map((child) => child.createNodeInstance(namedRootNodeProvider, visitedBranches.slice()))\n );\n }\n }),\n PARALLEL: (): CompositeAstNode => ({\n type: \"parallel\",\n attributes: [],\n children: [],\n validate() {\n // A parallel node must have at least a single node.\n if (this.children.length < 1) {\n throw new Error(\"a parallel node must have at least a single child\");\n }\n },\n createNodeInstance(namedRootNodeProvider, visitedBranches) {\n return new Parallel(\n this.attributes,\n this.children.map((child) => child.createNodeInstance(namedRootNodeProvider, visitedBranches.slice()))\n );\n }\n }),\n LOTTO: (): LottoAstNode => ({\n type: \"lotto\",\n attributes: [],\n children: [],\n tickets: [],\n validate() {\n // A lotto node must have at least a single node.\n if (this.children!.length < 1) {\n throw new Error(\"a lotto node must have at least a single child\");\n }\n },\n createNodeInstance(namedRootNodeProvider, visitedBranches) {\n return new Lotto(\n this.attributes,\n this.tickets!,\n this.children!.map((child) => child.createNodeInstance(namedRootNodeProvider, visitedBranches.slice()))\n );\n }\n }),\n REPEAT: (): RepeatAstNode => ({\n type: \"repeat\",\n attributes: [],\n iterations: null,\n iterationsMin: null,\n iterationsMax: null,\n children: [],\n validate() {\n // A repeat node must have a single node.\n if (this.children!.length !== 1) {\n throw new Error(\"a repeat node must have a single child\");\n }\n\n if (this.iterations !== null) {\n // A repeat node must have a positive number of iterations if defined.\n if (this.iterations < 0) {\n throw new Error(\"a repeat node must have a positive number of iterations if defined\");\n }\n } else if (this.iterationsMin !== null && this.iterationsMax !== null) {\n // A repeat node must have a positive min and max iteration count if they are defined.\n if (this.iterationsMin < 0 || this.iterationsMax < 0) {\n throw new Error(\n \"a repeat node must have a positive minimum and maximum iteration count if defined\"\n );\n }\n\n // A repeat node must not have an minimum iteration count that exceeds the maximum iteration count.\n if (this.iterationsMin > this.iterationsMax) {\n throw new Error(\n \"a repeat node must not have a minimum iteration count that exceeds the maximum iteration count\"\n );\n }\n } else {\n // If we have no explicit iteration count or a minimum and maximum iteration count set then we are dealing with a repeat node that iterates indefinitely.\n }\n },\n createNodeInstance(namedRootNodeProvider, visitedBranches) {\n return new Repeat(\n this.attributes,\n this.iterations,\n this.iterationsMin,\n this.iterationsMax,\n this.children![0].createNodeInstance(namedRootNodeProvider, visitedBranches.slice())\n );\n }\n }),\n RETRY: (): RetryAstNode => ({\n type: \"retry\",\n attributes: [],\n attempts: null,\n attemptsMin: null,\n attemptsMax: null,\n children: [],\n validate() {\n // A retry node must have a single node.\n if (this.children!.length !== 1) {\n throw new Error(\"a retry node must have a single child\");\n }\n\n if (this.attempts !== null) {\n // A retry node must have a positive number of attempts if defined.\n if (this.attempts < 0) {\n throw new Error(\"a retry node must have a positive number of attempts if defined\");\n }\n } else if (this.attemptsMin !== null && this.attemptsMax !== null) {\n // A retry node must have a positive min and max attempts count if they are defined.\n if (this.attemptsMin < 0 || this.attemptsMax < 0) {\n throw new Error(\"a retry node must have a positive minimum and maximum attempt count if defined\");\n }\n\n // A retry node must not have a minimum attempt count that exceeds the maximum attempt count.\n if (this.attemptsMin > this.attemptsMax) {\n throw new Error(\n \"a retry node must not have a minimum attempt count that exceeds the maximum attempt count\"\n );\n }\n } else {\n // If we have no explicit attempt count or a minimum and maximum attempt count set then we are dealing with a retry node that attempts indefinitely.\n }\n },\n createNodeInstance(namedRootNodeProvider, visitedBranches) {\n return new Retry(\n this.attributes,\n this.attempts,\n this.attemptsMin,\n this.attemptsMax,\n this.children![0].createNodeInstance(namedRootNodeProvider, visitedBranches.slice())\n );\n }\n }),\n FLIP: (): DecoratorAstNode => ({\n type: \"flip\",\n attributes: [],\n children: [],\n validate() {\n // A flip node must have a single node.\n if (this.children!.length !== 1) {\n throw new Error(\"a flip node must have a single child\");\n }\n },\n createNodeInstance(namedRootNodeProvider, visitedBranches) {\n return new Flip(\n this.attributes,\n this.children![0].createNodeInstance(namedRootNodeProvider, visitedBranches.slice())\n );\n }\n }),\n SUCCEED: (): DecoratorAstNode => ({\n type: \"succeed\",\n attributes: [],\n children: [],\n validate() {\n // A succeed node must have a single node.\n if (this.children!.length !== 1) {\n throw new Error(\"a succeed node must have a single child\");\n }\n },\n createNodeInstance(namedRootNodeProvider, visitedBranches) {\n return new Succeed(\n this.attributes,\n this.children![0].createNodeInstance(namedRootNodeProvider, visitedBranches.slice())\n );\n }\n }),\n FAIL: (): DecoratorAstNode => ({\n type: \"fail\",\n attributes: [],\n children: [],\n validate() {\n // A fail node must have a single node.\n if (this.children!.length !== 1) {\n throw new Error(\"a fail node must have a single child\");\n }\n },\n createNodeInstance(namedRootNodeProvider, visitedBranches) {\n return new Fail(\n this.attributes,\n this.children![0].createNodeInstance(namedRootNodeProvider, visitedBranches.slice())\n );\n }\n }),\n WAIT: (): WaitAstNode => ({\n type: \"wait\",\n attributes: [],\n duration: null,\n durationMin: null,\n durationMax: null,\n validate() {\n if (this.duration !== null) {\n // If an explict duration was defined then it must be a positive number.\n if (this.duration < 0) {\n throw new Error(\"a wait node must have a positive duration\");\n }\n } else if (this.durationMin !== null && this.durationMax !== null) {\n // A wait node must have a positive min and max duration.\n if (this.durationMin < 0 || this.durationMax < 0) {\n throw new Error(\"a wait node must have a positive minimum and maximum duration\");\n }\n\n // A wait node must not have a minimum duration that exceeds the maximum duration.\n if (this.durationMin > this.durationMax) {\n throw new Error(\"a wait node must not have a minimum duration that exceeds the maximum duration\");\n }\n } else {\n // If we have no explicit duration or duration bounds set then we are dealing with a wait node that waits indefinitely.\n }\n },\n createNodeInstance() {\n return new Wait(this.attributes, this.duration, this.durationMin, this.durationMax);\n }\n }),\n ACTION: (): ActionAstNode => ({\n type: \"action\",\n attributes: [],\n actionName: \"\",\n actionArguments: [],\n validate() {},\n createNodeInstance() {\n return new Action(this.attributes, this.actionName!, this.actionArguments!);\n }\n }),\n CONDITION: (): ConditionAstNode => ({\n type: \"condition\",\n attributes: [],\n conditionName: \"\",\n conditionArguments: [],\n validate() {},\n createNodeInstance() {\n return new Condition(this.attributes, this.conditionName!, this.conditionArguments!);\n }\n })\n};\n\ntype OtherAstNodes = AstNode[];\n\n/**\n * Create an array of root AST nodes based on the given definition.\n * @param definition The definition to parse the AST nodes from.\n * @returns The base definition AST nodes.\n */\nexport default function buildRootASTNodes(definition: string): RootAstNode[] {\n // Swap out any node/attribute argument string literals with a placeholder and get a mapping of placeholders to original values as well as the processed definition.\n const { placeholders, processedDefinition } = substituteStringLiterals(definition);\n\n // Convert the processed definition (with substituted string literals) into an array of raw tokens.\n const tokens = parseTokensFromDefinition(processedDefinition);\n\n // There must be at least 3 tokens for the tree definition to be valid. 'ROOT', '{' and '}'.\n if (tokens.length < 3) {\n throw new Error(\"invalid token count\");\n }\n\n // We should have a matching number of '{' and '}' tokens. If not, then there are scopes that have not been properly closed.\n if (tokens.filter((token) => token === \"{\").length !== tokens.filter((token) => token === \"}\").length) {\n throw new Error(\"scope character mismatch\");\n }\n\n // Create a stack of node children arrays, starting with a definition scope.\n const stack: [RootAstNode[], ...OtherAstNodes[]] = [[]];\n const rootScope = stack[0];\n\n // We should keep processing the raw tokens until we run out of them.\n while (tokens.length) {\n // Grab the next token.\n const token = tokens.shift();\n\n const currentScope = stack[stack.length - 1] as OtherAstNodes;\n\n // How we create the next AST token depends on the current raw token value.\n switch (token!.toUpperCase()) {\n case \"ROOT\": {\n // Create a ROOT AST node.\n const node = ASTNodeFactories.ROOT();\n\n // Push the ROOT node into the current scope.\n rootScope.push(node);\n\n // We may have a root node name defined as an argument.\n if (tokens[0] === \"[\") {\n const rootArguments = getArguments(tokens, placeholders);\n\n // We should have only a single argument that is not an empty string for a root node, which is the root name identifier.\n if (rootArguments.length === 1 && rootArguments[0].type === \"identifier\") {\n // The root name will be the first and only node argument.\n node.name = rootArguments[0].value as string;\n } else {\n throw new Error(\"expected single root name argument\");\n }\n }\n\n // Try to pick any attributes off of the token stack.\n node.attributes = getAttributes(tokens, placeholders);\n\n popAndCheck(tokens, \"{\");\n\n // The new scope is that of the new ROOT nodes children.\n stack.push(node.children!);\n break;\n }\n\n case \"BRANCH\": {\n // Create a BRANCH AST node.\n const node = ASTNodeFactories.BRANCH();\n\n // Push the BRANCH node into the current scope.\n currentScope.push(node);\n\n // We must have arguments defined, as we require a branch name argument.\n if (tokens[0] !== \"[\") {\n throw new Error(\"expected single branch name argument\");\n }\n\n // The branch name will be defined as a node argument.\n const branchArguments = getArguments(tokens, placeholders);\n\n // We should have only a single identifer argument for a branch node, which is the branch name.\n if (branchArguments.length === 1 && branchArguments[0].type === \"identifier\") {\n // The branch name will be the first and only node argument.\n node.branchName = branchArguments[0].value as string;\n } else {\n throw new Error(\"expected single branch name argument\");\n }\n break;\n }\n\n case \"SELECTOR\": {\n // Create a SELECTOR AST node.\n const node = ASTNodeFactories.SELECTOR();\n\n // Push the SELECTOR node into the current scope.\n currentScope.push(node);\n\n // Try to pick any attributes off of the token stack.\n node.attributes = getAttributes(tokens, placeholders);\n\n popAndCheck(tokens, \"{\");\n\n // The new scope is that of the new SELECTOR nodes children.\n stack.push(node.children!);\n break;\n }\n\n case \"SEQUENCE\": {\n // Create a SEQUENCE AST node.\n const node = ASTNodeFactories.SEQUENCE();\n\n // Push the SEQUENCE node into the current scope.\n currentScope.push(node);\n\n // Try to pick any attributes off of the token stack.\n node.attributes = getAttributes(tokens, placeholders);\n\n popAndCheck(tokens, \"{\");\n\n // The new scope is that of the new SEQUENCE nodes children.\n stack.push(node.children!);\n break;\n }\n\n case \"PARALLEL\": {\n // Create a PARALLEL AST node.\n const node = ASTNodeFactories.PARALLEL();\n\n // Push the PARALLEL node into the current scope.\n currentScope.push(node);\n\n // Try to pick any attributes off of the token stack.\n node.attributes = getAttributes(tokens, placeholders);\n\n popAndCheck(tokens, \"{\");\n\n // The new scope is that of the new PARALLEL nodes children.\n stack.push(node.children!);\n break;\n }\n\n case \"LOTTO\": {\n // Create a LOTTO AST node.\n const node = ASTNodeFactories.LOTTO();\n\n // Push the LOTTO node into the current scope.\n currentScope.push(node);\n\n // If the next token is a '[' character then some ticket counts have been defined as arguments.\n if (tokens[0] === \"[\") {\n // Get the ticket count arguments, each argument must be a number.\n node.tickets = getArguments(\n tokens,\n placeholders,\n (arg) => arg.type === \"number\" && !!arg.isInteger,\n \"lotto node ticket counts must be integer values\"\n ).map((argument) => argument.value as number);\n }\n\n // Try to pick any attributes off of the token stack.\n node.attributes = getAttributes(tokens, placeholders);\n\n popAndCheck(tokens, \"{\");\n\n // The new scope is that of the new LOTTO nodes children.\n stack.push(node.children!);\n break;\n }\n\n case \"CONDITION\": {\n // Create a CONDITION AST node.\n const node = ASTNodeFactories.CONDITION();\n\n // Push the CONDITION node into the current scope.\n currentScope.push(node);\n\n // We must have arguments defined, as we require a condition function name argument.\n if (tokens[0] !== \"[\") {\n throw new Error(\"expected condition name identifier argument\");\n }\n\n // Grab the condition node arguments.\n const conditionArguments = getArguments(tokens, placeholders);\n\n // We should have at least a single identifier argument for a condition node, which is the condition function name.\n if (conditionArguments.length && conditionArguments[0].type === \"identifier\") {\n // The condition function name will be the first node argument.\n node.conditionName = conditionArguments.shift()!.value as string;\n } else {\n throw new Error(\"expected condition name identifier argument\");\n }\n\n // Only the first argument should have been an identifier, all following arguments must be string, number, boolean or null.\n conditionArguments\n .filter((arg) => arg.type === \"identifier\")\n .forEach((arg) => {\n throw new Error(\n \"invalid condition node argument value '\" +\n arg.value +\n \"', must be string, number, boolean or null\"\n );\n });\n\n // Any node arguments that follow the condition name identifier will be treated as condition function arguments.\n node.conditionArguments = conditionArguments;\n\n // Try to pick any attributes off of the token stack.\n node.attributes = getAttributes(tokens, placeholders);\n break;\n }\n\n case \"FLIP\": {\n // Create a FLIP AST node.\n const node = ASTNodeFactories.FLIP();\n\n // Push the Flip node into the current scope.\n currentScope.push(node);\n\n // Try to pick any attributes off of the token stack.\n node.attributes = getAttributes(tokens, placeholders);\n\n popAndCheck(tokens, \"{\");\n\n // The new scope is that of the new FLIP nodes children.\n stack.push(node.children!);\n break;\n }\n\n case \"SUCCEED\": {\n // Create a SUCCEED AST node.\n const node = ASTNodeFactories.SUCCEED();\n\n // Push the Succeed node into the current scope.\n currentScope.push(node);\n\n // Try to pick any attributes off of the token stack.\n node.attributes = getAttributes(tokens, placeholders);\n\n popAndCheck(tokens, \"{\");\n\n // The new scope is that of the new Succeed nodes children.\n stack.push(node.children!);\n break;\n }\n\n case \"FAIL\": {\n // Create a FAIL AST node.\n const node = ASTNodeFactories.FAIL();\n\n // Push the Fail node into the current scope.\n currentScope.push(node);\n\n // Try to pick any attributes off of the token stack.\n node.attributes = getAttributes(tokens, placeholders);\n\n popAndCheck(tokens, \"{\");\n\n // The new scope is that of the new Fail nodes children.\n stack.push(node.children!);\n break;\n }\n\n case \"WAIT\": {\n // Create a WAIT AST node.\n const node = ASTNodeFactories.WAIT();\n\n // Push the WAIT node into the current scope.\n currentScope.push(node);\n\n // The arguments of a wait node are optional. We may have:\n // - No node arguments, in which case the wait will be indefinite until it is aborted.\n // - One node argument which will be the explicit duration of the wait.\n // - Two node arguments which define the min and max duration bounds from which a random duration will be picked.\n if (tokens[0] === \"[\") {\n // Get the optional duration and longest duration of the wait.\n const nodeArguments = getArguments(\n tokens,\n placeholders,\n (arg) => arg.type === \"number\" && !!arg.isInteger,\n \"wait node durations must be integer values\"\n ).map((argument) => argument.value);\n\n // We may have:\n // - One node argument which will be the explicit duration of the wait.\n // - Two node arguments which define the min and max duration bounds from which a random duration will be picked.\n // - Too many arguments, which is not valid.\n if (nodeArguments.length === 1) {\n // An explicit duration was defined.\n node.duration = nodeArguments[0] as number;\n } else if (nodeArguments.length === 2) {\n // Min and max duration bounds were defined from which a random duration will be picked.\n node.durationMin = nodeArguments[0] as number;\n node.durationMax = nodeArguments[1] as number;\n } else if (nodeArguments.length > 2) {\n // An incorrect number of durations was defined.\n throw new Error(\"invalid number of wait node duration arguments defined\");\n }\n }\n\n // Try to pick any attributes off of the token stack.\n node.attributes = getAttributes(tokens, placeholders);\n break;\n }\n\n case \"REPEAT\": {\n // Create a REPEAT AST node.\n const node = ASTNodeFactories.REPEAT();\n\n // Push the REPEAT node into the current scope.\n currentScope.push(node);\n\n // The arguments of a repeat node are optional. We may have:\n // - No node arguments, in which case the repeat note will iterate indefinitely.\n // - One node argument which will be the explicit number of iterations to make.\n // - Two node arguments which define the min and max iteration bounds from which a random iteration count will be picked.\n if (tokens[0] === \"[\") {\n // An iteration count has been defined. Get the iteration and potential maximum iteration of the wait.\n const nodeArguments = getArguments(\n tokens,\n placeholders,\n (arg) => arg.type === \"number\" && !!arg.isInteger,\n \"repeat node iteration counts must be integer values\"\n ).map((argument) => argument.value);\n\n // We should have got one or two iteration counts.\n if (nodeArguments.length === 1) {\n // A static iteration count was defined.\n node.iterations = nodeArguments[0] as number;\n } else if (nodeArguments.length === 2) {\n // A minimum and maximum iteration count was defined.\n node.iterationsMin = nodeArguments[0] as number;\n node.iterationsMax = nodeArguments[1] as number;\n } else {\n // An incorrect number of iteration counts was defined.\n throw new Error(\"invalid number of repeat node iteration count arguments defined\");\n }\n }\n\n // Try to pick any attributes off of the token stack.\n node.attributes = getAttributes(tokens, placeholders);\n\n popAndCheck(tokens, \"{\");\n\n // The new scope is that of the new REPEAT nodes children.\n stack.push(node.children!);\n break;\n }\n\n case \"RETRY\": {\n // Create a RETRY AST node.\n const node = ASTNodeFactories.RETRY();\n\n // Push the RETRY node into the current scope.\n currentScope.push(node);\n\n // The arguments of a retry node are optional. We may have:\n // - No node arguments, in which case the retry note will attempt indefinitely.\n // - One node argument which will be the explicit number of attempts to make.\n // - Two node arguments which define the min and max attempt bounds from which a random attempt count will be picked.\n if (tokens[0] === \"[\") {\n // An attempt count has been defined. Get the attempt count and potential maximum attempt count of the wait.\n const nodeArguments = getArguments(\n tokens,\n placeholders,\n (arg) => arg.type === \"number\" && !!arg.isInteger,\n \"retry node attempt counts must be integer values\"\n ).map((argument) => argument.value);\n\n // We should have got one or two attempt counts.\n if (nodeArguments.length === 1) {\n // A static attempt count was defined.\n node.attempts = nodeArguments[0] as number;\n } else if (nodeArguments.length === 2) {\n // A minimum and maximum attempt count was defined.\n node.attemptsMin = nodeArguments[0] as number;\n node.attemptsMax = nodeArguments[1] as number;\n } else {\n // An incorrect number of attempt counts was defined.\n throw new Error(\"invalid number of retry node attempt count arguments defined\");\n }\n }\n\n // Try to pick any attributes off of the token stack.\n node.attributes = getAttributes(tokens, placeholders);\n\n popAndCheck(tokens, \"{\");\n\n // The new scope is that of the new RETRY nodes children.\n stack.push(node.children!);\n break;\n }\n\n case \"ACTION\": {\n // Create a ACTION AST node.\n const node = ASTNodeFactories.ACTION();\n\n // Push the ACTION node into the current scope.\n currentScope.push(node);\n\n // We must have arguments defined, as we require an action name argument.\n if (tokens[0] !== \"[\") {\n throw new Error(\"expected action name identifier argument\");\n }\n\n // The action name will be defined as a node argument.\n const actionArguments = getArguments(tokens, placeholders);\n\n // We should have at least one identifer argument for an action node, which is the action name.\n if (actionArguments.length && actionArguments[0].type === \"identifier\") {\n // The action name will be the first and only node argument.\n node.actionName = actionArguments.shift()!.value as string;\n } else {\n throw new Error(\"expected action name identifier argument\");\n }\n\n // Only the first argument should have been an identifier, all following arguments must be string, number, boolean or null.\n actionArguments\n .filter((arg) => arg.type === \"identifier\")\n .forEach((arg) => {\n throw new Error(\n \"invalid action node argument value '\" +\n arg.value +\n \"', must be string, number, boolean or null\"\n );\n });\n\n // Any node arguments that follow the action name identifier will be treated as action function arguments.\n node.actionArguments = actionArguments;\n\n // Try to pick any attributes off of the token stack.\n node.attributes = getAttributes(tokens, placeholders);\n break;\n }\n\n case \"}\": {\n // The '}' character closes the current scope.\n stack.pop();\n break;\n }\n\n default: {\n throw new Error(`unexpected token '${token}'`);\n }\n }\n }\n\n // A function to recursively validate each of the nodes in the AST.\n const validateASTNode = (node: Validatable, depth: number): void => {\n // Validate the node.\n node.validate(depth);\n\n // Validate each child of the node.\n (node.children || []).forEach((child) => validateASTNode(child, depth + 1));\n };\n\n // Start node validation from the definition root.\n validateASTNode(\n {\n children: stack[0] as RootAstNode[],\n validate(this: { children: RootAstNode[] }) {\n // We must have at least one node defined as the definition scope, which should be a root node.\n if (this.children.length === 0) {\n throw new Error(\"expected root node to have been defined\");\n }\n\n // Each node at the base of the definition scope MUST be a root node.\n for (const definitionLevelNode of this.children) {\n if (definitionLevelNode.type !== \"root\") {\n throw new Error(\"expected root node at base of definition\");\n }\n }\n\n // Exactly one root node must not have a name defined. This will be the main root, others will have to be referenced via branch nodes.\n if (this.children.filter((definitionLevelNode) => definitionLevelNode.name === null).length !== 1) {\n throw new Error(\"expected single unnamed root node at base of definition to act as main root\");\n }\n\n // No two named root nodes can have matching names.\n const rootNodeNames: string[] = [];\n for (const definitionLevelNode of this.children) {\n if (rootNodeNames.indexOf(definitionLevelNode.name!) !== -1) {\n throw new Error(`multiple root nodes found with duplicate name '${definitionLevelNode.name}'`);\n } else {\n rootNodeNames.push(definitionLevelNode.name!);\n }\n }\n }\n },\n 0\n );\n\n // Return the root AST nodes.\n return stack[0];\n}\n\n/**\n * Pop the next raw token off of the stack and throw an error if it wasn't the expected one.\n * @param tokens The array of remaining tokens.\n * @param expected An optional string or array or items, one of which must match the next popped token.\n * @returns The popped token.\n */\nfunction popAndCheck(tokens: string[], expected: string | string[]) {\n // Get and remove the next token.\n const popped = tokens.shift();\n\n // We were expecting another token.\n if (popped === undefined) {\n throw new Error(\"unexpected end of definition\");\n }\n\n // Do we have an expected token/tokens array?\n if (expected !== undefined) {\n // Check whether the popped token matches at least one of our expected items.\n var tokenMatchesExpectation = ([] as string[])\n .concat(expected)\n .some((item) => popped.toUpperCase() === item.toUpperCase());\n\n // Throw an error if the popped token didn't match any of our expected items.\n if (!tokenMatchesExpectation) {\n const expectationString = ([] as string[])\n .concat(expected)\n .map((item) => \"'\" + item + \"'\")\n .join(\" or \");\n\n throw new Error(`unexpected token found. Expected '${expectationString}' but got '${popped}'`);\n }\n }\n\n // Return the popped token.\n return popped;\n}\n\ntype StringPlaceholders = { [key: string]: string };\n\n/**\n * Pull an argument definition list off of the token stack.\n * @param tokens The array of remaining tokens.\n * @param stringArgumentPlaceholders The mapping of string literal node argument placeholders to original values.\n * @param argumentValidator The argument validator function.\n * @param validationFailedMessage The exception message to throw if argument validation fails.\n * @returns The argument definition list.\n */\nfunction getArguments(\n tokens: string[],\n stringArgumentPlaceholders: StringPlaceholders,\n argumentValidator?: (arg: AnyArgument) => boolean,\n validationFailedMessage?: string\n) {\n // Any lists of arguments will always be wrapped in '[]' for node arguments or '()' for attribute arguments.\n // We are looking for a '[' or '(' opener that wraps the argument tokens and the relevant closer.\n const closer = popAndCheck(tokens, [\"[\", \"(\"]) === \"[\" ? \"]\" : \")\";\n\n const argumentListTokens: string[] = [];\n const argumentList: AnyArgument[] = [];\n\n // Grab all tokens between the '[' and ']' or '(' and ')'.\n while (tokens.length && tokens[0] !== closer) {\n // The next token is part of our arguments list.\n argumentListTokens.push(tokens.shift()!);\n }\n\n // Validate the order of the argument tokens. Each token must either be a ',' or a single argument that satisfies the validator.\n argumentListTokens.forEach((token, index) => {\n // Get whether this token should be an actual argument.\n const shouldBeArgumentToken = !(index & 1);\n\n // If the current token should be an actual argument then validate it,otherwise it should be a ',' token.\n if (shouldBeArgumentToken) {\n // Get the argument definition.\n const argumentDefinition = getArgumentDefinition(token!, stringArgumentPlaceholders);\n\n // Try to validate the argument.\n if (argumentValidator && !argumentValidator(argumentDefinition)) {\n throw new Error(validationFailedMessage);\n }\n\n // This is a valid argument!\n argumentList.push(argumentDefinition);\n } else {\n // The current token should be a ',' token.\n if (token !== \",\") {\n throw new Error(`invalid argument list, expected ',' or ']' but got '${token}'`);\n }\n }\n });\n\n // The arguments list should terminate with a ']' or ')' token, depending on the opener.\n popAndCheck(tokens, closer);\n\n // Return the argument list.\n return argumentList;\n}\n\n/**\n * Gets an argument value definition.\n * @param token The argument token.\n * @param stringArgumentPlaceholders The mapping of string literal node argument placeholders to original values.\n * @returns An argument value definition.\n */\nfunction getArgumentDefinition(token: string, stringArgumentPlaceholders: StringPlaceholders): AnyArgument {\n // Check whether the token represents a null value.\n if (token === \"null\") {\n return {\n value: null,\n type: \"null\"\n } as NullArgument;\n }\n\n // Check whether the token represents a boolean value.\n if (token === \"true\" || token === \"false\") {\n return {\n value: token === \"true\",\n type: \"boolean\"\n } as BooleanArgument;\n }\n\n // Check whether the token represents a number value.\n // TODO: Relies on broken isNaN - see MDN.\n // if (!Number.isNaN(token)) {\n if (!isNaN(token as any)) {\n return {\n value: parseFloat(token),\n isInteger: parseFloat(token) === parseInt(token, 10),\n type: \"number\"\n } as NumberArgument;\n }\n\n // Check whether the token is a placeholder (e.g. @@0@@) representing a string literal.\n if (token.match(/^@@\\d+@@$/g)) {\n return {\n value: stringArgumentPlaceholders[token].replace('\\\\\"', '\"'),\n type: \"string\"\n } as StringPlaceholderArgument;\n }\n\n // The only remaining option is that the argument value is an identifier.\n return {\n value: token,\n type: \"identifier\"\n } as IdentifierArgument;\n}\n\n/**\n * Pull any attributes off of the token stack.\n * @param tokens The array of remaining tokens.\n * @param stringArgumentPlaceholders The mapping of string literal node argument placeholders to original values.\n * @returns An array of attributes defined by any directly following tokens.\n */\nfunction getAttributes(tokens: string[], stringArgumentPlaceholders: StringPlaceholders) {\n // Create an array to hold any attributes found.\n const attributes: Attribute[] = [];\n\n // Keep track of names of attribute that we have found on the token stack, as we cannot have duplicates.\n const attributesFound: string[] = [];\n\n // Try to get the attribute factory for the next token.\n let attributeFactory = AttributeFactories[(tokens[0] || \"\").toUpperCase()];\n\n // Pull attribute tokens off of the tokens stack until we have no more.\n while (attributeFactory) {\n // Check to make sure that we have not already created a attribute of this type for this node.\n if (attributesFound.indexOf(tokens[0].toUpperCase()) !== -1) {\n throw new Error(`duplicate attribute '${tokens[0].toUpperCase()}' found for node`);\n }\n\n // Add the current attribute type to our array of found attributes.\n attributesFound.push(tokens.shift()!.toUpperCase());\n\n // Grab any attribute arguments.\n const attributeArguments = getArguments(tokens, stringArgumentPlaceholders);\n\n // The first attribute argument has to be an identifer, this will reference an agent function.\n if (attributeArguments.length === 0 || attributeArguments[0].type !== \"identifier\") {\n throw new Error(\"expected agent function name identifier argument for attribute\");\n }\n\n // Grab the first attribute which is an identifier that will reference an agent function.\n const attributeFunctionName = attributeArguments.shift()! as IdentifierArgument;\n\n // Any remaining attribute arguments must have a type of string, number, boolean or null.\n attributeArguments\n .filter((arg) => arg.type === \"identifier\")\n .forEach((arg) => {\n throw new Error(\n \"invalid attribute argument value '\" + arg.value + \"', must be string, number, boolean or null\"\n );\n });\n\n // Create the attribute and add it to the array of attributes found.\n attributes.push(attributeFactory(attributeFunctionName.value, attributeArguments));\n\n // Try to get the next attribute name token, as there could be multiple.\n attributeFactory = AttributeFactories[(tokens[0] || \"\").toUpperCase()];\n }\n\n return attributes;\n}\n\n/**\n * Swaps out any node/attribute argument string literals with placeholders.\n * @param definition The definition.\n * @returns An object containing a mapping of placeholders to original string values as well as the processed definition string.\n */\nfunction substituteStringLiterals(definition: string): {\n placeholders: { [key: string]: string };\n processedDefinition: string;\n} {\n // Create an object to hold the mapping of placeholders to original string values.\n const placeholders: StringPlaceholders = {};\n\n // Replace any string literals wrapped with double quotes in our definition with placeholders to be processed later.\n const processedDefinition = definition.replace(/\\\"(\\\\.|[^\"\\\\])*\\\"/g, (match) => {\n var strippedMatch = match.substring(1, match.length - 1);\n var placeholder = Object.keys(placeholders).find((key) => placeholders[key] === strippedMatch);\n\n // If we have no existing string literal match then create a new placeholder.\n if (!placeholder) {\n placeholder = `@@${Object.keys(placeholders).length}@@`;\n placeholders[placeholder] = strippedMatch;\n }\n\n return placeholder;\n });\n\n return { placeholders, processedDefinition };\n}\n\n/**\n * Parse the tree definition into an array of raw tokens.\n * @param definition The definition.\n * @returns An array of tokens parsed from the definition.\n */\nfunction parseTokensFromDefinition(definition: string): string[] {\n // Add some space around various important characters so that they can be plucked out easier as individual tokens.\n definition = definition.replace(/\\(/g, \" ( \");\n definition = definition.replace(/\\)/g, \" ) \");\n definition = definition.replace(/\\{/g, \" { \");\n definition = definition.replace(/\\}/g, \" } \");\n definition = definition.replace(/\\]/g, \" ] \");\n definition = definition.replace(/\\[/g, \" [ \");\n definition = definition.replace(/\\,/g, \" , \");\n\n // Split the definition into raw token form and return it.\n return definition.replace(/\\s+/g, \" \").trim().split(\" \");\n}\n", "import GuardPath, { GuardPathPart } from \"./attributes/guards/GuardPath\";\nimport buildRootASTNodes, { AnyArgument, RootAstNode } from \"./RootAstNodesBuilder\";\nimport State, { AnyState } from \"./State\";\nimport Lookup from \"./Lookup\";\nimport Node from \"./nodes/Node\";\nimport Root from \"./nodes/decorator/Root\";\nimport Composite from \"./nodes/composite/Composite\";\nimport Decorator from \"./nodes/decorator/Decorator\";\nimport { Agent, GlobalFunction } from \"./Agent\";\nimport { CallbackAttributeDetails } from \"./attributes/callbacks/Callback\";\nimport { GuardAttributeDetails } from \"./attributes/guards/Guard\";\nimport { BehaviourTreeOptions } from \"./BehaviourTreeOptions\";\nimport { parseMDSLToJSON } from \"./mdsl/MDSLDefinitionParser\";\n\n// Purely for outside inspection of the tree.\nexport type FlattenedTreeNode = {\n id: string;\n type: string;\n caption: string;\n state: AnyState;\n guards: GuardAttributeDetails[];\n callbacks: CallbackAttributeDetails[];\n args: AnyArgument[];\n parentId: string | null;\n};\n\n/**\n * A representation of a behaviour tree.\n */\nexport class BehaviourTree {\n /**\n * The main root tree node.\n */\n public readonly rootNode: Root;\n\n /**\n * Creates a new instance of the BehaviourTree class.\n * @param definition The behaviour tree definition.\n * @param agent The agent instance that this behaviour tree is modelling behaviour for.\n * @param options The behaviour tree options object.\n */\n constructor(definition: string, private agent: Agent, private options: BehaviourTreeOptions = {}) {\n // The tree definition must be defined and a valid string.\n if (typeof definition !== \"string\") {\n throw new Error(\"the tree definition must be a string\");\n }\n\n // The agent must be defined and not null.\n if (typeof agent !== \"object\" || agent === null) {\n throw new Error(\"the agent must be defined and not null\");\n }\n\n // Parse the behaviour tree definition, create the populated tree of behaviour tree nodes, and get the root.\n this.rootNode = BehaviourTree._createRootNode(definition);\n }\n\n /**\n * Gets whether the tree is in the RUNNING state.\n * @returns true if the tree is in the RUNNING state, otherwise false.\n */\n isRunning() {\n return this.rootNode.getState() === State.RUNNING;\n }\n\n /**\n * Gets the current tree state of SUCCEEDED, FAILED, READY or RUNNING.\n * @returns The current tree state.\n */\n getState() {\n return this.rootNode.getState();\n }\n\n /**\n * Step the tree.\n * 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.\n * 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\n * 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.\n *\n * 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.\n */\n step() {\n // If the root node has already been stepped to completion then we need to reset it.\n if (this.rootNode.getState() === State.SUCCEEDED || this.rootNode.getState() === State.FAILED) {\n this.rootNode.reset();\n }\n\n try {\n this.rootNode.update(this.agent, this.options);\n } catch (exception) {\n throw new Error(`error stepping tree: ${(exception as Error).message}`);\n }\n }\n\n /**\n * Resets the tree from the root node outwards to each nested node, giving each a state of READY.\n */\n reset() {\n this.rootNode.reset();\n }\n\n /**\n * Gets the flattened details of every node in the tree.\n * @returns The flattened details of every node in the tree.\n */\n getFlattenedNodeDetails(): FlattenedTreeNode[] {\n // Create an empty flattened array of tree nodes.\n const flattenedTreeNodes: FlattenedTreeNode[] = [];\n\n /**\n * Helper function to process a node instance and push details into the flattened tree nodes array.\n * @param node The current node.\n * @param parentUid The UID of the node parent, or null if the node is the main root node.\n */\n const processNode = (node: Node, parentUid: string | null) => {\n // Get the guard and callback attribute details for this node.\n const guards = node\n .getAttributes()\n .filter((attribute) => attribute.isGuard())\n .map((attribute) => attribute.getDetails()) as GuardAttributeDetails[];\n const callbacks = node\n .getAttributes()\n .filter((attribute) => !attribute.isGuard())\n .map((attribute) => attribute.getDetails()) as CallbackAttributeDetails[];\n\n // Push the current node into the flattened nodes array.\n flattenedTreeNodes.push({\n id: node.getUid(),\n type: node.getType(),\n caption: node.getName(),\n state: node.getState(),\n guards,\n callbacks,\n args: node.getArguments(),\n parentId: parentUid\n });\n\n // Process each of the nodes children if it is not a leaf node.\n if (!node.isLeafNode()) {\n (node as Composite | Decorator)\n .getChildren()\n .forEach((child) => processNode(child, (node as Composite | Decorator).getUid()));\n }\n };\n\n // Convert the nested node structure into a flattened array of node details.\n processNode(this.rootNode, null);\n\n return flattenedTreeNodes;\n }\n\n /**\n * Registers the action/condition/guard/callback function or subtree with the given name.\n * @param name The name of the function or subtree to register.\n * @param value The function or subtree definition to register.\n */\n static register(name: string, value: GlobalFunction | string) {\n if (typeof value === \"function\") {\n // We are going to register a action/condition/guard/callback function.\n Lookup.setFunc(name, value);\n } else if (typeof value === \"string\") {\n // We are going to register a subtree.\n let rootASTNodes: RootAstNode[];\n\n try {\n // Try to create the behaviour tree AST based on the definition provided, this could fail if the definition is invalid.\n rootASTNodes = buildRootASTNodes(value);\n } catch (exception) {\n // There was an issue in trying to parse and build the tree definition.\n throw new Error(`error registering definition: ${(exception as Error).message}`);\n }\n\n // This function should only ever be called with a definition containing a single unnamed root node.\n if (rootASTNodes.length != 1 || rootASTNodes[0].name !== null) {\n throw new Error(\"error registering definition: expected a single unnamed root node\");\n }\n\n Lookup.setSubtree(name, rootASTNodes[0]);\n } else {\n throw new Error(\"unexpected value, expected string definition or function\");\n }\n }\n\n /**\n * Unregisters the registered action/condition/guard/callback function or subtree with the given name.\n * @param name The name of the registered action/condition/guard/callback function or subtree to unregister.\n */\n static unregister(name: string): void {\n Lookup.remove(name);\n }\n\n /**\n * Unregister all registered action/condition/guard/callback functions and subtrees.\n */\n static unregisterAll(): void {\n Lookup.empty();\n }\n\n /**\n * Parses a behaviour tree definition and creates a tree of behaviour tree nodes.\n * @param {string} definition The behaviour tree definition.\n * @returns The root behaviour tree node.\n */\n private static _createRootNode(definition: string): Root {\n // TODO Remove!\n try {\n // parseToJSON(definition);\n } catch (exception) {\n console.log(exception);\n }\n\n try {\n // Try to create the behaviour tree AST based on the definition provided, this could fail if the definition is invalid.\n const rootASTNodes = buildRootASTNodes(definition);\n\n // Create a symbol to use as the main root key in our root node mapping.\n const mainRootNodeKey = Symbol(\"__root__\");\n\n // Create a mapping of root node names to root AST tokens. The main root node will have a key of Symbol(\"__root__\").\n const rootNodeMap: { [key: string | symbol]: RootAstNode } = {};\n for (const rootASTNode of rootASTNodes) {\n rootNodeMap[rootASTNode.name === null ? mainRootNodeKey : rootASTNode.name!] = rootASTNode;\n }\n\n // Convert the AST to our actual tree and get the root node.\n const rootNode: Root = rootNodeMap[mainRootNodeKey].createNodeInstance(\n // Create a provider for named root nodes that are part of our definition or have been registered. Prioritising the former.\n (name: string): RootAstNode => (rootNodeMap[name] ? rootNodeMap[name] : Lookup.getSubtree(name)),\n []\n );\n\n // Set a guard path on every leaf of the tree to evaluate as part of its update.\n BehaviourTree._applyLeafNodeGuardPaths(rootNode);\n\n // Return the root node.\n return rootNode;\n } catch (exception) {\n // There was an issue in trying to parse and build the tree definition.\n throw new Error(`error parsing tree: ${(exception as Error).message}`);\n }\n }\n\n /**\n * Applies a guard path to every leaf of the tree to evaluate as part of each update.\n * @param rootNode The main root tree node.\n */\n private static _applyLeafNodeGuardPaths(rootNode: Root) {\n const nodePaths: Node[][] = [];\n\n const findLeafNodes = (path: Node[], node: Node) => {\n // Add the current node to the path.\n path = path.concat(node);\n\n // Check whether the current node is a leaf node.\n if (node.isLeafNode()) {\n nodePaths.push(path);\n } else {\n (node as Composite | Decorator).getChildren().forEach((child) => findLeafNodes(path, child));\n }\n };\n\n // Find all leaf node paths, starting from the root.\n findLeafNodes([], rootNode);\n\n nodePaths.forEach((path) => {\n // Each node in the current path will have to be assigned a guard path, working from the root outwards.\n for (let depth = 0; depth < path.length; depth++) {\n // Get the node in the path at the current depth.\n const currentNode = path[depth];\n\n // The node may already have been assigned a guard path, if so just skip it.\n if (currentNode.hasGuardPath()) {\n continue;\n }\n\n // Create the guard path for the current node.\n const guardPath = new GuardPath(\n path\n .slice(0, depth + 1)\n .map((node) => ({ node, guards: node.getGuardAttributes() }))\n .filter((details) => details.guards.length > 0)\n );\n\n // Assign the guard path to the current node.\n currentNode.setGuardPath(guardPath);\n }\n });\n }\n}\n", "import {\n CompositeNodeDefinition,\n DecoratorNodeDefinition,\n NodeDefinition,\n RootNodeDefinition\n} from \"../BehaviourTreeDefinition\";\n\n/**\n * A type defining an object that holds a reference to substitued string literals parsed from the definition.\n */\nexport type StringLiteralPlaceholders = { [key: string]: string };\n\n/**\n * A type guard function that returns true if the specified node satisfies the RootNodeDefinition type.\n * @param node The node.\n * @returns A value of true if the specified node satisfies the RootNodeDefinition type.\n */\nexport function isRootNode(node: NodeDefinition): node is RootNodeDefinition {\n return node.type === \"root\";\n}\n\n/**\n * A type guard function that returns true if the specified node satisfies the NodeDefinition type.\n * @param node The node.\n * @returns A value of true if the specified node satisfies the NodeDefinition type.\n */\nexport function isLeafNode(node: NodeDefinition): node is NodeDefinition {\n return [\"branch\", \"action\", \"condition\", \"wait\"].includes(node.type);\n}\n\n/**\n * A type guard function that returns true if the specified node satisfies the DecoratorNodeDefinition type.\n * @param node The node.\n * @returns A value of true if the specified node satisfies the DecoratorNodeDefinition type.\n */\nexport function isDecoratorNode(node: NodeDefinition): node is DecoratorNodeDefinition {\n return [\"root\", \"repeat\", \"retry\", \"flip\", \"succeed\", \"fail\"].includes(node.type);\n}\n\n/**\n * A type guard function that returns true if the specified node satisfies the CompositeNodeDefinition type.\n * @param node The node.\n * @returns A value of true if the specified node satisfies the CompositeNodeDefinition type.\n */\nexport function isCompositeNode(node: NodeDefinition): node is CompositeNodeDefinition {\n return [\"sequence\", \"selector\", \"lotto\", \"parallel\"].includes(node.type);\n}\n\n/**\n * Pop the next raw token from the specified array of tokens and throw an error if it wasn't the expected one.\n * @param tokens The array of tokens.\n * @param expected An optional string or array or items, one of which must match the next popped token.\n * @returns The popped token.\n */\nexport function popAndCheck(tokens: string[], expected?: string | string[]): string {\n // Get and remove the next token.\n const popped = tokens.shift();\n\n // We were expecting another token but there aren't any.\n if (popped === undefined) {\n throw new Error(\"unexpected end of definition\");\n }\n\n // Do we have an expected token/tokens array?\n if (expected != undefined) {\n // Get an array of expected values, if the popped token matches any then we are all good.\n const expectedValues = typeof expected === \"string\" ? [expected] : expected;\n\n // Check whether the popped token matches at least one of our expected items.\n var tokenMatchesExpectation = expectedValues.some((item) => popped.toUpperCase() === item.toUpperCase());\n\n // Throw an error if the popped token didn't match any of our expected items.\n if (!tokenMatchesExpectation) {\n const expectationString = expectedValues.map((item) => \"'\" + item + \"'\").join(\" or \");\n throw new Error(\"unexpected token found. Expected \" + expectationString + \" but got '\" + popped + \"'\");\n }\n }\n\n // Return the popped token.\n return popped;\n}\n\n/**\n * Swaps out any node/attribute argument string literals with placeholders.\n * @param definition The definition.\n * @returns An object containing a mapping of placeholders to original string values as well as the processed definition string.\n */\nexport function substituteStringLiterals(definition: string): {\n placeholders: StringLiteralPlaceholders;\n processedDefinition: string;\n} {\n // Create an object to hold the mapping of placeholders to original string values.\n const placeholders: StringLiteralPlaceholders = {};\n\n // Replace any string literals wrapped with double quotes in our definition with placeholders to be processed later.\n const processedDefinition = definition.replace(/\\\"(\\\\.|[^\"\\\\])*\\\"/g, (match) => {\n var strippedMatch = match.substring(1, match.length - 1);\n var placeholder = Object.keys(placeholders).find((key) => placeholders[key] === strippedMatch);\n\n // If we have no existing string literal match then create a new placeholder.\n if (!placeholder) {\n placeholder = `@@${Object.keys(placeholders).length}@@`;\n placeholders[placeholder] = strippedMatch;\n }\n\n return placeholder;\n });\n\n return { placeholders, processedDefinition };\n}\n\n/**\n * Parse the tree definition into an array of raw tokens.\n * @param definition The definition.\n * @returns An array of tokens parsed from the definition.\n */\nexport function parseTokensFromDefinition(definition: string): string[] {\n // Add some space around various important characters so that they can be plucked out easier as individual tokens.\n definition = definition.replace(/\\(/g, \" ( \");\n definition = definition.replace(/\\)/g, \" ) \");\n definition = definition.replace(/\\{/g, \" { \");\n definition = definition.replace(/\\}/g, \" } \");\n definition = definition.replace(/\\]/g, \" ] \");\n definition = definition.replace(/\\[/g, \" [ \");\n definition = definition.replace(/\\,/g, \" , \");\n\n // Split the definition into raw token form and return it.\n return definition.replace(/\\s+/g, \" \").trim().split(\" \");\n}\n", "import { StringLiteralPlaceholders, popAndCheck } from \"./MDSLUtilities\";\n\nexport type Argument = {\n /** The argument value. */\n value: T;\n /** The argument type, used for validation. */\n type: string;\n};\n\nexport type NullArgument = Argument & {\n type: \"null\";\n};\n\nexport type BooleanArgument = Argument & {\n type: \"boolean\";\n};\n\nexport type NumberArgument = Argument & {\n type: \"number\";\n isInteger: boolean; // Used for validation.\n};\n\nexport type StringPlaceholderArgument = Argument & {\n type: \"string\";\n};\n\nexport type IdentifierArgument = Argument & {\n type: \"identifier\";\n};\n\nexport type AnyArgument =\n | NullArgument\n | BooleanArgument\n | NumberArgument\n | StringPlaceholderArgument\n | IdentifierArgument;\n\n/**\n * Parse an array of argument definitions from the specified tokens array.\n * @param tokens The array tokens to parse the argument definitions from.\n * @param stringArgumentPlaceholders The mapping of string literal node argument placeholders to original values.\n * @param argumentValidator The argument validator function.\n * @param validationFailedMessage The exception message to throw if argument validation fails.\n * @returns An array of argument definitions parsed from the specified tokens array.\n */\nexport function parseArgumentTokens(\n tokens: string[],\n stringArgumentPlaceholders: StringLiteralPlaceholders\n): AnyArgument[] {\n const argumentList: AnyArgument[] = [];\n\n // If the next token is not a '[' or '(' then we have no arguments to parse.\n if (![\"[\", \"(\"].includes(tokens[0])) {\n return argumentList;\n }\n\n // Any lists of arguments will always be wrapped in '[]' for node arguments or '()' for attribute arguments.\n // We are looking for a '[' or '(' opener that wraps the argument tokens and the relevant closer.\n const closingToken = popAndCheck(tokens, [\"[\", \"(\"]) === \"[\" ? \"]\" : \")\";\n\n const argumentListTokens: string[] = [];\n\n // Grab all tokens between the '[' and ']' or '(' and ')'.\n while (tokens.length && tokens[0] !== closingToken) {\n // The next token is part of our arguments list.\n argumentListTokens.push(tokens.shift()!);\n }\n\n // Validate the order of the argument tokens. Each token must either be a ',' or a single argument that satisfies the validator.\n argumentListTokens.forEach((token, index) => {\n // Get whether this token should be an actual argument.\n const shouldBeArgumentToken = !(index & 1);\n\n // If the current token should be an actual argument then validate it, otherwise it should be a ',' token.\n if (shouldBeArgumentToken) {\n // Get the argument definition.\n const argumentDefinition = getArgumentDefinition(token, stringArgumentPlaceholders);\n\n // This is a valid argument!\n argumentList.push(argumentDefinition);\n } else {\n // The current token should be a ',' token.\n if (token !== \",\") {\n throw new Error(`invalid argument list, expected ',' or ']' but got '${token}'`);\n }\n }\n });\n\n // The arguments list should terminate with a ']' or ')' token, depending on the opener.\n popAndCheck(tokens, closingToken);\n\n // Return the arguments.\n return argumentList;\n}\n\n/**\n * Gets an argument value definition.\n * @param token The argument token.\n * @param stringArgumentPlaceholders The mapping of string literal node argument placeholders to original values.\n * @returns An argument value definition.\n */\nfunction getArgumentDefinition(token: string, stringArgumentPlaceholders: StringLiteralPlaceholders): AnyArgument {\n // Check whether the token represents a null value.\n if (token === \"null\") {\n return {\n value: null,\n type: \"null\"\n } as NullArgument;\n }\n\n // Check whether the token represents a boolean value.\n if (token === \"true\" || token === \"false\") {\n return {\n value: token === \"true\",\n type: \"boolean\"\n } as BooleanArgument;\n }\n\n // Check whether the token represents a number value.\n // TODO: Relies on broken isNaN - see MDN.\n // if (!Number.isNaN(token)) {\n if (!isNaN(token as any)) {\n return {\n value: parseFloat(token),\n isInteger: parseFloat(token) === parseInt(token, 10),\n type: \"number\"\n } as NumberArgument;\n }\n\n // Check whether the token is a placeholder (e.g. @@0@@) representing a string literal.\n if (token.match(/^@@\\d+@@$/g)) {\n return {\n value: stringArgumentPlaceholders[token].replace('\\\\\"', '\"'),\n type: \"string\"\n } as StringPlaceholderArgument;\n }\n\n // The only remaining option is that the argument value is an identifier.\n return {\n value: token,\n type: \"identifier\"\n } as IdentifierArgument;\n}\n", "import { NodeAttributeDefinition } from \"../BehaviourTreeDefinition\";\nimport { parseArgumentTokens } from \"./MDSLNodeArgumentParser\";\nimport { StringLiteralPlaceholders } from \"./MDSLUtilities\";\n\n/**\n * A type defining the attribute definitions of a node.\n */\ntype NodeAttributes = {\n while?: NodeAttributeDefinition;\n until?: NodeAttributeDefinition;\n entry?: NodeAttributeDefinition;\n exit?: NodeAttributeDefinition;\n step?: NodeAttributeDefinition;\n};\n\n/**\n * Parse any node attribute definitions from the specified tokens array.\n * @param tokens The array of remaining tokens.\n * @param stringArgumentPlaceholders The mapping of string literal node argument placeholders to original values.\n * @returns An object of attribute definitions defined by any directly following tokens.\n */\nexport function parseAttributeTokens(\n tokens: string[],\n stringArgumentPlaceholders: StringLiteralPlaceholders\n): NodeAttributes {\n const nodeAttributeNames: (keyof NodeAttributes)[] = [\"while\", \"until\", \"entry\", \"exit\", \"step\"];\n\n // Create an object to hold any attributes found.\n const attributes: NodeAttributes = {};\n\n // Try to get the name of the attribute for the next token.\n let nextAttributeName = tokens[0]?.toLowerCase() as keyof NodeAttributes;\n\n // Pull attribute tokens as well as their arguments off of the tokens stack until we have no more.\n while (nodeAttributeNames.includes(nextAttributeName)) {\n // Check to make sure that we have not already created an attribute definition of this type.\n if (attributes[nextAttributeName]) {\n throw new Error(`duplicate attribute '${tokens[0].toUpperCase()}' found for node`);\n }\n\n // Remove the attribute name token from the array of tokens.\n tokens.shift();\n\n // Grab the attribute arguments, assuming the first to be an identifier.\n const [attributeCallIdentifier, ...attributeArguments] = parseArgumentTokens(\n tokens,\n stringArgumentPlaceholders\n );\n\n // The first attribute argument has to be an identifer, this will reference an agent function.\n if (attributeCallIdentifier?.type !== \"identifier\") {\n throw new Error(\"expected agent function name identifier argument for attribute\");\n }\n\n // Any attribute arguments (other than the expected call identifier) must have a type of string, number, boolean or null.\n attributeArguments\n .filter((arg) => arg.type === \"identifier\")\n .forEach((arg) => {\n throw new Error(\n `invalid attribute argument value '${arg.value}', must be string, number, boolean or null`\n );\n });\n\n // Create the attribute definition and add it to the object of attribute definitions found.\n attributes[nextAttributeName] = {\n call: attributeCallIdentifier.value,\n args: attributeArguments.map(({ value }) => value)\n };\n\n // Try to get the next attribute name token, as there could be multiple.\n nextAttributeName = tokens[0]?.toLowerCase() as keyof NodeAttributes;\n }\n\n return attributes;\n}\n", "import {\n ActionNodeDefinition,\n AnyChildNode,\n AnyNode,\n BranchNodeDefinition,\n ConditionNodeDefinition,\n FailNodeDefinition,\n FlipNodeDefinition,\n LottoNodeDefinition,\n ParallelNodeDefinition,\n RepeatNodeDefinition,\n RetryNodeDefinition,\n RootNodeDefinition,\n SelectorNodeDefinition,\n SequenceNodeDefinition,\n SucceedNodeDefinition,\n WaitNodeDefinition\n} from \"../BehaviourTreeDefinition\";\nimport { parseArgumentTokens } from \"./MDSLNodeArgumentParser\";\nimport { parseAttributeTokens } from \"./MDSLNodeAttributeParser\";\nimport {\n StringLiteralPlaceholders,\n isCompositeNode,\n isDecoratorNode,\n isLeafNode,\n isRootNode,\n parseTokensFromDefinition,\n popAndCheck,\n substituteStringLiterals\n} from \"./MDSLUtilities\";\n\n/**\n * Parse the MDSL tree definition string into an equivalent JSON definition.\n * @param definition The tree definition string as MDSL.\n * @returns The root node JSON definitions.\n */\nexport function parseMDSLToJSON(definition: string): RootNodeDefinition[] {\n // Swap out any node/attribute argument string literals with a placeholder and get a mapping of placeholders to original values as well as the processed definition.\n const { placeholders, processedDefinition } = substituteStringLiterals(definition);\n\n // Parse our definition definition string into an array of raw tokens.\n const tokens = parseTokensFromDefinition(processedDefinition);\n\n return convertTokensToJSONDefinition(tokens, placeholders);\n}\n\n/**\n * Converts the specified tree definition tokens into a JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The root node JSON definitions.\n */\nfunction convertTokensToJSONDefinition(\n tokens: string[],\n stringLiteralPlaceholders: StringLiteralPlaceholders\n): RootNodeDefinition[] {\n // There must be at least 3 tokens for the tree definition to be valid. 'ROOT', '{' and '}'.\n if (tokens.length < 3) {\n throw new Error(\"invalid token count\");\n }\n\n // We should have a matching number of '{' and '}' tokens. If not, then there are scopes that have not been properly closed.\n if (tokens.filter((token) => token === \"{\").length !== tokens.filter((token) => token === \"}\").length) {\n throw new Error(\"scope character mismatch\");\n }\n\n // Create an array of tree stack arrays where root nodes will always be at the botton and the current composite/decorator node at the top.\n // There should be an element in this array for every root node defined and every element should be an array with a root note as the first element.\n // E.g. A definition with two root nodes defined:\n // [\n // [root, lotto, sequence],\n // [root, selector]\n // ]\n const treeStacks: [Partial, ...Partial[]][] = [];\n\n // Create an array of all root node definitions that we create.\n const rootNodes: Partial[] = [];\n\n // A helper function used to push node definitions onto the tree stack.\n const pushNode = (node: AnyNode) => {\n // If the node is a root node then we need to create a new tree stack array with the root node at the root.\n if (isRootNode(node)) {\n // Add the root node definition to our array of all parsed root node definitions.\n rootNodes.push(node);\n\n // Add the root node definition to the root of a new tree stack.\n treeStacks.push([node]);\n\n return;\n }\n\n // All non-root nodes should be pushed after their root nodes so handle cases\n // where we may not have any tree stacks or our top-most tree stack is empty.\n if (!treeStacks.length || !treeStacks[treeStacks.length - 1].length) {\n throw new Error(\"expected root node at base of definition\");\n }\n\n // Get the current tree stack that we are populating.\n const topTreeStack = treeStacks[treeStacks.length - 1];\n\n // Get the top-most node in the current tree stack, this will be a composite/decorator node\n // for which we will populate its children array if composite or setting its child if a decorator.\n const topTreeStackTopNode = topTreeStack[topTreeStack.length - 1] as AnyNode;\n\n // If the top-most node in the current root stack is a composite or decorator\n // node then the current node should be added as a child of the top-most node.\n if (isCompositeNode(topTreeStackTopNode)) {\n topTreeStackTopNode.children = topTreeStackTopNode.children || [];\n topTreeStackTopNode.children.push(node);\n } else if (isDecoratorNode(topTreeStackTopNode)) {\n // If the top node already has a child node set then throw an error as a decorator should only have a single child.\n if (topTreeStackTopNode.child) {\n throw new Error(\"a decorator node must only have a single child node\");\n }\n\n topTreeStackTopNode.child = node;\n }\n\n // If the node we are adding is also a composite or decorator node, then we should push it\n // onto the current tree stack, as subsequent nodes will be added as its child/children.\n if (!isLeafNode(node)) {\n topTreeStack.push(node);\n }\n };\n\n // A helper function used to pop node definitions off of the stack.\n const popNode = () => {\n // Get the current tree stack that we are populating.\n const topTreeStack = treeStacks[treeStacks.length - 1];\n\n // Pop the top-most node in the current tree stack if there is one.\n if (topTreeStack.length) {\n topTreeStack.pop();\n }\n\n // We don't want any empty tree stacks in our stack of tree stacks.\n if (!topTreeStack.length) {\n treeStacks.pop();\n }\n };\n\n // We should keep processing the raw tokens until we run out of them.\n while (tokens.length) {\n // Grab the next token.\n const token = tokens.shift()!;\n\n // How we create the next node depends on the current raw token value.\n switch (token.toUpperCase()) {\n case \"ROOT\": {\n pushNode(createRootNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"SUCCEED\": {\n pushNode(createSucceedNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"FAIL\": {\n pushNode(createFailNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"FLIP\": {\n pushNode(createFlipNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"REPEAT\": {\n pushNode(createRepeatNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"RETRY\": {\n pushNode(createRetryNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"SEQUENCE\": {\n pushNode(createSequenceNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"SELECTOR\": {\n pushNode(createSelectorNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"PARALLEL\": {\n pushNode(createParallelNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"LOTTO\": {\n pushNode(createLottoNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"ACTION\": {\n pushNode(createActionNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"CONDITION\": {\n pushNode(createConditionNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"WAIT\": {\n pushNode(createWaitNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"BRANCH\": {\n pushNode(createBranchNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"}\": {\n // The '}' character closes the current scope and means that we have to pop a node off of the current stack.\n popNode();\n break;\n }\n\n default: {\n throw new Error(`unexpected token: ${token}`);\n }\n }\n }\n\n return rootNodes as RootNodeDefinition[];\n}\n\n/**\n * Creates a root node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The root node JSON definition.\n */\nfunction createRootNode(tokens: string[], stringLiteralPlaceholders: StringLiteralPlaceholders): RootNodeDefinition {\n // Create the root node definition.\n let node = {\n type: \"root\",\n id: undefined\n } as RootNodeDefinition;\n\n // Parse any node arguments, we should only have one if any which will be an identifier argument for the root identifier.\n const nodeArguments = parseArgumentTokens(tokens, stringLiteralPlaceholders);\n\n // Check whether any node arguments were defined.\n if (nodeArguments.length) {\n // We should only have one argument, if any, which will be an identifier argument for the root identifier.\n if (nodeArguments.length === 1 && nodeArguments[0].type === \"identifier\") {\n // The root node identifier will be the first and only node argument value.\n node.id = nodeArguments[0].value as string;\n } else {\n throw new Error(\"expected single root name argument\");\n }\n }\n\n // Grab any node attribute definitions and spread them into the node definition.\n node = { ...node, ...parseAttributeTokens(tokens, stringLiteralPlaceholders) };\n\n // This is a decorator node, so we expect an opening '{'.\n popAndCheck(tokens, \"{\");\n\n // Return the root node definition.\n return node;\n}\n\n/**\n * Creates a succeed node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The succeed node JSON definition.\n */\nfunction createSucceedNode(\n tokens: string[],\n stringLiteralPlaceholders: StringLiteralPlaceholders\n): SucceedNodeDefinition {\n const node = {\n type: \"succeed\",\n ...parseAttributeTokens(tokens, stringLiteralPlaceholders)\n } as SucceedNodeDefinition;\n\n // This is a decorator node, so we expect an opening '{'.\n popAndCheck(tokens, \"{\");\n\n // Return the succeed node definition.\n return node;\n}\n\n/**\n * Creates a fail node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The fail node JSON definition.\n */\nfunction createFailNode(tokens: string[], stringLiteralPlaceholders: StringLiteralPlaceholders): FailNodeDefinition {\n const node = {\n type: \"fail\",\n ...parseAttributeTokens(tokens, stringLiteralPlaceholders)\n } as FailNodeDefinition;\n\n // This is a decorator node, so we expect an opening '{'.\n popAndCheck(tokens, \"{\");\n\n // Return the fail node definition.\n return node;\n}\n\n/**\n * Creates a flip node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The flip node JSON definition.\n */\nfunction createFlipNode(tokens: string[], stringLiteralPlaceholders: StringLiteralPlaceholders): FlipNodeDefinition {\n const node = {\n type: \"flip\",\n ...parseAttributeTokens(tokens, stringLiteralPlaceholders)\n } as FlipNodeDefinition;\n\n // This is a decorator node, so we expect an opening '{'.\n popAndCheck(tokens, \"{\");\n\n // Return the flip node definition.\n return node;\n}\n\n/**\n * Creates a repeat node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The repeat node JSON definition.\n */\nfunction createRepeatNode(\n tokens: string[],\n stringLiteralPlaceholders: StringLiteralPlaceholders\n): RepeatNodeDefinition {\n let node = { type: \"repeat\" } as RepeatNodeDefinition;\n\n // Get the node arguments.\n const nodeArguments = parseArgumentTokens(tokens, stringLiteralPlaceholders);\n\n // The arguments of a repeat node are optional. We may have:\n // - No node arguments, in which case the repeat note will iterate indefinitely.\n // - One node argument which will be the explicit number of iterations to make.\n // - Two node arguments which define the min and max iteration bounds from which a random iteration count will be picked.\n if (nodeArguments.length) {\n // All repeat node arguments MUST be of type number and must be integer.\n nodeArguments\n .filter((arg) => arg.type !== \"number\" || !arg.isInteger)\n .forEach(() => {\n throw new Error(`repeat node iteration counts must be integer values`);\n });\n\n // We should have got one or two iteration counts.\n if (nodeArguments.length === 1) {\n // A static iteration count was defined.\n node.iterations = nodeArguments[0].value as number;\n } else if (nodeArguments.length === 2) {\n // A minimum and maximum iteration count was defined.\n node.iterations = [nodeArguments[0].value as number, nodeArguments[1].value as number];\n } else {\n // An incorrect number of iteration counts was defined.\n throw new Error(\"invalid number of repeat node iteration count arguments defined\");\n }\n }\n\n // Grab any node attribute definitions and spread them into the node definition.\n node = { ...node, ...parseAttributeTokens(tokens, stringLiteralPlaceholders) };\n\n // This is a decorator node, so we expect an opening '{'.\n popAndCheck(tokens, \"{\");\n\n // Return the repeat node definition.\n return node;\n}\n\n/**\n * Creates a retry node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The retry node JSON definition.\n */\nfunction createRetryNode(tokens: string[], stringLiteralPlaceholders: StringLiteralPlaceholders): RetryNodeDefinition {\n let node = { type: \"retry\" } as RetryNodeDefinition;\n\n // Get the node arguments.\n const nodeArguments = parseArgumentTokens(tokens, stringLiteralPlaceholders);\n\n // The arguments of a retry node are optional. We may have:\n // - No node arguments, in which case the retry note will attempt indefinitely.\n // - One node argument which will be the explicit number of attempts to make.\n // - Two node arguments which define the min and max attempt bounds from which a random attempt count will be picked.\n if (nodeArguments.length) {\n // All retry node arguments MUST be of type number and must be integer.\n nodeArguments\n .filter((arg) => arg.type !== \"number\" || !arg.isInteger)\n .forEach(() => {\n throw new Error(`retry node attempt counts must be integer values`);\n });\n\n // We should have got one or two attempt counts.\n if (nodeArguments.length === 1) {\n // A static attempt count was defined.\n node.attempts = nodeArguments[0].value as number;\n } else if (nodeArguments.length === 2) {\n // A minimum and maximum attempt count was defined.\n node.attempts = [nodeArguments[0].value as number, nodeArguments[1].value as number];\n } else {\n // An incorrect number of attempt counts was defined.\n throw new Error(\"invalid number of retry node attempt count arguments defined\");\n }\n }\n\n // Grab any node attribute definitions and spread them into the node definition.\n node = { ...node, ...parseAttributeTokens(tokens, stringLiteralPlaceholders) };\n\n // This is a decorator node, so we expect an opening '{'.\n popAndCheck(tokens, \"{\");\n\n // Return the retry node definition.\n return node;\n}\n\n/**\n * Creates a sequence node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The sequence node JSON definition.\n */\nfunction createSequenceNode(\n tokens: string[],\n stringLiteralPlaceholders: StringLiteralPlaceholders\n): SequenceNodeDefinition {\n const node = {\n type: \"sequence\",\n ...parseAttributeTokens(tokens, stringLiteralPlaceholders)\n } as SequenceNodeDefinition;\n\n // This is a composite node, so we expect an opening '{'.\n popAndCheck(tokens, \"{\");\n\n // Return the sequence node definition.\n return node;\n}\n\n/**\n * Creates a selector node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The selector node JSON definition.\n */\nfunction createSelectorNode(\n tokens: string[],\n stringLiteralPlaceholders: StringLiteralPlaceholders\n): SelectorNodeDefinition {\n const node = {\n type: \"selector\",\n ...parseAttributeTokens(tokens, stringLiteralPlaceholders)\n } as SelectorNodeDefinition;\n\n // This is a composite node, so we expect an opening '{'.\n popAndCheck(tokens, \"{\");\n\n // Return the selector node definition.\n return node;\n}\n\n/**\n * Creates a parallel node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The parallel node JSON definition.\n */\nfunction createParallelNode(\n tokens: string[],\n stringLiteralPlaceholders: StringLiteralPlaceholders\n): ParallelNodeDefinition {\n const node = {\n type: \"parallel\",\n ...parseAttributeTokens(tokens, stringLiteralPlaceholders)\n } as ParallelNodeDefinition;\n\n // This is a composite node, so we expect an opening '{'.\n popAndCheck(tokens, \"{\");\n\n // Return the parallel node definition.\n return node;\n}\n\n/**\n * Creates a lotto node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The lotto node JSON definition.\n */\nfunction createLottoNode(tokens: string[], stringLiteralPlaceholders: StringLiteralPlaceholders): LottoNodeDefinition {\n // If any node arguments have been defined then they must be our weights.\n const nodeArguments = parseArgumentTokens(tokens, stringLiteralPlaceholders);\n\n // All lotto node arguments MUST be of type number and must be integer.\n nodeArguments\n .filter((arg) => arg.type !== \"number\" || !arg.isInteger)\n .forEach(() => {\n throw new Error(`lotto node weight arguments must be integer values`);\n });\n\n const node = {\n type: \"lotto\",\n weights: nodeArguments.map(({ value }) => value),\n ...parseAttributeTokens(tokens, stringLiteralPlaceholders)\n } as LottoNodeDefinition;\n\n // This is a composite node, so we expect an opening '{'.\n popAndCheck(tokens, \"{\");\n\n // Return the lotto node definition.\n return node;\n}\n\n/**\n * Creates an action node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The action node JSON definition.\n */\nfunction createActionNode(\n tokens: string[],\n stringLiteralPlaceholders: StringLiteralPlaceholders\n): ActionNodeDefinition {\n // Parse any node arguments, we should have at least one which will be an identifier argument for the action name\n // and agent function to invoke for the action, all other arguments are to be passed as arguments to that function.\n const [actionNameIdentifier, ...agentFunctionArgs] = parseArgumentTokens(tokens, stringLiteralPlaceholders);\n\n // Our first argument MUST be defined and be an identifier as we require an action name argument.\n if (actionNameIdentifier?.type !== \"identifier\") {\n throw new Error(\"expected action name identifier argument\");\n }\n\n // Only the first argument should have been an identifier, all agent function arguments must be string, number, boolean or null.\n agentFunctionArgs\n .filter((arg) => arg.type === \"identifier\")\n .forEach((arg) => {\n throw new Error(\n `invalid action node argument value '${arg.value}', must be string, number, boolean or null`\n );\n });\n\n // Return the action node definition.\n return {\n type: \"action\",\n call: actionNameIdentifier.value,\n args: agentFunctionArgs.map(({ value }) => value),\n ...parseAttributeTokens(tokens, stringLiteralPlaceholders)\n };\n}\n\n/**\n * Creates a condition node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The condition node JSON definition.\n */\nfunction createConditionNode(\n tokens: string[],\n stringLiteralPlaceholders: StringLiteralPlaceholders\n): ConditionNodeDefinition {\n // Parse any node arguments, we should have at least one which will be an identifier argument for the condition name\n // and agent function to invoke for the condition, all other arguments are to be passed as arguments to that function.\n const [conditionNameIdentifier, ...agentFunctionArgs] = parseArgumentTokens(tokens, stringLiteralPlaceholders);\n\n // Our first argument MUST be defined and be an identifier as we require a condition name argument.\n if (conditionNameIdentifier?.type !== \"identifier\") {\n throw new Error(\"expected condition name identifier argument\");\n }\n\n // Only the first argument should have been an identifier, all agent function arguments must be string, number, boolean or null.\n agentFunctionArgs\n .filter((arg) => arg.type === \"identifier\")\n .forEach((arg) => {\n throw new Error(\n `invalid condition node argument value '${arg.value}', must be string, number, boolean or null`\n );\n });\n\n // Return the condition node definition.\n return {\n type: \"condition\",\n call: conditionNameIdentifier.value,\n args: agentFunctionArgs.map(({ value }) => value),\n ...parseAttributeTokens(tokens, stringLiteralPlaceholders)\n };\n}\n\n/**\n * Creates a wait node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The wait node JSON definition.\n */\nfunction createWaitNode(tokens: string[], stringLiteralPlaceholders: StringLiteralPlaceholders): WaitNodeDefinition {\n let node = { type: \"wait\" } as WaitNodeDefinition;\n\n // Get the node arguments.\n const nodeArguments = parseArgumentTokens(tokens, stringLiteralPlaceholders);\n\n // The arguments of a wait node are optional. We may have:\n // - No node arguments, in which case the wait will be indefinite until it is aborted.\n // - One node argument which will be the explicit duration of the wait.\n // - Two node arguments which define the min and max duration bounds from which a random duration will be picked.\n if (nodeArguments.length) {\n // All wait node arguments MUST be of type number and must be integer.\n nodeArguments\n .filter((arg) => arg.type !== \"number\" || !arg.isInteger)\n .forEach(() => {\n throw new Error(`wait node duration arguments must be integer values`);\n });\n\n // We may have:\n // - One node argument which will be the explicit duration of the wait.\n // - Two node arguments which define the min and max duration bounds from which a random duration will be picked.\n // - Too many arguments, which is not valid.\n if (nodeArguments.length === 1) {\n // An explicit duration was defined.\n node.duration = nodeArguments[0].value as number;\n } else if (nodeArguments.length === 2) {\n // Min and max duration bounds were defined from which a random duration will be picked.\n node.duration = [nodeArguments[0].value as number, nodeArguments[1].value as number];\n } else if (nodeArguments.length > 2) {\n // An incorrect number of duration arguments were defined.\n throw new Error(\"invalid number of wait node duration arguments defined\");\n }\n }\n\n // Return the wait node definition.\n return { ...node, ...parseAttributeTokens(tokens, stringLiteralPlaceholders) };\n}\n\n/**\n * Creates a branch node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The branch node JSON definition.\n */\nfunction createBranchNode(\n tokens: string[],\n stringLiteralPlaceholders: StringLiteralPlaceholders\n): BranchNodeDefinition {\n // Parse any node arguments, we should have one which will be an identifier argument for the root ref.\n const nodeArguments = parseArgumentTokens(tokens, stringLiteralPlaceholders);\n\n // We should have only a single identifer argument for a branch node, which is the root ref.\n if (nodeArguments.length !== 1 || nodeArguments[0].type !== \"identifier\") {\n throw new Error(\"expected single branch name argument\");\n }\n\n // Return the branch node definition.\n return { type: \"branch\", ref: nodeArguments[0].value };\n}\n"], - "mappings": "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", - "names": ["Participant", "Lotto", "createLotto", "State", "createLotto", "popAndCheck", "substituteStringLiterals", "parseTokensFromDefinition", "popAndCheck", "getArgumentDefinition", "substituteStringLiterals", "parseTokensFromDefinition", "popAndCheck"] + "sources": ["../node_modules/lotto-draw/dist/Participant.js", "../node_modules/lotto-draw/dist/Utilities.js", "../node_modules/lotto-draw/dist/Lotto.js", "../node_modules/lotto-draw/dist/createLotto.js", "../node_modules/lotto-draw/dist/index.js", "../src/index.ts", "../src/State.ts", "../src/BehaviourTreeDefinitionUtilities.ts", "../src/mdsl/MDSLUtilities.ts", "../src/mdsl/MDSLNodeArgumentParser.ts", "../src/mdsl/MDSLNodeAttributeParser.ts", "../src/mdsl/MDSLDefinitionParser.ts", "../src/BehaviourTreeDefinitionValidator.ts", "../src/attributes/guards/GuardUnsatisifedException.ts", "../src/attributes/guards/GuardPath.ts", "../src/nodes/Node.ts", "../src/nodes/leaf/Leaf.ts", "../src/Lookup.ts", "../src/nodes/leaf/Action.ts", "../src/nodes/leaf/Condition.ts", "../src/nodes/leaf/Wait.ts", "../src/nodes/decorator/Decorator.ts", "../src/nodes/decorator/Root.ts", "../src/nodes/decorator/Repeat.ts", "../src/nodes/decorator/Retry.ts", "../src/nodes/decorator/Flip.ts", "../src/nodes/decorator/Succeed.ts", "../src/nodes/decorator/Fail.ts", "../src/nodes/composite/Lotto.ts", "../src/nodes/composite/Composite.ts", "../src/nodes/composite/Selector.ts", "../src/nodes/composite/Sequence.ts", "../src/nodes/composite/Parallel.ts", "../src/attributes/Attribute.ts", "../src/attributes/guards/Guard.ts", "../src/attributes/guards/While.ts", "../src/attributes/guards/Until.ts", "../src/attributes/callbacks/Callback.ts", "../src/attributes/callbacks/Entry.ts", "../src/attributes/callbacks/Exit.ts", "../src/attributes/callbacks/Step.ts", "../src/RootAstNodesBuilder.ts", "../src/BehaviourTree.ts"], + "sourcesContent": ["\"use strict\";\r\nObject.defineProperty(exports, \"__esModule\", { value: true });\r\nexports.Participant = void 0;\r\n/**\r\n * A participant that holds a number of tickets.\r\n */\r\nvar Participant = /** @class */ (function () {\r\n /**\r\n * Creates an instance of the Participant class.\r\n * @param participant The actual participant.\r\n * @param tickets The number of tickets held by the participant.\r\n */\r\n function Participant(participant, tickets) {\r\n if (tickets === void 0) { tickets = 1; }\r\n this._participant = participant;\r\n this._tickets = tickets;\r\n }\r\n Object.defineProperty(Participant.prototype, \"participant\", {\r\n /** Gets the actual participant. */\r\n get: function () {\r\n return this._participant;\r\n },\r\n enumerable: false,\r\n configurable: true\r\n });\r\n Object.defineProperty(Participant.prototype, \"tickets\", {\r\n /** Gets or sets the number of tickets held by the participant. */\r\n get: function () {\r\n return this._tickets;\r\n },\r\n set: function (value) {\r\n this._tickets = value;\r\n },\r\n enumerable: false,\r\n configurable: true\r\n });\r\n return Participant;\r\n}());\r\nexports.Participant = Participant;\r\n", "\"use strict\";\r\nObject.defineProperty(exports, \"__esModule\", { value: true });\r\nexports.isNaturalNumber = exports.isNullOrUndefined = void 0;\r\n/**\r\n * Gets whether the value provided is null or undefined.\r\n * @param value The value to check.\r\n * @returns Whether the value provided is null or undefined.\r\n */\r\nfunction isNullOrUndefined(value) {\r\n return value === null || value === undefined;\r\n}\r\nexports.isNullOrUndefined = isNullOrUndefined;\r\n/**\r\n * Gets whether the value provided is a natural number.\r\n * @param value The value to check.\r\n * @returns Whether the value provided is a natural number.\r\n */\r\nfunction isNaturalNumber(value) {\r\n return typeof value === \"number\" && value >= 1 && Math.floor(value) === value;\r\n}\r\nexports.isNaturalNumber = isNaturalNumber;\r\n", "\"use strict\";\r\nObject.defineProperty(exports, \"__esModule\", { value: true });\r\nexports.Lotto = void 0;\r\nvar Participant_1 = require(\"./Participant\");\r\nvar Utilities_1 = require(\"./Utilities\");\r\n/**\r\n * Represents a lotto consisting of a number of pickable ticket-holding participants.\r\n */\r\nvar Lotto = /** @class */ (function () {\r\n /**\r\n * Creates a new instance of Lotto.\r\n * @param customRandom The custom RNG to use in place of Math.random().\r\n */\r\n function Lotto(customRandom) {\r\n /** The array of participants that are holding tickets in the lotto. */\r\n this._participants = [];\r\n this._customRandom = customRandom;\r\n }\r\n /**\r\n * Adds a participant with the specified number of tickets, or adds to the participant ticket count if the participant already holds tickets.\r\n * @param participant The participant to add or to increase the ticket count for if they already hold tickets.\r\n * @param tickets The number of tickets, defaults to 1.\r\n * @returns The Lotto instance.\r\n */\r\n Lotto.prototype.add = function (participant, tickets) {\r\n if (tickets === void 0) { tickets = 1; }\r\n // Check that we have a valid ticket count.\r\n if (!(0, Utilities_1.isNaturalNumber)(tickets)) {\r\n throw new Error(\"tickets value must be a natural number\");\r\n }\r\n // Check whether this participant has already been added.\r\n var existingParticipant = this._participants.find(function (part) { return part.participant === participant; });\r\n if (existingParticipant) {\r\n // The participant has already been added to the lotto so just add to their ticket count.\r\n existingParticipant.tickets += tickets;\r\n }\r\n else {\r\n // The participant is not part of the lotto so we should add them.\r\n this._participants.push(new Participant_1.Participant(participant, tickets));\r\n }\r\n return this;\r\n };\r\n /**\r\n * Removes the specified number of tickets for the given participant from the draw, or all tickets if a ticket number is not defined.\r\n * @param participant The participant to remove tickets for.\r\n * @param tickets The number of tickets to remove, or undefined if all tickets are to be removed.\r\n * @returns The Lotto instance.\r\n */\r\n Lotto.prototype.remove = function (participant, tickets) {\r\n // Attempt to get the existing participant.\r\n var existingParticipant = this._participants.find(function (part) { return part.participant === participant; });\r\n // There is nothing to do if the specified participant isn't even part of the lotto.\r\n if (!existingParticipant) {\r\n return this;\r\n }\r\n // Check whether a tickets value was given.\r\n if (tickets !== undefined) {\r\n // Check that we have a valid ticket count.\r\n if (!(0, Utilities_1.isNaturalNumber)(tickets)) {\r\n throw new Error(\"tickets value must be a natural number\");\r\n }\r\n existingParticipant.tickets -= tickets;\r\n // If the participant no longer holds any tickets then they should be removed.\r\n if (existingParticipant.tickets < 1) {\r\n this._participants = this._participants.filter(function (part) { return part !== existingParticipant; });\r\n }\r\n }\r\n else {\r\n // We are removing all tickets for the participant so just remove them from the lotto.\r\n this._participants = this._participants.filter(function (part) { return part !== existingParticipant; });\r\n }\r\n return this;\r\n };\r\n /**\r\n * Draw a winning ticket and return the participant that holds the ticket.\r\n * @param options The draw options.\r\n * @returns The participant that holds the winning ticket.\r\n */\r\n Lotto.prototype.draw = function (options) {\r\n if (options === void 0) { options = {}; }\r\n // If we have no participants then just return null.\r\n if (this._participants.length === 0) {\r\n return null;\r\n }\r\n var redrawable = (0, Utilities_1.isNullOrUndefined)(options.redrawable) ? true : options.redrawable;\r\n var pickable = [];\r\n this._participants.forEach(function (_a) {\r\n var participant = _a.participant, tickets = _a.tickets;\r\n for (var ticketCount = 0; ticketCount < tickets; ticketCount++) {\r\n pickable.push(participant);\r\n }\r\n });\r\n var random;\r\n // We need a random floating-point number between 0 (inclusive) and 1 to scale up to pick our winner.\r\n // If a custom random function exists then we should use that or fall back to Math.random().\r\n if (this._customRandom) {\r\n // Call our custom random function to get a random floating-point number.\r\n random = this._customRandom();\r\n // Verify that the result of calling our custom random function is a number between 0 (inclusive) and 1.\r\n if (typeof random !== \"number\" || random < 0 || random >= 1) {\r\n throw new Error(\"the 'random' function provided did not return a number between 0 (inclusive) and 1\");\r\n }\r\n }\r\n else {\r\n // No custom random function was defined so just use good ol' Math.random().\r\n random = Math.random();\r\n }\r\n // Pick a winning participant.\r\n var winner = pickable[Math.floor(random * pickable.length)];\r\n // If the ticket isn't redrawable then we should remove a ticket from the winning participants ticket count.\r\n if (!redrawable) {\r\n this.remove(winner, 1);\r\n }\r\n // Return the winning participant.\r\n return winner;\r\n };\r\n /**\r\n * Draws multiple winning tickets and return an array of the participants that hold the winning tickets.\r\n * @param tickets The number of winning tickets to draw.\r\n * @param options The draw multiple options.\r\n * @returns An array of the participants that hold the winning tickets.\r\n */\r\n Lotto.prototype.drawMultiple = function (tickets, options) {\r\n if (options === void 0) { options = {}; }\r\n var uniqueResults = (0, Utilities_1.isNullOrUndefined)(options.unique) ? false : options.unique;\r\n // Handle cases where the user has asked for zero tickets (no idea why they would do this be we should trust them).\r\n if (tickets === 0) {\r\n return [];\r\n }\r\n // Now that we know out tickets value is not zero we should check that it is a valid natural number.\r\n if (!(0, Utilities_1.isNaturalNumber)(tickets)) {\r\n throw new Error(\"tickets value must be a natural number\");\r\n }\r\n var result = [];\r\n // Keep drawing tickets until we either reach the number of required tickets or we simply run out of tickets to draw.\r\n // We can run out of tickets to draw if 'options.redrawable' is explicity 'false' or we just had no participants when 'drawMultiple' was called.\r\n while (result.length < tickets && this._participants.length > 0) {\r\n result.push(this.draw(options));\r\n }\r\n // If the 'unique' draw option is set then we need to remove duplicates from the result list.\r\n if (uniqueResults) {\r\n // Create an array to store our unique results.\r\n var unique = [];\r\n // Iterate over all of our participants (with potential duplicates) and populate our array of unique values.\r\n for (var _i = 0, result_1 = result; _i < result_1.length; _i++) {\r\n var participant = result_1[_i];\r\n if (unique.indexOf(participant) === -1) {\r\n unique.push(participant);\r\n }\r\n }\r\n result = unique;\r\n }\r\n return result;\r\n };\r\n return Lotto;\r\n}());\r\nexports.Lotto = Lotto;\r\n", "\"use strict\";\r\nObject.defineProperty(exports, \"__esModule\", { value: true });\r\nexports.createLotto = void 0;\r\nvar Lotto_1 = require(\"./Lotto\");\r\n/**\r\n * A function that creates and returns a Lotto instance.\r\n * @param participantsOrOptions An array of initial participants or options relating to the creation of a Lotto instance.\r\n * @returns A new Lotto instance.\r\n */\r\nfunction createLotto(participantsOrOptions) {\r\n // If no initial participants or lotto options were provided as an argument then we can just return a new lotto instance now.\r\n if (!participantsOrOptions) {\r\n return new Lotto_1.Lotto();\r\n }\r\n // Check whether we were provided with an array of initial participants or a lotto options object.\r\n if (Array.isArray(participantsOrOptions)) {\r\n // We are dealing with a pre-defined array of participants.\r\n var participants = participantsOrOptions;\r\n var lotto_1 = new Lotto_1.Lotto();\r\n // If the lotto participants have been defined upfront then we will need to add them all to our lotto instance now.\r\n participants.forEach(function (_a) {\r\n var participant = _a[0], tokens = _a[1];\r\n return lotto_1.add(participant, tokens);\r\n });\r\n // Return the Lotto instance.\r\n return lotto_1;\r\n }\r\n else {\r\n // We are dealing with some lotto options.\r\n var random = participantsOrOptions.random, participants = participantsOrOptions.participants;\r\n // Create a Lotto instance passing the custom RNG function to use in place of Math.random() (which could be undefined).\r\n var lotto_2 = new Lotto_1.Lotto(random);\r\n // If the lotto participants have been defined upfront as part of the options then we will need to add them all to our lotto instance now.\r\n if (participants) {\r\n participants.forEach(function (_a) {\r\n var participant = _a[0], tokens = _a[1];\r\n return lotto_2.add(participant, tokens);\r\n });\r\n }\r\n // Return the Lotto instance.\r\n return lotto_2;\r\n }\r\n}\r\nexports.createLotto = createLotto;\r\n", "\"use strict\";\r\nObject.defineProperty(exports, \"__esModule\", { value: true });\r\nvar createLotto_1 = require(\"./createLotto\");\r\nexports.default = createLotto_1.createLotto;\r\n", "import State from \"./State\";\nimport { validateDefinition } from \"./BehaviourTreeDefinitionValidator\";\nimport { convertMDSLToJSON } from \"./mdsl/MDSLDefinitionParser\";\nimport { BehaviourTree, FlattenedTreeNode } from \"./BehaviourTree\";\n\nexport { BehaviourTree, State, convertMDSLToJSON, validateDefinition };\nexport type { FlattenedTreeNode };\n", "/**\n * Enumeration of node state types.\n */\nexport enum State {\n READY = \"mistreevous.ready\",\n RUNNING = \"mistreevous.running\",\n SUCCEEDED = \"mistreevous.succeeded\",\n FAILED = \"mistreevous.failed\"\n}\n\nexport { State as default };\n\nexport type CompleteState = State.SUCCEEDED | State.FAILED;\nexport type AnyState = State.READY | State.RUNNING | CompleteState;\n", "import {\n NodeDefinition,\n RootNodeDefinition,\n DecoratorNodeDefinition,\n CompositeNodeDefinition,\n AnyNode,\n BranchNodeDefinition\n} from \"./BehaviourTreeDefinition\";\n\n/**\n * A type guard function that returns true if the specified node satisfies the RootNodeDefinition type.\n * @param node The node.\n * @returns A value of true if the specified node satisfies the RootNodeDefinition type.\n */\nexport function isRootNode(node: NodeDefinition): node is RootNodeDefinition {\n return node.type === \"root\";\n}\n\n/**\n * A type guard function that returns true if the specified node satisfies the BranchNodeDefinition type.\n * @param node The node.\n * @returns A value of true if the specified node satisfies the BranchNodeDefinition type.\n */\nexport function isBranchNode(node: NodeDefinition): node is BranchNodeDefinition {\n return node.type === \"branch\";\n}\n\n/**\n * A type guard function that returns true if the specified node satisfies the NodeDefinition type.\n * @param node The node.\n * @returns A value of true if the specified node satisfies the NodeDefinition type.\n */\nexport function isLeafNode(node: NodeDefinition): node is NodeDefinition {\n return [\"branch\", \"action\", \"condition\", \"wait\"].includes(node.type);\n}\n\n/**\n * A type guard function that returns true if the specified node satisfies the DecoratorNodeDefinition type.\n * @param node The node.\n * @returns A value of true if the specified node satisfies the DecoratorNodeDefinition type.\n */\nexport function isDecoratorNode(node: NodeDefinition): node is DecoratorNodeDefinition {\n return [\"root\", \"repeat\", \"retry\", \"flip\", \"succeed\", \"fail\"].includes(node.type);\n}\n\n/**\n * A type guard function that returns true if the specified node satisfies the CompositeNodeDefinition type.\n * @param node The node.\n * @returns A value of true if the specified node satisfies the CompositeNodeDefinition type.\n */\nexport function isCompositeNode(node: NodeDefinition): node is CompositeNodeDefinition {\n return [\"sequence\", \"selector\", \"lotto\", \"parallel\"].includes(node.type);\n}\n\n/**\n * Flatten a node definition into an array of all of its nested node definitions.\n * @param nodeDefinition The node definition to flatten.\n * @returns An array of all of nested node definitions.\n */\nexport function flattenDefinition(nodeDefinition: AnyNode): AnyNode[] {\n const nodes: AnyNode[] = [];\n\n const processNode = (currentNodeDefinition: AnyNode) => {\n nodes.push(currentNodeDefinition);\n\n if (isCompositeNode(currentNodeDefinition)) {\n currentNodeDefinition.children.forEach(processNode);\n } else if (isDecoratorNode(currentNodeDefinition)) {\n processNode(currentNodeDefinition.child);\n }\n };\n\n processNode(nodeDefinition);\n\n return nodes;\n}\n\n/**\n * Determines whether the passed value is an integer.\n * @param value The value to check.\n * @returns Whether the passed value is an integer.\n */\nexport function isInteger(value: unknown): boolean {\n return typeof value === \"number\" && Math.floor(value) === value;\n}\n", "/**\n * A type defining an object that holds a reference to substitued string literals parsed from the definition.\n */\nexport type StringLiteralPlaceholders = { [key: string]: string };\n\n/**\n * Pop the next raw token from the specified array of tokens and throw an error if it wasn't the expected one.\n * @param tokens The array of tokens.\n * @param expected An optional string or array or items, one of which must match the next popped token.\n * @returns The popped token.\n */\nexport function popAndCheck(tokens: string[], expected?: string | string[]): string {\n // Get and remove the next token.\n const popped = tokens.shift();\n\n // We were expecting another token but there aren't any.\n if (popped === undefined) {\n throw new Error(\"unexpected end of definition\");\n }\n\n // Do we have an expected token/tokens array?\n if (expected != undefined) {\n // Get an array of expected values, if the popped token matches any then we are all good.\n const expectedValues = typeof expected === \"string\" ? [expected] : expected;\n\n // Check whether the popped token matches at least one of our expected items.\n var tokenMatchesExpectation = expectedValues.some((item) => popped.toUpperCase() === item.toUpperCase());\n\n // Throw an error if the popped token didn't match any of our expected items.\n if (!tokenMatchesExpectation) {\n const expectationString = expectedValues.map((item) => \"'\" + item + \"'\").join(\" or \");\n throw new Error(\"unexpected token found. Expected \" + expectationString + \" but got '\" + popped + \"'\");\n }\n }\n\n // Return the popped token.\n return popped;\n}\n\n/**\n * Swaps out any node/attribute argument string literals with placeholders.\n * @param definition The definition.\n * @returns An object containing a mapping of placeholders to original string values as well as the processed definition string.\n */\nexport function substituteStringLiterals(definition: string): {\n placeholders: StringLiteralPlaceholders;\n processedDefinition: string;\n} {\n // Create an object to hold the mapping of placeholders to original string values.\n const placeholders: StringLiteralPlaceholders = {};\n\n // Replace any string literals wrapped with double quotes in our definition with placeholders to be processed later.\n const processedDefinition = definition.replace(/\\\"(\\\\.|[^\"\\\\])*\\\"/g, (match) => {\n var strippedMatch = match.substring(1, match.length - 1);\n var placeholder = Object.keys(placeholders).find((key) => placeholders[key] === strippedMatch);\n\n // If we have no existing string literal match then create a new placeholder.\n if (!placeholder) {\n placeholder = `@@${Object.keys(placeholders).length}@@`;\n placeholders[placeholder] = strippedMatch;\n }\n\n return placeholder;\n });\n\n return { placeholders, processedDefinition };\n}\n\n/**\n * Parse the tree definition into an array of raw tokens.\n * @param definition The definition.\n * @returns An array of tokens parsed from the definition.\n */\nexport function parseTokensFromDefinition(definition: string): string[] {\n // Add some space around various important characters so that they can be plucked out easier as individual tokens.\n definition = definition.replace(/\\(/g, \" ( \");\n definition = definition.replace(/\\)/g, \" ) \");\n definition = definition.replace(/\\{/g, \" { \");\n definition = definition.replace(/\\}/g, \" } \");\n definition = definition.replace(/\\]/g, \" ] \");\n definition = definition.replace(/\\[/g, \" [ \");\n definition = definition.replace(/\\,/g, \" , \");\n\n // Split the definition into raw token form and return it.\n return definition.replace(/\\s+/g, \" \").trim().split(\" \");\n}\n", "import { StringLiteralPlaceholders, popAndCheck } from \"./MDSLUtilities\";\n\nexport type Argument = {\n /** The argument value. */\n value: T;\n /** The argument type, used for validation. */\n type: string;\n};\n\nexport type NullArgument = Argument & {\n type: \"null\";\n};\n\nexport type BooleanArgument = Argument & {\n type: \"boolean\";\n};\n\nexport type NumberArgument = Argument & {\n type: \"number\";\n isInteger: boolean; // Used for validation.\n};\n\nexport type StringPlaceholderArgument = Argument & {\n type: \"string\";\n};\n\nexport type IdentifierArgument = Argument & {\n type: \"identifier\";\n};\n\nexport type AnyArgument =\n | NullArgument\n | BooleanArgument\n | NumberArgument\n | StringPlaceholderArgument\n | IdentifierArgument;\n\n/**\n * Parse an array of argument definitions from the specified tokens array.\n * @param tokens The array tokens to parse the argument definitions from.\n * @param stringArgumentPlaceholders The mapping of string literal node argument placeholders to original values.\n * @param argumentValidator The argument validator function.\n * @param validationFailedMessage The exception message to throw if argument validation fails.\n * @returns An array of argument definitions parsed from the specified tokens array.\n */\nexport function parseArgumentTokens(\n tokens: string[],\n stringArgumentPlaceholders: StringLiteralPlaceholders\n): AnyArgument[] {\n const argumentList: AnyArgument[] = [];\n\n // If the next token is not a '[' or '(' then we have no arguments to parse.\n if (![\"[\", \"(\"].includes(tokens[0])) {\n return argumentList;\n }\n\n // Any lists of arguments will always be wrapped in '[]' for node arguments or '()' for attribute arguments.\n // We are looking for a '[' or '(' opener that wraps the argument tokens and the relevant closer.\n const closingToken = popAndCheck(tokens, [\"[\", \"(\"]) === \"[\" ? \"]\" : \")\";\n\n const argumentListTokens: string[] = [];\n\n // Grab all tokens between the '[' and ']' or '(' and ')'.\n while (tokens.length && tokens[0] !== closingToken) {\n // The next token is part of our arguments list.\n argumentListTokens.push(tokens.shift()!);\n }\n\n // Validate the order of the argument tokens. Each token must either be a ',' or a single argument that satisfies the validator.\n argumentListTokens.forEach((token, index) => {\n // Get whether this token should be an actual argument.\n const shouldBeArgumentToken = !(index & 1);\n\n // If the current token should be an actual argument then validate it, otherwise it should be a ',' token.\n if (shouldBeArgumentToken) {\n // Get the argument definition.\n const argumentDefinition = getArgumentDefinition(token, stringArgumentPlaceholders);\n\n // This is a valid argument!\n argumentList.push(argumentDefinition);\n } else {\n // The current token should be a ',' token.\n if (token !== \",\") {\n throw new Error(`invalid argument list, expected ',' or ']' but got '${token}'`);\n }\n }\n });\n\n // The arguments list should terminate with a ']' or ')' token, depending on the opener.\n popAndCheck(tokens, closingToken);\n\n // Return the arguments.\n return argumentList;\n}\n\n/**\n * Gets an argument value definition.\n * @param token The argument token.\n * @param stringArgumentPlaceholders The mapping of string literal node argument placeholders to original values.\n * @returns An argument value definition.\n */\nfunction getArgumentDefinition(token: string, stringArgumentPlaceholders: StringLiteralPlaceholders): AnyArgument {\n // Check whether the token represents a null value.\n if (token === \"null\") {\n return {\n value: null,\n type: \"null\"\n } as NullArgument;\n }\n\n // Check whether the token represents a boolean value.\n if (token === \"true\" || token === \"false\") {\n return {\n value: token === \"true\",\n type: \"boolean\"\n } as BooleanArgument;\n }\n\n // Check whether the token represents a number value.\n // TODO: Relies on broken isNaN - see MDN.\n // if (!Number.isNaN(token)) {\n if (!isNaN(token as any)) {\n return {\n value: parseFloat(token),\n isInteger: parseFloat(token) === parseInt(token, 10),\n type: \"number\"\n } as NumberArgument;\n }\n\n // Check whether the token is a placeholder (e.g. @@0@@) representing a string literal.\n if (token.match(/^@@\\d+@@$/g)) {\n return {\n value: stringArgumentPlaceholders[token].replace('\\\\\"', '\"'),\n type: \"string\"\n } as StringPlaceholderArgument;\n }\n\n // The only remaining option is that the argument value is an identifier.\n return {\n value: token,\n type: \"identifier\"\n } as IdentifierArgument;\n}\n", "import { NodeAttributeDefinition } from \"../BehaviourTreeDefinition\";\nimport { parseArgumentTokens } from \"./MDSLNodeArgumentParser\";\nimport { StringLiteralPlaceholders } from \"./MDSLUtilities\";\n\n/**\n * A type defining the attribute definitions of a node.\n */\ntype NodeAttributes = {\n while?: NodeAttributeDefinition;\n until?: NodeAttributeDefinition;\n entry?: NodeAttributeDefinition;\n exit?: NodeAttributeDefinition;\n step?: NodeAttributeDefinition;\n};\n\n/**\n * Parse any node attribute definitions from the specified tokens array.\n * @param tokens The array of remaining tokens.\n * @param stringArgumentPlaceholders The mapping of string literal node argument placeholders to original values.\n * @returns An object of attribute definitions defined by any directly following tokens.\n */\nexport function parseAttributeTokens(\n tokens: string[],\n stringArgumentPlaceholders: StringLiteralPlaceholders\n): NodeAttributes {\n const nodeAttributeNames: (keyof NodeAttributes)[] = [\"while\", \"until\", \"entry\", \"exit\", \"step\"];\n\n // Create an object to hold any attributes found.\n const attributes: NodeAttributes = {};\n\n // Try to get the name of the attribute for the next token.\n let nextAttributeName = tokens[0]?.toLowerCase() as keyof NodeAttributes;\n\n // Pull attribute tokens as well as their arguments off of the tokens stack until we have no more.\n while (nodeAttributeNames.includes(nextAttributeName)) {\n // Check to make sure that we have not already created an attribute definition of this type.\n if (attributes[nextAttributeName]) {\n throw new Error(`duplicate attribute '${tokens[0].toUpperCase()}' found for node`);\n }\n\n // Remove the attribute name token from the array of tokens.\n tokens.shift();\n\n // Grab the attribute arguments, assuming the first to be an identifier.\n const [attributeCallIdentifier, ...attributeArguments] = parseArgumentTokens(\n tokens,\n stringArgumentPlaceholders\n );\n\n // The first attribute argument has to be an identifer, this will reference an agent function.\n if (attributeCallIdentifier?.type !== \"identifier\") {\n throw new Error(\"expected agent function name identifier argument for attribute\");\n }\n\n // Any attribute arguments (other than the expected call identifier) must have a type of string, number, boolean or null.\n attributeArguments\n .filter((arg) => arg.type === \"identifier\")\n .forEach((arg) => {\n throw new Error(\n `invalid attribute argument value '${arg.value}', must be string, number, boolean or null`\n );\n });\n\n // Create the attribute definition and add it to the object of attribute definitions found.\n attributes[nextAttributeName] = {\n call: attributeCallIdentifier.value,\n args: attributeArguments.map(({ value }) => value)\n };\n\n // Try to get the next attribute name token, as there could be multiple.\n nextAttributeName = tokens[0]?.toLowerCase() as keyof NodeAttributes;\n }\n\n return attributes;\n}\n", "import {\n ActionNodeDefinition,\n AnyChildNode,\n AnyNode,\n BranchNodeDefinition,\n ConditionNodeDefinition,\n FailNodeDefinition,\n FlipNodeDefinition,\n LottoNodeDefinition,\n ParallelNodeDefinition,\n RepeatNodeDefinition,\n RetryNodeDefinition,\n RootNodeDefinition,\n SelectorNodeDefinition,\n SequenceNodeDefinition,\n SucceedNodeDefinition,\n WaitNodeDefinition\n} from \"../BehaviourTreeDefinition\";\nimport { isCompositeNode, isDecoratorNode, isLeafNode, isRootNode } from \"../BehaviourTreeDefinitionUtilities\";\nimport { parseArgumentTokens } from \"./MDSLNodeArgumentParser\";\nimport { parseAttributeTokens } from \"./MDSLNodeAttributeParser\";\nimport {\n StringLiteralPlaceholders,\n parseTokensFromDefinition,\n popAndCheck,\n substituteStringLiterals\n} from \"./MDSLUtilities\";\n\n/**\n * Convert the MDSL tree definition string into an equivalent JSON definition.\n * @param definition The tree definition string as MDSL.\n * @returns The root node JSON definitions.\n */\nexport function convertMDSLToJSON(definition: string): RootNodeDefinition[] {\n // Swap out any node/attribute argument string literals with a placeholder and get a mapping of placeholders to original values as well as the processed definition.\n const { placeholders, processedDefinition } = substituteStringLiterals(definition);\n\n // Parse our definition definition string into an array of raw tokens.\n const tokens = parseTokensFromDefinition(processedDefinition);\n\n return convertTokensToJSONDefinition(tokens, placeholders);\n}\n\n/**\n * Converts the specified tree definition tokens into a JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The root node JSON definitions.\n */\nfunction convertTokensToJSONDefinition(\n tokens: string[],\n stringLiteralPlaceholders: StringLiteralPlaceholders\n): RootNodeDefinition[] {\n // There must be at least 3 tokens for the tree definition to be valid. 'ROOT', '{' and '}'.\n if (tokens.length < 3) {\n throw new Error(\"invalid token count\");\n }\n\n // We should have a matching number of '{' and '}' tokens. If not, then there are scopes that have not been properly closed.\n if (tokens.filter((token) => token === \"{\").length !== tokens.filter((token) => token === \"}\").length) {\n throw new Error(\"scope character mismatch\");\n }\n\n // Create an array of tree stack arrays where root nodes will always be at the botton and the current composite/decorator node at the top.\n // There should be an element in this array for every root node defined and every element should be an array with a root note as the first element.\n // E.g. A definition with two root nodes defined:\n // [\n // [root, lotto, sequence],\n // [root, selector]\n // ]\n const treeStacks: [Partial, ...Partial[]][] = [];\n\n // Create an array of all root node definitions that we create.\n const rootNodes: Partial[] = [];\n\n // A helper function used to push node definitions onto the tree stack.\n const pushNode = (node: AnyNode) => {\n // If the node is a root node then we need to create a new tree stack array with the root node at the root.\n if (isRootNode(node)) {\n // Add the root node definition to our array of all parsed root node definitions.\n rootNodes.push(node);\n\n // Add the root node definition to the root of a new tree stack.\n treeStacks.push([node]);\n\n return;\n }\n\n // All non-root nodes should be pushed after their root nodes so handle cases\n // where we may not have any tree stacks or our top-most tree stack is empty.\n if (!treeStacks.length || !treeStacks[treeStacks.length - 1].length) {\n throw new Error(\"expected root node at base of definition\");\n }\n\n // Get the current tree stack that we are populating.\n const topTreeStack = treeStacks[treeStacks.length - 1];\n\n // Get the top-most node in the current tree stack, this will be a composite/decorator node\n // for which we will populate its children array if composite or setting its child if a decorator.\n const topTreeStackTopNode = topTreeStack[topTreeStack.length - 1] as AnyNode;\n\n // If the top-most node in the current root stack is a composite or decorator\n // node then the current node should be added as a child of the top-most node.\n if (isCompositeNode(topTreeStackTopNode)) {\n topTreeStackTopNode.children = topTreeStackTopNode.children || [];\n topTreeStackTopNode.children.push(node);\n } else if (isDecoratorNode(topTreeStackTopNode)) {\n // If the top node already has a child node set then throw an error as a decorator should only have a single child.\n if (topTreeStackTopNode.child) {\n throw new Error(\"a decorator node must only have a single child node\");\n }\n\n topTreeStackTopNode.child = node;\n }\n\n // If the node we are adding is also a composite or decorator node, then we should push it\n // onto the current tree stack, as subsequent nodes will be added as its child/children.\n if (!isLeafNode(node)) {\n topTreeStack.push(node);\n }\n };\n\n // A helper function used to pop node definitions off of the stack.\n const popNode = () => {\n // Get the current tree stack that we are populating.\n const topTreeStack = treeStacks[treeStacks.length - 1];\n\n // Pop the top-most node in the current tree stack if there is one.\n if (topTreeStack.length) {\n topTreeStack.pop();\n }\n\n // We don't want any empty tree stacks in our stack of tree stacks.\n if (!topTreeStack.length) {\n treeStacks.pop();\n }\n };\n\n // We should keep processing the raw tokens until we run out of them.\n while (tokens.length) {\n // Grab the next token.\n const token = tokens.shift()!;\n\n // How we create the next node depends on the current raw token value.\n switch (token.toUpperCase()) {\n case \"ROOT\": {\n pushNode(createRootNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"SUCCEED\": {\n pushNode(createSucceedNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"FAIL\": {\n pushNode(createFailNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"FLIP\": {\n pushNode(createFlipNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"REPEAT\": {\n pushNode(createRepeatNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"RETRY\": {\n pushNode(createRetryNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"SEQUENCE\": {\n pushNode(createSequenceNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"SELECTOR\": {\n pushNode(createSelectorNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"PARALLEL\": {\n pushNode(createParallelNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"LOTTO\": {\n pushNode(createLottoNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"ACTION\": {\n pushNode(createActionNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"CONDITION\": {\n pushNode(createConditionNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"WAIT\": {\n pushNode(createWaitNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"BRANCH\": {\n pushNode(createBranchNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"}\": {\n // The '}' character closes the current scope and means that we have to pop a node off of the current stack.\n popNode();\n break;\n }\n\n default: {\n throw new Error(`unexpected token: ${token}`);\n }\n }\n }\n\n return rootNodes as RootNodeDefinition[];\n}\n\n/**\n * Creates a root node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The root node JSON definition.\n */\nfunction createRootNode(tokens: string[], stringLiteralPlaceholders: StringLiteralPlaceholders): RootNodeDefinition {\n // Create the root node definition.\n let node = {\n type: \"root\",\n id: undefined\n } as RootNodeDefinition;\n\n // Parse any node arguments, we should only have one if any which will be an identifier argument for the root identifier.\n const nodeArguments = parseArgumentTokens(tokens, stringLiteralPlaceholders);\n\n // Check whether any node arguments were defined.\n if (nodeArguments.length) {\n // We should only have one argument, if any, which will be an identifier argument for the root identifier.\n if (nodeArguments.length === 1 && nodeArguments[0].type === \"identifier\") {\n // The root node identifier will be the first and only node argument value.\n node.id = nodeArguments[0].value as string;\n } else {\n throw new Error(\"expected single root name argument\");\n }\n }\n\n // Grab any node attribute definitions and spread them into the node definition.\n node = { ...node, ...parseAttributeTokens(tokens, stringLiteralPlaceholders) };\n\n // This is a decorator node, so we expect an opening '{'.\n popAndCheck(tokens, \"{\");\n\n // Return the root node definition.\n return node;\n}\n\n/**\n * Creates a succeed node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The succeed node JSON definition.\n */\nfunction createSucceedNode(\n tokens: string[],\n stringLiteralPlaceholders: StringLiteralPlaceholders\n): SucceedNodeDefinition {\n const node = {\n type: \"succeed\",\n ...parseAttributeTokens(tokens, stringLiteralPlaceholders)\n } as SucceedNodeDefinition;\n\n // This is a decorator node, so we expect an opening '{'.\n popAndCheck(tokens, \"{\");\n\n // Return the succeed node definition.\n return node;\n}\n\n/**\n * Creates a fail node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The fail node JSON definition.\n */\nfunction createFailNode(tokens: string[], stringLiteralPlaceholders: StringLiteralPlaceholders): FailNodeDefinition {\n const node = {\n type: \"fail\",\n ...parseAttributeTokens(tokens, stringLiteralPlaceholders)\n } as FailNodeDefinition;\n\n // This is a decorator node, so we expect an opening '{'.\n popAndCheck(tokens, \"{\");\n\n // Return the fail node definition.\n return node;\n}\n\n/**\n * Creates a flip node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The flip node JSON definition.\n */\nfunction createFlipNode(tokens: string[], stringLiteralPlaceholders: StringLiteralPlaceholders): FlipNodeDefinition {\n const node = {\n type: \"flip\",\n ...parseAttributeTokens(tokens, stringLiteralPlaceholders)\n } as FlipNodeDefinition;\n\n // This is a decorator node, so we expect an opening '{'.\n popAndCheck(tokens, \"{\");\n\n // Return the flip node definition.\n return node;\n}\n\n/**\n * Creates a repeat node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The repeat node JSON definition.\n */\nfunction createRepeatNode(\n tokens: string[],\n stringLiteralPlaceholders: StringLiteralPlaceholders\n): RepeatNodeDefinition {\n let node = { type: \"repeat\" } as RepeatNodeDefinition;\n\n // Get the node arguments.\n const nodeArguments = parseArgumentTokens(tokens, stringLiteralPlaceholders);\n\n // The arguments of a repeat node are optional. We may have:\n // - No node arguments, in which case the repeat note will iterate indefinitely.\n // - One node argument which will be the explicit number of iterations to make.\n // - Two node arguments which define the min and max iteration bounds from which a random iteration count will be picked.\n if (nodeArguments.length) {\n // All repeat node arguments MUST be of type number and must be integer.\n nodeArguments\n .filter((arg) => arg.type !== \"number\" || !arg.isInteger)\n .forEach(() => {\n throw new Error(`repeat node iteration counts must be integer values`);\n });\n\n // We should have got one or two iteration counts.\n if (nodeArguments.length === 1) {\n // A static iteration count was defined.\n node.iterations = nodeArguments[0].value as number;\n } else if (nodeArguments.length === 2) {\n // A minimum and maximum iteration count was defined.\n node.iterations = [nodeArguments[0].value as number, nodeArguments[1].value as number];\n } else {\n // An incorrect number of iteration counts was defined.\n throw new Error(\"invalid number of repeat node iteration count arguments defined\");\n }\n }\n\n // Grab any node attribute definitions and spread them into the node definition.\n node = { ...node, ...parseAttributeTokens(tokens, stringLiteralPlaceholders) };\n\n // This is a decorator node, so we expect an opening '{'.\n popAndCheck(tokens, \"{\");\n\n // Return the repeat node definition.\n return node;\n}\n\n/**\n * Creates a retry node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The retry node JSON definition.\n */\nfunction createRetryNode(tokens: string[], stringLiteralPlaceholders: StringLiteralPlaceholders): RetryNodeDefinition {\n let node = { type: \"retry\" } as RetryNodeDefinition;\n\n // Get the node arguments.\n const nodeArguments = parseArgumentTokens(tokens, stringLiteralPlaceholders);\n\n // The arguments of a retry node are optional. We may have:\n // - No node arguments, in which case the retry note will attempt indefinitely.\n // - One node argument which will be the explicit number of attempts to make.\n // - Two node arguments which define the min and max attempt bounds from which a random attempt count will be picked.\n if (nodeArguments.length) {\n // All retry node arguments MUST be of type number and must be integer.\n nodeArguments\n .filter((arg) => arg.type !== \"number\" || !arg.isInteger)\n .forEach(() => {\n throw new Error(`retry node attempt counts must be integer values`);\n });\n\n // We should have got one or two attempt counts.\n if (nodeArguments.length === 1) {\n // A static attempt count was defined.\n node.attempts = nodeArguments[0].value as number;\n } else if (nodeArguments.length === 2) {\n // A minimum and maximum attempt count was defined.\n node.attempts = [nodeArguments[0].value as number, nodeArguments[1].value as number];\n } else {\n // An incorrect number of attempt counts was defined.\n throw new Error(\"invalid number of retry node attempt count arguments defined\");\n }\n }\n\n // Grab any node attribute definitions and spread them into the node definition.\n node = { ...node, ...parseAttributeTokens(tokens, stringLiteralPlaceholders) };\n\n // This is a decorator node, so we expect an opening '{'.\n popAndCheck(tokens, \"{\");\n\n // Return the retry node definition.\n return node;\n}\n\n/**\n * Creates a sequence node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The sequence node JSON definition.\n */\nfunction createSequenceNode(\n tokens: string[],\n stringLiteralPlaceholders: StringLiteralPlaceholders\n): SequenceNodeDefinition {\n const node = {\n type: \"sequence\",\n ...parseAttributeTokens(tokens, stringLiteralPlaceholders)\n } as SequenceNodeDefinition;\n\n // This is a composite node, so we expect an opening '{'.\n popAndCheck(tokens, \"{\");\n\n // Return the sequence node definition.\n return node;\n}\n\n/**\n * Creates a selector node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The selector node JSON definition.\n */\nfunction createSelectorNode(\n tokens: string[],\n stringLiteralPlaceholders: StringLiteralPlaceholders\n): SelectorNodeDefinition {\n const node = {\n type: \"selector\",\n ...parseAttributeTokens(tokens, stringLiteralPlaceholders)\n } as SelectorNodeDefinition;\n\n // This is a composite node, so we expect an opening '{'.\n popAndCheck(tokens, \"{\");\n\n // Return the selector node definition.\n return node;\n}\n\n/**\n * Creates a parallel node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The parallel node JSON definition.\n */\nfunction createParallelNode(\n tokens: string[],\n stringLiteralPlaceholders: StringLiteralPlaceholders\n): ParallelNodeDefinition {\n const node = {\n type: \"parallel\",\n ...parseAttributeTokens(tokens, stringLiteralPlaceholders)\n } as ParallelNodeDefinition;\n\n // This is a composite node, so we expect an opening '{'.\n popAndCheck(tokens, \"{\");\n\n // Return the parallel node definition.\n return node;\n}\n\n/**\n * Creates a lotto node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The lotto node JSON definition.\n */\nfunction createLottoNode(tokens: string[], stringLiteralPlaceholders: StringLiteralPlaceholders): LottoNodeDefinition {\n // If any node arguments have been defined then they must be our weights.\n const nodeArguments = parseArgumentTokens(tokens, stringLiteralPlaceholders);\n\n // All lotto node arguments MUST be of type number and must be integer.\n nodeArguments\n .filter((arg) => arg.type !== \"number\" || !arg.isInteger)\n .forEach(() => {\n throw new Error(`lotto node weight arguments must be integer values`);\n });\n\n const node = {\n type: \"lotto\",\n weights: nodeArguments.map(({ value }) => value),\n ...parseAttributeTokens(tokens, stringLiteralPlaceholders)\n } as LottoNodeDefinition;\n\n // This is a composite node, so we expect an opening '{'.\n popAndCheck(tokens, \"{\");\n\n // Return the lotto node definition.\n return node;\n}\n\n/**\n * Creates an action node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The action node JSON definition.\n */\nfunction createActionNode(\n tokens: string[],\n stringLiteralPlaceholders: StringLiteralPlaceholders\n): ActionNodeDefinition {\n // Parse any node arguments, we should have at least one which will be an identifier argument for the action name\n // and agent function to invoke for the action, all other arguments are to be passed as arguments to that function.\n const [actionNameIdentifier, ...agentFunctionArgs] = parseArgumentTokens(tokens, stringLiteralPlaceholders);\n\n // Our first argument MUST be defined and be an identifier as we require an action name argument.\n if (actionNameIdentifier?.type !== \"identifier\") {\n throw new Error(\"expected action name identifier argument\");\n }\n\n // Only the first argument should have been an identifier, all agent function arguments must be string, number, boolean or null.\n agentFunctionArgs\n .filter((arg) => arg.type === \"identifier\")\n .forEach((arg) => {\n throw new Error(\n `invalid action node argument value '${arg.value}', must be string, number, boolean or null`\n );\n });\n\n // Return the action node definition.\n return {\n type: \"action\",\n call: actionNameIdentifier.value,\n args: agentFunctionArgs.map(({ value }) => value),\n ...parseAttributeTokens(tokens, stringLiteralPlaceholders)\n };\n}\n\n/**\n * Creates a condition node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The condition node JSON definition.\n */\nfunction createConditionNode(\n tokens: string[],\n stringLiteralPlaceholders: StringLiteralPlaceholders\n): ConditionNodeDefinition {\n // Parse any node arguments, we should have at least one which will be an identifier argument for the condition name\n // and agent function to invoke for the condition, all other arguments are to be passed as arguments to that function.\n const [conditionNameIdentifier, ...agentFunctionArgs] = parseArgumentTokens(tokens, stringLiteralPlaceholders);\n\n // Our first argument MUST be defined and be an identifier as we require a condition name argument.\n if (conditionNameIdentifier?.type !== \"identifier\") {\n throw new Error(\"expected condition name identifier argument\");\n }\n\n // Only the first argument should have been an identifier, all agent function arguments must be string, number, boolean or null.\n agentFunctionArgs\n .filter((arg) => arg.type === \"identifier\")\n .forEach((arg) => {\n throw new Error(\n `invalid condition node argument value '${arg.value}', must be string, number, boolean or null`\n );\n });\n\n // Return the condition node definition.\n return {\n type: \"condition\",\n call: conditionNameIdentifier.value,\n args: agentFunctionArgs.map(({ value }) => value),\n ...parseAttributeTokens(tokens, stringLiteralPlaceholders)\n };\n}\n\n/**\n * Creates a wait node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The wait node JSON definition.\n */\nfunction createWaitNode(tokens: string[], stringLiteralPlaceholders: StringLiteralPlaceholders): WaitNodeDefinition {\n let node = { type: \"wait\" } as WaitNodeDefinition;\n\n // Get the node arguments.\n const nodeArguments = parseArgumentTokens(tokens, stringLiteralPlaceholders);\n\n // The arguments of a wait node are optional. We may have:\n // - No node arguments, in which case the wait will be indefinite until it is aborted.\n // - One node argument which will be the explicit duration of the wait.\n // - Two node arguments which define the min and max duration bounds from which a random duration will be picked.\n if (nodeArguments.length) {\n // All wait node arguments MUST be of type number and must be integer.\n nodeArguments\n .filter((arg) => arg.type !== \"number\" || !arg.isInteger)\n .forEach(() => {\n throw new Error(`wait node duration arguments must be integer values`);\n });\n\n // We may have:\n // - One node argument which will be the explicit duration of the wait.\n // - Two node arguments which define the min and max duration bounds from which a random duration will be picked.\n // - Too many arguments, which is not valid.\n if (nodeArguments.length === 1) {\n // An explicit duration was defined.\n node.duration = nodeArguments[0].value as number;\n } else if (nodeArguments.length === 2) {\n // Min and max duration bounds were defined from which a random duration will be picked.\n node.duration = [nodeArguments[0].value as number, nodeArguments[1].value as number];\n } else if (nodeArguments.length > 2) {\n // An incorrect number of duration arguments were defined.\n throw new Error(\"invalid number of wait node duration arguments defined\");\n }\n }\n\n // Return the wait node definition.\n return { ...node, ...parseAttributeTokens(tokens, stringLiteralPlaceholders) };\n}\n\n/**\n * Creates a branch node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The branch node JSON definition.\n */\nfunction createBranchNode(\n tokens: string[],\n stringLiteralPlaceholders: StringLiteralPlaceholders\n): BranchNodeDefinition {\n // Parse any node arguments, we should have one which will be an identifier argument for the root ref.\n const nodeArguments = parseArgumentTokens(tokens, stringLiteralPlaceholders);\n\n // We should have only a single identifer argument for a branch node, which is the root ref.\n if (nodeArguments.length !== 1 || nodeArguments[0].type !== \"identifier\") {\n throw new Error(\"expected single branch name argument\");\n }\n\n // Return the branch node definition.\n return { type: \"branch\", ref: nodeArguments[0].value };\n}\n", "import { RootNodeDefinition } from \"./BehaviourTreeDefinition\";\nimport { flattenDefinition, isBranchNode, isInteger } from \"./BehaviourTreeDefinitionUtilities\";\nimport { convertMDSLToJSON } from \"./mdsl/MDSLDefinitionParser\";\n\n/**\n * An object representing the result of validating a tree definition.\n */\nexport type DefinitionValidationResult = {\n /**\n * A flag defining whether validation succeeded.\n */\n succeeded: boolean;\n /**\n * A string containing the error message if validation did not succeed.\n */\n errorMessage?: string;\n};\n\n/**\n * Validates the specified behaviour tree definition in the form of JSON or MDSL.\n * @param definition The behaviour tree definition in the form of JSON or MDSL.\n * @returns An object representing the result of validating the given tree definition.\n */\nexport function validateDefinition(definition: any): DefinitionValidationResult {\n // A helper function to create a failure validation result with the given error message.\n const createFailureResult = (errorMessage: string) => ({ succeeded: false, errorMessage });\n\n // The definition must be defined.\n if (definition === null || typeof definition === \"undefined\") {\n return createFailureResult(\"definition is null or undefined\");\n }\n\n let rootNodeDefinitions: any[];\n\n // We are expecting a definition in one of three different forms:\n // - A string which we will assume is mdsl and we will parse this to JSON before validation.\n // - An array which we will assume is an array of root node definitions with at least one being the primary root node (no 'id' property)\n // - An object which we will assume is the primary root node and should not have an 'id' property.\n if (typeof definition === \"string\") {\n try {\n // The definition is a string which we can assume is mdsl, so attempt to parse it to a JSON definition in the form of an array of root node definitions.\n rootNodeDefinitions = convertMDSLToJSON(definition);\n } catch (error) {\n // We failed to parse the JSON from the mdsl, this is likely to be the result of it not being a valid mdsl string.\n return createFailureResult(`invalid mdsl: ${definition}`);\n }\n } else if (typeof definition === \"object\") {\n // The definition will either be an array (of root node definitions) or an object (the single primary root node definition).\n // If our definition is an array, we should verify that each of the elements within it are objects (potential root node definitions).\n if (Array.isArray(definition)) {\n // Find any invalid node definitions in our definition array, not full validation just a check that each is a valid object.\n const invalidDefinitionElements = definition.filter((element) => {\n // Each element isn't valid unless it is an object that isn't also an array and isn't null.\n return typeof element !== \"object\" || Array.isArray(element) || element === null;\n });\n\n // If we have any invalid node definitions then validation has failed.\n if (invalidDefinitionElements.length) {\n return createFailureResult(\n \"invalid elements in definition array, each must be an root node definition object\"\n );\n }\n\n // Our definition is already an array of root node definition objects.\n rootNodeDefinitions = definition;\n } else {\n // Our definition is an object, but we want an array of root node definitions.\n rootNodeDefinitions = [definition];\n }\n } else {\n return createFailureResult(`unexpected definition type of '${typeof definition}'`);\n }\n\n // Iterate over our array of root nodes and call validateNode for each, passing an initial depth of 0, wrapped in a try catch to handle validation failures.\n try {\n rootNodeDefinitions.forEach((rootNodeDefinition) => validateNode(rootNodeDefinition, 0));\n } catch (error) {\n // Handle cases where we have caught a thrown Error and return a failure result with the error message.\n if (error instanceof Error) {\n return createFailureResult(error.message);\n }\n\n // No idea what happened here!\n return createFailureResult(`unexpected error: ${error}`);\n }\n\n // Unpack all of the root node definitions into arrays of main ('id' defined) and sub ('id' not defined) root node definitions.\n const mainRootNodeDefinitions = rootNodeDefinitions.filter(({ id }) => typeof id === \"undefined\");\n const subRootNodeDefinitions = rootNodeDefinitions.filter(({ id }) => typeof id === \"string\" && id.length > 0);\n\n // We should ALWAYS have exactly one root node definition without an 'id' property defined, which is out main root node definition.\n if (mainRootNodeDefinitions.length !== 1) {\n return createFailureResult(\"expected single root node without 'id' property defined to act as main root\");\n }\n\n // We should never have duplicate 'id' properties across our sub root node definitions.\n const subRootNodeIdenitifers: string[] = [];\n for (const { id } of subRootNodeDefinitions) {\n // Have we already come across this 'id' property value?\n if (subRootNodeIdenitifers.includes(id)) {\n return createFailureResult(`multiple root nodes found with duplicate 'id' property value of '${id}'`);\n }\n\n subRootNodeIdenitifers.push(id);\n }\n\n // Check for any branch node circular depedencies. This will not include any globally registered subtrees.\n const circularDependencyPath = findBranchCircularDependencyPath(rootNodeDefinitions);\n\n // If we found a circular dependency in our root node and branch node definitions then the definition is definitely not valid.\n if (circularDependencyPath) {\n return createFailureResult(`circular dependency found in branch node references: ${circularDependencyPath}`);\n }\n\n // Our definition was valid!\n return { succeeded: true };\n}\n\n/**\n * Find the first circular depdendency path present in the array of root node definitions, or null if one doesn't exist.\n * This will not consider branch nodes that reference any globally registered subtrees.\n * @param rootNodeDefinitions The array of root node definitions.\n * @returns The first circular depdendency path present in the array of root node definitions as string, or null if one doesn't exist.\n */\nfunction findBranchCircularDependencyPath(rootNodeDefinitions: RootNodeDefinition[]): string | null {\n // Create a mapping of root node identifiers to other root nodes that they reference via branch nodes.\n // Below is an example of a mapping that includes a circular dependency (root => a => b => c => a)\n // [{ refs: [\"a\", \"b\"] }, { id: \"a\", refs: [\"b\"] }, { id: \"b\", refs: [\"c\"] }, { id: \"c\", refs: [\"a\"] }]\n const rootNodeMappings: { id: string | undefined; refs: string[] }[] = rootNodeDefinitions.map(\n (rootNodeDefinition) => ({\n id: rootNodeDefinition.id,\n refs: flattenDefinition(rootNodeDefinition)\n .filter(isBranchNode)\n .map(({ ref }) => ref)\n })\n );\n\n let badPathFormatted: string | null = null;\n\n // A recursive function to walk through the mappings, keeping track of which root nodes we have visited in the form of a path of root node identifiers.\n const followRefs = (mapping: { id: string | undefined; refs: string[] }, path: (string | undefined)[] = []) => {\n // Have we found a circular dependency?\n if (path.includes(mapping.id)) {\n // We found a circular dependency! Get the bad path of root node identifiers.\n const badPath = [...path, mapping.id];\n\n // Set the formatted path value. [undefined, \"a\", \"b\", \"c\", \"a\"] would be formatted as \"a -> b -> c -> a\".\n badPathFormatted = badPath.map((element) => !!element).join(\" => \");\n\n // No need to continue, we found a circular dependency.\n return;\n }\n\n for (const ref of mapping.refs) {\n // Find the mapping for the root node with an identifer matching the current ref.\n const subMapping = rootNodeMappings.find(({ id }) => id === ref);\n\n // We may not have a mapping for this ref, which will happen if this ref is for a globally registered subtree.\n if (subMapping) {\n followRefs(subMapping, [...path, mapping.id]);\n }\n }\n };\n\n return badPathFormatted;\n}\n\n/**\n * Validate an object that we expect to be a node definition.\n * @param definition An object that we expect to be a node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateNode(definition: any, depth: number): void {\n // Every node must be valid object and have a non-empty 'type' string property.\n if (typeof definition !== \"object\" || typeof definition.type !== \"string\" || definition.type.length === 0) {\n throw new Error(\n `node definition is not an object or 'type' property is not a non-empty string at depth '${depth}'`\n );\n }\n\n // How we validate this node definition will depend on its type.\n switch (definition.type) {\n case \"action\":\n validateActionNode(definition, depth);\n break;\n\n case \"condition\":\n validateConditionNode(definition, depth);\n break;\n\n case \"wait\":\n validateWaitNode(definition, depth);\n break;\n\n case \"branch\":\n validateBranchNode(definition, depth);\n break;\n\n case \"root\":\n validateRootNode(definition, depth);\n break;\n\n case \"success\":\n validateSuccessNode(definition, depth);\n break;\n\n case \"fail\":\n validateFailNode(definition, depth);\n break;\n\n case \"flip\":\n validateFlipNode(definition, depth);\n break;\n\n case \"repeat\":\n validateRepeatNode(definition, depth);\n break;\n\n case \"retry\":\n validateRetryNode(definition, depth);\n break;\n\n case \"sequence\":\n validateSequenceNode(definition, depth);\n break;\n\n case \"selector\":\n validateSelectorNode(definition, depth);\n break;\n\n case \"parallel\":\n validateParallelNode(definition, depth);\n break;\n\n default:\n throw new Error(`unexpected node type of '${definition.type}' at depth '${depth}'`);\n }\n}\n\n/**\n * Validate any attributes for a given node definition.\n * @param definition The node definition.\n * @param depth The depth of the node in the behaviour tree definition.\n */\nfunction validateNodeAttributes(definition: any, depth: number): void {\n // Validate each of the attribute types for this node.\n [\"while\", \"until\", \"entry\", \"exit\", \"step\"].forEach((attributeName) => {\n // Attempt to grab the definition for the current attribute from the node definition.\n const attributeDefinition = definition[attributeName];\n\n // All node attributes are optional, so there is nothing to do if the current attribute is not defined.\n if (typeof attributeDefinition === \"undefined\") {\n return;\n }\n\n // The attribute definition must be an object.\n if (typeof attributeDefinition !== \"object\") {\n throw new Error(\n `expected attribute '${attributeName}' to be an object for '${definition.type}' node at depth '${depth}'`\n );\n }\n\n // The 'call' property must be defined for any attribute definition.\n if (typeof attributeDefinition.call !== \"string\" || attributeDefinition.call.length === 0) {\n throw new Error(\n `expected 'call' property for attribute '${attributeName}' to be a non-empty string for '${definition.type}' node at depth '${depth}'`\n );\n }\n\n // If any node attribute arguments have been defined then they must have been defined in an array.\n if (typeof attributeDefinition.args !== \"undefined\" && !Array.isArray(attributeDefinition.args)) {\n throw new Error(\n `expected 'args' property for attribute '${attributeName}' to be an array for '${definition.type}' node at depth '${depth}'`\n );\n }\n });\n}\n\n/**\n * Validate an object that we expect to be a root node definition.\n * @param definition An object that we expect to be a root node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateRootNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"root\") {\n throw new Error(\"expected node type of 'root' for root node\");\n }\n\n // A root node cannot be the child of another node.\n if (depth > 0) {\n throw new Error(\"a root node cannot be the child of another node\");\n }\n\n // Check that, if the root node 'id' property is defined, it is a non-empty string.\n if (typeof definition.id !== \"undefined\" && (typeof definition.id !== \"string\" || definition.id.length === 0)) {\n throw new Error(\"expected non-empty string for 'id' property if defined for root node\");\n }\n\n // A root node is a decorator node, so must have a child node defined.\n if (typeof definition.child === \"undefined\") {\n throw new Error(\"expected property 'child' to be defined for root node\");\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n\n // Validate the child node of this decorator node.\n validateNode(definition.child, depth + 1);\n}\n\n/**\n * Validate an object that we expect to be a success node definition.\n * @param definition An object that we expect to be a success node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateSuccessNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"success\") {\n throw new Error(`expected node type of 'success' for success node at depth '${depth}'`);\n }\n\n // A success node is a decorator node, so must have a child node defined.\n if (typeof definition.child === \"undefined\") {\n throw new Error(`expected property 'child' to be defined for success node at depth '${depth}'`);\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n\n // Validate the child node of this decorator node.\n validateNode(definition.child, depth + 1);\n}\n\n/**\n * Validate an object that we expect to be a fail node definition.\n * @param definition An object that we expect to be a fail node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateFailNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"fail\") {\n throw new Error(`expected node type of 'fail' for fail node at depth '${depth}'`);\n }\n\n // A fail node is a decorator node, so must have a child node defined.\n if (typeof definition.child === \"undefined\") {\n throw new Error(`expected property 'child' to be defined for fail node at depth '${depth}'`);\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n\n // Validate the child node of this decorator node.\n validateNode(definition.child, depth + 1);\n}\n\n/**\n * Validate an object that we expect to be a flip node definition.\n * @param definition An object that we expect to be a flip node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateFlipNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"flip\") {\n throw new Error(`expected node type of 'flip' for flip node at depth '${depth}'`);\n }\n\n // A flip node is a decorator node, so must have a child node defined.\n if (typeof definition.child === \"undefined\") {\n throw new Error(`expected property 'child' to be defined for flip node at depth '${depth}'`);\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n\n // Validate the child node of this decorator node.\n validateNode(definition.child, depth + 1);\n}\n\n/**\n * Validate an object that we expect to be a repeat node definition.\n * @param definition An object that we expect to be a repeat node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateRepeatNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"repeat\") {\n throw new Error(`expected node type of 'repeat' for repeat node at depth '${depth}'`);\n }\n\n // A repeat node is a decorator node, so must have a child node defined.\n if (typeof definition.child === \"undefined\") {\n throw new Error(`expected property 'child' to be defined for repeat node at depth '${depth}'`);\n }\n\n // Check whether an 'iterations' property has been defined, it may not have been if this node is to repeat indefinitely.\n if (typeof definition.iterations !== \"undefined\") {\n if (Array.isArray(definition.iterations)) {\n // Check whether any elements of the array are not integer values.\n const containsNonInteger = !!definition.iterations.find((value: unknown) => !isInteger(value));\n\n // If the 'iterations' property is an array then it MUST contain two integer values.\n if (definition.iterations.length !== 2 || containsNonInteger) {\n throw new Error(\n `expected array containing two integer values for 'iterations' property if defined for repeat node at depth '${depth}'`\n );\n }\n } else if (!isInteger(definition.iterations)) {\n throw new Error(\n `expected integer value or array containing two integer values for 'iterations' property if defined for repeat node at depth '${depth}'`\n );\n }\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n\n // Validate the child node of this decorator node.\n validateNode(definition.child, depth + 1);\n}\n\n/**\n * Validate an object that we expect to be a retry node definition.\n * @param definition An object that we expect to be a retry node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateRetryNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"retry\") {\n throw new Error(`expected node type of 'retry' for retry node at depth '${depth}'`);\n }\n\n // A retry node is a decorator node, so must have a child node defined.\n if (typeof definition.child === \"undefined\") {\n throw new Error(`expected property 'child' to be defined for retry node at depth '${depth}'`);\n }\n\n // Check whether an 'attempts' property has been defined, it may not have been if this node is to retry indefinitely.\n if (typeof definition.attempts !== \"undefined\") {\n if (Array.isArray(definition.attempts)) {\n // Check whether any elements of the array are not integer values.\n const containsNonInteger = !!definition.attempts.find((value: unknown) => !isInteger(value));\n\n // If the 'attempts' property is an array then it MUST contain two integer values.\n if (definition.attempts.length !== 2 || containsNonInteger) {\n throw new Error(\n `expected array containing two integer values for 'attempts' property if defined for retry node at depth '${depth}'`\n );\n }\n } else if (!isInteger(definition.attempts)) {\n throw new Error(\n `expected integer value or array containing two integer values for 'attempts' property if defined for retry node at depth '${depth}'`\n );\n }\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n\n // Validate the child node of this decorator node.\n validateNode(definition.child, depth + 1);\n}\n\n/**\n * Validate an object that we expect to be a branch node definition.\n * @param definition An object that we expect to be a branch node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateBranchNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"branch\") {\n throw new Error(`expected node type of 'branch' for branch node at depth '${depth}'`);\n }\n\n // Check that the branch node 'ref' property is defined and is a non-empty string.\n if (typeof definition.ref !== \"string\" || definition.ref.length === 0) {\n throw new Error(`expected non-empty string for 'ref' property for branch node at depth '${depth}'`);\n }\n\n // It is invalid to define guard attributes for a branch node as they should be defined on the referenced root node.\n [\"while\", \"until\"].forEach((attributeName) => {\n if (typeof definition[attributeName] !== \"undefined\") {\n throw new Error(\n `guards should not be defined for branch nodes but guard '${attributeName}' was defined for branch node at depth '${depth}'`\n );\n }\n });\n\n // It is invalid to define callback attributes for a branch node as they should be defined on the referenced root node.\n [\"entry\", \"exit\", \"step\"].forEach((attributeName) => {\n if (typeof definition[attributeName] !== \"undefined\") {\n throw new Error(\n `callbacks should not be defined for branch nodes but callback '${attributeName}' was defined for branch node at depth '${depth}'`\n );\n }\n });\n}\n\n/**\n * Validate an object that we expect to be a action node definition.\n * @param definition An object that we expect to be a action node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateActionNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"action\") {\n throw new Error(`expected node type of 'action' for action node at depth '${depth}'`);\n }\n\n // The 'call' property must be defined for a action node definition.\n if (typeof definition.call !== \"string\" || definition.call.length === 0) {\n throw new Error(`expected non-empty string for 'call' property of action node at depth '${depth}'`);\n }\n\n // If any action function arguments have been defined then they must have been defined in an array.\n if (typeof definition.args !== \"undefined\" && !Array.isArray(definition.args)) {\n throw new Error(`expected array for 'args' property if defined for action node at depth '${depth}'`);\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n}\n\n/**\n * Validate an object that we expect to be a condition node definition.\n * @param definition An object that we expect to be a condition node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateConditionNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"condition\") {\n throw new Error(`expected node type of 'condition' for condition node at depth '${depth}'`);\n }\n\n // The 'call' property must be defined for a condition node definition.\n if (typeof definition.call !== \"string\" || definition.call.length === 0) {\n throw new Error(`expected non-empty string for 'call' property of condition node at depth '${depth}'`);\n }\n\n // If any condition function arguments have been defined then they must have been defined in an array.\n if (typeof definition.args !== \"undefined\" && !Array.isArray(definition.args)) {\n throw new Error(`expected array for 'args' property if defined for condition node at depth '${depth}'`);\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n}\n\n/**\n * Validate an object that we expect to be a wait node definition.\n * @param definition An object that we expect to be a wait node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateWaitNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"wait\") {\n throw new Error(`expected node type of 'wait' for wait node at depth '${depth}'`);\n }\n\n // Check whether a 'duration' property has been defined, it may not have been if this node is to wait indefinitely.\n if (typeof definition.duration !== \"undefined\") {\n if (Array.isArray(definition.duration)) {\n // Check whether any elements of the array are not integer values.\n const containsNonInteger = !!definition.duration.find((value: unknown) => !isInteger(value));\n\n // If the 'duration' property is an array then it MUST contain two integer values.\n if (definition.duration.length !== 2 || containsNonInteger) {\n throw new Error(\n `expected array containing two integer values for 'duration' property if defined for wait node at depth '${depth}'`\n );\n }\n } else if (!isInteger(definition.duration)) {\n throw new Error(\n `expected integer value or array containing two integer values for 'duration' property if defined for wait node at depth '${depth}'`\n );\n }\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n}\n\n/**\n * Validate an object that we expect to be a sequence node definition.\n * @param definition An object that we expect to be a sequence node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateSequenceNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"sequence\") {\n throw new Error(`expected node type of 'sequence' for sequence node at depth '${depth}'`);\n }\n\n // A sequence node is a composite node, so must have a children nodes array defined.\n if (!Array.isArray(definition.children) || definition.children.length === 0) {\n throw new Error(`expected non-empty 'children' array to be defined for sequence node at depth '${depth}'`);\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n\n // Validate the child nodes of this composite node.\n definition.children.forEach((child: any) => validateNode(child, depth + 1));\n}\n\n/**\n * Validate an object that we expect to be a selector node definition.\n * @param definition An object that we expect to be a selector node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateSelectorNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"selector\") {\n throw new Error(`expected node type of 'selector' for selector node at depth '${depth}'`);\n }\n\n // A selector node is a composite node, so must have a children nodes array defined.\n if (!Array.isArray(definition.children) || definition.children.length === 0) {\n throw new Error(`expected non-empty 'children' array to be defined for selector node at depth '${depth}'`);\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n\n // Validate the child nodes of this composite node.\n definition.children.forEach((child: any) => validateNode(child, depth + 1));\n}\n\n/**\n * Validate an object that we expect to be a parallel node definition.\n * @param definition An object that we expect to be a parallel node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateParallelNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"parallel\") {\n throw new Error(`expected node type of 'parallel' for parallel node at depth '${depth}'`);\n }\n\n // A parallel node is a composite node, so must have a children nodes array defined.\n if (!Array.isArray(definition.children) || definition.children.length === 0) {\n throw new Error(`expected non-empty 'children' array to be defined for parallel node at depth '${depth}'`);\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n\n // Validate the child nodes of this composite node.\n definition.children.forEach((child: any) => validateNode(child, depth + 1));\n}\n", "import Node from \"../../nodes/Node\";\n\n/**\n * An exception thrown when evaluating node guard path conditions and a conditions fails.\n */\nexport default class GuardUnsatisifedException extends Error {\n /**\n * @param source The node at which a guard condition failed.\n */\n constructor(private source: Node) {\n super(\"A guard path condition has failed\");\n }\n\n /**\n * Gets whether the specified node is the node at which a guard condition failed.\n * @param node The node to check against the source node.\n * @returns Whether the specified node is the node at which a guard condition failed.\n */\n isSourceNode = (node: Node) => node === this.source;\n}\n", "import { Agent } from \"../../Agent\";\nimport Guard from \"./Guard\";\nimport Node from \"../../nodes/Node\";\nimport GuardUnsatisifedException from \"./GuardUnsatisifedException\";\n\nexport type GuardPathPart = {\n node: Node;\n guards: Guard[];\n};\n\n/**\n * Represents a path of node guards along a root-to-leaf tree path.\n */\nexport default class GuardPath {\n /**\n * @param nodes An array of objects defining a node instance -> guard link, ordered by node depth.\n */\n constructor(private nodes: GuardPathPart[]) {}\n\n /**\n * Evaluate guard conditions for all guards in the tree path, moving outwards from the root.\n * @param agent The agent, required for guard evaluation.\n * @returns An evaluation results object.\n */\n evaluate = (agent: Agent) => {\n // We need to evaluate guard conditions for nodes up the tree, moving outwards from the root.\n for (const details of this.nodes) {\n // There can be multiple guards per node.\n for (const guard of details.guards) {\n // Check whether the guard condition passes, and throw an exception if not.\n if (!guard.isSatisfied(agent)) {\n throw new GuardUnsatisifedException(details.node);\n }\n }\n }\n };\n}\n", "import { Agent } from \"../Agent\";\nimport Attribute from \"../attributes/Attribute\";\nimport Entry from \"../attributes/callbacks/Entry\";\nimport Exit from \"../attributes/callbacks/Exit\";\nimport Step from \"../attributes/callbacks/Step\";\nimport Guard from \"../attributes/guards/Guard\";\nimport GuardPath from \"../attributes/guards/GuardPath\";\nimport GuardUnsatisifedException from \"../attributes/guards/GuardUnsatisifedException\";\nimport { BehaviourTreeOptions } from \"../BehaviourTreeOptions\";\nimport { AnyArgument } from \"../RootAstNodesBuilder\";\nimport State, { AnyState } from \"../State\";\nimport Leaf from \"./leaf/Leaf\";\n\n/**\n * A base node.\n */\nexport default abstract class Node {\n /**\n * The node uid.\n */\n private readonly uid: string = createNodeUid();\n /**\n * The node state.\n */\n private state: AnyState = State.READY;\n /**\n * The guard path to evaluate as part of a node update.\n */\n private guardPath: GuardPath | undefined;\n\n /**\n * @param type The node type.\n * @param attributes The node attributes.\n * @param args The node argument definitions.\n */\n constructor(private type: string, private attributes: Attribute[], private args: AnyArgument[]) {}\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected abstract onUpdate(agent: Agent, options: BehaviourTreeOptions): void;\n\n /**\n * Gets the name of the node.\n */\n public abstract getName(): string;\n\n /**\n * Gets whether this node is a leaf node.\n */\n public abstract isLeafNode: () => this is Leaf;\n\n /**\n * Gets/Sets the state of the node.\n */\n getState = (): AnyState => this.state;\n setState = (value: AnyState): void => {\n this.state = value;\n };\n\n /**\n * Gets the unique id of the node.\n */\n getUid = () => this.uid;\n\n /**\n * Gets the type of the node.\n */\n getType = () => this.type;\n\n /**\n * Gets the node attributes.\n */\n getAttributes = () => this.attributes;\n\n /**\n * Gets the node arguments.\n */\n getArguments = () => this.args;\n\n /**\n * Gets the node attribute with the specified type, or null if it does not exist.\n */\n getAttribute(type: \"entry\" | \"ENTRY\"): Entry;\n getAttribute(type: \"exit\" | \"EXIT\"): Exit;\n getAttribute(type: \"step\" | \"STEP\"): Step;\n getAttribute(type: string): Attribute {\n return (\n this.getAttributes().filter((decorator) => decorator.getType().toUpperCase() === type.toUpperCase())[0] ||\n null\n );\n }\n\n /**\n * Gets the node attributes.\n */\n getGuardAttributes = (): Guard[] => this.getAttributes().filter((decorator) => decorator.isGuard()) as Guard[];\n\n /**\n * Sets the guard path to evaluate as part of a node update.\n */\n setGuardPath = (value: GuardPath) => (this.guardPath = value);\n\n /**\n * Gets whether a guard path is assigned to this node.\n */\n hasGuardPath = () => !!this.guardPath;\n\n /**\n * Gets whether this node is in the specified state.\n * @param value The value to compare to the node state.\n */\n public is(value: AnyState): boolean {\n return this.state === value;\n }\n\n /**\n * Reset the state of the node.\n */\n public reset(): void {\n this.setState(State.READY);\n }\n\n /**\n * Abort the running of this node.\n * @param agent The agent.\n */\n public abort(agent: Agent): void {\n // There is nothing to do if this node is not in the running state.\n if (!this.is(State.RUNNING)) {\n return;\n }\n\n // Reset the state of this node.\n this.reset();\n\n this.getAttribute(\"exit\")?.callAgentFunction(agent, false, true);\n }\n\n /**\n * Update the node.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n * @returns The result of the update.\n */\n public update(agent: Agent, options: BehaviourTreeOptions): void {\n // If this node is already in a 'SUCCEEDED' or 'FAILED' state then there is nothing to do.\n if (this.is(State.SUCCEEDED) || this.is(State.FAILED)) {\n return;\n }\n\n try {\n // Evaluate all of the guard path conditions for the current tree path.\n this.guardPath!.evaluate(agent);\n\n // If this node is in the READY state then call the ENTRY for this node if it exists.\n if (this.is(State.READY)) {\n this.getAttribute(\"entry\")?.callAgentFunction(agent);\n }\n\n this.getAttribute(\"step\")?.callAgentFunction(agent);\n\n // Do the actual update.\n this.onUpdate(agent, options);\n\n // If this node is now in a 'SUCCEEDED' or 'FAILED' state then call the EXIT for this node if it exists.\n if (this.is(State.SUCCEEDED) || this.is(State.FAILED)) {\n this.getAttribute(\"exit\")?.callAgentFunction(agent, this.is(State.SUCCEEDED), false);\n }\n } catch (error) {\n // If the error is a GuardUnsatisfiedException then we need to determine if this node is the source.\n if (error instanceof GuardUnsatisifedException && error.isSourceNode(this)) {\n // Abort the current node.\n this.abort(agent);\n\n // Any node that is the source of an abort will be a failed node.\n this.setState(State.FAILED);\n } else {\n throw error;\n }\n }\n }\n}\n\n/**\n * Create a randomly generated node uid.\n * @returns A randomly generated node uid.\n */\nfunction createNodeUid(): string {\n var S4 = function () {\n return (((1 + Math.random()) * 0x10000) | 0).toString(16).substring(1);\n };\n return S4() + S4() + \"-\" + S4() + \"-\" + S4() + \"-\" + S4() + \"-\" + S4() + S4() + S4();\n}\n", "import Node from \"../Node\";\n\n/**\n * A leaf node.\n */\nexport default abstract class Leaf extends Node {\n /**\n * Gets whether this node is a leaf node.\n */\n isLeafNode = () => true;\n}\n", "import { ActionResult, Agent, ExitFunctionArg, FunctionArg, GlobalFunction } from \"./Agent\";\nimport { AnyArgument, RootAstNode } from \"./RootAstNodesBuilder\";\n\n// Exit callbacks receive their own special type of argument.\n// There's probably stricter ways to represent this but it feels overly complex right now.\ntype ExitResultArg = { value: ExitFunctionArg };\nexport type AnyExitArgument = AnyArgument | ExitResultArg;\n\nexport type InvokerFunction = (args: AnyExitArgument[]) => ActionResult;\n\n/**\n * A singleton used to store and lookup registered functions and subtrees.\n */\nexport default class Lookup {\n /**\n * The object holding any registered functions keyed on function name.\n */\n private static functionTable: { [key: string]: GlobalFunction } = {};\n /**\n * The object holding any registered sub-trees keyed on tree name.\n */\n private static subtreeTable: { [key: string]: RootAstNode } = {};\n\n /**\n * Gets the function with the specified name.\n * @param name The name of the function.\n * @returns The function with the specified name.\n */\n public static getFunc(name: string): GlobalFunction {\n return this.functionTable[name];\n }\n\n /**\n * Sets the function with the specified name for later lookup.\n * @param name The name of the function.\n * @param func The function.\n */\n public static setFunc(name: string, func: GlobalFunction): void {\n this.functionTable[name] = func;\n }\n\n /**\n * Gets the function invoker for the specified agent and function name.\n * If a function with the specified name exists on the agent object then it will\n * be returned, otherwise we will then check the registered functions for a match.\n * @param agent The agent instance that this behaviour tree is modelling behaviour for.\n * @param name The function name.\n * @returns The function invoker for the specified agent and function name.\n */\n static getFuncInvoker(agent: Agent, name: string): InvokerFunction | null {\n // Check whether the agent contains the specified function.\n const foundOnAgent = agent[name];\n if (foundOnAgent && typeof foundOnAgent === \"function\") {\n return (args: AnyExitArgument[]): boolean | ActionResult =>\n foundOnAgent.apply(\n agent,\n args.map((arg) => arg.value)\n );\n }\n\n // The agent does not contain the specified function but it may have been registered at some point.\n if (this.functionTable[name] && typeof this.functionTable[name] === \"function\") {\n return (args: AnyExitArgument[]) => this.functionTable[name](agent, ...args.map((arg) => arg.value));\n }\n\n // We have no function to invoke.\n return null;\n }\n\n /**\n * Gets the subtree with the specified name.\n * @param name The name of the subtree.\n * @returns The subtree with the specified name.\n */\n static getSubtree(name: string): RootAstNode {\n return this.subtreeTable[name];\n }\n\n /**\n * Sets the subtree with the specified name for later lookup.\n * @param name The name of the subtree.\n * @param subtree The subtree.\n */\n static setSubtree(name: string, subtree: RootAstNode) {\n this.subtreeTable[name] = subtree;\n }\n\n /**\n * Removes the registered function or subtree with the specified name.\n * @param name The name of the registered function or subtree.\n */\n static remove(name: string) {\n delete this.functionTable[name];\n delete this.subtreeTable[name];\n }\n\n /**\n * Remove all registered functions and subtrees.\n */\n static empty() {\n this.functionTable = {};\n this.subtreeTable = {};\n }\n}\n", "import Leaf from \"./Leaf\";\nimport State, { CompleteState } from \"../../State\";\nimport Lookup from \"../../Lookup\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { AnyArgument } from \"../../RootAstNodesBuilder\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * An Action leaf node.\n * This represents an immediate or ongoing state of behaviour.\n */\nexport default class Action extends Leaf {\n /**\n * @param attributes The node attributes.\n * @param actionName The action name.\n * @param actionArguments The array of action argument definitions.\n */\n constructor(attributes: Attribute[], private actionName: string, private actionArguments: AnyArgument[]) {\n super(\"action\", attributes, actionArguments);\n }\n\n /**\n * Whether there is a pending update promise.\n */\n private isUsingUpdatePromise = false;\n\n /**\n * The finished state result of an update promise.\n */\n private updatePromiseStateResult: CompleteState | null = null;\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // If the result of this action depends on an update promise then there is nothing to do until\n // it resolves, unless there has been a value set as a result of the update promise resolving.\n if (this.isUsingUpdatePromise) {\n // Check whether the update promise has resolved with a state value.\n if (this.updatePromiseStateResult) {\n // Set the state of this node to match the state returned by the promise.\n this.setState(this.updatePromiseStateResult);\n }\n\n return;\n }\n\n // Attempt to get the invoker for the action function.\n const actionFuncInvoker = Lookup.getFuncInvoker(agent, this.actionName);\n\n // The action function should be defined.\n if (actionFuncInvoker === null) {\n throw new Error(\n `cannot update action node as the action '${this.actionName}' function is not defined on the agent and has not been registered`\n );\n }\n\n // Call the action function, the result of which may be:\n // - The finished state of this action node.\n // - A promise to return a finished node state.\n // - Undefined if the node should remain in the running state.\n const updateResult = actionFuncInvoker(this.actionArguments) as CompleteState | Promise;\n\n if (updateResult instanceof Promise) {\n updateResult.then(\n (result) => {\n // If 'isUpdatePromisePending' is null then the promise was cleared as it was resolving, probably via an abort of reset.\n if (!this.isUsingUpdatePromise) {\n return;\n }\n\n // Check to make sure the result is a valid finished state.\n if (result !== State.SUCCEEDED && result !== State.FAILED) {\n throw new Error(\n \"action node promise resolved with an invalid value, expected a State.SUCCEEDED or State.FAILED value to be returned\"\n );\n }\n\n // Set pending update promise state result to be processed on next update.\n this.updatePromiseStateResult = result;\n },\n (reason) => {\n // If 'isUpdatePromisePending' is null then the promise was cleared as it was resolving, probably via an abort of reset.\n if (!this.isUsingUpdatePromise) {\n return;\n }\n\n // Just throw whatever was returned as the rejection argument.\n throw new Error(reason);\n }\n );\n\n // This node will be in the 'RUNNING' state until the update promise resolves.\n this.setState(State.RUNNING);\n\n // We are now waiting for the promise returned by the use to resolve before we know what state this node is in.\n this.isUsingUpdatePromise = true;\n } else {\n // Validate the returned value.\n this.validateUpdateResult(updateResult);\n\n // Set the state of this node, this may be undefined, which just means that the node is still in the 'RUNNING' state.\n this.setState(updateResult || State.RUNNING);\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => this.actionName;\n\n /**\n * Reset the state of the node.\n */\n reset = () => {\n // Reset the state of this node.\n this.setState(State.READY);\n\n // There is no longer an update promise that we care about.\n this.isUsingUpdatePromise = false;\n this.updatePromiseStateResult = null;\n };\n\n /**\n * Validate the result of an update function call.\n * @param result The result of an update function call.\n */\n private validateUpdateResult = (result: CompleteState | boolean) => {\n switch (result) {\n case State.SUCCEEDED:\n case State.FAILED:\n case undefined:\n return;\n default:\n throw new Error(\n `action '${this.actionName}' 'onUpdate' returned an invalid response, expected an optional State.SUCCEEDED or State.FAILED value to be returned`\n );\n }\n };\n}\n", "import Leaf from \"./Leaf\";\nimport State from \"../../State\";\nimport Lookup from \"../../Lookup\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { AnyArgument } from \"../../RootAstNodesBuilder\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A Condition leaf node.\n * This will succeed or fail immediately based on an agent predicate, without moving to the 'RUNNING' state.\n */\nexport default class Condition extends Leaf {\n /**\n * @param attributes The node attributes.\n * @param conditionName The name of the condition function.\n * @param conditionArguments The array of condition argument definitions.\n */\n constructor(attributes: Attribute[], private conditionName: string, private conditionArguments: AnyArgument[]) {\n super(\"condition\", attributes, conditionArguments);\n }\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // Attempt to get the invoker for the condition function.\n const conditionFuncInvoker = Lookup.getFuncInvoker(agent, this.conditionName);\n\n // The condition function should be defined.\n if (conditionFuncInvoker === null) {\n throw new Error(\n `cannot update condition node as the condition '${this.conditionName}' function is not defined on the agent and has not been registered`\n );\n }\n\n // Call the condition function to determine the state of this node.\n this.setState(!!conditionFuncInvoker(this.conditionArguments) ? State.SUCCEEDED : State.FAILED);\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => this.conditionName;\n}\n", "import Leaf from \"./Leaf\";\nimport State from \"../../State\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { Agent } from \"../../Agent\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A WAIT node.\n * The state of this node will change to SUCCEEDED after a duration of time\n */\nexport default class Wait extends Leaf {\n /**\n * @param attributes The node attributes.\n * @param duration The duration that this node will wait to succeed in milliseconds.\n * @param durationMin The minimum possible duration in milliseconds that this node will wait to succeed.\n * @param durationMax The maximum possible duration in milliseconds that this node will wait to succeed.\n */\n constructor(\n attributes: Attribute[],\n private duration: number | null,\n private durationMin: number | null,\n private durationMax: number | null\n ) {\n super(\"wait\", attributes, []);\n }\n\n /**\n * The time in milliseconds at which this node was first updated.\n */\n private initialUpdateTime: number = 0;\n\n /**\n * The total duration in milliseconds that this node will be waiting for.\n */\n private totalDuration: number | null = null;\n\n /**\n * The duration in milliseconds that this node has been waiting for.\n */\n private waitedDuration: number = 0;\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // If this node is in the READY state then we need to set the initial update time.\n if (this.is(State.READY)) {\n // Set the initial update time.\n this.initialUpdateTime = new Date().getTime();\n\n // Set the initial waited duration.\n this.waitedDuration = 0;\n\n // Are we dealing with an explicit duration or will we be randomly picking a duration between the min and max duration.\n if (this.duration !== null) {\n this.totalDuration = this.duration;\n } else if (this.durationMin !== null && this.durationMax !== null) {\n // We will be picking a random duration between a min and max duration, if the optional 'random' behaviour tree\n // function option is defined then we will be using that, otherwise we will fall back to using Math.random.\n const random = typeof options.random === \"function\" ? options.random : Math.random;\n\n // Pick a random duration between a min and max duration.\n this.totalDuration = Math.floor(\n random() * (this.durationMax - this.durationMin + 1) + this.durationMin\n );\n } else {\n this.totalDuration = null;\n }\n\n // The node is now running until we finish waiting.\n this.setState(State.RUNNING);\n }\n\n // If we have no total duration then this wait node will wait indefinitely until it is aborted.\n if (this.totalDuration === null) {\n return;\n }\n\n // If we have a 'getDeltaTime' function defined as part of our options then we will use it to figure out how long we have waited for.\n if (typeof options.getDeltaTime === \"function\") {\n // Get the delta time.\n const deltaTime = options.getDeltaTime();\n\n // Our delta time must be a valid number and cannot be NaN.\n if (typeof deltaTime !== \"number\" || isNaN(deltaTime)) {\n throw new Error(\"The delta time must be a valid number and not NaN.\");\n }\n\n // Update the amount of time that this node has been waiting for based on the delta time.\n this.waitedDuration += deltaTime * 1000;\n } else {\n // We are not using a delta time, so we will just work out hom much time has passed since the first update.\n this.waitedDuration = new Date().getTime() - this.initialUpdateTime;\n }\n\n // Have we waited long enough?\n if (this.waitedDuration >= this.totalDuration) {\n // We have finished waiting!\n this.setState(State.SUCCEEDED);\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => {\n if (this.duration !== null) {\n return `WAIT ${this.duration}ms`;\n } else if (this.durationMin !== null && this.durationMax !== null) {\n return `WAIT ${this.durationMin}ms-${this.durationMax}ms`;\n } else {\n return \"WAIT\";\n }\n };\n}\n", "import Node from \"../Node\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\n\n/**\n * A decorator node that wraps a single child node.\n */\nexport default abstract class Decorator extends Node {\n /**\n * @param type The node type.\n * @param attributes The node attributes.\n * @param child The child node.\n */\n constructor(type: string, attributes: Attribute[], protected child: Node) {\n super(type, attributes, []);\n }\n\n /**\n * Gets whether this node is a leaf node.\n */\n isLeafNode = () => false;\n\n /**\n * Gets the children of this node.\n */\n getChildren = () => [this.child];\n\n /**\n * Reset the state of the node.\n */\n reset = () => {\n // Reset the state of this node.\n this.setState(State.READY);\n\n // Reset the state of the child node.\n this.child.reset();\n };\n\n /**\n * Abort the running of this node.\n * @param agent The agent.\n */\n abort = (agent: Agent) => {\n // There is nothing to do if this node is not in the running state.\n if (!this.is(State.RUNNING)) {\n return;\n }\n\n // Abort the child node.\n this.child.abort(agent);\n\n // Reset the state of this node.\n this.reset();\n\n this.getAttribute(\"exit\")?.callAgentFunction(agent, false, true);\n };\n}\n", "import Node from \"../Node\";\nimport Decorator from \"./Decorator\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A Root node.\n * The root node will have a single child.\n */\nexport default class Root extends Decorator {\n /**\n * @param attributes The node attributes.\n * @param child The child node.\n */\n constructor(attributes: Attribute[], child: Node) {\n super(\"root\", attributes, child);\n }\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // If the child has never been updated or is running then we will need to update it now.\n if (this.child.getState() === State.READY || this.child.getState() === State.RUNNING) {\n // Update the child of this node.\n this.child.update(agent, options);\n }\n\n // The state of the root node is the state of its child.\n this.setState(this.child.getState());\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => \"ROOT\";\n}\n", "import Node from \"../Node\";\nimport Decorator from \"./Decorator\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A REPEAT node.\n * The node has a single child which can have:\n * -- A number of iterations for which to repeat the child node.\n * -- An infinite repeat loop if neither an iteration count or a condition function is defined.\n * The REPEAT node will stop and have a 'FAILED' state if its child is ever in a 'FAILED' state after an update.\n * The REPEAT node will attempt to move on to the next iteration if its child is ever in a 'SUCCEEDED' state.\n */\nexport default class Repeat extends Decorator {\n /**\n * @param attributes The node attributes.\n * @param iterations The number of iterations to repeat the child node.\n * @param iterationsMin The minimum possible number of iterations to repeat the child node.\n * @param iterationsMax The maximum possible number of iterations to repeat the child node.\n * @param child The child node.\n */\n constructor(\n attributes: Attribute[],\n private iterations: number | null,\n private iterationsMin: number | null,\n private iterationsMax: number | null,\n child: Node\n ) {\n super(\"repeat\", attributes, child);\n }\n\n /**\n * The number of target iterations to make.\n */\n private targetIterationCount: number | null = null;\n\n /**\n * The current iteration count.\n */\n private currentIterationCount: number = 0;\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // If this node is in the READY state then we need to reset the child and the target iteration count.\n if (this.is(State.READY)) {\n // Reset the child node.\n this.child.reset();\n\n // Reset the current iteration count.\n this.currentIterationCount = 0;\n\n // Set the target iteration count.\n this.setTargetIterationCount(options);\n }\n\n // Do a check to see if we can iterate. If we can then this node will move into the 'RUNNING' state.\n // If we cannot iterate then we have hit our target iteration count, which means that the node has succeeded.\n if (this.canIterate()) {\n // This node is in the running state and can do its initial iteration.\n this.setState(State.RUNNING);\n\n // We may have already completed an iteration, meaning that the child node will be in the SUCCEEDED state.\n // If this is the case then we will have to reset the child node now.\n if (this.child.getState() === State.SUCCEEDED) {\n this.child.reset();\n }\n\n // Update the child of this node.\n this.child.update(agent, options);\n\n // If the child moved into the FAILED state when we updated it then there is nothing left to do and this node has also failed.\n // If it has moved into the SUCCEEDED state then we have completed the current iteration.\n if (this.child.getState() === State.FAILED) {\n // The child has failed, meaning that this node has failed.\n this.setState(State.FAILED);\n\n return;\n } else if (this.child.getState() === State.SUCCEEDED) {\n // We have completed an iteration.\n this.currentIterationCount += 1;\n }\n } else {\n // This node is in the 'SUCCEEDED' state as we cannot iterate any more.\n this.setState(State.SUCCEEDED);\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => {\n if (this.iterations !== null) {\n return `REPEAT ${this.iterations}x`;\n } else if (this.iterationsMin !== null && this.iterationsMax !== null) {\n return `REPEAT ${this.iterationsMin}x-${this.iterationsMax}x`;\n } else {\n return \"REPEAT\";\n }\n };\n\n /**\n * Reset the state of the node.\n */\n reset = () => {\n // Reset the state of this node.\n this.setState(State.READY);\n\n // Reset the current iteration count.\n this.currentIterationCount = 0;\n\n // Reset the child node.\n this.child.reset();\n };\n\n /**\n * Gets whether an iteration can be made.\n * @returns Whether an iteration can be made.\n */\n private canIterate = () => {\n if (this.targetIterationCount !== null) {\n // We can iterate as long as we have not reached our target iteration count.\n return this.currentIterationCount < this.targetIterationCount;\n }\n\n // If neither an iteration count or a condition function were defined then we can iterate indefinitely.\n return true;\n };\n\n /**\n * Sets the target iteration count.\n * @param options The behaviour tree options object.\n */\n private setTargetIterationCount = (options: BehaviourTreeOptions) => {\n // Are we dealing with an explicit iteration count or will we be randomly picking a iteration count between the min and max iteration count.\n if (this.iterations !== null) {\n this.targetIterationCount = this.iterations;\n } else if (this.iterationsMin !== null && this.iterationsMax !== null) {\n // We will be picking a random iteration count between a min and max iteration count, if the optional 'random'\n // behaviour tree function option is defined then we will be using that, otherwise we will fall back to using Math.random.\n const random = typeof options.random === \"function\" ? options.random : Math.random;\n\n // Pick a random iteration count between a min and max iteration count.\n this.targetIterationCount = Math.floor(\n random() * (this.iterationsMax - this.iterationsMin + 1) + this.iterationsMin\n );\n } else {\n this.targetIterationCount = null;\n }\n };\n}\n", "import Node from \"../Node\";\nimport Decorator from \"./Decorator\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A RETRY node.\n * The node has a single child which can have:\n * -- A number of iterations for which to repeat the child node.\n * -- An infinite repeat loop if neither an iteration count or a condition function is defined.\n * The RETRY node will stop and have a 'SUCCEEDED' state if its child is ever in a 'SUCCEEDED' state after an update.\n * The RETRY node will attempt to move on to the next iteration if its child is ever in a 'FAILED' state.\n */\nexport default class Retry extends Decorator {\n /**\n * @param attributes The node attributes.\n * @param attempts The number of attempts to retry the child node.\n * @param attemptsMin The minimum possible number of attempts to retry the child node.\n * @param attemptsMax The maximum possible number of attempts to retry the child node.\n * @param child The child node.\n */\n constructor(\n attributes: Attribute[],\n private attempts: number | null,\n private attemptsMin: number | null,\n private attemptsMax: number | null,\n child: Node\n ) {\n super(\"retry\", attributes, child);\n }\n\n /**\n * The number of target attempts to make.\n */\n private targetAttemptCount: number | null = null;\n\n /**\n * The current attempt count.\n */\n private currentAttemptCount: number = 0;\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // If this node is in the READY state then we need to reset the child and the target attempt count.\n if (this.is(State.READY)) {\n // Reset the child node.\n this.child.reset();\n\n // Reset the current attempt count.\n this.currentAttemptCount = 0;\n\n // Set the target attempt count.\n this.setTargetAttemptCount(options);\n }\n\n // Do a check to see if we can attempt. If we can then this node will move into the 'RUNNING' state.\n // If we cannot attempt then we have hit our target attempt count, which means that the node has succeeded.\n if (this.canAttempt()) {\n // This node is in the running state and can do its initial attempt.\n this.setState(State.RUNNING);\n\n // We may have already completed an attempt, meaning that the child node will be in the FAILED state.\n // If this is the case then we will have to reset the child node now.\n if (this.child.getState() === State.FAILED) {\n this.child.reset();\n }\n\n // Update the child of this node.\n this.child.update(agent, options);\n\n // If the child moved into the SUCCEEDED state when we updated it then there is nothing left to do and this node has also succeeded.\n // If it has moved into the FAILED state then we have completed the current attempt.\n if (this.child.getState() === State.SUCCEEDED) {\n // The child has succeeded, meaning that this node has succeeded.\n this.setState(State.SUCCEEDED);\n\n return;\n } else if (this.child.getState() === State.FAILED) {\n // We have completed an attempt.\n this.currentAttemptCount += 1;\n }\n } else {\n // This node is in the 'FAILED' state as we cannot iterate any more.\n this.setState(State.FAILED);\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => {\n if (this.attempts !== null) {\n return `RETRY ${this.attempts}x`;\n } else if (this.attemptsMin !== null && this.attemptsMax !== null) {\n return `RETRY ${this.attemptsMin}x-${this.attemptsMax}x`;\n } else {\n return \"RETRY\";\n }\n };\n\n /**\n * Reset the state of the node.\n */\n reset = () => {\n // Reset the state of this node.\n this.setState(State.READY);\n\n // Reset the current attempt count.\n this.currentAttemptCount = 0;\n\n // Reset the child node.\n this.child.reset();\n };\n\n /**\n * Gets whether an attempt can be made.\n * @returns Whether an attempt can be made.\n */\n canAttempt = () => {\n if (this.targetAttemptCount !== null) {\n // We can attempt as long as we have not reached our target attempt count.\n return this.currentAttemptCount < this.targetAttemptCount;\n }\n\n // If neither an attempt count or a condition function were defined then we can attempt indefinitely.\n return true;\n };\n\n /**\n * Sets the target attempt count.\n * @param options The behaviour tree options object.\n */\n setTargetAttemptCount = (options: BehaviourTreeOptions) => {\n // Are we dealing with an explicit attempt count or will we be randomly picking an attempt count between the min and max attempt count.\n if (this.attempts !== null) {\n this.targetAttemptCount = this.attempts;\n } else if (this.attemptsMin !== null && this.attemptsMax !== null) {\n // We will be picking a random attempt count between a min and max attempt count, if the optional 'random'\n // behaviour tree function option is defined then we will be using that, otherwise we will fall back to using Math.random.\n const random = typeof options.random === \"function\" ? options.random : Math.random;\n\n // Pick a random attempt count between a min and max attempt count.\n this.targetAttemptCount = Math.floor(\n random() * (this.attemptsMax - this.attemptsMin + 1) + this.attemptsMin\n );\n } else {\n this.targetAttemptCount = null;\n }\n };\n}\n", "import Decorator from \"./Decorator\";\nimport State from \"../../State\";\nimport Node from \"../Node\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A Flip node.\n * This node wraps a single child and will flip the state of the child state.\n */\nexport default class Flip extends Decorator {\n /**\n * @param attributes The node attributes.\n * @param child The child node.\n */\n constructor(attributes: Attribute[], child: Node) {\n super(\"flip\", attributes, child);\n }\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // If the child has never been updated or is running then we will need to update it now.\n if (this.child.getState() === State.READY || this.child.getState() === State.RUNNING) {\n this.child.update(agent, options);\n }\n\n // The state of this node will depend in the state of its child.\n switch (this.child.getState()) {\n case State.RUNNING:\n this.setState(State.RUNNING);\n break;\n\n case State.SUCCEEDED:\n this.setState(State.FAILED);\n break;\n\n case State.FAILED:\n this.setState(State.SUCCEEDED);\n break;\n\n default:\n this.setState(State.READY);\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => \"FLIP\";\n}\n", "import Node from \"../Node\";\nimport Decorator from \"./Decorator\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A Succeed node.\n * This node wraps a single child and will always move to the 'SUCCEEDED' state when the child moves to a 'SUCCEEDED' or 'FAILED' state.\n */\nexport default class Succeed extends Decorator {\n /**\n * @param attributes The node attributes.\n * @param child The child node.\n */\n constructor(attributes: Attribute[], child: Node) {\n super(\"succeed\", attributes, child);\n }\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // If the child has never been updated or is running then we will need to update it now.\n if (this.child.getState() === State.READY || this.child.getState() === State.RUNNING) {\n this.child.update(agent, options);\n }\n\n // The state of this node will depend in the state of its child.\n switch (this.child.getState()) {\n case State.RUNNING:\n this.setState(State.RUNNING);\n break;\n\n case State.SUCCEEDED:\n case State.FAILED:\n this.setState(State.SUCCEEDED);\n break;\n\n default:\n this.setState(State.READY);\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => \"SUCCEED\";\n}\n", "import Node from \"../Node\";\nimport Decorator from \"./Decorator\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A Fail node.\n * This node wraps a single child and will always move to the 'FAILED' state when the child moves to a 'SUCCEEDED' or 'FAILED' state.\n */\nexport default class Fail extends Decorator {\n /**\n * @param attributes The node attributes.\n * @param child The child node.\n */\n constructor(attributes: Attribute[], child: Node) {\n super(\"fail\", attributes, child);\n }\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // If the child has never been updated or is running then we will need to update it now.\n if (this.child.getState() === State.READY || this.child.getState() === State.RUNNING) {\n this.child.update(agent, options);\n }\n\n // The state of this node will depend in the state of its child.\n switch (this.child.getState()) {\n case State.RUNNING:\n this.setState(State.RUNNING);\n break;\n\n case State.SUCCEEDED:\n case State.FAILED:\n this.setState(State.FAILED);\n break;\n\n default:\n this.setState(State.READY);\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => \"FAIL\";\n}\n", "import createLotto from \"lotto-draw\";\n\nimport Node from \"../Node\";\nimport Composite from \"./Composite\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A LOTTO node.\n * A winning child is picked on the initial update of this node, based on ticket weighting.\n * The state of this node will match the state of the winning child.\n */\nexport default class Lotto extends Composite {\n /**\n * @param attributes The node attributes.\n * @param tickets The child node tickets.\n * @param children The child nodes.\n */\n constructor(attributes: Attribute[], private tickets: number[], children: Node[]) {\n super(\"lotto\", attributes, children);\n }\n\n /**\n * The child node selected to be the active one.\n */\n private selectedChild: Node | undefined;\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // If this node is in the READY state then we need to pick a winning child node.\n if (this.is(State.READY)) {\n // Create a lotto draw with which to randomly pick a child node to become the active one.\n const lottoDraw = createLotto({\n // Hook up the optional 'random' behaviour tree function option to the one used by 'lotto-draw'.\n random: options.random,\n // Pass in each child node as a participant in the lotto draw with their respective ticket count.\n participants: this.children.map((child, index) => [child, this.tickets[index] || 1])\n });\n\n // Randomly pick a child based on ticket weighting, this will become the active child for this composite node.\n this.selectedChild = lottoDraw.draw() || undefined;\n }\n\n // If something went wrong and we don't have an active child then we should throw an error.\n if (!this.selectedChild) {\n throw new Error(\"failed to update lotto node as it has no active child\");\n }\n\n // If the selected child has never been updated or is running then we will need to update it now.\n if (this.selectedChild.getState() === State.READY || this.selectedChild.getState() === State.RUNNING) {\n this.selectedChild.update(agent, options);\n }\n\n // The state of the lotto node is the state of its selected child.\n this.setState(this.selectedChild.getState());\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => (this.tickets.length ? `LOTTO [${this.tickets.join(\",\")}]` : \"LOTTO\");\n}\n", "import Node from \"../Node\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\n\n/**\n * A composite node that wraps child nodes.\n */\nexport default abstract class Composite extends Node {\n /**\n * @param type The node type.\n * @param attributes The node attributes.\n * @param children The child nodes.\n */\n constructor(type: string, attributes: Attribute[], protected children: Node[]) {\n super(type, attributes, []);\n }\n\n /**\n * Gets whether this node is a leaf node.\n */\n isLeafNode = () => false;\n\n /**\n * Gets the children of this node.\n */\n getChildren = () => this.children;\n\n /**\n * Reset the state of the node.\n */\n reset = () => {\n // Reset the state of this node.\n this.setState(State.READY);\n\n // Reset the state of any child nodes.\n this.getChildren().forEach((child) => child.reset());\n };\n\n /**\n * Abort the running of this node.\n * @param agent The agent.\n */\n abort = (agent: Agent) => {\n // There is nothing to do if this node is not in the running state.\n if (!this.is(State.RUNNING)) {\n return;\n }\n\n // Abort any child nodes.\n this.getChildren().forEach((child) => child.abort(agent));\n\n // Reset the state of this node.\n this.reset();\n\n this.getAttribute(\"exit\")?.callAgentFunction(agent, false, true);\n };\n}\n", "import Composite from \"./Composite\";\nimport Node from \"../Node\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A SELECTOR node.\n * The child nodes are executed in sequence until one succeeds or all fail.\n */\nexport default class Selector extends Composite {\n /**\n * @param attributes The node attributes.\n * @param children The child nodes.\n */\n constructor(attributes: Attribute[], protected children: Node[]) {\n super(\"selector\", attributes, children);\n }\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // Iterate over all of the children of this node.\n for (const child of this.children) {\n // If the child has never been updated or is running then we will need to update it now.\n if (child.getState() === State.READY || child.getState() === State.RUNNING) {\n // Update the child of this node.\n child.update(agent, options);\n }\n\n // If the current child has a state of 'SUCCEEDED' then this node is also a 'SUCCEEDED' node.\n if (child.getState() === State.SUCCEEDED) {\n // This node is a 'SUCCEEDED' node.\n this.setState(State.SUCCEEDED);\n\n // There is no need to check the rest of the selector nodes.\n return;\n }\n\n // If the current child has a state of 'FAILED' then we should move on to the next child.\n if (child.getState() === State.FAILED) {\n // Find out if the current child is the last one in the selector.\n // If it is then this sequence node has also failed.\n if (this.children.indexOf(child) === this.children.length - 1) {\n // This node is a 'FAILED' node.\n this.setState(State.FAILED);\n\n // There is no need to check the rest of the selector as we have completed it.\n return;\n } else {\n // The child node failed, try the next one.\n continue;\n }\n }\n\n // The node should be in the 'RUNNING' state.\n if (child.getState() === State.RUNNING) {\n // This node is a 'RUNNING' node.\n this.setState(State.RUNNING);\n\n // There is no need to check the rest of the selector as the current child is still running.\n return;\n }\n\n // The child node was not in an expected state.\n throw new Error(\"child node was not in an expected state.\");\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => \"SELECTOR\";\n}\n", "import Composite from \"./Composite\";\nimport Node from \"../Node\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A SEQUENCE node.\n * The child nodes are executed in sequence until one fails or all succeed.\n */\nexport default class Sequence extends Composite {\n /**\n * @param attributes The node attributes.\n * @param children The child nodes.\n */\n constructor(attributes: Attribute[], protected children: Node[]) {\n super(\"sequence\", attributes, children);\n }\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // Iterate over all of the children of this node.\n for (const child of this.children) {\n // If the child has never been updated or is running then we will need to update it now.\n if (child.getState() === State.READY || child.getState() === State.RUNNING) {\n // Update the child of this node.\n child.update(agent, options);\n }\n\n // If the current child has a state of 'SUCCEEDED' then we should move on to the next child.\n if (child.getState() === State.SUCCEEDED) {\n // Find out if the current child is the last one in the sequence.\n // If it is then this sequence node has also succeeded.\n if (this.children.indexOf(child) === this.children.length - 1) {\n // This node is a 'SUCCEEDED' node.\n this.setState(State.SUCCEEDED);\n\n // There is no need to check the rest of the sequence as we have completed it.\n return;\n } else {\n // The child node succeeded, but we have not finished the sequence yet.\n continue;\n }\n }\n\n // If the current child has a state of 'FAILED' then this node is also a 'FAILED' node.\n if (child.getState() === State.FAILED) {\n // This node is a 'FAILED' node.\n this.setState(State.FAILED);\n\n // There is no need to check the rest of the sequence.\n return;\n }\n\n // The node should be in the 'RUNNING' state.\n if (child.getState() === State.RUNNING) {\n // This node is a 'RUNNING' node.\n this.setState(State.RUNNING);\n\n // There is no need to check the rest of the sequence as the current child is still running.\n return;\n }\n\n // The child node was not in an expected state.\n throw new Error(\"child node was not in an expected state.\");\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => \"SEQUENCE\";\n}\n", "import Composite from \"./Composite\";\nimport State from \"../../State\";\nimport Node from \"../Node\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A PARALLEL node.\n * The child nodes are executed concurrently until one fails or all succeed.\n */\nexport default class Parallel extends Composite {\n /**\n * @param attributes The node attributes.\n * @param children The child nodes.\n */\n constructor(attributes: Attribute[], children: Node[]) {\n super(\"parallel\", attributes, children);\n }\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // Keep a count of the number of succeeded child nodes.\n let succeededCount = 0;\n\n let hasChildFailed = false;\n\n // Iterate over all of the children of this node.\n for (const child of this.children) {\n // If the child has never been updated or is running then we will need to update it now.\n if (child.getState() === State.READY || child.getState() === State.RUNNING) {\n // Update the child of this node.\n child.update(agent, options);\n }\n\n // If the current child has a state of 'SUCCEEDED' then we should move on to the next child.\n if (child.getState() === State.SUCCEEDED) {\n // The child node has succeeded, keep track of this to determine if all children have.\n succeededCount++;\n\n // The child node succeeded, but we have not finished checking every child node yet.\n continue;\n }\n\n // If the current child has a state of 'FAILED' then this node is also a 'FAILED' node.\n if (child.getState() === State.FAILED) {\n hasChildFailed = true;\n\n // There is no need to check the rest of the children.\n break;\n }\n\n // The node should be in the 'RUNNING' state.\n if (child.getState() !== State.RUNNING) {\n // The child node was not in an expected state.\n throw new Error(\"child node was not in an expected state.\");\n }\n }\n\n if (hasChildFailed) {\n // This node is a 'FAILED' node.\n this.setState(State.FAILED);\n\n // Abort every running child.\n for (const child of this.children) {\n if (child.getState() === State.RUNNING) {\n child.abort(agent);\n }\n }\n } else {\n // If all children have succeeded then this node has also succeeded, otherwise it is still running.\n this.setState(succeededCount === this.children.length ? State.SUCCEEDED : State.RUNNING);\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => \"PARALLEL\";\n}\n", "import { AnyArgument } from \"../RootAstNodesBuilder\";\nimport Guard from \"./guards/Guard\";\n\nexport type AttributeDetails = {\n /** The attribute type. */\n type: string;\n\n /** The attribute arguments. */\n args: AnyArgument[];\n};\n\n/**\n * A base node attribute.\n */\nexport default abstract class Attribute {\n /**\n * @param type The node attribute type.\n * @param args The array of attribute argument definitions.\n */\n constructor(protected type: string, protected args: AnyArgument[]) {}\n\n /**\n * Gets the type of the attribute.\n */\n getType = () => this.type;\n\n /**\n * Gets the array of attribute argument definitions.\n */\n getArguments = () => this.args;\n\n /**\n * Gets the attribute details.\n */\n abstract getDetails(): TAttributeDetails;\n\n /**\n * Gets whether this attribute is a guard.\n */\n abstract isGuard: () => this is Guard;\n}\n", "import { Agent } from \"../../Agent\";\nimport { AnyArgument } from \"../../RootAstNodesBuilder\";\nimport Attribute, { AttributeDetails } from \"../Attribute\";\n\nexport type GuardAttributeDetails = {\n /** The name of the condition function that determines whether the guard is satisfied. */\n condition: string;\n} & AttributeDetails;\n\n/**\n * A base node guard attribute.\n */\nexport default abstract class Guard extends Attribute {\n /**\n * @param type The node attribute type.\n * @param args The array of decorator argument definitions.\n * @param condition The name of the condition function that determines whether the guard is satisfied.\n */\n constructor(type: string, args: AnyArgument[], private condition: string) {\n super(type, args);\n }\n\n /**\n * Gets the name of the condition function that determines whether the guard is satisfied.\n */\n getCondition = () => this.condition;\n\n /**\n * Gets whether this attribute is a guard.\n */\n isGuard = () => true;\n\n /**\n * Gets the attribute details.\n */\n getDetails(): GuardAttributeDetails {\n return {\n type: this.getType(),\n args: this.getArguments(),\n condition: this.getCondition()\n };\n }\n\n /**\n * Gets whether the guard is satisfied.\n * @param agent The agent.\n * @returns Whether the guard is satisfied.\n */\n abstract isSatisfied(agent: Agent): boolean;\n}\n", "import Guard from \"./Guard\";\nimport Lookup from \"../../Lookup\";\nimport { Agent } from \"../../Agent\";\nimport { AnyArgument } from \"../../RootAstNodesBuilder\";\n\n/**\n * A WHILE guard which is satisfied as long as the given condition remains true.\n */\nexport default class While extends Guard {\n /**\n * @param condition The name of the condition function that determines whether the guard is satisfied.\n * @param args The array of decorator argument definitions.\n */\n constructor(condition: string, args: AnyArgument[]) {\n super(\"while\", args, condition);\n }\n\n /**\n * Gets whether the guard is satisfied.\n * @param agent The agent.\n * @returns Whether the guard is satisfied.\n */\n isSatisfied = (agent: Agent) => {\n // Attempt to get the invoker for the condition function.\n const conditionFuncInvoker = Lookup.getFuncInvoker(agent, this.getCondition());\n\n // The condition function should be defined.\n if (conditionFuncInvoker === null) {\n throw new Error(\n `cannot evaluate node guard as the condition '${this.getCondition()}' function is not defined on the agent and has not been registered`\n );\n }\n\n // Call the condition function to determine whether this guard is satisfied.\n return !!conditionFuncInvoker(this.args);\n };\n}\n", "import Guard from \"./Guard\";\nimport Lookup from \"../../Lookup\";\nimport { Agent } from \"../../Agent\";\nimport { AnyArgument } from \"../../RootAstNodesBuilder\";\n\n/**\n * An UNTIL guard which is satisfied as long as the given condition remains false.\n */\nexport default class Until extends Guard {\n /**\n * @param condition The name of the condition function that determines whether the guard is satisfied.\n * @param args The array of decorator argument definitions.\n */\n constructor(condition: string, args: AnyArgument[]) {\n super(\"until\", args, condition);\n }\n\n /**\n * Gets whether the guard is satisfied.\n * @param agent The agent.\n * @returns Whether the guard is satisfied.\n */\n isSatisfied = (agent: Agent) => {\n // Attempt to get the invoker for the condition function.\n const conditionFuncInvoker = Lookup.getFuncInvoker(agent, this.getCondition());\n\n // The condition function should be defined.\n if (conditionFuncInvoker === null) {\n throw new Error(\n `cannot evaluate node guard as the condition '${this.getCondition()}' function is not defined on the agent and has not been registered`\n );\n }\n\n // Call the condition function to determine whether this guard is satisfied.\n return !!!conditionFuncInvoker(this.args);\n };\n}\n", "import { Agent } from \"../../Agent\";\nimport { AnyArgument } from \"../../RootAstNodesBuilder\";\nimport Attribute, { AttributeDetails } from \"../Attribute\";\n\nexport type CallbackAttributeDetails = {\n /** The name of the agent function that is called. */\n functionName: string;\n} & AttributeDetails;\n\n/**\n * A base node callback attribute.\n */\nexport default abstract class Callback extends Attribute {\n /**\n * @param type The node attribute type.\n * @param args The array of decorator argument definitions.\n * @param functionName The name of the agent function to call.\n */\n constructor(type: string, args: AnyArgument[], private functionName: string) {\n super(type, args);\n }\n\n /**\n * Gets the name of the agent function to call.\n */\n getFunctionName = () => this.functionName;\n\n /**\n * Gets whether this attribute is a guard.\n */\n isGuard = () => false;\n\n /**\n * Gets the attribute details.\n */\n getDetails(): CallbackAttributeDetails {\n return {\n type: this.getType(),\n args: this.getArguments(),\n functionName: this.getFunctionName()\n };\n }\n\n /**\n * Attempt to call the agent function that this callback refers to.\n * @param agent The agent.\n */\n abstract callAgentFunction: (agent: Agent, isSuccess: boolean, isAborted: boolean) => void;\n}\n", "import Callback from \"./Callback\";\nimport Lookup from \"../../Lookup\";\nimport { Agent } from \"../../Agent\";\nimport { AnyArgument } from \"../../RootAstNodesBuilder\";\n\n/**\n * An ENTRY callback which defines an agent function to call when the associated node is updated and moves out of running state.\n */\nexport default class Entry extends Callback {\n /**\n * @param functionName The name of the agent function to call.\n * @param args The array of callback argument definitions.\n */\n constructor(functionName: string, args: AnyArgument[]) {\n super(\"entry\", args, functionName);\n }\n\n /**\n * Attempt to call the agent function that this callback refers to.\n * @param agent The agent.\n */\n callAgentFunction = (agent: Agent) => {\n // Attempt to get the invoker for the callback function.\n const callbackFuncInvoker = Lookup.getFuncInvoker(agent, this.getFunctionName());\n\n // The callback function should be defined.\n if (callbackFuncInvoker === null) {\n throw new Error(\n `cannot call entry function '${this.getFunctionName()}' as is not defined on the agent and has not been registered`\n );\n }\n\n // Call the callback function.\n callbackFuncInvoker(this.args);\n };\n}\n", "import Callback from \"./Callback\";\nimport Lookup, { AnyExitArgument } from \"../../Lookup\";\nimport { Agent } from \"../../Agent\";\nimport { AnyArgument } from \"../../RootAstNodesBuilder\";\n\n/**\n * An EXIT callback which defines an agent function to call when the associated node is updated and moves to a finished state or is aborted.\n */\nexport default class Exit extends Callback {\n /**\n * @param functionName The name of the agent function to call.\n * @param args The array of callback argument definitions.\n */\n constructor(functionName: string, args: AnyArgument[]) {\n super(\"exit\", args, functionName);\n }\n\n /**\n * Attempt to call the agent function that this callback refers to.\n * @param agent The agent.\n * @param isSuccess Whether the decorated node was left with a success state.\n * @param isAborted Whether the decorated node was aborted.\n */\n callAgentFunction = (agent: Agent, isSuccess: boolean, isAborted: boolean) => {\n // Attempt to get the invoker for the callback function.\n const callbackFuncInvoker = Lookup.getFuncInvoker(agent, this.getFunctionName());\n\n // The callback function should be defined.\n if (callbackFuncInvoker === null) {\n throw new Error(\n `cannot call exit function '${this.getFunctionName()}' as is not defined on the agent and has not been registered`\n );\n }\n\n // Call the callback function\n callbackFuncInvoker([{ value: { succeeded: isSuccess, aborted: isAborted } }, ...this.args]);\n };\n}\n", "import Callback from \"./Callback\";\nimport Lookup from \"../../Lookup\";\nimport { Agent } from \"../../Agent\";\nimport { AnyArgument } from \"../../RootAstNodesBuilder\";\n\n/**\n * A STEP callback which defines an agent function to call when the associated node is updated.\n */\nexport default class Step extends Callback {\n /**\n * @param functionName The name of the agent function to call.\n * @param args The array of callback argument definitions.\n */\n constructor(functionName: string, args: AnyArgument[]) {\n super(\"step\", args, functionName);\n }\n\n /**\n * Attempt to call the agent function that this callback refers to.\n * @param agent The agent.\n */\n callAgentFunction = (agent: Agent) => {\n // Attempt to get the invoker for the callback function.\n const callbackFuncInvoker = Lookup.getFuncInvoker(agent, this.getFunctionName());\n\n // The callback function should be defined.\n if (callbackFuncInvoker === null) {\n throw new Error(\n `cannot call step function '${this.getFunctionName()}' as is not defined on the agent and has not been registered`\n );\n }\n\n // Call the callback function.\n callbackFuncInvoker(this.args);\n };\n}\n", "import Action from \"./nodes/leaf/Action\";\nimport Condition from \"./nodes/leaf/Condition\";\nimport Wait from \"./nodes/leaf/Wait\";\nimport Root from \"./nodes/decorator/Root\";\nimport Repeat from \"./nodes/decorator/Repeat\";\nimport Retry from \"./nodes/decorator/Retry\";\nimport Flip from \"./nodes/decorator/Flip\";\nimport Succeed from \"./nodes/decorator/Succeed\";\nimport Fail from \"./nodes/decorator/Fail\";\nimport Lotto from \"./nodes/composite/Lotto\";\nimport Selector from \"./nodes/composite/Selector\";\nimport Sequence from \"./nodes/composite/Sequence\";\nimport Parallel from \"./nodes/composite/Parallel\";\nimport Node from \"./nodes/Node\";\nimport While from \"./attributes/guards/While\";\nimport Until from \"./attributes/guards/Until\";\nimport Entry from \"./attributes/callbacks/Entry\";\nimport Exit from \"./attributes/callbacks/Exit\";\nimport Step from \"./attributes/callbacks/Step\";\nimport Callback from \"./attributes/callbacks/Callback\";\nimport Guard from \"./attributes/guards/Guard\";\nimport Attribute from \"./attributes/Attribute\";\nimport Composite from \"./nodes/composite/Composite\";\nimport Decorator from \"./nodes/decorator/Decorator\";\nimport Leaf from \"./nodes/leaf/Leaf\";\n\nexport type Argument = {\n value: T;\n type: string; // Used for validation.\n};\ntype NullArgument = Argument & {\n type: \"null\";\n};\ntype BooleanArgument = Argument & {\n type: \"boolean\";\n};\ntype NumberArgument = Argument & {\n type: \"number\";\n isInteger: boolean; // Used for validation.\n};\ntype StringPlaceholderArgument = Argument & {\n type: \"string\";\n};\ntype IdentifierArgument = Argument & {\n type: \"identifier\";\n};\nexport type AnyArgument =\n | NullArgument\n | BooleanArgument\n | NumberArgument\n | StringPlaceholderArgument\n | IdentifierArgument;\n\n/**\n * The node attribute factories.\n */\nconst AttributeFactories: {\n [key: string]: (functionName: string, attributeArguments: AnyArgument[]) => Callback | Guard;\n} = {\n WHILE: (condition: string, attributeArguments: AnyArgument[]) => new While(condition, attributeArguments),\n UNTIL: (condition: string, attributeArguments: AnyArgument[]) => new Until(condition, attributeArguments),\n ENTRY: (functionName: string, attributeArguments: AnyArgument[]) => new Entry(functionName, attributeArguments),\n EXIT: (functionName: string, attributeArguments: AnyArgument[]) => new Exit(functionName, attributeArguments),\n STEP: (functionName: string, attributeArguments: AnyArgument[]) => new Step(functionName, attributeArguments)\n};\n\ntype Validatable = {\n children?: AstNode[];\n validate: (depth: number) => void;\n};\n\ntype NodeInstanceCreator = (\n namedRootNodeProvider: (name: string) => RootAstNode,\n visitedBranches: string[]\n) => T;\n\nexport type AstNode = Validatable & {\n type: string;\n createNodeInstance: NodeInstanceCreator;\n};\n\nexport type LeafAstNode = AstNode & {\n type: \"action\" | \"condition\" | \"wait\";\n attributes: Attribute[];\n};\n\nexport type CompositeAstNode = AstNode & {\n type: \"lotto\" | \"parallel\" | \"selector\" | \"sequence\";\n attributes: Attribute[];\n children: AstNode[];\n};\n\nexport type DecoratorAstNode = AstNode & {\n type: \"fail\" | \"flip\" | \"repeat\" | \"retry\" | \"root\" | \"succeed\";\n attributes: Attribute[];\n children: AstNode[];\n};\n\nexport type BranchAstNode = AstNode & {\n type: \"branch\";\n branchName: \"\" | string;\n};\n\nexport type LottoAstNode = CompositeAstNode & {\n type: \"lotto\";\n tickets: number[];\n};\n\nexport type RootAstNode = DecoratorAstNode & {\n type: \"root\";\n name: null | string;\n};\n\nexport type RepeatAstNode = DecoratorAstNode & {\n type: \"repeat\";\n iterations: number | null;\n iterationsMin: number | null;\n iterationsMax: number | null;\n};\n\nexport type RetryAstNode = DecoratorAstNode & {\n type: \"retry\";\n attempts: number | null;\n attemptsMin: number | null;\n attemptsMax: number | null;\n};\n\nexport type ActionAstNode = LeafAstNode & {\n type: \"action\";\n actionName: string;\n actionArguments: AnyArgument[];\n};\n\nexport type ConditionAstNode = LeafAstNode & {\n type: \"condition\";\n conditionName: string;\n conditionArguments: AnyArgument[];\n};\n\nexport type WaitAstNode = LeafAstNode & {\n type: \"wait\";\n duration: number | null;\n durationMin: number | null;\n durationMax: number | null;\n};\n\nexport type AnyAstNode =\n | BranchAstNode\n | CompositeAstNode\n | LottoAstNode\n | DecoratorAstNode\n | RootAstNode\n | RepeatAstNode\n | RetryAstNode\n | LeafAstNode\n | ActionAstNode\n | ConditionAstNode\n | WaitAstNode;\n\n/**\n * The AST node factories.\n */\nconst ASTNodeFactories = {\n ROOT: (): RootAstNode => ({\n type: \"root\",\n attributes: [],\n name: null,\n children: [],\n validate(depth: number) {\n // A root node cannot be the child of another node.\n if (depth > 1) {\n throw new Error(\"a root node cannot be the child of another node\");\n }\n\n // A root node must have a single child node.\n if (this.children.length !== 1) {\n throw new Error(\"a root node must have a single child\");\n }\n },\n createNodeInstance(namedRootNodeProvider, visitedBranches) {\n return new Root(\n this.attributes,\n this.children![0].createNodeInstance(namedRootNodeProvider, visitedBranches.slice())\n );\n }\n }),\n BRANCH: (): BranchAstNode => ({\n type: \"branch\",\n branchName: \"\",\n validate() {},\n createNodeInstance(namedRootNodeProvider, visitedBranches) {\n // Try to find the root node with a matching branch name.\n const targetRootNode = namedRootNodeProvider(this.branchName);\n\n // If we have already visited this branch then we have a circular dependency.\n if (visitedBranches.indexOf(this.branchName) !== -1) {\n throw new Error(`circular dependency found in branch node references for branch '${this.branchName}'`);\n }\n\n // If we have a target root node, then the node instance we want will be the first and only child of the referenced root node.\n if (targetRootNode) {\n return targetRootNode\n .createNodeInstance(namedRootNodeProvider, visitedBranches.concat(this.branchName))\n .getChildren()[0];\n } else {\n throw new Error(`branch references root node '${this.branchName}' which has not been defined`);\n }\n }\n }),\n SELECTOR: (): CompositeAstNode => ({\n type: \"selector\",\n attributes: [],\n children: [],\n validate() {\n // A selector node must have at least a single node.\n if (this.children.length < 1) {\n throw new Error(\"a selector node must have at least a single child\");\n }\n },\n createNodeInstance(namedRootNodeProvider, visitedBranches) {\n return new Selector(\n this.attributes,\n this.children.map((child) => child.createNodeInstance(namedRootNodeProvider, visitedBranches.slice()))\n );\n }\n }),\n SEQUENCE: (): CompositeAstNode => ({\n type: \"sequence\",\n attributes: [],\n children: [],\n validate() {\n // A sequence node must have at least a single node.\n if (this.children.length < 1) {\n throw new Error(\"a sequence node must have at least a single child\");\n }\n },\n createNodeInstance(namedRootNodeProvider, visitedBranches) {\n return new Sequence(\n this.attributes,\n this.children.map((child) => child.createNodeInstance(namedRootNodeProvider, visitedBranches.slice()))\n );\n }\n }),\n PARALLEL: (): CompositeAstNode => ({\n type: \"parallel\",\n attributes: [],\n children: [],\n validate() {\n // A parallel node must have at least a single node.\n if (this.children.length < 1) {\n throw new Error(\"a parallel node must have at least a single child\");\n }\n },\n createNodeInstance(namedRootNodeProvider, visitedBranches) {\n return new Parallel(\n this.attributes,\n this.children.map((child) => child.createNodeInstance(namedRootNodeProvider, visitedBranches.slice()))\n );\n }\n }),\n LOTTO: (): LottoAstNode => ({\n type: \"lotto\",\n attributes: [],\n children: [],\n tickets: [],\n validate() {\n // A lotto node must have at least a single node.\n if (this.children!.length < 1) {\n throw new Error(\"a lotto node must have at least a single child\");\n }\n },\n createNodeInstance(namedRootNodeProvider, visitedBranches) {\n return new Lotto(\n this.attributes,\n this.tickets!,\n this.children!.map((child) => child.createNodeInstance(namedRootNodeProvider, visitedBranches.slice()))\n );\n }\n }),\n REPEAT: (): RepeatAstNode => ({\n type: \"repeat\",\n attributes: [],\n iterations: null,\n iterationsMin: null,\n iterationsMax: null,\n children: [],\n validate() {\n // A repeat node must have a single node.\n if (this.children!.length !== 1) {\n throw new Error(\"a repeat node must have a single child\");\n }\n\n if (this.iterations !== null) {\n // A repeat node must have a positive number of iterations if defined.\n if (this.iterations < 0) {\n throw new Error(\"a repeat node must have a positive number of iterations if defined\");\n }\n } else if (this.iterationsMin !== null && this.iterationsMax !== null) {\n // A repeat node must have a positive min and max iteration count if they are defined.\n if (this.iterationsMin < 0 || this.iterationsMax < 0) {\n throw new Error(\n \"a repeat node must have a positive minimum and maximum iteration count if defined\"\n );\n }\n\n // A repeat node must not have an minimum iteration count that exceeds the maximum iteration count.\n if (this.iterationsMin > this.iterationsMax) {\n throw new Error(\n \"a repeat node must not have a minimum iteration count that exceeds the maximum iteration count\"\n );\n }\n } else {\n // If we have no explicit iteration count or a minimum and maximum iteration count set then we are dealing with a repeat node that iterates indefinitely.\n }\n },\n createNodeInstance(namedRootNodeProvider, visitedBranches) {\n return new Repeat(\n this.attributes,\n this.iterations,\n this.iterationsMin,\n this.iterationsMax,\n this.children![0].createNodeInstance(namedRootNodeProvider, visitedBranches.slice())\n );\n }\n }),\n RETRY: (): RetryAstNode => ({\n type: \"retry\",\n attributes: [],\n attempts: null,\n attemptsMin: null,\n attemptsMax: null,\n children: [],\n validate() {\n // A retry node must have a single node.\n if (this.children!.length !== 1) {\n throw new Error(\"a retry node must have a single child\");\n }\n\n if (this.attempts !== null) {\n // A retry node must have a positive number of attempts if defined.\n if (this.attempts < 0) {\n throw new Error(\"a retry node must have a positive number of attempts if defined\");\n }\n } else if (this.attemptsMin !== null && this.attemptsMax !== null) {\n // A retry node must have a positive min and max attempts count if they are defined.\n if (this.attemptsMin < 0 || this.attemptsMax < 0) {\n throw new Error(\"a retry node must have a positive minimum and maximum attempt count if defined\");\n }\n\n // A retry node must not have a minimum attempt count that exceeds the maximum attempt count.\n if (this.attemptsMin > this.attemptsMax) {\n throw new Error(\n \"a retry node must not have a minimum attempt count that exceeds the maximum attempt count\"\n );\n }\n } else {\n // If we have no explicit attempt count or a minimum and maximum attempt count set then we are dealing with a retry node that attempts indefinitely.\n }\n },\n createNodeInstance(namedRootNodeProvider, visitedBranches) {\n return new Retry(\n this.attributes,\n this.attempts,\n this.attemptsMin,\n this.attemptsMax,\n this.children![0].createNodeInstance(namedRootNodeProvider, visitedBranches.slice())\n );\n }\n }),\n FLIP: (): DecoratorAstNode => ({\n type: \"flip\",\n attributes: [],\n children: [],\n validate() {\n // A flip node must have a single node.\n if (this.children!.length !== 1) {\n throw new Error(\"a flip node must have a single child\");\n }\n },\n createNodeInstance(namedRootNodeProvider, visitedBranches) {\n return new Flip(\n this.attributes,\n this.children![0].createNodeInstance(namedRootNodeProvider, visitedBranches.slice())\n );\n }\n }),\n SUCCEED: (): DecoratorAstNode => ({\n type: \"succeed\",\n attributes: [],\n children: [],\n validate() {\n // A succeed node must have a single node.\n if (this.children!.length !== 1) {\n throw new Error(\"a succeed node must have a single child\");\n }\n },\n createNodeInstance(namedRootNodeProvider, visitedBranches) {\n return new Succeed(\n this.attributes,\n this.children![0].createNodeInstance(namedRootNodeProvider, visitedBranches.slice())\n );\n }\n }),\n FAIL: (): DecoratorAstNode => ({\n type: \"fail\",\n attributes: [],\n children: [],\n validate() {\n // A fail node must have a single node.\n if (this.children!.length !== 1) {\n throw new Error(\"a fail node must have a single child\");\n }\n },\n createNodeInstance(namedRootNodeProvider, visitedBranches) {\n return new Fail(\n this.attributes,\n this.children![0].createNodeInstance(namedRootNodeProvider, visitedBranches.slice())\n );\n }\n }),\n WAIT: (): WaitAstNode => ({\n type: \"wait\",\n attributes: [],\n duration: null,\n durationMin: null,\n durationMax: null,\n validate() {\n if (this.duration !== null) {\n // If an explict duration was defined then it must be a positive number.\n if (this.duration < 0) {\n throw new Error(\"a wait node must have a positive duration\");\n }\n } else if (this.durationMin !== null && this.durationMax !== null) {\n // A wait node must have a positive min and max duration.\n if (this.durationMin < 0 || this.durationMax < 0) {\n throw new Error(\"a wait node must have a positive minimum and maximum duration\");\n }\n\n // A wait node must not have a minimum duration that exceeds the maximum duration.\n if (this.durationMin > this.durationMax) {\n throw new Error(\"a wait node must not have a minimum duration that exceeds the maximum duration\");\n }\n } else {\n // If we have no explicit duration or duration bounds set then we are dealing with a wait node that waits indefinitely.\n }\n },\n createNodeInstance() {\n return new Wait(this.attributes, this.duration, this.durationMin, this.durationMax);\n }\n }),\n ACTION: (): ActionAstNode => ({\n type: \"action\",\n attributes: [],\n actionName: \"\",\n actionArguments: [],\n validate() {},\n createNodeInstance() {\n return new Action(this.attributes, this.actionName!, this.actionArguments!);\n }\n }),\n CONDITION: (): ConditionAstNode => ({\n type: \"condition\",\n attributes: [],\n conditionName: \"\",\n conditionArguments: [],\n validate() {},\n createNodeInstance() {\n return new Condition(this.attributes, this.conditionName!, this.conditionArguments!);\n }\n })\n};\n\ntype OtherAstNodes = AstNode[];\n\n/**\n * Create an array of root AST nodes based on the given definition.\n * @param definition The definition to parse the AST nodes from.\n * @returns The base definition AST nodes.\n */\nexport default function buildRootASTNodes(definition: string): RootAstNode[] {\n // Swap out any node/attribute argument string literals with a placeholder and get a mapping of placeholders to original values as well as the processed definition.\n const { placeholders, processedDefinition } = substituteStringLiterals(definition);\n\n // Convert the processed definition (with substituted string literals) into an array of raw tokens.\n const tokens = parseTokensFromDefinition(processedDefinition);\n\n // There must be at least 3 tokens for the tree definition to be valid. 'ROOT', '{' and '}'.\n if (tokens.length < 3) {\n throw new Error(\"invalid token count\");\n }\n\n // We should have a matching number of '{' and '}' tokens. If not, then there are scopes that have not been properly closed.\n if (tokens.filter((token) => token === \"{\").length !== tokens.filter((token) => token === \"}\").length) {\n throw new Error(\"scope character mismatch\");\n }\n\n // Create a stack of node children arrays, starting with a definition scope.\n const stack: [RootAstNode[], ...OtherAstNodes[]] = [[]];\n const rootScope = stack[0];\n\n // We should keep processing the raw tokens until we run out of them.\n while (tokens.length) {\n // Grab the next token.\n const token = tokens.shift();\n\n const currentScope = stack[stack.length - 1] as OtherAstNodes;\n\n // How we create the next AST token depends on the current raw token value.\n switch (token!.toUpperCase()) {\n case \"ROOT\": {\n // Create a ROOT AST node.\n const node = ASTNodeFactories.ROOT();\n\n // Push the ROOT node into the current scope.\n rootScope.push(node);\n\n // We may have a root node name defined as an argument.\n if (tokens[0] === \"[\") {\n const rootArguments = getArguments(tokens, placeholders);\n\n // We should have only a single argument that is not an empty string for a root node, which is the root name identifier.\n if (rootArguments.length === 1 && rootArguments[0].type === \"identifier\") {\n // The root name will be the first and only node argument.\n node.name = rootArguments[0].value as string;\n } else {\n throw new Error(\"expected single root name argument\");\n }\n }\n\n // Try to pick any attributes off of the token stack.\n node.attributes = getAttributes(tokens, placeholders);\n\n popAndCheck(tokens, \"{\");\n\n // The new scope is that of the new ROOT nodes children.\n stack.push(node.children!);\n break;\n }\n\n case \"BRANCH\": {\n // Create a BRANCH AST node.\n const node = ASTNodeFactories.BRANCH();\n\n // Push the BRANCH node into the current scope.\n currentScope.push(node);\n\n // We must have arguments defined, as we require a branch name argument.\n if (tokens[0] !== \"[\") {\n throw new Error(\"expected single branch name argument\");\n }\n\n // The branch name will be defined as a node argument.\n const branchArguments = getArguments(tokens, placeholders);\n\n // We should have only a single identifer argument for a branch node, which is the branch name.\n if (branchArguments.length === 1 && branchArguments[0].type === \"identifier\") {\n // The branch name will be the first and only node argument.\n node.branchName = branchArguments[0].value as string;\n } else {\n throw new Error(\"expected single branch name argument\");\n }\n break;\n }\n\n case \"SELECTOR\": {\n // Create a SELECTOR AST node.\n const node = ASTNodeFactories.SELECTOR();\n\n // Push the SELECTOR node into the current scope.\n currentScope.push(node);\n\n // Try to pick any attributes off of the token stack.\n node.attributes = getAttributes(tokens, placeholders);\n\n popAndCheck(tokens, \"{\");\n\n // The new scope is that of the new SELECTOR nodes children.\n stack.push(node.children!);\n break;\n }\n\n case \"SEQUENCE\": {\n // Create a SEQUENCE AST node.\n const node = ASTNodeFactories.SEQUENCE();\n\n // Push the SEQUENCE node into the current scope.\n currentScope.push(node);\n\n // Try to pick any attributes off of the token stack.\n node.attributes = getAttributes(tokens, placeholders);\n\n popAndCheck(tokens, \"{\");\n\n // The new scope is that of the new SEQUENCE nodes children.\n stack.push(node.children!);\n break;\n }\n\n case \"PARALLEL\": {\n // Create a PARALLEL AST node.\n const node = ASTNodeFactories.PARALLEL();\n\n // Push the PARALLEL node into the current scope.\n currentScope.push(node);\n\n // Try to pick any attributes off of the token stack.\n node.attributes = getAttributes(tokens, placeholders);\n\n popAndCheck(tokens, \"{\");\n\n // The new scope is that of the new PARALLEL nodes children.\n stack.push(node.children!);\n break;\n }\n\n case \"LOTTO\": {\n // Create a LOTTO AST node.\n const node = ASTNodeFactories.LOTTO();\n\n // Push the LOTTO node into the current scope.\n currentScope.push(node);\n\n // If the next token is a '[' character then some ticket counts have been defined as arguments.\n if (tokens[0] === \"[\") {\n // Get the ticket count arguments, each argument must be a number.\n node.tickets = getArguments(\n tokens,\n placeholders,\n (arg) => arg.type === \"number\" && !!arg.isInteger,\n \"lotto node ticket counts must be integer values\"\n ).map((argument) => argument.value as number);\n }\n\n // Try to pick any attributes off of the token stack.\n node.attributes = getAttributes(tokens, placeholders);\n\n popAndCheck(tokens, \"{\");\n\n // The new scope is that of the new LOTTO nodes children.\n stack.push(node.children!);\n break;\n }\n\n case \"CONDITION\": {\n // Create a CONDITION AST node.\n const node = ASTNodeFactories.CONDITION();\n\n // Push the CONDITION node into the current scope.\n currentScope.push(node);\n\n // We must have arguments defined, as we require a condition function name argument.\n if (tokens[0] !== \"[\") {\n throw new Error(\"expected condition name identifier argument\");\n }\n\n // Grab the condition node arguments.\n const conditionArguments = getArguments(tokens, placeholders);\n\n // We should have at least a single identifier argument for a condition node, which is the condition function name.\n if (conditionArguments.length && conditionArguments[0].type === \"identifier\") {\n // The condition function name will be the first node argument.\n node.conditionName = conditionArguments.shift()!.value as string;\n } else {\n throw new Error(\"expected condition name identifier argument\");\n }\n\n // Only the first argument should have been an identifier, all following arguments must be string, number, boolean or null.\n conditionArguments\n .filter((arg) => arg.type === \"identifier\")\n .forEach((arg) => {\n throw new Error(\n \"invalid condition node argument value '\" +\n arg.value +\n \"', must be string, number, boolean or null\"\n );\n });\n\n // Any node arguments that follow the condition name identifier will be treated as condition function arguments.\n node.conditionArguments = conditionArguments;\n\n // Try to pick any attributes off of the token stack.\n node.attributes = getAttributes(tokens, placeholders);\n break;\n }\n\n case \"FLIP\": {\n // Create a FLIP AST node.\n const node = ASTNodeFactories.FLIP();\n\n // Push the Flip node into the current scope.\n currentScope.push(node);\n\n // Try to pick any attributes off of the token stack.\n node.attributes = getAttributes(tokens, placeholders);\n\n popAndCheck(tokens, \"{\");\n\n // The new scope is that of the new FLIP nodes children.\n stack.push(node.children!);\n break;\n }\n\n case \"SUCCEED\": {\n // Create a SUCCEED AST node.\n const node = ASTNodeFactories.SUCCEED();\n\n // Push the Succeed node into the current scope.\n currentScope.push(node);\n\n // Try to pick any attributes off of the token stack.\n node.attributes = getAttributes(tokens, placeholders);\n\n popAndCheck(tokens, \"{\");\n\n // The new scope is that of the new Succeed nodes children.\n stack.push(node.children!);\n break;\n }\n\n case \"FAIL\": {\n // Create a FAIL AST node.\n const node = ASTNodeFactories.FAIL();\n\n // Push the Fail node into the current scope.\n currentScope.push(node);\n\n // Try to pick any attributes off of the token stack.\n node.attributes = getAttributes(tokens, placeholders);\n\n popAndCheck(tokens, \"{\");\n\n // The new scope is that of the new Fail nodes children.\n stack.push(node.children!);\n break;\n }\n\n case \"WAIT\": {\n // Create a WAIT AST node.\n const node = ASTNodeFactories.WAIT();\n\n // Push the WAIT node into the current scope.\n currentScope.push(node);\n\n // The arguments of a wait node are optional. We may have:\n // - No node arguments, in which case the wait will be indefinite until it is aborted.\n // - One node argument which will be the explicit duration of the wait.\n // - Two node arguments which define the min and max duration bounds from which a random duration will be picked.\n if (tokens[0] === \"[\") {\n // Get the optional duration and longest duration of the wait.\n const nodeArguments = getArguments(\n tokens,\n placeholders,\n (arg) => arg.type === \"number\" && !!arg.isInteger,\n \"wait node durations must be integer values\"\n ).map((argument) => argument.value);\n\n // We may have:\n // - One node argument which will be the explicit duration of the wait.\n // - Two node arguments which define the min and max duration bounds from which a random duration will be picked.\n // - Too many arguments, which is not valid.\n if (nodeArguments.length === 1) {\n // An explicit duration was defined.\n node.duration = nodeArguments[0] as number;\n } else if (nodeArguments.length === 2) {\n // Min and max duration bounds were defined from which a random duration will be picked.\n node.durationMin = nodeArguments[0] as number;\n node.durationMax = nodeArguments[1] as number;\n } else if (nodeArguments.length > 2) {\n // An incorrect number of durations was defined.\n throw new Error(\"invalid number of wait node duration arguments defined\");\n }\n }\n\n // Try to pick any attributes off of the token stack.\n node.attributes = getAttributes(tokens, placeholders);\n break;\n }\n\n case \"REPEAT\": {\n // Create a REPEAT AST node.\n const node = ASTNodeFactories.REPEAT();\n\n // Push the REPEAT node into the current scope.\n currentScope.push(node);\n\n // The arguments of a repeat node are optional. We may have:\n // - No node arguments, in which case the repeat note will iterate indefinitely.\n // - One node argument which will be the explicit number of iterations to make.\n // - Two node arguments which define the min and max iteration bounds from which a random iteration count will be picked.\n if (tokens[0] === \"[\") {\n // An iteration count has been defined. Get the iteration and potential maximum iteration of the wait.\n const nodeArguments = getArguments(\n tokens,\n placeholders,\n (arg) => arg.type === \"number\" && !!arg.isInteger,\n \"repeat node iteration counts must be integer values\"\n ).map((argument) => argument.value);\n\n // We should have got one or two iteration counts.\n if (nodeArguments.length === 1) {\n // A static iteration count was defined.\n node.iterations = nodeArguments[0] as number;\n } else if (nodeArguments.length === 2) {\n // A minimum and maximum iteration count was defined.\n node.iterationsMin = nodeArguments[0] as number;\n node.iterationsMax = nodeArguments[1] as number;\n } else {\n // An incorrect number of iteration counts was defined.\n throw new Error(\"invalid number of repeat node iteration count arguments defined\");\n }\n }\n\n // Try to pick any attributes off of the token stack.\n node.attributes = getAttributes(tokens, placeholders);\n\n popAndCheck(tokens, \"{\");\n\n // The new scope is that of the new REPEAT nodes children.\n stack.push(node.children!);\n break;\n }\n\n case \"RETRY\": {\n // Create a RETRY AST node.\n const node = ASTNodeFactories.RETRY();\n\n // Push the RETRY node into the current scope.\n currentScope.push(node);\n\n // The arguments of a retry node are optional. We may have:\n // - No node arguments, in which case the retry note will attempt indefinitely.\n // - One node argument which will be the explicit number of attempts to make.\n // - Two node arguments which define the min and max attempt bounds from which a random attempt count will be picked.\n if (tokens[0] === \"[\") {\n // An attempt count has been defined. Get the attempt count and potential maximum attempt count of the wait.\n const nodeArguments = getArguments(\n tokens,\n placeholders,\n (arg) => arg.type === \"number\" && !!arg.isInteger,\n \"retry node attempt counts must be integer values\"\n ).map((argument) => argument.value);\n\n // We should have got one or two attempt counts.\n if (nodeArguments.length === 1) {\n // A static attempt count was defined.\n node.attempts = nodeArguments[0] as number;\n } else if (nodeArguments.length === 2) {\n // A minimum and maximum attempt count was defined.\n node.attemptsMin = nodeArguments[0] as number;\n node.attemptsMax = nodeArguments[1] as number;\n } else {\n // An incorrect number of attempt counts was defined.\n throw new Error(\"invalid number of retry node attempt count arguments defined\");\n }\n }\n\n // Try to pick any attributes off of the token stack.\n node.attributes = getAttributes(tokens, placeholders);\n\n popAndCheck(tokens, \"{\");\n\n // The new scope is that of the new RETRY nodes children.\n stack.push(node.children!);\n break;\n }\n\n case \"ACTION\": {\n // Create a ACTION AST node.\n const node = ASTNodeFactories.ACTION();\n\n // Push the ACTION node into the current scope.\n currentScope.push(node);\n\n // We must have arguments defined, as we require an action name argument.\n if (tokens[0] !== \"[\") {\n throw new Error(\"expected action name identifier argument\");\n }\n\n // The action name will be defined as a node argument.\n const actionArguments = getArguments(tokens, placeholders);\n\n // We should have at least one identifer argument for an action node, which is the action name.\n if (actionArguments.length && actionArguments[0].type === \"identifier\") {\n // The action name will be the first and only node argument.\n node.actionName = actionArguments.shift()!.value as string;\n } else {\n throw new Error(\"expected action name identifier argument\");\n }\n\n // Only the first argument should have been an identifier, all following arguments must be string, number, boolean or null.\n actionArguments\n .filter((arg) => arg.type === \"identifier\")\n .forEach((arg) => {\n throw new Error(\n \"invalid action node argument value '\" +\n arg.value +\n \"', must be string, number, boolean or null\"\n );\n });\n\n // Any node arguments that follow the action name identifier will be treated as action function arguments.\n node.actionArguments = actionArguments;\n\n // Try to pick any attributes off of the token stack.\n node.attributes = getAttributes(tokens, placeholders);\n break;\n }\n\n case \"}\": {\n // The '}' character closes the current scope.\n stack.pop();\n break;\n }\n\n default: {\n throw new Error(`unexpected token '${token}'`);\n }\n }\n }\n\n // A function to recursively validate each of the nodes in the AST.\n const validateASTNode = (node: Validatable, depth: number): void => {\n // Validate the node.\n node.validate(depth);\n\n // Validate each child of the node.\n (node.children || []).forEach((child) => validateASTNode(child, depth + 1));\n };\n\n // Start node validation from the definition root.\n validateASTNode(\n {\n children: stack[0] as RootAstNode[],\n validate(this: { children: RootAstNode[] }) {\n // We must have at least one node defined as the definition scope, which should be a root node.\n if (this.children.length === 0) {\n throw new Error(\"expected root node to have been defined\");\n }\n\n // Each node at the base of the definition scope MUST be a root node.\n for (const definitionLevelNode of this.children) {\n if (definitionLevelNode.type !== \"root\") {\n throw new Error(\"expected root node at base of definition\");\n }\n }\n\n // Exactly one root node must not have a name defined. This will be the main root, others will have to be referenced via branch nodes.\n if (this.children.filter((definitionLevelNode) => definitionLevelNode.name === null).length !== 1) {\n throw new Error(\"expected single unnamed root node at base of definition to act as main root\");\n }\n\n // No two named root nodes can have matching names.\n const rootNodeNames: string[] = [];\n for (const definitionLevelNode of this.children) {\n if (rootNodeNames.indexOf(definitionLevelNode.name!) !== -1) {\n throw new Error(`multiple root nodes found with duplicate name '${definitionLevelNode.name}'`);\n } else {\n rootNodeNames.push(definitionLevelNode.name!);\n }\n }\n }\n },\n 0\n );\n\n // Return the root AST nodes.\n return stack[0];\n}\n\n/**\n * Pop the next raw token off of the stack and throw an error if it wasn't the expected one.\n * @param tokens The array of remaining tokens.\n * @param expected An optional string or array or items, one of which must match the next popped token.\n * @returns The popped token.\n */\nfunction popAndCheck(tokens: string[], expected: string | string[]) {\n // Get and remove the next token.\n const popped = tokens.shift();\n\n // We were expecting another token.\n if (popped === undefined) {\n throw new Error(\"unexpected end of definition\");\n }\n\n // Do we have an expected token/tokens array?\n if (expected !== undefined) {\n // Check whether the popped token matches at least one of our expected items.\n var tokenMatchesExpectation = ([] as string[])\n .concat(expected)\n .some((item) => popped.toUpperCase() === item.toUpperCase());\n\n // Throw an error if the popped token didn't match any of our expected items.\n if (!tokenMatchesExpectation) {\n const expectationString = ([] as string[])\n .concat(expected)\n .map((item) => \"'\" + item + \"'\")\n .join(\" or \");\n\n throw new Error(`unexpected token found. Expected '${expectationString}' but got '${popped}'`);\n }\n }\n\n // Return the popped token.\n return popped;\n}\n\ntype StringPlaceholders = { [key: string]: string };\n\n/**\n * Pull an argument definition list off of the token stack.\n * @param tokens The array of remaining tokens.\n * @param stringArgumentPlaceholders The mapping of string literal node argument placeholders to original values.\n * @param argumentValidator The argument validator function.\n * @param validationFailedMessage The exception message to throw if argument validation fails.\n * @returns The argument definition list.\n */\nfunction getArguments(\n tokens: string[],\n stringArgumentPlaceholders: StringPlaceholders,\n argumentValidator?: (arg: AnyArgument) => boolean,\n validationFailedMessage?: string\n) {\n // Any lists of arguments will always be wrapped in '[]' for node arguments or '()' for attribute arguments.\n // We are looking for a '[' or '(' opener that wraps the argument tokens and the relevant closer.\n const closer = popAndCheck(tokens, [\"[\", \"(\"]) === \"[\" ? \"]\" : \")\";\n\n const argumentListTokens: string[] = [];\n const argumentList: AnyArgument[] = [];\n\n // Grab all tokens between the '[' and ']' or '(' and ')'.\n while (tokens.length && tokens[0] !== closer) {\n // The next token is part of our arguments list.\n argumentListTokens.push(tokens.shift()!);\n }\n\n // Validate the order of the argument tokens. Each token must either be a ',' or a single argument that satisfies the validator.\n argumentListTokens.forEach((token, index) => {\n // Get whether this token should be an actual argument.\n const shouldBeArgumentToken = !(index & 1);\n\n // If the current token should be an actual argument then validate it,otherwise it should be a ',' token.\n if (shouldBeArgumentToken) {\n // Get the argument definition.\n const argumentDefinition = getArgumentDefinition(token!, stringArgumentPlaceholders);\n\n // Try to validate the argument.\n if (argumentValidator && !argumentValidator(argumentDefinition)) {\n throw new Error(validationFailedMessage);\n }\n\n // This is a valid argument!\n argumentList.push(argumentDefinition);\n } else {\n // The current token should be a ',' token.\n if (token !== \",\") {\n throw new Error(`invalid argument list, expected ',' or ']' but got '${token}'`);\n }\n }\n });\n\n // The arguments list should terminate with a ']' or ')' token, depending on the opener.\n popAndCheck(tokens, closer);\n\n // Return the argument list.\n return argumentList;\n}\n\n/**\n * Gets an argument value definition.\n * @param token The argument token.\n * @param stringArgumentPlaceholders The mapping of string literal node argument placeholders to original values.\n * @returns An argument value definition.\n */\nfunction getArgumentDefinition(token: string, stringArgumentPlaceholders: StringPlaceholders): AnyArgument {\n // Check whether the token represents a null value.\n if (token === \"null\") {\n return {\n value: null,\n type: \"null\"\n } as NullArgument;\n }\n\n // Check whether the token represents a boolean value.\n if (token === \"true\" || token === \"false\") {\n return {\n value: token === \"true\",\n type: \"boolean\"\n } as BooleanArgument;\n }\n\n // Check whether the token represents a number value.\n // TODO: Relies on broken isNaN - see MDN.\n // if (!Number.isNaN(token)) {\n if (!isNaN(token as any)) {\n return {\n value: parseFloat(token),\n isInteger: parseFloat(token) === parseInt(token, 10),\n type: \"number\"\n } as NumberArgument;\n }\n\n // Check whether the token is a placeholder (e.g. @@0@@) representing a string literal.\n if (token.match(/^@@\\d+@@$/g)) {\n return {\n value: stringArgumentPlaceholders[token].replace('\\\\\"', '\"'),\n type: \"string\"\n } as StringPlaceholderArgument;\n }\n\n // The only remaining option is that the argument value is an identifier.\n return {\n value: token,\n type: \"identifier\"\n } as IdentifierArgument;\n}\n\n/**\n * Pull any attributes off of the token stack.\n * @param tokens The array of remaining tokens.\n * @param stringArgumentPlaceholders The mapping of string literal node argument placeholders to original values.\n * @returns An array of attributes defined by any directly following tokens.\n */\nfunction getAttributes(tokens: string[], stringArgumentPlaceholders: StringPlaceholders) {\n // Create an array to hold any attributes found.\n const attributes: Attribute[] = [];\n\n // Keep track of names of attribute that we have found on the token stack, as we cannot have duplicates.\n const attributesFound: string[] = [];\n\n // Try to get the attribute factory for the next token.\n let attributeFactory = AttributeFactories[(tokens[0] || \"\").toUpperCase()];\n\n // Pull attribute tokens off of the tokens stack until we have no more.\n while (attributeFactory) {\n // Check to make sure that we have not already created a attribute of this type for this node.\n if (attributesFound.indexOf(tokens[0].toUpperCase()) !== -1) {\n throw new Error(`duplicate attribute '${tokens[0].toUpperCase()}' found for node`);\n }\n\n // Add the current attribute type to our array of found attributes.\n attributesFound.push(tokens.shift()!.toUpperCase());\n\n // Grab any attribute arguments.\n const attributeArguments = getArguments(tokens, stringArgumentPlaceholders);\n\n // The first attribute argument has to be an identifer, this will reference an agent function.\n if (attributeArguments.length === 0 || attributeArguments[0].type !== \"identifier\") {\n throw new Error(\"expected agent function name identifier argument for attribute\");\n }\n\n // Grab the first attribute which is an identifier that will reference an agent function.\n const attributeFunctionName = attributeArguments.shift()! as IdentifierArgument;\n\n // Any remaining attribute arguments must have a type of string, number, boolean or null.\n attributeArguments\n .filter((arg) => arg.type === \"identifier\")\n .forEach((arg) => {\n throw new Error(\n \"invalid attribute argument value '\" + arg.value + \"', must be string, number, boolean or null\"\n );\n });\n\n // Create the attribute and add it to the array of attributes found.\n attributes.push(attributeFactory(attributeFunctionName.value, attributeArguments));\n\n // Try to get the next attribute name token, as there could be multiple.\n attributeFactory = AttributeFactories[(tokens[0] || \"\").toUpperCase()];\n }\n\n return attributes;\n}\n\n/**\n * Swaps out any node/attribute argument string literals with placeholders.\n * @param definition The definition.\n * @returns An object containing a mapping of placeholders to original string values as well as the processed definition string.\n */\nfunction substituteStringLiterals(definition: string): {\n placeholders: { [key: string]: string };\n processedDefinition: string;\n} {\n // Create an object to hold the mapping of placeholders to original string values.\n const placeholders: StringPlaceholders = {};\n\n // Replace any string literals wrapped with double quotes in our definition with placeholders to be processed later.\n const processedDefinition = definition.replace(/\\\"(\\\\.|[^\"\\\\])*\\\"/g, (match) => {\n var strippedMatch = match.substring(1, match.length - 1);\n var placeholder = Object.keys(placeholders).find((key) => placeholders[key] === strippedMatch);\n\n // If we have no existing string literal match then create a new placeholder.\n if (!placeholder) {\n placeholder = `@@${Object.keys(placeholders).length}@@`;\n placeholders[placeholder] = strippedMatch;\n }\n\n return placeholder;\n });\n\n return { placeholders, processedDefinition };\n}\n\n/**\n * Parse the tree definition into an array of raw tokens.\n * @param definition The definition.\n * @returns An array of tokens parsed from the definition.\n */\nfunction parseTokensFromDefinition(definition: string): string[] {\n // Add some space around various important characters so that they can be plucked out easier as individual tokens.\n definition = definition.replace(/\\(/g, \" ( \");\n definition = definition.replace(/\\)/g, \" ) \");\n definition = definition.replace(/\\{/g, \" { \");\n definition = definition.replace(/\\}/g, \" } \");\n definition = definition.replace(/\\]/g, \" ] \");\n definition = definition.replace(/\\[/g, \" [ \");\n definition = definition.replace(/\\,/g, \" , \");\n\n // Split the definition into raw token form and return it.\n return definition.replace(/\\s+/g, \" \").trim().split(\" \");\n}\n", "import GuardPath, { GuardPathPart } from \"./attributes/guards/GuardPath\";\nimport buildRootASTNodes, { AnyArgument, RootAstNode } from \"./RootAstNodesBuilder\";\nimport State, { AnyState } from \"./State\";\nimport Lookup from \"./Lookup\";\nimport Node from \"./nodes/Node\";\nimport Root from \"./nodes/decorator/Root\";\nimport Composite from \"./nodes/composite/Composite\";\nimport Decorator from \"./nodes/decorator/Decorator\";\nimport { Agent, GlobalFunction } from \"./Agent\";\nimport { CallbackAttributeDetails } from \"./attributes/callbacks/Callback\";\nimport { GuardAttributeDetails } from \"./attributes/guards/Guard\";\nimport { BehaviourTreeOptions } from \"./BehaviourTreeOptions\";\nimport { convertMDSLToJSON } from \"./mdsl/MDSLDefinitionParser\";\n\n// Purely for outside inspection of the tree.\nexport type FlattenedTreeNode = {\n id: string;\n type: string;\n caption: string;\n state: AnyState;\n guards: GuardAttributeDetails[];\n callbacks: CallbackAttributeDetails[];\n args: AnyArgument[];\n parentId: string | null;\n};\n\n/**\n * A representation of a behaviour tree.\n */\nexport class BehaviourTree {\n /**\n * The main root tree node.\n */\n public readonly rootNode: Root;\n\n /**\n * Creates a new instance of the BehaviourTree class.\n * @param definition The behaviour tree definition.\n * @param agent The agent instance that this behaviour tree is modelling behaviour for.\n * @param options The behaviour tree options object.\n */\n constructor(definition: string, private agent: Agent, private options: BehaviourTreeOptions = {}) {\n // The tree definition must be defined and a valid string.\n if (typeof definition !== \"string\") {\n throw new Error(\"the tree definition must be a string\");\n }\n\n // The agent must be defined and not null.\n if (typeof agent !== \"object\" || agent === null) {\n throw new Error(\"the agent must be defined and not null\");\n }\n\n // Parse the behaviour tree definition, create the populated tree of behaviour tree nodes, and get the root.\n this.rootNode = BehaviourTree._createRootNode(definition);\n }\n\n /**\n * Gets whether the tree is in the RUNNING state.\n * @returns true if the tree is in the RUNNING state, otherwise false.\n */\n isRunning() {\n return this.rootNode.getState() === State.RUNNING;\n }\n\n /**\n * Gets the current tree state of SUCCEEDED, FAILED, READY or RUNNING.\n * @returns The current tree state.\n */\n getState() {\n return this.rootNode.getState();\n }\n\n /**\n * Step the tree.\n * 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.\n * 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\n * 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.\n *\n * 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.\n */\n step() {\n // If the root node has already been stepped to completion then we need to reset it.\n if (this.rootNode.getState() === State.SUCCEEDED || this.rootNode.getState() === State.FAILED) {\n this.rootNode.reset();\n }\n\n try {\n this.rootNode.update(this.agent, this.options);\n } catch (exception) {\n throw new Error(`error stepping tree: ${(exception as Error).message}`);\n }\n }\n\n /**\n * Resets the tree from the root node outwards to each nested node, giving each a state of READY.\n */\n reset() {\n this.rootNode.reset();\n }\n\n /**\n * Gets the flattened details of every node in the tree.\n * @returns The flattened details of every node in the tree.\n */\n getFlattenedNodeDetails(): FlattenedTreeNode[] {\n // Create an empty flattened array of tree nodes.\n const flattenedTreeNodes: FlattenedTreeNode[] = [];\n\n /**\n * Helper function to process a node instance and push details into the flattened tree nodes array.\n * @param node The current node.\n * @param parentUid The UID of the node parent, or null if the node is the main root node.\n */\n const processNode = (node: Node, parentUid: string | null) => {\n // Get the guard and callback attribute details for this node.\n const guards = node\n .getAttributes()\n .filter((attribute) => attribute.isGuard())\n .map((attribute) => attribute.getDetails()) as GuardAttributeDetails[];\n const callbacks = node\n .getAttributes()\n .filter((attribute) => !attribute.isGuard())\n .map((attribute) => attribute.getDetails()) as CallbackAttributeDetails[];\n\n // Push the current node into the flattened nodes array.\n flattenedTreeNodes.push({\n id: node.getUid(),\n type: node.getType(),\n caption: node.getName(),\n state: node.getState(),\n guards,\n callbacks,\n args: node.getArguments(),\n parentId: parentUid\n });\n\n // Process each of the nodes children if it is not a leaf node.\n if (!node.isLeafNode()) {\n (node as Composite | Decorator)\n .getChildren()\n .forEach((child) => processNode(child, (node as Composite | Decorator).getUid()));\n }\n };\n\n // Convert the nested node structure into a flattened array of node details.\n processNode(this.rootNode, null);\n\n return flattenedTreeNodes;\n }\n\n /**\n * Registers the action/condition/guard/callback function or subtree with the given name.\n * @param name The name of the function or subtree to register.\n * @param value The function or subtree definition to register.\n */\n static register(name: string, value: GlobalFunction | string) {\n if (typeof value === \"function\") {\n // We are going to register a action/condition/guard/callback function.\n Lookup.setFunc(name, value);\n } else if (typeof value === \"string\") {\n // We are going to register a subtree.\n let rootASTNodes: RootAstNode[];\n\n try {\n // Try to create the behaviour tree AST based on the definition provided, this could fail if the definition is invalid.\n rootASTNodes = buildRootASTNodes(value);\n } catch (exception) {\n // There was an issue in trying to parse and build the tree definition.\n throw new Error(`error registering definition: ${(exception as Error).message}`);\n }\n\n // This function should only ever be called with a definition containing a single unnamed root node.\n if (rootASTNodes.length != 1 || rootASTNodes[0].name !== null) {\n throw new Error(\"error registering definition: expected a single unnamed root node\");\n }\n\n Lookup.setSubtree(name, rootASTNodes[0]);\n } else {\n throw new Error(\"unexpected value, expected string definition or function\");\n }\n }\n\n /**\n * Unregisters the registered action/condition/guard/callback function or subtree with the given name.\n * @param name The name of the registered action/condition/guard/callback function or subtree to unregister.\n */\n static unregister(name: string): void {\n Lookup.remove(name);\n }\n\n /**\n * Unregister all registered action/condition/guard/callback functions and subtrees.\n */\n static unregisterAll(): void {\n Lookup.empty();\n }\n\n /**\n * Parses a behaviour tree definition and creates a tree of behaviour tree nodes.\n * @param {string} definition The behaviour tree definition.\n * @returns The root behaviour tree node.\n */\n private static _createRootNode(definition: string): Root {\n // TODO Remove!\n try {\n // parseToJSON(definition);\n } catch (exception) {\n console.log(exception);\n }\n\n try {\n // Try to create the behaviour tree AST based on the definition provided, this could fail if the definition is invalid.\n const rootASTNodes = buildRootASTNodes(definition);\n\n // Create a symbol to use as the main root key in our root node mapping.\n const mainRootNodeKey = Symbol(\"__root__\");\n\n // Create a mapping of root node names to root AST tokens. The main root node will have a key of Symbol(\"__root__\").\n const rootNodeMap: { [key: string | symbol]: RootAstNode } = {};\n for (const rootASTNode of rootASTNodes) {\n rootNodeMap[rootASTNode.name === null ? mainRootNodeKey : rootASTNode.name!] = rootASTNode;\n }\n\n // Convert the AST to our actual tree and get the root node.\n const rootNode: Root = rootNodeMap[mainRootNodeKey].createNodeInstance(\n // Create a provider for named root nodes that are part of our definition or have been registered. Prioritising the former.\n (name: string): RootAstNode => (rootNodeMap[name] ? rootNodeMap[name] : Lookup.getSubtree(name)),\n []\n );\n\n // Set a guard path on every leaf of the tree to evaluate as part of its update.\n BehaviourTree._applyLeafNodeGuardPaths(rootNode);\n\n // Return the root node.\n return rootNode;\n } catch (exception) {\n // There was an issue in trying to parse and build the tree definition.\n throw new Error(`error parsing tree: ${(exception as Error).message}`);\n }\n }\n\n /**\n * Applies a guard path to every leaf of the tree to evaluate as part of each update.\n * @param rootNode The main root tree node.\n */\n private static _applyLeafNodeGuardPaths(rootNode: Root) {\n const nodePaths: Node[][] = [];\n\n const findLeafNodes = (path: Node[], node: Node) => {\n // Add the current node to the path.\n path = path.concat(node);\n\n // Check whether the current node is a leaf node.\n if (node.isLeafNode()) {\n nodePaths.push(path);\n } else {\n (node as Composite | Decorator).getChildren().forEach((child) => findLeafNodes(path, child));\n }\n };\n\n // Find all leaf node paths, starting from the root.\n findLeafNodes([], rootNode);\n\n nodePaths.forEach((path) => {\n // Each node in the current path will have to be assigned a guard path, working from the root outwards.\n for (let depth = 0; depth < path.length; depth++) {\n // Get the node in the path at the current depth.\n const currentNode = path[depth];\n\n // The node may already have been assigned a guard path, if so just skip it.\n if (currentNode.hasGuardPath()) {\n continue;\n }\n\n // Create the guard path for the current node.\n const guardPath = new GuardPath(\n path\n .slice(0, depth + 1)\n .map((node) => ({ node, guards: node.getGuardAttributes() }))\n .filter((details) => details.guards.length > 0)\n );\n\n // Assign the guard path to the current node.\n currentNode.setGuardPath(guardPath);\n }\n });\n }\n}\n"], + "mappings": "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", + "names": ["Participant", "Lotto", "createLotto", "State", "createLotto", "substituteStringLiterals", "parseTokensFromDefinition", "popAndCheck", "getArgumentDefinition"] } diff --git a/dist/index.d.ts b/dist/index.d.ts index 124b691..f58269e 100644 --- a/dist/index.d.ts +++ b/dist/index.d.ts @@ -1,5 +1,6 @@ -import { BehaviourTree, FlattenedTreeNode } from "./BehaviourTree"; import State from "./State"; -import { parseMDSLToJSON } from "./mdsl/MDSLDefinitionParser"; -export { BehaviourTree, State, parseMDSLToJSON }; +import { validateDefinition } from "./BehaviourTreeDefinitionValidator"; +import { convertMDSLToJSON } from "./mdsl/MDSLDefinitionParser"; +import { BehaviourTree, FlattenedTreeNode } from "./BehaviourTree"; +export { BehaviourTree, State, convertMDSLToJSON, validateDefinition }; export type { FlattenedTreeNode }; diff --git a/dist/index.js b/dist/index.js index 183a080..89f540a 100644 --- a/dist/index.js +++ b/dist/index.js @@ -252,35 +252,11 @@ var src_exports = {}; __export(src_exports, { BehaviourTree: () => BehaviourTree, State: () => State, - parseMDSLToJSON: () => parseMDSLToJSON + convertMDSLToJSON: () => convertMDSLToJSON, + validateDefinition: () => validateDefinition }); module.exports = __toCommonJS(src_exports); -// src/attributes/guards/GuardUnsatisifedException.ts -var GuardUnsatisifedException = class extends Error { - constructor(source) { - super("A guard path condition has failed"); - this.source = source; - } - isSourceNode = (node) => node === this.source; -}; - -// src/attributes/guards/GuardPath.ts -var GuardPath = class { - constructor(nodes) { - this.nodes = nodes; - } - evaluate = (agent) => { - for (const details of this.nodes) { - for (const guard of details.guards) { - if (!guard.isSatisfied(agent)) { - throw new GuardUnsatisifedException(details.node); - } - } - } - }; -}; - // src/State.ts var State = /* @__PURE__ */ ((State2) => { State2["READY"] = "mistreevous.ready"; @@ -290,2009 +266,2399 @@ var State = /* @__PURE__ */ ((State2) => { return State2; })(State || {}); -// src/nodes/Node.ts -var Node = class { - constructor(type, attributes, args) { - this.type = type; - this.attributes = attributes; - this.args = args; - } - uid = createNodeUid(); - state = "mistreevous.ready" /* READY */; - guardPath; - getState = () => this.state; - setState = (value) => { - this.state = value; +// src/BehaviourTreeDefinitionUtilities.ts +function isRootNode(node) { + return node.type === "root"; +} +function isBranchNode(node) { + return node.type === "branch"; +} +function isLeafNode(node) { + return ["branch", "action", "condition", "wait"].includes(node.type); +} +function isDecoratorNode(node) { + return ["root", "repeat", "retry", "flip", "succeed", "fail"].includes(node.type); +} +function isCompositeNode(node) { + return ["sequence", "selector", "lotto", "parallel"].includes(node.type); +} +function flattenDefinition(nodeDefinition) { + const nodes = []; + const processNode = (currentNodeDefinition) => { + nodes.push(currentNodeDefinition); + if (isCompositeNode(currentNodeDefinition)) { + currentNodeDefinition.children.forEach(processNode); + } else if (isDecoratorNode(currentNodeDefinition)) { + processNode(currentNodeDefinition.child); + } }; - getUid = () => this.uid; - getType = () => this.type; - getAttributes = () => this.attributes; - getArguments = () => this.args; - getAttribute(type) { - return this.getAttributes().filter((decorator) => decorator.getType().toUpperCase() === type.toUpperCase())[0] || null; - } - getGuardAttributes = () => this.getAttributes().filter((decorator) => decorator.isGuard()); - setGuardPath = (value) => this.guardPath = value; - hasGuardPath = () => !!this.guardPath; - is(value) { - return this.state === value; - } - reset() { - this.setState("mistreevous.ready" /* READY */); + processNode(nodeDefinition); + return nodes; +} +function isInteger(value) { + return typeof value === "number" && Math.floor(value) === value; +} + +// src/mdsl/MDSLUtilities.ts +function popAndCheck(tokens, expected) { + const popped = tokens.shift(); + if (popped === void 0) { + throw new Error("unexpected end of definition"); } - abort(agent) { - if (!this.is("mistreevous.running" /* RUNNING */)) { - return; + if (expected != void 0) { + const expectedValues = typeof expected === "string" ? [expected] : expected; + var tokenMatchesExpectation = expectedValues.some((item) => popped.toUpperCase() === item.toUpperCase()); + if (!tokenMatchesExpectation) { + const expectationString = expectedValues.map((item) => "'" + item + "'").join(" or "); + throw new Error("unexpected token found. Expected " + expectationString + " but got '" + popped + "'"); } - this.reset(); - this.getAttribute("exit")?.callAgentFunction(agent, false, true); } - update(agent, options) { - if (this.is("mistreevous.succeeded" /* SUCCEEDED */) || this.is("mistreevous.failed" /* FAILED */)) { - return; - } - try { - this.guardPath.evaluate(agent); - if (this.is("mistreevous.ready" /* READY */)) { - this.getAttribute("entry")?.callAgentFunction(agent); - } - this.getAttribute("step")?.callAgentFunction(agent); - this.onUpdate(agent, options); - if (this.is("mistreevous.succeeded" /* SUCCEEDED */) || this.is("mistreevous.failed" /* FAILED */)) { - this.getAttribute("exit")?.callAgentFunction(agent, this.is("mistreevous.succeeded" /* SUCCEEDED */), false); - } - } catch (error) { - if (error instanceof GuardUnsatisifedException && error.isSourceNode(this)) { - this.abort(agent); - this.setState("mistreevous.failed" /* FAILED */); - } else { - throw error; - } + return popped; +} +function substituteStringLiterals(definition) { + const placeholders = {}; + const processedDefinition = definition.replace(/\"(\\.|[^"\\])*\"/g, (match) => { + var strippedMatch = match.substring(1, match.length - 1); + var placeholder = Object.keys(placeholders).find((key) => placeholders[key] === strippedMatch); + if (!placeholder) { + placeholder = `@@${Object.keys(placeholders).length}@@`; + placeholders[placeholder] = strippedMatch; } - } -}; -function createNodeUid() { - var S4 = function() { - return ((1 + Math.random()) * 65536 | 0).toString(16).substring(1); - }; - return S4() + S4() + "-" + S4() + "-" + S4() + "-" + S4() + "-" + S4() + S4() + S4(); + return placeholder; + }); + return { placeholders, processedDefinition }; +} +function parseTokensFromDefinition(definition) { + definition = definition.replace(/\(/g, " ( "); + definition = definition.replace(/\)/g, " ) "); + definition = definition.replace(/\{/g, " { "); + definition = definition.replace(/\}/g, " } "); + definition = definition.replace(/\]/g, " ] "); + definition = definition.replace(/\[/g, " [ "); + definition = definition.replace(/\,/g, " , "); + return definition.replace(/\s+/g, " ").trim().split(" "); } -// src/nodes/leaf/Leaf.ts -var Leaf = class extends Node { - isLeafNode = () => true; -}; - -// src/Lookup.ts -var Lookup = class { - static getFunc(name) { - return this.functionTable[name]; +// src/mdsl/MDSLNodeArgumentParser.ts +function parseArgumentTokens(tokens, stringArgumentPlaceholders) { + const argumentList = []; + if (!["[", "("].includes(tokens[0])) { + return argumentList; } - static setFunc(name, func) { - this.functionTable[name] = func; + const closingToken = popAndCheck(tokens, ["[", "("]) === "[" ? "]" : ")"; + const argumentListTokens = []; + while (tokens.length && tokens[0] !== closingToken) { + argumentListTokens.push(tokens.shift()); } - static getFuncInvoker(agent, name) { - const foundOnAgent = agent[name]; - if (foundOnAgent && typeof foundOnAgent === "function") { - return (args) => foundOnAgent.apply( - agent, - args.map((arg) => arg.value) - ); - } - if (this.functionTable[name] && typeof this.functionTable[name] === "function") { - return (args) => this.functionTable[name](agent, ...args.map((arg) => arg.value)); + argumentListTokens.forEach((token, index) => { + const shouldBeArgumentToken = !(index & 1); + if (shouldBeArgumentToken) { + const argumentDefinition = getArgumentDefinition(token, stringArgumentPlaceholders); + argumentList.push(argumentDefinition); + } else { + if (token !== ",") { + throw new Error(`invalid argument list, expected ',' or ']' but got '${token}'`); + } } - return null; - } - static getSubtree(name) { - return this.subtreeTable[name]; + }); + popAndCheck(tokens, closingToken); + return argumentList; +} +function getArgumentDefinition(token, stringArgumentPlaceholders) { + if (token === "null") { + return { + value: null, + type: "null" + }; } - static setSubtree(name, subtree) { - this.subtreeTable[name] = subtree; + if (token === "true" || token === "false") { + return { + value: token === "true", + type: "boolean" + }; } - static remove(name) { - delete this.functionTable[name]; - delete this.subtreeTable[name]; + if (!isNaN(token)) { + return { + value: parseFloat(token), + isInteger: parseFloat(token) === parseInt(token, 10), + type: "number" + }; } - static empty() { - this.functionTable = {}; - this.subtreeTable = {}; + if (token.match(/^@@\d+@@$/g)) { + return { + value: stringArgumentPlaceholders[token].replace('\\"', '"'), + type: "string" + }; } -}; -__publicField(Lookup, "functionTable", {}); -__publicField(Lookup, "subtreeTable", {}); + return { + value: token, + type: "identifier" + }; +} -// src/nodes/leaf/Action.ts -var Action = class extends Leaf { - constructor(attributes, actionName, actionArguments) { - super("action", attributes, actionArguments); - this.actionName = actionName; - this.actionArguments = actionArguments; - } - isUsingUpdatePromise = false; - updatePromiseStateResult = null; - onUpdate(agent, options) { - if (this.isUsingUpdatePromise) { - if (this.updatePromiseStateResult) { - this.setState(this.updatePromiseStateResult); - } - return; +// src/mdsl/MDSLNodeAttributeParser.ts +function parseAttributeTokens(tokens, stringArgumentPlaceholders) { + const nodeAttributeNames = ["while", "until", "entry", "exit", "step"]; + const attributes = {}; + let nextAttributeName = tokens[0]?.toLowerCase(); + while (nodeAttributeNames.includes(nextAttributeName)) { + if (attributes[nextAttributeName]) { + throw new Error(`duplicate attribute '${tokens[0].toUpperCase()}' found for node`); } - const actionFuncInvoker = Lookup.getFuncInvoker(agent, this.actionName); - if (actionFuncInvoker === null) { + tokens.shift(); + const [attributeCallIdentifier, ...attributeArguments] = parseArgumentTokens( + tokens, + stringArgumentPlaceholders + ); + if (attributeCallIdentifier?.type !== "identifier") { + throw new Error("expected agent function name identifier argument for attribute"); + } + attributeArguments.filter((arg) => arg.type === "identifier").forEach((arg) => { throw new Error( - `cannot update action node as the action '${this.actionName}' function is not defined on the agent and has not been registered` + `invalid attribute argument value '${arg.value}', must be string, number, boolean or null` ); - } - const updateResult = actionFuncInvoker(this.actionArguments); - if (updateResult instanceof Promise) { - updateResult.then( - (result) => { - if (!this.isUsingUpdatePromise) { - return; - } - if (result !== "mistreevous.succeeded" /* SUCCEEDED */ && result !== "mistreevous.failed" /* FAILED */) { - throw new Error( - "action node promise resolved with an invalid value, expected a State.SUCCEEDED or State.FAILED value to be returned" - ); - } - this.updatePromiseStateResult = result; - }, - (reason) => { - if (!this.isUsingUpdatePromise) { - return; - } - throw new Error(reason); - } - ); - this.setState("mistreevous.running" /* RUNNING */); - this.isUsingUpdatePromise = true; - } else { - this.validateUpdateResult(updateResult); - this.setState(updateResult || "mistreevous.running" /* RUNNING */); - } - } - getName = () => this.actionName; - reset = () => { - this.setState("mistreevous.ready" /* READY */); - this.isUsingUpdatePromise = false; - this.updatePromiseStateResult = null; - }; - validateUpdateResult = (result) => { - switch (result) { - case "mistreevous.succeeded" /* SUCCEEDED */: - case "mistreevous.failed" /* FAILED */: - case void 0: - return; - default: - throw new Error( - `action '${this.actionName}' 'onUpdate' returned an invalid response, expected an optional State.SUCCEEDED or State.FAILED value to be returned` - ); - } - }; -}; - -// src/nodes/leaf/Condition.ts -var Condition = class extends Leaf { - constructor(attributes, conditionName, conditionArguments) { - super("condition", attributes, conditionArguments); - this.conditionName = conditionName; - this.conditionArguments = conditionArguments; - } - onUpdate(agent, options) { - const conditionFuncInvoker = Lookup.getFuncInvoker(agent, this.conditionName); - if (conditionFuncInvoker === null) { - throw new Error( - `cannot update condition node as the condition '${this.conditionName}' function is not defined on the agent and has not been registered` - ); - } - this.setState(!!conditionFuncInvoker(this.conditionArguments) ? "mistreevous.succeeded" /* SUCCEEDED */ : "mistreevous.failed" /* FAILED */); + }); + attributes[nextAttributeName] = { + call: attributeCallIdentifier.value, + args: attributeArguments.map(({ value }) => value) + }; + nextAttributeName = tokens[0]?.toLowerCase(); } - getName = () => this.conditionName; -}; + return attributes; +} -// src/nodes/leaf/Wait.ts -var Wait = class extends Leaf { - constructor(attributes, duration, durationMin, durationMax) { - super("wait", attributes, []); - this.duration = duration; - this.durationMin = durationMin; - this.durationMax = durationMax; - } - initialUpdateTime = 0; - totalDuration = null; - waitedDuration = 0; - onUpdate(agent, options) { - if (this.is("mistreevous.ready" /* READY */)) { - this.initialUpdateTime = new Date().getTime(); - this.waitedDuration = 0; - if (this.duration !== null) { - this.totalDuration = this.duration; - } else if (this.durationMin !== null && this.durationMax !== null) { - const random = typeof options.random === "function" ? options.random : Math.random; - this.totalDuration = Math.floor( - random() * (this.durationMax - this.durationMin + 1) + this.durationMin - ); - } else { - this.totalDuration = null; - } - this.setState("mistreevous.running" /* RUNNING */); - } - if (this.totalDuration === null) { - return; - } - if (typeof options.getDeltaTime === "function") { - const deltaTime = options.getDeltaTime(); - if (typeof deltaTime !== "number" || isNaN(deltaTime)) { - throw new Error("The delta time must be a valid number and not NaN."); - } - this.waitedDuration += deltaTime * 1e3; - } else { - this.waitedDuration = new Date().getTime() - this.initialUpdateTime; - } - if (this.waitedDuration >= this.totalDuration) { - this.setState("mistreevous.succeeded" /* SUCCEEDED */); - } +// src/mdsl/MDSLDefinitionParser.ts +function convertMDSLToJSON(definition) { + const { placeholders, processedDefinition } = substituteStringLiterals(definition); + const tokens = parseTokensFromDefinition(processedDefinition); + return convertTokensToJSONDefinition(tokens, placeholders); +} +function convertTokensToJSONDefinition(tokens, stringLiteralPlaceholders) { + if (tokens.length < 3) { + throw new Error("invalid token count"); } - getName = () => { - if (this.duration !== null) { - return `WAIT ${this.duration}ms`; - } else if (this.durationMin !== null && this.durationMax !== null) { - return `WAIT ${this.durationMin}ms-${this.durationMax}ms`; - } else { - return "WAIT"; - } - }; -}; - -// src/nodes/decorator/Decorator.ts -var Decorator = class extends Node { - constructor(type, attributes, child) { - super(type, attributes, []); - this.child = child; + if (tokens.filter((token) => token === "{").length !== tokens.filter((token) => token === "}").length) { + throw new Error("scope character mismatch"); } - isLeafNode = () => false; - getChildren = () => [this.child]; - reset = () => { - this.setState("mistreevous.ready" /* READY */); - this.child.reset(); - }; - abort = (agent) => { - if (!this.is("mistreevous.running" /* RUNNING */)) { + const treeStacks = []; + const rootNodes = []; + const pushNode = (node) => { + if (isRootNode(node)) { + rootNodes.push(node); + treeStacks.push([node]); return; } - this.child.abort(agent); - this.reset(); - this.getAttribute("exit")?.callAgentFunction(agent, false, true); - }; -}; - -// src/nodes/decorator/Root.ts -var Root = class extends Decorator { - constructor(attributes, child) { - super("root", attributes, child); - } - onUpdate(agent, options) { - if (this.child.getState() === "mistreevous.ready" /* READY */ || this.child.getState() === "mistreevous.running" /* RUNNING */) { - this.child.update(agent, options); - } - this.setState(this.child.getState()); - } - getName = () => "ROOT"; -}; - -// src/nodes/decorator/Repeat.ts -var Repeat = class extends Decorator { - constructor(attributes, iterations, iterationsMin, iterationsMax, child) { - super("repeat", attributes, child); - this.iterations = iterations; - this.iterationsMin = iterationsMin; - this.iterationsMax = iterationsMax; - } - targetIterationCount = null; - currentIterationCount = 0; - onUpdate(agent, options) { - if (this.is("mistreevous.ready" /* READY */)) { - this.child.reset(); - this.currentIterationCount = 0; - this.setTargetIterationCount(options); + if (!treeStacks.length || !treeStacks[treeStacks.length - 1].length) { + throw new Error("expected root node at base of definition"); } - if (this.canIterate()) { - this.setState("mistreevous.running" /* RUNNING */); - if (this.child.getState() === "mistreevous.succeeded" /* SUCCEEDED */) { - this.child.reset(); - } - this.child.update(agent, options); - if (this.child.getState() === "mistreevous.failed" /* FAILED */) { - this.setState("mistreevous.failed" /* FAILED */); - return; - } else if (this.child.getState() === "mistreevous.succeeded" /* SUCCEEDED */) { - this.currentIterationCount += 1; + const topTreeStack = treeStacks[treeStacks.length - 1]; + const topTreeStackTopNode = topTreeStack[topTreeStack.length - 1]; + if (isCompositeNode(topTreeStackTopNode)) { + topTreeStackTopNode.children = topTreeStackTopNode.children || []; + topTreeStackTopNode.children.push(node); + } else if (isDecoratorNode(topTreeStackTopNode)) { + if (topTreeStackTopNode.child) { + throw new Error("a decorator node must only have a single child node"); } - } else { - this.setState("mistreevous.succeeded" /* SUCCEEDED */); + topTreeStackTopNode.child = node; } - } - getName = () => { - if (this.iterations !== null) { - return `REPEAT ${this.iterations}x`; - } else if (this.iterationsMin !== null && this.iterationsMax !== null) { - return `REPEAT ${this.iterationsMin}x-${this.iterationsMax}x`; - } else { - return "REPEAT"; + if (!isLeafNode(node)) { + topTreeStack.push(node); } }; - reset = () => { - this.setState("mistreevous.ready" /* READY */); - this.currentIterationCount = 0; - this.child.reset(); - }; - canIterate = () => { - if (this.targetIterationCount !== null) { - return this.currentIterationCount < this.targetIterationCount; + const popNode = () => { + const topTreeStack = treeStacks[treeStacks.length - 1]; + if (topTreeStack.length) { + topTreeStack.pop(); } - return true; - }; - setTargetIterationCount = (options) => { - if (this.iterations !== null) { - this.targetIterationCount = this.iterations; - } else if (this.iterationsMin !== null && this.iterationsMax !== null) { - const random = typeof options.random === "function" ? options.random : Math.random; - this.targetIterationCount = Math.floor( - random() * (this.iterationsMax - this.iterationsMin + 1) + this.iterationsMin - ); - } else { - this.targetIterationCount = null; + if (!topTreeStack.length) { + treeStacks.pop(); } }; -}; - -// src/nodes/decorator/Retry.ts -var Retry = class extends Decorator { - constructor(attributes, attempts, attemptsMin, attemptsMax, child) { - super("retry", attributes, child); - this.attempts = attempts; - this.attemptsMin = attemptsMin; - this.attemptsMax = attemptsMax; - } - targetAttemptCount = null; - currentAttemptCount = 0; - onUpdate(agent, options) { - if (this.is("mistreevous.ready" /* READY */)) { - this.child.reset(); - this.currentAttemptCount = 0; - this.setTargetAttemptCount(options); - } - if (this.canAttempt()) { - this.setState("mistreevous.running" /* RUNNING */); - if (this.child.getState() === "mistreevous.failed" /* FAILED */) { - this.child.reset(); + while (tokens.length) { + const token = tokens.shift(); + switch (token.toUpperCase()) { + case "ROOT": { + pushNode(createRootNode(tokens, stringLiteralPlaceholders)); + break; } - this.child.update(agent, options); - if (this.child.getState() === "mistreevous.succeeded" /* SUCCEEDED */) { - this.setState("mistreevous.succeeded" /* SUCCEEDED */); - return; - } else if (this.child.getState() === "mistreevous.failed" /* FAILED */) { - this.currentAttemptCount += 1; + case "SUCCEED": { + pushNode(createSucceedNode(tokens, stringLiteralPlaceholders)); + break; } - } else { - this.setState("mistreevous.failed" /* FAILED */); - } - } - getName = () => { - if (this.attempts !== null) { - return `RETRY ${this.attempts}x`; - } else if (this.attemptsMin !== null && this.attemptsMax !== null) { - return `RETRY ${this.attemptsMin}x-${this.attemptsMax}x`; - } else { - return "RETRY"; - } - }; - reset = () => { - this.setState("mistreevous.ready" /* READY */); - this.currentAttemptCount = 0; - this.child.reset(); - }; - canAttempt = () => { - if (this.targetAttemptCount !== null) { - return this.currentAttemptCount < this.targetAttemptCount; - } - return true; - }; - setTargetAttemptCount = (options) => { - if (this.attempts !== null) { - this.targetAttemptCount = this.attempts; - } else if (this.attemptsMin !== null && this.attemptsMax !== null) { - const random = typeof options.random === "function" ? options.random : Math.random; - this.targetAttemptCount = Math.floor( - random() * (this.attemptsMax - this.attemptsMin + 1) + this.attemptsMin - ); - } else { - this.targetAttemptCount = null; - } - }; -}; - -// src/nodes/decorator/Flip.ts -var Flip = class extends Decorator { - constructor(attributes, child) { - super("flip", attributes, child); - } - onUpdate(agent, options) { - if (this.child.getState() === "mistreevous.ready" /* READY */ || this.child.getState() === "mistreevous.running" /* RUNNING */) { - this.child.update(agent, options); - } - switch (this.child.getState()) { - case "mistreevous.running" /* RUNNING */: - this.setState("mistreevous.running" /* RUNNING */); + case "FAIL": { + pushNode(createFailNode(tokens, stringLiteralPlaceholders)); break; - case "mistreevous.succeeded" /* SUCCEEDED */: - this.setState("mistreevous.failed" /* FAILED */); + } + case "FLIP": { + pushNode(createFlipNode(tokens, stringLiteralPlaceholders)); break; - case "mistreevous.failed" /* FAILED */: - this.setState("mistreevous.succeeded" /* SUCCEEDED */); + } + case "REPEAT": { + pushNode(createRepeatNode(tokens, stringLiteralPlaceholders)); break; - default: - this.setState("mistreevous.ready" /* READY */); - } - } - getName = () => "FLIP"; -}; - -// src/nodes/decorator/Succeed.ts -var Succeed = class extends Decorator { - constructor(attributes, child) { - super("succeed", attributes, child); - } - onUpdate(agent, options) { - if (this.child.getState() === "mistreevous.ready" /* READY */ || this.child.getState() === "mistreevous.running" /* RUNNING */) { - this.child.update(agent, options); - } - switch (this.child.getState()) { - case "mistreevous.running" /* RUNNING */: - this.setState("mistreevous.running" /* RUNNING */); + } + case "RETRY": { + pushNode(createRetryNode(tokens, stringLiteralPlaceholders)); break; - case "mistreevous.succeeded" /* SUCCEEDED */: - case "mistreevous.failed" /* FAILED */: - this.setState("mistreevous.succeeded" /* SUCCEEDED */); + } + case "SEQUENCE": { + pushNode(createSequenceNode(tokens, stringLiteralPlaceholders)); break; - default: - this.setState("mistreevous.ready" /* READY */); - } - } - getName = () => "SUCCEED"; -}; - -// src/nodes/decorator/Fail.ts -var Fail = class extends Decorator { - constructor(attributes, child) { - super("fail", attributes, child); - } - onUpdate(agent, options) { - if (this.child.getState() === "mistreevous.ready" /* READY */ || this.child.getState() === "mistreevous.running" /* RUNNING */) { - this.child.update(agent, options); - } - switch (this.child.getState()) { - case "mistreevous.running" /* RUNNING */: - this.setState("mistreevous.running" /* RUNNING */); + } + case "SELECTOR": { + pushNode(createSelectorNode(tokens, stringLiteralPlaceholders)); break; - case "mistreevous.succeeded" /* SUCCEEDED */: - case "mistreevous.failed" /* FAILED */: - this.setState("mistreevous.failed" /* FAILED */); + } + case "PARALLEL": { + pushNode(createParallelNode(tokens, stringLiteralPlaceholders)); break; - default: - this.setState("mistreevous.ready" /* READY */); - } - } - getName = () => "FAIL"; -}; - -// src/nodes/composite/Lotto.ts -var import_lotto_draw = __toESM(require_dist()); - -// src/nodes/composite/Composite.ts -var Composite = class extends Node { - constructor(type, attributes, children) { - super(type, attributes, []); - this.children = children; - } - isLeafNode = () => false; - getChildren = () => this.children; - reset = () => { - this.setState("mistreevous.ready" /* READY */); - this.getChildren().forEach((child) => child.reset()); - }; - abort = (agent) => { - if (!this.is("mistreevous.running" /* RUNNING */)) { - return; - } - this.getChildren().forEach((child) => child.abort(agent)); - this.reset(); - this.getAttribute("exit")?.callAgentFunction(agent, false, true); - }; -}; - -// src/nodes/composite/Lotto.ts -var Lotto = class extends Composite { - constructor(attributes, tickets, children) { - super("lotto", attributes, children); - this.tickets = tickets; - } - selectedChild; - onUpdate(agent, options) { - if (this.is("mistreevous.ready" /* READY */)) { - const lottoDraw = (0, import_lotto_draw.default)({ - random: options.random, - participants: this.children.map((child, index) => [child, this.tickets[index] || 1]) - }); - this.selectedChild = lottoDraw.draw() || void 0; - } - if (!this.selectedChild) { - throw new Error("failed to update lotto node as it has no active child"); - } - if (this.selectedChild.getState() === "mistreevous.ready" /* READY */ || this.selectedChild.getState() === "mistreevous.running" /* RUNNING */) { - this.selectedChild.update(agent, options); - } - this.setState(this.selectedChild.getState()); - } - getName = () => this.tickets.length ? `LOTTO [${this.tickets.join(",")}]` : "LOTTO"; -}; - -// src/nodes/composite/Selector.ts -var Selector = class extends Composite { - constructor(attributes, children) { - super("selector", attributes, children); - this.children = children; - } - onUpdate(agent, options) { - for (const child of this.children) { - if (child.getState() === "mistreevous.ready" /* READY */ || child.getState() === "mistreevous.running" /* RUNNING */) { - child.update(agent, options); } - if (child.getState() === "mistreevous.succeeded" /* SUCCEEDED */) { - this.setState("mistreevous.succeeded" /* SUCCEEDED */); - return; + case "LOTTO": { + pushNode(createLottoNode(tokens, stringLiteralPlaceholders)); + break; } - if (child.getState() === "mistreevous.failed" /* FAILED */) { - if (this.children.indexOf(child) === this.children.length - 1) { - this.setState("mistreevous.failed" /* FAILED */); - return; - } else { - continue; - } + case "ACTION": { + pushNode(createActionNode(tokens, stringLiteralPlaceholders)); + break; } - if (child.getState() === "mistreevous.running" /* RUNNING */) { - this.setState("mistreevous.running" /* RUNNING */); - return; + case "CONDITION": { + pushNode(createConditionNode(tokens, stringLiteralPlaceholders)); + break; + } + case "WAIT": { + pushNode(createWaitNode(tokens, stringLiteralPlaceholders)); + break; + } + case "BRANCH": { + pushNode(createBranchNode(tokens, stringLiteralPlaceholders)); + break; + } + case "}": { + popNode(); + break; + } + default: { + throw new Error(`unexpected token: ${token}`); } - throw new Error("child node was not in an expected state."); } } - getName = () => "SELECTOR"; -}; - -// src/nodes/composite/Sequence.ts -var Sequence = class extends Composite { - constructor(attributes, children) { - super("sequence", attributes, children); - this.children = children; + return rootNodes; +} +function createRootNode(tokens, stringLiteralPlaceholders) { + let node = { + type: "root", + id: void 0 + }; + const nodeArguments = parseArgumentTokens(tokens, stringLiteralPlaceholders); + if (nodeArguments.length) { + if (nodeArguments.length === 1 && nodeArguments[0].type === "identifier") { + node.id = nodeArguments[0].value; + } else { + throw new Error("expected single root name argument"); + } } - onUpdate(agent, options) { - for (const child of this.children) { - if (child.getState() === "mistreevous.ready" /* READY */ || child.getState() === "mistreevous.running" /* RUNNING */) { - child.update(agent, options); - } - if (child.getState() === "mistreevous.succeeded" /* SUCCEEDED */) { - if (this.children.indexOf(child) === this.children.length - 1) { - this.setState("mistreevous.succeeded" /* SUCCEEDED */); - return; - } else { - continue; - } - } - if (child.getState() === "mistreevous.failed" /* FAILED */) { - this.setState("mistreevous.failed" /* FAILED */); - return; - } - if (child.getState() === "mistreevous.running" /* RUNNING */) { - this.setState("mistreevous.running" /* RUNNING */); - return; - } - throw new Error("child node was not in an expected state."); + node = { ...node, ...parseAttributeTokens(tokens, stringLiteralPlaceholders) }; + popAndCheck(tokens, "{"); + return node; +} +function createSucceedNode(tokens, stringLiteralPlaceholders) { + const node = { + type: "succeed", + ...parseAttributeTokens(tokens, stringLiteralPlaceholders) + }; + popAndCheck(tokens, "{"); + return node; +} +function createFailNode(tokens, stringLiteralPlaceholders) { + const node = { + type: "fail", + ...parseAttributeTokens(tokens, stringLiteralPlaceholders) + }; + popAndCheck(tokens, "{"); + return node; +} +function createFlipNode(tokens, stringLiteralPlaceholders) { + const node = { + type: "flip", + ...parseAttributeTokens(tokens, stringLiteralPlaceholders) + }; + popAndCheck(tokens, "{"); + return node; +} +function createRepeatNode(tokens, stringLiteralPlaceholders) { + let node = { type: "repeat" }; + const nodeArguments = parseArgumentTokens(tokens, stringLiteralPlaceholders); + if (nodeArguments.length) { + nodeArguments.filter((arg) => arg.type !== "number" || !arg.isInteger).forEach(() => { + throw new Error(`repeat node iteration counts must be integer values`); + }); + if (nodeArguments.length === 1) { + node.iterations = nodeArguments[0].value; + } else if (nodeArguments.length === 2) { + node.iterations = [nodeArguments[0].value, nodeArguments[1].value]; + } else { + throw new Error("invalid number of repeat node iteration count arguments defined"); } } - getName = () => "SEQUENCE"; -}; - -// src/nodes/composite/Parallel.ts -var Parallel = class extends Composite { - constructor(attributes, children) { - super("parallel", attributes, children); + node = { ...node, ...parseAttributeTokens(tokens, stringLiteralPlaceholders) }; + popAndCheck(tokens, "{"); + return node; +} +function createRetryNode(tokens, stringLiteralPlaceholders) { + let node = { type: "retry" }; + const nodeArguments = parseArgumentTokens(tokens, stringLiteralPlaceholders); + if (nodeArguments.length) { + nodeArguments.filter((arg) => arg.type !== "number" || !arg.isInteger).forEach(() => { + throw new Error(`retry node attempt counts must be integer values`); + }); + if (nodeArguments.length === 1) { + node.attempts = nodeArguments[0].value; + } else if (nodeArguments.length === 2) { + node.attempts = [nodeArguments[0].value, nodeArguments[1].value]; + } else { + throw new Error("invalid number of retry node attempt count arguments defined"); + } } - onUpdate(agent, options) { - let succeededCount = 0; - let hasChildFailed = false; - for (const child of this.children) { - if (child.getState() === "mistreevous.ready" /* READY */ || child.getState() === "mistreevous.running" /* RUNNING */) { - child.update(agent, options); - } - if (child.getState() === "mistreevous.succeeded" /* SUCCEEDED */) { - succeededCount++; - continue; - } - if (child.getState() === "mistreevous.failed" /* FAILED */) { - hasChildFailed = true; - break; - } - if (child.getState() !== "mistreevous.running" /* RUNNING */) { - throw new Error("child node was not in an expected state."); - } + node = { ...node, ...parseAttributeTokens(tokens, stringLiteralPlaceholders) }; + popAndCheck(tokens, "{"); + return node; +} +function createSequenceNode(tokens, stringLiteralPlaceholders) { + const node = { + type: "sequence", + ...parseAttributeTokens(tokens, stringLiteralPlaceholders) + }; + popAndCheck(tokens, "{"); + return node; +} +function createSelectorNode(tokens, stringLiteralPlaceholders) { + const node = { + type: "selector", + ...parseAttributeTokens(tokens, stringLiteralPlaceholders) + }; + popAndCheck(tokens, "{"); + return node; +} +function createParallelNode(tokens, stringLiteralPlaceholders) { + const node = { + type: "parallel", + ...parseAttributeTokens(tokens, stringLiteralPlaceholders) + }; + popAndCheck(tokens, "{"); + return node; +} +function createLottoNode(tokens, stringLiteralPlaceholders) { + const nodeArguments = parseArgumentTokens(tokens, stringLiteralPlaceholders); + nodeArguments.filter((arg) => arg.type !== "number" || !arg.isInteger).forEach(() => { + throw new Error(`lotto node weight arguments must be integer values`); + }); + const node = { + type: "lotto", + weights: nodeArguments.map(({ value }) => value), + ...parseAttributeTokens(tokens, stringLiteralPlaceholders) + }; + popAndCheck(tokens, "{"); + return node; +} +function createActionNode(tokens, stringLiteralPlaceholders) { + const [actionNameIdentifier, ...agentFunctionArgs] = parseArgumentTokens(tokens, stringLiteralPlaceholders); + if (actionNameIdentifier?.type !== "identifier") { + throw new Error("expected action name identifier argument"); + } + agentFunctionArgs.filter((arg) => arg.type === "identifier").forEach((arg) => { + throw new Error( + `invalid action node argument value '${arg.value}', must be string, number, boolean or null` + ); + }); + return { + type: "action", + call: actionNameIdentifier.value, + args: agentFunctionArgs.map(({ value }) => value), + ...parseAttributeTokens(tokens, stringLiteralPlaceholders) + }; +} +function createConditionNode(tokens, stringLiteralPlaceholders) { + const [conditionNameIdentifier, ...agentFunctionArgs] = parseArgumentTokens(tokens, stringLiteralPlaceholders); + if (conditionNameIdentifier?.type !== "identifier") { + throw new Error("expected condition name identifier argument"); + } + agentFunctionArgs.filter((arg) => arg.type === "identifier").forEach((arg) => { + throw new Error( + `invalid condition node argument value '${arg.value}', must be string, number, boolean or null` + ); + }); + return { + type: "condition", + call: conditionNameIdentifier.value, + args: agentFunctionArgs.map(({ value }) => value), + ...parseAttributeTokens(tokens, stringLiteralPlaceholders) + }; +} +function createWaitNode(tokens, stringLiteralPlaceholders) { + let node = { type: "wait" }; + const nodeArguments = parseArgumentTokens(tokens, stringLiteralPlaceholders); + if (nodeArguments.length) { + nodeArguments.filter((arg) => arg.type !== "number" || !arg.isInteger).forEach(() => { + throw new Error(`wait node duration arguments must be integer values`); + }); + if (nodeArguments.length === 1) { + node.duration = nodeArguments[0].value; + } else if (nodeArguments.length === 2) { + node.duration = [nodeArguments[0].value, nodeArguments[1].value]; + } else if (nodeArguments.length > 2) { + throw new Error("invalid number of wait node duration arguments defined"); } - if (hasChildFailed) { - this.setState("mistreevous.failed" /* FAILED */); - for (const child of this.children) { - if (child.getState() === "mistreevous.running" /* RUNNING */) { - child.abort(agent); - } + } + return { ...node, ...parseAttributeTokens(tokens, stringLiteralPlaceholders) }; +} +function createBranchNode(tokens, stringLiteralPlaceholders) { + const nodeArguments = parseArgumentTokens(tokens, stringLiteralPlaceholders); + if (nodeArguments.length !== 1 || nodeArguments[0].type !== "identifier") { + throw new Error("expected single branch name argument"); + } + return { type: "branch", ref: nodeArguments[0].value }; +} + +// src/BehaviourTreeDefinitionValidator.ts +function validateDefinition(definition) { + const createFailureResult = (errorMessage) => ({ succeeded: false, errorMessage }); + if (definition === null || typeof definition === "undefined") { + return createFailureResult("definition is null or undefined"); + } + let rootNodeDefinitions; + if (typeof definition === "string") { + try { + rootNodeDefinitions = convertMDSLToJSON(definition); + } catch (error) { + return createFailureResult(`invalid mdsl: ${definition}`); + } + } else if (typeof definition === "object") { + if (Array.isArray(definition)) { + const invalidDefinitionElements = definition.filter((element) => { + return typeof element !== "object" || Array.isArray(element) || element === null; + }); + if (invalidDefinitionElements.length) { + return createFailureResult( + "invalid elements in definition array, each must be an root node definition object" + ); } + rootNodeDefinitions = definition; } else { - this.setState(succeededCount === this.children.length ? "mistreevous.succeeded" /* SUCCEEDED */ : "mistreevous.running" /* RUNNING */); + rootNodeDefinitions = [definition]; } + } else { + return createFailureResult(`unexpected definition type of '${typeof definition}'`); } - getName = () => "PARALLEL"; -}; - -// src/attributes/Attribute.ts -var Attribute = class { - constructor(type, args) { - this.type = type; - this.args = args; + try { + rootNodeDefinitions.forEach((rootNodeDefinition) => validateNode(rootNodeDefinition, 0)); + } catch (error) { + if (error instanceof Error) { + return createFailureResult(error.message); + } + return createFailureResult(`unexpected error: ${error}`); } - getType = () => this.type; - getArguments = () => this.args; -}; - -// src/attributes/guards/Guard.ts -var Guard = class extends Attribute { - constructor(type, args, condition) { - super(type, args); - this.condition = condition; + const mainRootNodeDefinitions = rootNodeDefinitions.filter(({ id }) => typeof id === "undefined"); + const subRootNodeDefinitions = rootNodeDefinitions.filter(({ id }) => typeof id === "string" && id.length > 0); + if (mainRootNodeDefinitions.length !== 1) { + return createFailureResult("expected single root node without 'id' property defined to act as main root"); } - getCondition = () => this.condition; - isGuard = () => true; - getDetails() { - return { - type: this.getType(), - args: this.getArguments(), - condition: this.getCondition() - }; + const subRootNodeIdenitifers = []; + for (const { id } of subRootNodeDefinitions) { + if (subRootNodeIdenitifers.includes(id)) { + return createFailureResult(`multiple root nodes found with duplicate 'id' property value of '${id}'`); + } + subRootNodeIdenitifers.push(id); } -}; - -// src/attributes/guards/While.ts -var While = class extends Guard { - constructor(condition, args) { - super("while", args, condition); + const circularDependencyPath = findBranchCircularDependencyPath(rootNodeDefinitions); + if (circularDependencyPath) { + return createFailureResult(`circular dependency found in branch node references: ${circularDependencyPath}`); } - isSatisfied = (agent) => { - const conditionFuncInvoker = Lookup.getFuncInvoker(agent, this.getCondition()); - if (conditionFuncInvoker === null) { - throw new Error( - `cannot evaluate node guard as the condition '${this.getCondition()}' function is not defined on the agent and has not been registered` - ); + return { succeeded: true }; +} +function findBranchCircularDependencyPath(rootNodeDefinitions) { + const rootNodeMappings = rootNodeDefinitions.map( + (rootNodeDefinition) => ({ + id: rootNodeDefinition.id, + refs: flattenDefinition(rootNodeDefinition).filter(isBranchNode).map(({ ref }) => ref) + }) + ); + let badPathFormatted = null; + const followRefs = (mapping, path = []) => { + if (path.includes(mapping.id)) { + const badPath = [...path, mapping.id]; + badPathFormatted = badPath.map((element) => !!element).join(" => "); + return; } - return !!conditionFuncInvoker(this.args); - }; -}; - -// src/attributes/guards/Until.ts -var Until = class extends Guard { - constructor(condition, args) { - super("until", args, condition); - } - isSatisfied = (agent) => { - const conditionFuncInvoker = Lookup.getFuncInvoker(agent, this.getCondition()); - if (conditionFuncInvoker === null) { - throw new Error( - `cannot evaluate node guard as the condition '${this.getCondition()}' function is not defined on the agent and has not been registered` - ); + for (const ref of mapping.refs) { + const subMapping = rootNodeMappings.find(({ id }) => id === ref); + if (subMapping) { + followRefs(subMapping, [...path, mapping.id]); + } } - return !!!conditionFuncInvoker(this.args); }; -}; - -// src/attributes/callbacks/Callback.ts -var Callback = class extends Attribute { - constructor(type, args, functionName) { - super(type, args); - this.functionName = functionName; - } - getFunctionName = () => this.functionName; - isGuard = () => false; - getDetails() { - return { - type: this.getType(), - args: this.getArguments(), - functionName: this.getFunctionName() - }; + return badPathFormatted; +} +function validateNode(definition, depth) { + if (typeof definition !== "object" || typeof definition.type !== "string" || definition.type.length === 0) { + throw new Error( + `node definition is not an object or 'type' property is not a non-empty string at depth '${depth}'` + ); } -}; - -// src/attributes/callbacks/Entry.ts -var Entry = class extends Callback { - constructor(functionName, args) { - super("entry", args, functionName); + switch (definition.type) { + case "action": + validateActionNode(definition, depth); + break; + case "condition": + validateConditionNode(definition, depth); + break; + case "wait": + validateWaitNode(definition, depth); + break; + case "branch": + validateBranchNode(definition, depth); + break; + case "root": + validateRootNode(definition, depth); + break; + case "success": + validateSuccessNode(definition, depth); + break; + case "fail": + validateFailNode(definition, depth); + break; + case "flip": + validateFlipNode(definition, depth); + break; + case "repeat": + validateRepeatNode(definition, depth); + break; + case "retry": + validateRetryNode(definition, depth); + break; + case "sequence": + validateSequenceNode(definition, depth); + break; + case "selector": + validateSelectorNode(definition, depth); + break; + case "parallel": + validateParallelNode(definition, depth); + break; + default: + throw new Error(`unexpected node type of '${definition.type}' at depth '${depth}'`); } - callAgentFunction = (agent) => { - const callbackFuncInvoker = Lookup.getFuncInvoker(agent, this.getFunctionName()); - if (callbackFuncInvoker === null) { +} +function validateNodeAttributes(definition, depth) { + ["while", "until", "entry", "exit", "step"].forEach((attributeName) => { + const attributeDefinition = definition[attributeName]; + if (typeof attributeDefinition === "undefined") { + return; + } + if (typeof attributeDefinition !== "object") { throw new Error( - `cannot call entry function '${this.getFunctionName()}' as is not defined on the agent and has not been registered` + `expected attribute '${attributeName}' to be an object for '${definition.type}' node at depth '${depth}'` ); } - callbackFuncInvoker(this.args); - }; -}; - -// src/attributes/callbacks/Exit.ts -var Exit = class extends Callback { - constructor(functionName, args) { - super("exit", args, functionName); - } - callAgentFunction = (agent, isSuccess, isAborted) => { - const callbackFuncInvoker = Lookup.getFuncInvoker(agent, this.getFunctionName()); - if (callbackFuncInvoker === null) { + if (typeof attributeDefinition.call !== "string" || attributeDefinition.call.length === 0) { throw new Error( - `cannot call exit function '${this.getFunctionName()}' as is not defined on the agent and has not been registered` + `expected 'call' property for attribute '${attributeName}' to be a non-empty string for '${definition.type}' node at depth '${depth}'` ); } - callbackFuncInvoker([{ value: { succeeded: isSuccess, aborted: isAborted } }, ...this.args]); - }; -}; - -// src/attributes/callbacks/Step.ts -var Step = class extends Callback { - constructor(functionName, args) { - super("step", args, functionName); - } - callAgentFunction = (agent) => { - const callbackFuncInvoker = Lookup.getFuncInvoker(agent, this.getFunctionName()); - if (callbackFuncInvoker === null) { + if (typeof attributeDefinition.args !== "undefined" && !Array.isArray(attributeDefinition.args)) { throw new Error( - `cannot call step function '${this.getFunctionName()}' as is not defined on the agent and has not been registered` + `expected 'args' property for attribute '${attributeName}' to be an array for '${definition.type}' node at depth '${depth}'` ); } - callbackFuncInvoker(this.args); - }; -}; - -// src/RootAstNodesBuilder.ts -var AttributeFactories = { - WHILE: (condition, attributeArguments) => new While(condition, attributeArguments), - UNTIL: (condition, attributeArguments) => new Until(condition, attributeArguments), - ENTRY: (functionName, attributeArguments) => new Entry(functionName, attributeArguments), - EXIT: (functionName, attributeArguments) => new Exit(functionName, attributeArguments), - STEP: (functionName, attributeArguments) => new Step(functionName, attributeArguments) -}; -var ASTNodeFactories = { - ROOT: () => ({ - type: "root", - attributes: [], - name: null, - children: [], - validate(depth) { - if (depth > 1) { - throw new Error("a root node cannot be the child of another node"); - } - if (this.children.length !== 1) { - throw new Error("a root node must have a single child"); + }); +} +function validateRootNode(definition, depth) { + if (definition.type !== "root") { + throw new Error("expected node type of 'root' for root node"); + } + if (depth > 0) { + throw new Error("a root node cannot be the child of another node"); + } + if (typeof definition.id !== "undefined" && (typeof definition.id !== "string" || definition.id.length === 0)) { + throw new Error("expected non-empty string for 'id' property if defined for root node"); + } + if (typeof definition.child === "undefined") { + throw new Error("expected property 'child' to be defined for root node"); + } + validateNodeAttributes(definition, depth); + validateNode(definition.child, depth + 1); +} +function validateSuccessNode(definition, depth) { + if (definition.type !== "success") { + throw new Error(`expected node type of 'success' for success node at depth '${depth}'`); + } + if (typeof definition.child === "undefined") { + throw new Error(`expected property 'child' to be defined for success node at depth '${depth}'`); + } + validateNodeAttributes(definition, depth); + validateNode(definition.child, depth + 1); +} +function validateFailNode(definition, depth) { + if (definition.type !== "fail") { + throw new Error(`expected node type of 'fail' for fail node at depth '${depth}'`); + } + if (typeof definition.child === "undefined") { + throw new Error(`expected property 'child' to be defined for fail node at depth '${depth}'`); + } + validateNodeAttributes(definition, depth); + validateNode(definition.child, depth + 1); +} +function validateFlipNode(definition, depth) { + if (definition.type !== "flip") { + throw new Error(`expected node type of 'flip' for flip node at depth '${depth}'`); + } + if (typeof definition.child === "undefined") { + throw new Error(`expected property 'child' to be defined for flip node at depth '${depth}'`); + } + validateNodeAttributes(definition, depth); + validateNode(definition.child, depth + 1); +} +function validateRepeatNode(definition, depth) { + if (definition.type !== "repeat") { + throw new Error(`expected node type of 'repeat' for repeat node at depth '${depth}'`); + } + if (typeof definition.child === "undefined") { + throw new Error(`expected property 'child' to be defined for repeat node at depth '${depth}'`); + } + if (typeof definition.iterations !== "undefined") { + if (Array.isArray(definition.iterations)) { + const containsNonInteger = !!definition.iterations.find((value) => !isInteger(value)); + if (definition.iterations.length !== 2 || containsNonInteger) { + throw new Error( + `expected array containing two integer values for 'iterations' property if defined for repeat node at depth '${depth}'` + ); } - }, - createNodeInstance(namedRootNodeProvider, visitedBranches) { - return new Root( - this.attributes, - this.children[0].createNodeInstance(namedRootNodeProvider, visitedBranches.slice()) + } else if (!isInteger(definition.iterations)) { + throw new Error( + `expected integer value or array containing two integer values for 'iterations' property if defined for repeat node at depth '${depth}'` ); } - }), - BRANCH: () => ({ - type: "branch", - branchName: "", - validate() { - }, - createNodeInstance(namedRootNodeProvider, visitedBranches) { - const targetRootNode = namedRootNodeProvider(this.branchName); - if (visitedBranches.indexOf(this.branchName) !== -1) { - throw new Error(`circular dependency found in branch node references for branch '${this.branchName}'`); - } - if (targetRootNode) { - return targetRootNode.createNodeInstance(namedRootNodeProvider, visitedBranches.concat(this.branchName)).getChildren()[0]; - } else { - throw new Error(`branch references root node '${this.branchName}' which has not been defined`); - } - } - }), - SELECTOR: () => ({ - type: "selector", - attributes: [], - children: [], - validate() { - if (this.children.length < 1) { - throw new Error("a selector node must have at least a single child"); + } + validateNodeAttributes(definition, depth); + validateNode(definition.child, depth + 1); +} +function validateRetryNode(definition, depth) { + if (definition.type !== "retry") { + throw new Error(`expected node type of 'retry' for retry node at depth '${depth}'`); + } + if (typeof definition.child === "undefined") { + throw new Error(`expected property 'child' to be defined for retry node at depth '${depth}'`); + } + if (typeof definition.attempts !== "undefined") { + if (Array.isArray(definition.attempts)) { + const containsNonInteger = !!definition.attempts.find((value) => !isInteger(value)); + if (definition.attempts.length !== 2 || containsNonInteger) { + throw new Error( + `expected array containing two integer values for 'attempts' property if defined for retry node at depth '${depth}'` + ); } - }, - createNodeInstance(namedRootNodeProvider, visitedBranches) { - return new Selector( - this.attributes, - this.children.map((child) => child.createNodeInstance(namedRootNodeProvider, visitedBranches.slice())) + } else if (!isInteger(definition.attempts)) { + throw new Error( + `expected integer value or array containing two integer values for 'attempts' property if defined for retry node at depth '${depth}'` ); } - }), - SEQUENCE: () => ({ - type: "sequence", - attributes: [], - children: [], - validate() { - if (this.children.length < 1) { - throw new Error("a sequence node must have at least a single child"); - } - }, - createNodeInstance(namedRootNodeProvider, visitedBranches) { - return new Sequence( - this.attributes, - this.children.map((child) => child.createNodeInstance(namedRootNodeProvider, visitedBranches.slice())) + } + validateNodeAttributes(definition, depth); + validateNode(definition.child, depth + 1); +} +function validateBranchNode(definition, depth) { + if (definition.type !== "branch") { + throw new Error(`expected node type of 'branch' for branch node at depth '${depth}'`); + } + if (typeof definition.ref !== "string" || definition.ref.length === 0) { + throw new Error(`expected non-empty string for 'ref' property for branch node at depth '${depth}'`); + } + ["while", "until"].forEach((attributeName) => { + if (typeof definition[attributeName] !== "undefined") { + throw new Error( + `guards should not be defined for branch nodes but guard '${attributeName}' was defined for branch node at depth '${depth}'` ); } - }), - PARALLEL: () => ({ - type: "parallel", - attributes: [], - children: [], - validate() { - if (this.children.length < 1) { - throw new Error("a parallel node must have at least a single child"); - } - }, - createNodeInstance(namedRootNodeProvider, visitedBranches) { - return new Parallel( - this.attributes, - this.children.map((child) => child.createNodeInstance(namedRootNodeProvider, visitedBranches.slice())) + }); + ["entry", "exit", "step"].forEach((attributeName) => { + if (typeof definition[attributeName] !== "undefined") { + throw new Error( + `callbacks should not be defined for branch nodes but callback '${attributeName}' was defined for branch node at depth '${depth}'` ); } - }), - LOTTO: () => ({ - type: "lotto", - attributes: [], - children: [], - tickets: [], - validate() { - if (this.children.length < 1) { - throw new Error("a lotto node must have at least a single child"); + }); +} +function validateActionNode(definition, depth) { + if (definition.type !== "action") { + throw new Error(`expected node type of 'action' for action node at depth '${depth}'`); + } + if (typeof definition.call !== "string" || definition.call.length === 0) { + throw new Error(`expected non-empty string for 'call' property of action node at depth '${depth}'`); + } + if (typeof definition.args !== "undefined" && !Array.isArray(definition.args)) { + throw new Error(`expected array for 'args' property if defined for action node at depth '${depth}'`); + } + validateNodeAttributes(definition, depth); +} +function validateConditionNode(definition, depth) { + if (definition.type !== "condition") { + throw new Error(`expected node type of 'condition' for condition node at depth '${depth}'`); + } + if (typeof definition.call !== "string" || definition.call.length === 0) { + throw new Error(`expected non-empty string for 'call' property of condition node at depth '${depth}'`); + } + if (typeof definition.args !== "undefined" && !Array.isArray(definition.args)) { + throw new Error(`expected array for 'args' property if defined for condition node at depth '${depth}'`); + } + validateNodeAttributes(definition, depth); +} +function validateWaitNode(definition, depth) { + if (definition.type !== "wait") { + throw new Error(`expected node type of 'wait' for wait node at depth '${depth}'`); + } + if (typeof definition.duration !== "undefined") { + if (Array.isArray(definition.duration)) { + const containsNonInteger = !!definition.duration.find((value) => !isInteger(value)); + if (definition.duration.length !== 2 || containsNonInteger) { + throw new Error( + `expected array containing two integer values for 'duration' property if defined for wait node at depth '${depth}'` + ); } - }, - createNodeInstance(namedRootNodeProvider, visitedBranches) { - return new Lotto( - this.attributes, - this.tickets, - this.children.map((child) => child.createNodeInstance(namedRootNodeProvider, visitedBranches.slice())) + } else if (!isInteger(definition.duration)) { + throw new Error( + `expected integer value or array containing two integer values for 'duration' property if defined for wait node at depth '${depth}'` ); } - }), - REPEAT: () => ({ - type: "repeat", - attributes: [], - iterations: null, - iterationsMin: null, - iterationsMax: null, - children: [], - validate() { - if (this.children.length !== 1) { - throw new Error("a repeat node must have a single child"); - } - if (this.iterations !== null) { - if (this.iterations < 0) { - throw new Error("a repeat node must have a positive number of iterations if defined"); - } - } else if (this.iterationsMin !== null && this.iterationsMax !== null) { - if (this.iterationsMin < 0 || this.iterationsMax < 0) { - throw new Error( - "a repeat node must have a positive minimum and maximum iteration count if defined" - ); - } - if (this.iterationsMin > this.iterationsMax) { - throw new Error( - "a repeat node must not have a minimum iteration count that exceeds the maximum iteration count" - ); + } + validateNodeAttributes(definition, depth); +} +function validateSequenceNode(definition, depth) { + if (definition.type !== "sequence") { + throw new Error(`expected node type of 'sequence' for sequence node at depth '${depth}'`); + } + if (!Array.isArray(definition.children) || definition.children.length === 0) { + throw new Error(`expected non-empty 'children' array to be defined for sequence node at depth '${depth}'`); + } + validateNodeAttributes(definition, depth); + definition.children.forEach((child) => validateNode(child, depth + 1)); +} +function validateSelectorNode(definition, depth) { + if (definition.type !== "selector") { + throw new Error(`expected node type of 'selector' for selector node at depth '${depth}'`); + } + if (!Array.isArray(definition.children) || definition.children.length === 0) { + throw new Error(`expected non-empty 'children' array to be defined for selector node at depth '${depth}'`); + } + validateNodeAttributes(definition, depth); + definition.children.forEach((child) => validateNode(child, depth + 1)); +} +function validateParallelNode(definition, depth) { + if (definition.type !== "parallel") { + throw new Error(`expected node type of 'parallel' for parallel node at depth '${depth}'`); + } + if (!Array.isArray(definition.children) || definition.children.length === 0) { + throw new Error(`expected non-empty 'children' array to be defined for parallel node at depth '${depth}'`); + } + validateNodeAttributes(definition, depth); + definition.children.forEach((child) => validateNode(child, depth + 1)); +} + +// src/attributes/guards/GuardUnsatisifedException.ts +var GuardUnsatisifedException = class extends Error { + constructor(source) { + super("A guard path condition has failed"); + this.source = source; + } + isSourceNode = (node) => node === this.source; +}; + +// src/attributes/guards/GuardPath.ts +var GuardPath = class { + constructor(nodes) { + this.nodes = nodes; + } + evaluate = (agent) => { + for (const details of this.nodes) { + for (const guard of details.guards) { + if (!guard.isSatisfied(agent)) { + throw new GuardUnsatisifedException(details.node); } - } else { } - }, - createNodeInstance(namedRootNodeProvider, visitedBranches) { - return new Repeat( - this.attributes, - this.iterations, - this.iterationsMin, - this.iterationsMax, - this.children[0].createNodeInstance(namedRootNodeProvider, visitedBranches.slice()) - ); } - }), - RETRY: () => ({ - type: "retry", - attributes: [], - attempts: null, - attemptsMin: null, - attemptsMax: null, - children: [], - validate() { - if (this.children.length !== 1) { - throw new Error("a retry node must have a single child"); + }; +}; + +// src/nodes/Node.ts +var Node = class { + constructor(type, attributes, args) { + this.type = type; + this.attributes = attributes; + this.args = args; + } + uid = createNodeUid(); + state = "mistreevous.ready" /* READY */; + guardPath; + getState = () => this.state; + setState = (value) => { + this.state = value; + }; + getUid = () => this.uid; + getType = () => this.type; + getAttributes = () => this.attributes; + getArguments = () => this.args; + getAttribute(type) { + return this.getAttributes().filter((decorator) => decorator.getType().toUpperCase() === type.toUpperCase())[0] || null; + } + getGuardAttributes = () => this.getAttributes().filter((decorator) => decorator.isGuard()); + setGuardPath = (value) => this.guardPath = value; + hasGuardPath = () => !!this.guardPath; + is(value) { + return this.state === value; + } + reset() { + this.setState("mistreevous.ready" /* READY */); + } + abort(agent) { + if (!this.is("mistreevous.running" /* RUNNING */)) { + return; + } + this.reset(); + this.getAttribute("exit")?.callAgentFunction(agent, false, true); + } + update(agent, options) { + if (this.is("mistreevous.succeeded" /* SUCCEEDED */) || this.is("mistreevous.failed" /* FAILED */)) { + return; + } + try { + this.guardPath.evaluate(agent); + if (this.is("mistreevous.ready" /* READY */)) { + this.getAttribute("entry")?.callAgentFunction(agent); } - if (this.attempts !== null) { - if (this.attempts < 0) { - throw new Error("a retry node must have a positive number of attempts if defined"); - } - } else if (this.attemptsMin !== null && this.attemptsMax !== null) { - if (this.attemptsMin < 0 || this.attemptsMax < 0) { - throw new Error("a retry node must have a positive minimum and maximum attempt count if defined"); - } - if (this.attemptsMin > this.attemptsMax) { - throw new Error( - "a retry node must not have a minimum attempt count that exceeds the maximum attempt count" - ); - } + this.getAttribute("step")?.callAgentFunction(agent); + this.onUpdate(agent, options); + if (this.is("mistreevous.succeeded" /* SUCCEEDED */) || this.is("mistreevous.failed" /* FAILED */)) { + this.getAttribute("exit")?.callAgentFunction(agent, this.is("mistreevous.succeeded" /* SUCCEEDED */), false); + } + } catch (error) { + if (error instanceof GuardUnsatisifedException && error.isSourceNode(this)) { + this.abort(agent); + this.setState("mistreevous.failed" /* FAILED */); } else { + throw error; } - }, - createNodeInstance(namedRootNodeProvider, visitedBranches) { - return new Retry( - this.attributes, - this.attempts, - this.attemptsMin, - this.attemptsMax, - this.children[0].createNodeInstance(namedRootNodeProvider, visitedBranches.slice()) - ); } - }), - FLIP: () => ({ - type: "flip", - attributes: [], - children: [], - validate() { - if (this.children.length !== 1) { - throw new Error("a flip node must have a single child"); - } - }, - createNodeInstance(namedRootNodeProvider, visitedBranches) { - return new Flip( - this.attributes, - this.children[0].createNodeInstance(namedRootNodeProvider, visitedBranches.slice()) + } +}; +function createNodeUid() { + var S4 = function() { + return ((1 + Math.random()) * 65536 | 0).toString(16).substring(1); + }; + return S4() + S4() + "-" + S4() + "-" + S4() + "-" + S4() + "-" + S4() + S4() + S4(); +} + +// src/nodes/leaf/Leaf.ts +var Leaf = class extends Node { + isLeafNode = () => true; +}; + +// src/Lookup.ts +var Lookup = class { + static getFunc(name) { + return this.functionTable[name]; + } + static setFunc(name, func) { + this.functionTable[name] = func; + } + static getFuncInvoker(agent, name) { + const foundOnAgent = agent[name]; + if (foundOnAgent && typeof foundOnAgent === "function") { + return (args) => foundOnAgent.apply( + agent, + args.map((arg) => arg.value) ); } - }), - SUCCEED: () => ({ - type: "succeed", - attributes: [], - children: [], - validate() { - if (this.children.length !== 1) { - throw new Error("a succeed node must have a single child"); - } - }, - createNodeInstance(namedRootNodeProvider, visitedBranches) { - return new Succeed( - this.attributes, - this.children[0].createNodeInstance(namedRootNodeProvider, visitedBranches.slice()) - ); + if (this.functionTable[name] && typeof this.functionTable[name] === "function") { + return (args) => this.functionTable[name](agent, ...args.map((arg) => arg.value)); } - }), - FAIL: () => ({ - type: "fail", - attributes: [], - children: [], - validate() { - if (this.children.length !== 1) { - throw new Error("a fail node must have a single child"); + return null; + } + static getSubtree(name) { + return this.subtreeTable[name]; + } + static setSubtree(name, subtree) { + this.subtreeTable[name] = subtree; + } + static remove(name) { + delete this.functionTable[name]; + delete this.subtreeTable[name]; + } + static empty() { + this.functionTable = {}; + this.subtreeTable = {}; + } +}; +__publicField(Lookup, "functionTable", {}); +__publicField(Lookup, "subtreeTable", {}); + +// src/nodes/leaf/Action.ts +var Action = class extends Leaf { + constructor(attributes, actionName, actionArguments) { + super("action", attributes, actionArguments); + this.actionName = actionName; + this.actionArguments = actionArguments; + } + isUsingUpdatePromise = false; + updatePromiseStateResult = null; + onUpdate(agent, options) { + if (this.isUsingUpdatePromise) { + if (this.updatePromiseStateResult) { + this.setState(this.updatePromiseStateResult); } - }, - createNodeInstance(namedRootNodeProvider, visitedBranches) { - return new Fail( - this.attributes, - this.children[0].createNodeInstance(namedRootNodeProvider, visitedBranches.slice()) + return; + } + const actionFuncInvoker = Lookup.getFuncInvoker(agent, this.actionName); + if (actionFuncInvoker === null) { + throw new Error( + `cannot update action node as the action '${this.actionName}' function is not defined on the agent and has not been registered` ); } - }), - WAIT: () => ({ - type: "wait", - attributes: [], - duration: null, - durationMin: null, - durationMax: null, - validate() { - if (this.duration !== null) { - if (this.duration < 0) { - throw new Error("a wait node must have a positive duration"); + const updateResult = actionFuncInvoker(this.actionArguments); + if (updateResult instanceof Promise) { + updateResult.then( + (result) => { + if (!this.isUsingUpdatePromise) { + return; + } + if (result !== "mistreevous.succeeded" /* SUCCEEDED */ && result !== "mistreevous.failed" /* FAILED */) { + throw new Error( + "action node promise resolved with an invalid value, expected a State.SUCCEEDED or State.FAILED value to be returned" + ); + } + this.updatePromiseStateResult = result; + }, + (reason) => { + if (!this.isUsingUpdatePromise) { + return; + } + throw new Error(reason); } + ); + this.setState("mistreevous.running" /* RUNNING */); + this.isUsingUpdatePromise = true; + } else { + this.validateUpdateResult(updateResult); + this.setState(updateResult || "mistreevous.running" /* RUNNING */); + } + } + getName = () => this.actionName; + reset = () => { + this.setState("mistreevous.ready" /* READY */); + this.isUsingUpdatePromise = false; + this.updatePromiseStateResult = null; + }; + validateUpdateResult = (result) => { + switch (result) { + case "mistreevous.succeeded" /* SUCCEEDED */: + case "mistreevous.failed" /* FAILED */: + case void 0: + return; + default: + throw new Error( + `action '${this.actionName}' 'onUpdate' returned an invalid response, expected an optional State.SUCCEEDED or State.FAILED value to be returned` + ); + } + }; +}; + +// src/nodes/leaf/Condition.ts +var Condition = class extends Leaf { + constructor(attributes, conditionName, conditionArguments) { + super("condition", attributes, conditionArguments); + this.conditionName = conditionName; + this.conditionArguments = conditionArguments; + } + onUpdate(agent, options) { + const conditionFuncInvoker = Lookup.getFuncInvoker(agent, this.conditionName); + if (conditionFuncInvoker === null) { + throw new Error( + `cannot update condition node as the condition '${this.conditionName}' function is not defined on the agent and has not been registered` + ); + } + this.setState(!!conditionFuncInvoker(this.conditionArguments) ? "mistreevous.succeeded" /* SUCCEEDED */ : "mistreevous.failed" /* FAILED */); + } + getName = () => this.conditionName; +}; + +// src/nodes/leaf/Wait.ts +var Wait = class extends Leaf { + constructor(attributes, duration, durationMin, durationMax) { + super("wait", attributes, []); + this.duration = duration; + this.durationMin = durationMin; + this.durationMax = durationMax; + } + initialUpdateTime = 0; + totalDuration = null; + waitedDuration = 0; + onUpdate(agent, options) { + if (this.is("mistreevous.ready" /* READY */)) { + this.initialUpdateTime = new Date().getTime(); + this.waitedDuration = 0; + if (this.duration !== null) { + this.totalDuration = this.duration; } else if (this.durationMin !== null && this.durationMax !== null) { - if (this.durationMin < 0 || this.durationMax < 0) { - throw new Error("a wait node must have a positive minimum and maximum duration"); - } - if (this.durationMin > this.durationMax) { - throw new Error("a wait node must not have a minimum duration that exceeds the maximum duration"); - } + const random = typeof options.random === "function" ? options.random : Math.random; + this.totalDuration = Math.floor( + random() * (this.durationMax - this.durationMin + 1) + this.durationMin + ); } else { + this.totalDuration = null; } - }, - createNodeInstance() { - return new Wait(this.attributes, this.duration, this.durationMin, this.durationMax); + this.setState("mistreevous.running" /* RUNNING */); } - }), - ACTION: () => ({ - type: "action", - attributes: [], - actionName: "", - actionArguments: [], - validate() { - }, - createNodeInstance() { - return new Action(this.attributes, this.actionName, this.actionArguments); + if (this.totalDuration === null) { + return; } - }), - CONDITION: () => ({ - type: "condition", - attributes: [], - conditionName: "", - conditionArguments: [], - validate() { - }, - createNodeInstance() { - return new Condition(this.attributes, this.conditionName, this.conditionArguments); + if (typeof options.getDeltaTime === "function") { + const deltaTime = options.getDeltaTime(); + if (typeof deltaTime !== "number" || isNaN(deltaTime)) { + throw new Error("The delta time must be a valid number and not NaN."); + } + this.waitedDuration += deltaTime * 1e3; + } else { + this.waitedDuration = new Date().getTime() - this.initialUpdateTime; } - }) + if (this.waitedDuration >= this.totalDuration) { + this.setState("mistreevous.succeeded" /* SUCCEEDED */); + } + } + getName = () => { + if (this.duration !== null) { + return `WAIT ${this.duration}ms`; + } else if (this.durationMin !== null && this.durationMax !== null) { + return `WAIT ${this.durationMin}ms-${this.durationMax}ms`; + } else { + return "WAIT"; + } + }; }; -function buildRootASTNodes(definition) { - const { placeholders, processedDefinition } = substituteStringLiterals(definition); - const tokens = parseTokensFromDefinition(processedDefinition); - if (tokens.length < 3) { - throw new Error("invalid token count"); + +// src/nodes/decorator/Decorator.ts +var Decorator = class extends Node { + constructor(type, attributes, child) { + super(type, attributes, []); + this.child = child; } - if (tokens.filter((token) => token === "{").length !== tokens.filter((token) => token === "}").length) { - throw new Error("scope character mismatch"); + isLeafNode = () => false; + getChildren = () => [this.child]; + reset = () => { + this.setState("mistreevous.ready" /* READY */); + this.child.reset(); + }; + abort = (agent) => { + if (!this.is("mistreevous.running" /* RUNNING */)) { + return; + } + this.child.abort(agent); + this.reset(); + this.getAttribute("exit")?.callAgentFunction(agent, false, true); + }; +}; + +// src/nodes/decorator/Root.ts +var Root = class extends Decorator { + constructor(attributes, child) { + super("root", attributes, child); } - const stack = [[]]; - const rootScope = stack[0]; - while (tokens.length) { - const token = tokens.shift(); - const currentScope = stack[stack.length - 1]; - switch (token.toUpperCase()) { - case "ROOT": { - const node = ASTNodeFactories.ROOT(); - rootScope.push(node); - if (tokens[0] === "[") { - const rootArguments = getArguments(tokens, placeholders); - if (rootArguments.length === 1 && rootArguments[0].type === "identifier") { - node.name = rootArguments[0].value; - } else { - throw new Error("expected single root name argument"); - } - } - node.attributes = getAttributes(tokens, placeholders); - popAndCheck(tokens, "{"); - stack.push(node.children); - break; + onUpdate(agent, options) { + if (this.child.getState() === "mistreevous.ready" /* READY */ || this.child.getState() === "mistreevous.running" /* RUNNING */) { + this.child.update(agent, options); + } + this.setState(this.child.getState()); + } + getName = () => "ROOT"; +}; + +// src/nodes/decorator/Repeat.ts +var Repeat = class extends Decorator { + constructor(attributes, iterations, iterationsMin, iterationsMax, child) { + super("repeat", attributes, child); + this.iterations = iterations; + this.iterationsMin = iterationsMin; + this.iterationsMax = iterationsMax; + } + targetIterationCount = null; + currentIterationCount = 0; + onUpdate(agent, options) { + if (this.is("mistreevous.ready" /* READY */)) { + this.child.reset(); + this.currentIterationCount = 0; + this.setTargetIterationCount(options); + } + if (this.canIterate()) { + this.setState("mistreevous.running" /* RUNNING */); + if (this.child.getState() === "mistreevous.succeeded" /* SUCCEEDED */) { + this.child.reset(); } - case "BRANCH": { - const node = ASTNodeFactories.BRANCH(); - currentScope.push(node); - if (tokens[0] !== "[") { - throw new Error("expected single branch name argument"); - } - const branchArguments = getArguments(tokens, placeholders); - if (branchArguments.length === 1 && branchArguments[0].type === "identifier") { - node.branchName = branchArguments[0].value; - } else { - throw new Error("expected single branch name argument"); - } - break; + this.child.update(agent, options); + if (this.child.getState() === "mistreevous.failed" /* FAILED */) { + this.setState("mistreevous.failed" /* FAILED */); + return; + } else if (this.child.getState() === "mistreevous.succeeded" /* SUCCEEDED */) { + this.currentIterationCount += 1; } - case "SELECTOR": { - const node = ASTNodeFactories.SELECTOR(); - currentScope.push(node); - node.attributes = getAttributes(tokens, placeholders); - popAndCheck(tokens, "{"); - stack.push(node.children); - break; - } - case "SEQUENCE": { - const node = ASTNodeFactories.SEQUENCE(); - currentScope.push(node); - node.attributes = getAttributes(tokens, placeholders); - popAndCheck(tokens, "{"); - stack.push(node.children); - break; + } else { + this.setState("mistreevous.succeeded" /* SUCCEEDED */); + } + } + getName = () => { + if (this.iterations !== null) { + return `REPEAT ${this.iterations}x`; + } else if (this.iterationsMin !== null && this.iterationsMax !== null) { + return `REPEAT ${this.iterationsMin}x-${this.iterationsMax}x`; + } else { + return "REPEAT"; + } + }; + reset = () => { + this.setState("mistreevous.ready" /* READY */); + this.currentIterationCount = 0; + this.child.reset(); + }; + canIterate = () => { + if (this.targetIterationCount !== null) { + return this.currentIterationCount < this.targetIterationCount; + } + return true; + }; + setTargetIterationCount = (options) => { + if (this.iterations !== null) { + this.targetIterationCount = this.iterations; + } else if (this.iterationsMin !== null && this.iterationsMax !== null) { + const random = typeof options.random === "function" ? options.random : Math.random; + this.targetIterationCount = Math.floor( + random() * (this.iterationsMax - this.iterationsMin + 1) + this.iterationsMin + ); + } else { + this.targetIterationCount = null; + } + }; +}; + +// src/nodes/decorator/Retry.ts +var Retry = class extends Decorator { + constructor(attributes, attempts, attemptsMin, attemptsMax, child) { + super("retry", attributes, child); + this.attempts = attempts; + this.attemptsMin = attemptsMin; + this.attemptsMax = attemptsMax; + } + targetAttemptCount = null; + currentAttemptCount = 0; + onUpdate(agent, options) { + if (this.is("mistreevous.ready" /* READY */)) { + this.child.reset(); + this.currentAttemptCount = 0; + this.setTargetAttemptCount(options); + } + if (this.canAttempt()) { + this.setState("mistreevous.running" /* RUNNING */); + if (this.child.getState() === "mistreevous.failed" /* FAILED */) { + this.child.reset(); } - case "PARALLEL": { - const node = ASTNodeFactories.PARALLEL(); - currentScope.push(node); - node.attributes = getAttributes(tokens, placeholders); - popAndCheck(tokens, "{"); - stack.push(node.children); - break; + this.child.update(agent, options); + if (this.child.getState() === "mistreevous.succeeded" /* SUCCEEDED */) { + this.setState("mistreevous.succeeded" /* SUCCEEDED */); + return; + } else if (this.child.getState() === "mistreevous.failed" /* FAILED */) { + this.currentAttemptCount += 1; } - case "LOTTO": { - const node = ASTNodeFactories.LOTTO(); - currentScope.push(node); - if (tokens[0] === "[") { - node.tickets = getArguments( - tokens, - placeholders, - (arg) => arg.type === "number" && !!arg.isInteger, - "lotto node ticket counts must be integer values" - ).map((argument) => argument.value); - } - node.attributes = getAttributes(tokens, placeholders); - popAndCheck(tokens, "{"); - stack.push(node.children); + } else { + this.setState("mistreevous.failed" /* FAILED */); + } + } + getName = () => { + if (this.attempts !== null) { + return `RETRY ${this.attempts}x`; + } else if (this.attemptsMin !== null && this.attemptsMax !== null) { + return `RETRY ${this.attemptsMin}x-${this.attemptsMax}x`; + } else { + return "RETRY"; + } + }; + reset = () => { + this.setState("mistreevous.ready" /* READY */); + this.currentAttemptCount = 0; + this.child.reset(); + }; + canAttempt = () => { + if (this.targetAttemptCount !== null) { + return this.currentAttemptCount < this.targetAttemptCount; + } + return true; + }; + setTargetAttemptCount = (options) => { + if (this.attempts !== null) { + this.targetAttemptCount = this.attempts; + } else if (this.attemptsMin !== null && this.attemptsMax !== null) { + const random = typeof options.random === "function" ? options.random : Math.random; + this.targetAttemptCount = Math.floor( + random() * (this.attemptsMax - this.attemptsMin + 1) + this.attemptsMin + ); + } else { + this.targetAttemptCount = null; + } + }; +}; + +// src/nodes/decorator/Flip.ts +var Flip = class extends Decorator { + constructor(attributes, child) { + super("flip", attributes, child); + } + onUpdate(agent, options) { + if (this.child.getState() === "mistreevous.ready" /* READY */ || this.child.getState() === "mistreevous.running" /* RUNNING */) { + this.child.update(agent, options); + } + switch (this.child.getState()) { + case "mistreevous.running" /* RUNNING */: + this.setState("mistreevous.running" /* RUNNING */); break; - } - case "CONDITION": { - const node = ASTNodeFactories.CONDITION(); - currentScope.push(node); - if (tokens[0] !== "[") { - throw new Error("expected condition name identifier argument"); - } - const conditionArguments = getArguments(tokens, placeholders); - if (conditionArguments.length && conditionArguments[0].type === "identifier") { - node.conditionName = conditionArguments.shift().value; - } else { - throw new Error("expected condition name identifier argument"); - } - conditionArguments.filter((arg) => arg.type === "identifier").forEach((arg) => { - throw new Error( - "invalid condition node argument value '" + arg.value + "', must be string, number, boolean or null" - ); - }); - node.conditionArguments = conditionArguments; - node.attributes = getAttributes(tokens, placeholders); + case "mistreevous.succeeded" /* SUCCEEDED */: + this.setState("mistreevous.failed" /* FAILED */); break; - } - case "FLIP": { - const node = ASTNodeFactories.FLIP(); - currentScope.push(node); - node.attributes = getAttributes(tokens, placeholders); - popAndCheck(tokens, "{"); - stack.push(node.children); + case "mistreevous.failed" /* FAILED */: + this.setState("mistreevous.succeeded" /* SUCCEEDED */); break; - } - case "SUCCEED": { - const node = ASTNodeFactories.SUCCEED(); - currentScope.push(node); - node.attributes = getAttributes(tokens, placeholders); - popAndCheck(tokens, "{"); - stack.push(node.children); + default: + this.setState("mistreevous.ready" /* READY */); + } + } + getName = () => "FLIP"; +}; + +// src/nodes/decorator/Succeed.ts +var Succeed = class extends Decorator { + constructor(attributes, child) { + super("succeed", attributes, child); + } + onUpdate(agent, options) { + if (this.child.getState() === "mistreevous.ready" /* READY */ || this.child.getState() === "mistreevous.running" /* RUNNING */) { + this.child.update(agent, options); + } + switch (this.child.getState()) { + case "mistreevous.running" /* RUNNING */: + this.setState("mistreevous.running" /* RUNNING */); break; - } - case "FAIL": { - const node = ASTNodeFactories.FAIL(); - currentScope.push(node); - node.attributes = getAttributes(tokens, placeholders); - popAndCheck(tokens, "{"); - stack.push(node.children); + case "mistreevous.succeeded" /* SUCCEEDED */: + case "mistreevous.failed" /* FAILED */: + this.setState("mistreevous.succeeded" /* SUCCEEDED */); break; - } - case "WAIT": { - const node = ASTNodeFactories.WAIT(); - currentScope.push(node); - if (tokens[0] === "[") { - const nodeArguments = getArguments( - tokens, - placeholders, - (arg) => arg.type === "number" && !!arg.isInteger, - "wait node durations must be integer values" - ).map((argument) => argument.value); - if (nodeArguments.length === 1) { - node.duration = nodeArguments[0]; - } else if (nodeArguments.length === 2) { - node.durationMin = nodeArguments[0]; - node.durationMax = nodeArguments[1]; - } else if (nodeArguments.length > 2) { - throw new Error("invalid number of wait node duration arguments defined"); - } - } - node.attributes = getAttributes(tokens, placeholders); + default: + this.setState("mistreevous.ready" /* READY */); + } + } + getName = () => "SUCCEED"; +}; + +// src/nodes/decorator/Fail.ts +var Fail = class extends Decorator { + constructor(attributes, child) { + super("fail", attributes, child); + } + onUpdate(agent, options) { + if (this.child.getState() === "mistreevous.ready" /* READY */ || this.child.getState() === "mistreevous.running" /* RUNNING */) { + this.child.update(agent, options); + } + switch (this.child.getState()) { + case "mistreevous.running" /* RUNNING */: + this.setState("mistreevous.running" /* RUNNING */); break; - } - case "REPEAT": { - const node = ASTNodeFactories.REPEAT(); - currentScope.push(node); - if (tokens[0] === "[") { - const nodeArguments = getArguments( - tokens, - placeholders, - (arg) => arg.type === "number" && !!arg.isInteger, - "repeat node iteration counts must be integer values" - ).map((argument) => argument.value); - if (nodeArguments.length === 1) { - node.iterations = nodeArguments[0]; - } else if (nodeArguments.length === 2) { - node.iterationsMin = nodeArguments[0]; - node.iterationsMax = nodeArguments[1]; - } else { - throw new Error("invalid number of repeat node iteration count arguments defined"); - } - } - node.attributes = getAttributes(tokens, placeholders); - popAndCheck(tokens, "{"); - stack.push(node.children); + case "mistreevous.succeeded" /* SUCCEEDED */: + case "mistreevous.failed" /* FAILED */: + this.setState("mistreevous.failed" /* FAILED */); break; + default: + this.setState("mistreevous.ready" /* READY */); + } + } + getName = () => "FAIL"; +}; + +// src/nodes/composite/Lotto.ts +var import_lotto_draw = __toESM(require_dist()); + +// src/nodes/composite/Composite.ts +var Composite = class extends Node { + constructor(type, attributes, children) { + super(type, attributes, []); + this.children = children; + } + isLeafNode = () => false; + getChildren = () => this.children; + reset = () => { + this.setState("mistreevous.ready" /* READY */); + this.getChildren().forEach((child) => child.reset()); + }; + abort = (agent) => { + if (!this.is("mistreevous.running" /* RUNNING */)) { + return; + } + this.getChildren().forEach((child) => child.abort(agent)); + this.reset(); + this.getAttribute("exit")?.callAgentFunction(agent, false, true); + }; +}; + +// src/nodes/composite/Lotto.ts +var Lotto = class extends Composite { + constructor(attributes, tickets, children) { + super("lotto", attributes, children); + this.tickets = tickets; + } + selectedChild; + onUpdate(agent, options) { + if (this.is("mistreevous.ready" /* READY */)) { + const lottoDraw = (0, import_lotto_draw.default)({ + random: options.random, + participants: this.children.map((child, index) => [child, this.tickets[index] || 1]) + }); + this.selectedChild = lottoDraw.draw() || void 0; + } + if (!this.selectedChild) { + throw new Error("failed to update lotto node as it has no active child"); + } + if (this.selectedChild.getState() === "mistreevous.ready" /* READY */ || this.selectedChild.getState() === "mistreevous.running" /* RUNNING */) { + this.selectedChild.update(agent, options); + } + this.setState(this.selectedChild.getState()); + } + getName = () => this.tickets.length ? `LOTTO [${this.tickets.join(",")}]` : "LOTTO"; +}; + +// src/nodes/composite/Selector.ts +var Selector = class extends Composite { + constructor(attributes, children) { + super("selector", attributes, children); + this.children = children; + } + onUpdate(agent, options) { + for (const child of this.children) { + if (child.getState() === "mistreevous.ready" /* READY */ || child.getState() === "mistreevous.running" /* RUNNING */) { + child.update(agent, options); } - case "RETRY": { - const node = ASTNodeFactories.RETRY(); - currentScope.push(node); - if (tokens[0] === "[") { - const nodeArguments = getArguments( - tokens, - placeholders, - (arg) => arg.type === "number" && !!arg.isInteger, - "retry node attempt counts must be integer values" - ).map((argument) => argument.value); - if (nodeArguments.length === 1) { - node.attempts = nodeArguments[0]; - } else if (nodeArguments.length === 2) { - node.attemptsMin = nodeArguments[0]; - node.attemptsMax = nodeArguments[1]; - } else { - throw new Error("invalid number of retry node attempt count arguments defined"); - } - } - node.attributes = getAttributes(tokens, placeholders); - popAndCheck(tokens, "{"); - stack.push(node.children); - break; + if (child.getState() === "mistreevous.succeeded" /* SUCCEEDED */) { + this.setState("mistreevous.succeeded" /* SUCCEEDED */); + return; } - case "ACTION": { - const node = ASTNodeFactories.ACTION(); - currentScope.push(node); - if (tokens[0] !== "[") { - throw new Error("expected action name identifier argument"); - } - const actionArguments = getArguments(tokens, placeholders); - if (actionArguments.length && actionArguments[0].type === "identifier") { - node.actionName = actionArguments.shift().value; + if (child.getState() === "mistreevous.failed" /* FAILED */) { + if (this.children.indexOf(child) === this.children.length - 1) { + this.setState("mistreevous.failed" /* FAILED */); + return; } else { - throw new Error("expected action name identifier argument"); + continue; } - actionArguments.filter((arg) => arg.type === "identifier").forEach((arg) => { - throw new Error( - "invalid action node argument value '" + arg.value + "', must be string, number, boolean or null" - ); - }); - node.actionArguments = actionArguments; - node.attributes = getAttributes(tokens, placeholders); - break; - } - case "}": { - stack.pop(); - break; } - default: { - throw new Error(`unexpected token '${token}'`); + if (child.getState() === "mistreevous.running" /* RUNNING */) { + this.setState("mistreevous.running" /* RUNNING */); + return; } + throw new Error("child node was not in an expected state."); } } - const validateASTNode = (node, depth) => { - node.validate(depth); - (node.children || []).forEach((child) => validateASTNode(child, depth + 1)); - }; - validateASTNode( - { - children: stack[0], - validate() { - if (this.children.length === 0) { - throw new Error("expected root node to have been defined"); - } - for (const definitionLevelNode of this.children) { - if (definitionLevelNode.type !== "root") { - throw new Error("expected root node at base of definition"); - } - } - if (this.children.filter((definitionLevelNode) => definitionLevelNode.name === null).length !== 1) { - throw new Error("expected single unnamed root node at base of definition to act as main root"); - } - const rootNodeNames = []; - for (const definitionLevelNode of this.children) { - if (rootNodeNames.indexOf(definitionLevelNode.name) !== -1) { - throw new Error(`multiple root nodes found with duplicate name '${definitionLevelNode.name}'`); - } else { - rootNodeNames.push(definitionLevelNode.name); - } + getName = () => "SELECTOR"; +}; + +// src/nodes/composite/Sequence.ts +var Sequence = class extends Composite { + constructor(attributes, children) { + super("sequence", attributes, children); + this.children = children; + } + onUpdate(agent, options) { + for (const child of this.children) { + if (child.getState() === "mistreevous.ready" /* READY */ || child.getState() === "mistreevous.running" /* RUNNING */) { + child.update(agent, options); + } + if (child.getState() === "mistreevous.succeeded" /* SUCCEEDED */) { + if (this.children.indexOf(child) === this.children.length - 1) { + this.setState("mistreevous.succeeded" /* SUCCEEDED */); + return; + } else { + continue; } } - }, - 0 - ); - return stack[0]; -} -function popAndCheck(tokens, expected) { - const popped = tokens.shift(); - if (popped === void 0) { - throw new Error("unexpected end of definition"); - } - if (expected !== void 0) { - var tokenMatchesExpectation = [].concat(expected).some((item) => popped.toUpperCase() === item.toUpperCase()); - if (!tokenMatchesExpectation) { - const expectationString = [].concat(expected).map((item) => "'" + item + "'").join(" or "); - throw new Error(`unexpected token found. Expected '${expectationString}' but got '${popped}'`); + if (child.getState() === "mistreevous.failed" /* FAILED */) { + this.setState("mistreevous.failed" /* FAILED */); + return; + } + if (child.getState() === "mistreevous.running" /* RUNNING */) { + this.setState("mistreevous.running" /* RUNNING */); + return; + } + throw new Error("child node was not in an expected state."); } } - return popped; -} -function getArguments(tokens, stringArgumentPlaceholders, argumentValidator, validationFailedMessage) { - const closer = popAndCheck(tokens, ["[", "("]) === "[" ? "]" : ")"; - const argumentListTokens = []; - const argumentList = []; - while (tokens.length && tokens[0] !== closer) { - argumentListTokens.push(tokens.shift()); + getName = () => "SEQUENCE"; +}; + +// src/nodes/composite/Parallel.ts +var Parallel = class extends Composite { + constructor(attributes, children) { + super("parallel", attributes, children); } - argumentListTokens.forEach((token, index) => { - const shouldBeArgumentToken = !(index & 1); - if (shouldBeArgumentToken) { - const argumentDefinition = getArgumentDefinition(token, stringArgumentPlaceholders); - if (argumentValidator && !argumentValidator(argumentDefinition)) { - throw new Error(validationFailedMessage); + onUpdate(agent, options) { + let succeededCount = 0; + let hasChildFailed = false; + for (const child of this.children) { + if (child.getState() === "mistreevous.ready" /* READY */ || child.getState() === "mistreevous.running" /* RUNNING */) { + child.update(agent, options); } - argumentList.push(argumentDefinition); - } else { - if (token !== ",") { - throw new Error(`invalid argument list, expected ',' or ']' but got '${token}'`); + if (child.getState() === "mistreevous.succeeded" /* SUCCEEDED */) { + succeededCount++; + continue; + } + if (child.getState() === "mistreevous.failed" /* FAILED */) { + hasChildFailed = true; + break; + } + if (child.getState() !== "mistreevous.running" /* RUNNING */) { + throw new Error("child node was not in an expected state."); } } - }); - popAndCheck(tokens, closer); - return argumentList; -} -function getArgumentDefinition(token, stringArgumentPlaceholders) { - if (token === "null") { + if (hasChildFailed) { + this.setState("mistreevous.failed" /* FAILED */); + for (const child of this.children) { + if (child.getState() === "mistreevous.running" /* RUNNING */) { + child.abort(agent); + } + } + } else { + this.setState(succeededCount === this.children.length ? "mistreevous.succeeded" /* SUCCEEDED */ : "mistreevous.running" /* RUNNING */); + } + } + getName = () => "PARALLEL"; +}; + +// src/attributes/Attribute.ts +var Attribute = class { + constructor(type, args) { + this.type = type; + this.args = args; + } + getType = () => this.type; + getArguments = () => this.args; +}; + +// src/attributes/guards/Guard.ts +var Guard = class extends Attribute { + constructor(type, args, condition) { + super(type, args); + this.condition = condition; + } + getCondition = () => this.condition; + isGuard = () => true; + getDetails() { return { - value: null, - type: "null" + type: this.getType(), + args: this.getArguments(), + condition: this.getCondition() }; } - if (token === "true" || token === "false") { - return { - value: token === "true", - type: "boolean" - }; +}; + +// src/attributes/guards/While.ts +var While = class extends Guard { + constructor(condition, args) { + super("while", args, condition); + } + isSatisfied = (agent) => { + const conditionFuncInvoker = Lookup.getFuncInvoker(agent, this.getCondition()); + if (conditionFuncInvoker === null) { + throw new Error( + `cannot evaluate node guard as the condition '${this.getCondition()}' function is not defined on the agent and has not been registered` + ); + } + return !!conditionFuncInvoker(this.args); + }; +}; + +// src/attributes/guards/Until.ts +var Until = class extends Guard { + constructor(condition, args) { + super("until", args, condition); + } + isSatisfied = (agent) => { + const conditionFuncInvoker = Lookup.getFuncInvoker(agent, this.getCondition()); + if (conditionFuncInvoker === null) { + throw new Error( + `cannot evaluate node guard as the condition '${this.getCondition()}' function is not defined on the agent and has not been registered` + ); + } + return !!!conditionFuncInvoker(this.args); + }; +}; + +// src/attributes/callbacks/Callback.ts +var Callback = class extends Attribute { + constructor(type, args, functionName) { + super(type, args); + this.functionName = functionName; } - if (!isNaN(token)) { + getFunctionName = () => this.functionName; + isGuard = () => false; + getDetails() { return { - value: parseFloat(token), - isInteger: parseFloat(token) === parseInt(token, 10), - type: "number" + type: this.getType(), + args: this.getArguments(), + functionName: this.getFunctionName() }; } - if (token.match(/^@@\d+@@$/g)) { - return { - value: stringArgumentPlaceholders[token].replace('\\"', '"'), - type: "string" - }; +}; + +// src/attributes/callbacks/Entry.ts +var Entry = class extends Callback { + constructor(functionName, args) { + super("entry", args, functionName); } - return { - value: token, - type: "identifier" - }; -} -function getAttributes(tokens, stringArgumentPlaceholders) { - const attributes = []; - const attributesFound = []; - let attributeFactory = AttributeFactories[(tokens[0] || "").toUpperCase()]; - while (attributeFactory) { - if (attributesFound.indexOf(tokens[0].toUpperCase()) !== -1) { - throw new Error(`duplicate attribute '${tokens[0].toUpperCase()}' found for node`); - } - attributesFound.push(tokens.shift().toUpperCase()); - const attributeArguments = getArguments(tokens, stringArgumentPlaceholders); - if (attributeArguments.length === 0 || attributeArguments[0].type !== "identifier") { - throw new Error("expected agent function name identifier argument for attribute"); - } - const attributeFunctionName = attributeArguments.shift(); - attributeArguments.filter((arg) => arg.type === "identifier").forEach((arg) => { + callAgentFunction = (agent) => { + const callbackFuncInvoker = Lookup.getFuncInvoker(agent, this.getFunctionName()); + if (callbackFuncInvoker === null) { throw new Error( - "invalid attribute argument value '" + arg.value + "', must be string, number, boolean or null" + `cannot call entry function '${this.getFunctionName()}' as is not defined on the agent and has not been registered` ); - }); - attributes.push(attributeFactory(attributeFunctionName.value, attributeArguments)); - attributeFactory = AttributeFactories[(tokens[0] || "").toUpperCase()]; - } - return attributes; -} -function substituteStringLiterals(definition) { - const placeholders = {}; - const processedDefinition = definition.replace(/\"(\\.|[^"\\])*\"/g, (match) => { - var strippedMatch = match.substring(1, match.length - 1); - var placeholder = Object.keys(placeholders).find((key) => placeholders[key] === strippedMatch); - if (!placeholder) { - placeholder = `@@${Object.keys(placeholders).length}@@`; - placeholders[placeholder] = strippedMatch; } - return placeholder; - }); - return { placeholders, processedDefinition }; -} -function parseTokensFromDefinition(definition) { - definition = definition.replace(/\(/g, " ( "); - definition = definition.replace(/\)/g, " ) "); - definition = definition.replace(/\{/g, " { "); - definition = definition.replace(/\}/g, " } "); - definition = definition.replace(/\]/g, " ] "); - definition = definition.replace(/\[/g, " [ "); - definition = definition.replace(/\,/g, " , "); - return definition.replace(/\s+/g, " ").trim().split(" "); -} + callbackFuncInvoker(this.args); + }; +}; -// src/BehaviourTree.ts -var BehaviourTree = class { - constructor(definition, agent, options = {}) { - this.agent = agent; - this.options = options; - if (typeof definition !== "string") { - throw new Error("the tree definition must be a string"); - } - if (typeof agent !== "object" || agent === null) { - throw new Error("the agent must be defined and not null"); - } - this.rootNode = BehaviourTree._createRootNode(definition); - } - rootNode; - isRunning() { - return this.rootNode.getState() === "mistreevous.running" /* RUNNING */; +// src/attributes/callbacks/Exit.ts +var Exit = class extends Callback { + constructor(functionName, args) { + super("exit", args, functionName); } - getState() { - return this.rootNode.getState(); + callAgentFunction = (agent, isSuccess, isAborted) => { + const callbackFuncInvoker = Lookup.getFuncInvoker(agent, this.getFunctionName()); + if (callbackFuncInvoker === null) { + throw new Error( + `cannot call exit function '${this.getFunctionName()}' as is not defined on the agent and has not been registered` + ); + } + callbackFuncInvoker([{ value: { succeeded: isSuccess, aborted: isAborted } }, ...this.args]); + }; +}; + +// src/attributes/callbacks/Step.ts +var Step = class extends Callback { + constructor(functionName, args) { + super("step", args, functionName); } - step() { - if (this.rootNode.getState() === "mistreevous.succeeded" /* SUCCEEDED */ || this.rootNode.getState() === "mistreevous.failed" /* FAILED */) { - this.rootNode.reset(); + callAgentFunction = (agent) => { + const callbackFuncInvoker = Lookup.getFuncInvoker(agent, this.getFunctionName()); + if (callbackFuncInvoker === null) { + throw new Error( + `cannot call step function '${this.getFunctionName()}' as is not defined on the agent and has not been registered` + ); } - try { - this.rootNode.update(this.agent, this.options); - } catch (exception) { - throw new Error(`error stepping tree: ${exception.message}`); + callbackFuncInvoker(this.args); + }; +}; + +// src/RootAstNodesBuilder.ts +var AttributeFactories = { + WHILE: (condition, attributeArguments) => new While(condition, attributeArguments), + UNTIL: (condition, attributeArguments) => new Until(condition, attributeArguments), + ENTRY: (functionName, attributeArguments) => new Entry(functionName, attributeArguments), + EXIT: (functionName, attributeArguments) => new Exit(functionName, attributeArguments), + STEP: (functionName, attributeArguments) => new Step(functionName, attributeArguments) +}; +var ASTNodeFactories = { + ROOT: () => ({ + type: "root", + attributes: [], + name: null, + children: [], + validate(depth) { + if (depth > 1) { + throw new Error("a root node cannot be the child of another node"); + } + if (this.children.length !== 1) { + throw new Error("a root node must have a single child"); + } + }, + createNodeInstance(namedRootNodeProvider, visitedBranches) { + return new Root( + this.attributes, + this.children[0].createNodeInstance(namedRootNodeProvider, visitedBranches.slice()) + ); } - } - reset() { - this.rootNode.reset(); - } - getFlattenedNodeDetails() { - const flattenedTreeNodes = []; - const processNode = (node, parentUid) => { - const guards = node.getAttributes().filter((attribute) => attribute.isGuard()).map((attribute) => attribute.getDetails()); - const callbacks = node.getAttributes().filter((attribute) => !attribute.isGuard()).map((attribute) => attribute.getDetails()); - flattenedTreeNodes.push({ - id: node.getUid(), - type: node.getType(), - caption: node.getName(), - state: node.getState(), - guards, - callbacks, - args: node.getArguments(), - parentId: parentUid - }); - if (!node.isLeafNode()) { - node.getChildren().forEach((child) => processNode(child, node.getUid())); + }), + BRANCH: () => ({ + type: "branch", + branchName: "", + validate() { + }, + createNodeInstance(namedRootNodeProvider, visitedBranches) { + const targetRootNode = namedRootNodeProvider(this.branchName); + if (visitedBranches.indexOf(this.branchName) !== -1) { + throw new Error(`circular dependency found in branch node references for branch '${this.branchName}'`); } - }; - processNode(this.rootNode, null); - return flattenedTreeNodes; - } - static register(name, value) { - if (typeof value === "function") { - Lookup.setFunc(name, value); - } else if (typeof value === "string") { - let rootASTNodes; - try { - rootASTNodes = buildRootASTNodes(value); - } catch (exception) { - throw new Error(`error registering definition: ${exception.message}`); + if (targetRootNode) { + return targetRootNode.createNodeInstance(namedRootNodeProvider, visitedBranches.concat(this.branchName)).getChildren()[0]; + } else { + throw new Error(`branch references root node '${this.branchName}' which has not been defined`); } - if (rootASTNodes.length != 1 || rootASTNodes[0].name !== null) { - throw new Error("error registering definition: expected a single unnamed root node"); + } + }), + SELECTOR: () => ({ + type: "selector", + attributes: [], + children: [], + validate() { + if (this.children.length < 1) { + throw new Error("a selector node must have at least a single child"); } - Lookup.setSubtree(name, rootASTNodes[0]); - } else { - throw new Error("unexpected value, expected string definition or function"); + }, + createNodeInstance(namedRootNodeProvider, visitedBranches) { + return new Selector( + this.attributes, + this.children.map((child) => child.createNodeInstance(namedRootNodeProvider, visitedBranches.slice())) + ); + } + }), + SEQUENCE: () => ({ + type: "sequence", + attributes: [], + children: [], + validate() { + if (this.children.length < 1) { + throw new Error("a sequence node must have at least a single child"); + } + }, + createNodeInstance(namedRootNodeProvider, visitedBranches) { + return new Sequence( + this.attributes, + this.children.map((child) => child.createNodeInstance(namedRootNodeProvider, visitedBranches.slice())) + ); } - } - static unregister(name) { - Lookup.remove(name); - } - static unregisterAll() { - Lookup.empty(); - } - static _createRootNode(definition) { - try { - } catch (exception) { - console.log(exception); + }), + PARALLEL: () => ({ + type: "parallel", + attributes: [], + children: [], + validate() { + if (this.children.length < 1) { + throw new Error("a parallel node must have at least a single child"); + } + }, + createNodeInstance(namedRootNodeProvider, visitedBranches) { + return new Parallel( + this.attributes, + this.children.map((child) => child.createNodeInstance(namedRootNodeProvider, visitedBranches.slice())) + ); } - try { - const rootASTNodes = buildRootASTNodes(definition); - const mainRootNodeKey = Symbol("__root__"); - const rootNodeMap = {}; - for (const rootASTNode of rootASTNodes) { - rootNodeMap[rootASTNode.name === null ? mainRootNodeKey : rootASTNode.name] = rootASTNode; + }), + LOTTO: () => ({ + type: "lotto", + attributes: [], + children: [], + tickets: [], + validate() { + if (this.children.length < 1) { + throw new Error("a lotto node must have at least a single child"); } - const rootNode = rootNodeMap[mainRootNodeKey].createNodeInstance( - (name) => rootNodeMap[name] ? rootNodeMap[name] : Lookup.getSubtree(name), - [] + }, + createNodeInstance(namedRootNodeProvider, visitedBranches) { + return new Lotto( + this.attributes, + this.tickets, + this.children.map((child) => child.createNodeInstance(namedRootNodeProvider, visitedBranches.slice())) ); - BehaviourTree._applyLeafNodeGuardPaths(rootNode); - return rootNode; - } catch (exception) { - throw new Error(`error parsing tree: ${exception.message}`); } - } - static _applyLeafNodeGuardPaths(rootNode) { - const nodePaths = []; - const findLeafNodes = (path, node) => { - path = path.concat(node); - if (node.isLeafNode()) { - nodePaths.push(path); + }), + REPEAT: () => ({ + type: "repeat", + attributes: [], + iterations: null, + iterationsMin: null, + iterationsMax: null, + children: [], + validate() { + if (this.children.length !== 1) { + throw new Error("a repeat node must have a single child"); + } + if (this.iterations !== null) { + if (this.iterations < 0) { + throw new Error("a repeat node must have a positive number of iterations if defined"); + } + } else if (this.iterationsMin !== null && this.iterationsMax !== null) { + if (this.iterationsMin < 0 || this.iterationsMax < 0) { + throw new Error( + "a repeat node must have a positive minimum and maximum iteration count if defined" + ); + } + if (this.iterationsMin > this.iterationsMax) { + throw new Error( + "a repeat node must not have a minimum iteration count that exceeds the maximum iteration count" + ); + } } else { - node.getChildren().forEach((child) => findLeafNodes(path, child)); } - }; - findLeafNodes([], rootNode); - nodePaths.forEach((path) => { - for (let depth = 0; depth < path.length; depth++) { - const currentNode = path[depth]; - if (currentNode.hasGuardPath()) { - continue; + }, + createNodeInstance(namedRootNodeProvider, visitedBranches) { + return new Repeat( + this.attributes, + this.iterations, + this.iterationsMin, + this.iterationsMax, + this.children[0].createNodeInstance(namedRootNodeProvider, visitedBranches.slice()) + ); + } + }), + RETRY: () => ({ + type: "retry", + attributes: [], + attempts: null, + attemptsMin: null, + attemptsMax: null, + children: [], + validate() { + if (this.children.length !== 1) { + throw new Error("a retry node must have a single child"); + } + if (this.attempts !== null) { + if (this.attempts < 0) { + throw new Error("a retry node must have a positive number of attempts if defined"); } - const guardPath = new GuardPath( - path.slice(0, depth + 1).map((node) => ({ node, guards: node.getGuardAttributes() })).filter((details) => details.guards.length > 0) - ); - currentNode.setGuardPath(guardPath); + } else if (this.attemptsMin !== null && this.attemptsMax !== null) { + if (this.attemptsMin < 0 || this.attemptsMax < 0) { + throw new Error("a retry node must have a positive minimum and maximum attempt count if defined"); + } + if (this.attemptsMin > this.attemptsMax) { + throw new Error( + "a retry node must not have a minimum attempt count that exceeds the maximum attempt count" + ); + } + } else { } - }); - } -}; - -// src/mdsl/MDSLUtilities.ts -function isRootNode(node) { - return node.type === "root"; -} -function isLeafNode(node) { - return ["branch", "action", "condition", "wait"].includes(node.type); -} -function isDecoratorNode(node) { - return ["root", "repeat", "retry", "flip", "succeed", "fail"].includes(node.type); -} -function isCompositeNode(node) { - return ["sequence", "selector", "lotto", "parallel"].includes(node.type); -} -function popAndCheck2(tokens, expected) { - const popped = tokens.shift(); - if (popped === void 0) { - throw new Error("unexpected end of definition"); - } - if (expected != void 0) { - const expectedValues = typeof expected === "string" ? [expected] : expected; - var tokenMatchesExpectation = expectedValues.some((item) => popped.toUpperCase() === item.toUpperCase()); - if (!tokenMatchesExpectation) { - const expectationString = expectedValues.map((item) => "'" + item + "'").join(" or "); - throw new Error("unexpected token found. Expected " + expectationString + " but got '" + popped + "'"); + }, + createNodeInstance(namedRootNodeProvider, visitedBranches) { + return new Retry( + this.attributes, + this.attempts, + this.attemptsMin, + this.attemptsMax, + this.children[0].createNodeInstance(namedRootNodeProvider, visitedBranches.slice()) + ); } - } - return popped; -} -function substituteStringLiterals2(definition) { - const placeholders = {}; - const processedDefinition = definition.replace(/\"(\\.|[^"\\])*\"/g, (match) => { - var strippedMatch = match.substring(1, match.length - 1); - var placeholder = Object.keys(placeholders).find((key) => placeholders[key] === strippedMatch); - if (!placeholder) { - placeholder = `@@${Object.keys(placeholders).length}@@`; - placeholders[placeholder] = strippedMatch; + }), + FLIP: () => ({ + type: "flip", + attributes: [], + children: [], + validate() { + if (this.children.length !== 1) { + throw new Error("a flip node must have a single child"); + } + }, + createNodeInstance(namedRootNodeProvider, visitedBranches) { + return new Flip( + this.attributes, + this.children[0].createNodeInstance(namedRootNodeProvider, visitedBranches.slice()) + ); } - return placeholder; - }); - return { placeholders, processedDefinition }; -} -function parseTokensFromDefinition2(definition) { - definition = definition.replace(/\(/g, " ( "); - definition = definition.replace(/\)/g, " ) "); - definition = definition.replace(/\{/g, " { "); - definition = definition.replace(/\}/g, " } "); - definition = definition.replace(/\]/g, " ] "); - definition = definition.replace(/\[/g, " [ "); - definition = definition.replace(/\,/g, " , "); - return definition.replace(/\s+/g, " ").trim().split(" "); -} - -// src/mdsl/MDSLNodeArgumentParser.ts -function parseArgumentTokens(tokens, stringArgumentPlaceholders) { - const argumentList = []; - if (!["[", "("].includes(tokens[0])) { - return argumentList; - } - const closingToken = popAndCheck2(tokens, ["[", "("]) === "[" ? "]" : ")"; - const argumentListTokens = []; - while (tokens.length && tokens[0] !== closingToken) { - argumentListTokens.push(tokens.shift()); - } - argumentListTokens.forEach((token, index) => { - const shouldBeArgumentToken = !(index & 1); - if (shouldBeArgumentToken) { - const argumentDefinition = getArgumentDefinition2(token, stringArgumentPlaceholders); - argumentList.push(argumentDefinition); - } else { - if (token !== ",") { - throw new Error(`invalid argument list, expected ',' or ']' but got '${token}'`); + }), + SUCCEED: () => ({ + type: "succeed", + attributes: [], + children: [], + validate() { + if (this.children.length !== 1) { + throw new Error("a succeed node must have a single child"); + } + }, + createNodeInstance(namedRootNodeProvider, visitedBranches) { + return new Succeed( + this.attributes, + this.children[0].createNodeInstance(namedRootNodeProvider, visitedBranches.slice()) + ); + } + }), + FAIL: () => ({ + type: "fail", + attributes: [], + children: [], + validate() { + if (this.children.length !== 1) { + throw new Error("a fail node must have a single child"); } + }, + createNodeInstance(namedRootNodeProvider, visitedBranches) { + return new Fail( + this.attributes, + this.children[0].createNodeInstance(namedRootNodeProvider, visitedBranches.slice()) + ); } - }); - popAndCheck2(tokens, closingToken); - return argumentList; -} -function getArgumentDefinition2(token, stringArgumentPlaceholders) { - if (token === "null") { - return { - value: null, - type: "null" - }; - } - if (token === "true" || token === "false") { - return { - value: token === "true", - type: "boolean" - }; - } - if (!isNaN(token)) { - return { - value: parseFloat(token), - isInteger: parseFloat(token) === parseInt(token, 10), - type: "number" - }; - } - if (token.match(/^@@\d+@@$/g)) { - return { - value: stringArgumentPlaceholders[token].replace('\\"', '"'), - type: "string" - }; - } - return { - value: token, - type: "identifier" - }; -} - -// src/mdsl/MDSLNodeAttributeParser.ts -function parseAttributeTokens(tokens, stringArgumentPlaceholders) { - const nodeAttributeNames = ["while", "until", "entry", "exit", "step"]; - const attributes = {}; - let nextAttributeName = tokens[0]?.toLowerCase(); - while (nodeAttributeNames.includes(nextAttributeName)) { - if (attributes[nextAttributeName]) { - throw new Error(`duplicate attribute '${tokens[0].toUpperCase()}' found for node`); + }), + WAIT: () => ({ + type: "wait", + attributes: [], + duration: null, + durationMin: null, + durationMax: null, + validate() { + if (this.duration !== null) { + if (this.duration < 0) { + throw new Error("a wait node must have a positive duration"); + } + } else if (this.durationMin !== null && this.durationMax !== null) { + if (this.durationMin < 0 || this.durationMax < 0) { + throw new Error("a wait node must have a positive minimum and maximum duration"); + } + if (this.durationMin > this.durationMax) { + throw new Error("a wait node must not have a minimum duration that exceeds the maximum duration"); + } + } else { + } + }, + createNodeInstance() { + return new Wait(this.attributes, this.duration, this.durationMin, this.durationMax); } - tokens.shift(); - const [attributeCallIdentifier, ...attributeArguments] = parseArgumentTokens( - tokens, - stringArgumentPlaceholders - ); - if (attributeCallIdentifier?.type !== "identifier") { - throw new Error("expected agent function name identifier argument for attribute"); + }), + ACTION: () => ({ + type: "action", + attributes: [], + actionName: "", + actionArguments: [], + validate() { + }, + createNodeInstance() { + return new Action(this.attributes, this.actionName, this.actionArguments); } - attributeArguments.filter((arg) => arg.type === "identifier").forEach((arg) => { - throw new Error( - `invalid attribute argument value '${arg.value}', must be string, number, boolean or null` - ); - }); - attributes[nextAttributeName] = { - call: attributeCallIdentifier.value, - args: attributeArguments.map(({ value }) => value) - }; - nextAttributeName = tokens[0]?.toLowerCase(); - } - return attributes; -} - -// src/mdsl/MDSLDefinitionParser.ts -function parseMDSLToJSON(definition) { + }), + CONDITION: () => ({ + type: "condition", + attributes: [], + conditionName: "", + conditionArguments: [], + validate() { + }, + createNodeInstance() { + return new Condition(this.attributes, this.conditionName, this.conditionArguments); + } + }) +}; +function buildRootASTNodes(definition) { const { placeholders, processedDefinition } = substituteStringLiterals2(definition); const tokens = parseTokensFromDefinition2(processedDefinition); - return convertTokensToJSONDefinition(tokens, placeholders); -} -function convertTokensToJSONDefinition(tokens, stringLiteralPlaceholders) { if (tokens.length < 3) { throw new Error("invalid token count"); } if (tokens.filter((token) => token === "{").length !== tokens.filter((token) => token === "}").length) { throw new Error("scope character mismatch"); } - const treeStacks = []; - const rootNodes = []; - const pushNode = (node) => { - if (isRootNode(node)) { - rootNodes.push(node); - treeStacks.push([node]); - return; - } - if (!treeStacks.length || !treeStacks[treeStacks.length - 1].length) { - throw new Error("expected root node at base of definition"); - } - const topTreeStack = treeStacks[treeStacks.length - 1]; - const topTreeStackTopNode = topTreeStack[topTreeStack.length - 1]; - if (isCompositeNode(topTreeStackTopNode)) { - topTreeStackTopNode.children = topTreeStackTopNode.children || []; - topTreeStackTopNode.children.push(node); - } else if (isDecoratorNode(topTreeStackTopNode)) { - if (topTreeStackTopNode.child) { - throw new Error("a decorator node must only have a single child node"); - } - topTreeStackTopNode.child = node; - } - if (!isLeafNode(node)) { - topTreeStack.push(node); - } - }; - const popNode = () => { - const topTreeStack = treeStacks[treeStacks.length - 1]; - if (topTreeStack.length) { - topTreeStack.pop(); - } - if (!topTreeStack.length) { - treeStacks.pop(); - } - }; + const stack = [[]]; + const rootScope = stack[0]; while (tokens.length) { const token = tokens.shift(); + const currentScope = stack[stack.length - 1]; switch (token.toUpperCase()) { case "ROOT": { - pushNode(createRootNode(tokens, stringLiteralPlaceholders)); + const node = ASTNodeFactories.ROOT(); + rootScope.push(node); + if (tokens[0] === "[") { + const rootArguments = getArguments(tokens, placeholders); + if (rootArguments.length === 1 && rootArguments[0].type === "identifier") { + node.name = rootArguments[0].value; + } else { + throw new Error("expected single root name argument"); + } + } + node.attributes = getAttributes(tokens, placeholders); + popAndCheck2(tokens, "{"); + stack.push(node.children); break; } - case "SUCCEED": { - pushNode(createSucceedNode(tokens, stringLiteralPlaceholders)); + case "BRANCH": { + const node = ASTNodeFactories.BRANCH(); + currentScope.push(node); + if (tokens[0] !== "[") { + throw new Error("expected single branch name argument"); + } + const branchArguments = getArguments(tokens, placeholders); + if (branchArguments.length === 1 && branchArguments[0].type === "identifier") { + node.branchName = branchArguments[0].value; + } else { + throw new Error("expected single branch name argument"); + } break; } - case "FAIL": { - pushNode(createFailNode(tokens, stringLiteralPlaceholders)); + case "SELECTOR": { + const node = ASTNodeFactories.SELECTOR(); + currentScope.push(node); + node.attributes = getAttributes(tokens, placeholders); + popAndCheck2(tokens, "{"); + stack.push(node.children); break; } - case "FLIP": { - pushNode(createFlipNode(tokens, stringLiteralPlaceholders)); + case "SEQUENCE": { + const node = ASTNodeFactories.SEQUENCE(); + currentScope.push(node); + node.attributes = getAttributes(tokens, placeholders); + popAndCheck2(tokens, "{"); + stack.push(node.children); break; } - case "REPEAT": { - pushNode(createRepeatNode(tokens, stringLiteralPlaceholders)); + case "PARALLEL": { + const node = ASTNodeFactories.PARALLEL(); + currentScope.push(node); + node.attributes = getAttributes(tokens, placeholders); + popAndCheck2(tokens, "{"); + stack.push(node.children); break; } - case "RETRY": { - pushNode(createRetryNode(tokens, stringLiteralPlaceholders)); + case "LOTTO": { + const node = ASTNodeFactories.LOTTO(); + currentScope.push(node); + if (tokens[0] === "[") { + node.tickets = getArguments( + tokens, + placeholders, + (arg) => arg.type === "number" && !!arg.isInteger, + "lotto node ticket counts must be integer values" + ).map((argument) => argument.value); + } + node.attributes = getAttributes(tokens, placeholders); + popAndCheck2(tokens, "{"); + stack.push(node.children); break; } - case "SEQUENCE": { - pushNode(createSequenceNode(tokens, stringLiteralPlaceholders)); + case "CONDITION": { + const node = ASTNodeFactories.CONDITION(); + currentScope.push(node); + if (tokens[0] !== "[") { + throw new Error("expected condition name identifier argument"); + } + const conditionArguments = getArguments(tokens, placeholders); + if (conditionArguments.length && conditionArguments[0].type === "identifier") { + node.conditionName = conditionArguments.shift().value; + } else { + throw new Error("expected condition name identifier argument"); + } + conditionArguments.filter((arg) => arg.type === "identifier").forEach((arg) => { + throw new Error( + "invalid condition node argument value '" + arg.value + "', must be string, number, boolean or null" + ); + }); + node.conditionArguments = conditionArguments; + node.attributes = getAttributes(tokens, placeholders); break; } - case "SELECTOR": { - pushNode(createSelectorNode(tokens, stringLiteralPlaceholders)); + case "FLIP": { + const node = ASTNodeFactories.FLIP(); + currentScope.push(node); + node.attributes = getAttributes(tokens, placeholders); + popAndCheck2(tokens, "{"); + stack.push(node.children); break; } - case "PARALLEL": { - pushNode(createParallelNode(tokens, stringLiteralPlaceholders)); + case "SUCCEED": { + const node = ASTNodeFactories.SUCCEED(); + currentScope.push(node); + node.attributes = getAttributes(tokens, placeholders); + popAndCheck2(tokens, "{"); + stack.push(node.children); break; } - case "LOTTO": { - pushNode(createLottoNode(tokens, stringLiteralPlaceholders)); + case "FAIL": { + const node = ASTNodeFactories.FAIL(); + currentScope.push(node); + node.attributes = getAttributes(tokens, placeholders); + popAndCheck2(tokens, "{"); + stack.push(node.children); break; } - case "ACTION": { - pushNode(createActionNode(tokens, stringLiteralPlaceholders)); + case "WAIT": { + const node = ASTNodeFactories.WAIT(); + currentScope.push(node); + if (tokens[0] === "[") { + const nodeArguments = getArguments( + tokens, + placeholders, + (arg) => arg.type === "number" && !!arg.isInteger, + "wait node durations must be integer values" + ).map((argument) => argument.value); + if (nodeArguments.length === 1) { + node.duration = nodeArguments[0]; + } else if (nodeArguments.length === 2) { + node.durationMin = nodeArguments[0]; + node.durationMax = nodeArguments[1]; + } else if (nodeArguments.length > 2) { + throw new Error("invalid number of wait node duration arguments defined"); + } + } + node.attributes = getAttributes(tokens, placeholders); break; } - case "CONDITION": { - pushNode(createConditionNode(tokens, stringLiteralPlaceholders)); + case "REPEAT": { + const node = ASTNodeFactories.REPEAT(); + currentScope.push(node); + if (tokens[0] === "[") { + const nodeArguments = getArguments( + tokens, + placeholders, + (arg) => arg.type === "number" && !!arg.isInteger, + "repeat node iteration counts must be integer values" + ).map((argument) => argument.value); + if (nodeArguments.length === 1) { + node.iterations = nodeArguments[0]; + } else if (nodeArguments.length === 2) { + node.iterationsMin = nodeArguments[0]; + node.iterationsMax = nodeArguments[1]; + } else { + throw new Error("invalid number of repeat node iteration count arguments defined"); + } + } + node.attributes = getAttributes(tokens, placeholders); + popAndCheck2(tokens, "{"); + stack.push(node.children); break; } - case "WAIT": { - pushNode(createWaitNode(tokens, stringLiteralPlaceholders)); + case "RETRY": { + const node = ASTNodeFactories.RETRY(); + currentScope.push(node); + if (tokens[0] === "[") { + const nodeArguments = getArguments( + tokens, + placeholders, + (arg) => arg.type === "number" && !!arg.isInteger, + "retry node attempt counts must be integer values" + ).map((argument) => argument.value); + if (nodeArguments.length === 1) { + node.attempts = nodeArguments[0]; + } else if (nodeArguments.length === 2) { + node.attemptsMin = nodeArguments[0]; + node.attemptsMax = nodeArguments[1]; + } else { + throw new Error("invalid number of retry node attempt count arguments defined"); + } + } + node.attributes = getAttributes(tokens, placeholders); + popAndCheck2(tokens, "{"); + stack.push(node.children); break; } - case "BRANCH": { - pushNode(createBranchNode(tokens, stringLiteralPlaceholders)); + case "ACTION": { + const node = ASTNodeFactories.ACTION(); + currentScope.push(node); + if (tokens[0] !== "[") { + throw new Error("expected action name identifier argument"); + } + const actionArguments = getArguments(tokens, placeholders); + if (actionArguments.length && actionArguments[0].type === "identifier") { + node.actionName = actionArguments.shift().value; + } else { + throw new Error("expected action name identifier argument"); + } + actionArguments.filter((arg) => arg.type === "identifier").forEach((arg) => { + throw new Error( + "invalid action node argument value '" + arg.value + "', must be string, number, boolean or null" + ); + }); + node.actionArguments = actionArguments; + node.attributes = getAttributes(tokens, placeholders); break; } case "}": { - popNode(); + stack.pop(); break; } default: { - throw new Error(`unexpected token: ${token}`); + throw new Error(`unexpected token '${token}'`); } } } - return rootNodes; -} -function createRootNode(tokens, stringLiteralPlaceholders) { - let node = { - type: "root", - id: void 0 - }; - const nodeArguments = parseArgumentTokens(tokens, stringLiteralPlaceholders); - if (nodeArguments.length) { - if (nodeArguments.length === 1 && nodeArguments[0].type === "identifier") { - node.id = nodeArguments[0].value; - } else { - throw new Error("expected single root name argument"); - } - } - node = { ...node, ...parseAttributeTokens(tokens, stringLiteralPlaceholders) }; - popAndCheck2(tokens, "{"); - return node; -} -function createSucceedNode(tokens, stringLiteralPlaceholders) { - const node = { - type: "succeed", - ...parseAttributeTokens(tokens, stringLiteralPlaceholders) - }; - popAndCheck2(tokens, "{"); - return node; -} -function createFailNode(tokens, stringLiteralPlaceholders) { - const node = { - type: "fail", - ...parseAttributeTokens(tokens, stringLiteralPlaceholders) - }; - popAndCheck2(tokens, "{"); - return node; -} -function createFlipNode(tokens, stringLiteralPlaceholders) { - const node = { - type: "flip", - ...parseAttributeTokens(tokens, stringLiteralPlaceholders) + const validateASTNode = (node, depth) => { + node.validate(depth); + (node.children || []).forEach((child) => validateASTNode(child, depth + 1)); }; - popAndCheck2(tokens, "{"); - return node; + validateASTNode( + { + children: stack[0], + validate() { + if (this.children.length === 0) { + throw new Error("expected root node to have been defined"); + } + for (const definitionLevelNode of this.children) { + if (definitionLevelNode.type !== "root") { + throw new Error("expected root node at base of definition"); + } + } + if (this.children.filter((definitionLevelNode) => definitionLevelNode.name === null).length !== 1) { + throw new Error("expected single unnamed root node at base of definition to act as main root"); + } + const rootNodeNames = []; + for (const definitionLevelNode of this.children) { + if (rootNodeNames.indexOf(definitionLevelNode.name) !== -1) { + throw new Error(`multiple root nodes found with duplicate name '${definitionLevelNode.name}'`); + } else { + rootNodeNames.push(definitionLevelNode.name); + } + } + } + }, + 0 + ); + return stack[0]; } -function createRepeatNode(tokens, stringLiteralPlaceholders) { - let node = { type: "repeat" }; - const nodeArguments = parseArgumentTokens(tokens, stringLiteralPlaceholders); - if (nodeArguments.length) { - nodeArguments.filter((arg) => arg.type !== "number" || !arg.isInteger).forEach(() => { - throw new Error(`repeat node iteration counts must be integer values`); - }); - if (nodeArguments.length === 1) { - node.iterations = nodeArguments[0].value; - } else if (nodeArguments.length === 2) { - node.iterations = [nodeArguments[0].value, nodeArguments[1].value]; - } else { - throw new Error("invalid number of repeat node iteration count arguments defined"); - } +function popAndCheck2(tokens, expected) { + const popped = tokens.shift(); + if (popped === void 0) { + throw new Error("unexpected end of definition"); } - node = { ...node, ...parseAttributeTokens(tokens, stringLiteralPlaceholders) }; - popAndCheck2(tokens, "{"); - return node; -} -function createRetryNode(tokens, stringLiteralPlaceholders) { - let node = { type: "retry" }; - const nodeArguments = parseArgumentTokens(tokens, stringLiteralPlaceholders); - if (nodeArguments.length) { - nodeArguments.filter((arg) => arg.type !== "number" || !arg.isInteger).forEach(() => { - throw new Error(`retry node attempt counts must be integer values`); - }); - if (nodeArguments.length === 1) { - node.attempts = nodeArguments[0].value; - } else if (nodeArguments.length === 2) { - node.attempts = [nodeArguments[0].value, nodeArguments[1].value]; - } else { - throw new Error("invalid number of retry node attempt count arguments defined"); + if (expected !== void 0) { + var tokenMatchesExpectation = [].concat(expected).some((item) => popped.toUpperCase() === item.toUpperCase()); + if (!tokenMatchesExpectation) { + const expectationString = [].concat(expected).map((item) => "'" + item + "'").join(" or "); + throw new Error(`unexpected token found. Expected '${expectationString}' but got '${popped}'`); } } - node = { ...node, ...parseAttributeTokens(tokens, stringLiteralPlaceholders) }; - popAndCheck2(tokens, "{"); - return node; -} -function createSequenceNode(tokens, stringLiteralPlaceholders) { - const node = { - type: "sequence", - ...parseAttributeTokens(tokens, stringLiteralPlaceholders) - }; - popAndCheck2(tokens, "{"); - return node; -} -function createSelectorNode(tokens, stringLiteralPlaceholders) { - const node = { - type: "selector", - ...parseAttributeTokens(tokens, stringLiteralPlaceholders) - }; - popAndCheck2(tokens, "{"); - return node; -} -function createParallelNode(tokens, stringLiteralPlaceholders) { - const node = { - type: "parallel", - ...parseAttributeTokens(tokens, stringLiteralPlaceholders) - }; - popAndCheck2(tokens, "{"); - return node; + return popped; } -function createLottoNode(tokens, stringLiteralPlaceholders) { - const nodeArguments = parseArgumentTokens(tokens, stringLiteralPlaceholders); - nodeArguments.filter((arg) => arg.type !== "number" || !arg.isInteger).forEach(() => { - throw new Error(`lotto node weight arguments must be integer values`); +function getArguments(tokens, stringArgumentPlaceholders, argumentValidator, validationFailedMessage) { + const closer = popAndCheck2(tokens, ["[", "("]) === "[" ? "]" : ")"; + const argumentListTokens = []; + const argumentList = []; + while (tokens.length && tokens[0] !== closer) { + argumentListTokens.push(tokens.shift()); + } + argumentListTokens.forEach((token, index) => { + const shouldBeArgumentToken = !(index & 1); + if (shouldBeArgumentToken) { + const argumentDefinition = getArgumentDefinition2(token, stringArgumentPlaceholders); + if (argumentValidator && !argumentValidator(argumentDefinition)) { + throw new Error(validationFailedMessage); + } + argumentList.push(argumentDefinition); + } else { + if (token !== ",") { + throw new Error(`invalid argument list, expected ',' or ']' but got '${token}'`); + } + } }); - const node = { - type: "lotto", - weights: nodeArguments.map(({ value }) => value), - ...parseAttributeTokens(tokens, stringLiteralPlaceholders) - }; - popAndCheck2(tokens, "{"); - return node; + popAndCheck2(tokens, closer); + return argumentList; } -function createActionNode(tokens, stringLiteralPlaceholders) { - const [actionNameIdentifier, ...agentFunctionArgs] = parseArgumentTokens(tokens, stringLiteralPlaceholders); - if (actionNameIdentifier?.type !== "identifier") { - throw new Error("expected action name identifier argument"); +function getArgumentDefinition2(token, stringArgumentPlaceholders) { + if (token === "null") { + return { + value: null, + type: "null" + }; + } + if (token === "true" || token === "false") { + return { + value: token === "true", + type: "boolean" + }; + } + if (!isNaN(token)) { + return { + value: parseFloat(token), + isInteger: parseFloat(token) === parseInt(token, 10), + type: "number" + }; + } + if (token.match(/^@@\d+@@$/g)) { + return { + value: stringArgumentPlaceholders[token].replace('\\"', '"'), + type: "string" + }; } - agentFunctionArgs.filter((arg) => arg.type === "identifier").forEach((arg) => { - throw new Error( - `invalid action node argument value '${arg.value}', must be string, number, boolean or null` - ); - }); return { - type: "action", - call: actionNameIdentifier.value, - args: agentFunctionArgs.map(({ value }) => value), - ...parseAttributeTokens(tokens, stringLiteralPlaceholders) + value: token, + type: "identifier" }; } -function createConditionNode(tokens, stringLiteralPlaceholders) { - const [conditionNameIdentifier, ...agentFunctionArgs] = parseArgumentTokens(tokens, stringLiteralPlaceholders); - if (conditionNameIdentifier?.type !== "identifier") { - throw new Error("expected condition name identifier argument"); +function getAttributes(tokens, stringArgumentPlaceholders) { + const attributes = []; + const attributesFound = []; + let attributeFactory = AttributeFactories[(tokens[0] || "").toUpperCase()]; + while (attributeFactory) { + if (attributesFound.indexOf(tokens[0].toUpperCase()) !== -1) { + throw new Error(`duplicate attribute '${tokens[0].toUpperCase()}' found for node`); + } + attributesFound.push(tokens.shift().toUpperCase()); + const attributeArguments = getArguments(tokens, stringArgumentPlaceholders); + if (attributeArguments.length === 0 || attributeArguments[0].type !== "identifier") { + throw new Error("expected agent function name identifier argument for attribute"); + } + const attributeFunctionName = attributeArguments.shift(); + attributeArguments.filter((arg) => arg.type === "identifier").forEach((arg) => { + throw new Error( + "invalid attribute argument value '" + arg.value + "', must be string, number, boolean or null" + ); + }); + attributes.push(attributeFactory(attributeFunctionName.value, attributeArguments)); + attributeFactory = AttributeFactories[(tokens[0] || "").toUpperCase()]; } - agentFunctionArgs.filter((arg) => arg.type === "identifier").forEach((arg) => { - throw new Error( - `invalid condition node argument value '${arg.value}', must be string, number, boolean or null` - ); + return attributes; +} +function substituteStringLiterals2(definition) { + const placeholders = {}; + const processedDefinition = definition.replace(/\"(\\.|[^"\\])*\"/g, (match) => { + var strippedMatch = match.substring(1, match.length - 1); + var placeholder = Object.keys(placeholders).find((key) => placeholders[key] === strippedMatch); + if (!placeholder) { + placeholder = `@@${Object.keys(placeholders).length}@@`; + placeholders[placeholder] = strippedMatch; + } + return placeholder; }); - return { - type: "condition", - call: conditionNameIdentifier.value, - args: agentFunctionArgs.map(({ value }) => value), - ...parseAttributeTokens(tokens, stringLiteralPlaceholders) - }; + return { placeholders, processedDefinition }; } -function createWaitNode(tokens, stringLiteralPlaceholders) { - let node = { type: "wait" }; - const nodeArguments = parseArgumentTokens(tokens, stringLiteralPlaceholders); - if (nodeArguments.length) { - nodeArguments.filter((arg) => arg.type !== "number" || !arg.isInteger).forEach(() => { - throw new Error(`wait node duration arguments must be integer values`); - }); - if (nodeArguments.length === 1) { - node.duration = nodeArguments[0].value; - } else if (nodeArguments.length === 2) { - node.duration = [nodeArguments[0].value, nodeArguments[1].value]; - } else if (nodeArguments.length > 2) { - throw new Error("invalid number of wait node duration arguments defined"); +function parseTokensFromDefinition2(definition) { + definition = definition.replace(/\(/g, " ( "); + definition = definition.replace(/\)/g, " ) "); + definition = definition.replace(/\{/g, " { "); + definition = definition.replace(/\}/g, " } "); + definition = definition.replace(/\]/g, " ] "); + definition = definition.replace(/\[/g, " [ "); + definition = definition.replace(/\,/g, " , "); + return definition.replace(/\s+/g, " ").trim().split(" "); +} + +// src/BehaviourTree.ts +var BehaviourTree = class { + constructor(definition, agent, options = {}) { + this.agent = agent; + this.options = options; + if (typeof definition !== "string") { + throw new Error("the tree definition must be a string"); } + if (typeof agent !== "object" || agent === null) { + throw new Error("the agent must be defined and not null"); + } + this.rootNode = BehaviourTree._createRootNode(definition); } - return { ...node, ...parseAttributeTokens(tokens, stringLiteralPlaceholders) }; -} -function createBranchNode(tokens, stringLiteralPlaceholders) { - const nodeArguments = parseArgumentTokens(tokens, stringLiteralPlaceholders); - if (nodeArguments.length !== 1 || nodeArguments[0].type !== "identifier") { - throw new Error("expected single branch name argument"); + rootNode; + isRunning() { + return this.rootNode.getState() === "mistreevous.running" /* RUNNING */; } - return { type: "branch", ref: nodeArguments[0].value }; -} + getState() { + return this.rootNode.getState(); + } + step() { + if (this.rootNode.getState() === "mistreevous.succeeded" /* SUCCEEDED */ || this.rootNode.getState() === "mistreevous.failed" /* FAILED */) { + this.rootNode.reset(); + } + try { + this.rootNode.update(this.agent, this.options); + } catch (exception) { + throw new Error(`error stepping tree: ${exception.message}`); + } + } + reset() { + this.rootNode.reset(); + } + getFlattenedNodeDetails() { + const flattenedTreeNodes = []; + const processNode = (node, parentUid) => { + const guards = node.getAttributes().filter((attribute) => attribute.isGuard()).map((attribute) => attribute.getDetails()); + const callbacks = node.getAttributes().filter((attribute) => !attribute.isGuard()).map((attribute) => attribute.getDetails()); + flattenedTreeNodes.push({ + id: node.getUid(), + type: node.getType(), + caption: node.getName(), + state: node.getState(), + guards, + callbacks, + args: node.getArguments(), + parentId: parentUid + }); + if (!node.isLeafNode()) { + node.getChildren().forEach((child) => processNode(child, node.getUid())); + } + }; + processNode(this.rootNode, null); + return flattenedTreeNodes; + } + static register(name, value) { + if (typeof value === "function") { + Lookup.setFunc(name, value); + } else if (typeof value === "string") { + let rootASTNodes; + try { + rootASTNodes = buildRootASTNodes(value); + } catch (exception) { + throw new Error(`error registering definition: ${exception.message}`); + } + if (rootASTNodes.length != 1 || rootASTNodes[0].name !== null) { + throw new Error("error registering definition: expected a single unnamed root node"); + } + Lookup.setSubtree(name, rootASTNodes[0]); + } else { + throw new Error("unexpected value, expected string definition or function"); + } + } + static unregister(name) { + Lookup.remove(name); + } + static unregisterAll() { + Lookup.empty(); + } + static _createRootNode(definition) { + try { + } catch (exception) { + console.log(exception); + } + try { + const rootASTNodes = buildRootASTNodes(definition); + const mainRootNodeKey = Symbol("__root__"); + const rootNodeMap = {}; + for (const rootASTNode of rootASTNodes) { + rootNodeMap[rootASTNode.name === null ? mainRootNodeKey : rootASTNode.name] = rootASTNode; + } + const rootNode = rootNodeMap[mainRootNodeKey].createNodeInstance( + (name) => rootNodeMap[name] ? rootNodeMap[name] : Lookup.getSubtree(name), + [] + ); + BehaviourTree._applyLeafNodeGuardPaths(rootNode); + return rootNode; + } catch (exception) { + throw new Error(`error parsing tree: ${exception.message}`); + } + } + static _applyLeafNodeGuardPaths(rootNode) { + const nodePaths = []; + const findLeafNodes = (path, node) => { + path = path.concat(node); + if (node.isLeafNode()) { + nodePaths.push(path); + } else { + node.getChildren().forEach((child) => findLeafNodes(path, child)); + } + }; + findLeafNodes([], rootNode); + nodePaths.forEach((path) => { + for (let depth = 0; depth < path.length; depth++) { + const currentNode = path[depth]; + if (currentNode.hasGuardPath()) { + continue; + } + const guardPath = new GuardPath( + path.slice(0, depth + 1).map((node) => ({ node, guards: node.getGuardAttributes() })).filter((details) => details.guards.length > 0) + ); + currentNode.setGuardPath(guardPath); + } + }); + } +}; // Annotate the CommonJS export names for ESM import in node: 0 && (module.exports = { BehaviourTree, State, - parseMDSLToJSON + convertMDSLToJSON, + validateDefinition }); //# sourceMappingURL=index.js.map diff --git a/dist/index.js.map b/dist/index.js.map index 603dc50..4ac134e 100644 --- a/dist/index.js.map +++ b/dist/index.js.map @@ -1,7 +1,7 @@ { "version": 3, - "sources": ["../node_modules/lotto-draw/dist/Participant.js", "../node_modules/lotto-draw/dist/Utilities.js", "../node_modules/lotto-draw/dist/Lotto.js", "../node_modules/lotto-draw/dist/createLotto.js", "../node_modules/lotto-draw/dist/index.js", "../src/index.ts", "../src/attributes/guards/GuardUnsatisifedException.ts", "../src/attributes/guards/GuardPath.ts", "../src/State.ts", "../src/nodes/Node.ts", "../src/nodes/leaf/Leaf.ts", "../src/Lookup.ts", "../src/nodes/leaf/Action.ts", "../src/nodes/leaf/Condition.ts", "../src/nodes/leaf/Wait.ts", "../src/nodes/decorator/Decorator.ts", "../src/nodes/decorator/Root.ts", "../src/nodes/decorator/Repeat.ts", "../src/nodes/decorator/Retry.ts", "../src/nodes/decorator/Flip.ts", "../src/nodes/decorator/Succeed.ts", "../src/nodes/decorator/Fail.ts", "../src/nodes/composite/Lotto.ts", "../src/nodes/composite/Composite.ts", "../src/nodes/composite/Selector.ts", "../src/nodes/composite/Sequence.ts", "../src/nodes/composite/Parallel.ts", "../src/attributes/Attribute.ts", "../src/attributes/guards/Guard.ts", "../src/attributes/guards/While.ts", "../src/attributes/guards/Until.ts", "../src/attributes/callbacks/Callback.ts", "../src/attributes/callbacks/Entry.ts", "../src/attributes/callbacks/Exit.ts", "../src/attributes/callbacks/Step.ts", "../src/RootAstNodesBuilder.ts", "../src/BehaviourTree.ts", "../src/mdsl/MDSLUtilities.ts", "../src/mdsl/MDSLNodeArgumentParser.ts", "../src/mdsl/MDSLNodeAttributeParser.ts", "../src/mdsl/MDSLDefinitionParser.ts"], - "sourcesContent": ["\"use strict\";\r\nObject.defineProperty(exports, \"__esModule\", { value: true });\r\nexports.Participant = void 0;\r\n/**\r\n * A participant that holds a number of tickets.\r\n */\r\nvar Participant = /** @class */ (function () {\r\n /**\r\n * Creates an instance of the Participant class.\r\n * @param participant The actual participant.\r\n * @param tickets The number of tickets held by the participant.\r\n */\r\n function Participant(participant, tickets) {\r\n if (tickets === void 0) { tickets = 1; }\r\n this._participant = participant;\r\n this._tickets = tickets;\r\n }\r\n Object.defineProperty(Participant.prototype, \"participant\", {\r\n /** Gets the actual participant. */\r\n get: function () {\r\n return this._participant;\r\n },\r\n enumerable: false,\r\n configurable: true\r\n });\r\n Object.defineProperty(Participant.prototype, \"tickets\", {\r\n /** Gets or sets the number of tickets held by the participant. */\r\n get: function () {\r\n return this._tickets;\r\n },\r\n set: function (value) {\r\n this._tickets = value;\r\n },\r\n enumerable: false,\r\n configurable: true\r\n });\r\n return Participant;\r\n}());\r\nexports.Participant = Participant;\r\n", "\"use strict\";\r\nObject.defineProperty(exports, \"__esModule\", { value: true });\r\nexports.isNaturalNumber = exports.isNullOrUndefined = void 0;\r\n/**\r\n * Gets whether the value provided is null or undefined.\r\n * @param value The value to check.\r\n * @returns Whether the value provided is null or undefined.\r\n */\r\nfunction isNullOrUndefined(value) {\r\n return value === null || value === undefined;\r\n}\r\nexports.isNullOrUndefined = isNullOrUndefined;\r\n/**\r\n * Gets whether the value provided is a natural number.\r\n * @param value The value to check.\r\n * @returns Whether the value provided is a natural number.\r\n */\r\nfunction isNaturalNumber(value) {\r\n return typeof value === \"number\" && value >= 1 && Math.floor(value) === value;\r\n}\r\nexports.isNaturalNumber = isNaturalNumber;\r\n", "\"use strict\";\r\nObject.defineProperty(exports, \"__esModule\", { value: true });\r\nexports.Lotto = void 0;\r\nvar Participant_1 = require(\"./Participant\");\r\nvar Utilities_1 = require(\"./Utilities\");\r\n/**\r\n * Represents a lotto consisting of a number of pickable ticket-holding participants.\r\n */\r\nvar Lotto = /** @class */ (function () {\r\n /**\r\n * Creates a new instance of Lotto.\r\n * @param customRandom The custom RNG to use in place of Math.random().\r\n */\r\n function Lotto(customRandom) {\r\n /** The array of participants that are holding tickets in the lotto. */\r\n this._participants = [];\r\n this._customRandom = customRandom;\r\n }\r\n /**\r\n * Adds a participant with the specified number of tickets, or adds to the participant ticket count if the participant already holds tickets.\r\n * @param participant The participant to add or to increase the ticket count for if they already hold tickets.\r\n * @param tickets The number of tickets, defaults to 1.\r\n * @returns The Lotto instance.\r\n */\r\n Lotto.prototype.add = function (participant, tickets) {\r\n if (tickets === void 0) { tickets = 1; }\r\n // Check that we have a valid ticket count.\r\n if (!(0, Utilities_1.isNaturalNumber)(tickets)) {\r\n throw new Error(\"tickets value must be a natural number\");\r\n }\r\n // Check whether this participant has already been added.\r\n var existingParticipant = this._participants.find(function (part) { return part.participant === participant; });\r\n if (existingParticipant) {\r\n // The participant has already been added to the lotto so just add to their ticket count.\r\n existingParticipant.tickets += tickets;\r\n }\r\n else {\r\n // The participant is not part of the lotto so we should add them.\r\n this._participants.push(new Participant_1.Participant(participant, tickets));\r\n }\r\n return this;\r\n };\r\n /**\r\n * Removes the specified number of tickets for the given participant from the draw, or all tickets if a ticket number is not defined.\r\n * @param participant The participant to remove tickets for.\r\n * @param tickets The number of tickets to remove, or undefined if all tickets are to be removed.\r\n * @returns The Lotto instance.\r\n */\r\n Lotto.prototype.remove = function (participant, tickets) {\r\n // Attempt to get the existing participant.\r\n var existingParticipant = this._participants.find(function (part) { return part.participant === participant; });\r\n // There is nothing to do if the specified participant isn't even part of the lotto.\r\n if (!existingParticipant) {\r\n return this;\r\n }\r\n // Check whether a tickets value was given.\r\n if (tickets !== undefined) {\r\n // Check that we have a valid ticket count.\r\n if (!(0, Utilities_1.isNaturalNumber)(tickets)) {\r\n throw new Error(\"tickets value must be a natural number\");\r\n }\r\n existingParticipant.tickets -= tickets;\r\n // If the participant no longer holds any tickets then they should be removed.\r\n if (existingParticipant.tickets < 1) {\r\n this._participants = this._participants.filter(function (part) { return part !== existingParticipant; });\r\n }\r\n }\r\n else {\r\n // We are removing all tickets for the participant so just remove them from the lotto.\r\n this._participants = this._participants.filter(function (part) { return part !== existingParticipant; });\r\n }\r\n return this;\r\n };\r\n /**\r\n * Draw a winning ticket and return the participant that holds the ticket.\r\n * @param options The draw options.\r\n * @returns The participant that holds the winning ticket.\r\n */\r\n Lotto.prototype.draw = function (options) {\r\n if (options === void 0) { options = {}; }\r\n // If we have no participants then just return null.\r\n if (this._participants.length === 0) {\r\n return null;\r\n }\r\n var redrawable = (0, Utilities_1.isNullOrUndefined)(options.redrawable) ? true : options.redrawable;\r\n var pickable = [];\r\n this._participants.forEach(function (_a) {\r\n var participant = _a.participant, tickets = _a.tickets;\r\n for (var ticketCount = 0; ticketCount < tickets; ticketCount++) {\r\n pickable.push(participant);\r\n }\r\n });\r\n var random;\r\n // We need a random floating-point number between 0 (inclusive) and 1 to scale up to pick our winner.\r\n // If a custom random function exists then we should use that or fall back to Math.random().\r\n if (this._customRandom) {\r\n // Call our custom random function to get a random floating-point number.\r\n random = this._customRandom();\r\n // Verify that the result of calling our custom random function is a number between 0 (inclusive) and 1.\r\n if (typeof random !== \"number\" || random < 0 || random >= 1) {\r\n throw new Error(\"the 'random' function provided did not return a number between 0 (inclusive) and 1\");\r\n }\r\n }\r\n else {\r\n // No custom random function was defined so just use good ol' Math.random().\r\n random = Math.random();\r\n }\r\n // Pick a winning participant.\r\n var winner = pickable[Math.floor(random * pickable.length)];\r\n // If the ticket isn't redrawable then we should remove a ticket from the winning participants ticket count.\r\n if (!redrawable) {\r\n this.remove(winner, 1);\r\n }\r\n // Return the winning participant.\r\n return winner;\r\n };\r\n /**\r\n * Draws multiple winning tickets and return an array of the participants that hold the winning tickets.\r\n * @param tickets The number of winning tickets to draw.\r\n * @param options The draw multiple options.\r\n * @returns An array of the participants that hold the winning tickets.\r\n */\r\n Lotto.prototype.drawMultiple = function (tickets, options) {\r\n if (options === void 0) { options = {}; }\r\n var uniqueResults = (0, Utilities_1.isNullOrUndefined)(options.unique) ? false : options.unique;\r\n // Handle cases where the user has asked for zero tickets (no idea why they would do this be we should trust them).\r\n if (tickets === 0) {\r\n return [];\r\n }\r\n // Now that we know out tickets value is not zero we should check that it is a valid natural number.\r\n if (!(0, Utilities_1.isNaturalNumber)(tickets)) {\r\n throw new Error(\"tickets value must be a natural number\");\r\n }\r\n var result = [];\r\n // Keep drawing tickets until we either reach the number of required tickets or we simply run out of tickets to draw.\r\n // We can run out of tickets to draw if 'options.redrawable' is explicity 'false' or we just had no participants when 'drawMultiple' was called.\r\n while (result.length < tickets && this._participants.length > 0) {\r\n result.push(this.draw(options));\r\n }\r\n // If the 'unique' draw option is set then we need to remove duplicates from the result list.\r\n if (uniqueResults) {\r\n // Create an array to store our unique results.\r\n var unique = [];\r\n // Iterate over all of our participants (with potential duplicates) and populate our array of unique values.\r\n for (var _i = 0, result_1 = result; _i < result_1.length; _i++) {\r\n var participant = result_1[_i];\r\n if (unique.indexOf(participant) === -1) {\r\n unique.push(participant);\r\n }\r\n }\r\n result = unique;\r\n }\r\n return result;\r\n };\r\n return Lotto;\r\n}());\r\nexports.Lotto = Lotto;\r\n", "\"use strict\";\r\nObject.defineProperty(exports, \"__esModule\", { value: true });\r\nexports.createLotto = void 0;\r\nvar Lotto_1 = require(\"./Lotto\");\r\n/**\r\n * A function that creates and returns a Lotto instance.\r\n * @param participantsOrOptions An array of initial participants or options relating to the creation of a Lotto instance.\r\n * @returns A new Lotto instance.\r\n */\r\nfunction createLotto(participantsOrOptions) {\r\n // If no initial participants or lotto options were provided as an argument then we can just return a new lotto instance now.\r\n if (!participantsOrOptions) {\r\n return new Lotto_1.Lotto();\r\n }\r\n // Check whether we were provided with an array of initial participants or a lotto options object.\r\n if (Array.isArray(participantsOrOptions)) {\r\n // We are dealing with a pre-defined array of participants.\r\n var participants = participantsOrOptions;\r\n var lotto_1 = new Lotto_1.Lotto();\r\n // If the lotto participants have been defined upfront then we will need to add them all to our lotto instance now.\r\n participants.forEach(function (_a) {\r\n var participant = _a[0], tokens = _a[1];\r\n return lotto_1.add(participant, tokens);\r\n });\r\n // Return the Lotto instance.\r\n return lotto_1;\r\n }\r\n else {\r\n // We are dealing with some lotto options.\r\n var random = participantsOrOptions.random, participants = participantsOrOptions.participants;\r\n // Create a Lotto instance passing the custom RNG function to use in place of Math.random() (which could be undefined).\r\n var lotto_2 = new Lotto_1.Lotto(random);\r\n // If the lotto participants have been defined upfront as part of the options then we will need to add them all to our lotto instance now.\r\n if (participants) {\r\n participants.forEach(function (_a) {\r\n var participant = _a[0], tokens = _a[1];\r\n return lotto_2.add(participant, tokens);\r\n });\r\n }\r\n // Return the Lotto instance.\r\n return lotto_2;\r\n }\r\n}\r\nexports.createLotto = createLotto;\r\n", "\"use strict\";\r\nObject.defineProperty(exports, \"__esModule\", { value: true });\r\nvar createLotto_1 = require(\"./createLotto\");\r\nexports.default = createLotto_1.createLotto;\r\n", "import { BehaviourTree, FlattenedTreeNode } from \"./BehaviourTree\";\nimport State from \"./State\";\nimport { parseMDSLToJSON } from \"./mdsl/MDSLDefinitionParser\";\n\nexport { BehaviourTree, State, parseMDSLToJSON };\nexport type { FlattenedTreeNode };\n", "import Node from \"../../nodes/Node\";\n\n/**\n * An exception thrown when evaluating node guard path conditions and a conditions fails.\n */\nexport default class GuardUnsatisifedException extends Error {\n /**\n * @param source The node at which a guard condition failed.\n */\n constructor(private source: Node) {\n super(\"A guard path condition has failed\");\n }\n\n /**\n * Gets whether the specified node is the node at which a guard condition failed.\n * @param node The node to check against the source node.\n * @returns Whether the specified node is the node at which a guard condition failed.\n */\n isSourceNode = (node: Node) => node === this.source;\n}\n", "import { Agent } from \"../../Agent\";\nimport Guard from \"./Guard\";\nimport Node from \"../../nodes/Node\";\nimport GuardUnsatisifedException from \"./GuardUnsatisifedException\";\n\nexport type GuardPathPart = {\n node: Node;\n guards: Guard[];\n};\n\n/**\n * Represents a path of node guards along a root-to-leaf tree path.\n */\nexport default class GuardPath {\n /**\n * @param nodes An array of objects defining a node instance -> guard link, ordered by node depth.\n */\n constructor(private nodes: GuardPathPart[]) {}\n\n /**\n * Evaluate guard conditions for all guards in the tree path, moving outwards from the root.\n * @param agent The agent, required for guard evaluation.\n * @returns An evaluation results object.\n */\n evaluate = (agent: Agent) => {\n // We need to evaluate guard conditions for nodes up the tree, moving outwards from the root.\n for (const details of this.nodes) {\n // There can be multiple guards per node.\n for (const guard of details.guards) {\n // Check whether the guard condition passes, and throw an exception if not.\n if (!guard.isSatisfied(agent)) {\n throw new GuardUnsatisifedException(details.node);\n }\n }\n }\n };\n}\n", "/**\n * Enumeration of node state types.\n */\nexport enum State {\n READY = \"mistreevous.ready\",\n RUNNING = \"mistreevous.running\",\n SUCCEEDED = \"mistreevous.succeeded\",\n FAILED = \"mistreevous.failed\"\n}\n\nexport { State as default };\n\nexport type CompleteState = State.SUCCEEDED | State.FAILED;\nexport type AnyState = State.READY | State.RUNNING | CompleteState;\n", "import { Agent } from \"../Agent\";\nimport Attribute from \"../attributes/Attribute\";\nimport Entry from \"../attributes/callbacks/Entry\";\nimport Exit from \"../attributes/callbacks/Exit\";\nimport Step from \"../attributes/callbacks/Step\";\nimport Guard from \"../attributes/guards/Guard\";\nimport GuardPath from \"../attributes/guards/GuardPath\";\nimport GuardUnsatisifedException from \"../attributes/guards/GuardUnsatisifedException\";\nimport { BehaviourTreeOptions } from \"../BehaviourTreeOptions\";\nimport { AnyArgument } from \"../RootAstNodesBuilder\";\nimport State, { AnyState } from \"../State\";\nimport Leaf from \"./leaf/Leaf\";\n\n/**\n * A base node.\n */\nexport default abstract class Node {\n /**\n * The node uid.\n */\n private readonly uid: string = createNodeUid();\n /**\n * The node state.\n */\n private state: AnyState = State.READY;\n /**\n * The guard path to evaluate as part of a node update.\n */\n private guardPath: GuardPath | undefined;\n\n /**\n * @param type The node type.\n * @param attributes The node attributes.\n * @param args The node argument definitions.\n */\n constructor(private type: string, private attributes: Attribute[], private args: AnyArgument[]) {}\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected abstract onUpdate(agent: Agent, options: BehaviourTreeOptions): void;\n\n /**\n * Gets the name of the node.\n */\n public abstract getName(): string;\n\n /**\n * Gets whether this node is a leaf node.\n */\n public abstract isLeafNode: () => this is Leaf;\n\n /**\n * Gets/Sets the state of the node.\n */\n getState = (): AnyState => this.state;\n setState = (value: AnyState): void => {\n this.state = value;\n };\n\n /**\n * Gets the unique id of the node.\n */\n getUid = () => this.uid;\n\n /**\n * Gets the type of the node.\n */\n getType = () => this.type;\n\n /**\n * Gets the node attributes.\n */\n getAttributes = () => this.attributes;\n\n /**\n * Gets the node arguments.\n */\n getArguments = () => this.args;\n\n /**\n * Gets the node attribute with the specified type, or null if it does not exist.\n */\n getAttribute(type: \"entry\" | \"ENTRY\"): Entry;\n getAttribute(type: \"exit\" | \"EXIT\"): Exit;\n getAttribute(type: \"step\" | \"STEP\"): Step;\n getAttribute(type: string): Attribute {\n return (\n this.getAttributes().filter((decorator) => decorator.getType().toUpperCase() === type.toUpperCase())[0] ||\n null\n );\n }\n\n /**\n * Gets the node attributes.\n */\n getGuardAttributes = (): Guard[] => this.getAttributes().filter((decorator) => decorator.isGuard()) as Guard[];\n\n /**\n * Sets the guard path to evaluate as part of a node update.\n */\n setGuardPath = (value: GuardPath) => (this.guardPath = value);\n\n /**\n * Gets whether a guard path is assigned to this node.\n */\n hasGuardPath = () => !!this.guardPath;\n\n /**\n * Gets whether this node is in the specified state.\n * @param value The value to compare to the node state.\n */\n public is(value: AnyState): boolean {\n return this.state === value;\n }\n\n /**\n * Reset the state of the node.\n */\n public reset(): void {\n this.setState(State.READY);\n }\n\n /**\n * Abort the running of this node.\n * @param agent The agent.\n */\n public abort(agent: Agent): void {\n // There is nothing to do if this node is not in the running state.\n if (!this.is(State.RUNNING)) {\n return;\n }\n\n // Reset the state of this node.\n this.reset();\n\n this.getAttribute(\"exit\")?.callAgentFunction(agent, false, true);\n }\n\n /**\n * Update the node.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n * @returns The result of the update.\n */\n public update(agent: Agent, options: BehaviourTreeOptions): void {\n // If this node is already in a 'SUCCEEDED' or 'FAILED' state then there is nothing to do.\n if (this.is(State.SUCCEEDED) || this.is(State.FAILED)) {\n return;\n }\n\n try {\n // Evaluate all of the guard path conditions for the current tree path.\n this.guardPath!.evaluate(agent);\n\n // If this node is in the READY state then call the ENTRY for this node if it exists.\n if (this.is(State.READY)) {\n this.getAttribute(\"entry\")?.callAgentFunction(agent);\n }\n\n this.getAttribute(\"step\")?.callAgentFunction(agent);\n\n // Do the actual update.\n this.onUpdate(agent, options);\n\n // If this node is now in a 'SUCCEEDED' or 'FAILED' state then call the EXIT for this node if it exists.\n if (this.is(State.SUCCEEDED) || this.is(State.FAILED)) {\n this.getAttribute(\"exit\")?.callAgentFunction(agent, this.is(State.SUCCEEDED), false);\n }\n } catch (error) {\n // If the error is a GuardUnsatisfiedException then we need to determine if this node is the source.\n if (error instanceof GuardUnsatisifedException && error.isSourceNode(this)) {\n // Abort the current node.\n this.abort(agent);\n\n // Any node that is the source of an abort will be a failed node.\n this.setState(State.FAILED);\n } else {\n throw error;\n }\n }\n }\n}\n\n/**\n * Create a randomly generated node uid.\n * @returns A randomly generated node uid.\n */\nfunction createNodeUid(): string {\n var S4 = function () {\n return (((1 + Math.random()) * 0x10000) | 0).toString(16).substring(1);\n };\n return S4() + S4() + \"-\" + S4() + \"-\" + S4() + \"-\" + S4() + \"-\" + S4() + S4() + S4();\n}\n", "import Node from \"../Node\";\n\n/**\n * A leaf node.\n */\nexport default abstract class Leaf extends Node {\n /**\n * Gets whether this node is a leaf node.\n */\n isLeafNode = () => true;\n}\n", "import { ActionResult, Agent, ExitFunctionArg, FunctionArg, GlobalFunction } from \"./Agent\";\nimport { AnyArgument, RootAstNode } from \"./RootAstNodesBuilder\";\n\n// Exit callbacks receive their own special type of argument.\n// There's probably stricter ways to represent this but it feels overly complex right now.\ntype ExitResultArg = { value: ExitFunctionArg };\nexport type AnyExitArgument = AnyArgument | ExitResultArg;\n\nexport type InvokerFunction = (args: AnyExitArgument[]) => ActionResult;\n\n/**\n * A singleton used to store and lookup registered functions and subtrees.\n */\nexport default class Lookup {\n /**\n * The object holding any registered functions keyed on function name.\n */\n private static functionTable: { [key: string]: GlobalFunction } = {};\n /**\n * The object holding any registered sub-trees keyed on tree name.\n */\n private static subtreeTable: { [key: string]: RootAstNode } = {};\n\n /**\n * Gets the function with the specified name.\n * @param name The name of the function.\n * @returns The function with the specified name.\n */\n public static getFunc(name: string): GlobalFunction {\n return this.functionTable[name];\n }\n\n /**\n * Sets the function with the specified name for later lookup.\n * @param name The name of the function.\n * @param func The function.\n */\n public static setFunc(name: string, func: GlobalFunction): void {\n this.functionTable[name] = func;\n }\n\n /**\n * Gets the function invoker for the specified agent and function name.\n * If a function with the specified name exists on the agent object then it will\n * be returned, otherwise we will then check the registered functions for a match.\n * @param agent The agent instance that this behaviour tree is modelling behaviour for.\n * @param name The function name.\n * @returns The function invoker for the specified agent and function name.\n */\n static getFuncInvoker(agent: Agent, name: string): InvokerFunction | null {\n // Check whether the agent contains the specified function.\n const foundOnAgent = agent[name];\n if (foundOnAgent && typeof foundOnAgent === \"function\") {\n return (args: AnyExitArgument[]): boolean | ActionResult =>\n foundOnAgent.apply(\n agent,\n args.map((arg) => arg.value)\n );\n }\n\n // The agent does not contain the specified function but it may have been registered at some point.\n if (this.functionTable[name] && typeof this.functionTable[name] === \"function\") {\n return (args: AnyExitArgument[]) => this.functionTable[name](agent, ...args.map((arg) => arg.value));\n }\n\n // We have no function to invoke.\n return null;\n }\n\n /**\n * Gets the subtree with the specified name.\n * @param name The name of the subtree.\n * @returns The subtree with the specified name.\n */\n static getSubtree(name: string): RootAstNode {\n return this.subtreeTable[name];\n }\n\n /**\n * Sets the subtree with the specified name for later lookup.\n * @param name The name of the subtree.\n * @param subtree The subtree.\n */\n static setSubtree(name: string, subtree: RootAstNode) {\n this.subtreeTable[name] = subtree;\n }\n\n /**\n * Removes the registered function or subtree with the specified name.\n * @param name The name of the registered function or subtree.\n */\n static remove(name: string) {\n delete this.functionTable[name];\n delete this.subtreeTable[name];\n }\n\n /**\n * Remove all registered functions and subtrees.\n */\n static empty() {\n this.functionTable = {};\n this.subtreeTable = {};\n }\n}\n", "import Leaf from \"./Leaf\";\nimport State, { CompleteState } from \"../../State\";\nimport Lookup from \"../../Lookup\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { AnyArgument } from \"../../RootAstNodesBuilder\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * An Action leaf node.\n * This represents an immediate or ongoing state of behaviour.\n */\nexport default class Action extends Leaf {\n /**\n * @param attributes The node attributes.\n * @param actionName The action name.\n * @param actionArguments The array of action argument definitions.\n */\n constructor(attributes: Attribute[], private actionName: string, private actionArguments: AnyArgument[]) {\n super(\"action\", attributes, actionArguments);\n }\n\n /**\n * Whether there is a pending update promise.\n */\n private isUsingUpdatePromise = false;\n\n /**\n * The finished state result of an update promise.\n */\n private updatePromiseStateResult: CompleteState | null = null;\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // If the result of this action depends on an update promise then there is nothing to do until\n // it resolves, unless there has been a value set as a result of the update promise resolving.\n if (this.isUsingUpdatePromise) {\n // Check whether the update promise has resolved with a state value.\n if (this.updatePromiseStateResult) {\n // Set the state of this node to match the state returned by the promise.\n this.setState(this.updatePromiseStateResult);\n }\n\n return;\n }\n\n // Attempt to get the invoker for the action function.\n const actionFuncInvoker = Lookup.getFuncInvoker(agent, this.actionName);\n\n // The action function should be defined.\n if (actionFuncInvoker === null) {\n throw new Error(\n `cannot update action node as the action '${this.actionName}' function is not defined on the agent and has not been registered`\n );\n }\n\n // Call the action function, the result of which may be:\n // - The finished state of this action node.\n // - A promise to return a finished node state.\n // - Undefined if the node should remain in the running state.\n const updateResult = actionFuncInvoker(this.actionArguments) as CompleteState | Promise;\n\n if (updateResult instanceof Promise) {\n updateResult.then(\n (result) => {\n // If 'isUpdatePromisePending' is null then the promise was cleared as it was resolving, probably via an abort of reset.\n if (!this.isUsingUpdatePromise) {\n return;\n }\n\n // Check to make sure the result is a valid finished state.\n if (result !== State.SUCCEEDED && result !== State.FAILED) {\n throw new Error(\n \"action node promise resolved with an invalid value, expected a State.SUCCEEDED or State.FAILED value to be returned\"\n );\n }\n\n // Set pending update promise state result to be processed on next update.\n this.updatePromiseStateResult = result;\n },\n (reason) => {\n // If 'isUpdatePromisePending' is null then the promise was cleared as it was resolving, probably via an abort of reset.\n if (!this.isUsingUpdatePromise) {\n return;\n }\n\n // Just throw whatever was returned as the rejection argument.\n throw new Error(reason);\n }\n );\n\n // This node will be in the 'RUNNING' state until the update promise resolves.\n this.setState(State.RUNNING);\n\n // We are now waiting for the promise returned by the use to resolve before we know what state this node is in.\n this.isUsingUpdatePromise = true;\n } else {\n // Validate the returned value.\n this.validateUpdateResult(updateResult);\n\n // Set the state of this node, this may be undefined, which just means that the node is still in the 'RUNNING' state.\n this.setState(updateResult || State.RUNNING);\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => this.actionName;\n\n /**\n * Reset the state of the node.\n */\n reset = () => {\n // Reset the state of this node.\n this.setState(State.READY);\n\n // There is no longer an update promise that we care about.\n this.isUsingUpdatePromise = false;\n this.updatePromiseStateResult = null;\n };\n\n /**\n * Validate the result of an update function call.\n * @param result The result of an update function call.\n */\n private validateUpdateResult = (result: CompleteState | boolean) => {\n switch (result) {\n case State.SUCCEEDED:\n case State.FAILED:\n case undefined:\n return;\n default:\n throw new Error(\n `action '${this.actionName}' 'onUpdate' returned an invalid response, expected an optional State.SUCCEEDED or State.FAILED value to be returned`\n );\n }\n };\n}\n", "import Leaf from \"./Leaf\";\nimport State from \"../../State\";\nimport Lookup from \"../../Lookup\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { AnyArgument } from \"../../RootAstNodesBuilder\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A Condition leaf node.\n * This will succeed or fail immediately based on an agent predicate, without moving to the 'RUNNING' state.\n */\nexport default class Condition extends Leaf {\n /**\n * @param attributes The node attributes.\n * @param conditionName The name of the condition function.\n * @param conditionArguments The array of condition argument definitions.\n */\n constructor(attributes: Attribute[], private conditionName: string, private conditionArguments: AnyArgument[]) {\n super(\"condition\", attributes, conditionArguments);\n }\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // Attempt to get the invoker for the condition function.\n const conditionFuncInvoker = Lookup.getFuncInvoker(agent, this.conditionName);\n\n // The condition function should be defined.\n if (conditionFuncInvoker === null) {\n throw new Error(\n `cannot update condition node as the condition '${this.conditionName}' function is not defined on the agent and has not been registered`\n );\n }\n\n // Call the condition function to determine the state of this node.\n this.setState(!!conditionFuncInvoker(this.conditionArguments) ? State.SUCCEEDED : State.FAILED);\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => this.conditionName;\n}\n", "import Leaf from \"./Leaf\";\nimport State from \"../../State\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { Agent } from \"../../Agent\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A WAIT node.\n * The state of this node will change to SUCCEEDED after a duration of time\n */\nexport default class Wait extends Leaf {\n /**\n * @param attributes The node attributes.\n * @param duration The duration that this node will wait to succeed in milliseconds.\n * @param durationMin The minimum possible duration in milliseconds that this node will wait to succeed.\n * @param durationMax The maximum possible duration in milliseconds that this node will wait to succeed.\n */\n constructor(\n attributes: Attribute[],\n private duration: number | null,\n private durationMin: number | null,\n private durationMax: number | null\n ) {\n super(\"wait\", attributes, []);\n }\n\n /**\n * The time in milliseconds at which this node was first updated.\n */\n private initialUpdateTime: number = 0;\n\n /**\n * The total duration in milliseconds that this node will be waiting for.\n */\n private totalDuration: number | null = null;\n\n /**\n * The duration in milliseconds that this node has been waiting for.\n */\n private waitedDuration: number = 0;\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // If this node is in the READY state then we need to set the initial update time.\n if (this.is(State.READY)) {\n // Set the initial update time.\n this.initialUpdateTime = new Date().getTime();\n\n // Set the initial waited duration.\n this.waitedDuration = 0;\n\n // Are we dealing with an explicit duration or will we be randomly picking a duration between the min and max duration.\n if (this.duration !== null) {\n this.totalDuration = this.duration;\n } else if (this.durationMin !== null && this.durationMax !== null) {\n // We will be picking a random duration between a min and max duration, if the optional 'random' behaviour tree\n // function option is defined then we will be using that, otherwise we will fall back to using Math.random.\n const random = typeof options.random === \"function\" ? options.random : Math.random;\n\n // Pick a random duration between a min and max duration.\n this.totalDuration = Math.floor(\n random() * (this.durationMax - this.durationMin + 1) + this.durationMin\n );\n } else {\n this.totalDuration = null;\n }\n\n // The node is now running until we finish waiting.\n this.setState(State.RUNNING);\n }\n\n // If we have no total duration then this wait node will wait indefinitely until it is aborted.\n if (this.totalDuration === null) {\n return;\n }\n\n // If we have a 'getDeltaTime' function defined as part of our options then we will use it to figure out how long we have waited for.\n if (typeof options.getDeltaTime === \"function\") {\n // Get the delta time.\n const deltaTime = options.getDeltaTime();\n\n // Our delta time must be a valid number and cannot be NaN.\n if (typeof deltaTime !== \"number\" || isNaN(deltaTime)) {\n throw new Error(\"The delta time must be a valid number and not NaN.\");\n }\n\n // Update the amount of time that this node has been waiting for based on the delta time.\n this.waitedDuration += deltaTime * 1000;\n } else {\n // We are not using a delta time, so we will just work out hom much time has passed since the first update.\n this.waitedDuration = new Date().getTime() - this.initialUpdateTime;\n }\n\n // Have we waited long enough?\n if (this.waitedDuration >= this.totalDuration) {\n // We have finished waiting!\n this.setState(State.SUCCEEDED);\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => {\n if (this.duration !== null) {\n return `WAIT ${this.duration}ms`;\n } else if (this.durationMin !== null && this.durationMax !== null) {\n return `WAIT ${this.durationMin}ms-${this.durationMax}ms`;\n } else {\n return \"WAIT\";\n }\n };\n}\n", "import Node from \"../Node\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\n\n/**\n * A decorator node that wraps a single child node.\n */\nexport default abstract class Decorator extends Node {\n /**\n * @param type The node type.\n * @param attributes The node attributes.\n * @param child The child node.\n */\n constructor(type: string, attributes: Attribute[], protected child: Node) {\n super(type, attributes, []);\n }\n\n /**\n * Gets whether this node is a leaf node.\n */\n isLeafNode = () => false;\n\n /**\n * Gets the children of this node.\n */\n getChildren = () => [this.child];\n\n /**\n * Reset the state of the node.\n */\n reset = () => {\n // Reset the state of this node.\n this.setState(State.READY);\n\n // Reset the state of the child node.\n this.child.reset();\n };\n\n /**\n * Abort the running of this node.\n * @param agent The agent.\n */\n abort = (agent: Agent) => {\n // There is nothing to do if this node is not in the running state.\n if (!this.is(State.RUNNING)) {\n return;\n }\n\n // Abort the child node.\n this.child.abort(agent);\n\n // Reset the state of this node.\n this.reset();\n\n this.getAttribute(\"exit\")?.callAgentFunction(agent, false, true);\n };\n}\n", "import Node from \"../Node\";\nimport Decorator from \"./Decorator\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A Root node.\n * The root node will have a single child.\n */\nexport default class Root extends Decorator {\n /**\n * @param attributes The node attributes.\n * @param child The child node.\n */\n constructor(attributes: Attribute[], child: Node) {\n super(\"root\", attributes, child);\n }\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // If the child has never been updated or is running then we will need to update it now.\n if (this.child.getState() === State.READY || this.child.getState() === State.RUNNING) {\n // Update the child of this node.\n this.child.update(agent, options);\n }\n\n // The state of the root node is the state of its child.\n this.setState(this.child.getState());\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => \"ROOT\";\n}\n", "import Node from \"../Node\";\nimport Decorator from \"./Decorator\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A REPEAT node.\n * The node has a single child which can have:\n * -- A number of iterations for which to repeat the child node.\n * -- An infinite repeat loop if neither an iteration count or a condition function is defined.\n * The REPEAT node will stop and have a 'FAILED' state if its child is ever in a 'FAILED' state after an update.\n * The REPEAT node will attempt to move on to the next iteration if its child is ever in a 'SUCCEEDED' state.\n */\nexport default class Repeat extends Decorator {\n /**\n * @param attributes The node attributes.\n * @param iterations The number of iterations to repeat the child node.\n * @param iterationsMin The minimum possible number of iterations to repeat the child node.\n * @param iterationsMax The maximum possible number of iterations to repeat the child node.\n * @param child The child node.\n */\n constructor(\n attributes: Attribute[],\n private iterations: number | null,\n private iterationsMin: number | null,\n private iterationsMax: number | null,\n child: Node\n ) {\n super(\"repeat\", attributes, child);\n }\n\n /**\n * The number of target iterations to make.\n */\n private targetIterationCount: number | null = null;\n\n /**\n * The current iteration count.\n */\n private currentIterationCount: number = 0;\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // If this node is in the READY state then we need to reset the child and the target iteration count.\n if (this.is(State.READY)) {\n // Reset the child node.\n this.child.reset();\n\n // Reset the current iteration count.\n this.currentIterationCount = 0;\n\n // Set the target iteration count.\n this.setTargetIterationCount(options);\n }\n\n // Do a check to see if we can iterate. If we can then this node will move into the 'RUNNING' state.\n // If we cannot iterate then we have hit our target iteration count, which means that the node has succeeded.\n if (this.canIterate()) {\n // This node is in the running state and can do its initial iteration.\n this.setState(State.RUNNING);\n\n // We may have already completed an iteration, meaning that the child node will be in the SUCCEEDED state.\n // If this is the case then we will have to reset the child node now.\n if (this.child.getState() === State.SUCCEEDED) {\n this.child.reset();\n }\n\n // Update the child of this node.\n this.child.update(agent, options);\n\n // If the child moved into the FAILED state when we updated it then there is nothing left to do and this node has also failed.\n // If it has moved into the SUCCEEDED state then we have completed the current iteration.\n if (this.child.getState() === State.FAILED) {\n // The child has failed, meaning that this node has failed.\n this.setState(State.FAILED);\n\n return;\n } else if (this.child.getState() === State.SUCCEEDED) {\n // We have completed an iteration.\n this.currentIterationCount += 1;\n }\n } else {\n // This node is in the 'SUCCEEDED' state as we cannot iterate any more.\n this.setState(State.SUCCEEDED);\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => {\n if (this.iterations !== null) {\n return `REPEAT ${this.iterations}x`;\n } else if (this.iterationsMin !== null && this.iterationsMax !== null) {\n return `REPEAT ${this.iterationsMin}x-${this.iterationsMax}x`;\n } else {\n return \"REPEAT\";\n }\n };\n\n /**\n * Reset the state of the node.\n */\n reset = () => {\n // Reset the state of this node.\n this.setState(State.READY);\n\n // Reset the current iteration count.\n this.currentIterationCount = 0;\n\n // Reset the child node.\n this.child.reset();\n };\n\n /**\n * Gets whether an iteration can be made.\n * @returns Whether an iteration can be made.\n */\n private canIterate = () => {\n if (this.targetIterationCount !== null) {\n // We can iterate as long as we have not reached our target iteration count.\n return this.currentIterationCount < this.targetIterationCount;\n }\n\n // If neither an iteration count or a condition function were defined then we can iterate indefinitely.\n return true;\n };\n\n /**\n * Sets the target iteration count.\n * @param options The behaviour tree options object.\n */\n private setTargetIterationCount = (options: BehaviourTreeOptions) => {\n // Are we dealing with an explicit iteration count or will we be randomly picking a iteration count between the min and max iteration count.\n if (this.iterations !== null) {\n this.targetIterationCount = this.iterations;\n } else if (this.iterationsMin !== null && this.iterationsMax !== null) {\n // We will be picking a random iteration count between a min and max iteration count, if the optional 'random'\n // behaviour tree function option is defined then we will be using that, otherwise we will fall back to using Math.random.\n const random = typeof options.random === \"function\" ? options.random : Math.random;\n\n // Pick a random iteration count between a min and max iteration count.\n this.targetIterationCount = Math.floor(\n random() * (this.iterationsMax - this.iterationsMin + 1) + this.iterationsMin\n );\n } else {\n this.targetIterationCount = null;\n }\n };\n}\n", "import Node from \"../Node\";\nimport Decorator from \"./Decorator\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A RETRY node.\n * The node has a single child which can have:\n * -- A number of iterations for which to repeat the child node.\n * -- An infinite repeat loop if neither an iteration count or a condition function is defined.\n * The RETRY node will stop and have a 'SUCCEEDED' state if its child is ever in a 'SUCCEEDED' state after an update.\n * The RETRY node will attempt to move on to the next iteration if its child is ever in a 'FAILED' state.\n */\nexport default class Retry extends Decorator {\n /**\n * @param attributes The node attributes.\n * @param attempts The number of attempts to retry the child node.\n * @param attemptsMin The minimum possible number of attempts to retry the child node.\n * @param attemptsMax The maximum possible number of attempts to retry the child node.\n * @param child The child node.\n */\n constructor(\n attributes: Attribute[],\n private attempts: number | null,\n private attemptsMin: number | null,\n private attemptsMax: number | null,\n child: Node\n ) {\n super(\"retry\", attributes, child);\n }\n\n /**\n * The number of target attempts to make.\n */\n private targetAttemptCount: number | null = null;\n\n /**\n * The current attempt count.\n */\n private currentAttemptCount: number = 0;\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // If this node is in the READY state then we need to reset the child and the target attempt count.\n if (this.is(State.READY)) {\n // Reset the child node.\n this.child.reset();\n\n // Reset the current attempt count.\n this.currentAttemptCount = 0;\n\n // Set the target attempt count.\n this.setTargetAttemptCount(options);\n }\n\n // Do a check to see if we can attempt. If we can then this node will move into the 'RUNNING' state.\n // If we cannot attempt then we have hit our target attempt count, which means that the node has succeeded.\n if (this.canAttempt()) {\n // This node is in the running state and can do its initial attempt.\n this.setState(State.RUNNING);\n\n // We may have already completed an attempt, meaning that the child node will be in the FAILED state.\n // If this is the case then we will have to reset the child node now.\n if (this.child.getState() === State.FAILED) {\n this.child.reset();\n }\n\n // Update the child of this node.\n this.child.update(agent, options);\n\n // If the child moved into the SUCCEEDED state when we updated it then there is nothing left to do and this node has also succeeded.\n // If it has moved into the FAILED state then we have completed the current attempt.\n if (this.child.getState() === State.SUCCEEDED) {\n // The child has succeeded, meaning that this node has succeeded.\n this.setState(State.SUCCEEDED);\n\n return;\n } else if (this.child.getState() === State.FAILED) {\n // We have completed an attempt.\n this.currentAttemptCount += 1;\n }\n } else {\n // This node is in the 'FAILED' state as we cannot iterate any more.\n this.setState(State.FAILED);\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => {\n if (this.attempts !== null) {\n return `RETRY ${this.attempts}x`;\n } else if (this.attemptsMin !== null && this.attemptsMax !== null) {\n return `RETRY ${this.attemptsMin}x-${this.attemptsMax}x`;\n } else {\n return \"RETRY\";\n }\n };\n\n /**\n * Reset the state of the node.\n */\n reset = () => {\n // Reset the state of this node.\n this.setState(State.READY);\n\n // Reset the current attempt count.\n this.currentAttemptCount = 0;\n\n // Reset the child node.\n this.child.reset();\n };\n\n /**\n * Gets whether an attempt can be made.\n * @returns Whether an attempt can be made.\n */\n canAttempt = () => {\n if (this.targetAttemptCount !== null) {\n // We can attempt as long as we have not reached our target attempt count.\n return this.currentAttemptCount < this.targetAttemptCount;\n }\n\n // If neither an attempt count or a condition function were defined then we can attempt indefinitely.\n return true;\n };\n\n /**\n * Sets the target attempt count.\n * @param options The behaviour tree options object.\n */\n setTargetAttemptCount = (options: BehaviourTreeOptions) => {\n // Are we dealing with an explicit attempt count or will we be randomly picking an attempt count between the min and max attempt count.\n if (this.attempts !== null) {\n this.targetAttemptCount = this.attempts;\n } else if (this.attemptsMin !== null && this.attemptsMax !== null) {\n // We will be picking a random attempt count between a min and max attempt count, if the optional 'random'\n // behaviour tree function option is defined then we will be using that, otherwise we will fall back to using Math.random.\n const random = typeof options.random === \"function\" ? options.random : Math.random;\n\n // Pick a random attempt count between a min and max attempt count.\n this.targetAttemptCount = Math.floor(\n random() * (this.attemptsMax - this.attemptsMin + 1) + this.attemptsMin\n );\n } else {\n this.targetAttemptCount = null;\n }\n };\n}\n", "import Decorator from \"./Decorator\";\nimport State from \"../../State\";\nimport Node from \"../Node\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A Flip node.\n * This node wraps a single child and will flip the state of the child state.\n */\nexport default class Flip extends Decorator {\n /**\n * @param attributes The node attributes.\n * @param child The child node.\n */\n constructor(attributes: Attribute[], child: Node) {\n super(\"flip\", attributes, child);\n }\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // If the child has never been updated or is running then we will need to update it now.\n if (this.child.getState() === State.READY || this.child.getState() === State.RUNNING) {\n this.child.update(agent, options);\n }\n\n // The state of this node will depend in the state of its child.\n switch (this.child.getState()) {\n case State.RUNNING:\n this.setState(State.RUNNING);\n break;\n\n case State.SUCCEEDED:\n this.setState(State.FAILED);\n break;\n\n case State.FAILED:\n this.setState(State.SUCCEEDED);\n break;\n\n default:\n this.setState(State.READY);\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => \"FLIP\";\n}\n", "import Node from \"../Node\";\nimport Decorator from \"./Decorator\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A Succeed node.\n * This node wraps a single child and will always move to the 'SUCCEEDED' state when the child moves to a 'SUCCEEDED' or 'FAILED' state.\n */\nexport default class Succeed extends Decorator {\n /**\n * @param attributes The node attributes.\n * @param child The child node.\n */\n constructor(attributes: Attribute[], child: Node) {\n super(\"succeed\", attributes, child);\n }\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // If the child has never been updated or is running then we will need to update it now.\n if (this.child.getState() === State.READY || this.child.getState() === State.RUNNING) {\n this.child.update(agent, options);\n }\n\n // The state of this node will depend in the state of its child.\n switch (this.child.getState()) {\n case State.RUNNING:\n this.setState(State.RUNNING);\n break;\n\n case State.SUCCEEDED:\n case State.FAILED:\n this.setState(State.SUCCEEDED);\n break;\n\n default:\n this.setState(State.READY);\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => \"SUCCEED\";\n}\n", "import Node from \"../Node\";\nimport Decorator from \"./Decorator\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A Fail node.\n * This node wraps a single child and will always move to the 'FAILED' state when the child moves to a 'SUCCEEDED' or 'FAILED' state.\n */\nexport default class Fail extends Decorator {\n /**\n * @param attributes The node attributes.\n * @param child The child node.\n */\n constructor(attributes: Attribute[], child: Node) {\n super(\"fail\", attributes, child);\n }\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // If the child has never been updated or is running then we will need to update it now.\n if (this.child.getState() === State.READY || this.child.getState() === State.RUNNING) {\n this.child.update(agent, options);\n }\n\n // The state of this node will depend in the state of its child.\n switch (this.child.getState()) {\n case State.RUNNING:\n this.setState(State.RUNNING);\n break;\n\n case State.SUCCEEDED:\n case State.FAILED:\n this.setState(State.FAILED);\n break;\n\n default:\n this.setState(State.READY);\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => \"FAIL\";\n}\n", "import createLotto from \"lotto-draw\";\n\nimport Node from \"../Node\";\nimport Composite from \"./Composite\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A LOTTO node.\n * A winning child is picked on the initial update of this node, based on ticket weighting.\n * The state of this node will match the state of the winning child.\n */\nexport default class Lotto extends Composite {\n /**\n * @param attributes The node attributes.\n * @param tickets The child node tickets.\n * @param children The child nodes.\n */\n constructor(attributes: Attribute[], private tickets: number[], children: Node[]) {\n super(\"lotto\", attributes, children);\n }\n\n /**\n * The child node selected to be the active one.\n */\n private selectedChild: Node | undefined;\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // If this node is in the READY state then we need to pick a winning child node.\n if (this.is(State.READY)) {\n // Create a lotto draw with which to randomly pick a child node to become the active one.\n const lottoDraw = createLotto({\n // Hook up the optional 'random' behaviour tree function option to the one used by 'lotto-draw'.\n random: options.random,\n // Pass in each child node as a participant in the lotto draw with their respective ticket count.\n participants: this.children.map((child, index) => [child, this.tickets[index] || 1])\n });\n\n // Randomly pick a child based on ticket weighting, this will become the active child for this composite node.\n this.selectedChild = lottoDraw.draw() || undefined;\n }\n\n // If something went wrong and we don't have an active child then we should throw an error.\n if (!this.selectedChild) {\n throw new Error(\"failed to update lotto node as it has no active child\");\n }\n\n // If the selected child has never been updated or is running then we will need to update it now.\n if (this.selectedChild.getState() === State.READY || this.selectedChild.getState() === State.RUNNING) {\n this.selectedChild.update(agent, options);\n }\n\n // The state of the lotto node is the state of its selected child.\n this.setState(this.selectedChild.getState());\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => (this.tickets.length ? `LOTTO [${this.tickets.join(\",\")}]` : \"LOTTO\");\n}\n", "import Node from \"../Node\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\n\n/**\n * A composite node that wraps child nodes.\n */\nexport default abstract class Composite extends Node {\n /**\n * @param type The node type.\n * @param attributes The node attributes.\n * @param children The child nodes.\n */\n constructor(type: string, attributes: Attribute[], protected children: Node[]) {\n super(type, attributes, []);\n }\n\n /**\n * Gets whether this node is a leaf node.\n */\n isLeafNode = () => false;\n\n /**\n * Gets the children of this node.\n */\n getChildren = () => this.children;\n\n /**\n * Reset the state of the node.\n */\n reset = () => {\n // Reset the state of this node.\n this.setState(State.READY);\n\n // Reset the state of any child nodes.\n this.getChildren().forEach((child) => child.reset());\n };\n\n /**\n * Abort the running of this node.\n * @param agent The agent.\n */\n abort = (agent: Agent) => {\n // There is nothing to do if this node is not in the running state.\n if (!this.is(State.RUNNING)) {\n return;\n }\n\n // Abort any child nodes.\n this.getChildren().forEach((child) => child.abort(agent));\n\n // Reset the state of this node.\n this.reset();\n\n this.getAttribute(\"exit\")?.callAgentFunction(agent, false, true);\n };\n}\n", "import Composite from \"./Composite\";\nimport Node from \"../Node\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A SELECTOR node.\n * The child nodes are executed in sequence until one succeeds or all fail.\n */\nexport default class Selector extends Composite {\n /**\n * @param attributes The node attributes.\n * @param children The child nodes.\n */\n constructor(attributes: Attribute[], protected children: Node[]) {\n super(\"selector\", attributes, children);\n }\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // Iterate over all of the children of this node.\n for (const child of this.children) {\n // If the child has never been updated or is running then we will need to update it now.\n if (child.getState() === State.READY || child.getState() === State.RUNNING) {\n // Update the child of this node.\n child.update(agent, options);\n }\n\n // If the current child has a state of 'SUCCEEDED' then this node is also a 'SUCCEEDED' node.\n if (child.getState() === State.SUCCEEDED) {\n // This node is a 'SUCCEEDED' node.\n this.setState(State.SUCCEEDED);\n\n // There is no need to check the rest of the selector nodes.\n return;\n }\n\n // If the current child has a state of 'FAILED' then we should move on to the next child.\n if (child.getState() === State.FAILED) {\n // Find out if the current child is the last one in the selector.\n // If it is then this sequence node has also failed.\n if (this.children.indexOf(child) === this.children.length - 1) {\n // This node is a 'FAILED' node.\n this.setState(State.FAILED);\n\n // There is no need to check the rest of the selector as we have completed it.\n return;\n } else {\n // The child node failed, try the next one.\n continue;\n }\n }\n\n // The node should be in the 'RUNNING' state.\n if (child.getState() === State.RUNNING) {\n // This node is a 'RUNNING' node.\n this.setState(State.RUNNING);\n\n // There is no need to check the rest of the selector as the current child is still running.\n return;\n }\n\n // The child node was not in an expected state.\n throw new Error(\"child node was not in an expected state.\");\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => \"SELECTOR\";\n}\n", "import Composite from \"./Composite\";\nimport Node from \"../Node\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A SEQUENCE node.\n * The child nodes are executed in sequence until one fails or all succeed.\n */\nexport default class Sequence extends Composite {\n /**\n * @param attributes The node attributes.\n * @param children The child nodes.\n */\n constructor(attributes: Attribute[], protected children: Node[]) {\n super(\"sequence\", attributes, children);\n }\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // Iterate over all of the children of this node.\n for (const child of this.children) {\n // If the child has never been updated or is running then we will need to update it now.\n if (child.getState() === State.READY || child.getState() === State.RUNNING) {\n // Update the child of this node.\n child.update(agent, options);\n }\n\n // If the current child has a state of 'SUCCEEDED' then we should move on to the next child.\n if (child.getState() === State.SUCCEEDED) {\n // Find out if the current child is the last one in the sequence.\n // If it is then this sequence node has also succeeded.\n if (this.children.indexOf(child) === this.children.length - 1) {\n // This node is a 'SUCCEEDED' node.\n this.setState(State.SUCCEEDED);\n\n // There is no need to check the rest of the sequence as we have completed it.\n return;\n } else {\n // The child node succeeded, but we have not finished the sequence yet.\n continue;\n }\n }\n\n // If the current child has a state of 'FAILED' then this node is also a 'FAILED' node.\n if (child.getState() === State.FAILED) {\n // This node is a 'FAILED' node.\n this.setState(State.FAILED);\n\n // There is no need to check the rest of the sequence.\n return;\n }\n\n // The node should be in the 'RUNNING' state.\n if (child.getState() === State.RUNNING) {\n // This node is a 'RUNNING' node.\n this.setState(State.RUNNING);\n\n // There is no need to check the rest of the sequence as the current child is still running.\n return;\n }\n\n // The child node was not in an expected state.\n throw new Error(\"child node was not in an expected state.\");\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => \"SEQUENCE\";\n}\n", "import Composite from \"./Composite\";\nimport State from \"../../State\";\nimport Node from \"../Node\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A PARALLEL node.\n * The child nodes are executed concurrently until one fails or all succeed.\n */\nexport default class Parallel extends Composite {\n /**\n * @param attributes The node attributes.\n * @param children The child nodes.\n */\n constructor(attributes: Attribute[], children: Node[]) {\n super(\"parallel\", attributes, children);\n }\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // Keep a count of the number of succeeded child nodes.\n let succeededCount = 0;\n\n let hasChildFailed = false;\n\n // Iterate over all of the children of this node.\n for (const child of this.children) {\n // If the child has never been updated or is running then we will need to update it now.\n if (child.getState() === State.READY || child.getState() === State.RUNNING) {\n // Update the child of this node.\n child.update(agent, options);\n }\n\n // If the current child has a state of 'SUCCEEDED' then we should move on to the next child.\n if (child.getState() === State.SUCCEEDED) {\n // The child node has succeeded, keep track of this to determine if all children have.\n succeededCount++;\n\n // The child node succeeded, but we have not finished checking every child node yet.\n continue;\n }\n\n // If the current child has a state of 'FAILED' then this node is also a 'FAILED' node.\n if (child.getState() === State.FAILED) {\n hasChildFailed = true;\n\n // There is no need to check the rest of the children.\n break;\n }\n\n // The node should be in the 'RUNNING' state.\n if (child.getState() !== State.RUNNING) {\n // The child node was not in an expected state.\n throw new Error(\"child node was not in an expected state.\");\n }\n }\n\n if (hasChildFailed) {\n // This node is a 'FAILED' node.\n this.setState(State.FAILED);\n\n // Abort every running child.\n for (const child of this.children) {\n if (child.getState() === State.RUNNING) {\n child.abort(agent);\n }\n }\n } else {\n // If all children have succeeded then this node has also succeeded, otherwise it is still running.\n this.setState(succeededCount === this.children.length ? State.SUCCEEDED : State.RUNNING);\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => \"PARALLEL\";\n}\n", "import { AnyArgument } from \"../RootAstNodesBuilder\";\nimport Guard from \"./guards/Guard\";\n\nexport type AttributeDetails = {\n /** The attribute type. */\n type: string;\n\n /** The attribute arguments. */\n args: AnyArgument[];\n};\n\n/**\n * A base node attribute.\n */\nexport default abstract class Attribute {\n /**\n * @param type The node attribute type.\n * @param args The array of attribute argument definitions.\n */\n constructor(protected type: string, protected args: AnyArgument[]) {}\n\n /**\n * Gets the type of the attribute.\n */\n getType = () => this.type;\n\n /**\n * Gets the array of attribute argument definitions.\n */\n getArguments = () => this.args;\n\n /**\n * Gets the attribute details.\n */\n abstract getDetails(): TAttributeDetails;\n\n /**\n * Gets whether this attribute is a guard.\n */\n abstract isGuard: () => this is Guard;\n}\n", "import { Agent } from \"../../Agent\";\nimport { AnyArgument } from \"../../RootAstNodesBuilder\";\nimport Attribute, { AttributeDetails } from \"../Attribute\";\n\nexport type GuardAttributeDetails = {\n /** The name of the condition function that determines whether the guard is satisfied. */\n condition: string;\n} & AttributeDetails;\n\n/**\n * A base node guard attribute.\n */\nexport default abstract class Guard extends Attribute {\n /**\n * @param type The node attribute type.\n * @param args The array of decorator argument definitions.\n * @param condition The name of the condition function that determines whether the guard is satisfied.\n */\n constructor(type: string, args: AnyArgument[], private condition: string) {\n super(type, args);\n }\n\n /**\n * Gets the name of the condition function that determines whether the guard is satisfied.\n */\n getCondition = () => this.condition;\n\n /**\n * Gets whether this attribute is a guard.\n */\n isGuard = () => true;\n\n /**\n * Gets the attribute details.\n */\n getDetails(): GuardAttributeDetails {\n return {\n type: this.getType(),\n args: this.getArguments(),\n condition: this.getCondition()\n };\n }\n\n /**\n * Gets whether the guard is satisfied.\n * @param agent The agent.\n * @returns Whether the guard is satisfied.\n */\n abstract isSatisfied(agent: Agent): boolean;\n}\n", "import Guard from \"./Guard\";\nimport Lookup from \"../../Lookup\";\nimport { Agent } from \"../../Agent\";\nimport { AnyArgument } from \"../../RootAstNodesBuilder\";\n\n/**\n * A WHILE guard which is satisfied as long as the given condition remains true.\n */\nexport default class While extends Guard {\n /**\n * @param condition The name of the condition function that determines whether the guard is satisfied.\n * @param args The array of decorator argument definitions.\n */\n constructor(condition: string, args: AnyArgument[]) {\n super(\"while\", args, condition);\n }\n\n /**\n * Gets whether the guard is satisfied.\n * @param agent The agent.\n * @returns Whether the guard is satisfied.\n */\n isSatisfied = (agent: Agent) => {\n // Attempt to get the invoker for the condition function.\n const conditionFuncInvoker = Lookup.getFuncInvoker(agent, this.getCondition());\n\n // The condition function should be defined.\n if (conditionFuncInvoker === null) {\n throw new Error(\n `cannot evaluate node guard as the condition '${this.getCondition()}' function is not defined on the agent and has not been registered`\n );\n }\n\n // Call the condition function to determine whether this guard is satisfied.\n return !!conditionFuncInvoker(this.args);\n };\n}\n", "import Guard from \"./Guard\";\nimport Lookup from \"../../Lookup\";\nimport { Agent } from \"../../Agent\";\nimport { AnyArgument } from \"../../RootAstNodesBuilder\";\n\n/**\n * An UNTIL guard which is satisfied as long as the given condition remains false.\n */\nexport default class Until extends Guard {\n /**\n * @param condition The name of the condition function that determines whether the guard is satisfied.\n * @param args The array of decorator argument definitions.\n */\n constructor(condition: string, args: AnyArgument[]) {\n super(\"until\", args, condition);\n }\n\n /**\n * Gets whether the guard is satisfied.\n * @param agent The agent.\n * @returns Whether the guard is satisfied.\n */\n isSatisfied = (agent: Agent) => {\n // Attempt to get the invoker for the condition function.\n const conditionFuncInvoker = Lookup.getFuncInvoker(agent, this.getCondition());\n\n // The condition function should be defined.\n if (conditionFuncInvoker === null) {\n throw new Error(\n `cannot evaluate node guard as the condition '${this.getCondition()}' function is not defined on the agent and has not been registered`\n );\n }\n\n // Call the condition function to determine whether this guard is satisfied.\n return !!!conditionFuncInvoker(this.args);\n };\n}\n", "import { Agent } from \"../../Agent\";\nimport { AnyArgument } from \"../../RootAstNodesBuilder\";\nimport Attribute, { AttributeDetails } from \"../Attribute\";\n\nexport type CallbackAttributeDetails = {\n /** The name of the agent function that is called. */\n functionName: string;\n} & AttributeDetails;\n\n/**\n * A base node callback attribute.\n */\nexport default abstract class Callback extends Attribute {\n /**\n * @param type The node attribute type.\n * @param args The array of decorator argument definitions.\n * @param functionName The name of the agent function to call.\n */\n constructor(type: string, args: AnyArgument[], private functionName: string) {\n super(type, args);\n }\n\n /**\n * Gets the name of the agent function to call.\n */\n getFunctionName = () => this.functionName;\n\n /**\n * Gets whether this attribute is a guard.\n */\n isGuard = () => false;\n\n /**\n * Gets the attribute details.\n */\n getDetails(): CallbackAttributeDetails {\n return {\n type: this.getType(),\n args: this.getArguments(),\n functionName: this.getFunctionName()\n };\n }\n\n /**\n * Attempt to call the agent function that this callback refers to.\n * @param agent The agent.\n */\n abstract callAgentFunction: (agent: Agent, isSuccess: boolean, isAborted: boolean) => void;\n}\n", "import Callback from \"./Callback\";\nimport Lookup from \"../../Lookup\";\nimport { Agent } from \"../../Agent\";\nimport { AnyArgument } from \"../../RootAstNodesBuilder\";\n\n/**\n * An ENTRY callback which defines an agent function to call when the associated node is updated and moves out of running state.\n */\nexport default class Entry extends Callback {\n /**\n * @param functionName The name of the agent function to call.\n * @param args The array of callback argument definitions.\n */\n constructor(functionName: string, args: AnyArgument[]) {\n super(\"entry\", args, functionName);\n }\n\n /**\n * Attempt to call the agent function that this callback refers to.\n * @param agent The agent.\n */\n callAgentFunction = (agent: Agent) => {\n // Attempt to get the invoker for the callback function.\n const callbackFuncInvoker = Lookup.getFuncInvoker(agent, this.getFunctionName());\n\n // The callback function should be defined.\n if (callbackFuncInvoker === null) {\n throw new Error(\n `cannot call entry function '${this.getFunctionName()}' as is not defined on the agent and has not been registered`\n );\n }\n\n // Call the callback function.\n callbackFuncInvoker(this.args);\n };\n}\n", "import Callback from \"./Callback\";\nimport Lookup, { AnyExitArgument } from \"../../Lookup\";\nimport { Agent } from \"../../Agent\";\nimport { AnyArgument } from \"../../RootAstNodesBuilder\";\n\n/**\n * An EXIT callback which defines an agent function to call when the associated node is updated and moves to a finished state or is aborted.\n */\nexport default class Exit extends Callback {\n /**\n * @param functionName The name of the agent function to call.\n * @param args The array of callback argument definitions.\n */\n constructor(functionName: string, args: AnyArgument[]) {\n super(\"exit\", args, functionName);\n }\n\n /**\n * Attempt to call the agent function that this callback refers to.\n * @param agent The agent.\n * @param isSuccess Whether the decorated node was left with a success state.\n * @param isAborted Whether the decorated node was aborted.\n */\n callAgentFunction = (agent: Agent, isSuccess: boolean, isAborted: boolean) => {\n // Attempt to get the invoker for the callback function.\n const callbackFuncInvoker = Lookup.getFuncInvoker(agent, this.getFunctionName());\n\n // The callback function should be defined.\n if (callbackFuncInvoker === null) {\n throw new Error(\n `cannot call exit function '${this.getFunctionName()}' as is not defined on the agent and has not been registered`\n );\n }\n\n // Call the callback function\n callbackFuncInvoker([{ value: { succeeded: isSuccess, aborted: isAborted } }, ...this.args]);\n };\n}\n", "import Callback from \"./Callback\";\nimport Lookup from \"../../Lookup\";\nimport { Agent } from \"../../Agent\";\nimport { AnyArgument } from \"../../RootAstNodesBuilder\";\n\n/**\n * A STEP callback which defines an agent function to call when the associated node is updated.\n */\nexport default class Step extends Callback {\n /**\n * @param functionName The name of the agent function to call.\n * @param args The array of callback argument definitions.\n */\n constructor(functionName: string, args: AnyArgument[]) {\n super(\"step\", args, functionName);\n }\n\n /**\n * Attempt to call the agent function that this callback refers to.\n * @param agent The agent.\n */\n callAgentFunction = (agent: Agent) => {\n // Attempt to get the invoker for the callback function.\n const callbackFuncInvoker = Lookup.getFuncInvoker(agent, this.getFunctionName());\n\n // The callback function should be defined.\n if (callbackFuncInvoker === null) {\n throw new Error(\n `cannot call step function '${this.getFunctionName()}' as is not defined on the agent and has not been registered`\n );\n }\n\n // Call the callback function.\n callbackFuncInvoker(this.args);\n };\n}\n", "import Action from \"./nodes/leaf/Action\";\nimport Condition from \"./nodes/leaf/Condition\";\nimport Wait from \"./nodes/leaf/Wait\";\nimport Root from \"./nodes/decorator/Root\";\nimport Repeat from \"./nodes/decorator/Repeat\";\nimport Retry from \"./nodes/decorator/Retry\";\nimport Flip from \"./nodes/decorator/Flip\";\nimport Succeed from \"./nodes/decorator/Succeed\";\nimport Fail from \"./nodes/decorator/Fail\";\nimport Lotto from \"./nodes/composite/Lotto\";\nimport Selector from \"./nodes/composite/Selector\";\nimport Sequence from \"./nodes/composite/Sequence\";\nimport Parallel from \"./nodes/composite/Parallel\";\nimport Node from \"./nodes/Node\";\nimport While from \"./attributes/guards/While\";\nimport Until from \"./attributes/guards/Until\";\nimport Entry from \"./attributes/callbacks/Entry\";\nimport Exit from \"./attributes/callbacks/Exit\";\nimport Step from \"./attributes/callbacks/Step\";\nimport Callback from \"./attributes/callbacks/Callback\";\nimport Guard from \"./attributes/guards/Guard\";\nimport Attribute from \"./attributes/Attribute\";\nimport Composite from \"./nodes/composite/Composite\";\nimport Decorator from \"./nodes/decorator/Decorator\";\nimport Leaf from \"./nodes/leaf/Leaf\";\n\nexport type Argument = {\n value: T;\n type: string; // Used for validation.\n};\ntype NullArgument = Argument & {\n type: \"null\";\n};\ntype BooleanArgument = Argument & {\n type: \"boolean\";\n};\ntype NumberArgument = Argument & {\n type: \"number\";\n isInteger: boolean; // Used for validation.\n};\ntype StringPlaceholderArgument = Argument & {\n type: \"string\";\n};\ntype IdentifierArgument = Argument & {\n type: \"identifier\";\n};\nexport type AnyArgument =\n | NullArgument\n | BooleanArgument\n | NumberArgument\n | StringPlaceholderArgument\n | IdentifierArgument;\n\n/**\n * The node attribute factories.\n */\nconst AttributeFactories: {\n [key: string]: (functionName: string, attributeArguments: AnyArgument[]) => Callback | Guard;\n} = {\n WHILE: (condition: string, attributeArguments: AnyArgument[]) => new While(condition, attributeArguments),\n UNTIL: (condition: string, attributeArguments: AnyArgument[]) => new Until(condition, attributeArguments),\n ENTRY: (functionName: string, attributeArguments: AnyArgument[]) => new Entry(functionName, attributeArguments),\n EXIT: (functionName: string, attributeArguments: AnyArgument[]) => new Exit(functionName, attributeArguments),\n STEP: (functionName: string, attributeArguments: AnyArgument[]) => new Step(functionName, attributeArguments)\n};\n\ntype Validatable = {\n children?: AstNode[];\n validate: (depth: number) => void;\n};\n\ntype NodeInstanceCreator = (\n namedRootNodeProvider: (name: string) => RootAstNode,\n visitedBranches: string[]\n) => T;\n\nexport type AstNode = Validatable & {\n type: string;\n createNodeInstance: NodeInstanceCreator;\n};\n\nexport type LeafAstNode = AstNode & {\n type: \"action\" | \"condition\" | \"wait\";\n attributes: Attribute[];\n};\n\nexport type CompositeAstNode = AstNode & {\n type: \"lotto\" | \"parallel\" | \"selector\" | \"sequence\";\n attributes: Attribute[];\n children: AstNode[];\n};\n\nexport type DecoratorAstNode = AstNode & {\n type: \"fail\" | \"flip\" | \"repeat\" | \"retry\" | \"root\" | \"succeed\";\n attributes: Attribute[];\n children: AstNode[];\n};\n\nexport type BranchAstNode = AstNode & {\n type: \"branch\";\n branchName: \"\" | string;\n};\n\nexport type LottoAstNode = CompositeAstNode & {\n type: \"lotto\";\n tickets: number[];\n};\n\nexport type RootAstNode = DecoratorAstNode & {\n type: \"root\";\n name: null | string;\n};\n\nexport type RepeatAstNode = DecoratorAstNode & {\n type: \"repeat\";\n iterations: number | null;\n iterationsMin: number | null;\n iterationsMax: number | null;\n};\n\nexport type RetryAstNode = DecoratorAstNode & {\n type: \"retry\";\n attempts: number | null;\n attemptsMin: number | null;\n attemptsMax: number | null;\n};\n\nexport type ActionAstNode = LeafAstNode & {\n type: \"action\";\n actionName: string;\n actionArguments: AnyArgument[];\n};\n\nexport type ConditionAstNode = LeafAstNode & {\n type: \"condition\";\n conditionName: string;\n conditionArguments: AnyArgument[];\n};\n\nexport type WaitAstNode = LeafAstNode & {\n type: \"wait\";\n duration: number | null;\n durationMin: number | null;\n durationMax: number | null;\n};\n\nexport type AnyAstNode =\n | BranchAstNode\n | CompositeAstNode\n | LottoAstNode\n | DecoratorAstNode\n | RootAstNode\n | RepeatAstNode\n | RetryAstNode\n | LeafAstNode\n | ActionAstNode\n | ConditionAstNode\n | WaitAstNode;\n\n/**\n * The AST node factories.\n */\nconst ASTNodeFactories = {\n ROOT: (): RootAstNode => ({\n type: \"root\",\n attributes: [],\n name: null,\n children: [],\n validate(depth: number) {\n // A root node cannot be the child of another node.\n if (depth > 1) {\n throw new Error(\"a root node cannot be the child of another node\");\n }\n\n // A root node must have a single child node.\n if (this.children.length !== 1) {\n throw new Error(\"a root node must have a single child\");\n }\n },\n createNodeInstance(namedRootNodeProvider, visitedBranches) {\n return new Root(\n this.attributes,\n this.children![0].createNodeInstance(namedRootNodeProvider, visitedBranches.slice())\n );\n }\n }),\n BRANCH: (): BranchAstNode => ({\n type: \"branch\",\n branchName: \"\",\n validate() {},\n createNodeInstance(namedRootNodeProvider, visitedBranches) {\n // Try to find the root node with a matching branch name.\n const targetRootNode = namedRootNodeProvider(this.branchName);\n\n // If we have already visited this branch then we have a circular dependency.\n if (visitedBranches.indexOf(this.branchName) !== -1) {\n throw new Error(`circular dependency found in branch node references for branch '${this.branchName}'`);\n }\n\n // If we have a target root node, then the node instance we want will be the first and only child of the referenced root node.\n if (targetRootNode) {\n return targetRootNode\n .createNodeInstance(namedRootNodeProvider, visitedBranches.concat(this.branchName))\n .getChildren()[0];\n } else {\n throw new Error(`branch references root node '${this.branchName}' which has not been defined`);\n }\n }\n }),\n SELECTOR: (): CompositeAstNode => ({\n type: \"selector\",\n attributes: [],\n children: [],\n validate() {\n // A selector node must have at least a single node.\n if (this.children.length < 1) {\n throw new Error(\"a selector node must have at least a single child\");\n }\n },\n createNodeInstance(namedRootNodeProvider, visitedBranches) {\n return new Selector(\n this.attributes,\n this.children.map((child) => child.createNodeInstance(namedRootNodeProvider, visitedBranches.slice()))\n );\n }\n }),\n SEQUENCE: (): CompositeAstNode => ({\n type: \"sequence\",\n attributes: [],\n children: [],\n validate() {\n // A sequence node must have at least a single node.\n if (this.children.length < 1) {\n throw new Error(\"a sequence node must have at least a single child\");\n }\n },\n createNodeInstance(namedRootNodeProvider, visitedBranches) {\n return new Sequence(\n this.attributes,\n this.children.map((child) => child.createNodeInstance(namedRootNodeProvider, visitedBranches.slice()))\n );\n }\n }),\n PARALLEL: (): CompositeAstNode => ({\n type: \"parallel\",\n attributes: [],\n children: [],\n validate() {\n // A parallel node must have at least a single node.\n if (this.children.length < 1) {\n throw new Error(\"a parallel node must have at least a single child\");\n }\n },\n createNodeInstance(namedRootNodeProvider, visitedBranches) {\n return new Parallel(\n this.attributes,\n this.children.map((child) => child.createNodeInstance(namedRootNodeProvider, visitedBranches.slice()))\n );\n }\n }),\n LOTTO: (): LottoAstNode => ({\n type: \"lotto\",\n attributes: [],\n children: [],\n tickets: [],\n validate() {\n // A lotto node must have at least a single node.\n if (this.children!.length < 1) {\n throw new Error(\"a lotto node must have at least a single child\");\n }\n },\n createNodeInstance(namedRootNodeProvider, visitedBranches) {\n return new Lotto(\n this.attributes,\n this.tickets!,\n this.children!.map((child) => child.createNodeInstance(namedRootNodeProvider, visitedBranches.slice()))\n );\n }\n }),\n REPEAT: (): RepeatAstNode => ({\n type: \"repeat\",\n attributes: [],\n iterations: null,\n iterationsMin: null,\n iterationsMax: null,\n children: [],\n validate() {\n // A repeat node must have a single node.\n if (this.children!.length !== 1) {\n throw new Error(\"a repeat node must have a single child\");\n }\n\n if (this.iterations !== null) {\n // A repeat node must have a positive number of iterations if defined.\n if (this.iterations < 0) {\n throw new Error(\"a repeat node must have a positive number of iterations if defined\");\n }\n } else if (this.iterationsMin !== null && this.iterationsMax !== null) {\n // A repeat node must have a positive min and max iteration count if they are defined.\n if (this.iterationsMin < 0 || this.iterationsMax < 0) {\n throw new Error(\n \"a repeat node must have a positive minimum and maximum iteration count if defined\"\n );\n }\n\n // A repeat node must not have an minimum iteration count that exceeds the maximum iteration count.\n if (this.iterationsMin > this.iterationsMax) {\n throw new Error(\n \"a repeat node must not have a minimum iteration count that exceeds the maximum iteration count\"\n );\n }\n } else {\n // If we have no explicit iteration count or a minimum and maximum iteration count set then we are dealing with a repeat node that iterates indefinitely.\n }\n },\n createNodeInstance(namedRootNodeProvider, visitedBranches) {\n return new Repeat(\n this.attributes,\n this.iterations,\n this.iterationsMin,\n this.iterationsMax,\n this.children![0].createNodeInstance(namedRootNodeProvider, visitedBranches.slice())\n );\n }\n }),\n RETRY: (): RetryAstNode => ({\n type: \"retry\",\n attributes: [],\n attempts: null,\n attemptsMin: null,\n attemptsMax: null,\n children: [],\n validate() {\n // A retry node must have a single node.\n if (this.children!.length !== 1) {\n throw new Error(\"a retry node must have a single child\");\n }\n\n if (this.attempts !== null) {\n // A retry node must have a positive number of attempts if defined.\n if (this.attempts < 0) {\n throw new Error(\"a retry node must have a positive number of attempts if defined\");\n }\n } else if (this.attemptsMin !== null && this.attemptsMax !== null) {\n // A retry node must have a positive min and max attempts count if they are defined.\n if (this.attemptsMin < 0 || this.attemptsMax < 0) {\n throw new Error(\"a retry node must have a positive minimum and maximum attempt count if defined\");\n }\n\n // A retry node must not have a minimum attempt count that exceeds the maximum attempt count.\n if (this.attemptsMin > this.attemptsMax) {\n throw new Error(\n \"a retry node must not have a minimum attempt count that exceeds the maximum attempt count\"\n );\n }\n } else {\n // If we have no explicit attempt count or a minimum and maximum attempt count set then we are dealing with a retry node that attempts indefinitely.\n }\n },\n createNodeInstance(namedRootNodeProvider, visitedBranches) {\n return new Retry(\n this.attributes,\n this.attempts,\n this.attemptsMin,\n this.attemptsMax,\n this.children![0].createNodeInstance(namedRootNodeProvider, visitedBranches.slice())\n );\n }\n }),\n FLIP: (): DecoratorAstNode => ({\n type: \"flip\",\n attributes: [],\n children: [],\n validate() {\n // A flip node must have a single node.\n if (this.children!.length !== 1) {\n throw new Error(\"a flip node must have a single child\");\n }\n },\n createNodeInstance(namedRootNodeProvider, visitedBranches) {\n return new Flip(\n this.attributes,\n this.children![0].createNodeInstance(namedRootNodeProvider, visitedBranches.slice())\n );\n }\n }),\n SUCCEED: (): DecoratorAstNode => ({\n type: \"succeed\",\n attributes: [],\n children: [],\n validate() {\n // A succeed node must have a single node.\n if (this.children!.length !== 1) {\n throw new Error(\"a succeed node must have a single child\");\n }\n },\n createNodeInstance(namedRootNodeProvider, visitedBranches) {\n return new Succeed(\n this.attributes,\n this.children![0].createNodeInstance(namedRootNodeProvider, visitedBranches.slice())\n );\n }\n }),\n FAIL: (): DecoratorAstNode => ({\n type: \"fail\",\n attributes: [],\n children: [],\n validate() {\n // A fail node must have a single node.\n if (this.children!.length !== 1) {\n throw new Error(\"a fail node must have a single child\");\n }\n },\n createNodeInstance(namedRootNodeProvider, visitedBranches) {\n return new Fail(\n this.attributes,\n this.children![0].createNodeInstance(namedRootNodeProvider, visitedBranches.slice())\n );\n }\n }),\n WAIT: (): WaitAstNode => ({\n type: \"wait\",\n attributes: [],\n duration: null,\n durationMin: null,\n durationMax: null,\n validate() {\n if (this.duration !== null) {\n // If an explict duration was defined then it must be a positive number.\n if (this.duration < 0) {\n throw new Error(\"a wait node must have a positive duration\");\n }\n } else if (this.durationMin !== null && this.durationMax !== null) {\n // A wait node must have a positive min and max duration.\n if (this.durationMin < 0 || this.durationMax < 0) {\n throw new Error(\"a wait node must have a positive minimum and maximum duration\");\n }\n\n // A wait node must not have a minimum duration that exceeds the maximum duration.\n if (this.durationMin > this.durationMax) {\n throw new Error(\"a wait node must not have a minimum duration that exceeds the maximum duration\");\n }\n } else {\n // If we have no explicit duration or duration bounds set then we are dealing with a wait node that waits indefinitely.\n }\n },\n createNodeInstance() {\n return new Wait(this.attributes, this.duration, this.durationMin, this.durationMax);\n }\n }),\n ACTION: (): ActionAstNode => ({\n type: \"action\",\n attributes: [],\n actionName: \"\",\n actionArguments: [],\n validate() {},\n createNodeInstance() {\n return new Action(this.attributes, this.actionName!, this.actionArguments!);\n }\n }),\n CONDITION: (): ConditionAstNode => ({\n type: \"condition\",\n attributes: [],\n conditionName: \"\",\n conditionArguments: [],\n validate() {},\n createNodeInstance() {\n return new Condition(this.attributes, this.conditionName!, this.conditionArguments!);\n }\n })\n};\n\ntype OtherAstNodes = AstNode[];\n\n/**\n * Create an array of root AST nodes based on the given definition.\n * @param definition The definition to parse the AST nodes from.\n * @returns The base definition AST nodes.\n */\nexport default function buildRootASTNodes(definition: string): RootAstNode[] {\n // Swap out any node/attribute argument string literals with a placeholder and get a mapping of placeholders to original values as well as the processed definition.\n const { placeholders, processedDefinition } = substituteStringLiterals(definition);\n\n // Convert the processed definition (with substituted string literals) into an array of raw tokens.\n const tokens = parseTokensFromDefinition(processedDefinition);\n\n // There must be at least 3 tokens for the tree definition to be valid. 'ROOT', '{' and '}'.\n if (tokens.length < 3) {\n throw new Error(\"invalid token count\");\n }\n\n // We should have a matching number of '{' and '}' tokens. If not, then there are scopes that have not been properly closed.\n if (tokens.filter((token) => token === \"{\").length !== tokens.filter((token) => token === \"}\").length) {\n throw new Error(\"scope character mismatch\");\n }\n\n // Create a stack of node children arrays, starting with a definition scope.\n const stack: [RootAstNode[], ...OtherAstNodes[]] = [[]];\n const rootScope = stack[0];\n\n // We should keep processing the raw tokens until we run out of them.\n while (tokens.length) {\n // Grab the next token.\n const token = tokens.shift();\n\n const currentScope = stack[stack.length - 1] as OtherAstNodes;\n\n // How we create the next AST token depends on the current raw token value.\n switch (token!.toUpperCase()) {\n case \"ROOT\": {\n // Create a ROOT AST node.\n const node = ASTNodeFactories.ROOT();\n\n // Push the ROOT node into the current scope.\n rootScope.push(node);\n\n // We may have a root node name defined as an argument.\n if (tokens[0] === \"[\") {\n const rootArguments = getArguments(tokens, placeholders);\n\n // We should have only a single argument that is not an empty string for a root node, which is the root name identifier.\n if (rootArguments.length === 1 && rootArguments[0].type === \"identifier\") {\n // The root name will be the first and only node argument.\n node.name = rootArguments[0].value as string;\n } else {\n throw new Error(\"expected single root name argument\");\n }\n }\n\n // Try to pick any attributes off of the token stack.\n node.attributes = getAttributes(tokens, placeholders);\n\n popAndCheck(tokens, \"{\");\n\n // The new scope is that of the new ROOT nodes children.\n stack.push(node.children!);\n break;\n }\n\n case \"BRANCH\": {\n // Create a BRANCH AST node.\n const node = ASTNodeFactories.BRANCH();\n\n // Push the BRANCH node into the current scope.\n currentScope.push(node);\n\n // We must have arguments defined, as we require a branch name argument.\n if (tokens[0] !== \"[\") {\n throw new Error(\"expected single branch name argument\");\n }\n\n // The branch name will be defined as a node argument.\n const branchArguments = getArguments(tokens, placeholders);\n\n // We should have only a single identifer argument for a branch node, which is the branch name.\n if (branchArguments.length === 1 && branchArguments[0].type === \"identifier\") {\n // The branch name will be the first and only node argument.\n node.branchName = branchArguments[0].value as string;\n } else {\n throw new Error(\"expected single branch name argument\");\n }\n break;\n }\n\n case \"SELECTOR\": {\n // Create a SELECTOR AST node.\n const node = ASTNodeFactories.SELECTOR();\n\n // Push the SELECTOR node into the current scope.\n currentScope.push(node);\n\n // Try to pick any attributes off of the token stack.\n node.attributes = getAttributes(tokens, placeholders);\n\n popAndCheck(tokens, \"{\");\n\n // The new scope is that of the new SELECTOR nodes children.\n stack.push(node.children!);\n break;\n }\n\n case \"SEQUENCE\": {\n // Create a SEQUENCE AST node.\n const node = ASTNodeFactories.SEQUENCE();\n\n // Push the SEQUENCE node into the current scope.\n currentScope.push(node);\n\n // Try to pick any attributes off of the token stack.\n node.attributes = getAttributes(tokens, placeholders);\n\n popAndCheck(tokens, \"{\");\n\n // The new scope is that of the new SEQUENCE nodes children.\n stack.push(node.children!);\n break;\n }\n\n case \"PARALLEL\": {\n // Create a PARALLEL AST node.\n const node = ASTNodeFactories.PARALLEL();\n\n // Push the PARALLEL node into the current scope.\n currentScope.push(node);\n\n // Try to pick any attributes off of the token stack.\n node.attributes = getAttributes(tokens, placeholders);\n\n popAndCheck(tokens, \"{\");\n\n // The new scope is that of the new PARALLEL nodes children.\n stack.push(node.children!);\n break;\n }\n\n case \"LOTTO\": {\n // Create a LOTTO AST node.\n const node = ASTNodeFactories.LOTTO();\n\n // Push the LOTTO node into the current scope.\n currentScope.push(node);\n\n // If the next token is a '[' character then some ticket counts have been defined as arguments.\n if (tokens[0] === \"[\") {\n // Get the ticket count arguments, each argument must be a number.\n node.tickets = getArguments(\n tokens,\n placeholders,\n (arg) => arg.type === \"number\" && !!arg.isInteger,\n \"lotto node ticket counts must be integer values\"\n ).map((argument) => argument.value as number);\n }\n\n // Try to pick any attributes off of the token stack.\n node.attributes = getAttributes(tokens, placeholders);\n\n popAndCheck(tokens, \"{\");\n\n // The new scope is that of the new LOTTO nodes children.\n stack.push(node.children!);\n break;\n }\n\n case \"CONDITION\": {\n // Create a CONDITION AST node.\n const node = ASTNodeFactories.CONDITION();\n\n // Push the CONDITION node into the current scope.\n currentScope.push(node);\n\n // We must have arguments defined, as we require a condition function name argument.\n if (tokens[0] !== \"[\") {\n throw new Error(\"expected condition name identifier argument\");\n }\n\n // Grab the condition node arguments.\n const conditionArguments = getArguments(tokens, placeholders);\n\n // We should have at least a single identifier argument for a condition node, which is the condition function name.\n if (conditionArguments.length && conditionArguments[0].type === \"identifier\") {\n // The condition function name will be the first node argument.\n node.conditionName = conditionArguments.shift()!.value as string;\n } else {\n throw new Error(\"expected condition name identifier argument\");\n }\n\n // Only the first argument should have been an identifier, all following arguments must be string, number, boolean or null.\n conditionArguments\n .filter((arg) => arg.type === \"identifier\")\n .forEach((arg) => {\n throw new Error(\n \"invalid condition node argument value '\" +\n arg.value +\n \"', must be string, number, boolean or null\"\n );\n });\n\n // Any node arguments that follow the condition name identifier will be treated as condition function arguments.\n node.conditionArguments = conditionArguments;\n\n // Try to pick any attributes off of the token stack.\n node.attributes = getAttributes(tokens, placeholders);\n break;\n }\n\n case \"FLIP\": {\n // Create a FLIP AST node.\n const node = ASTNodeFactories.FLIP();\n\n // Push the Flip node into the current scope.\n currentScope.push(node);\n\n // Try to pick any attributes off of the token stack.\n node.attributes = getAttributes(tokens, placeholders);\n\n popAndCheck(tokens, \"{\");\n\n // The new scope is that of the new FLIP nodes children.\n stack.push(node.children!);\n break;\n }\n\n case \"SUCCEED\": {\n // Create a SUCCEED AST node.\n const node = ASTNodeFactories.SUCCEED();\n\n // Push the Succeed node into the current scope.\n currentScope.push(node);\n\n // Try to pick any attributes off of the token stack.\n node.attributes = getAttributes(tokens, placeholders);\n\n popAndCheck(tokens, \"{\");\n\n // The new scope is that of the new Succeed nodes children.\n stack.push(node.children!);\n break;\n }\n\n case \"FAIL\": {\n // Create a FAIL AST node.\n const node = ASTNodeFactories.FAIL();\n\n // Push the Fail node into the current scope.\n currentScope.push(node);\n\n // Try to pick any attributes off of the token stack.\n node.attributes = getAttributes(tokens, placeholders);\n\n popAndCheck(tokens, \"{\");\n\n // The new scope is that of the new Fail nodes children.\n stack.push(node.children!);\n break;\n }\n\n case \"WAIT\": {\n // Create a WAIT AST node.\n const node = ASTNodeFactories.WAIT();\n\n // Push the WAIT node into the current scope.\n currentScope.push(node);\n\n // The arguments of a wait node are optional. We may have:\n // - No node arguments, in which case the wait will be indefinite until it is aborted.\n // - One node argument which will be the explicit duration of the wait.\n // - Two node arguments which define the min and max duration bounds from which a random duration will be picked.\n if (tokens[0] === \"[\") {\n // Get the optional duration and longest duration of the wait.\n const nodeArguments = getArguments(\n tokens,\n placeholders,\n (arg) => arg.type === \"number\" && !!arg.isInteger,\n \"wait node durations must be integer values\"\n ).map((argument) => argument.value);\n\n // We may have:\n // - One node argument which will be the explicit duration of the wait.\n // - Two node arguments which define the min and max duration bounds from which a random duration will be picked.\n // - Too many arguments, which is not valid.\n if (nodeArguments.length === 1) {\n // An explicit duration was defined.\n node.duration = nodeArguments[0] as number;\n } else if (nodeArguments.length === 2) {\n // Min and max duration bounds were defined from which a random duration will be picked.\n node.durationMin = nodeArguments[0] as number;\n node.durationMax = nodeArguments[1] as number;\n } else if (nodeArguments.length > 2) {\n // An incorrect number of durations was defined.\n throw new Error(\"invalid number of wait node duration arguments defined\");\n }\n }\n\n // Try to pick any attributes off of the token stack.\n node.attributes = getAttributes(tokens, placeholders);\n break;\n }\n\n case \"REPEAT\": {\n // Create a REPEAT AST node.\n const node = ASTNodeFactories.REPEAT();\n\n // Push the REPEAT node into the current scope.\n currentScope.push(node);\n\n // The arguments of a repeat node are optional. We may have:\n // - No node arguments, in which case the repeat note will iterate indefinitely.\n // - One node argument which will be the explicit number of iterations to make.\n // - Two node arguments which define the min and max iteration bounds from which a random iteration count will be picked.\n if (tokens[0] === \"[\") {\n // An iteration count has been defined. Get the iteration and potential maximum iteration of the wait.\n const nodeArguments = getArguments(\n tokens,\n placeholders,\n (arg) => arg.type === \"number\" && !!arg.isInteger,\n \"repeat node iteration counts must be integer values\"\n ).map((argument) => argument.value);\n\n // We should have got one or two iteration counts.\n if (nodeArguments.length === 1) {\n // A static iteration count was defined.\n node.iterations = nodeArguments[0] as number;\n } else if (nodeArguments.length === 2) {\n // A minimum and maximum iteration count was defined.\n node.iterationsMin = nodeArguments[0] as number;\n node.iterationsMax = nodeArguments[1] as number;\n } else {\n // An incorrect number of iteration counts was defined.\n throw new Error(\"invalid number of repeat node iteration count arguments defined\");\n }\n }\n\n // Try to pick any attributes off of the token stack.\n node.attributes = getAttributes(tokens, placeholders);\n\n popAndCheck(tokens, \"{\");\n\n // The new scope is that of the new REPEAT nodes children.\n stack.push(node.children!);\n break;\n }\n\n case \"RETRY\": {\n // Create a RETRY AST node.\n const node = ASTNodeFactories.RETRY();\n\n // Push the RETRY node into the current scope.\n currentScope.push(node);\n\n // The arguments of a retry node are optional. We may have:\n // - No node arguments, in which case the retry note will attempt indefinitely.\n // - One node argument which will be the explicit number of attempts to make.\n // - Two node arguments which define the min and max attempt bounds from which a random attempt count will be picked.\n if (tokens[0] === \"[\") {\n // An attempt count has been defined. Get the attempt count and potential maximum attempt count of the wait.\n const nodeArguments = getArguments(\n tokens,\n placeholders,\n (arg) => arg.type === \"number\" && !!arg.isInteger,\n \"retry node attempt counts must be integer values\"\n ).map((argument) => argument.value);\n\n // We should have got one or two attempt counts.\n if (nodeArguments.length === 1) {\n // A static attempt count was defined.\n node.attempts = nodeArguments[0] as number;\n } else if (nodeArguments.length === 2) {\n // A minimum and maximum attempt count was defined.\n node.attemptsMin = nodeArguments[0] as number;\n node.attemptsMax = nodeArguments[1] as number;\n } else {\n // An incorrect number of attempt counts was defined.\n throw new Error(\"invalid number of retry node attempt count arguments defined\");\n }\n }\n\n // Try to pick any attributes off of the token stack.\n node.attributes = getAttributes(tokens, placeholders);\n\n popAndCheck(tokens, \"{\");\n\n // The new scope is that of the new RETRY nodes children.\n stack.push(node.children!);\n break;\n }\n\n case \"ACTION\": {\n // Create a ACTION AST node.\n const node = ASTNodeFactories.ACTION();\n\n // Push the ACTION node into the current scope.\n currentScope.push(node);\n\n // We must have arguments defined, as we require an action name argument.\n if (tokens[0] !== \"[\") {\n throw new Error(\"expected action name identifier argument\");\n }\n\n // The action name will be defined as a node argument.\n const actionArguments = getArguments(tokens, placeholders);\n\n // We should have at least one identifer argument for an action node, which is the action name.\n if (actionArguments.length && actionArguments[0].type === \"identifier\") {\n // The action name will be the first and only node argument.\n node.actionName = actionArguments.shift()!.value as string;\n } else {\n throw new Error(\"expected action name identifier argument\");\n }\n\n // Only the first argument should have been an identifier, all following arguments must be string, number, boolean or null.\n actionArguments\n .filter((arg) => arg.type === \"identifier\")\n .forEach((arg) => {\n throw new Error(\n \"invalid action node argument value '\" +\n arg.value +\n \"', must be string, number, boolean or null\"\n );\n });\n\n // Any node arguments that follow the action name identifier will be treated as action function arguments.\n node.actionArguments = actionArguments;\n\n // Try to pick any attributes off of the token stack.\n node.attributes = getAttributes(tokens, placeholders);\n break;\n }\n\n case \"}\": {\n // The '}' character closes the current scope.\n stack.pop();\n break;\n }\n\n default: {\n throw new Error(`unexpected token '${token}'`);\n }\n }\n }\n\n // A function to recursively validate each of the nodes in the AST.\n const validateASTNode = (node: Validatable, depth: number): void => {\n // Validate the node.\n node.validate(depth);\n\n // Validate each child of the node.\n (node.children || []).forEach((child) => validateASTNode(child, depth + 1));\n };\n\n // Start node validation from the definition root.\n validateASTNode(\n {\n children: stack[0] as RootAstNode[],\n validate(this: { children: RootAstNode[] }) {\n // We must have at least one node defined as the definition scope, which should be a root node.\n if (this.children.length === 0) {\n throw new Error(\"expected root node to have been defined\");\n }\n\n // Each node at the base of the definition scope MUST be a root node.\n for (const definitionLevelNode of this.children) {\n if (definitionLevelNode.type !== \"root\") {\n throw new Error(\"expected root node at base of definition\");\n }\n }\n\n // Exactly one root node must not have a name defined. This will be the main root, others will have to be referenced via branch nodes.\n if (this.children.filter((definitionLevelNode) => definitionLevelNode.name === null).length !== 1) {\n throw new Error(\"expected single unnamed root node at base of definition to act as main root\");\n }\n\n // No two named root nodes can have matching names.\n const rootNodeNames: string[] = [];\n for (const definitionLevelNode of this.children) {\n if (rootNodeNames.indexOf(definitionLevelNode.name!) !== -1) {\n throw new Error(`multiple root nodes found with duplicate name '${definitionLevelNode.name}'`);\n } else {\n rootNodeNames.push(definitionLevelNode.name!);\n }\n }\n }\n },\n 0\n );\n\n // Return the root AST nodes.\n return stack[0];\n}\n\n/**\n * Pop the next raw token off of the stack and throw an error if it wasn't the expected one.\n * @param tokens The array of remaining tokens.\n * @param expected An optional string or array or items, one of which must match the next popped token.\n * @returns The popped token.\n */\nfunction popAndCheck(tokens: string[], expected: string | string[]) {\n // Get and remove the next token.\n const popped = tokens.shift();\n\n // We were expecting another token.\n if (popped === undefined) {\n throw new Error(\"unexpected end of definition\");\n }\n\n // Do we have an expected token/tokens array?\n if (expected !== undefined) {\n // Check whether the popped token matches at least one of our expected items.\n var tokenMatchesExpectation = ([] as string[])\n .concat(expected)\n .some((item) => popped.toUpperCase() === item.toUpperCase());\n\n // Throw an error if the popped token didn't match any of our expected items.\n if (!tokenMatchesExpectation) {\n const expectationString = ([] as string[])\n .concat(expected)\n .map((item) => \"'\" + item + \"'\")\n .join(\" or \");\n\n throw new Error(`unexpected token found. Expected '${expectationString}' but got '${popped}'`);\n }\n }\n\n // Return the popped token.\n return popped;\n}\n\ntype StringPlaceholders = { [key: string]: string };\n\n/**\n * Pull an argument definition list off of the token stack.\n * @param tokens The array of remaining tokens.\n * @param stringArgumentPlaceholders The mapping of string literal node argument placeholders to original values.\n * @param argumentValidator The argument validator function.\n * @param validationFailedMessage The exception message to throw if argument validation fails.\n * @returns The argument definition list.\n */\nfunction getArguments(\n tokens: string[],\n stringArgumentPlaceholders: StringPlaceholders,\n argumentValidator?: (arg: AnyArgument) => boolean,\n validationFailedMessage?: string\n) {\n // Any lists of arguments will always be wrapped in '[]' for node arguments or '()' for attribute arguments.\n // We are looking for a '[' or '(' opener that wraps the argument tokens and the relevant closer.\n const closer = popAndCheck(tokens, [\"[\", \"(\"]) === \"[\" ? \"]\" : \")\";\n\n const argumentListTokens: string[] = [];\n const argumentList: AnyArgument[] = [];\n\n // Grab all tokens between the '[' and ']' or '(' and ')'.\n while (tokens.length && tokens[0] !== closer) {\n // The next token is part of our arguments list.\n argumentListTokens.push(tokens.shift()!);\n }\n\n // Validate the order of the argument tokens. Each token must either be a ',' or a single argument that satisfies the validator.\n argumentListTokens.forEach((token, index) => {\n // Get whether this token should be an actual argument.\n const shouldBeArgumentToken = !(index & 1);\n\n // If the current token should be an actual argument then validate it,otherwise it should be a ',' token.\n if (shouldBeArgumentToken) {\n // Get the argument definition.\n const argumentDefinition = getArgumentDefinition(token!, stringArgumentPlaceholders);\n\n // Try to validate the argument.\n if (argumentValidator && !argumentValidator(argumentDefinition)) {\n throw new Error(validationFailedMessage);\n }\n\n // This is a valid argument!\n argumentList.push(argumentDefinition);\n } else {\n // The current token should be a ',' token.\n if (token !== \",\") {\n throw new Error(`invalid argument list, expected ',' or ']' but got '${token}'`);\n }\n }\n });\n\n // The arguments list should terminate with a ']' or ')' token, depending on the opener.\n popAndCheck(tokens, closer);\n\n // Return the argument list.\n return argumentList;\n}\n\n/**\n * Gets an argument value definition.\n * @param token The argument token.\n * @param stringArgumentPlaceholders The mapping of string literal node argument placeholders to original values.\n * @returns An argument value definition.\n */\nfunction getArgumentDefinition(token: string, stringArgumentPlaceholders: StringPlaceholders): AnyArgument {\n // Check whether the token represents a null value.\n if (token === \"null\") {\n return {\n value: null,\n type: \"null\"\n } as NullArgument;\n }\n\n // Check whether the token represents a boolean value.\n if (token === \"true\" || token === \"false\") {\n return {\n value: token === \"true\",\n type: \"boolean\"\n } as BooleanArgument;\n }\n\n // Check whether the token represents a number value.\n // TODO: Relies on broken isNaN - see MDN.\n // if (!Number.isNaN(token)) {\n if (!isNaN(token as any)) {\n return {\n value: parseFloat(token),\n isInteger: parseFloat(token) === parseInt(token, 10),\n type: \"number\"\n } as NumberArgument;\n }\n\n // Check whether the token is a placeholder (e.g. @@0@@) representing a string literal.\n if (token.match(/^@@\\d+@@$/g)) {\n return {\n value: stringArgumentPlaceholders[token].replace('\\\\\"', '\"'),\n type: \"string\"\n } as StringPlaceholderArgument;\n }\n\n // The only remaining option is that the argument value is an identifier.\n return {\n value: token,\n type: \"identifier\"\n } as IdentifierArgument;\n}\n\n/**\n * Pull any attributes off of the token stack.\n * @param tokens The array of remaining tokens.\n * @param stringArgumentPlaceholders The mapping of string literal node argument placeholders to original values.\n * @returns An array of attributes defined by any directly following tokens.\n */\nfunction getAttributes(tokens: string[], stringArgumentPlaceholders: StringPlaceholders) {\n // Create an array to hold any attributes found.\n const attributes: Attribute[] = [];\n\n // Keep track of names of attribute that we have found on the token stack, as we cannot have duplicates.\n const attributesFound: string[] = [];\n\n // Try to get the attribute factory for the next token.\n let attributeFactory = AttributeFactories[(tokens[0] || \"\").toUpperCase()];\n\n // Pull attribute tokens off of the tokens stack until we have no more.\n while (attributeFactory) {\n // Check to make sure that we have not already created a attribute of this type for this node.\n if (attributesFound.indexOf(tokens[0].toUpperCase()) !== -1) {\n throw new Error(`duplicate attribute '${tokens[0].toUpperCase()}' found for node`);\n }\n\n // Add the current attribute type to our array of found attributes.\n attributesFound.push(tokens.shift()!.toUpperCase());\n\n // Grab any attribute arguments.\n const attributeArguments = getArguments(tokens, stringArgumentPlaceholders);\n\n // The first attribute argument has to be an identifer, this will reference an agent function.\n if (attributeArguments.length === 0 || attributeArguments[0].type !== \"identifier\") {\n throw new Error(\"expected agent function name identifier argument for attribute\");\n }\n\n // Grab the first attribute which is an identifier that will reference an agent function.\n const attributeFunctionName = attributeArguments.shift()! as IdentifierArgument;\n\n // Any remaining attribute arguments must have a type of string, number, boolean or null.\n attributeArguments\n .filter((arg) => arg.type === \"identifier\")\n .forEach((arg) => {\n throw new Error(\n \"invalid attribute argument value '\" + arg.value + \"', must be string, number, boolean or null\"\n );\n });\n\n // Create the attribute and add it to the array of attributes found.\n attributes.push(attributeFactory(attributeFunctionName.value, attributeArguments));\n\n // Try to get the next attribute name token, as there could be multiple.\n attributeFactory = AttributeFactories[(tokens[0] || \"\").toUpperCase()];\n }\n\n return attributes;\n}\n\n/**\n * Swaps out any node/attribute argument string literals with placeholders.\n * @param definition The definition.\n * @returns An object containing a mapping of placeholders to original string values as well as the processed definition string.\n */\nfunction substituteStringLiterals(definition: string): {\n placeholders: { [key: string]: string };\n processedDefinition: string;\n} {\n // Create an object to hold the mapping of placeholders to original string values.\n const placeholders: StringPlaceholders = {};\n\n // Replace any string literals wrapped with double quotes in our definition with placeholders to be processed later.\n const processedDefinition = definition.replace(/\\\"(\\\\.|[^\"\\\\])*\\\"/g, (match) => {\n var strippedMatch = match.substring(1, match.length - 1);\n var placeholder = Object.keys(placeholders).find((key) => placeholders[key] === strippedMatch);\n\n // If we have no existing string literal match then create a new placeholder.\n if (!placeholder) {\n placeholder = `@@${Object.keys(placeholders).length}@@`;\n placeholders[placeholder] = strippedMatch;\n }\n\n return placeholder;\n });\n\n return { placeholders, processedDefinition };\n}\n\n/**\n * Parse the tree definition into an array of raw tokens.\n * @param definition The definition.\n * @returns An array of tokens parsed from the definition.\n */\nfunction parseTokensFromDefinition(definition: string): string[] {\n // Add some space around various important characters so that they can be plucked out easier as individual tokens.\n definition = definition.replace(/\\(/g, \" ( \");\n definition = definition.replace(/\\)/g, \" ) \");\n definition = definition.replace(/\\{/g, \" { \");\n definition = definition.replace(/\\}/g, \" } \");\n definition = definition.replace(/\\]/g, \" ] \");\n definition = definition.replace(/\\[/g, \" [ \");\n definition = definition.replace(/\\,/g, \" , \");\n\n // Split the definition into raw token form and return it.\n return definition.replace(/\\s+/g, \" \").trim().split(\" \");\n}\n", "import GuardPath, { GuardPathPart } from \"./attributes/guards/GuardPath\";\nimport buildRootASTNodes, { AnyArgument, RootAstNode } from \"./RootAstNodesBuilder\";\nimport State, { AnyState } from \"./State\";\nimport Lookup from \"./Lookup\";\nimport Node from \"./nodes/Node\";\nimport Root from \"./nodes/decorator/Root\";\nimport Composite from \"./nodes/composite/Composite\";\nimport Decorator from \"./nodes/decorator/Decorator\";\nimport { Agent, GlobalFunction } from \"./Agent\";\nimport { CallbackAttributeDetails } from \"./attributes/callbacks/Callback\";\nimport { GuardAttributeDetails } from \"./attributes/guards/Guard\";\nimport { BehaviourTreeOptions } from \"./BehaviourTreeOptions\";\nimport { parseMDSLToJSON } from \"./mdsl/MDSLDefinitionParser\";\n\n// Purely for outside inspection of the tree.\nexport type FlattenedTreeNode = {\n id: string;\n type: string;\n caption: string;\n state: AnyState;\n guards: GuardAttributeDetails[];\n callbacks: CallbackAttributeDetails[];\n args: AnyArgument[];\n parentId: string | null;\n};\n\n/**\n * A representation of a behaviour tree.\n */\nexport class BehaviourTree {\n /**\n * The main root tree node.\n */\n public readonly rootNode: Root;\n\n /**\n * Creates a new instance of the BehaviourTree class.\n * @param definition The behaviour tree definition.\n * @param agent The agent instance that this behaviour tree is modelling behaviour for.\n * @param options The behaviour tree options object.\n */\n constructor(definition: string, private agent: Agent, private options: BehaviourTreeOptions = {}) {\n // The tree definition must be defined and a valid string.\n if (typeof definition !== \"string\") {\n throw new Error(\"the tree definition must be a string\");\n }\n\n // The agent must be defined and not null.\n if (typeof agent !== \"object\" || agent === null) {\n throw new Error(\"the agent must be defined and not null\");\n }\n\n // Parse the behaviour tree definition, create the populated tree of behaviour tree nodes, and get the root.\n this.rootNode = BehaviourTree._createRootNode(definition);\n }\n\n /**\n * Gets whether the tree is in the RUNNING state.\n * @returns true if the tree is in the RUNNING state, otherwise false.\n */\n isRunning() {\n return this.rootNode.getState() === State.RUNNING;\n }\n\n /**\n * Gets the current tree state of SUCCEEDED, FAILED, READY or RUNNING.\n * @returns The current tree state.\n */\n getState() {\n return this.rootNode.getState();\n }\n\n /**\n * Step the tree.\n * 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.\n * 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\n * 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.\n *\n * 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.\n */\n step() {\n // If the root node has already been stepped to completion then we need to reset it.\n if (this.rootNode.getState() === State.SUCCEEDED || this.rootNode.getState() === State.FAILED) {\n this.rootNode.reset();\n }\n\n try {\n this.rootNode.update(this.agent, this.options);\n } catch (exception) {\n throw new Error(`error stepping tree: ${(exception as Error).message}`);\n }\n }\n\n /**\n * Resets the tree from the root node outwards to each nested node, giving each a state of READY.\n */\n reset() {\n this.rootNode.reset();\n }\n\n /**\n * Gets the flattened details of every node in the tree.\n * @returns The flattened details of every node in the tree.\n */\n getFlattenedNodeDetails(): FlattenedTreeNode[] {\n // Create an empty flattened array of tree nodes.\n const flattenedTreeNodes: FlattenedTreeNode[] = [];\n\n /**\n * Helper function to process a node instance and push details into the flattened tree nodes array.\n * @param node The current node.\n * @param parentUid The UID of the node parent, or null if the node is the main root node.\n */\n const processNode = (node: Node, parentUid: string | null) => {\n // Get the guard and callback attribute details for this node.\n const guards = node\n .getAttributes()\n .filter((attribute) => attribute.isGuard())\n .map((attribute) => attribute.getDetails()) as GuardAttributeDetails[];\n const callbacks = node\n .getAttributes()\n .filter((attribute) => !attribute.isGuard())\n .map((attribute) => attribute.getDetails()) as CallbackAttributeDetails[];\n\n // Push the current node into the flattened nodes array.\n flattenedTreeNodes.push({\n id: node.getUid(),\n type: node.getType(),\n caption: node.getName(),\n state: node.getState(),\n guards,\n callbacks,\n args: node.getArguments(),\n parentId: parentUid\n });\n\n // Process each of the nodes children if it is not a leaf node.\n if (!node.isLeafNode()) {\n (node as Composite | Decorator)\n .getChildren()\n .forEach((child) => processNode(child, (node as Composite | Decorator).getUid()));\n }\n };\n\n // Convert the nested node structure into a flattened array of node details.\n processNode(this.rootNode, null);\n\n return flattenedTreeNodes;\n }\n\n /**\n * Registers the action/condition/guard/callback function or subtree with the given name.\n * @param name The name of the function or subtree to register.\n * @param value The function or subtree definition to register.\n */\n static register(name: string, value: GlobalFunction | string) {\n if (typeof value === \"function\") {\n // We are going to register a action/condition/guard/callback function.\n Lookup.setFunc(name, value);\n } else if (typeof value === \"string\") {\n // We are going to register a subtree.\n let rootASTNodes: RootAstNode[];\n\n try {\n // Try to create the behaviour tree AST based on the definition provided, this could fail if the definition is invalid.\n rootASTNodes = buildRootASTNodes(value);\n } catch (exception) {\n // There was an issue in trying to parse and build the tree definition.\n throw new Error(`error registering definition: ${(exception as Error).message}`);\n }\n\n // This function should only ever be called with a definition containing a single unnamed root node.\n if (rootASTNodes.length != 1 || rootASTNodes[0].name !== null) {\n throw new Error(\"error registering definition: expected a single unnamed root node\");\n }\n\n Lookup.setSubtree(name, rootASTNodes[0]);\n } else {\n throw new Error(\"unexpected value, expected string definition or function\");\n }\n }\n\n /**\n * Unregisters the registered action/condition/guard/callback function or subtree with the given name.\n * @param name The name of the registered action/condition/guard/callback function or subtree to unregister.\n */\n static unregister(name: string): void {\n Lookup.remove(name);\n }\n\n /**\n * Unregister all registered action/condition/guard/callback functions and subtrees.\n */\n static unregisterAll(): void {\n Lookup.empty();\n }\n\n /**\n * Parses a behaviour tree definition and creates a tree of behaviour tree nodes.\n * @param {string} definition The behaviour tree definition.\n * @returns The root behaviour tree node.\n */\n private static _createRootNode(definition: string): Root {\n // TODO Remove!\n try {\n // parseToJSON(definition);\n } catch (exception) {\n console.log(exception);\n }\n\n try {\n // Try to create the behaviour tree AST based on the definition provided, this could fail if the definition is invalid.\n const rootASTNodes = buildRootASTNodes(definition);\n\n // Create a symbol to use as the main root key in our root node mapping.\n const mainRootNodeKey = Symbol(\"__root__\");\n\n // Create a mapping of root node names to root AST tokens. The main root node will have a key of Symbol(\"__root__\").\n const rootNodeMap: { [key: string | symbol]: RootAstNode } = {};\n for (const rootASTNode of rootASTNodes) {\n rootNodeMap[rootASTNode.name === null ? mainRootNodeKey : rootASTNode.name!] = rootASTNode;\n }\n\n // Convert the AST to our actual tree and get the root node.\n const rootNode: Root = rootNodeMap[mainRootNodeKey].createNodeInstance(\n // Create a provider for named root nodes that are part of our definition or have been registered. Prioritising the former.\n (name: string): RootAstNode => (rootNodeMap[name] ? rootNodeMap[name] : Lookup.getSubtree(name)),\n []\n );\n\n // Set a guard path on every leaf of the tree to evaluate as part of its update.\n BehaviourTree._applyLeafNodeGuardPaths(rootNode);\n\n // Return the root node.\n return rootNode;\n } catch (exception) {\n // There was an issue in trying to parse and build the tree definition.\n throw new Error(`error parsing tree: ${(exception as Error).message}`);\n }\n }\n\n /**\n * Applies a guard path to every leaf of the tree to evaluate as part of each update.\n * @param rootNode The main root tree node.\n */\n private static _applyLeafNodeGuardPaths(rootNode: Root) {\n const nodePaths: Node[][] = [];\n\n const findLeafNodes = (path: Node[], node: Node) => {\n // Add the current node to the path.\n path = path.concat(node);\n\n // Check whether the current node is a leaf node.\n if (node.isLeafNode()) {\n nodePaths.push(path);\n } else {\n (node as Composite | Decorator).getChildren().forEach((child) => findLeafNodes(path, child));\n }\n };\n\n // Find all leaf node paths, starting from the root.\n findLeafNodes([], rootNode);\n\n nodePaths.forEach((path) => {\n // Each node in the current path will have to be assigned a guard path, working from the root outwards.\n for (let depth = 0; depth < path.length; depth++) {\n // Get the node in the path at the current depth.\n const currentNode = path[depth];\n\n // The node may already have been assigned a guard path, if so just skip it.\n if (currentNode.hasGuardPath()) {\n continue;\n }\n\n // Create the guard path for the current node.\n const guardPath = new GuardPath(\n path\n .slice(0, depth + 1)\n .map((node) => ({ node, guards: node.getGuardAttributes() }))\n .filter((details) => details.guards.length > 0)\n );\n\n // Assign the guard path to the current node.\n currentNode.setGuardPath(guardPath);\n }\n });\n }\n}\n", "import {\n CompositeNodeDefinition,\n DecoratorNodeDefinition,\n NodeDefinition,\n RootNodeDefinition\n} from \"../BehaviourTreeDefinition\";\n\n/**\n * A type defining an object that holds a reference to substitued string literals parsed from the definition.\n */\nexport type StringLiteralPlaceholders = { [key: string]: string };\n\n/**\n * A type guard function that returns true if the specified node satisfies the RootNodeDefinition type.\n * @param node The node.\n * @returns A value of true if the specified node satisfies the RootNodeDefinition type.\n */\nexport function isRootNode(node: NodeDefinition): node is RootNodeDefinition {\n return node.type === \"root\";\n}\n\n/**\n * A type guard function that returns true if the specified node satisfies the NodeDefinition type.\n * @param node The node.\n * @returns A value of true if the specified node satisfies the NodeDefinition type.\n */\nexport function isLeafNode(node: NodeDefinition): node is NodeDefinition {\n return [\"branch\", \"action\", \"condition\", \"wait\"].includes(node.type);\n}\n\n/**\n * A type guard function that returns true if the specified node satisfies the DecoratorNodeDefinition type.\n * @param node The node.\n * @returns A value of true if the specified node satisfies the DecoratorNodeDefinition type.\n */\nexport function isDecoratorNode(node: NodeDefinition): node is DecoratorNodeDefinition {\n return [\"root\", \"repeat\", \"retry\", \"flip\", \"succeed\", \"fail\"].includes(node.type);\n}\n\n/**\n * A type guard function that returns true if the specified node satisfies the CompositeNodeDefinition type.\n * @param node The node.\n * @returns A value of true if the specified node satisfies the CompositeNodeDefinition type.\n */\nexport function isCompositeNode(node: NodeDefinition): node is CompositeNodeDefinition {\n return [\"sequence\", \"selector\", \"lotto\", \"parallel\"].includes(node.type);\n}\n\n/**\n * Pop the next raw token from the specified array of tokens and throw an error if it wasn't the expected one.\n * @param tokens The array of tokens.\n * @param expected An optional string or array or items, one of which must match the next popped token.\n * @returns The popped token.\n */\nexport function popAndCheck(tokens: string[], expected?: string | string[]): string {\n // Get and remove the next token.\n const popped = tokens.shift();\n\n // We were expecting another token but there aren't any.\n if (popped === undefined) {\n throw new Error(\"unexpected end of definition\");\n }\n\n // Do we have an expected token/tokens array?\n if (expected != undefined) {\n // Get an array of expected values, if the popped token matches any then we are all good.\n const expectedValues = typeof expected === \"string\" ? [expected] : expected;\n\n // Check whether the popped token matches at least one of our expected items.\n var tokenMatchesExpectation = expectedValues.some((item) => popped.toUpperCase() === item.toUpperCase());\n\n // Throw an error if the popped token didn't match any of our expected items.\n if (!tokenMatchesExpectation) {\n const expectationString = expectedValues.map((item) => \"'\" + item + \"'\").join(\" or \");\n throw new Error(\"unexpected token found. Expected \" + expectationString + \" but got '\" + popped + \"'\");\n }\n }\n\n // Return the popped token.\n return popped;\n}\n\n/**\n * Swaps out any node/attribute argument string literals with placeholders.\n * @param definition The definition.\n * @returns An object containing a mapping of placeholders to original string values as well as the processed definition string.\n */\nexport function substituteStringLiterals(definition: string): {\n placeholders: StringLiteralPlaceholders;\n processedDefinition: string;\n} {\n // Create an object to hold the mapping of placeholders to original string values.\n const placeholders: StringLiteralPlaceholders = {};\n\n // Replace any string literals wrapped with double quotes in our definition with placeholders to be processed later.\n const processedDefinition = definition.replace(/\\\"(\\\\.|[^\"\\\\])*\\\"/g, (match) => {\n var strippedMatch = match.substring(1, match.length - 1);\n var placeholder = Object.keys(placeholders).find((key) => placeholders[key] === strippedMatch);\n\n // If we have no existing string literal match then create a new placeholder.\n if (!placeholder) {\n placeholder = `@@${Object.keys(placeholders).length}@@`;\n placeholders[placeholder] = strippedMatch;\n }\n\n return placeholder;\n });\n\n return { placeholders, processedDefinition };\n}\n\n/**\n * Parse the tree definition into an array of raw tokens.\n * @param definition The definition.\n * @returns An array of tokens parsed from the definition.\n */\nexport function parseTokensFromDefinition(definition: string): string[] {\n // Add some space around various important characters so that they can be plucked out easier as individual tokens.\n definition = definition.replace(/\\(/g, \" ( \");\n definition = definition.replace(/\\)/g, \" ) \");\n definition = definition.replace(/\\{/g, \" { \");\n definition = definition.replace(/\\}/g, \" } \");\n definition = definition.replace(/\\]/g, \" ] \");\n definition = definition.replace(/\\[/g, \" [ \");\n definition = definition.replace(/\\,/g, \" , \");\n\n // Split the definition into raw token form and return it.\n return definition.replace(/\\s+/g, \" \").trim().split(\" \");\n}\n", "import { StringLiteralPlaceholders, popAndCheck } from \"./MDSLUtilities\";\n\nexport type Argument = {\n /** The argument value. */\n value: T;\n /** The argument type, used for validation. */\n type: string;\n};\n\nexport type NullArgument = Argument & {\n type: \"null\";\n};\n\nexport type BooleanArgument = Argument & {\n type: \"boolean\";\n};\n\nexport type NumberArgument = Argument & {\n type: \"number\";\n isInteger: boolean; // Used for validation.\n};\n\nexport type StringPlaceholderArgument = Argument & {\n type: \"string\";\n};\n\nexport type IdentifierArgument = Argument & {\n type: \"identifier\";\n};\n\nexport type AnyArgument =\n | NullArgument\n | BooleanArgument\n | NumberArgument\n | StringPlaceholderArgument\n | IdentifierArgument;\n\n/**\n * Parse an array of argument definitions from the specified tokens array.\n * @param tokens The array tokens to parse the argument definitions from.\n * @param stringArgumentPlaceholders The mapping of string literal node argument placeholders to original values.\n * @param argumentValidator The argument validator function.\n * @param validationFailedMessage The exception message to throw if argument validation fails.\n * @returns An array of argument definitions parsed from the specified tokens array.\n */\nexport function parseArgumentTokens(\n tokens: string[],\n stringArgumentPlaceholders: StringLiteralPlaceholders\n): AnyArgument[] {\n const argumentList: AnyArgument[] = [];\n\n // If the next token is not a '[' or '(' then we have no arguments to parse.\n if (![\"[\", \"(\"].includes(tokens[0])) {\n return argumentList;\n }\n\n // Any lists of arguments will always be wrapped in '[]' for node arguments or '()' for attribute arguments.\n // We are looking for a '[' or '(' opener that wraps the argument tokens and the relevant closer.\n const closingToken = popAndCheck(tokens, [\"[\", \"(\"]) === \"[\" ? \"]\" : \")\";\n\n const argumentListTokens: string[] = [];\n\n // Grab all tokens between the '[' and ']' or '(' and ')'.\n while (tokens.length && tokens[0] !== closingToken) {\n // The next token is part of our arguments list.\n argumentListTokens.push(tokens.shift()!);\n }\n\n // Validate the order of the argument tokens. Each token must either be a ',' or a single argument that satisfies the validator.\n argumentListTokens.forEach((token, index) => {\n // Get whether this token should be an actual argument.\n const shouldBeArgumentToken = !(index & 1);\n\n // If the current token should be an actual argument then validate it, otherwise it should be a ',' token.\n if (shouldBeArgumentToken) {\n // Get the argument definition.\n const argumentDefinition = getArgumentDefinition(token, stringArgumentPlaceholders);\n\n // This is a valid argument!\n argumentList.push(argumentDefinition);\n } else {\n // The current token should be a ',' token.\n if (token !== \",\") {\n throw new Error(`invalid argument list, expected ',' or ']' but got '${token}'`);\n }\n }\n });\n\n // The arguments list should terminate with a ']' or ')' token, depending on the opener.\n popAndCheck(tokens, closingToken);\n\n // Return the arguments.\n return argumentList;\n}\n\n/**\n * Gets an argument value definition.\n * @param token The argument token.\n * @param stringArgumentPlaceholders The mapping of string literal node argument placeholders to original values.\n * @returns An argument value definition.\n */\nfunction getArgumentDefinition(token: string, stringArgumentPlaceholders: StringLiteralPlaceholders): AnyArgument {\n // Check whether the token represents a null value.\n if (token === \"null\") {\n return {\n value: null,\n type: \"null\"\n } as NullArgument;\n }\n\n // Check whether the token represents a boolean value.\n if (token === \"true\" || token === \"false\") {\n return {\n value: token === \"true\",\n type: \"boolean\"\n } as BooleanArgument;\n }\n\n // Check whether the token represents a number value.\n // TODO: Relies on broken isNaN - see MDN.\n // if (!Number.isNaN(token)) {\n if (!isNaN(token as any)) {\n return {\n value: parseFloat(token),\n isInteger: parseFloat(token) === parseInt(token, 10),\n type: \"number\"\n } as NumberArgument;\n }\n\n // Check whether the token is a placeholder (e.g. @@0@@) representing a string literal.\n if (token.match(/^@@\\d+@@$/g)) {\n return {\n value: stringArgumentPlaceholders[token].replace('\\\\\"', '\"'),\n type: \"string\"\n } as StringPlaceholderArgument;\n }\n\n // The only remaining option is that the argument value is an identifier.\n return {\n value: token,\n type: \"identifier\"\n } as IdentifierArgument;\n}\n", "import { NodeAttributeDefinition } from \"../BehaviourTreeDefinition\";\nimport { parseArgumentTokens } from \"./MDSLNodeArgumentParser\";\nimport { StringLiteralPlaceholders } from \"./MDSLUtilities\";\n\n/**\n * A type defining the attribute definitions of a node.\n */\ntype NodeAttributes = {\n while?: NodeAttributeDefinition;\n until?: NodeAttributeDefinition;\n entry?: NodeAttributeDefinition;\n exit?: NodeAttributeDefinition;\n step?: NodeAttributeDefinition;\n};\n\n/**\n * Parse any node attribute definitions from the specified tokens array.\n * @param tokens The array of remaining tokens.\n * @param stringArgumentPlaceholders The mapping of string literal node argument placeholders to original values.\n * @returns An object of attribute definitions defined by any directly following tokens.\n */\nexport function parseAttributeTokens(\n tokens: string[],\n stringArgumentPlaceholders: StringLiteralPlaceholders\n): NodeAttributes {\n const nodeAttributeNames: (keyof NodeAttributes)[] = [\"while\", \"until\", \"entry\", \"exit\", \"step\"];\n\n // Create an object to hold any attributes found.\n const attributes: NodeAttributes = {};\n\n // Try to get the name of the attribute for the next token.\n let nextAttributeName = tokens[0]?.toLowerCase() as keyof NodeAttributes;\n\n // Pull attribute tokens as well as their arguments off of the tokens stack until we have no more.\n while (nodeAttributeNames.includes(nextAttributeName)) {\n // Check to make sure that we have not already created an attribute definition of this type.\n if (attributes[nextAttributeName]) {\n throw new Error(`duplicate attribute '${tokens[0].toUpperCase()}' found for node`);\n }\n\n // Remove the attribute name token from the array of tokens.\n tokens.shift();\n\n // Grab the attribute arguments, assuming the first to be an identifier.\n const [attributeCallIdentifier, ...attributeArguments] = parseArgumentTokens(\n tokens,\n stringArgumentPlaceholders\n );\n\n // The first attribute argument has to be an identifer, this will reference an agent function.\n if (attributeCallIdentifier?.type !== \"identifier\") {\n throw new Error(\"expected agent function name identifier argument for attribute\");\n }\n\n // Any attribute arguments (other than the expected call identifier) must have a type of string, number, boolean or null.\n attributeArguments\n .filter((arg) => arg.type === \"identifier\")\n .forEach((arg) => {\n throw new Error(\n `invalid attribute argument value '${arg.value}', must be string, number, boolean or null`\n );\n });\n\n // Create the attribute definition and add it to the object of attribute definitions found.\n attributes[nextAttributeName] = {\n call: attributeCallIdentifier.value,\n args: attributeArguments.map(({ value }) => value)\n };\n\n // Try to get the next attribute name token, as there could be multiple.\n nextAttributeName = tokens[0]?.toLowerCase() as keyof NodeAttributes;\n }\n\n return attributes;\n}\n", "import {\n ActionNodeDefinition,\n AnyChildNode,\n AnyNode,\n BranchNodeDefinition,\n ConditionNodeDefinition,\n FailNodeDefinition,\n FlipNodeDefinition,\n LottoNodeDefinition,\n ParallelNodeDefinition,\n RepeatNodeDefinition,\n RetryNodeDefinition,\n RootNodeDefinition,\n SelectorNodeDefinition,\n SequenceNodeDefinition,\n SucceedNodeDefinition,\n WaitNodeDefinition\n} from \"../BehaviourTreeDefinition\";\nimport { parseArgumentTokens } from \"./MDSLNodeArgumentParser\";\nimport { parseAttributeTokens } from \"./MDSLNodeAttributeParser\";\nimport {\n StringLiteralPlaceholders,\n isCompositeNode,\n isDecoratorNode,\n isLeafNode,\n isRootNode,\n parseTokensFromDefinition,\n popAndCheck,\n substituteStringLiterals\n} from \"./MDSLUtilities\";\n\n/**\n * Parse the MDSL tree definition string into an equivalent JSON definition.\n * @param definition The tree definition string as MDSL.\n * @returns The root node JSON definitions.\n */\nexport function parseMDSLToJSON(definition: string): RootNodeDefinition[] {\n // Swap out any node/attribute argument string literals with a placeholder and get a mapping of placeholders to original values as well as the processed definition.\n const { placeholders, processedDefinition } = substituteStringLiterals(definition);\n\n // Parse our definition definition string into an array of raw tokens.\n const tokens = parseTokensFromDefinition(processedDefinition);\n\n return convertTokensToJSONDefinition(tokens, placeholders);\n}\n\n/**\n * Converts the specified tree definition tokens into a JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The root node JSON definitions.\n */\nfunction convertTokensToJSONDefinition(\n tokens: string[],\n stringLiteralPlaceholders: StringLiteralPlaceholders\n): RootNodeDefinition[] {\n // There must be at least 3 tokens for the tree definition to be valid. 'ROOT', '{' and '}'.\n if (tokens.length < 3) {\n throw new Error(\"invalid token count\");\n }\n\n // We should have a matching number of '{' and '}' tokens. If not, then there are scopes that have not been properly closed.\n if (tokens.filter((token) => token === \"{\").length !== tokens.filter((token) => token === \"}\").length) {\n throw new Error(\"scope character mismatch\");\n }\n\n // Create an array of tree stack arrays where root nodes will always be at the botton and the current composite/decorator node at the top.\n // There should be an element in this array for every root node defined and every element should be an array with a root note as the first element.\n // E.g. A definition with two root nodes defined:\n // [\n // [root, lotto, sequence],\n // [root, selector]\n // ]\n const treeStacks: [Partial, ...Partial[]][] = [];\n\n // Create an array of all root node definitions that we create.\n const rootNodes: Partial[] = [];\n\n // A helper function used to push node definitions onto the tree stack.\n const pushNode = (node: AnyNode) => {\n // If the node is a root node then we need to create a new tree stack array with the root node at the root.\n if (isRootNode(node)) {\n // Add the root node definition to our array of all parsed root node definitions.\n rootNodes.push(node);\n\n // Add the root node definition to the root of a new tree stack.\n treeStacks.push([node]);\n\n return;\n }\n\n // All non-root nodes should be pushed after their root nodes so handle cases\n // where we may not have any tree stacks or our top-most tree stack is empty.\n if (!treeStacks.length || !treeStacks[treeStacks.length - 1].length) {\n throw new Error(\"expected root node at base of definition\");\n }\n\n // Get the current tree stack that we are populating.\n const topTreeStack = treeStacks[treeStacks.length - 1];\n\n // Get the top-most node in the current tree stack, this will be a composite/decorator node\n // for which we will populate its children array if composite or setting its child if a decorator.\n const topTreeStackTopNode = topTreeStack[topTreeStack.length - 1] as AnyNode;\n\n // If the top-most node in the current root stack is a composite or decorator\n // node then the current node should be added as a child of the top-most node.\n if (isCompositeNode(topTreeStackTopNode)) {\n topTreeStackTopNode.children = topTreeStackTopNode.children || [];\n topTreeStackTopNode.children.push(node);\n } else if (isDecoratorNode(topTreeStackTopNode)) {\n // If the top node already has a child node set then throw an error as a decorator should only have a single child.\n if (topTreeStackTopNode.child) {\n throw new Error(\"a decorator node must only have a single child node\");\n }\n\n topTreeStackTopNode.child = node;\n }\n\n // If the node we are adding is also a composite or decorator node, then we should push it\n // onto the current tree stack, as subsequent nodes will be added as its child/children.\n if (!isLeafNode(node)) {\n topTreeStack.push(node);\n }\n };\n\n // A helper function used to pop node definitions off of the stack.\n const popNode = () => {\n // Get the current tree stack that we are populating.\n const topTreeStack = treeStacks[treeStacks.length - 1];\n\n // Pop the top-most node in the current tree stack if there is one.\n if (topTreeStack.length) {\n topTreeStack.pop();\n }\n\n // We don't want any empty tree stacks in our stack of tree stacks.\n if (!topTreeStack.length) {\n treeStacks.pop();\n }\n };\n\n // We should keep processing the raw tokens until we run out of them.\n while (tokens.length) {\n // Grab the next token.\n const token = tokens.shift()!;\n\n // How we create the next node depends on the current raw token value.\n switch (token.toUpperCase()) {\n case \"ROOT\": {\n pushNode(createRootNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"SUCCEED\": {\n pushNode(createSucceedNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"FAIL\": {\n pushNode(createFailNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"FLIP\": {\n pushNode(createFlipNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"REPEAT\": {\n pushNode(createRepeatNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"RETRY\": {\n pushNode(createRetryNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"SEQUENCE\": {\n pushNode(createSequenceNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"SELECTOR\": {\n pushNode(createSelectorNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"PARALLEL\": {\n pushNode(createParallelNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"LOTTO\": {\n pushNode(createLottoNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"ACTION\": {\n pushNode(createActionNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"CONDITION\": {\n pushNode(createConditionNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"WAIT\": {\n pushNode(createWaitNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"BRANCH\": {\n pushNode(createBranchNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"}\": {\n // The '}' character closes the current scope and means that we have to pop a node off of the current stack.\n popNode();\n break;\n }\n\n default: {\n throw new Error(`unexpected token: ${token}`);\n }\n }\n }\n\n return rootNodes as RootNodeDefinition[];\n}\n\n/**\n * Creates a root node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The root node JSON definition.\n */\nfunction createRootNode(tokens: string[], stringLiteralPlaceholders: StringLiteralPlaceholders): RootNodeDefinition {\n // Create the root node definition.\n let node = {\n type: \"root\",\n id: undefined\n } as RootNodeDefinition;\n\n // Parse any node arguments, we should only have one if any which will be an identifier argument for the root identifier.\n const nodeArguments = parseArgumentTokens(tokens, stringLiteralPlaceholders);\n\n // Check whether any node arguments were defined.\n if (nodeArguments.length) {\n // We should only have one argument, if any, which will be an identifier argument for the root identifier.\n if (nodeArguments.length === 1 && nodeArguments[0].type === \"identifier\") {\n // The root node identifier will be the first and only node argument value.\n node.id = nodeArguments[0].value as string;\n } else {\n throw new Error(\"expected single root name argument\");\n }\n }\n\n // Grab any node attribute definitions and spread them into the node definition.\n node = { ...node, ...parseAttributeTokens(tokens, stringLiteralPlaceholders) };\n\n // This is a decorator node, so we expect an opening '{'.\n popAndCheck(tokens, \"{\");\n\n // Return the root node definition.\n return node;\n}\n\n/**\n * Creates a succeed node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The succeed node JSON definition.\n */\nfunction createSucceedNode(\n tokens: string[],\n stringLiteralPlaceholders: StringLiteralPlaceholders\n): SucceedNodeDefinition {\n const node = {\n type: \"succeed\",\n ...parseAttributeTokens(tokens, stringLiteralPlaceholders)\n } as SucceedNodeDefinition;\n\n // This is a decorator node, so we expect an opening '{'.\n popAndCheck(tokens, \"{\");\n\n // Return the succeed node definition.\n return node;\n}\n\n/**\n * Creates a fail node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The fail node JSON definition.\n */\nfunction createFailNode(tokens: string[], stringLiteralPlaceholders: StringLiteralPlaceholders): FailNodeDefinition {\n const node = {\n type: \"fail\",\n ...parseAttributeTokens(tokens, stringLiteralPlaceholders)\n } as FailNodeDefinition;\n\n // This is a decorator node, so we expect an opening '{'.\n popAndCheck(tokens, \"{\");\n\n // Return the fail node definition.\n return node;\n}\n\n/**\n * Creates a flip node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The flip node JSON definition.\n */\nfunction createFlipNode(tokens: string[], stringLiteralPlaceholders: StringLiteralPlaceholders): FlipNodeDefinition {\n const node = {\n type: \"flip\",\n ...parseAttributeTokens(tokens, stringLiteralPlaceholders)\n } as FlipNodeDefinition;\n\n // This is a decorator node, so we expect an opening '{'.\n popAndCheck(tokens, \"{\");\n\n // Return the flip node definition.\n return node;\n}\n\n/**\n * Creates a repeat node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The repeat node JSON definition.\n */\nfunction createRepeatNode(\n tokens: string[],\n stringLiteralPlaceholders: StringLiteralPlaceholders\n): RepeatNodeDefinition {\n let node = { type: \"repeat\" } as RepeatNodeDefinition;\n\n // Get the node arguments.\n const nodeArguments = parseArgumentTokens(tokens, stringLiteralPlaceholders);\n\n // The arguments of a repeat node are optional. We may have:\n // - No node arguments, in which case the repeat note will iterate indefinitely.\n // - One node argument which will be the explicit number of iterations to make.\n // - Two node arguments which define the min and max iteration bounds from which a random iteration count will be picked.\n if (nodeArguments.length) {\n // All repeat node arguments MUST be of type number and must be integer.\n nodeArguments\n .filter((arg) => arg.type !== \"number\" || !arg.isInteger)\n .forEach(() => {\n throw new Error(`repeat node iteration counts must be integer values`);\n });\n\n // We should have got one or two iteration counts.\n if (nodeArguments.length === 1) {\n // A static iteration count was defined.\n node.iterations = nodeArguments[0].value as number;\n } else if (nodeArguments.length === 2) {\n // A minimum and maximum iteration count was defined.\n node.iterations = [nodeArguments[0].value as number, nodeArguments[1].value as number];\n } else {\n // An incorrect number of iteration counts was defined.\n throw new Error(\"invalid number of repeat node iteration count arguments defined\");\n }\n }\n\n // Grab any node attribute definitions and spread them into the node definition.\n node = { ...node, ...parseAttributeTokens(tokens, stringLiteralPlaceholders) };\n\n // This is a decorator node, so we expect an opening '{'.\n popAndCheck(tokens, \"{\");\n\n // Return the repeat node definition.\n return node;\n}\n\n/**\n * Creates a retry node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The retry node JSON definition.\n */\nfunction createRetryNode(tokens: string[], stringLiteralPlaceholders: StringLiteralPlaceholders): RetryNodeDefinition {\n let node = { type: \"retry\" } as RetryNodeDefinition;\n\n // Get the node arguments.\n const nodeArguments = parseArgumentTokens(tokens, stringLiteralPlaceholders);\n\n // The arguments of a retry node are optional. We may have:\n // - No node arguments, in which case the retry note will attempt indefinitely.\n // - One node argument which will be the explicit number of attempts to make.\n // - Two node arguments which define the min and max attempt bounds from which a random attempt count will be picked.\n if (nodeArguments.length) {\n // All retry node arguments MUST be of type number and must be integer.\n nodeArguments\n .filter((arg) => arg.type !== \"number\" || !arg.isInteger)\n .forEach(() => {\n throw new Error(`retry node attempt counts must be integer values`);\n });\n\n // We should have got one or two attempt counts.\n if (nodeArguments.length === 1) {\n // A static attempt count was defined.\n node.attempts = nodeArguments[0].value as number;\n } else if (nodeArguments.length === 2) {\n // A minimum and maximum attempt count was defined.\n node.attempts = [nodeArguments[0].value as number, nodeArguments[1].value as number];\n } else {\n // An incorrect number of attempt counts was defined.\n throw new Error(\"invalid number of retry node attempt count arguments defined\");\n }\n }\n\n // Grab any node attribute definitions and spread them into the node definition.\n node = { ...node, ...parseAttributeTokens(tokens, stringLiteralPlaceholders) };\n\n // This is a decorator node, so we expect an opening '{'.\n popAndCheck(tokens, \"{\");\n\n // Return the retry node definition.\n return node;\n}\n\n/**\n * Creates a sequence node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The sequence node JSON definition.\n */\nfunction createSequenceNode(\n tokens: string[],\n stringLiteralPlaceholders: StringLiteralPlaceholders\n): SequenceNodeDefinition {\n const node = {\n type: \"sequence\",\n ...parseAttributeTokens(tokens, stringLiteralPlaceholders)\n } as SequenceNodeDefinition;\n\n // This is a composite node, so we expect an opening '{'.\n popAndCheck(tokens, \"{\");\n\n // Return the sequence node definition.\n return node;\n}\n\n/**\n * Creates a selector node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The selector node JSON definition.\n */\nfunction createSelectorNode(\n tokens: string[],\n stringLiteralPlaceholders: StringLiteralPlaceholders\n): SelectorNodeDefinition {\n const node = {\n type: \"selector\",\n ...parseAttributeTokens(tokens, stringLiteralPlaceholders)\n } as SelectorNodeDefinition;\n\n // This is a composite node, so we expect an opening '{'.\n popAndCheck(tokens, \"{\");\n\n // Return the selector node definition.\n return node;\n}\n\n/**\n * Creates a parallel node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The parallel node JSON definition.\n */\nfunction createParallelNode(\n tokens: string[],\n stringLiteralPlaceholders: StringLiteralPlaceholders\n): ParallelNodeDefinition {\n const node = {\n type: \"parallel\",\n ...parseAttributeTokens(tokens, stringLiteralPlaceholders)\n } as ParallelNodeDefinition;\n\n // This is a composite node, so we expect an opening '{'.\n popAndCheck(tokens, \"{\");\n\n // Return the parallel node definition.\n return node;\n}\n\n/**\n * Creates a lotto node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The lotto node JSON definition.\n */\nfunction createLottoNode(tokens: string[], stringLiteralPlaceholders: StringLiteralPlaceholders): LottoNodeDefinition {\n // If any node arguments have been defined then they must be our weights.\n const nodeArguments = parseArgumentTokens(tokens, stringLiteralPlaceholders);\n\n // All lotto node arguments MUST be of type number and must be integer.\n nodeArguments\n .filter((arg) => arg.type !== \"number\" || !arg.isInteger)\n .forEach(() => {\n throw new Error(`lotto node weight arguments must be integer values`);\n });\n\n const node = {\n type: \"lotto\",\n weights: nodeArguments.map(({ value }) => value),\n ...parseAttributeTokens(tokens, stringLiteralPlaceholders)\n } as LottoNodeDefinition;\n\n // This is a composite node, so we expect an opening '{'.\n popAndCheck(tokens, \"{\");\n\n // Return the lotto node definition.\n return node;\n}\n\n/**\n * Creates an action node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The action node JSON definition.\n */\nfunction createActionNode(\n tokens: string[],\n stringLiteralPlaceholders: StringLiteralPlaceholders\n): ActionNodeDefinition {\n // Parse any node arguments, we should have at least one which will be an identifier argument for the action name\n // and agent function to invoke for the action, all other arguments are to be passed as arguments to that function.\n const [actionNameIdentifier, ...agentFunctionArgs] = parseArgumentTokens(tokens, stringLiteralPlaceholders);\n\n // Our first argument MUST be defined and be an identifier as we require an action name argument.\n if (actionNameIdentifier?.type !== \"identifier\") {\n throw new Error(\"expected action name identifier argument\");\n }\n\n // Only the first argument should have been an identifier, all agent function arguments must be string, number, boolean or null.\n agentFunctionArgs\n .filter((arg) => arg.type === \"identifier\")\n .forEach((arg) => {\n throw new Error(\n `invalid action node argument value '${arg.value}', must be string, number, boolean or null`\n );\n });\n\n // Return the action node definition.\n return {\n type: \"action\",\n call: actionNameIdentifier.value,\n args: agentFunctionArgs.map(({ value }) => value),\n ...parseAttributeTokens(tokens, stringLiteralPlaceholders)\n };\n}\n\n/**\n * Creates a condition node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The condition node JSON definition.\n */\nfunction createConditionNode(\n tokens: string[],\n stringLiteralPlaceholders: StringLiteralPlaceholders\n): ConditionNodeDefinition {\n // Parse any node arguments, we should have at least one which will be an identifier argument for the condition name\n // and agent function to invoke for the condition, all other arguments are to be passed as arguments to that function.\n const [conditionNameIdentifier, ...agentFunctionArgs] = parseArgumentTokens(tokens, stringLiteralPlaceholders);\n\n // Our first argument MUST be defined and be an identifier as we require a condition name argument.\n if (conditionNameIdentifier?.type !== \"identifier\") {\n throw new Error(\"expected condition name identifier argument\");\n }\n\n // Only the first argument should have been an identifier, all agent function arguments must be string, number, boolean or null.\n agentFunctionArgs\n .filter((arg) => arg.type === \"identifier\")\n .forEach((arg) => {\n throw new Error(\n `invalid condition node argument value '${arg.value}', must be string, number, boolean or null`\n );\n });\n\n // Return the condition node definition.\n return {\n type: \"condition\",\n call: conditionNameIdentifier.value,\n args: agentFunctionArgs.map(({ value }) => value),\n ...parseAttributeTokens(tokens, stringLiteralPlaceholders)\n };\n}\n\n/**\n * Creates a wait node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The wait node JSON definition.\n */\nfunction createWaitNode(tokens: string[], stringLiteralPlaceholders: StringLiteralPlaceholders): WaitNodeDefinition {\n let node = { type: \"wait\" } as WaitNodeDefinition;\n\n // Get the node arguments.\n const nodeArguments = parseArgumentTokens(tokens, stringLiteralPlaceholders);\n\n // The arguments of a wait node are optional. We may have:\n // - No node arguments, in which case the wait will be indefinite until it is aborted.\n // - One node argument which will be the explicit duration of the wait.\n // - Two node arguments which define the min and max duration bounds from which a random duration will be picked.\n if (nodeArguments.length) {\n // All wait node arguments MUST be of type number and must be integer.\n nodeArguments\n .filter((arg) => arg.type !== \"number\" || !arg.isInteger)\n .forEach(() => {\n throw new Error(`wait node duration arguments must be integer values`);\n });\n\n // We may have:\n // - One node argument which will be the explicit duration of the wait.\n // - Two node arguments which define the min and max duration bounds from which a random duration will be picked.\n // - Too many arguments, which is not valid.\n if (nodeArguments.length === 1) {\n // An explicit duration was defined.\n node.duration = nodeArguments[0].value as number;\n } else if (nodeArguments.length === 2) {\n // Min and max duration bounds were defined from which a random duration will be picked.\n node.duration = [nodeArguments[0].value as number, nodeArguments[1].value as number];\n } else if (nodeArguments.length > 2) {\n // An incorrect number of duration arguments were defined.\n throw new Error(\"invalid number of wait node duration arguments defined\");\n }\n }\n\n // Return the wait node definition.\n return { ...node, ...parseAttributeTokens(tokens, stringLiteralPlaceholders) };\n}\n\n/**\n * Creates a branch node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The branch node JSON definition.\n */\nfunction createBranchNode(\n tokens: string[],\n stringLiteralPlaceholders: StringLiteralPlaceholders\n): BranchNodeDefinition {\n // Parse any node arguments, we should have one which will be an identifier argument for the root ref.\n const nodeArguments = parseArgumentTokens(tokens, stringLiteralPlaceholders);\n\n // We should have only a single identifer argument for a branch node, which is the root ref.\n if (nodeArguments.length !== 1 || nodeArguments[0].type !== \"identifier\") {\n throw new Error(\"expected single branch name argument\");\n }\n\n // Return the branch node definition.\n return { type: \"branch\", ref: nodeArguments[0].value };\n}\n"], - "mappings": "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", - "names": ["Participant", "Lotto", "createLotto", "State", "createLotto", "popAndCheck", "substituteStringLiterals", "parseTokensFromDefinition", "popAndCheck", "getArgumentDefinition", "substituteStringLiterals", "parseTokensFromDefinition", "popAndCheck"] + "sources": ["../node_modules/lotto-draw/dist/Participant.js", "../node_modules/lotto-draw/dist/Utilities.js", "../node_modules/lotto-draw/dist/Lotto.js", "../node_modules/lotto-draw/dist/createLotto.js", "../node_modules/lotto-draw/dist/index.js", "../src/index.ts", "../src/State.ts", "../src/BehaviourTreeDefinitionUtilities.ts", "../src/mdsl/MDSLUtilities.ts", "../src/mdsl/MDSLNodeArgumentParser.ts", "../src/mdsl/MDSLNodeAttributeParser.ts", "../src/mdsl/MDSLDefinitionParser.ts", "../src/BehaviourTreeDefinitionValidator.ts", "../src/attributes/guards/GuardUnsatisifedException.ts", "../src/attributes/guards/GuardPath.ts", "../src/nodes/Node.ts", "../src/nodes/leaf/Leaf.ts", "../src/Lookup.ts", "../src/nodes/leaf/Action.ts", "../src/nodes/leaf/Condition.ts", "../src/nodes/leaf/Wait.ts", "../src/nodes/decorator/Decorator.ts", "../src/nodes/decorator/Root.ts", "../src/nodes/decorator/Repeat.ts", "../src/nodes/decorator/Retry.ts", "../src/nodes/decorator/Flip.ts", "../src/nodes/decorator/Succeed.ts", "../src/nodes/decorator/Fail.ts", "../src/nodes/composite/Lotto.ts", "../src/nodes/composite/Composite.ts", "../src/nodes/composite/Selector.ts", "../src/nodes/composite/Sequence.ts", "../src/nodes/composite/Parallel.ts", "../src/attributes/Attribute.ts", "../src/attributes/guards/Guard.ts", "../src/attributes/guards/While.ts", "../src/attributes/guards/Until.ts", "../src/attributes/callbacks/Callback.ts", "../src/attributes/callbacks/Entry.ts", "../src/attributes/callbacks/Exit.ts", "../src/attributes/callbacks/Step.ts", "../src/RootAstNodesBuilder.ts", "../src/BehaviourTree.ts"], + "sourcesContent": ["\"use strict\";\r\nObject.defineProperty(exports, \"__esModule\", { value: true });\r\nexports.Participant = void 0;\r\n/**\r\n * A participant that holds a number of tickets.\r\n */\r\nvar Participant = /** @class */ (function () {\r\n /**\r\n * Creates an instance of the Participant class.\r\n * @param participant The actual participant.\r\n * @param tickets The number of tickets held by the participant.\r\n */\r\n function Participant(participant, tickets) {\r\n if (tickets === void 0) { tickets = 1; }\r\n this._participant = participant;\r\n this._tickets = tickets;\r\n }\r\n Object.defineProperty(Participant.prototype, \"participant\", {\r\n /** Gets the actual participant. */\r\n get: function () {\r\n return this._participant;\r\n },\r\n enumerable: false,\r\n configurable: true\r\n });\r\n Object.defineProperty(Participant.prototype, \"tickets\", {\r\n /** Gets or sets the number of tickets held by the participant. */\r\n get: function () {\r\n return this._tickets;\r\n },\r\n set: function (value) {\r\n this._tickets = value;\r\n },\r\n enumerable: false,\r\n configurable: true\r\n });\r\n return Participant;\r\n}());\r\nexports.Participant = Participant;\r\n", "\"use strict\";\r\nObject.defineProperty(exports, \"__esModule\", { value: true });\r\nexports.isNaturalNumber = exports.isNullOrUndefined = void 0;\r\n/**\r\n * Gets whether the value provided is null or undefined.\r\n * @param value The value to check.\r\n * @returns Whether the value provided is null or undefined.\r\n */\r\nfunction isNullOrUndefined(value) {\r\n return value === null || value === undefined;\r\n}\r\nexports.isNullOrUndefined = isNullOrUndefined;\r\n/**\r\n * Gets whether the value provided is a natural number.\r\n * @param value The value to check.\r\n * @returns Whether the value provided is a natural number.\r\n */\r\nfunction isNaturalNumber(value) {\r\n return typeof value === \"number\" && value >= 1 && Math.floor(value) === value;\r\n}\r\nexports.isNaturalNumber = isNaturalNumber;\r\n", "\"use strict\";\r\nObject.defineProperty(exports, \"__esModule\", { value: true });\r\nexports.Lotto = void 0;\r\nvar Participant_1 = require(\"./Participant\");\r\nvar Utilities_1 = require(\"./Utilities\");\r\n/**\r\n * Represents a lotto consisting of a number of pickable ticket-holding participants.\r\n */\r\nvar Lotto = /** @class */ (function () {\r\n /**\r\n * Creates a new instance of Lotto.\r\n * @param customRandom The custom RNG to use in place of Math.random().\r\n */\r\n function Lotto(customRandom) {\r\n /** The array of participants that are holding tickets in the lotto. */\r\n this._participants = [];\r\n this._customRandom = customRandom;\r\n }\r\n /**\r\n * Adds a participant with the specified number of tickets, or adds to the participant ticket count if the participant already holds tickets.\r\n * @param participant The participant to add or to increase the ticket count for if they already hold tickets.\r\n * @param tickets The number of tickets, defaults to 1.\r\n * @returns The Lotto instance.\r\n */\r\n Lotto.prototype.add = function (participant, tickets) {\r\n if (tickets === void 0) { tickets = 1; }\r\n // Check that we have a valid ticket count.\r\n if (!(0, Utilities_1.isNaturalNumber)(tickets)) {\r\n throw new Error(\"tickets value must be a natural number\");\r\n }\r\n // Check whether this participant has already been added.\r\n var existingParticipant = this._participants.find(function (part) { return part.participant === participant; });\r\n if (existingParticipant) {\r\n // The participant has already been added to the lotto so just add to their ticket count.\r\n existingParticipant.tickets += tickets;\r\n }\r\n else {\r\n // The participant is not part of the lotto so we should add them.\r\n this._participants.push(new Participant_1.Participant(participant, tickets));\r\n }\r\n return this;\r\n };\r\n /**\r\n * Removes the specified number of tickets for the given participant from the draw, or all tickets if a ticket number is not defined.\r\n * @param participant The participant to remove tickets for.\r\n * @param tickets The number of tickets to remove, or undefined if all tickets are to be removed.\r\n * @returns The Lotto instance.\r\n */\r\n Lotto.prototype.remove = function (participant, tickets) {\r\n // Attempt to get the existing participant.\r\n var existingParticipant = this._participants.find(function (part) { return part.participant === participant; });\r\n // There is nothing to do if the specified participant isn't even part of the lotto.\r\n if (!existingParticipant) {\r\n return this;\r\n }\r\n // Check whether a tickets value was given.\r\n if (tickets !== undefined) {\r\n // Check that we have a valid ticket count.\r\n if (!(0, Utilities_1.isNaturalNumber)(tickets)) {\r\n throw new Error(\"tickets value must be a natural number\");\r\n }\r\n existingParticipant.tickets -= tickets;\r\n // If the participant no longer holds any tickets then they should be removed.\r\n if (existingParticipant.tickets < 1) {\r\n this._participants = this._participants.filter(function (part) { return part !== existingParticipant; });\r\n }\r\n }\r\n else {\r\n // We are removing all tickets for the participant so just remove them from the lotto.\r\n this._participants = this._participants.filter(function (part) { return part !== existingParticipant; });\r\n }\r\n return this;\r\n };\r\n /**\r\n * Draw a winning ticket and return the participant that holds the ticket.\r\n * @param options The draw options.\r\n * @returns The participant that holds the winning ticket.\r\n */\r\n Lotto.prototype.draw = function (options) {\r\n if (options === void 0) { options = {}; }\r\n // If we have no participants then just return null.\r\n if (this._participants.length === 0) {\r\n return null;\r\n }\r\n var redrawable = (0, Utilities_1.isNullOrUndefined)(options.redrawable) ? true : options.redrawable;\r\n var pickable = [];\r\n this._participants.forEach(function (_a) {\r\n var participant = _a.participant, tickets = _a.tickets;\r\n for (var ticketCount = 0; ticketCount < tickets; ticketCount++) {\r\n pickable.push(participant);\r\n }\r\n });\r\n var random;\r\n // We need a random floating-point number between 0 (inclusive) and 1 to scale up to pick our winner.\r\n // If a custom random function exists then we should use that or fall back to Math.random().\r\n if (this._customRandom) {\r\n // Call our custom random function to get a random floating-point number.\r\n random = this._customRandom();\r\n // Verify that the result of calling our custom random function is a number between 0 (inclusive) and 1.\r\n if (typeof random !== \"number\" || random < 0 || random >= 1) {\r\n throw new Error(\"the 'random' function provided did not return a number between 0 (inclusive) and 1\");\r\n }\r\n }\r\n else {\r\n // No custom random function was defined so just use good ol' Math.random().\r\n random = Math.random();\r\n }\r\n // Pick a winning participant.\r\n var winner = pickable[Math.floor(random * pickable.length)];\r\n // If the ticket isn't redrawable then we should remove a ticket from the winning participants ticket count.\r\n if (!redrawable) {\r\n this.remove(winner, 1);\r\n }\r\n // Return the winning participant.\r\n return winner;\r\n };\r\n /**\r\n * Draws multiple winning tickets and return an array of the participants that hold the winning tickets.\r\n * @param tickets The number of winning tickets to draw.\r\n * @param options The draw multiple options.\r\n * @returns An array of the participants that hold the winning tickets.\r\n */\r\n Lotto.prototype.drawMultiple = function (tickets, options) {\r\n if (options === void 0) { options = {}; }\r\n var uniqueResults = (0, Utilities_1.isNullOrUndefined)(options.unique) ? false : options.unique;\r\n // Handle cases where the user has asked for zero tickets (no idea why they would do this be we should trust them).\r\n if (tickets === 0) {\r\n return [];\r\n }\r\n // Now that we know out tickets value is not zero we should check that it is a valid natural number.\r\n if (!(0, Utilities_1.isNaturalNumber)(tickets)) {\r\n throw new Error(\"tickets value must be a natural number\");\r\n }\r\n var result = [];\r\n // Keep drawing tickets until we either reach the number of required tickets or we simply run out of tickets to draw.\r\n // We can run out of tickets to draw if 'options.redrawable' is explicity 'false' or we just had no participants when 'drawMultiple' was called.\r\n while (result.length < tickets && this._participants.length > 0) {\r\n result.push(this.draw(options));\r\n }\r\n // If the 'unique' draw option is set then we need to remove duplicates from the result list.\r\n if (uniqueResults) {\r\n // Create an array to store our unique results.\r\n var unique = [];\r\n // Iterate over all of our participants (with potential duplicates) and populate our array of unique values.\r\n for (var _i = 0, result_1 = result; _i < result_1.length; _i++) {\r\n var participant = result_1[_i];\r\n if (unique.indexOf(participant) === -1) {\r\n unique.push(participant);\r\n }\r\n }\r\n result = unique;\r\n }\r\n return result;\r\n };\r\n return Lotto;\r\n}());\r\nexports.Lotto = Lotto;\r\n", "\"use strict\";\r\nObject.defineProperty(exports, \"__esModule\", { value: true });\r\nexports.createLotto = void 0;\r\nvar Lotto_1 = require(\"./Lotto\");\r\n/**\r\n * A function that creates and returns a Lotto instance.\r\n * @param participantsOrOptions An array of initial participants or options relating to the creation of a Lotto instance.\r\n * @returns A new Lotto instance.\r\n */\r\nfunction createLotto(participantsOrOptions) {\r\n // If no initial participants or lotto options were provided as an argument then we can just return a new lotto instance now.\r\n if (!participantsOrOptions) {\r\n return new Lotto_1.Lotto();\r\n }\r\n // Check whether we were provided with an array of initial participants or a lotto options object.\r\n if (Array.isArray(participantsOrOptions)) {\r\n // We are dealing with a pre-defined array of participants.\r\n var participants = participantsOrOptions;\r\n var lotto_1 = new Lotto_1.Lotto();\r\n // If the lotto participants have been defined upfront then we will need to add them all to our lotto instance now.\r\n participants.forEach(function (_a) {\r\n var participant = _a[0], tokens = _a[1];\r\n return lotto_1.add(participant, tokens);\r\n });\r\n // Return the Lotto instance.\r\n return lotto_1;\r\n }\r\n else {\r\n // We are dealing with some lotto options.\r\n var random = participantsOrOptions.random, participants = participantsOrOptions.participants;\r\n // Create a Lotto instance passing the custom RNG function to use in place of Math.random() (which could be undefined).\r\n var lotto_2 = new Lotto_1.Lotto(random);\r\n // If the lotto participants have been defined upfront as part of the options then we will need to add them all to our lotto instance now.\r\n if (participants) {\r\n participants.forEach(function (_a) {\r\n var participant = _a[0], tokens = _a[1];\r\n return lotto_2.add(participant, tokens);\r\n });\r\n }\r\n // Return the Lotto instance.\r\n return lotto_2;\r\n }\r\n}\r\nexports.createLotto = createLotto;\r\n", "\"use strict\";\r\nObject.defineProperty(exports, \"__esModule\", { value: true });\r\nvar createLotto_1 = require(\"./createLotto\");\r\nexports.default = createLotto_1.createLotto;\r\n", "import State from \"./State\";\nimport { validateDefinition } from \"./BehaviourTreeDefinitionValidator\";\nimport { convertMDSLToJSON } from \"./mdsl/MDSLDefinitionParser\";\nimport { BehaviourTree, FlattenedTreeNode } from \"./BehaviourTree\";\n\nexport { BehaviourTree, State, convertMDSLToJSON, validateDefinition };\nexport type { FlattenedTreeNode };\n", "/**\n * Enumeration of node state types.\n */\nexport enum State {\n READY = \"mistreevous.ready\",\n RUNNING = \"mistreevous.running\",\n SUCCEEDED = \"mistreevous.succeeded\",\n FAILED = \"mistreevous.failed\"\n}\n\nexport { State as default };\n\nexport type CompleteState = State.SUCCEEDED | State.FAILED;\nexport type AnyState = State.READY | State.RUNNING | CompleteState;\n", "import {\n NodeDefinition,\n RootNodeDefinition,\n DecoratorNodeDefinition,\n CompositeNodeDefinition,\n AnyNode,\n BranchNodeDefinition\n} from \"./BehaviourTreeDefinition\";\n\n/**\n * A type guard function that returns true if the specified node satisfies the RootNodeDefinition type.\n * @param node The node.\n * @returns A value of true if the specified node satisfies the RootNodeDefinition type.\n */\nexport function isRootNode(node: NodeDefinition): node is RootNodeDefinition {\n return node.type === \"root\";\n}\n\n/**\n * A type guard function that returns true if the specified node satisfies the BranchNodeDefinition type.\n * @param node The node.\n * @returns A value of true if the specified node satisfies the BranchNodeDefinition type.\n */\nexport function isBranchNode(node: NodeDefinition): node is BranchNodeDefinition {\n return node.type === \"branch\";\n}\n\n/**\n * A type guard function that returns true if the specified node satisfies the NodeDefinition type.\n * @param node The node.\n * @returns A value of true if the specified node satisfies the NodeDefinition type.\n */\nexport function isLeafNode(node: NodeDefinition): node is NodeDefinition {\n return [\"branch\", \"action\", \"condition\", \"wait\"].includes(node.type);\n}\n\n/**\n * A type guard function that returns true if the specified node satisfies the DecoratorNodeDefinition type.\n * @param node The node.\n * @returns A value of true if the specified node satisfies the DecoratorNodeDefinition type.\n */\nexport function isDecoratorNode(node: NodeDefinition): node is DecoratorNodeDefinition {\n return [\"root\", \"repeat\", \"retry\", \"flip\", \"succeed\", \"fail\"].includes(node.type);\n}\n\n/**\n * A type guard function that returns true if the specified node satisfies the CompositeNodeDefinition type.\n * @param node The node.\n * @returns A value of true if the specified node satisfies the CompositeNodeDefinition type.\n */\nexport function isCompositeNode(node: NodeDefinition): node is CompositeNodeDefinition {\n return [\"sequence\", \"selector\", \"lotto\", \"parallel\"].includes(node.type);\n}\n\n/**\n * Flatten a node definition into an array of all of its nested node definitions.\n * @param nodeDefinition The node definition to flatten.\n * @returns An array of all of nested node definitions.\n */\nexport function flattenDefinition(nodeDefinition: AnyNode): AnyNode[] {\n const nodes: AnyNode[] = [];\n\n const processNode = (currentNodeDefinition: AnyNode) => {\n nodes.push(currentNodeDefinition);\n\n if (isCompositeNode(currentNodeDefinition)) {\n currentNodeDefinition.children.forEach(processNode);\n } else if (isDecoratorNode(currentNodeDefinition)) {\n processNode(currentNodeDefinition.child);\n }\n };\n\n processNode(nodeDefinition);\n\n return nodes;\n}\n\n/**\n * Determines whether the passed value is an integer.\n * @param value The value to check.\n * @returns Whether the passed value is an integer.\n */\nexport function isInteger(value: unknown): boolean {\n return typeof value === \"number\" && Math.floor(value) === value;\n}\n", "/**\n * A type defining an object that holds a reference to substitued string literals parsed from the definition.\n */\nexport type StringLiteralPlaceholders = { [key: string]: string };\n\n/**\n * Pop the next raw token from the specified array of tokens and throw an error if it wasn't the expected one.\n * @param tokens The array of tokens.\n * @param expected An optional string or array or items, one of which must match the next popped token.\n * @returns The popped token.\n */\nexport function popAndCheck(tokens: string[], expected?: string | string[]): string {\n // Get and remove the next token.\n const popped = tokens.shift();\n\n // We were expecting another token but there aren't any.\n if (popped === undefined) {\n throw new Error(\"unexpected end of definition\");\n }\n\n // Do we have an expected token/tokens array?\n if (expected != undefined) {\n // Get an array of expected values, if the popped token matches any then we are all good.\n const expectedValues = typeof expected === \"string\" ? [expected] : expected;\n\n // Check whether the popped token matches at least one of our expected items.\n var tokenMatchesExpectation = expectedValues.some((item) => popped.toUpperCase() === item.toUpperCase());\n\n // Throw an error if the popped token didn't match any of our expected items.\n if (!tokenMatchesExpectation) {\n const expectationString = expectedValues.map((item) => \"'\" + item + \"'\").join(\" or \");\n throw new Error(\"unexpected token found. Expected \" + expectationString + \" but got '\" + popped + \"'\");\n }\n }\n\n // Return the popped token.\n return popped;\n}\n\n/**\n * Swaps out any node/attribute argument string literals with placeholders.\n * @param definition The definition.\n * @returns An object containing a mapping of placeholders to original string values as well as the processed definition string.\n */\nexport function substituteStringLiterals(definition: string): {\n placeholders: StringLiteralPlaceholders;\n processedDefinition: string;\n} {\n // Create an object to hold the mapping of placeholders to original string values.\n const placeholders: StringLiteralPlaceholders = {};\n\n // Replace any string literals wrapped with double quotes in our definition with placeholders to be processed later.\n const processedDefinition = definition.replace(/\\\"(\\\\.|[^\"\\\\])*\\\"/g, (match) => {\n var strippedMatch = match.substring(1, match.length - 1);\n var placeholder = Object.keys(placeholders).find((key) => placeholders[key] === strippedMatch);\n\n // If we have no existing string literal match then create a new placeholder.\n if (!placeholder) {\n placeholder = `@@${Object.keys(placeholders).length}@@`;\n placeholders[placeholder] = strippedMatch;\n }\n\n return placeholder;\n });\n\n return { placeholders, processedDefinition };\n}\n\n/**\n * Parse the tree definition into an array of raw tokens.\n * @param definition The definition.\n * @returns An array of tokens parsed from the definition.\n */\nexport function parseTokensFromDefinition(definition: string): string[] {\n // Add some space around various important characters so that they can be plucked out easier as individual tokens.\n definition = definition.replace(/\\(/g, \" ( \");\n definition = definition.replace(/\\)/g, \" ) \");\n definition = definition.replace(/\\{/g, \" { \");\n definition = definition.replace(/\\}/g, \" } \");\n definition = definition.replace(/\\]/g, \" ] \");\n definition = definition.replace(/\\[/g, \" [ \");\n definition = definition.replace(/\\,/g, \" , \");\n\n // Split the definition into raw token form and return it.\n return definition.replace(/\\s+/g, \" \").trim().split(\" \");\n}\n", "import { StringLiteralPlaceholders, popAndCheck } from \"./MDSLUtilities\";\n\nexport type Argument = {\n /** The argument value. */\n value: T;\n /** The argument type, used for validation. */\n type: string;\n};\n\nexport type NullArgument = Argument & {\n type: \"null\";\n};\n\nexport type BooleanArgument = Argument & {\n type: \"boolean\";\n};\n\nexport type NumberArgument = Argument & {\n type: \"number\";\n isInteger: boolean; // Used for validation.\n};\n\nexport type StringPlaceholderArgument = Argument & {\n type: \"string\";\n};\n\nexport type IdentifierArgument = Argument & {\n type: \"identifier\";\n};\n\nexport type AnyArgument =\n | NullArgument\n | BooleanArgument\n | NumberArgument\n | StringPlaceholderArgument\n | IdentifierArgument;\n\n/**\n * Parse an array of argument definitions from the specified tokens array.\n * @param tokens The array tokens to parse the argument definitions from.\n * @param stringArgumentPlaceholders The mapping of string literal node argument placeholders to original values.\n * @param argumentValidator The argument validator function.\n * @param validationFailedMessage The exception message to throw if argument validation fails.\n * @returns An array of argument definitions parsed from the specified tokens array.\n */\nexport function parseArgumentTokens(\n tokens: string[],\n stringArgumentPlaceholders: StringLiteralPlaceholders\n): AnyArgument[] {\n const argumentList: AnyArgument[] = [];\n\n // If the next token is not a '[' or '(' then we have no arguments to parse.\n if (![\"[\", \"(\"].includes(tokens[0])) {\n return argumentList;\n }\n\n // Any lists of arguments will always be wrapped in '[]' for node arguments or '()' for attribute arguments.\n // We are looking for a '[' or '(' opener that wraps the argument tokens and the relevant closer.\n const closingToken = popAndCheck(tokens, [\"[\", \"(\"]) === \"[\" ? \"]\" : \")\";\n\n const argumentListTokens: string[] = [];\n\n // Grab all tokens between the '[' and ']' or '(' and ')'.\n while (tokens.length && tokens[0] !== closingToken) {\n // The next token is part of our arguments list.\n argumentListTokens.push(tokens.shift()!);\n }\n\n // Validate the order of the argument tokens. Each token must either be a ',' or a single argument that satisfies the validator.\n argumentListTokens.forEach((token, index) => {\n // Get whether this token should be an actual argument.\n const shouldBeArgumentToken = !(index & 1);\n\n // If the current token should be an actual argument then validate it, otherwise it should be a ',' token.\n if (shouldBeArgumentToken) {\n // Get the argument definition.\n const argumentDefinition = getArgumentDefinition(token, stringArgumentPlaceholders);\n\n // This is a valid argument!\n argumentList.push(argumentDefinition);\n } else {\n // The current token should be a ',' token.\n if (token !== \",\") {\n throw new Error(`invalid argument list, expected ',' or ']' but got '${token}'`);\n }\n }\n });\n\n // The arguments list should terminate with a ']' or ')' token, depending on the opener.\n popAndCheck(tokens, closingToken);\n\n // Return the arguments.\n return argumentList;\n}\n\n/**\n * Gets an argument value definition.\n * @param token The argument token.\n * @param stringArgumentPlaceholders The mapping of string literal node argument placeholders to original values.\n * @returns An argument value definition.\n */\nfunction getArgumentDefinition(token: string, stringArgumentPlaceholders: StringLiteralPlaceholders): AnyArgument {\n // Check whether the token represents a null value.\n if (token === \"null\") {\n return {\n value: null,\n type: \"null\"\n } as NullArgument;\n }\n\n // Check whether the token represents a boolean value.\n if (token === \"true\" || token === \"false\") {\n return {\n value: token === \"true\",\n type: \"boolean\"\n } as BooleanArgument;\n }\n\n // Check whether the token represents a number value.\n // TODO: Relies on broken isNaN - see MDN.\n // if (!Number.isNaN(token)) {\n if (!isNaN(token as any)) {\n return {\n value: parseFloat(token),\n isInteger: parseFloat(token) === parseInt(token, 10),\n type: \"number\"\n } as NumberArgument;\n }\n\n // Check whether the token is a placeholder (e.g. @@0@@) representing a string literal.\n if (token.match(/^@@\\d+@@$/g)) {\n return {\n value: stringArgumentPlaceholders[token].replace('\\\\\"', '\"'),\n type: \"string\"\n } as StringPlaceholderArgument;\n }\n\n // The only remaining option is that the argument value is an identifier.\n return {\n value: token,\n type: \"identifier\"\n } as IdentifierArgument;\n}\n", "import { NodeAttributeDefinition } from \"../BehaviourTreeDefinition\";\nimport { parseArgumentTokens } from \"./MDSLNodeArgumentParser\";\nimport { StringLiteralPlaceholders } from \"./MDSLUtilities\";\n\n/**\n * A type defining the attribute definitions of a node.\n */\ntype NodeAttributes = {\n while?: NodeAttributeDefinition;\n until?: NodeAttributeDefinition;\n entry?: NodeAttributeDefinition;\n exit?: NodeAttributeDefinition;\n step?: NodeAttributeDefinition;\n};\n\n/**\n * Parse any node attribute definitions from the specified tokens array.\n * @param tokens The array of remaining tokens.\n * @param stringArgumentPlaceholders The mapping of string literal node argument placeholders to original values.\n * @returns An object of attribute definitions defined by any directly following tokens.\n */\nexport function parseAttributeTokens(\n tokens: string[],\n stringArgumentPlaceholders: StringLiteralPlaceholders\n): NodeAttributes {\n const nodeAttributeNames: (keyof NodeAttributes)[] = [\"while\", \"until\", \"entry\", \"exit\", \"step\"];\n\n // Create an object to hold any attributes found.\n const attributes: NodeAttributes = {};\n\n // Try to get the name of the attribute for the next token.\n let nextAttributeName = tokens[0]?.toLowerCase() as keyof NodeAttributes;\n\n // Pull attribute tokens as well as their arguments off of the tokens stack until we have no more.\n while (nodeAttributeNames.includes(nextAttributeName)) {\n // Check to make sure that we have not already created an attribute definition of this type.\n if (attributes[nextAttributeName]) {\n throw new Error(`duplicate attribute '${tokens[0].toUpperCase()}' found for node`);\n }\n\n // Remove the attribute name token from the array of tokens.\n tokens.shift();\n\n // Grab the attribute arguments, assuming the first to be an identifier.\n const [attributeCallIdentifier, ...attributeArguments] = parseArgumentTokens(\n tokens,\n stringArgumentPlaceholders\n );\n\n // The first attribute argument has to be an identifer, this will reference an agent function.\n if (attributeCallIdentifier?.type !== \"identifier\") {\n throw new Error(\"expected agent function name identifier argument for attribute\");\n }\n\n // Any attribute arguments (other than the expected call identifier) must have a type of string, number, boolean or null.\n attributeArguments\n .filter((arg) => arg.type === \"identifier\")\n .forEach((arg) => {\n throw new Error(\n `invalid attribute argument value '${arg.value}', must be string, number, boolean or null`\n );\n });\n\n // Create the attribute definition and add it to the object of attribute definitions found.\n attributes[nextAttributeName] = {\n call: attributeCallIdentifier.value,\n args: attributeArguments.map(({ value }) => value)\n };\n\n // Try to get the next attribute name token, as there could be multiple.\n nextAttributeName = tokens[0]?.toLowerCase() as keyof NodeAttributes;\n }\n\n return attributes;\n}\n", "import {\n ActionNodeDefinition,\n AnyChildNode,\n AnyNode,\n BranchNodeDefinition,\n ConditionNodeDefinition,\n FailNodeDefinition,\n FlipNodeDefinition,\n LottoNodeDefinition,\n ParallelNodeDefinition,\n RepeatNodeDefinition,\n RetryNodeDefinition,\n RootNodeDefinition,\n SelectorNodeDefinition,\n SequenceNodeDefinition,\n SucceedNodeDefinition,\n WaitNodeDefinition\n} from \"../BehaviourTreeDefinition\";\nimport { isCompositeNode, isDecoratorNode, isLeafNode, isRootNode } from \"../BehaviourTreeDefinitionUtilities\";\nimport { parseArgumentTokens } from \"./MDSLNodeArgumentParser\";\nimport { parseAttributeTokens } from \"./MDSLNodeAttributeParser\";\nimport {\n StringLiteralPlaceholders,\n parseTokensFromDefinition,\n popAndCheck,\n substituteStringLiterals\n} from \"./MDSLUtilities\";\n\n/**\n * Convert the MDSL tree definition string into an equivalent JSON definition.\n * @param definition The tree definition string as MDSL.\n * @returns The root node JSON definitions.\n */\nexport function convertMDSLToJSON(definition: string): RootNodeDefinition[] {\n // Swap out any node/attribute argument string literals with a placeholder and get a mapping of placeholders to original values as well as the processed definition.\n const { placeholders, processedDefinition } = substituteStringLiterals(definition);\n\n // Parse our definition definition string into an array of raw tokens.\n const tokens = parseTokensFromDefinition(processedDefinition);\n\n return convertTokensToJSONDefinition(tokens, placeholders);\n}\n\n/**\n * Converts the specified tree definition tokens into a JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The root node JSON definitions.\n */\nfunction convertTokensToJSONDefinition(\n tokens: string[],\n stringLiteralPlaceholders: StringLiteralPlaceholders\n): RootNodeDefinition[] {\n // There must be at least 3 tokens for the tree definition to be valid. 'ROOT', '{' and '}'.\n if (tokens.length < 3) {\n throw new Error(\"invalid token count\");\n }\n\n // We should have a matching number of '{' and '}' tokens. If not, then there are scopes that have not been properly closed.\n if (tokens.filter((token) => token === \"{\").length !== tokens.filter((token) => token === \"}\").length) {\n throw new Error(\"scope character mismatch\");\n }\n\n // Create an array of tree stack arrays where root nodes will always be at the botton and the current composite/decorator node at the top.\n // There should be an element in this array for every root node defined and every element should be an array with a root note as the first element.\n // E.g. A definition with two root nodes defined:\n // [\n // [root, lotto, sequence],\n // [root, selector]\n // ]\n const treeStacks: [Partial, ...Partial[]][] = [];\n\n // Create an array of all root node definitions that we create.\n const rootNodes: Partial[] = [];\n\n // A helper function used to push node definitions onto the tree stack.\n const pushNode = (node: AnyNode) => {\n // If the node is a root node then we need to create a new tree stack array with the root node at the root.\n if (isRootNode(node)) {\n // Add the root node definition to our array of all parsed root node definitions.\n rootNodes.push(node);\n\n // Add the root node definition to the root of a new tree stack.\n treeStacks.push([node]);\n\n return;\n }\n\n // All non-root nodes should be pushed after their root nodes so handle cases\n // where we may not have any tree stacks or our top-most tree stack is empty.\n if (!treeStacks.length || !treeStacks[treeStacks.length - 1].length) {\n throw new Error(\"expected root node at base of definition\");\n }\n\n // Get the current tree stack that we are populating.\n const topTreeStack = treeStacks[treeStacks.length - 1];\n\n // Get the top-most node in the current tree stack, this will be a composite/decorator node\n // for which we will populate its children array if composite or setting its child if a decorator.\n const topTreeStackTopNode = topTreeStack[topTreeStack.length - 1] as AnyNode;\n\n // If the top-most node in the current root stack is a composite or decorator\n // node then the current node should be added as a child of the top-most node.\n if (isCompositeNode(topTreeStackTopNode)) {\n topTreeStackTopNode.children = topTreeStackTopNode.children || [];\n topTreeStackTopNode.children.push(node);\n } else if (isDecoratorNode(topTreeStackTopNode)) {\n // If the top node already has a child node set then throw an error as a decorator should only have a single child.\n if (topTreeStackTopNode.child) {\n throw new Error(\"a decorator node must only have a single child node\");\n }\n\n topTreeStackTopNode.child = node;\n }\n\n // If the node we are adding is also a composite or decorator node, then we should push it\n // onto the current tree stack, as subsequent nodes will be added as its child/children.\n if (!isLeafNode(node)) {\n topTreeStack.push(node);\n }\n };\n\n // A helper function used to pop node definitions off of the stack.\n const popNode = () => {\n // Get the current tree stack that we are populating.\n const topTreeStack = treeStacks[treeStacks.length - 1];\n\n // Pop the top-most node in the current tree stack if there is one.\n if (topTreeStack.length) {\n topTreeStack.pop();\n }\n\n // We don't want any empty tree stacks in our stack of tree stacks.\n if (!topTreeStack.length) {\n treeStacks.pop();\n }\n };\n\n // We should keep processing the raw tokens until we run out of them.\n while (tokens.length) {\n // Grab the next token.\n const token = tokens.shift()!;\n\n // How we create the next node depends on the current raw token value.\n switch (token.toUpperCase()) {\n case \"ROOT\": {\n pushNode(createRootNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"SUCCEED\": {\n pushNode(createSucceedNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"FAIL\": {\n pushNode(createFailNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"FLIP\": {\n pushNode(createFlipNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"REPEAT\": {\n pushNode(createRepeatNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"RETRY\": {\n pushNode(createRetryNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"SEQUENCE\": {\n pushNode(createSequenceNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"SELECTOR\": {\n pushNode(createSelectorNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"PARALLEL\": {\n pushNode(createParallelNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"LOTTO\": {\n pushNode(createLottoNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"ACTION\": {\n pushNode(createActionNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"CONDITION\": {\n pushNode(createConditionNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"WAIT\": {\n pushNode(createWaitNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"BRANCH\": {\n pushNode(createBranchNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"}\": {\n // The '}' character closes the current scope and means that we have to pop a node off of the current stack.\n popNode();\n break;\n }\n\n default: {\n throw new Error(`unexpected token: ${token}`);\n }\n }\n }\n\n return rootNodes as RootNodeDefinition[];\n}\n\n/**\n * Creates a root node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The root node JSON definition.\n */\nfunction createRootNode(tokens: string[], stringLiteralPlaceholders: StringLiteralPlaceholders): RootNodeDefinition {\n // Create the root node definition.\n let node = {\n type: \"root\",\n id: undefined\n } as RootNodeDefinition;\n\n // Parse any node arguments, we should only have one if any which will be an identifier argument for the root identifier.\n const nodeArguments = parseArgumentTokens(tokens, stringLiteralPlaceholders);\n\n // Check whether any node arguments were defined.\n if (nodeArguments.length) {\n // We should only have one argument, if any, which will be an identifier argument for the root identifier.\n if (nodeArguments.length === 1 && nodeArguments[0].type === \"identifier\") {\n // The root node identifier will be the first and only node argument value.\n node.id = nodeArguments[0].value as string;\n } else {\n throw new Error(\"expected single root name argument\");\n }\n }\n\n // Grab any node attribute definitions and spread them into the node definition.\n node = { ...node, ...parseAttributeTokens(tokens, stringLiteralPlaceholders) };\n\n // This is a decorator node, so we expect an opening '{'.\n popAndCheck(tokens, \"{\");\n\n // Return the root node definition.\n return node;\n}\n\n/**\n * Creates a succeed node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The succeed node JSON definition.\n */\nfunction createSucceedNode(\n tokens: string[],\n stringLiteralPlaceholders: StringLiteralPlaceholders\n): SucceedNodeDefinition {\n const node = {\n type: \"succeed\",\n ...parseAttributeTokens(tokens, stringLiteralPlaceholders)\n } as SucceedNodeDefinition;\n\n // This is a decorator node, so we expect an opening '{'.\n popAndCheck(tokens, \"{\");\n\n // Return the succeed node definition.\n return node;\n}\n\n/**\n * Creates a fail node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The fail node JSON definition.\n */\nfunction createFailNode(tokens: string[], stringLiteralPlaceholders: StringLiteralPlaceholders): FailNodeDefinition {\n const node = {\n type: \"fail\",\n ...parseAttributeTokens(tokens, stringLiteralPlaceholders)\n } as FailNodeDefinition;\n\n // This is a decorator node, so we expect an opening '{'.\n popAndCheck(tokens, \"{\");\n\n // Return the fail node definition.\n return node;\n}\n\n/**\n * Creates a flip node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The flip node JSON definition.\n */\nfunction createFlipNode(tokens: string[], stringLiteralPlaceholders: StringLiteralPlaceholders): FlipNodeDefinition {\n const node = {\n type: \"flip\",\n ...parseAttributeTokens(tokens, stringLiteralPlaceholders)\n } as FlipNodeDefinition;\n\n // This is a decorator node, so we expect an opening '{'.\n popAndCheck(tokens, \"{\");\n\n // Return the flip node definition.\n return node;\n}\n\n/**\n * Creates a repeat node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The repeat node JSON definition.\n */\nfunction createRepeatNode(\n tokens: string[],\n stringLiteralPlaceholders: StringLiteralPlaceholders\n): RepeatNodeDefinition {\n let node = { type: \"repeat\" } as RepeatNodeDefinition;\n\n // Get the node arguments.\n const nodeArguments = parseArgumentTokens(tokens, stringLiteralPlaceholders);\n\n // The arguments of a repeat node are optional. We may have:\n // - No node arguments, in which case the repeat note will iterate indefinitely.\n // - One node argument which will be the explicit number of iterations to make.\n // - Two node arguments which define the min and max iteration bounds from which a random iteration count will be picked.\n if (nodeArguments.length) {\n // All repeat node arguments MUST be of type number and must be integer.\n nodeArguments\n .filter((arg) => arg.type !== \"number\" || !arg.isInteger)\n .forEach(() => {\n throw new Error(`repeat node iteration counts must be integer values`);\n });\n\n // We should have got one or two iteration counts.\n if (nodeArguments.length === 1) {\n // A static iteration count was defined.\n node.iterations = nodeArguments[0].value as number;\n } else if (nodeArguments.length === 2) {\n // A minimum and maximum iteration count was defined.\n node.iterations = [nodeArguments[0].value as number, nodeArguments[1].value as number];\n } else {\n // An incorrect number of iteration counts was defined.\n throw new Error(\"invalid number of repeat node iteration count arguments defined\");\n }\n }\n\n // Grab any node attribute definitions and spread them into the node definition.\n node = { ...node, ...parseAttributeTokens(tokens, stringLiteralPlaceholders) };\n\n // This is a decorator node, so we expect an opening '{'.\n popAndCheck(tokens, \"{\");\n\n // Return the repeat node definition.\n return node;\n}\n\n/**\n * Creates a retry node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The retry node JSON definition.\n */\nfunction createRetryNode(tokens: string[], stringLiteralPlaceholders: StringLiteralPlaceholders): RetryNodeDefinition {\n let node = { type: \"retry\" } as RetryNodeDefinition;\n\n // Get the node arguments.\n const nodeArguments = parseArgumentTokens(tokens, stringLiteralPlaceholders);\n\n // The arguments of a retry node are optional. We may have:\n // - No node arguments, in which case the retry note will attempt indefinitely.\n // - One node argument which will be the explicit number of attempts to make.\n // - Two node arguments which define the min and max attempt bounds from which a random attempt count will be picked.\n if (nodeArguments.length) {\n // All retry node arguments MUST be of type number and must be integer.\n nodeArguments\n .filter((arg) => arg.type !== \"number\" || !arg.isInteger)\n .forEach(() => {\n throw new Error(`retry node attempt counts must be integer values`);\n });\n\n // We should have got one or two attempt counts.\n if (nodeArguments.length === 1) {\n // A static attempt count was defined.\n node.attempts = nodeArguments[0].value as number;\n } else if (nodeArguments.length === 2) {\n // A minimum and maximum attempt count was defined.\n node.attempts = [nodeArguments[0].value as number, nodeArguments[1].value as number];\n } else {\n // An incorrect number of attempt counts was defined.\n throw new Error(\"invalid number of retry node attempt count arguments defined\");\n }\n }\n\n // Grab any node attribute definitions and spread them into the node definition.\n node = { ...node, ...parseAttributeTokens(tokens, stringLiteralPlaceholders) };\n\n // This is a decorator node, so we expect an opening '{'.\n popAndCheck(tokens, \"{\");\n\n // Return the retry node definition.\n return node;\n}\n\n/**\n * Creates a sequence node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The sequence node JSON definition.\n */\nfunction createSequenceNode(\n tokens: string[],\n stringLiteralPlaceholders: StringLiteralPlaceholders\n): SequenceNodeDefinition {\n const node = {\n type: \"sequence\",\n ...parseAttributeTokens(tokens, stringLiteralPlaceholders)\n } as SequenceNodeDefinition;\n\n // This is a composite node, so we expect an opening '{'.\n popAndCheck(tokens, \"{\");\n\n // Return the sequence node definition.\n return node;\n}\n\n/**\n * Creates a selector node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The selector node JSON definition.\n */\nfunction createSelectorNode(\n tokens: string[],\n stringLiteralPlaceholders: StringLiteralPlaceholders\n): SelectorNodeDefinition {\n const node = {\n type: \"selector\",\n ...parseAttributeTokens(tokens, stringLiteralPlaceholders)\n } as SelectorNodeDefinition;\n\n // This is a composite node, so we expect an opening '{'.\n popAndCheck(tokens, \"{\");\n\n // Return the selector node definition.\n return node;\n}\n\n/**\n * Creates a parallel node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The parallel node JSON definition.\n */\nfunction createParallelNode(\n tokens: string[],\n stringLiteralPlaceholders: StringLiteralPlaceholders\n): ParallelNodeDefinition {\n const node = {\n type: \"parallel\",\n ...parseAttributeTokens(tokens, stringLiteralPlaceholders)\n } as ParallelNodeDefinition;\n\n // This is a composite node, so we expect an opening '{'.\n popAndCheck(tokens, \"{\");\n\n // Return the parallel node definition.\n return node;\n}\n\n/**\n * Creates a lotto node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The lotto node JSON definition.\n */\nfunction createLottoNode(tokens: string[], stringLiteralPlaceholders: StringLiteralPlaceholders): LottoNodeDefinition {\n // If any node arguments have been defined then they must be our weights.\n const nodeArguments = parseArgumentTokens(tokens, stringLiteralPlaceholders);\n\n // All lotto node arguments MUST be of type number and must be integer.\n nodeArguments\n .filter((arg) => arg.type !== \"number\" || !arg.isInteger)\n .forEach(() => {\n throw new Error(`lotto node weight arguments must be integer values`);\n });\n\n const node = {\n type: \"lotto\",\n weights: nodeArguments.map(({ value }) => value),\n ...parseAttributeTokens(tokens, stringLiteralPlaceholders)\n } as LottoNodeDefinition;\n\n // This is a composite node, so we expect an opening '{'.\n popAndCheck(tokens, \"{\");\n\n // Return the lotto node definition.\n return node;\n}\n\n/**\n * Creates an action node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The action node JSON definition.\n */\nfunction createActionNode(\n tokens: string[],\n stringLiteralPlaceholders: StringLiteralPlaceholders\n): ActionNodeDefinition {\n // Parse any node arguments, we should have at least one which will be an identifier argument for the action name\n // and agent function to invoke for the action, all other arguments are to be passed as arguments to that function.\n const [actionNameIdentifier, ...agentFunctionArgs] = parseArgumentTokens(tokens, stringLiteralPlaceholders);\n\n // Our first argument MUST be defined and be an identifier as we require an action name argument.\n if (actionNameIdentifier?.type !== \"identifier\") {\n throw new Error(\"expected action name identifier argument\");\n }\n\n // Only the first argument should have been an identifier, all agent function arguments must be string, number, boolean or null.\n agentFunctionArgs\n .filter((arg) => arg.type === \"identifier\")\n .forEach((arg) => {\n throw new Error(\n `invalid action node argument value '${arg.value}', must be string, number, boolean or null`\n );\n });\n\n // Return the action node definition.\n return {\n type: \"action\",\n call: actionNameIdentifier.value,\n args: agentFunctionArgs.map(({ value }) => value),\n ...parseAttributeTokens(tokens, stringLiteralPlaceholders)\n };\n}\n\n/**\n * Creates a condition node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The condition node JSON definition.\n */\nfunction createConditionNode(\n tokens: string[],\n stringLiteralPlaceholders: StringLiteralPlaceholders\n): ConditionNodeDefinition {\n // Parse any node arguments, we should have at least one which will be an identifier argument for the condition name\n // and agent function to invoke for the condition, all other arguments are to be passed as arguments to that function.\n const [conditionNameIdentifier, ...agentFunctionArgs] = parseArgumentTokens(tokens, stringLiteralPlaceholders);\n\n // Our first argument MUST be defined and be an identifier as we require a condition name argument.\n if (conditionNameIdentifier?.type !== \"identifier\") {\n throw new Error(\"expected condition name identifier argument\");\n }\n\n // Only the first argument should have been an identifier, all agent function arguments must be string, number, boolean or null.\n agentFunctionArgs\n .filter((arg) => arg.type === \"identifier\")\n .forEach((arg) => {\n throw new Error(\n `invalid condition node argument value '${arg.value}', must be string, number, boolean or null`\n );\n });\n\n // Return the condition node definition.\n return {\n type: \"condition\",\n call: conditionNameIdentifier.value,\n args: agentFunctionArgs.map(({ value }) => value),\n ...parseAttributeTokens(tokens, stringLiteralPlaceholders)\n };\n}\n\n/**\n * Creates a wait node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The wait node JSON definition.\n */\nfunction createWaitNode(tokens: string[], stringLiteralPlaceholders: StringLiteralPlaceholders): WaitNodeDefinition {\n let node = { type: \"wait\" } as WaitNodeDefinition;\n\n // Get the node arguments.\n const nodeArguments = parseArgumentTokens(tokens, stringLiteralPlaceholders);\n\n // The arguments of a wait node are optional. We may have:\n // - No node arguments, in which case the wait will be indefinite until it is aborted.\n // - One node argument which will be the explicit duration of the wait.\n // - Two node arguments which define the min and max duration bounds from which a random duration will be picked.\n if (nodeArguments.length) {\n // All wait node arguments MUST be of type number and must be integer.\n nodeArguments\n .filter((arg) => arg.type !== \"number\" || !arg.isInteger)\n .forEach(() => {\n throw new Error(`wait node duration arguments must be integer values`);\n });\n\n // We may have:\n // - One node argument which will be the explicit duration of the wait.\n // - Two node arguments which define the min and max duration bounds from which a random duration will be picked.\n // - Too many arguments, which is not valid.\n if (nodeArguments.length === 1) {\n // An explicit duration was defined.\n node.duration = nodeArguments[0].value as number;\n } else if (nodeArguments.length === 2) {\n // Min and max duration bounds were defined from which a random duration will be picked.\n node.duration = [nodeArguments[0].value as number, nodeArguments[1].value as number];\n } else if (nodeArguments.length > 2) {\n // An incorrect number of duration arguments were defined.\n throw new Error(\"invalid number of wait node duration arguments defined\");\n }\n }\n\n // Return the wait node definition.\n return { ...node, ...parseAttributeTokens(tokens, stringLiteralPlaceholders) };\n}\n\n/**\n * Creates a branch node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The branch node JSON definition.\n */\nfunction createBranchNode(\n tokens: string[],\n stringLiteralPlaceholders: StringLiteralPlaceholders\n): BranchNodeDefinition {\n // Parse any node arguments, we should have one which will be an identifier argument for the root ref.\n const nodeArguments = parseArgumentTokens(tokens, stringLiteralPlaceholders);\n\n // We should have only a single identifer argument for a branch node, which is the root ref.\n if (nodeArguments.length !== 1 || nodeArguments[0].type !== \"identifier\") {\n throw new Error(\"expected single branch name argument\");\n }\n\n // Return the branch node definition.\n return { type: \"branch\", ref: nodeArguments[0].value };\n}\n", "import { RootNodeDefinition } from \"./BehaviourTreeDefinition\";\nimport { flattenDefinition, isBranchNode, isInteger } from \"./BehaviourTreeDefinitionUtilities\";\nimport { convertMDSLToJSON } from \"./mdsl/MDSLDefinitionParser\";\n\n/**\n * An object representing the result of validating a tree definition.\n */\nexport type DefinitionValidationResult = {\n /**\n * A flag defining whether validation succeeded.\n */\n succeeded: boolean;\n /**\n * A string containing the error message if validation did not succeed.\n */\n errorMessage?: string;\n};\n\n/**\n * Validates the specified behaviour tree definition in the form of JSON or MDSL.\n * @param definition The behaviour tree definition in the form of JSON or MDSL.\n * @returns An object representing the result of validating the given tree definition.\n */\nexport function validateDefinition(definition: any): DefinitionValidationResult {\n // A helper function to create a failure validation result with the given error message.\n const createFailureResult = (errorMessage: string) => ({ succeeded: false, errorMessage });\n\n // The definition must be defined.\n if (definition === null || typeof definition === \"undefined\") {\n return createFailureResult(\"definition is null or undefined\");\n }\n\n let rootNodeDefinitions: any[];\n\n // We are expecting a definition in one of three different forms:\n // - A string which we will assume is mdsl and we will parse this to JSON before validation.\n // - An array which we will assume is an array of root node definitions with at least one being the primary root node (no 'id' property)\n // - An object which we will assume is the primary root node and should not have an 'id' property.\n if (typeof definition === \"string\") {\n try {\n // The definition is a string which we can assume is mdsl, so attempt to parse it to a JSON definition in the form of an array of root node definitions.\n rootNodeDefinitions = convertMDSLToJSON(definition);\n } catch (error) {\n // We failed to parse the JSON from the mdsl, this is likely to be the result of it not being a valid mdsl string.\n return createFailureResult(`invalid mdsl: ${definition}`);\n }\n } else if (typeof definition === \"object\") {\n // The definition will either be an array (of root node definitions) or an object (the single primary root node definition).\n // If our definition is an array, we should verify that each of the elements within it are objects (potential root node definitions).\n if (Array.isArray(definition)) {\n // Find any invalid node definitions in our definition array, not full validation just a check that each is a valid object.\n const invalidDefinitionElements = definition.filter((element) => {\n // Each element isn't valid unless it is an object that isn't also an array and isn't null.\n return typeof element !== \"object\" || Array.isArray(element) || element === null;\n });\n\n // If we have any invalid node definitions then validation has failed.\n if (invalidDefinitionElements.length) {\n return createFailureResult(\n \"invalid elements in definition array, each must be an root node definition object\"\n );\n }\n\n // Our definition is already an array of root node definition objects.\n rootNodeDefinitions = definition;\n } else {\n // Our definition is an object, but we want an array of root node definitions.\n rootNodeDefinitions = [definition];\n }\n } else {\n return createFailureResult(`unexpected definition type of '${typeof definition}'`);\n }\n\n // Iterate over our array of root nodes and call validateNode for each, passing an initial depth of 0, wrapped in a try catch to handle validation failures.\n try {\n rootNodeDefinitions.forEach((rootNodeDefinition) => validateNode(rootNodeDefinition, 0));\n } catch (error) {\n // Handle cases where we have caught a thrown Error and return a failure result with the error message.\n if (error instanceof Error) {\n return createFailureResult(error.message);\n }\n\n // No idea what happened here!\n return createFailureResult(`unexpected error: ${error}`);\n }\n\n // Unpack all of the root node definitions into arrays of main ('id' defined) and sub ('id' not defined) root node definitions.\n const mainRootNodeDefinitions = rootNodeDefinitions.filter(({ id }) => typeof id === \"undefined\");\n const subRootNodeDefinitions = rootNodeDefinitions.filter(({ id }) => typeof id === \"string\" && id.length > 0);\n\n // We should ALWAYS have exactly one root node definition without an 'id' property defined, which is out main root node definition.\n if (mainRootNodeDefinitions.length !== 1) {\n return createFailureResult(\"expected single root node without 'id' property defined to act as main root\");\n }\n\n // We should never have duplicate 'id' properties across our sub root node definitions.\n const subRootNodeIdenitifers: string[] = [];\n for (const { id } of subRootNodeDefinitions) {\n // Have we already come across this 'id' property value?\n if (subRootNodeIdenitifers.includes(id)) {\n return createFailureResult(`multiple root nodes found with duplicate 'id' property value of '${id}'`);\n }\n\n subRootNodeIdenitifers.push(id);\n }\n\n // Check for any branch node circular depedencies. This will not include any globally registered subtrees.\n const circularDependencyPath = findBranchCircularDependencyPath(rootNodeDefinitions);\n\n // If we found a circular dependency in our root node and branch node definitions then the definition is definitely not valid.\n if (circularDependencyPath) {\n return createFailureResult(`circular dependency found in branch node references: ${circularDependencyPath}`);\n }\n\n // Our definition was valid!\n return { succeeded: true };\n}\n\n/**\n * Find the first circular depdendency path present in the array of root node definitions, or null if one doesn't exist.\n * This will not consider branch nodes that reference any globally registered subtrees.\n * @param rootNodeDefinitions The array of root node definitions.\n * @returns The first circular depdendency path present in the array of root node definitions as string, or null if one doesn't exist.\n */\nfunction findBranchCircularDependencyPath(rootNodeDefinitions: RootNodeDefinition[]): string | null {\n // Create a mapping of root node identifiers to other root nodes that they reference via branch nodes.\n // Below is an example of a mapping that includes a circular dependency (root => a => b => c => a)\n // [{ refs: [\"a\", \"b\"] }, { id: \"a\", refs: [\"b\"] }, { id: \"b\", refs: [\"c\"] }, { id: \"c\", refs: [\"a\"] }]\n const rootNodeMappings: { id: string | undefined; refs: string[] }[] = rootNodeDefinitions.map(\n (rootNodeDefinition) => ({\n id: rootNodeDefinition.id,\n refs: flattenDefinition(rootNodeDefinition)\n .filter(isBranchNode)\n .map(({ ref }) => ref)\n })\n );\n\n let badPathFormatted: string | null = null;\n\n // A recursive function to walk through the mappings, keeping track of which root nodes we have visited in the form of a path of root node identifiers.\n const followRefs = (mapping: { id: string | undefined; refs: string[] }, path: (string | undefined)[] = []) => {\n // Have we found a circular dependency?\n if (path.includes(mapping.id)) {\n // We found a circular dependency! Get the bad path of root node identifiers.\n const badPath = [...path, mapping.id];\n\n // Set the formatted path value. [undefined, \"a\", \"b\", \"c\", \"a\"] would be formatted as \"a -> b -> c -> a\".\n badPathFormatted = badPath.map((element) => !!element).join(\" => \");\n\n // No need to continue, we found a circular dependency.\n return;\n }\n\n for (const ref of mapping.refs) {\n // Find the mapping for the root node with an identifer matching the current ref.\n const subMapping = rootNodeMappings.find(({ id }) => id === ref);\n\n // We may not have a mapping for this ref, which will happen if this ref is for a globally registered subtree.\n if (subMapping) {\n followRefs(subMapping, [...path, mapping.id]);\n }\n }\n };\n\n return badPathFormatted;\n}\n\n/**\n * Validate an object that we expect to be a node definition.\n * @param definition An object that we expect to be a node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateNode(definition: any, depth: number): void {\n // Every node must be valid object and have a non-empty 'type' string property.\n if (typeof definition !== \"object\" || typeof definition.type !== \"string\" || definition.type.length === 0) {\n throw new Error(\n `node definition is not an object or 'type' property is not a non-empty string at depth '${depth}'`\n );\n }\n\n // How we validate this node definition will depend on its type.\n switch (definition.type) {\n case \"action\":\n validateActionNode(definition, depth);\n break;\n\n case \"condition\":\n validateConditionNode(definition, depth);\n break;\n\n case \"wait\":\n validateWaitNode(definition, depth);\n break;\n\n case \"branch\":\n validateBranchNode(definition, depth);\n break;\n\n case \"root\":\n validateRootNode(definition, depth);\n break;\n\n case \"success\":\n validateSuccessNode(definition, depth);\n break;\n\n case \"fail\":\n validateFailNode(definition, depth);\n break;\n\n case \"flip\":\n validateFlipNode(definition, depth);\n break;\n\n case \"repeat\":\n validateRepeatNode(definition, depth);\n break;\n\n case \"retry\":\n validateRetryNode(definition, depth);\n break;\n\n case \"sequence\":\n validateSequenceNode(definition, depth);\n break;\n\n case \"selector\":\n validateSelectorNode(definition, depth);\n break;\n\n case \"parallel\":\n validateParallelNode(definition, depth);\n break;\n\n default:\n throw new Error(`unexpected node type of '${definition.type}' at depth '${depth}'`);\n }\n}\n\n/**\n * Validate any attributes for a given node definition.\n * @param definition The node definition.\n * @param depth The depth of the node in the behaviour tree definition.\n */\nfunction validateNodeAttributes(definition: any, depth: number): void {\n // Validate each of the attribute types for this node.\n [\"while\", \"until\", \"entry\", \"exit\", \"step\"].forEach((attributeName) => {\n // Attempt to grab the definition for the current attribute from the node definition.\n const attributeDefinition = definition[attributeName];\n\n // All node attributes are optional, so there is nothing to do if the current attribute is not defined.\n if (typeof attributeDefinition === \"undefined\") {\n return;\n }\n\n // The attribute definition must be an object.\n if (typeof attributeDefinition !== \"object\") {\n throw new Error(\n `expected attribute '${attributeName}' to be an object for '${definition.type}' node at depth '${depth}'`\n );\n }\n\n // The 'call' property must be defined for any attribute definition.\n if (typeof attributeDefinition.call !== \"string\" || attributeDefinition.call.length === 0) {\n throw new Error(\n `expected 'call' property for attribute '${attributeName}' to be a non-empty string for '${definition.type}' node at depth '${depth}'`\n );\n }\n\n // If any node attribute arguments have been defined then they must have been defined in an array.\n if (typeof attributeDefinition.args !== \"undefined\" && !Array.isArray(attributeDefinition.args)) {\n throw new Error(\n `expected 'args' property for attribute '${attributeName}' to be an array for '${definition.type}' node at depth '${depth}'`\n );\n }\n });\n}\n\n/**\n * Validate an object that we expect to be a root node definition.\n * @param definition An object that we expect to be a root node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateRootNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"root\") {\n throw new Error(\"expected node type of 'root' for root node\");\n }\n\n // A root node cannot be the child of another node.\n if (depth > 0) {\n throw new Error(\"a root node cannot be the child of another node\");\n }\n\n // Check that, if the root node 'id' property is defined, it is a non-empty string.\n if (typeof definition.id !== \"undefined\" && (typeof definition.id !== \"string\" || definition.id.length === 0)) {\n throw new Error(\"expected non-empty string for 'id' property if defined for root node\");\n }\n\n // A root node is a decorator node, so must have a child node defined.\n if (typeof definition.child === \"undefined\") {\n throw new Error(\"expected property 'child' to be defined for root node\");\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n\n // Validate the child node of this decorator node.\n validateNode(definition.child, depth + 1);\n}\n\n/**\n * Validate an object that we expect to be a success node definition.\n * @param definition An object that we expect to be a success node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateSuccessNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"success\") {\n throw new Error(`expected node type of 'success' for success node at depth '${depth}'`);\n }\n\n // A success node is a decorator node, so must have a child node defined.\n if (typeof definition.child === \"undefined\") {\n throw new Error(`expected property 'child' to be defined for success node at depth '${depth}'`);\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n\n // Validate the child node of this decorator node.\n validateNode(definition.child, depth + 1);\n}\n\n/**\n * Validate an object that we expect to be a fail node definition.\n * @param definition An object that we expect to be a fail node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateFailNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"fail\") {\n throw new Error(`expected node type of 'fail' for fail node at depth '${depth}'`);\n }\n\n // A fail node is a decorator node, so must have a child node defined.\n if (typeof definition.child === \"undefined\") {\n throw new Error(`expected property 'child' to be defined for fail node at depth '${depth}'`);\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n\n // Validate the child node of this decorator node.\n validateNode(definition.child, depth + 1);\n}\n\n/**\n * Validate an object that we expect to be a flip node definition.\n * @param definition An object that we expect to be a flip node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateFlipNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"flip\") {\n throw new Error(`expected node type of 'flip' for flip node at depth '${depth}'`);\n }\n\n // A flip node is a decorator node, so must have a child node defined.\n if (typeof definition.child === \"undefined\") {\n throw new Error(`expected property 'child' to be defined for flip node at depth '${depth}'`);\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n\n // Validate the child node of this decorator node.\n validateNode(definition.child, depth + 1);\n}\n\n/**\n * Validate an object that we expect to be a repeat node definition.\n * @param definition An object that we expect to be a repeat node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateRepeatNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"repeat\") {\n throw new Error(`expected node type of 'repeat' for repeat node at depth '${depth}'`);\n }\n\n // A repeat node is a decorator node, so must have a child node defined.\n if (typeof definition.child === \"undefined\") {\n throw new Error(`expected property 'child' to be defined for repeat node at depth '${depth}'`);\n }\n\n // Check whether an 'iterations' property has been defined, it may not have been if this node is to repeat indefinitely.\n if (typeof definition.iterations !== \"undefined\") {\n if (Array.isArray(definition.iterations)) {\n // Check whether any elements of the array are not integer values.\n const containsNonInteger = !!definition.iterations.find((value: unknown) => !isInteger(value));\n\n // If the 'iterations' property is an array then it MUST contain two integer values.\n if (definition.iterations.length !== 2 || containsNonInteger) {\n throw new Error(\n `expected array containing two integer values for 'iterations' property if defined for repeat node at depth '${depth}'`\n );\n }\n } else if (!isInteger(definition.iterations)) {\n throw new Error(\n `expected integer value or array containing two integer values for 'iterations' property if defined for repeat node at depth '${depth}'`\n );\n }\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n\n // Validate the child node of this decorator node.\n validateNode(definition.child, depth + 1);\n}\n\n/**\n * Validate an object that we expect to be a retry node definition.\n * @param definition An object that we expect to be a retry node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateRetryNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"retry\") {\n throw new Error(`expected node type of 'retry' for retry node at depth '${depth}'`);\n }\n\n // A retry node is a decorator node, so must have a child node defined.\n if (typeof definition.child === \"undefined\") {\n throw new Error(`expected property 'child' to be defined for retry node at depth '${depth}'`);\n }\n\n // Check whether an 'attempts' property has been defined, it may not have been if this node is to retry indefinitely.\n if (typeof definition.attempts !== \"undefined\") {\n if (Array.isArray(definition.attempts)) {\n // Check whether any elements of the array are not integer values.\n const containsNonInteger = !!definition.attempts.find((value: unknown) => !isInteger(value));\n\n // If the 'attempts' property is an array then it MUST contain two integer values.\n if (definition.attempts.length !== 2 || containsNonInteger) {\n throw new Error(\n `expected array containing two integer values for 'attempts' property if defined for retry node at depth '${depth}'`\n );\n }\n } else if (!isInteger(definition.attempts)) {\n throw new Error(\n `expected integer value or array containing two integer values for 'attempts' property if defined for retry node at depth '${depth}'`\n );\n }\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n\n // Validate the child node of this decorator node.\n validateNode(definition.child, depth + 1);\n}\n\n/**\n * Validate an object that we expect to be a branch node definition.\n * @param definition An object that we expect to be a branch node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateBranchNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"branch\") {\n throw new Error(`expected node type of 'branch' for branch node at depth '${depth}'`);\n }\n\n // Check that the branch node 'ref' property is defined and is a non-empty string.\n if (typeof definition.ref !== \"string\" || definition.ref.length === 0) {\n throw new Error(`expected non-empty string for 'ref' property for branch node at depth '${depth}'`);\n }\n\n // It is invalid to define guard attributes for a branch node as they should be defined on the referenced root node.\n [\"while\", \"until\"].forEach((attributeName) => {\n if (typeof definition[attributeName] !== \"undefined\") {\n throw new Error(\n `guards should not be defined for branch nodes but guard '${attributeName}' was defined for branch node at depth '${depth}'`\n );\n }\n });\n\n // It is invalid to define callback attributes for a branch node as they should be defined on the referenced root node.\n [\"entry\", \"exit\", \"step\"].forEach((attributeName) => {\n if (typeof definition[attributeName] !== \"undefined\") {\n throw new Error(\n `callbacks should not be defined for branch nodes but callback '${attributeName}' was defined for branch node at depth '${depth}'`\n );\n }\n });\n}\n\n/**\n * Validate an object that we expect to be a action node definition.\n * @param definition An object that we expect to be a action node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateActionNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"action\") {\n throw new Error(`expected node type of 'action' for action node at depth '${depth}'`);\n }\n\n // The 'call' property must be defined for a action node definition.\n if (typeof definition.call !== \"string\" || definition.call.length === 0) {\n throw new Error(`expected non-empty string for 'call' property of action node at depth '${depth}'`);\n }\n\n // If any action function arguments have been defined then they must have been defined in an array.\n if (typeof definition.args !== \"undefined\" && !Array.isArray(definition.args)) {\n throw new Error(`expected array for 'args' property if defined for action node at depth '${depth}'`);\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n}\n\n/**\n * Validate an object that we expect to be a condition node definition.\n * @param definition An object that we expect to be a condition node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateConditionNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"condition\") {\n throw new Error(`expected node type of 'condition' for condition node at depth '${depth}'`);\n }\n\n // The 'call' property must be defined for a condition node definition.\n if (typeof definition.call !== \"string\" || definition.call.length === 0) {\n throw new Error(`expected non-empty string for 'call' property of condition node at depth '${depth}'`);\n }\n\n // If any condition function arguments have been defined then they must have been defined in an array.\n if (typeof definition.args !== \"undefined\" && !Array.isArray(definition.args)) {\n throw new Error(`expected array for 'args' property if defined for condition node at depth '${depth}'`);\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n}\n\n/**\n * Validate an object that we expect to be a wait node definition.\n * @param definition An object that we expect to be a wait node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateWaitNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"wait\") {\n throw new Error(`expected node type of 'wait' for wait node at depth '${depth}'`);\n }\n\n // Check whether a 'duration' property has been defined, it may not have been if this node is to wait indefinitely.\n if (typeof definition.duration !== \"undefined\") {\n if (Array.isArray(definition.duration)) {\n // Check whether any elements of the array are not integer values.\n const containsNonInteger = !!definition.duration.find((value: unknown) => !isInteger(value));\n\n // If the 'duration' property is an array then it MUST contain two integer values.\n if (definition.duration.length !== 2 || containsNonInteger) {\n throw new Error(\n `expected array containing two integer values for 'duration' property if defined for wait node at depth '${depth}'`\n );\n }\n } else if (!isInteger(definition.duration)) {\n throw new Error(\n `expected integer value or array containing two integer values for 'duration' property if defined for wait node at depth '${depth}'`\n );\n }\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n}\n\n/**\n * Validate an object that we expect to be a sequence node definition.\n * @param definition An object that we expect to be a sequence node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateSequenceNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"sequence\") {\n throw new Error(`expected node type of 'sequence' for sequence node at depth '${depth}'`);\n }\n\n // A sequence node is a composite node, so must have a children nodes array defined.\n if (!Array.isArray(definition.children) || definition.children.length === 0) {\n throw new Error(`expected non-empty 'children' array to be defined for sequence node at depth '${depth}'`);\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n\n // Validate the child nodes of this composite node.\n definition.children.forEach((child: any) => validateNode(child, depth + 1));\n}\n\n/**\n * Validate an object that we expect to be a selector node definition.\n * @param definition An object that we expect to be a selector node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateSelectorNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"selector\") {\n throw new Error(`expected node type of 'selector' for selector node at depth '${depth}'`);\n }\n\n // A selector node is a composite node, so must have a children nodes array defined.\n if (!Array.isArray(definition.children) || definition.children.length === 0) {\n throw new Error(`expected non-empty 'children' array to be defined for selector node at depth '${depth}'`);\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n\n // Validate the child nodes of this composite node.\n definition.children.forEach((child: any) => validateNode(child, depth + 1));\n}\n\n/**\n * Validate an object that we expect to be a parallel node definition.\n * @param definition An object that we expect to be a parallel node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateParallelNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"parallel\") {\n throw new Error(`expected node type of 'parallel' for parallel node at depth '${depth}'`);\n }\n\n // A parallel node is a composite node, so must have a children nodes array defined.\n if (!Array.isArray(definition.children) || definition.children.length === 0) {\n throw new Error(`expected non-empty 'children' array to be defined for parallel node at depth '${depth}'`);\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n\n // Validate the child nodes of this composite node.\n definition.children.forEach((child: any) => validateNode(child, depth + 1));\n}\n", "import Node from \"../../nodes/Node\";\n\n/**\n * An exception thrown when evaluating node guard path conditions and a conditions fails.\n */\nexport default class GuardUnsatisifedException extends Error {\n /**\n * @param source The node at which a guard condition failed.\n */\n constructor(private source: Node) {\n super(\"A guard path condition has failed\");\n }\n\n /**\n * Gets whether the specified node is the node at which a guard condition failed.\n * @param node The node to check against the source node.\n * @returns Whether the specified node is the node at which a guard condition failed.\n */\n isSourceNode = (node: Node) => node === this.source;\n}\n", "import { Agent } from \"../../Agent\";\nimport Guard from \"./Guard\";\nimport Node from \"../../nodes/Node\";\nimport GuardUnsatisifedException from \"./GuardUnsatisifedException\";\n\nexport type GuardPathPart = {\n node: Node;\n guards: Guard[];\n};\n\n/**\n * Represents a path of node guards along a root-to-leaf tree path.\n */\nexport default class GuardPath {\n /**\n * @param nodes An array of objects defining a node instance -> guard link, ordered by node depth.\n */\n constructor(private nodes: GuardPathPart[]) {}\n\n /**\n * Evaluate guard conditions for all guards in the tree path, moving outwards from the root.\n * @param agent The agent, required for guard evaluation.\n * @returns An evaluation results object.\n */\n evaluate = (agent: Agent) => {\n // We need to evaluate guard conditions for nodes up the tree, moving outwards from the root.\n for (const details of this.nodes) {\n // There can be multiple guards per node.\n for (const guard of details.guards) {\n // Check whether the guard condition passes, and throw an exception if not.\n if (!guard.isSatisfied(agent)) {\n throw new GuardUnsatisifedException(details.node);\n }\n }\n }\n };\n}\n", "import { Agent } from \"../Agent\";\nimport Attribute from \"../attributes/Attribute\";\nimport Entry from \"../attributes/callbacks/Entry\";\nimport Exit from \"../attributes/callbacks/Exit\";\nimport Step from \"../attributes/callbacks/Step\";\nimport Guard from \"../attributes/guards/Guard\";\nimport GuardPath from \"../attributes/guards/GuardPath\";\nimport GuardUnsatisifedException from \"../attributes/guards/GuardUnsatisifedException\";\nimport { BehaviourTreeOptions } from \"../BehaviourTreeOptions\";\nimport { AnyArgument } from \"../RootAstNodesBuilder\";\nimport State, { AnyState } from \"../State\";\nimport Leaf from \"./leaf/Leaf\";\n\n/**\n * A base node.\n */\nexport default abstract class Node {\n /**\n * The node uid.\n */\n private readonly uid: string = createNodeUid();\n /**\n * The node state.\n */\n private state: AnyState = State.READY;\n /**\n * The guard path to evaluate as part of a node update.\n */\n private guardPath: GuardPath | undefined;\n\n /**\n * @param type The node type.\n * @param attributes The node attributes.\n * @param args The node argument definitions.\n */\n constructor(private type: string, private attributes: Attribute[], private args: AnyArgument[]) {}\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected abstract onUpdate(agent: Agent, options: BehaviourTreeOptions): void;\n\n /**\n * Gets the name of the node.\n */\n public abstract getName(): string;\n\n /**\n * Gets whether this node is a leaf node.\n */\n public abstract isLeafNode: () => this is Leaf;\n\n /**\n * Gets/Sets the state of the node.\n */\n getState = (): AnyState => this.state;\n setState = (value: AnyState): void => {\n this.state = value;\n };\n\n /**\n * Gets the unique id of the node.\n */\n getUid = () => this.uid;\n\n /**\n * Gets the type of the node.\n */\n getType = () => this.type;\n\n /**\n * Gets the node attributes.\n */\n getAttributes = () => this.attributes;\n\n /**\n * Gets the node arguments.\n */\n getArguments = () => this.args;\n\n /**\n * Gets the node attribute with the specified type, or null if it does not exist.\n */\n getAttribute(type: \"entry\" | \"ENTRY\"): Entry;\n getAttribute(type: \"exit\" | \"EXIT\"): Exit;\n getAttribute(type: \"step\" | \"STEP\"): Step;\n getAttribute(type: string): Attribute {\n return (\n this.getAttributes().filter((decorator) => decorator.getType().toUpperCase() === type.toUpperCase())[0] ||\n null\n );\n }\n\n /**\n * Gets the node attributes.\n */\n getGuardAttributes = (): Guard[] => this.getAttributes().filter((decorator) => decorator.isGuard()) as Guard[];\n\n /**\n * Sets the guard path to evaluate as part of a node update.\n */\n setGuardPath = (value: GuardPath) => (this.guardPath = value);\n\n /**\n * Gets whether a guard path is assigned to this node.\n */\n hasGuardPath = () => !!this.guardPath;\n\n /**\n * Gets whether this node is in the specified state.\n * @param value The value to compare to the node state.\n */\n public is(value: AnyState): boolean {\n return this.state === value;\n }\n\n /**\n * Reset the state of the node.\n */\n public reset(): void {\n this.setState(State.READY);\n }\n\n /**\n * Abort the running of this node.\n * @param agent The agent.\n */\n public abort(agent: Agent): void {\n // There is nothing to do if this node is not in the running state.\n if (!this.is(State.RUNNING)) {\n return;\n }\n\n // Reset the state of this node.\n this.reset();\n\n this.getAttribute(\"exit\")?.callAgentFunction(agent, false, true);\n }\n\n /**\n * Update the node.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n * @returns The result of the update.\n */\n public update(agent: Agent, options: BehaviourTreeOptions): void {\n // If this node is already in a 'SUCCEEDED' or 'FAILED' state then there is nothing to do.\n if (this.is(State.SUCCEEDED) || this.is(State.FAILED)) {\n return;\n }\n\n try {\n // Evaluate all of the guard path conditions for the current tree path.\n this.guardPath!.evaluate(agent);\n\n // If this node is in the READY state then call the ENTRY for this node if it exists.\n if (this.is(State.READY)) {\n this.getAttribute(\"entry\")?.callAgentFunction(agent);\n }\n\n this.getAttribute(\"step\")?.callAgentFunction(agent);\n\n // Do the actual update.\n this.onUpdate(agent, options);\n\n // If this node is now in a 'SUCCEEDED' or 'FAILED' state then call the EXIT for this node if it exists.\n if (this.is(State.SUCCEEDED) || this.is(State.FAILED)) {\n this.getAttribute(\"exit\")?.callAgentFunction(agent, this.is(State.SUCCEEDED), false);\n }\n } catch (error) {\n // If the error is a GuardUnsatisfiedException then we need to determine if this node is the source.\n if (error instanceof GuardUnsatisifedException && error.isSourceNode(this)) {\n // Abort the current node.\n this.abort(agent);\n\n // Any node that is the source of an abort will be a failed node.\n this.setState(State.FAILED);\n } else {\n throw error;\n }\n }\n }\n}\n\n/**\n * Create a randomly generated node uid.\n * @returns A randomly generated node uid.\n */\nfunction createNodeUid(): string {\n var S4 = function () {\n return (((1 + Math.random()) * 0x10000) | 0).toString(16).substring(1);\n };\n return S4() + S4() + \"-\" + S4() + \"-\" + S4() + \"-\" + S4() + \"-\" + S4() + S4() + S4();\n}\n", "import Node from \"../Node\";\n\n/**\n * A leaf node.\n */\nexport default abstract class Leaf extends Node {\n /**\n * Gets whether this node is a leaf node.\n */\n isLeafNode = () => true;\n}\n", "import { ActionResult, Agent, ExitFunctionArg, FunctionArg, GlobalFunction } from \"./Agent\";\nimport { AnyArgument, RootAstNode } from \"./RootAstNodesBuilder\";\n\n// Exit callbacks receive their own special type of argument.\n// There's probably stricter ways to represent this but it feels overly complex right now.\ntype ExitResultArg = { value: ExitFunctionArg };\nexport type AnyExitArgument = AnyArgument | ExitResultArg;\n\nexport type InvokerFunction = (args: AnyExitArgument[]) => ActionResult;\n\n/**\n * A singleton used to store and lookup registered functions and subtrees.\n */\nexport default class Lookup {\n /**\n * The object holding any registered functions keyed on function name.\n */\n private static functionTable: { [key: string]: GlobalFunction } = {};\n /**\n * The object holding any registered sub-trees keyed on tree name.\n */\n private static subtreeTable: { [key: string]: RootAstNode } = {};\n\n /**\n * Gets the function with the specified name.\n * @param name The name of the function.\n * @returns The function with the specified name.\n */\n public static getFunc(name: string): GlobalFunction {\n return this.functionTable[name];\n }\n\n /**\n * Sets the function with the specified name for later lookup.\n * @param name The name of the function.\n * @param func The function.\n */\n public static setFunc(name: string, func: GlobalFunction): void {\n this.functionTable[name] = func;\n }\n\n /**\n * Gets the function invoker for the specified agent and function name.\n * If a function with the specified name exists on the agent object then it will\n * be returned, otherwise we will then check the registered functions for a match.\n * @param agent The agent instance that this behaviour tree is modelling behaviour for.\n * @param name The function name.\n * @returns The function invoker for the specified agent and function name.\n */\n static getFuncInvoker(agent: Agent, name: string): InvokerFunction | null {\n // Check whether the agent contains the specified function.\n const foundOnAgent = agent[name];\n if (foundOnAgent && typeof foundOnAgent === \"function\") {\n return (args: AnyExitArgument[]): boolean | ActionResult =>\n foundOnAgent.apply(\n agent,\n args.map((arg) => arg.value)\n );\n }\n\n // The agent does not contain the specified function but it may have been registered at some point.\n if (this.functionTable[name] && typeof this.functionTable[name] === \"function\") {\n return (args: AnyExitArgument[]) => this.functionTable[name](agent, ...args.map((arg) => arg.value));\n }\n\n // We have no function to invoke.\n return null;\n }\n\n /**\n * Gets the subtree with the specified name.\n * @param name The name of the subtree.\n * @returns The subtree with the specified name.\n */\n static getSubtree(name: string): RootAstNode {\n return this.subtreeTable[name];\n }\n\n /**\n * Sets the subtree with the specified name for later lookup.\n * @param name The name of the subtree.\n * @param subtree The subtree.\n */\n static setSubtree(name: string, subtree: RootAstNode) {\n this.subtreeTable[name] = subtree;\n }\n\n /**\n * Removes the registered function or subtree with the specified name.\n * @param name The name of the registered function or subtree.\n */\n static remove(name: string) {\n delete this.functionTable[name];\n delete this.subtreeTable[name];\n }\n\n /**\n * Remove all registered functions and subtrees.\n */\n static empty() {\n this.functionTable = {};\n this.subtreeTable = {};\n }\n}\n", "import Leaf from \"./Leaf\";\nimport State, { CompleteState } from \"../../State\";\nimport Lookup from \"../../Lookup\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { AnyArgument } from \"../../RootAstNodesBuilder\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * An Action leaf node.\n * This represents an immediate or ongoing state of behaviour.\n */\nexport default class Action extends Leaf {\n /**\n * @param attributes The node attributes.\n * @param actionName The action name.\n * @param actionArguments The array of action argument definitions.\n */\n constructor(attributes: Attribute[], private actionName: string, private actionArguments: AnyArgument[]) {\n super(\"action\", attributes, actionArguments);\n }\n\n /**\n * Whether there is a pending update promise.\n */\n private isUsingUpdatePromise = false;\n\n /**\n * The finished state result of an update promise.\n */\n private updatePromiseStateResult: CompleteState | null = null;\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // If the result of this action depends on an update promise then there is nothing to do until\n // it resolves, unless there has been a value set as a result of the update promise resolving.\n if (this.isUsingUpdatePromise) {\n // Check whether the update promise has resolved with a state value.\n if (this.updatePromiseStateResult) {\n // Set the state of this node to match the state returned by the promise.\n this.setState(this.updatePromiseStateResult);\n }\n\n return;\n }\n\n // Attempt to get the invoker for the action function.\n const actionFuncInvoker = Lookup.getFuncInvoker(agent, this.actionName);\n\n // The action function should be defined.\n if (actionFuncInvoker === null) {\n throw new Error(\n `cannot update action node as the action '${this.actionName}' function is not defined on the agent and has not been registered`\n );\n }\n\n // Call the action function, the result of which may be:\n // - The finished state of this action node.\n // - A promise to return a finished node state.\n // - Undefined if the node should remain in the running state.\n const updateResult = actionFuncInvoker(this.actionArguments) as CompleteState | Promise;\n\n if (updateResult instanceof Promise) {\n updateResult.then(\n (result) => {\n // If 'isUpdatePromisePending' is null then the promise was cleared as it was resolving, probably via an abort of reset.\n if (!this.isUsingUpdatePromise) {\n return;\n }\n\n // Check to make sure the result is a valid finished state.\n if (result !== State.SUCCEEDED && result !== State.FAILED) {\n throw new Error(\n \"action node promise resolved with an invalid value, expected a State.SUCCEEDED or State.FAILED value to be returned\"\n );\n }\n\n // Set pending update promise state result to be processed on next update.\n this.updatePromiseStateResult = result;\n },\n (reason) => {\n // If 'isUpdatePromisePending' is null then the promise was cleared as it was resolving, probably via an abort of reset.\n if (!this.isUsingUpdatePromise) {\n return;\n }\n\n // Just throw whatever was returned as the rejection argument.\n throw new Error(reason);\n }\n );\n\n // This node will be in the 'RUNNING' state until the update promise resolves.\n this.setState(State.RUNNING);\n\n // We are now waiting for the promise returned by the use to resolve before we know what state this node is in.\n this.isUsingUpdatePromise = true;\n } else {\n // Validate the returned value.\n this.validateUpdateResult(updateResult);\n\n // Set the state of this node, this may be undefined, which just means that the node is still in the 'RUNNING' state.\n this.setState(updateResult || State.RUNNING);\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => this.actionName;\n\n /**\n * Reset the state of the node.\n */\n reset = () => {\n // Reset the state of this node.\n this.setState(State.READY);\n\n // There is no longer an update promise that we care about.\n this.isUsingUpdatePromise = false;\n this.updatePromiseStateResult = null;\n };\n\n /**\n * Validate the result of an update function call.\n * @param result The result of an update function call.\n */\n private validateUpdateResult = (result: CompleteState | boolean) => {\n switch (result) {\n case State.SUCCEEDED:\n case State.FAILED:\n case undefined:\n return;\n default:\n throw new Error(\n `action '${this.actionName}' 'onUpdate' returned an invalid response, expected an optional State.SUCCEEDED or State.FAILED value to be returned`\n );\n }\n };\n}\n", "import Leaf from \"./Leaf\";\nimport State from \"../../State\";\nimport Lookup from \"../../Lookup\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { AnyArgument } from \"../../RootAstNodesBuilder\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A Condition leaf node.\n * This will succeed or fail immediately based on an agent predicate, without moving to the 'RUNNING' state.\n */\nexport default class Condition extends Leaf {\n /**\n * @param attributes The node attributes.\n * @param conditionName The name of the condition function.\n * @param conditionArguments The array of condition argument definitions.\n */\n constructor(attributes: Attribute[], private conditionName: string, private conditionArguments: AnyArgument[]) {\n super(\"condition\", attributes, conditionArguments);\n }\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // Attempt to get the invoker for the condition function.\n const conditionFuncInvoker = Lookup.getFuncInvoker(agent, this.conditionName);\n\n // The condition function should be defined.\n if (conditionFuncInvoker === null) {\n throw new Error(\n `cannot update condition node as the condition '${this.conditionName}' function is not defined on the agent and has not been registered`\n );\n }\n\n // Call the condition function to determine the state of this node.\n this.setState(!!conditionFuncInvoker(this.conditionArguments) ? State.SUCCEEDED : State.FAILED);\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => this.conditionName;\n}\n", "import Leaf from \"./Leaf\";\nimport State from \"../../State\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { Agent } from \"../../Agent\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A WAIT node.\n * The state of this node will change to SUCCEEDED after a duration of time\n */\nexport default class Wait extends Leaf {\n /**\n * @param attributes The node attributes.\n * @param duration The duration that this node will wait to succeed in milliseconds.\n * @param durationMin The minimum possible duration in milliseconds that this node will wait to succeed.\n * @param durationMax The maximum possible duration in milliseconds that this node will wait to succeed.\n */\n constructor(\n attributes: Attribute[],\n private duration: number | null,\n private durationMin: number | null,\n private durationMax: number | null\n ) {\n super(\"wait\", attributes, []);\n }\n\n /**\n * The time in milliseconds at which this node was first updated.\n */\n private initialUpdateTime: number = 0;\n\n /**\n * The total duration in milliseconds that this node will be waiting for.\n */\n private totalDuration: number | null = null;\n\n /**\n * The duration in milliseconds that this node has been waiting for.\n */\n private waitedDuration: number = 0;\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // If this node is in the READY state then we need to set the initial update time.\n if (this.is(State.READY)) {\n // Set the initial update time.\n this.initialUpdateTime = new Date().getTime();\n\n // Set the initial waited duration.\n this.waitedDuration = 0;\n\n // Are we dealing with an explicit duration or will we be randomly picking a duration between the min and max duration.\n if (this.duration !== null) {\n this.totalDuration = this.duration;\n } else if (this.durationMin !== null && this.durationMax !== null) {\n // We will be picking a random duration between a min and max duration, if the optional 'random' behaviour tree\n // function option is defined then we will be using that, otherwise we will fall back to using Math.random.\n const random = typeof options.random === \"function\" ? options.random : Math.random;\n\n // Pick a random duration between a min and max duration.\n this.totalDuration = Math.floor(\n random() * (this.durationMax - this.durationMin + 1) + this.durationMin\n );\n } else {\n this.totalDuration = null;\n }\n\n // The node is now running until we finish waiting.\n this.setState(State.RUNNING);\n }\n\n // If we have no total duration then this wait node will wait indefinitely until it is aborted.\n if (this.totalDuration === null) {\n return;\n }\n\n // If we have a 'getDeltaTime' function defined as part of our options then we will use it to figure out how long we have waited for.\n if (typeof options.getDeltaTime === \"function\") {\n // Get the delta time.\n const deltaTime = options.getDeltaTime();\n\n // Our delta time must be a valid number and cannot be NaN.\n if (typeof deltaTime !== \"number\" || isNaN(deltaTime)) {\n throw new Error(\"The delta time must be a valid number and not NaN.\");\n }\n\n // Update the amount of time that this node has been waiting for based on the delta time.\n this.waitedDuration += deltaTime * 1000;\n } else {\n // We are not using a delta time, so we will just work out hom much time has passed since the first update.\n this.waitedDuration = new Date().getTime() - this.initialUpdateTime;\n }\n\n // Have we waited long enough?\n if (this.waitedDuration >= this.totalDuration) {\n // We have finished waiting!\n this.setState(State.SUCCEEDED);\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => {\n if (this.duration !== null) {\n return `WAIT ${this.duration}ms`;\n } else if (this.durationMin !== null && this.durationMax !== null) {\n return `WAIT ${this.durationMin}ms-${this.durationMax}ms`;\n } else {\n return \"WAIT\";\n }\n };\n}\n", "import Node from \"../Node\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\n\n/**\n * A decorator node that wraps a single child node.\n */\nexport default abstract class Decorator extends Node {\n /**\n * @param type The node type.\n * @param attributes The node attributes.\n * @param child The child node.\n */\n constructor(type: string, attributes: Attribute[], protected child: Node) {\n super(type, attributes, []);\n }\n\n /**\n * Gets whether this node is a leaf node.\n */\n isLeafNode = () => false;\n\n /**\n * Gets the children of this node.\n */\n getChildren = () => [this.child];\n\n /**\n * Reset the state of the node.\n */\n reset = () => {\n // Reset the state of this node.\n this.setState(State.READY);\n\n // Reset the state of the child node.\n this.child.reset();\n };\n\n /**\n * Abort the running of this node.\n * @param agent The agent.\n */\n abort = (agent: Agent) => {\n // There is nothing to do if this node is not in the running state.\n if (!this.is(State.RUNNING)) {\n return;\n }\n\n // Abort the child node.\n this.child.abort(agent);\n\n // Reset the state of this node.\n this.reset();\n\n this.getAttribute(\"exit\")?.callAgentFunction(agent, false, true);\n };\n}\n", "import Node from \"../Node\";\nimport Decorator from \"./Decorator\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A Root node.\n * The root node will have a single child.\n */\nexport default class Root extends Decorator {\n /**\n * @param attributes The node attributes.\n * @param child The child node.\n */\n constructor(attributes: Attribute[], child: Node) {\n super(\"root\", attributes, child);\n }\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // If the child has never been updated or is running then we will need to update it now.\n if (this.child.getState() === State.READY || this.child.getState() === State.RUNNING) {\n // Update the child of this node.\n this.child.update(agent, options);\n }\n\n // The state of the root node is the state of its child.\n this.setState(this.child.getState());\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => \"ROOT\";\n}\n", "import Node from \"../Node\";\nimport Decorator from \"./Decorator\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A REPEAT node.\n * The node has a single child which can have:\n * -- A number of iterations for which to repeat the child node.\n * -- An infinite repeat loop if neither an iteration count or a condition function is defined.\n * The REPEAT node will stop and have a 'FAILED' state if its child is ever in a 'FAILED' state after an update.\n * The REPEAT node will attempt to move on to the next iteration if its child is ever in a 'SUCCEEDED' state.\n */\nexport default class Repeat extends Decorator {\n /**\n * @param attributes The node attributes.\n * @param iterations The number of iterations to repeat the child node.\n * @param iterationsMin The minimum possible number of iterations to repeat the child node.\n * @param iterationsMax The maximum possible number of iterations to repeat the child node.\n * @param child The child node.\n */\n constructor(\n attributes: Attribute[],\n private iterations: number | null,\n private iterationsMin: number | null,\n private iterationsMax: number | null,\n child: Node\n ) {\n super(\"repeat\", attributes, child);\n }\n\n /**\n * The number of target iterations to make.\n */\n private targetIterationCount: number | null = null;\n\n /**\n * The current iteration count.\n */\n private currentIterationCount: number = 0;\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // If this node is in the READY state then we need to reset the child and the target iteration count.\n if (this.is(State.READY)) {\n // Reset the child node.\n this.child.reset();\n\n // Reset the current iteration count.\n this.currentIterationCount = 0;\n\n // Set the target iteration count.\n this.setTargetIterationCount(options);\n }\n\n // Do a check to see if we can iterate. If we can then this node will move into the 'RUNNING' state.\n // If we cannot iterate then we have hit our target iteration count, which means that the node has succeeded.\n if (this.canIterate()) {\n // This node is in the running state and can do its initial iteration.\n this.setState(State.RUNNING);\n\n // We may have already completed an iteration, meaning that the child node will be in the SUCCEEDED state.\n // If this is the case then we will have to reset the child node now.\n if (this.child.getState() === State.SUCCEEDED) {\n this.child.reset();\n }\n\n // Update the child of this node.\n this.child.update(agent, options);\n\n // If the child moved into the FAILED state when we updated it then there is nothing left to do and this node has also failed.\n // If it has moved into the SUCCEEDED state then we have completed the current iteration.\n if (this.child.getState() === State.FAILED) {\n // The child has failed, meaning that this node has failed.\n this.setState(State.FAILED);\n\n return;\n } else if (this.child.getState() === State.SUCCEEDED) {\n // We have completed an iteration.\n this.currentIterationCount += 1;\n }\n } else {\n // This node is in the 'SUCCEEDED' state as we cannot iterate any more.\n this.setState(State.SUCCEEDED);\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => {\n if (this.iterations !== null) {\n return `REPEAT ${this.iterations}x`;\n } else if (this.iterationsMin !== null && this.iterationsMax !== null) {\n return `REPEAT ${this.iterationsMin}x-${this.iterationsMax}x`;\n } else {\n return \"REPEAT\";\n }\n };\n\n /**\n * Reset the state of the node.\n */\n reset = () => {\n // Reset the state of this node.\n this.setState(State.READY);\n\n // Reset the current iteration count.\n this.currentIterationCount = 0;\n\n // Reset the child node.\n this.child.reset();\n };\n\n /**\n * Gets whether an iteration can be made.\n * @returns Whether an iteration can be made.\n */\n private canIterate = () => {\n if (this.targetIterationCount !== null) {\n // We can iterate as long as we have not reached our target iteration count.\n return this.currentIterationCount < this.targetIterationCount;\n }\n\n // If neither an iteration count or a condition function were defined then we can iterate indefinitely.\n return true;\n };\n\n /**\n * Sets the target iteration count.\n * @param options The behaviour tree options object.\n */\n private setTargetIterationCount = (options: BehaviourTreeOptions) => {\n // Are we dealing with an explicit iteration count or will we be randomly picking a iteration count between the min and max iteration count.\n if (this.iterations !== null) {\n this.targetIterationCount = this.iterations;\n } else if (this.iterationsMin !== null && this.iterationsMax !== null) {\n // We will be picking a random iteration count between a min and max iteration count, if the optional 'random'\n // behaviour tree function option is defined then we will be using that, otherwise we will fall back to using Math.random.\n const random = typeof options.random === \"function\" ? options.random : Math.random;\n\n // Pick a random iteration count between a min and max iteration count.\n this.targetIterationCount = Math.floor(\n random() * (this.iterationsMax - this.iterationsMin + 1) + this.iterationsMin\n );\n } else {\n this.targetIterationCount = null;\n }\n };\n}\n", "import Node from \"../Node\";\nimport Decorator from \"./Decorator\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A RETRY node.\n * The node has a single child which can have:\n * -- A number of iterations for which to repeat the child node.\n * -- An infinite repeat loop if neither an iteration count or a condition function is defined.\n * The RETRY node will stop and have a 'SUCCEEDED' state if its child is ever in a 'SUCCEEDED' state after an update.\n * The RETRY node will attempt to move on to the next iteration if its child is ever in a 'FAILED' state.\n */\nexport default class Retry extends Decorator {\n /**\n * @param attributes The node attributes.\n * @param attempts The number of attempts to retry the child node.\n * @param attemptsMin The minimum possible number of attempts to retry the child node.\n * @param attemptsMax The maximum possible number of attempts to retry the child node.\n * @param child The child node.\n */\n constructor(\n attributes: Attribute[],\n private attempts: number | null,\n private attemptsMin: number | null,\n private attemptsMax: number | null,\n child: Node\n ) {\n super(\"retry\", attributes, child);\n }\n\n /**\n * The number of target attempts to make.\n */\n private targetAttemptCount: number | null = null;\n\n /**\n * The current attempt count.\n */\n private currentAttemptCount: number = 0;\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // If this node is in the READY state then we need to reset the child and the target attempt count.\n if (this.is(State.READY)) {\n // Reset the child node.\n this.child.reset();\n\n // Reset the current attempt count.\n this.currentAttemptCount = 0;\n\n // Set the target attempt count.\n this.setTargetAttemptCount(options);\n }\n\n // Do a check to see if we can attempt. If we can then this node will move into the 'RUNNING' state.\n // If we cannot attempt then we have hit our target attempt count, which means that the node has succeeded.\n if (this.canAttempt()) {\n // This node is in the running state and can do its initial attempt.\n this.setState(State.RUNNING);\n\n // We may have already completed an attempt, meaning that the child node will be in the FAILED state.\n // If this is the case then we will have to reset the child node now.\n if (this.child.getState() === State.FAILED) {\n this.child.reset();\n }\n\n // Update the child of this node.\n this.child.update(agent, options);\n\n // If the child moved into the SUCCEEDED state when we updated it then there is nothing left to do and this node has also succeeded.\n // If it has moved into the FAILED state then we have completed the current attempt.\n if (this.child.getState() === State.SUCCEEDED) {\n // The child has succeeded, meaning that this node has succeeded.\n this.setState(State.SUCCEEDED);\n\n return;\n } else if (this.child.getState() === State.FAILED) {\n // We have completed an attempt.\n this.currentAttemptCount += 1;\n }\n } else {\n // This node is in the 'FAILED' state as we cannot iterate any more.\n this.setState(State.FAILED);\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => {\n if (this.attempts !== null) {\n return `RETRY ${this.attempts}x`;\n } else if (this.attemptsMin !== null && this.attemptsMax !== null) {\n return `RETRY ${this.attemptsMin}x-${this.attemptsMax}x`;\n } else {\n return \"RETRY\";\n }\n };\n\n /**\n * Reset the state of the node.\n */\n reset = () => {\n // Reset the state of this node.\n this.setState(State.READY);\n\n // Reset the current attempt count.\n this.currentAttemptCount = 0;\n\n // Reset the child node.\n this.child.reset();\n };\n\n /**\n * Gets whether an attempt can be made.\n * @returns Whether an attempt can be made.\n */\n canAttempt = () => {\n if (this.targetAttemptCount !== null) {\n // We can attempt as long as we have not reached our target attempt count.\n return this.currentAttemptCount < this.targetAttemptCount;\n }\n\n // If neither an attempt count or a condition function were defined then we can attempt indefinitely.\n return true;\n };\n\n /**\n * Sets the target attempt count.\n * @param options The behaviour tree options object.\n */\n setTargetAttemptCount = (options: BehaviourTreeOptions) => {\n // Are we dealing with an explicit attempt count or will we be randomly picking an attempt count between the min and max attempt count.\n if (this.attempts !== null) {\n this.targetAttemptCount = this.attempts;\n } else if (this.attemptsMin !== null && this.attemptsMax !== null) {\n // We will be picking a random attempt count between a min and max attempt count, if the optional 'random'\n // behaviour tree function option is defined then we will be using that, otherwise we will fall back to using Math.random.\n const random = typeof options.random === \"function\" ? options.random : Math.random;\n\n // Pick a random attempt count between a min and max attempt count.\n this.targetAttemptCount = Math.floor(\n random() * (this.attemptsMax - this.attemptsMin + 1) + this.attemptsMin\n );\n } else {\n this.targetAttemptCount = null;\n }\n };\n}\n", "import Decorator from \"./Decorator\";\nimport State from \"../../State\";\nimport Node from \"../Node\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A Flip node.\n * This node wraps a single child and will flip the state of the child state.\n */\nexport default class Flip extends Decorator {\n /**\n * @param attributes The node attributes.\n * @param child The child node.\n */\n constructor(attributes: Attribute[], child: Node) {\n super(\"flip\", attributes, child);\n }\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // If the child has never been updated or is running then we will need to update it now.\n if (this.child.getState() === State.READY || this.child.getState() === State.RUNNING) {\n this.child.update(agent, options);\n }\n\n // The state of this node will depend in the state of its child.\n switch (this.child.getState()) {\n case State.RUNNING:\n this.setState(State.RUNNING);\n break;\n\n case State.SUCCEEDED:\n this.setState(State.FAILED);\n break;\n\n case State.FAILED:\n this.setState(State.SUCCEEDED);\n break;\n\n default:\n this.setState(State.READY);\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => \"FLIP\";\n}\n", "import Node from \"../Node\";\nimport Decorator from \"./Decorator\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A Succeed node.\n * This node wraps a single child and will always move to the 'SUCCEEDED' state when the child moves to a 'SUCCEEDED' or 'FAILED' state.\n */\nexport default class Succeed extends Decorator {\n /**\n * @param attributes The node attributes.\n * @param child The child node.\n */\n constructor(attributes: Attribute[], child: Node) {\n super(\"succeed\", attributes, child);\n }\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // If the child has never been updated or is running then we will need to update it now.\n if (this.child.getState() === State.READY || this.child.getState() === State.RUNNING) {\n this.child.update(agent, options);\n }\n\n // The state of this node will depend in the state of its child.\n switch (this.child.getState()) {\n case State.RUNNING:\n this.setState(State.RUNNING);\n break;\n\n case State.SUCCEEDED:\n case State.FAILED:\n this.setState(State.SUCCEEDED);\n break;\n\n default:\n this.setState(State.READY);\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => \"SUCCEED\";\n}\n", "import Node from \"../Node\";\nimport Decorator from \"./Decorator\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A Fail node.\n * This node wraps a single child and will always move to the 'FAILED' state when the child moves to a 'SUCCEEDED' or 'FAILED' state.\n */\nexport default class Fail extends Decorator {\n /**\n * @param attributes The node attributes.\n * @param child The child node.\n */\n constructor(attributes: Attribute[], child: Node) {\n super(\"fail\", attributes, child);\n }\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // If the child has never been updated or is running then we will need to update it now.\n if (this.child.getState() === State.READY || this.child.getState() === State.RUNNING) {\n this.child.update(agent, options);\n }\n\n // The state of this node will depend in the state of its child.\n switch (this.child.getState()) {\n case State.RUNNING:\n this.setState(State.RUNNING);\n break;\n\n case State.SUCCEEDED:\n case State.FAILED:\n this.setState(State.FAILED);\n break;\n\n default:\n this.setState(State.READY);\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => \"FAIL\";\n}\n", "import createLotto from \"lotto-draw\";\n\nimport Node from \"../Node\";\nimport Composite from \"./Composite\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A LOTTO node.\n * A winning child is picked on the initial update of this node, based on ticket weighting.\n * The state of this node will match the state of the winning child.\n */\nexport default class Lotto extends Composite {\n /**\n * @param attributes The node attributes.\n * @param tickets The child node tickets.\n * @param children The child nodes.\n */\n constructor(attributes: Attribute[], private tickets: number[], children: Node[]) {\n super(\"lotto\", attributes, children);\n }\n\n /**\n * The child node selected to be the active one.\n */\n private selectedChild: Node | undefined;\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // If this node is in the READY state then we need to pick a winning child node.\n if (this.is(State.READY)) {\n // Create a lotto draw with which to randomly pick a child node to become the active one.\n const lottoDraw = createLotto({\n // Hook up the optional 'random' behaviour tree function option to the one used by 'lotto-draw'.\n random: options.random,\n // Pass in each child node as a participant in the lotto draw with their respective ticket count.\n participants: this.children.map((child, index) => [child, this.tickets[index] || 1])\n });\n\n // Randomly pick a child based on ticket weighting, this will become the active child for this composite node.\n this.selectedChild = lottoDraw.draw() || undefined;\n }\n\n // If something went wrong and we don't have an active child then we should throw an error.\n if (!this.selectedChild) {\n throw new Error(\"failed to update lotto node as it has no active child\");\n }\n\n // If the selected child has never been updated or is running then we will need to update it now.\n if (this.selectedChild.getState() === State.READY || this.selectedChild.getState() === State.RUNNING) {\n this.selectedChild.update(agent, options);\n }\n\n // The state of the lotto node is the state of its selected child.\n this.setState(this.selectedChild.getState());\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => (this.tickets.length ? `LOTTO [${this.tickets.join(\",\")}]` : \"LOTTO\");\n}\n", "import Node from \"../Node\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\n\n/**\n * A composite node that wraps child nodes.\n */\nexport default abstract class Composite extends Node {\n /**\n * @param type The node type.\n * @param attributes The node attributes.\n * @param children The child nodes.\n */\n constructor(type: string, attributes: Attribute[], protected children: Node[]) {\n super(type, attributes, []);\n }\n\n /**\n * Gets whether this node is a leaf node.\n */\n isLeafNode = () => false;\n\n /**\n * Gets the children of this node.\n */\n getChildren = () => this.children;\n\n /**\n * Reset the state of the node.\n */\n reset = () => {\n // Reset the state of this node.\n this.setState(State.READY);\n\n // Reset the state of any child nodes.\n this.getChildren().forEach((child) => child.reset());\n };\n\n /**\n * Abort the running of this node.\n * @param agent The agent.\n */\n abort = (agent: Agent) => {\n // There is nothing to do if this node is not in the running state.\n if (!this.is(State.RUNNING)) {\n return;\n }\n\n // Abort any child nodes.\n this.getChildren().forEach((child) => child.abort(agent));\n\n // Reset the state of this node.\n this.reset();\n\n this.getAttribute(\"exit\")?.callAgentFunction(agent, false, true);\n };\n}\n", "import Composite from \"./Composite\";\nimport Node from \"../Node\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A SELECTOR node.\n * The child nodes are executed in sequence until one succeeds or all fail.\n */\nexport default class Selector extends Composite {\n /**\n * @param attributes The node attributes.\n * @param children The child nodes.\n */\n constructor(attributes: Attribute[], protected children: Node[]) {\n super(\"selector\", attributes, children);\n }\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // Iterate over all of the children of this node.\n for (const child of this.children) {\n // If the child has never been updated or is running then we will need to update it now.\n if (child.getState() === State.READY || child.getState() === State.RUNNING) {\n // Update the child of this node.\n child.update(agent, options);\n }\n\n // If the current child has a state of 'SUCCEEDED' then this node is also a 'SUCCEEDED' node.\n if (child.getState() === State.SUCCEEDED) {\n // This node is a 'SUCCEEDED' node.\n this.setState(State.SUCCEEDED);\n\n // There is no need to check the rest of the selector nodes.\n return;\n }\n\n // If the current child has a state of 'FAILED' then we should move on to the next child.\n if (child.getState() === State.FAILED) {\n // Find out if the current child is the last one in the selector.\n // If it is then this sequence node has also failed.\n if (this.children.indexOf(child) === this.children.length - 1) {\n // This node is a 'FAILED' node.\n this.setState(State.FAILED);\n\n // There is no need to check the rest of the selector as we have completed it.\n return;\n } else {\n // The child node failed, try the next one.\n continue;\n }\n }\n\n // The node should be in the 'RUNNING' state.\n if (child.getState() === State.RUNNING) {\n // This node is a 'RUNNING' node.\n this.setState(State.RUNNING);\n\n // There is no need to check the rest of the selector as the current child is still running.\n return;\n }\n\n // The child node was not in an expected state.\n throw new Error(\"child node was not in an expected state.\");\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => \"SELECTOR\";\n}\n", "import Composite from \"./Composite\";\nimport Node from \"../Node\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A SEQUENCE node.\n * The child nodes are executed in sequence until one fails or all succeed.\n */\nexport default class Sequence extends Composite {\n /**\n * @param attributes The node attributes.\n * @param children The child nodes.\n */\n constructor(attributes: Attribute[], protected children: Node[]) {\n super(\"sequence\", attributes, children);\n }\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // Iterate over all of the children of this node.\n for (const child of this.children) {\n // If the child has never been updated or is running then we will need to update it now.\n if (child.getState() === State.READY || child.getState() === State.RUNNING) {\n // Update the child of this node.\n child.update(agent, options);\n }\n\n // If the current child has a state of 'SUCCEEDED' then we should move on to the next child.\n if (child.getState() === State.SUCCEEDED) {\n // Find out if the current child is the last one in the sequence.\n // If it is then this sequence node has also succeeded.\n if (this.children.indexOf(child) === this.children.length - 1) {\n // This node is a 'SUCCEEDED' node.\n this.setState(State.SUCCEEDED);\n\n // There is no need to check the rest of the sequence as we have completed it.\n return;\n } else {\n // The child node succeeded, but we have not finished the sequence yet.\n continue;\n }\n }\n\n // If the current child has a state of 'FAILED' then this node is also a 'FAILED' node.\n if (child.getState() === State.FAILED) {\n // This node is a 'FAILED' node.\n this.setState(State.FAILED);\n\n // There is no need to check the rest of the sequence.\n return;\n }\n\n // The node should be in the 'RUNNING' state.\n if (child.getState() === State.RUNNING) {\n // This node is a 'RUNNING' node.\n this.setState(State.RUNNING);\n\n // There is no need to check the rest of the sequence as the current child is still running.\n return;\n }\n\n // The child node was not in an expected state.\n throw new Error(\"child node was not in an expected state.\");\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => \"SEQUENCE\";\n}\n", "import Composite from \"./Composite\";\nimport State from \"../../State\";\nimport Node from \"../Node\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A PARALLEL node.\n * The child nodes are executed concurrently until one fails or all succeed.\n */\nexport default class Parallel extends Composite {\n /**\n * @param attributes The node attributes.\n * @param children The child nodes.\n */\n constructor(attributes: Attribute[], children: Node[]) {\n super(\"parallel\", attributes, children);\n }\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // Keep a count of the number of succeeded child nodes.\n let succeededCount = 0;\n\n let hasChildFailed = false;\n\n // Iterate over all of the children of this node.\n for (const child of this.children) {\n // If the child has never been updated or is running then we will need to update it now.\n if (child.getState() === State.READY || child.getState() === State.RUNNING) {\n // Update the child of this node.\n child.update(agent, options);\n }\n\n // If the current child has a state of 'SUCCEEDED' then we should move on to the next child.\n if (child.getState() === State.SUCCEEDED) {\n // The child node has succeeded, keep track of this to determine if all children have.\n succeededCount++;\n\n // The child node succeeded, but we have not finished checking every child node yet.\n continue;\n }\n\n // If the current child has a state of 'FAILED' then this node is also a 'FAILED' node.\n if (child.getState() === State.FAILED) {\n hasChildFailed = true;\n\n // There is no need to check the rest of the children.\n break;\n }\n\n // The node should be in the 'RUNNING' state.\n if (child.getState() !== State.RUNNING) {\n // The child node was not in an expected state.\n throw new Error(\"child node was not in an expected state.\");\n }\n }\n\n if (hasChildFailed) {\n // This node is a 'FAILED' node.\n this.setState(State.FAILED);\n\n // Abort every running child.\n for (const child of this.children) {\n if (child.getState() === State.RUNNING) {\n child.abort(agent);\n }\n }\n } else {\n // If all children have succeeded then this node has also succeeded, otherwise it is still running.\n this.setState(succeededCount === this.children.length ? State.SUCCEEDED : State.RUNNING);\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => \"PARALLEL\";\n}\n", "import { AnyArgument } from \"../RootAstNodesBuilder\";\nimport Guard from \"./guards/Guard\";\n\nexport type AttributeDetails = {\n /** The attribute type. */\n type: string;\n\n /** The attribute arguments. */\n args: AnyArgument[];\n};\n\n/**\n * A base node attribute.\n */\nexport default abstract class Attribute {\n /**\n * @param type The node attribute type.\n * @param args The array of attribute argument definitions.\n */\n constructor(protected type: string, protected args: AnyArgument[]) {}\n\n /**\n * Gets the type of the attribute.\n */\n getType = () => this.type;\n\n /**\n * Gets the array of attribute argument definitions.\n */\n getArguments = () => this.args;\n\n /**\n * Gets the attribute details.\n */\n abstract getDetails(): TAttributeDetails;\n\n /**\n * Gets whether this attribute is a guard.\n */\n abstract isGuard: () => this is Guard;\n}\n", "import { Agent } from \"../../Agent\";\nimport { AnyArgument } from \"../../RootAstNodesBuilder\";\nimport Attribute, { AttributeDetails } from \"../Attribute\";\n\nexport type GuardAttributeDetails = {\n /** The name of the condition function that determines whether the guard is satisfied. */\n condition: string;\n} & AttributeDetails;\n\n/**\n * A base node guard attribute.\n */\nexport default abstract class Guard extends Attribute {\n /**\n * @param type The node attribute type.\n * @param args The array of decorator argument definitions.\n * @param condition The name of the condition function that determines whether the guard is satisfied.\n */\n constructor(type: string, args: AnyArgument[], private condition: string) {\n super(type, args);\n }\n\n /**\n * Gets the name of the condition function that determines whether the guard is satisfied.\n */\n getCondition = () => this.condition;\n\n /**\n * Gets whether this attribute is a guard.\n */\n isGuard = () => true;\n\n /**\n * Gets the attribute details.\n */\n getDetails(): GuardAttributeDetails {\n return {\n type: this.getType(),\n args: this.getArguments(),\n condition: this.getCondition()\n };\n }\n\n /**\n * Gets whether the guard is satisfied.\n * @param agent The agent.\n * @returns Whether the guard is satisfied.\n */\n abstract isSatisfied(agent: Agent): boolean;\n}\n", "import Guard from \"./Guard\";\nimport Lookup from \"../../Lookup\";\nimport { Agent } from \"../../Agent\";\nimport { AnyArgument } from \"../../RootAstNodesBuilder\";\n\n/**\n * A WHILE guard which is satisfied as long as the given condition remains true.\n */\nexport default class While extends Guard {\n /**\n * @param condition The name of the condition function that determines whether the guard is satisfied.\n * @param args The array of decorator argument definitions.\n */\n constructor(condition: string, args: AnyArgument[]) {\n super(\"while\", args, condition);\n }\n\n /**\n * Gets whether the guard is satisfied.\n * @param agent The agent.\n * @returns Whether the guard is satisfied.\n */\n isSatisfied = (agent: Agent) => {\n // Attempt to get the invoker for the condition function.\n const conditionFuncInvoker = Lookup.getFuncInvoker(agent, this.getCondition());\n\n // The condition function should be defined.\n if (conditionFuncInvoker === null) {\n throw new Error(\n `cannot evaluate node guard as the condition '${this.getCondition()}' function is not defined on the agent and has not been registered`\n );\n }\n\n // Call the condition function to determine whether this guard is satisfied.\n return !!conditionFuncInvoker(this.args);\n };\n}\n", "import Guard from \"./Guard\";\nimport Lookup from \"../../Lookup\";\nimport { Agent } from \"../../Agent\";\nimport { AnyArgument } from \"../../RootAstNodesBuilder\";\n\n/**\n * An UNTIL guard which is satisfied as long as the given condition remains false.\n */\nexport default class Until extends Guard {\n /**\n * @param condition The name of the condition function that determines whether the guard is satisfied.\n * @param args The array of decorator argument definitions.\n */\n constructor(condition: string, args: AnyArgument[]) {\n super(\"until\", args, condition);\n }\n\n /**\n * Gets whether the guard is satisfied.\n * @param agent The agent.\n * @returns Whether the guard is satisfied.\n */\n isSatisfied = (agent: Agent) => {\n // Attempt to get the invoker for the condition function.\n const conditionFuncInvoker = Lookup.getFuncInvoker(agent, this.getCondition());\n\n // The condition function should be defined.\n if (conditionFuncInvoker === null) {\n throw new Error(\n `cannot evaluate node guard as the condition '${this.getCondition()}' function is not defined on the agent and has not been registered`\n );\n }\n\n // Call the condition function to determine whether this guard is satisfied.\n return !!!conditionFuncInvoker(this.args);\n };\n}\n", "import { Agent } from \"../../Agent\";\nimport { AnyArgument } from \"../../RootAstNodesBuilder\";\nimport Attribute, { AttributeDetails } from \"../Attribute\";\n\nexport type CallbackAttributeDetails = {\n /** The name of the agent function that is called. */\n functionName: string;\n} & AttributeDetails;\n\n/**\n * A base node callback attribute.\n */\nexport default abstract class Callback extends Attribute {\n /**\n * @param type The node attribute type.\n * @param args The array of decorator argument definitions.\n * @param functionName The name of the agent function to call.\n */\n constructor(type: string, args: AnyArgument[], private functionName: string) {\n super(type, args);\n }\n\n /**\n * Gets the name of the agent function to call.\n */\n getFunctionName = () => this.functionName;\n\n /**\n * Gets whether this attribute is a guard.\n */\n isGuard = () => false;\n\n /**\n * Gets the attribute details.\n */\n getDetails(): CallbackAttributeDetails {\n return {\n type: this.getType(),\n args: this.getArguments(),\n functionName: this.getFunctionName()\n };\n }\n\n /**\n * Attempt to call the agent function that this callback refers to.\n * @param agent The agent.\n */\n abstract callAgentFunction: (agent: Agent, isSuccess: boolean, isAborted: boolean) => void;\n}\n", "import Callback from \"./Callback\";\nimport Lookup from \"../../Lookup\";\nimport { Agent } from \"../../Agent\";\nimport { AnyArgument } from \"../../RootAstNodesBuilder\";\n\n/**\n * An ENTRY callback which defines an agent function to call when the associated node is updated and moves out of running state.\n */\nexport default class Entry extends Callback {\n /**\n * @param functionName The name of the agent function to call.\n * @param args The array of callback argument definitions.\n */\n constructor(functionName: string, args: AnyArgument[]) {\n super(\"entry\", args, functionName);\n }\n\n /**\n * Attempt to call the agent function that this callback refers to.\n * @param agent The agent.\n */\n callAgentFunction = (agent: Agent) => {\n // Attempt to get the invoker for the callback function.\n const callbackFuncInvoker = Lookup.getFuncInvoker(agent, this.getFunctionName());\n\n // The callback function should be defined.\n if (callbackFuncInvoker === null) {\n throw new Error(\n `cannot call entry function '${this.getFunctionName()}' as is not defined on the agent and has not been registered`\n );\n }\n\n // Call the callback function.\n callbackFuncInvoker(this.args);\n };\n}\n", "import Callback from \"./Callback\";\nimport Lookup, { AnyExitArgument } from \"../../Lookup\";\nimport { Agent } from \"../../Agent\";\nimport { AnyArgument } from \"../../RootAstNodesBuilder\";\n\n/**\n * An EXIT callback which defines an agent function to call when the associated node is updated and moves to a finished state or is aborted.\n */\nexport default class Exit extends Callback {\n /**\n * @param functionName The name of the agent function to call.\n * @param args The array of callback argument definitions.\n */\n constructor(functionName: string, args: AnyArgument[]) {\n super(\"exit\", args, functionName);\n }\n\n /**\n * Attempt to call the agent function that this callback refers to.\n * @param agent The agent.\n * @param isSuccess Whether the decorated node was left with a success state.\n * @param isAborted Whether the decorated node was aborted.\n */\n callAgentFunction = (agent: Agent, isSuccess: boolean, isAborted: boolean) => {\n // Attempt to get the invoker for the callback function.\n const callbackFuncInvoker = Lookup.getFuncInvoker(agent, this.getFunctionName());\n\n // The callback function should be defined.\n if (callbackFuncInvoker === null) {\n throw new Error(\n `cannot call exit function '${this.getFunctionName()}' as is not defined on the agent and has not been registered`\n );\n }\n\n // Call the callback function\n callbackFuncInvoker([{ value: { succeeded: isSuccess, aborted: isAborted } }, ...this.args]);\n };\n}\n", "import Callback from \"./Callback\";\nimport Lookup from \"../../Lookup\";\nimport { Agent } from \"../../Agent\";\nimport { AnyArgument } from \"../../RootAstNodesBuilder\";\n\n/**\n * A STEP callback which defines an agent function to call when the associated node is updated.\n */\nexport default class Step extends Callback {\n /**\n * @param functionName The name of the agent function to call.\n * @param args The array of callback argument definitions.\n */\n constructor(functionName: string, args: AnyArgument[]) {\n super(\"step\", args, functionName);\n }\n\n /**\n * Attempt to call the agent function that this callback refers to.\n * @param agent The agent.\n */\n callAgentFunction = (agent: Agent) => {\n // Attempt to get the invoker for the callback function.\n const callbackFuncInvoker = Lookup.getFuncInvoker(agent, this.getFunctionName());\n\n // The callback function should be defined.\n if (callbackFuncInvoker === null) {\n throw new Error(\n `cannot call step function '${this.getFunctionName()}' as is not defined on the agent and has not been registered`\n );\n }\n\n // Call the callback function.\n callbackFuncInvoker(this.args);\n };\n}\n", "import Action from \"./nodes/leaf/Action\";\nimport Condition from \"./nodes/leaf/Condition\";\nimport Wait from \"./nodes/leaf/Wait\";\nimport Root from \"./nodes/decorator/Root\";\nimport Repeat from \"./nodes/decorator/Repeat\";\nimport Retry from \"./nodes/decorator/Retry\";\nimport Flip from \"./nodes/decorator/Flip\";\nimport Succeed from \"./nodes/decorator/Succeed\";\nimport Fail from \"./nodes/decorator/Fail\";\nimport Lotto from \"./nodes/composite/Lotto\";\nimport Selector from \"./nodes/composite/Selector\";\nimport Sequence from \"./nodes/composite/Sequence\";\nimport Parallel from \"./nodes/composite/Parallel\";\nimport Node from \"./nodes/Node\";\nimport While from \"./attributes/guards/While\";\nimport Until from \"./attributes/guards/Until\";\nimport Entry from \"./attributes/callbacks/Entry\";\nimport Exit from \"./attributes/callbacks/Exit\";\nimport Step from \"./attributes/callbacks/Step\";\nimport Callback from \"./attributes/callbacks/Callback\";\nimport Guard from \"./attributes/guards/Guard\";\nimport Attribute from \"./attributes/Attribute\";\nimport Composite from \"./nodes/composite/Composite\";\nimport Decorator from \"./nodes/decorator/Decorator\";\nimport Leaf from \"./nodes/leaf/Leaf\";\n\nexport type Argument = {\n value: T;\n type: string; // Used for validation.\n};\ntype NullArgument = Argument & {\n type: \"null\";\n};\ntype BooleanArgument = Argument & {\n type: \"boolean\";\n};\ntype NumberArgument = Argument & {\n type: \"number\";\n isInteger: boolean; // Used for validation.\n};\ntype StringPlaceholderArgument = Argument & {\n type: \"string\";\n};\ntype IdentifierArgument = Argument & {\n type: \"identifier\";\n};\nexport type AnyArgument =\n | NullArgument\n | BooleanArgument\n | NumberArgument\n | StringPlaceholderArgument\n | IdentifierArgument;\n\n/**\n * The node attribute factories.\n */\nconst AttributeFactories: {\n [key: string]: (functionName: string, attributeArguments: AnyArgument[]) => Callback | Guard;\n} = {\n WHILE: (condition: string, attributeArguments: AnyArgument[]) => new While(condition, attributeArguments),\n UNTIL: (condition: string, attributeArguments: AnyArgument[]) => new Until(condition, attributeArguments),\n ENTRY: (functionName: string, attributeArguments: AnyArgument[]) => new Entry(functionName, attributeArguments),\n EXIT: (functionName: string, attributeArguments: AnyArgument[]) => new Exit(functionName, attributeArguments),\n STEP: (functionName: string, attributeArguments: AnyArgument[]) => new Step(functionName, attributeArguments)\n};\n\ntype Validatable = {\n children?: AstNode[];\n validate: (depth: number) => void;\n};\n\ntype NodeInstanceCreator = (\n namedRootNodeProvider: (name: string) => RootAstNode,\n visitedBranches: string[]\n) => T;\n\nexport type AstNode = Validatable & {\n type: string;\n createNodeInstance: NodeInstanceCreator;\n};\n\nexport type LeafAstNode = AstNode & {\n type: \"action\" | \"condition\" | \"wait\";\n attributes: Attribute[];\n};\n\nexport type CompositeAstNode = AstNode & {\n type: \"lotto\" | \"parallel\" | \"selector\" | \"sequence\";\n attributes: Attribute[];\n children: AstNode[];\n};\n\nexport type DecoratorAstNode = AstNode & {\n type: \"fail\" | \"flip\" | \"repeat\" | \"retry\" | \"root\" | \"succeed\";\n attributes: Attribute[];\n children: AstNode[];\n};\n\nexport type BranchAstNode = AstNode & {\n type: \"branch\";\n branchName: \"\" | string;\n};\n\nexport type LottoAstNode = CompositeAstNode & {\n type: \"lotto\";\n tickets: number[];\n};\n\nexport type RootAstNode = DecoratorAstNode & {\n type: \"root\";\n name: null | string;\n};\n\nexport type RepeatAstNode = DecoratorAstNode & {\n type: \"repeat\";\n iterations: number | null;\n iterationsMin: number | null;\n iterationsMax: number | null;\n};\n\nexport type RetryAstNode = DecoratorAstNode & {\n type: \"retry\";\n attempts: number | null;\n attemptsMin: number | null;\n attemptsMax: number | null;\n};\n\nexport type ActionAstNode = LeafAstNode & {\n type: \"action\";\n actionName: string;\n actionArguments: AnyArgument[];\n};\n\nexport type ConditionAstNode = LeafAstNode & {\n type: \"condition\";\n conditionName: string;\n conditionArguments: AnyArgument[];\n};\n\nexport type WaitAstNode = LeafAstNode & {\n type: \"wait\";\n duration: number | null;\n durationMin: number | null;\n durationMax: number | null;\n};\n\nexport type AnyAstNode =\n | BranchAstNode\n | CompositeAstNode\n | LottoAstNode\n | DecoratorAstNode\n | RootAstNode\n | RepeatAstNode\n | RetryAstNode\n | LeafAstNode\n | ActionAstNode\n | ConditionAstNode\n | WaitAstNode;\n\n/**\n * The AST node factories.\n */\nconst ASTNodeFactories = {\n ROOT: (): RootAstNode => ({\n type: \"root\",\n attributes: [],\n name: null,\n children: [],\n validate(depth: number) {\n // A root node cannot be the child of another node.\n if (depth > 1) {\n throw new Error(\"a root node cannot be the child of another node\");\n }\n\n // A root node must have a single child node.\n if (this.children.length !== 1) {\n throw new Error(\"a root node must have a single child\");\n }\n },\n createNodeInstance(namedRootNodeProvider, visitedBranches) {\n return new Root(\n this.attributes,\n this.children![0].createNodeInstance(namedRootNodeProvider, visitedBranches.slice())\n );\n }\n }),\n BRANCH: (): BranchAstNode => ({\n type: \"branch\",\n branchName: \"\",\n validate() {},\n createNodeInstance(namedRootNodeProvider, visitedBranches) {\n // Try to find the root node with a matching branch name.\n const targetRootNode = namedRootNodeProvider(this.branchName);\n\n // If we have already visited this branch then we have a circular dependency.\n if (visitedBranches.indexOf(this.branchName) !== -1) {\n throw new Error(`circular dependency found in branch node references for branch '${this.branchName}'`);\n }\n\n // If we have a target root node, then the node instance we want will be the first and only child of the referenced root node.\n if (targetRootNode) {\n return targetRootNode\n .createNodeInstance(namedRootNodeProvider, visitedBranches.concat(this.branchName))\n .getChildren()[0];\n } else {\n throw new Error(`branch references root node '${this.branchName}' which has not been defined`);\n }\n }\n }),\n SELECTOR: (): CompositeAstNode => ({\n type: \"selector\",\n attributes: [],\n children: [],\n validate() {\n // A selector node must have at least a single node.\n if (this.children.length < 1) {\n throw new Error(\"a selector node must have at least a single child\");\n }\n },\n createNodeInstance(namedRootNodeProvider, visitedBranches) {\n return new Selector(\n this.attributes,\n this.children.map((child) => child.createNodeInstance(namedRootNodeProvider, visitedBranches.slice()))\n );\n }\n }),\n SEQUENCE: (): CompositeAstNode => ({\n type: \"sequence\",\n attributes: [],\n children: [],\n validate() {\n // A sequence node must have at least a single node.\n if (this.children.length < 1) {\n throw new Error(\"a sequence node must have at least a single child\");\n }\n },\n createNodeInstance(namedRootNodeProvider, visitedBranches) {\n return new Sequence(\n this.attributes,\n this.children.map((child) => child.createNodeInstance(namedRootNodeProvider, visitedBranches.slice()))\n );\n }\n }),\n PARALLEL: (): CompositeAstNode => ({\n type: \"parallel\",\n attributes: [],\n children: [],\n validate() {\n // A parallel node must have at least a single node.\n if (this.children.length < 1) {\n throw new Error(\"a parallel node must have at least a single child\");\n }\n },\n createNodeInstance(namedRootNodeProvider, visitedBranches) {\n return new Parallel(\n this.attributes,\n this.children.map((child) => child.createNodeInstance(namedRootNodeProvider, visitedBranches.slice()))\n );\n }\n }),\n LOTTO: (): LottoAstNode => ({\n type: \"lotto\",\n attributes: [],\n children: [],\n tickets: [],\n validate() {\n // A lotto node must have at least a single node.\n if (this.children!.length < 1) {\n throw new Error(\"a lotto node must have at least a single child\");\n }\n },\n createNodeInstance(namedRootNodeProvider, visitedBranches) {\n return new Lotto(\n this.attributes,\n this.tickets!,\n this.children!.map((child) => child.createNodeInstance(namedRootNodeProvider, visitedBranches.slice()))\n );\n }\n }),\n REPEAT: (): RepeatAstNode => ({\n type: \"repeat\",\n attributes: [],\n iterations: null,\n iterationsMin: null,\n iterationsMax: null,\n children: [],\n validate() {\n // A repeat node must have a single node.\n if (this.children!.length !== 1) {\n throw new Error(\"a repeat node must have a single child\");\n }\n\n if (this.iterations !== null) {\n // A repeat node must have a positive number of iterations if defined.\n if (this.iterations < 0) {\n throw new Error(\"a repeat node must have a positive number of iterations if defined\");\n }\n } else if (this.iterationsMin !== null && this.iterationsMax !== null) {\n // A repeat node must have a positive min and max iteration count if they are defined.\n if (this.iterationsMin < 0 || this.iterationsMax < 0) {\n throw new Error(\n \"a repeat node must have a positive minimum and maximum iteration count if defined\"\n );\n }\n\n // A repeat node must not have an minimum iteration count that exceeds the maximum iteration count.\n if (this.iterationsMin > this.iterationsMax) {\n throw new Error(\n \"a repeat node must not have a minimum iteration count that exceeds the maximum iteration count\"\n );\n }\n } else {\n // If we have no explicit iteration count or a minimum and maximum iteration count set then we are dealing with a repeat node that iterates indefinitely.\n }\n },\n createNodeInstance(namedRootNodeProvider, visitedBranches) {\n return new Repeat(\n this.attributes,\n this.iterations,\n this.iterationsMin,\n this.iterationsMax,\n this.children![0].createNodeInstance(namedRootNodeProvider, visitedBranches.slice())\n );\n }\n }),\n RETRY: (): RetryAstNode => ({\n type: \"retry\",\n attributes: [],\n attempts: null,\n attemptsMin: null,\n attemptsMax: null,\n children: [],\n validate() {\n // A retry node must have a single node.\n if (this.children!.length !== 1) {\n throw new Error(\"a retry node must have a single child\");\n }\n\n if (this.attempts !== null) {\n // A retry node must have a positive number of attempts if defined.\n if (this.attempts < 0) {\n throw new Error(\"a retry node must have a positive number of attempts if defined\");\n }\n } else if (this.attemptsMin !== null && this.attemptsMax !== null) {\n // A retry node must have a positive min and max attempts count if they are defined.\n if (this.attemptsMin < 0 || this.attemptsMax < 0) {\n throw new Error(\"a retry node must have a positive minimum and maximum attempt count if defined\");\n }\n\n // A retry node must not have a minimum attempt count that exceeds the maximum attempt count.\n if (this.attemptsMin > this.attemptsMax) {\n throw new Error(\n \"a retry node must not have a minimum attempt count that exceeds the maximum attempt count\"\n );\n }\n } else {\n // If we have no explicit attempt count or a minimum and maximum attempt count set then we are dealing with a retry node that attempts indefinitely.\n }\n },\n createNodeInstance(namedRootNodeProvider, visitedBranches) {\n return new Retry(\n this.attributes,\n this.attempts,\n this.attemptsMin,\n this.attemptsMax,\n this.children![0].createNodeInstance(namedRootNodeProvider, visitedBranches.slice())\n );\n }\n }),\n FLIP: (): DecoratorAstNode => ({\n type: \"flip\",\n attributes: [],\n children: [],\n validate() {\n // A flip node must have a single node.\n if (this.children!.length !== 1) {\n throw new Error(\"a flip node must have a single child\");\n }\n },\n createNodeInstance(namedRootNodeProvider, visitedBranches) {\n return new Flip(\n this.attributes,\n this.children![0].createNodeInstance(namedRootNodeProvider, visitedBranches.slice())\n );\n }\n }),\n SUCCEED: (): DecoratorAstNode => ({\n type: \"succeed\",\n attributes: [],\n children: [],\n validate() {\n // A succeed node must have a single node.\n if (this.children!.length !== 1) {\n throw new Error(\"a succeed node must have a single child\");\n }\n },\n createNodeInstance(namedRootNodeProvider, visitedBranches) {\n return new Succeed(\n this.attributes,\n this.children![0].createNodeInstance(namedRootNodeProvider, visitedBranches.slice())\n );\n }\n }),\n FAIL: (): DecoratorAstNode => ({\n type: \"fail\",\n attributes: [],\n children: [],\n validate() {\n // A fail node must have a single node.\n if (this.children!.length !== 1) {\n throw new Error(\"a fail node must have a single child\");\n }\n },\n createNodeInstance(namedRootNodeProvider, visitedBranches) {\n return new Fail(\n this.attributes,\n this.children![0].createNodeInstance(namedRootNodeProvider, visitedBranches.slice())\n );\n }\n }),\n WAIT: (): WaitAstNode => ({\n type: \"wait\",\n attributes: [],\n duration: null,\n durationMin: null,\n durationMax: null,\n validate() {\n if (this.duration !== null) {\n // If an explict duration was defined then it must be a positive number.\n if (this.duration < 0) {\n throw new Error(\"a wait node must have a positive duration\");\n }\n } else if (this.durationMin !== null && this.durationMax !== null) {\n // A wait node must have a positive min and max duration.\n if (this.durationMin < 0 || this.durationMax < 0) {\n throw new Error(\"a wait node must have a positive minimum and maximum duration\");\n }\n\n // A wait node must not have a minimum duration that exceeds the maximum duration.\n if (this.durationMin > this.durationMax) {\n throw new Error(\"a wait node must not have a minimum duration that exceeds the maximum duration\");\n }\n } else {\n // If we have no explicit duration or duration bounds set then we are dealing with a wait node that waits indefinitely.\n }\n },\n createNodeInstance() {\n return new Wait(this.attributes, this.duration, this.durationMin, this.durationMax);\n }\n }),\n ACTION: (): ActionAstNode => ({\n type: \"action\",\n attributes: [],\n actionName: \"\",\n actionArguments: [],\n validate() {},\n createNodeInstance() {\n return new Action(this.attributes, this.actionName!, this.actionArguments!);\n }\n }),\n CONDITION: (): ConditionAstNode => ({\n type: \"condition\",\n attributes: [],\n conditionName: \"\",\n conditionArguments: [],\n validate() {},\n createNodeInstance() {\n return new Condition(this.attributes, this.conditionName!, this.conditionArguments!);\n }\n })\n};\n\ntype OtherAstNodes = AstNode[];\n\n/**\n * Create an array of root AST nodes based on the given definition.\n * @param definition The definition to parse the AST nodes from.\n * @returns The base definition AST nodes.\n */\nexport default function buildRootASTNodes(definition: string): RootAstNode[] {\n // Swap out any node/attribute argument string literals with a placeholder and get a mapping of placeholders to original values as well as the processed definition.\n const { placeholders, processedDefinition } = substituteStringLiterals(definition);\n\n // Convert the processed definition (with substituted string literals) into an array of raw tokens.\n const tokens = parseTokensFromDefinition(processedDefinition);\n\n // There must be at least 3 tokens for the tree definition to be valid. 'ROOT', '{' and '}'.\n if (tokens.length < 3) {\n throw new Error(\"invalid token count\");\n }\n\n // We should have a matching number of '{' and '}' tokens. If not, then there are scopes that have not been properly closed.\n if (tokens.filter((token) => token === \"{\").length !== tokens.filter((token) => token === \"}\").length) {\n throw new Error(\"scope character mismatch\");\n }\n\n // Create a stack of node children arrays, starting with a definition scope.\n const stack: [RootAstNode[], ...OtherAstNodes[]] = [[]];\n const rootScope = stack[0];\n\n // We should keep processing the raw tokens until we run out of them.\n while (tokens.length) {\n // Grab the next token.\n const token = tokens.shift();\n\n const currentScope = stack[stack.length - 1] as OtherAstNodes;\n\n // How we create the next AST token depends on the current raw token value.\n switch (token!.toUpperCase()) {\n case \"ROOT\": {\n // Create a ROOT AST node.\n const node = ASTNodeFactories.ROOT();\n\n // Push the ROOT node into the current scope.\n rootScope.push(node);\n\n // We may have a root node name defined as an argument.\n if (tokens[0] === \"[\") {\n const rootArguments = getArguments(tokens, placeholders);\n\n // We should have only a single argument that is not an empty string for a root node, which is the root name identifier.\n if (rootArguments.length === 1 && rootArguments[0].type === \"identifier\") {\n // The root name will be the first and only node argument.\n node.name = rootArguments[0].value as string;\n } else {\n throw new Error(\"expected single root name argument\");\n }\n }\n\n // Try to pick any attributes off of the token stack.\n node.attributes = getAttributes(tokens, placeholders);\n\n popAndCheck(tokens, \"{\");\n\n // The new scope is that of the new ROOT nodes children.\n stack.push(node.children!);\n break;\n }\n\n case \"BRANCH\": {\n // Create a BRANCH AST node.\n const node = ASTNodeFactories.BRANCH();\n\n // Push the BRANCH node into the current scope.\n currentScope.push(node);\n\n // We must have arguments defined, as we require a branch name argument.\n if (tokens[0] !== \"[\") {\n throw new Error(\"expected single branch name argument\");\n }\n\n // The branch name will be defined as a node argument.\n const branchArguments = getArguments(tokens, placeholders);\n\n // We should have only a single identifer argument for a branch node, which is the branch name.\n if (branchArguments.length === 1 && branchArguments[0].type === \"identifier\") {\n // The branch name will be the first and only node argument.\n node.branchName = branchArguments[0].value as string;\n } else {\n throw new Error(\"expected single branch name argument\");\n }\n break;\n }\n\n case \"SELECTOR\": {\n // Create a SELECTOR AST node.\n const node = ASTNodeFactories.SELECTOR();\n\n // Push the SELECTOR node into the current scope.\n currentScope.push(node);\n\n // Try to pick any attributes off of the token stack.\n node.attributes = getAttributes(tokens, placeholders);\n\n popAndCheck(tokens, \"{\");\n\n // The new scope is that of the new SELECTOR nodes children.\n stack.push(node.children!);\n break;\n }\n\n case \"SEQUENCE\": {\n // Create a SEQUENCE AST node.\n const node = ASTNodeFactories.SEQUENCE();\n\n // Push the SEQUENCE node into the current scope.\n currentScope.push(node);\n\n // Try to pick any attributes off of the token stack.\n node.attributes = getAttributes(tokens, placeholders);\n\n popAndCheck(tokens, \"{\");\n\n // The new scope is that of the new SEQUENCE nodes children.\n stack.push(node.children!);\n break;\n }\n\n case \"PARALLEL\": {\n // Create a PARALLEL AST node.\n const node = ASTNodeFactories.PARALLEL();\n\n // Push the PARALLEL node into the current scope.\n currentScope.push(node);\n\n // Try to pick any attributes off of the token stack.\n node.attributes = getAttributes(tokens, placeholders);\n\n popAndCheck(tokens, \"{\");\n\n // The new scope is that of the new PARALLEL nodes children.\n stack.push(node.children!);\n break;\n }\n\n case \"LOTTO\": {\n // Create a LOTTO AST node.\n const node = ASTNodeFactories.LOTTO();\n\n // Push the LOTTO node into the current scope.\n currentScope.push(node);\n\n // If the next token is a '[' character then some ticket counts have been defined as arguments.\n if (tokens[0] === \"[\") {\n // Get the ticket count arguments, each argument must be a number.\n node.tickets = getArguments(\n tokens,\n placeholders,\n (arg) => arg.type === \"number\" && !!arg.isInteger,\n \"lotto node ticket counts must be integer values\"\n ).map((argument) => argument.value as number);\n }\n\n // Try to pick any attributes off of the token stack.\n node.attributes = getAttributes(tokens, placeholders);\n\n popAndCheck(tokens, \"{\");\n\n // The new scope is that of the new LOTTO nodes children.\n stack.push(node.children!);\n break;\n }\n\n case \"CONDITION\": {\n // Create a CONDITION AST node.\n const node = ASTNodeFactories.CONDITION();\n\n // Push the CONDITION node into the current scope.\n currentScope.push(node);\n\n // We must have arguments defined, as we require a condition function name argument.\n if (tokens[0] !== \"[\") {\n throw new Error(\"expected condition name identifier argument\");\n }\n\n // Grab the condition node arguments.\n const conditionArguments = getArguments(tokens, placeholders);\n\n // We should have at least a single identifier argument for a condition node, which is the condition function name.\n if (conditionArguments.length && conditionArguments[0].type === \"identifier\") {\n // The condition function name will be the first node argument.\n node.conditionName = conditionArguments.shift()!.value as string;\n } else {\n throw new Error(\"expected condition name identifier argument\");\n }\n\n // Only the first argument should have been an identifier, all following arguments must be string, number, boolean or null.\n conditionArguments\n .filter((arg) => arg.type === \"identifier\")\n .forEach((arg) => {\n throw new Error(\n \"invalid condition node argument value '\" +\n arg.value +\n \"', must be string, number, boolean or null\"\n );\n });\n\n // Any node arguments that follow the condition name identifier will be treated as condition function arguments.\n node.conditionArguments = conditionArguments;\n\n // Try to pick any attributes off of the token stack.\n node.attributes = getAttributes(tokens, placeholders);\n break;\n }\n\n case \"FLIP\": {\n // Create a FLIP AST node.\n const node = ASTNodeFactories.FLIP();\n\n // Push the Flip node into the current scope.\n currentScope.push(node);\n\n // Try to pick any attributes off of the token stack.\n node.attributes = getAttributes(tokens, placeholders);\n\n popAndCheck(tokens, \"{\");\n\n // The new scope is that of the new FLIP nodes children.\n stack.push(node.children!);\n break;\n }\n\n case \"SUCCEED\": {\n // Create a SUCCEED AST node.\n const node = ASTNodeFactories.SUCCEED();\n\n // Push the Succeed node into the current scope.\n currentScope.push(node);\n\n // Try to pick any attributes off of the token stack.\n node.attributes = getAttributes(tokens, placeholders);\n\n popAndCheck(tokens, \"{\");\n\n // The new scope is that of the new Succeed nodes children.\n stack.push(node.children!);\n break;\n }\n\n case \"FAIL\": {\n // Create a FAIL AST node.\n const node = ASTNodeFactories.FAIL();\n\n // Push the Fail node into the current scope.\n currentScope.push(node);\n\n // Try to pick any attributes off of the token stack.\n node.attributes = getAttributes(tokens, placeholders);\n\n popAndCheck(tokens, \"{\");\n\n // The new scope is that of the new Fail nodes children.\n stack.push(node.children!);\n break;\n }\n\n case \"WAIT\": {\n // Create a WAIT AST node.\n const node = ASTNodeFactories.WAIT();\n\n // Push the WAIT node into the current scope.\n currentScope.push(node);\n\n // The arguments of a wait node are optional. We may have:\n // - No node arguments, in which case the wait will be indefinite until it is aborted.\n // - One node argument which will be the explicit duration of the wait.\n // - Two node arguments which define the min and max duration bounds from which a random duration will be picked.\n if (tokens[0] === \"[\") {\n // Get the optional duration and longest duration of the wait.\n const nodeArguments = getArguments(\n tokens,\n placeholders,\n (arg) => arg.type === \"number\" && !!arg.isInteger,\n \"wait node durations must be integer values\"\n ).map((argument) => argument.value);\n\n // We may have:\n // - One node argument which will be the explicit duration of the wait.\n // - Two node arguments which define the min and max duration bounds from which a random duration will be picked.\n // - Too many arguments, which is not valid.\n if (nodeArguments.length === 1) {\n // An explicit duration was defined.\n node.duration = nodeArguments[0] as number;\n } else if (nodeArguments.length === 2) {\n // Min and max duration bounds were defined from which a random duration will be picked.\n node.durationMin = nodeArguments[0] as number;\n node.durationMax = nodeArguments[1] as number;\n } else if (nodeArguments.length > 2) {\n // An incorrect number of durations was defined.\n throw new Error(\"invalid number of wait node duration arguments defined\");\n }\n }\n\n // Try to pick any attributes off of the token stack.\n node.attributes = getAttributes(tokens, placeholders);\n break;\n }\n\n case \"REPEAT\": {\n // Create a REPEAT AST node.\n const node = ASTNodeFactories.REPEAT();\n\n // Push the REPEAT node into the current scope.\n currentScope.push(node);\n\n // The arguments of a repeat node are optional. We may have:\n // - No node arguments, in which case the repeat note will iterate indefinitely.\n // - One node argument which will be the explicit number of iterations to make.\n // - Two node arguments which define the min and max iteration bounds from which a random iteration count will be picked.\n if (tokens[0] === \"[\") {\n // An iteration count has been defined. Get the iteration and potential maximum iteration of the wait.\n const nodeArguments = getArguments(\n tokens,\n placeholders,\n (arg) => arg.type === \"number\" && !!arg.isInteger,\n \"repeat node iteration counts must be integer values\"\n ).map((argument) => argument.value);\n\n // We should have got one or two iteration counts.\n if (nodeArguments.length === 1) {\n // A static iteration count was defined.\n node.iterations = nodeArguments[0] as number;\n } else if (nodeArguments.length === 2) {\n // A minimum and maximum iteration count was defined.\n node.iterationsMin = nodeArguments[0] as number;\n node.iterationsMax = nodeArguments[1] as number;\n } else {\n // An incorrect number of iteration counts was defined.\n throw new Error(\"invalid number of repeat node iteration count arguments defined\");\n }\n }\n\n // Try to pick any attributes off of the token stack.\n node.attributes = getAttributes(tokens, placeholders);\n\n popAndCheck(tokens, \"{\");\n\n // The new scope is that of the new REPEAT nodes children.\n stack.push(node.children!);\n break;\n }\n\n case \"RETRY\": {\n // Create a RETRY AST node.\n const node = ASTNodeFactories.RETRY();\n\n // Push the RETRY node into the current scope.\n currentScope.push(node);\n\n // The arguments of a retry node are optional. We may have:\n // - No node arguments, in which case the retry note will attempt indefinitely.\n // - One node argument which will be the explicit number of attempts to make.\n // - Two node arguments which define the min and max attempt bounds from which a random attempt count will be picked.\n if (tokens[0] === \"[\") {\n // An attempt count has been defined. Get the attempt count and potential maximum attempt count of the wait.\n const nodeArguments = getArguments(\n tokens,\n placeholders,\n (arg) => arg.type === \"number\" && !!arg.isInteger,\n \"retry node attempt counts must be integer values\"\n ).map((argument) => argument.value);\n\n // We should have got one or two attempt counts.\n if (nodeArguments.length === 1) {\n // A static attempt count was defined.\n node.attempts = nodeArguments[0] as number;\n } else if (nodeArguments.length === 2) {\n // A minimum and maximum attempt count was defined.\n node.attemptsMin = nodeArguments[0] as number;\n node.attemptsMax = nodeArguments[1] as number;\n } else {\n // An incorrect number of attempt counts was defined.\n throw new Error(\"invalid number of retry node attempt count arguments defined\");\n }\n }\n\n // Try to pick any attributes off of the token stack.\n node.attributes = getAttributes(tokens, placeholders);\n\n popAndCheck(tokens, \"{\");\n\n // The new scope is that of the new RETRY nodes children.\n stack.push(node.children!);\n break;\n }\n\n case \"ACTION\": {\n // Create a ACTION AST node.\n const node = ASTNodeFactories.ACTION();\n\n // Push the ACTION node into the current scope.\n currentScope.push(node);\n\n // We must have arguments defined, as we require an action name argument.\n if (tokens[0] !== \"[\") {\n throw new Error(\"expected action name identifier argument\");\n }\n\n // The action name will be defined as a node argument.\n const actionArguments = getArguments(tokens, placeholders);\n\n // We should have at least one identifer argument for an action node, which is the action name.\n if (actionArguments.length && actionArguments[0].type === \"identifier\") {\n // The action name will be the first and only node argument.\n node.actionName = actionArguments.shift()!.value as string;\n } else {\n throw new Error(\"expected action name identifier argument\");\n }\n\n // Only the first argument should have been an identifier, all following arguments must be string, number, boolean or null.\n actionArguments\n .filter((arg) => arg.type === \"identifier\")\n .forEach((arg) => {\n throw new Error(\n \"invalid action node argument value '\" +\n arg.value +\n \"', must be string, number, boolean or null\"\n );\n });\n\n // Any node arguments that follow the action name identifier will be treated as action function arguments.\n node.actionArguments = actionArguments;\n\n // Try to pick any attributes off of the token stack.\n node.attributes = getAttributes(tokens, placeholders);\n break;\n }\n\n case \"}\": {\n // The '}' character closes the current scope.\n stack.pop();\n break;\n }\n\n default: {\n throw new Error(`unexpected token '${token}'`);\n }\n }\n }\n\n // A function to recursively validate each of the nodes in the AST.\n const validateASTNode = (node: Validatable, depth: number): void => {\n // Validate the node.\n node.validate(depth);\n\n // Validate each child of the node.\n (node.children || []).forEach((child) => validateASTNode(child, depth + 1));\n };\n\n // Start node validation from the definition root.\n validateASTNode(\n {\n children: stack[0] as RootAstNode[],\n validate(this: { children: RootAstNode[] }) {\n // We must have at least one node defined as the definition scope, which should be a root node.\n if (this.children.length === 0) {\n throw new Error(\"expected root node to have been defined\");\n }\n\n // Each node at the base of the definition scope MUST be a root node.\n for (const definitionLevelNode of this.children) {\n if (definitionLevelNode.type !== \"root\") {\n throw new Error(\"expected root node at base of definition\");\n }\n }\n\n // Exactly one root node must not have a name defined. This will be the main root, others will have to be referenced via branch nodes.\n if (this.children.filter((definitionLevelNode) => definitionLevelNode.name === null).length !== 1) {\n throw new Error(\"expected single unnamed root node at base of definition to act as main root\");\n }\n\n // No two named root nodes can have matching names.\n const rootNodeNames: string[] = [];\n for (const definitionLevelNode of this.children) {\n if (rootNodeNames.indexOf(definitionLevelNode.name!) !== -1) {\n throw new Error(`multiple root nodes found with duplicate name '${definitionLevelNode.name}'`);\n } else {\n rootNodeNames.push(definitionLevelNode.name!);\n }\n }\n }\n },\n 0\n );\n\n // Return the root AST nodes.\n return stack[0];\n}\n\n/**\n * Pop the next raw token off of the stack and throw an error if it wasn't the expected one.\n * @param tokens The array of remaining tokens.\n * @param expected An optional string or array or items, one of which must match the next popped token.\n * @returns The popped token.\n */\nfunction popAndCheck(tokens: string[], expected: string | string[]) {\n // Get and remove the next token.\n const popped = tokens.shift();\n\n // We were expecting another token.\n if (popped === undefined) {\n throw new Error(\"unexpected end of definition\");\n }\n\n // Do we have an expected token/tokens array?\n if (expected !== undefined) {\n // Check whether the popped token matches at least one of our expected items.\n var tokenMatchesExpectation = ([] as string[])\n .concat(expected)\n .some((item) => popped.toUpperCase() === item.toUpperCase());\n\n // Throw an error if the popped token didn't match any of our expected items.\n if (!tokenMatchesExpectation) {\n const expectationString = ([] as string[])\n .concat(expected)\n .map((item) => \"'\" + item + \"'\")\n .join(\" or \");\n\n throw new Error(`unexpected token found. Expected '${expectationString}' but got '${popped}'`);\n }\n }\n\n // Return the popped token.\n return popped;\n}\n\ntype StringPlaceholders = { [key: string]: string };\n\n/**\n * Pull an argument definition list off of the token stack.\n * @param tokens The array of remaining tokens.\n * @param stringArgumentPlaceholders The mapping of string literal node argument placeholders to original values.\n * @param argumentValidator The argument validator function.\n * @param validationFailedMessage The exception message to throw if argument validation fails.\n * @returns The argument definition list.\n */\nfunction getArguments(\n tokens: string[],\n stringArgumentPlaceholders: StringPlaceholders,\n argumentValidator?: (arg: AnyArgument) => boolean,\n validationFailedMessage?: string\n) {\n // Any lists of arguments will always be wrapped in '[]' for node arguments or '()' for attribute arguments.\n // We are looking for a '[' or '(' opener that wraps the argument tokens and the relevant closer.\n const closer = popAndCheck(tokens, [\"[\", \"(\"]) === \"[\" ? \"]\" : \")\";\n\n const argumentListTokens: string[] = [];\n const argumentList: AnyArgument[] = [];\n\n // Grab all tokens between the '[' and ']' or '(' and ')'.\n while (tokens.length && tokens[0] !== closer) {\n // The next token is part of our arguments list.\n argumentListTokens.push(tokens.shift()!);\n }\n\n // Validate the order of the argument tokens. Each token must either be a ',' or a single argument that satisfies the validator.\n argumentListTokens.forEach((token, index) => {\n // Get whether this token should be an actual argument.\n const shouldBeArgumentToken = !(index & 1);\n\n // If the current token should be an actual argument then validate it,otherwise it should be a ',' token.\n if (shouldBeArgumentToken) {\n // Get the argument definition.\n const argumentDefinition = getArgumentDefinition(token!, stringArgumentPlaceholders);\n\n // Try to validate the argument.\n if (argumentValidator && !argumentValidator(argumentDefinition)) {\n throw new Error(validationFailedMessage);\n }\n\n // This is a valid argument!\n argumentList.push(argumentDefinition);\n } else {\n // The current token should be a ',' token.\n if (token !== \",\") {\n throw new Error(`invalid argument list, expected ',' or ']' but got '${token}'`);\n }\n }\n });\n\n // The arguments list should terminate with a ']' or ')' token, depending on the opener.\n popAndCheck(tokens, closer);\n\n // Return the argument list.\n return argumentList;\n}\n\n/**\n * Gets an argument value definition.\n * @param token The argument token.\n * @param stringArgumentPlaceholders The mapping of string literal node argument placeholders to original values.\n * @returns An argument value definition.\n */\nfunction getArgumentDefinition(token: string, stringArgumentPlaceholders: StringPlaceholders): AnyArgument {\n // Check whether the token represents a null value.\n if (token === \"null\") {\n return {\n value: null,\n type: \"null\"\n } as NullArgument;\n }\n\n // Check whether the token represents a boolean value.\n if (token === \"true\" || token === \"false\") {\n return {\n value: token === \"true\",\n type: \"boolean\"\n } as BooleanArgument;\n }\n\n // Check whether the token represents a number value.\n // TODO: Relies on broken isNaN - see MDN.\n // if (!Number.isNaN(token)) {\n if (!isNaN(token as any)) {\n return {\n value: parseFloat(token),\n isInteger: parseFloat(token) === parseInt(token, 10),\n type: \"number\"\n } as NumberArgument;\n }\n\n // Check whether the token is a placeholder (e.g. @@0@@) representing a string literal.\n if (token.match(/^@@\\d+@@$/g)) {\n return {\n value: stringArgumentPlaceholders[token].replace('\\\\\"', '\"'),\n type: \"string\"\n } as StringPlaceholderArgument;\n }\n\n // The only remaining option is that the argument value is an identifier.\n return {\n value: token,\n type: \"identifier\"\n } as IdentifierArgument;\n}\n\n/**\n * Pull any attributes off of the token stack.\n * @param tokens The array of remaining tokens.\n * @param stringArgumentPlaceholders The mapping of string literal node argument placeholders to original values.\n * @returns An array of attributes defined by any directly following tokens.\n */\nfunction getAttributes(tokens: string[], stringArgumentPlaceholders: StringPlaceholders) {\n // Create an array to hold any attributes found.\n const attributes: Attribute[] = [];\n\n // Keep track of names of attribute that we have found on the token stack, as we cannot have duplicates.\n const attributesFound: string[] = [];\n\n // Try to get the attribute factory for the next token.\n let attributeFactory = AttributeFactories[(tokens[0] || \"\").toUpperCase()];\n\n // Pull attribute tokens off of the tokens stack until we have no more.\n while (attributeFactory) {\n // Check to make sure that we have not already created a attribute of this type for this node.\n if (attributesFound.indexOf(tokens[0].toUpperCase()) !== -1) {\n throw new Error(`duplicate attribute '${tokens[0].toUpperCase()}' found for node`);\n }\n\n // Add the current attribute type to our array of found attributes.\n attributesFound.push(tokens.shift()!.toUpperCase());\n\n // Grab any attribute arguments.\n const attributeArguments = getArguments(tokens, stringArgumentPlaceholders);\n\n // The first attribute argument has to be an identifer, this will reference an agent function.\n if (attributeArguments.length === 0 || attributeArguments[0].type !== \"identifier\") {\n throw new Error(\"expected agent function name identifier argument for attribute\");\n }\n\n // Grab the first attribute which is an identifier that will reference an agent function.\n const attributeFunctionName = attributeArguments.shift()! as IdentifierArgument;\n\n // Any remaining attribute arguments must have a type of string, number, boolean or null.\n attributeArguments\n .filter((arg) => arg.type === \"identifier\")\n .forEach((arg) => {\n throw new Error(\n \"invalid attribute argument value '\" + arg.value + \"', must be string, number, boolean or null\"\n );\n });\n\n // Create the attribute and add it to the array of attributes found.\n attributes.push(attributeFactory(attributeFunctionName.value, attributeArguments));\n\n // Try to get the next attribute name token, as there could be multiple.\n attributeFactory = AttributeFactories[(tokens[0] || \"\").toUpperCase()];\n }\n\n return attributes;\n}\n\n/**\n * Swaps out any node/attribute argument string literals with placeholders.\n * @param definition The definition.\n * @returns An object containing a mapping of placeholders to original string values as well as the processed definition string.\n */\nfunction substituteStringLiterals(definition: string): {\n placeholders: { [key: string]: string };\n processedDefinition: string;\n} {\n // Create an object to hold the mapping of placeholders to original string values.\n const placeholders: StringPlaceholders = {};\n\n // Replace any string literals wrapped with double quotes in our definition with placeholders to be processed later.\n const processedDefinition = definition.replace(/\\\"(\\\\.|[^\"\\\\])*\\\"/g, (match) => {\n var strippedMatch = match.substring(1, match.length - 1);\n var placeholder = Object.keys(placeholders).find((key) => placeholders[key] === strippedMatch);\n\n // If we have no existing string literal match then create a new placeholder.\n if (!placeholder) {\n placeholder = `@@${Object.keys(placeholders).length}@@`;\n placeholders[placeholder] = strippedMatch;\n }\n\n return placeholder;\n });\n\n return { placeholders, processedDefinition };\n}\n\n/**\n * Parse the tree definition into an array of raw tokens.\n * @param definition The definition.\n * @returns An array of tokens parsed from the definition.\n */\nfunction parseTokensFromDefinition(definition: string): string[] {\n // Add some space around various important characters so that they can be plucked out easier as individual tokens.\n definition = definition.replace(/\\(/g, \" ( \");\n definition = definition.replace(/\\)/g, \" ) \");\n definition = definition.replace(/\\{/g, \" { \");\n definition = definition.replace(/\\}/g, \" } \");\n definition = definition.replace(/\\]/g, \" ] \");\n definition = definition.replace(/\\[/g, \" [ \");\n definition = definition.replace(/\\,/g, \" , \");\n\n // Split the definition into raw token form and return it.\n return definition.replace(/\\s+/g, \" \").trim().split(\" \");\n}\n", "import GuardPath, { GuardPathPart } from \"./attributes/guards/GuardPath\";\nimport buildRootASTNodes, { AnyArgument, RootAstNode } from \"./RootAstNodesBuilder\";\nimport State, { AnyState } from \"./State\";\nimport Lookup from \"./Lookup\";\nimport Node from \"./nodes/Node\";\nimport Root from \"./nodes/decorator/Root\";\nimport Composite from \"./nodes/composite/Composite\";\nimport Decorator from \"./nodes/decorator/Decorator\";\nimport { Agent, GlobalFunction } from \"./Agent\";\nimport { CallbackAttributeDetails } from \"./attributes/callbacks/Callback\";\nimport { GuardAttributeDetails } from \"./attributes/guards/Guard\";\nimport { BehaviourTreeOptions } from \"./BehaviourTreeOptions\";\nimport { convertMDSLToJSON } from \"./mdsl/MDSLDefinitionParser\";\n\n// Purely for outside inspection of the tree.\nexport type FlattenedTreeNode = {\n id: string;\n type: string;\n caption: string;\n state: AnyState;\n guards: GuardAttributeDetails[];\n callbacks: CallbackAttributeDetails[];\n args: AnyArgument[];\n parentId: string | null;\n};\n\n/**\n * A representation of a behaviour tree.\n */\nexport class BehaviourTree {\n /**\n * The main root tree node.\n */\n public readonly rootNode: Root;\n\n /**\n * Creates a new instance of the BehaviourTree class.\n * @param definition The behaviour tree definition.\n * @param agent The agent instance that this behaviour tree is modelling behaviour for.\n * @param options The behaviour tree options object.\n */\n constructor(definition: string, private agent: Agent, private options: BehaviourTreeOptions = {}) {\n // The tree definition must be defined and a valid string.\n if (typeof definition !== \"string\") {\n throw new Error(\"the tree definition must be a string\");\n }\n\n // The agent must be defined and not null.\n if (typeof agent !== \"object\" || agent === null) {\n throw new Error(\"the agent must be defined and not null\");\n }\n\n // Parse the behaviour tree definition, create the populated tree of behaviour tree nodes, and get the root.\n this.rootNode = BehaviourTree._createRootNode(definition);\n }\n\n /**\n * Gets whether the tree is in the RUNNING state.\n * @returns true if the tree is in the RUNNING state, otherwise false.\n */\n isRunning() {\n return this.rootNode.getState() === State.RUNNING;\n }\n\n /**\n * Gets the current tree state of SUCCEEDED, FAILED, READY or RUNNING.\n * @returns The current tree state.\n */\n getState() {\n return this.rootNode.getState();\n }\n\n /**\n * Step the tree.\n * 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.\n * 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\n * 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.\n *\n * 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.\n */\n step() {\n // If the root node has already been stepped to completion then we need to reset it.\n if (this.rootNode.getState() === State.SUCCEEDED || this.rootNode.getState() === State.FAILED) {\n this.rootNode.reset();\n }\n\n try {\n this.rootNode.update(this.agent, this.options);\n } catch (exception) {\n throw new Error(`error stepping tree: ${(exception as Error).message}`);\n }\n }\n\n /**\n * Resets the tree from the root node outwards to each nested node, giving each a state of READY.\n */\n reset() {\n this.rootNode.reset();\n }\n\n /**\n * Gets the flattened details of every node in the tree.\n * @returns The flattened details of every node in the tree.\n */\n getFlattenedNodeDetails(): FlattenedTreeNode[] {\n // Create an empty flattened array of tree nodes.\n const flattenedTreeNodes: FlattenedTreeNode[] = [];\n\n /**\n * Helper function to process a node instance and push details into the flattened tree nodes array.\n * @param node The current node.\n * @param parentUid The UID of the node parent, or null if the node is the main root node.\n */\n const processNode = (node: Node, parentUid: string | null) => {\n // Get the guard and callback attribute details for this node.\n const guards = node\n .getAttributes()\n .filter((attribute) => attribute.isGuard())\n .map((attribute) => attribute.getDetails()) as GuardAttributeDetails[];\n const callbacks = node\n .getAttributes()\n .filter((attribute) => !attribute.isGuard())\n .map((attribute) => attribute.getDetails()) as CallbackAttributeDetails[];\n\n // Push the current node into the flattened nodes array.\n flattenedTreeNodes.push({\n id: node.getUid(),\n type: node.getType(),\n caption: node.getName(),\n state: node.getState(),\n guards,\n callbacks,\n args: node.getArguments(),\n parentId: parentUid\n });\n\n // Process each of the nodes children if it is not a leaf node.\n if (!node.isLeafNode()) {\n (node as Composite | Decorator)\n .getChildren()\n .forEach((child) => processNode(child, (node as Composite | Decorator).getUid()));\n }\n };\n\n // Convert the nested node structure into a flattened array of node details.\n processNode(this.rootNode, null);\n\n return flattenedTreeNodes;\n }\n\n /**\n * Registers the action/condition/guard/callback function or subtree with the given name.\n * @param name The name of the function or subtree to register.\n * @param value The function or subtree definition to register.\n */\n static register(name: string, value: GlobalFunction | string) {\n if (typeof value === \"function\") {\n // We are going to register a action/condition/guard/callback function.\n Lookup.setFunc(name, value);\n } else if (typeof value === \"string\") {\n // We are going to register a subtree.\n let rootASTNodes: RootAstNode[];\n\n try {\n // Try to create the behaviour tree AST based on the definition provided, this could fail if the definition is invalid.\n rootASTNodes = buildRootASTNodes(value);\n } catch (exception) {\n // There was an issue in trying to parse and build the tree definition.\n throw new Error(`error registering definition: ${(exception as Error).message}`);\n }\n\n // This function should only ever be called with a definition containing a single unnamed root node.\n if (rootASTNodes.length != 1 || rootASTNodes[0].name !== null) {\n throw new Error(\"error registering definition: expected a single unnamed root node\");\n }\n\n Lookup.setSubtree(name, rootASTNodes[0]);\n } else {\n throw new Error(\"unexpected value, expected string definition or function\");\n }\n }\n\n /**\n * Unregisters the registered action/condition/guard/callback function or subtree with the given name.\n * @param name The name of the registered action/condition/guard/callback function or subtree to unregister.\n */\n static unregister(name: string): void {\n Lookup.remove(name);\n }\n\n /**\n * Unregister all registered action/condition/guard/callback functions and subtrees.\n */\n static unregisterAll(): void {\n Lookup.empty();\n }\n\n /**\n * Parses a behaviour tree definition and creates a tree of behaviour tree nodes.\n * @param {string} definition The behaviour tree definition.\n * @returns The root behaviour tree node.\n */\n private static _createRootNode(definition: string): Root {\n // TODO Remove!\n try {\n // parseToJSON(definition);\n } catch (exception) {\n console.log(exception);\n }\n\n try {\n // Try to create the behaviour tree AST based on the definition provided, this could fail if the definition is invalid.\n const rootASTNodes = buildRootASTNodes(definition);\n\n // Create a symbol to use as the main root key in our root node mapping.\n const mainRootNodeKey = Symbol(\"__root__\");\n\n // Create a mapping of root node names to root AST tokens. The main root node will have a key of Symbol(\"__root__\").\n const rootNodeMap: { [key: string | symbol]: RootAstNode } = {};\n for (const rootASTNode of rootASTNodes) {\n rootNodeMap[rootASTNode.name === null ? mainRootNodeKey : rootASTNode.name!] = rootASTNode;\n }\n\n // Convert the AST to our actual tree and get the root node.\n const rootNode: Root = rootNodeMap[mainRootNodeKey].createNodeInstance(\n // Create a provider for named root nodes that are part of our definition or have been registered. Prioritising the former.\n (name: string): RootAstNode => (rootNodeMap[name] ? rootNodeMap[name] : Lookup.getSubtree(name)),\n []\n );\n\n // Set a guard path on every leaf of the tree to evaluate as part of its update.\n BehaviourTree._applyLeafNodeGuardPaths(rootNode);\n\n // Return the root node.\n return rootNode;\n } catch (exception) {\n // There was an issue in trying to parse and build the tree definition.\n throw new Error(`error parsing tree: ${(exception as Error).message}`);\n }\n }\n\n /**\n * Applies a guard path to every leaf of the tree to evaluate as part of each update.\n * @param rootNode The main root tree node.\n */\n private static _applyLeafNodeGuardPaths(rootNode: Root) {\n const nodePaths: Node[][] = [];\n\n const findLeafNodes = (path: Node[], node: Node) => {\n // Add the current node to the path.\n path = path.concat(node);\n\n // Check whether the current node is a leaf node.\n if (node.isLeafNode()) {\n nodePaths.push(path);\n } else {\n (node as Composite | Decorator).getChildren().forEach((child) => findLeafNodes(path, child));\n }\n };\n\n // Find all leaf node paths, starting from the root.\n findLeafNodes([], rootNode);\n\n nodePaths.forEach((path) => {\n // Each node in the current path will have to be assigned a guard path, working from the root outwards.\n for (let depth = 0; depth < path.length; depth++) {\n // Get the node in the path at the current depth.\n const currentNode = path[depth];\n\n // The node may already have been assigned a guard path, if so just skip it.\n if (currentNode.hasGuardPath()) {\n continue;\n }\n\n // Create the guard path for the current node.\n const guardPath = new GuardPath(\n path\n .slice(0, depth + 1)\n .map((node) => ({ node, guards: node.getGuardAttributes() }))\n .filter((details) => details.guards.length > 0)\n );\n\n // Assign the guard path to the current node.\n currentNode.setGuardPath(guardPath);\n }\n });\n }\n}\n"], + "mappings": "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", + "names": ["Participant", "Lotto", "createLotto", "State", "createLotto", "substituteStringLiterals", "parseTokensFromDefinition", "popAndCheck", "getArgumentDefinition"] } diff --git a/dist/mdsl/MDSLDefinitionParser.d.ts b/dist/mdsl/MDSLDefinitionParser.d.ts index a873221..53b2754 100644 --- a/dist/mdsl/MDSLDefinitionParser.d.ts +++ b/dist/mdsl/MDSLDefinitionParser.d.ts @@ -1,7 +1,7 @@ import { RootNodeDefinition } from "../BehaviourTreeDefinition"; /** - * Parse the MDSL tree definition string into an equivalent JSON definition. + * Convert the MDSL tree definition string into an equivalent JSON definition. * @param definition The tree definition string as MDSL. * @returns The root node JSON definitions. */ -export declare function parseMDSLToJSON(definition: string): RootNodeDefinition[]; +export declare function convertMDSLToJSON(definition: string): RootNodeDefinition[]; diff --git a/dist/mdsl/MDSLUtilities.d.ts b/dist/mdsl/MDSLUtilities.d.ts index 6e9acac..29312a5 100644 --- a/dist/mdsl/MDSLUtilities.d.ts +++ b/dist/mdsl/MDSLUtilities.d.ts @@ -1,34 +1,9 @@ -import { CompositeNodeDefinition, DecoratorNodeDefinition, NodeDefinition, RootNodeDefinition } from "../BehaviourTreeDefinition"; /** * A type defining an object that holds a reference to substitued string literals parsed from the definition. */ export type StringLiteralPlaceholders = { [key: string]: string; }; -/** - * A type guard function that returns true if the specified node satisfies the RootNodeDefinition type. - * @param node The node. - * @returns A value of true if the specified node satisfies the RootNodeDefinition type. - */ -export declare function isRootNode(node: NodeDefinition): node is RootNodeDefinition; -/** - * A type guard function that returns true if the specified node satisfies the NodeDefinition type. - * @param node The node. - * @returns A value of true if the specified node satisfies the NodeDefinition type. - */ -export declare function isLeafNode(node: NodeDefinition): node is NodeDefinition; -/** - * A type guard function that returns true if the specified node satisfies the DecoratorNodeDefinition type. - * @param node The node. - * @returns A value of true if the specified node satisfies the DecoratorNodeDefinition type. - */ -export declare function isDecoratorNode(node: NodeDefinition): node is DecoratorNodeDefinition; -/** - * A type guard function that returns true if the specified node satisfies the CompositeNodeDefinition type. - * @param node The node. - * @returns A value of true if the specified node satisfies the CompositeNodeDefinition type. - */ -export declare function isCompositeNode(node: NodeDefinition): node is CompositeNodeDefinition; /** * Pop the next raw token from the specified array of tokens and throw an error if it wasn't the expected one. * @param tokens The array of tokens. diff --git a/src/BehaviourTree.ts b/src/BehaviourTree.ts index 7713ea1..48ece1b 100644 --- a/src/BehaviourTree.ts +++ b/src/BehaviourTree.ts @@ -10,7 +10,7 @@ import { Agent, GlobalFunction } from "./Agent"; import { CallbackAttributeDetails } from "./attributes/callbacks/Callback"; import { GuardAttributeDetails } from "./attributes/guards/Guard"; import { BehaviourTreeOptions } from "./BehaviourTreeOptions"; -import { parseMDSLToJSON } from "./mdsl/MDSLDefinitionParser"; +import { convertMDSLToJSON } from "./mdsl/MDSLDefinitionParser"; // Purely for outside inspection of the tree. export type FlattenedTreeNode = { diff --git a/src/BehaviourTreeDefinitionUtilities.ts b/src/BehaviourTreeDefinitionUtilities.ts index 87cab25..78212e5 100644 --- a/src/BehaviourTreeDefinitionUtilities.ts +++ b/src/BehaviourTreeDefinitionUtilities.ts @@ -1,4 +1,11 @@ -import { NodeDefinition, RootNodeDefinition, DecoratorNodeDefinition, CompositeNodeDefinition, AnyNode, BranchNodeDefinition } from "./BehaviourTreeDefinition"; +import { + NodeDefinition, + RootNodeDefinition, + DecoratorNodeDefinition, + CompositeNodeDefinition, + AnyNode, + BranchNodeDefinition +} from "./BehaviourTreeDefinition"; /** * A type guard function that returns true if the specified node satisfies the RootNodeDefinition type. diff --git a/src/BehaviourTreeDefinitionValidator.ts b/src/BehaviourTreeDefinitionValidator.ts index 26bc517..06ea53d 100644 --- a/src/BehaviourTreeDefinitionValidator.ts +++ b/src/BehaviourTreeDefinitionValidator.ts @@ -1,16 +1,16 @@ import { RootNodeDefinition } from "./BehaviourTreeDefinition"; import { flattenDefinition, isBranchNode, isInteger } from "./BehaviourTreeDefinitionUtilities"; -import { parseMDSLToJSON } from "./mdsl/MDSLDefinitionParser"; +import { convertMDSLToJSON } from "./mdsl/MDSLDefinitionParser"; /** * An object representing the result of validating a tree definition. */ export type DefinitionValidationResult = { - /** + /** * A flag defining whether validation succeeded. */ succeeded: boolean; - /** + /** * A string containing the error message if validation did not succeed. */ errorMessage?: string; @@ -29,17 +29,17 @@ export function validateDefinition(definition: any): DefinitionValidationResult if (definition === null || typeof definition === "undefined") { return createFailureResult("definition is null or undefined"); } - + let rootNodeDefinitions: any[]; // We are expecting a definition in one of three different forms: // - A string which we will assume is mdsl and we will parse this to JSON before validation. // - An array which we will assume is an array of root node definitions with at least one being the primary root node (no 'id' property) - // - An object which we will assume is the primary root node and should not have an 'id' property. + // - An object which we will assume is the primary root node and should not have an 'id' property. if (typeof definition === "string") { try { // The definition is a string which we can assume is mdsl, so attempt to parse it to a JSON definition in the form of an array of root node definitions. - rootNodeDefinitions = parseMDSLToJSON(definition); + rootNodeDefinitions = convertMDSLToJSON(definition); } catch (error) { // We failed to parse the JSON from the mdsl, this is likely to be the result of it not being a valid mdsl string. return createFailureResult(`invalid mdsl: ${definition}`); @@ -56,7 +56,9 @@ export function validateDefinition(definition: any): DefinitionValidationResult // If we have any invalid node definitions then validation has failed. if (invalidDefinitionElements.length) { - return createFailureResult("invalid elements in definition array, each must be an root node definition object"); + return createFailureResult( + "invalid elements in definition array, each must be an root node definition object" + ); } // Our definition is already an array of root node definition objects. @@ -69,18 +71,29 @@ export function validateDefinition(definition: any): DefinitionValidationResult return createFailureResult(`unexpected definition type of '${typeof definition}'`); } - // TODO Iterate over our array of root nodes and call validateNode for each, passing an initial depth of 0, wrapped in a try catch to handle validation failures. + // Iterate over our array of root nodes and call validateNode for each, passing an initial depth of 0, wrapped in a try catch to handle validation failures. + try { + rootNodeDefinitions.forEach((rootNodeDefinition) => validateNode(rootNodeDefinition, 0)); + } catch (error) { + // Handle cases where we have caught a thrown Error and return a failure result with the error message. + if (error instanceof Error) { + return createFailureResult(error.message); + } + + // No idea what happened here! + return createFailureResult(`unexpected error: ${error}`); + } // Unpack all of the root node definitions into arrays of main ('id' defined) and sub ('id' not defined) root node definitions. const mainRootNodeDefinitions = rootNodeDefinitions.filter(({ id }) => typeof id === "undefined"); const subRootNodeDefinitions = rootNodeDefinitions.filter(({ id }) => typeof id === "string" && id.length > 0); - // We should ALWAYS have exactly one root node definition without an 'id' property defined, which is out main root node definition. + // We should ALWAYS have exactly one root node definition without an 'id' property defined, which is out main root node definition. if (mainRootNodeDefinitions.length !== 1) { return createFailureResult("expected single root node without 'id' property defined to act as main root"); } - // We should never have duplicate 'id' properties across our sub root node definitions. + // We should never have duplicate 'id' properties across our sub root node definitions. const subRootNodeIdenitifers: string[] = []; for (const { id } of subRootNodeDefinitions) { // Have we already come across this 'id' property value? @@ -98,7 +111,7 @@ export function validateDefinition(definition: any): DefinitionValidationResult if (circularDependencyPath) { return createFailureResult(`circular dependency found in branch node references: ${circularDependencyPath}`); } - + // Our definition was valid! return { succeeded: true }; } @@ -113,18 +126,21 @@ function findBranchCircularDependencyPath(rootNodeDefinitions: RootNodeDefinitio // Create a mapping of root node identifiers to other root nodes that they reference via branch nodes. // Below is an example of a mapping that includes a circular dependency (root => a => b => c => a) // [{ refs: ["a", "b"] }, { id: "a", refs: ["b"] }, { id: "b", refs: ["c"] }, { id: "c", refs: ["a"] }] - const rootNodeMappings: { id: string | undefined, refs: string[] }[] = rootNodeDefinitions - .map((rootNodeDefinition) => ({ + const rootNodeMappings: { id: string | undefined; refs: string[] }[] = rootNodeDefinitions.map( + (rootNodeDefinition) => ({ id: rootNodeDefinition.id, - refs: flattenDefinition(rootNodeDefinition).filter(isBranchNode).map(({ ref }) => ref) - })); + refs: flattenDefinition(rootNodeDefinition) + .filter(isBranchNode) + .map(({ ref }) => ref) + }) + ); let badPathFormatted: string | null = null; // A recursive function to walk through the mappings, keeping track of which root nodes we have visited in the form of a path of root node identifiers. - const followRefs = (mapping: { id: string | undefined, refs: string[] }, path: (string | undefined)[] = []) => { + const followRefs = (mapping: { id: string | undefined; refs: string[] }, path: (string | undefined)[] = []) => { // Have we found a circular dependency? - if(path.includes(mapping.id)) { + if (path.includes(mapping.id)) { // We found a circular dependency! Get the bad path of root node identifiers. const badPath = [...path, mapping.id]; @@ -144,7 +160,7 @@ function findBranchCircularDependencyPath(rootNodeDefinitions: RootNodeDefinitio followRefs(subMapping, [...path, mapping.id]); } } - } + }; return badPathFormatted; } @@ -157,7 +173,9 @@ function findBranchCircularDependencyPath(rootNodeDefinitions: RootNodeDefinitio function validateNode(definition: any, depth: number): void { // Every node must be valid object and have a non-empty 'type' string property. if (typeof definition !== "object" || typeof definition.type !== "string" || definition.type.length === 0) { - throw new Error(`node definition is not an object or 'type' property is not a non-empty string at depth '${depth}'`); + throw new Error( + `node definition is not an object or 'type' property is not a non-empty string at depth '${depth}'` + ); } // How we validate this node definition will depend on its type. @@ -173,7 +191,7 @@ function validateNode(definition: any, depth: number): void { case "wait": validateWaitNode(definition, depth); break; - + case "branch": validateBranchNode(definition, depth); break; @@ -194,6 +212,14 @@ function validateNode(definition: any, depth: number): void { validateFlipNode(definition, depth); break; + case "repeat": + validateRepeatNode(definition, depth); + break; + + case "retry": + validateRetryNode(definition, depth); + break; + case "sequence": validateSequenceNode(definition, depth); break; @@ -206,8 +232,6 @@ function validateNode(definition: any, depth: number): void { validateParallelNode(definition, depth); break; - // TODO Add cases for all other nodes. - default: throw new Error(`unexpected node type of '${definition.type}' at depth '${depth}'`); } @@ -231,17 +255,23 @@ function validateNodeAttributes(definition: any, depth: number): void { // The attribute definition must be an object. if (typeof attributeDefinition !== "object") { - throw new Error(`expected attribute '${attributeName}' to be an object for '${definition.type}' node at depth '${depth}'`); + throw new Error( + `expected attribute '${attributeName}' to be an object for '${definition.type}' node at depth '${depth}'` + ); } // The 'call' property must be defined for any attribute definition. if (typeof attributeDefinition.call !== "string" || attributeDefinition.call.length === 0) { - throw new Error(`expected 'call' property for attribute '${attributeName}' to be a non-empty string for '${definition.type}' node at depth '${depth}'`); + throw new Error( + `expected 'call' property for attribute '${attributeName}' to be a non-empty string for '${definition.type}' node at depth '${depth}'` + ); } // If any node attribute arguments have been defined then they must have been defined in an array. if (typeof attributeDefinition.args !== "undefined" && !Array.isArray(attributeDefinition.args)) { - throw new Error(`expected 'args' property for attribute '${attributeName}' to be an array for '${definition.type}' node at depth '${depth}'`); + throw new Error( + `expected 'args' property for attribute '${attributeName}' to be an array for '${definition.type}' node at depth '${depth}'` + ); } }); } @@ -348,6 +378,90 @@ function validateFlipNode(definition: any, depth: number): void { validateNode(definition.child, depth + 1); } +/** + * Validate an object that we expect to be a repeat node definition. + * @param definition An object that we expect to be a repeat node definition. + * @param depth The depth of the node in the definition tree. + */ +function validateRepeatNode(definition: any, depth: number): void { + // Check that the node type is correct. + if (definition.type !== "repeat") { + throw new Error(`expected node type of 'repeat' for repeat node at depth '${depth}'`); + } + + // A repeat node is a decorator node, so must have a child node defined. + if (typeof definition.child === "undefined") { + throw new Error(`expected property 'child' to be defined for repeat node at depth '${depth}'`); + } + + // Check whether an 'iterations' property has been defined, it may not have been if this node is to repeat indefinitely. + if (typeof definition.iterations !== "undefined") { + if (Array.isArray(definition.iterations)) { + // Check whether any elements of the array are not integer values. + const containsNonInteger = !!definition.iterations.find((value: unknown) => !isInteger(value)); + + // If the 'iterations' property is an array then it MUST contain two integer values. + if (definition.iterations.length !== 2 || containsNonInteger) { + throw new Error( + `expected array containing two integer values for 'iterations' property if defined for repeat node at depth '${depth}'` + ); + } + } else if (!isInteger(definition.iterations)) { + throw new Error( + `expected integer value or array containing two integer values for 'iterations' property if defined for repeat node at depth '${depth}'` + ); + } + } + + // Validate the node attributes. + validateNodeAttributes(definition, depth); + + // Validate the child node of this decorator node. + validateNode(definition.child, depth + 1); +} + +/** + * Validate an object that we expect to be a retry node definition. + * @param definition An object that we expect to be a retry node definition. + * @param depth The depth of the node in the definition tree. + */ +function validateRetryNode(definition: any, depth: number): void { + // Check that the node type is correct. + if (definition.type !== "retry") { + throw new Error(`expected node type of 'retry' for retry node at depth '${depth}'`); + } + + // A retry node is a decorator node, so must have a child node defined. + if (typeof definition.child === "undefined") { + throw new Error(`expected property 'child' to be defined for retry node at depth '${depth}'`); + } + + // Check whether an 'attempts' property has been defined, it may not have been if this node is to retry indefinitely. + if (typeof definition.attempts !== "undefined") { + if (Array.isArray(definition.attempts)) { + // Check whether any elements of the array are not integer values. + const containsNonInteger = !!definition.attempts.find((value: unknown) => !isInteger(value)); + + // If the 'attempts' property is an array then it MUST contain two integer values. + if (definition.attempts.length !== 2 || containsNonInteger) { + throw new Error( + `expected array containing two integer values for 'attempts' property if defined for retry node at depth '${depth}'` + ); + } + } else if (!isInteger(definition.attempts)) { + throw new Error( + `expected integer value or array containing two integer values for 'attempts' property if defined for retry node at depth '${depth}'` + ); + } + } + + // Validate the node attributes. + validateNodeAttributes(definition, depth); + + // Validate the child node of this decorator node. + validateNode(definition.child, depth + 1); +} + /** * Validate an object that we expect to be a branch node definition. * @param definition An object that we expect to be a branch node definition. @@ -367,14 +481,18 @@ function validateBranchNode(definition: any, depth: number): void { // It is invalid to define guard attributes for a branch node as they should be defined on the referenced root node. ["while", "until"].forEach((attributeName) => { if (typeof definition[attributeName] !== "undefined") { - throw new Error(`guards should not be defined for branch nodes but guard '${attributeName}' was defined for branch node at depth '${depth}'`); + throw new Error( + `guards should not be defined for branch nodes but guard '${attributeName}' was defined for branch node at depth '${depth}'` + ); } }); // It is invalid to define callback attributes for a branch node as they should be defined on the referenced root node. ["entry", "exit", "step"].forEach((attributeName) => { if (typeof definition[attributeName] !== "undefined") { - throw new Error(`callbacks should not be defined for branch nodes but callback '${attributeName}' was defined for branch node at depth '${depth}'`); + throw new Error( + `callbacks should not be defined for branch nodes but callback '${attributeName}' was defined for branch node at depth '${depth}'` + ); } }); } @@ -448,10 +566,14 @@ function validateWaitNode(definition: any, depth: number): void { // If the 'duration' property is an array then it MUST contain two integer values. if (definition.duration.length !== 2 || containsNonInteger) { - throw new Error(`expected array containing two integer values for 'duration' property if defined for wait node at depth '${depth}'`); + throw new Error( + `expected array containing two integer values for 'duration' property if defined for wait node at depth '${depth}'` + ); } } else if (!isInteger(definition.duration)) { - throw new Error(`expected integer value or array containing two integer values for 'duration' property if defined for wait node at depth '${depth}'`); + throw new Error( + `expected integer value or array containing two integer values for 'duration' property if defined for wait node at depth '${depth}'` + ); } } @@ -526,4 +648,4 @@ function validateParallelNode(definition: any, depth: number): void { // Validate the child nodes of this composite node. definition.children.forEach((child: any) => validateNode(child, depth + 1)); -} \ No newline at end of file +} diff --git a/src/index.ts b/src/index.ts index a02e59b..82fc8ea 100644 --- a/src/index.ts +++ b/src/index.ts @@ -1,6 +1,7 @@ -import { BehaviourTree, FlattenedTreeNode } from "./BehaviourTree"; import State from "./State"; -import { parseMDSLToJSON } from "./mdsl/MDSLDefinitionParser"; +import { validateDefinition } from "./BehaviourTreeDefinitionValidator"; +import { convertMDSLToJSON } from "./mdsl/MDSLDefinitionParser"; +import { BehaviourTree, FlattenedTreeNode } from "./BehaviourTree"; -export { BehaviourTree, State, parseMDSLToJSON }; +export { BehaviourTree, State, convertMDSLToJSON, validateDefinition }; export type { FlattenedTreeNode }; diff --git a/src/mdsl/MDSLDefinitionParser.ts b/src/mdsl/MDSLDefinitionParser.ts index aa04e59..163330f 100644 --- a/src/mdsl/MDSLDefinitionParser.ts +++ b/src/mdsl/MDSLDefinitionParser.ts @@ -27,11 +27,11 @@ import { } from "./MDSLUtilities"; /** - * Parse the MDSL tree definition string into an equivalent JSON definition. + * Convert the MDSL tree definition string into an equivalent JSON definition. * @param definition The tree definition string as MDSL. * @returns The root node JSON definitions. */ -export function parseMDSLToJSON(definition: string): RootNodeDefinition[] { +export function convertMDSLToJSON(definition: string): RootNodeDefinition[] { // Swap out any node/attribute argument string literals with a placeholder and get a mapping of placeholders to original values as well as the processed definition. const { placeholders, processedDefinition } = substituteStringLiterals(definition); diff --git a/test/BehaviourTreeDefinitionValidator.test.js b/test/BehaviourTreeDefinitionValidator.test.js new file mode 100644 index 0000000..c382f5c --- /dev/null +++ b/test/BehaviourTreeDefinitionValidator.test.js @@ -0,0 +1,10 @@ +const mistreevous = require("../dist/index"); +const chai = require("chai"); + +var assert = chai.assert; + +describe("The validateDefinition function", () => { + it("does stuff", () => { + assert.strictEqual(JSON.stringify(mistreevous.validateDefinition("root {}")), "Hello!"); + }); +}); diff --git a/test/mdsl/MDSLDefinitionParser.test.js b/test/mdsl/MDSLDefinitionParser.test.js index 98ac4ee..1805d66 100644 --- a/test/mdsl/MDSLDefinitionParser.test.js +++ b/test/mdsl/MDSLDefinitionParser.test.js @@ -3,8 +3,8 @@ const chai = require("chai"); var assert = chai.assert; -describe("The parseMDSLToJSON function", () => { +describe("The convertMDSLToJSON function", () => { it("does stuff", () => { - assert.strictEqual(mistreevous.parseMDSLToJSON("root {}"), JSON.stringify([{ type: "root" }])); + assert.strictEqual(mistreevous.convertMDSLToJSON("root {}"), JSON.stringify([{ type: "root" }])); }); }); From 8b17f7d4e4351cf5606f6cc47a6f1b5b61e52030 Mon Sep 17 00:00:00 2001 From: Nikolas Howard Date: Wed, 29 Nov 2023 13:26:02 +0000 Subject: [PATCH 17/48] Fixed issue with root-branch circular dependency validation --- dist/bundle.js | 17 +-- dist/bundle.js.map | 4 +- dist/index.js | 17 +-- dist/index.js.map | 4 +- src/BehaviourTreeDefinitionValidator.ts | 27 +--- test/BehaviourTreeDefinitionValidator.test.js | 128 +++++++++++++++++- test/mdsl/MDSLDefinitionParser.test.js | 2 +- 7 files changed, 141 insertions(+), 58 deletions(-) diff --git a/dist/bundle.js b/dist/bundle.js index ab89b14..4376af4 100644 --- a/dist/bundle.js +++ b/dist/bundle.js @@ -734,19 +734,7 @@ var mistreevous = (() => { return createFailureResult(`invalid mdsl: ${definition}`); } } else if (typeof definition === "object") { - if (Array.isArray(definition)) { - const invalidDefinitionElements = definition.filter((element) => { - return typeof element !== "object" || Array.isArray(element) || element === null; - }); - if (invalidDefinitionElements.length) { - return createFailureResult( - "invalid elements in definition array, each must be an root node definition object" - ); - } - rootNodeDefinitions = definition; - } else { - rootNodeDefinitions = [definition]; - } + rootNodeDefinitions = Array.isArray(definition) ? definition : [definition]; } else { return createFailureResult(`unexpected definition type of '${typeof definition}'`); } @@ -787,7 +775,7 @@ var mistreevous = (() => { const followRefs = (mapping, path = []) => { if (path.includes(mapping.id)) { const badPath = [...path, mapping.id]; - badPathFormatted = badPath.map((element) => !!element).join(" => "); + badPathFormatted = badPath.filter((element) => !!element).join(" => "); return; } for (const ref of mapping.refs) { @@ -797,6 +785,7 @@ var mistreevous = (() => { } } }; + followRefs(rootNodeMappings.find((mapping) => typeof mapping.id === "undefined")); return badPathFormatted; } function validateNode(definition, depth) { diff --git a/dist/bundle.js.map b/dist/bundle.js.map index e1708a1..833bdeb 100644 --- a/dist/bundle.js.map +++ b/dist/bundle.js.map @@ -1,7 +1,7 @@ { "version": 3, "sources": ["../node_modules/lotto-draw/dist/Participant.js", "../node_modules/lotto-draw/dist/Utilities.js", "../node_modules/lotto-draw/dist/Lotto.js", "../node_modules/lotto-draw/dist/createLotto.js", "../node_modules/lotto-draw/dist/index.js", "../src/index.ts", "../src/State.ts", "../src/BehaviourTreeDefinitionUtilities.ts", "../src/mdsl/MDSLUtilities.ts", "../src/mdsl/MDSLNodeArgumentParser.ts", "../src/mdsl/MDSLNodeAttributeParser.ts", "../src/mdsl/MDSLDefinitionParser.ts", "../src/BehaviourTreeDefinitionValidator.ts", "../src/attributes/guards/GuardUnsatisifedException.ts", "../src/attributes/guards/GuardPath.ts", "../src/nodes/Node.ts", "../src/nodes/leaf/Leaf.ts", "../src/Lookup.ts", "../src/nodes/leaf/Action.ts", "../src/nodes/leaf/Condition.ts", "../src/nodes/leaf/Wait.ts", "../src/nodes/decorator/Decorator.ts", "../src/nodes/decorator/Root.ts", "../src/nodes/decorator/Repeat.ts", "../src/nodes/decorator/Retry.ts", "../src/nodes/decorator/Flip.ts", "../src/nodes/decorator/Succeed.ts", "../src/nodes/decorator/Fail.ts", "../src/nodes/composite/Lotto.ts", "../src/nodes/composite/Composite.ts", "../src/nodes/composite/Selector.ts", "../src/nodes/composite/Sequence.ts", "../src/nodes/composite/Parallel.ts", "../src/attributes/Attribute.ts", "../src/attributes/guards/Guard.ts", "../src/attributes/guards/While.ts", "../src/attributes/guards/Until.ts", "../src/attributes/callbacks/Callback.ts", "../src/attributes/callbacks/Entry.ts", "../src/attributes/callbacks/Exit.ts", "../src/attributes/callbacks/Step.ts", "../src/RootAstNodesBuilder.ts", "../src/BehaviourTree.ts"], - "sourcesContent": ["\"use strict\";\r\nObject.defineProperty(exports, \"__esModule\", { value: true });\r\nexports.Participant = void 0;\r\n/**\r\n * A participant that holds a number of tickets.\r\n */\r\nvar Participant = /** @class */ (function () {\r\n /**\r\n * Creates an instance of the Participant class.\r\n * @param participant The actual participant.\r\n * @param tickets The number of tickets held by the participant.\r\n */\r\n function Participant(participant, tickets) {\r\n if (tickets === void 0) { tickets = 1; }\r\n this._participant = participant;\r\n this._tickets = tickets;\r\n }\r\n Object.defineProperty(Participant.prototype, \"participant\", {\r\n /** Gets the actual participant. */\r\n get: function () {\r\n return this._participant;\r\n },\r\n enumerable: false,\r\n configurable: true\r\n });\r\n Object.defineProperty(Participant.prototype, \"tickets\", {\r\n /** Gets or sets the number of tickets held by the participant. */\r\n get: function () {\r\n return this._tickets;\r\n },\r\n set: function (value) {\r\n this._tickets = value;\r\n },\r\n enumerable: false,\r\n configurable: true\r\n });\r\n return Participant;\r\n}());\r\nexports.Participant = Participant;\r\n", "\"use strict\";\r\nObject.defineProperty(exports, \"__esModule\", { value: true });\r\nexports.isNaturalNumber = exports.isNullOrUndefined = void 0;\r\n/**\r\n * Gets whether the value provided is null or undefined.\r\n * @param value The value to check.\r\n * @returns Whether the value provided is null or undefined.\r\n */\r\nfunction isNullOrUndefined(value) {\r\n return value === null || value === undefined;\r\n}\r\nexports.isNullOrUndefined = isNullOrUndefined;\r\n/**\r\n * Gets whether the value provided is a natural number.\r\n * @param value The value to check.\r\n * @returns Whether the value provided is a natural number.\r\n */\r\nfunction isNaturalNumber(value) {\r\n return typeof value === \"number\" && value >= 1 && Math.floor(value) === value;\r\n}\r\nexports.isNaturalNumber = isNaturalNumber;\r\n", "\"use strict\";\r\nObject.defineProperty(exports, \"__esModule\", { value: true });\r\nexports.Lotto = void 0;\r\nvar Participant_1 = require(\"./Participant\");\r\nvar Utilities_1 = require(\"./Utilities\");\r\n/**\r\n * Represents a lotto consisting of a number of pickable ticket-holding participants.\r\n */\r\nvar Lotto = /** @class */ (function () {\r\n /**\r\n * Creates a new instance of Lotto.\r\n * @param customRandom The custom RNG to use in place of Math.random().\r\n */\r\n function Lotto(customRandom) {\r\n /** The array of participants that are holding tickets in the lotto. */\r\n this._participants = [];\r\n this._customRandom = customRandom;\r\n }\r\n /**\r\n * Adds a participant with the specified number of tickets, or adds to the participant ticket count if the participant already holds tickets.\r\n * @param participant The participant to add or to increase the ticket count for if they already hold tickets.\r\n * @param tickets The number of tickets, defaults to 1.\r\n * @returns The Lotto instance.\r\n */\r\n Lotto.prototype.add = function (participant, tickets) {\r\n if (tickets === void 0) { tickets = 1; }\r\n // Check that we have a valid ticket count.\r\n if (!(0, Utilities_1.isNaturalNumber)(tickets)) {\r\n throw new Error(\"tickets value must be a natural number\");\r\n }\r\n // Check whether this participant has already been added.\r\n var existingParticipant = this._participants.find(function (part) { return part.participant === participant; });\r\n if (existingParticipant) {\r\n // The participant has already been added to the lotto so just add to their ticket count.\r\n existingParticipant.tickets += tickets;\r\n }\r\n else {\r\n // The participant is not part of the lotto so we should add them.\r\n this._participants.push(new Participant_1.Participant(participant, tickets));\r\n }\r\n return this;\r\n };\r\n /**\r\n * Removes the specified number of tickets for the given participant from the draw, or all tickets if a ticket number is not defined.\r\n * @param participant The participant to remove tickets for.\r\n * @param tickets The number of tickets to remove, or undefined if all tickets are to be removed.\r\n * @returns The Lotto instance.\r\n */\r\n Lotto.prototype.remove = function (participant, tickets) {\r\n // Attempt to get the existing participant.\r\n var existingParticipant = this._participants.find(function (part) { return part.participant === participant; });\r\n // There is nothing to do if the specified participant isn't even part of the lotto.\r\n if (!existingParticipant) {\r\n return this;\r\n }\r\n // Check whether a tickets value was given.\r\n if (tickets !== undefined) {\r\n // Check that we have a valid ticket count.\r\n if (!(0, Utilities_1.isNaturalNumber)(tickets)) {\r\n throw new Error(\"tickets value must be a natural number\");\r\n }\r\n existingParticipant.tickets -= tickets;\r\n // If the participant no longer holds any tickets then they should be removed.\r\n if (existingParticipant.tickets < 1) {\r\n this._participants = this._participants.filter(function (part) { return part !== existingParticipant; });\r\n }\r\n }\r\n else {\r\n // We are removing all tickets for the participant so just remove them from the lotto.\r\n this._participants = this._participants.filter(function (part) { return part !== existingParticipant; });\r\n }\r\n return this;\r\n };\r\n /**\r\n * Draw a winning ticket and return the participant that holds the ticket.\r\n * @param options The draw options.\r\n * @returns The participant that holds the winning ticket.\r\n */\r\n Lotto.prototype.draw = function (options) {\r\n if (options === void 0) { options = {}; }\r\n // If we have no participants then just return null.\r\n if (this._participants.length === 0) {\r\n return null;\r\n }\r\n var redrawable = (0, Utilities_1.isNullOrUndefined)(options.redrawable) ? true : options.redrawable;\r\n var pickable = [];\r\n this._participants.forEach(function (_a) {\r\n var participant = _a.participant, tickets = _a.tickets;\r\n for (var ticketCount = 0; ticketCount < tickets; ticketCount++) {\r\n pickable.push(participant);\r\n }\r\n });\r\n var random;\r\n // We need a random floating-point number between 0 (inclusive) and 1 to scale up to pick our winner.\r\n // If a custom random function exists then we should use that or fall back to Math.random().\r\n if (this._customRandom) {\r\n // Call our custom random function to get a random floating-point number.\r\n random = this._customRandom();\r\n // Verify that the result of calling our custom random function is a number between 0 (inclusive) and 1.\r\n if (typeof random !== \"number\" || random < 0 || random >= 1) {\r\n throw new Error(\"the 'random' function provided did not return a number between 0 (inclusive) and 1\");\r\n }\r\n }\r\n else {\r\n // No custom random function was defined so just use good ol' Math.random().\r\n random = Math.random();\r\n }\r\n // Pick a winning participant.\r\n var winner = pickable[Math.floor(random * pickable.length)];\r\n // If the ticket isn't redrawable then we should remove a ticket from the winning participants ticket count.\r\n if (!redrawable) {\r\n this.remove(winner, 1);\r\n }\r\n // Return the winning participant.\r\n return winner;\r\n };\r\n /**\r\n * Draws multiple winning tickets and return an array of the participants that hold the winning tickets.\r\n * @param tickets The number of winning tickets to draw.\r\n * @param options The draw multiple options.\r\n * @returns An array of the participants that hold the winning tickets.\r\n */\r\n Lotto.prototype.drawMultiple = function (tickets, options) {\r\n if (options === void 0) { options = {}; }\r\n var uniqueResults = (0, Utilities_1.isNullOrUndefined)(options.unique) ? false : options.unique;\r\n // Handle cases where the user has asked for zero tickets (no idea why they would do this be we should trust them).\r\n if (tickets === 0) {\r\n return [];\r\n }\r\n // Now that we know out tickets value is not zero we should check that it is a valid natural number.\r\n if (!(0, Utilities_1.isNaturalNumber)(tickets)) {\r\n throw new Error(\"tickets value must be a natural number\");\r\n }\r\n var result = [];\r\n // Keep drawing tickets until we either reach the number of required tickets or we simply run out of tickets to draw.\r\n // We can run out of tickets to draw if 'options.redrawable' is explicity 'false' or we just had no participants when 'drawMultiple' was called.\r\n while (result.length < tickets && this._participants.length > 0) {\r\n result.push(this.draw(options));\r\n }\r\n // If the 'unique' draw option is set then we need to remove duplicates from the result list.\r\n if (uniqueResults) {\r\n // Create an array to store our unique results.\r\n var unique = [];\r\n // Iterate over all of our participants (with potential duplicates) and populate our array of unique values.\r\n for (var _i = 0, result_1 = result; _i < result_1.length; _i++) {\r\n var participant = result_1[_i];\r\n if (unique.indexOf(participant) === -1) {\r\n unique.push(participant);\r\n }\r\n }\r\n result = unique;\r\n }\r\n return result;\r\n };\r\n return Lotto;\r\n}());\r\nexports.Lotto = Lotto;\r\n", "\"use strict\";\r\nObject.defineProperty(exports, \"__esModule\", { value: true });\r\nexports.createLotto = void 0;\r\nvar Lotto_1 = require(\"./Lotto\");\r\n/**\r\n * A function that creates and returns a Lotto instance.\r\n * @param participantsOrOptions An array of initial participants or options relating to the creation of a Lotto instance.\r\n * @returns A new Lotto instance.\r\n */\r\nfunction createLotto(participantsOrOptions) {\r\n // If no initial participants or lotto options were provided as an argument then we can just return a new lotto instance now.\r\n if (!participantsOrOptions) {\r\n return new Lotto_1.Lotto();\r\n }\r\n // Check whether we were provided with an array of initial participants or a lotto options object.\r\n if (Array.isArray(participantsOrOptions)) {\r\n // We are dealing with a pre-defined array of participants.\r\n var participants = participantsOrOptions;\r\n var lotto_1 = new Lotto_1.Lotto();\r\n // If the lotto participants have been defined upfront then we will need to add them all to our lotto instance now.\r\n participants.forEach(function (_a) {\r\n var participant = _a[0], tokens = _a[1];\r\n return lotto_1.add(participant, tokens);\r\n });\r\n // Return the Lotto instance.\r\n return lotto_1;\r\n }\r\n else {\r\n // We are dealing with some lotto options.\r\n var random = participantsOrOptions.random, participants = participantsOrOptions.participants;\r\n // Create a Lotto instance passing the custom RNG function to use in place of Math.random() (which could be undefined).\r\n var lotto_2 = new Lotto_1.Lotto(random);\r\n // If the lotto participants have been defined upfront as part of the options then we will need to add them all to our lotto instance now.\r\n if (participants) {\r\n participants.forEach(function (_a) {\r\n var participant = _a[0], tokens = _a[1];\r\n return lotto_2.add(participant, tokens);\r\n });\r\n }\r\n // Return the Lotto instance.\r\n return lotto_2;\r\n }\r\n}\r\nexports.createLotto = createLotto;\r\n", "\"use strict\";\r\nObject.defineProperty(exports, \"__esModule\", { value: true });\r\nvar createLotto_1 = require(\"./createLotto\");\r\nexports.default = createLotto_1.createLotto;\r\n", "import State from \"./State\";\nimport { validateDefinition } from \"./BehaviourTreeDefinitionValidator\";\nimport { convertMDSLToJSON } from \"./mdsl/MDSLDefinitionParser\";\nimport { BehaviourTree, FlattenedTreeNode } from \"./BehaviourTree\";\n\nexport { BehaviourTree, State, convertMDSLToJSON, validateDefinition };\nexport type { FlattenedTreeNode };\n", "/**\n * Enumeration of node state types.\n */\nexport enum State {\n READY = \"mistreevous.ready\",\n RUNNING = \"mistreevous.running\",\n SUCCEEDED = \"mistreevous.succeeded\",\n FAILED = \"mistreevous.failed\"\n}\n\nexport { State as default };\n\nexport type CompleteState = State.SUCCEEDED | State.FAILED;\nexport type AnyState = State.READY | State.RUNNING | CompleteState;\n", "import {\n NodeDefinition,\n RootNodeDefinition,\n DecoratorNodeDefinition,\n CompositeNodeDefinition,\n AnyNode,\n BranchNodeDefinition\n} from \"./BehaviourTreeDefinition\";\n\n/**\n * A type guard function that returns true if the specified node satisfies the RootNodeDefinition type.\n * @param node The node.\n * @returns A value of true if the specified node satisfies the RootNodeDefinition type.\n */\nexport function isRootNode(node: NodeDefinition): node is RootNodeDefinition {\n return node.type === \"root\";\n}\n\n/**\n * A type guard function that returns true if the specified node satisfies the BranchNodeDefinition type.\n * @param node The node.\n * @returns A value of true if the specified node satisfies the BranchNodeDefinition type.\n */\nexport function isBranchNode(node: NodeDefinition): node is BranchNodeDefinition {\n return node.type === \"branch\";\n}\n\n/**\n * A type guard function that returns true if the specified node satisfies the NodeDefinition type.\n * @param node The node.\n * @returns A value of true if the specified node satisfies the NodeDefinition type.\n */\nexport function isLeafNode(node: NodeDefinition): node is NodeDefinition {\n return [\"branch\", \"action\", \"condition\", \"wait\"].includes(node.type);\n}\n\n/**\n * A type guard function that returns true if the specified node satisfies the DecoratorNodeDefinition type.\n * @param node The node.\n * @returns A value of true if the specified node satisfies the DecoratorNodeDefinition type.\n */\nexport function isDecoratorNode(node: NodeDefinition): node is DecoratorNodeDefinition {\n return [\"root\", \"repeat\", \"retry\", \"flip\", \"succeed\", \"fail\"].includes(node.type);\n}\n\n/**\n * A type guard function that returns true if the specified node satisfies the CompositeNodeDefinition type.\n * @param node The node.\n * @returns A value of true if the specified node satisfies the CompositeNodeDefinition type.\n */\nexport function isCompositeNode(node: NodeDefinition): node is CompositeNodeDefinition {\n return [\"sequence\", \"selector\", \"lotto\", \"parallel\"].includes(node.type);\n}\n\n/**\n * Flatten a node definition into an array of all of its nested node definitions.\n * @param nodeDefinition The node definition to flatten.\n * @returns An array of all of nested node definitions.\n */\nexport function flattenDefinition(nodeDefinition: AnyNode): AnyNode[] {\n const nodes: AnyNode[] = [];\n\n const processNode = (currentNodeDefinition: AnyNode) => {\n nodes.push(currentNodeDefinition);\n\n if (isCompositeNode(currentNodeDefinition)) {\n currentNodeDefinition.children.forEach(processNode);\n } else if (isDecoratorNode(currentNodeDefinition)) {\n processNode(currentNodeDefinition.child);\n }\n };\n\n processNode(nodeDefinition);\n\n return nodes;\n}\n\n/**\n * Determines whether the passed value is an integer.\n * @param value The value to check.\n * @returns Whether the passed value is an integer.\n */\nexport function isInteger(value: unknown): boolean {\n return typeof value === \"number\" && Math.floor(value) === value;\n}\n", "/**\n * A type defining an object that holds a reference to substitued string literals parsed from the definition.\n */\nexport type StringLiteralPlaceholders = { [key: string]: string };\n\n/**\n * Pop the next raw token from the specified array of tokens and throw an error if it wasn't the expected one.\n * @param tokens The array of tokens.\n * @param expected An optional string or array or items, one of which must match the next popped token.\n * @returns The popped token.\n */\nexport function popAndCheck(tokens: string[], expected?: string | string[]): string {\n // Get and remove the next token.\n const popped = tokens.shift();\n\n // We were expecting another token but there aren't any.\n if (popped === undefined) {\n throw new Error(\"unexpected end of definition\");\n }\n\n // Do we have an expected token/tokens array?\n if (expected != undefined) {\n // Get an array of expected values, if the popped token matches any then we are all good.\n const expectedValues = typeof expected === \"string\" ? [expected] : expected;\n\n // Check whether the popped token matches at least one of our expected items.\n var tokenMatchesExpectation = expectedValues.some((item) => popped.toUpperCase() === item.toUpperCase());\n\n // Throw an error if the popped token didn't match any of our expected items.\n if (!tokenMatchesExpectation) {\n const expectationString = expectedValues.map((item) => \"'\" + item + \"'\").join(\" or \");\n throw new Error(\"unexpected token found. Expected \" + expectationString + \" but got '\" + popped + \"'\");\n }\n }\n\n // Return the popped token.\n return popped;\n}\n\n/**\n * Swaps out any node/attribute argument string literals with placeholders.\n * @param definition The definition.\n * @returns An object containing a mapping of placeholders to original string values as well as the processed definition string.\n */\nexport function substituteStringLiterals(definition: string): {\n placeholders: StringLiteralPlaceholders;\n processedDefinition: string;\n} {\n // Create an object to hold the mapping of placeholders to original string values.\n const placeholders: StringLiteralPlaceholders = {};\n\n // Replace any string literals wrapped with double quotes in our definition with placeholders to be processed later.\n const processedDefinition = definition.replace(/\\\"(\\\\.|[^\"\\\\])*\\\"/g, (match) => {\n var strippedMatch = match.substring(1, match.length - 1);\n var placeholder = Object.keys(placeholders).find((key) => placeholders[key] === strippedMatch);\n\n // If we have no existing string literal match then create a new placeholder.\n if (!placeholder) {\n placeholder = `@@${Object.keys(placeholders).length}@@`;\n placeholders[placeholder] = strippedMatch;\n }\n\n return placeholder;\n });\n\n return { placeholders, processedDefinition };\n}\n\n/**\n * Parse the tree definition into an array of raw tokens.\n * @param definition The definition.\n * @returns An array of tokens parsed from the definition.\n */\nexport function parseTokensFromDefinition(definition: string): string[] {\n // Add some space around various important characters so that they can be plucked out easier as individual tokens.\n definition = definition.replace(/\\(/g, \" ( \");\n definition = definition.replace(/\\)/g, \" ) \");\n definition = definition.replace(/\\{/g, \" { \");\n definition = definition.replace(/\\}/g, \" } \");\n definition = definition.replace(/\\]/g, \" ] \");\n definition = definition.replace(/\\[/g, \" [ \");\n definition = definition.replace(/\\,/g, \" , \");\n\n // Split the definition into raw token form and return it.\n return definition.replace(/\\s+/g, \" \").trim().split(\" \");\n}\n", "import { StringLiteralPlaceholders, popAndCheck } from \"./MDSLUtilities\";\n\nexport type Argument = {\n /** The argument value. */\n value: T;\n /** The argument type, used for validation. */\n type: string;\n};\n\nexport type NullArgument = Argument & {\n type: \"null\";\n};\n\nexport type BooleanArgument = Argument & {\n type: \"boolean\";\n};\n\nexport type NumberArgument = Argument & {\n type: \"number\";\n isInteger: boolean; // Used for validation.\n};\n\nexport type StringPlaceholderArgument = Argument & {\n type: \"string\";\n};\n\nexport type IdentifierArgument = Argument & {\n type: \"identifier\";\n};\n\nexport type AnyArgument =\n | NullArgument\n | BooleanArgument\n | NumberArgument\n | StringPlaceholderArgument\n | IdentifierArgument;\n\n/**\n * Parse an array of argument definitions from the specified tokens array.\n * @param tokens The array tokens to parse the argument definitions from.\n * @param stringArgumentPlaceholders The mapping of string literal node argument placeholders to original values.\n * @param argumentValidator The argument validator function.\n * @param validationFailedMessage The exception message to throw if argument validation fails.\n * @returns An array of argument definitions parsed from the specified tokens array.\n */\nexport function parseArgumentTokens(\n tokens: string[],\n stringArgumentPlaceholders: StringLiteralPlaceholders\n): AnyArgument[] {\n const argumentList: AnyArgument[] = [];\n\n // If the next token is not a '[' or '(' then we have no arguments to parse.\n if (![\"[\", \"(\"].includes(tokens[0])) {\n return argumentList;\n }\n\n // Any lists of arguments will always be wrapped in '[]' for node arguments or '()' for attribute arguments.\n // We are looking for a '[' or '(' opener that wraps the argument tokens and the relevant closer.\n const closingToken = popAndCheck(tokens, [\"[\", \"(\"]) === \"[\" ? \"]\" : \")\";\n\n const argumentListTokens: string[] = [];\n\n // Grab all tokens between the '[' and ']' or '(' and ')'.\n while (tokens.length && tokens[0] !== closingToken) {\n // The next token is part of our arguments list.\n argumentListTokens.push(tokens.shift()!);\n }\n\n // Validate the order of the argument tokens. Each token must either be a ',' or a single argument that satisfies the validator.\n argumentListTokens.forEach((token, index) => {\n // Get whether this token should be an actual argument.\n const shouldBeArgumentToken = !(index & 1);\n\n // If the current token should be an actual argument then validate it, otherwise it should be a ',' token.\n if (shouldBeArgumentToken) {\n // Get the argument definition.\n const argumentDefinition = getArgumentDefinition(token, stringArgumentPlaceholders);\n\n // This is a valid argument!\n argumentList.push(argumentDefinition);\n } else {\n // The current token should be a ',' token.\n if (token !== \",\") {\n throw new Error(`invalid argument list, expected ',' or ']' but got '${token}'`);\n }\n }\n });\n\n // The arguments list should terminate with a ']' or ')' token, depending on the opener.\n popAndCheck(tokens, closingToken);\n\n // Return the arguments.\n return argumentList;\n}\n\n/**\n * Gets an argument value definition.\n * @param token The argument token.\n * @param stringArgumentPlaceholders The mapping of string literal node argument placeholders to original values.\n * @returns An argument value definition.\n */\nfunction getArgumentDefinition(token: string, stringArgumentPlaceholders: StringLiteralPlaceholders): AnyArgument {\n // Check whether the token represents a null value.\n if (token === \"null\") {\n return {\n value: null,\n type: \"null\"\n } as NullArgument;\n }\n\n // Check whether the token represents a boolean value.\n if (token === \"true\" || token === \"false\") {\n return {\n value: token === \"true\",\n type: \"boolean\"\n } as BooleanArgument;\n }\n\n // Check whether the token represents a number value.\n // TODO: Relies on broken isNaN - see MDN.\n // if (!Number.isNaN(token)) {\n if (!isNaN(token as any)) {\n return {\n value: parseFloat(token),\n isInteger: parseFloat(token) === parseInt(token, 10),\n type: \"number\"\n } as NumberArgument;\n }\n\n // Check whether the token is a placeholder (e.g. @@0@@) representing a string literal.\n if (token.match(/^@@\\d+@@$/g)) {\n return {\n value: stringArgumentPlaceholders[token].replace('\\\\\"', '\"'),\n type: \"string\"\n } as StringPlaceholderArgument;\n }\n\n // The only remaining option is that the argument value is an identifier.\n return {\n value: token,\n type: \"identifier\"\n } as IdentifierArgument;\n}\n", "import { NodeAttributeDefinition } from \"../BehaviourTreeDefinition\";\nimport { parseArgumentTokens } from \"./MDSLNodeArgumentParser\";\nimport { StringLiteralPlaceholders } from \"./MDSLUtilities\";\n\n/**\n * A type defining the attribute definitions of a node.\n */\ntype NodeAttributes = {\n while?: NodeAttributeDefinition;\n until?: NodeAttributeDefinition;\n entry?: NodeAttributeDefinition;\n exit?: NodeAttributeDefinition;\n step?: NodeAttributeDefinition;\n};\n\n/**\n * Parse any node attribute definitions from the specified tokens array.\n * @param tokens The array of remaining tokens.\n * @param stringArgumentPlaceholders The mapping of string literal node argument placeholders to original values.\n * @returns An object of attribute definitions defined by any directly following tokens.\n */\nexport function parseAttributeTokens(\n tokens: string[],\n stringArgumentPlaceholders: StringLiteralPlaceholders\n): NodeAttributes {\n const nodeAttributeNames: (keyof NodeAttributes)[] = [\"while\", \"until\", \"entry\", \"exit\", \"step\"];\n\n // Create an object to hold any attributes found.\n const attributes: NodeAttributes = {};\n\n // Try to get the name of the attribute for the next token.\n let nextAttributeName = tokens[0]?.toLowerCase() as keyof NodeAttributes;\n\n // Pull attribute tokens as well as their arguments off of the tokens stack until we have no more.\n while (nodeAttributeNames.includes(nextAttributeName)) {\n // Check to make sure that we have not already created an attribute definition of this type.\n if (attributes[nextAttributeName]) {\n throw new Error(`duplicate attribute '${tokens[0].toUpperCase()}' found for node`);\n }\n\n // Remove the attribute name token from the array of tokens.\n tokens.shift();\n\n // Grab the attribute arguments, assuming the first to be an identifier.\n const [attributeCallIdentifier, ...attributeArguments] = parseArgumentTokens(\n tokens,\n stringArgumentPlaceholders\n );\n\n // The first attribute argument has to be an identifer, this will reference an agent function.\n if (attributeCallIdentifier?.type !== \"identifier\") {\n throw new Error(\"expected agent function name identifier argument for attribute\");\n }\n\n // Any attribute arguments (other than the expected call identifier) must have a type of string, number, boolean or null.\n attributeArguments\n .filter((arg) => arg.type === \"identifier\")\n .forEach((arg) => {\n throw new Error(\n `invalid attribute argument value '${arg.value}', must be string, number, boolean or null`\n );\n });\n\n // Create the attribute definition and add it to the object of attribute definitions found.\n attributes[nextAttributeName] = {\n call: attributeCallIdentifier.value,\n args: attributeArguments.map(({ value }) => value)\n };\n\n // Try to get the next attribute name token, as there could be multiple.\n nextAttributeName = tokens[0]?.toLowerCase() as keyof NodeAttributes;\n }\n\n return attributes;\n}\n", "import {\n ActionNodeDefinition,\n AnyChildNode,\n AnyNode,\n BranchNodeDefinition,\n ConditionNodeDefinition,\n FailNodeDefinition,\n FlipNodeDefinition,\n LottoNodeDefinition,\n ParallelNodeDefinition,\n RepeatNodeDefinition,\n RetryNodeDefinition,\n RootNodeDefinition,\n SelectorNodeDefinition,\n SequenceNodeDefinition,\n SucceedNodeDefinition,\n WaitNodeDefinition\n} from \"../BehaviourTreeDefinition\";\nimport { isCompositeNode, isDecoratorNode, isLeafNode, isRootNode } from \"../BehaviourTreeDefinitionUtilities\";\nimport { parseArgumentTokens } from \"./MDSLNodeArgumentParser\";\nimport { parseAttributeTokens } from \"./MDSLNodeAttributeParser\";\nimport {\n StringLiteralPlaceholders,\n parseTokensFromDefinition,\n popAndCheck,\n substituteStringLiterals\n} from \"./MDSLUtilities\";\n\n/**\n * Convert the MDSL tree definition string into an equivalent JSON definition.\n * @param definition The tree definition string as MDSL.\n * @returns The root node JSON definitions.\n */\nexport function convertMDSLToJSON(definition: string): RootNodeDefinition[] {\n // Swap out any node/attribute argument string literals with a placeholder and get a mapping of placeholders to original values as well as the processed definition.\n const { placeholders, processedDefinition } = substituteStringLiterals(definition);\n\n // Parse our definition definition string into an array of raw tokens.\n const tokens = parseTokensFromDefinition(processedDefinition);\n\n return convertTokensToJSONDefinition(tokens, placeholders);\n}\n\n/**\n * Converts the specified tree definition tokens into a JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The root node JSON definitions.\n */\nfunction convertTokensToJSONDefinition(\n tokens: string[],\n stringLiteralPlaceholders: StringLiteralPlaceholders\n): RootNodeDefinition[] {\n // There must be at least 3 tokens for the tree definition to be valid. 'ROOT', '{' and '}'.\n if (tokens.length < 3) {\n throw new Error(\"invalid token count\");\n }\n\n // We should have a matching number of '{' and '}' tokens. If not, then there are scopes that have not been properly closed.\n if (tokens.filter((token) => token === \"{\").length !== tokens.filter((token) => token === \"}\").length) {\n throw new Error(\"scope character mismatch\");\n }\n\n // Create an array of tree stack arrays where root nodes will always be at the botton and the current composite/decorator node at the top.\n // There should be an element in this array for every root node defined and every element should be an array with a root note as the first element.\n // E.g. A definition with two root nodes defined:\n // [\n // [root, lotto, sequence],\n // [root, selector]\n // ]\n const treeStacks: [Partial, ...Partial[]][] = [];\n\n // Create an array of all root node definitions that we create.\n const rootNodes: Partial[] = [];\n\n // A helper function used to push node definitions onto the tree stack.\n const pushNode = (node: AnyNode) => {\n // If the node is a root node then we need to create a new tree stack array with the root node at the root.\n if (isRootNode(node)) {\n // Add the root node definition to our array of all parsed root node definitions.\n rootNodes.push(node);\n\n // Add the root node definition to the root of a new tree stack.\n treeStacks.push([node]);\n\n return;\n }\n\n // All non-root nodes should be pushed after their root nodes so handle cases\n // where we may not have any tree stacks or our top-most tree stack is empty.\n if (!treeStacks.length || !treeStacks[treeStacks.length - 1].length) {\n throw new Error(\"expected root node at base of definition\");\n }\n\n // Get the current tree stack that we are populating.\n const topTreeStack = treeStacks[treeStacks.length - 1];\n\n // Get the top-most node in the current tree stack, this will be a composite/decorator node\n // for which we will populate its children array if composite or setting its child if a decorator.\n const topTreeStackTopNode = topTreeStack[topTreeStack.length - 1] as AnyNode;\n\n // If the top-most node in the current root stack is a composite or decorator\n // node then the current node should be added as a child of the top-most node.\n if (isCompositeNode(topTreeStackTopNode)) {\n topTreeStackTopNode.children = topTreeStackTopNode.children || [];\n topTreeStackTopNode.children.push(node);\n } else if (isDecoratorNode(topTreeStackTopNode)) {\n // If the top node already has a child node set then throw an error as a decorator should only have a single child.\n if (topTreeStackTopNode.child) {\n throw new Error(\"a decorator node must only have a single child node\");\n }\n\n topTreeStackTopNode.child = node;\n }\n\n // If the node we are adding is also a composite or decorator node, then we should push it\n // onto the current tree stack, as subsequent nodes will be added as its child/children.\n if (!isLeafNode(node)) {\n topTreeStack.push(node);\n }\n };\n\n // A helper function used to pop node definitions off of the stack.\n const popNode = () => {\n // Get the current tree stack that we are populating.\n const topTreeStack = treeStacks[treeStacks.length - 1];\n\n // Pop the top-most node in the current tree stack if there is one.\n if (topTreeStack.length) {\n topTreeStack.pop();\n }\n\n // We don't want any empty tree stacks in our stack of tree stacks.\n if (!topTreeStack.length) {\n treeStacks.pop();\n }\n };\n\n // We should keep processing the raw tokens until we run out of them.\n while (tokens.length) {\n // Grab the next token.\n const token = tokens.shift()!;\n\n // How we create the next node depends on the current raw token value.\n switch (token.toUpperCase()) {\n case \"ROOT\": {\n pushNode(createRootNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"SUCCEED\": {\n pushNode(createSucceedNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"FAIL\": {\n pushNode(createFailNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"FLIP\": {\n pushNode(createFlipNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"REPEAT\": {\n pushNode(createRepeatNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"RETRY\": {\n pushNode(createRetryNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"SEQUENCE\": {\n pushNode(createSequenceNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"SELECTOR\": {\n pushNode(createSelectorNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"PARALLEL\": {\n pushNode(createParallelNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"LOTTO\": {\n pushNode(createLottoNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"ACTION\": {\n pushNode(createActionNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"CONDITION\": {\n pushNode(createConditionNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"WAIT\": {\n pushNode(createWaitNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"BRANCH\": {\n pushNode(createBranchNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"}\": {\n // The '}' character closes the current scope and means that we have to pop a node off of the current stack.\n popNode();\n break;\n }\n\n default: {\n throw new Error(`unexpected token: ${token}`);\n }\n }\n }\n\n return rootNodes as RootNodeDefinition[];\n}\n\n/**\n * Creates a root node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The root node JSON definition.\n */\nfunction createRootNode(tokens: string[], stringLiteralPlaceholders: StringLiteralPlaceholders): RootNodeDefinition {\n // Create the root node definition.\n let node = {\n type: \"root\",\n id: undefined\n } as RootNodeDefinition;\n\n // Parse any node arguments, we should only have one if any which will be an identifier argument for the root identifier.\n const nodeArguments = parseArgumentTokens(tokens, stringLiteralPlaceholders);\n\n // Check whether any node arguments were defined.\n if (nodeArguments.length) {\n // We should only have one argument, if any, which will be an identifier argument for the root identifier.\n if (nodeArguments.length === 1 && nodeArguments[0].type === \"identifier\") {\n // The root node identifier will be the first and only node argument value.\n node.id = nodeArguments[0].value as string;\n } else {\n throw new Error(\"expected single root name argument\");\n }\n }\n\n // Grab any node attribute definitions and spread them into the node definition.\n node = { ...node, ...parseAttributeTokens(tokens, stringLiteralPlaceholders) };\n\n // This is a decorator node, so we expect an opening '{'.\n popAndCheck(tokens, \"{\");\n\n // Return the root node definition.\n return node;\n}\n\n/**\n * Creates a succeed node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The succeed node JSON definition.\n */\nfunction createSucceedNode(\n tokens: string[],\n stringLiteralPlaceholders: StringLiteralPlaceholders\n): SucceedNodeDefinition {\n const node = {\n type: \"succeed\",\n ...parseAttributeTokens(tokens, stringLiteralPlaceholders)\n } as SucceedNodeDefinition;\n\n // This is a decorator node, so we expect an opening '{'.\n popAndCheck(tokens, \"{\");\n\n // Return the succeed node definition.\n return node;\n}\n\n/**\n * Creates a fail node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The fail node JSON definition.\n */\nfunction createFailNode(tokens: string[], stringLiteralPlaceholders: StringLiteralPlaceholders): FailNodeDefinition {\n const node = {\n type: \"fail\",\n ...parseAttributeTokens(tokens, stringLiteralPlaceholders)\n } as FailNodeDefinition;\n\n // This is a decorator node, so we expect an opening '{'.\n popAndCheck(tokens, \"{\");\n\n // Return the fail node definition.\n return node;\n}\n\n/**\n * Creates a flip node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The flip node JSON definition.\n */\nfunction createFlipNode(tokens: string[], stringLiteralPlaceholders: StringLiteralPlaceholders): FlipNodeDefinition {\n const node = {\n type: \"flip\",\n ...parseAttributeTokens(tokens, stringLiteralPlaceholders)\n } as FlipNodeDefinition;\n\n // This is a decorator node, so we expect an opening '{'.\n popAndCheck(tokens, \"{\");\n\n // Return the flip node definition.\n return node;\n}\n\n/**\n * Creates a repeat node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The repeat node JSON definition.\n */\nfunction createRepeatNode(\n tokens: string[],\n stringLiteralPlaceholders: StringLiteralPlaceholders\n): RepeatNodeDefinition {\n let node = { type: \"repeat\" } as RepeatNodeDefinition;\n\n // Get the node arguments.\n const nodeArguments = parseArgumentTokens(tokens, stringLiteralPlaceholders);\n\n // The arguments of a repeat node are optional. We may have:\n // - No node arguments, in which case the repeat note will iterate indefinitely.\n // - One node argument which will be the explicit number of iterations to make.\n // - Two node arguments which define the min and max iteration bounds from which a random iteration count will be picked.\n if (nodeArguments.length) {\n // All repeat node arguments MUST be of type number and must be integer.\n nodeArguments\n .filter((arg) => arg.type !== \"number\" || !arg.isInteger)\n .forEach(() => {\n throw new Error(`repeat node iteration counts must be integer values`);\n });\n\n // We should have got one or two iteration counts.\n if (nodeArguments.length === 1) {\n // A static iteration count was defined.\n node.iterations = nodeArguments[0].value as number;\n } else if (nodeArguments.length === 2) {\n // A minimum and maximum iteration count was defined.\n node.iterations = [nodeArguments[0].value as number, nodeArguments[1].value as number];\n } else {\n // An incorrect number of iteration counts was defined.\n throw new Error(\"invalid number of repeat node iteration count arguments defined\");\n }\n }\n\n // Grab any node attribute definitions and spread them into the node definition.\n node = { ...node, ...parseAttributeTokens(tokens, stringLiteralPlaceholders) };\n\n // This is a decorator node, so we expect an opening '{'.\n popAndCheck(tokens, \"{\");\n\n // Return the repeat node definition.\n return node;\n}\n\n/**\n * Creates a retry node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The retry node JSON definition.\n */\nfunction createRetryNode(tokens: string[], stringLiteralPlaceholders: StringLiteralPlaceholders): RetryNodeDefinition {\n let node = { type: \"retry\" } as RetryNodeDefinition;\n\n // Get the node arguments.\n const nodeArguments = parseArgumentTokens(tokens, stringLiteralPlaceholders);\n\n // The arguments of a retry node are optional. We may have:\n // - No node arguments, in which case the retry note will attempt indefinitely.\n // - One node argument which will be the explicit number of attempts to make.\n // - Two node arguments which define the min and max attempt bounds from which a random attempt count will be picked.\n if (nodeArguments.length) {\n // All retry node arguments MUST be of type number and must be integer.\n nodeArguments\n .filter((arg) => arg.type !== \"number\" || !arg.isInteger)\n .forEach(() => {\n throw new Error(`retry node attempt counts must be integer values`);\n });\n\n // We should have got one or two attempt counts.\n if (nodeArguments.length === 1) {\n // A static attempt count was defined.\n node.attempts = nodeArguments[0].value as number;\n } else if (nodeArguments.length === 2) {\n // A minimum and maximum attempt count was defined.\n node.attempts = [nodeArguments[0].value as number, nodeArguments[1].value as number];\n } else {\n // An incorrect number of attempt counts was defined.\n throw new Error(\"invalid number of retry node attempt count arguments defined\");\n }\n }\n\n // Grab any node attribute definitions and spread them into the node definition.\n node = { ...node, ...parseAttributeTokens(tokens, stringLiteralPlaceholders) };\n\n // This is a decorator node, so we expect an opening '{'.\n popAndCheck(tokens, \"{\");\n\n // Return the retry node definition.\n return node;\n}\n\n/**\n * Creates a sequence node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The sequence node JSON definition.\n */\nfunction createSequenceNode(\n tokens: string[],\n stringLiteralPlaceholders: StringLiteralPlaceholders\n): SequenceNodeDefinition {\n const node = {\n type: \"sequence\",\n ...parseAttributeTokens(tokens, stringLiteralPlaceholders)\n } as SequenceNodeDefinition;\n\n // This is a composite node, so we expect an opening '{'.\n popAndCheck(tokens, \"{\");\n\n // Return the sequence node definition.\n return node;\n}\n\n/**\n * Creates a selector node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The selector node JSON definition.\n */\nfunction createSelectorNode(\n tokens: string[],\n stringLiteralPlaceholders: StringLiteralPlaceholders\n): SelectorNodeDefinition {\n const node = {\n type: \"selector\",\n ...parseAttributeTokens(tokens, stringLiteralPlaceholders)\n } as SelectorNodeDefinition;\n\n // This is a composite node, so we expect an opening '{'.\n popAndCheck(tokens, \"{\");\n\n // Return the selector node definition.\n return node;\n}\n\n/**\n * Creates a parallel node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The parallel node JSON definition.\n */\nfunction createParallelNode(\n tokens: string[],\n stringLiteralPlaceholders: StringLiteralPlaceholders\n): ParallelNodeDefinition {\n const node = {\n type: \"parallel\",\n ...parseAttributeTokens(tokens, stringLiteralPlaceholders)\n } as ParallelNodeDefinition;\n\n // This is a composite node, so we expect an opening '{'.\n popAndCheck(tokens, \"{\");\n\n // Return the parallel node definition.\n return node;\n}\n\n/**\n * Creates a lotto node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The lotto node JSON definition.\n */\nfunction createLottoNode(tokens: string[], stringLiteralPlaceholders: StringLiteralPlaceholders): LottoNodeDefinition {\n // If any node arguments have been defined then they must be our weights.\n const nodeArguments = parseArgumentTokens(tokens, stringLiteralPlaceholders);\n\n // All lotto node arguments MUST be of type number and must be integer.\n nodeArguments\n .filter((arg) => arg.type !== \"number\" || !arg.isInteger)\n .forEach(() => {\n throw new Error(`lotto node weight arguments must be integer values`);\n });\n\n const node = {\n type: \"lotto\",\n weights: nodeArguments.map(({ value }) => value),\n ...parseAttributeTokens(tokens, stringLiteralPlaceholders)\n } as LottoNodeDefinition;\n\n // This is a composite node, so we expect an opening '{'.\n popAndCheck(tokens, \"{\");\n\n // Return the lotto node definition.\n return node;\n}\n\n/**\n * Creates an action node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The action node JSON definition.\n */\nfunction createActionNode(\n tokens: string[],\n stringLiteralPlaceholders: StringLiteralPlaceholders\n): ActionNodeDefinition {\n // Parse any node arguments, we should have at least one which will be an identifier argument for the action name\n // and agent function to invoke for the action, all other arguments are to be passed as arguments to that function.\n const [actionNameIdentifier, ...agentFunctionArgs] = parseArgumentTokens(tokens, stringLiteralPlaceholders);\n\n // Our first argument MUST be defined and be an identifier as we require an action name argument.\n if (actionNameIdentifier?.type !== \"identifier\") {\n throw new Error(\"expected action name identifier argument\");\n }\n\n // Only the first argument should have been an identifier, all agent function arguments must be string, number, boolean or null.\n agentFunctionArgs\n .filter((arg) => arg.type === \"identifier\")\n .forEach((arg) => {\n throw new Error(\n `invalid action node argument value '${arg.value}', must be string, number, boolean or null`\n );\n });\n\n // Return the action node definition.\n return {\n type: \"action\",\n call: actionNameIdentifier.value,\n args: agentFunctionArgs.map(({ value }) => value),\n ...parseAttributeTokens(tokens, stringLiteralPlaceholders)\n };\n}\n\n/**\n * Creates a condition node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The condition node JSON definition.\n */\nfunction createConditionNode(\n tokens: string[],\n stringLiteralPlaceholders: StringLiteralPlaceholders\n): ConditionNodeDefinition {\n // Parse any node arguments, we should have at least one which will be an identifier argument for the condition name\n // and agent function to invoke for the condition, all other arguments are to be passed as arguments to that function.\n const [conditionNameIdentifier, ...agentFunctionArgs] = parseArgumentTokens(tokens, stringLiteralPlaceholders);\n\n // Our first argument MUST be defined and be an identifier as we require a condition name argument.\n if (conditionNameIdentifier?.type !== \"identifier\") {\n throw new Error(\"expected condition name identifier argument\");\n }\n\n // Only the first argument should have been an identifier, all agent function arguments must be string, number, boolean or null.\n agentFunctionArgs\n .filter((arg) => arg.type === \"identifier\")\n .forEach((arg) => {\n throw new Error(\n `invalid condition node argument value '${arg.value}', must be string, number, boolean or null`\n );\n });\n\n // Return the condition node definition.\n return {\n type: \"condition\",\n call: conditionNameIdentifier.value,\n args: agentFunctionArgs.map(({ value }) => value),\n ...parseAttributeTokens(tokens, stringLiteralPlaceholders)\n };\n}\n\n/**\n * Creates a wait node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The wait node JSON definition.\n */\nfunction createWaitNode(tokens: string[], stringLiteralPlaceholders: StringLiteralPlaceholders): WaitNodeDefinition {\n let node = { type: \"wait\" } as WaitNodeDefinition;\n\n // Get the node arguments.\n const nodeArguments = parseArgumentTokens(tokens, stringLiteralPlaceholders);\n\n // The arguments of a wait node are optional. We may have:\n // - No node arguments, in which case the wait will be indefinite until it is aborted.\n // - One node argument which will be the explicit duration of the wait.\n // - Two node arguments which define the min and max duration bounds from which a random duration will be picked.\n if (nodeArguments.length) {\n // All wait node arguments MUST be of type number and must be integer.\n nodeArguments\n .filter((arg) => arg.type !== \"number\" || !arg.isInteger)\n .forEach(() => {\n throw new Error(`wait node duration arguments must be integer values`);\n });\n\n // We may have:\n // - One node argument which will be the explicit duration of the wait.\n // - Two node arguments which define the min and max duration bounds from which a random duration will be picked.\n // - Too many arguments, which is not valid.\n if (nodeArguments.length === 1) {\n // An explicit duration was defined.\n node.duration = nodeArguments[0].value as number;\n } else if (nodeArguments.length === 2) {\n // Min and max duration bounds were defined from which a random duration will be picked.\n node.duration = [nodeArguments[0].value as number, nodeArguments[1].value as number];\n } else if (nodeArguments.length > 2) {\n // An incorrect number of duration arguments were defined.\n throw new Error(\"invalid number of wait node duration arguments defined\");\n }\n }\n\n // Return the wait node definition.\n return { ...node, ...parseAttributeTokens(tokens, stringLiteralPlaceholders) };\n}\n\n/**\n * Creates a branch node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The branch node JSON definition.\n */\nfunction createBranchNode(\n tokens: string[],\n stringLiteralPlaceholders: StringLiteralPlaceholders\n): BranchNodeDefinition {\n // Parse any node arguments, we should have one which will be an identifier argument for the root ref.\n const nodeArguments = parseArgumentTokens(tokens, stringLiteralPlaceholders);\n\n // We should have only a single identifer argument for a branch node, which is the root ref.\n if (nodeArguments.length !== 1 || nodeArguments[0].type !== \"identifier\") {\n throw new Error(\"expected single branch name argument\");\n }\n\n // Return the branch node definition.\n return { type: \"branch\", ref: nodeArguments[0].value };\n}\n", "import { RootNodeDefinition } from \"./BehaviourTreeDefinition\";\nimport { flattenDefinition, isBranchNode, isInteger } from \"./BehaviourTreeDefinitionUtilities\";\nimport { convertMDSLToJSON } from \"./mdsl/MDSLDefinitionParser\";\n\n/**\n * An object representing the result of validating a tree definition.\n */\nexport type DefinitionValidationResult = {\n /**\n * A flag defining whether validation succeeded.\n */\n succeeded: boolean;\n /**\n * A string containing the error message if validation did not succeed.\n */\n errorMessage?: string;\n};\n\n/**\n * Validates the specified behaviour tree definition in the form of JSON or MDSL.\n * @param definition The behaviour tree definition in the form of JSON or MDSL.\n * @returns An object representing the result of validating the given tree definition.\n */\nexport function validateDefinition(definition: any): DefinitionValidationResult {\n // A helper function to create a failure validation result with the given error message.\n const createFailureResult = (errorMessage: string) => ({ succeeded: false, errorMessage });\n\n // The definition must be defined.\n if (definition === null || typeof definition === \"undefined\") {\n return createFailureResult(\"definition is null or undefined\");\n }\n\n let rootNodeDefinitions: any[];\n\n // We are expecting a definition in one of three different forms:\n // - A string which we will assume is mdsl and we will parse this to JSON before validation.\n // - An array which we will assume is an array of root node definitions with at least one being the primary root node (no 'id' property)\n // - An object which we will assume is the primary root node and should not have an 'id' property.\n if (typeof definition === \"string\") {\n try {\n // The definition is a string which we can assume is mdsl, so attempt to parse it to a JSON definition in the form of an array of root node definitions.\n rootNodeDefinitions = convertMDSLToJSON(definition);\n } catch (error) {\n // We failed to parse the JSON from the mdsl, this is likely to be the result of it not being a valid mdsl string.\n return createFailureResult(`invalid mdsl: ${definition}`);\n }\n } else if (typeof definition === \"object\") {\n // The definition will either be an array (of root node definitions) or an object (the single primary root node definition).\n // If our definition is an array, we should verify that each of the elements within it are objects (potential root node definitions).\n if (Array.isArray(definition)) {\n // Find any invalid node definitions in our definition array, not full validation just a check that each is a valid object.\n const invalidDefinitionElements = definition.filter((element) => {\n // Each element isn't valid unless it is an object that isn't also an array and isn't null.\n return typeof element !== \"object\" || Array.isArray(element) || element === null;\n });\n\n // If we have any invalid node definitions then validation has failed.\n if (invalidDefinitionElements.length) {\n return createFailureResult(\n \"invalid elements in definition array, each must be an root node definition object\"\n );\n }\n\n // Our definition is already an array of root node definition objects.\n rootNodeDefinitions = definition;\n } else {\n // Our definition is an object, but we want an array of root node definitions.\n rootNodeDefinitions = [definition];\n }\n } else {\n return createFailureResult(`unexpected definition type of '${typeof definition}'`);\n }\n\n // Iterate over our array of root nodes and call validateNode for each, passing an initial depth of 0, wrapped in a try catch to handle validation failures.\n try {\n rootNodeDefinitions.forEach((rootNodeDefinition) => validateNode(rootNodeDefinition, 0));\n } catch (error) {\n // Handle cases where we have caught a thrown Error and return a failure result with the error message.\n if (error instanceof Error) {\n return createFailureResult(error.message);\n }\n\n // No idea what happened here!\n return createFailureResult(`unexpected error: ${error}`);\n }\n\n // Unpack all of the root node definitions into arrays of main ('id' defined) and sub ('id' not defined) root node definitions.\n const mainRootNodeDefinitions = rootNodeDefinitions.filter(({ id }) => typeof id === \"undefined\");\n const subRootNodeDefinitions = rootNodeDefinitions.filter(({ id }) => typeof id === \"string\" && id.length > 0);\n\n // We should ALWAYS have exactly one root node definition without an 'id' property defined, which is out main root node definition.\n if (mainRootNodeDefinitions.length !== 1) {\n return createFailureResult(\"expected single root node without 'id' property defined to act as main root\");\n }\n\n // We should never have duplicate 'id' properties across our sub root node definitions.\n const subRootNodeIdenitifers: string[] = [];\n for (const { id } of subRootNodeDefinitions) {\n // Have we already come across this 'id' property value?\n if (subRootNodeIdenitifers.includes(id)) {\n return createFailureResult(`multiple root nodes found with duplicate 'id' property value of '${id}'`);\n }\n\n subRootNodeIdenitifers.push(id);\n }\n\n // Check for any branch node circular depedencies. This will not include any globally registered subtrees.\n const circularDependencyPath = findBranchCircularDependencyPath(rootNodeDefinitions);\n\n // If we found a circular dependency in our root node and branch node definitions then the definition is definitely not valid.\n if (circularDependencyPath) {\n return createFailureResult(`circular dependency found in branch node references: ${circularDependencyPath}`);\n }\n\n // Our definition was valid!\n return { succeeded: true };\n}\n\n/**\n * Find the first circular depdendency path present in the array of root node definitions, or null if one doesn't exist.\n * This will not consider branch nodes that reference any globally registered subtrees.\n * @param rootNodeDefinitions The array of root node definitions.\n * @returns The first circular depdendency path present in the array of root node definitions as string, or null if one doesn't exist.\n */\nfunction findBranchCircularDependencyPath(rootNodeDefinitions: RootNodeDefinition[]): string | null {\n // Create a mapping of root node identifiers to other root nodes that they reference via branch nodes.\n // Below is an example of a mapping that includes a circular dependency (root => a => b => c => a)\n // [{ refs: [\"a\", \"b\"] }, { id: \"a\", refs: [\"b\"] }, { id: \"b\", refs: [\"c\"] }, { id: \"c\", refs: [\"a\"] }]\n const rootNodeMappings: { id: string | undefined; refs: string[] }[] = rootNodeDefinitions.map(\n (rootNodeDefinition) => ({\n id: rootNodeDefinition.id,\n refs: flattenDefinition(rootNodeDefinition)\n .filter(isBranchNode)\n .map(({ ref }) => ref)\n })\n );\n\n let badPathFormatted: string | null = null;\n\n // A recursive function to walk through the mappings, keeping track of which root nodes we have visited in the form of a path of root node identifiers.\n const followRefs = (mapping: { id: string | undefined; refs: string[] }, path: (string | undefined)[] = []) => {\n // Have we found a circular dependency?\n if (path.includes(mapping.id)) {\n // We found a circular dependency! Get the bad path of root node identifiers.\n const badPath = [...path, mapping.id];\n\n // Set the formatted path value. [undefined, \"a\", \"b\", \"c\", \"a\"] would be formatted as \"a -> b -> c -> a\".\n badPathFormatted = badPath.map((element) => !!element).join(\" => \");\n\n // No need to continue, we found a circular dependency.\n return;\n }\n\n for (const ref of mapping.refs) {\n // Find the mapping for the root node with an identifer matching the current ref.\n const subMapping = rootNodeMappings.find(({ id }) => id === ref);\n\n // We may not have a mapping for this ref, which will happen if this ref is for a globally registered subtree.\n if (subMapping) {\n followRefs(subMapping, [...path, mapping.id]);\n }\n }\n };\n\n return badPathFormatted;\n}\n\n/**\n * Validate an object that we expect to be a node definition.\n * @param definition An object that we expect to be a node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateNode(definition: any, depth: number): void {\n // Every node must be valid object and have a non-empty 'type' string property.\n if (typeof definition !== \"object\" || typeof definition.type !== \"string\" || definition.type.length === 0) {\n throw new Error(\n `node definition is not an object or 'type' property is not a non-empty string at depth '${depth}'`\n );\n }\n\n // How we validate this node definition will depend on its type.\n switch (definition.type) {\n case \"action\":\n validateActionNode(definition, depth);\n break;\n\n case \"condition\":\n validateConditionNode(definition, depth);\n break;\n\n case \"wait\":\n validateWaitNode(definition, depth);\n break;\n\n case \"branch\":\n validateBranchNode(definition, depth);\n break;\n\n case \"root\":\n validateRootNode(definition, depth);\n break;\n\n case \"success\":\n validateSuccessNode(definition, depth);\n break;\n\n case \"fail\":\n validateFailNode(definition, depth);\n break;\n\n case \"flip\":\n validateFlipNode(definition, depth);\n break;\n\n case \"repeat\":\n validateRepeatNode(definition, depth);\n break;\n\n case \"retry\":\n validateRetryNode(definition, depth);\n break;\n\n case \"sequence\":\n validateSequenceNode(definition, depth);\n break;\n\n case \"selector\":\n validateSelectorNode(definition, depth);\n break;\n\n case \"parallel\":\n validateParallelNode(definition, depth);\n break;\n\n default:\n throw new Error(`unexpected node type of '${definition.type}' at depth '${depth}'`);\n }\n}\n\n/**\n * Validate any attributes for a given node definition.\n * @param definition The node definition.\n * @param depth The depth of the node in the behaviour tree definition.\n */\nfunction validateNodeAttributes(definition: any, depth: number): void {\n // Validate each of the attribute types for this node.\n [\"while\", \"until\", \"entry\", \"exit\", \"step\"].forEach((attributeName) => {\n // Attempt to grab the definition for the current attribute from the node definition.\n const attributeDefinition = definition[attributeName];\n\n // All node attributes are optional, so there is nothing to do if the current attribute is not defined.\n if (typeof attributeDefinition === \"undefined\") {\n return;\n }\n\n // The attribute definition must be an object.\n if (typeof attributeDefinition !== \"object\") {\n throw new Error(\n `expected attribute '${attributeName}' to be an object for '${definition.type}' node at depth '${depth}'`\n );\n }\n\n // The 'call' property must be defined for any attribute definition.\n if (typeof attributeDefinition.call !== \"string\" || attributeDefinition.call.length === 0) {\n throw new Error(\n `expected 'call' property for attribute '${attributeName}' to be a non-empty string for '${definition.type}' node at depth '${depth}'`\n );\n }\n\n // If any node attribute arguments have been defined then they must have been defined in an array.\n if (typeof attributeDefinition.args !== \"undefined\" && !Array.isArray(attributeDefinition.args)) {\n throw new Error(\n `expected 'args' property for attribute '${attributeName}' to be an array for '${definition.type}' node at depth '${depth}'`\n );\n }\n });\n}\n\n/**\n * Validate an object that we expect to be a root node definition.\n * @param definition An object that we expect to be a root node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateRootNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"root\") {\n throw new Error(\"expected node type of 'root' for root node\");\n }\n\n // A root node cannot be the child of another node.\n if (depth > 0) {\n throw new Error(\"a root node cannot be the child of another node\");\n }\n\n // Check that, if the root node 'id' property is defined, it is a non-empty string.\n if (typeof definition.id !== \"undefined\" && (typeof definition.id !== \"string\" || definition.id.length === 0)) {\n throw new Error(\"expected non-empty string for 'id' property if defined for root node\");\n }\n\n // A root node is a decorator node, so must have a child node defined.\n if (typeof definition.child === \"undefined\") {\n throw new Error(\"expected property 'child' to be defined for root node\");\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n\n // Validate the child node of this decorator node.\n validateNode(definition.child, depth + 1);\n}\n\n/**\n * Validate an object that we expect to be a success node definition.\n * @param definition An object that we expect to be a success node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateSuccessNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"success\") {\n throw new Error(`expected node type of 'success' for success node at depth '${depth}'`);\n }\n\n // A success node is a decorator node, so must have a child node defined.\n if (typeof definition.child === \"undefined\") {\n throw new Error(`expected property 'child' to be defined for success node at depth '${depth}'`);\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n\n // Validate the child node of this decorator node.\n validateNode(definition.child, depth + 1);\n}\n\n/**\n * Validate an object that we expect to be a fail node definition.\n * @param definition An object that we expect to be a fail node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateFailNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"fail\") {\n throw new Error(`expected node type of 'fail' for fail node at depth '${depth}'`);\n }\n\n // A fail node is a decorator node, so must have a child node defined.\n if (typeof definition.child === \"undefined\") {\n throw new Error(`expected property 'child' to be defined for fail node at depth '${depth}'`);\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n\n // Validate the child node of this decorator node.\n validateNode(definition.child, depth + 1);\n}\n\n/**\n * Validate an object that we expect to be a flip node definition.\n * @param definition An object that we expect to be a flip node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateFlipNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"flip\") {\n throw new Error(`expected node type of 'flip' for flip node at depth '${depth}'`);\n }\n\n // A flip node is a decorator node, so must have a child node defined.\n if (typeof definition.child === \"undefined\") {\n throw new Error(`expected property 'child' to be defined for flip node at depth '${depth}'`);\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n\n // Validate the child node of this decorator node.\n validateNode(definition.child, depth + 1);\n}\n\n/**\n * Validate an object that we expect to be a repeat node definition.\n * @param definition An object that we expect to be a repeat node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateRepeatNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"repeat\") {\n throw new Error(`expected node type of 'repeat' for repeat node at depth '${depth}'`);\n }\n\n // A repeat node is a decorator node, so must have a child node defined.\n if (typeof definition.child === \"undefined\") {\n throw new Error(`expected property 'child' to be defined for repeat node at depth '${depth}'`);\n }\n\n // Check whether an 'iterations' property has been defined, it may not have been if this node is to repeat indefinitely.\n if (typeof definition.iterations !== \"undefined\") {\n if (Array.isArray(definition.iterations)) {\n // Check whether any elements of the array are not integer values.\n const containsNonInteger = !!definition.iterations.find((value: unknown) => !isInteger(value));\n\n // If the 'iterations' property is an array then it MUST contain two integer values.\n if (definition.iterations.length !== 2 || containsNonInteger) {\n throw new Error(\n `expected array containing two integer values for 'iterations' property if defined for repeat node at depth '${depth}'`\n );\n }\n } else if (!isInteger(definition.iterations)) {\n throw new Error(\n `expected integer value or array containing two integer values for 'iterations' property if defined for repeat node at depth '${depth}'`\n );\n }\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n\n // Validate the child node of this decorator node.\n validateNode(definition.child, depth + 1);\n}\n\n/**\n * Validate an object that we expect to be a retry node definition.\n * @param definition An object that we expect to be a retry node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateRetryNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"retry\") {\n throw new Error(`expected node type of 'retry' for retry node at depth '${depth}'`);\n }\n\n // A retry node is a decorator node, so must have a child node defined.\n if (typeof definition.child === \"undefined\") {\n throw new Error(`expected property 'child' to be defined for retry node at depth '${depth}'`);\n }\n\n // Check whether an 'attempts' property has been defined, it may not have been if this node is to retry indefinitely.\n if (typeof definition.attempts !== \"undefined\") {\n if (Array.isArray(definition.attempts)) {\n // Check whether any elements of the array are not integer values.\n const containsNonInteger = !!definition.attempts.find((value: unknown) => !isInteger(value));\n\n // If the 'attempts' property is an array then it MUST contain two integer values.\n if (definition.attempts.length !== 2 || containsNonInteger) {\n throw new Error(\n `expected array containing two integer values for 'attempts' property if defined for retry node at depth '${depth}'`\n );\n }\n } else if (!isInteger(definition.attempts)) {\n throw new Error(\n `expected integer value or array containing two integer values for 'attempts' property if defined for retry node at depth '${depth}'`\n );\n }\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n\n // Validate the child node of this decorator node.\n validateNode(definition.child, depth + 1);\n}\n\n/**\n * Validate an object that we expect to be a branch node definition.\n * @param definition An object that we expect to be a branch node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateBranchNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"branch\") {\n throw new Error(`expected node type of 'branch' for branch node at depth '${depth}'`);\n }\n\n // Check that the branch node 'ref' property is defined and is a non-empty string.\n if (typeof definition.ref !== \"string\" || definition.ref.length === 0) {\n throw new Error(`expected non-empty string for 'ref' property for branch node at depth '${depth}'`);\n }\n\n // It is invalid to define guard attributes for a branch node as they should be defined on the referenced root node.\n [\"while\", \"until\"].forEach((attributeName) => {\n if (typeof definition[attributeName] !== \"undefined\") {\n throw new Error(\n `guards should not be defined for branch nodes but guard '${attributeName}' was defined for branch node at depth '${depth}'`\n );\n }\n });\n\n // It is invalid to define callback attributes for a branch node as they should be defined on the referenced root node.\n [\"entry\", \"exit\", \"step\"].forEach((attributeName) => {\n if (typeof definition[attributeName] !== \"undefined\") {\n throw new Error(\n `callbacks should not be defined for branch nodes but callback '${attributeName}' was defined for branch node at depth '${depth}'`\n );\n }\n });\n}\n\n/**\n * Validate an object that we expect to be a action node definition.\n * @param definition An object that we expect to be a action node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateActionNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"action\") {\n throw new Error(`expected node type of 'action' for action node at depth '${depth}'`);\n }\n\n // The 'call' property must be defined for a action node definition.\n if (typeof definition.call !== \"string\" || definition.call.length === 0) {\n throw new Error(`expected non-empty string for 'call' property of action node at depth '${depth}'`);\n }\n\n // If any action function arguments have been defined then they must have been defined in an array.\n if (typeof definition.args !== \"undefined\" && !Array.isArray(definition.args)) {\n throw new Error(`expected array for 'args' property if defined for action node at depth '${depth}'`);\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n}\n\n/**\n * Validate an object that we expect to be a condition node definition.\n * @param definition An object that we expect to be a condition node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateConditionNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"condition\") {\n throw new Error(`expected node type of 'condition' for condition node at depth '${depth}'`);\n }\n\n // The 'call' property must be defined for a condition node definition.\n if (typeof definition.call !== \"string\" || definition.call.length === 0) {\n throw new Error(`expected non-empty string for 'call' property of condition node at depth '${depth}'`);\n }\n\n // If any condition function arguments have been defined then they must have been defined in an array.\n if (typeof definition.args !== \"undefined\" && !Array.isArray(definition.args)) {\n throw new Error(`expected array for 'args' property if defined for condition node at depth '${depth}'`);\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n}\n\n/**\n * Validate an object that we expect to be a wait node definition.\n * @param definition An object that we expect to be a wait node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateWaitNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"wait\") {\n throw new Error(`expected node type of 'wait' for wait node at depth '${depth}'`);\n }\n\n // Check whether a 'duration' property has been defined, it may not have been if this node is to wait indefinitely.\n if (typeof definition.duration !== \"undefined\") {\n if (Array.isArray(definition.duration)) {\n // Check whether any elements of the array are not integer values.\n const containsNonInteger = !!definition.duration.find((value: unknown) => !isInteger(value));\n\n // If the 'duration' property is an array then it MUST contain two integer values.\n if (definition.duration.length !== 2 || containsNonInteger) {\n throw new Error(\n `expected array containing two integer values for 'duration' property if defined for wait node at depth '${depth}'`\n );\n }\n } else if (!isInteger(definition.duration)) {\n throw new Error(\n `expected integer value or array containing two integer values for 'duration' property if defined for wait node at depth '${depth}'`\n );\n }\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n}\n\n/**\n * Validate an object that we expect to be a sequence node definition.\n * @param definition An object that we expect to be a sequence node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateSequenceNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"sequence\") {\n throw new Error(`expected node type of 'sequence' for sequence node at depth '${depth}'`);\n }\n\n // A sequence node is a composite node, so must have a children nodes array defined.\n if (!Array.isArray(definition.children) || definition.children.length === 0) {\n throw new Error(`expected non-empty 'children' array to be defined for sequence node at depth '${depth}'`);\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n\n // Validate the child nodes of this composite node.\n definition.children.forEach((child: any) => validateNode(child, depth + 1));\n}\n\n/**\n * Validate an object that we expect to be a selector node definition.\n * @param definition An object that we expect to be a selector node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateSelectorNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"selector\") {\n throw new Error(`expected node type of 'selector' for selector node at depth '${depth}'`);\n }\n\n // A selector node is a composite node, so must have a children nodes array defined.\n if (!Array.isArray(definition.children) || definition.children.length === 0) {\n throw new Error(`expected non-empty 'children' array to be defined for selector node at depth '${depth}'`);\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n\n // Validate the child nodes of this composite node.\n definition.children.forEach((child: any) => validateNode(child, depth + 1));\n}\n\n/**\n * Validate an object that we expect to be a parallel node definition.\n * @param definition An object that we expect to be a parallel node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateParallelNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"parallel\") {\n throw new Error(`expected node type of 'parallel' for parallel node at depth '${depth}'`);\n }\n\n // A parallel node is a composite node, so must have a children nodes array defined.\n if (!Array.isArray(definition.children) || definition.children.length === 0) {\n throw new Error(`expected non-empty 'children' array to be defined for parallel node at depth '${depth}'`);\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n\n // Validate the child nodes of this composite node.\n definition.children.forEach((child: any) => validateNode(child, depth + 1));\n}\n", "import Node from \"../../nodes/Node\";\n\n/**\n * An exception thrown when evaluating node guard path conditions and a conditions fails.\n */\nexport default class GuardUnsatisifedException extends Error {\n /**\n * @param source The node at which a guard condition failed.\n */\n constructor(private source: Node) {\n super(\"A guard path condition has failed\");\n }\n\n /**\n * Gets whether the specified node is the node at which a guard condition failed.\n * @param node The node to check against the source node.\n * @returns Whether the specified node is the node at which a guard condition failed.\n */\n isSourceNode = (node: Node) => node === this.source;\n}\n", "import { Agent } from \"../../Agent\";\nimport Guard from \"./Guard\";\nimport Node from \"../../nodes/Node\";\nimport GuardUnsatisifedException from \"./GuardUnsatisifedException\";\n\nexport type GuardPathPart = {\n node: Node;\n guards: Guard[];\n};\n\n/**\n * Represents a path of node guards along a root-to-leaf tree path.\n */\nexport default class GuardPath {\n /**\n * @param nodes An array of objects defining a node instance -> guard link, ordered by node depth.\n */\n constructor(private nodes: GuardPathPart[]) {}\n\n /**\n * Evaluate guard conditions for all guards in the tree path, moving outwards from the root.\n * @param agent The agent, required for guard evaluation.\n * @returns An evaluation results object.\n */\n evaluate = (agent: Agent) => {\n // We need to evaluate guard conditions for nodes up the tree, moving outwards from the root.\n for (const details of this.nodes) {\n // There can be multiple guards per node.\n for (const guard of details.guards) {\n // Check whether the guard condition passes, and throw an exception if not.\n if (!guard.isSatisfied(agent)) {\n throw new GuardUnsatisifedException(details.node);\n }\n }\n }\n };\n}\n", "import { Agent } from \"../Agent\";\nimport Attribute from \"../attributes/Attribute\";\nimport Entry from \"../attributes/callbacks/Entry\";\nimport Exit from \"../attributes/callbacks/Exit\";\nimport Step from \"../attributes/callbacks/Step\";\nimport Guard from \"../attributes/guards/Guard\";\nimport GuardPath from \"../attributes/guards/GuardPath\";\nimport GuardUnsatisifedException from \"../attributes/guards/GuardUnsatisifedException\";\nimport { BehaviourTreeOptions } from \"../BehaviourTreeOptions\";\nimport { AnyArgument } from \"../RootAstNodesBuilder\";\nimport State, { AnyState } from \"../State\";\nimport Leaf from \"./leaf/Leaf\";\n\n/**\n * A base node.\n */\nexport default abstract class Node {\n /**\n * The node uid.\n */\n private readonly uid: string = createNodeUid();\n /**\n * The node state.\n */\n private state: AnyState = State.READY;\n /**\n * The guard path to evaluate as part of a node update.\n */\n private guardPath: GuardPath | undefined;\n\n /**\n * @param type The node type.\n * @param attributes The node attributes.\n * @param args The node argument definitions.\n */\n constructor(private type: string, private attributes: Attribute[], private args: AnyArgument[]) {}\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected abstract onUpdate(agent: Agent, options: BehaviourTreeOptions): void;\n\n /**\n * Gets the name of the node.\n */\n public abstract getName(): string;\n\n /**\n * Gets whether this node is a leaf node.\n */\n public abstract isLeafNode: () => this is Leaf;\n\n /**\n * Gets/Sets the state of the node.\n */\n getState = (): AnyState => this.state;\n setState = (value: AnyState): void => {\n this.state = value;\n };\n\n /**\n * Gets the unique id of the node.\n */\n getUid = () => this.uid;\n\n /**\n * Gets the type of the node.\n */\n getType = () => this.type;\n\n /**\n * Gets the node attributes.\n */\n getAttributes = () => this.attributes;\n\n /**\n * Gets the node arguments.\n */\n getArguments = () => this.args;\n\n /**\n * Gets the node attribute with the specified type, or null if it does not exist.\n */\n getAttribute(type: \"entry\" | \"ENTRY\"): Entry;\n getAttribute(type: \"exit\" | \"EXIT\"): Exit;\n getAttribute(type: \"step\" | \"STEP\"): Step;\n getAttribute(type: string): Attribute {\n return (\n this.getAttributes().filter((decorator) => decorator.getType().toUpperCase() === type.toUpperCase())[0] ||\n null\n );\n }\n\n /**\n * Gets the node attributes.\n */\n getGuardAttributes = (): Guard[] => this.getAttributes().filter((decorator) => decorator.isGuard()) as Guard[];\n\n /**\n * Sets the guard path to evaluate as part of a node update.\n */\n setGuardPath = (value: GuardPath) => (this.guardPath = value);\n\n /**\n * Gets whether a guard path is assigned to this node.\n */\n hasGuardPath = () => !!this.guardPath;\n\n /**\n * Gets whether this node is in the specified state.\n * @param value The value to compare to the node state.\n */\n public is(value: AnyState): boolean {\n return this.state === value;\n }\n\n /**\n * Reset the state of the node.\n */\n public reset(): void {\n this.setState(State.READY);\n }\n\n /**\n * Abort the running of this node.\n * @param agent The agent.\n */\n public abort(agent: Agent): void {\n // There is nothing to do if this node is not in the running state.\n if (!this.is(State.RUNNING)) {\n return;\n }\n\n // Reset the state of this node.\n this.reset();\n\n this.getAttribute(\"exit\")?.callAgentFunction(agent, false, true);\n }\n\n /**\n * Update the node.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n * @returns The result of the update.\n */\n public update(agent: Agent, options: BehaviourTreeOptions): void {\n // If this node is already in a 'SUCCEEDED' or 'FAILED' state then there is nothing to do.\n if (this.is(State.SUCCEEDED) || this.is(State.FAILED)) {\n return;\n }\n\n try {\n // Evaluate all of the guard path conditions for the current tree path.\n this.guardPath!.evaluate(agent);\n\n // If this node is in the READY state then call the ENTRY for this node if it exists.\n if (this.is(State.READY)) {\n this.getAttribute(\"entry\")?.callAgentFunction(agent);\n }\n\n this.getAttribute(\"step\")?.callAgentFunction(agent);\n\n // Do the actual update.\n this.onUpdate(agent, options);\n\n // If this node is now in a 'SUCCEEDED' or 'FAILED' state then call the EXIT for this node if it exists.\n if (this.is(State.SUCCEEDED) || this.is(State.FAILED)) {\n this.getAttribute(\"exit\")?.callAgentFunction(agent, this.is(State.SUCCEEDED), false);\n }\n } catch (error) {\n // If the error is a GuardUnsatisfiedException then we need to determine if this node is the source.\n if (error instanceof GuardUnsatisifedException && error.isSourceNode(this)) {\n // Abort the current node.\n this.abort(agent);\n\n // Any node that is the source of an abort will be a failed node.\n this.setState(State.FAILED);\n } else {\n throw error;\n }\n }\n }\n}\n\n/**\n * Create a randomly generated node uid.\n * @returns A randomly generated node uid.\n */\nfunction createNodeUid(): string {\n var S4 = function () {\n return (((1 + Math.random()) * 0x10000) | 0).toString(16).substring(1);\n };\n return S4() + S4() + \"-\" + S4() + \"-\" + S4() + \"-\" + S4() + \"-\" + S4() + S4() + S4();\n}\n", "import Node from \"../Node\";\n\n/**\n * A leaf node.\n */\nexport default abstract class Leaf extends Node {\n /**\n * Gets whether this node is a leaf node.\n */\n isLeafNode = () => true;\n}\n", "import { ActionResult, Agent, ExitFunctionArg, FunctionArg, GlobalFunction } from \"./Agent\";\nimport { AnyArgument, RootAstNode } from \"./RootAstNodesBuilder\";\n\n// Exit callbacks receive their own special type of argument.\n// There's probably stricter ways to represent this but it feels overly complex right now.\ntype ExitResultArg = { value: ExitFunctionArg };\nexport type AnyExitArgument = AnyArgument | ExitResultArg;\n\nexport type InvokerFunction = (args: AnyExitArgument[]) => ActionResult;\n\n/**\n * A singleton used to store and lookup registered functions and subtrees.\n */\nexport default class Lookup {\n /**\n * The object holding any registered functions keyed on function name.\n */\n private static functionTable: { [key: string]: GlobalFunction } = {};\n /**\n * The object holding any registered sub-trees keyed on tree name.\n */\n private static subtreeTable: { [key: string]: RootAstNode } = {};\n\n /**\n * Gets the function with the specified name.\n * @param name The name of the function.\n * @returns The function with the specified name.\n */\n public static getFunc(name: string): GlobalFunction {\n return this.functionTable[name];\n }\n\n /**\n * Sets the function with the specified name for later lookup.\n * @param name The name of the function.\n * @param func The function.\n */\n public static setFunc(name: string, func: GlobalFunction): void {\n this.functionTable[name] = func;\n }\n\n /**\n * Gets the function invoker for the specified agent and function name.\n * If a function with the specified name exists on the agent object then it will\n * be returned, otherwise we will then check the registered functions for a match.\n * @param agent The agent instance that this behaviour tree is modelling behaviour for.\n * @param name The function name.\n * @returns The function invoker for the specified agent and function name.\n */\n static getFuncInvoker(agent: Agent, name: string): InvokerFunction | null {\n // Check whether the agent contains the specified function.\n const foundOnAgent = agent[name];\n if (foundOnAgent && typeof foundOnAgent === \"function\") {\n return (args: AnyExitArgument[]): boolean | ActionResult =>\n foundOnAgent.apply(\n agent,\n args.map((arg) => arg.value)\n );\n }\n\n // The agent does not contain the specified function but it may have been registered at some point.\n if (this.functionTable[name] && typeof this.functionTable[name] === \"function\") {\n return (args: AnyExitArgument[]) => this.functionTable[name](agent, ...args.map((arg) => arg.value));\n }\n\n // We have no function to invoke.\n return null;\n }\n\n /**\n * Gets the subtree with the specified name.\n * @param name The name of the subtree.\n * @returns The subtree with the specified name.\n */\n static getSubtree(name: string): RootAstNode {\n return this.subtreeTable[name];\n }\n\n /**\n * Sets the subtree with the specified name for later lookup.\n * @param name The name of the subtree.\n * @param subtree The subtree.\n */\n static setSubtree(name: string, subtree: RootAstNode) {\n this.subtreeTable[name] = subtree;\n }\n\n /**\n * Removes the registered function or subtree with the specified name.\n * @param name The name of the registered function or subtree.\n */\n static remove(name: string) {\n delete this.functionTable[name];\n delete this.subtreeTable[name];\n }\n\n /**\n * Remove all registered functions and subtrees.\n */\n static empty() {\n this.functionTable = {};\n this.subtreeTable = {};\n }\n}\n", "import Leaf from \"./Leaf\";\nimport State, { CompleteState } from \"../../State\";\nimport Lookup from \"../../Lookup\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { AnyArgument } from \"../../RootAstNodesBuilder\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * An Action leaf node.\n * This represents an immediate or ongoing state of behaviour.\n */\nexport default class Action extends Leaf {\n /**\n * @param attributes The node attributes.\n * @param actionName The action name.\n * @param actionArguments The array of action argument definitions.\n */\n constructor(attributes: Attribute[], private actionName: string, private actionArguments: AnyArgument[]) {\n super(\"action\", attributes, actionArguments);\n }\n\n /**\n * Whether there is a pending update promise.\n */\n private isUsingUpdatePromise = false;\n\n /**\n * The finished state result of an update promise.\n */\n private updatePromiseStateResult: CompleteState | null = null;\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // If the result of this action depends on an update promise then there is nothing to do until\n // it resolves, unless there has been a value set as a result of the update promise resolving.\n if (this.isUsingUpdatePromise) {\n // Check whether the update promise has resolved with a state value.\n if (this.updatePromiseStateResult) {\n // Set the state of this node to match the state returned by the promise.\n this.setState(this.updatePromiseStateResult);\n }\n\n return;\n }\n\n // Attempt to get the invoker for the action function.\n const actionFuncInvoker = Lookup.getFuncInvoker(agent, this.actionName);\n\n // The action function should be defined.\n if (actionFuncInvoker === null) {\n throw new Error(\n `cannot update action node as the action '${this.actionName}' function is not defined on the agent and has not been registered`\n );\n }\n\n // Call the action function, the result of which may be:\n // - The finished state of this action node.\n // - A promise to return a finished node state.\n // - Undefined if the node should remain in the running state.\n const updateResult = actionFuncInvoker(this.actionArguments) as CompleteState | Promise;\n\n if (updateResult instanceof Promise) {\n updateResult.then(\n (result) => {\n // If 'isUpdatePromisePending' is null then the promise was cleared as it was resolving, probably via an abort of reset.\n if (!this.isUsingUpdatePromise) {\n return;\n }\n\n // Check to make sure the result is a valid finished state.\n if (result !== State.SUCCEEDED && result !== State.FAILED) {\n throw new Error(\n \"action node promise resolved with an invalid value, expected a State.SUCCEEDED or State.FAILED value to be returned\"\n );\n }\n\n // Set pending update promise state result to be processed on next update.\n this.updatePromiseStateResult = result;\n },\n (reason) => {\n // If 'isUpdatePromisePending' is null then the promise was cleared as it was resolving, probably via an abort of reset.\n if (!this.isUsingUpdatePromise) {\n return;\n }\n\n // Just throw whatever was returned as the rejection argument.\n throw new Error(reason);\n }\n );\n\n // This node will be in the 'RUNNING' state until the update promise resolves.\n this.setState(State.RUNNING);\n\n // We are now waiting for the promise returned by the use to resolve before we know what state this node is in.\n this.isUsingUpdatePromise = true;\n } else {\n // Validate the returned value.\n this.validateUpdateResult(updateResult);\n\n // Set the state of this node, this may be undefined, which just means that the node is still in the 'RUNNING' state.\n this.setState(updateResult || State.RUNNING);\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => this.actionName;\n\n /**\n * Reset the state of the node.\n */\n reset = () => {\n // Reset the state of this node.\n this.setState(State.READY);\n\n // There is no longer an update promise that we care about.\n this.isUsingUpdatePromise = false;\n this.updatePromiseStateResult = null;\n };\n\n /**\n * Validate the result of an update function call.\n * @param result The result of an update function call.\n */\n private validateUpdateResult = (result: CompleteState | boolean) => {\n switch (result) {\n case State.SUCCEEDED:\n case State.FAILED:\n case undefined:\n return;\n default:\n throw new Error(\n `action '${this.actionName}' 'onUpdate' returned an invalid response, expected an optional State.SUCCEEDED or State.FAILED value to be returned`\n );\n }\n };\n}\n", "import Leaf from \"./Leaf\";\nimport State from \"../../State\";\nimport Lookup from \"../../Lookup\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { AnyArgument } from \"../../RootAstNodesBuilder\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A Condition leaf node.\n * This will succeed or fail immediately based on an agent predicate, without moving to the 'RUNNING' state.\n */\nexport default class Condition extends Leaf {\n /**\n * @param attributes The node attributes.\n * @param conditionName The name of the condition function.\n * @param conditionArguments The array of condition argument definitions.\n */\n constructor(attributes: Attribute[], private conditionName: string, private conditionArguments: AnyArgument[]) {\n super(\"condition\", attributes, conditionArguments);\n }\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // Attempt to get the invoker for the condition function.\n const conditionFuncInvoker = Lookup.getFuncInvoker(agent, this.conditionName);\n\n // The condition function should be defined.\n if (conditionFuncInvoker === null) {\n throw new Error(\n `cannot update condition node as the condition '${this.conditionName}' function is not defined on the agent and has not been registered`\n );\n }\n\n // Call the condition function to determine the state of this node.\n this.setState(!!conditionFuncInvoker(this.conditionArguments) ? State.SUCCEEDED : State.FAILED);\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => this.conditionName;\n}\n", "import Leaf from \"./Leaf\";\nimport State from \"../../State\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { Agent } from \"../../Agent\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A WAIT node.\n * The state of this node will change to SUCCEEDED after a duration of time\n */\nexport default class Wait extends Leaf {\n /**\n * @param attributes The node attributes.\n * @param duration The duration that this node will wait to succeed in milliseconds.\n * @param durationMin The minimum possible duration in milliseconds that this node will wait to succeed.\n * @param durationMax The maximum possible duration in milliseconds that this node will wait to succeed.\n */\n constructor(\n attributes: Attribute[],\n private duration: number | null,\n private durationMin: number | null,\n private durationMax: number | null\n ) {\n super(\"wait\", attributes, []);\n }\n\n /**\n * The time in milliseconds at which this node was first updated.\n */\n private initialUpdateTime: number = 0;\n\n /**\n * The total duration in milliseconds that this node will be waiting for.\n */\n private totalDuration: number | null = null;\n\n /**\n * The duration in milliseconds that this node has been waiting for.\n */\n private waitedDuration: number = 0;\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // If this node is in the READY state then we need to set the initial update time.\n if (this.is(State.READY)) {\n // Set the initial update time.\n this.initialUpdateTime = new Date().getTime();\n\n // Set the initial waited duration.\n this.waitedDuration = 0;\n\n // Are we dealing with an explicit duration or will we be randomly picking a duration between the min and max duration.\n if (this.duration !== null) {\n this.totalDuration = this.duration;\n } else if (this.durationMin !== null && this.durationMax !== null) {\n // We will be picking a random duration between a min and max duration, if the optional 'random' behaviour tree\n // function option is defined then we will be using that, otherwise we will fall back to using Math.random.\n const random = typeof options.random === \"function\" ? options.random : Math.random;\n\n // Pick a random duration between a min and max duration.\n this.totalDuration = Math.floor(\n random() * (this.durationMax - this.durationMin + 1) + this.durationMin\n );\n } else {\n this.totalDuration = null;\n }\n\n // The node is now running until we finish waiting.\n this.setState(State.RUNNING);\n }\n\n // If we have no total duration then this wait node will wait indefinitely until it is aborted.\n if (this.totalDuration === null) {\n return;\n }\n\n // If we have a 'getDeltaTime' function defined as part of our options then we will use it to figure out how long we have waited for.\n if (typeof options.getDeltaTime === \"function\") {\n // Get the delta time.\n const deltaTime = options.getDeltaTime();\n\n // Our delta time must be a valid number and cannot be NaN.\n if (typeof deltaTime !== \"number\" || isNaN(deltaTime)) {\n throw new Error(\"The delta time must be a valid number and not NaN.\");\n }\n\n // Update the amount of time that this node has been waiting for based on the delta time.\n this.waitedDuration += deltaTime * 1000;\n } else {\n // We are not using a delta time, so we will just work out hom much time has passed since the first update.\n this.waitedDuration = new Date().getTime() - this.initialUpdateTime;\n }\n\n // Have we waited long enough?\n if (this.waitedDuration >= this.totalDuration) {\n // We have finished waiting!\n this.setState(State.SUCCEEDED);\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => {\n if (this.duration !== null) {\n return `WAIT ${this.duration}ms`;\n } else if (this.durationMin !== null && this.durationMax !== null) {\n return `WAIT ${this.durationMin}ms-${this.durationMax}ms`;\n } else {\n return \"WAIT\";\n }\n };\n}\n", "import Node from \"../Node\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\n\n/**\n * A decorator node that wraps a single child node.\n */\nexport default abstract class Decorator extends Node {\n /**\n * @param type The node type.\n * @param attributes The node attributes.\n * @param child The child node.\n */\n constructor(type: string, attributes: Attribute[], protected child: Node) {\n super(type, attributes, []);\n }\n\n /**\n * Gets whether this node is a leaf node.\n */\n isLeafNode = () => false;\n\n /**\n * Gets the children of this node.\n */\n getChildren = () => [this.child];\n\n /**\n * Reset the state of the node.\n */\n reset = () => {\n // Reset the state of this node.\n this.setState(State.READY);\n\n // Reset the state of the child node.\n this.child.reset();\n };\n\n /**\n * Abort the running of this node.\n * @param agent The agent.\n */\n abort = (agent: Agent) => {\n // There is nothing to do if this node is not in the running state.\n if (!this.is(State.RUNNING)) {\n return;\n }\n\n // Abort the child node.\n this.child.abort(agent);\n\n // Reset the state of this node.\n this.reset();\n\n this.getAttribute(\"exit\")?.callAgentFunction(agent, false, true);\n };\n}\n", "import Node from \"../Node\";\nimport Decorator from \"./Decorator\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A Root node.\n * The root node will have a single child.\n */\nexport default class Root extends Decorator {\n /**\n * @param attributes The node attributes.\n * @param child The child node.\n */\n constructor(attributes: Attribute[], child: Node) {\n super(\"root\", attributes, child);\n }\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // If the child has never been updated or is running then we will need to update it now.\n if (this.child.getState() === State.READY || this.child.getState() === State.RUNNING) {\n // Update the child of this node.\n this.child.update(agent, options);\n }\n\n // The state of the root node is the state of its child.\n this.setState(this.child.getState());\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => \"ROOT\";\n}\n", "import Node from \"../Node\";\nimport Decorator from \"./Decorator\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A REPEAT node.\n * The node has a single child which can have:\n * -- A number of iterations for which to repeat the child node.\n * -- An infinite repeat loop if neither an iteration count or a condition function is defined.\n * The REPEAT node will stop and have a 'FAILED' state if its child is ever in a 'FAILED' state after an update.\n * The REPEAT node will attempt to move on to the next iteration if its child is ever in a 'SUCCEEDED' state.\n */\nexport default class Repeat extends Decorator {\n /**\n * @param attributes The node attributes.\n * @param iterations The number of iterations to repeat the child node.\n * @param iterationsMin The minimum possible number of iterations to repeat the child node.\n * @param iterationsMax The maximum possible number of iterations to repeat the child node.\n * @param child The child node.\n */\n constructor(\n attributes: Attribute[],\n private iterations: number | null,\n private iterationsMin: number | null,\n private iterationsMax: number | null,\n child: Node\n ) {\n super(\"repeat\", attributes, child);\n }\n\n /**\n * The number of target iterations to make.\n */\n private targetIterationCount: number | null = null;\n\n /**\n * The current iteration count.\n */\n private currentIterationCount: number = 0;\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // If this node is in the READY state then we need to reset the child and the target iteration count.\n if (this.is(State.READY)) {\n // Reset the child node.\n this.child.reset();\n\n // Reset the current iteration count.\n this.currentIterationCount = 0;\n\n // Set the target iteration count.\n this.setTargetIterationCount(options);\n }\n\n // Do a check to see if we can iterate. If we can then this node will move into the 'RUNNING' state.\n // If we cannot iterate then we have hit our target iteration count, which means that the node has succeeded.\n if (this.canIterate()) {\n // This node is in the running state and can do its initial iteration.\n this.setState(State.RUNNING);\n\n // We may have already completed an iteration, meaning that the child node will be in the SUCCEEDED state.\n // If this is the case then we will have to reset the child node now.\n if (this.child.getState() === State.SUCCEEDED) {\n this.child.reset();\n }\n\n // Update the child of this node.\n this.child.update(agent, options);\n\n // If the child moved into the FAILED state when we updated it then there is nothing left to do and this node has also failed.\n // If it has moved into the SUCCEEDED state then we have completed the current iteration.\n if (this.child.getState() === State.FAILED) {\n // The child has failed, meaning that this node has failed.\n this.setState(State.FAILED);\n\n return;\n } else if (this.child.getState() === State.SUCCEEDED) {\n // We have completed an iteration.\n this.currentIterationCount += 1;\n }\n } else {\n // This node is in the 'SUCCEEDED' state as we cannot iterate any more.\n this.setState(State.SUCCEEDED);\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => {\n if (this.iterations !== null) {\n return `REPEAT ${this.iterations}x`;\n } else if (this.iterationsMin !== null && this.iterationsMax !== null) {\n return `REPEAT ${this.iterationsMin}x-${this.iterationsMax}x`;\n } else {\n return \"REPEAT\";\n }\n };\n\n /**\n * Reset the state of the node.\n */\n reset = () => {\n // Reset the state of this node.\n this.setState(State.READY);\n\n // Reset the current iteration count.\n this.currentIterationCount = 0;\n\n // Reset the child node.\n this.child.reset();\n };\n\n /**\n * Gets whether an iteration can be made.\n * @returns Whether an iteration can be made.\n */\n private canIterate = () => {\n if (this.targetIterationCount !== null) {\n // We can iterate as long as we have not reached our target iteration count.\n return this.currentIterationCount < this.targetIterationCount;\n }\n\n // If neither an iteration count or a condition function were defined then we can iterate indefinitely.\n return true;\n };\n\n /**\n * Sets the target iteration count.\n * @param options The behaviour tree options object.\n */\n private setTargetIterationCount = (options: BehaviourTreeOptions) => {\n // Are we dealing with an explicit iteration count or will we be randomly picking a iteration count between the min and max iteration count.\n if (this.iterations !== null) {\n this.targetIterationCount = this.iterations;\n } else if (this.iterationsMin !== null && this.iterationsMax !== null) {\n // We will be picking a random iteration count between a min and max iteration count, if the optional 'random'\n // behaviour tree function option is defined then we will be using that, otherwise we will fall back to using Math.random.\n const random = typeof options.random === \"function\" ? options.random : Math.random;\n\n // Pick a random iteration count between a min and max iteration count.\n this.targetIterationCount = Math.floor(\n random() * (this.iterationsMax - this.iterationsMin + 1) + this.iterationsMin\n );\n } else {\n this.targetIterationCount = null;\n }\n };\n}\n", "import Node from \"../Node\";\nimport Decorator from \"./Decorator\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A RETRY node.\n * The node has a single child which can have:\n * -- A number of iterations for which to repeat the child node.\n * -- An infinite repeat loop if neither an iteration count or a condition function is defined.\n * The RETRY node will stop and have a 'SUCCEEDED' state if its child is ever in a 'SUCCEEDED' state after an update.\n * The RETRY node will attempt to move on to the next iteration if its child is ever in a 'FAILED' state.\n */\nexport default class Retry extends Decorator {\n /**\n * @param attributes The node attributes.\n * @param attempts The number of attempts to retry the child node.\n * @param attemptsMin The minimum possible number of attempts to retry the child node.\n * @param attemptsMax The maximum possible number of attempts to retry the child node.\n * @param child The child node.\n */\n constructor(\n attributes: Attribute[],\n private attempts: number | null,\n private attemptsMin: number | null,\n private attemptsMax: number | null,\n child: Node\n ) {\n super(\"retry\", attributes, child);\n }\n\n /**\n * The number of target attempts to make.\n */\n private targetAttemptCount: number | null = null;\n\n /**\n * The current attempt count.\n */\n private currentAttemptCount: number = 0;\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // If this node is in the READY state then we need to reset the child and the target attempt count.\n if (this.is(State.READY)) {\n // Reset the child node.\n this.child.reset();\n\n // Reset the current attempt count.\n this.currentAttemptCount = 0;\n\n // Set the target attempt count.\n this.setTargetAttemptCount(options);\n }\n\n // Do a check to see if we can attempt. If we can then this node will move into the 'RUNNING' state.\n // If we cannot attempt then we have hit our target attempt count, which means that the node has succeeded.\n if (this.canAttempt()) {\n // This node is in the running state and can do its initial attempt.\n this.setState(State.RUNNING);\n\n // We may have already completed an attempt, meaning that the child node will be in the FAILED state.\n // If this is the case then we will have to reset the child node now.\n if (this.child.getState() === State.FAILED) {\n this.child.reset();\n }\n\n // Update the child of this node.\n this.child.update(agent, options);\n\n // If the child moved into the SUCCEEDED state when we updated it then there is nothing left to do and this node has also succeeded.\n // If it has moved into the FAILED state then we have completed the current attempt.\n if (this.child.getState() === State.SUCCEEDED) {\n // The child has succeeded, meaning that this node has succeeded.\n this.setState(State.SUCCEEDED);\n\n return;\n } else if (this.child.getState() === State.FAILED) {\n // We have completed an attempt.\n this.currentAttemptCount += 1;\n }\n } else {\n // This node is in the 'FAILED' state as we cannot iterate any more.\n this.setState(State.FAILED);\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => {\n if (this.attempts !== null) {\n return `RETRY ${this.attempts}x`;\n } else if (this.attemptsMin !== null && this.attemptsMax !== null) {\n return `RETRY ${this.attemptsMin}x-${this.attemptsMax}x`;\n } else {\n return \"RETRY\";\n }\n };\n\n /**\n * Reset the state of the node.\n */\n reset = () => {\n // Reset the state of this node.\n this.setState(State.READY);\n\n // Reset the current attempt count.\n this.currentAttemptCount = 0;\n\n // Reset the child node.\n this.child.reset();\n };\n\n /**\n * Gets whether an attempt can be made.\n * @returns Whether an attempt can be made.\n */\n canAttempt = () => {\n if (this.targetAttemptCount !== null) {\n // We can attempt as long as we have not reached our target attempt count.\n return this.currentAttemptCount < this.targetAttemptCount;\n }\n\n // If neither an attempt count or a condition function were defined then we can attempt indefinitely.\n return true;\n };\n\n /**\n * Sets the target attempt count.\n * @param options The behaviour tree options object.\n */\n setTargetAttemptCount = (options: BehaviourTreeOptions) => {\n // Are we dealing with an explicit attempt count or will we be randomly picking an attempt count between the min and max attempt count.\n if (this.attempts !== null) {\n this.targetAttemptCount = this.attempts;\n } else if (this.attemptsMin !== null && this.attemptsMax !== null) {\n // We will be picking a random attempt count between a min and max attempt count, if the optional 'random'\n // behaviour tree function option is defined then we will be using that, otherwise we will fall back to using Math.random.\n const random = typeof options.random === \"function\" ? options.random : Math.random;\n\n // Pick a random attempt count between a min and max attempt count.\n this.targetAttemptCount = Math.floor(\n random() * (this.attemptsMax - this.attemptsMin + 1) + this.attemptsMin\n );\n } else {\n this.targetAttemptCount = null;\n }\n };\n}\n", "import Decorator from \"./Decorator\";\nimport State from \"../../State\";\nimport Node from \"../Node\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A Flip node.\n * This node wraps a single child and will flip the state of the child state.\n */\nexport default class Flip extends Decorator {\n /**\n * @param attributes The node attributes.\n * @param child The child node.\n */\n constructor(attributes: Attribute[], child: Node) {\n super(\"flip\", attributes, child);\n }\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // If the child has never been updated or is running then we will need to update it now.\n if (this.child.getState() === State.READY || this.child.getState() === State.RUNNING) {\n this.child.update(agent, options);\n }\n\n // The state of this node will depend in the state of its child.\n switch (this.child.getState()) {\n case State.RUNNING:\n this.setState(State.RUNNING);\n break;\n\n case State.SUCCEEDED:\n this.setState(State.FAILED);\n break;\n\n case State.FAILED:\n this.setState(State.SUCCEEDED);\n break;\n\n default:\n this.setState(State.READY);\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => \"FLIP\";\n}\n", "import Node from \"../Node\";\nimport Decorator from \"./Decorator\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A Succeed node.\n * This node wraps a single child and will always move to the 'SUCCEEDED' state when the child moves to a 'SUCCEEDED' or 'FAILED' state.\n */\nexport default class Succeed extends Decorator {\n /**\n * @param attributes The node attributes.\n * @param child The child node.\n */\n constructor(attributes: Attribute[], child: Node) {\n super(\"succeed\", attributes, child);\n }\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // If the child has never been updated or is running then we will need to update it now.\n if (this.child.getState() === State.READY || this.child.getState() === State.RUNNING) {\n this.child.update(agent, options);\n }\n\n // The state of this node will depend in the state of its child.\n switch (this.child.getState()) {\n case State.RUNNING:\n this.setState(State.RUNNING);\n break;\n\n case State.SUCCEEDED:\n case State.FAILED:\n this.setState(State.SUCCEEDED);\n break;\n\n default:\n this.setState(State.READY);\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => \"SUCCEED\";\n}\n", "import Node from \"../Node\";\nimport Decorator from \"./Decorator\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A Fail node.\n * This node wraps a single child and will always move to the 'FAILED' state when the child moves to a 'SUCCEEDED' or 'FAILED' state.\n */\nexport default class Fail extends Decorator {\n /**\n * @param attributes The node attributes.\n * @param child The child node.\n */\n constructor(attributes: Attribute[], child: Node) {\n super(\"fail\", attributes, child);\n }\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // If the child has never been updated or is running then we will need to update it now.\n if (this.child.getState() === State.READY || this.child.getState() === State.RUNNING) {\n this.child.update(agent, options);\n }\n\n // The state of this node will depend in the state of its child.\n switch (this.child.getState()) {\n case State.RUNNING:\n this.setState(State.RUNNING);\n break;\n\n case State.SUCCEEDED:\n case State.FAILED:\n this.setState(State.FAILED);\n break;\n\n default:\n this.setState(State.READY);\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => \"FAIL\";\n}\n", "import createLotto from \"lotto-draw\";\n\nimport Node from \"../Node\";\nimport Composite from \"./Composite\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A LOTTO node.\n * A winning child is picked on the initial update of this node, based on ticket weighting.\n * The state of this node will match the state of the winning child.\n */\nexport default class Lotto extends Composite {\n /**\n * @param attributes The node attributes.\n * @param tickets The child node tickets.\n * @param children The child nodes.\n */\n constructor(attributes: Attribute[], private tickets: number[], children: Node[]) {\n super(\"lotto\", attributes, children);\n }\n\n /**\n * The child node selected to be the active one.\n */\n private selectedChild: Node | undefined;\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // If this node is in the READY state then we need to pick a winning child node.\n if (this.is(State.READY)) {\n // Create a lotto draw with which to randomly pick a child node to become the active one.\n const lottoDraw = createLotto({\n // Hook up the optional 'random' behaviour tree function option to the one used by 'lotto-draw'.\n random: options.random,\n // Pass in each child node as a participant in the lotto draw with their respective ticket count.\n participants: this.children.map((child, index) => [child, this.tickets[index] || 1])\n });\n\n // Randomly pick a child based on ticket weighting, this will become the active child for this composite node.\n this.selectedChild = lottoDraw.draw() || undefined;\n }\n\n // If something went wrong and we don't have an active child then we should throw an error.\n if (!this.selectedChild) {\n throw new Error(\"failed to update lotto node as it has no active child\");\n }\n\n // If the selected child has never been updated or is running then we will need to update it now.\n if (this.selectedChild.getState() === State.READY || this.selectedChild.getState() === State.RUNNING) {\n this.selectedChild.update(agent, options);\n }\n\n // The state of the lotto node is the state of its selected child.\n this.setState(this.selectedChild.getState());\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => (this.tickets.length ? `LOTTO [${this.tickets.join(\",\")}]` : \"LOTTO\");\n}\n", "import Node from \"../Node\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\n\n/**\n * A composite node that wraps child nodes.\n */\nexport default abstract class Composite extends Node {\n /**\n * @param type The node type.\n * @param attributes The node attributes.\n * @param children The child nodes.\n */\n constructor(type: string, attributes: Attribute[], protected children: Node[]) {\n super(type, attributes, []);\n }\n\n /**\n * Gets whether this node is a leaf node.\n */\n isLeafNode = () => false;\n\n /**\n * Gets the children of this node.\n */\n getChildren = () => this.children;\n\n /**\n * Reset the state of the node.\n */\n reset = () => {\n // Reset the state of this node.\n this.setState(State.READY);\n\n // Reset the state of any child nodes.\n this.getChildren().forEach((child) => child.reset());\n };\n\n /**\n * Abort the running of this node.\n * @param agent The agent.\n */\n abort = (agent: Agent) => {\n // There is nothing to do if this node is not in the running state.\n if (!this.is(State.RUNNING)) {\n return;\n }\n\n // Abort any child nodes.\n this.getChildren().forEach((child) => child.abort(agent));\n\n // Reset the state of this node.\n this.reset();\n\n this.getAttribute(\"exit\")?.callAgentFunction(agent, false, true);\n };\n}\n", "import Composite from \"./Composite\";\nimport Node from \"../Node\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A SELECTOR node.\n * The child nodes are executed in sequence until one succeeds or all fail.\n */\nexport default class Selector extends Composite {\n /**\n * @param attributes The node attributes.\n * @param children The child nodes.\n */\n constructor(attributes: Attribute[], protected children: Node[]) {\n super(\"selector\", attributes, children);\n }\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // Iterate over all of the children of this node.\n for (const child of this.children) {\n // If the child has never been updated or is running then we will need to update it now.\n if (child.getState() === State.READY || child.getState() === State.RUNNING) {\n // Update the child of this node.\n child.update(agent, options);\n }\n\n // If the current child has a state of 'SUCCEEDED' then this node is also a 'SUCCEEDED' node.\n if (child.getState() === State.SUCCEEDED) {\n // This node is a 'SUCCEEDED' node.\n this.setState(State.SUCCEEDED);\n\n // There is no need to check the rest of the selector nodes.\n return;\n }\n\n // If the current child has a state of 'FAILED' then we should move on to the next child.\n if (child.getState() === State.FAILED) {\n // Find out if the current child is the last one in the selector.\n // If it is then this sequence node has also failed.\n if (this.children.indexOf(child) === this.children.length - 1) {\n // This node is a 'FAILED' node.\n this.setState(State.FAILED);\n\n // There is no need to check the rest of the selector as we have completed it.\n return;\n } else {\n // The child node failed, try the next one.\n continue;\n }\n }\n\n // The node should be in the 'RUNNING' state.\n if (child.getState() === State.RUNNING) {\n // This node is a 'RUNNING' node.\n this.setState(State.RUNNING);\n\n // There is no need to check the rest of the selector as the current child is still running.\n return;\n }\n\n // The child node was not in an expected state.\n throw new Error(\"child node was not in an expected state.\");\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => \"SELECTOR\";\n}\n", "import Composite from \"./Composite\";\nimport Node from \"../Node\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A SEQUENCE node.\n * The child nodes are executed in sequence until one fails or all succeed.\n */\nexport default class Sequence extends Composite {\n /**\n * @param attributes The node attributes.\n * @param children The child nodes.\n */\n constructor(attributes: Attribute[], protected children: Node[]) {\n super(\"sequence\", attributes, children);\n }\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // Iterate over all of the children of this node.\n for (const child of this.children) {\n // If the child has never been updated or is running then we will need to update it now.\n if (child.getState() === State.READY || child.getState() === State.RUNNING) {\n // Update the child of this node.\n child.update(agent, options);\n }\n\n // If the current child has a state of 'SUCCEEDED' then we should move on to the next child.\n if (child.getState() === State.SUCCEEDED) {\n // Find out if the current child is the last one in the sequence.\n // If it is then this sequence node has also succeeded.\n if (this.children.indexOf(child) === this.children.length - 1) {\n // This node is a 'SUCCEEDED' node.\n this.setState(State.SUCCEEDED);\n\n // There is no need to check the rest of the sequence as we have completed it.\n return;\n } else {\n // The child node succeeded, but we have not finished the sequence yet.\n continue;\n }\n }\n\n // If the current child has a state of 'FAILED' then this node is also a 'FAILED' node.\n if (child.getState() === State.FAILED) {\n // This node is a 'FAILED' node.\n this.setState(State.FAILED);\n\n // There is no need to check the rest of the sequence.\n return;\n }\n\n // The node should be in the 'RUNNING' state.\n if (child.getState() === State.RUNNING) {\n // This node is a 'RUNNING' node.\n this.setState(State.RUNNING);\n\n // There is no need to check the rest of the sequence as the current child is still running.\n return;\n }\n\n // The child node was not in an expected state.\n throw new Error(\"child node was not in an expected state.\");\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => \"SEQUENCE\";\n}\n", "import Composite from \"./Composite\";\nimport State from \"../../State\";\nimport Node from \"../Node\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A PARALLEL node.\n * The child nodes are executed concurrently until one fails or all succeed.\n */\nexport default class Parallel extends Composite {\n /**\n * @param attributes The node attributes.\n * @param children The child nodes.\n */\n constructor(attributes: Attribute[], children: Node[]) {\n super(\"parallel\", attributes, children);\n }\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // Keep a count of the number of succeeded child nodes.\n let succeededCount = 0;\n\n let hasChildFailed = false;\n\n // Iterate over all of the children of this node.\n for (const child of this.children) {\n // If the child has never been updated or is running then we will need to update it now.\n if (child.getState() === State.READY || child.getState() === State.RUNNING) {\n // Update the child of this node.\n child.update(agent, options);\n }\n\n // If the current child has a state of 'SUCCEEDED' then we should move on to the next child.\n if (child.getState() === State.SUCCEEDED) {\n // The child node has succeeded, keep track of this to determine if all children have.\n succeededCount++;\n\n // The child node succeeded, but we have not finished checking every child node yet.\n continue;\n }\n\n // If the current child has a state of 'FAILED' then this node is also a 'FAILED' node.\n if (child.getState() === State.FAILED) {\n hasChildFailed = true;\n\n // There is no need to check the rest of the children.\n break;\n }\n\n // The node should be in the 'RUNNING' state.\n if (child.getState() !== State.RUNNING) {\n // The child node was not in an expected state.\n throw new Error(\"child node was not in an expected state.\");\n }\n }\n\n if (hasChildFailed) {\n // This node is a 'FAILED' node.\n this.setState(State.FAILED);\n\n // Abort every running child.\n for (const child of this.children) {\n if (child.getState() === State.RUNNING) {\n child.abort(agent);\n }\n }\n } else {\n // If all children have succeeded then this node has also succeeded, otherwise it is still running.\n this.setState(succeededCount === this.children.length ? State.SUCCEEDED : State.RUNNING);\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => \"PARALLEL\";\n}\n", "import { AnyArgument } from \"../RootAstNodesBuilder\";\nimport Guard from \"./guards/Guard\";\n\nexport type AttributeDetails = {\n /** The attribute type. */\n type: string;\n\n /** The attribute arguments. */\n args: AnyArgument[];\n};\n\n/**\n * A base node attribute.\n */\nexport default abstract class Attribute {\n /**\n * @param type The node attribute type.\n * @param args The array of attribute argument definitions.\n */\n constructor(protected type: string, protected args: AnyArgument[]) {}\n\n /**\n * Gets the type of the attribute.\n */\n getType = () => this.type;\n\n /**\n * Gets the array of attribute argument definitions.\n */\n getArguments = () => this.args;\n\n /**\n * Gets the attribute details.\n */\n abstract getDetails(): TAttributeDetails;\n\n /**\n * Gets whether this attribute is a guard.\n */\n abstract isGuard: () => this is Guard;\n}\n", "import { Agent } from \"../../Agent\";\nimport { AnyArgument } from \"../../RootAstNodesBuilder\";\nimport Attribute, { AttributeDetails } from \"../Attribute\";\n\nexport type GuardAttributeDetails = {\n /** The name of the condition function that determines whether the guard is satisfied. */\n condition: string;\n} & AttributeDetails;\n\n/**\n * A base node guard attribute.\n */\nexport default abstract class Guard extends Attribute {\n /**\n * @param type The node attribute type.\n * @param args The array of decorator argument definitions.\n * @param condition The name of the condition function that determines whether the guard is satisfied.\n */\n constructor(type: string, args: AnyArgument[], private condition: string) {\n super(type, args);\n }\n\n /**\n * Gets the name of the condition function that determines whether the guard is satisfied.\n */\n getCondition = () => this.condition;\n\n /**\n * Gets whether this attribute is a guard.\n */\n isGuard = () => true;\n\n /**\n * Gets the attribute details.\n */\n getDetails(): GuardAttributeDetails {\n return {\n type: this.getType(),\n args: this.getArguments(),\n condition: this.getCondition()\n };\n }\n\n /**\n * Gets whether the guard is satisfied.\n * @param agent The agent.\n * @returns Whether the guard is satisfied.\n */\n abstract isSatisfied(agent: Agent): boolean;\n}\n", "import Guard from \"./Guard\";\nimport Lookup from \"../../Lookup\";\nimport { Agent } from \"../../Agent\";\nimport { AnyArgument } from \"../../RootAstNodesBuilder\";\n\n/**\n * A WHILE guard which is satisfied as long as the given condition remains true.\n */\nexport default class While extends Guard {\n /**\n * @param condition The name of the condition function that determines whether the guard is satisfied.\n * @param args The array of decorator argument definitions.\n */\n constructor(condition: string, args: AnyArgument[]) {\n super(\"while\", args, condition);\n }\n\n /**\n * Gets whether the guard is satisfied.\n * @param agent The agent.\n * @returns Whether the guard is satisfied.\n */\n isSatisfied = (agent: Agent) => {\n // Attempt to get the invoker for the condition function.\n const conditionFuncInvoker = Lookup.getFuncInvoker(agent, this.getCondition());\n\n // The condition function should be defined.\n if (conditionFuncInvoker === null) {\n throw new Error(\n `cannot evaluate node guard as the condition '${this.getCondition()}' function is not defined on the agent and has not been registered`\n );\n }\n\n // Call the condition function to determine whether this guard is satisfied.\n return !!conditionFuncInvoker(this.args);\n };\n}\n", "import Guard from \"./Guard\";\nimport Lookup from \"../../Lookup\";\nimport { Agent } from \"../../Agent\";\nimport { AnyArgument } from \"../../RootAstNodesBuilder\";\n\n/**\n * An UNTIL guard which is satisfied as long as the given condition remains false.\n */\nexport default class Until extends Guard {\n /**\n * @param condition The name of the condition function that determines whether the guard is satisfied.\n * @param args The array of decorator argument definitions.\n */\n constructor(condition: string, args: AnyArgument[]) {\n super(\"until\", args, condition);\n }\n\n /**\n * Gets whether the guard is satisfied.\n * @param agent The agent.\n * @returns Whether the guard is satisfied.\n */\n isSatisfied = (agent: Agent) => {\n // Attempt to get the invoker for the condition function.\n const conditionFuncInvoker = Lookup.getFuncInvoker(agent, this.getCondition());\n\n // The condition function should be defined.\n if (conditionFuncInvoker === null) {\n throw new Error(\n `cannot evaluate node guard as the condition '${this.getCondition()}' function is not defined on the agent and has not been registered`\n );\n }\n\n // Call the condition function to determine whether this guard is satisfied.\n return !!!conditionFuncInvoker(this.args);\n };\n}\n", "import { Agent } from \"../../Agent\";\nimport { AnyArgument } from \"../../RootAstNodesBuilder\";\nimport Attribute, { AttributeDetails } from \"../Attribute\";\n\nexport type CallbackAttributeDetails = {\n /** The name of the agent function that is called. */\n functionName: string;\n} & AttributeDetails;\n\n/**\n * A base node callback attribute.\n */\nexport default abstract class Callback extends Attribute {\n /**\n * @param type The node attribute type.\n * @param args The array of decorator argument definitions.\n * @param functionName The name of the agent function to call.\n */\n constructor(type: string, args: AnyArgument[], private functionName: string) {\n super(type, args);\n }\n\n /**\n * Gets the name of the agent function to call.\n */\n getFunctionName = () => this.functionName;\n\n /**\n * Gets whether this attribute is a guard.\n */\n isGuard = () => false;\n\n /**\n * Gets the attribute details.\n */\n getDetails(): CallbackAttributeDetails {\n return {\n type: this.getType(),\n args: this.getArguments(),\n functionName: this.getFunctionName()\n };\n }\n\n /**\n * Attempt to call the agent function that this callback refers to.\n * @param agent The agent.\n */\n abstract callAgentFunction: (agent: Agent, isSuccess: boolean, isAborted: boolean) => void;\n}\n", "import Callback from \"./Callback\";\nimport Lookup from \"../../Lookup\";\nimport { Agent } from \"../../Agent\";\nimport { AnyArgument } from \"../../RootAstNodesBuilder\";\n\n/**\n * An ENTRY callback which defines an agent function to call when the associated node is updated and moves out of running state.\n */\nexport default class Entry extends Callback {\n /**\n * @param functionName The name of the agent function to call.\n * @param args The array of callback argument definitions.\n */\n constructor(functionName: string, args: AnyArgument[]) {\n super(\"entry\", args, functionName);\n }\n\n /**\n * Attempt to call the agent function that this callback refers to.\n * @param agent The agent.\n */\n callAgentFunction = (agent: Agent) => {\n // Attempt to get the invoker for the callback function.\n const callbackFuncInvoker = Lookup.getFuncInvoker(agent, this.getFunctionName());\n\n // The callback function should be defined.\n if (callbackFuncInvoker === null) {\n throw new Error(\n `cannot call entry function '${this.getFunctionName()}' as is not defined on the agent and has not been registered`\n );\n }\n\n // Call the callback function.\n callbackFuncInvoker(this.args);\n };\n}\n", "import Callback from \"./Callback\";\nimport Lookup, { AnyExitArgument } from \"../../Lookup\";\nimport { Agent } from \"../../Agent\";\nimport { AnyArgument } from \"../../RootAstNodesBuilder\";\n\n/**\n * An EXIT callback which defines an agent function to call when the associated node is updated and moves to a finished state or is aborted.\n */\nexport default class Exit extends Callback {\n /**\n * @param functionName The name of the agent function to call.\n * @param args The array of callback argument definitions.\n */\n constructor(functionName: string, args: AnyArgument[]) {\n super(\"exit\", args, functionName);\n }\n\n /**\n * Attempt to call the agent function that this callback refers to.\n * @param agent The agent.\n * @param isSuccess Whether the decorated node was left with a success state.\n * @param isAborted Whether the decorated node was aborted.\n */\n callAgentFunction = (agent: Agent, isSuccess: boolean, isAborted: boolean) => {\n // Attempt to get the invoker for the callback function.\n const callbackFuncInvoker = Lookup.getFuncInvoker(agent, this.getFunctionName());\n\n // The callback function should be defined.\n if (callbackFuncInvoker === null) {\n throw new Error(\n `cannot call exit function '${this.getFunctionName()}' as is not defined on the agent and has not been registered`\n );\n }\n\n // Call the callback function\n callbackFuncInvoker([{ value: { succeeded: isSuccess, aborted: isAborted } }, ...this.args]);\n };\n}\n", "import Callback from \"./Callback\";\nimport Lookup from \"../../Lookup\";\nimport { Agent } from \"../../Agent\";\nimport { AnyArgument } from \"../../RootAstNodesBuilder\";\n\n/**\n * A STEP callback which defines an agent function to call when the associated node is updated.\n */\nexport default class Step extends Callback {\n /**\n * @param functionName The name of the agent function to call.\n * @param args The array of callback argument definitions.\n */\n constructor(functionName: string, args: AnyArgument[]) {\n super(\"step\", args, functionName);\n }\n\n /**\n * Attempt to call the agent function that this callback refers to.\n * @param agent The agent.\n */\n callAgentFunction = (agent: Agent) => {\n // Attempt to get the invoker for the callback function.\n const callbackFuncInvoker = Lookup.getFuncInvoker(agent, this.getFunctionName());\n\n // The callback function should be defined.\n if (callbackFuncInvoker === null) {\n throw new Error(\n `cannot call step function '${this.getFunctionName()}' as is not defined on the agent and has not been registered`\n );\n }\n\n // Call the callback function.\n callbackFuncInvoker(this.args);\n };\n}\n", "import Action from \"./nodes/leaf/Action\";\nimport Condition from \"./nodes/leaf/Condition\";\nimport Wait from \"./nodes/leaf/Wait\";\nimport Root from \"./nodes/decorator/Root\";\nimport Repeat from \"./nodes/decorator/Repeat\";\nimport Retry from \"./nodes/decorator/Retry\";\nimport Flip from \"./nodes/decorator/Flip\";\nimport Succeed from \"./nodes/decorator/Succeed\";\nimport Fail from \"./nodes/decorator/Fail\";\nimport Lotto from \"./nodes/composite/Lotto\";\nimport Selector from \"./nodes/composite/Selector\";\nimport Sequence from \"./nodes/composite/Sequence\";\nimport Parallel from \"./nodes/composite/Parallel\";\nimport Node from \"./nodes/Node\";\nimport While from \"./attributes/guards/While\";\nimport Until from \"./attributes/guards/Until\";\nimport Entry from \"./attributes/callbacks/Entry\";\nimport Exit from \"./attributes/callbacks/Exit\";\nimport Step from \"./attributes/callbacks/Step\";\nimport Callback from \"./attributes/callbacks/Callback\";\nimport Guard from \"./attributes/guards/Guard\";\nimport Attribute from \"./attributes/Attribute\";\nimport Composite from \"./nodes/composite/Composite\";\nimport Decorator from \"./nodes/decorator/Decorator\";\nimport Leaf from \"./nodes/leaf/Leaf\";\n\nexport type Argument = {\n value: T;\n type: string; // Used for validation.\n};\ntype NullArgument = Argument & {\n type: \"null\";\n};\ntype BooleanArgument = Argument & {\n type: \"boolean\";\n};\ntype NumberArgument = Argument & {\n type: \"number\";\n isInteger: boolean; // Used for validation.\n};\ntype StringPlaceholderArgument = Argument & {\n type: \"string\";\n};\ntype IdentifierArgument = Argument & {\n type: \"identifier\";\n};\nexport type AnyArgument =\n | NullArgument\n | BooleanArgument\n | NumberArgument\n | StringPlaceholderArgument\n | IdentifierArgument;\n\n/**\n * The node attribute factories.\n */\nconst AttributeFactories: {\n [key: string]: (functionName: string, attributeArguments: AnyArgument[]) => Callback | Guard;\n} = {\n WHILE: (condition: string, attributeArguments: AnyArgument[]) => new While(condition, attributeArguments),\n UNTIL: (condition: string, attributeArguments: AnyArgument[]) => new Until(condition, attributeArguments),\n ENTRY: (functionName: string, attributeArguments: AnyArgument[]) => new Entry(functionName, attributeArguments),\n EXIT: (functionName: string, attributeArguments: AnyArgument[]) => new Exit(functionName, attributeArguments),\n STEP: (functionName: string, attributeArguments: AnyArgument[]) => new Step(functionName, attributeArguments)\n};\n\ntype Validatable = {\n children?: AstNode[];\n validate: (depth: number) => void;\n};\n\ntype NodeInstanceCreator = (\n namedRootNodeProvider: (name: string) => RootAstNode,\n visitedBranches: string[]\n) => T;\n\nexport type AstNode = Validatable & {\n type: string;\n createNodeInstance: NodeInstanceCreator;\n};\n\nexport type LeafAstNode = AstNode & {\n type: \"action\" | \"condition\" | \"wait\";\n attributes: Attribute[];\n};\n\nexport type CompositeAstNode = AstNode & {\n type: \"lotto\" | \"parallel\" | \"selector\" | \"sequence\";\n attributes: Attribute[];\n children: AstNode[];\n};\n\nexport type DecoratorAstNode = AstNode & {\n type: \"fail\" | \"flip\" | \"repeat\" | \"retry\" | \"root\" | \"succeed\";\n attributes: Attribute[];\n children: AstNode[];\n};\n\nexport type BranchAstNode = AstNode & {\n type: \"branch\";\n branchName: \"\" | string;\n};\n\nexport type LottoAstNode = CompositeAstNode & {\n type: \"lotto\";\n tickets: number[];\n};\n\nexport type RootAstNode = DecoratorAstNode & {\n type: \"root\";\n name: null | string;\n};\n\nexport type RepeatAstNode = DecoratorAstNode & {\n type: \"repeat\";\n iterations: number | null;\n iterationsMin: number | null;\n iterationsMax: number | null;\n};\n\nexport type RetryAstNode = DecoratorAstNode & {\n type: \"retry\";\n attempts: number | null;\n attemptsMin: number | null;\n attemptsMax: number | null;\n};\n\nexport type ActionAstNode = LeafAstNode & {\n type: \"action\";\n actionName: string;\n actionArguments: AnyArgument[];\n};\n\nexport type ConditionAstNode = LeafAstNode & {\n type: \"condition\";\n conditionName: string;\n conditionArguments: AnyArgument[];\n};\n\nexport type WaitAstNode = LeafAstNode & {\n type: \"wait\";\n duration: number | null;\n durationMin: number | null;\n durationMax: number | null;\n};\n\nexport type AnyAstNode =\n | BranchAstNode\n | CompositeAstNode\n | LottoAstNode\n | DecoratorAstNode\n | RootAstNode\n | RepeatAstNode\n | RetryAstNode\n | LeafAstNode\n | ActionAstNode\n | ConditionAstNode\n | WaitAstNode;\n\n/**\n * The AST node factories.\n */\nconst ASTNodeFactories = {\n ROOT: (): RootAstNode => ({\n type: \"root\",\n attributes: [],\n name: null,\n children: [],\n validate(depth: number) {\n // A root node cannot be the child of another node.\n if (depth > 1) {\n throw new Error(\"a root node cannot be the child of another node\");\n }\n\n // A root node must have a single child node.\n if (this.children.length !== 1) {\n throw new Error(\"a root node must have a single child\");\n }\n },\n createNodeInstance(namedRootNodeProvider, visitedBranches) {\n return new Root(\n this.attributes,\n this.children![0].createNodeInstance(namedRootNodeProvider, visitedBranches.slice())\n );\n }\n }),\n BRANCH: (): BranchAstNode => ({\n type: \"branch\",\n branchName: \"\",\n validate() {},\n createNodeInstance(namedRootNodeProvider, visitedBranches) {\n // Try to find the root node with a matching branch name.\n const targetRootNode = namedRootNodeProvider(this.branchName);\n\n // If we have already visited this branch then we have a circular dependency.\n if (visitedBranches.indexOf(this.branchName) !== -1) {\n throw new Error(`circular dependency found in branch node references for branch '${this.branchName}'`);\n }\n\n // If we have a target root node, then the node instance we want will be the first and only child of the referenced root node.\n if (targetRootNode) {\n return targetRootNode\n .createNodeInstance(namedRootNodeProvider, visitedBranches.concat(this.branchName))\n .getChildren()[0];\n } else {\n throw new Error(`branch references root node '${this.branchName}' which has not been defined`);\n }\n }\n }),\n SELECTOR: (): CompositeAstNode => ({\n type: \"selector\",\n attributes: [],\n children: [],\n validate() {\n // A selector node must have at least a single node.\n if (this.children.length < 1) {\n throw new Error(\"a selector node must have at least a single child\");\n }\n },\n createNodeInstance(namedRootNodeProvider, visitedBranches) {\n return new Selector(\n this.attributes,\n this.children.map((child) => child.createNodeInstance(namedRootNodeProvider, visitedBranches.slice()))\n );\n }\n }),\n SEQUENCE: (): CompositeAstNode => ({\n type: \"sequence\",\n attributes: [],\n children: [],\n validate() {\n // A sequence node must have at least a single node.\n if (this.children.length < 1) {\n throw new Error(\"a sequence node must have at least a single child\");\n }\n },\n createNodeInstance(namedRootNodeProvider, visitedBranches) {\n return new Sequence(\n this.attributes,\n this.children.map((child) => child.createNodeInstance(namedRootNodeProvider, visitedBranches.slice()))\n );\n }\n }),\n PARALLEL: (): CompositeAstNode => ({\n type: \"parallel\",\n attributes: [],\n children: [],\n validate() {\n // A parallel node must have at least a single node.\n if (this.children.length < 1) {\n throw new Error(\"a parallel node must have at least a single child\");\n }\n },\n createNodeInstance(namedRootNodeProvider, visitedBranches) {\n return new Parallel(\n this.attributes,\n this.children.map((child) => child.createNodeInstance(namedRootNodeProvider, visitedBranches.slice()))\n );\n }\n }),\n LOTTO: (): LottoAstNode => ({\n type: \"lotto\",\n attributes: [],\n children: [],\n tickets: [],\n validate() {\n // A lotto node must have at least a single node.\n if (this.children!.length < 1) {\n throw new Error(\"a lotto node must have at least a single child\");\n }\n },\n createNodeInstance(namedRootNodeProvider, visitedBranches) {\n return new Lotto(\n this.attributes,\n this.tickets!,\n this.children!.map((child) => child.createNodeInstance(namedRootNodeProvider, visitedBranches.slice()))\n );\n }\n }),\n REPEAT: (): RepeatAstNode => ({\n type: \"repeat\",\n attributes: [],\n iterations: null,\n iterationsMin: null,\n iterationsMax: null,\n children: [],\n validate() {\n // A repeat node must have a single node.\n if (this.children!.length !== 1) {\n throw new Error(\"a repeat node must have a single child\");\n }\n\n if (this.iterations !== null) {\n // A repeat node must have a positive number of iterations if defined.\n if (this.iterations < 0) {\n throw new Error(\"a repeat node must have a positive number of iterations if defined\");\n }\n } else if (this.iterationsMin !== null && this.iterationsMax !== null) {\n // A repeat node must have a positive min and max iteration count if they are defined.\n if (this.iterationsMin < 0 || this.iterationsMax < 0) {\n throw new Error(\n \"a repeat node must have a positive minimum and maximum iteration count if defined\"\n );\n }\n\n // A repeat node must not have an minimum iteration count that exceeds the maximum iteration count.\n if (this.iterationsMin > this.iterationsMax) {\n throw new Error(\n \"a repeat node must not have a minimum iteration count that exceeds the maximum iteration count\"\n );\n }\n } else {\n // If we have no explicit iteration count or a minimum and maximum iteration count set then we are dealing with a repeat node that iterates indefinitely.\n }\n },\n createNodeInstance(namedRootNodeProvider, visitedBranches) {\n return new Repeat(\n this.attributes,\n this.iterations,\n this.iterationsMin,\n this.iterationsMax,\n this.children![0].createNodeInstance(namedRootNodeProvider, visitedBranches.slice())\n );\n }\n }),\n RETRY: (): RetryAstNode => ({\n type: \"retry\",\n attributes: [],\n attempts: null,\n attemptsMin: null,\n attemptsMax: null,\n children: [],\n validate() {\n // A retry node must have a single node.\n if (this.children!.length !== 1) {\n throw new Error(\"a retry node must have a single child\");\n }\n\n if (this.attempts !== null) {\n // A retry node must have a positive number of attempts if defined.\n if (this.attempts < 0) {\n throw new Error(\"a retry node must have a positive number of attempts if defined\");\n }\n } else if (this.attemptsMin !== null && this.attemptsMax !== null) {\n // A retry node must have a positive min and max attempts count if they are defined.\n if (this.attemptsMin < 0 || this.attemptsMax < 0) {\n throw new Error(\"a retry node must have a positive minimum and maximum attempt count if defined\");\n }\n\n // A retry node must not have a minimum attempt count that exceeds the maximum attempt count.\n if (this.attemptsMin > this.attemptsMax) {\n throw new Error(\n \"a retry node must not have a minimum attempt count that exceeds the maximum attempt count\"\n );\n }\n } else {\n // If we have no explicit attempt count or a minimum and maximum attempt count set then we are dealing with a retry node that attempts indefinitely.\n }\n },\n createNodeInstance(namedRootNodeProvider, visitedBranches) {\n return new Retry(\n this.attributes,\n this.attempts,\n this.attemptsMin,\n this.attemptsMax,\n this.children![0].createNodeInstance(namedRootNodeProvider, visitedBranches.slice())\n );\n }\n }),\n FLIP: (): DecoratorAstNode => ({\n type: \"flip\",\n attributes: [],\n children: [],\n validate() {\n // A flip node must have a single node.\n if (this.children!.length !== 1) {\n throw new Error(\"a flip node must have a single child\");\n }\n },\n createNodeInstance(namedRootNodeProvider, visitedBranches) {\n return new Flip(\n this.attributes,\n this.children![0].createNodeInstance(namedRootNodeProvider, visitedBranches.slice())\n );\n }\n }),\n SUCCEED: (): DecoratorAstNode => ({\n type: \"succeed\",\n attributes: [],\n children: [],\n validate() {\n // A succeed node must have a single node.\n if (this.children!.length !== 1) {\n throw new Error(\"a succeed node must have a single child\");\n }\n },\n createNodeInstance(namedRootNodeProvider, visitedBranches) {\n return new Succeed(\n this.attributes,\n this.children![0].createNodeInstance(namedRootNodeProvider, visitedBranches.slice())\n );\n }\n }),\n FAIL: (): DecoratorAstNode => ({\n type: \"fail\",\n attributes: [],\n children: [],\n validate() {\n // A fail node must have a single node.\n if (this.children!.length !== 1) {\n throw new Error(\"a fail node must have a single child\");\n }\n },\n createNodeInstance(namedRootNodeProvider, visitedBranches) {\n return new Fail(\n this.attributes,\n this.children![0].createNodeInstance(namedRootNodeProvider, visitedBranches.slice())\n );\n }\n }),\n WAIT: (): WaitAstNode => ({\n type: \"wait\",\n attributes: [],\n duration: null,\n durationMin: null,\n durationMax: null,\n validate() {\n if (this.duration !== null) {\n // If an explict duration was defined then it must be a positive number.\n if (this.duration < 0) {\n throw new Error(\"a wait node must have a positive duration\");\n }\n } else if (this.durationMin !== null && this.durationMax !== null) {\n // A wait node must have a positive min and max duration.\n if (this.durationMin < 0 || this.durationMax < 0) {\n throw new Error(\"a wait node must have a positive minimum and maximum duration\");\n }\n\n // A wait node must not have a minimum duration that exceeds the maximum duration.\n if (this.durationMin > this.durationMax) {\n throw new Error(\"a wait node must not have a minimum duration that exceeds the maximum duration\");\n }\n } else {\n // If we have no explicit duration or duration bounds set then we are dealing with a wait node that waits indefinitely.\n }\n },\n createNodeInstance() {\n return new Wait(this.attributes, this.duration, this.durationMin, this.durationMax);\n }\n }),\n ACTION: (): ActionAstNode => ({\n type: \"action\",\n attributes: [],\n actionName: \"\",\n actionArguments: [],\n validate() {},\n createNodeInstance() {\n return new Action(this.attributes, this.actionName!, this.actionArguments!);\n }\n }),\n CONDITION: (): ConditionAstNode => ({\n type: \"condition\",\n attributes: [],\n conditionName: \"\",\n conditionArguments: [],\n validate() {},\n createNodeInstance() {\n return new Condition(this.attributes, this.conditionName!, this.conditionArguments!);\n }\n })\n};\n\ntype OtherAstNodes = AstNode[];\n\n/**\n * Create an array of root AST nodes based on the given definition.\n * @param definition The definition to parse the AST nodes from.\n * @returns The base definition AST nodes.\n */\nexport default function buildRootASTNodes(definition: string): RootAstNode[] {\n // Swap out any node/attribute argument string literals with a placeholder and get a mapping of placeholders to original values as well as the processed definition.\n const { placeholders, processedDefinition } = substituteStringLiterals(definition);\n\n // Convert the processed definition (with substituted string literals) into an array of raw tokens.\n const tokens = parseTokensFromDefinition(processedDefinition);\n\n // There must be at least 3 tokens for the tree definition to be valid. 'ROOT', '{' and '}'.\n if (tokens.length < 3) {\n throw new Error(\"invalid token count\");\n }\n\n // We should have a matching number of '{' and '}' tokens. If not, then there are scopes that have not been properly closed.\n if (tokens.filter((token) => token === \"{\").length !== tokens.filter((token) => token === \"}\").length) {\n throw new Error(\"scope character mismatch\");\n }\n\n // Create a stack of node children arrays, starting with a definition scope.\n const stack: [RootAstNode[], ...OtherAstNodes[]] = [[]];\n const rootScope = stack[0];\n\n // We should keep processing the raw tokens until we run out of them.\n while (tokens.length) {\n // Grab the next token.\n const token = tokens.shift();\n\n const currentScope = stack[stack.length - 1] as OtherAstNodes;\n\n // How we create the next AST token depends on the current raw token value.\n switch (token!.toUpperCase()) {\n case \"ROOT\": {\n // Create a ROOT AST node.\n const node = ASTNodeFactories.ROOT();\n\n // Push the ROOT node into the current scope.\n rootScope.push(node);\n\n // We may have a root node name defined as an argument.\n if (tokens[0] === \"[\") {\n const rootArguments = getArguments(tokens, placeholders);\n\n // We should have only a single argument that is not an empty string for a root node, which is the root name identifier.\n if (rootArguments.length === 1 && rootArguments[0].type === \"identifier\") {\n // The root name will be the first and only node argument.\n node.name = rootArguments[0].value as string;\n } else {\n throw new Error(\"expected single root name argument\");\n }\n }\n\n // Try to pick any attributes off of the token stack.\n node.attributes = getAttributes(tokens, placeholders);\n\n popAndCheck(tokens, \"{\");\n\n // The new scope is that of the new ROOT nodes children.\n stack.push(node.children!);\n break;\n }\n\n case \"BRANCH\": {\n // Create a BRANCH AST node.\n const node = ASTNodeFactories.BRANCH();\n\n // Push the BRANCH node into the current scope.\n currentScope.push(node);\n\n // We must have arguments defined, as we require a branch name argument.\n if (tokens[0] !== \"[\") {\n throw new Error(\"expected single branch name argument\");\n }\n\n // The branch name will be defined as a node argument.\n const branchArguments = getArguments(tokens, placeholders);\n\n // We should have only a single identifer argument for a branch node, which is the branch name.\n if (branchArguments.length === 1 && branchArguments[0].type === \"identifier\") {\n // The branch name will be the first and only node argument.\n node.branchName = branchArguments[0].value as string;\n } else {\n throw new Error(\"expected single branch name argument\");\n }\n break;\n }\n\n case \"SELECTOR\": {\n // Create a SELECTOR AST node.\n const node = ASTNodeFactories.SELECTOR();\n\n // Push the SELECTOR node into the current scope.\n currentScope.push(node);\n\n // Try to pick any attributes off of the token stack.\n node.attributes = getAttributes(tokens, placeholders);\n\n popAndCheck(tokens, \"{\");\n\n // The new scope is that of the new SELECTOR nodes children.\n stack.push(node.children!);\n break;\n }\n\n case \"SEQUENCE\": {\n // Create a SEQUENCE AST node.\n const node = ASTNodeFactories.SEQUENCE();\n\n // Push the SEQUENCE node into the current scope.\n currentScope.push(node);\n\n // Try to pick any attributes off of the token stack.\n node.attributes = getAttributes(tokens, placeholders);\n\n popAndCheck(tokens, \"{\");\n\n // The new scope is that of the new SEQUENCE nodes children.\n stack.push(node.children!);\n break;\n }\n\n case \"PARALLEL\": {\n // Create a PARALLEL AST node.\n const node = ASTNodeFactories.PARALLEL();\n\n // Push the PARALLEL node into the current scope.\n currentScope.push(node);\n\n // Try to pick any attributes off of the token stack.\n node.attributes = getAttributes(tokens, placeholders);\n\n popAndCheck(tokens, \"{\");\n\n // The new scope is that of the new PARALLEL nodes children.\n stack.push(node.children!);\n break;\n }\n\n case \"LOTTO\": {\n // Create a LOTTO AST node.\n const node = ASTNodeFactories.LOTTO();\n\n // Push the LOTTO node into the current scope.\n currentScope.push(node);\n\n // If the next token is a '[' character then some ticket counts have been defined as arguments.\n if (tokens[0] === \"[\") {\n // Get the ticket count arguments, each argument must be a number.\n node.tickets = getArguments(\n tokens,\n placeholders,\n (arg) => arg.type === \"number\" && !!arg.isInteger,\n \"lotto node ticket counts must be integer values\"\n ).map((argument) => argument.value as number);\n }\n\n // Try to pick any attributes off of the token stack.\n node.attributes = getAttributes(tokens, placeholders);\n\n popAndCheck(tokens, \"{\");\n\n // The new scope is that of the new LOTTO nodes children.\n stack.push(node.children!);\n break;\n }\n\n case \"CONDITION\": {\n // Create a CONDITION AST node.\n const node = ASTNodeFactories.CONDITION();\n\n // Push the CONDITION node into the current scope.\n currentScope.push(node);\n\n // We must have arguments defined, as we require a condition function name argument.\n if (tokens[0] !== \"[\") {\n throw new Error(\"expected condition name identifier argument\");\n }\n\n // Grab the condition node arguments.\n const conditionArguments = getArguments(tokens, placeholders);\n\n // We should have at least a single identifier argument for a condition node, which is the condition function name.\n if (conditionArguments.length && conditionArguments[0].type === \"identifier\") {\n // The condition function name will be the first node argument.\n node.conditionName = conditionArguments.shift()!.value as string;\n } else {\n throw new Error(\"expected condition name identifier argument\");\n }\n\n // Only the first argument should have been an identifier, all following arguments must be string, number, boolean or null.\n conditionArguments\n .filter((arg) => arg.type === \"identifier\")\n .forEach((arg) => {\n throw new Error(\n \"invalid condition node argument value '\" +\n arg.value +\n \"', must be string, number, boolean or null\"\n );\n });\n\n // Any node arguments that follow the condition name identifier will be treated as condition function arguments.\n node.conditionArguments = conditionArguments;\n\n // Try to pick any attributes off of the token stack.\n node.attributes = getAttributes(tokens, placeholders);\n break;\n }\n\n case \"FLIP\": {\n // Create a FLIP AST node.\n const node = ASTNodeFactories.FLIP();\n\n // Push the Flip node into the current scope.\n currentScope.push(node);\n\n // Try to pick any attributes off of the token stack.\n node.attributes = getAttributes(tokens, placeholders);\n\n popAndCheck(tokens, \"{\");\n\n // The new scope is that of the new FLIP nodes children.\n stack.push(node.children!);\n break;\n }\n\n case \"SUCCEED\": {\n // Create a SUCCEED AST node.\n const node = ASTNodeFactories.SUCCEED();\n\n // Push the Succeed node into the current scope.\n currentScope.push(node);\n\n // Try to pick any attributes off of the token stack.\n node.attributes = getAttributes(tokens, placeholders);\n\n popAndCheck(tokens, \"{\");\n\n // The new scope is that of the new Succeed nodes children.\n stack.push(node.children!);\n break;\n }\n\n case \"FAIL\": {\n // Create a FAIL AST node.\n const node = ASTNodeFactories.FAIL();\n\n // Push the Fail node into the current scope.\n currentScope.push(node);\n\n // Try to pick any attributes off of the token stack.\n node.attributes = getAttributes(tokens, placeholders);\n\n popAndCheck(tokens, \"{\");\n\n // The new scope is that of the new Fail nodes children.\n stack.push(node.children!);\n break;\n }\n\n case \"WAIT\": {\n // Create a WAIT AST node.\n const node = ASTNodeFactories.WAIT();\n\n // Push the WAIT node into the current scope.\n currentScope.push(node);\n\n // The arguments of a wait node are optional. We may have:\n // - No node arguments, in which case the wait will be indefinite until it is aborted.\n // - One node argument which will be the explicit duration of the wait.\n // - Two node arguments which define the min and max duration bounds from which a random duration will be picked.\n if (tokens[0] === \"[\") {\n // Get the optional duration and longest duration of the wait.\n const nodeArguments = getArguments(\n tokens,\n placeholders,\n (arg) => arg.type === \"number\" && !!arg.isInteger,\n \"wait node durations must be integer values\"\n ).map((argument) => argument.value);\n\n // We may have:\n // - One node argument which will be the explicit duration of the wait.\n // - Two node arguments which define the min and max duration bounds from which a random duration will be picked.\n // - Too many arguments, which is not valid.\n if (nodeArguments.length === 1) {\n // An explicit duration was defined.\n node.duration = nodeArguments[0] as number;\n } else if (nodeArguments.length === 2) {\n // Min and max duration bounds were defined from which a random duration will be picked.\n node.durationMin = nodeArguments[0] as number;\n node.durationMax = nodeArguments[1] as number;\n } else if (nodeArguments.length > 2) {\n // An incorrect number of durations was defined.\n throw new Error(\"invalid number of wait node duration arguments defined\");\n }\n }\n\n // Try to pick any attributes off of the token stack.\n node.attributes = getAttributes(tokens, placeholders);\n break;\n }\n\n case \"REPEAT\": {\n // Create a REPEAT AST node.\n const node = ASTNodeFactories.REPEAT();\n\n // Push the REPEAT node into the current scope.\n currentScope.push(node);\n\n // The arguments of a repeat node are optional. We may have:\n // - No node arguments, in which case the repeat note will iterate indefinitely.\n // - One node argument which will be the explicit number of iterations to make.\n // - Two node arguments which define the min and max iteration bounds from which a random iteration count will be picked.\n if (tokens[0] === \"[\") {\n // An iteration count has been defined. Get the iteration and potential maximum iteration of the wait.\n const nodeArguments = getArguments(\n tokens,\n placeholders,\n (arg) => arg.type === \"number\" && !!arg.isInteger,\n \"repeat node iteration counts must be integer values\"\n ).map((argument) => argument.value);\n\n // We should have got one or two iteration counts.\n if (nodeArguments.length === 1) {\n // A static iteration count was defined.\n node.iterations = nodeArguments[0] as number;\n } else if (nodeArguments.length === 2) {\n // A minimum and maximum iteration count was defined.\n node.iterationsMin = nodeArguments[0] as number;\n node.iterationsMax = nodeArguments[1] as number;\n } else {\n // An incorrect number of iteration counts was defined.\n throw new Error(\"invalid number of repeat node iteration count arguments defined\");\n }\n }\n\n // Try to pick any attributes off of the token stack.\n node.attributes = getAttributes(tokens, placeholders);\n\n popAndCheck(tokens, \"{\");\n\n // The new scope is that of the new REPEAT nodes children.\n stack.push(node.children!);\n break;\n }\n\n case \"RETRY\": {\n // Create a RETRY AST node.\n const node = ASTNodeFactories.RETRY();\n\n // Push the RETRY node into the current scope.\n currentScope.push(node);\n\n // The arguments of a retry node are optional. We may have:\n // - No node arguments, in which case the retry note will attempt indefinitely.\n // - One node argument which will be the explicit number of attempts to make.\n // - Two node arguments which define the min and max attempt bounds from which a random attempt count will be picked.\n if (tokens[0] === \"[\") {\n // An attempt count has been defined. Get the attempt count and potential maximum attempt count of the wait.\n const nodeArguments = getArguments(\n tokens,\n placeholders,\n (arg) => arg.type === \"number\" && !!arg.isInteger,\n \"retry node attempt counts must be integer values\"\n ).map((argument) => argument.value);\n\n // We should have got one or two attempt counts.\n if (nodeArguments.length === 1) {\n // A static attempt count was defined.\n node.attempts = nodeArguments[0] as number;\n } else if (nodeArguments.length === 2) {\n // A minimum and maximum attempt count was defined.\n node.attemptsMin = nodeArguments[0] as number;\n node.attemptsMax = nodeArguments[1] as number;\n } else {\n // An incorrect number of attempt counts was defined.\n throw new Error(\"invalid number of retry node attempt count arguments defined\");\n }\n }\n\n // Try to pick any attributes off of the token stack.\n node.attributes = getAttributes(tokens, placeholders);\n\n popAndCheck(tokens, \"{\");\n\n // The new scope is that of the new RETRY nodes children.\n stack.push(node.children!);\n break;\n }\n\n case \"ACTION\": {\n // Create a ACTION AST node.\n const node = ASTNodeFactories.ACTION();\n\n // Push the ACTION node into the current scope.\n currentScope.push(node);\n\n // We must have arguments defined, as we require an action name argument.\n if (tokens[0] !== \"[\") {\n throw new Error(\"expected action name identifier argument\");\n }\n\n // The action name will be defined as a node argument.\n const actionArguments = getArguments(tokens, placeholders);\n\n // We should have at least one identifer argument for an action node, which is the action name.\n if (actionArguments.length && actionArguments[0].type === \"identifier\") {\n // The action name will be the first and only node argument.\n node.actionName = actionArguments.shift()!.value as string;\n } else {\n throw new Error(\"expected action name identifier argument\");\n }\n\n // Only the first argument should have been an identifier, all following arguments must be string, number, boolean or null.\n actionArguments\n .filter((arg) => arg.type === \"identifier\")\n .forEach((arg) => {\n throw new Error(\n \"invalid action node argument value '\" +\n arg.value +\n \"', must be string, number, boolean or null\"\n );\n });\n\n // Any node arguments that follow the action name identifier will be treated as action function arguments.\n node.actionArguments = actionArguments;\n\n // Try to pick any attributes off of the token stack.\n node.attributes = getAttributes(tokens, placeholders);\n break;\n }\n\n case \"}\": {\n // The '}' character closes the current scope.\n stack.pop();\n break;\n }\n\n default: {\n throw new Error(`unexpected token '${token}'`);\n }\n }\n }\n\n // A function to recursively validate each of the nodes in the AST.\n const validateASTNode = (node: Validatable, depth: number): void => {\n // Validate the node.\n node.validate(depth);\n\n // Validate each child of the node.\n (node.children || []).forEach((child) => validateASTNode(child, depth + 1));\n };\n\n // Start node validation from the definition root.\n validateASTNode(\n {\n children: stack[0] as RootAstNode[],\n validate(this: { children: RootAstNode[] }) {\n // We must have at least one node defined as the definition scope, which should be a root node.\n if (this.children.length === 0) {\n throw new Error(\"expected root node to have been defined\");\n }\n\n // Each node at the base of the definition scope MUST be a root node.\n for (const definitionLevelNode of this.children) {\n if (definitionLevelNode.type !== \"root\") {\n throw new Error(\"expected root node at base of definition\");\n }\n }\n\n // Exactly one root node must not have a name defined. This will be the main root, others will have to be referenced via branch nodes.\n if (this.children.filter((definitionLevelNode) => definitionLevelNode.name === null).length !== 1) {\n throw new Error(\"expected single unnamed root node at base of definition to act as main root\");\n }\n\n // No two named root nodes can have matching names.\n const rootNodeNames: string[] = [];\n for (const definitionLevelNode of this.children) {\n if (rootNodeNames.indexOf(definitionLevelNode.name!) !== -1) {\n throw new Error(`multiple root nodes found with duplicate name '${definitionLevelNode.name}'`);\n } else {\n rootNodeNames.push(definitionLevelNode.name!);\n }\n }\n }\n },\n 0\n );\n\n // Return the root AST nodes.\n return stack[0];\n}\n\n/**\n * Pop the next raw token off of the stack and throw an error if it wasn't the expected one.\n * @param tokens The array of remaining tokens.\n * @param expected An optional string or array or items, one of which must match the next popped token.\n * @returns The popped token.\n */\nfunction popAndCheck(tokens: string[], expected: string | string[]) {\n // Get and remove the next token.\n const popped = tokens.shift();\n\n // We were expecting another token.\n if (popped === undefined) {\n throw new Error(\"unexpected end of definition\");\n }\n\n // Do we have an expected token/tokens array?\n if (expected !== undefined) {\n // Check whether the popped token matches at least one of our expected items.\n var tokenMatchesExpectation = ([] as string[])\n .concat(expected)\n .some((item) => popped.toUpperCase() === item.toUpperCase());\n\n // Throw an error if the popped token didn't match any of our expected items.\n if (!tokenMatchesExpectation) {\n const expectationString = ([] as string[])\n .concat(expected)\n .map((item) => \"'\" + item + \"'\")\n .join(\" or \");\n\n throw new Error(`unexpected token found. Expected '${expectationString}' but got '${popped}'`);\n }\n }\n\n // Return the popped token.\n return popped;\n}\n\ntype StringPlaceholders = { [key: string]: string };\n\n/**\n * Pull an argument definition list off of the token stack.\n * @param tokens The array of remaining tokens.\n * @param stringArgumentPlaceholders The mapping of string literal node argument placeholders to original values.\n * @param argumentValidator The argument validator function.\n * @param validationFailedMessage The exception message to throw if argument validation fails.\n * @returns The argument definition list.\n */\nfunction getArguments(\n tokens: string[],\n stringArgumentPlaceholders: StringPlaceholders,\n argumentValidator?: (arg: AnyArgument) => boolean,\n validationFailedMessage?: string\n) {\n // Any lists of arguments will always be wrapped in '[]' for node arguments or '()' for attribute arguments.\n // We are looking for a '[' or '(' opener that wraps the argument tokens and the relevant closer.\n const closer = popAndCheck(tokens, [\"[\", \"(\"]) === \"[\" ? \"]\" : \")\";\n\n const argumentListTokens: string[] = [];\n const argumentList: AnyArgument[] = [];\n\n // Grab all tokens between the '[' and ']' or '(' and ')'.\n while (tokens.length && tokens[0] !== closer) {\n // The next token is part of our arguments list.\n argumentListTokens.push(tokens.shift()!);\n }\n\n // Validate the order of the argument tokens. Each token must either be a ',' or a single argument that satisfies the validator.\n argumentListTokens.forEach((token, index) => {\n // Get whether this token should be an actual argument.\n const shouldBeArgumentToken = !(index & 1);\n\n // If the current token should be an actual argument then validate it,otherwise it should be a ',' token.\n if (shouldBeArgumentToken) {\n // Get the argument definition.\n const argumentDefinition = getArgumentDefinition(token!, stringArgumentPlaceholders);\n\n // Try to validate the argument.\n if (argumentValidator && !argumentValidator(argumentDefinition)) {\n throw new Error(validationFailedMessage);\n }\n\n // This is a valid argument!\n argumentList.push(argumentDefinition);\n } else {\n // The current token should be a ',' token.\n if (token !== \",\") {\n throw new Error(`invalid argument list, expected ',' or ']' but got '${token}'`);\n }\n }\n });\n\n // The arguments list should terminate with a ']' or ')' token, depending on the opener.\n popAndCheck(tokens, closer);\n\n // Return the argument list.\n return argumentList;\n}\n\n/**\n * Gets an argument value definition.\n * @param token The argument token.\n * @param stringArgumentPlaceholders The mapping of string literal node argument placeholders to original values.\n * @returns An argument value definition.\n */\nfunction getArgumentDefinition(token: string, stringArgumentPlaceholders: StringPlaceholders): AnyArgument {\n // Check whether the token represents a null value.\n if (token === \"null\") {\n return {\n value: null,\n type: \"null\"\n } as NullArgument;\n }\n\n // Check whether the token represents a boolean value.\n if (token === \"true\" || token === \"false\") {\n return {\n value: token === \"true\",\n type: \"boolean\"\n } as BooleanArgument;\n }\n\n // Check whether the token represents a number value.\n // TODO: Relies on broken isNaN - see MDN.\n // if (!Number.isNaN(token)) {\n if (!isNaN(token as any)) {\n return {\n value: parseFloat(token),\n isInteger: parseFloat(token) === parseInt(token, 10),\n type: \"number\"\n } as NumberArgument;\n }\n\n // Check whether the token is a placeholder (e.g. @@0@@) representing a string literal.\n if (token.match(/^@@\\d+@@$/g)) {\n return {\n value: stringArgumentPlaceholders[token].replace('\\\\\"', '\"'),\n type: \"string\"\n } as StringPlaceholderArgument;\n }\n\n // The only remaining option is that the argument value is an identifier.\n return {\n value: token,\n type: \"identifier\"\n } as IdentifierArgument;\n}\n\n/**\n * Pull any attributes off of the token stack.\n * @param tokens The array of remaining tokens.\n * @param stringArgumentPlaceholders The mapping of string literal node argument placeholders to original values.\n * @returns An array of attributes defined by any directly following tokens.\n */\nfunction getAttributes(tokens: string[], stringArgumentPlaceholders: StringPlaceholders) {\n // Create an array to hold any attributes found.\n const attributes: Attribute[] = [];\n\n // Keep track of names of attribute that we have found on the token stack, as we cannot have duplicates.\n const attributesFound: string[] = [];\n\n // Try to get the attribute factory for the next token.\n let attributeFactory = AttributeFactories[(tokens[0] || \"\").toUpperCase()];\n\n // Pull attribute tokens off of the tokens stack until we have no more.\n while (attributeFactory) {\n // Check to make sure that we have not already created a attribute of this type for this node.\n if (attributesFound.indexOf(tokens[0].toUpperCase()) !== -1) {\n throw new Error(`duplicate attribute '${tokens[0].toUpperCase()}' found for node`);\n }\n\n // Add the current attribute type to our array of found attributes.\n attributesFound.push(tokens.shift()!.toUpperCase());\n\n // Grab any attribute arguments.\n const attributeArguments = getArguments(tokens, stringArgumentPlaceholders);\n\n // The first attribute argument has to be an identifer, this will reference an agent function.\n if (attributeArguments.length === 0 || attributeArguments[0].type !== \"identifier\") {\n throw new Error(\"expected agent function name identifier argument for attribute\");\n }\n\n // Grab the first attribute which is an identifier that will reference an agent function.\n const attributeFunctionName = attributeArguments.shift()! as IdentifierArgument;\n\n // Any remaining attribute arguments must have a type of string, number, boolean or null.\n attributeArguments\n .filter((arg) => arg.type === \"identifier\")\n .forEach((arg) => {\n throw new Error(\n \"invalid attribute argument value '\" + arg.value + \"', must be string, number, boolean or null\"\n );\n });\n\n // Create the attribute and add it to the array of attributes found.\n attributes.push(attributeFactory(attributeFunctionName.value, attributeArguments));\n\n // Try to get the next attribute name token, as there could be multiple.\n attributeFactory = AttributeFactories[(tokens[0] || \"\").toUpperCase()];\n }\n\n return attributes;\n}\n\n/**\n * Swaps out any node/attribute argument string literals with placeholders.\n * @param definition The definition.\n * @returns An object containing a mapping of placeholders to original string values as well as the processed definition string.\n */\nfunction substituteStringLiterals(definition: string): {\n placeholders: { [key: string]: string };\n processedDefinition: string;\n} {\n // Create an object to hold the mapping of placeholders to original string values.\n const placeholders: StringPlaceholders = {};\n\n // Replace any string literals wrapped with double quotes in our definition with placeholders to be processed later.\n const processedDefinition = definition.replace(/\\\"(\\\\.|[^\"\\\\])*\\\"/g, (match) => {\n var strippedMatch = match.substring(1, match.length - 1);\n var placeholder = Object.keys(placeholders).find((key) => placeholders[key] === strippedMatch);\n\n // If we have no existing string literal match then create a new placeholder.\n if (!placeholder) {\n placeholder = `@@${Object.keys(placeholders).length}@@`;\n placeholders[placeholder] = strippedMatch;\n }\n\n return placeholder;\n });\n\n return { placeholders, processedDefinition };\n}\n\n/**\n * Parse the tree definition into an array of raw tokens.\n * @param definition The definition.\n * @returns An array of tokens parsed from the definition.\n */\nfunction parseTokensFromDefinition(definition: string): string[] {\n // Add some space around various important characters so that they can be plucked out easier as individual tokens.\n definition = definition.replace(/\\(/g, \" ( \");\n definition = definition.replace(/\\)/g, \" ) \");\n definition = definition.replace(/\\{/g, \" { \");\n definition = definition.replace(/\\}/g, \" } \");\n definition = definition.replace(/\\]/g, \" ] \");\n definition = definition.replace(/\\[/g, \" [ \");\n definition = definition.replace(/\\,/g, \" , \");\n\n // Split the definition into raw token form and return it.\n return definition.replace(/\\s+/g, \" \").trim().split(\" \");\n}\n", "import GuardPath, { GuardPathPart } from \"./attributes/guards/GuardPath\";\nimport buildRootASTNodes, { AnyArgument, RootAstNode } from \"./RootAstNodesBuilder\";\nimport State, { AnyState } from \"./State\";\nimport Lookup from \"./Lookup\";\nimport Node from \"./nodes/Node\";\nimport Root from \"./nodes/decorator/Root\";\nimport Composite from \"./nodes/composite/Composite\";\nimport Decorator from \"./nodes/decorator/Decorator\";\nimport { Agent, GlobalFunction } from \"./Agent\";\nimport { CallbackAttributeDetails } from \"./attributes/callbacks/Callback\";\nimport { GuardAttributeDetails } from \"./attributes/guards/Guard\";\nimport { BehaviourTreeOptions } from \"./BehaviourTreeOptions\";\nimport { convertMDSLToJSON } from \"./mdsl/MDSLDefinitionParser\";\n\n// Purely for outside inspection of the tree.\nexport type FlattenedTreeNode = {\n id: string;\n type: string;\n caption: string;\n state: AnyState;\n guards: GuardAttributeDetails[];\n callbacks: CallbackAttributeDetails[];\n args: AnyArgument[];\n parentId: string | null;\n};\n\n/**\n * A representation of a behaviour tree.\n */\nexport class BehaviourTree {\n /**\n * The main root tree node.\n */\n public readonly rootNode: Root;\n\n /**\n * Creates a new instance of the BehaviourTree class.\n * @param definition The behaviour tree definition.\n * @param agent The agent instance that this behaviour tree is modelling behaviour for.\n * @param options The behaviour tree options object.\n */\n constructor(definition: string, private agent: Agent, private options: BehaviourTreeOptions = {}) {\n // The tree definition must be defined and a valid string.\n if (typeof definition !== \"string\") {\n throw new Error(\"the tree definition must be a string\");\n }\n\n // The agent must be defined and not null.\n if (typeof agent !== \"object\" || agent === null) {\n throw new Error(\"the agent must be defined and not null\");\n }\n\n // Parse the behaviour tree definition, create the populated tree of behaviour tree nodes, and get the root.\n this.rootNode = BehaviourTree._createRootNode(definition);\n }\n\n /**\n * Gets whether the tree is in the RUNNING state.\n * @returns true if the tree is in the RUNNING state, otherwise false.\n */\n isRunning() {\n return this.rootNode.getState() === State.RUNNING;\n }\n\n /**\n * Gets the current tree state of SUCCEEDED, FAILED, READY or RUNNING.\n * @returns The current tree state.\n */\n getState() {\n return this.rootNode.getState();\n }\n\n /**\n * Step the tree.\n * 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.\n * 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\n * 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.\n *\n * 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.\n */\n step() {\n // If the root node has already been stepped to completion then we need to reset it.\n if (this.rootNode.getState() === State.SUCCEEDED || this.rootNode.getState() === State.FAILED) {\n this.rootNode.reset();\n }\n\n try {\n this.rootNode.update(this.agent, this.options);\n } catch (exception) {\n throw new Error(`error stepping tree: ${(exception as Error).message}`);\n }\n }\n\n /**\n * Resets the tree from the root node outwards to each nested node, giving each a state of READY.\n */\n reset() {\n this.rootNode.reset();\n }\n\n /**\n * Gets the flattened details of every node in the tree.\n * @returns The flattened details of every node in the tree.\n */\n getFlattenedNodeDetails(): FlattenedTreeNode[] {\n // Create an empty flattened array of tree nodes.\n const flattenedTreeNodes: FlattenedTreeNode[] = [];\n\n /**\n * Helper function to process a node instance and push details into the flattened tree nodes array.\n * @param node The current node.\n * @param parentUid The UID of the node parent, or null if the node is the main root node.\n */\n const processNode = (node: Node, parentUid: string | null) => {\n // Get the guard and callback attribute details for this node.\n const guards = node\n .getAttributes()\n .filter((attribute) => attribute.isGuard())\n .map((attribute) => attribute.getDetails()) as GuardAttributeDetails[];\n const callbacks = node\n .getAttributes()\n .filter((attribute) => !attribute.isGuard())\n .map((attribute) => attribute.getDetails()) as CallbackAttributeDetails[];\n\n // Push the current node into the flattened nodes array.\n flattenedTreeNodes.push({\n id: node.getUid(),\n type: node.getType(),\n caption: node.getName(),\n state: node.getState(),\n guards,\n callbacks,\n args: node.getArguments(),\n parentId: parentUid\n });\n\n // Process each of the nodes children if it is not a leaf node.\n if (!node.isLeafNode()) {\n (node as Composite | Decorator)\n .getChildren()\n .forEach((child) => processNode(child, (node as Composite | Decorator).getUid()));\n }\n };\n\n // Convert the nested node structure into a flattened array of node details.\n processNode(this.rootNode, null);\n\n return flattenedTreeNodes;\n }\n\n /**\n * Registers the action/condition/guard/callback function or subtree with the given name.\n * @param name The name of the function or subtree to register.\n * @param value The function or subtree definition to register.\n */\n static register(name: string, value: GlobalFunction | string) {\n if (typeof value === \"function\") {\n // We are going to register a action/condition/guard/callback function.\n Lookup.setFunc(name, value);\n } else if (typeof value === \"string\") {\n // We are going to register a subtree.\n let rootASTNodes: RootAstNode[];\n\n try {\n // Try to create the behaviour tree AST based on the definition provided, this could fail if the definition is invalid.\n rootASTNodes = buildRootASTNodes(value);\n } catch (exception) {\n // There was an issue in trying to parse and build the tree definition.\n throw new Error(`error registering definition: ${(exception as Error).message}`);\n }\n\n // This function should only ever be called with a definition containing a single unnamed root node.\n if (rootASTNodes.length != 1 || rootASTNodes[0].name !== null) {\n throw new Error(\"error registering definition: expected a single unnamed root node\");\n }\n\n Lookup.setSubtree(name, rootASTNodes[0]);\n } else {\n throw new Error(\"unexpected value, expected string definition or function\");\n }\n }\n\n /**\n * Unregisters the registered action/condition/guard/callback function or subtree with the given name.\n * @param name The name of the registered action/condition/guard/callback function or subtree to unregister.\n */\n static unregister(name: string): void {\n Lookup.remove(name);\n }\n\n /**\n * Unregister all registered action/condition/guard/callback functions and subtrees.\n */\n static unregisterAll(): void {\n Lookup.empty();\n }\n\n /**\n * Parses a behaviour tree definition and creates a tree of behaviour tree nodes.\n * @param {string} definition The behaviour tree definition.\n * @returns The root behaviour tree node.\n */\n private static _createRootNode(definition: string): Root {\n // TODO Remove!\n try {\n // parseToJSON(definition);\n } catch (exception) {\n console.log(exception);\n }\n\n try {\n // Try to create the behaviour tree AST based on the definition provided, this could fail if the definition is invalid.\n const rootASTNodes = buildRootASTNodes(definition);\n\n // Create a symbol to use as the main root key in our root node mapping.\n const mainRootNodeKey = Symbol(\"__root__\");\n\n // Create a mapping of root node names to root AST tokens. The main root node will have a key of Symbol(\"__root__\").\n const rootNodeMap: { [key: string | symbol]: RootAstNode } = {};\n for (const rootASTNode of rootASTNodes) {\n rootNodeMap[rootASTNode.name === null ? mainRootNodeKey : rootASTNode.name!] = rootASTNode;\n }\n\n // Convert the AST to our actual tree and get the root node.\n const rootNode: Root = rootNodeMap[mainRootNodeKey].createNodeInstance(\n // Create a provider for named root nodes that are part of our definition or have been registered. Prioritising the former.\n (name: string): RootAstNode => (rootNodeMap[name] ? rootNodeMap[name] : Lookup.getSubtree(name)),\n []\n );\n\n // Set a guard path on every leaf of the tree to evaluate as part of its update.\n BehaviourTree._applyLeafNodeGuardPaths(rootNode);\n\n // Return the root node.\n return rootNode;\n } catch (exception) {\n // There was an issue in trying to parse and build the tree definition.\n throw new Error(`error parsing tree: ${(exception as Error).message}`);\n }\n }\n\n /**\n * Applies a guard path to every leaf of the tree to evaluate as part of each update.\n * @param rootNode The main root tree node.\n */\n private static _applyLeafNodeGuardPaths(rootNode: Root) {\n const nodePaths: Node[][] = [];\n\n const findLeafNodes = (path: Node[], node: Node) => {\n // Add the current node to the path.\n path = path.concat(node);\n\n // Check whether the current node is a leaf node.\n if (node.isLeafNode()) {\n nodePaths.push(path);\n } else {\n (node as Composite | Decorator).getChildren().forEach((child) => findLeafNodes(path, child));\n }\n };\n\n // Find all leaf node paths, starting from the root.\n findLeafNodes([], rootNode);\n\n nodePaths.forEach((path) => {\n // Each node in the current path will have to be assigned a guard path, working from the root outwards.\n for (let depth = 0; depth < path.length; depth++) {\n // Get the node in the path at the current depth.\n const currentNode = path[depth];\n\n // The node may already have been assigned a guard path, if so just skip it.\n if (currentNode.hasGuardPath()) {\n continue;\n }\n\n // Create the guard path for the current node.\n const guardPath = new GuardPath(\n path\n .slice(0, depth + 1)\n .map((node) => ({ node, guards: node.getGuardAttributes() }))\n .filter((details) => details.guards.length > 0)\n );\n\n // Assign the guard path to the current node.\n currentNode.setGuardPath(guardPath);\n }\n });\n }\n}\n"], - "mappings": "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", + "sourcesContent": ["\"use strict\";\r\nObject.defineProperty(exports, \"__esModule\", { value: true });\r\nexports.Participant = void 0;\r\n/**\r\n * A participant that holds a number of tickets.\r\n */\r\nvar Participant = /** @class */ (function () {\r\n /**\r\n * Creates an instance of the Participant class.\r\n * @param participant The actual participant.\r\n * @param tickets The number of tickets held by the participant.\r\n */\r\n function Participant(participant, tickets) {\r\n if (tickets === void 0) { tickets = 1; }\r\n this._participant = participant;\r\n this._tickets = tickets;\r\n }\r\n Object.defineProperty(Participant.prototype, \"participant\", {\r\n /** Gets the actual participant. */\r\n get: function () {\r\n return this._participant;\r\n },\r\n enumerable: false,\r\n configurable: true\r\n });\r\n Object.defineProperty(Participant.prototype, \"tickets\", {\r\n /** Gets or sets the number of tickets held by the participant. */\r\n get: function () {\r\n return this._tickets;\r\n },\r\n set: function (value) {\r\n this._tickets = value;\r\n },\r\n enumerable: false,\r\n configurable: true\r\n });\r\n return Participant;\r\n}());\r\nexports.Participant = Participant;\r\n", "\"use strict\";\r\nObject.defineProperty(exports, \"__esModule\", { value: true });\r\nexports.isNaturalNumber = exports.isNullOrUndefined = void 0;\r\n/**\r\n * Gets whether the value provided is null or undefined.\r\n * @param value The value to check.\r\n * @returns Whether the value provided is null or undefined.\r\n */\r\nfunction isNullOrUndefined(value) {\r\n return value === null || value === undefined;\r\n}\r\nexports.isNullOrUndefined = isNullOrUndefined;\r\n/**\r\n * Gets whether the value provided is a natural number.\r\n * @param value The value to check.\r\n * @returns Whether the value provided is a natural number.\r\n */\r\nfunction isNaturalNumber(value) {\r\n return typeof value === \"number\" && value >= 1 && Math.floor(value) === value;\r\n}\r\nexports.isNaturalNumber = isNaturalNumber;\r\n", "\"use strict\";\r\nObject.defineProperty(exports, \"__esModule\", { value: true });\r\nexports.Lotto = void 0;\r\nvar Participant_1 = require(\"./Participant\");\r\nvar Utilities_1 = require(\"./Utilities\");\r\n/**\r\n * Represents a lotto consisting of a number of pickable ticket-holding participants.\r\n */\r\nvar Lotto = /** @class */ (function () {\r\n /**\r\n * Creates a new instance of Lotto.\r\n * @param customRandom The custom RNG to use in place of Math.random().\r\n */\r\n function Lotto(customRandom) {\r\n /** The array of participants that are holding tickets in the lotto. */\r\n this._participants = [];\r\n this._customRandom = customRandom;\r\n }\r\n /**\r\n * Adds a participant with the specified number of tickets, or adds to the participant ticket count if the participant already holds tickets.\r\n * @param participant The participant to add or to increase the ticket count for if they already hold tickets.\r\n * @param tickets The number of tickets, defaults to 1.\r\n * @returns The Lotto instance.\r\n */\r\n Lotto.prototype.add = function (participant, tickets) {\r\n if (tickets === void 0) { tickets = 1; }\r\n // Check that we have a valid ticket count.\r\n if (!(0, Utilities_1.isNaturalNumber)(tickets)) {\r\n throw new Error(\"tickets value must be a natural number\");\r\n }\r\n // Check whether this participant has already been added.\r\n var existingParticipant = this._participants.find(function (part) { return part.participant === participant; });\r\n if (existingParticipant) {\r\n // The participant has already been added to the lotto so just add to their ticket count.\r\n existingParticipant.tickets += tickets;\r\n }\r\n else {\r\n // The participant is not part of the lotto so we should add them.\r\n this._participants.push(new Participant_1.Participant(participant, tickets));\r\n }\r\n return this;\r\n };\r\n /**\r\n * Removes the specified number of tickets for the given participant from the draw, or all tickets if a ticket number is not defined.\r\n * @param participant The participant to remove tickets for.\r\n * @param tickets The number of tickets to remove, or undefined if all tickets are to be removed.\r\n * @returns The Lotto instance.\r\n */\r\n Lotto.prototype.remove = function (participant, tickets) {\r\n // Attempt to get the existing participant.\r\n var existingParticipant = this._participants.find(function (part) { return part.participant === participant; });\r\n // There is nothing to do if the specified participant isn't even part of the lotto.\r\n if (!existingParticipant) {\r\n return this;\r\n }\r\n // Check whether a tickets value was given.\r\n if (tickets !== undefined) {\r\n // Check that we have a valid ticket count.\r\n if (!(0, Utilities_1.isNaturalNumber)(tickets)) {\r\n throw new Error(\"tickets value must be a natural number\");\r\n }\r\n existingParticipant.tickets -= tickets;\r\n // If the participant no longer holds any tickets then they should be removed.\r\n if (existingParticipant.tickets < 1) {\r\n this._participants = this._participants.filter(function (part) { return part !== existingParticipant; });\r\n }\r\n }\r\n else {\r\n // We are removing all tickets for the participant so just remove them from the lotto.\r\n this._participants = this._participants.filter(function (part) { return part !== existingParticipant; });\r\n }\r\n return this;\r\n };\r\n /**\r\n * Draw a winning ticket and return the participant that holds the ticket.\r\n * @param options The draw options.\r\n * @returns The participant that holds the winning ticket.\r\n */\r\n Lotto.prototype.draw = function (options) {\r\n if (options === void 0) { options = {}; }\r\n // If we have no participants then just return null.\r\n if (this._participants.length === 0) {\r\n return null;\r\n }\r\n var redrawable = (0, Utilities_1.isNullOrUndefined)(options.redrawable) ? true : options.redrawable;\r\n var pickable = [];\r\n this._participants.forEach(function (_a) {\r\n var participant = _a.participant, tickets = _a.tickets;\r\n for (var ticketCount = 0; ticketCount < tickets; ticketCount++) {\r\n pickable.push(participant);\r\n }\r\n });\r\n var random;\r\n // We need a random floating-point number between 0 (inclusive) and 1 to scale up to pick our winner.\r\n // If a custom random function exists then we should use that or fall back to Math.random().\r\n if (this._customRandom) {\r\n // Call our custom random function to get a random floating-point number.\r\n random = this._customRandom();\r\n // Verify that the result of calling our custom random function is a number between 0 (inclusive) and 1.\r\n if (typeof random !== \"number\" || random < 0 || random >= 1) {\r\n throw new Error(\"the 'random' function provided did not return a number between 0 (inclusive) and 1\");\r\n }\r\n }\r\n else {\r\n // No custom random function was defined so just use good ol' Math.random().\r\n random = Math.random();\r\n }\r\n // Pick a winning participant.\r\n var winner = pickable[Math.floor(random * pickable.length)];\r\n // If the ticket isn't redrawable then we should remove a ticket from the winning participants ticket count.\r\n if (!redrawable) {\r\n this.remove(winner, 1);\r\n }\r\n // Return the winning participant.\r\n return winner;\r\n };\r\n /**\r\n * Draws multiple winning tickets and return an array of the participants that hold the winning tickets.\r\n * @param tickets The number of winning tickets to draw.\r\n * @param options The draw multiple options.\r\n * @returns An array of the participants that hold the winning tickets.\r\n */\r\n Lotto.prototype.drawMultiple = function (tickets, options) {\r\n if (options === void 0) { options = {}; }\r\n var uniqueResults = (0, Utilities_1.isNullOrUndefined)(options.unique) ? false : options.unique;\r\n // Handle cases where the user has asked for zero tickets (no idea why they would do this be we should trust them).\r\n if (tickets === 0) {\r\n return [];\r\n }\r\n // Now that we know out tickets value is not zero we should check that it is a valid natural number.\r\n if (!(0, Utilities_1.isNaturalNumber)(tickets)) {\r\n throw new Error(\"tickets value must be a natural number\");\r\n }\r\n var result = [];\r\n // Keep drawing tickets until we either reach the number of required tickets or we simply run out of tickets to draw.\r\n // We can run out of tickets to draw if 'options.redrawable' is explicity 'false' or we just had no participants when 'drawMultiple' was called.\r\n while (result.length < tickets && this._participants.length > 0) {\r\n result.push(this.draw(options));\r\n }\r\n // If the 'unique' draw option is set then we need to remove duplicates from the result list.\r\n if (uniqueResults) {\r\n // Create an array to store our unique results.\r\n var unique = [];\r\n // Iterate over all of our participants (with potential duplicates) and populate our array of unique values.\r\n for (var _i = 0, result_1 = result; _i < result_1.length; _i++) {\r\n var participant = result_1[_i];\r\n if (unique.indexOf(participant) === -1) {\r\n unique.push(participant);\r\n }\r\n }\r\n result = unique;\r\n }\r\n return result;\r\n };\r\n return Lotto;\r\n}());\r\nexports.Lotto = Lotto;\r\n", "\"use strict\";\r\nObject.defineProperty(exports, \"__esModule\", { value: true });\r\nexports.createLotto = void 0;\r\nvar Lotto_1 = require(\"./Lotto\");\r\n/**\r\n * A function that creates and returns a Lotto instance.\r\n * @param participantsOrOptions An array of initial participants or options relating to the creation of a Lotto instance.\r\n * @returns A new Lotto instance.\r\n */\r\nfunction createLotto(participantsOrOptions) {\r\n // If no initial participants or lotto options were provided as an argument then we can just return a new lotto instance now.\r\n if (!participantsOrOptions) {\r\n return new Lotto_1.Lotto();\r\n }\r\n // Check whether we were provided with an array of initial participants or a lotto options object.\r\n if (Array.isArray(participantsOrOptions)) {\r\n // We are dealing with a pre-defined array of participants.\r\n var participants = participantsOrOptions;\r\n var lotto_1 = new Lotto_1.Lotto();\r\n // If the lotto participants have been defined upfront then we will need to add them all to our lotto instance now.\r\n participants.forEach(function (_a) {\r\n var participant = _a[0], tokens = _a[1];\r\n return lotto_1.add(participant, tokens);\r\n });\r\n // Return the Lotto instance.\r\n return lotto_1;\r\n }\r\n else {\r\n // We are dealing with some lotto options.\r\n var random = participantsOrOptions.random, participants = participantsOrOptions.participants;\r\n // Create a Lotto instance passing the custom RNG function to use in place of Math.random() (which could be undefined).\r\n var lotto_2 = new Lotto_1.Lotto(random);\r\n // If the lotto participants have been defined upfront as part of the options then we will need to add them all to our lotto instance now.\r\n if (participants) {\r\n participants.forEach(function (_a) {\r\n var participant = _a[0], tokens = _a[1];\r\n return lotto_2.add(participant, tokens);\r\n });\r\n }\r\n // Return the Lotto instance.\r\n return lotto_2;\r\n }\r\n}\r\nexports.createLotto = createLotto;\r\n", "\"use strict\";\r\nObject.defineProperty(exports, \"__esModule\", { value: true });\r\nvar createLotto_1 = require(\"./createLotto\");\r\nexports.default = createLotto_1.createLotto;\r\n", "import State from \"./State\";\nimport { validateDefinition } from \"./BehaviourTreeDefinitionValidator\";\nimport { convertMDSLToJSON } from \"./mdsl/MDSLDefinitionParser\";\nimport { BehaviourTree, FlattenedTreeNode } from \"./BehaviourTree\";\n\nexport { BehaviourTree, State, convertMDSLToJSON, validateDefinition };\nexport type { FlattenedTreeNode };\n", "/**\n * Enumeration of node state types.\n */\nexport enum State {\n READY = \"mistreevous.ready\",\n RUNNING = \"mistreevous.running\",\n SUCCEEDED = \"mistreevous.succeeded\",\n FAILED = \"mistreevous.failed\"\n}\n\nexport { State as default };\n\nexport type CompleteState = State.SUCCEEDED | State.FAILED;\nexport type AnyState = State.READY | State.RUNNING | CompleteState;\n", "import {\n NodeDefinition,\n RootNodeDefinition,\n DecoratorNodeDefinition,\n CompositeNodeDefinition,\n AnyNode,\n BranchNodeDefinition\n} from \"./BehaviourTreeDefinition\";\n\n/**\n * A type guard function that returns true if the specified node satisfies the RootNodeDefinition type.\n * @param node The node.\n * @returns A value of true if the specified node satisfies the RootNodeDefinition type.\n */\nexport function isRootNode(node: NodeDefinition): node is RootNodeDefinition {\n return node.type === \"root\";\n}\n\n/**\n * A type guard function that returns true if the specified node satisfies the BranchNodeDefinition type.\n * @param node The node.\n * @returns A value of true if the specified node satisfies the BranchNodeDefinition type.\n */\nexport function isBranchNode(node: NodeDefinition): node is BranchNodeDefinition {\n return node.type === \"branch\";\n}\n\n/**\n * A type guard function that returns true if the specified node satisfies the NodeDefinition type.\n * @param node The node.\n * @returns A value of true if the specified node satisfies the NodeDefinition type.\n */\nexport function isLeafNode(node: NodeDefinition): node is NodeDefinition {\n return [\"branch\", \"action\", \"condition\", \"wait\"].includes(node.type);\n}\n\n/**\n * A type guard function that returns true if the specified node satisfies the DecoratorNodeDefinition type.\n * @param node The node.\n * @returns A value of true if the specified node satisfies the DecoratorNodeDefinition type.\n */\nexport function isDecoratorNode(node: NodeDefinition): node is DecoratorNodeDefinition {\n return [\"root\", \"repeat\", \"retry\", \"flip\", \"succeed\", \"fail\"].includes(node.type);\n}\n\n/**\n * A type guard function that returns true if the specified node satisfies the CompositeNodeDefinition type.\n * @param node The node.\n * @returns A value of true if the specified node satisfies the CompositeNodeDefinition type.\n */\nexport function isCompositeNode(node: NodeDefinition): node is CompositeNodeDefinition {\n return [\"sequence\", \"selector\", \"lotto\", \"parallel\"].includes(node.type);\n}\n\n/**\n * Flatten a node definition into an array of all of its nested node definitions.\n * @param nodeDefinition The node definition to flatten.\n * @returns An array of all of nested node definitions.\n */\nexport function flattenDefinition(nodeDefinition: AnyNode): AnyNode[] {\n const nodes: AnyNode[] = [];\n\n const processNode = (currentNodeDefinition: AnyNode) => {\n nodes.push(currentNodeDefinition);\n\n if (isCompositeNode(currentNodeDefinition)) {\n currentNodeDefinition.children.forEach(processNode);\n } else if (isDecoratorNode(currentNodeDefinition)) {\n processNode(currentNodeDefinition.child);\n }\n };\n\n processNode(nodeDefinition);\n\n return nodes;\n}\n\n/**\n * Determines whether the passed value is an integer.\n * @param value The value to check.\n * @returns Whether the passed value is an integer.\n */\nexport function isInteger(value: unknown): boolean {\n return typeof value === \"number\" && Math.floor(value) === value;\n}\n", "/**\n * A type defining an object that holds a reference to substitued string literals parsed from the definition.\n */\nexport type StringLiteralPlaceholders = { [key: string]: string };\n\n/**\n * Pop the next raw token from the specified array of tokens and throw an error if it wasn't the expected one.\n * @param tokens The array of tokens.\n * @param expected An optional string or array or items, one of which must match the next popped token.\n * @returns The popped token.\n */\nexport function popAndCheck(tokens: string[], expected?: string | string[]): string {\n // Get and remove the next token.\n const popped = tokens.shift();\n\n // We were expecting another token but there aren't any.\n if (popped === undefined) {\n throw new Error(\"unexpected end of definition\");\n }\n\n // Do we have an expected token/tokens array?\n if (expected != undefined) {\n // Get an array of expected values, if the popped token matches any then we are all good.\n const expectedValues = typeof expected === \"string\" ? [expected] : expected;\n\n // Check whether the popped token matches at least one of our expected items.\n var tokenMatchesExpectation = expectedValues.some((item) => popped.toUpperCase() === item.toUpperCase());\n\n // Throw an error if the popped token didn't match any of our expected items.\n if (!tokenMatchesExpectation) {\n const expectationString = expectedValues.map((item) => \"'\" + item + \"'\").join(\" or \");\n throw new Error(\"unexpected token found. Expected \" + expectationString + \" but got '\" + popped + \"'\");\n }\n }\n\n // Return the popped token.\n return popped;\n}\n\n/**\n * Swaps out any node/attribute argument string literals with placeholders.\n * @param definition The definition.\n * @returns An object containing a mapping of placeholders to original string values as well as the processed definition string.\n */\nexport function substituteStringLiterals(definition: string): {\n placeholders: StringLiteralPlaceholders;\n processedDefinition: string;\n} {\n // Create an object to hold the mapping of placeholders to original string values.\n const placeholders: StringLiteralPlaceholders = {};\n\n // Replace any string literals wrapped with double quotes in our definition with placeholders to be processed later.\n const processedDefinition = definition.replace(/\\\"(\\\\.|[^\"\\\\])*\\\"/g, (match) => {\n var strippedMatch = match.substring(1, match.length - 1);\n var placeholder = Object.keys(placeholders).find((key) => placeholders[key] === strippedMatch);\n\n // If we have no existing string literal match then create a new placeholder.\n if (!placeholder) {\n placeholder = `@@${Object.keys(placeholders).length}@@`;\n placeholders[placeholder] = strippedMatch;\n }\n\n return placeholder;\n });\n\n return { placeholders, processedDefinition };\n}\n\n/**\n * Parse the tree definition into an array of raw tokens.\n * @param definition The definition.\n * @returns An array of tokens parsed from the definition.\n */\nexport function parseTokensFromDefinition(definition: string): string[] {\n // Add some space around various important characters so that they can be plucked out easier as individual tokens.\n definition = definition.replace(/\\(/g, \" ( \");\n definition = definition.replace(/\\)/g, \" ) \");\n definition = definition.replace(/\\{/g, \" { \");\n definition = definition.replace(/\\}/g, \" } \");\n definition = definition.replace(/\\]/g, \" ] \");\n definition = definition.replace(/\\[/g, \" [ \");\n definition = definition.replace(/\\,/g, \" , \");\n\n // Split the definition into raw token form and return it.\n return definition.replace(/\\s+/g, \" \").trim().split(\" \");\n}\n", "import { StringLiteralPlaceholders, popAndCheck } from \"./MDSLUtilities\";\n\nexport type Argument = {\n /** The argument value. */\n value: T;\n /** The argument type, used for validation. */\n type: string;\n};\n\nexport type NullArgument = Argument & {\n type: \"null\";\n};\n\nexport type BooleanArgument = Argument & {\n type: \"boolean\";\n};\n\nexport type NumberArgument = Argument & {\n type: \"number\";\n isInteger: boolean; // Used for validation.\n};\n\nexport type StringPlaceholderArgument = Argument & {\n type: \"string\";\n};\n\nexport type IdentifierArgument = Argument & {\n type: \"identifier\";\n};\n\nexport type AnyArgument =\n | NullArgument\n | BooleanArgument\n | NumberArgument\n | StringPlaceholderArgument\n | IdentifierArgument;\n\n/**\n * Parse an array of argument definitions from the specified tokens array.\n * @param tokens The array tokens to parse the argument definitions from.\n * @param stringArgumentPlaceholders The mapping of string literal node argument placeholders to original values.\n * @param argumentValidator The argument validator function.\n * @param validationFailedMessage The exception message to throw if argument validation fails.\n * @returns An array of argument definitions parsed from the specified tokens array.\n */\nexport function parseArgumentTokens(\n tokens: string[],\n stringArgumentPlaceholders: StringLiteralPlaceholders\n): AnyArgument[] {\n const argumentList: AnyArgument[] = [];\n\n // If the next token is not a '[' or '(' then we have no arguments to parse.\n if (![\"[\", \"(\"].includes(tokens[0])) {\n return argumentList;\n }\n\n // Any lists of arguments will always be wrapped in '[]' for node arguments or '()' for attribute arguments.\n // We are looking for a '[' or '(' opener that wraps the argument tokens and the relevant closer.\n const closingToken = popAndCheck(tokens, [\"[\", \"(\"]) === \"[\" ? \"]\" : \")\";\n\n const argumentListTokens: string[] = [];\n\n // Grab all tokens between the '[' and ']' or '(' and ')'.\n while (tokens.length && tokens[0] !== closingToken) {\n // The next token is part of our arguments list.\n argumentListTokens.push(tokens.shift()!);\n }\n\n // Validate the order of the argument tokens. Each token must either be a ',' or a single argument that satisfies the validator.\n argumentListTokens.forEach((token, index) => {\n // Get whether this token should be an actual argument.\n const shouldBeArgumentToken = !(index & 1);\n\n // If the current token should be an actual argument then validate it, otherwise it should be a ',' token.\n if (shouldBeArgumentToken) {\n // Get the argument definition.\n const argumentDefinition = getArgumentDefinition(token, stringArgumentPlaceholders);\n\n // This is a valid argument!\n argumentList.push(argumentDefinition);\n } else {\n // The current token should be a ',' token.\n if (token !== \",\") {\n throw new Error(`invalid argument list, expected ',' or ']' but got '${token}'`);\n }\n }\n });\n\n // The arguments list should terminate with a ']' or ')' token, depending on the opener.\n popAndCheck(tokens, closingToken);\n\n // Return the arguments.\n return argumentList;\n}\n\n/**\n * Gets an argument value definition.\n * @param token The argument token.\n * @param stringArgumentPlaceholders The mapping of string literal node argument placeholders to original values.\n * @returns An argument value definition.\n */\nfunction getArgumentDefinition(token: string, stringArgumentPlaceholders: StringLiteralPlaceholders): AnyArgument {\n // Check whether the token represents a null value.\n if (token === \"null\") {\n return {\n value: null,\n type: \"null\"\n } as NullArgument;\n }\n\n // Check whether the token represents a boolean value.\n if (token === \"true\" || token === \"false\") {\n return {\n value: token === \"true\",\n type: \"boolean\"\n } as BooleanArgument;\n }\n\n // Check whether the token represents a number value.\n // TODO: Relies on broken isNaN - see MDN.\n // if (!Number.isNaN(token)) {\n if (!isNaN(token as any)) {\n return {\n value: parseFloat(token),\n isInteger: parseFloat(token) === parseInt(token, 10),\n type: \"number\"\n } as NumberArgument;\n }\n\n // Check whether the token is a placeholder (e.g. @@0@@) representing a string literal.\n if (token.match(/^@@\\d+@@$/g)) {\n return {\n value: stringArgumentPlaceholders[token].replace('\\\\\"', '\"'),\n type: \"string\"\n } as StringPlaceholderArgument;\n }\n\n // The only remaining option is that the argument value is an identifier.\n return {\n value: token,\n type: \"identifier\"\n } as IdentifierArgument;\n}\n", "import { NodeAttributeDefinition } from \"../BehaviourTreeDefinition\";\nimport { parseArgumentTokens } from \"./MDSLNodeArgumentParser\";\nimport { StringLiteralPlaceholders } from \"./MDSLUtilities\";\n\n/**\n * A type defining the attribute definitions of a node.\n */\ntype NodeAttributes = {\n while?: NodeAttributeDefinition;\n until?: NodeAttributeDefinition;\n entry?: NodeAttributeDefinition;\n exit?: NodeAttributeDefinition;\n step?: NodeAttributeDefinition;\n};\n\n/**\n * Parse any node attribute definitions from the specified tokens array.\n * @param tokens The array of remaining tokens.\n * @param stringArgumentPlaceholders The mapping of string literal node argument placeholders to original values.\n * @returns An object of attribute definitions defined by any directly following tokens.\n */\nexport function parseAttributeTokens(\n tokens: string[],\n stringArgumentPlaceholders: StringLiteralPlaceholders\n): NodeAttributes {\n const nodeAttributeNames: (keyof NodeAttributes)[] = [\"while\", \"until\", \"entry\", \"exit\", \"step\"];\n\n // Create an object to hold any attributes found.\n const attributes: NodeAttributes = {};\n\n // Try to get the name of the attribute for the next token.\n let nextAttributeName = tokens[0]?.toLowerCase() as keyof NodeAttributes;\n\n // Pull attribute tokens as well as their arguments off of the tokens stack until we have no more.\n while (nodeAttributeNames.includes(nextAttributeName)) {\n // Check to make sure that we have not already created an attribute definition of this type.\n if (attributes[nextAttributeName]) {\n throw new Error(`duplicate attribute '${tokens[0].toUpperCase()}' found for node`);\n }\n\n // Remove the attribute name token from the array of tokens.\n tokens.shift();\n\n // Grab the attribute arguments, assuming the first to be an identifier.\n const [attributeCallIdentifier, ...attributeArguments] = parseArgumentTokens(\n tokens,\n stringArgumentPlaceholders\n );\n\n // The first attribute argument has to be an identifer, this will reference an agent function.\n if (attributeCallIdentifier?.type !== \"identifier\") {\n throw new Error(\"expected agent function name identifier argument for attribute\");\n }\n\n // Any attribute arguments (other than the expected call identifier) must have a type of string, number, boolean or null.\n attributeArguments\n .filter((arg) => arg.type === \"identifier\")\n .forEach((arg) => {\n throw new Error(\n `invalid attribute argument value '${arg.value}', must be string, number, boolean or null`\n );\n });\n\n // Create the attribute definition and add it to the object of attribute definitions found.\n attributes[nextAttributeName] = {\n call: attributeCallIdentifier.value,\n args: attributeArguments.map(({ value }) => value)\n };\n\n // Try to get the next attribute name token, as there could be multiple.\n nextAttributeName = tokens[0]?.toLowerCase() as keyof NodeAttributes;\n }\n\n return attributes;\n}\n", "import {\n ActionNodeDefinition,\n AnyChildNode,\n AnyNode,\n BranchNodeDefinition,\n ConditionNodeDefinition,\n FailNodeDefinition,\n FlipNodeDefinition,\n LottoNodeDefinition,\n ParallelNodeDefinition,\n RepeatNodeDefinition,\n RetryNodeDefinition,\n RootNodeDefinition,\n SelectorNodeDefinition,\n SequenceNodeDefinition,\n SucceedNodeDefinition,\n WaitNodeDefinition\n} from \"../BehaviourTreeDefinition\";\nimport { isCompositeNode, isDecoratorNode, isLeafNode, isRootNode } from \"../BehaviourTreeDefinitionUtilities\";\nimport { parseArgumentTokens } from \"./MDSLNodeArgumentParser\";\nimport { parseAttributeTokens } from \"./MDSLNodeAttributeParser\";\nimport {\n StringLiteralPlaceholders,\n parseTokensFromDefinition,\n popAndCheck,\n substituteStringLiterals\n} from \"./MDSLUtilities\";\n\n/**\n * Convert the MDSL tree definition string into an equivalent JSON definition.\n * @param definition The tree definition string as MDSL.\n * @returns The root node JSON definitions.\n */\nexport function convertMDSLToJSON(definition: string): RootNodeDefinition[] {\n // Swap out any node/attribute argument string literals with a placeholder and get a mapping of placeholders to original values as well as the processed definition.\n const { placeholders, processedDefinition } = substituteStringLiterals(definition);\n\n // Parse our definition definition string into an array of raw tokens.\n const tokens = parseTokensFromDefinition(processedDefinition);\n\n return convertTokensToJSONDefinition(tokens, placeholders);\n}\n\n/**\n * Converts the specified tree definition tokens into a JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The root node JSON definitions.\n */\nfunction convertTokensToJSONDefinition(\n tokens: string[],\n stringLiteralPlaceholders: StringLiteralPlaceholders\n): RootNodeDefinition[] {\n // There must be at least 3 tokens for the tree definition to be valid. 'ROOT', '{' and '}'.\n if (tokens.length < 3) {\n throw new Error(\"invalid token count\");\n }\n\n // We should have a matching number of '{' and '}' tokens. If not, then there are scopes that have not been properly closed.\n if (tokens.filter((token) => token === \"{\").length !== tokens.filter((token) => token === \"}\").length) {\n throw new Error(\"scope character mismatch\");\n }\n\n // Create an array of tree stack arrays where root nodes will always be at the botton and the current composite/decorator node at the top.\n // There should be an element in this array for every root node defined and every element should be an array with a root note as the first element.\n // E.g. A definition with two root nodes defined:\n // [\n // [root, lotto, sequence],\n // [root, selector]\n // ]\n const treeStacks: [Partial, ...Partial[]][] = [];\n\n // Create an array of all root node definitions that we create.\n const rootNodes: Partial[] = [];\n\n // A helper function used to push node definitions onto the tree stack.\n const pushNode = (node: AnyNode) => {\n // If the node is a root node then we need to create a new tree stack array with the root node at the root.\n if (isRootNode(node)) {\n // Add the root node definition to our array of all parsed root node definitions.\n rootNodes.push(node);\n\n // Add the root node definition to the root of a new tree stack.\n treeStacks.push([node]);\n\n return;\n }\n\n // All non-root nodes should be pushed after their root nodes so handle cases\n // where we may not have any tree stacks or our top-most tree stack is empty.\n if (!treeStacks.length || !treeStacks[treeStacks.length - 1].length) {\n throw new Error(\"expected root node at base of definition\");\n }\n\n // Get the current tree stack that we are populating.\n const topTreeStack = treeStacks[treeStacks.length - 1];\n\n // Get the top-most node in the current tree stack, this will be a composite/decorator node\n // for which we will populate its children array if composite or setting its child if a decorator.\n const topTreeStackTopNode = topTreeStack[topTreeStack.length - 1] as AnyNode;\n\n // If the top-most node in the current root stack is a composite or decorator\n // node then the current node should be added as a child of the top-most node.\n if (isCompositeNode(topTreeStackTopNode)) {\n topTreeStackTopNode.children = topTreeStackTopNode.children || [];\n topTreeStackTopNode.children.push(node);\n } else if (isDecoratorNode(topTreeStackTopNode)) {\n // If the top node already has a child node set then throw an error as a decorator should only have a single child.\n if (topTreeStackTopNode.child) {\n throw new Error(\"a decorator node must only have a single child node\");\n }\n\n topTreeStackTopNode.child = node;\n }\n\n // If the node we are adding is also a composite or decorator node, then we should push it\n // onto the current tree stack, as subsequent nodes will be added as its child/children.\n if (!isLeafNode(node)) {\n topTreeStack.push(node);\n }\n };\n\n // A helper function used to pop node definitions off of the stack.\n const popNode = () => {\n // Get the current tree stack that we are populating.\n const topTreeStack = treeStacks[treeStacks.length - 1];\n\n // Pop the top-most node in the current tree stack if there is one.\n if (topTreeStack.length) {\n topTreeStack.pop();\n }\n\n // We don't want any empty tree stacks in our stack of tree stacks.\n if (!topTreeStack.length) {\n treeStacks.pop();\n }\n };\n\n // We should keep processing the raw tokens until we run out of them.\n while (tokens.length) {\n // Grab the next token.\n const token = tokens.shift()!;\n\n // How we create the next node depends on the current raw token value.\n switch (token.toUpperCase()) {\n case \"ROOT\": {\n pushNode(createRootNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"SUCCEED\": {\n pushNode(createSucceedNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"FAIL\": {\n pushNode(createFailNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"FLIP\": {\n pushNode(createFlipNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"REPEAT\": {\n pushNode(createRepeatNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"RETRY\": {\n pushNode(createRetryNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"SEQUENCE\": {\n pushNode(createSequenceNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"SELECTOR\": {\n pushNode(createSelectorNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"PARALLEL\": {\n pushNode(createParallelNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"LOTTO\": {\n pushNode(createLottoNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"ACTION\": {\n pushNode(createActionNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"CONDITION\": {\n pushNode(createConditionNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"WAIT\": {\n pushNode(createWaitNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"BRANCH\": {\n pushNode(createBranchNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"}\": {\n // The '}' character closes the current scope and means that we have to pop a node off of the current stack.\n popNode();\n break;\n }\n\n default: {\n throw new Error(`unexpected token: ${token}`);\n }\n }\n }\n\n return rootNodes as RootNodeDefinition[];\n}\n\n/**\n * Creates a root node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The root node JSON definition.\n */\nfunction createRootNode(tokens: string[], stringLiteralPlaceholders: StringLiteralPlaceholders): RootNodeDefinition {\n // Create the root node definition.\n let node = {\n type: \"root\",\n id: undefined\n } as RootNodeDefinition;\n\n // Parse any node arguments, we should only have one if any which will be an identifier argument for the root identifier.\n const nodeArguments = parseArgumentTokens(tokens, stringLiteralPlaceholders);\n\n // Check whether any node arguments were defined.\n if (nodeArguments.length) {\n // We should only have one argument, if any, which will be an identifier argument for the root identifier.\n if (nodeArguments.length === 1 && nodeArguments[0].type === \"identifier\") {\n // The root node identifier will be the first and only node argument value.\n node.id = nodeArguments[0].value as string;\n } else {\n throw new Error(\"expected single root name argument\");\n }\n }\n\n // Grab any node attribute definitions and spread them into the node definition.\n node = { ...node, ...parseAttributeTokens(tokens, stringLiteralPlaceholders) };\n\n // This is a decorator node, so we expect an opening '{'.\n popAndCheck(tokens, \"{\");\n\n // Return the root node definition.\n return node;\n}\n\n/**\n * Creates a succeed node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The succeed node JSON definition.\n */\nfunction createSucceedNode(\n tokens: string[],\n stringLiteralPlaceholders: StringLiteralPlaceholders\n): SucceedNodeDefinition {\n const node = {\n type: \"succeed\",\n ...parseAttributeTokens(tokens, stringLiteralPlaceholders)\n } as SucceedNodeDefinition;\n\n // This is a decorator node, so we expect an opening '{'.\n popAndCheck(tokens, \"{\");\n\n // Return the succeed node definition.\n return node;\n}\n\n/**\n * Creates a fail node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The fail node JSON definition.\n */\nfunction createFailNode(tokens: string[], stringLiteralPlaceholders: StringLiteralPlaceholders): FailNodeDefinition {\n const node = {\n type: \"fail\",\n ...parseAttributeTokens(tokens, stringLiteralPlaceholders)\n } as FailNodeDefinition;\n\n // This is a decorator node, so we expect an opening '{'.\n popAndCheck(tokens, \"{\");\n\n // Return the fail node definition.\n return node;\n}\n\n/**\n * Creates a flip node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The flip node JSON definition.\n */\nfunction createFlipNode(tokens: string[], stringLiteralPlaceholders: StringLiteralPlaceholders): FlipNodeDefinition {\n const node = {\n type: \"flip\",\n ...parseAttributeTokens(tokens, stringLiteralPlaceholders)\n } as FlipNodeDefinition;\n\n // This is a decorator node, so we expect an opening '{'.\n popAndCheck(tokens, \"{\");\n\n // Return the flip node definition.\n return node;\n}\n\n/**\n * Creates a repeat node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The repeat node JSON definition.\n */\nfunction createRepeatNode(\n tokens: string[],\n stringLiteralPlaceholders: StringLiteralPlaceholders\n): RepeatNodeDefinition {\n let node = { type: \"repeat\" } as RepeatNodeDefinition;\n\n // Get the node arguments.\n const nodeArguments = parseArgumentTokens(tokens, stringLiteralPlaceholders);\n\n // The arguments of a repeat node are optional. We may have:\n // - No node arguments, in which case the repeat note will iterate indefinitely.\n // - One node argument which will be the explicit number of iterations to make.\n // - Two node arguments which define the min and max iteration bounds from which a random iteration count will be picked.\n if (nodeArguments.length) {\n // All repeat node arguments MUST be of type number and must be integer.\n nodeArguments\n .filter((arg) => arg.type !== \"number\" || !arg.isInteger)\n .forEach(() => {\n throw new Error(`repeat node iteration counts must be integer values`);\n });\n\n // We should have got one or two iteration counts.\n if (nodeArguments.length === 1) {\n // A static iteration count was defined.\n node.iterations = nodeArguments[0].value as number;\n } else if (nodeArguments.length === 2) {\n // A minimum and maximum iteration count was defined.\n node.iterations = [nodeArguments[0].value as number, nodeArguments[1].value as number];\n } else {\n // An incorrect number of iteration counts was defined.\n throw new Error(\"invalid number of repeat node iteration count arguments defined\");\n }\n }\n\n // Grab any node attribute definitions and spread them into the node definition.\n node = { ...node, ...parseAttributeTokens(tokens, stringLiteralPlaceholders) };\n\n // This is a decorator node, so we expect an opening '{'.\n popAndCheck(tokens, \"{\");\n\n // Return the repeat node definition.\n return node;\n}\n\n/**\n * Creates a retry node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The retry node JSON definition.\n */\nfunction createRetryNode(tokens: string[], stringLiteralPlaceholders: StringLiteralPlaceholders): RetryNodeDefinition {\n let node = { type: \"retry\" } as RetryNodeDefinition;\n\n // Get the node arguments.\n const nodeArguments = parseArgumentTokens(tokens, stringLiteralPlaceholders);\n\n // The arguments of a retry node are optional. We may have:\n // - No node arguments, in which case the retry note will attempt indefinitely.\n // - One node argument which will be the explicit number of attempts to make.\n // - Two node arguments which define the min and max attempt bounds from which a random attempt count will be picked.\n if (nodeArguments.length) {\n // All retry node arguments MUST be of type number and must be integer.\n nodeArguments\n .filter((arg) => arg.type !== \"number\" || !arg.isInteger)\n .forEach(() => {\n throw new Error(`retry node attempt counts must be integer values`);\n });\n\n // We should have got one or two attempt counts.\n if (nodeArguments.length === 1) {\n // A static attempt count was defined.\n node.attempts = nodeArguments[0].value as number;\n } else if (nodeArguments.length === 2) {\n // A minimum and maximum attempt count was defined.\n node.attempts = [nodeArguments[0].value as number, nodeArguments[1].value as number];\n } else {\n // An incorrect number of attempt counts was defined.\n throw new Error(\"invalid number of retry node attempt count arguments defined\");\n }\n }\n\n // Grab any node attribute definitions and spread them into the node definition.\n node = { ...node, ...parseAttributeTokens(tokens, stringLiteralPlaceholders) };\n\n // This is a decorator node, so we expect an opening '{'.\n popAndCheck(tokens, \"{\");\n\n // Return the retry node definition.\n return node;\n}\n\n/**\n * Creates a sequence node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The sequence node JSON definition.\n */\nfunction createSequenceNode(\n tokens: string[],\n stringLiteralPlaceholders: StringLiteralPlaceholders\n): SequenceNodeDefinition {\n const node = {\n type: \"sequence\",\n ...parseAttributeTokens(tokens, stringLiteralPlaceholders)\n } as SequenceNodeDefinition;\n\n // This is a composite node, so we expect an opening '{'.\n popAndCheck(tokens, \"{\");\n\n // Return the sequence node definition.\n return node;\n}\n\n/**\n * Creates a selector node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The selector node JSON definition.\n */\nfunction createSelectorNode(\n tokens: string[],\n stringLiteralPlaceholders: StringLiteralPlaceholders\n): SelectorNodeDefinition {\n const node = {\n type: \"selector\",\n ...parseAttributeTokens(tokens, stringLiteralPlaceholders)\n } as SelectorNodeDefinition;\n\n // This is a composite node, so we expect an opening '{'.\n popAndCheck(tokens, \"{\");\n\n // Return the selector node definition.\n return node;\n}\n\n/**\n * Creates a parallel node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The parallel node JSON definition.\n */\nfunction createParallelNode(\n tokens: string[],\n stringLiteralPlaceholders: StringLiteralPlaceholders\n): ParallelNodeDefinition {\n const node = {\n type: \"parallel\",\n ...parseAttributeTokens(tokens, stringLiteralPlaceholders)\n } as ParallelNodeDefinition;\n\n // This is a composite node, so we expect an opening '{'.\n popAndCheck(tokens, \"{\");\n\n // Return the parallel node definition.\n return node;\n}\n\n/**\n * Creates a lotto node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The lotto node JSON definition.\n */\nfunction createLottoNode(tokens: string[], stringLiteralPlaceholders: StringLiteralPlaceholders): LottoNodeDefinition {\n // If any node arguments have been defined then they must be our weights.\n const nodeArguments = parseArgumentTokens(tokens, stringLiteralPlaceholders);\n\n // All lotto node arguments MUST be of type number and must be integer.\n nodeArguments\n .filter((arg) => arg.type !== \"number\" || !arg.isInteger)\n .forEach(() => {\n throw new Error(`lotto node weight arguments must be integer values`);\n });\n\n const node = {\n type: \"lotto\",\n weights: nodeArguments.map(({ value }) => value),\n ...parseAttributeTokens(tokens, stringLiteralPlaceholders)\n } as LottoNodeDefinition;\n\n // This is a composite node, so we expect an opening '{'.\n popAndCheck(tokens, \"{\");\n\n // Return the lotto node definition.\n return node;\n}\n\n/**\n * Creates an action node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The action node JSON definition.\n */\nfunction createActionNode(\n tokens: string[],\n stringLiteralPlaceholders: StringLiteralPlaceholders\n): ActionNodeDefinition {\n // Parse any node arguments, we should have at least one which will be an identifier argument for the action name\n // and agent function to invoke for the action, all other arguments are to be passed as arguments to that function.\n const [actionNameIdentifier, ...agentFunctionArgs] = parseArgumentTokens(tokens, stringLiteralPlaceholders);\n\n // Our first argument MUST be defined and be an identifier as we require an action name argument.\n if (actionNameIdentifier?.type !== \"identifier\") {\n throw new Error(\"expected action name identifier argument\");\n }\n\n // Only the first argument should have been an identifier, all agent function arguments must be string, number, boolean or null.\n agentFunctionArgs\n .filter((arg) => arg.type === \"identifier\")\n .forEach((arg) => {\n throw new Error(\n `invalid action node argument value '${arg.value}', must be string, number, boolean or null`\n );\n });\n\n // Return the action node definition.\n return {\n type: \"action\",\n call: actionNameIdentifier.value,\n args: agentFunctionArgs.map(({ value }) => value),\n ...parseAttributeTokens(tokens, stringLiteralPlaceholders)\n };\n}\n\n/**\n * Creates a condition node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The condition node JSON definition.\n */\nfunction createConditionNode(\n tokens: string[],\n stringLiteralPlaceholders: StringLiteralPlaceholders\n): ConditionNodeDefinition {\n // Parse any node arguments, we should have at least one which will be an identifier argument for the condition name\n // and agent function to invoke for the condition, all other arguments are to be passed as arguments to that function.\n const [conditionNameIdentifier, ...agentFunctionArgs] = parseArgumentTokens(tokens, stringLiteralPlaceholders);\n\n // Our first argument MUST be defined and be an identifier as we require a condition name argument.\n if (conditionNameIdentifier?.type !== \"identifier\") {\n throw new Error(\"expected condition name identifier argument\");\n }\n\n // Only the first argument should have been an identifier, all agent function arguments must be string, number, boolean or null.\n agentFunctionArgs\n .filter((arg) => arg.type === \"identifier\")\n .forEach((arg) => {\n throw new Error(\n `invalid condition node argument value '${arg.value}', must be string, number, boolean or null`\n );\n });\n\n // Return the condition node definition.\n return {\n type: \"condition\",\n call: conditionNameIdentifier.value,\n args: agentFunctionArgs.map(({ value }) => value),\n ...parseAttributeTokens(tokens, stringLiteralPlaceholders)\n };\n}\n\n/**\n * Creates a wait node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The wait node JSON definition.\n */\nfunction createWaitNode(tokens: string[], stringLiteralPlaceholders: StringLiteralPlaceholders): WaitNodeDefinition {\n let node = { type: \"wait\" } as WaitNodeDefinition;\n\n // Get the node arguments.\n const nodeArguments = parseArgumentTokens(tokens, stringLiteralPlaceholders);\n\n // The arguments of a wait node are optional. We may have:\n // - No node arguments, in which case the wait will be indefinite until it is aborted.\n // - One node argument which will be the explicit duration of the wait.\n // - Two node arguments which define the min and max duration bounds from which a random duration will be picked.\n if (nodeArguments.length) {\n // All wait node arguments MUST be of type number and must be integer.\n nodeArguments\n .filter((arg) => arg.type !== \"number\" || !arg.isInteger)\n .forEach(() => {\n throw new Error(`wait node duration arguments must be integer values`);\n });\n\n // We may have:\n // - One node argument which will be the explicit duration of the wait.\n // - Two node arguments which define the min and max duration bounds from which a random duration will be picked.\n // - Too many arguments, which is not valid.\n if (nodeArguments.length === 1) {\n // An explicit duration was defined.\n node.duration = nodeArguments[0].value as number;\n } else if (nodeArguments.length === 2) {\n // Min and max duration bounds were defined from which a random duration will be picked.\n node.duration = [nodeArguments[0].value as number, nodeArguments[1].value as number];\n } else if (nodeArguments.length > 2) {\n // An incorrect number of duration arguments were defined.\n throw new Error(\"invalid number of wait node duration arguments defined\");\n }\n }\n\n // Return the wait node definition.\n return { ...node, ...parseAttributeTokens(tokens, stringLiteralPlaceholders) };\n}\n\n/**\n * Creates a branch node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The branch node JSON definition.\n */\nfunction createBranchNode(\n tokens: string[],\n stringLiteralPlaceholders: StringLiteralPlaceholders\n): BranchNodeDefinition {\n // Parse any node arguments, we should have one which will be an identifier argument for the root ref.\n const nodeArguments = parseArgumentTokens(tokens, stringLiteralPlaceholders);\n\n // We should have only a single identifer argument for a branch node, which is the root ref.\n if (nodeArguments.length !== 1 || nodeArguments[0].type !== \"identifier\") {\n throw new Error(\"expected single branch name argument\");\n }\n\n // Return the branch node definition.\n return { type: \"branch\", ref: nodeArguments[0].value };\n}\n", "import { RootNodeDefinition } from \"./BehaviourTreeDefinition\";\nimport { flattenDefinition, isBranchNode, isInteger } from \"./BehaviourTreeDefinitionUtilities\";\nimport { convertMDSLToJSON } from \"./mdsl/MDSLDefinitionParser\";\n\n/**\n * An object representing the result of validating a tree definition.\n */\nexport type DefinitionValidationResult = {\n /**\n * A flag defining whether validation succeeded.\n */\n succeeded: boolean;\n /**\n * A string containing the error message if validation did not succeed.\n */\n errorMessage?: string;\n};\n\n/**\n * Validates the specified behaviour tree definition in the form of JSON or MDSL.\n * @param definition The behaviour tree definition in the form of JSON or MDSL.\n * @returns An object representing the result of validating the given tree definition.\n */\nexport function validateDefinition(definition: any): DefinitionValidationResult {\n // A helper function to create a failure validation result with the given error message.\n const createFailureResult = (errorMessage: string) => ({ succeeded: false, errorMessage });\n\n // The definition must be defined.\n if (definition === null || typeof definition === \"undefined\") {\n return createFailureResult(\"definition is null or undefined\");\n }\n\n let rootNodeDefinitions: any[];\n\n // We are expecting a definition in one of three different forms:\n // - A string which we will assume is mdsl and we will parse this to JSON before validation.\n // - An array which we will assume is an array of root node definitions with at least one being the primary root node (no 'id' property)\n // - An object which we will assume is the primary root node and should not have an 'id' property.\n if (typeof definition === \"string\") {\n try {\n // The definition is a string which we can assume is mdsl, so attempt to parse it to a JSON definition in the form of an array of root node definitions.\n rootNodeDefinitions = convertMDSLToJSON(definition);\n } catch (error) {\n // We failed to parse the JSON from the mdsl, this is likely to be the result of it not being a valid mdsl string.\n return createFailureResult(`invalid mdsl: ${definition}`);\n }\n } else if (typeof definition === \"object\") {\n // The definition will either be an array (of root node definitions) or an object (the single primary root node definition).\n rootNodeDefinitions = Array.isArray(definition) ? definition : [definition];\n } else {\n return createFailureResult(`unexpected definition type of '${typeof definition}'`);\n }\n\n // Iterate over our array of root nodes and call validateNode for each, passing an initial depth of 0, wrapped in a try catch to handle validation failures.\n try {\n rootNodeDefinitions.forEach((rootNodeDefinition) => validateNode(rootNodeDefinition, 0));\n } catch (error) {\n // Handle cases where we have caught a thrown Error and return a failure result with the error message.\n if (error instanceof Error) {\n return createFailureResult(error.message);\n }\n\n // No idea what happened here!\n return createFailureResult(`unexpected error: ${error}`);\n }\n\n // Unpack all of the root node definitions into arrays of main ('id' defined) and sub ('id' not defined) root node definitions.\n const mainRootNodeDefinitions = rootNodeDefinitions.filter(({ id }) => typeof id === \"undefined\");\n const subRootNodeDefinitions = rootNodeDefinitions.filter(({ id }) => typeof id === \"string\" && id.length > 0);\n\n // We should ALWAYS have exactly one root node definition without an 'id' property defined, which is out main root node definition.\n if (mainRootNodeDefinitions.length !== 1) {\n return createFailureResult(\"expected single root node without 'id' property defined to act as main root\");\n }\n\n // We should never have duplicate 'id' properties across our sub root node definitions.\n const subRootNodeIdenitifers: string[] = [];\n for (const { id } of subRootNodeDefinitions) {\n // Have we already come across this 'id' property value?\n if (subRootNodeIdenitifers.includes(id)) {\n return createFailureResult(`multiple root nodes found with duplicate 'id' property value of '${id}'`);\n }\n\n subRootNodeIdenitifers.push(id);\n }\n\n // Check for any branch node circular depedencies. This will not include any globally registered subtrees.\n const circularDependencyPath = findBranchCircularDependencyPath(rootNodeDefinitions);\n\n // If we found a circular dependency in our root node and branch node definitions then the definition is definitely not valid.\n if (circularDependencyPath) {\n return createFailureResult(`circular dependency found in branch node references: ${circularDependencyPath}`);\n }\n\n // Our definition was valid!\n return { succeeded: true };\n}\n\n/**\n * Find the first circular depdendency path present in the array of root node definitions, or null if one doesn't exist.\n * This will not consider branch nodes that reference any globally registered subtrees.\n * @param rootNodeDefinitions The array of root node definitions.\n * @returns The first circular depdendency path present in the array of root node definitions as string, or null if one doesn't exist.\n */\nfunction findBranchCircularDependencyPath(rootNodeDefinitions: RootNodeDefinition[]): string | null {\n // Create a mapping of root node identifiers to other root nodes that they reference via branch nodes.\n // Below is an example of a mapping that includes a circular dependency (root => a => b => c => a)\n // [{ refs: [\"a\", \"b\"] }, { id: \"a\", refs: [\"b\"] }, { id: \"b\", refs: [\"c\"] }, { id: \"c\", refs: [\"a\"] }]\n const rootNodeMappings: { id: string | undefined; refs: string[] }[] = rootNodeDefinitions.map(\n (rootNodeDefinition) => ({\n id: rootNodeDefinition.id,\n refs: flattenDefinition(rootNodeDefinition)\n .filter(isBranchNode)\n .map(({ ref }) => ref)\n })\n );\n\n let badPathFormatted: string | null = null;\n\n // A recursive function to walk through the mappings, keeping track of which root nodes we have visited in the form of a path of root node identifiers.\n const followRefs = (mapping: { id: string | undefined; refs: string[] }, path: (string | undefined)[] = []) => {\n // Have we found a circular dependency?\n if (path.includes(mapping.id)) {\n // We found a circular dependency! Get the bad path of root node identifiers.\n const badPath = [...path, mapping.id];\n\n // Set the formatted path value. [undefined, \"a\", \"b\", \"c\", \"a\"] would be formatted as \"a -> b -> c -> a\".\n badPathFormatted = badPath.filter((element) => !!element).join(\" => \");\n\n // No need to continue, we found a circular dependency.\n return;\n }\n\n for (const ref of mapping.refs) {\n // Find the mapping for the root node with an identifer matching the current ref.\n const subMapping = rootNodeMappings.find(({ id }) => id === ref);\n\n // We may not have a mapping for this ref, which will happen if this ref is for a globally registered subtree.\n if (subMapping) {\n followRefs(subMapping, [...path, mapping.id]);\n }\n }\n };\n\n // Start looking for circular dependencies from the root.\n followRefs(rootNodeMappings.find((mapping) => typeof mapping.id === \"undefined\")!);\n\n return badPathFormatted;\n}\n\n/**\n * Validate an object that we expect to be a node definition.\n * @param definition An object that we expect to be a node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateNode(definition: any, depth: number): void {\n // Every node must be valid object and have a non-empty 'type' string property.\n if (typeof definition !== \"object\" || typeof definition.type !== \"string\" || definition.type.length === 0) {\n throw new Error(\n `node definition is not an object or 'type' property is not a non-empty string at depth '${depth}'`\n );\n }\n\n // How we validate this node definition will depend on its type.\n switch (definition.type) {\n case \"action\":\n validateActionNode(definition, depth);\n break;\n\n case \"condition\":\n validateConditionNode(definition, depth);\n break;\n\n case \"wait\":\n validateWaitNode(definition, depth);\n break;\n\n case \"branch\":\n validateBranchNode(definition, depth);\n break;\n\n case \"root\":\n validateRootNode(definition, depth);\n break;\n\n case \"success\":\n validateSuccessNode(definition, depth);\n break;\n\n case \"fail\":\n validateFailNode(definition, depth);\n break;\n\n case \"flip\":\n validateFlipNode(definition, depth);\n break;\n\n case \"repeat\":\n validateRepeatNode(definition, depth);\n break;\n\n case \"retry\":\n validateRetryNode(definition, depth);\n break;\n\n case \"sequence\":\n validateSequenceNode(definition, depth);\n break;\n\n case \"selector\":\n validateSelectorNode(definition, depth);\n break;\n\n case \"parallel\":\n validateParallelNode(definition, depth);\n break;\n\n default:\n throw new Error(`unexpected node type of '${definition.type}' at depth '${depth}'`);\n }\n}\n\n/**\n * Validate any attributes for a given node definition.\n * @param definition The node definition.\n * @param depth The depth of the node in the behaviour tree definition.\n */\nfunction validateNodeAttributes(definition: any, depth: number): void {\n // Validate each of the attribute types for this node.\n [\"while\", \"until\", \"entry\", \"exit\", \"step\"].forEach((attributeName) => {\n // Attempt to grab the definition for the current attribute from the node definition.\n const attributeDefinition = definition[attributeName];\n\n // All node attributes are optional, so there is nothing to do if the current attribute is not defined.\n if (typeof attributeDefinition === \"undefined\") {\n return;\n }\n\n // The attribute definition must be an object.\n if (typeof attributeDefinition !== \"object\") {\n throw new Error(\n `expected attribute '${attributeName}' to be an object for '${definition.type}' node at depth '${depth}'`\n );\n }\n\n // The 'call' property must be defined for any attribute definition.\n if (typeof attributeDefinition.call !== \"string\" || attributeDefinition.call.length === 0) {\n throw new Error(\n `expected 'call' property for attribute '${attributeName}' to be a non-empty string for '${definition.type}' node at depth '${depth}'`\n );\n }\n\n // If any node attribute arguments have been defined then they must have been defined in an array.\n if (typeof attributeDefinition.args !== \"undefined\" && !Array.isArray(attributeDefinition.args)) {\n throw new Error(\n `expected 'args' property for attribute '${attributeName}' to be an array for '${definition.type}' node at depth '${depth}'`\n );\n }\n });\n}\n\n/**\n * Validate an object that we expect to be a root node definition.\n * @param definition An object that we expect to be a root node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateRootNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"root\") {\n throw new Error(\"expected node type of 'root' for root node\");\n }\n\n // A root node cannot be the child of another node.\n if (depth > 0) {\n throw new Error(\"a root node cannot be the child of another node\");\n }\n\n // Check that, if the root node 'id' property is defined, it is a non-empty string.\n if (typeof definition.id !== \"undefined\" && (typeof definition.id !== \"string\" || definition.id.length === 0)) {\n throw new Error(\"expected non-empty string for 'id' property if defined for root node\");\n }\n\n // A root node is a decorator node, so must have a child node defined.\n if (typeof definition.child === \"undefined\") {\n throw new Error(\"expected property 'child' to be defined for root node\");\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n\n // Validate the child node of this decorator node.\n validateNode(definition.child, depth + 1);\n}\n\n/**\n * Validate an object that we expect to be a success node definition.\n * @param definition An object that we expect to be a success node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateSuccessNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"success\") {\n throw new Error(`expected node type of 'success' for success node at depth '${depth}'`);\n }\n\n // A success node is a decorator node, so must have a child node defined.\n if (typeof definition.child === \"undefined\") {\n throw new Error(`expected property 'child' to be defined for success node at depth '${depth}'`);\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n\n // Validate the child node of this decorator node.\n validateNode(definition.child, depth + 1);\n}\n\n/**\n * Validate an object that we expect to be a fail node definition.\n * @param definition An object that we expect to be a fail node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateFailNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"fail\") {\n throw new Error(`expected node type of 'fail' for fail node at depth '${depth}'`);\n }\n\n // A fail node is a decorator node, so must have a child node defined.\n if (typeof definition.child === \"undefined\") {\n throw new Error(`expected property 'child' to be defined for fail node at depth '${depth}'`);\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n\n // Validate the child node of this decorator node.\n validateNode(definition.child, depth + 1);\n}\n\n/**\n * Validate an object that we expect to be a flip node definition.\n * @param definition An object that we expect to be a flip node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateFlipNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"flip\") {\n throw new Error(`expected node type of 'flip' for flip node at depth '${depth}'`);\n }\n\n // A flip node is a decorator node, so must have a child node defined.\n if (typeof definition.child === \"undefined\") {\n throw new Error(`expected property 'child' to be defined for flip node at depth '${depth}'`);\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n\n // Validate the child node of this decorator node.\n validateNode(definition.child, depth + 1);\n}\n\n/**\n * Validate an object that we expect to be a repeat node definition.\n * @param definition An object that we expect to be a repeat node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateRepeatNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"repeat\") {\n throw new Error(`expected node type of 'repeat' for repeat node at depth '${depth}'`);\n }\n\n // A repeat node is a decorator node, so must have a child node defined.\n if (typeof definition.child === \"undefined\") {\n throw new Error(`expected property 'child' to be defined for repeat node at depth '${depth}'`);\n }\n\n // Check whether an 'iterations' property has been defined, it may not have been if this node is to repeat indefinitely.\n if (typeof definition.iterations !== \"undefined\") {\n if (Array.isArray(definition.iterations)) {\n // Check whether any elements of the array are not integer values.\n const containsNonInteger = !!definition.iterations.find((value: unknown) => !isInteger(value));\n\n // If the 'iterations' property is an array then it MUST contain two integer values.\n if (definition.iterations.length !== 2 || containsNonInteger) {\n throw new Error(\n `expected array containing two integer values for 'iterations' property if defined for repeat node at depth '${depth}'`\n );\n }\n } else if (!isInteger(definition.iterations)) {\n throw new Error(\n `expected integer value or array containing two integer values for 'iterations' property if defined for repeat node at depth '${depth}'`\n );\n }\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n\n // Validate the child node of this decorator node.\n validateNode(definition.child, depth + 1);\n}\n\n/**\n * Validate an object that we expect to be a retry node definition.\n * @param definition An object that we expect to be a retry node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateRetryNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"retry\") {\n throw new Error(`expected node type of 'retry' for retry node at depth '${depth}'`);\n }\n\n // A retry node is a decorator node, so must have a child node defined.\n if (typeof definition.child === \"undefined\") {\n throw new Error(`expected property 'child' to be defined for retry node at depth '${depth}'`);\n }\n\n // Check whether an 'attempts' property has been defined, it may not have been if this node is to retry indefinitely.\n if (typeof definition.attempts !== \"undefined\") {\n if (Array.isArray(definition.attempts)) {\n // Check whether any elements of the array are not integer values.\n const containsNonInteger = !!definition.attempts.find((value: unknown) => !isInteger(value));\n\n // If the 'attempts' property is an array then it MUST contain two integer values.\n if (definition.attempts.length !== 2 || containsNonInteger) {\n throw new Error(\n `expected array containing two integer values for 'attempts' property if defined for retry node at depth '${depth}'`\n );\n }\n } else if (!isInteger(definition.attempts)) {\n throw new Error(\n `expected integer value or array containing two integer values for 'attempts' property if defined for retry node at depth '${depth}'`\n );\n }\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n\n // Validate the child node of this decorator node.\n validateNode(definition.child, depth + 1);\n}\n\n/**\n * Validate an object that we expect to be a branch node definition.\n * @param definition An object that we expect to be a branch node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateBranchNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"branch\") {\n throw new Error(`expected node type of 'branch' for branch node at depth '${depth}'`);\n }\n\n // Check that the branch node 'ref' property is defined and is a non-empty string.\n if (typeof definition.ref !== \"string\" || definition.ref.length === 0) {\n throw new Error(`expected non-empty string for 'ref' property for branch node at depth '${depth}'`);\n }\n\n // It is invalid to define guard attributes for a branch node as they should be defined on the referenced root node.\n [\"while\", \"until\"].forEach((attributeName) => {\n if (typeof definition[attributeName] !== \"undefined\") {\n throw new Error(\n `guards should not be defined for branch nodes but guard '${attributeName}' was defined for branch node at depth '${depth}'`\n );\n }\n });\n\n // It is invalid to define callback attributes for a branch node as they should be defined on the referenced root node.\n [\"entry\", \"exit\", \"step\"].forEach((attributeName) => {\n if (typeof definition[attributeName] !== \"undefined\") {\n throw new Error(\n `callbacks should not be defined for branch nodes but callback '${attributeName}' was defined for branch node at depth '${depth}'`\n );\n }\n });\n}\n\n/**\n * Validate an object that we expect to be a action node definition.\n * @param definition An object that we expect to be a action node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateActionNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"action\") {\n throw new Error(`expected node type of 'action' for action node at depth '${depth}'`);\n }\n\n // The 'call' property must be defined for a action node definition.\n if (typeof definition.call !== \"string\" || definition.call.length === 0) {\n throw new Error(`expected non-empty string for 'call' property of action node at depth '${depth}'`);\n }\n\n // If any action function arguments have been defined then they must have been defined in an array.\n if (typeof definition.args !== \"undefined\" && !Array.isArray(definition.args)) {\n throw new Error(`expected array for 'args' property if defined for action node at depth '${depth}'`);\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n}\n\n/**\n * Validate an object that we expect to be a condition node definition.\n * @param definition An object that we expect to be a condition node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateConditionNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"condition\") {\n throw new Error(`expected node type of 'condition' for condition node at depth '${depth}'`);\n }\n\n // The 'call' property must be defined for a condition node definition.\n if (typeof definition.call !== \"string\" || definition.call.length === 0) {\n throw new Error(`expected non-empty string for 'call' property of condition node at depth '${depth}'`);\n }\n\n // If any condition function arguments have been defined then they must have been defined in an array.\n if (typeof definition.args !== \"undefined\" && !Array.isArray(definition.args)) {\n throw new Error(`expected array for 'args' property if defined for condition node at depth '${depth}'`);\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n}\n\n/**\n * Validate an object that we expect to be a wait node definition.\n * @param definition An object that we expect to be a wait node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateWaitNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"wait\") {\n throw new Error(`expected node type of 'wait' for wait node at depth '${depth}'`);\n }\n\n // Check whether a 'duration' property has been defined, it may not have been if this node is to wait indefinitely.\n if (typeof definition.duration !== \"undefined\") {\n if (Array.isArray(definition.duration)) {\n // Check whether any elements of the array are not integer values.\n const containsNonInteger = !!definition.duration.find((value: unknown) => !isInteger(value));\n\n // If the 'duration' property is an array then it MUST contain two integer values.\n if (definition.duration.length !== 2 || containsNonInteger) {\n throw new Error(\n `expected array containing two integer values for 'duration' property if defined for wait node at depth '${depth}'`\n );\n }\n } else if (!isInteger(definition.duration)) {\n throw new Error(\n `expected integer value or array containing two integer values for 'duration' property if defined for wait node at depth '${depth}'`\n );\n }\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n}\n\n/**\n * Validate an object that we expect to be a sequence node definition.\n * @param definition An object that we expect to be a sequence node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateSequenceNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"sequence\") {\n throw new Error(`expected node type of 'sequence' for sequence node at depth '${depth}'`);\n }\n\n // A sequence node is a composite node, so must have a children nodes array defined.\n if (!Array.isArray(definition.children) || definition.children.length === 0) {\n throw new Error(`expected non-empty 'children' array to be defined for sequence node at depth '${depth}'`);\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n\n // Validate the child nodes of this composite node.\n definition.children.forEach((child: any) => validateNode(child, depth + 1));\n}\n\n/**\n * Validate an object that we expect to be a selector node definition.\n * @param definition An object that we expect to be a selector node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateSelectorNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"selector\") {\n throw new Error(`expected node type of 'selector' for selector node at depth '${depth}'`);\n }\n\n // A selector node is a composite node, so must have a children nodes array defined.\n if (!Array.isArray(definition.children) || definition.children.length === 0) {\n throw new Error(`expected non-empty 'children' array to be defined for selector node at depth '${depth}'`);\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n\n // Validate the child nodes of this composite node.\n definition.children.forEach((child: any) => validateNode(child, depth + 1));\n}\n\n/**\n * Validate an object that we expect to be a parallel node definition.\n * @param definition An object that we expect to be a parallel node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateParallelNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"parallel\") {\n throw new Error(`expected node type of 'parallel' for parallel node at depth '${depth}'`);\n }\n\n // A parallel node is a composite node, so must have a children nodes array defined.\n if (!Array.isArray(definition.children) || definition.children.length === 0) {\n throw new Error(`expected non-empty 'children' array to be defined for parallel node at depth '${depth}'`);\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n\n // Validate the child nodes of this composite node.\n definition.children.forEach((child: any) => validateNode(child, depth + 1));\n}\n", "import Node from \"../../nodes/Node\";\n\n/**\n * An exception thrown when evaluating node guard path conditions and a conditions fails.\n */\nexport default class GuardUnsatisifedException extends Error {\n /**\n * @param source The node at which a guard condition failed.\n */\n constructor(private source: Node) {\n super(\"A guard path condition has failed\");\n }\n\n /**\n * Gets whether the specified node is the node at which a guard condition failed.\n * @param node The node to check against the source node.\n * @returns Whether the specified node is the node at which a guard condition failed.\n */\n isSourceNode = (node: Node) => node === this.source;\n}\n", "import { Agent } from \"../../Agent\";\nimport Guard from \"./Guard\";\nimport Node from \"../../nodes/Node\";\nimport GuardUnsatisifedException from \"./GuardUnsatisifedException\";\n\nexport type GuardPathPart = {\n node: Node;\n guards: Guard[];\n};\n\n/**\n * Represents a path of node guards along a root-to-leaf tree path.\n */\nexport default class GuardPath {\n /**\n * @param nodes An array of objects defining a node instance -> guard link, ordered by node depth.\n */\n constructor(private nodes: GuardPathPart[]) {}\n\n /**\n * Evaluate guard conditions for all guards in the tree path, moving outwards from the root.\n * @param agent The agent, required for guard evaluation.\n * @returns An evaluation results object.\n */\n evaluate = (agent: Agent) => {\n // We need to evaluate guard conditions for nodes up the tree, moving outwards from the root.\n for (const details of this.nodes) {\n // There can be multiple guards per node.\n for (const guard of details.guards) {\n // Check whether the guard condition passes, and throw an exception if not.\n if (!guard.isSatisfied(agent)) {\n throw new GuardUnsatisifedException(details.node);\n }\n }\n }\n };\n}\n", "import { Agent } from \"../Agent\";\nimport Attribute from \"../attributes/Attribute\";\nimport Entry from \"../attributes/callbacks/Entry\";\nimport Exit from \"../attributes/callbacks/Exit\";\nimport Step from \"../attributes/callbacks/Step\";\nimport Guard from \"../attributes/guards/Guard\";\nimport GuardPath from \"../attributes/guards/GuardPath\";\nimport GuardUnsatisifedException from \"../attributes/guards/GuardUnsatisifedException\";\nimport { BehaviourTreeOptions } from \"../BehaviourTreeOptions\";\nimport { AnyArgument } from \"../RootAstNodesBuilder\";\nimport State, { AnyState } from \"../State\";\nimport Leaf from \"./leaf/Leaf\";\n\n/**\n * A base node.\n */\nexport default abstract class Node {\n /**\n * The node uid.\n */\n private readonly uid: string = createNodeUid();\n /**\n * The node state.\n */\n private state: AnyState = State.READY;\n /**\n * The guard path to evaluate as part of a node update.\n */\n private guardPath: GuardPath | undefined;\n\n /**\n * @param type The node type.\n * @param attributes The node attributes.\n * @param args The node argument definitions.\n */\n constructor(private type: string, private attributes: Attribute[], private args: AnyArgument[]) {}\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected abstract onUpdate(agent: Agent, options: BehaviourTreeOptions): void;\n\n /**\n * Gets the name of the node.\n */\n public abstract getName(): string;\n\n /**\n * Gets whether this node is a leaf node.\n */\n public abstract isLeafNode: () => this is Leaf;\n\n /**\n * Gets/Sets the state of the node.\n */\n getState = (): AnyState => this.state;\n setState = (value: AnyState): void => {\n this.state = value;\n };\n\n /**\n * Gets the unique id of the node.\n */\n getUid = () => this.uid;\n\n /**\n * Gets the type of the node.\n */\n getType = () => this.type;\n\n /**\n * Gets the node attributes.\n */\n getAttributes = () => this.attributes;\n\n /**\n * Gets the node arguments.\n */\n getArguments = () => this.args;\n\n /**\n * Gets the node attribute with the specified type, or null if it does not exist.\n */\n getAttribute(type: \"entry\" | \"ENTRY\"): Entry;\n getAttribute(type: \"exit\" | \"EXIT\"): Exit;\n getAttribute(type: \"step\" | \"STEP\"): Step;\n getAttribute(type: string): Attribute {\n return (\n this.getAttributes().filter((decorator) => decorator.getType().toUpperCase() === type.toUpperCase())[0] ||\n null\n );\n }\n\n /**\n * Gets the node attributes.\n */\n getGuardAttributes = (): Guard[] => this.getAttributes().filter((decorator) => decorator.isGuard()) as Guard[];\n\n /**\n * Sets the guard path to evaluate as part of a node update.\n */\n setGuardPath = (value: GuardPath) => (this.guardPath = value);\n\n /**\n * Gets whether a guard path is assigned to this node.\n */\n hasGuardPath = () => !!this.guardPath;\n\n /**\n * Gets whether this node is in the specified state.\n * @param value The value to compare to the node state.\n */\n public is(value: AnyState): boolean {\n return this.state === value;\n }\n\n /**\n * Reset the state of the node.\n */\n public reset(): void {\n this.setState(State.READY);\n }\n\n /**\n * Abort the running of this node.\n * @param agent The agent.\n */\n public abort(agent: Agent): void {\n // There is nothing to do if this node is not in the running state.\n if (!this.is(State.RUNNING)) {\n return;\n }\n\n // Reset the state of this node.\n this.reset();\n\n this.getAttribute(\"exit\")?.callAgentFunction(agent, false, true);\n }\n\n /**\n * Update the node.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n * @returns The result of the update.\n */\n public update(agent: Agent, options: BehaviourTreeOptions): void {\n // If this node is already in a 'SUCCEEDED' or 'FAILED' state then there is nothing to do.\n if (this.is(State.SUCCEEDED) || this.is(State.FAILED)) {\n return;\n }\n\n try {\n // Evaluate all of the guard path conditions for the current tree path.\n this.guardPath!.evaluate(agent);\n\n // If this node is in the READY state then call the ENTRY for this node if it exists.\n if (this.is(State.READY)) {\n this.getAttribute(\"entry\")?.callAgentFunction(agent);\n }\n\n this.getAttribute(\"step\")?.callAgentFunction(agent);\n\n // Do the actual update.\n this.onUpdate(agent, options);\n\n // If this node is now in a 'SUCCEEDED' or 'FAILED' state then call the EXIT for this node if it exists.\n if (this.is(State.SUCCEEDED) || this.is(State.FAILED)) {\n this.getAttribute(\"exit\")?.callAgentFunction(agent, this.is(State.SUCCEEDED), false);\n }\n } catch (error) {\n // If the error is a GuardUnsatisfiedException then we need to determine if this node is the source.\n if (error instanceof GuardUnsatisifedException && error.isSourceNode(this)) {\n // Abort the current node.\n this.abort(agent);\n\n // Any node that is the source of an abort will be a failed node.\n this.setState(State.FAILED);\n } else {\n throw error;\n }\n }\n }\n}\n\n/**\n * Create a randomly generated node uid.\n * @returns A randomly generated node uid.\n */\nfunction createNodeUid(): string {\n var S4 = function () {\n return (((1 + Math.random()) * 0x10000) | 0).toString(16).substring(1);\n };\n return S4() + S4() + \"-\" + S4() + \"-\" + S4() + \"-\" + S4() + \"-\" + S4() + S4() + S4();\n}\n", "import Node from \"../Node\";\n\n/**\n * A leaf node.\n */\nexport default abstract class Leaf extends Node {\n /**\n * Gets whether this node is a leaf node.\n */\n isLeafNode = () => true;\n}\n", "import { ActionResult, Agent, ExitFunctionArg, FunctionArg, GlobalFunction } from \"./Agent\";\nimport { AnyArgument, RootAstNode } from \"./RootAstNodesBuilder\";\n\n// Exit callbacks receive their own special type of argument.\n// There's probably stricter ways to represent this but it feels overly complex right now.\ntype ExitResultArg = { value: ExitFunctionArg };\nexport type AnyExitArgument = AnyArgument | ExitResultArg;\n\nexport type InvokerFunction = (args: AnyExitArgument[]) => ActionResult;\n\n/**\n * A singleton used to store and lookup registered functions and subtrees.\n */\nexport default class Lookup {\n /**\n * The object holding any registered functions keyed on function name.\n */\n private static functionTable: { [key: string]: GlobalFunction } = {};\n /**\n * The object holding any registered sub-trees keyed on tree name.\n */\n private static subtreeTable: { [key: string]: RootAstNode } = {};\n\n /**\n * Gets the function with the specified name.\n * @param name The name of the function.\n * @returns The function with the specified name.\n */\n public static getFunc(name: string): GlobalFunction {\n return this.functionTable[name];\n }\n\n /**\n * Sets the function with the specified name for later lookup.\n * @param name The name of the function.\n * @param func The function.\n */\n public static setFunc(name: string, func: GlobalFunction): void {\n this.functionTable[name] = func;\n }\n\n /**\n * Gets the function invoker for the specified agent and function name.\n * If a function with the specified name exists on the agent object then it will\n * be returned, otherwise we will then check the registered functions for a match.\n * @param agent The agent instance that this behaviour tree is modelling behaviour for.\n * @param name The function name.\n * @returns The function invoker for the specified agent and function name.\n */\n static getFuncInvoker(agent: Agent, name: string): InvokerFunction | null {\n // Check whether the agent contains the specified function.\n const foundOnAgent = agent[name];\n if (foundOnAgent && typeof foundOnAgent === \"function\") {\n return (args: AnyExitArgument[]): boolean | ActionResult =>\n foundOnAgent.apply(\n agent,\n args.map((arg) => arg.value)\n );\n }\n\n // The agent does not contain the specified function but it may have been registered at some point.\n if (this.functionTable[name] && typeof this.functionTable[name] === \"function\") {\n return (args: AnyExitArgument[]) => this.functionTable[name](agent, ...args.map((arg) => arg.value));\n }\n\n // We have no function to invoke.\n return null;\n }\n\n /**\n * Gets the subtree with the specified name.\n * @param name The name of the subtree.\n * @returns The subtree with the specified name.\n */\n static getSubtree(name: string): RootAstNode {\n return this.subtreeTable[name];\n }\n\n /**\n * Sets the subtree with the specified name for later lookup.\n * @param name The name of the subtree.\n * @param subtree The subtree.\n */\n static setSubtree(name: string, subtree: RootAstNode) {\n this.subtreeTable[name] = subtree;\n }\n\n /**\n * Removes the registered function or subtree with the specified name.\n * @param name The name of the registered function or subtree.\n */\n static remove(name: string) {\n delete this.functionTable[name];\n delete this.subtreeTable[name];\n }\n\n /**\n * Remove all registered functions and subtrees.\n */\n static empty() {\n this.functionTable = {};\n this.subtreeTable = {};\n }\n}\n", "import Leaf from \"./Leaf\";\nimport State, { CompleteState } from \"../../State\";\nimport Lookup from \"../../Lookup\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { AnyArgument } from \"../../RootAstNodesBuilder\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * An Action leaf node.\n * This represents an immediate or ongoing state of behaviour.\n */\nexport default class Action extends Leaf {\n /**\n * @param attributes The node attributes.\n * @param actionName The action name.\n * @param actionArguments The array of action argument definitions.\n */\n constructor(attributes: Attribute[], private actionName: string, private actionArguments: AnyArgument[]) {\n super(\"action\", attributes, actionArguments);\n }\n\n /**\n * Whether there is a pending update promise.\n */\n private isUsingUpdatePromise = false;\n\n /**\n * The finished state result of an update promise.\n */\n private updatePromiseStateResult: CompleteState | null = null;\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // If the result of this action depends on an update promise then there is nothing to do until\n // it resolves, unless there has been a value set as a result of the update promise resolving.\n if (this.isUsingUpdatePromise) {\n // Check whether the update promise has resolved with a state value.\n if (this.updatePromiseStateResult) {\n // Set the state of this node to match the state returned by the promise.\n this.setState(this.updatePromiseStateResult);\n }\n\n return;\n }\n\n // Attempt to get the invoker for the action function.\n const actionFuncInvoker = Lookup.getFuncInvoker(agent, this.actionName);\n\n // The action function should be defined.\n if (actionFuncInvoker === null) {\n throw new Error(\n `cannot update action node as the action '${this.actionName}' function is not defined on the agent and has not been registered`\n );\n }\n\n // Call the action function, the result of which may be:\n // - The finished state of this action node.\n // - A promise to return a finished node state.\n // - Undefined if the node should remain in the running state.\n const updateResult = actionFuncInvoker(this.actionArguments) as CompleteState | Promise;\n\n if (updateResult instanceof Promise) {\n updateResult.then(\n (result) => {\n // If 'isUpdatePromisePending' is null then the promise was cleared as it was resolving, probably via an abort of reset.\n if (!this.isUsingUpdatePromise) {\n return;\n }\n\n // Check to make sure the result is a valid finished state.\n if (result !== State.SUCCEEDED && result !== State.FAILED) {\n throw new Error(\n \"action node promise resolved with an invalid value, expected a State.SUCCEEDED or State.FAILED value to be returned\"\n );\n }\n\n // Set pending update promise state result to be processed on next update.\n this.updatePromiseStateResult = result;\n },\n (reason) => {\n // If 'isUpdatePromisePending' is null then the promise was cleared as it was resolving, probably via an abort of reset.\n if (!this.isUsingUpdatePromise) {\n return;\n }\n\n // Just throw whatever was returned as the rejection argument.\n throw new Error(reason);\n }\n );\n\n // This node will be in the 'RUNNING' state until the update promise resolves.\n this.setState(State.RUNNING);\n\n // We are now waiting for the promise returned by the use to resolve before we know what state this node is in.\n this.isUsingUpdatePromise = true;\n } else {\n // Validate the returned value.\n this.validateUpdateResult(updateResult);\n\n // Set the state of this node, this may be undefined, which just means that the node is still in the 'RUNNING' state.\n this.setState(updateResult || State.RUNNING);\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => this.actionName;\n\n /**\n * Reset the state of the node.\n */\n reset = () => {\n // Reset the state of this node.\n this.setState(State.READY);\n\n // There is no longer an update promise that we care about.\n this.isUsingUpdatePromise = false;\n this.updatePromiseStateResult = null;\n };\n\n /**\n * Validate the result of an update function call.\n * @param result The result of an update function call.\n */\n private validateUpdateResult = (result: CompleteState | boolean) => {\n switch (result) {\n case State.SUCCEEDED:\n case State.FAILED:\n case undefined:\n return;\n default:\n throw new Error(\n `action '${this.actionName}' 'onUpdate' returned an invalid response, expected an optional State.SUCCEEDED or State.FAILED value to be returned`\n );\n }\n };\n}\n", "import Leaf from \"./Leaf\";\nimport State from \"../../State\";\nimport Lookup from \"../../Lookup\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { AnyArgument } from \"../../RootAstNodesBuilder\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A Condition leaf node.\n * This will succeed or fail immediately based on an agent predicate, without moving to the 'RUNNING' state.\n */\nexport default class Condition extends Leaf {\n /**\n * @param attributes The node attributes.\n * @param conditionName The name of the condition function.\n * @param conditionArguments The array of condition argument definitions.\n */\n constructor(attributes: Attribute[], private conditionName: string, private conditionArguments: AnyArgument[]) {\n super(\"condition\", attributes, conditionArguments);\n }\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // Attempt to get the invoker for the condition function.\n const conditionFuncInvoker = Lookup.getFuncInvoker(agent, this.conditionName);\n\n // The condition function should be defined.\n if (conditionFuncInvoker === null) {\n throw new Error(\n `cannot update condition node as the condition '${this.conditionName}' function is not defined on the agent and has not been registered`\n );\n }\n\n // Call the condition function to determine the state of this node.\n this.setState(!!conditionFuncInvoker(this.conditionArguments) ? State.SUCCEEDED : State.FAILED);\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => this.conditionName;\n}\n", "import Leaf from \"./Leaf\";\nimport State from \"../../State\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { Agent } from \"../../Agent\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A WAIT node.\n * The state of this node will change to SUCCEEDED after a duration of time\n */\nexport default class Wait extends Leaf {\n /**\n * @param attributes The node attributes.\n * @param duration The duration that this node will wait to succeed in milliseconds.\n * @param durationMin The minimum possible duration in milliseconds that this node will wait to succeed.\n * @param durationMax The maximum possible duration in milliseconds that this node will wait to succeed.\n */\n constructor(\n attributes: Attribute[],\n private duration: number | null,\n private durationMin: number | null,\n private durationMax: number | null\n ) {\n super(\"wait\", attributes, []);\n }\n\n /**\n * The time in milliseconds at which this node was first updated.\n */\n private initialUpdateTime: number = 0;\n\n /**\n * The total duration in milliseconds that this node will be waiting for.\n */\n private totalDuration: number | null = null;\n\n /**\n * The duration in milliseconds that this node has been waiting for.\n */\n private waitedDuration: number = 0;\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // If this node is in the READY state then we need to set the initial update time.\n if (this.is(State.READY)) {\n // Set the initial update time.\n this.initialUpdateTime = new Date().getTime();\n\n // Set the initial waited duration.\n this.waitedDuration = 0;\n\n // Are we dealing with an explicit duration or will we be randomly picking a duration between the min and max duration.\n if (this.duration !== null) {\n this.totalDuration = this.duration;\n } else if (this.durationMin !== null && this.durationMax !== null) {\n // We will be picking a random duration between a min and max duration, if the optional 'random' behaviour tree\n // function option is defined then we will be using that, otherwise we will fall back to using Math.random.\n const random = typeof options.random === \"function\" ? options.random : Math.random;\n\n // Pick a random duration between a min and max duration.\n this.totalDuration = Math.floor(\n random() * (this.durationMax - this.durationMin + 1) + this.durationMin\n );\n } else {\n this.totalDuration = null;\n }\n\n // The node is now running until we finish waiting.\n this.setState(State.RUNNING);\n }\n\n // If we have no total duration then this wait node will wait indefinitely until it is aborted.\n if (this.totalDuration === null) {\n return;\n }\n\n // If we have a 'getDeltaTime' function defined as part of our options then we will use it to figure out how long we have waited for.\n if (typeof options.getDeltaTime === \"function\") {\n // Get the delta time.\n const deltaTime = options.getDeltaTime();\n\n // Our delta time must be a valid number and cannot be NaN.\n if (typeof deltaTime !== \"number\" || isNaN(deltaTime)) {\n throw new Error(\"The delta time must be a valid number and not NaN.\");\n }\n\n // Update the amount of time that this node has been waiting for based on the delta time.\n this.waitedDuration += deltaTime * 1000;\n } else {\n // We are not using a delta time, so we will just work out hom much time has passed since the first update.\n this.waitedDuration = new Date().getTime() - this.initialUpdateTime;\n }\n\n // Have we waited long enough?\n if (this.waitedDuration >= this.totalDuration) {\n // We have finished waiting!\n this.setState(State.SUCCEEDED);\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => {\n if (this.duration !== null) {\n return `WAIT ${this.duration}ms`;\n } else if (this.durationMin !== null && this.durationMax !== null) {\n return `WAIT ${this.durationMin}ms-${this.durationMax}ms`;\n } else {\n return \"WAIT\";\n }\n };\n}\n", "import Node from \"../Node\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\n\n/**\n * A decorator node that wraps a single child node.\n */\nexport default abstract class Decorator extends Node {\n /**\n * @param type The node type.\n * @param attributes The node attributes.\n * @param child The child node.\n */\n constructor(type: string, attributes: Attribute[], protected child: Node) {\n super(type, attributes, []);\n }\n\n /**\n * Gets whether this node is a leaf node.\n */\n isLeafNode = () => false;\n\n /**\n * Gets the children of this node.\n */\n getChildren = () => [this.child];\n\n /**\n * Reset the state of the node.\n */\n reset = () => {\n // Reset the state of this node.\n this.setState(State.READY);\n\n // Reset the state of the child node.\n this.child.reset();\n };\n\n /**\n * Abort the running of this node.\n * @param agent The agent.\n */\n abort = (agent: Agent) => {\n // There is nothing to do if this node is not in the running state.\n if (!this.is(State.RUNNING)) {\n return;\n }\n\n // Abort the child node.\n this.child.abort(agent);\n\n // Reset the state of this node.\n this.reset();\n\n this.getAttribute(\"exit\")?.callAgentFunction(agent, false, true);\n };\n}\n", "import Node from \"../Node\";\nimport Decorator from \"./Decorator\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A Root node.\n * The root node will have a single child.\n */\nexport default class Root extends Decorator {\n /**\n * @param attributes The node attributes.\n * @param child The child node.\n */\n constructor(attributes: Attribute[], child: Node) {\n super(\"root\", attributes, child);\n }\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // If the child has never been updated or is running then we will need to update it now.\n if (this.child.getState() === State.READY || this.child.getState() === State.RUNNING) {\n // Update the child of this node.\n this.child.update(agent, options);\n }\n\n // The state of the root node is the state of its child.\n this.setState(this.child.getState());\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => \"ROOT\";\n}\n", "import Node from \"../Node\";\nimport Decorator from \"./Decorator\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A REPEAT node.\n * The node has a single child which can have:\n * -- A number of iterations for which to repeat the child node.\n * -- An infinite repeat loop if neither an iteration count or a condition function is defined.\n * The REPEAT node will stop and have a 'FAILED' state if its child is ever in a 'FAILED' state after an update.\n * The REPEAT node will attempt to move on to the next iteration if its child is ever in a 'SUCCEEDED' state.\n */\nexport default class Repeat extends Decorator {\n /**\n * @param attributes The node attributes.\n * @param iterations The number of iterations to repeat the child node.\n * @param iterationsMin The minimum possible number of iterations to repeat the child node.\n * @param iterationsMax The maximum possible number of iterations to repeat the child node.\n * @param child The child node.\n */\n constructor(\n attributes: Attribute[],\n private iterations: number | null,\n private iterationsMin: number | null,\n private iterationsMax: number | null,\n child: Node\n ) {\n super(\"repeat\", attributes, child);\n }\n\n /**\n * The number of target iterations to make.\n */\n private targetIterationCount: number | null = null;\n\n /**\n * The current iteration count.\n */\n private currentIterationCount: number = 0;\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // If this node is in the READY state then we need to reset the child and the target iteration count.\n if (this.is(State.READY)) {\n // Reset the child node.\n this.child.reset();\n\n // Reset the current iteration count.\n this.currentIterationCount = 0;\n\n // Set the target iteration count.\n this.setTargetIterationCount(options);\n }\n\n // Do a check to see if we can iterate. If we can then this node will move into the 'RUNNING' state.\n // If we cannot iterate then we have hit our target iteration count, which means that the node has succeeded.\n if (this.canIterate()) {\n // This node is in the running state and can do its initial iteration.\n this.setState(State.RUNNING);\n\n // We may have already completed an iteration, meaning that the child node will be in the SUCCEEDED state.\n // If this is the case then we will have to reset the child node now.\n if (this.child.getState() === State.SUCCEEDED) {\n this.child.reset();\n }\n\n // Update the child of this node.\n this.child.update(agent, options);\n\n // If the child moved into the FAILED state when we updated it then there is nothing left to do and this node has also failed.\n // If it has moved into the SUCCEEDED state then we have completed the current iteration.\n if (this.child.getState() === State.FAILED) {\n // The child has failed, meaning that this node has failed.\n this.setState(State.FAILED);\n\n return;\n } else if (this.child.getState() === State.SUCCEEDED) {\n // We have completed an iteration.\n this.currentIterationCount += 1;\n }\n } else {\n // This node is in the 'SUCCEEDED' state as we cannot iterate any more.\n this.setState(State.SUCCEEDED);\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => {\n if (this.iterations !== null) {\n return `REPEAT ${this.iterations}x`;\n } else if (this.iterationsMin !== null && this.iterationsMax !== null) {\n return `REPEAT ${this.iterationsMin}x-${this.iterationsMax}x`;\n } else {\n return \"REPEAT\";\n }\n };\n\n /**\n * Reset the state of the node.\n */\n reset = () => {\n // Reset the state of this node.\n this.setState(State.READY);\n\n // Reset the current iteration count.\n this.currentIterationCount = 0;\n\n // Reset the child node.\n this.child.reset();\n };\n\n /**\n * Gets whether an iteration can be made.\n * @returns Whether an iteration can be made.\n */\n private canIterate = () => {\n if (this.targetIterationCount !== null) {\n // We can iterate as long as we have not reached our target iteration count.\n return this.currentIterationCount < this.targetIterationCount;\n }\n\n // If neither an iteration count or a condition function were defined then we can iterate indefinitely.\n return true;\n };\n\n /**\n * Sets the target iteration count.\n * @param options The behaviour tree options object.\n */\n private setTargetIterationCount = (options: BehaviourTreeOptions) => {\n // Are we dealing with an explicit iteration count or will we be randomly picking a iteration count between the min and max iteration count.\n if (this.iterations !== null) {\n this.targetIterationCount = this.iterations;\n } else if (this.iterationsMin !== null && this.iterationsMax !== null) {\n // We will be picking a random iteration count between a min and max iteration count, if the optional 'random'\n // behaviour tree function option is defined then we will be using that, otherwise we will fall back to using Math.random.\n const random = typeof options.random === \"function\" ? options.random : Math.random;\n\n // Pick a random iteration count between a min and max iteration count.\n this.targetIterationCount = Math.floor(\n random() * (this.iterationsMax - this.iterationsMin + 1) + this.iterationsMin\n );\n } else {\n this.targetIterationCount = null;\n }\n };\n}\n", "import Node from \"../Node\";\nimport Decorator from \"./Decorator\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A RETRY node.\n * The node has a single child which can have:\n * -- A number of iterations for which to repeat the child node.\n * -- An infinite repeat loop if neither an iteration count or a condition function is defined.\n * The RETRY node will stop and have a 'SUCCEEDED' state if its child is ever in a 'SUCCEEDED' state after an update.\n * The RETRY node will attempt to move on to the next iteration if its child is ever in a 'FAILED' state.\n */\nexport default class Retry extends Decorator {\n /**\n * @param attributes The node attributes.\n * @param attempts The number of attempts to retry the child node.\n * @param attemptsMin The minimum possible number of attempts to retry the child node.\n * @param attemptsMax The maximum possible number of attempts to retry the child node.\n * @param child The child node.\n */\n constructor(\n attributes: Attribute[],\n private attempts: number | null,\n private attemptsMin: number | null,\n private attemptsMax: number | null,\n child: Node\n ) {\n super(\"retry\", attributes, child);\n }\n\n /**\n * The number of target attempts to make.\n */\n private targetAttemptCount: number | null = null;\n\n /**\n * The current attempt count.\n */\n private currentAttemptCount: number = 0;\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // If this node is in the READY state then we need to reset the child and the target attempt count.\n if (this.is(State.READY)) {\n // Reset the child node.\n this.child.reset();\n\n // Reset the current attempt count.\n this.currentAttemptCount = 0;\n\n // Set the target attempt count.\n this.setTargetAttemptCount(options);\n }\n\n // Do a check to see if we can attempt. If we can then this node will move into the 'RUNNING' state.\n // If we cannot attempt then we have hit our target attempt count, which means that the node has succeeded.\n if (this.canAttempt()) {\n // This node is in the running state and can do its initial attempt.\n this.setState(State.RUNNING);\n\n // We may have already completed an attempt, meaning that the child node will be in the FAILED state.\n // If this is the case then we will have to reset the child node now.\n if (this.child.getState() === State.FAILED) {\n this.child.reset();\n }\n\n // Update the child of this node.\n this.child.update(agent, options);\n\n // If the child moved into the SUCCEEDED state when we updated it then there is nothing left to do and this node has also succeeded.\n // If it has moved into the FAILED state then we have completed the current attempt.\n if (this.child.getState() === State.SUCCEEDED) {\n // The child has succeeded, meaning that this node has succeeded.\n this.setState(State.SUCCEEDED);\n\n return;\n } else if (this.child.getState() === State.FAILED) {\n // We have completed an attempt.\n this.currentAttemptCount += 1;\n }\n } else {\n // This node is in the 'FAILED' state as we cannot iterate any more.\n this.setState(State.FAILED);\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => {\n if (this.attempts !== null) {\n return `RETRY ${this.attempts}x`;\n } else if (this.attemptsMin !== null && this.attemptsMax !== null) {\n return `RETRY ${this.attemptsMin}x-${this.attemptsMax}x`;\n } else {\n return \"RETRY\";\n }\n };\n\n /**\n * Reset the state of the node.\n */\n reset = () => {\n // Reset the state of this node.\n this.setState(State.READY);\n\n // Reset the current attempt count.\n this.currentAttemptCount = 0;\n\n // Reset the child node.\n this.child.reset();\n };\n\n /**\n * Gets whether an attempt can be made.\n * @returns Whether an attempt can be made.\n */\n canAttempt = () => {\n if (this.targetAttemptCount !== null) {\n // We can attempt as long as we have not reached our target attempt count.\n return this.currentAttemptCount < this.targetAttemptCount;\n }\n\n // If neither an attempt count or a condition function were defined then we can attempt indefinitely.\n return true;\n };\n\n /**\n * Sets the target attempt count.\n * @param options The behaviour tree options object.\n */\n setTargetAttemptCount = (options: BehaviourTreeOptions) => {\n // Are we dealing with an explicit attempt count or will we be randomly picking an attempt count between the min and max attempt count.\n if (this.attempts !== null) {\n this.targetAttemptCount = this.attempts;\n } else if (this.attemptsMin !== null && this.attemptsMax !== null) {\n // We will be picking a random attempt count between a min and max attempt count, if the optional 'random'\n // behaviour tree function option is defined then we will be using that, otherwise we will fall back to using Math.random.\n const random = typeof options.random === \"function\" ? options.random : Math.random;\n\n // Pick a random attempt count between a min and max attempt count.\n this.targetAttemptCount = Math.floor(\n random() * (this.attemptsMax - this.attemptsMin + 1) + this.attemptsMin\n );\n } else {\n this.targetAttemptCount = null;\n }\n };\n}\n", "import Decorator from \"./Decorator\";\nimport State from \"../../State\";\nimport Node from \"../Node\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A Flip node.\n * This node wraps a single child and will flip the state of the child state.\n */\nexport default class Flip extends Decorator {\n /**\n * @param attributes The node attributes.\n * @param child The child node.\n */\n constructor(attributes: Attribute[], child: Node) {\n super(\"flip\", attributes, child);\n }\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // If the child has never been updated or is running then we will need to update it now.\n if (this.child.getState() === State.READY || this.child.getState() === State.RUNNING) {\n this.child.update(agent, options);\n }\n\n // The state of this node will depend in the state of its child.\n switch (this.child.getState()) {\n case State.RUNNING:\n this.setState(State.RUNNING);\n break;\n\n case State.SUCCEEDED:\n this.setState(State.FAILED);\n break;\n\n case State.FAILED:\n this.setState(State.SUCCEEDED);\n break;\n\n default:\n this.setState(State.READY);\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => \"FLIP\";\n}\n", "import Node from \"../Node\";\nimport Decorator from \"./Decorator\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A Succeed node.\n * This node wraps a single child and will always move to the 'SUCCEEDED' state when the child moves to a 'SUCCEEDED' or 'FAILED' state.\n */\nexport default class Succeed extends Decorator {\n /**\n * @param attributes The node attributes.\n * @param child The child node.\n */\n constructor(attributes: Attribute[], child: Node) {\n super(\"succeed\", attributes, child);\n }\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // If the child has never been updated or is running then we will need to update it now.\n if (this.child.getState() === State.READY || this.child.getState() === State.RUNNING) {\n this.child.update(agent, options);\n }\n\n // The state of this node will depend in the state of its child.\n switch (this.child.getState()) {\n case State.RUNNING:\n this.setState(State.RUNNING);\n break;\n\n case State.SUCCEEDED:\n case State.FAILED:\n this.setState(State.SUCCEEDED);\n break;\n\n default:\n this.setState(State.READY);\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => \"SUCCEED\";\n}\n", "import Node from \"../Node\";\nimport Decorator from \"./Decorator\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A Fail node.\n * This node wraps a single child and will always move to the 'FAILED' state when the child moves to a 'SUCCEEDED' or 'FAILED' state.\n */\nexport default class Fail extends Decorator {\n /**\n * @param attributes The node attributes.\n * @param child The child node.\n */\n constructor(attributes: Attribute[], child: Node) {\n super(\"fail\", attributes, child);\n }\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // If the child has never been updated or is running then we will need to update it now.\n if (this.child.getState() === State.READY || this.child.getState() === State.RUNNING) {\n this.child.update(agent, options);\n }\n\n // The state of this node will depend in the state of its child.\n switch (this.child.getState()) {\n case State.RUNNING:\n this.setState(State.RUNNING);\n break;\n\n case State.SUCCEEDED:\n case State.FAILED:\n this.setState(State.FAILED);\n break;\n\n default:\n this.setState(State.READY);\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => \"FAIL\";\n}\n", "import createLotto from \"lotto-draw\";\n\nimport Node from \"../Node\";\nimport Composite from \"./Composite\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A LOTTO node.\n * A winning child is picked on the initial update of this node, based on ticket weighting.\n * The state of this node will match the state of the winning child.\n */\nexport default class Lotto extends Composite {\n /**\n * @param attributes The node attributes.\n * @param tickets The child node tickets.\n * @param children The child nodes.\n */\n constructor(attributes: Attribute[], private tickets: number[], children: Node[]) {\n super(\"lotto\", attributes, children);\n }\n\n /**\n * The child node selected to be the active one.\n */\n private selectedChild: Node | undefined;\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // If this node is in the READY state then we need to pick a winning child node.\n if (this.is(State.READY)) {\n // Create a lotto draw with which to randomly pick a child node to become the active one.\n const lottoDraw = createLotto({\n // Hook up the optional 'random' behaviour tree function option to the one used by 'lotto-draw'.\n random: options.random,\n // Pass in each child node as a participant in the lotto draw with their respective ticket count.\n participants: this.children.map((child, index) => [child, this.tickets[index] || 1])\n });\n\n // Randomly pick a child based on ticket weighting, this will become the active child for this composite node.\n this.selectedChild = lottoDraw.draw() || undefined;\n }\n\n // If something went wrong and we don't have an active child then we should throw an error.\n if (!this.selectedChild) {\n throw new Error(\"failed to update lotto node as it has no active child\");\n }\n\n // If the selected child has never been updated or is running then we will need to update it now.\n if (this.selectedChild.getState() === State.READY || this.selectedChild.getState() === State.RUNNING) {\n this.selectedChild.update(agent, options);\n }\n\n // The state of the lotto node is the state of its selected child.\n this.setState(this.selectedChild.getState());\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => (this.tickets.length ? `LOTTO [${this.tickets.join(\",\")}]` : \"LOTTO\");\n}\n", "import Node from \"../Node\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\n\n/**\n * A composite node that wraps child nodes.\n */\nexport default abstract class Composite extends Node {\n /**\n * @param type The node type.\n * @param attributes The node attributes.\n * @param children The child nodes.\n */\n constructor(type: string, attributes: Attribute[], protected children: Node[]) {\n super(type, attributes, []);\n }\n\n /**\n * Gets whether this node is a leaf node.\n */\n isLeafNode = () => false;\n\n /**\n * Gets the children of this node.\n */\n getChildren = () => this.children;\n\n /**\n * Reset the state of the node.\n */\n reset = () => {\n // Reset the state of this node.\n this.setState(State.READY);\n\n // Reset the state of any child nodes.\n this.getChildren().forEach((child) => child.reset());\n };\n\n /**\n * Abort the running of this node.\n * @param agent The agent.\n */\n abort = (agent: Agent) => {\n // There is nothing to do if this node is not in the running state.\n if (!this.is(State.RUNNING)) {\n return;\n }\n\n // Abort any child nodes.\n this.getChildren().forEach((child) => child.abort(agent));\n\n // Reset the state of this node.\n this.reset();\n\n this.getAttribute(\"exit\")?.callAgentFunction(agent, false, true);\n };\n}\n", "import Composite from \"./Composite\";\nimport Node from \"../Node\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A SELECTOR node.\n * The child nodes are executed in sequence until one succeeds or all fail.\n */\nexport default class Selector extends Composite {\n /**\n * @param attributes The node attributes.\n * @param children The child nodes.\n */\n constructor(attributes: Attribute[], protected children: Node[]) {\n super(\"selector\", attributes, children);\n }\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // Iterate over all of the children of this node.\n for (const child of this.children) {\n // If the child has never been updated or is running then we will need to update it now.\n if (child.getState() === State.READY || child.getState() === State.RUNNING) {\n // Update the child of this node.\n child.update(agent, options);\n }\n\n // If the current child has a state of 'SUCCEEDED' then this node is also a 'SUCCEEDED' node.\n if (child.getState() === State.SUCCEEDED) {\n // This node is a 'SUCCEEDED' node.\n this.setState(State.SUCCEEDED);\n\n // There is no need to check the rest of the selector nodes.\n return;\n }\n\n // If the current child has a state of 'FAILED' then we should move on to the next child.\n if (child.getState() === State.FAILED) {\n // Find out if the current child is the last one in the selector.\n // If it is then this sequence node has also failed.\n if (this.children.indexOf(child) === this.children.length - 1) {\n // This node is a 'FAILED' node.\n this.setState(State.FAILED);\n\n // There is no need to check the rest of the selector as we have completed it.\n return;\n } else {\n // The child node failed, try the next one.\n continue;\n }\n }\n\n // The node should be in the 'RUNNING' state.\n if (child.getState() === State.RUNNING) {\n // This node is a 'RUNNING' node.\n this.setState(State.RUNNING);\n\n // There is no need to check the rest of the selector as the current child is still running.\n return;\n }\n\n // The child node was not in an expected state.\n throw new Error(\"child node was not in an expected state.\");\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => \"SELECTOR\";\n}\n", "import Composite from \"./Composite\";\nimport Node from \"../Node\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A SEQUENCE node.\n * The child nodes are executed in sequence until one fails or all succeed.\n */\nexport default class Sequence extends Composite {\n /**\n * @param attributes The node attributes.\n * @param children The child nodes.\n */\n constructor(attributes: Attribute[], protected children: Node[]) {\n super(\"sequence\", attributes, children);\n }\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // Iterate over all of the children of this node.\n for (const child of this.children) {\n // If the child has never been updated or is running then we will need to update it now.\n if (child.getState() === State.READY || child.getState() === State.RUNNING) {\n // Update the child of this node.\n child.update(agent, options);\n }\n\n // If the current child has a state of 'SUCCEEDED' then we should move on to the next child.\n if (child.getState() === State.SUCCEEDED) {\n // Find out if the current child is the last one in the sequence.\n // If it is then this sequence node has also succeeded.\n if (this.children.indexOf(child) === this.children.length - 1) {\n // This node is a 'SUCCEEDED' node.\n this.setState(State.SUCCEEDED);\n\n // There is no need to check the rest of the sequence as we have completed it.\n return;\n } else {\n // The child node succeeded, but we have not finished the sequence yet.\n continue;\n }\n }\n\n // If the current child has a state of 'FAILED' then this node is also a 'FAILED' node.\n if (child.getState() === State.FAILED) {\n // This node is a 'FAILED' node.\n this.setState(State.FAILED);\n\n // There is no need to check the rest of the sequence.\n return;\n }\n\n // The node should be in the 'RUNNING' state.\n if (child.getState() === State.RUNNING) {\n // This node is a 'RUNNING' node.\n this.setState(State.RUNNING);\n\n // There is no need to check the rest of the sequence as the current child is still running.\n return;\n }\n\n // The child node was not in an expected state.\n throw new Error(\"child node was not in an expected state.\");\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => \"SEQUENCE\";\n}\n", "import Composite from \"./Composite\";\nimport State from \"../../State\";\nimport Node from \"../Node\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A PARALLEL node.\n * The child nodes are executed concurrently until one fails or all succeed.\n */\nexport default class Parallel extends Composite {\n /**\n * @param attributes The node attributes.\n * @param children The child nodes.\n */\n constructor(attributes: Attribute[], children: Node[]) {\n super(\"parallel\", attributes, children);\n }\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // Keep a count of the number of succeeded child nodes.\n let succeededCount = 0;\n\n let hasChildFailed = false;\n\n // Iterate over all of the children of this node.\n for (const child of this.children) {\n // If the child has never been updated or is running then we will need to update it now.\n if (child.getState() === State.READY || child.getState() === State.RUNNING) {\n // Update the child of this node.\n child.update(agent, options);\n }\n\n // If the current child has a state of 'SUCCEEDED' then we should move on to the next child.\n if (child.getState() === State.SUCCEEDED) {\n // The child node has succeeded, keep track of this to determine if all children have.\n succeededCount++;\n\n // The child node succeeded, but we have not finished checking every child node yet.\n continue;\n }\n\n // If the current child has a state of 'FAILED' then this node is also a 'FAILED' node.\n if (child.getState() === State.FAILED) {\n hasChildFailed = true;\n\n // There is no need to check the rest of the children.\n break;\n }\n\n // The node should be in the 'RUNNING' state.\n if (child.getState() !== State.RUNNING) {\n // The child node was not in an expected state.\n throw new Error(\"child node was not in an expected state.\");\n }\n }\n\n if (hasChildFailed) {\n // This node is a 'FAILED' node.\n this.setState(State.FAILED);\n\n // Abort every running child.\n for (const child of this.children) {\n if (child.getState() === State.RUNNING) {\n child.abort(agent);\n }\n }\n } else {\n // If all children have succeeded then this node has also succeeded, otherwise it is still running.\n this.setState(succeededCount === this.children.length ? State.SUCCEEDED : State.RUNNING);\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => \"PARALLEL\";\n}\n", "import { AnyArgument } from \"../RootAstNodesBuilder\";\nimport Guard from \"./guards/Guard\";\n\nexport type AttributeDetails = {\n /** The attribute type. */\n type: string;\n\n /** The attribute arguments. */\n args: AnyArgument[];\n};\n\n/**\n * A base node attribute.\n */\nexport default abstract class Attribute {\n /**\n * @param type The node attribute type.\n * @param args The array of attribute argument definitions.\n */\n constructor(protected type: string, protected args: AnyArgument[]) {}\n\n /**\n * Gets the type of the attribute.\n */\n getType = () => this.type;\n\n /**\n * Gets the array of attribute argument definitions.\n */\n getArguments = () => this.args;\n\n /**\n * Gets the attribute details.\n */\n abstract getDetails(): TAttributeDetails;\n\n /**\n * Gets whether this attribute is a guard.\n */\n abstract isGuard: () => this is Guard;\n}\n", "import { Agent } from \"../../Agent\";\nimport { AnyArgument } from \"../../RootAstNodesBuilder\";\nimport Attribute, { AttributeDetails } from \"../Attribute\";\n\nexport type GuardAttributeDetails = {\n /** The name of the condition function that determines whether the guard is satisfied. */\n condition: string;\n} & AttributeDetails;\n\n/**\n * A base node guard attribute.\n */\nexport default abstract class Guard extends Attribute {\n /**\n * @param type The node attribute type.\n * @param args The array of decorator argument definitions.\n * @param condition The name of the condition function that determines whether the guard is satisfied.\n */\n constructor(type: string, args: AnyArgument[], private condition: string) {\n super(type, args);\n }\n\n /**\n * Gets the name of the condition function that determines whether the guard is satisfied.\n */\n getCondition = () => this.condition;\n\n /**\n * Gets whether this attribute is a guard.\n */\n isGuard = () => true;\n\n /**\n * Gets the attribute details.\n */\n getDetails(): GuardAttributeDetails {\n return {\n type: this.getType(),\n args: this.getArguments(),\n condition: this.getCondition()\n };\n }\n\n /**\n * Gets whether the guard is satisfied.\n * @param agent The agent.\n * @returns Whether the guard is satisfied.\n */\n abstract isSatisfied(agent: Agent): boolean;\n}\n", "import Guard from \"./Guard\";\nimport Lookup from \"../../Lookup\";\nimport { Agent } from \"../../Agent\";\nimport { AnyArgument } from \"../../RootAstNodesBuilder\";\n\n/**\n * A WHILE guard which is satisfied as long as the given condition remains true.\n */\nexport default class While extends Guard {\n /**\n * @param condition The name of the condition function that determines whether the guard is satisfied.\n * @param args The array of decorator argument definitions.\n */\n constructor(condition: string, args: AnyArgument[]) {\n super(\"while\", args, condition);\n }\n\n /**\n * Gets whether the guard is satisfied.\n * @param agent The agent.\n * @returns Whether the guard is satisfied.\n */\n isSatisfied = (agent: Agent) => {\n // Attempt to get the invoker for the condition function.\n const conditionFuncInvoker = Lookup.getFuncInvoker(agent, this.getCondition());\n\n // The condition function should be defined.\n if (conditionFuncInvoker === null) {\n throw new Error(\n `cannot evaluate node guard as the condition '${this.getCondition()}' function is not defined on the agent and has not been registered`\n );\n }\n\n // Call the condition function to determine whether this guard is satisfied.\n return !!conditionFuncInvoker(this.args);\n };\n}\n", "import Guard from \"./Guard\";\nimport Lookup from \"../../Lookup\";\nimport { Agent } from \"../../Agent\";\nimport { AnyArgument } from \"../../RootAstNodesBuilder\";\n\n/**\n * An UNTIL guard which is satisfied as long as the given condition remains false.\n */\nexport default class Until extends Guard {\n /**\n * @param condition The name of the condition function that determines whether the guard is satisfied.\n * @param args The array of decorator argument definitions.\n */\n constructor(condition: string, args: AnyArgument[]) {\n super(\"until\", args, condition);\n }\n\n /**\n * Gets whether the guard is satisfied.\n * @param agent The agent.\n * @returns Whether the guard is satisfied.\n */\n isSatisfied = (agent: Agent) => {\n // Attempt to get the invoker for the condition function.\n const conditionFuncInvoker = Lookup.getFuncInvoker(agent, this.getCondition());\n\n // The condition function should be defined.\n if (conditionFuncInvoker === null) {\n throw new Error(\n `cannot evaluate node guard as the condition '${this.getCondition()}' function is not defined on the agent and has not been registered`\n );\n }\n\n // Call the condition function to determine whether this guard is satisfied.\n return !!!conditionFuncInvoker(this.args);\n };\n}\n", "import { Agent } from \"../../Agent\";\nimport { AnyArgument } from \"../../RootAstNodesBuilder\";\nimport Attribute, { AttributeDetails } from \"../Attribute\";\n\nexport type CallbackAttributeDetails = {\n /** The name of the agent function that is called. */\n functionName: string;\n} & AttributeDetails;\n\n/**\n * A base node callback attribute.\n */\nexport default abstract class Callback extends Attribute {\n /**\n * @param type The node attribute type.\n * @param args The array of decorator argument definitions.\n * @param functionName The name of the agent function to call.\n */\n constructor(type: string, args: AnyArgument[], private functionName: string) {\n super(type, args);\n }\n\n /**\n * Gets the name of the agent function to call.\n */\n getFunctionName = () => this.functionName;\n\n /**\n * Gets whether this attribute is a guard.\n */\n isGuard = () => false;\n\n /**\n * Gets the attribute details.\n */\n getDetails(): CallbackAttributeDetails {\n return {\n type: this.getType(),\n args: this.getArguments(),\n functionName: this.getFunctionName()\n };\n }\n\n /**\n * Attempt to call the agent function that this callback refers to.\n * @param agent The agent.\n */\n abstract callAgentFunction: (agent: Agent, isSuccess: boolean, isAborted: boolean) => void;\n}\n", "import Callback from \"./Callback\";\nimport Lookup from \"../../Lookup\";\nimport { Agent } from \"../../Agent\";\nimport { AnyArgument } from \"../../RootAstNodesBuilder\";\n\n/**\n * An ENTRY callback which defines an agent function to call when the associated node is updated and moves out of running state.\n */\nexport default class Entry extends Callback {\n /**\n * @param functionName The name of the agent function to call.\n * @param args The array of callback argument definitions.\n */\n constructor(functionName: string, args: AnyArgument[]) {\n super(\"entry\", args, functionName);\n }\n\n /**\n * Attempt to call the agent function that this callback refers to.\n * @param agent The agent.\n */\n callAgentFunction = (agent: Agent) => {\n // Attempt to get the invoker for the callback function.\n const callbackFuncInvoker = Lookup.getFuncInvoker(agent, this.getFunctionName());\n\n // The callback function should be defined.\n if (callbackFuncInvoker === null) {\n throw new Error(\n `cannot call entry function '${this.getFunctionName()}' as is not defined on the agent and has not been registered`\n );\n }\n\n // Call the callback function.\n callbackFuncInvoker(this.args);\n };\n}\n", "import Callback from \"./Callback\";\nimport Lookup, { AnyExitArgument } from \"../../Lookup\";\nimport { Agent } from \"../../Agent\";\nimport { AnyArgument } from \"../../RootAstNodesBuilder\";\n\n/**\n * An EXIT callback which defines an agent function to call when the associated node is updated and moves to a finished state or is aborted.\n */\nexport default class Exit extends Callback {\n /**\n * @param functionName The name of the agent function to call.\n * @param args The array of callback argument definitions.\n */\n constructor(functionName: string, args: AnyArgument[]) {\n super(\"exit\", args, functionName);\n }\n\n /**\n * Attempt to call the agent function that this callback refers to.\n * @param agent The agent.\n * @param isSuccess Whether the decorated node was left with a success state.\n * @param isAborted Whether the decorated node was aborted.\n */\n callAgentFunction = (agent: Agent, isSuccess: boolean, isAborted: boolean) => {\n // Attempt to get the invoker for the callback function.\n const callbackFuncInvoker = Lookup.getFuncInvoker(agent, this.getFunctionName());\n\n // The callback function should be defined.\n if (callbackFuncInvoker === null) {\n throw new Error(\n `cannot call exit function '${this.getFunctionName()}' as is not defined on the agent and has not been registered`\n );\n }\n\n // Call the callback function\n callbackFuncInvoker([{ value: { succeeded: isSuccess, aborted: isAborted } }, ...this.args]);\n };\n}\n", "import Callback from \"./Callback\";\nimport Lookup from \"../../Lookup\";\nimport { Agent } from \"../../Agent\";\nimport { AnyArgument } from \"../../RootAstNodesBuilder\";\n\n/**\n * A STEP callback which defines an agent function to call when the associated node is updated.\n */\nexport default class Step extends Callback {\n /**\n * @param functionName The name of the agent function to call.\n * @param args The array of callback argument definitions.\n */\n constructor(functionName: string, args: AnyArgument[]) {\n super(\"step\", args, functionName);\n }\n\n /**\n * Attempt to call the agent function that this callback refers to.\n * @param agent The agent.\n */\n callAgentFunction = (agent: Agent) => {\n // Attempt to get the invoker for the callback function.\n const callbackFuncInvoker = Lookup.getFuncInvoker(agent, this.getFunctionName());\n\n // The callback function should be defined.\n if (callbackFuncInvoker === null) {\n throw new Error(\n `cannot call step function '${this.getFunctionName()}' as is not defined on the agent and has not been registered`\n );\n }\n\n // Call the callback function.\n callbackFuncInvoker(this.args);\n };\n}\n", "import Action from \"./nodes/leaf/Action\";\nimport Condition from \"./nodes/leaf/Condition\";\nimport Wait from \"./nodes/leaf/Wait\";\nimport Root from \"./nodes/decorator/Root\";\nimport Repeat from \"./nodes/decorator/Repeat\";\nimport Retry from \"./nodes/decorator/Retry\";\nimport Flip from \"./nodes/decorator/Flip\";\nimport Succeed from \"./nodes/decorator/Succeed\";\nimport Fail from \"./nodes/decorator/Fail\";\nimport Lotto from \"./nodes/composite/Lotto\";\nimport Selector from \"./nodes/composite/Selector\";\nimport Sequence from \"./nodes/composite/Sequence\";\nimport Parallel from \"./nodes/composite/Parallel\";\nimport Node from \"./nodes/Node\";\nimport While from \"./attributes/guards/While\";\nimport Until from \"./attributes/guards/Until\";\nimport Entry from \"./attributes/callbacks/Entry\";\nimport Exit from \"./attributes/callbacks/Exit\";\nimport Step from \"./attributes/callbacks/Step\";\nimport Callback from \"./attributes/callbacks/Callback\";\nimport Guard from \"./attributes/guards/Guard\";\nimport Attribute from \"./attributes/Attribute\";\nimport Composite from \"./nodes/composite/Composite\";\nimport Decorator from \"./nodes/decorator/Decorator\";\nimport Leaf from \"./nodes/leaf/Leaf\";\n\nexport type Argument = {\n value: T;\n type: string; // Used for validation.\n};\ntype NullArgument = Argument & {\n type: \"null\";\n};\ntype BooleanArgument = Argument & {\n type: \"boolean\";\n};\ntype NumberArgument = Argument & {\n type: \"number\";\n isInteger: boolean; // Used for validation.\n};\ntype StringPlaceholderArgument = Argument & {\n type: \"string\";\n};\ntype IdentifierArgument = Argument & {\n type: \"identifier\";\n};\nexport type AnyArgument =\n | NullArgument\n | BooleanArgument\n | NumberArgument\n | StringPlaceholderArgument\n | IdentifierArgument;\n\n/**\n * The node attribute factories.\n */\nconst AttributeFactories: {\n [key: string]: (functionName: string, attributeArguments: AnyArgument[]) => Callback | Guard;\n} = {\n WHILE: (condition: string, attributeArguments: AnyArgument[]) => new While(condition, attributeArguments),\n UNTIL: (condition: string, attributeArguments: AnyArgument[]) => new Until(condition, attributeArguments),\n ENTRY: (functionName: string, attributeArguments: AnyArgument[]) => new Entry(functionName, attributeArguments),\n EXIT: (functionName: string, attributeArguments: AnyArgument[]) => new Exit(functionName, attributeArguments),\n STEP: (functionName: string, attributeArguments: AnyArgument[]) => new Step(functionName, attributeArguments)\n};\n\ntype Validatable = {\n children?: AstNode[];\n validate: (depth: number) => void;\n};\n\ntype NodeInstanceCreator = (\n namedRootNodeProvider: (name: string) => RootAstNode,\n visitedBranches: string[]\n) => T;\n\nexport type AstNode = Validatable & {\n type: string;\n createNodeInstance: NodeInstanceCreator;\n};\n\nexport type LeafAstNode = AstNode & {\n type: \"action\" | \"condition\" | \"wait\";\n attributes: Attribute[];\n};\n\nexport type CompositeAstNode = AstNode & {\n type: \"lotto\" | \"parallel\" | \"selector\" | \"sequence\";\n attributes: Attribute[];\n children: AstNode[];\n};\n\nexport type DecoratorAstNode = AstNode & {\n type: \"fail\" | \"flip\" | \"repeat\" | \"retry\" | \"root\" | \"succeed\";\n attributes: Attribute[];\n children: AstNode[];\n};\n\nexport type BranchAstNode = AstNode & {\n type: \"branch\";\n branchName: \"\" | string;\n};\n\nexport type LottoAstNode = CompositeAstNode & {\n type: \"lotto\";\n tickets: number[];\n};\n\nexport type RootAstNode = DecoratorAstNode & {\n type: \"root\";\n name: null | string;\n};\n\nexport type RepeatAstNode = DecoratorAstNode & {\n type: \"repeat\";\n iterations: number | null;\n iterationsMin: number | null;\n iterationsMax: number | null;\n};\n\nexport type RetryAstNode = DecoratorAstNode & {\n type: \"retry\";\n attempts: number | null;\n attemptsMin: number | null;\n attemptsMax: number | null;\n};\n\nexport type ActionAstNode = LeafAstNode & {\n type: \"action\";\n actionName: string;\n actionArguments: AnyArgument[];\n};\n\nexport type ConditionAstNode = LeafAstNode & {\n type: \"condition\";\n conditionName: string;\n conditionArguments: AnyArgument[];\n};\n\nexport type WaitAstNode = LeafAstNode & {\n type: \"wait\";\n duration: number | null;\n durationMin: number | null;\n durationMax: number | null;\n};\n\nexport type AnyAstNode =\n | BranchAstNode\n | CompositeAstNode\n | LottoAstNode\n | DecoratorAstNode\n | RootAstNode\n | RepeatAstNode\n | RetryAstNode\n | LeafAstNode\n | ActionAstNode\n | ConditionAstNode\n | WaitAstNode;\n\n/**\n * The AST node factories.\n */\nconst ASTNodeFactories = {\n ROOT: (): RootAstNode => ({\n type: \"root\",\n attributes: [],\n name: null,\n children: [],\n validate(depth: number) {\n // A root node cannot be the child of another node.\n if (depth > 1) {\n throw new Error(\"a root node cannot be the child of another node\");\n }\n\n // A root node must have a single child node.\n if (this.children.length !== 1) {\n throw new Error(\"a root node must have a single child\");\n }\n },\n createNodeInstance(namedRootNodeProvider, visitedBranches) {\n return new Root(\n this.attributes,\n this.children![0].createNodeInstance(namedRootNodeProvider, visitedBranches.slice())\n );\n }\n }),\n BRANCH: (): BranchAstNode => ({\n type: \"branch\",\n branchName: \"\",\n validate() {},\n createNodeInstance(namedRootNodeProvider, visitedBranches) {\n // Try to find the root node with a matching branch name.\n const targetRootNode = namedRootNodeProvider(this.branchName);\n\n // If we have already visited this branch then we have a circular dependency.\n if (visitedBranches.indexOf(this.branchName) !== -1) {\n throw new Error(`circular dependency found in branch node references for branch '${this.branchName}'`);\n }\n\n // If we have a target root node, then the node instance we want will be the first and only child of the referenced root node.\n if (targetRootNode) {\n return targetRootNode\n .createNodeInstance(namedRootNodeProvider, visitedBranches.concat(this.branchName))\n .getChildren()[0];\n } else {\n throw new Error(`branch references root node '${this.branchName}' which has not been defined`);\n }\n }\n }),\n SELECTOR: (): CompositeAstNode => ({\n type: \"selector\",\n attributes: [],\n children: [],\n validate() {\n // A selector node must have at least a single node.\n if (this.children.length < 1) {\n throw new Error(\"a selector node must have at least a single child\");\n }\n },\n createNodeInstance(namedRootNodeProvider, visitedBranches) {\n return new Selector(\n this.attributes,\n this.children.map((child) => child.createNodeInstance(namedRootNodeProvider, visitedBranches.slice()))\n );\n }\n }),\n SEQUENCE: (): CompositeAstNode => ({\n type: \"sequence\",\n attributes: [],\n children: [],\n validate() {\n // A sequence node must have at least a single node.\n if (this.children.length < 1) {\n throw new Error(\"a sequence node must have at least a single child\");\n }\n },\n createNodeInstance(namedRootNodeProvider, visitedBranches) {\n return new Sequence(\n this.attributes,\n this.children.map((child) => child.createNodeInstance(namedRootNodeProvider, visitedBranches.slice()))\n );\n }\n }),\n PARALLEL: (): CompositeAstNode => ({\n type: \"parallel\",\n attributes: [],\n children: [],\n validate() {\n // A parallel node must have at least a single node.\n if (this.children.length < 1) {\n throw new Error(\"a parallel node must have at least a single child\");\n }\n },\n createNodeInstance(namedRootNodeProvider, visitedBranches) {\n return new Parallel(\n this.attributes,\n this.children.map((child) => child.createNodeInstance(namedRootNodeProvider, visitedBranches.slice()))\n );\n }\n }),\n LOTTO: (): LottoAstNode => ({\n type: \"lotto\",\n attributes: [],\n children: [],\n tickets: [],\n validate() {\n // A lotto node must have at least a single node.\n if (this.children!.length < 1) {\n throw new Error(\"a lotto node must have at least a single child\");\n }\n },\n createNodeInstance(namedRootNodeProvider, visitedBranches) {\n return new Lotto(\n this.attributes,\n this.tickets!,\n this.children!.map((child) => child.createNodeInstance(namedRootNodeProvider, visitedBranches.slice()))\n );\n }\n }),\n REPEAT: (): RepeatAstNode => ({\n type: \"repeat\",\n attributes: [],\n iterations: null,\n iterationsMin: null,\n iterationsMax: null,\n children: [],\n validate() {\n // A repeat node must have a single node.\n if (this.children!.length !== 1) {\n throw new Error(\"a repeat node must have a single child\");\n }\n\n if (this.iterations !== null) {\n // A repeat node must have a positive number of iterations if defined.\n if (this.iterations < 0) {\n throw new Error(\"a repeat node must have a positive number of iterations if defined\");\n }\n } else if (this.iterationsMin !== null && this.iterationsMax !== null) {\n // A repeat node must have a positive min and max iteration count if they are defined.\n if (this.iterationsMin < 0 || this.iterationsMax < 0) {\n throw new Error(\n \"a repeat node must have a positive minimum and maximum iteration count if defined\"\n );\n }\n\n // A repeat node must not have an minimum iteration count that exceeds the maximum iteration count.\n if (this.iterationsMin > this.iterationsMax) {\n throw new Error(\n \"a repeat node must not have a minimum iteration count that exceeds the maximum iteration count\"\n );\n }\n } else {\n // If we have no explicit iteration count or a minimum and maximum iteration count set then we are dealing with a repeat node that iterates indefinitely.\n }\n },\n createNodeInstance(namedRootNodeProvider, visitedBranches) {\n return new Repeat(\n this.attributes,\n this.iterations,\n this.iterationsMin,\n this.iterationsMax,\n this.children![0].createNodeInstance(namedRootNodeProvider, visitedBranches.slice())\n );\n }\n }),\n RETRY: (): RetryAstNode => ({\n type: \"retry\",\n attributes: [],\n attempts: null,\n attemptsMin: null,\n attemptsMax: null,\n children: [],\n validate() {\n // A retry node must have a single node.\n if (this.children!.length !== 1) {\n throw new Error(\"a retry node must have a single child\");\n }\n\n if (this.attempts !== null) {\n // A retry node must have a positive number of attempts if defined.\n if (this.attempts < 0) {\n throw new Error(\"a retry node must have a positive number of attempts if defined\");\n }\n } else if (this.attemptsMin !== null && this.attemptsMax !== null) {\n // A retry node must have a positive min and max attempts count if they are defined.\n if (this.attemptsMin < 0 || this.attemptsMax < 0) {\n throw new Error(\"a retry node must have a positive minimum and maximum attempt count if defined\");\n }\n\n // A retry node must not have a minimum attempt count that exceeds the maximum attempt count.\n if (this.attemptsMin > this.attemptsMax) {\n throw new Error(\n \"a retry node must not have a minimum attempt count that exceeds the maximum attempt count\"\n );\n }\n } else {\n // If we have no explicit attempt count or a minimum and maximum attempt count set then we are dealing with a retry node that attempts indefinitely.\n }\n },\n createNodeInstance(namedRootNodeProvider, visitedBranches) {\n return new Retry(\n this.attributes,\n this.attempts,\n this.attemptsMin,\n this.attemptsMax,\n this.children![0].createNodeInstance(namedRootNodeProvider, visitedBranches.slice())\n );\n }\n }),\n FLIP: (): DecoratorAstNode => ({\n type: \"flip\",\n attributes: [],\n children: [],\n validate() {\n // A flip node must have a single node.\n if (this.children!.length !== 1) {\n throw new Error(\"a flip node must have a single child\");\n }\n },\n createNodeInstance(namedRootNodeProvider, visitedBranches) {\n return new Flip(\n this.attributes,\n this.children![0].createNodeInstance(namedRootNodeProvider, visitedBranches.slice())\n );\n }\n }),\n SUCCEED: (): DecoratorAstNode => ({\n type: \"succeed\",\n attributes: [],\n children: [],\n validate() {\n // A succeed node must have a single node.\n if (this.children!.length !== 1) {\n throw new Error(\"a succeed node must have a single child\");\n }\n },\n createNodeInstance(namedRootNodeProvider, visitedBranches) {\n return new Succeed(\n this.attributes,\n this.children![0].createNodeInstance(namedRootNodeProvider, visitedBranches.slice())\n );\n }\n }),\n FAIL: (): DecoratorAstNode => ({\n type: \"fail\",\n attributes: [],\n children: [],\n validate() {\n // A fail node must have a single node.\n if (this.children!.length !== 1) {\n throw new Error(\"a fail node must have a single child\");\n }\n },\n createNodeInstance(namedRootNodeProvider, visitedBranches) {\n return new Fail(\n this.attributes,\n this.children![0].createNodeInstance(namedRootNodeProvider, visitedBranches.slice())\n );\n }\n }),\n WAIT: (): WaitAstNode => ({\n type: \"wait\",\n attributes: [],\n duration: null,\n durationMin: null,\n durationMax: null,\n validate() {\n if (this.duration !== null) {\n // If an explict duration was defined then it must be a positive number.\n if (this.duration < 0) {\n throw new Error(\"a wait node must have a positive duration\");\n }\n } else if (this.durationMin !== null && this.durationMax !== null) {\n // A wait node must have a positive min and max duration.\n if (this.durationMin < 0 || this.durationMax < 0) {\n throw new Error(\"a wait node must have a positive minimum and maximum duration\");\n }\n\n // A wait node must not have a minimum duration that exceeds the maximum duration.\n if (this.durationMin > this.durationMax) {\n throw new Error(\"a wait node must not have a minimum duration that exceeds the maximum duration\");\n }\n } else {\n // If we have no explicit duration or duration bounds set then we are dealing with a wait node that waits indefinitely.\n }\n },\n createNodeInstance() {\n return new Wait(this.attributes, this.duration, this.durationMin, this.durationMax);\n }\n }),\n ACTION: (): ActionAstNode => ({\n type: \"action\",\n attributes: [],\n actionName: \"\",\n actionArguments: [],\n validate() {},\n createNodeInstance() {\n return new Action(this.attributes, this.actionName!, this.actionArguments!);\n }\n }),\n CONDITION: (): ConditionAstNode => ({\n type: \"condition\",\n attributes: [],\n conditionName: \"\",\n conditionArguments: [],\n validate() {},\n createNodeInstance() {\n return new Condition(this.attributes, this.conditionName!, this.conditionArguments!);\n }\n })\n};\n\ntype OtherAstNodes = AstNode[];\n\n/**\n * Create an array of root AST nodes based on the given definition.\n * @param definition The definition to parse the AST nodes from.\n * @returns The base definition AST nodes.\n */\nexport default function buildRootASTNodes(definition: string): RootAstNode[] {\n // Swap out any node/attribute argument string literals with a placeholder and get a mapping of placeholders to original values as well as the processed definition.\n const { placeholders, processedDefinition } = substituteStringLiterals(definition);\n\n // Convert the processed definition (with substituted string literals) into an array of raw tokens.\n const tokens = parseTokensFromDefinition(processedDefinition);\n\n // There must be at least 3 tokens for the tree definition to be valid. 'ROOT', '{' and '}'.\n if (tokens.length < 3) {\n throw new Error(\"invalid token count\");\n }\n\n // We should have a matching number of '{' and '}' tokens. If not, then there are scopes that have not been properly closed.\n if (tokens.filter((token) => token === \"{\").length !== tokens.filter((token) => token === \"}\").length) {\n throw new Error(\"scope character mismatch\");\n }\n\n // Create a stack of node children arrays, starting with a definition scope.\n const stack: [RootAstNode[], ...OtherAstNodes[]] = [[]];\n const rootScope = stack[0];\n\n // We should keep processing the raw tokens until we run out of them.\n while (tokens.length) {\n // Grab the next token.\n const token = tokens.shift();\n\n const currentScope = stack[stack.length - 1] as OtherAstNodes;\n\n // How we create the next AST token depends on the current raw token value.\n switch (token!.toUpperCase()) {\n case \"ROOT\": {\n // Create a ROOT AST node.\n const node = ASTNodeFactories.ROOT();\n\n // Push the ROOT node into the current scope.\n rootScope.push(node);\n\n // We may have a root node name defined as an argument.\n if (tokens[0] === \"[\") {\n const rootArguments = getArguments(tokens, placeholders);\n\n // We should have only a single argument that is not an empty string for a root node, which is the root name identifier.\n if (rootArguments.length === 1 && rootArguments[0].type === \"identifier\") {\n // The root name will be the first and only node argument.\n node.name = rootArguments[0].value as string;\n } else {\n throw new Error(\"expected single root name argument\");\n }\n }\n\n // Try to pick any attributes off of the token stack.\n node.attributes = getAttributes(tokens, placeholders);\n\n popAndCheck(tokens, \"{\");\n\n // The new scope is that of the new ROOT nodes children.\n stack.push(node.children!);\n break;\n }\n\n case \"BRANCH\": {\n // Create a BRANCH AST node.\n const node = ASTNodeFactories.BRANCH();\n\n // Push the BRANCH node into the current scope.\n currentScope.push(node);\n\n // We must have arguments defined, as we require a branch name argument.\n if (tokens[0] !== \"[\") {\n throw new Error(\"expected single branch name argument\");\n }\n\n // The branch name will be defined as a node argument.\n const branchArguments = getArguments(tokens, placeholders);\n\n // We should have only a single identifer argument for a branch node, which is the branch name.\n if (branchArguments.length === 1 && branchArguments[0].type === \"identifier\") {\n // The branch name will be the first and only node argument.\n node.branchName = branchArguments[0].value as string;\n } else {\n throw new Error(\"expected single branch name argument\");\n }\n break;\n }\n\n case \"SELECTOR\": {\n // Create a SELECTOR AST node.\n const node = ASTNodeFactories.SELECTOR();\n\n // Push the SELECTOR node into the current scope.\n currentScope.push(node);\n\n // Try to pick any attributes off of the token stack.\n node.attributes = getAttributes(tokens, placeholders);\n\n popAndCheck(tokens, \"{\");\n\n // The new scope is that of the new SELECTOR nodes children.\n stack.push(node.children!);\n break;\n }\n\n case \"SEQUENCE\": {\n // Create a SEQUENCE AST node.\n const node = ASTNodeFactories.SEQUENCE();\n\n // Push the SEQUENCE node into the current scope.\n currentScope.push(node);\n\n // Try to pick any attributes off of the token stack.\n node.attributes = getAttributes(tokens, placeholders);\n\n popAndCheck(tokens, \"{\");\n\n // The new scope is that of the new SEQUENCE nodes children.\n stack.push(node.children!);\n break;\n }\n\n case \"PARALLEL\": {\n // Create a PARALLEL AST node.\n const node = ASTNodeFactories.PARALLEL();\n\n // Push the PARALLEL node into the current scope.\n currentScope.push(node);\n\n // Try to pick any attributes off of the token stack.\n node.attributes = getAttributes(tokens, placeholders);\n\n popAndCheck(tokens, \"{\");\n\n // The new scope is that of the new PARALLEL nodes children.\n stack.push(node.children!);\n break;\n }\n\n case \"LOTTO\": {\n // Create a LOTTO AST node.\n const node = ASTNodeFactories.LOTTO();\n\n // Push the LOTTO node into the current scope.\n currentScope.push(node);\n\n // If the next token is a '[' character then some ticket counts have been defined as arguments.\n if (tokens[0] === \"[\") {\n // Get the ticket count arguments, each argument must be a number.\n node.tickets = getArguments(\n tokens,\n placeholders,\n (arg) => arg.type === \"number\" && !!arg.isInteger,\n \"lotto node ticket counts must be integer values\"\n ).map((argument) => argument.value as number);\n }\n\n // Try to pick any attributes off of the token stack.\n node.attributes = getAttributes(tokens, placeholders);\n\n popAndCheck(tokens, \"{\");\n\n // The new scope is that of the new LOTTO nodes children.\n stack.push(node.children!);\n break;\n }\n\n case \"CONDITION\": {\n // Create a CONDITION AST node.\n const node = ASTNodeFactories.CONDITION();\n\n // Push the CONDITION node into the current scope.\n currentScope.push(node);\n\n // We must have arguments defined, as we require a condition function name argument.\n if (tokens[0] !== \"[\") {\n throw new Error(\"expected condition name identifier argument\");\n }\n\n // Grab the condition node arguments.\n const conditionArguments = getArguments(tokens, placeholders);\n\n // We should have at least a single identifier argument for a condition node, which is the condition function name.\n if (conditionArguments.length && conditionArguments[0].type === \"identifier\") {\n // The condition function name will be the first node argument.\n node.conditionName = conditionArguments.shift()!.value as string;\n } else {\n throw new Error(\"expected condition name identifier argument\");\n }\n\n // Only the first argument should have been an identifier, all following arguments must be string, number, boolean or null.\n conditionArguments\n .filter((arg) => arg.type === \"identifier\")\n .forEach((arg) => {\n throw new Error(\n \"invalid condition node argument value '\" +\n arg.value +\n \"', must be string, number, boolean or null\"\n );\n });\n\n // Any node arguments that follow the condition name identifier will be treated as condition function arguments.\n node.conditionArguments = conditionArguments;\n\n // Try to pick any attributes off of the token stack.\n node.attributes = getAttributes(tokens, placeholders);\n break;\n }\n\n case \"FLIP\": {\n // Create a FLIP AST node.\n const node = ASTNodeFactories.FLIP();\n\n // Push the Flip node into the current scope.\n currentScope.push(node);\n\n // Try to pick any attributes off of the token stack.\n node.attributes = getAttributes(tokens, placeholders);\n\n popAndCheck(tokens, \"{\");\n\n // The new scope is that of the new FLIP nodes children.\n stack.push(node.children!);\n break;\n }\n\n case \"SUCCEED\": {\n // Create a SUCCEED AST node.\n const node = ASTNodeFactories.SUCCEED();\n\n // Push the Succeed node into the current scope.\n currentScope.push(node);\n\n // Try to pick any attributes off of the token stack.\n node.attributes = getAttributes(tokens, placeholders);\n\n popAndCheck(tokens, \"{\");\n\n // The new scope is that of the new Succeed nodes children.\n stack.push(node.children!);\n break;\n }\n\n case \"FAIL\": {\n // Create a FAIL AST node.\n const node = ASTNodeFactories.FAIL();\n\n // Push the Fail node into the current scope.\n currentScope.push(node);\n\n // Try to pick any attributes off of the token stack.\n node.attributes = getAttributes(tokens, placeholders);\n\n popAndCheck(tokens, \"{\");\n\n // The new scope is that of the new Fail nodes children.\n stack.push(node.children!);\n break;\n }\n\n case \"WAIT\": {\n // Create a WAIT AST node.\n const node = ASTNodeFactories.WAIT();\n\n // Push the WAIT node into the current scope.\n currentScope.push(node);\n\n // The arguments of a wait node are optional. We may have:\n // - No node arguments, in which case the wait will be indefinite until it is aborted.\n // - One node argument which will be the explicit duration of the wait.\n // - Two node arguments which define the min and max duration bounds from which a random duration will be picked.\n if (tokens[0] === \"[\") {\n // Get the optional duration and longest duration of the wait.\n const nodeArguments = getArguments(\n tokens,\n placeholders,\n (arg) => arg.type === \"number\" && !!arg.isInteger,\n \"wait node durations must be integer values\"\n ).map((argument) => argument.value);\n\n // We may have:\n // - One node argument which will be the explicit duration of the wait.\n // - Two node arguments which define the min and max duration bounds from which a random duration will be picked.\n // - Too many arguments, which is not valid.\n if (nodeArguments.length === 1) {\n // An explicit duration was defined.\n node.duration = nodeArguments[0] as number;\n } else if (nodeArguments.length === 2) {\n // Min and max duration bounds were defined from which a random duration will be picked.\n node.durationMin = nodeArguments[0] as number;\n node.durationMax = nodeArguments[1] as number;\n } else if (nodeArguments.length > 2) {\n // An incorrect number of durations was defined.\n throw new Error(\"invalid number of wait node duration arguments defined\");\n }\n }\n\n // Try to pick any attributes off of the token stack.\n node.attributes = getAttributes(tokens, placeholders);\n break;\n }\n\n case \"REPEAT\": {\n // Create a REPEAT AST node.\n const node = ASTNodeFactories.REPEAT();\n\n // Push the REPEAT node into the current scope.\n currentScope.push(node);\n\n // The arguments of a repeat node are optional. We may have:\n // - No node arguments, in which case the repeat note will iterate indefinitely.\n // - One node argument which will be the explicit number of iterations to make.\n // - Two node arguments which define the min and max iteration bounds from which a random iteration count will be picked.\n if (tokens[0] === \"[\") {\n // An iteration count has been defined. Get the iteration and potential maximum iteration of the wait.\n const nodeArguments = getArguments(\n tokens,\n placeholders,\n (arg) => arg.type === \"number\" && !!arg.isInteger,\n \"repeat node iteration counts must be integer values\"\n ).map((argument) => argument.value);\n\n // We should have got one or two iteration counts.\n if (nodeArguments.length === 1) {\n // A static iteration count was defined.\n node.iterations = nodeArguments[0] as number;\n } else if (nodeArguments.length === 2) {\n // A minimum and maximum iteration count was defined.\n node.iterationsMin = nodeArguments[0] as number;\n node.iterationsMax = nodeArguments[1] as number;\n } else {\n // An incorrect number of iteration counts was defined.\n throw new Error(\"invalid number of repeat node iteration count arguments defined\");\n }\n }\n\n // Try to pick any attributes off of the token stack.\n node.attributes = getAttributes(tokens, placeholders);\n\n popAndCheck(tokens, \"{\");\n\n // The new scope is that of the new REPEAT nodes children.\n stack.push(node.children!);\n break;\n }\n\n case \"RETRY\": {\n // Create a RETRY AST node.\n const node = ASTNodeFactories.RETRY();\n\n // Push the RETRY node into the current scope.\n currentScope.push(node);\n\n // The arguments of a retry node are optional. We may have:\n // - No node arguments, in which case the retry note will attempt indefinitely.\n // - One node argument which will be the explicit number of attempts to make.\n // - Two node arguments which define the min and max attempt bounds from which a random attempt count will be picked.\n if (tokens[0] === \"[\") {\n // An attempt count has been defined. Get the attempt count and potential maximum attempt count of the wait.\n const nodeArguments = getArguments(\n tokens,\n placeholders,\n (arg) => arg.type === \"number\" && !!arg.isInteger,\n \"retry node attempt counts must be integer values\"\n ).map((argument) => argument.value);\n\n // We should have got one or two attempt counts.\n if (nodeArguments.length === 1) {\n // A static attempt count was defined.\n node.attempts = nodeArguments[0] as number;\n } else if (nodeArguments.length === 2) {\n // A minimum and maximum attempt count was defined.\n node.attemptsMin = nodeArguments[0] as number;\n node.attemptsMax = nodeArguments[1] as number;\n } else {\n // An incorrect number of attempt counts was defined.\n throw new Error(\"invalid number of retry node attempt count arguments defined\");\n }\n }\n\n // Try to pick any attributes off of the token stack.\n node.attributes = getAttributes(tokens, placeholders);\n\n popAndCheck(tokens, \"{\");\n\n // The new scope is that of the new RETRY nodes children.\n stack.push(node.children!);\n break;\n }\n\n case \"ACTION\": {\n // Create a ACTION AST node.\n const node = ASTNodeFactories.ACTION();\n\n // Push the ACTION node into the current scope.\n currentScope.push(node);\n\n // We must have arguments defined, as we require an action name argument.\n if (tokens[0] !== \"[\") {\n throw new Error(\"expected action name identifier argument\");\n }\n\n // The action name will be defined as a node argument.\n const actionArguments = getArguments(tokens, placeholders);\n\n // We should have at least one identifer argument for an action node, which is the action name.\n if (actionArguments.length && actionArguments[0].type === \"identifier\") {\n // The action name will be the first and only node argument.\n node.actionName = actionArguments.shift()!.value as string;\n } else {\n throw new Error(\"expected action name identifier argument\");\n }\n\n // Only the first argument should have been an identifier, all following arguments must be string, number, boolean or null.\n actionArguments\n .filter((arg) => arg.type === \"identifier\")\n .forEach((arg) => {\n throw new Error(\n \"invalid action node argument value '\" +\n arg.value +\n \"', must be string, number, boolean or null\"\n );\n });\n\n // Any node arguments that follow the action name identifier will be treated as action function arguments.\n node.actionArguments = actionArguments;\n\n // Try to pick any attributes off of the token stack.\n node.attributes = getAttributes(tokens, placeholders);\n break;\n }\n\n case \"}\": {\n // The '}' character closes the current scope.\n stack.pop();\n break;\n }\n\n default: {\n throw new Error(`unexpected token '${token}'`);\n }\n }\n }\n\n // A function to recursively validate each of the nodes in the AST.\n const validateASTNode = (node: Validatable, depth: number): void => {\n // Validate the node.\n node.validate(depth);\n\n // Validate each child of the node.\n (node.children || []).forEach((child) => validateASTNode(child, depth + 1));\n };\n\n // Start node validation from the definition root.\n validateASTNode(\n {\n children: stack[0] as RootAstNode[],\n validate(this: { children: RootAstNode[] }) {\n // We must have at least one node defined as the definition scope, which should be a root node.\n if (this.children.length === 0) {\n throw new Error(\"expected root node to have been defined\");\n }\n\n // Each node at the base of the definition scope MUST be a root node.\n for (const definitionLevelNode of this.children) {\n if (definitionLevelNode.type !== \"root\") {\n throw new Error(\"expected root node at base of definition\");\n }\n }\n\n // Exactly one root node must not have a name defined. This will be the main root, others will have to be referenced via branch nodes.\n if (this.children.filter((definitionLevelNode) => definitionLevelNode.name === null).length !== 1) {\n throw new Error(\"expected single unnamed root node at base of definition to act as main root\");\n }\n\n // No two named root nodes can have matching names.\n const rootNodeNames: string[] = [];\n for (const definitionLevelNode of this.children) {\n if (rootNodeNames.indexOf(definitionLevelNode.name!) !== -1) {\n throw new Error(`multiple root nodes found with duplicate name '${definitionLevelNode.name}'`);\n } else {\n rootNodeNames.push(definitionLevelNode.name!);\n }\n }\n }\n },\n 0\n );\n\n // Return the root AST nodes.\n return stack[0];\n}\n\n/**\n * Pop the next raw token off of the stack and throw an error if it wasn't the expected one.\n * @param tokens The array of remaining tokens.\n * @param expected An optional string or array or items, one of which must match the next popped token.\n * @returns The popped token.\n */\nfunction popAndCheck(tokens: string[], expected: string | string[]) {\n // Get and remove the next token.\n const popped = tokens.shift();\n\n // We were expecting another token.\n if (popped === undefined) {\n throw new Error(\"unexpected end of definition\");\n }\n\n // Do we have an expected token/tokens array?\n if (expected !== undefined) {\n // Check whether the popped token matches at least one of our expected items.\n var tokenMatchesExpectation = ([] as string[])\n .concat(expected)\n .some((item) => popped.toUpperCase() === item.toUpperCase());\n\n // Throw an error if the popped token didn't match any of our expected items.\n if (!tokenMatchesExpectation) {\n const expectationString = ([] as string[])\n .concat(expected)\n .map((item) => \"'\" + item + \"'\")\n .join(\" or \");\n\n throw new Error(`unexpected token found. Expected '${expectationString}' but got '${popped}'`);\n }\n }\n\n // Return the popped token.\n return popped;\n}\n\ntype StringPlaceholders = { [key: string]: string };\n\n/**\n * Pull an argument definition list off of the token stack.\n * @param tokens The array of remaining tokens.\n * @param stringArgumentPlaceholders The mapping of string literal node argument placeholders to original values.\n * @param argumentValidator The argument validator function.\n * @param validationFailedMessage The exception message to throw if argument validation fails.\n * @returns The argument definition list.\n */\nfunction getArguments(\n tokens: string[],\n stringArgumentPlaceholders: StringPlaceholders,\n argumentValidator?: (arg: AnyArgument) => boolean,\n validationFailedMessage?: string\n) {\n // Any lists of arguments will always be wrapped in '[]' for node arguments or '()' for attribute arguments.\n // We are looking for a '[' or '(' opener that wraps the argument tokens and the relevant closer.\n const closer = popAndCheck(tokens, [\"[\", \"(\"]) === \"[\" ? \"]\" : \")\";\n\n const argumentListTokens: string[] = [];\n const argumentList: AnyArgument[] = [];\n\n // Grab all tokens between the '[' and ']' or '(' and ')'.\n while (tokens.length && tokens[0] !== closer) {\n // The next token is part of our arguments list.\n argumentListTokens.push(tokens.shift()!);\n }\n\n // Validate the order of the argument tokens. Each token must either be a ',' or a single argument that satisfies the validator.\n argumentListTokens.forEach((token, index) => {\n // Get whether this token should be an actual argument.\n const shouldBeArgumentToken = !(index & 1);\n\n // If the current token should be an actual argument then validate it,otherwise it should be a ',' token.\n if (shouldBeArgumentToken) {\n // Get the argument definition.\n const argumentDefinition = getArgumentDefinition(token!, stringArgumentPlaceholders);\n\n // Try to validate the argument.\n if (argumentValidator && !argumentValidator(argumentDefinition)) {\n throw new Error(validationFailedMessage);\n }\n\n // This is a valid argument!\n argumentList.push(argumentDefinition);\n } else {\n // The current token should be a ',' token.\n if (token !== \",\") {\n throw new Error(`invalid argument list, expected ',' or ']' but got '${token}'`);\n }\n }\n });\n\n // The arguments list should terminate with a ']' or ')' token, depending on the opener.\n popAndCheck(tokens, closer);\n\n // Return the argument list.\n return argumentList;\n}\n\n/**\n * Gets an argument value definition.\n * @param token The argument token.\n * @param stringArgumentPlaceholders The mapping of string literal node argument placeholders to original values.\n * @returns An argument value definition.\n */\nfunction getArgumentDefinition(token: string, stringArgumentPlaceholders: StringPlaceholders): AnyArgument {\n // Check whether the token represents a null value.\n if (token === \"null\") {\n return {\n value: null,\n type: \"null\"\n } as NullArgument;\n }\n\n // Check whether the token represents a boolean value.\n if (token === \"true\" || token === \"false\") {\n return {\n value: token === \"true\",\n type: \"boolean\"\n } as BooleanArgument;\n }\n\n // Check whether the token represents a number value.\n // TODO: Relies on broken isNaN - see MDN.\n // if (!Number.isNaN(token)) {\n if (!isNaN(token as any)) {\n return {\n value: parseFloat(token),\n isInteger: parseFloat(token) === parseInt(token, 10),\n type: \"number\"\n } as NumberArgument;\n }\n\n // Check whether the token is a placeholder (e.g. @@0@@) representing a string literal.\n if (token.match(/^@@\\d+@@$/g)) {\n return {\n value: stringArgumentPlaceholders[token].replace('\\\\\"', '\"'),\n type: \"string\"\n } as StringPlaceholderArgument;\n }\n\n // The only remaining option is that the argument value is an identifier.\n return {\n value: token,\n type: \"identifier\"\n } as IdentifierArgument;\n}\n\n/**\n * Pull any attributes off of the token stack.\n * @param tokens The array of remaining tokens.\n * @param stringArgumentPlaceholders The mapping of string literal node argument placeholders to original values.\n * @returns An array of attributes defined by any directly following tokens.\n */\nfunction getAttributes(tokens: string[], stringArgumentPlaceholders: StringPlaceholders) {\n // Create an array to hold any attributes found.\n const attributes: Attribute[] = [];\n\n // Keep track of names of attribute that we have found on the token stack, as we cannot have duplicates.\n const attributesFound: string[] = [];\n\n // Try to get the attribute factory for the next token.\n let attributeFactory = AttributeFactories[(tokens[0] || \"\").toUpperCase()];\n\n // Pull attribute tokens off of the tokens stack until we have no more.\n while (attributeFactory) {\n // Check to make sure that we have not already created a attribute of this type for this node.\n if (attributesFound.indexOf(tokens[0].toUpperCase()) !== -1) {\n throw new Error(`duplicate attribute '${tokens[0].toUpperCase()}' found for node`);\n }\n\n // Add the current attribute type to our array of found attributes.\n attributesFound.push(tokens.shift()!.toUpperCase());\n\n // Grab any attribute arguments.\n const attributeArguments = getArguments(tokens, stringArgumentPlaceholders);\n\n // The first attribute argument has to be an identifer, this will reference an agent function.\n if (attributeArguments.length === 0 || attributeArguments[0].type !== \"identifier\") {\n throw new Error(\"expected agent function name identifier argument for attribute\");\n }\n\n // Grab the first attribute which is an identifier that will reference an agent function.\n const attributeFunctionName = attributeArguments.shift()! as IdentifierArgument;\n\n // Any remaining attribute arguments must have a type of string, number, boolean or null.\n attributeArguments\n .filter((arg) => arg.type === \"identifier\")\n .forEach((arg) => {\n throw new Error(\n \"invalid attribute argument value '\" + arg.value + \"', must be string, number, boolean or null\"\n );\n });\n\n // Create the attribute and add it to the array of attributes found.\n attributes.push(attributeFactory(attributeFunctionName.value, attributeArguments));\n\n // Try to get the next attribute name token, as there could be multiple.\n attributeFactory = AttributeFactories[(tokens[0] || \"\").toUpperCase()];\n }\n\n return attributes;\n}\n\n/**\n * Swaps out any node/attribute argument string literals with placeholders.\n * @param definition The definition.\n * @returns An object containing a mapping of placeholders to original string values as well as the processed definition string.\n */\nfunction substituteStringLiterals(definition: string): {\n placeholders: { [key: string]: string };\n processedDefinition: string;\n} {\n // Create an object to hold the mapping of placeholders to original string values.\n const placeholders: StringPlaceholders = {};\n\n // Replace any string literals wrapped with double quotes in our definition with placeholders to be processed later.\n const processedDefinition = definition.replace(/\\\"(\\\\.|[^\"\\\\])*\\\"/g, (match) => {\n var strippedMatch = match.substring(1, match.length - 1);\n var placeholder = Object.keys(placeholders).find((key) => placeholders[key] === strippedMatch);\n\n // If we have no existing string literal match then create a new placeholder.\n if (!placeholder) {\n placeholder = `@@${Object.keys(placeholders).length}@@`;\n placeholders[placeholder] = strippedMatch;\n }\n\n return placeholder;\n });\n\n return { placeholders, processedDefinition };\n}\n\n/**\n * Parse the tree definition into an array of raw tokens.\n * @param definition The definition.\n * @returns An array of tokens parsed from the definition.\n */\nfunction parseTokensFromDefinition(definition: string): string[] {\n // Add some space around various important characters so that they can be plucked out easier as individual tokens.\n definition = definition.replace(/\\(/g, \" ( \");\n definition = definition.replace(/\\)/g, \" ) \");\n definition = definition.replace(/\\{/g, \" { \");\n definition = definition.replace(/\\}/g, \" } \");\n definition = definition.replace(/\\]/g, \" ] \");\n definition = definition.replace(/\\[/g, \" [ \");\n definition = definition.replace(/\\,/g, \" , \");\n\n // Split the definition into raw token form and return it.\n return definition.replace(/\\s+/g, \" \").trim().split(\" \");\n}\n", "import GuardPath, { GuardPathPart } from \"./attributes/guards/GuardPath\";\nimport buildRootASTNodes, { AnyArgument, RootAstNode } from \"./RootAstNodesBuilder\";\nimport State, { AnyState } from \"./State\";\nimport Lookup from \"./Lookup\";\nimport Node from \"./nodes/Node\";\nimport Root from \"./nodes/decorator/Root\";\nimport Composite from \"./nodes/composite/Composite\";\nimport Decorator from \"./nodes/decorator/Decorator\";\nimport { Agent, GlobalFunction } from \"./Agent\";\nimport { CallbackAttributeDetails } from \"./attributes/callbacks/Callback\";\nimport { GuardAttributeDetails } from \"./attributes/guards/Guard\";\nimport { BehaviourTreeOptions } from \"./BehaviourTreeOptions\";\nimport { convertMDSLToJSON } from \"./mdsl/MDSLDefinitionParser\";\n\n// Purely for outside inspection of the tree.\nexport type FlattenedTreeNode = {\n id: string;\n type: string;\n caption: string;\n state: AnyState;\n guards: GuardAttributeDetails[];\n callbacks: CallbackAttributeDetails[];\n args: AnyArgument[];\n parentId: string | null;\n};\n\n/**\n * A representation of a behaviour tree.\n */\nexport class BehaviourTree {\n /**\n * The main root tree node.\n */\n public readonly rootNode: Root;\n\n /**\n * Creates a new instance of the BehaviourTree class.\n * @param definition The behaviour tree definition.\n * @param agent The agent instance that this behaviour tree is modelling behaviour for.\n * @param options The behaviour tree options object.\n */\n constructor(definition: string, private agent: Agent, private options: BehaviourTreeOptions = {}) {\n // The tree definition must be defined and a valid string.\n if (typeof definition !== \"string\") {\n throw new Error(\"the tree definition must be a string\");\n }\n\n // The agent must be defined and not null.\n if (typeof agent !== \"object\" || agent === null) {\n throw new Error(\"the agent must be defined and not null\");\n }\n\n // Parse the behaviour tree definition, create the populated tree of behaviour tree nodes, and get the root.\n this.rootNode = BehaviourTree._createRootNode(definition);\n }\n\n /**\n * Gets whether the tree is in the RUNNING state.\n * @returns true if the tree is in the RUNNING state, otherwise false.\n */\n isRunning() {\n return this.rootNode.getState() === State.RUNNING;\n }\n\n /**\n * Gets the current tree state of SUCCEEDED, FAILED, READY or RUNNING.\n * @returns The current tree state.\n */\n getState() {\n return this.rootNode.getState();\n }\n\n /**\n * Step the tree.\n * 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.\n * 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\n * 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.\n *\n * 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.\n */\n step() {\n // If the root node has already been stepped to completion then we need to reset it.\n if (this.rootNode.getState() === State.SUCCEEDED || this.rootNode.getState() === State.FAILED) {\n this.rootNode.reset();\n }\n\n try {\n this.rootNode.update(this.agent, this.options);\n } catch (exception) {\n throw new Error(`error stepping tree: ${(exception as Error).message}`);\n }\n }\n\n /**\n * Resets the tree from the root node outwards to each nested node, giving each a state of READY.\n */\n reset() {\n this.rootNode.reset();\n }\n\n /**\n * Gets the flattened details of every node in the tree.\n * @returns The flattened details of every node in the tree.\n */\n getFlattenedNodeDetails(): FlattenedTreeNode[] {\n // Create an empty flattened array of tree nodes.\n const flattenedTreeNodes: FlattenedTreeNode[] = [];\n\n /**\n * Helper function to process a node instance and push details into the flattened tree nodes array.\n * @param node The current node.\n * @param parentUid The UID of the node parent, or null if the node is the main root node.\n */\n const processNode = (node: Node, parentUid: string | null) => {\n // Get the guard and callback attribute details for this node.\n const guards = node\n .getAttributes()\n .filter((attribute) => attribute.isGuard())\n .map((attribute) => attribute.getDetails()) as GuardAttributeDetails[];\n const callbacks = node\n .getAttributes()\n .filter((attribute) => !attribute.isGuard())\n .map((attribute) => attribute.getDetails()) as CallbackAttributeDetails[];\n\n // Push the current node into the flattened nodes array.\n flattenedTreeNodes.push({\n id: node.getUid(),\n type: node.getType(),\n caption: node.getName(),\n state: node.getState(),\n guards,\n callbacks,\n args: node.getArguments(),\n parentId: parentUid\n });\n\n // Process each of the nodes children if it is not a leaf node.\n if (!node.isLeafNode()) {\n (node as Composite | Decorator)\n .getChildren()\n .forEach((child) => processNode(child, (node as Composite | Decorator).getUid()));\n }\n };\n\n // Convert the nested node structure into a flattened array of node details.\n processNode(this.rootNode, null);\n\n return flattenedTreeNodes;\n }\n\n /**\n * Registers the action/condition/guard/callback function or subtree with the given name.\n * @param name The name of the function or subtree to register.\n * @param value The function or subtree definition to register.\n */\n static register(name: string, value: GlobalFunction | string) {\n if (typeof value === \"function\") {\n // We are going to register a action/condition/guard/callback function.\n Lookup.setFunc(name, value);\n } else if (typeof value === \"string\") {\n // We are going to register a subtree.\n let rootASTNodes: RootAstNode[];\n\n try {\n // Try to create the behaviour tree AST based on the definition provided, this could fail if the definition is invalid.\n rootASTNodes = buildRootASTNodes(value);\n } catch (exception) {\n // There was an issue in trying to parse and build the tree definition.\n throw new Error(`error registering definition: ${(exception as Error).message}`);\n }\n\n // This function should only ever be called with a definition containing a single unnamed root node.\n if (rootASTNodes.length != 1 || rootASTNodes[0].name !== null) {\n throw new Error(\"error registering definition: expected a single unnamed root node\");\n }\n\n Lookup.setSubtree(name, rootASTNodes[0]);\n } else {\n throw new Error(\"unexpected value, expected string definition or function\");\n }\n }\n\n /**\n * Unregisters the registered action/condition/guard/callback function or subtree with the given name.\n * @param name The name of the registered action/condition/guard/callback function or subtree to unregister.\n */\n static unregister(name: string): void {\n Lookup.remove(name);\n }\n\n /**\n * Unregister all registered action/condition/guard/callback functions and subtrees.\n */\n static unregisterAll(): void {\n Lookup.empty();\n }\n\n /**\n * Parses a behaviour tree definition and creates a tree of behaviour tree nodes.\n * @param {string} definition The behaviour tree definition.\n * @returns The root behaviour tree node.\n */\n private static _createRootNode(definition: string): Root {\n // TODO Remove!\n try {\n // parseToJSON(definition);\n } catch (exception) {\n console.log(exception);\n }\n\n try {\n // Try to create the behaviour tree AST based on the definition provided, this could fail if the definition is invalid.\n const rootASTNodes = buildRootASTNodes(definition);\n\n // Create a symbol to use as the main root key in our root node mapping.\n const mainRootNodeKey = Symbol(\"__root__\");\n\n // Create a mapping of root node names to root AST tokens. The main root node will have a key of Symbol(\"__root__\").\n const rootNodeMap: { [key: string | symbol]: RootAstNode } = {};\n for (const rootASTNode of rootASTNodes) {\n rootNodeMap[rootASTNode.name === null ? mainRootNodeKey : rootASTNode.name!] = rootASTNode;\n }\n\n // Convert the AST to our actual tree and get the root node.\n const rootNode: Root = rootNodeMap[mainRootNodeKey].createNodeInstance(\n // Create a provider for named root nodes that are part of our definition or have been registered. Prioritising the former.\n (name: string): RootAstNode => (rootNodeMap[name] ? rootNodeMap[name] : Lookup.getSubtree(name)),\n []\n );\n\n // Set a guard path on every leaf of the tree to evaluate as part of its update.\n BehaviourTree._applyLeafNodeGuardPaths(rootNode);\n\n // Return the root node.\n return rootNode;\n } catch (exception) {\n // There was an issue in trying to parse and build the tree definition.\n throw new Error(`error parsing tree: ${(exception as Error).message}`);\n }\n }\n\n /**\n * Applies a guard path to every leaf of the tree to evaluate as part of each update.\n * @param rootNode The main root tree node.\n */\n private static _applyLeafNodeGuardPaths(rootNode: Root) {\n const nodePaths: Node[][] = [];\n\n const findLeafNodes = (path: Node[], node: Node) => {\n // Add the current node to the path.\n path = path.concat(node);\n\n // Check whether the current node is a leaf node.\n if (node.isLeafNode()) {\n nodePaths.push(path);\n } else {\n (node as Composite | Decorator).getChildren().forEach((child) => findLeafNodes(path, child));\n }\n };\n\n // Find all leaf node paths, starting from the root.\n findLeafNodes([], rootNode);\n\n nodePaths.forEach((path) => {\n // Each node in the current path will have to be assigned a guard path, working from the root outwards.\n for (let depth = 0; depth < path.length; depth++) {\n // Get the node in the path at the current depth.\n const currentNode = path[depth];\n\n // The node may already have been assigned a guard path, if so just skip it.\n if (currentNode.hasGuardPath()) {\n continue;\n }\n\n // Create the guard path for the current node.\n const guardPath = new GuardPath(\n path\n .slice(0, depth + 1)\n .map((node) => ({ node, guards: node.getGuardAttributes() }))\n .filter((details) => details.guards.length > 0)\n );\n\n // Assign the guard path to the current node.\n currentNode.setGuardPath(guardPath);\n }\n });\n }\n}\n"], + "mappings": "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", "names": ["Participant", "Lotto", "createLotto", "State", "createLotto", "substituteStringLiterals", "parseTokensFromDefinition", "popAndCheck", "getArgumentDefinition"] } diff --git a/dist/index.js b/dist/index.js index 89f540a..4026ca4 100644 --- a/dist/index.js +++ b/dist/index.js @@ -734,19 +734,7 @@ function validateDefinition(definition) { return createFailureResult(`invalid mdsl: ${definition}`); } } else if (typeof definition === "object") { - if (Array.isArray(definition)) { - const invalidDefinitionElements = definition.filter((element) => { - return typeof element !== "object" || Array.isArray(element) || element === null; - }); - if (invalidDefinitionElements.length) { - return createFailureResult( - "invalid elements in definition array, each must be an root node definition object" - ); - } - rootNodeDefinitions = definition; - } else { - rootNodeDefinitions = [definition]; - } + rootNodeDefinitions = Array.isArray(definition) ? definition : [definition]; } else { return createFailureResult(`unexpected definition type of '${typeof definition}'`); } @@ -787,7 +775,7 @@ function findBranchCircularDependencyPath(rootNodeDefinitions) { const followRefs = (mapping, path = []) => { if (path.includes(mapping.id)) { const badPath = [...path, mapping.id]; - badPathFormatted = badPath.map((element) => !!element).join(" => "); + badPathFormatted = badPath.filter((element) => !!element).join(" => "); return; } for (const ref of mapping.refs) { @@ -797,6 +785,7 @@ function findBranchCircularDependencyPath(rootNodeDefinitions) { } } }; + followRefs(rootNodeMappings.find((mapping) => typeof mapping.id === "undefined")); return badPathFormatted; } function validateNode(definition, depth) { diff --git a/dist/index.js.map b/dist/index.js.map index 4ac134e..25a98d2 100644 --- a/dist/index.js.map +++ b/dist/index.js.map @@ -1,7 +1,7 @@ { "version": 3, "sources": ["../node_modules/lotto-draw/dist/Participant.js", "../node_modules/lotto-draw/dist/Utilities.js", "../node_modules/lotto-draw/dist/Lotto.js", "../node_modules/lotto-draw/dist/createLotto.js", "../node_modules/lotto-draw/dist/index.js", "../src/index.ts", "../src/State.ts", "../src/BehaviourTreeDefinitionUtilities.ts", "../src/mdsl/MDSLUtilities.ts", "../src/mdsl/MDSLNodeArgumentParser.ts", "../src/mdsl/MDSLNodeAttributeParser.ts", "../src/mdsl/MDSLDefinitionParser.ts", "../src/BehaviourTreeDefinitionValidator.ts", "../src/attributes/guards/GuardUnsatisifedException.ts", "../src/attributes/guards/GuardPath.ts", "../src/nodes/Node.ts", "../src/nodes/leaf/Leaf.ts", "../src/Lookup.ts", "../src/nodes/leaf/Action.ts", "../src/nodes/leaf/Condition.ts", "../src/nodes/leaf/Wait.ts", "../src/nodes/decorator/Decorator.ts", "../src/nodes/decorator/Root.ts", "../src/nodes/decorator/Repeat.ts", "../src/nodes/decorator/Retry.ts", "../src/nodes/decorator/Flip.ts", "../src/nodes/decorator/Succeed.ts", "../src/nodes/decorator/Fail.ts", "../src/nodes/composite/Lotto.ts", "../src/nodes/composite/Composite.ts", "../src/nodes/composite/Selector.ts", "../src/nodes/composite/Sequence.ts", "../src/nodes/composite/Parallel.ts", "../src/attributes/Attribute.ts", "../src/attributes/guards/Guard.ts", "../src/attributes/guards/While.ts", "../src/attributes/guards/Until.ts", "../src/attributes/callbacks/Callback.ts", "../src/attributes/callbacks/Entry.ts", "../src/attributes/callbacks/Exit.ts", "../src/attributes/callbacks/Step.ts", "../src/RootAstNodesBuilder.ts", "../src/BehaviourTree.ts"], - "sourcesContent": ["\"use strict\";\r\nObject.defineProperty(exports, \"__esModule\", { value: true });\r\nexports.Participant = void 0;\r\n/**\r\n * A participant that holds a number of tickets.\r\n */\r\nvar Participant = /** @class */ (function () {\r\n /**\r\n * Creates an instance of the Participant class.\r\n * @param participant The actual participant.\r\n * @param tickets The number of tickets held by the participant.\r\n */\r\n function Participant(participant, tickets) {\r\n if (tickets === void 0) { tickets = 1; }\r\n this._participant = participant;\r\n this._tickets = tickets;\r\n }\r\n Object.defineProperty(Participant.prototype, \"participant\", {\r\n /** Gets the actual participant. */\r\n get: function () {\r\n return this._participant;\r\n },\r\n enumerable: false,\r\n configurable: true\r\n });\r\n Object.defineProperty(Participant.prototype, \"tickets\", {\r\n /** Gets or sets the number of tickets held by the participant. */\r\n get: function () {\r\n return this._tickets;\r\n },\r\n set: function (value) {\r\n this._tickets = value;\r\n },\r\n enumerable: false,\r\n configurable: true\r\n });\r\n return Participant;\r\n}());\r\nexports.Participant = Participant;\r\n", "\"use strict\";\r\nObject.defineProperty(exports, \"__esModule\", { value: true });\r\nexports.isNaturalNumber = exports.isNullOrUndefined = void 0;\r\n/**\r\n * Gets whether the value provided is null or undefined.\r\n * @param value The value to check.\r\n * @returns Whether the value provided is null or undefined.\r\n */\r\nfunction isNullOrUndefined(value) {\r\n return value === null || value === undefined;\r\n}\r\nexports.isNullOrUndefined = isNullOrUndefined;\r\n/**\r\n * Gets whether the value provided is a natural number.\r\n * @param value The value to check.\r\n * @returns Whether the value provided is a natural number.\r\n */\r\nfunction isNaturalNumber(value) {\r\n return typeof value === \"number\" && value >= 1 && Math.floor(value) === value;\r\n}\r\nexports.isNaturalNumber = isNaturalNumber;\r\n", "\"use strict\";\r\nObject.defineProperty(exports, \"__esModule\", { value: true });\r\nexports.Lotto = void 0;\r\nvar Participant_1 = require(\"./Participant\");\r\nvar Utilities_1 = require(\"./Utilities\");\r\n/**\r\n * Represents a lotto consisting of a number of pickable ticket-holding participants.\r\n */\r\nvar Lotto = /** @class */ (function () {\r\n /**\r\n * Creates a new instance of Lotto.\r\n * @param customRandom The custom RNG to use in place of Math.random().\r\n */\r\n function Lotto(customRandom) {\r\n /** The array of participants that are holding tickets in the lotto. */\r\n this._participants = [];\r\n this._customRandom = customRandom;\r\n }\r\n /**\r\n * Adds a participant with the specified number of tickets, or adds to the participant ticket count if the participant already holds tickets.\r\n * @param participant The participant to add or to increase the ticket count for if they already hold tickets.\r\n * @param tickets The number of tickets, defaults to 1.\r\n * @returns The Lotto instance.\r\n */\r\n Lotto.prototype.add = function (participant, tickets) {\r\n if (tickets === void 0) { tickets = 1; }\r\n // Check that we have a valid ticket count.\r\n if (!(0, Utilities_1.isNaturalNumber)(tickets)) {\r\n throw new Error(\"tickets value must be a natural number\");\r\n }\r\n // Check whether this participant has already been added.\r\n var existingParticipant = this._participants.find(function (part) { return part.participant === participant; });\r\n if (existingParticipant) {\r\n // The participant has already been added to the lotto so just add to their ticket count.\r\n existingParticipant.tickets += tickets;\r\n }\r\n else {\r\n // The participant is not part of the lotto so we should add them.\r\n this._participants.push(new Participant_1.Participant(participant, tickets));\r\n }\r\n return this;\r\n };\r\n /**\r\n * Removes the specified number of tickets for the given participant from the draw, or all tickets if a ticket number is not defined.\r\n * @param participant The participant to remove tickets for.\r\n * @param tickets The number of tickets to remove, or undefined if all tickets are to be removed.\r\n * @returns The Lotto instance.\r\n */\r\n Lotto.prototype.remove = function (participant, tickets) {\r\n // Attempt to get the existing participant.\r\n var existingParticipant = this._participants.find(function (part) { return part.participant === participant; });\r\n // There is nothing to do if the specified participant isn't even part of the lotto.\r\n if (!existingParticipant) {\r\n return this;\r\n }\r\n // Check whether a tickets value was given.\r\n if (tickets !== undefined) {\r\n // Check that we have a valid ticket count.\r\n if (!(0, Utilities_1.isNaturalNumber)(tickets)) {\r\n throw new Error(\"tickets value must be a natural number\");\r\n }\r\n existingParticipant.tickets -= tickets;\r\n // If the participant no longer holds any tickets then they should be removed.\r\n if (existingParticipant.tickets < 1) {\r\n this._participants = this._participants.filter(function (part) { return part !== existingParticipant; });\r\n }\r\n }\r\n else {\r\n // We are removing all tickets for the participant so just remove them from the lotto.\r\n this._participants = this._participants.filter(function (part) { return part !== existingParticipant; });\r\n }\r\n return this;\r\n };\r\n /**\r\n * Draw a winning ticket and return the participant that holds the ticket.\r\n * @param options The draw options.\r\n * @returns The participant that holds the winning ticket.\r\n */\r\n Lotto.prototype.draw = function (options) {\r\n if (options === void 0) { options = {}; }\r\n // If we have no participants then just return null.\r\n if (this._participants.length === 0) {\r\n return null;\r\n }\r\n var redrawable = (0, Utilities_1.isNullOrUndefined)(options.redrawable) ? true : options.redrawable;\r\n var pickable = [];\r\n this._participants.forEach(function (_a) {\r\n var participant = _a.participant, tickets = _a.tickets;\r\n for (var ticketCount = 0; ticketCount < tickets; ticketCount++) {\r\n pickable.push(participant);\r\n }\r\n });\r\n var random;\r\n // We need a random floating-point number between 0 (inclusive) and 1 to scale up to pick our winner.\r\n // If a custom random function exists then we should use that or fall back to Math.random().\r\n if (this._customRandom) {\r\n // Call our custom random function to get a random floating-point number.\r\n random = this._customRandom();\r\n // Verify that the result of calling our custom random function is a number between 0 (inclusive) and 1.\r\n if (typeof random !== \"number\" || random < 0 || random >= 1) {\r\n throw new Error(\"the 'random' function provided did not return a number between 0 (inclusive) and 1\");\r\n }\r\n }\r\n else {\r\n // No custom random function was defined so just use good ol' Math.random().\r\n random = Math.random();\r\n }\r\n // Pick a winning participant.\r\n var winner = pickable[Math.floor(random * pickable.length)];\r\n // If the ticket isn't redrawable then we should remove a ticket from the winning participants ticket count.\r\n if (!redrawable) {\r\n this.remove(winner, 1);\r\n }\r\n // Return the winning participant.\r\n return winner;\r\n };\r\n /**\r\n * Draws multiple winning tickets and return an array of the participants that hold the winning tickets.\r\n * @param tickets The number of winning tickets to draw.\r\n * @param options The draw multiple options.\r\n * @returns An array of the participants that hold the winning tickets.\r\n */\r\n Lotto.prototype.drawMultiple = function (tickets, options) {\r\n if (options === void 0) { options = {}; }\r\n var uniqueResults = (0, Utilities_1.isNullOrUndefined)(options.unique) ? false : options.unique;\r\n // Handle cases where the user has asked for zero tickets (no idea why they would do this be we should trust them).\r\n if (tickets === 0) {\r\n return [];\r\n }\r\n // Now that we know out tickets value is not zero we should check that it is a valid natural number.\r\n if (!(0, Utilities_1.isNaturalNumber)(tickets)) {\r\n throw new Error(\"tickets value must be a natural number\");\r\n }\r\n var result = [];\r\n // Keep drawing tickets until we either reach the number of required tickets or we simply run out of tickets to draw.\r\n // We can run out of tickets to draw if 'options.redrawable' is explicity 'false' or we just had no participants when 'drawMultiple' was called.\r\n while (result.length < tickets && this._participants.length > 0) {\r\n result.push(this.draw(options));\r\n }\r\n // If the 'unique' draw option is set then we need to remove duplicates from the result list.\r\n if (uniqueResults) {\r\n // Create an array to store our unique results.\r\n var unique = [];\r\n // Iterate over all of our participants (with potential duplicates) and populate our array of unique values.\r\n for (var _i = 0, result_1 = result; _i < result_1.length; _i++) {\r\n var participant = result_1[_i];\r\n if (unique.indexOf(participant) === -1) {\r\n unique.push(participant);\r\n }\r\n }\r\n result = unique;\r\n }\r\n return result;\r\n };\r\n return Lotto;\r\n}());\r\nexports.Lotto = Lotto;\r\n", "\"use strict\";\r\nObject.defineProperty(exports, \"__esModule\", { value: true });\r\nexports.createLotto = void 0;\r\nvar Lotto_1 = require(\"./Lotto\");\r\n/**\r\n * A function that creates and returns a Lotto instance.\r\n * @param participantsOrOptions An array of initial participants or options relating to the creation of a Lotto instance.\r\n * @returns A new Lotto instance.\r\n */\r\nfunction createLotto(participantsOrOptions) {\r\n // If no initial participants or lotto options were provided as an argument then we can just return a new lotto instance now.\r\n if (!participantsOrOptions) {\r\n return new Lotto_1.Lotto();\r\n }\r\n // Check whether we were provided with an array of initial participants or a lotto options object.\r\n if (Array.isArray(participantsOrOptions)) {\r\n // We are dealing with a pre-defined array of participants.\r\n var participants = participantsOrOptions;\r\n var lotto_1 = new Lotto_1.Lotto();\r\n // If the lotto participants have been defined upfront then we will need to add them all to our lotto instance now.\r\n participants.forEach(function (_a) {\r\n var participant = _a[0], tokens = _a[1];\r\n return lotto_1.add(participant, tokens);\r\n });\r\n // Return the Lotto instance.\r\n return lotto_1;\r\n }\r\n else {\r\n // We are dealing with some lotto options.\r\n var random = participantsOrOptions.random, participants = participantsOrOptions.participants;\r\n // Create a Lotto instance passing the custom RNG function to use in place of Math.random() (which could be undefined).\r\n var lotto_2 = new Lotto_1.Lotto(random);\r\n // If the lotto participants have been defined upfront as part of the options then we will need to add them all to our lotto instance now.\r\n if (participants) {\r\n participants.forEach(function (_a) {\r\n var participant = _a[0], tokens = _a[1];\r\n return lotto_2.add(participant, tokens);\r\n });\r\n }\r\n // Return the Lotto instance.\r\n return lotto_2;\r\n }\r\n}\r\nexports.createLotto = createLotto;\r\n", "\"use strict\";\r\nObject.defineProperty(exports, \"__esModule\", { value: true });\r\nvar createLotto_1 = require(\"./createLotto\");\r\nexports.default = createLotto_1.createLotto;\r\n", "import State from \"./State\";\nimport { validateDefinition } from \"./BehaviourTreeDefinitionValidator\";\nimport { convertMDSLToJSON } from \"./mdsl/MDSLDefinitionParser\";\nimport { BehaviourTree, FlattenedTreeNode } from \"./BehaviourTree\";\n\nexport { BehaviourTree, State, convertMDSLToJSON, validateDefinition };\nexport type { FlattenedTreeNode };\n", "/**\n * Enumeration of node state types.\n */\nexport enum State {\n READY = \"mistreevous.ready\",\n RUNNING = \"mistreevous.running\",\n SUCCEEDED = \"mistreevous.succeeded\",\n FAILED = \"mistreevous.failed\"\n}\n\nexport { State as default };\n\nexport type CompleteState = State.SUCCEEDED | State.FAILED;\nexport type AnyState = State.READY | State.RUNNING | CompleteState;\n", "import {\n NodeDefinition,\n RootNodeDefinition,\n DecoratorNodeDefinition,\n CompositeNodeDefinition,\n AnyNode,\n BranchNodeDefinition\n} from \"./BehaviourTreeDefinition\";\n\n/**\n * A type guard function that returns true if the specified node satisfies the RootNodeDefinition type.\n * @param node The node.\n * @returns A value of true if the specified node satisfies the RootNodeDefinition type.\n */\nexport function isRootNode(node: NodeDefinition): node is RootNodeDefinition {\n return node.type === \"root\";\n}\n\n/**\n * A type guard function that returns true if the specified node satisfies the BranchNodeDefinition type.\n * @param node The node.\n * @returns A value of true if the specified node satisfies the BranchNodeDefinition type.\n */\nexport function isBranchNode(node: NodeDefinition): node is BranchNodeDefinition {\n return node.type === \"branch\";\n}\n\n/**\n * A type guard function that returns true if the specified node satisfies the NodeDefinition type.\n * @param node The node.\n * @returns A value of true if the specified node satisfies the NodeDefinition type.\n */\nexport function isLeafNode(node: NodeDefinition): node is NodeDefinition {\n return [\"branch\", \"action\", \"condition\", \"wait\"].includes(node.type);\n}\n\n/**\n * A type guard function that returns true if the specified node satisfies the DecoratorNodeDefinition type.\n * @param node The node.\n * @returns A value of true if the specified node satisfies the DecoratorNodeDefinition type.\n */\nexport function isDecoratorNode(node: NodeDefinition): node is DecoratorNodeDefinition {\n return [\"root\", \"repeat\", \"retry\", \"flip\", \"succeed\", \"fail\"].includes(node.type);\n}\n\n/**\n * A type guard function that returns true if the specified node satisfies the CompositeNodeDefinition type.\n * @param node The node.\n * @returns A value of true if the specified node satisfies the CompositeNodeDefinition type.\n */\nexport function isCompositeNode(node: NodeDefinition): node is CompositeNodeDefinition {\n return [\"sequence\", \"selector\", \"lotto\", \"parallel\"].includes(node.type);\n}\n\n/**\n * Flatten a node definition into an array of all of its nested node definitions.\n * @param nodeDefinition The node definition to flatten.\n * @returns An array of all of nested node definitions.\n */\nexport function flattenDefinition(nodeDefinition: AnyNode): AnyNode[] {\n const nodes: AnyNode[] = [];\n\n const processNode = (currentNodeDefinition: AnyNode) => {\n nodes.push(currentNodeDefinition);\n\n if (isCompositeNode(currentNodeDefinition)) {\n currentNodeDefinition.children.forEach(processNode);\n } else if (isDecoratorNode(currentNodeDefinition)) {\n processNode(currentNodeDefinition.child);\n }\n };\n\n processNode(nodeDefinition);\n\n return nodes;\n}\n\n/**\n * Determines whether the passed value is an integer.\n * @param value The value to check.\n * @returns Whether the passed value is an integer.\n */\nexport function isInteger(value: unknown): boolean {\n return typeof value === \"number\" && Math.floor(value) === value;\n}\n", "/**\n * A type defining an object that holds a reference to substitued string literals parsed from the definition.\n */\nexport type StringLiteralPlaceholders = { [key: string]: string };\n\n/**\n * Pop the next raw token from the specified array of tokens and throw an error if it wasn't the expected one.\n * @param tokens The array of tokens.\n * @param expected An optional string or array or items, one of which must match the next popped token.\n * @returns The popped token.\n */\nexport function popAndCheck(tokens: string[], expected?: string | string[]): string {\n // Get and remove the next token.\n const popped = tokens.shift();\n\n // We were expecting another token but there aren't any.\n if (popped === undefined) {\n throw new Error(\"unexpected end of definition\");\n }\n\n // Do we have an expected token/tokens array?\n if (expected != undefined) {\n // Get an array of expected values, if the popped token matches any then we are all good.\n const expectedValues = typeof expected === \"string\" ? [expected] : expected;\n\n // Check whether the popped token matches at least one of our expected items.\n var tokenMatchesExpectation = expectedValues.some((item) => popped.toUpperCase() === item.toUpperCase());\n\n // Throw an error if the popped token didn't match any of our expected items.\n if (!tokenMatchesExpectation) {\n const expectationString = expectedValues.map((item) => \"'\" + item + \"'\").join(\" or \");\n throw new Error(\"unexpected token found. Expected \" + expectationString + \" but got '\" + popped + \"'\");\n }\n }\n\n // Return the popped token.\n return popped;\n}\n\n/**\n * Swaps out any node/attribute argument string literals with placeholders.\n * @param definition The definition.\n * @returns An object containing a mapping of placeholders to original string values as well as the processed definition string.\n */\nexport function substituteStringLiterals(definition: string): {\n placeholders: StringLiteralPlaceholders;\n processedDefinition: string;\n} {\n // Create an object to hold the mapping of placeholders to original string values.\n const placeholders: StringLiteralPlaceholders = {};\n\n // Replace any string literals wrapped with double quotes in our definition with placeholders to be processed later.\n const processedDefinition = definition.replace(/\\\"(\\\\.|[^\"\\\\])*\\\"/g, (match) => {\n var strippedMatch = match.substring(1, match.length - 1);\n var placeholder = Object.keys(placeholders).find((key) => placeholders[key] === strippedMatch);\n\n // If we have no existing string literal match then create a new placeholder.\n if (!placeholder) {\n placeholder = `@@${Object.keys(placeholders).length}@@`;\n placeholders[placeholder] = strippedMatch;\n }\n\n return placeholder;\n });\n\n return { placeholders, processedDefinition };\n}\n\n/**\n * Parse the tree definition into an array of raw tokens.\n * @param definition The definition.\n * @returns An array of tokens parsed from the definition.\n */\nexport function parseTokensFromDefinition(definition: string): string[] {\n // Add some space around various important characters so that they can be plucked out easier as individual tokens.\n definition = definition.replace(/\\(/g, \" ( \");\n definition = definition.replace(/\\)/g, \" ) \");\n definition = definition.replace(/\\{/g, \" { \");\n definition = definition.replace(/\\}/g, \" } \");\n definition = definition.replace(/\\]/g, \" ] \");\n definition = definition.replace(/\\[/g, \" [ \");\n definition = definition.replace(/\\,/g, \" , \");\n\n // Split the definition into raw token form and return it.\n return definition.replace(/\\s+/g, \" \").trim().split(\" \");\n}\n", "import { StringLiteralPlaceholders, popAndCheck } from \"./MDSLUtilities\";\n\nexport type Argument = {\n /** The argument value. */\n value: T;\n /** The argument type, used for validation. */\n type: string;\n};\n\nexport type NullArgument = Argument & {\n type: \"null\";\n};\n\nexport type BooleanArgument = Argument & {\n type: \"boolean\";\n};\n\nexport type NumberArgument = Argument & {\n type: \"number\";\n isInteger: boolean; // Used for validation.\n};\n\nexport type StringPlaceholderArgument = Argument & {\n type: \"string\";\n};\n\nexport type IdentifierArgument = Argument & {\n type: \"identifier\";\n};\n\nexport type AnyArgument =\n | NullArgument\n | BooleanArgument\n | NumberArgument\n | StringPlaceholderArgument\n | IdentifierArgument;\n\n/**\n * Parse an array of argument definitions from the specified tokens array.\n * @param tokens The array tokens to parse the argument definitions from.\n * @param stringArgumentPlaceholders The mapping of string literal node argument placeholders to original values.\n * @param argumentValidator The argument validator function.\n * @param validationFailedMessage The exception message to throw if argument validation fails.\n * @returns An array of argument definitions parsed from the specified tokens array.\n */\nexport function parseArgumentTokens(\n tokens: string[],\n stringArgumentPlaceholders: StringLiteralPlaceholders\n): AnyArgument[] {\n const argumentList: AnyArgument[] = [];\n\n // If the next token is not a '[' or '(' then we have no arguments to parse.\n if (![\"[\", \"(\"].includes(tokens[0])) {\n return argumentList;\n }\n\n // Any lists of arguments will always be wrapped in '[]' for node arguments or '()' for attribute arguments.\n // We are looking for a '[' or '(' opener that wraps the argument tokens and the relevant closer.\n const closingToken = popAndCheck(tokens, [\"[\", \"(\"]) === \"[\" ? \"]\" : \")\";\n\n const argumentListTokens: string[] = [];\n\n // Grab all tokens between the '[' and ']' or '(' and ')'.\n while (tokens.length && tokens[0] !== closingToken) {\n // The next token is part of our arguments list.\n argumentListTokens.push(tokens.shift()!);\n }\n\n // Validate the order of the argument tokens. Each token must either be a ',' or a single argument that satisfies the validator.\n argumentListTokens.forEach((token, index) => {\n // Get whether this token should be an actual argument.\n const shouldBeArgumentToken = !(index & 1);\n\n // If the current token should be an actual argument then validate it, otherwise it should be a ',' token.\n if (shouldBeArgumentToken) {\n // Get the argument definition.\n const argumentDefinition = getArgumentDefinition(token, stringArgumentPlaceholders);\n\n // This is a valid argument!\n argumentList.push(argumentDefinition);\n } else {\n // The current token should be a ',' token.\n if (token !== \",\") {\n throw new Error(`invalid argument list, expected ',' or ']' but got '${token}'`);\n }\n }\n });\n\n // The arguments list should terminate with a ']' or ')' token, depending on the opener.\n popAndCheck(tokens, closingToken);\n\n // Return the arguments.\n return argumentList;\n}\n\n/**\n * Gets an argument value definition.\n * @param token The argument token.\n * @param stringArgumentPlaceholders The mapping of string literal node argument placeholders to original values.\n * @returns An argument value definition.\n */\nfunction getArgumentDefinition(token: string, stringArgumentPlaceholders: StringLiteralPlaceholders): AnyArgument {\n // Check whether the token represents a null value.\n if (token === \"null\") {\n return {\n value: null,\n type: \"null\"\n } as NullArgument;\n }\n\n // Check whether the token represents a boolean value.\n if (token === \"true\" || token === \"false\") {\n return {\n value: token === \"true\",\n type: \"boolean\"\n } as BooleanArgument;\n }\n\n // Check whether the token represents a number value.\n // TODO: Relies on broken isNaN - see MDN.\n // if (!Number.isNaN(token)) {\n if (!isNaN(token as any)) {\n return {\n value: parseFloat(token),\n isInteger: parseFloat(token) === parseInt(token, 10),\n type: \"number\"\n } as NumberArgument;\n }\n\n // Check whether the token is a placeholder (e.g. @@0@@) representing a string literal.\n if (token.match(/^@@\\d+@@$/g)) {\n return {\n value: stringArgumentPlaceholders[token].replace('\\\\\"', '\"'),\n type: \"string\"\n } as StringPlaceholderArgument;\n }\n\n // The only remaining option is that the argument value is an identifier.\n return {\n value: token,\n type: \"identifier\"\n } as IdentifierArgument;\n}\n", "import { NodeAttributeDefinition } from \"../BehaviourTreeDefinition\";\nimport { parseArgumentTokens } from \"./MDSLNodeArgumentParser\";\nimport { StringLiteralPlaceholders } from \"./MDSLUtilities\";\n\n/**\n * A type defining the attribute definitions of a node.\n */\ntype NodeAttributes = {\n while?: NodeAttributeDefinition;\n until?: NodeAttributeDefinition;\n entry?: NodeAttributeDefinition;\n exit?: NodeAttributeDefinition;\n step?: NodeAttributeDefinition;\n};\n\n/**\n * Parse any node attribute definitions from the specified tokens array.\n * @param tokens The array of remaining tokens.\n * @param stringArgumentPlaceholders The mapping of string literal node argument placeholders to original values.\n * @returns An object of attribute definitions defined by any directly following tokens.\n */\nexport function parseAttributeTokens(\n tokens: string[],\n stringArgumentPlaceholders: StringLiteralPlaceholders\n): NodeAttributes {\n const nodeAttributeNames: (keyof NodeAttributes)[] = [\"while\", \"until\", \"entry\", \"exit\", \"step\"];\n\n // Create an object to hold any attributes found.\n const attributes: NodeAttributes = {};\n\n // Try to get the name of the attribute for the next token.\n let nextAttributeName = tokens[0]?.toLowerCase() as keyof NodeAttributes;\n\n // Pull attribute tokens as well as their arguments off of the tokens stack until we have no more.\n while (nodeAttributeNames.includes(nextAttributeName)) {\n // Check to make sure that we have not already created an attribute definition of this type.\n if (attributes[nextAttributeName]) {\n throw new Error(`duplicate attribute '${tokens[0].toUpperCase()}' found for node`);\n }\n\n // Remove the attribute name token from the array of tokens.\n tokens.shift();\n\n // Grab the attribute arguments, assuming the first to be an identifier.\n const [attributeCallIdentifier, ...attributeArguments] = parseArgumentTokens(\n tokens,\n stringArgumentPlaceholders\n );\n\n // The first attribute argument has to be an identifer, this will reference an agent function.\n if (attributeCallIdentifier?.type !== \"identifier\") {\n throw new Error(\"expected agent function name identifier argument for attribute\");\n }\n\n // Any attribute arguments (other than the expected call identifier) must have a type of string, number, boolean or null.\n attributeArguments\n .filter((arg) => arg.type === \"identifier\")\n .forEach((arg) => {\n throw new Error(\n `invalid attribute argument value '${arg.value}', must be string, number, boolean or null`\n );\n });\n\n // Create the attribute definition and add it to the object of attribute definitions found.\n attributes[nextAttributeName] = {\n call: attributeCallIdentifier.value,\n args: attributeArguments.map(({ value }) => value)\n };\n\n // Try to get the next attribute name token, as there could be multiple.\n nextAttributeName = tokens[0]?.toLowerCase() as keyof NodeAttributes;\n }\n\n return attributes;\n}\n", "import {\n ActionNodeDefinition,\n AnyChildNode,\n AnyNode,\n BranchNodeDefinition,\n ConditionNodeDefinition,\n FailNodeDefinition,\n FlipNodeDefinition,\n LottoNodeDefinition,\n ParallelNodeDefinition,\n RepeatNodeDefinition,\n RetryNodeDefinition,\n RootNodeDefinition,\n SelectorNodeDefinition,\n SequenceNodeDefinition,\n SucceedNodeDefinition,\n WaitNodeDefinition\n} from \"../BehaviourTreeDefinition\";\nimport { isCompositeNode, isDecoratorNode, isLeafNode, isRootNode } from \"../BehaviourTreeDefinitionUtilities\";\nimport { parseArgumentTokens } from \"./MDSLNodeArgumentParser\";\nimport { parseAttributeTokens } from \"./MDSLNodeAttributeParser\";\nimport {\n StringLiteralPlaceholders,\n parseTokensFromDefinition,\n popAndCheck,\n substituteStringLiterals\n} from \"./MDSLUtilities\";\n\n/**\n * Convert the MDSL tree definition string into an equivalent JSON definition.\n * @param definition The tree definition string as MDSL.\n * @returns The root node JSON definitions.\n */\nexport function convertMDSLToJSON(definition: string): RootNodeDefinition[] {\n // Swap out any node/attribute argument string literals with a placeholder and get a mapping of placeholders to original values as well as the processed definition.\n const { placeholders, processedDefinition } = substituteStringLiterals(definition);\n\n // Parse our definition definition string into an array of raw tokens.\n const tokens = parseTokensFromDefinition(processedDefinition);\n\n return convertTokensToJSONDefinition(tokens, placeholders);\n}\n\n/**\n * Converts the specified tree definition tokens into a JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The root node JSON definitions.\n */\nfunction convertTokensToJSONDefinition(\n tokens: string[],\n stringLiteralPlaceholders: StringLiteralPlaceholders\n): RootNodeDefinition[] {\n // There must be at least 3 tokens for the tree definition to be valid. 'ROOT', '{' and '}'.\n if (tokens.length < 3) {\n throw new Error(\"invalid token count\");\n }\n\n // We should have a matching number of '{' and '}' tokens. If not, then there are scopes that have not been properly closed.\n if (tokens.filter((token) => token === \"{\").length !== tokens.filter((token) => token === \"}\").length) {\n throw new Error(\"scope character mismatch\");\n }\n\n // Create an array of tree stack arrays where root nodes will always be at the botton and the current composite/decorator node at the top.\n // There should be an element in this array for every root node defined and every element should be an array with a root note as the first element.\n // E.g. A definition with two root nodes defined:\n // [\n // [root, lotto, sequence],\n // [root, selector]\n // ]\n const treeStacks: [Partial, ...Partial[]][] = [];\n\n // Create an array of all root node definitions that we create.\n const rootNodes: Partial[] = [];\n\n // A helper function used to push node definitions onto the tree stack.\n const pushNode = (node: AnyNode) => {\n // If the node is a root node then we need to create a new tree stack array with the root node at the root.\n if (isRootNode(node)) {\n // Add the root node definition to our array of all parsed root node definitions.\n rootNodes.push(node);\n\n // Add the root node definition to the root of a new tree stack.\n treeStacks.push([node]);\n\n return;\n }\n\n // All non-root nodes should be pushed after their root nodes so handle cases\n // where we may not have any tree stacks or our top-most tree stack is empty.\n if (!treeStacks.length || !treeStacks[treeStacks.length - 1].length) {\n throw new Error(\"expected root node at base of definition\");\n }\n\n // Get the current tree stack that we are populating.\n const topTreeStack = treeStacks[treeStacks.length - 1];\n\n // Get the top-most node in the current tree stack, this will be a composite/decorator node\n // for which we will populate its children array if composite or setting its child if a decorator.\n const topTreeStackTopNode = topTreeStack[topTreeStack.length - 1] as AnyNode;\n\n // If the top-most node in the current root stack is a composite or decorator\n // node then the current node should be added as a child of the top-most node.\n if (isCompositeNode(topTreeStackTopNode)) {\n topTreeStackTopNode.children = topTreeStackTopNode.children || [];\n topTreeStackTopNode.children.push(node);\n } else if (isDecoratorNode(topTreeStackTopNode)) {\n // If the top node already has a child node set then throw an error as a decorator should only have a single child.\n if (topTreeStackTopNode.child) {\n throw new Error(\"a decorator node must only have a single child node\");\n }\n\n topTreeStackTopNode.child = node;\n }\n\n // If the node we are adding is also a composite or decorator node, then we should push it\n // onto the current tree stack, as subsequent nodes will be added as its child/children.\n if (!isLeafNode(node)) {\n topTreeStack.push(node);\n }\n };\n\n // A helper function used to pop node definitions off of the stack.\n const popNode = () => {\n // Get the current tree stack that we are populating.\n const topTreeStack = treeStacks[treeStacks.length - 1];\n\n // Pop the top-most node in the current tree stack if there is one.\n if (topTreeStack.length) {\n topTreeStack.pop();\n }\n\n // We don't want any empty tree stacks in our stack of tree stacks.\n if (!topTreeStack.length) {\n treeStacks.pop();\n }\n };\n\n // We should keep processing the raw tokens until we run out of them.\n while (tokens.length) {\n // Grab the next token.\n const token = tokens.shift()!;\n\n // How we create the next node depends on the current raw token value.\n switch (token.toUpperCase()) {\n case \"ROOT\": {\n pushNode(createRootNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"SUCCEED\": {\n pushNode(createSucceedNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"FAIL\": {\n pushNode(createFailNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"FLIP\": {\n pushNode(createFlipNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"REPEAT\": {\n pushNode(createRepeatNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"RETRY\": {\n pushNode(createRetryNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"SEQUENCE\": {\n pushNode(createSequenceNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"SELECTOR\": {\n pushNode(createSelectorNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"PARALLEL\": {\n pushNode(createParallelNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"LOTTO\": {\n pushNode(createLottoNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"ACTION\": {\n pushNode(createActionNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"CONDITION\": {\n pushNode(createConditionNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"WAIT\": {\n pushNode(createWaitNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"BRANCH\": {\n pushNode(createBranchNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"}\": {\n // The '}' character closes the current scope and means that we have to pop a node off of the current stack.\n popNode();\n break;\n }\n\n default: {\n throw new Error(`unexpected token: ${token}`);\n }\n }\n }\n\n return rootNodes as RootNodeDefinition[];\n}\n\n/**\n * Creates a root node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The root node JSON definition.\n */\nfunction createRootNode(tokens: string[], stringLiteralPlaceholders: StringLiteralPlaceholders): RootNodeDefinition {\n // Create the root node definition.\n let node = {\n type: \"root\",\n id: undefined\n } as RootNodeDefinition;\n\n // Parse any node arguments, we should only have one if any which will be an identifier argument for the root identifier.\n const nodeArguments = parseArgumentTokens(tokens, stringLiteralPlaceholders);\n\n // Check whether any node arguments were defined.\n if (nodeArguments.length) {\n // We should only have one argument, if any, which will be an identifier argument for the root identifier.\n if (nodeArguments.length === 1 && nodeArguments[0].type === \"identifier\") {\n // The root node identifier will be the first and only node argument value.\n node.id = nodeArguments[0].value as string;\n } else {\n throw new Error(\"expected single root name argument\");\n }\n }\n\n // Grab any node attribute definitions and spread them into the node definition.\n node = { ...node, ...parseAttributeTokens(tokens, stringLiteralPlaceholders) };\n\n // This is a decorator node, so we expect an opening '{'.\n popAndCheck(tokens, \"{\");\n\n // Return the root node definition.\n return node;\n}\n\n/**\n * Creates a succeed node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The succeed node JSON definition.\n */\nfunction createSucceedNode(\n tokens: string[],\n stringLiteralPlaceholders: StringLiteralPlaceholders\n): SucceedNodeDefinition {\n const node = {\n type: \"succeed\",\n ...parseAttributeTokens(tokens, stringLiteralPlaceholders)\n } as SucceedNodeDefinition;\n\n // This is a decorator node, so we expect an opening '{'.\n popAndCheck(tokens, \"{\");\n\n // Return the succeed node definition.\n return node;\n}\n\n/**\n * Creates a fail node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The fail node JSON definition.\n */\nfunction createFailNode(tokens: string[], stringLiteralPlaceholders: StringLiteralPlaceholders): FailNodeDefinition {\n const node = {\n type: \"fail\",\n ...parseAttributeTokens(tokens, stringLiteralPlaceholders)\n } as FailNodeDefinition;\n\n // This is a decorator node, so we expect an opening '{'.\n popAndCheck(tokens, \"{\");\n\n // Return the fail node definition.\n return node;\n}\n\n/**\n * Creates a flip node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The flip node JSON definition.\n */\nfunction createFlipNode(tokens: string[], stringLiteralPlaceholders: StringLiteralPlaceholders): FlipNodeDefinition {\n const node = {\n type: \"flip\",\n ...parseAttributeTokens(tokens, stringLiteralPlaceholders)\n } as FlipNodeDefinition;\n\n // This is a decorator node, so we expect an opening '{'.\n popAndCheck(tokens, \"{\");\n\n // Return the flip node definition.\n return node;\n}\n\n/**\n * Creates a repeat node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The repeat node JSON definition.\n */\nfunction createRepeatNode(\n tokens: string[],\n stringLiteralPlaceholders: StringLiteralPlaceholders\n): RepeatNodeDefinition {\n let node = { type: \"repeat\" } as RepeatNodeDefinition;\n\n // Get the node arguments.\n const nodeArguments = parseArgumentTokens(tokens, stringLiteralPlaceholders);\n\n // The arguments of a repeat node are optional. We may have:\n // - No node arguments, in which case the repeat note will iterate indefinitely.\n // - One node argument which will be the explicit number of iterations to make.\n // - Two node arguments which define the min and max iteration bounds from which a random iteration count will be picked.\n if (nodeArguments.length) {\n // All repeat node arguments MUST be of type number and must be integer.\n nodeArguments\n .filter((arg) => arg.type !== \"number\" || !arg.isInteger)\n .forEach(() => {\n throw new Error(`repeat node iteration counts must be integer values`);\n });\n\n // We should have got one or two iteration counts.\n if (nodeArguments.length === 1) {\n // A static iteration count was defined.\n node.iterations = nodeArguments[0].value as number;\n } else if (nodeArguments.length === 2) {\n // A minimum and maximum iteration count was defined.\n node.iterations = [nodeArguments[0].value as number, nodeArguments[1].value as number];\n } else {\n // An incorrect number of iteration counts was defined.\n throw new Error(\"invalid number of repeat node iteration count arguments defined\");\n }\n }\n\n // Grab any node attribute definitions and spread them into the node definition.\n node = { ...node, ...parseAttributeTokens(tokens, stringLiteralPlaceholders) };\n\n // This is a decorator node, so we expect an opening '{'.\n popAndCheck(tokens, \"{\");\n\n // Return the repeat node definition.\n return node;\n}\n\n/**\n * Creates a retry node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The retry node JSON definition.\n */\nfunction createRetryNode(tokens: string[], stringLiteralPlaceholders: StringLiteralPlaceholders): RetryNodeDefinition {\n let node = { type: \"retry\" } as RetryNodeDefinition;\n\n // Get the node arguments.\n const nodeArguments = parseArgumentTokens(tokens, stringLiteralPlaceholders);\n\n // The arguments of a retry node are optional. We may have:\n // - No node arguments, in which case the retry note will attempt indefinitely.\n // - One node argument which will be the explicit number of attempts to make.\n // - Two node arguments which define the min and max attempt bounds from which a random attempt count will be picked.\n if (nodeArguments.length) {\n // All retry node arguments MUST be of type number and must be integer.\n nodeArguments\n .filter((arg) => arg.type !== \"number\" || !arg.isInteger)\n .forEach(() => {\n throw new Error(`retry node attempt counts must be integer values`);\n });\n\n // We should have got one or two attempt counts.\n if (nodeArguments.length === 1) {\n // A static attempt count was defined.\n node.attempts = nodeArguments[0].value as number;\n } else if (nodeArguments.length === 2) {\n // A minimum and maximum attempt count was defined.\n node.attempts = [nodeArguments[0].value as number, nodeArguments[1].value as number];\n } else {\n // An incorrect number of attempt counts was defined.\n throw new Error(\"invalid number of retry node attempt count arguments defined\");\n }\n }\n\n // Grab any node attribute definitions and spread them into the node definition.\n node = { ...node, ...parseAttributeTokens(tokens, stringLiteralPlaceholders) };\n\n // This is a decorator node, so we expect an opening '{'.\n popAndCheck(tokens, \"{\");\n\n // Return the retry node definition.\n return node;\n}\n\n/**\n * Creates a sequence node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The sequence node JSON definition.\n */\nfunction createSequenceNode(\n tokens: string[],\n stringLiteralPlaceholders: StringLiteralPlaceholders\n): SequenceNodeDefinition {\n const node = {\n type: \"sequence\",\n ...parseAttributeTokens(tokens, stringLiteralPlaceholders)\n } as SequenceNodeDefinition;\n\n // This is a composite node, so we expect an opening '{'.\n popAndCheck(tokens, \"{\");\n\n // Return the sequence node definition.\n return node;\n}\n\n/**\n * Creates a selector node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The selector node JSON definition.\n */\nfunction createSelectorNode(\n tokens: string[],\n stringLiteralPlaceholders: StringLiteralPlaceholders\n): SelectorNodeDefinition {\n const node = {\n type: \"selector\",\n ...parseAttributeTokens(tokens, stringLiteralPlaceholders)\n } as SelectorNodeDefinition;\n\n // This is a composite node, so we expect an opening '{'.\n popAndCheck(tokens, \"{\");\n\n // Return the selector node definition.\n return node;\n}\n\n/**\n * Creates a parallel node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The parallel node JSON definition.\n */\nfunction createParallelNode(\n tokens: string[],\n stringLiteralPlaceholders: StringLiteralPlaceholders\n): ParallelNodeDefinition {\n const node = {\n type: \"parallel\",\n ...parseAttributeTokens(tokens, stringLiteralPlaceholders)\n } as ParallelNodeDefinition;\n\n // This is a composite node, so we expect an opening '{'.\n popAndCheck(tokens, \"{\");\n\n // Return the parallel node definition.\n return node;\n}\n\n/**\n * Creates a lotto node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The lotto node JSON definition.\n */\nfunction createLottoNode(tokens: string[], stringLiteralPlaceholders: StringLiteralPlaceholders): LottoNodeDefinition {\n // If any node arguments have been defined then they must be our weights.\n const nodeArguments = parseArgumentTokens(tokens, stringLiteralPlaceholders);\n\n // All lotto node arguments MUST be of type number and must be integer.\n nodeArguments\n .filter((arg) => arg.type !== \"number\" || !arg.isInteger)\n .forEach(() => {\n throw new Error(`lotto node weight arguments must be integer values`);\n });\n\n const node = {\n type: \"lotto\",\n weights: nodeArguments.map(({ value }) => value),\n ...parseAttributeTokens(tokens, stringLiteralPlaceholders)\n } as LottoNodeDefinition;\n\n // This is a composite node, so we expect an opening '{'.\n popAndCheck(tokens, \"{\");\n\n // Return the lotto node definition.\n return node;\n}\n\n/**\n * Creates an action node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The action node JSON definition.\n */\nfunction createActionNode(\n tokens: string[],\n stringLiteralPlaceholders: StringLiteralPlaceholders\n): ActionNodeDefinition {\n // Parse any node arguments, we should have at least one which will be an identifier argument for the action name\n // and agent function to invoke for the action, all other arguments are to be passed as arguments to that function.\n const [actionNameIdentifier, ...agentFunctionArgs] = parseArgumentTokens(tokens, stringLiteralPlaceholders);\n\n // Our first argument MUST be defined and be an identifier as we require an action name argument.\n if (actionNameIdentifier?.type !== \"identifier\") {\n throw new Error(\"expected action name identifier argument\");\n }\n\n // Only the first argument should have been an identifier, all agent function arguments must be string, number, boolean or null.\n agentFunctionArgs\n .filter((arg) => arg.type === \"identifier\")\n .forEach((arg) => {\n throw new Error(\n `invalid action node argument value '${arg.value}', must be string, number, boolean or null`\n );\n });\n\n // Return the action node definition.\n return {\n type: \"action\",\n call: actionNameIdentifier.value,\n args: agentFunctionArgs.map(({ value }) => value),\n ...parseAttributeTokens(tokens, stringLiteralPlaceholders)\n };\n}\n\n/**\n * Creates a condition node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The condition node JSON definition.\n */\nfunction createConditionNode(\n tokens: string[],\n stringLiteralPlaceholders: StringLiteralPlaceholders\n): ConditionNodeDefinition {\n // Parse any node arguments, we should have at least one which will be an identifier argument for the condition name\n // and agent function to invoke for the condition, all other arguments are to be passed as arguments to that function.\n const [conditionNameIdentifier, ...agentFunctionArgs] = parseArgumentTokens(tokens, stringLiteralPlaceholders);\n\n // Our first argument MUST be defined and be an identifier as we require a condition name argument.\n if (conditionNameIdentifier?.type !== \"identifier\") {\n throw new Error(\"expected condition name identifier argument\");\n }\n\n // Only the first argument should have been an identifier, all agent function arguments must be string, number, boolean or null.\n agentFunctionArgs\n .filter((arg) => arg.type === \"identifier\")\n .forEach((arg) => {\n throw new Error(\n `invalid condition node argument value '${arg.value}', must be string, number, boolean or null`\n );\n });\n\n // Return the condition node definition.\n return {\n type: \"condition\",\n call: conditionNameIdentifier.value,\n args: agentFunctionArgs.map(({ value }) => value),\n ...parseAttributeTokens(tokens, stringLiteralPlaceholders)\n };\n}\n\n/**\n * Creates a wait node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The wait node JSON definition.\n */\nfunction createWaitNode(tokens: string[], stringLiteralPlaceholders: StringLiteralPlaceholders): WaitNodeDefinition {\n let node = { type: \"wait\" } as WaitNodeDefinition;\n\n // Get the node arguments.\n const nodeArguments = parseArgumentTokens(tokens, stringLiteralPlaceholders);\n\n // The arguments of a wait node are optional. We may have:\n // - No node arguments, in which case the wait will be indefinite until it is aborted.\n // - One node argument which will be the explicit duration of the wait.\n // - Two node arguments which define the min and max duration bounds from which a random duration will be picked.\n if (nodeArguments.length) {\n // All wait node arguments MUST be of type number and must be integer.\n nodeArguments\n .filter((arg) => arg.type !== \"number\" || !arg.isInteger)\n .forEach(() => {\n throw new Error(`wait node duration arguments must be integer values`);\n });\n\n // We may have:\n // - One node argument which will be the explicit duration of the wait.\n // - Two node arguments which define the min and max duration bounds from which a random duration will be picked.\n // - Too many arguments, which is not valid.\n if (nodeArguments.length === 1) {\n // An explicit duration was defined.\n node.duration = nodeArguments[0].value as number;\n } else if (nodeArguments.length === 2) {\n // Min and max duration bounds were defined from which a random duration will be picked.\n node.duration = [nodeArguments[0].value as number, nodeArguments[1].value as number];\n } else if (nodeArguments.length > 2) {\n // An incorrect number of duration arguments were defined.\n throw new Error(\"invalid number of wait node duration arguments defined\");\n }\n }\n\n // Return the wait node definition.\n return { ...node, ...parseAttributeTokens(tokens, stringLiteralPlaceholders) };\n}\n\n/**\n * Creates a branch node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The branch node JSON definition.\n */\nfunction createBranchNode(\n tokens: string[],\n stringLiteralPlaceholders: StringLiteralPlaceholders\n): BranchNodeDefinition {\n // Parse any node arguments, we should have one which will be an identifier argument for the root ref.\n const nodeArguments = parseArgumentTokens(tokens, stringLiteralPlaceholders);\n\n // We should have only a single identifer argument for a branch node, which is the root ref.\n if (nodeArguments.length !== 1 || nodeArguments[0].type !== \"identifier\") {\n throw new Error(\"expected single branch name argument\");\n }\n\n // Return the branch node definition.\n return { type: \"branch\", ref: nodeArguments[0].value };\n}\n", "import { RootNodeDefinition } from \"./BehaviourTreeDefinition\";\nimport { flattenDefinition, isBranchNode, isInteger } from \"./BehaviourTreeDefinitionUtilities\";\nimport { convertMDSLToJSON } from \"./mdsl/MDSLDefinitionParser\";\n\n/**\n * An object representing the result of validating a tree definition.\n */\nexport type DefinitionValidationResult = {\n /**\n * A flag defining whether validation succeeded.\n */\n succeeded: boolean;\n /**\n * A string containing the error message if validation did not succeed.\n */\n errorMessage?: string;\n};\n\n/**\n * Validates the specified behaviour tree definition in the form of JSON or MDSL.\n * @param definition The behaviour tree definition in the form of JSON or MDSL.\n * @returns An object representing the result of validating the given tree definition.\n */\nexport function validateDefinition(definition: any): DefinitionValidationResult {\n // A helper function to create a failure validation result with the given error message.\n const createFailureResult = (errorMessage: string) => ({ succeeded: false, errorMessage });\n\n // The definition must be defined.\n if (definition === null || typeof definition === \"undefined\") {\n return createFailureResult(\"definition is null or undefined\");\n }\n\n let rootNodeDefinitions: any[];\n\n // We are expecting a definition in one of three different forms:\n // - A string which we will assume is mdsl and we will parse this to JSON before validation.\n // - An array which we will assume is an array of root node definitions with at least one being the primary root node (no 'id' property)\n // - An object which we will assume is the primary root node and should not have an 'id' property.\n if (typeof definition === \"string\") {\n try {\n // The definition is a string which we can assume is mdsl, so attempt to parse it to a JSON definition in the form of an array of root node definitions.\n rootNodeDefinitions = convertMDSLToJSON(definition);\n } catch (error) {\n // We failed to parse the JSON from the mdsl, this is likely to be the result of it not being a valid mdsl string.\n return createFailureResult(`invalid mdsl: ${definition}`);\n }\n } else if (typeof definition === \"object\") {\n // The definition will either be an array (of root node definitions) or an object (the single primary root node definition).\n // If our definition is an array, we should verify that each of the elements within it are objects (potential root node definitions).\n if (Array.isArray(definition)) {\n // Find any invalid node definitions in our definition array, not full validation just a check that each is a valid object.\n const invalidDefinitionElements = definition.filter((element) => {\n // Each element isn't valid unless it is an object that isn't also an array and isn't null.\n return typeof element !== \"object\" || Array.isArray(element) || element === null;\n });\n\n // If we have any invalid node definitions then validation has failed.\n if (invalidDefinitionElements.length) {\n return createFailureResult(\n \"invalid elements in definition array, each must be an root node definition object\"\n );\n }\n\n // Our definition is already an array of root node definition objects.\n rootNodeDefinitions = definition;\n } else {\n // Our definition is an object, but we want an array of root node definitions.\n rootNodeDefinitions = [definition];\n }\n } else {\n return createFailureResult(`unexpected definition type of '${typeof definition}'`);\n }\n\n // Iterate over our array of root nodes and call validateNode for each, passing an initial depth of 0, wrapped in a try catch to handle validation failures.\n try {\n rootNodeDefinitions.forEach((rootNodeDefinition) => validateNode(rootNodeDefinition, 0));\n } catch (error) {\n // Handle cases where we have caught a thrown Error and return a failure result with the error message.\n if (error instanceof Error) {\n return createFailureResult(error.message);\n }\n\n // No idea what happened here!\n return createFailureResult(`unexpected error: ${error}`);\n }\n\n // Unpack all of the root node definitions into arrays of main ('id' defined) and sub ('id' not defined) root node definitions.\n const mainRootNodeDefinitions = rootNodeDefinitions.filter(({ id }) => typeof id === \"undefined\");\n const subRootNodeDefinitions = rootNodeDefinitions.filter(({ id }) => typeof id === \"string\" && id.length > 0);\n\n // We should ALWAYS have exactly one root node definition without an 'id' property defined, which is out main root node definition.\n if (mainRootNodeDefinitions.length !== 1) {\n return createFailureResult(\"expected single root node without 'id' property defined to act as main root\");\n }\n\n // We should never have duplicate 'id' properties across our sub root node definitions.\n const subRootNodeIdenitifers: string[] = [];\n for (const { id } of subRootNodeDefinitions) {\n // Have we already come across this 'id' property value?\n if (subRootNodeIdenitifers.includes(id)) {\n return createFailureResult(`multiple root nodes found with duplicate 'id' property value of '${id}'`);\n }\n\n subRootNodeIdenitifers.push(id);\n }\n\n // Check for any branch node circular depedencies. This will not include any globally registered subtrees.\n const circularDependencyPath = findBranchCircularDependencyPath(rootNodeDefinitions);\n\n // If we found a circular dependency in our root node and branch node definitions then the definition is definitely not valid.\n if (circularDependencyPath) {\n return createFailureResult(`circular dependency found in branch node references: ${circularDependencyPath}`);\n }\n\n // Our definition was valid!\n return { succeeded: true };\n}\n\n/**\n * Find the first circular depdendency path present in the array of root node definitions, or null if one doesn't exist.\n * This will not consider branch nodes that reference any globally registered subtrees.\n * @param rootNodeDefinitions The array of root node definitions.\n * @returns The first circular depdendency path present in the array of root node definitions as string, or null if one doesn't exist.\n */\nfunction findBranchCircularDependencyPath(rootNodeDefinitions: RootNodeDefinition[]): string | null {\n // Create a mapping of root node identifiers to other root nodes that they reference via branch nodes.\n // Below is an example of a mapping that includes a circular dependency (root => a => b => c => a)\n // [{ refs: [\"a\", \"b\"] }, { id: \"a\", refs: [\"b\"] }, { id: \"b\", refs: [\"c\"] }, { id: \"c\", refs: [\"a\"] }]\n const rootNodeMappings: { id: string | undefined; refs: string[] }[] = rootNodeDefinitions.map(\n (rootNodeDefinition) => ({\n id: rootNodeDefinition.id,\n refs: flattenDefinition(rootNodeDefinition)\n .filter(isBranchNode)\n .map(({ ref }) => ref)\n })\n );\n\n let badPathFormatted: string | null = null;\n\n // A recursive function to walk through the mappings, keeping track of which root nodes we have visited in the form of a path of root node identifiers.\n const followRefs = (mapping: { id: string | undefined; refs: string[] }, path: (string | undefined)[] = []) => {\n // Have we found a circular dependency?\n if (path.includes(mapping.id)) {\n // We found a circular dependency! Get the bad path of root node identifiers.\n const badPath = [...path, mapping.id];\n\n // Set the formatted path value. [undefined, \"a\", \"b\", \"c\", \"a\"] would be formatted as \"a -> b -> c -> a\".\n badPathFormatted = badPath.map((element) => !!element).join(\" => \");\n\n // No need to continue, we found a circular dependency.\n return;\n }\n\n for (const ref of mapping.refs) {\n // Find the mapping for the root node with an identifer matching the current ref.\n const subMapping = rootNodeMappings.find(({ id }) => id === ref);\n\n // We may not have a mapping for this ref, which will happen if this ref is for a globally registered subtree.\n if (subMapping) {\n followRefs(subMapping, [...path, mapping.id]);\n }\n }\n };\n\n return badPathFormatted;\n}\n\n/**\n * Validate an object that we expect to be a node definition.\n * @param definition An object that we expect to be a node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateNode(definition: any, depth: number): void {\n // Every node must be valid object and have a non-empty 'type' string property.\n if (typeof definition !== \"object\" || typeof definition.type !== \"string\" || definition.type.length === 0) {\n throw new Error(\n `node definition is not an object or 'type' property is not a non-empty string at depth '${depth}'`\n );\n }\n\n // How we validate this node definition will depend on its type.\n switch (definition.type) {\n case \"action\":\n validateActionNode(definition, depth);\n break;\n\n case \"condition\":\n validateConditionNode(definition, depth);\n break;\n\n case \"wait\":\n validateWaitNode(definition, depth);\n break;\n\n case \"branch\":\n validateBranchNode(definition, depth);\n break;\n\n case \"root\":\n validateRootNode(definition, depth);\n break;\n\n case \"success\":\n validateSuccessNode(definition, depth);\n break;\n\n case \"fail\":\n validateFailNode(definition, depth);\n break;\n\n case \"flip\":\n validateFlipNode(definition, depth);\n break;\n\n case \"repeat\":\n validateRepeatNode(definition, depth);\n break;\n\n case \"retry\":\n validateRetryNode(definition, depth);\n break;\n\n case \"sequence\":\n validateSequenceNode(definition, depth);\n break;\n\n case \"selector\":\n validateSelectorNode(definition, depth);\n break;\n\n case \"parallel\":\n validateParallelNode(definition, depth);\n break;\n\n default:\n throw new Error(`unexpected node type of '${definition.type}' at depth '${depth}'`);\n }\n}\n\n/**\n * Validate any attributes for a given node definition.\n * @param definition The node definition.\n * @param depth The depth of the node in the behaviour tree definition.\n */\nfunction validateNodeAttributes(definition: any, depth: number): void {\n // Validate each of the attribute types for this node.\n [\"while\", \"until\", \"entry\", \"exit\", \"step\"].forEach((attributeName) => {\n // Attempt to grab the definition for the current attribute from the node definition.\n const attributeDefinition = definition[attributeName];\n\n // All node attributes are optional, so there is nothing to do if the current attribute is not defined.\n if (typeof attributeDefinition === \"undefined\") {\n return;\n }\n\n // The attribute definition must be an object.\n if (typeof attributeDefinition !== \"object\") {\n throw new Error(\n `expected attribute '${attributeName}' to be an object for '${definition.type}' node at depth '${depth}'`\n );\n }\n\n // The 'call' property must be defined for any attribute definition.\n if (typeof attributeDefinition.call !== \"string\" || attributeDefinition.call.length === 0) {\n throw new Error(\n `expected 'call' property for attribute '${attributeName}' to be a non-empty string for '${definition.type}' node at depth '${depth}'`\n );\n }\n\n // If any node attribute arguments have been defined then they must have been defined in an array.\n if (typeof attributeDefinition.args !== \"undefined\" && !Array.isArray(attributeDefinition.args)) {\n throw new Error(\n `expected 'args' property for attribute '${attributeName}' to be an array for '${definition.type}' node at depth '${depth}'`\n );\n }\n });\n}\n\n/**\n * Validate an object that we expect to be a root node definition.\n * @param definition An object that we expect to be a root node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateRootNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"root\") {\n throw new Error(\"expected node type of 'root' for root node\");\n }\n\n // A root node cannot be the child of another node.\n if (depth > 0) {\n throw new Error(\"a root node cannot be the child of another node\");\n }\n\n // Check that, if the root node 'id' property is defined, it is a non-empty string.\n if (typeof definition.id !== \"undefined\" && (typeof definition.id !== \"string\" || definition.id.length === 0)) {\n throw new Error(\"expected non-empty string for 'id' property if defined for root node\");\n }\n\n // A root node is a decorator node, so must have a child node defined.\n if (typeof definition.child === \"undefined\") {\n throw new Error(\"expected property 'child' to be defined for root node\");\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n\n // Validate the child node of this decorator node.\n validateNode(definition.child, depth + 1);\n}\n\n/**\n * Validate an object that we expect to be a success node definition.\n * @param definition An object that we expect to be a success node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateSuccessNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"success\") {\n throw new Error(`expected node type of 'success' for success node at depth '${depth}'`);\n }\n\n // A success node is a decorator node, so must have a child node defined.\n if (typeof definition.child === \"undefined\") {\n throw new Error(`expected property 'child' to be defined for success node at depth '${depth}'`);\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n\n // Validate the child node of this decorator node.\n validateNode(definition.child, depth + 1);\n}\n\n/**\n * Validate an object that we expect to be a fail node definition.\n * @param definition An object that we expect to be a fail node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateFailNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"fail\") {\n throw new Error(`expected node type of 'fail' for fail node at depth '${depth}'`);\n }\n\n // A fail node is a decorator node, so must have a child node defined.\n if (typeof definition.child === \"undefined\") {\n throw new Error(`expected property 'child' to be defined for fail node at depth '${depth}'`);\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n\n // Validate the child node of this decorator node.\n validateNode(definition.child, depth + 1);\n}\n\n/**\n * Validate an object that we expect to be a flip node definition.\n * @param definition An object that we expect to be a flip node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateFlipNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"flip\") {\n throw new Error(`expected node type of 'flip' for flip node at depth '${depth}'`);\n }\n\n // A flip node is a decorator node, so must have a child node defined.\n if (typeof definition.child === \"undefined\") {\n throw new Error(`expected property 'child' to be defined for flip node at depth '${depth}'`);\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n\n // Validate the child node of this decorator node.\n validateNode(definition.child, depth + 1);\n}\n\n/**\n * Validate an object that we expect to be a repeat node definition.\n * @param definition An object that we expect to be a repeat node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateRepeatNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"repeat\") {\n throw new Error(`expected node type of 'repeat' for repeat node at depth '${depth}'`);\n }\n\n // A repeat node is a decorator node, so must have a child node defined.\n if (typeof definition.child === \"undefined\") {\n throw new Error(`expected property 'child' to be defined for repeat node at depth '${depth}'`);\n }\n\n // Check whether an 'iterations' property has been defined, it may not have been if this node is to repeat indefinitely.\n if (typeof definition.iterations !== \"undefined\") {\n if (Array.isArray(definition.iterations)) {\n // Check whether any elements of the array are not integer values.\n const containsNonInteger = !!definition.iterations.find((value: unknown) => !isInteger(value));\n\n // If the 'iterations' property is an array then it MUST contain two integer values.\n if (definition.iterations.length !== 2 || containsNonInteger) {\n throw new Error(\n `expected array containing two integer values for 'iterations' property if defined for repeat node at depth '${depth}'`\n );\n }\n } else if (!isInteger(definition.iterations)) {\n throw new Error(\n `expected integer value or array containing two integer values for 'iterations' property if defined for repeat node at depth '${depth}'`\n );\n }\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n\n // Validate the child node of this decorator node.\n validateNode(definition.child, depth + 1);\n}\n\n/**\n * Validate an object that we expect to be a retry node definition.\n * @param definition An object that we expect to be a retry node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateRetryNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"retry\") {\n throw new Error(`expected node type of 'retry' for retry node at depth '${depth}'`);\n }\n\n // A retry node is a decorator node, so must have a child node defined.\n if (typeof definition.child === \"undefined\") {\n throw new Error(`expected property 'child' to be defined for retry node at depth '${depth}'`);\n }\n\n // Check whether an 'attempts' property has been defined, it may not have been if this node is to retry indefinitely.\n if (typeof definition.attempts !== \"undefined\") {\n if (Array.isArray(definition.attempts)) {\n // Check whether any elements of the array are not integer values.\n const containsNonInteger = !!definition.attempts.find((value: unknown) => !isInteger(value));\n\n // If the 'attempts' property is an array then it MUST contain two integer values.\n if (definition.attempts.length !== 2 || containsNonInteger) {\n throw new Error(\n `expected array containing two integer values for 'attempts' property if defined for retry node at depth '${depth}'`\n );\n }\n } else if (!isInteger(definition.attempts)) {\n throw new Error(\n `expected integer value or array containing two integer values for 'attempts' property if defined for retry node at depth '${depth}'`\n );\n }\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n\n // Validate the child node of this decorator node.\n validateNode(definition.child, depth + 1);\n}\n\n/**\n * Validate an object that we expect to be a branch node definition.\n * @param definition An object that we expect to be a branch node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateBranchNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"branch\") {\n throw new Error(`expected node type of 'branch' for branch node at depth '${depth}'`);\n }\n\n // Check that the branch node 'ref' property is defined and is a non-empty string.\n if (typeof definition.ref !== \"string\" || definition.ref.length === 0) {\n throw new Error(`expected non-empty string for 'ref' property for branch node at depth '${depth}'`);\n }\n\n // It is invalid to define guard attributes for a branch node as they should be defined on the referenced root node.\n [\"while\", \"until\"].forEach((attributeName) => {\n if (typeof definition[attributeName] !== \"undefined\") {\n throw new Error(\n `guards should not be defined for branch nodes but guard '${attributeName}' was defined for branch node at depth '${depth}'`\n );\n }\n });\n\n // It is invalid to define callback attributes for a branch node as they should be defined on the referenced root node.\n [\"entry\", \"exit\", \"step\"].forEach((attributeName) => {\n if (typeof definition[attributeName] !== \"undefined\") {\n throw new Error(\n `callbacks should not be defined for branch nodes but callback '${attributeName}' was defined for branch node at depth '${depth}'`\n );\n }\n });\n}\n\n/**\n * Validate an object that we expect to be a action node definition.\n * @param definition An object that we expect to be a action node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateActionNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"action\") {\n throw new Error(`expected node type of 'action' for action node at depth '${depth}'`);\n }\n\n // The 'call' property must be defined for a action node definition.\n if (typeof definition.call !== \"string\" || definition.call.length === 0) {\n throw new Error(`expected non-empty string for 'call' property of action node at depth '${depth}'`);\n }\n\n // If any action function arguments have been defined then they must have been defined in an array.\n if (typeof definition.args !== \"undefined\" && !Array.isArray(definition.args)) {\n throw new Error(`expected array for 'args' property if defined for action node at depth '${depth}'`);\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n}\n\n/**\n * Validate an object that we expect to be a condition node definition.\n * @param definition An object that we expect to be a condition node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateConditionNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"condition\") {\n throw new Error(`expected node type of 'condition' for condition node at depth '${depth}'`);\n }\n\n // The 'call' property must be defined for a condition node definition.\n if (typeof definition.call !== \"string\" || definition.call.length === 0) {\n throw new Error(`expected non-empty string for 'call' property of condition node at depth '${depth}'`);\n }\n\n // If any condition function arguments have been defined then they must have been defined in an array.\n if (typeof definition.args !== \"undefined\" && !Array.isArray(definition.args)) {\n throw new Error(`expected array for 'args' property if defined for condition node at depth '${depth}'`);\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n}\n\n/**\n * Validate an object that we expect to be a wait node definition.\n * @param definition An object that we expect to be a wait node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateWaitNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"wait\") {\n throw new Error(`expected node type of 'wait' for wait node at depth '${depth}'`);\n }\n\n // Check whether a 'duration' property has been defined, it may not have been if this node is to wait indefinitely.\n if (typeof definition.duration !== \"undefined\") {\n if (Array.isArray(definition.duration)) {\n // Check whether any elements of the array are not integer values.\n const containsNonInteger = !!definition.duration.find((value: unknown) => !isInteger(value));\n\n // If the 'duration' property is an array then it MUST contain two integer values.\n if (definition.duration.length !== 2 || containsNonInteger) {\n throw new Error(\n `expected array containing two integer values for 'duration' property if defined for wait node at depth '${depth}'`\n );\n }\n } else if (!isInteger(definition.duration)) {\n throw new Error(\n `expected integer value or array containing two integer values for 'duration' property if defined for wait node at depth '${depth}'`\n );\n }\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n}\n\n/**\n * Validate an object that we expect to be a sequence node definition.\n * @param definition An object that we expect to be a sequence node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateSequenceNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"sequence\") {\n throw new Error(`expected node type of 'sequence' for sequence node at depth '${depth}'`);\n }\n\n // A sequence node is a composite node, so must have a children nodes array defined.\n if (!Array.isArray(definition.children) || definition.children.length === 0) {\n throw new Error(`expected non-empty 'children' array to be defined for sequence node at depth '${depth}'`);\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n\n // Validate the child nodes of this composite node.\n definition.children.forEach((child: any) => validateNode(child, depth + 1));\n}\n\n/**\n * Validate an object that we expect to be a selector node definition.\n * @param definition An object that we expect to be a selector node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateSelectorNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"selector\") {\n throw new Error(`expected node type of 'selector' for selector node at depth '${depth}'`);\n }\n\n // A selector node is a composite node, so must have a children nodes array defined.\n if (!Array.isArray(definition.children) || definition.children.length === 0) {\n throw new Error(`expected non-empty 'children' array to be defined for selector node at depth '${depth}'`);\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n\n // Validate the child nodes of this composite node.\n definition.children.forEach((child: any) => validateNode(child, depth + 1));\n}\n\n/**\n * Validate an object that we expect to be a parallel node definition.\n * @param definition An object that we expect to be a parallel node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateParallelNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"parallel\") {\n throw new Error(`expected node type of 'parallel' for parallel node at depth '${depth}'`);\n }\n\n // A parallel node is a composite node, so must have a children nodes array defined.\n if (!Array.isArray(definition.children) || definition.children.length === 0) {\n throw new Error(`expected non-empty 'children' array to be defined for parallel node at depth '${depth}'`);\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n\n // Validate the child nodes of this composite node.\n definition.children.forEach((child: any) => validateNode(child, depth + 1));\n}\n", "import Node from \"../../nodes/Node\";\n\n/**\n * An exception thrown when evaluating node guard path conditions and a conditions fails.\n */\nexport default class GuardUnsatisifedException extends Error {\n /**\n * @param source The node at which a guard condition failed.\n */\n constructor(private source: Node) {\n super(\"A guard path condition has failed\");\n }\n\n /**\n * Gets whether the specified node is the node at which a guard condition failed.\n * @param node The node to check against the source node.\n * @returns Whether the specified node is the node at which a guard condition failed.\n */\n isSourceNode = (node: Node) => node === this.source;\n}\n", "import { Agent } from \"../../Agent\";\nimport Guard from \"./Guard\";\nimport Node from \"../../nodes/Node\";\nimport GuardUnsatisifedException from \"./GuardUnsatisifedException\";\n\nexport type GuardPathPart = {\n node: Node;\n guards: Guard[];\n};\n\n/**\n * Represents a path of node guards along a root-to-leaf tree path.\n */\nexport default class GuardPath {\n /**\n * @param nodes An array of objects defining a node instance -> guard link, ordered by node depth.\n */\n constructor(private nodes: GuardPathPart[]) {}\n\n /**\n * Evaluate guard conditions for all guards in the tree path, moving outwards from the root.\n * @param agent The agent, required for guard evaluation.\n * @returns An evaluation results object.\n */\n evaluate = (agent: Agent) => {\n // We need to evaluate guard conditions for nodes up the tree, moving outwards from the root.\n for (const details of this.nodes) {\n // There can be multiple guards per node.\n for (const guard of details.guards) {\n // Check whether the guard condition passes, and throw an exception if not.\n if (!guard.isSatisfied(agent)) {\n throw new GuardUnsatisifedException(details.node);\n }\n }\n }\n };\n}\n", "import { Agent } from \"../Agent\";\nimport Attribute from \"../attributes/Attribute\";\nimport Entry from \"../attributes/callbacks/Entry\";\nimport Exit from \"../attributes/callbacks/Exit\";\nimport Step from \"../attributes/callbacks/Step\";\nimport Guard from \"../attributes/guards/Guard\";\nimport GuardPath from \"../attributes/guards/GuardPath\";\nimport GuardUnsatisifedException from \"../attributes/guards/GuardUnsatisifedException\";\nimport { BehaviourTreeOptions } from \"../BehaviourTreeOptions\";\nimport { AnyArgument } from \"../RootAstNodesBuilder\";\nimport State, { AnyState } from \"../State\";\nimport Leaf from \"./leaf/Leaf\";\n\n/**\n * A base node.\n */\nexport default abstract class Node {\n /**\n * The node uid.\n */\n private readonly uid: string = createNodeUid();\n /**\n * The node state.\n */\n private state: AnyState = State.READY;\n /**\n * The guard path to evaluate as part of a node update.\n */\n private guardPath: GuardPath | undefined;\n\n /**\n * @param type The node type.\n * @param attributes The node attributes.\n * @param args The node argument definitions.\n */\n constructor(private type: string, private attributes: Attribute[], private args: AnyArgument[]) {}\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected abstract onUpdate(agent: Agent, options: BehaviourTreeOptions): void;\n\n /**\n * Gets the name of the node.\n */\n public abstract getName(): string;\n\n /**\n * Gets whether this node is a leaf node.\n */\n public abstract isLeafNode: () => this is Leaf;\n\n /**\n * Gets/Sets the state of the node.\n */\n getState = (): AnyState => this.state;\n setState = (value: AnyState): void => {\n this.state = value;\n };\n\n /**\n * Gets the unique id of the node.\n */\n getUid = () => this.uid;\n\n /**\n * Gets the type of the node.\n */\n getType = () => this.type;\n\n /**\n * Gets the node attributes.\n */\n getAttributes = () => this.attributes;\n\n /**\n * Gets the node arguments.\n */\n getArguments = () => this.args;\n\n /**\n * Gets the node attribute with the specified type, or null if it does not exist.\n */\n getAttribute(type: \"entry\" | \"ENTRY\"): Entry;\n getAttribute(type: \"exit\" | \"EXIT\"): Exit;\n getAttribute(type: \"step\" | \"STEP\"): Step;\n getAttribute(type: string): Attribute {\n return (\n this.getAttributes().filter((decorator) => decorator.getType().toUpperCase() === type.toUpperCase())[0] ||\n null\n );\n }\n\n /**\n * Gets the node attributes.\n */\n getGuardAttributes = (): Guard[] => this.getAttributes().filter((decorator) => decorator.isGuard()) as Guard[];\n\n /**\n * Sets the guard path to evaluate as part of a node update.\n */\n setGuardPath = (value: GuardPath) => (this.guardPath = value);\n\n /**\n * Gets whether a guard path is assigned to this node.\n */\n hasGuardPath = () => !!this.guardPath;\n\n /**\n * Gets whether this node is in the specified state.\n * @param value The value to compare to the node state.\n */\n public is(value: AnyState): boolean {\n return this.state === value;\n }\n\n /**\n * Reset the state of the node.\n */\n public reset(): void {\n this.setState(State.READY);\n }\n\n /**\n * Abort the running of this node.\n * @param agent The agent.\n */\n public abort(agent: Agent): void {\n // There is nothing to do if this node is not in the running state.\n if (!this.is(State.RUNNING)) {\n return;\n }\n\n // Reset the state of this node.\n this.reset();\n\n this.getAttribute(\"exit\")?.callAgentFunction(agent, false, true);\n }\n\n /**\n * Update the node.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n * @returns The result of the update.\n */\n public update(agent: Agent, options: BehaviourTreeOptions): void {\n // If this node is already in a 'SUCCEEDED' or 'FAILED' state then there is nothing to do.\n if (this.is(State.SUCCEEDED) || this.is(State.FAILED)) {\n return;\n }\n\n try {\n // Evaluate all of the guard path conditions for the current tree path.\n this.guardPath!.evaluate(agent);\n\n // If this node is in the READY state then call the ENTRY for this node if it exists.\n if (this.is(State.READY)) {\n this.getAttribute(\"entry\")?.callAgentFunction(agent);\n }\n\n this.getAttribute(\"step\")?.callAgentFunction(agent);\n\n // Do the actual update.\n this.onUpdate(agent, options);\n\n // If this node is now in a 'SUCCEEDED' or 'FAILED' state then call the EXIT for this node if it exists.\n if (this.is(State.SUCCEEDED) || this.is(State.FAILED)) {\n this.getAttribute(\"exit\")?.callAgentFunction(agent, this.is(State.SUCCEEDED), false);\n }\n } catch (error) {\n // If the error is a GuardUnsatisfiedException then we need to determine if this node is the source.\n if (error instanceof GuardUnsatisifedException && error.isSourceNode(this)) {\n // Abort the current node.\n this.abort(agent);\n\n // Any node that is the source of an abort will be a failed node.\n this.setState(State.FAILED);\n } else {\n throw error;\n }\n }\n }\n}\n\n/**\n * Create a randomly generated node uid.\n * @returns A randomly generated node uid.\n */\nfunction createNodeUid(): string {\n var S4 = function () {\n return (((1 + Math.random()) * 0x10000) | 0).toString(16).substring(1);\n };\n return S4() + S4() + \"-\" + S4() + \"-\" + S4() + \"-\" + S4() + \"-\" + S4() + S4() + S4();\n}\n", "import Node from \"../Node\";\n\n/**\n * A leaf node.\n */\nexport default abstract class Leaf extends Node {\n /**\n * Gets whether this node is a leaf node.\n */\n isLeafNode = () => true;\n}\n", "import { ActionResult, Agent, ExitFunctionArg, FunctionArg, GlobalFunction } from \"./Agent\";\nimport { AnyArgument, RootAstNode } from \"./RootAstNodesBuilder\";\n\n// Exit callbacks receive their own special type of argument.\n// There's probably stricter ways to represent this but it feels overly complex right now.\ntype ExitResultArg = { value: ExitFunctionArg };\nexport type AnyExitArgument = AnyArgument | ExitResultArg;\n\nexport type InvokerFunction = (args: AnyExitArgument[]) => ActionResult;\n\n/**\n * A singleton used to store and lookup registered functions and subtrees.\n */\nexport default class Lookup {\n /**\n * The object holding any registered functions keyed on function name.\n */\n private static functionTable: { [key: string]: GlobalFunction } = {};\n /**\n * The object holding any registered sub-trees keyed on tree name.\n */\n private static subtreeTable: { [key: string]: RootAstNode } = {};\n\n /**\n * Gets the function with the specified name.\n * @param name The name of the function.\n * @returns The function with the specified name.\n */\n public static getFunc(name: string): GlobalFunction {\n return this.functionTable[name];\n }\n\n /**\n * Sets the function with the specified name for later lookup.\n * @param name The name of the function.\n * @param func The function.\n */\n public static setFunc(name: string, func: GlobalFunction): void {\n this.functionTable[name] = func;\n }\n\n /**\n * Gets the function invoker for the specified agent and function name.\n * If a function with the specified name exists on the agent object then it will\n * be returned, otherwise we will then check the registered functions for a match.\n * @param agent The agent instance that this behaviour tree is modelling behaviour for.\n * @param name The function name.\n * @returns The function invoker for the specified agent and function name.\n */\n static getFuncInvoker(agent: Agent, name: string): InvokerFunction | null {\n // Check whether the agent contains the specified function.\n const foundOnAgent = agent[name];\n if (foundOnAgent && typeof foundOnAgent === \"function\") {\n return (args: AnyExitArgument[]): boolean | ActionResult =>\n foundOnAgent.apply(\n agent,\n args.map((arg) => arg.value)\n );\n }\n\n // The agent does not contain the specified function but it may have been registered at some point.\n if (this.functionTable[name] && typeof this.functionTable[name] === \"function\") {\n return (args: AnyExitArgument[]) => this.functionTable[name](agent, ...args.map((arg) => arg.value));\n }\n\n // We have no function to invoke.\n return null;\n }\n\n /**\n * Gets the subtree with the specified name.\n * @param name The name of the subtree.\n * @returns The subtree with the specified name.\n */\n static getSubtree(name: string): RootAstNode {\n return this.subtreeTable[name];\n }\n\n /**\n * Sets the subtree with the specified name for later lookup.\n * @param name The name of the subtree.\n * @param subtree The subtree.\n */\n static setSubtree(name: string, subtree: RootAstNode) {\n this.subtreeTable[name] = subtree;\n }\n\n /**\n * Removes the registered function or subtree with the specified name.\n * @param name The name of the registered function or subtree.\n */\n static remove(name: string) {\n delete this.functionTable[name];\n delete this.subtreeTable[name];\n }\n\n /**\n * Remove all registered functions and subtrees.\n */\n static empty() {\n this.functionTable = {};\n this.subtreeTable = {};\n }\n}\n", "import Leaf from \"./Leaf\";\nimport State, { CompleteState } from \"../../State\";\nimport Lookup from \"../../Lookup\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { AnyArgument } from \"../../RootAstNodesBuilder\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * An Action leaf node.\n * This represents an immediate or ongoing state of behaviour.\n */\nexport default class Action extends Leaf {\n /**\n * @param attributes The node attributes.\n * @param actionName The action name.\n * @param actionArguments The array of action argument definitions.\n */\n constructor(attributes: Attribute[], private actionName: string, private actionArguments: AnyArgument[]) {\n super(\"action\", attributes, actionArguments);\n }\n\n /**\n * Whether there is a pending update promise.\n */\n private isUsingUpdatePromise = false;\n\n /**\n * The finished state result of an update promise.\n */\n private updatePromiseStateResult: CompleteState | null = null;\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // If the result of this action depends on an update promise then there is nothing to do until\n // it resolves, unless there has been a value set as a result of the update promise resolving.\n if (this.isUsingUpdatePromise) {\n // Check whether the update promise has resolved with a state value.\n if (this.updatePromiseStateResult) {\n // Set the state of this node to match the state returned by the promise.\n this.setState(this.updatePromiseStateResult);\n }\n\n return;\n }\n\n // Attempt to get the invoker for the action function.\n const actionFuncInvoker = Lookup.getFuncInvoker(agent, this.actionName);\n\n // The action function should be defined.\n if (actionFuncInvoker === null) {\n throw new Error(\n `cannot update action node as the action '${this.actionName}' function is not defined on the agent and has not been registered`\n );\n }\n\n // Call the action function, the result of which may be:\n // - The finished state of this action node.\n // - A promise to return a finished node state.\n // - Undefined if the node should remain in the running state.\n const updateResult = actionFuncInvoker(this.actionArguments) as CompleteState | Promise;\n\n if (updateResult instanceof Promise) {\n updateResult.then(\n (result) => {\n // If 'isUpdatePromisePending' is null then the promise was cleared as it was resolving, probably via an abort of reset.\n if (!this.isUsingUpdatePromise) {\n return;\n }\n\n // Check to make sure the result is a valid finished state.\n if (result !== State.SUCCEEDED && result !== State.FAILED) {\n throw new Error(\n \"action node promise resolved with an invalid value, expected a State.SUCCEEDED or State.FAILED value to be returned\"\n );\n }\n\n // Set pending update promise state result to be processed on next update.\n this.updatePromiseStateResult = result;\n },\n (reason) => {\n // If 'isUpdatePromisePending' is null then the promise was cleared as it was resolving, probably via an abort of reset.\n if (!this.isUsingUpdatePromise) {\n return;\n }\n\n // Just throw whatever was returned as the rejection argument.\n throw new Error(reason);\n }\n );\n\n // This node will be in the 'RUNNING' state until the update promise resolves.\n this.setState(State.RUNNING);\n\n // We are now waiting for the promise returned by the use to resolve before we know what state this node is in.\n this.isUsingUpdatePromise = true;\n } else {\n // Validate the returned value.\n this.validateUpdateResult(updateResult);\n\n // Set the state of this node, this may be undefined, which just means that the node is still in the 'RUNNING' state.\n this.setState(updateResult || State.RUNNING);\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => this.actionName;\n\n /**\n * Reset the state of the node.\n */\n reset = () => {\n // Reset the state of this node.\n this.setState(State.READY);\n\n // There is no longer an update promise that we care about.\n this.isUsingUpdatePromise = false;\n this.updatePromiseStateResult = null;\n };\n\n /**\n * Validate the result of an update function call.\n * @param result The result of an update function call.\n */\n private validateUpdateResult = (result: CompleteState | boolean) => {\n switch (result) {\n case State.SUCCEEDED:\n case State.FAILED:\n case undefined:\n return;\n default:\n throw new Error(\n `action '${this.actionName}' 'onUpdate' returned an invalid response, expected an optional State.SUCCEEDED or State.FAILED value to be returned`\n );\n }\n };\n}\n", "import Leaf from \"./Leaf\";\nimport State from \"../../State\";\nimport Lookup from \"../../Lookup\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { AnyArgument } from \"../../RootAstNodesBuilder\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A Condition leaf node.\n * This will succeed or fail immediately based on an agent predicate, without moving to the 'RUNNING' state.\n */\nexport default class Condition extends Leaf {\n /**\n * @param attributes The node attributes.\n * @param conditionName The name of the condition function.\n * @param conditionArguments The array of condition argument definitions.\n */\n constructor(attributes: Attribute[], private conditionName: string, private conditionArguments: AnyArgument[]) {\n super(\"condition\", attributes, conditionArguments);\n }\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // Attempt to get the invoker for the condition function.\n const conditionFuncInvoker = Lookup.getFuncInvoker(agent, this.conditionName);\n\n // The condition function should be defined.\n if (conditionFuncInvoker === null) {\n throw new Error(\n `cannot update condition node as the condition '${this.conditionName}' function is not defined on the agent and has not been registered`\n );\n }\n\n // Call the condition function to determine the state of this node.\n this.setState(!!conditionFuncInvoker(this.conditionArguments) ? State.SUCCEEDED : State.FAILED);\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => this.conditionName;\n}\n", "import Leaf from \"./Leaf\";\nimport State from \"../../State\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { Agent } from \"../../Agent\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A WAIT node.\n * The state of this node will change to SUCCEEDED after a duration of time\n */\nexport default class Wait extends Leaf {\n /**\n * @param attributes The node attributes.\n * @param duration The duration that this node will wait to succeed in milliseconds.\n * @param durationMin The minimum possible duration in milliseconds that this node will wait to succeed.\n * @param durationMax The maximum possible duration in milliseconds that this node will wait to succeed.\n */\n constructor(\n attributes: Attribute[],\n private duration: number | null,\n private durationMin: number | null,\n private durationMax: number | null\n ) {\n super(\"wait\", attributes, []);\n }\n\n /**\n * The time in milliseconds at which this node was first updated.\n */\n private initialUpdateTime: number = 0;\n\n /**\n * The total duration in milliseconds that this node will be waiting for.\n */\n private totalDuration: number | null = null;\n\n /**\n * The duration in milliseconds that this node has been waiting for.\n */\n private waitedDuration: number = 0;\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // If this node is in the READY state then we need to set the initial update time.\n if (this.is(State.READY)) {\n // Set the initial update time.\n this.initialUpdateTime = new Date().getTime();\n\n // Set the initial waited duration.\n this.waitedDuration = 0;\n\n // Are we dealing with an explicit duration or will we be randomly picking a duration between the min and max duration.\n if (this.duration !== null) {\n this.totalDuration = this.duration;\n } else if (this.durationMin !== null && this.durationMax !== null) {\n // We will be picking a random duration between a min and max duration, if the optional 'random' behaviour tree\n // function option is defined then we will be using that, otherwise we will fall back to using Math.random.\n const random = typeof options.random === \"function\" ? options.random : Math.random;\n\n // Pick a random duration between a min and max duration.\n this.totalDuration = Math.floor(\n random() * (this.durationMax - this.durationMin + 1) + this.durationMin\n );\n } else {\n this.totalDuration = null;\n }\n\n // The node is now running until we finish waiting.\n this.setState(State.RUNNING);\n }\n\n // If we have no total duration then this wait node will wait indefinitely until it is aborted.\n if (this.totalDuration === null) {\n return;\n }\n\n // If we have a 'getDeltaTime' function defined as part of our options then we will use it to figure out how long we have waited for.\n if (typeof options.getDeltaTime === \"function\") {\n // Get the delta time.\n const deltaTime = options.getDeltaTime();\n\n // Our delta time must be a valid number and cannot be NaN.\n if (typeof deltaTime !== \"number\" || isNaN(deltaTime)) {\n throw new Error(\"The delta time must be a valid number and not NaN.\");\n }\n\n // Update the amount of time that this node has been waiting for based on the delta time.\n this.waitedDuration += deltaTime * 1000;\n } else {\n // We are not using a delta time, so we will just work out hom much time has passed since the first update.\n this.waitedDuration = new Date().getTime() - this.initialUpdateTime;\n }\n\n // Have we waited long enough?\n if (this.waitedDuration >= this.totalDuration) {\n // We have finished waiting!\n this.setState(State.SUCCEEDED);\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => {\n if (this.duration !== null) {\n return `WAIT ${this.duration}ms`;\n } else if (this.durationMin !== null && this.durationMax !== null) {\n return `WAIT ${this.durationMin}ms-${this.durationMax}ms`;\n } else {\n return \"WAIT\";\n }\n };\n}\n", "import Node from \"../Node\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\n\n/**\n * A decorator node that wraps a single child node.\n */\nexport default abstract class Decorator extends Node {\n /**\n * @param type The node type.\n * @param attributes The node attributes.\n * @param child The child node.\n */\n constructor(type: string, attributes: Attribute[], protected child: Node) {\n super(type, attributes, []);\n }\n\n /**\n * Gets whether this node is a leaf node.\n */\n isLeafNode = () => false;\n\n /**\n * Gets the children of this node.\n */\n getChildren = () => [this.child];\n\n /**\n * Reset the state of the node.\n */\n reset = () => {\n // Reset the state of this node.\n this.setState(State.READY);\n\n // Reset the state of the child node.\n this.child.reset();\n };\n\n /**\n * Abort the running of this node.\n * @param agent The agent.\n */\n abort = (agent: Agent) => {\n // There is nothing to do if this node is not in the running state.\n if (!this.is(State.RUNNING)) {\n return;\n }\n\n // Abort the child node.\n this.child.abort(agent);\n\n // Reset the state of this node.\n this.reset();\n\n this.getAttribute(\"exit\")?.callAgentFunction(agent, false, true);\n };\n}\n", "import Node from \"../Node\";\nimport Decorator from \"./Decorator\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A Root node.\n * The root node will have a single child.\n */\nexport default class Root extends Decorator {\n /**\n * @param attributes The node attributes.\n * @param child The child node.\n */\n constructor(attributes: Attribute[], child: Node) {\n super(\"root\", attributes, child);\n }\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // If the child has never been updated or is running then we will need to update it now.\n if (this.child.getState() === State.READY || this.child.getState() === State.RUNNING) {\n // Update the child of this node.\n this.child.update(agent, options);\n }\n\n // The state of the root node is the state of its child.\n this.setState(this.child.getState());\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => \"ROOT\";\n}\n", "import Node from \"../Node\";\nimport Decorator from \"./Decorator\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A REPEAT node.\n * The node has a single child which can have:\n * -- A number of iterations for which to repeat the child node.\n * -- An infinite repeat loop if neither an iteration count or a condition function is defined.\n * The REPEAT node will stop and have a 'FAILED' state if its child is ever in a 'FAILED' state after an update.\n * The REPEAT node will attempt to move on to the next iteration if its child is ever in a 'SUCCEEDED' state.\n */\nexport default class Repeat extends Decorator {\n /**\n * @param attributes The node attributes.\n * @param iterations The number of iterations to repeat the child node.\n * @param iterationsMin The minimum possible number of iterations to repeat the child node.\n * @param iterationsMax The maximum possible number of iterations to repeat the child node.\n * @param child The child node.\n */\n constructor(\n attributes: Attribute[],\n private iterations: number | null,\n private iterationsMin: number | null,\n private iterationsMax: number | null,\n child: Node\n ) {\n super(\"repeat\", attributes, child);\n }\n\n /**\n * The number of target iterations to make.\n */\n private targetIterationCount: number | null = null;\n\n /**\n * The current iteration count.\n */\n private currentIterationCount: number = 0;\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // If this node is in the READY state then we need to reset the child and the target iteration count.\n if (this.is(State.READY)) {\n // Reset the child node.\n this.child.reset();\n\n // Reset the current iteration count.\n this.currentIterationCount = 0;\n\n // Set the target iteration count.\n this.setTargetIterationCount(options);\n }\n\n // Do a check to see if we can iterate. If we can then this node will move into the 'RUNNING' state.\n // If we cannot iterate then we have hit our target iteration count, which means that the node has succeeded.\n if (this.canIterate()) {\n // This node is in the running state and can do its initial iteration.\n this.setState(State.RUNNING);\n\n // We may have already completed an iteration, meaning that the child node will be in the SUCCEEDED state.\n // If this is the case then we will have to reset the child node now.\n if (this.child.getState() === State.SUCCEEDED) {\n this.child.reset();\n }\n\n // Update the child of this node.\n this.child.update(agent, options);\n\n // If the child moved into the FAILED state when we updated it then there is nothing left to do and this node has also failed.\n // If it has moved into the SUCCEEDED state then we have completed the current iteration.\n if (this.child.getState() === State.FAILED) {\n // The child has failed, meaning that this node has failed.\n this.setState(State.FAILED);\n\n return;\n } else if (this.child.getState() === State.SUCCEEDED) {\n // We have completed an iteration.\n this.currentIterationCount += 1;\n }\n } else {\n // This node is in the 'SUCCEEDED' state as we cannot iterate any more.\n this.setState(State.SUCCEEDED);\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => {\n if (this.iterations !== null) {\n return `REPEAT ${this.iterations}x`;\n } else if (this.iterationsMin !== null && this.iterationsMax !== null) {\n return `REPEAT ${this.iterationsMin}x-${this.iterationsMax}x`;\n } else {\n return \"REPEAT\";\n }\n };\n\n /**\n * Reset the state of the node.\n */\n reset = () => {\n // Reset the state of this node.\n this.setState(State.READY);\n\n // Reset the current iteration count.\n this.currentIterationCount = 0;\n\n // Reset the child node.\n this.child.reset();\n };\n\n /**\n * Gets whether an iteration can be made.\n * @returns Whether an iteration can be made.\n */\n private canIterate = () => {\n if (this.targetIterationCount !== null) {\n // We can iterate as long as we have not reached our target iteration count.\n return this.currentIterationCount < this.targetIterationCount;\n }\n\n // If neither an iteration count or a condition function were defined then we can iterate indefinitely.\n return true;\n };\n\n /**\n * Sets the target iteration count.\n * @param options The behaviour tree options object.\n */\n private setTargetIterationCount = (options: BehaviourTreeOptions) => {\n // Are we dealing with an explicit iteration count or will we be randomly picking a iteration count between the min and max iteration count.\n if (this.iterations !== null) {\n this.targetIterationCount = this.iterations;\n } else if (this.iterationsMin !== null && this.iterationsMax !== null) {\n // We will be picking a random iteration count between a min and max iteration count, if the optional 'random'\n // behaviour tree function option is defined then we will be using that, otherwise we will fall back to using Math.random.\n const random = typeof options.random === \"function\" ? options.random : Math.random;\n\n // Pick a random iteration count between a min and max iteration count.\n this.targetIterationCount = Math.floor(\n random() * (this.iterationsMax - this.iterationsMin + 1) + this.iterationsMin\n );\n } else {\n this.targetIterationCount = null;\n }\n };\n}\n", "import Node from \"../Node\";\nimport Decorator from \"./Decorator\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A RETRY node.\n * The node has a single child which can have:\n * -- A number of iterations for which to repeat the child node.\n * -- An infinite repeat loop if neither an iteration count or a condition function is defined.\n * The RETRY node will stop and have a 'SUCCEEDED' state if its child is ever in a 'SUCCEEDED' state after an update.\n * The RETRY node will attempt to move on to the next iteration if its child is ever in a 'FAILED' state.\n */\nexport default class Retry extends Decorator {\n /**\n * @param attributes The node attributes.\n * @param attempts The number of attempts to retry the child node.\n * @param attemptsMin The minimum possible number of attempts to retry the child node.\n * @param attemptsMax The maximum possible number of attempts to retry the child node.\n * @param child The child node.\n */\n constructor(\n attributes: Attribute[],\n private attempts: number | null,\n private attemptsMin: number | null,\n private attemptsMax: number | null,\n child: Node\n ) {\n super(\"retry\", attributes, child);\n }\n\n /**\n * The number of target attempts to make.\n */\n private targetAttemptCount: number | null = null;\n\n /**\n * The current attempt count.\n */\n private currentAttemptCount: number = 0;\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // If this node is in the READY state then we need to reset the child and the target attempt count.\n if (this.is(State.READY)) {\n // Reset the child node.\n this.child.reset();\n\n // Reset the current attempt count.\n this.currentAttemptCount = 0;\n\n // Set the target attempt count.\n this.setTargetAttemptCount(options);\n }\n\n // Do a check to see if we can attempt. If we can then this node will move into the 'RUNNING' state.\n // If we cannot attempt then we have hit our target attempt count, which means that the node has succeeded.\n if (this.canAttempt()) {\n // This node is in the running state and can do its initial attempt.\n this.setState(State.RUNNING);\n\n // We may have already completed an attempt, meaning that the child node will be in the FAILED state.\n // If this is the case then we will have to reset the child node now.\n if (this.child.getState() === State.FAILED) {\n this.child.reset();\n }\n\n // Update the child of this node.\n this.child.update(agent, options);\n\n // If the child moved into the SUCCEEDED state when we updated it then there is nothing left to do and this node has also succeeded.\n // If it has moved into the FAILED state then we have completed the current attempt.\n if (this.child.getState() === State.SUCCEEDED) {\n // The child has succeeded, meaning that this node has succeeded.\n this.setState(State.SUCCEEDED);\n\n return;\n } else if (this.child.getState() === State.FAILED) {\n // We have completed an attempt.\n this.currentAttemptCount += 1;\n }\n } else {\n // This node is in the 'FAILED' state as we cannot iterate any more.\n this.setState(State.FAILED);\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => {\n if (this.attempts !== null) {\n return `RETRY ${this.attempts}x`;\n } else if (this.attemptsMin !== null && this.attemptsMax !== null) {\n return `RETRY ${this.attemptsMin}x-${this.attemptsMax}x`;\n } else {\n return \"RETRY\";\n }\n };\n\n /**\n * Reset the state of the node.\n */\n reset = () => {\n // Reset the state of this node.\n this.setState(State.READY);\n\n // Reset the current attempt count.\n this.currentAttemptCount = 0;\n\n // Reset the child node.\n this.child.reset();\n };\n\n /**\n * Gets whether an attempt can be made.\n * @returns Whether an attempt can be made.\n */\n canAttempt = () => {\n if (this.targetAttemptCount !== null) {\n // We can attempt as long as we have not reached our target attempt count.\n return this.currentAttemptCount < this.targetAttemptCount;\n }\n\n // If neither an attempt count or a condition function were defined then we can attempt indefinitely.\n return true;\n };\n\n /**\n * Sets the target attempt count.\n * @param options The behaviour tree options object.\n */\n setTargetAttemptCount = (options: BehaviourTreeOptions) => {\n // Are we dealing with an explicit attempt count or will we be randomly picking an attempt count between the min and max attempt count.\n if (this.attempts !== null) {\n this.targetAttemptCount = this.attempts;\n } else if (this.attemptsMin !== null && this.attemptsMax !== null) {\n // We will be picking a random attempt count between a min and max attempt count, if the optional 'random'\n // behaviour tree function option is defined then we will be using that, otherwise we will fall back to using Math.random.\n const random = typeof options.random === \"function\" ? options.random : Math.random;\n\n // Pick a random attempt count between a min and max attempt count.\n this.targetAttemptCount = Math.floor(\n random() * (this.attemptsMax - this.attemptsMin + 1) + this.attemptsMin\n );\n } else {\n this.targetAttemptCount = null;\n }\n };\n}\n", "import Decorator from \"./Decorator\";\nimport State from \"../../State\";\nimport Node from \"../Node\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A Flip node.\n * This node wraps a single child and will flip the state of the child state.\n */\nexport default class Flip extends Decorator {\n /**\n * @param attributes The node attributes.\n * @param child The child node.\n */\n constructor(attributes: Attribute[], child: Node) {\n super(\"flip\", attributes, child);\n }\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // If the child has never been updated or is running then we will need to update it now.\n if (this.child.getState() === State.READY || this.child.getState() === State.RUNNING) {\n this.child.update(agent, options);\n }\n\n // The state of this node will depend in the state of its child.\n switch (this.child.getState()) {\n case State.RUNNING:\n this.setState(State.RUNNING);\n break;\n\n case State.SUCCEEDED:\n this.setState(State.FAILED);\n break;\n\n case State.FAILED:\n this.setState(State.SUCCEEDED);\n break;\n\n default:\n this.setState(State.READY);\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => \"FLIP\";\n}\n", "import Node from \"../Node\";\nimport Decorator from \"./Decorator\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A Succeed node.\n * This node wraps a single child and will always move to the 'SUCCEEDED' state when the child moves to a 'SUCCEEDED' or 'FAILED' state.\n */\nexport default class Succeed extends Decorator {\n /**\n * @param attributes The node attributes.\n * @param child The child node.\n */\n constructor(attributes: Attribute[], child: Node) {\n super(\"succeed\", attributes, child);\n }\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // If the child has never been updated or is running then we will need to update it now.\n if (this.child.getState() === State.READY || this.child.getState() === State.RUNNING) {\n this.child.update(agent, options);\n }\n\n // The state of this node will depend in the state of its child.\n switch (this.child.getState()) {\n case State.RUNNING:\n this.setState(State.RUNNING);\n break;\n\n case State.SUCCEEDED:\n case State.FAILED:\n this.setState(State.SUCCEEDED);\n break;\n\n default:\n this.setState(State.READY);\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => \"SUCCEED\";\n}\n", "import Node from \"../Node\";\nimport Decorator from \"./Decorator\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A Fail node.\n * This node wraps a single child and will always move to the 'FAILED' state when the child moves to a 'SUCCEEDED' or 'FAILED' state.\n */\nexport default class Fail extends Decorator {\n /**\n * @param attributes The node attributes.\n * @param child The child node.\n */\n constructor(attributes: Attribute[], child: Node) {\n super(\"fail\", attributes, child);\n }\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // If the child has never been updated or is running then we will need to update it now.\n if (this.child.getState() === State.READY || this.child.getState() === State.RUNNING) {\n this.child.update(agent, options);\n }\n\n // The state of this node will depend in the state of its child.\n switch (this.child.getState()) {\n case State.RUNNING:\n this.setState(State.RUNNING);\n break;\n\n case State.SUCCEEDED:\n case State.FAILED:\n this.setState(State.FAILED);\n break;\n\n default:\n this.setState(State.READY);\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => \"FAIL\";\n}\n", "import createLotto from \"lotto-draw\";\n\nimport Node from \"../Node\";\nimport Composite from \"./Composite\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A LOTTO node.\n * A winning child is picked on the initial update of this node, based on ticket weighting.\n * The state of this node will match the state of the winning child.\n */\nexport default class Lotto extends Composite {\n /**\n * @param attributes The node attributes.\n * @param tickets The child node tickets.\n * @param children The child nodes.\n */\n constructor(attributes: Attribute[], private tickets: number[], children: Node[]) {\n super(\"lotto\", attributes, children);\n }\n\n /**\n * The child node selected to be the active one.\n */\n private selectedChild: Node | undefined;\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // If this node is in the READY state then we need to pick a winning child node.\n if (this.is(State.READY)) {\n // Create a lotto draw with which to randomly pick a child node to become the active one.\n const lottoDraw = createLotto({\n // Hook up the optional 'random' behaviour tree function option to the one used by 'lotto-draw'.\n random: options.random,\n // Pass in each child node as a participant in the lotto draw with their respective ticket count.\n participants: this.children.map((child, index) => [child, this.tickets[index] || 1])\n });\n\n // Randomly pick a child based on ticket weighting, this will become the active child for this composite node.\n this.selectedChild = lottoDraw.draw() || undefined;\n }\n\n // If something went wrong and we don't have an active child then we should throw an error.\n if (!this.selectedChild) {\n throw new Error(\"failed to update lotto node as it has no active child\");\n }\n\n // If the selected child has never been updated or is running then we will need to update it now.\n if (this.selectedChild.getState() === State.READY || this.selectedChild.getState() === State.RUNNING) {\n this.selectedChild.update(agent, options);\n }\n\n // The state of the lotto node is the state of its selected child.\n this.setState(this.selectedChild.getState());\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => (this.tickets.length ? `LOTTO [${this.tickets.join(\",\")}]` : \"LOTTO\");\n}\n", "import Node from \"../Node\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\n\n/**\n * A composite node that wraps child nodes.\n */\nexport default abstract class Composite extends Node {\n /**\n * @param type The node type.\n * @param attributes The node attributes.\n * @param children The child nodes.\n */\n constructor(type: string, attributes: Attribute[], protected children: Node[]) {\n super(type, attributes, []);\n }\n\n /**\n * Gets whether this node is a leaf node.\n */\n isLeafNode = () => false;\n\n /**\n * Gets the children of this node.\n */\n getChildren = () => this.children;\n\n /**\n * Reset the state of the node.\n */\n reset = () => {\n // Reset the state of this node.\n this.setState(State.READY);\n\n // Reset the state of any child nodes.\n this.getChildren().forEach((child) => child.reset());\n };\n\n /**\n * Abort the running of this node.\n * @param agent The agent.\n */\n abort = (agent: Agent) => {\n // There is nothing to do if this node is not in the running state.\n if (!this.is(State.RUNNING)) {\n return;\n }\n\n // Abort any child nodes.\n this.getChildren().forEach((child) => child.abort(agent));\n\n // Reset the state of this node.\n this.reset();\n\n this.getAttribute(\"exit\")?.callAgentFunction(agent, false, true);\n };\n}\n", "import Composite from \"./Composite\";\nimport Node from \"../Node\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A SELECTOR node.\n * The child nodes are executed in sequence until one succeeds or all fail.\n */\nexport default class Selector extends Composite {\n /**\n * @param attributes The node attributes.\n * @param children The child nodes.\n */\n constructor(attributes: Attribute[], protected children: Node[]) {\n super(\"selector\", attributes, children);\n }\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // Iterate over all of the children of this node.\n for (const child of this.children) {\n // If the child has never been updated or is running then we will need to update it now.\n if (child.getState() === State.READY || child.getState() === State.RUNNING) {\n // Update the child of this node.\n child.update(agent, options);\n }\n\n // If the current child has a state of 'SUCCEEDED' then this node is also a 'SUCCEEDED' node.\n if (child.getState() === State.SUCCEEDED) {\n // This node is a 'SUCCEEDED' node.\n this.setState(State.SUCCEEDED);\n\n // There is no need to check the rest of the selector nodes.\n return;\n }\n\n // If the current child has a state of 'FAILED' then we should move on to the next child.\n if (child.getState() === State.FAILED) {\n // Find out if the current child is the last one in the selector.\n // If it is then this sequence node has also failed.\n if (this.children.indexOf(child) === this.children.length - 1) {\n // This node is a 'FAILED' node.\n this.setState(State.FAILED);\n\n // There is no need to check the rest of the selector as we have completed it.\n return;\n } else {\n // The child node failed, try the next one.\n continue;\n }\n }\n\n // The node should be in the 'RUNNING' state.\n if (child.getState() === State.RUNNING) {\n // This node is a 'RUNNING' node.\n this.setState(State.RUNNING);\n\n // There is no need to check the rest of the selector as the current child is still running.\n return;\n }\n\n // The child node was not in an expected state.\n throw new Error(\"child node was not in an expected state.\");\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => \"SELECTOR\";\n}\n", "import Composite from \"./Composite\";\nimport Node from \"../Node\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A SEQUENCE node.\n * The child nodes are executed in sequence until one fails or all succeed.\n */\nexport default class Sequence extends Composite {\n /**\n * @param attributes The node attributes.\n * @param children The child nodes.\n */\n constructor(attributes: Attribute[], protected children: Node[]) {\n super(\"sequence\", attributes, children);\n }\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // Iterate over all of the children of this node.\n for (const child of this.children) {\n // If the child has never been updated or is running then we will need to update it now.\n if (child.getState() === State.READY || child.getState() === State.RUNNING) {\n // Update the child of this node.\n child.update(agent, options);\n }\n\n // If the current child has a state of 'SUCCEEDED' then we should move on to the next child.\n if (child.getState() === State.SUCCEEDED) {\n // Find out if the current child is the last one in the sequence.\n // If it is then this sequence node has also succeeded.\n if (this.children.indexOf(child) === this.children.length - 1) {\n // This node is a 'SUCCEEDED' node.\n this.setState(State.SUCCEEDED);\n\n // There is no need to check the rest of the sequence as we have completed it.\n return;\n } else {\n // The child node succeeded, but we have not finished the sequence yet.\n continue;\n }\n }\n\n // If the current child has a state of 'FAILED' then this node is also a 'FAILED' node.\n if (child.getState() === State.FAILED) {\n // This node is a 'FAILED' node.\n this.setState(State.FAILED);\n\n // There is no need to check the rest of the sequence.\n return;\n }\n\n // The node should be in the 'RUNNING' state.\n if (child.getState() === State.RUNNING) {\n // This node is a 'RUNNING' node.\n this.setState(State.RUNNING);\n\n // There is no need to check the rest of the sequence as the current child is still running.\n return;\n }\n\n // The child node was not in an expected state.\n throw new Error(\"child node was not in an expected state.\");\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => \"SEQUENCE\";\n}\n", "import Composite from \"./Composite\";\nimport State from \"../../State\";\nimport Node from \"../Node\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A PARALLEL node.\n * The child nodes are executed concurrently until one fails or all succeed.\n */\nexport default class Parallel extends Composite {\n /**\n * @param attributes The node attributes.\n * @param children The child nodes.\n */\n constructor(attributes: Attribute[], children: Node[]) {\n super(\"parallel\", attributes, children);\n }\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // Keep a count of the number of succeeded child nodes.\n let succeededCount = 0;\n\n let hasChildFailed = false;\n\n // Iterate over all of the children of this node.\n for (const child of this.children) {\n // If the child has never been updated or is running then we will need to update it now.\n if (child.getState() === State.READY || child.getState() === State.RUNNING) {\n // Update the child of this node.\n child.update(agent, options);\n }\n\n // If the current child has a state of 'SUCCEEDED' then we should move on to the next child.\n if (child.getState() === State.SUCCEEDED) {\n // The child node has succeeded, keep track of this to determine if all children have.\n succeededCount++;\n\n // The child node succeeded, but we have not finished checking every child node yet.\n continue;\n }\n\n // If the current child has a state of 'FAILED' then this node is also a 'FAILED' node.\n if (child.getState() === State.FAILED) {\n hasChildFailed = true;\n\n // There is no need to check the rest of the children.\n break;\n }\n\n // The node should be in the 'RUNNING' state.\n if (child.getState() !== State.RUNNING) {\n // The child node was not in an expected state.\n throw new Error(\"child node was not in an expected state.\");\n }\n }\n\n if (hasChildFailed) {\n // This node is a 'FAILED' node.\n this.setState(State.FAILED);\n\n // Abort every running child.\n for (const child of this.children) {\n if (child.getState() === State.RUNNING) {\n child.abort(agent);\n }\n }\n } else {\n // If all children have succeeded then this node has also succeeded, otherwise it is still running.\n this.setState(succeededCount === this.children.length ? State.SUCCEEDED : State.RUNNING);\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => \"PARALLEL\";\n}\n", "import { AnyArgument } from \"../RootAstNodesBuilder\";\nimport Guard from \"./guards/Guard\";\n\nexport type AttributeDetails = {\n /** The attribute type. */\n type: string;\n\n /** The attribute arguments. */\n args: AnyArgument[];\n};\n\n/**\n * A base node attribute.\n */\nexport default abstract class Attribute {\n /**\n * @param type The node attribute type.\n * @param args The array of attribute argument definitions.\n */\n constructor(protected type: string, protected args: AnyArgument[]) {}\n\n /**\n * Gets the type of the attribute.\n */\n getType = () => this.type;\n\n /**\n * Gets the array of attribute argument definitions.\n */\n getArguments = () => this.args;\n\n /**\n * Gets the attribute details.\n */\n abstract getDetails(): TAttributeDetails;\n\n /**\n * Gets whether this attribute is a guard.\n */\n abstract isGuard: () => this is Guard;\n}\n", "import { Agent } from \"../../Agent\";\nimport { AnyArgument } from \"../../RootAstNodesBuilder\";\nimport Attribute, { AttributeDetails } from \"../Attribute\";\n\nexport type GuardAttributeDetails = {\n /** The name of the condition function that determines whether the guard is satisfied. */\n condition: string;\n} & AttributeDetails;\n\n/**\n * A base node guard attribute.\n */\nexport default abstract class Guard extends Attribute {\n /**\n * @param type The node attribute type.\n * @param args The array of decorator argument definitions.\n * @param condition The name of the condition function that determines whether the guard is satisfied.\n */\n constructor(type: string, args: AnyArgument[], private condition: string) {\n super(type, args);\n }\n\n /**\n * Gets the name of the condition function that determines whether the guard is satisfied.\n */\n getCondition = () => this.condition;\n\n /**\n * Gets whether this attribute is a guard.\n */\n isGuard = () => true;\n\n /**\n * Gets the attribute details.\n */\n getDetails(): GuardAttributeDetails {\n return {\n type: this.getType(),\n args: this.getArguments(),\n condition: this.getCondition()\n };\n }\n\n /**\n * Gets whether the guard is satisfied.\n * @param agent The agent.\n * @returns Whether the guard is satisfied.\n */\n abstract isSatisfied(agent: Agent): boolean;\n}\n", "import Guard from \"./Guard\";\nimport Lookup from \"../../Lookup\";\nimport { Agent } from \"../../Agent\";\nimport { AnyArgument } from \"../../RootAstNodesBuilder\";\n\n/**\n * A WHILE guard which is satisfied as long as the given condition remains true.\n */\nexport default class While extends Guard {\n /**\n * @param condition The name of the condition function that determines whether the guard is satisfied.\n * @param args The array of decorator argument definitions.\n */\n constructor(condition: string, args: AnyArgument[]) {\n super(\"while\", args, condition);\n }\n\n /**\n * Gets whether the guard is satisfied.\n * @param agent The agent.\n * @returns Whether the guard is satisfied.\n */\n isSatisfied = (agent: Agent) => {\n // Attempt to get the invoker for the condition function.\n const conditionFuncInvoker = Lookup.getFuncInvoker(agent, this.getCondition());\n\n // The condition function should be defined.\n if (conditionFuncInvoker === null) {\n throw new Error(\n `cannot evaluate node guard as the condition '${this.getCondition()}' function is not defined on the agent and has not been registered`\n );\n }\n\n // Call the condition function to determine whether this guard is satisfied.\n return !!conditionFuncInvoker(this.args);\n };\n}\n", "import Guard from \"./Guard\";\nimport Lookup from \"../../Lookup\";\nimport { Agent } from \"../../Agent\";\nimport { AnyArgument } from \"../../RootAstNodesBuilder\";\n\n/**\n * An UNTIL guard which is satisfied as long as the given condition remains false.\n */\nexport default class Until extends Guard {\n /**\n * @param condition The name of the condition function that determines whether the guard is satisfied.\n * @param args The array of decorator argument definitions.\n */\n constructor(condition: string, args: AnyArgument[]) {\n super(\"until\", args, condition);\n }\n\n /**\n * Gets whether the guard is satisfied.\n * @param agent The agent.\n * @returns Whether the guard is satisfied.\n */\n isSatisfied = (agent: Agent) => {\n // Attempt to get the invoker for the condition function.\n const conditionFuncInvoker = Lookup.getFuncInvoker(agent, this.getCondition());\n\n // The condition function should be defined.\n if (conditionFuncInvoker === null) {\n throw new Error(\n `cannot evaluate node guard as the condition '${this.getCondition()}' function is not defined on the agent and has not been registered`\n );\n }\n\n // Call the condition function to determine whether this guard is satisfied.\n return !!!conditionFuncInvoker(this.args);\n };\n}\n", "import { Agent } from \"../../Agent\";\nimport { AnyArgument } from \"../../RootAstNodesBuilder\";\nimport Attribute, { AttributeDetails } from \"../Attribute\";\n\nexport type CallbackAttributeDetails = {\n /** The name of the agent function that is called. */\n functionName: string;\n} & AttributeDetails;\n\n/**\n * A base node callback attribute.\n */\nexport default abstract class Callback extends Attribute {\n /**\n * @param type The node attribute type.\n * @param args The array of decorator argument definitions.\n * @param functionName The name of the agent function to call.\n */\n constructor(type: string, args: AnyArgument[], private functionName: string) {\n super(type, args);\n }\n\n /**\n * Gets the name of the agent function to call.\n */\n getFunctionName = () => this.functionName;\n\n /**\n * Gets whether this attribute is a guard.\n */\n isGuard = () => false;\n\n /**\n * Gets the attribute details.\n */\n getDetails(): CallbackAttributeDetails {\n return {\n type: this.getType(),\n args: this.getArguments(),\n functionName: this.getFunctionName()\n };\n }\n\n /**\n * Attempt to call the agent function that this callback refers to.\n * @param agent The agent.\n */\n abstract callAgentFunction: (agent: Agent, isSuccess: boolean, isAborted: boolean) => void;\n}\n", "import Callback from \"./Callback\";\nimport Lookup from \"../../Lookup\";\nimport { Agent } from \"../../Agent\";\nimport { AnyArgument } from \"../../RootAstNodesBuilder\";\n\n/**\n * An ENTRY callback which defines an agent function to call when the associated node is updated and moves out of running state.\n */\nexport default class Entry extends Callback {\n /**\n * @param functionName The name of the agent function to call.\n * @param args The array of callback argument definitions.\n */\n constructor(functionName: string, args: AnyArgument[]) {\n super(\"entry\", args, functionName);\n }\n\n /**\n * Attempt to call the agent function that this callback refers to.\n * @param agent The agent.\n */\n callAgentFunction = (agent: Agent) => {\n // Attempt to get the invoker for the callback function.\n const callbackFuncInvoker = Lookup.getFuncInvoker(agent, this.getFunctionName());\n\n // The callback function should be defined.\n if (callbackFuncInvoker === null) {\n throw new Error(\n `cannot call entry function '${this.getFunctionName()}' as is not defined on the agent and has not been registered`\n );\n }\n\n // Call the callback function.\n callbackFuncInvoker(this.args);\n };\n}\n", "import Callback from \"./Callback\";\nimport Lookup, { AnyExitArgument } from \"../../Lookup\";\nimport { Agent } from \"../../Agent\";\nimport { AnyArgument } from \"../../RootAstNodesBuilder\";\n\n/**\n * An EXIT callback which defines an agent function to call when the associated node is updated and moves to a finished state or is aborted.\n */\nexport default class Exit extends Callback {\n /**\n * @param functionName The name of the agent function to call.\n * @param args The array of callback argument definitions.\n */\n constructor(functionName: string, args: AnyArgument[]) {\n super(\"exit\", args, functionName);\n }\n\n /**\n * Attempt to call the agent function that this callback refers to.\n * @param agent The agent.\n * @param isSuccess Whether the decorated node was left with a success state.\n * @param isAborted Whether the decorated node was aborted.\n */\n callAgentFunction = (agent: Agent, isSuccess: boolean, isAborted: boolean) => {\n // Attempt to get the invoker for the callback function.\n const callbackFuncInvoker = Lookup.getFuncInvoker(agent, this.getFunctionName());\n\n // The callback function should be defined.\n if (callbackFuncInvoker === null) {\n throw new Error(\n `cannot call exit function '${this.getFunctionName()}' as is not defined on the agent and has not been registered`\n );\n }\n\n // Call the callback function\n callbackFuncInvoker([{ value: { succeeded: isSuccess, aborted: isAborted } }, ...this.args]);\n };\n}\n", "import Callback from \"./Callback\";\nimport Lookup from \"../../Lookup\";\nimport { Agent } from \"../../Agent\";\nimport { AnyArgument } from \"../../RootAstNodesBuilder\";\n\n/**\n * A STEP callback which defines an agent function to call when the associated node is updated.\n */\nexport default class Step extends Callback {\n /**\n * @param functionName The name of the agent function to call.\n * @param args The array of callback argument definitions.\n */\n constructor(functionName: string, args: AnyArgument[]) {\n super(\"step\", args, functionName);\n }\n\n /**\n * Attempt to call the agent function that this callback refers to.\n * @param agent The agent.\n */\n callAgentFunction = (agent: Agent) => {\n // Attempt to get the invoker for the callback function.\n const callbackFuncInvoker = Lookup.getFuncInvoker(agent, this.getFunctionName());\n\n // The callback function should be defined.\n if (callbackFuncInvoker === null) {\n throw new Error(\n `cannot call step function '${this.getFunctionName()}' as is not defined on the agent and has not been registered`\n );\n }\n\n // Call the callback function.\n callbackFuncInvoker(this.args);\n };\n}\n", "import Action from \"./nodes/leaf/Action\";\nimport Condition from \"./nodes/leaf/Condition\";\nimport Wait from \"./nodes/leaf/Wait\";\nimport Root from \"./nodes/decorator/Root\";\nimport Repeat from \"./nodes/decorator/Repeat\";\nimport Retry from \"./nodes/decorator/Retry\";\nimport Flip from \"./nodes/decorator/Flip\";\nimport Succeed from \"./nodes/decorator/Succeed\";\nimport Fail from \"./nodes/decorator/Fail\";\nimport Lotto from \"./nodes/composite/Lotto\";\nimport Selector from \"./nodes/composite/Selector\";\nimport Sequence from \"./nodes/composite/Sequence\";\nimport Parallel from \"./nodes/composite/Parallel\";\nimport Node from \"./nodes/Node\";\nimport While from \"./attributes/guards/While\";\nimport Until from \"./attributes/guards/Until\";\nimport Entry from \"./attributes/callbacks/Entry\";\nimport Exit from \"./attributes/callbacks/Exit\";\nimport Step from \"./attributes/callbacks/Step\";\nimport Callback from \"./attributes/callbacks/Callback\";\nimport Guard from \"./attributes/guards/Guard\";\nimport Attribute from \"./attributes/Attribute\";\nimport Composite from \"./nodes/composite/Composite\";\nimport Decorator from \"./nodes/decorator/Decorator\";\nimport Leaf from \"./nodes/leaf/Leaf\";\n\nexport type Argument = {\n value: T;\n type: string; // Used for validation.\n};\ntype NullArgument = Argument & {\n type: \"null\";\n};\ntype BooleanArgument = Argument & {\n type: \"boolean\";\n};\ntype NumberArgument = Argument & {\n type: \"number\";\n isInteger: boolean; // Used for validation.\n};\ntype StringPlaceholderArgument = Argument & {\n type: \"string\";\n};\ntype IdentifierArgument = Argument & {\n type: \"identifier\";\n};\nexport type AnyArgument =\n | NullArgument\n | BooleanArgument\n | NumberArgument\n | StringPlaceholderArgument\n | IdentifierArgument;\n\n/**\n * The node attribute factories.\n */\nconst AttributeFactories: {\n [key: string]: (functionName: string, attributeArguments: AnyArgument[]) => Callback | Guard;\n} = {\n WHILE: (condition: string, attributeArguments: AnyArgument[]) => new While(condition, attributeArguments),\n UNTIL: (condition: string, attributeArguments: AnyArgument[]) => new Until(condition, attributeArguments),\n ENTRY: (functionName: string, attributeArguments: AnyArgument[]) => new Entry(functionName, attributeArguments),\n EXIT: (functionName: string, attributeArguments: AnyArgument[]) => new Exit(functionName, attributeArguments),\n STEP: (functionName: string, attributeArguments: AnyArgument[]) => new Step(functionName, attributeArguments)\n};\n\ntype Validatable = {\n children?: AstNode[];\n validate: (depth: number) => void;\n};\n\ntype NodeInstanceCreator = (\n namedRootNodeProvider: (name: string) => RootAstNode,\n visitedBranches: string[]\n) => T;\n\nexport type AstNode = Validatable & {\n type: string;\n createNodeInstance: NodeInstanceCreator;\n};\n\nexport type LeafAstNode = AstNode & {\n type: \"action\" | \"condition\" | \"wait\";\n attributes: Attribute[];\n};\n\nexport type CompositeAstNode = AstNode & {\n type: \"lotto\" | \"parallel\" | \"selector\" | \"sequence\";\n attributes: Attribute[];\n children: AstNode[];\n};\n\nexport type DecoratorAstNode = AstNode & {\n type: \"fail\" | \"flip\" | \"repeat\" | \"retry\" | \"root\" | \"succeed\";\n attributes: Attribute[];\n children: AstNode[];\n};\n\nexport type BranchAstNode = AstNode & {\n type: \"branch\";\n branchName: \"\" | string;\n};\n\nexport type LottoAstNode = CompositeAstNode & {\n type: \"lotto\";\n tickets: number[];\n};\n\nexport type RootAstNode = DecoratorAstNode & {\n type: \"root\";\n name: null | string;\n};\n\nexport type RepeatAstNode = DecoratorAstNode & {\n type: \"repeat\";\n iterations: number | null;\n iterationsMin: number | null;\n iterationsMax: number | null;\n};\n\nexport type RetryAstNode = DecoratorAstNode & {\n type: \"retry\";\n attempts: number | null;\n attemptsMin: number | null;\n attemptsMax: number | null;\n};\n\nexport type ActionAstNode = LeafAstNode & {\n type: \"action\";\n actionName: string;\n actionArguments: AnyArgument[];\n};\n\nexport type ConditionAstNode = LeafAstNode & {\n type: \"condition\";\n conditionName: string;\n conditionArguments: AnyArgument[];\n};\n\nexport type WaitAstNode = LeafAstNode & {\n type: \"wait\";\n duration: number | null;\n durationMin: number | null;\n durationMax: number | null;\n};\n\nexport type AnyAstNode =\n | BranchAstNode\n | CompositeAstNode\n | LottoAstNode\n | DecoratorAstNode\n | RootAstNode\n | RepeatAstNode\n | RetryAstNode\n | LeafAstNode\n | ActionAstNode\n | ConditionAstNode\n | WaitAstNode;\n\n/**\n * The AST node factories.\n */\nconst ASTNodeFactories = {\n ROOT: (): RootAstNode => ({\n type: \"root\",\n attributes: [],\n name: null,\n children: [],\n validate(depth: number) {\n // A root node cannot be the child of another node.\n if (depth > 1) {\n throw new Error(\"a root node cannot be the child of another node\");\n }\n\n // A root node must have a single child node.\n if (this.children.length !== 1) {\n throw new Error(\"a root node must have a single child\");\n }\n },\n createNodeInstance(namedRootNodeProvider, visitedBranches) {\n return new Root(\n this.attributes,\n this.children![0].createNodeInstance(namedRootNodeProvider, visitedBranches.slice())\n );\n }\n }),\n BRANCH: (): BranchAstNode => ({\n type: \"branch\",\n branchName: \"\",\n validate() {},\n createNodeInstance(namedRootNodeProvider, visitedBranches) {\n // Try to find the root node with a matching branch name.\n const targetRootNode = namedRootNodeProvider(this.branchName);\n\n // If we have already visited this branch then we have a circular dependency.\n if (visitedBranches.indexOf(this.branchName) !== -1) {\n throw new Error(`circular dependency found in branch node references for branch '${this.branchName}'`);\n }\n\n // If we have a target root node, then the node instance we want will be the first and only child of the referenced root node.\n if (targetRootNode) {\n return targetRootNode\n .createNodeInstance(namedRootNodeProvider, visitedBranches.concat(this.branchName))\n .getChildren()[0];\n } else {\n throw new Error(`branch references root node '${this.branchName}' which has not been defined`);\n }\n }\n }),\n SELECTOR: (): CompositeAstNode => ({\n type: \"selector\",\n attributes: [],\n children: [],\n validate() {\n // A selector node must have at least a single node.\n if (this.children.length < 1) {\n throw new Error(\"a selector node must have at least a single child\");\n }\n },\n createNodeInstance(namedRootNodeProvider, visitedBranches) {\n return new Selector(\n this.attributes,\n this.children.map((child) => child.createNodeInstance(namedRootNodeProvider, visitedBranches.slice()))\n );\n }\n }),\n SEQUENCE: (): CompositeAstNode => ({\n type: \"sequence\",\n attributes: [],\n children: [],\n validate() {\n // A sequence node must have at least a single node.\n if (this.children.length < 1) {\n throw new Error(\"a sequence node must have at least a single child\");\n }\n },\n createNodeInstance(namedRootNodeProvider, visitedBranches) {\n return new Sequence(\n this.attributes,\n this.children.map((child) => child.createNodeInstance(namedRootNodeProvider, visitedBranches.slice()))\n );\n }\n }),\n PARALLEL: (): CompositeAstNode => ({\n type: \"parallel\",\n attributes: [],\n children: [],\n validate() {\n // A parallel node must have at least a single node.\n if (this.children.length < 1) {\n throw new Error(\"a parallel node must have at least a single child\");\n }\n },\n createNodeInstance(namedRootNodeProvider, visitedBranches) {\n return new Parallel(\n this.attributes,\n this.children.map((child) => child.createNodeInstance(namedRootNodeProvider, visitedBranches.slice()))\n );\n }\n }),\n LOTTO: (): LottoAstNode => ({\n type: \"lotto\",\n attributes: [],\n children: [],\n tickets: [],\n validate() {\n // A lotto node must have at least a single node.\n if (this.children!.length < 1) {\n throw new Error(\"a lotto node must have at least a single child\");\n }\n },\n createNodeInstance(namedRootNodeProvider, visitedBranches) {\n return new Lotto(\n this.attributes,\n this.tickets!,\n this.children!.map((child) => child.createNodeInstance(namedRootNodeProvider, visitedBranches.slice()))\n );\n }\n }),\n REPEAT: (): RepeatAstNode => ({\n type: \"repeat\",\n attributes: [],\n iterations: null,\n iterationsMin: null,\n iterationsMax: null,\n children: [],\n validate() {\n // A repeat node must have a single node.\n if (this.children!.length !== 1) {\n throw new Error(\"a repeat node must have a single child\");\n }\n\n if (this.iterations !== null) {\n // A repeat node must have a positive number of iterations if defined.\n if (this.iterations < 0) {\n throw new Error(\"a repeat node must have a positive number of iterations if defined\");\n }\n } else if (this.iterationsMin !== null && this.iterationsMax !== null) {\n // A repeat node must have a positive min and max iteration count if they are defined.\n if (this.iterationsMin < 0 || this.iterationsMax < 0) {\n throw new Error(\n \"a repeat node must have a positive minimum and maximum iteration count if defined\"\n );\n }\n\n // A repeat node must not have an minimum iteration count that exceeds the maximum iteration count.\n if (this.iterationsMin > this.iterationsMax) {\n throw new Error(\n \"a repeat node must not have a minimum iteration count that exceeds the maximum iteration count\"\n );\n }\n } else {\n // If we have no explicit iteration count or a minimum and maximum iteration count set then we are dealing with a repeat node that iterates indefinitely.\n }\n },\n createNodeInstance(namedRootNodeProvider, visitedBranches) {\n return new Repeat(\n this.attributes,\n this.iterations,\n this.iterationsMin,\n this.iterationsMax,\n this.children![0].createNodeInstance(namedRootNodeProvider, visitedBranches.slice())\n );\n }\n }),\n RETRY: (): RetryAstNode => ({\n type: \"retry\",\n attributes: [],\n attempts: null,\n attemptsMin: null,\n attemptsMax: null,\n children: [],\n validate() {\n // A retry node must have a single node.\n if (this.children!.length !== 1) {\n throw new Error(\"a retry node must have a single child\");\n }\n\n if (this.attempts !== null) {\n // A retry node must have a positive number of attempts if defined.\n if (this.attempts < 0) {\n throw new Error(\"a retry node must have a positive number of attempts if defined\");\n }\n } else if (this.attemptsMin !== null && this.attemptsMax !== null) {\n // A retry node must have a positive min and max attempts count if they are defined.\n if (this.attemptsMin < 0 || this.attemptsMax < 0) {\n throw new Error(\"a retry node must have a positive minimum and maximum attempt count if defined\");\n }\n\n // A retry node must not have a minimum attempt count that exceeds the maximum attempt count.\n if (this.attemptsMin > this.attemptsMax) {\n throw new Error(\n \"a retry node must not have a minimum attempt count that exceeds the maximum attempt count\"\n );\n }\n } else {\n // If we have no explicit attempt count or a minimum and maximum attempt count set then we are dealing with a retry node that attempts indefinitely.\n }\n },\n createNodeInstance(namedRootNodeProvider, visitedBranches) {\n return new Retry(\n this.attributes,\n this.attempts,\n this.attemptsMin,\n this.attemptsMax,\n this.children![0].createNodeInstance(namedRootNodeProvider, visitedBranches.slice())\n );\n }\n }),\n FLIP: (): DecoratorAstNode => ({\n type: \"flip\",\n attributes: [],\n children: [],\n validate() {\n // A flip node must have a single node.\n if (this.children!.length !== 1) {\n throw new Error(\"a flip node must have a single child\");\n }\n },\n createNodeInstance(namedRootNodeProvider, visitedBranches) {\n return new Flip(\n this.attributes,\n this.children![0].createNodeInstance(namedRootNodeProvider, visitedBranches.slice())\n );\n }\n }),\n SUCCEED: (): DecoratorAstNode => ({\n type: \"succeed\",\n attributes: [],\n children: [],\n validate() {\n // A succeed node must have a single node.\n if (this.children!.length !== 1) {\n throw new Error(\"a succeed node must have a single child\");\n }\n },\n createNodeInstance(namedRootNodeProvider, visitedBranches) {\n return new Succeed(\n this.attributes,\n this.children![0].createNodeInstance(namedRootNodeProvider, visitedBranches.slice())\n );\n }\n }),\n FAIL: (): DecoratorAstNode => ({\n type: \"fail\",\n attributes: [],\n children: [],\n validate() {\n // A fail node must have a single node.\n if (this.children!.length !== 1) {\n throw new Error(\"a fail node must have a single child\");\n }\n },\n createNodeInstance(namedRootNodeProvider, visitedBranches) {\n return new Fail(\n this.attributes,\n this.children![0].createNodeInstance(namedRootNodeProvider, visitedBranches.slice())\n );\n }\n }),\n WAIT: (): WaitAstNode => ({\n type: \"wait\",\n attributes: [],\n duration: null,\n durationMin: null,\n durationMax: null,\n validate() {\n if (this.duration !== null) {\n // If an explict duration was defined then it must be a positive number.\n if (this.duration < 0) {\n throw new Error(\"a wait node must have a positive duration\");\n }\n } else if (this.durationMin !== null && this.durationMax !== null) {\n // A wait node must have a positive min and max duration.\n if (this.durationMin < 0 || this.durationMax < 0) {\n throw new Error(\"a wait node must have a positive minimum and maximum duration\");\n }\n\n // A wait node must not have a minimum duration that exceeds the maximum duration.\n if (this.durationMin > this.durationMax) {\n throw new Error(\"a wait node must not have a minimum duration that exceeds the maximum duration\");\n }\n } else {\n // If we have no explicit duration or duration bounds set then we are dealing with a wait node that waits indefinitely.\n }\n },\n createNodeInstance() {\n return new Wait(this.attributes, this.duration, this.durationMin, this.durationMax);\n }\n }),\n ACTION: (): ActionAstNode => ({\n type: \"action\",\n attributes: [],\n actionName: \"\",\n actionArguments: [],\n validate() {},\n createNodeInstance() {\n return new Action(this.attributes, this.actionName!, this.actionArguments!);\n }\n }),\n CONDITION: (): ConditionAstNode => ({\n type: \"condition\",\n attributes: [],\n conditionName: \"\",\n conditionArguments: [],\n validate() {},\n createNodeInstance() {\n return new Condition(this.attributes, this.conditionName!, this.conditionArguments!);\n }\n })\n};\n\ntype OtherAstNodes = AstNode[];\n\n/**\n * Create an array of root AST nodes based on the given definition.\n * @param definition The definition to parse the AST nodes from.\n * @returns The base definition AST nodes.\n */\nexport default function buildRootASTNodes(definition: string): RootAstNode[] {\n // Swap out any node/attribute argument string literals with a placeholder and get a mapping of placeholders to original values as well as the processed definition.\n const { placeholders, processedDefinition } = substituteStringLiterals(definition);\n\n // Convert the processed definition (with substituted string literals) into an array of raw tokens.\n const tokens = parseTokensFromDefinition(processedDefinition);\n\n // There must be at least 3 tokens for the tree definition to be valid. 'ROOT', '{' and '}'.\n if (tokens.length < 3) {\n throw new Error(\"invalid token count\");\n }\n\n // We should have a matching number of '{' and '}' tokens. If not, then there are scopes that have not been properly closed.\n if (tokens.filter((token) => token === \"{\").length !== tokens.filter((token) => token === \"}\").length) {\n throw new Error(\"scope character mismatch\");\n }\n\n // Create a stack of node children arrays, starting with a definition scope.\n const stack: [RootAstNode[], ...OtherAstNodes[]] = [[]];\n const rootScope = stack[0];\n\n // We should keep processing the raw tokens until we run out of them.\n while (tokens.length) {\n // Grab the next token.\n const token = tokens.shift();\n\n const currentScope = stack[stack.length - 1] as OtherAstNodes;\n\n // How we create the next AST token depends on the current raw token value.\n switch (token!.toUpperCase()) {\n case \"ROOT\": {\n // Create a ROOT AST node.\n const node = ASTNodeFactories.ROOT();\n\n // Push the ROOT node into the current scope.\n rootScope.push(node);\n\n // We may have a root node name defined as an argument.\n if (tokens[0] === \"[\") {\n const rootArguments = getArguments(tokens, placeholders);\n\n // We should have only a single argument that is not an empty string for a root node, which is the root name identifier.\n if (rootArguments.length === 1 && rootArguments[0].type === \"identifier\") {\n // The root name will be the first and only node argument.\n node.name = rootArguments[0].value as string;\n } else {\n throw new Error(\"expected single root name argument\");\n }\n }\n\n // Try to pick any attributes off of the token stack.\n node.attributes = getAttributes(tokens, placeholders);\n\n popAndCheck(tokens, \"{\");\n\n // The new scope is that of the new ROOT nodes children.\n stack.push(node.children!);\n break;\n }\n\n case \"BRANCH\": {\n // Create a BRANCH AST node.\n const node = ASTNodeFactories.BRANCH();\n\n // Push the BRANCH node into the current scope.\n currentScope.push(node);\n\n // We must have arguments defined, as we require a branch name argument.\n if (tokens[0] !== \"[\") {\n throw new Error(\"expected single branch name argument\");\n }\n\n // The branch name will be defined as a node argument.\n const branchArguments = getArguments(tokens, placeholders);\n\n // We should have only a single identifer argument for a branch node, which is the branch name.\n if (branchArguments.length === 1 && branchArguments[0].type === \"identifier\") {\n // The branch name will be the first and only node argument.\n node.branchName = branchArguments[0].value as string;\n } else {\n throw new Error(\"expected single branch name argument\");\n }\n break;\n }\n\n case \"SELECTOR\": {\n // Create a SELECTOR AST node.\n const node = ASTNodeFactories.SELECTOR();\n\n // Push the SELECTOR node into the current scope.\n currentScope.push(node);\n\n // Try to pick any attributes off of the token stack.\n node.attributes = getAttributes(tokens, placeholders);\n\n popAndCheck(tokens, \"{\");\n\n // The new scope is that of the new SELECTOR nodes children.\n stack.push(node.children!);\n break;\n }\n\n case \"SEQUENCE\": {\n // Create a SEQUENCE AST node.\n const node = ASTNodeFactories.SEQUENCE();\n\n // Push the SEQUENCE node into the current scope.\n currentScope.push(node);\n\n // Try to pick any attributes off of the token stack.\n node.attributes = getAttributes(tokens, placeholders);\n\n popAndCheck(tokens, \"{\");\n\n // The new scope is that of the new SEQUENCE nodes children.\n stack.push(node.children!);\n break;\n }\n\n case \"PARALLEL\": {\n // Create a PARALLEL AST node.\n const node = ASTNodeFactories.PARALLEL();\n\n // Push the PARALLEL node into the current scope.\n currentScope.push(node);\n\n // Try to pick any attributes off of the token stack.\n node.attributes = getAttributes(tokens, placeholders);\n\n popAndCheck(tokens, \"{\");\n\n // The new scope is that of the new PARALLEL nodes children.\n stack.push(node.children!);\n break;\n }\n\n case \"LOTTO\": {\n // Create a LOTTO AST node.\n const node = ASTNodeFactories.LOTTO();\n\n // Push the LOTTO node into the current scope.\n currentScope.push(node);\n\n // If the next token is a '[' character then some ticket counts have been defined as arguments.\n if (tokens[0] === \"[\") {\n // Get the ticket count arguments, each argument must be a number.\n node.tickets = getArguments(\n tokens,\n placeholders,\n (arg) => arg.type === \"number\" && !!arg.isInteger,\n \"lotto node ticket counts must be integer values\"\n ).map((argument) => argument.value as number);\n }\n\n // Try to pick any attributes off of the token stack.\n node.attributes = getAttributes(tokens, placeholders);\n\n popAndCheck(tokens, \"{\");\n\n // The new scope is that of the new LOTTO nodes children.\n stack.push(node.children!);\n break;\n }\n\n case \"CONDITION\": {\n // Create a CONDITION AST node.\n const node = ASTNodeFactories.CONDITION();\n\n // Push the CONDITION node into the current scope.\n currentScope.push(node);\n\n // We must have arguments defined, as we require a condition function name argument.\n if (tokens[0] !== \"[\") {\n throw new Error(\"expected condition name identifier argument\");\n }\n\n // Grab the condition node arguments.\n const conditionArguments = getArguments(tokens, placeholders);\n\n // We should have at least a single identifier argument for a condition node, which is the condition function name.\n if (conditionArguments.length && conditionArguments[0].type === \"identifier\") {\n // The condition function name will be the first node argument.\n node.conditionName = conditionArguments.shift()!.value as string;\n } else {\n throw new Error(\"expected condition name identifier argument\");\n }\n\n // Only the first argument should have been an identifier, all following arguments must be string, number, boolean or null.\n conditionArguments\n .filter((arg) => arg.type === \"identifier\")\n .forEach((arg) => {\n throw new Error(\n \"invalid condition node argument value '\" +\n arg.value +\n \"', must be string, number, boolean or null\"\n );\n });\n\n // Any node arguments that follow the condition name identifier will be treated as condition function arguments.\n node.conditionArguments = conditionArguments;\n\n // Try to pick any attributes off of the token stack.\n node.attributes = getAttributes(tokens, placeholders);\n break;\n }\n\n case \"FLIP\": {\n // Create a FLIP AST node.\n const node = ASTNodeFactories.FLIP();\n\n // Push the Flip node into the current scope.\n currentScope.push(node);\n\n // Try to pick any attributes off of the token stack.\n node.attributes = getAttributes(tokens, placeholders);\n\n popAndCheck(tokens, \"{\");\n\n // The new scope is that of the new FLIP nodes children.\n stack.push(node.children!);\n break;\n }\n\n case \"SUCCEED\": {\n // Create a SUCCEED AST node.\n const node = ASTNodeFactories.SUCCEED();\n\n // Push the Succeed node into the current scope.\n currentScope.push(node);\n\n // Try to pick any attributes off of the token stack.\n node.attributes = getAttributes(tokens, placeholders);\n\n popAndCheck(tokens, \"{\");\n\n // The new scope is that of the new Succeed nodes children.\n stack.push(node.children!);\n break;\n }\n\n case \"FAIL\": {\n // Create a FAIL AST node.\n const node = ASTNodeFactories.FAIL();\n\n // Push the Fail node into the current scope.\n currentScope.push(node);\n\n // Try to pick any attributes off of the token stack.\n node.attributes = getAttributes(tokens, placeholders);\n\n popAndCheck(tokens, \"{\");\n\n // The new scope is that of the new Fail nodes children.\n stack.push(node.children!);\n break;\n }\n\n case \"WAIT\": {\n // Create a WAIT AST node.\n const node = ASTNodeFactories.WAIT();\n\n // Push the WAIT node into the current scope.\n currentScope.push(node);\n\n // The arguments of a wait node are optional. We may have:\n // - No node arguments, in which case the wait will be indefinite until it is aborted.\n // - One node argument which will be the explicit duration of the wait.\n // - Two node arguments which define the min and max duration bounds from which a random duration will be picked.\n if (tokens[0] === \"[\") {\n // Get the optional duration and longest duration of the wait.\n const nodeArguments = getArguments(\n tokens,\n placeholders,\n (arg) => arg.type === \"number\" && !!arg.isInteger,\n \"wait node durations must be integer values\"\n ).map((argument) => argument.value);\n\n // We may have:\n // - One node argument which will be the explicit duration of the wait.\n // - Two node arguments which define the min and max duration bounds from which a random duration will be picked.\n // - Too many arguments, which is not valid.\n if (nodeArguments.length === 1) {\n // An explicit duration was defined.\n node.duration = nodeArguments[0] as number;\n } else if (nodeArguments.length === 2) {\n // Min and max duration bounds were defined from which a random duration will be picked.\n node.durationMin = nodeArguments[0] as number;\n node.durationMax = nodeArguments[1] as number;\n } else if (nodeArguments.length > 2) {\n // An incorrect number of durations was defined.\n throw new Error(\"invalid number of wait node duration arguments defined\");\n }\n }\n\n // Try to pick any attributes off of the token stack.\n node.attributes = getAttributes(tokens, placeholders);\n break;\n }\n\n case \"REPEAT\": {\n // Create a REPEAT AST node.\n const node = ASTNodeFactories.REPEAT();\n\n // Push the REPEAT node into the current scope.\n currentScope.push(node);\n\n // The arguments of a repeat node are optional. We may have:\n // - No node arguments, in which case the repeat note will iterate indefinitely.\n // - One node argument which will be the explicit number of iterations to make.\n // - Two node arguments which define the min and max iteration bounds from which a random iteration count will be picked.\n if (tokens[0] === \"[\") {\n // An iteration count has been defined. Get the iteration and potential maximum iteration of the wait.\n const nodeArguments = getArguments(\n tokens,\n placeholders,\n (arg) => arg.type === \"number\" && !!arg.isInteger,\n \"repeat node iteration counts must be integer values\"\n ).map((argument) => argument.value);\n\n // We should have got one or two iteration counts.\n if (nodeArguments.length === 1) {\n // A static iteration count was defined.\n node.iterations = nodeArguments[0] as number;\n } else if (nodeArguments.length === 2) {\n // A minimum and maximum iteration count was defined.\n node.iterationsMin = nodeArguments[0] as number;\n node.iterationsMax = nodeArguments[1] as number;\n } else {\n // An incorrect number of iteration counts was defined.\n throw new Error(\"invalid number of repeat node iteration count arguments defined\");\n }\n }\n\n // Try to pick any attributes off of the token stack.\n node.attributes = getAttributes(tokens, placeholders);\n\n popAndCheck(tokens, \"{\");\n\n // The new scope is that of the new REPEAT nodes children.\n stack.push(node.children!);\n break;\n }\n\n case \"RETRY\": {\n // Create a RETRY AST node.\n const node = ASTNodeFactories.RETRY();\n\n // Push the RETRY node into the current scope.\n currentScope.push(node);\n\n // The arguments of a retry node are optional. We may have:\n // - No node arguments, in which case the retry note will attempt indefinitely.\n // - One node argument which will be the explicit number of attempts to make.\n // - Two node arguments which define the min and max attempt bounds from which a random attempt count will be picked.\n if (tokens[0] === \"[\") {\n // An attempt count has been defined. Get the attempt count and potential maximum attempt count of the wait.\n const nodeArguments = getArguments(\n tokens,\n placeholders,\n (arg) => arg.type === \"number\" && !!arg.isInteger,\n \"retry node attempt counts must be integer values\"\n ).map((argument) => argument.value);\n\n // We should have got one or two attempt counts.\n if (nodeArguments.length === 1) {\n // A static attempt count was defined.\n node.attempts = nodeArguments[0] as number;\n } else if (nodeArguments.length === 2) {\n // A minimum and maximum attempt count was defined.\n node.attemptsMin = nodeArguments[0] as number;\n node.attemptsMax = nodeArguments[1] as number;\n } else {\n // An incorrect number of attempt counts was defined.\n throw new Error(\"invalid number of retry node attempt count arguments defined\");\n }\n }\n\n // Try to pick any attributes off of the token stack.\n node.attributes = getAttributes(tokens, placeholders);\n\n popAndCheck(tokens, \"{\");\n\n // The new scope is that of the new RETRY nodes children.\n stack.push(node.children!);\n break;\n }\n\n case \"ACTION\": {\n // Create a ACTION AST node.\n const node = ASTNodeFactories.ACTION();\n\n // Push the ACTION node into the current scope.\n currentScope.push(node);\n\n // We must have arguments defined, as we require an action name argument.\n if (tokens[0] !== \"[\") {\n throw new Error(\"expected action name identifier argument\");\n }\n\n // The action name will be defined as a node argument.\n const actionArguments = getArguments(tokens, placeholders);\n\n // We should have at least one identifer argument for an action node, which is the action name.\n if (actionArguments.length && actionArguments[0].type === \"identifier\") {\n // The action name will be the first and only node argument.\n node.actionName = actionArguments.shift()!.value as string;\n } else {\n throw new Error(\"expected action name identifier argument\");\n }\n\n // Only the first argument should have been an identifier, all following arguments must be string, number, boolean or null.\n actionArguments\n .filter((arg) => arg.type === \"identifier\")\n .forEach((arg) => {\n throw new Error(\n \"invalid action node argument value '\" +\n arg.value +\n \"', must be string, number, boolean or null\"\n );\n });\n\n // Any node arguments that follow the action name identifier will be treated as action function arguments.\n node.actionArguments = actionArguments;\n\n // Try to pick any attributes off of the token stack.\n node.attributes = getAttributes(tokens, placeholders);\n break;\n }\n\n case \"}\": {\n // The '}' character closes the current scope.\n stack.pop();\n break;\n }\n\n default: {\n throw new Error(`unexpected token '${token}'`);\n }\n }\n }\n\n // A function to recursively validate each of the nodes in the AST.\n const validateASTNode = (node: Validatable, depth: number): void => {\n // Validate the node.\n node.validate(depth);\n\n // Validate each child of the node.\n (node.children || []).forEach((child) => validateASTNode(child, depth + 1));\n };\n\n // Start node validation from the definition root.\n validateASTNode(\n {\n children: stack[0] as RootAstNode[],\n validate(this: { children: RootAstNode[] }) {\n // We must have at least one node defined as the definition scope, which should be a root node.\n if (this.children.length === 0) {\n throw new Error(\"expected root node to have been defined\");\n }\n\n // Each node at the base of the definition scope MUST be a root node.\n for (const definitionLevelNode of this.children) {\n if (definitionLevelNode.type !== \"root\") {\n throw new Error(\"expected root node at base of definition\");\n }\n }\n\n // Exactly one root node must not have a name defined. This will be the main root, others will have to be referenced via branch nodes.\n if (this.children.filter((definitionLevelNode) => definitionLevelNode.name === null).length !== 1) {\n throw new Error(\"expected single unnamed root node at base of definition to act as main root\");\n }\n\n // No two named root nodes can have matching names.\n const rootNodeNames: string[] = [];\n for (const definitionLevelNode of this.children) {\n if (rootNodeNames.indexOf(definitionLevelNode.name!) !== -1) {\n throw new Error(`multiple root nodes found with duplicate name '${definitionLevelNode.name}'`);\n } else {\n rootNodeNames.push(definitionLevelNode.name!);\n }\n }\n }\n },\n 0\n );\n\n // Return the root AST nodes.\n return stack[0];\n}\n\n/**\n * Pop the next raw token off of the stack and throw an error if it wasn't the expected one.\n * @param tokens The array of remaining tokens.\n * @param expected An optional string or array or items, one of which must match the next popped token.\n * @returns The popped token.\n */\nfunction popAndCheck(tokens: string[], expected: string | string[]) {\n // Get and remove the next token.\n const popped = tokens.shift();\n\n // We were expecting another token.\n if (popped === undefined) {\n throw new Error(\"unexpected end of definition\");\n }\n\n // Do we have an expected token/tokens array?\n if (expected !== undefined) {\n // Check whether the popped token matches at least one of our expected items.\n var tokenMatchesExpectation = ([] as string[])\n .concat(expected)\n .some((item) => popped.toUpperCase() === item.toUpperCase());\n\n // Throw an error if the popped token didn't match any of our expected items.\n if (!tokenMatchesExpectation) {\n const expectationString = ([] as string[])\n .concat(expected)\n .map((item) => \"'\" + item + \"'\")\n .join(\" or \");\n\n throw new Error(`unexpected token found. Expected '${expectationString}' but got '${popped}'`);\n }\n }\n\n // Return the popped token.\n return popped;\n}\n\ntype StringPlaceholders = { [key: string]: string };\n\n/**\n * Pull an argument definition list off of the token stack.\n * @param tokens The array of remaining tokens.\n * @param stringArgumentPlaceholders The mapping of string literal node argument placeholders to original values.\n * @param argumentValidator The argument validator function.\n * @param validationFailedMessage The exception message to throw if argument validation fails.\n * @returns The argument definition list.\n */\nfunction getArguments(\n tokens: string[],\n stringArgumentPlaceholders: StringPlaceholders,\n argumentValidator?: (arg: AnyArgument) => boolean,\n validationFailedMessage?: string\n) {\n // Any lists of arguments will always be wrapped in '[]' for node arguments or '()' for attribute arguments.\n // We are looking for a '[' or '(' opener that wraps the argument tokens and the relevant closer.\n const closer = popAndCheck(tokens, [\"[\", \"(\"]) === \"[\" ? \"]\" : \")\";\n\n const argumentListTokens: string[] = [];\n const argumentList: AnyArgument[] = [];\n\n // Grab all tokens between the '[' and ']' or '(' and ')'.\n while (tokens.length && tokens[0] !== closer) {\n // The next token is part of our arguments list.\n argumentListTokens.push(tokens.shift()!);\n }\n\n // Validate the order of the argument tokens. Each token must either be a ',' or a single argument that satisfies the validator.\n argumentListTokens.forEach((token, index) => {\n // Get whether this token should be an actual argument.\n const shouldBeArgumentToken = !(index & 1);\n\n // If the current token should be an actual argument then validate it,otherwise it should be a ',' token.\n if (shouldBeArgumentToken) {\n // Get the argument definition.\n const argumentDefinition = getArgumentDefinition(token!, stringArgumentPlaceholders);\n\n // Try to validate the argument.\n if (argumentValidator && !argumentValidator(argumentDefinition)) {\n throw new Error(validationFailedMessage);\n }\n\n // This is a valid argument!\n argumentList.push(argumentDefinition);\n } else {\n // The current token should be a ',' token.\n if (token !== \",\") {\n throw new Error(`invalid argument list, expected ',' or ']' but got '${token}'`);\n }\n }\n });\n\n // The arguments list should terminate with a ']' or ')' token, depending on the opener.\n popAndCheck(tokens, closer);\n\n // Return the argument list.\n return argumentList;\n}\n\n/**\n * Gets an argument value definition.\n * @param token The argument token.\n * @param stringArgumentPlaceholders The mapping of string literal node argument placeholders to original values.\n * @returns An argument value definition.\n */\nfunction getArgumentDefinition(token: string, stringArgumentPlaceholders: StringPlaceholders): AnyArgument {\n // Check whether the token represents a null value.\n if (token === \"null\") {\n return {\n value: null,\n type: \"null\"\n } as NullArgument;\n }\n\n // Check whether the token represents a boolean value.\n if (token === \"true\" || token === \"false\") {\n return {\n value: token === \"true\",\n type: \"boolean\"\n } as BooleanArgument;\n }\n\n // Check whether the token represents a number value.\n // TODO: Relies on broken isNaN - see MDN.\n // if (!Number.isNaN(token)) {\n if (!isNaN(token as any)) {\n return {\n value: parseFloat(token),\n isInteger: parseFloat(token) === parseInt(token, 10),\n type: \"number\"\n } as NumberArgument;\n }\n\n // Check whether the token is a placeholder (e.g. @@0@@) representing a string literal.\n if (token.match(/^@@\\d+@@$/g)) {\n return {\n value: stringArgumentPlaceholders[token].replace('\\\\\"', '\"'),\n type: \"string\"\n } as StringPlaceholderArgument;\n }\n\n // The only remaining option is that the argument value is an identifier.\n return {\n value: token,\n type: \"identifier\"\n } as IdentifierArgument;\n}\n\n/**\n * Pull any attributes off of the token stack.\n * @param tokens The array of remaining tokens.\n * @param stringArgumentPlaceholders The mapping of string literal node argument placeholders to original values.\n * @returns An array of attributes defined by any directly following tokens.\n */\nfunction getAttributes(tokens: string[], stringArgumentPlaceholders: StringPlaceholders) {\n // Create an array to hold any attributes found.\n const attributes: Attribute[] = [];\n\n // Keep track of names of attribute that we have found on the token stack, as we cannot have duplicates.\n const attributesFound: string[] = [];\n\n // Try to get the attribute factory for the next token.\n let attributeFactory = AttributeFactories[(tokens[0] || \"\").toUpperCase()];\n\n // Pull attribute tokens off of the tokens stack until we have no more.\n while (attributeFactory) {\n // Check to make sure that we have not already created a attribute of this type for this node.\n if (attributesFound.indexOf(tokens[0].toUpperCase()) !== -1) {\n throw new Error(`duplicate attribute '${tokens[0].toUpperCase()}' found for node`);\n }\n\n // Add the current attribute type to our array of found attributes.\n attributesFound.push(tokens.shift()!.toUpperCase());\n\n // Grab any attribute arguments.\n const attributeArguments = getArguments(tokens, stringArgumentPlaceholders);\n\n // The first attribute argument has to be an identifer, this will reference an agent function.\n if (attributeArguments.length === 0 || attributeArguments[0].type !== \"identifier\") {\n throw new Error(\"expected agent function name identifier argument for attribute\");\n }\n\n // Grab the first attribute which is an identifier that will reference an agent function.\n const attributeFunctionName = attributeArguments.shift()! as IdentifierArgument;\n\n // Any remaining attribute arguments must have a type of string, number, boolean or null.\n attributeArguments\n .filter((arg) => arg.type === \"identifier\")\n .forEach((arg) => {\n throw new Error(\n \"invalid attribute argument value '\" + arg.value + \"', must be string, number, boolean or null\"\n );\n });\n\n // Create the attribute and add it to the array of attributes found.\n attributes.push(attributeFactory(attributeFunctionName.value, attributeArguments));\n\n // Try to get the next attribute name token, as there could be multiple.\n attributeFactory = AttributeFactories[(tokens[0] || \"\").toUpperCase()];\n }\n\n return attributes;\n}\n\n/**\n * Swaps out any node/attribute argument string literals with placeholders.\n * @param definition The definition.\n * @returns An object containing a mapping of placeholders to original string values as well as the processed definition string.\n */\nfunction substituteStringLiterals(definition: string): {\n placeholders: { [key: string]: string };\n processedDefinition: string;\n} {\n // Create an object to hold the mapping of placeholders to original string values.\n const placeholders: StringPlaceholders = {};\n\n // Replace any string literals wrapped with double quotes in our definition with placeholders to be processed later.\n const processedDefinition = definition.replace(/\\\"(\\\\.|[^\"\\\\])*\\\"/g, (match) => {\n var strippedMatch = match.substring(1, match.length - 1);\n var placeholder = Object.keys(placeholders).find((key) => placeholders[key] === strippedMatch);\n\n // If we have no existing string literal match then create a new placeholder.\n if (!placeholder) {\n placeholder = `@@${Object.keys(placeholders).length}@@`;\n placeholders[placeholder] = strippedMatch;\n }\n\n return placeholder;\n });\n\n return { placeholders, processedDefinition };\n}\n\n/**\n * Parse the tree definition into an array of raw tokens.\n * @param definition The definition.\n * @returns An array of tokens parsed from the definition.\n */\nfunction parseTokensFromDefinition(definition: string): string[] {\n // Add some space around various important characters so that they can be plucked out easier as individual tokens.\n definition = definition.replace(/\\(/g, \" ( \");\n definition = definition.replace(/\\)/g, \" ) \");\n definition = definition.replace(/\\{/g, \" { \");\n definition = definition.replace(/\\}/g, \" } \");\n definition = definition.replace(/\\]/g, \" ] \");\n definition = definition.replace(/\\[/g, \" [ \");\n definition = definition.replace(/\\,/g, \" , \");\n\n // Split the definition into raw token form and return it.\n return definition.replace(/\\s+/g, \" \").trim().split(\" \");\n}\n", "import GuardPath, { GuardPathPart } from \"./attributes/guards/GuardPath\";\nimport buildRootASTNodes, { AnyArgument, RootAstNode } from \"./RootAstNodesBuilder\";\nimport State, { AnyState } from \"./State\";\nimport Lookup from \"./Lookup\";\nimport Node from \"./nodes/Node\";\nimport Root from \"./nodes/decorator/Root\";\nimport Composite from \"./nodes/composite/Composite\";\nimport Decorator from \"./nodes/decorator/Decorator\";\nimport { Agent, GlobalFunction } from \"./Agent\";\nimport { CallbackAttributeDetails } from \"./attributes/callbacks/Callback\";\nimport { GuardAttributeDetails } from \"./attributes/guards/Guard\";\nimport { BehaviourTreeOptions } from \"./BehaviourTreeOptions\";\nimport { convertMDSLToJSON } from \"./mdsl/MDSLDefinitionParser\";\n\n// Purely for outside inspection of the tree.\nexport type FlattenedTreeNode = {\n id: string;\n type: string;\n caption: string;\n state: AnyState;\n guards: GuardAttributeDetails[];\n callbacks: CallbackAttributeDetails[];\n args: AnyArgument[];\n parentId: string | null;\n};\n\n/**\n * A representation of a behaviour tree.\n */\nexport class BehaviourTree {\n /**\n * The main root tree node.\n */\n public readonly rootNode: Root;\n\n /**\n * Creates a new instance of the BehaviourTree class.\n * @param definition The behaviour tree definition.\n * @param agent The agent instance that this behaviour tree is modelling behaviour for.\n * @param options The behaviour tree options object.\n */\n constructor(definition: string, private agent: Agent, private options: BehaviourTreeOptions = {}) {\n // The tree definition must be defined and a valid string.\n if (typeof definition !== \"string\") {\n throw new Error(\"the tree definition must be a string\");\n }\n\n // The agent must be defined and not null.\n if (typeof agent !== \"object\" || agent === null) {\n throw new Error(\"the agent must be defined and not null\");\n }\n\n // Parse the behaviour tree definition, create the populated tree of behaviour tree nodes, and get the root.\n this.rootNode = BehaviourTree._createRootNode(definition);\n }\n\n /**\n * Gets whether the tree is in the RUNNING state.\n * @returns true if the tree is in the RUNNING state, otherwise false.\n */\n isRunning() {\n return this.rootNode.getState() === State.RUNNING;\n }\n\n /**\n * Gets the current tree state of SUCCEEDED, FAILED, READY or RUNNING.\n * @returns The current tree state.\n */\n getState() {\n return this.rootNode.getState();\n }\n\n /**\n * Step the tree.\n * 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.\n * 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\n * 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.\n *\n * 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.\n */\n step() {\n // If the root node has already been stepped to completion then we need to reset it.\n if (this.rootNode.getState() === State.SUCCEEDED || this.rootNode.getState() === State.FAILED) {\n this.rootNode.reset();\n }\n\n try {\n this.rootNode.update(this.agent, this.options);\n } catch (exception) {\n throw new Error(`error stepping tree: ${(exception as Error).message}`);\n }\n }\n\n /**\n * Resets the tree from the root node outwards to each nested node, giving each a state of READY.\n */\n reset() {\n this.rootNode.reset();\n }\n\n /**\n * Gets the flattened details of every node in the tree.\n * @returns The flattened details of every node in the tree.\n */\n getFlattenedNodeDetails(): FlattenedTreeNode[] {\n // Create an empty flattened array of tree nodes.\n const flattenedTreeNodes: FlattenedTreeNode[] = [];\n\n /**\n * Helper function to process a node instance and push details into the flattened tree nodes array.\n * @param node The current node.\n * @param parentUid The UID of the node parent, or null if the node is the main root node.\n */\n const processNode = (node: Node, parentUid: string | null) => {\n // Get the guard and callback attribute details for this node.\n const guards = node\n .getAttributes()\n .filter((attribute) => attribute.isGuard())\n .map((attribute) => attribute.getDetails()) as GuardAttributeDetails[];\n const callbacks = node\n .getAttributes()\n .filter((attribute) => !attribute.isGuard())\n .map((attribute) => attribute.getDetails()) as CallbackAttributeDetails[];\n\n // Push the current node into the flattened nodes array.\n flattenedTreeNodes.push({\n id: node.getUid(),\n type: node.getType(),\n caption: node.getName(),\n state: node.getState(),\n guards,\n callbacks,\n args: node.getArguments(),\n parentId: parentUid\n });\n\n // Process each of the nodes children if it is not a leaf node.\n if (!node.isLeafNode()) {\n (node as Composite | Decorator)\n .getChildren()\n .forEach((child) => processNode(child, (node as Composite | Decorator).getUid()));\n }\n };\n\n // Convert the nested node structure into a flattened array of node details.\n processNode(this.rootNode, null);\n\n return flattenedTreeNodes;\n }\n\n /**\n * Registers the action/condition/guard/callback function or subtree with the given name.\n * @param name The name of the function or subtree to register.\n * @param value The function or subtree definition to register.\n */\n static register(name: string, value: GlobalFunction | string) {\n if (typeof value === \"function\") {\n // We are going to register a action/condition/guard/callback function.\n Lookup.setFunc(name, value);\n } else if (typeof value === \"string\") {\n // We are going to register a subtree.\n let rootASTNodes: RootAstNode[];\n\n try {\n // Try to create the behaviour tree AST based on the definition provided, this could fail if the definition is invalid.\n rootASTNodes = buildRootASTNodes(value);\n } catch (exception) {\n // There was an issue in trying to parse and build the tree definition.\n throw new Error(`error registering definition: ${(exception as Error).message}`);\n }\n\n // This function should only ever be called with a definition containing a single unnamed root node.\n if (rootASTNodes.length != 1 || rootASTNodes[0].name !== null) {\n throw new Error(\"error registering definition: expected a single unnamed root node\");\n }\n\n Lookup.setSubtree(name, rootASTNodes[0]);\n } else {\n throw new Error(\"unexpected value, expected string definition or function\");\n }\n }\n\n /**\n * Unregisters the registered action/condition/guard/callback function or subtree with the given name.\n * @param name The name of the registered action/condition/guard/callback function or subtree to unregister.\n */\n static unregister(name: string): void {\n Lookup.remove(name);\n }\n\n /**\n * Unregister all registered action/condition/guard/callback functions and subtrees.\n */\n static unregisterAll(): void {\n Lookup.empty();\n }\n\n /**\n * Parses a behaviour tree definition and creates a tree of behaviour tree nodes.\n * @param {string} definition The behaviour tree definition.\n * @returns The root behaviour tree node.\n */\n private static _createRootNode(definition: string): Root {\n // TODO Remove!\n try {\n // parseToJSON(definition);\n } catch (exception) {\n console.log(exception);\n }\n\n try {\n // Try to create the behaviour tree AST based on the definition provided, this could fail if the definition is invalid.\n const rootASTNodes = buildRootASTNodes(definition);\n\n // Create a symbol to use as the main root key in our root node mapping.\n const mainRootNodeKey = Symbol(\"__root__\");\n\n // Create a mapping of root node names to root AST tokens. The main root node will have a key of Symbol(\"__root__\").\n const rootNodeMap: { [key: string | symbol]: RootAstNode } = {};\n for (const rootASTNode of rootASTNodes) {\n rootNodeMap[rootASTNode.name === null ? mainRootNodeKey : rootASTNode.name!] = rootASTNode;\n }\n\n // Convert the AST to our actual tree and get the root node.\n const rootNode: Root = rootNodeMap[mainRootNodeKey].createNodeInstance(\n // Create a provider for named root nodes that are part of our definition or have been registered. Prioritising the former.\n (name: string): RootAstNode => (rootNodeMap[name] ? rootNodeMap[name] : Lookup.getSubtree(name)),\n []\n );\n\n // Set a guard path on every leaf of the tree to evaluate as part of its update.\n BehaviourTree._applyLeafNodeGuardPaths(rootNode);\n\n // Return the root node.\n return rootNode;\n } catch (exception) {\n // There was an issue in trying to parse and build the tree definition.\n throw new Error(`error parsing tree: ${(exception as Error).message}`);\n }\n }\n\n /**\n * Applies a guard path to every leaf of the tree to evaluate as part of each update.\n * @param rootNode The main root tree node.\n */\n private static _applyLeafNodeGuardPaths(rootNode: Root) {\n const nodePaths: Node[][] = [];\n\n const findLeafNodes = (path: Node[], node: Node) => {\n // Add the current node to the path.\n path = path.concat(node);\n\n // Check whether the current node is a leaf node.\n if (node.isLeafNode()) {\n nodePaths.push(path);\n } else {\n (node as Composite | Decorator).getChildren().forEach((child) => findLeafNodes(path, child));\n }\n };\n\n // Find all leaf node paths, starting from the root.\n findLeafNodes([], rootNode);\n\n nodePaths.forEach((path) => {\n // Each node in the current path will have to be assigned a guard path, working from the root outwards.\n for (let depth = 0; depth < path.length; depth++) {\n // Get the node in the path at the current depth.\n const currentNode = path[depth];\n\n // The node may already have been assigned a guard path, if so just skip it.\n if (currentNode.hasGuardPath()) {\n continue;\n }\n\n // Create the guard path for the current node.\n const guardPath = new GuardPath(\n path\n .slice(0, depth + 1)\n .map((node) => ({ node, guards: node.getGuardAttributes() }))\n .filter((details) => details.guards.length > 0)\n );\n\n // Assign the guard path to the current node.\n currentNode.setGuardPath(guardPath);\n }\n });\n }\n}\n"], - "mappings": "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", + "sourcesContent": ["\"use strict\";\r\nObject.defineProperty(exports, \"__esModule\", { value: true });\r\nexports.Participant = void 0;\r\n/**\r\n * A participant that holds a number of tickets.\r\n */\r\nvar Participant = /** @class */ (function () {\r\n /**\r\n * Creates an instance of the Participant class.\r\n * @param participant The actual participant.\r\n * @param tickets The number of tickets held by the participant.\r\n */\r\n function Participant(participant, tickets) {\r\n if (tickets === void 0) { tickets = 1; }\r\n this._participant = participant;\r\n this._tickets = tickets;\r\n }\r\n Object.defineProperty(Participant.prototype, \"participant\", {\r\n /** Gets the actual participant. */\r\n get: function () {\r\n return this._participant;\r\n },\r\n enumerable: false,\r\n configurable: true\r\n });\r\n Object.defineProperty(Participant.prototype, \"tickets\", {\r\n /** Gets or sets the number of tickets held by the participant. */\r\n get: function () {\r\n return this._tickets;\r\n },\r\n set: function (value) {\r\n this._tickets = value;\r\n },\r\n enumerable: false,\r\n configurable: true\r\n });\r\n return Participant;\r\n}());\r\nexports.Participant = Participant;\r\n", "\"use strict\";\r\nObject.defineProperty(exports, \"__esModule\", { value: true });\r\nexports.isNaturalNumber = exports.isNullOrUndefined = void 0;\r\n/**\r\n * Gets whether the value provided is null or undefined.\r\n * @param value The value to check.\r\n * @returns Whether the value provided is null or undefined.\r\n */\r\nfunction isNullOrUndefined(value) {\r\n return value === null || value === undefined;\r\n}\r\nexports.isNullOrUndefined = isNullOrUndefined;\r\n/**\r\n * Gets whether the value provided is a natural number.\r\n * @param value The value to check.\r\n * @returns Whether the value provided is a natural number.\r\n */\r\nfunction isNaturalNumber(value) {\r\n return typeof value === \"number\" && value >= 1 && Math.floor(value) === value;\r\n}\r\nexports.isNaturalNumber = isNaturalNumber;\r\n", "\"use strict\";\r\nObject.defineProperty(exports, \"__esModule\", { value: true });\r\nexports.Lotto = void 0;\r\nvar Participant_1 = require(\"./Participant\");\r\nvar Utilities_1 = require(\"./Utilities\");\r\n/**\r\n * Represents a lotto consisting of a number of pickable ticket-holding participants.\r\n */\r\nvar Lotto = /** @class */ (function () {\r\n /**\r\n * Creates a new instance of Lotto.\r\n * @param customRandom The custom RNG to use in place of Math.random().\r\n */\r\n function Lotto(customRandom) {\r\n /** The array of participants that are holding tickets in the lotto. */\r\n this._participants = [];\r\n this._customRandom = customRandom;\r\n }\r\n /**\r\n * Adds a participant with the specified number of tickets, or adds to the participant ticket count if the participant already holds tickets.\r\n * @param participant The participant to add or to increase the ticket count for if they already hold tickets.\r\n * @param tickets The number of tickets, defaults to 1.\r\n * @returns The Lotto instance.\r\n */\r\n Lotto.prototype.add = function (participant, tickets) {\r\n if (tickets === void 0) { tickets = 1; }\r\n // Check that we have a valid ticket count.\r\n if (!(0, Utilities_1.isNaturalNumber)(tickets)) {\r\n throw new Error(\"tickets value must be a natural number\");\r\n }\r\n // Check whether this participant has already been added.\r\n var existingParticipant = this._participants.find(function (part) { return part.participant === participant; });\r\n if (existingParticipant) {\r\n // The participant has already been added to the lotto so just add to their ticket count.\r\n existingParticipant.tickets += tickets;\r\n }\r\n else {\r\n // The participant is not part of the lotto so we should add them.\r\n this._participants.push(new Participant_1.Participant(participant, tickets));\r\n }\r\n return this;\r\n };\r\n /**\r\n * Removes the specified number of tickets for the given participant from the draw, or all tickets if a ticket number is not defined.\r\n * @param participant The participant to remove tickets for.\r\n * @param tickets The number of tickets to remove, or undefined if all tickets are to be removed.\r\n * @returns The Lotto instance.\r\n */\r\n Lotto.prototype.remove = function (participant, tickets) {\r\n // Attempt to get the existing participant.\r\n var existingParticipant = this._participants.find(function (part) { return part.participant === participant; });\r\n // There is nothing to do if the specified participant isn't even part of the lotto.\r\n if (!existingParticipant) {\r\n return this;\r\n }\r\n // Check whether a tickets value was given.\r\n if (tickets !== undefined) {\r\n // Check that we have a valid ticket count.\r\n if (!(0, Utilities_1.isNaturalNumber)(tickets)) {\r\n throw new Error(\"tickets value must be a natural number\");\r\n }\r\n existingParticipant.tickets -= tickets;\r\n // If the participant no longer holds any tickets then they should be removed.\r\n if (existingParticipant.tickets < 1) {\r\n this._participants = this._participants.filter(function (part) { return part !== existingParticipant; });\r\n }\r\n }\r\n else {\r\n // We are removing all tickets for the participant so just remove them from the lotto.\r\n this._participants = this._participants.filter(function (part) { return part !== existingParticipant; });\r\n }\r\n return this;\r\n };\r\n /**\r\n * Draw a winning ticket and return the participant that holds the ticket.\r\n * @param options The draw options.\r\n * @returns The participant that holds the winning ticket.\r\n */\r\n Lotto.prototype.draw = function (options) {\r\n if (options === void 0) { options = {}; }\r\n // If we have no participants then just return null.\r\n if (this._participants.length === 0) {\r\n return null;\r\n }\r\n var redrawable = (0, Utilities_1.isNullOrUndefined)(options.redrawable) ? true : options.redrawable;\r\n var pickable = [];\r\n this._participants.forEach(function (_a) {\r\n var participant = _a.participant, tickets = _a.tickets;\r\n for (var ticketCount = 0; ticketCount < tickets; ticketCount++) {\r\n pickable.push(participant);\r\n }\r\n });\r\n var random;\r\n // We need a random floating-point number between 0 (inclusive) and 1 to scale up to pick our winner.\r\n // If a custom random function exists then we should use that or fall back to Math.random().\r\n if (this._customRandom) {\r\n // Call our custom random function to get a random floating-point number.\r\n random = this._customRandom();\r\n // Verify that the result of calling our custom random function is a number between 0 (inclusive) and 1.\r\n if (typeof random !== \"number\" || random < 0 || random >= 1) {\r\n throw new Error(\"the 'random' function provided did not return a number between 0 (inclusive) and 1\");\r\n }\r\n }\r\n else {\r\n // No custom random function was defined so just use good ol' Math.random().\r\n random = Math.random();\r\n }\r\n // Pick a winning participant.\r\n var winner = pickable[Math.floor(random * pickable.length)];\r\n // If the ticket isn't redrawable then we should remove a ticket from the winning participants ticket count.\r\n if (!redrawable) {\r\n this.remove(winner, 1);\r\n }\r\n // Return the winning participant.\r\n return winner;\r\n };\r\n /**\r\n * Draws multiple winning tickets and return an array of the participants that hold the winning tickets.\r\n * @param tickets The number of winning tickets to draw.\r\n * @param options The draw multiple options.\r\n * @returns An array of the participants that hold the winning tickets.\r\n */\r\n Lotto.prototype.drawMultiple = function (tickets, options) {\r\n if (options === void 0) { options = {}; }\r\n var uniqueResults = (0, Utilities_1.isNullOrUndefined)(options.unique) ? false : options.unique;\r\n // Handle cases where the user has asked for zero tickets (no idea why they would do this be we should trust them).\r\n if (tickets === 0) {\r\n return [];\r\n }\r\n // Now that we know out tickets value is not zero we should check that it is a valid natural number.\r\n if (!(0, Utilities_1.isNaturalNumber)(tickets)) {\r\n throw new Error(\"tickets value must be a natural number\");\r\n }\r\n var result = [];\r\n // Keep drawing tickets until we either reach the number of required tickets or we simply run out of tickets to draw.\r\n // We can run out of tickets to draw if 'options.redrawable' is explicity 'false' or we just had no participants when 'drawMultiple' was called.\r\n while (result.length < tickets && this._participants.length > 0) {\r\n result.push(this.draw(options));\r\n }\r\n // If the 'unique' draw option is set then we need to remove duplicates from the result list.\r\n if (uniqueResults) {\r\n // Create an array to store our unique results.\r\n var unique = [];\r\n // Iterate over all of our participants (with potential duplicates) and populate our array of unique values.\r\n for (var _i = 0, result_1 = result; _i < result_1.length; _i++) {\r\n var participant = result_1[_i];\r\n if (unique.indexOf(participant) === -1) {\r\n unique.push(participant);\r\n }\r\n }\r\n result = unique;\r\n }\r\n return result;\r\n };\r\n return Lotto;\r\n}());\r\nexports.Lotto = Lotto;\r\n", "\"use strict\";\r\nObject.defineProperty(exports, \"__esModule\", { value: true });\r\nexports.createLotto = void 0;\r\nvar Lotto_1 = require(\"./Lotto\");\r\n/**\r\n * A function that creates and returns a Lotto instance.\r\n * @param participantsOrOptions An array of initial participants or options relating to the creation of a Lotto instance.\r\n * @returns A new Lotto instance.\r\n */\r\nfunction createLotto(participantsOrOptions) {\r\n // If no initial participants or lotto options were provided as an argument then we can just return a new lotto instance now.\r\n if (!participantsOrOptions) {\r\n return new Lotto_1.Lotto();\r\n }\r\n // Check whether we were provided with an array of initial participants or a lotto options object.\r\n if (Array.isArray(participantsOrOptions)) {\r\n // We are dealing with a pre-defined array of participants.\r\n var participants = participantsOrOptions;\r\n var lotto_1 = new Lotto_1.Lotto();\r\n // If the lotto participants have been defined upfront then we will need to add them all to our lotto instance now.\r\n participants.forEach(function (_a) {\r\n var participant = _a[0], tokens = _a[1];\r\n return lotto_1.add(participant, tokens);\r\n });\r\n // Return the Lotto instance.\r\n return lotto_1;\r\n }\r\n else {\r\n // We are dealing with some lotto options.\r\n var random = participantsOrOptions.random, participants = participantsOrOptions.participants;\r\n // Create a Lotto instance passing the custom RNG function to use in place of Math.random() (which could be undefined).\r\n var lotto_2 = new Lotto_1.Lotto(random);\r\n // If the lotto participants have been defined upfront as part of the options then we will need to add them all to our lotto instance now.\r\n if (participants) {\r\n participants.forEach(function (_a) {\r\n var participant = _a[0], tokens = _a[1];\r\n return lotto_2.add(participant, tokens);\r\n });\r\n }\r\n // Return the Lotto instance.\r\n return lotto_2;\r\n }\r\n}\r\nexports.createLotto = createLotto;\r\n", "\"use strict\";\r\nObject.defineProperty(exports, \"__esModule\", { value: true });\r\nvar createLotto_1 = require(\"./createLotto\");\r\nexports.default = createLotto_1.createLotto;\r\n", "import State from \"./State\";\nimport { validateDefinition } from \"./BehaviourTreeDefinitionValidator\";\nimport { convertMDSLToJSON } from \"./mdsl/MDSLDefinitionParser\";\nimport { BehaviourTree, FlattenedTreeNode } from \"./BehaviourTree\";\n\nexport { BehaviourTree, State, convertMDSLToJSON, validateDefinition };\nexport type { FlattenedTreeNode };\n", "/**\n * Enumeration of node state types.\n */\nexport enum State {\n READY = \"mistreevous.ready\",\n RUNNING = \"mistreevous.running\",\n SUCCEEDED = \"mistreevous.succeeded\",\n FAILED = \"mistreevous.failed\"\n}\n\nexport { State as default };\n\nexport type CompleteState = State.SUCCEEDED | State.FAILED;\nexport type AnyState = State.READY | State.RUNNING | CompleteState;\n", "import {\n NodeDefinition,\n RootNodeDefinition,\n DecoratorNodeDefinition,\n CompositeNodeDefinition,\n AnyNode,\n BranchNodeDefinition\n} from \"./BehaviourTreeDefinition\";\n\n/**\n * A type guard function that returns true if the specified node satisfies the RootNodeDefinition type.\n * @param node The node.\n * @returns A value of true if the specified node satisfies the RootNodeDefinition type.\n */\nexport function isRootNode(node: NodeDefinition): node is RootNodeDefinition {\n return node.type === \"root\";\n}\n\n/**\n * A type guard function that returns true if the specified node satisfies the BranchNodeDefinition type.\n * @param node The node.\n * @returns A value of true if the specified node satisfies the BranchNodeDefinition type.\n */\nexport function isBranchNode(node: NodeDefinition): node is BranchNodeDefinition {\n return node.type === \"branch\";\n}\n\n/**\n * A type guard function that returns true if the specified node satisfies the NodeDefinition type.\n * @param node The node.\n * @returns A value of true if the specified node satisfies the NodeDefinition type.\n */\nexport function isLeafNode(node: NodeDefinition): node is NodeDefinition {\n return [\"branch\", \"action\", \"condition\", \"wait\"].includes(node.type);\n}\n\n/**\n * A type guard function that returns true if the specified node satisfies the DecoratorNodeDefinition type.\n * @param node The node.\n * @returns A value of true if the specified node satisfies the DecoratorNodeDefinition type.\n */\nexport function isDecoratorNode(node: NodeDefinition): node is DecoratorNodeDefinition {\n return [\"root\", \"repeat\", \"retry\", \"flip\", \"succeed\", \"fail\"].includes(node.type);\n}\n\n/**\n * A type guard function that returns true if the specified node satisfies the CompositeNodeDefinition type.\n * @param node The node.\n * @returns A value of true if the specified node satisfies the CompositeNodeDefinition type.\n */\nexport function isCompositeNode(node: NodeDefinition): node is CompositeNodeDefinition {\n return [\"sequence\", \"selector\", \"lotto\", \"parallel\"].includes(node.type);\n}\n\n/**\n * Flatten a node definition into an array of all of its nested node definitions.\n * @param nodeDefinition The node definition to flatten.\n * @returns An array of all of nested node definitions.\n */\nexport function flattenDefinition(nodeDefinition: AnyNode): AnyNode[] {\n const nodes: AnyNode[] = [];\n\n const processNode = (currentNodeDefinition: AnyNode) => {\n nodes.push(currentNodeDefinition);\n\n if (isCompositeNode(currentNodeDefinition)) {\n currentNodeDefinition.children.forEach(processNode);\n } else if (isDecoratorNode(currentNodeDefinition)) {\n processNode(currentNodeDefinition.child);\n }\n };\n\n processNode(nodeDefinition);\n\n return nodes;\n}\n\n/**\n * Determines whether the passed value is an integer.\n * @param value The value to check.\n * @returns Whether the passed value is an integer.\n */\nexport function isInteger(value: unknown): boolean {\n return typeof value === \"number\" && Math.floor(value) === value;\n}\n", "/**\n * A type defining an object that holds a reference to substitued string literals parsed from the definition.\n */\nexport type StringLiteralPlaceholders = { [key: string]: string };\n\n/**\n * Pop the next raw token from the specified array of tokens and throw an error if it wasn't the expected one.\n * @param tokens The array of tokens.\n * @param expected An optional string or array or items, one of which must match the next popped token.\n * @returns The popped token.\n */\nexport function popAndCheck(tokens: string[], expected?: string | string[]): string {\n // Get and remove the next token.\n const popped = tokens.shift();\n\n // We were expecting another token but there aren't any.\n if (popped === undefined) {\n throw new Error(\"unexpected end of definition\");\n }\n\n // Do we have an expected token/tokens array?\n if (expected != undefined) {\n // Get an array of expected values, if the popped token matches any then we are all good.\n const expectedValues = typeof expected === \"string\" ? [expected] : expected;\n\n // Check whether the popped token matches at least one of our expected items.\n var tokenMatchesExpectation = expectedValues.some((item) => popped.toUpperCase() === item.toUpperCase());\n\n // Throw an error if the popped token didn't match any of our expected items.\n if (!tokenMatchesExpectation) {\n const expectationString = expectedValues.map((item) => \"'\" + item + \"'\").join(\" or \");\n throw new Error(\"unexpected token found. Expected \" + expectationString + \" but got '\" + popped + \"'\");\n }\n }\n\n // Return the popped token.\n return popped;\n}\n\n/**\n * Swaps out any node/attribute argument string literals with placeholders.\n * @param definition The definition.\n * @returns An object containing a mapping of placeholders to original string values as well as the processed definition string.\n */\nexport function substituteStringLiterals(definition: string): {\n placeholders: StringLiteralPlaceholders;\n processedDefinition: string;\n} {\n // Create an object to hold the mapping of placeholders to original string values.\n const placeholders: StringLiteralPlaceholders = {};\n\n // Replace any string literals wrapped with double quotes in our definition with placeholders to be processed later.\n const processedDefinition = definition.replace(/\\\"(\\\\.|[^\"\\\\])*\\\"/g, (match) => {\n var strippedMatch = match.substring(1, match.length - 1);\n var placeholder = Object.keys(placeholders).find((key) => placeholders[key] === strippedMatch);\n\n // If we have no existing string literal match then create a new placeholder.\n if (!placeholder) {\n placeholder = `@@${Object.keys(placeholders).length}@@`;\n placeholders[placeholder] = strippedMatch;\n }\n\n return placeholder;\n });\n\n return { placeholders, processedDefinition };\n}\n\n/**\n * Parse the tree definition into an array of raw tokens.\n * @param definition The definition.\n * @returns An array of tokens parsed from the definition.\n */\nexport function parseTokensFromDefinition(definition: string): string[] {\n // Add some space around various important characters so that they can be plucked out easier as individual tokens.\n definition = definition.replace(/\\(/g, \" ( \");\n definition = definition.replace(/\\)/g, \" ) \");\n definition = definition.replace(/\\{/g, \" { \");\n definition = definition.replace(/\\}/g, \" } \");\n definition = definition.replace(/\\]/g, \" ] \");\n definition = definition.replace(/\\[/g, \" [ \");\n definition = definition.replace(/\\,/g, \" , \");\n\n // Split the definition into raw token form and return it.\n return definition.replace(/\\s+/g, \" \").trim().split(\" \");\n}\n", "import { StringLiteralPlaceholders, popAndCheck } from \"./MDSLUtilities\";\n\nexport type Argument = {\n /** The argument value. */\n value: T;\n /** The argument type, used for validation. */\n type: string;\n};\n\nexport type NullArgument = Argument & {\n type: \"null\";\n};\n\nexport type BooleanArgument = Argument & {\n type: \"boolean\";\n};\n\nexport type NumberArgument = Argument & {\n type: \"number\";\n isInteger: boolean; // Used for validation.\n};\n\nexport type StringPlaceholderArgument = Argument & {\n type: \"string\";\n};\n\nexport type IdentifierArgument = Argument & {\n type: \"identifier\";\n};\n\nexport type AnyArgument =\n | NullArgument\n | BooleanArgument\n | NumberArgument\n | StringPlaceholderArgument\n | IdentifierArgument;\n\n/**\n * Parse an array of argument definitions from the specified tokens array.\n * @param tokens The array tokens to parse the argument definitions from.\n * @param stringArgumentPlaceholders The mapping of string literal node argument placeholders to original values.\n * @param argumentValidator The argument validator function.\n * @param validationFailedMessage The exception message to throw if argument validation fails.\n * @returns An array of argument definitions parsed from the specified tokens array.\n */\nexport function parseArgumentTokens(\n tokens: string[],\n stringArgumentPlaceholders: StringLiteralPlaceholders\n): AnyArgument[] {\n const argumentList: AnyArgument[] = [];\n\n // If the next token is not a '[' or '(' then we have no arguments to parse.\n if (![\"[\", \"(\"].includes(tokens[0])) {\n return argumentList;\n }\n\n // Any lists of arguments will always be wrapped in '[]' for node arguments or '()' for attribute arguments.\n // We are looking for a '[' or '(' opener that wraps the argument tokens and the relevant closer.\n const closingToken = popAndCheck(tokens, [\"[\", \"(\"]) === \"[\" ? \"]\" : \")\";\n\n const argumentListTokens: string[] = [];\n\n // Grab all tokens between the '[' and ']' or '(' and ')'.\n while (tokens.length && tokens[0] !== closingToken) {\n // The next token is part of our arguments list.\n argumentListTokens.push(tokens.shift()!);\n }\n\n // Validate the order of the argument tokens. Each token must either be a ',' or a single argument that satisfies the validator.\n argumentListTokens.forEach((token, index) => {\n // Get whether this token should be an actual argument.\n const shouldBeArgumentToken = !(index & 1);\n\n // If the current token should be an actual argument then validate it, otherwise it should be a ',' token.\n if (shouldBeArgumentToken) {\n // Get the argument definition.\n const argumentDefinition = getArgumentDefinition(token, stringArgumentPlaceholders);\n\n // This is a valid argument!\n argumentList.push(argumentDefinition);\n } else {\n // The current token should be a ',' token.\n if (token !== \",\") {\n throw new Error(`invalid argument list, expected ',' or ']' but got '${token}'`);\n }\n }\n });\n\n // The arguments list should terminate with a ']' or ')' token, depending on the opener.\n popAndCheck(tokens, closingToken);\n\n // Return the arguments.\n return argumentList;\n}\n\n/**\n * Gets an argument value definition.\n * @param token The argument token.\n * @param stringArgumentPlaceholders The mapping of string literal node argument placeholders to original values.\n * @returns An argument value definition.\n */\nfunction getArgumentDefinition(token: string, stringArgumentPlaceholders: StringLiteralPlaceholders): AnyArgument {\n // Check whether the token represents a null value.\n if (token === \"null\") {\n return {\n value: null,\n type: \"null\"\n } as NullArgument;\n }\n\n // Check whether the token represents a boolean value.\n if (token === \"true\" || token === \"false\") {\n return {\n value: token === \"true\",\n type: \"boolean\"\n } as BooleanArgument;\n }\n\n // Check whether the token represents a number value.\n // TODO: Relies on broken isNaN - see MDN.\n // if (!Number.isNaN(token)) {\n if (!isNaN(token as any)) {\n return {\n value: parseFloat(token),\n isInteger: parseFloat(token) === parseInt(token, 10),\n type: \"number\"\n } as NumberArgument;\n }\n\n // Check whether the token is a placeholder (e.g. @@0@@) representing a string literal.\n if (token.match(/^@@\\d+@@$/g)) {\n return {\n value: stringArgumentPlaceholders[token].replace('\\\\\"', '\"'),\n type: \"string\"\n } as StringPlaceholderArgument;\n }\n\n // The only remaining option is that the argument value is an identifier.\n return {\n value: token,\n type: \"identifier\"\n } as IdentifierArgument;\n}\n", "import { NodeAttributeDefinition } from \"../BehaviourTreeDefinition\";\nimport { parseArgumentTokens } from \"./MDSLNodeArgumentParser\";\nimport { StringLiteralPlaceholders } from \"./MDSLUtilities\";\n\n/**\n * A type defining the attribute definitions of a node.\n */\ntype NodeAttributes = {\n while?: NodeAttributeDefinition;\n until?: NodeAttributeDefinition;\n entry?: NodeAttributeDefinition;\n exit?: NodeAttributeDefinition;\n step?: NodeAttributeDefinition;\n};\n\n/**\n * Parse any node attribute definitions from the specified tokens array.\n * @param tokens The array of remaining tokens.\n * @param stringArgumentPlaceholders The mapping of string literal node argument placeholders to original values.\n * @returns An object of attribute definitions defined by any directly following tokens.\n */\nexport function parseAttributeTokens(\n tokens: string[],\n stringArgumentPlaceholders: StringLiteralPlaceholders\n): NodeAttributes {\n const nodeAttributeNames: (keyof NodeAttributes)[] = [\"while\", \"until\", \"entry\", \"exit\", \"step\"];\n\n // Create an object to hold any attributes found.\n const attributes: NodeAttributes = {};\n\n // Try to get the name of the attribute for the next token.\n let nextAttributeName = tokens[0]?.toLowerCase() as keyof NodeAttributes;\n\n // Pull attribute tokens as well as their arguments off of the tokens stack until we have no more.\n while (nodeAttributeNames.includes(nextAttributeName)) {\n // Check to make sure that we have not already created an attribute definition of this type.\n if (attributes[nextAttributeName]) {\n throw new Error(`duplicate attribute '${tokens[0].toUpperCase()}' found for node`);\n }\n\n // Remove the attribute name token from the array of tokens.\n tokens.shift();\n\n // Grab the attribute arguments, assuming the first to be an identifier.\n const [attributeCallIdentifier, ...attributeArguments] = parseArgumentTokens(\n tokens,\n stringArgumentPlaceholders\n );\n\n // The first attribute argument has to be an identifer, this will reference an agent function.\n if (attributeCallIdentifier?.type !== \"identifier\") {\n throw new Error(\"expected agent function name identifier argument for attribute\");\n }\n\n // Any attribute arguments (other than the expected call identifier) must have a type of string, number, boolean or null.\n attributeArguments\n .filter((arg) => arg.type === \"identifier\")\n .forEach((arg) => {\n throw new Error(\n `invalid attribute argument value '${arg.value}', must be string, number, boolean or null`\n );\n });\n\n // Create the attribute definition and add it to the object of attribute definitions found.\n attributes[nextAttributeName] = {\n call: attributeCallIdentifier.value,\n args: attributeArguments.map(({ value }) => value)\n };\n\n // Try to get the next attribute name token, as there could be multiple.\n nextAttributeName = tokens[0]?.toLowerCase() as keyof NodeAttributes;\n }\n\n return attributes;\n}\n", "import {\n ActionNodeDefinition,\n AnyChildNode,\n AnyNode,\n BranchNodeDefinition,\n ConditionNodeDefinition,\n FailNodeDefinition,\n FlipNodeDefinition,\n LottoNodeDefinition,\n ParallelNodeDefinition,\n RepeatNodeDefinition,\n RetryNodeDefinition,\n RootNodeDefinition,\n SelectorNodeDefinition,\n SequenceNodeDefinition,\n SucceedNodeDefinition,\n WaitNodeDefinition\n} from \"../BehaviourTreeDefinition\";\nimport { isCompositeNode, isDecoratorNode, isLeafNode, isRootNode } from \"../BehaviourTreeDefinitionUtilities\";\nimport { parseArgumentTokens } from \"./MDSLNodeArgumentParser\";\nimport { parseAttributeTokens } from \"./MDSLNodeAttributeParser\";\nimport {\n StringLiteralPlaceholders,\n parseTokensFromDefinition,\n popAndCheck,\n substituteStringLiterals\n} from \"./MDSLUtilities\";\n\n/**\n * Convert the MDSL tree definition string into an equivalent JSON definition.\n * @param definition The tree definition string as MDSL.\n * @returns The root node JSON definitions.\n */\nexport function convertMDSLToJSON(definition: string): RootNodeDefinition[] {\n // Swap out any node/attribute argument string literals with a placeholder and get a mapping of placeholders to original values as well as the processed definition.\n const { placeholders, processedDefinition } = substituteStringLiterals(definition);\n\n // Parse our definition definition string into an array of raw tokens.\n const tokens = parseTokensFromDefinition(processedDefinition);\n\n return convertTokensToJSONDefinition(tokens, placeholders);\n}\n\n/**\n * Converts the specified tree definition tokens into a JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The root node JSON definitions.\n */\nfunction convertTokensToJSONDefinition(\n tokens: string[],\n stringLiteralPlaceholders: StringLiteralPlaceholders\n): RootNodeDefinition[] {\n // There must be at least 3 tokens for the tree definition to be valid. 'ROOT', '{' and '}'.\n if (tokens.length < 3) {\n throw new Error(\"invalid token count\");\n }\n\n // We should have a matching number of '{' and '}' tokens. If not, then there are scopes that have not been properly closed.\n if (tokens.filter((token) => token === \"{\").length !== tokens.filter((token) => token === \"}\").length) {\n throw new Error(\"scope character mismatch\");\n }\n\n // Create an array of tree stack arrays where root nodes will always be at the botton and the current composite/decorator node at the top.\n // There should be an element in this array for every root node defined and every element should be an array with a root note as the first element.\n // E.g. A definition with two root nodes defined:\n // [\n // [root, lotto, sequence],\n // [root, selector]\n // ]\n const treeStacks: [Partial, ...Partial[]][] = [];\n\n // Create an array of all root node definitions that we create.\n const rootNodes: Partial[] = [];\n\n // A helper function used to push node definitions onto the tree stack.\n const pushNode = (node: AnyNode) => {\n // If the node is a root node then we need to create a new tree stack array with the root node at the root.\n if (isRootNode(node)) {\n // Add the root node definition to our array of all parsed root node definitions.\n rootNodes.push(node);\n\n // Add the root node definition to the root of a new tree stack.\n treeStacks.push([node]);\n\n return;\n }\n\n // All non-root nodes should be pushed after their root nodes so handle cases\n // where we may not have any tree stacks or our top-most tree stack is empty.\n if (!treeStacks.length || !treeStacks[treeStacks.length - 1].length) {\n throw new Error(\"expected root node at base of definition\");\n }\n\n // Get the current tree stack that we are populating.\n const topTreeStack = treeStacks[treeStacks.length - 1];\n\n // Get the top-most node in the current tree stack, this will be a composite/decorator node\n // for which we will populate its children array if composite or setting its child if a decorator.\n const topTreeStackTopNode = topTreeStack[topTreeStack.length - 1] as AnyNode;\n\n // If the top-most node in the current root stack is a composite or decorator\n // node then the current node should be added as a child of the top-most node.\n if (isCompositeNode(topTreeStackTopNode)) {\n topTreeStackTopNode.children = topTreeStackTopNode.children || [];\n topTreeStackTopNode.children.push(node);\n } else if (isDecoratorNode(topTreeStackTopNode)) {\n // If the top node already has a child node set then throw an error as a decorator should only have a single child.\n if (topTreeStackTopNode.child) {\n throw new Error(\"a decorator node must only have a single child node\");\n }\n\n topTreeStackTopNode.child = node;\n }\n\n // If the node we are adding is also a composite or decorator node, then we should push it\n // onto the current tree stack, as subsequent nodes will be added as its child/children.\n if (!isLeafNode(node)) {\n topTreeStack.push(node);\n }\n };\n\n // A helper function used to pop node definitions off of the stack.\n const popNode = () => {\n // Get the current tree stack that we are populating.\n const topTreeStack = treeStacks[treeStacks.length - 1];\n\n // Pop the top-most node in the current tree stack if there is one.\n if (topTreeStack.length) {\n topTreeStack.pop();\n }\n\n // We don't want any empty tree stacks in our stack of tree stacks.\n if (!topTreeStack.length) {\n treeStacks.pop();\n }\n };\n\n // We should keep processing the raw tokens until we run out of them.\n while (tokens.length) {\n // Grab the next token.\n const token = tokens.shift()!;\n\n // How we create the next node depends on the current raw token value.\n switch (token.toUpperCase()) {\n case \"ROOT\": {\n pushNode(createRootNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"SUCCEED\": {\n pushNode(createSucceedNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"FAIL\": {\n pushNode(createFailNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"FLIP\": {\n pushNode(createFlipNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"REPEAT\": {\n pushNode(createRepeatNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"RETRY\": {\n pushNode(createRetryNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"SEQUENCE\": {\n pushNode(createSequenceNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"SELECTOR\": {\n pushNode(createSelectorNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"PARALLEL\": {\n pushNode(createParallelNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"LOTTO\": {\n pushNode(createLottoNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"ACTION\": {\n pushNode(createActionNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"CONDITION\": {\n pushNode(createConditionNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"WAIT\": {\n pushNode(createWaitNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"BRANCH\": {\n pushNode(createBranchNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"}\": {\n // The '}' character closes the current scope and means that we have to pop a node off of the current stack.\n popNode();\n break;\n }\n\n default: {\n throw new Error(`unexpected token: ${token}`);\n }\n }\n }\n\n return rootNodes as RootNodeDefinition[];\n}\n\n/**\n * Creates a root node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The root node JSON definition.\n */\nfunction createRootNode(tokens: string[], stringLiteralPlaceholders: StringLiteralPlaceholders): RootNodeDefinition {\n // Create the root node definition.\n let node = {\n type: \"root\",\n id: undefined\n } as RootNodeDefinition;\n\n // Parse any node arguments, we should only have one if any which will be an identifier argument for the root identifier.\n const nodeArguments = parseArgumentTokens(tokens, stringLiteralPlaceholders);\n\n // Check whether any node arguments were defined.\n if (nodeArguments.length) {\n // We should only have one argument, if any, which will be an identifier argument for the root identifier.\n if (nodeArguments.length === 1 && nodeArguments[0].type === \"identifier\") {\n // The root node identifier will be the first and only node argument value.\n node.id = nodeArguments[0].value as string;\n } else {\n throw new Error(\"expected single root name argument\");\n }\n }\n\n // Grab any node attribute definitions and spread them into the node definition.\n node = { ...node, ...parseAttributeTokens(tokens, stringLiteralPlaceholders) };\n\n // This is a decorator node, so we expect an opening '{'.\n popAndCheck(tokens, \"{\");\n\n // Return the root node definition.\n return node;\n}\n\n/**\n * Creates a succeed node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The succeed node JSON definition.\n */\nfunction createSucceedNode(\n tokens: string[],\n stringLiteralPlaceholders: StringLiteralPlaceholders\n): SucceedNodeDefinition {\n const node = {\n type: \"succeed\",\n ...parseAttributeTokens(tokens, stringLiteralPlaceholders)\n } as SucceedNodeDefinition;\n\n // This is a decorator node, so we expect an opening '{'.\n popAndCheck(tokens, \"{\");\n\n // Return the succeed node definition.\n return node;\n}\n\n/**\n * Creates a fail node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The fail node JSON definition.\n */\nfunction createFailNode(tokens: string[], stringLiteralPlaceholders: StringLiteralPlaceholders): FailNodeDefinition {\n const node = {\n type: \"fail\",\n ...parseAttributeTokens(tokens, stringLiteralPlaceholders)\n } as FailNodeDefinition;\n\n // This is a decorator node, so we expect an opening '{'.\n popAndCheck(tokens, \"{\");\n\n // Return the fail node definition.\n return node;\n}\n\n/**\n * Creates a flip node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The flip node JSON definition.\n */\nfunction createFlipNode(tokens: string[], stringLiteralPlaceholders: StringLiteralPlaceholders): FlipNodeDefinition {\n const node = {\n type: \"flip\",\n ...parseAttributeTokens(tokens, stringLiteralPlaceholders)\n } as FlipNodeDefinition;\n\n // This is a decorator node, so we expect an opening '{'.\n popAndCheck(tokens, \"{\");\n\n // Return the flip node definition.\n return node;\n}\n\n/**\n * Creates a repeat node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The repeat node JSON definition.\n */\nfunction createRepeatNode(\n tokens: string[],\n stringLiteralPlaceholders: StringLiteralPlaceholders\n): RepeatNodeDefinition {\n let node = { type: \"repeat\" } as RepeatNodeDefinition;\n\n // Get the node arguments.\n const nodeArguments = parseArgumentTokens(tokens, stringLiteralPlaceholders);\n\n // The arguments of a repeat node are optional. We may have:\n // - No node arguments, in which case the repeat note will iterate indefinitely.\n // - One node argument which will be the explicit number of iterations to make.\n // - Two node arguments which define the min and max iteration bounds from which a random iteration count will be picked.\n if (nodeArguments.length) {\n // All repeat node arguments MUST be of type number and must be integer.\n nodeArguments\n .filter((arg) => arg.type !== \"number\" || !arg.isInteger)\n .forEach(() => {\n throw new Error(`repeat node iteration counts must be integer values`);\n });\n\n // We should have got one or two iteration counts.\n if (nodeArguments.length === 1) {\n // A static iteration count was defined.\n node.iterations = nodeArguments[0].value as number;\n } else if (nodeArguments.length === 2) {\n // A minimum and maximum iteration count was defined.\n node.iterations = [nodeArguments[0].value as number, nodeArguments[1].value as number];\n } else {\n // An incorrect number of iteration counts was defined.\n throw new Error(\"invalid number of repeat node iteration count arguments defined\");\n }\n }\n\n // Grab any node attribute definitions and spread them into the node definition.\n node = { ...node, ...parseAttributeTokens(tokens, stringLiteralPlaceholders) };\n\n // This is a decorator node, so we expect an opening '{'.\n popAndCheck(tokens, \"{\");\n\n // Return the repeat node definition.\n return node;\n}\n\n/**\n * Creates a retry node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The retry node JSON definition.\n */\nfunction createRetryNode(tokens: string[], stringLiteralPlaceholders: StringLiteralPlaceholders): RetryNodeDefinition {\n let node = { type: \"retry\" } as RetryNodeDefinition;\n\n // Get the node arguments.\n const nodeArguments = parseArgumentTokens(tokens, stringLiteralPlaceholders);\n\n // The arguments of a retry node are optional. We may have:\n // - No node arguments, in which case the retry note will attempt indefinitely.\n // - One node argument which will be the explicit number of attempts to make.\n // - Two node arguments which define the min and max attempt bounds from which a random attempt count will be picked.\n if (nodeArguments.length) {\n // All retry node arguments MUST be of type number and must be integer.\n nodeArguments\n .filter((arg) => arg.type !== \"number\" || !arg.isInteger)\n .forEach(() => {\n throw new Error(`retry node attempt counts must be integer values`);\n });\n\n // We should have got one or two attempt counts.\n if (nodeArguments.length === 1) {\n // A static attempt count was defined.\n node.attempts = nodeArguments[0].value as number;\n } else if (nodeArguments.length === 2) {\n // A minimum and maximum attempt count was defined.\n node.attempts = [nodeArguments[0].value as number, nodeArguments[1].value as number];\n } else {\n // An incorrect number of attempt counts was defined.\n throw new Error(\"invalid number of retry node attempt count arguments defined\");\n }\n }\n\n // Grab any node attribute definitions and spread them into the node definition.\n node = { ...node, ...parseAttributeTokens(tokens, stringLiteralPlaceholders) };\n\n // This is a decorator node, so we expect an opening '{'.\n popAndCheck(tokens, \"{\");\n\n // Return the retry node definition.\n return node;\n}\n\n/**\n * Creates a sequence node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The sequence node JSON definition.\n */\nfunction createSequenceNode(\n tokens: string[],\n stringLiteralPlaceholders: StringLiteralPlaceholders\n): SequenceNodeDefinition {\n const node = {\n type: \"sequence\",\n ...parseAttributeTokens(tokens, stringLiteralPlaceholders)\n } as SequenceNodeDefinition;\n\n // This is a composite node, so we expect an opening '{'.\n popAndCheck(tokens, \"{\");\n\n // Return the sequence node definition.\n return node;\n}\n\n/**\n * Creates a selector node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The selector node JSON definition.\n */\nfunction createSelectorNode(\n tokens: string[],\n stringLiteralPlaceholders: StringLiteralPlaceholders\n): SelectorNodeDefinition {\n const node = {\n type: \"selector\",\n ...parseAttributeTokens(tokens, stringLiteralPlaceholders)\n } as SelectorNodeDefinition;\n\n // This is a composite node, so we expect an opening '{'.\n popAndCheck(tokens, \"{\");\n\n // Return the selector node definition.\n return node;\n}\n\n/**\n * Creates a parallel node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The parallel node JSON definition.\n */\nfunction createParallelNode(\n tokens: string[],\n stringLiteralPlaceholders: StringLiteralPlaceholders\n): ParallelNodeDefinition {\n const node = {\n type: \"parallel\",\n ...parseAttributeTokens(tokens, stringLiteralPlaceholders)\n } as ParallelNodeDefinition;\n\n // This is a composite node, so we expect an opening '{'.\n popAndCheck(tokens, \"{\");\n\n // Return the parallel node definition.\n return node;\n}\n\n/**\n * Creates a lotto node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The lotto node JSON definition.\n */\nfunction createLottoNode(tokens: string[], stringLiteralPlaceholders: StringLiteralPlaceholders): LottoNodeDefinition {\n // If any node arguments have been defined then they must be our weights.\n const nodeArguments = parseArgumentTokens(tokens, stringLiteralPlaceholders);\n\n // All lotto node arguments MUST be of type number and must be integer.\n nodeArguments\n .filter((arg) => arg.type !== \"number\" || !arg.isInteger)\n .forEach(() => {\n throw new Error(`lotto node weight arguments must be integer values`);\n });\n\n const node = {\n type: \"lotto\",\n weights: nodeArguments.map(({ value }) => value),\n ...parseAttributeTokens(tokens, stringLiteralPlaceholders)\n } as LottoNodeDefinition;\n\n // This is a composite node, so we expect an opening '{'.\n popAndCheck(tokens, \"{\");\n\n // Return the lotto node definition.\n return node;\n}\n\n/**\n * Creates an action node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The action node JSON definition.\n */\nfunction createActionNode(\n tokens: string[],\n stringLiteralPlaceholders: StringLiteralPlaceholders\n): ActionNodeDefinition {\n // Parse any node arguments, we should have at least one which will be an identifier argument for the action name\n // and agent function to invoke for the action, all other arguments are to be passed as arguments to that function.\n const [actionNameIdentifier, ...agentFunctionArgs] = parseArgumentTokens(tokens, stringLiteralPlaceholders);\n\n // Our first argument MUST be defined and be an identifier as we require an action name argument.\n if (actionNameIdentifier?.type !== \"identifier\") {\n throw new Error(\"expected action name identifier argument\");\n }\n\n // Only the first argument should have been an identifier, all agent function arguments must be string, number, boolean or null.\n agentFunctionArgs\n .filter((arg) => arg.type === \"identifier\")\n .forEach((arg) => {\n throw new Error(\n `invalid action node argument value '${arg.value}', must be string, number, boolean or null`\n );\n });\n\n // Return the action node definition.\n return {\n type: \"action\",\n call: actionNameIdentifier.value,\n args: agentFunctionArgs.map(({ value }) => value),\n ...parseAttributeTokens(tokens, stringLiteralPlaceholders)\n };\n}\n\n/**\n * Creates a condition node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The condition node JSON definition.\n */\nfunction createConditionNode(\n tokens: string[],\n stringLiteralPlaceholders: StringLiteralPlaceholders\n): ConditionNodeDefinition {\n // Parse any node arguments, we should have at least one which will be an identifier argument for the condition name\n // and agent function to invoke for the condition, all other arguments are to be passed as arguments to that function.\n const [conditionNameIdentifier, ...agentFunctionArgs] = parseArgumentTokens(tokens, stringLiteralPlaceholders);\n\n // Our first argument MUST be defined and be an identifier as we require a condition name argument.\n if (conditionNameIdentifier?.type !== \"identifier\") {\n throw new Error(\"expected condition name identifier argument\");\n }\n\n // Only the first argument should have been an identifier, all agent function arguments must be string, number, boolean or null.\n agentFunctionArgs\n .filter((arg) => arg.type === \"identifier\")\n .forEach((arg) => {\n throw new Error(\n `invalid condition node argument value '${arg.value}', must be string, number, boolean or null`\n );\n });\n\n // Return the condition node definition.\n return {\n type: \"condition\",\n call: conditionNameIdentifier.value,\n args: agentFunctionArgs.map(({ value }) => value),\n ...parseAttributeTokens(tokens, stringLiteralPlaceholders)\n };\n}\n\n/**\n * Creates a wait node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The wait node JSON definition.\n */\nfunction createWaitNode(tokens: string[], stringLiteralPlaceholders: StringLiteralPlaceholders): WaitNodeDefinition {\n let node = { type: \"wait\" } as WaitNodeDefinition;\n\n // Get the node arguments.\n const nodeArguments = parseArgumentTokens(tokens, stringLiteralPlaceholders);\n\n // The arguments of a wait node are optional. We may have:\n // - No node arguments, in which case the wait will be indefinite until it is aborted.\n // - One node argument which will be the explicit duration of the wait.\n // - Two node arguments which define the min and max duration bounds from which a random duration will be picked.\n if (nodeArguments.length) {\n // All wait node arguments MUST be of type number and must be integer.\n nodeArguments\n .filter((arg) => arg.type !== \"number\" || !arg.isInteger)\n .forEach(() => {\n throw new Error(`wait node duration arguments must be integer values`);\n });\n\n // We may have:\n // - One node argument which will be the explicit duration of the wait.\n // - Two node arguments which define the min and max duration bounds from which a random duration will be picked.\n // - Too many arguments, which is not valid.\n if (nodeArguments.length === 1) {\n // An explicit duration was defined.\n node.duration = nodeArguments[0].value as number;\n } else if (nodeArguments.length === 2) {\n // Min and max duration bounds were defined from which a random duration will be picked.\n node.duration = [nodeArguments[0].value as number, nodeArguments[1].value as number];\n } else if (nodeArguments.length > 2) {\n // An incorrect number of duration arguments were defined.\n throw new Error(\"invalid number of wait node duration arguments defined\");\n }\n }\n\n // Return the wait node definition.\n return { ...node, ...parseAttributeTokens(tokens, stringLiteralPlaceholders) };\n}\n\n/**\n * Creates a branch node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The branch node JSON definition.\n */\nfunction createBranchNode(\n tokens: string[],\n stringLiteralPlaceholders: StringLiteralPlaceholders\n): BranchNodeDefinition {\n // Parse any node arguments, we should have one which will be an identifier argument for the root ref.\n const nodeArguments = parseArgumentTokens(tokens, stringLiteralPlaceholders);\n\n // We should have only a single identifer argument for a branch node, which is the root ref.\n if (nodeArguments.length !== 1 || nodeArguments[0].type !== \"identifier\") {\n throw new Error(\"expected single branch name argument\");\n }\n\n // Return the branch node definition.\n return { type: \"branch\", ref: nodeArguments[0].value };\n}\n", "import { RootNodeDefinition } from \"./BehaviourTreeDefinition\";\nimport { flattenDefinition, isBranchNode, isInteger } from \"./BehaviourTreeDefinitionUtilities\";\nimport { convertMDSLToJSON } from \"./mdsl/MDSLDefinitionParser\";\n\n/**\n * An object representing the result of validating a tree definition.\n */\nexport type DefinitionValidationResult = {\n /**\n * A flag defining whether validation succeeded.\n */\n succeeded: boolean;\n /**\n * A string containing the error message if validation did not succeed.\n */\n errorMessage?: string;\n};\n\n/**\n * Validates the specified behaviour tree definition in the form of JSON or MDSL.\n * @param definition The behaviour tree definition in the form of JSON or MDSL.\n * @returns An object representing the result of validating the given tree definition.\n */\nexport function validateDefinition(definition: any): DefinitionValidationResult {\n // A helper function to create a failure validation result with the given error message.\n const createFailureResult = (errorMessage: string) => ({ succeeded: false, errorMessage });\n\n // The definition must be defined.\n if (definition === null || typeof definition === \"undefined\") {\n return createFailureResult(\"definition is null or undefined\");\n }\n\n let rootNodeDefinitions: any[];\n\n // We are expecting a definition in one of three different forms:\n // - A string which we will assume is mdsl and we will parse this to JSON before validation.\n // - An array which we will assume is an array of root node definitions with at least one being the primary root node (no 'id' property)\n // - An object which we will assume is the primary root node and should not have an 'id' property.\n if (typeof definition === \"string\") {\n try {\n // The definition is a string which we can assume is mdsl, so attempt to parse it to a JSON definition in the form of an array of root node definitions.\n rootNodeDefinitions = convertMDSLToJSON(definition);\n } catch (error) {\n // We failed to parse the JSON from the mdsl, this is likely to be the result of it not being a valid mdsl string.\n return createFailureResult(`invalid mdsl: ${definition}`);\n }\n } else if (typeof definition === \"object\") {\n // The definition will either be an array (of root node definitions) or an object (the single primary root node definition).\n rootNodeDefinitions = Array.isArray(definition) ? definition : [definition];\n } else {\n return createFailureResult(`unexpected definition type of '${typeof definition}'`);\n }\n\n // Iterate over our array of root nodes and call validateNode for each, passing an initial depth of 0, wrapped in a try catch to handle validation failures.\n try {\n rootNodeDefinitions.forEach((rootNodeDefinition) => validateNode(rootNodeDefinition, 0));\n } catch (error) {\n // Handle cases where we have caught a thrown Error and return a failure result with the error message.\n if (error instanceof Error) {\n return createFailureResult(error.message);\n }\n\n // No idea what happened here!\n return createFailureResult(`unexpected error: ${error}`);\n }\n\n // Unpack all of the root node definitions into arrays of main ('id' defined) and sub ('id' not defined) root node definitions.\n const mainRootNodeDefinitions = rootNodeDefinitions.filter(({ id }) => typeof id === \"undefined\");\n const subRootNodeDefinitions = rootNodeDefinitions.filter(({ id }) => typeof id === \"string\" && id.length > 0);\n\n // We should ALWAYS have exactly one root node definition without an 'id' property defined, which is out main root node definition.\n if (mainRootNodeDefinitions.length !== 1) {\n return createFailureResult(\"expected single root node without 'id' property defined to act as main root\");\n }\n\n // We should never have duplicate 'id' properties across our sub root node definitions.\n const subRootNodeIdenitifers: string[] = [];\n for (const { id } of subRootNodeDefinitions) {\n // Have we already come across this 'id' property value?\n if (subRootNodeIdenitifers.includes(id)) {\n return createFailureResult(`multiple root nodes found with duplicate 'id' property value of '${id}'`);\n }\n\n subRootNodeIdenitifers.push(id);\n }\n\n // Check for any branch node circular depedencies. This will not include any globally registered subtrees.\n const circularDependencyPath = findBranchCircularDependencyPath(rootNodeDefinitions);\n\n // If we found a circular dependency in our root node and branch node definitions then the definition is definitely not valid.\n if (circularDependencyPath) {\n return createFailureResult(`circular dependency found in branch node references: ${circularDependencyPath}`);\n }\n\n // Our definition was valid!\n return { succeeded: true };\n}\n\n/**\n * Find the first circular depdendency path present in the array of root node definitions, or null if one doesn't exist.\n * This will not consider branch nodes that reference any globally registered subtrees.\n * @param rootNodeDefinitions The array of root node definitions.\n * @returns The first circular depdendency path present in the array of root node definitions as string, or null if one doesn't exist.\n */\nfunction findBranchCircularDependencyPath(rootNodeDefinitions: RootNodeDefinition[]): string | null {\n // Create a mapping of root node identifiers to other root nodes that they reference via branch nodes.\n // Below is an example of a mapping that includes a circular dependency (root => a => b => c => a)\n // [{ refs: [\"a\", \"b\"] }, { id: \"a\", refs: [\"b\"] }, { id: \"b\", refs: [\"c\"] }, { id: \"c\", refs: [\"a\"] }]\n const rootNodeMappings: { id: string | undefined; refs: string[] }[] = rootNodeDefinitions.map(\n (rootNodeDefinition) => ({\n id: rootNodeDefinition.id,\n refs: flattenDefinition(rootNodeDefinition)\n .filter(isBranchNode)\n .map(({ ref }) => ref)\n })\n );\n\n let badPathFormatted: string | null = null;\n\n // A recursive function to walk through the mappings, keeping track of which root nodes we have visited in the form of a path of root node identifiers.\n const followRefs = (mapping: { id: string | undefined; refs: string[] }, path: (string | undefined)[] = []) => {\n // Have we found a circular dependency?\n if (path.includes(mapping.id)) {\n // We found a circular dependency! Get the bad path of root node identifiers.\n const badPath = [...path, mapping.id];\n\n // Set the formatted path value. [undefined, \"a\", \"b\", \"c\", \"a\"] would be formatted as \"a -> b -> c -> a\".\n badPathFormatted = badPath.filter((element) => !!element).join(\" => \");\n\n // No need to continue, we found a circular dependency.\n return;\n }\n\n for (const ref of mapping.refs) {\n // Find the mapping for the root node with an identifer matching the current ref.\n const subMapping = rootNodeMappings.find(({ id }) => id === ref);\n\n // We may not have a mapping for this ref, which will happen if this ref is for a globally registered subtree.\n if (subMapping) {\n followRefs(subMapping, [...path, mapping.id]);\n }\n }\n };\n\n // Start looking for circular dependencies from the root.\n followRefs(rootNodeMappings.find((mapping) => typeof mapping.id === \"undefined\")!);\n\n return badPathFormatted;\n}\n\n/**\n * Validate an object that we expect to be a node definition.\n * @param definition An object that we expect to be a node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateNode(definition: any, depth: number): void {\n // Every node must be valid object and have a non-empty 'type' string property.\n if (typeof definition !== \"object\" || typeof definition.type !== \"string\" || definition.type.length === 0) {\n throw new Error(\n `node definition is not an object or 'type' property is not a non-empty string at depth '${depth}'`\n );\n }\n\n // How we validate this node definition will depend on its type.\n switch (definition.type) {\n case \"action\":\n validateActionNode(definition, depth);\n break;\n\n case \"condition\":\n validateConditionNode(definition, depth);\n break;\n\n case \"wait\":\n validateWaitNode(definition, depth);\n break;\n\n case \"branch\":\n validateBranchNode(definition, depth);\n break;\n\n case \"root\":\n validateRootNode(definition, depth);\n break;\n\n case \"success\":\n validateSuccessNode(definition, depth);\n break;\n\n case \"fail\":\n validateFailNode(definition, depth);\n break;\n\n case \"flip\":\n validateFlipNode(definition, depth);\n break;\n\n case \"repeat\":\n validateRepeatNode(definition, depth);\n break;\n\n case \"retry\":\n validateRetryNode(definition, depth);\n break;\n\n case \"sequence\":\n validateSequenceNode(definition, depth);\n break;\n\n case \"selector\":\n validateSelectorNode(definition, depth);\n break;\n\n case \"parallel\":\n validateParallelNode(definition, depth);\n break;\n\n default:\n throw new Error(`unexpected node type of '${definition.type}' at depth '${depth}'`);\n }\n}\n\n/**\n * Validate any attributes for a given node definition.\n * @param definition The node definition.\n * @param depth The depth of the node in the behaviour tree definition.\n */\nfunction validateNodeAttributes(definition: any, depth: number): void {\n // Validate each of the attribute types for this node.\n [\"while\", \"until\", \"entry\", \"exit\", \"step\"].forEach((attributeName) => {\n // Attempt to grab the definition for the current attribute from the node definition.\n const attributeDefinition = definition[attributeName];\n\n // All node attributes are optional, so there is nothing to do if the current attribute is not defined.\n if (typeof attributeDefinition === \"undefined\") {\n return;\n }\n\n // The attribute definition must be an object.\n if (typeof attributeDefinition !== \"object\") {\n throw new Error(\n `expected attribute '${attributeName}' to be an object for '${definition.type}' node at depth '${depth}'`\n );\n }\n\n // The 'call' property must be defined for any attribute definition.\n if (typeof attributeDefinition.call !== \"string\" || attributeDefinition.call.length === 0) {\n throw new Error(\n `expected 'call' property for attribute '${attributeName}' to be a non-empty string for '${definition.type}' node at depth '${depth}'`\n );\n }\n\n // If any node attribute arguments have been defined then they must have been defined in an array.\n if (typeof attributeDefinition.args !== \"undefined\" && !Array.isArray(attributeDefinition.args)) {\n throw new Error(\n `expected 'args' property for attribute '${attributeName}' to be an array for '${definition.type}' node at depth '${depth}'`\n );\n }\n });\n}\n\n/**\n * Validate an object that we expect to be a root node definition.\n * @param definition An object that we expect to be a root node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateRootNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"root\") {\n throw new Error(\"expected node type of 'root' for root node\");\n }\n\n // A root node cannot be the child of another node.\n if (depth > 0) {\n throw new Error(\"a root node cannot be the child of another node\");\n }\n\n // Check that, if the root node 'id' property is defined, it is a non-empty string.\n if (typeof definition.id !== \"undefined\" && (typeof definition.id !== \"string\" || definition.id.length === 0)) {\n throw new Error(\"expected non-empty string for 'id' property if defined for root node\");\n }\n\n // A root node is a decorator node, so must have a child node defined.\n if (typeof definition.child === \"undefined\") {\n throw new Error(\"expected property 'child' to be defined for root node\");\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n\n // Validate the child node of this decorator node.\n validateNode(definition.child, depth + 1);\n}\n\n/**\n * Validate an object that we expect to be a success node definition.\n * @param definition An object that we expect to be a success node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateSuccessNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"success\") {\n throw new Error(`expected node type of 'success' for success node at depth '${depth}'`);\n }\n\n // A success node is a decorator node, so must have a child node defined.\n if (typeof definition.child === \"undefined\") {\n throw new Error(`expected property 'child' to be defined for success node at depth '${depth}'`);\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n\n // Validate the child node of this decorator node.\n validateNode(definition.child, depth + 1);\n}\n\n/**\n * Validate an object that we expect to be a fail node definition.\n * @param definition An object that we expect to be a fail node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateFailNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"fail\") {\n throw new Error(`expected node type of 'fail' for fail node at depth '${depth}'`);\n }\n\n // A fail node is a decorator node, so must have a child node defined.\n if (typeof definition.child === \"undefined\") {\n throw new Error(`expected property 'child' to be defined for fail node at depth '${depth}'`);\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n\n // Validate the child node of this decorator node.\n validateNode(definition.child, depth + 1);\n}\n\n/**\n * Validate an object that we expect to be a flip node definition.\n * @param definition An object that we expect to be a flip node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateFlipNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"flip\") {\n throw new Error(`expected node type of 'flip' for flip node at depth '${depth}'`);\n }\n\n // A flip node is a decorator node, so must have a child node defined.\n if (typeof definition.child === \"undefined\") {\n throw new Error(`expected property 'child' to be defined for flip node at depth '${depth}'`);\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n\n // Validate the child node of this decorator node.\n validateNode(definition.child, depth + 1);\n}\n\n/**\n * Validate an object that we expect to be a repeat node definition.\n * @param definition An object that we expect to be a repeat node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateRepeatNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"repeat\") {\n throw new Error(`expected node type of 'repeat' for repeat node at depth '${depth}'`);\n }\n\n // A repeat node is a decorator node, so must have a child node defined.\n if (typeof definition.child === \"undefined\") {\n throw new Error(`expected property 'child' to be defined for repeat node at depth '${depth}'`);\n }\n\n // Check whether an 'iterations' property has been defined, it may not have been if this node is to repeat indefinitely.\n if (typeof definition.iterations !== \"undefined\") {\n if (Array.isArray(definition.iterations)) {\n // Check whether any elements of the array are not integer values.\n const containsNonInteger = !!definition.iterations.find((value: unknown) => !isInteger(value));\n\n // If the 'iterations' property is an array then it MUST contain two integer values.\n if (definition.iterations.length !== 2 || containsNonInteger) {\n throw new Error(\n `expected array containing two integer values for 'iterations' property if defined for repeat node at depth '${depth}'`\n );\n }\n } else if (!isInteger(definition.iterations)) {\n throw new Error(\n `expected integer value or array containing two integer values for 'iterations' property if defined for repeat node at depth '${depth}'`\n );\n }\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n\n // Validate the child node of this decorator node.\n validateNode(definition.child, depth + 1);\n}\n\n/**\n * Validate an object that we expect to be a retry node definition.\n * @param definition An object that we expect to be a retry node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateRetryNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"retry\") {\n throw new Error(`expected node type of 'retry' for retry node at depth '${depth}'`);\n }\n\n // A retry node is a decorator node, so must have a child node defined.\n if (typeof definition.child === \"undefined\") {\n throw new Error(`expected property 'child' to be defined for retry node at depth '${depth}'`);\n }\n\n // Check whether an 'attempts' property has been defined, it may not have been if this node is to retry indefinitely.\n if (typeof definition.attempts !== \"undefined\") {\n if (Array.isArray(definition.attempts)) {\n // Check whether any elements of the array are not integer values.\n const containsNonInteger = !!definition.attempts.find((value: unknown) => !isInteger(value));\n\n // If the 'attempts' property is an array then it MUST contain two integer values.\n if (definition.attempts.length !== 2 || containsNonInteger) {\n throw new Error(\n `expected array containing two integer values for 'attempts' property if defined for retry node at depth '${depth}'`\n );\n }\n } else if (!isInteger(definition.attempts)) {\n throw new Error(\n `expected integer value or array containing two integer values for 'attempts' property if defined for retry node at depth '${depth}'`\n );\n }\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n\n // Validate the child node of this decorator node.\n validateNode(definition.child, depth + 1);\n}\n\n/**\n * Validate an object that we expect to be a branch node definition.\n * @param definition An object that we expect to be a branch node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateBranchNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"branch\") {\n throw new Error(`expected node type of 'branch' for branch node at depth '${depth}'`);\n }\n\n // Check that the branch node 'ref' property is defined and is a non-empty string.\n if (typeof definition.ref !== \"string\" || definition.ref.length === 0) {\n throw new Error(`expected non-empty string for 'ref' property for branch node at depth '${depth}'`);\n }\n\n // It is invalid to define guard attributes for a branch node as they should be defined on the referenced root node.\n [\"while\", \"until\"].forEach((attributeName) => {\n if (typeof definition[attributeName] !== \"undefined\") {\n throw new Error(\n `guards should not be defined for branch nodes but guard '${attributeName}' was defined for branch node at depth '${depth}'`\n );\n }\n });\n\n // It is invalid to define callback attributes for a branch node as they should be defined on the referenced root node.\n [\"entry\", \"exit\", \"step\"].forEach((attributeName) => {\n if (typeof definition[attributeName] !== \"undefined\") {\n throw new Error(\n `callbacks should not be defined for branch nodes but callback '${attributeName}' was defined for branch node at depth '${depth}'`\n );\n }\n });\n}\n\n/**\n * Validate an object that we expect to be a action node definition.\n * @param definition An object that we expect to be a action node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateActionNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"action\") {\n throw new Error(`expected node type of 'action' for action node at depth '${depth}'`);\n }\n\n // The 'call' property must be defined for a action node definition.\n if (typeof definition.call !== \"string\" || definition.call.length === 0) {\n throw new Error(`expected non-empty string for 'call' property of action node at depth '${depth}'`);\n }\n\n // If any action function arguments have been defined then they must have been defined in an array.\n if (typeof definition.args !== \"undefined\" && !Array.isArray(definition.args)) {\n throw new Error(`expected array for 'args' property if defined for action node at depth '${depth}'`);\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n}\n\n/**\n * Validate an object that we expect to be a condition node definition.\n * @param definition An object that we expect to be a condition node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateConditionNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"condition\") {\n throw new Error(`expected node type of 'condition' for condition node at depth '${depth}'`);\n }\n\n // The 'call' property must be defined for a condition node definition.\n if (typeof definition.call !== \"string\" || definition.call.length === 0) {\n throw new Error(`expected non-empty string for 'call' property of condition node at depth '${depth}'`);\n }\n\n // If any condition function arguments have been defined then they must have been defined in an array.\n if (typeof definition.args !== \"undefined\" && !Array.isArray(definition.args)) {\n throw new Error(`expected array for 'args' property if defined for condition node at depth '${depth}'`);\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n}\n\n/**\n * Validate an object that we expect to be a wait node definition.\n * @param definition An object that we expect to be a wait node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateWaitNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"wait\") {\n throw new Error(`expected node type of 'wait' for wait node at depth '${depth}'`);\n }\n\n // Check whether a 'duration' property has been defined, it may not have been if this node is to wait indefinitely.\n if (typeof definition.duration !== \"undefined\") {\n if (Array.isArray(definition.duration)) {\n // Check whether any elements of the array are not integer values.\n const containsNonInteger = !!definition.duration.find((value: unknown) => !isInteger(value));\n\n // If the 'duration' property is an array then it MUST contain two integer values.\n if (definition.duration.length !== 2 || containsNonInteger) {\n throw new Error(\n `expected array containing two integer values for 'duration' property if defined for wait node at depth '${depth}'`\n );\n }\n } else if (!isInteger(definition.duration)) {\n throw new Error(\n `expected integer value or array containing two integer values for 'duration' property if defined for wait node at depth '${depth}'`\n );\n }\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n}\n\n/**\n * Validate an object that we expect to be a sequence node definition.\n * @param definition An object that we expect to be a sequence node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateSequenceNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"sequence\") {\n throw new Error(`expected node type of 'sequence' for sequence node at depth '${depth}'`);\n }\n\n // A sequence node is a composite node, so must have a children nodes array defined.\n if (!Array.isArray(definition.children) || definition.children.length === 0) {\n throw new Error(`expected non-empty 'children' array to be defined for sequence node at depth '${depth}'`);\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n\n // Validate the child nodes of this composite node.\n definition.children.forEach((child: any) => validateNode(child, depth + 1));\n}\n\n/**\n * Validate an object that we expect to be a selector node definition.\n * @param definition An object that we expect to be a selector node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateSelectorNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"selector\") {\n throw new Error(`expected node type of 'selector' for selector node at depth '${depth}'`);\n }\n\n // A selector node is a composite node, so must have a children nodes array defined.\n if (!Array.isArray(definition.children) || definition.children.length === 0) {\n throw new Error(`expected non-empty 'children' array to be defined for selector node at depth '${depth}'`);\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n\n // Validate the child nodes of this composite node.\n definition.children.forEach((child: any) => validateNode(child, depth + 1));\n}\n\n/**\n * Validate an object that we expect to be a parallel node definition.\n * @param definition An object that we expect to be a parallel node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateParallelNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"parallel\") {\n throw new Error(`expected node type of 'parallel' for parallel node at depth '${depth}'`);\n }\n\n // A parallel node is a composite node, so must have a children nodes array defined.\n if (!Array.isArray(definition.children) || definition.children.length === 0) {\n throw new Error(`expected non-empty 'children' array to be defined for parallel node at depth '${depth}'`);\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n\n // Validate the child nodes of this composite node.\n definition.children.forEach((child: any) => validateNode(child, depth + 1));\n}\n", "import Node from \"../../nodes/Node\";\n\n/**\n * An exception thrown when evaluating node guard path conditions and a conditions fails.\n */\nexport default class GuardUnsatisifedException extends Error {\n /**\n * @param source The node at which a guard condition failed.\n */\n constructor(private source: Node) {\n super(\"A guard path condition has failed\");\n }\n\n /**\n * Gets whether the specified node is the node at which a guard condition failed.\n * @param node The node to check against the source node.\n * @returns Whether the specified node is the node at which a guard condition failed.\n */\n isSourceNode = (node: Node) => node === this.source;\n}\n", "import { Agent } from \"../../Agent\";\nimport Guard from \"./Guard\";\nimport Node from \"../../nodes/Node\";\nimport GuardUnsatisifedException from \"./GuardUnsatisifedException\";\n\nexport type GuardPathPart = {\n node: Node;\n guards: Guard[];\n};\n\n/**\n * Represents a path of node guards along a root-to-leaf tree path.\n */\nexport default class GuardPath {\n /**\n * @param nodes An array of objects defining a node instance -> guard link, ordered by node depth.\n */\n constructor(private nodes: GuardPathPart[]) {}\n\n /**\n * Evaluate guard conditions for all guards in the tree path, moving outwards from the root.\n * @param agent The agent, required for guard evaluation.\n * @returns An evaluation results object.\n */\n evaluate = (agent: Agent) => {\n // We need to evaluate guard conditions for nodes up the tree, moving outwards from the root.\n for (const details of this.nodes) {\n // There can be multiple guards per node.\n for (const guard of details.guards) {\n // Check whether the guard condition passes, and throw an exception if not.\n if (!guard.isSatisfied(agent)) {\n throw new GuardUnsatisifedException(details.node);\n }\n }\n }\n };\n}\n", "import { Agent } from \"../Agent\";\nimport Attribute from \"../attributes/Attribute\";\nimport Entry from \"../attributes/callbacks/Entry\";\nimport Exit from \"../attributes/callbacks/Exit\";\nimport Step from \"../attributes/callbacks/Step\";\nimport Guard from \"../attributes/guards/Guard\";\nimport GuardPath from \"../attributes/guards/GuardPath\";\nimport GuardUnsatisifedException from \"../attributes/guards/GuardUnsatisifedException\";\nimport { BehaviourTreeOptions } from \"../BehaviourTreeOptions\";\nimport { AnyArgument } from \"../RootAstNodesBuilder\";\nimport State, { AnyState } from \"../State\";\nimport Leaf from \"./leaf/Leaf\";\n\n/**\n * A base node.\n */\nexport default abstract class Node {\n /**\n * The node uid.\n */\n private readonly uid: string = createNodeUid();\n /**\n * The node state.\n */\n private state: AnyState = State.READY;\n /**\n * The guard path to evaluate as part of a node update.\n */\n private guardPath: GuardPath | undefined;\n\n /**\n * @param type The node type.\n * @param attributes The node attributes.\n * @param args The node argument definitions.\n */\n constructor(private type: string, private attributes: Attribute[], private args: AnyArgument[]) {}\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected abstract onUpdate(agent: Agent, options: BehaviourTreeOptions): void;\n\n /**\n * Gets the name of the node.\n */\n public abstract getName(): string;\n\n /**\n * Gets whether this node is a leaf node.\n */\n public abstract isLeafNode: () => this is Leaf;\n\n /**\n * Gets/Sets the state of the node.\n */\n getState = (): AnyState => this.state;\n setState = (value: AnyState): void => {\n this.state = value;\n };\n\n /**\n * Gets the unique id of the node.\n */\n getUid = () => this.uid;\n\n /**\n * Gets the type of the node.\n */\n getType = () => this.type;\n\n /**\n * Gets the node attributes.\n */\n getAttributes = () => this.attributes;\n\n /**\n * Gets the node arguments.\n */\n getArguments = () => this.args;\n\n /**\n * Gets the node attribute with the specified type, or null if it does not exist.\n */\n getAttribute(type: \"entry\" | \"ENTRY\"): Entry;\n getAttribute(type: \"exit\" | \"EXIT\"): Exit;\n getAttribute(type: \"step\" | \"STEP\"): Step;\n getAttribute(type: string): Attribute {\n return (\n this.getAttributes().filter((decorator) => decorator.getType().toUpperCase() === type.toUpperCase())[0] ||\n null\n );\n }\n\n /**\n * Gets the node attributes.\n */\n getGuardAttributes = (): Guard[] => this.getAttributes().filter((decorator) => decorator.isGuard()) as Guard[];\n\n /**\n * Sets the guard path to evaluate as part of a node update.\n */\n setGuardPath = (value: GuardPath) => (this.guardPath = value);\n\n /**\n * Gets whether a guard path is assigned to this node.\n */\n hasGuardPath = () => !!this.guardPath;\n\n /**\n * Gets whether this node is in the specified state.\n * @param value The value to compare to the node state.\n */\n public is(value: AnyState): boolean {\n return this.state === value;\n }\n\n /**\n * Reset the state of the node.\n */\n public reset(): void {\n this.setState(State.READY);\n }\n\n /**\n * Abort the running of this node.\n * @param agent The agent.\n */\n public abort(agent: Agent): void {\n // There is nothing to do if this node is not in the running state.\n if (!this.is(State.RUNNING)) {\n return;\n }\n\n // Reset the state of this node.\n this.reset();\n\n this.getAttribute(\"exit\")?.callAgentFunction(agent, false, true);\n }\n\n /**\n * Update the node.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n * @returns The result of the update.\n */\n public update(agent: Agent, options: BehaviourTreeOptions): void {\n // If this node is already in a 'SUCCEEDED' or 'FAILED' state then there is nothing to do.\n if (this.is(State.SUCCEEDED) || this.is(State.FAILED)) {\n return;\n }\n\n try {\n // Evaluate all of the guard path conditions for the current tree path.\n this.guardPath!.evaluate(agent);\n\n // If this node is in the READY state then call the ENTRY for this node if it exists.\n if (this.is(State.READY)) {\n this.getAttribute(\"entry\")?.callAgentFunction(agent);\n }\n\n this.getAttribute(\"step\")?.callAgentFunction(agent);\n\n // Do the actual update.\n this.onUpdate(agent, options);\n\n // If this node is now in a 'SUCCEEDED' or 'FAILED' state then call the EXIT for this node if it exists.\n if (this.is(State.SUCCEEDED) || this.is(State.FAILED)) {\n this.getAttribute(\"exit\")?.callAgentFunction(agent, this.is(State.SUCCEEDED), false);\n }\n } catch (error) {\n // If the error is a GuardUnsatisfiedException then we need to determine if this node is the source.\n if (error instanceof GuardUnsatisifedException && error.isSourceNode(this)) {\n // Abort the current node.\n this.abort(agent);\n\n // Any node that is the source of an abort will be a failed node.\n this.setState(State.FAILED);\n } else {\n throw error;\n }\n }\n }\n}\n\n/**\n * Create a randomly generated node uid.\n * @returns A randomly generated node uid.\n */\nfunction createNodeUid(): string {\n var S4 = function () {\n return (((1 + Math.random()) * 0x10000) | 0).toString(16).substring(1);\n };\n return S4() + S4() + \"-\" + S4() + \"-\" + S4() + \"-\" + S4() + \"-\" + S4() + S4() + S4();\n}\n", "import Node from \"../Node\";\n\n/**\n * A leaf node.\n */\nexport default abstract class Leaf extends Node {\n /**\n * Gets whether this node is a leaf node.\n */\n isLeafNode = () => true;\n}\n", "import { ActionResult, Agent, ExitFunctionArg, FunctionArg, GlobalFunction } from \"./Agent\";\nimport { AnyArgument, RootAstNode } from \"./RootAstNodesBuilder\";\n\n// Exit callbacks receive their own special type of argument.\n// There's probably stricter ways to represent this but it feels overly complex right now.\ntype ExitResultArg = { value: ExitFunctionArg };\nexport type AnyExitArgument = AnyArgument | ExitResultArg;\n\nexport type InvokerFunction = (args: AnyExitArgument[]) => ActionResult;\n\n/**\n * A singleton used to store and lookup registered functions and subtrees.\n */\nexport default class Lookup {\n /**\n * The object holding any registered functions keyed on function name.\n */\n private static functionTable: { [key: string]: GlobalFunction } = {};\n /**\n * The object holding any registered sub-trees keyed on tree name.\n */\n private static subtreeTable: { [key: string]: RootAstNode } = {};\n\n /**\n * Gets the function with the specified name.\n * @param name The name of the function.\n * @returns The function with the specified name.\n */\n public static getFunc(name: string): GlobalFunction {\n return this.functionTable[name];\n }\n\n /**\n * Sets the function with the specified name for later lookup.\n * @param name The name of the function.\n * @param func The function.\n */\n public static setFunc(name: string, func: GlobalFunction): void {\n this.functionTable[name] = func;\n }\n\n /**\n * Gets the function invoker for the specified agent and function name.\n * If a function with the specified name exists on the agent object then it will\n * be returned, otherwise we will then check the registered functions for a match.\n * @param agent The agent instance that this behaviour tree is modelling behaviour for.\n * @param name The function name.\n * @returns The function invoker for the specified agent and function name.\n */\n static getFuncInvoker(agent: Agent, name: string): InvokerFunction | null {\n // Check whether the agent contains the specified function.\n const foundOnAgent = agent[name];\n if (foundOnAgent && typeof foundOnAgent === \"function\") {\n return (args: AnyExitArgument[]): boolean | ActionResult =>\n foundOnAgent.apply(\n agent,\n args.map((arg) => arg.value)\n );\n }\n\n // The agent does not contain the specified function but it may have been registered at some point.\n if (this.functionTable[name] && typeof this.functionTable[name] === \"function\") {\n return (args: AnyExitArgument[]) => this.functionTable[name](agent, ...args.map((arg) => arg.value));\n }\n\n // We have no function to invoke.\n return null;\n }\n\n /**\n * Gets the subtree with the specified name.\n * @param name The name of the subtree.\n * @returns The subtree with the specified name.\n */\n static getSubtree(name: string): RootAstNode {\n return this.subtreeTable[name];\n }\n\n /**\n * Sets the subtree with the specified name for later lookup.\n * @param name The name of the subtree.\n * @param subtree The subtree.\n */\n static setSubtree(name: string, subtree: RootAstNode) {\n this.subtreeTable[name] = subtree;\n }\n\n /**\n * Removes the registered function or subtree with the specified name.\n * @param name The name of the registered function or subtree.\n */\n static remove(name: string) {\n delete this.functionTable[name];\n delete this.subtreeTable[name];\n }\n\n /**\n * Remove all registered functions and subtrees.\n */\n static empty() {\n this.functionTable = {};\n this.subtreeTable = {};\n }\n}\n", "import Leaf from \"./Leaf\";\nimport State, { CompleteState } from \"../../State\";\nimport Lookup from \"../../Lookup\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { AnyArgument } from \"../../RootAstNodesBuilder\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * An Action leaf node.\n * This represents an immediate or ongoing state of behaviour.\n */\nexport default class Action extends Leaf {\n /**\n * @param attributes The node attributes.\n * @param actionName The action name.\n * @param actionArguments The array of action argument definitions.\n */\n constructor(attributes: Attribute[], private actionName: string, private actionArguments: AnyArgument[]) {\n super(\"action\", attributes, actionArguments);\n }\n\n /**\n * Whether there is a pending update promise.\n */\n private isUsingUpdatePromise = false;\n\n /**\n * The finished state result of an update promise.\n */\n private updatePromiseStateResult: CompleteState | null = null;\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // If the result of this action depends on an update promise then there is nothing to do until\n // it resolves, unless there has been a value set as a result of the update promise resolving.\n if (this.isUsingUpdatePromise) {\n // Check whether the update promise has resolved with a state value.\n if (this.updatePromiseStateResult) {\n // Set the state of this node to match the state returned by the promise.\n this.setState(this.updatePromiseStateResult);\n }\n\n return;\n }\n\n // Attempt to get the invoker for the action function.\n const actionFuncInvoker = Lookup.getFuncInvoker(agent, this.actionName);\n\n // The action function should be defined.\n if (actionFuncInvoker === null) {\n throw new Error(\n `cannot update action node as the action '${this.actionName}' function is not defined on the agent and has not been registered`\n );\n }\n\n // Call the action function, the result of which may be:\n // - The finished state of this action node.\n // - A promise to return a finished node state.\n // - Undefined if the node should remain in the running state.\n const updateResult = actionFuncInvoker(this.actionArguments) as CompleteState | Promise;\n\n if (updateResult instanceof Promise) {\n updateResult.then(\n (result) => {\n // If 'isUpdatePromisePending' is null then the promise was cleared as it was resolving, probably via an abort of reset.\n if (!this.isUsingUpdatePromise) {\n return;\n }\n\n // Check to make sure the result is a valid finished state.\n if (result !== State.SUCCEEDED && result !== State.FAILED) {\n throw new Error(\n \"action node promise resolved with an invalid value, expected a State.SUCCEEDED or State.FAILED value to be returned\"\n );\n }\n\n // Set pending update promise state result to be processed on next update.\n this.updatePromiseStateResult = result;\n },\n (reason) => {\n // If 'isUpdatePromisePending' is null then the promise was cleared as it was resolving, probably via an abort of reset.\n if (!this.isUsingUpdatePromise) {\n return;\n }\n\n // Just throw whatever was returned as the rejection argument.\n throw new Error(reason);\n }\n );\n\n // This node will be in the 'RUNNING' state until the update promise resolves.\n this.setState(State.RUNNING);\n\n // We are now waiting for the promise returned by the use to resolve before we know what state this node is in.\n this.isUsingUpdatePromise = true;\n } else {\n // Validate the returned value.\n this.validateUpdateResult(updateResult);\n\n // Set the state of this node, this may be undefined, which just means that the node is still in the 'RUNNING' state.\n this.setState(updateResult || State.RUNNING);\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => this.actionName;\n\n /**\n * Reset the state of the node.\n */\n reset = () => {\n // Reset the state of this node.\n this.setState(State.READY);\n\n // There is no longer an update promise that we care about.\n this.isUsingUpdatePromise = false;\n this.updatePromiseStateResult = null;\n };\n\n /**\n * Validate the result of an update function call.\n * @param result The result of an update function call.\n */\n private validateUpdateResult = (result: CompleteState | boolean) => {\n switch (result) {\n case State.SUCCEEDED:\n case State.FAILED:\n case undefined:\n return;\n default:\n throw new Error(\n `action '${this.actionName}' 'onUpdate' returned an invalid response, expected an optional State.SUCCEEDED or State.FAILED value to be returned`\n );\n }\n };\n}\n", "import Leaf from \"./Leaf\";\nimport State from \"../../State\";\nimport Lookup from \"../../Lookup\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { AnyArgument } from \"../../RootAstNodesBuilder\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A Condition leaf node.\n * This will succeed or fail immediately based on an agent predicate, without moving to the 'RUNNING' state.\n */\nexport default class Condition extends Leaf {\n /**\n * @param attributes The node attributes.\n * @param conditionName The name of the condition function.\n * @param conditionArguments The array of condition argument definitions.\n */\n constructor(attributes: Attribute[], private conditionName: string, private conditionArguments: AnyArgument[]) {\n super(\"condition\", attributes, conditionArguments);\n }\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // Attempt to get the invoker for the condition function.\n const conditionFuncInvoker = Lookup.getFuncInvoker(agent, this.conditionName);\n\n // The condition function should be defined.\n if (conditionFuncInvoker === null) {\n throw new Error(\n `cannot update condition node as the condition '${this.conditionName}' function is not defined on the agent and has not been registered`\n );\n }\n\n // Call the condition function to determine the state of this node.\n this.setState(!!conditionFuncInvoker(this.conditionArguments) ? State.SUCCEEDED : State.FAILED);\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => this.conditionName;\n}\n", "import Leaf from \"./Leaf\";\nimport State from \"../../State\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { Agent } from \"../../Agent\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A WAIT node.\n * The state of this node will change to SUCCEEDED after a duration of time\n */\nexport default class Wait extends Leaf {\n /**\n * @param attributes The node attributes.\n * @param duration The duration that this node will wait to succeed in milliseconds.\n * @param durationMin The minimum possible duration in milliseconds that this node will wait to succeed.\n * @param durationMax The maximum possible duration in milliseconds that this node will wait to succeed.\n */\n constructor(\n attributes: Attribute[],\n private duration: number | null,\n private durationMin: number | null,\n private durationMax: number | null\n ) {\n super(\"wait\", attributes, []);\n }\n\n /**\n * The time in milliseconds at which this node was first updated.\n */\n private initialUpdateTime: number = 0;\n\n /**\n * The total duration in milliseconds that this node will be waiting for.\n */\n private totalDuration: number | null = null;\n\n /**\n * The duration in milliseconds that this node has been waiting for.\n */\n private waitedDuration: number = 0;\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // If this node is in the READY state then we need to set the initial update time.\n if (this.is(State.READY)) {\n // Set the initial update time.\n this.initialUpdateTime = new Date().getTime();\n\n // Set the initial waited duration.\n this.waitedDuration = 0;\n\n // Are we dealing with an explicit duration or will we be randomly picking a duration between the min and max duration.\n if (this.duration !== null) {\n this.totalDuration = this.duration;\n } else if (this.durationMin !== null && this.durationMax !== null) {\n // We will be picking a random duration between a min and max duration, if the optional 'random' behaviour tree\n // function option is defined then we will be using that, otherwise we will fall back to using Math.random.\n const random = typeof options.random === \"function\" ? options.random : Math.random;\n\n // Pick a random duration between a min and max duration.\n this.totalDuration = Math.floor(\n random() * (this.durationMax - this.durationMin + 1) + this.durationMin\n );\n } else {\n this.totalDuration = null;\n }\n\n // The node is now running until we finish waiting.\n this.setState(State.RUNNING);\n }\n\n // If we have no total duration then this wait node will wait indefinitely until it is aborted.\n if (this.totalDuration === null) {\n return;\n }\n\n // If we have a 'getDeltaTime' function defined as part of our options then we will use it to figure out how long we have waited for.\n if (typeof options.getDeltaTime === \"function\") {\n // Get the delta time.\n const deltaTime = options.getDeltaTime();\n\n // Our delta time must be a valid number and cannot be NaN.\n if (typeof deltaTime !== \"number\" || isNaN(deltaTime)) {\n throw new Error(\"The delta time must be a valid number and not NaN.\");\n }\n\n // Update the amount of time that this node has been waiting for based on the delta time.\n this.waitedDuration += deltaTime * 1000;\n } else {\n // We are not using a delta time, so we will just work out hom much time has passed since the first update.\n this.waitedDuration = new Date().getTime() - this.initialUpdateTime;\n }\n\n // Have we waited long enough?\n if (this.waitedDuration >= this.totalDuration) {\n // We have finished waiting!\n this.setState(State.SUCCEEDED);\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => {\n if (this.duration !== null) {\n return `WAIT ${this.duration}ms`;\n } else if (this.durationMin !== null && this.durationMax !== null) {\n return `WAIT ${this.durationMin}ms-${this.durationMax}ms`;\n } else {\n return \"WAIT\";\n }\n };\n}\n", "import Node from \"../Node\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\n\n/**\n * A decorator node that wraps a single child node.\n */\nexport default abstract class Decorator extends Node {\n /**\n * @param type The node type.\n * @param attributes The node attributes.\n * @param child The child node.\n */\n constructor(type: string, attributes: Attribute[], protected child: Node) {\n super(type, attributes, []);\n }\n\n /**\n * Gets whether this node is a leaf node.\n */\n isLeafNode = () => false;\n\n /**\n * Gets the children of this node.\n */\n getChildren = () => [this.child];\n\n /**\n * Reset the state of the node.\n */\n reset = () => {\n // Reset the state of this node.\n this.setState(State.READY);\n\n // Reset the state of the child node.\n this.child.reset();\n };\n\n /**\n * Abort the running of this node.\n * @param agent The agent.\n */\n abort = (agent: Agent) => {\n // There is nothing to do if this node is not in the running state.\n if (!this.is(State.RUNNING)) {\n return;\n }\n\n // Abort the child node.\n this.child.abort(agent);\n\n // Reset the state of this node.\n this.reset();\n\n this.getAttribute(\"exit\")?.callAgentFunction(agent, false, true);\n };\n}\n", "import Node from \"../Node\";\nimport Decorator from \"./Decorator\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A Root node.\n * The root node will have a single child.\n */\nexport default class Root extends Decorator {\n /**\n * @param attributes The node attributes.\n * @param child The child node.\n */\n constructor(attributes: Attribute[], child: Node) {\n super(\"root\", attributes, child);\n }\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // If the child has never been updated or is running then we will need to update it now.\n if (this.child.getState() === State.READY || this.child.getState() === State.RUNNING) {\n // Update the child of this node.\n this.child.update(agent, options);\n }\n\n // The state of the root node is the state of its child.\n this.setState(this.child.getState());\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => \"ROOT\";\n}\n", "import Node from \"../Node\";\nimport Decorator from \"./Decorator\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A REPEAT node.\n * The node has a single child which can have:\n * -- A number of iterations for which to repeat the child node.\n * -- An infinite repeat loop if neither an iteration count or a condition function is defined.\n * The REPEAT node will stop and have a 'FAILED' state if its child is ever in a 'FAILED' state after an update.\n * The REPEAT node will attempt to move on to the next iteration if its child is ever in a 'SUCCEEDED' state.\n */\nexport default class Repeat extends Decorator {\n /**\n * @param attributes The node attributes.\n * @param iterations The number of iterations to repeat the child node.\n * @param iterationsMin The minimum possible number of iterations to repeat the child node.\n * @param iterationsMax The maximum possible number of iterations to repeat the child node.\n * @param child The child node.\n */\n constructor(\n attributes: Attribute[],\n private iterations: number | null,\n private iterationsMin: number | null,\n private iterationsMax: number | null,\n child: Node\n ) {\n super(\"repeat\", attributes, child);\n }\n\n /**\n * The number of target iterations to make.\n */\n private targetIterationCount: number | null = null;\n\n /**\n * The current iteration count.\n */\n private currentIterationCount: number = 0;\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // If this node is in the READY state then we need to reset the child and the target iteration count.\n if (this.is(State.READY)) {\n // Reset the child node.\n this.child.reset();\n\n // Reset the current iteration count.\n this.currentIterationCount = 0;\n\n // Set the target iteration count.\n this.setTargetIterationCount(options);\n }\n\n // Do a check to see if we can iterate. If we can then this node will move into the 'RUNNING' state.\n // If we cannot iterate then we have hit our target iteration count, which means that the node has succeeded.\n if (this.canIterate()) {\n // This node is in the running state and can do its initial iteration.\n this.setState(State.RUNNING);\n\n // We may have already completed an iteration, meaning that the child node will be in the SUCCEEDED state.\n // If this is the case then we will have to reset the child node now.\n if (this.child.getState() === State.SUCCEEDED) {\n this.child.reset();\n }\n\n // Update the child of this node.\n this.child.update(agent, options);\n\n // If the child moved into the FAILED state when we updated it then there is nothing left to do and this node has also failed.\n // If it has moved into the SUCCEEDED state then we have completed the current iteration.\n if (this.child.getState() === State.FAILED) {\n // The child has failed, meaning that this node has failed.\n this.setState(State.FAILED);\n\n return;\n } else if (this.child.getState() === State.SUCCEEDED) {\n // We have completed an iteration.\n this.currentIterationCount += 1;\n }\n } else {\n // This node is in the 'SUCCEEDED' state as we cannot iterate any more.\n this.setState(State.SUCCEEDED);\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => {\n if (this.iterations !== null) {\n return `REPEAT ${this.iterations}x`;\n } else if (this.iterationsMin !== null && this.iterationsMax !== null) {\n return `REPEAT ${this.iterationsMin}x-${this.iterationsMax}x`;\n } else {\n return \"REPEAT\";\n }\n };\n\n /**\n * Reset the state of the node.\n */\n reset = () => {\n // Reset the state of this node.\n this.setState(State.READY);\n\n // Reset the current iteration count.\n this.currentIterationCount = 0;\n\n // Reset the child node.\n this.child.reset();\n };\n\n /**\n * Gets whether an iteration can be made.\n * @returns Whether an iteration can be made.\n */\n private canIterate = () => {\n if (this.targetIterationCount !== null) {\n // We can iterate as long as we have not reached our target iteration count.\n return this.currentIterationCount < this.targetIterationCount;\n }\n\n // If neither an iteration count or a condition function were defined then we can iterate indefinitely.\n return true;\n };\n\n /**\n * Sets the target iteration count.\n * @param options The behaviour tree options object.\n */\n private setTargetIterationCount = (options: BehaviourTreeOptions) => {\n // Are we dealing with an explicit iteration count or will we be randomly picking a iteration count between the min and max iteration count.\n if (this.iterations !== null) {\n this.targetIterationCount = this.iterations;\n } else if (this.iterationsMin !== null && this.iterationsMax !== null) {\n // We will be picking a random iteration count between a min and max iteration count, if the optional 'random'\n // behaviour tree function option is defined then we will be using that, otherwise we will fall back to using Math.random.\n const random = typeof options.random === \"function\" ? options.random : Math.random;\n\n // Pick a random iteration count between a min and max iteration count.\n this.targetIterationCount = Math.floor(\n random() * (this.iterationsMax - this.iterationsMin + 1) + this.iterationsMin\n );\n } else {\n this.targetIterationCount = null;\n }\n };\n}\n", "import Node from \"../Node\";\nimport Decorator from \"./Decorator\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A RETRY node.\n * The node has a single child which can have:\n * -- A number of iterations for which to repeat the child node.\n * -- An infinite repeat loop if neither an iteration count or a condition function is defined.\n * The RETRY node will stop and have a 'SUCCEEDED' state if its child is ever in a 'SUCCEEDED' state after an update.\n * The RETRY node will attempt to move on to the next iteration if its child is ever in a 'FAILED' state.\n */\nexport default class Retry extends Decorator {\n /**\n * @param attributes The node attributes.\n * @param attempts The number of attempts to retry the child node.\n * @param attemptsMin The minimum possible number of attempts to retry the child node.\n * @param attemptsMax The maximum possible number of attempts to retry the child node.\n * @param child The child node.\n */\n constructor(\n attributes: Attribute[],\n private attempts: number | null,\n private attemptsMin: number | null,\n private attemptsMax: number | null,\n child: Node\n ) {\n super(\"retry\", attributes, child);\n }\n\n /**\n * The number of target attempts to make.\n */\n private targetAttemptCount: number | null = null;\n\n /**\n * The current attempt count.\n */\n private currentAttemptCount: number = 0;\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // If this node is in the READY state then we need to reset the child and the target attempt count.\n if (this.is(State.READY)) {\n // Reset the child node.\n this.child.reset();\n\n // Reset the current attempt count.\n this.currentAttemptCount = 0;\n\n // Set the target attempt count.\n this.setTargetAttemptCount(options);\n }\n\n // Do a check to see if we can attempt. If we can then this node will move into the 'RUNNING' state.\n // If we cannot attempt then we have hit our target attempt count, which means that the node has succeeded.\n if (this.canAttempt()) {\n // This node is in the running state and can do its initial attempt.\n this.setState(State.RUNNING);\n\n // We may have already completed an attempt, meaning that the child node will be in the FAILED state.\n // If this is the case then we will have to reset the child node now.\n if (this.child.getState() === State.FAILED) {\n this.child.reset();\n }\n\n // Update the child of this node.\n this.child.update(agent, options);\n\n // If the child moved into the SUCCEEDED state when we updated it then there is nothing left to do and this node has also succeeded.\n // If it has moved into the FAILED state then we have completed the current attempt.\n if (this.child.getState() === State.SUCCEEDED) {\n // The child has succeeded, meaning that this node has succeeded.\n this.setState(State.SUCCEEDED);\n\n return;\n } else if (this.child.getState() === State.FAILED) {\n // We have completed an attempt.\n this.currentAttemptCount += 1;\n }\n } else {\n // This node is in the 'FAILED' state as we cannot iterate any more.\n this.setState(State.FAILED);\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => {\n if (this.attempts !== null) {\n return `RETRY ${this.attempts}x`;\n } else if (this.attemptsMin !== null && this.attemptsMax !== null) {\n return `RETRY ${this.attemptsMin}x-${this.attemptsMax}x`;\n } else {\n return \"RETRY\";\n }\n };\n\n /**\n * Reset the state of the node.\n */\n reset = () => {\n // Reset the state of this node.\n this.setState(State.READY);\n\n // Reset the current attempt count.\n this.currentAttemptCount = 0;\n\n // Reset the child node.\n this.child.reset();\n };\n\n /**\n * Gets whether an attempt can be made.\n * @returns Whether an attempt can be made.\n */\n canAttempt = () => {\n if (this.targetAttemptCount !== null) {\n // We can attempt as long as we have not reached our target attempt count.\n return this.currentAttemptCount < this.targetAttemptCount;\n }\n\n // If neither an attempt count or a condition function were defined then we can attempt indefinitely.\n return true;\n };\n\n /**\n * Sets the target attempt count.\n * @param options The behaviour tree options object.\n */\n setTargetAttemptCount = (options: BehaviourTreeOptions) => {\n // Are we dealing with an explicit attempt count or will we be randomly picking an attempt count between the min and max attempt count.\n if (this.attempts !== null) {\n this.targetAttemptCount = this.attempts;\n } else if (this.attemptsMin !== null && this.attemptsMax !== null) {\n // We will be picking a random attempt count between a min and max attempt count, if the optional 'random'\n // behaviour tree function option is defined then we will be using that, otherwise we will fall back to using Math.random.\n const random = typeof options.random === \"function\" ? options.random : Math.random;\n\n // Pick a random attempt count between a min and max attempt count.\n this.targetAttemptCount = Math.floor(\n random() * (this.attemptsMax - this.attemptsMin + 1) + this.attemptsMin\n );\n } else {\n this.targetAttemptCount = null;\n }\n };\n}\n", "import Decorator from \"./Decorator\";\nimport State from \"../../State\";\nimport Node from \"../Node\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A Flip node.\n * This node wraps a single child and will flip the state of the child state.\n */\nexport default class Flip extends Decorator {\n /**\n * @param attributes The node attributes.\n * @param child The child node.\n */\n constructor(attributes: Attribute[], child: Node) {\n super(\"flip\", attributes, child);\n }\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // If the child has never been updated or is running then we will need to update it now.\n if (this.child.getState() === State.READY || this.child.getState() === State.RUNNING) {\n this.child.update(agent, options);\n }\n\n // The state of this node will depend in the state of its child.\n switch (this.child.getState()) {\n case State.RUNNING:\n this.setState(State.RUNNING);\n break;\n\n case State.SUCCEEDED:\n this.setState(State.FAILED);\n break;\n\n case State.FAILED:\n this.setState(State.SUCCEEDED);\n break;\n\n default:\n this.setState(State.READY);\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => \"FLIP\";\n}\n", "import Node from \"../Node\";\nimport Decorator from \"./Decorator\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A Succeed node.\n * This node wraps a single child and will always move to the 'SUCCEEDED' state when the child moves to a 'SUCCEEDED' or 'FAILED' state.\n */\nexport default class Succeed extends Decorator {\n /**\n * @param attributes The node attributes.\n * @param child The child node.\n */\n constructor(attributes: Attribute[], child: Node) {\n super(\"succeed\", attributes, child);\n }\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // If the child has never been updated or is running then we will need to update it now.\n if (this.child.getState() === State.READY || this.child.getState() === State.RUNNING) {\n this.child.update(agent, options);\n }\n\n // The state of this node will depend in the state of its child.\n switch (this.child.getState()) {\n case State.RUNNING:\n this.setState(State.RUNNING);\n break;\n\n case State.SUCCEEDED:\n case State.FAILED:\n this.setState(State.SUCCEEDED);\n break;\n\n default:\n this.setState(State.READY);\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => \"SUCCEED\";\n}\n", "import Node from \"../Node\";\nimport Decorator from \"./Decorator\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A Fail node.\n * This node wraps a single child and will always move to the 'FAILED' state when the child moves to a 'SUCCEEDED' or 'FAILED' state.\n */\nexport default class Fail extends Decorator {\n /**\n * @param attributes The node attributes.\n * @param child The child node.\n */\n constructor(attributes: Attribute[], child: Node) {\n super(\"fail\", attributes, child);\n }\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // If the child has never been updated or is running then we will need to update it now.\n if (this.child.getState() === State.READY || this.child.getState() === State.RUNNING) {\n this.child.update(agent, options);\n }\n\n // The state of this node will depend in the state of its child.\n switch (this.child.getState()) {\n case State.RUNNING:\n this.setState(State.RUNNING);\n break;\n\n case State.SUCCEEDED:\n case State.FAILED:\n this.setState(State.FAILED);\n break;\n\n default:\n this.setState(State.READY);\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => \"FAIL\";\n}\n", "import createLotto from \"lotto-draw\";\n\nimport Node from \"../Node\";\nimport Composite from \"./Composite\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A LOTTO node.\n * A winning child is picked on the initial update of this node, based on ticket weighting.\n * The state of this node will match the state of the winning child.\n */\nexport default class Lotto extends Composite {\n /**\n * @param attributes The node attributes.\n * @param tickets The child node tickets.\n * @param children The child nodes.\n */\n constructor(attributes: Attribute[], private tickets: number[], children: Node[]) {\n super(\"lotto\", attributes, children);\n }\n\n /**\n * The child node selected to be the active one.\n */\n private selectedChild: Node | undefined;\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // If this node is in the READY state then we need to pick a winning child node.\n if (this.is(State.READY)) {\n // Create a lotto draw with which to randomly pick a child node to become the active one.\n const lottoDraw = createLotto({\n // Hook up the optional 'random' behaviour tree function option to the one used by 'lotto-draw'.\n random: options.random,\n // Pass in each child node as a participant in the lotto draw with their respective ticket count.\n participants: this.children.map((child, index) => [child, this.tickets[index] || 1])\n });\n\n // Randomly pick a child based on ticket weighting, this will become the active child for this composite node.\n this.selectedChild = lottoDraw.draw() || undefined;\n }\n\n // If something went wrong and we don't have an active child then we should throw an error.\n if (!this.selectedChild) {\n throw new Error(\"failed to update lotto node as it has no active child\");\n }\n\n // If the selected child has never been updated or is running then we will need to update it now.\n if (this.selectedChild.getState() === State.READY || this.selectedChild.getState() === State.RUNNING) {\n this.selectedChild.update(agent, options);\n }\n\n // The state of the lotto node is the state of its selected child.\n this.setState(this.selectedChild.getState());\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => (this.tickets.length ? `LOTTO [${this.tickets.join(\",\")}]` : \"LOTTO\");\n}\n", "import Node from \"../Node\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\n\n/**\n * A composite node that wraps child nodes.\n */\nexport default abstract class Composite extends Node {\n /**\n * @param type The node type.\n * @param attributes The node attributes.\n * @param children The child nodes.\n */\n constructor(type: string, attributes: Attribute[], protected children: Node[]) {\n super(type, attributes, []);\n }\n\n /**\n * Gets whether this node is a leaf node.\n */\n isLeafNode = () => false;\n\n /**\n * Gets the children of this node.\n */\n getChildren = () => this.children;\n\n /**\n * Reset the state of the node.\n */\n reset = () => {\n // Reset the state of this node.\n this.setState(State.READY);\n\n // Reset the state of any child nodes.\n this.getChildren().forEach((child) => child.reset());\n };\n\n /**\n * Abort the running of this node.\n * @param agent The agent.\n */\n abort = (agent: Agent) => {\n // There is nothing to do if this node is not in the running state.\n if (!this.is(State.RUNNING)) {\n return;\n }\n\n // Abort any child nodes.\n this.getChildren().forEach((child) => child.abort(agent));\n\n // Reset the state of this node.\n this.reset();\n\n this.getAttribute(\"exit\")?.callAgentFunction(agent, false, true);\n };\n}\n", "import Composite from \"./Composite\";\nimport Node from \"../Node\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A SELECTOR node.\n * The child nodes are executed in sequence until one succeeds or all fail.\n */\nexport default class Selector extends Composite {\n /**\n * @param attributes The node attributes.\n * @param children The child nodes.\n */\n constructor(attributes: Attribute[], protected children: Node[]) {\n super(\"selector\", attributes, children);\n }\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // Iterate over all of the children of this node.\n for (const child of this.children) {\n // If the child has never been updated or is running then we will need to update it now.\n if (child.getState() === State.READY || child.getState() === State.RUNNING) {\n // Update the child of this node.\n child.update(agent, options);\n }\n\n // If the current child has a state of 'SUCCEEDED' then this node is also a 'SUCCEEDED' node.\n if (child.getState() === State.SUCCEEDED) {\n // This node is a 'SUCCEEDED' node.\n this.setState(State.SUCCEEDED);\n\n // There is no need to check the rest of the selector nodes.\n return;\n }\n\n // If the current child has a state of 'FAILED' then we should move on to the next child.\n if (child.getState() === State.FAILED) {\n // Find out if the current child is the last one in the selector.\n // If it is then this sequence node has also failed.\n if (this.children.indexOf(child) === this.children.length - 1) {\n // This node is a 'FAILED' node.\n this.setState(State.FAILED);\n\n // There is no need to check the rest of the selector as we have completed it.\n return;\n } else {\n // The child node failed, try the next one.\n continue;\n }\n }\n\n // The node should be in the 'RUNNING' state.\n if (child.getState() === State.RUNNING) {\n // This node is a 'RUNNING' node.\n this.setState(State.RUNNING);\n\n // There is no need to check the rest of the selector as the current child is still running.\n return;\n }\n\n // The child node was not in an expected state.\n throw new Error(\"child node was not in an expected state.\");\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => \"SELECTOR\";\n}\n", "import Composite from \"./Composite\";\nimport Node from \"../Node\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A SEQUENCE node.\n * The child nodes are executed in sequence until one fails or all succeed.\n */\nexport default class Sequence extends Composite {\n /**\n * @param attributes The node attributes.\n * @param children The child nodes.\n */\n constructor(attributes: Attribute[], protected children: Node[]) {\n super(\"sequence\", attributes, children);\n }\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // Iterate over all of the children of this node.\n for (const child of this.children) {\n // If the child has never been updated or is running then we will need to update it now.\n if (child.getState() === State.READY || child.getState() === State.RUNNING) {\n // Update the child of this node.\n child.update(agent, options);\n }\n\n // If the current child has a state of 'SUCCEEDED' then we should move on to the next child.\n if (child.getState() === State.SUCCEEDED) {\n // Find out if the current child is the last one in the sequence.\n // If it is then this sequence node has also succeeded.\n if (this.children.indexOf(child) === this.children.length - 1) {\n // This node is a 'SUCCEEDED' node.\n this.setState(State.SUCCEEDED);\n\n // There is no need to check the rest of the sequence as we have completed it.\n return;\n } else {\n // The child node succeeded, but we have not finished the sequence yet.\n continue;\n }\n }\n\n // If the current child has a state of 'FAILED' then this node is also a 'FAILED' node.\n if (child.getState() === State.FAILED) {\n // This node is a 'FAILED' node.\n this.setState(State.FAILED);\n\n // There is no need to check the rest of the sequence.\n return;\n }\n\n // The node should be in the 'RUNNING' state.\n if (child.getState() === State.RUNNING) {\n // This node is a 'RUNNING' node.\n this.setState(State.RUNNING);\n\n // There is no need to check the rest of the sequence as the current child is still running.\n return;\n }\n\n // The child node was not in an expected state.\n throw new Error(\"child node was not in an expected state.\");\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => \"SEQUENCE\";\n}\n", "import Composite from \"./Composite\";\nimport State from \"../../State\";\nimport Node from \"../Node\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A PARALLEL node.\n * The child nodes are executed concurrently until one fails or all succeed.\n */\nexport default class Parallel extends Composite {\n /**\n * @param attributes The node attributes.\n * @param children The child nodes.\n */\n constructor(attributes: Attribute[], children: Node[]) {\n super(\"parallel\", attributes, children);\n }\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // Keep a count of the number of succeeded child nodes.\n let succeededCount = 0;\n\n let hasChildFailed = false;\n\n // Iterate over all of the children of this node.\n for (const child of this.children) {\n // If the child has never been updated or is running then we will need to update it now.\n if (child.getState() === State.READY || child.getState() === State.RUNNING) {\n // Update the child of this node.\n child.update(agent, options);\n }\n\n // If the current child has a state of 'SUCCEEDED' then we should move on to the next child.\n if (child.getState() === State.SUCCEEDED) {\n // The child node has succeeded, keep track of this to determine if all children have.\n succeededCount++;\n\n // The child node succeeded, but we have not finished checking every child node yet.\n continue;\n }\n\n // If the current child has a state of 'FAILED' then this node is also a 'FAILED' node.\n if (child.getState() === State.FAILED) {\n hasChildFailed = true;\n\n // There is no need to check the rest of the children.\n break;\n }\n\n // The node should be in the 'RUNNING' state.\n if (child.getState() !== State.RUNNING) {\n // The child node was not in an expected state.\n throw new Error(\"child node was not in an expected state.\");\n }\n }\n\n if (hasChildFailed) {\n // This node is a 'FAILED' node.\n this.setState(State.FAILED);\n\n // Abort every running child.\n for (const child of this.children) {\n if (child.getState() === State.RUNNING) {\n child.abort(agent);\n }\n }\n } else {\n // If all children have succeeded then this node has also succeeded, otherwise it is still running.\n this.setState(succeededCount === this.children.length ? State.SUCCEEDED : State.RUNNING);\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => \"PARALLEL\";\n}\n", "import { AnyArgument } from \"../RootAstNodesBuilder\";\nimport Guard from \"./guards/Guard\";\n\nexport type AttributeDetails = {\n /** The attribute type. */\n type: string;\n\n /** The attribute arguments. */\n args: AnyArgument[];\n};\n\n/**\n * A base node attribute.\n */\nexport default abstract class Attribute {\n /**\n * @param type The node attribute type.\n * @param args The array of attribute argument definitions.\n */\n constructor(protected type: string, protected args: AnyArgument[]) {}\n\n /**\n * Gets the type of the attribute.\n */\n getType = () => this.type;\n\n /**\n * Gets the array of attribute argument definitions.\n */\n getArguments = () => this.args;\n\n /**\n * Gets the attribute details.\n */\n abstract getDetails(): TAttributeDetails;\n\n /**\n * Gets whether this attribute is a guard.\n */\n abstract isGuard: () => this is Guard;\n}\n", "import { Agent } from \"../../Agent\";\nimport { AnyArgument } from \"../../RootAstNodesBuilder\";\nimport Attribute, { AttributeDetails } from \"../Attribute\";\n\nexport type GuardAttributeDetails = {\n /** The name of the condition function that determines whether the guard is satisfied. */\n condition: string;\n} & AttributeDetails;\n\n/**\n * A base node guard attribute.\n */\nexport default abstract class Guard extends Attribute {\n /**\n * @param type The node attribute type.\n * @param args The array of decorator argument definitions.\n * @param condition The name of the condition function that determines whether the guard is satisfied.\n */\n constructor(type: string, args: AnyArgument[], private condition: string) {\n super(type, args);\n }\n\n /**\n * Gets the name of the condition function that determines whether the guard is satisfied.\n */\n getCondition = () => this.condition;\n\n /**\n * Gets whether this attribute is a guard.\n */\n isGuard = () => true;\n\n /**\n * Gets the attribute details.\n */\n getDetails(): GuardAttributeDetails {\n return {\n type: this.getType(),\n args: this.getArguments(),\n condition: this.getCondition()\n };\n }\n\n /**\n * Gets whether the guard is satisfied.\n * @param agent The agent.\n * @returns Whether the guard is satisfied.\n */\n abstract isSatisfied(agent: Agent): boolean;\n}\n", "import Guard from \"./Guard\";\nimport Lookup from \"../../Lookup\";\nimport { Agent } from \"../../Agent\";\nimport { AnyArgument } from \"../../RootAstNodesBuilder\";\n\n/**\n * A WHILE guard which is satisfied as long as the given condition remains true.\n */\nexport default class While extends Guard {\n /**\n * @param condition The name of the condition function that determines whether the guard is satisfied.\n * @param args The array of decorator argument definitions.\n */\n constructor(condition: string, args: AnyArgument[]) {\n super(\"while\", args, condition);\n }\n\n /**\n * Gets whether the guard is satisfied.\n * @param agent The agent.\n * @returns Whether the guard is satisfied.\n */\n isSatisfied = (agent: Agent) => {\n // Attempt to get the invoker for the condition function.\n const conditionFuncInvoker = Lookup.getFuncInvoker(agent, this.getCondition());\n\n // The condition function should be defined.\n if (conditionFuncInvoker === null) {\n throw new Error(\n `cannot evaluate node guard as the condition '${this.getCondition()}' function is not defined on the agent and has not been registered`\n );\n }\n\n // Call the condition function to determine whether this guard is satisfied.\n return !!conditionFuncInvoker(this.args);\n };\n}\n", "import Guard from \"./Guard\";\nimport Lookup from \"../../Lookup\";\nimport { Agent } from \"../../Agent\";\nimport { AnyArgument } from \"../../RootAstNodesBuilder\";\n\n/**\n * An UNTIL guard which is satisfied as long as the given condition remains false.\n */\nexport default class Until extends Guard {\n /**\n * @param condition The name of the condition function that determines whether the guard is satisfied.\n * @param args The array of decorator argument definitions.\n */\n constructor(condition: string, args: AnyArgument[]) {\n super(\"until\", args, condition);\n }\n\n /**\n * Gets whether the guard is satisfied.\n * @param agent The agent.\n * @returns Whether the guard is satisfied.\n */\n isSatisfied = (agent: Agent) => {\n // Attempt to get the invoker for the condition function.\n const conditionFuncInvoker = Lookup.getFuncInvoker(agent, this.getCondition());\n\n // The condition function should be defined.\n if (conditionFuncInvoker === null) {\n throw new Error(\n `cannot evaluate node guard as the condition '${this.getCondition()}' function is not defined on the agent and has not been registered`\n );\n }\n\n // Call the condition function to determine whether this guard is satisfied.\n return !!!conditionFuncInvoker(this.args);\n };\n}\n", "import { Agent } from \"../../Agent\";\nimport { AnyArgument } from \"../../RootAstNodesBuilder\";\nimport Attribute, { AttributeDetails } from \"../Attribute\";\n\nexport type CallbackAttributeDetails = {\n /** The name of the agent function that is called. */\n functionName: string;\n} & AttributeDetails;\n\n/**\n * A base node callback attribute.\n */\nexport default abstract class Callback extends Attribute {\n /**\n * @param type The node attribute type.\n * @param args The array of decorator argument definitions.\n * @param functionName The name of the agent function to call.\n */\n constructor(type: string, args: AnyArgument[], private functionName: string) {\n super(type, args);\n }\n\n /**\n * Gets the name of the agent function to call.\n */\n getFunctionName = () => this.functionName;\n\n /**\n * Gets whether this attribute is a guard.\n */\n isGuard = () => false;\n\n /**\n * Gets the attribute details.\n */\n getDetails(): CallbackAttributeDetails {\n return {\n type: this.getType(),\n args: this.getArguments(),\n functionName: this.getFunctionName()\n };\n }\n\n /**\n * Attempt to call the agent function that this callback refers to.\n * @param agent The agent.\n */\n abstract callAgentFunction: (agent: Agent, isSuccess: boolean, isAborted: boolean) => void;\n}\n", "import Callback from \"./Callback\";\nimport Lookup from \"../../Lookup\";\nimport { Agent } from \"../../Agent\";\nimport { AnyArgument } from \"../../RootAstNodesBuilder\";\n\n/**\n * An ENTRY callback which defines an agent function to call when the associated node is updated and moves out of running state.\n */\nexport default class Entry extends Callback {\n /**\n * @param functionName The name of the agent function to call.\n * @param args The array of callback argument definitions.\n */\n constructor(functionName: string, args: AnyArgument[]) {\n super(\"entry\", args, functionName);\n }\n\n /**\n * Attempt to call the agent function that this callback refers to.\n * @param agent The agent.\n */\n callAgentFunction = (agent: Agent) => {\n // Attempt to get the invoker for the callback function.\n const callbackFuncInvoker = Lookup.getFuncInvoker(agent, this.getFunctionName());\n\n // The callback function should be defined.\n if (callbackFuncInvoker === null) {\n throw new Error(\n `cannot call entry function '${this.getFunctionName()}' as is not defined on the agent and has not been registered`\n );\n }\n\n // Call the callback function.\n callbackFuncInvoker(this.args);\n };\n}\n", "import Callback from \"./Callback\";\nimport Lookup, { AnyExitArgument } from \"../../Lookup\";\nimport { Agent } from \"../../Agent\";\nimport { AnyArgument } from \"../../RootAstNodesBuilder\";\n\n/**\n * An EXIT callback which defines an agent function to call when the associated node is updated and moves to a finished state or is aborted.\n */\nexport default class Exit extends Callback {\n /**\n * @param functionName The name of the agent function to call.\n * @param args The array of callback argument definitions.\n */\n constructor(functionName: string, args: AnyArgument[]) {\n super(\"exit\", args, functionName);\n }\n\n /**\n * Attempt to call the agent function that this callback refers to.\n * @param agent The agent.\n * @param isSuccess Whether the decorated node was left with a success state.\n * @param isAborted Whether the decorated node was aborted.\n */\n callAgentFunction = (agent: Agent, isSuccess: boolean, isAborted: boolean) => {\n // Attempt to get the invoker for the callback function.\n const callbackFuncInvoker = Lookup.getFuncInvoker(agent, this.getFunctionName());\n\n // The callback function should be defined.\n if (callbackFuncInvoker === null) {\n throw new Error(\n `cannot call exit function '${this.getFunctionName()}' as is not defined on the agent and has not been registered`\n );\n }\n\n // Call the callback function\n callbackFuncInvoker([{ value: { succeeded: isSuccess, aborted: isAborted } }, ...this.args]);\n };\n}\n", "import Callback from \"./Callback\";\nimport Lookup from \"../../Lookup\";\nimport { Agent } from \"../../Agent\";\nimport { AnyArgument } from \"../../RootAstNodesBuilder\";\n\n/**\n * A STEP callback which defines an agent function to call when the associated node is updated.\n */\nexport default class Step extends Callback {\n /**\n * @param functionName The name of the agent function to call.\n * @param args The array of callback argument definitions.\n */\n constructor(functionName: string, args: AnyArgument[]) {\n super(\"step\", args, functionName);\n }\n\n /**\n * Attempt to call the agent function that this callback refers to.\n * @param agent The agent.\n */\n callAgentFunction = (agent: Agent) => {\n // Attempt to get the invoker for the callback function.\n const callbackFuncInvoker = Lookup.getFuncInvoker(agent, this.getFunctionName());\n\n // The callback function should be defined.\n if (callbackFuncInvoker === null) {\n throw new Error(\n `cannot call step function '${this.getFunctionName()}' as is not defined on the agent and has not been registered`\n );\n }\n\n // Call the callback function.\n callbackFuncInvoker(this.args);\n };\n}\n", "import Action from \"./nodes/leaf/Action\";\nimport Condition from \"./nodes/leaf/Condition\";\nimport Wait from \"./nodes/leaf/Wait\";\nimport Root from \"./nodes/decorator/Root\";\nimport Repeat from \"./nodes/decorator/Repeat\";\nimport Retry from \"./nodes/decorator/Retry\";\nimport Flip from \"./nodes/decorator/Flip\";\nimport Succeed from \"./nodes/decorator/Succeed\";\nimport Fail from \"./nodes/decorator/Fail\";\nimport Lotto from \"./nodes/composite/Lotto\";\nimport Selector from \"./nodes/composite/Selector\";\nimport Sequence from \"./nodes/composite/Sequence\";\nimport Parallel from \"./nodes/composite/Parallel\";\nimport Node from \"./nodes/Node\";\nimport While from \"./attributes/guards/While\";\nimport Until from \"./attributes/guards/Until\";\nimport Entry from \"./attributes/callbacks/Entry\";\nimport Exit from \"./attributes/callbacks/Exit\";\nimport Step from \"./attributes/callbacks/Step\";\nimport Callback from \"./attributes/callbacks/Callback\";\nimport Guard from \"./attributes/guards/Guard\";\nimport Attribute from \"./attributes/Attribute\";\nimport Composite from \"./nodes/composite/Composite\";\nimport Decorator from \"./nodes/decorator/Decorator\";\nimport Leaf from \"./nodes/leaf/Leaf\";\n\nexport type Argument = {\n value: T;\n type: string; // Used for validation.\n};\ntype NullArgument = Argument & {\n type: \"null\";\n};\ntype BooleanArgument = Argument & {\n type: \"boolean\";\n};\ntype NumberArgument = Argument & {\n type: \"number\";\n isInteger: boolean; // Used for validation.\n};\ntype StringPlaceholderArgument = Argument & {\n type: \"string\";\n};\ntype IdentifierArgument = Argument & {\n type: \"identifier\";\n};\nexport type AnyArgument =\n | NullArgument\n | BooleanArgument\n | NumberArgument\n | StringPlaceholderArgument\n | IdentifierArgument;\n\n/**\n * The node attribute factories.\n */\nconst AttributeFactories: {\n [key: string]: (functionName: string, attributeArguments: AnyArgument[]) => Callback | Guard;\n} = {\n WHILE: (condition: string, attributeArguments: AnyArgument[]) => new While(condition, attributeArguments),\n UNTIL: (condition: string, attributeArguments: AnyArgument[]) => new Until(condition, attributeArguments),\n ENTRY: (functionName: string, attributeArguments: AnyArgument[]) => new Entry(functionName, attributeArguments),\n EXIT: (functionName: string, attributeArguments: AnyArgument[]) => new Exit(functionName, attributeArguments),\n STEP: (functionName: string, attributeArguments: AnyArgument[]) => new Step(functionName, attributeArguments)\n};\n\ntype Validatable = {\n children?: AstNode[];\n validate: (depth: number) => void;\n};\n\ntype NodeInstanceCreator = (\n namedRootNodeProvider: (name: string) => RootAstNode,\n visitedBranches: string[]\n) => T;\n\nexport type AstNode = Validatable & {\n type: string;\n createNodeInstance: NodeInstanceCreator;\n};\n\nexport type LeafAstNode = AstNode & {\n type: \"action\" | \"condition\" | \"wait\";\n attributes: Attribute[];\n};\n\nexport type CompositeAstNode = AstNode & {\n type: \"lotto\" | \"parallel\" | \"selector\" | \"sequence\";\n attributes: Attribute[];\n children: AstNode[];\n};\n\nexport type DecoratorAstNode = AstNode & {\n type: \"fail\" | \"flip\" | \"repeat\" | \"retry\" | \"root\" | \"succeed\";\n attributes: Attribute[];\n children: AstNode[];\n};\n\nexport type BranchAstNode = AstNode & {\n type: \"branch\";\n branchName: \"\" | string;\n};\n\nexport type LottoAstNode = CompositeAstNode & {\n type: \"lotto\";\n tickets: number[];\n};\n\nexport type RootAstNode = DecoratorAstNode & {\n type: \"root\";\n name: null | string;\n};\n\nexport type RepeatAstNode = DecoratorAstNode & {\n type: \"repeat\";\n iterations: number | null;\n iterationsMin: number | null;\n iterationsMax: number | null;\n};\n\nexport type RetryAstNode = DecoratorAstNode & {\n type: \"retry\";\n attempts: number | null;\n attemptsMin: number | null;\n attemptsMax: number | null;\n};\n\nexport type ActionAstNode = LeafAstNode & {\n type: \"action\";\n actionName: string;\n actionArguments: AnyArgument[];\n};\n\nexport type ConditionAstNode = LeafAstNode & {\n type: \"condition\";\n conditionName: string;\n conditionArguments: AnyArgument[];\n};\n\nexport type WaitAstNode = LeafAstNode & {\n type: \"wait\";\n duration: number | null;\n durationMin: number | null;\n durationMax: number | null;\n};\n\nexport type AnyAstNode =\n | BranchAstNode\n | CompositeAstNode\n | LottoAstNode\n | DecoratorAstNode\n | RootAstNode\n | RepeatAstNode\n | RetryAstNode\n | LeafAstNode\n | ActionAstNode\n | ConditionAstNode\n | WaitAstNode;\n\n/**\n * The AST node factories.\n */\nconst ASTNodeFactories = {\n ROOT: (): RootAstNode => ({\n type: \"root\",\n attributes: [],\n name: null,\n children: [],\n validate(depth: number) {\n // A root node cannot be the child of another node.\n if (depth > 1) {\n throw new Error(\"a root node cannot be the child of another node\");\n }\n\n // A root node must have a single child node.\n if (this.children.length !== 1) {\n throw new Error(\"a root node must have a single child\");\n }\n },\n createNodeInstance(namedRootNodeProvider, visitedBranches) {\n return new Root(\n this.attributes,\n this.children![0].createNodeInstance(namedRootNodeProvider, visitedBranches.slice())\n );\n }\n }),\n BRANCH: (): BranchAstNode => ({\n type: \"branch\",\n branchName: \"\",\n validate() {},\n createNodeInstance(namedRootNodeProvider, visitedBranches) {\n // Try to find the root node with a matching branch name.\n const targetRootNode = namedRootNodeProvider(this.branchName);\n\n // If we have already visited this branch then we have a circular dependency.\n if (visitedBranches.indexOf(this.branchName) !== -1) {\n throw new Error(`circular dependency found in branch node references for branch '${this.branchName}'`);\n }\n\n // If we have a target root node, then the node instance we want will be the first and only child of the referenced root node.\n if (targetRootNode) {\n return targetRootNode\n .createNodeInstance(namedRootNodeProvider, visitedBranches.concat(this.branchName))\n .getChildren()[0];\n } else {\n throw new Error(`branch references root node '${this.branchName}' which has not been defined`);\n }\n }\n }),\n SELECTOR: (): CompositeAstNode => ({\n type: \"selector\",\n attributes: [],\n children: [],\n validate() {\n // A selector node must have at least a single node.\n if (this.children.length < 1) {\n throw new Error(\"a selector node must have at least a single child\");\n }\n },\n createNodeInstance(namedRootNodeProvider, visitedBranches) {\n return new Selector(\n this.attributes,\n this.children.map((child) => child.createNodeInstance(namedRootNodeProvider, visitedBranches.slice()))\n );\n }\n }),\n SEQUENCE: (): CompositeAstNode => ({\n type: \"sequence\",\n attributes: [],\n children: [],\n validate() {\n // A sequence node must have at least a single node.\n if (this.children.length < 1) {\n throw new Error(\"a sequence node must have at least a single child\");\n }\n },\n createNodeInstance(namedRootNodeProvider, visitedBranches) {\n return new Sequence(\n this.attributes,\n this.children.map((child) => child.createNodeInstance(namedRootNodeProvider, visitedBranches.slice()))\n );\n }\n }),\n PARALLEL: (): CompositeAstNode => ({\n type: \"parallel\",\n attributes: [],\n children: [],\n validate() {\n // A parallel node must have at least a single node.\n if (this.children.length < 1) {\n throw new Error(\"a parallel node must have at least a single child\");\n }\n },\n createNodeInstance(namedRootNodeProvider, visitedBranches) {\n return new Parallel(\n this.attributes,\n this.children.map((child) => child.createNodeInstance(namedRootNodeProvider, visitedBranches.slice()))\n );\n }\n }),\n LOTTO: (): LottoAstNode => ({\n type: \"lotto\",\n attributes: [],\n children: [],\n tickets: [],\n validate() {\n // A lotto node must have at least a single node.\n if (this.children!.length < 1) {\n throw new Error(\"a lotto node must have at least a single child\");\n }\n },\n createNodeInstance(namedRootNodeProvider, visitedBranches) {\n return new Lotto(\n this.attributes,\n this.tickets!,\n this.children!.map((child) => child.createNodeInstance(namedRootNodeProvider, visitedBranches.slice()))\n );\n }\n }),\n REPEAT: (): RepeatAstNode => ({\n type: \"repeat\",\n attributes: [],\n iterations: null,\n iterationsMin: null,\n iterationsMax: null,\n children: [],\n validate() {\n // A repeat node must have a single node.\n if (this.children!.length !== 1) {\n throw new Error(\"a repeat node must have a single child\");\n }\n\n if (this.iterations !== null) {\n // A repeat node must have a positive number of iterations if defined.\n if (this.iterations < 0) {\n throw new Error(\"a repeat node must have a positive number of iterations if defined\");\n }\n } else if (this.iterationsMin !== null && this.iterationsMax !== null) {\n // A repeat node must have a positive min and max iteration count if they are defined.\n if (this.iterationsMin < 0 || this.iterationsMax < 0) {\n throw new Error(\n \"a repeat node must have a positive minimum and maximum iteration count if defined\"\n );\n }\n\n // A repeat node must not have an minimum iteration count that exceeds the maximum iteration count.\n if (this.iterationsMin > this.iterationsMax) {\n throw new Error(\n \"a repeat node must not have a minimum iteration count that exceeds the maximum iteration count\"\n );\n }\n } else {\n // If we have no explicit iteration count or a minimum and maximum iteration count set then we are dealing with a repeat node that iterates indefinitely.\n }\n },\n createNodeInstance(namedRootNodeProvider, visitedBranches) {\n return new Repeat(\n this.attributes,\n this.iterations,\n this.iterationsMin,\n this.iterationsMax,\n this.children![0].createNodeInstance(namedRootNodeProvider, visitedBranches.slice())\n );\n }\n }),\n RETRY: (): RetryAstNode => ({\n type: \"retry\",\n attributes: [],\n attempts: null,\n attemptsMin: null,\n attemptsMax: null,\n children: [],\n validate() {\n // A retry node must have a single node.\n if (this.children!.length !== 1) {\n throw new Error(\"a retry node must have a single child\");\n }\n\n if (this.attempts !== null) {\n // A retry node must have a positive number of attempts if defined.\n if (this.attempts < 0) {\n throw new Error(\"a retry node must have a positive number of attempts if defined\");\n }\n } else if (this.attemptsMin !== null && this.attemptsMax !== null) {\n // A retry node must have a positive min and max attempts count if they are defined.\n if (this.attemptsMin < 0 || this.attemptsMax < 0) {\n throw new Error(\"a retry node must have a positive minimum and maximum attempt count if defined\");\n }\n\n // A retry node must not have a minimum attempt count that exceeds the maximum attempt count.\n if (this.attemptsMin > this.attemptsMax) {\n throw new Error(\n \"a retry node must not have a minimum attempt count that exceeds the maximum attempt count\"\n );\n }\n } else {\n // If we have no explicit attempt count or a minimum and maximum attempt count set then we are dealing with a retry node that attempts indefinitely.\n }\n },\n createNodeInstance(namedRootNodeProvider, visitedBranches) {\n return new Retry(\n this.attributes,\n this.attempts,\n this.attemptsMin,\n this.attemptsMax,\n this.children![0].createNodeInstance(namedRootNodeProvider, visitedBranches.slice())\n );\n }\n }),\n FLIP: (): DecoratorAstNode => ({\n type: \"flip\",\n attributes: [],\n children: [],\n validate() {\n // A flip node must have a single node.\n if (this.children!.length !== 1) {\n throw new Error(\"a flip node must have a single child\");\n }\n },\n createNodeInstance(namedRootNodeProvider, visitedBranches) {\n return new Flip(\n this.attributes,\n this.children![0].createNodeInstance(namedRootNodeProvider, visitedBranches.slice())\n );\n }\n }),\n SUCCEED: (): DecoratorAstNode => ({\n type: \"succeed\",\n attributes: [],\n children: [],\n validate() {\n // A succeed node must have a single node.\n if (this.children!.length !== 1) {\n throw new Error(\"a succeed node must have a single child\");\n }\n },\n createNodeInstance(namedRootNodeProvider, visitedBranches) {\n return new Succeed(\n this.attributes,\n this.children![0].createNodeInstance(namedRootNodeProvider, visitedBranches.slice())\n );\n }\n }),\n FAIL: (): DecoratorAstNode => ({\n type: \"fail\",\n attributes: [],\n children: [],\n validate() {\n // A fail node must have a single node.\n if (this.children!.length !== 1) {\n throw new Error(\"a fail node must have a single child\");\n }\n },\n createNodeInstance(namedRootNodeProvider, visitedBranches) {\n return new Fail(\n this.attributes,\n this.children![0].createNodeInstance(namedRootNodeProvider, visitedBranches.slice())\n );\n }\n }),\n WAIT: (): WaitAstNode => ({\n type: \"wait\",\n attributes: [],\n duration: null,\n durationMin: null,\n durationMax: null,\n validate() {\n if (this.duration !== null) {\n // If an explict duration was defined then it must be a positive number.\n if (this.duration < 0) {\n throw new Error(\"a wait node must have a positive duration\");\n }\n } else if (this.durationMin !== null && this.durationMax !== null) {\n // A wait node must have a positive min and max duration.\n if (this.durationMin < 0 || this.durationMax < 0) {\n throw new Error(\"a wait node must have a positive minimum and maximum duration\");\n }\n\n // A wait node must not have a minimum duration that exceeds the maximum duration.\n if (this.durationMin > this.durationMax) {\n throw new Error(\"a wait node must not have a minimum duration that exceeds the maximum duration\");\n }\n } else {\n // If we have no explicit duration or duration bounds set then we are dealing with a wait node that waits indefinitely.\n }\n },\n createNodeInstance() {\n return new Wait(this.attributes, this.duration, this.durationMin, this.durationMax);\n }\n }),\n ACTION: (): ActionAstNode => ({\n type: \"action\",\n attributes: [],\n actionName: \"\",\n actionArguments: [],\n validate() {},\n createNodeInstance() {\n return new Action(this.attributes, this.actionName!, this.actionArguments!);\n }\n }),\n CONDITION: (): ConditionAstNode => ({\n type: \"condition\",\n attributes: [],\n conditionName: \"\",\n conditionArguments: [],\n validate() {},\n createNodeInstance() {\n return new Condition(this.attributes, this.conditionName!, this.conditionArguments!);\n }\n })\n};\n\ntype OtherAstNodes = AstNode[];\n\n/**\n * Create an array of root AST nodes based on the given definition.\n * @param definition The definition to parse the AST nodes from.\n * @returns The base definition AST nodes.\n */\nexport default function buildRootASTNodes(definition: string): RootAstNode[] {\n // Swap out any node/attribute argument string literals with a placeholder and get a mapping of placeholders to original values as well as the processed definition.\n const { placeholders, processedDefinition } = substituteStringLiterals(definition);\n\n // Convert the processed definition (with substituted string literals) into an array of raw tokens.\n const tokens = parseTokensFromDefinition(processedDefinition);\n\n // There must be at least 3 tokens for the tree definition to be valid. 'ROOT', '{' and '}'.\n if (tokens.length < 3) {\n throw new Error(\"invalid token count\");\n }\n\n // We should have a matching number of '{' and '}' tokens. If not, then there are scopes that have not been properly closed.\n if (tokens.filter((token) => token === \"{\").length !== tokens.filter((token) => token === \"}\").length) {\n throw new Error(\"scope character mismatch\");\n }\n\n // Create a stack of node children arrays, starting with a definition scope.\n const stack: [RootAstNode[], ...OtherAstNodes[]] = [[]];\n const rootScope = stack[0];\n\n // We should keep processing the raw tokens until we run out of them.\n while (tokens.length) {\n // Grab the next token.\n const token = tokens.shift();\n\n const currentScope = stack[stack.length - 1] as OtherAstNodes;\n\n // How we create the next AST token depends on the current raw token value.\n switch (token!.toUpperCase()) {\n case \"ROOT\": {\n // Create a ROOT AST node.\n const node = ASTNodeFactories.ROOT();\n\n // Push the ROOT node into the current scope.\n rootScope.push(node);\n\n // We may have a root node name defined as an argument.\n if (tokens[0] === \"[\") {\n const rootArguments = getArguments(tokens, placeholders);\n\n // We should have only a single argument that is not an empty string for a root node, which is the root name identifier.\n if (rootArguments.length === 1 && rootArguments[0].type === \"identifier\") {\n // The root name will be the first and only node argument.\n node.name = rootArguments[0].value as string;\n } else {\n throw new Error(\"expected single root name argument\");\n }\n }\n\n // Try to pick any attributes off of the token stack.\n node.attributes = getAttributes(tokens, placeholders);\n\n popAndCheck(tokens, \"{\");\n\n // The new scope is that of the new ROOT nodes children.\n stack.push(node.children!);\n break;\n }\n\n case \"BRANCH\": {\n // Create a BRANCH AST node.\n const node = ASTNodeFactories.BRANCH();\n\n // Push the BRANCH node into the current scope.\n currentScope.push(node);\n\n // We must have arguments defined, as we require a branch name argument.\n if (tokens[0] !== \"[\") {\n throw new Error(\"expected single branch name argument\");\n }\n\n // The branch name will be defined as a node argument.\n const branchArguments = getArguments(tokens, placeholders);\n\n // We should have only a single identifer argument for a branch node, which is the branch name.\n if (branchArguments.length === 1 && branchArguments[0].type === \"identifier\") {\n // The branch name will be the first and only node argument.\n node.branchName = branchArguments[0].value as string;\n } else {\n throw new Error(\"expected single branch name argument\");\n }\n break;\n }\n\n case \"SELECTOR\": {\n // Create a SELECTOR AST node.\n const node = ASTNodeFactories.SELECTOR();\n\n // Push the SELECTOR node into the current scope.\n currentScope.push(node);\n\n // Try to pick any attributes off of the token stack.\n node.attributes = getAttributes(tokens, placeholders);\n\n popAndCheck(tokens, \"{\");\n\n // The new scope is that of the new SELECTOR nodes children.\n stack.push(node.children!);\n break;\n }\n\n case \"SEQUENCE\": {\n // Create a SEQUENCE AST node.\n const node = ASTNodeFactories.SEQUENCE();\n\n // Push the SEQUENCE node into the current scope.\n currentScope.push(node);\n\n // Try to pick any attributes off of the token stack.\n node.attributes = getAttributes(tokens, placeholders);\n\n popAndCheck(tokens, \"{\");\n\n // The new scope is that of the new SEQUENCE nodes children.\n stack.push(node.children!);\n break;\n }\n\n case \"PARALLEL\": {\n // Create a PARALLEL AST node.\n const node = ASTNodeFactories.PARALLEL();\n\n // Push the PARALLEL node into the current scope.\n currentScope.push(node);\n\n // Try to pick any attributes off of the token stack.\n node.attributes = getAttributes(tokens, placeholders);\n\n popAndCheck(tokens, \"{\");\n\n // The new scope is that of the new PARALLEL nodes children.\n stack.push(node.children!);\n break;\n }\n\n case \"LOTTO\": {\n // Create a LOTTO AST node.\n const node = ASTNodeFactories.LOTTO();\n\n // Push the LOTTO node into the current scope.\n currentScope.push(node);\n\n // If the next token is a '[' character then some ticket counts have been defined as arguments.\n if (tokens[0] === \"[\") {\n // Get the ticket count arguments, each argument must be a number.\n node.tickets = getArguments(\n tokens,\n placeholders,\n (arg) => arg.type === \"number\" && !!arg.isInteger,\n \"lotto node ticket counts must be integer values\"\n ).map((argument) => argument.value as number);\n }\n\n // Try to pick any attributes off of the token stack.\n node.attributes = getAttributes(tokens, placeholders);\n\n popAndCheck(tokens, \"{\");\n\n // The new scope is that of the new LOTTO nodes children.\n stack.push(node.children!);\n break;\n }\n\n case \"CONDITION\": {\n // Create a CONDITION AST node.\n const node = ASTNodeFactories.CONDITION();\n\n // Push the CONDITION node into the current scope.\n currentScope.push(node);\n\n // We must have arguments defined, as we require a condition function name argument.\n if (tokens[0] !== \"[\") {\n throw new Error(\"expected condition name identifier argument\");\n }\n\n // Grab the condition node arguments.\n const conditionArguments = getArguments(tokens, placeholders);\n\n // We should have at least a single identifier argument for a condition node, which is the condition function name.\n if (conditionArguments.length && conditionArguments[0].type === \"identifier\") {\n // The condition function name will be the first node argument.\n node.conditionName = conditionArguments.shift()!.value as string;\n } else {\n throw new Error(\"expected condition name identifier argument\");\n }\n\n // Only the first argument should have been an identifier, all following arguments must be string, number, boolean or null.\n conditionArguments\n .filter((arg) => arg.type === \"identifier\")\n .forEach((arg) => {\n throw new Error(\n \"invalid condition node argument value '\" +\n arg.value +\n \"', must be string, number, boolean or null\"\n );\n });\n\n // Any node arguments that follow the condition name identifier will be treated as condition function arguments.\n node.conditionArguments = conditionArguments;\n\n // Try to pick any attributes off of the token stack.\n node.attributes = getAttributes(tokens, placeholders);\n break;\n }\n\n case \"FLIP\": {\n // Create a FLIP AST node.\n const node = ASTNodeFactories.FLIP();\n\n // Push the Flip node into the current scope.\n currentScope.push(node);\n\n // Try to pick any attributes off of the token stack.\n node.attributes = getAttributes(tokens, placeholders);\n\n popAndCheck(tokens, \"{\");\n\n // The new scope is that of the new FLIP nodes children.\n stack.push(node.children!);\n break;\n }\n\n case \"SUCCEED\": {\n // Create a SUCCEED AST node.\n const node = ASTNodeFactories.SUCCEED();\n\n // Push the Succeed node into the current scope.\n currentScope.push(node);\n\n // Try to pick any attributes off of the token stack.\n node.attributes = getAttributes(tokens, placeholders);\n\n popAndCheck(tokens, \"{\");\n\n // The new scope is that of the new Succeed nodes children.\n stack.push(node.children!);\n break;\n }\n\n case \"FAIL\": {\n // Create a FAIL AST node.\n const node = ASTNodeFactories.FAIL();\n\n // Push the Fail node into the current scope.\n currentScope.push(node);\n\n // Try to pick any attributes off of the token stack.\n node.attributes = getAttributes(tokens, placeholders);\n\n popAndCheck(tokens, \"{\");\n\n // The new scope is that of the new Fail nodes children.\n stack.push(node.children!);\n break;\n }\n\n case \"WAIT\": {\n // Create a WAIT AST node.\n const node = ASTNodeFactories.WAIT();\n\n // Push the WAIT node into the current scope.\n currentScope.push(node);\n\n // The arguments of a wait node are optional. We may have:\n // - No node arguments, in which case the wait will be indefinite until it is aborted.\n // - One node argument which will be the explicit duration of the wait.\n // - Two node arguments which define the min and max duration bounds from which a random duration will be picked.\n if (tokens[0] === \"[\") {\n // Get the optional duration and longest duration of the wait.\n const nodeArguments = getArguments(\n tokens,\n placeholders,\n (arg) => arg.type === \"number\" && !!arg.isInteger,\n \"wait node durations must be integer values\"\n ).map((argument) => argument.value);\n\n // We may have:\n // - One node argument which will be the explicit duration of the wait.\n // - Two node arguments which define the min and max duration bounds from which a random duration will be picked.\n // - Too many arguments, which is not valid.\n if (nodeArguments.length === 1) {\n // An explicit duration was defined.\n node.duration = nodeArguments[0] as number;\n } else if (nodeArguments.length === 2) {\n // Min and max duration bounds were defined from which a random duration will be picked.\n node.durationMin = nodeArguments[0] as number;\n node.durationMax = nodeArguments[1] as number;\n } else if (nodeArguments.length > 2) {\n // An incorrect number of durations was defined.\n throw new Error(\"invalid number of wait node duration arguments defined\");\n }\n }\n\n // Try to pick any attributes off of the token stack.\n node.attributes = getAttributes(tokens, placeholders);\n break;\n }\n\n case \"REPEAT\": {\n // Create a REPEAT AST node.\n const node = ASTNodeFactories.REPEAT();\n\n // Push the REPEAT node into the current scope.\n currentScope.push(node);\n\n // The arguments of a repeat node are optional. We may have:\n // - No node arguments, in which case the repeat note will iterate indefinitely.\n // - One node argument which will be the explicit number of iterations to make.\n // - Two node arguments which define the min and max iteration bounds from which a random iteration count will be picked.\n if (tokens[0] === \"[\") {\n // An iteration count has been defined. Get the iteration and potential maximum iteration of the wait.\n const nodeArguments = getArguments(\n tokens,\n placeholders,\n (arg) => arg.type === \"number\" && !!arg.isInteger,\n \"repeat node iteration counts must be integer values\"\n ).map((argument) => argument.value);\n\n // We should have got one or two iteration counts.\n if (nodeArguments.length === 1) {\n // A static iteration count was defined.\n node.iterations = nodeArguments[0] as number;\n } else if (nodeArguments.length === 2) {\n // A minimum and maximum iteration count was defined.\n node.iterationsMin = nodeArguments[0] as number;\n node.iterationsMax = nodeArguments[1] as number;\n } else {\n // An incorrect number of iteration counts was defined.\n throw new Error(\"invalid number of repeat node iteration count arguments defined\");\n }\n }\n\n // Try to pick any attributes off of the token stack.\n node.attributes = getAttributes(tokens, placeholders);\n\n popAndCheck(tokens, \"{\");\n\n // The new scope is that of the new REPEAT nodes children.\n stack.push(node.children!);\n break;\n }\n\n case \"RETRY\": {\n // Create a RETRY AST node.\n const node = ASTNodeFactories.RETRY();\n\n // Push the RETRY node into the current scope.\n currentScope.push(node);\n\n // The arguments of a retry node are optional. We may have:\n // - No node arguments, in which case the retry note will attempt indefinitely.\n // - One node argument which will be the explicit number of attempts to make.\n // - Two node arguments which define the min and max attempt bounds from which a random attempt count will be picked.\n if (tokens[0] === \"[\") {\n // An attempt count has been defined. Get the attempt count and potential maximum attempt count of the wait.\n const nodeArguments = getArguments(\n tokens,\n placeholders,\n (arg) => arg.type === \"number\" && !!arg.isInteger,\n \"retry node attempt counts must be integer values\"\n ).map((argument) => argument.value);\n\n // We should have got one or two attempt counts.\n if (nodeArguments.length === 1) {\n // A static attempt count was defined.\n node.attempts = nodeArguments[0] as number;\n } else if (nodeArguments.length === 2) {\n // A minimum and maximum attempt count was defined.\n node.attemptsMin = nodeArguments[0] as number;\n node.attemptsMax = nodeArguments[1] as number;\n } else {\n // An incorrect number of attempt counts was defined.\n throw new Error(\"invalid number of retry node attempt count arguments defined\");\n }\n }\n\n // Try to pick any attributes off of the token stack.\n node.attributes = getAttributes(tokens, placeholders);\n\n popAndCheck(tokens, \"{\");\n\n // The new scope is that of the new RETRY nodes children.\n stack.push(node.children!);\n break;\n }\n\n case \"ACTION\": {\n // Create a ACTION AST node.\n const node = ASTNodeFactories.ACTION();\n\n // Push the ACTION node into the current scope.\n currentScope.push(node);\n\n // We must have arguments defined, as we require an action name argument.\n if (tokens[0] !== \"[\") {\n throw new Error(\"expected action name identifier argument\");\n }\n\n // The action name will be defined as a node argument.\n const actionArguments = getArguments(tokens, placeholders);\n\n // We should have at least one identifer argument for an action node, which is the action name.\n if (actionArguments.length && actionArguments[0].type === \"identifier\") {\n // The action name will be the first and only node argument.\n node.actionName = actionArguments.shift()!.value as string;\n } else {\n throw new Error(\"expected action name identifier argument\");\n }\n\n // Only the first argument should have been an identifier, all following arguments must be string, number, boolean or null.\n actionArguments\n .filter((arg) => arg.type === \"identifier\")\n .forEach((arg) => {\n throw new Error(\n \"invalid action node argument value '\" +\n arg.value +\n \"', must be string, number, boolean or null\"\n );\n });\n\n // Any node arguments that follow the action name identifier will be treated as action function arguments.\n node.actionArguments = actionArguments;\n\n // Try to pick any attributes off of the token stack.\n node.attributes = getAttributes(tokens, placeholders);\n break;\n }\n\n case \"}\": {\n // The '}' character closes the current scope.\n stack.pop();\n break;\n }\n\n default: {\n throw new Error(`unexpected token '${token}'`);\n }\n }\n }\n\n // A function to recursively validate each of the nodes in the AST.\n const validateASTNode = (node: Validatable, depth: number): void => {\n // Validate the node.\n node.validate(depth);\n\n // Validate each child of the node.\n (node.children || []).forEach((child) => validateASTNode(child, depth + 1));\n };\n\n // Start node validation from the definition root.\n validateASTNode(\n {\n children: stack[0] as RootAstNode[],\n validate(this: { children: RootAstNode[] }) {\n // We must have at least one node defined as the definition scope, which should be a root node.\n if (this.children.length === 0) {\n throw new Error(\"expected root node to have been defined\");\n }\n\n // Each node at the base of the definition scope MUST be a root node.\n for (const definitionLevelNode of this.children) {\n if (definitionLevelNode.type !== \"root\") {\n throw new Error(\"expected root node at base of definition\");\n }\n }\n\n // Exactly one root node must not have a name defined. This will be the main root, others will have to be referenced via branch nodes.\n if (this.children.filter((definitionLevelNode) => definitionLevelNode.name === null).length !== 1) {\n throw new Error(\"expected single unnamed root node at base of definition to act as main root\");\n }\n\n // No two named root nodes can have matching names.\n const rootNodeNames: string[] = [];\n for (const definitionLevelNode of this.children) {\n if (rootNodeNames.indexOf(definitionLevelNode.name!) !== -1) {\n throw new Error(`multiple root nodes found with duplicate name '${definitionLevelNode.name}'`);\n } else {\n rootNodeNames.push(definitionLevelNode.name!);\n }\n }\n }\n },\n 0\n );\n\n // Return the root AST nodes.\n return stack[0];\n}\n\n/**\n * Pop the next raw token off of the stack and throw an error if it wasn't the expected one.\n * @param tokens The array of remaining tokens.\n * @param expected An optional string or array or items, one of which must match the next popped token.\n * @returns The popped token.\n */\nfunction popAndCheck(tokens: string[], expected: string | string[]) {\n // Get and remove the next token.\n const popped = tokens.shift();\n\n // We were expecting another token.\n if (popped === undefined) {\n throw new Error(\"unexpected end of definition\");\n }\n\n // Do we have an expected token/tokens array?\n if (expected !== undefined) {\n // Check whether the popped token matches at least one of our expected items.\n var tokenMatchesExpectation = ([] as string[])\n .concat(expected)\n .some((item) => popped.toUpperCase() === item.toUpperCase());\n\n // Throw an error if the popped token didn't match any of our expected items.\n if (!tokenMatchesExpectation) {\n const expectationString = ([] as string[])\n .concat(expected)\n .map((item) => \"'\" + item + \"'\")\n .join(\" or \");\n\n throw new Error(`unexpected token found. Expected '${expectationString}' but got '${popped}'`);\n }\n }\n\n // Return the popped token.\n return popped;\n}\n\ntype StringPlaceholders = { [key: string]: string };\n\n/**\n * Pull an argument definition list off of the token stack.\n * @param tokens The array of remaining tokens.\n * @param stringArgumentPlaceholders The mapping of string literal node argument placeholders to original values.\n * @param argumentValidator The argument validator function.\n * @param validationFailedMessage The exception message to throw if argument validation fails.\n * @returns The argument definition list.\n */\nfunction getArguments(\n tokens: string[],\n stringArgumentPlaceholders: StringPlaceholders,\n argumentValidator?: (arg: AnyArgument) => boolean,\n validationFailedMessage?: string\n) {\n // Any lists of arguments will always be wrapped in '[]' for node arguments or '()' for attribute arguments.\n // We are looking for a '[' or '(' opener that wraps the argument tokens and the relevant closer.\n const closer = popAndCheck(tokens, [\"[\", \"(\"]) === \"[\" ? \"]\" : \")\";\n\n const argumentListTokens: string[] = [];\n const argumentList: AnyArgument[] = [];\n\n // Grab all tokens between the '[' and ']' or '(' and ')'.\n while (tokens.length && tokens[0] !== closer) {\n // The next token is part of our arguments list.\n argumentListTokens.push(tokens.shift()!);\n }\n\n // Validate the order of the argument tokens. Each token must either be a ',' or a single argument that satisfies the validator.\n argumentListTokens.forEach((token, index) => {\n // Get whether this token should be an actual argument.\n const shouldBeArgumentToken = !(index & 1);\n\n // If the current token should be an actual argument then validate it,otherwise it should be a ',' token.\n if (shouldBeArgumentToken) {\n // Get the argument definition.\n const argumentDefinition = getArgumentDefinition(token!, stringArgumentPlaceholders);\n\n // Try to validate the argument.\n if (argumentValidator && !argumentValidator(argumentDefinition)) {\n throw new Error(validationFailedMessage);\n }\n\n // This is a valid argument!\n argumentList.push(argumentDefinition);\n } else {\n // The current token should be a ',' token.\n if (token !== \",\") {\n throw new Error(`invalid argument list, expected ',' or ']' but got '${token}'`);\n }\n }\n });\n\n // The arguments list should terminate with a ']' or ')' token, depending on the opener.\n popAndCheck(tokens, closer);\n\n // Return the argument list.\n return argumentList;\n}\n\n/**\n * Gets an argument value definition.\n * @param token The argument token.\n * @param stringArgumentPlaceholders The mapping of string literal node argument placeholders to original values.\n * @returns An argument value definition.\n */\nfunction getArgumentDefinition(token: string, stringArgumentPlaceholders: StringPlaceholders): AnyArgument {\n // Check whether the token represents a null value.\n if (token === \"null\") {\n return {\n value: null,\n type: \"null\"\n } as NullArgument;\n }\n\n // Check whether the token represents a boolean value.\n if (token === \"true\" || token === \"false\") {\n return {\n value: token === \"true\",\n type: \"boolean\"\n } as BooleanArgument;\n }\n\n // Check whether the token represents a number value.\n // TODO: Relies on broken isNaN - see MDN.\n // if (!Number.isNaN(token)) {\n if (!isNaN(token as any)) {\n return {\n value: parseFloat(token),\n isInteger: parseFloat(token) === parseInt(token, 10),\n type: \"number\"\n } as NumberArgument;\n }\n\n // Check whether the token is a placeholder (e.g. @@0@@) representing a string literal.\n if (token.match(/^@@\\d+@@$/g)) {\n return {\n value: stringArgumentPlaceholders[token].replace('\\\\\"', '\"'),\n type: \"string\"\n } as StringPlaceholderArgument;\n }\n\n // The only remaining option is that the argument value is an identifier.\n return {\n value: token,\n type: \"identifier\"\n } as IdentifierArgument;\n}\n\n/**\n * Pull any attributes off of the token stack.\n * @param tokens The array of remaining tokens.\n * @param stringArgumentPlaceholders The mapping of string literal node argument placeholders to original values.\n * @returns An array of attributes defined by any directly following tokens.\n */\nfunction getAttributes(tokens: string[], stringArgumentPlaceholders: StringPlaceholders) {\n // Create an array to hold any attributes found.\n const attributes: Attribute[] = [];\n\n // Keep track of names of attribute that we have found on the token stack, as we cannot have duplicates.\n const attributesFound: string[] = [];\n\n // Try to get the attribute factory for the next token.\n let attributeFactory = AttributeFactories[(tokens[0] || \"\").toUpperCase()];\n\n // Pull attribute tokens off of the tokens stack until we have no more.\n while (attributeFactory) {\n // Check to make sure that we have not already created a attribute of this type for this node.\n if (attributesFound.indexOf(tokens[0].toUpperCase()) !== -1) {\n throw new Error(`duplicate attribute '${tokens[0].toUpperCase()}' found for node`);\n }\n\n // Add the current attribute type to our array of found attributes.\n attributesFound.push(tokens.shift()!.toUpperCase());\n\n // Grab any attribute arguments.\n const attributeArguments = getArguments(tokens, stringArgumentPlaceholders);\n\n // The first attribute argument has to be an identifer, this will reference an agent function.\n if (attributeArguments.length === 0 || attributeArguments[0].type !== \"identifier\") {\n throw new Error(\"expected agent function name identifier argument for attribute\");\n }\n\n // Grab the first attribute which is an identifier that will reference an agent function.\n const attributeFunctionName = attributeArguments.shift()! as IdentifierArgument;\n\n // Any remaining attribute arguments must have a type of string, number, boolean or null.\n attributeArguments\n .filter((arg) => arg.type === \"identifier\")\n .forEach((arg) => {\n throw new Error(\n \"invalid attribute argument value '\" + arg.value + \"', must be string, number, boolean or null\"\n );\n });\n\n // Create the attribute and add it to the array of attributes found.\n attributes.push(attributeFactory(attributeFunctionName.value, attributeArguments));\n\n // Try to get the next attribute name token, as there could be multiple.\n attributeFactory = AttributeFactories[(tokens[0] || \"\").toUpperCase()];\n }\n\n return attributes;\n}\n\n/**\n * Swaps out any node/attribute argument string literals with placeholders.\n * @param definition The definition.\n * @returns An object containing a mapping of placeholders to original string values as well as the processed definition string.\n */\nfunction substituteStringLiterals(definition: string): {\n placeholders: { [key: string]: string };\n processedDefinition: string;\n} {\n // Create an object to hold the mapping of placeholders to original string values.\n const placeholders: StringPlaceholders = {};\n\n // Replace any string literals wrapped with double quotes in our definition with placeholders to be processed later.\n const processedDefinition = definition.replace(/\\\"(\\\\.|[^\"\\\\])*\\\"/g, (match) => {\n var strippedMatch = match.substring(1, match.length - 1);\n var placeholder = Object.keys(placeholders).find((key) => placeholders[key] === strippedMatch);\n\n // If we have no existing string literal match then create a new placeholder.\n if (!placeholder) {\n placeholder = `@@${Object.keys(placeholders).length}@@`;\n placeholders[placeholder] = strippedMatch;\n }\n\n return placeholder;\n });\n\n return { placeholders, processedDefinition };\n}\n\n/**\n * Parse the tree definition into an array of raw tokens.\n * @param definition The definition.\n * @returns An array of tokens parsed from the definition.\n */\nfunction parseTokensFromDefinition(definition: string): string[] {\n // Add some space around various important characters so that they can be plucked out easier as individual tokens.\n definition = definition.replace(/\\(/g, \" ( \");\n definition = definition.replace(/\\)/g, \" ) \");\n definition = definition.replace(/\\{/g, \" { \");\n definition = definition.replace(/\\}/g, \" } \");\n definition = definition.replace(/\\]/g, \" ] \");\n definition = definition.replace(/\\[/g, \" [ \");\n definition = definition.replace(/\\,/g, \" , \");\n\n // Split the definition into raw token form and return it.\n return definition.replace(/\\s+/g, \" \").trim().split(\" \");\n}\n", "import GuardPath, { GuardPathPart } from \"./attributes/guards/GuardPath\";\nimport buildRootASTNodes, { AnyArgument, RootAstNode } from \"./RootAstNodesBuilder\";\nimport State, { AnyState } from \"./State\";\nimport Lookup from \"./Lookup\";\nimport Node from \"./nodes/Node\";\nimport Root from \"./nodes/decorator/Root\";\nimport Composite from \"./nodes/composite/Composite\";\nimport Decorator from \"./nodes/decorator/Decorator\";\nimport { Agent, GlobalFunction } from \"./Agent\";\nimport { CallbackAttributeDetails } from \"./attributes/callbacks/Callback\";\nimport { GuardAttributeDetails } from \"./attributes/guards/Guard\";\nimport { BehaviourTreeOptions } from \"./BehaviourTreeOptions\";\nimport { convertMDSLToJSON } from \"./mdsl/MDSLDefinitionParser\";\n\n// Purely for outside inspection of the tree.\nexport type FlattenedTreeNode = {\n id: string;\n type: string;\n caption: string;\n state: AnyState;\n guards: GuardAttributeDetails[];\n callbacks: CallbackAttributeDetails[];\n args: AnyArgument[];\n parentId: string | null;\n};\n\n/**\n * A representation of a behaviour tree.\n */\nexport class BehaviourTree {\n /**\n * The main root tree node.\n */\n public readonly rootNode: Root;\n\n /**\n * Creates a new instance of the BehaviourTree class.\n * @param definition The behaviour tree definition.\n * @param agent The agent instance that this behaviour tree is modelling behaviour for.\n * @param options The behaviour tree options object.\n */\n constructor(definition: string, private agent: Agent, private options: BehaviourTreeOptions = {}) {\n // The tree definition must be defined and a valid string.\n if (typeof definition !== \"string\") {\n throw new Error(\"the tree definition must be a string\");\n }\n\n // The agent must be defined and not null.\n if (typeof agent !== \"object\" || agent === null) {\n throw new Error(\"the agent must be defined and not null\");\n }\n\n // Parse the behaviour tree definition, create the populated tree of behaviour tree nodes, and get the root.\n this.rootNode = BehaviourTree._createRootNode(definition);\n }\n\n /**\n * Gets whether the tree is in the RUNNING state.\n * @returns true if the tree is in the RUNNING state, otherwise false.\n */\n isRunning() {\n return this.rootNode.getState() === State.RUNNING;\n }\n\n /**\n * Gets the current tree state of SUCCEEDED, FAILED, READY or RUNNING.\n * @returns The current tree state.\n */\n getState() {\n return this.rootNode.getState();\n }\n\n /**\n * Step the tree.\n * 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.\n * 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\n * 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.\n *\n * 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.\n */\n step() {\n // If the root node has already been stepped to completion then we need to reset it.\n if (this.rootNode.getState() === State.SUCCEEDED || this.rootNode.getState() === State.FAILED) {\n this.rootNode.reset();\n }\n\n try {\n this.rootNode.update(this.agent, this.options);\n } catch (exception) {\n throw new Error(`error stepping tree: ${(exception as Error).message}`);\n }\n }\n\n /**\n * Resets the tree from the root node outwards to each nested node, giving each a state of READY.\n */\n reset() {\n this.rootNode.reset();\n }\n\n /**\n * Gets the flattened details of every node in the tree.\n * @returns The flattened details of every node in the tree.\n */\n getFlattenedNodeDetails(): FlattenedTreeNode[] {\n // Create an empty flattened array of tree nodes.\n const flattenedTreeNodes: FlattenedTreeNode[] = [];\n\n /**\n * Helper function to process a node instance and push details into the flattened tree nodes array.\n * @param node The current node.\n * @param parentUid The UID of the node parent, or null if the node is the main root node.\n */\n const processNode = (node: Node, parentUid: string | null) => {\n // Get the guard and callback attribute details for this node.\n const guards = node\n .getAttributes()\n .filter((attribute) => attribute.isGuard())\n .map((attribute) => attribute.getDetails()) as GuardAttributeDetails[];\n const callbacks = node\n .getAttributes()\n .filter((attribute) => !attribute.isGuard())\n .map((attribute) => attribute.getDetails()) as CallbackAttributeDetails[];\n\n // Push the current node into the flattened nodes array.\n flattenedTreeNodes.push({\n id: node.getUid(),\n type: node.getType(),\n caption: node.getName(),\n state: node.getState(),\n guards,\n callbacks,\n args: node.getArguments(),\n parentId: parentUid\n });\n\n // Process each of the nodes children if it is not a leaf node.\n if (!node.isLeafNode()) {\n (node as Composite | Decorator)\n .getChildren()\n .forEach((child) => processNode(child, (node as Composite | Decorator).getUid()));\n }\n };\n\n // Convert the nested node structure into a flattened array of node details.\n processNode(this.rootNode, null);\n\n return flattenedTreeNodes;\n }\n\n /**\n * Registers the action/condition/guard/callback function or subtree with the given name.\n * @param name The name of the function or subtree to register.\n * @param value The function or subtree definition to register.\n */\n static register(name: string, value: GlobalFunction | string) {\n if (typeof value === \"function\") {\n // We are going to register a action/condition/guard/callback function.\n Lookup.setFunc(name, value);\n } else if (typeof value === \"string\") {\n // We are going to register a subtree.\n let rootASTNodes: RootAstNode[];\n\n try {\n // Try to create the behaviour tree AST based on the definition provided, this could fail if the definition is invalid.\n rootASTNodes = buildRootASTNodes(value);\n } catch (exception) {\n // There was an issue in trying to parse and build the tree definition.\n throw new Error(`error registering definition: ${(exception as Error).message}`);\n }\n\n // This function should only ever be called with a definition containing a single unnamed root node.\n if (rootASTNodes.length != 1 || rootASTNodes[0].name !== null) {\n throw new Error(\"error registering definition: expected a single unnamed root node\");\n }\n\n Lookup.setSubtree(name, rootASTNodes[0]);\n } else {\n throw new Error(\"unexpected value, expected string definition or function\");\n }\n }\n\n /**\n * Unregisters the registered action/condition/guard/callback function or subtree with the given name.\n * @param name The name of the registered action/condition/guard/callback function or subtree to unregister.\n */\n static unregister(name: string): void {\n Lookup.remove(name);\n }\n\n /**\n * Unregister all registered action/condition/guard/callback functions and subtrees.\n */\n static unregisterAll(): void {\n Lookup.empty();\n }\n\n /**\n * Parses a behaviour tree definition and creates a tree of behaviour tree nodes.\n * @param {string} definition The behaviour tree definition.\n * @returns The root behaviour tree node.\n */\n private static _createRootNode(definition: string): Root {\n // TODO Remove!\n try {\n // parseToJSON(definition);\n } catch (exception) {\n console.log(exception);\n }\n\n try {\n // Try to create the behaviour tree AST based on the definition provided, this could fail if the definition is invalid.\n const rootASTNodes = buildRootASTNodes(definition);\n\n // Create a symbol to use as the main root key in our root node mapping.\n const mainRootNodeKey = Symbol(\"__root__\");\n\n // Create a mapping of root node names to root AST tokens. The main root node will have a key of Symbol(\"__root__\").\n const rootNodeMap: { [key: string | symbol]: RootAstNode } = {};\n for (const rootASTNode of rootASTNodes) {\n rootNodeMap[rootASTNode.name === null ? mainRootNodeKey : rootASTNode.name!] = rootASTNode;\n }\n\n // Convert the AST to our actual tree and get the root node.\n const rootNode: Root = rootNodeMap[mainRootNodeKey].createNodeInstance(\n // Create a provider for named root nodes that are part of our definition or have been registered. Prioritising the former.\n (name: string): RootAstNode => (rootNodeMap[name] ? rootNodeMap[name] : Lookup.getSubtree(name)),\n []\n );\n\n // Set a guard path on every leaf of the tree to evaluate as part of its update.\n BehaviourTree._applyLeafNodeGuardPaths(rootNode);\n\n // Return the root node.\n return rootNode;\n } catch (exception) {\n // There was an issue in trying to parse and build the tree definition.\n throw new Error(`error parsing tree: ${(exception as Error).message}`);\n }\n }\n\n /**\n * Applies a guard path to every leaf of the tree to evaluate as part of each update.\n * @param rootNode The main root tree node.\n */\n private static _applyLeafNodeGuardPaths(rootNode: Root) {\n const nodePaths: Node[][] = [];\n\n const findLeafNodes = (path: Node[], node: Node) => {\n // Add the current node to the path.\n path = path.concat(node);\n\n // Check whether the current node is a leaf node.\n if (node.isLeafNode()) {\n nodePaths.push(path);\n } else {\n (node as Composite | Decorator).getChildren().forEach((child) => findLeafNodes(path, child));\n }\n };\n\n // Find all leaf node paths, starting from the root.\n findLeafNodes([], rootNode);\n\n nodePaths.forEach((path) => {\n // Each node in the current path will have to be assigned a guard path, working from the root outwards.\n for (let depth = 0; depth < path.length; depth++) {\n // Get the node in the path at the current depth.\n const currentNode = path[depth];\n\n // The node may already have been assigned a guard path, if so just skip it.\n if (currentNode.hasGuardPath()) {\n continue;\n }\n\n // Create the guard path for the current node.\n const guardPath = new GuardPath(\n path\n .slice(0, depth + 1)\n .map((node) => ({ node, guards: node.getGuardAttributes() }))\n .filter((details) => details.guards.length > 0)\n );\n\n // Assign the guard path to the current node.\n currentNode.setGuardPath(guardPath);\n }\n });\n }\n}\n"], + "mappings": "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", "names": ["Participant", "Lotto", "createLotto", "State", "createLotto", "substituteStringLiterals", "parseTokensFromDefinition", "popAndCheck", "getArgumentDefinition"] } diff --git a/src/BehaviourTreeDefinitionValidator.ts b/src/BehaviourTreeDefinitionValidator.ts index 06ea53d..fed4baf 100644 --- a/src/BehaviourTreeDefinitionValidator.ts +++ b/src/BehaviourTreeDefinitionValidator.ts @@ -46,27 +46,7 @@ export function validateDefinition(definition: any): DefinitionValidationResult } } else if (typeof definition === "object") { // The definition will either be an array (of root node definitions) or an object (the single primary root node definition). - // If our definition is an array, we should verify that each of the elements within it are objects (potential root node definitions). - if (Array.isArray(definition)) { - // Find any invalid node definitions in our definition array, not full validation just a check that each is a valid object. - const invalidDefinitionElements = definition.filter((element) => { - // Each element isn't valid unless it is an object that isn't also an array and isn't null. - return typeof element !== "object" || Array.isArray(element) || element === null; - }); - - // If we have any invalid node definitions then validation has failed. - if (invalidDefinitionElements.length) { - return createFailureResult( - "invalid elements in definition array, each must be an root node definition object" - ); - } - - // Our definition is already an array of root node definition objects. - rootNodeDefinitions = definition; - } else { - // Our definition is an object, but we want an array of root node definitions. - rootNodeDefinitions = [definition]; - } + rootNodeDefinitions = Array.isArray(definition) ? definition : [definition]; } else { return createFailureResult(`unexpected definition type of '${typeof definition}'`); } @@ -145,7 +125,7 @@ function findBranchCircularDependencyPath(rootNodeDefinitions: RootNodeDefinitio const badPath = [...path, mapping.id]; // Set the formatted path value. [undefined, "a", "b", "c", "a"] would be formatted as "a -> b -> c -> a". - badPathFormatted = badPath.map((element) => !!element).join(" => "); + badPathFormatted = badPath.filter((element) => !!element).join(" => "); // No need to continue, we found a circular dependency. return; @@ -162,6 +142,9 @@ function findBranchCircularDependencyPath(rootNodeDefinitions: RootNodeDefinitio } }; + // Start looking for circular dependencies from the root. + followRefs(rootNodeMappings.find((mapping) => typeof mapping.id === "undefined")!); + return badPathFormatted; } diff --git a/test/BehaviourTreeDefinitionValidator.test.js b/test/BehaviourTreeDefinitionValidator.test.js index c382f5c..95cd9b7 100644 --- a/test/BehaviourTreeDefinitionValidator.test.js +++ b/test/BehaviourTreeDefinitionValidator.test.js @@ -3,8 +3,130 @@ const chai = require("chai"); var assert = chai.assert; -describe("The validateDefinition function", () => { - it("does stuff", () => { - assert.strictEqual(JSON.stringify(mistreevous.validateDefinition("root {}")), "Hello!"); +describe("The validateDefinition function takes a tree definition as an argument and", () => { + // Helper function to carry out the validation and verify the expected result. + const verifyResult = (definition, success, errorMessage) => { + // Do the actual validation. + const result = mistreevous.validateDefinition(definition); + + // Verify the result matches the expected succeeded state and error message. + assert.deepEqual(result, success ? { succeeded: true } : { succeeded: false, errorMessage }); + }; + + describe("where the type of that definition is", () => { + describe("mdsl", () => { + // TODO Add better validation to mdsl parsing to better match the json validation. + }); + + describe("json", () => { + describe("returns a validation failure when", () => { + it("the definition doesn't contain a main root node (has no root node identifier defined)", () => { + const definition = { + id: "not-main-root", + type: "root", + child: { + type: "action", + call: "noop" + } + }; + + // The definition can be either an array (of root node definitions) or an object (the single primary root node definition), verify both. + verifyResult( + definition, + false, + "expected single root node without 'id' property defined to act as main root" + ); + verifyResult( + [definition], + false, + "expected single root node without 'id' property defined to act as main root" + ); + }); + + it("there are duplicate root node identifiers", () => { + verifyResult( + [ + { + type: "root", + child: { + type: "action", + call: "noop" + } + }, + { + id: "sub-root-node", + type: "root", + child: { + type: "action", + call: "noop" + } + }, + { + id: "sub-root-node", + type: "root", + child: { + type: "action", + call: "noop" + } + } + ], + false, + "multiple root nodes found with duplicate 'id' property value of 'sub-root-node'" + ); + }); + + it("there are circular dependencies found in any branch node references", () => { + verifyResult( + [ + { + type: "root", + child: { + type: "branch", + ref: "RN_A" + } + }, + { + id: "RN_A", + type: "root", + child: { + type: "branch", + ref: "RN_B" + } + }, + { + id: "RN_B", + type: "root", + child: { + type: "branch", + ref: "RN_C" + } + }, + { + id: "RN_C", + type: "root", + child: { + type: "branch", + ref: "RN_A" + } + } + ], + false, + "circular dependency found in branch node references: RN_A => RN_B => RN_C => RN_A" + ); + }); + }); + }); + }); + + describe("returns a validation failure when the definition is", () => { + it("null", () => verifyResult(null, false, "definition is null or undefined")); + + it("undefined", () => verifyResult(undefined, false, "definition is null or undefined")); + + it("an unexpected type", () => { + verifyResult(true, false, "unexpected definition type of 'boolean'"); + verifyResult(false, false, "unexpected definition type of 'boolean'"); + verifyResult(42, false, "unexpected definition type of 'number'"); + }); }); }); diff --git a/test/mdsl/MDSLDefinitionParser.test.js b/test/mdsl/MDSLDefinitionParser.test.js index 1805d66..ca4a6f9 100644 --- a/test/mdsl/MDSLDefinitionParser.test.js +++ b/test/mdsl/MDSLDefinitionParser.test.js @@ -5,6 +5,6 @@ var assert = chai.assert; describe("The convertMDSLToJSON function", () => { it("does stuff", () => { - assert.strictEqual(mistreevous.convertMDSLToJSON("root {}"), JSON.stringify([{ type: "root" }])); + // assert.strictEqual(mistreevous.convertMDSLToJSON("root {}"), JSON.stringify([{ type: "root" }])); }); }); From fca74d80576a51bb8f4e7938690f65774509e8c2 Mon Sep 17 00:00:00 2001 From: Nikolas Howard Date: Wed, 31 Jan 2024 13:04:49 +0000 Subject: [PATCH 18/48] working on definition validator --- dist/BehaviourTreeDefinitionValidator.d.ts | 13 +++ dist/bundle.js | 65 +++++++++--- dist/bundle.js.map | 4 +- dist/index.js | 65 +++++++++--- dist/index.js.map | 4 +- src/BehaviourTreeDefinitionValidator.ts | 118 ++++++++++++++++----- 6 files changed, 211 insertions(+), 58 deletions(-) diff --git a/dist/BehaviourTreeDefinitionValidator.d.ts b/dist/BehaviourTreeDefinitionValidator.d.ts index 4c812e5..a5de380 100644 --- a/dist/BehaviourTreeDefinitionValidator.d.ts +++ b/dist/BehaviourTreeDefinitionValidator.d.ts @@ -1,3 +1,4 @@ +import { RootNodeDefinition } from "./BehaviourTreeDefinition"; /** * An object representing the result of validating a tree definition. */ @@ -17,3 +18,15 @@ export type DefinitionValidationResult = { * @returns An object representing the result of validating the given tree definition. */ export declare function validateDefinition(definition: any): DefinitionValidationResult; +/** + * Validates the specified behaviour tree definition in the form of MDSL. + * @param definition The behaviour tree definition in the form of MDSL. + * @returns An object representing the result of validating the given tree definition. + */ +export declare function validateMDSLDefinition(definition: string): DefinitionValidationResult; +/** + * Validates the specified behaviour tree definition in the form of JSON. + * @param definition The behaviour tree definition in the form of JSON. + * @returns An object representing the result of validating the given tree definition. + */ +export declare function validateJSONDefinition(definition: RootNodeDefinition | RootNodeDefinition[]): DefinitionValidationResult; diff --git a/dist/bundle.js b/dist/bundle.js index 4376af4..e3bc0d0 100644 --- a/dist/bundle.js +++ b/dist/bundle.js @@ -722,45 +722,77 @@ var mistreevous = (() => { // src/BehaviourTreeDefinitionValidator.ts function validateDefinition(definition) { - const createFailureResult = (errorMessage) => ({ succeeded: false, errorMessage }); if (definition === null || typeof definition === "undefined") { - return createFailureResult("definition is null or undefined"); + return createValidationFailureResult("definition is null or undefined"); } - let rootNodeDefinitions; if (typeof definition === "string") { - try { - rootNodeDefinitions = convertMDSLToJSON(definition); - } catch (error) { - return createFailureResult(`invalid mdsl: ${definition}`); - } + return validateMDSLDefinition(definition); } else if (typeof definition === "object") { - rootNodeDefinitions = Array.isArray(definition) ? definition : [definition]; + return validateJSONDefinition(definition); } else { - return createFailureResult(`unexpected definition type of '${typeof definition}'`); + return createValidationFailureResult(`unexpected definition type of '${typeof definition}'`); + } + } + function validateMDSLDefinition(definition) { + let rootNodeDefinitions; + try { + rootNodeDefinitions = convertMDSLToJSON(definition); + } catch (error) { + return createValidationFailureResult(`invalid MDSL: ${definition}`); + } + const mainRootNodeDefinitions = rootNodeDefinitions.filter(({ id }) => typeof id === "undefined"); + const subRootNodeDefinitions = rootNodeDefinitions.filter(({ id }) => typeof id === "string" && id.length > 0); + if (mainRootNodeDefinitions.length !== 1) { + return createValidationFailureResult( + "expected single unnamed root node at base of definition to act as main root" + ); + } + const subRootNodeIdenitifers = []; + for (const { id } of subRootNodeDefinitions) { + if (subRootNodeIdenitifers.includes(id)) { + return createValidationFailureResult(`multiple root nodes found with duplicate name '${id}'`); + } + subRootNodeIdenitifers.push(id); } + const circularDependencyPath = findBranchCircularDependencyPath(rootNodeDefinitions); + if (circularDependencyPath) { + return createValidationFailureResult( + `circular dependency found in branch node references: ${circularDependencyPath}` + ); + } + return { succeeded: true }; + } + function validateJSONDefinition(definition) { + const rootNodeDefinitions = Array.isArray(definition) ? definition : [definition]; try { rootNodeDefinitions.forEach((rootNodeDefinition) => validateNode(rootNodeDefinition, 0)); } catch (error) { if (error instanceof Error) { - return createFailureResult(error.message); + return createValidationFailureResult(error.message); } - return createFailureResult(`unexpected error: ${error}`); + return createValidationFailureResult(`unexpected error: ${error}`); } const mainRootNodeDefinitions = rootNodeDefinitions.filter(({ id }) => typeof id === "undefined"); const subRootNodeDefinitions = rootNodeDefinitions.filter(({ id }) => typeof id === "string" && id.length > 0); if (mainRootNodeDefinitions.length !== 1) { - return createFailureResult("expected single root node without 'id' property defined to act as main root"); + return createValidationFailureResult( + "expected single root node without 'id' property defined to act as main root" + ); } const subRootNodeIdenitifers = []; for (const { id } of subRootNodeDefinitions) { if (subRootNodeIdenitifers.includes(id)) { - return createFailureResult(`multiple root nodes found with duplicate 'id' property value of '${id}'`); + return createValidationFailureResult( + `multiple root nodes found with duplicate 'id' property value of '${id}'` + ); } subRootNodeIdenitifers.push(id); } const circularDependencyPath = findBranchCircularDependencyPath(rootNodeDefinitions); if (circularDependencyPath) { - return createFailureResult(`circular dependency found in branch node references: ${circularDependencyPath}`); + return createValidationFailureResult( + `circular dependency found in branch node references: ${circularDependencyPath}` + ); } return { succeeded: true }; } @@ -1051,6 +1083,9 @@ var mistreevous = (() => { validateNodeAttributes(definition, depth); definition.children.forEach((child) => validateNode(child, depth + 1)); } + function createValidationFailureResult(errorMessage) { + return { succeeded: false, errorMessage }; + } // src/attributes/guards/GuardUnsatisifedException.ts var GuardUnsatisifedException = class extends Error { diff --git a/dist/bundle.js.map b/dist/bundle.js.map index 833bdeb..b3528a0 100644 --- a/dist/bundle.js.map +++ b/dist/bundle.js.map @@ -1,7 +1,7 @@ { "version": 3, "sources": ["../node_modules/lotto-draw/dist/Participant.js", "../node_modules/lotto-draw/dist/Utilities.js", "../node_modules/lotto-draw/dist/Lotto.js", "../node_modules/lotto-draw/dist/createLotto.js", "../node_modules/lotto-draw/dist/index.js", "../src/index.ts", "../src/State.ts", "../src/BehaviourTreeDefinitionUtilities.ts", "../src/mdsl/MDSLUtilities.ts", "../src/mdsl/MDSLNodeArgumentParser.ts", "../src/mdsl/MDSLNodeAttributeParser.ts", "../src/mdsl/MDSLDefinitionParser.ts", "../src/BehaviourTreeDefinitionValidator.ts", "../src/attributes/guards/GuardUnsatisifedException.ts", "../src/attributes/guards/GuardPath.ts", "../src/nodes/Node.ts", "../src/nodes/leaf/Leaf.ts", "../src/Lookup.ts", "../src/nodes/leaf/Action.ts", "../src/nodes/leaf/Condition.ts", "../src/nodes/leaf/Wait.ts", "../src/nodes/decorator/Decorator.ts", "../src/nodes/decorator/Root.ts", "../src/nodes/decorator/Repeat.ts", "../src/nodes/decorator/Retry.ts", "../src/nodes/decorator/Flip.ts", "../src/nodes/decorator/Succeed.ts", "../src/nodes/decorator/Fail.ts", "../src/nodes/composite/Lotto.ts", "../src/nodes/composite/Composite.ts", "../src/nodes/composite/Selector.ts", "../src/nodes/composite/Sequence.ts", "../src/nodes/composite/Parallel.ts", "../src/attributes/Attribute.ts", "../src/attributes/guards/Guard.ts", "../src/attributes/guards/While.ts", "../src/attributes/guards/Until.ts", "../src/attributes/callbacks/Callback.ts", "../src/attributes/callbacks/Entry.ts", "../src/attributes/callbacks/Exit.ts", "../src/attributes/callbacks/Step.ts", "../src/RootAstNodesBuilder.ts", "../src/BehaviourTree.ts"], - "sourcesContent": ["\"use strict\";\r\nObject.defineProperty(exports, \"__esModule\", { value: true });\r\nexports.Participant = void 0;\r\n/**\r\n * A participant that holds a number of tickets.\r\n */\r\nvar Participant = /** @class */ (function () {\r\n /**\r\n * Creates an instance of the Participant class.\r\n * @param participant The actual participant.\r\n * @param tickets The number of tickets held by the participant.\r\n */\r\n function Participant(participant, tickets) {\r\n if (tickets === void 0) { tickets = 1; }\r\n this._participant = participant;\r\n this._tickets = tickets;\r\n }\r\n Object.defineProperty(Participant.prototype, \"participant\", {\r\n /** Gets the actual participant. */\r\n get: function () {\r\n return this._participant;\r\n },\r\n enumerable: false,\r\n configurable: true\r\n });\r\n Object.defineProperty(Participant.prototype, \"tickets\", {\r\n /** Gets or sets the number of tickets held by the participant. */\r\n get: function () {\r\n return this._tickets;\r\n },\r\n set: function (value) {\r\n this._tickets = value;\r\n },\r\n enumerable: false,\r\n configurable: true\r\n });\r\n return Participant;\r\n}());\r\nexports.Participant = Participant;\r\n", "\"use strict\";\r\nObject.defineProperty(exports, \"__esModule\", { value: true });\r\nexports.isNaturalNumber = exports.isNullOrUndefined = void 0;\r\n/**\r\n * Gets whether the value provided is null or undefined.\r\n * @param value The value to check.\r\n * @returns Whether the value provided is null or undefined.\r\n */\r\nfunction isNullOrUndefined(value) {\r\n return value === null || value === undefined;\r\n}\r\nexports.isNullOrUndefined = isNullOrUndefined;\r\n/**\r\n * Gets whether the value provided is a natural number.\r\n * @param value The value to check.\r\n * @returns Whether the value provided is a natural number.\r\n */\r\nfunction isNaturalNumber(value) {\r\n return typeof value === \"number\" && value >= 1 && Math.floor(value) === value;\r\n}\r\nexports.isNaturalNumber = isNaturalNumber;\r\n", "\"use strict\";\r\nObject.defineProperty(exports, \"__esModule\", { value: true });\r\nexports.Lotto = void 0;\r\nvar Participant_1 = require(\"./Participant\");\r\nvar Utilities_1 = require(\"./Utilities\");\r\n/**\r\n * Represents a lotto consisting of a number of pickable ticket-holding participants.\r\n */\r\nvar Lotto = /** @class */ (function () {\r\n /**\r\n * Creates a new instance of Lotto.\r\n * @param customRandom The custom RNG to use in place of Math.random().\r\n */\r\n function Lotto(customRandom) {\r\n /** The array of participants that are holding tickets in the lotto. */\r\n this._participants = [];\r\n this._customRandom = customRandom;\r\n }\r\n /**\r\n * Adds a participant with the specified number of tickets, or adds to the participant ticket count if the participant already holds tickets.\r\n * @param participant The participant to add or to increase the ticket count for if they already hold tickets.\r\n * @param tickets The number of tickets, defaults to 1.\r\n * @returns The Lotto instance.\r\n */\r\n Lotto.prototype.add = function (participant, tickets) {\r\n if (tickets === void 0) { tickets = 1; }\r\n // Check that we have a valid ticket count.\r\n if (!(0, Utilities_1.isNaturalNumber)(tickets)) {\r\n throw new Error(\"tickets value must be a natural number\");\r\n }\r\n // Check whether this participant has already been added.\r\n var existingParticipant = this._participants.find(function (part) { return part.participant === participant; });\r\n if (existingParticipant) {\r\n // The participant has already been added to the lotto so just add to their ticket count.\r\n existingParticipant.tickets += tickets;\r\n }\r\n else {\r\n // The participant is not part of the lotto so we should add them.\r\n this._participants.push(new Participant_1.Participant(participant, tickets));\r\n }\r\n return this;\r\n };\r\n /**\r\n * Removes the specified number of tickets for the given participant from the draw, or all tickets if a ticket number is not defined.\r\n * @param participant The participant to remove tickets for.\r\n * @param tickets The number of tickets to remove, or undefined if all tickets are to be removed.\r\n * @returns The Lotto instance.\r\n */\r\n Lotto.prototype.remove = function (participant, tickets) {\r\n // Attempt to get the existing participant.\r\n var existingParticipant = this._participants.find(function (part) { return part.participant === participant; });\r\n // There is nothing to do if the specified participant isn't even part of the lotto.\r\n if (!existingParticipant) {\r\n return this;\r\n }\r\n // Check whether a tickets value was given.\r\n if (tickets !== undefined) {\r\n // Check that we have a valid ticket count.\r\n if (!(0, Utilities_1.isNaturalNumber)(tickets)) {\r\n throw new Error(\"tickets value must be a natural number\");\r\n }\r\n existingParticipant.tickets -= tickets;\r\n // If the participant no longer holds any tickets then they should be removed.\r\n if (existingParticipant.tickets < 1) {\r\n this._participants = this._participants.filter(function (part) { return part !== existingParticipant; });\r\n }\r\n }\r\n else {\r\n // We are removing all tickets for the participant so just remove them from the lotto.\r\n this._participants = this._participants.filter(function (part) { return part !== existingParticipant; });\r\n }\r\n return this;\r\n };\r\n /**\r\n * Draw a winning ticket and return the participant that holds the ticket.\r\n * @param options The draw options.\r\n * @returns The participant that holds the winning ticket.\r\n */\r\n Lotto.prototype.draw = function (options) {\r\n if (options === void 0) { options = {}; }\r\n // If we have no participants then just return null.\r\n if (this._participants.length === 0) {\r\n return null;\r\n }\r\n var redrawable = (0, Utilities_1.isNullOrUndefined)(options.redrawable) ? true : options.redrawable;\r\n var pickable = [];\r\n this._participants.forEach(function (_a) {\r\n var participant = _a.participant, tickets = _a.tickets;\r\n for (var ticketCount = 0; ticketCount < tickets; ticketCount++) {\r\n pickable.push(participant);\r\n }\r\n });\r\n var random;\r\n // We need a random floating-point number between 0 (inclusive) and 1 to scale up to pick our winner.\r\n // If a custom random function exists then we should use that or fall back to Math.random().\r\n if (this._customRandom) {\r\n // Call our custom random function to get a random floating-point number.\r\n random = this._customRandom();\r\n // Verify that the result of calling our custom random function is a number between 0 (inclusive) and 1.\r\n if (typeof random !== \"number\" || random < 0 || random >= 1) {\r\n throw new Error(\"the 'random' function provided did not return a number between 0 (inclusive) and 1\");\r\n }\r\n }\r\n else {\r\n // No custom random function was defined so just use good ol' Math.random().\r\n random = Math.random();\r\n }\r\n // Pick a winning participant.\r\n var winner = pickable[Math.floor(random * pickable.length)];\r\n // If the ticket isn't redrawable then we should remove a ticket from the winning participants ticket count.\r\n if (!redrawable) {\r\n this.remove(winner, 1);\r\n }\r\n // Return the winning participant.\r\n return winner;\r\n };\r\n /**\r\n * Draws multiple winning tickets and return an array of the participants that hold the winning tickets.\r\n * @param tickets The number of winning tickets to draw.\r\n * @param options The draw multiple options.\r\n * @returns An array of the participants that hold the winning tickets.\r\n */\r\n Lotto.prototype.drawMultiple = function (tickets, options) {\r\n if (options === void 0) { options = {}; }\r\n var uniqueResults = (0, Utilities_1.isNullOrUndefined)(options.unique) ? false : options.unique;\r\n // Handle cases where the user has asked for zero tickets (no idea why they would do this be we should trust them).\r\n if (tickets === 0) {\r\n return [];\r\n }\r\n // Now that we know out tickets value is not zero we should check that it is a valid natural number.\r\n if (!(0, Utilities_1.isNaturalNumber)(tickets)) {\r\n throw new Error(\"tickets value must be a natural number\");\r\n }\r\n var result = [];\r\n // Keep drawing tickets until we either reach the number of required tickets or we simply run out of tickets to draw.\r\n // We can run out of tickets to draw if 'options.redrawable' is explicity 'false' or we just had no participants when 'drawMultiple' was called.\r\n while (result.length < tickets && this._participants.length > 0) {\r\n result.push(this.draw(options));\r\n }\r\n // If the 'unique' draw option is set then we need to remove duplicates from the result list.\r\n if (uniqueResults) {\r\n // Create an array to store our unique results.\r\n var unique = [];\r\n // Iterate over all of our participants (with potential duplicates) and populate our array of unique values.\r\n for (var _i = 0, result_1 = result; _i < result_1.length; _i++) {\r\n var participant = result_1[_i];\r\n if (unique.indexOf(participant) === -1) {\r\n unique.push(participant);\r\n }\r\n }\r\n result = unique;\r\n }\r\n return result;\r\n };\r\n return Lotto;\r\n}());\r\nexports.Lotto = Lotto;\r\n", "\"use strict\";\r\nObject.defineProperty(exports, \"__esModule\", { value: true });\r\nexports.createLotto = void 0;\r\nvar Lotto_1 = require(\"./Lotto\");\r\n/**\r\n * A function that creates and returns a Lotto instance.\r\n * @param participantsOrOptions An array of initial participants or options relating to the creation of a Lotto instance.\r\n * @returns A new Lotto instance.\r\n */\r\nfunction createLotto(participantsOrOptions) {\r\n // If no initial participants or lotto options were provided as an argument then we can just return a new lotto instance now.\r\n if (!participantsOrOptions) {\r\n return new Lotto_1.Lotto();\r\n }\r\n // Check whether we were provided with an array of initial participants or a lotto options object.\r\n if (Array.isArray(participantsOrOptions)) {\r\n // We are dealing with a pre-defined array of participants.\r\n var participants = participantsOrOptions;\r\n var lotto_1 = new Lotto_1.Lotto();\r\n // If the lotto participants have been defined upfront then we will need to add them all to our lotto instance now.\r\n participants.forEach(function (_a) {\r\n var participant = _a[0], tokens = _a[1];\r\n return lotto_1.add(participant, tokens);\r\n });\r\n // Return the Lotto instance.\r\n return lotto_1;\r\n }\r\n else {\r\n // We are dealing with some lotto options.\r\n var random = participantsOrOptions.random, participants = participantsOrOptions.participants;\r\n // Create a Lotto instance passing the custom RNG function to use in place of Math.random() (which could be undefined).\r\n var lotto_2 = new Lotto_1.Lotto(random);\r\n // If the lotto participants have been defined upfront as part of the options then we will need to add them all to our lotto instance now.\r\n if (participants) {\r\n participants.forEach(function (_a) {\r\n var participant = _a[0], tokens = _a[1];\r\n return lotto_2.add(participant, tokens);\r\n });\r\n }\r\n // Return the Lotto instance.\r\n return lotto_2;\r\n }\r\n}\r\nexports.createLotto = createLotto;\r\n", "\"use strict\";\r\nObject.defineProperty(exports, \"__esModule\", { value: true });\r\nvar createLotto_1 = require(\"./createLotto\");\r\nexports.default = createLotto_1.createLotto;\r\n", "import State from \"./State\";\nimport { validateDefinition } from \"./BehaviourTreeDefinitionValidator\";\nimport { convertMDSLToJSON } from \"./mdsl/MDSLDefinitionParser\";\nimport { BehaviourTree, FlattenedTreeNode } from \"./BehaviourTree\";\n\nexport { BehaviourTree, State, convertMDSLToJSON, validateDefinition };\nexport type { FlattenedTreeNode };\n", "/**\n * Enumeration of node state types.\n */\nexport enum State {\n READY = \"mistreevous.ready\",\n RUNNING = \"mistreevous.running\",\n SUCCEEDED = \"mistreevous.succeeded\",\n FAILED = \"mistreevous.failed\"\n}\n\nexport { State as default };\n\nexport type CompleteState = State.SUCCEEDED | State.FAILED;\nexport type AnyState = State.READY | State.RUNNING | CompleteState;\n", "import {\n NodeDefinition,\n RootNodeDefinition,\n DecoratorNodeDefinition,\n CompositeNodeDefinition,\n AnyNode,\n BranchNodeDefinition\n} from \"./BehaviourTreeDefinition\";\n\n/**\n * A type guard function that returns true if the specified node satisfies the RootNodeDefinition type.\n * @param node The node.\n * @returns A value of true if the specified node satisfies the RootNodeDefinition type.\n */\nexport function isRootNode(node: NodeDefinition): node is RootNodeDefinition {\n return node.type === \"root\";\n}\n\n/**\n * A type guard function that returns true if the specified node satisfies the BranchNodeDefinition type.\n * @param node The node.\n * @returns A value of true if the specified node satisfies the BranchNodeDefinition type.\n */\nexport function isBranchNode(node: NodeDefinition): node is BranchNodeDefinition {\n return node.type === \"branch\";\n}\n\n/**\n * A type guard function that returns true if the specified node satisfies the NodeDefinition type.\n * @param node The node.\n * @returns A value of true if the specified node satisfies the NodeDefinition type.\n */\nexport function isLeafNode(node: NodeDefinition): node is NodeDefinition {\n return [\"branch\", \"action\", \"condition\", \"wait\"].includes(node.type);\n}\n\n/**\n * A type guard function that returns true if the specified node satisfies the DecoratorNodeDefinition type.\n * @param node The node.\n * @returns A value of true if the specified node satisfies the DecoratorNodeDefinition type.\n */\nexport function isDecoratorNode(node: NodeDefinition): node is DecoratorNodeDefinition {\n return [\"root\", \"repeat\", \"retry\", \"flip\", \"succeed\", \"fail\"].includes(node.type);\n}\n\n/**\n * A type guard function that returns true if the specified node satisfies the CompositeNodeDefinition type.\n * @param node The node.\n * @returns A value of true if the specified node satisfies the CompositeNodeDefinition type.\n */\nexport function isCompositeNode(node: NodeDefinition): node is CompositeNodeDefinition {\n return [\"sequence\", \"selector\", \"lotto\", \"parallel\"].includes(node.type);\n}\n\n/**\n * Flatten a node definition into an array of all of its nested node definitions.\n * @param nodeDefinition The node definition to flatten.\n * @returns An array of all of nested node definitions.\n */\nexport function flattenDefinition(nodeDefinition: AnyNode): AnyNode[] {\n const nodes: AnyNode[] = [];\n\n const processNode = (currentNodeDefinition: AnyNode) => {\n nodes.push(currentNodeDefinition);\n\n if (isCompositeNode(currentNodeDefinition)) {\n currentNodeDefinition.children.forEach(processNode);\n } else if (isDecoratorNode(currentNodeDefinition)) {\n processNode(currentNodeDefinition.child);\n }\n };\n\n processNode(nodeDefinition);\n\n return nodes;\n}\n\n/**\n * Determines whether the passed value is an integer.\n * @param value The value to check.\n * @returns Whether the passed value is an integer.\n */\nexport function isInteger(value: unknown): boolean {\n return typeof value === \"number\" && Math.floor(value) === value;\n}\n", "/**\n * A type defining an object that holds a reference to substitued string literals parsed from the definition.\n */\nexport type StringLiteralPlaceholders = { [key: string]: string };\n\n/**\n * Pop the next raw token from the specified array of tokens and throw an error if it wasn't the expected one.\n * @param tokens The array of tokens.\n * @param expected An optional string or array or items, one of which must match the next popped token.\n * @returns The popped token.\n */\nexport function popAndCheck(tokens: string[], expected?: string | string[]): string {\n // Get and remove the next token.\n const popped = tokens.shift();\n\n // We were expecting another token but there aren't any.\n if (popped === undefined) {\n throw new Error(\"unexpected end of definition\");\n }\n\n // Do we have an expected token/tokens array?\n if (expected != undefined) {\n // Get an array of expected values, if the popped token matches any then we are all good.\n const expectedValues = typeof expected === \"string\" ? [expected] : expected;\n\n // Check whether the popped token matches at least one of our expected items.\n var tokenMatchesExpectation = expectedValues.some((item) => popped.toUpperCase() === item.toUpperCase());\n\n // Throw an error if the popped token didn't match any of our expected items.\n if (!tokenMatchesExpectation) {\n const expectationString = expectedValues.map((item) => \"'\" + item + \"'\").join(\" or \");\n throw new Error(\"unexpected token found. Expected \" + expectationString + \" but got '\" + popped + \"'\");\n }\n }\n\n // Return the popped token.\n return popped;\n}\n\n/**\n * Swaps out any node/attribute argument string literals with placeholders.\n * @param definition The definition.\n * @returns An object containing a mapping of placeholders to original string values as well as the processed definition string.\n */\nexport function substituteStringLiterals(definition: string): {\n placeholders: StringLiteralPlaceholders;\n processedDefinition: string;\n} {\n // Create an object to hold the mapping of placeholders to original string values.\n const placeholders: StringLiteralPlaceholders = {};\n\n // Replace any string literals wrapped with double quotes in our definition with placeholders to be processed later.\n const processedDefinition = definition.replace(/\\\"(\\\\.|[^\"\\\\])*\\\"/g, (match) => {\n var strippedMatch = match.substring(1, match.length - 1);\n var placeholder = Object.keys(placeholders).find((key) => placeholders[key] === strippedMatch);\n\n // If we have no existing string literal match then create a new placeholder.\n if (!placeholder) {\n placeholder = `@@${Object.keys(placeholders).length}@@`;\n placeholders[placeholder] = strippedMatch;\n }\n\n return placeholder;\n });\n\n return { placeholders, processedDefinition };\n}\n\n/**\n * Parse the tree definition into an array of raw tokens.\n * @param definition The definition.\n * @returns An array of tokens parsed from the definition.\n */\nexport function parseTokensFromDefinition(definition: string): string[] {\n // Add some space around various important characters so that they can be plucked out easier as individual tokens.\n definition = definition.replace(/\\(/g, \" ( \");\n definition = definition.replace(/\\)/g, \" ) \");\n definition = definition.replace(/\\{/g, \" { \");\n definition = definition.replace(/\\}/g, \" } \");\n definition = definition.replace(/\\]/g, \" ] \");\n definition = definition.replace(/\\[/g, \" [ \");\n definition = definition.replace(/\\,/g, \" , \");\n\n // Split the definition into raw token form and return it.\n return definition.replace(/\\s+/g, \" \").trim().split(\" \");\n}\n", "import { StringLiteralPlaceholders, popAndCheck } from \"./MDSLUtilities\";\n\nexport type Argument = {\n /** The argument value. */\n value: T;\n /** The argument type, used for validation. */\n type: string;\n};\n\nexport type NullArgument = Argument & {\n type: \"null\";\n};\n\nexport type BooleanArgument = Argument & {\n type: \"boolean\";\n};\n\nexport type NumberArgument = Argument & {\n type: \"number\";\n isInteger: boolean; // Used for validation.\n};\n\nexport type StringPlaceholderArgument = Argument & {\n type: \"string\";\n};\n\nexport type IdentifierArgument = Argument & {\n type: \"identifier\";\n};\n\nexport type AnyArgument =\n | NullArgument\n | BooleanArgument\n | NumberArgument\n | StringPlaceholderArgument\n | IdentifierArgument;\n\n/**\n * Parse an array of argument definitions from the specified tokens array.\n * @param tokens The array tokens to parse the argument definitions from.\n * @param stringArgumentPlaceholders The mapping of string literal node argument placeholders to original values.\n * @param argumentValidator The argument validator function.\n * @param validationFailedMessage The exception message to throw if argument validation fails.\n * @returns An array of argument definitions parsed from the specified tokens array.\n */\nexport function parseArgumentTokens(\n tokens: string[],\n stringArgumentPlaceholders: StringLiteralPlaceholders\n): AnyArgument[] {\n const argumentList: AnyArgument[] = [];\n\n // If the next token is not a '[' or '(' then we have no arguments to parse.\n if (![\"[\", \"(\"].includes(tokens[0])) {\n return argumentList;\n }\n\n // Any lists of arguments will always be wrapped in '[]' for node arguments or '()' for attribute arguments.\n // We are looking for a '[' or '(' opener that wraps the argument tokens and the relevant closer.\n const closingToken = popAndCheck(tokens, [\"[\", \"(\"]) === \"[\" ? \"]\" : \")\";\n\n const argumentListTokens: string[] = [];\n\n // Grab all tokens between the '[' and ']' or '(' and ')'.\n while (tokens.length && tokens[0] !== closingToken) {\n // The next token is part of our arguments list.\n argumentListTokens.push(tokens.shift()!);\n }\n\n // Validate the order of the argument tokens. Each token must either be a ',' or a single argument that satisfies the validator.\n argumentListTokens.forEach((token, index) => {\n // Get whether this token should be an actual argument.\n const shouldBeArgumentToken = !(index & 1);\n\n // If the current token should be an actual argument then validate it, otherwise it should be a ',' token.\n if (shouldBeArgumentToken) {\n // Get the argument definition.\n const argumentDefinition = getArgumentDefinition(token, stringArgumentPlaceholders);\n\n // This is a valid argument!\n argumentList.push(argumentDefinition);\n } else {\n // The current token should be a ',' token.\n if (token !== \",\") {\n throw new Error(`invalid argument list, expected ',' or ']' but got '${token}'`);\n }\n }\n });\n\n // The arguments list should terminate with a ']' or ')' token, depending on the opener.\n popAndCheck(tokens, closingToken);\n\n // Return the arguments.\n return argumentList;\n}\n\n/**\n * Gets an argument value definition.\n * @param token The argument token.\n * @param stringArgumentPlaceholders The mapping of string literal node argument placeholders to original values.\n * @returns An argument value definition.\n */\nfunction getArgumentDefinition(token: string, stringArgumentPlaceholders: StringLiteralPlaceholders): AnyArgument {\n // Check whether the token represents a null value.\n if (token === \"null\") {\n return {\n value: null,\n type: \"null\"\n } as NullArgument;\n }\n\n // Check whether the token represents a boolean value.\n if (token === \"true\" || token === \"false\") {\n return {\n value: token === \"true\",\n type: \"boolean\"\n } as BooleanArgument;\n }\n\n // Check whether the token represents a number value.\n // TODO: Relies on broken isNaN - see MDN.\n // if (!Number.isNaN(token)) {\n if (!isNaN(token as any)) {\n return {\n value: parseFloat(token),\n isInteger: parseFloat(token) === parseInt(token, 10),\n type: \"number\"\n } as NumberArgument;\n }\n\n // Check whether the token is a placeholder (e.g. @@0@@) representing a string literal.\n if (token.match(/^@@\\d+@@$/g)) {\n return {\n value: stringArgumentPlaceholders[token].replace('\\\\\"', '\"'),\n type: \"string\"\n } as StringPlaceholderArgument;\n }\n\n // The only remaining option is that the argument value is an identifier.\n return {\n value: token,\n type: \"identifier\"\n } as IdentifierArgument;\n}\n", "import { NodeAttributeDefinition } from \"../BehaviourTreeDefinition\";\nimport { parseArgumentTokens } from \"./MDSLNodeArgumentParser\";\nimport { StringLiteralPlaceholders } from \"./MDSLUtilities\";\n\n/**\n * A type defining the attribute definitions of a node.\n */\ntype NodeAttributes = {\n while?: NodeAttributeDefinition;\n until?: NodeAttributeDefinition;\n entry?: NodeAttributeDefinition;\n exit?: NodeAttributeDefinition;\n step?: NodeAttributeDefinition;\n};\n\n/**\n * Parse any node attribute definitions from the specified tokens array.\n * @param tokens The array of remaining tokens.\n * @param stringArgumentPlaceholders The mapping of string literal node argument placeholders to original values.\n * @returns An object of attribute definitions defined by any directly following tokens.\n */\nexport function parseAttributeTokens(\n tokens: string[],\n stringArgumentPlaceholders: StringLiteralPlaceholders\n): NodeAttributes {\n const nodeAttributeNames: (keyof NodeAttributes)[] = [\"while\", \"until\", \"entry\", \"exit\", \"step\"];\n\n // Create an object to hold any attributes found.\n const attributes: NodeAttributes = {};\n\n // Try to get the name of the attribute for the next token.\n let nextAttributeName = tokens[0]?.toLowerCase() as keyof NodeAttributes;\n\n // Pull attribute tokens as well as their arguments off of the tokens stack until we have no more.\n while (nodeAttributeNames.includes(nextAttributeName)) {\n // Check to make sure that we have not already created an attribute definition of this type.\n if (attributes[nextAttributeName]) {\n throw new Error(`duplicate attribute '${tokens[0].toUpperCase()}' found for node`);\n }\n\n // Remove the attribute name token from the array of tokens.\n tokens.shift();\n\n // Grab the attribute arguments, assuming the first to be an identifier.\n const [attributeCallIdentifier, ...attributeArguments] = parseArgumentTokens(\n tokens,\n stringArgumentPlaceholders\n );\n\n // The first attribute argument has to be an identifer, this will reference an agent function.\n if (attributeCallIdentifier?.type !== \"identifier\") {\n throw new Error(\"expected agent function name identifier argument for attribute\");\n }\n\n // Any attribute arguments (other than the expected call identifier) must have a type of string, number, boolean or null.\n attributeArguments\n .filter((arg) => arg.type === \"identifier\")\n .forEach((arg) => {\n throw new Error(\n `invalid attribute argument value '${arg.value}', must be string, number, boolean or null`\n );\n });\n\n // Create the attribute definition and add it to the object of attribute definitions found.\n attributes[nextAttributeName] = {\n call: attributeCallIdentifier.value,\n args: attributeArguments.map(({ value }) => value)\n };\n\n // Try to get the next attribute name token, as there could be multiple.\n nextAttributeName = tokens[0]?.toLowerCase() as keyof NodeAttributes;\n }\n\n return attributes;\n}\n", "import {\n ActionNodeDefinition,\n AnyChildNode,\n AnyNode,\n BranchNodeDefinition,\n ConditionNodeDefinition,\n FailNodeDefinition,\n FlipNodeDefinition,\n LottoNodeDefinition,\n ParallelNodeDefinition,\n RepeatNodeDefinition,\n RetryNodeDefinition,\n RootNodeDefinition,\n SelectorNodeDefinition,\n SequenceNodeDefinition,\n SucceedNodeDefinition,\n WaitNodeDefinition\n} from \"../BehaviourTreeDefinition\";\nimport { isCompositeNode, isDecoratorNode, isLeafNode, isRootNode } from \"../BehaviourTreeDefinitionUtilities\";\nimport { parseArgumentTokens } from \"./MDSLNodeArgumentParser\";\nimport { parseAttributeTokens } from \"./MDSLNodeAttributeParser\";\nimport {\n StringLiteralPlaceholders,\n parseTokensFromDefinition,\n popAndCheck,\n substituteStringLiterals\n} from \"./MDSLUtilities\";\n\n/**\n * Convert the MDSL tree definition string into an equivalent JSON definition.\n * @param definition The tree definition string as MDSL.\n * @returns The root node JSON definitions.\n */\nexport function convertMDSLToJSON(definition: string): RootNodeDefinition[] {\n // Swap out any node/attribute argument string literals with a placeholder and get a mapping of placeholders to original values as well as the processed definition.\n const { placeholders, processedDefinition } = substituteStringLiterals(definition);\n\n // Parse our definition definition string into an array of raw tokens.\n const tokens = parseTokensFromDefinition(processedDefinition);\n\n return convertTokensToJSONDefinition(tokens, placeholders);\n}\n\n/**\n * Converts the specified tree definition tokens into a JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The root node JSON definitions.\n */\nfunction convertTokensToJSONDefinition(\n tokens: string[],\n stringLiteralPlaceholders: StringLiteralPlaceholders\n): RootNodeDefinition[] {\n // There must be at least 3 tokens for the tree definition to be valid. 'ROOT', '{' and '}'.\n if (tokens.length < 3) {\n throw new Error(\"invalid token count\");\n }\n\n // We should have a matching number of '{' and '}' tokens. If not, then there are scopes that have not been properly closed.\n if (tokens.filter((token) => token === \"{\").length !== tokens.filter((token) => token === \"}\").length) {\n throw new Error(\"scope character mismatch\");\n }\n\n // Create an array of tree stack arrays where root nodes will always be at the botton and the current composite/decorator node at the top.\n // There should be an element in this array for every root node defined and every element should be an array with a root note as the first element.\n // E.g. A definition with two root nodes defined:\n // [\n // [root, lotto, sequence],\n // [root, selector]\n // ]\n const treeStacks: [Partial, ...Partial[]][] = [];\n\n // Create an array of all root node definitions that we create.\n const rootNodes: Partial[] = [];\n\n // A helper function used to push node definitions onto the tree stack.\n const pushNode = (node: AnyNode) => {\n // If the node is a root node then we need to create a new tree stack array with the root node at the root.\n if (isRootNode(node)) {\n // Add the root node definition to our array of all parsed root node definitions.\n rootNodes.push(node);\n\n // Add the root node definition to the root of a new tree stack.\n treeStacks.push([node]);\n\n return;\n }\n\n // All non-root nodes should be pushed after their root nodes so handle cases\n // where we may not have any tree stacks or our top-most tree stack is empty.\n if (!treeStacks.length || !treeStacks[treeStacks.length - 1].length) {\n throw new Error(\"expected root node at base of definition\");\n }\n\n // Get the current tree stack that we are populating.\n const topTreeStack = treeStacks[treeStacks.length - 1];\n\n // Get the top-most node in the current tree stack, this will be a composite/decorator node\n // for which we will populate its children array if composite or setting its child if a decorator.\n const topTreeStackTopNode = topTreeStack[topTreeStack.length - 1] as AnyNode;\n\n // If the top-most node in the current root stack is a composite or decorator\n // node then the current node should be added as a child of the top-most node.\n if (isCompositeNode(topTreeStackTopNode)) {\n topTreeStackTopNode.children = topTreeStackTopNode.children || [];\n topTreeStackTopNode.children.push(node);\n } else if (isDecoratorNode(topTreeStackTopNode)) {\n // If the top node already has a child node set then throw an error as a decorator should only have a single child.\n if (topTreeStackTopNode.child) {\n throw new Error(\"a decorator node must only have a single child node\");\n }\n\n topTreeStackTopNode.child = node;\n }\n\n // If the node we are adding is also a composite or decorator node, then we should push it\n // onto the current tree stack, as subsequent nodes will be added as its child/children.\n if (!isLeafNode(node)) {\n topTreeStack.push(node);\n }\n };\n\n // A helper function used to pop node definitions off of the stack.\n const popNode = () => {\n // Get the current tree stack that we are populating.\n const topTreeStack = treeStacks[treeStacks.length - 1];\n\n // Pop the top-most node in the current tree stack if there is one.\n if (topTreeStack.length) {\n topTreeStack.pop();\n }\n\n // We don't want any empty tree stacks in our stack of tree stacks.\n if (!topTreeStack.length) {\n treeStacks.pop();\n }\n };\n\n // We should keep processing the raw tokens until we run out of them.\n while (tokens.length) {\n // Grab the next token.\n const token = tokens.shift()!;\n\n // How we create the next node depends on the current raw token value.\n switch (token.toUpperCase()) {\n case \"ROOT\": {\n pushNode(createRootNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"SUCCEED\": {\n pushNode(createSucceedNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"FAIL\": {\n pushNode(createFailNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"FLIP\": {\n pushNode(createFlipNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"REPEAT\": {\n pushNode(createRepeatNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"RETRY\": {\n pushNode(createRetryNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"SEQUENCE\": {\n pushNode(createSequenceNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"SELECTOR\": {\n pushNode(createSelectorNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"PARALLEL\": {\n pushNode(createParallelNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"LOTTO\": {\n pushNode(createLottoNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"ACTION\": {\n pushNode(createActionNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"CONDITION\": {\n pushNode(createConditionNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"WAIT\": {\n pushNode(createWaitNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"BRANCH\": {\n pushNode(createBranchNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"}\": {\n // The '}' character closes the current scope and means that we have to pop a node off of the current stack.\n popNode();\n break;\n }\n\n default: {\n throw new Error(`unexpected token: ${token}`);\n }\n }\n }\n\n return rootNodes as RootNodeDefinition[];\n}\n\n/**\n * Creates a root node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The root node JSON definition.\n */\nfunction createRootNode(tokens: string[], stringLiteralPlaceholders: StringLiteralPlaceholders): RootNodeDefinition {\n // Create the root node definition.\n let node = {\n type: \"root\",\n id: undefined\n } as RootNodeDefinition;\n\n // Parse any node arguments, we should only have one if any which will be an identifier argument for the root identifier.\n const nodeArguments = parseArgumentTokens(tokens, stringLiteralPlaceholders);\n\n // Check whether any node arguments were defined.\n if (nodeArguments.length) {\n // We should only have one argument, if any, which will be an identifier argument for the root identifier.\n if (nodeArguments.length === 1 && nodeArguments[0].type === \"identifier\") {\n // The root node identifier will be the first and only node argument value.\n node.id = nodeArguments[0].value as string;\n } else {\n throw new Error(\"expected single root name argument\");\n }\n }\n\n // Grab any node attribute definitions and spread them into the node definition.\n node = { ...node, ...parseAttributeTokens(tokens, stringLiteralPlaceholders) };\n\n // This is a decorator node, so we expect an opening '{'.\n popAndCheck(tokens, \"{\");\n\n // Return the root node definition.\n return node;\n}\n\n/**\n * Creates a succeed node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The succeed node JSON definition.\n */\nfunction createSucceedNode(\n tokens: string[],\n stringLiteralPlaceholders: StringLiteralPlaceholders\n): SucceedNodeDefinition {\n const node = {\n type: \"succeed\",\n ...parseAttributeTokens(tokens, stringLiteralPlaceholders)\n } as SucceedNodeDefinition;\n\n // This is a decorator node, so we expect an opening '{'.\n popAndCheck(tokens, \"{\");\n\n // Return the succeed node definition.\n return node;\n}\n\n/**\n * Creates a fail node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The fail node JSON definition.\n */\nfunction createFailNode(tokens: string[], stringLiteralPlaceholders: StringLiteralPlaceholders): FailNodeDefinition {\n const node = {\n type: \"fail\",\n ...parseAttributeTokens(tokens, stringLiteralPlaceholders)\n } as FailNodeDefinition;\n\n // This is a decorator node, so we expect an opening '{'.\n popAndCheck(tokens, \"{\");\n\n // Return the fail node definition.\n return node;\n}\n\n/**\n * Creates a flip node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The flip node JSON definition.\n */\nfunction createFlipNode(tokens: string[], stringLiteralPlaceholders: StringLiteralPlaceholders): FlipNodeDefinition {\n const node = {\n type: \"flip\",\n ...parseAttributeTokens(tokens, stringLiteralPlaceholders)\n } as FlipNodeDefinition;\n\n // This is a decorator node, so we expect an opening '{'.\n popAndCheck(tokens, \"{\");\n\n // Return the flip node definition.\n return node;\n}\n\n/**\n * Creates a repeat node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The repeat node JSON definition.\n */\nfunction createRepeatNode(\n tokens: string[],\n stringLiteralPlaceholders: StringLiteralPlaceholders\n): RepeatNodeDefinition {\n let node = { type: \"repeat\" } as RepeatNodeDefinition;\n\n // Get the node arguments.\n const nodeArguments = parseArgumentTokens(tokens, stringLiteralPlaceholders);\n\n // The arguments of a repeat node are optional. We may have:\n // - No node arguments, in which case the repeat note will iterate indefinitely.\n // - One node argument which will be the explicit number of iterations to make.\n // - Two node arguments which define the min and max iteration bounds from which a random iteration count will be picked.\n if (nodeArguments.length) {\n // All repeat node arguments MUST be of type number and must be integer.\n nodeArguments\n .filter((arg) => arg.type !== \"number\" || !arg.isInteger)\n .forEach(() => {\n throw new Error(`repeat node iteration counts must be integer values`);\n });\n\n // We should have got one or two iteration counts.\n if (nodeArguments.length === 1) {\n // A static iteration count was defined.\n node.iterations = nodeArguments[0].value as number;\n } else if (nodeArguments.length === 2) {\n // A minimum and maximum iteration count was defined.\n node.iterations = [nodeArguments[0].value as number, nodeArguments[1].value as number];\n } else {\n // An incorrect number of iteration counts was defined.\n throw new Error(\"invalid number of repeat node iteration count arguments defined\");\n }\n }\n\n // Grab any node attribute definitions and spread them into the node definition.\n node = { ...node, ...parseAttributeTokens(tokens, stringLiteralPlaceholders) };\n\n // This is a decorator node, so we expect an opening '{'.\n popAndCheck(tokens, \"{\");\n\n // Return the repeat node definition.\n return node;\n}\n\n/**\n * Creates a retry node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The retry node JSON definition.\n */\nfunction createRetryNode(tokens: string[], stringLiteralPlaceholders: StringLiteralPlaceholders): RetryNodeDefinition {\n let node = { type: \"retry\" } as RetryNodeDefinition;\n\n // Get the node arguments.\n const nodeArguments = parseArgumentTokens(tokens, stringLiteralPlaceholders);\n\n // The arguments of a retry node are optional. We may have:\n // - No node arguments, in which case the retry note will attempt indefinitely.\n // - One node argument which will be the explicit number of attempts to make.\n // - Two node arguments which define the min and max attempt bounds from which a random attempt count will be picked.\n if (nodeArguments.length) {\n // All retry node arguments MUST be of type number and must be integer.\n nodeArguments\n .filter((arg) => arg.type !== \"number\" || !arg.isInteger)\n .forEach(() => {\n throw new Error(`retry node attempt counts must be integer values`);\n });\n\n // We should have got one or two attempt counts.\n if (nodeArguments.length === 1) {\n // A static attempt count was defined.\n node.attempts = nodeArguments[0].value as number;\n } else if (nodeArguments.length === 2) {\n // A minimum and maximum attempt count was defined.\n node.attempts = [nodeArguments[0].value as number, nodeArguments[1].value as number];\n } else {\n // An incorrect number of attempt counts was defined.\n throw new Error(\"invalid number of retry node attempt count arguments defined\");\n }\n }\n\n // Grab any node attribute definitions and spread them into the node definition.\n node = { ...node, ...parseAttributeTokens(tokens, stringLiteralPlaceholders) };\n\n // This is a decorator node, so we expect an opening '{'.\n popAndCheck(tokens, \"{\");\n\n // Return the retry node definition.\n return node;\n}\n\n/**\n * Creates a sequence node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The sequence node JSON definition.\n */\nfunction createSequenceNode(\n tokens: string[],\n stringLiteralPlaceholders: StringLiteralPlaceholders\n): SequenceNodeDefinition {\n const node = {\n type: \"sequence\",\n ...parseAttributeTokens(tokens, stringLiteralPlaceholders)\n } as SequenceNodeDefinition;\n\n // This is a composite node, so we expect an opening '{'.\n popAndCheck(tokens, \"{\");\n\n // Return the sequence node definition.\n return node;\n}\n\n/**\n * Creates a selector node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The selector node JSON definition.\n */\nfunction createSelectorNode(\n tokens: string[],\n stringLiteralPlaceholders: StringLiteralPlaceholders\n): SelectorNodeDefinition {\n const node = {\n type: \"selector\",\n ...parseAttributeTokens(tokens, stringLiteralPlaceholders)\n } as SelectorNodeDefinition;\n\n // This is a composite node, so we expect an opening '{'.\n popAndCheck(tokens, \"{\");\n\n // Return the selector node definition.\n return node;\n}\n\n/**\n * Creates a parallel node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The parallel node JSON definition.\n */\nfunction createParallelNode(\n tokens: string[],\n stringLiteralPlaceholders: StringLiteralPlaceholders\n): ParallelNodeDefinition {\n const node = {\n type: \"parallel\",\n ...parseAttributeTokens(tokens, stringLiteralPlaceholders)\n } as ParallelNodeDefinition;\n\n // This is a composite node, so we expect an opening '{'.\n popAndCheck(tokens, \"{\");\n\n // Return the parallel node definition.\n return node;\n}\n\n/**\n * Creates a lotto node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The lotto node JSON definition.\n */\nfunction createLottoNode(tokens: string[], stringLiteralPlaceholders: StringLiteralPlaceholders): LottoNodeDefinition {\n // If any node arguments have been defined then they must be our weights.\n const nodeArguments = parseArgumentTokens(tokens, stringLiteralPlaceholders);\n\n // All lotto node arguments MUST be of type number and must be integer.\n nodeArguments\n .filter((arg) => arg.type !== \"number\" || !arg.isInteger)\n .forEach(() => {\n throw new Error(`lotto node weight arguments must be integer values`);\n });\n\n const node = {\n type: \"lotto\",\n weights: nodeArguments.map(({ value }) => value),\n ...parseAttributeTokens(tokens, stringLiteralPlaceholders)\n } as LottoNodeDefinition;\n\n // This is a composite node, so we expect an opening '{'.\n popAndCheck(tokens, \"{\");\n\n // Return the lotto node definition.\n return node;\n}\n\n/**\n * Creates an action node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The action node JSON definition.\n */\nfunction createActionNode(\n tokens: string[],\n stringLiteralPlaceholders: StringLiteralPlaceholders\n): ActionNodeDefinition {\n // Parse any node arguments, we should have at least one which will be an identifier argument for the action name\n // and agent function to invoke for the action, all other arguments are to be passed as arguments to that function.\n const [actionNameIdentifier, ...agentFunctionArgs] = parseArgumentTokens(tokens, stringLiteralPlaceholders);\n\n // Our first argument MUST be defined and be an identifier as we require an action name argument.\n if (actionNameIdentifier?.type !== \"identifier\") {\n throw new Error(\"expected action name identifier argument\");\n }\n\n // Only the first argument should have been an identifier, all agent function arguments must be string, number, boolean or null.\n agentFunctionArgs\n .filter((arg) => arg.type === \"identifier\")\n .forEach((arg) => {\n throw new Error(\n `invalid action node argument value '${arg.value}', must be string, number, boolean or null`\n );\n });\n\n // Return the action node definition.\n return {\n type: \"action\",\n call: actionNameIdentifier.value,\n args: agentFunctionArgs.map(({ value }) => value),\n ...parseAttributeTokens(tokens, stringLiteralPlaceholders)\n };\n}\n\n/**\n * Creates a condition node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The condition node JSON definition.\n */\nfunction createConditionNode(\n tokens: string[],\n stringLiteralPlaceholders: StringLiteralPlaceholders\n): ConditionNodeDefinition {\n // Parse any node arguments, we should have at least one which will be an identifier argument for the condition name\n // and agent function to invoke for the condition, all other arguments are to be passed as arguments to that function.\n const [conditionNameIdentifier, ...agentFunctionArgs] = parseArgumentTokens(tokens, stringLiteralPlaceholders);\n\n // Our first argument MUST be defined and be an identifier as we require a condition name argument.\n if (conditionNameIdentifier?.type !== \"identifier\") {\n throw new Error(\"expected condition name identifier argument\");\n }\n\n // Only the first argument should have been an identifier, all agent function arguments must be string, number, boolean or null.\n agentFunctionArgs\n .filter((arg) => arg.type === \"identifier\")\n .forEach((arg) => {\n throw new Error(\n `invalid condition node argument value '${arg.value}', must be string, number, boolean or null`\n );\n });\n\n // Return the condition node definition.\n return {\n type: \"condition\",\n call: conditionNameIdentifier.value,\n args: agentFunctionArgs.map(({ value }) => value),\n ...parseAttributeTokens(tokens, stringLiteralPlaceholders)\n };\n}\n\n/**\n * Creates a wait node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The wait node JSON definition.\n */\nfunction createWaitNode(tokens: string[], stringLiteralPlaceholders: StringLiteralPlaceholders): WaitNodeDefinition {\n let node = { type: \"wait\" } as WaitNodeDefinition;\n\n // Get the node arguments.\n const nodeArguments = parseArgumentTokens(tokens, stringLiteralPlaceholders);\n\n // The arguments of a wait node are optional. We may have:\n // - No node arguments, in which case the wait will be indefinite until it is aborted.\n // - One node argument which will be the explicit duration of the wait.\n // - Two node arguments which define the min and max duration bounds from which a random duration will be picked.\n if (nodeArguments.length) {\n // All wait node arguments MUST be of type number and must be integer.\n nodeArguments\n .filter((arg) => arg.type !== \"number\" || !arg.isInteger)\n .forEach(() => {\n throw new Error(`wait node duration arguments must be integer values`);\n });\n\n // We may have:\n // - One node argument which will be the explicit duration of the wait.\n // - Two node arguments which define the min and max duration bounds from which a random duration will be picked.\n // - Too many arguments, which is not valid.\n if (nodeArguments.length === 1) {\n // An explicit duration was defined.\n node.duration = nodeArguments[0].value as number;\n } else if (nodeArguments.length === 2) {\n // Min and max duration bounds were defined from which a random duration will be picked.\n node.duration = [nodeArguments[0].value as number, nodeArguments[1].value as number];\n } else if (nodeArguments.length > 2) {\n // An incorrect number of duration arguments were defined.\n throw new Error(\"invalid number of wait node duration arguments defined\");\n }\n }\n\n // Return the wait node definition.\n return { ...node, ...parseAttributeTokens(tokens, stringLiteralPlaceholders) };\n}\n\n/**\n * Creates a branch node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The branch node JSON definition.\n */\nfunction createBranchNode(\n tokens: string[],\n stringLiteralPlaceholders: StringLiteralPlaceholders\n): BranchNodeDefinition {\n // Parse any node arguments, we should have one which will be an identifier argument for the root ref.\n const nodeArguments = parseArgumentTokens(tokens, stringLiteralPlaceholders);\n\n // We should have only a single identifer argument for a branch node, which is the root ref.\n if (nodeArguments.length !== 1 || nodeArguments[0].type !== \"identifier\") {\n throw new Error(\"expected single branch name argument\");\n }\n\n // Return the branch node definition.\n return { type: \"branch\", ref: nodeArguments[0].value };\n}\n", "import { RootNodeDefinition } from \"./BehaviourTreeDefinition\";\nimport { flattenDefinition, isBranchNode, isInteger } from \"./BehaviourTreeDefinitionUtilities\";\nimport { convertMDSLToJSON } from \"./mdsl/MDSLDefinitionParser\";\n\n/**\n * An object representing the result of validating a tree definition.\n */\nexport type DefinitionValidationResult = {\n /**\n * A flag defining whether validation succeeded.\n */\n succeeded: boolean;\n /**\n * A string containing the error message if validation did not succeed.\n */\n errorMessage?: string;\n};\n\n/**\n * Validates the specified behaviour tree definition in the form of JSON or MDSL.\n * @param definition The behaviour tree definition in the form of JSON or MDSL.\n * @returns An object representing the result of validating the given tree definition.\n */\nexport function validateDefinition(definition: any): DefinitionValidationResult {\n // A helper function to create a failure validation result with the given error message.\n const createFailureResult = (errorMessage: string) => ({ succeeded: false, errorMessage });\n\n // The definition must be defined.\n if (definition === null || typeof definition === \"undefined\") {\n return createFailureResult(\"definition is null or undefined\");\n }\n\n let rootNodeDefinitions: any[];\n\n // We are expecting a definition in one of three different forms:\n // - A string which we will assume is mdsl and we will parse this to JSON before validation.\n // - An array which we will assume is an array of root node definitions with at least one being the primary root node (no 'id' property)\n // - An object which we will assume is the primary root node and should not have an 'id' property.\n if (typeof definition === \"string\") {\n try {\n // The definition is a string which we can assume is mdsl, so attempt to parse it to a JSON definition in the form of an array of root node definitions.\n rootNodeDefinitions = convertMDSLToJSON(definition);\n } catch (error) {\n // We failed to parse the JSON from the mdsl, this is likely to be the result of it not being a valid mdsl string.\n return createFailureResult(`invalid mdsl: ${definition}`);\n }\n } else if (typeof definition === \"object\") {\n // The definition will either be an array (of root node definitions) or an object (the single primary root node definition).\n rootNodeDefinitions = Array.isArray(definition) ? definition : [definition];\n } else {\n return createFailureResult(`unexpected definition type of '${typeof definition}'`);\n }\n\n // Iterate over our array of root nodes and call validateNode for each, passing an initial depth of 0, wrapped in a try catch to handle validation failures.\n try {\n rootNodeDefinitions.forEach((rootNodeDefinition) => validateNode(rootNodeDefinition, 0));\n } catch (error) {\n // Handle cases where we have caught a thrown Error and return a failure result with the error message.\n if (error instanceof Error) {\n return createFailureResult(error.message);\n }\n\n // No idea what happened here!\n return createFailureResult(`unexpected error: ${error}`);\n }\n\n // Unpack all of the root node definitions into arrays of main ('id' defined) and sub ('id' not defined) root node definitions.\n const mainRootNodeDefinitions = rootNodeDefinitions.filter(({ id }) => typeof id === \"undefined\");\n const subRootNodeDefinitions = rootNodeDefinitions.filter(({ id }) => typeof id === \"string\" && id.length > 0);\n\n // We should ALWAYS have exactly one root node definition without an 'id' property defined, which is out main root node definition.\n if (mainRootNodeDefinitions.length !== 1) {\n return createFailureResult(\"expected single root node without 'id' property defined to act as main root\");\n }\n\n // We should never have duplicate 'id' properties across our sub root node definitions.\n const subRootNodeIdenitifers: string[] = [];\n for (const { id } of subRootNodeDefinitions) {\n // Have we already come across this 'id' property value?\n if (subRootNodeIdenitifers.includes(id)) {\n return createFailureResult(`multiple root nodes found with duplicate 'id' property value of '${id}'`);\n }\n\n subRootNodeIdenitifers.push(id);\n }\n\n // Check for any branch node circular depedencies. This will not include any globally registered subtrees.\n const circularDependencyPath = findBranchCircularDependencyPath(rootNodeDefinitions);\n\n // If we found a circular dependency in our root node and branch node definitions then the definition is definitely not valid.\n if (circularDependencyPath) {\n return createFailureResult(`circular dependency found in branch node references: ${circularDependencyPath}`);\n }\n\n // Our definition was valid!\n return { succeeded: true };\n}\n\n/**\n * Find the first circular depdendency path present in the array of root node definitions, or null if one doesn't exist.\n * This will not consider branch nodes that reference any globally registered subtrees.\n * @param rootNodeDefinitions The array of root node definitions.\n * @returns The first circular depdendency path present in the array of root node definitions as string, or null if one doesn't exist.\n */\nfunction findBranchCircularDependencyPath(rootNodeDefinitions: RootNodeDefinition[]): string | null {\n // Create a mapping of root node identifiers to other root nodes that they reference via branch nodes.\n // Below is an example of a mapping that includes a circular dependency (root => a => b => c => a)\n // [{ refs: [\"a\", \"b\"] }, { id: \"a\", refs: [\"b\"] }, { id: \"b\", refs: [\"c\"] }, { id: \"c\", refs: [\"a\"] }]\n const rootNodeMappings: { id: string | undefined; refs: string[] }[] = rootNodeDefinitions.map(\n (rootNodeDefinition) => ({\n id: rootNodeDefinition.id,\n refs: flattenDefinition(rootNodeDefinition)\n .filter(isBranchNode)\n .map(({ ref }) => ref)\n })\n );\n\n let badPathFormatted: string | null = null;\n\n // A recursive function to walk through the mappings, keeping track of which root nodes we have visited in the form of a path of root node identifiers.\n const followRefs = (mapping: { id: string | undefined; refs: string[] }, path: (string | undefined)[] = []) => {\n // Have we found a circular dependency?\n if (path.includes(mapping.id)) {\n // We found a circular dependency! Get the bad path of root node identifiers.\n const badPath = [...path, mapping.id];\n\n // Set the formatted path value. [undefined, \"a\", \"b\", \"c\", \"a\"] would be formatted as \"a -> b -> c -> a\".\n badPathFormatted = badPath.filter((element) => !!element).join(\" => \");\n\n // No need to continue, we found a circular dependency.\n return;\n }\n\n for (const ref of mapping.refs) {\n // Find the mapping for the root node with an identifer matching the current ref.\n const subMapping = rootNodeMappings.find(({ id }) => id === ref);\n\n // We may not have a mapping for this ref, which will happen if this ref is for a globally registered subtree.\n if (subMapping) {\n followRefs(subMapping, [...path, mapping.id]);\n }\n }\n };\n\n // Start looking for circular dependencies from the root.\n followRefs(rootNodeMappings.find((mapping) => typeof mapping.id === \"undefined\")!);\n\n return badPathFormatted;\n}\n\n/**\n * Validate an object that we expect to be a node definition.\n * @param definition An object that we expect to be a node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateNode(definition: any, depth: number): void {\n // Every node must be valid object and have a non-empty 'type' string property.\n if (typeof definition !== \"object\" || typeof definition.type !== \"string\" || definition.type.length === 0) {\n throw new Error(\n `node definition is not an object or 'type' property is not a non-empty string at depth '${depth}'`\n );\n }\n\n // How we validate this node definition will depend on its type.\n switch (definition.type) {\n case \"action\":\n validateActionNode(definition, depth);\n break;\n\n case \"condition\":\n validateConditionNode(definition, depth);\n break;\n\n case \"wait\":\n validateWaitNode(definition, depth);\n break;\n\n case \"branch\":\n validateBranchNode(definition, depth);\n break;\n\n case \"root\":\n validateRootNode(definition, depth);\n break;\n\n case \"success\":\n validateSuccessNode(definition, depth);\n break;\n\n case \"fail\":\n validateFailNode(definition, depth);\n break;\n\n case \"flip\":\n validateFlipNode(definition, depth);\n break;\n\n case \"repeat\":\n validateRepeatNode(definition, depth);\n break;\n\n case \"retry\":\n validateRetryNode(definition, depth);\n break;\n\n case \"sequence\":\n validateSequenceNode(definition, depth);\n break;\n\n case \"selector\":\n validateSelectorNode(definition, depth);\n break;\n\n case \"parallel\":\n validateParallelNode(definition, depth);\n break;\n\n default:\n throw new Error(`unexpected node type of '${definition.type}' at depth '${depth}'`);\n }\n}\n\n/**\n * Validate any attributes for a given node definition.\n * @param definition The node definition.\n * @param depth The depth of the node in the behaviour tree definition.\n */\nfunction validateNodeAttributes(definition: any, depth: number): void {\n // Validate each of the attribute types for this node.\n [\"while\", \"until\", \"entry\", \"exit\", \"step\"].forEach((attributeName) => {\n // Attempt to grab the definition for the current attribute from the node definition.\n const attributeDefinition = definition[attributeName];\n\n // All node attributes are optional, so there is nothing to do if the current attribute is not defined.\n if (typeof attributeDefinition === \"undefined\") {\n return;\n }\n\n // The attribute definition must be an object.\n if (typeof attributeDefinition !== \"object\") {\n throw new Error(\n `expected attribute '${attributeName}' to be an object for '${definition.type}' node at depth '${depth}'`\n );\n }\n\n // The 'call' property must be defined for any attribute definition.\n if (typeof attributeDefinition.call !== \"string\" || attributeDefinition.call.length === 0) {\n throw new Error(\n `expected 'call' property for attribute '${attributeName}' to be a non-empty string for '${definition.type}' node at depth '${depth}'`\n );\n }\n\n // If any node attribute arguments have been defined then they must have been defined in an array.\n if (typeof attributeDefinition.args !== \"undefined\" && !Array.isArray(attributeDefinition.args)) {\n throw new Error(\n `expected 'args' property for attribute '${attributeName}' to be an array for '${definition.type}' node at depth '${depth}'`\n );\n }\n });\n}\n\n/**\n * Validate an object that we expect to be a root node definition.\n * @param definition An object that we expect to be a root node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateRootNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"root\") {\n throw new Error(\"expected node type of 'root' for root node\");\n }\n\n // A root node cannot be the child of another node.\n if (depth > 0) {\n throw new Error(\"a root node cannot be the child of another node\");\n }\n\n // Check that, if the root node 'id' property is defined, it is a non-empty string.\n if (typeof definition.id !== \"undefined\" && (typeof definition.id !== \"string\" || definition.id.length === 0)) {\n throw new Error(\"expected non-empty string for 'id' property if defined for root node\");\n }\n\n // A root node is a decorator node, so must have a child node defined.\n if (typeof definition.child === \"undefined\") {\n throw new Error(\"expected property 'child' to be defined for root node\");\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n\n // Validate the child node of this decorator node.\n validateNode(definition.child, depth + 1);\n}\n\n/**\n * Validate an object that we expect to be a success node definition.\n * @param definition An object that we expect to be a success node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateSuccessNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"success\") {\n throw new Error(`expected node type of 'success' for success node at depth '${depth}'`);\n }\n\n // A success node is a decorator node, so must have a child node defined.\n if (typeof definition.child === \"undefined\") {\n throw new Error(`expected property 'child' to be defined for success node at depth '${depth}'`);\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n\n // Validate the child node of this decorator node.\n validateNode(definition.child, depth + 1);\n}\n\n/**\n * Validate an object that we expect to be a fail node definition.\n * @param definition An object that we expect to be a fail node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateFailNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"fail\") {\n throw new Error(`expected node type of 'fail' for fail node at depth '${depth}'`);\n }\n\n // A fail node is a decorator node, so must have a child node defined.\n if (typeof definition.child === \"undefined\") {\n throw new Error(`expected property 'child' to be defined for fail node at depth '${depth}'`);\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n\n // Validate the child node of this decorator node.\n validateNode(definition.child, depth + 1);\n}\n\n/**\n * Validate an object that we expect to be a flip node definition.\n * @param definition An object that we expect to be a flip node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateFlipNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"flip\") {\n throw new Error(`expected node type of 'flip' for flip node at depth '${depth}'`);\n }\n\n // A flip node is a decorator node, so must have a child node defined.\n if (typeof definition.child === \"undefined\") {\n throw new Error(`expected property 'child' to be defined for flip node at depth '${depth}'`);\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n\n // Validate the child node of this decorator node.\n validateNode(definition.child, depth + 1);\n}\n\n/**\n * Validate an object that we expect to be a repeat node definition.\n * @param definition An object that we expect to be a repeat node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateRepeatNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"repeat\") {\n throw new Error(`expected node type of 'repeat' for repeat node at depth '${depth}'`);\n }\n\n // A repeat node is a decorator node, so must have a child node defined.\n if (typeof definition.child === \"undefined\") {\n throw new Error(`expected property 'child' to be defined for repeat node at depth '${depth}'`);\n }\n\n // Check whether an 'iterations' property has been defined, it may not have been if this node is to repeat indefinitely.\n if (typeof definition.iterations !== \"undefined\") {\n if (Array.isArray(definition.iterations)) {\n // Check whether any elements of the array are not integer values.\n const containsNonInteger = !!definition.iterations.find((value: unknown) => !isInteger(value));\n\n // If the 'iterations' property is an array then it MUST contain two integer values.\n if (definition.iterations.length !== 2 || containsNonInteger) {\n throw new Error(\n `expected array containing two integer values for 'iterations' property if defined for repeat node at depth '${depth}'`\n );\n }\n } else if (!isInteger(definition.iterations)) {\n throw new Error(\n `expected integer value or array containing two integer values for 'iterations' property if defined for repeat node at depth '${depth}'`\n );\n }\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n\n // Validate the child node of this decorator node.\n validateNode(definition.child, depth + 1);\n}\n\n/**\n * Validate an object that we expect to be a retry node definition.\n * @param definition An object that we expect to be a retry node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateRetryNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"retry\") {\n throw new Error(`expected node type of 'retry' for retry node at depth '${depth}'`);\n }\n\n // A retry node is a decorator node, so must have a child node defined.\n if (typeof definition.child === \"undefined\") {\n throw new Error(`expected property 'child' to be defined for retry node at depth '${depth}'`);\n }\n\n // Check whether an 'attempts' property has been defined, it may not have been if this node is to retry indefinitely.\n if (typeof definition.attempts !== \"undefined\") {\n if (Array.isArray(definition.attempts)) {\n // Check whether any elements of the array are not integer values.\n const containsNonInteger = !!definition.attempts.find((value: unknown) => !isInteger(value));\n\n // If the 'attempts' property is an array then it MUST contain two integer values.\n if (definition.attempts.length !== 2 || containsNonInteger) {\n throw new Error(\n `expected array containing two integer values for 'attempts' property if defined for retry node at depth '${depth}'`\n );\n }\n } else if (!isInteger(definition.attempts)) {\n throw new Error(\n `expected integer value or array containing two integer values for 'attempts' property if defined for retry node at depth '${depth}'`\n );\n }\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n\n // Validate the child node of this decorator node.\n validateNode(definition.child, depth + 1);\n}\n\n/**\n * Validate an object that we expect to be a branch node definition.\n * @param definition An object that we expect to be a branch node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateBranchNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"branch\") {\n throw new Error(`expected node type of 'branch' for branch node at depth '${depth}'`);\n }\n\n // Check that the branch node 'ref' property is defined and is a non-empty string.\n if (typeof definition.ref !== \"string\" || definition.ref.length === 0) {\n throw new Error(`expected non-empty string for 'ref' property for branch node at depth '${depth}'`);\n }\n\n // It is invalid to define guard attributes for a branch node as they should be defined on the referenced root node.\n [\"while\", \"until\"].forEach((attributeName) => {\n if (typeof definition[attributeName] !== \"undefined\") {\n throw new Error(\n `guards should not be defined for branch nodes but guard '${attributeName}' was defined for branch node at depth '${depth}'`\n );\n }\n });\n\n // It is invalid to define callback attributes for a branch node as they should be defined on the referenced root node.\n [\"entry\", \"exit\", \"step\"].forEach((attributeName) => {\n if (typeof definition[attributeName] !== \"undefined\") {\n throw new Error(\n `callbacks should not be defined for branch nodes but callback '${attributeName}' was defined for branch node at depth '${depth}'`\n );\n }\n });\n}\n\n/**\n * Validate an object that we expect to be a action node definition.\n * @param definition An object that we expect to be a action node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateActionNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"action\") {\n throw new Error(`expected node type of 'action' for action node at depth '${depth}'`);\n }\n\n // The 'call' property must be defined for a action node definition.\n if (typeof definition.call !== \"string\" || definition.call.length === 0) {\n throw new Error(`expected non-empty string for 'call' property of action node at depth '${depth}'`);\n }\n\n // If any action function arguments have been defined then they must have been defined in an array.\n if (typeof definition.args !== \"undefined\" && !Array.isArray(definition.args)) {\n throw new Error(`expected array for 'args' property if defined for action node at depth '${depth}'`);\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n}\n\n/**\n * Validate an object that we expect to be a condition node definition.\n * @param definition An object that we expect to be a condition node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateConditionNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"condition\") {\n throw new Error(`expected node type of 'condition' for condition node at depth '${depth}'`);\n }\n\n // The 'call' property must be defined for a condition node definition.\n if (typeof definition.call !== \"string\" || definition.call.length === 0) {\n throw new Error(`expected non-empty string for 'call' property of condition node at depth '${depth}'`);\n }\n\n // If any condition function arguments have been defined then they must have been defined in an array.\n if (typeof definition.args !== \"undefined\" && !Array.isArray(definition.args)) {\n throw new Error(`expected array for 'args' property if defined for condition node at depth '${depth}'`);\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n}\n\n/**\n * Validate an object that we expect to be a wait node definition.\n * @param definition An object that we expect to be a wait node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateWaitNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"wait\") {\n throw new Error(`expected node type of 'wait' for wait node at depth '${depth}'`);\n }\n\n // Check whether a 'duration' property has been defined, it may not have been if this node is to wait indefinitely.\n if (typeof definition.duration !== \"undefined\") {\n if (Array.isArray(definition.duration)) {\n // Check whether any elements of the array are not integer values.\n const containsNonInteger = !!definition.duration.find((value: unknown) => !isInteger(value));\n\n // If the 'duration' property is an array then it MUST contain two integer values.\n if (definition.duration.length !== 2 || containsNonInteger) {\n throw new Error(\n `expected array containing two integer values for 'duration' property if defined for wait node at depth '${depth}'`\n );\n }\n } else if (!isInteger(definition.duration)) {\n throw new Error(\n `expected integer value or array containing two integer values for 'duration' property if defined for wait node at depth '${depth}'`\n );\n }\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n}\n\n/**\n * Validate an object that we expect to be a sequence node definition.\n * @param definition An object that we expect to be a sequence node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateSequenceNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"sequence\") {\n throw new Error(`expected node type of 'sequence' for sequence node at depth '${depth}'`);\n }\n\n // A sequence node is a composite node, so must have a children nodes array defined.\n if (!Array.isArray(definition.children) || definition.children.length === 0) {\n throw new Error(`expected non-empty 'children' array to be defined for sequence node at depth '${depth}'`);\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n\n // Validate the child nodes of this composite node.\n definition.children.forEach((child: any) => validateNode(child, depth + 1));\n}\n\n/**\n * Validate an object that we expect to be a selector node definition.\n * @param definition An object that we expect to be a selector node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateSelectorNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"selector\") {\n throw new Error(`expected node type of 'selector' for selector node at depth '${depth}'`);\n }\n\n // A selector node is a composite node, so must have a children nodes array defined.\n if (!Array.isArray(definition.children) || definition.children.length === 0) {\n throw new Error(`expected non-empty 'children' array to be defined for selector node at depth '${depth}'`);\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n\n // Validate the child nodes of this composite node.\n definition.children.forEach((child: any) => validateNode(child, depth + 1));\n}\n\n/**\n * Validate an object that we expect to be a parallel node definition.\n * @param definition An object that we expect to be a parallel node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateParallelNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"parallel\") {\n throw new Error(`expected node type of 'parallel' for parallel node at depth '${depth}'`);\n }\n\n // A parallel node is a composite node, so must have a children nodes array defined.\n if (!Array.isArray(definition.children) || definition.children.length === 0) {\n throw new Error(`expected non-empty 'children' array to be defined for parallel node at depth '${depth}'`);\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n\n // Validate the child nodes of this composite node.\n definition.children.forEach((child: any) => validateNode(child, depth + 1));\n}\n", "import Node from \"../../nodes/Node\";\n\n/**\n * An exception thrown when evaluating node guard path conditions and a conditions fails.\n */\nexport default class GuardUnsatisifedException extends Error {\n /**\n * @param source The node at which a guard condition failed.\n */\n constructor(private source: Node) {\n super(\"A guard path condition has failed\");\n }\n\n /**\n * Gets whether the specified node is the node at which a guard condition failed.\n * @param node The node to check against the source node.\n * @returns Whether the specified node is the node at which a guard condition failed.\n */\n isSourceNode = (node: Node) => node === this.source;\n}\n", "import { Agent } from \"../../Agent\";\nimport Guard from \"./Guard\";\nimport Node from \"../../nodes/Node\";\nimport GuardUnsatisifedException from \"./GuardUnsatisifedException\";\n\nexport type GuardPathPart = {\n node: Node;\n guards: Guard[];\n};\n\n/**\n * Represents a path of node guards along a root-to-leaf tree path.\n */\nexport default class GuardPath {\n /**\n * @param nodes An array of objects defining a node instance -> guard link, ordered by node depth.\n */\n constructor(private nodes: GuardPathPart[]) {}\n\n /**\n * Evaluate guard conditions for all guards in the tree path, moving outwards from the root.\n * @param agent The agent, required for guard evaluation.\n * @returns An evaluation results object.\n */\n evaluate = (agent: Agent) => {\n // We need to evaluate guard conditions for nodes up the tree, moving outwards from the root.\n for (const details of this.nodes) {\n // There can be multiple guards per node.\n for (const guard of details.guards) {\n // Check whether the guard condition passes, and throw an exception if not.\n if (!guard.isSatisfied(agent)) {\n throw new GuardUnsatisifedException(details.node);\n }\n }\n }\n };\n}\n", "import { Agent } from \"../Agent\";\nimport Attribute from \"../attributes/Attribute\";\nimport Entry from \"../attributes/callbacks/Entry\";\nimport Exit from \"../attributes/callbacks/Exit\";\nimport Step from \"../attributes/callbacks/Step\";\nimport Guard from \"../attributes/guards/Guard\";\nimport GuardPath from \"../attributes/guards/GuardPath\";\nimport GuardUnsatisifedException from \"../attributes/guards/GuardUnsatisifedException\";\nimport { BehaviourTreeOptions } from \"../BehaviourTreeOptions\";\nimport { AnyArgument } from \"../RootAstNodesBuilder\";\nimport State, { AnyState } from \"../State\";\nimport Leaf from \"./leaf/Leaf\";\n\n/**\n * A base node.\n */\nexport default abstract class Node {\n /**\n * The node uid.\n */\n private readonly uid: string = createNodeUid();\n /**\n * The node state.\n */\n private state: AnyState = State.READY;\n /**\n * The guard path to evaluate as part of a node update.\n */\n private guardPath: GuardPath | undefined;\n\n /**\n * @param type The node type.\n * @param attributes The node attributes.\n * @param args The node argument definitions.\n */\n constructor(private type: string, private attributes: Attribute[], private args: AnyArgument[]) {}\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected abstract onUpdate(agent: Agent, options: BehaviourTreeOptions): void;\n\n /**\n * Gets the name of the node.\n */\n public abstract getName(): string;\n\n /**\n * Gets whether this node is a leaf node.\n */\n public abstract isLeafNode: () => this is Leaf;\n\n /**\n * Gets/Sets the state of the node.\n */\n getState = (): AnyState => this.state;\n setState = (value: AnyState): void => {\n this.state = value;\n };\n\n /**\n * Gets the unique id of the node.\n */\n getUid = () => this.uid;\n\n /**\n * Gets the type of the node.\n */\n getType = () => this.type;\n\n /**\n * Gets the node attributes.\n */\n getAttributes = () => this.attributes;\n\n /**\n * Gets the node arguments.\n */\n getArguments = () => this.args;\n\n /**\n * Gets the node attribute with the specified type, or null if it does not exist.\n */\n getAttribute(type: \"entry\" | \"ENTRY\"): Entry;\n getAttribute(type: \"exit\" | \"EXIT\"): Exit;\n getAttribute(type: \"step\" | \"STEP\"): Step;\n getAttribute(type: string): Attribute {\n return (\n this.getAttributes().filter((decorator) => decorator.getType().toUpperCase() === type.toUpperCase())[0] ||\n null\n );\n }\n\n /**\n * Gets the node attributes.\n */\n getGuardAttributes = (): Guard[] => this.getAttributes().filter((decorator) => decorator.isGuard()) as Guard[];\n\n /**\n * Sets the guard path to evaluate as part of a node update.\n */\n setGuardPath = (value: GuardPath) => (this.guardPath = value);\n\n /**\n * Gets whether a guard path is assigned to this node.\n */\n hasGuardPath = () => !!this.guardPath;\n\n /**\n * Gets whether this node is in the specified state.\n * @param value The value to compare to the node state.\n */\n public is(value: AnyState): boolean {\n return this.state === value;\n }\n\n /**\n * Reset the state of the node.\n */\n public reset(): void {\n this.setState(State.READY);\n }\n\n /**\n * Abort the running of this node.\n * @param agent The agent.\n */\n public abort(agent: Agent): void {\n // There is nothing to do if this node is not in the running state.\n if (!this.is(State.RUNNING)) {\n return;\n }\n\n // Reset the state of this node.\n this.reset();\n\n this.getAttribute(\"exit\")?.callAgentFunction(agent, false, true);\n }\n\n /**\n * Update the node.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n * @returns The result of the update.\n */\n public update(agent: Agent, options: BehaviourTreeOptions): void {\n // If this node is already in a 'SUCCEEDED' or 'FAILED' state then there is nothing to do.\n if (this.is(State.SUCCEEDED) || this.is(State.FAILED)) {\n return;\n }\n\n try {\n // Evaluate all of the guard path conditions for the current tree path.\n this.guardPath!.evaluate(agent);\n\n // If this node is in the READY state then call the ENTRY for this node if it exists.\n if (this.is(State.READY)) {\n this.getAttribute(\"entry\")?.callAgentFunction(agent);\n }\n\n this.getAttribute(\"step\")?.callAgentFunction(agent);\n\n // Do the actual update.\n this.onUpdate(agent, options);\n\n // If this node is now in a 'SUCCEEDED' or 'FAILED' state then call the EXIT for this node if it exists.\n if (this.is(State.SUCCEEDED) || this.is(State.FAILED)) {\n this.getAttribute(\"exit\")?.callAgentFunction(agent, this.is(State.SUCCEEDED), false);\n }\n } catch (error) {\n // If the error is a GuardUnsatisfiedException then we need to determine if this node is the source.\n if (error instanceof GuardUnsatisifedException && error.isSourceNode(this)) {\n // Abort the current node.\n this.abort(agent);\n\n // Any node that is the source of an abort will be a failed node.\n this.setState(State.FAILED);\n } else {\n throw error;\n }\n }\n }\n}\n\n/**\n * Create a randomly generated node uid.\n * @returns A randomly generated node uid.\n */\nfunction createNodeUid(): string {\n var S4 = function () {\n return (((1 + Math.random()) * 0x10000) | 0).toString(16).substring(1);\n };\n return S4() + S4() + \"-\" + S4() + \"-\" + S4() + \"-\" + S4() + \"-\" + S4() + S4() + S4();\n}\n", "import Node from \"../Node\";\n\n/**\n * A leaf node.\n */\nexport default abstract class Leaf extends Node {\n /**\n * Gets whether this node is a leaf node.\n */\n isLeafNode = () => true;\n}\n", "import { ActionResult, Agent, ExitFunctionArg, FunctionArg, GlobalFunction } from \"./Agent\";\nimport { AnyArgument, RootAstNode } from \"./RootAstNodesBuilder\";\n\n// Exit callbacks receive their own special type of argument.\n// There's probably stricter ways to represent this but it feels overly complex right now.\ntype ExitResultArg = { value: ExitFunctionArg };\nexport type AnyExitArgument = AnyArgument | ExitResultArg;\n\nexport type InvokerFunction = (args: AnyExitArgument[]) => ActionResult;\n\n/**\n * A singleton used to store and lookup registered functions and subtrees.\n */\nexport default class Lookup {\n /**\n * The object holding any registered functions keyed on function name.\n */\n private static functionTable: { [key: string]: GlobalFunction } = {};\n /**\n * The object holding any registered sub-trees keyed on tree name.\n */\n private static subtreeTable: { [key: string]: RootAstNode } = {};\n\n /**\n * Gets the function with the specified name.\n * @param name The name of the function.\n * @returns The function with the specified name.\n */\n public static getFunc(name: string): GlobalFunction {\n return this.functionTable[name];\n }\n\n /**\n * Sets the function with the specified name for later lookup.\n * @param name The name of the function.\n * @param func The function.\n */\n public static setFunc(name: string, func: GlobalFunction): void {\n this.functionTable[name] = func;\n }\n\n /**\n * Gets the function invoker for the specified agent and function name.\n * If a function with the specified name exists on the agent object then it will\n * be returned, otherwise we will then check the registered functions for a match.\n * @param agent The agent instance that this behaviour tree is modelling behaviour for.\n * @param name The function name.\n * @returns The function invoker for the specified agent and function name.\n */\n static getFuncInvoker(agent: Agent, name: string): InvokerFunction | null {\n // Check whether the agent contains the specified function.\n const foundOnAgent = agent[name];\n if (foundOnAgent && typeof foundOnAgent === \"function\") {\n return (args: AnyExitArgument[]): boolean | ActionResult =>\n foundOnAgent.apply(\n agent,\n args.map((arg) => arg.value)\n );\n }\n\n // The agent does not contain the specified function but it may have been registered at some point.\n if (this.functionTable[name] && typeof this.functionTable[name] === \"function\") {\n return (args: AnyExitArgument[]) => this.functionTable[name](agent, ...args.map((arg) => arg.value));\n }\n\n // We have no function to invoke.\n return null;\n }\n\n /**\n * Gets the subtree with the specified name.\n * @param name The name of the subtree.\n * @returns The subtree with the specified name.\n */\n static getSubtree(name: string): RootAstNode {\n return this.subtreeTable[name];\n }\n\n /**\n * Sets the subtree with the specified name for later lookup.\n * @param name The name of the subtree.\n * @param subtree The subtree.\n */\n static setSubtree(name: string, subtree: RootAstNode) {\n this.subtreeTable[name] = subtree;\n }\n\n /**\n * Removes the registered function or subtree with the specified name.\n * @param name The name of the registered function or subtree.\n */\n static remove(name: string) {\n delete this.functionTable[name];\n delete this.subtreeTable[name];\n }\n\n /**\n * Remove all registered functions and subtrees.\n */\n static empty() {\n this.functionTable = {};\n this.subtreeTable = {};\n }\n}\n", "import Leaf from \"./Leaf\";\nimport State, { CompleteState } from \"../../State\";\nimport Lookup from \"../../Lookup\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { AnyArgument } from \"../../RootAstNodesBuilder\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * An Action leaf node.\n * This represents an immediate or ongoing state of behaviour.\n */\nexport default class Action extends Leaf {\n /**\n * @param attributes The node attributes.\n * @param actionName The action name.\n * @param actionArguments The array of action argument definitions.\n */\n constructor(attributes: Attribute[], private actionName: string, private actionArguments: AnyArgument[]) {\n super(\"action\", attributes, actionArguments);\n }\n\n /**\n * Whether there is a pending update promise.\n */\n private isUsingUpdatePromise = false;\n\n /**\n * The finished state result of an update promise.\n */\n private updatePromiseStateResult: CompleteState | null = null;\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // If the result of this action depends on an update promise then there is nothing to do until\n // it resolves, unless there has been a value set as a result of the update promise resolving.\n if (this.isUsingUpdatePromise) {\n // Check whether the update promise has resolved with a state value.\n if (this.updatePromiseStateResult) {\n // Set the state of this node to match the state returned by the promise.\n this.setState(this.updatePromiseStateResult);\n }\n\n return;\n }\n\n // Attempt to get the invoker for the action function.\n const actionFuncInvoker = Lookup.getFuncInvoker(agent, this.actionName);\n\n // The action function should be defined.\n if (actionFuncInvoker === null) {\n throw new Error(\n `cannot update action node as the action '${this.actionName}' function is not defined on the agent and has not been registered`\n );\n }\n\n // Call the action function, the result of which may be:\n // - The finished state of this action node.\n // - A promise to return a finished node state.\n // - Undefined if the node should remain in the running state.\n const updateResult = actionFuncInvoker(this.actionArguments) as CompleteState | Promise;\n\n if (updateResult instanceof Promise) {\n updateResult.then(\n (result) => {\n // If 'isUpdatePromisePending' is null then the promise was cleared as it was resolving, probably via an abort of reset.\n if (!this.isUsingUpdatePromise) {\n return;\n }\n\n // Check to make sure the result is a valid finished state.\n if (result !== State.SUCCEEDED && result !== State.FAILED) {\n throw new Error(\n \"action node promise resolved with an invalid value, expected a State.SUCCEEDED or State.FAILED value to be returned\"\n );\n }\n\n // Set pending update promise state result to be processed on next update.\n this.updatePromiseStateResult = result;\n },\n (reason) => {\n // If 'isUpdatePromisePending' is null then the promise was cleared as it was resolving, probably via an abort of reset.\n if (!this.isUsingUpdatePromise) {\n return;\n }\n\n // Just throw whatever was returned as the rejection argument.\n throw new Error(reason);\n }\n );\n\n // This node will be in the 'RUNNING' state until the update promise resolves.\n this.setState(State.RUNNING);\n\n // We are now waiting for the promise returned by the use to resolve before we know what state this node is in.\n this.isUsingUpdatePromise = true;\n } else {\n // Validate the returned value.\n this.validateUpdateResult(updateResult);\n\n // Set the state of this node, this may be undefined, which just means that the node is still in the 'RUNNING' state.\n this.setState(updateResult || State.RUNNING);\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => this.actionName;\n\n /**\n * Reset the state of the node.\n */\n reset = () => {\n // Reset the state of this node.\n this.setState(State.READY);\n\n // There is no longer an update promise that we care about.\n this.isUsingUpdatePromise = false;\n this.updatePromiseStateResult = null;\n };\n\n /**\n * Validate the result of an update function call.\n * @param result The result of an update function call.\n */\n private validateUpdateResult = (result: CompleteState | boolean) => {\n switch (result) {\n case State.SUCCEEDED:\n case State.FAILED:\n case undefined:\n return;\n default:\n throw new Error(\n `action '${this.actionName}' 'onUpdate' returned an invalid response, expected an optional State.SUCCEEDED or State.FAILED value to be returned`\n );\n }\n };\n}\n", "import Leaf from \"./Leaf\";\nimport State from \"../../State\";\nimport Lookup from \"../../Lookup\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { AnyArgument } from \"../../RootAstNodesBuilder\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A Condition leaf node.\n * This will succeed or fail immediately based on an agent predicate, without moving to the 'RUNNING' state.\n */\nexport default class Condition extends Leaf {\n /**\n * @param attributes The node attributes.\n * @param conditionName The name of the condition function.\n * @param conditionArguments The array of condition argument definitions.\n */\n constructor(attributes: Attribute[], private conditionName: string, private conditionArguments: AnyArgument[]) {\n super(\"condition\", attributes, conditionArguments);\n }\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // Attempt to get the invoker for the condition function.\n const conditionFuncInvoker = Lookup.getFuncInvoker(agent, this.conditionName);\n\n // The condition function should be defined.\n if (conditionFuncInvoker === null) {\n throw new Error(\n `cannot update condition node as the condition '${this.conditionName}' function is not defined on the agent and has not been registered`\n );\n }\n\n // Call the condition function to determine the state of this node.\n this.setState(!!conditionFuncInvoker(this.conditionArguments) ? State.SUCCEEDED : State.FAILED);\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => this.conditionName;\n}\n", "import Leaf from \"./Leaf\";\nimport State from \"../../State\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { Agent } from \"../../Agent\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A WAIT node.\n * The state of this node will change to SUCCEEDED after a duration of time\n */\nexport default class Wait extends Leaf {\n /**\n * @param attributes The node attributes.\n * @param duration The duration that this node will wait to succeed in milliseconds.\n * @param durationMin The minimum possible duration in milliseconds that this node will wait to succeed.\n * @param durationMax The maximum possible duration in milliseconds that this node will wait to succeed.\n */\n constructor(\n attributes: Attribute[],\n private duration: number | null,\n private durationMin: number | null,\n private durationMax: number | null\n ) {\n super(\"wait\", attributes, []);\n }\n\n /**\n * The time in milliseconds at which this node was first updated.\n */\n private initialUpdateTime: number = 0;\n\n /**\n * The total duration in milliseconds that this node will be waiting for.\n */\n private totalDuration: number | null = null;\n\n /**\n * The duration in milliseconds that this node has been waiting for.\n */\n private waitedDuration: number = 0;\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // If this node is in the READY state then we need to set the initial update time.\n if (this.is(State.READY)) {\n // Set the initial update time.\n this.initialUpdateTime = new Date().getTime();\n\n // Set the initial waited duration.\n this.waitedDuration = 0;\n\n // Are we dealing with an explicit duration or will we be randomly picking a duration between the min and max duration.\n if (this.duration !== null) {\n this.totalDuration = this.duration;\n } else if (this.durationMin !== null && this.durationMax !== null) {\n // We will be picking a random duration between a min and max duration, if the optional 'random' behaviour tree\n // function option is defined then we will be using that, otherwise we will fall back to using Math.random.\n const random = typeof options.random === \"function\" ? options.random : Math.random;\n\n // Pick a random duration between a min and max duration.\n this.totalDuration = Math.floor(\n random() * (this.durationMax - this.durationMin + 1) + this.durationMin\n );\n } else {\n this.totalDuration = null;\n }\n\n // The node is now running until we finish waiting.\n this.setState(State.RUNNING);\n }\n\n // If we have no total duration then this wait node will wait indefinitely until it is aborted.\n if (this.totalDuration === null) {\n return;\n }\n\n // If we have a 'getDeltaTime' function defined as part of our options then we will use it to figure out how long we have waited for.\n if (typeof options.getDeltaTime === \"function\") {\n // Get the delta time.\n const deltaTime = options.getDeltaTime();\n\n // Our delta time must be a valid number and cannot be NaN.\n if (typeof deltaTime !== \"number\" || isNaN(deltaTime)) {\n throw new Error(\"The delta time must be a valid number and not NaN.\");\n }\n\n // Update the amount of time that this node has been waiting for based on the delta time.\n this.waitedDuration += deltaTime * 1000;\n } else {\n // We are not using a delta time, so we will just work out hom much time has passed since the first update.\n this.waitedDuration = new Date().getTime() - this.initialUpdateTime;\n }\n\n // Have we waited long enough?\n if (this.waitedDuration >= this.totalDuration) {\n // We have finished waiting!\n this.setState(State.SUCCEEDED);\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => {\n if (this.duration !== null) {\n return `WAIT ${this.duration}ms`;\n } else if (this.durationMin !== null && this.durationMax !== null) {\n return `WAIT ${this.durationMin}ms-${this.durationMax}ms`;\n } else {\n return \"WAIT\";\n }\n };\n}\n", "import Node from \"../Node\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\n\n/**\n * A decorator node that wraps a single child node.\n */\nexport default abstract class Decorator extends Node {\n /**\n * @param type The node type.\n * @param attributes The node attributes.\n * @param child The child node.\n */\n constructor(type: string, attributes: Attribute[], protected child: Node) {\n super(type, attributes, []);\n }\n\n /**\n * Gets whether this node is a leaf node.\n */\n isLeafNode = () => false;\n\n /**\n * Gets the children of this node.\n */\n getChildren = () => [this.child];\n\n /**\n * Reset the state of the node.\n */\n reset = () => {\n // Reset the state of this node.\n this.setState(State.READY);\n\n // Reset the state of the child node.\n this.child.reset();\n };\n\n /**\n * Abort the running of this node.\n * @param agent The agent.\n */\n abort = (agent: Agent) => {\n // There is nothing to do if this node is not in the running state.\n if (!this.is(State.RUNNING)) {\n return;\n }\n\n // Abort the child node.\n this.child.abort(agent);\n\n // Reset the state of this node.\n this.reset();\n\n this.getAttribute(\"exit\")?.callAgentFunction(agent, false, true);\n };\n}\n", "import Node from \"../Node\";\nimport Decorator from \"./Decorator\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A Root node.\n * The root node will have a single child.\n */\nexport default class Root extends Decorator {\n /**\n * @param attributes The node attributes.\n * @param child The child node.\n */\n constructor(attributes: Attribute[], child: Node) {\n super(\"root\", attributes, child);\n }\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // If the child has never been updated or is running then we will need to update it now.\n if (this.child.getState() === State.READY || this.child.getState() === State.RUNNING) {\n // Update the child of this node.\n this.child.update(agent, options);\n }\n\n // The state of the root node is the state of its child.\n this.setState(this.child.getState());\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => \"ROOT\";\n}\n", "import Node from \"../Node\";\nimport Decorator from \"./Decorator\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A REPEAT node.\n * The node has a single child which can have:\n * -- A number of iterations for which to repeat the child node.\n * -- An infinite repeat loop if neither an iteration count or a condition function is defined.\n * The REPEAT node will stop and have a 'FAILED' state if its child is ever in a 'FAILED' state after an update.\n * The REPEAT node will attempt to move on to the next iteration if its child is ever in a 'SUCCEEDED' state.\n */\nexport default class Repeat extends Decorator {\n /**\n * @param attributes The node attributes.\n * @param iterations The number of iterations to repeat the child node.\n * @param iterationsMin The minimum possible number of iterations to repeat the child node.\n * @param iterationsMax The maximum possible number of iterations to repeat the child node.\n * @param child The child node.\n */\n constructor(\n attributes: Attribute[],\n private iterations: number | null,\n private iterationsMin: number | null,\n private iterationsMax: number | null,\n child: Node\n ) {\n super(\"repeat\", attributes, child);\n }\n\n /**\n * The number of target iterations to make.\n */\n private targetIterationCount: number | null = null;\n\n /**\n * The current iteration count.\n */\n private currentIterationCount: number = 0;\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // If this node is in the READY state then we need to reset the child and the target iteration count.\n if (this.is(State.READY)) {\n // Reset the child node.\n this.child.reset();\n\n // Reset the current iteration count.\n this.currentIterationCount = 0;\n\n // Set the target iteration count.\n this.setTargetIterationCount(options);\n }\n\n // Do a check to see if we can iterate. If we can then this node will move into the 'RUNNING' state.\n // If we cannot iterate then we have hit our target iteration count, which means that the node has succeeded.\n if (this.canIterate()) {\n // This node is in the running state and can do its initial iteration.\n this.setState(State.RUNNING);\n\n // We may have already completed an iteration, meaning that the child node will be in the SUCCEEDED state.\n // If this is the case then we will have to reset the child node now.\n if (this.child.getState() === State.SUCCEEDED) {\n this.child.reset();\n }\n\n // Update the child of this node.\n this.child.update(agent, options);\n\n // If the child moved into the FAILED state when we updated it then there is nothing left to do and this node has also failed.\n // If it has moved into the SUCCEEDED state then we have completed the current iteration.\n if (this.child.getState() === State.FAILED) {\n // The child has failed, meaning that this node has failed.\n this.setState(State.FAILED);\n\n return;\n } else if (this.child.getState() === State.SUCCEEDED) {\n // We have completed an iteration.\n this.currentIterationCount += 1;\n }\n } else {\n // This node is in the 'SUCCEEDED' state as we cannot iterate any more.\n this.setState(State.SUCCEEDED);\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => {\n if (this.iterations !== null) {\n return `REPEAT ${this.iterations}x`;\n } else if (this.iterationsMin !== null && this.iterationsMax !== null) {\n return `REPEAT ${this.iterationsMin}x-${this.iterationsMax}x`;\n } else {\n return \"REPEAT\";\n }\n };\n\n /**\n * Reset the state of the node.\n */\n reset = () => {\n // Reset the state of this node.\n this.setState(State.READY);\n\n // Reset the current iteration count.\n this.currentIterationCount = 0;\n\n // Reset the child node.\n this.child.reset();\n };\n\n /**\n * Gets whether an iteration can be made.\n * @returns Whether an iteration can be made.\n */\n private canIterate = () => {\n if (this.targetIterationCount !== null) {\n // We can iterate as long as we have not reached our target iteration count.\n return this.currentIterationCount < this.targetIterationCount;\n }\n\n // If neither an iteration count or a condition function were defined then we can iterate indefinitely.\n return true;\n };\n\n /**\n * Sets the target iteration count.\n * @param options The behaviour tree options object.\n */\n private setTargetIterationCount = (options: BehaviourTreeOptions) => {\n // Are we dealing with an explicit iteration count or will we be randomly picking a iteration count between the min and max iteration count.\n if (this.iterations !== null) {\n this.targetIterationCount = this.iterations;\n } else if (this.iterationsMin !== null && this.iterationsMax !== null) {\n // We will be picking a random iteration count between a min and max iteration count, if the optional 'random'\n // behaviour tree function option is defined then we will be using that, otherwise we will fall back to using Math.random.\n const random = typeof options.random === \"function\" ? options.random : Math.random;\n\n // Pick a random iteration count between a min and max iteration count.\n this.targetIterationCount = Math.floor(\n random() * (this.iterationsMax - this.iterationsMin + 1) + this.iterationsMin\n );\n } else {\n this.targetIterationCount = null;\n }\n };\n}\n", "import Node from \"../Node\";\nimport Decorator from \"./Decorator\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A RETRY node.\n * The node has a single child which can have:\n * -- A number of iterations for which to repeat the child node.\n * -- An infinite repeat loop if neither an iteration count or a condition function is defined.\n * The RETRY node will stop and have a 'SUCCEEDED' state if its child is ever in a 'SUCCEEDED' state after an update.\n * The RETRY node will attempt to move on to the next iteration if its child is ever in a 'FAILED' state.\n */\nexport default class Retry extends Decorator {\n /**\n * @param attributes The node attributes.\n * @param attempts The number of attempts to retry the child node.\n * @param attemptsMin The minimum possible number of attempts to retry the child node.\n * @param attemptsMax The maximum possible number of attempts to retry the child node.\n * @param child The child node.\n */\n constructor(\n attributes: Attribute[],\n private attempts: number | null,\n private attemptsMin: number | null,\n private attemptsMax: number | null,\n child: Node\n ) {\n super(\"retry\", attributes, child);\n }\n\n /**\n * The number of target attempts to make.\n */\n private targetAttemptCount: number | null = null;\n\n /**\n * The current attempt count.\n */\n private currentAttemptCount: number = 0;\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // If this node is in the READY state then we need to reset the child and the target attempt count.\n if (this.is(State.READY)) {\n // Reset the child node.\n this.child.reset();\n\n // Reset the current attempt count.\n this.currentAttemptCount = 0;\n\n // Set the target attempt count.\n this.setTargetAttemptCount(options);\n }\n\n // Do a check to see if we can attempt. If we can then this node will move into the 'RUNNING' state.\n // If we cannot attempt then we have hit our target attempt count, which means that the node has succeeded.\n if (this.canAttempt()) {\n // This node is in the running state and can do its initial attempt.\n this.setState(State.RUNNING);\n\n // We may have already completed an attempt, meaning that the child node will be in the FAILED state.\n // If this is the case then we will have to reset the child node now.\n if (this.child.getState() === State.FAILED) {\n this.child.reset();\n }\n\n // Update the child of this node.\n this.child.update(agent, options);\n\n // If the child moved into the SUCCEEDED state when we updated it then there is nothing left to do and this node has also succeeded.\n // If it has moved into the FAILED state then we have completed the current attempt.\n if (this.child.getState() === State.SUCCEEDED) {\n // The child has succeeded, meaning that this node has succeeded.\n this.setState(State.SUCCEEDED);\n\n return;\n } else if (this.child.getState() === State.FAILED) {\n // We have completed an attempt.\n this.currentAttemptCount += 1;\n }\n } else {\n // This node is in the 'FAILED' state as we cannot iterate any more.\n this.setState(State.FAILED);\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => {\n if (this.attempts !== null) {\n return `RETRY ${this.attempts}x`;\n } else if (this.attemptsMin !== null && this.attemptsMax !== null) {\n return `RETRY ${this.attemptsMin}x-${this.attemptsMax}x`;\n } else {\n return \"RETRY\";\n }\n };\n\n /**\n * Reset the state of the node.\n */\n reset = () => {\n // Reset the state of this node.\n this.setState(State.READY);\n\n // Reset the current attempt count.\n this.currentAttemptCount = 0;\n\n // Reset the child node.\n this.child.reset();\n };\n\n /**\n * Gets whether an attempt can be made.\n * @returns Whether an attempt can be made.\n */\n canAttempt = () => {\n if (this.targetAttemptCount !== null) {\n // We can attempt as long as we have not reached our target attempt count.\n return this.currentAttemptCount < this.targetAttemptCount;\n }\n\n // If neither an attempt count or a condition function were defined then we can attempt indefinitely.\n return true;\n };\n\n /**\n * Sets the target attempt count.\n * @param options The behaviour tree options object.\n */\n setTargetAttemptCount = (options: BehaviourTreeOptions) => {\n // Are we dealing with an explicit attempt count or will we be randomly picking an attempt count between the min and max attempt count.\n if (this.attempts !== null) {\n this.targetAttemptCount = this.attempts;\n } else if (this.attemptsMin !== null && this.attemptsMax !== null) {\n // We will be picking a random attempt count between a min and max attempt count, if the optional 'random'\n // behaviour tree function option is defined then we will be using that, otherwise we will fall back to using Math.random.\n const random = typeof options.random === \"function\" ? options.random : Math.random;\n\n // Pick a random attempt count between a min and max attempt count.\n this.targetAttemptCount = Math.floor(\n random() * (this.attemptsMax - this.attemptsMin + 1) + this.attemptsMin\n );\n } else {\n this.targetAttemptCount = null;\n }\n };\n}\n", "import Decorator from \"./Decorator\";\nimport State from \"../../State\";\nimport Node from \"../Node\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A Flip node.\n * This node wraps a single child and will flip the state of the child state.\n */\nexport default class Flip extends Decorator {\n /**\n * @param attributes The node attributes.\n * @param child The child node.\n */\n constructor(attributes: Attribute[], child: Node) {\n super(\"flip\", attributes, child);\n }\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // If the child has never been updated or is running then we will need to update it now.\n if (this.child.getState() === State.READY || this.child.getState() === State.RUNNING) {\n this.child.update(agent, options);\n }\n\n // The state of this node will depend in the state of its child.\n switch (this.child.getState()) {\n case State.RUNNING:\n this.setState(State.RUNNING);\n break;\n\n case State.SUCCEEDED:\n this.setState(State.FAILED);\n break;\n\n case State.FAILED:\n this.setState(State.SUCCEEDED);\n break;\n\n default:\n this.setState(State.READY);\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => \"FLIP\";\n}\n", "import Node from \"../Node\";\nimport Decorator from \"./Decorator\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A Succeed node.\n * This node wraps a single child and will always move to the 'SUCCEEDED' state when the child moves to a 'SUCCEEDED' or 'FAILED' state.\n */\nexport default class Succeed extends Decorator {\n /**\n * @param attributes The node attributes.\n * @param child The child node.\n */\n constructor(attributes: Attribute[], child: Node) {\n super(\"succeed\", attributes, child);\n }\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // If the child has never been updated or is running then we will need to update it now.\n if (this.child.getState() === State.READY || this.child.getState() === State.RUNNING) {\n this.child.update(agent, options);\n }\n\n // The state of this node will depend in the state of its child.\n switch (this.child.getState()) {\n case State.RUNNING:\n this.setState(State.RUNNING);\n break;\n\n case State.SUCCEEDED:\n case State.FAILED:\n this.setState(State.SUCCEEDED);\n break;\n\n default:\n this.setState(State.READY);\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => \"SUCCEED\";\n}\n", "import Node from \"../Node\";\nimport Decorator from \"./Decorator\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A Fail node.\n * This node wraps a single child and will always move to the 'FAILED' state when the child moves to a 'SUCCEEDED' or 'FAILED' state.\n */\nexport default class Fail extends Decorator {\n /**\n * @param attributes The node attributes.\n * @param child The child node.\n */\n constructor(attributes: Attribute[], child: Node) {\n super(\"fail\", attributes, child);\n }\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // If the child has never been updated or is running then we will need to update it now.\n if (this.child.getState() === State.READY || this.child.getState() === State.RUNNING) {\n this.child.update(agent, options);\n }\n\n // The state of this node will depend in the state of its child.\n switch (this.child.getState()) {\n case State.RUNNING:\n this.setState(State.RUNNING);\n break;\n\n case State.SUCCEEDED:\n case State.FAILED:\n this.setState(State.FAILED);\n break;\n\n default:\n this.setState(State.READY);\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => \"FAIL\";\n}\n", "import createLotto from \"lotto-draw\";\n\nimport Node from \"../Node\";\nimport Composite from \"./Composite\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A LOTTO node.\n * A winning child is picked on the initial update of this node, based on ticket weighting.\n * The state of this node will match the state of the winning child.\n */\nexport default class Lotto extends Composite {\n /**\n * @param attributes The node attributes.\n * @param tickets The child node tickets.\n * @param children The child nodes.\n */\n constructor(attributes: Attribute[], private tickets: number[], children: Node[]) {\n super(\"lotto\", attributes, children);\n }\n\n /**\n * The child node selected to be the active one.\n */\n private selectedChild: Node | undefined;\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // If this node is in the READY state then we need to pick a winning child node.\n if (this.is(State.READY)) {\n // Create a lotto draw with which to randomly pick a child node to become the active one.\n const lottoDraw = createLotto({\n // Hook up the optional 'random' behaviour tree function option to the one used by 'lotto-draw'.\n random: options.random,\n // Pass in each child node as a participant in the lotto draw with their respective ticket count.\n participants: this.children.map((child, index) => [child, this.tickets[index] || 1])\n });\n\n // Randomly pick a child based on ticket weighting, this will become the active child for this composite node.\n this.selectedChild = lottoDraw.draw() || undefined;\n }\n\n // If something went wrong and we don't have an active child then we should throw an error.\n if (!this.selectedChild) {\n throw new Error(\"failed to update lotto node as it has no active child\");\n }\n\n // If the selected child has never been updated or is running then we will need to update it now.\n if (this.selectedChild.getState() === State.READY || this.selectedChild.getState() === State.RUNNING) {\n this.selectedChild.update(agent, options);\n }\n\n // The state of the lotto node is the state of its selected child.\n this.setState(this.selectedChild.getState());\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => (this.tickets.length ? `LOTTO [${this.tickets.join(\",\")}]` : \"LOTTO\");\n}\n", "import Node from \"../Node\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\n\n/**\n * A composite node that wraps child nodes.\n */\nexport default abstract class Composite extends Node {\n /**\n * @param type The node type.\n * @param attributes The node attributes.\n * @param children The child nodes.\n */\n constructor(type: string, attributes: Attribute[], protected children: Node[]) {\n super(type, attributes, []);\n }\n\n /**\n * Gets whether this node is a leaf node.\n */\n isLeafNode = () => false;\n\n /**\n * Gets the children of this node.\n */\n getChildren = () => this.children;\n\n /**\n * Reset the state of the node.\n */\n reset = () => {\n // Reset the state of this node.\n this.setState(State.READY);\n\n // Reset the state of any child nodes.\n this.getChildren().forEach((child) => child.reset());\n };\n\n /**\n * Abort the running of this node.\n * @param agent The agent.\n */\n abort = (agent: Agent) => {\n // There is nothing to do if this node is not in the running state.\n if (!this.is(State.RUNNING)) {\n return;\n }\n\n // Abort any child nodes.\n this.getChildren().forEach((child) => child.abort(agent));\n\n // Reset the state of this node.\n this.reset();\n\n this.getAttribute(\"exit\")?.callAgentFunction(agent, false, true);\n };\n}\n", "import Composite from \"./Composite\";\nimport Node from \"../Node\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A SELECTOR node.\n * The child nodes are executed in sequence until one succeeds or all fail.\n */\nexport default class Selector extends Composite {\n /**\n * @param attributes The node attributes.\n * @param children The child nodes.\n */\n constructor(attributes: Attribute[], protected children: Node[]) {\n super(\"selector\", attributes, children);\n }\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // Iterate over all of the children of this node.\n for (const child of this.children) {\n // If the child has never been updated or is running then we will need to update it now.\n if (child.getState() === State.READY || child.getState() === State.RUNNING) {\n // Update the child of this node.\n child.update(agent, options);\n }\n\n // If the current child has a state of 'SUCCEEDED' then this node is also a 'SUCCEEDED' node.\n if (child.getState() === State.SUCCEEDED) {\n // This node is a 'SUCCEEDED' node.\n this.setState(State.SUCCEEDED);\n\n // There is no need to check the rest of the selector nodes.\n return;\n }\n\n // If the current child has a state of 'FAILED' then we should move on to the next child.\n if (child.getState() === State.FAILED) {\n // Find out if the current child is the last one in the selector.\n // If it is then this sequence node has also failed.\n if (this.children.indexOf(child) === this.children.length - 1) {\n // This node is a 'FAILED' node.\n this.setState(State.FAILED);\n\n // There is no need to check the rest of the selector as we have completed it.\n return;\n } else {\n // The child node failed, try the next one.\n continue;\n }\n }\n\n // The node should be in the 'RUNNING' state.\n if (child.getState() === State.RUNNING) {\n // This node is a 'RUNNING' node.\n this.setState(State.RUNNING);\n\n // There is no need to check the rest of the selector as the current child is still running.\n return;\n }\n\n // The child node was not in an expected state.\n throw new Error(\"child node was not in an expected state.\");\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => \"SELECTOR\";\n}\n", "import Composite from \"./Composite\";\nimport Node from \"../Node\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A SEQUENCE node.\n * The child nodes are executed in sequence until one fails or all succeed.\n */\nexport default class Sequence extends Composite {\n /**\n * @param attributes The node attributes.\n * @param children The child nodes.\n */\n constructor(attributes: Attribute[], protected children: Node[]) {\n super(\"sequence\", attributes, children);\n }\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // Iterate over all of the children of this node.\n for (const child of this.children) {\n // If the child has never been updated or is running then we will need to update it now.\n if (child.getState() === State.READY || child.getState() === State.RUNNING) {\n // Update the child of this node.\n child.update(agent, options);\n }\n\n // If the current child has a state of 'SUCCEEDED' then we should move on to the next child.\n if (child.getState() === State.SUCCEEDED) {\n // Find out if the current child is the last one in the sequence.\n // If it is then this sequence node has also succeeded.\n if (this.children.indexOf(child) === this.children.length - 1) {\n // This node is a 'SUCCEEDED' node.\n this.setState(State.SUCCEEDED);\n\n // There is no need to check the rest of the sequence as we have completed it.\n return;\n } else {\n // The child node succeeded, but we have not finished the sequence yet.\n continue;\n }\n }\n\n // If the current child has a state of 'FAILED' then this node is also a 'FAILED' node.\n if (child.getState() === State.FAILED) {\n // This node is a 'FAILED' node.\n this.setState(State.FAILED);\n\n // There is no need to check the rest of the sequence.\n return;\n }\n\n // The node should be in the 'RUNNING' state.\n if (child.getState() === State.RUNNING) {\n // This node is a 'RUNNING' node.\n this.setState(State.RUNNING);\n\n // There is no need to check the rest of the sequence as the current child is still running.\n return;\n }\n\n // The child node was not in an expected state.\n throw new Error(\"child node was not in an expected state.\");\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => \"SEQUENCE\";\n}\n", "import Composite from \"./Composite\";\nimport State from \"../../State\";\nimport Node from \"../Node\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A PARALLEL node.\n * The child nodes are executed concurrently until one fails or all succeed.\n */\nexport default class Parallel extends Composite {\n /**\n * @param attributes The node attributes.\n * @param children The child nodes.\n */\n constructor(attributes: Attribute[], children: Node[]) {\n super(\"parallel\", attributes, children);\n }\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // Keep a count of the number of succeeded child nodes.\n let succeededCount = 0;\n\n let hasChildFailed = false;\n\n // Iterate over all of the children of this node.\n for (const child of this.children) {\n // If the child has never been updated or is running then we will need to update it now.\n if (child.getState() === State.READY || child.getState() === State.RUNNING) {\n // Update the child of this node.\n child.update(agent, options);\n }\n\n // If the current child has a state of 'SUCCEEDED' then we should move on to the next child.\n if (child.getState() === State.SUCCEEDED) {\n // The child node has succeeded, keep track of this to determine if all children have.\n succeededCount++;\n\n // The child node succeeded, but we have not finished checking every child node yet.\n continue;\n }\n\n // If the current child has a state of 'FAILED' then this node is also a 'FAILED' node.\n if (child.getState() === State.FAILED) {\n hasChildFailed = true;\n\n // There is no need to check the rest of the children.\n break;\n }\n\n // The node should be in the 'RUNNING' state.\n if (child.getState() !== State.RUNNING) {\n // The child node was not in an expected state.\n throw new Error(\"child node was not in an expected state.\");\n }\n }\n\n if (hasChildFailed) {\n // This node is a 'FAILED' node.\n this.setState(State.FAILED);\n\n // Abort every running child.\n for (const child of this.children) {\n if (child.getState() === State.RUNNING) {\n child.abort(agent);\n }\n }\n } else {\n // If all children have succeeded then this node has also succeeded, otherwise it is still running.\n this.setState(succeededCount === this.children.length ? State.SUCCEEDED : State.RUNNING);\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => \"PARALLEL\";\n}\n", "import { AnyArgument } from \"../RootAstNodesBuilder\";\nimport Guard from \"./guards/Guard\";\n\nexport type AttributeDetails = {\n /** The attribute type. */\n type: string;\n\n /** The attribute arguments. */\n args: AnyArgument[];\n};\n\n/**\n * A base node attribute.\n */\nexport default abstract class Attribute {\n /**\n * @param type The node attribute type.\n * @param args The array of attribute argument definitions.\n */\n constructor(protected type: string, protected args: AnyArgument[]) {}\n\n /**\n * Gets the type of the attribute.\n */\n getType = () => this.type;\n\n /**\n * Gets the array of attribute argument definitions.\n */\n getArguments = () => this.args;\n\n /**\n * Gets the attribute details.\n */\n abstract getDetails(): TAttributeDetails;\n\n /**\n * Gets whether this attribute is a guard.\n */\n abstract isGuard: () => this is Guard;\n}\n", "import { Agent } from \"../../Agent\";\nimport { AnyArgument } from \"../../RootAstNodesBuilder\";\nimport Attribute, { AttributeDetails } from \"../Attribute\";\n\nexport type GuardAttributeDetails = {\n /** The name of the condition function that determines whether the guard is satisfied. */\n condition: string;\n} & AttributeDetails;\n\n/**\n * A base node guard attribute.\n */\nexport default abstract class Guard extends Attribute {\n /**\n * @param type The node attribute type.\n * @param args The array of decorator argument definitions.\n * @param condition The name of the condition function that determines whether the guard is satisfied.\n */\n constructor(type: string, args: AnyArgument[], private condition: string) {\n super(type, args);\n }\n\n /**\n * Gets the name of the condition function that determines whether the guard is satisfied.\n */\n getCondition = () => this.condition;\n\n /**\n * Gets whether this attribute is a guard.\n */\n isGuard = () => true;\n\n /**\n * Gets the attribute details.\n */\n getDetails(): GuardAttributeDetails {\n return {\n type: this.getType(),\n args: this.getArguments(),\n condition: this.getCondition()\n };\n }\n\n /**\n * Gets whether the guard is satisfied.\n * @param agent The agent.\n * @returns Whether the guard is satisfied.\n */\n abstract isSatisfied(agent: Agent): boolean;\n}\n", "import Guard from \"./Guard\";\nimport Lookup from \"../../Lookup\";\nimport { Agent } from \"../../Agent\";\nimport { AnyArgument } from \"../../RootAstNodesBuilder\";\n\n/**\n * A WHILE guard which is satisfied as long as the given condition remains true.\n */\nexport default class While extends Guard {\n /**\n * @param condition The name of the condition function that determines whether the guard is satisfied.\n * @param args The array of decorator argument definitions.\n */\n constructor(condition: string, args: AnyArgument[]) {\n super(\"while\", args, condition);\n }\n\n /**\n * Gets whether the guard is satisfied.\n * @param agent The agent.\n * @returns Whether the guard is satisfied.\n */\n isSatisfied = (agent: Agent) => {\n // Attempt to get the invoker for the condition function.\n const conditionFuncInvoker = Lookup.getFuncInvoker(agent, this.getCondition());\n\n // The condition function should be defined.\n if (conditionFuncInvoker === null) {\n throw new Error(\n `cannot evaluate node guard as the condition '${this.getCondition()}' function is not defined on the agent and has not been registered`\n );\n }\n\n // Call the condition function to determine whether this guard is satisfied.\n return !!conditionFuncInvoker(this.args);\n };\n}\n", "import Guard from \"./Guard\";\nimport Lookup from \"../../Lookup\";\nimport { Agent } from \"../../Agent\";\nimport { AnyArgument } from \"../../RootAstNodesBuilder\";\n\n/**\n * An UNTIL guard which is satisfied as long as the given condition remains false.\n */\nexport default class Until extends Guard {\n /**\n * @param condition The name of the condition function that determines whether the guard is satisfied.\n * @param args The array of decorator argument definitions.\n */\n constructor(condition: string, args: AnyArgument[]) {\n super(\"until\", args, condition);\n }\n\n /**\n * Gets whether the guard is satisfied.\n * @param agent The agent.\n * @returns Whether the guard is satisfied.\n */\n isSatisfied = (agent: Agent) => {\n // Attempt to get the invoker for the condition function.\n const conditionFuncInvoker = Lookup.getFuncInvoker(agent, this.getCondition());\n\n // The condition function should be defined.\n if (conditionFuncInvoker === null) {\n throw new Error(\n `cannot evaluate node guard as the condition '${this.getCondition()}' function is not defined on the agent and has not been registered`\n );\n }\n\n // Call the condition function to determine whether this guard is satisfied.\n return !!!conditionFuncInvoker(this.args);\n };\n}\n", "import { Agent } from \"../../Agent\";\nimport { AnyArgument } from \"../../RootAstNodesBuilder\";\nimport Attribute, { AttributeDetails } from \"../Attribute\";\n\nexport type CallbackAttributeDetails = {\n /** The name of the agent function that is called. */\n functionName: string;\n} & AttributeDetails;\n\n/**\n * A base node callback attribute.\n */\nexport default abstract class Callback extends Attribute {\n /**\n * @param type The node attribute type.\n * @param args The array of decorator argument definitions.\n * @param functionName The name of the agent function to call.\n */\n constructor(type: string, args: AnyArgument[], private functionName: string) {\n super(type, args);\n }\n\n /**\n * Gets the name of the agent function to call.\n */\n getFunctionName = () => this.functionName;\n\n /**\n * Gets whether this attribute is a guard.\n */\n isGuard = () => false;\n\n /**\n * Gets the attribute details.\n */\n getDetails(): CallbackAttributeDetails {\n return {\n type: this.getType(),\n args: this.getArguments(),\n functionName: this.getFunctionName()\n };\n }\n\n /**\n * Attempt to call the agent function that this callback refers to.\n * @param agent The agent.\n */\n abstract callAgentFunction: (agent: Agent, isSuccess: boolean, isAborted: boolean) => void;\n}\n", "import Callback from \"./Callback\";\nimport Lookup from \"../../Lookup\";\nimport { Agent } from \"../../Agent\";\nimport { AnyArgument } from \"../../RootAstNodesBuilder\";\n\n/**\n * An ENTRY callback which defines an agent function to call when the associated node is updated and moves out of running state.\n */\nexport default class Entry extends Callback {\n /**\n * @param functionName The name of the agent function to call.\n * @param args The array of callback argument definitions.\n */\n constructor(functionName: string, args: AnyArgument[]) {\n super(\"entry\", args, functionName);\n }\n\n /**\n * Attempt to call the agent function that this callback refers to.\n * @param agent The agent.\n */\n callAgentFunction = (agent: Agent) => {\n // Attempt to get the invoker for the callback function.\n const callbackFuncInvoker = Lookup.getFuncInvoker(agent, this.getFunctionName());\n\n // The callback function should be defined.\n if (callbackFuncInvoker === null) {\n throw new Error(\n `cannot call entry function '${this.getFunctionName()}' as is not defined on the agent and has not been registered`\n );\n }\n\n // Call the callback function.\n callbackFuncInvoker(this.args);\n };\n}\n", "import Callback from \"./Callback\";\nimport Lookup, { AnyExitArgument } from \"../../Lookup\";\nimport { Agent } from \"../../Agent\";\nimport { AnyArgument } from \"../../RootAstNodesBuilder\";\n\n/**\n * An EXIT callback which defines an agent function to call when the associated node is updated and moves to a finished state or is aborted.\n */\nexport default class Exit extends Callback {\n /**\n * @param functionName The name of the agent function to call.\n * @param args The array of callback argument definitions.\n */\n constructor(functionName: string, args: AnyArgument[]) {\n super(\"exit\", args, functionName);\n }\n\n /**\n * Attempt to call the agent function that this callback refers to.\n * @param agent The agent.\n * @param isSuccess Whether the decorated node was left with a success state.\n * @param isAborted Whether the decorated node was aborted.\n */\n callAgentFunction = (agent: Agent, isSuccess: boolean, isAborted: boolean) => {\n // Attempt to get the invoker for the callback function.\n const callbackFuncInvoker = Lookup.getFuncInvoker(agent, this.getFunctionName());\n\n // The callback function should be defined.\n if (callbackFuncInvoker === null) {\n throw new Error(\n `cannot call exit function '${this.getFunctionName()}' as is not defined on the agent and has not been registered`\n );\n }\n\n // Call the callback function\n callbackFuncInvoker([{ value: { succeeded: isSuccess, aborted: isAborted } }, ...this.args]);\n };\n}\n", "import Callback from \"./Callback\";\nimport Lookup from \"../../Lookup\";\nimport { Agent } from \"../../Agent\";\nimport { AnyArgument } from \"../../RootAstNodesBuilder\";\n\n/**\n * A STEP callback which defines an agent function to call when the associated node is updated.\n */\nexport default class Step extends Callback {\n /**\n * @param functionName The name of the agent function to call.\n * @param args The array of callback argument definitions.\n */\n constructor(functionName: string, args: AnyArgument[]) {\n super(\"step\", args, functionName);\n }\n\n /**\n * Attempt to call the agent function that this callback refers to.\n * @param agent The agent.\n */\n callAgentFunction = (agent: Agent) => {\n // Attempt to get the invoker for the callback function.\n const callbackFuncInvoker = Lookup.getFuncInvoker(agent, this.getFunctionName());\n\n // The callback function should be defined.\n if (callbackFuncInvoker === null) {\n throw new Error(\n `cannot call step function '${this.getFunctionName()}' as is not defined on the agent and has not been registered`\n );\n }\n\n // Call the callback function.\n callbackFuncInvoker(this.args);\n };\n}\n", "import Action from \"./nodes/leaf/Action\";\nimport Condition from \"./nodes/leaf/Condition\";\nimport Wait from \"./nodes/leaf/Wait\";\nimport Root from \"./nodes/decorator/Root\";\nimport Repeat from \"./nodes/decorator/Repeat\";\nimport Retry from \"./nodes/decorator/Retry\";\nimport Flip from \"./nodes/decorator/Flip\";\nimport Succeed from \"./nodes/decorator/Succeed\";\nimport Fail from \"./nodes/decorator/Fail\";\nimport Lotto from \"./nodes/composite/Lotto\";\nimport Selector from \"./nodes/composite/Selector\";\nimport Sequence from \"./nodes/composite/Sequence\";\nimport Parallel from \"./nodes/composite/Parallel\";\nimport Node from \"./nodes/Node\";\nimport While from \"./attributes/guards/While\";\nimport Until from \"./attributes/guards/Until\";\nimport Entry from \"./attributes/callbacks/Entry\";\nimport Exit from \"./attributes/callbacks/Exit\";\nimport Step from \"./attributes/callbacks/Step\";\nimport Callback from \"./attributes/callbacks/Callback\";\nimport Guard from \"./attributes/guards/Guard\";\nimport Attribute from \"./attributes/Attribute\";\nimport Composite from \"./nodes/composite/Composite\";\nimport Decorator from \"./nodes/decorator/Decorator\";\nimport Leaf from \"./nodes/leaf/Leaf\";\n\nexport type Argument = {\n value: T;\n type: string; // Used for validation.\n};\ntype NullArgument = Argument & {\n type: \"null\";\n};\ntype BooleanArgument = Argument & {\n type: \"boolean\";\n};\ntype NumberArgument = Argument & {\n type: \"number\";\n isInteger: boolean; // Used for validation.\n};\ntype StringPlaceholderArgument = Argument & {\n type: \"string\";\n};\ntype IdentifierArgument = Argument & {\n type: \"identifier\";\n};\nexport type AnyArgument =\n | NullArgument\n | BooleanArgument\n | NumberArgument\n | StringPlaceholderArgument\n | IdentifierArgument;\n\n/**\n * The node attribute factories.\n */\nconst AttributeFactories: {\n [key: string]: (functionName: string, attributeArguments: AnyArgument[]) => Callback | Guard;\n} = {\n WHILE: (condition: string, attributeArguments: AnyArgument[]) => new While(condition, attributeArguments),\n UNTIL: (condition: string, attributeArguments: AnyArgument[]) => new Until(condition, attributeArguments),\n ENTRY: (functionName: string, attributeArguments: AnyArgument[]) => new Entry(functionName, attributeArguments),\n EXIT: (functionName: string, attributeArguments: AnyArgument[]) => new Exit(functionName, attributeArguments),\n STEP: (functionName: string, attributeArguments: AnyArgument[]) => new Step(functionName, attributeArguments)\n};\n\ntype Validatable = {\n children?: AstNode[];\n validate: (depth: number) => void;\n};\n\ntype NodeInstanceCreator = (\n namedRootNodeProvider: (name: string) => RootAstNode,\n visitedBranches: string[]\n) => T;\n\nexport type AstNode = Validatable & {\n type: string;\n createNodeInstance: NodeInstanceCreator;\n};\n\nexport type LeafAstNode = AstNode & {\n type: \"action\" | \"condition\" | \"wait\";\n attributes: Attribute[];\n};\n\nexport type CompositeAstNode = AstNode & {\n type: \"lotto\" | \"parallel\" | \"selector\" | \"sequence\";\n attributes: Attribute[];\n children: AstNode[];\n};\n\nexport type DecoratorAstNode = AstNode & {\n type: \"fail\" | \"flip\" | \"repeat\" | \"retry\" | \"root\" | \"succeed\";\n attributes: Attribute[];\n children: AstNode[];\n};\n\nexport type BranchAstNode = AstNode & {\n type: \"branch\";\n branchName: \"\" | string;\n};\n\nexport type LottoAstNode = CompositeAstNode & {\n type: \"lotto\";\n tickets: number[];\n};\n\nexport type RootAstNode = DecoratorAstNode & {\n type: \"root\";\n name: null | string;\n};\n\nexport type RepeatAstNode = DecoratorAstNode & {\n type: \"repeat\";\n iterations: number | null;\n iterationsMin: number | null;\n iterationsMax: number | null;\n};\n\nexport type RetryAstNode = DecoratorAstNode & {\n type: \"retry\";\n attempts: number | null;\n attemptsMin: number | null;\n attemptsMax: number | null;\n};\n\nexport type ActionAstNode = LeafAstNode & {\n type: \"action\";\n actionName: string;\n actionArguments: AnyArgument[];\n};\n\nexport type ConditionAstNode = LeafAstNode & {\n type: \"condition\";\n conditionName: string;\n conditionArguments: AnyArgument[];\n};\n\nexport type WaitAstNode = LeafAstNode & {\n type: \"wait\";\n duration: number | null;\n durationMin: number | null;\n durationMax: number | null;\n};\n\nexport type AnyAstNode =\n | BranchAstNode\n | CompositeAstNode\n | LottoAstNode\n | DecoratorAstNode\n | RootAstNode\n | RepeatAstNode\n | RetryAstNode\n | LeafAstNode\n | ActionAstNode\n | ConditionAstNode\n | WaitAstNode;\n\n/**\n * The AST node factories.\n */\nconst ASTNodeFactories = {\n ROOT: (): RootAstNode => ({\n type: \"root\",\n attributes: [],\n name: null,\n children: [],\n validate(depth: number) {\n // A root node cannot be the child of another node.\n if (depth > 1) {\n throw new Error(\"a root node cannot be the child of another node\");\n }\n\n // A root node must have a single child node.\n if (this.children.length !== 1) {\n throw new Error(\"a root node must have a single child\");\n }\n },\n createNodeInstance(namedRootNodeProvider, visitedBranches) {\n return new Root(\n this.attributes,\n this.children![0].createNodeInstance(namedRootNodeProvider, visitedBranches.slice())\n );\n }\n }),\n BRANCH: (): BranchAstNode => ({\n type: \"branch\",\n branchName: \"\",\n validate() {},\n createNodeInstance(namedRootNodeProvider, visitedBranches) {\n // Try to find the root node with a matching branch name.\n const targetRootNode = namedRootNodeProvider(this.branchName);\n\n // If we have already visited this branch then we have a circular dependency.\n if (visitedBranches.indexOf(this.branchName) !== -1) {\n throw new Error(`circular dependency found in branch node references for branch '${this.branchName}'`);\n }\n\n // If we have a target root node, then the node instance we want will be the first and only child of the referenced root node.\n if (targetRootNode) {\n return targetRootNode\n .createNodeInstance(namedRootNodeProvider, visitedBranches.concat(this.branchName))\n .getChildren()[0];\n } else {\n throw new Error(`branch references root node '${this.branchName}' which has not been defined`);\n }\n }\n }),\n SELECTOR: (): CompositeAstNode => ({\n type: \"selector\",\n attributes: [],\n children: [],\n validate() {\n // A selector node must have at least a single node.\n if (this.children.length < 1) {\n throw new Error(\"a selector node must have at least a single child\");\n }\n },\n createNodeInstance(namedRootNodeProvider, visitedBranches) {\n return new Selector(\n this.attributes,\n this.children.map((child) => child.createNodeInstance(namedRootNodeProvider, visitedBranches.slice()))\n );\n }\n }),\n SEQUENCE: (): CompositeAstNode => ({\n type: \"sequence\",\n attributes: [],\n children: [],\n validate() {\n // A sequence node must have at least a single node.\n if (this.children.length < 1) {\n throw new Error(\"a sequence node must have at least a single child\");\n }\n },\n createNodeInstance(namedRootNodeProvider, visitedBranches) {\n return new Sequence(\n this.attributes,\n this.children.map((child) => child.createNodeInstance(namedRootNodeProvider, visitedBranches.slice()))\n );\n }\n }),\n PARALLEL: (): CompositeAstNode => ({\n type: \"parallel\",\n attributes: [],\n children: [],\n validate() {\n // A parallel node must have at least a single node.\n if (this.children.length < 1) {\n throw new Error(\"a parallel node must have at least a single child\");\n }\n },\n createNodeInstance(namedRootNodeProvider, visitedBranches) {\n return new Parallel(\n this.attributes,\n this.children.map((child) => child.createNodeInstance(namedRootNodeProvider, visitedBranches.slice()))\n );\n }\n }),\n LOTTO: (): LottoAstNode => ({\n type: \"lotto\",\n attributes: [],\n children: [],\n tickets: [],\n validate() {\n // A lotto node must have at least a single node.\n if (this.children!.length < 1) {\n throw new Error(\"a lotto node must have at least a single child\");\n }\n },\n createNodeInstance(namedRootNodeProvider, visitedBranches) {\n return new Lotto(\n this.attributes,\n this.tickets!,\n this.children!.map((child) => child.createNodeInstance(namedRootNodeProvider, visitedBranches.slice()))\n );\n }\n }),\n REPEAT: (): RepeatAstNode => ({\n type: \"repeat\",\n attributes: [],\n iterations: null,\n iterationsMin: null,\n iterationsMax: null,\n children: [],\n validate() {\n // A repeat node must have a single node.\n if (this.children!.length !== 1) {\n throw new Error(\"a repeat node must have a single child\");\n }\n\n if (this.iterations !== null) {\n // A repeat node must have a positive number of iterations if defined.\n if (this.iterations < 0) {\n throw new Error(\"a repeat node must have a positive number of iterations if defined\");\n }\n } else if (this.iterationsMin !== null && this.iterationsMax !== null) {\n // A repeat node must have a positive min and max iteration count if they are defined.\n if (this.iterationsMin < 0 || this.iterationsMax < 0) {\n throw new Error(\n \"a repeat node must have a positive minimum and maximum iteration count if defined\"\n );\n }\n\n // A repeat node must not have an minimum iteration count that exceeds the maximum iteration count.\n if (this.iterationsMin > this.iterationsMax) {\n throw new Error(\n \"a repeat node must not have a minimum iteration count that exceeds the maximum iteration count\"\n );\n }\n } else {\n // If we have no explicit iteration count or a minimum and maximum iteration count set then we are dealing with a repeat node that iterates indefinitely.\n }\n },\n createNodeInstance(namedRootNodeProvider, visitedBranches) {\n return new Repeat(\n this.attributes,\n this.iterations,\n this.iterationsMin,\n this.iterationsMax,\n this.children![0].createNodeInstance(namedRootNodeProvider, visitedBranches.slice())\n );\n }\n }),\n RETRY: (): RetryAstNode => ({\n type: \"retry\",\n attributes: [],\n attempts: null,\n attemptsMin: null,\n attemptsMax: null,\n children: [],\n validate() {\n // A retry node must have a single node.\n if (this.children!.length !== 1) {\n throw new Error(\"a retry node must have a single child\");\n }\n\n if (this.attempts !== null) {\n // A retry node must have a positive number of attempts if defined.\n if (this.attempts < 0) {\n throw new Error(\"a retry node must have a positive number of attempts if defined\");\n }\n } else if (this.attemptsMin !== null && this.attemptsMax !== null) {\n // A retry node must have a positive min and max attempts count if they are defined.\n if (this.attemptsMin < 0 || this.attemptsMax < 0) {\n throw new Error(\"a retry node must have a positive minimum and maximum attempt count if defined\");\n }\n\n // A retry node must not have a minimum attempt count that exceeds the maximum attempt count.\n if (this.attemptsMin > this.attemptsMax) {\n throw new Error(\n \"a retry node must not have a minimum attempt count that exceeds the maximum attempt count\"\n );\n }\n } else {\n // If we have no explicit attempt count or a minimum and maximum attempt count set then we are dealing with a retry node that attempts indefinitely.\n }\n },\n createNodeInstance(namedRootNodeProvider, visitedBranches) {\n return new Retry(\n this.attributes,\n this.attempts,\n this.attemptsMin,\n this.attemptsMax,\n this.children![0].createNodeInstance(namedRootNodeProvider, visitedBranches.slice())\n );\n }\n }),\n FLIP: (): DecoratorAstNode => ({\n type: \"flip\",\n attributes: [],\n children: [],\n validate() {\n // A flip node must have a single node.\n if (this.children!.length !== 1) {\n throw new Error(\"a flip node must have a single child\");\n }\n },\n createNodeInstance(namedRootNodeProvider, visitedBranches) {\n return new Flip(\n this.attributes,\n this.children![0].createNodeInstance(namedRootNodeProvider, visitedBranches.slice())\n );\n }\n }),\n SUCCEED: (): DecoratorAstNode => ({\n type: \"succeed\",\n attributes: [],\n children: [],\n validate() {\n // A succeed node must have a single node.\n if (this.children!.length !== 1) {\n throw new Error(\"a succeed node must have a single child\");\n }\n },\n createNodeInstance(namedRootNodeProvider, visitedBranches) {\n return new Succeed(\n this.attributes,\n this.children![0].createNodeInstance(namedRootNodeProvider, visitedBranches.slice())\n );\n }\n }),\n FAIL: (): DecoratorAstNode => ({\n type: \"fail\",\n attributes: [],\n children: [],\n validate() {\n // A fail node must have a single node.\n if (this.children!.length !== 1) {\n throw new Error(\"a fail node must have a single child\");\n }\n },\n createNodeInstance(namedRootNodeProvider, visitedBranches) {\n return new Fail(\n this.attributes,\n this.children![0].createNodeInstance(namedRootNodeProvider, visitedBranches.slice())\n );\n }\n }),\n WAIT: (): WaitAstNode => ({\n type: \"wait\",\n attributes: [],\n duration: null,\n durationMin: null,\n durationMax: null,\n validate() {\n if (this.duration !== null) {\n // If an explict duration was defined then it must be a positive number.\n if (this.duration < 0) {\n throw new Error(\"a wait node must have a positive duration\");\n }\n } else if (this.durationMin !== null && this.durationMax !== null) {\n // A wait node must have a positive min and max duration.\n if (this.durationMin < 0 || this.durationMax < 0) {\n throw new Error(\"a wait node must have a positive minimum and maximum duration\");\n }\n\n // A wait node must not have a minimum duration that exceeds the maximum duration.\n if (this.durationMin > this.durationMax) {\n throw new Error(\"a wait node must not have a minimum duration that exceeds the maximum duration\");\n }\n } else {\n // If we have no explicit duration or duration bounds set then we are dealing with a wait node that waits indefinitely.\n }\n },\n createNodeInstance() {\n return new Wait(this.attributes, this.duration, this.durationMin, this.durationMax);\n }\n }),\n ACTION: (): ActionAstNode => ({\n type: \"action\",\n attributes: [],\n actionName: \"\",\n actionArguments: [],\n validate() {},\n createNodeInstance() {\n return new Action(this.attributes, this.actionName!, this.actionArguments!);\n }\n }),\n CONDITION: (): ConditionAstNode => ({\n type: \"condition\",\n attributes: [],\n conditionName: \"\",\n conditionArguments: [],\n validate() {},\n createNodeInstance() {\n return new Condition(this.attributes, this.conditionName!, this.conditionArguments!);\n }\n })\n};\n\ntype OtherAstNodes = AstNode[];\n\n/**\n * Create an array of root AST nodes based on the given definition.\n * @param definition The definition to parse the AST nodes from.\n * @returns The base definition AST nodes.\n */\nexport default function buildRootASTNodes(definition: string): RootAstNode[] {\n // Swap out any node/attribute argument string literals with a placeholder and get a mapping of placeholders to original values as well as the processed definition.\n const { placeholders, processedDefinition } = substituteStringLiterals(definition);\n\n // Convert the processed definition (with substituted string literals) into an array of raw tokens.\n const tokens = parseTokensFromDefinition(processedDefinition);\n\n // There must be at least 3 tokens for the tree definition to be valid. 'ROOT', '{' and '}'.\n if (tokens.length < 3) {\n throw new Error(\"invalid token count\");\n }\n\n // We should have a matching number of '{' and '}' tokens. If not, then there are scopes that have not been properly closed.\n if (tokens.filter((token) => token === \"{\").length !== tokens.filter((token) => token === \"}\").length) {\n throw new Error(\"scope character mismatch\");\n }\n\n // Create a stack of node children arrays, starting with a definition scope.\n const stack: [RootAstNode[], ...OtherAstNodes[]] = [[]];\n const rootScope = stack[0];\n\n // We should keep processing the raw tokens until we run out of them.\n while (tokens.length) {\n // Grab the next token.\n const token = tokens.shift();\n\n const currentScope = stack[stack.length - 1] as OtherAstNodes;\n\n // How we create the next AST token depends on the current raw token value.\n switch (token!.toUpperCase()) {\n case \"ROOT\": {\n // Create a ROOT AST node.\n const node = ASTNodeFactories.ROOT();\n\n // Push the ROOT node into the current scope.\n rootScope.push(node);\n\n // We may have a root node name defined as an argument.\n if (tokens[0] === \"[\") {\n const rootArguments = getArguments(tokens, placeholders);\n\n // We should have only a single argument that is not an empty string for a root node, which is the root name identifier.\n if (rootArguments.length === 1 && rootArguments[0].type === \"identifier\") {\n // The root name will be the first and only node argument.\n node.name = rootArguments[0].value as string;\n } else {\n throw new Error(\"expected single root name argument\");\n }\n }\n\n // Try to pick any attributes off of the token stack.\n node.attributes = getAttributes(tokens, placeholders);\n\n popAndCheck(tokens, \"{\");\n\n // The new scope is that of the new ROOT nodes children.\n stack.push(node.children!);\n break;\n }\n\n case \"BRANCH\": {\n // Create a BRANCH AST node.\n const node = ASTNodeFactories.BRANCH();\n\n // Push the BRANCH node into the current scope.\n currentScope.push(node);\n\n // We must have arguments defined, as we require a branch name argument.\n if (tokens[0] !== \"[\") {\n throw new Error(\"expected single branch name argument\");\n }\n\n // The branch name will be defined as a node argument.\n const branchArguments = getArguments(tokens, placeholders);\n\n // We should have only a single identifer argument for a branch node, which is the branch name.\n if (branchArguments.length === 1 && branchArguments[0].type === \"identifier\") {\n // The branch name will be the first and only node argument.\n node.branchName = branchArguments[0].value as string;\n } else {\n throw new Error(\"expected single branch name argument\");\n }\n break;\n }\n\n case \"SELECTOR\": {\n // Create a SELECTOR AST node.\n const node = ASTNodeFactories.SELECTOR();\n\n // Push the SELECTOR node into the current scope.\n currentScope.push(node);\n\n // Try to pick any attributes off of the token stack.\n node.attributes = getAttributes(tokens, placeholders);\n\n popAndCheck(tokens, \"{\");\n\n // The new scope is that of the new SELECTOR nodes children.\n stack.push(node.children!);\n break;\n }\n\n case \"SEQUENCE\": {\n // Create a SEQUENCE AST node.\n const node = ASTNodeFactories.SEQUENCE();\n\n // Push the SEQUENCE node into the current scope.\n currentScope.push(node);\n\n // Try to pick any attributes off of the token stack.\n node.attributes = getAttributes(tokens, placeholders);\n\n popAndCheck(tokens, \"{\");\n\n // The new scope is that of the new SEQUENCE nodes children.\n stack.push(node.children!);\n break;\n }\n\n case \"PARALLEL\": {\n // Create a PARALLEL AST node.\n const node = ASTNodeFactories.PARALLEL();\n\n // Push the PARALLEL node into the current scope.\n currentScope.push(node);\n\n // Try to pick any attributes off of the token stack.\n node.attributes = getAttributes(tokens, placeholders);\n\n popAndCheck(tokens, \"{\");\n\n // The new scope is that of the new PARALLEL nodes children.\n stack.push(node.children!);\n break;\n }\n\n case \"LOTTO\": {\n // Create a LOTTO AST node.\n const node = ASTNodeFactories.LOTTO();\n\n // Push the LOTTO node into the current scope.\n currentScope.push(node);\n\n // If the next token is a '[' character then some ticket counts have been defined as arguments.\n if (tokens[0] === \"[\") {\n // Get the ticket count arguments, each argument must be a number.\n node.tickets = getArguments(\n tokens,\n placeholders,\n (arg) => arg.type === \"number\" && !!arg.isInteger,\n \"lotto node ticket counts must be integer values\"\n ).map((argument) => argument.value as number);\n }\n\n // Try to pick any attributes off of the token stack.\n node.attributes = getAttributes(tokens, placeholders);\n\n popAndCheck(tokens, \"{\");\n\n // The new scope is that of the new LOTTO nodes children.\n stack.push(node.children!);\n break;\n }\n\n case \"CONDITION\": {\n // Create a CONDITION AST node.\n const node = ASTNodeFactories.CONDITION();\n\n // Push the CONDITION node into the current scope.\n currentScope.push(node);\n\n // We must have arguments defined, as we require a condition function name argument.\n if (tokens[0] !== \"[\") {\n throw new Error(\"expected condition name identifier argument\");\n }\n\n // Grab the condition node arguments.\n const conditionArguments = getArguments(tokens, placeholders);\n\n // We should have at least a single identifier argument for a condition node, which is the condition function name.\n if (conditionArguments.length && conditionArguments[0].type === \"identifier\") {\n // The condition function name will be the first node argument.\n node.conditionName = conditionArguments.shift()!.value as string;\n } else {\n throw new Error(\"expected condition name identifier argument\");\n }\n\n // Only the first argument should have been an identifier, all following arguments must be string, number, boolean or null.\n conditionArguments\n .filter((arg) => arg.type === \"identifier\")\n .forEach((arg) => {\n throw new Error(\n \"invalid condition node argument value '\" +\n arg.value +\n \"', must be string, number, boolean or null\"\n );\n });\n\n // Any node arguments that follow the condition name identifier will be treated as condition function arguments.\n node.conditionArguments = conditionArguments;\n\n // Try to pick any attributes off of the token stack.\n node.attributes = getAttributes(tokens, placeholders);\n break;\n }\n\n case \"FLIP\": {\n // Create a FLIP AST node.\n const node = ASTNodeFactories.FLIP();\n\n // Push the Flip node into the current scope.\n currentScope.push(node);\n\n // Try to pick any attributes off of the token stack.\n node.attributes = getAttributes(tokens, placeholders);\n\n popAndCheck(tokens, \"{\");\n\n // The new scope is that of the new FLIP nodes children.\n stack.push(node.children!);\n break;\n }\n\n case \"SUCCEED\": {\n // Create a SUCCEED AST node.\n const node = ASTNodeFactories.SUCCEED();\n\n // Push the Succeed node into the current scope.\n currentScope.push(node);\n\n // Try to pick any attributes off of the token stack.\n node.attributes = getAttributes(tokens, placeholders);\n\n popAndCheck(tokens, \"{\");\n\n // The new scope is that of the new Succeed nodes children.\n stack.push(node.children!);\n break;\n }\n\n case \"FAIL\": {\n // Create a FAIL AST node.\n const node = ASTNodeFactories.FAIL();\n\n // Push the Fail node into the current scope.\n currentScope.push(node);\n\n // Try to pick any attributes off of the token stack.\n node.attributes = getAttributes(tokens, placeholders);\n\n popAndCheck(tokens, \"{\");\n\n // The new scope is that of the new Fail nodes children.\n stack.push(node.children!);\n break;\n }\n\n case \"WAIT\": {\n // Create a WAIT AST node.\n const node = ASTNodeFactories.WAIT();\n\n // Push the WAIT node into the current scope.\n currentScope.push(node);\n\n // The arguments of a wait node are optional. We may have:\n // - No node arguments, in which case the wait will be indefinite until it is aborted.\n // - One node argument which will be the explicit duration of the wait.\n // - Two node arguments which define the min and max duration bounds from which a random duration will be picked.\n if (tokens[0] === \"[\") {\n // Get the optional duration and longest duration of the wait.\n const nodeArguments = getArguments(\n tokens,\n placeholders,\n (arg) => arg.type === \"number\" && !!arg.isInteger,\n \"wait node durations must be integer values\"\n ).map((argument) => argument.value);\n\n // We may have:\n // - One node argument which will be the explicit duration of the wait.\n // - Two node arguments which define the min and max duration bounds from which a random duration will be picked.\n // - Too many arguments, which is not valid.\n if (nodeArguments.length === 1) {\n // An explicit duration was defined.\n node.duration = nodeArguments[0] as number;\n } else if (nodeArguments.length === 2) {\n // Min and max duration bounds were defined from which a random duration will be picked.\n node.durationMin = nodeArguments[0] as number;\n node.durationMax = nodeArguments[1] as number;\n } else if (nodeArguments.length > 2) {\n // An incorrect number of durations was defined.\n throw new Error(\"invalid number of wait node duration arguments defined\");\n }\n }\n\n // Try to pick any attributes off of the token stack.\n node.attributes = getAttributes(tokens, placeholders);\n break;\n }\n\n case \"REPEAT\": {\n // Create a REPEAT AST node.\n const node = ASTNodeFactories.REPEAT();\n\n // Push the REPEAT node into the current scope.\n currentScope.push(node);\n\n // The arguments of a repeat node are optional. We may have:\n // - No node arguments, in which case the repeat note will iterate indefinitely.\n // - One node argument which will be the explicit number of iterations to make.\n // - Two node arguments which define the min and max iteration bounds from which a random iteration count will be picked.\n if (tokens[0] === \"[\") {\n // An iteration count has been defined. Get the iteration and potential maximum iteration of the wait.\n const nodeArguments = getArguments(\n tokens,\n placeholders,\n (arg) => arg.type === \"number\" && !!arg.isInteger,\n \"repeat node iteration counts must be integer values\"\n ).map((argument) => argument.value);\n\n // We should have got one or two iteration counts.\n if (nodeArguments.length === 1) {\n // A static iteration count was defined.\n node.iterations = nodeArguments[0] as number;\n } else if (nodeArguments.length === 2) {\n // A minimum and maximum iteration count was defined.\n node.iterationsMin = nodeArguments[0] as number;\n node.iterationsMax = nodeArguments[1] as number;\n } else {\n // An incorrect number of iteration counts was defined.\n throw new Error(\"invalid number of repeat node iteration count arguments defined\");\n }\n }\n\n // Try to pick any attributes off of the token stack.\n node.attributes = getAttributes(tokens, placeholders);\n\n popAndCheck(tokens, \"{\");\n\n // The new scope is that of the new REPEAT nodes children.\n stack.push(node.children!);\n break;\n }\n\n case \"RETRY\": {\n // Create a RETRY AST node.\n const node = ASTNodeFactories.RETRY();\n\n // Push the RETRY node into the current scope.\n currentScope.push(node);\n\n // The arguments of a retry node are optional. We may have:\n // - No node arguments, in which case the retry note will attempt indefinitely.\n // - One node argument which will be the explicit number of attempts to make.\n // - Two node arguments which define the min and max attempt bounds from which a random attempt count will be picked.\n if (tokens[0] === \"[\") {\n // An attempt count has been defined. Get the attempt count and potential maximum attempt count of the wait.\n const nodeArguments = getArguments(\n tokens,\n placeholders,\n (arg) => arg.type === \"number\" && !!arg.isInteger,\n \"retry node attempt counts must be integer values\"\n ).map((argument) => argument.value);\n\n // We should have got one or two attempt counts.\n if (nodeArguments.length === 1) {\n // A static attempt count was defined.\n node.attempts = nodeArguments[0] as number;\n } else if (nodeArguments.length === 2) {\n // A minimum and maximum attempt count was defined.\n node.attemptsMin = nodeArguments[0] as number;\n node.attemptsMax = nodeArguments[1] as number;\n } else {\n // An incorrect number of attempt counts was defined.\n throw new Error(\"invalid number of retry node attempt count arguments defined\");\n }\n }\n\n // Try to pick any attributes off of the token stack.\n node.attributes = getAttributes(tokens, placeholders);\n\n popAndCheck(tokens, \"{\");\n\n // The new scope is that of the new RETRY nodes children.\n stack.push(node.children!);\n break;\n }\n\n case \"ACTION\": {\n // Create a ACTION AST node.\n const node = ASTNodeFactories.ACTION();\n\n // Push the ACTION node into the current scope.\n currentScope.push(node);\n\n // We must have arguments defined, as we require an action name argument.\n if (tokens[0] !== \"[\") {\n throw new Error(\"expected action name identifier argument\");\n }\n\n // The action name will be defined as a node argument.\n const actionArguments = getArguments(tokens, placeholders);\n\n // We should have at least one identifer argument for an action node, which is the action name.\n if (actionArguments.length && actionArguments[0].type === \"identifier\") {\n // The action name will be the first and only node argument.\n node.actionName = actionArguments.shift()!.value as string;\n } else {\n throw new Error(\"expected action name identifier argument\");\n }\n\n // Only the first argument should have been an identifier, all following arguments must be string, number, boolean or null.\n actionArguments\n .filter((arg) => arg.type === \"identifier\")\n .forEach((arg) => {\n throw new Error(\n \"invalid action node argument value '\" +\n arg.value +\n \"', must be string, number, boolean or null\"\n );\n });\n\n // Any node arguments that follow the action name identifier will be treated as action function arguments.\n node.actionArguments = actionArguments;\n\n // Try to pick any attributes off of the token stack.\n node.attributes = getAttributes(tokens, placeholders);\n break;\n }\n\n case \"}\": {\n // The '}' character closes the current scope.\n stack.pop();\n break;\n }\n\n default: {\n throw new Error(`unexpected token '${token}'`);\n }\n }\n }\n\n // A function to recursively validate each of the nodes in the AST.\n const validateASTNode = (node: Validatable, depth: number): void => {\n // Validate the node.\n node.validate(depth);\n\n // Validate each child of the node.\n (node.children || []).forEach((child) => validateASTNode(child, depth + 1));\n };\n\n // Start node validation from the definition root.\n validateASTNode(\n {\n children: stack[0] as RootAstNode[],\n validate(this: { children: RootAstNode[] }) {\n // We must have at least one node defined as the definition scope, which should be a root node.\n if (this.children.length === 0) {\n throw new Error(\"expected root node to have been defined\");\n }\n\n // Each node at the base of the definition scope MUST be a root node.\n for (const definitionLevelNode of this.children) {\n if (definitionLevelNode.type !== \"root\") {\n throw new Error(\"expected root node at base of definition\");\n }\n }\n\n // Exactly one root node must not have a name defined. This will be the main root, others will have to be referenced via branch nodes.\n if (this.children.filter((definitionLevelNode) => definitionLevelNode.name === null).length !== 1) {\n throw new Error(\"expected single unnamed root node at base of definition to act as main root\");\n }\n\n // No two named root nodes can have matching names.\n const rootNodeNames: string[] = [];\n for (const definitionLevelNode of this.children) {\n if (rootNodeNames.indexOf(definitionLevelNode.name!) !== -1) {\n throw new Error(`multiple root nodes found with duplicate name '${definitionLevelNode.name}'`);\n } else {\n rootNodeNames.push(definitionLevelNode.name!);\n }\n }\n }\n },\n 0\n );\n\n // Return the root AST nodes.\n return stack[0];\n}\n\n/**\n * Pop the next raw token off of the stack and throw an error if it wasn't the expected one.\n * @param tokens The array of remaining tokens.\n * @param expected An optional string or array or items, one of which must match the next popped token.\n * @returns The popped token.\n */\nfunction popAndCheck(tokens: string[], expected: string | string[]) {\n // Get and remove the next token.\n const popped = tokens.shift();\n\n // We were expecting another token.\n if (popped === undefined) {\n throw new Error(\"unexpected end of definition\");\n }\n\n // Do we have an expected token/tokens array?\n if (expected !== undefined) {\n // Check whether the popped token matches at least one of our expected items.\n var tokenMatchesExpectation = ([] as string[])\n .concat(expected)\n .some((item) => popped.toUpperCase() === item.toUpperCase());\n\n // Throw an error if the popped token didn't match any of our expected items.\n if (!tokenMatchesExpectation) {\n const expectationString = ([] as string[])\n .concat(expected)\n .map((item) => \"'\" + item + \"'\")\n .join(\" or \");\n\n throw new Error(`unexpected token found. Expected '${expectationString}' but got '${popped}'`);\n }\n }\n\n // Return the popped token.\n return popped;\n}\n\ntype StringPlaceholders = { [key: string]: string };\n\n/**\n * Pull an argument definition list off of the token stack.\n * @param tokens The array of remaining tokens.\n * @param stringArgumentPlaceholders The mapping of string literal node argument placeholders to original values.\n * @param argumentValidator The argument validator function.\n * @param validationFailedMessage The exception message to throw if argument validation fails.\n * @returns The argument definition list.\n */\nfunction getArguments(\n tokens: string[],\n stringArgumentPlaceholders: StringPlaceholders,\n argumentValidator?: (arg: AnyArgument) => boolean,\n validationFailedMessage?: string\n) {\n // Any lists of arguments will always be wrapped in '[]' for node arguments or '()' for attribute arguments.\n // We are looking for a '[' or '(' opener that wraps the argument tokens and the relevant closer.\n const closer = popAndCheck(tokens, [\"[\", \"(\"]) === \"[\" ? \"]\" : \")\";\n\n const argumentListTokens: string[] = [];\n const argumentList: AnyArgument[] = [];\n\n // Grab all tokens between the '[' and ']' or '(' and ')'.\n while (tokens.length && tokens[0] !== closer) {\n // The next token is part of our arguments list.\n argumentListTokens.push(tokens.shift()!);\n }\n\n // Validate the order of the argument tokens. Each token must either be a ',' or a single argument that satisfies the validator.\n argumentListTokens.forEach((token, index) => {\n // Get whether this token should be an actual argument.\n const shouldBeArgumentToken = !(index & 1);\n\n // If the current token should be an actual argument then validate it,otherwise it should be a ',' token.\n if (shouldBeArgumentToken) {\n // Get the argument definition.\n const argumentDefinition = getArgumentDefinition(token!, stringArgumentPlaceholders);\n\n // Try to validate the argument.\n if (argumentValidator && !argumentValidator(argumentDefinition)) {\n throw new Error(validationFailedMessage);\n }\n\n // This is a valid argument!\n argumentList.push(argumentDefinition);\n } else {\n // The current token should be a ',' token.\n if (token !== \",\") {\n throw new Error(`invalid argument list, expected ',' or ']' but got '${token}'`);\n }\n }\n });\n\n // The arguments list should terminate with a ']' or ')' token, depending on the opener.\n popAndCheck(tokens, closer);\n\n // Return the argument list.\n return argumentList;\n}\n\n/**\n * Gets an argument value definition.\n * @param token The argument token.\n * @param stringArgumentPlaceholders The mapping of string literal node argument placeholders to original values.\n * @returns An argument value definition.\n */\nfunction getArgumentDefinition(token: string, stringArgumentPlaceholders: StringPlaceholders): AnyArgument {\n // Check whether the token represents a null value.\n if (token === \"null\") {\n return {\n value: null,\n type: \"null\"\n } as NullArgument;\n }\n\n // Check whether the token represents a boolean value.\n if (token === \"true\" || token === \"false\") {\n return {\n value: token === \"true\",\n type: \"boolean\"\n } as BooleanArgument;\n }\n\n // Check whether the token represents a number value.\n // TODO: Relies on broken isNaN - see MDN.\n // if (!Number.isNaN(token)) {\n if (!isNaN(token as any)) {\n return {\n value: parseFloat(token),\n isInteger: parseFloat(token) === parseInt(token, 10),\n type: \"number\"\n } as NumberArgument;\n }\n\n // Check whether the token is a placeholder (e.g. @@0@@) representing a string literal.\n if (token.match(/^@@\\d+@@$/g)) {\n return {\n value: stringArgumentPlaceholders[token].replace('\\\\\"', '\"'),\n type: \"string\"\n } as StringPlaceholderArgument;\n }\n\n // The only remaining option is that the argument value is an identifier.\n return {\n value: token,\n type: \"identifier\"\n } as IdentifierArgument;\n}\n\n/**\n * Pull any attributes off of the token stack.\n * @param tokens The array of remaining tokens.\n * @param stringArgumentPlaceholders The mapping of string literal node argument placeholders to original values.\n * @returns An array of attributes defined by any directly following tokens.\n */\nfunction getAttributes(tokens: string[], stringArgumentPlaceholders: StringPlaceholders) {\n // Create an array to hold any attributes found.\n const attributes: Attribute[] = [];\n\n // Keep track of names of attribute that we have found on the token stack, as we cannot have duplicates.\n const attributesFound: string[] = [];\n\n // Try to get the attribute factory for the next token.\n let attributeFactory = AttributeFactories[(tokens[0] || \"\").toUpperCase()];\n\n // Pull attribute tokens off of the tokens stack until we have no more.\n while (attributeFactory) {\n // Check to make sure that we have not already created a attribute of this type for this node.\n if (attributesFound.indexOf(tokens[0].toUpperCase()) !== -1) {\n throw new Error(`duplicate attribute '${tokens[0].toUpperCase()}' found for node`);\n }\n\n // Add the current attribute type to our array of found attributes.\n attributesFound.push(tokens.shift()!.toUpperCase());\n\n // Grab any attribute arguments.\n const attributeArguments = getArguments(tokens, stringArgumentPlaceholders);\n\n // The first attribute argument has to be an identifer, this will reference an agent function.\n if (attributeArguments.length === 0 || attributeArguments[0].type !== \"identifier\") {\n throw new Error(\"expected agent function name identifier argument for attribute\");\n }\n\n // Grab the first attribute which is an identifier that will reference an agent function.\n const attributeFunctionName = attributeArguments.shift()! as IdentifierArgument;\n\n // Any remaining attribute arguments must have a type of string, number, boolean or null.\n attributeArguments\n .filter((arg) => arg.type === \"identifier\")\n .forEach((arg) => {\n throw new Error(\n \"invalid attribute argument value '\" + arg.value + \"', must be string, number, boolean or null\"\n );\n });\n\n // Create the attribute and add it to the array of attributes found.\n attributes.push(attributeFactory(attributeFunctionName.value, attributeArguments));\n\n // Try to get the next attribute name token, as there could be multiple.\n attributeFactory = AttributeFactories[(tokens[0] || \"\").toUpperCase()];\n }\n\n return attributes;\n}\n\n/**\n * Swaps out any node/attribute argument string literals with placeholders.\n * @param definition The definition.\n * @returns An object containing a mapping of placeholders to original string values as well as the processed definition string.\n */\nfunction substituteStringLiterals(definition: string): {\n placeholders: { [key: string]: string };\n processedDefinition: string;\n} {\n // Create an object to hold the mapping of placeholders to original string values.\n const placeholders: StringPlaceholders = {};\n\n // Replace any string literals wrapped with double quotes in our definition with placeholders to be processed later.\n const processedDefinition = definition.replace(/\\\"(\\\\.|[^\"\\\\])*\\\"/g, (match) => {\n var strippedMatch = match.substring(1, match.length - 1);\n var placeholder = Object.keys(placeholders).find((key) => placeholders[key] === strippedMatch);\n\n // If we have no existing string literal match then create a new placeholder.\n if (!placeholder) {\n placeholder = `@@${Object.keys(placeholders).length}@@`;\n placeholders[placeholder] = strippedMatch;\n }\n\n return placeholder;\n });\n\n return { placeholders, processedDefinition };\n}\n\n/**\n * Parse the tree definition into an array of raw tokens.\n * @param definition The definition.\n * @returns An array of tokens parsed from the definition.\n */\nfunction parseTokensFromDefinition(definition: string): string[] {\n // Add some space around various important characters so that they can be plucked out easier as individual tokens.\n definition = definition.replace(/\\(/g, \" ( \");\n definition = definition.replace(/\\)/g, \" ) \");\n definition = definition.replace(/\\{/g, \" { \");\n definition = definition.replace(/\\}/g, \" } \");\n definition = definition.replace(/\\]/g, \" ] \");\n definition = definition.replace(/\\[/g, \" [ \");\n definition = definition.replace(/\\,/g, \" , \");\n\n // Split the definition into raw token form and return it.\n return definition.replace(/\\s+/g, \" \").trim().split(\" \");\n}\n", "import GuardPath, { GuardPathPart } from \"./attributes/guards/GuardPath\";\nimport buildRootASTNodes, { AnyArgument, RootAstNode } from \"./RootAstNodesBuilder\";\nimport State, { AnyState } from \"./State\";\nimport Lookup from \"./Lookup\";\nimport Node from \"./nodes/Node\";\nimport Root from \"./nodes/decorator/Root\";\nimport Composite from \"./nodes/composite/Composite\";\nimport Decorator from \"./nodes/decorator/Decorator\";\nimport { Agent, GlobalFunction } from \"./Agent\";\nimport { CallbackAttributeDetails } from \"./attributes/callbacks/Callback\";\nimport { GuardAttributeDetails } from \"./attributes/guards/Guard\";\nimport { BehaviourTreeOptions } from \"./BehaviourTreeOptions\";\nimport { convertMDSLToJSON } from \"./mdsl/MDSLDefinitionParser\";\n\n// Purely for outside inspection of the tree.\nexport type FlattenedTreeNode = {\n id: string;\n type: string;\n caption: string;\n state: AnyState;\n guards: GuardAttributeDetails[];\n callbacks: CallbackAttributeDetails[];\n args: AnyArgument[];\n parentId: string | null;\n};\n\n/**\n * A representation of a behaviour tree.\n */\nexport class BehaviourTree {\n /**\n * The main root tree node.\n */\n public readonly rootNode: Root;\n\n /**\n * Creates a new instance of the BehaviourTree class.\n * @param definition The behaviour tree definition.\n * @param agent The agent instance that this behaviour tree is modelling behaviour for.\n * @param options The behaviour tree options object.\n */\n constructor(definition: string, private agent: Agent, private options: BehaviourTreeOptions = {}) {\n // The tree definition must be defined and a valid string.\n if (typeof definition !== \"string\") {\n throw new Error(\"the tree definition must be a string\");\n }\n\n // The agent must be defined and not null.\n if (typeof agent !== \"object\" || agent === null) {\n throw new Error(\"the agent must be defined and not null\");\n }\n\n // Parse the behaviour tree definition, create the populated tree of behaviour tree nodes, and get the root.\n this.rootNode = BehaviourTree._createRootNode(definition);\n }\n\n /**\n * Gets whether the tree is in the RUNNING state.\n * @returns true if the tree is in the RUNNING state, otherwise false.\n */\n isRunning() {\n return this.rootNode.getState() === State.RUNNING;\n }\n\n /**\n * Gets the current tree state of SUCCEEDED, FAILED, READY or RUNNING.\n * @returns The current tree state.\n */\n getState() {\n return this.rootNode.getState();\n }\n\n /**\n * Step the tree.\n * 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.\n * 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\n * 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.\n *\n * 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.\n */\n step() {\n // If the root node has already been stepped to completion then we need to reset it.\n if (this.rootNode.getState() === State.SUCCEEDED || this.rootNode.getState() === State.FAILED) {\n this.rootNode.reset();\n }\n\n try {\n this.rootNode.update(this.agent, this.options);\n } catch (exception) {\n throw new Error(`error stepping tree: ${(exception as Error).message}`);\n }\n }\n\n /**\n * Resets the tree from the root node outwards to each nested node, giving each a state of READY.\n */\n reset() {\n this.rootNode.reset();\n }\n\n /**\n * Gets the flattened details of every node in the tree.\n * @returns The flattened details of every node in the tree.\n */\n getFlattenedNodeDetails(): FlattenedTreeNode[] {\n // Create an empty flattened array of tree nodes.\n const flattenedTreeNodes: FlattenedTreeNode[] = [];\n\n /**\n * Helper function to process a node instance and push details into the flattened tree nodes array.\n * @param node The current node.\n * @param parentUid The UID of the node parent, or null if the node is the main root node.\n */\n const processNode = (node: Node, parentUid: string | null) => {\n // Get the guard and callback attribute details for this node.\n const guards = node\n .getAttributes()\n .filter((attribute) => attribute.isGuard())\n .map((attribute) => attribute.getDetails()) as GuardAttributeDetails[];\n const callbacks = node\n .getAttributes()\n .filter((attribute) => !attribute.isGuard())\n .map((attribute) => attribute.getDetails()) as CallbackAttributeDetails[];\n\n // Push the current node into the flattened nodes array.\n flattenedTreeNodes.push({\n id: node.getUid(),\n type: node.getType(),\n caption: node.getName(),\n state: node.getState(),\n guards,\n callbacks,\n args: node.getArguments(),\n parentId: parentUid\n });\n\n // Process each of the nodes children if it is not a leaf node.\n if (!node.isLeafNode()) {\n (node as Composite | Decorator)\n .getChildren()\n .forEach((child) => processNode(child, (node as Composite | Decorator).getUid()));\n }\n };\n\n // Convert the nested node structure into a flattened array of node details.\n processNode(this.rootNode, null);\n\n return flattenedTreeNodes;\n }\n\n /**\n * Registers the action/condition/guard/callback function or subtree with the given name.\n * @param name The name of the function or subtree to register.\n * @param value The function or subtree definition to register.\n */\n static register(name: string, value: GlobalFunction | string) {\n if (typeof value === \"function\") {\n // We are going to register a action/condition/guard/callback function.\n Lookup.setFunc(name, value);\n } else if (typeof value === \"string\") {\n // We are going to register a subtree.\n let rootASTNodes: RootAstNode[];\n\n try {\n // Try to create the behaviour tree AST based on the definition provided, this could fail if the definition is invalid.\n rootASTNodes = buildRootASTNodes(value);\n } catch (exception) {\n // There was an issue in trying to parse and build the tree definition.\n throw new Error(`error registering definition: ${(exception as Error).message}`);\n }\n\n // This function should only ever be called with a definition containing a single unnamed root node.\n if (rootASTNodes.length != 1 || rootASTNodes[0].name !== null) {\n throw new Error(\"error registering definition: expected a single unnamed root node\");\n }\n\n Lookup.setSubtree(name, rootASTNodes[0]);\n } else {\n throw new Error(\"unexpected value, expected string definition or function\");\n }\n }\n\n /**\n * Unregisters the registered action/condition/guard/callback function or subtree with the given name.\n * @param name The name of the registered action/condition/guard/callback function or subtree to unregister.\n */\n static unregister(name: string): void {\n Lookup.remove(name);\n }\n\n /**\n * Unregister all registered action/condition/guard/callback functions and subtrees.\n */\n static unregisterAll(): void {\n Lookup.empty();\n }\n\n /**\n * Parses a behaviour tree definition and creates a tree of behaviour tree nodes.\n * @param {string} definition The behaviour tree definition.\n * @returns The root behaviour tree node.\n */\n private static _createRootNode(definition: string): Root {\n // TODO Remove!\n try {\n // parseToJSON(definition);\n } catch (exception) {\n console.log(exception);\n }\n\n try {\n // Try to create the behaviour tree AST based on the definition provided, this could fail if the definition is invalid.\n const rootASTNodes = buildRootASTNodes(definition);\n\n // Create a symbol to use as the main root key in our root node mapping.\n const mainRootNodeKey = Symbol(\"__root__\");\n\n // Create a mapping of root node names to root AST tokens. The main root node will have a key of Symbol(\"__root__\").\n const rootNodeMap: { [key: string | symbol]: RootAstNode } = {};\n for (const rootASTNode of rootASTNodes) {\n rootNodeMap[rootASTNode.name === null ? mainRootNodeKey : rootASTNode.name!] = rootASTNode;\n }\n\n // Convert the AST to our actual tree and get the root node.\n const rootNode: Root = rootNodeMap[mainRootNodeKey].createNodeInstance(\n // Create a provider for named root nodes that are part of our definition or have been registered. Prioritising the former.\n (name: string): RootAstNode => (rootNodeMap[name] ? rootNodeMap[name] : Lookup.getSubtree(name)),\n []\n );\n\n // Set a guard path on every leaf of the tree to evaluate as part of its update.\n BehaviourTree._applyLeafNodeGuardPaths(rootNode);\n\n // Return the root node.\n return rootNode;\n } catch (exception) {\n // There was an issue in trying to parse and build the tree definition.\n throw new Error(`error parsing tree: ${(exception as Error).message}`);\n }\n }\n\n /**\n * Applies a guard path to every leaf of the tree to evaluate as part of each update.\n * @param rootNode The main root tree node.\n */\n private static _applyLeafNodeGuardPaths(rootNode: Root) {\n const nodePaths: Node[][] = [];\n\n const findLeafNodes = (path: Node[], node: Node) => {\n // Add the current node to the path.\n path = path.concat(node);\n\n // Check whether the current node is a leaf node.\n if (node.isLeafNode()) {\n nodePaths.push(path);\n } else {\n (node as Composite | Decorator).getChildren().forEach((child) => findLeafNodes(path, child));\n }\n };\n\n // Find all leaf node paths, starting from the root.\n findLeafNodes([], rootNode);\n\n nodePaths.forEach((path) => {\n // Each node in the current path will have to be assigned a guard path, working from the root outwards.\n for (let depth = 0; depth < path.length; depth++) {\n // Get the node in the path at the current depth.\n const currentNode = path[depth];\n\n // The node may already have been assigned a guard path, if so just skip it.\n if (currentNode.hasGuardPath()) {\n continue;\n }\n\n // Create the guard path for the current node.\n const guardPath = new GuardPath(\n path\n .slice(0, depth + 1)\n .map((node) => ({ node, guards: node.getGuardAttributes() }))\n .filter((details) => details.guards.length > 0)\n );\n\n // Assign the guard path to the current node.\n currentNode.setGuardPath(guardPath);\n }\n });\n }\n}\n"], - "mappings": ";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AACA,aAAO,eAAe,SAAS,cAAc,EAAE,OAAO,KAAK,CAAC;AAC5D,cAAQ,cAAc;AAItB,UAAI,cAA6B,WAAY;AAMzC,iBAASA,aAAY,aAAa,SAAS;AACvC,cAAI,YAAY,QAAQ;AAAE,sBAAU;AAAA,UAAG;AACvC,eAAK,eAAe;AACpB,eAAK,WAAW;AAAA,QACpB;AACA,eAAO,eAAeA,aAAY,WAAW,eAAe;AAAA,UAExD,KAAK,WAAY;AACb,mBAAO,KAAK;AAAA,UAChB;AAAA,UACA,YAAY;AAAA,UACZ,cAAc;AAAA,QAClB,CAAC;AACD,eAAO,eAAeA,aAAY,WAAW,WAAW;AAAA,UAEpD,KAAK,WAAY;AACb,mBAAO,KAAK;AAAA,UAChB;AAAA,UACA,KAAK,SAAU,OAAO;AAClB,iBAAK,WAAW;AAAA,UACpB;AAAA,UACA,YAAY;AAAA,UACZ,cAAc;AAAA,QAClB,CAAC;AACD,eAAOA;AAAA,MACX,EAAE;AACF,cAAQ,cAAc;AAAA;AAAA;;;ACtCtB;AAAA;AAAA;AACA,aAAO,eAAe,SAAS,cAAc,EAAE,OAAO,KAAK,CAAC;AAC5D,cAAQ,kBAAkB,QAAQ,oBAAoB;AAMtD,eAAS,kBAAkB,OAAO;AAC9B,eAAO,UAAU,QAAQ,UAAU;AAAA,MACvC;AACA,cAAQ,oBAAoB;AAM5B,eAAS,gBAAgB,OAAO;AAC5B,eAAO,OAAO,UAAU,YAAY,SAAS,KAAK,KAAK,MAAM,KAAK,MAAM;AAAA,MAC5E;AACA,cAAQ,kBAAkB;AAAA;AAAA;;;ACpB1B;AAAA;AAAA;AACA,aAAO,eAAe,SAAS,cAAc,EAAE,OAAO,KAAK,CAAC;AAC5D,cAAQ,QAAQ;AAChB,UAAI,gBAAgB;AACpB,UAAI,cAAc;AAIlB,UAAIC,SAAuB,WAAY;AAKnC,iBAASA,OAAM,cAAc;AAEzB,eAAK,gBAAgB,CAAC;AACtB,eAAK,gBAAgB;AAAA,QACzB;AAOA,QAAAA,OAAM,UAAU,MAAM,SAAU,aAAa,SAAS;AAClD,cAAI,YAAY,QAAQ;AAAE,sBAAU;AAAA,UAAG;AAEvC,cAAI,EAAE,GAAG,YAAY,iBAAiB,OAAO,GAAG;AAC5C,kBAAM,IAAI,MAAM,wCAAwC;AAAA,UAC5D;AAEA,cAAI,sBAAsB,KAAK,cAAc,KAAK,SAAU,MAAM;AAAE,mBAAO,KAAK,gBAAgB;AAAA,UAAa,CAAC;AAC9G,cAAI,qBAAqB;AAErB,gCAAoB,WAAW;AAAA,UACnC,OACK;AAED,iBAAK,cAAc,KAAK,IAAI,cAAc,YAAY,aAAa,OAAO,CAAC;AAAA,UAC/E;AACA,iBAAO;AAAA,QACX;AAOA,QAAAA,OAAM,UAAU,SAAS,SAAU,aAAa,SAAS;AAErD,cAAI,sBAAsB,KAAK,cAAc,KAAK,SAAU,MAAM;AAAE,mBAAO,KAAK,gBAAgB;AAAA,UAAa,CAAC;AAE9G,cAAI,CAAC,qBAAqB;AACtB,mBAAO;AAAA,UACX;AAEA,cAAI,YAAY,QAAW;AAEvB,gBAAI,EAAE,GAAG,YAAY,iBAAiB,OAAO,GAAG;AAC5C,oBAAM,IAAI,MAAM,wCAAwC;AAAA,YAC5D;AACA,gCAAoB,WAAW;AAE/B,gBAAI,oBAAoB,UAAU,GAAG;AACjC,mBAAK,gBAAgB,KAAK,cAAc,OAAO,SAAU,MAAM;AAAE,uBAAO,SAAS;AAAA,cAAqB,CAAC;AAAA,YAC3G;AAAA,UACJ,OACK;AAED,iBAAK,gBAAgB,KAAK,cAAc,OAAO,SAAU,MAAM;AAAE,qBAAO,SAAS;AAAA,YAAqB,CAAC;AAAA,UAC3G;AACA,iBAAO;AAAA,QACX;AAMA,QAAAA,OAAM,UAAU,OAAO,SAAU,SAAS;AACtC,cAAI,YAAY,QAAQ;AAAE,sBAAU,CAAC;AAAA,UAAG;AAExC,cAAI,KAAK,cAAc,WAAW,GAAG;AACjC,mBAAO;AAAA,UACX;AACA,cAAI,cAAc,GAAG,YAAY,mBAAmB,QAAQ,UAAU,IAAI,OAAO,QAAQ;AACzF,cAAI,WAAW,CAAC;AAChB,eAAK,cAAc,QAAQ,SAAU,IAAI;AACrC,gBAAI,cAAc,GAAG,aAAa,UAAU,GAAG;AAC/C,qBAAS,cAAc,GAAG,cAAc,SAAS,eAAe;AAC5D,uBAAS,KAAK,WAAW;AAAA,YAC7B;AAAA,UACJ,CAAC;AACD,cAAI;AAGJ,cAAI,KAAK,eAAe;AAEpB,qBAAS,KAAK,cAAc;AAE5B,gBAAI,OAAO,WAAW,YAAY,SAAS,KAAK,UAAU,GAAG;AACzD,oBAAM,IAAI,MAAM,oFAAoF;AAAA,YACxG;AAAA,UACJ,OACK;AAED,qBAAS,KAAK,OAAO;AAAA,UACzB;AAEA,cAAI,SAAS,SAAS,KAAK,MAAM,SAAS,SAAS,MAAM;AAEzD,cAAI,CAAC,YAAY;AACb,iBAAK,OAAO,QAAQ,CAAC;AAAA,UACzB;AAEA,iBAAO;AAAA,QACX;AAOA,QAAAA,OAAM,UAAU,eAAe,SAAU,SAAS,SAAS;AACvD,cAAI,YAAY,QAAQ;AAAE,sBAAU,CAAC;AAAA,UAAG;AACxC,cAAI,iBAAiB,GAAG,YAAY,mBAAmB,QAAQ,MAAM,IAAI,QAAQ,QAAQ;AAEzF,cAAI,YAAY,GAAG;AACf,mBAAO,CAAC;AAAA,UACZ;AAEA,cAAI,EAAE,GAAG,YAAY,iBAAiB,OAAO,GAAG;AAC5C,kBAAM,IAAI,MAAM,wCAAwC;AAAA,UAC5D;AACA,cAAI,SAAS,CAAC;AAGd,iBAAO,OAAO,SAAS,WAAW,KAAK,cAAc,SAAS,GAAG;AAC7D,mBAAO,KAAK,KAAK,KAAK,OAAO,CAAC;AAAA,UAClC;AAEA,cAAI,eAAe;AAEf,gBAAI,SAAS,CAAC;AAEd,qBAAS,KAAK,GAAG,WAAW,QAAQ,KAAK,SAAS,QAAQ,MAAM;AAC5D,kBAAI,cAAc,SAAS;AAC3B,kBAAI,OAAO,QAAQ,WAAW,MAAM,IAAI;AACpC,uBAAO,KAAK,WAAW;AAAA,cAC3B;AAAA,YACJ;AACA,qBAAS;AAAA,UACb;AACA,iBAAO;AAAA,QACX;AACA,eAAOA;AAAA,MACX,EAAE;AACF,cAAQ,QAAQA;AAAA;AAAA;;;AC5JhB;AAAA;AAAA;AACA,aAAO,eAAe,SAAS,cAAc,EAAE,OAAO,KAAK,CAAC;AAC5D,cAAQ,cAAc;AACtB,UAAI,UAAU;AAMd,eAASC,aAAY,uBAAuB;AAExC,YAAI,CAAC,uBAAuB;AACxB,iBAAO,IAAI,QAAQ,MAAM;AAAA,QAC7B;AAEA,YAAI,MAAM,QAAQ,qBAAqB,GAAG;AAEtC,cAAI,eAAe;AACnB,cAAI,UAAU,IAAI,QAAQ,MAAM;AAEhC,uBAAa,QAAQ,SAAU,IAAI;AAC/B,gBAAI,cAAc,GAAG,IAAI,SAAS,GAAG;AACrC,mBAAO,QAAQ,IAAI,aAAa,MAAM;AAAA,UAC1C,CAAC;AAED,iBAAO;AAAA,QACX,OACK;AAED,cAAI,SAAS,sBAAsB,QAAQ,eAAe,sBAAsB;AAEhF,cAAI,UAAU,IAAI,QAAQ,MAAM,MAAM;AAEtC,cAAI,cAAc;AACd,yBAAa,QAAQ,SAAU,IAAI;AAC/B,kBAAI,cAAc,GAAG,IAAI,SAAS,GAAG;AACrC,qBAAO,QAAQ,IAAI,aAAa,MAAM;AAAA,YAC1C,CAAC;AAAA,UACL;AAEA,iBAAO;AAAA,QACX;AAAA,MACJ;AACA,cAAQ,cAAcA;AAAA;AAAA;;;AC3CtB;AAAA;AAAA;AACA,aAAO,eAAe,SAAS,cAAc,EAAE,OAAO,KAAK,CAAC;AAC5D,UAAI,gBAAgB;AACpB,cAAQ,UAAU,cAAc;AAAA;AAAA;;;ACHhC;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;;ACGO,MAAK,QAAL,kBAAKC,WAAL;AACH,IAAAA,OAAA,WAAQ;AACR,IAAAA,OAAA,aAAU;AACV,IAAAA,OAAA,eAAY;AACZ,IAAAA,OAAA,YAAS;AAJD,WAAAA;AAAA,KAAA;;;ACWL,WAAS,WAAW,MAAkD;AACzE,WAAO,KAAK,SAAS;AAAA,EACzB;AAOO,WAAS,aAAa,MAAoD;AAC7E,WAAO,KAAK,SAAS;AAAA,EACzB;AAOO,WAAS,WAAW,MAA8C;AACrE,WAAO,CAAC,UAAU,UAAU,aAAa,MAAM,EAAE,SAAS,KAAK,IAAI;AAAA,EACvE;AAOO,WAAS,gBAAgB,MAAuD;AACnF,WAAO,CAAC,QAAQ,UAAU,SAAS,QAAQ,WAAW,MAAM,EAAE,SAAS,KAAK,IAAI;AAAA,EACpF;AAOO,WAAS,gBAAgB,MAAuD;AACnF,WAAO,CAAC,YAAY,YAAY,SAAS,UAAU,EAAE,SAAS,KAAK,IAAI;AAAA,EAC3E;AAOO,WAAS,kBAAkB,gBAAoC;AAClE,UAAM,QAAmB,CAAC;AAE1B,UAAM,cAAc,CAAC,0BAAmC;AACpD,YAAM,KAAK,qBAAqB;AAEhC,UAAI,gBAAgB,qBAAqB,GAAG;AACxC,8BAAsB,SAAS,QAAQ,WAAW;AAAA,MACtD,WAAW,gBAAgB,qBAAqB,GAAG;AAC/C,oBAAY,sBAAsB,KAAK;AAAA,MAC3C;AAAA,IACJ;AAEA,gBAAY,cAAc;AAE1B,WAAO;AAAA,EACX;AAOO,WAAS,UAAU,OAAyB;AAC/C,WAAO,OAAO,UAAU,YAAY,KAAK,MAAM,KAAK,MAAM;AAAA,EAC9D;;;ACzEO,WAAS,YAAY,QAAkB,UAAsC;AAEhF,UAAM,SAAS,OAAO,MAAM;AAG5B,QAAI,WAAW,QAAW;AACtB,YAAM,IAAI,MAAM,8BAA8B;AAAA,IAClD;AAGA,QAAI,YAAY,QAAW;AAEvB,YAAM,iBAAiB,OAAO,aAAa,WAAW,CAAC,QAAQ,IAAI;AAGnE,UAAI,0BAA0B,eAAe,KAAK,CAAC,SAAS,OAAO,YAAY,MAAM,KAAK,YAAY,CAAC;AAGvG,UAAI,CAAC,yBAAyB;AAC1B,cAAM,oBAAoB,eAAe,IAAI,CAAC,SAAS,MAAM,OAAO,GAAG,EAAE,KAAK,MAAM;AACpF,cAAM,IAAI,MAAM,sCAAsC,oBAAoB,eAAe,SAAS,GAAG;AAAA,MACzG;AAAA,IACJ;AAGA,WAAO;AAAA,EACX;AAOO,WAAS,yBAAyB,YAGvC;AAEE,UAAM,eAA0C,CAAC;AAGjD,UAAM,sBAAsB,WAAW,QAAQ,sBAAsB,CAAC,UAAU;AAC5E,UAAI,gBAAgB,MAAM,UAAU,GAAG,MAAM,SAAS,CAAC;AACvD,UAAI,cAAc,OAAO,KAAK,YAAY,EAAE,KAAK,CAAC,QAAQ,aAAa,SAAS,aAAa;AAG7F,UAAI,CAAC,aAAa;AACd,sBAAc,KAAK,OAAO,KAAK,YAAY,EAAE;AAC7C,qBAAa,eAAe;AAAA,MAChC;AAEA,aAAO;AAAA,IACX,CAAC;AAED,WAAO,EAAE,cAAc,oBAAoB;AAAA,EAC/C;AAOO,WAAS,0BAA0B,YAA8B;AAEpE,iBAAa,WAAW,QAAQ,OAAO,KAAK;AAC5C,iBAAa,WAAW,QAAQ,OAAO,KAAK;AAC5C,iBAAa,WAAW,QAAQ,OAAO,KAAK;AAC5C,iBAAa,WAAW,QAAQ,OAAO,KAAK;AAC5C,iBAAa,WAAW,QAAQ,OAAO,KAAK;AAC5C,iBAAa,WAAW,QAAQ,OAAO,KAAK;AAC5C,iBAAa,WAAW,QAAQ,OAAO,KAAK;AAG5C,WAAO,WAAW,QAAQ,QAAQ,GAAG,EAAE,KAAK,EAAE,MAAM,GAAG;AAAA,EAC3D;;;ACxCO,WAAS,oBACZ,QACA,4BACa;AACb,UAAM,eAA8B,CAAC;AAGrC,QAAI,CAAC,CAAC,KAAK,GAAG,EAAE,SAAS,OAAO,EAAE,GAAG;AACjC,aAAO;AAAA,IACX;AAIA,UAAM,eAAe,YAAY,QAAQ,CAAC,KAAK,GAAG,CAAC,MAAM,MAAM,MAAM;AAErE,UAAM,qBAA+B,CAAC;AAGtC,WAAO,OAAO,UAAU,OAAO,OAAO,cAAc;AAEhD,yBAAmB,KAAK,OAAO,MAAM,CAAE;AAAA,IAC3C;AAGA,uBAAmB,QAAQ,CAAC,OAAO,UAAU;AAEzC,YAAM,wBAAwB,EAAE,QAAQ;AAGxC,UAAI,uBAAuB;AAEvB,cAAM,qBAAqB,sBAAsB,OAAO,0BAA0B;AAGlF,qBAAa,KAAK,kBAAkB;AAAA,MACxC,OAAO;AAEH,YAAI,UAAU,KAAK;AACf,gBAAM,IAAI,MAAM,uDAAuD,QAAQ;AAAA,QACnF;AAAA,MACJ;AAAA,IACJ,CAAC;AAGD,gBAAY,QAAQ,YAAY;AAGhC,WAAO;AAAA,EACX;AAQA,WAAS,sBAAsB,OAAe,4BAAoE;AAE9G,QAAI,UAAU,QAAQ;AAClB,aAAO;AAAA,QACH,OAAO;AAAA,QACP,MAAM;AAAA,MACV;AAAA,IACJ;AAGA,QAAI,UAAU,UAAU,UAAU,SAAS;AACvC,aAAO;AAAA,QACH,OAAO,UAAU;AAAA,QACjB,MAAM;AAAA,MACV;AAAA,IACJ;AAKA,QAAI,CAAC,MAAM,KAAY,GAAG;AACtB,aAAO;AAAA,QACH,OAAO,WAAW,KAAK;AAAA,QACvB,WAAW,WAAW,KAAK,MAAM,SAAS,OAAO,EAAE;AAAA,QACnD,MAAM;AAAA,MACV;AAAA,IACJ;AAGA,QAAI,MAAM,MAAM,YAAY,GAAG;AAC3B,aAAO;AAAA,QACH,OAAO,2BAA2B,OAAO,QAAQ,OAAO,GAAG;AAAA,QAC3D,MAAM;AAAA,MACV;AAAA,IACJ;AAGA,WAAO;AAAA,MACH,OAAO;AAAA,MACP,MAAM;AAAA,IACV;AAAA,EACJ;;;ACzHO,WAAS,qBACZ,QACA,4BACc;AACd,UAAM,qBAA+C,CAAC,SAAS,SAAS,SAAS,QAAQ,MAAM;AAG/F,UAAM,aAA6B,CAAC;AAGpC,QAAI,oBAAoB,OAAO,IAAI,YAAY;AAG/C,WAAO,mBAAmB,SAAS,iBAAiB,GAAG;AAEnD,UAAI,WAAW,oBAAoB;AAC/B,cAAM,IAAI,MAAM,wBAAwB,OAAO,GAAG,YAAY,mBAAmB;AAAA,MACrF;AAGA,aAAO,MAAM;AAGb,YAAM,CAAC,4BAA4B,kBAAkB,IAAI;AAAA,QACrD;AAAA,QACA;AAAA,MACJ;AAGA,UAAI,yBAAyB,SAAS,cAAc;AAChD,cAAM,IAAI,MAAM,gEAAgE;AAAA,MACpF;AAGA,yBACK,OAAO,CAAC,QAAQ,IAAI,SAAS,YAAY,EACzC,QAAQ,CAAC,QAAQ;AACd,cAAM,IAAI;AAAA,UACN,qCAAqC,IAAI;AAAA,QAC7C;AAAA,MACJ,CAAC;AAGL,iBAAW,qBAAqB;AAAA,QAC5B,MAAM,wBAAwB;AAAA,QAC9B,MAAM,mBAAmB,IAAI,CAAC,EAAE,MAAM,MAAM,KAAK;AAAA,MACrD;AAGA,0BAAoB,OAAO,IAAI,YAAY;AAAA,IAC/C;AAEA,WAAO;AAAA,EACX;;;ACzCO,WAAS,kBAAkB,YAA0C;AAExE,UAAM,EAAE,cAAc,oBAAoB,IAAI,yBAAyB,UAAU;AAGjF,UAAM,SAAS,0BAA0B,mBAAmB;AAE5D,WAAO,8BAA8B,QAAQ,YAAY;AAAA,EAC7D;AAQA,WAAS,8BACL,QACA,2BACoB;AAEpB,QAAI,OAAO,SAAS,GAAG;AACnB,YAAM,IAAI,MAAM,qBAAqB;AAAA,IACzC;AAGA,QAAI,OAAO,OAAO,CAAC,UAAU,UAAU,GAAG,EAAE,WAAW,OAAO,OAAO,CAAC,UAAU,UAAU,GAAG,EAAE,QAAQ;AACnG,YAAM,IAAI,MAAM,0BAA0B;AAAA,IAC9C;AASA,UAAM,aAA0E,CAAC;AAGjF,UAAM,YAA2C,CAAC;AAGlD,UAAM,WAAW,CAAC,SAAkB;AAEhC,UAAI,WAAW,IAAI,GAAG;AAElB,kBAAU,KAAK,IAAI;AAGnB,mBAAW,KAAK,CAAC,IAAI,CAAC;AAEtB;AAAA,MACJ;AAIA,UAAI,CAAC,WAAW,UAAU,CAAC,WAAW,WAAW,SAAS,GAAG,QAAQ;AACjE,cAAM,IAAI,MAAM,0CAA0C;AAAA,MAC9D;AAGA,YAAM,eAAe,WAAW,WAAW,SAAS;AAIpD,YAAM,sBAAsB,aAAa,aAAa,SAAS;AAI/D,UAAI,gBAAgB,mBAAmB,GAAG;AACtC,4BAAoB,WAAW,oBAAoB,YAAY,CAAC;AAChE,4BAAoB,SAAS,KAAK,IAAI;AAAA,MAC1C,WAAW,gBAAgB,mBAAmB,GAAG;AAE7C,YAAI,oBAAoB,OAAO;AAC3B,gBAAM,IAAI,MAAM,qDAAqD;AAAA,QACzE;AAEA,4BAAoB,QAAQ;AAAA,MAChC;AAIA,UAAI,CAAC,WAAW,IAAI,GAAG;AACnB,qBAAa,KAAK,IAAI;AAAA,MAC1B;AAAA,IACJ;AAGA,UAAM,UAAU,MAAM;AAElB,YAAM,eAAe,WAAW,WAAW,SAAS;AAGpD,UAAI,aAAa,QAAQ;AACrB,qBAAa,IAAI;AAAA,MACrB;AAGA,UAAI,CAAC,aAAa,QAAQ;AACtB,mBAAW,IAAI;AAAA,MACnB;AAAA,IACJ;AAGA,WAAO,OAAO,QAAQ;AAElB,YAAM,QAAQ,OAAO,MAAM;AAG3B,cAAQ,MAAM,YAAY,GAAG;AAAA,QACzB,KAAK,QAAQ;AACT,mBAAS,eAAe,QAAQ,yBAAyB,CAAC;AAC1D;AAAA,QACJ;AAAA,QAEA,KAAK,WAAW;AACZ,mBAAS,kBAAkB,QAAQ,yBAAyB,CAAC;AAC7D;AAAA,QACJ;AAAA,QAEA,KAAK,QAAQ;AACT,mBAAS,eAAe,QAAQ,yBAAyB,CAAC;AAC1D;AAAA,QACJ;AAAA,QAEA,KAAK,QAAQ;AACT,mBAAS,eAAe,QAAQ,yBAAyB,CAAC;AAC1D;AAAA,QACJ;AAAA,QAEA,KAAK,UAAU;AACX,mBAAS,iBAAiB,QAAQ,yBAAyB,CAAC;AAC5D;AAAA,QACJ;AAAA,QAEA,KAAK,SAAS;AACV,mBAAS,gBAAgB,QAAQ,yBAAyB,CAAC;AAC3D;AAAA,QACJ;AAAA,QAEA,KAAK,YAAY;AACb,mBAAS,mBAAmB,QAAQ,yBAAyB,CAAC;AAC9D;AAAA,QACJ;AAAA,QAEA,KAAK,YAAY;AACb,mBAAS,mBAAmB,QAAQ,yBAAyB,CAAC;AAC9D;AAAA,QACJ;AAAA,QAEA,KAAK,YAAY;AACb,mBAAS,mBAAmB,QAAQ,yBAAyB,CAAC;AAC9D;AAAA,QACJ;AAAA,QAEA,KAAK,SAAS;AACV,mBAAS,gBAAgB,QAAQ,yBAAyB,CAAC;AAC3D;AAAA,QACJ;AAAA,QAEA,KAAK,UAAU;AACX,mBAAS,iBAAiB,QAAQ,yBAAyB,CAAC;AAC5D;AAAA,QACJ;AAAA,QAEA,KAAK,aAAa;AACd,mBAAS,oBAAoB,QAAQ,yBAAyB,CAAC;AAC/D;AAAA,QACJ;AAAA,QAEA,KAAK,QAAQ;AACT,mBAAS,eAAe,QAAQ,yBAAyB,CAAC;AAC1D;AAAA,QACJ;AAAA,QAEA,KAAK,UAAU;AACX,mBAAS,iBAAiB,QAAQ,yBAAyB,CAAC;AAC5D;AAAA,QACJ;AAAA,QAEA,KAAK,KAAK;AAEN,kBAAQ;AACR;AAAA,QACJ;AAAA,QAEA,SAAS;AACL,gBAAM,IAAI,MAAM,qBAAqB,OAAO;AAAA,QAChD;AAAA,MACJ;AAAA,IACJ;AAEA,WAAO;AAAA,EACX;AAQA,WAAS,eAAe,QAAkB,2BAA0E;AAEhH,QAAI,OAAO;AAAA,MACP,MAAM;AAAA,MACN,IAAI;AAAA,IACR;AAGA,UAAM,gBAAgB,oBAAoB,QAAQ,yBAAyB;AAG3E,QAAI,cAAc,QAAQ;AAEtB,UAAI,cAAc,WAAW,KAAK,cAAc,GAAG,SAAS,cAAc;AAEtE,aAAK,KAAK,cAAc,GAAG;AAAA,MAC/B,OAAO;AACH,cAAM,IAAI,MAAM,oCAAoC;AAAA,MACxD;AAAA,IACJ;AAGA,WAAO,EAAE,GAAG,MAAM,GAAG,qBAAqB,QAAQ,yBAAyB,EAAE;AAG7E,gBAAY,QAAQ,GAAG;AAGvB,WAAO;AAAA,EACX;AAQA,WAAS,kBACL,QACA,2BACqB;AACrB,UAAM,OAAO;AAAA,MACT,MAAM;AAAA,MACN,GAAG,qBAAqB,QAAQ,yBAAyB;AAAA,IAC7D;AAGA,gBAAY,QAAQ,GAAG;AAGvB,WAAO;AAAA,EACX;AAQA,WAAS,eAAe,QAAkB,2BAA0E;AAChH,UAAM,OAAO;AAAA,MACT,MAAM;AAAA,MACN,GAAG,qBAAqB,QAAQ,yBAAyB;AAAA,IAC7D;AAGA,gBAAY,QAAQ,GAAG;AAGvB,WAAO;AAAA,EACX;AAQA,WAAS,eAAe,QAAkB,2BAA0E;AAChH,UAAM,OAAO;AAAA,MACT,MAAM;AAAA,MACN,GAAG,qBAAqB,QAAQ,yBAAyB;AAAA,IAC7D;AAGA,gBAAY,QAAQ,GAAG;AAGvB,WAAO;AAAA,EACX;AAQA,WAAS,iBACL,QACA,2BACoB;AACpB,QAAI,OAAO,EAAE,MAAM,SAAS;AAG5B,UAAM,gBAAgB,oBAAoB,QAAQ,yBAAyB;AAM3E,QAAI,cAAc,QAAQ;AAEtB,oBACK,OAAO,CAAC,QAAQ,IAAI,SAAS,YAAY,CAAC,IAAI,SAAS,EACvD,QAAQ,MAAM;AACX,cAAM,IAAI,MAAM,qDAAqD;AAAA,MACzE,CAAC;AAGL,UAAI,cAAc,WAAW,GAAG;AAE5B,aAAK,aAAa,cAAc,GAAG;AAAA,MACvC,WAAW,cAAc,WAAW,GAAG;AAEnC,aAAK,aAAa,CAAC,cAAc,GAAG,OAAiB,cAAc,GAAG,KAAe;AAAA,MACzF,OAAO;AAEH,cAAM,IAAI,MAAM,iEAAiE;AAAA,MACrF;AAAA,IACJ;AAGA,WAAO,EAAE,GAAG,MAAM,GAAG,qBAAqB,QAAQ,yBAAyB,EAAE;AAG7E,gBAAY,QAAQ,GAAG;AAGvB,WAAO;AAAA,EACX;AAQA,WAAS,gBAAgB,QAAkB,2BAA2E;AAClH,QAAI,OAAO,EAAE,MAAM,QAAQ;AAG3B,UAAM,gBAAgB,oBAAoB,QAAQ,yBAAyB;AAM3E,QAAI,cAAc,QAAQ;AAEtB,oBACK,OAAO,CAAC,QAAQ,IAAI,SAAS,YAAY,CAAC,IAAI,SAAS,EACvD,QAAQ,MAAM;AACX,cAAM,IAAI,MAAM,kDAAkD;AAAA,MACtE,CAAC;AAGL,UAAI,cAAc,WAAW,GAAG;AAE5B,aAAK,WAAW,cAAc,GAAG;AAAA,MACrC,WAAW,cAAc,WAAW,GAAG;AAEnC,aAAK,WAAW,CAAC,cAAc,GAAG,OAAiB,cAAc,GAAG,KAAe;AAAA,MACvF,OAAO;AAEH,cAAM,IAAI,MAAM,8DAA8D;AAAA,MAClF;AAAA,IACJ;AAGA,WAAO,EAAE,GAAG,MAAM,GAAG,qBAAqB,QAAQ,yBAAyB,EAAE;AAG7E,gBAAY,QAAQ,GAAG;AAGvB,WAAO;AAAA,EACX;AAQA,WAAS,mBACL,QACA,2BACsB;AACtB,UAAM,OAAO;AAAA,MACT,MAAM;AAAA,MACN,GAAG,qBAAqB,QAAQ,yBAAyB;AAAA,IAC7D;AAGA,gBAAY,QAAQ,GAAG;AAGvB,WAAO;AAAA,EACX;AAQA,WAAS,mBACL,QACA,2BACsB;AACtB,UAAM,OAAO;AAAA,MACT,MAAM;AAAA,MACN,GAAG,qBAAqB,QAAQ,yBAAyB;AAAA,IAC7D;AAGA,gBAAY,QAAQ,GAAG;AAGvB,WAAO;AAAA,EACX;AAQA,WAAS,mBACL,QACA,2BACsB;AACtB,UAAM,OAAO;AAAA,MACT,MAAM;AAAA,MACN,GAAG,qBAAqB,QAAQ,yBAAyB;AAAA,IAC7D;AAGA,gBAAY,QAAQ,GAAG;AAGvB,WAAO;AAAA,EACX;AAQA,WAAS,gBAAgB,QAAkB,2BAA2E;AAElH,UAAM,gBAAgB,oBAAoB,QAAQ,yBAAyB;AAG3E,kBACK,OAAO,CAAC,QAAQ,IAAI,SAAS,YAAY,CAAC,IAAI,SAAS,EACvD,QAAQ,MAAM;AACX,YAAM,IAAI,MAAM,oDAAoD;AAAA,IACxE,CAAC;AAEL,UAAM,OAAO;AAAA,MACT,MAAM;AAAA,MACN,SAAS,cAAc,IAAI,CAAC,EAAE,MAAM,MAAM,KAAK;AAAA,MAC/C,GAAG,qBAAqB,QAAQ,yBAAyB;AAAA,IAC7D;AAGA,gBAAY,QAAQ,GAAG;AAGvB,WAAO;AAAA,EACX;AAQA,WAAS,iBACL,QACA,2BACoB;AAGpB,UAAM,CAAC,yBAAyB,iBAAiB,IAAI,oBAAoB,QAAQ,yBAAyB;AAG1G,QAAI,sBAAsB,SAAS,cAAc;AAC7C,YAAM,IAAI,MAAM,0CAA0C;AAAA,IAC9D;AAGA,sBACK,OAAO,CAAC,QAAQ,IAAI,SAAS,YAAY,EACzC,QAAQ,CAAC,QAAQ;AACd,YAAM,IAAI;AAAA,QACN,uCAAuC,IAAI;AAAA,MAC/C;AAAA,IACJ,CAAC;AAGL,WAAO;AAAA,MACH,MAAM;AAAA,MACN,MAAM,qBAAqB;AAAA,MAC3B,MAAM,kBAAkB,IAAI,CAAC,EAAE,MAAM,MAAM,KAAK;AAAA,MAChD,GAAG,qBAAqB,QAAQ,yBAAyB;AAAA,IAC7D;AAAA,EACJ;AAQA,WAAS,oBACL,QACA,2BACuB;AAGvB,UAAM,CAAC,4BAA4B,iBAAiB,IAAI,oBAAoB,QAAQ,yBAAyB;AAG7G,QAAI,yBAAyB,SAAS,cAAc;AAChD,YAAM,IAAI,MAAM,6CAA6C;AAAA,IACjE;AAGA,sBACK,OAAO,CAAC,QAAQ,IAAI,SAAS,YAAY,EACzC,QAAQ,CAAC,QAAQ;AACd,YAAM,IAAI;AAAA,QACN,0CAA0C,IAAI;AAAA,MAClD;AAAA,IACJ,CAAC;AAGL,WAAO;AAAA,MACH,MAAM;AAAA,MACN,MAAM,wBAAwB;AAAA,MAC9B,MAAM,kBAAkB,IAAI,CAAC,EAAE,MAAM,MAAM,KAAK;AAAA,MAChD,GAAG,qBAAqB,QAAQ,yBAAyB;AAAA,IAC7D;AAAA,EACJ;AAQA,WAAS,eAAe,QAAkB,2BAA0E;AAChH,QAAI,OAAO,EAAE,MAAM,OAAO;AAG1B,UAAM,gBAAgB,oBAAoB,QAAQ,yBAAyB;AAM3E,QAAI,cAAc,QAAQ;AAEtB,oBACK,OAAO,CAAC,QAAQ,IAAI,SAAS,YAAY,CAAC,IAAI,SAAS,EACvD,QAAQ,MAAM;AACX,cAAM,IAAI,MAAM,qDAAqD;AAAA,MACzE,CAAC;AAML,UAAI,cAAc,WAAW,GAAG;AAE5B,aAAK,WAAW,cAAc,GAAG;AAAA,MACrC,WAAW,cAAc,WAAW,GAAG;AAEnC,aAAK,WAAW,CAAC,cAAc,GAAG,OAAiB,cAAc,GAAG,KAAe;AAAA,MACvF,WAAW,cAAc,SAAS,GAAG;AAEjC,cAAM,IAAI,MAAM,wDAAwD;AAAA,MAC5E;AAAA,IACJ;AAGA,WAAO,EAAE,GAAG,MAAM,GAAG,qBAAqB,QAAQ,yBAAyB,EAAE;AAAA,EACjF;AAQA,WAAS,iBACL,QACA,2BACoB;AAEpB,UAAM,gBAAgB,oBAAoB,QAAQ,yBAAyB;AAG3E,QAAI,cAAc,WAAW,KAAK,cAAc,GAAG,SAAS,cAAc;AACtE,YAAM,IAAI,MAAM,sCAAsC;AAAA,IAC1D;AAGA,WAAO,EAAE,MAAM,UAAU,KAAK,cAAc,GAAG,MAAM;AAAA,EACzD;;;AC3nBO,WAAS,mBAAmB,YAA6C;AAE5E,UAAM,sBAAsB,CAAC,kBAA0B,EAAE,WAAW,OAAO,aAAa;AAGxF,QAAI,eAAe,QAAQ,OAAO,eAAe,aAAa;AAC1D,aAAO,oBAAoB,iCAAiC;AAAA,IAChE;AAEA,QAAI;AAMJ,QAAI,OAAO,eAAe,UAAU;AAChC,UAAI;AAEA,8BAAsB,kBAAkB,UAAU;AAAA,MACtD,SAAS,OAAP;AAEE,eAAO,oBAAoB,iBAAiB,YAAY;AAAA,MAC5D;AAAA,IACJ,WAAW,OAAO,eAAe,UAAU;AAEvC,4BAAsB,MAAM,QAAQ,UAAU,IAAI,aAAa,CAAC,UAAU;AAAA,IAC9E,OAAO;AACH,aAAO,oBAAoB,kCAAkC,OAAO,aAAa;AAAA,IACrF;AAGA,QAAI;AACA,0BAAoB,QAAQ,CAAC,uBAAuB,aAAa,oBAAoB,CAAC,CAAC;AAAA,IAC3F,SAAS,OAAP;AAEE,UAAI,iBAAiB,OAAO;AACxB,eAAO,oBAAoB,MAAM,OAAO;AAAA,MAC5C;AAGA,aAAO,oBAAoB,qBAAqB,OAAO;AAAA,IAC3D;AAGA,UAAM,0BAA0B,oBAAoB,OAAO,CAAC,EAAE,GAAG,MAAM,OAAO,OAAO,WAAW;AAChG,UAAM,yBAAyB,oBAAoB,OAAO,CAAC,EAAE,GAAG,MAAM,OAAO,OAAO,YAAY,GAAG,SAAS,CAAC;AAG7G,QAAI,wBAAwB,WAAW,GAAG;AACtC,aAAO,oBAAoB,6EAA6E;AAAA,IAC5G;AAGA,UAAM,yBAAmC,CAAC;AAC1C,eAAW,EAAE,GAAG,KAAK,wBAAwB;AAEzC,UAAI,uBAAuB,SAAS,EAAE,GAAG;AACrC,eAAO,oBAAoB,oEAAoE,KAAK;AAAA,MACxG;AAEA,6BAAuB,KAAK,EAAE;AAAA,IAClC;AAGA,UAAM,yBAAyB,iCAAiC,mBAAmB;AAGnF,QAAI,wBAAwB;AACxB,aAAO,oBAAoB,wDAAwD,wBAAwB;AAAA,IAC/G;AAGA,WAAO,EAAE,WAAW,KAAK;AAAA,EAC7B;AAQA,WAAS,iCAAiC,qBAA0D;AAIhG,UAAM,mBAAiE,oBAAoB;AAAA,MACvF,CAAC,wBAAwB;AAAA,QACrB,IAAI,mBAAmB;AAAA,QACvB,MAAM,kBAAkB,kBAAkB,EACrC,OAAO,YAAY,EACnB,IAAI,CAAC,EAAE,IAAI,MAAM,GAAG;AAAA,MAC7B;AAAA,IACJ;AAEA,QAAI,mBAAkC;AAGtC,UAAM,aAAa,CAAC,SAAqD,OAA+B,CAAC,MAAM;AAE3G,UAAI,KAAK,SAAS,QAAQ,EAAE,GAAG;AAE3B,cAAM,UAAU,CAAC,GAAG,MAAM,QAAQ,EAAE;AAGpC,2BAAmB,QAAQ,OAAO,CAAC,YAAY,CAAC,CAAC,OAAO,EAAE,KAAK,MAAM;AAGrE;AAAA,MACJ;AAEA,iBAAW,OAAO,QAAQ,MAAM;AAE5B,cAAM,aAAa,iBAAiB,KAAK,CAAC,EAAE,GAAG,MAAM,OAAO,GAAG;AAG/D,YAAI,YAAY;AACZ,qBAAW,YAAY,CAAC,GAAG,MAAM,QAAQ,EAAE,CAAC;AAAA,QAChD;AAAA,MACJ;AAAA,IACJ;AAGA,eAAW,iBAAiB,KAAK,CAAC,YAAY,OAAO,QAAQ,OAAO,WAAW,CAAE;AAEjF,WAAO;AAAA,EACX;AAOA,WAAS,aAAa,YAAiB,OAAqB;AAExD,QAAI,OAAO,eAAe,YAAY,OAAO,WAAW,SAAS,YAAY,WAAW,KAAK,WAAW,GAAG;AACvG,YAAM,IAAI;AAAA,QACN,2FAA2F;AAAA,MAC/F;AAAA,IACJ;AAGA,YAAQ,WAAW,MAAM;AAAA,MACrB,KAAK;AACD,2BAAmB,YAAY,KAAK;AACpC;AAAA,MAEJ,KAAK;AACD,8BAAsB,YAAY,KAAK;AACvC;AAAA,MAEJ,KAAK;AACD,yBAAiB,YAAY,KAAK;AAClC;AAAA,MAEJ,KAAK;AACD,2BAAmB,YAAY,KAAK;AACpC;AAAA,MAEJ,KAAK;AACD,yBAAiB,YAAY,KAAK;AAClC;AAAA,MAEJ,KAAK;AACD,4BAAoB,YAAY,KAAK;AACrC;AAAA,MAEJ,KAAK;AACD,yBAAiB,YAAY,KAAK;AAClC;AAAA,MAEJ,KAAK;AACD,yBAAiB,YAAY,KAAK;AAClC;AAAA,MAEJ,KAAK;AACD,2BAAmB,YAAY,KAAK;AACpC;AAAA,MAEJ,KAAK;AACD,0BAAkB,YAAY,KAAK;AACnC;AAAA,MAEJ,KAAK;AACD,6BAAqB,YAAY,KAAK;AACtC;AAAA,MAEJ,KAAK;AACD,6BAAqB,YAAY,KAAK;AACtC;AAAA,MAEJ,KAAK;AACD,6BAAqB,YAAY,KAAK;AACtC;AAAA,MAEJ;AACI,cAAM,IAAI,MAAM,4BAA4B,WAAW,mBAAmB,QAAQ;AAAA,IAC1F;AAAA,EACJ;AAOA,WAAS,uBAAuB,YAAiB,OAAqB;AAElE,KAAC,SAAS,SAAS,SAAS,QAAQ,MAAM,EAAE,QAAQ,CAAC,kBAAkB;AAEnE,YAAM,sBAAsB,WAAW;AAGvC,UAAI,OAAO,wBAAwB,aAAa;AAC5C;AAAA,MACJ;AAGA,UAAI,OAAO,wBAAwB,UAAU;AACzC,cAAM,IAAI;AAAA,UACN,uBAAuB,uCAAuC,WAAW,wBAAwB;AAAA,QACrG;AAAA,MACJ;AAGA,UAAI,OAAO,oBAAoB,SAAS,YAAY,oBAAoB,KAAK,WAAW,GAAG;AACvF,cAAM,IAAI;AAAA,UACN,2CAA2C,gDAAgD,WAAW,wBAAwB;AAAA,QAClI;AAAA,MACJ;AAGA,UAAI,OAAO,oBAAoB,SAAS,eAAe,CAAC,MAAM,QAAQ,oBAAoB,IAAI,GAAG;AAC7F,cAAM,IAAI;AAAA,UACN,2CAA2C,sCAAsC,WAAW,wBAAwB;AAAA,QACxH;AAAA,MACJ;AAAA,IACJ,CAAC;AAAA,EACL;AAOA,WAAS,iBAAiB,YAAiB,OAAqB;AAE5D,QAAI,WAAW,SAAS,QAAQ;AAC5B,YAAM,IAAI,MAAM,4CAA4C;AAAA,IAChE;AAGA,QAAI,QAAQ,GAAG;AACX,YAAM,IAAI,MAAM,iDAAiD;AAAA,IACrE;AAGA,QAAI,OAAO,WAAW,OAAO,gBAAgB,OAAO,WAAW,OAAO,YAAY,WAAW,GAAG,WAAW,IAAI;AAC3G,YAAM,IAAI,MAAM,sEAAsE;AAAA,IAC1F;AAGA,QAAI,OAAO,WAAW,UAAU,aAAa;AACzC,YAAM,IAAI,MAAM,uDAAuD;AAAA,IAC3E;AAGA,2BAAuB,YAAY,KAAK;AAGxC,iBAAa,WAAW,OAAO,QAAQ,CAAC;AAAA,EAC5C;AAOA,WAAS,oBAAoB,YAAiB,OAAqB;AAE/D,QAAI,WAAW,SAAS,WAAW;AAC/B,YAAM,IAAI,MAAM,8DAA8D,QAAQ;AAAA,IAC1F;AAGA,QAAI,OAAO,WAAW,UAAU,aAAa;AACzC,YAAM,IAAI,MAAM,sEAAsE,QAAQ;AAAA,IAClG;AAGA,2BAAuB,YAAY,KAAK;AAGxC,iBAAa,WAAW,OAAO,QAAQ,CAAC;AAAA,EAC5C;AAOA,WAAS,iBAAiB,YAAiB,OAAqB;AAE5D,QAAI,WAAW,SAAS,QAAQ;AAC5B,YAAM,IAAI,MAAM,wDAAwD,QAAQ;AAAA,IACpF;AAGA,QAAI,OAAO,WAAW,UAAU,aAAa;AACzC,YAAM,IAAI,MAAM,mEAAmE,QAAQ;AAAA,IAC/F;AAGA,2BAAuB,YAAY,KAAK;AAGxC,iBAAa,WAAW,OAAO,QAAQ,CAAC;AAAA,EAC5C;AAOA,WAAS,iBAAiB,YAAiB,OAAqB;AAE5D,QAAI,WAAW,SAAS,QAAQ;AAC5B,YAAM,IAAI,MAAM,wDAAwD,QAAQ;AAAA,IACpF;AAGA,QAAI,OAAO,WAAW,UAAU,aAAa;AACzC,YAAM,IAAI,MAAM,mEAAmE,QAAQ;AAAA,IAC/F;AAGA,2BAAuB,YAAY,KAAK;AAGxC,iBAAa,WAAW,OAAO,QAAQ,CAAC;AAAA,EAC5C;AAOA,WAAS,mBAAmB,YAAiB,OAAqB;AAE9D,QAAI,WAAW,SAAS,UAAU;AAC9B,YAAM,IAAI,MAAM,4DAA4D,QAAQ;AAAA,IACxF;AAGA,QAAI,OAAO,WAAW,UAAU,aAAa;AACzC,YAAM,IAAI,MAAM,qEAAqE,QAAQ;AAAA,IACjG;AAGA,QAAI,OAAO,WAAW,eAAe,aAAa;AAC9C,UAAI,MAAM,QAAQ,WAAW,UAAU,GAAG;AAEtC,cAAM,qBAAqB,CAAC,CAAC,WAAW,WAAW,KAAK,CAAC,UAAmB,CAAC,UAAU,KAAK,CAAC;AAG7F,YAAI,WAAW,WAAW,WAAW,KAAK,oBAAoB;AAC1D,gBAAM,IAAI;AAAA,YACN,+GAA+G;AAAA,UACnH;AAAA,QACJ;AAAA,MACJ,WAAW,CAAC,UAAU,WAAW,UAAU,GAAG;AAC1C,cAAM,IAAI;AAAA,UACN,gIAAgI;AAAA,QACpI;AAAA,MACJ;AAAA,IACJ;AAGA,2BAAuB,YAAY,KAAK;AAGxC,iBAAa,WAAW,OAAO,QAAQ,CAAC;AAAA,EAC5C;AAOA,WAAS,kBAAkB,YAAiB,OAAqB;AAE7D,QAAI,WAAW,SAAS,SAAS;AAC7B,YAAM,IAAI,MAAM,0DAA0D,QAAQ;AAAA,IACtF;AAGA,QAAI,OAAO,WAAW,UAAU,aAAa;AACzC,YAAM,IAAI,MAAM,oEAAoE,QAAQ;AAAA,IAChG;AAGA,QAAI,OAAO,WAAW,aAAa,aAAa;AAC5C,UAAI,MAAM,QAAQ,WAAW,QAAQ,GAAG;AAEpC,cAAM,qBAAqB,CAAC,CAAC,WAAW,SAAS,KAAK,CAAC,UAAmB,CAAC,UAAU,KAAK,CAAC;AAG3F,YAAI,WAAW,SAAS,WAAW,KAAK,oBAAoB;AACxD,gBAAM,IAAI;AAAA,YACN,4GAA4G;AAAA,UAChH;AAAA,QACJ;AAAA,MACJ,WAAW,CAAC,UAAU,WAAW,QAAQ,GAAG;AACxC,cAAM,IAAI;AAAA,UACN,6HAA6H;AAAA,QACjI;AAAA,MACJ;AAAA,IACJ;AAGA,2BAAuB,YAAY,KAAK;AAGxC,iBAAa,WAAW,OAAO,QAAQ,CAAC;AAAA,EAC5C;AAOA,WAAS,mBAAmB,YAAiB,OAAqB;AAE9D,QAAI,WAAW,SAAS,UAAU;AAC9B,YAAM,IAAI,MAAM,4DAA4D,QAAQ;AAAA,IACxF;AAGA,QAAI,OAAO,WAAW,QAAQ,YAAY,WAAW,IAAI,WAAW,GAAG;AACnE,YAAM,IAAI,MAAM,0EAA0E,QAAQ;AAAA,IACtG;AAGA,KAAC,SAAS,OAAO,EAAE,QAAQ,CAAC,kBAAkB;AAC1C,UAAI,OAAO,WAAW,mBAAmB,aAAa;AAClD,cAAM,IAAI;AAAA,UACN,4DAA4D,wDAAwD;AAAA,QACxH;AAAA,MACJ;AAAA,IACJ,CAAC;AAGD,KAAC,SAAS,QAAQ,MAAM,EAAE,QAAQ,CAAC,kBAAkB;AACjD,UAAI,OAAO,WAAW,mBAAmB,aAAa;AAClD,cAAM,IAAI;AAAA,UACN,kEAAkE,wDAAwD;AAAA,QAC9H;AAAA,MACJ;AAAA,IACJ,CAAC;AAAA,EACL;AAOA,WAAS,mBAAmB,YAAiB,OAAqB;AAE9D,QAAI,WAAW,SAAS,UAAU;AAC9B,YAAM,IAAI,MAAM,4DAA4D,QAAQ;AAAA,IACxF;AAGA,QAAI,OAAO,WAAW,SAAS,YAAY,WAAW,KAAK,WAAW,GAAG;AACrE,YAAM,IAAI,MAAM,0EAA0E,QAAQ;AAAA,IACtG;AAGA,QAAI,OAAO,WAAW,SAAS,eAAe,CAAC,MAAM,QAAQ,WAAW,IAAI,GAAG;AAC3E,YAAM,IAAI,MAAM,2EAA2E,QAAQ;AAAA,IACvG;AAGA,2BAAuB,YAAY,KAAK;AAAA,EAC5C;AAOA,WAAS,sBAAsB,YAAiB,OAAqB;AAEjE,QAAI,WAAW,SAAS,aAAa;AACjC,YAAM,IAAI,MAAM,kEAAkE,QAAQ;AAAA,IAC9F;AAGA,QAAI,OAAO,WAAW,SAAS,YAAY,WAAW,KAAK,WAAW,GAAG;AACrE,YAAM,IAAI,MAAM,6EAA6E,QAAQ;AAAA,IACzG;AAGA,QAAI,OAAO,WAAW,SAAS,eAAe,CAAC,MAAM,QAAQ,WAAW,IAAI,GAAG;AAC3E,YAAM,IAAI,MAAM,8EAA8E,QAAQ;AAAA,IAC1G;AAGA,2BAAuB,YAAY,KAAK;AAAA,EAC5C;AAOA,WAAS,iBAAiB,YAAiB,OAAqB;AAE5D,QAAI,WAAW,SAAS,QAAQ;AAC5B,YAAM,IAAI,MAAM,wDAAwD,QAAQ;AAAA,IACpF;AAGA,QAAI,OAAO,WAAW,aAAa,aAAa;AAC5C,UAAI,MAAM,QAAQ,WAAW,QAAQ,GAAG;AAEpC,cAAM,qBAAqB,CAAC,CAAC,WAAW,SAAS,KAAK,CAAC,UAAmB,CAAC,UAAU,KAAK,CAAC;AAG3F,YAAI,WAAW,SAAS,WAAW,KAAK,oBAAoB;AACxD,gBAAM,IAAI;AAAA,YACN,2GAA2G;AAAA,UAC/G;AAAA,QACJ;AAAA,MACJ,WAAW,CAAC,UAAU,WAAW,QAAQ,GAAG;AACxC,cAAM,IAAI;AAAA,UACN,4HAA4H;AAAA,QAChI;AAAA,MACJ;AAAA,IACJ;AAGA,2BAAuB,YAAY,KAAK;AAAA,EAC5C;AAOA,WAAS,qBAAqB,YAAiB,OAAqB;AAEhE,QAAI,WAAW,SAAS,YAAY;AAChC,YAAM,IAAI,MAAM,gEAAgE,QAAQ;AAAA,IAC5F;AAGA,QAAI,CAAC,MAAM,QAAQ,WAAW,QAAQ,KAAK,WAAW,SAAS,WAAW,GAAG;AACzE,YAAM,IAAI,MAAM,iFAAiF,QAAQ;AAAA,IAC7G;AAGA,2BAAuB,YAAY,KAAK;AAGxC,eAAW,SAAS,QAAQ,CAAC,UAAe,aAAa,OAAO,QAAQ,CAAC,CAAC;AAAA,EAC9E;AAOA,WAAS,qBAAqB,YAAiB,OAAqB;AAEhE,QAAI,WAAW,SAAS,YAAY;AAChC,YAAM,IAAI,MAAM,gEAAgE,QAAQ;AAAA,IAC5F;AAGA,QAAI,CAAC,MAAM,QAAQ,WAAW,QAAQ,KAAK,WAAW,SAAS,WAAW,GAAG;AACzE,YAAM,IAAI,MAAM,iFAAiF,QAAQ;AAAA,IAC7G;AAGA,2BAAuB,YAAY,KAAK;AAGxC,eAAW,SAAS,QAAQ,CAAC,UAAe,aAAa,OAAO,QAAQ,CAAC,CAAC;AAAA,EAC9E;AAOA,WAAS,qBAAqB,YAAiB,OAAqB;AAEhE,QAAI,WAAW,SAAS,YAAY;AAChC,YAAM,IAAI,MAAM,gEAAgE,QAAQ;AAAA,IAC5F;AAGA,QAAI,CAAC,MAAM,QAAQ,WAAW,QAAQ,KAAK,WAAW,SAAS,WAAW,GAAG;AACzE,YAAM,IAAI,MAAM,iFAAiF,QAAQ;AAAA,IAC7G;AAGA,2BAAuB,YAAY,KAAK;AAGxC,eAAW,SAAS,QAAQ,CAAC,UAAe,aAAa,OAAO,QAAQ,CAAC,CAAC;AAAA,EAC9E;;;ACpnBA,MAAqB,4BAArB,cAAuD,MAAM;AAAA,IAIzD,YAAoB,QAAc;AAC9B,YAAM,mCAAmC;AADzB;AAAA,IAEpB;AAAA,IAOA,eAAe,CAAC,SAAe,SAAS,KAAK;AAAA,EACjD;;;ACNA,MAAqB,YAArB,MAA+B;AAAA,IAI3B,YAAoB,OAAwB;AAAxB;AAAA,IAAyB;AAAA,IAO7C,WAAW,CAAC,UAAiB;AAEzB,iBAAW,WAAW,KAAK,OAAO;AAE9B,mBAAW,SAAS,QAAQ,QAAQ;AAEhC,cAAI,CAAC,MAAM,YAAY,KAAK,GAAG;AAC3B,kBAAM,IAAI,0BAA0B,QAAQ,IAAI;AAAA,UACpD;AAAA,QACJ;AAAA,MACJ;AAAA,IACJ;AAAA,EACJ;;;ACpBA,MAA8B,OAA9B,MAAmC;AAAA,IAmB/B,YAAoB,MAAsB,YAAiC,MAAqB;AAA5E;AAAsB;AAAiC;AAAA,IAAsB;AAAA,IAfhF,MAAc,cAAc;AAAA,IAIrC;AAAA,IAIA;AAAA,IA6BR,WAAW,MAAgB,KAAK;AAAA,IAChC,WAAW,CAAC,UAA0B;AAClC,WAAK,QAAQ;AAAA,IACjB;AAAA,IAKA,SAAS,MAAM,KAAK;AAAA,IAKpB,UAAU,MAAM,KAAK;AAAA,IAKrB,gBAAgB,MAAM,KAAK;AAAA,IAK3B,eAAe,MAAM,KAAK;AAAA,IAQ1B,aAAa,MAAyB;AAClC,aACI,KAAK,cAAc,EAAE,OAAO,CAAC,cAAc,UAAU,QAAQ,EAAE,YAAY,MAAM,KAAK,YAAY,CAAC,EAAE,MACrG;AAAA,IAER;AAAA,IAKA,qBAAqB,MAAe,KAAK,cAAc,EAAE,OAAO,CAAC,cAAc,UAAU,QAAQ,CAAC;AAAA,IAKlG,eAAe,CAAC,UAAsB,KAAK,YAAY;AAAA,IAKvD,eAAe,MAAM,CAAC,CAAC,KAAK;AAAA,IAMrB,GAAG,OAA0B;AAChC,aAAO,KAAK,UAAU;AAAA,IAC1B;AAAA,IAKO,QAAc;AACjB,WAAK,wCAAoB;AAAA,IAC7B;AAAA,IAMO,MAAM,OAAoB;AAE7B,UAAI,CAAC,KAAK,sCAAgB,GAAG;AACzB;AAAA,MACJ;AAGA,WAAK,MAAM;AAEX,WAAK,aAAa,MAAM,GAAG,kBAAkB,OAAO,OAAO,IAAI;AAAA,IACnE;AAAA,IAQO,OAAO,OAAc,SAAqC;AAE7D,UAAI,KAAK,0CAAkB,KAAK,KAAK,oCAAe,GAAG;AACnD;AAAA,MACJ;AAEA,UAAI;AAEA,aAAK,UAAW,SAAS,KAAK;AAG9B,YAAI,KAAK,kCAAc,GAAG;AACtB,eAAK,aAAa,OAAO,GAAG,kBAAkB,KAAK;AAAA,QACvD;AAEA,aAAK,aAAa,MAAM,GAAG,kBAAkB,KAAK;AAGlD,aAAK,SAAS,OAAO,OAAO;AAG5B,YAAI,KAAK,0CAAkB,KAAK,KAAK,oCAAe,GAAG;AACnD,eAAK,aAAa,MAAM,GAAG,kBAAkB,OAAO,KAAK,0CAAkB,GAAG,KAAK;AAAA,QACvF;AAAA,MACJ,SAAS,OAAP;AAEE,YAAI,iBAAiB,6BAA6B,MAAM,aAAa,IAAI,GAAG;AAExE,eAAK,MAAM,KAAK;AAGhB,eAAK,0CAAqB;AAAA,QAC9B,OAAO;AACH,gBAAM;AAAA,QACV;AAAA,MACJ;AAAA,IACJ;AAAA,EACJ;AAMA,WAAS,gBAAwB;AAC7B,QAAI,KAAK,WAAY;AACjB,eAAU,IAAI,KAAK,OAAO,KAAK,QAAW,GAAG,SAAS,EAAE,EAAE,UAAU,CAAC;AAAA,IACzE;AACA,WAAO,GAAG,IAAI,GAAG,IAAI,MAAM,GAAG,IAAI,MAAM,GAAG,IAAI,MAAM,GAAG,IAAI,MAAM,GAAG,IAAI,GAAG,IAAI,GAAG;AAAA,EACvF;;;AC9LA,MAA8B,OAA9B,cAA2C,KAAK;AAAA,IAI5C,aAAa,MAAM;AAAA,EACvB;;;ACGA,MAAqB,SAArB,MAA4B;AAAA,IAexB,OAAc,QAAQ,MAA8B;AAChD,aAAO,KAAK,cAAc;AAAA,IAC9B;AAAA,IAOA,OAAc,QAAQ,MAAc,MAA4B;AAC5D,WAAK,cAAc,QAAQ;AAAA,IAC/B;AAAA,IAUA,OAAO,eAAe,OAAc,MAAsC;AAEtE,YAAM,eAAe,MAAM;AAC3B,UAAI,gBAAgB,OAAO,iBAAiB,YAAY;AACpD,eAAO,CAAC,SACJ,aAAa;AAAA,UACT;AAAA,UACA,KAAK,IAAI,CAAC,QAAQ,IAAI,KAAK;AAAA,QAC/B;AAAA,MACR;AAGA,UAAI,KAAK,cAAc,SAAS,OAAO,KAAK,cAAc,UAAU,YAAY;AAC5E,eAAO,CAAC,SAA4B,KAAK,cAAc,MAAM,OAAO,GAAG,KAAK,IAAI,CAAC,QAAQ,IAAI,KAAK,CAAC;AAAA,MACvG;AAGA,aAAO;AAAA,IACX;AAAA,IAOA,OAAO,WAAW,MAA2B;AACzC,aAAO,KAAK,aAAa;AAAA,IAC7B;AAAA,IAOA,OAAO,WAAW,MAAc,SAAsB;AAClD,WAAK,aAAa,QAAQ;AAAA,IAC9B;AAAA,IAMA,OAAO,OAAO,MAAc;AACxB,aAAO,KAAK,cAAc;AAC1B,aAAO,KAAK,aAAa;AAAA,IAC7B;AAAA,IAKA,OAAO,QAAQ;AACX,WAAK,gBAAgB,CAAC;AACtB,WAAK,eAAe,CAAC;AAAA,IACzB;AAAA,EACJ;AAtFI,gBAJiB,QAIF,iBAAmD,CAAC;AAInE,gBARiB,QAQF,gBAA+C,CAAC;;;ACTnE,MAAqB,SAArB,cAAoC,KAAK;AAAA,IAMrC,YAAY,YAAiC,YAA4B,iBAAgC;AACrG,YAAM,UAAU,YAAY,eAAe;AADF;AAA4B;AAAA,IAEzE;AAAA,IAKQ,uBAAuB;AAAA,IAKvB,2BAAiD;AAAA,IAO/C,SAAS,OAAc,SAAqC;AAGlE,UAAI,KAAK,sBAAsB;AAE3B,YAAI,KAAK,0BAA0B;AAE/B,eAAK,SAAS,KAAK,wBAAwB;AAAA,QAC/C;AAEA;AAAA,MACJ;AAGA,YAAM,oBAAoB,OAAO,eAAe,OAAO,KAAK,UAAU;AAGtE,UAAI,sBAAsB,MAAM;AAC5B,cAAM,IAAI;AAAA,UACN,4CAA4C,KAAK;AAAA,QACrD;AAAA,MACJ;AAMA,YAAM,eAAe,kBAAkB,KAAK,eAAe;AAE3D,UAAI,wBAAwB,SAAS;AACjC,qBAAa;AAAA,UACT,CAAC,WAAW;AAER,gBAAI,CAAC,KAAK,sBAAsB;AAC5B;AAAA,YACJ;AAGA,gBAAI,sDAA8B,8CAAyB;AACvD,oBAAM,IAAI;AAAA,gBACN;AAAA,cACJ;AAAA,YACJ;AAGA,iBAAK,2BAA2B;AAAA,UACpC;AAAA,UACA,CAAC,WAAW;AAER,gBAAI,CAAC,KAAK,sBAAsB;AAC5B;AAAA,YACJ;AAGA,kBAAM,IAAI,MAAM,MAAM;AAAA,UAC1B;AAAA,QACJ;AAGA,aAAK,4CAAsB;AAG3B,aAAK,uBAAuB;AAAA,MAChC,OAAO;AAEH,aAAK,qBAAqB,YAAY;AAGtC,aAAK,SAAS,mDAA6B;AAAA,MAC/C;AAAA,IACJ;AAAA,IAKA,UAAU,MAAM,KAAK;AAAA,IAKrB,QAAQ,MAAM;AAEV,WAAK,wCAAoB;AAGzB,WAAK,uBAAuB;AAC5B,WAAK,2BAA2B;AAAA,IACpC;AAAA,IAMQ,uBAAuB,CAAC,WAAoC;AAChE,cAAQ,QAAQ;AAAA,QACZ;AAAA,QACA;AAAA,QACA,KAAK;AACD;AAAA,QACJ;AACI,gBAAM,IAAI;AAAA,YACN,WAAW,KAAK;AAAA,UACpB;AAAA,MACR;AAAA,IACJ;AAAA,EACJ;;;AClIA,MAAqB,YAArB,cAAuC,KAAK;AAAA,IAMxC,YAAY,YAAiC,eAA+B,oBAAmC;AAC3G,YAAM,aAAa,YAAY,kBAAkB;AADR;AAA+B;AAAA,IAE5E;AAAA,IAOU,SAAS,OAAc,SAAqC;AAElE,YAAM,uBAAuB,OAAO,eAAe,OAAO,KAAK,aAAa;AAG5E,UAAI,yBAAyB,MAAM;AAC/B,cAAM,IAAI;AAAA,UACN,kDAAkD,KAAK;AAAA,QAC3D;AAAA,MACJ;AAGA,WAAK,SAAS,CAAC,CAAC,qBAAqB,KAAK,kBAAkB,+EAAkC;AAAA,IAClG;AAAA,IAKA,UAAU,MAAM,KAAK;AAAA,EACzB;;;ACpCA,MAAqB,OAArB,cAAkC,KAAK;AAAA,IAOnC,YACI,YACQ,UACA,aACA,aACV;AACE,YAAM,QAAQ,YAAY,CAAC,CAAC;AAJpB;AACA;AACA;AAAA,IAGZ;AAAA,IAKQ,oBAA4B;AAAA,IAK5B,gBAA+B;AAAA,IAK/B,iBAAyB;AAAA,IAOvB,SAAS,OAAc,SAAqC;AAElE,UAAI,KAAK,kCAAc,GAAG;AAEtB,aAAK,oBAAoB,IAAI,KAAK,EAAE,QAAQ;AAG5C,aAAK,iBAAiB;AAGtB,YAAI,KAAK,aAAa,MAAM;AACxB,eAAK,gBAAgB,KAAK;AAAA,QAC9B,WAAW,KAAK,gBAAgB,QAAQ,KAAK,gBAAgB,MAAM;AAG/D,gBAAM,SAAS,OAAO,QAAQ,WAAW,aAAa,QAAQ,SAAS,KAAK;AAG5E,eAAK,gBAAgB,KAAK;AAAA,YACtB,OAAO,KAAK,KAAK,cAAc,KAAK,cAAc,KAAK,KAAK;AAAA,UAChE;AAAA,QACJ,OAAO;AACH,eAAK,gBAAgB;AAAA,QACzB;AAGA,aAAK,4CAAsB;AAAA,MAC/B;AAGA,UAAI,KAAK,kBAAkB,MAAM;AAC7B;AAAA,MACJ;AAGA,UAAI,OAAO,QAAQ,iBAAiB,YAAY;AAE5C,cAAM,YAAY,QAAQ,aAAa;AAGvC,YAAI,OAAO,cAAc,YAAY,MAAM,SAAS,GAAG;AACnD,gBAAM,IAAI,MAAM,oDAAoD;AAAA,QACxE;AAGA,aAAK,kBAAkB,YAAY;AAAA,MACvC,OAAO;AAEH,aAAK,iBAAiB,IAAI,KAAK,EAAE,QAAQ,IAAI,KAAK;AAAA,MACtD;AAGA,UAAI,KAAK,kBAAkB,KAAK,eAAe;AAE3C,aAAK,gDAAwB;AAAA,MACjC;AAAA,IACJ;AAAA,IAKA,UAAU,MAAM;AACZ,UAAI,KAAK,aAAa,MAAM;AACxB,eAAO,QAAQ,KAAK;AAAA,MACxB,WAAW,KAAK,gBAAgB,QAAQ,KAAK,gBAAgB,MAAM;AAC/D,eAAO,QAAQ,KAAK,iBAAiB,KAAK;AAAA,MAC9C,OAAO;AACH,eAAO;AAAA,MACX;AAAA,IACJ;AAAA,EACJ;;;AC5GA,MAA8B,YAA9B,cAAgD,KAAK;AAAA,IAMjD,YAAY,MAAc,YAAmC,OAAa;AACtE,YAAM,MAAM,YAAY,CAAC,CAAC;AAD+B;AAAA,IAE7D;AAAA,IAKA,aAAa,MAAM;AAAA,IAKnB,cAAc,MAAM,CAAC,KAAK,KAAK;AAAA,IAK/B,QAAQ,MAAM;AAEV,WAAK,wCAAoB;AAGzB,WAAK,MAAM,MAAM;AAAA,IACrB;AAAA,IAMA,QAAQ,CAAC,UAAiB;AAEtB,UAAI,CAAC,KAAK,sCAAgB,GAAG;AACzB;AAAA,MACJ;AAGA,WAAK,MAAM,MAAM,KAAK;AAGtB,WAAK,MAAM;AAEX,WAAK,aAAa,MAAM,GAAG,kBAAkB,OAAO,OAAO,IAAI;AAAA,IACnE;AAAA,EACJ;;;AC9CA,MAAqB,OAArB,cAAkC,UAAU;AAAA,IAKxC,YAAY,YAAyB,OAAa;AAC9C,YAAM,QAAQ,YAAY,KAAK;AAAA,IACnC;AAAA,IAOU,SAAS,OAAc,SAAqC;AAElE,UAAI,KAAK,MAAM,SAAS,yCAAqB,KAAK,MAAM,SAAS,2CAAqB;AAElF,aAAK,MAAM,OAAO,OAAO,OAAO;AAAA,MACpC;AAGA,WAAK,SAAS,KAAK,MAAM,SAAS,CAAC;AAAA,IACvC;AAAA,IAKA,UAAU,MAAM;AAAA,EACpB;;;ACzBA,MAAqB,SAArB,cAAoC,UAAU;AAAA,IAQ1C,YACI,YACQ,YACA,eACA,eACR,OACF;AACE,YAAM,UAAU,YAAY,KAAK;AALzB;AACA;AACA;AAAA,IAIZ;AAAA,IAKQ,uBAAsC;AAAA,IAKtC,wBAAgC;AAAA,IAO9B,SAAS,OAAc,SAAqC;AAElE,UAAI,KAAK,kCAAc,GAAG;AAEtB,aAAK,MAAM,MAAM;AAGjB,aAAK,wBAAwB;AAG7B,aAAK,wBAAwB,OAAO;AAAA,MACxC;AAIA,UAAI,KAAK,WAAW,GAAG;AAEnB,aAAK,4CAAsB;AAI3B,YAAI,KAAK,MAAM,SAAS,+CAAuB;AAC3C,eAAK,MAAM,MAAM;AAAA,QACrB;AAGA,aAAK,MAAM,OAAO,OAAO,OAAO;AAIhC,YAAI,KAAK,MAAM,SAAS,yCAAoB;AAExC,eAAK,0CAAqB;AAE1B;AAAA,QACJ,WAAW,KAAK,MAAM,SAAS,+CAAuB;AAElD,eAAK,yBAAyB;AAAA,QAClC;AAAA,MACJ,OAAO;AAEH,aAAK,gDAAwB;AAAA,MACjC;AAAA,IACJ;AAAA,IAKA,UAAU,MAAM;AACZ,UAAI,KAAK,eAAe,MAAM;AAC1B,eAAO,UAAU,KAAK;AAAA,MAC1B,WAAW,KAAK,kBAAkB,QAAQ,KAAK,kBAAkB,MAAM;AACnE,eAAO,UAAU,KAAK,kBAAkB,KAAK;AAAA,MACjD,OAAO;AACH,eAAO;AAAA,MACX;AAAA,IACJ;AAAA,IAKA,QAAQ,MAAM;AAEV,WAAK,wCAAoB;AAGzB,WAAK,wBAAwB;AAG7B,WAAK,MAAM,MAAM;AAAA,IACrB;AAAA,IAMQ,aAAa,MAAM;AACvB,UAAI,KAAK,yBAAyB,MAAM;AAEpC,eAAO,KAAK,wBAAwB,KAAK;AAAA,MAC7C;AAGA,aAAO;AAAA,IACX;AAAA,IAMQ,0BAA0B,CAAC,YAAkC;AAEjE,UAAI,KAAK,eAAe,MAAM;AAC1B,aAAK,uBAAuB,KAAK;AAAA,MACrC,WAAW,KAAK,kBAAkB,QAAQ,KAAK,kBAAkB,MAAM;AAGnE,cAAM,SAAS,OAAO,QAAQ,WAAW,aAAa,QAAQ,SAAS,KAAK;AAG5E,aAAK,uBAAuB,KAAK;AAAA,UAC7B,OAAO,KAAK,KAAK,gBAAgB,KAAK,gBAAgB,KAAK,KAAK;AAAA,QACpE;AAAA,MACJ,OAAO;AACH,aAAK,uBAAuB;AAAA,MAChC;AAAA,IACJ;AAAA,EACJ;;;AC5IA,MAAqB,QAArB,cAAmC,UAAU;AAAA,IAQzC,YACI,YACQ,UACA,aACA,aACR,OACF;AACE,YAAM,SAAS,YAAY,KAAK;AALxB;AACA;AACA;AAAA,IAIZ;AAAA,IAKQ,qBAAoC;AAAA,IAKpC,sBAA8B;AAAA,IAO5B,SAAS,OAAc,SAAqC;AAElE,UAAI,KAAK,kCAAc,GAAG;AAEtB,aAAK,MAAM,MAAM;AAGjB,aAAK,sBAAsB;AAG3B,aAAK,sBAAsB,OAAO;AAAA,MACtC;AAIA,UAAI,KAAK,WAAW,GAAG;AAEnB,aAAK,4CAAsB;AAI3B,YAAI,KAAK,MAAM,SAAS,yCAAoB;AACxC,eAAK,MAAM,MAAM;AAAA,QACrB;AAGA,aAAK,MAAM,OAAO,OAAO,OAAO;AAIhC,YAAI,KAAK,MAAM,SAAS,+CAAuB;AAE3C,eAAK,gDAAwB;AAE7B;AAAA,QACJ,WAAW,KAAK,MAAM,SAAS,yCAAoB;AAE/C,eAAK,uBAAuB;AAAA,QAChC;AAAA,MACJ,OAAO;AAEH,aAAK,0CAAqB;AAAA,MAC9B;AAAA,IACJ;AAAA,IAKA,UAAU,MAAM;AACZ,UAAI,KAAK,aAAa,MAAM;AACxB,eAAO,SAAS,KAAK;AAAA,MACzB,WAAW,KAAK,gBAAgB,QAAQ,KAAK,gBAAgB,MAAM;AAC/D,eAAO,SAAS,KAAK,gBAAgB,KAAK;AAAA,MAC9C,OAAO;AACH,eAAO;AAAA,MACX;AAAA,IACJ;AAAA,IAKA,QAAQ,MAAM;AAEV,WAAK,wCAAoB;AAGzB,WAAK,sBAAsB;AAG3B,WAAK,MAAM,MAAM;AAAA,IACrB;AAAA,IAMA,aAAa,MAAM;AACf,UAAI,KAAK,uBAAuB,MAAM;AAElC,eAAO,KAAK,sBAAsB,KAAK;AAAA,MAC3C;AAGA,aAAO;AAAA,IACX;AAAA,IAMA,wBAAwB,CAAC,YAAkC;AAEvD,UAAI,KAAK,aAAa,MAAM;AACxB,aAAK,qBAAqB,KAAK;AAAA,MACnC,WAAW,KAAK,gBAAgB,QAAQ,KAAK,gBAAgB,MAAM;AAG/D,cAAM,SAAS,OAAO,QAAQ,WAAW,aAAa,QAAQ,SAAS,KAAK;AAG5E,aAAK,qBAAqB,KAAK;AAAA,UAC3B,OAAO,KAAK,KAAK,cAAc,KAAK,cAAc,KAAK,KAAK;AAAA,QAChE;AAAA,MACJ,OAAO;AACH,aAAK,qBAAqB;AAAA,MAC9B;AAAA,IACJ;AAAA,EACJ;;;AChJA,MAAqB,OAArB,cAAkC,UAAU;AAAA,IAKxC,YAAY,YAAyB,OAAa;AAC9C,YAAM,QAAQ,YAAY,KAAK;AAAA,IACnC;AAAA,IAOU,SAAS,OAAc,SAAqC;AAElE,UAAI,KAAK,MAAM,SAAS,yCAAqB,KAAK,MAAM,SAAS,2CAAqB;AAClF,aAAK,MAAM,OAAO,OAAO,OAAO;AAAA,MACpC;AAGA,cAAQ,KAAK,MAAM,SAAS,GAAG;AAAA,QAC3B;AACI,eAAK,4CAAsB;AAC3B;AAAA,QAEJ;AACI,eAAK,0CAAqB;AAC1B;AAAA,QAEJ;AACI,eAAK,gDAAwB;AAC7B;AAAA,QAEJ;AACI,eAAK,wCAAoB;AAAA,MACjC;AAAA,IACJ;AAAA,IAKA,UAAU,MAAM;AAAA,EACpB;;;AC3CA,MAAqB,UAArB,cAAqC,UAAU;AAAA,IAK3C,YAAY,YAAyB,OAAa;AAC9C,YAAM,WAAW,YAAY,KAAK;AAAA,IACtC;AAAA,IAOU,SAAS,OAAc,SAAqC;AAElE,UAAI,KAAK,MAAM,SAAS,yCAAqB,KAAK,MAAM,SAAS,2CAAqB;AAClF,aAAK,MAAM,OAAO,OAAO,OAAO;AAAA,MACpC;AAGA,cAAQ,KAAK,MAAM,SAAS,GAAG;AAAA,QAC3B;AACI,eAAK,4CAAsB;AAC3B;AAAA,QAEJ;AAAA,QACA;AACI,eAAK,gDAAwB;AAC7B;AAAA,QAEJ;AACI,eAAK,wCAAoB;AAAA,MACjC;AAAA,IACJ;AAAA,IAKA,UAAU,MAAM;AAAA,EACpB;;;ACxCA,MAAqB,OAArB,cAAkC,UAAU;AAAA,IAKxC,YAAY,YAAyB,OAAa;AAC9C,YAAM,QAAQ,YAAY,KAAK;AAAA,IACnC;AAAA,IAOU,SAAS,OAAc,SAAqC;AAElE,UAAI,KAAK,MAAM,SAAS,yCAAqB,KAAK,MAAM,SAAS,2CAAqB;AAClF,aAAK,MAAM,OAAO,OAAO,OAAO;AAAA,MACpC;AAGA,cAAQ,KAAK,MAAM,SAAS,GAAG;AAAA,QAC3B;AACI,eAAK,4CAAsB;AAC3B;AAAA,QAEJ;AAAA,QACA;AACI,eAAK,0CAAqB;AAC1B;AAAA,QAEJ;AACI,eAAK,wCAAoB;AAAA,MACjC;AAAA,IACJ;AAAA,IAKA,UAAU,MAAM;AAAA,EACpB;;;ACnDA,0BAAwB;;;ACQxB,MAA8B,YAA9B,cAAgD,KAAK;AAAA,IAMjD,YAAY,MAAc,YAAmC,UAAkB;AAC3E,YAAM,MAAM,YAAY,CAAC,CAAC;AAD+B;AAAA,IAE7D;AAAA,IAKA,aAAa,MAAM;AAAA,IAKnB,cAAc,MAAM,KAAK;AAAA,IAKzB,QAAQ,MAAM;AAEV,WAAK,wCAAoB;AAGzB,WAAK,YAAY,EAAE,QAAQ,CAAC,UAAU,MAAM,MAAM,CAAC;AAAA,IACvD;AAAA,IAMA,QAAQ,CAAC,UAAiB;AAEtB,UAAI,CAAC,KAAK,sCAAgB,GAAG;AACzB;AAAA,MACJ;AAGA,WAAK,YAAY,EAAE,QAAQ,CAAC,UAAU,MAAM,MAAM,KAAK,CAAC;AAGxD,WAAK,MAAM;AAEX,WAAK,aAAa,MAAM,GAAG,kBAAkB,OAAO,OAAO,IAAI;AAAA,IACnE;AAAA,EACJ;;;AD3CA,MAAqB,QAArB,cAAmC,UAAU;AAAA,IAMzC,YAAY,YAAiC,SAAmB,UAAkB;AAC9E,YAAM,SAAS,YAAY,QAAQ;AADM;AAAA,IAE7C;AAAA,IAKQ;AAAA,IAOE,SAAS,OAAc,SAAqC;AAElE,UAAI,KAAK,kCAAc,GAAG;AAEtB,cAAM,gBAAY,kBAAAC,SAAkB;AAAA,UAEhC,QAAQ,QAAQ;AAAA,UAEhB,cAAc,KAAK,SAAS,IAAI,CAAC,OAAO,UAAU,CAAC,OAAO,KAAK,QAAQ,UAAU,CAAC,CAAC;AAAA,QACvF,CAAC;AAGD,aAAK,gBAAgB,UAAU,KAAK,KAAK;AAAA,MAC7C;AAGA,UAAI,CAAC,KAAK,eAAe;AACrB,cAAM,IAAI,MAAM,uDAAuD;AAAA,MAC3E;AAGA,UAAI,KAAK,cAAc,SAAS,yCAAqB,KAAK,cAAc,SAAS,2CAAqB;AAClG,aAAK,cAAc,OAAO,OAAO,OAAO;AAAA,MAC5C;AAGA,WAAK,SAAS,KAAK,cAAc,SAAS,CAAC;AAAA,IAC/C;AAAA,IAKA,UAAU,MAAO,KAAK,QAAQ,SAAS,UAAU,KAAK,QAAQ,KAAK,GAAG,OAAO;AAAA,EACjF;;;AExDA,MAAqB,WAArB,cAAsC,UAAU;AAAA,IAK5C,YAAY,YAAmC,UAAkB;AAC7D,YAAM,YAAY,YAAY,QAAQ;AADK;AAAA,IAE/C;AAAA,IAOU,SAAS,OAAc,SAAqC;AAElE,iBAAW,SAAS,KAAK,UAAU;AAE/B,YAAI,MAAM,SAAS,yCAAqB,MAAM,SAAS,2CAAqB;AAExE,gBAAM,OAAO,OAAO,OAAO;AAAA,QAC/B;AAGA,YAAI,MAAM,SAAS,+CAAuB;AAEtC,eAAK,gDAAwB;AAG7B;AAAA,QACJ;AAGA,YAAI,MAAM,SAAS,yCAAoB;AAGnC,cAAI,KAAK,SAAS,QAAQ,KAAK,MAAM,KAAK,SAAS,SAAS,GAAG;AAE3D,iBAAK,0CAAqB;AAG1B;AAAA,UACJ,OAAO;AAEH;AAAA,UACJ;AAAA,QACJ;AAGA,YAAI,MAAM,SAAS,2CAAqB;AAEpC,eAAK,4CAAsB;AAG3B;AAAA,QACJ;AAGA,cAAM,IAAI,MAAM,0CAA0C;AAAA,MAC9D;AAAA,IACJ;AAAA,IAKA,UAAU,MAAM;AAAA,EACpB;;;AClEA,MAAqB,WAArB,cAAsC,UAAU;AAAA,IAK5C,YAAY,YAAmC,UAAkB;AAC7D,YAAM,YAAY,YAAY,QAAQ;AADK;AAAA,IAE/C;AAAA,IAOU,SAAS,OAAc,SAAqC;AAElE,iBAAW,SAAS,KAAK,UAAU;AAE/B,YAAI,MAAM,SAAS,yCAAqB,MAAM,SAAS,2CAAqB;AAExE,gBAAM,OAAO,OAAO,OAAO;AAAA,QAC/B;AAGA,YAAI,MAAM,SAAS,+CAAuB;AAGtC,cAAI,KAAK,SAAS,QAAQ,KAAK,MAAM,KAAK,SAAS,SAAS,GAAG;AAE3D,iBAAK,gDAAwB;AAG7B;AAAA,UACJ,OAAO;AAEH;AAAA,UACJ;AAAA,QACJ;AAGA,YAAI,MAAM,SAAS,yCAAoB;AAEnC,eAAK,0CAAqB;AAG1B;AAAA,QACJ;AAGA,YAAI,MAAM,SAAS,2CAAqB;AAEpC,eAAK,4CAAsB;AAG3B;AAAA,QACJ;AAGA,cAAM,IAAI,MAAM,0CAA0C;AAAA,MAC9D;AAAA,IACJ;AAAA,IAKA,UAAU,MAAM;AAAA,EACpB;;;AClEA,MAAqB,WAArB,cAAsC,UAAU;AAAA,IAK5C,YAAY,YAAyB,UAAkB;AACnD,YAAM,YAAY,YAAY,QAAQ;AAAA,IAC1C;AAAA,IAOU,SAAS,OAAc,SAAqC;AAElE,UAAI,iBAAiB;AAErB,UAAI,iBAAiB;AAGrB,iBAAW,SAAS,KAAK,UAAU;AAE/B,YAAI,MAAM,SAAS,yCAAqB,MAAM,SAAS,2CAAqB;AAExE,gBAAM,OAAO,OAAO,OAAO;AAAA,QAC/B;AAGA,YAAI,MAAM,SAAS,+CAAuB;AAEtC;AAGA;AAAA,QACJ;AAGA,YAAI,MAAM,SAAS,yCAAoB;AACnC,2BAAiB;AAGjB;AAAA,QACJ;AAGA,YAAI,MAAM,SAAS,2CAAqB;AAEpC,gBAAM,IAAI,MAAM,0CAA0C;AAAA,QAC9D;AAAA,MACJ;AAEA,UAAI,gBAAgB;AAEhB,aAAK,0CAAqB;AAG1B,mBAAW,SAAS,KAAK,UAAU;AAC/B,cAAI,MAAM,SAAS,2CAAqB;AACpC,kBAAM,MAAM,KAAK;AAAA,UACrB;AAAA,QACJ;AAAA,MACJ,OAAO;AAEH,aAAK,SAAS,mBAAmB,KAAK,SAAS,sFAAwC;AAAA,MAC3F;AAAA,IACJ;AAAA,IAKA,UAAU,MAAM;AAAA,EACpB;;;ACrEA,MAA8B,YAA9B,MAAuG;AAAA,IAKnG,YAAsB,MAAwB,MAAqB;AAA7C;AAAwB;AAAA,IAAsB;AAAA,IAKpE,UAAU,MAAM,KAAK;AAAA,IAKrB,eAAe,MAAM,KAAK;AAAA,EAW9B;;;AC5BA,MAA8B,QAA9B,cAA4C,UAAiC;AAAA,IAMzE,YAAY,MAAc,MAA6B,WAAmB;AACtE,YAAM,MAAM,IAAI;AADmC;AAAA,IAEvD;AAAA,IAKA,eAAe,MAAM,KAAK;AAAA,IAK1B,UAAU,MAAM;AAAA,IAKhB,aAAoC;AAChC,aAAO;AAAA,QACH,MAAM,KAAK,QAAQ;AAAA,QACnB,MAAM,KAAK,aAAa;AAAA,QACxB,WAAW,KAAK,aAAa;AAAA,MACjC;AAAA,IACJ;AAAA,EAQJ;;;ACzCA,MAAqB,QAArB,cAAmC,MAAM;AAAA,IAKrC,YAAY,WAAmB,MAAqB;AAChD,YAAM,SAAS,MAAM,SAAS;AAAA,IAClC;AAAA,IAOA,cAAc,CAAC,UAAiB;AAE5B,YAAM,uBAAuB,OAAO,eAAe,OAAO,KAAK,aAAa,CAAC;AAG7E,UAAI,yBAAyB,MAAM;AAC/B,cAAM,IAAI;AAAA,UACN,gDAAgD,KAAK,aAAa;AAAA,QACtE;AAAA,MACJ;AAGA,aAAO,CAAC,CAAC,qBAAqB,KAAK,IAAI;AAAA,IAC3C;AAAA,EACJ;;;AC5BA,MAAqB,QAArB,cAAmC,MAAM;AAAA,IAKrC,YAAY,WAAmB,MAAqB;AAChD,YAAM,SAAS,MAAM,SAAS;AAAA,IAClC;AAAA,IAOA,cAAc,CAAC,UAAiB;AAE5B,YAAM,uBAAuB,OAAO,eAAe,OAAO,KAAK,aAAa,CAAC;AAG7E,UAAI,yBAAyB,MAAM;AAC/B,cAAM,IAAI;AAAA,UACN,gDAAgD,KAAK,aAAa;AAAA,QACtE;AAAA,MACJ;AAGA,aAAO,CAAC,CAAC,CAAC,qBAAqB,KAAK,IAAI;AAAA,IAC5C;AAAA,EACJ;;;ACxBA,MAA8B,WAA9B,cAA+C,UAAoC;AAAA,IAM/E,YAAY,MAAc,MAA6B,cAAsB;AACzE,YAAM,MAAM,IAAI;AADmC;AAAA,IAEvD;AAAA,IAKA,kBAAkB,MAAM,KAAK;AAAA,IAK7B,UAAU,MAAM;AAAA,IAKhB,aAAuC;AACnC,aAAO;AAAA,QACH,MAAM,KAAK,QAAQ;AAAA,QACnB,MAAM,KAAK,aAAa;AAAA,QACxB,cAAc,KAAK,gBAAgB;AAAA,MACvC;AAAA,IACJ;AAAA,EAOJ;;;ACxCA,MAAqB,QAArB,cAAmC,SAAS;AAAA,IAKxC,YAAY,cAAsB,MAAqB;AACnD,YAAM,SAAS,MAAM,YAAY;AAAA,IACrC;AAAA,IAMA,oBAAoB,CAAC,UAAiB;AAElC,YAAM,sBAAsB,OAAO,eAAe,OAAO,KAAK,gBAAgB,CAAC;AAG/E,UAAI,wBAAwB,MAAM;AAC9B,cAAM,IAAI;AAAA,UACN,+BAA+B,KAAK,gBAAgB;AAAA,QACxD;AAAA,MACJ;AAGA,0BAAoB,KAAK,IAAI;AAAA,IACjC;AAAA,EACJ;;;AC3BA,MAAqB,OAArB,cAAkC,SAAS;AAAA,IAKvC,YAAY,cAAsB,MAAqB;AACnD,YAAM,QAAQ,MAAM,YAAY;AAAA,IACpC;AAAA,IAQA,oBAAoB,CAAC,OAAc,WAAoB,cAAuB;AAE1E,YAAM,sBAAsB,OAAO,eAAe,OAAO,KAAK,gBAAgB,CAAC;AAG/E,UAAI,wBAAwB,MAAM;AAC9B,cAAM,IAAI;AAAA,UACN,8BAA8B,KAAK,gBAAgB;AAAA,QACvD;AAAA,MACJ;AAGA,0BAAoB,CAAC,EAAE,OAAO,EAAE,WAAW,WAAW,SAAS,UAAU,EAAE,GAAG,GAAG,KAAK,IAAI,CAAC;AAAA,IAC/F;AAAA,EACJ;;;AC7BA,MAAqB,OAArB,cAAkC,SAAS;AAAA,IAKvC,YAAY,cAAsB,MAAqB;AACnD,YAAM,QAAQ,MAAM,YAAY;AAAA,IACpC;AAAA,IAMA,oBAAoB,CAAC,UAAiB;AAElC,YAAM,sBAAsB,OAAO,eAAe,OAAO,KAAK,gBAAgB,CAAC;AAG/E,UAAI,wBAAwB,MAAM;AAC9B,cAAM,IAAI;AAAA,UACN,8BAA8B,KAAK,gBAAgB;AAAA,QACvD;AAAA,MACJ;AAGA,0BAAoB,KAAK,IAAI;AAAA,IACjC;AAAA,EACJ;;;ACqBA,MAAM,qBAEF;AAAA,IACA,OAAO,CAAC,WAAmB,uBAAsC,IAAI,MAAM,WAAW,kBAAkB;AAAA,IACxG,OAAO,CAAC,WAAmB,uBAAsC,IAAI,MAAM,WAAW,kBAAkB;AAAA,IACxG,OAAO,CAAC,cAAsB,uBAAsC,IAAI,MAAM,cAAc,kBAAkB;AAAA,IAC9G,MAAM,CAAC,cAAsB,uBAAsC,IAAI,KAAK,cAAc,kBAAkB;AAAA,IAC5G,MAAM,CAAC,cAAsB,uBAAsC,IAAI,KAAK,cAAc,kBAAkB;AAAA,EAChH;AAkGA,MAAM,mBAAmB;AAAA,IACrB,MAAM,OAAoB;AAAA,MACtB,MAAM;AAAA,MACN,YAAY,CAAC;AAAA,MACb,MAAM;AAAA,MACN,UAAU,CAAC;AAAA,MACX,SAAS,OAAe;AAEpB,YAAI,QAAQ,GAAG;AACX,gBAAM,IAAI,MAAM,iDAAiD;AAAA,QACrE;AAGA,YAAI,KAAK,SAAS,WAAW,GAAG;AAC5B,gBAAM,IAAI,MAAM,sCAAsC;AAAA,QAC1D;AAAA,MACJ;AAAA,MACA,mBAAmB,uBAAuB,iBAAiB;AACvD,eAAO,IAAI;AAAA,UACP,KAAK;AAAA,UACL,KAAK,SAAU,GAAG,mBAAmB,uBAAuB,gBAAgB,MAAM,CAAC;AAAA,QACvF;AAAA,MACJ;AAAA,IACJ;AAAA,IACA,QAAQ,OAAsB;AAAA,MAC1B,MAAM;AAAA,MACN,YAAY;AAAA,MACZ,WAAW;AAAA,MAAC;AAAA,MACZ,mBAAmB,uBAAuB,iBAAiB;AAEvD,cAAM,iBAAiB,sBAAsB,KAAK,UAAU;AAG5D,YAAI,gBAAgB,QAAQ,KAAK,UAAU,MAAM,IAAI;AACjD,gBAAM,IAAI,MAAM,mEAAmE,KAAK,aAAa;AAAA,QACzG;AAGA,YAAI,gBAAgB;AAChB,iBAAO,eACF,mBAAmB,uBAAuB,gBAAgB,OAAO,KAAK,UAAU,CAAC,EACjF,YAAY,EAAE;AAAA,QACvB,OAAO;AACH,gBAAM,IAAI,MAAM,gCAAgC,KAAK,wCAAwC;AAAA,QACjG;AAAA,MACJ;AAAA,IACJ;AAAA,IACA,UAAU,OAAyB;AAAA,MAC/B,MAAM;AAAA,MACN,YAAY,CAAC;AAAA,MACb,UAAU,CAAC;AAAA,MACX,WAAW;AAEP,YAAI,KAAK,SAAS,SAAS,GAAG;AAC1B,gBAAM,IAAI,MAAM,mDAAmD;AAAA,QACvE;AAAA,MACJ;AAAA,MACA,mBAAmB,uBAAuB,iBAAiB;AACvD,eAAO,IAAI;AAAA,UACP,KAAK;AAAA,UACL,KAAK,SAAS,IAAI,CAAC,UAAU,MAAM,mBAAmB,uBAAuB,gBAAgB,MAAM,CAAC,CAAC;AAAA,QACzG;AAAA,MACJ;AAAA,IACJ;AAAA,IACA,UAAU,OAAyB;AAAA,MAC/B,MAAM;AAAA,MACN,YAAY,CAAC;AAAA,MACb,UAAU,CAAC;AAAA,MACX,WAAW;AAEP,YAAI,KAAK,SAAS,SAAS,GAAG;AAC1B,gBAAM,IAAI,MAAM,mDAAmD;AAAA,QACvE;AAAA,MACJ;AAAA,MACA,mBAAmB,uBAAuB,iBAAiB;AACvD,eAAO,IAAI;AAAA,UACP,KAAK;AAAA,UACL,KAAK,SAAS,IAAI,CAAC,UAAU,MAAM,mBAAmB,uBAAuB,gBAAgB,MAAM,CAAC,CAAC;AAAA,QACzG;AAAA,MACJ;AAAA,IACJ;AAAA,IACA,UAAU,OAAyB;AAAA,MAC/B,MAAM;AAAA,MACN,YAAY,CAAC;AAAA,MACb,UAAU,CAAC;AAAA,MACX,WAAW;AAEP,YAAI,KAAK,SAAS,SAAS,GAAG;AAC1B,gBAAM,IAAI,MAAM,mDAAmD;AAAA,QACvE;AAAA,MACJ;AAAA,MACA,mBAAmB,uBAAuB,iBAAiB;AACvD,eAAO,IAAI;AAAA,UACP,KAAK;AAAA,UACL,KAAK,SAAS,IAAI,CAAC,UAAU,MAAM,mBAAmB,uBAAuB,gBAAgB,MAAM,CAAC,CAAC;AAAA,QACzG;AAAA,MACJ;AAAA,IACJ;AAAA,IACA,OAAO,OAAqB;AAAA,MACxB,MAAM;AAAA,MACN,YAAY,CAAC;AAAA,MACb,UAAU,CAAC;AAAA,MACX,SAAS,CAAC;AAAA,MACV,WAAW;AAEP,YAAI,KAAK,SAAU,SAAS,GAAG;AAC3B,gBAAM,IAAI,MAAM,gDAAgD;AAAA,QACpE;AAAA,MACJ;AAAA,MACA,mBAAmB,uBAAuB,iBAAiB;AACvD,eAAO,IAAI;AAAA,UACP,KAAK;AAAA,UACL,KAAK;AAAA,UACL,KAAK,SAAU,IAAI,CAAC,UAAU,MAAM,mBAAmB,uBAAuB,gBAAgB,MAAM,CAAC,CAAC;AAAA,QAC1G;AAAA,MACJ;AAAA,IACJ;AAAA,IACA,QAAQ,OAAsB;AAAA,MAC1B,MAAM;AAAA,MACN,YAAY,CAAC;AAAA,MACb,YAAY;AAAA,MACZ,eAAe;AAAA,MACf,eAAe;AAAA,MACf,UAAU,CAAC;AAAA,MACX,WAAW;AAEP,YAAI,KAAK,SAAU,WAAW,GAAG;AAC7B,gBAAM,IAAI,MAAM,wCAAwC;AAAA,QAC5D;AAEA,YAAI,KAAK,eAAe,MAAM;AAE1B,cAAI,KAAK,aAAa,GAAG;AACrB,kBAAM,IAAI,MAAM,oEAAoE;AAAA,UACxF;AAAA,QACJ,WAAW,KAAK,kBAAkB,QAAQ,KAAK,kBAAkB,MAAM;AAEnE,cAAI,KAAK,gBAAgB,KAAK,KAAK,gBAAgB,GAAG;AAClD,kBAAM,IAAI;AAAA,cACN;AAAA,YACJ;AAAA,UACJ;AAGA,cAAI,KAAK,gBAAgB,KAAK,eAAe;AACzC,kBAAM,IAAI;AAAA,cACN;AAAA,YACJ;AAAA,UACJ;AAAA,QACJ,OAAO;AAAA,QAEP;AAAA,MACJ;AAAA,MACA,mBAAmB,uBAAuB,iBAAiB;AACvD,eAAO,IAAI;AAAA,UACP,KAAK;AAAA,UACL,KAAK;AAAA,UACL,KAAK;AAAA,UACL,KAAK;AAAA,UACL,KAAK,SAAU,GAAG,mBAAmB,uBAAuB,gBAAgB,MAAM,CAAC;AAAA,QACvF;AAAA,MACJ;AAAA,IACJ;AAAA,IACA,OAAO,OAAqB;AAAA,MACxB,MAAM;AAAA,MACN,YAAY,CAAC;AAAA,MACb,UAAU;AAAA,MACV,aAAa;AAAA,MACb,aAAa;AAAA,MACb,UAAU,CAAC;AAAA,MACX,WAAW;AAEP,YAAI,KAAK,SAAU,WAAW,GAAG;AAC7B,gBAAM,IAAI,MAAM,uCAAuC;AAAA,QAC3D;AAEA,YAAI,KAAK,aAAa,MAAM;AAExB,cAAI,KAAK,WAAW,GAAG;AACnB,kBAAM,IAAI,MAAM,iEAAiE;AAAA,UACrF;AAAA,QACJ,WAAW,KAAK,gBAAgB,QAAQ,KAAK,gBAAgB,MAAM;AAE/D,cAAI,KAAK,cAAc,KAAK,KAAK,cAAc,GAAG;AAC9C,kBAAM,IAAI,MAAM,gFAAgF;AAAA,UACpG;AAGA,cAAI,KAAK,cAAc,KAAK,aAAa;AACrC,kBAAM,IAAI;AAAA,cACN;AAAA,YACJ;AAAA,UACJ;AAAA,QACJ,OAAO;AAAA,QAEP;AAAA,MACJ;AAAA,MACA,mBAAmB,uBAAuB,iBAAiB;AACvD,eAAO,IAAI;AAAA,UACP,KAAK;AAAA,UACL,KAAK;AAAA,UACL,KAAK;AAAA,UACL,KAAK;AAAA,UACL,KAAK,SAAU,GAAG,mBAAmB,uBAAuB,gBAAgB,MAAM,CAAC;AAAA,QACvF;AAAA,MACJ;AAAA,IACJ;AAAA,IACA,MAAM,OAAyB;AAAA,MAC3B,MAAM;AAAA,MACN,YAAY,CAAC;AAAA,MACb,UAAU,CAAC;AAAA,MACX,WAAW;AAEP,YAAI,KAAK,SAAU,WAAW,GAAG;AAC7B,gBAAM,IAAI,MAAM,sCAAsC;AAAA,QAC1D;AAAA,MACJ;AAAA,MACA,mBAAmB,uBAAuB,iBAAiB;AACvD,eAAO,IAAI;AAAA,UACP,KAAK;AAAA,UACL,KAAK,SAAU,GAAG,mBAAmB,uBAAuB,gBAAgB,MAAM,CAAC;AAAA,QACvF;AAAA,MACJ;AAAA,IACJ;AAAA,IACA,SAAS,OAAyB;AAAA,MAC9B,MAAM;AAAA,MACN,YAAY,CAAC;AAAA,MACb,UAAU,CAAC;AAAA,MACX,WAAW;AAEP,YAAI,KAAK,SAAU,WAAW,GAAG;AAC7B,gBAAM,IAAI,MAAM,yCAAyC;AAAA,QAC7D;AAAA,MACJ;AAAA,MACA,mBAAmB,uBAAuB,iBAAiB;AACvD,eAAO,IAAI;AAAA,UACP,KAAK;AAAA,UACL,KAAK,SAAU,GAAG,mBAAmB,uBAAuB,gBAAgB,MAAM,CAAC;AAAA,QACvF;AAAA,MACJ;AAAA,IACJ;AAAA,IACA,MAAM,OAAyB;AAAA,MAC3B,MAAM;AAAA,MACN,YAAY,CAAC;AAAA,MACb,UAAU,CAAC;AAAA,MACX,WAAW;AAEP,YAAI,KAAK,SAAU,WAAW,GAAG;AAC7B,gBAAM,IAAI,MAAM,sCAAsC;AAAA,QAC1D;AAAA,MACJ;AAAA,MACA,mBAAmB,uBAAuB,iBAAiB;AACvD,eAAO,IAAI;AAAA,UACP,KAAK;AAAA,UACL,KAAK,SAAU,GAAG,mBAAmB,uBAAuB,gBAAgB,MAAM,CAAC;AAAA,QACvF;AAAA,MACJ;AAAA,IACJ;AAAA,IACA,MAAM,OAAoB;AAAA,MACtB,MAAM;AAAA,MACN,YAAY,CAAC;AAAA,MACb,UAAU;AAAA,MACV,aAAa;AAAA,MACb,aAAa;AAAA,MACb,WAAW;AACP,YAAI,KAAK,aAAa,MAAM;AAExB,cAAI,KAAK,WAAW,GAAG;AACnB,kBAAM,IAAI,MAAM,2CAA2C;AAAA,UAC/D;AAAA,QACJ,WAAW,KAAK,gBAAgB,QAAQ,KAAK,gBAAgB,MAAM;AAE/D,cAAI,KAAK,cAAc,KAAK,KAAK,cAAc,GAAG;AAC9C,kBAAM,IAAI,MAAM,+DAA+D;AAAA,UACnF;AAGA,cAAI,KAAK,cAAc,KAAK,aAAa;AACrC,kBAAM,IAAI,MAAM,gFAAgF;AAAA,UACpG;AAAA,QACJ,OAAO;AAAA,QAEP;AAAA,MACJ;AAAA,MACA,qBAAqB;AACjB,eAAO,IAAI,KAAK,KAAK,YAAY,KAAK,UAAU,KAAK,aAAa,KAAK,WAAW;AAAA,MACtF;AAAA,IACJ;AAAA,IACA,QAAQ,OAAsB;AAAA,MAC1B,MAAM;AAAA,MACN,YAAY,CAAC;AAAA,MACb,YAAY;AAAA,MACZ,iBAAiB,CAAC;AAAA,MAClB,WAAW;AAAA,MAAC;AAAA,MACZ,qBAAqB;AACjB,eAAO,IAAI,OAAO,KAAK,YAAY,KAAK,YAAa,KAAK,eAAgB;AAAA,MAC9E;AAAA,IACJ;AAAA,IACA,WAAW,OAAyB;AAAA,MAChC,MAAM;AAAA,MACN,YAAY,CAAC;AAAA,MACb,eAAe;AAAA,MACf,oBAAoB,CAAC;AAAA,MACrB,WAAW;AAAA,MAAC;AAAA,MACZ,qBAAqB;AACjB,eAAO,IAAI,UAAU,KAAK,YAAY,KAAK,eAAgB,KAAK,kBAAmB;AAAA,MACvF;AAAA,IACJ;AAAA,EACJ;AASe,WAAR,kBAAmC,YAAmC;AAEzE,UAAM,EAAE,cAAc,oBAAoB,IAAIC,0BAAyB,UAAU;AAGjF,UAAM,SAASC,2BAA0B,mBAAmB;AAG5D,QAAI,OAAO,SAAS,GAAG;AACnB,YAAM,IAAI,MAAM,qBAAqB;AAAA,IACzC;AAGA,QAAI,OAAO,OAAO,CAAC,UAAU,UAAU,GAAG,EAAE,WAAW,OAAO,OAAO,CAAC,UAAU,UAAU,GAAG,EAAE,QAAQ;AACnG,YAAM,IAAI,MAAM,0BAA0B;AAAA,IAC9C;AAGA,UAAM,QAA6C,CAAC,CAAC,CAAC;AACtD,UAAM,YAAY,MAAM;AAGxB,WAAO,OAAO,QAAQ;AAElB,YAAM,QAAQ,OAAO,MAAM;AAE3B,YAAM,eAAe,MAAM,MAAM,SAAS;AAG1C,cAAQ,MAAO,YAAY,GAAG;AAAA,QAC1B,KAAK,QAAQ;AAET,gBAAM,OAAO,iBAAiB,KAAK;AAGnC,oBAAU,KAAK,IAAI;AAGnB,cAAI,OAAO,OAAO,KAAK;AACnB,kBAAM,gBAAgB,aAAa,QAAQ,YAAY;AAGvD,gBAAI,cAAc,WAAW,KAAK,cAAc,GAAG,SAAS,cAAc;AAEtE,mBAAK,OAAO,cAAc,GAAG;AAAA,YACjC,OAAO;AACH,oBAAM,IAAI,MAAM,oCAAoC;AAAA,YACxD;AAAA,UACJ;AAGA,eAAK,aAAa,cAAc,QAAQ,YAAY;AAEpD,UAAAC,aAAY,QAAQ,GAAG;AAGvB,gBAAM,KAAK,KAAK,QAAS;AACzB;AAAA,QACJ;AAAA,QAEA,KAAK,UAAU;AAEX,gBAAM,OAAO,iBAAiB,OAAO;AAGrC,uBAAa,KAAK,IAAI;AAGtB,cAAI,OAAO,OAAO,KAAK;AACnB,kBAAM,IAAI,MAAM,sCAAsC;AAAA,UAC1D;AAGA,gBAAM,kBAAkB,aAAa,QAAQ,YAAY;AAGzD,cAAI,gBAAgB,WAAW,KAAK,gBAAgB,GAAG,SAAS,cAAc;AAE1E,iBAAK,aAAa,gBAAgB,GAAG;AAAA,UACzC,OAAO;AACH,kBAAM,IAAI,MAAM,sCAAsC;AAAA,UAC1D;AACA;AAAA,QACJ;AAAA,QAEA,KAAK,YAAY;AAEb,gBAAM,OAAO,iBAAiB,SAAS;AAGvC,uBAAa,KAAK,IAAI;AAGtB,eAAK,aAAa,cAAc,QAAQ,YAAY;AAEpD,UAAAA,aAAY,QAAQ,GAAG;AAGvB,gBAAM,KAAK,KAAK,QAAS;AACzB;AAAA,QACJ;AAAA,QAEA,KAAK,YAAY;AAEb,gBAAM,OAAO,iBAAiB,SAAS;AAGvC,uBAAa,KAAK,IAAI;AAGtB,eAAK,aAAa,cAAc,QAAQ,YAAY;AAEpD,UAAAA,aAAY,QAAQ,GAAG;AAGvB,gBAAM,KAAK,KAAK,QAAS;AACzB;AAAA,QACJ;AAAA,QAEA,KAAK,YAAY;AAEb,gBAAM,OAAO,iBAAiB,SAAS;AAGvC,uBAAa,KAAK,IAAI;AAGtB,eAAK,aAAa,cAAc,QAAQ,YAAY;AAEpD,UAAAA,aAAY,QAAQ,GAAG;AAGvB,gBAAM,KAAK,KAAK,QAAS;AACzB;AAAA,QACJ;AAAA,QAEA,KAAK,SAAS;AAEV,gBAAM,OAAO,iBAAiB,MAAM;AAGpC,uBAAa,KAAK,IAAI;AAGtB,cAAI,OAAO,OAAO,KAAK;AAEnB,iBAAK,UAAU;AAAA,cACX;AAAA,cACA;AAAA,cACA,CAAC,QAAQ,IAAI,SAAS,YAAY,CAAC,CAAC,IAAI;AAAA,cACxC;AAAA,YACJ,EAAE,IAAI,CAAC,aAAa,SAAS,KAAe;AAAA,UAChD;AAGA,eAAK,aAAa,cAAc,QAAQ,YAAY;AAEpD,UAAAA,aAAY,QAAQ,GAAG;AAGvB,gBAAM,KAAK,KAAK,QAAS;AACzB;AAAA,QACJ;AAAA,QAEA,KAAK,aAAa;AAEd,gBAAM,OAAO,iBAAiB,UAAU;AAGxC,uBAAa,KAAK,IAAI;AAGtB,cAAI,OAAO,OAAO,KAAK;AACnB,kBAAM,IAAI,MAAM,6CAA6C;AAAA,UACjE;AAGA,gBAAM,qBAAqB,aAAa,QAAQ,YAAY;AAG5D,cAAI,mBAAmB,UAAU,mBAAmB,GAAG,SAAS,cAAc;AAE1E,iBAAK,gBAAgB,mBAAmB,MAAM,EAAG;AAAA,UACrD,OAAO;AACH,kBAAM,IAAI,MAAM,6CAA6C;AAAA,UACjE;AAGA,6BACK,OAAO,CAAC,QAAQ,IAAI,SAAS,YAAY,EACzC,QAAQ,CAAC,QAAQ;AACd,kBAAM,IAAI;AAAA,cACN,4CACI,IAAI,QACJ;AAAA,YACR;AAAA,UACJ,CAAC;AAGL,eAAK,qBAAqB;AAG1B,eAAK,aAAa,cAAc,QAAQ,YAAY;AACpD;AAAA,QACJ;AAAA,QAEA,KAAK,QAAQ;AAET,gBAAM,OAAO,iBAAiB,KAAK;AAGnC,uBAAa,KAAK,IAAI;AAGtB,eAAK,aAAa,cAAc,QAAQ,YAAY;AAEpD,UAAAA,aAAY,QAAQ,GAAG;AAGvB,gBAAM,KAAK,KAAK,QAAS;AACzB;AAAA,QACJ;AAAA,QAEA,KAAK,WAAW;AAEZ,gBAAM,OAAO,iBAAiB,QAAQ;AAGtC,uBAAa,KAAK,IAAI;AAGtB,eAAK,aAAa,cAAc,QAAQ,YAAY;AAEpD,UAAAA,aAAY,QAAQ,GAAG;AAGvB,gBAAM,KAAK,KAAK,QAAS;AACzB;AAAA,QACJ;AAAA,QAEA,KAAK,QAAQ;AAET,gBAAM,OAAO,iBAAiB,KAAK;AAGnC,uBAAa,KAAK,IAAI;AAGtB,eAAK,aAAa,cAAc,QAAQ,YAAY;AAEpD,UAAAA,aAAY,QAAQ,GAAG;AAGvB,gBAAM,KAAK,KAAK,QAAS;AACzB;AAAA,QACJ;AAAA,QAEA,KAAK,QAAQ;AAET,gBAAM,OAAO,iBAAiB,KAAK;AAGnC,uBAAa,KAAK,IAAI;AAMtB,cAAI,OAAO,OAAO,KAAK;AAEnB,kBAAM,gBAAgB;AAAA,cAClB;AAAA,cACA;AAAA,cACA,CAAC,QAAQ,IAAI,SAAS,YAAY,CAAC,CAAC,IAAI;AAAA,cACxC;AAAA,YACJ,EAAE,IAAI,CAAC,aAAa,SAAS,KAAK;AAMlC,gBAAI,cAAc,WAAW,GAAG;AAE5B,mBAAK,WAAW,cAAc;AAAA,YAClC,WAAW,cAAc,WAAW,GAAG;AAEnC,mBAAK,cAAc,cAAc;AACjC,mBAAK,cAAc,cAAc;AAAA,YACrC,WAAW,cAAc,SAAS,GAAG;AAEjC,oBAAM,IAAI,MAAM,wDAAwD;AAAA,YAC5E;AAAA,UACJ;AAGA,eAAK,aAAa,cAAc,QAAQ,YAAY;AACpD;AAAA,QACJ;AAAA,QAEA,KAAK,UAAU;AAEX,gBAAM,OAAO,iBAAiB,OAAO;AAGrC,uBAAa,KAAK,IAAI;AAMtB,cAAI,OAAO,OAAO,KAAK;AAEnB,kBAAM,gBAAgB;AAAA,cAClB;AAAA,cACA;AAAA,cACA,CAAC,QAAQ,IAAI,SAAS,YAAY,CAAC,CAAC,IAAI;AAAA,cACxC;AAAA,YACJ,EAAE,IAAI,CAAC,aAAa,SAAS,KAAK;AAGlC,gBAAI,cAAc,WAAW,GAAG;AAE5B,mBAAK,aAAa,cAAc;AAAA,YACpC,WAAW,cAAc,WAAW,GAAG;AAEnC,mBAAK,gBAAgB,cAAc;AACnC,mBAAK,gBAAgB,cAAc;AAAA,YACvC,OAAO;AAEH,oBAAM,IAAI,MAAM,iEAAiE;AAAA,YACrF;AAAA,UACJ;AAGA,eAAK,aAAa,cAAc,QAAQ,YAAY;AAEpD,UAAAA,aAAY,QAAQ,GAAG;AAGvB,gBAAM,KAAK,KAAK,QAAS;AACzB;AAAA,QACJ;AAAA,QAEA,KAAK,SAAS;AAEV,gBAAM,OAAO,iBAAiB,MAAM;AAGpC,uBAAa,KAAK,IAAI;AAMtB,cAAI,OAAO,OAAO,KAAK;AAEnB,kBAAM,gBAAgB;AAAA,cAClB;AAAA,cACA;AAAA,cACA,CAAC,QAAQ,IAAI,SAAS,YAAY,CAAC,CAAC,IAAI;AAAA,cACxC;AAAA,YACJ,EAAE,IAAI,CAAC,aAAa,SAAS,KAAK;AAGlC,gBAAI,cAAc,WAAW,GAAG;AAE5B,mBAAK,WAAW,cAAc;AAAA,YAClC,WAAW,cAAc,WAAW,GAAG;AAEnC,mBAAK,cAAc,cAAc;AACjC,mBAAK,cAAc,cAAc;AAAA,YACrC,OAAO;AAEH,oBAAM,IAAI,MAAM,8DAA8D;AAAA,YAClF;AAAA,UACJ;AAGA,eAAK,aAAa,cAAc,QAAQ,YAAY;AAEpD,UAAAA,aAAY,QAAQ,GAAG;AAGvB,gBAAM,KAAK,KAAK,QAAS;AACzB;AAAA,QACJ;AAAA,QAEA,KAAK,UAAU;AAEX,gBAAM,OAAO,iBAAiB,OAAO;AAGrC,uBAAa,KAAK,IAAI;AAGtB,cAAI,OAAO,OAAO,KAAK;AACnB,kBAAM,IAAI,MAAM,0CAA0C;AAAA,UAC9D;AAGA,gBAAM,kBAAkB,aAAa,QAAQ,YAAY;AAGzD,cAAI,gBAAgB,UAAU,gBAAgB,GAAG,SAAS,cAAc;AAEpE,iBAAK,aAAa,gBAAgB,MAAM,EAAG;AAAA,UAC/C,OAAO;AACH,kBAAM,IAAI,MAAM,0CAA0C;AAAA,UAC9D;AAGA,0BACK,OAAO,CAAC,QAAQ,IAAI,SAAS,YAAY,EACzC,QAAQ,CAAC,QAAQ;AACd,kBAAM,IAAI;AAAA,cACN,yCACI,IAAI,QACJ;AAAA,YACR;AAAA,UACJ,CAAC;AAGL,eAAK,kBAAkB;AAGvB,eAAK,aAAa,cAAc,QAAQ,YAAY;AACpD;AAAA,QACJ;AAAA,QAEA,KAAK,KAAK;AAEN,gBAAM,IAAI;AACV;AAAA,QACJ;AAAA,QAEA,SAAS;AACL,gBAAM,IAAI,MAAM,qBAAqB,QAAQ;AAAA,QACjD;AAAA,MACJ;AAAA,IACJ;AAGA,UAAM,kBAAkB,CAAC,MAAmB,UAAwB;AAEhE,WAAK,SAAS,KAAK;AAGnB,OAAC,KAAK,YAAY,CAAC,GAAG,QAAQ,CAAC,UAAU,gBAAgB,OAAO,QAAQ,CAAC,CAAC;AAAA,IAC9E;AAGA;AAAA,MACI;AAAA,QACI,UAAU,MAAM;AAAA,QAChB,WAA4C;AAExC,cAAI,KAAK,SAAS,WAAW,GAAG;AAC5B,kBAAM,IAAI,MAAM,yCAAyC;AAAA,UAC7D;AAGA,qBAAW,uBAAuB,KAAK,UAAU;AAC7C,gBAAI,oBAAoB,SAAS,QAAQ;AACrC,oBAAM,IAAI,MAAM,0CAA0C;AAAA,YAC9D;AAAA,UACJ;AAGA,cAAI,KAAK,SAAS,OAAO,CAAC,wBAAwB,oBAAoB,SAAS,IAAI,EAAE,WAAW,GAAG;AAC/F,kBAAM,IAAI,MAAM,6EAA6E;AAAA,UACjG;AAGA,gBAAM,gBAA0B,CAAC;AACjC,qBAAW,uBAAuB,KAAK,UAAU;AAC7C,gBAAI,cAAc,QAAQ,oBAAoB,IAAK,MAAM,IAAI;AACzD,oBAAM,IAAI,MAAM,kDAAkD,oBAAoB,OAAO;AAAA,YACjG,OAAO;AACH,4BAAc,KAAK,oBAAoB,IAAK;AAAA,YAChD;AAAA,UACJ;AAAA,QACJ;AAAA,MACJ;AAAA,MACA;AAAA,IACJ;AAGA,WAAO,MAAM;AAAA,EACjB;AAQA,WAASA,aAAY,QAAkB,UAA6B;AAEhE,UAAM,SAAS,OAAO,MAAM;AAG5B,QAAI,WAAW,QAAW;AACtB,YAAM,IAAI,MAAM,8BAA8B;AAAA,IAClD;AAGA,QAAI,aAAa,QAAW;AAExB,UAAI,0BAA2B,CAAC,EAC3B,OAAO,QAAQ,EACf,KAAK,CAAC,SAAS,OAAO,YAAY,MAAM,KAAK,YAAY,CAAC;AAG/D,UAAI,CAAC,yBAAyB;AAC1B,cAAM,oBAAqB,CAAC,EACvB,OAAO,QAAQ,EACf,IAAI,CAAC,SAAS,MAAM,OAAO,GAAG,EAC9B,KAAK,MAAM;AAEhB,cAAM,IAAI,MAAM,qCAAqC,+BAA+B,SAAS;AAAA,MACjG;AAAA,IACJ;AAGA,WAAO;AAAA,EACX;AAYA,WAAS,aACL,QACA,4BACA,mBACA,yBACF;AAGE,UAAM,SAASA,aAAY,QAAQ,CAAC,KAAK,GAAG,CAAC,MAAM,MAAM,MAAM;AAE/D,UAAM,qBAA+B,CAAC;AACtC,UAAM,eAA8B,CAAC;AAGrC,WAAO,OAAO,UAAU,OAAO,OAAO,QAAQ;AAE1C,yBAAmB,KAAK,OAAO,MAAM,CAAE;AAAA,IAC3C;AAGA,uBAAmB,QAAQ,CAAC,OAAO,UAAU;AAEzC,YAAM,wBAAwB,EAAE,QAAQ;AAGxC,UAAI,uBAAuB;AAEvB,cAAM,qBAAqBC,uBAAsB,OAAQ,0BAA0B;AAGnF,YAAI,qBAAqB,CAAC,kBAAkB,kBAAkB,GAAG;AAC7D,gBAAM,IAAI,MAAM,uBAAuB;AAAA,QAC3C;AAGA,qBAAa,KAAK,kBAAkB;AAAA,MACxC,OAAO;AAEH,YAAI,UAAU,KAAK;AACf,gBAAM,IAAI,MAAM,uDAAuD,QAAQ;AAAA,QACnF;AAAA,MACJ;AAAA,IACJ,CAAC;AAGD,IAAAD,aAAY,QAAQ,MAAM;AAG1B,WAAO;AAAA,EACX;AAQA,WAASC,uBAAsB,OAAe,4BAA6D;AAEvG,QAAI,UAAU,QAAQ;AAClB,aAAO;AAAA,QACH,OAAO;AAAA,QACP,MAAM;AAAA,MACV;AAAA,IACJ;AAGA,QAAI,UAAU,UAAU,UAAU,SAAS;AACvC,aAAO;AAAA,QACH,OAAO,UAAU;AAAA,QACjB,MAAM;AAAA,MACV;AAAA,IACJ;AAKA,QAAI,CAAC,MAAM,KAAY,GAAG;AACtB,aAAO;AAAA,QACH,OAAO,WAAW,KAAK;AAAA,QACvB,WAAW,WAAW,KAAK,MAAM,SAAS,OAAO,EAAE;AAAA,QACnD,MAAM;AAAA,MACV;AAAA,IACJ;AAGA,QAAI,MAAM,MAAM,YAAY,GAAG;AAC3B,aAAO;AAAA,QACH,OAAO,2BAA2B,OAAO,QAAQ,OAAO,GAAG;AAAA,QAC3D,MAAM;AAAA,MACV;AAAA,IACJ;AAGA,WAAO;AAAA,MACH,OAAO;AAAA,MACP,MAAM;AAAA,IACV;AAAA,EACJ;AAQA,WAAS,cAAc,QAAkB,4BAAgD;AAErF,UAAM,aAA0B,CAAC;AAGjC,UAAM,kBAA4B,CAAC;AAGnC,QAAI,mBAAmB,oBAAoB,OAAO,MAAM,IAAI,YAAY;AAGxE,WAAO,kBAAkB;AAErB,UAAI,gBAAgB,QAAQ,OAAO,GAAG,YAAY,CAAC,MAAM,IAAI;AACzD,cAAM,IAAI,MAAM,wBAAwB,OAAO,GAAG,YAAY,mBAAmB;AAAA,MACrF;AAGA,sBAAgB,KAAK,OAAO,MAAM,EAAG,YAAY,CAAC;AAGlD,YAAM,qBAAqB,aAAa,QAAQ,0BAA0B;AAG1E,UAAI,mBAAmB,WAAW,KAAK,mBAAmB,GAAG,SAAS,cAAc;AAChF,cAAM,IAAI,MAAM,gEAAgE;AAAA,MACpF;AAGA,YAAM,wBAAwB,mBAAmB,MAAM;AAGvD,yBACK,OAAO,CAAC,QAAQ,IAAI,SAAS,YAAY,EACzC,QAAQ,CAAC,QAAQ;AACd,cAAM,IAAI;AAAA,UACN,uCAAuC,IAAI,QAAQ;AAAA,QACvD;AAAA,MACJ,CAAC;AAGL,iBAAW,KAAK,iBAAiB,sBAAsB,OAAO,kBAAkB,CAAC;AAGjF,yBAAmB,oBAAoB,OAAO,MAAM,IAAI,YAAY;AAAA,IACxE;AAEA,WAAO;AAAA,EACX;AAOA,WAASH,0BAAyB,YAGhC;AAEE,UAAM,eAAmC,CAAC;AAG1C,UAAM,sBAAsB,WAAW,QAAQ,sBAAsB,CAAC,UAAU;AAC5E,UAAI,gBAAgB,MAAM,UAAU,GAAG,MAAM,SAAS,CAAC;AACvD,UAAI,cAAc,OAAO,KAAK,YAAY,EAAE,KAAK,CAAC,QAAQ,aAAa,SAAS,aAAa;AAG7F,UAAI,CAAC,aAAa;AACd,sBAAc,KAAK,OAAO,KAAK,YAAY,EAAE;AAC7C,qBAAa,eAAe;AAAA,MAChC;AAEA,aAAO;AAAA,IACX,CAAC;AAED,WAAO,EAAE,cAAc,oBAAoB;AAAA,EAC/C;AAOA,WAASC,2BAA0B,YAA8B;AAE7D,iBAAa,WAAW,QAAQ,OAAO,KAAK;AAC5C,iBAAa,WAAW,QAAQ,OAAO,KAAK;AAC5C,iBAAa,WAAW,QAAQ,OAAO,KAAK;AAC5C,iBAAa,WAAW,QAAQ,OAAO,KAAK;AAC5C,iBAAa,WAAW,QAAQ,OAAO,KAAK;AAC5C,iBAAa,WAAW,QAAQ,OAAO,KAAK;AAC5C,iBAAa,WAAW,QAAQ,OAAO,KAAK;AAG5C,WAAO,WAAW,QAAQ,QAAQ,GAAG,EAAE,KAAK,EAAE,MAAM,GAAG;AAAA,EAC3D;;;ACrqCO,MAAM,gBAAN,MAAoB;AAAA,IAYvB,YAAY,YAA4B,OAAsB,UAAgC,CAAC,GAAG;AAA1D;AAAsB;AAE1D,UAAI,OAAO,eAAe,UAAU;AAChC,cAAM,IAAI,MAAM,sCAAsC;AAAA,MAC1D;AAGA,UAAI,OAAO,UAAU,YAAY,UAAU,MAAM;AAC7C,cAAM,IAAI,MAAM,wCAAwC;AAAA,MAC5D;AAGA,WAAK,WAAW,cAAc,gBAAgB,UAAU;AAAA,IAC5D;AAAA,IArBgB;AAAA,IA2BhB,YAAY;AACR,aAAO,KAAK,SAAS,SAAS;AAAA,IAClC;AAAA,IAMA,WAAW;AACP,aAAO,KAAK,SAAS,SAAS;AAAA,IAClC;AAAA,IAUA,OAAO;AAEH,UAAI,KAAK,SAAS,SAAS,iDAAyB,KAAK,SAAS,SAAS,yCAAoB;AAC3F,aAAK,SAAS,MAAM;AAAA,MACxB;AAEA,UAAI;AACA,aAAK,SAAS,OAAO,KAAK,OAAO,KAAK,OAAO;AAAA,MACjD,SAAS,WAAP;AACE,cAAM,IAAI,MAAM,wBAAyB,UAAoB,SAAS;AAAA,MAC1E;AAAA,IACJ;AAAA,IAKA,QAAQ;AACJ,WAAK,SAAS,MAAM;AAAA,IACxB;AAAA,IAMA,0BAA+C;AAE3C,YAAM,qBAA0C,CAAC;AAOjD,YAAM,cAAc,CAAC,MAAY,cAA6B;AAE1D,cAAM,SAAS,KACV,cAAc,EACd,OAAO,CAAC,cAAc,UAAU,QAAQ,CAAC,EACzC,IAAI,CAAC,cAAc,UAAU,WAAW,CAAC;AAC9C,cAAM,YAAY,KACb,cAAc,EACd,OAAO,CAAC,cAAc,CAAC,UAAU,QAAQ,CAAC,EAC1C,IAAI,CAAC,cAAc,UAAU,WAAW,CAAC;AAG9C,2BAAmB,KAAK;AAAA,UACpB,IAAI,KAAK,OAAO;AAAA,UAChB,MAAM,KAAK,QAAQ;AAAA,UACnB,SAAS,KAAK,QAAQ;AAAA,UACtB,OAAO,KAAK,SAAS;AAAA,UACrB;AAAA,UACA;AAAA,UACA,MAAM,KAAK,aAAa;AAAA,UACxB,UAAU;AAAA,QACd,CAAC;AAGD,YAAI,CAAC,KAAK,WAAW,GAAG;AACpB,UAAC,KACI,YAAY,EACZ,QAAQ,CAAC,UAAU,YAAY,OAAQ,KAA+B,OAAO,CAAC,CAAC;AAAA,QACxF;AAAA,MACJ;AAGA,kBAAY,KAAK,UAAU,IAAI;AAE/B,aAAO;AAAA,IACX;AAAA,IAOA,OAAO,SAAS,MAAc,OAAgC;AAC1D,UAAI,OAAO,UAAU,YAAY;AAE7B,eAAO,QAAQ,MAAM,KAAK;AAAA,MAC9B,WAAW,OAAO,UAAU,UAAU;AAElC,YAAI;AAEJ,YAAI;AAEA,yBAAe,kBAAkB,KAAK;AAAA,QAC1C,SAAS,WAAP;AAEE,gBAAM,IAAI,MAAM,iCAAkC,UAAoB,SAAS;AAAA,QACnF;AAGA,YAAI,aAAa,UAAU,KAAK,aAAa,GAAG,SAAS,MAAM;AAC3D,gBAAM,IAAI,MAAM,mEAAmE;AAAA,QACvF;AAEA,eAAO,WAAW,MAAM,aAAa,EAAE;AAAA,MAC3C,OAAO;AACH,cAAM,IAAI,MAAM,0DAA0D;AAAA,MAC9E;AAAA,IACJ;AAAA,IAMA,OAAO,WAAW,MAAoB;AAClC,aAAO,OAAO,IAAI;AAAA,IACtB;AAAA,IAKA,OAAO,gBAAsB;AACzB,aAAO,MAAM;AAAA,IACjB;AAAA,IAOA,OAAe,gBAAgB,YAA0B;AAErD,UAAI;AAAA,MAEJ,SAAS,WAAP;AACE,gBAAQ,IAAI,SAAS;AAAA,MACzB;AAEA,UAAI;AAEA,cAAM,eAAe,kBAAkB,UAAU;AAGjD,cAAM,kBAAkB,OAAO,UAAU;AAGzC,cAAM,cAAuD,CAAC;AAC9D,mBAAW,eAAe,cAAc;AACpC,sBAAY,YAAY,SAAS,OAAO,kBAAkB,YAAY,QAAS;AAAA,QACnF;AAGA,cAAM,WAAiB,YAAY,iBAAiB;AAAA,UAEhD,CAAC,SAA+B,YAAY,QAAQ,YAAY,QAAQ,OAAO,WAAW,IAAI;AAAA,UAC9F,CAAC;AAAA,QACL;AAGA,sBAAc,yBAAyB,QAAQ;AAG/C,eAAO;AAAA,MACX,SAAS,WAAP;AAEE,cAAM,IAAI,MAAM,uBAAwB,UAAoB,SAAS;AAAA,MACzE;AAAA,IACJ;AAAA,IAMA,OAAe,yBAAyB,UAAgB;AACpD,YAAM,YAAsB,CAAC;AAE7B,YAAM,gBAAgB,CAAC,MAAc,SAAe;AAEhD,eAAO,KAAK,OAAO,IAAI;AAGvB,YAAI,KAAK,WAAW,GAAG;AACnB,oBAAU,KAAK,IAAI;AAAA,QACvB,OAAO;AACH,UAAC,KAA+B,YAAY,EAAE,QAAQ,CAAC,UAAU,cAAc,MAAM,KAAK,CAAC;AAAA,QAC/F;AAAA,MACJ;AAGA,oBAAc,CAAC,GAAG,QAAQ;AAE1B,gBAAU,QAAQ,CAAC,SAAS;AAExB,iBAAS,QAAQ,GAAG,QAAQ,KAAK,QAAQ,SAAS;AAE9C,gBAAM,cAAc,KAAK;AAGzB,cAAI,YAAY,aAAa,GAAG;AAC5B;AAAA,UACJ;AAGA,gBAAM,YAAY,IAAI;AAAA,YAClB,KACK,MAAM,GAAG,QAAQ,CAAC,EAClB,IAAmB,CAAC,UAAU,EAAE,MAAM,QAAQ,KAAK,mBAAmB,EAAE,EAAE,EAC1E,OAAO,CAAC,YAAY,QAAQ,OAAO,SAAS,CAAC;AAAA,UACtD;AAGA,sBAAY,aAAa,SAAS;AAAA,QACtC;AAAA,MACJ,CAAC;AAAA,IACL;AAAA,EACJ;", + "sourcesContent": ["\"use strict\";\r\nObject.defineProperty(exports, \"__esModule\", { value: true });\r\nexports.Participant = void 0;\r\n/**\r\n * A participant that holds a number of tickets.\r\n */\r\nvar Participant = /** @class */ (function () {\r\n /**\r\n * Creates an instance of the Participant class.\r\n * @param participant The actual participant.\r\n * @param tickets The number of tickets held by the participant.\r\n */\r\n function Participant(participant, tickets) {\r\n if (tickets === void 0) { tickets = 1; }\r\n this._participant = participant;\r\n this._tickets = tickets;\r\n }\r\n Object.defineProperty(Participant.prototype, \"participant\", {\r\n /** Gets the actual participant. */\r\n get: function () {\r\n return this._participant;\r\n },\r\n enumerable: false,\r\n configurable: true\r\n });\r\n Object.defineProperty(Participant.prototype, \"tickets\", {\r\n /** Gets or sets the number of tickets held by the participant. */\r\n get: function () {\r\n return this._tickets;\r\n },\r\n set: function (value) {\r\n this._tickets = value;\r\n },\r\n enumerable: false,\r\n configurable: true\r\n });\r\n return Participant;\r\n}());\r\nexports.Participant = Participant;\r\n", "\"use strict\";\r\nObject.defineProperty(exports, \"__esModule\", { value: true });\r\nexports.isNaturalNumber = exports.isNullOrUndefined = void 0;\r\n/**\r\n * Gets whether the value provided is null or undefined.\r\n * @param value The value to check.\r\n * @returns Whether the value provided is null or undefined.\r\n */\r\nfunction isNullOrUndefined(value) {\r\n return value === null || value === undefined;\r\n}\r\nexports.isNullOrUndefined = isNullOrUndefined;\r\n/**\r\n * Gets whether the value provided is a natural number.\r\n * @param value The value to check.\r\n * @returns Whether the value provided is a natural number.\r\n */\r\nfunction isNaturalNumber(value) {\r\n return typeof value === \"number\" && value >= 1 && Math.floor(value) === value;\r\n}\r\nexports.isNaturalNumber = isNaturalNumber;\r\n", "\"use strict\";\r\nObject.defineProperty(exports, \"__esModule\", { value: true });\r\nexports.Lotto = void 0;\r\nvar Participant_1 = require(\"./Participant\");\r\nvar Utilities_1 = require(\"./Utilities\");\r\n/**\r\n * Represents a lotto consisting of a number of pickable ticket-holding participants.\r\n */\r\nvar Lotto = /** @class */ (function () {\r\n /**\r\n * Creates a new instance of Lotto.\r\n * @param customRandom The custom RNG to use in place of Math.random().\r\n */\r\n function Lotto(customRandom) {\r\n /** The array of participants that are holding tickets in the lotto. */\r\n this._participants = [];\r\n this._customRandom = customRandom;\r\n }\r\n /**\r\n * Adds a participant with the specified number of tickets, or adds to the participant ticket count if the participant already holds tickets.\r\n * @param participant The participant to add or to increase the ticket count for if they already hold tickets.\r\n * @param tickets The number of tickets, defaults to 1.\r\n * @returns The Lotto instance.\r\n */\r\n Lotto.prototype.add = function (participant, tickets) {\r\n if (tickets === void 0) { tickets = 1; }\r\n // Check that we have a valid ticket count.\r\n if (!(0, Utilities_1.isNaturalNumber)(tickets)) {\r\n throw new Error(\"tickets value must be a natural number\");\r\n }\r\n // Check whether this participant has already been added.\r\n var existingParticipant = this._participants.find(function (part) { return part.participant === participant; });\r\n if (existingParticipant) {\r\n // The participant has already been added to the lotto so just add to their ticket count.\r\n existingParticipant.tickets += tickets;\r\n }\r\n else {\r\n // The participant is not part of the lotto so we should add them.\r\n this._participants.push(new Participant_1.Participant(participant, tickets));\r\n }\r\n return this;\r\n };\r\n /**\r\n * Removes the specified number of tickets for the given participant from the draw, or all tickets if a ticket number is not defined.\r\n * @param participant The participant to remove tickets for.\r\n * @param tickets The number of tickets to remove, or undefined if all tickets are to be removed.\r\n * @returns The Lotto instance.\r\n */\r\n Lotto.prototype.remove = function (participant, tickets) {\r\n // Attempt to get the existing participant.\r\n var existingParticipant = this._participants.find(function (part) { return part.participant === participant; });\r\n // There is nothing to do if the specified participant isn't even part of the lotto.\r\n if (!existingParticipant) {\r\n return this;\r\n }\r\n // Check whether a tickets value was given.\r\n if (tickets !== undefined) {\r\n // Check that we have a valid ticket count.\r\n if (!(0, Utilities_1.isNaturalNumber)(tickets)) {\r\n throw new Error(\"tickets value must be a natural number\");\r\n }\r\n existingParticipant.tickets -= tickets;\r\n // If the participant no longer holds any tickets then they should be removed.\r\n if (existingParticipant.tickets < 1) {\r\n this._participants = this._participants.filter(function (part) { return part !== existingParticipant; });\r\n }\r\n }\r\n else {\r\n // We are removing all tickets for the participant so just remove them from the lotto.\r\n this._participants = this._participants.filter(function (part) { return part !== existingParticipant; });\r\n }\r\n return this;\r\n };\r\n /**\r\n * Draw a winning ticket and return the participant that holds the ticket.\r\n * @param options The draw options.\r\n * @returns The participant that holds the winning ticket.\r\n */\r\n Lotto.prototype.draw = function (options) {\r\n if (options === void 0) { options = {}; }\r\n // If we have no participants then just return null.\r\n if (this._participants.length === 0) {\r\n return null;\r\n }\r\n var redrawable = (0, Utilities_1.isNullOrUndefined)(options.redrawable) ? true : options.redrawable;\r\n var pickable = [];\r\n this._participants.forEach(function (_a) {\r\n var participant = _a.participant, tickets = _a.tickets;\r\n for (var ticketCount = 0; ticketCount < tickets; ticketCount++) {\r\n pickable.push(participant);\r\n }\r\n });\r\n var random;\r\n // We need a random floating-point number between 0 (inclusive) and 1 to scale up to pick our winner.\r\n // If a custom random function exists then we should use that or fall back to Math.random().\r\n if (this._customRandom) {\r\n // Call our custom random function to get a random floating-point number.\r\n random = this._customRandom();\r\n // Verify that the result of calling our custom random function is a number between 0 (inclusive) and 1.\r\n if (typeof random !== \"number\" || random < 0 || random >= 1) {\r\n throw new Error(\"the 'random' function provided did not return a number between 0 (inclusive) and 1\");\r\n }\r\n }\r\n else {\r\n // No custom random function was defined so just use good ol' Math.random().\r\n random = Math.random();\r\n }\r\n // Pick a winning participant.\r\n var winner = pickable[Math.floor(random * pickable.length)];\r\n // If the ticket isn't redrawable then we should remove a ticket from the winning participants ticket count.\r\n if (!redrawable) {\r\n this.remove(winner, 1);\r\n }\r\n // Return the winning participant.\r\n return winner;\r\n };\r\n /**\r\n * Draws multiple winning tickets and return an array of the participants that hold the winning tickets.\r\n * @param tickets The number of winning tickets to draw.\r\n * @param options The draw multiple options.\r\n * @returns An array of the participants that hold the winning tickets.\r\n */\r\n Lotto.prototype.drawMultiple = function (tickets, options) {\r\n if (options === void 0) { options = {}; }\r\n var uniqueResults = (0, Utilities_1.isNullOrUndefined)(options.unique) ? false : options.unique;\r\n // Handle cases where the user has asked for zero tickets (no idea why they would do this be we should trust them).\r\n if (tickets === 0) {\r\n return [];\r\n }\r\n // Now that we know out tickets value is not zero we should check that it is a valid natural number.\r\n if (!(0, Utilities_1.isNaturalNumber)(tickets)) {\r\n throw new Error(\"tickets value must be a natural number\");\r\n }\r\n var result = [];\r\n // Keep drawing tickets until we either reach the number of required tickets or we simply run out of tickets to draw.\r\n // We can run out of tickets to draw if 'options.redrawable' is explicity 'false' or we just had no participants when 'drawMultiple' was called.\r\n while (result.length < tickets && this._participants.length > 0) {\r\n result.push(this.draw(options));\r\n }\r\n // If the 'unique' draw option is set then we need to remove duplicates from the result list.\r\n if (uniqueResults) {\r\n // Create an array to store our unique results.\r\n var unique = [];\r\n // Iterate over all of our participants (with potential duplicates) and populate our array of unique values.\r\n for (var _i = 0, result_1 = result; _i < result_1.length; _i++) {\r\n var participant = result_1[_i];\r\n if (unique.indexOf(participant) === -1) {\r\n unique.push(participant);\r\n }\r\n }\r\n result = unique;\r\n }\r\n return result;\r\n };\r\n return Lotto;\r\n}());\r\nexports.Lotto = Lotto;\r\n", "\"use strict\";\r\nObject.defineProperty(exports, \"__esModule\", { value: true });\r\nexports.createLotto = void 0;\r\nvar Lotto_1 = require(\"./Lotto\");\r\n/**\r\n * A function that creates and returns a Lotto instance.\r\n * @param participantsOrOptions An array of initial participants or options relating to the creation of a Lotto instance.\r\n * @returns A new Lotto instance.\r\n */\r\nfunction createLotto(participantsOrOptions) {\r\n // If no initial participants or lotto options were provided as an argument then we can just return a new lotto instance now.\r\n if (!participantsOrOptions) {\r\n return new Lotto_1.Lotto();\r\n }\r\n // Check whether we were provided with an array of initial participants or a lotto options object.\r\n if (Array.isArray(participantsOrOptions)) {\r\n // We are dealing with a pre-defined array of participants.\r\n var participants = participantsOrOptions;\r\n var lotto_1 = new Lotto_1.Lotto();\r\n // If the lotto participants have been defined upfront then we will need to add them all to our lotto instance now.\r\n participants.forEach(function (_a) {\r\n var participant = _a[0], tokens = _a[1];\r\n return lotto_1.add(participant, tokens);\r\n });\r\n // Return the Lotto instance.\r\n return lotto_1;\r\n }\r\n else {\r\n // We are dealing with some lotto options.\r\n var random = participantsOrOptions.random, participants = participantsOrOptions.participants;\r\n // Create a Lotto instance passing the custom RNG function to use in place of Math.random() (which could be undefined).\r\n var lotto_2 = new Lotto_1.Lotto(random);\r\n // If the lotto participants have been defined upfront as part of the options then we will need to add them all to our lotto instance now.\r\n if (participants) {\r\n participants.forEach(function (_a) {\r\n var participant = _a[0], tokens = _a[1];\r\n return lotto_2.add(participant, tokens);\r\n });\r\n }\r\n // Return the Lotto instance.\r\n return lotto_2;\r\n }\r\n}\r\nexports.createLotto = createLotto;\r\n", "\"use strict\";\r\nObject.defineProperty(exports, \"__esModule\", { value: true });\r\nvar createLotto_1 = require(\"./createLotto\");\r\nexports.default = createLotto_1.createLotto;\r\n", "import State from \"./State\";\nimport { validateDefinition } from \"./BehaviourTreeDefinitionValidator\";\nimport { convertMDSLToJSON } from \"./mdsl/MDSLDefinitionParser\";\nimport { BehaviourTree, FlattenedTreeNode } from \"./BehaviourTree\";\n\nexport { BehaviourTree, State, convertMDSLToJSON, validateDefinition };\nexport type { FlattenedTreeNode };\n", "/**\n * Enumeration of node state types.\n */\nexport enum State {\n READY = \"mistreevous.ready\",\n RUNNING = \"mistreevous.running\",\n SUCCEEDED = \"mistreevous.succeeded\",\n FAILED = \"mistreevous.failed\"\n}\n\nexport { State as default };\n\nexport type CompleteState = State.SUCCEEDED | State.FAILED;\nexport type AnyState = State.READY | State.RUNNING | CompleteState;\n", "import {\n NodeDefinition,\n RootNodeDefinition,\n DecoratorNodeDefinition,\n CompositeNodeDefinition,\n AnyNode,\n BranchNodeDefinition\n} from \"./BehaviourTreeDefinition\";\n\n/**\n * A type guard function that returns true if the specified node satisfies the RootNodeDefinition type.\n * @param node The node.\n * @returns A value of true if the specified node satisfies the RootNodeDefinition type.\n */\nexport function isRootNode(node: NodeDefinition): node is RootNodeDefinition {\n return node.type === \"root\";\n}\n\n/**\n * A type guard function that returns true if the specified node satisfies the BranchNodeDefinition type.\n * @param node The node.\n * @returns A value of true if the specified node satisfies the BranchNodeDefinition type.\n */\nexport function isBranchNode(node: NodeDefinition): node is BranchNodeDefinition {\n return node.type === \"branch\";\n}\n\n/**\n * A type guard function that returns true if the specified node satisfies the NodeDefinition type.\n * @param node The node.\n * @returns A value of true if the specified node satisfies the NodeDefinition type.\n */\nexport function isLeafNode(node: NodeDefinition): node is NodeDefinition {\n return [\"branch\", \"action\", \"condition\", \"wait\"].includes(node.type);\n}\n\n/**\n * A type guard function that returns true if the specified node satisfies the DecoratorNodeDefinition type.\n * @param node The node.\n * @returns A value of true if the specified node satisfies the DecoratorNodeDefinition type.\n */\nexport function isDecoratorNode(node: NodeDefinition): node is DecoratorNodeDefinition {\n return [\"root\", \"repeat\", \"retry\", \"flip\", \"succeed\", \"fail\"].includes(node.type);\n}\n\n/**\n * A type guard function that returns true if the specified node satisfies the CompositeNodeDefinition type.\n * @param node The node.\n * @returns A value of true if the specified node satisfies the CompositeNodeDefinition type.\n */\nexport function isCompositeNode(node: NodeDefinition): node is CompositeNodeDefinition {\n return [\"sequence\", \"selector\", \"lotto\", \"parallel\"].includes(node.type);\n}\n\n/**\n * Flatten a node definition into an array of all of its nested node definitions.\n * @param nodeDefinition The node definition to flatten.\n * @returns An array of all of nested node definitions.\n */\nexport function flattenDefinition(nodeDefinition: AnyNode): AnyNode[] {\n const nodes: AnyNode[] = [];\n\n const processNode = (currentNodeDefinition: AnyNode) => {\n nodes.push(currentNodeDefinition);\n\n if (isCompositeNode(currentNodeDefinition)) {\n currentNodeDefinition.children.forEach(processNode);\n } else if (isDecoratorNode(currentNodeDefinition)) {\n processNode(currentNodeDefinition.child);\n }\n };\n\n processNode(nodeDefinition);\n\n return nodes;\n}\n\n/**\n * Determines whether the passed value is an integer.\n * @param value The value to check.\n * @returns Whether the passed value is an integer.\n */\nexport function isInteger(value: unknown): boolean {\n return typeof value === \"number\" && Math.floor(value) === value;\n}\n", "/**\n * A type defining an object that holds a reference to substitued string literals parsed from the definition.\n */\nexport type StringLiteralPlaceholders = { [key: string]: string };\n\n/**\n * Pop the next raw token from the specified array of tokens and throw an error if it wasn't the expected one.\n * @param tokens The array of tokens.\n * @param expected An optional string or array or items, one of which must match the next popped token.\n * @returns The popped token.\n */\nexport function popAndCheck(tokens: string[], expected?: string | string[]): string {\n // Get and remove the next token.\n const popped = tokens.shift();\n\n // We were expecting another token but there aren't any.\n if (popped === undefined) {\n throw new Error(\"unexpected end of definition\");\n }\n\n // Do we have an expected token/tokens array?\n if (expected != undefined) {\n // Get an array of expected values, if the popped token matches any then we are all good.\n const expectedValues = typeof expected === \"string\" ? [expected] : expected;\n\n // Check whether the popped token matches at least one of our expected items.\n var tokenMatchesExpectation = expectedValues.some((item) => popped.toUpperCase() === item.toUpperCase());\n\n // Throw an error if the popped token didn't match any of our expected items.\n if (!tokenMatchesExpectation) {\n const expectationString = expectedValues.map((item) => \"'\" + item + \"'\").join(\" or \");\n throw new Error(\"unexpected token found. Expected \" + expectationString + \" but got '\" + popped + \"'\");\n }\n }\n\n // Return the popped token.\n return popped;\n}\n\n/**\n * Swaps out any node/attribute argument string literals with placeholders.\n * @param definition The definition.\n * @returns An object containing a mapping of placeholders to original string values as well as the processed definition string.\n */\nexport function substituteStringLiterals(definition: string): {\n placeholders: StringLiteralPlaceholders;\n processedDefinition: string;\n} {\n // Create an object to hold the mapping of placeholders to original string values.\n const placeholders: StringLiteralPlaceholders = {};\n\n // Replace any string literals wrapped with double quotes in our definition with placeholders to be processed later.\n const processedDefinition = definition.replace(/\\\"(\\\\.|[^\"\\\\])*\\\"/g, (match) => {\n var strippedMatch = match.substring(1, match.length - 1);\n var placeholder = Object.keys(placeholders).find((key) => placeholders[key] === strippedMatch);\n\n // If we have no existing string literal match then create a new placeholder.\n if (!placeholder) {\n placeholder = `@@${Object.keys(placeholders).length}@@`;\n placeholders[placeholder] = strippedMatch;\n }\n\n return placeholder;\n });\n\n return { placeholders, processedDefinition };\n}\n\n/**\n * Parse the tree definition into an array of raw tokens.\n * @param definition The definition.\n * @returns An array of tokens parsed from the definition.\n */\nexport function parseTokensFromDefinition(definition: string): string[] {\n // Add some space around various important characters so that they can be plucked out easier as individual tokens.\n definition = definition.replace(/\\(/g, \" ( \");\n definition = definition.replace(/\\)/g, \" ) \");\n definition = definition.replace(/\\{/g, \" { \");\n definition = definition.replace(/\\}/g, \" } \");\n definition = definition.replace(/\\]/g, \" ] \");\n definition = definition.replace(/\\[/g, \" [ \");\n definition = definition.replace(/\\,/g, \" , \");\n\n // Split the definition into raw token form and return it.\n return definition.replace(/\\s+/g, \" \").trim().split(\" \");\n}\n", "import { StringLiteralPlaceholders, popAndCheck } from \"./MDSLUtilities\";\n\nexport type Argument = {\n /** The argument value. */\n value: T;\n /** The argument type, used for validation. */\n type: string;\n};\n\nexport type NullArgument = Argument & {\n type: \"null\";\n};\n\nexport type BooleanArgument = Argument & {\n type: \"boolean\";\n};\n\nexport type NumberArgument = Argument & {\n type: \"number\";\n isInteger: boolean; // Used for validation.\n};\n\nexport type StringPlaceholderArgument = Argument & {\n type: \"string\";\n};\n\nexport type IdentifierArgument = Argument & {\n type: \"identifier\";\n};\n\nexport type AnyArgument =\n | NullArgument\n | BooleanArgument\n | NumberArgument\n | StringPlaceholderArgument\n | IdentifierArgument;\n\n/**\n * Parse an array of argument definitions from the specified tokens array.\n * @param tokens The array tokens to parse the argument definitions from.\n * @param stringArgumentPlaceholders The mapping of string literal node argument placeholders to original values.\n * @param argumentValidator The argument validator function.\n * @param validationFailedMessage The exception message to throw if argument validation fails.\n * @returns An array of argument definitions parsed from the specified tokens array.\n */\nexport function parseArgumentTokens(\n tokens: string[],\n stringArgumentPlaceholders: StringLiteralPlaceholders\n): AnyArgument[] {\n const argumentList: AnyArgument[] = [];\n\n // If the next token is not a '[' or '(' then we have no arguments to parse.\n if (![\"[\", \"(\"].includes(tokens[0])) {\n return argumentList;\n }\n\n // Any lists of arguments will always be wrapped in '[]' for node arguments or '()' for attribute arguments.\n // We are looking for a '[' or '(' opener that wraps the argument tokens and the relevant closer.\n const closingToken = popAndCheck(tokens, [\"[\", \"(\"]) === \"[\" ? \"]\" : \")\";\n\n const argumentListTokens: string[] = [];\n\n // Grab all tokens between the '[' and ']' or '(' and ')'.\n while (tokens.length && tokens[0] !== closingToken) {\n // The next token is part of our arguments list.\n argumentListTokens.push(tokens.shift()!);\n }\n\n // Validate the order of the argument tokens. Each token must either be a ',' or a single argument that satisfies the validator.\n argumentListTokens.forEach((token, index) => {\n // Get whether this token should be an actual argument.\n const shouldBeArgumentToken = !(index & 1);\n\n // If the current token should be an actual argument then validate it, otherwise it should be a ',' token.\n if (shouldBeArgumentToken) {\n // Get the argument definition.\n const argumentDefinition = getArgumentDefinition(token, stringArgumentPlaceholders);\n\n // This is a valid argument!\n argumentList.push(argumentDefinition);\n } else {\n // The current token should be a ',' token.\n if (token !== \",\") {\n throw new Error(`invalid argument list, expected ',' or ']' but got '${token}'`);\n }\n }\n });\n\n // The arguments list should terminate with a ']' or ')' token, depending on the opener.\n popAndCheck(tokens, closingToken);\n\n // Return the arguments.\n return argumentList;\n}\n\n/**\n * Gets an argument value definition.\n * @param token The argument token.\n * @param stringArgumentPlaceholders The mapping of string literal node argument placeholders to original values.\n * @returns An argument value definition.\n */\nfunction getArgumentDefinition(token: string, stringArgumentPlaceholders: StringLiteralPlaceholders): AnyArgument {\n // Check whether the token represents a null value.\n if (token === \"null\") {\n return {\n value: null,\n type: \"null\"\n } as NullArgument;\n }\n\n // Check whether the token represents a boolean value.\n if (token === \"true\" || token === \"false\") {\n return {\n value: token === \"true\",\n type: \"boolean\"\n } as BooleanArgument;\n }\n\n // Check whether the token represents a number value.\n // TODO: Relies on broken isNaN - see MDN.\n // if (!Number.isNaN(token)) {\n if (!isNaN(token as any)) {\n return {\n value: parseFloat(token),\n isInteger: parseFloat(token) === parseInt(token, 10),\n type: \"number\"\n } as NumberArgument;\n }\n\n // Check whether the token is a placeholder (e.g. @@0@@) representing a string literal.\n if (token.match(/^@@\\d+@@$/g)) {\n return {\n value: stringArgumentPlaceholders[token].replace('\\\\\"', '\"'),\n type: \"string\"\n } as StringPlaceholderArgument;\n }\n\n // The only remaining option is that the argument value is an identifier.\n return {\n value: token,\n type: \"identifier\"\n } as IdentifierArgument;\n}\n", "import { NodeAttributeDefinition } from \"../BehaviourTreeDefinition\";\nimport { parseArgumentTokens } from \"./MDSLNodeArgumentParser\";\nimport { StringLiteralPlaceholders } from \"./MDSLUtilities\";\n\n/**\n * A type defining the attribute definitions of a node.\n */\ntype NodeAttributes = {\n while?: NodeAttributeDefinition;\n until?: NodeAttributeDefinition;\n entry?: NodeAttributeDefinition;\n exit?: NodeAttributeDefinition;\n step?: NodeAttributeDefinition;\n};\n\n/**\n * Parse any node attribute definitions from the specified tokens array.\n * @param tokens The array of remaining tokens.\n * @param stringArgumentPlaceholders The mapping of string literal node argument placeholders to original values.\n * @returns An object of attribute definitions defined by any directly following tokens.\n */\nexport function parseAttributeTokens(\n tokens: string[],\n stringArgumentPlaceholders: StringLiteralPlaceholders\n): NodeAttributes {\n const nodeAttributeNames: (keyof NodeAttributes)[] = [\"while\", \"until\", \"entry\", \"exit\", \"step\"];\n\n // Create an object to hold any attributes found.\n const attributes: NodeAttributes = {};\n\n // Try to get the name of the attribute for the next token.\n let nextAttributeName = tokens[0]?.toLowerCase() as keyof NodeAttributes;\n\n // Pull attribute tokens as well as their arguments off of the tokens stack until we have no more.\n while (nodeAttributeNames.includes(nextAttributeName)) {\n // Check to make sure that we have not already created an attribute definition of this type.\n if (attributes[nextAttributeName]) {\n throw new Error(`duplicate attribute '${tokens[0].toUpperCase()}' found for node`);\n }\n\n // Remove the attribute name token from the array of tokens.\n tokens.shift();\n\n // Grab the attribute arguments, assuming the first to be an identifier.\n const [attributeCallIdentifier, ...attributeArguments] = parseArgumentTokens(\n tokens,\n stringArgumentPlaceholders\n );\n\n // The first attribute argument has to be an identifer, this will reference an agent function.\n if (attributeCallIdentifier?.type !== \"identifier\") {\n throw new Error(\"expected agent function name identifier argument for attribute\");\n }\n\n // Any attribute arguments (other than the expected call identifier) must have a type of string, number, boolean or null.\n attributeArguments\n .filter((arg) => arg.type === \"identifier\")\n .forEach((arg) => {\n throw new Error(\n `invalid attribute argument value '${arg.value}', must be string, number, boolean or null`\n );\n });\n\n // Create the attribute definition and add it to the object of attribute definitions found.\n attributes[nextAttributeName] = {\n call: attributeCallIdentifier.value,\n args: attributeArguments.map(({ value }) => value)\n };\n\n // Try to get the next attribute name token, as there could be multiple.\n nextAttributeName = tokens[0]?.toLowerCase() as keyof NodeAttributes;\n }\n\n return attributes;\n}\n", "import {\n ActionNodeDefinition,\n AnyChildNode,\n AnyNode,\n BranchNodeDefinition,\n ConditionNodeDefinition,\n FailNodeDefinition,\n FlipNodeDefinition,\n LottoNodeDefinition,\n ParallelNodeDefinition,\n RepeatNodeDefinition,\n RetryNodeDefinition,\n RootNodeDefinition,\n SelectorNodeDefinition,\n SequenceNodeDefinition,\n SucceedNodeDefinition,\n WaitNodeDefinition\n} from \"../BehaviourTreeDefinition\";\nimport { isCompositeNode, isDecoratorNode, isLeafNode, isRootNode } from \"../BehaviourTreeDefinitionUtilities\";\nimport { parseArgumentTokens } from \"./MDSLNodeArgumentParser\";\nimport { parseAttributeTokens } from \"./MDSLNodeAttributeParser\";\nimport {\n StringLiteralPlaceholders,\n parseTokensFromDefinition,\n popAndCheck,\n substituteStringLiterals\n} from \"./MDSLUtilities\";\n\n/**\n * Convert the MDSL tree definition string into an equivalent JSON definition.\n * @param definition The tree definition string as MDSL.\n * @returns The root node JSON definitions.\n */\nexport function convertMDSLToJSON(definition: string): RootNodeDefinition[] {\n // Swap out any node/attribute argument string literals with a placeholder and get a mapping of placeholders to original values as well as the processed definition.\n const { placeholders, processedDefinition } = substituteStringLiterals(definition);\n\n // Parse our definition definition string into an array of raw tokens.\n const tokens = parseTokensFromDefinition(processedDefinition);\n\n return convertTokensToJSONDefinition(tokens, placeholders);\n}\n\n/**\n * Converts the specified tree definition tokens into a JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The root node JSON definitions.\n */\nfunction convertTokensToJSONDefinition(\n tokens: string[],\n stringLiteralPlaceholders: StringLiteralPlaceholders\n): RootNodeDefinition[] {\n // There must be at least 3 tokens for the tree definition to be valid. 'ROOT', '{' and '}'.\n if (tokens.length < 3) {\n throw new Error(\"invalid token count\");\n }\n\n // We should have a matching number of '{' and '}' tokens. If not, then there are scopes that have not been properly closed.\n if (tokens.filter((token) => token === \"{\").length !== tokens.filter((token) => token === \"}\").length) {\n throw new Error(\"scope character mismatch\");\n }\n\n // Create an array of tree stack arrays where root nodes will always be at the botton and the current composite/decorator node at the top.\n // There should be an element in this array for every root node defined and every element should be an array with a root note as the first element.\n // E.g. A definition with two root nodes defined:\n // [\n // [root, lotto, sequence],\n // [root, selector]\n // ]\n const treeStacks: [Partial, ...Partial[]][] = [];\n\n // Create an array of all root node definitions that we create.\n const rootNodes: Partial[] = [];\n\n // A helper function used to push node definitions onto the tree stack.\n const pushNode = (node: AnyNode) => {\n // If the node is a root node then we need to create a new tree stack array with the root node at the root.\n if (isRootNode(node)) {\n // Add the root node definition to our array of all parsed root node definitions.\n rootNodes.push(node);\n\n // Add the root node definition to the root of a new tree stack.\n treeStacks.push([node]);\n\n return;\n }\n\n // All non-root nodes should be pushed after their root nodes so handle cases\n // where we may not have any tree stacks or our top-most tree stack is empty.\n if (!treeStacks.length || !treeStacks[treeStacks.length - 1].length) {\n throw new Error(\"expected root node at base of definition\");\n }\n\n // Get the current tree stack that we are populating.\n const topTreeStack = treeStacks[treeStacks.length - 1];\n\n // Get the top-most node in the current tree stack, this will be a composite/decorator node\n // for which we will populate its children array if composite or setting its child if a decorator.\n const topTreeStackTopNode = topTreeStack[topTreeStack.length - 1] as AnyNode;\n\n // If the top-most node in the current root stack is a composite or decorator\n // node then the current node should be added as a child of the top-most node.\n if (isCompositeNode(topTreeStackTopNode)) {\n topTreeStackTopNode.children = topTreeStackTopNode.children || [];\n topTreeStackTopNode.children.push(node);\n } else if (isDecoratorNode(topTreeStackTopNode)) {\n // If the top node already has a child node set then throw an error as a decorator should only have a single child.\n if (topTreeStackTopNode.child) {\n throw new Error(\"a decorator node must only have a single child node\");\n }\n\n topTreeStackTopNode.child = node;\n }\n\n // If the node we are adding is also a composite or decorator node, then we should push it\n // onto the current tree stack, as subsequent nodes will be added as its child/children.\n if (!isLeafNode(node)) {\n topTreeStack.push(node);\n }\n };\n\n // A helper function used to pop node definitions off of the stack.\n const popNode = () => {\n // Get the current tree stack that we are populating.\n const topTreeStack = treeStacks[treeStacks.length - 1];\n\n // Pop the top-most node in the current tree stack if there is one.\n if (topTreeStack.length) {\n topTreeStack.pop();\n }\n\n // We don't want any empty tree stacks in our stack of tree stacks.\n if (!topTreeStack.length) {\n treeStacks.pop();\n }\n };\n\n // We should keep processing the raw tokens until we run out of them.\n while (tokens.length) {\n // Grab the next token.\n const token = tokens.shift()!;\n\n // How we create the next node depends on the current raw token value.\n switch (token.toUpperCase()) {\n case \"ROOT\": {\n pushNode(createRootNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"SUCCEED\": {\n pushNode(createSucceedNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"FAIL\": {\n pushNode(createFailNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"FLIP\": {\n pushNode(createFlipNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"REPEAT\": {\n pushNode(createRepeatNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"RETRY\": {\n pushNode(createRetryNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"SEQUENCE\": {\n pushNode(createSequenceNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"SELECTOR\": {\n pushNode(createSelectorNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"PARALLEL\": {\n pushNode(createParallelNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"LOTTO\": {\n pushNode(createLottoNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"ACTION\": {\n pushNode(createActionNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"CONDITION\": {\n pushNode(createConditionNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"WAIT\": {\n pushNode(createWaitNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"BRANCH\": {\n pushNode(createBranchNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"}\": {\n // The '}' character closes the current scope and means that we have to pop a node off of the current stack.\n popNode();\n break;\n }\n\n default: {\n throw new Error(`unexpected token: ${token}`);\n }\n }\n }\n\n return rootNodes as RootNodeDefinition[];\n}\n\n/**\n * Creates a root node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The root node JSON definition.\n */\nfunction createRootNode(tokens: string[], stringLiteralPlaceholders: StringLiteralPlaceholders): RootNodeDefinition {\n // Create the root node definition.\n let node = {\n type: \"root\",\n id: undefined\n } as RootNodeDefinition;\n\n // Parse any node arguments, we should only have one if any which will be an identifier argument for the root identifier.\n const nodeArguments = parseArgumentTokens(tokens, stringLiteralPlaceholders);\n\n // Check whether any node arguments were defined.\n if (nodeArguments.length) {\n // We should only have one argument, if any, which will be an identifier argument for the root identifier.\n if (nodeArguments.length === 1 && nodeArguments[0].type === \"identifier\") {\n // The root node identifier will be the first and only node argument value.\n node.id = nodeArguments[0].value as string;\n } else {\n throw new Error(\"expected single root name argument\");\n }\n }\n\n // Grab any node attribute definitions and spread them into the node definition.\n node = { ...node, ...parseAttributeTokens(tokens, stringLiteralPlaceholders) };\n\n // This is a decorator node, so we expect an opening '{'.\n popAndCheck(tokens, \"{\");\n\n // Return the root node definition.\n return node;\n}\n\n/**\n * Creates a succeed node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The succeed node JSON definition.\n */\nfunction createSucceedNode(\n tokens: string[],\n stringLiteralPlaceholders: StringLiteralPlaceholders\n): SucceedNodeDefinition {\n const node = {\n type: \"succeed\",\n ...parseAttributeTokens(tokens, stringLiteralPlaceholders)\n } as SucceedNodeDefinition;\n\n // This is a decorator node, so we expect an opening '{'.\n popAndCheck(tokens, \"{\");\n\n // Return the succeed node definition.\n return node;\n}\n\n/**\n * Creates a fail node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The fail node JSON definition.\n */\nfunction createFailNode(tokens: string[], stringLiteralPlaceholders: StringLiteralPlaceholders): FailNodeDefinition {\n const node = {\n type: \"fail\",\n ...parseAttributeTokens(tokens, stringLiteralPlaceholders)\n } as FailNodeDefinition;\n\n // This is a decorator node, so we expect an opening '{'.\n popAndCheck(tokens, \"{\");\n\n // Return the fail node definition.\n return node;\n}\n\n/**\n * Creates a flip node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The flip node JSON definition.\n */\nfunction createFlipNode(tokens: string[], stringLiteralPlaceholders: StringLiteralPlaceholders): FlipNodeDefinition {\n const node = {\n type: \"flip\",\n ...parseAttributeTokens(tokens, stringLiteralPlaceholders)\n } as FlipNodeDefinition;\n\n // This is a decorator node, so we expect an opening '{'.\n popAndCheck(tokens, \"{\");\n\n // Return the flip node definition.\n return node;\n}\n\n/**\n * Creates a repeat node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The repeat node JSON definition.\n */\nfunction createRepeatNode(\n tokens: string[],\n stringLiteralPlaceholders: StringLiteralPlaceholders\n): RepeatNodeDefinition {\n let node = { type: \"repeat\" } as RepeatNodeDefinition;\n\n // Get the node arguments.\n const nodeArguments = parseArgumentTokens(tokens, stringLiteralPlaceholders);\n\n // The arguments of a repeat node are optional. We may have:\n // - No node arguments, in which case the repeat note will iterate indefinitely.\n // - One node argument which will be the explicit number of iterations to make.\n // - Two node arguments which define the min and max iteration bounds from which a random iteration count will be picked.\n if (nodeArguments.length) {\n // All repeat node arguments MUST be of type number and must be integer.\n nodeArguments\n .filter((arg) => arg.type !== \"number\" || !arg.isInteger)\n .forEach(() => {\n throw new Error(`repeat node iteration counts must be integer values`);\n });\n\n // We should have got one or two iteration counts.\n if (nodeArguments.length === 1) {\n // A static iteration count was defined.\n node.iterations = nodeArguments[0].value as number;\n } else if (nodeArguments.length === 2) {\n // A minimum and maximum iteration count was defined.\n node.iterations = [nodeArguments[0].value as number, nodeArguments[1].value as number];\n } else {\n // An incorrect number of iteration counts was defined.\n throw new Error(\"invalid number of repeat node iteration count arguments defined\");\n }\n }\n\n // Grab any node attribute definitions and spread them into the node definition.\n node = { ...node, ...parseAttributeTokens(tokens, stringLiteralPlaceholders) };\n\n // This is a decorator node, so we expect an opening '{'.\n popAndCheck(tokens, \"{\");\n\n // Return the repeat node definition.\n return node;\n}\n\n/**\n * Creates a retry node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The retry node JSON definition.\n */\nfunction createRetryNode(tokens: string[], stringLiteralPlaceholders: StringLiteralPlaceholders): RetryNodeDefinition {\n let node = { type: \"retry\" } as RetryNodeDefinition;\n\n // Get the node arguments.\n const nodeArguments = parseArgumentTokens(tokens, stringLiteralPlaceholders);\n\n // The arguments of a retry node are optional. We may have:\n // - No node arguments, in which case the retry note will attempt indefinitely.\n // - One node argument which will be the explicit number of attempts to make.\n // - Two node arguments which define the min and max attempt bounds from which a random attempt count will be picked.\n if (nodeArguments.length) {\n // All retry node arguments MUST be of type number and must be integer.\n nodeArguments\n .filter((arg) => arg.type !== \"number\" || !arg.isInteger)\n .forEach(() => {\n throw new Error(`retry node attempt counts must be integer values`);\n });\n\n // We should have got one or two attempt counts.\n if (nodeArguments.length === 1) {\n // A static attempt count was defined.\n node.attempts = nodeArguments[0].value as number;\n } else if (nodeArguments.length === 2) {\n // A minimum and maximum attempt count was defined.\n node.attempts = [nodeArguments[0].value as number, nodeArguments[1].value as number];\n } else {\n // An incorrect number of attempt counts was defined.\n throw new Error(\"invalid number of retry node attempt count arguments defined\");\n }\n }\n\n // Grab any node attribute definitions and spread them into the node definition.\n node = { ...node, ...parseAttributeTokens(tokens, stringLiteralPlaceholders) };\n\n // This is a decorator node, so we expect an opening '{'.\n popAndCheck(tokens, \"{\");\n\n // Return the retry node definition.\n return node;\n}\n\n/**\n * Creates a sequence node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The sequence node JSON definition.\n */\nfunction createSequenceNode(\n tokens: string[],\n stringLiteralPlaceholders: StringLiteralPlaceholders\n): SequenceNodeDefinition {\n const node = {\n type: \"sequence\",\n ...parseAttributeTokens(tokens, stringLiteralPlaceholders)\n } as SequenceNodeDefinition;\n\n // This is a composite node, so we expect an opening '{'.\n popAndCheck(tokens, \"{\");\n\n // Return the sequence node definition.\n return node;\n}\n\n/**\n * Creates a selector node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The selector node JSON definition.\n */\nfunction createSelectorNode(\n tokens: string[],\n stringLiteralPlaceholders: StringLiteralPlaceholders\n): SelectorNodeDefinition {\n const node = {\n type: \"selector\",\n ...parseAttributeTokens(tokens, stringLiteralPlaceholders)\n } as SelectorNodeDefinition;\n\n // This is a composite node, so we expect an opening '{'.\n popAndCheck(tokens, \"{\");\n\n // Return the selector node definition.\n return node;\n}\n\n/**\n * Creates a parallel node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The parallel node JSON definition.\n */\nfunction createParallelNode(\n tokens: string[],\n stringLiteralPlaceholders: StringLiteralPlaceholders\n): ParallelNodeDefinition {\n const node = {\n type: \"parallel\",\n ...parseAttributeTokens(tokens, stringLiteralPlaceholders)\n } as ParallelNodeDefinition;\n\n // This is a composite node, so we expect an opening '{'.\n popAndCheck(tokens, \"{\");\n\n // Return the parallel node definition.\n return node;\n}\n\n/**\n * Creates a lotto node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The lotto node JSON definition.\n */\nfunction createLottoNode(tokens: string[], stringLiteralPlaceholders: StringLiteralPlaceholders): LottoNodeDefinition {\n // If any node arguments have been defined then they must be our weights.\n const nodeArguments = parseArgumentTokens(tokens, stringLiteralPlaceholders);\n\n // All lotto node arguments MUST be of type number and must be integer.\n nodeArguments\n .filter((arg) => arg.type !== \"number\" || !arg.isInteger)\n .forEach(() => {\n throw new Error(`lotto node weight arguments must be integer values`);\n });\n\n const node = {\n type: \"lotto\",\n weights: nodeArguments.map(({ value }) => value),\n ...parseAttributeTokens(tokens, stringLiteralPlaceholders)\n } as LottoNodeDefinition;\n\n // This is a composite node, so we expect an opening '{'.\n popAndCheck(tokens, \"{\");\n\n // Return the lotto node definition.\n return node;\n}\n\n/**\n * Creates an action node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The action node JSON definition.\n */\nfunction createActionNode(\n tokens: string[],\n stringLiteralPlaceholders: StringLiteralPlaceholders\n): ActionNodeDefinition {\n // Parse any node arguments, we should have at least one which will be an identifier argument for the action name\n // and agent function to invoke for the action, all other arguments are to be passed as arguments to that function.\n const [actionNameIdentifier, ...agentFunctionArgs] = parseArgumentTokens(tokens, stringLiteralPlaceholders);\n\n // Our first argument MUST be defined and be an identifier as we require an action name argument.\n if (actionNameIdentifier?.type !== \"identifier\") {\n throw new Error(\"expected action name identifier argument\");\n }\n\n // Only the first argument should have been an identifier, all agent function arguments must be string, number, boolean or null.\n agentFunctionArgs\n .filter((arg) => arg.type === \"identifier\")\n .forEach((arg) => {\n throw new Error(\n `invalid action node argument value '${arg.value}', must be string, number, boolean or null`\n );\n });\n\n // Return the action node definition.\n return {\n type: \"action\",\n call: actionNameIdentifier.value,\n args: agentFunctionArgs.map(({ value }) => value),\n ...parseAttributeTokens(tokens, stringLiteralPlaceholders)\n };\n}\n\n/**\n * Creates a condition node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The condition node JSON definition.\n */\nfunction createConditionNode(\n tokens: string[],\n stringLiteralPlaceholders: StringLiteralPlaceholders\n): ConditionNodeDefinition {\n // Parse any node arguments, we should have at least one which will be an identifier argument for the condition name\n // and agent function to invoke for the condition, all other arguments are to be passed as arguments to that function.\n const [conditionNameIdentifier, ...agentFunctionArgs] = parseArgumentTokens(tokens, stringLiteralPlaceholders);\n\n // Our first argument MUST be defined and be an identifier as we require a condition name argument.\n if (conditionNameIdentifier?.type !== \"identifier\") {\n throw new Error(\"expected condition name identifier argument\");\n }\n\n // Only the first argument should have been an identifier, all agent function arguments must be string, number, boolean or null.\n agentFunctionArgs\n .filter((arg) => arg.type === \"identifier\")\n .forEach((arg) => {\n throw new Error(\n `invalid condition node argument value '${arg.value}', must be string, number, boolean or null`\n );\n });\n\n // Return the condition node definition.\n return {\n type: \"condition\",\n call: conditionNameIdentifier.value,\n args: agentFunctionArgs.map(({ value }) => value),\n ...parseAttributeTokens(tokens, stringLiteralPlaceholders)\n };\n}\n\n/**\n * Creates a wait node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The wait node JSON definition.\n */\nfunction createWaitNode(tokens: string[], stringLiteralPlaceholders: StringLiteralPlaceholders): WaitNodeDefinition {\n let node = { type: \"wait\" } as WaitNodeDefinition;\n\n // Get the node arguments.\n const nodeArguments = parseArgumentTokens(tokens, stringLiteralPlaceholders);\n\n // The arguments of a wait node are optional. We may have:\n // - No node arguments, in which case the wait will be indefinite until it is aborted.\n // - One node argument which will be the explicit duration of the wait.\n // - Two node arguments which define the min and max duration bounds from which a random duration will be picked.\n if (nodeArguments.length) {\n // All wait node arguments MUST be of type number and must be integer.\n nodeArguments\n .filter((arg) => arg.type !== \"number\" || !arg.isInteger)\n .forEach(() => {\n throw new Error(`wait node duration arguments must be integer values`);\n });\n\n // We may have:\n // - One node argument which will be the explicit duration of the wait.\n // - Two node arguments which define the min and max duration bounds from which a random duration will be picked.\n // - Too many arguments, which is not valid.\n if (nodeArguments.length === 1) {\n // An explicit duration was defined.\n node.duration = nodeArguments[0].value as number;\n } else if (nodeArguments.length === 2) {\n // Min and max duration bounds were defined from which a random duration will be picked.\n node.duration = [nodeArguments[0].value as number, nodeArguments[1].value as number];\n } else if (nodeArguments.length > 2) {\n // An incorrect number of duration arguments were defined.\n throw new Error(\"invalid number of wait node duration arguments defined\");\n }\n }\n\n // Return the wait node definition.\n return { ...node, ...parseAttributeTokens(tokens, stringLiteralPlaceholders) };\n}\n\n/**\n * Creates a branch node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The branch node JSON definition.\n */\nfunction createBranchNode(\n tokens: string[],\n stringLiteralPlaceholders: StringLiteralPlaceholders\n): BranchNodeDefinition {\n // Parse any node arguments, we should have one which will be an identifier argument for the root ref.\n const nodeArguments = parseArgumentTokens(tokens, stringLiteralPlaceholders);\n\n // We should have only a single identifer argument for a branch node, which is the root ref.\n if (nodeArguments.length !== 1 || nodeArguments[0].type !== \"identifier\") {\n throw new Error(\"expected single branch name argument\");\n }\n\n // Return the branch node definition.\n return { type: \"branch\", ref: nodeArguments[0].value };\n}\n", "import { RootNodeDefinition } from \"./BehaviourTreeDefinition\";\nimport { flattenDefinition, isBranchNode, isInteger } from \"./BehaviourTreeDefinitionUtilities\";\nimport { convertMDSLToJSON } from \"./mdsl/MDSLDefinitionParser\";\n\n/**\n * An object representing the result of validating a tree definition.\n */\nexport type DefinitionValidationResult = {\n /**\n * A flag defining whether validation succeeded.\n */\n succeeded: boolean;\n /**\n * A string containing the error message if validation did not succeed.\n */\n errorMessage?: string;\n};\n\n/**\n * Validates the specified behaviour tree definition in the form of JSON or MDSL.\n * @param definition The behaviour tree definition in the form of JSON or MDSL.\n * @returns An object representing the result of validating the given tree definition.\n */\nexport function validateDefinition(definition: any): DefinitionValidationResult {\n // The definition must be defined.\n if (definition === null || typeof definition === \"undefined\") {\n return createValidationFailureResult(\"definition is null or undefined\");\n }\n\n // We are expecting a definition in one of three different forms:\n // - A string which we will assume is MDSL and we will parse this to JSON before validation.\n // - An array which we will assume is an array of root node definitions with at least one being the primary root node (no 'id' property)\n // - An object which we will assume is the primary root node and should not have an 'id' property.\n if (typeof definition === \"string\") {\n // The definition is a string which we can assume is MDSL, so attempt to validate it.\n return validateMDSLDefinition(definition);\n } else if (typeof definition === \"object\") {\n // The definition will either be an array (of root node definitions) or an object (the single primary root node definition).\n return validateJSONDefinition(definition);\n } else {\n return createValidationFailureResult(`unexpected definition type of '${typeof definition}'`);\n }\n}\n\n/**\n * Validates the specified behaviour tree definition in the form of MDSL.\n * @param definition The behaviour tree definition in the form of MDSL.\n * @returns An object representing the result of validating the given tree definition.\n */\nexport function validateMDSLDefinition(definition: string): DefinitionValidationResult {\n let rootNodeDefinitions;\n\n // The first thing the we need to do is to attempt to convert our MDSL into JSON.\n try {\n // The definition is a string which we can assume is MDSL, so attempt to parse it to a JSON definition in the form of an array of root node definitions.\n rootNodeDefinitions = convertMDSLToJSON(definition);\n } catch (error) {\n // We failed to parse the JSON from the MDSL, this is likely to be the result of it not being a valid MDSL string.\n return createValidationFailureResult(`invalid MDSL: ${definition}`);\n }\n\n // Unpack all of the root node definitions into arrays of main ('id' defined) and sub ('id' not defined) root node definitions.\n const mainRootNodeDefinitions = rootNodeDefinitions.filter(({ id }) => typeof id === \"undefined\");\n const subRootNodeDefinitions = rootNodeDefinitions.filter(({ id }) => typeof id === \"string\" && id.length > 0);\n\n // We should ALWAYS have exactly one root node definition without an 'id' property defined, which is out main root node definition.\n if (mainRootNodeDefinitions.length !== 1) {\n return createValidationFailureResult(\n \"expected single unnamed root node at base of definition to act as main root\"\n );\n }\n\n // We should never have duplicate 'id' properties across our sub root node definitions.\n const subRootNodeIdenitifers: string[] = [];\n for (const { id } of subRootNodeDefinitions) {\n // Have we already come across this 'id' property value?\n if (subRootNodeIdenitifers.includes(id!)) {\n return createValidationFailureResult(`multiple root nodes found with duplicate name '${id}'`);\n }\n\n subRootNodeIdenitifers.push(id!);\n }\n\n // Check for any branch node circular depedencies. This will NOT include any globally registered subtrees.\n const circularDependencyPath = findBranchCircularDependencyPath(rootNodeDefinitions);\n\n // If we found a circular dependency in our root node and branch node definitions then the definition is definitely not valid.\n if (circularDependencyPath) {\n return createValidationFailureResult(\n `circular dependency found in branch node references: ${circularDependencyPath}`\n );\n }\n\n // Our definition was valid!\n return { succeeded: true };\n}\n\n/**\n * Validates the specified behaviour tree definition in the form of JSON.\n * @param definition The behaviour tree definition in the form of JSON.\n * @returns An object representing the result of validating the given tree definition.\n */\nexport function validateJSONDefinition(\n definition: RootNodeDefinition | RootNodeDefinition[]\n): DefinitionValidationResult {\n // The definition will either be an array (of root node definitions) or an object (the single primary root node definition).\n const rootNodeDefinitions = Array.isArray(definition) ? definition : [definition];\n\n // Iterate over our array of root nodes and call validateNode for each, passing an initial depth of 0, wrapped in a try catch to handle validation failures.\n try {\n rootNodeDefinitions.forEach((rootNodeDefinition) => validateNode(rootNodeDefinition, 0));\n } catch (error) {\n // Handle cases where we have caught a thrown Error and return a failure result with the error message.\n if (error instanceof Error) {\n return createValidationFailureResult(error.message);\n }\n\n // No idea what happened here!\n return createValidationFailureResult(`unexpected error: ${error}`);\n }\n\n // Unpack all of the root node definitions into arrays of main ('id' defined) and sub ('id' not defined) root node definitions.\n const mainRootNodeDefinitions = rootNodeDefinitions.filter(({ id }) => typeof id === \"undefined\");\n const subRootNodeDefinitions = rootNodeDefinitions.filter(({ id }) => typeof id === \"string\" && id.length > 0);\n\n // We should ALWAYS have exactly one root node definition without an 'id' property defined, which is out main root node definition.\n if (mainRootNodeDefinitions.length !== 1) {\n return createValidationFailureResult(\n \"expected single root node without 'id' property defined to act as main root\"\n );\n }\n\n // We should never have duplicate 'id' properties across our sub root node definitions.\n const subRootNodeIdenitifers: string[] = [];\n for (const { id } of subRootNodeDefinitions) {\n // Have we already come across this 'id' property value?\n if (subRootNodeIdenitifers.includes(id!)) {\n return createValidationFailureResult(\n `multiple root nodes found with duplicate 'id' property value of '${id}'`\n );\n }\n\n subRootNodeIdenitifers.push(id!);\n }\n\n // Check for any branch node circular depedencies. This will NOT include any globally registered subtrees.\n const circularDependencyPath = findBranchCircularDependencyPath(rootNodeDefinitions);\n\n // If we found a circular dependency in our root node and branch node definitions then the definition is definitely not valid.\n if (circularDependencyPath) {\n return createValidationFailureResult(\n `circular dependency found in branch node references: ${circularDependencyPath}`\n );\n }\n\n // Our definition was valid!\n return { succeeded: true };\n}\n\n/**\n * Find the first circular depdendency path present in the array of root node definitions, or null if one doesn't exist.\n * This will not consider branch nodes that reference any globally registered subtrees.\n * @param rootNodeDefinitions The array of root node definitions.\n * @returns The first circular depdendency path present in the array of root node definitions as string, or null if one doesn't exist.\n */\nfunction findBranchCircularDependencyPath(rootNodeDefinitions: RootNodeDefinition[]): string | null {\n // Create a mapping of root node identifiers to other root nodes that they reference via branch nodes.\n // Below is an example of a mapping that includes a circular dependency (root => a => b => c => a)\n // [{ refs: [\"a\", \"b\"] }, { id: \"a\", refs: [\"b\"] }, { id: \"b\", refs: [\"c\"] }, { id: \"c\", refs: [\"a\"] }]\n const rootNodeMappings: { id: string | undefined; refs: string[] }[] = rootNodeDefinitions.map(\n (rootNodeDefinition) => ({\n id: rootNodeDefinition.id,\n refs: flattenDefinition(rootNodeDefinition)\n .filter(isBranchNode)\n .map(({ ref }) => ref)\n })\n );\n\n let badPathFormatted: string | null = null;\n\n // A recursive function to walk through the mappings, keeping track of which root nodes we have visited in the form of a path of root node identifiers.\n const followRefs = (mapping: { id: string | undefined; refs: string[] }, path: (string | undefined)[] = []) => {\n // Have we found a circular dependency?\n if (path.includes(mapping.id)) {\n // We found a circular dependency! Get the bad path of root node identifiers.\n const badPath = [...path, mapping.id];\n\n // Set the formatted path value. [undefined, \"a\", \"b\", \"c\", \"a\"] would be formatted as \"a -> b -> c -> a\".\n badPathFormatted = badPath.filter((element) => !!element).join(\" => \");\n\n // No need to continue, we found a circular dependency.\n return;\n }\n\n for (const ref of mapping.refs) {\n // Find the mapping for the root node with an identifer matching the current ref.\n const subMapping = rootNodeMappings.find(({ id }) => id === ref);\n\n // We may not have a mapping for this ref, which will happen if this ref is for a globally registered subtree.\n if (subMapping) {\n followRefs(subMapping, [...path, mapping.id]);\n }\n }\n };\n\n // Start looking for circular dependencies from the root.\n followRefs(rootNodeMappings.find((mapping) => typeof mapping.id === \"undefined\")!);\n\n return badPathFormatted;\n}\n\n/**\n * Validate an object that we expect to be a node definition.\n * @param definition An object that we expect to be a node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateNode(definition: any, depth: number): void {\n // Every node must be valid object and have a non-empty 'type' string property.\n if (typeof definition !== \"object\" || typeof definition.type !== \"string\" || definition.type.length === 0) {\n throw new Error(\n `node definition is not an object or 'type' property is not a non-empty string at depth '${depth}'`\n );\n }\n\n // How we validate this node definition will depend on its type.\n switch (definition.type) {\n case \"action\":\n validateActionNode(definition, depth);\n break;\n\n case \"condition\":\n validateConditionNode(definition, depth);\n break;\n\n case \"wait\":\n validateWaitNode(definition, depth);\n break;\n\n case \"branch\":\n validateBranchNode(definition, depth);\n break;\n\n case \"root\":\n validateRootNode(definition, depth);\n break;\n\n case \"success\":\n validateSuccessNode(definition, depth);\n break;\n\n case \"fail\":\n validateFailNode(definition, depth);\n break;\n\n case \"flip\":\n validateFlipNode(definition, depth);\n break;\n\n case \"repeat\":\n validateRepeatNode(definition, depth);\n break;\n\n case \"retry\":\n validateRetryNode(definition, depth);\n break;\n\n case \"sequence\":\n validateSequenceNode(definition, depth);\n break;\n\n case \"selector\":\n validateSelectorNode(definition, depth);\n break;\n\n case \"parallel\":\n validateParallelNode(definition, depth);\n break;\n\n default:\n throw new Error(`unexpected node type of '${definition.type}' at depth '${depth}'`);\n }\n}\n\n/**\n * Validate any attributes for a given node definition.\n * @param definition The node definition.\n * @param depth The depth of the node in the behaviour tree definition.\n */\nfunction validateNodeAttributes(definition: any, depth: number): void {\n // Validate each of the attribute types for this node.\n [\"while\", \"until\", \"entry\", \"exit\", \"step\"].forEach((attributeName) => {\n // Attempt to grab the definition for the current attribute from the node definition.\n const attributeDefinition = definition[attributeName];\n\n // All node attributes are optional, so there is nothing to do if the current attribute is not defined.\n if (typeof attributeDefinition === \"undefined\") {\n return;\n }\n\n // The attribute definition must be an object.\n if (typeof attributeDefinition !== \"object\") {\n throw new Error(\n `expected attribute '${attributeName}' to be an object for '${definition.type}' node at depth '${depth}'`\n );\n }\n\n // The 'call' property must be defined for any attribute definition.\n if (typeof attributeDefinition.call !== \"string\" || attributeDefinition.call.length === 0) {\n throw new Error(\n `expected 'call' property for attribute '${attributeName}' to be a non-empty string for '${definition.type}' node at depth '${depth}'`\n );\n }\n\n // If any node attribute arguments have been defined then they must have been defined in an array.\n if (typeof attributeDefinition.args !== \"undefined\" && !Array.isArray(attributeDefinition.args)) {\n throw new Error(\n `expected 'args' property for attribute '${attributeName}' to be an array for '${definition.type}' node at depth '${depth}'`\n );\n }\n });\n}\n\n/**\n * Validate an object that we expect to be a root node definition.\n * @param definition An object that we expect to be a root node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateRootNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"root\") {\n throw new Error(\"expected node type of 'root' for root node\");\n }\n\n // A root node cannot be the child of another node.\n if (depth > 0) {\n throw new Error(\"a root node cannot be the child of another node\");\n }\n\n // Check that, if the root node 'id' property is defined, it is a non-empty string.\n if (typeof definition.id !== \"undefined\" && (typeof definition.id !== \"string\" || definition.id.length === 0)) {\n throw new Error(\"expected non-empty string for 'id' property if defined for root node\");\n }\n\n // A root node is a decorator node, so must have a child node defined.\n if (typeof definition.child === \"undefined\") {\n throw new Error(\"expected property 'child' to be defined for root node\");\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n\n // Validate the child node of this decorator node.\n validateNode(definition.child, depth + 1);\n}\n\n/**\n * Validate an object that we expect to be a success node definition.\n * @param definition An object that we expect to be a success node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateSuccessNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"success\") {\n throw new Error(`expected node type of 'success' for success node at depth '${depth}'`);\n }\n\n // A success node is a decorator node, so must have a child node defined.\n if (typeof definition.child === \"undefined\") {\n throw new Error(`expected property 'child' to be defined for success node at depth '${depth}'`);\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n\n // Validate the child node of this decorator node.\n validateNode(definition.child, depth + 1);\n}\n\n/**\n * Validate an object that we expect to be a fail node definition.\n * @param definition An object that we expect to be a fail node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateFailNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"fail\") {\n throw new Error(`expected node type of 'fail' for fail node at depth '${depth}'`);\n }\n\n // A fail node is a decorator node, so must have a child node defined.\n if (typeof definition.child === \"undefined\") {\n throw new Error(`expected property 'child' to be defined for fail node at depth '${depth}'`);\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n\n // Validate the child node of this decorator node.\n validateNode(definition.child, depth + 1);\n}\n\n/**\n * Validate an object that we expect to be a flip node definition.\n * @param definition An object that we expect to be a flip node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateFlipNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"flip\") {\n throw new Error(`expected node type of 'flip' for flip node at depth '${depth}'`);\n }\n\n // A flip node is a decorator node, so must have a child node defined.\n if (typeof definition.child === \"undefined\") {\n throw new Error(`expected property 'child' to be defined for flip node at depth '${depth}'`);\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n\n // Validate the child node of this decorator node.\n validateNode(definition.child, depth + 1);\n}\n\n/**\n * Validate an object that we expect to be a repeat node definition.\n * @param definition An object that we expect to be a repeat node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateRepeatNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"repeat\") {\n throw new Error(`expected node type of 'repeat' for repeat node at depth '${depth}'`);\n }\n\n // A repeat node is a decorator node, so must have a child node defined.\n if (typeof definition.child === \"undefined\") {\n throw new Error(`expected property 'child' to be defined for repeat node at depth '${depth}'`);\n }\n\n // Check whether an 'iterations' property has been defined, it may not have been if this node is to repeat indefinitely.\n if (typeof definition.iterations !== \"undefined\") {\n if (Array.isArray(definition.iterations)) {\n // Check whether any elements of the array are not integer values.\n const containsNonInteger = !!definition.iterations.find((value: unknown) => !isInteger(value));\n\n // If the 'iterations' property is an array then it MUST contain two integer values.\n if (definition.iterations.length !== 2 || containsNonInteger) {\n throw new Error(\n `expected array containing two integer values for 'iterations' property if defined for repeat node at depth '${depth}'`\n );\n }\n } else if (!isInteger(definition.iterations)) {\n throw new Error(\n `expected integer value or array containing two integer values for 'iterations' property if defined for repeat node at depth '${depth}'`\n );\n }\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n\n // Validate the child node of this decorator node.\n validateNode(definition.child, depth + 1);\n}\n\n/**\n * Validate an object that we expect to be a retry node definition.\n * @param definition An object that we expect to be a retry node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateRetryNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"retry\") {\n throw new Error(`expected node type of 'retry' for retry node at depth '${depth}'`);\n }\n\n // A retry node is a decorator node, so must have a child node defined.\n if (typeof definition.child === \"undefined\") {\n throw new Error(`expected property 'child' to be defined for retry node at depth '${depth}'`);\n }\n\n // Check whether an 'attempts' property has been defined, it may not have been if this node is to retry indefinitely.\n if (typeof definition.attempts !== \"undefined\") {\n if (Array.isArray(definition.attempts)) {\n // Check whether any elements of the array are not integer values.\n const containsNonInteger = !!definition.attempts.find((value: unknown) => !isInteger(value));\n\n // If the 'attempts' property is an array then it MUST contain two integer values.\n if (definition.attempts.length !== 2 || containsNonInteger) {\n throw new Error(\n `expected array containing two integer values for 'attempts' property if defined for retry node at depth '${depth}'`\n );\n }\n } else if (!isInteger(definition.attempts)) {\n throw new Error(\n `expected integer value or array containing two integer values for 'attempts' property if defined for retry node at depth '${depth}'`\n );\n }\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n\n // Validate the child node of this decorator node.\n validateNode(definition.child, depth + 1);\n}\n\n/**\n * Validate an object that we expect to be a branch node definition.\n * @param definition An object that we expect to be a branch node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateBranchNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"branch\") {\n throw new Error(`expected node type of 'branch' for branch node at depth '${depth}'`);\n }\n\n // Check that the branch node 'ref' property is defined and is a non-empty string.\n if (typeof definition.ref !== \"string\" || definition.ref.length === 0) {\n throw new Error(`expected non-empty string for 'ref' property for branch node at depth '${depth}'`);\n }\n\n // It is invalid to define guard attributes for a branch node as they should be defined on the referenced root node.\n [\"while\", \"until\"].forEach((attributeName) => {\n if (typeof definition[attributeName] !== \"undefined\") {\n throw new Error(\n `guards should not be defined for branch nodes but guard '${attributeName}' was defined for branch node at depth '${depth}'`\n );\n }\n });\n\n // It is invalid to define callback attributes for a branch node as they should be defined on the referenced root node.\n [\"entry\", \"exit\", \"step\"].forEach((attributeName) => {\n if (typeof definition[attributeName] !== \"undefined\") {\n throw new Error(\n `callbacks should not be defined for branch nodes but callback '${attributeName}' was defined for branch node at depth '${depth}'`\n );\n }\n });\n}\n\n/**\n * Validate an object that we expect to be a action node definition.\n * @param definition An object that we expect to be a action node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateActionNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"action\") {\n throw new Error(`expected node type of 'action' for action node at depth '${depth}'`);\n }\n\n // The 'call' property must be defined for a action node definition.\n if (typeof definition.call !== \"string\" || definition.call.length === 0) {\n throw new Error(`expected non-empty string for 'call' property of action node at depth '${depth}'`);\n }\n\n // If any action function arguments have been defined then they must have been defined in an array.\n if (typeof definition.args !== \"undefined\" && !Array.isArray(definition.args)) {\n throw new Error(`expected array for 'args' property if defined for action node at depth '${depth}'`);\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n}\n\n/**\n * Validate an object that we expect to be a condition node definition.\n * @param definition An object that we expect to be a condition node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateConditionNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"condition\") {\n throw new Error(`expected node type of 'condition' for condition node at depth '${depth}'`);\n }\n\n // The 'call' property must be defined for a condition node definition.\n if (typeof definition.call !== \"string\" || definition.call.length === 0) {\n throw new Error(`expected non-empty string for 'call' property of condition node at depth '${depth}'`);\n }\n\n // If any condition function arguments have been defined then they must have been defined in an array.\n if (typeof definition.args !== \"undefined\" && !Array.isArray(definition.args)) {\n throw new Error(`expected array for 'args' property if defined for condition node at depth '${depth}'`);\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n}\n\n/**\n * Validate an object that we expect to be a wait node definition.\n * @param definition An object that we expect to be a wait node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateWaitNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"wait\") {\n throw new Error(`expected node type of 'wait' for wait node at depth '${depth}'`);\n }\n\n // Check whether a 'duration' property has been defined, it may not have been if this node is to wait indefinitely.\n if (typeof definition.duration !== \"undefined\") {\n if (Array.isArray(definition.duration)) {\n // Check whether any elements of the array are not integer values.\n const containsNonInteger = !!definition.duration.find((value: unknown) => !isInteger(value));\n\n // If the 'duration' property is an array then it MUST contain two integer values.\n if (definition.duration.length !== 2 || containsNonInteger) {\n throw new Error(\n `expected array containing two integer values for 'duration' property if defined for wait node at depth '${depth}'`\n );\n }\n } else if (!isInteger(definition.duration)) {\n throw new Error(\n `expected integer value or array containing two integer values for 'duration' property if defined for wait node at depth '${depth}'`\n );\n }\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n}\n\n/**\n * Validate an object that we expect to be a sequence node definition.\n * @param definition An object that we expect to be a sequence node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateSequenceNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"sequence\") {\n throw new Error(`expected node type of 'sequence' for sequence node at depth '${depth}'`);\n }\n\n // A sequence node is a composite node, so must have a children nodes array defined.\n if (!Array.isArray(definition.children) || definition.children.length === 0) {\n throw new Error(`expected non-empty 'children' array to be defined for sequence node at depth '${depth}'`);\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n\n // Validate the child nodes of this composite node.\n definition.children.forEach((child: any) => validateNode(child, depth + 1));\n}\n\n/**\n * Validate an object that we expect to be a selector node definition.\n * @param definition An object that we expect to be a selector node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateSelectorNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"selector\") {\n throw new Error(`expected node type of 'selector' for selector node at depth '${depth}'`);\n }\n\n // A selector node is a composite node, so must have a children nodes array defined.\n if (!Array.isArray(definition.children) || definition.children.length === 0) {\n throw new Error(`expected non-empty 'children' array to be defined for selector node at depth '${depth}'`);\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n\n // Validate the child nodes of this composite node.\n definition.children.forEach((child: any) => validateNode(child, depth + 1));\n}\n\n/**\n * Validate an object that we expect to be a parallel node definition.\n * @param definition An object that we expect to be a parallel node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateParallelNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"parallel\") {\n throw new Error(`expected node type of 'parallel' for parallel node at depth '${depth}'`);\n }\n\n // A parallel node is a composite node, so must have a children nodes array defined.\n if (!Array.isArray(definition.children) || definition.children.length === 0) {\n throw new Error(`expected non-empty 'children' array to be defined for parallel node at depth '${depth}'`);\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n\n // Validate the child nodes of this composite node.\n definition.children.forEach((child: any) => validateNode(child, depth + 1));\n}\n\n/**\n * A helper function to create a failure validation result with the given error message.\n * @param errorMessage The validation failure error message.\n * @returns A failure validation result with the given error message.\n */\nfunction createValidationFailureResult(errorMessage: string): DefinitionValidationResult {\n return { succeeded: false, errorMessage };\n}\n", "import Node from \"../../nodes/Node\";\n\n/**\n * An exception thrown when evaluating node guard path conditions and a conditions fails.\n */\nexport default class GuardUnsatisifedException extends Error {\n /**\n * @param source The node at which a guard condition failed.\n */\n constructor(private source: Node) {\n super(\"A guard path condition has failed\");\n }\n\n /**\n * Gets whether the specified node is the node at which a guard condition failed.\n * @param node The node to check against the source node.\n * @returns Whether the specified node is the node at which a guard condition failed.\n */\n isSourceNode = (node: Node) => node === this.source;\n}\n", "import { Agent } from \"../../Agent\";\nimport Guard from \"./Guard\";\nimport Node from \"../../nodes/Node\";\nimport GuardUnsatisifedException from \"./GuardUnsatisifedException\";\n\nexport type GuardPathPart = {\n node: Node;\n guards: Guard[];\n};\n\n/**\n * Represents a path of node guards along a root-to-leaf tree path.\n */\nexport default class GuardPath {\n /**\n * @param nodes An array of objects defining a node instance -> guard link, ordered by node depth.\n */\n constructor(private nodes: GuardPathPart[]) {}\n\n /**\n * Evaluate guard conditions for all guards in the tree path, moving outwards from the root.\n * @param agent The agent, required for guard evaluation.\n * @returns An evaluation results object.\n */\n evaluate = (agent: Agent) => {\n // We need to evaluate guard conditions for nodes up the tree, moving outwards from the root.\n for (const details of this.nodes) {\n // There can be multiple guards per node.\n for (const guard of details.guards) {\n // Check whether the guard condition passes, and throw an exception if not.\n if (!guard.isSatisfied(agent)) {\n throw new GuardUnsatisifedException(details.node);\n }\n }\n }\n };\n}\n", "import { Agent } from \"../Agent\";\nimport Attribute from \"../attributes/Attribute\";\nimport Entry from \"../attributes/callbacks/Entry\";\nimport Exit from \"../attributes/callbacks/Exit\";\nimport Step from \"../attributes/callbacks/Step\";\nimport Guard from \"../attributes/guards/Guard\";\nimport GuardPath from \"../attributes/guards/GuardPath\";\nimport GuardUnsatisifedException from \"../attributes/guards/GuardUnsatisifedException\";\nimport { BehaviourTreeOptions } from \"../BehaviourTreeOptions\";\nimport { AnyArgument } from \"../RootAstNodesBuilder\";\nimport State, { AnyState } from \"../State\";\nimport Leaf from \"./leaf/Leaf\";\n\n/**\n * A base node.\n */\nexport default abstract class Node {\n /**\n * The node uid.\n */\n private readonly uid: string = createNodeUid();\n /**\n * The node state.\n */\n private state: AnyState = State.READY;\n /**\n * The guard path to evaluate as part of a node update.\n */\n private guardPath: GuardPath | undefined;\n\n /**\n * @param type The node type.\n * @param attributes The node attributes.\n * @param args The node argument definitions.\n */\n constructor(private type: string, private attributes: Attribute[], private args: AnyArgument[]) {}\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected abstract onUpdate(agent: Agent, options: BehaviourTreeOptions): void;\n\n /**\n * Gets the name of the node.\n */\n public abstract getName(): string;\n\n /**\n * Gets whether this node is a leaf node.\n */\n public abstract isLeafNode: () => this is Leaf;\n\n /**\n * Gets/Sets the state of the node.\n */\n getState = (): AnyState => this.state;\n setState = (value: AnyState): void => {\n this.state = value;\n };\n\n /**\n * Gets the unique id of the node.\n */\n getUid = () => this.uid;\n\n /**\n * Gets the type of the node.\n */\n getType = () => this.type;\n\n /**\n * Gets the node attributes.\n */\n getAttributes = () => this.attributes;\n\n /**\n * Gets the node arguments.\n */\n getArguments = () => this.args;\n\n /**\n * Gets the node attribute with the specified type, or null if it does not exist.\n */\n getAttribute(type: \"entry\" | \"ENTRY\"): Entry;\n getAttribute(type: \"exit\" | \"EXIT\"): Exit;\n getAttribute(type: \"step\" | \"STEP\"): Step;\n getAttribute(type: string): Attribute {\n return (\n this.getAttributes().filter((decorator) => decorator.getType().toUpperCase() === type.toUpperCase())[0] ||\n null\n );\n }\n\n /**\n * Gets the node attributes.\n */\n getGuardAttributes = (): Guard[] => this.getAttributes().filter((decorator) => decorator.isGuard()) as Guard[];\n\n /**\n * Sets the guard path to evaluate as part of a node update.\n */\n setGuardPath = (value: GuardPath) => (this.guardPath = value);\n\n /**\n * Gets whether a guard path is assigned to this node.\n */\n hasGuardPath = () => !!this.guardPath;\n\n /**\n * Gets whether this node is in the specified state.\n * @param value The value to compare to the node state.\n */\n public is(value: AnyState): boolean {\n return this.state === value;\n }\n\n /**\n * Reset the state of the node.\n */\n public reset(): void {\n this.setState(State.READY);\n }\n\n /**\n * Abort the running of this node.\n * @param agent The agent.\n */\n public abort(agent: Agent): void {\n // There is nothing to do if this node is not in the running state.\n if (!this.is(State.RUNNING)) {\n return;\n }\n\n // Reset the state of this node.\n this.reset();\n\n this.getAttribute(\"exit\")?.callAgentFunction(agent, false, true);\n }\n\n /**\n * Update the node.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n * @returns The result of the update.\n */\n public update(agent: Agent, options: BehaviourTreeOptions): void {\n // If this node is already in a 'SUCCEEDED' or 'FAILED' state then there is nothing to do.\n if (this.is(State.SUCCEEDED) || this.is(State.FAILED)) {\n return;\n }\n\n try {\n // Evaluate all of the guard path conditions for the current tree path.\n this.guardPath!.evaluate(agent);\n\n // If this node is in the READY state then call the ENTRY for this node if it exists.\n if (this.is(State.READY)) {\n this.getAttribute(\"entry\")?.callAgentFunction(agent);\n }\n\n this.getAttribute(\"step\")?.callAgentFunction(agent);\n\n // Do the actual update.\n this.onUpdate(agent, options);\n\n // If this node is now in a 'SUCCEEDED' or 'FAILED' state then call the EXIT for this node if it exists.\n if (this.is(State.SUCCEEDED) || this.is(State.FAILED)) {\n this.getAttribute(\"exit\")?.callAgentFunction(agent, this.is(State.SUCCEEDED), false);\n }\n } catch (error) {\n // If the error is a GuardUnsatisfiedException then we need to determine if this node is the source.\n if (error instanceof GuardUnsatisifedException && error.isSourceNode(this)) {\n // Abort the current node.\n this.abort(agent);\n\n // Any node that is the source of an abort will be a failed node.\n this.setState(State.FAILED);\n } else {\n throw error;\n }\n }\n }\n}\n\n/**\n * Create a randomly generated node uid.\n * @returns A randomly generated node uid.\n */\nfunction createNodeUid(): string {\n var S4 = function () {\n return (((1 + Math.random()) * 0x10000) | 0).toString(16).substring(1);\n };\n return S4() + S4() + \"-\" + S4() + \"-\" + S4() + \"-\" + S4() + \"-\" + S4() + S4() + S4();\n}\n", "import Node from \"../Node\";\n\n/**\n * A leaf node.\n */\nexport default abstract class Leaf extends Node {\n /**\n * Gets whether this node is a leaf node.\n */\n isLeafNode = () => true;\n}\n", "import { ActionResult, Agent, ExitFunctionArg, FunctionArg, GlobalFunction } from \"./Agent\";\nimport { AnyArgument, RootAstNode } from \"./RootAstNodesBuilder\";\n\n// Exit callbacks receive their own special type of argument.\n// There's probably stricter ways to represent this but it feels overly complex right now.\ntype ExitResultArg = { value: ExitFunctionArg };\nexport type AnyExitArgument = AnyArgument | ExitResultArg;\n\nexport type InvokerFunction = (args: AnyExitArgument[]) => ActionResult;\n\n/**\n * A singleton used to store and lookup registered functions and subtrees.\n */\nexport default class Lookup {\n /**\n * The object holding any registered functions keyed on function name.\n */\n private static functionTable: { [key: string]: GlobalFunction } = {};\n /**\n * The object holding any registered sub-trees keyed on tree name.\n */\n private static subtreeTable: { [key: string]: RootAstNode } = {};\n\n /**\n * Gets the function with the specified name.\n * @param name The name of the function.\n * @returns The function with the specified name.\n */\n public static getFunc(name: string): GlobalFunction {\n return this.functionTable[name];\n }\n\n /**\n * Sets the function with the specified name for later lookup.\n * @param name The name of the function.\n * @param func The function.\n */\n public static setFunc(name: string, func: GlobalFunction): void {\n this.functionTable[name] = func;\n }\n\n /**\n * Gets the function invoker for the specified agent and function name.\n * If a function with the specified name exists on the agent object then it will\n * be returned, otherwise we will then check the registered functions for a match.\n * @param agent The agent instance that this behaviour tree is modelling behaviour for.\n * @param name The function name.\n * @returns The function invoker for the specified agent and function name.\n */\n static getFuncInvoker(agent: Agent, name: string): InvokerFunction | null {\n // Check whether the agent contains the specified function.\n const foundOnAgent = agent[name];\n if (foundOnAgent && typeof foundOnAgent === \"function\") {\n return (args: AnyExitArgument[]): boolean | ActionResult =>\n foundOnAgent.apply(\n agent,\n args.map((arg) => arg.value)\n );\n }\n\n // The agent does not contain the specified function but it may have been registered at some point.\n if (this.functionTable[name] && typeof this.functionTable[name] === \"function\") {\n return (args: AnyExitArgument[]) => this.functionTable[name](agent, ...args.map((arg) => arg.value));\n }\n\n // We have no function to invoke.\n return null;\n }\n\n /**\n * Gets the subtree with the specified name.\n * @param name The name of the subtree.\n * @returns The subtree with the specified name.\n */\n static getSubtree(name: string): RootAstNode {\n return this.subtreeTable[name];\n }\n\n /**\n * Sets the subtree with the specified name for later lookup.\n * @param name The name of the subtree.\n * @param subtree The subtree.\n */\n static setSubtree(name: string, subtree: RootAstNode) {\n this.subtreeTable[name] = subtree;\n }\n\n /**\n * Removes the registered function or subtree with the specified name.\n * @param name The name of the registered function or subtree.\n */\n static remove(name: string) {\n delete this.functionTable[name];\n delete this.subtreeTable[name];\n }\n\n /**\n * Remove all registered functions and subtrees.\n */\n static empty() {\n this.functionTable = {};\n this.subtreeTable = {};\n }\n}\n", "import Leaf from \"./Leaf\";\nimport State, { CompleteState } from \"../../State\";\nimport Lookup from \"../../Lookup\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { AnyArgument } from \"../../RootAstNodesBuilder\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * An Action leaf node.\n * This represents an immediate or ongoing state of behaviour.\n */\nexport default class Action extends Leaf {\n /**\n * @param attributes The node attributes.\n * @param actionName The action name.\n * @param actionArguments The array of action argument definitions.\n */\n constructor(attributes: Attribute[], private actionName: string, private actionArguments: AnyArgument[]) {\n super(\"action\", attributes, actionArguments);\n }\n\n /**\n * Whether there is a pending update promise.\n */\n private isUsingUpdatePromise = false;\n\n /**\n * The finished state result of an update promise.\n */\n private updatePromiseStateResult: CompleteState | null = null;\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // If the result of this action depends on an update promise then there is nothing to do until\n // it resolves, unless there has been a value set as a result of the update promise resolving.\n if (this.isUsingUpdatePromise) {\n // Check whether the update promise has resolved with a state value.\n if (this.updatePromiseStateResult) {\n // Set the state of this node to match the state returned by the promise.\n this.setState(this.updatePromiseStateResult);\n }\n\n return;\n }\n\n // Attempt to get the invoker for the action function.\n const actionFuncInvoker = Lookup.getFuncInvoker(agent, this.actionName);\n\n // The action function should be defined.\n if (actionFuncInvoker === null) {\n throw new Error(\n `cannot update action node as the action '${this.actionName}' function is not defined on the agent and has not been registered`\n );\n }\n\n // Call the action function, the result of which may be:\n // - The finished state of this action node.\n // - A promise to return a finished node state.\n // - Undefined if the node should remain in the running state.\n const updateResult = actionFuncInvoker(this.actionArguments) as CompleteState | Promise;\n\n if (updateResult instanceof Promise) {\n updateResult.then(\n (result) => {\n // If 'isUpdatePromisePending' is null then the promise was cleared as it was resolving, probably via an abort of reset.\n if (!this.isUsingUpdatePromise) {\n return;\n }\n\n // Check to make sure the result is a valid finished state.\n if (result !== State.SUCCEEDED && result !== State.FAILED) {\n throw new Error(\n \"action node promise resolved with an invalid value, expected a State.SUCCEEDED or State.FAILED value to be returned\"\n );\n }\n\n // Set pending update promise state result to be processed on next update.\n this.updatePromiseStateResult = result;\n },\n (reason) => {\n // If 'isUpdatePromisePending' is null then the promise was cleared as it was resolving, probably via an abort of reset.\n if (!this.isUsingUpdatePromise) {\n return;\n }\n\n // Just throw whatever was returned as the rejection argument.\n throw new Error(reason);\n }\n );\n\n // This node will be in the 'RUNNING' state until the update promise resolves.\n this.setState(State.RUNNING);\n\n // We are now waiting for the promise returned by the use to resolve before we know what state this node is in.\n this.isUsingUpdatePromise = true;\n } else {\n // Validate the returned value.\n this.validateUpdateResult(updateResult);\n\n // Set the state of this node, this may be undefined, which just means that the node is still in the 'RUNNING' state.\n this.setState(updateResult || State.RUNNING);\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => this.actionName;\n\n /**\n * Reset the state of the node.\n */\n reset = () => {\n // Reset the state of this node.\n this.setState(State.READY);\n\n // There is no longer an update promise that we care about.\n this.isUsingUpdatePromise = false;\n this.updatePromiseStateResult = null;\n };\n\n /**\n * Validate the result of an update function call.\n * @param result The result of an update function call.\n */\n private validateUpdateResult = (result: CompleteState | boolean) => {\n switch (result) {\n case State.SUCCEEDED:\n case State.FAILED:\n case undefined:\n return;\n default:\n throw new Error(\n `action '${this.actionName}' 'onUpdate' returned an invalid response, expected an optional State.SUCCEEDED or State.FAILED value to be returned`\n );\n }\n };\n}\n", "import Leaf from \"./Leaf\";\nimport State from \"../../State\";\nimport Lookup from \"../../Lookup\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { AnyArgument } from \"../../RootAstNodesBuilder\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A Condition leaf node.\n * This will succeed or fail immediately based on an agent predicate, without moving to the 'RUNNING' state.\n */\nexport default class Condition extends Leaf {\n /**\n * @param attributes The node attributes.\n * @param conditionName The name of the condition function.\n * @param conditionArguments The array of condition argument definitions.\n */\n constructor(attributes: Attribute[], private conditionName: string, private conditionArguments: AnyArgument[]) {\n super(\"condition\", attributes, conditionArguments);\n }\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // Attempt to get the invoker for the condition function.\n const conditionFuncInvoker = Lookup.getFuncInvoker(agent, this.conditionName);\n\n // The condition function should be defined.\n if (conditionFuncInvoker === null) {\n throw new Error(\n `cannot update condition node as the condition '${this.conditionName}' function is not defined on the agent and has not been registered`\n );\n }\n\n // Call the condition function to determine the state of this node.\n this.setState(!!conditionFuncInvoker(this.conditionArguments) ? State.SUCCEEDED : State.FAILED);\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => this.conditionName;\n}\n", "import Leaf from \"./Leaf\";\nimport State from \"../../State\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { Agent } from \"../../Agent\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A WAIT node.\n * The state of this node will change to SUCCEEDED after a duration of time\n */\nexport default class Wait extends Leaf {\n /**\n * @param attributes The node attributes.\n * @param duration The duration that this node will wait to succeed in milliseconds.\n * @param durationMin The minimum possible duration in milliseconds that this node will wait to succeed.\n * @param durationMax The maximum possible duration in milliseconds that this node will wait to succeed.\n */\n constructor(\n attributes: Attribute[],\n private duration: number | null,\n private durationMin: number | null,\n private durationMax: number | null\n ) {\n super(\"wait\", attributes, []);\n }\n\n /**\n * The time in milliseconds at which this node was first updated.\n */\n private initialUpdateTime: number = 0;\n\n /**\n * The total duration in milliseconds that this node will be waiting for.\n */\n private totalDuration: number | null = null;\n\n /**\n * The duration in milliseconds that this node has been waiting for.\n */\n private waitedDuration: number = 0;\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // If this node is in the READY state then we need to set the initial update time.\n if (this.is(State.READY)) {\n // Set the initial update time.\n this.initialUpdateTime = new Date().getTime();\n\n // Set the initial waited duration.\n this.waitedDuration = 0;\n\n // Are we dealing with an explicit duration or will we be randomly picking a duration between the min and max duration.\n if (this.duration !== null) {\n this.totalDuration = this.duration;\n } else if (this.durationMin !== null && this.durationMax !== null) {\n // We will be picking a random duration between a min and max duration, if the optional 'random' behaviour tree\n // function option is defined then we will be using that, otherwise we will fall back to using Math.random.\n const random = typeof options.random === \"function\" ? options.random : Math.random;\n\n // Pick a random duration between a min and max duration.\n this.totalDuration = Math.floor(\n random() * (this.durationMax - this.durationMin + 1) + this.durationMin\n );\n } else {\n this.totalDuration = null;\n }\n\n // The node is now running until we finish waiting.\n this.setState(State.RUNNING);\n }\n\n // If we have no total duration then this wait node will wait indefinitely until it is aborted.\n if (this.totalDuration === null) {\n return;\n }\n\n // If we have a 'getDeltaTime' function defined as part of our options then we will use it to figure out how long we have waited for.\n if (typeof options.getDeltaTime === \"function\") {\n // Get the delta time.\n const deltaTime = options.getDeltaTime();\n\n // Our delta time must be a valid number and cannot be NaN.\n if (typeof deltaTime !== \"number\" || isNaN(deltaTime)) {\n throw new Error(\"The delta time must be a valid number and not NaN.\");\n }\n\n // Update the amount of time that this node has been waiting for based on the delta time.\n this.waitedDuration += deltaTime * 1000;\n } else {\n // We are not using a delta time, so we will just work out hom much time has passed since the first update.\n this.waitedDuration = new Date().getTime() - this.initialUpdateTime;\n }\n\n // Have we waited long enough?\n if (this.waitedDuration >= this.totalDuration) {\n // We have finished waiting!\n this.setState(State.SUCCEEDED);\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => {\n if (this.duration !== null) {\n return `WAIT ${this.duration}ms`;\n } else if (this.durationMin !== null && this.durationMax !== null) {\n return `WAIT ${this.durationMin}ms-${this.durationMax}ms`;\n } else {\n return \"WAIT\";\n }\n };\n}\n", "import Node from \"../Node\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\n\n/**\n * A decorator node that wraps a single child node.\n */\nexport default abstract class Decorator extends Node {\n /**\n * @param type The node type.\n * @param attributes The node attributes.\n * @param child The child node.\n */\n constructor(type: string, attributes: Attribute[], protected child: Node) {\n super(type, attributes, []);\n }\n\n /**\n * Gets whether this node is a leaf node.\n */\n isLeafNode = () => false;\n\n /**\n * Gets the children of this node.\n */\n getChildren = () => [this.child];\n\n /**\n * Reset the state of the node.\n */\n reset = () => {\n // Reset the state of this node.\n this.setState(State.READY);\n\n // Reset the state of the child node.\n this.child.reset();\n };\n\n /**\n * Abort the running of this node.\n * @param agent The agent.\n */\n abort = (agent: Agent) => {\n // There is nothing to do if this node is not in the running state.\n if (!this.is(State.RUNNING)) {\n return;\n }\n\n // Abort the child node.\n this.child.abort(agent);\n\n // Reset the state of this node.\n this.reset();\n\n this.getAttribute(\"exit\")?.callAgentFunction(agent, false, true);\n };\n}\n", "import Node from \"../Node\";\nimport Decorator from \"./Decorator\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A Root node.\n * The root node will have a single child.\n */\nexport default class Root extends Decorator {\n /**\n * @param attributes The node attributes.\n * @param child The child node.\n */\n constructor(attributes: Attribute[], child: Node) {\n super(\"root\", attributes, child);\n }\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // If the child has never been updated or is running then we will need to update it now.\n if (this.child.getState() === State.READY || this.child.getState() === State.RUNNING) {\n // Update the child of this node.\n this.child.update(agent, options);\n }\n\n // The state of the root node is the state of its child.\n this.setState(this.child.getState());\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => \"ROOT\";\n}\n", "import Node from \"../Node\";\nimport Decorator from \"./Decorator\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A REPEAT node.\n * The node has a single child which can have:\n * -- A number of iterations for which to repeat the child node.\n * -- An infinite repeat loop if neither an iteration count or a condition function is defined.\n * The REPEAT node will stop and have a 'FAILED' state if its child is ever in a 'FAILED' state after an update.\n * The REPEAT node will attempt to move on to the next iteration if its child is ever in a 'SUCCEEDED' state.\n */\nexport default class Repeat extends Decorator {\n /**\n * @param attributes The node attributes.\n * @param iterations The number of iterations to repeat the child node.\n * @param iterationsMin The minimum possible number of iterations to repeat the child node.\n * @param iterationsMax The maximum possible number of iterations to repeat the child node.\n * @param child The child node.\n */\n constructor(\n attributes: Attribute[],\n private iterations: number | null,\n private iterationsMin: number | null,\n private iterationsMax: number | null,\n child: Node\n ) {\n super(\"repeat\", attributes, child);\n }\n\n /**\n * The number of target iterations to make.\n */\n private targetIterationCount: number | null = null;\n\n /**\n * The current iteration count.\n */\n private currentIterationCount: number = 0;\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // If this node is in the READY state then we need to reset the child and the target iteration count.\n if (this.is(State.READY)) {\n // Reset the child node.\n this.child.reset();\n\n // Reset the current iteration count.\n this.currentIterationCount = 0;\n\n // Set the target iteration count.\n this.setTargetIterationCount(options);\n }\n\n // Do a check to see if we can iterate. If we can then this node will move into the 'RUNNING' state.\n // If we cannot iterate then we have hit our target iteration count, which means that the node has succeeded.\n if (this.canIterate()) {\n // This node is in the running state and can do its initial iteration.\n this.setState(State.RUNNING);\n\n // We may have already completed an iteration, meaning that the child node will be in the SUCCEEDED state.\n // If this is the case then we will have to reset the child node now.\n if (this.child.getState() === State.SUCCEEDED) {\n this.child.reset();\n }\n\n // Update the child of this node.\n this.child.update(agent, options);\n\n // If the child moved into the FAILED state when we updated it then there is nothing left to do and this node has also failed.\n // If it has moved into the SUCCEEDED state then we have completed the current iteration.\n if (this.child.getState() === State.FAILED) {\n // The child has failed, meaning that this node has failed.\n this.setState(State.FAILED);\n\n return;\n } else if (this.child.getState() === State.SUCCEEDED) {\n // We have completed an iteration.\n this.currentIterationCount += 1;\n }\n } else {\n // This node is in the 'SUCCEEDED' state as we cannot iterate any more.\n this.setState(State.SUCCEEDED);\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => {\n if (this.iterations !== null) {\n return `REPEAT ${this.iterations}x`;\n } else if (this.iterationsMin !== null && this.iterationsMax !== null) {\n return `REPEAT ${this.iterationsMin}x-${this.iterationsMax}x`;\n } else {\n return \"REPEAT\";\n }\n };\n\n /**\n * Reset the state of the node.\n */\n reset = () => {\n // Reset the state of this node.\n this.setState(State.READY);\n\n // Reset the current iteration count.\n this.currentIterationCount = 0;\n\n // Reset the child node.\n this.child.reset();\n };\n\n /**\n * Gets whether an iteration can be made.\n * @returns Whether an iteration can be made.\n */\n private canIterate = () => {\n if (this.targetIterationCount !== null) {\n // We can iterate as long as we have not reached our target iteration count.\n return this.currentIterationCount < this.targetIterationCount;\n }\n\n // If neither an iteration count or a condition function were defined then we can iterate indefinitely.\n return true;\n };\n\n /**\n * Sets the target iteration count.\n * @param options The behaviour tree options object.\n */\n private setTargetIterationCount = (options: BehaviourTreeOptions) => {\n // Are we dealing with an explicit iteration count or will we be randomly picking a iteration count between the min and max iteration count.\n if (this.iterations !== null) {\n this.targetIterationCount = this.iterations;\n } else if (this.iterationsMin !== null && this.iterationsMax !== null) {\n // We will be picking a random iteration count between a min and max iteration count, if the optional 'random'\n // behaviour tree function option is defined then we will be using that, otherwise we will fall back to using Math.random.\n const random = typeof options.random === \"function\" ? options.random : Math.random;\n\n // Pick a random iteration count between a min and max iteration count.\n this.targetIterationCount = Math.floor(\n random() * (this.iterationsMax - this.iterationsMin + 1) + this.iterationsMin\n );\n } else {\n this.targetIterationCount = null;\n }\n };\n}\n", "import Node from \"../Node\";\nimport Decorator from \"./Decorator\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A RETRY node.\n * The node has a single child which can have:\n * -- A number of iterations for which to repeat the child node.\n * -- An infinite repeat loop if neither an iteration count or a condition function is defined.\n * The RETRY node will stop and have a 'SUCCEEDED' state if its child is ever in a 'SUCCEEDED' state after an update.\n * The RETRY node will attempt to move on to the next iteration if its child is ever in a 'FAILED' state.\n */\nexport default class Retry extends Decorator {\n /**\n * @param attributes The node attributes.\n * @param attempts The number of attempts to retry the child node.\n * @param attemptsMin The minimum possible number of attempts to retry the child node.\n * @param attemptsMax The maximum possible number of attempts to retry the child node.\n * @param child The child node.\n */\n constructor(\n attributes: Attribute[],\n private attempts: number | null,\n private attemptsMin: number | null,\n private attemptsMax: number | null,\n child: Node\n ) {\n super(\"retry\", attributes, child);\n }\n\n /**\n * The number of target attempts to make.\n */\n private targetAttemptCount: number | null = null;\n\n /**\n * The current attempt count.\n */\n private currentAttemptCount: number = 0;\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // If this node is in the READY state then we need to reset the child and the target attempt count.\n if (this.is(State.READY)) {\n // Reset the child node.\n this.child.reset();\n\n // Reset the current attempt count.\n this.currentAttemptCount = 0;\n\n // Set the target attempt count.\n this.setTargetAttemptCount(options);\n }\n\n // Do a check to see if we can attempt. If we can then this node will move into the 'RUNNING' state.\n // If we cannot attempt then we have hit our target attempt count, which means that the node has succeeded.\n if (this.canAttempt()) {\n // This node is in the running state and can do its initial attempt.\n this.setState(State.RUNNING);\n\n // We may have already completed an attempt, meaning that the child node will be in the FAILED state.\n // If this is the case then we will have to reset the child node now.\n if (this.child.getState() === State.FAILED) {\n this.child.reset();\n }\n\n // Update the child of this node.\n this.child.update(agent, options);\n\n // If the child moved into the SUCCEEDED state when we updated it then there is nothing left to do and this node has also succeeded.\n // If it has moved into the FAILED state then we have completed the current attempt.\n if (this.child.getState() === State.SUCCEEDED) {\n // The child has succeeded, meaning that this node has succeeded.\n this.setState(State.SUCCEEDED);\n\n return;\n } else if (this.child.getState() === State.FAILED) {\n // We have completed an attempt.\n this.currentAttemptCount += 1;\n }\n } else {\n // This node is in the 'FAILED' state as we cannot iterate any more.\n this.setState(State.FAILED);\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => {\n if (this.attempts !== null) {\n return `RETRY ${this.attempts}x`;\n } else if (this.attemptsMin !== null && this.attemptsMax !== null) {\n return `RETRY ${this.attemptsMin}x-${this.attemptsMax}x`;\n } else {\n return \"RETRY\";\n }\n };\n\n /**\n * Reset the state of the node.\n */\n reset = () => {\n // Reset the state of this node.\n this.setState(State.READY);\n\n // Reset the current attempt count.\n this.currentAttemptCount = 0;\n\n // Reset the child node.\n this.child.reset();\n };\n\n /**\n * Gets whether an attempt can be made.\n * @returns Whether an attempt can be made.\n */\n canAttempt = () => {\n if (this.targetAttemptCount !== null) {\n // We can attempt as long as we have not reached our target attempt count.\n return this.currentAttemptCount < this.targetAttemptCount;\n }\n\n // If neither an attempt count or a condition function were defined then we can attempt indefinitely.\n return true;\n };\n\n /**\n * Sets the target attempt count.\n * @param options The behaviour tree options object.\n */\n setTargetAttemptCount = (options: BehaviourTreeOptions) => {\n // Are we dealing with an explicit attempt count or will we be randomly picking an attempt count between the min and max attempt count.\n if (this.attempts !== null) {\n this.targetAttemptCount = this.attempts;\n } else if (this.attemptsMin !== null && this.attemptsMax !== null) {\n // We will be picking a random attempt count between a min and max attempt count, if the optional 'random'\n // behaviour tree function option is defined then we will be using that, otherwise we will fall back to using Math.random.\n const random = typeof options.random === \"function\" ? options.random : Math.random;\n\n // Pick a random attempt count between a min and max attempt count.\n this.targetAttemptCount = Math.floor(\n random() * (this.attemptsMax - this.attemptsMin + 1) + this.attemptsMin\n );\n } else {\n this.targetAttemptCount = null;\n }\n };\n}\n", "import Decorator from \"./Decorator\";\nimport State from \"../../State\";\nimport Node from \"../Node\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A Flip node.\n * This node wraps a single child and will flip the state of the child state.\n */\nexport default class Flip extends Decorator {\n /**\n * @param attributes The node attributes.\n * @param child The child node.\n */\n constructor(attributes: Attribute[], child: Node) {\n super(\"flip\", attributes, child);\n }\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // If the child has never been updated or is running then we will need to update it now.\n if (this.child.getState() === State.READY || this.child.getState() === State.RUNNING) {\n this.child.update(agent, options);\n }\n\n // The state of this node will depend in the state of its child.\n switch (this.child.getState()) {\n case State.RUNNING:\n this.setState(State.RUNNING);\n break;\n\n case State.SUCCEEDED:\n this.setState(State.FAILED);\n break;\n\n case State.FAILED:\n this.setState(State.SUCCEEDED);\n break;\n\n default:\n this.setState(State.READY);\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => \"FLIP\";\n}\n", "import Node from \"../Node\";\nimport Decorator from \"./Decorator\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A Succeed node.\n * This node wraps a single child and will always move to the 'SUCCEEDED' state when the child moves to a 'SUCCEEDED' or 'FAILED' state.\n */\nexport default class Succeed extends Decorator {\n /**\n * @param attributes The node attributes.\n * @param child The child node.\n */\n constructor(attributes: Attribute[], child: Node) {\n super(\"succeed\", attributes, child);\n }\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // If the child has never been updated or is running then we will need to update it now.\n if (this.child.getState() === State.READY || this.child.getState() === State.RUNNING) {\n this.child.update(agent, options);\n }\n\n // The state of this node will depend in the state of its child.\n switch (this.child.getState()) {\n case State.RUNNING:\n this.setState(State.RUNNING);\n break;\n\n case State.SUCCEEDED:\n case State.FAILED:\n this.setState(State.SUCCEEDED);\n break;\n\n default:\n this.setState(State.READY);\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => \"SUCCEED\";\n}\n", "import Node from \"../Node\";\nimport Decorator from \"./Decorator\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A Fail node.\n * This node wraps a single child and will always move to the 'FAILED' state when the child moves to a 'SUCCEEDED' or 'FAILED' state.\n */\nexport default class Fail extends Decorator {\n /**\n * @param attributes The node attributes.\n * @param child The child node.\n */\n constructor(attributes: Attribute[], child: Node) {\n super(\"fail\", attributes, child);\n }\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // If the child has never been updated or is running then we will need to update it now.\n if (this.child.getState() === State.READY || this.child.getState() === State.RUNNING) {\n this.child.update(agent, options);\n }\n\n // The state of this node will depend in the state of its child.\n switch (this.child.getState()) {\n case State.RUNNING:\n this.setState(State.RUNNING);\n break;\n\n case State.SUCCEEDED:\n case State.FAILED:\n this.setState(State.FAILED);\n break;\n\n default:\n this.setState(State.READY);\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => \"FAIL\";\n}\n", "import createLotto from \"lotto-draw\";\n\nimport Node from \"../Node\";\nimport Composite from \"./Composite\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A LOTTO node.\n * A winning child is picked on the initial update of this node, based on ticket weighting.\n * The state of this node will match the state of the winning child.\n */\nexport default class Lotto extends Composite {\n /**\n * @param attributes The node attributes.\n * @param tickets The child node tickets.\n * @param children The child nodes.\n */\n constructor(attributes: Attribute[], private tickets: number[], children: Node[]) {\n super(\"lotto\", attributes, children);\n }\n\n /**\n * The child node selected to be the active one.\n */\n private selectedChild: Node | undefined;\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // If this node is in the READY state then we need to pick a winning child node.\n if (this.is(State.READY)) {\n // Create a lotto draw with which to randomly pick a child node to become the active one.\n const lottoDraw = createLotto({\n // Hook up the optional 'random' behaviour tree function option to the one used by 'lotto-draw'.\n random: options.random,\n // Pass in each child node as a participant in the lotto draw with their respective ticket count.\n participants: this.children.map((child, index) => [child, this.tickets[index] || 1])\n });\n\n // Randomly pick a child based on ticket weighting, this will become the active child for this composite node.\n this.selectedChild = lottoDraw.draw() || undefined;\n }\n\n // If something went wrong and we don't have an active child then we should throw an error.\n if (!this.selectedChild) {\n throw new Error(\"failed to update lotto node as it has no active child\");\n }\n\n // If the selected child has never been updated or is running then we will need to update it now.\n if (this.selectedChild.getState() === State.READY || this.selectedChild.getState() === State.RUNNING) {\n this.selectedChild.update(agent, options);\n }\n\n // The state of the lotto node is the state of its selected child.\n this.setState(this.selectedChild.getState());\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => (this.tickets.length ? `LOTTO [${this.tickets.join(\",\")}]` : \"LOTTO\");\n}\n", "import Node from \"../Node\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\n\n/**\n * A composite node that wraps child nodes.\n */\nexport default abstract class Composite extends Node {\n /**\n * @param type The node type.\n * @param attributes The node attributes.\n * @param children The child nodes.\n */\n constructor(type: string, attributes: Attribute[], protected children: Node[]) {\n super(type, attributes, []);\n }\n\n /**\n * Gets whether this node is a leaf node.\n */\n isLeafNode = () => false;\n\n /**\n * Gets the children of this node.\n */\n getChildren = () => this.children;\n\n /**\n * Reset the state of the node.\n */\n reset = () => {\n // Reset the state of this node.\n this.setState(State.READY);\n\n // Reset the state of any child nodes.\n this.getChildren().forEach((child) => child.reset());\n };\n\n /**\n * Abort the running of this node.\n * @param agent The agent.\n */\n abort = (agent: Agent) => {\n // There is nothing to do if this node is not in the running state.\n if (!this.is(State.RUNNING)) {\n return;\n }\n\n // Abort any child nodes.\n this.getChildren().forEach((child) => child.abort(agent));\n\n // Reset the state of this node.\n this.reset();\n\n this.getAttribute(\"exit\")?.callAgentFunction(agent, false, true);\n };\n}\n", "import Composite from \"./Composite\";\nimport Node from \"../Node\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A SELECTOR node.\n * The child nodes are executed in sequence until one succeeds or all fail.\n */\nexport default class Selector extends Composite {\n /**\n * @param attributes The node attributes.\n * @param children The child nodes.\n */\n constructor(attributes: Attribute[], protected children: Node[]) {\n super(\"selector\", attributes, children);\n }\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // Iterate over all of the children of this node.\n for (const child of this.children) {\n // If the child has never been updated or is running then we will need to update it now.\n if (child.getState() === State.READY || child.getState() === State.RUNNING) {\n // Update the child of this node.\n child.update(agent, options);\n }\n\n // If the current child has a state of 'SUCCEEDED' then this node is also a 'SUCCEEDED' node.\n if (child.getState() === State.SUCCEEDED) {\n // This node is a 'SUCCEEDED' node.\n this.setState(State.SUCCEEDED);\n\n // There is no need to check the rest of the selector nodes.\n return;\n }\n\n // If the current child has a state of 'FAILED' then we should move on to the next child.\n if (child.getState() === State.FAILED) {\n // Find out if the current child is the last one in the selector.\n // If it is then this sequence node has also failed.\n if (this.children.indexOf(child) === this.children.length - 1) {\n // This node is a 'FAILED' node.\n this.setState(State.FAILED);\n\n // There is no need to check the rest of the selector as we have completed it.\n return;\n } else {\n // The child node failed, try the next one.\n continue;\n }\n }\n\n // The node should be in the 'RUNNING' state.\n if (child.getState() === State.RUNNING) {\n // This node is a 'RUNNING' node.\n this.setState(State.RUNNING);\n\n // There is no need to check the rest of the selector as the current child is still running.\n return;\n }\n\n // The child node was not in an expected state.\n throw new Error(\"child node was not in an expected state.\");\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => \"SELECTOR\";\n}\n", "import Composite from \"./Composite\";\nimport Node from \"../Node\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A SEQUENCE node.\n * The child nodes are executed in sequence until one fails or all succeed.\n */\nexport default class Sequence extends Composite {\n /**\n * @param attributes The node attributes.\n * @param children The child nodes.\n */\n constructor(attributes: Attribute[], protected children: Node[]) {\n super(\"sequence\", attributes, children);\n }\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // Iterate over all of the children of this node.\n for (const child of this.children) {\n // If the child has never been updated or is running then we will need to update it now.\n if (child.getState() === State.READY || child.getState() === State.RUNNING) {\n // Update the child of this node.\n child.update(agent, options);\n }\n\n // If the current child has a state of 'SUCCEEDED' then we should move on to the next child.\n if (child.getState() === State.SUCCEEDED) {\n // Find out if the current child is the last one in the sequence.\n // If it is then this sequence node has also succeeded.\n if (this.children.indexOf(child) === this.children.length - 1) {\n // This node is a 'SUCCEEDED' node.\n this.setState(State.SUCCEEDED);\n\n // There is no need to check the rest of the sequence as we have completed it.\n return;\n } else {\n // The child node succeeded, but we have not finished the sequence yet.\n continue;\n }\n }\n\n // If the current child has a state of 'FAILED' then this node is also a 'FAILED' node.\n if (child.getState() === State.FAILED) {\n // This node is a 'FAILED' node.\n this.setState(State.FAILED);\n\n // There is no need to check the rest of the sequence.\n return;\n }\n\n // The node should be in the 'RUNNING' state.\n if (child.getState() === State.RUNNING) {\n // This node is a 'RUNNING' node.\n this.setState(State.RUNNING);\n\n // There is no need to check the rest of the sequence as the current child is still running.\n return;\n }\n\n // The child node was not in an expected state.\n throw new Error(\"child node was not in an expected state.\");\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => \"SEQUENCE\";\n}\n", "import Composite from \"./Composite\";\nimport State from \"../../State\";\nimport Node from \"../Node\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A PARALLEL node.\n * The child nodes are executed concurrently until one fails or all succeed.\n */\nexport default class Parallel extends Composite {\n /**\n * @param attributes The node attributes.\n * @param children The child nodes.\n */\n constructor(attributes: Attribute[], children: Node[]) {\n super(\"parallel\", attributes, children);\n }\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // Keep a count of the number of succeeded child nodes.\n let succeededCount = 0;\n\n let hasChildFailed = false;\n\n // Iterate over all of the children of this node.\n for (const child of this.children) {\n // If the child has never been updated or is running then we will need to update it now.\n if (child.getState() === State.READY || child.getState() === State.RUNNING) {\n // Update the child of this node.\n child.update(agent, options);\n }\n\n // If the current child has a state of 'SUCCEEDED' then we should move on to the next child.\n if (child.getState() === State.SUCCEEDED) {\n // The child node has succeeded, keep track of this to determine if all children have.\n succeededCount++;\n\n // The child node succeeded, but we have not finished checking every child node yet.\n continue;\n }\n\n // If the current child has a state of 'FAILED' then this node is also a 'FAILED' node.\n if (child.getState() === State.FAILED) {\n hasChildFailed = true;\n\n // There is no need to check the rest of the children.\n break;\n }\n\n // The node should be in the 'RUNNING' state.\n if (child.getState() !== State.RUNNING) {\n // The child node was not in an expected state.\n throw new Error(\"child node was not in an expected state.\");\n }\n }\n\n if (hasChildFailed) {\n // This node is a 'FAILED' node.\n this.setState(State.FAILED);\n\n // Abort every running child.\n for (const child of this.children) {\n if (child.getState() === State.RUNNING) {\n child.abort(agent);\n }\n }\n } else {\n // If all children have succeeded then this node has also succeeded, otherwise it is still running.\n this.setState(succeededCount === this.children.length ? State.SUCCEEDED : State.RUNNING);\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => \"PARALLEL\";\n}\n", "import { AnyArgument } from \"../RootAstNodesBuilder\";\nimport Guard from \"./guards/Guard\";\n\nexport type AttributeDetails = {\n /** The attribute type. */\n type: string;\n\n /** The attribute arguments. */\n args: AnyArgument[];\n};\n\n/**\n * A base node attribute.\n */\nexport default abstract class Attribute {\n /**\n * @param type The node attribute type.\n * @param args The array of attribute argument definitions.\n */\n constructor(protected type: string, protected args: AnyArgument[]) {}\n\n /**\n * Gets the type of the attribute.\n */\n getType = () => this.type;\n\n /**\n * Gets the array of attribute argument definitions.\n */\n getArguments = () => this.args;\n\n /**\n * Gets the attribute details.\n */\n abstract getDetails(): TAttributeDetails;\n\n /**\n * Gets whether this attribute is a guard.\n */\n abstract isGuard: () => this is Guard;\n}\n", "import { Agent } from \"../../Agent\";\nimport { AnyArgument } from \"../../RootAstNodesBuilder\";\nimport Attribute, { AttributeDetails } from \"../Attribute\";\n\nexport type GuardAttributeDetails = {\n /** The name of the condition function that determines whether the guard is satisfied. */\n condition: string;\n} & AttributeDetails;\n\n/**\n * A base node guard attribute.\n */\nexport default abstract class Guard extends Attribute {\n /**\n * @param type The node attribute type.\n * @param args The array of decorator argument definitions.\n * @param condition The name of the condition function that determines whether the guard is satisfied.\n */\n constructor(type: string, args: AnyArgument[], private condition: string) {\n super(type, args);\n }\n\n /**\n * Gets the name of the condition function that determines whether the guard is satisfied.\n */\n getCondition = () => this.condition;\n\n /**\n * Gets whether this attribute is a guard.\n */\n isGuard = () => true;\n\n /**\n * Gets the attribute details.\n */\n getDetails(): GuardAttributeDetails {\n return {\n type: this.getType(),\n args: this.getArguments(),\n condition: this.getCondition()\n };\n }\n\n /**\n * Gets whether the guard is satisfied.\n * @param agent The agent.\n * @returns Whether the guard is satisfied.\n */\n abstract isSatisfied(agent: Agent): boolean;\n}\n", "import Guard from \"./Guard\";\nimport Lookup from \"../../Lookup\";\nimport { Agent } from \"../../Agent\";\nimport { AnyArgument } from \"../../RootAstNodesBuilder\";\n\n/**\n * A WHILE guard which is satisfied as long as the given condition remains true.\n */\nexport default class While extends Guard {\n /**\n * @param condition The name of the condition function that determines whether the guard is satisfied.\n * @param args The array of decorator argument definitions.\n */\n constructor(condition: string, args: AnyArgument[]) {\n super(\"while\", args, condition);\n }\n\n /**\n * Gets whether the guard is satisfied.\n * @param agent The agent.\n * @returns Whether the guard is satisfied.\n */\n isSatisfied = (agent: Agent) => {\n // Attempt to get the invoker for the condition function.\n const conditionFuncInvoker = Lookup.getFuncInvoker(agent, this.getCondition());\n\n // The condition function should be defined.\n if (conditionFuncInvoker === null) {\n throw new Error(\n `cannot evaluate node guard as the condition '${this.getCondition()}' function is not defined on the agent and has not been registered`\n );\n }\n\n // Call the condition function to determine whether this guard is satisfied.\n return !!conditionFuncInvoker(this.args);\n };\n}\n", "import Guard from \"./Guard\";\nimport Lookup from \"../../Lookup\";\nimport { Agent } from \"../../Agent\";\nimport { AnyArgument } from \"../../RootAstNodesBuilder\";\n\n/**\n * An UNTIL guard which is satisfied as long as the given condition remains false.\n */\nexport default class Until extends Guard {\n /**\n * @param condition The name of the condition function that determines whether the guard is satisfied.\n * @param args The array of decorator argument definitions.\n */\n constructor(condition: string, args: AnyArgument[]) {\n super(\"until\", args, condition);\n }\n\n /**\n * Gets whether the guard is satisfied.\n * @param agent The agent.\n * @returns Whether the guard is satisfied.\n */\n isSatisfied = (agent: Agent) => {\n // Attempt to get the invoker for the condition function.\n const conditionFuncInvoker = Lookup.getFuncInvoker(agent, this.getCondition());\n\n // The condition function should be defined.\n if (conditionFuncInvoker === null) {\n throw new Error(\n `cannot evaluate node guard as the condition '${this.getCondition()}' function is not defined on the agent and has not been registered`\n );\n }\n\n // Call the condition function to determine whether this guard is satisfied.\n return !!!conditionFuncInvoker(this.args);\n };\n}\n", "import { Agent } from \"../../Agent\";\nimport { AnyArgument } from \"../../RootAstNodesBuilder\";\nimport Attribute, { AttributeDetails } from \"../Attribute\";\n\nexport type CallbackAttributeDetails = {\n /** The name of the agent function that is called. */\n functionName: string;\n} & AttributeDetails;\n\n/**\n * A base node callback attribute.\n */\nexport default abstract class Callback extends Attribute {\n /**\n * @param type The node attribute type.\n * @param args The array of decorator argument definitions.\n * @param functionName The name of the agent function to call.\n */\n constructor(type: string, args: AnyArgument[], private functionName: string) {\n super(type, args);\n }\n\n /**\n * Gets the name of the agent function to call.\n */\n getFunctionName = () => this.functionName;\n\n /**\n * Gets whether this attribute is a guard.\n */\n isGuard = () => false;\n\n /**\n * Gets the attribute details.\n */\n getDetails(): CallbackAttributeDetails {\n return {\n type: this.getType(),\n args: this.getArguments(),\n functionName: this.getFunctionName()\n };\n }\n\n /**\n * Attempt to call the agent function that this callback refers to.\n * @param agent The agent.\n */\n abstract callAgentFunction: (agent: Agent, isSuccess: boolean, isAborted: boolean) => void;\n}\n", "import Callback from \"./Callback\";\nimport Lookup from \"../../Lookup\";\nimport { Agent } from \"../../Agent\";\nimport { AnyArgument } from \"../../RootAstNodesBuilder\";\n\n/**\n * An ENTRY callback which defines an agent function to call when the associated node is updated and moves out of running state.\n */\nexport default class Entry extends Callback {\n /**\n * @param functionName The name of the agent function to call.\n * @param args The array of callback argument definitions.\n */\n constructor(functionName: string, args: AnyArgument[]) {\n super(\"entry\", args, functionName);\n }\n\n /**\n * Attempt to call the agent function that this callback refers to.\n * @param agent The agent.\n */\n callAgentFunction = (agent: Agent) => {\n // Attempt to get the invoker for the callback function.\n const callbackFuncInvoker = Lookup.getFuncInvoker(agent, this.getFunctionName());\n\n // The callback function should be defined.\n if (callbackFuncInvoker === null) {\n throw new Error(\n `cannot call entry function '${this.getFunctionName()}' as is not defined on the agent and has not been registered`\n );\n }\n\n // Call the callback function.\n callbackFuncInvoker(this.args);\n };\n}\n", "import Callback from \"./Callback\";\nimport Lookup, { AnyExitArgument } from \"../../Lookup\";\nimport { Agent } from \"../../Agent\";\nimport { AnyArgument } from \"../../RootAstNodesBuilder\";\n\n/**\n * An EXIT callback which defines an agent function to call when the associated node is updated and moves to a finished state or is aborted.\n */\nexport default class Exit extends Callback {\n /**\n * @param functionName The name of the agent function to call.\n * @param args The array of callback argument definitions.\n */\n constructor(functionName: string, args: AnyArgument[]) {\n super(\"exit\", args, functionName);\n }\n\n /**\n * Attempt to call the agent function that this callback refers to.\n * @param agent The agent.\n * @param isSuccess Whether the decorated node was left with a success state.\n * @param isAborted Whether the decorated node was aborted.\n */\n callAgentFunction = (agent: Agent, isSuccess: boolean, isAborted: boolean) => {\n // Attempt to get the invoker for the callback function.\n const callbackFuncInvoker = Lookup.getFuncInvoker(agent, this.getFunctionName());\n\n // The callback function should be defined.\n if (callbackFuncInvoker === null) {\n throw new Error(\n `cannot call exit function '${this.getFunctionName()}' as is not defined on the agent and has not been registered`\n );\n }\n\n // Call the callback function\n callbackFuncInvoker([{ value: { succeeded: isSuccess, aborted: isAborted } }, ...this.args]);\n };\n}\n", "import Callback from \"./Callback\";\nimport Lookup from \"../../Lookup\";\nimport { Agent } from \"../../Agent\";\nimport { AnyArgument } from \"../../RootAstNodesBuilder\";\n\n/**\n * A STEP callback which defines an agent function to call when the associated node is updated.\n */\nexport default class Step extends Callback {\n /**\n * @param functionName The name of the agent function to call.\n * @param args The array of callback argument definitions.\n */\n constructor(functionName: string, args: AnyArgument[]) {\n super(\"step\", args, functionName);\n }\n\n /**\n * Attempt to call the agent function that this callback refers to.\n * @param agent The agent.\n */\n callAgentFunction = (agent: Agent) => {\n // Attempt to get the invoker for the callback function.\n const callbackFuncInvoker = Lookup.getFuncInvoker(agent, this.getFunctionName());\n\n // The callback function should be defined.\n if (callbackFuncInvoker === null) {\n throw new Error(\n `cannot call step function '${this.getFunctionName()}' as is not defined on the agent and has not been registered`\n );\n }\n\n // Call the callback function.\n callbackFuncInvoker(this.args);\n };\n}\n", "import Action from \"./nodes/leaf/Action\";\nimport Condition from \"./nodes/leaf/Condition\";\nimport Wait from \"./nodes/leaf/Wait\";\nimport Root from \"./nodes/decorator/Root\";\nimport Repeat from \"./nodes/decorator/Repeat\";\nimport Retry from \"./nodes/decorator/Retry\";\nimport Flip from \"./nodes/decorator/Flip\";\nimport Succeed from \"./nodes/decorator/Succeed\";\nimport Fail from \"./nodes/decorator/Fail\";\nimport Lotto from \"./nodes/composite/Lotto\";\nimport Selector from \"./nodes/composite/Selector\";\nimport Sequence from \"./nodes/composite/Sequence\";\nimport Parallel from \"./nodes/composite/Parallel\";\nimport Node from \"./nodes/Node\";\nimport While from \"./attributes/guards/While\";\nimport Until from \"./attributes/guards/Until\";\nimport Entry from \"./attributes/callbacks/Entry\";\nimport Exit from \"./attributes/callbacks/Exit\";\nimport Step from \"./attributes/callbacks/Step\";\nimport Callback from \"./attributes/callbacks/Callback\";\nimport Guard from \"./attributes/guards/Guard\";\nimport Attribute from \"./attributes/Attribute\";\nimport Composite from \"./nodes/composite/Composite\";\nimport Decorator from \"./nodes/decorator/Decorator\";\nimport Leaf from \"./nodes/leaf/Leaf\";\n\nexport type Argument = {\n value: T;\n type: string; // Used for validation.\n};\ntype NullArgument = Argument & {\n type: \"null\";\n};\ntype BooleanArgument = Argument & {\n type: \"boolean\";\n};\ntype NumberArgument = Argument & {\n type: \"number\";\n isInteger: boolean; // Used for validation.\n};\ntype StringPlaceholderArgument = Argument & {\n type: \"string\";\n};\ntype IdentifierArgument = Argument & {\n type: \"identifier\";\n};\nexport type AnyArgument =\n | NullArgument\n | BooleanArgument\n | NumberArgument\n | StringPlaceholderArgument\n | IdentifierArgument;\n\n/**\n * The node attribute factories.\n */\nconst AttributeFactories: {\n [key: string]: (functionName: string, attributeArguments: AnyArgument[]) => Callback | Guard;\n} = {\n WHILE: (condition: string, attributeArguments: AnyArgument[]) => new While(condition, attributeArguments),\n UNTIL: (condition: string, attributeArguments: AnyArgument[]) => new Until(condition, attributeArguments),\n ENTRY: (functionName: string, attributeArguments: AnyArgument[]) => new Entry(functionName, attributeArguments),\n EXIT: (functionName: string, attributeArguments: AnyArgument[]) => new Exit(functionName, attributeArguments),\n STEP: (functionName: string, attributeArguments: AnyArgument[]) => new Step(functionName, attributeArguments)\n};\n\ntype Validatable = {\n children?: AstNode[];\n validate: (depth: number) => void;\n};\n\ntype NodeInstanceCreator = (\n namedRootNodeProvider: (name: string) => RootAstNode,\n visitedBranches: string[]\n) => T;\n\nexport type AstNode = Validatable & {\n type: string;\n createNodeInstance: NodeInstanceCreator;\n};\n\nexport type LeafAstNode = AstNode & {\n type: \"action\" | \"condition\" | \"wait\";\n attributes: Attribute[];\n};\n\nexport type CompositeAstNode = AstNode & {\n type: \"lotto\" | \"parallel\" | \"selector\" | \"sequence\";\n attributes: Attribute[];\n children: AstNode[];\n};\n\nexport type DecoratorAstNode = AstNode & {\n type: \"fail\" | \"flip\" | \"repeat\" | \"retry\" | \"root\" | \"succeed\";\n attributes: Attribute[];\n children: AstNode[];\n};\n\nexport type BranchAstNode = AstNode & {\n type: \"branch\";\n branchName: \"\" | string;\n};\n\nexport type LottoAstNode = CompositeAstNode & {\n type: \"lotto\";\n tickets: number[];\n};\n\nexport type RootAstNode = DecoratorAstNode & {\n type: \"root\";\n name: null | string;\n};\n\nexport type RepeatAstNode = DecoratorAstNode & {\n type: \"repeat\";\n iterations: number | null;\n iterationsMin: number | null;\n iterationsMax: number | null;\n};\n\nexport type RetryAstNode = DecoratorAstNode & {\n type: \"retry\";\n attempts: number | null;\n attemptsMin: number | null;\n attemptsMax: number | null;\n};\n\nexport type ActionAstNode = LeafAstNode & {\n type: \"action\";\n actionName: string;\n actionArguments: AnyArgument[];\n};\n\nexport type ConditionAstNode = LeafAstNode & {\n type: \"condition\";\n conditionName: string;\n conditionArguments: AnyArgument[];\n};\n\nexport type WaitAstNode = LeafAstNode & {\n type: \"wait\";\n duration: number | null;\n durationMin: number | null;\n durationMax: number | null;\n};\n\nexport type AnyAstNode =\n | BranchAstNode\n | CompositeAstNode\n | LottoAstNode\n | DecoratorAstNode\n | RootAstNode\n | RepeatAstNode\n | RetryAstNode\n | LeafAstNode\n | ActionAstNode\n | ConditionAstNode\n | WaitAstNode;\n\n/**\n * The AST node factories.\n */\nconst ASTNodeFactories = {\n ROOT: (): RootAstNode => ({\n type: \"root\",\n attributes: [],\n name: null,\n children: [],\n validate(depth: number) {\n // A root node cannot be the child of another node.\n if (depth > 1) {\n throw new Error(\"a root node cannot be the child of another node\");\n }\n\n // A root node must have a single child node.\n if (this.children.length !== 1) {\n throw new Error(\"a root node must have a single child\");\n }\n },\n createNodeInstance(namedRootNodeProvider, visitedBranches) {\n return new Root(\n this.attributes,\n this.children![0].createNodeInstance(namedRootNodeProvider, visitedBranches.slice())\n );\n }\n }),\n BRANCH: (): BranchAstNode => ({\n type: \"branch\",\n branchName: \"\",\n validate() {},\n createNodeInstance(namedRootNodeProvider, visitedBranches) {\n // Try to find the root node with a matching branch name.\n const targetRootNode = namedRootNodeProvider(this.branchName);\n\n // If we have already visited this branch then we have a circular dependency.\n if (visitedBranches.indexOf(this.branchName) !== -1) {\n throw new Error(`circular dependency found in branch node references for branch '${this.branchName}'`);\n }\n\n // If we have a target root node, then the node instance we want will be the first and only child of the referenced root node.\n if (targetRootNode) {\n return targetRootNode\n .createNodeInstance(namedRootNodeProvider, visitedBranches.concat(this.branchName))\n .getChildren()[0];\n } else {\n throw new Error(`branch references root node '${this.branchName}' which has not been defined`);\n }\n }\n }),\n SELECTOR: (): CompositeAstNode => ({\n type: \"selector\",\n attributes: [],\n children: [],\n validate() {\n // A selector node must have at least a single node.\n if (this.children.length < 1) {\n throw new Error(\"a selector node must have at least a single child\");\n }\n },\n createNodeInstance(namedRootNodeProvider, visitedBranches) {\n return new Selector(\n this.attributes,\n this.children.map((child) => child.createNodeInstance(namedRootNodeProvider, visitedBranches.slice()))\n );\n }\n }),\n SEQUENCE: (): CompositeAstNode => ({\n type: \"sequence\",\n attributes: [],\n children: [],\n validate() {\n // A sequence node must have at least a single node.\n if (this.children.length < 1) {\n throw new Error(\"a sequence node must have at least a single child\");\n }\n },\n createNodeInstance(namedRootNodeProvider, visitedBranches) {\n return new Sequence(\n this.attributes,\n this.children.map((child) => child.createNodeInstance(namedRootNodeProvider, visitedBranches.slice()))\n );\n }\n }),\n PARALLEL: (): CompositeAstNode => ({\n type: \"parallel\",\n attributes: [],\n children: [],\n validate() {\n // A parallel node must have at least a single node.\n if (this.children.length < 1) {\n throw new Error(\"a parallel node must have at least a single child\");\n }\n },\n createNodeInstance(namedRootNodeProvider, visitedBranches) {\n return new Parallel(\n this.attributes,\n this.children.map((child) => child.createNodeInstance(namedRootNodeProvider, visitedBranches.slice()))\n );\n }\n }),\n LOTTO: (): LottoAstNode => ({\n type: \"lotto\",\n attributes: [],\n children: [],\n tickets: [],\n validate() {\n // A lotto node must have at least a single node.\n if (this.children!.length < 1) {\n throw new Error(\"a lotto node must have at least a single child\");\n }\n },\n createNodeInstance(namedRootNodeProvider, visitedBranches) {\n return new Lotto(\n this.attributes,\n this.tickets!,\n this.children!.map((child) => child.createNodeInstance(namedRootNodeProvider, visitedBranches.slice()))\n );\n }\n }),\n REPEAT: (): RepeatAstNode => ({\n type: \"repeat\",\n attributes: [],\n iterations: null,\n iterationsMin: null,\n iterationsMax: null,\n children: [],\n validate() {\n // A repeat node must have a single node.\n if (this.children!.length !== 1) {\n throw new Error(\"a repeat node must have a single child\");\n }\n\n if (this.iterations !== null) {\n // A repeat node must have a positive number of iterations if defined.\n if (this.iterations < 0) {\n throw new Error(\"a repeat node must have a positive number of iterations if defined\");\n }\n } else if (this.iterationsMin !== null && this.iterationsMax !== null) {\n // A repeat node must have a positive min and max iteration count if they are defined.\n if (this.iterationsMin < 0 || this.iterationsMax < 0) {\n throw new Error(\n \"a repeat node must have a positive minimum and maximum iteration count if defined\"\n );\n }\n\n // A repeat node must not have an minimum iteration count that exceeds the maximum iteration count.\n if (this.iterationsMin > this.iterationsMax) {\n throw new Error(\n \"a repeat node must not have a minimum iteration count that exceeds the maximum iteration count\"\n );\n }\n } else {\n // If we have no explicit iteration count or a minimum and maximum iteration count set then we are dealing with a repeat node that iterates indefinitely.\n }\n },\n createNodeInstance(namedRootNodeProvider, visitedBranches) {\n return new Repeat(\n this.attributes,\n this.iterations,\n this.iterationsMin,\n this.iterationsMax,\n this.children![0].createNodeInstance(namedRootNodeProvider, visitedBranches.slice())\n );\n }\n }),\n RETRY: (): RetryAstNode => ({\n type: \"retry\",\n attributes: [],\n attempts: null,\n attemptsMin: null,\n attemptsMax: null,\n children: [],\n validate() {\n // A retry node must have a single node.\n if (this.children!.length !== 1) {\n throw new Error(\"a retry node must have a single child\");\n }\n\n if (this.attempts !== null) {\n // A retry node must have a positive number of attempts if defined.\n if (this.attempts < 0) {\n throw new Error(\"a retry node must have a positive number of attempts if defined\");\n }\n } else if (this.attemptsMin !== null && this.attemptsMax !== null) {\n // A retry node must have a positive min and max attempts count if they are defined.\n if (this.attemptsMin < 0 || this.attemptsMax < 0) {\n throw new Error(\"a retry node must have a positive minimum and maximum attempt count if defined\");\n }\n\n // A retry node must not have a minimum attempt count that exceeds the maximum attempt count.\n if (this.attemptsMin > this.attemptsMax) {\n throw new Error(\n \"a retry node must not have a minimum attempt count that exceeds the maximum attempt count\"\n );\n }\n } else {\n // If we have no explicit attempt count or a minimum and maximum attempt count set then we are dealing with a retry node that attempts indefinitely.\n }\n },\n createNodeInstance(namedRootNodeProvider, visitedBranches) {\n return new Retry(\n this.attributes,\n this.attempts,\n this.attemptsMin,\n this.attemptsMax,\n this.children![0].createNodeInstance(namedRootNodeProvider, visitedBranches.slice())\n );\n }\n }),\n FLIP: (): DecoratorAstNode => ({\n type: \"flip\",\n attributes: [],\n children: [],\n validate() {\n // A flip node must have a single node.\n if (this.children!.length !== 1) {\n throw new Error(\"a flip node must have a single child\");\n }\n },\n createNodeInstance(namedRootNodeProvider, visitedBranches) {\n return new Flip(\n this.attributes,\n this.children![0].createNodeInstance(namedRootNodeProvider, visitedBranches.slice())\n );\n }\n }),\n SUCCEED: (): DecoratorAstNode => ({\n type: \"succeed\",\n attributes: [],\n children: [],\n validate() {\n // A succeed node must have a single node.\n if (this.children!.length !== 1) {\n throw new Error(\"a succeed node must have a single child\");\n }\n },\n createNodeInstance(namedRootNodeProvider, visitedBranches) {\n return new Succeed(\n this.attributes,\n this.children![0].createNodeInstance(namedRootNodeProvider, visitedBranches.slice())\n );\n }\n }),\n FAIL: (): DecoratorAstNode => ({\n type: \"fail\",\n attributes: [],\n children: [],\n validate() {\n // A fail node must have a single node.\n if (this.children!.length !== 1) {\n throw new Error(\"a fail node must have a single child\");\n }\n },\n createNodeInstance(namedRootNodeProvider, visitedBranches) {\n return new Fail(\n this.attributes,\n this.children![0].createNodeInstance(namedRootNodeProvider, visitedBranches.slice())\n );\n }\n }),\n WAIT: (): WaitAstNode => ({\n type: \"wait\",\n attributes: [],\n duration: null,\n durationMin: null,\n durationMax: null,\n validate() {\n if (this.duration !== null) {\n // If an explict duration was defined then it must be a positive number.\n if (this.duration < 0) {\n throw new Error(\"a wait node must have a positive duration\");\n }\n } else if (this.durationMin !== null && this.durationMax !== null) {\n // A wait node must have a positive min and max duration.\n if (this.durationMin < 0 || this.durationMax < 0) {\n throw new Error(\"a wait node must have a positive minimum and maximum duration\");\n }\n\n // A wait node must not have a minimum duration that exceeds the maximum duration.\n if (this.durationMin > this.durationMax) {\n throw new Error(\"a wait node must not have a minimum duration that exceeds the maximum duration\");\n }\n } else {\n // If we have no explicit duration or duration bounds set then we are dealing with a wait node that waits indefinitely.\n }\n },\n createNodeInstance() {\n return new Wait(this.attributes, this.duration, this.durationMin, this.durationMax);\n }\n }),\n ACTION: (): ActionAstNode => ({\n type: \"action\",\n attributes: [],\n actionName: \"\",\n actionArguments: [],\n validate() {},\n createNodeInstance() {\n return new Action(this.attributes, this.actionName!, this.actionArguments!);\n }\n }),\n CONDITION: (): ConditionAstNode => ({\n type: \"condition\",\n attributes: [],\n conditionName: \"\",\n conditionArguments: [],\n validate() {},\n createNodeInstance() {\n return new Condition(this.attributes, this.conditionName!, this.conditionArguments!);\n }\n })\n};\n\ntype OtherAstNodes = AstNode[];\n\n/**\n * Create an array of root AST nodes based on the given definition.\n * @param definition The definition to parse the AST nodes from.\n * @returns The base definition AST nodes.\n */\nexport default function buildRootASTNodes(definition: string): RootAstNode[] {\n // Swap out any node/attribute argument string literals with a placeholder and get a mapping of placeholders to original values as well as the processed definition.\n const { placeholders, processedDefinition } = substituteStringLiterals(definition);\n\n // Convert the processed definition (with substituted string literals) into an array of raw tokens.\n const tokens = parseTokensFromDefinition(processedDefinition);\n\n // There must be at least 3 tokens for the tree definition to be valid. 'ROOT', '{' and '}'.\n if (tokens.length < 3) {\n throw new Error(\"invalid token count\");\n }\n\n // We should have a matching number of '{' and '}' tokens. If not, then there are scopes that have not been properly closed.\n if (tokens.filter((token) => token === \"{\").length !== tokens.filter((token) => token === \"}\").length) {\n throw new Error(\"scope character mismatch\");\n }\n\n // Create a stack of node children arrays, starting with a definition scope.\n const stack: [RootAstNode[], ...OtherAstNodes[]] = [[]];\n const rootScope = stack[0];\n\n // We should keep processing the raw tokens until we run out of them.\n while (tokens.length) {\n // Grab the next token.\n const token = tokens.shift();\n\n const currentScope = stack[stack.length - 1] as OtherAstNodes;\n\n // How we create the next AST token depends on the current raw token value.\n switch (token!.toUpperCase()) {\n case \"ROOT\": {\n // Create a ROOT AST node.\n const node = ASTNodeFactories.ROOT();\n\n // Push the ROOT node into the current scope.\n rootScope.push(node);\n\n // We may have a root node name defined as an argument.\n if (tokens[0] === \"[\") {\n const rootArguments = getArguments(tokens, placeholders);\n\n // We should have only a single argument that is not an empty string for a root node, which is the root name identifier.\n if (rootArguments.length === 1 && rootArguments[0].type === \"identifier\") {\n // The root name will be the first and only node argument.\n node.name = rootArguments[0].value as string;\n } else {\n throw new Error(\"expected single root name argument\");\n }\n }\n\n // Try to pick any attributes off of the token stack.\n node.attributes = getAttributes(tokens, placeholders);\n\n popAndCheck(tokens, \"{\");\n\n // The new scope is that of the new ROOT nodes children.\n stack.push(node.children!);\n break;\n }\n\n case \"BRANCH\": {\n // Create a BRANCH AST node.\n const node = ASTNodeFactories.BRANCH();\n\n // Push the BRANCH node into the current scope.\n currentScope.push(node);\n\n // We must have arguments defined, as we require a branch name argument.\n if (tokens[0] !== \"[\") {\n throw new Error(\"expected single branch name argument\");\n }\n\n // The branch name will be defined as a node argument.\n const branchArguments = getArguments(tokens, placeholders);\n\n // We should have only a single identifer argument for a branch node, which is the branch name.\n if (branchArguments.length === 1 && branchArguments[0].type === \"identifier\") {\n // The branch name will be the first and only node argument.\n node.branchName = branchArguments[0].value as string;\n } else {\n throw new Error(\"expected single branch name argument\");\n }\n break;\n }\n\n case \"SELECTOR\": {\n // Create a SELECTOR AST node.\n const node = ASTNodeFactories.SELECTOR();\n\n // Push the SELECTOR node into the current scope.\n currentScope.push(node);\n\n // Try to pick any attributes off of the token stack.\n node.attributes = getAttributes(tokens, placeholders);\n\n popAndCheck(tokens, \"{\");\n\n // The new scope is that of the new SELECTOR nodes children.\n stack.push(node.children!);\n break;\n }\n\n case \"SEQUENCE\": {\n // Create a SEQUENCE AST node.\n const node = ASTNodeFactories.SEQUENCE();\n\n // Push the SEQUENCE node into the current scope.\n currentScope.push(node);\n\n // Try to pick any attributes off of the token stack.\n node.attributes = getAttributes(tokens, placeholders);\n\n popAndCheck(tokens, \"{\");\n\n // The new scope is that of the new SEQUENCE nodes children.\n stack.push(node.children!);\n break;\n }\n\n case \"PARALLEL\": {\n // Create a PARALLEL AST node.\n const node = ASTNodeFactories.PARALLEL();\n\n // Push the PARALLEL node into the current scope.\n currentScope.push(node);\n\n // Try to pick any attributes off of the token stack.\n node.attributes = getAttributes(tokens, placeholders);\n\n popAndCheck(tokens, \"{\");\n\n // The new scope is that of the new PARALLEL nodes children.\n stack.push(node.children!);\n break;\n }\n\n case \"LOTTO\": {\n // Create a LOTTO AST node.\n const node = ASTNodeFactories.LOTTO();\n\n // Push the LOTTO node into the current scope.\n currentScope.push(node);\n\n // If the next token is a '[' character then some ticket counts have been defined as arguments.\n if (tokens[0] === \"[\") {\n // Get the ticket count arguments, each argument must be a number.\n node.tickets = getArguments(\n tokens,\n placeholders,\n (arg) => arg.type === \"number\" && !!arg.isInteger,\n \"lotto node ticket counts must be integer values\"\n ).map((argument) => argument.value as number);\n }\n\n // Try to pick any attributes off of the token stack.\n node.attributes = getAttributes(tokens, placeholders);\n\n popAndCheck(tokens, \"{\");\n\n // The new scope is that of the new LOTTO nodes children.\n stack.push(node.children!);\n break;\n }\n\n case \"CONDITION\": {\n // Create a CONDITION AST node.\n const node = ASTNodeFactories.CONDITION();\n\n // Push the CONDITION node into the current scope.\n currentScope.push(node);\n\n // We must have arguments defined, as we require a condition function name argument.\n if (tokens[0] !== \"[\") {\n throw new Error(\"expected condition name identifier argument\");\n }\n\n // Grab the condition node arguments.\n const conditionArguments = getArguments(tokens, placeholders);\n\n // We should have at least a single identifier argument for a condition node, which is the condition function name.\n if (conditionArguments.length && conditionArguments[0].type === \"identifier\") {\n // The condition function name will be the first node argument.\n node.conditionName = conditionArguments.shift()!.value as string;\n } else {\n throw new Error(\"expected condition name identifier argument\");\n }\n\n // Only the first argument should have been an identifier, all following arguments must be string, number, boolean or null.\n conditionArguments\n .filter((arg) => arg.type === \"identifier\")\n .forEach((arg) => {\n throw new Error(\n \"invalid condition node argument value '\" +\n arg.value +\n \"', must be string, number, boolean or null\"\n );\n });\n\n // Any node arguments that follow the condition name identifier will be treated as condition function arguments.\n node.conditionArguments = conditionArguments;\n\n // Try to pick any attributes off of the token stack.\n node.attributes = getAttributes(tokens, placeholders);\n break;\n }\n\n case \"FLIP\": {\n // Create a FLIP AST node.\n const node = ASTNodeFactories.FLIP();\n\n // Push the Flip node into the current scope.\n currentScope.push(node);\n\n // Try to pick any attributes off of the token stack.\n node.attributes = getAttributes(tokens, placeholders);\n\n popAndCheck(tokens, \"{\");\n\n // The new scope is that of the new FLIP nodes children.\n stack.push(node.children!);\n break;\n }\n\n case \"SUCCEED\": {\n // Create a SUCCEED AST node.\n const node = ASTNodeFactories.SUCCEED();\n\n // Push the Succeed node into the current scope.\n currentScope.push(node);\n\n // Try to pick any attributes off of the token stack.\n node.attributes = getAttributes(tokens, placeholders);\n\n popAndCheck(tokens, \"{\");\n\n // The new scope is that of the new Succeed nodes children.\n stack.push(node.children!);\n break;\n }\n\n case \"FAIL\": {\n // Create a FAIL AST node.\n const node = ASTNodeFactories.FAIL();\n\n // Push the Fail node into the current scope.\n currentScope.push(node);\n\n // Try to pick any attributes off of the token stack.\n node.attributes = getAttributes(tokens, placeholders);\n\n popAndCheck(tokens, \"{\");\n\n // The new scope is that of the new Fail nodes children.\n stack.push(node.children!);\n break;\n }\n\n case \"WAIT\": {\n // Create a WAIT AST node.\n const node = ASTNodeFactories.WAIT();\n\n // Push the WAIT node into the current scope.\n currentScope.push(node);\n\n // The arguments of a wait node are optional. We may have:\n // - No node arguments, in which case the wait will be indefinite until it is aborted.\n // - One node argument which will be the explicit duration of the wait.\n // - Two node arguments which define the min and max duration bounds from which a random duration will be picked.\n if (tokens[0] === \"[\") {\n // Get the optional duration and longest duration of the wait.\n const nodeArguments = getArguments(\n tokens,\n placeholders,\n (arg) => arg.type === \"number\" && !!arg.isInteger,\n \"wait node durations must be integer values\"\n ).map((argument) => argument.value);\n\n // We may have:\n // - One node argument which will be the explicit duration of the wait.\n // - Two node arguments which define the min and max duration bounds from which a random duration will be picked.\n // - Too many arguments, which is not valid.\n if (nodeArguments.length === 1) {\n // An explicit duration was defined.\n node.duration = nodeArguments[0] as number;\n } else if (nodeArguments.length === 2) {\n // Min and max duration bounds were defined from which a random duration will be picked.\n node.durationMin = nodeArguments[0] as number;\n node.durationMax = nodeArguments[1] as number;\n } else if (nodeArguments.length > 2) {\n // An incorrect number of durations was defined.\n throw new Error(\"invalid number of wait node duration arguments defined\");\n }\n }\n\n // Try to pick any attributes off of the token stack.\n node.attributes = getAttributes(tokens, placeholders);\n break;\n }\n\n case \"REPEAT\": {\n // Create a REPEAT AST node.\n const node = ASTNodeFactories.REPEAT();\n\n // Push the REPEAT node into the current scope.\n currentScope.push(node);\n\n // The arguments of a repeat node are optional. We may have:\n // - No node arguments, in which case the repeat note will iterate indefinitely.\n // - One node argument which will be the explicit number of iterations to make.\n // - Two node arguments which define the min and max iteration bounds from which a random iteration count will be picked.\n if (tokens[0] === \"[\") {\n // An iteration count has been defined. Get the iteration and potential maximum iteration of the wait.\n const nodeArguments = getArguments(\n tokens,\n placeholders,\n (arg) => arg.type === \"number\" && !!arg.isInteger,\n \"repeat node iteration counts must be integer values\"\n ).map((argument) => argument.value);\n\n // We should have got one or two iteration counts.\n if (nodeArguments.length === 1) {\n // A static iteration count was defined.\n node.iterations = nodeArguments[0] as number;\n } else if (nodeArguments.length === 2) {\n // A minimum and maximum iteration count was defined.\n node.iterationsMin = nodeArguments[0] as number;\n node.iterationsMax = nodeArguments[1] as number;\n } else {\n // An incorrect number of iteration counts was defined.\n throw new Error(\"invalid number of repeat node iteration count arguments defined\");\n }\n }\n\n // Try to pick any attributes off of the token stack.\n node.attributes = getAttributes(tokens, placeholders);\n\n popAndCheck(tokens, \"{\");\n\n // The new scope is that of the new REPEAT nodes children.\n stack.push(node.children!);\n break;\n }\n\n case \"RETRY\": {\n // Create a RETRY AST node.\n const node = ASTNodeFactories.RETRY();\n\n // Push the RETRY node into the current scope.\n currentScope.push(node);\n\n // The arguments of a retry node are optional. We may have:\n // - No node arguments, in which case the retry note will attempt indefinitely.\n // - One node argument which will be the explicit number of attempts to make.\n // - Two node arguments which define the min and max attempt bounds from which a random attempt count will be picked.\n if (tokens[0] === \"[\") {\n // An attempt count has been defined. Get the attempt count and potential maximum attempt count of the wait.\n const nodeArguments = getArguments(\n tokens,\n placeholders,\n (arg) => arg.type === \"number\" && !!arg.isInteger,\n \"retry node attempt counts must be integer values\"\n ).map((argument) => argument.value);\n\n // We should have got one or two attempt counts.\n if (nodeArguments.length === 1) {\n // A static attempt count was defined.\n node.attempts = nodeArguments[0] as number;\n } else if (nodeArguments.length === 2) {\n // A minimum and maximum attempt count was defined.\n node.attemptsMin = nodeArguments[0] as number;\n node.attemptsMax = nodeArguments[1] as number;\n } else {\n // An incorrect number of attempt counts was defined.\n throw new Error(\"invalid number of retry node attempt count arguments defined\");\n }\n }\n\n // Try to pick any attributes off of the token stack.\n node.attributes = getAttributes(tokens, placeholders);\n\n popAndCheck(tokens, \"{\");\n\n // The new scope is that of the new RETRY nodes children.\n stack.push(node.children!);\n break;\n }\n\n case \"ACTION\": {\n // Create a ACTION AST node.\n const node = ASTNodeFactories.ACTION();\n\n // Push the ACTION node into the current scope.\n currentScope.push(node);\n\n // We must have arguments defined, as we require an action name argument.\n if (tokens[0] !== \"[\") {\n throw new Error(\"expected action name identifier argument\");\n }\n\n // The action name will be defined as a node argument.\n const actionArguments = getArguments(tokens, placeholders);\n\n // We should have at least one identifer argument for an action node, which is the action name.\n if (actionArguments.length && actionArguments[0].type === \"identifier\") {\n // The action name will be the first and only node argument.\n node.actionName = actionArguments.shift()!.value as string;\n } else {\n throw new Error(\"expected action name identifier argument\");\n }\n\n // Only the first argument should have been an identifier, all following arguments must be string, number, boolean or null.\n actionArguments\n .filter((arg) => arg.type === \"identifier\")\n .forEach((arg) => {\n throw new Error(\n \"invalid action node argument value '\" +\n arg.value +\n \"', must be string, number, boolean or null\"\n );\n });\n\n // Any node arguments that follow the action name identifier will be treated as action function arguments.\n node.actionArguments = actionArguments;\n\n // Try to pick any attributes off of the token stack.\n node.attributes = getAttributes(tokens, placeholders);\n break;\n }\n\n case \"}\": {\n // The '}' character closes the current scope.\n stack.pop();\n break;\n }\n\n default: {\n throw new Error(`unexpected token '${token}'`);\n }\n }\n }\n\n // A function to recursively validate each of the nodes in the AST.\n const validateASTNode = (node: Validatable, depth: number): void => {\n // Validate the node.\n node.validate(depth);\n\n // Validate each child of the node.\n (node.children || []).forEach((child) => validateASTNode(child, depth + 1));\n };\n\n // Start node validation from the definition root.\n validateASTNode(\n {\n children: stack[0] as RootAstNode[],\n validate(this: { children: RootAstNode[] }) {\n // We must have at least one node defined as the definition scope, which should be a root node.\n if (this.children.length === 0) {\n throw new Error(\"expected root node to have been defined\");\n }\n\n // Each node at the base of the definition scope MUST be a root node.\n for (const definitionLevelNode of this.children) {\n if (definitionLevelNode.type !== \"root\") {\n throw new Error(\"expected root node at base of definition\");\n }\n }\n\n // Exactly one root node must not have a name defined. This will be the main root, others will have to be referenced via branch nodes.\n if (this.children.filter((definitionLevelNode) => definitionLevelNode.name === null).length !== 1) {\n throw new Error(\"expected single unnamed root node at base of definition to act as main root\");\n }\n\n // No two named root nodes can have matching names.\n const rootNodeNames: string[] = [];\n for (const definitionLevelNode of this.children) {\n if (rootNodeNames.indexOf(definitionLevelNode.name!) !== -1) {\n throw new Error(`multiple root nodes found with duplicate name '${definitionLevelNode.name}'`);\n } else {\n rootNodeNames.push(definitionLevelNode.name!);\n }\n }\n }\n },\n 0\n );\n\n // Return the root AST nodes.\n return stack[0];\n}\n\n/**\n * Pop the next raw token off of the stack and throw an error if it wasn't the expected one.\n * @param tokens The array of remaining tokens.\n * @param expected An optional string or array or items, one of which must match the next popped token.\n * @returns The popped token.\n */\nfunction popAndCheck(tokens: string[], expected: string | string[]) {\n // Get and remove the next token.\n const popped = tokens.shift();\n\n // We were expecting another token.\n if (popped === undefined) {\n throw new Error(\"unexpected end of definition\");\n }\n\n // Do we have an expected token/tokens array?\n if (expected !== undefined) {\n // Check whether the popped token matches at least one of our expected items.\n var tokenMatchesExpectation = ([] as string[])\n .concat(expected)\n .some((item) => popped.toUpperCase() === item.toUpperCase());\n\n // Throw an error if the popped token didn't match any of our expected items.\n if (!tokenMatchesExpectation) {\n const expectationString = ([] as string[])\n .concat(expected)\n .map((item) => \"'\" + item + \"'\")\n .join(\" or \");\n\n throw new Error(`unexpected token found. Expected '${expectationString}' but got '${popped}'`);\n }\n }\n\n // Return the popped token.\n return popped;\n}\n\ntype StringPlaceholders = { [key: string]: string };\n\n/**\n * Pull an argument definition list off of the token stack.\n * @param tokens The array of remaining tokens.\n * @param stringArgumentPlaceholders The mapping of string literal node argument placeholders to original values.\n * @param argumentValidator The argument validator function.\n * @param validationFailedMessage The exception message to throw if argument validation fails.\n * @returns The argument definition list.\n */\nfunction getArguments(\n tokens: string[],\n stringArgumentPlaceholders: StringPlaceholders,\n argumentValidator?: (arg: AnyArgument) => boolean,\n validationFailedMessage?: string\n) {\n // Any lists of arguments will always be wrapped in '[]' for node arguments or '()' for attribute arguments.\n // We are looking for a '[' or '(' opener that wraps the argument tokens and the relevant closer.\n const closer = popAndCheck(tokens, [\"[\", \"(\"]) === \"[\" ? \"]\" : \")\";\n\n const argumentListTokens: string[] = [];\n const argumentList: AnyArgument[] = [];\n\n // Grab all tokens between the '[' and ']' or '(' and ')'.\n while (tokens.length && tokens[0] !== closer) {\n // The next token is part of our arguments list.\n argumentListTokens.push(tokens.shift()!);\n }\n\n // Validate the order of the argument tokens. Each token must either be a ',' or a single argument that satisfies the validator.\n argumentListTokens.forEach((token, index) => {\n // Get whether this token should be an actual argument.\n const shouldBeArgumentToken = !(index & 1);\n\n // If the current token should be an actual argument then validate it,otherwise it should be a ',' token.\n if (shouldBeArgumentToken) {\n // Get the argument definition.\n const argumentDefinition = getArgumentDefinition(token!, stringArgumentPlaceholders);\n\n // Try to validate the argument.\n if (argumentValidator && !argumentValidator(argumentDefinition)) {\n throw new Error(validationFailedMessage);\n }\n\n // This is a valid argument!\n argumentList.push(argumentDefinition);\n } else {\n // The current token should be a ',' token.\n if (token !== \",\") {\n throw new Error(`invalid argument list, expected ',' or ']' but got '${token}'`);\n }\n }\n });\n\n // The arguments list should terminate with a ']' or ')' token, depending on the opener.\n popAndCheck(tokens, closer);\n\n // Return the argument list.\n return argumentList;\n}\n\n/**\n * Gets an argument value definition.\n * @param token The argument token.\n * @param stringArgumentPlaceholders The mapping of string literal node argument placeholders to original values.\n * @returns An argument value definition.\n */\nfunction getArgumentDefinition(token: string, stringArgumentPlaceholders: StringPlaceholders): AnyArgument {\n // Check whether the token represents a null value.\n if (token === \"null\") {\n return {\n value: null,\n type: \"null\"\n } as NullArgument;\n }\n\n // Check whether the token represents a boolean value.\n if (token === \"true\" || token === \"false\") {\n return {\n value: token === \"true\",\n type: \"boolean\"\n } as BooleanArgument;\n }\n\n // Check whether the token represents a number value.\n // TODO: Relies on broken isNaN - see MDN.\n // if (!Number.isNaN(token)) {\n if (!isNaN(token as any)) {\n return {\n value: parseFloat(token),\n isInteger: parseFloat(token) === parseInt(token, 10),\n type: \"number\"\n } as NumberArgument;\n }\n\n // Check whether the token is a placeholder (e.g. @@0@@) representing a string literal.\n if (token.match(/^@@\\d+@@$/g)) {\n return {\n value: stringArgumentPlaceholders[token].replace('\\\\\"', '\"'),\n type: \"string\"\n } as StringPlaceholderArgument;\n }\n\n // The only remaining option is that the argument value is an identifier.\n return {\n value: token,\n type: \"identifier\"\n } as IdentifierArgument;\n}\n\n/**\n * Pull any attributes off of the token stack.\n * @param tokens The array of remaining tokens.\n * @param stringArgumentPlaceholders The mapping of string literal node argument placeholders to original values.\n * @returns An array of attributes defined by any directly following tokens.\n */\nfunction getAttributes(tokens: string[], stringArgumentPlaceholders: StringPlaceholders) {\n // Create an array to hold any attributes found.\n const attributes: Attribute[] = [];\n\n // Keep track of names of attribute that we have found on the token stack, as we cannot have duplicates.\n const attributesFound: string[] = [];\n\n // Try to get the attribute factory for the next token.\n let attributeFactory = AttributeFactories[(tokens[0] || \"\").toUpperCase()];\n\n // Pull attribute tokens off of the tokens stack until we have no more.\n while (attributeFactory) {\n // Check to make sure that we have not already created a attribute of this type for this node.\n if (attributesFound.indexOf(tokens[0].toUpperCase()) !== -1) {\n throw new Error(`duplicate attribute '${tokens[0].toUpperCase()}' found for node`);\n }\n\n // Add the current attribute type to our array of found attributes.\n attributesFound.push(tokens.shift()!.toUpperCase());\n\n // Grab any attribute arguments.\n const attributeArguments = getArguments(tokens, stringArgumentPlaceholders);\n\n // The first attribute argument has to be an identifer, this will reference an agent function.\n if (attributeArguments.length === 0 || attributeArguments[0].type !== \"identifier\") {\n throw new Error(\"expected agent function name identifier argument for attribute\");\n }\n\n // Grab the first attribute which is an identifier that will reference an agent function.\n const attributeFunctionName = attributeArguments.shift()! as IdentifierArgument;\n\n // Any remaining attribute arguments must have a type of string, number, boolean or null.\n attributeArguments\n .filter((arg) => arg.type === \"identifier\")\n .forEach((arg) => {\n throw new Error(\n \"invalid attribute argument value '\" + arg.value + \"', must be string, number, boolean or null\"\n );\n });\n\n // Create the attribute and add it to the array of attributes found.\n attributes.push(attributeFactory(attributeFunctionName.value, attributeArguments));\n\n // Try to get the next attribute name token, as there could be multiple.\n attributeFactory = AttributeFactories[(tokens[0] || \"\").toUpperCase()];\n }\n\n return attributes;\n}\n\n/**\n * Swaps out any node/attribute argument string literals with placeholders.\n * @param definition The definition.\n * @returns An object containing a mapping of placeholders to original string values as well as the processed definition string.\n */\nfunction substituteStringLiterals(definition: string): {\n placeholders: { [key: string]: string };\n processedDefinition: string;\n} {\n // Create an object to hold the mapping of placeholders to original string values.\n const placeholders: StringPlaceholders = {};\n\n // Replace any string literals wrapped with double quotes in our definition with placeholders to be processed later.\n const processedDefinition = definition.replace(/\\\"(\\\\.|[^\"\\\\])*\\\"/g, (match) => {\n var strippedMatch = match.substring(1, match.length - 1);\n var placeholder = Object.keys(placeholders).find((key) => placeholders[key] === strippedMatch);\n\n // If we have no existing string literal match then create a new placeholder.\n if (!placeholder) {\n placeholder = `@@${Object.keys(placeholders).length}@@`;\n placeholders[placeholder] = strippedMatch;\n }\n\n return placeholder;\n });\n\n return { placeholders, processedDefinition };\n}\n\n/**\n * Parse the tree definition into an array of raw tokens.\n * @param definition The definition.\n * @returns An array of tokens parsed from the definition.\n */\nfunction parseTokensFromDefinition(definition: string): string[] {\n // Add some space around various important characters so that they can be plucked out easier as individual tokens.\n definition = definition.replace(/\\(/g, \" ( \");\n definition = definition.replace(/\\)/g, \" ) \");\n definition = definition.replace(/\\{/g, \" { \");\n definition = definition.replace(/\\}/g, \" } \");\n definition = definition.replace(/\\]/g, \" ] \");\n definition = definition.replace(/\\[/g, \" [ \");\n definition = definition.replace(/\\,/g, \" , \");\n\n // Split the definition into raw token form and return it.\n return definition.replace(/\\s+/g, \" \").trim().split(\" \");\n}\n", "import GuardPath, { GuardPathPart } from \"./attributes/guards/GuardPath\";\nimport buildRootASTNodes, { AnyArgument, RootAstNode } from \"./RootAstNodesBuilder\";\nimport State, { AnyState } from \"./State\";\nimport Lookup from \"./Lookup\";\nimport Node from \"./nodes/Node\";\nimport Root from \"./nodes/decorator/Root\";\nimport Composite from \"./nodes/composite/Composite\";\nimport Decorator from \"./nodes/decorator/Decorator\";\nimport { Agent, GlobalFunction } from \"./Agent\";\nimport { CallbackAttributeDetails } from \"./attributes/callbacks/Callback\";\nimport { GuardAttributeDetails } from \"./attributes/guards/Guard\";\nimport { BehaviourTreeOptions } from \"./BehaviourTreeOptions\";\nimport { convertMDSLToJSON } from \"./mdsl/MDSLDefinitionParser\";\n\n// Purely for outside inspection of the tree.\nexport type FlattenedTreeNode = {\n id: string;\n type: string;\n caption: string;\n state: AnyState;\n guards: GuardAttributeDetails[];\n callbacks: CallbackAttributeDetails[];\n args: AnyArgument[];\n parentId: string | null;\n};\n\n/**\n * A representation of a behaviour tree.\n */\nexport class BehaviourTree {\n /**\n * The main root tree node.\n */\n public readonly rootNode: Root;\n\n /**\n * Creates a new instance of the BehaviourTree class.\n * @param definition The behaviour tree definition.\n * @param agent The agent instance that this behaviour tree is modelling behaviour for.\n * @param options The behaviour tree options object.\n */\n constructor(definition: string, private agent: Agent, private options: BehaviourTreeOptions = {}) {\n // The tree definition must be defined and a valid string.\n if (typeof definition !== \"string\") {\n throw new Error(\"the tree definition must be a string\");\n }\n\n // The agent must be defined and not null.\n if (typeof agent !== \"object\" || agent === null) {\n throw new Error(\"the agent must be defined and not null\");\n }\n\n // Parse the behaviour tree definition, create the populated tree of behaviour tree nodes, and get the root.\n this.rootNode = BehaviourTree._createRootNode(definition);\n }\n\n /**\n * Gets whether the tree is in the RUNNING state.\n * @returns true if the tree is in the RUNNING state, otherwise false.\n */\n isRunning() {\n return this.rootNode.getState() === State.RUNNING;\n }\n\n /**\n * Gets the current tree state of SUCCEEDED, FAILED, READY or RUNNING.\n * @returns The current tree state.\n */\n getState() {\n return this.rootNode.getState();\n }\n\n /**\n * Step the tree.\n * 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.\n * 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\n * 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.\n *\n * 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.\n */\n step() {\n // If the root node has already been stepped to completion then we need to reset it.\n if (this.rootNode.getState() === State.SUCCEEDED || this.rootNode.getState() === State.FAILED) {\n this.rootNode.reset();\n }\n\n try {\n this.rootNode.update(this.agent, this.options);\n } catch (exception) {\n throw new Error(`error stepping tree: ${(exception as Error).message}`);\n }\n }\n\n /**\n * Resets the tree from the root node outwards to each nested node, giving each a state of READY.\n */\n reset() {\n this.rootNode.reset();\n }\n\n /**\n * Gets the flattened details of every node in the tree.\n * @returns The flattened details of every node in the tree.\n */\n getFlattenedNodeDetails(): FlattenedTreeNode[] {\n // Create an empty flattened array of tree nodes.\n const flattenedTreeNodes: FlattenedTreeNode[] = [];\n\n /**\n * Helper function to process a node instance and push details into the flattened tree nodes array.\n * @param node The current node.\n * @param parentUid The UID of the node parent, or null if the node is the main root node.\n */\n const processNode = (node: Node, parentUid: string | null) => {\n // Get the guard and callback attribute details for this node.\n const guards = node\n .getAttributes()\n .filter((attribute) => attribute.isGuard())\n .map((attribute) => attribute.getDetails()) as GuardAttributeDetails[];\n const callbacks = node\n .getAttributes()\n .filter((attribute) => !attribute.isGuard())\n .map((attribute) => attribute.getDetails()) as CallbackAttributeDetails[];\n\n // Push the current node into the flattened nodes array.\n flattenedTreeNodes.push({\n id: node.getUid(),\n type: node.getType(),\n caption: node.getName(),\n state: node.getState(),\n guards,\n callbacks,\n args: node.getArguments(),\n parentId: parentUid\n });\n\n // Process each of the nodes children if it is not a leaf node.\n if (!node.isLeafNode()) {\n (node as Composite | Decorator)\n .getChildren()\n .forEach((child) => processNode(child, (node as Composite | Decorator).getUid()));\n }\n };\n\n // Convert the nested node structure into a flattened array of node details.\n processNode(this.rootNode, null);\n\n return flattenedTreeNodes;\n }\n\n /**\n * Registers the action/condition/guard/callback function or subtree with the given name.\n * @param name The name of the function or subtree to register.\n * @param value The function or subtree definition to register.\n */\n static register(name: string, value: GlobalFunction | string) {\n if (typeof value === \"function\") {\n // We are going to register a action/condition/guard/callback function.\n Lookup.setFunc(name, value);\n } else if (typeof value === \"string\") {\n // We are going to register a subtree.\n let rootASTNodes: RootAstNode[];\n\n try {\n // Try to create the behaviour tree AST based on the definition provided, this could fail if the definition is invalid.\n rootASTNodes = buildRootASTNodes(value);\n } catch (exception) {\n // There was an issue in trying to parse and build the tree definition.\n throw new Error(`error registering definition: ${(exception as Error).message}`);\n }\n\n // This function should only ever be called with a definition containing a single unnamed root node.\n if (rootASTNodes.length != 1 || rootASTNodes[0].name !== null) {\n throw new Error(\"error registering definition: expected a single unnamed root node\");\n }\n\n Lookup.setSubtree(name, rootASTNodes[0]);\n } else {\n throw new Error(\"unexpected value, expected string definition or function\");\n }\n }\n\n /**\n * Unregisters the registered action/condition/guard/callback function or subtree with the given name.\n * @param name The name of the registered action/condition/guard/callback function or subtree to unregister.\n */\n static unregister(name: string): void {\n Lookup.remove(name);\n }\n\n /**\n * Unregister all registered action/condition/guard/callback functions and subtrees.\n */\n static unregisterAll(): void {\n Lookup.empty();\n }\n\n /**\n * Parses a behaviour tree definition and creates a tree of behaviour tree nodes.\n * @param {string} definition The behaviour tree definition.\n * @returns The root behaviour tree node.\n */\n private static _createRootNode(definition: string): Root {\n // TODO Remove!\n try {\n // parseToJSON(definition);\n } catch (exception) {\n console.log(exception);\n }\n\n try {\n // Try to create the behaviour tree AST based on the definition provided, this could fail if the definition is invalid.\n const rootASTNodes = buildRootASTNodes(definition);\n\n // Create a symbol to use as the main root key in our root node mapping.\n const mainRootNodeKey = Symbol(\"__root__\");\n\n // Create a mapping of root node names to root AST tokens. The main root node will have a key of Symbol(\"__root__\").\n const rootNodeMap: { [key: string | symbol]: RootAstNode } = {};\n for (const rootASTNode of rootASTNodes) {\n rootNodeMap[rootASTNode.name === null ? mainRootNodeKey : rootASTNode.name!] = rootASTNode;\n }\n\n // Convert the AST to our actual tree and get the root node.\n const rootNode: Root = rootNodeMap[mainRootNodeKey].createNodeInstance(\n // Create a provider for named root nodes that are part of our definition or have been registered. Prioritising the former.\n (name: string): RootAstNode => (rootNodeMap[name] ? rootNodeMap[name] : Lookup.getSubtree(name)),\n []\n );\n\n // Set a guard path on every leaf of the tree to evaluate as part of its update.\n BehaviourTree._applyLeafNodeGuardPaths(rootNode);\n\n // Return the root node.\n return rootNode;\n } catch (exception) {\n // There was an issue in trying to parse and build the tree definition.\n throw new Error(`error parsing tree: ${(exception as Error).message}`);\n }\n }\n\n /**\n * Applies a guard path to every leaf of the tree to evaluate as part of each update.\n * @param rootNode The main root tree node.\n */\n private static _applyLeafNodeGuardPaths(rootNode: Root) {\n const nodePaths: Node[][] = [];\n\n const findLeafNodes = (path: Node[], node: Node) => {\n // Add the current node to the path.\n path = path.concat(node);\n\n // Check whether the current node is a leaf node.\n if (node.isLeafNode()) {\n nodePaths.push(path);\n } else {\n (node as Composite | Decorator).getChildren().forEach((child) => findLeafNodes(path, child));\n }\n };\n\n // Find all leaf node paths, starting from the root.\n findLeafNodes([], rootNode);\n\n nodePaths.forEach((path) => {\n // Each node in the current path will have to be assigned a guard path, working from the root outwards.\n for (let depth = 0; depth < path.length; depth++) {\n // Get the node in the path at the current depth.\n const currentNode = path[depth];\n\n // The node may already have been assigned a guard path, if so just skip it.\n if (currentNode.hasGuardPath()) {\n continue;\n }\n\n // Create the guard path for the current node.\n const guardPath = new GuardPath(\n path\n .slice(0, depth + 1)\n .map((node) => ({ node, guards: node.getGuardAttributes() }))\n .filter((details) => details.guards.length > 0)\n );\n\n // Assign the guard path to the current node.\n currentNode.setGuardPath(guardPath);\n }\n });\n }\n}\n"], + "mappings": "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", "names": ["Participant", "Lotto", "createLotto", "State", "createLotto", "substituteStringLiterals", "parseTokensFromDefinition", "popAndCheck", "getArgumentDefinition"] } diff --git a/dist/index.js b/dist/index.js index 4026ca4..07402bf 100644 --- a/dist/index.js +++ b/dist/index.js @@ -722,45 +722,77 @@ function createBranchNode(tokens, stringLiteralPlaceholders) { // src/BehaviourTreeDefinitionValidator.ts function validateDefinition(definition) { - const createFailureResult = (errorMessage) => ({ succeeded: false, errorMessage }); if (definition === null || typeof definition === "undefined") { - return createFailureResult("definition is null or undefined"); + return createValidationFailureResult("definition is null or undefined"); } - let rootNodeDefinitions; if (typeof definition === "string") { - try { - rootNodeDefinitions = convertMDSLToJSON(definition); - } catch (error) { - return createFailureResult(`invalid mdsl: ${definition}`); - } + return validateMDSLDefinition(definition); } else if (typeof definition === "object") { - rootNodeDefinitions = Array.isArray(definition) ? definition : [definition]; + return validateJSONDefinition(definition); } else { - return createFailureResult(`unexpected definition type of '${typeof definition}'`); + return createValidationFailureResult(`unexpected definition type of '${typeof definition}'`); + } +} +function validateMDSLDefinition(definition) { + let rootNodeDefinitions; + try { + rootNodeDefinitions = convertMDSLToJSON(definition); + } catch (error) { + return createValidationFailureResult(`invalid MDSL: ${definition}`); + } + const mainRootNodeDefinitions = rootNodeDefinitions.filter(({ id }) => typeof id === "undefined"); + const subRootNodeDefinitions = rootNodeDefinitions.filter(({ id }) => typeof id === "string" && id.length > 0); + if (mainRootNodeDefinitions.length !== 1) { + return createValidationFailureResult( + "expected single unnamed root node at base of definition to act as main root" + ); + } + const subRootNodeIdenitifers = []; + for (const { id } of subRootNodeDefinitions) { + if (subRootNodeIdenitifers.includes(id)) { + return createValidationFailureResult(`multiple root nodes found with duplicate name '${id}'`); + } + subRootNodeIdenitifers.push(id); } + const circularDependencyPath = findBranchCircularDependencyPath(rootNodeDefinitions); + if (circularDependencyPath) { + return createValidationFailureResult( + `circular dependency found in branch node references: ${circularDependencyPath}` + ); + } + return { succeeded: true }; +} +function validateJSONDefinition(definition) { + const rootNodeDefinitions = Array.isArray(definition) ? definition : [definition]; try { rootNodeDefinitions.forEach((rootNodeDefinition) => validateNode(rootNodeDefinition, 0)); } catch (error) { if (error instanceof Error) { - return createFailureResult(error.message); + return createValidationFailureResult(error.message); } - return createFailureResult(`unexpected error: ${error}`); + return createValidationFailureResult(`unexpected error: ${error}`); } const mainRootNodeDefinitions = rootNodeDefinitions.filter(({ id }) => typeof id === "undefined"); const subRootNodeDefinitions = rootNodeDefinitions.filter(({ id }) => typeof id === "string" && id.length > 0); if (mainRootNodeDefinitions.length !== 1) { - return createFailureResult("expected single root node without 'id' property defined to act as main root"); + return createValidationFailureResult( + "expected single root node without 'id' property defined to act as main root" + ); } const subRootNodeIdenitifers = []; for (const { id } of subRootNodeDefinitions) { if (subRootNodeIdenitifers.includes(id)) { - return createFailureResult(`multiple root nodes found with duplicate 'id' property value of '${id}'`); + return createValidationFailureResult( + `multiple root nodes found with duplicate 'id' property value of '${id}'` + ); } subRootNodeIdenitifers.push(id); } const circularDependencyPath = findBranchCircularDependencyPath(rootNodeDefinitions); if (circularDependencyPath) { - return createFailureResult(`circular dependency found in branch node references: ${circularDependencyPath}`); + return createValidationFailureResult( + `circular dependency found in branch node references: ${circularDependencyPath}` + ); } return { succeeded: true }; } @@ -1051,6 +1083,9 @@ function validateParallelNode(definition, depth) { validateNodeAttributes(definition, depth); definition.children.forEach((child) => validateNode(child, depth + 1)); } +function createValidationFailureResult(errorMessage) { + return { succeeded: false, errorMessage }; +} // src/attributes/guards/GuardUnsatisifedException.ts var GuardUnsatisifedException = class extends Error { diff --git a/dist/index.js.map b/dist/index.js.map index 25a98d2..8ab89ad 100644 --- a/dist/index.js.map +++ b/dist/index.js.map @@ -1,7 +1,7 @@ { "version": 3, "sources": ["../node_modules/lotto-draw/dist/Participant.js", "../node_modules/lotto-draw/dist/Utilities.js", "../node_modules/lotto-draw/dist/Lotto.js", "../node_modules/lotto-draw/dist/createLotto.js", "../node_modules/lotto-draw/dist/index.js", "../src/index.ts", "../src/State.ts", "../src/BehaviourTreeDefinitionUtilities.ts", "../src/mdsl/MDSLUtilities.ts", "../src/mdsl/MDSLNodeArgumentParser.ts", "../src/mdsl/MDSLNodeAttributeParser.ts", "../src/mdsl/MDSLDefinitionParser.ts", "../src/BehaviourTreeDefinitionValidator.ts", "../src/attributes/guards/GuardUnsatisifedException.ts", "../src/attributes/guards/GuardPath.ts", "../src/nodes/Node.ts", "../src/nodes/leaf/Leaf.ts", "../src/Lookup.ts", "../src/nodes/leaf/Action.ts", "../src/nodes/leaf/Condition.ts", "../src/nodes/leaf/Wait.ts", "../src/nodes/decorator/Decorator.ts", "../src/nodes/decorator/Root.ts", "../src/nodes/decorator/Repeat.ts", "../src/nodes/decorator/Retry.ts", "../src/nodes/decorator/Flip.ts", "../src/nodes/decorator/Succeed.ts", "../src/nodes/decorator/Fail.ts", "../src/nodes/composite/Lotto.ts", "../src/nodes/composite/Composite.ts", "../src/nodes/composite/Selector.ts", "../src/nodes/composite/Sequence.ts", "../src/nodes/composite/Parallel.ts", "../src/attributes/Attribute.ts", "../src/attributes/guards/Guard.ts", "../src/attributes/guards/While.ts", "../src/attributes/guards/Until.ts", "../src/attributes/callbacks/Callback.ts", "../src/attributes/callbacks/Entry.ts", "../src/attributes/callbacks/Exit.ts", "../src/attributes/callbacks/Step.ts", "../src/RootAstNodesBuilder.ts", "../src/BehaviourTree.ts"], - "sourcesContent": ["\"use strict\";\r\nObject.defineProperty(exports, \"__esModule\", { value: true });\r\nexports.Participant = void 0;\r\n/**\r\n * A participant that holds a number of tickets.\r\n */\r\nvar Participant = /** @class */ (function () {\r\n /**\r\n * Creates an instance of the Participant class.\r\n * @param participant The actual participant.\r\n * @param tickets The number of tickets held by the participant.\r\n */\r\n function Participant(participant, tickets) {\r\n if (tickets === void 0) { tickets = 1; }\r\n this._participant = participant;\r\n this._tickets = tickets;\r\n }\r\n Object.defineProperty(Participant.prototype, \"participant\", {\r\n /** Gets the actual participant. */\r\n get: function () {\r\n return this._participant;\r\n },\r\n enumerable: false,\r\n configurable: true\r\n });\r\n Object.defineProperty(Participant.prototype, \"tickets\", {\r\n /** Gets or sets the number of tickets held by the participant. */\r\n get: function () {\r\n return this._tickets;\r\n },\r\n set: function (value) {\r\n this._tickets = value;\r\n },\r\n enumerable: false,\r\n configurable: true\r\n });\r\n return Participant;\r\n}());\r\nexports.Participant = Participant;\r\n", "\"use strict\";\r\nObject.defineProperty(exports, \"__esModule\", { value: true });\r\nexports.isNaturalNumber = exports.isNullOrUndefined = void 0;\r\n/**\r\n * Gets whether the value provided is null or undefined.\r\n * @param value The value to check.\r\n * @returns Whether the value provided is null or undefined.\r\n */\r\nfunction isNullOrUndefined(value) {\r\n return value === null || value === undefined;\r\n}\r\nexports.isNullOrUndefined = isNullOrUndefined;\r\n/**\r\n * Gets whether the value provided is a natural number.\r\n * @param value The value to check.\r\n * @returns Whether the value provided is a natural number.\r\n */\r\nfunction isNaturalNumber(value) {\r\n return typeof value === \"number\" && value >= 1 && Math.floor(value) === value;\r\n}\r\nexports.isNaturalNumber = isNaturalNumber;\r\n", "\"use strict\";\r\nObject.defineProperty(exports, \"__esModule\", { value: true });\r\nexports.Lotto = void 0;\r\nvar Participant_1 = require(\"./Participant\");\r\nvar Utilities_1 = require(\"./Utilities\");\r\n/**\r\n * Represents a lotto consisting of a number of pickable ticket-holding participants.\r\n */\r\nvar Lotto = /** @class */ (function () {\r\n /**\r\n * Creates a new instance of Lotto.\r\n * @param customRandom The custom RNG to use in place of Math.random().\r\n */\r\n function Lotto(customRandom) {\r\n /** The array of participants that are holding tickets in the lotto. */\r\n this._participants = [];\r\n this._customRandom = customRandom;\r\n }\r\n /**\r\n * Adds a participant with the specified number of tickets, or adds to the participant ticket count if the participant already holds tickets.\r\n * @param participant The participant to add or to increase the ticket count for if they already hold tickets.\r\n * @param tickets The number of tickets, defaults to 1.\r\n * @returns The Lotto instance.\r\n */\r\n Lotto.prototype.add = function (participant, tickets) {\r\n if (tickets === void 0) { tickets = 1; }\r\n // Check that we have a valid ticket count.\r\n if (!(0, Utilities_1.isNaturalNumber)(tickets)) {\r\n throw new Error(\"tickets value must be a natural number\");\r\n }\r\n // Check whether this participant has already been added.\r\n var existingParticipant = this._participants.find(function (part) { return part.participant === participant; });\r\n if (existingParticipant) {\r\n // The participant has already been added to the lotto so just add to their ticket count.\r\n existingParticipant.tickets += tickets;\r\n }\r\n else {\r\n // The participant is not part of the lotto so we should add them.\r\n this._participants.push(new Participant_1.Participant(participant, tickets));\r\n }\r\n return this;\r\n };\r\n /**\r\n * Removes the specified number of tickets for the given participant from the draw, or all tickets if a ticket number is not defined.\r\n * @param participant The participant to remove tickets for.\r\n * @param tickets The number of tickets to remove, or undefined if all tickets are to be removed.\r\n * @returns The Lotto instance.\r\n */\r\n Lotto.prototype.remove = function (participant, tickets) {\r\n // Attempt to get the existing participant.\r\n var existingParticipant = this._participants.find(function (part) { return part.participant === participant; });\r\n // There is nothing to do if the specified participant isn't even part of the lotto.\r\n if (!existingParticipant) {\r\n return this;\r\n }\r\n // Check whether a tickets value was given.\r\n if (tickets !== undefined) {\r\n // Check that we have a valid ticket count.\r\n if (!(0, Utilities_1.isNaturalNumber)(tickets)) {\r\n throw new Error(\"tickets value must be a natural number\");\r\n }\r\n existingParticipant.tickets -= tickets;\r\n // If the participant no longer holds any tickets then they should be removed.\r\n if (existingParticipant.tickets < 1) {\r\n this._participants = this._participants.filter(function (part) { return part !== existingParticipant; });\r\n }\r\n }\r\n else {\r\n // We are removing all tickets for the participant so just remove them from the lotto.\r\n this._participants = this._participants.filter(function (part) { return part !== existingParticipant; });\r\n }\r\n return this;\r\n };\r\n /**\r\n * Draw a winning ticket and return the participant that holds the ticket.\r\n * @param options The draw options.\r\n * @returns The participant that holds the winning ticket.\r\n */\r\n Lotto.prototype.draw = function (options) {\r\n if (options === void 0) { options = {}; }\r\n // If we have no participants then just return null.\r\n if (this._participants.length === 0) {\r\n return null;\r\n }\r\n var redrawable = (0, Utilities_1.isNullOrUndefined)(options.redrawable) ? true : options.redrawable;\r\n var pickable = [];\r\n this._participants.forEach(function (_a) {\r\n var participant = _a.participant, tickets = _a.tickets;\r\n for (var ticketCount = 0; ticketCount < tickets; ticketCount++) {\r\n pickable.push(participant);\r\n }\r\n });\r\n var random;\r\n // We need a random floating-point number between 0 (inclusive) and 1 to scale up to pick our winner.\r\n // If a custom random function exists then we should use that or fall back to Math.random().\r\n if (this._customRandom) {\r\n // Call our custom random function to get a random floating-point number.\r\n random = this._customRandom();\r\n // Verify that the result of calling our custom random function is a number between 0 (inclusive) and 1.\r\n if (typeof random !== \"number\" || random < 0 || random >= 1) {\r\n throw new Error(\"the 'random' function provided did not return a number between 0 (inclusive) and 1\");\r\n }\r\n }\r\n else {\r\n // No custom random function was defined so just use good ol' Math.random().\r\n random = Math.random();\r\n }\r\n // Pick a winning participant.\r\n var winner = pickable[Math.floor(random * pickable.length)];\r\n // If the ticket isn't redrawable then we should remove a ticket from the winning participants ticket count.\r\n if (!redrawable) {\r\n this.remove(winner, 1);\r\n }\r\n // Return the winning participant.\r\n return winner;\r\n };\r\n /**\r\n * Draws multiple winning tickets and return an array of the participants that hold the winning tickets.\r\n * @param tickets The number of winning tickets to draw.\r\n * @param options The draw multiple options.\r\n * @returns An array of the participants that hold the winning tickets.\r\n */\r\n Lotto.prototype.drawMultiple = function (tickets, options) {\r\n if (options === void 0) { options = {}; }\r\n var uniqueResults = (0, Utilities_1.isNullOrUndefined)(options.unique) ? false : options.unique;\r\n // Handle cases where the user has asked for zero tickets (no idea why they would do this be we should trust them).\r\n if (tickets === 0) {\r\n return [];\r\n }\r\n // Now that we know out tickets value is not zero we should check that it is a valid natural number.\r\n if (!(0, Utilities_1.isNaturalNumber)(tickets)) {\r\n throw new Error(\"tickets value must be a natural number\");\r\n }\r\n var result = [];\r\n // Keep drawing tickets until we either reach the number of required tickets or we simply run out of tickets to draw.\r\n // We can run out of tickets to draw if 'options.redrawable' is explicity 'false' or we just had no participants when 'drawMultiple' was called.\r\n while (result.length < tickets && this._participants.length > 0) {\r\n result.push(this.draw(options));\r\n }\r\n // If the 'unique' draw option is set then we need to remove duplicates from the result list.\r\n if (uniqueResults) {\r\n // Create an array to store our unique results.\r\n var unique = [];\r\n // Iterate over all of our participants (with potential duplicates) and populate our array of unique values.\r\n for (var _i = 0, result_1 = result; _i < result_1.length; _i++) {\r\n var participant = result_1[_i];\r\n if (unique.indexOf(participant) === -1) {\r\n unique.push(participant);\r\n }\r\n }\r\n result = unique;\r\n }\r\n return result;\r\n };\r\n return Lotto;\r\n}());\r\nexports.Lotto = Lotto;\r\n", "\"use strict\";\r\nObject.defineProperty(exports, \"__esModule\", { value: true });\r\nexports.createLotto = void 0;\r\nvar Lotto_1 = require(\"./Lotto\");\r\n/**\r\n * A function that creates and returns a Lotto instance.\r\n * @param participantsOrOptions An array of initial participants or options relating to the creation of a Lotto instance.\r\n * @returns A new Lotto instance.\r\n */\r\nfunction createLotto(participantsOrOptions) {\r\n // If no initial participants or lotto options were provided as an argument then we can just return a new lotto instance now.\r\n if (!participantsOrOptions) {\r\n return new Lotto_1.Lotto();\r\n }\r\n // Check whether we were provided with an array of initial participants or a lotto options object.\r\n if (Array.isArray(participantsOrOptions)) {\r\n // We are dealing with a pre-defined array of participants.\r\n var participants = participantsOrOptions;\r\n var lotto_1 = new Lotto_1.Lotto();\r\n // If the lotto participants have been defined upfront then we will need to add them all to our lotto instance now.\r\n participants.forEach(function (_a) {\r\n var participant = _a[0], tokens = _a[1];\r\n return lotto_1.add(participant, tokens);\r\n });\r\n // Return the Lotto instance.\r\n return lotto_1;\r\n }\r\n else {\r\n // We are dealing with some lotto options.\r\n var random = participantsOrOptions.random, participants = participantsOrOptions.participants;\r\n // Create a Lotto instance passing the custom RNG function to use in place of Math.random() (which could be undefined).\r\n var lotto_2 = new Lotto_1.Lotto(random);\r\n // If the lotto participants have been defined upfront as part of the options then we will need to add them all to our lotto instance now.\r\n if (participants) {\r\n participants.forEach(function (_a) {\r\n var participant = _a[0], tokens = _a[1];\r\n return lotto_2.add(participant, tokens);\r\n });\r\n }\r\n // Return the Lotto instance.\r\n return lotto_2;\r\n }\r\n}\r\nexports.createLotto = createLotto;\r\n", "\"use strict\";\r\nObject.defineProperty(exports, \"__esModule\", { value: true });\r\nvar createLotto_1 = require(\"./createLotto\");\r\nexports.default = createLotto_1.createLotto;\r\n", "import State from \"./State\";\nimport { validateDefinition } from \"./BehaviourTreeDefinitionValidator\";\nimport { convertMDSLToJSON } from \"./mdsl/MDSLDefinitionParser\";\nimport { BehaviourTree, FlattenedTreeNode } from \"./BehaviourTree\";\n\nexport { BehaviourTree, State, convertMDSLToJSON, validateDefinition };\nexport type { FlattenedTreeNode };\n", "/**\n * Enumeration of node state types.\n */\nexport enum State {\n READY = \"mistreevous.ready\",\n RUNNING = \"mistreevous.running\",\n SUCCEEDED = \"mistreevous.succeeded\",\n FAILED = \"mistreevous.failed\"\n}\n\nexport { State as default };\n\nexport type CompleteState = State.SUCCEEDED | State.FAILED;\nexport type AnyState = State.READY | State.RUNNING | CompleteState;\n", "import {\n NodeDefinition,\n RootNodeDefinition,\n DecoratorNodeDefinition,\n CompositeNodeDefinition,\n AnyNode,\n BranchNodeDefinition\n} from \"./BehaviourTreeDefinition\";\n\n/**\n * A type guard function that returns true if the specified node satisfies the RootNodeDefinition type.\n * @param node The node.\n * @returns A value of true if the specified node satisfies the RootNodeDefinition type.\n */\nexport function isRootNode(node: NodeDefinition): node is RootNodeDefinition {\n return node.type === \"root\";\n}\n\n/**\n * A type guard function that returns true if the specified node satisfies the BranchNodeDefinition type.\n * @param node The node.\n * @returns A value of true if the specified node satisfies the BranchNodeDefinition type.\n */\nexport function isBranchNode(node: NodeDefinition): node is BranchNodeDefinition {\n return node.type === \"branch\";\n}\n\n/**\n * A type guard function that returns true if the specified node satisfies the NodeDefinition type.\n * @param node The node.\n * @returns A value of true if the specified node satisfies the NodeDefinition type.\n */\nexport function isLeafNode(node: NodeDefinition): node is NodeDefinition {\n return [\"branch\", \"action\", \"condition\", \"wait\"].includes(node.type);\n}\n\n/**\n * A type guard function that returns true if the specified node satisfies the DecoratorNodeDefinition type.\n * @param node The node.\n * @returns A value of true if the specified node satisfies the DecoratorNodeDefinition type.\n */\nexport function isDecoratorNode(node: NodeDefinition): node is DecoratorNodeDefinition {\n return [\"root\", \"repeat\", \"retry\", \"flip\", \"succeed\", \"fail\"].includes(node.type);\n}\n\n/**\n * A type guard function that returns true if the specified node satisfies the CompositeNodeDefinition type.\n * @param node The node.\n * @returns A value of true if the specified node satisfies the CompositeNodeDefinition type.\n */\nexport function isCompositeNode(node: NodeDefinition): node is CompositeNodeDefinition {\n return [\"sequence\", \"selector\", \"lotto\", \"parallel\"].includes(node.type);\n}\n\n/**\n * Flatten a node definition into an array of all of its nested node definitions.\n * @param nodeDefinition The node definition to flatten.\n * @returns An array of all of nested node definitions.\n */\nexport function flattenDefinition(nodeDefinition: AnyNode): AnyNode[] {\n const nodes: AnyNode[] = [];\n\n const processNode = (currentNodeDefinition: AnyNode) => {\n nodes.push(currentNodeDefinition);\n\n if (isCompositeNode(currentNodeDefinition)) {\n currentNodeDefinition.children.forEach(processNode);\n } else if (isDecoratorNode(currentNodeDefinition)) {\n processNode(currentNodeDefinition.child);\n }\n };\n\n processNode(nodeDefinition);\n\n return nodes;\n}\n\n/**\n * Determines whether the passed value is an integer.\n * @param value The value to check.\n * @returns Whether the passed value is an integer.\n */\nexport function isInteger(value: unknown): boolean {\n return typeof value === \"number\" && Math.floor(value) === value;\n}\n", "/**\n * A type defining an object that holds a reference to substitued string literals parsed from the definition.\n */\nexport type StringLiteralPlaceholders = { [key: string]: string };\n\n/**\n * Pop the next raw token from the specified array of tokens and throw an error if it wasn't the expected one.\n * @param tokens The array of tokens.\n * @param expected An optional string or array or items, one of which must match the next popped token.\n * @returns The popped token.\n */\nexport function popAndCheck(tokens: string[], expected?: string | string[]): string {\n // Get and remove the next token.\n const popped = tokens.shift();\n\n // We were expecting another token but there aren't any.\n if (popped === undefined) {\n throw new Error(\"unexpected end of definition\");\n }\n\n // Do we have an expected token/tokens array?\n if (expected != undefined) {\n // Get an array of expected values, if the popped token matches any then we are all good.\n const expectedValues = typeof expected === \"string\" ? [expected] : expected;\n\n // Check whether the popped token matches at least one of our expected items.\n var tokenMatchesExpectation = expectedValues.some((item) => popped.toUpperCase() === item.toUpperCase());\n\n // Throw an error if the popped token didn't match any of our expected items.\n if (!tokenMatchesExpectation) {\n const expectationString = expectedValues.map((item) => \"'\" + item + \"'\").join(\" or \");\n throw new Error(\"unexpected token found. Expected \" + expectationString + \" but got '\" + popped + \"'\");\n }\n }\n\n // Return the popped token.\n return popped;\n}\n\n/**\n * Swaps out any node/attribute argument string literals with placeholders.\n * @param definition The definition.\n * @returns An object containing a mapping of placeholders to original string values as well as the processed definition string.\n */\nexport function substituteStringLiterals(definition: string): {\n placeholders: StringLiteralPlaceholders;\n processedDefinition: string;\n} {\n // Create an object to hold the mapping of placeholders to original string values.\n const placeholders: StringLiteralPlaceholders = {};\n\n // Replace any string literals wrapped with double quotes in our definition with placeholders to be processed later.\n const processedDefinition = definition.replace(/\\\"(\\\\.|[^\"\\\\])*\\\"/g, (match) => {\n var strippedMatch = match.substring(1, match.length - 1);\n var placeholder = Object.keys(placeholders).find((key) => placeholders[key] === strippedMatch);\n\n // If we have no existing string literal match then create a new placeholder.\n if (!placeholder) {\n placeholder = `@@${Object.keys(placeholders).length}@@`;\n placeholders[placeholder] = strippedMatch;\n }\n\n return placeholder;\n });\n\n return { placeholders, processedDefinition };\n}\n\n/**\n * Parse the tree definition into an array of raw tokens.\n * @param definition The definition.\n * @returns An array of tokens parsed from the definition.\n */\nexport function parseTokensFromDefinition(definition: string): string[] {\n // Add some space around various important characters so that they can be plucked out easier as individual tokens.\n definition = definition.replace(/\\(/g, \" ( \");\n definition = definition.replace(/\\)/g, \" ) \");\n definition = definition.replace(/\\{/g, \" { \");\n definition = definition.replace(/\\}/g, \" } \");\n definition = definition.replace(/\\]/g, \" ] \");\n definition = definition.replace(/\\[/g, \" [ \");\n definition = definition.replace(/\\,/g, \" , \");\n\n // Split the definition into raw token form and return it.\n return definition.replace(/\\s+/g, \" \").trim().split(\" \");\n}\n", "import { StringLiteralPlaceholders, popAndCheck } from \"./MDSLUtilities\";\n\nexport type Argument = {\n /** The argument value. */\n value: T;\n /** The argument type, used for validation. */\n type: string;\n};\n\nexport type NullArgument = Argument & {\n type: \"null\";\n};\n\nexport type BooleanArgument = Argument & {\n type: \"boolean\";\n};\n\nexport type NumberArgument = Argument & {\n type: \"number\";\n isInteger: boolean; // Used for validation.\n};\n\nexport type StringPlaceholderArgument = Argument & {\n type: \"string\";\n};\n\nexport type IdentifierArgument = Argument & {\n type: \"identifier\";\n};\n\nexport type AnyArgument =\n | NullArgument\n | BooleanArgument\n | NumberArgument\n | StringPlaceholderArgument\n | IdentifierArgument;\n\n/**\n * Parse an array of argument definitions from the specified tokens array.\n * @param tokens The array tokens to parse the argument definitions from.\n * @param stringArgumentPlaceholders The mapping of string literal node argument placeholders to original values.\n * @param argumentValidator The argument validator function.\n * @param validationFailedMessage The exception message to throw if argument validation fails.\n * @returns An array of argument definitions parsed from the specified tokens array.\n */\nexport function parseArgumentTokens(\n tokens: string[],\n stringArgumentPlaceholders: StringLiteralPlaceholders\n): AnyArgument[] {\n const argumentList: AnyArgument[] = [];\n\n // If the next token is not a '[' or '(' then we have no arguments to parse.\n if (![\"[\", \"(\"].includes(tokens[0])) {\n return argumentList;\n }\n\n // Any lists of arguments will always be wrapped in '[]' for node arguments or '()' for attribute arguments.\n // We are looking for a '[' or '(' opener that wraps the argument tokens and the relevant closer.\n const closingToken = popAndCheck(tokens, [\"[\", \"(\"]) === \"[\" ? \"]\" : \")\";\n\n const argumentListTokens: string[] = [];\n\n // Grab all tokens between the '[' and ']' or '(' and ')'.\n while (tokens.length && tokens[0] !== closingToken) {\n // The next token is part of our arguments list.\n argumentListTokens.push(tokens.shift()!);\n }\n\n // Validate the order of the argument tokens. Each token must either be a ',' or a single argument that satisfies the validator.\n argumentListTokens.forEach((token, index) => {\n // Get whether this token should be an actual argument.\n const shouldBeArgumentToken = !(index & 1);\n\n // If the current token should be an actual argument then validate it, otherwise it should be a ',' token.\n if (shouldBeArgumentToken) {\n // Get the argument definition.\n const argumentDefinition = getArgumentDefinition(token, stringArgumentPlaceholders);\n\n // This is a valid argument!\n argumentList.push(argumentDefinition);\n } else {\n // The current token should be a ',' token.\n if (token !== \",\") {\n throw new Error(`invalid argument list, expected ',' or ']' but got '${token}'`);\n }\n }\n });\n\n // The arguments list should terminate with a ']' or ')' token, depending on the opener.\n popAndCheck(tokens, closingToken);\n\n // Return the arguments.\n return argumentList;\n}\n\n/**\n * Gets an argument value definition.\n * @param token The argument token.\n * @param stringArgumentPlaceholders The mapping of string literal node argument placeholders to original values.\n * @returns An argument value definition.\n */\nfunction getArgumentDefinition(token: string, stringArgumentPlaceholders: StringLiteralPlaceholders): AnyArgument {\n // Check whether the token represents a null value.\n if (token === \"null\") {\n return {\n value: null,\n type: \"null\"\n } as NullArgument;\n }\n\n // Check whether the token represents a boolean value.\n if (token === \"true\" || token === \"false\") {\n return {\n value: token === \"true\",\n type: \"boolean\"\n } as BooleanArgument;\n }\n\n // Check whether the token represents a number value.\n // TODO: Relies on broken isNaN - see MDN.\n // if (!Number.isNaN(token)) {\n if (!isNaN(token as any)) {\n return {\n value: parseFloat(token),\n isInteger: parseFloat(token) === parseInt(token, 10),\n type: \"number\"\n } as NumberArgument;\n }\n\n // Check whether the token is a placeholder (e.g. @@0@@) representing a string literal.\n if (token.match(/^@@\\d+@@$/g)) {\n return {\n value: stringArgumentPlaceholders[token].replace('\\\\\"', '\"'),\n type: \"string\"\n } as StringPlaceholderArgument;\n }\n\n // The only remaining option is that the argument value is an identifier.\n return {\n value: token,\n type: \"identifier\"\n } as IdentifierArgument;\n}\n", "import { NodeAttributeDefinition } from \"../BehaviourTreeDefinition\";\nimport { parseArgumentTokens } from \"./MDSLNodeArgumentParser\";\nimport { StringLiteralPlaceholders } from \"./MDSLUtilities\";\n\n/**\n * A type defining the attribute definitions of a node.\n */\ntype NodeAttributes = {\n while?: NodeAttributeDefinition;\n until?: NodeAttributeDefinition;\n entry?: NodeAttributeDefinition;\n exit?: NodeAttributeDefinition;\n step?: NodeAttributeDefinition;\n};\n\n/**\n * Parse any node attribute definitions from the specified tokens array.\n * @param tokens The array of remaining tokens.\n * @param stringArgumentPlaceholders The mapping of string literal node argument placeholders to original values.\n * @returns An object of attribute definitions defined by any directly following tokens.\n */\nexport function parseAttributeTokens(\n tokens: string[],\n stringArgumentPlaceholders: StringLiteralPlaceholders\n): NodeAttributes {\n const nodeAttributeNames: (keyof NodeAttributes)[] = [\"while\", \"until\", \"entry\", \"exit\", \"step\"];\n\n // Create an object to hold any attributes found.\n const attributes: NodeAttributes = {};\n\n // Try to get the name of the attribute for the next token.\n let nextAttributeName = tokens[0]?.toLowerCase() as keyof NodeAttributes;\n\n // Pull attribute tokens as well as their arguments off of the tokens stack until we have no more.\n while (nodeAttributeNames.includes(nextAttributeName)) {\n // Check to make sure that we have not already created an attribute definition of this type.\n if (attributes[nextAttributeName]) {\n throw new Error(`duplicate attribute '${tokens[0].toUpperCase()}' found for node`);\n }\n\n // Remove the attribute name token from the array of tokens.\n tokens.shift();\n\n // Grab the attribute arguments, assuming the first to be an identifier.\n const [attributeCallIdentifier, ...attributeArguments] = parseArgumentTokens(\n tokens,\n stringArgumentPlaceholders\n );\n\n // The first attribute argument has to be an identifer, this will reference an agent function.\n if (attributeCallIdentifier?.type !== \"identifier\") {\n throw new Error(\"expected agent function name identifier argument for attribute\");\n }\n\n // Any attribute arguments (other than the expected call identifier) must have a type of string, number, boolean or null.\n attributeArguments\n .filter((arg) => arg.type === \"identifier\")\n .forEach((arg) => {\n throw new Error(\n `invalid attribute argument value '${arg.value}', must be string, number, boolean or null`\n );\n });\n\n // Create the attribute definition and add it to the object of attribute definitions found.\n attributes[nextAttributeName] = {\n call: attributeCallIdentifier.value,\n args: attributeArguments.map(({ value }) => value)\n };\n\n // Try to get the next attribute name token, as there could be multiple.\n nextAttributeName = tokens[0]?.toLowerCase() as keyof NodeAttributes;\n }\n\n return attributes;\n}\n", "import {\n ActionNodeDefinition,\n AnyChildNode,\n AnyNode,\n BranchNodeDefinition,\n ConditionNodeDefinition,\n FailNodeDefinition,\n FlipNodeDefinition,\n LottoNodeDefinition,\n ParallelNodeDefinition,\n RepeatNodeDefinition,\n RetryNodeDefinition,\n RootNodeDefinition,\n SelectorNodeDefinition,\n SequenceNodeDefinition,\n SucceedNodeDefinition,\n WaitNodeDefinition\n} from \"../BehaviourTreeDefinition\";\nimport { isCompositeNode, isDecoratorNode, isLeafNode, isRootNode } from \"../BehaviourTreeDefinitionUtilities\";\nimport { parseArgumentTokens } from \"./MDSLNodeArgumentParser\";\nimport { parseAttributeTokens } from \"./MDSLNodeAttributeParser\";\nimport {\n StringLiteralPlaceholders,\n parseTokensFromDefinition,\n popAndCheck,\n substituteStringLiterals\n} from \"./MDSLUtilities\";\n\n/**\n * Convert the MDSL tree definition string into an equivalent JSON definition.\n * @param definition The tree definition string as MDSL.\n * @returns The root node JSON definitions.\n */\nexport function convertMDSLToJSON(definition: string): RootNodeDefinition[] {\n // Swap out any node/attribute argument string literals with a placeholder and get a mapping of placeholders to original values as well as the processed definition.\n const { placeholders, processedDefinition } = substituteStringLiterals(definition);\n\n // Parse our definition definition string into an array of raw tokens.\n const tokens = parseTokensFromDefinition(processedDefinition);\n\n return convertTokensToJSONDefinition(tokens, placeholders);\n}\n\n/**\n * Converts the specified tree definition tokens into a JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The root node JSON definitions.\n */\nfunction convertTokensToJSONDefinition(\n tokens: string[],\n stringLiteralPlaceholders: StringLiteralPlaceholders\n): RootNodeDefinition[] {\n // There must be at least 3 tokens for the tree definition to be valid. 'ROOT', '{' and '}'.\n if (tokens.length < 3) {\n throw new Error(\"invalid token count\");\n }\n\n // We should have a matching number of '{' and '}' tokens. If not, then there are scopes that have not been properly closed.\n if (tokens.filter((token) => token === \"{\").length !== tokens.filter((token) => token === \"}\").length) {\n throw new Error(\"scope character mismatch\");\n }\n\n // Create an array of tree stack arrays where root nodes will always be at the botton and the current composite/decorator node at the top.\n // There should be an element in this array for every root node defined and every element should be an array with a root note as the first element.\n // E.g. A definition with two root nodes defined:\n // [\n // [root, lotto, sequence],\n // [root, selector]\n // ]\n const treeStacks: [Partial, ...Partial[]][] = [];\n\n // Create an array of all root node definitions that we create.\n const rootNodes: Partial[] = [];\n\n // A helper function used to push node definitions onto the tree stack.\n const pushNode = (node: AnyNode) => {\n // If the node is a root node then we need to create a new tree stack array with the root node at the root.\n if (isRootNode(node)) {\n // Add the root node definition to our array of all parsed root node definitions.\n rootNodes.push(node);\n\n // Add the root node definition to the root of a new tree stack.\n treeStacks.push([node]);\n\n return;\n }\n\n // All non-root nodes should be pushed after their root nodes so handle cases\n // where we may not have any tree stacks or our top-most tree stack is empty.\n if (!treeStacks.length || !treeStacks[treeStacks.length - 1].length) {\n throw new Error(\"expected root node at base of definition\");\n }\n\n // Get the current tree stack that we are populating.\n const topTreeStack = treeStacks[treeStacks.length - 1];\n\n // Get the top-most node in the current tree stack, this will be a composite/decorator node\n // for which we will populate its children array if composite or setting its child if a decorator.\n const topTreeStackTopNode = topTreeStack[topTreeStack.length - 1] as AnyNode;\n\n // If the top-most node in the current root stack is a composite or decorator\n // node then the current node should be added as a child of the top-most node.\n if (isCompositeNode(topTreeStackTopNode)) {\n topTreeStackTopNode.children = topTreeStackTopNode.children || [];\n topTreeStackTopNode.children.push(node);\n } else if (isDecoratorNode(topTreeStackTopNode)) {\n // If the top node already has a child node set then throw an error as a decorator should only have a single child.\n if (topTreeStackTopNode.child) {\n throw new Error(\"a decorator node must only have a single child node\");\n }\n\n topTreeStackTopNode.child = node;\n }\n\n // If the node we are adding is also a composite or decorator node, then we should push it\n // onto the current tree stack, as subsequent nodes will be added as its child/children.\n if (!isLeafNode(node)) {\n topTreeStack.push(node);\n }\n };\n\n // A helper function used to pop node definitions off of the stack.\n const popNode = () => {\n // Get the current tree stack that we are populating.\n const topTreeStack = treeStacks[treeStacks.length - 1];\n\n // Pop the top-most node in the current tree stack if there is one.\n if (topTreeStack.length) {\n topTreeStack.pop();\n }\n\n // We don't want any empty tree stacks in our stack of tree stacks.\n if (!topTreeStack.length) {\n treeStacks.pop();\n }\n };\n\n // We should keep processing the raw tokens until we run out of them.\n while (tokens.length) {\n // Grab the next token.\n const token = tokens.shift()!;\n\n // How we create the next node depends on the current raw token value.\n switch (token.toUpperCase()) {\n case \"ROOT\": {\n pushNode(createRootNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"SUCCEED\": {\n pushNode(createSucceedNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"FAIL\": {\n pushNode(createFailNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"FLIP\": {\n pushNode(createFlipNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"REPEAT\": {\n pushNode(createRepeatNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"RETRY\": {\n pushNode(createRetryNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"SEQUENCE\": {\n pushNode(createSequenceNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"SELECTOR\": {\n pushNode(createSelectorNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"PARALLEL\": {\n pushNode(createParallelNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"LOTTO\": {\n pushNode(createLottoNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"ACTION\": {\n pushNode(createActionNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"CONDITION\": {\n pushNode(createConditionNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"WAIT\": {\n pushNode(createWaitNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"BRANCH\": {\n pushNode(createBranchNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"}\": {\n // The '}' character closes the current scope and means that we have to pop a node off of the current stack.\n popNode();\n break;\n }\n\n default: {\n throw new Error(`unexpected token: ${token}`);\n }\n }\n }\n\n return rootNodes as RootNodeDefinition[];\n}\n\n/**\n * Creates a root node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The root node JSON definition.\n */\nfunction createRootNode(tokens: string[], stringLiteralPlaceholders: StringLiteralPlaceholders): RootNodeDefinition {\n // Create the root node definition.\n let node = {\n type: \"root\",\n id: undefined\n } as RootNodeDefinition;\n\n // Parse any node arguments, we should only have one if any which will be an identifier argument for the root identifier.\n const nodeArguments = parseArgumentTokens(tokens, stringLiteralPlaceholders);\n\n // Check whether any node arguments were defined.\n if (nodeArguments.length) {\n // We should only have one argument, if any, which will be an identifier argument for the root identifier.\n if (nodeArguments.length === 1 && nodeArguments[0].type === \"identifier\") {\n // The root node identifier will be the first and only node argument value.\n node.id = nodeArguments[0].value as string;\n } else {\n throw new Error(\"expected single root name argument\");\n }\n }\n\n // Grab any node attribute definitions and spread them into the node definition.\n node = { ...node, ...parseAttributeTokens(tokens, stringLiteralPlaceholders) };\n\n // This is a decorator node, so we expect an opening '{'.\n popAndCheck(tokens, \"{\");\n\n // Return the root node definition.\n return node;\n}\n\n/**\n * Creates a succeed node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The succeed node JSON definition.\n */\nfunction createSucceedNode(\n tokens: string[],\n stringLiteralPlaceholders: StringLiteralPlaceholders\n): SucceedNodeDefinition {\n const node = {\n type: \"succeed\",\n ...parseAttributeTokens(tokens, stringLiteralPlaceholders)\n } as SucceedNodeDefinition;\n\n // This is a decorator node, so we expect an opening '{'.\n popAndCheck(tokens, \"{\");\n\n // Return the succeed node definition.\n return node;\n}\n\n/**\n * Creates a fail node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The fail node JSON definition.\n */\nfunction createFailNode(tokens: string[], stringLiteralPlaceholders: StringLiteralPlaceholders): FailNodeDefinition {\n const node = {\n type: \"fail\",\n ...parseAttributeTokens(tokens, stringLiteralPlaceholders)\n } as FailNodeDefinition;\n\n // This is a decorator node, so we expect an opening '{'.\n popAndCheck(tokens, \"{\");\n\n // Return the fail node definition.\n return node;\n}\n\n/**\n * Creates a flip node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The flip node JSON definition.\n */\nfunction createFlipNode(tokens: string[], stringLiteralPlaceholders: StringLiteralPlaceholders): FlipNodeDefinition {\n const node = {\n type: \"flip\",\n ...parseAttributeTokens(tokens, stringLiteralPlaceholders)\n } as FlipNodeDefinition;\n\n // This is a decorator node, so we expect an opening '{'.\n popAndCheck(tokens, \"{\");\n\n // Return the flip node definition.\n return node;\n}\n\n/**\n * Creates a repeat node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The repeat node JSON definition.\n */\nfunction createRepeatNode(\n tokens: string[],\n stringLiteralPlaceholders: StringLiteralPlaceholders\n): RepeatNodeDefinition {\n let node = { type: \"repeat\" } as RepeatNodeDefinition;\n\n // Get the node arguments.\n const nodeArguments = parseArgumentTokens(tokens, stringLiteralPlaceholders);\n\n // The arguments of a repeat node are optional. We may have:\n // - No node arguments, in which case the repeat note will iterate indefinitely.\n // - One node argument which will be the explicit number of iterations to make.\n // - Two node arguments which define the min and max iteration bounds from which a random iteration count will be picked.\n if (nodeArguments.length) {\n // All repeat node arguments MUST be of type number and must be integer.\n nodeArguments\n .filter((arg) => arg.type !== \"number\" || !arg.isInteger)\n .forEach(() => {\n throw new Error(`repeat node iteration counts must be integer values`);\n });\n\n // We should have got one or two iteration counts.\n if (nodeArguments.length === 1) {\n // A static iteration count was defined.\n node.iterations = nodeArguments[0].value as number;\n } else if (nodeArguments.length === 2) {\n // A minimum and maximum iteration count was defined.\n node.iterations = [nodeArguments[0].value as number, nodeArguments[1].value as number];\n } else {\n // An incorrect number of iteration counts was defined.\n throw new Error(\"invalid number of repeat node iteration count arguments defined\");\n }\n }\n\n // Grab any node attribute definitions and spread them into the node definition.\n node = { ...node, ...parseAttributeTokens(tokens, stringLiteralPlaceholders) };\n\n // This is a decorator node, so we expect an opening '{'.\n popAndCheck(tokens, \"{\");\n\n // Return the repeat node definition.\n return node;\n}\n\n/**\n * Creates a retry node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The retry node JSON definition.\n */\nfunction createRetryNode(tokens: string[], stringLiteralPlaceholders: StringLiteralPlaceholders): RetryNodeDefinition {\n let node = { type: \"retry\" } as RetryNodeDefinition;\n\n // Get the node arguments.\n const nodeArguments = parseArgumentTokens(tokens, stringLiteralPlaceholders);\n\n // The arguments of a retry node are optional. We may have:\n // - No node arguments, in which case the retry note will attempt indefinitely.\n // - One node argument which will be the explicit number of attempts to make.\n // - Two node arguments which define the min and max attempt bounds from which a random attempt count will be picked.\n if (nodeArguments.length) {\n // All retry node arguments MUST be of type number and must be integer.\n nodeArguments\n .filter((arg) => arg.type !== \"number\" || !arg.isInteger)\n .forEach(() => {\n throw new Error(`retry node attempt counts must be integer values`);\n });\n\n // We should have got one or two attempt counts.\n if (nodeArguments.length === 1) {\n // A static attempt count was defined.\n node.attempts = nodeArguments[0].value as number;\n } else if (nodeArguments.length === 2) {\n // A minimum and maximum attempt count was defined.\n node.attempts = [nodeArguments[0].value as number, nodeArguments[1].value as number];\n } else {\n // An incorrect number of attempt counts was defined.\n throw new Error(\"invalid number of retry node attempt count arguments defined\");\n }\n }\n\n // Grab any node attribute definitions and spread them into the node definition.\n node = { ...node, ...parseAttributeTokens(tokens, stringLiteralPlaceholders) };\n\n // This is a decorator node, so we expect an opening '{'.\n popAndCheck(tokens, \"{\");\n\n // Return the retry node definition.\n return node;\n}\n\n/**\n * Creates a sequence node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The sequence node JSON definition.\n */\nfunction createSequenceNode(\n tokens: string[],\n stringLiteralPlaceholders: StringLiteralPlaceholders\n): SequenceNodeDefinition {\n const node = {\n type: \"sequence\",\n ...parseAttributeTokens(tokens, stringLiteralPlaceholders)\n } as SequenceNodeDefinition;\n\n // This is a composite node, so we expect an opening '{'.\n popAndCheck(tokens, \"{\");\n\n // Return the sequence node definition.\n return node;\n}\n\n/**\n * Creates a selector node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The selector node JSON definition.\n */\nfunction createSelectorNode(\n tokens: string[],\n stringLiteralPlaceholders: StringLiteralPlaceholders\n): SelectorNodeDefinition {\n const node = {\n type: \"selector\",\n ...parseAttributeTokens(tokens, stringLiteralPlaceholders)\n } as SelectorNodeDefinition;\n\n // This is a composite node, so we expect an opening '{'.\n popAndCheck(tokens, \"{\");\n\n // Return the selector node definition.\n return node;\n}\n\n/**\n * Creates a parallel node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The parallel node JSON definition.\n */\nfunction createParallelNode(\n tokens: string[],\n stringLiteralPlaceholders: StringLiteralPlaceholders\n): ParallelNodeDefinition {\n const node = {\n type: \"parallel\",\n ...parseAttributeTokens(tokens, stringLiteralPlaceholders)\n } as ParallelNodeDefinition;\n\n // This is a composite node, so we expect an opening '{'.\n popAndCheck(tokens, \"{\");\n\n // Return the parallel node definition.\n return node;\n}\n\n/**\n * Creates a lotto node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The lotto node JSON definition.\n */\nfunction createLottoNode(tokens: string[], stringLiteralPlaceholders: StringLiteralPlaceholders): LottoNodeDefinition {\n // If any node arguments have been defined then they must be our weights.\n const nodeArguments = parseArgumentTokens(tokens, stringLiteralPlaceholders);\n\n // All lotto node arguments MUST be of type number and must be integer.\n nodeArguments\n .filter((arg) => arg.type !== \"number\" || !arg.isInteger)\n .forEach(() => {\n throw new Error(`lotto node weight arguments must be integer values`);\n });\n\n const node = {\n type: \"lotto\",\n weights: nodeArguments.map(({ value }) => value),\n ...parseAttributeTokens(tokens, stringLiteralPlaceholders)\n } as LottoNodeDefinition;\n\n // This is a composite node, so we expect an opening '{'.\n popAndCheck(tokens, \"{\");\n\n // Return the lotto node definition.\n return node;\n}\n\n/**\n * Creates an action node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The action node JSON definition.\n */\nfunction createActionNode(\n tokens: string[],\n stringLiteralPlaceholders: StringLiteralPlaceholders\n): ActionNodeDefinition {\n // Parse any node arguments, we should have at least one which will be an identifier argument for the action name\n // and agent function to invoke for the action, all other arguments are to be passed as arguments to that function.\n const [actionNameIdentifier, ...agentFunctionArgs] = parseArgumentTokens(tokens, stringLiteralPlaceholders);\n\n // Our first argument MUST be defined and be an identifier as we require an action name argument.\n if (actionNameIdentifier?.type !== \"identifier\") {\n throw new Error(\"expected action name identifier argument\");\n }\n\n // Only the first argument should have been an identifier, all agent function arguments must be string, number, boolean or null.\n agentFunctionArgs\n .filter((arg) => arg.type === \"identifier\")\n .forEach((arg) => {\n throw new Error(\n `invalid action node argument value '${arg.value}', must be string, number, boolean or null`\n );\n });\n\n // Return the action node definition.\n return {\n type: \"action\",\n call: actionNameIdentifier.value,\n args: agentFunctionArgs.map(({ value }) => value),\n ...parseAttributeTokens(tokens, stringLiteralPlaceholders)\n };\n}\n\n/**\n * Creates a condition node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The condition node JSON definition.\n */\nfunction createConditionNode(\n tokens: string[],\n stringLiteralPlaceholders: StringLiteralPlaceholders\n): ConditionNodeDefinition {\n // Parse any node arguments, we should have at least one which will be an identifier argument for the condition name\n // and agent function to invoke for the condition, all other arguments are to be passed as arguments to that function.\n const [conditionNameIdentifier, ...agentFunctionArgs] = parseArgumentTokens(tokens, stringLiteralPlaceholders);\n\n // Our first argument MUST be defined and be an identifier as we require a condition name argument.\n if (conditionNameIdentifier?.type !== \"identifier\") {\n throw new Error(\"expected condition name identifier argument\");\n }\n\n // Only the first argument should have been an identifier, all agent function arguments must be string, number, boolean or null.\n agentFunctionArgs\n .filter((arg) => arg.type === \"identifier\")\n .forEach((arg) => {\n throw new Error(\n `invalid condition node argument value '${arg.value}', must be string, number, boolean or null`\n );\n });\n\n // Return the condition node definition.\n return {\n type: \"condition\",\n call: conditionNameIdentifier.value,\n args: agentFunctionArgs.map(({ value }) => value),\n ...parseAttributeTokens(tokens, stringLiteralPlaceholders)\n };\n}\n\n/**\n * Creates a wait node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The wait node JSON definition.\n */\nfunction createWaitNode(tokens: string[], stringLiteralPlaceholders: StringLiteralPlaceholders): WaitNodeDefinition {\n let node = { type: \"wait\" } as WaitNodeDefinition;\n\n // Get the node arguments.\n const nodeArguments = parseArgumentTokens(tokens, stringLiteralPlaceholders);\n\n // The arguments of a wait node are optional. We may have:\n // - No node arguments, in which case the wait will be indefinite until it is aborted.\n // - One node argument which will be the explicit duration of the wait.\n // - Two node arguments which define the min and max duration bounds from which a random duration will be picked.\n if (nodeArguments.length) {\n // All wait node arguments MUST be of type number and must be integer.\n nodeArguments\n .filter((arg) => arg.type !== \"number\" || !arg.isInteger)\n .forEach(() => {\n throw new Error(`wait node duration arguments must be integer values`);\n });\n\n // We may have:\n // - One node argument which will be the explicit duration of the wait.\n // - Two node arguments which define the min and max duration bounds from which a random duration will be picked.\n // - Too many arguments, which is not valid.\n if (nodeArguments.length === 1) {\n // An explicit duration was defined.\n node.duration = nodeArguments[0].value as number;\n } else if (nodeArguments.length === 2) {\n // Min and max duration bounds were defined from which a random duration will be picked.\n node.duration = [nodeArguments[0].value as number, nodeArguments[1].value as number];\n } else if (nodeArguments.length > 2) {\n // An incorrect number of duration arguments were defined.\n throw new Error(\"invalid number of wait node duration arguments defined\");\n }\n }\n\n // Return the wait node definition.\n return { ...node, ...parseAttributeTokens(tokens, stringLiteralPlaceholders) };\n}\n\n/**\n * Creates a branch node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The branch node JSON definition.\n */\nfunction createBranchNode(\n tokens: string[],\n stringLiteralPlaceholders: StringLiteralPlaceholders\n): BranchNodeDefinition {\n // Parse any node arguments, we should have one which will be an identifier argument for the root ref.\n const nodeArguments = parseArgumentTokens(tokens, stringLiteralPlaceholders);\n\n // We should have only a single identifer argument for a branch node, which is the root ref.\n if (nodeArguments.length !== 1 || nodeArguments[0].type !== \"identifier\") {\n throw new Error(\"expected single branch name argument\");\n }\n\n // Return the branch node definition.\n return { type: \"branch\", ref: nodeArguments[0].value };\n}\n", "import { RootNodeDefinition } from \"./BehaviourTreeDefinition\";\nimport { flattenDefinition, isBranchNode, isInteger } from \"./BehaviourTreeDefinitionUtilities\";\nimport { convertMDSLToJSON } from \"./mdsl/MDSLDefinitionParser\";\n\n/**\n * An object representing the result of validating a tree definition.\n */\nexport type DefinitionValidationResult = {\n /**\n * A flag defining whether validation succeeded.\n */\n succeeded: boolean;\n /**\n * A string containing the error message if validation did not succeed.\n */\n errorMessage?: string;\n};\n\n/**\n * Validates the specified behaviour tree definition in the form of JSON or MDSL.\n * @param definition The behaviour tree definition in the form of JSON or MDSL.\n * @returns An object representing the result of validating the given tree definition.\n */\nexport function validateDefinition(definition: any): DefinitionValidationResult {\n // A helper function to create a failure validation result with the given error message.\n const createFailureResult = (errorMessage: string) => ({ succeeded: false, errorMessage });\n\n // The definition must be defined.\n if (definition === null || typeof definition === \"undefined\") {\n return createFailureResult(\"definition is null or undefined\");\n }\n\n let rootNodeDefinitions: any[];\n\n // We are expecting a definition in one of three different forms:\n // - A string which we will assume is mdsl and we will parse this to JSON before validation.\n // - An array which we will assume is an array of root node definitions with at least one being the primary root node (no 'id' property)\n // - An object which we will assume is the primary root node and should not have an 'id' property.\n if (typeof definition === \"string\") {\n try {\n // The definition is a string which we can assume is mdsl, so attempt to parse it to a JSON definition in the form of an array of root node definitions.\n rootNodeDefinitions = convertMDSLToJSON(definition);\n } catch (error) {\n // We failed to parse the JSON from the mdsl, this is likely to be the result of it not being a valid mdsl string.\n return createFailureResult(`invalid mdsl: ${definition}`);\n }\n } else if (typeof definition === \"object\") {\n // The definition will either be an array (of root node definitions) or an object (the single primary root node definition).\n rootNodeDefinitions = Array.isArray(definition) ? definition : [definition];\n } else {\n return createFailureResult(`unexpected definition type of '${typeof definition}'`);\n }\n\n // Iterate over our array of root nodes and call validateNode for each, passing an initial depth of 0, wrapped in a try catch to handle validation failures.\n try {\n rootNodeDefinitions.forEach((rootNodeDefinition) => validateNode(rootNodeDefinition, 0));\n } catch (error) {\n // Handle cases where we have caught a thrown Error and return a failure result with the error message.\n if (error instanceof Error) {\n return createFailureResult(error.message);\n }\n\n // No idea what happened here!\n return createFailureResult(`unexpected error: ${error}`);\n }\n\n // Unpack all of the root node definitions into arrays of main ('id' defined) and sub ('id' not defined) root node definitions.\n const mainRootNodeDefinitions = rootNodeDefinitions.filter(({ id }) => typeof id === \"undefined\");\n const subRootNodeDefinitions = rootNodeDefinitions.filter(({ id }) => typeof id === \"string\" && id.length > 0);\n\n // We should ALWAYS have exactly one root node definition without an 'id' property defined, which is out main root node definition.\n if (mainRootNodeDefinitions.length !== 1) {\n return createFailureResult(\"expected single root node without 'id' property defined to act as main root\");\n }\n\n // We should never have duplicate 'id' properties across our sub root node definitions.\n const subRootNodeIdenitifers: string[] = [];\n for (const { id } of subRootNodeDefinitions) {\n // Have we already come across this 'id' property value?\n if (subRootNodeIdenitifers.includes(id)) {\n return createFailureResult(`multiple root nodes found with duplicate 'id' property value of '${id}'`);\n }\n\n subRootNodeIdenitifers.push(id);\n }\n\n // Check for any branch node circular depedencies. This will not include any globally registered subtrees.\n const circularDependencyPath = findBranchCircularDependencyPath(rootNodeDefinitions);\n\n // If we found a circular dependency in our root node and branch node definitions then the definition is definitely not valid.\n if (circularDependencyPath) {\n return createFailureResult(`circular dependency found in branch node references: ${circularDependencyPath}`);\n }\n\n // Our definition was valid!\n return { succeeded: true };\n}\n\n/**\n * Find the first circular depdendency path present in the array of root node definitions, or null if one doesn't exist.\n * This will not consider branch nodes that reference any globally registered subtrees.\n * @param rootNodeDefinitions The array of root node definitions.\n * @returns The first circular depdendency path present in the array of root node definitions as string, or null if one doesn't exist.\n */\nfunction findBranchCircularDependencyPath(rootNodeDefinitions: RootNodeDefinition[]): string | null {\n // Create a mapping of root node identifiers to other root nodes that they reference via branch nodes.\n // Below is an example of a mapping that includes a circular dependency (root => a => b => c => a)\n // [{ refs: [\"a\", \"b\"] }, { id: \"a\", refs: [\"b\"] }, { id: \"b\", refs: [\"c\"] }, { id: \"c\", refs: [\"a\"] }]\n const rootNodeMappings: { id: string | undefined; refs: string[] }[] = rootNodeDefinitions.map(\n (rootNodeDefinition) => ({\n id: rootNodeDefinition.id,\n refs: flattenDefinition(rootNodeDefinition)\n .filter(isBranchNode)\n .map(({ ref }) => ref)\n })\n );\n\n let badPathFormatted: string | null = null;\n\n // A recursive function to walk through the mappings, keeping track of which root nodes we have visited in the form of a path of root node identifiers.\n const followRefs = (mapping: { id: string | undefined; refs: string[] }, path: (string | undefined)[] = []) => {\n // Have we found a circular dependency?\n if (path.includes(mapping.id)) {\n // We found a circular dependency! Get the bad path of root node identifiers.\n const badPath = [...path, mapping.id];\n\n // Set the formatted path value. [undefined, \"a\", \"b\", \"c\", \"a\"] would be formatted as \"a -> b -> c -> a\".\n badPathFormatted = badPath.filter((element) => !!element).join(\" => \");\n\n // No need to continue, we found a circular dependency.\n return;\n }\n\n for (const ref of mapping.refs) {\n // Find the mapping for the root node with an identifer matching the current ref.\n const subMapping = rootNodeMappings.find(({ id }) => id === ref);\n\n // We may not have a mapping for this ref, which will happen if this ref is for a globally registered subtree.\n if (subMapping) {\n followRefs(subMapping, [...path, mapping.id]);\n }\n }\n };\n\n // Start looking for circular dependencies from the root.\n followRefs(rootNodeMappings.find((mapping) => typeof mapping.id === \"undefined\")!);\n\n return badPathFormatted;\n}\n\n/**\n * Validate an object that we expect to be a node definition.\n * @param definition An object that we expect to be a node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateNode(definition: any, depth: number): void {\n // Every node must be valid object and have a non-empty 'type' string property.\n if (typeof definition !== \"object\" || typeof definition.type !== \"string\" || definition.type.length === 0) {\n throw new Error(\n `node definition is not an object or 'type' property is not a non-empty string at depth '${depth}'`\n );\n }\n\n // How we validate this node definition will depend on its type.\n switch (definition.type) {\n case \"action\":\n validateActionNode(definition, depth);\n break;\n\n case \"condition\":\n validateConditionNode(definition, depth);\n break;\n\n case \"wait\":\n validateWaitNode(definition, depth);\n break;\n\n case \"branch\":\n validateBranchNode(definition, depth);\n break;\n\n case \"root\":\n validateRootNode(definition, depth);\n break;\n\n case \"success\":\n validateSuccessNode(definition, depth);\n break;\n\n case \"fail\":\n validateFailNode(definition, depth);\n break;\n\n case \"flip\":\n validateFlipNode(definition, depth);\n break;\n\n case \"repeat\":\n validateRepeatNode(definition, depth);\n break;\n\n case \"retry\":\n validateRetryNode(definition, depth);\n break;\n\n case \"sequence\":\n validateSequenceNode(definition, depth);\n break;\n\n case \"selector\":\n validateSelectorNode(definition, depth);\n break;\n\n case \"parallel\":\n validateParallelNode(definition, depth);\n break;\n\n default:\n throw new Error(`unexpected node type of '${definition.type}' at depth '${depth}'`);\n }\n}\n\n/**\n * Validate any attributes for a given node definition.\n * @param definition The node definition.\n * @param depth The depth of the node in the behaviour tree definition.\n */\nfunction validateNodeAttributes(definition: any, depth: number): void {\n // Validate each of the attribute types for this node.\n [\"while\", \"until\", \"entry\", \"exit\", \"step\"].forEach((attributeName) => {\n // Attempt to grab the definition for the current attribute from the node definition.\n const attributeDefinition = definition[attributeName];\n\n // All node attributes are optional, so there is nothing to do if the current attribute is not defined.\n if (typeof attributeDefinition === \"undefined\") {\n return;\n }\n\n // The attribute definition must be an object.\n if (typeof attributeDefinition !== \"object\") {\n throw new Error(\n `expected attribute '${attributeName}' to be an object for '${definition.type}' node at depth '${depth}'`\n );\n }\n\n // The 'call' property must be defined for any attribute definition.\n if (typeof attributeDefinition.call !== \"string\" || attributeDefinition.call.length === 0) {\n throw new Error(\n `expected 'call' property for attribute '${attributeName}' to be a non-empty string for '${definition.type}' node at depth '${depth}'`\n );\n }\n\n // If any node attribute arguments have been defined then they must have been defined in an array.\n if (typeof attributeDefinition.args !== \"undefined\" && !Array.isArray(attributeDefinition.args)) {\n throw new Error(\n `expected 'args' property for attribute '${attributeName}' to be an array for '${definition.type}' node at depth '${depth}'`\n );\n }\n });\n}\n\n/**\n * Validate an object that we expect to be a root node definition.\n * @param definition An object that we expect to be a root node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateRootNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"root\") {\n throw new Error(\"expected node type of 'root' for root node\");\n }\n\n // A root node cannot be the child of another node.\n if (depth > 0) {\n throw new Error(\"a root node cannot be the child of another node\");\n }\n\n // Check that, if the root node 'id' property is defined, it is a non-empty string.\n if (typeof definition.id !== \"undefined\" && (typeof definition.id !== \"string\" || definition.id.length === 0)) {\n throw new Error(\"expected non-empty string for 'id' property if defined for root node\");\n }\n\n // A root node is a decorator node, so must have a child node defined.\n if (typeof definition.child === \"undefined\") {\n throw new Error(\"expected property 'child' to be defined for root node\");\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n\n // Validate the child node of this decorator node.\n validateNode(definition.child, depth + 1);\n}\n\n/**\n * Validate an object that we expect to be a success node definition.\n * @param definition An object that we expect to be a success node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateSuccessNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"success\") {\n throw new Error(`expected node type of 'success' for success node at depth '${depth}'`);\n }\n\n // A success node is a decorator node, so must have a child node defined.\n if (typeof definition.child === \"undefined\") {\n throw new Error(`expected property 'child' to be defined for success node at depth '${depth}'`);\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n\n // Validate the child node of this decorator node.\n validateNode(definition.child, depth + 1);\n}\n\n/**\n * Validate an object that we expect to be a fail node definition.\n * @param definition An object that we expect to be a fail node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateFailNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"fail\") {\n throw new Error(`expected node type of 'fail' for fail node at depth '${depth}'`);\n }\n\n // A fail node is a decorator node, so must have a child node defined.\n if (typeof definition.child === \"undefined\") {\n throw new Error(`expected property 'child' to be defined for fail node at depth '${depth}'`);\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n\n // Validate the child node of this decorator node.\n validateNode(definition.child, depth + 1);\n}\n\n/**\n * Validate an object that we expect to be a flip node definition.\n * @param definition An object that we expect to be a flip node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateFlipNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"flip\") {\n throw new Error(`expected node type of 'flip' for flip node at depth '${depth}'`);\n }\n\n // A flip node is a decorator node, so must have a child node defined.\n if (typeof definition.child === \"undefined\") {\n throw new Error(`expected property 'child' to be defined for flip node at depth '${depth}'`);\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n\n // Validate the child node of this decorator node.\n validateNode(definition.child, depth + 1);\n}\n\n/**\n * Validate an object that we expect to be a repeat node definition.\n * @param definition An object that we expect to be a repeat node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateRepeatNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"repeat\") {\n throw new Error(`expected node type of 'repeat' for repeat node at depth '${depth}'`);\n }\n\n // A repeat node is a decorator node, so must have a child node defined.\n if (typeof definition.child === \"undefined\") {\n throw new Error(`expected property 'child' to be defined for repeat node at depth '${depth}'`);\n }\n\n // Check whether an 'iterations' property has been defined, it may not have been if this node is to repeat indefinitely.\n if (typeof definition.iterations !== \"undefined\") {\n if (Array.isArray(definition.iterations)) {\n // Check whether any elements of the array are not integer values.\n const containsNonInteger = !!definition.iterations.find((value: unknown) => !isInteger(value));\n\n // If the 'iterations' property is an array then it MUST contain two integer values.\n if (definition.iterations.length !== 2 || containsNonInteger) {\n throw new Error(\n `expected array containing two integer values for 'iterations' property if defined for repeat node at depth '${depth}'`\n );\n }\n } else if (!isInteger(definition.iterations)) {\n throw new Error(\n `expected integer value or array containing two integer values for 'iterations' property if defined for repeat node at depth '${depth}'`\n );\n }\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n\n // Validate the child node of this decorator node.\n validateNode(definition.child, depth + 1);\n}\n\n/**\n * Validate an object that we expect to be a retry node definition.\n * @param definition An object that we expect to be a retry node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateRetryNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"retry\") {\n throw new Error(`expected node type of 'retry' for retry node at depth '${depth}'`);\n }\n\n // A retry node is a decorator node, so must have a child node defined.\n if (typeof definition.child === \"undefined\") {\n throw new Error(`expected property 'child' to be defined for retry node at depth '${depth}'`);\n }\n\n // Check whether an 'attempts' property has been defined, it may not have been if this node is to retry indefinitely.\n if (typeof definition.attempts !== \"undefined\") {\n if (Array.isArray(definition.attempts)) {\n // Check whether any elements of the array are not integer values.\n const containsNonInteger = !!definition.attempts.find((value: unknown) => !isInteger(value));\n\n // If the 'attempts' property is an array then it MUST contain two integer values.\n if (definition.attempts.length !== 2 || containsNonInteger) {\n throw new Error(\n `expected array containing two integer values for 'attempts' property if defined for retry node at depth '${depth}'`\n );\n }\n } else if (!isInteger(definition.attempts)) {\n throw new Error(\n `expected integer value or array containing two integer values for 'attempts' property if defined for retry node at depth '${depth}'`\n );\n }\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n\n // Validate the child node of this decorator node.\n validateNode(definition.child, depth + 1);\n}\n\n/**\n * Validate an object that we expect to be a branch node definition.\n * @param definition An object that we expect to be a branch node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateBranchNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"branch\") {\n throw new Error(`expected node type of 'branch' for branch node at depth '${depth}'`);\n }\n\n // Check that the branch node 'ref' property is defined and is a non-empty string.\n if (typeof definition.ref !== \"string\" || definition.ref.length === 0) {\n throw new Error(`expected non-empty string for 'ref' property for branch node at depth '${depth}'`);\n }\n\n // It is invalid to define guard attributes for a branch node as they should be defined on the referenced root node.\n [\"while\", \"until\"].forEach((attributeName) => {\n if (typeof definition[attributeName] !== \"undefined\") {\n throw new Error(\n `guards should not be defined for branch nodes but guard '${attributeName}' was defined for branch node at depth '${depth}'`\n );\n }\n });\n\n // It is invalid to define callback attributes for a branch node as they should be defined on the referenced root node.\n [\"entry\", \"exit\", \"step\"].forEach((attributeName) => {\n if (typeof definition[attributeName] !== \"undefined\") {\n throw new Error(\n `callbacks should not be defined for branch nodes but callback '${attributeName}' was defined for branch node at depth '${depth}'`\n );\n }\n });\n}\n\n/**\n * Validate an object that we expect to be a action node definition.\n * @param definition An object that we expect to be a action node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateActionNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"action\") {\n throw new Error(`expected node type of 'action' for action node at depth '${depth}'`);\n }\n\n // The 'call' property must be defined for a action node definition.\n if (typeof definition.call !== \"string\" || definition.call.length === 0) {\n throw new Error(`expected non-empty string for 'call' property of action node at depth '${depth}'`);\n }\n\n // If any action function arguments have been defined then they must have been defined in an array.\n if (typeof definition.args !== \"undefined\" && !Array.isArray(definition.args)) {\n throw new Error(`expected array for 'args' property if defined for action node at depth '${depth}'`);\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n}\n\n/**\n * Validate an object that we expect to be a condition node definition.\n * @param definition An object that we expect to be a condition node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateConditionNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"condition\") {\n throw new Error(`expected node type of 'condition' for condition node at depth '${depth}'`);\n }\n\n // The 'call' property must be defined for a condition node definition.\n if (typeof definition.call !== \"string\" || definition.call.length === 0) {\n throw new Error(`expected non-empty string for 'call' property of condition node at depth '${depth}'`);\n }\n\n // If any condition function arguments have been defined then they must have been defined in an array.\n if (typeof definition.args !== \"undefined\" && !Array.isArray(definition.args)) {\n throw new Error(`expected array for 'args' property if defined for condition node at depth '${depth}'`);\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n}\n\n/**\n * Validate an object that we expect to be a wait node definition.\n * @param definition An object that we expect to be a wait node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateWaitNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"wait\") {\n throw new Error(`expected node type of 'wait' for wait node at depth '${depth}'`);\n }\n\n // Check whether a 'duration' property has been defined, it may not have been if this node is to wait indefinitely.\n if (typeof definition.duration !== \"undefined\") {\n if (Array.isArray(definition.duration)) {\n // Check whether any elements of the array are not integer values.\n const containsNonInteger = !!definition.duration.find((value: unknown) => !isInteger(value));\n\n // If the 'duration' property is an array then it MUST contain two integer values.\n if (definition.duration.length !== 2 || containsNonInteger) {\n throw new Error(\n `expected array containing two integer values for 'duration' property if defined for wait node at depth '${depth}'`\n );\n }\n } else if (!isInteger(definition.duration)) {\n throw new Error(\n `expected integer value or array containing two integer values for 'duration' property if defined for wait node at depth '${depth}'`\n );\n }\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n}\n\n/**\n * Validate an object that we expect to be a sequence node definition.\n * @param definition An object that we expect to be a sequence node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateSequenceNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"sequence\") {\n throw new Error(`expected node type of 'sequence' for sequence node at depth '${depth}'`);\n }\n\n // A sequence node is a composite node, so must have a children nodes array defined.\n if (!Array.isArray(definition.children) || definition.children.length === 0) {\n throw new Error(`expected non-empty 'children' array to be defined for sequence node at depth '${depth}'`);\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n\n // Validate the child nodes of this composite node.\n definition.children.forEach((child: any) => validateNode(child, depth + 1));\n}\n\n/**\n * Validate an object that we expect to be a selector node definition.\n * @param definition An object that we expect to be a selector node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateSelectorNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"selector\") {\n throw new Error(`expected node type of 'selector' for selector node at depth '${depth}'`);\n }\n\n // A selector node is a composite node, so must have a children nodes array defined.\n if (!Array.isArray(definition.children) || definition.children.length === 0) {\n throw new Error(`expected non-empty 'children' array to be defined for selector node at depth '${depth}'`);\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n\n // Validate the child nodes of this composite node.\n definition.children.forEach((child: any) => validateNode(child, depth + 1));\n}\n\n/**\n * Validate an object that we expect to be a parallel node definition.\n * @param definition An object that we expect to be a parallel node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateParallelNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"parallel\") {\n throw new Error(`expected node type of 'parallel' for parallel node at depth '${depth}'`);\n }\n\n // A parallel node is a composite node, so must have a children nodes array defined.\n if (!Array.isArray(definition.children) || definition.children.length === 0) {\n throw new Error(`expected non-empty 'children' array to be defined for parallel node at depth '${depth}'`);\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n\n // Validate the child nodes of this composite node.\n definition.children.forEach((child: any) => validateNode(child, depth + 1));\n}\n", "import Node from \"../../nodes/Node\";\n\n/**\n * An exception thrown when evaluating node guard path conditions and a conditions fails.\n */\nexport default class GuardUnsatisifedException extends Error {\n /**\n * @param source The node at which a guard condition failed.\n */\n constructor(private source: Node) {\n super(\"A guard path condition has failed\");\n }\n\n /**\n * Gets whether the specified node is the node at which a guard condition failed.\n * @param node The node to check against the source node.\n * @returns Whether the specified node is the node at which a guard condition failed.\n */\n isSourceNode = (node: Node) => node === this.source;\n}\n", "import { Agent } from \"../../Agent\";\nimport Guard from \"./Guard\";\nimport Node from \"../../nodes/Node\";\nimport GuardUnsatisifedException from \"./GuardUnsatisifedException\";\n\nexport type GuardPathPart = {\n node: Node;\n guards: Guard[];\n};\n\n/**\n * Represents a path of node guards along a root-to-leaf tree path.\n */\nexport default class GuardPath {\n /**\n * @param nodes An array of objects defining a node instance -> guard link, ordered by node depth.\n */\n constructor(private nodes: GuardPathPart[]) {}\n\n /**\n * Evaluate guard conditions for all guards in the tree path, moving outwards from the root.\n * @param agent The agent, required for guard evaluation.\n * @returns An evaluation results object.\n */\n evaluate = (agent: Agent) => {\n // We need to evaluate guard conditions for nodes up the tree, moving outwards from the root.\n for (const details of this.nodes) {\n // There can be multiple guards per node.\n for (const guard of details.guards) {\n // Check whether the guard condition passes, and throw an exception if not.\n if (!guard.isSatisfied(agent)) {\n throw new GuardUnsatisifedException(details.node);\n }\n }\n }\n };\n}\n", "import { Agent } from \"../Agent\";\nimport Attribute from \"../attributes/Attribute\";\nimport Entry from \"../attributes/callbacks/Entry\";\nimport Exit from \"../attributes/callbacks/Exit\";\nimport Step from \"../attributes/callbacks/Step\";\nimport Guard from \"../attributes/guards/Guard\";\nimport GuardPath from \"../attributes/guards/GuardPath\";\nimport GuardUnsatisifedException from \"../attributes/guards/GuardUnsatisifedException\";\nimport { BehaviourTreeOptions } from \"../BehaviourTreeOptions\";\nimport { AnyArgument } from \"../RootAstNodesBuilder\";\nimport State, { AnyState } from \"../State\";\nimport Leaf from \"./leaf/Leaf\";\n\n/**\n * A base node.\n */\nexport default abstract class Node {\n /**\n * The node uid.\n */\n private readonly uid: string = createNodeUid();\n /**\n * The node state.\n */\n private state: AnyState = State.READY;\n /**\n * The guard path to evaluate as part of a node update.\n */\n private guardPath: GuardPath | undefined;\n\n /**\n * @param type The node type.\n * @param attributes The node attributes.\n * @param args The node argument definitions.\n */\n constructor(private type: string, private attributes: Attribute[], private args: AnyArgument[]) {}\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected abstract onUpdate(agent: Agent, options: BehaviourTreeOptions): void;\n\n /**\n * Gets the name of the node.\n */\n public abstract getName(): string;\n\n /**\n * Gets whether this node is a leaf node.\n */\n public abstract isLeafNode: () => this is Leaf;\n\n /**\n * Gets/Sets the state of the node.\n */\n getState = (): AnyState => this.state;\n setState = (value: AnyState): void => {\n this.state = value;\n };\n\n /**\n * Gets the unique id of the node.\n */\n getUid = () => this.uid;\n\n /**\n * Gets the type of the node.\n */\n getType = () => this.type;\n\n /**\n * Gets the node attributes.\n */\n getAttributes = () => this.attributes;\n\n /**\n * Gets the node arguments.\n */\n getArguments = () => this.args;\n\n /**\n * Gets the node attribute with the specified type, or null if it does not exist.\n */\n getAttribute(type: \"entry\" | \"ENTRY\"): Entry;\n getAttribute(type: \"exit\" | \"EXIT\"): Exit;\n getAttribute(type: \"step\" | \"STEP\"): Step;\n getAttribute(type: string): Attribute {\n return (\n this.getAttributes().filter((decorator) => decorator.getType().toUpperCase() === type.toUpperCase())[0] ||\n null\n );\n }\n\n /**\n * Gets the node attributes.\n */\n getGuardAttributes = (): Guard[] => this.getAttributes().filter((decorator) => decorator.isGuard()) as Guard[];\n\n /**\n * Sets the guard path to evaluate as part of a node update.\n */\n setGuardPath = (value: GuardPath) => (this.guardPath = value);\n\n /**\n * Gets whether a guard path is assigned to this node.\n */\n hasGuardPath = () => !!this.guardPath;\n\n /**\n * Gets whether this node is in the specified state.\n * @param value The value to compare to the node state.\n */\n public is(value: AnyState): boolean {\n return this.state === value;\n }\n\n /**\n * Reset the state of the node.\n */\n public reset(): void {\n this.setState(State.READY);\n }\n\n /**\n * Abort the running of this node.\n * @param agent The agent.\n */\n public abort(agent: Agent): void {\n // There is nothing to do if this node is not in the running state.\n if (!this.is(State.RUNNING)) {\n return;\n }\n\n // Reset the state of this node.\n this.reset();\n\n this.getAttribute(\"exit\")?.callAgentFunction(agent, false, true);\n }\n\n /**\n * Update the node.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n * @returns The result of the update.\n */\n public update(agent: Agent, options: BehaviourTreeOptions): void {\n // If this node is already in a 'SUCCEEDED' or 'FAILED' state then there is nothing to do.\n if (this.is(State.SUCCEEDED) || this.is(State.FAILED)) {\n return;\n }\n\n try {\n // Evaluate all of the guard path conditions for the current tree path.\n this.guardPath!.evaluate(agent);\n\n // If this node is in the READY state then call the ENTRY for this node if it exists.\n if (this.is(State.READY)) {\n this.getAttribute(\"entry\")?.callAgentFunction(agent);\n }\n\n this.getAttribute(\"step\")?.callAgentFunction(agent);\n\n // Do the actual update.\n this.onUpdate(agent, options);\n\n // If this node is now in a 'SUCCEEDED' or 'FAILED' state then call the EXIT for this node if it exists.\n if (this.is(State.SUCCEEDED) || this.is(State.FAILED)) {\n this.getAttribute(\"exit\")?.callAgentFunction(agent, this.is(State.SUCCEEDED), false);\n }\n } catch (error) {\n // If the error is a GuardUnsatisfiedException then we need to determine if this node is the source.\n if (error instanceof GuardUnsatisifedException && error.isSourceNode(this)) {\n // Abort the current node.\n this.abort(agent);\n\n // Any node that is the source of an abort will be a failed node.\n this.setState(State.FAILED);\n } else {\n throw error;\n }\n }\n }\n}\n\n/**\n * Create a randomly generated node uid.\n * @returns A randomly generated node uid.\n */\nfunction createNodeUid(): string {\n var S4 = function () {\n return (((1 + Math.random()) * 0x10000) | 0).toString(16).substring(1);\n };\n return S4() + S4() + \"-\" + S4() + \"-\" + S4() + \"-\" + S4() + \"-\" + S4() + S4() + S4();\n}\n", "import Node from \"../Node\";\n\n/**\n * A leaf node.\n */\nexport default abstract class Leaf extends Node {\n /**\n * Gets whether this node is a leaf node.\n */\n isLeafNode = () => true;\n}\n", "import { ActionResult, Agent, ExitFunctionArg, FunctionArg, GlobalFunction } from \"./Agent\";\nimport { AnyArgument, RootAstNode } from \"./RootAstNodesBuilder\";\n\n// Exit callbacks receive their own special type of argument.\n// There's probably stricter ways to represent this but it feels overly complex right now.\ntype ExitResultArg = { value: ExitFunctionArg };\nexport type AnyExitArgument = AnyArgument | ExitResultArg;\n\nexport type InvokerFunction = (args: AnyExitArgument[]) => ActionResult;\n\n/**\n * A singleton used to store and lookup registered functions and subtrees.\n */\nexport default class Lookup {\n /**\n * The object holding any registered functions keyed on function name.\n */\n private static functionTable: { [key: string]: GlobalFunction } = {};\n /**\n * The object holding any registered sub-trees keyed on tree name.\n */\n private static subtreeTable: { [key: string]: RootAstNode } = {};\n\n /**\n * Gets the function with the specified name.\n * @param name The name of the function.\n * @returns The function with the specified name.\n */\n public static getFunc(name: string): GlobalFunction {\n return this.functionTable[name];\n }\n\n /**\n * Sets the function with the specified name for later lookup.\n * @param name The name of the function.\n * @param func The function.\n */\n public static setFunc(name: string, func: GlobalFunction): void {\n this.functionTable[name] = func;\n }\n\n /**\n * Gets the function invoker for the specified agent and function name.\n * If a function with the specified name exists on the agent object then it will\n * be returned, otherwise we will then check the registered functions for a match.\n * @param agent The agent instance that this behaviour tree is modelling behaviour for.\n * @param name The function name.\n * @returns The function invoker for the specified agent and function name.\n */\n static getFuncInvoker(agent: Agent, name: string): InvokerFunction | null {\n // Check whether the agent contains the specified function.\n const foundOnAgent = agent[name];\n if (foundOnAgent && typeof foundOnAgent === \"function\") {\n return (args: AnyExitArgument[]): boolean | ActionResult =>\n foundOnAgent.apply(\n agent,\n args.map((arg) => arg.value)\n );\n }\n\n // The agent does not contain the specified function but it may have been registered at some point.\n if (this.functionTable[name] && typeof this.functionTable[name] === \"function\") {\n return (args: AnyExitArgument[]) => this.functionTable[name](agent, ...args.map((arg) => arg.value));\n }\n\n // We have no function to invoke.\n return null;\n }\n\n /**\n * Gets the subtree with the specified name.\n * @param name The name of the subtree.\n * @returns The subtree with the specified name.\n */\n static getSubtree(name: string): RootAstNode {\n return this.subtreeTable[name];\n }\n\n /**\n * Sets the subtree with the specified name for later lookup.\n * @param name The name of the subtree.\n * @param subtree The subtree.\n */\n static setSubtree(name: string, subtree: RootAstNode) {\n this.subtreeTable[name] = subtree;\n }\n\n /**\n * Removes the registered function or subtree with the specified name.\n * @param name The name of the registered function or subtree.\n */\n static remove(name: string) {\n delete this.functionTable[name];\n delete this.subtreeTable[name];\n }\n\n /**\n * Remove all registered functions and subtrees.\n */\n static empty() {\n this.functionTable = {};\n this.subtreeTable = {};\n }\n}\n", "import Leaf from \"./Leaf\";\nimport State, { CompleteState } from \"../../State\";\nimport Lookup from \"../../Lookup\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { AnyArgument } from \"../../RootAstNodesBuilder\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * An Action leaf node.\n * This represents an immediate or ongoing state of behaviour.\n */\nexport default class Action extends Leaf {\n /**\n * @param attributes The node attributes.\n * @param actionName The action name.\n * @param actionArguments The array of action argument definitions.\n */\n constructor(attributes: Attribute[], private actionName: string, private actionArguments: AnyArgument[]) {\n super(\"action\", attributes, actionArguments);\n }\n\n /**\n * Whether there is a pending update promise.\n */\n private isUsingUpdatePromise = false;\n\n /**\n * The finished state result of an update promise.\n */\n private updatePromiseStateResult: CompleteState | null = null;\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // If the result of this action depends on an update promise then there is nothing to do until\n // it resolves, unless there has been a value set as a result of the update promise resolving.\n if (this.isUsingUpdatePromise) {\n // Check whether the update promise has resolved with a state value.\n if (this.updatePromiseStateResult) {\n // Set the state of this node to match the state returned by the promise.\n this.setState(this.updatePromiseStateResult);\n }\n\n return;\n }\n\n // Attempt to get the invoker for the action function.\n const actionFuncInvoker = Lookup.getFuncInvoker(agent, this.actionName);\n\n // The action function should be defined.\n if (actionFuncInvoker === null) {\n throw new Error(\n `cannot update action node as the action '${this.actionName}' function is not defined on the agent and has not been registered`\n );\n }\n\n // Call the action function, the result of which may be:\n // - The finished state of this action node.\n // - A promise to return a finished node state.\n // - Undefined if the node should remain in the running state.\n const updateResult = actionFuncInvoker(this.actionArguments) as CompleteState | Promise;\n\n if (updateResult instanceof Promise) {\n updateResult.then(\n (result) => {\n // If 'isUpdatePromisePending' is null then the promise was cleared as it was resolving, probably via an abort of reset.\n if (!this.isUsingUpdatePromise) {\n return;\n }\n\n // Check to make sure the result is a valid finished state.\n if (result !== State.SUCCEEDED && result !== State.FAILED) {\n throw new Error(\n \"action node promise resolved with an invalid value, expected a State.SUCCEEDED or State.FAILED value to be returned\"\n );\n }\n\n // Set pending update promise state result to be processed on next update.\n this.updatePromiseStateResult = result;\n },\n (reason) => {\n // If 'isUpdatePromisePending' is null then the promise was cleared as it was resolving, probably via an abort of reset.\n if (!this.isUsingUpdatePromise) {\n return;\n }\n\n // Just throw whatever was returned as the rejection argument.\n throw new Error(reason);\n }\n );\n\n // This node will be in the 'RUNNING' state until the update promise resolves.\n this.setState(State.RUNNING);\n\n // We are now waiting for the promise returned by the use to resolve before we know what state this node is in.\n this.isUsingUpdatePromise = true;\n } else {\n // Validate the returned value.\n this.validateUpdateResult(updateResult);\n\n // Set the state of this node, this may be undefined, which just means that the node is still in the 'RUNNING' state.\n this.setState(updateResult || State.RUNNING);\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => this.actionName;\n\n /**\n * Reset the state of the node.\n */\n reset = () => {\n // Reset the state of this node.\n this.setState(State.READY);\n\n // There is no longer an update promise that we care about.\n this.isUsingUpdatePromise = false;\n this.updatePromiseStateResult = null;\n };\n\n /**\n * Validate the result of an update function call.\n * @param result The result of an update function call.\n */\n private validateUpdateResult = (result: CompleteState | boolean) => {\n switch (result) {\n case State.SUCCEEDED:\n case State.FAILED:\n case undefined:\n return;\n default:\n throw new Error(\n `action '${this.actionName}' 'onUpdate' returned an invalid response, expected an optional State.SUCCEEDED or State.FAILED value to be returned`\n );\n }\n };\n}\n", "import Leaf from \"./Leaf\";\nimport State from \"../../State\";\nimport Lookup from \"../../Lookup\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { AnyArgument } from \"../../RootAstNodesBuilder\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A Condition leaf node.\n * This will succeed or fail immediately based on an agent predicate, without moving to the 'RUNNING' state.\n */\nexport default class Condition extends Leaf {\n /**\n * @param attributes The node attributes.\n * @param conditionName The name of the condition function.\n * @param conditionArguments The array of condition argument definitions.\n */\n constructor(attributes: Attribute[], private conditionName: string, private conditionArguments: AnyArgument[]) {\n super(\"condition\", attributes, conditionArguments);\n }\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // Attempt to get the invoker for the condition function.\n const conditionFuncInvoker = Lookup.getFuncInvoker(agent, this.conditionName);\n\n // The condition function should be defined.\n if (conditionFuncInvoker === null) {\n throw new Error(\n `cannot update condition node as the condition '${this.conditionName}' function is not defined on the agent and has not been registered`\n );\n }\n\n // Call the condition function to determine the state of this node.\n this.setState(!!conditionFuncInvoker(this.conditionArguments) ? State.SUCCEEDED : State.FAILED);\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => this.conditionName;\n}\n", "import Leaf from \"./Leaf\";\nimport State from \"../../State\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { Agent } from \"../../Agent\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A WAIT node.\n * The state of this node will change to SUCCEEDED after a duration of time\n */\nexport default class Wait extends Leaf {\n /**\n * @param attributes The node attributes.\n * @param duration The duration that this node will wait to succeed in milliseconds.\n * @param durationMin The minimum possible duration in milliseconds that this node will wait to succeed.\n * @param durationMax The maximum possible duration in milliseconds that this node will wait to succeed.\n */\n constructor(\n attributes: Attribute[],\n private duration: number | null,\n private durationMin: number | null,\n private durationMax: number | null\n ) {\n super(\"wait\", attributes, []);\n }\n\n /**\n * The time in milliseconds at which this node was first updated.\n */\n private initialUpdateTime: number = 0;\n\n /**\n * The total duration in milliseconds that this node will be waiting for.\n */\n private totalDuration: number | null = null;\n\n /**\n * The duration in milliseconds that this node has been waiting for.\n */\n private waitedDuration: number = 0;\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // If this node is in the READY state then we need to set the initial update time.\n if (this.is(State.READY)) {\n // Set the initial update time.\n this.initialUpdateTime = new Date().getTime();\n\n // Set the initial waited duration.\n this.waitedDuration = 0;\n\n // Are we dealing with an explicit duration or will we be randomly picking a duration between the min and max duration.\n if (this.duration !== null) {\n this.totalDuration = this.duration;\n } else if (this.durationMin !== null && this.durationMax !== null) {\n // We will be picking a random duration between a min and max duration, if the optional 'random' behaviour tree\n // function option is defined then we will be using that, otherwise we will fall back to using Math.random.\n const random = typeof options.random === \"function\" ? options.random : Math.random;\n\n // Pick a random duration between a min and max duration.\n this.totalDuration = Math.floor(\n random() * (this.durationMax - this.durationMin + 1) + this.durationMin\n );\n } else {\n this.totalDuration = null;\n }\n\n // The node is now running until we finish waiting.\n this.setState(State.RUNNING);\n }\n\n // If we have no total duration then this wait node will wait indefinitely until it is aborted.\n if (this.totalDuration === null) {\n return;\n }\n\n // If we have a 'getDeltaTime' function defined as part of our options then we will use it to figure out how long we have waited for.\n if (typeof options.getDeltaTime === \"function\") {\n // Get the delta time.\n const deltaTime = options.getDeltaTime();\n\n // Our delta time must be a valid number and cannot be NaN.\n if (typeof deltaTime !== \"number\" || isNaN(deltaTime)) {\n throw new Error(\"The delta time must be a valid number and not NaN.\");\n }\n\n // Update the amount of time that this node has been waiting for based on the delta time.\n this.waitedDuration += deltaTime * 1000;\n } else {\n // We are not using a delta time, so we will just work out hom much time has passed since the first update.\n this.waitedDuration = new Date().getTime() - this.initialUpdateTime;\n }\n\n // Have we waited long enough?\n if (this.waitedDuration >= this.totalDuration) {\n // We have finished waiting!\n this.setState(State.SUCCEEDED);\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => {\n if (this.duration !== null) {\n return `WAIT ${this.duration}ms`;\n } else if (this.durationMin !== null && this.durationMax !== null) {\n return `WAIT ${this.durationMin}ms-${this.durationMax}ms`;\n } else {\n return \"WAIT\";\n }\n };\n}\n", "import Node from \"../Node\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\n\n/**\n * A decorator node that wraps a single child node.\n */\nexport default abstract class Decorator extends Node {\n /**\n * @param type The node type.\n * @param attributes The node attributes.\n * @param child The child node.\n */\n constructor(type: string, attributes: Attribute[], protected child: Node) {\n super(type, attributes, []);\n }\n\n /**\n * Gets whether this node is a leaf node.\n */\n isLeafNode = () => false;\n\n /**\n * Gets the children of this node.\n */\n getChildren = () => [this.child];\n\n /**\n * Reset the state of the node.\n */\n reset = () => {\n // Reset the state of this node.\n this.setState(State.READY);\n\n // Reset the state of the child node.\n this.child.reset();\n };\n\n /**\n * Abort the running of this node.\n * @param agent The agent.\n */\n abort = (agent: Agent) => {\n // There is nothing to do if this node is not in the running state.\n if (!this.is(State.RUNNING)) {\n return;\n }\n\n // Abort the child node.\n this.child.abort(agent);\n\n // Reset the state of this node.\n this.reset();\n\n this.getAttribute(\"exit\")?.callAgentFunction(agent, false, true);\n };\n}\n", "import Node from \"../Node\";\nimport Decorator from \"./Decorator\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A Root node.\n * The root node will have a single child.\n */\nexport default class Root extends Decorator {\n /**\n * @param attributes The node attributes.\n * @param child The child node.\n */\n constructor(attributes: Attribute[], child: Node) {\n super(\"root\", attributes, child);\n }\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // If the child has never been updated or is running then we will need to update it now.\n if (this.child.getState() === State.READY || this.child.getState() === State.RUNNING) {\n // Update the child of this node.\n this.child.update(agent, options);\n }\n\n // The state of the root node is the state of its child.\n this.setState(this.child.getState());\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => \"ROOT\";\n}\n", "import Node from \"../Node\";\nimport Decorator from \"./Decorator\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A REPEAT node.\n * The node has a single child which can have:\n * -- A number of iterations for which to repeat the child node.\n * -- An infinite repeat loop if neither an iteration count or a condition function is defined.\n * The REPEAT node will stop and have a 'FAILED' state if its child is ever in a 'FAILED' state after an update.\n * The REPEAT node will attempt to move on to the next iteration if its child is ever in a 'SUCCEEDED' state.\n */\nexport default class Repeat extends Decorator {\n /**\n * @param attributes The node attributes.\n * @param iterations The number of iterations to repeat the child node.\n * @param iterationsMin The minimum possible number of iterations to repeat the child node.\n * @param iterationsMax The maximum possible number of iterations to repeat the child node.\n * @param child The child node.\n */\n constructor(\n attributes: Attribute[],\n private iterations: number | null,\n private iterationsMin: number | null,\n private iterationsMax: number | null,\n child: Node\n ) {\n super(\"repeat\", attributes, child);\n }\n\n /**\n * The number of target iterations to make.\n */\n private targetIterationCount: number | null = null;\n\n /**\n * The current iteration count.\n */\n private currentIterationCount: number = 0;\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // If this node is in the READY state then we need to reset the child and the target iteration count.\n if (this.is(State.READY)) {\n // Reset the child node.\n this.child.reset();\n\n // Reset the current iteration count.\n this.currentIterationCount = 0;\n\n // Set the target iteration count.\n this.setTargetIterationCount(options);\n }\n\n // Do a check to see if we can iterate. If we can then this node will move into the 'RUNNING' state.\n // If we cannot iterate then we have hit our target iteration count, which means that the node has succeeded.\n if (this.canIterate()) {\n // This node is in the running state and can do its initial iteration.\n this.setState(State.RUNNING);\n\n // We may have already completed an iteration, meaning that the child node will be in the SUCCEEDED state.\n // If this is the case then we will have to reset the child node now.\n if (this.child.getState() === State.SUCCEEDED) {\n this.child.reset();\n }\n\n // Update the child of this node.\n this.child.update(agent, options);\n\n // If the child moved into the FAILED state when we updated it then there is nothing left to do and this node has also failed.\n // If it has moved into the SUCCEEDED state then we have completed the current iteration.\n if (this.child.getState() === State.FAILED) {\n // The child has failed, meaning that this node has failed.\n this.setState(State.FAILED);\n\n return;\n } else if (this.child.getState() === State.SUCCEEDED) {\n // We have completed an iteration.\n this.currentIterationCount += 1;\n }\n } else {\n // This node is in the 'SUCCEEDED' state as we cannot iterate any more.\n this.setState(State.SUCCEEDED);\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => {\n if (this.iterations !== null) {\n return `REPEAT ${this.iterations}x`;\n } else if (this.iterationsMin !== null && this.iterationsMax !== null) {\n return `REPEAT ${this.iterationsMin}x-${this.iterationsMax}x`;\n } else {\n return \"REPEAT\";\n }\n };\n\n /**\n * Reset the state of the node.\n */\n reset = () => {\n // Reset the state of this node.\n this.setState(State.READY);\n\n // Reset the current iteration count.\n this.currentIterationCount = 0;\n\n // Reset the child node.\n this.child.reset();\n };\n\n /**\n * Gets whether an iteration can be made.\n * @returns Whether an iteration can be made.\n */\n private canIterate = () => {\n if (this.targetIterationCount !== null) {\n // We can iterate as long as we have not reached our target iteration count.\n return this.currentIterationCount < this.targetIterationCount;\n }\n\n // If neither an iteration count or a condition function were defined then we can iterate indefinitely.\n return true;\n };\n\n /**\n * Sets the target iteration count.\n * @param options The behaviour tree options object.\n */\n private setTargetIterationCount = (options: BehaviourTreeOptions) => {\n // Are we dealing with an explicit iteration count or will we be randomly picking a iteration count between the min and max iteration count.\n if (this.iterations !== null) {\n this.targetIterationCount = this.iterations;\n } else if (this.iterationsMin !== null && this.iterationsMax !== null) {\n // We will be picking a random iteration count between a min and max iteration count, if the optional 'random'\n // behaviour tree function option is defined then we will be using that, otherwise we will fall back to using Math.random.\n const random = typeof options.random === \"function\" ? options.random : Math.random;\n\n // Pick a random iteration count between a min and max iteration count.\n this.targetIterationCount = Math.floor(\n random() * (this.iterationsMax - this.iterationsMin + 1) + this.iterationsMin\n );\n } else {\n this.targetIterationCount = null;\n }\n };\n}\n", "import Node from \"../Node\";\nimport Decorator from \"./Decorator\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A RETRY node.\n * The node has a single child which can have:\n * -- A number of iterations for which to repeat the child node.\n * -- An infinite repeat loop if neither an iteration count or a condition function is defined.\n * The RETRY node will stop and have a 'SUCCEEDED' state if its child is ever in a 'SUCCEEDED' state after an update.\n * The RETRY node will attempt to move on to the next iteration if its child is ever in a 'FAILED' state.\n */\nexport default class Retry extends Decorator {\n /**\n * @param attributes The node attributes.\n * @param attempts The number of attempts to retry the child node.\n * @param attemptsMin The minimum possible number of attempts to retry the child node.\n * @param attemptsMax The maximum possible number of attempts to retry the child node.\n * @param child The child node.\n */\n constructor(\n attributes: Attribute[],\n private attempts: number | null,\n private attemptsMin: number | null,\n private attemptsMax: number | null,\n child: Node\n ) {\n super(\"retry\", attributes, child);\n }\n\n /**\n * The number of target attempts to make.\n */\n private targetAttemptCount: number | null = null;\n\n /**\n * The current attempt count.\n */\n private currentAttemptCount: number = 0;\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // If this node is in the READY state then we need to reset the child and the target attempt count.\n if (this.is(State.READY)) {\n // Reset the child node.\n this.child.reset();\n\n // Reset the current attempt count.\n this.currentAttemptCount = 0;\n\n // Set the target attempt count.\n this.setTargetAttemptCount(options);\n }\n\n // Do a check to see if we can attempt. If we can then this node will move into the 'RUNNING' state.\n // If we cannot attempt then we have hit our target attempt count, which means that the node has succeeded.\n if (this.canAttempt()) {\n // This node is in the running state and can do its initial attempt.\n this.setState(State.RUNNING);\n\n // We may have already completed an attempt, meaning that the child node will be in the FAILED state.\n // If this is the case then we will have to reset the child node now.\n if (this.child.getState() === State.FAILED) {\n this.child.reset();\n }\n\n // Update the child of this node.\n this.child.update(agent, options);\n\n // If the child moved into the SUCCEEDED state when we updated it then there is nothing left to do and this node has also succeeded.\n // If it has moved into the FAILED state then we have completed the current attempt.\n if (this.child.getState() === State.SUCCEEDED) {\n // The child has succeeded, meaning that this node has succeeded.\n this.setState(State.SUCCEEDED);\n\n return;\n } else if (this.child.getState() === State.FAILED) {\n // We have completed an attempt.\n this.currentAttemptCount += 1;\n }\n } else {\n // This node is in the 'FAILED' state as we cannot iterate any more.\n this.setState(State.FAILED);\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => {\n if (this.attempts !== null) {\n return `RETRY ${this.attempts}x`;\n } else if (this.attemptsMin !== null && this.attemptsMax !== null) {\n return `RETRY ${this.attemptsMin}x-${this.attemptsMax}x`;\n } else {\n return \"RETRY\";\n }\n };\n\n /**\n * Reset the state of the node.\n */\n reset = () => {\n // Reset the state of this node.\n this.setState(State.READY);\n\n // Reset the current attempt count.\n this.currentAttemptCount = 0;\n\n // Reset the child node.\n this.child.reset();\n };\n\n /**\n * Gets whether an attempt can be made.\n * @returns Whether an attempt can be made.\n */\n canAttempt = () => {\n if (this.targetAttemptCount !== null) {\n // We can attempt as long as we have not reached our target attempt count.\n return this.currentAttemptCount < this.targetAttemptCount;\n }\n\n // If neither an attempt count or a condition function were defined then we can attempt indefinitely.\n return true;\n };\n\n /**\n * Sets the target attempt count.\n * @param options The behaviour tree options object.\n */\n setTargetAttemptCount = (options: BehaviourTreeOptions) => {\n // Are we dealing with an explicit attempt count or will we be randomly picking an attempt count between the min and max attempt count.\n if (this.attempts !== null) {\n this.targetAttemptCount = this.attempts;\n } else if (this.attemptsMin !== null && this.attemptsMax !== null) {\n // We will be picking a random attempt count between a min and max attempt count, if the optional 'random'\n // behaviour tree function option is defined then we will be using that, otherwise we will fall back to using Math.random.\n const random = typeof options.random === \"function\" ? options.random : Math.random;\n\n // Pick a random attempt count between a min and max attempt count.\n this.targetAttemptCount = Math.floor(\n random() * (this.attemptsMax - this.attemptsMin + 1) + this.attemptsMin\n );\n } else {\n this.targetAttemptCount = null;\n }\n };\n}\n", "import Decorator from \"./Decorator\";\nimport State from \"../../State\";\nimport Node from \"../Node\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A Flip node.\n * This node wraps a single child and will flip the state of the child state.\n */\nexport default class Flip extends Decorator {\n /**\n * @param attributes The node attributes.\n * @param child The child node.\n */\n constructor(attributes: Attribute[], child: Node) {\n super(\"flip\", attributes, child);\n }\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // If the child has never been updated or is running then we will need to update it now.\n if (this.child.getState() === State.READY || this.child.getState() === State.RUNNING) {\n this.child.update(agent, options);\n }\n\n // The state of this node will depend in the state of its child.\n switch (this.child.getState()) {\n case State.RUNNING:\n this.setState(State.RUNNING);\n break;\n\n case State.SUCCEEDED:\n this.setState(State.FAILED);\n break;\n\n case State.FAILED:\n this.setState(State.SUCCEEDED);\n break;\n\n default:\n this.setState(State.READY);\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => \"FLIP\";\n}\n", "import Node from \"../Node\";\nimport Decorator from \"./Decorator\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A Succeed node.\n * This node wraps a single child and will always move to the 'SUCCEEDED' state when the child moves to a 'SUCCEEDED' or 'FAILED' state.\n */\nexport default class Succeed extends Decorator {\n /**\n * @param attributes The node attributes.\n * @param child The child node.\n */\n constructor(attributes: Attribute[], child: Node) {\n super(\"succeed\", attributes, child);\n }\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // If the child has never been updated or is running then we will need to update it now.\n if (this.child.getState() === State.READY || this.child.getState() === State.RUNNING) {\n this.child.update(agent, options);\n }\n\n // The state of this node will depend in the state of its child.\n switch (this.child.getState()) {\n case State.RUNNING:\n this.setState(State.RUNNING);\n break;\n\n case State.SUCCEEDED:\n case State.FAILED:\n this.setState(State.SUCCEEDED);\n break;\n\n default:\n this.setState(State.READY);\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => \"SUCCEED\";\n}\n", "import Node from \"../Node\";\nimport Decorator from \"./Decorator\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A Fail node.\n * This node wraps a single child and will always move to the 'FAILED' state when the child moves to a 'SUCCEEDED' or 'FAILED' state.\n */\nexport default class Fail extends Decorator {\n /**\n * @param attributes The node attributes.\n * @param child The child node.\n */\n constructor(attributes: Attribute[], child: Node) {\n super(\"fail\", attributes, child);\n }\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // If the child has never been updated or is running then we will need to update it now.\n if (this.child.getState() === State.READY || this.child.getState() === State.RUNNING) {\n this.child.update(agent, options);\n }\n\n // The state of this node will depend in the state of its child.\n switch (this.child.getState()) {\n case State.RUNNING:\n this.setState(State.RUNNING);\n break;\n\n case State.SUCCEEDED:\n case State.FAILED:\n this.setState(State.FAILED);\n break;\n\n default:\n this.setState(State.READY);\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => \"FAIL\";\n}\n", "import createLotto from \"lotto-draw\";\n\nimport Node from \"../Node\";\nimport Composite from \"./Composite\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A LOTTO node.\n * A winning child is picked on the initial update of this node, based on ticket weighting.\n * The state of this node will match the state of the winning child.\n */\nexport default class Lotto extends Composite {\n /**\n * @param attributes The node attributes.\n * @param tickets The child node tickets.\n * @param children The child nodes.\n */\n constructor(attributes: Attribute[], private tickets: number[], children: Node[]) {\n super(\"lotto\", attributes, children);\n }\n\n /**\n * The child node selected to be the active one.\n */\n private selectedChild: Node | undefined;\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // If this node is in the READY state then we need to pick a winning child node.\n if (this.is(State.READY)) {\n // Create a lotto draw with which to randomly pick a child node to become the active one.\n const lottoDraw = createLotto({\n // Hook up the optional 'random' behaviour tree function option to the one used by 'lotto-draw'.\n random: options.random,\n // Pass in each child node as a participant in the lotto draw with their respective ticket count.\n participants: this.children.map((child, index) => [child, this.tickets[index] || 1])\n });\n\n // Randomly pick a child based on ticket weighting, this will become the active child for this composite node.\n this.selectedChild = lottoDraw.draw() || undefined;\n }\n\n // If something went wrong and we don't have an active child then we should throw an error.\n if (!this.selectedChild) {\n throw new Error(\"failed to update lotto node as it has no active child\");\n }\n\n // If the selected child has never been updated or is running then we will need to update it now.\n if (this.selectedChild.getState() === State.READY || this.selectedChild.getState() === State.RUNNING) {\n this.selectedChild.update(agent, options);\n }\n\n // The state of the lotto node is the state of its selected child.\n this.setState(this.selectedChild.getState());\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => (this.tickets.length ? `LOTTO [${this.tickets.join(\",\")}]` : \"LOTTO\");\n}\n", "import Node from \"../Node\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\n\n/**\n * A composite node that wraps child nodes.\n */\nexport default abstract class Composite extends Node {\n /**\n * @param type The node type.\n * @param attributes The node attributes.\n * @param children The child nodes.\n */\n constructor(type: string, attributes: Attribute[], protected children: Node[]) {\n super(type, attributes, []);\n }\n\n /**\n * Gets whether this node is a leaf node.\n */\n isLeafNode = () => false;\n\n /**\n * Gets the children of this node.\n */\n getChildren = () => this.children;\n\n /**\n * Reset the state of the node.\n */\n reset = () => {\n // Reset the state of this node.\n this.setState(State.READY);\n\n // Reset the state of any child nodes.\n this.getChildren().forEach((child) => child.reset());\n };\n\n /**\n * Abort the running of this node.\n * @param agent The agent.\n */\n abort = (agent: Agent) => {\n // There is nothing to do if this node is not in the running state.\n if (!this.is(State.RUNNING)) {\n return;\n }\n\n // Abort any child nodes.\n this.getChildren().forEach((child) => child.abort(agent));\n\n // Reset the state of this node.\n this.reset();\n\n this.getAttribute(\"exit\")?.callAgentFunction(agent, false, true);\n };\n}\n", "import Composite from \"./Composite\";\nimport Node from \"../Node\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A SELECTOR node.\n * The child nodes are executed in sequence until one succeeds or all fail.\n */\nexport default class Selector extends Composite {\n /**\n * @param attributes The node attributes.\n * @param children The child nodes.\n */\n constructor(attributes: Attribute[], protected children: Node[]) {\n super(\"selector\", attributes, children);\n }\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // Iterate over all of the children of this node.\n for (const child of this.children) {\n // If the child has never been updated or is running then we will need to update it now.\n if (child.getState() === State.READY || child.getState() === State.RUNNING) {\n // Update the child of this node.\n child.update(agent, options);\n }\n\n // If the current child has a state of 'SUCCEEDED' then this node is also a 'SUCCEEDED' node.\n if (child.getState() === State.SUCCEEDED) {\n // This node is a 'SUCCEEDED' node.\n this.setState(State.SUCCEEDED);\n\n // There is no need to check the rest of the selector nodes.\n return;\n }\n\n // If the current child has a state of 'FAILED' then we should move on to the next child.\n if (child.getState() === State.FAILED) {\n // Find out if the current child is the last one in the selector.\n // If it is then this sequence node has also failed.\n if (this.children.indexOf(child) === this.children.length - 1) {\n // This node is a 'FAILED' node.\n this.setState(State.FAILED);\n\n // There is no need to check the rest of the selector as we have completed it.\n return;\n } else {\n // The child node failed, try the next one.\n continue;\n }\n }\n\n // The node should be in the 'RUNNING' state.\n if (child.getState() === State.RUNNING) {\n // This node is a 'RUNNING' node.\n this.setState(State.RUNNING);\n\n // There is no need to check the rest of the selector as the current child is still running.\n return;\n }\n\n // The child node was not in an expected state.\n throw new Error(\"child node was not in an expected state.\");\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => \"SELECTOR\";\n}\n", "import Composite from \"./Composite\";\nimport Node from \"../Node\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A SEQUENCE node.\n * The child nodes are executed in sequence until one fails or all succeed.\n */\nexport default class Sequence extends Composite {\n /**\n * @param attributes The node attributes.\n * @param children The child nodes.\n */\n constructor(attributes: Attribute[], protected children: Node[]) {\n super(\"sequence\", attributes, children);\n }\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // Iterate over all of the children of this node.\n for (const child of this.children) {\n // If the child has never been updated or is running then we will need to update it now.\n if (child.getState() === State.READY || child.getState() === State.RUNNING) {\n // Update the child of this node.\n child.update(agent, options);\n }\n\n // If the current child has a state of 'SUCCEEDED' then we should move on to the next child.\n if (child.getState() === State.SUCCEEDED) {\n // Find out if the current child is the last one in the sequence.\n // If it is then this sequence node has also succeeded.\n if (this.children.indexOf(child) === this.children.length - 1) {\n // This node is a 'SUCCEEDED' node.\n this.setState(State.SUCCEEDED);\n\n // There is no need to check the rest of the sequence as we have completed it.\n return;\n } else {\n // The child node succeeded, but we have not finished the sequence yet.\n continue;\n }\n }\n\n // If the current child has a state of 'FAILED' then this node is also a 'FAILED' node.\n if (child.getState() === State.FAILED) {\n // This node is a 'FAILED' node.\n this.setState(State.FAILED);\n\n // There is no need to check the rest of the sequence.\n return;\n }\n\n // The node should be in the 'RUNNING' state.\n if (child.getState() === State.RUNNING) {\n // This node is a 'RUNNING' node.\n this.setState(State.RUNNING);\n\n // There is no need to check the rest of the sequence as the current child is still running.\n return;\n }\n\n // The child node was not in an expected state.\n throw new Error(\"child node was not in an expected state.\");\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => \"SEQUENCE\";\n}\n", "import Composite from \"./Composite\";\nimport State from \"../../State\";\nimport Node from \"../Node\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A PARALLEL node.\n * The child nodes are executed concurrently until one fails or all succeed.\n */\nexport default class Parallel extends Composite {\n /**\n * @param attributes The node attributes.\n * @param children The child nodes.\n */\n constructor(attributes: Attribute[], children: Node[]) {\n super(\"parallel\", attributes, children);\n }\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // Keep a count of the number of succeeded child nodes.\n let succeededCount = 0;\n\n let hasChildFailed = false;\n\n // Iterate over all of the children of this node.\n for (const child of this.children) {\n // If the child has never been updated or is running then we will need to update it now.\n if (child.getState() === State.READY || child.getState() === State.RUNNING) {\n // Update the child of this node.\n child.update(agent, options);\n }\n\n // If the current child has a state of 'SUCCEEDED' then we should move on to the next child.\n if (child.getState() === State.SUCCEEDED) {\n // The child node has succeeded, keep track of this to determine if all children have.\n succeededCount++;\n\n // The child node succeeded, but we have not finished checking every child node yet.\n continue;\n }\n\n // If the current child has a state of 'FAILED' then this node is also a 'FAILED' node.\n if (child.getState() === State.FAILED) {\n hasChildFailed = true;\n\n // There is no need to check the rest of the children.\n break;\n }\n\n // The node should be in the 'RUNNING' state.\n if (child.getState() !== State.RUNNING) {\n // The child node was not in an expected state.\n throw new Error(\"child node was not in an expected state.\");\n }\n }\n\n if (hasChildFailed) {\n // This node is a 'FAILED' node.\n this.setState(State.FAILED);\n\n // Abort every running child.\n for (const child of this.children) {\n if (child.getState() === State.RUNNING) {\n child.abort(agent);\n }\n }\n } else {\n // If all children have succeeded then this node has also succeeded, otherwise it is still running.\n this.setState(succeededCount === this.children.length ? State.SUCCEEDED : State.RUNNING);\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => \"PARALLEL\";\n}\n", "import { AnyArgument } from \"../RootAstNodesBuilder\";\nimport Guard from \"./guards/Guard\";\n\nexport type AttributeDetails = {\n /** The attribute type. */\n type: string;\n\n /** The attribute arguments. */\n args: AnyArgument[];\n};\n\n/**\n * A base node attribute.\n */\nexport default abstract class Attribute {\n /**\n * @param type The node attribute type.\n * @param args The array of attribute argument definitions.\n */\n constructor(protected type: string, protected args: AnyArgument[]) {}\n\n /**\n * Gets the type of the attribute.\n */\n getType = () => this.type;\n\n /**\n * Gets the array of attribute argument definitions.\n */\n getArguments = () => this.args;\n\n /**\n * Gets the attribute details.\n */\n abstract getDetails(): TAttributeDetails;\n\n /**\n * Gets whether this attribute is a guard.\n */\n abstract isGuard: () => this is Guard;\n}\n", "import { Agent } from \"../../Agent\";\nimport { AnyArgument } from \"../../RootAstNodesBuilder\";\nimport Attribute, { AttributeDetails } from \"../Attribute\";\n\nexport type GuardAttributeDetails = {\n /** The name of the condition function that determines whether the guard is satisfied. */\n condition: string;\n} & AttributeDetails;\n\n/**\n * A base node guard attribute.\n */\nexport default abstract class Guard extends Attribute {\n /**\n * @param type The node attribute type.\n * @param args The array of decorator argument definitions.\n * @param condition The name of the condition function that determines whether the guard is satisfied.\n */\n constructor(type: string, args: AnyArgument[], private condition: string) {\n super(type, args);\n }\n\n /**\n * Gets the name of the condition function that determines whether the guard is satisfied.\n */\n getCondition = () => this.condition;\n\n /**\n * Gets whether this attribute is a guard.\n */\n isGuard = () => true;\n\n /**\n * Gets the attribute details.\n */\n getDetails(): GuardAttributeDetails {\n return {\n type: this.getType(),\n args: this.getArguments(),\n condition: this.getCondition()\n };\n }\n\n /**\n * Gets whether the guard is satisfied.\n * @param agent The agent.\n * @returns Whether the guard is satisfied.\n */\n abstract isSatisfied(agent: Agent): boolean;\n}\n", "import Guard from \"./Guard\";\nimport Lookup from \"../../Lookup\";\nimport { Agent } from \"../../Agent\";\nimport { AnyArgument } from \"../../RootAstNodesBuilder\";\n\n/**\n * A WHILE guard which is satisfied as long as the given condition remains true.\n */\nexport default class While extends Guard {\n /**\n * @param condition The name of the condition function that determines whether the guard is satisfied.\n * @param args The array of decorator argument definitions.\n */\n constructor(condition: string, args: AnyArgument[]) {\n super(\"while\", args, condition);\n }\n\n /**\n * Gets whether the guard is satisfied.\n * @param agent The agent.\n * @returns Whether the guard is satisfied.\n */\n isSatisfied = (agent: Agent) => {\n // Attempt to get the invoker for the condition function.\n const conditionFuncInvoker = Lookup.getFuncInvoker(agent, this.getCondition());\n\n // The condition function should be defined.\n if (conditionFuncInvoker === null) {\n throw new Error(\n `cannot evaluate node guard as the condition '${this.getCondition()}' function is not defined on the agent and has not been registered`\n );\n }\n\n // Call the condition function to determine whether this guard is satisfied.\n return !!conditionFuncInvoker(this.args);\n };\n}\n", "import Guard from \"./Guard\";\nimport Lookup from \"../../Lookup\";\nimport { Agent } from \"../../Agent\";\nimport { AnyArgument } from \"../../RootAstNodesBuilder\";\n\n/**\n * An UNTIL guard which is satisfied as long as the given condition remains false.\n */\nexport default class Until extends Guard {\n /**\n * @param condition The name of the condition function that determines whether the guard is satisfied.\n * @param args The array of decorator argument definitions.\n */\n constructor(condition: string, args: AnyArgument[]) {\n super(\"until\", args, condition);\n }\n\n /**\n * Gets whether the guard is satisfied.\n * @param agent The agent.\n * @returns Whether the guard is satisfied.\n */\n isSatisfied = (agent: Agent) => {\n // Attempt to get the invoker for the condition function.\n const conditionFuncInvoker = Lookup.getFuncInvoker(agent, this.getCondition());\n\n // The condition function should be defined.\n if (conditionFuncInvoker === null) {\n throw new Error(\n `cannot evaluate node guard as the condition '${this.getCondition()}' function is not defined on the agent and has not been registered`\n );\n }\n\n // Call the condition function to determine whether this guard is satisfied.\n return !!!conditionFuncInvoker(this.args);\n };\n}\n", "import { Agent } from \"../../Agent\";\nimport { AnyArgument } from \"../../RootAstNodesBuilder\";\nimport Attribute, { AttributeDetails } from \"../Attribute\";\n\nexport type CallbackAttributeDetails = {\n /** The name of the agent function that is called. */\n functionName: string;\n} & AttributeDetails;\n\n/**\n * A base node callback attribute.\n */\nexport default abstract class Callback extends Attribute {\n /**\n * @param type The node attribute type.\n * @param args The array of decorator argument definitions.\n * @param functionName The name of the agent function to call.\n */\n constructor(type: string, args: AnyArgument[], private functionName: string) {\n super(type, args);\n }\n\n /**\n * Gets the name of the agent function to call.\n */\n getFunctionName = () => this.functionName;\n\n /**\n * Gets whether this attribute is a guard.\n */\n isGuard = () => false;\n\n /**\n * Gets the attribute details.\n */\n getDetails(): CallbackAttributeDetails {\n return {\n type: this.getType(),\n args: this.getArguments(),\n functionName: this.getFunctionName()\n };\n }\n\n /**\n * Attempt to call the agent function that this callback refers to.\n * @param agent The agent.\n */\n abstract callAgentFunction: (agent: Agent, isSuccess: boolean, isAborted: boolean) => void;\n}\n", "import Callback from \"./Callback\";\nimport Lookup from \"../../Lookup\";\nimport { Agent } from \"../../Agent\";\nimport { AnyArgument } from \"../../RootAstNodesBuilder\";\n\n/**\n * An ENTRY callback which defines an agent function to call when the associated node is updated and moves out of running state.\n */\nexport default class Entry extends Callback {\n /**\n * @param functionName The name of the agent function to call.\n * @param args The array of callback argument definitions.\n */\n constructor(functionName: string, args: AnyArgument[]) {\n super(\"entry\", args, functionName);\n }\n\n /**\n * Attempt to call the agent function that this callback refers to.\n * @param agent The agent.\n */\n callAgentFunction = (agent: Agent) => {\n // Attempt to get the invoker for the callback function.\n const callbackFuncInvoker = Lookup.getFuncInvoker(agent, this.getFunctionName());\n\n // The callback function should be defined.\n if (callbackFuncInvoker === null) {\n throw new Error(\n `cannot call entry function '${this.getFunctionName()}' as is not defined on the agent and has not been registered`\n );\n }\n\n // Call the callback function.\n callbackFuncInvoker(this.args);\n };\n}\n", "import Callback from \"./Callback\";\nimport Lookup, { AnyExitArgument } from \"../../Lookup\";\nimport { Agent } from \"../../Agent\";\nimport { AnyArgument } from \"../../RootAstNodesBuilder\";\n\n/**\n * An EXIT callback which defines an agent function to call when the associated node is updated and moves to a finished state or is aborted.\n */\nexport default class Exit extends Callback {\n /**\n * @param functionName The name of the agent function to call.\n * @param args The array of callback argument definitions.\n */\n constructor(functionName: string, args: AnyArgument[]) {\n super(\"exit\", args, functionName);\n }\n\n /**\n * Attempt to call the agent function that this callback refers to.\n * @param agent The agent.\n * @param isSuccess Whether the decorated node was left with a success state.\n * @param isAborted Whether the decorated node was aborted.\n */\n callAgentFunction = (agent: Agent, isSuccess: boolean, isAborted: boolean) => {\n // Attempt to get the invoker for the callback function.\n const callbackFuncInvoker = Lookup.getFuncInvoker(agent, this.getFunctionName());\n\n // The callback function should be defined.\n if (callbackFuncInvoker === null) {\n throw new Error(\n `cannot call exit function '${this.getFunctionName()}' as is not defined on the agent and has not been registered`\n );\n }\n\n // Call the callback function\n callbackFuncInvoker([{ value: { succeeded: isSuccess, aborted: isAborted } }, ...this.args]);\n };\n}\n", "import Callback from \"./Callback\";\nimport Lookup from \"../../Lookup\";\nimport { Agent } from \"../../Agent\";\nimport { AnyArgument } from \"../../RootAstNodesBuilder\";\n\n/**\n * A STEP callback which defines an agent function to call when the associated node is updated.\n */\nexport default class Step extends Callback {\n /**\n * @param functionName The name of the agent function to call.\n * @param args The array of callback argument definitions.\n */\n constructor(functionName: string, args: AnyArgument[]) {\n super(\"step\", args, functionName);\n }\n\n /**\n * Attempt to call the agent function that this callback refers to.\n * @param agent The agent.\n */\n callAgentFunction = (agent: Agent) => {\n // Attempt to get the invoker for the callback function.\n const callbackFuncInvoker = Lookup.getFuncInvoker(agent, this.getFunctionName());\n\n // The callback function should be defined.\n if (callbackFuncInvoker === null) {\n throw new Error(\n `cannot call step function '${this.getFunctionName()}' as is not defined on the agent and has not been registered`\n );\n }\n\n // Call the callback function.\n callbackFuncInvoker(this.args);\n };\n}\n", "import Action from \"./nodes/leaf/Action\";\nimport Condition from \"./nodes/leaf/Condition\";\nimport Wait from \"./nodes/leaf/Wait\";\nimport Root from \"./nodes/decorator/Root\";\nimport Repeat from \"./nodes/decorator/Repeat\";\nimport Retry from \"./nodes/decorator/Retry\";\nimport Flip from \"./nodes/decorator/Flip\";\nimport Succeed from \"./nodes/decorator/Succeed\";\nimport Fail from \"./nodes/decorator/Fail\";\nimport Lotto from \"./nodes/composite/Lotto\";\nimport Selector from \"./nodes/composite/Selector\";\nimport Sequence from \"./nodes/composite/Sequence\";\nimport Parallel from \"./nodes/composite/Parallel\";\nimport Node from \"./nodes/Node\";\nimport While from \"./attributes/guards/While\";\nimport Until from \"./attributes/guards/Until\";\nimport Entry from \"./attributes/callbacks/Entry\";\nimport Exit from \"./attributes/callbacks/Exit\";\nimport Step from \"./attributes/callbacks/Step\";\nimport Callback from \"./attributes/callbacks/Callback\";\nimport Guard from \"./attributes/guards/Guard\";\nimport Attribute from \"./attributes/Attribute\";\nimport Composite from \"./nodes/composite/Composite\";\nimport Decorator from \"./nodes/decorator/Decorator\";\nimport Leaf from \"./nodes/leaf/Leaf\";\n\nexport type Argument = {\n value: T;\n type: string; // Used for validation.\n};\ntype NullArgument = Argument & {\n type: \"null\";\n};\ntype BooleanArgument = Argument & {\n type: \"boolean\";\n};\ntype NumberArgument = Argument & {\n type: \"number\";\n isInteger: boolean; // Used for validation.\n};\ntype StringPlaceholderArgument = Argument & {\n type: \"string\";\n};\ntype IdentifierArgument = Argument & {\n type: \"identifier\";\n};\nexport type AnyArgument =\n | NullArgument\n | BooleanArgument\n | NumberArgument\n | StringPlaceholderArgument\n | IdentifierArgument;\n\n/**\n * The node attribute factories.\n */\nconst AttributeFactories: {\n [key: string]: (functionName: string, attributeArguments: AnyArgument[]) => Callback | Guard;\n} = {\n WHILE: (condition: string, attributeArguments: AnyArgument[]) => new While(condition, attributeArguments),\n UNTIL: (condition: string, attributeArguments: AnyArgument[]) => new Until(condition, attributeArguments),\n ENTRY: (functionName: string, attributeArguments: AnyArgument[]) => new Entry(functionName, attributeArguments),\n EXIT: (functionName: string, attributeArguments: AnyArgument[]) => new Exit(functionName, attributeArguments),\n STEP: (functionName: string, attributeArguments: AnyArgument[]) => new Step(functionName, attributeArguments)\n};\n\ntype Validatable = {\n children?: AstNode[];\n validate: (depth: number) => void;\n};\n\ntype NodeInstanceCreator = (\n namedRootNodeProvider: (name: string) => RootAstNode,\n visitedBranches: string[]\n) => T;\n\nexport type AstNode = Validatable & {\n type: string;\n createNodeInstance: NodeInstanceCreator;\n};\n\nexport type LeafAstNode = AstNode & {\n type: \"action\" | \"condition\" | \"wait\";\n attributes: Attribute[];\n};\n\nexport type CompositeAstNode = AstNode & {\n type: \"lotto\" | \"parallel\" | \"selector\" | \"sequence\";\n attributes: Attribute[];\n children: AstNode[];\n};\n\nexport type DecoratorAstNode = AstNode & {\n type: \"fail\" | \"flip\" | \"repeat\" | \"retry\" | \"root\" | \"succeed\";\n attributes: Attribute[];\n children: AstNode[];\n};\n\nexport type BranchAstNode = AstNode & {\n type: \"branch\";\n branchName: \"\" | string;\n};\n\nexport type LottoAstNode = CompositeAstNode & {\n type: \"lotto\";\n tickets: number[];\n};\n\nexport type RootAstNode = DecoratorAstNode & {\n type: \"root\";\n name: null | string;\n};\n\nexport type RepeatAstNode = DecoratorAstNode & {\n type: \"repeat\";\n iterations: number | null;\n iterationsMin: number | null;\n iterationsMax: number | null;\n};\n\nexport type RetryAstNode = DecoratorAstNode & {\n type: \"retry\";\n attempts: number | null;\n attemptsMin: number | null;\n attemptsMax: number | null;\n};\n\nexport type ActionAstNode = LeafAstNode & {\n type: \"action\";\n actionName: string;\n actionArguments: AnyArgument[];\n};\n\nexport type ConditionAstNode = LeafAstNode & {\n type: \"condition\";\n conditionName: string;\n conditionArguments: AnyArgument[];\n};\n\nexport type WaitAstNode = LeafAstNode & {\n type: \"wait\";\n duration: number | null;\n durationMin: number | null;\n durationMax: number | null;\n};\n\nexport type AnyAstNode =\n | BranchAstNode\n | CompositeAstNode\n | LottoAstNode\n | DecoratorAstNode\n | RootAstNode\n | RepeatAstNode\n | RetryAstNode\n | LeafAstNode\n | ActionAstNode\n | ConditionAstNode\n | WaitAstNode;\n\n/**\n * The AST node factories.\n */\nconst ASTNodeFactories = {\n ROOT: (): RootAstNode => ({\n type: \"root\",\n attributes: [],\n name: null,\n children: [],\n validate(depth: number) {\n // A root node cannot be the child of another node.\n if (depth > 1) {\n throw new Error(\"a root node cannot be the child of another node\");\n }\n\n // A root node must have a single child node.\n if (this.children.length !== 1) {\n throw new Error(\"a root node must have a single child\");\n }\n },\n createNodeInstance(namedRootNodeProvider, visitedBranches) {\n return new Root(\n this.attributes,\n this.children![0].createNodeInstance(namedRootNodeProvider, visitedBranches.slice())\n );\n }\n }),\n BRANCH: (): BranchAstNode => ({\n type: \"branch\",\n branchName: \"\",\n validate() {},\n createNodeInstance(namedRootNodeProvider, visitedBranches) {\n // Try to find the root node with a matching branch name.\n const targetRootNode = namedRootNodeProvider(this.branchName);\n\n // If we have already visited this branch then we have a circular dependency.\n if (visitedBranches.indexOf(this.branchName) !== -1) {\n throw new Error(`circular dependency found in branch node references for branch '${this.branchName}'`);\n }\n\n // If we have a target root node, then the node instance we want will be the first and only child of the referenced root node.\n if (targetRootNode) {\n return targetRootNode\n .createNodeInstance(namedRootNodeProvider, visitedBranches.concat(this.branchName))\n .getChildren()[0];\n } else {\n throw new Error(`branch references root node '${this.branchName}' which has not been defined`);\n }\n }\n }),\n SELECTOR: (): CompositeAstNode => ({\n type: \"selector\",\n attributes: [],\n children: [],\n validate() {\n // A selector node must have at least a single node.\n if (this.children.length < 1) {\n throw new Error(\"a selector node must have at least a single child\");\n }\n },\n createNodeInstance(namedRootNodeProvider, visitedBranches) {\n return new Selector(\n this.attributes,\n this.children.map((child) => child.createNodeInstance(namedRootNodeProvider, visitedBranches.slice()))\n );\n }\n }),\n SEQUENCE: (): CompositeAstNode => ({\n type: \"sequence\",\n attributes: [],\n children: [],\n validate() {\n // A sequence node must have at least a single node.\n if (this.children.length < 1) {\n throw new Error(\"a sequence node must have at least a single child\");\n }\n },\n createNodeInstance(namedRootNodeProvider, visitedBranches) {\n return new Sequence(\n this.attributes,\n this.children.map((child) => child.createNodeInstance(namedRootNodeProvider, visitedBranches.slice()))\n );\n }\n }),\n PARALLEL: (): CompositeAstNode => ({\n type: \"parallel\",\n attributes: [],\n children: [],\n validate() {\n // A parallel node must have at least a single node.\n if (this.children.length < 1) {\n throw new Error(\"a parallel node must have at least a single child\");\n }\n },\n createNodeInstance(namedRootNodeProvider, visitedBranches) {\n return new Parallel(\n this.attributes,\n this.children.map((child) => child.createNodeInstance(namedRootNodeProvider, visitedBranches.slice()))\n );\n }\n }),\n LOTTO: (): LottoAstNode => ({\n type: \"lotto\",\n attributes: [],\n children: [],\n tickets: [],\n validate() {\n // A lotto node must have at least a single node.\n if (this.children!.length < 1) {\n throw new Error(\"a lotto node must have at least a single child\");\n }\n },\n createNodeInstance(namedRootNodeProvider, visitedBranches) {\n return new Lotto(\n this.attributes,\n this.tickets!,\n this.children!.map((child) => child.createNodeInstance(namedRootNodeProvider, visitedBranches.slice()))\n );\n }\n }),\n REPEAT: (): RepeatAstNode => ({\n type: \"repeat\",\n attributes: [],\n iterations: null,\n iterationsMin: null,\n iterationsMax: null,\n children: [],\n validate() {\n // A repeat node must have a single node.\n if (this.children!.length !== 1) {\n throw new Error(\"a repeat node must have a single child\");\n }\n\n if (this.iterations !== null) {\n // A repeat node must have a positive number of iterations if defined.\n if (this.iterations < 0) {\n throw new Error(\"a repeat node must have a positive number of iterations if defined\");\n }\n } else if (this.iterationsMin !== null && this.iterationsMax !== null) {\n // A repeat node must have a positive min and max iteration count if they are defined.\n if (this.iterationsMin < 0 || this.iterationsMax < 0) {\n throw new Error(\n \"a repeat node must have a positive minimum and maximum iteration count if defined\"\n );\n }\n\n // A repeat node must not have an minimum iteration count that exceeds the maximum iteration count.\n if (this.iterationsMin > this.iterationsMax) {\n throw new Error(\n \"a repeat node must not have a minimum iteration count that exceeds the maximum iteration count\"\n );\n }\n } else {\n // If we have no explicit iteration count or a minimum and maximum iteration count set then we are dealing with a repeat node that iterates indefinitely.\n }\n },\n createNodeInstance(namedRootNodeProvider, visitedBranches) {\n return new Repeat(\n this.attributes,\n this.iterations,\n this.iterationsMin,\n this.iterationsMax,\n this.children![0].createNodeInstance(namedRootNodeProvider, visitedBranches.slice())\n );\n }\n }),\n RETRY: (): RetryAstNode => ({\n type: \"retry\",\n attributes: [],\n attempts: null,\n attemptsMin: null,\n attemptsMax: null,\n children: [],\n validate() {\n // A retry node must have a single node.\n if (this.children!.length !== 1) {\n throw new Error(\"a retry node must have a single child\");\n }\n\n if (this.attempts !== null) {\n // A retry node must have a positive number of attempts if defined.\n if (this.attempts < 0) {\n throw new Error(\"a retry node must have a positive number of attempts if defined\");\n }\n } else if (this.attemptsMin !== null && this.attemptsMax !== null) {\n // A retry node must have a positive min and max attempts count if they are defined.\n if (this.attemptsMin < 0 || this.attemptsMax < 0) {\n throw new Error(\"a retry node must have a positive minimum and maximum attempt count if defined\");\n }\n\n // A retry node must not have a minimum attempt count that exceeds the maximum attempt count.\n if (this.attemptsMin > this.attemptsMax) {\n throw new Error(\n \"a retry node must not have a minimum attempt count that exceeds the maximum attempt count\"\n );\n }\n } else {\n // If we have no explicit attempt count or a minimum and maximum attempt count set then we are dealing with a retry node that attempts indefinitely.\n }\n },\n createNodeInstance(namedRootNodeProvider, visitedBranches) {\n return new Retry(\n this.attributes,\n this.attempts,\n this.attemptsMin,\n this.attemptsMax,\n this.children![0].createNodeInstance(namedRootNodeProvider, visitedBranches.slice())\n );\n }\n }),\n FLIP: (): DecoratorAstNode => ({\n type: \"flip\",\n attributes: [],\n children: [],\n validate() {\n // A flip node must have a single node.\n if (this.children!.length !== 1) {\n throw new Error(\"a flip node must have a single child\");\n }\n },\n createNodeInstance(namedRootNodeProvider, visitedBranches) {\n return new Flip(\n this.attributes,\n this.children![0].createNodeInstance(namedRootNodeProvider, visitedBranches.slice())\n );\n }\n }),\n SUCCEED: (): DecoratorAstNode => ({\n type: \"succeed\",\n attributes: [],\n children: [],\n validate() {\n // A succeed node must have a single node.\n if (this.children!.length !== 1) {\n throw new Error(\"a succeed node must have a single child\");\n }\n },\n createNodeInstance(namedRootNodeProvider, visitedBranches) {\n return new Succeed(\n this.attributes,\n this.children![0].createNodeInstance(namedRootNodeProvider, visitedBranches.slice())\n );\n }\n }),\n FAIL: (): DecoratorAstNode => ({\n type: \"fail\",\n attributes: [],\n children: [],\n validate() {\n // A fail node must have a single node.\n if (this.children!.length !== 1) {\n throw new Error(\"a fail node must have a single child\");\n }\n },\n createNodeInstance(namedRootNodeProvider, visitedBranches) {\n return new Fail(\n this.attributes,\n this.children![0].createNodeInstance(namedRootNodeProvider, visitedBranches.slice())\n );\n }\n }),\n WAIT: (): WaitAstNode => ({\n type: \"wait\",\n attributes: [],\n duration: null,\n durationMin: null,\n durationMax: null,\n validate() {\n if (this.duration !== null) {\n // If an explict duration was defined then it must be a positive number.\n if (this.duration < 0) {\n throw new Error(\"a wait node must have a positive duration\");\n }\n } else if (this.durationMin !== null && this.durationMax !== null) {\n // A wait node must have a positive min and max duration.\n if (this.durationMin < 0 || this.durationMax < 0) {\n throw new Error(\"a wait node must have a positive minimum and maximum duration\");\n }\n\n // A wait node must not have a minimum duration that exceeds the maximum duration.\n if (this.durationMin > this.durationMax) {\n throw new Error(\"a wait node must not have a minimum duration that exceeds the maximum duration\");\n }\n } else {\n // If we have no explicit duration or duration bounds set then we are dealing with a wait node that waits indefinitely.\n }\n },\n createNodeInstance() {\n return new Wait(this.attributes, this.duration, this.durationMin, this.durationMax);\n }\n }),\n ACTION: (): ActionAstNode => ({\n type: \"action\",\n attributes: [],\n actionName: \"\",\n actionArguments: [],\n validate() {},\n createNodeInstance() {\n return new Action(this.attributes, this.actionName!, this.actionArguments!);\n }\n }),\n CONDITION: (): ConditionAstNode => ({\n type: \"condition\",\n attributes: [],\n conditionName: \"\",\n conditionArguments: [],\n validate() {},\n createNodeInstance() {\n return new Condition(this.attributes, this.conditionName!, this.conditionArguments!);\n }\n })\n};\n\ntype OtherAstNodes = AstNode[];\n\n/**\n * Create an array of root AST nodes based on the given definition.\n * @param definition The definition to parse the AST nodes from.\n * @returns The base definition AST nodes.\n */\nexport default function buildRootASTNodes(definition: string): RootAstNode[] {\n // Swap out any node/attribute argument string literals with a placeholder and get a mapping of placeholders to original values as well as the processed definition.\n const { placeholders, processedDefinition } = substituteStringLiterals(definition);\n\n // Convert the processed definition (with substituted string literals) into an array of raw tokens.\n const tokens = parseTokensFromDefinition(processedDefinition);\n\n // There must be at least 3 tokens for the tree definition to be valid. 'ROOT', '{' and '}'.\n if (tokens.length < 3) {\n throw new Error(\"invalid token count\");\n }\n\n // We should have a matching number of '{' and '}' tokens. If not, then there are scopes that have not been properly closed.\n if (tokens.filter((token) => token === \"{\").length !== tokens.filter((token) => token === \"}\").length) {\n throw new Error(\"scope character mismatch\");\n }\n\n // Create a stack of node children arrays, starting with a definition scope.\n const stack: [RootAstNode[], ...OtherAstNodes[]] = [[]];\n const rootScope = stack[0];\n\n // We should keep processing the raw tokens until we run out of them.\n while (tokens.length) {\n // Grab the next token.\n const token = tokens.shift();\n\n const currentScope = stack[stack.length - 1] as OtherAstNodes;\n\n // How we create the next AST token depends on the current raw token value.\n switch (token!.toUpperCase()) {\n case \"ROOT\": {\n // Create a ROOT AST node.\n const node = ASTNodeFactories.ROOT();\n\n // Push the ROOT node into the current scope.\n rootScope.push(node);\n\n // We may have a root node name defined as an argument.\n if (tokens[0] === \"[\") {\n const rootArguments = getArguments(tokens, placeholders);\n\n // We should have only a single argument that is not an empty string for a root node, which is the root name identifier.\n if (rootArguments.length === 1 && rootArguments[0].type === \"identifier\") {\n // The root name will be the first and only node argument.\n node.name = rootArguments[0].value as string;\n } else {\n throw new Error(\"expected single root name argument\");\n }\n }\n\n // Try to pick any attributes off of the token stack.\n node.attributes = getAttributes(tokens, placeholders);\n\n popAndCheck(tokens, \"{\");\n\n // The new scope is that of the new ROOT nodes children.\n stack.push(node.children!);\n break;\n }\n\n case \"BRANCH\": {\n // Create a BRANCH AST node.\n const node = ASTNodeFactories.BRANCH();\n\n // Push the BRANCH node into the current scope.\n currentScope.push(node);\n\n // We must have arguments defined, as we require a branch name argument.\n if (tokens[0] !== \"[\") {\n throw new Error(\"expected single branch name argument\");\n }\n\n // The branch name will be defined as a node argument.\n const branchArguments = getArguments(tokens, placeholders);\n\n // We should have only a single identifer argument for a branch node, which is the branch name.\n if (branchArguments.length === 1 && branchArguments[0].type === \"identifier\") {\n // The branch name will be the first and only node argument.\n node.branchName = branchArguments[0].value as string;\n } else {\n throw new Error(\"expected single branch name argument\");\n }\n break;\n }\n\n case \"SELECTOR\": {\n // Create a SELECTOR AST node.\n const node = ASTNodeFactories.SELECTOR();\n\n // Push the SELECTOR node into the current scope.\n currentScope.push(node);\n\n // Try to pick any attributes off of the token stack.\n node.attributes = getAttributes(tokens, placeholders);\n\n popAndCheck(tokens, \"{\");\n\n // The new scope is that of the new SELECTOR nodes children.\n stack.push(node.children!);\n break;\n }\n\n case \"SEQUENCE\": {\n // Create a SEQUENCE AST node.\n const node = ASTNodeFactories.SEQUENCE();\n\n // Push the SEQUENCE node into the current scope.\n currentScope.push(node);\n\n // Try to pick any attributes off of the token stack.\n node.attributes = getAttributes(tokens, placeholders);\n\n popAndCheck(tokens, \"{\");\n\n // The new scope is that of the new SEQUENCE nodes children.\n stack.push(node.children!);\n break;\n }\n\n case \"PARALLEL\": {\n // Create a PARALLEL AST node.\n const node = ASTNodeFactories.PARALLEL();\n\n // Push the PARALLEL node into the current scope.\n currentScope.push(node);\n\n // Try to pick any attributes off of the token stack.\n node.attributes = getAttributes(tokens, placeholders);\n\n popAndCheck(tokens, \"{\");\n\n // The new scope is that of the new PARALLEL nodes children.\n stack.push(node.children!);\n break;\n }\n\n case \"LOTTO\": {\n // Create a LOTTO AST node.\n const node = ASTNodeFactories.LOTTO();\n\n // Push the LOTTO node into the current scope.\n currentScope.push(node);\n\n // If the next token is a '[' character then some ticket counts have been defined as arguments.\n if (tokens[0] === \"[\") {\n // Get the ticket count arguments, each argument must be a number.\n node.tickets = getArguments(\n tokens,\n placeholders,\n (arg) => arg.type === \"number\" && !!arg.isInteger,\n \"lotto node ticket counts must be integer values\"\n ).map((argument) => argument.value as number);\n }\n\n // Try to pick any attributes off of the token stack.\n node.attributes = getAttributes(tokens, placeholders);\n\n popAndCheck(tokens, \"{\");\n\n // The new scope is that of the new LOTTO nodes children.\n stack.push(node.children!);\n break;\n }\n\n case \"CONDITION\": {\n // Create a CONDITION AST node.\n const node = ASTNodeFactories.CONDITION();\n\n // Push the CONDITION node into the current scope.\n currentScope.push(node);\n\n // We must have arguments defined, as we require a condition function name argument.\n if (tokens[0] !== \"[\") {\n throw new Error(\"expected condition name identifier argument\");\n }\n\n // Grab the condition node arguments.\n const conditionArguments = getArguments(tokens, placeholders);\n\n // We should have at least a single identifier argument for a condition node, which is the condition function name.\n if (conditionArguments.length && conditionArguments[0].type === \"identifier\") {\n // The condition function name will be the first node argument.\n node.conditionName = conditionArguments.shift()!.value as string;\n } else {\n throw new Error(\"expected condition name identifier argument\");\n }\n\n // Only the first argument should have been an identifier, all following arguments must be string, number, boolean or null.\n conditionArguments\n .filter((arg) => arg.type === \"identifier\")\n .forEach((arg) => {\n throw new Error(\n \"invalid condition node argument value '\" +\n arg.value +\n \"', must be string, number, boolean or null\"\n );\n });\n\n // Any node arguments that follow the condition name identifier will be treated as condition function arguments.\n node.conditionArguments = conditionArguments;\n\n // Try to pick any attributes off of the token stack.\n node.attributes = getAttributes(tokens, placeholders);\n break;\n }\n\n case \"FLIP\": {\n // Create a FLIP AST node.\n const node = ASTNodeFactories.FLIP();\n\n // Push the Flip node into the current scope.\n currentScope.push(node);\n\n // Try to pick any attributes off of the token stack.\n node.attributes = getAttributes(tokens, placeholders);\n\n popAndCheck(tokens, \"{\");\n\n // The new scope is that of the new FLIP nodes children.\n stack.push(node.children!);\n break;\n }\n\n case \"SUCCEED\": {\n // Create a SUCCEED AST node.\n const node = ASTNodeFactories.SUCCEED();\n\n // Push the Succeed node into the current scope.\n currentScope.push(node);\n\n // Try to pick any attributes off of the token stack.\n node.attributes = getAttributes(tokens, placeholders);\n\n popAndCheck(tokens, \"{\");\n\n // The new scope is that of the new Succeed nodes children.\n stack.push(node.children!);\n break;\n }\n\n case \"FAIL\": {\n // Create a FAIL AST node.\n const node = ASTNodeFactories.FAIL();\n\n // Push the Fail node into the current scope.\n currentScope.push(node);\n\n // Try to pick any attributes off of the token stack.\n node.attributes = getAttributes(tokens, placeholders);\n\n popAndCheck(tokens, \"{\");\n\n // The new scope is that of the new Fail nodes children.\n stack.push(node.children!);\n break;\n }\n\n case \"WAIT\": {\n // Create a WAIT AST node.\n const node = ASTNodeFactories.WAIT();\n\n // Push the WAIT node into the current scope.\n currentScope.push(node);\n\n // The arguments of a wait node are optional. We may have:\n // - No node arguments, in which case the wait will be indefinite until it is aborted.\n // - One node argument which will be the explicit duration of the wait.\n // - Two node arguments which define the min and max duration bounds from which a random duration will be picked.\n if (tokens[0] === \"[\") {\n // Get the optional duration and longest duration of the wait.\n const nodeArguments = getArguments(\n tokens,\n placeholders,\n (arg) => arg.type === \"number\" && !!arg.isInteger,\n \"wait node durations must be integer values\"\n ).map((argument) => argument.value);\n\n // We may have:\n // - One node argument which will be the explicit duration of the wait.\n // - Two node arguments which define the min and max duration bounds from which a random duration will be picked.\n // - Too many arguments, which is not valid.\n if (nodeArguments.length === 1) {\n // An explicit duration was defined.\n node.duration = nodeArguments[0] as number;\n } else if (nodeArguments.length === 2) {\n // Min and max duration bounds were defined from which a random duration will be picked.\n node.durationMin = nodeArguments[0] as number;\n node.durationMax = nodeArguments[1] as number;\n } else if (nodeArguments.length > 2) {\n // An incorrect number of durations was defined.\n throw new Error(\"invalid number of wait node duration arguments defined\");\n }\n }\n\n // Try to pick any attributes off of the token stack.\n node.attributes = getAttributes(tokens, placeholders);\n break;\n }\n\n case \"REPEAT\": {\n // Create a REPEAT AST node.\n const node = ASTNodeFactories.REPEAT();\n\n // Push the REPEAT node into the current scope.\n currentScope.push(node);\n\n // The arguments of a repeat node are optional. We may have:\n // - No node arguments, in which case the repeat note will iterate indefinitely.\n // - One node argument which will be the explicit number of iterations to make.\n // - Two node arguments which define the min and max iteration bounds from which a random iteration count will be picked.\n if (tokens[0] === \"[\") {\n // An iteration count has been defined. Get the iteration and potential maximum iteration of the wait.\n const nodeArguments = getArguments(\n tokens,\n placeholders,\n (arg) => arg.type === \"number\" && !!arg.isInteger,\n \"repeat node iteration counts must be integer values\"\n ).map((argument) => argument.value);\n\n // We should have got one or two iteration counts.\n if (nodeArguments.length === 1) {\n // A static iteration count was defined.\n node.iterations = nodeArguments[0] as number;\n } else if (nodeArguments.length === 2) {\n // A minimum and maximum iteration count was defined.\n node.iterationsMin = nodeArguments[0] as number;\n node.iterationsMax = nodeArguments[1] as number;\n } else {\n // An incorrect number of iteration counts was defined.\n throw new Error(\"invalid number of repeat node iteration count arguments defined\");\n }\n }\n\n // Try to pick any attributes off of the token stack.\n node.attributes = getAttributes(tokens, placeholders);\n\n popAndCheck(tokens, \"{\");\n\n // The new scope is that of the new REPEAT nodes children.\n stack.push(node.children!);\n break;\n }\n\n case \"RETRY\": {\n // Create a RETRY AST node.\n const node = ASTNodeFactories.RETRY();\n\n // Push the RETRY node into the current scope.\n currentScope.push(node);\n\n // The arguments of a retry node are optional. We may have:\n // - No node arguments, in which case the retry note will attempt indefinitely.\n // - One node argument which will be the explicit number of attempts to make.\n // - Two node arguments which define the min and max attempt bounds from which a random attempt count will be picked.\n if (tokens[0] === \"[\") {\n // An attempt count has been defined. Get the attempt count and potential maximum attempt count of the wait.\n const nodeArguments = getArguments(\n tokens,\n placeholders,\n (arg) => arg.type === \"number\" && !!arg.isInteger,\n \"retry node attempt counts must be integer values\"\n ).map((argument) => argument.value);\n\n // We should have got one or two attempt counts.\n if (nodeArguments.length === 1) {\n // A static attempt count was defined.\n node.attempts = nodeArguments[0] as number;\n } else if (nodeArguments.length === 2) {\n // A minimum and maximum attempt count was defined.\n node.attemptsMin = nodeArguments[0] as number;\n node.attemptsMax = nodeArguments[1] as number;\n } else {\n // An incorrect number of attempt counts was defined.\n throw new Error(\"invalid number of retry node attempt count arguments defined\");\n }\n }\n\n // Try to pick any attributes off of the token stack.\n node.attributes = getAttributes(tokens, placeholders);\n\n popAndCheck(tokens, \"{\");\n\n // The new scope is that of the new RETRY nodes children.\n stack.push(node.children!);\n break;\n }\n\n case \"ACTION\": {\n // Create a ACTION AST node.\n const node = ASTNodeFactories.ACTION();\n\n // Push the ACTION node into the current scope.\n currentScope.push(node);\n\n // We must have arguments defined, as we require an action name argument.\n if (tokens[0] !== \"[\") {\n throw new Error(\"expected action name identifier argument\");\n }\n\n // The action name will be defined as a node argument.\n const actionArguments = getArguments(tokens, placeholders);\n\n // We should have at least one identifer argument for an action node, which is the action name.\n if (actionArguments.length && actionArguments[0].type === \"identifier\") {\n // The action name will be the first and only node argument.\n node.actionName = actionArguments.shift()!.value as string;\n } else {\n throw new Error(\"expected action name identifier argument\");\n }\n\n // Only the first argument should have been an identifier, all following arguments must be string, number, boolean or null.\n actionArguments\n .filter((arg) => arg.type === \"identifier\")\n .forEach((arg) => {\n throw new Error(\n \"invalid action node argument value '\" +\n arg.value +\n \"', must be string, number, boolean or null\"\n );\n });\n\n // Any node arguments that follow the action name identifier will be treated as action function arguments.\n node.actionArguments = actionArguments;\n\n // Try to pick any attributes off of the token stack.\n node.attributes = getAttributes(tokens, placeholders);\n break;\n }\n\n case \"}\": {\n // The '}' character closes the current scope.\n stack.pop();\n break;\n }\n\n default: {\n throw new Error(`unexpected token '${token}'`);\n }\n }\n }\n\n // A function to recursively validate each of the nodes in the AST.\n const validateASTNode = (node: Validatable, depth: number): void => {\n // Validate the node.\n node.validate(depth);\n\n // Validate each child of the node.\n (node.children || []).forEach((child) => validateASTNode(child, depth + 1));\n };\n\n // Start node validation from the definition root.\n validateASTNode(\n {\n children: stack[0] as RootAstNode[],\n validate(this: { children: RootAstNode[] }) {\n // We must have at least one node defined as the definition scope, which should be a root node.\n if (this.children.length === 0) {\n throw new Error(\"expected root node to have been defined\");\n }\n\n // Each node at the base of the definition scope MUST be a root node.\n for (const definitionLevelNode of this.children) {\n if (definitionLevelNode.type !== \"root\") {\n throw new Error(\"expected root node at base of definition\");\n }\n }\n\n // Exactly one root node must not have a name defined. This will be the main root, others will have to be referenced via branch nodes.\n if (this.children.filter((definitionLevelNode) => definitionLevelNode.name === null).length !== 1) {\n throw new Error(\"expected single unnamed root node at base of definition to act as main root\");\n }\n\n // No two named root nodes can have matching names.\n const rootNodeNames: string[] = [];\n for (const definitionLevelNode of this.children) {\n if (rootNodeNames.indexOf(definitionLevelNode.name!) !== -1) {\n throw new Error(`multiple root nodes found with duplicate name '${definitionLevelNode.name}'`);\n } else {\n rootNodeNames.push(definitionLevelNode.name!);\n }\n }\n }\n },\n 0\n );\n\n // Return the root AST nodes.\n return stack[0];\n}\n\n/**\n * Pop the next raw token off of the stack and throw an error if it wasn't the expected one.\n * @param tokens The array of remaining tokens.\n * @param expected An optional string or array or items, one of which must match the next popped token.\n * @returns The popped token.\n */\nfunction popAndCheck(tokens: string[], expected: string | string[]) {\n // Get and remove the next token.\n const popped = tokens.shift();\n\n // We were expecting another token.\n if (popped === undefined) {\n throw new Error(\"unexpected end of definition\");\n }\n\n // Do we have an expected token/tokens array?\n if (expected !== undefined) {\n // Check whether the popped token matches at least one of our expected items.\n var tokenMatchesExpectation = ([] as string[])\n .concat(expected)\n .some((item) => popped.toUpperCase() === item.toUpperCase());\n\n // Throw an error if the popped token didn't match any of our expected items.\n if (!tokenMatchesExpectation) {\n const expectationString = ([] as string[])\n .concat(expected)\n .map((item) => \"'\" + item + \"'\")\n .join(\" or \");\n\n throw new Error(`unexpected token found. Expected '${expectationString}' but got '${popped}'`);\n }\n }\n\n // Return the popped token.\n return popped;\n}\n\ntype StringPlaceholders = { [key: string]: string };\n\n/**\n * Pull an argument definition list off of the token stack.\n * @param tokens The array of remaining tokens.\n * @param stringArgumentPlaceholders The mapping of string literal node argument placeholders to original values.\n * @param argumentValidator The argument validator function.\n * @param validationFailedMessage The exception message to throw if argument validation fails.\n * @returns The argument definition list.\n */\nfunction getArguments(\n tokens: string[],\n stringArgumentPlaceholders: StringPlaceholders,\n argumentValidator?: (arg: AnyArgument) => boolean,\n validationFailedMessage?: string\n) {\n // Any lists of arguments will always be wrapped in '[]' for node arguments or '()' for attribute arguments.\n // We are looking for a '[' or '(' opener that wraps the argument tokens and the relevant closer.\n const closer = popAndCheck(tokens, [\"[\", \"(\"]) === \"[\" ? \"]\" : \")\";\n\n const argumentListTokens: string[] = [];\n const argumentList: AnyArgument[] = [];\n\n // Grab all tokens between the '[' and ']' or '(' and ')'.\n while (tokens.length && tokens[0] !== closer) {\n // The next token is part of our arguments list.\n argumentListTokens.push(tokens.shift()!);\n }\n\n // Validate the order of the argument tokens. Each token must either be a ',' or a single argument that satisfies the validator.\n argumentListTokens.forEach((token, index) => {\n // Get whether this token should be an actual argument.\n const shouldBeArgumentToken = !(index & 1);\n\n // If the current token should be an actual argument then validate it,otherwise it should be a ',' token.\n if (shouldBeArgumentToken) {\n // Get the argument definition.\n const argumentDefinition = getArgumentDefinition(token!, stringArgumentPlaceholders);\n\n // Try to validate the argument.\n if (argumentValidator && !argumentValidator(argumentDefinition)) {\n throw new Error(validationFailedMessage);\n }\n\n // This is a valid argument!\n argumentList.push(argumentDefinition);\n } else {\n // The current token should be a ',' token.\n if (token !== \",\") {\n throw new Error(`invalid argument list, expected ',' or ']' but got '${token}'`);\n }\n }\n });\n\n // The arguments list should terminate with a ']' or ')' token, depending on the opener.\n popAndCheck(tokens, closer);\n\n // Return the argument list.\n return argumentList;\n}\n\n/**\n * Gets an argument value definition.\n * @param token The argument token.\n * @param stringArgumentPlaceholders The mapping of string literal node argument placeholders to original values.\n * @returns An argument value definition.\n */\nfunction getArgumentDefinition(token: string, stringArgumentPlaceholders: StringPlaceholders): AnyArgument {\n // Check whether the token represents a null value.\n if (token === \"null\") {\n return {\n value: null,\n type: \"null\"\n } as NullArgument;\n }\n\n // Check whether the token represents a boolean value.\n if (token === \"true\" || token === \"false\") {\n return {\n value: token === \"true\",\n type: \"boolean\"\n } as BooleanArgument;\n }\n\n // Check whether the token represents a number value.\n // TODO: Relies on broken isNaN - see MDN.\n // if (!Number.isNaN(token)) {\n if (!isNaN(token as any)) {\n return {\n value: parseFloat(token),\n isInteger: parseFloat(token) === parseInt(token, 10),\n type: \"number\"\n } as NumberArgument;\n }\n\n // Check whether the token is a placeholder (e.g. @@0@@) representing a string literal.\n if (token.match(/^@@\\d+@@$/g)) {\n return {\n value: stringArgumentPlaceholders[token].replace('\\\\\"', '\"'),\n type: \"string\"\n } as StringPlaceholderArgument;\n }\n\n // The only remaining option is that the argument value is an identifier.\n return {\n value: token,\n type: \"identifier\"\n } as IdentifierArgument;\n}\n\n/**\n * Pull any attributes off of the token stack.\n * @param tokens The array of remaining tokens.\n * @param stringArgumentPlaceholders The mapping of string literal node argument placeholders to original values.\n * @returns An array of attributes defined by any directly following tokens.\n */\nfunction getAttributes(tokens: string[], stringArgumentPlaceholders: StringPlaceholders) {\n // Create an array to hold any attributes found.\n const attributes: Attribute[] = [];\n\n // Keep track of names of attribute that we have found on the token stack, as we cannot have duplicates.\n const attributesFound: string[] = [];\n\n // Try to get the attribute factory for the next token.\n let attributeFactory = AttributeFactories[(tokens[0] || \"\").toUpperCase()];\n\n // Pull attribute tokens off of the tokens stack until we have no more.\n while (attributeFactory) {\n // Check to make sure that we have not already created a attribute of this type for this node.\n if (attributesFound.indexOf(tokens[0].toUpperCase()) !== -1) {\n throw new Error(`duplicate attribute '${tokens[0].toUpperCase()}' found for node`);\n }\n\n // Add the current attribute type to our array of found attributes.\n attributesFound.push(tokens.shift()!.toUpperCase());\n\n // Grab any attribute arguments.\n const attributeArguments = getArguments(tokens, stringArgumentPlaceholders);\n\n // The first attribute argument has to be an identifer, this will reference an agent function.\n if (attributeArguments.length === 0 || attributeArguments[0].type !== \"identifier\") {\n throw new Error(\"expected agent function name identifier argument for attribute\");\n }\n\n // Grab the first attribute which is an identifier that will reference an agent function.\n const attributeFunctionName = attributeArguments.shift()! as IdentifierArgument;\n\n // Any remaining attribute arguments must have a type of string, number, boolean or null.\n attributeArguments\n .filter((arg) => arg.type === \"identifier\")\n .forEach((arg) => {\n throw new Error(\n \"invalid attribute argument value '\" + arg.value + \"', must be string, number, boolean or null\"\n );\n });\n\n // Create the attribute and add it to the array of attributes found.\n attributes.push(attributeFactory(attributeFunctionName.value, attributeArguments));\n\n // Try to get the next attribute name token, as there could be multiple.\n attributeFactory = AttributeFactories[(tokens[0] || \"\").toUpperCase()];\n }\n\n return attributes;\n}\n\n/**\n * Swaps out any node/attribute argument string literals with placeholders.\n * @param definition The definition.\n * @returns An object containing a mapping of placeholders to original string values as well as the processed definition string.\n */\nfunction substituteStringLiterals(definition: string): {\n placeholders: { [key: string]: string };\n processedDefinition: string;\n} {\n // Create an object to hold the mapping of placeholders to original string values.\n const placeholders: StringPlaceholders = {};\n\n // Replace any string literals wrapped with double quotes in our definition with placeholders to be processed later.\n const processedDefinition = definition.replace(/\\\"(\\\\.|[^\"\\\\])*\\\"/g, (match) => {\n var strippedMatch = match.substring(1, match.length - 1);\n var placeholder = Object.keys(placeholders).find((key) => placeholders[key] === strippedMatch);\n\n // If we have no existing string literal match then create a new placeholder.\n if (!placeholder) {\n placeholder = `@@${Object.keys(placeholders).length}@@`;\n placeholders[placeholder] = strippedMatch;\n }\n\n return placeholder;\n });\n\n return { placeholders, processedDefinition };\n}\n\n/**\n * Parse the tree definition into an array of raw tokens.\n * @param definition The definition.\n * @returns An array of tokens parsed from the definition.\n */\nfunction parseTokensFromDefinition(definition: string): string[] {\n // Add some space around various important characters so that they can be plucked out easier as individual tokens.\n definition = definition.replace(/\\(/g, \" ( \");\n definition = definition.replace(/\\)/g, \" ) \");\n definition = definition.replace(/\\{/g, \" { \");\n definition = definition.replace(/\\}/g, \" } \");\n definition = definition.replace(/\\]/g, \" ] \");\n definition = definition.replace(/\\[/g, \" [ \");\n definition = definition.replace(/\\,/g, \" , \");\n\n // Split the definition into raw token form and return it.\n return definition.replace(/\\s+/g, \" \").trim().split(\" \");\n}\n", "import GuardPath, { GuardPathPart } from \"./attributes/guards/GuardPath\";\nimport buildRootASTNodes, { AnyArgument, RootAstNode } from \"./RootAstNodesBuilder\";\nimport State, { AnyState } from \"./State\";\nimport Lookup from \"./Lookup\";\nimport Node from \"./nodes/Node\";\nimport Root from \"./nodes/decorator/Root\";\nimport Composite from \"./nodes/composite/Composite\";\nimport Decorator from \"./nodes/decorator/Decorator\";\nimport { Agent, GlobalFunction } from \"./Agent\";\nimport { CallbackAttributeDetails } from \"./attributes/callbacks/Callback\";\nimport { GuardAttributeDetails } from \"./attributes/guards/Guard\";\nimport { BehaviourTreeOptions } from \"./BehaviourTreeOptions\";\nimport { convertMDSLToJSON } from \"./mdsl/MDSLDefinitionParser\";\n\n// Purely for outside inspection of the tree.\nexport type FlattenedTreeNode = {\n id: string;\n type: string;\n caption: string;\n state: AnyState;\n guards: GuardAttributeDetails[];\n callbacks: CallbackAttributeDetails[];\n args: AnyArgument[];\n parentId: string | null;\n};\n\n/**\n * A representation of a behaviour tree.\n */\nexport class BehaviourTree {\n /**\n * The main root tree node.\n */\n public readonly rootNode: Root;\n\n /**\n * Creates a new instance of the BehaviourTree class.\n * @param definition The behaviour tree definition.\n * @param agent The agent instance that this behaviour tree is modelling behaviour for.\n * @param options The behaviour tree options object.\n */\n constructor(definition: string, private agent: Agent, private options: BehaviourTreeOptions = {}) {\n // The tree definition must be defined and a valid string.\n if (typeof definition !== \"string\") {\n throw new Error(\"the tree definition must be a string\");\n }\n\n // The agent must be defined and not null.\n if (typeof agent !== \"object\" || agent === null) {\n throw new Error(\"the agent must be defined and not null\");\n }\n\n // Parse the behaviour tree definition, create the populated tree of behaviour tree nodes, and get the root.\n this.rootNode = BehaviourTree._createRootNode(definition);\n }\n\n /**\n * Gets whether the tree is in the RUNNING state.\n * @returns true if the tree is in the RUNNING state, otherwise false.\n */\n isRunning() {\n return this.rootNode.getState() === State.RUNNING;\n }\n\n /**\n * Gets the current tree state of SUCCEEDED, FAILED, READY or RUNNING.\n * @returns The current tree state.\n */\n getState() {\n return this.rootNode.getState();\n }\n\n /**\n * Step the tree.\n * 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.\n * 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\n * 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.\n *\n * 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.\n */\n step() {\n // If the root node has already been stepped to completion then we need to reset it.\n if (this.rootNode.getState() === State.SUCCEEDED || this.rootNode.getState() === State.FAILED) {\n this.rootNode.reset();\n }\n\n try {\n this.rootNode.update(this.agent, this.options);\n } catch (exception) {\n throw new Error(`error stepping tree: ${(exception as Error).message}`);\n }\n }\n\n /**\n * Resets the tree from the root node outwards to each nested node, giving each a state of READY.\n */\n reset() {\n this.rootNode.reset();\n }\n\n /**\n * Gets the flattened details of every node in the tree.\n * @returns The flattened details of every node in the tree.\n */\n getFlattenedNodeDetails(): FlattenedTreeNode[] {\n // Create an empty flattened array of tree nodes.\n const flattenedTreeNodes: FlattenedTreeNode[] = [];\n\n /**\n * Helper function to process a node instance and push details into the flattened tree nodes array.\n * @param node The current node.\n * @param parentUid The UID of the node parent, or null if the node is the main root node.\n */\n const processNode = (node: Node, parentUid: string | null) => {\n // Get the guard and callback attribute details for this node.\n const guards = node\n .getAttributes()\n .filter((attribute) => attribute.isGuard())\n .map((attribute) => attribute.getDetails()) as GuardAttributeDetails[];\n const callbacks = node\n .getAttributes()\n .filter((attribute) => !attribute.isGuard())\n .map((attribute) => attribute.getDetails()) as CallbackAttributeDetails[];\n\n // Push the current node into the flattened nodes array.\n flattenedTreeNodes.push({\n id: node.getUid(),\n type: node.getType(),\n caption: node.getName(),\n state: node.getState(),\n guards,\n callbacks,\n args: node.getArguments(),\n parentId: parentUid\n });\n\n // Process each of the nodes children if it is not a leaf node.\n if (!node.isLeafNode()) {\n (node as Composite | Decorator)\n .getChildren()\n .forEach((child) => processNode(child, (node as Composite | Decorator).getUid()));\n }\n };\n\n // Convert the nested node structure into a flattened array of node details.\n processNode(this.rootNode, null);\n\n return flattenedTreeNodes;\n }\n\n /**\n * Registers the action/condition/guard/callback function or subtree with the given name.\n * @param name The name of the function or subtree to register.\n * @param value The function or subtree definition to register.\n */\n static register(name: string, value: GlobalFunction | string) {\n if (typeof value === \"function\") {\n // We are going to register a action/condition/guard/callback function.\n Lookup.setFunc(name, value);\n } else if (typeof value === \"string\") {\n // We are going to register a subtree.\n let rootASTNodes: RootAstNode[];\n\n try {\n // Try to create the behaviour tree AST based on the definition provided, this could fail if the definition is invalid.\n rootASTNodes = buildRootASTNodes(value);\n } catch (exception) {\n // There was an issue in trying to parse and build the tree definition.\n throw new Error(`error registering definition: ${(exception as Error).message}`);\n }\n\n // This function should only ever be called with a definition containing a single unnamed root node.\n if (rootASTNodes.length != 1 || rootASTNodes[0].name !== null) {\n throw new Error(\"error registering definition: expected a single unnamed root node\");\n }\n\n Lookup.setSubtree(name, rootASTNodes[0]);\n } else {\n throw new Error(\"unexpected value, expected string definition or function\");\n }\n }\n\n /**\n * Unregisters the registered action/condition/guard/callback function or subtree with the given name.\n * @param name The name of the registered action/condition/guard/callback function or subtree to unregister.\n */\n static unregister(name: string): void {\n Lookup.remove(name);\n }\n\n /**\n * Unregister all registered action/condition/guard/callback functions and subtrees.\n */\n static unregisterAll(): void {\n Lookup.empty();\n }\n\n /**\n * Parses a behaviour tree definition and creates a tree of behaviour tree nodes.\n * @param {string} definition The behaviour tree definition.\n * @returns The root behaviour tree node.\n */\n private static _createRootNode(definition: string): Root {\n // TODO Remove!\n try {\n // parseToJSON(definition);\n } catch (exception) {\n console.log(exception);\n }\n\n try {\n // Try to create the behaviour tree AST based on the definition provided, this could fail if the definition is invalid.\n const rootASTNodes = buildRootASTNodes(definition);\n\n // Create a symbol to use as the main root key in our root node mapping.\n const mainRootNodeKey = Symbol(\"__root__\");\n\n // Create a mapping of root node names to root AST tokens. The main root node will have a key of Symbol(\"__root__\").\n const rootNodeMap: { [key: string | symbol]: RootAstNode } = {};\n for (const rootASTNode of rootASTNodes) {\n rootNodeMap[rootASTNode.name === null ? mainRootNodeKey : rootASTNode.name!] = rootASTNode;\n }\n\n // Convert the AST to our actual tree and get the root node.\n const rootNode: Root = rootNodeMap[mainRootNodeKey].createNodeInstance(\n // Create a provider for named root nodes that are part of our definition or have been registered. Prioritising the former.\n (name: string): RootAstNode => (rootNodeMap[name] ? rootNodeMap[name] : Lookup.getSubtree(name)),\n []\n );\n\n // Set a guard path on every leaf of the tree to evaluate as part of its update.\n BehaviourTree._applyLeafNodeGuardPaths(rootNode);\n\n // Return the root node.\n return rootNode;\n } catch (exception) {\n // There was an issue in trying to parse and build the tree definition.\n throw new Error(`error parsing tree: ${(exception as Error).message}`);\n }\n }\n\n /**\n * Applies a guard path to every leaf of the tree to evaluate as part of each update.\n * @param rootNode The main root tree node.\n */\n private static _applyLeafNodeGuardPaths(rootNode: Root) {\n const nodePaths: Node[][] = [];\n\n const findLeafNodes = (path: Node[], node: Node) => {\n // Add the current node to the path.\n path = path.concat(node);\n\n // Check whether the current node is a leaf node.\n if (node.isLeafNode()) {\n nodePaths.push(path);\n } else {\n (node as Composite | Decorator).getChildren().forEach((child) => findLeafNodes(path, child));\n }\n };\n\n // Find all leaf node paths, starting from the root.\n findLeafNodes([], rootNode);\n\n nodePaths.forEach((path) => {\n // Each node in the current path will have to be assigned a guard path, working from the root outwards.\n for (let depth = 0; depth < path.length; depth++) {\n // Get the node in the path at the current depth.\n const currentNode = path[depth];\n\n // The node may already have been assigned a guard path, if so just skip it.\n if (currentNode.hasGuardPath()) {\n continue;\n }\n\n // Create the guard path for the current node.\n const guardPath = new GuardPath(\n path\n .slice(0, depth + 1)\n .map((node) => ({ node, guards: node.getGuardAttributes() }))\n .filter((details) => details.guards.length > 0)\n );\n\n // Assign the guard path to the current node.\n currentNode.setGuardPath(guardPath);\n }\n });\n }\n}\n"], - "mappings": "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", + "sourcesContent": ["\"use strict\";\r\nObject.defineProperty(exports, \"__esModule\", { value: true });\r\nexports.Participant = void 0;\r\n/**\r\n * A participant that holds a number of tickets.\r\n */\r\nvar Participant = /** @class */ (function () {\r\n /**\r\n * Creates an instance of the Participant class.\r\n * @param participant The actual participant.\r\n * @param tickets The number of tickets held by the participant.\r\n */\r\n function Participant(participant, tickets) {\r\n if (tickets === void 0) { tickets = 1; }\r\n this._participant = participant;\r\n this._tickets = tickets;\r\n }\r\n Object.defineProperty(Participant.prototype, \"participant\", {\r\n /** Gets the actual participant. */\r\n get: function () {\r\n return this._participant;\r\n },\r\n enumerable: false,\r\n configurable: true\r\n });\r\n Object.defineProperty(Participant.prototype, \"tickets\", {\r\n /** Gets or sets the number of tickets held by the participant. */\r\n get: function () {\r\n return this._tickets;\r\n },\r\n set: function (value) {\r\n this._tickets = value;\r\n },\r\n enumerable: false,\r\n configurable: true\r\n });\r\n return Participant;\r\n}());\r\nexports.Participant = Participant;\r\n", "\"use strict\";\r\nObject.defineProperty(exports, \"__esModule\", { value: true });\r\nexports.isNaturalNumber = exports.isNullOrUndefined = void 0;\r\n/**\r\n * Gets whether the value provided is null or undefined.\r\n * @param value The value to check.\r\n * @returns Whether the value provided is null or undefined.\r\n */\r\nfunction isNullOrUndefined(value) {\r\n return value === null || value === undefined;\r\n}\r\nexports.isNullOrUndefined = isNullOrUndefined;\r\n/**\r\n * Gets whether the value provided is a natural number.\r\n * @param value The value to check.\r\n * @returns Whether the value provided is a natural number.\r\n */\r\nfunction isNaturalNumber(value) {\r\n return typeof value === \"number\" && value >= 1 && Math.floor(value) === value;\r\n}\r\nexports.isNaturalNumber = isNaturalNumber;\r\n", "\"use strict\";\r\nObject.defineProperty(exports, \"__esModule\", { value: true });\r\nexports.Lotto = void 0;\r\nvar Participant_1 = require(\"./Participant\");\r\nvar Utilities_1 = require(\"./Utilities\");\r\n/**\r\n * Represents a lotto consisting of a number of pickable ticket-holding participants.\r\n */\r\nvar Lotto = /** @class */ (function () {\r\n /**\r\n * Creates a new instance of Lotto.\r\n * @param customRandom The custom RNG to use in place of Math.random().\r\n */\r\n function Lotto(customRandom) {\r\n /** The array of participants that are holding tickets in the lotto. */\r\n this._participants = [];\r\n this._customRandom = customRandom;\r\n }\r\n /**\r\n * Adds a participant with the specified number of tickets, or adds to the participant ticket count if the participant already holds tickets.\r\n * @param participant The participant to add or to increase the ticket count for if they already hold tickets.\r\n * @param tickets The number of tickets, defaults to 1.\r\n * @returns The Lotto instance.\r\n */\r\n Lotto.prototype.add = function (participant, tickets) {\r\n if (tickets === void 0) { tickets = 1; }\r\n // Check that we have a valid ticket count.\r\n if (!(0, Utilities_1.isNaturalNumber)(tickets)) {\r\n throw new Error(\"tickets value must be a natural number\");\r\n }\r\n // Check whether this participant has already been added.\r\n var existingParticipant = this._participants.find(function (part) { return part.participant === participant; });\r\n if (existingParticipant) {\r\n // The participant has already been added to the lotto so just add to their ticket count.\r\n existingParticipant.tickets += tickets;\r\n }\r\n else {\r\n // The participant is not part of the lotto so we should add them.\r\n this._participants.push(new Participant_1.Participant(participant, tickets));\r\n }\r\n return this;\r\n };\r\n /**\r\n * Removes the specified number of tickets for the given participant from the draw, or all tickets if a ticket number is not defined.\r\n * @param participant The participant to remove tickets for.\r\n * @param tickets The number of tickets to remove, or undefined if all tickets are to be removed.\r\n * @returns The Lotto instance.\r\n */\r\n Lotto.prototype.remove = function (participant, tickets) {\r\n // Attempt to get the existing participant.\r\n var existingParticipant = this._participants.find(function (part) { return part.participant === participant; });\r\n // There is nothing to do if the specified participant isn't even part of the lotto.\r\n if (!existingParticipant) {\r\n return this;\r\n }\r\n // Check whether a tickets value was given.\r\n if (tickets !== undefined) {\r\n // Check that we have a valid ticket count.\r\n if (!(0, Utilities_1.isNaturalNumber)(tickets)) {\r\n throw new Error(\"tickets value must be a natural number\");\r\n }\r\n existingParticipant.tickets -= tickets;\r\n // If the participant no longer holds any tickets then they should be removed.\r\n if (existingParticipant.tickets < 1) {\r\n this._participants = this._participants.filter(function (part) { return part !== existingParticipant; });\r\n }\r\n }\r\n else {\r\n // We are removing all tickets for the participant so just remove them from the lotto.\r\n this._participants = this._participants.filter(function (part) { return part !== existingParticipant; });\r\n }\r\n return this;\r\n };\r\n /**\r\n * Draw a winning ticket and return the participant that holds the ticket.\r\n * @param options The draw options.\r\n * @returns The participant that holds the winning ticket.\r\n */\r\n Lotto.prototype.draw = function (options) {\r\n if (options === void 0) { options = {}; }\r\n // If we have no participants then just return null.\r\n if (this._participants.length === 0) {\r\n return null;\r\n }\r\n var redrawable = (0, Utilities_1.isNullOrUndefined)(options.redrawable) ? true : options.redrawable;\r\n var pickable = [];\r\n this._participants.forEach(function (_a) {\r\n var participant = _a.participant, tickets = _a.tickets;\r\n for (var ticketCount = 0; ticketCount < tickets; ticketCount++) {\r\n pickable.push(participant);\r\n }\r\n });\r\n var random;\r\n // We need a random floating-point number between 0 (inclusive) and 1 to scale up to pick our winner.\r\n // If a custom random function exists then we should use that or fall back to Math.random().\r\n if (this._customRandom) {\r\n // Call our custom random function to get a random floating-point number.\r\n random = this._customRandom();\r\n // Verify that the result of calling our custom random function is a number between 0 (inclusive) and 1.\r\n if (typeof random !== \"number\" || random < 0 || random >= 1) {\r\n throw new Error(\"the 'random' function provided did not return a number between 0 (inclusive) and 1\");\r\n }\r\n }\r\n else {\r\n // No custom random function was defined so just use good ol' Math.random().\r\n random = Math.random();\r\n }\r\n // Pick a winning participant.\r\n var winner = pickable[Math.floor(random * pickable.length)];\r\n // If the ticket isn't redrawable then we should remove a ticket from the winning participants ticket count.\r\n if (!redrawable) {\r\n this.remove(winner, 1);\r\n }\r\n // Return the winning participant.\r\n return winner;\r\n };\r\n /**\r\n * Draws multiple winning tickets and return an array of the participants that hold the winning tickets.\r\n * @param tickets The number of winning tickets to draw.\r\n * @param options The draw multiple options.\r\n * @returns An array of the participants that hold the winning tickets.\r\n */\r\n Lotto.prototype.drawMultiple = function (tickets, options) {\r\n if (options === void 0) { options = {}; }\r\n var uniqueResults = (0, Utilities_1.isNullOrUndefined)(options.unique) ? false : options.unique;\r\n // Handle cases where the user has asked for zero tickets (no idea why they would do this be we should trust them).\r\n if (tickets === 0) {\r\n return [];\r\n }\r\n // Now that we know out tickets value is not zero we should check that it is a valid natural number.\r\n if (!(0, Utilities_1.isNaturalNumber)(tickets)) {\r\n throw new Error(\"tickets value must be a natural number\");\r\n }\r\n var result = [];\r\n // Keep drawing tickets until we either reach the number of required tickets or we simply run out of tickets to draw.\r\n // We can run out of tickets to draw if 'options.redrawable' is explicity 'false' or we just had no participants when 'drawMultiple' was called.\r\n while (result.length < tickets && this._participants.length > 0) {\r\n result.push(this.draw(options));\r\n }\r\n // If the 'unique' draw option is set then we need to remove duplicates from the result list.\r\n if (uniqueResults) {\r\n // Create an array to store our unique results.\r\n var unique = [];\r\n // Iterate over all of our participants (with potential duplicates) and populate our array of unique values.\r\n for (var _i = 0, result_1 = result; _i < result_1.length; _i++) {\r\n var participant = result_1[_i];\r\n if (unique.indexOf(participant) === -1) {\r\n unique.push(participant);\r\n }\r\n }\r\n result = unique;\r\n }\r\n return result;\r\n };\r\n return Lotto;\r\n}());\r\nexports.Lotto = Lotto;\r\n", "\"use strict\";\r\nObject.defineProperty(exports, \"__esModule\", { value: true });\r\nexports.createLotto = void 0;\r\nvar Lotto_1 = require(\"./Lotto\");\r\n/**\r\n * A function that creates and returns a Lotto instance.\r\n * @param participantsOrOptions An array of initial participants or options relating to the creation of a Lotto instance.\r\n * @returns A new Lotto instance.\r\n */\r\nfunction createLotto(participantsOrOptions) {\r\n // If no initial participants or lotto options were provided as an argument then we can just return a new lotto instance now.\r\n if (!participantsOrOptions) {\r\n return new Lotto_1.Lotto();\r\n }\r\n // Check whether we were provided with an array of initial participants or a lotto options object.\r\n if (Array.isArray(participantsOrOptions)) {\r\n // We are dealing with a pre-defined array of participants.\r\n var participants = participantsOrOptions;\r\n var lotto_1 = new Lotto_1.Lotto();\r\n // If the lotto participants have been defined upfront then we will need to add them all to our lotto instance now.\r\n participants.forEach(function (_a) {\r\n var participant = _a[0], tokens = _a[1];\r\n return lotto_1.add(participant, tokens);\r\n });\r\n // Return the Lotto instance.\r\n return lotto_1;\r\n }\r\n else {\r\n // We are dealing with some lotto options.\r\n var random = participantsOrOptions.random, participants = participantsOrOptions.participants;\r\n // Create a Lotto instance passing the custom RNG function to use in place of Math.random() (which could be undefined).\r\n var lotto_2 = new Lotto_1.Lotto(random);\r\n // If the lotto participants have been defined upfront as part of the options then we will need to add them all to our lotto instance now.\r\n if (participants) {\r\n participants.forEach(function (_a) {\r\n var participant = _a[0], tokens = _a[1];\r\n return lotto_2.add(participant, tokens);\r\n });\r\n }\r\n // Return the Lotto instance.\r\n return lotto_2;\r\n }\r\n}\r\nexports.createLotto = createLotto;\r\n", "\"use strict\";\r\nObject.defineProperty(exports, \"__esModule\", { value: true });\r\nvar createLotto_1 = require(\"./createLotto\");\r\nexports.default = createLotto_1.createLotto;\r\n", "import State from \"./State\";\nimport { validateDefinition } from \"./BehaviourTreeDefinitionValidator\";\nimport { convertMDSLToJSON } from \"./mdsl/MDSLDefinitionParser\";\nimport { BehaviourTree, FlattenedTreeNode } from \"./BehaviourTree\";\n\nexport { BehaviourTree, State, convertMDSLToJSON, validateDefinition };\nexport type { FlattenedTreeNode };\n", "/**\n * Enumeration of node state types.\n */\nexport enum State {\n READY = \"mistreevous.ready\",\n RUNNING = \"mistreevous.running\",\n SUCCEEDED = \"mistreevous.succeeded\",\n FAILED = \"mistreevous.failed\"\n}\n\nexport { State as default };\n\nexport type CompleteState = State.SUCCEEDED | State.FAILED;\nexport type AnyState = State.READY | State.RUNNING | CompleteState;\n", "import {\n NodeDefinition,\n RootNodeDefinition,\n DecoratorNodeDefinition,\n CompositeNodeDefinition,\n AnyNode,\n BranchNodeDefinition\n} from \"./BehaviourTreeDefinition\";\n\n/**\n * A type guard function that returns true if the specified node satisfies the RootNodeDefinition type.\n * @param node The node.\n * @returns A value of true if the specified node satisfies the RootNodeDefinition type.\n */\nexport function isRootNode(node: NodeDefinition): node is RootNodeDefinition {\n return node.type === \"root\";\n}\n\n/**\n * A type guard function that returns true if the specified node satisfies the BranchNodeDefinition type.\n * @param node The node.\n * @returns A value of true if the specified node satisfies the BranchNodeDefinition type.\n */\nexport function isBranchNode(node: NodeDefinition): node is BranchNodeDefinition {\n return node.type === \"branch\";\n}\n\n/**\n * A type guard function that returns true if the specified node satisfies the NodeDefinition type.\n * @param node The node.\n * @returns A value of true if the specified node satisfies the NodeDefinition type.\n */\nexport function isLeafNode(node: NodeDefinition): node is NodeDefinition {\n return [\"branch\", \"action\", \"condition\", \"wait\"].includes(node.type);\n}\n\n/**\n * A type guard function that returns true if the specified node satisfies the DecoratorNodeDefinition type.\n * @param node The node.\n * @returns A value of true if the specified node satisfies the DecoratorNodeDefinition type.\n */\nexport function isDecoratorNode(node: NodeDefinition): node is DecoratorNodeDefinition {\n return [\"root\", \"repeat\", \"retry\", \"flip\", \"succeed\", \"fail\"].includes(node.type);\n}\n\n/**\n * A type guard function that returns true if the specified node satisfies the CompositeNodeDefinition type.\n * @param node The node.\n * @returns A value of true if the specified node satisfies the CompositeNodeDefinition type.\n */\nexport function isCompositeNode(node: NodeDefinition): node is CompositeNodeDefinition {\n return [\"sequence\", \"selector\", \"lotto\", \"parallel\"].includes(node.type);\n}\n\n/**\n * Flatten a node definition into an array of all of its nested node definitions.\n * @param nodeDefinition The node definition to flatten.\n * @returns An array of all of nested node definitions.\n */\nexport function flattenDefinition(nodeDefinition: AnyNode): AnyNode[] {\n const nodes: AnyNode[] = [];\n\n const processNode = (currentNodeDefinition: AnyNode) => {\n nodes.push(currentNodeDefinition);\n\n if (isCompositeNode(currentNodeDefinition)) {\n currentNodeDefinition.children.forEach(processNode);\n } else if (isDecoratorNode(currentNodeDefinition)) {\n processNode(currentNodeDefinition.child);\n }\n };\n\n processNode(nodeDefinition);\n\n return nodes;\n}\n\n/**\n * Determines whether the passed value is an integer.\n * @param value The value to check.\n * @returns Whether the passed value is an integer.\n */\nexport function isInteger(value: unknown): boolean {\n return typeof value === \"number\" && Math.floor(value) === value;\n}\n", "/**\n * A type defining an object that holds a reference to substitued string literals parsed from the definition.\n */\nexport type StringLiteralPlaceholders = { [key: string]: string };\n\n/**\n * Pop the next raw token from the specified array of tokens and throw an error if it wasn't the expected one.\n * @param tokens The array of tokens.\n * @param expected An optional string or array or items, one of which must match the next popped token.\n * @returns The popped token.\n */\nexport function popAndCheck(tokens: string[], expected?: string | string[]): string {\n // Get and remove the next token.\n const popped = tokens.shift();\n\n // We were expecting another token but there aren't any.\n if (popped === undefined) {\n throw new Error(\"unexpected end of definition\");\n }\n\n // Do we have an expected token/tokens array?\n if (expected != undefined) {\n // Get an array of expected values, if the popped token matches any then we are all good.\n const expectedValues = typeof expected === \"string\" ? [expected] : expected;\n\n // Check whether the popped token matches at least one of our expected items.\n var tokenMatchesExpectation = expectedValues.some((item) => popped.toUpperCase() === item.toUpperCase());\n\n // Throw an error if the popped token didn't match any of our expected items.\n if (!tokenMatchesExpectation) {\n const expectationString = expectedValues.map((item) => \"'\" + item + \"'\").join(\" or \");\n throw new Error(\"unexpected token found. Expected \" + expectationString + \" but got '\" + popped + \"'\");\n }\n }\n\n // Return the popped token.\n return popped;\n}\n\n/**\n * Swaps out any node/attribute argument string literals with placeholders.\n * @param definition The definition.\n * @returns An object containing a mapping of placeholders to original string values as well as the processed definition string.\n */\nexport function substituteStringLiterals(definition: string): {\n placeholders: StringLiteralPlaceholders;\n processedDefinition: string;\n} {\n // Create an object to hold the mapping of placeholders to original string values.\n const placeholders: StringLiteralPlaceholders = {};\n\n // Replace any string literals wrapped with double quotes in our definition with placeholders to be processed later.\n const processedDefinition = definition.replace(/\\\"(\\\\.|[^\"\\\\])*\\\"/g, (match) => {\n var strippedMatch = match.substring(1, match.length - 1);\n var placeholder = Object.keys(placeholders).find((key) => placeholders[key] === strippedMatch);\n\n // If we have no existing string literal match then create a new placeholder.\n if (!placeholder) {\n placeholder = `@@${Object.keys(placeholders).length}@@`;\n placeholders[placeholder] = strippedMatch;\n }\n\n return placeholder;\n });\n\n return { placeholders, processedDefinition };\n}\n\n/**\n * Parse the tree definition into an array of raw tokens.\n * @param definition The definition.\n * @returns An array of tokens parsed from the definition.\n */\nexport function parseTokensFromDefinition(definition: string): string[] {\n // Add some space around various important characters so that they can be plucked out easier as individual tokens.\n definition = definition.replace(/\\(/g, \" ( \");\n definition = definition.replace(/\\)/g, \" ) \");\n definition = definition.replace(/\\{/g, \" { \");\n definition = definition.replace(/\\}/g, \" } \");\n definition = definition.replace(/\\]/g, \" ] \");\n definition = definition.replace(/\\[/g, \" [ \");\n definition = definition.replace(/\\,/g, \" , \");\n\n // Split the definition into raw token form and return it.\n return definition.replace(/\\s+/g, \" \").trim().split(\" \");\n}\n", "import { StringLiteralPlaceholders, popAndCheck } from \"./MDSLUtilities\";\n\nexport type Argument = {\n /** The argument value. */\n value: T;\n /** The argument type, used for validation. */\n type: string;\n};\n\nexport type NullArgument = Argument & {\n type: \"null\";\n};\n\nexport type BooleanArgument = Argument & {\n type: \"boolean\";\n};\n\nexport type NumberArgument = Argument & {\n type: \"number\";\n isInteger: boolean; // Used for validation.\n};\n\nexport type StringPlaceholderArgument = Argument & {\n type: \"string\";\n};\n\nexport type IdentifierArgument = Argument & {\n type: \"identifier\";\n};\n\nexport type AnyArgument =\n | NullArgument\n | BooleanArgument\n | NumberArgument\n | StringPlaceholderArgument\n | IdentifierArgument;\n\n/**\n * Parse an array of argument definitions from the specified tokens array.\n * @param tokens The array tokens to parse the argument definitions from.\n * @param stringArgumentPlaceholders The mapping of string literal node argument placeholders to original values.\n * @param argumentValidator The argument validator function.\n * @param validationFailedMessage The exception message to throw if argument validation fails.\n * @returns An array of argument definitions parsed from the specified tokens array.\n */\nexport function parseArgumentTokens(\n tokens: string[],\n stringArgumentPlaceholders: StringLiteralPlaceholders\n): AnyArgument[] {\n const argumentList: AnyArgument[] = [];\n\n // If the next token is not a '[' or '(' then we have no arguments to parse.\n if (![\"[\", \"(\"].includes(tokens[0])) {\n return argumentList;\n }\n\n // Any lists of arguments will always be wrapped in '[]' for node arguments or '()' for attribute arguments.\n // We are looking for a '[' or '(' opener that wraps the argument tokens and the relevant closer.\n const closingToken = popAndCheck(tokens, [\"[\", \"(\"]) === \"[\" ? \"]\" : \")\";\n\n const argumentListTokens: string[] = [];\n\n // Grab all tokens between the '[' and ']' or '(' and ')'.\n while (tokens.length && tokens[0] !== closingToken) {\n // The next token is part of our arguments list.\n argumentListTokens.push(tokens.shift()!);\n }\n\n // Validate the order of the argument tokens. Each token must either be a ',' or a single argument that satisfies the validator.\n argumentListTokens.forEach((token, index) => {\n // Get whether this token should be an actual argument.\n const shouldBeArgumentToken = !(index & 1);\n\n // If the current token should be an actual argument then validate it, otherwise it should be a ',' token.\n if (shouldBeArgumentToken) {\n // Get the argument definition.\n const argumentDefinition = getArgumentDefinition(token, stringArgumentPlaceholders);\n\n // This is a valid argument!\n argumentList.push(argumentDefinition);\n } else {\n // The current token should be a ',' token.\n if (token !== \",\") {\n throw new Error(`invalid argument list, expected ',' or ']' but got '${token}'`);\n }\n }\n });\n\n // The arguments list should terminate with a ']' or ')' token, depending on the opener.\n popAndCheck(tokens, closingToken);\n\n // Return the arguments.\n return argumentList;\n}\n\n/**\n * Gets an argument value definition.\n * @param token The argument token.\n * @param stringArgumentPlaceholders The mapping of string literal node argument placeholders to original values.\n * @returns An argument value definition.\n */\nfunction getArgumentDefinition(token: string, stringArgumentPlaceholders: StringLiteralPlaceholders): AnyArgument {\n // Check whether the token represents a null value.\n if (token === \"null\") {\n return {\n value: null,\n type: \"null\"\n } as NullArgument;\n }\n\n // Check whether the token represents a boolean value.\n if (token === \"true\" || token === \"false\") {\n return {\n value: token === \"true\",\n type: \"boolean\"\n } as BooleanArgument;\n }\n\n // Check whether the token represents a number value.\n // TODO: Relies on broken isNaN - see MDN.\n // if (!Number.isNaN(token)) {\n if (!isNaN(token as any)) {\n return {\n value: parseFloat(token),\n isInteger: parseFloat(token) === parseInt(token, 10),\n type: \"number\"\n } as NumberArgument;\n }\n\n // Check whether the token is a placeholder (e.g. @@0@@) representing a string literal.\n if (token.match(/^@@\\d+@@$/g)) {\n return {\n value: stringArgumentPlaceholders[token].replace('\\\\\"', '\"'),\n type: \"string\"\n } as StringPlaceholderArgument;\n }\n\n // The only remaining option is that the argument value is an identifier.\n return {\n value: token,\n type: \"identifier\"\n } as IdentifierArgument;\n}\n", "import { NodeAttributeDefinition } from \"../BehaviourTreeDefinition\";\nimport { parseArgumentTokens } from \"./MDSLNodeArgumentParser\";\nimport { StringLiteralPlaceholders } from \"./MDSLUtilities\";\n\n/**\n * A type defining the attribute definitions of a node.\n */\ntype NodeAttributes = {\n while?: NodeAttributeDefinition;\n until?: NodeAttributeDefinition;\n entry?: NodeAttributeDefinition;\n exit?: NodeAttributeDefinition;\n step?: NodeAttributeDefinition;\n};\n\n/**\n * Parse any node attribute definitions from the specified tokens array.\n * @param tokens The array of remaining tokens.\n * @param stringArgumentPlaceholders The mapping of string literal node argument placeholders to original values.\n * @returns An object of attribute definitions defined by any directly following tokens.\n */\nexport function parseAttributeTokens(\n tokens: string[],\n stringArgumentPlaceholders: StringLiteralPlaceholders\n): NodeAttributes {\n const nodeAttributeNames: (keyof NodeAttributes)[] = [\"while\", \"until\", \"entry\", \"exit\", \"step\"];\n\n // Create an object to hold any attributes found.\n const attributes: NodeAttributes = {};\n\n // Try to get the name of the attribute for the next token.\n let nextAttributeName = tokens[0]?.toLowerCase() as keyof NodeAttributes;\n\n // Pull attribute tokens as well as their arguments off of the tokens stack until we have no more.\n while (nodeAttributeNames.includes(nextAttributeName)) {\n // Check to make sure that we have not already created an attribute definition of this type.\n if (attributes[nextAttributeName]) {\n throw new Error(`duplicate attribute '${tokens[0].toUpperCase()}' found for node`);\n }\n\n // Remove the attribute name token from the array of tokens.\n tokens.shift();\n\n // Grab the attribute arguments, assuming the first to be an identifier.\n const [attributeCallIdentifier, ...attributeArguments] = parseArgumentTokens(\n tokens,\n stringArgumentPlaceholders\n );\n\n // The first attribute argument has to be an identifer, this will reference an agent function.\n if (attributeCallIdentifier?.type !== \"identifier\") {\n throw new Error(\"expected agent function name identifier argument for attribute\");\n }\n\n // Any attribute arguments (other than the expected call identifier) must have a type of string, number, boolean or null.\n attributeArguments\n .filter((arg) => arg.type === \"identifier\")\n .forEach((arg) => {\n throw new Error(\n `invalid attribute argument value '${arg.value}', must be string, number, boolean or null`\n );\n });\n\n // Create the attribute definition and add it to the object of attribute definitions found.\n attributes[nextAttributeName] = {\n call: attributeCallIdentifier.value,\n args: attributeArguments.map(({ value }) => value)\n };\n\n // Try to get the next attribute name token, as there could be multiple.\n nextAttributeName = tokens[0]?.toLowerCase() as keyof NodeAttributes;\n }\n\n return attributes;\n}\n", "import {\n ActionNodeDefinition,\n AnyChildNode,\n AnyNode,\n BranchNodeDefinition,\n ConditionNodeDefinition,\n FailNodeDefinition,\n FlipNodeDefinition,\n LottoNodeDefinition,\n ParallelNodeDefinition,\n RepeatNodeDefinition,\n RetryNodeDefinition,\n RootNodeDefinition,\n SelectorNodeDefinition,\n SequenceNodeDefinition,\n SucceedNodeDefinition,\n WaitNodeDefinition\n} from \"../BehaviourTreeDefinition\";\nimport { isCompositeNode, isDecoratorNode, isLeafNode, isRootNode } from \"../BehaviourTreeDefinitionUtilities\";\nimport { parseArgumentTokens } from \"./MDSLNodeArgumentParser\";\nimport { parseAttributeTokens } from \"./MDSLNodeAttributeParser\";\nimport {\n StringLiteralPlaceholders,\n parseTokensFromDefinition,\n popAndCheck,\n substituteStringLiterals\n} from \"./MDSLUtilities\";\n\n/**\n * Convert the MDSL tree definition string into an equivalent JSON definition.\n * @param definition The tree definition string as MDSL.\n * @returns The root node JSON definitions.\n */\nexport function convertMDSLToJSON(definition: string): RootNodeDefinition[] {\n // Swap out any node/attribute argument string literals with a placeholder and get a mapping of placeholders to original values as well as the processed definition.\n const { placeholders, processedDefinition } = substituteStringLiterals(definition);\n\n // Parse our definition definition string into an array of raw tokens.\n const tokens = parseTokensFromDefinition(processedDefinition);\n\n return convertTokensToJSONDefinition(tokens, placeholders);\n}\n\n/**\n * Converts the specified tree definition tokens into a JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The root node JSON definitions.\n */\nfunction convertTokensToJSONDefinition(\n tokens: string[],\n stringLiteralPlaceholders: StringLiteralPlaceholders\n): RootNodeDefinition[] {\n // There must be at least 3 tokens for the tree definition to be valid. 'ROOT', '{' and '}'.\n if (tokens.length < 3) {\n throw new Error(\"invalid token count\");\n }\n\n // We should have a matching number of '{' and '}' tokens. If not, then there are scopes that have not been properly closed.\n if (tokens.filter((token) => token === \"{\").length !== tokens.filter((token) => token === \"}\").length) {\n throw new Error(\"scope character mismatch\");\n }\n\n // Create an array of tree stack arrays where root nodes will always be at the botton and the current composite/decorator node at the top.\n // There should be an element in this array for every root node defined and every element should be an array with a root note as the first element.\n // E.g. A definition with two root nodes defined:\n // [\n // [root, lotto, sequence],\n // [root, selector]\n // ]\n const treeStacks: [Partial, ...Partial[]][] = [];\n\n // Create an array of all root node definitions that we create.\n const rootNodes: Partial[] = [];\n\n // A helper function used to push node definitions onto the tree stack.\n const pushNode = (node: AnyNode) => {\n // If the node is a root node then we need to create a new tree stack array with the root node at the root.\n if (isRootNode(node)) {\n // Add the root node definition to our array of all parsed root node definitions.\n rootNodes.push(node);\n\n // Add the root node definition to the root of a new tree stack.\n treeStacks.push([node]);\n\n return;\n }\n\n // All non-root nodes should be pushed after their root nodes so handle cases\n // where we may not have any tree stacks or our top-most tree stack is empty.\n if (!treeStacks.length || !treeStacks[treeStacks.length - 1].length) {\n throw new Error(\"expected root node at base of definition\");\n }\n\n // Get the current tree stack that we are populating.\n const topTreeStack = treeStacks[treeStacks.length - 1];\n\n // Get the top-most node in the current tree stack, this will be a composite/decorator node\n // for which we will populate its children array if composite or setting its child if a decorator.\n const topTreeStackTopNode = topTreeStack[topTreeStack.length - 1] as AnyNode;\n\n // If the top-most node in the current root stack is a composite or decorator\n // node then the current node should be added as a child of the top-most node.\n if (isCompositeNode(topTreeStackTopNode)) {\n topTreeStackTopNode.children = topTreeStackTopNode.children || [];\n topTreeStackTopNode.children.push(node);\n } else if (isDecoratorNode(topTreeStackTopNode)) {\n // If the top node already has a child node set then throw an error as a decorator should only have a single child.\n if (topTreeStackTopNode.child) {\n throw new Error(\"a decorator node must only have a single child node\");\n }\n\n topTreeStackTopNode.child = node;\n }\n\n // If the node we are adding is also a composite or decorator node, then we should push it\n // onto the current tree stack, as subsequent nodes will be added as its child/children.\n if (!isLeafNode(node)) {\n topTreeStack.push(node);\n }\n };\n\n // A helper function used to pop node definitions off of the stack.\n const popNode = () => {\n // Get the current tree stack that we are populating.\n const topTreeStack = treeStacks[treeStacks.length - 1];\n\n // Pop the top-most node in the current tree stack if there is one.\n if (topTreeStack.length) {\n topTreeStack.pop();\n }\n\n // We don't want any empty tree stacks in our stack of tree stacks.\n if (!topTreeStack.length) {\n treeStacks.pop();\n }\n };\n\n // We should keep processing the raw tokens until we run out of them.\n while (tokens.length) {\n // Grab the next token.\n const token = tokens.shift()!;\n\n // How we create the next node depends on the current raw token value.\n switch (token.toUpperCase()) {\n case \"ROOT\": {\n pushNode(createRootNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"SUCCEED\": {\n pushNode(createSucceedNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"FAIL\": {\n pushNode(createFailNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"FLIP\": {\n pushNode(createFlipNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"REPEAT\": {\n pushNode(createRepeatNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"RETRY\": {\n pushNode(createRetryNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"SEQUENCE\": {\n pushNode(createSequenceNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"SELECTOR\": {\n pushNode(createSelectorNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"PARALLEL\": {\n pushNode(createParallelNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"LOTTO\": {\n pushNode(createLottoNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"ACTION\": {\n pushNode(createActionNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"CONDITION\": {\n pushNode(createConditionNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"WAIT\": {\n pushNode(createWaitNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"BRANCH\": {\n pushNode(createBranchNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"}\": {\n // The '}' character closes the current scope and means that we have to pop a node off of the current stack.\n popNode();\n break;\n }\n\n default: {\n throw new Error(`unexpected token: ${token}`);\n }\n }\n }\n\n return rootNodes as RootNodeDefinition[];\n}\n\n/**\n * Creates a root node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The root node JSON definition.\n */\nfunction createRootNode(tokens: string[], stringLiteralPlaceholders: StringLiteralPlaceholders): RootNodeDefinition {\n // Create the root node definition.\n let node = {\n type: \"root\",\n id: undefined\n } as RootNodeDefinition;\n\n // Parse any node arguments, we should only have one if any which will be an identifier argument for the root identifier.\n const nodeArguments = parseArgumentTokens(tokens, stringLiteralPlaceholders);\n\n // Check whether any node arguments were defined.\n if (nodeArguments.length) {\n // We should only have one argument, if any, which will be an identifier argument for the root identifier.\n if (nodeArguments.length === 1 && nodeArguments[0].type === \"identifier\") {\n // The root node identifier will be the first and only node argument value.\n node.id = nodeArguments[0].value as string;\n } else {\n throw new Error(\"expected single root name argument\");\n }\n }\n\n // Grab any node attribute definitions and spread them into the node definition.\n node = { ...node, ...parseAttributeTokens(tokens, stringLiteralPlaceholders) };\n\n // This is a decorator node, so we expect an opening '{'.\n popAndCheck(tokens, \"{\");\n\n // Return the root node definition.\n return node;\n}\n\n/**\n * Creates a succeed node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The succeed node JSON definition.\n */\nfunction createSucceedNode(\n tokens: string[],\n stringLiteralPlaceholders: StringLiteralPlaceholders\n): SucceedNodeDefinition {\n const node = {\n type: \"succeed\",\n ...parseAttributeTokens(tokens, stringLiteralPlaceholders)\n } as SucceedNodeDefinition;\n\n // This is a decorator node, so we expect an opening '{'.\n popAndCheck(tokens, \"{\");\n\n // Return the succeed node definition.\n return node;\n}\n\n/**\n * Creates a fail node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The fail node JSON definition.\n */\nfunction createFailNode(tokens: string[], stringLiteralPlaceholders: StringLiteralPlaceholders): FailNodeDefinition {\n const node = {\n type: \"fail\",\n ...parseAttributeTokens(tokens, stringLiteralPlaceholders)\n } as FailNodeDefinition;\n\n // This is a decorator node, so we expect an opening '{'.\n popAndCheck(tokens, \"{\");\n\n // Return the fail node definition.\n return node;\n}\n\n/**\n * Creates a flip node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The flip node JSON definition.\n */\nfunction createFlipNode(tokens: string[], stringLiteralPlaceholders: StringLiteralPlaceholders): FlipNodeDefinition {\n const node = {\n type: \"flip\",\n ...parseAttributeTokens(tokens, stringLiteralPlaceholders)\n } as FlipNodeDefinition;\n\n // This is a decorator node, so we expect an opening '{'.\n popAndCheck(tokens, \"{\");\n\n // Return the flip node definition.\n return node;\n}\n\n/**\n * Creates a repeat node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The repeat node JSON definition.\n */\nfunction createRepeatNode(\n tokens: string[],\n stringLiteralPlaceholders: StringLiteralPlaceholders\n): RepeatNodeDefinition {\n let node = { type: \"repeat\" } as RepeatNodeDefinition;\n\n // Get the node arguments.\n const nodeArguments = parseArgumentTokens(tokens, stringLiteralPlaceholders);\n\n // The arguments of a repeat node are optional. We may have:\n // - No node arguments, in which case the repeat note will iterate indefinitely.\n // - One node argument which will be the explicit number of iterations to make.\n // - Two node arguments which define the min and max iteration bounds from which a random iteration count will be picked.\n if (nodeArguments.length) {\n // All repeat node arguments MUST be of type number and must be integer.\n nodeArguments\n .filter((arg) => arg.type !== \"number\" || !arg.isInteger)\n .forEach(() => {\n throw new Error(`repeat node iteration counts must be integer values`);\n });\n\n // We should have got one or two iteration counts.\n if (nodeArguments.length === 1) {\n // A static iteration count was defined.\n node.iterations = nodeArguments[0].value as number;\n } else if (nodeArguments.length === 2) {\n // A minimum and maximum iteration count was defined.\n node.iterations = [nodeArguments[0].value as number, nodeArguments[1].value as number];\n } else {\n // An incorrect number of iteration counts was defined.\n throw new Error(\"invalid number of repeat node iteration count arguments defined\");\n }\n }\n\n // Grab any node attribute definitions and spread them into the node definition.\n node = { ...node, ...parseAttributeTokens(tokens, stringLiteralPlaceholders) };\n\n // This is a decorator node, so we expect an opening '{'.\n popAndCheck(tokens, \"{\");\n\n // Return the repeat node definition.\n return node;\n}\n\n/**\n * Creates a retry node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The retry node JSON definition.\n */\nfunction createRetryNode(tokens: string[], stringLiteralPlaceholders: StringLiteralPlaceholders): RetryNodeDefinition {\n let node = { type: \"retry\" } as RetryNodeDefinition;\n\n // Get the node arguments.\n const nodeArguments = parseArgumentTokens(tokens, stringLiteralPlaceholders);\n\n // The arguments of a retry node are optional. We may have:\n // - No node arguments, in which case the retry note will attempt indefinitely.\n // - One node argument which will be the explicit number of attempts to make.\n // - Two node arguments which define the min and max attempt bounds from which a random attempt count will be picked.\n if (nodeArguments.length) {\n // All retry node arguments MUST be of type number and must be integer.\n nodeArguments\n .filter((arg) => arg.type !== \"number\" || !arg.isInteger)\n .forEach(() => {\n throw new Error(`retry node attempt counts must be integer values`);\n });\n\n // We should have got one or two attempt counts.\n if (nodeArguments.length === 1) {\n // A static attempt count was defined.\n node.attempts = nodeArguments[0].value as number;\n } else if (nodeArguments.length === 2) {\n // A minimum and maximum attempt count was defined.\n node.attempts = [nodeArguments[0].value as number, nodeArguments[1].value as number];\n } else {\n // An incorrect number of attempt counts was defined.\n throw new Error(\"invalid number of retry node attempt count arguments defined\");\n }\n }\n\n // Grab any node attribute definitions and spread them into the node definition.\n node = { ...node, ...parseAttributeTokens(tokens, stringLiteralPlaceholders) };\n\n // This is a decorator node, so we expect an opening '{'.\n popAndCheck(tokens, \"{\");\n\n // Return the retry node definition.\n return node;\n}\n\n/**\n * Creates a sequence node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The sequence node JSON definition.\n */\nfunction createSequenceNode(\n tokens: string[],\n stringLiteralPlaceholders: StringLiteralPlaceholders\n): SequenceNodeDefinition {\n const node = {\n type: \"sequence\",\n ...parseAttributeTokens(tokens, stringLiteralPlaceholders)\n } as SequenceNodeDefinition;\n\n // This is a composite node, so we expect an opening '{'.\n popAndCheck(tokens, \"{\");\n\n // Return the sequence node definition.\n return node;\n}\n\n/**\n * Creates a selector node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The selector node JSON definition.\n */\nfunction createSelectorNode(\n tokens: string[],\n stringLiteralPlaceholders: StringLiteralPlaceholders\n): SelectorNodeDefinition {\n const node = {\n type: \"selector\",\n ...parseAttributeTokens(tokens, stringLiteralPlaceholders)\n } as SelectorNodeDefinition;\n\n // This is a composite node, so we expect an opening '{'.\n popAndCheck(tokens, \"{\");\n\n // Return the selector node definition.\n return node;\n}\n\n/**\n * Creates a parallel node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The parallel node JSON definition.\n */\nfunction createParallelNode(\n tokens: string[],\n stringLiteralPlaceholders: StringLiteralPlaceholders\n): ParallelNodeDefinition {\n const node = {\n type: \"parallel\",\n ...parseAttributeTokens(tokens, stringLiteralPlaceholders)\n } as ParallelNodeDefinition;\n\n // This is a composite node, so we expect an opening '{'.\n popAndCheck(tokens, \"{\");\n\n // Return the parallel node definition.\n return node;\n}\n\n/**\n * Creates a lotto node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The lotto node JSON definition.\n */\nfunction createLottoNode(tokens: string[], stringLiteralPlaceholders: StringLiteralPlaceholders): LottoNodeDefinition {\n // If any node arguments have been defined then they must be our weights.\n const nodeArguments = parseArgumentTokens(tokens, stringLiteralPlaceholders);\n\n // All lotto node arguments MUST be of type number and must be integer.\n nodeArguments\n .filter((arg) => arg.type !== \"number\" || !arg.isInteger)\n .forEach(() => {\n throw new Error(`lotto node weight arguments must be integer values`);\n });\n\n const node = {\n type: \"lotto\",\n weights: nodeArguments.map(({ value }) => value),\n ...parseAttributeTokens(tokens, stringLiteralPlaceholders)\n } as LottoNodeDefinition;\n\n // This is a composite node, so we expect an opening '{'.\n popAndCheck(tokens, \"{\");\n\n // Return the lotto node definition.\n return node;\n}\n\n/**\n * Creates an action node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The action node JSON definition.\n */\nfunction createActionNode(\n tokens: string[],\n stringLiteralPlaceholders: StringLiteralPlaceholders\n): ActionNodeDefinition {\n // Parse any node arguments, we should have at least one which will be an identifier argument for the action name\n // and agent function to invoke for the action, all other arguments are to be passed as arguments to that function.\n const [actionNameIdentifier, ...agentFunctionArgs] = parseArgumentTokens(tokens, stringLiteralPlaceholders);\n\n // Our first argument MUST be defined and be an identifier as we require an action name argument.\n if (actionNameIdentifier?.type !== \"identifier\") {\n throw new Error(\"expected action name identifier argument\");\n }\n\n // Only the first argument should have been an identifier, all agent function arguments must be string, number, boolean or null.\n agentFunctionArgs\n .filter((arg) => arg.type === \"identifier\")\n .forEach((arg) => {\n throw new Error(\n `invalid action node argument value '${arg.value}', must be string, number, boolean or null`\n );\n });\n\n // Return the action node definition.\n return {\n type: \"action\",\n call: actionNameIdentifier.value,\n args: agentFunctionArgs.map(({ value }) => value),\n ...parseAttributeTokens(tokens, stringLiteralPlaceholders)\n };\n}\n\n/**\n * Creates a condition node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The condition node JSON definition.\n */\nfunction createConditionNode(\n tokens: string[],\n stringLiteralPlaceholders: StringLiteralPlaceholders\n): ConditionNodeDefinition {\n // Parse any node arguments, we should have at least one which will be an identifier argument for the condition name\n // and agent function to invoke for the condition, all other arguments are to be passed as arguments to that function.\n const [conditionNameIdentifier, ...agentFunctionArgs] = parseArgumentTokens(tokens, stringLiteralPlaceholders);\n\n // Our first argument MUST be defined and be an identifier as we require a condition name argument.\n if (conditionNameIdentifier?.type !== \"identifier\") {\n throw new Error(\"expected condition name identifier argument\");\n }\n\n // Only the first argument should have been an identifier, all agent function arguments must be string, number, boolean or null.\n agentFunctionArgs\n .filter((arg) => arg.type === \"identifier\")\n .forEach((arg) => {\n throw new Error(\n `invalid condition node argument value '${arg.value}', must be string, number, boolean or null`\n );\n });\n\n // Return the condition node definition.\n return {\n type: \"condition\",\n call: conditionNameIdentifier.value,\n args: agentFunctionArgs.map(({ value }) => value),\n ...parseAttributeTokens(tokens, stringLiteralPlaceholders)\n };\n}\n\n/**\n * Creates a wait node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The wait node JSON definition.\n */\nfunction createWaitNode(tokens: string[], stringLiteralPlaceholders: StringLiteralPlaceholders): WaitNodeDefinition {\n let node = { type: \"wait\" } as WaitNodeDefinition;\n\n // Get the node arguments.\n const nodeArguments = parseArgumentTokens(tokens, stringLiteralPlaceholders);\n\n // The arguments of a wait node are optional. We may have:\n // - No node arguments, in which case the wait will be indefinite until it is aborted.\n // - One node argument which will be the explicit duration of the wait.\n // - Two node arguments which define the min and max duration bounds from which a random duration will be picked.\n if (nodeArguments.length) {\n // All wait node arguments MUST be of type number and must be integer.\n nodeArguments\n .filter((arg) => arg.type !== \"number\" || !arg.isInteger)\n .forEach(() => {\n throw new Error(`wait node duration arguments must be integer values`);\n });\n\n // We may have:\n // - One node argument which will be the explicit duration of the wait.\n // - Two node arguments which define the min and max duration bounds from which a random duration will be picked.\n // - Too many arguments, which is not valid.\n if (nodeArguments.length === 1) {\n // An explicit duration was defined.\n node.duration = nodeArguments[0].value as number;\n } else if (nodeArguments.length === 2) {\n // Min and max duration bounds were defined from which a random duration will be picked.\n node.duration = [nodeArguments[0].value as number, nodeArguments[1].value as number];\n } else if (nodeArguments.length > 2) {\n // An incorrect number of duration arguments were defined.\n throw new Error(\"invalid number of wait node duration arguments defined\");\n }\n }\n\n // Return the wait node definition.\n return { ...node, ...parseAttributeTokens(tokens, stringLiteralPlaceholders) };\n}\n\n/**\n * Creates a branch node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The branch node JSON definition.\n */\nfunction createBranchNode(\n tokens: string[],\n stringLiteralPlaceholders: StringLiteralPlaceholders\n): BranchNodeDefinition {\n // Parse any node arguments, we should have one which will be an identifier argument for the root ref.\n const nodeArguments = parseArgumentTokens(tokens, stringLiteralPlaceholders);\n\n // We should have only a single identifer argument for a branch node, which is the root ref.\n if (nodeArguments.length !== 1 || nodeArguments[0].type !== \"identifier\") {\n throw new Error(\"expected single branch name argument\");\n }\n\n // Return the branch node definition.\n return { type: \"branch\", ref: nodeArguments[0].value };\n}\n", "import { RootNodeDefinition } from \"./BehaviourTreeDefinition\";\nimport { flattenDefinition, isBranchNode, isInteger } from \"./BehaviourTreeDefinitionUtilities\";\nimport { convertMDSLToJSON } from \"./mdsl/MDSLDefinitionParser\";\n\n/**\n * An object representing the result of validating a tree definition.\n */\nexport type DefinitionValidationResult = {\n /**\n * A flag defining whether validation succeeded.\n */\n succeeded: boolean;\n /**\n * A string containing the error message if validation did not succeed.\n */\n errorMessage?: string;\n};\n\n/**\n * Validates the specified behaviour tree definition in the form of JSON or MDSL.\n * @param definition The behaviour tree definition in the form of JSON or MDSL.\n * @returns An object representing the result of validating the given tree definition.\n */\nexport function validateDefinition(definition: any): DefinitionValidationResult {\n // The definition must be defined.\n if (definition === null || typeof definition === \"undefined\") {\n return createValidationFailureResult(\"definition is null or undefined\");\n }\n\n // We are expecting a definition in one of three different forms:\n // - A string which we will assume is MDSL and we will parse this to JSON before validation.\n // - An array which we will assume is an array of root node definitions with at least one being the primary root node (no 'id' property)\n // - An object which we will assume is the primary root node and should not have an 'id' property.\n if (typeof definition === \"string\") {\n // The definition is a string which we can assume is MDSL, so attempt to validate it.\n return validateMDSLDefinition(definition);\n } else if (typeof definition === \"object\") {\n // The definition will either be an array (of root node definitions) or an object (the single primary root node definition).\n return validateJSONDefinition(definition);\n } else {\n return createValidationFailureResult(`unexpected definition type of '${typeof definition}'`);\n }\n}\n\n/**\n * Validates the specified behaviour tree definition in the form of MDSL.\n * @param definition The behaviour tree definition in the form of MDSL.\n * @returns An object representing the result of validating the given tree definition.\n */\nexport function validateMDSLDefinition(definition: string): DefinitionValidationResult {\n let rootNodeDefinitions;\n\n // The first thing the we need to do is to attempt to convert our MDSL into JSON.\n try {\n // The definition is a string which we can assume is MDSL, so attempt to parse it to a JSON definition in the form of an array of root node definitions.\n rootNodeDefinitions = convertMDSLToJSON(definition);\n } catch (error) {\n // We failed to parse the JSON from the MDSL, this is likely to be the result of it not being a valid MDSL string.\n return createValidationFailureResult(`invalid MDSL: ${definition}`);\n }\n\n // Unpack all of the root node definitions into arrays of main ('id' defined) and sub ('id' not defined) root node definitions.\n const mainRootNodeDefinitions = rootNodeDefinitions.filter(({ id }) => typeof id === \"undefined\");\n const subRootNodeDefinitions = rootNodeDefinitions.filter(({ id }) => typeof id === \"string\" && id.length > 0);\n\n // We should ALWAYS have exactly one root node definition without an 'id' property defined, which is out main root node definition.\n if (mainRootNodeDefinitions.length !== 1) {\n return createValidationFailureResult(\n \"expected single unnamed root node at base of definition to act as main root\"\n );\n }\n\n // We should never have duplicate 'id' properties across our sub root node definitions.\n const subRootNodeIdenitifers: string[] = [];\n for (const { id } of subRootNodeDefinitions) {\n // Have we already come across this 'id' property value?\n if (subRootNodeIdenitifers.includes(id!)) {\n return createValidationFailureResult(`multiple root nodes found with duplicate name '${id}'`);\n }\n\n subRootNodeIdenitifers.push(id!);\n }\n\n // Check for any branch node circular depedencies. This will NOT include any globally registered subtrees.\n const circularDependencyPath = findBranchCircularDependencyPath(rootNodeDefinitions);\n\n // If we found a circular dependency in our root node and branch node definitions then the definition is definitely not valid.\n if (circularDependencyPath) {\n return createValidationFailureResult(\n `circular dependency found in branch node references: ${circularDependencyPath}`\n );\n }\n\n // Our definition was valid!\n return { succeeded: true };\n}\n\n/**\n * Validates the specified behaviour tree definition in the form of JSON.\n * @param definition The behaviour tree definition in the form of JSON.\n * @returns An object representing the result of validating the given tree definition.\n */\nexport function validateJSONDefinition(\n definition: RootNodeDefinition | RootNodeDefinition[]\n): DefinitionValidationResult {\n // The definition will either be an array (of root node definitions) or an object (the single primary root node definition).\n const rootNodeDefinitions = Array.isArray(definition) ? definition : [definition];\n\n // Iterate over our array of root nodes and call validateNode for each, passing an initial depth of 0, wrapped in a try catch to handle validation failures.\n try {\n rootNodeDefinitions.forEach((rootNodeDefinition) => validateNode(rootNodeDefinition, 0));\n } catch (error) {\n // Handle cases where we have caught a thrown Error and return a failure result with the error message.\n if (error instanceof Error) {\n return createValidationFailureResult(error.message);\n }\n\n // No idea what happened here!\n return createValidationFailureResult(`unexpected error: ${error}`);\n }\n\n // Unpack all of the root node definitions into arrays of main ('id' defined) and sub ('id' not defined) root node definitions.\n const mainRootNodeDefinitions = rootNodeDefinitions.filter(({ id }) => typeof id === \"undefined\");\n const subRootNodeDefinitions = rootNodeDefinitions.filter(({ id }) => typeof id === \"string\" && id.length > 0);\n\n // We should ALWAYS have exactly one root node definition without an 'id' property defined, which is out main root node definition.\n if (mainRootNodeDefinitions.length !== 1) {\n return createValidationFailureResult(\n \"expected single root node without 'id' property defined to act as main root\"\n );\n }\n\n // We should never have duplicate 'id' properties across our sub root node definitions.\n const subRootNodeIdenitifers: string[] = [];\n for (const { id } of subRootNodeDefinitions) {\n // Have we already come across this 'id' property value?\n if (subRootNodeIdenitifers.includes(id!)) {\n return createValidationFailureResult(\n `multiple root nodes found with duplicate 'id' property value of '${id}'`\n );\n }\n\n subRootNodeIdenitifers.push(id!);\n }\n\n // Check for any branch node circular depedencies. This will NOT include any globally registered subtrees.\n const circularDependencyPath = findBranchCircularDependencyPath(rootNodeDefinitions);\n\n // If we found a circular dependency in our root node and branch node definitions then the definition is definitely not valid.\n if (circularDependencyPath) {\n return createValidationFailureResult(\n `circular dependency found in branch node references: ${circularDependencyPath}`\n );\n }\n\n // Our definition was valid!\n return { succeeded: true };\n}\n\n/**\n * Find the first circular depdendency path present in the array of root node definitions, or null if one doesn't exist.\n * This will not consider branch nodes that reference any globally registered subtrees.\n * @param rootNodeDefinitions The array of root node definitions.\n * @returns The first circular depdendency path present in the array of root node definitions as string, or null if one doesn't exist.\n */\nfunction findBranchCircularDependencyPath(rootNodeDefinitions: RootNodeDefinition[]): string | null {\n // Create a mapping of root node identifiers to other root nodes that they reference via branch nodes.\n // Below is an example of a mapping that includes a circular dependency (root => a => b => c => a)\n // [{ refs: [\"a\", \"b\"] }, { id: \"a\", refs: [\"b\"] }, { id: \"b\", refs: [\"c\"] }, { id: \"c\", refs: [\"a\"] }]\n const rootNodeMappings: { id: string | undefined; refs: string[] }[] = rootNodeDefinitions.map(\n (rootNodeDefinition) => ({\n id: rootNodeDefinition.id,\n refs: flattenDefinition(rootNodeDefinition)\n .filter(isBranchNode)\n .map(({ ref }) => ref)\n })\n );\n\n let badPathFormatted: string | null = null;\n\n // A recursive function to walk through the mappings, keeping track of which root nodes we have visited in the form of a path of root node identifiers.\n const followRefs = (mapping: { id: string | undefined; refs: string[] }, path: (string | undefined)[] = []) => {\n // Have we found a circular dependency?\n if (path.includes(mapping.id)) {\n // We found a circular dependency! Get the bad path of root node identifiers.\n const badPath = [...path, mapping.id];\n\n // Set the formatted path value. [undefined, \"a\", \"b\", \"c\", \"a\"] would be formatted as \"a -> b -> c -> a\".\n badPathFormatted = badPath.filter((element) => !!element).join(\" => \");\n\n // No need to continue, we found a circular dependency.\n return;\n }\n\n for (const ref of mapping.refs) {\n // Find the mapping for the root node with an identifer matching the current ref.\n const subMapping = rootNodeMappings.find(({ id }) => id === ref);\n\n // We may not have a mapping for this ref, which will happen if this ref is for a globally registered subtree.\n if (subMapping) {\n followRefs(subMapping, [...path, mapping.id]);\n }\n }\n };\n\n // Start looking for circular dependencies from the root.\n followRefs(rootNodeMappings.find((mapping) => typeof mapping.id === \"undefined\")!);\n\n return badPathFormatted;\n}\n\n/**\n * Validate an object that we expect to be a node definition.\n * @param definition An object that we expect to be a node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateNode(definition: any, depth: number): void {\n // Every node must be valid object and have a non-empty 'type' string property.\n if (typeof definition !== \"object\" || typeof definition.type !== \"string\" || definition.type.length === 0) {\n throw new Error(\n `node definition is not an object or 'type' property is not a non-empty string at depth '${depth}'`\n );\n }\n\n // How we validate this node definition will depend on its type.\n switch (definition.type) {\n case \"action\":\n validateActionNode(definition, depth);\n break;\n\n case \"condition\":\n validateConditionNode(definition, depth);\n break;\n\n case \"wait\":\n validateWaitNode(definition, depth);\n break;\n\n case \"branch\":\n validateBranchNode(definition, depth);\n break;\n\n case \"root\":\n validateRootNode(definition, depth);\n break;\n\n case \"success\":\n validateSuccessNode(definition, depth);\n break;\n\n case \"fail\":\n validateFailNode(definition, depth);\n break;\n\n case \"flip\":\n validateFlipNode(definition, depth);\n break;\n\n case \"repeat\":\n validateRepeatNode(definition, depth);\n break;\n\n case \"retry\":\n validateRetryNode(definition, depth);\n break;\n\n case \"sequence\":\n validateSequenceNode(definition, depth);\n break;\n\n case \"selector\":\n validateSelectorNode(definition, depth);\n break;\n\n case \"parallel\":\n validateParallelNode(definition, depth);\n break;\n\n default:\n throw new Error(`unexpected node type of '${definition.type}' at depth '${depth}'`);\n }\n}\n\n/**\n * Validate any attributes for a given node definition.\n * @param definition The node definition.\n * @param depth The depth of the node in the behaviour tree definition.\n */\nfunction validateNodeAttributes(definition: any, depth: number): void {\n // Validate each of the attribute types for this node.\n [\"while\", \"until\", \"entry\", \"exit\", \"step\"].forEach((attributeName) => {\n // Attempt to grab the definition for the current attribute from the node definition.\n const attributeDefinition = definition[attributeName];\n\n // All node attributes are optional, so there is nothing to do if the current attribute is not defined.\n if (typeof attributeDefinition === \"undefined\") {\n return;\n }\n\n // The attribute definition must be an object.\n if (typeof attributeDefinition !== \"object\") {\n throw new Error(\n `expected attribute '${attributeName}' to be an object for '${definition.type}' node at depth '${depth}'`\n );\n }\n\n // The 'call' property must be defined for any attribute definition.\n if (typeof attributeDefinition.call !== \"string\" || attributeDefinition.call.length === 0) {\n throw new Error(\n `expected 'call' property for attribute '${attributeName}' to be a non-empty string for '${definition.type}' node at depth '${depth}'`\n );\n }\n\n // If any node attribute arguments have been defined then they must have been defined in an array.\n if (typeof attributeDefinition.args !== \"undefined\" && !Array.isArray(attributeDefinition.args)) {\n throw new Error(\n `expected 'args' property for attribute '${attributeName}' to be an array for '${definition.type}' node at depth '${depth}'`\n );\n }\n });\n}\n\n/**\n * Validate an object that we expect to be a root node definition.\n * @param definition An object that we expect to be a root node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateRootNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"root\") {\n throw new Error(\"expected node type of 'root' for root node\");\n }\n\n // A root node cannot be the child of another node.\n if (depth > 0) {\n throw new Error(\"a root node cannot be the child of another node\");\n }\n\n // Check that, if the root node 'id' property is defined, it is a non-empty string.\n if (typeof definition.id !== \"undefined\" && (typeof definition.id !== \"string\" || definition.id.length === 0)) {\n throw new Error(\"expected non-empty string for 'id' property if defined for root node\");\n }\n\n // A root node is a decorator node, so must have a child node defined.\n if (typeof definition.child === \"undefined\") {\n throw new Error(\"expected property 'child' to be defined for root node\");\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n\n // Validate the child node of this decorator node.\n validateNode(definition.child, depth + 1);\n}\n\n/**\n * Validate an object that we expect to be a success node definition.\n * @param definition An object that we expect to be a success node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateSuccessNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"success\") {\n throw new Error(`expected node type of 'success' for success node at depth '${depth}'`);\n }\n\n // A success node is a decorator node, so must have a child node defined.\n if (typeof definition.child === \"undefined\") {\n throw new Error(`expected property 'child' to be defined for success node at depth '${depth}'`);\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n\n // Validate the child node of this decorator node.\n validateNode(definition.child, depth + 1);\n}\n\n/**\n * Validate an object that we expect to be a fail node definition.\n * @param definition An object that we expect to be a fail node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateFailNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"fail\") {\n throw new Error(`expected node type of 'fail' for fail node at depth '${depth}'`);\n }\n\n // A fail node is a decorator node, so must have a child node defined.\n if (typeof definition.child === \"undefined\") {\n throw new Error(`expected property 'child' to be defined for fail node at depth '${depth}'`);\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n\n // Validate the child node of this decorator node.\n validateNode(definition.child, depth + 1);\n}\n\n/**\n * Validate an object that we expect to be a flip node definition.\n * @param definition An object that we expect to be a flip node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateFlipNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"flip\") {\n throw new Error(`expected node type of 'flip' for flip node at depth '${depth}'`);\n }\n\n // A flip node is a decorator node, so must have a child node defined.\n if (typeof definition.child === \"undefined\") {\n throw new Error(`expected property 'child' to be defined for flip node at depth '${depth}'`);\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n\n // Validate the child node of this decorator node.\n validateNode(definition.child, depth + 1);\n}\n\n/**\n * Validate an object that we expect to be a repeat node definition.\n * @param definition An object that we expect to be a repeat node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateRepeatNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"repeat\") {\n throw new Error(`expected node type of 'repeat' for repeat node at depth '${depth}'`);\n }\n\n // A repeat node is a decorator node, so must have a child node defined.\n if (typeof definition.child === \"undefined\") {\n throw new Error(`expected property 'child' to be defined for repeat node at depth '${depth}'`);\n }\n\n // Check whether an 'iterations' property has been defined, it may not have been if this node is to repeat indefinitely.\n if (typeof definition.iterations !== \"undefined\") {\n if (Array.isArray(definition.iterations)) {\n // Check whether any elements of the array are not integer values.\n const containsNonInteger = !!definition.iterations.find((value: unknown) => !isInteger(value));\n\n // If the 'iterations' property is an array then it MUST contain two integer values.\n if (definition.iterations.length !== 2 || containsNonInteger) {\n throw new Error(\n `expected array containing two integer values for 'iterations' property if defined for repeat node at depth '${depth}'`\n );\n }\n } else if (!isInteger(definition.iterations)) {\n throw new Error(\n `expected integer value or array containing two integer values for 'iterations' property if defined for repeat node at depth '${depth}'`\n );\n }\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n\n // Validate the child node of this decorator node.\n validateNode(definition.child, depth + 1);\n}\n\n/**\n * Validate an object that we expect to be a retry node definition.\n * @param definition An object that we expect to be a retry node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateRetryNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"retry\") {\n throw new Error(`expected node type of 'retry' for retry node at depth '${depth}'`);\n }\n\n // A retry node is a decorator node, so must have a child node defined.\n if (typeof definition.child === \"undefined\") {\n throw new Error(`expected property 'child' to be defined for retry node at depth '${depth}'`);\n }\n\n // Check whether an 'attempts' property has been defined, it may not have been if this node is to retry indefinitely.\n if (typeof definition.attempts !== \"undefined\") {\n if (Array.isArray(definition.attempts)) {\n // Check whether any elements of the array are not integer values.\n const containsNonInteger = !!definition.attempts.find((value: unknown) => !isInteger(value));\n\n // If the 'attempts' property is an array then it MUST contain two integer values.\n if (definition.attempts.length !== 2 || containsNonInteger) {\n throw new Error(\n `expected array containing two integer values for 'attempts' property if defined for retry node at depth '${depth}'`\n );\n }\n } else if (!isInteger(definition.attempts)) {\n throw new Error(\n `expected integer value or array containing two integer values for 'attempts' property if defined for retry node at depth '${depth}'`\n );\n }\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n\n // Validate the child node of this decorator node.\n validateNode(definition.child, depth + 1);\n}\n\n/**\n * Validate an object that we expect to be a branch node definition.\n * @param definition An object that we expect to be a branch node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateBranchNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"branch\") {\n throw new Error(`expected node type of 'branch' for branch node at depth '${depth}'`);\n }\n\n // Check that the branch node 'ref' property is defined and is a non-empty string.\n if (typeof definition.ref !== \"string\" || definition.ref.length === 0) {\n throw new Error(`expected non-empty string for 'ref' property for branch node at depth '${depth}'`);\n }\n\n // It is invalid to define guard attributes for a branch node as they should be defined on the referenced root node.\n [\"while\", \"until\"].forEach((attributeName) => {\n if (typeof definition[attributeName] !== \"undefined\") {\n throw new Error(\n `guards should not be defined for branch nodes but guard '${attributeName}' was defined for branch node at depth '${depth}'`\n );\n }\n });\n\n // It is invalid to define callback attributes for a branch node as they should be defined on the referenced root node.\n [\"entry\", \"exit\", \"step\"].forEach((attributeName) => {\n if (typeof definition[attributeName] !== \"undefined\") {\n throw new Error(\n `callbacks should not be defined for branch nodes but callback '${attributeName}' was defined for branch node at depth '${depth}'`\n );\n }\n });\n}\n\n/**\n * Validate an object that we expect to be a action node definition.\n * @param definition An object that we expect to be a action node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateActionNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"action\") {\n throw new Error(`expected node type of 'action' for action node at depth '${depth}'`);\n }\n\n // The 'call' property must be defined for a action node definition.\n if (typeof definition.call !== \"string\" || definition.call.length === 0) {\n throw new Error(`expected non-empty string for 'call' property of action node at depth '${depth}'`);\n }\n\n // If any action function arguments have been defined then they must have been defined in an array.\n if (typeof definition.args !== \"undefined\" && !Array.isArray(definition.args)) {\n throw new Error(`expected array for 'args' property if defined for action node at depth '${depth}'`);\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n}\n\n/**\n * Validate an object that we expect to be a condition node definition.\n * @param definition An object that we expect to be a condition node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateConditionNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"condition\") {\n throw new Error(`expected node type of 'condition' for condition node at depth '${depth}'`);\n }\n\n // The 'call' property must be defined for a condition node definition.\n if (typeof definition.call !== \"string\" || definition.call.length === 0) {\n throw new Error(`expected non-empty string for 'call' property of condition node at depth '${depth}'`);\n }\n\n // If any condition function arguments have been defined then they must have been defined in an array.\n if (typeof definition.args !== \"undefined\" && !Array.isArray(definition.args)) {\n throw new Error(`expected array for 'args' property if defined for condition node at depth '${depth}'`);\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n}\n\n/**\n * Validate an object that we expect to be a wait node definition.\n * @param definition An object that we expect to be a wait node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateWaitNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"wait\") {\n throw new Error(`expected node type of 'wait' for wait node at depth '${depth}'`);\n }\n\n // Check whether a 'duration' property has been defined, it may not have been if this node is to wait indefinitely.\n if (typeof definition.duration !== \"undefined\") {\n if (Array.isArray(definition.duration)) {\n // Check whether any elements of the array are not integer values.\n const containsNonInteger = !!definition.duration.find((value: unknown) => !isInteger(value));\n\n // If the 'duration' property is an array then it MUST contain two integer values.\n if (definition.duration.length !== 2 || containsNonInteger) {\n throw new Error(\n `expected array containing two integer values for 'duration' property if defined for wait node at depth '${depth}'`\n );\n }\n } else if (!isInteger(definition.duration)) {\n throw new Error(\n `expected integer value or array containing two integer values for 'duration' property if defined for wait node at depth '${depth}'`\n );\n }\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n}\n\n/**\n * Validate an object that we expect to be a sequence node definition.\n * @param definition An object that we expect to be a sequence node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateSequenceNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"sequence\") {\n throw new Error(`expected node type of 'sequence' for sequence node at depth '${depth}'`);\n }\n\n // A sequence node is a composite node, so must have a children nodes array defined.\n if (!Array.isArray(definition.children) || definition.children.length === 0) {\n throw new Error(`expected non-empty 'children' array to be defined for sequence node at depth '${depth}'`);\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n\n // Validate the child nodes of this composite node.\n definition.children.forEach((child: any) => validateNode(child, depth + 1));\n}\n\n/**\n * Validate an object that we expect to be a selector node definition.\n * @param definition An object that we expect to be a selector node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateSelectorNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"selector\") {\n throw new Error(`expected node type of 'selector' for selector node at depth '${depth}'`);\n }\n\n // A selector node is a composite node, so must have a children nodes array defined.\n if (!Array.isArray(definition.children) || definition.children.length === 0) {\n throw new Error(`expected non-empty 'children' array to be defined for selector node at depth '${depth}'`);\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n\n // Validate the child nodes of this composite node.\n definition.children.forEach((child: any) => validateNode(child, depth + 1));\n}\n\n/**\n * Validate an object that we expect to be a parallel node definition.\n * @param definition An object that we expect to be a parallel node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateParallelNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"parallel\") {\n throw new Error(`expected node type of 'parallel' for parallel node at depth '${depth}'`);\n }\n\n // A parallel node is a composite node, so must have a children nodes array defined.\n if (!Array.isArray(definition.children) || definition.children.length === 0) {\n throw new Error(`expected non-empty 'children' array to be defined for parallel node at depth '${depth}'`);\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n\n // Validate the child nodes of this composite node.\n definition.children.forEach((child: any) => validateNode(child, depth + 1));\n}\n\n/**\n * A helper function to create a failure validation result with the given error message.\n * @param errorMessage The validation failure error message.\n * @returns A failure validation result with the given error message.\n */\nfunction createValidationFailureResult(errorMessage: string): DefinitionValidationResult {\n return { succeeded: false, errorMessage };\n}\n", "import Node from \"../../nodes/Node\";\n\n/**\n * An exception thrown when evaluating node guard path conditions and a conditions fails.\n */\nexport default class GuardUnsatisifedException extends Error {\n /**\n * @param source The node at which a guard condition failed.\n */\n constructor(private source: Node) {\n super(\"A guard path condition has failed\");\n }\n\n /**\n * Gets whether the specified node is the node at which a guard condition failed.\n * @param node The node to check against the source node.\n * @returns Whether the specified node is the node at which a guard condition failed.\n */\n isSourceNode = (node: Node) => node === this.source;\n}\n", "import { Agent } from \"../../Agent\";\nimport Guard from \"./Guard\";\nimport Node from \"../../nodes/Node\";\nimport GuardUnsatisifedException from \"./GuardUnsatisifedException\";\n\nexport type GuardPathPart = {\n node: Node;\n guards: Guard[];\n};\n\n/**\n * Represents a path of node guards along a root-to-leaf tree path.\n */\nexport default class GuardPath {\n /**\n * @param nodes An array of objects defining a node instance -> guard link, ordered by node depth.\n */\n constructor(private nodes: GuardPathPart[]) {}\n\n /**\n * Evaluate guard conditions for all guards in the tree path, moving outwards from the root.\n * @param agent The agent, required for guard evaluation.\n * @returns An evaluation results object.\n */\n evaluate = (agent: Agent) => {\n // We need to evaluate guard conditions for nodes up the tree, moving outwards from the root.\n for (const details of this.nodes) {\n // There can be multiple guards per node.\n for (const guard of details.guards) {\n // Check whether the guard condition passes, and throw an exception if not.\n if (!guard.isSatisfied(agent)) {\n throw new GuardUnsatisifedException(details.node);\n }\n }\n }\n };\n}\n", "import { Agent } from \"../Agent\";\nimport Attribute from \"../attributes/Attribute\";\nimport Entry from \"../attributes/callbacks/Entry\";\nimport Exit from \"../attributes/callbacks/Exit\";\nimport Step from \"../attributes/callbacks/Step\";\nimport Guard from \"../attributes/guards/Guard\";\nimport GuardPath from \"../attributes/guards/GuardPath\";\nimport GuardUnsatisifedException from \"../attributes/guards/GuardUnsatisifedException\";\nimport { BehaviourTreeOptions } from \"../BehaviourTreeOptions\";\nimport { AnyArgument } from \"../RootAstNodesBuilder\";\nimport State, { AnyState } from \"../State\";\nimport Leaf from \"./leaf/Leaf\";\n\n/**\n * A base node.\n */\nexport default abstract class Node {\n /**\n * The node uid.\n */\n private readonly uid: string = createNodeUid();\n /**\n * The node state.\n */\n private state: AnyState = State.READY;\n /**\n * The guard path to evaluate as part of a node update.\n */\n private guardPath: GuardPath | undefined;\n\n /**\n * @param type The node type.\n * @param attributes The node attributes.\n * @param args The node argument definitions.\n */\n constructor(private type: string, private attributes: Attribute[], private args: AnyArgument[]) {}\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected abstract onUpdate(agent: Agent, options: BehaviourTreeOptions): void;\n\n /**\n * Gets the name of the node.\n */\n public abstract getName(): string;\n\n /**\n * Gets whether this node is a leaf node.\n */\n public abstract isLeafNode: () => this is Leaf;\n\n /**\n * Gets/Sets the state of the node.\n */\n getState = (): AnyState => this.state;\n setState = (value: AnyState): void => {\n this.state = value;\n };\n\n /**\n * Gets the unique id of the node.\n */\n getUid = () => this.uid;\n\n /**\n * Gets the type of the node.\n */\n getType = () => this.type;\n\n /**\n * Gets the node attributes.\n */\n getAttributes = () => this.attributes;\n\n /**\n * Gets the node arguments.\n */\n getArguments = () => this.args;\n\n /**\n * Gets the node attribute with the specified type, or null if it does not exist.\n */\n getAttribute(type: \"entry\" | \"ENTRY\"): Entry;\n getAttribute(type: \"exit\" | \"EXIT\"): Exit;\n getAttribute(type: \"step\" | \"STEP\"): Step;\n getAttribute(type: string): Attribute {\n return (\n this.getAttributes().filter((decorator) => decorator.getType().toUpperCase() === type.toUpperCase())[0] ||\n null\n );\n }\n\n /**\n * Gets the node attributes.\n */\n getGuardAttributes = (): Guard[] => this.getAttributes().filter((decorator) => decorator.isGuard()) as Guard[];\n\n /**\n * Sets the guard path to evaluate as part of a node update.\n */\n setGuardPath = (value: GuardPath) => (this.guardPath = value);\n\n /**\n * Gets whether a guard path is assigned to this node.\n */\n hasGuardPath = () => !!this.guardPath;\n\n /**\n * Gets whether this node is in the specified state.\n * @param value The value to compare to the node state.\n */\n public is(value: AnyState): boolean {\n return this.state === value;\n }\n\n /**\n * Reset the state of the node.\n */\n public reset(): void {\n this.setState(State.READY);\n }\n\n /**\n * Abort the running of this node.\n * @param agent The agent.\n */\n public abort(agent: Agent): void {\n // There is nothing to do if this node is not in the running state.\n if (!this.is(State.RUNNING)) {\n return;\n }\n\n // Reset the state of this node.\n this.reset();\n\n this.getAttribute(\"exit\")?.callAgentFunction(agent, false, true);\n }\n\n /**\n * Update the node.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n * @returns The result of the update.\n */\n public update(agent: Agent, options: BehaviourTreeOptions): void {\n // If this node is already in a 'SUCCEEDED' or 'FAILED' state then there is nothing to do.\n if (this.is(State.SUCCEEDED) || this.is(State.FAILED)) {\n return;\n }\n\n try {\n // Evaluate all of the guard path conditions for the current tree path.\n this.guardPath!.evaluate(agent);\n\n // If this node is in the READY state then call the ENTRY for this node if it exists.\n if (this.is(State.READY)) {\n this.getAttribute(\"entry\")?.callAgentFunction(agent);\n }\n\n this.getAttribute(\"step\")?.callAgentFunction(agent);\n\n // Do the actual update.\n this.onUpdate(agent, options);\n\n // If this node is now in a 'SUCCEEDED' or 'FAILED' state then call the EXIT for this node if it exists.\n if (this.is(State.SUCCEEDED) || this.is(State.FAILED)) {\n this.getAttribute(\"exit\")?.callAgentFunction(agent, this.is(State.SUCCEEDED), false);\n }\n } catch (error) {\n // If the error is a GuardUnsatisfiedException then we need to determine if this node is the source.\n if (error instanceof GuardUnsatisifedException && error.isSourceNode(this)) {\n // Abort the current node.\n this.abort(agent);\n\n // Any node that is the source of an abort will be a failed node.\n this.setState(State.FAILED);\n } else {\n throw error;\n }\n }\n }\n}\n\n/**\n * Create a randomly generated node uid.\n * @returns A randomly generated node uid.\n */\nfunction createNodeUid(): string {\n var S4 = function () {\n return (((1 + Math.random()) * 0x10000) | 0).toString(16).substring(1);\n };\n return S4() + S4() + \"-\" + S4() + \"-\" + S4() + \"-\" + S4() + \"-\" + S4() + S4() + S4();\n}\n", "import Node from \"../Node\";\n\n/**\n * A leaf node.\n */\nexport default abstract class Leaf extends Node {\n /**\n * Gets whether this node is a leaf node.\n */\n isLeafNode = () => true;\n}\n", "import { ActionResult, Agent, ExitFunctionArg, FunctionArg, GlobalFunction } from \"./Agent\";\nimport { AnyArgument, RootAstNode } from \"./RootAstNodesBuilder\";\n\n// Exit callbacks receive their own special type of argument.\n// There's probably stricter ways to represent this but it feels overly complex right now.\ntype ExitResultArg = { value: ExitFunctionArg };\nexport type AnyExitArgument = AnyArgument | ExitResultArg;\n\nexport type InvokerFunction = (args: AnyExitArgument[]) => ActionResult;\n\n/**\n * A singleton used to store and lookup registered functions and subtrees.\n */\nexport default class Lookup {\n /**\n * The object holding any registered functions keyed on function name.\n */\n private static functionTable: { [key: string]: GlobalFunction } = {};\n /**\n * The object holding any registered sub-trees keyed on tree name.\n */\n private static subtreeTable: { [key: string]: RootAstNode } = {};\n\n /**\n * Gets the function with the specified name.\n * @param name The name of the function.\n * @returns The function with the specified name.\n */\n public static getFunc(name: string): GlobalFunction {\n return this.functionTable[name];\n }\n\n /**\n * Sets the function with the specified name for later lookup.\n * @param name The name of the function.\n * @param func The function.\n */\n public static setFunc(name: string, func: GlobalFunction): void {\n this.functionTable[name] = func;\n }\n\n /**\n * Gets the function invoker for the specified agent and function name.\n * If a function with the specified name exists on the agent object then it will\n * be returned, otherwise we will then check the registered functions for a match.\n * @param agent The agent instance that this behaviour tree is modelling behaviour for.\n * @param name The function name.\n * @returns The function invoker for the specified agent and function name.\n */\n static getFuncInvoker(agent: Agent, name: string): InvokerFunction | null {\n // Check whether the agent contains the specified function.\n const foundOnAgent = agent[name];\n if (foundOnAgent && typeof foundOnAgent === \"function\") {\n return (args: AnyExitArgument[]): boolean | ActionResult =>\n foundOnAgent.apply(\n agent,\n args.map((arg) => arg.value)\n );\n }\n\n // The agent does not contain the specified function but it may have been registered at some point.\n if (this.functionTable[name] && typeof this.functionTable[name] === \"function\") {\n return (args: AnyExitArgument[]) => this.functionTable[name](agent, ...args.map((arg) => arg.value));\n }\n\n // We have no function to invoke.\n return null;\n }\n\n /**\n * Gets the subtree with the specified name.\n * @param name The name of the subtree.\n * @returns The subtree with the specified name.\n */\n static getSubtree(name: string): RootAstNode {\n return this.subtreeTable[name];\n }\n\n /**\n * Sets the subtree with the specified name for later lookup.\n * @param name The name of the subtree.\n * @param subtree The subtree.\n */\n static setSubtree(name: string, subtree: RootAstNode) {\n this.subtreeTable[name] = subtree;\n }\n\n /**\n * Removes the registered function or subtree with the specified name.\n * @param name The name of the registered function or subtree.\n */\n static remove(name: string) {\n delete this.functionTable[name];\n delete this.subtreeTable[name];\n }\n\n /**\n * Remove all registered functions and subtrees.\n */\n static empty() {\n this.functionTable = {};\n this.subtreeTable = {};\n }\n}\n", "import Leaf from \"./Leaf\";\nimport State, { CompleteState } from \"../../State\";\nimport Lookup from \"../../Lookup\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { AnyArgument } from \"../../RootAstNodesBuilder\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * An Action leaf node.\n * This represents an immediate or ongoing state of behaviour.\n */\nexport default class Action extends Leaf {\n /**\n * @param attributes The node attributes.\n * @param actionName The action name.\n * @param actionArguments The array of action argument definitions.\n */\n constructor(attributes: Attribute[], private actionName: string, private actionArguments: AnyArgument[]) {\n super(\"action\", attributes, actionArguments);\n }\n\n /**\n * Whether there is a pending update promise.\n */\n private isUsingUpdatePromise = false;\n\n /**\n * The finished state result of an update promise.\n */\n private updatePromiseStateResult: CompleteState | null = null;\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // If the result of this action depends on an update promise then there is nothing to do until\n // it resolves, unless there has been a value set as a result of the update promise resolving.\n if (this.isUsingUpdatePromise) {\n // Check whether the update promise has resolved with a state value.\n if (this.updatePromiseStateResult) {\n // Set the state of this node to match the state returned by the promise.\n this.setState(this.updatePromiseStateResult);\n }\n\n return;\n }\n\n // Attempt to get the invoker for the action function.\n const actionFuncInvoker = Lookup.getFuncInvoker(agent, this.actionName);\n\n // The action function should be defined.\n if (actionFuncInvoker === null) {\n throw new Error(\n `cannot update action node as the action '${this.actionName}' function is not defined on the agent and has not been registered`\n );\n }\n\n // Call the action function, the result of which may be:\n // - The finished state of this action node.\n // - A promise to return a finished node state.\n // - Undefined if the node should remain in the running state.\n const updateResult = actionFuncInvoker(this.actionArguments) as CompleteState | Promise;\n\n if (updateResult instanceof Promise) {\n updateResult.then(\n (result) => {\n // If 'isUpdatePromisePending' is null then the promise was cleared as it was resolving, probably via an abort of reset.\n if (!this.isUsingUpdatePromise) {\n return;\n }\n\n // Check to make sure the result is a valid finished state.\n if (result !== State.SUCCEEDED && result !== State.FAILED) {\n throw new Error(\n \"action node promise resolved with an invalid value, expected a State.SUCCEEDED or State.FAILED value to be returned\"\n );\n }\n\n // Set pending update promise state result to be processed on next update.\n this.updatePromiseStateResult = result;\n },\n (reason) => {\n // If 'isUpdatePromisePending' is null then the promise was cleared as it was resolving, probably via an abort of reset.\n if (!this.isUsingUpdatePromise) {\n return;\n }\n\n // Just throw whatever was returned as the rejection argument.\n throw new Error(reason);\n }\n );\n\n // This node will be in the 'RUNNING' state until the update promise resolves.\n this.setState(State.RUNNING);\n\n // We are now waiting for the promise returned by the use to resolve before we know what state this node is in.\n this.isUsingUpdatePromise = true;\n } else {\n // Validate the returned value.\n this.validateUpdateResult(updateResult);\n\n // Set the state of this node, this may be undefined, which just means that the node is still in the 'RUNNING' state.\n this.setState(updateResult || State.RUNNING);\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => this.actionName;\n\n /**\n * Reset the state of the node.\n */\n reset = () => {\n // Reset the state of this node.\n this.setState(State.READY);\n\n // There is no longer an update promise that we care about.\n this.isUsingUpdatePromise = false;\n this.updatePromiseStateResult = null;\n };\n\n /**\n * Validate the result of an update function call.\n * @param result The result of an update function call.\n */\n private validateUpdateResult = (result: CompleteState | boolean) => {\n switch (result) {\n case State.SUCCEEDED:\n case State.FAILED:\n case undefined:\n return;\n default:\n throw new Error(\n `action '${this.actionName}' 'onUpdate' returned an invalid response, expected an optional State.SUCCEEDED or State.FAILED value to be returned`\n );\n }\n };\n}\n", "import Leaf from \"./Leaf\";\nimport State from \"../../State\";\nimport Lookup from \"../../Lookup\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { AnyArgument } from \"../../RootAstNodesBuilder\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A Condition leaf node.\n * This will succeed or fail immediately based on an agent predicate, without moving to the 'RUNNING' state.\n */\nexport default class Condition extends Leaf {\n /**\n * @param attributes The node attributes.\n * @param conditionName The name of the condition function.\n * @param conditionArguments The array of condition argument definitions.\n */\n constructor(attributes: Attribute[], private conditionName: string, private conditionArguments: AnyArgument[]) {\n super(\"condition\", attributes, conditionArguments);\n }\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // Attempt to get the invoker for the condition function.\n const conditionFuncInvoker = Lookup.getFuncInvoker(agent, this.conditionName);\n\n // The condition function should be defined.\n if (conditionFuncInvoker === null) {\n throw new Error(\n `cannot update condition node as the condition '${this.conditionName}' function is not defined on the agent and has not been registered`\n );\n }\n\n // Call the condition function to determine the state of this node.\n this.setState(!!conditionFuncInvoker(this.conditionArguments) ? State.SUCCEEDED : State.FAILED);\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => this.conditionName;\n}\n", "import Leaf from \"./Leaf\";\nimport State from \"../../State\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { Agent } from \"../../Agent\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A WAIT node.\n * The state of this node will change to SUCCEEDED after a duration of time\n */\nexport default class Wait extends Leaf {\n /**\n * @param attributes The node attributes.\n * @param duration The duration that this node will wait to succeed in milliseconds.\n * @param durationMin The minimum possible duration in milliseconds that this node will wait to succeed.\n * @param durationMax The maximum possible duration in milliseconds that this node will wait to succeed.\n */\n constructor(\n attributes: Attribute[],\n private duration: number | null,\n private durationMin: number | null,\n private durationMax: number | null\n ) {\n super(\"wait\", attributes, []);\n }\n\n /**\n * The time in milliseconds at which this node was first updated.\n */\n private initialUpdateTime: number = 0;\n\n /**\n * The total duration in milliseconds that this node will be waiting for.\n */\n private totalDuration: number | null = null;\n\n /**\n * The duration in milliseconds that this node has been waiting for.\n */\n private waitedDuration: number = 0;\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // If this node is in the READY state then we need to set the initial update time.\n if (this.is(State.READY)) {\n // Set the initial update time.\n this.initialUpdateTime = new Date().getTime();\n\n // Set the initial waited duration.\n this.waitedDuration = 0;\n\n // Are we dealing with an explicit duration or will we be randomly picking a duration between the min and max duration.\n if (this.duration !== null) {\n this.totalDuration = this.duration;\n } else if (this.durationMin !== null && this.durationMax !== null) {\n // We will be picking a random duration between a min and max duration, if the optional 'random' behaviour tree\n // function option is defined then we will be using that, otherwise we will fall back to using Math.random.\n const random = typeof options.random === \"function\" ? options.random : Math.random;\n\n // Pick a random duration between a min and max duration.\n this.totalDuration = Math.floor(\n random() * (this.durationMax - this.durationMin + 1) + this.durationMin\n );\n } else {\n this.totalDuration = null;\n }\n\n // The node is now running until we finish waiting.\n this.setState(State.RUNNING);\n }\n\n // If we have no total duration then this wait node will wait indefinitely until it is aborted.\n if (this.totalDuration === null) {\n return;\n }\n\n // If we have a 'getDeltaTime' function defined as part of our options then we will use it to figure out how long we have waited for.\n if (typeof options.getDeltaTime === \"function\") {\n // Get the delta time.\n const deltaTime = options.getDeltaTime();\n\n // Our delta time must be a valid number and cannot be NaN.\n if (typeof deltaTime !== \"number\" || isNaN(deltaTime)) {\n throw new Error(\"The delta time must be a valid number and not NaN.\");\n }\n\n // Update the amount of time that this node has been waiting for based on the delta time.\n this.waitedDuration += deltaTime * 1000;\n } else {\n // We are not using a delta time, so we will just work out hom much time has passed since the first update.\n this.waitedDuration = new Date().getTime() - this.initialUpdateTime;\n }\n\n // Have we waited long enough?\n if (this.waitedDuration >= this.totalDuration) {\n // We have finished waiting!\n this.setState(State.SUCCEEDED);\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => {\n if (this.duration !== null) {\n return `WAIT ${this.duration}ms`;\n } else if (this.durationMin !== null && this.durationMax !== null) {\n return `WAIT ${this.durationMin}ms-${this.durationMax}ms`;\n } else {\n return \"WAIT\";\n }\n };\n}\n", "import Node from \"../Node\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\n\n/**\n * A decorator node that wraps a single child node.\n */\nexport default abstract class Decorator extends Node {\n /**\n * @param type The node type.\n * @param attributes The node attributes.\n * @param child The child node.\n */\n constructor(type: string, attributes: Attribute[], protected child: Node) {\n super(type, attributes, []);\n }\n\n /**\n * Gets whether this node is a leaf node.\n */\n isLeafNode = () => false;\n\n /**\n * Gets the children of this node.\n */\n getChildren = () => [this.child];\n\n /**\n * Reset the state of the node.\n */\n reset = () => {\n // Reset the state of this node.\n this.setState(State.READY);\n\n // Reset the state of the child node.\n this.child.reset();\n };\n\n /**\n * Abort the running of this node.\n * @param agent The agent.\n */\n abort = (agent: Agent) => {\n // There is nothing to do if this node is not in the running state.\n if (!this.is(State.RUNNING)) {\n return;\n }\n\n // Abort the child node.\n this.child.abort(agent);\n\n // Reset the state of this node.\n this.reset();\n\n this.getAttribute(\"exit\")?.callAgentFunction(agent, false, true);\n };\n}\n", "import Node from \"../Node\";\nimport Decorator from \"./Decorator\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A Root node.\n * The root node will have a single child.\n */\nexport default class Root extends Decorator {\n /**\n * @param attributes The node attributes.\n * @param child The child node.\n */\n constructor(attributes: Attribute[], child: Node) {\n super(\"root\", attributes, child);\n }\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // If the child has never been updated or is running then we will need to update it now.\n if (this.child.getState() === State.READY || this.child.getState() === State.RUNNING) {\n // Update the child of this node.\n this.child.update(agent, options);\n }\n\n // The state of the root node is the state of its child.\n this.setState(this.child.getState());\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => \"ROOT\";\n}\n", "import Node from \"../Node\";\nimport Decorator from \"./Decorator\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A REPEAT node.\n * The node has a single child which can have:\n * -- A number of iterations for which to repeat the child node.\n * -- An infinite repeat loop if neither an iteration count or a condition function is defined.\n * The REPEAT node will stop and have a 'FAILED' state if its child is ever in a 'FAILED' state after an update.\n * The REPEAT node will attempt to move on to the next iteration if its child is ever in a 'SUCCEEDED' state.\n */\nexport default class Repeat extends Decorator {\n /**\n * @param attributes The node attributes.\n * @param iterations The number of iterations to repeat the child node.\n * @param iterationsMin The minimum possible number of iterations to repeat the child node.\n * @param iterationsMax The maximum possible number of iterations to repeat the child node.\n * @param child The child node.\n */\n constructor(\n attributes: Attribute[],\n private iterations: number | null,\n private iterationsMin: number | null,\n private iterationsMax: number | null,\n child: Node\n ) {\n super(\"repeat\", attributes, child);\n }\n\n /**\n * The number of target iterations to make.\n */\n private targetIterationCount: number | null = null;\n\n /**\n * The current iteration count.\n */\n private currentIterationCount: number = 0;\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // If this node is in the READY state then we need to reset the child and the target iteration count.\n if (this.is(State.READY)) {\n // Reset the child node.\n this.child.reset();\n\n // Reset the current iteration count.\n this.currentIterationCount = 0;\n\n // Set the target iteration count.\n this.setTargetIterationCount(options);\n }\n\n // Do a check to see if we can iterate. If we can then this node will move into the 'RUNNING' state.\n // If we cannot iterate then we have hit our target iteration count, which means that the node has succeeded.\n if (this.canIterate()) {\n // This node is in the running state and can do its initial iteration.\n this.setState(State.RUNNING);\n\n // We may have already completed an iteration, meaning that the child node will be in the SUCCEEDED state.\n // If this is the case then we will have to reset the child node now.\n if (this.child.getState() === State.SUCCEEDED) {\n this.child.reset();\n }\n\n // Update the child of this node.\n this.child.update(agent, options);\n\n // If the child moved into the FAILED state when we updated it then there is nothing left to do and this node has also failed.\n // If it has moved into the SUCCEEDED state then we have completed the current iteration.\n if (this.child.getState() === State.FAILED) {\n // The child has failed, meaning that this node has failed.\n this.setState(State.FAILED);\n\n return;\n } else if (this.child.getState() === State.SUCCEEDED) {\n // We have completed an iteration.\n this.currentIterationCount += 1;\n }\n } else {\n // This node is in the 'SUCCEEDED' state as we cannot iterate any more.\n this.setState(State.SUCCEEDED);\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => {\n if (this.iterations !== null) {\n return `REPEAT ${this.iterations}x`;\n } else if (this.iterationsMin !== null && this.iterationsMax !== null) {\n return `REPEAT ${this.iterationsMin}x-${this.iterationsMax}x`;\n } else {\n return \"REPEAT\";\n }\n };\n\n /**\n * Reset the state of the node.\n */\n reset = () => {\n // Reset the state of this node.\n this.setState(State.READY);\n\n // Reset the current iteration count.\n this.currentIterationCount = 0;\n\n // Reset the child node.\n this.child.reset();\n };\n\n /**\n * Gets whether an iteration can be made.\n * @returns Whether an iteration can be made.\n */\n private canIterate = () => {\n if (this.targetIterationCount !== null) {\n // We can iterate as long as we have not reached our target iteration count.\n return this.currentIterationCount < this.targetIterationCount;\n }\n\n // If neither an iteration count or a condition function were defined then we can iterate indefinitely.\n return true;\n };\n\n /**\n * Sets the target iteration count.\n * @param options The behaviour tree options object.\n */\n private setTargetIterationCount = (options: BehaviourTreeOptions) => {\n // Are we dealing with an explicit iteration count or will we be randomly picking a iteration count between the min and max iteration count.\n if (this.iterations !== null) {\n this.targetIterationCount = this.iterations;\n } else if (this.iterationsMin !== null && this.iterationsMax !== null) {\n // We will be picking a random iteration count between a min and max iteration count, if the optional 'random'\n // behaviour tree function option is defined then we will be using that, otherwise we will fall back to using Math.random.\n const random = typeof options.random === \"function\" ? options.random : Math.random;\n\n // Pick a random iteration count between a min and max iteration count.\n this.targetIterationCount = Math.floor(\n random() * (this.iterationsMax - this.iterationsMin + 1) + this.iterationsMin\n );\n } else {\n this.targetIterationCount = null;\n }\n };\n}\n", "import Node from \"../Node\";\nimport Decorator from \"./Decorator\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A RETRY node.\n * The node has a single child which can have:\n * -- A number of iterations for which to repeat the child node.\n * -- An infinite repeat loop if neither an iteration count or a condition function is defined.\n * The RETRY node will stop and have a 'SUCCEEDED' state if its child is ever in a 'SUCCEEDED' state after an update.\n * The RETRY node will attempt to move on to the next iteration if its child is ever in a 'FAILED' state.\n */\nexport default class Retry extends Decorator {\n /**\n * @param attributes The node attributes.\n * @param attempts The number of attempts to retry the child node.\n * @param attemptsMin The minimum possible number of attempts to retry the child node.\n * @param attemptsMax The maximum possible number of attempts to retry the child node.\n * @param child The child node.\n */\n constructor(\n attributes: Attribute[],\n private attempts: number | null,\n private attemptsMin: number | null,\n private attemptsMax: number | null,\n child: Node\n ) {\n super(\"retry\", attributes, child);\n }\n\n /**\n * The number of target attempts to make.\n */\n private targetAttemptCount: number | null = null;\n\n /**\n * The current attempt count.\n */\n private currentAttemptCount: number = 0;\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // If this node is in the READY state then we need to reset the child and the target attempt count.\n if (this.is(State.READY)) {\n // Reset the child node.\n this.child.reset();\n\n // Reset the current attempt count.\n this.currentAttemptCount = 0;\n\n // Set the target attempt count.\n this.setTargetAttemptCount(options);\n }\n\n // Do a check to see if we can attempt. If we can then this node will move into the 'RUNNING' state.\n // If we cannot attempt then we have hit our target attempt count, which means that the node has succeeded.\n if (this.canAttempt()) {\n // This node is in the running state and can do its initial attempt.\n this.setState(State.RUNNING);\n\n // We may have already completed an attempt, meaning that the child node will be in the FAILED state.\n // If this is the case then we will have to reset the child node now.\n if (this.child.getState() === State.FAILED) {\n this.child.reset();\n }\n\n // Update the child of this node.\n this.child.update(agent, options);\n\n // If the child moved into the SUCCEEDED state when we updated it then there is nothing left to do and this node has also succeeded.\n // If it has moved into the FAILED state then we have completed the current attempt.\n if (this.child.getState() === State.SUCCEEDED) {\n // The child has succeeded, meaning that this node has succeeded.\n this.setState(State.SUCCEEDED);\n\n return;\n } else if (this.child.getState() === State.FAILED) {\n // We have completed an attempt.\n this.currentAttemptCount += 1;\n }\n } else {\n // This node is in the 'FAILED' state as we cannot iterate any more.\n this.setState(State.FAILED);\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => {\n if (this.attempts !== null) {\n return `RETRY ${this.attempts}x`;\n } else if (this.attemptsMin !== null && this.attemptsMax !== null) {\n return `RETRY ${this.attemptsMin}x-${this.attemptsMax}x`;\n } else {\n return \"RETRY\";\n }\n };\n\n /**\n * Reset the state of the node.\n */\n reset = () => {\n // Reset the state of this node.\n this.setState(State.READY);\n\n // Reset the current attempt count.\n this.currentAttemptCount = 0;\n\n // Reset the child node.\n this.child.reset();\n };\n\n /**\n * Gets whether an attempt can be made.\n * @returns Whether an attempt can be made.\n */\n canAttempt = () => {\n if (this.targetAttemptCount !== null) {\n // We can attempt as long as we have not reached our target attempt count.\n return this.currentAttemptCount < this.targetAttemptCount;\n }\n\n // If neither an attempt count or a condition function were defined then we can attempt indefinitely.\n return true;\n };\n\n /**\n * Sets the target attempt count.\n * @param options The behaviour tree options object.\n */\n setTargetAttemptCount = (options: BehaviourTreeOptions) => {\n // Are we dealing with an explicit attempt count or will we be randomly picking an attempt count between the min and max attempt count.\n if (this.attempts !== null) {\n this.targetAttemptCount = this.attempts;\n } else if (this.attemptsMin !== null && this.attemptsMax !== null) {\n // We will be picking a random attempt count between a min and max attempt count, if the optional 'random'\n // behaviour tree function option is defined then we will be using that, otherwise we will fall back to using Math.random.\n const random = typeof options.random === \"function\" ? options.random : Math.random;\n\n // Pick a random attempt count between a min and max attempt count.\n this.targetAttemptCount = Math.floor(\n random() * (this.attemptsMax - this.attemptsMin + 1) + this.attemptsMin\n );\n } else {\n this.targetAttemptCount = null;\n }\n };\n}\n", "import Decorator from \"./Decorator\";\nimport State from \"../../State\";\nimport Node from \"../Node\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A Flip node.\n * This node wraps a single child and will flip the state of the child state.\n */\nexport default class Flip extends Decorator {\n /**\n * @param attributes The node attributes.\n * @param child The child node.\n */\n constructor(attributes: Attribute[], child: Node) {\n super(\"flip\", attributes, child);\n }\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // If the child has never been updated or is running then we will need to update it now.\n if (this.child.getState() === State.READY || this.child.getState() === State.RUNNING) {\n this.child.update(agent, options);\n }\n\n // The state of this node will depend in the state of its child.\n switch (this.child.getState()) {\n case State.RUNNING:\n this.setState(State.RUNNING);\n break;\n\n case State.SUCCEEDED:\n this.setState(State.FAILED);\n break;\n\n case State.FAILED:\n this.setState(State.SUCCEEDED);\n break;\n\n default:\n this.setState(State.READY);\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => \"FLIP\";\n}\n", "import Node from \"../Node\";\nimport Decorator from \"./Decorator\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A Succeed node.\n * This node wraps a single child and will always move to the 'SUCCEEDED' state when the child moves to a 'SUCCEEDED' or 'FAILED' state.\n */\nexport default class Succeed extends Decorator {\n /**\n * @param attributes The node attributes.\n * @param child The child node.\n */\n constructor(attributes: Attribute[], child: Node) {\n super(\"succeed\", attributes, child);\n }\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // If the child has never been updated or is running then we will need to update it now.\n if (this.child.getState() === State.READY || this.child.getState() === State.RUNNING) {\n this.child.update(agent, options);\n }\n\n // The state of this node will depend in the state of its child.\n switch (this.child.getState()) {\n case State.RUNNING:\n this.setState(State.RUNNING);\n break;\n\n case State.SUCCEEDED:\n case State.FAILED:\n this.setState(State.SUCCEEDED);\n break;\n\n default:\n this.setState(State.READY);\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => \"SUCCEED\";\n}\n", "import Node from \"../Node\";\nimport Decorator from \"./Decorator\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A Fail node.\n * This node wraps a single child and will always move to the 'FAILED' state when the child moves to a 'SUCCEEDED' or 'FAILED' state.\n */\nexport default class Fail extends Decorator {\n /**\n * @param attributes The node attributes.\n * @param child The child node.\n */\n constructor(attributes: Attribute[], child: Node) {\n super(\"fail\", attributes, child);\n }\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // If the child has never been updated or is running then we will need to update it now.\n if (this.child.getState() === State.READY || this.child.getState() === State.RUNNING) {\n this.child.update(agent, options);\n }\n\n // The state of this node will depend in the state of its child.\n switch (this.child.getState()) {\n case State.RUNNING:\n this.setState(State.RUNNING);\n break;\n\n case State.SUCCEEDED:\n case State.FAILED:\n this.setState(State.FAILED);\n break;\n\n default:\n this.setState(State.READY);\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => \"FAIL\";\n}\n", "import createLotto from \"lotto-draw\";\n\nimport Node from \"../Node\";\nimport Composite from \"./Composite\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A LOTTO node.\n * A winning child is picked on the initial update of this node, based on ticket weighting.\n * The state of this node will match the state of the winning child.\n */\nexport default class Lotto extends Composite {\n /**\n * @param attributes The node attributes.\n * @param tickets The child node tickets.\n * @param children The child nodes.\n */\n constructor(attributes: Attribute[], private tickets: number[], children: Node[]) {\n super(\"lotto\", attributes, children);\n }\n\n /**\n * The child node selected to be the active one.\n */\n private selectedChild: Node | undefined;\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // If this node is in the READY state then we need to pick a winning child node.\n if (this.is(State.READY)) {\n // Create a lotto draw with which to randomly pick a child node to become the active one.\n const lottoDraw = createLotto({\n // Hook up the optional 'random' behaviour tree function option to the one used by 'lotto-draw'.\n random: options.random,\n // Pass in each child node as a participant in the lotto draw with their respective ticket count.\n participants: this.children.map((child, index) => [child, this.tickets[index] || 1])\n });\n\n // Randomly pick a child based on ticket weighting, this will become the active child for this composite node.\n this.selectedChild = lottoDraw.draw() || undefined;\n }\n\n // If something went wrong and we don't have an active child then we should throw an error.\n if (!this.selectedChild) {\n throw new Error(\"failed to update lotto node as it has no active child\");\n }\n\n // If the selected child has never been updated or is running then we will need to update it now.\n if (this.selectedChild.getState() === State.READY || this.selectedChild.getState() === State.RUNNING) {\n this.selectedChild.update(agent, options);\n }\n\n // The state of the lotto node is the state of its selected child.\n this.setState(this.selectedChild.getState());\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => (this.tickets.length ? `LOTTO [${this.tickets.join(\",\")}]` : \"LOTTO\");\n}\n", "import Node from \"../Node\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\n\n/**\n * A composite node that wraps child nodes.\n */\nexport default abstract class Composite extends Node {\n /**\n * @param type The node type.\n * @param attributes The node attributes.\n * @param children The child nodes.\n */\n constructor(type: string, attributes: Attribute[], protected children: Node[]) {\n super(type, attributes, []);\n }\n\n /**\n * Gets whether this node is a leaf node.\n */\n isLeafNode = () => false;\n\n /**\n * Gets the children of this node.\n */\n getChildren = () => this.children;\n\n /**\n * Reset the state of the node.\n */\n reset = () => {\n // Reset the state of this node.\n this.setState(State.READY);\n\n // Reset the state of any child nodes.\n this.getChildren().forEach((child) => child.reset());\n };\n\n /**\n * Abort the running of this node.\n * @param agent The agent.\n */\n abort = (agent: Agent) => {\n // There is nothing to do if this node is not in the running state.\n if (!this.is(State.RUNNING)) {\n return;\n }\n\n // Abort any child nodes.\n this.getChildren().forEach((child) => child.abort(agent));\n\n // Reset the state of this node.\n this.reset();\n\n this.getAttribute(\"exit\")?.callAgentFunction(agent, false, true);\n };\n}\n", "import Composite from \"./Composite\";\nimport Node from \"../Node\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A SELECTOR node.\n * The child nodes are executed in sequence until one succeeds or all fail.\n */\nexport default class Selector extends Composite {\n /**\n * @param attributes The node attributes.\n * @param children The child nodes.\n */\n constructor(attributes: Attribute[], protected children: Node[]) {\n super(\"selector\", attributes, children);\n }\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // Iterate over all of the children of this node.\n for (const child of this.children) {\n // If the child has never been updated or is running then we will need to update it now.\n if (child.getState() === State.READY || child.getState() === State.RUNNING) {\n // Update the child of this node.\n child.update(agent, options);\n }\n\n // If the current child has a state of 'SUCCEEDED' then this node is also a 'SUCCEEDED' node.\n if (child.getState() === State.SUCCEEDED) {\n // This node is a 'SUCCEEDED' node.\n this.setState(State.SUCCEEDED);\n\n // There is no need to check the rest of the selector nodes.\n return;\n }\n\n // If the current child has a state of 'FAILED' then we should move on to the next child.\n if (child.getState() === State.FAILED) {\n // Find out if the current child is the last one in the selector.\n // If it is then this sequence node has also failed.\n if (this.children.indexOf(child) === this.children.length - 1) {\n // This node is a 'FAILED' node.\n this.setState(State.FAILED);\n\n // There is no need to check the rest of the selector as we have completed it.\n return;\n } else {\n // The child node failed, try the next one.\n continue;\n }\n }\n\n // The node should be in the 'RUNNING' state.\n if (child.getState() === State.RUNNING) {\n // This node is a 'RUNNING' node.\n this.setState(State.RUNNING);\n\n // There is no need to check the rest of the selector as the current child is still running.\n return;\n }\n\n // The child node was not in an expected state.\n throw new Error(\"child node was not in an expected state.\");\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => \"SELECTOR\";\n}\n", "import Composite from \"./Composite\";\nimport Node from \"../Node\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A SEQUENCE node.\n * The child nodes are executed in sequence until one fails or all succeed.\n */\nexport default class Sequence extends Composite {\n /**\n * @param attributes The node attributes.\n * @param children The child nodes.\n */\n constructor(attributes: Attribute[], protected children: Node[]) {\n super(\"sequence\", attributes, children);\n }\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // Iterate over all of the children of this node.\n for (const child of this.children) {\n // If the child has never been updated or is running then we will need to update it now.\n if (child.getState() === State.READY || child.getState() === State.RUNNING) {\n // Update the child of this node.\n child.update(agent, options);\n }\n\n // If the current child has a state of 'SUCCEEDED' then we should move on to the next child.\n if (child.getState() === State.SUCCEEDED) {\n // Find out if the current child is the last one in the sequence.\n // If it is then this sequence node has also succeeded.\n if (this.children.indexOf(child) === this.children.length - 1) {\n // This node is a 'SUCCEEDED' node.\n this.setState(State.SUCCEEDED);\n\n // There is no need to check the rest of the sequence as we have completed it.\n return;\n } else {\n // The child node succeeded, but we have not finished the sequence yet.\n continue;\n }\n }\n\n // If the current child has a state of 'FAILED' then this node is also a 'FAILED' node.\n if (child.getState() === State.FAILED) {\n // This node is a 'FAILED' node.\n this.setState(State.FAILED);\n\n // There is no need to check the rest of the sequence.\n return;\n }\n\n // The node should be in the 'RUNNING' state.\n if (child.getState() === State.RUNNING) {\n // This node is a 'RUNNING' node.\n this.setState(State.RUNNING);\n\n // There is no need to check the rest of the sequence as the current child is still running.\n return;\n }\n\n // The child node was not in an expected state.\n throw new Error(\"child node was not in an expected state.\");\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => \"SEQUENCE\";\n}\n", "import Composite from \"./Composite\";\nimport State from \"../../State\";\nimport Node from \"../Node\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A PARALLEL node.\n * The child nodes are executed concurrently until one fails or all succeed.\n */\nexport default class Parallel extends Composite {\n /**\n * @param attributes The node attributes.\n * @param children The child nodes.\n */\n constructor(attributes: Attribute[], children: Node[]) {\n super(\"parallel\", attributes, children);\n }\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // Keep a count of the number of succeeded child nodes.\n let succeededCount = 0;\n\n let hasChildFailed = false;\n\n // Iterate over all of the children of this node.\n for (const child of this.children) {\n // If the child has never been updated or is running then we will need to update it now.\n if (child.getState() === State.READY || child.getState() === State.RUNNING) {\n // Update the child of this node.\n child.update(agent, options);\n }\n\n // If the current child has a state of 'SUCCEEDED' then we should move on to the next child.\n if (child.getState() === State.SUCCEEDED) {\n // The child node has succeeded, keep track of this to determine if all children have.\n succeededCount++;\n\n // The child node succeeded, but we have not finished checking every child node yet.\n continue;\n }\n\n // If the current child has a state of 'FAILED' then this node is also a 'FAILED' node.\n if (child.getState() === State.FAILED) {\n hasChildFailed = true;\n\n // There is no need to check the rest of the children.\n break;\n }\n\n // The node should be in the 'RUNNING' state.\n if (child.getState() !== State.RUNNING) {\n // The child node was not in an expected state.\n throw new Error(\"child node was not in an expected state.\");\n }\n }\n\n if (hasChildFailed) {\n // This node is a 'FAILED' node.\n this.setState(State.FAILED);\n\n // Abort every running child.\n for (const child of this.children) {\n if (child.getState() === State.RUNNING) {\n child.abort(agent);\n }\n }\n } else {\n // If all children have succeeded then this node has also succeeded, otherwise it is still running.\n this.setState(succeededCount === this.children.length ? State.SUCCEEDED : State.RUNNING);\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => \"PARALLEL\";\n}\n", "import { AnyArgument } from \"../RootAstNodesBuilder\";\nimport Guard from \"./guards/Guard\";\n\nexport type AttributeDetails = {\n /** The attribute type. */\n type: string;\n\n /** The attribute arguments. */\n args: AnyArgument[];\n};\n\n/**\n * A base node attribute.\n */\nexport default abstract class Attribute {\n /**\n * @param type The node attribute type.\n * @param args The array of attribute argument definitions.\n */\n constructor(protected type: string, protected args: AnyArgument[]) {}\n\n /**\n * Gets the type of the attribute.\n */\n getType = () => this.type;\n\n /**\n * Gets the array of attribute argument definitions.\n */\n getArguments = () => this.args;\n\n /**\n * Gets the attribute details.\n */\n abstract getDetails(): TAttributeDetails;\n\n /**\n * Gets whether this attribute is a guard.\n */\n abstract isGuard: () => this is Guard;\n}\n", "import { Agent } from \"../../Agent\";\nimport { AnyArgument } from \"../../RootAstNodesBuilder\";\nimport Attribute, { AttributeDetails } from \"../Attribute\";\n\nexport type GuardAttributeDetails = {\n /** The name of the condition function that determines whether the guard is satisfied. */\n condition: string;\n} & AttributeDetails;\n\n/**\n * A base node guard attribute.\n */\nexport default abstract class Guard extends Attribute {\n /**\n * @param type The node attribute type.\n * @param args The array of decorator argument definitions.\n * @param condition The name of the condition function that determines whether the guard is satisfied.\n */\n constructor(type: string, args: AnyArgument[], private condition: string) {\n super(type, args);\n }\n\n /**\n * Gets the name of the condition function that determines whether the guard is satisfied.\n */\n getCondition = () => this.condition;\n\n /**\n * Gets whether this attribute is a guard.\n */\n isGuard = () => true;\n\n /**\n * Gets the attribute details.\n */\n getDetails(): GuardAttributeDetails {\n return {\n type: this.getType(),\n args: this.getArguments(),\n condition: this.getCondition()\n };\n }\n\n /**\n * Gets whether the guard is satisfied.\n * @param agent The agent.\n * @returns Whether the guard is satisfied.\n */\n abstract isSatisfied(agent: Agent): boolean;\n}\n", "import Guard from \"./Guard\";\nimport Lookup from \"../../Lookup\";\nimport { Agent } from \"../../Agent\";\nimport { AnyArgument } from \"../../RootAstNodesBuilder\";\n\n/**\n * A WHILE guard which is satisfied as long as the given condition remains true.\n */\nexport default class While extends Guard {\n /**\n * @param condition The name of the condition function that determines whether the guard is satisfied.\n * @param args The array of decorator argument definitions.\n */\n constructor(condition: string, args: AnyArgument[]) {\n super(\"while\", args, condition);\n }\n\n /**\n * Gets whether the guard is satisfied.\n * @param agent The agent.\n * @returns Whether the guard is satisfied.\n */\n isSatisfied = (agent: Agent) => {\n // Attempt to get the invoker for the condition function.\n const conditionFuncInvoker = Lookup.getFuncInvoker(agent, this.getCondition());\n\n // The condition function should be defined.\n if (conditionFuncInvoker === null) {\n throw new Error(\n `cannot evaluate node guard as the condition '${this.getCondition()}' function is not defined on the agent and has not been registered`\n );\n }\n\n // Call the condition function to determine whether this guard is satisfied.\n return !!conditionFuncInvoker(this.args);\n };\n}\n", "import Guard from \"./Guard\";\nimport Lookup from \"../../Lookup\";\nimport { Agent } from \"../../Agent\";\nimport { AnyArgument } from \"../../RootAstNodesBuilder\";\n\n/**\n * An UNTIL guard which is satisfied as long as the given condition remains false.\n */\nexport default class Until extends Guard {\n /**\n * @param condition The name of the condition function that determines whether the guard is satisfied.\n * @param args The array of decorator argument definitions.\n */\n constructor(condition: string, args: AnyArgument[]) {\n super(\"until\", args, condition);\n }\n\n /**\n * Gets whether the guard is satisfied.\n * @param agent The agent.\n * @returns Whether the guard is satisfied.\n */\n isSatisfied = (agent: Agent) => {\n // Attempt to get the invoker for the condition function.\n const conditionFuncInvoker = Lookup.getFuncInvoker(agent, this.getCondition());\n\n // The condition function should be defined.\n if (conditionFuncInvoker === null) {\n throw new Error(\n `cannot evaluate node guard as the condition '${this.getCondition()}' function is not defined on the agent and has not been registered`\n );\n }\n\n // Call the condition function to determine whether this guard is satisfied.\n return !!!conditionFuncInvoker(this.args);\n };\n}\n", "import { Agent } from \"../../Agent\";\nimport { AnyArgument } from \"../../RootAstNodesBuilder\";\nimport Attribute, { AttributeDetails } from \"../Attribute\";\n\nexport type CallbackAttributeDetails = {\n /** The name of the agent function that is called. */\n functionName: string;\n} & AttributeDetails;\n\n/**\n * A base node callback attribute.\n */\nexport default abstract class Callback extends Attribute {\n /**\n * @param type The node attribute type.\n * @param args The array of decorator argument definitions.\n * @param functionName The name of the agent function to call.\n */\n constructor(type: string, args: AnyArgument[], private functionName: string) {\n super(type, args);\n }\n\n /**\n * Gets the name of the agent function to call.\n */\n getFunctionName = () => this.functionName;\n\n /**\n * Gets whether this attribute is a guard.\n */\n isGuard = () => false;\n\n /**\n * Gets the attribute details.\n */\n getDetails(): CallbackAttributeDetails {\n return {\n type: this.getType(),\n args: this.getArguments(),\n functionName: this.getFunctionName()\n };\n }\n\n /**\n * Attempt to call the agent function that this callback refers to.\n * @param agent The agent.\n */\n abstract callAgentFunction: (agent: Agent, isSuccess: boolean, isAborted: boolean) => void;\n}\n", "import Callback from \"./Callback\";\nimport Lookup from \"../../Lookup\";\nimport { Agent } from \"../../Agent\";\nimport { AnyArgument } from \"../../RootAstNodesBuilder\";\n\n/**\n * An ENTRY callback which defines an agent function to call when the associated node is updated and moves out of running state.\n */\nexport default class Entry extends Callback {\n /**\n * @param functionName The name of the agent function to call.\n * @param args The array of callback argument definitions.\n */\n constructor(functionName: string, args: AnyArgument[]) {\n super(\"entry\", args, functionName);\n }\n\n /**\n * Attempt to call the agent function that this callback refers to.\n * @param agent The agent.\n */\n callAgentFunction = (agent: Agent) => {\n // Attempt to get the invoker for the callback function.\n const callbackFuncInvoker = Lookup.getFuncInvoker(agent, this.getFunctionName());\n\n // The callback function should be defined.\n if (callbackFuncInvoker === null) {\n throw new Error(\n `cannot call entry function '${this.getFunctionName()}' as is not defined on the agent and has not been registered`\n );\n }\n\n // Call the callback function.\n callbackFuncInvoker(this.args);\n };\n}\n", "import Callback from \"./Callback\";\nimport Lookup, { AnyExitArgument } from \"../../Lookup\";\nimport { Agent } from \"../../Agent\";\nimport { AnyArgument } from \"../../RootAstNodesBuilder\";\n\n/**\n * An EXIT callback which defines an agent function to call when the associated node is updated and moves to a finished state or is aborted.\n */\nexport default class Exit extends Callback {\n /**\n * @param functionName The name of the agent function to call.\n * @param args The array of callback argument definitions.\n */\n constructor(functionName: string, args: AnyArgument[]) {\n super(\"exit\", args, functionName);\n }\n\n /**\n * Attempt to call the agent function that this callback refers to.\n * @param agent The agent.\n * @param isSuccess Whether the decorated node was left with a success state.\n * @param isAborted Whether the decorated node was aborted.\n */\n callAgentFunction = (agent: Agent, isSuccess: boolean, isAborted: boolean) => {\n // Attempt to get the invoker for the callback function.\n const callbackFuncInvoker = Lookup.getFuncInvoker(agent, this.getFunctionName());\n\n // The callback function should be defined.\n if (callbackFuncInvoker === null) {\n throw new Error(\n `cannot call exit function '${this.getFunctionName()}' as is not defined on the agent and has not been registered`\n );\n }\n\n // Call the callback function\n callbackFuncInvoker([{ value: { succeeded: isSuccess, aborted: isAborted } }, ...this.args]);\n };\n}\n", "import Callback from \"./Callback\";\nimport Lookup from \"../../Lookup\";\nimport { Agent } from \"../../Agent\";\nimport { AnyArgument } from \"../../RootAstNodesBuilder\";\n\n/**\n * A STEP callback which defines an agent function to call when the associated node is updated.\n */\nexport default class Step extends Callback {\n /**\n * @param functionName The name of the agent function to call.\n * @param args The array of callback argument definitions.\n */\n constructor(functionName: string, args: AnyArgument[]) {\n super(\"step\", args, functionName);\n }\n\n /**\n * Attempt to call the agent function that this callback refers to.\n * @param agent The agent.\n */\n callAgentFunction = (agent: Agent) => {\n // Attempt to get the invoker for the callback function.\n const callbackFuncInvoker = Lookup.getFuncInvoker(agent, this.getFunctionName());\n\n // The callback function should be defined.\n if (callbackFuncInvoker === null) {\n throw new Error(\n `cannot call step function '${this.getFunctionName()}' as is not defined on the agent and has not been registered`\n );\n }\n\n // Call the callback function.\n callbackFuncInvoker(this.args);\n };\n}\n", "import Action from \"./nodes/leaf/Action\";\nimport Condition from \"./nodes/leaf/Condition\";\nimport Wait from \"./nodes/leaf/Wait\";\nimport Root from \"./nodes/decorator/Root\";\nimport Repeat from \"./nodes/decorator/Repeat\";\nimport Retry from \"./nodes/decorator/Retry\";\nimport Flip from \"./nodes/decorator/Flip\";\nimport Succeed from \"./nodes/decorator/Succeed\";\nimport Fail from \"./nodes/decorator/Fail\";\nimport Lotto from \"./nodes/composite/Lotto\";\nimport Selector from \"./nodes/composite/Selector\";\nimport Sequence from \"./nodes/composite/Sequence\";\nimport Parallel from \"./nodes/composite/Parallel\";\nimport Node from \"./nodes/Node\";\nimport While from \"./attributes/guards/While\";\nimport Until from \"./attributes/guards/Until\";\nimport Entry from \"./attributes/callbacks/Entry\";\nimport Exit from \"./attributes/callbacks/Exit\";\nimport Step from \"./attributes/callbacks/Step\";\nimport Callback from \"./attributes/callbacks/Callback\";\nimport Guard from \"./attributes/guards/Guard\";\nimport Attribute from \"./attributes/Attribute\";\nimport Composite from \"./nodes/composite/Composite\";\nimport Decorator from \"./nodes/decorator/Decorator\";\nimport Leaf from \"./nodes/leaf/Leaf\";\n\nexport type Argument = {\n value: T;\n type: string; // Used for validation.\n};\ntype NullArgument = Argument & {\n type: \"null\";\n};\ntype BooleanArgument = Argument & {\n type: \"boolean\";\n};\ntype NumberArgument = Argument & {\n type: \"number\";\n isInteger: boolean; // Used for validation.\n};\ntype StringPlaceholderArgument = Argument & {\n type: \"string\";\n};\ntype IdentifierArgument = Argument & {\n type: \"identifier\";\n};\nexport type AnyArgument =\n | NullArgument\n | BooleanArgument\n | NumberArgument\n | StringPlaceholderArgument\n | IdentifierArgument;\n\n/**\n * The node attribute factories.\n */\nconst AttributeFactories: {\n [key: string]: (functionName: string, attributeArguments: AnyArgument[]) => Callback | Guard;\n} = {\n WHILE: (condition: string, attributeArguments: AnyArgument[]) => new While(condition, attributeArguments),\n UNTIL: (condition: string, attributeArguments: AnyArgument[]) => new Until(condition, attributeArguments),\n ENTRY: (functionName: string, attributeArguments: AnyArgument[]) => new Entry(functionName, attributeArguments),\n EXIT: (functionName: string, attributeArguments: AnyArgument[]) => new Exit(functionName, attributeArguments),\n STEP: (functionName: string, attributeArguments: AnyArgument[]) => new Step(functionName, attributeArguments)\n};\n\ntype Validatable = {\n children?: AstNode[];\n validate: (depth: number) => void;\n};\n\ntype NodeInstanceCreator = (\n namedRootNodeProvider: (name: string) => RootAstNode,\n visitedBranches: string[]\n) => T;\n\nexport type AstNode = Validatable & {\n type: string;\n createNodeInstance: NodeInstanceCreator;\n};\n\nexport type LeafAstNode = AstNode & {\n type: \"action\" | \"condition\" | \"wait\";\n attributes: Attribute[];\n};\n\nexport type CompositeAstNode = AstNode & {\n type: \"lotto\" | \"parallel\" | \"selector\" | \"sequence\";\n attributes: Attribute[];\n children: AstNode[];\n};\n\nexport type DecoratorAstNode = AstNode & {\n type: \"fail\" | \"flip\" | \"repeat\" | \"retry\" | \"root\" | \"succeed\";\n attributes: Attribute[];\n children: AstNode[];\n};\n\nexport type BranchAstNode = AstNode & {\n type: \"branch\";\n branchName: \"\" | string;\n};\n\nexport type LottoAstNode = CompositeAstNode & {\n type: \"lotto\";\n tickets: number[];\n};\n\nexport type RootAstNode = DecoratorAstNode & {\n type: \"root\";\n name: null | string;\n};\n\nexport type RepeatAstNode = DecoratorAstNode & {\n type: \"repeat\";\n iterations: number | null;\n iterationsMin: number | null;\n iterationsMax: number | null;\n};\n\nexport type RetryAstNode = DecoratorAstNode & {\n type: \"retry\";\n attempts: number | null;\n attemptsMin: number | null;\n attemptsMax: number | null;\n};\n\nexport type ActionAstNode = LeafAstNode & {\n type: \"action\";\n actionName: string;\n actionArguments: AnyArgument[];\n};\n\nexport type ConditionAstNode = LeafAstNode & {\n type: \"condition\";\n conditionName: string;\n conditionArguments: AnyArgument[];\n};\n\nexport type WaitAstNode = LeafAstNode & {\n type: \"wait\";\n duration: number | null;\n durationMin: number | null;\n durationMax: number | null;\n};\n\nexport type AnyAstNode =\n | BranchAstNode\n | CompositeAstNode\n | LottoAstNode\n | DecoratorAstNode\n | RootAstNode\n | RepeatAstNode\n | RetryAstNode\n | LeafAstNode\n | ActionAstNode\n | ConditionAstNode\n | WaitAstNode;\n\n/**\n * The AST node factories.\n */\nconst ASTNodeFactories = {\n ROOT: (): RootAstNode => ({\n type: \"root\",\n attributes: [],\n name: null,\n children: [],\n validate(depth: number) {\n // A root node cannot be the child of another node.\n if (depth > 1) {\n throw new Error(\"a root node cannot be the child of another node\");\n }\n\n // A root node must have a single child node.\n if (this.children.length !== 1) {\n throw new Error(\"a root node must have a single child\");\n }\n },\n createNodeInstance(namedRootNodeProvider, visitedBranches) {\n return new Root(\n this.attributes,\n this.children![0].createNodeInstance(namedRootNodeProvider, visitedBranches.slice())\n );\n }\n }),\n BRANCH: (): BranchAstNode => ({\n type: \"branch\",\n branchName: \"\",\n validate() {},\n createNodeInstance(namedRootNodeProvider, visitedBranches) {\n // Try to find the root node with a matching branch name.\n const targetRootNode = namedRootNodeProvider(this.branchName);\n\n // If we have already visited this branch then we have a circular dependency.\n if (visitedBranches.indexOf(this.branchName) !== -1) {\n throw new Error(`circular dependency found in branch node references for branch '${this.branchName}'`);\n }\n\n // If we have a target root node, then the node instance we want will be the first and only child of the referenced root node.\n if (targetRootNode) {\n return targetRootNode\n .createNodeInstance(namedRootNodeProvider, visitedBranches.concat(this.branchName))\n .getChildren()[0];\n } else {\n throw new Error(`branch references root node '${this.branchName}' which has not been defined`);\n }\n }\n }),\n SELECTOR: (): CompositeAstNode => ({\n type: \"selector\",\n attributes: [],\n children: [],\n validate() {\n // A selector node must have at least a single node.\n if (this.children.length < 1) {\n throw new Error(\"a selector node must have at least a single child\");\n }\n },\n createNodeInstance(namedRootNodeProvider, visitedBranches) {\n return new Selector(\n this.attributes,\n this.children.map((child) => child.createNodeInstance(namedRootNodeProvider, visitedBranches.slice()))\n );\n }\n }),\n SEQUENCE: (): CompositeAstNode => ({\n type: \"sequence\",\n attributes: [],\n children: [],\n validate() {\n // A sequence node must have at least a single node.\n if (this.children.length < 1) {\n throw new Error(\"a sequence node must have at least a single child\");\n }\n },\n createNodeInstance(namedRootNodeProvider, visitedBranches) {\n return new Sequence(\n this.attributes,\n this.children.map((child) => child.createNodeInstance(namedRootNodeProvider, visitedBranches.slice()))\n );\n }\n }),\n PARALLEL: (): CompositeAstNode => ({\n type: \"parallel\",\n attributes: [],\n children: [],\n validate() {\n // A parallel node must have at least a single node.\n if (this.children.length < 1) {\n throw new Error(\"a parallel node must have at least a single child\");\n }\n },\n createNodeInstance(namedRootNodeProvider, visitedBranches) {\n return new Parallel(\n this.attributes,\n this.children.map((child) => child.createNodeInstance(namedRootNodeProvider, visitedBranches.slice()))\n );\n }\n }),\n LOTTO: (): LottoAstNode => ({\n type: \"lotto\",\n attributes: [],\n children: [],\n tickets: [],\n validate() {\n // A lotto node must have at least a single node.\n if (this.children!.length < 1) {\n throw new Error(\"a lotto node must have at least a single child\");\n }\n },\n createNodeInstance(namedRootNodeProvider, visitedBranches) {\n return new Lotto(\n this.attributes,\n this.tickets!,\n this.children!.map((child) => child.createNodeInstance(namedRootNodeProvider, visitedBranches.slice()))\n );\n }\n }),\n REPEAT: (): RepeatAstNode => ({\n type: \"repeat\",\n attributes: [],\n iterations: null,\n iterationsMin: null,\n iterationsMax: null,\n children: [],\n validate() {\n // A repeat node must have a single node.\n if (this.children!.length !== 1) {\n throw new Error(\"a repeat node must have a single child\");\n }\n\n if (this.iterations !== null) {\n // A repeat node must have a positive number of iterations if defined.\n if (this.iterations < 0) {\n throw new Error(\"a repeat node must have a positive number of iterations if defined\");\n }\n } else if (this.iterationsMin !== null && this.iterationsMax !== null) {\n // A repeat node must have a positive min and max iteration count if they are defined.\n if (this.iterationsMin < 0 || this.iterationsMax < 0) {\n throw new Error(\n \"a repeat node must have a positive minimum and maximum iteration count if defined\"\n );\n }\n\n // A repeat node must not have an minimum iteration count that exceeds the maximum iteration count.\n if (this.iterationsMin > this.iterationsMax) {\n throw new Error(\n \"a repeat node must not have a minimum iteration count that exceeds the maximum iteration count\"\n );\n }\n } else {\n // If we have no explicit iteration count or a minimum and maximum iteration count set then we are dealing with a repeat node that iterates indefinitely.\n }\n },\n createNodeInstance(namedRootNodeProvider, visitedBranches) {\n return new Repeat(\n this.attributes,\n this.iterations,\n this.iterationsMin,\n this.iterationsMax,\n this.children![0].createNodeInstance(namedRootNodeProvider, visitedBranches.slice())\n );\n }\n }),\n RETRY: (): RetryAstNode => ({\n type: \"retry\",\n attributes: [],\n attempts: null,\n attemptsMin: null,\n attemptsMax: null,\n children: [],\n validate() {\n // A retry node must have a single node.\n if (this.children!.length !== 1) {\n throw new Error(\"a retry node must have a single child\");\n }\n\n if (this.attempts !== null) {\n // A retry node must have a positive number of attempts if defined.\n if (this.attempts < 0) {\n throw new Error(\"a retry node must have a positive number of attempts if defined\");\n }\n } else if (this.attemptsMin !== null && this.attemptsMax !== null) {\n // A retry node must have a positive min and max attempts count if they are defined.\n if (this.attemptsMin < 0 || this.attemptsMax < 0) {\n throw new Error(\"a retry node must have a positive minimum and maximum attempt count if defined\");\n }\n\n // A retry node must not have a minimum attempt count that exceeds the maximum attempt count.\n if (this.attemptsMin > this.attemptsMax) {\n throw new Error(\n \"a retry node must not have a minimum attempt count that exceeds the maximum attempt count\"\n );\n }\n } else {\n // If we have no explicit attempt count or a minimum and maximum attempt count set then we are dealing with a retry node that attempts indefinitely.\n }\n },\n createNodeInstance(namedRootNodeProvider, visitedBranches) {\n return new Retry(\n this.attributes,\n this.attempts,\n this.attemptsMin,\n this.attemptsMax,\n this.children![0].createNodeInstance(namedRootNodeProvider, visitedBranches.slice())\n );\n }\n }),\n FLIP: (): DecoratorAstNode => ({\n type: \"flip\",\n attributes: [],\n children: [],\n validate() {\n // A flip node must have a single node.\n if (this.children!.length !== 1) {\n throw new Error(\"a flip node must have a single child\");\n }\n },\n createNodeInstance(namedRootNodeProvider, visitedBranches) {\n return new Flip(\n this.attributes,\n this.children![0].createNodeInstance(namedRootNodeProvider, visitedBranches.slice())\n );\n }\n }),\n SUCCEED: (): DecoratorAstNode => ({\n type: \"succeed\",\n attributes: [],\n children: [],\n validate() {\n // A succeed node must have a single node.\n if (this.children!.length !== 1) {\n throw new Error(\"a succeed node must have a single child\");\n }\n },\n createNodeInstance(namedRootNodeProvider, visitedBranches) {\n return new Succeed(\n this.attributes,\n this.children![0].createNodeInstance(namedRootNodeProvider, visitedBranches.slice())\n );\n }\n }),\n FAIL: (): DecoratorAstNode => ({\n type: \"fail\",\n attributes: [],\n children: [],\n validate() {\n // A fail node must have a single node.\n if (this.children!.length !== 1) {\n throw new Error(\"a fail node must have a single child\");\n }\n },\n createNodeInstance(namedRootNodeProvider, visitedBranches) {\n return new Fail(\n this.attributes,\n this.children![0].createNodeInstance(namedRootNodeProvider, visitedBranches.slice())\n );\n }\n }),\n WAIT: (): WaitAstNode => ({\n type: \"wait\",\n attributes: [],\n duration: null,\n durationMin: null,\n durationMax: null,\n validate() {\n if (this.duration !== null) {\n // If an explict duration was defined then it must be a positive number.\n if (this.duration < 0) {\n throw new Error(\"a wait node must have a positive duration\");\n }\n } else if (this.durationMin !== null && this.durationMax !== null) {\n // A wait node must have a positive min and max duration.\n if (this.durationMin < 0 || this.durationMax < 0) {\n throw new Error(\"a wait node must have a positive minimum and maximum duration\");\n }\n\n // A wait node must not have a minimum duration that exceeds the maximum duration.\n if (this.durationMin > this.durationMax) {\n throw new Error(\"a wait node must not have a minimum duration that exceeds the maximum duration\");\n }\n } else {\n // If we have no explicit duration or duration bounds set then we are dealing with a wait node that waits indefinitely.\n }\n },\n createNodeInstance() {\n return new Wait(this.attributes, this.duration, this.durationMin, this.durationMax);\n }\n }),\n ACTION: (): ActionAstNode => ({\n type: \"action\",\n attributes: [],\n actionName: \"\",\n actionArguments: [],\n validate() {},\n createNodeInstance() {\n return new Action(this.attributes, this.actionName!, this.actionArguments!);\n }\n }),\n CONDITION: (): ConditionAstNode => ({\n type: \"condition\",\n attributes: [],\n conditionName: \"\",\n conditionArguments: [],\n validate() {},\n createNodeInstance() {\n return new Condition(this.attributes, this.conditionName!, this.conditionArguments!);\n }\n })\n};\n\ntype OtherAstNodes = AstNode[];\n\n/**\n * Create an array of root AST nodes based on the given definition.\n * @param definition The definition to parse the AST nodes from.\n * @returns The base definition AST nodes.\n */\nexport default function buildRootASTNodes(definition: string): RootAstNode[] {\n // Swap out any node/attribute argument string literals with a placeholder and get a mapping of placeholders to original values as well as the processed definition.\n const { placeholders, processedDefinition } = substituteStringLiterals(definition);\n\n // Convert the processed definition (with substituted string literals) into an array of raw tokens.\n const tokens = parseTokensFromDefinition(processedDefinition);\n\n // There must be at least 3 tokens for the tree definition to be valid. 'ROOT', '{' and '}'.\n if (tokens.length < 3) {\n throw new Error(\"invalid token count\");\n }\n\n // We should have a matching number of '{' and '}' tokens. If not, then there are scopes that have not been properly closed.\n if (tokens.filter((token) => token === \"{\").length !== tokens.filter((token) => token === \"}\").length) {\n throw new Error(\"scope character mismatch\");\n }\n\n // Create a stack of node children arrays, starting with a definition scope.\n const stack: [RootAstNode[], ...OtherAstNodes[]] = [[]];\n const rootScope = stack[0];\n\n // We should keep processing the raw tokens until we run out of them.\n while (tokens.length) {\n // Grab the next token.\n const token = tokens.shift();\n\n const currentScope = stack[stack.length - 1] as OtherAstNodes;\n\n // How we create the next AST token depends on the current raw token value.\n switch (token!.toUpperCase()) {\n case \"ROOT\": {\n // Create a ROOT AST node.\n const node = ASTNodeFactories.ROOT();\n\n // Push the ROOT node into the current scope.\n rootScope.push(node);\n\n // We may have a root node name defined as an argument.\n if (tokens[0] === \"[\") {\n const rootArguments = getArguments(tokens, placeholders);\n\n // We should have only a single argument that is not an empty string for a root node, which is the root name identifier.\n if (rootArguments.length === 1 && rootArguments[0].type === \"identifier\") {\n // The root name will be the first and only node argument.\n node.name = rootArguments[0].value as string;\n } else {\n throw new Error(\"expected single root name argument\");\n }\n }\n\n // Try to pick any attributes off of the token stack.\n node.attributes = getAttributes(tokens, placeholders);\n\n popAndCheck(tokens, \"{\");\n\n // The new scope is that of the new ROOT nodes children.\n stack.push(node.children!);\n break;\n }\n\n case \"BRANCH\": {\n // Create a BRANCH AST node.\n const node = ASTNodeFactories.BRANCH();\n\n // Push the BRANCH node into the current scope.\n currentScope.push(node);\n\n // We must have arguments defined, as we require a branch name argument.\n if (tokens[0] !== \"[\") {\n throw new Error(\"expected single branch name argument\");\n }\n\n // The branch name will be defined as a node argument.\n const branchArguments = getArguments(tokens, placeholders);\n\n // We should have only a single identifer argument for a branch node, which is the branch name.\n if (branchArguments.length === 1 && branchArguments[0].type === \"identifier\") {\n // The branch name will be the first and only node argument.\n node.branchName = branchArguments[0].value as string;\n } else {\n throw new Error(\"expected single branch name argument\");\n }\n break;\n }\n\n case \"SELECTOR\": {\n // Create a SELECTOR AST node.\n const node = ASTNodeFactories.SELECTOR();\n\n // Push the SELECTOR node into the current scope.\n currentScope.push(node);\n\n // Try to pick any attributes off of the token stack.\n node.attributes = getAttributes(tokens, placeholders);\n\n popAndCheck(tokens, \"{\");\n\n // The new scope is that of the new SELECTOR nodes children.\n stack.push(node.children!);\n break;\n }\n\n case \"SEQUENCE\": {\n // Create a SEQUENCE AST node.\n const node = ASTNodeFactories.SEQUENCE();\n\n // Push the SEQUENCE node into the current scope.\n currentScope.push(node);\n\n // Try to pick any attributes off of the token stack.\n node.attributes = getAttributes(tokens, placeholders);\n\n popAndCheck(tokens, \"{\");\n\n // The new scope is that of the new SEQUENCE nodes children.\n stack.push(node.children!);\n break;\n }\n\n case \"PARALLEL\": {\n // Create a PARALLEL AST node.\n const node = ASTNodeFactories.PARALLEL();\n\n // Push the PARALLEL node into the current scope.\n currentScope.push(node);\n\n // Try to pick any attributes off of the token stack.\n node.attributes = getAttributes(tokens, placeholders);\n\n popAndCheck(tokens, \"{\");\n\n // The new scope is that of the new PARALLEL nodes children.\n stack.push(node.children!);\n break;\n }\n\n case \"LOTTO\": {\n // Create a LOTTO AST node.\n const node = ASTNodeFactories.LOTTO();\n\n // Push the LOTTO node into the current scope.\n currentScope.push(node);\n\n // If the next token is a '[' character then some ticket counts have been defined as arguments.\n if (tokens[0] === \"[\") {\n // Get the ticket count arguments, each argument must be a number.\n node.tickets = getArguments(\n tokens,\n placeholders,\n (arg) => arg.type === \"number\" && !!arg.isInteger,\n \"lotto node ticket counts must be integer values\"\n ).map((argument) => argument.value as number);\n }\n\n // Try to pick any attributes off of the token stack.\n node.attributes = getAttributes(tokens, placeholders);\n\n popAndCheck(tokens, \"{\");\n\n // The new scope is that of the new LOTTO nodes children.\n stack.push(node.children!);\n break;\n }\n\n case \"CONDITION\": {\n // Create a CONDITION AST node.\n const node = ASTNodeFactories.CONDITION();\n\n // Push the CONDITION node into the current scope.\n currentScope.push(node);\n\n // We must have arguments defined, as we require a condition function name argument.\n if (tokens[0] !== \"[\") {\n throw new Error(\"expected condition name identifier argument\");\n }\n\n // Grab the condition node arguments.\n const conditionArguments = getArguments(tokens, placeholders);\n\n // We should have at least a single identifier argument for a condition node, which is the condition function name.\n if (conditionArguments.length && conditionArguments[0].type === \"identifier\") {\n // The condition function name will be the first node argument.\n node.conditionName = conditionArguments.shift()!.value as string;\n } else {\n throw new Error(\"expected condition name identifier argument\");\n }\n\n // Only the first argument should have been an identifier, all following arguments must be string, number, boolean or null.\n conditionArguments\n .filter((arg) => arg.type === \"identifier\")\n .forEach((arg) => {\n throw new Error(\n \"invalid condition node argument value '\" +\n arg.value +\n \"', must be string, number, boolean or null\"\n );\n });\n\n // Any node arguments that follow the condition name identifier will be treated as condition function arguments.\n node.conditionArguments = conditionArguments;\n\n // Try to pick any attributes off of the token stack.\n node.attributes = getAttributes(tokens, placeholders);\n break;\n }\n\n case \"FLIP\": {\n // Create a FLIP AST node.\n const node = ASTNodeFactories.FLIP();\n\n // Push the Flip node into the current scope.\n currentScope.push(node);\n\n // Try to pick any attributes off of the token stack.\n node.attributes = getAttributes(tokens, placeholders);\n\n popAndCheck(tokens, \"{\");\n\n // The new scope is that of the new FLIP nodes children.\n stack.push(node.children!);\n break;\n }\n\n case \"SUCCEED\": {\n // Create a SUCCEED AST node.\n const node = ASTNodeFactories.SUCCEED();\n\n // Push the Succeed node into the current scope.\n currentScope.push(node);\n\n // Try to pick any attributes off of the token stack.\n node.attributes = getAttributes(tokens, placeholders);\n\n popAndCheck(tokens, \"{\");\n\n // The new scope is that of the new Succeed nodes children.\n stack.push(node.children!);\n break;\n }\n\n case \"FAIL\": {\n // Create a FAIL AST node.\n const node = ASTNodeFactories.FAIL();\n\n // Push the Fail node into the current scope.\n currentScope.push(node);\n\n // Try to pick any attributes off of the token stack.\n node.attributes = getAttributes(tokens, placeholders);\n\n popAndCheck(tokens, \"{\");\n\n // The new scope is that of the new Fail nodes children.\n stack.push(node.children!);\n break;\n }\n\n case \"WAIT\": {\n // Create a WAIT AST node.\n const node = ASTNodeFactories.WAIT();\n\n // Push the WAIT node into the current scope.\n currentScope.push(node);\n\n // The arguments of a wait node are optional. We may have:\n // - No node arguments, in which case the wait will be indefinite until it is aborted.\n // - One node argument which will be the explicit duration of the wait.\n // - Two node arguments which define the min and max duration bounds from which a random duration will be picked.\n if (tokens[0] === \"[\") {\n // Get the optional duration and longest duration of the wait.\n const nodeArguments = getArguments(\n tokens,\n placeholders,\n (arg) => arg.type === \"number\" && !!arg.isInteger,\n \"wait node durations must be integer values\"\n ).map((argument) => argument.value);\n\n // We may have:\n // - One node argument which will be the explicit duration of the wait.\n // - Two node arguments which define the min and max duration bounds from which a random duration will be picked.\n // - Too many arguments, which is not valid.\n if (nodeArguments.length === 1) {\n // An explicit duration was defined.\n node.duration = nodeArguments[0] as number;\n } else if (nodeArguments.length === 2) {\n // Min and max duration bounds were defined from which a random duration will be picked.\n node.durationMin = nodeArguments[0] as number;\n node.durationMax = nodeArguments[1] as number;\n } else if (nodeArguments.length > 2) {\n // An incorrect number of durations was defined.\n throw new Error(\"invalid number of wait node duration arguments defined\");\n }\n }\n\n // Try to pick any attributes off of the token stack.\n node.attributes = getAttributes(tokens, placeholders);\n break;\n }\n\n case \"REPEAT\": {\n // Create a REPEAT AST node.\n const node = ASTNodeFactories.REPEAT();\n\n // Push the REPEAT node into the current scope.\n currentScope.push(node);\n\n // The arguments of a repeat node are optional. We may have:\n // - No node arguments, in which case the repeat note will iterate indefinitely.\n // - One node argument which will be the explicit number of iterations to make.\n // - Two node arguments which define the min and max iteration bounds from which a random iteration count will be picked.\n if (tokens[0] === \"[\") {\n // An iteration count has been defined. Get the iteration and potential maximum iteration of the wait.\n const nodeArguments = getArguments(\n tokens,\n placeholders,\n (arg) => arg.type === \"number\" && !!arg.isInteger,\n \"repeat node iteration counts must be integer values\"\n ).map((argument) => argument.value);\n\n // We should have got one or two iteration counts.\n if (nodeArguments.length === 1) {\n // A static iteration count was defined.\n node.iterations = nodeArguments[0] as number;\n } else if (nodeArguments.length === 2) {\n // A minimum and maximum iteration count was defined.\n node.iterationsMin = nodeArguments[0] as number;\n node.iterationsMax = nodeArguments[1] as number;\n } else {\n // An incorrect number of iteration counts was defined.\n throw new Error(\"invalid number of repeat node iteration count arguments defined\");\n }\n }\n\n // Try to pick any attributes off of the token stack.\n node.attributes = getAttributes(tokens, placeholders);\n\n popAndCheck(tokens, \"{\");\n\n // The new scope is that of the new REPEAT nodes children.\n stack.push(node.children!);\n break;\n }\n\n case \"RETRY\": {\n // Create a RETRY AST node.\n const node = ASTNodeFactories.RETRY();\n\n // Push the RETRY node into the current scope.\n currentScope.push(node);\n\n // The arguments of a retry node are optional. We may have:\n // - No node arguments, in which case the retry note will attempt indefinitely.\n // - One node argument which will be the explicit number of attempts to make.\n // - Two node arguments which define the min and max attempt bounds from which a random attempt count will be picked.\n if (tokens[0] === \"[\") {\n // An attempt count has been defined. Get the attempt count and potential maximum attempt count of the wait.\n const nodeArguments = getArguments(\n tokens,\n placeholders,\n (arg) => arg.type === \"number\" && !!arg.isInteger,\n \"retry node attempt counts must be integer values\"\n ).map((argument) => argument.value);\n\n // We should have got one or two attempt counts.\n if (nodeArguments.length === 1) {\n // A static attempt count was defined.\n node.attempts = nodeArguments[0] as number;\n } else if (nodeArguments.length === 2) {\n // A minimum and maximum attempt count was defined.\n node.attemptsMin = nodeArguments[0] as number;\n node.attemptsMax = nodeArguments[1] as number;\n } else {\n // An incorrect number of attempt counts was defined.\n throw new Error(\"invalid number of retry node attempt count arguments defined\");\n }\n }\n\n // Try to pick any attributes off of the token stack.\n node.attributes = getAttributes(tokens, placeholders);\n\n popAndCheck(tokens, \"{\");\n\n // The new scope is that of the new RETRY nodes children.\n stack.push(node.children!);\n break;\n }\n\n case \"ACTION\": {\n // Create a ACTION AST node.\n const node = ASTNodeFactories.ACTION();\n\n // Push the ACTION node into the current scope.\n currentScope.push(node);\n\n // We must have arguments defined, as we require an action name argument.\n if (tokens[0] !== \"[\") {\n throw new Error(\"expected action name identifier argument\");\n }\n\n // The action name will be defined as a node argument.\n const actionArguments = getArguments(tokens, placeholders);\n\n // We should have at least one identifer argument for an action node, which is the action name.\n if (actionArguments.length && actionArguments[0].type === \"identifier\") {\n // The action name will be the first and only node argument.\n node.actionName = actionArguments.shift()!.value as string;\n } else {\n throw new Error(\"expected action name identifier argument\");\n }\n\n // Only the first argument should have been an identifier, all following arguments must be string, number, boolean or null.\n actionArguments\n .filter((arg) => arg.type === \"identifier\")\n .forEach((arg) => {\n throw new Error(\n \"invalid action node argument value '\" +\n arg.value +\n \"', must be string, number, boolean or null\"\n );\n });\n\n // Any node arguments that follow the action name identifier will be treated as action function arguments.\n node.actionArguments = actionArguments;\n\n // Try to pick any attributes off of the token stack.\n node.attributes = getAttributes(tokens, placeholders);\n break;\n }\n\n case \"}\": {\n // The '}' character closes the current scope.\n stack.pop();\n break;\n }\n\n default: {\n throw new Error(`unexpected token '${token}'`);\n }\n }\n }\n\n // A function to recursively validate each of the nodes in the AST.\n const validateASTNode = (node: Validatable, depth: number): void => {\n // Validate the node.\n node.validate(depth);\n\n // Validate each child of the node.\n (node.children || []).forEach((child) => validateASTNode(child, depth + 1));\n };\n\n // Start node validation from the definition root.\n validateASTNode(\n {\n children: stack[0] as RootAstNode[],\n validate(this: { children: RootAstNode[] }) {\n // We must have at least one node defined as the definition scope, which should be a root node.\n if (this.children.length === 0) {\n throw new Error(\"expected root node to have been defined\");\n }\n\n // Each node at the base of the definition scope MUST be a root node.\n for (const definitionLevelNode of this.children) {\n if (definitionLevelNode.type !== \"root\") {\n throw new Error(\"expected root node at base of definition\");\n }\n }\n\n // Exactly one root node must not have a name defined. This will be the main root, others will have to be referenced via branch nodes.\n if (this.children.filter((definitionLevelNode) => definitionLevelNode.name === null).length !== 1) {\n throw new Error(\"expected single unnamed root node at base of definition to act as main root\");\n }\n\n // No two named root nodes can have matching names.\n const rootNodeNames: string[] = [];\n for (const definitionLevelNode of this.children) {\n if (rootNodeNames.indexOf(definitionLevelNode.name!) !== -1) {\n throw new Error(`multiple root nodes found with duplicate name '${definitionLevelNode.name}'`);\n } else {\n rootNodeNames.push(definitionLevelNode.name!);\n }\n }\n }\n },\n 0\n );\n\n // Return the root AST nodes.\n return stack[0];\n}\n\n/**\n * Pop the next raw token off of the stack and throw an error if it wasn't the expected one.\n * @param tokens The array of remaining tokens.\n * @param expected An optional string or array or items, one of which must match the next popped token.\n * @returns The popped token.\n */\nfunction popAndCheck(tokens: string[], expected: string | string[]) {\n // Get and remove the next token.\n const popped = tokens.shift();\n\n // We were expecting another token.\n if (popped === undefined) {\n throw new Error(\"unexpected end of definition\");\n }\n\n // Do we have an expected token/tokens array?\n if (expected !== undefined) {\n // Check whether the popped token matches at least one of our expected items.\n var tokenMatchesExpectation = ([] as string[])\n .concat(expected)\n .some((item) => popped.toUpperCase() === item.toUpperCase());\n\n // Throw an error if the popped token didn't match any of our expected items.\n if (!tokenMatchesExpectation) {\n const expectationString = ([] as string[])\n .concat(expected)\n .map((item) => \"'\" + item + \"'\")\n .join(\" or \");\n\n throw new Error(`unexpected token found. Expected '${expectationString}' but got '${popped}'`);\n }\n }\n\n // Return the popped token.\n return popped;\n}\n\ntype StringPlaceholders = { [key: string]: string };\n\n/**\n * Pull an argument definition list off of the token stack.\n * @param tokens The array of remaining tokens.\n * @param stringArgumentPlaceholders The mapping of string literal node argument placeholders to original values.\n * @param argumentValidator The argument validator function.\n * @param validationFailedMessage The exception message to throw if argument validation fails.\n * @returns The argument definition list.\n */\nfunction getArguments(\n tokens: string[],\n stringArgumentPlaceholders: StringPlaceholders,\n argumentValidator?: (arg: AnyArgument) => boolean,\n validationFailedMessage?: string\n) {\n // Any lists of arguments will always be wrapped in '[]' for node arguments or '()' for attribute arguments.\n // We are looking for a '[' or '(' opener that wraps the argument tokens and the relevant closer.\n const closer = popAndCheck(tokens, [\"[\", \"(\"]) === \"[\" ? \"]\" : \")\";\n\n const argumentListTokens: string[] = [];\n const argumentList: AnyArgument[] = [];\n\n // Grab all tokens between the '[' and ']' or '(' and ')'.\n while (tokens.length && tokens[0] !== closer) {\n // The next token is part of our arguments list.\n argumentListTokens.push(tokens.shift()!);\n }\n\n // Validate the order of the argument tokens. Each token must either be a ',' or a single argument that satisfies the validator.\n argumentListTokens.forEach((token, index) => {\n // Get whether this token should be an actual argument.\n const shouldBeArgumentToken = !(index & 1);\n\n // If the current token should be an actual argument then validate it,otherwise it should be a ',' token.\n if (shouldBeArgumentToken) {\n // Get the argument definition.\n const argumentDefinition = getArgumentDefinition(token!, stringArgumentPlaceholders);\n\n // Try to validate the argument.\n if (argumentValidator && !argumentValidator(argumentDefinition)) {\n throw new Error(validationFailedMessage);\n }\n\n // This is a valid argument!\n argumentList.push(argumentDefinition);\n } else {\n // The current token should be a ',' token.\n if (token !== \",\") {\n throw new Error(`invalid argument list, expected ',' or ']' but got '${token}'`);\n }\n }\n });\n\n // The arguments list should terminate with a ']' or ')' token, depending on the opener.\n popAndCheck(tokens, closer);\n\n // Return the argument list.\n return argumentList;\n}\n\n/**\n * Gets an argument value definition.\n * @param token The argument token.\n * @param stringArgumentPlaceholders The mapping of string literal node argument placeholders to original values.\n * @returns An argument value definition.\n */\nfunction getArgumentDefinition(token: string, stringArgumentPlaceholders: StringPlaceholders): AnyArgument {\n // Check whether the token represents a null value.\n if (token === \"null\") {\n return {\n value: null,\n type: \"null\"\n } as NullArgument;\n }\n\n // Check whether the token represents a boolean value.\n if (token === \"true\" || token === \"false\") {\n return {\n value: token === \"true\",\n type: \"boolean\"\n } as BooleanArgument;\n }\n\n // Check whether the token represents a number value.\n // TODO: Relies on broken isNaN - see MDN.\n // if (!Number.isNaN(token)) {\n if (!isNaN(token as any)) {\n return {\n value: parseFloat(token),\n isInteger: parseFloat(token) === parseInt(token, 10),\n type: \"number\"\n } as NumberArgument;\n }\n\n // Check whether the token is a placeholder (e.g. @@0@@) representing a string literal.\n if (token.match(/^@@\\d+@@$/g)) {\n return {\n value: stringArgumentPlaceholders[token].replace('\\\\\"', '\"'),\n type: \"string\"\n } as StringPlaceholderArgument;\n }\n\n // The only remaining option is that the argument value is an identifier.\n return {\n value: token,\n type: \"identifier\"\n } as IdentifierArgument;\n}\n\n/**\n * Pull any attributes off of the token stack.\n * @param tokens The array of remaining tokens.\n * @param stringArgumentPlaceholders The mapping of string literal node argument placeholders to original values.\n * @returns An array of attributes defined by any directly following tokens.\n */\nfunction getAttributes(tokens: string[], stringArgumentPlaceholders: StringPlaceholders) {\n // Create an array to hold any attributes found.\n const attributes: Attribute[] = [];\n\n // Keep track of names of attribute that we have found on the token stack, as we cannot have duplicates.\n const attributesFound: string[] = [];\n\n // Try to get the attribute factory for the next token.\n let attributeFactory = AttributeFactories[(tokens[0] || \"\").toUpperCase()];\n\n // Pull attribute tokens off of the tokens stack until we have no more.\n while (attributeFactory) {\n // Check to make sure that we have not already created a attribute of this type for this node.\n if (attributesFound.indexOf(tokens[0].toUpperCase()) !== -1) {\n throw new Error(`duplicate attribute '${tokens[0].toUpperCase()}' found for node`);\n }\n\n // Add the current attribute type to our array of found attributes.\n attributesFound.push(tokens.shift()!.toUpperCase());\n\n // Grab any attribute arguments.\n const attributeArguments = getArguments(tokens, stringArgumentPlaceholders);\n\n // The first attribute argument has to be an identifer, this will reference an agent function.\n if (attributeArguments.length === 0 || attributeArguments[0].type !== \"identifier\") {\n throw new Error(\"expected agent function name identifier argument for attribute\");\n }\n\n // Grab the first attribute which is an identifier that will reference an agent function.\n const attributeFunctionName = attributeArguments.shift()! as IdentifierArgument;\n\n // Any remaining attribute arguments must have a type of string, number, boolean or null.\n attributeArguments\n .filter((arg) => arg.type === \"identifier\")\n .forEach((arg) => {\n throw new Error(\n \"invalid attribute argument value '\" + arg.value + \"', must be string, number, boolean or null\"\n );\n });\n\n // Create the attribute and add it to the array of attributes found.\n attributes.push(attributeFactory(attributeFunctionName.value, attributeArguments));\n\n // Try to get the next attribute name token, as there could be multiple.\n attributeFactory = AttributeFactories[(tokens[0] || \"\").toUpperCase()];\n }\n\n return attributes;\n}\n\n/**\n * Swaps out any node/attribute argument string literals with placeholders.\n * @param definition The definition.\n * @returns An object containing a mapping of placeholders to original string values as well as the processed definition string.\n */\nfunction substituteStringLiterals(definition: string): {\n placeholders: { [key: string]: string };\n processedDefinition: string;\n} {\n // Create an object to hold the mapping of placeholders to original string values.\n const placeholders: StringPlaceholders = {};\n\n // Replace any string literals wrapped with double quotes in our definition with placeholders to be processed later.\n const processedDefinition = definition.replace(/\\\"(\\\\.|[^\"\\\\])*\\\"/g, (match) => {\n var strippedMatch = match.substring(1, match.length - 1);\n var placeholder = Object.keys(placeholders).find((key) => placeholders[key] === strippedMatch);\n\n // If we have no existing string literal match then create a new placeholder.\n if (!placeholder) {\n placeholder = `@@${Object.keys(placeholders).length}@@`;\n placeholders[placeholder] = strippedMatch;\n }\n\n return placeholder;\n });\n\n return { placeholders, processedDefinition };\n}\n\n/**\n * Parse the tree definition into an array of raw tokens.\n * @param definition The definition.\n * @returns An array of tokens parsed from the definition.\n */\nfunction parseTokensFromDefinition(definition: string): string[] {\n // Add some space around various important characters so that they can be plucked out easier as individual tokens.\n definition = definition.replace(/\\(/g, \" ( \");\n definition = definition.replace(/\\)/g, \" ) \");\n definition = definition.replace(/\\{/g, \" { \");\n definition = definition.replace(/\\}/g, \" } \");\n definition = definition.replace(/\\]/g, \" ] \");\n definition = definition.replace(/\\[/g, \" [ \");\n definition = definition.replace(/\\,/g, \" , \");\n\n // Split the definition into raw token form and return it.\n return definition.replace(/\\s+/g, \" \").trim().split(\" \");\n}\n", "import GuardPath, { GuardPathPart } from \"./attributes/guards/GuardPath\";\nimport buildRootASTNodes, { AnyArgument, RootAstNode } from \"./RootAstNodesBuilder\";\nimport State, { AnyState } from \"./State\";\nimport Lookup from \"./Lookup\";\nimport Node from \"./nodes/Node\";\nimport Root from \"./nodes/decorator/Root\";\nimport Composite from \"./nodes/composite/Composite\";\nimport Decorator from \"./nodes/decorator/Decorator\";\nimport { Agent, GlobalFunction } from \"./Agent\";\nimport { CallbackAttributeDetails } from \"./attributes/callbacks/Callback\";\nimport { GuardAttributeDetails } from \"./attributes/guards/Guard\";\nimport { BehaviourTreeOptions } from \"./BehaviourTreeOptions\";\nimport { convertMDSLToJSON } from \"./mdsl/MDSLDefinitionParser\";\n\n// Purely for outside inspection of the tree.\nexport type FlattenedTreeNode = {\n id: string;\n type: string;\n caption: string;\n state: AnyState;\n guards: GuardAttributeDetails[];\n callbacks: CallbackAttributeDetails[];\n args: AnyArgument[];\n parentId: string | null;\n};\n\n/**\n * A representation of a behaviour tree.\n */\nexport class BehaviourTree {\n /**\n * The main root tree node.\n */\n public readonly rootNode: Root;\n\n /**\n * Creates a new instance of the BehaviourTree class.\n * @param definition The behaviour tree definition.\n * @param agent The agent instance that this behaviour tree is modelling behaviour for.\n * @param options The behaviour tree options object.\n */\n constructor(definition: string, private agent: Agent, private options: BehaviourTreeOptions = {}) {\n // The tree definition must be defined and a valid string.\n if (typeof definition !== \"string\") {\n throw new Error(\"the tree definition must be a string\");\n }\n\n // The agent must be defined and not null.\n if (typeof agent !== \"object\" || agent === null) {\n throw new Error(\"the agent must be defined and not null\");\n }\n\n // Parse the behaviour tree definition, create the populated tree of behaviour tree nodes, and get the root.\n this.rootNode = BehaviourTree._createRootNode(definition);\n }\n\n /**\n * Gets whether the tree is in the RUNNING state.\n * @returns true if the tree is in the RUNNING state, otherwise false.\n */\n isRunning() {\n return this.rootNode.getState() === State.RUNNING;\n }\n\n /**\n * Gets the current tree state of SUCCEEDED, FAILED, READY or RUNNING.\n * @returns The current tree state.\n */\n getState() {\n return this.rootNode.getState();\n }\n\n /**\n * Step the tree.\n * 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.\n * 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\n * 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.\n *\n * 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.\n */\n step() {\n // If the root node has already been stepped to completion then we need to reset it.\n if (this.rootNode.getState() === State.SUCCEEDED || this.rootNode.getState() === State.FAILED) {\n this.rootNode.reset();\n }\n\n try {\n this.rootNode.update(this.agent, this.options);\n } catch (exception) {\n throw new Error(`error stepping tree: ${(exception as Error).message}`);\n }\n }\n\n /**\n * Resets the tree from the root node outwards to each nested node, giving each a state of READY.\n */\n reset() {\n this.rootNode.reset();\n }\n\n /**\n * Gets the flattened details of every node in the tree.\n * @returns The flattened details of every node in the tree.\n */\n getFlattenedNodeDetails(): FlattenedTreeNode[] {\n // Create an empty flattened array of tree nodes.\n const flattenedTreeNodes: FlattenedTreeNode[] = [];\n\n /**\n * Helper function to process a node instance and push details into the flattened tree nodes array.\n * @param node The current node.\n * @param parentUid The UID of the node parent, or null if the node is the main root node.\n */\n const processNode = (node: Node, parentUid: string | null) => {\n // Get the guard and callback attribute details for this node.\n const guards = node\n .getAttributes()\n .filter((attribute) => attribute.isGuard())\n .map((attribute) => attribute.getDetails()) as GuardAttributeDetails[];\n const callbacks = node\n .getAttributes()\n .filter((attribute) => !attribute.isGuard())\n .map((attribute) => attribute.getDetails()) as CallbackAttributeDetails[];\n\n // Push the current node into the flattened nodes array.\n flattenedTreeNodes.push({\n id: node.getUid(),\n type: node.getType(),\n caption: node.getName(),\n state: node.getState(),\n guards,\n callbacks,\n args: node.getArguments(),\n parentId: parentUid\n });\n\n // Process each of the nodes children if it is not a leaf node.\n if (!node.isLeafNode()) {\n (node as Composite | Decorator)\n .getChildren()\n .forEach((child) => processNode(child, (node as Composite | Decorator).getUid()));\n }\n };\n\n // Convert the nested node structure into a flattened array of node details.\n processNode(this.rootNode, null);\n\n return flattenedTreeNodes;\n }\n\n /**\n * Registers the action/condition/guard/callback function or subtree with the given name.\n * @param name The name of the function or subtree to register.\n * @param value The function or subtree definition to register.\n */\n static register(name: string, value: GlobalFunction | string) {\n if (typeof value === \"function\") {\n // We are going to register a action/condition/guard/callback function.\n Lookup.setFunc(name, value);\n } else if (typeof value === \"string\") {\n // We are going to register a subtree.\n let rootASTNodes: RootAstNode[];\n\n try {\n // Try to create the behaviour tree AST based on the definition provided, this could fail if the definition is invalid.\n rootASTNodes = buildRootASTNodes(value);\n } catch (exception) {\n // There was an issue in trying to parse and build the tree definition.\n throw new Error(`error registering definition: ${(exception as Error).message}`);\n }\n\n // This function should only ever be called with a definition containing a single unnamed root node.\n if (rootASTNodes.length != 1 || rootASTNodes[0].name !== null) {\n throw new Error(\"error registering definition: expected a single unnamed root node\");\n }\n\n Lookup.setSubtree(name, rootASTNodes[0]);\n } else {\n throw new Error(\"unexpected value, expected string definition or function\");\n }\n }\n\n /**\n * Unregisters the registered action/condition/guard/callback function or subtree with the given name.\n * @param name The name of the registered action/condition/guard/callback function or subtree to unregister.\n */\n static unregister(name: string): void {\n Lookup.remove(name);\n }\n\n /**\n * Unregister all registered action/condition/guard/callback functions and subtrees.\n */\n static unregisterAll(): void {\n Lookup.empty();\n }\n\n /**\n * Parses a behaviour tree definition and creates a tree of behaviour tree nodes.\n * @param {string} definition The behaviour tree definition.\n * @returns The root behaviour tree node.\n */\n private static _createRootNode(definition: string): Root {\n // TODO Remove!\n try {\n // parseToJSON(definition);\n } catch (exception) {\n console.log(exception);\n }\n\n try {\n // Try to create the behaviour tree AST based on the definition provided, this could fail if the definition is invalid.\n const rootASTNodes = buildRootASTNodes(definition);\n\n // Create a symbol to use as the main root key in our root node mapping.\n const mainRootNodeKey = Symbol(\"__root__\");\n\n // Create a mapping of root node names to root AST tokens. The main root node will have a key of Symbol(\"__root__\").\n const rootNodeMap: { [key: string | symbol]: RootAstNode } = {};\n for (const rootASTNode of rootASTNodes) {\n rootNodeMap[rootASTNode.name === null ? mainRootNodeKey : rootASTNode.name!] = rootASTNode;\n }\n\n // Convert the AST to our actual tree and get the root node.\n const rootNode: Root = rootNodeMap[mainRootNodeKey].createNodeInstance(\n // Create a provider for named root nodes that are part of our definition or have been registered. Prioritising the former.\n (name: string): RootAstNode => (rootNodeMap[name] ? rootNodeMap[name] : Lookup.getSubtree(name)),\n []\n );\n\n // Set a guard path on every leaf of the tree to evaluate as part of its update.\n BehaviourTree._applyLeafNodeGuardPaths(rootNode);\n\n // Return the root node.\n return rootNode;\n } catch (exception) {\n // There was an issue in trying to parse and build the tree definition.\n throw new Error(`error parsing tree: ${(exception as Error).message}`);\n }\n }\n\n /**\n * Applies a guard path to every leaf of the tree to evaluate as part of each update.\n * @param rootNode The main root tree node.\n */\n private static _applyLeafNodeGuardPaths(rootNode: Root) {\n const nodePaths: Node[][] = [];\n\n const findLeafNodes = (path: Node[], node: Node) => {\n // Add the current node to the path.\n path = path.concat(node);\n\n // Check whether the current node is a leaf node.\n if (node.isLeafNode()) {\n nodePaths.push(path);\n } else {\n (node as Composite | Decorator).getChildren().forEach((child) => findLeafNodes(path, child));\n }\n };\n\n // Find all leaf node paths, starting from the root.\n findLeafNodes([], rootNode);\n\n nodePaths.forEach((path) => {\n // Each node in the current path will have to be assigned a guard path, working from the root outwards.\n for (let depth = 0; depth < path.length; depth++) {\n // Get the node in the path at the current depth.\n const currentNode = path[depth];\n\n // The node may already have been assigned a guard path, if so just skip it.\n if (currentNode.hasGuardPath()) {\n continue;\n }\n\n // Create the guard path for the current node.\n const guardPath = new GuardPath(\n path\n .slice(0, depth + 1)\n .map((node) => ({ node, guards: node.getGuardAttributes() }))\n .filter((details) => details.guards.length > 0)\n );\n\n // Assign the guard path to the current node.\n currentNode.setGuardPath(guardPath);\n }\n });\n }\n}\n"], + "mappings": "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", "names": ["Participant", "Lotto", "createLotto", "State", "createLotto", "substituteStringLiterals", "parseTokensFromDefinition", "popAndCheck", "getArgumentDefinition"] } diff --git a/src/BehaviourTreeDefinitionValidator.ts b/src/BehaviourTreeDefinitionValidator.ts index fed4baf..96a4a3b 100644 --- a/src/BehaviourTreeDefinitionValidator.ts +++ b/src/BehaviourTreeDefinitionValidator.ts @@ -22,46 +22,101 @@ export type DefinitionValidationResult = { * @returns An object representing the result of validating the given tree definition. */ export function validateDefinition(definition: any): DefinitionValidationResult { - // A helper function to create a failure validation result with the given error message. - const createFailureResult = (errorMessage: string) => ({ succeeded: false, errorMessage }); - // The definition must be defined. if (definition === null || typeof definition === "undefined") { - return createFailureResult("definition is null or undefined"); + return createValidationFailureResult("definition is null or undefined"); } - let rootNodeDefinitions: any[]; - // We are expecting a definition in one of three different forms: - // - A string which we will assume is mdsl and we will parse this to JSON before validation. + // - A string which we will assume is MDSL and we will parse this to JSON before validation. // - An array which we will assume is an array of root node definitions with at least one being the primary root node (no 'id' property) // - An object which we will assume is the primary root node and should not have an 'id' property. if (typeof definition === "string") { - try { - // The definition is a string which we can assume is mdsl, so attempt to parse it to a JSON definition in the form of an array of root node definitions. - rootNodeDefinitions = convertMDSLToJSON(definition); - } catch (error) { - // We failed to parse the JSON from the mdsl, this is likely to be the result of it not being a valid mdsl string. - return createFailureResult(`invalid mdsl: ${definition}`); - } + // The definition is a string which we can assume is MDSL, so attempt to validate it. + return validateMDSLDefinition(definition); } else if (typeof definition === "object") { // The definition will either be an array (of root node definitions) or an object (the single primary root node definition). - rootNodeDefinitions = Array.isArray(definition) ? definition : [definition]; + return validateJSONDefinition(definition); } else { - return createFailureResult(`unexpected definition type of '${typeof definition}'`); + return createValidationFailureResult(`unexpected definition type of '${typeof definition}'`); + } +} + +/** + * Validates the specified behaviour tree definition in the form of MDSL. + * @param definition The behaviour tree definition in the form of MDSL. + * @returns An object representing the result of validating the given tree definition. + */ +export function validateMDSLDefinition(definition: string): DefinitionValidationResult { + let rootNodeDefinitions; + + // The first thing the we need to do is to attempt to convert our MDSL into JSON. + try { + // The definition is a string which we can assume is MDSL, so attempt to parse it to a JSON definition in the form of an array of root node definitions. + rootNodeDefinitions = convertMDSLToJSON(definition); + } catch (error) { + // We failed to parse the JSON from the MDSL, this is likely to be the result of it not being a valid MDSL string. + return createValidationFailureResult(`invalid MDSL: ${definition}`); + } + + // Unpack all of the root node definitions into arrays of main ('id' defined) and sub ('id' not defined) root node definitions. + const mainRootNodeDefinitions = rootNodeDefinitions.filter(({ id }) => typeof id === "undefined"); + const subRootNodeDefinitions = rootNodeDefinitions.filter(({ id }) => typeof id === "string" && id.length > 0); + + // We should ALWAYS have exactly one root node definition without an 'id' property defined, which is out main root node definition. + if (mainRootNodeDefinitions.length !== 1) { + return createValidationFailureResult( + "expected single unnamed root node at base of definition to act as main root" + ); } + // We should never have duplicate 'id' properties across our sub root node definitions. + const subRootNodeIdenitifers: string[] = []; + for (const { id } of subRootNodeDefinitions) { + // Have we already come across this 'id' property value? + if (subRootNodeIdenitifers.includes(id!)) { + return createValidationFailureResult(`multiple root nodes found with duplicate name '${id}'`); + } + + subRootNodeIdenitifers.push(id!); + } + + // Check for any branch node circular depedencies. This will NOT include any globally registered subtrees. + const circularDependencyPath = findBranchCircularDependencyPath(rootNodeDefinitions); + + // If we found a circular dependency in our root node and branch node definitions then the definition is definitely not valid. + if (circularDependencyPath) { + return createValidationFailureResult( + `circular dependency found in branch node references: ${circularDependencyPath}` + ); + } + + // Our definition was valid! + return { succeeded: true }; +} + +/** + * Validates the specified behaviour tree definition in the form of JSON. + * @param definition The behaviour tree definition in the form of JSON. + * @returns An object representing the result of validating the given tree definition. + */ +export function validateJSONDefinition( + definition: RootNodeDefinition | RootNodeDefinition[] +): DefinitionValidationResult { + // The definition will either be an array (of root node definitions) or an object (the single primary root node definition). + const rootNodeDefinitions = Array.isArray(definition) ? definition : [definition]; + // Iterate over our array of root nodes and call validateNode for each, passing an initial depth of 0, wrapped in a try catch to handle validation failures. try { rootNodeDefinitions.forEach((rootNodeDefinition) => validateNode(rootNodeDefinition, 0)); } catch (error) { // Handle cases where we have caught a thrown Error and return a failure result with the error message. if (error instanceof Error) { - return createFailureResult(error.message); + return createValidationFailureResult(error.message); } // No idea what happened here! - return createFailureResult(`unexpected error: ${error}`); + return createValidationFailureResult(`unexpected error: ${error}`); } // Unpack all of the root node definitions into arrays of main ('id' defined) and sub ('id' not defined) root node definitions. @@ -70,26 +125,32 @@ export function validateDefinition(definition: any): DefinitionValidationResult // We should ALWAYS have exactly one root node definition without an 'id' property defined, which is out main root node definition. if (mainRootNodeDefinitions.length !== 1) { - return createFailureResult("expected single root node without 'id' property defined to act as main root"); + return createValidationFailureResult( + "expected single root node without 'id' property defined to act as main root" + ); } // We should never have duplicate 'id' properties across our sub root node definitions. const subRootNodeIdenitifers: string[] = []; for (const { id } of subRootNodeDefinitions) { // Have we already come across this 'id' property value? - if (subRootNodeIdenitifers.includes(id)) { - return createFailureResult(`multiple root nodes found with duplicate 'id' property value of '${id}'`); + if (subRootNodeIdenitifers.includes(id!)) { + return createValidationFailureResult( + `multiple root nodes found with duplicate 'id' property value of '${id}'` + ); } - subRootNodeIdenitifers.push(id); + subRootNodeIdenitifers.push(id!); } - // Check for any branch node circular depedencies. This will not include any globally registered subtrees. + // Check for any branch node circular depedencies. This will NOT include any globally registered subtrees. const circularDependencyPath = findBranchCircularDependencyPath(rootNodeDefinitions); // If we found a circular dependency in our root node and branch node definitions then the definition is definitely not valid. if (circularDependencyPath) { - return createFailureResult(`circular dependency found in branch node references: ${circularDependencyPath}`); + return createValidationFailureResult( + `circular dependency found in branch node references: ${circularDependencyPath}` + ); } // Our definition was valid! @@ -632,3 +693,12 @@ function validateParallelNode(definition: any, depth: number): void { // Validate the child nodes of this composite node. definition.children.forEach((child: any) => validateNode(child, depth + 1)); } + +/** + * A helper function to create a failure validation result with the given error message. + * @param errorMessage The validation failure error message. + * @returns A failure validation result with the given error message. + */ +function createValidationFailureResult(errorMessage: string): DefinitionValidationResult { + return { succeeded: false, errorMessage }; +} From 6e38ea43ba4fae0c57c85f64ac83132644e18d80 Mon Sep 17 00:00:00 2001 From: Nikolas Howard Date: Mon, 5 Feb 2024 17:35:30 +0000 Subject: [PATCH 19/48] stuff --- src/BehaviourTree.ts | 175 ++++++++++-------------- src/BehaviourTreeBuilder.ts | 121 ++++++++++++++++ src/BehaviourTreeDefinition.ts | 10 +- src/BehaviourTreeDefinitionUtilities.ts | 8 +- src/BehaviourTreeDefinitionValidator.ts | 2 +- src/Lookup.ts | 19 ++- src/mdsl/MDSLDefinitionParser.ts | 10 +- 7 files changed, 218 insertions(+), 127 deletions(-) create mode 100644 src/BehaviourTreeBuilder.ts diff --git a/src/BehaviourTree.ts b/src/BehaviourTree.ts index 48ece1b..941d605 100644 --- a/src/BehaviourTree.ts +++ b/src/BehaviourTree.ts @@ -1,16 +1,18 @@ -import GuardPath, { GuardPathPart } from "./attributes/guards/GuardPath"; -import buildRootASTNodes, { AnyArgument, RootAstNode } from "./RootAstNodesBuilder"; import State, { AnyState } from "./State"; import Lookup from "./Lookup"; import Node from "./nodes/Node"; import Root from "./nodes/decorator/Root"; import Composite from "./nodes/composite/Composite"; import Decorator from "./nodes/decorator/Decorator"; +import { AnyArgument } from "./RootAstNodesBuilder"; import { Agent, GlobalFunction } from "./Agent"; import { CallbackAttributeDetails } from "./attributes/callbacks/Callback"; import { GuardAttributeDetails } from "./attributes/guards/Guard"; import { BehaviourTreeOptions } from "./BehaviourTreeOptions"; import { convertMDSLToJSON } from "./mdsl/MDSLDefinitionParser"; +import { RootNodeDefinition } from "./BehaviourTreeDefinition"; +import { validateJSONDefinition } from "./BehaviourTreeDefinitionValidator"; +import buildRootNode from "./BehaviourTreeBuilder"; // Purely for outside inspection of the tree. export type FlattenedTreeNode = { @@ -39,10 +41,10 @@ export class BehaviourTree { * @param agent The agent instance that this behaviour tree is modelling behaviour for. * @param options The behaviour tree options object. */ - constructor(definition: string, private agent: Agent, private options: BehaviourTreeOptions = {}) { - // The tree definition must be defined and a valid string. - if (typeof definition !== "string") { - throw new Error("the tree definition must be a string"); + constructor(definition: string | RootNodeDefinition | RootNodeDefinition[], private agent: Agent, private options: BehaviourTreeOptions = {}) { + // The tree definition must be defined. + if (!definition) { + throw new Error("the tree definition must be a string ro"); } // The agent must be defined and not null. @@ -50,8 +52,13 @@ export class BehaviourTree { throw new Error("the agent must be defined and not null"); } - // Parse the behaviour tree definition, create the populated tree of behaviour tree nodes, and get the root. - this.rootNode = BehaviourTree._createRootNode(definition); + try { + // Parse the behaviour tree definition, create the populated tree of behaviour tree nodes, and get the root. + this.rootNode = this._createRootNode(definition); + } catch (exception) { + // There was an issue in trying build and populate the behaviour tree. + throw new Error(`error building tree: ${(exception as Error).message}`); + } } /** @@ -153,30 +160,61 @@ export class BehaviourTree { * @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) { + static register(name: string, value: GlobalFunction | string | RootNodeDefinition) { + // Are we going to register a action/condition/guard/callback function? if (typeof value === "function") { - // We are going to register a action/condition/guard/callback function. Lookup.setFunc(name, value); - } else if (typeof value === "string") { - // We are going to register a subtree. - let rootASTNodes: RootAstNode[]; + return; + } + + // We are not registering an action/condition/guard/callback function, so we must be registering a subtree. + if (typeof value === "string") { + let rootNodeDefinitions: RootNodeDefinition[]; + // We will assume that any string passed in will be a mdsl definition. try { - // Try to create the behaviour tree AST based on the definition provided, this could fail if the definition is invalid. - rootASTNodes = buildRootASTNodes(value); + rootNodeDefinitions = convertMDSLToJSON(value); } catch (exception) { - // There was an issue in trying to parse and build the tree definition. - throw new Error(`error registering definition: ${(exception as Error).message}`); + throw new Error(`error registering definition, invalid MDSL: ${(exception as Error).message}`); } // This function should only ever be called with a definition containing a single unnamed root node. - if (rootASTNodes.length != 1 || rootASTNodes[0].name !== null) { + if (rootNodeDefinitions.length != 1 || rootNodeDefinitions[0].id !== null) { throw new Error("error registering definition: expected a single unnamed root node"); } - Lookup.setSubtree(name, rootASTNodes[0]); + // We should validate the subtree as we don't want invalid subtrees available via the lookup. + try { + const { succeeded, errorMessage } = validateJSONDefinition(rootNodeDefinitions[0]); + + // Did our validation fail without error? + if (!succeeded) { + throw new Error(errorMessage); + } + } catch (exception) { + throw new Error(`error registering definition: ${(exception as Error).message}`); + } + + // Everything seems hunky-dory, register the subtree. + Lookup.setSubtree(name, rootNodeDefinitions[0]); + } else if (typeof value === "object" && !Array.isArray(value)) { + // We will assume that any object passed in is a root node definition. + // We should validate the subtree as we don't want invalid subtrees available via the lookup. + try { + const { succeeded, errorMessage } = validateJSONDefinition(value); + + // Did our validation fail without error? + if (!succeeded) { + throw new Error(errorMessage); + } + } catch (exception) { + throw new Error(`error registering definition: ${(exception as Error).message}`); + } + + // Everything seems hunky-dory, register the subtree. + Lookup.setSubtree(name, value); } else { - throw new Error("unexpected value, expected string definition or function"); + throw new Error("unexpected value, expected string mdsl definition, root node json definition or function"); } } @@ -196,93 +234,26 @@ export class BehaviourTree { } /** - * Parses a behaviour tree definition and creates a tree of behaviour tree nodes. - * @param {string} definition The behaviour tree definition. + * Parses a behaviour tree definition and creates a tree of behaviour tree nodes populated at a root. + * @param {string | RootNodeDefinition | RootNodeDefinition[]} definition The behaviour tree definition. * @returns The root behaviour tree node. */ - private static _createRootNode(definition: string): Root { - // TODO Remove! - try { - // parseToJSON(definition); - } catch (exception) { - console.log(exception); - } - - try { - // Try to create the behaviour tree AST based on the definition provided, this could fail if the definition is invalid. - const rootASTNodes = buildRootASTNodes(definition); - - // Create a symbol to use as the main root key in our root node mapping. - const mainRootNodeKey = Symbol("__root__"); + private _createRootNode(definition: string | RootNodeDefinition | RootNodeDefinition[]): Root { + let resolvedDefinition: RootNodeDefinition | RootNodeDefinition[] - // Create a mapping of root node names to root AST tokens. The main root node will have a key of Symbol("__root__"). - const rootNodeMap: { [key: string | symbol]: RootAstNode } = {}; - for (const rootASTNode of rootASTNodes) { - rootNodeMap[rootASTNode.name === null ? mainRootNodeKey : rootASTNode.name!] = rootASTNode; + // If the definition is a string then we will assume that it is an mdsl string which needs to be converted to a JSON definition. + if (typeof definition === "string") { + try { + resolvedDefinition = convertMDSLToJSON(definition); + } catch (exception) { + throw new Error(`invalid mdsl definition: ${(exception as Error).message}`); } - - // Convert the AST to our actual tree and get the root node. - const rootNode: Root = rootNodeMap[mainRootNodeKey].createNodeInstance( - // Create a provider for named root nodes that are part of our definition or have been registered. Prioritising the former. - (name: string): RootAstNode => (rootNodeMap[name] ? rootNodeMap[name] : Lookup.getSubtree(name)), - [] - ); - - // Set a guard path on every leaf of the tree to evaluate as part of its update. - BehaviourTree._applyLeafNodeGuardPaths(rootNode); - - // Return the root node. - return rootNode; - } catch (exception) { - // There was an issue in trying to parse and build the tree definition. - throw new Error(`error parsing tree: ${(exception as Error).message}`); + } else { + // The definition is not a string, so we should assume that it is already a JSON definition. + resolvedDefinition = definition; } - } - /** - * 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(rootNode: Root) { - const nodePaths: Node[][] = []; - - const findLeafNodes = (path: Node[], node: Node) => { - // Add the current node to the path. - path = path.concat(node); - - // Check whether the current node is a leaf node. - if (node.isLeafNode()) { - nodePaths.push(path); - } else { - (node as Composite | Decorator).getChildren().forEach((child) => findLeafNodes(path, child)); - } - }; - - // Find all leaf node paths, starting from the root. - findLeafNodes([], rootNode); - - nodePaths.forEach((path) => { - // Each node in the current path will have to be assigned a guard path, working from the root outwards. - for (let depth = 0; depth < path.length; depth++) { - // Get the node in the path at the current depth. - const currentNode = path[depth]; - - // The node may already have been assigned a guard path, if so just skip it. - if (currentNode.hasGuardPath()) { - continue; - } - - // Create the guard path for the current node. - const guardPath = new GuardPath( - path - .slice(0, depth + 1) - .map((node) => ({ node, guards: node.getGuardAttributes() })) - .filter((details) => details.guards.length > 0) - ); - - // Assign the guard path to the current node. - currentNode.setGuardPath(guardPath); - } - }); + // Build and populate the root node. + return buildRootNode(Array.isArray(resolvedDefinition) ? resolvedDefinition : [resolvedDefinition]); } } diff --git a/src/BehaviourTreeBuilder.ts b/src/BehaviourTreeBuilder.ts new file mode 100644 index 0000000..6e5ff2c --- /dev/null +++ b/src/BehaviourTreeBuilder.ts @@ -0,0 +1,121 @@ + +import { AnyNodeDefinition, RootNodeDefinition } from "./BehaviourTreeDefinition"; +import { validateJSONDefinition } from "./BehaviourTreeDefinitionValidator"; +import Parallel from "./nodes/composite/Parallel"; +import Selector from "./nodes/composite/Selector"; +import Sequence from "./nodes/composite/Sequence"; +import Lotto from "./nodes/composite/Lotto"; +import Fail from "./nodes/decorator/Fail"; +import Flip from "./nodes/decorator/Flip"; +import Repeat from "./nodes/decorator/Repeat"; +import Retry from "./nodes/decorator/Retry"; +import Root from "./nodes/decorator/Root"; +import Succeed from "./nodes/decorator/Succeed"; +import Action from "./nodes/leaf/Action"; +import Condition from "./nodes/leaf/Condition"; +import Wait from "./nodes/leaf/Wait"; +import Lookup from "./Lookup"; +import Attribute from "./attributes/Attribute"; +import While from "./attributes/guards/While"; + +/** + * A type representing any node instance in a behaviour tree. + */ +type AnyNode = Root | Action | Condition | Wait | Sequence | Selector | Lotto | Parallel | Repeat | Retry | Flip | Succeed | Fail; + +/** + * A type defining a mapping of root node identifiers to root node definitions. + */ +type RootNodeDefinitionMap = { [key: string | symbol]: RootNodeDefinition }; + +/** + * A symbol to use as the main root key in any root node mappings. + */ +const MAIN_ROOT_NODE_KEY = Symbol("__root__"); + +/** + * Build and populate the root nodes based on the provided definition, assuming that the definition has been validated. + * @param definition The root node definitions. + * @returns The built and populated root node definitions. + */ +export default function buildRootNode(definition: RootNodeDefinition[]): Root { + // Create a mapping of root node identifers to root node definitions, including globally registered subtree root node definitions. + const rootNodeDefinitionMap = createRootNodeDefinitionMap(definition); + + // Now that we have all of our root node definitons (those part of the tree definition and those globally registered) we should validate + // the definition. This will also double-check that we dont have any circular depdendencies in our branch -> root node references. + try { + const { succeeded, errorMessage } = validateJSONDefinition(Object.values(rootNodeDefinitionMap)); + + // Did our validation fail without error? + if (!succeeded) { + throw new Error(errorMessage); + } + } catch (exception) { + throw new Error(`root node validation failed: '${(exception as Error).message}'`); + } + + // Create our populated tree of node instances, starting with our main root node. + const rootNode = nodeFactory(rootNodeDefinitionMap[MAIN_ROOT_NODE_KEY]) as Root; + + // TODO Set a guard path on every leaf of the tree to evaluate as part of its update. (see BehaviourTree._applyLeafNodeGuardPaths) + + // We only need to return the main root node. + return rootNode; +} + +/** + * A factory function which creates a node instance based on the specified definition. + * @param definition The node definition. + * @returns A node instance based on the specified definition. + */ +function nodeFactory(definition: AnyNodeDefinition): AnyNode { + // Get the attributes for the node. + const attributes = nodeAttributesFactory(definition); + + // Create the node instance based on the definition type. + switch (definition.type) { + case "root": + return new Root(attributes, nodeFactory(definition.child)); + + // ... + + default: + throw new Error(`unexpected node type of '${definition.type}'`); + } +} + +function nodeAttributesFactory(definition: AnyNodeDefinition): Attribute[] { + const attributes: Attribute[] = []; + + if (definition.while) { + // TODO does this take args as any? We have AnyArgument type but is that just for mdsl parsing??? + // TODO Double check that validateJSONDefinition handles the args, surely they can be 'any' at this point? + attributes.push(new While(definition.while.call, definition.while.args)); + } + + return attributes; +} + +/** + * Creates a mapping of root node identifers to root node definitions, mixing in globally registered subtree root node definitions. + * @param definition The root node definitions. + * @returns A mapping of root node identifers to root node definitions, including globally registered subtree root node definitions. + */ +function createRootNodeDefinitionMap(definition: RootNodeDefinition[]): RootNodeDefinitionMap { + // Create a mapping of root node identifers to root node definitions. + const rootNodeMap: RootNodeDefinitionMap = {}; + + // Add in any registered subtree root node definitions. + for (const [name, rootNodeDefinition] of Object.entries(Lookup.getSubtrees())) { + rootNodeMap[name] = rootNodeDefinition; + } + + // Populate the map with the root node definitions that were included with the tree definition. + // We do this after adding any registered subtrees as we want these to take presedence. + for (const rootNodeDefinition of definition) { + rootNodeMap[rootNodeDefinition.id ?? MAIN_ROOT_NODE_KEY] = rootNodeDefinition; + } + + return rootNodeMap; +} \ No newline at end of file diff --git a/src/BehaviourTreeDefinition.ts b/src/BehaviourTreeDefinition.ts index 886cd34..edb42bc 100644 --- a/src/BehaviourTreeDefinition.ts +++ b/src/BehaviourTreeDefinition.ts @@ -49,7 +49,7 @@ export interface CompositeNodeDefinition extends NodeDefinition { /** * The child nodes of this composite node. */ - children: AnyChildNode[]; + children: AnyChildNodeDefinition[]; } /** @@ -59,7 +59,7 @@ export interface DecoratorNodeDefinition extends NodeDefinition { /** * The child node of this decorator node. */ - child: AnyChildNode; + child: AnyChildNodeDefinition; } /** @@ -234,9 +234,9 @@ export interface FailNodeDefinition extends DecoratorNodeDefinition { } /** - * A type defining any node type. + * A type defining any node definition. */ -export type AnyNode = +export type AnyNodeDefinition = | BranchNodeDefinition | ActionNodeDefinition | ConditionNodeDefinition @@ -255,4 +255,4 @@ export type AnyNode = /** * A type defining any node type that can be a child of composite parent node. */ -export type AnyChildNode = Exclude; +export type AnyChildNodeDefinition = Exclude; diff --git a/src/BehaviourTreeDefinitionUtilities.ts b/src/BehaviourTreeDefinitionUtilities.ts index 78212e5..165e8eb 100644 --- a/src/BehaviourTreeDefinitionUtilities.ts +++ b/src/BehaviourTreeDefinitionUtilities.ts @@ -3,7 +3,7 @@ import { RootNodeDefinition, DecoratorNodeDefinition, CompositeNodeDefinition, - AnyNode, + AnyNodeDefinition, BranchNodeDefinition } from "./BehaviourTreeDefinition"; @@ -57,10 +57,10 @@ export function isCompositeNode(node: NodeDefinition): node is CompositeNodeDefi * @param nodeDefinition The node definition to flatten. * @returns An array of all of nested node definitions. */ -export function flattenDefinition(nodeDefinition: AnyNode): AnyNode[] { - const nodes: AnyNode[] = []; +export function flattenDefinition(nodeDefinition: AnyNodeDefinition): AnyNodeDefinition[] { + const nodes: AnyNodeDefinition[] = []; - const processNode = (currentNodeDefinition: AnyNode) => { + const processNode = (currentNodeDefinition: AnyNodeDefinition) => { nodes.push(currentNodeDefinition); if (isCompositeNode(currentNodeDefinition)) { diff --git a/src/BehaviourTreeDefinitionValidator.ts b/src/BehaviourTreeDefinitionValidator.ts index 96a4a3b..4957eb2 100644 --- a/src/BehaviourTreeDefinitionValidator.ts +++ b/src/BehaviourTreeDefinitionValidator.ts @@ -163,7 +163,7 @@ export function validateJSONDefinition( * @param rootNodeDefinitions The array of root node definitions. * @returns The first circular depdendency path present in the array of root node definitions as string, or null if one doesn't exist. */ -function findBranchCircularDependencyPath(rootNodeDefinitions: RootNodeDefinition[]): string | null { +export function findBranchCircularDependencyPath(rootNodeDefinitions: RootNodeDefinition[]): string | null { // Create a mapping of root node identifiers to other root nodes that they reference via branch nodes. // Below is an example of a mapping that includes a circular dependency (root => a => b => c => a) // [{ refs: ["a", "b"] }, { id: "a", refs: ["b"] }, { id: "b", refs: ["c"] }, { id: "c", refs: ["a"] }] diff --git a/src/Lookup.ts b/src/Lookup.ts index b67b568..cd010b7 100644 --- a/src/Lookup.ts +++ b/src/Lookup.ts @@ -1,5 +1,6 @@ -import { ActionResult, Agent, ExitFunctionArg, FunctionArg, GlobalFunction } from "./Agent"; -import { AnyArgument, RootAstNode } from "./RootAstNodesBuilder"; +import { ActionResult, Agent, ExitFunctionArg, GlobalFunction } from "./Agent"; +import { RootNodeDefinition } from "./BehaviourTreeDefinition"; +import { AnyArgument } from "./RootAstNodesBuilder"; // Exit callbacks receive their own special type of argument. // There's probably stricter ways to represent this but it feels overly complex right now. @@ -17,9 +18,9 @@ export default class Lookup { */ private static functionTable: { [key: string]: GlobalFunction } = {}; /** - * The object holding any registered sub-trees keyed on tree name. + * The object holding any registered subtree root node definitions keyed on tree name. */ - private static subtreeTable: { [key: string]: RootAstNode } = {}; + private static subtreeTable: { [key: string]: RootNodeDefinition } = {}; /** * Gets the function with the specified name. @@ -68,12 +69,10 @@ export default class Lookup { } /** - * Gets the subtree with the specified name. - * @param name The name of the subtree. - * @returns The subtree with the specified name. + * Gets all registered subtree root node definitions. */ - static getSubtree(name: string): RootAstNode { - return this.subtreeTable[name]; + static getSubtrees(): { [key: string]: RootNodeDefinition } { + return this.subtreeTable; } /** @@ -81,7 +80,7 @@ export default class Lookup { * @param name The name of the subtree. * @param subtree The subtree. */ - static setSubtree(name: string, subtree: RootAstNode) { + static setSubtree(name: string, subtree: RootNodeDefinition) { this.subtreeTable[name] = subtree; } diff --git a/src/mdsl/MDSLDefinitionParser.ts b/src/mdsl/MDSLDefinitionParser.ts index 163330f..3f870b4 100644 --- a/src/mdsl/MDSLDefinitionParser.ts +++ b/src/mdsl/MDSLDefinitionParser.ts @@ -1,7 +1,7 @@ import { ActionNodeDefinition, - AnyChildNode, - AnyNode, + AnyChildNodeDefinition, + AnyNodeDefinition, BranchNodeDefinition, ConditionNodeDefinition, FailNodeDefinition, @@ -68,13 +68,13 @@ function convertTokensToJSONDefinition( // [root, lotto, sequence], // [root, selector] // ] - const treeStacks: [Partial, ...Partial[]][] = []; + const treeStacks: [Partial, ...Partial[]][] = []; // Create an array of all root node definitions that we create. const rootNodes: Partial[] = []; // A helper function used to push node definitions onto the tree stack. - const pushNode = (node: AnyNode) => { + const pushNode = (node: AnyNodeDefinition) => { // If the node is a root node then we need to create a new tree stack array with the root node at the root. if (isRootNode(node)) { // Add the root node definition to our array of all parsed root node definitions. @@ -97,7 +97,7 @@ function convertTokensToJSONDefinition( // Get the top-most node in the current tree stack, this will be a composite/decorator node // for which we will populate its children array if composite or setting its child if a decorator. - const topTreeStackTopNode = topTreeStack[topTreeStack.length - 1] as AnyNode; + const topTreeStackTopNode = topTreeStack[topTreeStack.length - 1] as AnyNodeDefinition; // If the top-most node in the current root stack is a composite or decorator // node then the current node should be added as a child of the top-most node. From d6f2c53381d4c84b2cd853f335a611d9d77894b5 Mon Sep 17 00:00:00 2001 From: Nikolas Howard Date: Tue, 6 Feb 2024 17:34:32 +0000 Subject: [PATCH 20/48] working on BehaviourTreeBuilder --- dist/Agent.d.ts | 3 + dist/BehaviourTree.d.ts | 19 +- dist/BehaviourTreeBuilder.d.ts | 8 + dist/BehaviourTreeDefinition.d.ts | 10 +- dist/BehaviourTreeDefinitionUtilities.d.ts | 4 +- dist/BehaviourTreeDefinitionValidator.d.ts | 10 +- dist/Lookup.d.ts | 23 +- dist/attributes/Attribute.d.ts | 19 +- dist/attributes/callbacks/Callback.d.ts | 3 +- dist/attributes/callbacks/Entry.d.ts | 3 +- dist/attributes/callbacks/Exit.d.ts | 3 +- dist/attributes/callbacks/Step.d.ts | 3 +- dist/attributes/guards/Guard.d.ts | 3 +- dist/attributes/guards/Until.d.ts | 3 +- dist/attributes/guards/While.d.ts | 3 +- dist/bundle.js | 1774 +++----------------- dist/bundle.js.map | 8 +- dist/index.js | 1774 +++----------------- dist/index.js.map | 8 +- dist/mdsl/MDSLNodeArgumentParser.d.ts | 32 +- dist/nodes/Node.d.ts | 11 +- dist/nodes/leaf/Action.d.ts | 7 +- dist/nodes/leaf/Condition.d.ts | 7 +- src/Agent.ts | 3 + src/BehaviourTree.ts | 20 +- src/BehaviourTreeBuilder.ts | 134 +- src/BehaviourTreeDefinitionValidator.ts | 60 +- src/DSLtoJSON.js | 268 --- src/Lookup.ts | 18 +- src/RootAstNodesBuilder.ts | 1219 -------------- src/attributes/Attribute.ts | 17 +- src/attributes/callbacks/Callback.ts | 7 +- src/attributes/callbacks/Entry.ts | 3 +- src/attributes/callbacks/Exit.ts | 5 +- src/attributes/callbacks/Step.ts | 3 +- src/attributes/guards/Guard.ts | 7 +- src/attributes/guards/Until.ts | 3 +- src/attributes/guards/While.ts | 3 +- src/mdsl/MDSLNodeArgumentParser.ts | 38 +- src/nodes/Node.ts | 12 +- src/nodes/leaf/Action.ts | 9 +- src/nodes/leaf/Condition.ts | 9 +- 42 files changed, 737 insertions(+), 4839 deletions(-) create mode 100644 dist/BehaviourTreeBuilder.d.ts delete mode 100644 src/DSLtoJSON.js delete mode 100644 src/RootAstNodesBuilder.ts diff --git a/dist/Agent.d.ts b/dist/Agent.d.ts index abde15d..bd0a3ac 100644 --- a/dist/Agent.d.ts +++ b/dist/Agent.d.ts @@ -1,4 +1,7 @@ import { CompleteState } from "./State"; +/** + * A type representing an agent that a behavior tree instance would operate on. + */ export type Agent = { [actionName: string]: AgentFunction; }; diff --git a/dist/BehaviourTree.d.ts b/dist/BehaviourTree.d.ts index 5b62d16..e31453d 100644 --- a/dist/BehaviourTree.d.ts +++ b/dist/BehaviourTree.d.ts @@ -1,10 +1,10 @@ -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"; +import { RootNodeDefinition } from "./BehaviourTreeDefinition"; export type FlattenedTreeNode = { id: string; type: string; @@ -12,7 +12,7 @@ export type FlattenedTreeNode = { state: AnyState; guards: GuardAttributeDetails[]; callbacks: CallbackAttributeDetails[]; - args: AnyArgument[]; + args: any[]; parentId: string | null; }; /** @@ -31,7 +31,7 @@ export declare class BehaviourTree { * @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); + constructor(definition: string | RootNodeDefinition | RootNodeDefinition[], 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. @@ -65,7 +65,7 @@ export declare class BehaviourTree { * @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; + static register(name: string, value: GlobalFunction | string | RootNodeDefinition): 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. @@ -76,14 +76,9 @@ export declare class BehaviourTree { */ static unregisterAll(): void; /** - * Parses a behaviour tree definition and creates a tree of behaviour tree nodes. - * @param {string} definition The behaviour tree definition. + * Parses a behaviour tree definition and creates a tree of behaviour tree nodes populated at a root. + * @param {string | RootNodeDefinition | RootNodeDefinition[]} 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; + private _createRootNode; } diff --git a/dist/BehaviourTreeBuilder.d.ts b/dist/BehaviourTreeBuilder.d.ts new file mode 100644 index 0000000..f99c54a --- /dev/null +++ b/dist/BehaviourTreeBuilder.d.ts @@ -0,0 +1,8 @@ +import { RootNodeDefinition } from "./BehaviourTreeDefinition"; +import Root from "./nodes/decorator/Root"; +/** + * Build and populate the root nodes based on the provided definition, assuming that the definition has been validated. + * @param definition The root node definitions. + * @returns The built and populated root node definitions. + */ +export default function buildRootNode(definition: RootNodeDefinition[]): Root; diff --git a/dist/BehaviourTreeDefinition.d.ts b/dist/BehaviourTreeDefinition.d.ts index 10005c8..08281af 100644 --- a/dist/BehaviourTreeDefinition.d.ts +++ b/dist/BehaviourTreeDefinition.d.ts @@ -47,7 +47,7 @@ export interface CompositeNodeDefinition extends NodeDefinition { /** * The child nodes of this composite node. */ - children: AnyChildNode[]; + children: AnyChildNodeDefinition[]; } /** * A decorator node, a composite with only a single child node. @@ -56,7 +56,7 @@ export interface DecoratorNodeDefinition extends NodeDefinition { /** * The child node of this decorator node. */ - child: AnyChildNode; + child: AnyChildNodeDefinition; } /** * A branch node. @@ -216,10 +216,10 @@ export interface FailNodeDefinition extends DecoratorNodeDefinition { type: "fail"; } /** - * A type defining any node type. + * A type defining any node definition. */ -export type AnyNode = BranchNodeDefinition | ActionNodeDefinition | ConditionNodeDefinition | WaitNodeDefinition | SequenceNodeDefinition | SelectorNodeDefinition | LottoNodeDefinition | ParallelNodeDefinition | RootNodeDefinition | RepeatNodeDefinition | RetryNodeDefinition | FlipNodeDefinition | SucceedNodeDefinition | FailNodeDefinition; +export type AnyNodeDefinition = BranchNodeDefinition | ActionNodeDefinition | ConditionNodeDefinition | WaitNodeDefinition | SequenceNodeDefinition | SelectorNodeDefinition | LottoNodeDefinition | ParallelNodeDefinition | RootNodeDefinition | RepeatNodeDefinition | RetryNodeDefinition | FlipNodeDefinition | SucceedNodeDefinition | FailNodeDefinition; /** * A type defining any node type that can be a child of composite parent node. */ -export type AnyChildNode = Exclude; +export type AnyChildNodeDefinition = Exclude; diff --git a/dist/BehaviourTreeDefinitionUtilities.d.ts b/dist/BehaviourTreeDefinitionUtilities.d.ts index 46096da..212778a 100644 --- a/dist/BehaviourTreeDefinitionUtilities.d.ts +++ b/dist/BehaviourTreeDefinitionUtilities.d.ts @@ -1,4 +1,4 @@ -import { NodeDefinition, RootNodeDefinition, DecoratorNodeDefinition, CompositeNodeDefinition, AnyNode, BranchNodeDefinition } from "./BehaviourTreeDefinition"; +import { NodeDefinition, RootNodeDefinition, DecoratorNodeDefinition, CompositeNodeDefinition, AnyNodeDefinition, BranchNodeDefinition } from "./BehaviourTreeDefinition"; /** * A type guard function that returns true if the specified node satisfies the RootNodeDefinition type. * @param node The node. @@ -34,7 +34,7 @@ export declare function isCompositeNode(node: NodeDefinition): node is Composite * @param nodeDefinition The node definition to flatten. * @returns An array of all of nested node definitions. */ -export declare function flattenDefinition(nodeDefinition: AnyNode): AnyNode[]; +export declare function flattenDefinition(nodeDefinition: AnyNodeDefinition): AnyNodeDefinition[]; /** * Determines whether the passed value is an integer. * @param value The value to check. diff --git a/dist/BehaviourTreeDefinitionValidator.d.ts b/dist/BehaviourTreeDefinitionValidator.d.ts index a5de380..531d5f6 100644 --- a/dist/BehaviourTreeDefinitionValidator.d.ts +++ b/dist/BehaviourTreeDefinitionValidator.d.ts @@ -13,7 +13,7 @@ export type DefinitionValidationResult = { errorMessage?: string; }; /** - * Validates the specified behaviour tree definition in the form of JSON or MDSL. + * Validates the specified behaviour tree definition in the form of JSON or MDSL, not taking any globally registered subtrees into consideration. * @param definition The behaviour tree definition in the form of JSON or MDSL. * @returns An object representing the result of validating the given tree definition. */ @@ -30,3 +30,11 @@ export declare function validateMDSLDefinition(definition: string): DefinitionVa * @returns An object representing the result of validating the given tree definition. */ export declare function validateJSONDefinition(definition: RootNodeDefinition | RootNodeDefinition[]): DefinitionValidationResult; +/** + * Validates the branch -> subtree links across all provided root node definitions. + * This will not consider branch nodes that reference any globally registered subtrees unless includesGlobalSubtrees + * is set to true, in which case we will also verify that there are no broken branch -> subtree links. + * @param rootNodeDefinitions The array of root node definitions. + * @param includesGlobalSubtrees A flag defining whether the array includes all global subtree root node definitions. + */ +export declare function validateBranchSubtreeLinks(rootNodeDefinitions: RootNodeDefinition[], includesGlobalSubtrees: boolean): void; diff --git a/dist/Lookup.d.ts b/dist/Lookup.d.ts index 8efbc28..134dd92 100644 --- a/dist/Lookup.d.ts +++ b/dist/Lookup.d.ts @@ -1,10 +1,6 @@ -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; +import { ActionResult, Agent, GlobalFunction } from "./Agent"; +import { RootNodeDefinition } from "./BehaviourTreeDefinition"; +export type InvokerFunction = (args: any[]) => ActionResult; /** * A singleton used to store and lookup registered functions and subtrees. */ @@ -14,7 +10,7 @@ export default class Lookup { */ private static functionTable; /** - * The object holding any registered sub-trees keyed on tree name. + * The object holding any registered subtree root node definitions keyed on tree name. */ private static subtreeTable; /** @@ -39,17 +35,17 @@ export default class Lookup { */ 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. + * Gets all registered subtree root node definitions. */ - static getSubtree(name: string): RootAstNode; + static getSubtrees(): { + [key: string]: RootNodeDefinition; + }; /** * 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; + static setSubtree(name: string, subtree: RootNodeDefinition): void; /** * Removes the registered function or subtree with the specified name. * @param name The name of the registered function or subtree. @@ -60,4 +56,3 @@ export default class Lookup { */ static empty(): void; } -export {}; diff --git a/dist/attributes/Attribute.d.ts b/dist/attributes/Attribute.d.ts index 6fb7bb3..515015a 100644 --- a/dist/attributes/Attribute.d.ts +++ b/dist/attributes/Attribute.d.ts @@ -1,30 +1,21 @@ -import { AnyArgument } from "../RootAstNodesBuilder"; import Guard from "./guards/Guard"; export type AttributeDetails = { /** The attribute type. */ type: string; /** The attribute arguments. */ - args: AnyArgument[]; + args: any[]; }; /** * A base node attribute. */ export default abstract class Attribute { - protected type: string; - protected args: AnyArgument[]; + type: string; + args: any[]; /** * @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. + * @param args The array of attribute arguments. */ - getArguments: () => AnyArgument[]; + constructor(type: string, args: any[]); /** * Gets the attribute details. */ diff --git a/dist/attributes/callbacks/Callback.d.ts b/dist/attributes/callbacks/Callback.d.ts index 6a294b7..0ff5296 100644 --- a/dist/attributes/callbacks/Callback.d.ts +++ b/dist/attributes/callbacks/Callback.d.ts @@ -1,5 +1,4 @@ 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. */ @@ -15,7 +14,7 @@ export default abstract class Callback extends Attribute { * @param args The array of decorator argument definitions. * @param condition The name of the condition function that determines whether the guard is satisfied. */ - constructor(type: string, args: AnyArgument[], condition: string); + constructor(type: string, args: any[], condition: string); /** * Gets the name of the condition function that determines whether the guard is satisfied. */ diff --git a/dist/attributes/guards/Until.d.ts b/dist/attributes/guards/Until.d.ts index 5ec505f..55bb8bf 100644 --- a/dist/attributes/guards/Until.d.ts +++ b/dist/attributes/guards/Until.d.ts @@ -1,6 +1,5 @@ import Guard from "./Guard"; import { Agent } from "../../Agent"; -import { AnyArgument } from "../../RootAstNodesBuilder"; /** * An UNTIL guard which is satisfied as long as the given condition remains false. */ @@ -9,7 +8,7 @@ export default class Until extends Guard { * @param condition The name of the condition function that determines whether the guard is satisfied. * @param args The array of decorator argument definitions. */ - constructor(condition: string, args: AnyArgument[]); + constructor(condition: string, args: any[]); /** * Gets whether the guard is satisfied. * @param agent The agent. diff --git a/dist/attributes/guards/While.d.ts b/dist/attributes/guards/While.d.ts index dd4f6bf..d40f4bf 100644 --- a/dist/attributes/guards/While.d.ts +++ b/dist/attributes/guards/While.d.ts @@ -1,6 +1,5 @@ import Guard from "./Guard"; import { Agent } from "../../Agent"; -import { AnyArgument } from "../../RootAstNodesBuilder"; /** * A WHILE guard which is satisfied as long as the given condition remains true. */ @@ -9,7 +8,7 @@ export default class While extends Guard { * @param condition The name of the condition function that determines whether the guard is satisfied. * @param args The array of decorator argument definitions. */ - constructor(condition: string, args: AnyArgument[]); + constructor(condition: string, args: any[]); /** * Gets whether the guard is satisfied. * @param agent The agent. diff --git a/dist/bundle.js b/dist/bundle.js index e3bc0d0..8ca7544 100644 --- a/dist/bundle.js +++ b/dist/bundle.js @@ -1,15 +1,10 @@ "use strict"; var mistreevous = (() => { - var __create = Object.create; var __defProp = Object.defineProperty; var __getOwnPropDesc = Object.getOwnPropertyDescriptor; var __getOwnPropNames = Object.getOwnPropertyNames; - var __getProtoOf = Object.getPrototypeOf; var __hasOwnProp = Object.prototype.hasOwnProperty; var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value; - var __commonJS = (cb, mod) => function __require() { - return mod || (0, cb[__getOwnPropNames(cb)[0]])((mod = { exports: {} }).exports, mod), mod.exports; - }; var __export = (target, all) => { for (var name in all) __defProp(target, name, { get: all[name], enumerable: true }); @@ -22,232 +17,12 @@ var mistreevous = (() => { } return to; }; - var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps( - isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target, - mod - )); var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod); var __publicField = (obj, key, value) => { __defNormalProp(obj, typeof key !== "symbol" ? key + "" : key, value); return value; }; - // node_modules/lotto-draw/dist/Participant.js - var require_Participant = __commonJS({ - "node_modules/lotto-draw/dist/Participant.js"(exports) { - "use strict"; - Object.defineProperty(exports, "__esModule", { value: true }); - exports.Participant = void 0; - var Participant = function() { - function Participant2(participant, tickets) { - if (tickets === void 0) { - tickets = 1; - } - this._participant = participant; - this._tickets = tickets; - } - Object.defineProperty(Participant2.prototype, "participant", { - get: function() { - return this._participant; - }, - enumerable: false, - configurable: true - }); - Object.defineProperty(Participant2.prototype, "tickets", { - get: function() { - return this._tickets; - }, - set: function(value) { - this._tickets = value; - }, - enumerable: false, - configurable: true - }); - return Participant2; - }(); - exports.Participant = Participant; - } - }); - - // node_modules/lotto-draw/dist/Utilities.js - var require_Utilities = __commonJS({ - "node_modules/lotto-draw/dist/Utilities.js"(exports) { - "use strict"; - Object.defineProperty(exports, "__esModule", { value: true }); - exports.isNaturalNumber = exports.isNullOrUndefined = void 0; - function isNullOrUndefined(value) { - return value === null || value === void 0; - } - exports.isNullOrUndefined = isNullOrUndefined; - function isNaturalNumber(value) { - return typeof value === "number" && value >= 1 && Math.floor(value) === value; - } - exports.isNaturalNumber = isNaturalNumber; - } - }); - - // node_modules/lotto-draw/dist/Lotto.js - var require_Lotto = __commonJS({ - "node_modules/lotto-draw/dist/Lotto.js"(exports) { - "use strict"; - Object.defineProperty(exports, "__esModule", { value: true }); - exports.Lotto = void 0; - var Participant_1 = require_Participant(); - var Utilities_1 = require_Utilities(); - var Lotto2 = function() { - function Lotto3(customRandom) { - this._participants = []; - this._customRandom = customRandom; - } - Lotto3.prototype.add = function(participant, tickets) { - if (tickets === void 0) { - tickets = 1; - } - if (!(0, Utilities_1.isNaturalNumber)(tickets)) { - throw new Error("tickets value must be a natural number"); - } - var existingParticipant = this._participants.find(function(part) { - return part.participant === participant; - }); - if (existingParticipant) { - existingParticipant.tickets += tickets; - } else { - this._participants.push(new Participant_1.Participant(participant, tickets)); - } - return this; - }; - Lotto3.prototype.remove = function(participant, tickets) { - var existingParticipant = this._participants.find(function(part) { - return part.participant === participant; - }); - if (!existingParticipant) { - return this; - } - if (tickets !== void 0) { - if (!(0, Utilities_1.isNaturalNumber)(tickets)) { - throw new Error("tickets value must be a natural number"); - } - existingParticipant.tickets -= tickets; - if (existingParticipant.tickets < 1) { - this._participants = this._participants.filter(function(part) { - return part !== existingParticipant; - }); - } - } else { - this._participants = this._participants.filter(function(part) { - return part !== existingParticipant; - }); - } - return this; - }; - Lotto3.prototype.draw = function(options) { - if (options === void 0) { - options = {}; - } - if (this._participants.length === 0) { - return null; - } - var redrawable = (0, Utilities_1.isNullOrUndefined)(options.redrawable) ? true : options.redrawable; - var pickable = []; - this._participants.forEach(function(_a) { - var participant = _a.participant, tickets = _a.tickets; - for (var ticketCount = 0; ticketCount < tickets; ticketCount++) { - pickable.push(participant); - } - }); - var random; - if (this._customRandom) { - random = this._customRandom(); - if (typeof random !== "number" || random < 0 || random >= 1) { - throw new Error("the 'random' function provided did not return a number between 0 (inclusive) and 1"); - } - } else { - random = Math.random(); - } - var winner = pickable[Math.floor(random * pickable.length)]; - if (!redrawable) { - this.remove(winner, 1); - } - return winner; - }; - Lotto3.prototype.drawMultiple = function(tickets, options) { - if (options === void 0) { - options = {}; - } - var uniqueResults = (0, Utilities_1.isNullOrUndefined)(options.unique) ? false : options.unique; - if (tickets === 0) { - return []; - } - if (!(0, Utilities_1.isNaturalNumber)(tickets)) { - throw new Error("tickets value must be a natural number"); - } - var result = []; - while (result.length < tickets && this._participants.length > 0) { - result.push(this.draw(options)); - } - if (uniqueResults) { - var unique = []; - for (var _i = 0, result_1 = result; _i < result_1.length; _i++) { - var participant = result_1[_i]; - if (unique.indexOf(participant) === -1) { - unique.push(participant); - } - } - result = unique; - } - return result; - }; - return Lotto3; - }(); - exports.Lotto = Lotto2; - } - }); - - // node_modules/lotto-draw/dist/createLotto.js - var require_createLotto = __commonJS({ - "node_modules/lotto-draw/dist/createLotto.js"(exports) { - "use strict"; - Object.defineProperty(exports, "__esModule", { value: true }); - exports.createLotto = void 0; - var Lotto_1 = require_Lotto(); - function createLotto2(participantsOrOptions) { - if (!participantsOrOptions) { - return new Lotto_1.Lotto(); - } - if (Array.isArray(participantsOrOptions)) { - var participants = participantsOrOptions; - var lotto_1 = new Lotto_1.Lotto(); - participants.forEach(function(_a) { - var participant = _a[0], tokens = _a[1]; - return lotto_1.add(participant, tokens); - }); - return lotto_1; - } else { - var random = participantsOrOptions.random, participants = participantsOrOptions.participants; - var lotto_2 = new Lotto_1.Lotto(random); - if (participants) { - participants.forEach(function(_a) { - var participant = _a[0], tokens = _a[1]; - return lotto_2.add(participant, tokens); - }); - } - return lotto_2; - } - } - exports.createLotto = createLotto2; - } - }); - - // node_modules/lotto-draw/dist/index.js - var require_dist = __commonJS({ - "node_modules/lotto-draw/dist/index.js"(exports) { - "use strict"; - Object.defineProperty(exports, "__esModule", { value: true }); - var createLotto_1 = require_createLotto(); - exports.default = createLotto_1.createLotto; - } - }); - // src/index.ts var src_exports = {}; __export(src_exports, { @@ -738,7 +513,7 @@ var mistreevous = (() => { try { rootNodeDefinitions = convertMDSLToJSON(definition); } catch (error) { - return createValidationFailureResult(`invalid MDSL: ${definition}`); + return createValidationFailureResult(`invalid MDSL: ${error}`); } const mainRootNodeDefinitions = rootNodeDefinitions.filter(({ id }) => typeof id === "undefined"); const subRootNodeDefinitions = rootNodeDefinitions.filter(({ id }) => typeof id === "string" && id.length > 0); @@ -754,11 +529,10 @@ var mistreevous = (() => { } subRootNodeIdenitifers.push(id); } - const circularDependencyPath = findBranchCircularDependencyPath(rootNodeDefinitions); - if (circularDependencyPath) { - return createValidationFailureResult( - `circular dependency found in branch node references: ${circularDependencyPath}` - ); + try { + validateBranchSubtreeLinks(rootNodeDefinitions, false); + } catch (exception) { + return createValidationFailureResult(exception.message); } return { succeeded: true }; } @@ -788,37 +562,38 @@ var mistreevous = (() => { } subRootNodeIdenitifers.push(id); } - const circularDependencyPath = findBranchCircularDependencyPath(rootNodeDefinitions); - if (circularDependencyPath) { - return createValidationFailureResult( - `circular dependency found in branch node references: ${circularDependencyPath}` - ); + try { + validateBranchSubtreeLinks(rootNodeDefinitions, false); + } catch (exception) { + return createValidationFailureResult(exception.message); } return { succeeded: true }; } - function findBranchCircularDependencyPath(rootNodeDefinitions) { + function validateBranchSubtreeLinks(rootNodeDefinitions, includesGlobalSubtrees) { const rootNodeMappings = rootNodeDefinitions.map( (rootNodeDefinition) => ({ id: rootNodeDefinition.id, refs: flattenDefinition(rootNodeDefinition).filter(isBranchNode).map(({ ref }) => ref) }) ); - let badPathFormatted = null; const followRefs = (mapping, path = []) => { if (path.includes(mapping.id)) { const badPath = [...path, mapping.id]; - badPathFormatted = badPath.filter((element) => !!element).join(" => "); - return; + const badPathFormatted = badPath.filter((element) => !!element).join(" => "); + throw new Error(`circular dependency found in branch node references: ${badPathFormatted}`); } for (const ref of mapping.refs) { const subMapping = rootNodeMappings.find(({ id }) => id === ref); if (subMapping) { followRefs(subMapping, [...path, mapping.id]); + } else if (includesGlobalSubtrees) { + throw new Error( + mapping.id ? `subtree '${mapping.id}' has branch node that references root node '${ref}' which has not been defined` : `primary tree has branch node that references root node '${ref}' which has not been defined` + ); } } }; followRefs(rootNodeMappings.find((mapping) => typeof mapping.id === "undefined")); - return badPathFormatted; } function validateNode(definition, depth) { if (typeof definition !== "object" || typeof definition.type !== "string" || definition.type.length === 0) { @@ -1087,6 +862,42 @@ var mistreevous = (() => { return { succeeded: false, errorMessage }; } + // src/Lookup.ts + var Lookup = class { + static getFunc(name) { + return this.functionTable[name]; + } + static setFunc(name, func) { + this.functionTable[name] = func; + } + static getFuncInvoker(agent, name) { + const foundOnAgent = agent[name]; + if (foundOnAgent && typeof foundOnAgent === "function") { + return (args) => foundOnAgent.apply(agent, args); + } + if (this.functionTable[name] && typeof this.functionTable[name] === "function") { + return (args) => this.functionTable[name](agent, ...args.map((arg) => arg.value)); + } + return null; + } + static getSubtrees() { + return this.subtreeTable; + } + static setSubtree(name, subtree) { + this.subtreeTable[name] = subtree; + } + static remove(name) { + delete this.functionTable[name]; + delete this.subtreeTable[name]; + } + static empty() { + this.functionTable = {}; + this.subtreeTable = {}; + } + }; + __publicField(Lookup, "functionTable", {}); + __publicField(Lookup, "subtreeTable", {}); + // src/attributes/guards/GuardUnsatisifedException.ts var GuardUnsatisifedException = class extends Error { constructor(source) { @@ -1131,7 +942,7 @@ var mistreevous = (() => { getAttributes = () => this.attributes; getArguments = () => this.args; getAttribute(type) { - return this.getAttributes().filter((decorator) => decorator.getType().toUpperCase() === type.toUpperCase())[0] || null; + return this.getAttributes().filter((decorator) => decorator.type.toUpperCase() === type.toUpperCase())[0] || null; } getGuardAttributes = () => this.getAttributes().filter((decorator) => decorator.isGuard()); setGuardPath = (value) => this.guardPath = value; @@ -1180,193 +991,6 @@ var mistreevous = (() => { return S4() + S4() + "-" + S4() + "-" + S4() + "-" + S4() + "-" + S4() + S4() + S4(); } - // src/nodes/leaf/Leaf.ts - var Leaf = class extends Node { - isLeafNode = () => true; - }; - - // src/Lookup.ts - var Lookup = class { - static getFunc(name) { - return this.functionTable[name]; - } - static setFunc(name, func) { - this.functionTable[name] = func; - } - static getFuncInvoker(agent, name) { - const foundOnAgent = agent[name]; - if (foundOnAgent && typeof foundOnAgent === "function") { - return (args) => foundOnAgent.apply( - agent, - args.map((arg) => arg.value) - ); - } - if (this.functionTable[name] && typeof this.functionTable[name] === "function") { - return (args) => this.functionTable[name](agent, ...args.map((arg) => arg.value)); - } - return null; - } - static getSubtree(name) { - return this.subtreeTable[name]; - } - static setSubtree(name, subtree) { - this.subtreeTable[name] = subtree; - } - static remove(name) { - delete this.functionTable[name]; - delete this.subtreeTable[name]; - } - static empty() { - this.functionTable = {}; - this.subtreeTable = {}; - } - }; - __publicField(Lookup, "functionTable", {}); - __publicField(Lookup, "subtreeTable", {}); - - // src/nodes/leaf/Action.ts - var Action = class extends Leaf { - constructor(attributes, actionName, actionArguments) { - super("action", attributes, actionArguments); - this.actionName = actionName; - this.actionArguments = actionArguments; - } - isUsingUpdatePromise = false; - updatePromiseStateResult = null; - onUpdate(agent, options) { - if (this.isUsingUpdatePromise) { - if (this.updatePromiseStateResult) { - this.setState(this.updatePromiseStateResult); - } - return; - } - const actionFuncInvoker = Lookup.getFuncInvoker(agent, this.actionName); - if (actionFuncInvoker === null) { - throw new Error( - `cannot update action node as the action '${this.actionName}' function is not defined on the agent and has not been registered` - ); - } - const updateResult = actionFuncInvoker(this.actionArguments); - if (updateResult instanceof Promise) { - updateResult.then( - (result) => { - if (!this.isUsingUpdatePromise) { - return; - } - if (result !== "mistreevous.succeeded" /* SUCCEEDED */ && result !== "mistreevous.failed" /* FAILED */) { - throw new Error( - "action node promise resolved with an invalid value, expected a State.SUCCEEDED or State.FAILED value to be returned" - ); - } - this.updatePromiseStateResult = result; - }, - (reason) => { - if (!this.isUsingUpdatePromise) { - return; - } - throw new Error(reason); - } - ); - this.setState("mistreevous.running" /* RUNNING */); - this.isUsingUpdatePromise = true; - } else { - this.validateUpdateResult(updateResult); - this.setState(updateResult || "mistreevous.running" /* RUNNING */); - } - } - getName = () => this.actionName; - reset = () => { - this.setState("mistreevous.ready" /* READY */); - this.isUsingUpdatePromise = false; - this.updatePromiseStateResult = null; - }; - validateUpdateResult = (result) => { - switch (result) { - case "mistreevous.succeeded" /* SUCCEEDED */: - case "mistreevous.failed" /* FAILED */: - case void 0: - return; - default: - throw new Error( - `action '${this.actionName}' 'onUpdate' returned an invalid response, expected an optional State.SUCCEEDED or State.FAILED value to be returned` - ); - } - }; - }; - - // src/nodes/leaf/Condition.ts - var Condition = class extends Leaf { - constructor(attributes, conditionName, conditionArguments) { - super("condition", attributes, conditionArguments); - this.conditionName = conditionName; - this.conditionArguments = conditionArguments; - } - onUpdate(agent, options) { - const conditionFuncInvoker = Lookup.getFuncInvoker(agent, this.conditionName); - if (conditionFuncInvoker === null) { - throw new Error( - `cannot update condition node as the condition '${this.conditionName}' function is not defined on the agent and has not been registered` - ); - } - this.setState(!!conditionFuncInvoker(this.conditionArguments) ? "mistreevous.succeeded" /* SUCCEEDED */ : "mistreevous.failed" /* FAILED */); - } - getName = () => this.conditionName; - }; - - // src/nodes/leaf/Wait.ts - var Wait = class extends Leaf { - constructor(attributes, duration, durationMin, durationMax) { - super("wait", attributes, []); - this.duration = duration; - this.durationMin = durationMin; - this.durationMax = durationMax; - } - initialUpdateTime = 0; - totalDuration = null; - waitedDuration = 0; - onUpdate(agent, options) { - if (this.is("mistreevous.ready" /* READY */)) { - this.initialUpdateTime = new Date().getTime(); - this.waitedDuration = 0; - if (this.duration !== null) { - this.totalDuration = this.duration; - } else if (this.durationMin !== null && this.durationMax !== null) { - const random = typeof options.random === "function" ? options.random : Math.random; - this.totalDuration = Math.floor( - random() * (this.durationMax - this.durationMin + 1) + this.durationMin - ); - } else { - this.totalDuration = null; - } - this.setState("mistreevous.running" /* RUNNING */); - } - if (this.totalDuration === null) { - return; - } - if (typeof options.getDeltaTime === "function") { - const deltaTime = options.getDeltaTime(); - if (typeof deltaTime !== "number" || isNaN(deltaTime)) { - throw new Error("The delta time must be a valid number and not NaN."); - } - this.waitedDuration += deltaTime * 1e3; - } else { - this.waitedDuration = new Date().getTime() - this.initialUpdateTime; - } - if (this.waitedDuration >= this.totalDuration) { - this.setState("mistreevous.succeeded" /* SUCCEEDED */); - } - } - getName = () => { - if (this.duration !== null) { - return `WAIT ${this.duration}ms`; - } else if (this.durationMin !== null && this.durationMax !== null) { - return `WAIT ${this.durationMin}ms-${this.durationMax}ms`; - } else { - return "WAIT"; - } - }; - }; - // src/nodes/decorator/Decorator.ts var Decorator = class extends Node { constructor(type, attributes, child) { @@ -1403,438 +1027,75 @@ var mistreevous = (() => { getName = () => "ROOT"; }; - // src/nodes/decorator/Repeat.ts - var Repeat = class extends Decorator { - constructor(attributes, iterations, iterationsMin, iterationsMax, child) { - super("repeat", attributes, child); - this.iterations = iterations; - this.iterationsMin = iterationsMin; - this.iterationsMax = iterationsMax; - } - targetIterationCount = null; - currentIterationCount = 0; - onUpdate(agent, options) { - if (this.is("mistreevous.ready" /* READY */)) { - this.child.reset(); - this.currentIterationCount = 0; - this.setTargetIterationCount(options); - } - if (this.canIterate()) { - this.setState("mistreevous.running" /* RUNNING */); - if (this.child.getState() === "mistreevous.succeeded" /* SUCCEEDED */) { - this.child.reset(); - } - this.child.update(agent, options); - if (this.child.getState() === "mistreevous.failed" /* FAILED */) { - this.setState("mistreevous.failed" /* FAILED */); - return; - } else if (this.child.getState() === "mistreevous.succeeded" /* SUCCEEDED */) { - this.currentIterationCount += 1; - } - } else { - this.setState("mistreevous.succeeded" /* SUCCEEDED */); - } + // src/attributes/Attribute.ts + var Attribute = class { + constructor(type, args) { + this.type = type; + this.args = args; } - getName = () => { - if (this.iterations !== null) { - return `REPEAT ${this.iterations}x`; - } else if (this.iterationsMin !== null && this.iterationsMax !== null) { - return `REPEAT ${this.iterationsMin}x-${this.iterationsMax}x`; - } else { - return "REPEAT"; - } - }; - reset = () => { - this.setState("mistreevous.ready" /* READY */); - this.currentIterationCount = 0; - this.child.reset(); - }; - canIterate = () => { - if (this.targetIterationCount !== null) { - return this.currentIterationCount < this.targetIterationCount; - } - return true; - }; - setTargetIterationCount = (options) => { - if (this.iterations !== null) { - this.targetIterationCount = this.iterations; - } else if (this.iterationsMin !== null && this.iterationsMax !== null) { - const random = typeof options.random === "function" ? options.random : Math.random; - this.targetIterationCount = Math.floor( - random() * (this.iterationsMax - this.iterationsMin + 1) + this.iterationsMin + }; + + // src/attributes/guards/Guard.ts + var Guard = class extends Attribute { + constructor(type, args, condition) { + super(type, args); + this.condition = condition; + } + getCondition = () => this.condition; + isGuard = () => true; + getDetails() { + return { + type: this.type, + args: this.args, + condition: this.getCondition() + }; + } + }; + + // src/attributes/guards/While.ts + var While = class extends Guard { + constructor(condition, args) { + super("while", args, condition); + } + isSatisfied = (agent) => { + const conditionFuncInvoker = Lookup.getFuncInvoker(agent, this.getCondition()); + if (conditionFuncInvoker === null) { + throw new Error( + `cannot evaluate node guard as the condition '${this.getCondition()}' function is not defined on the agent and has not been registered` ); - } else { - this.targetIterationCount = null; } + return !!conditionFuncInvoker(this.args); }; }; - // src/nodes/decorator/Retry.ts - var Retry = class extends Decorator { - constructor(attributes, attempts, attemptsMin, attemptsMax, child) { - super("retry", attributes, child); - this.attempts = attempts; - this.attemptsMin = attemptsMin; - this.attemptsMax = attemptsMax; - } - targetAttemptCount = null; - currentAttemptCount = 0; - onUpdate(agent, options) { - if (this.is("mistreevous.ready" /* READY */)) { - this.child.reset(); - this.currentAttemptCount = 0; - this.setTargetAttemptCount(options); - } - if (this.canAttempt()) { - this.setState("mistreevous.running" /* RUNNING */); - if (this.child.getState() === "mistreevous.failed" /* FAILED */) { - this.child.reset(); - } - this.child.update(agent, options); - if (this.child.getState() === "mistreevous.succeeded" /* SUCCEEDED */) { - this.setState("mistreevous.succeeded" /* SUCCEEDED */); - return; - } else if (this.child.getState() === "mistreevous.failed" /* FAILED */) { - this.currentAttemptCount += 1; - } - } else { - this.setState("mistreevous.failed" /* FAILED */); - } + // src/attributes/guards/Until.ts + var Until = class extends Guard { + constructor(condition, args) { + super("until", args, condition); } - getName = () => { - if (this.attempts !== null) { - return `RETRY ${this.attempts}x`; - } else if (this.attemptsMin !== null && this.attemptsMax !== null) { - return `RETRY ${this.attemptsMin}x-${this.attemptsMax}x`; - } else { - return "RETRY"; - } - }; - reset = () => { - this.setState("mistreevous.ready" /* READY */); - this.currentAttemptCount = 0; - this.child.reset(); - }; - canAttempt = () => { - if (this.targetAttemptCount !== null) { - return this.currentAttemptCount < this.targetAttemptCount; - } - return true; - }; - setTargetAttemptCount = (options) => { - if (this.attempts !== null) { - this.targetAttemptCount = this.attempts; - } else if (this.attemptsMin !== null && this.attemptsMax !== null) { - const random = typeof options.random === "function" ? options.random : Math.random; - this.targetAttemptCount = Math.floor( - random() * (this.attemptsMax - this.attemptsMin + 1) + this.attemptsMin + isSatisfied = (agent) => { + const conditionFuncInvoker = Lookup.getFuncInvoker(agent, this.getCondition()); + if (conditionFuncInvoker === null) { + throw new Error( + `cannot evaluate node guard as the condition '${this.getCondition()}' function is not defined on the agent and has not been registered` ); - } else { - this.targetAttemptCount = null; } + return !!!conditionFuncInvoker(this.args); }; }; - // src/nodes/decorator/Flip.ts - var Flip = class extends Decorator { - constructor(attributes, child) { - super("flip", attributes, child); - } - onUpdate(agent, options) { - if (this.child.getState() === "mistreevous.ready" /* READY */ || this.child.getState() === "mistreevous.running" /* RUNNING */) { - this.child.update(agent, options); - } - switch (this.child.getState()) { - case "mistreevous.running" /* RUNNING */: - this.setState("mistreevous.running" /* RUNNING */); - break; - case "mistreevous.succeeded" /* SUCCEEDED */: - this.setState("mistreevous.failed" /* FAILED */); - break; - case "mistreevous.failed" /* FAILED */: - this.setState("mistreevous.succeeded" /* SUCCEEDED */); - break; - default: - this.setState("mistreevous.ready" /* READY */); - } - } - getName = () => "FLIP"; - }; - - // src/nodes/decorator/Succeed.ts - var Succeed = class extends Decorator { - constructor(attributes, child) { - super("succeed", attributes, child); - } - onUpdate(agent, options) { - if (this.child.getState() === "mistreevous.ready" /* READY */ || this.child.getState() === "mistreevous.running" /* RUNNING */) { - this.child.update(agent, options); - } - switch (this.child.getState()) { - case "mistreevous.running" /* RUNNING */: - this.setState("mistreevous.running" /* RUNNING */); - break; - case "mistreevous.succeeded" /* SUCCEEDED */: - case "mistreevous.failed" /* FAILED */: - this.setState("mistreevous.succeeded" /* SUCCEEDED */); - break; - default: - this.setState("mistreevous.ready" /* READY */); - } - } - getName = () => "SUCCEED"; - }; - - // src/nodes/decorator/Fail.ts - var Fail = class extends Decorator { - constructor(attributes, child) { - super("fail", attributes, child); - } - onUpdate(agent, options) { - if (this.child.getState() === "mistreevous.ready" /* READY */ || this.child.getState() === "mistreevous.running" /* RUNNING */) { - this.child.update(agent, options); - } - switch (this.child.getState()) { - case "mistreevous.running" /* RUNNING */: - this.setState("mistreevous.running" /* RUNNING */); - break; - case "mistreevous.succeeded" /* SUCCEEDED */: - case "mistreevous.failed" /* FAILED */: - this.setState("mistreevous.failed" /* FAILED */); - break; - default: - this.setState("mistreevous.ready" /* READY */); - } - } - getName = () => "FAIL"; - }; - - // src/nodes/composite/Lotto.ts - var import_lotto_draw = __toESM(require_dist()); - - // src/nodes/composite/Composite.ts - var Composite = class extends Node { - constructor(type, attributes, children) { - super(type, attributes, []); - this.children = children; - } - isLeafNode = () => false; - getChildren = () => this.children; - reset = () => { - this.setState("mistreevous.ready" /* READY */); - this.getChildren().forEach((child) => child.reset()); - }; - abort = (agent) => { - if (!this.is("mistreevous.running" /* RUNNING */)) { - return; - } - this.getChildren().forEach((child) => child.abort(agent)); - this.reset(); - this.getAttribute("exit")?.callAgentFunction(agent, false, true); - }; - }; - - // src/nodes/composite/Lotto.ts - var Lotto = class extends Composite { - constructor(attributes, tickets, children) { - super("lotto", attributes, children); - this.tickets = tickets; - } - selectedChild; - onUpdate(agent, options) { - if (this.is("mistreevous.ready" /* READY */)) { - const lottoDraw = (0, import_lotto_draw.default)({ - random: options.random, - participants: this.children.map((child, index) => [child, this.tickets[index] || 1]) - }); - this.selectedChild = lottoDraw.draw() || void 0; - } - if (!this.selectedChild) { - throw new Error("failed to update lotto node as it has no active child"); - } - if (this.selectedChild.getState() === "mistreevous.ready" /* READY */ || this.selectedChild.getState() === "mistreevous.running" /* RUNNING */) { - this.selectedChild.update(agent, options); - } - this.setState(this.selectedChild.getState()); - } - getName = () => this.tickets.length ? `LOTTO [${this.tickets.join(",")}]` : "LOTTO"; - }; - - // src/nodes/composite/Selector.ts - var Selector = class extends Composite { - constructor(attributes, children) { - super("selector", attributes, children); - this.children = children; - } - onUpdate(agent, options) { - for (const child of this.children) { - if (child.getState() === "mistreevous.ready" /* READY */ || child.getState() === "mistreevous.running" /* RUNNING */) { - child.update(agent, options); - } - if (child.getState() === "mistreevous.succeeded" /* SUCCEEDED */) { - this.setState("mistreevous.succeeded" /* SUCCEEDED */); - return; - } - if (child.getState() === "mistreevous.failed" /* FAILED */) { - if (this.children.indexOf(child) === this.children.length - 1) { - this.setState("mistreevous.failed" /* FAILED */); - return; - } else { - continue; - } - } - if (child.getState() === "mistreevous.running" /* RUNNING */) { - this.setState("mistreevous.running" /* RUNNING */); - return; - } - throw new Error("child node was not in an expected state."); - } - } - getName = () => "SELECTOR"; - }; - - // src/nodes/composite/Sequence.ts - var Sequence = class extends Composite { - constructor(attributes, children) { - super("sequence", attributes, children); - this.children = children; - } - onUpdate(agent, options) { - for (const child of this.children) { - if (child.getState() === "mistreevous.ready" /* READY */ || child.getState() === "mistreevous.running" /* RUNNING */) { - child.update(agent, options); - } - if (child.getState() === "mistreevous.succeeded" /* SUCCEEDED */) { - if (this.children.indexOf(child) === this.children.length - 1) { - this.setState("mistreevous.succeeded" /* SUCCEEDED */); - return; - } else { - continue; - } - } - if (child.getState() === "mistreevous.failed" /* FAILED */) { - this.setState("mistreevous.failed" /* FAILED */); - return; - } - if (child.getState() === "mistreevous.running" /* RUNNING */) { - this.setState("mistreevous.running" /* RUNNING */); - return; - } - throw new Error("child node was not in an expected state."); - } - } - getName = () => "SEQUENCE"; - }; - - // src/nodes/composite/Parallel.ts - var Parallel = class extends Composite { - constructor(attributes, children) { - super("parallel", attributes, children); - } - onUpdate(agent, options) { - let succeededCount = 0; - let hasChildFailed = false; - for (const child of this.children) { - if (child.getState() === "mistreevous.ready" /* READY */ || child.getState() === "mistreevous.running" /* RUNNING */) { - child.update(agent, options); - } - if (child.getState() === "mistreevous.succeeded" /* SUCCEEDED */) { - succeededCount++; - continue; - } - if (child.getState() === "mistreevous.failed" /* FAILED */) { - hasChildFailed = true; - break; - } - if (child.getState() !== "mistreevous.running" /* RUNNING */) { - throw new Error("child node was not in an expected state."); - } - } - if (hasChildFailed) { - this.setState("mistreevous.failed" /* FAILED */); - for (const child of this.children) { - if (child.getState() === "mistreevous.running" /* RUNNING */) { - child.abort(agent); - } - } - } else { - this.setState(succeededCount === this.children.length ? "mistreevous.succeeded" /* SUCCEEDED */ : "mistreevous.running" /* RUNNING */); - } - } - getName = () => "PARALLEL"; - }; - - // src/attributes/Attribute.ts - var Attribute = class { - constructor(type, args) { - this.type = type; - this.args = args; - } - getType = () => this.type; - getArguments = () => this.args; - }; - - // src/attributes/guards/Guard.ts - var Guard = class extends Attribute { - constructor(type, args, condition) { - super(type, args); - this.condition = condition; - } - getCondition = () => this.condition; - isGuard = () => true; - getDetails() { - return { - type: this.getType(), - args: this.getArguments(), - condition: this.getCondition() - }; - } - }; - - // src/attributes/guards/While.ts - var While = class extends Guard { - constructor(condition, args) { - super("while", args, condition); - } - isSatisfied = (agent) => { - const conditionFuncInvoker = Lookup.getFuncInvoker(agent, this.getCondition()); - if (conditionFuncInvoker === null) { - throw new Error( - `cannot evaluate node guard as the condition '${this.getCondition()}' function is not defined on the agent and has not been registered` - ); - } - return !!conditionFuncInvoker(this.args); - }; - }; - - // src/attributes/guards/Until.ts - var Until = class extends Guard { - constructor(condition, args) { - super("until", args, condition); - } - isSatisfied = (agent) => { - const conditionFuncInvoker = Lookup.getFuncInvoker(agent, this.getCondition()); - if (conditionFuncInvoker === null) { - throw new Error( - `cannot evaluate node guard as the condition '${this.getCondition()}' function is not defined on the agent and has not been registered` - ); - } - return !!!conditionFuncInvoker(this.args); - }; - }; - - // src/attributes/callbacks/Callback.ts - var Callback = class extends Attribute { - constructor(type, args, functionName) { - super(type, args); - this.functionName = functionName; + // src/attributes/callbacks/Callback.ts + var Callback = class extends Attribute { + constructor(type, args, functionName) { + super(type, args); + this.functionName = functionName; } getFunctionName = () => this.functionName; isGuard = () => false; getDetails() { return { - type: this.getType(), - args: this.getArguments(), + type: this.type, + args: this.args, functionName: this.getFunctionName() }; } @@ -1856,700 +1117,108 @@ var mistreevous = (() => { }; }; - // src/attributes/callbacks/Exit.ts - var Exit = class extends Callback { + // src/attributes/callbacks/Step.ts + var Step = class extends Callback { constructor(functionName, args) { - super("exit", args, functionName); + super("step", args, functionName); } - callAgentFunction = (agent, isSuccess, isAborted) => { + callAgentFunction = (agent) => { const callbackFuncInvoker = Lookup.getFuncInvoker(agent, this.getFunctionName()); if (callbackFuncInvoker === null) { throw new Error( - `cannot call exit function '${this.getFunctionName()}' as is not defined on the agent and has not been registered` + `cannot call step function '${this.getFunctionName()}' as is not defined on the agent and has not been registered` ); } - callbackFuncInvoker([{ value: { succeeded: isSuccess, aborted: isAborted } }, ...this.args]); + callbackFuncInvoker(this.args); }; }; - // src/attributes/callbacks/Step.ts - var Step = class extends Callback { + // src/attributes/callbacks/Exit.ts + var Exit = class extends Callback { constructor(functionName, args) { - super("step", args, functionName); + super("exit", args, functionName); } - callAgentFunction = (agent) => { + callAgentFunction = (agent, isSuccess, isAborted) => { const callbackFuncInvoker = Lookup.getFuncInvoker(agent, this.getFunctionName()); if (callbackFuncInvoker === null) { throw new Error( - `cannot call step function '${this.getFunctionName()}' as is not defined on the agent and has not been registered` + `cannot call exit function '${this.getFunctionName()}' as is not defined on the agent and has not been registered` ); } - callbackFuncInvoker(this.args); + callbackFuncInvoker([{ value: { succeeded: isSuccess, aborted: isAborted } }, ...this.args]); }; }; - // src/RootAstNodesBuilder.ts - var AttributeFactories = { - WHILE: (condition, attributeArguments) => new While(condition, attributeArguments), - UNTIL: (condition, attributeArguments) => new Until(condition, attributeArguments), - ENTRY: (functionName, attributeArguments) => new Entry(functionName, attributeArguments), - EXIT: (functionName, attributeArguments) => new Exit(functionName, attributeArguments), - STEP: (functionName, attributeArguments) => new Step(functionName, attributeArguments) - }; - var ASTNodeFactories = { - ROOT: () => ({ - type: "root", - attributes: [], - name: null, - children: [], - validate(depth) { - if (depth > 1) { - throw new Error("a root node cannot be the child of another node"); - } - if (this.children.length !== 1) { - throw new Error("a root node must have a single child"); - } - }, - createNodeInstance(namedRootNodeProvider, visitedBranches) { - return new Root( - this.attributes, - this.children[0].createNodeInstance(namedRootNodeProvider, visitedBranches.slice()) - ); - } - }), - BRANCH: () => ({ - type: "branch", - branchName: "", - validate() { - }, - createNodeInstance(namedRootNodeProvider, visitedBranches) { - const targetRootNode = namedRootNodeProvider(this.branchName); - if (visitedBranches.indexOf(this.branchName) !== -1) { - throw new Error(`circular dependency found in branch node references for branch '${this.branchName}'`); - } - if (targetRootNode) { - return targetRootNode.createNodeInstance(namedRootNodeProvider, visitedBranches.concat(this.branchName)).getChildren()[0]; - } else { - throw new Error(`branch references root node '${this.branchName}' which has not been defined`); - } - } - }), - SELECTOR: () => ({ - type: "selector", - attributes: [], - children: [], - validate() { - if (this.children.length < 1) { - throw new Error("a selector node must have at least a single child"); - } - }, - createNodeInstance(namedRootNodeProvider, visitedBranches) { - return new Selector( - this.attributes, - this.children.map((child) => child.createNodeInstance(namedRootNodeProvider, visitedBranches.slice())) - ); - } - }), - SEQUENCE: () => ({ - type: "sequence", - attributes: [], - children: [], - validate() { - if (this.children.length < 1) { - throw new Error("a sequence node must have at least a single child"); - } - }, - createNodeInstance(namedRootNodeProvider, visitedBranches) { - return new Sequence( - this.attributes, - this.children.map((child) => child.createNodeInstance(namedRootNodeProvider, visitedBranches.slice())) - ); - } - }), - PARALLEL: () => ({ - type: "parallel", - attributes: [], - children: [], - validate() { - if (this.children.length < 1) { - throw new Error("a parallel node must have at least a single child"); - } - }, - createNodeInstance(namedRootNodeProvider, visitedBranches) { - return new Parallel( - this.attributes, - this.children.map((child) => child.createNodeInstance(namedRootNodeProvider, visitedBranches.slice())) - ); - } - }), - LOTTO: () => ({ - type: "lotto", - attributes: [], - children: [], - tickets: [], - validate() { - if (this.children.length < 1) { - throw new Error("a lotto node must have at least a single child"); - } - }, - createNodeInstance(namedRootNodeProvider, visitedBranches) { - return new Lotto( - this.attributes, - this.tickets, - this.children.map((child) => child.createNodeInstance(namedRootNodeProvider, visitedBranches.slice())) - ); - } - }), - REPEAT: () => ({ - type: "repeat", - attributes: [], - iterations: null, - iterationsMin: null, - iterationsMax: null, - children: [], - validate() { - if (this.children.length !== 1) { - throw new Error("a repeat node must have a single child"); - } - if (this.iterations !== null) { - if (this.iterations < 0) { - throw new Error("a repeat node must have a positive number of iterations if defined"); - } - } else if (this.iterationsMin !== null && this.iterationsMax !== null) { - if (this.iterationsMin < 0 || this.iterationsMax < 0) { - throw new Error( - "a repeat node must have a positive minimum and maximum iteration count if defined" - ); - } - if (this.iterationsMin > this.iterationsMax) { - throw new Error( - "a repeat node must not have a minimum iteration count that exceeds the maximum iteration count" - ); - } - } else { - } - }, - createNodeInstance(namedRootNodeProvider, visitedBranches) { - return new Repeat( - this.attributes, - this.iterations, - this.iterationsMin, - this.iterationsMax, - this.children[0].createNodeInstance(namedRootNodeProvider, visitedBranches.slice()) - ); - } - }), - RETRY: () => ({ - type: "retry", - attributes: [], - attempts: null, - attemptsMin: null, - attemptsMax: null, - children: [], - validate() { - if (this.children.length !== 1) { - throw new Error("a retry node must have a single child"); - } - if (this.attempts !== null) { - if (this.attempts < 0) { - throw new Error("a retry node must have a positive number of attempts if defined"); - } - } else if (this.attemptsMin !== null && this.attemptsMax !== null) { - if (this.attemptsMin < 0 || this.attemptsMax < 0) { - throw new Error("a retry node must have a positive minimum and maximum attempt count if defined"); - } - if (this.attemptsMin > this.attemptsMax) { - throw new Error( - "a retry node must not have a minimum attempt count that exceeds the maximum attempt count" - ); - } - } else { - } - }, - createNodeInstance(namedRootNodeProvider, visitedBranches) { - return new Retry( - this.attributes, - this.attempts, - this.attemptsMin, - this.attemptsMax, - this.children[0].createNodeInstance(namedRootNodeProvider, visitedBranches.slice()) - ); - } - }), - FLIP: () => ({ - type: "flip", - attributes: [], - children: [], - validate() { - if (this.children.length !== 1) { - throw new Error("a flip node must have a single child"); - } - }, - createNodeInstance(namedRootNodeProvider, visitedBranches) { - return new Flip( - this.attributes, - this.children[0].createNodeInstance(namedRootNodeProvider, visitedBranches.slice()) - ); - } - }), - SUCCEED: () => ({ - type: "succeed", - attributes: [], - children: [], - validate() { - if (this.children.length !== 1) { - throw new Error("a succeed node must have a single child"); - } - }, - createNodeInstance(namedRootNodeProvider, visitedBranches) { - return new Succeed( - this.attributes, - this.children[0].createNodeInstance(namedRootNodeProvider, visitedBranches.slice()) - ); - } - }), - FAIL: () => ({ - type: "fail", - attributes: [], - children: [], - validate() { - if (this.children.length !== 1) { - throw new Error("a fail node must have a single child"); - } - }, - createNodeInstance(namedRootNodeProvider, visitedBranches) { - return new Fail( - this.attributes, - this.children[0].createNodeInstance(namedRootNodeProvider, visitedBranches.slice()) - ); - } - }), - WAIT: () => ({ - type: "wait", - attributes: [], - duration: null, - durationMin: null, - durationMax: null, - validate() { - if (this.duration !== null) { - if (this.duration < 0) { - throw new Error("a wait node must have a positive duration"); - } - } else if (this.durationMin !== null && this.durationMax !== null) { - if (this.durationMin < 0 || this.durationMax < 0) { - throw new Error("a wait node must have a positive minimum and maximum duration"); - } - if (this.durationMin > this.durationMax) { - throw new Error("a wait node must not have a minimum duration that exceeds the maximum duration"); - } - } else { - } - }, - createNodeInstance() { - return new Wait(this.attributes, this.duration, this.durationMin, this.durationMax); - } - }), - ACTION: () => ({ - type: "action", - attributes: [], - actionName: "", - actionArguments: [], - validate() { - }, - createNodeInstance() { - return new Action(this.attributes, this.actionName, this.actionArguments); - } - }), - CONDITION: () => ({ - type: "condition", - attributes: [], - conditionName: "", - conditionArguments: [], - validate() { - }, - createNodeInstance() { - return new Condition(this.attributes, this.conditionName, this.conditionArguments); - } - }) - }; - function buildRootASTNodes(definition) { - const { placeholders, processedDefinition } = substituteStringLiterals2(definition); - const tokens = parseTokensFromDefinition2(processedDefinition); - if (tokens.length < 3) { - throw new Error("invalid token count"); - } - if (tokens.filter((token) => token === "{").length !== tokens.filter((token) => token === "}").length) { - throw new Error("scope character mismatch"); - } - const stack = [[]]; - const rootScope = stack[0]; - while (tokens.length) { - const token = tokens.shift(); - const currentScope = stack[stack.length - 1]; - switch (token.toUpperCase()) { - case "ROOT": { - const node = ASTNodeFactories.ROOT(); - rootScope.push(node); - if (tokens[0] === "[") { - const rootArguments = getArguments(tokens, placeholders); - if (rootArguments.length === 1 && rootArguments[0].type === "identifier") { - node.name = rootArguments[0].value; - } else { - throw new Error("expected single root name argument"); - } - } - node.attributes = getAttributes(tokens, placeholders); - popAndCheck2(tokens, "{"); - stack.push(node.children); - break; - } - case "BRANCH": { - const node = ASTNodeFactories.BRANCH(); - currentScope.push(node); - if (tokens[0] !== "[") { - throw new Error("expected single branch name argument"); - } - const branchArguments = getArguments(tokens, placeholders); - if (branchArguments.length === 1 && branchArguments[0].type === "identifier") { - node.branchName = branchArguments[0].value; - } else { - throw new Error("expected single branch name argument"); - } - break; - } - case "SELECTOR": { - const node = ASTNodeFactories.SELECTOR(); - currentScope.push(node); - node.attributes = getAttributes(tokens, placeholders); - popAndCheck2(tokens, "{"); - stack.push(node.children); - break; - } - case "SEQUENCE": { - const node = ASTNodeFactories.SEQUENCE(); - currentScope.push(node); - node.attributes = getAttributes(tokens, placeholders); - popAndCheck2(tokens, "{"); - stack.push(node.children); - break; - } - case "PARALLEL": { - const node = ASTNodeFactories.PARALLEL(); - currentScope.push(node); - node.attributes = getAttributes(tokens, placeholders); - popAndCheck2(tokens, "{"); - stack.push(node.children); - break; - } - case "LOTTO": { - const node = ASTNodeFactories.LOTTO(); - currentScope.push(node); - if (tokens[0] === "[") { - node.tickets = getArguments( - tokens, - placeholders, - (arg) => arg.type === "number" && !!arg.isInteger, - "lotto node ticket counts must be integer values" - ).map((argument) => argument.value); - } - node.attributes = getAttributes(tokens, placeholders); - popAndCheck2(tokens, "{"); - stack.push(node.children); - break; - } - case "CONDITION": { - const node = ASTNodeFactories.CONDITION(); - currentScope.push(node); - if (tokens[0] !== "[") { - throw new Error("expected condition name identifier argument"); - } - const conditionArguments = getArguments(tokens, placeholders); - if (conditionArguments.length && conditionArguments[0].type === "identifier") { - node.conditionName = conditionArguments.shift().value; - } else { - throw new Error("expected condition name identifier argument"); - } - conditionArguments.filter((arg) => arg.type === "identifier").forEach((arg) => { - throw new Error( - "invalid condition node argument value '" + arg.value + "', must be string, number, boolean or null" - ); - }); - node.conditionArguments = conditionArguments; - node.attributes = getAttributes(tokens, placeholders); - break; - } - case "FLIP": { - const node = ASTNodeFactories.FLIP(); - currentScope.push(node); - node.attributes = getAttributes(tokens, placeholders); - popAndCheck2(tokens, "{"); - stack.push(node.children); - break; - } - case "SUCCEED": { - const node = ASTNodeFactories.SUCCEED(); - currentScope.push(node); - node.attributes = getAttributes(tokens, placeholders); - popAndCheck2(tokens, "{"); - stack.push(node.children); - break; - } - case "FAIL": { - const node = ASTNodeFactories.FAIL(); - currentScope.push(node); - node.attributes = getAttributes(tokens, placeholders); - popAndCheck2(tokens, "{"); - stack.push(node.children); - break; - } - case "WAIT": { - const node = ASTNodeFactories.WAIT(); - currentScope.push(node); - if (tokens[0] === "[") { - const nodeArguments = getArguments( - tokens, - placeholders, - (arg) => arg.type === "number" && !!arg.isInteger, - "wait node durations must be integer values" - ).map((argument) => argument.value); - if (nodeArguments.length === 1) { - node.duration = nodeArguments[0]; - } else if (nodeArguments.length === 2) { - node.durationMin = nodeArguments[0]; - node.durationMax = nodeArguments[1]; - } else if (nodeArguments.length > 2) { - throw new Error("invalid number of wait node duration arguments defined"); - } - } - node.attributes = getAttributes(tokens, placeholders); - break; - } - case "REPEAT": { - const node = ASTNodeFactories.REPEAT(); - currentScope.push(node); - if (tokens[0] === "[") { - const nodeArguments = getArguments( - tokens, - placeholders, - (arg) => arg.type === "number" && !!arg.isInteger, - "repeat node iteration counts must be integer values" - ).map((argument) => argument.value); - if (nodeArguments.length === 1) { - node.iterations = nodeArguments[0]; - } else if (nodeArguments.length === 2) { - node.iterationsMin = nodeArguments[0]; - node.iterationsMax = nodeArguments[1]; - } else { - throw new Error("invalid number of repeat node iteration count arguments defined"); - } - } - node.attributes = getAttributes(tokens, placeholders); - popAndCheck2(tokens, "{"); - stack.push(node.children); - break; - } - case "RETRY": { - const node = ASTNodeFactories.RETRY(); - currentScope.push(node); - if (tokens[0] === "[") { - const nodeArguments = getArguments( - tokens, - placeholders, - (arg) => arg.type === "number" && !!arg.isInteger, - "retry node attempt counts must be integer values" - ).map((argument) => argument.value); - if (nodeArguments.length === 1) { - node.attempts = nodeArguments[0]; - } else if (nodeArguments.length === 2) { - node.attemptsMin = nodeArguments[0]; - node.attemptsMax = nodeArguments[1]; - } else { - throw new Error("invalid number of retry node attempt count arguments defined"); - } - } - node.attributes = getAttributes(tokens, placeholders); - popAndCheck2(tokens, "{"); - stack.push(node.children); - break; - } - case "ACTION": { - const node = ASTNodeFactories.ACTION(); - currentScope.push(node); - if (tokens[0] !== "[") { - throw new Error("expected action name identifier argument"); - } - const actionArguments = getArguments(tokens, placeholders); - if (actionArguments.length && actionArguments[0].type === "identifier") { - node.actionName = actionArguments.shift().value; - } else { - throw new Error("expected action name identifier argument"); - } - actionArguments.filter((arg) => arg.type === "identifier").forEach((arg) => { - throw new Error( - "invalid action node argument value '" + arg.value + "', must be string, number, boolean or null" - ); - }); - node.actionArguments = actionArguments; - node.attributes = getAttributes(tokens, placeholders); - break; - } - case "}": { - stack.pop(); - break; - } - default: { - throw new Error(`unexpected token '${token}'`); - } - } + // src/BehaviourTreeBuilder.ts + var MAIN_ROOT_NODE_KEY = Symbol("__root__"); + function buildRootNode(definition) { + const rootNodeDefinitionMap = createRootNodeDefinitionMap(definition); + validateBranchSubtreeLinks(definition, true); + const rootNode = nodeFactory(rootNodeDefinitionMap[MAIN_ROOT_NODE_KEY]); + applyLeafNodeGuardPaths(rootNode); + return rootNode; + } + function nodeFactory(definition) { + const attributes = nodeAttributesFactory(definition); + switch (definition.type) { + case "root": + return new Root(attributes, nodeFactory(definition.child)); + default: + throw new Error(`unexpected node type of '${definition.type}'`); } - const validateASTNode = (node, depth) => { - node.validate(depth); - (node.children || []).forEach((child) => validateASTNode(child, depth + 1)); - }; - validateASTNode( - { - children: stack[0], - validate() { - if (this.children.length === 0) { - throw new Error("expected root node to have been defined"); - } - for (const definitionLevelNode of this.children) { - if (definitionLevelNode.type !== "root") { - throw new Error("expected root node at base of definition"); - } - } - if (this.children.filter((definitionLevelNode) => definitionLevelNode.name === null).length !== 1) { - throw new Error("expected single unnamed root node at base of definition to act as main root"); - } - const rootNodeNames = []; - for (const definitionLevelNode of this.children) { - if (rootNodeNames.indexOf(definitionLevelNode.name) !== -1) { - throw new Error(`multiple root nodes found with duplicate name '${definitionLevelNode.name}'`); - } else { - rootNodeNames.push(definitionLevelNode.name); - } - } - } - }, - 0 - ); - return stack[0]; } - function popAndCheck2(tokens, expected) { - const popped = tokens.shift(); - if (popped === void 0) { - throw new Error("unexpected end of definition"); + function nodeAttributesFactory(definition) { + const attributes = []; + if (definition.while) { + attributes.push(new While(definition.while.call, definition.while.args ?? [])); } - if (expected !== void 0) { - var tokenMatchesExpectation = [].concat(expected).some((item) => popped.toUpperCase() === item.toUpperCase()); - if (!tokenMatchesExpectation) { - const expectationString = [].concat(expected).map((item) => "'" + item + "'").join(" or "); - throw new Error(`unexpected token found. Expected '${expectationString}' but got '${popped}'`); - } + if (definition.until) { + attributes.push(new Until(definition.until.call, definition.until.args ?? [])); } - return popped; - } - function getArguments(tokens, stringArgumentPlaceholders, argumentValidator, validationFailedMessage) { - const closer = popAndCheck2(tokens, ["[", "("]) === "[" ? "]" : ")"; - const argumentListTokens = []; - const argumentList = []; - while (tokens.length && tokens[0] !== closer) { - argumentListTokens.push(tokens.shift()); + if (definition.entry) { + attributes.push(new Entry(definition.entry.call, definition.entry.args ?? [])); } - argumentListTokens.forEach((token, index) => { - const shouldBeArgumentToken = !(index & 1); - if (shouldBeArgumentToken) { - const argumentDefinition = getArgumentDefinition2(token, stringArgumentPlaceholders); - if (argumentValidator && !argumentValidator(argumentDefinition)) { - throw new Error(validationFailedMessage); - } - argumentList.push(argumentDefinition); - } else { - if (token !== ",") { - throw new Error(`invalid argument list, expected ',' or ']' but got '${token}'`); - } - } - }); - popAndCheck2(tokens, closer); - return argumentList; - } - function getArgumentDefinition2(token, stringArgumentPlaceholders) { - if (token === "null") { - return { - value: null, - type: "null" - }; + if (definition.step) { + attributes.push(new Step(definition.step.call, definition.step.args ?? [])); } - if (token === "true" || token === "false") { - return { - value: token === "true", - type: "boolean" - }; + if (definition.exit) { + attributes.push(new Exit(definition.exit.call, definition.exit.args ?? [])); } - if (!isNaN(token)) { - return { - value: parseFloat(token), - isInteger: parseFloat(token) === parseInt(token, 10), - type: "number" - }; + return attributes; + } + function createRootNodeDefinitionMap(definition) { + const rootNodeMap = {}; + for (const [name, rootNodeDefinition] of Object.entries(Lookup.getSubtrees())) { + rootNodeMap[name] = { ...rootNodeDefinition, id: name }; } - if (token.match(/^@@\d+@@$/g)) { - return { - value: stringArgumentPlaceholders[token].replace('\\"', '"'), - type: "string" - }; + for (const rootNodeDefinition of definition) { + rootNodeMap[rootNodeDefinition.id ?? MAIN_ROOT_NODE_KEY] = rootNodeDefinition; } - return { - value: token, - type: "identifier" - }; + return rootNodeMap; } - function getAttributes(tokens, stringArgumentPlaceholders) { - const attributes = []; - const attributesFound = []; - let attributeFactory = AttributeFactories[(tokens[0] || "").toUpperCase()]; - while (attributeFactory) { - if (attributesFound.indexOf(tokens[0].toUpperCase()) !== -1) { - throw new Error(`duplicate attribute '${tokens[0].toUpperCase()}' found for node`); - } - attributesFound.push(tokens.shift().toUpperCase()); - const attributeArguments = getArguments(tokens, stringArgumentPlaceholders); - if (attributeArguments.length === 0 || attributeArguments[0].type !== "identifier") { - throw new Error("expected agent function name identifier argument for attribute"); + function applyLeafNodeGuardPaths(root) { + const nodePaths = []; + const findLeafNodes = (path, node) => { + path = path.concat(node); + if (node.isLeafNode()) { + nodePaths.push(path); + } else { + node.getChildren().forEach((child) => findLeafNodes(path, child)); } - const attributeFunctionName = attributeArguments.shift(); - attributeArguments.filter((arg) => arg.type === "identifier").forEach((arg) => { - throw new Error( - "invalid attribute argument value '" + arg.value + "', must be string, number, boolean or null" + }; + findLeafNodes([], root); + nodePaths.forEach((path) => { + for (let depth = 0; depth < path.length; depth++) { + const currentNode = path[depth]; + if (currentNode.hasGuardPath()) { + continue; + } + const guardPath = new GuardPath( + path.slice(0, depth + 1).map((node) => ({ node, guards: node.getGuardAttributes() })).filter((details) => details.guards.length > 0) ); - }); - attributes.push(attributeFactory(attributeFunctionName.value, attributeArguments)); - attributeFactory = AttributeFactories[(tokens[0] || "").toUpperCase()]; - } - return attributes; - } - function substituteStringLiterals2(definition) { - const placeholders = {}; - const processedDefinition = definition.replace(/\"(\\.|[^"\\])*\"/g, (match) => { - var strippedMatch = match.substring(1, match.length - 1); - var placeholder = Object.keys(placeholders).find((key) => placeholders[key] === strippedMatch); - if (!placeholder) { - placeholder = `@@${Object.keys(placeholders).length}@@`; - placeholders[placeholder] = strippedMatch; + currentNode.setGuardPath(guardPath); } - return placeholder; }); - return { placeholders, processedDefinition }; - } - function parseTokensFromDefinition2(definition) { - definition = definition.replace(/\(/g, " ( "); - definition = definition.replace(/\)/g, " ) "); - definition = definition.replace(/\{/g, " { "); - definition = definition.replace(/\}/g, " } "); - definition = definition.replace(/\]/g, " ] "); - definition = definition.replace(/\[/g, " [ "); - definition = definition.replace(/\,/g, " , "); - return definition.replace(/\s+/g, " ").trim().split(" "); } // src/BehaviourTree.ts @@ -2557,13 +1226,17 @@ var mistreevous = (() => { constructor(definition, agent, options = {}) { this.agent = agent; this.options = options; - if (typeof definition !== "string") { - throw new Error("the tree definition must be a string"); + if (!definition) { + throw new Error("the tree definition must be a string ro"); } if (typeof agent !== "object" || agent === null) { throw new Error("the agent must be defined and not null"); } - this.rootNode = BehaviourTree._createRootNode(definition); + try { + this.rootNode = this._createRootNode(definition); + } catch (exception) { + throw new Error(`error building tree: ${exception.message}`); + } } rootNode; isRunning() { @@ -2610,19 +1283,39 @@ var mistreevous = (() => { static register(name, value) { if (typeof value === "function") { Lookup.setFunc(name, value); - } else if (typeof value === "string") { - let rootASTNodes; + return; + } + if (typeof value === "string") { + let rootNodeDefinitions; try { - rootASTNodes = buildRootASTNodes(value); + rootNodeDefinitions = convertMDSLToJSON(value); } catch (exception) { - throw new Error(`error registering definition: ${exception.message}`); + throw new Error(`error registering definition, invalid MDSL: ${exception.message}`); } - if (rootASTNodes.length != 1 || rootASTNodes[0].name !== null) { + if (rootNodeDefinitions.length != 1 || rootNodeDefinitions[0].id !== null) { throw new Error("error registering definition: expected a single unnamed root node"); } - Lookup.setSubtree(name, rootASTNodes[0]); + try { + const { succeeded, errorMessage } = validateJSONDefinition(rootNodeDefinitions[0]); + if (!succeeded) { + throw new Error(errorMessage); + } + } catch (exception) { + throw new Error(`error registering definition: ${exception.message}`); + } + Lookup.setSubtree(name, rootNodeDefinitions[0]); + } else if (typeof value === "object" && !Array.isArray(value)) { + try { + const { succeeded, errorMessage } = validateJSONDefinition(value); + if (!succeeded) { + throw new Error(errorMessage); + } + } catch (exception) { + throw new Error(`error registering definition: ${exception.message}`); + } + Lookup.setSubtree(name, value); } else { - throw new Error("unexpected value, expected string definition or function"); + throw new Error("unexpected value, expected string mdsl definition, root node json definition or function"); } } static unregister(name) { @@ -2631,51 +1324,18 @@ var mistreevous = (() => { static unregisterAll() { Lookup.empty(); } - static _createRootNode(definition) { - try { - } catch (exception) { - console.log(exception); - } - try { - const rootASTNodes = buildRootASTNodes(definition); - const mainRootNodeKey = Symbol("__root__"); - const rootNodeMap = {}; - for (const rootASTNode of rootASTNodes) { - rootNodeMap[rootASTNode.name === null ? mainRootNodeKey : rootASTNode.name] = rootASTNode; + _createRootNode(definition) { + let resolvedDefinition; + if (typeof definition === "string") { + try { + resolvedDefinition = convertMDSLToJSON(definition); + } catch (exception) { + throw new Error(`invalid mdsl definition: ${exception.message}`); } - const rootNode = rootNodeMap[mainRootNodeKey].createNodeInstance( - (name) => rootNodeMap[name] ? rootNodeMap[name] : Lookup.getSubtree(name), - [] - ); - BehaviourTree._applyLeafNodeGuardPaths(rootNode); - return rootNode; - } catch (exception) { - throw new Error(`error parsing tree: ${exception.message}`); + } else { + resolvedDefinition = definition; } - } - static _applyLeafNodeGuardPaths(rootNode) { - const nodePaths = []; - const findLeafNodes = (path, node) => { - path = path.concat(node); - if (node.isLeafNode()) { - nodePaths.push(path); - } else { - node.getChildren().forEach((child) => findLeafNodes(path, child)); - } - }; - findLeafNodes([], rootNode); - nodePaths.forEach((path) => { - for (let depth = 0; depth < path.length; depth++) { - const currentNode = path[depth]; - if (currentNode.hasGuardPath()) { - continue; - } - const guardPath = new GuardPath( - path.slice(0, depth + 1).map((node) => ({ node, guards: node.getGuardAttributes() })).filter((details) => details.guards.length > 0) - ); - currentNode.setGuardPath(guardPath); - } - }); + return buildRootNode(Array.isArray(resolvedDefinition) ? resolvedDefinition : [resolvedDefinition]); } }; return __toCommonJS(src_exports); diff --git a/dist/bundle.js.map b/dist/bundle.js.map index b3528a0..99b85ef 100644 --- a/dist/bundle.js.map +++ b/dist/bundle.js.map @@ -1,7 +1,7 @@ { "version": 3, - "sources": ["../node_modules/lotto-draw/dist/Participant.js", "../node_modules/lotto-draw/dist/Utilities.js", "../node_modules/lotto-draw/dist/Lotto.js", "../node_modules/lotto-draw/dist/createLotto.js", "../node_modules/lotto-draw/dist/index.js", "../src/index.ts", "../src/State.ts", "../src/BehaviourTreeDefinitionUtilities.ts", "../src/mdsl/MDSLUtilities.ts", "../src/mdsl/MDSLNodeArgumentParser.ts", "../src/mdsl/MDSLNodeAttributeParser.ts", "../src/mdsl/MDSLDefinitionParser.ts", "../src/BehaviourTreeDefinitionValidator.ts", "../src/attributes/guards/GuardUnsatisifedException.ts", "../src/attributes/guards/GuardPath.ts", "../src/nodes/Node.ts", "../src/nodes/leaf/Leaf.ts", "../src/Lookup.ts", "../src/nodes/leaf/Action.ts", "../src/nodes/leaf/Condition.ts", "../src/nodes/leaf/Wait.ts", "../src/nodes/decorator/Decorator.ts", "../src/nodes/decorator/Root.ts", "../src/nodes/decorator/Repeat.ts", "../src/nodes/decorator/Retry.ts", "../src/nodes/decorator/Flip.ts", "../src/nodes/decorator/Succeed.ts", "../src/nodes/decorator/Fail.ts", "../src/nodes/composite/Lotto.ts", "../src/nodes/composite/Composite.ts", "../src/nodes/composite/Selector.ts", "../src/nodes/composite/Sequence.ts", "../src/nodes/composite/Parallel.ts", "../src/attributes/Attribute.ts", "../src/attributes/guards/Guard.ts", "../src/attributes/guards/While.ts", "../src/attributes/guards/Until.ts", "../src/attributes/callbacks/Callback.ts", "../src/attributes/callbacks/Entry.ts", "../src/attributes/callbacks/Exit.ts", "../src/attributes/callbacks/Step.ts", "../src/RootAstNodesBuilder.ts", "../src/BehaviourTree.ts"], - "sourcesContent": ["\"use strict\";\r\nObject.defineProperty(exports, \"__esModule\", { value: true });\r\nexports.Participant = void 0;\r\n/**\r\n * A participant that holds a number of tickets.\r\n */\r\nvar Participant = /** @class */ (function () {\r\n /**\r\n * Creates an instance of the Participant class.\r\n * @param participant The actual participant.\r\n * @param tickets The number of tickets held by the participant.\r\n */\r\n function Participant(participant, tickets) {\r\n if (tickets === void 0) { tickets = 1; }\r\n this._participant = participant;\r\n this._tickets = tickets;\r\n }\r\n Object.defineProperty(Participant.prototype, \"participant\", {\r\n /** Gets the actual participant. */\r\n get: function () {\r\n return this._participant;\r\n },\r\n enumerable: false,\r\n configurable: true\r\n });\r\n Object.defineProperty(Participant.prototype, \"tickets\", {\r\n /** Gets or sets the number of tickets held by the participant. */\r\n get: function () {\r\n return this._tickets;\r\n },\r\n set: function (value) {\r\n this._tickets = value;\r\n },\r\n enumerable: false,\r\n configurable: true\r\n });\r\n return Participant;\r\n}());\r\nexports.Participant = Participant;\r\n", "\"use strict\";\r\nObject.defineProperty(exports, \"__esModule\", { value: true });\r\nexports.isNaturalNumber = exports.isNullOrUndefined = void 0;\r\n/**\r\n * Gets whether the value provided is null or undefined.\r\n * @param value The value to check.\r\n * @returns Whether the value provided is null or undefined.\r\n */\r\nfunction isNullOrUndefined(value) {\r\n return value === null || value === undefined;\r\n}\r\nexports.isNullOrUndefined = isNullOrUndefined;\r\n/**\r\n * Gets whether the value provided is a natural number.\r\n * @param value The value to check.\r\n * @returns Whether the value provided is a natural number.\r\n */\r\nfunction isNaturalNumber(value) {\r\n return typeof value === \"number\" && value >= 1 && Math.floor(value) === value;\r\n}\r\nexports.isNaturalNumber = isNaturalNumber;\r\n", "\"use strict\";\r\nObject.defineProperty(exports, \"__esModule\", { value: true });\r\nexports.Lotto = void 0;\r\nvar Participant_1 = require(\"./Participant\");\r\nvar Utilities_1 = require(\"./Utilities\");\r\n/**\r\n * Represents a lotto consisting of a number of pickable ticket-holding participants.\r\n */\r\nvar Lotto = /** @class */ (function () {\r\n /**\r\n * Creates a new instance of Lotto.\r\n * @param customRandom The custom RNG to use in place of Math.random().\r\n */\r\n function Lotto(customRandom) {\r\n /** The array of participants that are holding tickets in the lotto. */\r\n this._participants = [];\r\n this._customRandom = customRandom;\r\n }\r\n /**\r\n * Adds a participant with the specified number of tickets, or adds to the participant ticket count if the participant already holds tickets.\r\n * @param participant The participant to add or to increase the ticket count for if they already hold tickets.\r\n * @param tickets The number of tickets, defaults to 1.\r\n * @returns The Lotto instance.\r\n */\r\n Lotto.prototype.add = function (participant, tickets) {\r\n if (tickets === void 0) { tickets = 1; }\r\n // Check that we have a valid ticket count.\r\n if (!(0, Utilities_1.isNaturalNumber)(tickets)) {\r\n throw new Error(\"tickets value must be a natural number\");\r\n }\r\n // Check whether this participant has already been added.\r\n var existingParticipant = this._participants.find(function (part) { return part.participant === participant; });\r\n if (existingParticipant) {\r\n // The participant has already been added to the lotto so just add to their ticket count.\r\n existingParticipant.tickets += tickets;\r\n }\r\n else {\r\n // The participant is not part of the lotto so we should add them.\r\n this._participants.push(new Participant_1.Participant(participant, tickets));\r\n }\r\n return this;\r\n };\r\n /**\r\n * Removes the specified number of tickets for the given participant from the draw, or all tickets if a ticket number is not defined.\r\n * @param participant The participant to remove tickets for.\r\n * @param tickets The number of tickets to remove, or undefined if all tickets are to be removed.\r\n * @returns The Lotto instance.\r\n */\r\n Lotto.prototype.remove = function (participant, tickets) {\r\n // Attempt to get the existing participant.\r\n var existingParticipant = this._participants.find(function (part) { return part.participant === participant; });\r\n // There is nothing to do if the specified participant isn't even part of the lotto.\r\n if (!existingParticipant) {\r\n return this;\r\n }\r\n // Check whether a tickets value was given.\r\n if (tickets !== undefined) {\r\n // Check that we have a valid ticket count.\r\n if (!(0, Utilities_1.isNaturalNumber)(tickets)) {\r\n throw new Error(\"tickets value must be a natural number\");\r\n }\r\n existingParticipant.tickets -= tickets;\r\n // If the participant no longer holds any tickets then they should be removed.\r\n if (existingParticipant.tickets < 1) {\r\n this._participants = this._participants.filter(function (part) { return part !== existingParticipant; });\r\n }\r\n }\r\n else {\r\n // We are removing all tickets for the participant so just remove them from the lotto.\r\n this._participants = this._participants.filter(function (part) { return part !== existingParticipant; });\r\n }\r\n return this;\r\n };\r\n /**\r\n * Draw a winning ticket and return the participant that holds the ticket.\r\n * @param options The draw options.\r\n * @returns The participant that holds the winning ticket.\r\n */\r\n Lotto.prototype.draw = function (options) {\r\n if (options === void 0) { options = {}; }\r\n // If we have no participants then just return null.\r\n if (this._participants.length === 0) {\r\n return null;\r\n }\r\n var redrawable = (0, Utilities_1.isNullOrUndefined)(options.redrawable) ? true : options.redrawable;\r\n var pickable = [];\r\n this._participants.forEach(function (_a) {\r\n var participant = _a.participant, tickets = _a.tickets;\r\n for (var ticketCount = 0; ticketCount < tickets; ticketCount++) {\r\n pickable.push(participant);\r\n }\r\n });\r\n var random;\r\n // We need a random floating-point number between 0 (inclusive) and 1 to scale up to pick our winner.\r\n // If a custom random function exists then we should use that or fall back to Math.random().\r\n if (this._customRandom) {\r\n // Call our custom random function to get a random floating-point number.\r\n random = this._customRandom();\r\n // Verify that the result of calling our custom random function is a number between 0 (inclusive) and 1.\r\n if (typeof random !== \"number\" || random < 0 || random >= 1) {\r\n throw new Error(\"the 'random' function provided did not return a number between 0 (inclusive) and 1\");\r\n }\r\n }\r\n else {\r\n // No custom random function was defined so just use good ol' Math.random().\r\n random = Math.random();\r\n }\r\n // Pick a winning participant.\r\n var winner = pickable[Math.floor(random * pickable.length)];\r\n // If the ticket isn't redrawable then we should remove a ticket from the winning participants ticket count.\r\n if (!redrawable) {\r\n this.remove(winner, 1);\r\n }\r\n // Return the winning participant.\r\n return winner;\r\n };\r\n /**\r\n * Draws multiple winning tickets and return an array of the participants that hold the winning tickets.\r\n * @param tickets The number of winning tickets to draw.\r\n * @param options The draw multiple options.\r\n * @returns An array of the participants that hold the winning tickets.\r\n */\r\n Lotto.prototype.drawMultiple = function (tickets, options) {\r\n if (options === void 0) { options = {}; }\r\n var uniqueResults = (0, Utilities_1.isNullOrUndefined)(options.unique) ? false : options.unique;\r\n // Handle cases where the user has asked for zero tickets (no idea why they would do this be we should trust them).\r\n if (tickets === 0) {\r\n return [];\r\n }\r\n // Now that we know out tickets value is not zero we should check that it is a valid natural number.\r\n if (!(0, Utilities_1.isNaturalNumber)(tickets)) {\r\n throw new Error(\"tickets value must be a natural number\");\r\n }\r\n var result = [];\r\n // Keep drawing tickets until we either reach the number of required tickets or we simply run out of tickets to draw.\r\n // We can run out of tickets to draw if 'options.redrawable' is explicity 'false' or we just had no participants when 'drawMultiple' was called.\r\n while (result.length < tickets && this._participants.length > 0) {\r\n result.push(this.draw(options));\r\n }\r\n // If the 'unique' draw option is set then we need to remove duplicates from the result list.\r\n if (uniqueResults) {\r\n // Create an array to store our unique results.\r\n var unique = [];\r\n // Iterate over all of our participants (with potential duplicates) and populate our array of unique values.\r\n for (var _i = 0, result_1 = result; _i < result_1.length; _i++) {\r\n var participant = result_1[_i];\r\n if (unique.indexOf(participant) === -1) {\r\n unique.push(participant);\r\n }\r\n }\r\n result = unique;\r\n }\r\n return result;\r\n };\r\n return Lotto;\r\n}());\r\nexports.Lotto = Lotto;\r\n", "\"use strict\";\r\nObject.defineProperty(exports, \"__esModule\", { value: true });\r\nexports.createLotto = void 0;\r\nvar Lotto_1 = require(\"./Lotto\");\r\n/**\r\n * A function that creates and returns a Lotto instance.\r\n * @param participantsOrOptions An array of initial participants or options relating to the creation of a Lotto instance.\r\n * @returns A new Lotto instance.\r\n */\r\nfunction createLotto(participantsOrOptions) {\r\n // If no initial participants or lotto options were provided as an argument then we can just return a new lotto instance now.\r\n if (!participantsOrOptions) {\r\n return new Lotto_1.Lotto();\r\n }\r\n // Check whether we were provided with an array of initial participants or a lotto options object.\r\n if (Array.isArray(participantsOrOptions)) {\r\n // We are dealing with a pre-defined array of participants.\r\n var participants = participantsOrOptions;\r\n var lotto_1 = new Lotto_1.Lotto();\r\n // If the lotto participants have been defined upfront then we will need to add them all to our lotto instance now.\r\n participants.forEach(function (_a) {\r\n var participant = _a[0], tokens = _a[1];\r\n return lotto_1.add(participant, tokens);\r\n });\r\n // Return the Lotto instance.\r\n return lotto_1;\r\n }\r\n else {\r\n // We are dealing with some lotto options.\r\n var random = participantsOrOptions.random, participants = participantsOrOptions.participants;\r\n // Create a Lotto instance passing the custom RNG function to use in place of Math.random() (which could be undefined).\r\n var lotto_2 = new Lotto_1.Lotto(random);\r\n // If the lotto participants have been defined upfront as part of the options then we will need to add them all to our lotto instance now.\r\n if (participants) {\r\n participants.forEach(function (_a) {\r\n var participant = _a[0], tokens = _a[1];\r\n return lotto_2.add(participant, tokens);\r\n });\r\n }\r\n // Return the Lotto instance.\r\n return lotto_2;\r\n }\r\n}\r\nexports.createLotto = createLotto;\r\n", "\"use strict\";\r\nObject.defineProperty(exports, \"__esModule\", { value: true });\r\nvar createLotto_1 = require(\"./createLotto\");\r\nexports.default = createLotto_1.createLotto;\r\n", "import State from \"./State\";\nimport { validateDefinition } from \"./BehaviourTreeDefinitionValidator\";\nimport { convertMDSLToJSON } from \"./mdsl/MDSLDefinitionParser\";\nimport { BehaviourTree, FlattenedTreeNode } from \"./BehaviourTree\";\n\nexport { BehaviourTree, State, convertMDSLToJSON, validateDefinition };\nexport type { FlattenedTreeNode };\n", "/**\n * Enumeration of node state types.\n */\nexport enum State {\n READY = \"mistreevous.ready\",\n RUNNING = \"mistreevous.running\",\n SUCCEEDED = \"mistreevous.succeeded\",\n FAILED = \"mistreevous.failed\"\n}\n\nexport { State as default };\n\nexport type CompleteState = State.SUCCEEDED | State.FAILED;\nexport type AnyState = State.READY | State.RUNNING | CompleteState;\n", "import {\n NodeDefinition,\n RootNodeDefinition,\n DecoratorNodeDefinition,\n CompositeNodeDefinition,\n AnyNode,\n BranchNodeDefinition\n} from \"./BehaviourTreeDefinition\";\n\n/**\n * A type guard function that returns true if the specified node satisfies the RootNodeDefinition type.\n * @param node The node.\n * @returns A value of true if the specified node satisfies the RootNodeDefinition type.\n */\nexport function isRootNode(node: NodeDefinition): node is RootNodeDefinition {\n return node.type === \"root\";\n}\n\n/**\n * A type guard function that returns true if the specified node satisfies the BranchNodeDefinition type.\n * @param node The node.\n * @returns A value of true if the specified node satisfies the BranchNodeDefinition type.\n */\nexport function isBranchNode(node: NodeDefinition): node is BranchNodeDefinition {\n return node.type === \"branch\";\n}\n\n/**\n * A type guard function that returns true if the specified node satisfies the NodeDefinition type.\n * @param node The node.\n * @returns A value of true if the specified node satisfies the NodeDefinition type.\n */\nexport function isLeafNode(node: NodeDefinition): node is NodeDefinition {\n return [\"branch\", \"action\", \"condition\", \"wait\"].includes(node.type);\n}\n\n/**\n * A type guard function that returns true if the specified node satisfies the DecoratorNodeDefinition type.\n * @param node The node.\n * @returns A value of true if the specified node satisfies the DecoratorNodeDefinition type.\n */\nexport function isDecoratorNode(node: NodeDefinition): node is DecoratorNodeDefinition {\n return [\"root\", \"repeat\", \"retry\", \"flip\", \"succeed\", \"fail\"].includes(node.type);\n}\n\n/**\n * A type guard function that returns true if the specified node satisfies the CompositeNodeDefinition type.\n * @param node The node.\n * @returns A value of true if the specified node satisfies the CompositeNodeDefinition type.\n */\nexport function isCompositeNode(node: NodeDefinition): node is CompositeNodeDefinition {\n return [\"sequence\", \"selector\", \"lotto\", \"parallel\"].includes(node.type);\n}\n\n/**\n * Flatten a node definition into an array of all of its nested node definitions.\n * @param nodeDefinition The node definition to flatten.\n * @returns An array of all of nested node definitions.\n */\nexport function flattenDefinition(nodeDefinition: AnyNode): AnyNode[] {\n const nodes: AnyNode[] = [];\n\n const processNode = (currentNodeDefinition: AnyNode) => {\n nodes.push(currentNodeDefinition);\n\n if (isCompositeNode(currentNodeDefinition)) {\n currentNodeDefinition.children.forEach(processNode);\n } else if (isDecoratorNode(currentNodeDefinition)) {\n processNode(currentNodeDefinition.child);\n }\n };\n\n processNode(nodeDefinition);\n\n return nodes;\n}\n\n/**\n * Determines whether the passed value is an integer.\n * @param value The value to check.\n * @returns Whether the passed value is an integer.\n */\nexport function isInteger(value: unknown): boolean {\n return typeof value === \"number\" && Math.floor(value) === value;\n}\n", "/**\n * A type defining an object that holds a reference to substitued string literals parsed from the definition.\n */\nexport type StringLiteralPlaceholders = { [key: string]: string };\n\n/**\n * Pop the next raw token from the specified array of tokens and throw an error if it wasn't the expected one.\n * @param tokens The array of tokens.\n * @param expected An optional string or array or items, one of which must match the next popped token.\n * @returns The popped token.\n */\nexport function popAndCheck(tokens: string[], expected?: string | string[]): string {\n // Get and remove the next token.\n const popped = tokens.shift();\n\n // We were expecting another token but there aren't any.\n if (popped === undefined) {\n throw new Error(\"unexpected end of definition\");\n }\n\n // Do we have an expected token/tokens array?\n if (expected != undefined) {\n // Get an array of expected values, if the popped token matches any then we are all good.\n const expectedValues = typeof expected === \"string\" ? [expected] : expected;\n\n // Check whether the popped token matches at least one of our expected items.\n var tokenMatchesExpectation = expectedValues.some((item) => popped.toUpperCase() === item.toUpperCase());\n\n // Throw an error if the popped token didn't match any of our expected items.\n if (!tokenMatchesExpectation) {\n const expectationString = expectedValues.map((item) => \"'\" + item + \"'\").join(\" or \");\n throw new Error(\"unexpected token found. Expected \" + expectationString + \" but got '\" + popped + \"'\");\n }\n }\n\n // Return the popped token.\n return popped;\n}\n\n/**\n * Swaps out any node/attribute argument string literals with placeholders.\n * @param definition The definition.\n * @returns An object containing a mapping of placeholders to original string values as well as the processed definition string.\n */\nexport function substituteStringLiterals(definition: string): {\n placeholders: StringLiteralPlaceholders;\n processedDefinition: string;\n} {\n // Create an object to hold the mapping of placeholders to original string values.\n const placeholders: StringLiteralPlaceholders = {};\n\n // Replace any string literals wrapped with double quotes in our definition with placeholders to be processed later.\n const processedDefinition = definition.replace(/\\\"(\\\\.|[^\"\\\\])*\\\"/g, (match) => {\n var strippedMatch = match.substring(1, match.length - 1);\n var placeholder = Object.keys(placeholders).find((key) => placeholders[key] === strippedMatch);\n\n // If we have no existing string literal match then create a new placeholder.\n if (!placeholder) {\n placeholder = `@@${Object.keys(placeholders).length}@@`;\n placeholders[placeholder] = strippedMatch;\n }\n\n return placeholder;\n });\n\n return { placeholders, processedDefinition };\n}\n\n/**\n * Parse the tree definition into an array of raw tokens.\n * @param definition The definition.\n * @returns An array of tokens parsed from the definition.\n */\nexport function parseTokensFromDefinition(definition: string): string[] {\n // Add some space around various important characters so that they can be plucked out easier as individual tokens.\n definition = definition.replace(/\\(/g, \" ( \");\n definition = definition.replace(/\\)/g, \" ) \");\n definition = definition.replace(/\\{/g, \" { \");\n definition = definition.replace(/\\}/g, \" } \");\n definition = definition.replace(/\\]/g, \" ] \");\n definition = definition.replace(/\\[/g, \" [ \");\n definition = definition.replace(/\\,/g, \" , \");\n\n // Split the definition into raw token form and return it.\n return definition.replace(/\\s+/g, \" \").trim().split(\" \");\n}\n", "import { StringLiteralPlaceholders, popAndCheck } from \"./MDSLUtilities\";\n\nexport type Argument = {\n /** The argument value. */\n value: T;\n /** The argument type, used for validation. */\n type: string;\n};\n\nexport type NullArgument = Argument & {\n type: \"null\";\n};\n\nexport type BooleanArgument = Argument & {\n type: \"boolean\";\n};\n\nexport type NumberArgument = Argument & {\n type: \"number\";\n isInteger: boolean; // Used for validation.\n};\n\nexport type StringPlaceholderArgument = Argument & {\n type: \"string\";\n};\n\nexport type IdentifierArgument = Argument & {\n type: \"identifier\";\n};\n\nexport type AnyArgument =\n | NullArgument\n | BooleanArgument\n | NumberArgument\n | StringPlaceholderArgument\n | IdentifierArgument;\n\n/**\n * Parse an array of argument definitions from the specified tokens array.\n * @param tokens The array tokens to parse the argument definitions from.\n * @param stringArgumentPlaceholders The mapping of string literal node argument placeholders to original values.\n * @param argumentValidator The argument validator function.\n * @param validationFailedMessage The exception message to throw if argument validation fails.\n * @returns An array of argument definitions parsed from the specified tokens array.\n */\nexport function parseArgumentTokens(\n tokens: string[],\n stringArgumentPlaceholders: StringLiteralPlaceholders\n): AnyArgument[] {\n const argumentList: AnyArgument[] = [];\n\n // If the next token is not a '[' or '(' then we have no arguments to parse.\n if (![\"[\", \"(\"].includes(tokens[0])) {\n return argumentList;\n }\n\n // Any lists of arguments will always be wrapped in '[]' for node arguments or '()' for attribute arguments.\n // We are looking for a '[' or '(' opener that wraps the argument tokens and the relevant closer.\n const closingToken = popAndCheck(tokens, [\"[\", \"(\"]) === \"[\" ? \"]\" : \")\";\n\n const argumentListTokens: string[] = [];\n\n // Grab all tokens between the '[' and ']' or '(' and ')'.\n while (tokens.length && tokens[0] !== closingToken) {\n // The next token is part of our arguments list.\n argumentListTokens.push(tokens.shift()!);\n }\n\n // Validate the order of the argument tokens. Each token must either be a ',' or a single argument that satisfies the validator.\n argumentListTokens.forEach((token, index) => {\n // Get whether this token should be an actual argument.\n const shouldBeArgumentToken = !(index & 1);\n\n // If the current token should be an actual argument then validate it, otherwise it should be a ',' token.\n if (shouldBeArgumentToken) {\n // Get the argument definition.\n const argumentDefinition = getArgumentDefinition(token, stringArgumentPlaceholders);\n\n // This is a valid argument!\n argumentList.push(argumentDefinition);\n } else {\n // The current token should be a ',' token.\n if (token !== \",\") {\n throw new Error(`invalid argument list, expected ',' or ']' but got '${token}'`);\n }\n }\n });\n\n // The arguments list should terminate with a ']' or ')' token, depending on the opener.\n popAndCheck(tokens, closingToken);\n\n // Return the arguments.\n return argumentList;\n}\n\n/**\n * Gets an argument value definition.\n * @param token The argument token.\n * @param stringArgumentPlaceholders The mapping of string literal node argument placeholders to original values.\n * @returns An argument value definition.\n */\nfunction getArgumentDefinition(token: string, stringArgumentPlaceholders: StringLiteralPlaceholders): AnyArgument {\n // Check whether the token represents a null value.\n if (token === \"null\") {\n return {\n value: null,\n type: \"null\"\n } as NullArgument;\n }\n\n // Check whether the token represents a boolean value.\n if (token === \"true\" || token === \"false\") {\n return {\n value: token === \"true\",\n type: \"boolean\"\n } as BooleanArgument;\n }\n\n // Check whether the token represents a number value.\n // TODO: Relies on broken isNaN - see MDN.\n // if (!Number.isNaN(token)) {\n if (!isNaN(token as any)) {\n return {\n value: parseFloat(token),\n isInteger: parseFloat(token) === parseInt(token, 10),\n type: \"number\"\n } as NumberArgument;\n }\n\n // Check whether the token is a placeholder (e.g. @@0@@) representing a string literal.\n if (token.match(/^@@\\d+@@$/g)) {\n return {\n value: stringArgumentPlaceholders[token].replace('\\\\\"', '\"'),\n type: \"string\"\n } as StringPlaceholderArgument;\n }\n\n // The only remaining option is that the argument value is an identifier.\n return {\n value: token,\n type: \"identifier\"\n } as IdentifierArgument;\n}\n", "import { NodeAttributeDefinition } from \"../BehaviourTreeDefinition\";\nimport { parseArgumentTokens } from \"./MDSLNodeArgumentParser\";\nimport { StringLiteralPlaceholders } from \"./MDSLUtilities\";\n\n/**\n * A type defining the attribute definitions of a node.\n */\ntype NodeAttributes = {\n while?: NodeAttributeDefinition;\n until?: NodeAttributeDefinition;\n entry?: NodeAttributeDefinition;\n exit?: NodeAttributeDefinition;\n step?: NodeAttributeDefinition;\n};\n\n/**\n * Parse any node attribute definitions from the specified tokens array.\n * @param tokens The array of remaining tokens.\n * @param stringArgumentPlaceholders The mapping of string literal node argument placeholders to original values.\n * @returns An object of attribute definitions defined by any directly following tokens.\n */\nexport function parseAttributeTokens(\n tokens: string[],\n stringArgumentPlaceholders: StringLiteralPlaceholders\n): NodeAttributes {\n const nodeAttributeNames: (keyof NodeAttributes)[] = [\"while\", \"until\", \"entry\", \"exit\", \"step\"];\n\n // Create an object to hold any attributes found.\n const attributes: NodeAttributes = {};\n\n // Try to get the name of the attribute for the next token.\n let nextAttributeName = tokens[0]?.toLowerCase() as keyof NodeAttributes;\n\n // Pull attribute tokens as well as their arguments off of the tokens stack until we have no more.\n while (nodeAttributeNames.includes(nextAttributeName)) {\n // Check to make sure that we have not already created an attribute definition of this type.\n if (attributes[nextAttributeName]) {\n throw new Error(`duplicate attribute '${tokens[0].toUpperCase()}' found for node`);\n }\n\n // Remove the attribute name token from the array of tokens.\n tokens.shift();\n\n // Grab the attribute arguments, assuming the first to be an identifier.\n const [attributeCallIdentifier, ...attributeArguments] = parseArgumentTokens(\n tokens,\n stringArgumentPlaceholders\n );\n\n // The first attribute argument has to be an identifer, this will reference an agent function.\n if (attributeCallIdentifier?.type !== \"identifier\") {\n throw new Error(\"expected agent function name identifier argument for attribute\");\n }\n\n // Any attribute arguments (other than the expected call identifier) must have a type of string, number, boolean or null.\n attributeArguments\n .filter((arg) => arg.type === \"identifier\")\n .forEach((arg) => {\n throw new Error(\n `invalid attribute argument value '${arg.value}', must be string, number, boolean or null`\n );\n });\n\n // Create the attribute definition and add it to the object of attribute definitions found.\n attributes[nextAttributeName] = {\n call: attributeCallIdentifier.value,\n args: attributeArguments.map(({ value }) => value)\n };\n\n // Try to get the next attribute name token, as there could be multiple.\n nextAttributeName = tokens[0]?.toLowerCase() as keyof NodeAttributes;\n }\n\n return attributes;\n}\n", "import {\n ActionNodeDefinition,\n AnyChildNode,\n AnyNode,\n BranchNodeDefinition,\n ConditionNodeDefinition,\n FailNodeDefinition,\n FlipNodeDefinition,\n LottoNodeDefinition,\n ParallelNodeDefinition,\n RepeatNodeDefinition,\n RetryNodeDefinition,\n RootNodeDefinition,\n SelectorNodeDefinition,\n SequenceNodeDefinition,\n SucceedNodeDefinition,\n WaitNodeDefinition\n} from \"../BehaviourTreeDefinition\";\nimport { isCompositeNode, isDecoratorNode, isLeafNode, isRootNode } from \"../BehaviourTreeDefinitionUtilities\";\nimport { parseArgumentTokens } from \"./MDSLNodeArgumentParser\";\nimport { parseAttributeTokens } from \"./MDSLNodeAttributeParser\";\nimport {\n StringLiteralPlaceholders,\n parseTokensFromDefinition,\n popAndCheck,\n substituteStringLiterals\n} from \"./MDSLUtilities\";\n\n/**\n * Convert the MDSL tree definition string into an equivalent JSON definition.\n * @param definition The tree definition string as MDSL.\n * @returns The root node JSON definitions.\n */\nexport function convertMDSLToJSON(definition: string): RootNodeDefinition[] {\n // Swap out any node/attribute argument string literals with a placeholder and get a mapping of placeholders to original values as well as the processed definition.\n const { placeholders, processedDefinition } = substituteStringLiterals(definition);\n\n // Parse our definition definition string into an array of raw tokens.\n const tokens = parseTokensFromDefinition(processedDefinition);\n\n return convertTokensToJSONDefinition(tokens, placeholders);\n}\n\n/**\n * Converts the specified tree definition tokens into a JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The root node JSON definitions.\n */\nfunction convertTokensToJSONDefinition(\n tokens: string[],\n stringLiteralPlaceholders: StringLiteralPlaceholders\n): RootNodeDefinition[] {\n // There must be at least 3 tokens for the tree definition to be valid. 'ROOT', '{' and '}'.\n if (tokens.length < 3) {\n throw new Error(\"invalid token count\");\n }\n\n // We should have a matching number of '{' and '}' tokens. If not, then there are scopes that have not been properly closed.\n if (tokens.filter((token) => token === \"{\").length !== tokens.filter((token) => token === \"}\").length) {\n throw new Error(\"scope character mismatch\");\n }\n\n // Create an array of tree stack arrays where root nodes will always be at the botton and the current composite/decorator node at the top.\n // There should be an element in this array for every root node defined and every element should be an array with a root note as the first element.\n // E.g. A definition with two root nodes defined:\n // [\n // [root, lotto, sequence],\n // [root, selector]\n // ]\n const treeStacks: [Partial, ...Partial[]][] = [];\n\n // Create an array of all root node definitions that we create.\n const rootNodes: Partial[] = [];\n\n // A helper function used to push node definitions onto the tree stack.\n const pushNode = (node: AnyNode) => {\n // If the node is a root node then we need to create a new tree stack array with the root node at the root.\n if (isRootNode(node)) {\n // Add the root node definition to our array of all parsed root node definitions.\n rootNodes.push(node);\n\n // Add the root node definition to the root of a new tree stack.\n treeStacks.push([node]);\n\n return;\n }\n\n // All non-root nodes should be pushed after their root nodes so handle cases\n // where we may not have any tree stacks or our top-most tree stack is empty.\n if (!treeStacks.length || !treeStacks[treeStacks.length - 1].length) {\n throw new Error(\"expected root node at base of definition\");\n }\n\n // Get the current tree stack that we are populating.\n const topTreeStack = treeStacks[treeStacks.length - 1];\n\n // Get the top-most node in the current tree stack, this will be a composite/decorator node\n // for which we will populate its children array if composite or setting its child if a decorator.\n const topTreeStackTopNode = topTreeStack[topTreeStack.length - 1] as AnyNode;\n\n // If the top-most node in the current root stack is a composite or decorator\n // node then the current node should be added as a child of the top-most node.\n if (isCompositeNode(topTreeStackTopNode)) {\n topTreeStackTopNode.children = topTreeStackTopNode.children || [];\n topTreeStackTopNode.children.push(node);\n } else if (isDecoratorNode(topTreeStackTopNode)) {\n // If the top node already has a child node set then throw an error as a decorator should only have a single child.\n if (topTreeStackTopNode.child) {\n throw new Error(\"a decorator node must only have a single child node\");\n }\n\n topTreeStackTopNode.child = node;\n }\n\n // If the node we are adding is also a composite or decorator node, then we should push it\n // onto the current tree stack, as subsequent nodes will be added as its child/children.\n if (!isLeafNode(node)) {\n topTreeStack.push(node);\n }\n };\n\n // A helper function used to pop node definitions off of the stack.\n const popNode = () => {\n // Get the current tree stack that we are populating.\n const topTreeStack = treeStacks[treeStacks.length - 1];\n\n // Pop the top-most node in the current tree stack if there is one.\n if (topTreeStack.length) {\n topTreeStack.pop();\n }\n\n // We don't want any empty tree stacks in our stack of tree stacks.\n if (!topTreeStack.length) {\n treeStacks.pop();\n }\n };\n\n // We should keep processing the raw tokens until we run out of them.\n while (tokens.length) {\n // Grab the next token.\n const token = tokens.shift()!;\n\n // How we create the next node depends on the current raw token value.\n switch (token.toUpperCase()) {\n case \"ROOT\": {\n pushNode(createRootNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"SUCCEED\": {\n pushNode(createSucceedNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"FAIL\": {\n pushNode(createFailNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"FLIP\": {\n pushNode(createFlipNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"REPEAT\": {\n pushNode(createRepeatNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"RETRY\": {\n pushNode(createRetryNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"SEQUENCE\": {\n pushNode(createSequenceNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"SELECTOR\": {\n pushNode(createSelectorNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"PARALLEL\": {\n pushNode(createParallelNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"LOTTO\": {\n pushNode(createLottoNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"ACTION\": {\n pushNode(createActionNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"CONDITION\": {\n pushNode(createConditionNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"WAIT\": {\n pushNode(createWaitNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"BRANCH\": {\n pushNode(createBranchNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"}\": {\n // The '}' character closes the current scope and means that we have to pop a node off of the current stack.\n popNode();\n break;\n }\n\n default: {\n throw new Error(`unexpected token: ${token}`);\n }\n }\n }\n\n return rootNodes as RootNodeDefinition[];\n}\n\n/**\n * Creates a root node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The root node JSON definition.\n */\nfunction createRootNode(tokens: string[], stringLiteralPlaceholders: StringLiteralPlaceholders): RootNodeDefinition {\n // Create the root node definition.\n let node = {\n type: \"root\",\n id: undefined\n } as RootNodeDefinition;\n\n // Parse any node arguments, we should only have one if any which will be an identifier argument for the root identifier.\n const nodeArguments = parseArgumentTokens(tokens, stringLiteralPlaceholders);\n\n // Check whether any node arguments were defined.\n if (nodeArguments.length) {\n // We should only have one argument, if any, which will be an identifier argument for the root identifier.\n if (nodeArguments.length === 1 && nodeArguments[0].type === \"identifier\") {\n // The root node identifier will be the first and only node argument value.\n node.id = nodeArguments[0].value as string;\n } else {\n throw new Error(\"expected single root name argument\");\n }\n }\n\n // Grab any node attribute definitions and spread them into the node definition.\n node = { ...node, ...parseAttributeTokens(tokens, stringLiteralPlaceholders) };\n\n // This is a decorator node, so we expect an opening '{'.\n popAndCheck(tokens, \"{\");\n\n // Return the root node definition.\n return node;\n}\n\n/**\n * Creates a succeed node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The succeed node JSON definition.\n */\nfunction createSucceedNode(\n tokens: string[],\n stringLiteralPlaceholders: StringLiteralPlaceholders\n): SucceedNodeDefinition {\n const node = {\n type: \"succeed\",\n ...parseAttributeTokens(tokens, stringLiteralPlaceholders)\n } as SucceedNodeDefinition;\n\n // This is a decorator node, so we expect an opening '{'.\n popAndCheck(tokens, \"{\");\n\n // Return the succeed node definition.\n return node;\n}\n\n/**\n * Creates a fail node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The fail node JSON definition.\n */\nfunction createFailNode(tokens: string[], stringLiteralPlaceholders: StringLiteralPlaceholders): FailNodeDefinition {\n const node = {\n type: \"fail\",\n ...parseAttributeTokens(tokens, stringLiteralPlaceholders)\n } as FailNodeDefinition;\n\n // This is a decorator node, so we expect an opening '{'.\n popAndCheck(tokens, \"{\");\n\n // Return the fail node definition.\n return node;\n}\n\n/**\n * Creates a flip node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The flip node JSON definition.\n */\nfunction createFlipNode(tokens: string[], stringLiteralPlaceholders: StringLiteralPlaceholders): FlipNodeDefinition {\n const node = {\n type: \"flip\",\n ...parseAttributeTokens(tokens, stringLiteralPlaceholders)\n } as FlipNodeDefinition;\n\n // This is a decorator node, so we expect an opening '{'.\n popAndCheck(tokens, \"{\");\n\n // Return the flip node definition.\n return node;\n}\n\n/**\n * Creates a repeat node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The repeat node JSON definition.\n */\nfunction createRepeatNode(\n tokens: string[],\n stringLiteralPlaceholders: StringLiteralPlaceholders\n): RepeatNodeDefinition {\n let node = { type: \"repeat\" } as RepeatNodeDefinition;\n\n // Get the node arguments.\n const nodeArguments = parseArgumentTokens(tokens, stringLiteralPlaceholders);\n\n // The arguments of a repeat node are optional. We may have:\n // - No node arguments, in which case the repeat note will iterate indefinitely.\n // - One node argument which will be the explicit number of iterations to make.\n // - Two node arguments which define the min and max iteration bounds from which a random iteration count will be picked.\n if (nodeArguments.length) {\n // All repeat node arguments MUST be of type number and must be integer.\n nodeArguments\n .filter((arg) => arg.type !== \"number\" || !arg.isInteger)\n .forEach(() => {\n throw new Error(`repeat node iteration counts must be integer values`);\n });\n\n // We should have got one or two iteration counts.\n if (nodeArguments.length === 1) {\n // A static iteration count was defined.\n node.iterations = nodeArguments[0].value as number;\n } else if (nodeArguments.length === 2) {\n // A minimum and maximum iteration count was defined.\n node.iterations = [nodeArguments[0].value as number, nodeArguments[1].value as number];\n } else {\n // An incorrect number of iteration counts was defined.\n throw new Error(\"invalid number of repeat node iteration count arguments defined\");\n }\n }\n\n // Grab any node attribute definitions and spread them into the node definition.\n node = { ...node, ...parseAttributeTokens(tokens, stringLiteralPlaceholders) };\n\n // This is a decorator node, so we expect an opening '{'.\n popAndCheck(tokens, \"{\");\n\n // Return the repeat node definition.\n return node;\n}\n\n/**\n * Creates a retry node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The retry node JSON definition.\n */\nfunction createRetryNode(tokens: string[], stringLiteralPlaceholders: StringLiteralPlaceholders): RetryNodeDefinition {\n let node = { type: \"retry\" } as RetryNodeDefinition;\n\n // Get the node arguments.\n const nodeArguments = parseArgumentTokens(tokens, stringLiteralPlaceholders);\n\n // The arguments of a retry node are optional. We may have:\n // - No node arguments, in which case the retry note will attempt indefinitely.\n // - One node argument which will be the explicit number of attempts to make.\n // - Two node arguments which define the min and max attempt bounds from which a random attempt count will be picked.\n if (nodeArguments.length) {\n // All retry node arguments MUST be of type number and must be integer.\n nodeArguments\n .filter((arg) => arg.type !== \"number\" || !arg.isInteger)\n .forEach(() => {\n throw new Error(`retry node attempt counts must be integer values`);\n });\n\n // We should have got one or two attempt counts.\n if (nodeArguments.length === 1) {\n // A static attempt count was defined.\n node.attempts = nodeArguments[0].value as number;\n } else if (nodeArguments.length === 2) {\n // A minimum and maximum attempt count was defined.\n node.attempts = [nodeArguments[0].value as number, nodeArguments[1].value as number];\n } else {\n // An incorrect number of attempt counts was defined.\n throw new Error(\"invalid number of retry node attempt count arguments defined\");\n }\n }\n\n // Grab any node attribute definitions and spread them into the node definition.\n node = { ...node, ...parseAttributeTokens(tokens, stringLiteralPlaceholders) };\n\n // This is a decorator node, so we expect an opening '{'.\n popAndCheck(tokens, \"{\");\n\n // Return the retry node definition.\n return node;\n}\n\n/**\n * Creates a sequence node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The sequence node JSON definition.\n */\nfunction createSequenceNode(\n tokens: string[],\n stringLiteralPlaceholders: StringLiteralPlaceholders\n): SequenceNodeDefinition {\n const node = {\n type: \"sequence\",\n ...parseAttributeTokens(tokens, stringLiteralPlaceholders)\n } as SequenceNodeDefinition;\n\n // This is a composite node, so we expect an opening '{'.\n popAndCheck(tokens, \"{\");\n\n // Return the sequence node definition.\n return node;\n}\n\n/**\n * Creates a selector node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The selector node JSON definition.\n */\nfunction createSelectorNode(\n tokens: string[],\n stringLiteralPlaceholders: StringLiteralPlaceholders\n): SelectorNodeDefinition {\n const node = {\n type: \"selector\",\n ...parseAttributeTokens(tokens, stringLiteralPlaceholders)\n } as SelectorNodeDefinition;\n\n // This is a composite node, so we expect an opening '{'.\n popAndCheck(tokens, \"{\");\n\n // Return the selector node definition.\n return node;\n}\n\n/**\n * Creates a parallel node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The parallel node JSON definition.\n */\nfunction createParallelNode(\n tokens: string[],\n stringLiteralPlaceholders: StringLiteralPlaceholders\n): ParallelNodeDefinition {\n const node = {\n type: \"parallel\",\n ...parseAttributeTokens(tokens, stringLiteralPlaceholders)\n } as ParallelNodeDefinition;\n\n // This is a composite node, so we expect an opening '{'.\n popAndCheck(tokens, \"{\");\n\n // Return the parallel node definition.\n return node;\n}\n\n/**\n * Creates a lotto node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The lotto node JSON definition.\n */\nfunction createLottoNode(tokens: string[], stringLiteralPlaceholders: StringLiteralPlaceholders): LottoNodeDefinition {\n // If any node arguments have been defined then they must be our weights.\n const nodeArguments = parseArgumentTokens(tokens, stringLiteralPlaceholders);\n\n // All lotto node arguments MUST be of type number and must be integer.\n nodeArguments\n .filter((arg) => arg.type !== \"number\" || !arg.isInteger)\n .forEach(() => {\n throw new Error(`lotto node weight arguments must be integer values`);\n });\n\n const node = {\n type: \"lotto\",\n weights: nodeArguments.map(({ value }) => value),\n ...parseAttributeTokens(tokens, stringLiteralPlaceholders)\n } as LottoNodeDefinition;\n\n // This is a composite node, so we expect an opening '{'.\n popAndCheck(tokens, \"{\");\n\n // Return the lotto node definition.\n return node;\n}\n\n/**\n * Creates an action node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The action node JSON definition.\n */\nfunction createActionNode(\n tokens: string[],\n stringLiteralPlaceholders: StringLiteralPlaceholders\n): ActionNodeDefinition {\n // Parse any node arguments, we should have at least one which will be an identifier argument for the action name\n // and agent function to invoke for the action, all other arguments are to be passed as arguments to that function.\n const [actionNameIdentifier, ...agentFunctionArgs] = parseArgumentTokens(tokens, stringLiteralPlaceholders);\n\n // Our first argument MUST be defined and be an identifier as we require an action name argument.\n if (actionNameIdentifier?.type !== \"identifier\") {\n throw new Error(\"expected action name identifier argument\");\n }\n\n // Only the first argument should have been an identifier, all agent function arguments must be string, number, boolean or null.\n agentFunctionArgs\n .filter((arg) => arg.type === \"identifier\")\n .forEach((arg) => {\n throw new Error(\n `invalid action node argument value '${arg.value}', must be string, number, boolean or null`\n );\n });\n\n // Return the action node definition.\n return {\n type: \"action\",\n call: actionNameIdentifier.value,\n args: agentFunctionArgs.map(({ value }) => value),\n ...parseAttributeTokens(tokens, stringLiteralPlaceholders)\n };\n}\n\n/**\n * Creates a condition node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The condition node JSON definition.\n */\nfunction createConditionNode(\n tokens: string[],\n stringLiteralPlaceholders: StringLiteralPlaceholders\n): ConditionNodeDefinition {\n // Parse any node arguments, we should have at least one which will be an identifier argument for the condition name\n // and agent function to invoke for the condition, all other arguments are to be passed as arguments to that function.\n const [conditionNameIdentifier, ...agentFunctionArgs] = parseArgumentTokens(tokens, stringLiteralPlaceholders);\n\n // Our first argument MUST be defined and be an identifier as we require a condition name argument.\n if (conditionNameIdentifier?.type !== \"identifier\") {\n throw new Error(\"expected condition name identifier argument\");\n }\n\n // Only the first argument should have been an identifier, all agent function arguments must be string, number, boolean or null.\n agentFunctionArgs\n .filter((arg) => arg.type === \"identifier\")\n .forEach((arg) => {\n throw new Error(\n `invalid condition node argument value '${arg.value}', must be string, number, boolean or null`\n );\n });\n\n // Return the condition node definition.\n return {\n type: \"condition\",\n call: conditionNameIdentifier.value,\n args: agentFunctionArgs.map(({ value }) => value),\n ...parseAttributeTokens(tokens, stringLiteralPlaceholders)\n };\n}\n\n/**\n * Creates a wait node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The wait node JSON definition.\n */\nfunction createWaitNode(tokens: string[], stringLiteralPlaceholders: StringLiteralPlaceholders): WaitNodeDefinition {\n let node = { type: \"wait\" } as WaitNodeDefinition;\n\n // Get the node arguments.\n const nodeArguments = parseArgumentTokens(tokens, stringLiteralPlaceholders);\n\n // The arguments of a wait node are optional. We may have:\n // - No node arguments, in which case the wait will be indefinite until it is aborted.\n // - One node argument which will be the explicit duration of the wait.\n // - Two node arguments which define the min and max duration bounds from which a random duration will be picked.\n if (nodeArguments.length) {\n // All wait node arguments MUST be of type number and must be integer.\n nodeArguments\n .filter((arg) => arg.type !== \"number\" || !arg.isInteger)\n .forEach(() => {\n throw new Error(`wait node duration arguments must be integer values`);\n });\n\n // We may have:\n // - One node argument which will be the explicit duration of the wait.\n // - Two node arguments which define the min and max duration bounds from which a random duration will be picked.\n // - Too many arguments, which is not valid.\n if (nodeArguments.length === 1) {\n // An explicit duration was defined.\n node.duration = nodeArguments[0].value as number;\n } else if (nodeArguments.length === 2) {\n // Min and max duration bounds were defined from which a random duration will be picked.\n node.duration = [nodeArguments[0].value as number, nodeArguments[1].value as number];\n } else if (nodeArguments.length > 2) {\n // An incorrect number of duration arguments were defined.\n throw new Error(\"invalid number of wait node duration arguments defined\");\n }\n }\n\n // Return the wait node definition.\n return { ...node, ...parseAttributeTokens(tokens, stringLiteralPlaceholders) };\n}\n\n/**\n * Creates a branch node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The branch node JSON definition.\n */\nfunction createBranchNode(\n tokens: string[],\n stringLiteralPlaceholders: StringLiteralPlaceholders\n): BranchNodeDefinition {\n // Parse any node arguments, we should have one which will be an identifier argument for the root ref.\n const nodeArguments = parseArgumentTokens(tokens, stringLiteralPlaceholders);\n\n // We should have only a single identifer argument for a branch node, which is the root ref.\n if (nodeArguments.length !== 1 || nodeArguments[0].type !== \"identifier\") {\n throw new Error(\"expected single branch name argument\");\n }\n\n // Return the branch node definition.\n return { type: \"branch\", ref: nodeArguments[0].value };\n}\n", "import { RootNodeDefinition } from \"./BehaviourTreeDefinition\";\nimport { flattenDefinition, isBranchNode, isInteger } from \"./BehaviourTreeDefinitionUtilities\";\nimport { convertMDSLToJSON } from \"./mdsl/MDSLDefinitionParser\";\n\n/**\n * An object representing the result of validating a tree definition.\n */\nexport type DefinitionValidationResult = {\n /**\n * A flag defining whether validation succeeded.\n */\n succeeded: boolean;\n /**\n * A string containing the error message if validation did not succeed.\n */\n errorMessage?: string;\n};\n\n/**\n * Validates the specified behaviour tree definition in the form of JSON or MDSL.\n * @param definition The behaviour tree definition in the form of JSON or MDSL.\n * @returns An object representing the result of validating the given tree definition.\n */\nexport function validateDefinition(definition: any): DefinitionValidationResult {\n // The definition must be defined.\n if (definition === null || typeof definition === \"undefined\") {\n return createValidationFailureResult(\"definition is null or undefined\");\n }\n\n // We are expecting a definition in one of three different forms:\n // - A string which we will assume is MDSL and we will parse this to JSON before validation.\n // - An array which we will assume is an array of root node definitions with at least one being the primary root node (no 'id' property)\n // - An object which we will assume is the primary root node and should not have an 'id' property.\n if (typeof definition === \"string\") {\n // The definition is a string which we can assume is MDSL, so attempt to validate it.\n return validateMDSLDefinition(definition);\n } else if (typeof definition === \"object\") {\n // The definition will either be an array (of root node definitions) or an object (the single primary root node definition).\n return validateJSONDefinition(definition);\n } else {\n return createValidationFailureResult(`unexpected definition type of '${typeof definition}'`);\n }\n}\n\n/**\n * Validates the specified behaviour tree definition in the form of MDSL.\n * @param definition The behaviour tree definition in the form of MDSL.\n * @returns An object representing the result of validating the given tree definition.\n */\nexport function validateMDSLDefinition(definition: string): DefinitionValidationResult {\n let rootNodeDefinitions;\n\n // The first thing the we need to do is to attempt to convert our MDSL into JSON.\n try {\n // The definition is a string which we can assume is MDSL, so attempt to parse it to a JSON definition in the form of an array of root node definitions.\n rootNodeDefinitions = convertMDSLToJSON(definition);\n } catch (error) {\n // We failed to parse the JSON from the MDSL, this is likely to be the result of it not being a valid MDSL string.\n return createValidationFailureResult(`invalid MDSL: ${definition}`);\n }\n\n // Unpack all of the root node definitions into arrays of main ('id' defined) and sub ('id' not defined) root node definitions.\n const mainRootNodeDefinitions = rootNodeDefinitions.filter(({ id }) => typeof id === \"undefined\");\n const subRootNodeDefinitions = rootNodeDefinitions.filter(({ id }) => typeof id === \"string\" && id.length > 0);\n\n // We should ALWAYS have exactly one root node definition without an 'id' property defined, which is out main root node definition.\n if (mainRootNodeDefinitions.length !== 1) {\n return createValidationFailureResult(\n \"expected single unnamed root node at base of definition to act as main root\"\n );\n }\n\n // We should never have duplicate 'id' properties across our sub root node definitions.\n const subRootNodeIdenitifers: string[] = [];\n for (const { id } of subRootNodeDefinitions) {\n // Have we already come across this 'id' property value?\n if (subRootNodeIdenitifers.includes(id!)) {\n return createValidationFailureResult(`multiple root nodes found with duplicate name '${id}'`);\n }\n\n subRootNodeIdenitifers.push(id!);\n }\n\n // Check for any branch node circular depedencies. This will NOT include any globally registered subtrees.\n const circularDependencyPath = findBranchCircularDependencyPath(rootNodeDefinitions);\n\n // If we found a circular dependency in our root node and branch node definitions then the definition is definitely not valid.\n if (circularDependencyPath) {\n return createValidationFailureResult(\n `circular dependency found in branch node references: ${circularDependencyPath}`\n );\n }\n\n // Our definition was valid!\n return { succeeded: true };\n}\n\n/**\n * Validates the specified behaviour tree definition in the form of JSON.\n * @param definition The behaviour tree definition in the form of JSON.\n * @returns An object representing the result of validating the given tree definition.\n */\nexport function validateJSONDefinition(\n definition: RootNodeDefinition | RootNodeDefinition[]\n): DefinitionValidationResult {\n // The definition will either be an array (of root node definitions) or an object (the single primary root node definition).\n const rootNodeDefinitions = Array.isArray(definition) ? definition : [definition];\n\n // Iterate over our array of root nodes and call validateNode for each, passing an initial depth of 0, wrapped in a try catch to handle validation failures.\n try {\n rootNodeDefinitions.forEach((rootNodeDefinition) => validateNode(rootNodeDefinition, 0));\n } catch (error) {\n // Handle cases where we have caught a thrown Error and return a failure result with the error message.\n if (error instanceof Error) {\n return createValidationFailureResult(error.message);\n }\n\n // No idea what happened here!\n return createValidationFailureResult(`unexpected error: ${error}`);\n }\n\n // Unpack all of the root node definitions into arrays of main ('id' defined) and sub ('id' not defined) root node definitions.\n const mainRootNodeDefinitions = rootNodeDefinitions.filter(({ id }) => typeof id === \"undefined\");\n const subRootNodeDefinitions = rootNodeDefinitions.filter(({ id }) => typeof id === \"string\" && id.length > 0);\n\n // We should ALWAYS have exactly one root node definition without an 'id' property defined, which is out main root node definition.\n if (mainRootNodeDefinitions.length !== 1) {\n return createValidationFailureResult(\n \"expected single root node without 'id' property defined to act as main root\"\n );\n }\n\n // We should never have duplicate 'id' properties across our sub root node definitions.\n const subRootNodeIdenitifers: string[] = [];\n for (const { id } of subRootNodeDefinitions) {\n // Have we already come across this 'id' property value?\n if (subRootNodeIdenitifers.includes(id!)) {\n return createValidationFailureResult(\n `multiple root nodes found with duplicate 'id' property value of '${id}'`\n );\n }\n\n subRootNodeIdenitifers.push(id!);\n }\n\n // Check for any branch node circular depedencies. This will NOT include any globally registered subtrees.\n const circularDependencyPath = findBranchCircularDependencyPath(rootNodeDefinitions);\n\n // If we found a circular dependency in our root node and branch node definitions then the definition is definitely not valid.\n if (circularDependencyPath) {\n return createValidationFailureResult(\n `circular dependency found in branch node references: ${circularDependencyPath}`\n );\n }\n\n // Our definition was valid!\n return { succeeded: true };\n}\n\n/**\n * Find the first circular depdendency path present in the array of root node definitions, or null if one doesn't exist.\n * This will not consider branch nodes that reference any globally registered subtrees.\n * @param rootNodeDefinitions The array of root node definitions.\n * @returns The first circular depdendency path present in the array of root node definitions as string, or null if one doesn't exist.\n */\nfunction findBranchCircularDependencyPath(rootNodeDefinitions: RootNodeDefinition[]): string | null {\n // Create a mapping of root node identifiers to other root nodes that they reference via branch nodes.\n // Below is an example of a mapping that includes a circular dependency (root => a => b => c => a)\n // [{ refs: [\"a\", \"b\"] }, { id: \"a\", refs: [\"b\"] }, { id: \"b\", refs: [\"c\"] }, { id: \"c\", refs: [\"a\"] }]\n const rootNodeMappings: { id: string | undefined; refs: string[] }[] = rootNodeDefinitions.map(\n (rootNodeDefinition) => ({\n id: rootNodeDefinition.id,\n refs: flattenDefinition(rootNodeDefinition)\n .filter(isBranchNode)\n .map(({ ref }) => ref)\n })\n );\n\n let badPathFormatted: string | null = null;\n\n // A recursive function to walk through the mappings, keeping track of which root nodes we have visited in the form of a path of root node identifiers.\n const followRefs = (mapping: { id: string | undefined; refs: string[] }, path: (string | undefined)[] = []) => {\n // Have we found a circular dependency?\n if (path.includes(mapping.id)) {\n // We found a circular dependency! Get the bad path of root node identifiers.\n const badPath = [...path, mapping.id];\n\n // Set the formatted path value. [undefined, \"a\", \"b\", \"c\", \"a\"] would be formatted as \"a -> b -> c -> a\".\n badPathFormatted = badPath.filter((element) => !!element).join(\" => \");\n\n // No need to continue, we found a circular dependency.\n return;\n }\n\n for (const ref of mapping.refs) {\n // Find the mapping for the root node with an identifer matching the current ref.\n const subMapping = rootNodeMappings.find(({ id }) => id === ref);\n\n // We may not have a mapping for this ref, which will happen if this ref is for a globally registered subtree.\n if (subMapping) {\n followRefs(subMapping, [...path, mapping.id]);\n }\n }\n };\n\n // Start looking for circular dependencies from the root.\n followRefs(rootNodeMappings.find((mapping) => typeof mapping.id === \"undefined\")!);\n\n return badPathFormatted;\n}\n\n/**\n * Validate an object that we expect to be a node definition.\n * @param definition An object that we expect to be a node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateNode(definition: any, depth: number): void {\n // Every node must be valid object and have a non-empty 'type' string property.\n if (typeof definition !== \"object\" || typeof definition.type !== \"string\" || definition.type.length === 0) {\n throw new Error(\n `node definition is not an object or 'type' property is not a non-empty string at depth '${depth}'`\n );\n }\n\n // How we validate this node definition will depend on its type.\n switch (definition.type) {\n case \"action\":\n validateActionNode(definition, depth);\n break;\n\n case \"condition\":\n validateConditionNode(definition, depth);\n break;\n\n case \"wait\":\n validateWaitNode(definition, depth);\n break;\n\n case \"branch\":\n validateBranchNode(definition, depth);\n break;\n\n case \"root\":\n validateRootNode(definition, depth);\n break;\n\n case \"success\":\n validateSuccessNode(definition, depth);\n break;\n\n case \"fail\":\n validateFailNode(definition, depth);\n break;\n\n case \"flip\":\n validateFlipNode(definition, depth);\n break;\n\n case \"repeat\":\n validateRepeatNode(definition, depth);\n break;\n\n case \"retry\":\n validateRetryNode(definition, depth);\n break;\n\n case \"sequence\":\n validateSequenceNode(definition, depth);\n break;\n\n case \"selector\":\n validateSelectorNode(definition, depth);\n break;\n\n case \"parallel\":\n validateParallelNode(definition, depth);\n break;\n\n default:\n throw new Error(`unexpected node type of '${definition.type}' at depth '${depth}'`);\n }\n}\n\n/**\n * Validate any attributes for a given node definition.\n * @param definition The node definition.\n * @param depth The depth of the node in the behaviour tree definition.\n */\nfunction validateNodeAttributes(definition: any, depth: number): void {\n // Validate each of the attribute types for this node.\n [\"while\", \"until\", \"entry\", \"exit\", \"step\"].forEach((attributeName) => {\n // Attempt to grab the definition for the current attribute from the node definition.\n const attributeDefinition = definition[attributeName];\n\n // All node attributes are optional, so there is nothing to do if the current attribute is not defined.\n if (typeof attributeDefinition === \"undefined\") {\n return;\n }\n\n // The attribute definition must be an object.\n if (typeof attributeDefinition !== \"object\") {\n throw new Error(\n `expected attribute '${attributeName}' to be an object for '${definition.type}' node at depth '${depth}'`\n );\n }\n\n // The 'call' property must be defined for any attribute definition.\n if (typeof attributeDefinition.call !== \"string\" || attributeDefinition.call.length === 0) {\n throw new Error(\n `expected 'call' property for attribute '${attributeName}' to be a non-empty string for '${definition.type}' node at depth '${depth}'`\n );\n }\n\n // If any node attribute arguments have been defined then they must have been defined in an array.\n if (typeof attributeDefinition.args !== \"undefined\" && !Array.isArray(attributeDefinition.args)) {\n throw new Error(\n `expected 'args' property for attribute '${attributeName}' to be an array for '${definition.type}' node at depth '${depth}'`\n );\n }\n });\n}\n\n/**\n * Validate an object that we expect to be a root node definition.\n * @param definition An object that we expect to be a root node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateRootNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"root\") {\n throw new Error(\"expected node type of 'root' for root node\");\n }\n\n // A root node cannot be the child of another node.\n if (depth > 0) {\n throw new Error(\"a root node cannot be the child of another node\");\n }\n\n // Check that, if the root node 'id' property is defined, it is a non-empty string.\n if (typeof definition.id !== \"undefined\" && (typeof definition.id !== \"string\" || definition.id.length === 0)) {\n throw new Error(\"expected non-empty string for 'id' property if defined for root node\");\n }\n\n // A root node is a decorator node, so must have a child node defined.\n if (typeof definition.child === \"undefined\") {\n throw new Error(\"expected property 'child' to be defined for root node\");\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n\n // Validate the child node of this decorator node.\n validateNode(definition.child, depth + 1);\n}\n\n/**\n * Validate an object that we expect to be a success node definition.\n * @param definition An object that we expect to be a success node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateSuccessNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"success\") {\n throw new Error(`expected node type of 'success' for success node at depth '${depth}'`);\n }\n\n // A success node is a decorator node, so must have a child node defined.\n if (typeof definition.child === \"undefined\") {\n throw new Error(`expected property 'child' to be defined for success node at depth '${depth}'`);\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n\n // Validate the child node of this decorator node.\n validateNode(definition.child, depth + 1);\n}\n\n/**\n * Validate an object that we expect to be a fail node definition.\n * @param definition An object that we expect to be a fail node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateFailNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"fail\") {\n throw new Error(`expected node type of 'fail' for fail node at depth '${depth}'`);\n }\n\n // A fail node is a decorator node, so must have a child node defined.\n if (typeof definition.child === \"undefined\") {\n throw new Error(`expected property 'child' to be defined for fail node at depth '${depth}'`);\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n\n // Validate the child node of this decorator node.\n validateNode(definition.child, depth + 1);\n}\n\n/**\n * Validate an object that we expect to be a flip node definition.\n * @param definition An object that we expect to be a flip node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateFlipNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"flip\") {\n throw new Error(`expected node type of 'flip' for flip node at depth '${depth}'`);\n }\n\n // A flip node is a decorator node, so must have a child node defined.\n if (typeof definition.child === \"undefined\") {\n throw new Error(`expected property 'child' to be defined for flip node at depth '${depth}'`);\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n\n // Validate the child node of this decorator node.\n validateNode(definition.child, depth + 1);\n}\n\n/**\n * Validate an object that we expect to be a repeat node definition.\n * @param definition An object that we expect to be a repeat node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateRepeatNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"repeat\") {\n throw new Error(`expected node type of 'repeat' for repeat node at depth '${depth}'`);\n }\n\n // A repeat node is a decorator node, so must have a child node defined.\n if (typeof definition.child === \"undefined\") {\n throw new Error(`expected property 'child' to be defined for repeat node at depth '${depth}'`);\n }\n\n // Check whether an 'iterations' property has been defined, it may not have been if this node is to repeat indefinitely.\n if (typeof definition.iterations !== \"undefined\") {\n if (Array.isArray(definition.iterations)) {\n // Check whether any elements of the array are not integer values.\n const containsNonInteger = !!definition.iterations.find((value: unknown) => !isInteger(value));\n\n // If the 'iterations' property is an array then it MUST contain two integer values.\n if (definition.iterations.length !== 2 || containsNonInteger) {\n throw new Error(\n `expected array containing two integer values for 'iterations' property if defined for repeat node at depth '${depth}'`\n );\n }\n } else if (!isInteger(definition.iterations)) {\n throw new Error(\n `expected integer value or array containing two integer values for 'iterations' property if defined for repeat node at depth '${depth}'`\n );\n }\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n\n // Validate the child node of this decorator node.\n validateNode(definition.child, depth + 1);\n}\n\n/**\n * Validate an object that we expect to be a retry node definition.\n * @param definition An object that we expect to be a retry node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateRetryNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"retry\") {\n throw new Error(`expected node type of 'retry' for retry node at depth '${depth}'`);\n }\n\n // A retry node is a decorator node, so must have a child node defined.\n if (typeof definition.child === \"undefined\") {\n throw new Error(`expected property 'child' to be defined for retry node at depth '${depth}'`);\n }\n\n // Check whether an 'attempts' property has been defined, it may not have been if this node is to retry indefinitely.\n if (typeof definition.attempts !== \"undefined\") {\n if (Array.isArray(definition.attempts)) {\n // Check whether any elements of the array are not integer values.\n const containsNonInteger = !!definition.attempts.find((value: unknown) => !isInteger(value));\n\n // If the 'attempts' property is an array then it MUST contain two integer values.\n if (definition.attempts.length !== 2 || containsNonInteger) {\n throw new Error(\n `expected array containing two integer values for 'attempts' property if defined for retry node at depth '${depth}'`\n );\n }\n } else if (!isInteger(definition.attempts)) {\n throw new Error(\n `expected integer value or array containing two integer values for 'attempts' property if defined for retry node at depth '${depth}'`\n );\n }\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n\n // Validate the child node of this decorator node.\n validateNode(definition.child, depth + 1);\n}\n\n/**\n * Validate an object that we expect to be a branch node definition.\n * @param definition An object that we expect to be a branch node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateBranchNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"branch\") {\n throw new Error(`expected node type of 'branch' for branch node at depth '${depth}'`);\n }\n\n // Check that the branch node 'ref' property is defined and is a non-empty string.\n if (typeof definition.ref !== \"string\" || definition.ref.length === 0) {\n throw new Error(`expected non-empty string for 'ref' property for branch node at depth '${depth}'`);\n }\n\n // It is invalid to define guard attributes for a branch node as they should be defined on the referenced root node.\n [\"while\", \"until\"].forEach((attributeName) => {\n if (typeof definition[attributeName] !== \"undefined\") {\n throw new Error(\n `guards should not be defined for branch nodes but guard '${attributeName}' was defined for branch node at depth '${depth}'`\n );\n }\n });\n\n // It is invalid to define callback attributes for a branch node as they should be defined on the referenced root node.\n [\"entry\", \"exit\", \"step\"].forEach((attributeName) => {\n if (typeof definition[attributeName] !== \"undefined\") {\n throw new Error(\n `callbacks should not be defined for branch nodes but callback '${attributeName}' was defined for branch node at depth '${depth}'`\n );\n }\n });\n}\n\n/**\n * Validate an object that we expect to be a action node definition.\n * @param definition An object that we expect to be a action node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateActionNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"action\") {\n throw new Error(`expected node type of 'action' for action node at depth '${depth}'`);\n }\n\n // The 'call' property must be defined for a action node definition.\n if (typeof definition.call !== \"string\" || definition.call.length === 0) {\n throw new Error(`expected non-empty string for 'call' property of action node at depth '${depth}'`);\n }\n\n // If any action function arguments have been defined then they must have been defined in an array.\n if (typeof definition.args !== \"undefined\" && !Array.isArray(definition.args)) {\n throw new Error(`expected array for 'args' property if defined for action node at depth '${depth}'`);\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n}\n\n/**\n * Validate an object that we expect to be a condition node definition.\n * @param definition An object that we expect to be a condition node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateConditionNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"condition\") {\n throw new Error(`expected node type of 'condition' for condition node at depth '${depth}'`);\n }\n\n // The 'call' property must be defined for a condition node definition.\n if (typeof definition.call !== \"string\" || definition.call.length === 0) {\n throw new Error(`expected non-empty string for 'call' property of condition node at depth '${depth}'`);\n }\n\n // If any condition function arguments have been defined then they must have been defined in an array.\n if (typeof definition.args !== \"undefined\" && !Array.isArray(definition.args)) {\n throw new Error(`expected array for 'args' property if defined for condition node at depth '${depth}'`);\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n}\n\n/**\n * Validate an object that we expect to be a wait node definition.\n * @param definition An object that we expect to be a wait node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateWaitNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"wait\") {\n throw new Error(`expected node type of 'wait' for wait node at depth '${depth}'`);\n }\n\n // Check whether a 'duration' property has been defined, it may not have been if this node is to wait indefinitely.\n if (typeof definition.duration !== \"undefined\") {\n if (Array.isArray(definition.duration)) {\n // Check whether any elements of the array are not integer values.\n const containsNonInteger = !!definition.duration.find((value: unknown) => !isInteger(value));\n\n // If the 'duration' property is an array then it MUST contain two integer values.\n if (definition.duration.length !== 2 || containsNonInteger) {\n throw new Error(\n `expected array containing two integer values for 'duration' property if defined for wait node at depth '${depth}'`\n );\n }\n } else if (!isInteger(definition.duration)) {\n throw new Error(\n `expected integer value or array containing two integer values for 'duration' property if defined for wait node at depth '${depth}'`\n );\n }\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n}\n\n/**\n * Validate an object that we expect to be a sequence node definition.\n * @param definition An object that we expect to be a sequence node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateSequenceNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"sequence\") {\n throw new Error(`expected node type of 'sequence' for sequence node at depth '${depth}'`);\n }\n\n // A sequence node is a composite node, so must have a children nodes array defined.\n if (!Array.isArray(definition.children) || definition.children.length === 0) {\n throw new Error(`expected non-empty 'children' array to be defined for sequence node at depth '${depth}'`);\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n\n // Validate the child nodes of this composite node.\n definition.children.forEach((child: any) => validateNode(child, depth + 1));\n}\n\n/**\n * Validate an object that we expect to be a selector node definition.\n * @param definition An object that we expect to be a selector node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateSelectorNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"selector\") {\n throw new Error(`expected node type of 'selector' for selector node at depth '${depth}'`);\n }\n\n // A selector node is a composite node, so must have a children nodes array defined.\n if (!Array.isArray(definition.children) || definition.children.length === 0) {\n throw new Error(`expected non-empty 'children' array to be defined for selector node at depth '${depth}'`);\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n\n // Validate the child nodes of this composite node.\n definition.children.forEach((child: any) => validateNode(child, depth + 1));\n}\n\n/**\n * Validate an object that we expect to be a parallel node definition.\n * @param definition An object that we expect to be a parallel node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateParallelNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"parallel\") {\n throw new Error(`expected node type of 'parallel' for parallel node at depth '${depth}'`);\n }\n\n // A parallel node is a composite node, so must have a children nodes array defined.\n if (!Array.isArray(definition.children) || definition.children.length === 0) {\n throw new Error(`expected non-empty 'children' array to be defined for parallel node at depth '${depth}'`);\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n\n // Validate the child nodes of this composite node.\n definition.children.forEach((child: any) => validateNode(child, depth + 1));\n}\n\n/**\n * A helper function to create a failure validation result with the given error message.\n * @param errorMessage The validation failure error message.\n * @returns A failure validation result with the given error message.\n */\nfunction createValidationFailureResult(errorMessage: string): DefinitionValidationResult {\n return { succeeded: false, errorMessage };\n}\n", "import Node from \"../../nodes/Node\";\n\n/**\n * An exception thrown when evaluating node guard path conditions and a conditions fails.\n */\nexport default class GuardUnsatisifedException extends Error {\n /**\n * @param source The node at which a guard condition failed.\n */\n constructor(private source: Node) {\n super(\"A guard path condition has failed\");\n }\n\n /**\n * Gets whether the specified node is the node at which a guard condition failed.\n * @param node The node to check against the source node.\n * @returns Whether the specified node is the node at which a guard condition failed.\n */\n isSourceNode = (node: Node) => node === this.source;\n}\n", "import { Agent } from \"../../Agent\";\nimport Guard from \"./Guard\";\nimport Node from \"../../nodes/Node\";\nimport GuardUnsatisifedException from \"./GuardUnsatisifedException\";\n\nexport type GuardPathPart = {\n node: Node;\n guards: Guard[];\n};\n\n/**\n * Represents a path of node guards along a root-to-leaf tree path.\n */\nexport default class GuardPath {\n /**\n * @param nodes An array of objects defining a node instance -> guard link, ordered by node depth.\n */\n constructor(private nodes: GuardPathPart[]) {}\n\n /**\n * Evaluate guard conditions for all guards in the tree path, moving outwards from the root.\n * @param agent The agent, required for guard evaluation.\n * @returns An evaluation results object.\n */\n evaluate = (agent: Agent) => {\n // We need to evaluate guard conditions for nodes up the tree, moving outwards from the root.\n for (const details of this.nodes) {\n // There can be multiple guards per node.\n for (const guard of details.guards) {\n // Check whether the guard condition passes, and throw an exception if not.\n if (!guard.isSatisfied(agent)) {\n throw new GuardUnsatisifedException(details.node);\n }\n }\n }\n };\n}\n", "import { Agent } from \"../Agent\";\nimport Attribute from \"../attributes/Attribute\";\nimport Entry from \"../attributes/callbacks/Entry\";\nimport Exit from \"../attributes/callbacks/Exit\";\nimport Step from \"../attributes/callbacks/Step\";\nimport Guard from \"../attributes/guards/Guard\";\nimport GuardPath from \"../attributes/guards/GuardPath\";\nimport GuardUnsatisifedException from \"../attributes/guards/GuardUnsatisifedException\";\nimport { BehaviourTreeOptions } from \"../BehaviourTreeOptions\";\nimport { AnyArgument } from \"../RootAstNodesBuilder\";\nimport State, { AnyState } from \"../State\";\nimport Leaf from \"./leaf/Leaf\";\n\n/**\n * A base node.\n */\nexport default abstract class Node {\n /**\n * The node uid.\n */\n private readonly uid: string = createNodeUid();\n /**\n * The node state.\n */\n private state: AnyState = State.READY;\n /**\n * The guard path to evaluate as part of a node update.\n */\n private guardPath: GuardPath | undefined;\n\n /**\n * @param type The node type.\n * @param attributes The node attributes.\n * @param args The node argument definitions.\n */\n constructor(private type: string, private attributes: Attribute[], private args: AnyArgument[]) {}\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected abstract onUpdate(agent: Agent, options: BehaviourTreeOptions): void;\n\n /**\n * Gets the name of the node.\n */\n public abstract getName(): string;\n\n /**\n * Gets whether this node is a leaf node.\n */\n public abstract isLeafNode: () => this is Leaf;\n\n /**\n * Gets/Sets the state of the node.\n */\n getState = (): AnyState => this.state;\n setState = (value: AnyState): void => {\n this.state = value;\n };\n\n /**\n * Gets the unique id of the node.\n */\n getUid = () => this.uid;\n\n /**\n * Gets the type of the node.\n */\n getType = () => this.type;\n\n /**\n * Gets the node attributes.\n */\n getAttributes = () => this.attributes;\n\n /**\n * Gets the node arguments.\n */\n getArguments = () => this.args;\n\n /**\n * Gets the node attribute with the specified type, or null if it does not exist.\n */\n getAttribute(type: \"entry\" | \"ENTRY\"): Entry;\n getAttribute(type: \"exit\" | \"EXIT\"): Exit;\n getAttribute(type: \"step\" | \"STEP\"): Step;\n getAttribute(type: string): Attribute {\n return (\n this.getAttributes().filter((decorator) => decorator.getType().toUpperCase() === type.toUpperCase())[0] ||\n null\n );\n }\n\n /**\n * Gets the node attributes.\n */\n getGuardAttributes = (): Guard[] => this.getAttributes().filter((decorator) => decorator.isGuard()) as Guard[];\n\n /**\n * Sets the guard path to evaluate as part of a node update.\n */\n setGuardPath = (value: GuardPath) => (this.guardPath = value);\n\n /**\n * Gets whether a guard path is assigned to this node.\n */\n hasGuardPath = () => !!this.guardPath;\n\n /**\n * Gets whether this node is in the specified state.\n * @param value The value to compare to the node state.\n */\n public is(value: AnyState): boolean {\n return this.state === value;\n }\n\n /**\n * Reset the state of the node.\n */\n public reset(): void {\n this.setState(State.READY);\n }\n\n /**\n * Abort the running of this node.\n * @param agent The agent.\n */\n public abort(agent: Agent): void {\n // There is nothing to do if this node is not in the running state.\n if (!this.is(State.RUNNING)) {\n return;\n }\n\n // Reset the state of this node.\n this.reset();\n\n this.getAttribute(\"exit\")?.callAgentFunction(agent, false, true);\n }\n\n /**\n * Update the node.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n * @returns The result of the update.\n */\n public update(agent: Agent, options: BehaviourTreeOptions): void {\n // If this node is already in a 'SUCCEEDED' or 'FAILED' state then there is nothing to do.\n if (this.is(State.SUCCEEDED) || this.is(State.FAILED)) {\n return;\n }\n\n try {\n // Evaluate all of the guard path conditions for the current tree path.\n this.guardPath!.evaluate(agent);\n\n // If this node is in the READY state then call the ENTRY for this node if it exists.\n if (this.is(State.READY)) {\n this.getAttribute(\"entry\")?.callAgentFunction(agent);\n }\n\n this.getAttribute(\"step\")?.callAgentFunction(agent);\n\n // Do the actual update.\n this.onUpdate(agent, options);\n\n // If this node is now in a 'SUCCEEDED' or 'FAILED' state then call the EXIT for this node if it exists.\n if (this.is(State.SUCCEEDED) || this.is(State.FAILED)) {\n this.getAttribute(\"exit\")?.callAgentFunction(agent, this.is(State.SUCCEEDED), false);\n }\n } catch (error) {\n // If the error is a GuardUnsatisfiedException then we need to determine if this node is the source.\n if (error instanceof GuardUnsatisifedException && error.isSourceNode(this)) {\n // Abort the current node.\n this.abort(agent);\n\n // Any node that is the source of an abort will be a failed node.\n this.setState(State.FAILED);\n } else {\n throw error;\n }\n }\n }\n}\n\n/**\n * Create a randomly generated node uid.\n * @returns A randomly generated node uid.\n */\nfunction createNodeUid(): string {\n var S4 = function () {\n return (((1 + Math.random()) * 0x10000) | 0).toString(16).substring(1);\n };\n return S4() + S4() + \"-\" + S4() + \"-\" + S4() + \"-\" + S4() + \"-\" + S4() + S4() + S4();\n}\n", "import Node from \"../Node\";\n\n/**\n * A leaf node.\n */\nexport default abstract class Leaf extends Node {\n /**\n * Gets whether this node is a leaf node.\n */\n isLeafNode = () => true;\n}\n", "import { ActionResult, Agent, ExitFunctionArg, FunctionArg, GlobalFunction } from \"./Agent\";\nimport { AnyArgument, RootAstNode } from \"./RootAstNodesBuilder\";\n\n// Exit callbacks receive their own special type of argument.\n// There's probably stricter ways to represent this but it feels overly complex right now.\ntype ExitResultArg = { value: ExitFunctionArg };\nexport type AnyExitArgument = AnyArgument | ExitResultArg;\n\nexport type InvokerFunction = (args: AnyExitArgument[]) => ActionResult;\n\n/**\n * A singleton used to store and lookup registered functions and subtrees.\n */\nexport default class Lookup {\n /**\n * The object holding any registered functions keyed on function name.\n */\n private static functionTable: { [key: string]: GlobalFunction } = {};\n /**\n * The object holding any registered sub-trees keyed on tree name.\n */\n private static subtreeTable: { [key: string]: RootAstNode } = {};\n\n /**\n * Gets the function with the specified name.\n * @param name The name of the function.\n * @returns The function with the specified name.\n */\n public static getFunc(name: string): GlobalFunction {\n return this.functionTable[name];\n }\n\n /**\n * Sets the function with the specified name for later lookup.\n * @param name The name of the function.\n * @param func The function.\n */\n public static setFunc(name: string, func: GlobalFunction): void {\n this.functionTable[name] = func;\n }\n\n /**\n * Gets the function invoker for the specified agent and function name.\n * If a function with the specified name exists on the agent object then it will\n * be returned, otherwise we will then check the registered functions for a match.\n * @param agent The agent instance that this behaviour tree is modelling behaviour for.\n * @param name The function name.\n * @returns The function invoker for the specified agent and function name.\n */\n static getFuncInvoker(agent: Agent, name: string): InvokerFunction | null {\n // Check whether the agent contains the specified function.\n const foundOnAgent = agent[name];\n if (foundOnAgent && typeof foundOnAgent === \"function\") {\n return (args: AnyExitArgument[]): boolean | ActionResult =>\n foundOnAgent.apply(\n agent,\n args.map((arg) => arg.value)\n );\n }\n\n // The agent does not contain the specified function but it may have been registered at some point.\n if (this.functionTable[name] && typeof this.functionTable[name] === \"function\") {\n return (args: AnyExitArgument[]) => this.functionTable[name](agent, ...args.map((arg) => arg.value));\n }\n\n // We have no function to invoke.\n return null;\n }\n\n /**\n * Gets the subtree with the specified name.\n * @param name The name of the subtree.\n * @returns The subtree with the specified name.\n */\n static getSubtree(name: string): RootAstNode {\n return this.subtreeTable[name];\n }\n\n /**\n * Sets the subtree with the specified name for later lookup.\n * @param name The name of the subtree.\n * @param subtree The subtree.\n */\n static setSubtree(name: string, subtree: RootAstNode) {\n this.subtreeTable[name] = subtree;\n }\n\n /**\n * Removes the registered function or subtree with the specified name.\n * @param name The name of the registered function or subtree.\n */\n static remove(name: string) {\n delete this.functionTable[name];\n delete this.subtreeTable[name];\n }\n\n /**\n * Remove all registered functions and subtrees.\n */\n static empty() {\n this.functionTable = {};\n this.subtreeTable = {};\n }\n}\n", "import Leaf from \"./Leaf\";\nimport State, { CompleteState } from \"../../State\";\nimport Lookup from \"../../Lookup\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { AnyArgument } from \"../../RootAstNodesBuilder\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * An Action leaf node.\n * This represents an immediate or ongoing state of behaviour.\n */\nexport default class Action extends Leaf {\n /**\n * @param attributes The node attributes.\n * @param actionName The action name.\n * @param actionArguments The array of action argument definitions.\n */\n constructor(attributes: Attribute[], private actionName: string, private actionArguments: AnyArgument[]) {\n super(\"action\", attributes, actionArguments);\n }\n\n /**\n * Whether there is a pending update promise.\n */\n private isUsingUpdatePromise = false;\n\n /**\n * The finished state result of an update promise.\n */\n private updatePromiseStateResult: CompleteState | null = null;\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // If the result of this action depends on an update promise then there is nothing to do until\n // it resolves, unless there has been a value set as a result of the update promise resolving.\n if (this.isUsingUpdatePromise) {\n // Check whether the update promise has resolved with a state value.\n if (this.updatePromiseStateResult) {\n // Set the state of this node to match the state returned by the promise.\n this.setState(this.updatePromiseStateResult);\n }\n\n return;\n }\n\n // Attempt to get the invoker for the action function.\n const actionFuncInvoker = Lookup.getFuncInvoker(agent, this.actionName);\n\n // The action function should be defined.\n if (actionFuncInvoker === null) {\n throw new Error(\n `cannot update action node as the action '${this.actionName}' function is not defined on the agent and has not been registered`\n );\n }\n\n // Call the action function, the result of which may be:\n // - The finished state of this action node.\n // - A promise to return a finished node state.\n // - Undefined if the node should remain in the running state.\n const updateResult = actionFuncInvoker(this.actionArguments) as CompleteState | Promise;\n\n if (updateResult instanceof Promise) {\n updateResult.then(\n (result) => {\n // If 'isUpdatePromisePending' is null then the promise was cleared as it was resolving, probably via an abort of reset.\n if (!this.isUsingUpdatePromise) {\n return;\n }\n\n // Check to make sure the result is a valid finished state.\n if (result !== State.SUCCEEDED && result !== State.FAILED) {\n throw new Error(\n \"action node promise resolved with an invalid value, expected a State.SUCCEEDED or State.FAILED value to be returned\"\n );\n }\n\n // Set pending update promise state result to be processed on next update.\n this.updatePromiseStateResult = result;\n },\n (reason) => {\n // If 'isUpdatePromisePending' is null then the promise was cleared as it was resolving, probably via an abort of reset.\n if (!this.isUsingUpdatePromise) {\n return;\n }\n\n // Just throw whatever was returned as the rejection argument.\n throw new Error(reason);\n }\n );\n\n // This node will be in the 'RUNNING' state until the update promise resolves.\n this.setState(State.RUNNING);\n\n // We are now waiting for the promise returned by the use to resolve before we know what state this node is in.\n this.isUsingUpdatePromise = true;\n } else {\n // Validate the returned value.\n this.validateUpdateResult(updateResult);\n\n // Set the state of this node, this may be undefined, which just means that the node is still in the 'RUNNING' state.\n this.setState(updateResult || State.RUNNING);\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => this.actionName;\n\n /**\n * Reset the state of the node.\n */\n reset = () => {\n // Reset the state of this node.\n this.setState(State.READY);\n\n // There is no longer an update promise that we care about.\n this.isUsingUpdatePromise = false;\n this.updatePromiseStateResult = null;\n };\n\n /**\n * Validate the result of an update function call.\n * @param result The result of an update function call.\n */\n private validateUpdateResult = (result: CompleteState | boolean) => {\n switch (result) {\n case State.SUCCEEDED:\n case State.FAILED:\n case undefined:\n return;\n default:\n throw new Error(\n `action '${this.actionName}' 'onUpdate' returned an invalid response, expected an optional State.SUCCEEDED or State.FAILED value to be returned`\n );\n }\n };\n}\n", "import Leaf from \"./Leaf\";\nimport State from \"../../State\";\nimport Lookup from \"../../Lookup\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { AnyArgument } from \"../../RootAstNodesBuilder\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A Condition leaf node.\n * This will succeed or fail immediately based on an agent predicate, without moving to the 'RUNNING' state.\n */\nexport default class Condition extends Leaf {\n /**\n * @param attributes The node attributes.\n * @param conditionName The name of the condition function.\n * @param conditionArguments The array of condition argument definitions.\n */\n constructor(attributes: Attribute[], private conditionName: string, private conditionArguments: AnyArgument[]) {\n super(\"condition\", attributes, conditionArguments);\n }\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // Attempt to get the invoker for the condition function.\n const conditionFuncInvoker = Lookup.getFuncInvoker(agent, this.conditionName);\n\n // The condition function should be defined.\n if (conditionFuncInvoker === null) {\n throw new Error(\n `cannot update condition node as the condition '${this.conditionName}' function is not defined on the agent and has not been registered`\n );\n }\n\n // Call the condition function to determine the state of this node.\n this.setState(!!conditionFuncInvoker(this.conditionArguments) ? State.SUCCEEDED : State.FAILED);\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => this.conditionName;\n}\n", "import Leaf from \"./Leaf\";\nimport State from \"../../State\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { Agent } from \"../../Agent\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A WAIT node.\n * The state of this node will change to SUCCEEDED after a duration of time\n */\nexport default class Wait extends Leaf {\n /**\n * @param attributes The node attributes.\n * @param duration The duration that this node will wait to succeed in milliseconds.\n * @param durationMin The minimum possible duration in milliseconds that this node will wait to succeed.\n * @param durationMax The maximum possible duration in milliseconds that this node will wait to succeed.\n */\n constructor(\n attributes: Attribute[],\n private duration: number | null,\n private durationMin: number | null,\n private durationMax: number | null\n ) {\n super(\"wait\", attributes, []);\n }\n\n /**\n * The time in milliseconds at which this node was first updated.\n */\n private initialUpdateTime: number = 0;\n\n /**\n * The total duration in milliseconds that this node will be waiting for.\n */\n private totalDuration: number | null = null;\n\n /**\n * The duration in milliseconds that this node has been waiting for.\n */\n private waitedDuration: number = 0;\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // If this node is in the READY state then we need to set the initial update time.\n if (this.is(State.READY)) {\n // Set the initial update time.\n this.initialUpdateTime = new Date().getTime();\n\n // Set the initial waited duration.\n this.waitedDuration = 0;\n\n // Are we dealing with an explicit duration or will we be randomly picking a duration between the min and max duration.\n if (this.duration !== null) {\n this.totalDuration = this.duration;\n } else if (this.durationMin !== null && this.durationMax !== null) {\n // We will be picking a random duration between a min and max duration, if the optional 'random' behaviour tree\n // function option is defined then we will be using that, otherwise we will fall back to using Math.random.\n const random = typeof options.random === \"function\" ? options.random : Math.random;\n\n // Pick a random duration between a min and max duration.\n this.totalDuration = Math.floor(\n random() * (this.durationMax - this.durationMin + 1) + this.durationMin\n );\n } else {\n this.totalDuration = null;\n }\n\n // The node is now running until we finish waiting.\n this.setState(State.RUNNING);\n }\n\n // If we have no total duration then this wait node will wait indefinitely until it is aborted.\n if (this.totalDuration === null) {\n return;\n }\n\n // If we have a 'getDeltaTime' function defined as part of our options then we will use it to figure out how long we have waited for.\n if (typeof options.getDeltaTime === \"function\") {\n // Get the delta time.\n const deltaTime = options.getDeltaTime();\n\n // Our delta time must be a valid number and cannot be NaN.\n if (typeof deltaTime !== \"number\" || isNaN(deltaTime)) {\n throw new Error(\"The delta time must be a valid number and not NaN.\");\n }\n\n // Update the amount of time that this node has been waiting for based on the delta time.\n this.waitedDuration += deltaTime * 1000;\n } else {\n // We are not using a delta time, so we will just work out hom much time has passed since the first update.\n this.waitedDuration = new Date().getTime() - this.initialUpdateTime;\n }\n\n // Have we waited long enough?\n if (this.waitedDuration >= this.totalDuration) {\n // We have finished waiting!\n this.setState(State.SUCCEEDED);\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => {\n if (this.duration !== null) {\n return `WAIT ${this.duration}ms`;\n } else if (this.durationMin !== null && this.durationMax !== null) {\n return `WAIT ${this.durationMin}ms-${this.durationMax}ms`;\n } else {\n return \"WAIT\";\n }\n };\n}\n", "import Node from \"../Node\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\n\n/**\n * A decorator node that wraps a single child node.\n */\nexport default abstract class Decorator extends Node {\n /**\n * @param type The node type.\n * @param attributes The node attributes.\n * @param child The child node.\n */\n constructor(type: string, attributes: Attribute[], protected child: Node) {\n super(type, attributes, []);\n }\n\n /**\n * Gets whether this node is a leaf node.\n */\n isLeafNode = () => false;\n\n /**\n * Gets the children of this node.\n */\n getChildren = () => [this.child];\n\n /**\n * Reset the state of the node.\n */\n reset = () => {\n // Reset the state of this node.\n this.setState(State.READY);\n\n // Reset the state of the child node.\n this.child.reset();\n };\n\n /**\n * Abort the running of this node.\n * @param agent The agent.\n */\n abort = (agent: Agent) => {\n // There is nothing to do if this node is not in the running state.\n if (!this.is(State.RUNNING)) {\n return;\n }\n\n // Abort the child node.\n this.child.abort(agent);\n\n // Reset the state of this node.\n this.reset();\n\n this.getAttribute(\"exit\")?.callAgentFunction(agent, false, true);\n };\n}\n", "import Node from \"../Node\";\nimport Decorator from \"./Decorator\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A Root node.\n * The root node will have a single child.\n */\nexport default class Root extends Decorator {\n /**\n * @param attributes The node attributes.\n * @param child The child node.\n */\n constructor(attributes: Attribute[], child: Node) {\n super(\"root\", attributes, child);\n }\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // If the child has never been updated or is running then we will need to update it now.\n if (this.child.getState() === State.READY || this.child.getState() === State.RUNNING) {\n // Update the child of this node.\n this.child.update(agent, options);\n }\n\n // The state of the root node is the state of its child.\n this.setState(this.child.getState());\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => \"ROOT\";\n}\n", "import Node from \"../Node\";\nimport Decorator from \"./Decorator\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A REPEAT node.\n * The node has a single child which can have:\n * -- A number of iterations for which to repeat the child node.\n * -- An infinite repeat loop if neither an iteration count or a condition function is defined.\n * The REPEAT node will stop and have a 'FAILED' state if its child is ever in a 'FAILED' state after an update.\n * The REPEAT node will attempt to move on to the next iteration if its child is ever in a 'SUCCEEDED' state.\n */\nexport default class Repeat extends Decorator {\n /**\n * @param attributes The node attributes.\n * @param iterations The number of iterations to repeat the child node.\n * @param iterationsMin The minimum possible number of iterations to repeat the child node.\n * @param iterationsMax The maximum possible number of iterations to repeat the child node.\n * @param child The child node.\n */\n constructor(\n attributes: Attribute[],\n private iterations: number | null,\n private iterationsMin: number | null,\n private iterationsMax: number | null,\n child: Node\n ) {\n super(\"repeat\", attributes, child);\n }\n\n /**\n * The number of target iterations to make.\n */\n private targetIterationCount: number | null = null;\n\n /**\n * The current iteration count.\n */\n private currentIterationCount: number = 0;\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // If this node is in the READY state then we need to reset the child and the target iteration count.\n if (this.is(State.READY)) {\n // Reset the child node.\n this.child.reset();\n\n // Reset the current iteration count.\n this.currentIterationCount = 0;\n\n // Set the target iteration count.\n this.setTargetIterationCount(options);\n }\n\n // Do a check to see if we can iterate. If we can then this node will move into the 'RUNNING' state.\n // If we cannot iterate then we have hit our target iteration count, which means that the node has succeeded.\n if (this.canIterate()) {\n // This node is in the running state and can do its initial iteration.\n this.setState(State.RUNNING);\n\n // We may have already completed an iteration, meaning that the child node will be in the SUCCEEDED state.\n // If this is the case then we will have to reset the child node now.\n if (this.child.getState() === State.SUCCEEDED) {\n this.child.reset();\n }\n\n // Update the child of this node.\n this.child.update(agent, options);\n\n // If the child moved into the FAILED state when we updated it then there is nothing left to do and this node has also failed.\n // If it has moved into the SUCCEEDED state then we have completed the current iteration.\n if (this.child.getState() === State.FAILED) {\n // The child has failed, meaning that this node has failed.\n this.setState(State.FAILED);\n\n return;\n } else if (this.child.getState() === State.SUCCEEDED) {\n // We have completed an iteration.\n this.currentIterationCount += 1;\n }\n } else {\n // This node is in the 'SUCCEEDED' state as we cannot iterate any more.\n this.setState(State.SUCCEEDED);\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => {\n if (this.iterations !== null) {\n return `REPEAT ${this.iterations}x`;\n } else if (this.iterationsMin !== null && this.iterationsMax !== null) {\n return `REPEAT ${this.iterationsMin}x-${this.iterationsMax}x`;\n } else {\n return \"REPEAT\";\n }\n };\n\n /**\n * Reset the state of the node.\n */\n reset = () => {\n // Reset the state of this node.\n this.setState(State.READY);\n\n // Reset the current iteration count.\n this.currentIterationCount = 0;\n\n // Reset the child node.\n this.child.reset();\n };\n\n /**\n * Gets whether an iteration can be made.\n * @returns Whether an iteration can be made.\n */\n private canIterate = () => {\n if (this.targetIterationCount !== null) {\n // We can iterate as long as we have not reached our target iteration count.\n return this.currentIterationCount < this.targetIterationCount;\n }\n\n // If neither an iteration count or a condition function were defined then we can iterate indefinitely.\n return true;\n };\n\n /**\n * Sets the target iteration count.\n * @param options The behaviour tree options object.\n */\n private setTargetIterationCount = (options: BehaviourTreeOptions) => {\n // Are we dealing with an explicit iteration count or will we be randomly picking a iteration count between the min and max iteration count.\n if (this.iterations !== null) {\n this.targetIterationCount = this.iterations;\n } else if (this.iterationsMin !== null && this.iterationsMax !== null) {\n // We will be picking a random iteration count between a min and max iteration count, if the optional 'random'\n // behaviour tree function option is defined then we will be using that, otherwise we will fall back to using Math.random.\n const random = typeof options.random === \"function\" ? options.random : Math.random;\n\n // Pick a random iteration count between a min and max iteration count.\n this.targetIterationCount = Math.floor(\n random() * (this.iterationsMax - this.iterationsMin + 1) + this.iterationsMin\n );\n } else {\n this.targetIterationCount = null;\n }\n };\n}\n", "import Node from \"../Node\";\nimport Decorator from \"./Decorator\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A RETRY node.\n * The node has a single child which can have:\n * -- A number of iterations for which to repeat the child node.\n * -- An infinite repeat loop if neither an iteration count or a condition function is defined.\n * The RETRY node will stop and have a 'SUCCEEDED' state if its child is ever in a 'SUCCEEDED' state after an update.\n * The RETRY node will attempt to move on to the next iteration if its child is ever in a 'FAILED' state.\n */\nexport default class Retry extends Decorator {\n /**\n * @param attributes The node attributes.\n * @param attempts The number of attempts to retry the child node.\n * @param attemptsMin The minimum possible number of attempts to retry the child node.\n * @param attemptsMax The maximum possible number of attempts to retry the child node.\n * @param child The child node.\n */\n constructor(\n attributes: Attribute[],\n private attempts: number | null,\n private attemptsMin: number | null,\n private attemptsMax: number | null,\n child: Node\n ) {\n super(\"retry\", attributes, child);\n }\n\n /**\n * The number of target attempts to make.\n */\n private targetAttemptCount: number | null = null;\n\n /**\n * The current attempt count.\n */\n private currentAttemptCount: number = 0;\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // If this node is in the READY state then we need to reset the child and the target attempt count.\n if (this.is(State.READY)) {\n // Reset the child node.\n this.child.reset();\n\n // Reset the current attempt count.\n this.currentAttemptCount = 0;\n\n // Set the target attempt count.\n this.setTargetAttemptCount(options);\n }\n\n // Do a check to see if we can attempt. If we can then this node will move into the 'RUNNING' state.\n // If we cannot attempt then we have hit our target attempt count, which means that the node has succeeded.\n if (this.canAttempt()) {\n // This node is in the running state and can do its initial attempt.\n this.setState(State.RUNNING);\n\n // We may have already completed an attempt, meaning that the child node will be in the FAILED state.\n // If this is the case then we will have to reset the child node now.\n if (this.child.getState() === State.FAILED) {\n this.child.reset();\n }\n\n // Update the child of this node.\n this.child.update(agent, options);\n\n // If the child moved into the SUCCEEDED state when we updated it then there is nothing left to do and this node has also succeeded.\n // If it has moved into the FAILED state then we have completed the current attempt.\n if (this.child.getState() === State.SUCCEEDED) {\n // The child has succeeded, meaning that this node has succeeded.\n this.setState(State.SUCCEEDED);\n\n return;\n } else if (this.child.getState() === State.FAILED) {\n // We have completed an attempt.\n this.currentAttemptCount += 1;\n }\n } else {\n // This node is in the 'FAILED' state as we cannot iterate any more.\n this.setState(State.FAILED);\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => {\n if (this.attempts !== null) {\n return `RETRY ${this.attempts}x`;\n } else if (this.attemptsMin !== null && this.attemptsMax !== null) {\n return `RETRY ${this.attemptsMin}x-${this.attemptsMax}x`;\n } else {\n return \"RETRY\";\n }\n };\n\n /**\n * Reset the state of the node.\n */\n reset = () => {\n // Reset the state of this node.\n this.setState(State.READY);\n\n // Reset the current attempt count.\n this.currentAttemptCount = 0;\n\n // Reset the child node.\n this.child.reset();\n };\n\n /**\n * Gets whether an attempt can be made.\n * @returns Whether an attempt can be made.\n */\n canAttempt = () => {\n if (this.targetAttemptCount !== null) {\n // We can attempt as long as we have not reached our target attempt count.\n return this.currentAttemptCount < this.targetAttemptCount;\n }\n\n // If neither an attempt count or a condition function were defined then we can attempt indefinitely.\n return true;\n };\n\n /**\n * Sets the target attempt count.\n * @param options The behaviour tree options object.\n */\n setTargetAttemptCount = (options: BehaviourTreeOptions) => {\n // Are we dealing with an explicit attempt count or will we be randomly picking an attempt count between the min and max attempt count.\n if (this.attempts !== null) {\n this.targetAttemptCount = this.attempts;\n } else if (this.attemptsMin !== null && this.attemptsMax !== null) {\n // We will be picking a random attempt count between a min and max attempt count, if the optional 'random'\n // behaviour tree function option is defined then we will be using that, otherwise we will fall back to using Math.random.\n const random = typeof options.random === \"function\" ? options.random : Math.random;\n\n // Pick a random attempt count between a min and max attempt count.\n this.targetAttemptCount = Math.floor(\n random() * (this.attemptsMax - this.attemptsMin + 1) + this.attemptsMin\n );\n } else {\n this.targetAttemptCount = null;\n }\n };\n}\n", "import Decorator from \"./Decorator\";\nimport State from \"../../State\";\nimport Node from \"../Node\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A Flip node.\n * This node wraps a single child and will flip the state of the child state.\n */\nexport default class Flip extends Decorator {\n /**\n * @param attributes The node attributes.\n * @param child The child node.\n */\n constructor(attributes: Attribute[], child: Node) {\n super(\"flip\", attributes, child);\n }\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // If the child has never been updated or is running then we will need to update it now.\n if (this.child.getState() === State.READY || this.child.getState() === State.RUNNING) {\n this.child.update(agent, options);\n }\n\n // The state of this node will depend in the state of its child.\n switch (this.child.getState()) {\n case State.RUNNING:\n this.setState(State.RUNNING);\n break;\n\n case State.SUCCEEDED:\n this.setState(State.FAILED);\n break;\n\n case State.FAILED:\n this.setState(State.SUCCEEDED);\n break;\n\n default:\n this.setState(State.READY);\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => \"FLIP\";\n}\n", "import Node from \"../Node\";\nimport Decorator from \"./Decorator\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A Succeed node.\n * This node wraps a single child and will always move to the 'SUCCEEDED' state when the child moves to a 'SUCCEEDED' or 'FAILED' state.\n */\nexport default class Succeed extends Decorator {\n /**\n * @param attributes The node attributes.\n * @param child The child node.\n */\n constructor(attributes: Attribute[], child: Node) {\n super(\"succeed\", attributes, child);\n }\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // If the child has never been updated or is running then we will need to update it now.\n if (this.child.getState() === State.READY || this.child.getState() === State.RUNNING) {\n this.child.update(agent, options);\n }\n\n // The state of this node will depend in the state of its child.\n switch (this.child.getState()) {\n case State.RUNNING:\n this.setState(State.RUNNING);\n break;\n\n case State.SUCCEEDED:\n case State.FAILED:\n this.setState(State.SUCCEEDED);\n break;\n\n default:\n this.setState(State.READY);\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => \"SUCCEED\";\n}\n", "import Node from \"../Node\";\nimport Decorator from \"./Decorator\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A Fail node.\n * This node wraps a single child and will always move to the 'FAILED' state when the child moves to a 'SUCCEEDED' or 'FAILED' state.\n */\nexport default class Fail extends Decorator {\n /**\n * @param attributes The node attributes.\n * @param child The child node.\n */\n constructor(attributes: Attribute[], child: Node) {\n super(\"fail\", attributes, child);\n }\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // If the child has never been updated or is running then we will need to update it now.\n if (this.child.getState() === State.READY || this.child.getState() === State.RUNNING) {\n this.child.update(agent, options);\n }\n\n // The state of this node will depend in the state of its child.\n switch (this.child.getState()) {\n case State.RUNNING:\n this.setState(State.RUNNING);\n break;\n\n case State.SUCCEEDED:\n case State.FAILED:\n this.setState(State.FAILED);\n break;\n\n default:\n this.setState(State.READY);\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => \"FAIL\";\n}\n", "import createLotto from \"lotto-draw\";\n\nimport Node from \"../Node\";\nimport Composite from \"./Composite\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A LOTTO node.\n * A winning child is picked on the initial update of this node, based on ticket weighting.\n * The state of this node will match the state of the winning child.\n */\nexport default class Lotto extends Composite {\n /**\n * @param attributes The node attributes.\n * @param tickets The child node tickets.\n * @param children The child nodes.\n */\n constructor(attributes: Attribute[], private tickets: number[], children: Node[]) {\n super(\"lotto\", attributes, children);\n }\n\n /**\n * The child node selected to be the active one.\n */\n private selectedChild: Node | undefined;\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // If this node is in the READY state then we need to pick a winning child node.\n if (this.is(State.READY)) {\n // Create a lotto draw with which to randomly pick a child node to become the active one.\n const lottoDraw = createLotto({\n // Hook up the optional 'random' behaviour tree function option to the one used by 'lotto-draw'.\n random: options.random,\n // Pass in each child node as a participant in the lotto draw with their respective ticket count.\n participants: this.children.map((child, index) => [child, this.tickets[index] || 1])\n });\n\n // Randomly pick a child based on ticket weighting, this will become the active child for this composite node.\n this.selectedChild = lottoDraw.draw() || undefined;\n }\n\n // If something went wrong and we don't have an active child then we should throw an error.\n if (!this.selectedChild) {\n throw new Error(\"failed to update lotto node as it has no active child\");\n }\n\n // If the selected child has never been updated or is running then we will need to update it now.\n if (this.selectedChild.getState() === State.READY || this.selectedChild.getState() === State.RUNNING) {\n this.selectedChild.update(agent, options);\n }\n\n // The state of the lotto node is the state of its selected child.\n this.setState(this.selectedChild.getState());\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => (this.tickets.length ? `LOTTO [${this.tickets.join(\",\")}]` : \"LOTTO\");\n}\n", "import Node from \"../Node\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\n\n/**\n * A composite node that wraps child nodes.\n */\nexport default abstract class Composite extends Node {\n /**\n * @param type The node type.\n * @param attributes The node attributes.\n * @param children The child nodes.\n */\n constructor(type: string, attributes: Attribute[], protected children: Node[]) {\n super(type, attributes, []);\n }\n\n /**\n * Gets whether this node is a leaf node.\n */\n isLeafNode = () => false;\n\n /**\n * Gets the children of this node.\n */\n getChildren = () => this.children;\n\n /**\n * Reset the state of the node.\n */\n reset = () => {\n // Reset the state of this node.\n this.setState(State.READY);\n\n // Reset the state of any child nodes.\n this.getChildren().forEach((child) => child.reset());\n };\n\n /**\n * Abort the running of this node.\n * @param agent The agent.\n */\n abort = (agent: Agent) => {\n // There is nothing to do if this node is not in the running state.\n if (!this.is(State.RUNNING)) {\n return;\n }\n\n // Abort any child nodes.\n this.getChildren().forEach((child) => child.abort(agent));\n\n // Reset the state of this node.\n this.reset();\n\n this.getAttribute(\"exit\")?.callAgentFunction(agent, false, true);\n };\n}\n", "import Composite from \"./Composite\";\nimport Node from \"../Node\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A SELECTOR node.\n * The child nodes are executed in sequence until one succeeds or all fail.\n */\nexport default class Selector extends Composite {\n /**\n * @param attributes The node attributes.\n * @param children The child nodes.\n */\n constructor(attributes: Attribute[], protected children: Node[]) {\n super(\"selector\", attributes, children);\n }\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // Iterate over all of the children of this node.\n for (const child of this.children) {\n // If the child has never been updated or is running then we will need to update it now.\n if (child.getState() === State.READY || child.getState() === State.RUNNING) {\n // Update the child of this node.\n child.update(agent, options);\n }\n\n // If the current child has a state of 'SUCCEEDED' then this node is also a 'SUCCEEDED' node.\n if (child.getState() === State.SUCCEEDED) {\n // This node is a 'SUCCEEDED' node.\n this.setState(State.SUCCEEDED);\n\n // There is no need to check the rest of the selector nodes.\n return;\n }\n\n // If the current child has a state of 'FAILED' then we should move on to the next child.\n if (child.getState() === State.FAILED) {\n // Find out if the current child is the last one in the selector.\n // If it is then this sequence node has also failed.\n if (this.children.indexOf(child) === this.children.length - 1) {\n // This node is a 'FAILED' node.\n this.setState(State.FAILED);\n\n // There is no need to check the rest of the selector as we have completed it.\n return;\n } else {\n // The child node failed, try the next one.\n continue;\n }\n }\n\n // The node should be in the 'RUNNING' state.\n if (child.getState() === State.RUNNING) {\n // This node is a 'RUNNING' node.\n this.setState(State.RUNNING);\n\n // There is no need to check the rest of the selector as the current child is still running.\n return;\n }\n\n // The child node was not in an expected state.\n throw new Error(\"child node was not in an expected state.\");\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => \"SELECTOR\";\n}\n", "import Composite from \"./Composite\";\nimport Node from \"../Node\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A SEQUENCE node.\n * The child nodes are executed in sequence until one fails or all succeed.\n */\nexport default class Sequence extends Composite {\n /**\n * @param attributes The node attributes.\n * @param children The child nodes.\n */\n constructor(attributes: Attribute[], protected children: Node[]) {\n super(\"sequence\", attributes, children);\n }\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // Iterate over all of the children of this node.\n for (const child of this.children) {\n // If the child has never been updated or is running then we will need to update it now.\n if (child.getState() === State.READY || child.getState() === State.RUNNING) {\n // Update the child of this node.\n child.update(agent, options);\n }\n\n // If the current child has a state of 'SUCCEEDED' then we should move on to the next child.\n if (child.getState() === State.SUCCEEDED) {\n // Find out if the current child is the last one in the sequence.\n // If it is then this sequence node has also succeeded.\n if (this.children.indexOf(child) === this.children.length - 1) {\n // This node is a 'SUCCEEDED' node.\n this.setState(State.SUCCEEDED);\n\n // There is no need to check the rest of the sequence as we have completed it.\n return;\n } else {\n // The child node succeeded, but we have not finished the sequence yet.\n continue;\n }\n }\n\n // If the current child has a state of 'FAILED' then this node is also a 'FAILED' node.\n if (child.getState() === State.FAILED) {\n // This node is a 'FAILED' node.\n this.setState(State.FAILED);\n\n // There is no need to check the rest of the sequence.\n return;\n }\n\n // The node should be in the 'RUNNING' state.\n if (child.getState() === State.RUNNING) {\n // This node is a 'RUNNING' node.\n this.setState(State.RUNNING);\n\n // There is no need to check the rest of the sequence as the current child is still running.\n return;\n }\n\n // The child node was not in an expected state.\n throw new Error(\"child node was not in an expected state.\");\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => \"SEQUENCE\";\n}\n", "import Composite from \"./Composite\";\nimport State from \"../../State\";\nimport Node from \"../Node\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A PARALLEL node.\n * The child nodes are executed concurrently until one fails or all succeed.\n */\nexport default class Parallel extends Composite {\n /**\n * @param attributes The node attributes.\n * @param children The child nodes.\n */\n constructor(attributes: Attribute[], children: Node[]) {\n super(\"parallel\", attributes, children);\n }\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // Keep a count of the number of succeeded child nodes.\n let succeededCount = 0;\n\n let hasChildFailed = false;\n\n // Iterate over all of the children of this node.\n for (const child of this.children) {\n // If the child has never been updated or is running then we will need to update it now.\n if (child.getState() === State.READY || child.getState() === State.RUNNING) {\n // Update the child of this node.\n child.update(agent, options);\n }\n\n // If the current child has a state of 'SUCCEEDED' then we should move on to the next child.\n if (child.getState() === State.SUCCEEDED) {\n // The child node has succeeded, keep track of this to determine if all children have.\n succeededCount++;\n\n // The child node succeeded, but we have not finished checking every child node yet.\n continue;\n }\n\n // If the current child has a state of 'FAILED' then this node is also a 'FAILED' node.\n if (child.getState() === State.FAILED) {\n hasChildFailed = true;\n\n // There is no need to check the rest of the children.\n break;\n }\n\n // The node should be in the 'RUNNING' state.\n if (child.getState() !== State.RUNNING) {\n // The child node was not in an expected state.\n throw new Error(\"child node was not in an expected state.\");\n }\n }\n\n if (hasChildFailed) {\n // This node is a 'FAILED' node.\n this.setState(State.FAILED);\n\n // Abort every running child.\n for (const child of this.children) {\n if (child.getState() === State.RUNNING) {\n child.abort(agent);\n }\n }\n } else {\n // If all children have succeeded then this node has also succeeded, otherwise it is still running.\n this.setState(succeededCount === this.children.length ? State.SUCCEEDED : State.RUNNING);\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => \"PARALLEL\";\n}\n", "import { AnyArgument } from \"../RootAstNodesBuilder\";\nimport Guard from \"./guards/Guard\";\n\nexport type AttributeDetails = {\n /** The attribute type. */\n type: string;\n\n /** The attribute arguments. */\n args: AnyArgument[];\n};\n\n/**\n * A base node attribute.\n */\nexport default abstract class Attribute {\n /**\n * @param type The node attribute type.\n * @param args The array of attribute argument definitions.\n */\n constructor(protected type: string, protected args: AnyArgument[]) {}\n\n /**\n * Gets the type of the attribute.\n */\n getType = () => this.type;\n\n /**\n * Gets the array of attribute argument definitions.\n */\n getArguments = () => this.args;\n\n /**\n * Gets the attribute details.\n */\n abstract getDetails(): TAttributeDetails;\n\n /**\n * Gets whether this attribute is a guard.\n */\n abstract isGuard: () => this is Guard;\n}\n", "import { Agent } from \"../../Agent\";\nimport { AnyArgument } from \"../../RootAstNodesBuilder\";\nimport Attribute, { AttributeDetails } from \"../Attribute\";\n\nexport type GuardAttributeDetails = {\n /** The name of the condition function that determines whether the guard is satisfied. */\n condition: string;\n} & AttributeDetails;\n\n/**\n * A base node guard attribute.\n */\nexport default abstract class Guard extends Attribute {\n /**\n * @param type The node attribute type.\n * @param args The array of decorator argument definitions.\n * @param condition The name of the condition function that determines whether the guard is satisfied.\n */\n constructor(type: string, args: AnyArgument[], private condition: string) {\n super(type, args);\n }\n\n /**\n * Gets the name of the condition function that determines whether the guard is satisfied.\n */\n getCondition = () => this.condition;\n\n /**\n * Gets whether this attribute is a guard.\n */\n isGuard = () => true;\n\n /**\n * Gets the attribute details.\n */\n getDetails(): GuardAttributeDetails {\n return {\n type: this.getType(),\n args: this.getArguments(),\n condition: this.getCondition()\n };\n }\n\n /**\n * Gets whether the guard is satisfied.\n * @param agent The agent.\n * @returns Whether the guard is satisfied.\n */\n abstract isSatisfied(agent: Agent): boolean;\n}\n", "import Guard from \"./Guard\";\nimport Lookup from \"../../Lookup\";\nimport { Agent } from \"../../Agent\";\nimport { AnyArgument } from \"../../RootAstNodesBuilder\";\n\n/**\n * A WHILE guard which is satisfied as long as the given condition remains true.\n */\nexport default class While extends Guard {\n /**\n * @param condition The name of the condition function that determines whether the guard is satisfied.\n * @param args The array of decorator argument definitions.\n */\n constructor(condition: string, args: AnyArgument[]) {\n super(\"while\", args, condition);\n }\n\n /**\n * Gets whether the guard is satisfied.\n * @param agent The agent.\n * @returns Whether the guard is satisfied.\n */\n isSatisfied = (agent: Agent) => {\n // Attempt to get the invoker for the condition function.\n const conditionFuncInvoker = Lookup.getFuncInvoker(agent, this.getCondition());\n\n // The condition function should be defined.\n if (conditionFuncInvoker === null) {\n throw new Error(\n `cannot evaluate node guard as the condition '${this.getCondition()}' function is not defined on the agent and has not been registered`\n );\n }\n\n // Call the condition function to determine whether this guard is satisfied.\n return !!conditionFuncInvoker(this.args);\n };\n}\n", "import Guard from \"./Guard\";\nimport Lookup from \"../../Lookup\";\nimport { Agent } from \"../../Agent\";\nimport { AnyArgument } from \"../../RootAstNodesBuilder\";\n\n/**\n * An UNTIL guard which is satisfied as long as the given condition remains false.\n */\nexport default class Until extends Guard {\n /**\n * @param condition The name of the condition function that determines whether the guard is satisfied.\n * @param args The array of decorator argument definitions.\n */\n constructor(condition: string, args: AnyArgument[]) {\n super(\"until\", args, condition);\n }\n\n /**\n * Gets whether the guard is satisfied.\n * @param agent The agent.\n * @returns Whether the guard is satisfied.\n */\n isSatisfied = (agent: Agent) => {\n // Attempt to get the invoker for the condition function.\n const conditionFuncInvoker = Lookup.getFuncInvoker(agent, this.getCondition());\n\n // The condition function should be defined.\n if (conditionFuncInvoker === null) {\n throw new Error(\n `cannot evaluate node guard as the condition '${this.getCondition()}' function is not defined on the agent and has not been registered`\n );\n }\n\n // Call the condition function to determine whether this guard is satisfied.\n return !!!conditionFuncInvoker(this.args);\n };\n}\n", "import { Agent } from \"../../Agent\";\nimport { AnyArgument } from \"../../RootAstNodesBuilder\";\nimport Attribute, { AttributeDetails } from \"../Attribute\";\n\nexport type CallbackAttributeDetails = {\n /** The name of the agent function that is called. */\n functionName: string;\n} & AttributeDetails;\n\n/**\n * A base node callback attribute.\n */\nexport default abstract class Callback extends Attribute {\n /**\n * @param type The node attribute type.\n * @param args The array of decorator argument definitions.\n * @param functionName The name of the agent function to call.\n */\n constructor(type: string, args: AnyArgument[], private functionName: string) {\n super(type, args);\n }\n\n /**\n * Gets the name of the agent function to call.\n */\n getFunctionName = () => this.functionName;\n\n /**\n * Gets whether this attribute is a guard.\n */\n isGuard = () => false;\n\n /**\n * Gets the attribute details.\n */\n getDetails(): CallbackAttributeDetails {\n return {\n type: this.getType(),\n args: this.getArguments(),\n functionName: this.getFunctionName()\n };\n }\n\n /**\n * Attempt to call the agent function that this callback refers to.\n * @param agent The agent.\n */\n abstract callAgentFunction: (agent: Agent, isSuccess: boolean, isAborted: boolean) => void;\n}\n", "import Callback from \"./Callback\";\nimport Lookup from \"../../Lookup\";\nimport { Agent } from \"../../Agent\";\nimport { AnyArgument } from \"../../RootAstNodesBuilder\";\n\n/**\n * An ENTRY callback which defines an agent function to call when the associated node is updated and moves out of running state.\n */\nexport default class Entry extends Callback {\n /**\n * @param functionName The name of the agent function to call.\n * @param args The array of callback argument definitions.\n */\n constructor(functionName: string, args: AnyArgument[]) {\n super(\"entry\", args, functionName);\n }\n\n /**\n * Attempt to call the agent function that this callback refers to.\n * @param agent The agent.\n */\n callAgentFunction = (agent: Agent) => {\n // Attempt to get the invoker for the callback function.\n const callbackFuncInvoker = Lookup.getFuncInvoker(agent, this.getFunctionName());\n\n // The callback function should be defined.\n if (callbackFuncInvoker === null) {\n throw new Error(\n `cannot call entry function '${this.getFunctionName()}' as is not defined on the agent and has not been registered`\n );\n }\n\n // Call the callback function.\n callbackFuncInvoker(this.args);\n };\n}\n", "import Callback from \"./Callback\";\nimport Lookup, { AnyExitArgument } from \"../../Lookup\";\nimport { Agent } from \"../../Agent\";\nimport { AnyArgument } from \"../../RootAstNodesBuilder\";\n\n/**\n * An EXIT callback which defines an agent function to call when the associated node is updated and moves to a finished state or is aborted.\n */\nexport default class Exit extends Callback {\n /**\n * @param functionName The name of the agent function to call.\n * @param args The array of callback argument definitions.\n */\n constructor(functionName: string, args: AnyArgument[]) {\n super(\"exit\", args, functionName);\n }\n\n /**\n * Attempt to call the agent function that this callback refers to.\n * @param agent The agent.\n * @param isSuccess Whether the decorated node was left with a success state.\n * @param isAborted Whether the decorated node was aborted.\n */\n callAgentFunction = (agent: Agent, isSuccess: boolean, isAborted: boolean) => {\n // Attempt to get the invoker for the callback function.\n const callbackFuncInvoker = Lookup.getFuncInvoker(agent, this.getFunctionName());\n\n // The callback function should be defined.\n if (callbackFuncInvoker === null) {\n throw new Error(\n `cannot call exit function '${this.getFunctionName()}' as is not defined on the agent and has not been registered`\n );\n }\n\n // Call the callback function\n callbackFuncInvoker([{ value: { succeeded: isSuccess, aborted: isAborted } }, ...this.args]);\n };\n}\n", "import Callback from \"./Callback\";\nimport Lookup from \"../../Lookup\";\nimport { Agent } from \"../../Agent\";\nimport { AnyArgument } from \"../../RootAstNodesBuilder\";\n\n/**\n * A STEP callback which defines an agent function to call when the associated node is updated.\n */\nexport default class Step extends Callback {\n /**\n * @param functionName The name of the agent function to call.\n * @param args The array of callback argument definitions.\n */\n constructor(functionName: string, args: AnyArgument[]) {\n super(\"step\", args, functionName);\n }\n\n /**\n * Attempt to call the agent function that this callback refers to.\n * @param agent The agent.\n */\n callAgentFunction = (agent: Agent) => {\n // Attempt to get the invoker for the callback function.\n const callbackFuncInvoker = Lookup.getFuncInvoker(agent, this.getFunctionName());\n\n // The callback function should be defined.\n if (callbackFuncInvoker === null) {\n throw new Error(\n `cannot call step function '${this.getFunctionName()}' as is not defined on the agent and has not been registered`\n );\n }\n\n // Call the callback function.\n callbackFuncInvoker(this.args);\n };\n}\n", "import Action from \"./nodes/leaf/Action\";\nimport Condition from \"./nodes/leaf/Condition\";\nimport Wait from \"./nodes/leaf/Wait\";\nimport Root from \"./nodes/decorator/Root\";\nimport Repeat from \"./nodes/decorator/Repeat\";\nimport Retry from \"./nodes/decorator/Retry\";\nimport Flip from \"./nodes/decorator/Flip\";\nimport Succeed from \"./nodes/decorator/Succeed\";\nimport Fail from \"./nodes/decorator/Fail\";\nimport Lotto from \"./nodes/composite/Lotto\";\nimport Selector from \"./nodes/composite/Selector\";\nimport Sequence from \"./nodes/composite/Sequence\";\nimport Parallel from \"./nodes/composite/Parallel\";\nimport Node from \"./nodes/Node\";\nimport While from \"./attributes/guards/While\";\nimport Until from \"./attributes/guards/Until\";\nimport Entry from \"./attributes/callbacks/Entry\";\nimport Exit from \"./attributes/callbacks/Exit\";\nimport Step from \"./attributes/callbacks/Step\";\nimport Callback from \"./attributes/callbacks/Callback\";\nimport Guard from \"./attributes/guards/Guard\";\nimport Attribute from \"./attributes/Attribute\";\nimport Composite from \"./nodes/composite/Composite\";\nimport Decorator from \"./nodes/decorator/Decorator\";\nimport Leaf from \"./nodes/leaf/Leaf\";\n\nexport type Argument = {\n value: T;\n type: string; // Used for validation.\n};\ntype NullArgument = Argument & {\n type: \"null\";\n};\ntype BooleanArgument = Argument & {\n type: \"boolean\";\n};\ntype NumberArgument = Argument & {\n type: \"number\";\n isInteger: boolean; // Used for validation.\n};\ntype StringPlaceholderArgument = Argument & {\n type: \"string\";\n};\ntype IdentifierArgument = Argument & {\n type: \"identifier\";\n};\nexport type AnyArgument =\n | NullArgument\n | BooleanArgument\n | NumberArgument\n | StringPlaceholderArgument\n | IdentifierArgument;\n\n/**\n * The node attribute factories.\n */\nconst AttributeFactories: {\n [key: string]: (functionName: string, attributeArguments: AnyArgument[]) => Callback | Guard;\n} = {\n WHILE: (condition: string, attributeArguments: AnyArgument[]) => new While(condition, attributeArguments),\n UNTIL: (condition: string, attributeArguments: AnyArgument[]) => new Until(condition, attributeArguments),\n ENTRY: (functionName: string, attributeArguments: AnyArgument[]) => new Entry(functionName, attributeArguments),\n EXIT: (functionName: string, attributeArguments: AnyArgument[]) => new Exit(functionName, attributeArguments),\n STEP: (functionName: string, attributeArguments: AnyArgument[]) => new Step(functionName, attributeArguments)\n};\n\ntype Validatable = {\n children?: AstNode[];\n validate: (depth: number) => void;\n};\n\ntype NodeInstanceCreator = (\n namedRootNodeProvider: (name: string) => RootAstNode,\n visitedBranches: string[]\n) => T;\n\nexport type AstNode = Validatable & {\n type: string;\n createNodeInstance: NodeInstanceCreator;\n};\n\nexport type LeafAstNode = AstNode & {\n type: \"action\" | \"condition\" | \"wait\";\n attributes: Attribute[];\n};\n\nexport type CompositeAstNode = AstNode & {\n type: \"lotto\" | \"parallel\" | \"selector\" | \"sequence\";\n attributes: Attribute[];\n children: AstNode[];\n};\n\nexport type DecoratorAstNode = AstNode & {\n type: \"fail\" | \"flip\" | \"repeat\" | \"retry\" | \"root\" | \"succeed\";\n attributes: Attribute[];\n children: AstNode[];\n};\n\nexport type BranchAstNode = AstNode & {\n type: \"branch\";\n branchName: \"\" | string;\n};\n\nexport type LottoAstNode = CompositeAstNode & {\n type: \"lotto\";\n tickets: number[];\n};\n\nexport type RootAstNode = DecoratorAstNode & {\n type: \"root\";\n name: null | string;\n};\n\nexport type RepeatAstNode = DecoratorAstNode & {\n type: \"repeat\";\n iterations: number | null;\n iterationsMin: number | null;\n iterationsMax: number | null;\n};\n\nexport type RetryAstNode = DecoratorAstNode & {\n type: \"retry\";\n attempts: number | null;\n attemptsMin: number | null;\n attemptsMax: number | null;\n};\n\nexport type ActionAstNode = LeafAstNode & {\n type: \"action\";\n actionName: string;\n actionArguments: AnyArgument[];\n};\n\nexport type ConditionAstNode = LeafAstNode & {\n type: \"condition\";\n conditionName: string;\n conditionArguments: AnyArgument[];\n};\n\nexport type WaitAstNode = LeafAstNode & {\n type: \"wait\";\n duration: number | null;\n durationMin: number | null;\n durationMax: number | null;\n};\n\nexport type AnyAstNode =\n | BranchAstNode\n | CompositeAstNode\n | LottoAstNode\n | DecoratorAstNode\n | RootAstNode\n | RepeatAstNode\n | RetryAstNode\n | LeafAstNode\n | ActionAstNode\n | ConditionAstNode\n | WaitAstNode;\n\n/**\n * The AST node factories.\n */\nconst ASTNodeFactories = {\n ROOT: (): RootAstNode => ({\n type: \"root\",\n attributes: [],\n name: null,\n children: [],\n validate(depth: number) {\n // A root node cannot be the child of another node.\n if (depth > 1) {\n throw new Error(\"a root node cannot be the child of another node\");\n }\n\n // A root node must have a single child node.\n if (this.children.length !== 1) {\n throw new Error(\"a root node must have a single child\");\n }\n },\n createNodeInstance(namedRootNodeProvider, visitedBranches) {\n return new Root(\n this.attributes,\n this.children![0].createNodeInstance(namedRootNodeProvider, visitedBranches.slice())\n );\n }\n }),\n BRANCH: (): BranchAstNode => ({\n type: \"branch\",\n branchName: \"\",\n validate() {},\n createNodeInstance(namedRootNodeProvider, visitedBranches) {\n // Try to find the root node with a matching branch name.\n const targetRootNode = namedRootNodeProvider(this.branchName);\n\n // If we have already visited this branch then we have a circular dependency.\n if (visitedBranches.indexOf(this.branchName) !== -1) {\n throw new Error(`circular dependency found in branch node references for branch '${this.branchName}'`);\n }\n\n // If we have a target root node, then the node instance we want will be the first and only child of the referenced root node.\n if (targetRootNode) {\n return targetRootNode\n .createNodeInstance(namedRootNodeProvider, visitedBranches.concat(this.branchName))\n .getChildren()[0];\n } else {\n throw new Error(`branch references root node '${this.branchName}' which has not been defined`);\n }\n }\n }),\n SELECTOR: (): CompositeAstNode => ({\n type: \"selector\",\n attributes: [],\n children: [],\n validate() {\n // A selector node must have at least a single node.\n if (this.children.length < 1) {\n throw new Error(\"a selector node must have at least a single child\");\n }\n },\n createNodeInstance(namedRootNodeProvider, visitedBranches) {\n return new Selector(\n this.attributes,\n this.children.map((child) => child.createNodeInstance(namedRootNodeProvider, visitedBranches.slice()))\n );\n }\n }),\n SEQUENCE: (): CompositeAstNode => ({\n type: \"sequence\",\n attributes: [],\n children: [],\n validate() {\n // A sequence node must have at least a single node.\n if (this.children.length < 1) {\n throw new Error(\"a sequence node must have at least a single child\");\n }\n },\n createNodeInstance(namedRootNodeProvider, visitedBranches) {\n return new Sequence(\n this.attributes,\n this.children.map((child) => child.createNodeInstance(namedRootNodeProvider, visitedBranches.slice()))\n );\n }\n }),\n PARALLEL: (): CompositeAstNode => ({\n type: \"parallel\",\n attributes: [],\n children: [],\n validate() {\n // A parallel node must have at least a single node.\n if (this.children.length < 1) {\n throw new Error(\"a parallel node must have at least a single child\");\n }\n },\n createNodeInstance(namedRootNodeProvider, visitedBranches) {\n return new Parallel(\n this.attributes,\n this.children.map((child) => child.createNodeInstance(namedRootNodeProvider, visitedBranches.slice()))\n );\n }\n }),\n LOTTO: (): LottoAstNode => ({\n type: \"lotto\",\n attributes: [],\n children: [],\n tickets: [],\n validate() {\n // A lotto node must have at least a single node.\n if (this.children!.length < 1) {\n throw new Error(\"a lotto node must have at least a single child\");\n }\n },\n createNodeInstance(namedRootNodeProvider, visitedBranches) {\n return new Lotto(\n this.attributes,\n this.tickets!,\n this.children!.map((child) => child.createNodeInstance(namedRootNodeProvider, visitedBranches.slice()))\n );\n }\n }),\n REPEAT: (): RepeatAstNode => ({\n type: \"repeat\",\n attributes: [],\n iterations: null,\n iterationsMin: null,\n iterationsMax: null,\n children: [],\n validate() {\n // A repeat node must have a single node.\n if (this.children!.length !== 1) {\n throw new Error(\"a repeat node must have a single child\");\n }\n\n if (this.iterations !== null) {\n // A repeat node must have a positive number of iterations if defined.\n if (this.iterations < 0) {\n throw new Error(\"a repeat node must have a positive number of iterations if defined\");\n }\n } else if (this.iterationsMin !== null && this.iterationsMax !== null) {\n // A repeat node must have a positive min and max iteration count if they are defined.\n if (this.iterationsMin < 0 || this.iterationsMax < 0) {\n throw new Error(\n \"a repeat node must have a positive minimum and maximum iteration count if defined\"\n );\n }\n\n // A repeat node must not have an minimum iteration count that exceeds the maximum iteration count.\n if (this.iterationsMin > this.iterationsMax) {\n throw new Error(\n \"a repeat node must not have a minimum iteration count that exceeds the maximum iteration count\"\n );\n }\n } else {\n // If we have no explicit iteration count or a minimum and maximum iteration count set then we are dealing with a repeat node that iterates indefinitely.\n }\n },\n createNodeInstance(namedRootNodeProvider, visitedBranches) {\n return new Repeat(\n this.attributes,\n this.iterations,\n this.iterationsMin,\n this.iterationsMax,\n this.children![0].createNodeInstance(namedRootNodeProvider, visitedBranches.slice())\n );\n }\n }),\n RETRY: (): RetryAstNode => ({\n type: \"retry\",\n attributes: [],\n attempts: null,\n attemptsMin: null,\n attemptsMax: null,\n children: [],\n validate() {\n // A retry node must have a single node.\n if (this.children!.length !== 1) {\n throw new Error(\"a retry node must have a single child\");\n }\n\n if (this.attempts !== null) {\n // A retry node must have a positive number of attempts if defined.\n if (this.attempts < 0) {\n throw new Error(\"a retry node must have a positive number of attempts if defined\");\n }\n } else if (this.attemptsMin !== null && this.attemptsMax !== null) {\n // A retry node must have a positive min and max attempts count if they are defined.\n if (this.attemptsMin < 0 || this.attemptsMax < 0) {\n throw new Error(\"a retry node must have a positive minimum and maximum attempt count if defined\");\n }\n\n // A retry node must not have a minimum attempt count that exceeds the maximum attempt count.\n if (this.attemptsMin > this.attemptsMax) {\n throw new Error(\n \"a retry node must not have a minimum attempt count that exceeds the maximum attempt count\"\n );\n }\n } else {\n // If we have no explicit attempt count or a minimum and maximum attempt count set then we are dealing with a retry node that attempts indefinitely.\n }\n },\n createNodeInstance(namedRootNodeProvider, visitedBranches) {\n return new Retry(\n this.attributes,\n this.attempts,\n this.attemptsMin,\n this.attemptsMax,\n this.children![0].createNodeInstance(namedRootNodeProvider, visitedBranches.slice())\n );\n }\n }),\n FLIP: (): DecoratorAstNode => ({\n type: \"flip\",\n attributes: [],\n children: [],\n validate() {\n // A flip node must have a single node.\n if (this.children!.length !== 1) {\n throw new Error(\"a flip node must have a single child\");\n }\n },\n createNodeInstance(namedRootNodeProvider, visitedBranches) {\n return new Flip(\n this.attributes,\n this.children![0].createNodeInstance(namedRootNodeProvider, visitedBranches.slice())\n );\n }\n }),\n SUCCEED: (): DecoratorAstNode => ({\n type: \"succeed\",\n attributes: [],\n children: [],\n validate() {\n // A succeed node must have a single node.\n if (this.children!.length !== 1) {\n throw new Error(\"a succeed node must have a single child\");\n }\n },\n createNodeInstance(namedRootNodeProvider, visitedBranches) {\n return new Succeed(\n this.attributes,\n this.children![0].createNodeInstance(namedRootNodeProvider, visitedBranches.slice())\n );\n }\n }),\n FAIL: (): DecoratorAstNode => ({\n type: \"fail\",\n attributes: [],\n children: [],\n validate() {\n // A fail node must have a single node.\n if (this.children!.length !== 1) {\n throw new Error(\"a fail node must have a single child\");\n }\n },\n createNodeInstance(namedRootNodeProvider, visitedBranches) {\n return new Fail(\n this.attributes,\n this.children![0].createNodeInstance(namedRootNodeProvider, visitedBranches.slice())\n );\n }\n }),\n WAIT: (): WaitAstNode => ({\n type: \"wait\",\n attributes: [],\n duration: null,\n durationMin: null,\n durationMax: null,\n validate() {\n if (this.duration !== null) {\n // If an explict duration was defined then it must be a positive number.\n if (this.duration < 0) {\n throw new Error(\"a wait node must have a positive duration\");\n }\n } else if (this.durationMin !== null && this.durationMax !== null) {\n // A wait node must have a positive min and max duration.\n if (this.durationMin < 0 || this.durationMax < 0) {\n throw new Error(\"a wait node must have a positive minimum and maximum duration\");\n }\n\n // A wait node must not have a minimum duration that exceeds the maximum duration.\n if (this.durationMin > this.durationMax) {\n throw new Error(\"a wait node must not have a minimum duration that exceeds the maximum duration\");\n }\n } else {\n // If we have no explicit duration or duration bounds set then we are dealing with a wait node that waits indefinitely.\n }\n },\n createNodeInstance() {\n return new Wait(this.attributes, this.duration, this.durationMin, this.durationMax);\n }\n }),\n ACTION: (): ActionAstNode => ({\n type: \"action\",\n attributes: [],\n actionName: \"\",\n actionArguments: [],\n validate() {},\n createNodeInstance() {\n return new Action(this.attributes, this.actionName!, this.actionArguments!);\n }\n }),\n CONDITION: (): ConditionAstNode => ({\n type: \"condition\",\n attributes: [],\n conditionName: \"\",\n conditionArguments: [],\n validate() {},\n createNodeInstance() {\n return new Condition(this.attributes, this.conditionName!, this.conditionArguments!);\n }\n })\n};\n\ntype OtherAstNodes = AstNode[];\n\n/**\n * Create an array of root AST nodes based on the given definition.\n * @param definition The definition to parse the AST nodes from.\n * @returns The base definition AST nodes.\n */\nexport default function buildRootASTNodes(definition: string): RootAstNode[] {\n // Swap out any node/attribute argument string literals with a placeholder and get a mapping of placeholders to original values as well as the processed definition.\n const { placeholders, processedDefinition } = substituteStringLiterals(definition);\n\n // Convert the processed definition (with substituted string literals) into an array of raw tokens.\n const tokens = parseTokensFromDefinition(processedDefinition);\n\n // There must be at least 3 tokens for the tree definition to be valid. 'ROOT', '{' and '}'.\n if (tokens.length < 3) {\n throw new Error(\"invalid token count\");\n }\n\n // We should have a matching number of '{' and '}' tokens. If not, then there are scopes that have not been properly closed.\n if (tokens.filter((token) => token === \"{\").length !== tokens.filter((token) => token === \"}\").length) {\n throw new Error(\"scope character mismatch\");\n }\n\n // Create a stack of node children arrays, starting with a definition scope.\n const stack: [RootAstNode[], ...OtherAstNodes[]] = [[]];\n const rootScope = stack[0];\n\n // We should keep processing the raw tokens until we run out of them.\n while (tokens.length) {\n // Grab the next token.\n const token = tokens.shift();\n\n const currentScope = stack[stack.length - 1] as OtherAstNodes;\n\n // How we create the next AST token depends on the current raw token value.\n switch (token!.toUpperCase()) {\n case \"ROOT\": {\n // Create a ROOT AST node.\n const node = ASTNodeFactories.ROOT();\n\n // Push the ROOT node into the current scope.\n rootScope.push(node);\n\n // We may have a root node name defined as an argument.\n if (tokens[0] === \"[\") {\n const rootArguments = getArguments(tokens, placeholders);\n\n // We should have only a single argument that is not an empty string for a root node, which is the root name identifier.\n if (rootArguments.length === 1 && rootArguments[0].type === \"identifier\") {\n // The root name will be the first and only node argument.\n node.name = rootArguments[0].value as string;\n } else {\n throw new Error(\"expected single root name argument\");\n }\n }\n\n // Try to pick any attributes off of the token stack.\n node.attributes = getAttributes(tokens, placeholders);\n\n popAndCheck(tokens, \"{\");\n\n // The new scope is that of the new ROOT nodes children.\n stack.push(node.children!);\n break;\n }\n\n case \"BRANCH\": {\n // Create a BRANCH AST node.\n const node = ASTNodeFactories.BRANCH();\n\n // Push the BRANCH node into the current scope.\n currentScope.push(node);\n\n // We must have arguments defined, as we require a branch name argument.\n if (tokens[0] !== \"[\") {\n throw new Error(\"expected single branch name argument\");\n }\n\n // The branch name will be defined as a node argument.\n const branchArguments = getArguments(tokens, placeholders);\n\n // We should have only a single identifer argument for a branch node, which is the branch name.\n if (branchArguments.length === 1 && branchArguments[0].type === \"identifier\") {\n // The branch name will be the first and only node argument.\n node.branchName = branchArguments[0].value as string;\n } else {\n throw new Error(\"expected single branch name argument\");\n }\n break;\n }\n\n case \"SELECTOR\": {\n // Create a SELECTOR AST node.\n const node = ASTNodeFactories.SELECTOR();\n\n // Push the SELECTOR node into the current scope.\n currentScope.push(node);\n\n // Try to pick any attributes off of the token stack.\n node.attributes = getAttributes(tokens, placeholders);\n\n popAndCheck(tokens, \"{\");\n\n // The new scope is that of the new SELECTOR nodes children.\n stack.push(node.children!);\n break;\n }\n\n case \"SEQUENCE\": {\n // Create a SEQUENCE AST node.\n const node = ASTNodeFactories.SEQUENCE();\n\n // Push the SEQUENCE node into the current scope.\n currentScope.push(node);\n\n // Try to pick any attributes off of the token stack.\n node.attributes = getAttributes(tokens, placeholders);\n\n popAndCheck(tokens, \"{\");\n\n // The new scope is that of the new SEQUENCE nodes children.\n stack.push(node.children!);\n break;\n }\n\n case \"PARALLEL\": {\n // Create a PARALLEL AST node.\n const node = ASTNodeFactories.PARALLEL();\n\n // Push the PARALLEL node into the current scope.\n currentScope.push(node);\n\n // Try to pick any attributes off of the token stack.\n node.attributes = getAttributes(tokens, placeholders);\n\n popAndCheck(tokens, \"{\");\n\n // The new scope is that of the new PARALLEL nodes children.\n stack.push(node.children!);\n break;\n }\n\n case \"LOTTO\": {\n // Create a LOTTO AST node.\n const node = ASTNodeFactories.LOTTO();\n\n // Push the LOTTO node into the current scope.\n currentScope.push(node);\n\n // If the next token is a '[' character then some ticket counts have been defined as arguments.\n if (tokens[0] === \"[\") {\n // Get the ticket count arguments, each argument must be a number.\n node.tickets = getArguments(\n tokens,\n placeholders,\n (arg) => arg.type === \"number\" && !!arg.isInteger,\n \"lotto node ticket counts must be integer values\"\n ).map((argument) => argument.value as number);\n }\n\n // Try to pick any attributes off of the token stack.\n node.attributes = getAttributes(tokens, placeholders);\n\n popAndCheck(tokens, \"{\");\n\n // The new scope is that of the new LOTTO nodes children.\n stack.push(node.children!);\n break;\n }\n\n case \"CONDITION\": {\n // Create a CONDITION AST node.\n const node = ASTNodeFactories.CONDITION();\n\n // Push the CONDITION node into the current scope.\n currentScope.push(node);\n\n // We must have arguments defined, as we require a condition function name argument.\n if (tokens[0] !== \"[\") {\n throw new Error(\"expected condition name identifier argument\");\n }\n\n // Grab the condition node arguments.\n const conditionArguments = getArguments(tokens, placeholders);\n\n // We should have at least a single identifier argument for a condition node, which is the condition function name.\n if (conditionArguments.length && conditionArguments[0].type === \"identifier\") {\n // The condition function name will be the first node argument.\n node.conditionName = conditionArguments.shift()!.value as string;\n } else {\n throw new Error(\"expected condition name identifier argument\");\n }\n\n // Only the first argument should have been an identifier, all following arguments must be string, number, boolean or null.\n conditionArguments\n .filter((arg) => arg.type === \"identifier\")\n .forEach((arg) => {\n throw new Error(\n \"invalid condition node argument value '\" +\n arg.value +\n \"', must be string, number, boolean or null\"\n );\n });\n\n // Any node arguments that follow the condition name identifier will be treated as condition function arguments.\n node.conditionArguments = conditionArguments;\n\n // Try to pick any attributes off of the token stack.\n node.attributes = getAttributes(tokens, placeholders);\n break;\n }\n\n case \"FLIP\": {\n // Create a FLIP AST node.\n const node = ASTNodeFactories.FLIP();\n\n // Push the Flip node into the current scope.\n currentScope.push(node);\n\n // Try to pick any attributes off of the token stack.\n node.attributes = getAttributes(tokens, placeholders);\n\n popAndCheck(tokens, \"{\");\n\n // The new scope is that of the new FLIP nodes children.\n stack.push(node.children!);\n break;\n }\n\n case \"SUCCEED\": {\n // Create a SUCCEED AST node.\n const node = ASTNodeFactories.SUCCEED();\n\n // Push the Succeed node into the current scope.\n currentScope.push(node);\n\n // Try to pick any attributes off of the token stack.\n node.attributes = getAttributes(tokens, placeholders);\n\n popAndCheck(tokens, \"{\");\n\n // The new scope is that of the new Succeed nodes children.\n stack.push(node.children!);\n break;\n }\n\n case \"FAIL\": {\n // Create a FAIL AST node.\n const node = ASTNodeFactories.FAIL();\n\n // Push the Fail node into the current scope.\n currentScope.push(node);\n\n // Try to pick any attributes off of the token stack.\n node.attributes = getAttributes(tokens, placeholders);\n\n popAndCheck(tokens, \"{\");\n\n // The new scope is that of the new Fail nodes children.\n stack.push(node.children!);\n break;\n }\n\n case \"WAIT\": {\n // Create a WAIT AST node.\n const node = ASTNodeFactories.WAIT();\n\n // Push the WAIT node into the current scope.\n currentScope.push(node);\n\n // The arguments of a wait node are optional. We may have:\n // - No node arguments, in which case the wait will be indefinite until it is aborted.\n // - One node argument which will be the explicit duration of the wait.\n // - Two node arguments which define the min and max duration bounds from which a random duration will be picked.\n if (tokens[0] === \"[\") {\n // Get the optional duration and longest duration of the wait.\n const nodeArguments = getArguments(\n tokens,\n placeholders,\n (arg) => arg.type === \"number\" && !!arg.isInteger,\n \"wait node durations must be integer values\"\n ).map((argument) => argument.value);\n\n // We may have:\n // - One node argument which will be the explicit duration of the wait.\n // - Two node arguments which define the min and max duration bounds from which a random duration will be picked.\n // - Too many arguments, which is not valid.\n if (nodeArguments.length === 1) {\n // An explicit duration was defined.\n node.duration = nodeArguments[0] as number;\n } else if (nodeArguments.length === 2) {\n // Min and max duration bounds were defined from which a random duration will be picked.\n node.durationMin = nodeArguments[0] as number;\n node.durationMax = nodeArguments[1] as number;\n } else if (nodeArguments.length > 2) {\n // An incorrect number of durations was defined.\n throw new Error(\"invalid number of wait node duration arguments defined\");\n }\n }\n\n // Try to pick any attributes off of the token stack.\n node.attributes = getAttributes(tokens, placeholders);\n break;\n }\n\n case \"REPEAT\": {\n // Create a REPEAT AST node.\n const node = ASTNodeFactories.REPEAT();\n\n // Push the REPEAT node into the current scope.\n currentScope.push(node);\n\n // The arguments of a repeat node are optional. We may have:\n // - No node arguments, in which case the repeat note will iterate indefinitely.\n // - One node argument which will be the explicit number of iterations to make.\n // - Two node arguments which define the min and max iteration bounds from which a random iteration count will be picked.\n if (tokens[0] === \"[\") {\n // An iteration count has been defined. Get the iteration and potential maximum iteration of the wait.\n const nodeArguments = getArguments(\n tokens,\n placeholders,\n (arg) => arg.type === \"number\" && !!arg.isInteger,\n \"repeat node iteration counts must be integer values\"\n ).map((argument) => argument.value);\n\n // We should have got one or two iteration counts.\n if (nodeArguments.length === 1) {\n // A static iteration count was defined.\n node.iterations = nodeArguments[0] as number;\n } else if (nodeArguments.length === 2) {\n // A minimum and maximum iteration count was defined.\n node.iterationsMin = nodeArguments[0] as number;\n node.iterationsMax = nodeArguments[1] as number;\n } else {\n // An incorrect number of iteration counts was defined.\n throw new Error(\"invalid number of repeat node iteration count arguments defined\");\n }\n }\n\n // Try to pick any attributes off of the token stack.\n node.attributes = getAttributes(tokens, placeholders);\n\n popAndCheck(tokens, \"{\");\n\n // The new scope is that of the new REPEAT nodes children.\n stack.push(node.children!);\n break;\n }\n\n case \"RETRY\": {\n // Create a RETRY AST node.\n const node = ASTNodeFactories.RETRY();\n\n // Push the RETRY node into the current scope.\n currentScope.push(node);\n\n // The arguments of a retry node are optional. We may have:\n // - No node arguments, in which case the retry note will attempt indefinitely.\n // - One node argument which will be the explicit number of attempts to make.\n // - Two node arguments which define the min and max attempt bounds from which a random attempt count will be picked.\n if (tokens[0] === \"[\") {\n // An attempt count has been defined. Get the attempt count and potential maximum attempt count of the wait.\n const nodeArguments = getArguments(\n tokens,\n placeholders,\n (arg) => arg.type === \"number\" && !!arg.isInteger,\n \"retry node attempt counts must be integer values\"\n ).map((argument) => argument.value);\n\n // We should have got one or two attempt counts.\n if (nodeArguments.length === 1) {\n // A static attempt count was defined.\n node.attempts = nodeArguments[0] as number;\n } else if (nodeArguments.length === 2) {\n // A minimum and maximum attempt count was defined.\n node.attemptsMin = nodeArguments[0] as number;\n node.attemptsMax = nodeArguments[1] as number;\n } else {\n // An incorrect number of attempt counts was defined.\n throw new Error(\"invalid number of retry node attempt count arguments defined\");\n }\n }\n\n // Try to pick any attributes off of the token stack.\n node.attributes = getAttributes(tokens, placeholders);\n\n popAndCheck(tokens, \"{\");\n\n // The new scope is that of the new RETRY nodes children.\n stack.push(node.children!);\n break;\n }\n\n case \"ACTION\": {\n // Create a ACTION AST node.\n const node = ASTNodeFactories.ACTION();\n\n // Push the ACTION node into the current scope.\n currentScope.push(node);\n\n // We must have arguments defined, as we require an action name argument.\n if (tokens[0] !== \"[\") {\n throw new Error(\"expected action name identifier argument\");\n }\n\n // The action name will be defined as a node argument.\n const actionArguments = getArguments(tokens, placeholders);\n\n // We should have at least one identifer argument for an action node, which is the action name.\n if (actionArguments.length && actionArguments[0].type === \"identifier\") {\n // The action name will be the first and only node argument.\n node.actionName = actionArguments.shift()!.value as string;\n } else {\n throw new Error(\"expected action name identifier argument\");\n }\n\n // Only the first argument should have been an identifier, all following arguments must be string, number, boolean or null.\n actionArguments\n .filter((arg) => arg.type === \"identifier\")\n .forEach((arg) => {\n throw new Error(\n \"invalid action node argument value '\" +\n arg.value +\n \"', must be string, number, boolean or null\"\n );\n });\n\n // Any node arguments that follow the action name identifier will be treated as action function arguments.\n node.actionArguments = actionArguments;\n\n // Try to pick any attributes off of the token stack.\n node.attributes = getAttributes(tokens, placeholders);\n break;\n }\n\n case \"}\": {\n // The '}' character closes the current scope.\n stack.pop();\n break;\n }\n\n default: {\n throw new Error(`unexpected token '${token}'`);\n }\n }\n }\n\n // A function to recursively validate each of the nodes in the AST.\n const validateASTNode = (node: Validatable, depth: number): void => {\n // Validate the node.\n node.validate(depth);\n\n // Validate each child of the node.\n (node.children || []).forEach((child) => validateASTNode(child, depth + 1));\n };\n\n // Start node validation from the definition root.\n validateASTNode(\n {\n children: stack[0] as RootAstNode[],\n validate(this: { children: RootAstNode[] }) {\n // We must have at least one node defined as the definition scope, which should be a root node.\n if (this.children.length === 0) {\n throw new Error(\"expected root node to have been defined\");\n }\n\n // Each node at the base of the definition scope MUST be a root node.\n for (const definitionLevelNode of this.children) {\n if (definitionLevelNode.type !== \"root\") {\n throw new Error(\"expected root node at base of definition\");\n }\n }\n\n // Exactly one root node must not have a name defined. This will be the main root, others will have to be referenced via branch nodes.\n if (this.children.filter((definitionLevelNode) => definitionLevelNode.name === null).length !== 1) {\n throw new Error(\"expected single unnamed root node at base of definition to act as main root\");\n }\n\n // No two named root nodes can have matching names.\n const rootNodeNames: string[] = [];\n for (const definitionLevelNode of this.children) {\n if (rootNodeNames.indexOf(definitionLevelNode.name!) !== -1) {\n throw new Error(`multiple root nodes found with duplicate name '${definitionLevelNode.name}'`);\n } else {\n rootNodeNames.push(definitionLevelNode.name!);\n }\n }\n }\n },\n 0\n );\n\n // Return the root AST nodes.\n return stack[0];\n}\n\n/**\n * Pop the next raw token off of the stack and throw an error if it wasn't the expected one.\n * @param tokens The array of remaining tokens.\n * @param expected An optional string or array or items, one of which must match the next popped token.\n * @returns The popped token.\n */\nfunction popAndCheck(tokens: string[], expected: string | string[]) {\n // Get and remove the next token.\n const popped = tokens.shift();\n\n // We were expecting another token.\n if (popped === undefined) {\n throw new Error(\"unexpected end of definition\");\n }\n\n // Do we have an expected token/tokens array?\n if (expected !== undefined) {\n // Check whether the popped token matches at least one of our expected items.\n var tokenMatchesExpectation = ([] as string[])\n .concat(expected)\n .some((item) => popped.toUpperCase() === item.toUpperCase());\n\n // Throw an error if the popped token didn't match any of our expected items.\n if (!tokenMatchesExpectation) {\n const expectationString = ([] as string[])\n .concat(expected)\n .map((item) => \"'\" + item + \"'\")\n .join(\" or \");\n\n throw new Error(`unexpected token found. Expected '${expectationString}' but got '${popped}'`);\n }\n }\n\n // Return the popped token.\n return popped;\n}\n\ntype StringPlaceholders = { [key: string]: string };\n\n/**\n * Pull an argument definition list off of the token stack.\n * @param tokens The array of remaining tokens.\n * @param stringArgumentPlaceholders The mapping of string literal node argument placeholders to original values.\n * @param argumentValidator The argument validator function.\n * @param validationFailedMessage The exception message to throw if argument validation fails.\n * @returns The argument definition list.\n */\nfunction getArguments(\n tokens: string[],\n stringArgumentPlaceholders: StringPlaceholders,\n argumentValidator?: (arg: AnyArgument) => boolean,\n validationFailedMessage?: string\n) {\n // Any lists of arguments will always be wrapped in '[]' for node arguments or '()' for attribute arguments.\n // We are looking for a '[' or '(' opener that wraps the argument tokens and the relevant closer.\n const closer = popAndCheck(tokens, [\"[\", \"(\"]) === \"[\" ? \"]\" : \")\";\n\n const argumentListTokens: string[] = [];\n const argumentList: AnyArgument[] = [];\n\n // Grab all tokens between the '[' and ']' or '(' and ')'.\n while (tokens.length && tokens[0] !== closer) {\n // The next token is part of our arguments list.\n argumentListTokens.push(tokens.shift()!);\n }\n\n // Validate the order of the argument tokens. Each token must either be a ',' or a single argument that satisfies the validator.\n argumentListTokens.forEach((token, index) => {\n // Get whether this token should be an actual argument.\n const shouldBeArgumentToken = !(index & 1);\n\n // If the current token should be an actual argument then validate it,otherwise it should be a ',' token.\n if (shouldBeArgumentToken) {\n // Get the argument definition.\n const argumentDefinition = getArgumentDefinition(token!, stringArgumentPlaceholders);\n\n // Try to validate the argument.\n if (argumentValidator && !argumentValidator(argumentDefinition)) {\n throw new Error(validationFailedMessage);\n }\n\n // This is a valid argument!\n argumentList.push(argumentDefinition);\n } else {\n // The current token should be a ',' token.\n if (token !== \",\") {\n throw new Error(`invalid argument list, expected ',' or ']' but got '${token}'`);\n }\n }\n });\n\n // The arguments list should terminate with a ']' or ')' token, depending on the opener.\n popAndCheck(tokens, closer);\n\n // Return the argument list.\n return argumentList;\n}\n\n/**\n * Gets an argument value definition.\n * @param token The argument token.\n * @param stringArgumentPlaceholders The mapping of string literal node argument placeholders to original values.\n * @returns An argument value definition.\n */\nfunction getArgumentDefinition(token: string, stringArgumentPlaceholders: StringPlaceholders): AnyArgument {\n // Check whether the token represents a null value.\n if (token === \"null\") {\n return {\n value: null,\n type: \"null\"\n } as NullArgument;\n }\n\n // Check whether the token represents a boolean value.\n if (token === \"true\" || token === \"false\") {\n return {\n value: token === \"true\",\n type: \"boolean\"\n } as BooleanArgument;\n }\n\n // Check whether the token represents a number value.\n // TODO: Relies on broken isNaN - see MDN.\n // if (!Number.isNaN(token)) {\n if (!isNaN(token as any)) {\n return {\n value: parseFloat(token),\n isInteger: parseFloat(token) === parseInt(token, 10),\n type: \"number\"\n } as NumberArgument;\n }\n\n // Check whether the token is a placeholder (e.g. @@0@@) representing a string literal.\n if (token.match(/^@@\\d+@@$/g)) {\n return {\n value: stringArgumentPlaceholders[token].replace('\\\\\"', '\"'),\n type: \"string\"\n } as StringPlaceholderArgument;\n }\n\n // The only remaining option is that the argument value is an identifier.\n return {\n value: token,\n type: \"identifier\"\n } as IdentifierArgument;\n}\n\n/**\n * Pull any attributes off of the token stack.\n * @param tokens The array of remaining tokens.\n * @param stringArgumentPlaceholders The mapping of string literal node argument placeholders to original values.\n * @returns An array of attributes defined by any directly following tokens.\n */\nfunction getAttributes(tokens: string[], stringArgumentPlaceholders: StringPlaceholders) {\n // Create an array to hold any attributes found.\n const attributes: Attribute[] = [];\n\n // Keep track of names of attribute that we have found on the token stack, as we cannot have duplicates.\n const attributesFound: string[] = [];\n\n // Try to get the attribute factory for the next token.\n let attributeFactory = AttributeFactories[(tokens[0] || \"\").toUpperCase()];\n\n // Pull attribute tokens off of the tokens stack until we have no more.\n while (attributeFactory) {\n // Check to make sure that we have not already created a attribute of this type for this node.\n if (attributesFound.indexOf(tokens[0].toUpperCase()) !== -1) {\n throw new Error(`duplicate attribute '${tokens[0].toUpperCase()}' found for node`);\n }\n\n // Add the current attribute type to our array of found attributes.\n attributesFound.push(tokens.shift()!.toUpperCase());\n\n // Grab any attribute arguments.\n const attributeArguments = getArguments(tokens, stringArgumentPlaceholders);\n\n // The first attribute argument has to be an identifer, this will reference an agent function.\n if (attributeArguments.length === 0 || attributeArguments[0].type !== \"identifier\") {\n throw new Error(\"expected agent function name identifier argument for attribute\");\n }\n\n // Grab the first attribute which is an identifier that will reference an agent function.\n const attributeFunctionName = attributeArguments.shift()! as IdentifierArgument;\n\n // Any remaining attribute arguments must have a type of string, number, boolean or null.\n attributeArguments\n .filter((arg) => arg.type === \"identifier\")\n .forEach((arg) => {\n throw new Error(\n \"invalid attribute argument value '\" + arg.value + \"', must be string, number, boolean or null\"\n );\n });\n\n // Create the attribute and add it to the array of attributes found.\n attributes.push(attributeFactory(attributeFunctionName.value, attributeArguments));\n\n // Try to get the next attribute name token, as there could be multiple.\n attributeFactory = AttributeFactories[(tokens[0] || \"\").toUpperCase()];\n }\n\n return attributes;\n}\n\n/**\n * Swaps out any node/attribute argument string literals with placeholders.\n * @param definition The definition.\n * @returns An object containing a mapping of placeholders to original string values as well as the processed definition string.\n */\nfunction substituteStringLiterals(definition: string): {\n placeholders: { [key: string]: string };\n processedDefinition: string;\n} {\n // Create an object to hold the mapping of placeholders to original string values.\n const placeholders: StringPlaceholders = {};\n\n // Replace any string literals wrapped with double quotes in our definition with placeholders to be processed later.\n const processedDefinition = definition.replace(/\\\"(\\\\.|[^\"\\\\])*\\\"/g, (match) => {\n var strippedMatch = match.substring(1, match.length - 1);\n var placeholder = Object.keys(placeholders).find((key) => placeholders[key] === strippedMatch);\n\n // If we have no existing string literal match then create a new placeholder.\n if (!placeholder) {\n placeholder = `@@${Object.keys(placeholders).length}@@`;\n placeholders[placeholder] = strippedMatch;\n }\n\n return placeholder;\n });\n\n return { placeholders, processedDefinition };\n}\n\n/**\n * Parse the tree definition into an array of raw tokens.\n * @param definition The definition.\n * @returns An array of tokens parsed from the definition.\n */\nfunction parseTokensFromDefinition(definition: string): string[] {\n // Add some space around various important characters so that they can be plucked out easier as individual tokens.\n definition = definition.replace(/\\(/g, \" ( \");\n definition = definition.replace(/\\)/g, \" ) \");\n definition = definition.replace(/\\{/g, \" { \");\n definition = definition.replace(/\\}/g, \" } \");\n definition = definition.replace(/\\]/g, \" ] \");\n definition = definition.replace(/\\[/g, \" [ \");\n definition = definition.replace(/\\,/g, \" , \");\n\n // Split the definition into raw token form and return it.\n return definition.replace(/\\s+/g, \" \").trim().split(\" \");\n}\n", "import GuardPath, { GuardPathPart } from \"./attributes/guards/GuardPath\";\nimport buildRootASTNodes, { AnyArgument, RootAstNode } from \"./RootAstNodesBuilder\";\nimport State, { AnyState } from \"./State\";\nimport Lookup from \"./Lookup\";\nimport Node from \"./nodes/Node\";\nimport Root from \"./nodes/decorator/Root\";\nimport Composite from \"./nodes/composite/Composite\";\nimport Decorator from \"./nodes/decorator/Decorator\";\nimport { Agent, GlobalFunction } from \"./Agent\";\nimport { CallbackAttributeDetails } from \"./attributes/callbacks/Callback\";\nimport { GuardAttributeDetails } from \"./attributes/guards/Guard\";\nimport { BehaviourTreeOptions } from \"./BehaviourTreeOptions\";\nimport { convertMDSLToJSON } from \"./mdsl/MDSLDefinitionParser\";\n\n// Purely for outside inspection of the tree.\nexport type FlattenedTreeNode = {\n id: string;\n type: string;\n caption: string;\n state: AnyState;\n guards: GuardAttributeDetails[];\n callbacks: CallbackAttributeDetails[];\n args: AnyArgument[];\n parentId: string | null;\n};\n\n/**\n * A representation of a behaviour tree.\n */\nexport class BehaviourTree {\n /**\n * The main root tree node.\n */\n public readonly rootNode: Root;\n\n /**\n * Creates a new instance of the BehaviourTree class.\n * @param definition The behaviour tree definition.\n * @param agent The agent instance that this behaviour tree is modelling behaviour for.\n * @param options The behaviour tree options object.\n */\n constructor(definition: string, private agent: Agent, private options: BehaviourTreeOptions = {}) {\n // The tree definition must be defined and a valid string.\n if (typeof definition !== \"string\") {\n throw new Error(\"the tree definition must be a string\");\n }\n\n // The agent must be defined and not null.\n if (typeof agent !== \"object\" || agent === null) {\n throw new Error(\"the agent must be defined and not null\");\n }\n\n // Parse the behaviour tree definition, create the populated tree of behaviour tree nodes, and get the root.\n this.rootNode = BehaviourTree._createRootNode(definition);\n }\n\n /**\n * Gets whether the tree is in the RUNNING state.\n * @returns true if the tree is in the RUNNING state, otherwise false.\n */\n isRunning() {\n return this.rootNode.getState() === State.RUNNING;\n }\n\n /**\n * Gets the current tree state of SUCCEEDED, FAILED, READY or RUNNING.\n * @returns The current tree state.\n */\n getState() {\n return this.rootNode.getState();\n }\n\n /**\n * Step the tree.\n * 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.\n * 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\n * 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.\n *\n * 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.\n */\n step() {\n // If the root node has already been stepped to completion then we need to reset it.\n if (this.rootNode.getState() === State.SUCCEEDED || this.rootNode.getState() === State.FAILED) {\n this.rootNode.reset();\n }\n\n try {\n this.rootNode.update(this.agent, this.options);\n } catch (exception) {\n throw new Error(`error stepping tree: ${(exception as Error).message}`);\n }\n }\n\n /**\n * Resets the tree from the root node outwards to each nested node, giving each a state of READY.\n */\n reset() {\n this.rootNode.reset();\n }\n\n /**\n * Gets the flattened details of every node in the tree.\n * @returns The flattened details of every node in the tree.\n */\n getFlattenedNodeDetails(): FlattenedTreeNode[] {\n // Create an empty flattened array of tree nodes.\n const flattenedTreeNodes: FlattenedTreeNode[] = [];\n\n /**\n * Helper function to process a node instance and push details into the flattened tree nodes array.\n * @param node The current node.\n * @param parentUid The UID of the node parent, or null if the node is the main root node.\n */\n const processNode = (node: Node, parentUid: string | null) => {\n // Get the guard and callback attribute details for this node.\n const guards = node\n .getAttributes()\n .filter((attribute) => attribute.isGuard())\n .map((attribute) => attribute.getDetails()) as GuardAttributeDetails[];\n const callbacks = node\n .getAttributes()\n .filter((attribute) => !attribute.isGuard())\n .map((attribute) => attribute.getDetails()) as CallbackAttributeDetails[];\n\n // Push the current node into the flattened nodes array.\n flattenedTreeNodes.push({\n id: node.getUid(),\n type: node.getType(),\n caption: node.getName(),\n state: node.getState(),\n guards,\n callbacks,\n args: node.getArguments(),\n parentId: parentUid\n });\n\n // Process each of the nodes children if it is not a leaf node.\n if (!node.isLeafNode()) {\n (node as Composite | Decorator)\n .getChildren()\n .forEach((child) => processNode(child, (node as Composite | Decorator).getUid()));\n }\n };\n\n // Convert the nested node structure into a flattened array of node details.\n processNode(this.rootNode, null);\n\n return flattenedTreeNodes;\n }\n\n /**\n * Registers the action/condition/guard/callback function or subtree with the given name.\n * @param name The name of the function or subtree to register.\n * @param value The function or subtree definition to register.\n */\n static register(name: string, value: GlobalFunction | string) {\n if (typeof value === \"function\") {\n // We are going to register a action/condition/guard/callback function.\n Lookup.setFunc(name, value);\n } else if (typeof value === \"string\") {\n // We are going to register a subtree.\n let rootASTNodes: RootAstNode[];\n\n try {\n // Try to create the behaviour tree AST based on the definition provided, this could fail if the definition is invalid.\n rootASTNodes = buildRootASTNodes(value);\n } catch (exception) {\n // There was an issue in trying to parse and build the tree definition.\n throw new Error(`error registering definition: ${(exception as Error).message}`);\n }\n\n // This function should only ever be called with a definition containing a single unnamed root node.\n if (rootASTNodes.length != 1 || rootASTNodes[0].name !== null) {\n throw new Error(\"error registering definition: expected a single unnamed root node\");\n }\n\n Lookup.setSubtree(name, rootASTNodes[0]);\n } else {\n throw new Error(\"unexpected value, expected string definition or function\");\n }\n }\n\n /**\n * Unregisters the registered action/condition/guard/callback function or subtree with the given name.\n * @param name The name of the registered action/condition/guard/callback function or subtree to unregister.\n */\n static unregister(name: string): void {\n Lookup.remove(name);\n }\n\n /**\n * Unregister all registered action/condition/guard/callback functions and subtrees.\n */\n static unregisterAll(): void {\n Lookup.empty();\n }\n\n /**\n * Parses a behaviour tree definition and creates a tree of behaviour tree nodes.\n * @param {string} definition The behaviour tree definition.\n * @returns The root behaviour tree node.\n */\n private static _createRootNode(definition: string): Root {\n // TODO Remove!\n try {\n // parseToJSON(definition);\n } catch (exception) {\n console.log(exception);\n }\n\n try {\n // Try to create the behaviour tree AST based on the definition provided, this could fail if the definition is invalid.\n const rootASTNodes = buildRootASTNodes(definition);\n\n // Create a symbol to use as the main root key in our root node mapping.\n const mainRootNodeKey = Symbol(\"__root__\");\n\n // Create a mapping of root node names to root AST tokens. The main root node will have a key of Symbol(\"__root__\").\n const rootNodeMap: { [key: string | symbol]: RootAstNode } = {};\n for (const rootASTNode of rootASTNodes) {\n rootNodeMap[rootASTNode.name === null ? mainRootNodeKey : rootASTNode.name!] = rootASTNode;\n }\n\n // Convert the AST to our actual tree and get the root node.\n const rootNode: Root = rootNodeMap[mainRootNodeKey].createNodeInstance(\n // Create a provider for named root nodes that are part of our definition or have been registered. Prioritising the former.\n (name: string): RootAstNode => (rootNodeMap[name] ? rootNodeMap[name] : Lookup.getSubtree(name)),\n []\n );\n\n // Set a guard path on every leaf of the tree to evaluate as part of its update.\n BehaviourTree._applyLeafNodeGuardPaths(rootNode);\n\n // Return the root node.\n return rootNode;\n } catch (exception) {\n // There was an issue in trying to parse and build the tree definition.\n throw new Error(`error parsing tree: ${(exception as Error).message}`);\n }\n }\n\n /**\n * Applies a guard path to every leaf of the tree to evaluate as part of each update.\n * @param rootNode The main root tree node.\n */\n private static _applyLeafNodeGuardPaths(rootNode: Root) {\n const nodePaths: Node[][] = [];\n\n const findLeafNodes = (path: Node[], node: Node) => {\n // Add the current node to the path.\n path = path.concat(node);\n\n // Check whether the current node is a leaf node.\n if (node.isLeafNode()) {\n nodePaths.push(path);\n } else {\n (node as Composite | Decorator).getChildren().forEach((child) => findLeafNodes(path, child));\n }\n };\n\n // Find all leaf node paths, starting from the root.\n findLeafNodes([], rootNode);\n\n nodePaths.forEach((path) => {\n // Each node in the current path will have to be assigned a guard path, working from the root outwards.\n for (let depth = 0; depth < path.length; depth++) {\n // Get the node in the path at the current depth.\n const currentNode = path[depth];\n\n // The node may already have been assigned a guard path, if so just skip it.\n if (currentNode.hasGuardPath()) {\n continue;\n }\n\n // Create the guard path for the current node.\n const guardPath = new GuardPath(\n path\n .slice(0, depth + 1)\n .map((node) => ({ node, guards: node.getGuardAttributes() }))\n .filter((details) => details.guards.length > 0)\n );\n\n // Assign the guard path to the current node.\n currentNode.setGuardPath(guardPath);\n }\n });\n }\n}\n"], - "mappings": "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", - "names": ["Participant", "Lotto", "createLotto", "State", "createLotto", "substituteStringLiterals", "parseTokensFromDefinition", "popAndCheck", "getArgumentDefinition"] + "sources": ["../src/index.ts", "../src/State.ts", "../src/BehaviourTreeDefinitionUtilities.ts", "../src/mdsl/MDSLUtilities.ts", "../src/mdsl/MDSLNodeArgumentParser.ts", "../src/mdsl/MDSLNodeAttributeParser.ts", "../src/mdsl/MDSLDefinitionParser.ts", "../src/BehaviourTreeDefinitionValidator.ts", "../src/Lookup.ts", "../src/attributes/guards/GuardUnsatisifedException.ts", "../src/attributes/guards/GuardPath.ts", "../src/nodes/Node.ts", "../src/nodes/decorator/Decorator.ts", "../src/nodes/decorator/Root.ts", "../src/attributes/Attribute.ts", "../src/attributes/guards/Guard.ts", "../src/attributes/guards/While.ts", "../src/attributes/guards/Until.ts", "../src/attributes/callbacks/Callback.ts", "../src/attributes/callbacks/Entry.ts", "../src/attributes/callbacks/Step.ts", "../src/attributes/callbacks/Exit.ts", "../src/BehaviourTreeBuilder.ts", "../src/BehaviourTree.ts"], + "sourcesContent": ["import State from \"./State\";\nimport { validateDefinition } from \"./BehaviourTreeDefinitionValidator\";\nimport { convertMDSLToJSON } from \"./mdsl/MDSLDefinitionParser\";\nimport { BehaviourTree, FlattenedTreeNode } from \"./BehaviourTree\";\n\nexport { BehaviourTree, State, convertMDSLToJSON, validateDefinition };\nexport type { FlattenedTreeNode };\n", "/**\n * Enumeration of node state types.\n */\nexport enum State {\n READY = \"mistreevous.ready\",\n RUNNING = \"mistreevous.running\",\n SUCCEEDED = \"mistreevous.succeeded\",\n FAILED = \"mistreevous.failed\"\n}\n\nexport { State as default };\n\nexport type CompleteState = State.SUCCEEDED | State.FAILED;\nexport type AnyState = State.READY | State.RUNNING | CompleteState;\n", "import {\n NodeDefinition,\n RootNodeDefinition,\n DecoratorNodeDefinition,\n CompositeNodeDefinition,\n AnyNodeDefinition,\n BranchNodeDefinition\n} from \"./BehaviourTreeDefinition\";\n\n/**\n * A type guard function that returns true if the specified node satisfies the RootNodeDefinition type.\n * @param node The node.\n * @returns A value of true if the specified node satisfies the RootNodeDefinition type.\n */\nexport function isRootNode(node: NodeDefinition): node is RootNodeDefinition {\n return node.type === \"root\";\n}\n\n/**\n * A type guard function that returns true if the specified node satisfies the BranchNodeDefinition type.\n * @param node The node.\n * @returns A value of true if the specified node satisfies the BranchNodeDefinition type.\n */\nexport function isBranchNode(node: NodeDefinition): node is BranchNodeDefinition {\n return node.type === \"branch\";\n}\n\n/**\n * A type guard function that returns true if the specified node satisfies the NodeDefinition type.\n * @param node The node.\n * @returns A value of true if the specified node satisfies the NodeDefinition type.\n */\nexport function isLeafNode(node: NodeDefinition): node is NodeDefinition {\n return [\"branch\", \"action\", \"condition\", \"wait\"].includes(node.type);\n}\n\n/**\n * A type guard function that returns true if the specified node satisfies the DecoratorNodeDefinition type.\n * @param node The node.\n * @returns A value of true if the specified node satisfies the DecoratorNodeDefinition type.\n */\nexport function isDecoratorNode(node: NodeDefinition): node is DecoratorNodeDefinition {\n return [\"root\", \"repeat\", \"retry\", \"flip\", \"succeed\", \"fail\"].includes(node.type);\n}\n\n/**\n * A type guard function that returns true if the specified node satisfies the CompositeNodeDefinition type.\n * @param node The node.\n * @returns A value of true if the specified node satisfies the CompositeNodeDefinition type.\n */\nexport function isCompositeNode(node: NodeDefinition): node is CompositeNodeDefinition {\n return [\"sequence\", \"selector\", \"lotto\", \"parallel\"].includes(node.type);\n}\n\n/**\n * Flatten a node definition into an array of all of its nested node definitions.\n * @param nodeDefinition The node definition to flatten.\n * @returns An array of all of nested node definitions.\n */\nexport function flattenDefinition(nodeDefinition: AnyNodeDefinition): AnyNodeDefinition[] {\n const nodes: AnyNodeDefinition[] = [];\n\n const processNode = (currentNodeDefinition: AnyNodeDefinition) => {\n nodes.push(currentNodeDefinition);\n\n if (isCompositeNode(currentNodeDefinition)) {\n currentNodeDefinition.children.forEach(processNode);\n } else if (isDecoratorNode(currentNodeDefinition)) {\n processNode(currentNodeDefinition.child);\n }\n };\n\n processNode(nodeDefinition);\n\n return nodes;\n}\n\n/**\n * Determines whether the passed value is an integer.\n * @param value The value to check.\n * @returns Whether the passed value is an integer.\n */\nexport function isInteger(value: unknown): boolean {\n return typeof value === \"number\" && Math.floor(value) === value;\n}\n", "/**\n * A type defining an object that holds a reference to substitued string literals parsed from the definition.\n */\nexport type StringLiteralPlaceholders = { [key: string]: string };\n\n/**\n * Pop the next raw token from the specified array of tokens and throw an error if it wasn't the expected one.\n * @param tokens The array of tokens.\n * @param expected An optional string or array or items, one of which must match the next popped token.\n * @returns The popped token.\n */\nexport function popAndCheck(tokens: string[], expected?: string | string[]): string {\n // Get and remove the next token.\n const popped = tokens.shift();\n\n // We were expecting another token but there aren't any.\n if (popped === undefined) {\n throw new Error(\"unexpected end of definition\");\n }\n\n // Do we have an expected token/tokens array?\n if (expected != undefined) {\n // Get an array of expected values, if the popped token matches any then we are all good.\n const expectedValues = typeof expected === \"string\" ? [expected] : expected;\n\n // Check whether the popped token matches at least one of our expected items.\n var tokenMatchesExpectation = expectedValues.some((item) => popped.toUpperCase() === item.toUpperCase());\n\n // Throw an error if the popped token didn't match any of our expected items.\n if (!tokenMatchesExpectation) {\n const expectationString = expectedValues.map((item) => \"'\" + item + \"'\").join(\" or \");\n throw new Error(\"unexpected token found. Expected \" + expectationString + \" but got '\" + popped + \"'\");\n }\n }\n\n // Return the popped token.\n return popped;\n}\n\n/**\n * Swaps out any node/attribute argument string literals with placeholders.\n * @param definition The definition.\n * @returns An object containing a mapping of placeholders to original string values as well as the processed definition string.\n */\nexport function substituteStringLiterals(definition: string): {\n placeholders: StringLiteralPlaceholders;\n processedDefinition: string;\n} {\n // Create an object to hold the mapping of placeholders to original string values.\n const placeholders: StringLiteralPlaceholders = {};\n\n // Replace any string literals wrapped with double quotes in our definition with placeholders to be processed later.\n const processedDefinition = definition.replace(/\\\"(\\\\.|[^\"\\\\])*\\\"/g, (match) => {\n var strippedMatch = match.substring(1, match.length - 1);\n var placeholder = Object.keys(placeholders).find((key) => placeholders[key] === strippedMatch);\n\n // If we have no existing string literal match then create a new placeholder.\n if (!placeholder) {\n placeholder = `@@${Object.keys(placeholders).length}@@`;\n placeholders[placeholder] = strippedMatch;\n }\n\n return placeholder;\n });\n\n return { placeholders, processedDefinition };\n}\n\n/**\n * Parse the tree definition into an array of raw tokens.\n * @param definition The definition.\n * @returns An array of tokens parsed from the definition.\n */\nexport function parseTokensFromDefinition(definition: string): string[] {\n // Add some space around various important characters so that they can be plucked out easier as individual tokens.\n definition = definition.replace(/\\(/g, \" ( \");\n definition = definition.replace(/\\)/g, \" ) \");\n definition = definition.replace(/\\{/g, \" { \");\n definition = definition.replace(/\\}/g, \" } \");\n definition = definition.replace(/\\]/g, \" ] \");\n definition = definition.replace(/\\[/g, \" [ \");\n definition = definition.replace(/\\,/g, \" , \");\n\n // Split the definition into raw token form and return it.\n return definition.replace(/\\s+/g, \" \").trim().split(\" \");\n}\n", "import { StringLiteralPlaceholders, popAndCheck } from \"./MDSLUtilities\";\n\n/**\n * A type representing any node function argument.\n */\ntype Argument = {\n /**\n * The argument value.\n */\n value: T;\n /**\n * The argument type, used for validation.\n */\n type: string;\n};\n\ntype NullArgument = Argument & {\n type: \"null\";\n};\n\ntype BooleanArgument = Argument & {\n type: \"boolean\";\n};\n\ntype NumberArgument = Argument & {\n type: \"number\";\n /**\n * A flag defining whether the number argument value is a valid integer. (used for validation)\n */\n isInteger: boolean;\n};\n\ntype StringPlaceholderArgument = Argument & {\n type: \"string\";\n};\n\ntype IdentifierArgument = Argument & {\n type: \"identifier\";\n};\n\n/**\n * A type representing a reference to any node function argument.\n */\ntype AnyArgument = NullArgument | BooleanArgument | NumberArgument | StringPlaceholderArgument | IdentifierArgument;\n\n/**\n * Parse an array of argument definitions from the specified tokens array.\n * @param tokens The array tokens to parse the argument definitions from.\n * @param stringArgumentPlaceholders The mapping of string literal node argument placeholders to original values.\n * @param argumentValidator The argument validator function.\n * @param validationFailedMessage The exception message to throw if argument validation fails.\n * @returns An array of argument definitions parsed from the specified tokens array.\n */\nexport function parseArgumentTokens(\n tokens: string[],\n stringArgumentPlaceholders: StringLiteralPlaceholders\n): AnyArgument[] {\n const argumentList: AnyArgument[] = [];\n\n // If the next token is not a '[' or '(' then we have no arguments to parse.\n if (![\"[\", \"(\"].includes(tokens[0])) {\n return argumentList;\n }\n\n // Any lists of arguments will always be wrapped in '[]' for node arguments or '()' for attribute arguments.\n // We are looking for a '[' or '(' opener that wraps the argument tokens and the relevant closer.\n const closingToken = popAndCheck(tokens, [\"[\", \"(\"]) === \"[\" ? \"]\" : \")\";\n\n const argumentListTokens: string[] = [];\n\n // Grab all tokens between the '[' and ']' or '(' and ')'.\n while (tokens.length && tokens[0] !== closingToken) {\n // The next token is part of our arguments list.\n argumentListTokens.push(tokens.shift()!);\n }\n\n // Validate the order of the argument tokens. Each token must either be a ',' or a single argument that satisfies the validator.\n argumentListTokens.forEach((token, index) => {\n // Get whether this token should be an actual argument.\n const shouldBeArgumentToken = !(index & 1);\n\n // If the current token should be an actual argument then validate it, otherwise it should be a ',' token.\n if (shouldBeArgumentToken) {\n // Get the argument definition.\n const argumentDefinition = getArgumentDefinition(token, stringArgumentPlaceholders);\n\n // This is a valid argument!\n argumentList.push(argumentDefinition);\n } else {\n // The current token should be a ',' token.\n if (token !== \",\") {\n throw new Error(`invalid argument list, expected ',' or ']' but got '${token}'`);\n }\n }\n });\n\n // The arguments list should terminate with a ']' or ')' token, depending on the opener.\n popAndCheck(tokens, closingToken);\n\n // Return the arguments.\n return argumentList;\n}\n\n/**\n * Gets an argument value definition.\n * @param token The argument token.\n * @param stringArgumentPlaceholders The mapping of string literal node argument placeholders to original values.\n * @returns An argument value definition.\n */\nfunction getArgumentDefinition(token: string, stringArgumentPlaceholders: StringLiteralPlaceholders): AnyArgument {\n // Check whether the token represents a null value.\n if (token === \"null\") {\n return {\n value: null,\n type: \"null\"\n } as NullArgument;\n }\n\n // Check whether the token represents a boolean value.\n if (token === \"true\" || token === \"false\") {\n return {\n value: token === \"true\",\n type: \"boolean\"\n } as BooleanArgument;\n }\n\n // Check whether the token represents a number value.\n // TODO: Relies on broken isNaN - see MDN.\n // if (!Number.isNaN(token)) {\n if (!isNaN(token as any)) {\n return {\n value: parseFloat(token),\n isInteger: parseFloat(token) === parseInt(token, 10),\n type: \"number\"\n } as NumberArgument;\n }\n\n // Check whether the token is a placeholder (e.g. @@0@@) representing a string literal.\n if (token.match(/^@@\\d+@@$/g)) {\n return {\n value: stringArgumentPlaceholders[token].replace('\\\\\"', '\"'),\n type: \"string\"\n } as StringPlaceholderArgument;\n }\n\n // The only remaining option is that the argument value is an identifier.\n return {\n value: token,\n type: \"identifier\"\n } as IdentifierArgument;\n}\n", "import { NodeAttributeDefinition } from \"../BehaviourTreeDefinition\";\nimport { parseArgumentTokens } from \"./MDSLNodeArgumentParser\";\nimport { StringLiteralPlaceholders } from \"./MDSLUtilities\";\n\n/**\n * A type defining the attribute definitions of a node.\n */\ntype NodeAttributes = {\n while?: NodeAttributeDefinition;\n until?: NodeAttributeDefinition;\n entry?: NodeAttributeDefinition;\n exit?: NodeAttributeDefinition;\n step?: NodeAttributeDefinition;\n};\n\n/**\n * Parse any node attribute definitions from the specified tokens array.\n * @param tokens The array of remaining tokens.\n * @param stringArgumentPlaceholders The mapping of string literal node argument placeholders to original values.\n * @returns An object of attribute definitions defined by any directly following tokens.\n */\nexport function parseAttributeTokens(\n tokens: string[],\n stringArgumentPlaceholders: StringLiteralPlaceholders\n): NodeAttributes {\n const nodeAttributeNames: (keyof NodeAttributes)[] = [\"while\", \"until\", \"entry\", \"exit\", \"step\"];\n\n // Create an object to hold any attributes found.\n const attributes: NodeAttributes = {};\n\n // Try to get the name of the attribute for the next token.\n let nextAttributeName = tokens[0]?.toLowerCase() as keyof NodeAttributes;\n\n // Pull attribute tokens as well as their arguments off of the tokens stack until we have no more.\n while (nodeAttributeNames.includes(nextAttributeName)) {\n // Check to make sure that we have not already created an attribute definition of this type.\n if (attributes[nextAttributeName]) {\n throw new Error(`duplicate attribute '${tokens[0].toUpperCase()}' found for node`);\n }\n\n // Remove the attribute name token from the array of tokens.\n tokens.shift();\n\n // Grab the attribute arguments, assuming the first to be an identifier.\n const [attributeCallIdentifier, ...attributeArguments] = parseArgumentTokens(\n tokens,\n stringArgumentPlaceholders\n );\n\n // The first attribute argument has to be an identifer, this will reference an agent function.\n if (attributeCallIdentifier?.type !== \"identifier\") {\n throw new Error(\"expected agent function name identifier argument for attribute\");\n }\n\n // Any attribute arguments (other than the expected call identifier) must have a type of string, number, boolean or null.\n attributeArguments\n .filter((arg) => arg.type === \"identifier\")\n .forEach((arg) => {\n throw new Error(\n `invalid attribute argument value '${arg.value}', must be string, number, boolean or null`\n );\n });\n\n // Create the attribute definition and add it to the object of attribute definitions found.\n attributes[nextAttributeName] = {\n call: attributeCallIdentifier.value,\n args: attributeArguments.map(({ value }) => value)\n };\n\n // Try to get the next attribute name token, as there could be multiple.\n nextAttributeName = tokens[0]?.toLowerCase() as keyof NodeAttributes;\n }\n\n return attributes;\n}\n", "import {\n ActionNodeDefinition,\n AnyChildNodeDefinition,\n AnyNodeDefinition,\n BranchNodeDefinition,\n ConditionNodeDefinition,\n FailNodeDefinition,\n FlipNodeDefinition,\n LottoNodeDefinition,\n ParallelNodeDefinition,\n RepeatNodeDefinition,\n RetryNodeDefinition,\n RootNodeDefinition,\n SelectorNodeDefinition,\n SequenceNodeDefinition,\n SucceedNodeDefinition,\n WaitNodeDefinition\n} from \"../BehaviourTreeDefinition\";\nimport { isCompositeNode, isDecoratorNode, isLeafNode, isRootNode } from \"../BehaviourTreeDefinitionUtilities\";\nimport { parseArgumentTokens } from \"./MDSLNodeArgumentParser\";\nimport { parseAttributeTokens } from \"./MDSLNodeAttributeParser\";\nimport {\n StringLiteralPlaceholders,\n parseTokensFromDefinition,\n popAndCheck,\n substituteStringLiterals\n} from \"./MDSLUtilities\";\n\n/**\n * Convert the MDSL tree definition string into an equivalent JSON definition.\n * @param definition The tree definition string as MDSL.\n * @returns The root node JSON definitions.\n */\nexport function convertMDSLToJSON(definition: string): RootNodeDefinition[] {\n // Swap out any node/attribute argument string literals with a placeholder and get a mapping of placeholders to original values as well as the processed definition.\n const { placeholders, processedDefinition } = substituteStringLiterals(definition);\n\n // Parse our definition definition string into an array of raw tokens.\n const tokens = parseTokensFromDefinition(processedDefinition);\n\n return convertTokensToJSONDefinition(tokens, placeholders);\n}\n\n/**\n * Converts the specified tree definition tokens into a JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The root node JSON definitions.\n */\nfunction convertTokensToJSONDefinition(\n tokens: string[],\n stringLiteralPlaceholders: StringLiteralPlaceholders\n): RootNodeDefinition[] {\n // There must be at least 3 tokens for the tree definition to be valid. 'ROOT', '{' and '}'.\n if (tokens.length < 3) {\n throw new Error(\"invalid token count\");\n }\n\n // We should have a matching number of '{' and '}' tokens. If not, then there are scopes that have not been properly closed.\n if (tokens.filter((token) => token === \"{\").length !== tokens.filter((token) => token === \"}\").length) {\n throw new Error(\"scope character mismatch\");\n }\n\n // Create an array of tree stack arrays where root nodes will always be at the botton and the current composite/decorator node at the top.\n // There should be an element in this array for every root node defined and every element should be an array with a root note as the first element.\n // E.g. A definition with two root nodes defined:\n // [\n // [root, lotto, sequence],\n // [root, selector]\n // ]\n const treeStacks: [Partial, ...Partial[]][] = [];\n\n // Create an array of all root node definitions that we create.\n const rootNodes: Partial[] = [];\n\n // A helper function used to push node definitions onto the tree stack.\n const pushNode = (node: AnyNodeDefinition) => {\n // If the node is a root node then we need to create a new tree stack array with the root node at the root.\n if (isRootNode(node)) {\n // Add the root node definition to our array of all parsed root node definitions.\n rootNodes.push(node);\n\n // Add the root node definition to the root of a new tree stack.\n treeStacks.push([node]);\n\n return;\n }\n\n // All non-root nodes should be pushed after their root nodes so handle cases\n // where we may not have any tree stacks or our top-most tree stack is empty.\n if (!treeStacks.length || !treeStacks[treeStacks.length - 1].length) {\n throw new Error(\"expected root node at base of definition\");\n }\n\n // Get the current tree stack that we are populating.\n const topTreeStack = treeStacks[treeStacks.length - 1];\n\n // Get the top-most node in the current tree stack, this will be a composite/decorator node\n // for which we will populate its children array if composite or setting its child if a decorator.\n const topTreeStackTopNode = topTreeStack[topTreeStack.length - 1] as AnyNodeDefinition;\n\n // If the top-most node in the current root stack is a composite or decorator\n // node then the current node should be added as a child of the top-most node.\n if (isCompositeNode(topTreeStackTopNode)) {\n topTreeStackTopNode.children = topTreeStackTopNode.children || [];\n topTreeStackTopNode.children.push(node);\n } else if (isDecoratorNode(topTreeStackTopNode)) {\n // If the top node already has a child node set then throw an error as a decorator should only have a single child.\n if (topTreeStackTopNode.child) {\n throw new Error(\"a decorator node must only have a single child node\");\n }\n\n topTreeStackTopNode.child = node;\n }\n\n // If the node we are adding is also a composite or decorator node, then we should push it\n // onto the current tree stack, as subsequent nodes will be added as its child/children.\n if (!isLeafNode(node)) {\n topTreeStack.push(node);\n }\n };\n\n // A helper function used to pop node definitions off of the stack.\n const popNode = () => {\n // Get the current tree stack that we are populating.\n const topTreeStack = treeStacks[treeStacks.length - 1];\n\n // Pop the top-most node in the current tree stack if there is one.\n if (topTreeStack.length) {\n topTreeStack.pop();\n }\n\n // We don't want any empty tree stacks in our stack of tree stacks.\n if (!topTreeStack.length) {\n treeStacks.pop();\n }\n };\n\n // We should keep processing the raw tokens until we run out of them.\n while (tokens.length) {\n // Grab the next token.\n const token = tokens.shift()!;\n\n // How we create the next node depends on the current raw token value.\n switch (token.toUpperCase()) {\n case \"ROOT\": {\n pushNode(createRootNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"SUCCEED\": {\n pushNode(createSucceedNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"FAIL\": {\n pushNode(createFailNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"FLIP\": {\n pushNode(createFlipNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"REPEAT\": {\n pushNode(createRepeatNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"RETRY\": {\n pushNode(createRetryNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"SEQUENCE\": {\n pushNode(createSequenceNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"SELECTOR\": {\n pushNode(createSelectorNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"PARALLEL\": {\n pushNode(createParallelNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"LOTTO\": {\n pushNode(createLottoNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"ACTION\": {\n pushNode(createActionNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"CONDITION\": {\n pushNode(createConditionNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"WAIT\": {\n pushNode(createWaitNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"BRANCH\": {\n pushNode(createBranchNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"}\": {\n // The '}' character closes the current scope and means that we have to pop a node off of the current stack.\n popNode();\n break;\n }\n\n default: {\n throw new Error(`unexpected token: ${token}`);\n }\n }\n }\n\n return rootNodes as RootNodeDefinition[];\n}\n\n/**\n * Creates a root node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The root node JSON definition.\n */\nfunction createRootNode(tokens: string[], stringLiteralPlaceholders: StringLiteralPlaceholders): RootNodeDefinition {\n // Create the root node definition.\n let node = {\n type: \"root\",\n id: undefined\n } as RootNodeDefinition;\n\n // Parse any node arguments, we should only have one if any which will be an identifier argument for the root identifier.\n const nodeArguments = parseArgumentTokens(tokens, stringLiteralPlaceholders);\n\n // Check whether any node arguments were defined.\n if (nodeArguments.length) {\n // We should only have one argument, if any, which will be an identifier argument for the root identifier.\n if (nodeArguments.length === 1 && nodeArguments[0].type === \"identifier\") {\n // The root node identifier will be the first and only node argument value.\n node.id = nodeArguments[0].value as string;\n } else {\n throw new Error(\"expected single root name argument\");\n }\n }\n\n // Grab any node attribute definitions and spread them into the node definition.\n node = { ...node, ...parseAttributeTokens(tokens, stringLiteralPlaceholders) };\n\n // This is a decorator node, so we expect an opening '{'.\n popAndCheck(tokens, \"{\");\n\n // Return the root node definition.\n return node;\n}\n\n/**\n * Creates a succeed node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The succeed node JSON definition.\n */\nfunction createSucceedNode(\n tokens: string[],\n stringLiteralPlaceholders: StringLiteralPlaceholders\n): SucceedNodeDefinition {\n const node = {\n type: \"succeed\",\n ...parseAttributeTokens(tokens, stringLiteralPlaceholders)\n } as SucceedNodeDefinition;\n\n // This is a decorator node, so we expect an opening '{'.\n popAndCheck(tokens, \"{\");\n\n // Return the succeed node definition.\n return node;\n}\n\n/**\n * Creates a fail node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The fail node JSON definition.\n */\nfunction createFailNode(tokens: string[], stringLiteralPlaceholders: StringLiteralPlaceholders): FailNodeDefinition {\n const node = {\n type: \"fail\",\n ...parseAttributeTokens(tokens, stringLiteralPlaceholders)\n } as FailNodeDefinition;\n\n // This is a decorator node, so we expect an opening '{'.\n popAndCheck(tokens, \"{\");\n\n // Return the fail node definition.\n return node;\n}\n\n/**\n * Creates a flip node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The flip node JSON definition.\n */\nfunction createFlipNode(tokens: string[], stringLiteralPlaceholders: StringLiteralPlaceholders): FlipNodeDefinition {\n const node = {\n type: \"flip\",\n ...parseAttributeTokens(tokens, stringLiteralPlaceholders)\n } as FlipNodeDefinition;\n\n // This is a decorator node, so we expect an opening '{'.\n popAndCheck(tokens, \"{\");\n\n // Return the flip node definition.\n return node;\n}\n\n/**\n * Creates a repeat node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The repeat node JSON definition.\n */\nfunction createRepeatNode(\n tokens: string[],\n stringLiteralPlaceholders: StringLiteralPlaceholders\n): RepeatNodeDefinition {\n let node = { type: \"repeat\" } as RepeatNodeDefinition;\n\n // Get the node arguments.\n const nodeArguments = parseArgumentTokens(tokens, stringLiteralPlaceholders);\n\n // The arguments of a repeat node are optional. We may have:\n // - No node arguments, in which case the repeat note will iterate indefinitely.\n // - One node argument which will be the explicit number of iterations to make.\n // - Two node arguments which define the min and max iteration bounds from which a random iteration count will be picked.\n if (nodeArguments.length) {\n // All repeat node arguments MUST be of type number and must be integer.\n nodeArguments\n .filter((arg) => arg.type !== \"number\" || !arg.isInteger)\n .forEach(() => {\n throw new Error(`repeat node iteration counts must be integer values`);\n });\n\n // We should have got one or two iteration counts.\n if (nodeArguments.length === 1) {\n // A static iteration count was defined.\n node.iterations = nodeArguments[0].value as number;\n } else if (nodeArguments.length === 2) {\n // A minimum and maximum iteration count was defined.\n node.iterations = [nodeArguments[0].value as number, nodeArguments[1].value as number];\n } else {\n // An incorrect number of iteration counts was defined.\n throw new Error(\"invalid number of repeat node iteration count arguments defined\");\n }\n }\n\n // Grab any node attribute definitions and spread them into the node definition.\n node = { ...node, ...parseAttributeTokens(tokens, stringLiteralPlaceholders) };\n\n // This is a decorator node, so we expect an opening '{'.\n popAndCheck(tokens, \"{\");\n\n // Return the repeat node definition.\n return node;\n}\n\n/**\n * Creates a retry node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The retry node JSON definition.\n */\nfunction createRetryNode(tokens: string[], stringLiteralPlaceholders: StringLiteralPlaceholders): RetryNodeDefinition {\n let node = { type: \"retry\" } as RetryNodeDefinition;\n\n // Get the node arguments.\n const nodeArguments = parseArgumentTokens(tokens, stringLiteralPlaceholders);\n\n // The arguments of a retry node are optional. We may have:\n // - No node arguments, in which case the retry note will attempt indefinitely.\n // - One node argument which will be the explicit number of attempts to make.\n // - Two node arguments which define the min and max attempt bounds from which a random attempt count will be picked.\n if (nodeArguments.length) {\n // All retry node arguments MUST be of type number and must be integer.\n nodeArguments\n .filter((arg) => arg.type !== \"number\" || !arg.isInteger)\n .forEach(() => {\n throw new Error(`retry node attempt counts must be integer values`);\n });\n\n // We should have got one or two attempt counts.\n if (nodeArguments.length === 1) {\n // A static attempt count was defined.\n node.attempts = nodeArguments[0].value as number;\n } else if (nodeArguments.length === 2) {\n // A minimum and maximum attempt count was defined.\n node.attempts = [nodeArguments[0].value as number, nodeArguments[1].value as number];\n } else {\n // An incorrect number of attempt counts was defined.\n throw new Error(\"invalid number of retry node attempt count arguments defined\");\n }\n }\n\n // Grab any node attribute definitions and spread them into the node definition.\n node = { ...node, ...parseAttributeTokens(tokens, stringLiteralPlaceholders) };\n\n // This is a decorator node, so we expect an opening '{'.\n popAndCheck(tokens, \"{\");\n\n // Return the retry node definition.\n return node;\n}\n\n/**\n * Creates a sequence node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The sequence node JSON definition.\n */\nfunction createSequenceNode(\n tokens: string[],\n stringLiteralPlaceholders: StringLiteralPlaceholders\n): SequenceNodeDefinition {\n const node = {\n type: \"sequence\",\n ...parseAttributeTokens(tokens, stringLiteralPlaceholders)\n } as SequenceNodeDefinition;\n\n // This is a composite node, so we expect an opening '{'.\n popAndCheck(tokens, \"{\");\n\n // Return the sequence node definition.\n return node;\n}\n\n/**\n * Creates a selector node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The selector node JSON definition.\n */\nfunction createSelectorNode(\n tokens: string[],\n stringLiteralPlaceholders: StringLiteralPlaceholders\n): SelectorNodeDefinition {\n const node = {\n type: \"selector\",\n ...parseAttributeTokens(tokens, stringLiteralPlaceholders)\n } as SelectorNodeDefinition;\n\n // This is a composite node, so we expect an opening '{'.\n popAndCheck(tokens, \"{\");\n\n // Return the selector node definition.\n return node;\n}\n\n/**\n * Creates a parallel node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The parallel node JSON definition.\n */\nfunction createParallelNode(\n tokens: string[],\n stringLiteralPlaceholders: StringLiteralPlaceholders\n): ParallelNodeDefinition {\n const node = {\n type: \"parallel\",\n ...parseAttributeTokens(tokens, stringLiteralPlaceholders)\n } as ParallelNodeDefinition;\n\n // This is a composite node, so we expect an opening '{'.\n popAndCheck(tokens, \"{\");\n\n // Return the parallel node definition.\n return node;\n}\n\n/**\n * Creates a lotto node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The lotto node JSON definition.\n */\nfunction createLottoNode(tokens: string[], stringLiteralPlaceholders: StringLiteralPlaceholders): LottoNodeDefinition {\n // If any node arguments have been defined then they must be our weights.\n const nodeArguments = parseArgumentTokens(tokens, stringLiteralPlaceholders);\n\n // All lotto node arguments MUST be of type number and must be integer.\n nodeArguments\n .filter((arg) => arg.type !== \"number\" || !arg.isInteger)\n .forEach(() => {\n throw new Error(`lotto node weight arguments must be integer values`);\n });\n\n const node = {\n type: \"lotto\",\n weights: nodeArguments.map(({ value }) => value),\n ...parseAttributeTokens(tokens, stringLiteralPlaceholders)\n } as LottoNodeDefinition;\n\n // This is a composite node, so we expect an opening '{'.\n popAndCheck(tokens, \"{\");\n\n // Return the lotto node definition.\n return node;\n}\n\n/**\n * Creates an action node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The action node JSON definition.\n */\nfunction createActionNode(\n tokens: string[],\n stringLiteralPlaceholders: StringLiteralPlaceholders\n): ActionNodeDefinition {\n // Parse any node arguments, we should have at least one which will be an identifier argument for the action name\n // and agent function to invoke for the action, all other arguments are to be passed as arguments to that function.\n const [actionNameIdentifier, ...agentFunctionArgs] = parseArgumentTokens(tokens, stringLiteralPlaceholders);\n\n // Our first argument MUST be defined and be an identifier as we require an action name argument.\n if (actionNameIdentifier?.type !== \"identifier\") {\n throw new Error(\"expected action name identifier argument\");\n }\n\n // Only the first argument should have been an identifier, all agent function arguments must be string, number, boolean or null.\n agentFunctionArgs\n .filter((arg) => arg.type === \"identifier\")\n .forEach((arg) => {\n throw new Error(\n `invalid action node argument value '${arg.value}', must be string, number, boolean or null`\n );\n });\n\n // Return the action node definition.\n return {\n type: \"action\",\n call: actionNameIdentifier.value,\n args: agentFunctionArgs.map(({ value }) => value),\n ...parseAttributeTokens(tokens, stringLiteralPlaceholders)\n };\n}\n\n/**\n * Creates a condition node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The condition node JSON definition.\n */\nfunction createConditionNode(\n tokens: string[],\n stringLiteralPlaceholders: StringLiteralPlaceholders\n): ConditionNodeDefinition {\n // Parse any node arguments, we should have at least one which will be an identifier argument for the condition name\n // and agent function to invoke for the condition, all other arguments are to be passed as arguments to that function.\n const [conditionNameIdentifier, ...agentFunctionArgs] = parseArgumentTokens(tokens, stringLiteralPlaceholders);\n\n // Our first argument MUST be defined and be an identifier as we require a condition name argument.\n if (conditionNameIdentifier?.type !== \"identifier\") {\n throw new Error(\"expected condition name identifier argument\");\n }\n\n // Only the first argument should have been an identifier, all agent function arguments must be string, number, boolean or null.\n agentFunctionArgs\n .filter((arg) => arg.type === \"identifier\")\n .forEach((arg) => {\n throw new Error(\n `invalid condition node argument value '${arg.value}', must be string, number, boolean or null`\n );\n });\n\n // Return the condition node definition.\n return {\n type: \"condition\",\n call: conditionNameIdentifier.value,\n args: agentFunctionArgs.map(({ value }) => value),\n ...parseAttributeTokens(tokens, stringLiteralPlaceholders)\n };\n}\n\n/**\n * Creates a wait node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The wait node JSON definition.\n */\nfunction createWaitNode(tokens: string[], stringLiteralPlaceholders: StringLiteralPlaceholders): WaitNodeDefinition {\n let node = { type: \"wait\" } as WaitNodeDefinition;\n\n // Get the node arguments.\n const nodeArguments = parseArgumentTokens(tokens, stringLiteralPlaceholders);\n\n // The arguments of a wait node are optional. We may have:\n // - No node arguments, in which case the wait will be indefinite until it is aborted.\n // - One node argument which will be the explicit duration of the wait.\n // - Two node arguments which define the min and max duration bounds from which a random duration will be picked.\n if (nodeArguments.length) {\n // All wait node arguments MUST be of type number and must be integer.\n nodeArguments\n .filter((arg) => arg.type !== \"number\" || !arg.isInteger)\n .forEach(() => {\n throw new Error(`wait node duration arguments must be integer values`);\n });\n\n // We may have:\n // - One node argument which will be the explicit duration of the wait.\n // - Two node arguments which define the min and max duration bounds from which a random duration will be picked.\n // - Too many arguments, which is not valid.\n if (nodeArguments.length === 1) {\n // An explicit duration was defined.\n node.duration = nodeArguments[0].value as number;\n } else if (nodeArguments.length === 2) {\n // Min and max duration bounds were defined from which a random duration will be picked.\n node.duration = [nodeArguments[0].value as number, nodeArguments[1].value as number];\n } else if (nodeArguments.length > 2) {\n // An incorrect number of duration arguments were defined.\n throw new Error(\"invalid number of wait node duration arguments defined\");\n }\n }\n\n // Return the wait node definition.\n return { ...node, ...parseAttributeTokens(tokens, stringLiteralPlaceholders) };\n}\n\n/**\n * Creates a branch node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The branch node JSON definition.\n */\nfunction createBranchNode(\n tokens: string[],\n stringLiteralPlaceholders: StringLiteralPlaceholders\n): BranchNodeDefinition {\n // Parse any node arguments, we should have one which will be an identifier argument for the root ref.\n const nodeArguments = parseArgumentTokens(tokens, stringLiteralPlaceholders);\n\n // We should have only a single identifer argument for a branch node, which is the root ref.\n if (nodeArguments.length !== 1 || nodeArguments[0].type !== \"identifier\") {\n throw new Error(\"expected single branch name argument\");\n }\n\n // Return the branch node definition.\n return { type: \"branch\", ref: nodeArguments[0].value };\n}\n", "import { RootNodeDefinition } from \"./BehaviourTreeDefinition\";\nimport { flattenDefinition, isBranchNode, isInteger } from \"./BehaviourTreeDefinitionUtilities\";\nimport { convertMDSLToJSON } from \"./mdsl/MDSLDefinitionParser\";\n\n/**\n * An object representing the result of validating a tree definition.\n */\nexport type DefinitionValidationResult = {\n /**\n * A flag defining whether validation succeeded.\n */\n succeeded: boolean;\n /**\n * A string containing the error message if validation did not succeed.\n */\n errorMessage?: string;\n};\n\n/**\n * Validates the specified behaviour tree definition in the form of JSON or MDSL, not taking any globally registered subtrees into consideration.\n * @param definition The behaviour tree definition in the form of JSON or MDSL.\n * @returns An object representing the result of validating the given tree definition.\n */\nexport function validateDefinition(definition: any): DefinitionValidationResult {\n // The definition must be defined.\n if (definition === null || typeof definition === \"undefined\") {\n return createValidationFailureResult(\"definition is null or undefined\");\n }\n\n // We are expecting a definition in one of three different forms:\n // - A string which we will assume is MDSL and we will parse this to JSON before validation.\n // - An array which we will assume is an array of root node definitions with at least one being the primary root node (no 'id' property)\n // - An object which we will assume is the primary root node and should not have an 'id' property.\n if (typeof definition === \"string\") {\n // The definition is a string which we can assume is MDSL, so attempt to validate it.\n return validateMDSLDefinition(definition);\n } else if (typeof definition === \"object\") {\n // The definition will either be an array (of root node definitions) or an object (the single primary root node definition).\n return validateJSONDefinition(definition);\n } else {\n return createValidationFailureResult(`unexpected definition type of '${typeof definition}'`);\n }\n}\n\n/**\n * Validates the specified behaviour tree definition in the form of MDSL.\n * @param definition The behaviour tree definition in the form of MDSL.\n * @returns An object representing the result of validating the given tree definition.\n */\nexport function validateMDSLDefinition(definition: string): DefinitionValidationResult {\n let rootNodeDefinitions;\n\n // The first thing the we need to do is to attempt to convert our MDSL into JSON.\n try {\n // The definition is a string which we can assume is MDSL, so attempt to parse it to a JSON definition in the form of an array of root node definitions.\n rootNodeDefinitions = convertMDSLToJSON(definition);\n } catch (error) {\n // We failed to parse the JSON from the MDSL, this is likely to be the result of it not being a valid MDSL string.\n return createValidationFailureResult(`invalid MDSL: ${error}`);\n }\n\n // Unpack all of the root node definitions into arrays of main ('id' defined) and sub ('id' not defined) root node definitions.\n const mainRootNodeDefinitions = rootNodeDefinitions.filter(({ id }) => typeof id === \"undefined\");\n const subRootNodeDefinitions = rootNodeDefinitions.filter(({ id }) => typeof id === \"string\" && id.length > 0);\n\n // We should ALWAYS have exactly one root node definition without an 'id' property defined, which is out main root node definition.\n if (mainRootNodeDefinitions.length !== 1) {\n return createValidationFailureResult(\n \"expected single unnamed root node at base of definition to act as main root\"\n );\n }\n\n // We should never have duplicate 'id' properties across our sub root node definitions.\n const subRootNodeIdenitifers: string[] = [];\n for (const { id } of subRootNodeDefinitions) {\n // Have we already come across this 'id' property value?\n if (subRootNodeIdenitifers.includes(id!)) {\n return createValidationFailureResult(`multiple root nodes found with duplicate name '${id}'`);\n }\n\n subRootNodeIdenitifers.push(id!);\n }\n\n try {\n // Validate our branch -> subtree links and check for any circular dependencies, we don't care about checking for broken subtree links here.\n validateBranchSubtreeLinks(rootNodeDefinitions, false);\n } catch (exception) {\n return createValidationFailureResult((exception as Error).message);\n }\n\n // Our definition was valid!\n return { succeeded: true };\n}\n\n/**\n * Validates the specified behaviour tree definition in the form of JSON.\n * @param definition The behaviour tree definition in the form of JSON.\n * @returns An object representing the result of validating the given tree definition.\n */\nexport function validateJSONDefinition(\n definition: RootNodeDefinition | RootNodeDefinition[]\n): DefinitionValidationResult {\n // The definition will either be an array (of root node definitions) or an object (the single primary root node definition).\n const rootNodeDefinitions = Array.isArray(definition) ? definition : [definition];\n\n // Iterate over our array of root nodes and call validateNode for each, passing an initial depth of 0, wrapped in a try catch to handle validation failures.\n try {\n rootNodeDefinitions.forEach((rootNodeDefinition) => validateNode(rootNodeDefinition, 0));\n } catch (error) {\n // Handle cases where we have caught a thrown Error and return a failure result with the error message.\n if (error instanceof Error) {\n return createValidationFailureResult(error.message);\n }\n\n // No idea what happened here!\n return createValidationFailureResult(`unexpected error: ${error}`);\n }\n\n // Unpack all of the root node definitions into arrays of main ('id' defined) and sub ('id' not defined) root node definitions.\n const mainRootNodeDefinitions = rootNodeDefinitions.filter(({ id }) => typeof id === \"undefined\");\n const subRootNodeDefinitions = rootNodeDefinitions.filter(({ id }) => typeof id === \"string\" && id.length > 0);\n\n // We should ALWAYS have exactly one root node definition without an 'id' property defined, which is out main root node definition.\n if (mainRootNodeDefinitions.length !== 1) {\n return createValidationFailureResult(\n \"expected single root node without 'id' property defined to act as main root\"\n );\n }\n\n // We should never have duplicate 'id' properties across our sub root node definitions.\n const subRootNodeIdenitifers: string[] = [];\n for (const { id } of subRootNodeDefinitions) {\n // Have we already come across this 'id' property value?\n if (subRootNodeIdenitifers.includes(id!)) {\n return createValidationFailureResult(\n `multiple root nodes found with duplicate 'id' property value of '${id}'`\n );\n }\n\n subRootNodeIdenitifers.push(id!);\n }\n\n try {\n // Validate our branch -> subtree links and check for any circular dependencies, we don't care about checking for broken subtree links here.\n validateBranchSubtreeLinks(rootNodeDefinitions, false);\n } catch (exception) {\n return createValidationFailureResult((exception as Error).message);\n }\n\n // Our definition was valid!\n return { succeeded: true };\n}\n\n/**\n * Validates the branch -> subtree links across all provided root node definitions.\n * This will not consider branch nodes that reference any globally registered subtrees unless includesGlobalSubtrees\n * is set to true, in which case we will also verify that there are no broken branch -> subtree links.\n * @param rootNodeDefinitions The array of root node definitions.\n * @param includesGlobalSubtrees A flag defining whether the array includes all global subtree root node definitions.\n */\nexport function validateBranchSubtreeLinks(rootNodeDefinitions: RootNodeDefinition[], includesGlobalSubtrees: boolean) {\n // Create a mapping of root node identifiers to other root nodes that they reference via branch nodes.\n // Below is an example of a mapping that includes a circular dependency (root => a => b => c => a)\n // [{ refs: [\"a\", \"b\"] }, { id: \"a\", refs: [\"b\"] }, { id: \"b\", refs: [\"c\"] }, { id: \"c\", refs: [\"a\"] }]\n const rootNodeMappings: { id: string | undefined; refs: string[] }[] = rootNodeDefinitions.map(\n (rootNodeDefinition) => ({\n id: rootNodeDefinition.id,\n refs: flattenDefinition(rootNodeDefinition)\n .filter(isBranchNode)\n .map(({ ref }) => ref)\n })\n );\n\n // A recursive function to walk through the mappings, keeping track of which root nodes we have visited in the form of a path of root node identifiers.\n const followRefs = (mapping: { id: string | undefined; refs: string[] }, path: (string | undefined)[] = []) => {\n // Have we found a circular dependency?\n if (path.includes(mapping.id)) {\n // We found a circular dependency! Get the bad path of root node identifiers.\n const badPath = [...path, mapping.id];\n\n // Create the formatted path value. [undefined, \"a\", \"b\", \"c\", \"a\"] would be formatted as \"a -> b -> c -> a\".\n const badPathFormatted = badPath.filter((element) => !!element).join(\" => \");\n\n // No need to continue, we found a circular dependency.\n throw new Error(`circular dependency found in branch node references: ${badPathFormatted}`);\n }\n\n for (const ref of mapping.refs) {\n // Find the mapping for the root node with an identifer matching the current ref.\n const subMapping = rootNodeMappings.find(({ id }) => id === ref);\n\n // We may not have a mapping for this ref, which is normal when we aren't considering all globally registered subtrees.\n if (subMapping) {\n followRefs(subMapping, [...path, mapping.id]);\n } else if (includesGlobalSubtrees) {\n // We found a reference to a root node that doesn't exist, which is a problem seeing as the root node definitons includes all globally registered subtrees.\n throw new Error(\n mapping.id\n ? `subtree '${mapping.id}' has branch node that references root node '${ref}' which has not been defined`\n : `primary tree has branch node that references root node '${ref}' which has not been defined`\n );\n }\n }\n };\n\n // Start looking for circular dependencies and broken references from the primary root node definition.\n followRefs(rootNodeMappings.find((mapping) => typeof mapping.id === \"undefined\")!);\n}\n\n/**\n * Validate an object that we expect to be a node definition.\n * @param definition An object that we expect to be a node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateNode(definition: any, depth: number): void {\n // Every node must be valid object and have a non-empty 'type' string property.\n if (typeof definition !== \"object\" || typeof definition.type !== \"string\" || definition.type.length === 0) {\n throw new Error(\n `node definition is not an object or 'type' property is not a non-empty string at depth '${depth}'`\n );\n }\n\n // How we validate this node definition will depend on its type.\n switch (definition.type) {\n case \"action\":\n validateActionNode(definition, depth);\n break;\n\n case \"condition\":\n validateConditionNode(definition, depth);\n break;\n\n case \"wait\":\n validateWaitNode(definition, depth);\n break;\n\n case \"branch\":\n validateBranchNode(definition, depth);\n break;\n\n case \"root\":\n validateRootNode(definition, depth);\n break;\n\n case \"success\":\n validateSuccessNode(definition, depth);\n break;\n\n case \"fail\":\n validateFailNode(definition, depth);\n break;\n\n case \"flip\":\n validateFlipNode(definition, depth);\n break;\n\n case \"repeat\":\n validateRepeatNode(definition, depth);\n break;\n\n case \"retry\":\n validateRetryNode(definition, depth);\n break;\n\n case \"sequence\":\n validateSequenceNode(definition, depth);\n break;\n\n case \"selector\":\n validateSelectorNode(definition, depth);\n break;\n\n case \"parallel\":\n validateParallelNode(definition, depth);\n break;\n\n default:\n throw new Error(`unexpected node type of '${definition.type}' at depth '${depth}'`);\n }\n}\n\n/**\n * Validate any attributes for a given node definition.\n * @param definition The node definition.\n * @param depth The depth of the node in the behaviour tree definition.\n */\nfunction validateNodeAttributes(definition: any, depth: number): void {\n // Validate each of the attribute types for this node.\n [\"while\", \"until\", \"entry\", \"exit\", \"step\"].forEach((attributeName) => {\n // Attempt to grab the definition for the current attribute from the node definition.\n const attributeDefinition = definition[attributeName];\n\n // All node attributes are optional, so there is nothing to do if the current attribute is not defined.\n if (typeof attributeDefinition === \"undefined\") {\n return;\n }\n\n // The attribute definition must be an object.\n if (typeof attributeDefinition !== \"object\") {\n throw new Error(\n `expected attribute '${attributeName}' to be an object for '${definition.type}' node at depth '${depth}'`\n );\n }\n\n // The 'call' property must be defined for any attribute definition.\n if (typeof attributeDefinition.call !== \"string\" || attributeDefinition.call.length === 0) {\n throw new Error(\n `expected 'call' property for attribute '${attributeName}' to be a non-empty string for '${definition.type}' node at depth '${depth}'`\n );\n }\n\n // If any node attribute arguments have been defined then they must have been defined in an array.\n if (typeof attributeDefinition.args !== \"undefined\" && !Array.isArray(attributeDefinition.args)) {\n throw new Error(\n `expected 'args' property for attribute '${attributeName}' to be an array for '${definition.type}' node at depth '${depth}'`\n );\n }\n });\n}\n\n/**\n * Validate an object that we expect to be a root node definition.\n * @param definition An object that we expect to be a root node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateRootNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"root\") {\n throw new Error(\"expected node type of 'root' for root node\");\n }\n\n // A root node cannot be the child of another node.\n if (depth > 0) {\n throw new Error(\"a root node cannot be the child of another node\");\n }\n\n // Check that, if the root node 'id' property is defined, it is a non-empty string.\n if (typeof definition.id !== \"undefined\" && (typeof definition.id !== \"string\" || definition.id.length === 0)) {\n throw new Error(\"expected non-empty string for 'id' property if defined for root node\");\n }\n\n // A root node is a decorator node, so must have a child node defined.\n if (typeof definition.child === \"undefined\") {\n throw new Error(\"expected property 'child' to be defined for root node\");\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n\n // Validate the child node of this decorator node.\n validateNode(definition.child, depth + 1);\n}\n\n/**\n * Validate an object that we expect to be a success node definition.\n * @param definition An object that we expect to be a success node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateSuccessNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"success\") {\n throw new Error(`expected node type of 'success' for success node at depth '${depth}'`);\n }\n\n // A success node is a decorator node, so must have a child node defined.\n if (typeof definition.child === \"undefined\") {\n throw new Error(`expected property 'child' to be defined for success node at depth '${depth}'`);\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n\n // Validate the child node of this decorator node.\n validateNode(definition.child, depth + 1);\n}\n\n/**\n * Validate an object that we expect to be a fail node definition.\n * @param definition An object that we expect to be a fail node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateFailNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"fail\") {\n throw new Error(`expected node type of 'fail' for fail node at depth '${depth}'`);\n }\n\n // A fail node is a decorator node, so must have a child node defined.\n if (typeof definition.child === \"undefined\") {\n throw new Error(`expected property 'child' to be defined for fail node at depth '${depth}'`);\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n\n // Validate the child node of this decorator node.\n validateNode(definition.child, depth + 1);\n}\n\n/**\n * Validate an object that we expect to be a flip node definition.\n * @param definition An object that we expect to be a flip node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateFlipNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"flip\") {\n throw new Error(`expected node type of 'flip' for flip node at depth '${depth}'`);\n }\n\n // A flip node is a decorator node, so must have a child node defined.\n if (typeof definition.child === \"undefined\") {\n throw new Error(`expected property 'child' to be defined for flip node at depth '${depth}'`);\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n\n // Validate the child node of this decorator node.\n validateNode(definition.child, depth + 1);\n}\n\n/**\n * Validate an object that we expect to be a repeat node definition.\n * @param definition An object that we expect to be a repeat node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateRepeatNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"repeat\") {\n throw new Error(`expected node type of 'repeat' for repeat node at depth '${depth}'`);\n }\n\n // A repeat node is a decorator node, so must have a child node defined.\n if (typeof definition.child === \"undefined\") {\n throw new Error(`expected property 'child' to be defined for repeat node at depth '${depth}'`);\n }\n\n // Check whether an 'iterations' property has been defined, it may not have been if this node is to repeat indefinitely.\n if (typeof definition.iterations !== \"undefined\") {\n if (Array.isArray(definition.iterations)) {\n // Check whether any elements of the array are not integer values.\n const containsNonInteger = !!definition.iterations.find((value: unknown) => !isInteger(value));\n\n // If the 'iterations' property is an array then it MUST contain two integer values.\n if (definition.iterations.length !== 2 || containsNonInteger) {\n throw new Error(\n `expected array containing two integer values for 'iterations' property if defined for repeat node at depth '${depth}'`\n );\n }\n } else if (!isInteger(definition.iterations)) {\n throw new Error(\n `expected integer value or array containing two integer values for 'iterations' property if defined for repeat node at depth '${depth}'`\n );\n }\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n\n // Validate the child node of this decorator node.\n validateNode(definition.child, depth + 1);\n}\n\n/**\n * Validate an object that we expect to be a retry node definition.\n * @param definition An object that we expect to be a retry node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateRetryNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"retry\") {\n throw new Error(`expected node type of 'retry' for retry node at depth '${depth}'`);\n }\n\n // A retry node is a decorator node, so must have a child node defined.\n if (typeof definition.child === \"undefined\") {\n throw new Error(`expected property 'child' to be defined for retry node at depth '${depth}'`);\n }\n\n // Check whether an 'attempts' property has been defined, it may not have been if this node is to retry indefinitely.\n if (typeof definition.attempts !== \"undefined\") {\n if (Array.isArray(definition.attempts)) {\n // Check whether any elements of the array are not integer values.\n const containsNonInteger = !!definition.attempts.find((value: unknown) => !isInteger(value));\n\n // If the 'attempts' property is an array then it MUST contain two integer values.\n if (definition.attempts.length !== 2 || containsNonInteger) {\n throw new Error(\n `expected array containing two integer values for 'attempts' property if defined for retry node at depth '${depth}'`\n );\n }\n } else if (!isInteger(definition.attempts)) {\n throw new Error(\n `expected integer value or array containing two integer values for 'attempts' property if defined for retry node at depth '${depth}'`\n );\n }\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n\n // Validate the child node of this decorator node.\n validateNode(definition.child, depth + 1);\n}\n\n/**\n * Validate an object that we expect to be a branch node definition.\n * @param definition An object that we expect to be a branch node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateBranchNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"branch\") {\n throw new Error(`expected node type of 'branch' for branch node at depth '${depth}'`);\n }\n\n // Check that the branch node 'ref' property is defined and is a non-empty string.\n if (typeof definition.ref !== \"string\" || definition.ref.length === 0) {\n throw new Error(`expected non-empty string for 'ref' property for branch node at depth '${depth}'`);\n }\n\n // It is invalid to define guard attributes for a branch node as they should be defined on the referenced root node.\n [\"while\", \"until\"].forEach((attributeName) => {\n if (typeof definition[attributeName] !== \"undefined\") {\n throw new Error(\n `guards should not be defined for branch nodes but guard '${attributeName}' was defined for branch node at depth '${depth}'`\n );\n }\n });\n\n // It is invalid to define callback attributes for a branch node as they should be defined on the referenced root node.\n [\"entry\", \"exit\", \"step\"].forEach((attributeName) => {\n if (typeof definition[attributeName] !== \"undefined\") {\n throw new Error(\n `callbacks should not be defined for branch nodes but callback '${attributeName}' was defined for branch node at depth '${depth}'`\n );\n }\n });\n}\n\n/**\n * Validate an object that we expect to be a action node definition.\n * @param definition An object that we expect to be a action node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateActionNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"action\") {\n throw new Error(`expected node type of 'action' for action node at depth '${depth}'`);\n }\n\n // The 'call' property must be defined for a action node definition.\n if (typeof definition.call !== \"string\" || definition.call.length === 0) {\n throw new Error(`expected non-empty string for 'call' property of action node at depth '${depth}'`);\n }\n\n // If any action function arguments have been defined then they must have been defined in an array.\n if (typeof definition.args !== \"undefined\" && !Array.isArray(definition.args)) {\n throw new Error(`expected array for 'args' property if defined for action node at depth '${depth}'`);\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n}\n\n/**\n * Validate an object that we expect to be a condition node definition.\n * @param definition An object that we expect to be a condition node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateConditionNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"condition\") {\n throw new Error(`expected node type of 'condition' for condition node at depth '${depth}'`);\n }\n\n // The 'call' property must be defined for a condition node definition.\n if (typeof definition.call !== \"string\" || definition.call.length === 0) {\n throw new Error(`expected non-empty string for 'call' property of condition node at depth '${depth}'`);\n }\n\n // If any condition function arguments have been defined then they must have been defined in an array.\n if (typeof definition.args !== \"undefined\" && !Array.isArray(definition.args)) {\n throw new Error(`expected array for 'args' property if defined for condition node at depth '${depth}'`);\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n}\n\n/**\n * Validate an object that we expect to be a wait node definition.\n * @param definition An object that we expect to be a wait node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateWaitNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"wait\") {\n throw new Error(`expected node type of 'wait' for wait node at depth '${depth}'`);\n }\n\n // Check whether a 'duration' property has been defined, it may not have been if this node is to wait indefinitely.\n if (typeof definition.duration !== \"undefined\") {\n if (Array.isArray(definition.duration)) {\n // Check whether any elements of the array are not integer values.\n const containsNonInteger = !!definition.duration.find((value: unknown) => !isInteger(value));\n\n // If the 'duration' property is an array then it MUST contain two integer values.\n if (definition.duration.length !== 2 || containsNonInteger) {\n throw new Error(\n `expected array containing two integer values for 'duration' property if defined for wait node at depth '${depth}'`\n );\n }\n } else if (!isInteger(definition.duration)) {\n throw new Error(\n `expected integer value or array containing two integer values for 'duration' property if defined for wait node at depth '${depth}'`\n );\n }\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n}\n\n/**\n * Validate an object that we expect to be a sequence node definition.\n * @param definition An object that we expect to be a sequence node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateSequenceNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"sequence\") {\n throw new Error(`expected node type of 'sequence' for sequence node at depth '${depth}'`);\n }\n\n // A sequence node is a composite node, so must have a children nodes array defined.\n if (!Array.isArray(definition.children) || definition.children.length === 0) {\n throw new Error(`expected non-empty 'children' array to be defined for sequence node at depth '${depth}'`);\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n\n // Validate the child nodes of this composite node.\n definition.children.forEach((child: any) => validateNode(child, depth + 1));\n}\n\n/**\n * Validate an object that we expect to be a selector node definition.\n * @param definition An object that we expect to be a selector node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateSelectorNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"selector\") {\n throw new Error(`expected node type of 'selector' for selector node at depth '${depth}'`);\n }\n\n // A selector node is a composite node, so must have a children nodes array defined.\n if (!Array.isArray(definition.children) || definition.children.length === 0) {\n throw new Error(`expected non-empty 'children' array to be defined for selector node at depth '${depth}'`);\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n\n // Validate the child nodes of this composite node.\n definition.children.forEach((child: any) => validateNode(child, depth + 1));\n}\n\n/**\n * Validate an object that we expect to be a parallel node definition.\n * @param definition An object that we expect to be a parallel node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateParallelNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"parallel\") {\n throw new Error(`expected node type of 'parallel' for parallel node at depth '${depth}'`);\n }\n\n // A parallel node is a composite node, so must have a children nodes array defined.\n if (!Array.isArray(definition.children) || definition.children.length === 0) {\n throw new Error(`expected non-empty 'children' array to be defined for parallel node at depth '${depth}'`);\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n\n // Validate the child nodes of this composite node.\n definition.children.forEach((child: any) => validateNode(child, depth + 1));\n}\n\n/**\n * A helper function to create a failure validation result with the given error message.\n * @param errorMessage The validation failure error message.\n * @returns A failure validation result with the given error message.\n */\nfunction createValidationFailureResult(errorMessage: string): DefinitionValidationResult {\n return { succeeded: false, errorMessage };\n}\n", "import { ActionResult, Agent, GlobalFunction } from \"./Agent\";\nimport { RootNodeDefinition } from \"./BehaviourTreeDefinition\";\n\nexport type InvokerFunction = (args: any[]) => ActionResult;\n\n/**\n * A singleton used to store and lookup registered functions and subtrees.\n */\nexport default class Lookup {\n /**\n * The object holding any registered functions keyed on function name.\n */\n private static functionTable: { [key: string]: GlobalFunction } = {};\n /**\n * The object holding any registered subtree root node definitions keyed on tree name.\n */\n private static subtreeTable: { [key: string]: RootNodeDefinition } = {};\n\n /**\n * Gets the function with the specified name.\n * @param name The name of the function.\n * @returns The function with the specified name.\n */\n public static getFunc(name: string): GlobalFunction {\n return this.functionTable[name];\n }\n\n /**\n * Sets the function with the specified name for later lookup.\n * @param name The name of the function.\n * @param func The function.\n */\n public static setFunc(name: string, func: GlobalFunction): void {\n this.functionTable[name] = func;\n }\n\n /**\n * Gets the function invoker for the specified agent and function name.\n * If a function with the specified name exists on the agent object then it will\n * be returned, otherwise we will then check the registered functions for a match.\n * @param agent The agent instance that this behaviour tree is modelling behaviour for.\n * @param name The function name.\n * @returns The function invoker for the specified agent and function name.\n */\n static getFuncInvoker(agent: Agent, name: string): InvokerFunction | null {\n // Check whether the agent contains the specified function.\n const foundOnAgent = agent[name];\n if (foundOnAgent && typeof foundOnAgent === \"function\") {\n return (args: any[]): boolean | ActionResult => foundOnAgent.apply(agent, args);\n }\n\n // The agent does not contain the specified function but it may have been registered at some point.\n if (this.functionTable[name] && typeof this.functionTable[name] === \"function\") {\n return (args: any[]) => this.functionTable[name](agent, ...args.map((arg) => arg.value));\n }\n\n // We have no function to invoke.\n return null;\n }\n\n /**\n * Gets all registered subtree root node definitions.\n */\n static getSubtrees(): { [key: string]: RootNodeDefinition } {\n return this.subtreeTable;\n }\n\n /**\n * Sets the subtree with the specified name for later lookup.\n * @param name The name of the subtree.\n * @param subtree The subtree.\n */\n static setSubtree(name: string, subtree: RootNodeDefinition) {\n this.subtreeTable[name] = subtree;\n }\n\n /**\n * Removes the registered function or subtree with the specified name.\n * @param name The name of the registered function or subtree.\n */\n static remove(name: string) {\n delete this.functionTable[name];\n delete this.subtreeTable[name];\n }\n\n /**\n * Remove all registered functions and subtrees.\n */\n static empty() {\n this.functionTable = {};\n this.subtreeTable = {};\n }\n}\n", "import Node from \"../../nodes/Node\";\n\n/**\n * An exception thrown when evaluating node guard path conditions and a conditions fails.\n */\nexport default class GuardUnsatisifedException extends Error {\n /**\n * @param source The node at which a guard condition failed.\n */\n constructor(private source: Node) {\n super(\"A guard path condition has failed\");\n }\n\n /**\n * Gets whether the specified node is the node at which a guard condition failed.\n * @param node The node to check against the source node.\n * @returns Whether the specified node is the node at which a guard condition failed.\n */\n isSourceNode = (node: Node) => node === this.source;\n}\n", "import { Agent } from \"../../Agent\";\nimport Guard from \"./Guard\";\nimport Node from \"../../nodes/Node\";\nimport GuardUnsatisifedException from \"./GuardUnsatisifedException\";\n\nexport type GuardPathPart = {\n node: Node;\n guards: Guard[];\n};\n\n/**\n * Represents a path of node guards along a root-to-leaf tree path.\n */\nexport default class GuardPath {\n /**\n * @param nodes An array of objects defining a node instance -> guard link, ordered by node depth.\n */\n constructor(private nodes: GuardPathPart[]) {}\n\n /**\n * Evaluate guard conditions for all guards in the tree path, moving outwards from the root.\n * @param agent The agent, required for guard evaluation.\n * @returns An evaluation results object.\n */\n evaluate = (agent: Agent) => {\n // We need to evaluate guard conditions for nodes up the tree, moving outwards from the root.\n for (const details of this.nodes) {\n // There can be multiple guards per node.\n for (const guard of details.guards) {\n // Check whether the guard condition passes, and throw an exception if not.\n if (!guard.isSatisfied(agent)) {\n throw new GuardUnsatisifedException(details.node);\n }\n }\n }\n };\n}\n", "import { BehaviourTreeOptions } from \"../BehaviourTreeOptions\";\nimport State, { AnyState } from \"../State\";\nimport { Agent } from \"../Agent\";\nimport Leaf from \"./leaf/Leaf\";\nimport Attribute from \"../attributes/Attribute\";\nimport Entry from \"../attributes/callbacks/Entry\";\nimport Exit from \"../attributes/callbacks/Exit\";\nimport Step from \"../attributes/callbacks/Step\";\nimport Guard from \"../attributes/guards/Guard\";\nimport GuardPath from \"../attributes/guards/GuardPath\";\nimport GuardUnsatisifedException from \"../attributes/guards/GuardUnsatisifedException\";\n\n/**\n * A base node.\n */\nexport default abstract class Node {\n /**\n * The node uid.\n */\n private readonly uid: string = createNodeUid();\n /**\n * The node state.\n */\n private state: AnyState = State.READY;\n /**\n * The guard path to evaluate as part of a node update.\n */\n private guardPath: GuardPath | undefined;\n\n /**\n * @param type The node type.\n * @param attributes The node attributes.\n * @param args The node argument definitions.\n */\n constructor(private type: string, private attributes: Attribute[], private args: any[]) {}\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected abstract onUpdate(agent: Agent, options: BehaviourTreeOptions): void;\n\n /**\n * Gets the name of the node.\n */\n public abstract getName(): string;\n\n /**\n * Gets whether this node is a leaf node.\n */\n public abstract isLeafNode: () => this is Leaf;\n\n /**\n * Gets/Sets the state of the node.\n */\n getState = (): AnyState => this.state;\n setState = (value: AnyState): void => {\n this.state = value;\n };\n\n /**\n * Gets the unique id of the node.\n */\n getUid = () => this.uid;\n\n /**\n * Gets the type of the node.\n */\n getType = () => this.type;\n\n /**\n * Gets the node attributes.\n */\n getAttributes = () => this.attributes;\n\n /**\n * Gets the node arguments.\n */\n getArguments = () => this.args;\n\n /**\n * Gets the node attribute with the specified type, or null if it does not exist.\n */\n getAttribute(type: \"entry\" | \"ENTRY\"): Entry;\n getAttribute(type: \"exit\" | \"EXIT\"): Exit;\n getAttribute(type: \"step\" | \"STEP\"): Step;\n getAttribute(type: string): Attribute {\n return (\n this.getAttributes().filter((decorator) => decorator.type.toUpperCase() === type.toUpperCase())[0] || null\n );\n }\n\n /**\n * Gets the node attributes.\n */\n getGuardAttributes = (): Guard[] => this.getAttributes().filter((decorator) => decorator.isGuard()) as Guard[];\n\n /**\n * Sets the guard path to evaluate as part of a node update.\n */\n setGuardPath = (value: GuardPath) => (this.guardPath = value);\n\n /**\n * Gets whether a guard path is assigned to this node.\n */\n hasGuardPath = () => !!this.guardPath;\n\n /**\n * Gets whether this node is in the specified state.\n * @param value The value to compare to the node state.\n */\n public is(value: AnyState): boolean {\n return this.state === value;\n }\n\n /**\n * Reset the state of the node.\n */\n public reset(): void {\n this.setState(State.READY);\n }\n\n /**\n * Abort the running of this node.\n * @param agent The agent.\n */\n public abort(agent: Agent): void {\n // There is nothing to do if this node is not in the running state.\n if (!this.is(State.RUNNING)) {\n return;\n }\n\n // Reset the state of this node.\n this.reset();\n\n this.getAttribute(\"exit\")?.callAgentFunction(agent, false, true);\n }\n\n /**\n * Update the node.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n * @returns The result of the update.\n */\n public update(agent: Agent, options: BehaviourTreeOptions): void {\n // If this node is already in a 'SUCCEEDED' or 'FAILED' state then there is nothing to do.\n if (this.is(State.SUCCEEDED) || this.is(State.FAILED)) {\n return;\n }\n\n try {\n // Evaluate all of the guard path conditions for the current tree path.\n this.guardPath!.evaluate(agent);\n\n // If this node is in the READY state then call the ENTRY for this node if it exists.\n if (this.is(State.READY)) {\n this.getAttribute(\"entry\")?.callAgentFunction(agent);\n }\n\n this.getAttribute(\"step\")?.callAgentFunction(agent);\n\n // Do the actual update.\n this.onUpdate(agent, options);\n\n // If this node is now in a 'SUCCEEDED' or 'FAILED' state then call the EXIT for this node if it exists.\n if (this.is(State.SUCCEEDED) || this.is(State.FAILED)) {\n this.getAttribute(\"exit\")?.callAgentFunction(agent, this.is(State.SUCCEEDED), false);\n }\n } catch (error) {\n // If the error is a GuardUnsatisfiedException then we need to determine if this node is the source.\n if (error instanceof GuardUnsatisifedException && error.isSourceNode(this)) {\n // Abort the current node.\n this.abort(agent);\n\n // Any node that is the source of an abort will be a failed node.\n this.setState(State.FAILED);\n } else {\n throw error;\n }\n }\n }\n}\n\n/**\n * Create a randomly generated node uid.\n * @returns A randomly generated node uid.\n */\nfunction createNodeUid(): string {\n var S4 = function () {\n return (((1 + Math.random()) * 0x10000) | 0).toString(16).substring(1);\n };\n return S4() + S4() + \"-\" + S4() + \"-\" + S4() + \"-\" + S4() + \"-\" + S4() + S4() + S4();\n}\n", "import Node from \"../Node\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\n\n/**\n * A decorator node that wraps a single child node.\n */\nexport default abstract class Decorator extends Node {\n /**\n * @param type The node type.\n * @param attributes The node attributes.\n * @param child The child node.\n */\n constructor(type: string, attributes: Attribute[], protected child: Node) {\n super(type, attributes, []);\n }\n\n /**\n * Gets whether this node is a leaf node.\n */\n isLeafNode = () => false;\n\n /**\n * Gets the children of this node.\n */\n getChildren = () => [this.child];\n\n /**\n * Reset the state of the node.\n */\n reset = () => {\n // Reset the state of this node.\n this.setState(State.READY);\n\n // Reset the state of the child node.\n this.child.reset();\n };\n\n /**\n * Abort the running of this node.\n * @param agent The agent.\n */\n abort = (agent: Agent) => {\n // There is nothing to do if this node is not in the running state.\n if (!this.is(State.RUNNING)) {\n return;\n }\n\n // Abort the child node.\n this.child.abort(agent);\n\n // Reset the state of this node.\n this.reset();\n\n this.getAttribute(\"exit\")?.callAgentFunction(agent, false, true);\n };\n}\n", "import Node from \"../Node\";\nimport Decorator from \"./Decorator\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A Root node.\n * The root node will have a single child.\n */\nexport default class Root extends Decorator {\n /**\n * @param attributes The node attributes.\n * @param child The child node.\n */\n constructor(attributes: Attribute[], child: Node) {\n super(\"root\", attributes, child);\n }\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // If the child has never been updated or is running then we will need to update it now.\n if (this.child.getState() === State.READY || this.child.getState() === State.RUNNING) {\n // Update the child of this node.\n this.child.update(agent, options);\n }\n\n // The state of the root node is the state of its child.\n this.setState(this.child.getState());\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => \"ROOT\";\n}\n", "import Guard from \"./guards/Guard\";\n\nexport type AttributeDetails = {\n /** The attribute type. */\n type: string;\n\n /** The attribute arguments. */\n args: any[];\n};\n\n/**\n * A base node attribute.\n */\nexport default abstract class Attribute {\n /**\n * @param type The node attribute type.\n * @param args The array of attribute arguments.\n */\n constructor(public type: string, public args: any[]) {}\n\n /**\n * Gets the attribute details.\n */\n abstract getDetails(): TAttributeDetails;\n\n /**\n * Gets whether this attribute is a guard.\n */\n abstract isGuard: () => this is Guard;\n}\n", "import { Agent } from \"../../Agent\";\nimport Attribute, { AttributeDetails } from \"../Attribute\";\n\nexport type GuardAttributeDetails = {\n /** The name of the condition function that determines whether the guard is satisfied. */\n condition: string;\n} & AttributeDetails;\n\n/**\n * A base node guard attribute.\n */\nexport default abstract class Guard extends Attribute {\n /**\n * @param type The node attribute type.\n * @param args The array of decorator argument definitions.\n * @param condition The name of the condition function that determines whether the guard is satisfied.\n */\n constructor(type: string, args: any[], private condition: string) {\n super(type, args);\n }\n\n /**\n * Gets the name of the condition function that determines whether the guard is satisfied.\n */\n getCondition = () => this.condition;\n\n /**\n * Gets whether this attribute is a guard.\n */\n isGuard = () => true;\n\n /**\n * Gets the attribute details.\n */\n getDetails(): GuardAttributeDetails {\n return {\n type: this.type,\n args: this.args,\n condition: this.getCondition()\n };\n }\n\n /**\n * Gets whether the guard is satisfied.\n * @param agent The agent.\n * @returns Whether the guard is satisfied.\n */\n abstract isSatisfied(agent: Agent): boolean;\n}\n", "import Guard from \"./Guard\";\nimport Lookup from \"../../Lookup\";\nimport { Agent } from \"../../Agent\";\n\n/**\n * A WHILE guard which is satisfied as long as the given condition remains true.\n */\nexport default class While extends Guard {\n /**\n * @param condition The name of the condition function that determines whether the guard is satisfied.\n * @param args The array of decorator argument definitions.\n */\n constructor(condition: string, args: any[]) {\n super(\"while\", args, condition);\n }\n\n /**\n * Gets whether the guard is satisfied.\n * @param agent The agent.\n * @returns Whether the guard is satisfied.\n */\n isSatisfied = (agent: Agent) => {\n // Attempt to get the invoker for the condition function.\n const conditionFuncInvoker = Lookup.getFuncInvoker(agent, this.getCondition());\n\n // The condition function should be defined.\n if (conditionFuncInvoker === null) {\n throw new Error(\n `cannot evaluate node guard as the condition '${this.getCondition()}' function is not defined on the agent and has not been registered`\n );\n }\n\n // Call the condition function to determine whether this guard is satisfied.\n return !!conditionFuncInvoker(this.args);\n };\n}\n", "import Guard from \"./Guard\";\nimport Lookup from \"../../Lookup\";\nimport { Agent } from \"../../Agent\";\n\n/**\n * An UNTIL guard which is satisfied as long as the given condition remains false.\n */\nexport default class Until extends Guard {\n /**\n * @param condition The name of the condition function that determines whether the guard is satisfied.\n * @param args The array of decorator argument definitions.\n */\n constructor(condition: string, args: any[]) {\n super(\"until\", args, condition);\n }\n\n /**\n * Gets whether the guard is satisfied.\n * @param agent The agent.\n * @returns Whether the guard is satisfied.\n */\n isSatisfied = (agent: Agent) => {\n // Attempt to get the invoker for the condition function.\n const conditionFuncInvoker = Lookup.getFuncInvoker(agent, this.getCondition());\n\n // The condition function should be defined.\n if (conditionFuncInvoker === null) {\n throw new Error(\n `cannot evaluate node guard as the condition '${this.getCondition()}' function is not defined on the agent and has not been registered`\n );\n }\n\n // Call the condition function to determine whether this guard is satisfied.\n return !!!conditionFuncInvoker(this.args);\n };\n}\n", "import { Agent } from \"../../Agent\";\nimport Attribute, { AttributeDetails } from \"../Attribute\";\n\nexport type CallbackAttributeDetails = {\n /** The name of the agent function that is called. */\n functionName: string;\n} & AttributeDetails;\n\n/**\n * A base node callback attribute.\n */\nexport default abstract class Callback extends Attribute {\n /**\n * @param type The node attribute type.\n * @param args The array of decorator argument definitions.\n * @param functionName The name of the agent function to call.\n */\n constructor(type: string, args: any[], private functionName: string) {\n super(type, args);\n }\n\n /**\n * Gets the name of the agent function to call.\n */\n getFunctionName = () => this.functionName;\n\n /**\n * Gets whether this attribute is a guard.\n */\n isGuard = () => false;\n\n /**\n * Gets the attribute details.\n */\n getDetails(): CallbackAttributeDetails {\n return {\n type: this.type,\n args: this.args,\n functionName: this.getFunctionName()\n };\n }\n\n /**\n * Attempt to call the agent function that this callback refers to.\n * @param agent The agent.\n */\n abstract callAgentFunction: (agent: Agent, isSuccess: boolean, isAborted: boolean) => void;\n}\n", "import Callback from \"./Callback\";\nimport Lookup from \"../../Lookup\";\nimport { Agent } from \"../../Agent\";\n\n/**\n * An ENTRY callback which defines an agent function to call when the associated node is updated and moves out of running state.\n */\nexport default class Entry extends Callback {\n /**\n * @param functionName The name of the agent function to call.\n * @param args The array of callback argument definitions.\n */\n constructor(functionName: string, args: any[]) {\n super(\"entry\", args, functionName);\n }\n\n /**\n * Attempt to call the agent function that this callback refers to.\n * @param agent The agent.\n */\n callAgentFunction = (agent: Agent) => {\n // Attempt to get the invoker for the callback function.\n const callbackFuncInvoker = Lookup.getFuncInvoker(agent, this.getFunctionName());\n\n // The callback function should be defined.\n if (callbackFuncInvoker === null) {\n throw new Error(\n `cannot call entry function '${this.getFunctionName()}' as is not defined on the agent and has not been registered`\n );\n }\n\n // Call the callback function.\n callbackFuncInvoker(this.args);\n };\n}\n", "import Callback from \"./Callback\";\nimport Lookup from \"../../Lookup\";\nimport { Agent } from \"../../Agent\";\n\n/**\n * A STEP callback which defines an agent function to call when the associated node is updated.\n */\nexport default class Step extends Callback {\n /**\n * @param functionName The name of the agent function to call.\n * @param args The array of callback argument definitions.\n */\n constructor(functionName: string, args: any[]) {\n super(\"step\", args, functionName);\n }\n\n /**\n * Attempt to call the agent function that this callback refers to.\n * @param agent The agent.\n */\n callAgentFunction = (agent: Agent) => {\n // Attempt to get the invoker for the callback function.\n const callbackFuncInvoker = Lookup.getFuncInvoker(agent, this.getFunctionName());\n\n // The callback function should be defined.\n if (callbackFuncInvoker === null) {\n throw new Error(\n `cannot call step function '${this.getFunctionName()}' as is not defined on the agent and has not been registered`\n );\n }\n\n // Call the callback function.\n callbackFuncInvoker(this.args);\n };\n}\n", "import Callback from \"./Callback\";\nimport Lookup from \"../../Lookup\";\nimport { Agent } from \"../../Agent\";\n\n/**\n * An EXIT callback which defines an agent function to call when the associated node is updated and moves to a finished state or is aborted.\n */\nexport default class Exit extends Callback {\n /**\n * @param functionName The name of the agent function to call.\n * @param args The array of callback argument definitions.\n */\n constructor(functionName: string, args: any[]) {\n super(\"exit\", args, functionName);\n }\n\n /**\n * Attempt to call the agent function that this callback refers to.\n * @param agent The agent.\n * @param isSuccess Whether the decorated node was left with a success state.\n * @param isAborted Whether the decorated node was aborted.\n */\n callAgentFunction = (agent: Agent, isSuccess: boolean, isAborted: boolean) => {\n // Attempt to get the invoker for the callback function.\n const callbackFuncInvoker = Lookup.getFuncInvoker(agent, this.getFunctionName());\n\n // The callback function should be defined.\n if (callbackFuncInvoker === null) {\n throw new Error(\n `cannot call exit function '${this.getFunctionName()}' as is not defined on the agent and has not been registered`\n );\n }\n\n // Call the callback function\n callbackFuncInvoker([{ value: { succeeded: isSuccess, aborted: isAborted } }, ...this.args]);\n };\n}\n", "import { AnyNodeDefinition, RootNodeDefinition } from \"./BehaviourTreeDefinition\";\nimport GuardPath, { GuardPathPart } from \"./attributes/guards/GuardPath\";\nimport { validateBranchSubtreeLinks } from \"./BehaviourTreeDefinitionValidator\";\nimport Node from \"./nodes/Node\";\nimport Composite from \"./nodes/composite/Composite\";\nimport Decorator from \"./nodes/decorator/Decorator\";\nimport Parallel from \"./nodes/composite/Parallel\";\nimport Selector from \"./nodes/composite/Selector\";\nimport Sequence from \"./nodes/composite/Sequence\";\nimport Lotto from \"./nodes/composite/Lotto\";\nimport Fail from \"./nodes/decorator/Fail\";\nimport Flip from \"./nodes/decorator/Flip\";\nimport Repeat from \"./nodes/decorator/Repeat\";\nimport Retry from \"./nodes/decorator/Retry\";\nimport Root from \"./nodes/decorator/Root\";\nimport Succeed from \"./nodes/decorator/Succeed\";\nimport Action from \"./nodes/leaf/Action\";\nimport Condition from \"./nodes/leaf/Condition\";\nimport Wait from \"./nodes/leaf/Wait\";\nimport Lookup from \"./Lookup\";\nimport Attribute from \"./attributes/Attribute\";\nimport While from \"./attributes/guards/While\";\nimport Until from \"./attributes/guards/Until\";\nimport Entry from \"./attributes/callbacks/Entry\";\nimport Step from \"./attributes/callbacks/Step\";\nimport Exit from \"./attributes/callbacks/Exit\";\n\n/**\n * A type representing any node instance in a behaviour tree.\n */\ntype AnyNode =\n | Root\n | Action\n | Condition\n | Wait\n | Sequence\n | Selector\n | Lotto\n | Parallel\n | Repeat\n | Retry\n | Flip\n | Succeed\n | Fail;\n\n/**\n * A type defining a mapping of root node identifiers to root node definitions.\n */\ntype RootNodeDefinitionMap = { [key: string | symbol]: RootNodeDefinition };\n\n/**\n * A symbol to use as the main root key in any root node mappings.\n */\nconst MAIN_ROOT_NODE_KEY = Symbol(\"__root__\");\n\n/**\n * Build and populate the root nodes based on the provided definition, assuming that the definition has been validated.\n * @param definition The root node definitions.\n * @returns The built and populated root node definitions.\n */\nexport default function buildRootNode(definition: RootNodeDefinition[]): Root {\n // Create a mapping of root node identifers to root node definitions, including globally registered subtree root node definitions.\n const rootNodeDefinitionMap = createRootNodeDefinitionMap(definition);\n\n // Now that we have all of our root node definitons (those part of the tree definition and those globally\n // registered) we should validate the definition. This will also double-check that we dont have any circular\n // dependencies in our branch -> subtree references and that we have no broken branch -> subtree links.\n validateBranchSubtreeLinks(definition, true);\n\n // Create our populated tree of node instances, starting with our main root node.\n const rootNode = nodeFactory(rootNodeDefinitionMap[MAIN_ROOT_NODE_KEY]) as Root;\n\n // Set a guard path on every leaf of the tree to evaluate as part of its update.\n applyLeafNodeGuardPaths(rootNode);\n\n // We only need to return the main root node.\n return rootNode;\n}\n\n/**\n * A factory function which creates a node instance based on the specified definition.\n * @param definition The node definition.\n * @returns A node instance based on the specified definition.\n */\nfunction nodeFactory(definition: AnyNodeDefinition): AnyNode {\n // Get the attributes for the node.\n const attributes = nodeAttributesFactory(definition);\n\n // Create the node instance based on the definition type.\n switch (definition.type) {\n case \"root\":\n return new Root(attributes, nodeFactory(definition.child));\n\n // ...\n\n default:\n throw new Error(`unexpected node type of '${definition.type}'`);\n }\n}\n\n/**\n * Creates an array of node attribute instances based on the specified node definition.\n * @param definition The node definition.\n * @returns An array of node attribute instances based on the specified node definition.\n */\nfunction nodeAttributesFactory(definition: AnyNodeDefinition): Attribute[] {\n const attributes: Attribute[] = [];\n\n if (definition.while) {\n attributes.push(new While(definition.while.call, definition.while.args ?? []));\n }\n\n if (definition.until) {\n attributes.push(new Until(definition.until.call, definition.until.args ?? []));\n }\n\n if (definition.entry) {\n attributes.push(new Entry(definition.entry.call, definition.entry.args ?? []));\n }\n\n if (definition.step) {\n attributes.push(new Step(definition.step.call, definition.step.args ?? []));\n }\n\n if (definition.exit) {\n attributes.push(new Exit(definition.exit.call, definition.exit.args ?? []));\n }\n\n return attributes;\n}\n\n/**\n * Creates a mapping of root node identifers to root node definitions, mixing in globally registered subtree root node definitions.\n * @param definition The root node definitions.\n * @returns A mapping of root node identifers to root node definitions, including globally registered subtree root node definitions.\n */\nfunction createRootNodeDefinitionMap(definition: RootNodeDefinition[]): RootNodeDefinitionMap {\n // Create a mapping of root node identifers to root node definitions.\n const rootNodeMap: RootNodeDefinitionMap = {};\n\n // Add in any registered subtree root node definitions.\n for (const [name, rootNodeDefinition] of Object.entries(Lookup.getSubtrees())) {\n // The name used when registering the subtree will be used as the root node identifier.\n rootNodeMap[name] = { ...rootNodeDefinition, id: name };\n }\n\n // Populate the map with the root node definitions that were included with the tree definition.\n // We do this after adding any registered subtrees as we want these to take presedence.\n for (const rootNodeDefinition of definition) {\n rootNodeMap[rootNodeDefinition.id ?? MAIN_ROOT_NODE_KEY] = rootNodeDefinition;\n }\n\n return rootNodeMap;\n}\n\n/**\n * Applies a guard path to every leaf of the tree to evaluate as part of each update.\n * @param root The main root tree node.\n */\nfunction applyLeafNodeGuardPaths(root: Root) {\n const nodePaths: Node[][] = [];\n\n const findLeafNodes = (path: Node[], node: Node) => {\n // Add the current node to the path.\n path = path.concat(node);\n\n // Check whether the current node is a leaf node.\n if (node.isLeafNode()) {\n nodePaths.push(path);\n } else {\n (node as Composite | Decorator).getChildren().forEach((child) => findLeafNodes(path, child));\n }\n };\n\n // Find all leaf node paths, starting from the root.\n findLeafNodes([], root);\n\n nodePaths.forEach((path) => {\n // Each node in the current path will have to be assigned a guard path, working from the root outwards.\n for (let depth = 0; depth < path.length; depth++) {\n // Get the node in the path at the current depth.\n const currentNode = path[depth];\n\n // The node may already have been assigned a guard path, if so just skip it.\n if (currentNode.hasGuardPath()) {\n continue;\n }\n\n // Create the guard path for the current node.\n const guardPath = new GuardPath(\n path\n .slice(0, depth + 1)\n .map((node) => ({ node, guards: node.getGuardAttributes() }))\n .filter((details) => details.guards.length > 0)\n );\n\n // Assign the guard path to the current node.\n currentNode.setGuardPath(guardPath);\n }\n });\n}\n", "import State, { AnyState } from \"./State\";\nimport Lookup from \"./Lookup\";\nimport Node from \"./nodes/Node\";\nimport Root from \"./nodes/decorator/Root\";\nimport Composite from \"./nodes/composite/Composite\";\nimport Decorator from \"./nodes/decorator/Decorator\";\nimport { Agent, GlobalFunction } from \"./Agent\";\nimport { CallbackAttributeDetails } from \"./attributes/callbacks/Callback\";\nimport { GuardAttributeDetails } from \"./attributes/guards/Guard\";\nimport { BehaviourTreeOptions } from \"./BehaviourTreeOptions\";\nimport { convertMDSLToJSON } from \"./mdsl/MDSLDefinitionParser\";\nimport { RootNodeDefinition } from \"./BehaviourTreeDefinition\";\nimport { validateJSONDefinition } from \"./BehaviourTreeDefinitionValidator\";\nimport buildRootNode from \"./BehaviourTreeBuilder\";\n\n// Purely for outside inspection of the tree.\nexport type FlattenedTreeNode = {\n id: string;\n type: string;\n caption: string;\n state: AnyState;\n guards: GuardAttributeDetails[];\n callbacks: CallbackAttributeDetails[];\n args: any[];\n parentId: string | null;\n};\n\n/**\n * A representation of a behaviour tree.\n */\nexport class BehaviourTree {\n /**\n * The main root tree node.\n */\n public readonly rootNode: Root;\n\n /**\n * Creates a new instance of the BehaviourTree class.\n * @param definition The behaviour tree definition.\n * @param agent The agent instance that this behaviour tree is modelling behaviour for.\n * @param options The behaviour tree options object.\n */\n constructor(\n definition: string | RootNodeDefinition | RootNodeDefinition[],\n private agent: Agent,\n private options: BehaviourTreeOptions = {}\n ) {\n // The tree definition must be defined.\n if (!definition) {\n throw new Error(\"the tree definition must be a string ro\");\n }\n\n // The agent must be defined and not null.\n if (typeof agent !== \"object\" || agent === null) {\n throw new Error(\"the agent must be defined and not null\");\n }\n\n try {\n // Parse the behaviour tree definition, create the populated tree of behaviour tree nodes, and get the root.\n this.rootNode = this._createRootNode(definition);\n } catch (exception) {\n // There was an issue in trying build and populate the behaviour tree.\n throw new Error(`error building tree: ${(exception as Error).message}`);\n }\n }\n\n /**\n * Gets whether the tree is in the RUNNING state.\n * @returns true if the tree is in the RUNNING state, otherwise false.\n */\n isRunning() {\n return this.rootNode.getState() === State.RUNNING;\n }\n\n /**\n * Gets the current tree state of SUCCEEDED, FAILED, READY or RUNNING.\n * @returns The current tree state.\n */\n getState() {\n return this.rootNode.getState();\n }\n\n /**\n * Step the tree.\n * 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.\n * 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\n * 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.\n *\n * 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.\n */\n step() {\n // If the root node has already been stepped to completion then we need to reset it.\n if (this.rootNode.getState() === State.SUCCEEDED || this.rootNode.getState() === State.FAILED) {\n this.rootNode.reset();\n }\n\n try {\n this.rootNode.update(this.agent, this.options);\n } catch (exception) {\n throw new Error(`error stepping tree: ${(exception as Error).message}`);\n }\n }\n\n /**\n * Resets the tree from the root node outwards to each nested node, giving each a state of READY.\n */\n reset() {\n this.rootNode.reset();\n }\n\n /**\n * Gets the flattened details of every node in the tree.\n * @returns The flattened details of every node in the tree.\n */\n getFlattenedNodeDetails(): FlattenedTreeNode[] {\n // Create an empty flattened array of tree nodes.\n const flattenedTreeNodes: FlattenedTreeNode[] = [];\n\n /**\n * Helper function to process a node instance and push details into the flattened tree nodes array.\n * @param node The current node.\n * @param parentUid The UID of the node parent, or null if the node is the main root node.\n */\n const processNode = (node: Node, parentUid: string | null) => {\n // Get the guard and callback attribute details for this node.\n const guards = node\n .getAttributes()\n .filter((attribute) => attribute.isGuard())\n .map((attribute) => attribute.getDetails()) as GuardAttributeDetails[];\n const callbacks = node\n .getAttributes()\n .filter((attribute) => !attribute.isGuard())\n .map((attribute) => attribute.getDetails()) as CallbackAttributeDetails[];\n\n // Push the current node into the flattened nodes array.\n flattenedTreeNodes.push({\n id: node.getUid(),\n type: node.getType(),\n caption: node.getName(),\n state: node.getState(),\n guards,\n callbacks,\n args: node.getArguments(),\n parentId: parentUid\n });\n\n // Process each of the nodes children if it is not a leaf node.\n if (!node.isLeafNode()) {\n (node as Composite | Decorator)\n .getChildren()\n .forEach((child) => processNode(child, (node as Composite | Decorator).getUid()));\n }\n };\n\n // Convert the nested node structure into a flattened array of node details.\n processNode(this.rootNode, null);\n\n return flattenedTreeNodes;\n }\n\n /**\n * Registers the action/condition/guard/callback function or subtree with the given name.\n * @param name The name of the function or subtree to register.\n * @param value The function or subtree definition to register.\n */\n static register(name: string, value: GlobalFunction | string | RootNodeDefinition) {\n // Are we going to register a action/condition/guard/callback function?\n if (typeof value === \"function\") {\n Lookup.setFunc(name, value);\n return;\n }\n\n // We are not registering an action/condition/guard/callback function, so we must be registering a subtree.\n if (typeof value === \"string\") {\n let rootNodeDefinitions: RootNodeDefinition[];\n\n // We will assume that any string passed in will be a mdsl definition.\n try {\n rootNodeDefinitions = convertMDSLToJSON(value);\n } catch (exception) {\n throw new Error(`error registering definition, invalid MDSL: ${(exception as Error).message}`);\n }\n\n // This function should only ever be called with a definition containing a single unnamed root node.\n if (rootNodeDefinitions.length != 1 || rootNodeDefinitions[0].id !== null) {\n throw new Error(\"error registering definition: expected a single unnamed root node\");\n }\n\n try {\n // We should validate the subtree as we don't want invalid subtrees available via the lookup.\n const { succeeded, errorMessage } = validateJSONDefinition(rootNodeDefinitions[0]);\n\n // Did our validation fail without error?\n if (!succeeded) {\n throw new Error(errorMessage);\n }\n } catch (exception) {\n throw new Error(`error registering definition: ${(exception as Error).message}`);\n }\n\n // Everything seems hunky-dory, register the subtree.\n Lookup.setSubtree(name, rootNodeDefinitions[0]);\n } else if (typeof value === \"object\" && !Array.isArray(value)) {\n // We will assume that any object passed in is a root node definition.\n\n try {\n // We should validate the subtree as we don't want invalid subtrees available via the lookup.\n const { succeeded, errorMessage } = validateJSONDefinition(value);\n\n // Did our validation fail without error?\n if (!succeeded) {\n throw new Error(errorMessage);\n }\n } catch (exception) {\n throw new Error(`error registering definition: ${(exception as Error).message}`);\n }\n\n // Everything seems hunky-dory, register the subtree.\n Lookup.setSubtree(name, value);\n } else {\n throw new Error(\"unexpected value, expected string mdsl definition, root node json definition or function\");\n }\n }\n\n /**\n * Unregisters the registered action/condition/guard/callback function or subtree with the given name.\n * @param name The name of the registered action/condition/guard/callback function or subtree to unregister.\n */\n static unregister(name: string): void {\n Lookup.remove(name);\n }\n\n /**\n * Unregister all registered action/condition/guard/callback functions and subtrees.\n */\n static unregisterAll(): void {\n Lookup.empty();\n }\n\n /**\n * Parses a behaviour tree definition and creates a tree of behaviour tree nodes populated at a root.\n * @param {string | RootNodeDefinition | RootNodeDefinition[]} definition The behaviour tree definition.\n * @returns The root behaviour tree node.\n */\n private _createRootNode(definition: string | RootNodeDefinition | RootNodeDefinition[]): Root {\n let resolvedDefinition: RootNodeDefinition | RootNodeDefinition[];\n\n // If the definition is a string then we will assume that it is an mdsl string which needs to be converted to a JSON definition.\n if (typeof definition === \"string\") {\n try {\n resolvedDefinition = convertMDSLToJSON(definition);\n } catch (exception) {\n throw new Error(`invalid mdsl definition: ${(exception as Error).message}`);\n }\n } else {\n // The definition is not a string, so we should assume that it is already a JSON definition.\n resolvedDefinition = definition;\n }\n\n // Build and populate the root node.\n return buildRootNode(Array.isArray(resolvedDefinition) ? resolvedDefinition : [resolvedDefinition]);\n }\n}\n"], + "mappings": "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", + "names": ["State"] } diff --git a/dist/index.js b/dist/index.js index 07402bf..6be62c4 100644 --- a/dist/index.js +++ b/dist/index.js @@ -1,14 +1,9 @@ "use strict"; -var __create = Object.create; var __defProp = Object.defineProperty; var __getOwnPropDesc = Object.getOwnPropertyDescriptor; var __getOwnPropNames = Object.getOwnPropertyNames; -var __getProtoOf = Object.getPrototypeOf; var __hasOwnProp = Object.prototype.hasOwnProperty; var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value; -var __commonJS = (cb, mod) => function __require() { - return mod || (0, cb[__getOwnPropNames(cb)[0]])((mod = { exports: {} }).exports, mod), mod.exports; -}; var __export = (target, all) => { for (var name in all) __defProp(target, name, { get: all[name], enumerable: true }); @@ -21,232 +16,12 @@ var __copyProps = (to, from, except, desc) => { } return to; }; -var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps( - isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target, - mod -)); var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod); var __publicField = (obj, key, value) => { __defNormalProp(obj, typeof key !== "symbol" ? key + "" : key, value); return value; }; -// node_modules/lotto-draw/dist/Participant.js -var require_Participant = __commonJS({ - "node_modules/lotto-draw/dist/Participant.js"(exports) { - "use strict"; - Object.defineProperty(exports, "__esModule", { value: true }); - exports.Participant = void 0; - var Participant = function() { - function Participant2(participant, tickets) { - if (tickets === void 0) { - tickets = 1; - } - this._participant = participant; - this._tickets = tickets; - } - Object.defineProperty(Participant2.prototype, "participant", { - get: function() { - return this._participant; - }, - enumerable: false, - configurable: true - }); - Object.defineProperty(Participant2.prototype, "tickets", { - get: function() { - return this._tickets; - }, - set: function(value) { - this._tickets = value; - }, - enumerable: false, - configurable: true - }); - return Participant2; - }(); - exports.Participant = Participant; - } -}); - -// node_modules/lotto-draw/dist/Utilities.js -var require_Utilities = __commonJS({ - "node_modules/lotto-draw/dist/Utilities.js"(exports) { - "use strict"; - Object.defineProperty(exports, "__esModule", { value: true }); - exports.isNaturalNumber = exports.isNullOrUndefined = void 0; - function isNullOrUndefined(value) { - return value === null || value === void 0; - } - exports.isNullOrUndefined = isNullOrUndefined; - function isNaturalNumber(value) { - return typeof value === "number" && value >= 1 && Math.floor(value) === value; - } - exports.isNaturalNumber = isNaturalNumber; - } -}); - -// node_modules/lotto-draw/dist/Lotto.js -var require_Lotto = __commonJS({ - "node_modules/lotto-draw/dist/Lotto.js"(exports) { - "use strict"; - Object.defineProperty(exports, "__esModule", { value: true }); - exports.Lotto = void 0; - var Participant_1 = require_Participant(); - var Utilities_1 = require_Utilities(); - var Lotto2 = function() { - function Lotto3(customRandom) { - this._participants = []; - this._customRandom = customRandom; - } - Lotto3.prototype.add = function(participant, tickets) { - if (tickets === void 0) { - tickets = 1; - } - if (!(0, Utilities_1.isNaturalNumber)(tickets)) { - throw new Error("tickets value must be a natural number"); - } - var existingParticipant = this._participants.find(function(part) { - return part.participant === participant; - }); - if (existingParticipant) { - existingParticipant.tickets += tickets; - } else { - this._participants.push(new Participant_1.Participant(participant, tickets)); - } - return this; - }; - Lotto3.prototype.remove = function(participant, tickets) { - var existingParticipant = this._participants.find(function(part) { - return part.participant === participant; - }); - if (!existingParticipant) { - return this; - } - if (tickets !== void 0) { - if (!(0, Utilities_1.isNaturalNumber)(tickets)) { - throw new Error("tickets value must be a natural number"); - } - existingParticipant.tickets -= tickets; - if (existingParticipant.tickets < 1) { - this._participants = this._participants.filter(function(part) { - return part !== existingParticipant; - }); - } - } else { - this._participants = this._participants.filter(function(part) { - return part !== existingParticipant; - }); - } - return this; - }; - Lotto3.prototype.draw = function(options) { - if (options === void 0) { - options = {}; - } - if (this._participants.length === 0) { - return null; - } - var redrawable = (0, Utilities_1.isNullOrUndefined)(options.redrawable) ? true : options.redrawable; - var pickable = []; - this._participants.forEach(function(_a) { - var participant = _a.participant, tickets = _a.tickets; - for (var ticketCount = 0; ticketCount < tickets; ticketCount++) { - pickable.push(participant); - } - }); - var random; - if (this._customRandom) { - random = this._customRandom(); - if (typeof random !== "number" || random < 0 || random >= 1) { - throw new Error("the 'random' function provided did not return a number between 0 (inclusive) and 1"); - } - } else { - random = Math.random(); - } - var winner = pickable[Math.floor(random * pickable.length)]; - if (!redrawable) { - this.remove(winner, 1); - } - return winner; - }; - Lotto3.prototype.drawMultiple = function(tickets, options) { - if (options === void 0) { - options = {}; - } - var uniqueResults = (0, Utilities_1.isNullOrUndefined)(options.unique) ? false : options.unique; - if (tickets === 0) { - return []; - } - if (!(0, Utilities_1.isNaturalNumber)(tickets)) { - throw new Error("tickets value must be a natural number"); - } - var result = []; - while (result.length < tickets && this._participants.length > 0) { - result.push(this.draw(options)); - } - if (uniqueResults) { - var unique = []; - for (var _i = 0, result_1 = result; _i < result_1.length; _i++) { - var participant = result_1[_i]; - if (unique.indexOf(participant) === -1) { - unique.push(participant); - } - } - result = unique; - } - return result; - }; - return Lotto3; - }(); - exports.Lotto = Lotto2; - } -}); - -// node_modules/lotto-draw/dist/createLotto.js -var require_createLotto = __commonJS({ - "node_modules/lotto-draw/dist/createLotto.js"(exports) { - "use strict"; - Object.defineProperty(exports, "__esModule", { value: true }); - exports.createLotto = void 0; - var Lotto_1 = require_Lotto(); - function createLotto2(participantsOrOptions) { - if (!participantsOrOptions) { - return new Lotto_1.Lotto(); - } - if (Array.isArray(participantsOrOptions)) { - var participants = participantsOrOptions; - var lotto_1 = new Lotto_1.Lotto(); - participants.forEach(function(_a) { - var participant = _a[0], tokens = _a[1]; - return lotto_1.add(participant, tokens); - }); - return lotto_1; - } else { - var random = participantsOrOptions.random, participants = participantsOrOptions.participants; - var lotto_2 = new Lotto_1.Lotto(random); - if (participants) { - participants.forEach(function(_a) { - var participant = _a[0], tokens = _a[1]; - return lotto_2.add(participant, tokens); - }); - } - return lotto_2; - } - } - exports.createLotto = createLotto2; - } -}); - -// node_modules/lotto-draw/dist/index.js -var require_dist = __commonJS({ - "node_modules/lotto-draw/dist/index.js"(exports) { - "use strict"; - Object.defineProperty(exports, "__esModule", { value: true }); - var createLotto_1 = require_createLotto(); - exports.default = createLotto_1.createLotto; - } -}); - // src/index.ts var src_exports = {}; __export(src_exports, { @@ -738,7 +513,7 @@ function validateMDSLDefinition(definition) { try { rootNodeDefinitions = convertMDSLToJSON(definition); } catch (error) { - return createValidationFailureResult(`invalid MDSL: ${definition}`); + return createValidationFailureResult(`invalid MDSL: ${error}`); } const mainRootNodeDefinitions = rootNodeDefinitions.filter(({ id }) => typeof id === "undefined"); const subRootNodeDefinitions = rootNodeDefinitions.filter(({ id }) => typeof id === "string" && id.length > 0); @@ -754,11 +529,10 @@ function validateMDSLDefinition(definition) { } subRootNodeIdenitifers.push(id); } - const circularDependencyPath = findBranchCircularDependencyPath(rootNodeDefinitions); - if (circularDependencyPath) { - return createValidationFailureResult( - `circular dependency found in branch node references: ${circularDependencyPath}` - ); + try { + validateBranchSubtreeLinks(rootNodeDefinitions, false); + } catch (exception) { + return createValidationFailureResult(exception.message); } return { succeeded: true }; } @@ -788,37 +562,38 @@ function validateJSONDefinition(definition) { } subRootNodeIdenitifers.push(id); } - const circularDependencyPath = findBranchCircularDependencyPath(rootNodeDefinitions); - if (circularDependencyPath) { - return createValidationFailureResult( - `circular dependency found in branch node references: ${circularDependencyPath}` - ); + try { + validateBranchSubtreeLinks(rootNodeDefinitions, false); + } catch (exception) { + return createValidationFailureResult(exception.message); } return { succeeded: true }; } -function findBranchCircularDependencyPath(rootNodeDefinitions) { +function validateBranchSubtreeLinks(rootNodeDefinitions, includesGlobalSubtrees) { const rootNodeMappings = rootNodeDefinitions.map( (rootNodeDefinition) => ({ id: rootNodeDefinition.id, refs: flattenDefinition(rootNodeDefinition).filter(isBranchNode).map(({ ref }) => ref) }) ); - let badPathFormatted = null; const followRefs = (mapping, path = []) => { if (path.includes(mapping.id)) { const badPath = [...path, mapping.id]; - badPathFormatted = badPath.filter((element) => !!element).join(" => "); - return; + const badPathFormatted = badPath.filter((element) => !!element).join(" => "); + throw new Error(`circular dependency found in branch node references: ${badPathFormatted}`); } for (const ref of mapping.refs) { const subMapping = rootNodeMappings.find(({ id }) => id === ref); if (subMapping) { followRefs(subMapping, [...path, mapping.id]); + } else if (includesGlobalSubtrees) { + throw new Error( + mapping.id ? `subtree '${mapping.id}' has branch node that references root node '${ref}' which has not been defined` : `primary tree has branch node that references root node '${ref}' which has not been defined` + ); } } }; followRefs(rootNodeMappings.find((mapping) => typeof mapping.id === "undefined")); - return badPathFormatted; } function validateNode(definition, depth) { if (typeof definition !== "object" || typeof definition.type !== "string" || definition.type.length === 0) { @@ -1087,6 +862,42 @@ function createValidationFailureResult(errorMessage) { return { succeeded: false, errorMessage }; } +// src/Lookup.ts +var Lookup = class { + static getFunc(name) { + return this.functionTable[name]; + } + static setFunc(name, func) { + this.functionTable[name] = func; + } + static getFuncInvoker(agent, name) { + const foundOnAgent = agent[name]; + if (foundOnAgent && typeof foundOnAgent === "function") { + return (args) => foundOnAgent.apply(agent, args); + } + if (this.functionTable[name] && typeof this.functionTable[name] === "function") { + return (args) => this.functionTable[name](agent, ...args.map((arg) => arg.value)); + } + return null; + } + static getSubtrees() { + return this.subtreeTable; + } + static setSubtree(name, subtree) { + this.subtreeTable[name] = subtree; + } + static remove(name) { + delete this.functionTable[name]; + delete this.subtreeTable[name]; + } + static empty() { + this.functionTable = {}; + this.subtreeTable = {}; + } +}; +__publicField(Lookup, "functionTable", {}); +__publicField(Lookup, "subtreeTable", {}); + // src/attributes/guards/GuardUnsatisifedException.ts var GuardUnsatisifedException = class extends Error { constructor(source) { @@ -1131,7 +942,7 @@ var Node = class { getAttributes = () => this.attributes; getArguments = () => this.args; getAttribute(type) { - return this.getAttributes().filter((decorator) => decorator.getType().toUpperCase() === type.toUpperCase())[0] || null; + return this.getAttributes().filter((decorator) => decorator.type.toUpperCase() === type.toUpperCase())[0] || null; } getGuardAttributes = () => this.getAttributes().filter((decorator) => decorator.isGuard()); setGuardPath = (value) => this.guardPath = value; @@ -1180,193 +991,6 @@ function createNodeUid() { return S4() + S4() + "-" + S4() + "-" + S4() + "-" + S4() + "-" + S4() + S4() + S4(); } -// src/nodes/leaf/Leaf.ts -var Leaf = class extends Node { - isLeafNode = () => true; -}; - -// src/Lookup.ts -var Lookup = class { - static getFunc(name) { - return this.functionTable[name]; - } - static setFunc(name, func) { - this.functionTable[name] = func; - } - static getFuncInvoker(agent, name) { - const foundOnAgent = agent[name]; - if (foundOnAgent && typeof foundOnAgent === "function") { - return (args) => foundOnAgent.apply( - agent, - args.map((arg) => arg.value) - ); - } - if (this.functionTable[name] && typeof this.functionTable[name] === "function") { - return (args) => this.functionTable[name](agent, ...args.map((arg) => arg.value)); - } - return null; - } - static getSubtree(name) { - return this.subtreeTable[name]; - } - static setSubtree(name, subtree) { - this.subtreeTable[name] = subtree; - } - static remove(name) { - delete this.functionTable[name]; - delete this.subtreeTable[name]; - } - static empty() { - this.functionTable = {}; - this.subtreeTable = {}; - } -}; -__publicField(Lookup, "functionTable", {}); -__publicField(Lookup, "subtreeTable", {}); - -// src/nodes/leaf/Action.ts -var Action = class extends Leaf { - constructor(attributes, actionName, actionArguments) { - super("action", attributes, actionArguments); - this.actionName = actionName; - this.actionArguments = actionArguments; - } - isUsingUpdatePromise = false; - updatePromiseStateResult = null; - onUpdate(agent, options) { - if (this.isUsingUpdatePromise) { - if (this.updatePromiseStateResult) { - this.setState(this.updatePromiseStateResult); - } - return; - } - const actionFuncInvoker = Lookup.getFuncInvoker(agent, this.actionName); - if (actionFuncInvoker === null) { - throw new Error( - `cannot update action node as the action '${this.actionName}' function is not defined on the agent and has not been registered` - ); - } - const updateResult = actionFuncInvoker(this.actionArguments); - if (updateResult instanceof Promise) { - updateResult.then( - (result) => { - if (!this.isUsingUpdatePromise) { - return; - } - if (result !== "mistreevous.succeeded" /* SUCCEEDED */ && result !== "mistreevous.failed" /* FAILED */) { - throw new Error( - "action node promise resolved with an invalid value, expected a State.SUCCEEDED or State.FAILED value to be returned" - ); - } - this.updatePromiseStateResult = result; - }, - (reason) => { - if (!this.isUsingUpdatePromise) { - return; - } - throw new Error(reason); - } - ); - this.setState("mistreevous.running" /* RUNNING */); - this.isUsingUpdatePromise = true; - } else { - this.validateUpdateResult(updateResult); - this.setState(updateResult || "mistreevous.running" /* RUNNING */); - } - } - getName = () => this.actionName; - reset = () => { - this.setState("mistreevous.ready" /* READY */); - this.isUsingUpdatePromise = false; - this.updatePromiseStateResult = null; - }; - validateUpdateResult = (result) => { - switch (result) { - case "mistreevous.succeeded" /* SUCCEEDED */: - case "mistreevous.failed" /* FAILED */: - case void 0: - return; - default: - throw new Error( - `action '${this.actionName}' 'onUpdate' returned an invalid response, expected an optional State.SUCCEEDED or State.FAILED value to be returned` - ); - } - }; -}; - -// src/nodes/leaf/Condition.ts -var Condition = class extends Leaf { - constructor(attributes, conditionName, conditionArguments) { - super("condition", attributes, conditionArguments); - this.conditionName = conditionName; - this.conditionArguments = conditionArguments; - } - onUpdate(agent, options) { - const conditionFuncInvoker = Lookup.getFuncInvoker(agent, this.conditionName); - if (conditionFuncInvoker === null) { - throw new Error( - `cannot update condition node as the condition '${this.conditionName}' function is not defined on the agent and has not been registered` - ); - } - this.setState(!!conditionFuncInvoker(this.conditionArguments) ? "mistreevous.succeeded" /* SUCCEEDED */ : "mistreevous.failed" /* FAILED */); - } - getName = () => this.conditionName; -}; - -// src/nodes/leaf/Wait.ts -var Wait = class extends Leaf { - constructor(attributes, duration, durationMin, durationMax) { - super("wait", attributes, []); - this.duration = duration; - this.durationMin = durationMin; - this.durationMax = durationMax; - } - initialUpdateTime = 0; - totalDuration = null; - waitedDuration = 0; - onUpdate(agent, options) { - if (this.is("mistreevous.ready" /* READY */)) { - this.initialUpdateTime = new Date().getTime(); - this.waitedDuration = 0; - if (this.duration !== null) { - this.totalDuration = this.duration; - } else if (this.durationMin !== null && this.durationMax !== null) { - const random = typeof options.random === "function" ? options.random : Math.random; - this.totalDuration = Math.floor( - random() * (this.durationMax - this.durationMin + 1) + this.durationMin - ); - } else { - this.totalDuration = null; - } - this.setState("mistreevous.running" /* RUNNING */); - } - if (this.totalDuration === null) { - return; - } - if (typeof options.getDeltaTime === "function") { - const deltaTime = options.getDeltaTime(); - if (typeof deltaTime !== "number" || isNaN(deltaTime)) { - throw new Error("The delta time must be a valid number and not NaN."); - } - this.waitedDuration += deltaTime * 1e3; - } else { - this.waitedDuration = new Date().getTime() - this.initialUpdateTime; - } - if (this.waitedDuration >= this.totalDuration) { - this.setState("mistreevous.succeeded" /* SUCCEEDED */); - } - } - getName = () => { - if (this.duration !== null) { - return `WAIT ${this.duration}ms`; - } else if (this.durationMin !== null && this.durationMax !== null) { - return `WAIT ${this.durationMin}ms-${this.durationMax}ms`; - } else { - return "WAIT"; - } - }; -}; - // src/nodes/decorator/Decorator.ts var Decorator = class extends Node { constructor(type, attributes, child) { @@ -1403,438 +1027,75 @@ var Root = class extends Decorator { getName = () => "ROOT"; }; -// src/nodes/decorator/Repeat.ts -var Repeat = class extends Decorator { - constructor(attributes, iterations, iterationsMin, iterationsMax, child) { - super("repeat", attributes, child); - this.iterations = iterations; - this.iterationsMin = iterationsMin; - this.iterationsMax = iterationsMax; - } - targetIterationCount = null; - currentIterationCount = 0; - onUpdate(agent, options) { - if (this.is("mistreevous.ready" /* READY */)) { - this.child.reset(); - this.currentIterationCount = 0; - this.setTargetIterationCount(options); - } - if (this.canIterate()) { - this.setState("mistreevous.running" /* RUNNING */); - if (this.child.getState() === "mistreevous.succeeded" /* SUCCEEDED */) { - this.child.reset(); - } - this.child.update(agent, options); - if (this.child.getState() === "mistreevous.failed" /* FAILED */) { - this.setState("mistreevous.failed" /* FAILED */); - return; - } else if (this.child.getState() === "mistreevous.succeeded" /* SUCCEEDED */) { - this.currentIterationCount += 1; - } - } else { - this.setState("mistreevous.succeeded" /* SUCCEEDED */); - } +// src/attributes/Attribute.ts +var Attribute = class { + constructor(type, args) { + this.type = type; + this.args = args; } - getName = () => { - if (this.iterations !== null) { - return `REPEAT ${this.iterations}x`; - } else if (this.iterationsMin !== null && this.iterationsMax !== null) { - return `REPEAT ${this.iterationsMin}x-${this.iterationsMax}x`; - } else { - return "REPEAT"; - } - }; - reset = () => { - this.setState("mistreevous.ready" /* READY */); - this.currentIterationCount = 0; - this.child.reset(); - }; - canIterate = () => { - if (this.targetIterationCount !== null) { - return this.currentIterationCount < this.targetIterationCount; - } - return true; - }; - setTargetIterationCount = (options) => { - if (this.iterations !== null) { - this.targetIterationCount = this.iterations; - } else if (this.iterationsMin !== null && this.iterationsMax !== null) { - const random = typeof options.random === "function" ? options.random : Math.random; - this.targetIterationCount = Math.floor( - random() * (this.iterationsMax - this.iterationsMin + 1) + this.iterationsMin +}; + +// src/attributes/guards/Guard.ts +var Guard = class extends Attribute { + constructor(type, args, condition) { + super(type, args); + this.condition = condition; + } + getCondition = () => this.condition; + isGuard = () => true; + getDetails() { + return { + type: this.type, + args: this.args, + condition: this.getCondition() + }; + } +}; + +// src/attributes/guards/While.ts +var While = class extends Guard { + constructor(condition, args) { + super("while", args, condition); + } + isSatisfied = (agent) => { + const conditionFuncInvoker = Lookup.getFuncInvoker(agent, this.getCondition()); + if (conditionFuncInvoker === null) { + throw new Error( + `cannot evaluate node guard as the condition '${this.getCondition()}' function is not defined on the agent and has not been registered` ); - } else { - this.targetIterationCount = null; } + return !!conditionFuncInvoker(this.args); }; }; -// src/nodes/decorator/Retry.ts -var Retry = class extends Decorator { - constructor(attributes, attempts, attemptsMin, attemptsMax, child) { - super("retry", attributes, child); - this.attempts = attempts; - this.attemptsMin = attemptsMin; - this.attemptsMax = attemptsMax; - } - targetAttemptCount = null; - currentAttemptCount = 0; - onUpdate(agent, options) { - if (this.is("mistreevous.ready" /* READY */)) { - this.child.reset(); - this.currentAttemptCount = 0; - this.setTargetAttemptCount(options); - } - if (this.canAttempt()) { - this.setState("mistreevous.running" /* RUNNING */); - if (this.child.getState() === "mistreevous.failed" /* FAILED */) { - this.child.reset(); - } - this.child.update(agent, options); - if (this.child.getState() === "mistreevous.succeeded" /* SUCCEEDED */) { - this.setState("mistreevous.succeeded" /* SUCCEEDED */); - return; - } else if (this.child.getState() === "mistreevous.failed" /* FAILED */) { - this.currentAttemptCount += 1; - } - } else { - this.setState("mistreevous.failed" /* FAILED */); - } +// src/attributes/guards/Until.ts +var Until = class extends Guard { + constructor(condition, args) { + super("until", args, condition); } - getName = () => { - if (this.attempts !== null) { - return `RETRY ${this.attempts}x`; - } else if (this.attemptsMin !== null && this.attemptsMax !== null) { - return `RETRY ${this.attemptsMin}x-${this.attemptsMax}x`; - } else { - return "RETRY"; - } - }; - reset = () => { - this.setState("mistreevous.ready" /* READY */); - this.currentAttemptCount = 0; - this.child.reset(); - }; - canAttempt = () => { - if (this.targetAttemptCount !== null) { - return this.currentAttemptCount < this.targetAttemptCount; - } - return true; - }; - setTargetAttemptCount = (options) => { - if (this.attempts !== null) { - this.targetAttemptCount = this.attempts; - } else if (this.attemptsMin !== null && this.attemptsMax !== null) { - const random = typeof options.random === "function" ? options.random : Math.random; - this.targetAttemptCount = Math.floor( - random() * (this.attemptsMax - this.attemptsMin + 1) + this.attemptsMin + isSatisfied = (agent) => { + const conditionFuncInvoker = Lookup.getFuncInvoker(agent, this.getCondition()); + if (conditionFuncInvoker === null) { + throw new Error( + `cannot evaluate node guard as the condition '${this.getCondition()}' function is not defined on the agent and has not been registered` ); - } else { - this.targetAttemptCount = null; } + return !!!conditionFuncInvoker(this.args); }; }; -// src/nodes/decorator/Flip.ts -var Flip = class extends Decorator { - constructor(attributes, child) { - super("flip", attributes, child); - } - onUpdate(agent, options) { - if (this.child.getState() === "mistreevous.ready" /* READY */ || this.child.getState() === "mistreevous.running" /* RUNNING */) { - this.child.update(agent, options); - } - switch (this.child.getState()) { - case "mistreevous.running" /* RUNNING */: - this.setState("mistreevous.running" /* RUNNING */); - break; - case "mistreevous.succeeded" /* SUCCEEDED */: - this.setState("mistreevous.failed" /* FAILED */); - break; - case "mistreevous.failed" /* FAILED */: - this.setState("mistreevous.succeeded" /* SUCCEEDED */); - break; - default: - this.setState("mistreevous.ready" /* READY */); - } - } - getName = () => "FLIP"; -}; - -// src/nodes/decorator/Succeed.ts -var Succeed = class extends Decorator { - constructor(attributes, child) { - super("succeed", attributes, child); - } - onUpdate(agent, options) { - if (this.child.getState() === "mistreevous.ready" /* READY */ || this.child.getState() === "mistreevous.running" /* RUNNING */) { - this.child.update(agent, options); - } - switch (this.child.getState()) { - case "mistreevous.running" /* RUNNING */: - this.setState("mistreevous.running" /* RUNNING */); - break; - case "mistreevous.succeeded" /* SUCCEEDED */: - case "mistreevous.failed" /* FAILED */: - this.setState("mistreevous.succeeded" /* SUCCEEDED */); - break; - default: - this.setState("mistreevous.ready" /* READY */); - } - } - getName = () => "SUCCEED"; -}; - -// src/nodes/decorator/Fail.ts -var Fail = class extends Decorator { - constructor(attributes, child) { - super("fail", attributes, child); - } - onUpdate(agent, options) { - if (this.child.getState() === "mistreevous.ready" /* READY */ || this.child.getState() === "mistreevous.running" /* RUNNING */) { - this.child.update(agent, options); - } - switch (this.child.getState()) { - case "mistreevous.running" /* RUNNING */: - this.setState("mistreevous.running" /* RUNNING */); - break; - case "mistreevous.succeeded" /* SUCCEEDED */: - case "mistreevous.failed" /* FAILED */: - this.setState("mistreevous.failed" /* FAILED */); - break; - default: - this.setState("mistreevous.ready" /* READY */); - } - } - getName = () => "FAIL"; -}; - -// src/nodes/composite/Lotto.ts -var import_lotto_draw = __toESM(require_dist()); - -// src/nodes/composite/Composite.ts -var Composite = class extends Node { - constructor(type, attributes, children) { - super(type, attributes, []); - this.children = children; - } - isLeafNode = () => false; - getChildren = () => this.children; - reset = () => { - this.setState("mistreevous.ready" /* READY */); - this.getChildren().forEach((child) => child.reset()); - }; - abort = (agent) => { - if (!this.is("mistreevous.running" /* RUNNING */)) { - return; - } - this.getChildren().forEach((child) => child.abort(agent)); - this.reset(); - this.getAttribute("exit")?.callAgentFunction(agent, false, true); - }; -}; - -// src/nodes/composite/Lotto.ts -var Lotto = class extends Composite { - constructor(attributes, tickets, children) { - super("lotto", attributes, children); - this.tickets = tickets; - } - selectedChild; - onUpdate(agent, options) { - if (this.is("mistreevous.ready" /* READY */)) { - const lottoDraw = (0, import_lotto_draw.default)({ - random: options.random, - participants: this.children.map((child, index) => [child, this.tickets[index] || 1]) - }); - this.selectedChild = lottoDraw.draw() || void 0; - } - if (!this.selectedChild) { - throw new Error("failed to update lotto node as it has no active child"); - } - if (this.selectedChild.getState() === "mistreevous.ready" /* READY */ || this.selectedChild.getState() === "mistreevous.running" /* RUNNING */) { - this.selectedChild.update(agent, options); - } - this.setState(this.selectedChild.getState()); - } - getName = () => this.tickets.length ? `LOTTO [${this.tickets.join(",")}]` : "LOTTO"; -}; - -// src/nodes/composite/Selector.ts -var Selector = class extends Composite { - constructor(attributes, children) { - super("selector", attributes, children); - this.children = children; - } - onUpdate(agent, options) { - for (const child of this.children) { - if (child.getState() === "mistreevous.ready" /* READY */ || child.getState() === "mistreevous.running" /* RUNNING */) { - child.update(agent, options); - } - if (child.getState() === "mistreevous.succeeded" /* SUCCEEDED */) { - this.setState("mistreevous.succeeded" /* SUCCEEDED */); - return; - } - if (child.getState() === "mistreevous.failed" /* FAILED */) { - if (this.children.indexOf(child) === this.children.length - 1) { - this.setState("mistreevous.failed" /* FAILED */); - return; - } else { - continue; - } - } - if (child.getState() === "mistreevous.running" /* RUNNING */) { - this.setState("mistreevous.running" /* RUNNING */); - return; - } - throw new Error("child node was not in an expected state."); - } - } - getName = () => "SELECTOR"; -}; - -// src/nodes/composite/Sequence.ts -var Sequence = class extends Composite { - constructor(attributes, children) { - super("sequence", attributes, children); - this.children = children; - } - onUpdate(agent, options) { - for (const child of this.children) { - if (child.getState() === "mistreevous.ready" /* READY */ || child.getState() === "mistreevous.running" /* RUNNING */) { - child.update(agent, options); - } - if (child.getState() === "mistreevous.succeeded" /* SUCCEEDED */) { - if (this.children.indexOf(child) === this.children.length - 1) { - this.setState("mistreevous.succeeded" /* SUCCEEDED */); - return; - } else { - continue; - } - } - if (child.getState() === "mistreevous.failed" /* FAILED */) { - this.setState("mistreevous.failed" /* FAILED */); - return; - } - if (child.getState() === "mistreevous.running" /* RUNNING */) { - this.setState("mistreevous.running" /* RUNNING */); - return; - } - throw new Error("child node was not in an expected state."); - } - } - getName = () => "SEQUENCE"; -}; - -// src/nodes/composite/Parallel.ts -var Parallel = class extends Composite { - constructor(attributes, children) { - super("parallel", attributes, children); - } - onUpdate(agent, options) { - let succeededCount = 0; - let hasChildFailed = false; - for (const child of this.children) { - if (child.getState() === "mistreevous.ready" /* READY */ || child.getState() === "mistreevous.running" /* RUNNING */) { - child.update(agent, options); - } - if (child.getState() === "mistreevous.succeeded" /* SUCCEEDED */) { - succeededCount++; - continue; - } - if (child.getState() === "mistreevous.failed" /* FAILED */) { - hasChildFailed = true; - break; - } - if (child.getState() !== "mistreevous.running" /* RUNNING */) { - throw new Error("child node was not in an expected state."); - } - } - if (hasChildFailed) { - this.setState("mistreevous.failed" /* FAILED */); - for (const child of this.children) { - if (child.getState() === "mistreevous.running" /* RUNNING */) { - child.abort(agent); - } - } - } else { - this.setState(succeededCount === this.children.length ? "mistreevous.succeeded" /* SUCCEEDED */ : "mistreevous.running" /* RUNNING */); - } - } - getName = () => "PARALLEL"; -}; - -// src/attributes/Attribute.ts -var Attribute = class { - constructor(type, args) { - this.type = type; - this.args = args; - } - getType = () => this.type; - getArguments = () => this.args; -}; - -// src/attributes/guards/Guard.ts -var Guard = class extends Attribute { - constructor(type, args, condition) { - super(type, args); - this.condition = condition; - } - getCondition = () => this.condition; - isGuard = () => true; - getDetails() { - return { - type: this.getType(), - args: this.getArguments(), - condition: this.getCondition() - }; - } -}; - -// src/attributes/guards/While.ts -var While = class extends Guard { - constructor(condition, args) { - super("while", args, condition); - } - isSatisfied = (agent) => { - const conditionFuncInvoker = Lookup.getFuncInvoker(agent, this.getCondition()); - if (conditionFuncInvoker === null) { - throw new Error( - `cannot evaluate node guard as the condition '${this.getCondition()}' function is not defined on the agent and has not been registered` - ); - } - return !!conditionFuncInvoker(this.args); - }; -}; - -// src/attributes/guards/Until.ts -var Until = class extends Guard { - constructor(condition, args) { - super("until", args, condition); - } - isSatisfied = (agent) => { - const conditionFuncInvoker = Lookup.getFuncInvoker(agent, this.getCondition()); - if (conditionFuncInvoker === null) { - throw new Error( - `cannot evaluate node guard as the condition '${this.getCondition()}' function is not defined on the agent and has not been registered` - ); - } - return !!!conditionFuncInvoker(this.args); - }; -}; - -// src/attributes/callbacks/Callback.ts -var Callback = class extends Attribute { - constructor(type, args, functionName) { - super(type, args); - this.functionName = functionName; +// src/attributes/callbacks/Callback.ts +var Callback = class extends Attribute { + constructor(type, args, functionName) { + super(type, args); + this.functionName = functionName; } getFunctionName = () => this.functionName; isGuard = () => false; getDetails() { return { - type: this.getType(), - args: this.getArguments(), + type: this.type, + args: this.args, functionName: this.getFunctionName() }; } @@ -1856,700 +1117,108 @@ var Entry = class extends Callback { }; }; -// src/attributes/callbacks/Exit.ts -var Exit = class extends Callback { +// src/attributes/callbacks/Step.ts +var Step = class extends Callback { constructor(functionName, args) { - super("exit", args, functionName); + super("step", args, functionName); } - callAgentFunction = (agent, isSuccess, isAborted) => { + callAgentFunction = (agent) => { const callbackFuncInvoker = Lookup.getFuncInvoker(agent, this.getFunctionName()); if (callbackFuncInvoker === null) { throw new Error( - `cannot call exit function '${this.getFunctionName()}' as is not defined on the agent and has not been registered` + `cannot call step function '${this.getFunctionName()}' as is not defined on the agent and has not been registered` ); } - callbackFuncInvoker([{ value: { succeeded: isSuccess, aborted: isAborted } }, ...this.args]); + callbackFuncInvoker(this.args); }; }; -// src/attributes/callbacks/Step.ts -var Step = class extends Callback { +// src/attributes/callbacks/Exit.ts +var Exit = class extends Callback { constructor(functionName, args) { - super("step", args, functionName); + super("exit", args, functionName); } - callAgentFunction = (agent) => { + callAgentFunction = (agent, isSuccess, isAborted) => { const callbackFuncInvoker = Lookup.getFuncInvoker(agent, this.getFunctionName()); if (callbackFuncInvoker === null) { throw new Error( - `cannot call step function '${this.getFunctionName()}' as is not defined on the agent and has not been registered` + `cannot call exit function '${this.getFunctionName()}' as is not defined on the agent and has not been registered` ); } - callbackFuncInvoker(this.args); + callbackFuncInvoker([{ value: { succeeded: isSuccess, aborted: isAborted } }, ...this.args]); }; }; -// src/RootAstNodesBuilder.ts -var AttributeFactories = { - WHILE: (condition, attributeArguments) => new While(condition, attributeArguments), - UNTIL: (condition, attributeArguments) => new Until(condition, attributeArguments), - ENTRY: (functionName, attributeArguments) => new Entry(functionName, attributeArguments), - EXIT: (functionName, attributeArguments) => new Exit(functionName, attributeArguments), - STEP: (functionName, attributeArguments) => new Step(functionName, attributeArguments) -}; -var ASTNodeFactories = { - ROOT: () => ({ - type: "root", - attributes: [], - name: null, - children: [], - validate(depth) { - if (depth > 1) { - throw new Error("a root node cannot be the child of another node"); - } - if (this.children.length !== 1) { - throw new Error("a root node must have a single child"); - } - }, - createNodeInstance(namedRootNodeProvider, visitedBranches) { - return new Root( - this.attributes, - this.children[0].createNodeInstance(namedRootNodeProvider, visitedBranches.slice()) - ); - } - }), - BRANCH: () => ({ - type: "branch", - branchName: "", - validate() { - }, - createNodeInstance(namedRootNodeProvider, visitedBranches) { - const targetRootNode = namedRootNodeProvider(this.branchName); - if (visitedBranches.indexOf(this.branchName) !== -1) { - throw new Error(`circular dependency found in branch node references for branch '${this.branchName}'`); - } - if (targetRootNode) { - return targetRootNode.createNodeInstance(namedRootNodeProvider, visitedBranches.concat(this.branchName)).getChildren()[0]; - } else { - throw new Error(`branch references root node '${this.branchName}' which has not been defined`); - } - } - }), - SELECTOR: () => ({ - type: "selector", - attributes: [], - children: [], - validate() { - if (this.children.length < 1) { - throw new Error("a selector node must have at least a single child"); - } - }, - createNodeInstance(namedRootNodeProvider, visitedBranches) { - return new Selector( - this.attributes, - this.children.map((child) => child.createNodeInstance(namedRootNodeProvider, visitedBranches.slice())) - ); - } - }), - SEQUENCE: () => ({ - type: "sequence", - attributes: [], - children: [], - validate() { - if (this.children.length < 1) { - throw new Error("a sequence node must have at least a single child"); - } - }, - createNodeInstance(namedRootNodeProvider, visitedBranches) { - return new Sequence( - this.attributes, - this.children.map((child) => child.createNodeInstance(namedRootNodeProvider, visitedBranches.slice())) - ); - } - }), - PARALLEL: () => ({ - type: "parallel", - attributes: [], - children: [], - validate() { - if (this.children.length < 1) { - throw new Error("a parallel node must have at least a single child"); - } - }, - createNodeInstance(namedRootNodeProvider, visitedBranches) { - return new Parallel( - this.attributes, - this.children.map((child) => child.createNodeInstance(namedRootNodeProvider, visitedBranches.slice())) - ); - } - }), - LOTTO: () => ({ - type: "lotto", - attributes: [], - children: [], - tickets: [], - validate() { - if (this.children.length < 1) { - throw new Error("a lotto node must have at least a single child"); - } - }, - createNodeInstance(namedRootNodeProvider, visitedBranches) { - return new Lotto( - this.attributes, - this.tickets, - this.children.map((child) => child.createNodeInstance(namedRootNodeProvider, visitedBranches.slice())) - ); - } - }), - REPEAT: () => ({ - type: "repeat", - attributes: [], - iterations: null, - iterationsMin: null, - iterationsMax: null, - children: [], - validate() { - if (this.children.length !== 1) { - throw new Error("a repeat node must have a single child"); - } - if (this.iterations !== null) { - if (this.iterations < 0) { - throw new Error("a repeat node must have a positive number of iterations if defined"); - } - } else if (this.iterationsMin !== null && this.iterationsMax !== null) { - if (this.iterationsMin < 0 || this.iterationsMax < 0) { - throw new Error( - "a repeat node must have a positive minimum and maximum iteration count if defined" - ); - } - if (this.iterationsMin > this.iterationsMax) { - throw new Error( - "a repeat node must not have a minimum iteration count that exceeds the maximum iteration count" - ); - } - } else { - } - }, - createNodeInstance(namedRootNodeProvider, visitedBranches) { - return new Repeat( - this.attributes, - this.iterations, - this.iterationsMin, - this.iterationsMax, - this.children[0].createNodeInstance(namedRootNodeProvider, visitedBranches.slice()) - ); - } - }), - RETRY: () => ({ - type: "retry", - attributes: [], - attempts: null, - attemptsMin: null, - attemptsMax: null, - children: [], - validate() { - if (this.children.length !== 1) { - throw new Error("a retry node must have a single child"); - } - if (this.attempts !== null) { - if (this.attempts < 0) { - throw new Error("a retry node must have a positive number of attempts if defined"); - } - } else if (this.attemptsMin !== null && this.attemptsMax !== null) { - if (this.attemptsMin < 0 || this.attemptsMax < 0) { - throw new Error("a retry node must have a positive minimum and maximum attempt count if defined"); - } - if (this.attemptsMin > this.attemptsMax) { - throw new Error( - "a retry node must not have a minimum attempt count that exceeds the maximum attempt count" - ); - } - } else { - } - }, - createNodeInstance(namedRootNodeProvider, visitedBranches) { - return new Retry( - this.attributes, - this.attempts, - this.attemptsMin, - this.attemptsMax, - this.children[0].createNodeInstance(namedRootNodeProvider, visitedBranches.slice()) - ); - } - }), - FLIP: () => ({ - type: "flip", - attributes: [], - children: [], - validate() { - if (this.children.length !== 1) { - throw new Error("a flip node must have a single child"); - } - }, - createNodeInstance(namedRootNodeProvider, visitedBranches) { - return new Flip( - this.attributes, - this.children[0].createNodeInstance(namedRootNodeProvider, visitedBranches.slice()) - ); - } - }), - SUCCEED: () => ({ - type: "succeed", - attributes: [], - children: [], - validate() { - if (this.children.length !== 1) { - throw new Error("a succeed node must have a single child"); - } - }, - createNodeInstance(namedRootNodeProvider, visitedBranches) { - return new Succeed( - this.attributes, - this.children[0].createNodeInstance(namedRootNodeProvider, visitedBranches.slice()) - ); - } - }), - FAIL: () => ({ - type: "fail", - attributes: [], - children: [], - validate() { - if (this.children.length !== 1) { - throw new Error("a fail node must have a single child"); - } - }, - createNodeInstance(namedRootNodeProvider, visitedBranches) { - return new Fail( - this.attributes, - this.children[0].createNodeInstance(namedRootNodeProvider, visitedBranches.slice()) - ); - } - }), - WAIT: () => ({ - type: "wait", - attributes: [], - duration: null, - durationMin: null, - durationMax: null, - validate() { - if (this.duration !== null) { - if (this.duration < 0) { - throw new Error("a wait node must have a positive duration"); - } - } else if (this.durationMin !== null && this.durationMax !== null) { - if (this.durationMin < 0 || this.durationMax < 0) { - throw new Error("a wait node must have a positive minimum and maximum duration"); - } - if (this.durationMin > this.durationMax) { - throw new Error("a wait node must not have a minimum duration that exceeds the maximum duration"); - } - } else { - } - }, - createNodeInstance() { - return new Wait(this.attributes, this.duration, this.durationMin, this.durationMax); - } - }), - ACTION: () => ({ - type: "action", - attributes: [], - actionName: "", - actionArguments: [], - validate() { - }, - createNodeInstance() { - return new Action(this.attributes, this.actionName, this.actionArguments); - } - }), - CONDITION: () => ({ - type: "condition", - attributes: [], - conditionName: "", - conditionArguments: [], - validate() { - }, - createNodeInstance() { - return new Condition(this.attributes, this.conditionName, this.conditionArguments); - } - }) -}; -function buildRootASTNodes(definition) { - const { placeholders, processedDefinition } = substituteStringLiterals2(definition); - const tokens = parseTokensFromDefinition2(processedDefinition); - if (tokens.length < 3) { - throw new Error("invalid token count"); - } - if (tokens.filter((token) => token === "{").length !== tokens.filter((token) => token === "}").length) { - throw new Error("scope character mismatch"); - } - const stack = [[]]; - const rootScope = stack[0]; - while (tokens.length) { - const token = tokens.shift(); - const currentScope = stack[stack.length - 1]; - switch (token.toUpperCase()) { - case "ROOT": { - const node = ASTNodeFactories.ROOT(); - rootScope.push(node); - if (tokens[0] === "[") { - const rootArguments = getArguments(tokens, placeholders); - if (rootArguments.length === 1 && rootArguments[0].type === "identifier") { - node.name = rootArguments[0].value; - } else { - throw new Error("expected single root name argument"); - } - } - node.attributes = getAttributes(tokens, placeholders); - popAndCheck2(tokens, "{"); - stack.push(node.children); - break; - } - case "BRANCH": { - const node = ASTNodeFactories.BRANCH(); - currentScope.push(node); - if (tokens[0] !== "[") { - throw new Error("expected single branch name argument"); - } - const branchArguments = getArguments(tokens, placeholders); - if (branchArguments.length === 1 && branchArguments[0].type === "identifier") { - node.branchName = branchArguments[0].value; - } else { - throw new Error("expected single branch name argument"); - } - break; - } - case "SELECTOR": { - const node = ASTNodeFactories.SELECTOR(); - currentScope.push(node); - node.attributes = getAttributes(tokens, placeholders); - popAndCheck2(tokens, "{"); - stack.push(node.children); - break; - } - case "SEQUENCE": { - const node = ASTNodeFactories.SEQUENCE(); - currentScope.push(node); - node.attributes = getAttributes(tokens, placeholders); - popAndCheck2(tokens, "{"); - stack.push(node.children); - break; - } - case "PARALLEL": { - const node = ASTNodeFactories.PARALLEL(); - currentScope.push(node); - node.attributes = getAttributes(tokens, placeholders); - popAndCheck2(tokens, "{"); - stack.push(node.children); - break; - } - case "LOTTO": { - const node = ASTNodeFactories.LOTTO(); - currentScope.push(node); - if (tokens[0] === "[") { - node.tickets = getArguments( - tokens, - placeholders, - (arg) => arg.type === "number" && !!arg.isInteger, - "lotto node ticket counts must be integer values" - ).map((argument) => argument.value); - } - node.attributes = getAttributes(tokens, placeholders); - popAndCheck2(tokens, "{"); - stack.push(node.children); - break; - } - case "CONDITION": { - const node = ASTNodeFactories.CONDITION(); - currentScope.push(node); - if (tokens[0] !== "[") { - throw new Error("expected condition name identifier argument"); - } - const conditionArguments = getArguments(tokens, placeholders); - if (conditionArguments.length && conditionArguments[0].type === "identifier") { - node.conditionName = conditionArguments.shift().value; - } else { - throw new Error("expected condition name identifier argument"); - } - conditionArguments.filter((arg) => arg.type === "identifier").forEach((arg) => { - throw new Error( - "invalid condition node argument value '" + arg.value + "', must be string, number, boolean or null" - ); - }); - node.conditionArguments = conditionArguments; - node.attributes = getAttributes(tokens, placeholders); - break; - } - case "FLIP": { - const node = ASTNodeFactories.FLIP(); - currentScope.push(node); - node.attributes = getAttributes(tokens, placeholders); - popAndCheck2(tokens, "{"); - stack.push(node.children); - break; - } - case "SUCCEED": { - const node = ASTNodeFactories.SUCCEED(); - currentScope.push(node); - node.attributes = getAttributes(tokens, placeholders); - popAndCheck2(tokens, "{"); - stack.push(node.children); - break; - } - case "FAIL": { - const node = ASTNodeFactories.FAIL(); - currentScope.push(node); - node.attributes = getAttributes(tokens, placeholders); - popAndCheck2(tokens, "{"); - stack.push(node.children); - break; - } - case "WAIT": { - const node = ASTNodeFactories.WAIT(); - currentScope.push(node); - if (tokens[0] === "[") { - const nodeArguments = getArguments( - tokens, - placeholders, - (arg) => arg.type === "number" && !!arg.isInteger, - "wait node durations must be integer values" - ).map((argument) => argument.value); - if (nodeArguments.length === 1) { - node.duration = nodeArguments[0]; - } else if (nodeArguments.length === 2) { - node.durationMin = nodeArguments[0]; - node.durationMax = nodeArguments[1]; - } else if (nodeArguments.length > 2) { - throw new Error("invalid number of wait node duration arguments defined"); - } - } - node.attributes = getAttributes(tokens, placeholders); - break; - } - case "REPEAT": { - const node = ASTNodeFactories.REPEAT(); - currentScope.push(node); - if (tokens[0] === "[") { - const nodeArguments = getArguments( - tokens, - placeholders, - (arg) => arg.type === "number" && !!arg.isInteger, - "repeat node iteration counts must be integer values" - ).map((argument) => argument.value); - if (nodeArguments.length === 1) { - node.iterations = nodeArguments[0]; - } else if (nodeArguments.length === 2) { - node.iterationsMin = nodeArguments[0]; - node.iterationsMax = nodeArguments[1]; - } else { - throw new Error("invalid number of repeat node iteration count arguments defined"); - } - } - node.attributes = getAttributes(tokens, placeholders); - popAndCheck2(tokens, "{"); - stack.push(node.children); - break; - } - case "RETRY": { - const node = ASTNodeFactories.RETRY(); - currentScope.push(node); - if (tokens[0] === "[") { - const nodeArguments = getArguments( - tokens, - placeholders, - (arg) => arg.type === "number" && !!arg.isInteger, - "retry node attempt counts must be integer values" - ).map((argument) => argument.value); - if (nodeArguments.length === 1) { - node.attempts = nodeArguments[0]; - } else if (nodeArguments.length === 2) { - node.attemptsMin = nodeArguments[0]; - node.attemptsMax = nodeArguments[1]; - } else { - throw new Error("invalid number of retry node attempt count arguments defined"); - } - } - node.attributes = getAttributes(tokens, placeholders); - popAndCheck2(tokens, "{"); - stack.push(node.children); - break; - } - case "ACTION": { - const node = ASTNodeFactories.ACTION(); - currentScope.push(node); - if (tokens[0] !== "[") { - throw new Error("expected action name identifier argument"); - } - const actionArguments = getArguments(tokens, placeholders); - if (actionArguments.length && actionArguments[0].type === "identifier") { - node.actionName = actionArguments.shift().value; - } else { - throw new Error("expected action name identifier argument"); - } - actionArguments.filter((arg) => arg.type === "identifier").forEach((arg) => { - throw new Error( - "invalid action node argument value '" + arg.value + "', must be string, number, boolean or null" - ); - }); - node.actionArguments = actionArguments; - node.attributes = getAttributes(tokens, placeholders); - break; - } - case "}": { - stack.pop(); - break; - } - default: { - throw new Error(`unexpected token '${token}'`); - } - } +// src/BehaviourTreeBuilder.ts +var MAIN_ROOT_NODE_KEY = Symbol("__root__"); +function buildRootNode(definition) { + const rootNodeDefinitionMap = createRootNodeDefinitionMap(definition); + validateBranchSubtreeLinks(definition, true); + const rootNode = nodeFactory(rootNodeDefinitionMap[MAIN_ROOT_NODE_KEY]); + applyLeafNodeGuardPaths(rootNode); + return rootNode; +} +function nodeFactory(definition) { + const attributes = nodeAttributesFactory(definition); + switch (definition.type) { + case "root": + return new Root(attributes, nodeFactory(definition.child)); + default: + throw new Error(`unexpected node type of '${definition.type}'`); } - const validateASTNode = (node, depth) => { - node.validate(depth); - (node.children || []).forEach((child) => validateASTNode(child, depth + 1)); - }; - validateASTNode( - { - children: stack[0], - validate() { - if (this.children.length === 0) { - throw new Error("expected root node to have been defined"); - } - for (const definitionLevelNode of this.children) { - if (definitionLevelNode.type !== "root") { - throw new Error("expected root node at base of definition"); - } - } - if (this.children.filter((definitionLevelNode) => definitionLevelNode.name === null).length !== 1) { - throw new Error("expected single unnamed root node at base of definition to act as main root"); - } - const rootNodeNames = []; - for (const definitionLevelNode of this.children) { - if (rootNodeNames.indexOf(definitionLevelNode.name) !== -1) { - throw new Error(`multiple root nodes found with duplicate name '${definitionLevelNode.name}'`); - } else { - rootNodeNames.push(definitionLevelNode.name); - } - } - } - }, - 0 - ); - return stack[0]; } -function popAndCheck2(tokens, expected) { - const popped = tokens.shift(); - if (popped === void 0) { - throw new Error("unexpected end of definition"); +function nodeAttributesFactory(definition) { + const attributes = []; + if (definition.while) { + attributes.push(new While(definition.while.call, definition.while.args ?? [])); } - if (expected !== void 0) { - var tokenMatchesExpectation = [].concat(expected).some((item) => popped.toUpperCase() === item.toUpperCase()); - if (!tokenMatchesExpectation) { - const expectationString = [].concat(expected).map((item) => "'" + item + "'").join(" or "); - throw new Error(`unexpected token found. Expected '${expectationString}' but got '${popped}'`); - } + if (definition.until) { + attributes.push(new Until(definition.until.call, definition.until.args ?? [])); } - return popped; -} -function getArguments(tokens, stringArgumentPlaceholders, argumentValidator, validationFailedMessage) { - const closer = popAndCheck2(tokens, ["[", "("]) === "[" ? "]" : ")"; - const argumentListTokens = []; - const argumentList = []; - while (tokens.length && tokens[0] !== closer) { - argumentListTokens.push(tokens.shift()); + if (definition.entry) { + attributes.push(new Entry(definition.entry.call, definition.entry.args ?? [])); } - argumentListTokens.forEach((token, index) => { - const shouldBeArgumentToken = !(index & 1); - if (shouldBeArgumentToken) { - const argumentDefinition = getArgumentDefinition2(token, stringArgumentPlaceholders); - if (argumentValidator && !argumentValidator(argumentDefinition)) { - throw new Error(validationFailedMessage); - } - argumentList.push(argumentDefinition); - } else { - if (token !== ",") { - throw new Error(`invalid argument list, expected ',' or ']' but got '${token}'`); - } - } - }); - popAndCheck2(tokens, closer); - return argumentList; -} -function getArgumentDefinition2(token, stringArgumentPlaceholders) { - if (token === "null") { - return { - value: null, - type: "null" - }; + if (definition.step) { + attributes.push(new Step(definition.step.call, definition.step.args ?? [])); } - if (token === "true" || token === "false") { - return { - value: token === "true", - type: "boolean" - }; + if (definition.exit) { + attributes.push(new Exit(definition.exit.call, definition.exit.args ?? [])); } - if (!isNaN(token)) { - return { - value: parseFloat(token), - isInteger: parseFloat(token) === parseInt(token, 10), - type: "number" - }; + return attributes; +} +function createRootNodeDefinitionMap(definition) { + const rootNodeMap = {}; + for (const [name, rootNodeDefinition] of Object.entries(Lookup.getSubtrees())) { + rootNodeMap[name] = { ...rootNodeDefinition, id: name }; } - if (token.match(/^@@\d+@@$/g)) { - return { - value: stringArgumentPlaceholders[token].replace('\\"', '"'), - type: "string" - }; + for (const rootNodeDefinition of definition) { + rootNodeMap[rootNodeDefinition.id ?? MAIN_ROOT_NODE_KEY] = rootNodeDefinition; } - return { - value: token, - type: "identifier" - }; + return rootNodeMap; } -function getAttributes(tokens, stringArgumentPlaceholders) { - const attributes = []; - const attributesFound = []; - let attributeFactory = AttributeFactories[(tokens[0] || "").toUpperCase()]; - while (attributeFactory) { - if (attributesFound.indexOf(tokens[0].toUpperCase()) !== -1) { - throw new Error(`duplicate attribute '${tokens[0].toUpperCase()}' found for node`); - } - attributesFound.push(tokens.shift().toUpperCase()); - const attributeArguments = getArguments(tokens, stringArgumentPlaceholders); - if (attributeArguments.length === 0 || attributeArguments[0].type !== "identifier") { - throw new Error("expected agent function name identifier argument for attribute"); +function applyLeafNodeGuardPaths(root) { + const nodePaths = []; + const findLeafNodes = (path, node) => { + path = path.concat(node); + if (node.isLeafNode()) { + nodePaths.push(path); + } else { + node.getChildren().forEach((child) => findLeafNodes(path, child)); } - const attributeFunctionName = attributeArguments.shift(); - attributeArguments.filter((arg) => arg.type === "identifier").forEach((arg) => { - throw new Error( - "invalid attribute argument value '" + arg.value + "', must be string, number, boolean or null" + }; + findLeafNodes([], root); + nodePaths.forEach((path) => { + for (let depth = 0; depth < path.length; depth++) { + const currentNode = path[depth]; + if (currentNode.hasGuardPath()) { + continue; + } + const guardPath = new GuardPath( + path.slice(0, depth + 1).map((node) => ({ node, guards: node.getGuardAttributes() })).filter((details) => details.guards.length > 0) ); - }); - attributes.push(attributeFactory(attributeFunctionName.value, attributeArguments)); - attributeFactory = AttributeFactories[(tokens[0] || "").toUpperCase()]; - } - return attributes; -} -function substituteStringLiterals2(definition) { - const placeholders = {}; - const processedDefinition = definition.replace(/\"(\\.|[^"\\])*\"/g, (match) => { - var strippedMatch = match.substring(1, match.length - 1); - var placeholder = Object.keys(placeholders).find((key) => placeholders[key] === strippedMatch); - if (!placeholder) { - placeholder = `@@${Object.keys(placeholders).length}@@`; - placeholders[placeholder] = strippedMatch; + currentNode.setGuardPath(guardPath); } - return placeholder; }); - return { placeholders, processedDefinition }; -} -function parseTokensFromDefinition2(definition) { - definition = definition.replace(/\(/g, " ( "); - definition = definition.replace(/\)/g, " ) "); - definition = definition.replace(/\{/g, " { "); - definition = definition.replace(/\}/g, " } "); - definition = definition.replace(/\]/g, " ] "); - definition = definition.replace(/\[/g, " [ "); - definition = definition.replace(/\,/g, " , "); - return definition.replace(/\s+/g, " ").trim().split(" "); } // src/BehaviourTree.ts @@ -2557,13 +1226,17 @@ var BehaviourTree = class { constructor(definition, agent, options = {}) { this.agent = agent; this.options = options; - if (typeof definition !== "string") { - throw new Error("the tree definition must be a string"); + if (!definition) { + throw new Error("the tree definition must be a string ro"); } if (typeof agent !== "object" || agent === null) { throw new Error("the agent must be defined and not null"); } - this.rootNode = BehaviourTree._createRootNode(definition); + try { + this.rootNode = this._createRootNode(definition); + } catch (exception) { + throw new Error(`error building tree: ${exception.message}`); + } } rootNode; isRunning() { @@ -2610,19 +1283,39 @@ var BehaviourTree = class { static register(name, value) { if (typeof value === "function") { Lookup.setFunc(name, value); - } else if (typeof value === "string") { - let rootASTNodes; + return; + } + if (typeof value === "string") { + let rootNodeDefinitions; try { - rootASTNodes = buildRootASTNodes(value); + rootNodeDefinitions = convertMDSLToJSON(value); } catch (exception) { - throw new Error(`error registering definition: ${exception.message}`); + throw new Error(`error registering definition, invalid MDSL: ${exception.message}`); } - if (rootASTNodes.length != 1 || rootASTNodes[0].name !== null) { + if (rootNodeDefinitions.length != 1 || rootNodeDefinitions[0].id !== null) { throw new Error("error registering definition: expected a single unnamed root node"); } - Lookup.setSubtree(name, rootASTNodes[0]); + try { + const { succeeded, errorMessage } = validateJSONDefinition(rootNodeDefinitions[0]); + if (!succeeded) { + throw new Error(errorMessage); + } + } catch (exception) { + throw new Error(`error registering definition: ${exception.message}`); + } + Lookup.setSubtree(name, rootNodeDefinitions[0]); + } else if (typeof value === "object" && !Array.isArray(value)) { + try { + const { succeeded, errorMessage } = validateJSONDefinition(value); + if (!succeeded) { + throw new Error(errorMessage); + } + } catch (exception) { + throw new Error(`error registering definition: ${exception.message}`); + } + Lookup.setSubtree(name, value); } else { - throw new Error("unexpected value, expected string definition or function"); + throw new Error("unexpected value, expected string mdsl definition, root node json definition or function"); } } static unregister(name) { @@ -2631,51 +1324,18 @@ var BehaviourTree = class { static unregisterAll() { Lookup.empty(); } - static _createRootNode(definition) { - try { - } catch (exception) { - console.log(exception); - } - try { - const rootASTNodes = buildRootASTNodes(definition); - const mainRootNodeKey = Symbol("__root__"); - const rootNodeMap = {}; - for (const rootASTNode of rootASTNodes) { - rootNodeMap[rootASTNode.name === null ? mainRootNodeKey : rootASTNode.name] = rootASTNode; + _createRootNode(definition) { + let resolvedDefinition; + if (typeof definition === "string") { + try { + resolvedDefinition = convertMDSLToJSON(definition); + } catch (exception) { + throw new Error(`invalid mdsl definition: ${exception.message}`); } - const rootNode = rootNodeMap[mainRootNodeKey].createNodeInstance( - (name) => rootNodeMap[name] ? rootNodeMap[name] : Lookup.getSubtree(name), - [] - ); - BehaviourTree._applyLeafNodeGuardPaths(rootNode); - return rootNode; - } catch (exception) { - throw new Error(`error parsing tree: ${exception.message}`); + } else { + resolvedDefinition = definition; } - } - static _applyLeafNodeGuardPaths(rootNode) { - const nodePaths = []; - const findLeafNodes = (path, node) => { - path = path.concat(node); - if (node.isLeafNode()) { - nodePaths.push(path); - } else { - node.getChildren().forEach((child) => findLeafNodes(path, child)); - } - }; - findLeafNodes([], rootNode); - nodePaths.forEach((path) => { - for (let depth = 0; depth < path.length; depth++) { - const currentNode = path[depth]; - if (currentNode.hasGuardPath()) { - continue; - } - const guardPath = new GuardPath( - path.slice(0, depth + 1).map((node) => ({ node, guards: node.getGuardAttributes() })).filter((details) => details.guards.length > 0) - ); - currentNode.setGuardPath(guardPath); - } - }); + return buildRootNode(Array.isArray(resolvedDefinition) ? resolvedDefinition : [resolvedDefinition]); } }; // Annotate the CommonJS export names for ESM import in node: diff --git a/dist/index.js.map b/dist/index.js.map index 8ab89ad..3dd1e21 100644 --- a/dist/index.js.map +++ b/dist/index.js.map @@ -1,7 +1,7 @@ { "version": 3, - "sources": ["../node_modules/lotto-draw/dist/Participant.js", "../node_modules/lotto-draw/dist/Utilities.js", "../node_modules/lotto-draw/dist/Lotto.js", "../node_modules/lotto-draw/dist/createLotto.js", "../node_modules/lotto-draw/dist/index.js", "../src/index.ts", "../src/State.ts", "../src/BehaviourTreeDefinitionUtilities.ts", "../src/mdsl/MDSLUtilities.ts", "../src/mdsl/MDSLNodeArgumentParser.ts", "../src/mdsl/MDSLNodeAttributeParser.ts", "../src/mdsl/MDSLDefinitionParser.ts", "../src/BehaviourTreeDefinitionValidator.ts", "../src/attributes/guards/GuardUnsatisifedException.ts", "../src/attributes/guards/GuardPath.ts", "../src/nodes/Node.ts", "../src/nodes/leaf/Leaf.ts", "../src/Lookup.ts", "../src/nodes/leaf/Action.ts", "../src/nodes/leaf/Condition.ts", "../src/nodes/leaf/Wait.ts", "../src/nodes/decorator/Decorator.ts", "../src/nodes/decorator/Root.ts", "../src/nodes/decorator/Repeat.ts", "../src/nodes/decorator/Retry.ts", "../src/nodes/decorator/Flip.ts", "../src/nodes/decorator/Succeed.ts", "../src/nodes/decorator/Fail.ts", "../src/nodes/composite/Lotto.ts", "../src/nodes/composite/Composite.ts", "../src/nodes/composite/Selector.ts", "../src/nodes/composite/Sequence.ts", "../src/nodes/composite/Parallel.ts", "../src/attributes/Attribute.ts", "../src/attributes/guards/Guard.ts", "../src/attributes/guards/While.ts", "../src/attributes/guards/Until.ts", "../src/attributes/callbacks/Callback.ts", "../src/attributes/callbacks/Entry.ts", "../src/attributes/callbacks/Exit.ts", "../src/attributes/callbacks/Step.ts", "../src/RootAstNodesBuilder.ts", "../src/BehaviourTree.ts"], - "sourcesContent": ["\"use strict\";\r\nObject.defineProperty(exports, \"__esModule\", { value: true });\r\nexports.Participant = void 0;\r\n/**\r\n * A participant that holds a number of tickets.\r\n */\r\nvar Participant = /** @class */ (function () {\r\n /**\r\n * Creates an instance of the Participant class.\r\n * @param participant The actual participant.\r\n * @param tickets The number of tickets held by the participant.\r\n */\r\n function Participant(participant, tickets) {\r\n if (tickets === void 0) { tickets = 1; }\r\n this._participant = participant;\r\n this._tickets = tickets;\r\n }\r\n Object.defineProperty(Participant.prototype, \"participant\", {\r\n /** Gets the actual participant. */\r\n get: function () {\r\n return this._participant;\r\n },\r\n enumerable: false,\r\n configurable: true\r\n });\r\n Object.defineProperty(Participant.prototype, \"tickets\", {\r\n /** Gets or sets the number of tickets held by the participant. */\r\n get: function () {\r\n return this._tickets;\r\n },\r\n set: function (value) {\r\n this._tickets = value;\r\n },\r\n enumerable: false,\r\n configurable: true\r\n });\r\n return Participant;\r\n}());\r\nexports.Participant = Participant;\r\n", "\"use strict\";\r\nObject.defineProperty(exports, \"__esModule\", { value: true });\r\nexports.isNaturalNumber = exports.isNullOrUndefined = void 0;\r\n/**\r\n * Gets whether the value provided is null or undefined.\r\n * @param value The value to check.\r\n * @returns Whether the value provided is null or undefined.\r\n */\r\nfunction isNullOrUndefined(value) {\r\n return value === null || value === undefined;\r\n}\r\nexports.isNullOrUndefined = isNullOrUndefined;\r\n/**\r\n * Gets whether the value provided is a natural number.\r\n * @param value The value to check.\r\n * @returns Whether the value provided is a natural number.\r\n */\r\nfunction isNaturalNumber(value) {\r\n return typeof value === \"number\" && value >= 1 && Math.floor(value) === value;\r\n}\r\nexports.isNaturalNumber = isNaturalNumber;\r\n", "\"use strict\";\r\nObject.defineProperty(exports, \"__esModule\", { value: true });\r\nexports.Lotto = void 0;\r\nvar Participant_1 = require(\"./Participant\");\r\nvar Utilities_1 = require(\"./Utilities\");\r\n/**\r\n * Represents a lotto consisting of a number of pickable ticket-holding participants.\r\n */\r\nvar Lotto = /** @class */ (function () {\r\n /**\r\n * Creates a new instance of Lotto.\r\n * @param customRandom The custom RNG to use in place of Math.random().\r\n */\r\n function Lotto(customRandom) {\r\n /** The array of participants that are holding tickets in the lotto. */\r\n this._participants = [];\r\n this._customRandom = customRandom;\r\n }\r\n /**\r\n * Adds a participant with the specified number of tickets, or adds to the participant ticket count if the participant already holds tickets.\r\n * @param participant The participant to add or to increase the ticket count for if they already hold tickets.\r\n * @param tickets The number of tickets, defaults to 1.\r\n * @returns The Lotto instance.\r\n */\r\n Lotto.prototype.add = function (participant, tickets) {\r\n if (tickets === void 0) { tickets = 1; }\r\n // Check that we have a valid ticket count.\r\n if (!(0, Utilities_1.isNaturalNumber)(tickets)) {\r\n throw new Error(\"tickets value must be a natural number\");\r\n }\r\n // Check whether this participant has already been added.\r\n var existingParticipant = this._participants.find(function (part) { return part.participant === participant; });\r\n if (existingParticipant) {\r\n // The participant has already been added to the lotto so just add to their ticket count.\r\n existingParticipant.tickets += tickets;\r\n }\r\n else {\r\n // The participant is not part of the lotto so we should add them.\r\n this._participants.push(new Participant_1.Participant(participant, tickets));\r\n }\r\n return this;\r\n };\r\n /**\r\n * Removes the specified number of tickets for the given participant from the draw, or all tickets if a ticket number is not defined.\r\n * @param participant The participant to remove tickets for.\r\n * @param tickets The number of tickets to remove, or undefined if all tickets are to be removed.\r\n * @returns The Lotto instance.\r\n */\r\n Lotto.prototype.remove = function (participant, tickets) {\r\n // Attempt to get the existing participant.\r\n var existingParticipant = this._participants.find(function (part) { return part.participant === participant; });\r\n // There is nothing to do if the specified participant isn't even part of the lotto.\r\n if (!existingParticipant) {\r\n return this;\r\n }\r\n // Check whether a tickets value was given.\r\n if (tickets !== undefined) {\r\n // Check that we have a valid ticket count.\r\n if (!(0, Utilities_1.isNaturalNumber)(tickets)) {\r\n throw new Error(\"tickets value must be a natural number\");\r\n }\r\n existingParticipant.tickets -= tickets;\r\n // If the participant no longer holds any tickets then they should be removed.\r\n if (existingParticipant.tickets < 1) {\r\n this._participants = this._participants.filter(function (part) { return part !== existingParticipant; });\r\n }\r\n }\r\n else {\r\n // We are removing all tickets for the participant so just remove them from the lotto.\r\n this._participants = this._participants.filter(function (part) { return part !== existingParticipant; });\r\n }\r\n return this;\r\n };\r\n /**\r\n * Draw a winning ticket and return the participant that holds the ticket.\r\n * @param options The draw options.\r\n * @returns The participant that holds the winning ticket.\r\n */\r\n Lotto.prototype.draw = function (options) {\r\n if (options === void 0) { options = {}; }\r\n // If we have no participants then just return null.\r\n if (this._participants.length === 0) {\r\n return null;\r\n }\r\n var redrawable = (0, Utilities_1.isNullOrUndefined)(options.redrawable) ? true : options.redrawable;\r\n var pickable = [];\r\n this._participants.forEach(function (_a) {\r\n var participant = _a.participant, tickets = _a.tickets;\r\n for (var ticketCount = 0; ticketCount < tickets; ticketCount++) {\r\n pickable.push(participant);\r\n }\r\n });\r\n var random;\r\n // We need a random floating-point number between 0 (inclusive) and 1 to scale up to pick our winner.\r\n // If a custom random function exists then we should use that or fall back to Math.random().\r\n if (this._customRandom) {\r\n // Call our custom random function to get a random floating-point number.\r\n random = this._customRandom();\r\n // Verify that the result of calling our custom random function is a number between 0 (inclusive) and 1.\r\n if (typeof random !== \"number\" || random < 0 || random >= 1) {\r\n throw new Error(\"the 'random' function provided did not return a number between 0 (inclusive) and 1\");\r\n }\r\n }\r\n else {\r\n // No custom random function was defined so just use good ol' Math.random().\r\n random = Math.random();\r\n }\r\n // Pick a winning participant.\r\n var winner = pickable[Math.floor(random * pickable.length)];\r\n // If the ticket isn't redrawable then we should remove a ticket from the winning participants ticket count.\r\n if (!redrawable) {\r\n this.remove(winner, 1);\r\n }\r\n // Return the winning participant.\r\n return winner;\r\n };\r\n /**\r\n * Draws multiple winning tickets and return an array of the participants that hold the winning tickets.\r\n * @param tickets The number of winning tickets to draw.\r\n * @param options The draw multiple options.\r\n * @returns An array of the participants that hold the winning tickets.\r\n */\r\n Lotto.prototype.drawMultiple = function (tickets, options) {\r\n if (options === void 0) { options = {}; }\r\n var uniqueResults = (0, Utilities_1.isNullOrUndefined)(options.unique) ? false : options.unique;\r\n // Handle cases where the user has asked for zero tickets (no idea why they would do this be we should trust them).\r\n if (tickets === 0) {\r\n return [];\r\n }\r\n // Now that we know out tickets value is not zero we should check that it is a valid natural number.\r\n if (!(0, Utilities_1.isNaturalNumber)(tickets)) {\r\n throw new Error(\"tickets value must be a natural number\");\r\n }\r\n var result = [];\r\n // Keep drawing tickets until we either reach the number of required tickets or we simply run out of tickets to draw.\r\n // We can run out of tickets to draw if 'options.redrawable' is explicity 'false' or we just had no participants when 'drawMultiple' was called.\r\n while (result.length < tickets && this._participants.length > 0) {\r\n result.push(this.draw(options));\r\n }\r\n // If the 'unique' draw option is set then we need to remove duplicates from the result list.\r\n if (uniqueResults) {\r\n // Create an array to store our unique results.\r\n var unique = [];\r\n // Iterate over all of our participants (with potential duplicates) and populate our array of unique values.\r\n for (var _i = 0, result_1 = result; _i < result_1.length; _i++) {\r\n var participant = result_1[_i];\r\n if (unique.indexOf(participant) === -1) {\r\n unique.push(participant);\r\n }\r\n }\r\n result = unique;\r\n }\r\n return result;\r\n };\r\n return Lotto;\r\n}());\r\nexports.Lotto = Lotto;\r\n", "\"use strict\";\r\nObject.defineProperty(exports, \"__esModule\", { value: true });\r\nexports.createLotto = void 0;\r\nvar Lotto_1 = require(\"./Lotto\");\r\n/**\r\n * A function that creates and returns a Lotto instance.\r\n * @param participantsOrOptions An array of initial participants or options relating to the creation of a Lotto instance.\r\n * @returns A new Lotto instance.\r\n */\r\nfunction createLotto(participantsOrOptions) {\r\n // If no initial participants or lotto options were provided as an argument then we can just return a new lotto instance now.\r\n if (!participantsOrOptions) {\r\n return new Lotto_1.Lotto();\r\n }\r\n // Check whether we were provided with an array of initial participants or a lotto options object.\r\n if (Array.isArray(participantsOrOptions)) {\r\n // We are dealing with a pre-defined array of participants.\r\n var participants = participantsOrOptions;\r\n var lotto_1 = new Lotto_1.Lotto();\r\n // If the lotto participants have been defined upfront then we will need to add them all to our lotto instance now.\r\n participants.forEach(function (_a) {\r\n var participant = _a[0], tokens = _a[1];\r\n return lotto_1.add(participant, tokens);\r\n });\r\n // Return the Lotto instance.\r\n return lotto_1;\r\n }\r\n else {\r\n // We are dealing with some lotto options.\r\n var random = participantsOrOptions.random, participants = participantsOrOptions.participants;\r\n // Create a Lotto instance passing the custom RNG function to use in place of Math.random() (which could be undefined).\r\n var lotto_2 = new Lotto_1.Lotto(random);\r\n // If the lotto participants have been defined upfront as part of the options then we will need to add them all to our lotto instance now.\r\n if (participants) {\r\n participants.forEach(function (_a) {\r\n var participant = _a[0], tokens = _a[1];\r\n return lotto_2.add(participant, tokens);\r\n });\r\n }\r\n // Return the Lotto instance.\r\n return lotto_2;\r\n }\r\n}\r\nexports.createLotto = createLotto;\r\n", "\"use strict\";\r\nObject.defineProperty(exports, \"__esModule\", { value: true });\r\nvar createLotto_1 = require(\"./createLotto\");\r\nexports.default = createLotto_1.createLotto;\r\n", "import State from \"./State\";\nimport { validateDefinition } from \"./BehaviourTreeDefinitionValidator\";\nimport { convertMDSLToJSON } from \"./mdsl/MDSLDefinitionParser\";\nimport { BehaviourTree, FlattenedTreeNode } from \"./BehaviourTree\";\n\nexport { BehaviourTree, State, convertMDSLToJSON, validateDefinition };\nexport type { FlattenedTreeNode };\n", "/**\n * Enumeration of node state types.\n */\nexport enum State {\n READY = \"mistreevous.ready\",\n RUNNING = \"mistreevous.running\",\n SUCCEEDED = \"mistreevous.succeeded\",\n FAILED = \"mistreevous.failed\"\n}\n\nexport { State as default };\n\nexport type CompleteState = State.SUCCEEDED | State.FAILED;\nexport type AnyState = State.READY | State.RUNNING | CompleteState;\n", "import {\n NodeDefinition,\n RootNodeDefinition,\n DecoratorNodeDefinition,\n CompositeNodeDefinition,\n AnyNode,\n BranchNodeDefinition\n} from \"./BehaviourTreeDefinition\";\n\n/**\n * A type guard function that returns true if the specified node satisfies the RootNodeDefinition type.\n * @param node The node.\n * @returns A value of true if the specified node satisfies the RootNodeDefinition type.\n */\nexport function isRootNode(node: NodeDefinition): node is RootNodeDefinition {\n return node.type === \"root\";\n}\n\n/**\n * A type guard function that returns true if the specified node satisfies the BranchNodeDefinition type.\n * @param node The node.\n * @returns A value of true if the specified node satisfies the BranchNodeDefinition type.\n */\nexport function isBranchNode(node: NodeDefinition): node is BranchNodeDefinition {\n return node.type === \"branch\";\n}\n\n/**\n * A type guard function that returns true if the specified node satisfies the NodeDefinition type.\n * @param node The node.\n * @returns A value of true if the specified node satisfies the NodeDefinition type.\n */\nexport function isLeafNode(node: NodeDefinition): node is NodeDefinition {\n return [\"branch\", \"action\", \"condition\", \"wait\"].includes(node.type);\n}\n\n/**\n * A type guard function that returns true if the specified node satisfies the DecoratorNodeDefinition type.\n * @param node The node.\n * @returns A value of true if the specified node satisfies the DecoratorNodeDefinition type.\n */\nexport function isDecoratorNode(node: NodeDefinition): node is DecoratorNodeDefinition {\n return [\"root\", \"repeat\", \"retry\", \"flip\", \"succeed\", \"fail\"].includes(node.type);\n}\n\n/**\n * A type guard function that returns true if the specified node satisfies the CompositeNodeDefinition type.\n * @param node The node.\n * @returns A value of true if the specified node satisfies the CompositeNodeDefinition type.\n */\nexport function isCompositeNode(node: NodeDefinition): node is CompositeNodeDefinition {\n return [\"sequence\", \"selector\", \"lotto\", \"parallel\"].includes(node.type);\n}\n\n/**\n * Flatten a node definition into an array of all of its nested node definitions.\n * @param nodeDefinition The node definition to flatten.\n * @returns An array of all of nested node definitions.\n */\nexport function flattenDefinition(nodeDefinition: AnyNode): AnyNode[] {\n const nodes: AnyNode[] = [];\n\n const processNode = (currentNodeDefinition: AnyNode) => {\n nodes.push(currentNodeDefinition);\n\n if (isCompositeNode(currentNodeDefinition)) {\n currentNodeDefinition.children.forEach(processNode);\n } else if (isDecoratorNode(currentNodeDefinition)) {\n processNode(currentNodeDefinition.child);\n }\n };\n\n processNode(nodeDefinition);\n\n return nodes;\n}\n\n/**\n * Determines whether the passed value is an integer.\n * @param value The value to check.\n * @returns Whether the passed value is an integer.\n */\nexport function isInteger(value: unknown): boolean {\n return typeof value === \"number\" && Math.floor(value) === value;\n}\n", "/**\n * A type defining an object that holds a reference to substitued string literals parsed from the definition.\n */\nexport type StringLiteralPlaceholders = { [key: string]: string };\n\n/**\n * Pop the next raw token from the specified array of tokens and throw an error if it wasn't the expected one.\n * @param tokens The array of tokens.\n * @param expected An optional string or array or items, one of which must match the next popped token.\n * @returns The popped token.\n */\nexport function popAndCheck(tokens: string[], expected?: string | string[]): string {\n // Get and remove the next token.\n const popped = tokens.shift();\n\n // We were expecting another token but there aren't any.\n if (popped === undefined) {\n throw new Error(\"unexpected end of definition\");\n }\n\n // Do we have an expected token/tokens array?\n if (expected != undefined) {\n // Get an array of expected values, if the popped token matches any then we are all good.\n const expectedValues = typeof expected === \"string\" ? [expected] : expected;\n\n // Check whether the popped token matches at least one of our expected items.\n var tokenMatchesExpectation = expectedValues.some((item) => popped.toUpperCase() === item.toUpperCase());\n\n // Throw an error if the popped token didn't match any of our expected items.\n if (!tokenMatchesExpectation) {\n const expectationString = expectedValues.map((item) => \"'\" + item + \"'\").join(\" or \");\n throw new Error(\"unexpected token found. Expected \" + expectationString + \" but got '\" + popped + \"'\");\n }\n }\n\n // Return the popped token.\n return popped;\n}\n\n/**\n * Swaps out any node/attribute argument string literals with placeholders.\n * @param definition The definition.\n * @returns An object containing a mapping of placeholders to original string values as well as the processed definition string.\n */\nexport function substituteStringLiterals(definition: string): {\n placeholders: StringLiteralPlaceholders;\n processedDefinition: string;\n} {\n // Create an object to hold the mapping of placeholders to original string values.\n const placeholders: StringLiteralPlaceholders = {};\n\n // Replace any string literals wrapped with double quotes in our definition with placeholders to be processed later.\n const processedDefinition = definition.replace(/\\\"(\\\\.|[^\"\\\\])*\\\"/g, (match) => {\n var strippedMatch = match.substring(1, match.length - 1);\n var placeholder = Object.keys(placeholders).find((key) => placeholders[key] === strippedMatch);\n\n // If we have no existing string literal match then create a new placeholder.\n if (!placeholder) {\n placeholder = `@@${Object.keys(placeholders).length}@@`;\n placeholders[placeholder] = strippedMatch;\n }\n\n return placeholder;\n });\n\n return { placeholders, processedDefinition };\n}\n\n/**\n * Parse the tree definition into an array of raw tokens.\n * @param definition The definition.\n * @returns An array of tokens parsed from the definition.\n */\nexport function parseTokensFromDefinition(definition: string): string[] {\n // Add some space around various important characters so that they can be plucked out easier as individual tokens.\n definition = definition.replace(/\\(/g, \" ( \");\n definition = definition.replace(/\\)/g, \" ) \");\n definition = definition.replace(/\\{/g, \" { \");\n definition = definition.replace(/\\}/g, \" } \");\n definition = definition.replace(/\\]/g, \" ] \");\n definition = definition.replace(/\\[/g, \" [ \");\n definition = definition.replace(/\\,/g, \" , \");\n\n // Split the definition into raw token form and return it.\n return definition.replace(/\\s+/g, \" \").trim().split(\" \");\n}\n", "import { StringLiteralPlaceholders, popAndCheck } from \"./MDSLUtilities\";\n\nexport type Argument = {\n /** The argument value. */\n value: T;\n /** The argument type, used for validation. */\n type: string;\n};\n\nexport type NullArgument = Argument & {\n type: \"null\";\n};\n\nexport type BooleanArgument = Argument & {\n type: \"boolean\";\n};\n\nexport type NumberArgument = Argument & {\n type: \"number\";\n isInteger: boolean; // Used for validation.\n};\n\nexport type StringPlaceholderArgument = Argument & {\n type: \"string\";\n};\n\nexport type IdentifierArgument = Argument & {\n type: \"identifier\";\n};\n\nexport type AnyArgument =\n | NullArgument\n | BooleanArgument\n | NumberArgument\n | StringPlaceholderArgument\n | IdentifierArgument;\n\n/**\n * Parse an array of argument definitions from the specified tokens array.\n * @param tokens The array tokens to parse the argument definitions from.\n * @param stringArgumentPlaceholders The mapping of string literal node argument placeholders to original values.\n * @param argumentValidator The argument validator function.\n * @param validationFailedMessage The exception message to throw if argument validation fails.\n * @returns An array of argument definitions parsed from the specified tokens array.\n */\nexport function parseArgumentTokens(\n tokens: string[],\n stringArgumentPlaceholders: StringLiteralPlaceholders\n): AnyArgument[] {\n const argumentList: AnyArgument[] = [];\n\n // If the next token is not a '[' or '(' then we have no arguments to parse.\n if (![\"[\", \"(\"].includes(tokens[0])) {\n return argumentList;\n }\n\n // Any lists of arguments will always be wrapped in '[]' for node arguments or '()' for attribute arguments.\n // We are looking for a '[' or '(' opener that wraps the argument tokens and the relevant closer.\n const closingToken = popAndCheck(tokens, [\"[\", \"(\"]) === \"[\" ? \"]\" : \")\";\n\n const argumentListTokens: string[] = [];\n\n // Grab all tokens between the '[' and ']' or '(' and ')'.\n while (tokens.length && tokens[0] !== closingToken) {\n // The next token is part of our arguments list.\n argumentListTokens.push(tokens.shift()!);\n }\n\n // Validate the order of the argument tokens. Each token must either be a ',' or a single argument that satisfies the validator.\n argumentListTokens.forEach((token, index) => {\n // Get whether this token should be an actual argument.\n const shouldBeArgumentToken = !(index & 1);\n\n // If the current token should be an actual argument then validate it, otherwise it should be a ',' token.\n if (shouldBeArgumentToken) {\n // Get the argument definition.\n const argumentDefinition = getArgumentDefinition(token, stringArgumentPlaceholders);\n\n // This is a valid argument!\n argumentList.push(argumentDefinition);\n } else {\n // The current token should be a ',' token.\n if (token !== \",\") {\n throw new Error(`invalid argument list, expected ',' or ']' but got '${token}'`);\n }\n }\n });\n\n // The arguments list should terminate with a ']' or ')' token, depending on the opener.\n popAndCheck(tokens, closingToken);\n\n // Return the arguments.\n return argumentList;\n}\n\n/**\n * Gets an argument value definition.\n * @param token The argument token.\n * @param stringArgumentPlaceholders The mapping of string literal node argument placeholders to original values.\n * @returns An argument value definition.\n */\nfunction getArgumentDefinition(token: string, stringArgumentPlaceholders: StringLiteralPlaceholders): AnyArgument {\n // Check whether the token represents a null value.\n if (token === \"null\") {\n return {\n value: null,\n type: \"null\"\n } as NullArgument;\n }\n\n // Check whether the token represents a boolean value.\n if (token === \"true\" || token === \"false\") {\n return {\n value: token === \"true\",\n type: \"boolean\"\n } as BooleanArgument;\n }\n\n // Check whether the token represents a number value.\n // TODO: Relies on broken isNaN - see MDN.\n // if (!Number.isNaN(token)) {\n if (!isNaN(token as any)) {\n return {\n value: parseFloat(token),\n isInteger: parseFloat(token) === parseInt(token, 10),\n type: \"number\"\n } as NumberArgument;\n }\n\n // Check whether the token is a placeholder (e.g. @@0@@) representing a string literal.\n if (token.match(/^@@\\d+@@$/g)) {\n return {\n value: stringArgumentPlaceholders[token].replace('\\\\\"', '\"'),\n type: \"string\"\n } as StringPlaceholderArgument;\n }\n\n // The only remaining option is that the argument value is an identifier.\n return {\n value: token,\n type: \"identifier\"\n } as IdentifierArgument;\n}\n", "import { NodeAttributeDefinition } from \"../BehaviourTreeDefinition\";\nimport { parseArgumentTokens } from \"./MDSLNodeArgumentParser\";\nimport { StringLiteralPlaceholders } from \"./MDSLUtilities\";\n\n/**\n * A type defining the attribute definitions of a node.\n */\ntype NodeAttributes = {\n while?: NodeAttributeDefinition;\n until?: NodeAttributeDefinition;\n entry?: NodeAttributeDefinition;\n exit?: NodeAttributeDefinition;\n step?: NodeAttributeDefinition;\n};\n\n/**\n * Parse any node attribute definitions from the specified tokens array.\n * @param tokens The array of remaining tokens.\n * @param stringArgumentPlaceholders The mapping of string literal node argument placeholders to original values.\n * @returns An object of attribute definitions defined by any directly following tokens.\n */\nexport function parseAttributeTokens(\n tokens: string[],\n stringArgumentPlaceholders: StringLiteralPlaceholders\n): NodeAttributes {\n const nodeAttributeNames: (keyof NodeAttributes)[] = [\"while\", \"until\", \"entry\", \"exit\", \"step\"];\n\n // Create an object to hold any attributes found.\n const attributes: NodeAttributes = {};\n\n // Try to get the name of the attribute for the next token.\n let nextAttributeName = tokens[0]?.toLowerCase() as keyof NodeAttributes;\n\n // Pull attribute tokens as well as their arguments off of the tokens stack until we have no more.\n while (nodeAttributeNames.includes(nextAttributeName)) {\n // Check to make sure that we have not already created an attribute definition of this type.\n if (attributes[nextAttributeName]) {\n throw new Error(`duplicate attribute '${tokens[0].toUpperCase()}' found for node`);\n }\n\n // Remove the attribute name token from the array of tokens.\n tokens.shift();\n\n // Grab the attribute arguments, assuming the first to be an identifier.\n const [attributeCallIdentifier, ...attributeArguments] = parseArgumentTokens(\n tokens,\n stringArgumentPlaceholders\n );\n\n // The first attribute argument has to be an identifer, this will reference an agent function.\n if (attributeCallIdentifier?.type !== \"identifier\") {\n throw new Error(\"expected agent function name identifier argument for attribute\");\n }\n\n // Any attribute arguments (other than the expected call identifier) must have a type of string, number, boolean or null.\n attributeArguments\n .filter((arg) => arg.type === \"identifier\")\n .forEach((arg) => {\n throw new Error(\n `invalid attribute argument value '${arg.value}', must be string, number, boolean or null`\n );\n });\n\n // Create the attribute definition and add it to the object of attribute definitions found.\n attributes[nextAttributeName] = {\n call: attributeCallIdentifier.value,\n args: attributeArguments.map(({ value }) => value)\n };\n\n // Try to get the next attribute name token, as there could be multiple.\n nextAttributeName = tokens[0]?.toLowerCase() as keyof NodeAttributes;\n }\n\n return attributes;\n}\n", "import {\n ActionNodeDefinition,\n AnyChildNode,\n AnyNode,\n BranchNodeDefinition,\n ConditionNodeDefinition,\n FailNodeDefinition,\n FlipNodeDefinition,\n LottoNodeDefinition,\n ParallelNodeDefinition,\n RepeatNodeDefinition,\n RetryNodeDefinition,\n RootNodeDefinition,\n SelectorNodeDefinition,\n SequenceNodeDefinition,\n SucceedNodeDefinition,\n WaitNodeDefinition\n} from \"../BehaviourTreeDefinition\";\nimport { isCompositeNode, isDecoratorNode, isLeafNode, isRootNode } from \"../BehaviourTreeDefinitionUtilities\";\nimport { parseArgumentTokens } from \"./MDSLNodeArgumentParser\";\nimport { parseAttributeTokens } from \"./MDSLNodeAttributeParser\";\nimport {\n StringLiteralPlaceholders,\n parseTokensFromDefinition,\n popAndCheck,\n substituteStringLiterals\n} from \"./MDSLUtilities\";\n\n/**\n * Convert the MDSL tree definition string into an equivalent JSON definition.\n * @param definition The tree definition string as MDSL.\n * @returns The root node JSON definitions.\n */\nexport function convertMDSLToJSON(definition: string): RootNodeDefinition[] {\n // Swap out any node/attribute argument string literals with a placeholder and get a mapping of placeholders to original values as well as the processed definition.\n const { placeholders, processedDefinition } = substituteStringLiterals(definition);\n\n // Parse our definition definition string into an array of raw tokens.\n const tokens = parseTokensFromDefinition(processedDefinition);\n\n return convertTokensToJSONDefinition(tokens, placeholders);\n}\n\n/**\n * Converts the specified tree definition tokens into a JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The root node JSON definitions.\n */\nfunction convertTokensToJSONDefinition(\n tokens: string[],\n stringLiteralPlaceholders: StringLiteralPlaceholders\n): RootNodeDefinition[] {\n // There must be at least 3 tokens for the tree definition to be valid. 'ROOT', '{' and '}'.\n if (tokens.length < 3) {\n throw new Error(\"invalid token count\");\n }\n\n // We should have a matching number of '{' and '}' tokens. If not, then there are scopes that have not been properly closed.\n if (tokens.filter((token) => token === \"{\").length !== tokens.filter((token) => token === \"}\").length) {\n throw new Error(\"scope character mismatch\");\n }\n\n // Create an array of tree stack arrays where root nodes will always be at the botton and the current composite/decorator node at the top.\n // There should be an element in this array for every root node defined and every element should be an array with a root note as the first element.\n // E.g. A definition with two root nodes defined:\n // [\n // [root, lotto, sequence],\n // [root, selector]\n // ]\n const treeStacks: [Partial, ...Partial[]][] = [];\n\n // Create an array of all root node definitions that we create.\n const rootNodes: Partial[] = [];\n\n // A helper function used to push node definitions onto the tree stack.\n const pushNode = (node: AnyNode) => {\n // If the node is a root node then we need to create a new tree stack array with the root node at the root.\n if (isRootNode(node)) {\n // Add the root node definition to our array of all parsed root node definitions.\n rootNodes.push(node);\n\n // Add the root node definition to the root of a new tree stack.\n treeStacks.push([node]);\n\n return;\n }\n\n // All non-root nodes should be pushed after their root nodes so handle cases\n // where we may not have any tree stacks or our top-most tree stack is empty.\n if (!treeStacks.length || !treeStacks[treeStacks.length - 1].length) {\n throw new Error(\"expected root node at base of definition\");\n }\n\n // Get the current tree stack that we are populating.\n const topTreeStack = treeStacks[treeStacks.length - 1];\n\n // Get the top-most node in the current tree stack, this will be a composite/decorator node\n // for which we will populate its children array if composite or setting its child if a decorator.\n const topTreeStackTopNode = topTreeStack[topTreeStack.length - 1] as AnyNode;\n\n // If the top-most node in the current root stack is a composite or decorator\n // node then the current node should be added as a child of the top-most node.\n if (isCompositeNode(topTreeStackTopNode)) {\n topTreeStackTopNode.children = topTreeStackTopNode.children || [];\n topTreeStackTopNode.children.push(node);\n } else if (isDecoratorNode(topTreeStackTopNode)) {\n // If the top node already has a child node set then throw an error as a decorator should only have a single child.\n if (topTreeStackTopNode.child) {\n throw new Error(\"a decorator node must only have a single child node\");\n }\n\n topTreeStackTopNode.child = node;\n }\n\n // If the node we are adding is also a composite or decorator node, then we should push it\n // onto the current tree stack, as subsequent nodes will be added as its child/children.\n if (!isLeafNode(node)) {\n topTreeStack.push(node);\n }\n };\n\n // A helper function used to pop node definitions off of the stack.\n const popNode = () => {\n // Get the current tree stack that we are populating.\n const topTreeStack = treeStacks[treeStacks.length - 1];\n\n // Pop the top-most node in the current tree stack if there is one.\n if (topTreeStack.length) {\n topTreeStack.pop();\n }\n\n // We don't want any empty tree stacks in our stack of tree stacks.\n if (!topTreeStack.length) {\n treeStacks.pop();\n }\n };\n\n // We should keep processing the raw tokens until we run out of them.\n while (tokens.length) {\n // Grab the next token.\n const token = tokens.shift()!;\n\n // How we create the next node depends on the current raw token value.\n switch (token.toUpperCase()) {\n case \"ROOT\": {\n pushNode(createRootNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"SUCCEED\": {\n pushNode(createSucceedNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"FAIL\": {\n pushNode(createFailNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"FLIP\": {\n pushNode(createFlipNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"REPEAT\": {\n pushNode(createRepeatNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"RETRY\": {\n pushNode(createRetryNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"SEQUENCE\": {\n pushNode(createSequenceNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"SELECTOR\": {\n pushNode(createSelectorNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"PARALLEL\": {\n pushNode(createParallelNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"LOTTO\": {\n pushNode(createLottoNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"ACTION\": {\n pushNode(createActionNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"CONDITION\": {\n pushNode(createConditionNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"WAIT\": {\n pushNode(createWaitNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"BRANCH\": {\n pushNode(createBranchNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"}\": {\n // The '}' character closes the current scope and means that we have to pop a node off of the current stack.\n popNode();\n break;\n }\n\n default: {\n throw new Error(`unexpected token: ${token}`);\n }\n }\n }\n\n return rootNodes as RootNodeDefinition[];\n}\n\n/**\n * Creates a root node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The root node JSON definition.\n */\nfunction createRootNode(tokens: string[], stringLiteralPlaceholders: StringLiteralPlaceholders): RootNodeDefinition {\n // Create the root node definition.\n let node = {\n type: \"root\",\n id: undefined\n } as RootNodeDefinition;\n\n // Parse any node arguments, we should only have one if any which will be an identifier argument for the root identifier.\n const nodeArguments = parseArgumentTokens(tokens, stringLiteralPlaceholders);\n\n // Check whether any node arguments were defined.\n if (nodeArguments.length) {\n // We should only have one argument, if any, which will be an identifier argument for the root identifier.\n if (nodeArguments.length === 1 && nodeArguments[0].type === \"identifier\") {\n // The root node identifier will be the first and only node argument value.\n node.id = nodeArguments[0].value as string;\n } else {\n throw new Error(\"expected single root name argument\");\n }\n }\n\n // Grab any node attribute definitions and spread them into the node definition.\n node = { ...node, ...parseAttributeTokens(tokens, stringLiteralPlaceholders) };\n\n // This is a decorator node, so we expect an opening '{'.\n popAndCheck(tokens, \"{\");\n\n // Return the root node definition.\n return node;\n}\n\n/**\n * Creates a succeed node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The succeed node JSON definition.\n */\nfunction createSucceedNode(\n tokens: string[],\n stringLiteralPlaceholders: StringLiteralPlaceholders\n): SucceedNodeDefinition {\n const node = {\n type: \"succeed\",\n ...parseAttributeTokens(tokens, stringLiteralPlaceholders)\n } as SucceedNodeDefinition;\n\n // This is a decorator node, so we expect an opening '{'.\n popAndCheck(tokens, \"{\");\n\n // Return the succeed node definition.\n return node;\n}\n\n/**\n * Creates a fail node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The fail node JSON definition.\n */\nfunction createFailNode(tokens: string[], stringLiteralPlaceholders: StringLiteralPlaceholders): FailNodeDefinition {\n const node = {\n type: \"fail\",\n ...parseAttributeTokens(tokens, stringLiteralPlaceholders)\n } as FailNodeDefinition;\n\n // This is a decorator node, so we expect an opening '{'.\n popAndCheck(tokens, \"{\");\n\n // Return the fail node definition.\n return node;\n}\n\n/**\n * Creates a flip node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The flip node JSON definition.\n */\nfunction createFlipNode(tokens: string[], stringLiteralPlaceholders: StringLiteralPlaceholders): FlipNodeDefinition {\n const node = {\n type: \"flip\",\n ...parseAttributeTokens(tokens, stringLiteralPlaceholders)\n } as FlipNodeDefinition;\n\n // This is a decorator node, so we expect an opening '{'.\n popAndCheck(tokens, \"{\");\n\n // Return the flip node definition.\n return node;\n}\n\n/**\n * Creates a repeat node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The repeat node JSON definition.\n */\nfunction createRepeatNode(\n tokens: string[],\n stringLiteralPlaceholders: StringLiteralPlaceholders\n): RepeatNodeDefinition {\n let node = { type: \"repeat\" } as RepeatNodeDefinition;\n\n // Get the node arguments.\n const nodeArguments = parseArgumentTokens(tokens, stringLiteralPlaceholders);\n\n // The arguments of a repeat node are optional. We may have:\n // - No node arguments, in which case the repeat note will iterate indefinitely.\n // - One node argument which will be the explicit number of iterations to make.\n // - Two node arguments which define the min and max iteration bounds from which a random iteration count will be picked.\n if (nodeArguments.length) {\n // All repeat node arguments MUST be of type number and must be integer.\n nodeArguments\n .filter((arg) => arg.type !== \"number\" || !arg.isInteger)\n .forEach(() => {\n throw new Error(`repeat node iteration counts must be integer values`);\n });\n\n // We should have got one or two iteration counts.\n if (nodeArguments.length === 1) {\n // A static iteration count was defined.\n node.iterations = nodeArguments[0].value as number;\n } else if (nodeArguments.length === 2) {\n // A minimum and maximum iteration count was defined.\n node.iterations = [nodeArguments[0].value as number, nodeArguments[1].value as number];\n } else {\n // An incorrect number of iteration counts was defined.\n throw new Error(\"invalid number of repeat node iteration count arguments defined\");\n }\n }\n\n // Grab any node attribute definitions and spread them into the node definition.\n node = { ...node, ...parseAttributeTokens(tokens, stringLiteralPlaceholders) };\n\n // This is a decorator node, so we expect an opening '{'.\n popAndCheck(tokens, \"{\");\n\n // Return the repeat node definition.\n return node;\n}\n\n/**\n * Creates a retry node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The retry node JSON definition.\n */\nfunction createRetryNode(tokens: string[], stringLiteralPlaceholders: StringLiteralPlaceholders): RetryNodeDefinition {\n let node = { type: \"retry\" } as RetryNodeDefinition;\n\n // Get the node arguments.\n const nodeArguments = parseArgumentTokens(tokens, stringLiteralPlaceholders);\n\n // The arguments of a retry node are optional. We may have:\n // - No node arguments, in which case the retry note will attempt indefinitely.\n // - One node argument which will be the explicit number of attempts to make.\n // - Two node arguments which define the min and max attempt bounds from which a random attempt count will be picked.\n if (nodeArguments.length) {\n // All retry node arguments MUST be of type number and must be integer.\n nodeArguments\n .filter((arg) => arg.type !== \"number\" || !arg.isInteger)\n .forEach(() => {\n throw new Error(`retry node attempt counts must be integer values`);\n });\n\n // We should have got one or two attempt counts.\n if (nodeArguments.length === 1) {\n // A static attempt count was defined.\n node.attempts = nodeArguments[0].value as number;\n } else if (nodeArguments.length === 2) {\n // A minimum and maximum attempt count was defined.\n node.attempts = [nodeArguments[0].value as number, nodeArguments[1].value as number];\n } else {\n // An incorrect number of attempt counts was defined.\n throw new Error(\"invalid number of retry node attempt count arguments defined\");\n }\n }\n\n // Grab any node attribute definitions and spread them into the node definition.\n node = { ...node, ...parseAttributeTokens(tokens, stringLiteralPlaceholders) };\n\n // This is a decorator node, so we expect an opening '{'.\n popAndCheck(tokens, \"{\");\n\n // Return the retry node definition.\n return node;\n}\n\n/**\n * Creates a sequence node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The sequence node JSON definition.\n */\nfunction createSequenceNode(\n tokens: string[],\n stringLiteralPlaceholders: StringLiteralPlaceholders\n): SequenceNodeDefinition {\n const node = {\n type: \"sequence\",\n ...parseAttributeTokens(tokens, stringLiteralPlaceholders)\n } as SequenceNodeDefinition;\n\n // This is a composite node, so we expect an opening '{'.\n popAndCheck(tokens, \"{\");\n\n // Return the sequence node definition.\n return node;\n}\n\n/**\n * Creates a selector node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The selector node JSON definition.\n */\nfunction createSelectorNode(\n tokens: string[],\n stringLiteralPlaceholders: StringLiteralPlaceholders\n): SelectorNodeDefinition {\n const node = {\n type: \"selector\",\n ...parseAttributeTokens(tokens, stringLiteralPlaceholders)\n } as SelectorNodeDefinition;\n\n // This is a composite node, so we expect an opening '{'.\n popAndCheck(tokens, \"{\");\n\n // Return the selector node definition.\n return node;\n}\n\n/**\n * Creates a parallel node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The parallel node JSON definition.\n */\nfunction createParallelNode(\n tokens: string[],\n stringLiteralPlaceholders: StringLiteralPlaceholders\n): ParallelNodeDefinition {\n const node = {\n type: \"parallel\",\n ...parseAttributeTokens(tokens, stringLiteralPlaceholders)\n } as ParallelNodeDefinition;\n\n // This is a composite node, so we expect an opening '{'.\n popAndCheck(tokens, \"{\");\n\n // Return the parallel node definition.\n return node;\n}\n\n/**\n * Creates a lotto node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The lotto node JSON definition.\n */\nfunction createLottoNode(tokens: string[], stringLiteralPlaceholders: StringLiteralPlaceholders): LottoNodeDefinition {\n // If any node arguments have been defined then they must be our weights.\n const nodeArguments = parseArgumentTokens(tokens, stringLiteralPlaceholders);\n\n // All lotto node arguments MUST be of type number and must be integer.\n nodeArguments\n .filter((arg) => arg.type !== \"number\" || !arg.isInteger)\n .forEach(() => {\n throw new Error(`lotto node weight arguments must be integer values`);\n });\n\n const node = {\n type: \"lotto\",\n weights: nodeArguments.map(({ value }) => value),\n ...parseAttributeTokens(tokens, stringLiteralPlaceholders)\n } as LottoNodeDefinition;\n\n // This is a composite node, so we expect an opening '{'.\n popAndCheck(tokens, \"{\");\n\n // Return the lotto node definition.\n return node;\n}\n\n/**\n * Creates an action node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The action node JSON definition.\n */\nfunction createActionNode(\n tokens: string[],\n stringLiteralPlaceholders: StringLiteralPlaceholders\n): ActionNodeDefinition {\n // Parse any node arguments, we should have at least one which will be an identifier argument for the action name\n // and agent function to invoke for the action, all other arguments are to be passed as arguments to that function.\n const [actionNameIdentifier, ...agentFunctionArgs] = parseArgumentTokens(tokens, stringLiteralPlaceholders);\n\n // Our first argument MUST be defined and be an identifier as we require an action name argument.\n if (actionNameIdentifier?.type !== \"identifier\") {\n throw new Error(\"expected action name identifier argument\");\n }\n\n // Only the first argument should have been an identifier, all agent function arguments must be string, number, boolean or null.\n agentFunctionArgs\n .filter((arg) => arg.type === \"identifier\")\n .forEach((arg) => {\n throw new Error(\n `invalid action node argument value '${arg.value}', must be string, number, boolean or null`\n );\n });\n\n // Return the action node definition.\n return {\n type: \"action\",\n call: actionNameIdentifier.value,\n args: agentFunctionArgs.map(({ value }) => value),\n ...parseAttributeTokens(tokens, stringLiteralPlaceholders)\n };\n}\n\n/**\n * Creates a condition node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The condition node JSON definition.\n */\nfunction createConditionNode(\n tokens: string[],\n stringLiteralPlaceholders: StringLiteralPlaceholders\n): ConditionNodeDefinition {\n // Parse any node arguments, we should have at least one which will be an identifier argument for the condition name\n // and agent function to invoke for the condition, all other arguments are to be passed as arguments to that function.\n const [conditionNameIdentifier, ...agentFunctionArgs] = parseArgumentTokens(tokens, stringLiteralPlaceholders);\n\n // Our first argument MUST be defined and be an identifier as we require a condition name argument.\n if (conditionNameIdentifier?.type !== \"identifier\") {\n throw new Error(\"expected condition name identifier argument\");\n }\n\n // Only the first argument should have been an identifier, all agent function arguments must be string, number, boolean or null.\n agentFunctionArgs\n .filter((arg) => arg.type === \"identifier\")\n .forEach((arg) => {\n throw new Error(\n `invalid condition node argument value '${arg.value}', must be string, number, boolean or null`\n );\n });\n\n // Return the condition node definition.\n return {\n type: \"condition\",\n call: conditionNameIdentifier.value,\n args: agentFunctionArgs.map(({ value }) => value),\n ...parseAttributeTokens(tokens, stringLiteralPlaceholders)\n };\n}\n\n/**\n * Creates a wait node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The wait node JSON definition.\n */\nfunction createWaitNode(tokens: string[], stringLiteralPlaceholders: StringLiteralPlaceholders): WaitNodeDefinition {\n let node = { type: \"wait\" } as WaitNodeDefinition;\n\n // Get the node arguments.\n const nodeArguments = parseArgumentTokens(tokens, stringLiteralPlaceholders);\n\n // The arguments of a wait node are optional. We may have:\n // - No node arguments, in which case the wait will be indefinite until it is aborted.\n // - One node argument which will be the explicit duration of the wait.\n // - Two node arguments which define the min and max duration bounds from which a random duration will be picked.\n if (nodeArguments.length) {\n // All wait node arguments MUST be of type number and must be integer.\n nodeArguments\n .filter((arg) => arg.type !== \"number\" || !arg.isInteger)\n .forEach(() => {\n throw new Error(`wait node duration arguments must be integer values`);\n });\n\n // We may have:\n // - One node argument which will be the explicit duration of the wait.\n // - Two node arguments which define the min and max duration bounds from which a random duration will be picked.\n // - Too many arguments, which is not valid.\n if (nodeArguments.length === 1) {\n // An explicit duration was defined.\n node.duration = nodeArguments[0].value as number;\n } else if (nodeArguments.length === 2) {\n // Min and max duration bounds were defined from which a random duration will be picked.\n node.duration = [nodeArguments[0].value as number, nodeArguments[1].value as number];\n } else if (nodeArguments.length > 2) {\n // An incorrect number of duration arguments were defined.\n throw new Error(\"invalid number of wait node duration arguments defined\");\n }\n }\n\n // Return the wait node definition.\n return { ...node, ...parseAttributeTokens(tokens, stringLiteralPlaceholders) };\n}\n\n/**\n * Creates a branch node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The branch node JSON definition.\n */\nfunction createBranchNode(\n tokens: string[],\n stringLiteralPlaceholders: StringLiteralPlaceholders\n): BranchNodeDefinition {\n // Parse any node arguments, we should have one which will be an identifier argument for the root ref.\n const nodeArguments = parseArgumentTokens(tokens, stringLiteralPlaceholders);\n\n // We should have only a single identifer argument for a branch node, which is the root ref.\n if (nodeArguments.length !== 1 || nodeArguments[0].type !== \"identifier\") {\n throw new Error(\"expected single branch name argument\");\n }\n\n // Return the branch node definition.\n return { type: \"branch\", ref: nodeArguments[0].value };\n}\n", "import { RootNodeDefinition } from \"./BehaviourTreeDefinition\";\nimport { flattenDefinition, isBranchNode, isInteger } from \"./BehaviourTreeDefinitionUtilities\";\nimport { convertMDSLToJSON } from \"./mdsl/MDSLDefinitionParser\";\n\n/**\n * An object representing the result of validating a tree definition.\n */\nexport type DefinitionValidationResult = {\n /**\n * A flag defining whether validation succeeded.\n */\n succeeded: boolean;\n /**\n * A string containing the error message if validation did not succeed.\n */\n errorMessage?: string;\n};\n\n/**\n * Validates the specified behaviour tree definition in the form of JSON or MDSL.\n * @param definition The behaviour tree definition in the form of JSON or MDSL.\n * @returns An object representing the result of validating the given tree definition.\n */\nexport function validateDefinition(definition: any): DefinitionValidationResult {\n // The definition must be defined.\n if (definition === null || typeof definition === \"undefined\") {\n return createValidationFailureResult(\"definition is null or undefined\");\n }\n\n // We are expecting a definition in one of three different forms:\n // - A string which we will assume is MDSL and we will parse this to JSON before validation.\n // - An array which we will assume is an array of root node definitions with at least one being the primary root node (no 'id' property)\n // - An object which we will assume is the primary root node and should not have an 'id' property.\n if (typeof definition === \"string\") {\n // The definition is a string which we can assume is MDSL, so attempt to validate it.\n return validateMDSLDefinition(definition);\n } else if (typeof definition === \"object\") {\n // The definition will either be an array (of root node definitions) or an object (the single primary root node definition).\n return validateJSONDefinition(definition);\n } else {\n return createValidationFailureResult(`unexpected definition type of '${typeof definition}'`);\n }\n}\n\n/**\n * Validates the specified behaviour tree definition in the form of MDSL.\n * @param definition The behaviour tree definition in the form of MDSL.\n * @returns An object representing the result of validating the given tree definition.\n */\nexport function validateMDSLDefinition(definition: string): DefinitionValidationResult {\n let rootNodeDefinitions;\n\n // The first thing the we need to do is to attempt to convert our MDSL into JSON.\n try {\n // The definition is a string which we can assume is MDSL, so attempt to parse it to a JSON definition in the form of an array of root node definitions.\n rootNodeDefinitions = convertMDSLToJSON(definition);\n } catch (error) {\n // We failed to parse the JSON from the MDSL, this is likely to be the result of it not being a valid MDSL string.\n return createValidationFailureResult(`invalid MDSL: ${definition}`);\n }\n\n // Unpack all of the root node definitions into arrays of main ('id' defined) and sub ('id' not defined) root node definitions.\n const mainRootNodeDefinitions = rootNodeDefinitions.filter(({ id }) => typeof id === \"undefined\");\n const subRootNodeDefinitions = rootNodeDefinitions.filter(({ id }) => typeof id === \"string\" && id.length > 0);\n\n // We should ALWAYS have exactly one root node definition without an 'id' property defined, which is out main root node definition.\n if (mainRootNodeDefinitions.length !== 1) {\n return createValidationFailureResult(\n \"expected single unnamed root node at base of definition to act as main root\"\n );\n }\n\n // We should never have duplicate 'id' properties across our sub root node definitions.\n const subRootNodeIdenitifers: string[] = [];\n for (const { id } of subRootNodeDefinitions) {\n // Have we already come across this 'id' property value?\n if (subRootNodeIdenitifers.includes(id!)) {\n return createValidationFailureResult(`multiple root nodes found with duplicate name '${id}'`);\n }\n\n subRootNodeIdenitifers.push(id!);\n }\n\n // Check for any branch node circular depedencies. This will NOT include any globally registered subtrees.\n const circularDependencyPath = findBranchCircularDependencyPath(rootNodeDefinitions);\n\n // If we found a circular dependency in our root node and branch node definitions then the definition is definitely not valid.\n if (circularDependencyPath) {\n return createValidationFailureResult(\n `circular dependency found in branch node references: ${circularDependencyPath}`\n );\n }\n\n // Our definition was valid!\n return { succeeded: true };\n}\n\n/**\n * Validates the specified behaviour tree definition in the form of JSON.\n * @param definition The behaviour tree definition in the form of JSON.\n * @returns An object representing the result of validating the given tree definition.\n */\nexport function validateJSONDefinition(\n definition: RootNodeDefinition | RootNodeDefinition[]\n): DefinitionValidationResult {\n // The definition will either be an array (of root node definitions) or an object (the single primary root node definition).\n const rootNodeDefinitions = Array.isArray(definition) ? definition : [definition];\n\n // Iterate over our array of root nodes and call validateNode for each, passing an initial depth of 0, wrapped in a try catch to handle validation failures.\n try {\n rootNodeDefinitions.forEach((rootNodeDefinition) => validateNode(rootNodeDefinition, 0));\n } catch (error) {\n // Handle cases where we have caught a thrown Error and return a failure result with the error message.\n if (error instanceof Error) {\n return createValidationFailureResult(error.message);\n }\n\n // No idea what happened here!\n return createValidationFailureResult(`unexpected error: ${error}`);\n }\n\n // Unpack all of the root node definitions into arrays of main ('id' defined) and sub ('id' not defined) root node definitions.\n const mainRootNodeDefinitions = rootNodeDefinitions.filter(({ id }) => typeof id === \"undefined\");\n const subRootNodeDefinitions = rootNodeDefinitions.filter(({ id }) => typeof id === \"string\" && id.length > 0);\n\n // We should ALWAYS have exactly one root node definition without an 'id' property defined, which is out main root node definition.\n if (mainRootNodeDefinitions.length !== 1) {\n return createValidationFailureResult(\n \"expected single root node without 'id' property defined to act as main root\"\n );\n }\n\n // We should never have duplicate 'id' properties across our sub root node definitions.\n const subRootNodeIdenitifers: string[] = [];\n for (const { id } of subRootNodeDefinitions) {\n // Have we already come across this 'id' property value?\n if (subRootNodeIdenitifers.includes(id!)) {\n return createValidationFailureResult(\n `multiple root nodes found with duplicate 'id' property value of '${id}'`\n );\n }\n\n subRootNodeIdenitifers.push(id!);\n }\n\n // Check for any branch node circular depedencies. This will NOT include any globally registered subtrees.\n const circularDependencyPath = findBranchCircularDependencyPath(rootNodeDefinitions);\n\n // If we found a circular dependency in our root node and branch node definitions then the definition is definitely not valid.\n if (circularDependencyPath) {\n return createValidationFailureResult(\n `circular dependency found in branch node references: ${circularDependencyPath}`\n );\n }\n\n // Our definition was valid!\n return { succeeded: true };\n}\n\n/**\n * Find the first circular depdendency path present in the array of root node definitions, or null if one doesn't exist.\n * This will not consider branch nodes that reference any globally registered subtrees.\n * @param rootNodeDefinitions The array of root node definitions.\n * @returns The first circular depdendency path present in the array of root node definitions as string, or null if one doesn't exist.\n */\nfunction findBranchCircularDependencyPath(rootNodeDefinitions: RootNodeDefinition[]): string | null {\n // Create a mapping of root node identifiers to other root nodes that they reference via branch nodes.\n // Below is an example of a mapping that includes a circular dependency (root => a => b => c => a)\n // [{ refs: [\"a\", \"b\"] }, { id: \"a\", refs: [\"b\"] }, { id: \"b\", refs: [\"c\"] }, { id: \"c\", refs: [\"a\"] }]\n const rootNodeMappings: { id: string | undefined; refs: string[] }[] = rootNodeDefinitions.map(\n (rootNodeDefinition) => ({\n id: rootNodeDefinition.id,\n refs: flattenDefinition(rootNodeDefinition)\n .filter(isBranchNode)\n .map(({ ref }) => ref)\n })\n );\n\n let badPathFormatted: string | null = null;\n\n // A recursive function to walk through the mappings, keeping track of which root nodes we have visited in the form of a path of root node identifiers.\n const followRefs = (mapping: { id: string | undefined; refs: string[] }, path: (string | undefined)[] = []) => {\n // Have we found a circular dependency?\n if (path.includes(mapping.id)) {\n // We found a circular dependency! Get the bad path of root node identifiers.\n const badPath = [...path, mapping.id];\n\n // Set the formatted path value. [undefined, \"a\", \"b\", \"c\", \"a\"] would be formatted as \"a -> b -> c -> a\".\n badPathFormatted = badPath.filter((element) => !!element).join(\" => \");\n\n // No need to continue, we found a circular dependency.\n return;\n }\n\n for (const ref of mapping.refs) {\n // Find the mapping for the root node with an identifer matching the current ref.\n const subMapping = rootNodeMappings.find(({ id }) => id === ref);\n\n // We may not have a mapping for this ref, which will happen if this ref is for a globally registered subtree.\n if (subMapping) {\n followRefs(subMapping, [...path, mapping.id]);\n }\n }\n };\n\n // Start looking for circular dependencies from the root.\n followRefs(rootNodeMappings.find((mapping) => typeof mapping.id === \"undefined\")!);\n\n return badPathFormatted;\n}\n\n/**\n * Validate an object that we expect to be a node definition.\n * @param definition An object that we expect to be a node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateNode(definition: any, depth: number): void {\n // Every node must be valid object and have a non-empty 'type' string property.\n if (typeof definition !== \"object\" || typeof definition.type !== \"string\" || definition.type.length === 0) {\n throw new Error(\n `node definition is not an object or 'type' property is not a non-empty string at depth '${depth}'`\n );\n }\n\n // How we validate this node definition will depend on its type.\n switch (definition.type) {\n case \"action\":\n validateActionNode(definition, depth);\n break;\n\n case \"condition\":\n validateConditionNode(definition, depth);\n break;\n\n case \"wait\":\n validateWaitNode(definition, depth);\n break;\n\n case \"branch\":\n validateBranchNode(definition, depth);\n break;\n\n case \"root\":\n validateRootNode(definition, depth);\n break;\n\n case \"success\":\n validateSuccessNode(definition, depth);\n break;\n\n case \"fail\":\n validateFailNode(definition, depth);\n break;\n\n case \"flip\":\n validateFlipNode(definition, depth);\n break;\n\n case \"repeat\":\n validateRepeatNode(definition, depth);\n break;\n\n case \"retry\":\n validateRetryNode(definition, depth);\n break;\n\n case \"sequence\":\n validateSequenceNode(definition, depth);\n break;\n\n case \"selector\":\n validateSelectorNode(definition, depth);\n break;\n\n case \"parallel\":\n validateParallelNode(definition, depth);\n break;\n\n default:\n throw new Error(`unexpected node type of '${definition.type}' at depth '${depth}'`);\n }\n}\n\n/**\n * Validate any attributes for a given node definition.\n * @param definition The node definition.\n * @param depth The depth of the node in the behaviour tree definition.\n */\nfunction validateNodeAttributes(definition: any, depth: number): void {\n // Validate each of the attribute types for this node.\n [\"while\", \"until\", \"entry\", \"exit\", \"step\"].forEach((attributeName) => {\n // Attempt to grab the definition for the current attribute from the node definition.\n const attributeDefinition = definition[attributeName];\n\n // All node attributes are optional, so there is nothing to do if the current attribute is not defined.\n if (typeof attributeDefinition === \"undefined\") {\n return;\n }\n\n // The attribute definition must be an object.\n if (typeof attributeDefinition !== \"object\") {\n throw new Error(\n `expected attribute '${attributeName}' to be an object for '${definition.type}' node at depth '${depth}'`\n );\n }\n\n // The 'call' property must be defined for any attribute definition.\n if (typeof attributeDefinition.call !== \"string\" || attributeDefinition.call.length === 0) {\n throw new Error(\n `expected 'call' property for attribute '${attributeName}' to be a non-empty string for '${definition.type}' node at depth '${depth}'`\n );\n }\n\n // If any node attribute arguments have been defined then they must have been defined in an array.\n if (typeof attributeDefinition.args !== \"undefined\" && !Array.isArray(attributeDefinition.args)) {\n throw new Error(\n `expected 'args' property for attribute '${attributeName}' to be an array for '${definition.type}' node at depth '${depth}'`\n );\n }\n });\n}\n\n/**\n * Validate an object that we expect to be a root node definition.\n * @param definition An object that we expect to be a root node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateRootNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"root\") {\n throw new Error(\"expected node type of 'root' for root node\");\n }\n\n // A root node cannot be the child of another node.\n if (depth > 0) {\n throw new Error(\"a root node cannot be the child of another node\");\n }\n\n // Check that, if the root node 'id' property is defined, it is a non-empty string.\n if (typeof definition.id !== \"undefined\" && (typeof definition.id !== \"string\" || definition.id.length === 0)) {\n throw new Error(\"expected non-empty string for 'id' property if defined for root node\");\n }\n\n // A root node is a decorator node, so must have a child node defined.\n if (typeof definition.child === \"undefined\") {\n throw new Error(\"expected property 'child' to be defined for root node\");\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n\n // Validate the child node of this decorator node.\n validateNode(definition.child, depth + 1);\n}\n\n/**\n * Validate an object that we expect to be a success node definition.\n * @param definition An object that we expect to be a success node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateSuccessNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"success\") {\n throw new Error(`expected node type of 'success' for success node at depth '${depth}'`);\n }\n\n // A success node is a decorator node, so must have a child node defined.\n if (typeof definition.child === \"undefined\") {\n throw new Error(`expected property 'child' to be defined for success node at depth '${depth}'`);\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n\n // Validate the child node of this decorator node.\n validateNode(definition.child, depth + 1);\n}\n\n/**\n * Validate an object that we expect to be a fail node definition.\n * @param definition An object that we expect to be a fail node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateFailNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"fail\") {\n throw new Error(`expected node type of 'fail' for fail node at depth '${depth}'`);\n }\n\n // A fail node is a decorator node, so must have a child node defined.\n if (typeof definition.child === \"undefined\") {\n throw new Error(`expected property 'child' to be defined for fail node at depth '${depth}'`);\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n\n // Validate the child node of this decorator node.\n validateNode(definition.child, depth + 1);\n}\n\n/**\n * Validate an object that we expect to be a flip node definition.\n * @param definition An object that we expect to be a flip node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateFlipNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"flip\") {\n throw new Error(`expected node type of 'flip' for flip node at depth '${depth}'`);\n }\n\n // A flip node is a decorator node, so must have a child node defined.\n if (typeof definition.child === \"undefined\") {\n throw new Error(`expected property 'child' to be defined for flip node at depth '${depth}'`);\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n\n // Validate the child node of this decorator node.\n validateNode(definition.child, depth + 1);\n}\n\n/**\n * Validate an object that we expect to be a repeat node definition.\n * @param definition An object that we expect to be a repeat node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateRepeatNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"repeat\") {\n throw new Error(`expected node type of 'repeat' for repeat node at depth '${depth}'`);\n }\n\n // A repeat node is a decorator node, so must have a child node defined.\n if (typeof definition.child === \"undefined\") {\n throw new Error(`expected property 'child' to be defined for repeat node at depth '${depth}'`);\n }\n\n // Check whether an 'iterations' property has been defined, it may not have been if this node is to repeat indefinitely.\n if (typeof definition.iterations !== \"undefined\") {\n if (Array.isArray(definition.iterations)) {\n // Check whether any elements of the array are not integer values.\n const containsNonInteger = !!definition.iterations.find((value: unknown) => !isInteger(value));\n\n // If the 'iterations' property is an array then it MUST contain two integer values.\n if (definition.iterations.length !== 2 || containsNonInteger) {\n throw new Error(\n `expected array containing two integer values for 'iterations' property if defined for repeat node at depth '${depth}'`\n );\n }\n } else if (!isInteger(definition.iterations)) {\n throw new Error(\n `expected integer value or array containing two integer values for 'iterations' property if defined for repeat node at depth '${depth}'`\n );\n }\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n\n // Validate the child node of this decorator node.\n validateNode(definition.child, depth + 1);\n}\n\n/**\n * Validate an object that we expect to be a retry node definition.\n * @param definition An object that we expect to be a retry node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateRetryNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"retry\") {\n throw new Error(`expected node type of 'retry' for retry node at depth '${depth}'`);\n }\n\n // A retry node is a decorator node, so must have a child node defined.\n if (typeof definition.child === \"undefined\") {\n throw new Error(`expected property 'child' to be defined for retry node at depth '${depth}'`);\n }\n\n // Check whether an 'attempts' property has been defined, it may not have been if this node is to retry indefinitely.\n if (typeof definition.attempts !== \"undefined\") {\n if (Array.isArray(definition.attempts)) {\n // Check whether any elements of the array are not integer values.\n const containsNonInteger = !!definition.attempts.find((value: unknown) => !isInteger(value));\n\n // If the 'attempts' property is an array then it MUST contain two integer values.\n if (definition.attempts.length !== 2 || containsNonInteger) {\n throw new Error(\n `expected array containing two integer values for 'attempts' property if defined for retry node at depth '${depth}'`\n );\n }\n } else if (!isInteger(definition.attempts)) {\n throw new Error(\n `expected integer value or array containing two integer values for 'attempts' property if defined for retry node at depth '${depth}'`\n );\n }\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n\n // Validate the child node of this decorator node.\n validateNode(definition.child, depth + 1);\n}\n\n/**\n * Validate an object that we expect to be a branch node definition.\n * @param definition An object that we expect to be a branch node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateBranchNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"branch\") {\n throw new Error(`expected node type of 'branch' for branch node at depth '${depth}'`);\n }\n\n // Check that the branch node 'ref' property is defined and is a non-empty string.\n if (typeof definition.ref !== \"string\" || definition.ref.length === 0) {\n throw new Error(`expected non-empty string for 'ref' property for branch node at depth '${depth}'`);\n }\n\n // It is invalid to define guard attributes for a branch node as they should be defined on the referenced root node.\n [\"while\", \"until\"].forEach((attributeName) => {\n if (typeof definition[attributeName] !== \"undefined\") {\n throw new Error(\n `guards should not be defined for branch nodes but guard '${attributeName}' was defined for branch node at depth '${depth}'`\n );\n }\n });\n\n // It is invalid to define callback attributes for a branch node as they should be defined on the referenced root node.\n [\"entry\", \"exit\", \"step\"].forEach((attributeName) => {\n if (typeof definition[attributeName] !== \"undefined\") {\n throw new Error(\n `callbacks should not be defined for branch nodes but callback '${attributeName}' was defined for branch node at depth '${depth}'`\n );\n }\n });\n}\n\n/**\n * Validate an object that we expect to be a action node definition.\n * @param definition An object that we expect to be a action node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateActionNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"action\") {\n throw new Error(`expected node type of 'action' for action node at depth '${depth}'`);\n }\n\n // The 'call' property must be defined for a action node definition.\n if (typeof definition.call !== \"string\" || definition.call.length === 0) {\n throw new Error(`expected non-empty string for 'call' property of action node at depth '${depth}'`);\n }\n\n // If any action function arguments have been defined then they must have been defined in an array.\n if (typeof definition.args !== \"undefined\" && !Array.isArray(definition.args)) {\n throw new Error(`expected array for 'args' property if defined for action node at depth '${depth}'`);\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n}\n\n/**\n * Validate an object that we expect to be a condition node definition.\n * @param definition An object that we expect to be a condition node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateConditionNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"condition\") {\n throw new Error(`expected node type of 'condition' for condition node at depth '${depth}'`);\n }\n\n // The 'call' property must be defined for a condition node definition.\n if (typeof definition.call !== \"string\" || definition.call.length === 0) {\n throw new Error(`expected non-empty string for 'call' property of condition node at depth '${depth}'`);\n }\n\n // If any condition function arguments have been defined then they must have been defined in an array.\n if (typeof definition.args !== \"undefined\" && !Array.isArray(definition.args)) {\n throw new Error(`expected array for 'args' property if defined for condition node at depth '${depth}'`);\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n}\n\n/**\n * Validate an object that we expect to be a wait node definition.\n * @param definition An object that we expect to be a wait node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateWaitNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"wait\") {\n throw new Error(`expected node type of 'wait' for wait node at depth '${depth}'`);\n }\n\n // Check whether a 'duration' property has been defined, it may not have been if this node is to wait indefinitely.\n if (typeof definition.duration !== \"undefined\") {\n if (Array.isArray(definition.duration)) {\n // Check whether any elements of the array are not integer values.\n const containsNonInteger = !!definition.duration.find((value: unknown) => !isInteger(value));\n\n // If the 'duration' property is an array then it MUST contain two integer values.\n if (definition.duration.length !== 2 || containsNonInteger) {\n throw new Error(\n `expected array containing two integer values for 'duration' property if defined for wait node at depth '${depth}'`\n );\n }\n } else if (!isInteger(definition.duration)) {\n throw new Error(\n `expected integer value or array containing two integer values for 'duration' property if defined for wait node at depth '${depth}'`\n );\n }\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n}\n\n/**\n * Validate an object that we expect to be a sequence node definition.\n * @param definition An object that we expect to be a sequence node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateSequenceNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"sequence\") {\n throw new Error(`expected node type of 'sequence' for sequence node at depth '${depth}'`);\n }\n\n // A sequence node is a composite node, so must have a children nodes array defined.\n if (!Array.isArray(definition.children) || definition.children.length === 0) {\n throw new Error(`expected non-empty 'children' array to be defined for sequence node at depth '${depth}'`);\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n\n // Validate the child nodes of this composite node.\n definition.children.forEach((child: any) => validateNode(child, depth + 1));\n}\n\n/**\n * Validate an object that we expect to be a selector node definition.\n * @param definition An object that we expect to be a selector node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateSelectorNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"selector\") {\n throw new Error(`expected node type of 'selector' for selector node at depth '${depth}'`);\n }\n\n // A selector node is a composite node, so must have a children nodes array defined.\n if (!Array.isArray(definition.children) || definition.children.length === 0) {\n throw new Error(`expected non-empty 'children' array to be defined for selector node at depth '${depth}'`);\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n\n // Validate the child nodes of this composite node.\n definition.children.forEach((child: any) => validateNode(child, depth + 1));\n}\n\n/**\n * Validate an object that we expect to be a parallel node definition.\n * @param definition An object that we expect to be a parallel node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateParallelNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"parallel\") {\n throw new Error(`expected node type of 'parallel' for parallel node at depth '${depth}'`);\n }\n\n // A parallel node is a composite node, so must have a children nodes array defined.\n if (!Array.isArray(definition.children) || definition.children.length === 0) {\n throw new Error(`expected non-empty 'children' array to be defined for parallel node at depth '${depth}'`);\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n\n // Validate the child nodes of this composite node.\n definition.children.forEach((child: any) => validateNode(child, depth + 1));\n}\n\n/**\n * A helper function to create a failure validation result with the given error message.\n * @param errorMessage The validation failure error message.\n * @returns A failure validation result with the given error message.\n */\nfunction createValidationFailureResult(errorMessage: string): DefinitionValidationResult {\n return { succeeded: false, errorMessage };\n}\n", "import Node from \"../../nodes/Node\";\n\n/**\n * An exception thrown when evaluating node guard path conditions and a conditions fails.\n */\nexport default class GuardUnsatisifedException extends Error {\n /**\n * @param source The node at which a guard condition failed.\n */\n constructor(private source: Node) {\n super(\"A guard path condition has failed\");\n }\n\n /**\n * Gets whether the specified node is the node at which a guard condition failed.\n * @param node The node to check against the source node.\n * @returns Whether the specified node is the node at which a guard condition failed.\n */\n isSourceNode = (node: Node) => node === this.source;\n}\n", "import { Agent } from \"../../Agent\";\nimport Guard from \"./Guard\";\nimport Node from \"../../nodes/Node\";\nimport GuardUnsatisifedException from \"./GuardUnsatisifedException\";\n\nexport type GuardPathPart = {\n node: Node;\n guards: Guard[];\n};\n\n/**\n * Represents a path of node guards along a root-to-leaf tree path.\n */\nexport default class GuardPath {\n /**\n * @param nodes An array of objects defining a node instance -> guard link, ordered by node depth.\n */\n constructor(private nodes: GuardPathPart[]) {}\n\n /**\n * Evaluate guard conditions for all guards in the tree path, moving outwards from the root.\n * @param agent The agent, required for guard evaluation.\n * @returns An evaluation results object.\n */\n evaluate = (agent: Agent) => {\n // We need to evaluate guard conditions for nodes up the tree, moving outwards from the root.\n for (const details of this.nodes) {\n // There can be multiple guards per node.\n for (const guard of details.guards) {\n // Check whether the guard condition passes, and throw an exception if not.\n if (!guard.isSatisfied(agent)) {\n throw new GuardUnsatisifedException(details.node);\n }\n }\n }\n };\n}\n", "import { Agent } from \"../Agent\";\nimport Attribute from \"../attributes/Attribute\";\nimport Entry from \"../attributes/callbacks/Entry\";\nimport Exit from \"../attributes/callbacks/Exit\";\nimport Step from \"../attributes/callbacks/Step\";\nimport Guard from \"../attributes/guards/Guard\";\nimport GuardPath from \"../attributes/guards/GuardPath\";\nimport GuardUnsatisifedException from \"../attributes/guards/GuardUnsatisifedException\";\nimport { BehaviourTreeOptions } from \"../BehaviourTreeOptions\";\nimport { AnyArgument } from \"../RootAstNodesBuilder\";\nimport State, { AnyState } from \"../State\";\nimport Leaf from \"./leaf/Leaf\";\n\n/**\n * A base node.\n */\nexport default abstract class Node {\n /**\n * The node uid.\n */\n private readonly uid: string = createNodeUid();\n /**\n * The node state.\n */\n private state: AnyState = State.READY;\n /**\n * The guard path to evaluate as part of a node update.\n */\n private guardPath: GuardPath | undefined;\n\n /**\n * @param type The node type.\n * @param attributes The node attributes.\n * @param args The node argument definitions.\n */\n constructor(private type: string, private attributes: Attribute[], private args: AnyArgument[]) {}\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected abstract onUpdate(agent: Agent, options: BehaviourTreeOptions): void;\n\n /**\n * Gets the name of the node.\n */\n public abstract getName(): string;\n\n /**\n * Gets whether this node is a leaf node.\n */\n public abstract isLeafNode: () => this is Leaf;\n\n /**\n * Gets/Sets the state of the node.\n */\n getState = (): AnyState => this.state;\n setState = (value: AnyState): void => {\n this.state = value;\n };\n\n /**\n * Gets the unique id of the node.\n */\n getUid = () => this.uid;\n\n /**\n * Gets the type of the node.\n */\n getType = () => this.type;\n\n /**\n * Gets the node attributes.\n */\n getAttributes = () => this.attributes;\n\n /**\n * Gets the node arguments.\n */\n getArguments = () => this.args;\n\n /**\n * Gets the node attribute with the specified type, or null if it does not exist.\n */\n getAttribute(type: \"entry\" | \"ENTRY\"): Entry;\n getAttribute(type: \"exit\" | \"EXIT\"): Exit;\n getAttribute(type: \"step\" | \"STEP\"): Step;\n getAttribute(type: string): Attribute {\n return (\n this.getAttributes().filter((decorator) => decorator.getType().toUpperCase() === type.toUpperCase())[0] ||\n null\n );\n }\n\n /**\n * Gets the node attributes.\n */\n getGuardAttributes = (): Guard[] => this.getAttributes().filter((decorator) => decorator.isGuard()) as Guard[];\n\n /**\n * Sets the guard path to evaluate as part of a node update.\n */\n setGuardPath = (value: GuardPath) => (this.guardPath = value);\n\n /**\n * Gets whether a guard path is assigned to this node.\n */\n hasGuardPath = () => !!this.guardPath;\n\n /**\n * Gets whether this node is in the specified state.\n * @param value The value to compare to the node state.\n */\n public is(value: AnyState): boolean {\n return this.state === value;\n }\n\n /**\n * Reset the state of the node.\n */\n public reset(): void {\n this.setState(State.READY);\n }\n\n /**\n * Abort the running of this node.\n * @param agent The agent.\n */\n public abort(agent: Agent): void {\n // There is nothing to do if this node is not in the running state.\n if (!this.is(State.RUNNING)) {\n return;\n }\n\n // Reset the state of this node.\n this.reset();\n\n this.getAttribute(\"exit\")?.callAgentFunction(agent, false, true);\n }\n\n /**\n * Update the node.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n * @returns The result of the update.\n */\n public update(agent: Agent, options: BehaviourTreeOptions): void {\n // If this node is already in a 'SUCCEEDED' or 'FAILED' state then there is nothing to do.\n if (this.is(State.SUCCEEDED) || this.is(State.FAILED)) {\n return;\n }\n\n try {\n // Evaluate all of the guard path conditions for the current tree path.\n this.guardPath!.evaluate(agent);\n\n // If this node is in the READY state then call the ENTRY for this node if it exists.\n if (this.is(State.READY)) {\n this.getAttribute(\"entry\")?.callAgentFunction(agent);\n }\n\n this.getAttribute(\"step\")?.callAgentFunction(agent);\n\n // Do the actual update.\n this.onUpdate(agent, options);\n\n // If this node is now in a 'SUCCEEDED' or 'FAILED' state then call the EXIT for this node if it exists.\n if (this.is(State.SUCCEEDED) || this.is(State.FAILED)) {\n this.getAttribute(\"exit\")?.callAgentFunction(agent, this.is(State.SUCCEEDED), false);\n }\n } catch (error) {\n // If the error is a GuardUnsatisfiedException then we need to determine if this node is the source.\n if (error instanceof GuardUnsatisifedException && error.isSourceNode(this)) {\n // Abort the current node.\n this.abort(agent);\n\n // Any node that is the source of an abort will be a failed node.\n this.setState(State.FAILED);\n } else {\n throw error;\n }\n }\n }\n}\n\n/**\n * Create a randomly generated node uid.\n * @returns A randomly generated node uid.\n */\nfunction createNodeUid(): string {\n var S4 = function () {\n return (((1 + Math.random()) * 0x10000) | 0).toString(16).substring(1);\n };\n return S4() + S4() + \"-\" + S4() + \"-\" + S4() + \"-\" + S4() + \"-\" + S4() + S4() + S4();\n}\n", "import Node from \"../Node\";\n\n/**\n * A leaf node.\n */\nexport default abstract class Leaf extends Node {\n /**\n * Gets whether this node is a leaf node.\n */\n isLeafNode = () => true;\n}\n", "import { ActionResult, Agent, ExitFunctionArg, FunctionArg, GlobalFunction } from \"./Agent\";\nimport { AnyArgument, RootAstNode } from \"./RootAstNodesBuilder\";\n\n// Exit callbacks receive their own special type of argument.\n// There's probably stricter ways to represent this but it feels overly complex right now.\ntype ExitResultArg = { value: ExitFunctionArg };\nexport type AnyExitArgument = AnyArgument | ExitResultArg;\n\nexport type InvokerFunction = (args: AnyExitArgument[]) => ActionResult;\n\n/**\n * A singleton used to store and lookup registered functions and subtrees.\n */\nexport default class Lookup {\n /**\n * The object holding any registered functions keyed on function name.\n */\n private static functionTable: { [key: string]: GlobalFunction } = {};\n /**\n * The object holding any registered sub-trees keyed on tree name.\n */\n private static subtreeTable: { [key: string]: RootAstNode } = {};\n\n /**\n * Gets the function with the specified name.\n * @param name The name of the function.\n * @returns The function with the specified name.\n */\n public static getFunc(name: string): GlobalFunction {\n return this.functionTable[name];\n }\n\n /**\n * Sets the function with the specified name for later lookup.\n * @param name The name of the function.\n * @param func The function.\n */\n public static setFunc(name: string, func: GlobalFunction): void {\n this.functionTable[name] = func;\n }\n\n /**\n * Gets the function invoker for the specified agent and function name.\n * If a function with the specified name exists on the agent object then it will\n * be returned, otherwise we will then check the registered functions for a match.\n * @param agent The agent instance that this behaviour tree is modelling behaviour for.\n * @param name The function name.\n * @returns The function invoker for the specified agent and function name.\n */\n static getFuncInvoker(agent: Agent, name: string): InvokerFunction | null {\n // Check whether the agent contains the specified function.\n const foundOnAgent = agent[name];\n if (foundOnAgent && typeof foundOnAgent === \"function\") {\n return (args: AnyExitArgument[]): boolean | ActionResult =>\n foundOnAgent.apply(\n agent,\n args.map((arg) => arg.value)\n );\n }\n\n // The agent does not contain the specified function but it may have been registered at some point.\n if (this.functionTable[name] && typeof this.functionTable[name] === \"function\") {\n return (args: AnyExitArgument[]) => this.functionTable[name](agent, ...args.map((arg) => arg.value));\n }\n\n // We have no function to invoke.\n return null;\n }\n\n /**\n * Gets the subtree with the specified name.\n * @param name The name of the subtree.\n * @returns The subtree with the specified name.\n */\n static getSubtree(name: string): RootAstNode {\n return this.subtreeTable[name];\n }\n\n /**\n * Sets the subtree with the specified name for later lookup.\n * @param name The name of the subtree.\n * @param subtree The subtree.\n */\n static setSubtree(name: string, subtree: RootAstNode) {\n this.subtreeTable[name] = subtree;\n }\n\n /**\n * Removes the registered function or subtree with the specified name.\n * @param name The name of the registered function or subtree.\n */\n static remove(name: string) {\n delete this.functionTable[name];\n delete this.subtreeTable[name];\n }\n\n /**\n * Remove all registered functions and subtrees.\n */\n static empty() {\n this.functionTable = {};\n this.subtreeTable = {};\n }\n}\n", "import Leaf from \"./Leaf\";\nimport State, { CompleteState } from \"../../State\";\nimport Lookup from \"../../Lookup\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { AnyArgument } from \"../../RootAstNodesBuilder\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * An Action leaf node.\n * This represents an immediate or ongoing state of behaviour.\n */\nexport default class Action extends Leaf {\n /**\n * @param attributes The node attributes.\n * @param actionName The action name.\n * @param actionArguments The array of action argument definitions.\n */\n constructor(attributes: Attribute[], private actionName: string, private actionArguments: AnyArgument[]) {\n super(\"action\", attributes, actionArguments);\n }\n\n /**\n * Whether there is a pending update promise.\n */\n private isUsingUpdatePromise = false;\n\n /**\n * The finished state result of an update promise.\n */\n private updatePromiseStateResult: CompleteState | null = null;\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // If the result of this action depends on an update promise then there is nothing to do until\n // it resolves, unless there has been a value set as a result of the update promise resolving.\n if (this.isUsingUpdatePromise) {\n // Check whether the update promise has resolved with a state value.\n if (this.updatePromiseStateResult) {\n // Set the state of this node to match the state returned by the promise.\n this.setState(this.updatePromiseStateResult);\n }\n\n return;\n }\n\n // Attempt to get the invoker for the action function.\n const actionFuncInvoker = Lookup.getFuncInvoker(agent, this.actionName);\n\n // The action function should be defined.\n if (actionFuncInvoker === null) {\n throw new Error(\n `cannot update action node as the action '${this.actionName}' function is not defined on the agent and has not been registered`\n );\n }\n\n // Call the action function, the result of which may be:\n // - The finished state of this action node.\n // - A promise to return a finished node state.\n // - Undefined if the node should remain in the running state.\n const updateResult = actionFuncInvoker(this.actionArguments) as CompleteState | Promise;\n\n if (updateResult instanceof Promise) {\n updateResult.then(\n (result) => {\n // If 'isUpdatePromisePending' is null then the promise was cleared as it was resolving, probably via an abort of reset.\n if (!this.isUsingUpdatePromise) {\n return;\n }\n\n // Check to make sure the result is a valid finished state.\n if (result !== State.SUCCEEDED && result !== State.FAILED) {\n throw new Error(\n \"action node promise resolved with an invalid value, expected a State.SUCCEEDED or State.FAILED value to be returned\"\n );\n }\n\n // Set pending update promise state result to be processed on next update.\n this.updatePromiseStateResult = result;\n },\n (reason) => {\n // If 'isUpdatePromisePending' is null then the promise was cleared as it was resolving, probably via an abort of reset.\n if (!this.isUsingUpdatePromise) {\n return;\n }\n\n // Just throw whatever was returned as the rejection argument.\n throw new Error(reason);\n }\n );\n\n // This node will be in the 'RUNNING' state until the update promise resolves.\n this.setState(State.RUNNING);\n\n // We are now waiting for the promise returned by the use to resolve before we know what state this node is in.\n this.isUsingUpdatePromise = true;\n } else {\n // Validate the returned value.\n this.validateUpdateResult(updateResult);\n\n // Set the state of this node, this may be undefined, which just means that the node is still in the 'RUNNING' state.\n this.setState(updateResult || State.RUNNING);\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => this.actionName;\n\n /**\n * Reset the state of the node.\n */\n reset = () => {\n // Reset the state of this node.\n this.setState(State.READY);\n\n // There is no longer an update promise that we care about.\n this.isUsingUpdatePromise = false;\n this.updatePromiseStateResult = null;\n };\n\n /**\n * Validate the result of an update function call.\n * @param result The result of an update function call.\n */\n private validateUpdateResult = (result: CompleteState | boolean) => {\n switch (result) {\n case State.SUCCEEDED:\n case State.FAILED:\n case undefined:\n return;\n default:\n throw new Error(\n `action '${this.actionName}' 'onUpdate' returned an invalid response, expected an optional State.SUCCEEDED or State.FAILED value to be returned`\n );\n }\n };\n}\n", "import Leaf from \"./Leaf\";\nimport State from \"../../State\";\nimport Lookup from \"../../Lookup\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { AnyArgument } from \"../../RootAstNodesBuilder\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A Condition leaf node.\n * This will succeed or fail immediately based on an agent predicate, without moving to the 'RUNNING' state.\n */\nexport default class Condition extends Leaf {\n /**\n * @param attributes The node attributes.\n * @param conditionName The name of the condition function.\n * @param conditionArguments The array of condition argument definitions.\n */\n constructor(attributes: Attribute[], private conditionName: string, private conditionArguments: AnyArgument[]) {\n super(\"condition\", attributes, conditionArguments);\n }\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // Attempt to get the invoker for the condition function.\n const conditionFuncInvoker = Lookup.getFuncInvoker(agent, this.conditionName);\n\n // The condition function should be defined.\n if (conditionFuncInvoker === null) {\n throw new Error(\n `cannot update condition node as the condition '${this.conditionName}' function is not defined on the agent and has not been registered`\n );\n }\n\n // Call the condition function to determine the state of this node.\n this.setState(!!conditionFuncInvoker(this.conditionArguments) ? State.SUCCEEDED : State.FAILED);\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => this.conditionName;\n}\n", "import Leaf from \"./Leaf\";\nimport State from \"../../State\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { Agent } from \"../../Agent\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A WAIT node.\n * The state of this node will change to SUCCEEDED after a duration of time\n */\nexport default class Wait extends Leaf {\n /**\n * @param attributes The node attributes.\n * @param duration The duration that this node will wait to succeed in milliseconds.\n * @param durationMin The minimum possible duration in milliseconds that this node will wait to succeed.\n * @param durationMax The maximum possible duration in milliseconds that this node will wait to succeed.\n */\n constructor(\n attributes: Attribute[],\n private duration: number | null,\n private durationMin: number | null,\n private durationMax: number | null\n ) {\n super(\"wait\", attributes, []);\n }\n\n /**\n * The time in milliseconds at which this node was first updated.\n */\n private initialUpdateTime: number = 0;\n\n /**\n * The total duration in milliseconds that this node will be waiting for.\n */\n private totalDuration: number | null = null;\n\n /**\n * The duration in milliseconds that this node has been waiting for.\n */\n private waitedDuration: number = 0;\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // If this node is in the READY state then we need to set the initial update time.\n if (this.is(State.READY)) {\n // Set the initial update time.\n this.initialUpdateTime = new Date().getTime();\n\n // Set the initial waited duration.\n this.waitedDuration = 0;\n\n // Are we dealing with an explicit duration or will we be randomly picking a duration between the min and max duration.\n if (this.duration !== null) {\n this.totalDuration = this.duration;\n } else if (this.durationMin !== null && this.durationMax !== null) {\n // We will be picking a random duration between a min and max duration, if the optional 'random' behaviour tree\n // function option is defined then we will be using that, otherwise we will fall back to using Math.random.\n const random = typeof options.random === \"function\" ? options.random : Math.random;\n\n // Pick a random duration between a min and max duration.\n this.totalDuration = Math.floor(\n random() * (this.durationMax - this.durationMin + 1) + this.durationMin\n );\n } else {\n this.totalDuration = null;\n }\n\n // The node is now running until we finish waiting.\n this.setState(State.RUNNING);\n }\n\n // If we have no total duration then this wait node will wait indefinitely until it is aborted.\n if (this.totalDuration === null) {\n return;\n }\n\n // If we have a 'getDeltaTime' function defined as part of our options then we will use it to figure out how long we have waited for.\n if (typeof options.getDeltaTime === \"function\") {\n // Get the delta time.\n const deltaTime = options.getDeltaTime();\n\n // Our delta time must be a valid number and cannot be NaN.\n if (typeof deltaTime !== \"number\" || isNaN(deltaTime)) {\n throw new Error(\"The delta time must be a valid number and not NaN.\");\n }\n\n // Update the amount of time that this node has been waiting for based on the delta time.\n this.waitedDuration += deltaTime * 1000;\n } else {\n // We are not using a delta time, so we will just work out hom much time has passed since the first update.\n this.waitedDuration = new Date().getTime() - this.initialUpdateTime;\n }\n\n // Have we waited long enough?\n if (this.waitedDuration >= this.totalDuration) {\n // We have finished waiting!\n this.setState(State.SUCCEEDED);\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => {\n if (this.duration !== null) {\n return `WAIT ${this.duration}ms`;\n } else if (this.durationMin !== null && this.durationMax !== null) {\n return `WAIT ${this.durationMin}ms-${this.durationMax}ms`;\n } else {\n return \"WAIT\";\n }\n };\n}\n", "import Node from \"../Node\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\n\n/**\n * A decorator node that wraps a single child node.\n */\nexport default abstract class Decorator extends Node {\n /**\n * @param type The node type.\n * @param attributes The node attributes.\n * @param child The child node.\n */\n constructor(type: string, attributes: Attribute[], protected child: Node) {\n super(type, attributes, []);\n }\n\n /**\n * Gets whether this node is a leaf node.\n */\n isLeafNode = () => false;\n\n /**\n * Gets the children of this node.\n */\n getChildren = () => [this.child];\n\n /**\n * Reset the state of the node.\n */\n reset = () => {\n // Reset the state of this node.\n this.setState(State.READY);\n\n // Reset the state of the child node.\n this.child.reset();\n };\n\n /**\n * Abort the running of this node.\n * @param agent The agent.\n */\n abort = (agent: Agent) => {\n // There is nothing to do if this node is not in the running state.\n if (!this.is(State.RUNNING)) {\n return;\n }\n\n // Abort the child node.\n this.child.abort(agent);\n\n // Reset the state of this node.\n this.reset();\n\n this.getAttribute(\"exit\")?.callAgentFunction(agent, false, true);\n };\n}\n", "import Node from \"../Node\";\nimport Decorator from \"./Decorator\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A Root node.\n * The root node will have a single child.\n */\nexport default class Root extends Decorator {\n /**\n * @param attributes The node attributes.\n * @param child The child node.\n */\n constructor(attributes: Attribute[], child: Node) {\n super(\"root\", attributes, child);\n }\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // If the child has never been updated or is running then we will need to update it now.\n if (this.child.getState() === State.READY || this.child.getState() === State.RUNNING) {\n // Update the child of this node.\n this.child.update(agent, options);\n }\n\n // The state of the root node is the state of its child.\n this.setState(this.child.getState());\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => \"ROOT\";\n}\n", "import Node from \"../Node\";\nimport Decorator from \"./Decorator\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A REPEAT node.\n * The node has a single child which can have:\n * -- A number of iterations for which to repeat the child node.\n * -- An infinite repeat loop if neither an iteration count or a condition function is defined.\n * The REPEAT node will stop and have a 'FAILED' state if its child is ever in a 'FAILED' state after an update.\n * The REPEAT node will attempt to move on to the next iteration if its child is ever in a 'SUCCEEDED' state.\n */\nexport default class Repeat extends Decorator {\n /**\n * @param attributes The node attributes.\n * @param iterations The number of iterations to repeat the child node.\n * @param iterationsMin The minimum possible number of iterations to repeat the child node.\n * @param iterationsMax The maximum possible number of iterations to repeat the child node.\n * @param child The child node.\n */\n constructor(\n attributes: Attribute[],\n private iterations: number | null,\n private iterationsMin: number | null,\n private iterationsMax: number | null,\n child: Node\n ) {\n super(\"repeat\", attributes, child);\n }\n\n /**\n * The number of target iterations to make.\n */\n private targetIterationCount: number | null = null;\n\n /**\n * The current iteration count.\n */\n private currentIterationCount: number = 0;\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // If this node is in the READY state then we need to reset the child and the target iteration count.\n if (this.is(State.READY)) {\n // Reset the child node.\n this.child.reset();\n\n // Reset the current iteration count.\n this.currentIterationCount = 0;\n\n // Set the target iteration count.\n this.setTargetIterationCount(options);\n }\n\n // Do a check to see if we can iterate. If we can then this node will move into the 'RUNNING' state.\n // If we cannot iterate then we have hit our target iteration count, which means that the node has succeeded.\n if (this.canIterate()) {\n // This node is in the running state and can do its initial iteration.\n this.setState(State.RUNNING);\n\n // We may have already completed an iteration, meaning that the child node will be in the SUCCEEDED state.\n // If this is the case then we will have to reset the child node now.\n if (this.child.getState() === State.SUCCEEDED) {\n this.child.reset();\n }\n\n // Update the child of this node.\n this.child.update(agent, options);\n\n // If the child moved into the FAILED state when we updated it then there is nothing left to do and this node has also failed.\n // If it has moved into the SUCCEEDED state then we have completed the current iteration.\n if (this.child.getState() === State.FAILED) {\n // The child has failed, meaning that this node has failed.\n this.setState(State.FAILED);\n\n return;\n } else if (this.child.getState() === State.SUCCEEDED) {\n // We have completed an iteration.\n this.currentIterationCount += 1;\n }\n } else {\n // This node is in the 'SUCCEEDED' state as we cannot iterate any more.\n this.setState(State.SUCCEEDED);\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => {\n if (this.iterations !== null) {\n return `REPEAT ${this.iterations}x`;\n } else if (this.iterationsMin !== null && this.iterationsMax !== null) {\n return `REPEAT ${this.iterationsMin}x-${this.iterationsMax}x`;\n } else {\n return \"REPEAT\";\n }\n };\n\n /**\n * Reset the state of the node.\n */\n reset = () => {\n // Reset the state of this node.\n this.setState(State.READY);\n\n // Reset the current iteration count.\n this.currentIterationCount = 0;\n\n // Reset the child node.\n this.child.reset();\n };\n\n /**\n * Gets whether an iteration can be made.\n * @returns Whether an iteration can be made.\n */\n private canIterate = () => {\n if (this.targetIterationCount !== null) {\n // We can iterate as long as we have not reached our target iteration count.\n return this.currentIterationCount < this.targetIterationCount;\n }\n\n // If neither an iteration count or a condition function were defined then we can iterate indefinitely.\n return true;\n };\n\n /**\n * Sets the target iteration count.\n * @param options The behaviour tree options object.\n */\n private setTargetIterationCount = (options: BehaviourTreeOptions) => {\n // Are we dealing with an explicit iteration count or will we be randomly picking a iteration count between the min and max iteration count.\n if (this.iterations !== null) {\n this.targetIterationCount = this.iterations;\n } else if (this.iterationsMin !== null && this.iterationsMax !== null) {\n // We will be picking a random iteration count between a min and max iteration count, if the optional 'random'\n // behaviour tree function option is defined then we will be using that, otherwise we will fall back to using Math.random.\n const random = typeof options.random === \"function\" ? options.random : Math.random;\n\n // Pick a random iteration count between a min and max iteration count.\n this.targetIterationCount = Math.floor(\n random() * (this.iterationsMax - this.iterationsMin + 1) + this.iterationsMin\n );\n } else {\n this.targetIterationCount = null;\n }\n };\n}\n", "import Node from \"../Node\";\nimport Decorator from \"./Decorator\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A RETRY node.\n * The node has a single child which can have:\n * -- A number of iterations for which to repeat the child node.\n * -- An infinite repeat loop if neither an iteration count or a condition function is defined.\n * The RETRY node will stop and have a 'SUCCEEDED' state if its child is ever in a 'SUCCEEDED' state after an update.\n * The RETRY node will attempt to move on to the next iteration if its child is ever in a 'FAILED' state.\n */\nexport default class Retry extends Decorator {\n /**\n * @param attributes The node attributes.\n * @param attempts The number of attempts to retry the child node.\n * @param attemptsMin The minimum possible number of attempts to retry the child node.\n * @param attemptsMax The maximum possible number of attempts to retry the child node.\n * @param child The child node.\n */\n constructor(\n attributes: Attribute[],\n private attempts: number | null,\n private attemptsMin: number | null,\n private attemptsMax: number | null,\n child: Node\n ) {\n super(\"retry\", attributes, child);\n }\n\n /**\n * The number of target attempts to make.\n */\n private targetAttemptCount: number | null = null;\n\n /**\n * The current attempt count.\n */\n private currentAttemptCount: number = 0;\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // If this node is in the READY state then we need to reset the child and the target attempt count.\n if (this.is(State.READY)) {\n // Reset the child node.\n this.child.reset();\n\n // Reset the current attempt count.\n this.currentAttemptCount = 0;\n\n // Set the target attempt count.\n this.setTargetAttemptCount(options);\n }\n\n // Do a check to see if we can attempt. If we can then this node will move into the 'RUNNING' state.\n // If we cannot attempt then we have hit our target attempt count, which means that the node has succeeded.\n if (this.canAttempt()) {\n // This node is in the running state and can do its initial attempt.\n this.setState(State.RUNNING);\n\n // We may have already completed an attempt, meaning that the child node will be in the FAILED state.\n // If this is the case then we will have to reset the child node now.\n if (this.child.getState() === State.FAILED) {\n this.child.reset();\n }\n\n // Update the child of this node.\n this.child.update(agent, options);\n\n // If the child moved into the SUCCEEDED state when we updated it then there is nothing left to do and this node has also succeeded.\n // If it has moved into the FAILED state then we have completed the current attempt.\n if (this.child.getState() === State.SUCCEEDED) {\n // The child has succeeded, meaning that this node has succeeded.\n this.setState(State.SUCCEEDED);\n\n return;\n } else if (this.child.getState() === State.FAILED) {\n // We have completed an attempt.\n this.currentAttemptCount += 1;\n }\n } else {\n // This node is in the 'FAILED' state as we cannot iterate any more.\n this.setState(State.FAILED);\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => {\n if (this.attempts !== null) {\n return `RETRY ${this.attempts}x`;\n } else if (this.attemptsMin !== null && this.attemptsMax !== null) {\n return `RETRY ${this.attemptsMin}x-${this.attemptsMax}x`;\n } else {\n return \"RETRY\";\n }\n };\n\n /**\n * Reset the state of the node.\n */\n reset = () => {\n // Reset the state of this node.\n this.setState(State.READY);\n\n // Reset the current attempt count.\n this.currentAttemptCount = 0;\n\n // Reset the child node.\n this.child.reset();\n };\n\n /**\n * Gets whether an attempt can be made.\n * @returns Whether an attempt can be made.\n */\n canAttempt = () => {\n if (this.targetAttemptCount !== null) {\n // We can attempt as long as we have not reached our target attempt count.\n return this.currentAttemptCount < this.targetAttemptCount;\n }\n\n // If neither an attempt count or a condition function were defined then we can attempt indefinitely.\n return true;\n };\n\n /**\n * Sets the target attempt count.\n * @param options The behaviour tree options object.\n */\n setTargetAttemptCount = (options: BehaviourTreeOptions) => {\n // Are we dealing with an explicit attempt count or will we be randomly picking an attempt count between the min and max attempt count.\n if (this.attempts !== null) {\n this.targetAttemptCount = this.attempts;\n } else if (this.attemptsMin !== null && this.attemptsMax !== null) {\n // We will be picking a random attempt count between a min and max attempt count, if the optional 'random'\n // behaviour tree function option is defined then we will be using that, otherwise we will fall back to using Math.random.\n const random = typeof options.random === \"function\" ? options.random : Math.random;\n\n // Pick a random attempt count between a min and max attempt count.\n this.targetAttemptCount = Math.floor(\n random() * (this.attemptsMax - this.attemptsMin + 1) + this.attemptsMin\n );\n } else {\n this.targetAttemptCount = null;\n }\n };\n}\n", "import Decorator from \"./Decorator\";\nimport State from \"../../State\";\nimport Node from \"../Node\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A Flip node.\n * This node wraps a single child and will flip the state of the child state.\n */\nexport default class Flip extends Decorator {\n /**\n * @param attributes The node attributes.\n * @param child The child node.\n */\n constructor(attributes: Attribute[], child: Node) {\n super(\"flip\", attributes, child);\n }\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // If the child has never been updated or is running then we will need to update it now.\n if (this.child.getState() === State.READY || this.child.getState() === State.RUNNING) {\n this.child.update(agent, options);\n }\n\n // The state of this node will depend in the state of its child.\n switch (this.child.getState()) {\n case State.RUNNING:\n this.setState(State.RUNNING);\n break;\n\n case State.SUCCEEDED:\n this.setState(State.FAILED);\n break;\n\n case State.FAILED:\n this.setState(State.SUCCEEDED);\n break;\n\n default:\n this.setState(State.READY);\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => \"FLIP\";\n}\n", "import Node from \"../Node\";\nimport Decorator from \"./Decorator\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A Succeed node.\n * This node wraps a single child and will always move to the 'SUCCEEDED' state when the child moves to a 'SUCCEEDED' or 'FAILED' state.\n */\nexport default class Succeed extends Decorator {\n /**\n * @param attributes The node attributes.\n * @param child The child node.\n */\n constructor(attributes: Attribute[], child: Node) {\n super(\"succeed\", attributes, child);\n }\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // If the child has never been updated or is running then we will need to update it now.\n if (this.child.getState() === State.READY || this.child.getState() === State.RUNNING) {\n this.child.update(agent, options);\n }\n\n // The state of this node will depend in the state of its child.\n switch (this.child.getState()) {\n case State.RUNNING:\n this.setState(State.RUNNING);\n break;\n\n case State.SUCCEEDED:\n case State.FAILED:\n this.setState(State.SUCCEEDED);\n break;\n\n default:\n this.setState(State.READY);\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => \"SUCCEED\";\n}\n", "import Node from \"../Node\";\nimport Decorator from \"./Decorator\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A Fail node.\n * This node wraps a single child and will always move to the 'FAILED' state when the child moves to a 'SUCCEEDED' or 'FAILED' state.\n */\nexport default class Fail extends Decorator {\n /**\n * @param attributes The node attributes.\n * @param child The child node.\n */\n constructor(attributes: Attribute[], child: Node) {\n super(\"fail\", attributes, child);\n }\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // If the child has never been updated or is running then we will need to update it now.\n if (this.child.getState() === State.READY || this.child.getState() === State.RUNNING) {\n this.child.update(agent, options);\n }\n\n // The state of this node will depend in the state of its child.\n switch (this.child.getState()) {\n case State.RUNNING:\n this.setState(State.RUNNING);\n break;\n\n case State.SUCCEEDED:\n case State.FAILED:\n this.setState(State.FAILED);\n break;\n\n default:\n this.setState(State.READY);\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => \"FAIL\";\n}\n", "import createLotto from \"lotto-draw\";\n\nimport Node from \"../Node\";\nimport Composite from \"./Composite\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A LOTTO node.\n * A winning child is picked on the initial update of this node, based on ticket weighting.\n * The state of this node will match the state of the winning child.\n */\nexport default class Lotto extends Composite {\n /**\n * @param attributes The node attributes.\n * @param tickets The child node tickets.\n * @param children The child nodes.\n */\n constructor(attributes: Attribute[], private tickets: number[], children: Node[]) {\n super(\"lotto\", attributes, children);\n }\n\n /**\n * The child node selected to be the active one.\n */\n private selectedChild: Node | undefined;\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // If this node is in the READY state then we need to pick a winning child node.\n if (this.is(State.READY)) {\n // Create a lotto draw with which to randomly pick a child node to become the active one.\n const lottoDraw = createLotto({\n // Hook up the optional 'random' behaviour tree function option to the one used by 'lotto-draw'.\n random: options.random,\n // Pass in each child node as a participant in the lotto draw with their respective ticket count.\n participants: this.children.map((child, index) => [child, this.tickets[index] || 1])\n });\n\n // Randomly pick a child based on ticket weighting, this will become the active child for this composite node.\n this.selectedChild = lottoDraw.draw() || undefined;\n }\n\n // If something went wrong and we don't have an active child then we should throw an error.\n if (!this.selectedChild) {\n throw new Error(\"failed to update lotto node as it has no active child\");\n }\n\n // If the selected child has never been updated or is running then we will need to update it now.\n if (this.selectedChild.getState() === State.READY || this.selectedChild.getState() === State.RUNNING) {\n this.selectedChild.update(agent, options);\n }\n\n // The state of the lotto node is the state of its selected child.\n this.setState(this.selectedChild.getState());\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => (this.tickets.length ? `LOTTO [${this.tickets.join(\",\")}]` : \"LOTTO\");\n}\n", "import Node from \"../Node\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\n\n/**\n * A composite node that wraps child nodes.\n */\nexport default abstract class Composite extends Node {\n /**\n * @param type The node type.\n * @param attributes The node attributes.\n * @param children The child nodes.\n */\n constructor(type: string, attributes: Attribute[], protected children: Node[]) {\n super(type, attributes, []);\n }\n\n /**\n * Gets whether this node is a leaf node.\n */\n isLeafNode = () => false;\n\n /**\n * Gets the children of this node.\n */\n getChildren = () => this.children;\n\n /**\n * Reset the state of the node.\n */\n reset = () => {\n // Reset the state of this node.\n this.setState(State.READY);\n\n // Reset the state of any child nodes.\n this.getChildren().forEach((child) => child.reset());\n };\n\n /**\n * Abort the running of this node.\n * @param agent The agent.\n */\n abort = (agent: Agent) => {\n // There is nothing to do if this node is not in the running state.\n if (!this.is(State.RUNNING)) {\n return;\n }\n\n // Abort any child nodes.\n this.getChildren().forEach((child) => child.abort(agent));\n\n // Reset the state of this node.\n this.reset();\n\n this.getAttribute(\"exit\")?.callAgentFunction(agent, false, true);\n };\n}\n", "import Composite from \"./Composite\";\nimport Node from \"../Node\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A SELECTOR node.\n * The child nodes are executed in sequence until one succeeds or all fail.\n */\nexport default class Selector extends Composite {\n /**\n * @param attributes The node attributes.\n * @param children The child nodes.\n */\n constructor(attributes: Attribute[], protected children: Node[]) {\n super(\"selector\", attributes, children);\n }\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // Iterate over all of the children of this node.\n for (const child of this.children) {\n // If the child has never been updated or is running then we will need to update it now.\n if (child.getState() === State.READY || child.getState() === State.RUNNING) {\n // Update the child of this node.\n child.update(agent, options);\n }\n\n // If the current child has a state of 'SUCCEEDED' then this node is also a 'SUCCEEDED' node.\n if (child.getState() === State.SUCCEEDED) {\n // This node is a 'SUCCEEDED' node.\n this.setState(State.SUCCEEDED);\n\n // There is no need to check the rest of the selector nodes.\n return;\n }\n\n // If the current child has a state of 'FAILED' then we should move on to the next child.\n if (child.getState() === State.FAILED) {\n // Find out if the current child is the last one in the selector.\n // If it is then this sequence node has also failed.\n if (this.children.indexOf(child) === this.children.length - 1) {\n // This node is a 'FAILED' node.\n this.setState(State.FAILED);\n\n // There is no need to check the rest of the selector as we have completed it.\n return;\n } else {\n // The child node failed, try the next one.\n continue;\n }\n }\n\n // The node should be in the 'RUNNING' state.\n if (child.getState() === State.RUNNING) {\n // This node is a 'RUNNING' node.\n this.setState(State.RUNNING);\n\n // There is no need to check the rest of the selector as the current child is still running.\n return;\n }\n\n // The child node was not in an expected state.\n throw new Error(\"child node was not in an expected state.\");\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => \"SELECTOR\";\n}\n", "import Composite from \"./Composite\";\nimport Node from \"../Node\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A SEQUENCE node.\n * The child nodes are executed in sequence until one fails or all succeed.\n */\nexport default class Sequence extends Composite {\n /**\n * @param attributes The node attributes.\n * @param children The child nodes.\n */\n constructor(attributes: Attribute[], protected children: Node[]) {\n super(\"sequence\", attributes, children);\n }\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // Iterate over all of the children of this node.\n for (const child of this.children) {\n // If the child has never been updated or is running then we will need to update it now.\n if (child.getState() === State.READY || child.getState() === State.RUNNING) {\n // Update the child of this node.\n child.update(agent, options);\n }\n\n // If the current child has a state of 'SUCCEEDED' then we should move on to the next child.\n if (child.getState() === State.SUCCEEDED) {\n // Find out if the current child is the last one in the sequence.\n // If it is then this sequence node has also succeeded.\n if (this.children.indexOf(child) === this.children.length - 1) {\n // This node is a 'SUCCEEDED' node.\n this.setState(State.SUCCEEDED);\n\n // There is no need to check the rest of the sequence as we have completed it.\n return;\n } else {\n // The child node succeeded, but we have not finished the sequence yet.\n continue;\n }\n }\n\n // If the current child has a state of 'FAILED' then this node is also a 'FAILED' node.\n if (child.getState() === State.FAILED) {\n // This node is a 'FAILED' node.\n this.setState(State.FAILED);\n\n // There is no need to check the rest of the sequence.\n return;\n }\n\n // The node should be in the 'RUNNING' state.\n if (child.getState() === State.RUNNING) {\n // This node is a 'RUNNING' node.\n this.setState(State.RUNNING);\n\n // There is no need to check the rest of the sequence as the current child is still running.\n return;\n }\n\n // The child node was not in an expected state.\n throw new Error(\"child node was not in an expected state.\");\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => \"SEQUENCE\";\n}\n", "import Composite from \"./Composite\";\nimport State from \"../../State\";\nimport Node from \"../Node\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A PARALLEL node.\n * The child nodes are executed concurrently until one fails or all succeed.\n */\nexport default class Parallel extends Composite {\n /**\n * @param attributes The node attributes.\n * @param children The child nodes.\n */\n constructor(attributes: Attribute[], children: Node[]) {\n super(\"parallel\", attributes, children);\n }\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // Keep a count of the number of succeeded child nodes.\n let succeededCount = 0;\n\n let hasChildFailed = false;\n\n // Iterate over all of the children of this node.\n for (const child of this.children) {\n // If the child has never been updated or is running then we will need to update it now.\n if (child.getState() === State.READY || child.getState() === State.RUNNING) {\n // Update the child of this node.\n child.update(agent, options);\n }\n\n // If the current child has a state of 'SUCCEEDED' then we should move on to the next child.\n if (child.getState() === State.SUCCEEDED) {\n // The child node has succeeded, keep track of this to determine if all children have.\n succeededCount++;\n\n // The child node succeeded, but we have not finished checking every child node yet.\n continue;\n }\n\n // If the current child has a state of 'FAILED' then this node is also a 'FAILED' node.\n if (child.getState() === State.FAILED) {\n hasChildFailed = true;\n\n // There is no need to check the rest of the children.\n break;\n }\n\n // The node should be in the 'RUNNING' state.\n if (child.getState() !== State.RUNNING) {\n // The child node was not in an expected state.\n throw new Error(\"child node was not in an expected state.\");\n }\n }\n\n if (hasChildFailed) {\n // This node is a 'FAILED' node.\n this.setState(State.FAILED);\n\n // Abort every running child.\n for (const child of this.children) {\n if (child.getState() === State.RUNNING) {\n child.abort(agent);\n }\n }\n } else {\n // If all children have succeeded then this node has also succeeded, otherwise it is still running.\n this.setState(succeededCount === this.children.length ? State.SUCCEEDED : State.RUNNING);\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => \"PARALLEL\";\n}\n", "import { AnyArgument } from \"../RootAstNodesBuilder\";\nimport Guard from \"./guards/Guard\";\n\nexport type AttributeDetails = {\n /** The attribute type. */\n type: string;\n\n /** The attribute arguments. */\n args: AnyArgument[];\n};\n\n/**\n * A base node attribute.\n */\nexport default abstract class Attribute {\n /**\n * @param type The node attribute type.\n * @param args The array of attribute argument definitions.\n */\n constructor(protected type: string, protected args: AnyArgument[]) {}\n\n /**\n * Gets the type of the attribute.\n */\n getType = () => this.type;\n\n /**\n * Gets the array of attribute argument definitions.\n */\n getArguments = () => this.args;\n\n /**\n * Gets the attribute details.\n */\n abstract getDetails(): TAttributeDetails;\n\n /**\n * Gets whether this attribute is a guard.\n */\n abstract isGuard: () => this is Guard;\n}\n", "import { Agent } from \"../../Agent\";\nimport { AnyArgument } from \"../../RootAstNodesBuilder\";\nimport Attribute, { AttributeDetails } from \"../Attribute\";\n\nexport type GuardAttributeDetails = {\n /** The name of the condition function that determines whether the guard is satisfied. */\n condition: string;\n} & AttributeDetails;\n\n/**\n * A base node guard attribute.\n */\nexport default abstract class Guard extends Attribute {\n /**\n * @param type The node attribute type.\n * @param args The array of decorator argument definitions.\n * @param condition The name of the condition function that determines whether the guard is satisfied.\n */\n constructor(type: string, args: AnyArgument[], private condition: string) {\n super(type, args);\n }\n\n /**\n * Gets the name of the condition function that determines whether the guard is satisfied.\n */\n getCondition = () => this.condition;\n\n /**\n * Gets whether this attribute is a guard.\n */\n isGuard = () => true;\n\n /**\n * Gets the attribute details.\n */\n getDetails(): GuardAttributeDetails {\n return {\n type: this.getType(),\n args: this.getArguments(),\n condition: this.getCondition()\n };\n }\n\n /**\n * Gets whether the guard is satisfied.\n * @param agent The agent.\n * @returns Whether the guard is satisfied.\n */\n abstract isSatisfied(agent: Agent): boolean;\n}\n", "import Guard from \"./Guard\";\nimport Lookup from \"../../Lookup\";\nimport { Agent } from \"../../Agent\";\nimport { AnyArgument } from \"../../RootAstNodesBuilder\";\n\n/**\n * A WHILE guard which is satisfied as long as the given condition remains true.\n */\nexport default class While extends Guard {\n /**\n * @param condition The name of the condition function that determines whether the guard is satisfied.\n * @param args The array of decorator argument definitions.\n */\n constructor(condition: string, args: AnyArgument[]) {\n super(\"while\", args, condition);\n }\n\n /**\n * Gets whether the guard is satisfied.\n * @param agent The agent.\n * @returns Whether the guard is satisfied.\n */\n isSatisfied = (agent: Agent) => {\n // Attempt to get the invoker for the condition function.\n const conditionFuncInvoker = Lookup.getFuncInvoker(agent, this.getCondition());\n\n // The condition function should be defined.\n if (conditionFuncInvoker === null) {\n throw new Error(\n `cannot evaluate node guard as the condition '${this.getCondition()}' function is not defined on the agent and has not been registered`\n );\n }\n\n // Call the condition function to determine whether this guard is satisfied.\n return !!conditionFuncInvoker(this.args);\n };\n}\n", "import Guard from \"./Guard\";\nimport Lookup from \"../../Lookup\";\nimport { Agent } from \"../../Agent\";\nimport { AnyArgument } from \"../../RootAstNodesBuilder\";\n\n/**\n * An UNTIL guard which is satisfied as long as the given condition remains false.\n */\nexport default class Until extends Guard {\n /**\n * @param condition The name of the condition function that determines whether the guard is satisfied.\n * @param args The array of decorator argument definitions.\n */\n constructor(condition: string, args: AnyArgument[]) {\n super(\"until\", args, condition);\n }\n\n /**\n * Gets whether the guard is satisfied.\n * @param agent The agent.\n * @returns Whether the guard is satisfied.\n */\n isSatisfied = (agent: Agent) => {\n // Attempt to get the invoker for the condition function.\n const conditionFuncInvoker = Lookup.getFuncInvoker(agent, this.getCondition());\n\n // The condition function should be defined.\n if (conditionFuncInvoker === null) {\n throw new Error(\n `cannot evaluate node guard as the condition '${this.getCondition()}' function is not defined on the agent and has not been registered`\n );\n }\n\n // Call the condition function to determine whether this guard is satisfied.\n return !!!conditionFuncInvoker(this.args);\n };\n}\n", "import { Agent } from \"../../Agent\";\nimport { AnyArgument } from \"../../RootAstNodesBuilder\";\nimport Attribute, { AttributeDetails } from \"../Attribute\";\n\nexport type CallbackAttributeDetails = {\n /** The name of the agent function that is called. */\n functionName: string;\n} & AttributeDetails;\n\n/**\n * A base node callback attribute.\n */\nexport default abstract class Callback extends Attribute {\n /**\n * @param type The node attribute type.\n * @param args The array of decorator argument definitions.\n * @param functionName The name of the agent function to call.\n */\n constructor(type: string, args: AnyArgument[], private functionName: string) {\n super(type, args);\n }\n\n /**\n * Gets the name of the agent function to call.\n */\n getFunctionName = () => this.functionName;\n\n /**\n * Gets whether this attribute is a guard.\n */\n isGuard = () => false;\n\n /**\n * Gets the attribute details.\n */\n getDetails(): CallbackAttributeDetails {\n return {\n type: this.getType(),\n args: this.getArguments(),\n functionName: this.getFunctionName()\n };\n }\n\n /**\n * Attempt to call the agent function that this callback refers to.\n * @param agent The agent.\n */\n abstract callAgentFunction: (agent: Agent, isSuccess: boolean, isAborted: boolean) => void;\n}\n", "import Callback from \"./Callback\";\nimport Lookup from \"../../Lookup\";\nimport { Agent } from \"../../Agent\";\nimport { AnyArgument } from \"../../RootAstNodesBuilder\";\n\n/**\n * An ENTRY callback which defines an agent function to call when the associated node is updated and moves out of running state.\n */\nexport default class Entry extends Callback {\n /**\n * @param functionName The name of the agent function to call.\n * @param args The array of callback argument definitions.\n */\n constructor(functionName: string, args: AnyArgument[]) {\n super(\"entry\", args, functionName);\n }\n\n /**\n * Attempt to call the agent function that this callback refers to.\n * @param agent The agent.\n */\n callAgentFunction = (agent: Agent) => {\n // Attempt to get the invoker for the callback function.\n const callbackFuncInvoker = Lookup.getFuncInvoker(agent, this.getFunctionName());\n\n // The callback function should be defined.\n if (callbackFuncInvoker === null) {\n throw new Error(\n `cannot call entry function '${this.getFunctionName()}' as is not defined on the agent and has not been registered`\n );\n }\n\n // Call the callback function.\n callbackFuncInvoker(this.args);\n };\n}\n", "import Callback from \"./Callback\";\nimport Lookup, { AnyExitArgument } from \"../../Lookup\";\nimport { Agent } from \"../../Agent\";\nimport { AnyArgument } from \"../../RootAstNodesBuilder\";\n\n/**\n * An EXIT callback which defines an agent function to call when the associated node is updated and moves to a finished state or is aborted.\n */\nexport default class Exit extends Callback {\n /**\n * @param functionName The name of the agent function to call.\n * @param args The array of callback argument definitions.\n */\n constructor(functionName: string, args: AnyArgument[]) {\n super(\"exit\", args, functionName);\n }\n\n /**\n * Attempt to call the agent function that this callback refers to.\n * @param agent The agent.\n * @param isSuccess Whether the decorated node was left with a success state.\n * @param isAborted Whether the decorated node was aborted.\n */\n callAgentFunction = (agent: Agent, isSuccess: boolean, isAborted: boolean) => {\n // Attempt to get the invoker for the callback function.\n const callbackFuncInvoker = Lookup.getFuncInvoker(agent, this.getFunctionName());\n\n // The callback function should be defined.\n if (callbackFuncInvoker === null) {\n throw new Error(\n `cannot call exit function '${this.getFunctionName()}' as is not defined on the agent and has not been registered`\n );\n }\n\n // Call the callback function\n callbackFuncInvoker([{ value: { succeeded: isSuccess, aborted: isAborted } }, ...this.args]);\n };\n}\n", "import Callback from \"./Callback\";\nimport Lookup from \"../../Lookup\";\nimport { Agent } from \"../../Agent\";\nimport { AnyArgument } from \"../../RootAstNodesBuilder\";\n\n/**\n * A STEP callback which defines an agent function to call when the associated node is updated.\n */\nexport default class Step extends Callback {\n /**\n * @param functionName The name of the agent function to call.\n * @param args The array of callback argument definitions.\n */\n constructor(functionName: string, args: AnyArgument[]) {\n super(\"step\", args, functionName);\n }\n\n /**\n * Attempt to call the agent function that this callback refers to.\n * @param agent The agent.\n */\n callAgentFunction = (agent: Agent) => {\n // Attempt to get the invoker for the callback function.\n const callbackFuncInvoker = Lookup.getFuncInvoker(agent, this.getFunctionName());\n\n // The callback function should be defined.\n if (callbackFuncInvoker === null) {\n throw new Error(\n `cannot call step function '${this.getFunctionName()}' as is not defined on the agent and has not been registered`\n );\n }\n\n // Call the callback function.\n callbackFuncInvoker(this.args);\n };\n}\n", "import Action from \"./nodes/leaf/Action\";\nimport Condition from \"./nodes/leaf/Condition\";\nimport Wait from \"./nodes/leaf/Wait\";\nimport Root from \"./nodes/decorator/Root\";\nimport Repeat from \"./nodes/decorator/Repeat\";\nimport Retry from \"./nodes/decorator/Retry\";\nimport Flip from \"./nodes/decorator/Flip\";\nimport Succeed from \"./nodes/decorator/Succeed\";\nimport Fail from \"./nodes/decorator/Fail\";\nimport Lotto from \"./nodes/composite/Lotto\";\nimport Selector from \"./nodes/composite/Selector\";\nimport Sequence from \"./nodes/composite/Sequence\";\nimport Parallel from \"./nodes/composite/Parallel\";\nimport Node from \"./nodes/Node\";\nimport While from \"./attributes/guards/While\";\nimport Until from \"./attributes/guards/Until\";\nimport Entry from \"./attributes/callbacks/Entry\";\nimport Exit from \"./attributes/callbacks/Exit\";\nimport Step from \"./attributes/callbacks/Step\";\nimport Callback from \"./attributes/callbacks/Callback\";\nimport Guard from \"./attributes/guards/Guard\";\nimport Attribute from \"./attributes/Attribute\";\nimport Composite from \"./nodes/composite/Composite\";\nimport Decorator from \"./nodes/decorator/Decorator\";\nimport Leaf from \"./nodes/leaf/Leaf\";\n\nexport type Argument = {\n value: T;\n type: string; // Used for validation.\n};\ntype NullArgument = Argument & {\n type: \"null\";\n};\ntype BooleanArgument = Argument & {\n type: \"boolean\";\n};\ntype NumberArgument = Argument & {\n type: \"number\";\n isInteger: boolean; // Used for validation.\n};\ntype StringPlaceholderArgument = Argument & {\n type: \"string\";\n};\ntype IdentifierArgument = Argument & {\n type: \"identifier\";\n};\nexport type AnyArgument =\n | NullArgument\n | BooleanArgument\n | NumberArgument\n | StringPlaceholderArgument\n | IdentifierArgument;\n\n/**\n * The node attribute factories.\n */\nconst AttributeFactories: {\n [key: string]: (functionName: string, attributeArguments: AnyArgument[]) => Callback | Guard;\n} = {\n WHILE: (condition: string, attributeArguments: AnyArgument[]) => new While(condition, attributeArguments),\n UNTIL: (condition: string, attributeArguments: AnyArgument[]) => new Until(condition, attributeArguments),\n ENTRY: (functionName: string, attributeArguments: AnyArgument[]) => new Entry(functionName, attributeArguments),\n EXIT: (functionName: string, attributeArguments: AnyArgument[]) => new Exit(functionName, attributeArguments),\n STEP: (functionName: string, attributeArguments: AnyArgument[]) => new Step(functionName, attributeArguments)\n};\n\ntype Validatable = {\n children?: AstNode[];\n validate: (depth: number) => void;\n};\n\ntype NodeInstanceCreator = (\n namedRootNodeProvider: (name: string) => RootAstNode,\n visitedBranches: string[]\n) => T;\n\nexport type AstNode = Validatable & {\n type: string;\n createNodeInstance: NodeInstanceCreator;\n};\n\nexport type LeafAstNode = AstNode & {\n type: \"action\" | \"condition\" | \"wait\";\n attributes: Attribute[];\n};\n\nexport type CompositeAstNode = AstNode & {\n type: \"lotto\" | \"parallel\" | \"selector\" | \"sequence\";\n attributes: Attribute[];\n children: AstNode[];\n};\n\nexport type DecoratorAstNode = AstNode & {\n type: \"fail\" | \"flip\" | \"repeat\" | \"retry\" | \"root\" | \"succeed\";\n attributes: Attribute[];\n children: AstNode[];\n};\n\nexport type BranchAstNode = AstNode & {\n type: \"branch\";\n branchName: \"\" | string;\n};\n\nexport type LottoAstNode = CompositeAstNode & {\n type: \"lotto\";\n tickets: number[];\n};\n\nexport type RootAstNode = DecoratorAstNode & {\n type: \"root\";\n name: null | string;\n};\n\nexport type RepeatAstNode = DecoratorAstNode & {\n type: \"repeat\";\n iterations: number | null;\n iterationsMin: number | null;\n iterationsMax: number | null;\n};\n\nexport type RetryAstNode = DecoratorAstNode & {\n type: \"retry\";\n attempts: number | null;\n attemptsMin: number | null;\n attemptsMax: number | null;\n};\n\nexport type ActionAstNode = LeafAstNode & {\n type: \"action\";\n actionName: string;\n actionArguments: AnyArgument[];\n};\n\nexport type ConditionAstNode = LeafAstNode & {\n type: \"condition\";\n conditionName: string;\n conditionArguments: AnyArgument[];\n};\n\nexport type WaitAstNode = LeafAstNode & {\n type: \"wait\";\n duration: number | null;\n durationMin: number | null;\n durationMax: number | null;\n};\n\nexport type AnyAstNode =\n | BranchAstNode\n | CompositeAstNode\n | LottoAstNode\n | DecoratorAstNode\n | RootAstNode\n | RepeatAstNode\n | RetryAstNode\n | LeafAstNode\n | ActionAstNode\n | ConditionAstNode\n | WaitAstNode;\n\n/**\n * The AST node factories.\n */\nconst ASTNodeFactories = {\n ROOT: (): RootAstNode => ({\n type: \"root\",\n attributes: [],\n name: null,\n children: [],\n validate(depth: number) {\n // A root node cannot be the child of another node.\n if (depth > 1) {\n throw new Error(\"a root node cannot be the child of another node\");\n }\n\n // A root node must have a single child node.\n if (this.children.length !== 1) {\n throw new Error(\"a root node must have a single child\");\n }\n },\n createNodeInstance(namedRootNodeProvider, visitedBranches) {\n return new Root(\n this.attributes,\n this.children![0].createNodeInstance(namedRootNodeProvider, visitedBranches.slice())\n );\n }\n }),\n BRANCH: (): BranchAstNode => ({\n type: \"branch\",\n branchName: \"\",\n validate() {},\n createNodeInstance(namedRootNodeProvider, visitedBranches) {\n // Try to find the root node with a matching branch name.\n const targetRootNode = namedRootNodeProvider(this.branchName);\n\n // If we have already visited this branch then we have a circular dependency.\n if (visitedBranches.indexOf(this.branchName) !== -1) {\n throw new Error(`circular dependency found in branch node references for branch '${this.branchName}'`);\n }\n\n // If we have a target root node, then the node instance we want will be the first and only child of the referenced root node.\n if (targetRootNode) {\n return targetRootNode\n .createNodeInstance(namedRootNodeProvider, visitedBranches.concat(this.branchName))\n .getChildren()[0];\n } else {\n throw new Error(`branch references root node '${this.branchName}' which has not been defined`);\n }\n }\n }),\n SELECTOR: (): CompositeAstNode => ({\n type: \"selector\",\n attributes: [],\n children: [],\n validate() {\n // A selector node must have at least a single node.\n if (this.children.length < 1) {\n throw new Error(\"a selector node must have at least a single child\");\n }\n },\n createNodeInstance(namedRootNodeProvider, visitedBranches) {\n return new Selector(\n this.attributes,\n this.children.map((child) => child.createNodeInstance(namedRootNodeProvider, visitedBranches.slice()))\n );\n }\n }),\n SEQUENCE: (): CompositeAstNode => ({\n type: \"sequence\",\n attributes: [],\n children: [],\n validate() {\n // A sequence node must have at least a single node.\n if (this.children.length < 1) {\n throw new Error(\"a sequence node must have at least a single child\");\n }\n },\n createNodeInstance(namedRootNodeProvider, visitedBranches) {\n return new Sequence(\n this.attributes,\n this.children.map((child) => child.createNodeInstance(namedRootNodeProvider, visitedBranches.slice()))\n );\n }\n }),\n PARALLEL: (): CompositeAstNode => ({\n type: \"parallel\",\n attributes: [],\n children: [],\n validate() {\n // A parallel node must have at least a single node.\n if (this.children.length < 1) {\n throw new Error(\"a parallel node must have at least a single child\");\n }\n },\n createNodeInstance(namedRootNodeProvider, visitedBranches) {\n return new Parallel(\n this.attributes,\n this.children.map((child) => child.createNodeInstance(namedRootNodeProvider, visitedBranches.slice()))\n );\n }\n }),\n LOTTO: (): LottoAstNode => ({\n type: \"lotto\",\n attributes: [],\n children: [],\n tickets: [],\n validate() {\n // A lotto node must have at least a single node.\n if (this.children!.length < 1) {\n throw new Error(\"a lotto node must have at least a single child\");\n }\n },\n createNodeInstance(namedRootNodeProvider, visitedBranches) {\n return new Lotto(\n this.attributes,\n this.tickets!,\n this.children!.map((child) => child.createNodeInstance(namedRootNodeProvider, visitedBranches.slice()))\n );\n }\n }),\n REPEAT: (): RepeatAstNode => ({\n type: \"repeat\",\n attributes: [],\n iterations: null,\n iterationsMin: null,\n iterationsMax: null,\n children: [],\n validate() {\n // A repeat node must have a single node.\n if (this.children!.length !== 1) {\n throw new Error(\"a repeat node must have a single child\");\n }\n\n if (this.iterations !== null) {\n // A repeat node must have a positive number of iterations if defined.\n if (this.iterations < 0) {\n throw new Error(\"a repeat node must have a positive number of iterations if defined\");\n }\n } else if (this.iterationsMin !== null && this.iterationsMax !== null) {\n // A repeat node must have a positive min and max iteration count if they are defined.\n if (this.iterationsMin < 0 || this.iterationsMax < 0) {\n throw new Error(\n \"a repeat node must have a positive minimum and maximum iteration count if defined\"\n );\n }\n\n // A repeat node must not have an minimum iteration count that exceeds the maximum iteration count.\n if (this.iterationsMin > this.iterationsMax) {\n throw new Error(\n \"a repeat node must not have a minimum iteration count that exceeds the maximum iteration count\"\n );\n }\n } else {\n // If we have no explicit iteration count or a minimum and maximum iteration count set then we are dealing with a repeat node that iterates indefinitely.\n }\n },\n createNodeInstance(namedRootNodeProvider, visitedBranches) {\n return new Repeat(\n this.attributes,\n this.iterations,\n this.iterationsMin,\n this.iterationsMax,\n this.children![0].createNodeInstance(namedRootNodeProvider, visitedBranches.slice())\n );\n }\n }),\n RETRY: (): RetryAstNode => ({\n type: \"retry\",\n attributes: [],\n attempts: null,\n attemptsMin: null,\n attemptsMax: null,\n children: [],\n validate() {\n // A retry node must have a single node.\n if (this.children!.length !== 1) {\n throw new Error(\"a retry node must have a single child\");\n }\n\n if (this.attempts !== null) {\n // A retry node must have a positive number of attempts if defined.\n if (this.attempts < 0) {\n throw new Error(\"a retry node must have a positive number of attempts if defined\");\n }\n } else if (this.attemptsMin !== null && this.attemptsMax !== null) {\n // A retry node must have a positive min and max attempts count if they are defined.\n if (this.attemptsMin < 0 || this.attemptsMax < 0) {\n throw new Error(\"a retry node must have a positive minimum and maximum attempt count if defined\");\n }\n\n // A retry node must not have a minimum attempt count that exceeds the maximum attempt count.\n if (this.attemptsMin > this.attemptsMax) {\n throw new Error(\n \"a retry node must not have a minimum attempt count that exceeds the maximum attempt count\"\n );\n }\n } else {\n // If we have no explicit attempt count or a minimum and maximum attempt count set then we are dealing with a retry node that attempts indefinitely.\n }\n },\n createNodeInstance(namedRootNodeProvider, visitedBranches) {\n return new Retry(\n this.attributes,\n this.attempts,\n this.attemptsMin,\n this.attemptsMax,\n this.children![0].createNodeInstance(namedRootNodeProvider, visitedBranches.slice())\n );\n }\n }),\n FLIP: (): DecoratorAstNode => ({\n type: \"flip\",\n attributes: [],\n children: [],\n validate() {\n // A flip node must have a single node.\n if (this.children!.length !== 1) {\n throw new Error(\"a flip node must have a single child\");\n }\n },\n createNodeInstance(namedRootNodeProvider, visitedBranches) {\n return new Flip(\n this.attributes,\n this.children![0].createNodeInstance(namedRootNodeProvider, visitedBranches.slice())\n );\n }\n }),\n SUCCEED: (): DecoratorAstNode => ({\n type: \"succeed\",\n attributes: [],\n children: [],\n validate() {\n // A succeed node must have a single node.\n if (this.children!.length !== 1) {\n throw new Error(\"a succeed node must have a single child\");\n }\n },\n createNodeInstance(namedRootNodeProvider, visitedBranches) {\n return new Succeed(\n this.attributes,\n this.children![0].createNodeInstance(namedRootNodeProvider, visitedBranches.slice())\n );\n }\n }),\n FAIL: (): DecoratorAstNode => ({\n type: \"fail\",\n attributes: [],\n children: [],\n validate() {\n // A fail node must have a single node.\n if (this.children!.length !== 1) {\n throw new Error(\"a fail node must have a single child\");\n }\n },\n createNodeInstance(namedRootNodeProvider, visitedBranches) {\n return new Fail(\n this.attributes,\n this.children![0].createNodeInstance(namedRootNodeProvider, visitedBranches.slice())\n );\n }\n }),\n WAIT: (): WaitAstNode => ({\n type: \"wait\",\n attributes: [],\n duration: null,\n durationMin: null,\n durationMax: null,\n validate() {\n if (this.duration !== null) {\n // If an explict duration was defined then it must be a positive number.\n if (this.duration < 0) {\n throw new Error(\"a wait node must have a positive duration\");\n }\n } else if (this.durationMin !== null && this.durationMax !== null) {\n // A wait node must have a positive min and max duration.\n if (this.durationMin < 0 || this.durationMax < 0) {\n throw new Error(\"a wait node must have a positive minimum and maximum duration\");\n }\n\n // A wait node must not have a minimum duration that exceeds the maximum duration.\n if (this.durationMin > this.durationMax) {\n throw new Error(\"a wait node must not have a minimum duration that exceeds the maximum duration\");\n }\n } else {\n // If we have no explicit duration or duration bounds set then we are dealing with a wait node that waits indefinitely.\n }\n },\n createNodeInstance() {\n return new Wait(this.attributes, this.duration, this.durationMin, this.durationMax);\n }\n }),\n ACTION: (): ActionAstNode => ({\n type: \"action\",\n attributes: [],\n actionName: \"\",\n actionArguments: [],\n validate() {},\n createNodeInstance() {\n return new Action(this.attributes, this.actionName!, this.actionArguments!);\n }\n }),\n CONDITION: (): ConditionAstNode => ({\n type: \"condition\",\n attributes: [],\n conditionName: \"\",\n conditionArguments: [],\n validate() {},\n createNodeInstance() {\n return new Condition(this.attributes, this.conditionName!, this.conditionArguments!);\n }\n })\n};\n\ntype OtherAstNodes = AstNode[];\n\n/**\n * Create an array of root AST nodes based on the given definition.\n * @param definition The definition to parse the AST nodes from.\n * @returns The base definition AST nodes.\n */\nexport default function buildRootASTNodes(definition: string): RootAstNode[] {\n // Swap out any node/attribute argument string literals with a placeholder and get a mapping of placeholders to original values as well as the processed definition.\n const { placeholders, processedDefinition } = substituteStringLiterals(definition);\n\n // Convert the processed definition (with substituted string literals) into an array of raw tokens.\n const tokens = parseTokensFromDefinition(processedDefinition);\n\n // There must be at least 3 tokens for the tree definition to be valid. 'ROOT', '{' and '}'.\n if (tokens.length < 3) {\n throw new Error(\"invalid token count\");\n }\n\n // We should have a matching number of '{' and '}' tokens. If not, then there are scopes that have not been properly closed.\n if (tokens.filter((token) => token === \"{\").length !== tokens.filter((token) => token === \"}\").length) {\n throw new Error(\"scope character mismatch\");\n }\n\n // Create a stack of node children arrays, starting with a definition scope.\n const stack: [RootAstNode[], ...OtherAstNodes[]] = [[]];\n const rootScope = stack[0];\n\n // We should keep processing the raw tokens until we run out of them.\n while (tokens.length) {\n // Grab the next token.\n const token = tokens.shift();\n\n const currentScope = stack[stack.length - 1] as OtherAstNodes;\n\n // How we create the next AST token depends on the current raw token value.\n switch (token!.toUpperCase()) {\n case \"ROOT\": {\n // Create a ROOT AST node.\n const node = ASTNodeFactories.ROOT();\n\n // Push the ROOT node into the current scope.\n rootScope.push(node);\n\n // We may have a root node name defined as an argument.\n if (tokens[0] === \"[\") {\n const rootArguments = getArguments(tokens, placeholders);\n\n // We should have only a single argument that is not an empty string for a root node, which is the root name identifier.\n if (rootArguments.length === 1 && rootArguments[0].type === \"identifier\") {\n // The root name will be the first and only node argument.\n node.name = rootArguments[0].value as string;\n } else {\n throw new Error(\"expected single root name argument\");\n }\n }\n\n // Try to pick any attributes off of the token stack.\n node.attributes = getAttributes(tokens, placeholders);\n\n popAndCheck(tokens, \"{\");\n\n // The new scope is that of the new ROOT nodes children.\n stack.push(node.children!);\n break;\n }\n\n case \"BRANCH\": {\n // Create a BRANCH AST node.\n const node = ASTNodeFactories.BRANCH();\n\n // Push the BRANCH node into the current scope.\n currentScope.push(node);\n\n // We must have arguments defined, as we require a branch name argument.\n if (tokens[0] !== \"[\") {\n throw new Error(\"expected single branch name argument\");\n }\n\n // The branch name will be defined as a node argument.\n const branchArguments = getArguments(tokens, placeholders);\n\n // We should have only a single identifer argument for a branch node, which is the branch name.\n if (branchArguments.length === 1 && branchArguments[0].type === \"identifier\") {\n // The branch name will be the first and only node argument.\n node.branchName = branchArguments[0].value as string;\n } else {\n throw new Error(\"expected single branch name argument\");\n }\n break;\n }\n\n case \"SELECTOR\": {\n // Create a SELECTOR AST node.\n const node = ASTNodeFactories.SELECTOR();\n\n // Push the SELECTOR node into the current scope.\n currentScope.push(node);\n\n // Try to pick any attributes off of the token stack.\n node.attributes = getAttributes(tokens, placeholders);\n\n popAndCheck(tokens, \"{\");\n\n // The new scope is that of the new SELECTOR nodes children.\n stack.push(node.children!);\n break;\n }\n\n case \"SEQUENCE\": {\n // Create a SEQUENCE AST node.\n const node = ASTNodeFactories.SEQUENCE();\n\n // Push the SEQUENCE node into the current scope.\n currentScope.push(node);\n\n // Try to pick any attributes off of the token stack.\n node.attributes = getAttributes(tokens, placeholders);\n\n popAndCheck(tokens, \"{\");\n\n // The new scope is that of the new SEQUENCE nodes children.\n stack.push(node.children!);\n break;\n }\n\n case \"PARALLEL\": {\n // Create a PARALLEL AST node.\n const node = ASTNodeFactories.PARALLEL();\n\n // Push the PARALLEL node into the current scope.\n currentScope.push(node);\n\n // Try to pick any attributes off of the token stack.\n node.attributes = getAttributes(tokens, placeholders);\n\n popAndCheck(tokens, \"{\");\n\n // The new scope is that of the new PARALLEL nodes children.\n stack.push(node.children!);\n break;\n }\n\n case \"LOTTO\": {\n // Create a LOTTO AST node.\n const node = ASTNodeFactories.LOTTO();\n\n // Push the LOTTO node into the current scope.\n currentScope.push(node);\n\n // If the next token is a '[' character then some ticket counts have been defined as arguments.\n if (tokens[0] === \"[\") {\n // Get the ticket count arguments, each argument must be a number.\n node.tickets = getArguments(\n tokens,\n placeholders,\n (arg) => arg.type === \"number\" && !!arg.isInteger,\n \"lotto node ticket counts must be integer values\"\n ).map((argument) => argument.value as number);\n }\n\n // Try to pick any attributes off of the token stack.\n node.attributes = getAttributes(tokens, placeholders);\n\n popAndCheck(tokens, \"{\");\n\n // The new scope is that of the new LOTTO nodes children.\n stack.push(node.children!);\n break;\n }\n\n case \"CONDITION\": {\n // Create a CONDITION AST node.\n const node = ASTNodeFactories.CONDITION();\n\n // Push the CONDITION node into the current scope.\n currentScope.push(node);\n\n // We must have arguments defined, as we require a condition function name argument.\n if (tokens[0] !== \"[\") {\n throw new Error(\"expected condition name identifier argument\");\n }\n\n // Grab the condition node arguments.\n const conditionArguments = getArguments(tokens, placeholders);\n\n // We should have at least a single identifier argument for a condition node, which is the condition function name.\n if (conditionArguments.length && conditionArguments[0].type === \"identifier\") {\n // The condition function name will be the first node argument.\n node.conditionName = conditionArguments.shift()!.value as string;\n } else {\n throw new Error(\"expected condition name identifier argument\");\n }\n\n // Only the first argument should have been an identifier, all following arguments must be string, number, boolean or null.\n conditionArguments\n .filter((arg) => arg.type === \"identifier\")\n .forEach((arg) => {\n throw new Error(\n \"invalid condition node argument value '\" +\n arg.value +\n \"', must be string, number, boolean or null\"\n );\n });\n\n // Any node arguments that follow the condition name identifier will be treated as condition function arguments.\n node.conditionArguments = conditionArguments;\n\n // Try to pick any attributes off of the token stack.\n node.attributes = getAttributes(tokens, placeholders);\n break;\n }\n\n case \"FLIP\": {\n // Create a FLIP AST node.\n const node = ASTNodeFactories.FLIP();\n\n // Push the Flip node into the current scope.\n currentScope.push(node);\n\n // Try to pick any attributes off of the token stack.\n node.attributes = getAttributes(tokens, placeholders);\n\n popAndCheck(tokens, \"{\");\n\n // The new scope is that of the new FLIP nodes children.\n stack.push(node.children!);\n break;\n }\n\n case \"SUCCEED\": {\n // Create a SUCCEED AST node.\n const node = ASTNodeFactories.SUCCEED();\n\n // Push the Succeed node into the current scope.\n currentScope.push(node);\n\n // Try to pick any attributes off of the token stack.\n node.attributes = getAttributes(tokens, placeholders);\n\n popAndCheck(tokens, \"{\");\n\n // The new scope is that of the new Succeed nodes children.\n stack.push(node.children!);\n break;\n }\n\n case \"FAIL\": {\n // Create a FAIL AST node.\n const node = ASTNodeFactories.FAIL();\n\n // Push the Fail node into the current scope.\n currentScope.push(node);\n\n // Try to pick any attributes off of the token stack.\n node.attributes = getAttributes(tokens, placeholders);\n\n popAndCheck(tokens, \"{\");\n\n // The new scope is that of the new Fail nodes children.\n stack.push(node.children!);\n break;\n }\n\n case \"WAIT\": {\n // Create a WAIT AST node.\n const node = ASTNodeFactories.WAIT();\n\n // Push the WAIT node into the current scope.\n currentScope.push(node);\n\n // The arguments of a wait node are optional. We may have:\n // - No node arguments, in which case the wait will be indefinite until it is aborted.\n // - One node argument which will be the explicit duration of the wait.\n // - Two node arguments which define the min and max duration bounds from which a random duration will be picked.\n if (tokens[0] === \"[\") {\n // Get the optional duration and longest duration of the wait.\n const nodeArguments = getArguments(\n tokens,\n placeholders,\n (arg) => arg.type === \"number\" && !!arg.isInteger,\n \"wait node durations must be integer values\"\n ).map((argument) => argument.value);\n\n // We may have:\n // - One node argument which will be the explicit duration of the wait.\n // - Two node arguments which define the min and max duration bounds from which a random duration will be picked.\n // - Too many arguments, which is not valid.\n if (nodeArguments.length === 1) {\n // An explicit duration was defined.\n node.duration = nodeArguments[0] as number;\n } else if (nodeArguments.length === 2) {\n // Min and max duration bounds were defined from which a random duration will be picked.\n node.durationMin = nodeArguments[0] as number;\n node.durationMax = nodeArguments[1] as number;\n } else if (nodeArguments.length > 2) {\n // An incorrect number of durations was defined.\n throw new Error(\"invalid number of wait node duration arguments defined\");\n }\n }\n\n // Try to pick any attributes off of the token stack.\n node.attributes = getAttributes(tokens, placeholders);\n break;\n }\n\n case \"REPEAT\": {\n // Create a REPEAT AST node.\n const node = ASTNodeFactories.REPEAT();\n\n // Push the REPEAT node into the current scope.\n currentScope.push(node);\n\n // The arguments of a repeat node are optional. We may have:\n // - No node arguments, in which case the repeat note will iterate indefinitely.\n // - One node argument which will be the explicit number of iterations to make.\n // - Two node arguments which define the min and max iteration bounds from which a random iteration count will be picked.\n if (tokens[0] === \"[\") {\n // An iteration count has been defined. Get the iteration and potential maximum iteration of the wait.\n const nodeArguments = getArguments(\n tokens,\n placeholders,\n (arg) => arg.type === \"number\" && !!arg.isInteger,\n \"repeat node iteration counts must be integer values\"\n ).map((argument) => argument.value);\n\n // We should have got one or two iteration counts.\n if (nodeArguments.length === 1) {\n // A static iteration count was defined.\n node.iterations = nodeArguments[0] as number;\n } else if (nodeArguments.length === 2) {\n // A minimum and maximum iteration count was defined.\n node.iterationsMin = nodeArguments[0] as number;\n node.iterationsMax = nodeArguments[1] as number;\n } else {\n // An incorrect number of iteration counts was defined.\n throw new Error(\"invalid number of repeat node iteration count arguments defined\");\n }\n }\n\n // Try to pick any attributes off of the token stack.\n node.attributes = getAttributes(tokens, placeholders);\n\n popAndCheck(tokens, \"{\");\n\n // The new scope is that of the new REPEAT nodes children.\n stack.push(node.children!);\n break;\n }\n\n case \"RETRY\": {\n // Create a RETRY AST node.\n const node = ASTNodeFactories.RETRY();\n\n // Push the RETRY node into the current scope.\n currentScope.push(node);\n\n // The arguments of a retry node are optional. We may have:\n // - No node arguments, in which case the retry note will attempt indefinitely.\n // - One node argument which will be the explicit number of attempts to make.\n // - Two node arguments which define the min and max attempt bounds from which a random attempt count will be picked.\n if (tokens[0] === \"[\") {\n // An attempt count has been defined. Get the attempt count and potential maximum attempt count of the wait.\n const nodeArguments = getArguments(\n tokens,\n placeholders,\n (arg) => arg.type === \"number\" && !!arg.isInteger,\n \"retry node attempt counts must be integer values\"\n ).map((argument) => argument.value);\n\n // We should have got one or two attempt counts.\n if (nodeArguments.length === 1) {\n // A static attempt count was defined.\n node.attempts = nodeArguments[0] as number;\n } else if (nodeArguments.length === 2) {\n // A minimum and maximum attempt count was defined.\n node.attemptsMin = nodeArguments[0] as number;\n node.attemptsMax = nodeArguments[1] as number;\n } else {\n // An incorrect number of attempt counts was defined.\n throw new Error(\"invalid number of retry node attempt count arguments defined\");\n }\n }\n\n // Try to pick any attributes off of the token stack.\n node.attributes = getAttributes(tokens, placeholders);\n\n popAndCheck(tokens, \"{\");\n\n // The new scope is that of the new RETRY nodes children.\n stack.push(node.children!);\n break;\n }\n\n case \"ACTION\": {\n // Create a ACTION AST node.\n const node = ASTNodeFactories.ACTION();\n\n // Push the ACTION node into the current scope.\n currentScope.push(node);\n\n // We must have arguments defined, as we require an action name argument.\n if (tokens[0] !== \"[\") {\n throw new Error(\"expected action name identifier argument\");\n }\n\n // The action name will be defined as a node argument.\n const actionArguments = getArguments(tokens, placeholders);\n\n // We should have at least one identifer argument for an action node, which is the action name.\n if (actionArguments.length && actionArguments[0].type === \"identifier\") {\n // The action name will be the first and only node argument.\n node.actionName = actionArguments.shift()!.value as string;\n } else {\n throw new Error(\"expected action name identifier argument\");\n }\n\n // Only the first argument should have been an identifier, all following arguments must be string, number, boolean or null.\n actionArguments\n .filter((arg) => arg.type === \"identifier\")\n .forEach((arg) => {\n throw new Error(\n \"invalid action node argument value '\" +\n arg.value +\n \"', must be string, number, boolean or null\"\n );\n });\n\n // Any node arguments that follow the action name identifier will be treated as action function arguments.\n node.actionArguments = actionArguments;\n\n // Try to pick any attributes off of the token stack.\n node.attributes = getAttributes(tokens, placeholders);\n break;\n }\n\n case \"}\": {\n // The '}' character closes the current scope.\n stack.pop();\n break;\n }\n\n default: {\n throw new Error(`unexpected token '${token}'`);\n }\n }\n }\n\n // A function to recursively validate each of the nodes in the AST.\n const validateASTNode = (node: Validatable, depth: number): void => {\n // Validate the node.\n node.validate(depth);\n\n // Validate each child of the node.\n (node.children || []).forEach((child) => validateASTNode(child, depth + 1));\n };\n\n // Start node validation from the definition root.\n validateASTNode(\n {\n children: stack[0] as RootAstNode[],\n validate(this: { children: RootAstNode[] }) {\n // We must have at least one node defined as the definition scope, which should be a root node.\n if (this.children.length === 0) {\n throw new Error(\"expected root node to have been defined\");\n }\n\n // Each node at the base of the definition scope MUST be a root node.\n for (const definitionLevelNode of this.children) {\n if (definitionLevelNode.type !== \"root\") {\n throw new Error(\"expected root node at base of definition\");\n }\n }\n\n // Exactly one root node must not have a name defined. This will be the main root, others will have to be referenced via branch nodes.\n if (this.children.filter((definitionLevelNode) => definitionLevelNode.name === null).length !== 1) {\n throw new Error(\"expected single unnamed root node at base of definition to act as main root\");\n }\n\n // No two named root nodes can have matching names.\n const rootNodeNames: string[] = [];\n for (const definitionLevelNode of this.children) {\n if (rootNodeNames.indexOf(definitionLevelNode.name!) !== -1) {\n throw new Error(`multiple root nodes found with duplicate name '${definitionLevelNode.name}'`);\n } else {\n rootNodeNames.push(definitionLevelNode.name!);\n }\n }\n }\n },\n 0\n );\n\n // Return the root AST nodes.\n return stack[0];\n}\n\n/**\n * Pop the next raw token off of the stack and throw an error if it wasn't the expected one.\n * @param tokens The array of remaining tokens.\n * @param expected An optional string or array or items, one of which must match the next popped token.\n * @returns The popped token.\n */\nfunction popAndCheck(tokens: string[], expected: string | string[]) {\n // Get and remove the next token.\n const popped = tokens.shift();\n\n // We were expecting another token.\n if (popped === undefined) {\n throw new Error(\"unexpected end of definition\");\n }\n\n // Do we have an expected token/tokens array?\n if (expected !== undefined) {\n // Check whether the popped token matches at least one of our expected items.\n var tokenMatchesExpectation = ([] as string[])\n .concat(expected)\n .some((item) => popped.toUpperCase() === item.toUpperCase());\n\n // Throw an error if the popped token didn't match any of our expected items.\n if (!tokenMatchesExpectation) {\n const expectationString = ([] as string[])\n .concat(expected)\n .map((item) => \"'\" + item + \"'\")\n .join(\" or \");\n\n throw new Error(`unexpected token found. Expected '${expectationString}' but got '${popped}'`);\n }\n }\n\n // Return the popped token.\n return popped;\n}\n\ntype StringPlaceholders = { [key: string]: string };\n\n/**\n * Pull an argument definition list off of the token stack.\n * @param tokens The array of remaining tokens.\n * @param stringArgumentPlaceholders The mapping of string literal node argument placeholders to original values.\n * @param argumentValidator The argument validator function.\n * @param validationFailedMessage The exception message to throw if argument validation fails.\n * @returns The argument definition list.\n */\nfunction getArguments(\n tokens: string[],\n stringArgumentPlaceholders: StringPlaceholders,\n argumentValidator?: (arg: AnyArgument) => boolean,\n validationFailedMessage?: string\n) {\n // Any lists of arguments will always be wrapped in '[]' for node arguments or '()' for attribute arguments.\n // We are looking for a '[' or '(' opener that wraps the argument tokens and the relevant closer.\n const closer = popAndCheck(tokens, [\"[\", \"(\"]) === \"[\" ? \"]\" : \")\";\n\n const argumentListTokens: string[] = [];\n const argumentList: AnyArgument[] = [];\n\n // Grab all tokens between the '[' and ']' or '(' and ')'.\n while (tokens.length && tokens[0] !== closer) {\n // The next token is part of our arguments list.\n argumentListTokens.push(tokens.shift()!);\n }\n\n // Validate the order of the argument tokens. Each token must either be a ',' or a single argument that satisfies the validator.\n argumentListTokens.forEach((token, index) => {\n // Get whether this token should be an actual argument.\n const shouldBeArgumentToken = !(index & 1);\n\n // If the current token should be an actual argument then validate it,otherwise it should be a ',' token.\n if (shouldBeArgumentToken) {\n // Get the argument definition.\n const argumentDefinition = getArgumentDefinition(token!, stringArgumentPlaceholders);\n\n // Try to validate the argument.\n if (argumentValidator && !argumentValidator(argumentDefinition)) {\n throw new Error(validationFailedMessage);\n }\n\n // This is a valid argument!\n argumentList.push(argumentDefinition);\n } else {\n // The current token should be a ',' token.\n if (token !== \",\") {\n throw new Error(`invalid argument list, expected ',' or ']' but got '${token}'`);\n }\n }\n });\n\n // The arguments list should terminate with a ']' or ')' token, depending on the opener.\n popAndCheck(tokens, closer);\n\n // Return the argument list.\n return argumentList;\n}\n\n/**\n * Gets an argument value definition.\n * @param token The argument token.\n * @param stringArgumentPlaceholders The mapping of string literal node argument placeholders to original values.\n * @returns An argument value definition.\n */\nfunction getArgumentDefinition(token: string, stringArgumentPlaceholders: StringPlaceholders): AnyArgument {\n // Check whether the token represents a null value.\n if (token === \"null\") {\n return {\n value: null,\n type: \"null\"\n } as NullArgument;\n }\n\n // Check whether the token represents a boolean value.\n if (token === \"true\" || token === \"false\") {\n return {\n value: token === \"true\",\n type: \"boolean\"\n } as BooleanArgument;\n }\n\n // Check whether the token represents a number value.\n // TODO: Relies on broken isNaN - see MDN.\n // if (!Number.isNaN(token)) {\n if (!isNaN(token as any)) {\n return {\n value: parseFloat(token),\n isInteger: parseFloat(token) === parseInt(token, 10),\n type: \"number\"\n } as NumberArgument;\n }\n\n // Check whether the token is a placeholder (e.g. @@0@@) representing a string literal.\n if (token.match(/^@@\\d+@@$/g)) {\n return {\n value: stringArgumentPlaceholders[token].replace('\\\\\"', '\"'),\n type: \"string\"\n } as StringPlaceholderArgument;\n }\n\n // The only remaining option is that the argument value is an identifier.\n return {\n value: token,\n type: \"identifier\"\n } as IdentifierArgument;\n}\n\n/**\n * Pull any attributes off of the token stack.\n * @param tokens The array of remaining tokens.\n * @param stringArgumentPlaceholders The mapping of string literal node argument placeholders to original values.\n * @returns An array of attributes defined by any directly following tokens.\n */\nfunction getAttributes(tokens: string[], stringArgumentPlaceholders: StringPlaceholders) {\n // Create an array to hold any attributes found.\n const attributes: Attribute[] = [];\n\n // Keep track of names of attribute that we have found on the token stack, as we cannot have duplicates.\n const attributesFound: string[] = [];\n\n // Try to get the attribute factory for the next token.\n let attributeFactory = AttributeFactories[(tokens[0] || \"\").toUpperCase()];\n\n // Pull attribute tokens off of the tokens stack until we have no more.\n while (attributeFactory) {\n // Check to make sure that we have not already created a attribute of this type for this node.\n if (attributesFound.indexOf(tokens[0].toUpperCase()) !== -1) {\n throw new Error(`duplicate attribute '${tokens[0].toUpperCase()}' found for node`);\n }\n\n // Add the current attribute type to our array of found attributes.\n attributesFound.push(tokens.shift()!.toUpperCase());\n\n // Grab any attribute arguments.\n const attributeArguments = getArguments(tokens, stringArgumentPlaceholders);\n\n // The first attribute argument has to be an identifer, this will reference an agent function.\n if (attributeArguments.length === 0 || attributeArguments[0].type !== \"identifier\") {\n throw new Error(\"expected agent function name identifier argument for attribute\");\n }\n\n // Grab the first attribute which is an identifier that will reference an agent function.\n const attributeFunctionName = attributeArguments.shift()! as IdentifierArgument;\n\n // Any remaining attribute arguments must have a type of string, number, boolean or null.\n attributeArguments\n .filter((arg) => arg.type === \"identifier\")\n .forEach((arg) => {\n throw new Error(\n \"invalid attribute argument value '\" + arg.value + \"', must be string, number, boolean or null\"\n );\n });\n\n // Create the attribute and add it to the array of attributes found.\n attributes.push(attributeFactory(attributeFunctionName.value, attributeArguments));\n\n // Try to get the next attribute name token, as there could be multiple.\n attributeFactory = AttributeFactories[(tokens[0] || \"\").toUpperCase()];\n }\n\n return attributes;\n}\n\n/**\n * Swaps out any node/attribute argument string literals with placeholders.\n * @param definition The definition.\n * @returns An object containing a mapping of placeholders to original string values as well as the processed definition string.\n */\nfunction substituteStringLiterals(definition: string): {\n placeholders: { [key: string]: string };\n processedDefinition: string;\n} {\n // Create an object to hold the mapping of placeholders to original string values.\n const placeholders: StringPlaceholders = {};\n\n // Replace any string literals wrapped with double quotes in our definition with placeholders to be processed later.\n const processedDefinition = definition.replace(/\\\"(\\\\.|[^\"\\\\])*\\\"/g, (match) => {\n var strippedMatch = match.substring(1, match.length - 1);\n var placeholder = Object.keys(placeholders).find((key) => placeholders[key] === strippedMatch);\n\n // If we have no existing string literal match then create a new placeholder.\n if (!placeholder) {\n placeholder = `@@${Object.keys(placeholders).length}@@`;\n placeholders[placeholder] = strippedMatch;\n }\n\n return placeholder;\n });\n\n return { placeholders, processedDefinition };\n}\n\n/**\n * Parse the tree definition into an array of raw tokens.\n * @param definition The definition.\n * @returns An array of tokens parsed from the definition.\n */\nfunction parseTokensFromDefinition(definition: string): string[] {\n // Add some space around various important characters so that they can be plucked out easier as individual tokens.\n definition = definition.replace(/\\(/g, \" ( \");\n definition = definition.replace(/\\)/g, \" ) \");\n definition = definition.replace(/\\{/g, \" { \");\n definition = definition.replace(/\\}/g, \" } \");\n definition = definition.replace(/\\]/g, \" ] \");\n definition = definition.replace(/\\[/g, \" [ \");\n definition = definition.replace(/\\,/g, \" , \");\n\n // Split the definition into raw token form and return it.\n return definition.replace(/\\s+/g, \" \").trim().split(\" \");\n}\n", "import GuardPath, { GuardPathPart } from \"./attributes/guards/GuardPath\";\nimport buildRootASTNodes, { AnyArgument, RootAstNode } from \"./RootAstNodesBuilder\";\nimport State, { AnyState } from \"./State\";\nimport Lookup from \"./Lookup\";\nimport Node from \"./nodes/Node\";\nimport Root from \"./nodes/decorator/Root\";\nimport Composite from \"./nodes/composite/Composite\";\nimport Decorator from \"./nodes/decorator/Decorator\";\nimport { Agent, GlobalFunction } from \"./Agent\";\nimport { CallbackAttributeDetails } from \"./attributes/callbacks/Callback\";\nimport { GuardAttributeDetails } from \"./attributes/guards/Guard\";\nimport { BehaviourTreeOptions } from \"./BehaviourTreeOptions\";\nimport { convertMDSLToJSON } from \"./mdsl/MDSLDefinitionParser\";\n\n// Purely for outside inspection of the tree.\nexport type FlattenedTreeNode = {\n id: string;\n type: string;\n caption: string;\n state: AnyState;\n guards: GuardAttributeDetails[];\n callbacks: CallbackAttributeDetails[];\n args: AnyArgument[];\n parentId: string | null;\n};\n\n/**\n * A representation of a behaviour tree.\n */\nexport class BehaviourTree {\n /**\n * The main root tree node.\n */\n public readonly rootNode: Root;\n\n /**\n * Creates a new instance of the BehaviourTree class.\n * @param definition The behaviour tree definition.\n * @param agent The agent instance that this behaviour tree is modelling behaviour for.\n * @param options The behaviour tree options object.\n */\n constructor(definition: string, private agent: Agent, private options: BehaviourTreeOptions = {}) {\n // The tree definition must be defined and a valid string.\n if (typeof definition !== \"string\") {\n throw new Error(\"the tree definition must be a string\");\n }\n\n // The agent must be defined and not null.\n if (typeof agent !== \"object\" || agent === null) {\n throw new Error(\"the agent must be defined and not null\");\n }\n\n // Parse the behaviour tree definition, create the populated tree of behaviour tree nodes, and get the root.\n this.rootNode = BehaviourTree._createRootNode(definition);\n }\n\n /**\n * Gets whether the tree is in the RUNNING state.\n * @returns true if the tree is in the RUNNING state, otherwise false.\n */\n isRunning() {\n return this.rootNode.getState() === State.RUNNING;\n }\n\n /**\n * Gets the current tree state of SUCCEEDED, FAILED, READY or RUNNING.\n * @returns The current tree state.\n */\n getState() {\n return this.rootNode.getState();\n }\n\n /**\n * Step the tree.\n * 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.\n * 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\n * 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.\n *\n * 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.\n */\n step() {\n // If the root node has already been stepped to completion then we need to reset it.\n if (this.rootNode.getState() === State.SUCCEEDED || this.rootNode.getState() === State.FAILED) {\n this.rootNode.reset();\n }\n\n try {\n this.rootNode.update(this.agent, this.options);\n } catch (exception) {\n throw new Error(`error stepping tree: ${(exception as Error).message}`);\n }\n }\n\n /**\n * Resets the tree from the root node outwards to each nested node, giving each a state of READY.\n */\n reset() {\n this.rootNode.reset();\n }\n\n /**\n * Gets the flattened details of every node in the tree.\n * @returns The flattened details of every node in the tree.\n */\n getFlattenedNodeDetails(): FlattenedTreeNode[] {\n // Create an empty flattened array of tree nodes.\n const flattenedTreeNodes: FlattenedTreeNode[] = [];\n\n /**\n * Helper function to process a node instance and push details into the flattened tree nodes array.\n * @param node The current node.\n * @param parentUid The UID of the node parent, or null if the node is the main root node.\n */\n const processNode = (node: Node, parentUid: string | null) => {\n // Get the guard and callback attribute details for this node.\n const guards = node\n .getAttributes()\n .filter((attribute) => attribute.isGuard())\n .map((attribute) => attribute.getDetails()) as GuardAttributeDetails[];\n const callbacks = node\n .getAttributes()\n .filter((attribute) => !attribute.isGuard())\n .map((attribute) => attribute.getDetails()) as CallbackAttributeDetails[];\n\n // Push the current node into the flattened nodes array.\n flattenedTreeNodes.push({\n id: node.getUid(),\n type: node.getType(),\n caption: node.getName(),\n state: node.getState(),\n guards,\n callbacks,\n args: node.getArguments(),\n parentId: parentUid\n });\n\n // Process each of the nodes children if it is not a leaf node.\n if (!node.isLeafNode()) {\n (node as Composite | Decorator)\n .getChildren()\n .forEach((child) => processNode(child, (node as Composite | Decorator).getUid()));\n }\n };\n\n // Convert the nested node structure into a flattened array of node details.\n processNode(this.rootNode, null);\n\n return flattenedTreeNodes;\n }\n\n /**\n * Registers the action/condition/guard/callback function or subtree with the given name.\n * @param name The name of the function or subtree to register.\n * @param value The function or subtree definition to register.\n */\n static register(name: string, value: GlobalFunction | string) {\n if (typeof value === \"function\") {\n // We are going to register a action/condition/guard/callback function.\n Lookup.setFunc(name, value);\n } else if (typeof value === \"string\") {\n // We are going to register a subtree.\n let rootASTNodes: RootAstNode[];\n\n try {\n // Try to create the behaviour tree AST based on the definition provided, this could fail if the definition is invalid.\n rootASTNodes = buildRootASTNodes(value);\n } catch (exception) {\n // There was an issue in trying to parse and build the tree definition.\n throw new Error(`error registering definition: ${(exception as Error).message}`);\n }\n\n // This function should only ever be called with a definition containing a single unnamed root node.\n if (rootASTNodes.length != 1 || rootASTNodes[0].name !== null) {\n throw new Error(\"error registering definition: expected a single unnamed root node\");\n }\n\n Lookup.setSubtree(name, rootASTNodes[0]);\n } else {\n throw new Error(\"unexpected value, expected string definition or function\");\n }\n }\n\n /**\n * Unregisters the registered action/condition/guard/callback function or subtree with the given name.\n * @param name The name of the registered action/condition/guard/callback function or subtree to unregister.\n */\n static unregister(name: string): void {\n Lookup.remove(name);\n }\n\n /**\n * Unregister all registered action/condition/guard/callback functions and subtrees.\n */\n static unregisterAll(): void {\n Lookup.empty();\n }\n\n /**\n * Parses a behaviour tree definition and creates a tree of behaviour tree nodes.\n * @param {string} definition The behaviour tree definition.\n * @returns The root behaviour tree node.\n */\n private static _createRootNode(definition: string): Root {\n // TODO Remove!\n try {\n // parseToJSON(definition);\n } catch (exception) {\n console.log(exception);\n }\n\n try {\n // Try to create the behaviour tree AST based on the definition provided, this could fail if the definition is invalid.\n const rootASTNodes = buildRootASTNodes(definition);\n\n // Create a symbol to use as the main root key in our root node mapping.\n const mainRootNodeKey = Symbol(\"__root__\");\n\n // Create a mapping of root node names to root AST tokens. The main root node will have a key of Symbol(\"__root__\").\n const rootNodeMap: { [key: string | symbol]: RootAstNode } = {};\n for (const rootASTNode of rootASTNodes) {\n rootNodeMap[rootASTNode.name === null ? mainRootNodeKey : rootASTNode.name!] = rootASTNode;\n }\n\n // Convert the AST to our actual tree and get the root node.\n const rootNode: Root = rootNodeMap[mainRootNodeKey].createNodeInstance(\n // Create a provider for named root nodes that are part of our definition or have been registered. Prioritising the former.\n (name: string): RootAstNode => (rootNodeMap[name] ? rootNodeMap[name] : Lookup.getSubtree(name)),\n []\n );\n\n // Set a guard path on every leaf of the tree to evaluate as part of its update.\n BehaviourTree._applyLeafNodeGuardPaths(rootNode);\n\n // Return the root node.\n return rootNode;\n } catch (exception) {\n // There was an issue in trying to parse and build the tree definition.\n throw new Error(`error parsing tree: ${(exception as Error).message}`);\n }\n }\n\n /**\n * Applies a guard path to every leaf of the tree to evaluate as part of each update.\n * @param rootNode The main root tree node.\n */\n private static _applyLeafNodeGuardPaths(rootNode: Root) {\n const nodePaths: Node[][] = [];\n\n const findLeafNodes = (path: Node[], node: Node) => {\n // Add the current node to the path.\n path = path.concat(node);\n\n // Check whether the current node is a leaf node.\n if (node.isLeafNode()) {\n nodePaths.push(path);\n } else {\n (node as Composite | Decorator).getChildren().forEach((child) => findLeafNodes(path, child));\n }\n };\n\n // Find all leaf node paths, starting from the root.\n findLeafNodes([], rootNode);\n\n nodePaths.forEach((path) => {\n // Each node in the current path will have to be assigned a guard path, working from the root outwards.\n for (let depth = 0; depth < path.length; depth++) {\n // Get the node in the path at the current depth.\n const currentNode = path[depth];\n\n // The node may already have been assigned a guard path, if so just skip it.\n if (currentNode.hasGuardPath()) {\n continue;\n }\n\n // Create the guard path for the current node.\n const guardPath = new GuardPath(\n path\n .slice(0, depth + 1)\n .map((node) => ({ node, guards: node.getGuardAttributes() }))\n .filter((details) => details.guards.length > 0)\n );\n\n // Assign the guard path to the current node.\n currentNode.setGuardPath(guardPath);\n }\n });\n }\n}\n"], - "mappings": "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", - "names": ["Participant", "Lotto", "createLotto", "State", "createLotto", "substituteStringLiterals", "parseTokensFromDefinition", "popAndCheck", "getArgumentDefinition"] + "sources": ["../src/index.ts", "../src/State.ts", "../src/BehaviourTreeDefinitionUtilities.ts", "../src/mdsl/MDSLUtilities.ts", "../src/mdsl/MDSLNodeArgumentParser.ts", "../src/mdsl/MDSLNodeAttributeParser.ts", "../src/mdsl/MDSLDefinitionParser.ts", "../src/BehaviourTreeDefinitionValidator.ts", "../src/Lookup.ts", "../src/attributes/guards/GuardUnsatisifedException.ts", "../src/attributes/guards/GuardPath.ts", "../src/nodes/Node.ts", "../src/nodes/decorator/Decorator.ts", "../src/nodes/decorator/Root.ts", "../src/attributes/Attribute.ts", "../src/attributes/guards/Guard.ts", "../src/attributes/guards/While.ts", "../src/attributes/guards/Until.ts", "../src/attributes/callbacks/Callback.ts", "../src/attributes/callbacks/Entry.ts", "../src/attributes/callbacks/Step.ts", "../src/attributes/callbacks/Exit.ts", "../src/BehaviourTreeBuilder.ts", "../src/BehaviourTree.ts"], + "sourcesContent": ["import State from \"./State\";\nimport { validateDefinition } from \"./BehaviourTreeDefinitionValidator\";\nimport { convertMDSLToJSON } from \"./mdsl/MDSLDefinitionParser\";\nimport { BehaviourTree, FlattenedTreeNode } from \"./BehaviourTree\";\n\nexport { BehaviourTree, State, convertMDSLToJSON, validateDefinition };\nexport type { FlattenedTreeNode };\n", "/**\n * Enumeration of node state types.\n */\nexport enum State {\n READY = \"mistreevous.ready\",\n RUNNING = \"mistreevous.running\",\n SUCCEEDED = \"mistreevous.succeeded\",\n FAILED = \"mistreevous.failed\"\n}\n\nexport { State as default };\n\nexport type CompleteState = State.SUCCEEDED | State.FAILED;\nexport type AnyState = State.READY | State.RUNNING | CompleteState;\n", "import {\n NodeDefinition,\n RootNodeDefinition,\n DecoratorNodeDefinition,\n CompositeNodeDefinition,\n AnyNodeDefinition,\n BranchNodeDefinition\n} from \"./BehaviourTreeDefinition\";\n\n/**\n * A type guard function that returns true if the specified node satisfies the RootNodeDefinition type.\n * @param node The node.\n * @returns A value of true if the specified node satisfies the RootNodeDefinition type.\n */\nexport function isRootNode(node: NodeDefinition): node is RootNodeDefinition {\n return node.type === \"root\";\n}\n\n/**\n * A type guard function that returns true if the specified node satisfies the BranchNodeDefinition type.\n * @param node The node.\n * @returns A value of true if the specified node satisfies the BranchNodeDefinition type.\n */\nexport function isBranchNode(node: NodeDefinition): node is BranchNodeDefinition {\n return node.type === \"branch\";\n}\n\n/**\n * A type guard function that returns true if the specified node satisfies the NodeDefinition type.\n * @param node The node.\n * @returns A value of true if the specified node satisfies the NodeDefinition type.\n */\nexport function isLeafNode(node: NodeDefinition): node is NodeDefinition {\n return [\"branch\", \"action\", \"condition\", \"wait\"].includes(node.type);\n}\n\n/**\n * A type guard function that returns true if the specified node satisfies the DecoratorNodeDefinition type.\n * @param node The node.\n * @returns A value of true if the specified node satisfies the DecoratorNodeDefinition type.\n */\nexport function isDecoratorNode(node: NodeDefinition): node is DecoratorNodeDefinition {\n return [\"root\", \"repeat\", \"retry\", \"flip\", \"succeed\", \"fail\"].includes(node.type);\n}\n\n/**\n * A type guard function that returns true if the specified node satisfies the CompositeNodeDefinition type.\n * @param node The node.\n * @returns A value of true if the specified node satisfies the CompositeNodeDefinition type.\n */\nexport function isCompositeNode(node: NodeDefinition): node is CompositeNodeDefinition {\n return [\"sequence\", \"selector\", \"lotto\", \"parallel\"].includes(node.type);\n}\n\n/**\n * Flatten a node definition into an array of all of its nested node definitions.\n * @param nodeDefinition The node definition to flatten.\n * @returns An array of all of nested node definitions.\n */\nexport function flattenDefinition(nodeDefinition: AnyNodeDefinition): AnyNodeDefinition[] {\n const nodes: AnyNodeDefinition[] = [];\n\n const processNode = (currentNodeDefinition: AnyNodeDefinition) => {\n nodes.push(currentNodeDefinition);\n\n if (isCompositeNode(currentNodeDefinition)) {\n currentNodeDefinition.children.forEach(processNode);\n } else if (isDecoratorNode(currentNodeDefinition)) {\n processNode(currentNodeDefinition.child);\n }\n };\n\n processNode(nodeDefinition);\n\n return nodes;\n}\n\n/**\n * Determines whether the passed value is an integer.\n * @param value The value to check.\n * @returns Whether the passed value is an integer.\n */\nexport function isInteger(value: unknown): boolean {\n return typeof value === \"number\" && Math.floor(value) === value;\n}\n", "/**\n * A type defining an object that holds a reference to substitued string literals parsed from the definition.\n */\nexport type StringLiteralPlaceholders = { [key: string]: string };\n\n/**\n * Pop the next raw token from the specified array of tokens and throw an error if it wasn't the expected one.\n * @param tokens The array of tokens.\n * @param expected An optional string or array or items, one of which must match the next popped token.\n * @returns The popped token.\n */\nexport function popAndCheck(tokens: string[], expected?: string | string[]): string {\n // Get and remove the next token.\n const popped = tokens.shift();\n\n // We were expecting another token but there aren't any.\n if (popped === undefined) {\n throw new Error(\"unexpected end of definition\");\n }\n\n // Do we have an expected token/tokens array?\n if (expected != undefined) {\n // Get an array of expected values, if the popped token matches any then we are all good.\n const expectedValues = typeof expected === \"string\" ? [expected] : expected;\n\n // Check whether the popped token matches at least one of our expected items.\n var tokenMatchesExpectation = expectedValues.some((item) => popped.toUpperCase() === item.toUpperCase());\n\n // Throw an error if the popped token didn't match any of our expected items.\n if (!tokenMatchesExpectation) {\n const expectationString = expectedValues.map((item) => \"'\" + item + \"'\").join(\" or \");\n throw new Error(\"unexpected token found. Expected \" + expectationString + \" but got '\" + popped + \"'\");\n }\n }\n\n // Return the popped token.\n return popped;\n}\n\n/**\n * Swaps out any node/attribute argument string literals with placeholders.\n * @param definition The definition.\n * @returns An object containing a mapping of placeholders to original string values as well as the processed definition string.\n */\nexport function substituteStringLiterals(definition: string): {\n placeholders: StringLiteralPlaceholders;\n processedDefinition: string;\n} {\n // Create an object to hold the mapping of placeholders to original string values.\n const placeholders: StringLiteralPlaceholders = {};\n\n // Replace any string literals wrapped with double quotes in our definition with placeholders to be processed later.\n const processedDefinition = definition.replace(/\\\"(\\\\.|[^\"\\\\])*\\\"/g, (match) => {\n var strippedMatch = match.substring(1, match.length - 1);\n var placeholder = Object.keys(placeholders).find((key) => placeholders[key] === strippedMatch);\n\n // If we have no existing string literal match then create a new placeholder.\n if (!placeholder) {\n placeholder = `@@${Object.keys(placeholders).length}@@`;\n placeholders[placeholder] = strippedMatch;\n }\n\n return placeholder;\n });\n\n return { placeholders, processedDefinition };\n}\n\n/**\n * Parse the tree definition into an array of raw tokens.\n * @param definition The definition.\n * @returns An array of tokens parsed from the definition.\n */\nexport function parseTokensFromDefinition(definition: string): string[] {\n // Add some space around various important characters so that they can be plucked out easier as individual tokens.\n definition = definition.replace(/\\(/g, \" ( \");\n definition = definition.replace(/\\)/g, \" ) \");\n definition = definition.replace(/\\{/g, \" { \");\n definition = definition.replace(/\\}/g, \" } \");\n definition = definition.replace(/\\]/g, \" ] \");\n definition = definition.replace(/\\[/g, \" [ \");\n definition = definition.replace(/\\,/g, \" , \");\n\n // Split the definition into raw token form and return it.\n return definition.replace(/\\s+/g, \" \").trim().split(\" \");\n}\n", "import { StringLiteralPlaceholders, popAndCheck } from \"./MDSLUtilities\";\n\n/**\n * A type representing any node function argument.\n */\ntype Argument = {\n /**\n * The argument value.\n */\n value: T;\n /**\n * The argument type, used for validation.\n */\n type: string;\n};\n\ntype NullArgument = Argument & {\n type: \"null\";\n};\n\ntype BooleanArgument = Argument & {\n type: \"boolean\";\n};\n\ntype NumberArgument = Argument & {\n type: \"number\";\n /**\n * A flag defining whether the number argument value is a valid integer. (used for validation)\n */\n isInteger: boolean;\n};\n\ntype StringPlaceholderArgument = Argument & {\n type: \"string\";\n};\n\ntype IdentifierArgument = Argument & {\n type: \"identifier\";\n};\n\n/**\n * A type representing a reference to any node function argument.\n */\ntype AnyArgument = NullArgument | BooleanArgument | NumberArgument | StringPlaceholderArgument | IdentifierArgument;\n\n/**\n * Parse an array of argument definitions from the specified tokens array.\n * @param tokens The array tokens to parse the argument definitions from.\n * @param stringArgumentPlaceholders The mapping of string literal node argument placeholders to original values.\n * @param argumentValidator The argument validator function.\n * @param validationFailedMessage The exception message to throw if argument validation fails.\n * @returns An array of argument definitions parsed from the specified tokens array.\n */\nexport function parseArgumentTokens(\n tokens: string[],\n stringArgumentPlaceholders: StringLiteralPlaceholders\n): AnyArgument[] {\n const argumentList: AnyArgument[] = [];\n\n // If the next token is not a '[' or '(' then we have no arguments to parse.\n if (![\"[\", \"(\"].includes(tokens[0])) {\n return argumentList;\n }\n\n // Any lists of arguments will always be wrapped in '[]' for node arguments or '()' for attribute arguments.\n // We are looking for a '[' or '(' opener that wraps the argument tokens and the relevant closer.\n const closingToken = popAndCheck(tokens, [\"[\", \"(\"]) === \"[\" ? \"]\" : \")\";\n\n const argumentListTokens: string[] = [];\n\n // Grab all tokens between the '[' and ']' or '(' and ')'.\n while (tokens.length && tokens[0] !== closingToken) {\n // The next token is part of our arguments list.\n argumentListTokens.push(tokens.shift()!);\n }\n\n // Validate the order of the argument tokens. Each token must either be a ',' or a single argument that satisfies the validator.\n argumentListTokens.forEach((token, index) => {\n // Get whether this token should be an actual argument.\n const shouldBeArgumentToken = !(index & 1);\n\n // If the current token should be an actual argument then validate it, otherwise it should be a ',' token.\n if (shouldBeArgumentToken) {\n // Get the argument definition.\n const argumentDefinition = getArgumentDefinition(token, stringArgumentPlaceholders);\n\n // This is a valid argument!\n argumentList.push(argumentDefinition);\n } else {\n // The current token should be a ',' token.\n if (token !== \",\") {\n throw new Error(`invalid argument list, expected ',' or ']' but got '${token}'`);\n }\n }\n });\n\n // The arguments list should terminate with a ']' or ')' token, depending on the opener.\n popAndCheck(tokens, closingToken);\n\n // Return the arguments.\n return argumentList;\n}\n\n/**\n * Gets an argument value definition.\n * @param token The argument token.\n * @param stringArgumentPlaceholders The mapping of string literal node argument placeholders to original values.\n * @returns An argument value definition.\n */\nfunction getArgumentDefinition(token: string, stringArgumentPlaceholders: StringLiteralPlaceholders): AnyArgument {\n // Check whether the token represents a null value.\n if (token === \"null\") {\n return {\n value: null,\n type: \"null\"\n } as NullArgument;\n }\n\n // Check whether the token represents a boolean value.\n if (token === \"true\" || token === \"false\") {\n return {\n value: token === \"true\",\n type: \"boolean\"\n } as BooleanArgument;\n }\n\n // Check whether the token represents a number value.\n // TODO: Relies on broken isNaN - see MDN.\n // if (!Number.isNaN(token)) {\n if (!isNaN(token as any)) {\n return {\n value: parseFloat(token),\n isInteger: parseFloat(token) === parseInt(token, 10),\n type: \"number\"\n } as NumberArgument;\n }\n\n // Check whether the token is a placeholder (e.g. @@0@@) representing a string literal.\n if (token.match(/^@@\\d+@@$/g)) {\n return {\n value: stringArgumentPlaceholders[token].replace('\\\\\"', '\"'),\n type: \"string\"\n } as StringPlaceholderArgument;\n }\n\n // The only remaining option is that the argument value is an identifier.\n return {\n value: token,\n type: \"identifier\"\n } as IdentifierArgument;\n}\n", "import { NodeAttributeDefinition } from \"../BehaviourTreeDefinition\";\nimport { parseArgumentTokens } from \"./MDSLNodeArgumentParser\";\nimport { StringLiteralPlaceholders } from \"./MDSLUtilities\";\n\n/**\n * A type defining the attribute definitions of a node.\n */\ntype NodeAttributes = {\n while?: NodeAttributeDefinition;\n until?: NodeAttributeDefinition;\n entry?: NodeAttributeDefinition;\n exit?: NodeAttributeDefinition;\n step?: NodeAttributeDefinition;\n};\n\n/**\n * Parse any node attribute definitions from the specified tokens array.\n * @param tokens The array of remaining tokens.\n * @param stringArgumentPlaceholders The mapping of string literal node argument placeholders to original values.\n * @returns An object of attribute definitions defined by any directly following tokens.\n */\nexport function parseAttributeTokens(\n tokens: string[],\n stringArgumentPlaceholders: StringLiteralPlaceholders\n): NodeAttributes {\n const nodeAttributeNames: (keyof NodeAttributes)[] = [\"while\", \"until\", \"entry\", \"exit\", \"step\"];\n\n // Create an object to hold any attributes found.\n const attributes: NodeAttributes = {};\n\n // Try to get the name of the attribute for the next token.\n let nextAttributeName = tokens[0]?.toLowerCase() as keyof NodeAttributes;\n\n // Pull attribute tokens as well as their arguments off of the tokens stack until we have no more.\n while (nodeAttributeNames.includes(nextAttributeName)) {\n // Check to make sure that we have not already created an attribute definition of this type.\n if (attributes[nextAttributeName]) {\n throw new Error(`duplicate attribute '${tokens[0].toUpperCase()}' found for node`);\n }\n\n // Remove the attribute name token from the array of tokens.\n tokens.shift();\n\n // Grab the attribute arguments, assuming the first to be an identifier.\n const [attributeCallIdentifier, ...attributeArguments] = parseArgumentTokens(\n tokens,\n stringArgumentPlaceholders\n );\n\n // The first attribute argument has to be an identifer, this will reference an agent function.\n if (attributeCallIdentifier?.type !== \"identifier\") {\n throw new Error(\"expected agent function name identifier argument for attribute\");\n }\n\n // Any attribute arguments (other than the expected call identifier) must have a type of string, number, boolean or null.\n attributeArguments\n .filter((arg) => arg.type === \"identifier\")\n .forEach((arg) => {\n throw new Error(\n `invalid attribute argument value '${arg.value}', must be string, number, boolean or null`\n );\n });\n\n // Create the attribute definition and add it to the object of attribute definitions found.\n attributes[nextAttributeName] = {\n call: attributeCallIdentifier.value,\n args: attributeArguments.map(({ value }) => value)\n };\n\n // Try to get the next attribute name token, as there could be multiple.\n nextAttributeName = tokens[0]?.toLowerCase() as keyof NodeAttributes;\n }\n\n return attributes;\n}\n", "import {\n ActionNodeDefinition,\n AnyChildNodeDefinition,\n AnyNodeDefinition,\n BranchNodeDefinition,\n ConditionNodeDefinition,\n FailNodeDefinition,\n FlipNodeDefinition,\n LottoNodeDefinition,\n ParallelNodeDefinition,\n RepeatNodeDefinition,\n RetryNodeDefinition,\n RootNodeDefinition,\n SelectorNodeDefinition,\n SequenceNodeDefinition,\n SucceedNodeDefinition,\n WaitNodeDefinition\n} from \"../BehaviourTreeDefinition\";\nimport { isCompositeNode, isDecoratorNode, isLeafNode, isRootNode } from \"../BehaviourTreeDefinitionUtilities\";\nimport { parseArgumentTokens } from \"./MDSLNodeArgumentParser\";\nimport { parseAttributeTokens } from \"./MDSLNodeAttributeParser\";\nimport {\n StringLiteralPlaceholders,\n parseTokensFromDefinition,\n popAndCheck,\n substituteStringLiterals\n} from \"./MDSLUtilities\";\n\n/**\n * Convert the MDSL tree definition string into an equivalent JSON definition.\n * @param definition The tree definition string as MDSL.\n * @returns The root node JSON definitions.\n */\nexport function convertMDSLToJSON(definition: string): RootNodeDefinition[] {\n // Swap out any node/attribute argument string literals with a placeholder and get a mapping of placeholders to original values as well as the processed definition.\n const { placeholders, processedDefinition } = substituteStringLiterals(definition);\n\n // Parse our definition definition string into an array of raw tokens.\n const tokens = parseTokensFromDefinition(processedDefinition);\n\n return convertTokensToJSONDefinition(tokens, placeholders);\n}\n\n/**\n * Converts the specified tree definition tokens into a JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The root node JSON definitions.\n */\nfunction convertTokensToJSONDefinition(\n tokens: string[],\n stringLiteralPlaceholders: StringLiteralPlaceholders\n): RootNodeDefinition[] {\n // There must be at least 3 tokens for the tree definition to be valid. 'ROOT', '{' and '}'.\n if (tokens.length < 3) {\n throw new Error(\"invalid token count\");\n }\n\n // We should have a matching number of '{' and '}' tokens. If not, then there are scopes that have not been properly closed.\n if (tokens.filter((token) => token === \"{\").length !== tokens.filter((token) => token === \"}\").length) {\n throw new Error(\"scope character mismatch\");\n }\n\n // Create an array of tree stack arrays where root nodes will always be at the botton and the current composite/decorator node at the top.\n // There should be an element in this array for every root node defined and every element should be an array with a root note as the first element.\n // E.g. A definition with two root nodes defined:\n // [\n // [root, lotto, sequence],\n // [root, selector]\n // ]\n const treeStacks: [Partial, ...Partial[]][] = [];\n\n // Create an array of all root node definitions that we create.\n const rootNodes: Partial[] = [];\n\n // A helper function used to push node definitions onto the tree stack.\n const pushNode = (node: AnyNodeDefinition) => {\n // If the node is a root node then we need to create a new tree stack array with the root node at the root.\n if (isRootNode(node)) {\n // Add the root node definition to our array of all parsed root node definitions.\n rootNodes.push(node);\n\n // Add the root node definition to the root of a new tree stack.\n treeStacks.push([node]);\n\n return;\n }\n\n // All non-root nodes should be pushed after their root nodes so handle cases\n // where we may not have any tree stacks or our top-most tree stack is empty.\n if (!treeStacks.length || !treeStacks[treeStacks.length - 1].length) {\n throw new Error(\"expected root node at base of definition\");\n }\n\n // Get the current tree stack that we are populating.\n const topTreeStack = treeStacks[treeStacks.length - 1];\n\n // Get the top-most node in the current tree stack, this will be a composite/decorator node\n // for which we will populate its children array if composite or setting its child if a decorator.\n const topTreeStackTopNode = topTreeStack[topTreeStack.length - 1] as AnyNodeDefinition;\n\n // If the top-most node in the current root stack is a composite or decorator\n // node then the current node should be added as a child of the top-most node.\n if (isCompositeNode(topTreeStackTopNode)) {\n topTreeStackTopNode.children = topTreeStackTopNode.children || [];\n topTreeStackTopNode.children.push(node);\n } else if (isDecoratorNode(topTreeStackTopNode)) {\n // If the top node already has a child node set then throw an error as a decorator should only have a single child.\n if (topTreeStackTopNode.child) {\n throw new Error(\"a decorator node must only have a single child node\");\n }\n\n topTreeStackTopNode.child = node;\n }\n\n // If the node we are adding is also a composite or decorator node, then we should push it\n // onto the current tree stack, as subsequent nodes will be added as its child/children.\n if (!isLeafNode(node)) {\n topTreeStack.push(node);\n }\n };\n\n // A helper function used to pop node definitions off of the stack.\n const popNode = () => {\n // Get the current tree stack that we are populating.\n const topTreeStack = treeStacks[treeStacks.length - 1];\n\n // Pop the top-most node in the current tree stack if there is one.\n if (topTreeStack.length) {\n topTreeStack.pop();\n }\n\n // We don't want any empty tree stacks in our stack of tree stacks.\n if (!topTreeStack.length) {\n treeStacks.pop();\n }\n };\n\n // We should keep processing the raw tokens until we run out of them.\n while (tokens.length) {\n // Grab the next token.\n const token = tokens.shift()!;\n\n // How we create the next node depends on the current raw token value.\n switch (token.toUpperCase()) {\n case \"ROOT\": {\n pushNode(createRootNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"SUCCEED\": {\n pushNode(createSucceedNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"FAIL\": {\n pushNode(createFailNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"FLIP\": {\n pushNode(createFlipNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"REPEAT\": {\n pushNode(createRepeatNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"RETRY\": {\n pushNode(createRetryNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"SEQUENCE\": {\n pushNode(createSequenceNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"SELECTOR\": {\n pushNode(createSelectorNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"PARALLEL\": {\n pushNode(createParallelNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"LOTTO\": {\n pushNode(createLottoNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"ACTION\": {\n pushNode(createActionNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"CONDITION\": {\n pushNode(createConditionNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"WAIT\": {\n pushNode(createWaitNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"BRANCH\": {\n pushNode(createBranchNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"}\": {\n // The '}' character closes the current scope and means that we have to pop a node off of the current stack.\n popNode();\n break;\n }\n\n default: {\n throw new Error(`unexpected token: ${token}`);\n }\n }\n }\n\n return rootNodes as RootNodeDefinition[];\n}\n\n/**\n * Creates a root node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The root node JSON definition.\n */\nfunction createRootNode(tokens: string[], stringLiteralPlaceholders: StringLiteralPlaceholders): RootNodeDefinition {\n // Create the root node definition.\n let node = {\n type: \"root\",\n id: undefined\n } as RootNodeDefinition;\n\n // Parse any node arguments, we should only have one if any which will be an identifier argument for the root identifier.\n const nodeArguments = parseArgumentTokens(tokens, stringLiteralPlaceholders);\n\n // Check whether any node arguments were defined.\n if (nodeArguments.length) {\n // We should only have one argument, if any, which will be an identifier argument for the root identifier.\n if (nodeArguments.length === 1 && nodeArguments[0].type === \"identifier\") {\n // The root node identifier will be the first and only node argument value.\n node.id = nodeArguments[0].value as string;\n } else {\n throw new Error(\"expected single root name argument\");\n }\n }\n\n // Grab any node attribute definitions and spread them into the node definition.\n node = { ...node, ...parseAttributeTokens(tokens, stringLiteralPlaceholders) };\n\n // This is a decorator node, so we expect an opening '{'.\n popAndCheck(tokens, \"{\");\n\n // Return the root node definition.\n return node;\n}\n\n/**\n * Creates a succeed node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The succeed node JSON definition.\n */\nfunction createSucceedNode(\n tokens: string[],\n stringLiteralPlaceholders: StringLiteralPlaceholders\n): SucceedNodeDefinition {\n const node = {\n type: \"succeed\",\n ...parseAttributeTokens(tokens, stringLiteralPlaceholders)\n } as SucceedNodeDefinition;\n\n // This is a decorator node, so we expect an opening '{'.\n popAndCheck(tokens, \"{\");\n\n // Return the succeed node definition.\n return node;\n}\n\n/**\n * Creates a fail node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The fail node JSON definition.\n */\nfunction createFailNode(tokens: string[], stringLiteralPlaceholders: StringLiteralPlaceholders): FailNodeDefinition {\n const node = {\n type: \"fail\",\n ...parseAttributeTokens(tokens, stringLiteralPlaceholders)\n } as FailNodeDefinition;\n\n // This is a decorator node, so we expect an opening '{'.\n popAndCheck(tokens, \"{\");\n\n // Return the fail node definition.\n return node;\n}\n\n/**\n * Creates a flip node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The flip node JSON definition.\n */\nfunction createFlipNode(tokens: string[], stringLiteralPlaceholders: StringLiteralPlaceholders): FlipNodeDefinition {\n const node = {\n type: \"flip\",\n ...parseAttributeTokens(tokens, stringLiteralPlaceholders)\n } as FlipNodeDefinition;\n\n // This is a decorator node, so we expect an opening '{'.\n popAndCheck(tokens, \"{\");\n\n // Return the flip node definition.\n return node;\n}\n\n/**\n * Creates a repeat node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The repeat node JSON definition.\n */\nfunction createRepeatNode(\n tokens: string[],\n stringLiteralPlaceholders: StringLiteralPlaceholders\n): RepeatNodeDefinition {\n let node = { type: \"repeat\" } as RepeatNodeDefinition;\n\n // Get the node arguments.\n const nodeArguments = parseArgumentTokens(tokens, stringLiteralPlaceholders);\n\n // The arguments of a repeat node are optional. We may have:\n // - No node arguments, in which case the repeat note will iterate indefinitely.\n // - One node argument which will be the explicit number of iterations to make.\n // - Two node arguments which define the min and max iteration bounds from which a random iteration count will be picked.\n if (nodeArguments.length) {\n // All repeat node arguments MUST be of type number and must be integer.\n nodeArguments\n .filter((arg) => arg.type !== \"number\" || !arg.isInteger)\n .forEach(() => {\n throw new Error(`repeat node iteration counts must be integer values`);\n });\n\n // We should have got one or two iteration counts.\n if (nodeArguments.length === 1) {\n // A static iteration count was defined.\n node.iterations = nodeArguments[0].value as number;\n } else if (nodeArguments.length === 2) {\n // A minimum and maximum iteration count was defined.\n node.iterations = [nodeArguments[0].value as number, nodeArguments[1].value as number];\n } else {\n // An incorrect number of iteration counts was defined.\n throw new Error(\"invalid number of repeat node iteration count arguments defined\");\n }\n }\n\n // Grab any node attribute definitions and spread them into the node definition.\n node = { ...node, ...parseAttributeTokens(tokens, stringLiteralPlaceholders) };\n\n // This is a decorator node, so we expect an opening '{'.\n popAndCheck(tokens, \"{\");\n\n // Return the repeat node definition.\n return node;\n}\n\n/**\n * Creates a retry node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The retry node JSON definition.\n */\nfunction createRetryNode(tokens: string[], stringLiteralPlaceholders: StringLiteralPlaceholders): RetryNodeDefinition {\n let node = { type: \"retry\" } as RetryNodeDefinition;\n\n // Get the node arguments.\n const nodeArguments = parseArgumentTokens(tokens, stringLiteralPlaceholders);\n\n // The arguments of a retry node are optional. We may have:\n // - No node arguments, in which case the retry note will attempt indefinitely.\n // - One node argument which will be the explicit number of attempts to make.\n // - Two node arguments which define the min and max attempt bounds from which a random attempt count will be picked.\n if (nodeArguments.length) {\n // All retry node arguments MUST be of type number and must be integer.\n nodeArguments\n .filter((arg) => arg.type !== \"number\" || !arg.isInteger)\n .forEach(() => {\n throw new Error(`retry node attempt counts must be integer values`);\n });\n\n // We should have got one or two attempt counts.\n if (nodeArguments.length === 1) {\n // A static attempt count was defined.\n node.attempts = nodeArguments[0].value as number;\n } else if (nodeArguments.length === 2) {\n // A minimum and maximum attempt count was defined.\n node.attempts = [nodeArguments[0].value as number, nodeArguments[1].value as number];\n } else {\n // An incorrect number of attempt counts was defined.\n throw new Error(\"invalid number of retry node attempt count arguments defined\");\n }\n }\n\n // Grab any node attribute definitions and spread them into the node definition.\n node = { ...node, ...parseAttributeTokens(tokens, stringLiteralPlaceholders) };\n\n // This is a decorator node, so we expect an opening '{'.\n popAndCheck(tokens, \"{\");\n\n // Return the retry node definition.\n return node;\n}\n\n/**\n * Creates a sequence node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The sequence node JSON definition.\n */\nfunction createSequenceNode(\n tokens: string[],\n stringLiteralPlaceholders: StringLiteralPlaceholders\n): SequenceNodeDefinition {\n const node = {\n type: \"sequence\",\n ...parseAttributeTokens(tokens, stringLiteralPlaceholders)\n } as SequenceNodeDefinition;\n\n // This is a composite node, so we expect an opening '{'.\n popAndCheck(tokens, \"{\");\n\n // Return the sequence node definition.\n return node;\n}\n\n/**\n * Creates a selector node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The selector node JSON definition.\n */\nfunction createSelectorNode(\n tokens: string[],\n stringLiteralPlaceholders: StringLiteralPlaceholders\n): SelectorNodeDefinition {\n const node = {\n type: \"selector\",\n ...parseAttributeTokens(tokens, stringLiteralPlaceholders)\n } as SelectorNodeDefinition;\n\n // This is a composite node, so we expect an opening '{'.\n popAndCheck(tokens, \"{\");\n\n // Return the selector node definition.\n return node;\n}\n\n/**\n * Creates a parallel node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The parallel node JSON definition.\n */\nfunction createParallelNode(\n tokens: string[],\n stringLiteralPlaceholders: StringLiteralPlaceholders\n): ParallelNodeDefinition {\n const node = {\n type: \"parallel\",\n ...parseAttributeTokens(tokens, stringLiteralPlaceholders)\n } as ParallelNodeDefinition;\n\n // This is a composite node, so we expect an opening '{'.\n popAndCheck(tokens, \"{\");\n\n // Return the parallel node definition.\n return node;\n}\n\n/**\n * Creates a lotto node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The lotto node JSON definition.\n */\nfunction createLottoNode(tokens: string[], stringLiteralPlaceholders: StringLiteralPlaceholders): LottoNodeDefinition {\n // If any node arguments have been defined then they must be our weights.\n const nodeArguments = parseArgumentTokens(tokens, stringLiteralPlaceholders);\n\n // All lotto node arguments MUST be of type number and must be integer.\n nodeArguments\n .filter((arg) => arg.type !== \"number\" || !arg.isInteger)\n .forEach(() => {\n throw new Error(`lotto node weight arguments must be integer values`);\n });\n\n const node = {\n type: \"lotto\",\n weights: nodeArguments.map(({ value }) => value),\n ...parseAttributeTokens(tokens, stringLiteralPlaceholders)\n } as LottoNodeDefinition;\n\n // This is a composite node, so we expect an opening '{'.\n popAndCheck(tokens, \"{\");\n\n // Return the lotto node definition.\n return node;\n}\n\n/**\n * Creates an action node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The action node JSON definition.\n */\nfunction createActionNode(\n tokens: string[],\n stringLiteralPlaceholders: StringLiteralPlaceholders\n): ActionNodeDefinition {\n // Parse any node arguments, we should have at least one which will be an identifier argument for the action name\n // and agent function to invoke for the action, all other arguments are to be passed as arguments to that function.\n const [actionNameIdentifier, ...agentFunctionArgs] = parseArgumentTokens(tokens, stringLiteralPlaceholders);\n\n // Our first argument MUST be defined and be an identifier as we require an action name argument.\n if (actionNameIdentifier?.type !== \"identifier\") {\n throw new Error(\"expected action name identifier argument\");\n }\n\n // Only the first argument should have been an identifier, all agent function arguments must be string, number, boolean or null.\n agentFunctionArgs\n .filter((arg) => arg.type === \"identifier\")\n .forEach((arg) => {\n throw new Error(\n `invalid action node argument value '${arg.value}', must be string, number, boolean or null`\n );\n });\n\n // Return the action node definition.\n return {\n type: \"action\",\n call: actionNameIdentifier.value,\n args: agentFunctionArgs.map(({ value }) => value),\n ...parseAttributeTokens(tokens, stringLiteralPlaceholders)\n };\n}\n\n/**\n * Creates a condition node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The condition node JSON definition.\n */\nfunction createConditionNode(\n tokens: string[],\n stringLiteralPlaceholders: StringLiteralPlaceholders\n): ConditionNodeDefinition {\n // Parse any node arguments, we should have at least one which will be an identifier argument for the condition name\n // and agent function to invoke for the condition, all other arguments are to be passed as arguments to that function.\n const [conditionNameIdentifier, ...agentFunctionArgs] = parseArgumentTokens(tokens, stringLiteralPlaceholders);\n\n // Our first argument MUST be defined and be an identifier as we require a condition name argument.\n if (conditionNameIdentifier?.type !== \"identifier\") {\n throw new Error(\"expected condition name identifier argument\");\n }\n\n // Only the first argument should have been an identifier, all agent function arguments must be string, number, boolean or null.\n agentFunctionArgs\n .filter((arg) => arg.type === \"identifier\")\n .forEach((arg) => {\n throw new Error(\n `invalid condition node argument value '${arg.value}', must be string, number, boolean or null`\n );\n });\n\n // Return the condition node definition.\n return {\n type: \"condition\",\n call: conditionNameIdentifier.value,\n args: agentFunctionArgs.map(({ value }) => value),\n ...parseAttributeTokens(tokens, stringLiteralPlaceholders)\n };\n}\n\n/**\n * Creates a wait node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The wait node JSON definition.\n */\nfunction createWaitNode(tokens: string[], stringLiteralPlaceholders: StringLiteralPlaceholders): WaitNodeDefinition {\n let node = { type: \"wait\" } as WaitNodeDefinition;\n\n // Get the node arguments.\n const nodeArguments = parseArgumentTokens(tokens, stringLiteralPlaceholders);\n\n // The arguments of a wait node are optional. We may have:\n // - No node arguments, in which case the wait will be indefinite until it is aborted.\n // - One node argument which will be the explicit duration of the wait.\n // - Two node arguments which define the min and max duration bounds from which a random duration will be picked.\n if (nodeArguments.length) {\n // All wait node arguments MUST be of type number and must be integer.\n nodeArguments\n .filter((arg) => arg.type !== \"number\" || !arg.isInteger)\n .forEach(() => {\n throw new Error(`wait node duration arguments must be integer values`);\n });\n\n // We may have:\n // - One node argument which will be the explicit duration of the wait.\n // - Two node arguments which define the min and max duration bounds from which a random duration will be picked.\n // - Too many arguments, which is not valid.\n if (nodeArguments.length === 1) {\n // An explicit duration was defined.\n node.duration = nodeArguments[0].value as number;\n } else if (nodeArguments.length === 2) {\n // Min and max duration bounds were defined from which a random duration will be picked.\n node.duration = [nodeArguments[0].value as number, nodeArguments[1].value as number];\n } else if (nodeArguments.length > 2) {\n // An incorrect number of duration arguments were defined.\n throw new Error(\"invalid number of wait node duration arguments defined\");\n }\n }\n\n // Return the wait node definition.\n return { ...node, ...parseAttributeTokens(tokens, stringLiteralPlaceholders) };\n}\n\n/**\n * Creates a branch node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The branch node JSON definition.\n */\nfunction createBranchNode(\n tokens: string[],\n stringLiteralPlaceholders: StringLiteralPlaceholders\n): BranchNodeDefinition {\n // Parse any node arguments, we should have one which will be an identifier argument for the root ref.\n const nodeArguments = parseArgumentTokens(tokens, stringLiteralPlaceholders);\n\n // We should have only a single identifer argument for a branch node, which is the root ref.\n if (nodeArguments.length !== 1 || nodeArguments[0].type !== \"identifier\") {\n throw new Error(\"expected single branch name argument\");\n }\n\n // Return the branch node definition.\n return { type: \"branch\", ref: nodeArguments[0].value };\n}\n", "import { RootNodeDefinition } from \"./BehaviourTreeDefinition\";\nimport { flattenDefinition, isBranchNode, isInteger } from \"./BehaviourTreeDefinitionUtilities\";\nimport { convertMDSLToJSON } from \"./mdsl/MDSLDefinitionParser\";\n\n/**\n * An object representing the result of validating a tree definition.\n */\nexport type DefinitionValidationResult = {\n /**\n * A flag defining whether validation succeeded.\n */\n succeeded: boolean;\n /**\n * A string containing the error message if validation did not succeed.\n */\n errorMessage?: string;\n};\n\n/**\n * Validates the specified behaviour tree definition in the form of JSON or MDSL, not taking any globally registered subtrees into consideration.\n * @param definition The behaviour tree definition in the form of JSON or MDSL.\n * @returns An object representing the result of validating the given tree definition.\n */\nexport function validateDefinition(definition: any): DefinitionValidationResult {\n // The definition must be defined.\n if (definition === null || typeof definition === \"undefined\") {\n return createValidationFailureResult(\"definition is null or undefined\");\n }\n\n // We are expecting a definition in one of three different forms:\n // - A string which we will assume is MDSL and we will parse this to JSON before validation.\n // - An array which we will assume is an array of root node definitions with at least one being the primary root node (no 'id' property)\n // - An object which we will assume is the primary root node and should not have an 'id' property.\n if (typeof definition === \"string\") {\n // The definition is a string which we can assume is MDSL, so attempt to validate it.\n return validateMDSLDefinition(definition);\n } else if (typeof definition === \"object\") {\n // The definition will either be an array (of root node definitions) or an object (the single primary root node definition).\n return validateJSONDefinition(definition);\n } else {\n return createValidationFailureResult(`unexpected definition type of '${typeof definition}'`);\n }\n}\n\n/**\n * Validates the specified behaviour tree definition in the form of MDSL.\n * @param definition The behaviour tree definition in the form of MDSL.\n * @returns An object representing the result of validating the given tree definition.\n */\nexport function validateMDSLDefinition(definition: string): DefinitionValidationResult {\n let rootNodeDefinitions;\n\n // The first thing the we need to do is to attempt to convert our MDSL into JSON.\n try {\n // The definition is a string which we can assume is MDSL, so attempt to parse it to a JSON definition in the form of an array of root node definitions.\n rootNodeDefinitions = convertMDSLToJSON(definition);\n } catch (error) {\n // We failed to parse the JSON from the MDSL, this is likely to be the result of it not being a valid MDSL string.\n return createValidationFailureResult(`invalid MDSL: ${error}`);\n }\n\n // Unpack all of the root node definitions into arrays of main ('id' defined) and sub ('id' not defined) root node definitions.\n const mainRootNodeDefinitions = rootNodeDefinitions.filter(({ id }) => typeof id === \"undefined\");\n const subRootNodeDefinitions = rootNodeDefinitions.filter(({ id }) => typeof id === \"string\" && id.length > 0);\n\n // We should ALWAYS have exactly one root node definition without an 'id' property defined, which is out main root node definition.\n if (mainRootNodeDefinitions.length !== 1) {\n return createValidationFailureResult(\n \"expected single unnamed root node at base of definition to act as main root\"\n );\n }\n\n // We should never have duplicate 'id' properties across our sub root node definitions.\n const subRootNodeIdenitifers: string[] = [];\n for (const { id } of subRootNodeDefinitions) {\n // Have we already come across this 'id' property value?\n if (subRootNodeIdenitifers.includes(id!)) {\n return createValidationFailureResult(`multiple root nodes found with duplicate name '${id}'`);\n }\n\n subRootNodeIdenitifers.push(id!);\n }\n\n try {\n // Validate our branch -> subtree links and check for any circular dependencies, we don't care about checking for broken subtree links here.\n validateBranchSubtreeLinks(rootNodeDefinitions, false);\n } catch (exception) {\n return createValidationFailureResult((exception as Error).message);\n }\n\n // Our definition was valid!\n return { succeeded: true };\n}\n\n/**\n * Validates the specified behaviour tree definition in the form of JSON.\n * @param definition The behaviour tree definition in the form of JSON.\n * @returns An object representing the result of validating the given tree definition.\n */\nexport function validateJSONDefinition(\n definition: RootNodeDefinition | RootNodeDefinition[]\n): DefinitionValidationResult {\n // The definition will either be an array (of root node definitions) or an object (the single primary root node definition).\n const rootNodeDefinitions = Array.isArray(definition) ? definition : [definition];\n\n // Iterate over our array of root nodes and call validateNode for each, passing an initial depth of 0, wrapped in a try catch to handle validation failures.\n try {\n rootNodeDefinitions.forEach((rootNodeDefinition) => validateNode(rootNodeDefinition, 0));\n } catch (error) {\n // Handle cases where we have caught a thrown Error and return a failure result with the error message.\n if (error instanceof Error) {\n return createValidationFailureResult(error.message);\n }\n\n // No idea what happened here!\n return createValidationFailureResult(`unexpected error: ${error}`);\n }\n\n // Unpack all of the root node definitions into arrays of main ('id' defined) and sub ('id' not defined) root node definitions.\n const mainRootNodeDefinitions = rootNodeDefinitions.filter(({ id }) => typeof id === \"undefined\");\n const subRootNodeDefinitions = rootNodeDefinitions.filter(({ id }) => typeof id === \"string\" && id.length > 0);\n\n // We should ALWAYS have exactly one root node definition without an 'id' property defined, which is out main root node definition.\n if (mainRootNodeDefinitions.length !== 1) {\n return createValidationFailureResult(\n \"expected single root node without 'id' property defined to act as main root\"\n );\n }\n\n // We should never have duplicate 'id' properties across our sub root node definitions.\n const subRootNodeIdenitifers: string[] = [];\n for (const { id } of subRootNodeDefinitions) {\n // Have we already come across this 'id' property value?\n if (subRootNodeIdenitifers.includes(id!)) {\n return createValidationFailureResult(\n `multiple root nodes found with duplicate 'id' property value of '${id}'`\n );\n }\n\n subRootNodeIdenitifers.push(id!);\n }\n\n try {\n // Validate our branch -> subtree links and check for any circular dependencies, we don't care about checking for broken subtree links here.\n validateBranchSubtreeLinks(rootNodeDefinitions, false);\n } catch (exception) {\n return createValidationFailureResult((exception as Error).message);\n }\n\n // Our definition was valid!\n return { succeeded: true };\n}\n\n/**\n * Validates the branch -> subtree links across all provided root node definitions.\n * This will not consider branch nodes that reference any globally registered subtrees unless includesGlobalSubtrees\n * is set to true, in which case we will also verify that there are no broken branch -> subtree links.\n * @param rootNodeDefinitions The array of root node definitions.\n * @param includesGlobalSubtrees A flag defining whether the array includes all global subtree root node definitions.\n */\nexport function validateBranchSubtreeLinks(rootNodeDefinitions: RootNodeDefinition[], includesGlobalSubtrees: boolean) {\n // Create a mapping of root node identifiers to other root nodes that they reference via branch nodes.\n // Below is an example of a mapping that includes a circular dependency (root => a => b => c => a)\n // [{ refs: [\"a\", \"b\"] }, { id: \"a\", refs: [\"b\"] }, { id: \"b\", refs: [\"c\"] }, { id: \"c\", refs: [\"a\"] }]\n const rootNodeMappings: { id: string | undefined; refs: string[] }[] = rootNodeDefinitions.map(\n (rootNodeDefinition) => ({\n id: rootNodeDefinition.id,\n refs: flattenDefinition(rootNodeDefinition)\n .filter(isBranchNode)\n .map(({ ref }) => ref)\n })\n );\n\n // A recursive function to walk through the mappings, keeping track of which root nodes we have visited in the form of a path of root node identifiers.\n const followRefs = (mapping: { id: string | undefined; refs: string[] }, path: (string | undefined)[] = []) => {\n // Have we found a circular dependency?\n if (path.includes(mapping.id)) {\n // We found a circular dependency! Get the bad path of root node identifiers.\n const badPath = [...path, mapping.id];\n\n // Create the formatted path value. [undefined, \"a\", \"b\", \"c\", \"a\"] would be formatted as \"a -> b -> c -> a\".\n const badPathFormatted = badPath.filter((element) => !!element).join(\" => \");\n\n // No need to continue, we found a circular dependency.\n throw new Error(`circular dependency found in branch node references: ${badPathFormatted}`);\n }\n\n for (const ref of mapping.refs) {\n // Find the mapping for the root node with an identifer matching the current ref.\n const subMapping = rootNodeMappings.find(({ id }) => id === ref);\n\n // We may not have a mapping for this ref, which is normal when we aren't considering all globally registered subtrees.\n if (subMapping) {\n followRefs(subMapping, [...path, mapping.id]);\n } else if (includesGlobalSubtrees) {\n // We found a reference to a root node that doesn't exist, which is a problem seeing as the root node definitons includes all globally registered subtrees.\n throw new Error(\n mapping.id\n ? `subtree '${mapping.id}' has branch node that references root node '${ref}' which has not been defined`\n : `primary tree has branch node that references root node '${ref}' which has not been defined`\n );\n }\n }\n };\n\n // Start looking for circular dependencies and broken references from the primary root node definition.\n followRefs(rootNodeMappings.find((mapping) => typeof mapping.id === \"undefined\")!);\n}\n\n/**\n * Validate an object that we expect to be a node definition.\n * @param definition An object that we expect to be a node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateNode(definition: any, depth: number): void {\n // Every node must be valid object and have a non-empty 'type' string property.\n if (typeof definition !== \"object\" || typeof definition.type !== \"string\" || definition.type.length === 0) {\n throw new Error(\n `node definition is not an object or 'type' property is not a non-empty string at depth '${depth}'`\n );\n }\n\n // How we validate this node definition will depend on its type.\n switch (definition.type) {\n case \"action\":\n validateActionNode(definition, depth);\n break;\n\n case \"condition\":\n validateConditionNode(definition, depth);\n break;\n\n case \"wait\":\n validateWaitNode(definition, depth);\n break;\n\n case \"branch\":\n validateBranchNode(definition, depth);\n break;\n\n case \"root\":\n validateRootNode(definition, depth);\n break;\n\n case \"success\":\n validateSuccessNode(definition, depth);\n break;\n\n case \"fail\":\n validateFailNode(definition, depth);\n break;\n\n case \"flip\":\n validateFlipNode(definition, depth);\n break;\n\n case \"repeat\":\n validateRepeatNode(definition, depth);\n break;\n\n case \"retry\":\n validateRetryNode(definition, depth);\n break;\n\n case \"sequence\":\n validateSequenceNode(definition, depth);\n break;\n\n case \"selector\":\n validateSelectorNode(definition, depth);\n break;\n\n case \"parallel\":\n validateParallelNode(definition, depth);\n break;\n\n default:\n throw new Error(`unexpected node type of '${definition.type}' at depth '${depth}'`);\n }\n}\n\n/**\n * Validate any attributes for a given node definition.\n * @param definition The node definition.\n * @param depth The depth of the node in the behaviour tree definition.\n */\nfunction validateNodeAttributes(definition: any, depth: number): void {\n // Validate each of the attribute types for this node.\n [\"while\", \"until\", \"entry\", \"exit\", \"step\"].forEach((attributeName) => {\n // Attempt to grab the definition for the current attribute from the node definition.\n const attributeDefinition = definition[attributeName];\n\n // All node attributes are optional, so there is nothing to do if the current attribute is not defined.\n if (typeof attributeDefinition === \"undefined\") {\n return;\n }\n\n // The attribute definition must be an object.\n if (typeof attributeDefinition !== \"object\") {\n throw new Error(\n `expected attribute '${attributeName}' to be an object for '${definition.type}' node at depth '${depth}'`\n );\n }\n\n // The 'call' property must be defined for any attribute definition.\n if (typeof attributeDefinition.call !== \"string\" || attributeDefinition.call.length === 0) {\n throw new Error(\n `expected 'call' property for attribute '${attributeName}' to be a non-empty string for '${definition.type}' node at depth '${depth}'`\n );\n }\n\n // If any node attribute arguments have been defined then they must have been defined in an array.\n if (typeof attributeDefinition.args !== \"undefined\" && !Array.isArray(attributeDefinition.args)) {\n throw new Error(\n `expected 'args' property for attribute '${attributeName}' to be an array for '${definition.type}' node at depth '${depth}'`\n );\n }\n });\n}\n\n/**\n * Validate an object that we expect to be a root node definition.\n * @param definition An object that we expect to be a root node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateRootNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"root\") {\n throw new Error(\"expected node type of 'root' for root node\");\n }\n\n // A root node cannot be the child of another node.\n if (depth > 0) {\n throw new Error(\"a root node cannot be the child of another node\");\n }\n\n // Check that, if the root node 'id' property is defined, it is a non-empty string.\n if (typeof definition.id !== \"undefined\" && (typeof definition.id !== \"string\" || definition.id.length === 0)) {\n throw new Error(\"expected non-empty string for 'id' property if defined for root node\");\n }\n\n // A root node is a decorator node, so must have a child node defined.\n if (typeof definition.child === \"undefined\") {\n throw new Error(\"expected property 'child' to be defined for root node\");\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n\n // Validate the child node of this decorator node.\n validateNode(definition.child, depth + 1);\n}\n\n/**\n * Validate an object that we expect to be a success node definition.\n * @param definition An object that we expect to be a success node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateSuccessNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"success\") {\n throw new Error(`expected node type of 'success' for success node at depth '${depth}'`);\n }\n\n // A success node is a decorator node, so must have a child node defined.\n if (typeof definition.child === \"undefined\") {\n throw new Error(`expected property 'child' to be defined for success node at depth '${depth}'`);\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n\n // Validate the child node of this decorator node.\n validateNode(definition.child, depth + 1);\n}\n\n/**\n * Validate an object that we expect to be a fail node definition.\n * @param definition An object that we expect to be a fail node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateFailNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"fail\") {\n throw new Error(`expected node type of 'fail' for fail node at depth '${depth}'`);\n }\n\n // A fail node is a decorator node, so must have a child node defined.\n if (typeof definition.child === \"undefined\") {\n throw new Error(`expected property 'child' to be defined for fail node at depth '${depth}'`);\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n\n // Validate the child node of this decorator node.\n validateNode(definition.child, depth + 1);\n}\n\n/**\n * Validate an object that we expect to be a flip node definition.\n * @param definition An object that we expect to be a flip node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateFlipNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"flip\") {\n throw new Error(`expected node type of 'flip' for flip node at depth '${depth}'`);\n }\n\n // A flip node is a decorator node, so must have a child node defined.\n if (typeof definition.child === \"undefined\") {\n throw new Error(`expected property 'child' to be defined for flip node at depth '${depth}'`);\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n\n // Validate the child node of this decorator node.\n validateNode(definition.child, depth + 1);\n}\n\n/**\n * Validate an object that we expect to be a repeat node definition.\n * @param definition An object that we expect to be a repeat node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateRepeatNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"repeat\") {\n throw new Error(`expected node type of 'repeat' for repeat node at depth '${depth}'`);\n }\n\n // A repeat node is a decorator node, so must have a child node defined.\n if (typeof definition.child === \"undefined\") {\n throw new Error(`expected property 'child' to be defined for repeat node at depth '${depth}'`);\n }\n\n // Check whether an 'iterations' property has been defined, it may not have been if this node is to repeat indefinitely.\n if (typeof definition.iterations !== \"undefined\") {\n if (Array.isArray(definition.iterations)) {\n // Check whether any elements of the array are not integer values.\n const containsNonInteger = !!definition.iterations.find((value: unknown) => !isInteger(value));\n\n // If the 'iterations' property is an array then it MUST contain two integer values.\n if (definition.iterations.length !== 2 || containsNonInteger) {\n throw new Error(\n `expected array containing two integer values for 'iterations' property if defined for repeat node at depth '${depth}'`\n );\n }\n } else if (!isInteger(definition.iterations)) {\n throw new Error(\n `expected integer value or array containing two integer values for 'iterations' property if defined for repeat node at depth '${depth}'`\n );\n }\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n\n // Validate the child node of this decorator node.\n validateNode(definition.child, depth + 1);\n}\n\n/**\n * Validate an object that we expect to be a retry node definition.\n * @param definition An object that we expect to be a retry node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateRetryNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"retry\") {\n throw new Error(`expected node type of 'retry' for retry node at depth '${depth}'`);\n }\n\n // A retry node is a decorator node, so must have a child node defined.\n if (typeof definition.child === \"undefined\") {\n throw new Error(`expected property 'child' to be defined for retry node at depth '${depth}'`);\n }\n\n // Check whether an 'attempts' property has been defined, it may not have been if this node is to retry indefinitely.\n if (typeof definition.attempts !== \"undefined\") {\n if (Array.isArray(definition.attempts)) {\n // Check whether any elements of the array are not integer values.\n const containsNonInteger = !!definition.attempts.find((value: unknown) => !isInteger(value));\n\n // If the 'attempts' property is an array then it MUST contain two integer values.\n if (definition.attempts.length !== 2 || containsNonInteger) {\n throw new Error(\n `expected array containing two integer values for 'attempts' property if defined for retry node at depth '${depth}'`\n );\n }\n } else if (!isInteger(definition.attempts)) {\n throw new Error(\n `expected integer value or array containing two integer values for 'attempts' property if defined for retry node at depth '${depth}'`\n );\n }\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n\n // Validate the child node of this decorator node.\n validateNode(definition.child, depth + 1);\n}\n\n/**\n * Validate an object that we expect to be a branch node definition.\n * @param definition An object that we expect to be a branch node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateBranchNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"branch\") {\n throw new Error(`expected node type of 'branch' for branch node at depth '${depth}'`);\n }\n\n // Check that the branch node 'ref' property is defined and is a non-empty string.\n if (typeof definition.ref !== \"string\" || definition.ref.length === 0) {\n throw new Error(`expected non-empty string for 'ref' property for branch node at depth '${depth}'`);\n }\n\n // It is invalid to define guard attributes for a branch node as they should be defined on the referenced root node.\n [\"while\", \"until\"].forEach((attributeName) => {\n if (typeof definition[attributeName] !== \"undefined\") {\n throw new Error(\n `guards should not be defined for branch nodes but guard '${attributeName}' was defined for branch node at depth '${depth}'`\n );\n }\n });\n\n // It is invalid to define callback attributes for a branch node as they should be defined on the referenced root node.\n [\"entry\", \"exit\", \"step\"].forEach((attributeName) => {\n if (typeof definition[attributeName] !== \"undefined\") {\n throw new Error(\n `callbacks should not be defined for branch nodes but callback '${attributeName}' was defined for branch node at depth '${depth}'`\n );\n }\n });\n}\n\n/**\n * Validate an object that we expect to be a action node definition.\n * @param definition An object that we expect to be a action node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateActionNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"action\") {\n throw new Error(`expected node type of 'action' for action node at depth '${depth}'`);\n }\n\n // The 'call' property must be defined for a action node definition.\n if (typeof definition.call !== \"string\" || definition.call.length === 0) {\n throw new Error(`expected non-empty string for 'call' property of action node at depth '${depth}'`);\n }\n\n // If any action function arguments have been defined then they must have been defined in an array.\n if (typeof definition.args !== \"undefined\" && !Array.isArray(definition.args)) {\n throw new Error(`expected array for 'args' property if defined for action node at depth '${depth}'`);\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n}\n\n/**\n * Validate an object that we expect to be a condition node definition.\n * @param definition An object that we expect to be a condition node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateConditionNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"condition\") {\n throw new Error(`expected node type of 'condition' for condition node at depth '${depth}'`);\n }\n\n // The 'call' property must be defined for a condition node definition.\n if (typeof definition.call !== \"string\" || definition.call.length === 0) {\n throw new Error(`expected non-empty string for 'call' property of condition node at depth '${depth}'`);\n }\n\n // If any condition function arguments have been defined then they must have been defined in an array.\n if (typeof definition.args !== \"undefined\" && !Array.isArray(definition.args)) {\n throw new Error(`expected array for 'args' property if defined for condition node at depth '${depth}'`);\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n}\n\n/**\n * Validate an object that we expect to be a wait node definition.\n * @param definition An object that we expect to be a wait node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateWaitNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"wait\") {\n throw new Error(`expected node type of 'wait' for wait node at depth '${depth}'`);\n }\n\n // Check whether a 'duration' property has been defined, it may not have been if this node is to wait indefinitely.\n if (typeof definition.duration !== \"undefined\") {\n if (Array.isArray(definition.duration)) {\n // Check whether any elements of the array are not integer values.\n const containsNonInteger = !!definition.duration.find((value: unknown) => !isInteger(value));\n\n // If the 'duration' property is an array then it MUST contain two integer values.\n if (definition.duration.length !== 2 || containsNonInteger) {\n throw new Error(\n `expected array containing two integer values for 'duration' property if defined for wait node at depth '${depth}'`\n );\n }\n } else if (!isInteger(definition.duration)) {\n throw new Error(\n `expected integer value or array containing two integer values for 'duration' property if defined for wait node at depth '${depth}'`\n );\n }\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n}\n\n/**\n * Validate an object that we expect to be a sequence node definition.\n * @param definition An object that we expect to be a sequence node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateSequenceNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"sequence\") {\n throw new Error(`expected node type of 'sequence' for sequence node at depth '${depth}'`);\n }\n\n // A sequence node is a composite node, so must have a children nodes array defined.\n if (!Array.isArray(definition.children) || definition.children.length === 0) {\n throw new Error(`expected non-empty 'children' array to be defined for sequence node at depth '${depth}'`);\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n\n // Validate the child nodes of this composite node.\n definition.children.forEach((child: any) => validateNode(child, depth + 1));\n}\n\n/**\n * Validate an object that we expect to be a selector node definition.\n * @param definition An object that we expect to be a selector node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateSelectorNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"selector\") {\n throw new Error(`expected node type of 'selector' for selector node at depth '${depth}'`);\n }\n\n // A selector node is a composite node, so must have a children nodes array defined.\n if (!Array.isArray(definition.children) || definition.children.length === 0) {\n throw new Error(`expected non-empty 'children' array to be defined for selector node at depth '${depth}'`);\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n\n // Validate the child nodes of this composite node.\n definition.children.forEach((child: any) => validateNode(child, depth + 1));\n}\n\n/**\n * Validate an object that we expect to be a parallel node definition.\n * @param definition An object that we expect to be a parallel node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateParallelNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"parallel\") {\n throw new Error(`expected node type of 'parallel' for parallel node at depth '${depth}'`);\n }\n\n // A parallel node is a composite node, so must have a children nodes array defined.\n if (!Array.isArray(definition.children) || definition.children.length === 0) {\n throw new Error(`expected non-empty 'children' array to be defined for parallel node at depth '${depth}'`);\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n\n // Validate the child nodes of this composite node.\n definition.children.forEach((child: any) => validateNode(child, depth + 1));\n}\n\n/**\n * A helper function to create a failure validation result with the given error message.\n * @param errorMessage The validation failure error message.\n * @returns A failure validation result with the given error message.\n */\nfunction createValidationFailureResult(errorMessage: string): DefinitionValidationResult {\n return { succeeded: false, errorMessage };\n}\n", "import { ActionResult, Agent, GlobalFunction } from \"./Agent\";\nimport { RootNodeDefinition } from \"./BehaviourTreeDefinition\";\n\nexport type InvokerFunction = (args: any[]) => ActionResult;\n\n/**\n * A singleton used to store and lookup registered functions and subtrees.\n */\nexport default class Lookup {\n /**\n * The object holding any registered functions keyed on function name.\n */\n private static functionTable: { [key: string]: GlobalFunction } = {};\n /**\n * The object holding any registered subtree root node definitions keyed on tree name.\n */\n private static subtreeTable: { [key: string]: RootNodeDefinition } = {};\n\n /**\n * Gets the function with the specified name.\n * @param name The name of the function.\n * @returns The function with the specified name.\n */\n public static getFunc(name: string): GlobalFunction {\n return this.functionTable[name];\n }\n\n /**\n * Sets the function with the specified name for later lookup.\n * @param name The name of the function.\n * @param func The function.\n */\n public static setFunc(name: string, func: GlobalFunction): void {\n this.functionTable[name] = func;\n }\n\n /**\n * Gets the function invoker for the specified agent and function name.\n * If a function with the specified name exists on the agent object then it will\n * be returned, otherwise we will then check the registered functions for a match.\n * @param agent The agent instance that this behaviour tree is modelling behaviour for.\n * @param name The function name.\n * @returns The function invoker for the specified agent and function name.\n */\n static getFuncInvoker(agent: Agent, name: string): InvokerFunction | null {\n // Check whether the agent contains the specified function.\n const foundOnAgent = agent[name];\n if (foundOnAgent && typeof foundOnAgent === \"function\") {\n return (args: any[]): boolean | ActionResult => foundOnAgent.apply(agent, args);\n }\n\n // The agent does not contain the specified function but it may have been registered at some point.\n if (this.functionTable[name] && typeof this.functionTable[name] === \"function\") {\n return (args: any[]) => this.functionTable[name](agent, ...args.map((arg) => arg.value));\n }\n\n // We have no function to invoke.\n return null;\n }\n\n /**\n * Gets all registered subtree root node definitions.\n */\n static getSubtrees(): { [key: string]: RootNodeDefinition } {\n return this.subtreeTable;\n }\n\n /**\n * Sets the subtree with the specified name for later lookup.\n * @param name The name of the subtree.\n * @param subtree The subtree.\n */\n static setSubtree(name: string, subtree: RootNodeDefinition) {\n this.subtreeTable[name] = subtree;\n }\n\n /**\n * Removes the registered function or subtree with the specified name.\n * @param name The name of the registered function or subtree.\n */\n static remove(name: string) {\n delete this.functionTable[name];\n delete this.subtreeTable[name];\n }\n\n /**\n * Remove all registered functions and subtrees.\n */\n static empty() {\n this.functionTable = {};\n this.subtreeTable = {};\n }\n}\n", "import Node from \"../../nodes/Node\";\n\n/**\n * An exception thrown when evaluating node guard path conditions and a conditions fails.\n */\nexport default class GuardUnsatisifedException extends Error {\n /**\n * @param source The node at which a guard condition failed.\n */\n constructor(private source: Node) {\n super(\"A guard path condition has failed\");\n }\n\n /**\n * Gets whether the specified node is the node at which a guard condition failed.\n * @param node The node to check against the source node.\n * @returns Whether the specified node is the node at which a guard condition failed.\n */\n isSourceNode = (node: Node) => node === this.source;\n}\n", "import { Agent } from \"../../Agent\";\nimport Guard from \"./Guard\";\nimport Node from \"../../nodes/Node\";\nimport GuardUnsatisifedException from \"./GuardUnsatisifedException\";\n\nexport type GuardPathPart = {\n node: Node;\n guards: Guard[];\n};\n\n/**\n * Represents a path of node guards along a root-to-leaf tree path.\n */\nexport default class GuardPath {\n /**\n * @param nodes An array of objects defining a node instance -> guard link, ordered by node depth.\n */\n constructor(private nodes: GuardPathPart[]) {}\n\n /**\n * Evaluate guard conditions for all guards in the tree path, moving outwards from the root.\n * @param agent The agent, required for guard evaluation.\n * @returns An evaluation results object.\n */\n evaluate = (agent: Agent) => {\n // We need to evaluate guard conditions for nodes up the tree, moving outwards from the root.\n for (const details of this.nodes) {\n // There can be multiple guards per node.\n for (const guard of details.guards) {\n // Check whether the guard condition passes, and throw an exception if not.\n if (!guard.isSatisfied(agent)) {\n throw new GuardUnsatisifedException(details.node);\n }\n }\n }\n };\n}\n", "import { BehaviourTreeOptions } from \"../BehaviourTreeOptions\";\nimport State, { AnyState } from \"../State\";\nimport { Agent } from \"../Agent\";\nimport Leaf from \"./leaf/Leaf\";\nimport Attribute from \"../attributes/Attribute\";\nimport Entry from \"../attributes/callbacks/Entry\";\nimport Exit from \"../attributes/callbacks/Exit\";\nimport Step from \"../attributes/callbacks/Step\";\nimport Guard from \"../attributes/guards/Guard\";\nimport GuardPath from \"../attributes/guards/GuardPath\";\nimport GuardUnsatisifedException from \"../attributes/guards/GuardUnsatisifedException\";\n\n/**\n * A base node.\n */\nexport default abstract class Node {\n /**\n * The node uid.\n */\n private readonly uid: string = createNodeUid();\n /**\n * The node state.\n */\n private state: AnyState = State.READY;\n /**\n * The guard path to evaluate as part of a node update.\n */\n private guardPath: GuardPath | undefined;\n\n /**\n * @param type The node type.\n * @param attributes The node attributes.\n * @param args The node argument definitions.\n */\n constructor(private type: string, private attributes: Attribute[], private args: any[]) {}\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected abstract onUpdate(agent: Agent, options: BehaviourTreeOptions): void;\n\n /**\n * Gets the name of the node.\n */\n public abstract getName(): string;\n\n /**\n * Gets whether this node is a leaf node.\n */\n public abstract isLeafNode: () => this is Leaf;\n\n /**\n * Gets/Sets the state of the node.\n */\n getState = (): AnyState => this.state;\n setState = (value: AnyState): void => {\n this.state = value;\n };\n\n /**\n * Gets the unique id of the node.\n */\n getUid = () => this.uid;\n\n /**\n * Gets the type of the node.\n */\n getType = () => this.type;\n\n /**\n * Gets the node attributes.\n */\n getAttributes = () => this.attributes;\n\n /**\n * Gets the node arguments.\n */\n getArguments = () => this.args;\n\n /**\n * Gets the node attribute with the specified type, or null if it does not exist.\n */\n getAttribute(type: \"entry\" | \"ENTRY\"): Entry;\n getAttribute(type: \"exit\" | \"EXIT\"): Exit;\n getAttribute(type: \"step\" | \"STEP\"): Step;\n getAttribute(type: string): Attribute {\n return (\n this.getAttributes().filter((decorator) => decorator.type.toUpperCase() === type.toUpperCase())[0] || null\n );\n }\n\n /**\n * Gets the node attributes.\n */\n getGuardAttributes = (): Guard[] => this.getAttributes().filter((decorator) => decorator.isGuard()) as Guard[];\n\n /**\n * Sets the guard path to evaluate as part of a node update.\n */\n setGuardPath = (value: GuardPath) => (this.guardPath = value);\n\n /**\n * Gets whether a guard path is assigned to this node.\n */\n hasGuardPath = () => !!this.guardPath;\n\n /**\n * Gets whether this node is in the specified state.\n * @param value The value to compare to the node state.\n */\n public is(value: AnyState): boolean {\n return this.state === value;\n }\n\n /**\n * Reset the state of the node.\n */\n public reset(): void {\n this.setState(State.READY);\n }\n\n /**\n * Abort the running of this node.\n * @param agent The agent.\n */\n public abort(agent: Agent): void {\n // There is nothing to do if this node is not in the running state.\n if (!this.is(State.RUNNING)) {\n return;\n }\n\n // Reset the state of this node.\n this.reset();\n\n this.getAttribute(\"exit\")?.callAgentFunction(agent, false, true);\n }\n\n /**\n * Update the node.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n * @returns The result of the update.\n */\n public update(agent: Agent, options: BehaviourTreeOptions): void {\n // If this node is already in a 'SUCCEEDED' or 'FAILED' state then there is nothing to do.\n if (this.is(State.SUCCEEDED) || this.is(State.FAILED)) {\n return;\n }\n\n try {\n // Evaluate all of the guard path conditions for the current tree path.\n this.guardPath!.evaluate(agent);\n\n // If this node is in the READY state then call the ENTRY for this node if it exists.\n if (this.is(State.READY)) {\n this.getAttribute(\"entry\")?.callAgentFunction(agent);\n }\n\n this.getAttribute(\"step\")?.callAgentFunction(agent);\n\n // Do the actual update.\n this.onUpdate(agent, options);\n\n // If this node is now in a 'SUCCEEDED' or 'FAILED' state then call the EXIT for this node if it exists.\n if (this.is(State.SUCCEEDED) || this.is(State.FAILED)) {\n this.getAttribute(\"exit\")?.callAgentFunction(agent, this.is(State.SUCCEEDED), false);\n }\n } catch (error) {\n // If the error is a GuardUnsatisfiedException then we need to determine if this node is the source.\n if (error instanceof GuardUnsatisifedException && error.isSourceNode(this)) {\n // Abort the current node.\n this.abort(agent);\n\n // Any node that is the source of an abort will be a failed node.\n this.setState(State.FAILED);\n } else {\n throw error;\n }\n }\n }\n}\n\n/**\n * Create a randomly generated node uid.\n * @returns A randomly generated node uid.\n */\nfunction createNodeUid(): string {\n var S4 = function () {\n return (((1 + Math.random()) * 0x10000) | 0).toString(16).substring(1);\n };\n return S4() + S4() + \"-\" + S4() + \"-\" + S4() + \"-\" + S4() + \"-\" + S4() + S4() + S4();\n}\n", "import Node from \"../Node\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\n\n/**\n * A decorator node that wraps a single child node.\n */\nexport default abstract class Decorator extends Node {\n /**\n * @param type The node type.\n * @param attributes The node attributes.\n * @param child The child node.\n */\n constructor(type: string, attributes: Attribute[], protected child: Node) {\n super(type, attributes, []);\n }\n\n /**\n * Gets whether this node is a leaf node.\n */\n isLeafNode = () => false;\n\n /**\n * Gets the children of this node.\n */\n getChildren = () => [this.child];\n\n /**\n * Reset the state of the node.\n */\n reset = () => {\n // Reset the state of this node.\n this.setState(State.READY);\n\n // Reset the state of the child node.\n this.child.reset();\n };\n\n /**\n * Abort the running of this node.\n * @param agent The agent.\n */\n abort = (agent: Agent) => {\n // There is nothing to do if this node is not in the running state.\n if (!this.is(State.RUNNING)) {\n return;\n }\n\n // Abort the child node.\n this.child.abort(agent);\n\n // Reset the state of this node.\n this.reset();\n\n this.getAttribute(\"exit\")?.callAgentFunction(agent, false, true);\n };\n}\n", "import Node from \"../Node\";\nimport Decorator from \"./Decorator\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A Root node.\n * The root node will have a single child.\n */\nexport default class Root extends Decorator {\n /**\n * @param attributes The node attributes.\n * @param child The child node.\n */\n constructor(attributes: Attribute[], child: Node) {\n super(\"root\", attributes, child);\n }\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // If the child has never been updated or is running then we will need to update it now.\n if (this.child.getState() === State.READY || this.child.getState() === State.RUNNING) {\n // Update the child of this node.\n this.child.update(agent, options);\n }\n\n // The state of the root node is the state of its child.\n this.setState(this.child.getState());\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => \"ROOT\";\n}\n", "import Guard from \"./guards/Guard\";\n\nexport type AttributeDetails = {\n /** The attribute type. */\n type: string;\n\n /** The attribute arguments. */\n args: any[];\n};\n\n/**\n * A base node attribute.\n */\nexport default abstract class Attribute {\n /**\n * @param type The node attribute type.\n * @param args The array of attribute arguments.\n */\n constructor(public type: string, public args: any[]) {}\n\n /**\n * Gets the attribute details.\n */\n abstract getDetails(): TAttributeDetails;\n\n /**\n * Gets whether this attribute is a guard.\n */\n abstract isGuard: () => this is Guard;\n}\n", "import { Agent } from \"../../Agent\";\nimport Attribute, { AttributeDetails } from \"../Attribute\";\n\nexport type GuardAttributeDetails = {\n /** The name of the condition function that determines whether the guard is satisfied. */\n condition: string;\n} & AttributeDetails;\n\n/**\n * A base node guard attribute.\n */\nexport default abstract class Guard extends Attribute {\n /**\n * @param type The node attribute type.\n * @param args The array of decorator argument definitions.\n * @param condition The name of the condition function that determines whether the guard is satisfied.\n */\n constructor(type: string, args: any[], private condition: string) {\n super(type, args);\n }\n\n /**\n * Gets the name of the condition function that determines whether the guard is satisfied.\n */\n getCondition = () => this.condition;\n\n /**\n * Gets whether this attribute is a guard.\n */\n isGuard = () => true;\n\n /**\n * Gets the attribute details.\n */\n getDetails(): GuardAttributeDetails {\n return {\n type: this.type,\n args: this.args,\n condition: this.getCondition()\n };\n }\n\n /**\n * Gets whether the guard is satisfied.\n * @param agent The agent.\n * @returns Whether the guard is satisfied.\n */\n abstract isSatisfied(agent: Agent): boolean;\n}\n", "import Guard from \"./Guard\";\nimport Lookup from \"../../Lookup\";\nimport { Agent } from \"../../Agent\";\n\n/**\n * A WHILE guard which is satisfied as long as the given condition remains true.\n */\nexport default class While extends Guard {\n /**\n * @param condition The name of the condition function that determines whether the guard is satisfied.\n * @param args The array of decorator argument definitions.\n */\n constructor(condition: string, args: any[]) {\n super(\"while\", args, condition);\n }\n\n /**\n * Gets whether the guard is satisfied.\n * @param agent The agent.\n * @returns Whether the guard is satisfied.\n */\n isSatisfied = (agent: Agent) => {\n // Attempt to get the invoker for the condition function.\n const conditionFuncInvoker = Lookup.getFuncInvoker(agent, this.getCondition());\n\n // The condition function should be defined.\n if (conditionFuncInvoker === null) {\n throw new Error(\n `cannot evaluate node guard as the condition '${this.getCondition()}' function is not defined on the agent and has not been registered`\n );\n }\n\n // Call the condition function to determine whether this guard is satisfied.\n return !!conditionFuncInvoker(this.args);\n };\n}\n", "import Guard from \"./Guard\";\nimport Lookup from \"../../Lookup\";\nimport { Agent } from \"../../Agent\";\n\n/**\n * An UNTIL guard which is satisfied as long as the given condition remains false.\n */\nexport default class Until extends Guard {\n /**\n * @param condition The name of the condition function that determines whether the guard is satisfied.\n * @param args The array of decorator argument definitions.\n */\n constructor(condition: string, args: any[]) {\n super(\"until\", args, condition);\n }\n\n /**\n * Gets whether the guard is satisfied.\n * @param agent The agent.\n * @returns Whether the guard is satisfied.\n */\n isSatisfied = (agent: Agent) => {\n // Attempt to get the invoker for the condition function.\n const conditionFuncInvoker = Lookup.getFuncInvoker(agent, this.getCondition());\n\n // The condition function should be defined.\n if (conditionFuncInvoker === null) {\n throw new Error(\n `cannot evaluate node guard as the condition '${this.getCondition()}' function is not defined on the agent and has not been registered`\n );\n }\n\n // Call the condition function to determine whether this guard is satisfied.\n return !!!conditionFuncInvoker(this.args);\n };\n}\n", "import { Agent } from \"../../Agent\";\nimport Attribute, { AttributeDetails } from \"../Attribute\";\n\nexport type CallbackAttributeDetails = {\n /** The name of the agent function that is called. */\n functionName: string;\n} & AttributeDetails;\n\n/**\n * A base node callback attribute.\n */\nexport default abstract class Callback extends Attribute {\n /**\n * @param type The node attribute type.\n * @param args The array of decorator argument definitions.\n * @param functionName The name of the agent function to call.\n */\n constructor(type: string, args: any[], private functionName: string) {\n super(type, args);\n }\n\n /**\n * Gets the name of the agent function to call.\n */\n getFunctionName = () => this.functionName;\n\n /**\n * Gets whether this attribute is a guard.\n */\n isGuard = () => false;\n\n /**\n * Gets the attribute details.\n */\n getDetails(): CallbackAttributeDetails {\n return {\n type: this.type,\n args: this.args,\n functionName: this.getFunctionName()\n };\n }\n\n /**\n * Attempt to call the agent function that this callback refers to.\n * @param agent The agent.\n */\n abstract callAgentFunction: (agent: Agent, isSuccess: boolean, isAborted: boolean) => void;\n}\n", "import Callback from \"./Callback\";\nimport Lookup from \"../../Lookup\";\nimport { Agent } from \"../../Agent\";\n\n/**\n * An ENTRY callback which defines an agent function to call when the associated node is updated and moves out of running state.\n */\nexport default class Entry extends Callback {\n /**\n * @param functionName The name of the agent function to call.\n * @param args The array of callback argument definitions.\n */\n constructor(functionName: string, args: any[]) {\n super(\"entry\", args, functionName);\n }\n\n /**\n * Attempt to call the agent function that this callback refers to.\n * @param agent The agent.\n */\n callAgentFunction = (agent: Agent) => {\n // Attempt to get the invoker for the callback function.\n const callbackFuncInvoker = Lookup.getFuncInvoker(agent, this.getFunctionName());\n\n // The callback function should be defined.\n if (callbackFuncInvoker === null) {\n throw new Error(\n `cannot call entry function '${this.getFunctionName()}' as is not defined on the agent and has not been registered`\n );\n }\n\n // Call the callback function.\n callbackFuncInvoker(this.args);\n };\n}\n", "import Callback from \"./Callback\";\nimport Lookup from \"../../Lookup\";\nimport { Agent } from \"../../Agent\";\n\n/**\n * A STEP callback which defines an agent function to call when the associated node is updated.\n */\nexport default class Step extends Callback {\n /**\n * @param functionName The name of the agent function to call.\n * @param args The array of callback argument definitions.\n */\n constructor(functionName: string, args: any[]) {\n super(\"step\", args, functionName);\n }\n\n /**\n * Attempt to call the agent function that this callback refers to.\n * @param agent The agent.\n */\n callAgentFunction = (agent: Agent) => {\n // Attempt to get the invoker for the callback function.\n const callbackFuncInvoker = Lookup.getFuncInvoker(agent, this.getFunctionName());\n\n // The callback function should be defined.\n if (callbackFuncInvoker === null) {\n throw new Error(\n `cannot call step function '${this.getFunctionName()}' as is not defined on the agent and has not been registered`\n );\n }\n\n // Call the callback function.\n callbackFuncInvoker(this.args);\n };\n}\n", "import Callback from \"./Callback\";\nimport Lookup from \"../../Lookup\";\nimport { Agent } from \"../../Agent\";\n\n/**\n * An EXIT callback which defines an agent function to call when the associated node is updated and moves to a finished state or is aborted.\n */\nexport default class Exit extends Callback {\n /**\n * @param functionName The name of the agent function to call.\n * @param args The array of callback argument definitions.\n */\n constructor(functionName: string, args: any[]) {\n super(\"exit\", args, functionName);\n }\n\n /**\n * Attempt to call the agent function that this callback refers to.\n * @param agent The agent.\n * @param isSuccess Whether the decorated node was left with a success state.\n * @param isAborted Whether the decorated node was aborted.\n */\n callAgentFunction = (agent: Agent, isSuccess: boolean, isAborted: boolean) => {\n // Attempt to get the invoker for the callback function.\n const callbackFuncInvoker = Lookup.getFuncInvoker(agent, this.getFunctionName());\n\n // The callback function should be defined.\n if (callbackFuncInvoker === null) {\n throw new Error(\n `cannot call exit function '${this.getFunctionName()}' as is not defined on the agent and has not been registered`\n );\n }\n\n // Call the callback function\n callbackFuncInvoker([{ value: { succeeded: isSuccess, aborted: isAborted } }, ...this.args]);\n };\n}\n", "import { AnyNodeDefinition, RootNodeDefinition } from \"./BehaviourTreeDefinition\";\nimport GuardPath, { GuardPathPart } from \"./attributes/guards/GuardPath\";\nimport { validateBranchSubtreeLinks } from \"./BehaviourTreeDefinitionValidator\";\nimport Node from \"./nodes/Node\";\nimport Composite from \"./nodes/composite/Composite\";\nimport Decorator from \"./nodes/decorator/Decorator\";\nimport Parallel from \"./nodes/composite/Parallel\";\nimport Selector from \"./nodes/composite/Selector\";\nimport Sequence from \"./nodes/composite/Sequence\";\nimport Lotto from \"./nodes/composite/Lotto\";\nimport Fail from \"./nodes/decorator/Fail\";\nimport Flip from \"./nodes/decorator/Flip\";\nimport Repeat from \"./nodes/decorator/Repeat\";\nimport Retry from \"./nodes/decorator/Retry\";\nimport Root from \"./nodes/decorator/Root\";\nimport Succeed from \"./nodes/decorator/Succeed\";\nimport Action from \"./nodes/leaf/Action\";\nimport Condition from \"./nodes/leaf/Condition\";\nimport Wait from \"./nodes/leaf/Wait\";\nimport Lookup from \"./Lookup\";\nimport Attribute from \"./attributes/Attribute\";\nimport While from \"./attributes/guards/While\";\nimport Until from \"./attributes/guards/Until\";\nimport Entry from \"./attributes/callbacks/Entry\";\nimport Step from \"./attributes/callbacks/Step\";\nimport Exit from \"./attributes/callbacks/Exit\";\n\n/**\n * A type representing any node instance in a behaviour tree.\n */\ntype AnyNode =\n | Root\n | Action\n | Condition\n | Wait\n | Sequence\n | Selector\n | Lotto\n | Parallel\n | Repeat\n | Retry\n | Flip\n | Succeed\n | Fail;\n\n/**\n * A type defining a mapping of root node identifiers to root node definitions.\n */\ntype RootNodeDefinitionMap = { [key: string | symbol]: RootNodeDefinition };\n\n/**\n * A symbol to use as the main root key in any root node mappings.\n */\nconst MAIN_ROOT_NODE_KEY = Symbol(\"__root__\");\n\n/**\n * Build and populate the root nodes based on the provided definition, assuming that the definition has been validated.\n * @param definition The root node definitions.\n * @returns The built and populated root node definitions.\n */\nexport default function buildRootNode(definition: RootNodeDefinition[]): Root {\n // Create a mapping of root node identifers to root node definitions, including globally registered subtree root node definitions.\n const rootNodeDefinitionMap = createRootNodeDefinitionMap(definition);\n\n // Now that we have all of our root node definitons (those part of the tree definition and those globally\n // registered) we should validate the definition. This will also double-check that we dont have any circular\n // dependencies in our branch -> subtree references and that we have no broken branch -> subtree links.\n validateBranchSubtreeLinks(definition, true);\n\n // Create our populated tree of node instances, starting with our main root node.\n const rootNode = nodeFactory(rootNodeDefinitionMap[MAIN_ROOT_NODE_KEY]) as Root;\n\n // Set a guard path on every leaf of the tree to evaluate as part of its update.\n applyLeafNodeGuardPaths(rootNode);\n\n // We only need to return the main root node.\n return rootNode;\n}\n\n/**\n * A factory function which creates a node instance based on the specified definition.\n * @param definition The node definition.\n * @returns A node instance based on the specified definition.\n */\nfunction nodeFactory(definition: AnyNodeDefinition): AnyNode {\n // Get the attributes for the node.\n const attributes = nodeAttributesFactory(definition);\n\n // Create the node instance based on the definition type.\n switch (definition.type) {\n case \"root\":\n return new Root(attributes, nodeFactory(definition.child));\n\n // ...\n\n default:\n throw new Error(`unexpected node type of '${definition.type}'`);\n }\n}\n\n/**\n * Creates an array of node attribute instances based on the specified node definition.\n * @param definition The node definition.\n * @returns An array of node attribute instances based on the specified node definition.\n */\nfunction nodeAttributesFactory(definition: AnyNodeDefinition): Attribute[] {\n const attributes: Attribute[] = [];\n\n if (definition.while) {\n attributes.push(new While(definition.while.call, definition.while.args ?? []));\n }\n\n if (definition.until) {\n attributes.push(new Until(definition.until.call, definition.until.args ?? []));\n }\n\n if (definition.entry) {\n attributes.push(new Entry(definition.entry.call, definition.entry.args ?? []));\n }\n\n if (definition.step) {\n attributes.push(new Step(definition.step.call, definition.step.args ?? []));\n }\n\n if (definition.exit) {\n attributes.push(new Exit(definition.exit.call, definition.exit.args ?? []));\n }\n\n return attributes;\n}\n\n/**\n * Creates a mapping of root node identifers to root node definitions, mixing in globally registered subtree root node definitions.\n * @param definition The root node definitions.\n * @returns A mapping of root node identifers to root node definitions, including globally registered subtree root node definitions.\n */\nfunction createRootNodeDefinitionMap(definition: RootNodeDefinition[]): RootNodeDefinitionMap {\n // Create a mapping of root node identifers to root node definitions.\n const rootNodeMap: RootNodeDefinitionMap = {};\n\n // Add in any registered subtree root node definitions.\n for (const [name, rootNodeDefinition] of Object.entries(Lookup.getSubtrees())) {\n // The name used when registering the subtree will be used as the root node identifier.\n rootNodeMap[name] = { ...rootNodeDefinition, id: name };\n }\n\n // Populate the map with the root node definitions that were included with the tree definition.\n // We do this after adding any registered subtrees as we want these to take presedence.\n for (const rootNodeDefinition of definition) {\n rootNodeMap[rootNodeDefinition.id ?? MAIN_ROOT_NODE_KEY] = rootNodeDefinition;\n }\n\n return rootNodeMap;\n}\n\n/**\n * Applies a guard path to every leaf of the tree to evaluate as part of each update.\n * @param root The main root tree node.\n */\nfunction applyLeafNodeGuardPaths(root: Root) {\n const nodePaths: Node[][] = [];\n\n const findLeafNodes = (path: Node[], node: Node) => {\n // Add the current node to the path.\n path = path.concat(node);\n\n // Check whether the current node is a leaf node.\n if (node.isLeafNode()) {\n nodePaths.push(path);\n } else {\n (node as Composite | Decorator).getChildren().forEach((child) => findLeafNodes(path, child));\n }\n };\n\n // Find all leaf node paths, starting from the root.\n findLeafNodes([], root);\n\n nodePaths.forEach((path) => {\n // Each node in the current path will have to be assigned a guard path, working from the root outwards.\n for (let depth = 0; depth < path.length; depth++) {\n // Get the node in the path at the current depth.\n const currentNode = path[depth];\n\n // The node may already have been assigned a guard path, if so just skip it.\n if (currentNode.hasGuardPath()) {\n continue;\n }\n\n // Create the guard path for the current node.\n const guardPath = new GuardPath(\n path\n .slice(0, depth + 1)\n .map((node) => ({ node, guards: node.getGuardAttributes() }))\n .filter((details) => details.guards.length > 0)\n );\n\n // Assign the guard path to the current node.\n currentNode.setGuardPath(guardPath);\n }\n });\n}\n", "import State, { AnyState } from \"./State\";\nimport Lookup from \"./Lookup\";\nimport Node from \"./nodes/Node\";\nimport Root from \"./nodes/decorator/Root\";\nimport Composite from \"./nodes/composite/Composite\";\nimport Decorator from \"./nodes/decorator/Decorator\";\nimport { Agent, GlobalFunction } from \"./Agent\";\nimport { CallbackAttributeDetails } from \"./attributes/callbacks/Callback\";\nimport { GuardAttributeDetails } from \"./attributes/guards/Guard\";\nimport { BehaviourTreeOptions } from \"./BehaviourTreeOptions\";\nimport { convertMDSLToJSON } from \"./mdsl/MDSLDefinitionParser\";\nimport { RootNodeDefinition } from \"./BehaviourTreeDefinition\";\nimport { validateJSONDefinition } from \"./BehaviourTreeDefinitionValidator\";\nimport buildRootNode from \"./BehaviourTreeBuilder\";\n\n// Purely for outside inspection of the tree.\nexport type FlattenedTreeNode = {\n id: string;\n type: string;\n caption: string;\n state: AnyState;\n guards: GuardAttributeDetails[];\n callbacks: CallbackAttributeDetails[];\n args: any[];\n parentId: string | null;\n};\n\n/**\n * A representation of a behaviour tree.\n */\nexport class BehaviourTree {\n /**\n * The main root tree node.\n */\n public readonly rootNode: Root;\n\n /**\n * Creates a new instance of the BehaviourTree class.\n * @param definition The behaviour tree definition.\n * @param agent The agent instance that this behaviour tree is modelling behaviour for.\n * @param options The behaviour tree options object.\n */\n constructor(\n definition: string | RootNodeDefinition | RootNodeDefinition[],\n private agent: Agent,\n private options: BehaviourTreeOptions = {}\n ) {\n // The tree definition must be defined.\n if (!definition) {\n throw new Error(\"the tree definition must be a string ro\");\n }\n\n // The agent must be defined and not null.\n if (typeof agent !== \"object\" || agent === null) {\n throw new Error(\"the agent must be defined and not null\");\n }\n\n try {\n // Parse the behaviour tree definition, create the populated tree of behaviour tree nodes, and get the root.\n this.rootNode = this._createRootNode(definition);\n } catch (exception) {\n // There was an issue in trying build and populate the behaviour tree.\n throw new Error(`error building tree: ${(exception as Error).message}`);\n }\n }\n\n /**\n * Gets whether the tree is in the RUNNING state.\n * @returns true if the tree is in the RUNNING state, otherwise false.\n */\n isRunning() {\n return this.rootNode.getState() === State.RUNNING;\n }\n\n /**\n * Gets the current tree state of SUCCEEDED, FAILED, READY or RUNNING.\n * @returns The current tree state.\n */\n getState() {\n return this.rootNode.getState();\n }\n\n /**\n * Step the tree.\n * 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.\n * 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\n * 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.\n *\n * 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.\n */\n step() {\n // If the root node has already been stepped to completion then we need to reset it.\n if (this.rootNode.getState() === State.SUCCEEDED || this.rootNode.getState() === State.FAILED) {\n this.rootNode.reset();\n }\n\n try {\n this.rootNode.update(this.agent, this.options);\n } catch (exception) {\n throw new Error(`error stepping tree: ${(exception as Error).message}`);\n }\n }\n\n /**\n * Resets the tree from the root node outwards to each nested node, giving each a state of READY.\n */\n reset() {\n this.rootNode.reset();\n }\n\n /**\n * Gets the flattened details of every node in the tree.\n * @returns The flattened details of every node in the tree.\n */\n getFlattenedNodeDetails(): FlattenedTreeNode[] {\n // Create an empty flattened array of tree nodes.\n const flattenedTreeNodes: FlattenedTreeNode[] = [];\n\n /**\n * Helper function to process a node instance and push details into the flattened tree nodes array.\n * @param node The current node.\n * @param parentUid The UID of the node parent, or null if the node is the main root node.\n */\n const processNode = (node: Node, parentUid: string | null) => {\n // Get the guard and callback attribute details for this node.\n const guards = node\n .getAttributes()\n .filter((attribute) => attribute.isGuard())\n .map((attribute) => attribute.getDetails()) as GuardAttributeDetails[];\n const callbacks = node\n .getAttributes()\n .filter((attribute) => !attribute.isGuard())\n .map((attribute) => attribute.getDetails()) as CallbackAttributeDetails[];\n\n // Push the current node into the flattened nodes array.\n flattenedTreeNodes.push({\n id: node.getUid(),\n type: node.getType(),\n caption: node.getName(),\n state: node.getState(),\n guards,\n callbacks,\n args: node.getArguments(),\n parentId: parentUid\n });\n\n // Process each of the nodes children if it is not a leaf node.\n if (!node.isLeafNode()) {\n (node as Composite | Decorator)\n .getChildren()\n .forEach((child) => processNode(child, (node as Composite | Decorator).getUid()));\n }\n };\n\n // Convert the nested node structure into a flattened array of node details.\n processNode(this.rootNode, null);\n\n return flattenedTreeNodes;\n }\n\n /**\n * Registers the action/condition/guard/callback function or subtree with the given name.\n * @param name The name of the function or subtree to register.\n * @param value The function or subtree definition to register.\n */\n static register(name: string, value: GlobalFunction | string | RootNodeDefinition) {\n // Are we going to register a action/condition/guard/callback function?\n if (typeof value === \"function\") {\n Lookup.setFunc(name, value);\n return;\n }\n\n // We are not registering an action/condition/guard/callback function, so we must be registering a subtree.\n if (typeof value === \"string\") {\n let rootNodeDefinitions: RootNodeDefinition[];\n\n // We will assume that any string passed in will be a mdsl definition.\n try {\n rootNodeDefinitions = convertMDSLToJSON(value);\n } catch (exception) {\n throw new Error(`error registering definition, invalid MDSL: ${(exception as Error).message}`);\n }\n\n // This function should only ever be called with a definition containing a single unnamed root node.\n if (rootNodeDefinitions.length != 1 || rootNodeDefinitions[0].id !== null) {\n throw new Error(\"error registering definition: expected a single unnamed root node\");\n }\n\n try {\n // We should validate the subtree as we don't want invalid subtrees available via the lookup.\n const { succeeded, errorMessage } = validateJSONDefinition(rootNodeDefinitions[0]);\n\n // Did our validation fail without error?\n if (!succeeded) {\n throw new Error(errorMessage);\n }\n } catch (exception) {\n throw new Error(`error registering definition: ${(exception as Error).message}`);\n }\n\n // Everything seems hunky-dory, register the subtree.\n Lookup.setSubtree(name, rootNodeDefinitions[0]);\n } else if (typeof value === \"object\" && !Array.isArray(value)) {\n // We will assume that any object passed in is a root node definition.\n\n try {\n // We should validate the subtree as we don't want invalid subtrees available via the lookup.\n const { succeeded, errorMessage } = validateJSONDefinition(value);\n\n // Did our validation fail without error?\n if (!succeeded) {\n throw new Error(errorMessage);\n }\n } catch (exception) {\n throw new Error(`error registering definition: ${(exception as Error).message}`);\n }\n\n // Everything seems hunky-dory, register the subtree.\n Lookup.setSubtree(name, value);\n } else {\n throw new Error(\"unexpected value, expected string mdsl definition, root node json definition or function\");\n }\n }\n\n /**\n * Unregisters the registered action/condition/guard/callback function or subtree with the given name.\n * @param name The name of the registered action/condition/guard/callback function or subtree to unregister.\n */\n static unregister(name: string): void {\n Lookup.remove(name);\n }\n\n /**\n * Unregister all registered action/condition/guard/callback functions and subtrees.\n */\n static unregisterAll(): void {\n Lookup.empty();\n }\n\n /**\n * Parses a behaviour tree definition and creates a tree of behaviour tree nodes populated at a root.\n * @param {string | RootNodeDefinition | RootNodeDefinition[]} definition The behaviour tree definition.\n * @returns The root behaviour tree node.\n */\n private _createRootNode(definition: string | RootNodeDefinition | RootNodeDefinition[]): Root {\n let resolvedDefinition: RootNodeDefinition | RootNodeDefinition[];\n\n // If the definition is a string then we will assume that it is an mdsl string which needs to be converted to a JSON definition.\n if (typeof definition === \"string\") {\n try {\n resolvedDefinition = convertMDSLToJSON(definition);\n } catch (exception) {\n throw new Error(`invalid mdsl definition: ${(exception as Error).message}`);\n }\n } else {\n // The definition is not a string, so we should assume that it is already a JSON definition.\n resolvedDefinition = definition;\n }\n\n // Build and populate the root node.\n return buildRootNode(Array.isArray(resolvedDefinition) ? resolvedDefinition : [resolvedDefinition]);\n }\n}\n"], + "mappings": "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", + "names": ["State"] } diff --git a/dist/mdsl/MDSLNodeArgumentParser.d.ts b/dist/mdsl/MDSLNodeArgumentParser.d.ts index 23d1a89..affc2e5 100644 --- a/dist/mdsl/MDSLNodeArgumentParser.d.ts +++ b/dist/mdsl/MDSLNodeArgumentParser.d.ts @@ -1,27 +1,40 @@ import { StringLiteralPlaceholders } from "./MDSLUtilities"; -export type Argument = { - /** The argument value. */ +/** + * A type representing any node function argument. + */ +type Argument = { + /** + * The argument value. + */ value: T; - /** The argument type, used for validation. */ + /** + * The argument type, used for validation. + */ type: string; }; -export type NullArgument = Argument & { +type NullArgument = Argument & { type: "null"; }; -export type BooleanArgument = Argument & { +type BooleanArgument = Argument & { type: "boolean"; }; -export type NumberArgument = Argument & { +type NumberArgument = Argument & { type: "number"; + /** + * A flag defining whether the number argument value is a valid integer. (used for validation) + */ isInteger: boolean; }; -export type StringPlaceholderArgument = Argument & { +type StringPlaceholderArgument = Argument & { type: "string"; }; -export type IdentifierArgument = Argument & { +type IdentifierArgument = Argument & { type: "identifier"; }; -export type AnyArgument = NullArgument | BooleanArgument | NumberArgument | StringPlaceholderArgument | IdentifierArgument; +/** + * A type representing a reference to any node function argument. + */ +type AnyArgument = NullArgument | BooleanArgument | NumberArgument | StringPlaceholderArgument | IdentifierArgument; /** * Parse an array of argument definitions from the specified tokens array. * @param tokens The array tokens to parse the argument definitions from. @@ -31,3 +44,4 @@ export type AnyArgument = NullArgument | BooleanArgument | NumberArgument | Stri * @returns An array of argument definitions parsed from the specified tokens array. */ export declare function parseArgumentTokens(tokens: string[], stringArgumentPlaceholders: StringLiteralPlaceholders): AnyArgument[]; +export {}; diff --git a/dist/nodes/Node.d.ts b/dist/nodes/Node.d.ts index 864bffc..765b572 100644 --- a/dist/nodes/Node.d.ts +++ b/dist/nodes/Node.d.ts @@ -1,14 +1,13 @@ +import { BehaviourTreeOptions } from "../BehaviourTreeOptions"; +import { AnyState } from "../State"; import { Agent } from "../Agent"; +import Leaf from "./leaf/Leaf"; import Attribute from "../attributes/Attribute"; import Entry from "../attributes/callbacks/Entry"; import Exit from "../attributes/callbacks/Exit"; import Step from "../attributes/callbacks/Step"; import Guard from "../attributes/guards/Guard"; import GuardPath from "../attributes/guards/GuardPath"; -import { BehaviourTreeOptions } from "../BehaviourTreeOptions"; -import { AnyArgument } from "../RootAstNodesBuilder"; -import { AnyState } from "../State"; -import Leaf from "./leaf/Leaf"; /** * A base node. */ @@ -33,7 +32,7 @@ export default abstract class Node { * @param attributes The node attributes. * @param args The node argument definitions. */ - constructor(type: string, attributes: Attribute[], args: AnyArgument[]); + constructor(type: string, attributes: Attribute[], args: any[]); /** * Called when the node is being updated. * @param agent The agent. @@ -68,7 +67,7 @@ export default abstract class Node { /** * Gets the node arguments. */ - getArguments: () => AnyArgument[]; + getArguments: () => any[]; /** * Gets the node attribute with the specified type, or null if it does not exist. */ diff --git a/dist/nodes/leaf/Action.d.ts b/dist/nodes/leaf/Action.d.ts index 3b889be..0ce5e29 100644 --- a/dist/nodes/leaf/Action.d.ts +++ b/dist/nodes/leaf/Action.d.ts @@ -1,8 +1,7 @@ -import Leaf from "./Leaf"; +import { BehaviourTreeOptions } from "../../BehaviourTreeOptions"; import { Agent } from "../../Agent"; +import Leaf from "./Leaf"; import Attribute from "../../attributes/Attribute"; -import { AnyArgument } from "../../RootAstNodesBuilder"; -import { BehaviourTreeOptions } from "../../BehaviourTreeOptions"; /** * An Action leaf node. * This represents an immediate or ongoing state of behaviour. @@ -15,7 +14,7 @@ export default class Action extends Leaf { * @param actionName The action name. * @param actionArguments The array of action argument definitions. */ - constructor(attributes: Attribute[], actionName: string, actionArguments: AnyArgument[]); + constructor(attributes: Attribute[], actionName: string, actionArguments: any[]); /** * Whether there is a pending update promise. */ diff --git a/dist/nodes/leaf/Condition.d.ts b/dist/nodes/leaf/Condition.d.ts index e2f08bd..edf7d56 100644 --- a/dist/nodes/leaf/Condition.d.ts +++ b/dist/nodes/leaf/Condition.d.ts @@ -1,8 +1,7 @@ -import Leaf from "./Leaf"; +import { BehaviourTreeOptions } from "../../BehaviourTreeOptions"; import { Agent } from "../../Agent"; +import Leaf from "./Leaf"; import Attribute from "../../attributes/Attribute"; -import { AnyArgument } from "../../RootAstNodesBuilder"; -import { BehaviourTreeOptions } from "../../BehaviourTreeOptions"; /** * A Condition leaf node. * This will succeed or fail immediately based on an agent predicate, without moving to the 'RUNNING' state. @@ -15,7 +14,7 @@ export default class Condition extends Leaf { * @param conditionName The name of the condition function. * @param conditionArguments The array of condition argument definitions. */ - constructor(attributes: Attribute[], conditionName: string, conditionArguments: AnyArgument[]); + constructor(attributes: Attribute[], conditionName: string, conditionArguments: any[]); /** * Called when the node is being updated. * @param agent The agent. diff --git a/src/Agent.ts b/src/Agent.ts index 8fbdc92..60d0767 100644 --- a/src/Agent.ts +++ b/src/Agent.ts @@ -1,5 +1,8 @@ import { CompleteState } from "./State"; +/** + * A type representing an agent that a behavior tree instance would operate on. + */ export type Agent = { [actionName: string]: AgentFunction; }; diff --git a/src/BehaviourTree.ts b/src/BehaviourTree.ts index 941d605..608e974 100644 --- a/src/BehaviourTree.ts +++ b/src/BehaviourTree.ts @@ -4,7 +4,6 @@ import Node from "./nodes/Node"; import Root from "./nodes/decorator/Root"; import Composite from "./nodes/composite/Composite"; import Decorator from "./nodes/decorator/Decorator"; -import { AnyArgument } from "./RootAstNodesBuilder"; import { Agent, GlobalFunction } from "./Agent"; import { CallbackAttributeDetails } from "./attributes/callbacks/Callback"; import { GuardAttributeDetails } from "./attributes/guards/Guard"; @@ -22,7 +21,7 @@ export type FlattenedTreeNode = { state: AnyState; guards: GuardAttributeDetails[]; callbacks: CallbackAttributeDetails[]; - args: AnyArgument[]; + args: any[]; parentId: string | null; }; @@ -41,7 +40,11 @@ export class BehaviourTree { * @param agent The agent instance that this behaviour tree is modelling behaviour for. * @param options The behaviour tree options object. */ - constructor(definition: string | RootNodeDefinition | RootNodeDefinition[], private agent: Agent, private options: BehaviourTreeOptions = {}) { + constructor( + definition: string | RootNodeDefinition | RootNodeDefinition[], + private agent: Agent, + private options: BehaviourTreeOptions = {} + ) { // The tree definition must be defined. if (!definition) { throw new Error("the tree definition must be a string ro"); @@ -166,8 +169,8 @@ export class BehaviourTree { Lookup.setFunc(name, value); return; } - - // We are not registering an action/condition/guard/callback function, so we must be registering a subtree. + + // We are not registering an action/condition/guard/callback function, so we must be registering a subtree. if (typeof value === "string") { let rootNodeDefinitions: RootNodeDefinition[]; @@ -183,8 +186,8 @@ export class BehaviourTree { throw new Error("error registering definition: expected a single unnamed root node"); } - // We should validate the subtree as we don't want invalid subtrees available via the lookup. try { + // We should validate the subtree as we don't want invalid subtrees available via the lookup. const { succeeded, errorMessage } = validateJSONDefinition(rootNodeDefinitions[0]); // Did our validation fail without error? @@ -199,8 +202,9 @@ export class BehaviourTree { Lookup.setSubtree(name, rootNodeDefinitions[0]); } else if (typeof value === "object" && !Array.isArray(value)) { // We will assume that any object passed in is a root node definition. - // We should validate the subtree as we don't want invalid subtrees available via the lookup. + try { + // We should validate the subtree as we don't want invalid subtrees available via the lookup. const { succeeded, errorMessage } = validateJSONDefinition(value); // Did our validation fail without error? @@ -239,7 +243,7 @@ export class BehaviourTree { * @returns The root behaviour tree node. */ private _createRootNode(definition: string | RootNodeDefinition | RootNodeDefinition[]): Root { - let resolvedDefinition: RootNodeDefinition | RootNodeDefinition[] + let resolvedDefinition: RootNodeDefinition | RootNodeDefinition[]; // If the definition is a string then we will assume that it is an mdsl string which needs to be converted to a JSON definition. if (typeof definition === "string") { diff --git a/src/BehaviourTreeBuilder.ts b/src/BehaviourTreeBuilder.ts index 6e5ff2c..0329023 100644 --- a/src/BehaviourTreeBuilder.ts +++ b/src/BehaviourTreeBuilder.ts @@ -1,6 +1,9 @@ - import { AnyNodeDefinition, RootNodeDefinition } from "./BehaviourTreeDefinition"; -import { validateJSONDefinition } from "./BehaviourTreeDefinitionValidator"; +import GuardPath, { GuardPathPart } from "./attributes/guards/GuardPath"; +import { validateBranchSubtreeLinks } from "./BehaviourTreeDefinitionValidator"; +import Node from "./nodes/Node"; +import Composite from "./nodes/composite/Composite"; +import Decorator from "./nodes/decorator/Decorator"; import Parallel from "./nodes/composite/Parallel"; import Selector from "./nodes/composite/Selector"; import Sequence from "./nodes/composite/Sequence"; @@ -17,11 +20,28 @@ import Wait from "./nodes/leaf/Wait"; import Lookup from "./Lookup"; import Attribute from "./attributes/Attribute"; import While from "./attributes/guards/While"; +import Until from "./attributes/guards/Until"; +import Entry from "./attributes/callbacks/Entry"; +import Step from "./attributes/callbacks/Step"; +import Exit from "./attributes/callbacks/Exit"; /** * A type representing any node instance in a behaviour tree. */ -type AnyNode = Root | Action | Condition | Wait | Sequence | Selector | Lotto | Parallel | Repeat | Retry | Flip | Succeed | Fail; +type AnyNode = + | Root + | Action + | Condition + | Wait + | Sequence + | Selector + | Lotto + | Parallel + | Repeat + | Retry + | Flip + | Succeed + | Fail; /** * A type defining a mapping of root node identifiers to root node definitions. @@ -42,23 +62,16 @@ export default function buildRootNode(definition: RootNodeDefinition[]): Root { // Create a mapping of root node identifers to root node definitions, including globally registered subtree root node definitions. const rootNodeDefinitionMap = createRootNodeDefinitionMap(definition); - // Now that we have all of our root node definitons (those part of the tree definition and those globally registered) we should validate - // the definition. This will also double-check that we dont have any circular depdendencies in our branch -> root node references. - try { - const { succeeded, errorMessage } = validateJSONDefinition(Object.values(rootNodeDefinitionMap)); - - // Did our validation fail without error? - if (!succeeded) { - throw new Error(errorMessage); - } - } catch (exception) { - throw new Error(`root node validation failed: '${(exception as Error).message}'`); - } + // Now that we have all of our root node definitons (those part of the tree definition and those globally + // registered) we should validate the definition. This will also double-check that we dont have any circular + // dependencies in our branch -> subtree references and that we have no broken branch -> subtree links. + validateBranchSubtreeLinks(definition, true); // Create our populated tree of node instances, starting with our main root node. const rootNode = nodeFactory(rootNodeDefinitionMap[MAIN_ROOT_NODE_KEY]) as Root; - // TODO Set a guard path on every leaf of the tree to evaluate as part of its update. (see BehaviourTree._applyLeafNodeGuardPaths) + // Set a guard path on every leaf of the tree to evaluate as part of its update. + applyLeafNodeGuardPaths(rootNode); // We only need to return the main root node. return rootNode; @@ -79,22 +92,41 @@ function nodeFactory(definition: AnyNodeDefinition): AnyNode { return new Root(attributes, nodeFactory(definition.child)); // ... - + default: - throw new Error(`unexpected node type of '${definition.type}'`); + throw new Error(`unexpected node type of '${definition.type}'`); } } +/** + * Creates an array of node attribute instances based on the specified node definition. + * @param definition The node definition. + * @returns An array of node attribute instances based on the specified node definition. + */ function nodeAttributesFactory(definition: AnyNodeDefinition): Attribute[] { - const attributes: Attribute[] = []; + const attributes: Attribute[] = []; + + if (definition.while) { + attributes.push(new While(definition.while.call, definition.while.args ?? [])); + } + + if (definition.until) { + attributes.push(new Until(definition.until.call, definition.until.args ?? [])); + } - if (definition.while) { - // TODO does this take args as any? We have AnyArgument type but is that just for mdsl parsing??? - // TODO Double check that validateJSONDefinition handles the args, surely they can be 'any' at this point? - attributes.push(new While(definition.while.call, definition.while.args)); - } + if (definition.entry) { + attributes.push(new Entry(definition.entry.call, definition.entry.args ?? [])); + } + + if (definition.step) { + attributes.push(new Step(definition.step.call, definition.step.args ?? [])); + } - return attributes; + if (definition.exit) { + attributes.push(new Exit(definition.exit.call, definition.exit.args ?? [])); + } + + return attributes; } /** @@ -108,7 +140,8 @@ function createRootNodeDefinitionMap(definition: RootNodeDefinition[]): RootNode // Add in any registered subtree root node definitions. for (const [name, rootNodeDefinition] of Object.entries(Lookup.getSubtrees())) { - rootNodeMap[name] = rootNodeDefinition; + // The name used when registering the subtree will be used as the root node identifier. + rootNodeMap[name] = { ...rootNodeDefinition, id: name }; } // Populate the map with the root node definitions that were included with the tree definition. @@ -118,4 +151,51 @@ function createRootNodeDefinitionMap(definition: RootNodeDefinition[]): RootNode } return rootNodeMap; -} \ No newline at end of file +} + +/** + * Applies a guard path to every leaf of the tree to evaluate as part of each update. + * @param root The main root tree node. + */ +function applyLeafNodeGuardPaths(root: Root) { + const nodePaths: Node[][] = []; + + const findLeafNodes = (path: Node[], node: Node) => { + // Add the current node to the path. + path = path.concat(node); + + // Check whether the current node is a leaf node. + if (node.isLeafNode()) { + nodePaths.push(path); + } else { + (node as Composite | Decorator).getChildren().forEach((child) => findLeafNodes(path, child)); + } + }; + + // Find all leaf node paths, starting from the root. + findLeafNodes([], root); + + nodePaths.forEach((path) => { + // Each node in the current path will have to be assigned a guard path, working from the root outwards. + for (let depth = 0; depth < path.length; depth++) { + // Get the node in the path at the current depth. + const currentNode = path[depth]; + + // The node may already have been assigned a guard path, if so just skip it. + if (currentNode.hasGuardPath()) { + continue; + } + + // Create the guard path for the current node. + const guardPath = new GuardPath( + path + .slice(0, depth + 1) + .map((node) => ({ node, guards: node.getGuardAttributes() })) + .filter((details) => details.guards.length > 0) + ); + + // Assign the guard path to the current node. + currentNode.setGuardPath(guardPath); + } + }); +} diff --git a/src/BehaviourTreeDefinitionValidator.ts b/src/BehaviourTreeDefinitionValidator.ts index 4957eb2..7006acb 100644 --- a/src/BehaviourTreeDefinitionValidator.ts +++ b/src/BehaviourTreeDefinitionValidator.ts @@ -17,7 +17,7 @@ export type DefinitionValidationResult = { }; /** - * Validates the specified behaviour tree definition in the form of JSON or MDSL. + * Validates the specified behaviour tree definition in the form of JSON or MDSL, not taking any globally registered subtrees into consideration. * @param definition The behaviour tree definition in the form of JSON or MDSL. * @returns An object representing the result of validating the given tree definition. */ @@ -56,7 +56,7 @@ export function validateMDSLDefinition(definition: string): DefinitionValidation rootNodeDefinitions = convertMDSLToJSON(definition); } catch (error) { // We failed to parse the JSON from the MDSL, this is likely to be the result of it not being a valid MDSL string. - return createValidationFailureResult(`invalid MDSL: ${definition}`); + return createValidationFailureResult(`invalid MDSL: ${error}`); } // Unpack all of the root node definitions into arrays of main ('id' defined) and sub ('id' not defined) root node definitions. @@ -81,14 +81,11 @@ export function validateMDSLDefinition(definition: string): DefinitionValidation subRootNodeIdenitifers.push(id!); } - // Check for any branch node circular depedencies. This will NOT include any globally registered subtrees. - const circularDependencyPath = findBranchCircularDependencyPath(rootNodeDefinitions); - - // If we found a circular dependency in our root node and branch node definitions then the definition is definitely not valid. - if (circularDependencyPath) { - return createValidationFailureResult( - `circular dependency found in branch node references: ${circularDependencyPath}` - ); + try { + // Validate our branch -> subtree links and check for any circular dependencies, we don't care about checking for broken subtree links here. + validateBranchSubtreeLinks(rootNodeDefinitions, false); + } catch (exception) { + return createValidationFailureResult((exception as Error).message); } // Our definition was valid! @@ -143,14 +140,11 @@ export function validateJSONDefinition( subRootNodeIdenitifers.push(id!); } - // Check for any branch node circular depedencies. This will NOT include any globally registered subtrees. - const circularDependencyPath = findBranchCircularDependencyPath(rootNodeDefinitions); - - // If we found a circular dependency in our root node and branch node definitions then the definition is definitely not valid. - if (circularDependencyPath) { - return createValidationFailureResult( - `circular dependency found in branch node references: ${circularDependencyPath}` - ); + try { + // Validate our branch -> subtree links and check for any circular dependencies, we don't care about checking for broken subtree links here. + validateBranchSubtreeLinks(rootNodeDefinitions, false); + } catch (exception) { + return createValidationFailureResult((exception as Error).message); } // Our definition was valid! @@ -158,12 +152,13 @@ export function validateJSONDefinition( } /** - * Find the first circular depdendency path present in the array of root node definitions, or null if one doesn't exist. - * This will not consider branch nodes that reference any globally registered subtrees. + * Validates the branch -> subtree links across all provided root node definitions. + * This will not consider branch nodes that reference any globally registered subtrees unless includesGlobalSubtrees + * is set to true, in which case we will also verify that there are no broken branch -> subtree links. * @param rootNodeDefinitions The array of root node definitions. - * @returns The first circular depdendency path present in the array of root node definitions as string, or null if one doesn't exist. + * @param includesGlobalSubtrees A flag defining whether the array includes all global subtree root node definitions. */ -export function findBranchCircularDependencyPath(rootNodeDefinitions: RootNodeDefinition[]): string | null { +export function validateBranchSubtreeLinks(rootNodeDefinitions: RootNodeDefinition[], includesGlobalSubtrees: boolean) { // Create a mapping of root node identifiers to other root nodes that they reference via branch nodes. // Below is an example of a mapping that includes a circular dependency (root => a => b => c => a) // [{ refs: ["a", "b"] }, { id: "a", refs: ["b"] }, { id: "b", refs: ["c"] }, { id: "c", refs: ["a"] }] @@ -176,8 +171,6 @@ export function findBranchCircularDependencyPath(rootNodeDefinitions: RootNodeDe }) ); - let badPathFormatted: string | null = null; - // A recursive function to walk through the mappings, keeping track of which root nodes we have visited in the form of a path of root node identifiers. const followRefs = (mapping: { id: string | undefined; refs: string[] }, path: (string | undefined)[] = []) => { // Have we found a circular dependency? @@ -185,28 +178,33 @@ export function findBranchCircularDependencyPath(rootNodeDefinitions: RootNodeDe // We found a circular dependency! Get the bad path of root node identifiers. const badPath = [...path, mapping.id]; - // Set the formatted path value. [undefined, "a", "b", "c", "a"] would be formatted as "a -> b -> c -> a". - badPathFormatted = badPath.filter((element) => !!element).join(" => "); + // Create the formatted path value. [undefined, "a", "b", "c", "a"] would be formatted as "a -> b -> c -> a". + const badPathFormatted = badPath.filter((element) => !!element).join(" => "); // No need to continue, we found a circular dependency. - return; + throw new Error(`circular dependency found in branch node references: ${badPathFormatted}`); } for (const ref of mapping.refs) { // Find the mapping for the root node with an identifer matching the current ref. const subMapping = rootNodeMappings.find(({ id }) => id === ref); - // We may not have a mapping for this ref, which will happen if this ref is for a globally registered subtree. + // We may not have a mapping for this ref, which is normal when we aren't considering all globally registered subtrees. if (subMapping) { followRefs(subMapping, [...path, mapping.id]); + } else if (includesGlobalSubtrees) { + // We found a reference to a root node that doesn't exist, which is a problem seeing as the root node definitons includes all globally registered subtrees. + throw new Error( + mapping.id + ? `subtree '${mapping.id}' has branch node that references root node '${ref}' which has not been defined` + : `primary tree has branch node that references root node '${ref}' which has not been defined` + ); } } }; - // Start looking for circular dependencies from the root. + // Start looking for circular dependencies and broken references from the primary root node definition. followRefs(rootNodeMappings.find((mapping) => typeof mapping.id === "undefined")!); - - return badPathFormatted; } /** diff --git a/src/DSLtoJSON.js b/src/DSLtoJSON.js deleted file mode 100644 index 6ce0e75..0000000 --- a/src/DSLtoJSON.js +++ /dev/null @@ -1,268 +0,0 @@ -//root { -// action [SomeAction] -//} - -let definition = { - type: "root", - children: [ - { - type: "action", - call: "SomeAction" - } - ] -} - - -//root { -// branch [SomeOtherTree] -//} -// -//root [SomeOtherTree] { -// action [Dance] -//} - -definition = [ - { - type: "root", - children: [ - { - type: "branch", - ref: "SomeOtherTree" - } - ] - }, - { - type: "root", - id: "SomeOtherTree", - children: [ - { - type: "action", - call: "SomeAction" - } - ] - } -] - -//root { -// action [Say, "hello world", 5, true] -//} - -definition = { - type: "root", - children: [ - { - type: "action", - call: "SomeAction", - args: ["hello world", 5, true] - } - ] -} - -//root { -// condition [SomeCondition] -//} - -definition = { - type: "root", - children: [ - { - type: "condition", - call: "SomeCondition" - } - ] -} - -//root { -// condition [HasItem, "gold", 500] -//} - -definition = { - type: "root", - children: [ - { - type: "condition", - call: "HasItem", - args: ["gold", 500] - } - ] -} - -//root { -// wait [2000] -//} - -definition = { - type: "root", - children: [ - { - type: "wait", - duration: 2000 - } - ] -} - -//root { -// wait [2000, 5000] -//} - -definition = { - type: "root", - children: [ - { - type: "wait", - duration: [2000, 5000] - } - ] -} - -//root { -// sequence { -// action [Walk] -// } -//} - -definition = { - type: "root", - children: [ - { - type: "sequence", - children: [ - { - type: "action", - call: "Walk" - } - ] - } - ] -} - -//root { -// selector { -// action [Walk] -// } -//} - -definition = { - type: "root", - children: [ - { - type: "selector", - children: [ - { - type: "action", - call: "Walk" - } - ] - } - ] -} - -//root { -// lotto { -// action [GoLeft] -// action [GoRight] -// } -//} - -definition = { - type: "root", - children: [ - { - type: "lotto", - children: [ - { - type: "action", - call: "GoLeft" - }, - { - type: "action", - call: "GoRight" - } - ] - } - ] -} - -//root { -// lotto [9, 1] { -// action [CommonAction] -// action [RareAction] -// } -//} - -definition = { - type: "root", - children: [ - { - type: "lotto", - weights: [9, 1], - children: [ - { - type: "action", - call: "CommonAction" - }, - { - type: "action", - call: "RareAction" - } - ] - } - ] -} - -//root { -// repeat { -// sequence { -// wait [1000] -// } -// } -//} - -definition = { - type: "root", - children: [ - { - type: "repeat", - child: { - type: "sequence", - children: [ - { - type: "wait", - duration: 1000 - } - ] - } - } - ] -} - -//root { -// selector { -// action [SomeAction] while(IsKeyDown, "Enter") -// } -//} - -//root { -// selector { -// action [Walk] -// } -//} - -definition = { - type: "root", - children: [ - { - type: "selector", - children: [ - { - type: "action", - call: "SomeAction", - while: { - call: "IsKeyDown", - args: ["Enter"] - } - } - ] - } - ] -} \ No newline at end of file diff --git a/src/Lookup.ts b/src/Lookup.ts index cd010b7..523274e 100644 --- a/src/Lookup.ts +++ b/src/Lookup.ts @@ -1,13 +1,7 @@ -import { ActionResult, Agent, ExitFunctionArg, GlobalFunction } from "./Agent"; +import { ActionResult, Agent, GlobalFunction } from "./Agent"; import { RootNodeDefinition } from "./BehaviourTreeDefinition"; -import { AnyArgument } from "./RootAstNodesBuilder"; -// Exit callbacks receive their own special type of argument. -// There's probably stricter ways to represent this but it feels overly complex right now. -type ExitResultArg = { value: ExitFunctionArg }; -export type AnyExitArgument = AnyArgument | ExitResultArg; - -export type InvokerFunction = (args: AnyExitArgument[]) => ActionResult; +export type InvokerFunction = (args: any[]) => ActionResult; /** * A singleton used to store and lookup registered functions and subtrees. @@ -52,16 +46,12 @@ export default class Lookup { // Check whether the agent contains the specified function. const foundOnAgent = agent[name]; if (foundOnAgent && typeof foundOnAgent === "function") { - return (args: AnyExitArgument[]): boolean | ActionResult => - foundOnAgent.apply( - agent, - args.map((arg) => arg.value) - ); + return (args: any[]): boolean | ActionResult => foundOnAgent.apply(agent, args); } // The agent does not contain the specified function but it may have been registered at some point. if (this.functionTable[name] && typeof this.functionTable[name] === "function") { - return (args: AnyExitArgument[]) => this.functionTable[name](agent, ...args.map((arg) => arg.value)); + return (args: any[]) => this.functionTable[name](agent, ...args.map((arg) => arg.value)); } // We have no function to invoke. diff --git a/src/RootAstNodesBuilder.ts b/src/RootAstNodesBuilder.ts deleted file mode 100644 index d8f875e..0000000 --- a/src/RootAstNodesBuilder.ts +++ /dev/null @@ -1,1219 +0,0 @@ -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 Flip from "./nodes/decorator/Flip"; -import Succeed from "./nodes/decorator/Succeed"; -import Fail from "./nodes/decorator/Fail"; -import Lotto from "./nodes/composite/Lotto"; -import Selector from "./nodes/composite/Selector"; -import Sequence from "./nodes/composite/Sequence"; -import Parallel from "./nodes/composite/Parallel"; -import Node from "./nodes/Node"; -import While from "./attributes/guards/While"; -import Until from "./attributes/guards/Until"; -import Entry from "./attributes/callbacks/Entry"; -import Exit from "./attributes/callbacks/Exit"; -import Step from "./attributes/callbacks/Step"; -import Callback from "./attributes/callbacks/Callback"; -import Guard from "./attributes/guards/Guard"; -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 = { - value: T; - type: string; // Used for validation. -}; -type NullArgument = Argument & { - type: "null"; -}; -type BooleanArgument = Argument & { - type: "boolean"; -}; -type NumberArgument = Argument & { - type: "number"; - isInteger: boolean; // Used for validation. -}; -type StringPlaceholderArgument = Argument & { - type: "string"; -}; -type IdentifierArgument = Argument & { - type: "identifier"; -}; -export type AnyArgument = - | NullArgument - | BooleanArgument - | NumberArgument - | StringPlaceholderArgument - | IdentifierArgument; - -/** - * The node attribute factories. - */ -const AttributeFactories: { - [key: string]: (functionName: string, attributeArguments: AnyArgument[]) => Callback | Guard; -} = { - WHILE: (condition: string, attributeArguments: AnyArgument[]) => new While(condition, attributeArguments), - UNTIL: (condition: string, attributeArguments: AnyArgument[]) => new Until(condition, attributeArguments), - ENTRY: (functionName: string, attributeArguments: AnyArgument[]) => new Entry(functionName, attributeArguments), - EXIT: (functionName: string, attributeArguments: AnyArgument[]) => new Exit(functionName, attributeArguments), - STEP: (functionName: string, attributeArguments: AnyArgument[]) => new Step(functionName, attributeArguments) -}; - -type Validatable = { - children?: AstNode[]; - validate: (depth: number) => void; -}; - -type NodeInstanceCreator = ( - namedRootNodeProvider: (name: string) => RootAstNode, - visitedBranches: string[] -) => T; - -export type AstNode = Validatable & { - type: string; - createNodeInstance: NodeInstanceCreator; -}; - -export type LeafAstNode = AstNode & { - type: "action" | "condition" | "wait"; - attributes: Attribute[]; -}; - -export type CompositeAstNode = AstNode & { - type: "lotto" | "parallel" | "selector" | "sequence"; - attributes: Attribute[]; - children: AstNode[]; -}; - -export type DecoratorAstNode = AstNode & { - type: "fail" | "flip" | "repeat" | "retry" | "root" | "succeed"; - attributes: Attribute[]; - children: AstNode[]; -}; - -export type BranchAstNode = AstNode & { - type: "branch"; - branchName: "" | string; -}; - -export type LottoAstNode = CompositeAstNode & { - type: "lotto"; - tickets: number[]; -}; - -export type RootAstNode = DecoratorAstNode & { - type: "root"; - name: null | string; -}; - -export type RepeatAstNode = DecoratorAstNode & { - type: "repeat"; - iterations: number | null; - iterationsMin: number | null; - iterationsMax: number | null; -}; - -export type RetryAstNode = DecoratorAstNode & { - type: "retry"; - attempts: number | null; - attemptsMin: number | null; - attemptsMax: number | null; -}; - -export type ActionAstNode = LeafAstNode & { - type: "action"; - actionName: string; - actionArguments: AnyArgument[]; -}; - -export type ConditionAstNode = LeafAstNode & { - type: "condition"; - conditionName: string; - conditionArguments: AnyArgument[]; -}; - -export type WaitAstNode = LeafAstNode & { - 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; - -/** - * The AST node factories. - */ -const ASTNodeFactories = { - ROOT: (): RootAstNode => ({ - type: "root", - attributes: [], - name: null, - children: [], - validate(depth: number) { - // A root node cannot be the child of another node. - if (depth > 1) { - throw new Error("a root node cannot be the child of another node"); - } - - // A root node must have a single child node. - if (this.children.length !== 1) { - throw new Error("a root node must have a single child"); - } - }, - createNodeInstance(namedRootNodeProvider, visitedBranches) { - return new Root( - this.attributes, - this.children![0].createNodeInstance(namedRootNodeProvider, visitedBranches.slice()) - ); - } - }), - BRANCH: (): BranchAstNode => ({ - type: "branch", - branchName: "", - validate() {}, - createNodeInstance(namedRootNodeProvider, visitedBranches) { - // Try to find the root node with a matching branch name. - const targetRootNode = namedRootNodeProvider(this.branchName); - - // If we have already visited this branch then we have a circular dependency. - if (visitedBranches.indexOf(this.branchName) !== -1) { - throw new Error(`circular dependency found in branch node references for branch '${this.branchName}'`); - } - - // If we have a target root node, then the node instance we want will be the first and only child of the referenced root node. - if (targetRootNode) { - return targetRootNode - .createNodeInstance(namedRootNodeProvider, visitedBranches.concat(this.branchName)) - .getChildren()[0]; - } else { - throw new Error(`branch references root node '${this.branchName}' which has not been defined`); - } - } - }), - SELECTOR: (): CompositeAstNode => ({ - type: "selector", - attributes: [], - children: [], - validate() { - // A selector node must have at least a single node. - if (this.children.length < 1) { - throw new Error("a selector node must have at least a single child"); - } - }, - createNodeInstance(namedRootNodeProvider, visitedBranches) { - return new Selector( - this.attributes, - this.children.map((child) => child.createNodeInstance(namedRootNodeProvider, visitedBranches.slice())) - ); - } - }), - SEQUENCE: (): CompositeAstNode => ({ - type: "sequence", - attributes: [], - children: [], - validate() { - // A sequence node must have at least a single node. - if (this.children.length < 1) { - throw new Error("a sequence node must have at least a single child"); - } - }, - createNodeInstance(namedRootNodeProvider, visitedBranches) { - return new Sequence( - this.attributes, - this.children.map((child) => child.createNodeInstance(namedRootNodeProvider, visitedBranches.slice())) - ); - } - }), - PARALLEL: (): CompositeAstNode => ({ - type: "parallel", - attributes: [], - children: [], - validate() { - // A parallel node must have at least a single node. - if (this.children.length < 1) { - throw new Error("a parallel node must have at least a single child"); - } - }, - createNodeInstance(namedRootNodeProvider, visitedBranches) { - return new Parallel( - this.attributes, - this.children.map((child) => child.createNodeInstance(namedRootNodeProvider, visitedBranches.slice())) - ); - } - }), - LOTTO: (): LottoAstNode => ({ - type: "lotto", - attributes: [], - children: [], - tickets: [], - validate() { - // A lotto node must have at least a single node. - if (this.children!.length < 1) { - throw new Error("a lotto node must have at least a single child"); - } - }, - createNodeInstance(namedRootNodeProvider, visitedBranches) { - return new Lotto( - this.attributes, - this.tickets!, - this.children!.map((child) => child.createNodeInstance(namedRootNodeProvider, visitedBranches.slice())) - ); - } - }), - REPEAT: (): RepeatAstNode => ({ - type: "repeat", - attributes: [], - iterations: null, - iterationsMin: null, - iterationsMax: null, - children: [], - validate() { - // A repeat node must have a single node. - if (this.children!.length !== 1) { - throw new Error("a repeat node must have a single child"); - } - - if (this.iterations !== null) { - // A repeat node must have a positive number of iterations if defined. - if (this.iterations < 0) { - throw new Error("a repeat node must have a positive number of iterations if defined"); - } - } else if (this.iterationsMin !== null && this.iterationsMax !== null) { - // A repeat node must have a positive min and max iteration count if they are defined. - if (this.iterationsMin < 0 || this.iterationsMax < 0) { - throw new Error( - "a repeat node must have a positive minimum and maximum iteration count if defined" - ); - } - - // A repeat node must not have an minimum iteration count that exceeds the maximum iteration count. - if (this.iterationsMin > this.iterationsMax) { - throw new Error( - "a repeat node must not have a minimum iteration count that exceeds the maximum iteration count" - ); - } - } else { - // If we have no explicit iteration count or a minimum and maximum iteration count set then we are dealing with a repeat node that iterates indefinitely. - } - }, - createNodeInstance(namedRootNodeProvider, visitedBranches) { - return new Repeat( - this.attributes, - this.iterations, - this.iterationsMin, - this.iterationsMax, - this.children![0].createNodeInstance(namedRootNodeProvider, visitedBranches.slice()) - ); - } - }), - RETRY: (): RetryAstNode => ({ - type: "retry", - attributes: [], - attempts: null, - attemptsMin: null, - attemptsMax: null, - children: [], - validate() { - // A retry node must have a single node. - if (this.children!.length !== 1) { - throw new Error("a retry node must have a single child"); - } - - if (this.attempts !== null) { - // A retry node must have a positive number of attempts if defined. - if (this.attempts < 0) { - throw new Error("a retry node must have a positive number of attempts if defined"); - } - } else if (this.attemptsMin !== null && this.attemptsMax !== null) { - // A retry node must have a positive min and max attempts count if they are defined. - if (this.attemptsMin < 0 || this.attemptsMax < 0) { - throw new Error("a retry node must have a positive minimum and maximum attempt count if defined"); - } - - // A retry node must not have a minimum attempt count that exceeds the maximum attempt count. - if (this.attemptsMin > this.attemptsMax) { - throw new Error( - "a retry node must not have a minimum attempt count that exceeds the maximum attempt count" - ); - } - } else { - // If we have no explicit attempt count or a minimum and maximum attempt count set then we are dealing with a retry node that attempts indefinitely. - } - }, - createNodeInstance(namedRootNodeProvider, visitedBranches) { - return new Retry( - this.attributes, - this.attempts, - this.attemptsMin, - this.attemptsMax, - this.children![0].createNodeInstance(namedRootNodeProvider, visitedBranches.slice()) - ); - } - }), - FLIP: (): DecoratorAstNode => ({ - type: "flip", - attributes: [], - children: [], - validate() { - // A flip node must have a single node. - if (this.children!.length !== 1) { - throw new Error("a flip node must have a single child"); - } - }, - createNodeInstance(namedRootNodeProvider, visitedBranches) { - return new Flip( - this.attributes, - this.children![0].createNodeInstance(namedRootNodeProvider, visitedBranches.slice()) - ); - } - }), - SUCCEED: (): DecoratorAstNode => ({ - type: "succeed", - attributes: [], - children: [], - validate() { - // A succeed node must have a single node. - if (this.children!.length !== 1) { - throw new Error("a succeed node must have a single child"); - } - }, - createNodeInstance(namedRootNodeProvider, visitedBranches) { - return new Succeed( - this.attributes, - this.children![0].createNodeInstance(namedRootNodeProvider, visitedBranches.slice()) - ); - } - }), - FAIL: (): DecoratorAstNode => ({ - type: "fail", - attributes: [], - children: [], - validate() { - // A fail node must have a single node. - if (this.children!.length !== 1) { - throw new Error("a fail node must have a single child"); - } - }, - createNodeInstance(namedRootNodeProvider, visitedBranches) { - return new Fail( - this.attributes, - this.children![0].createNodeInstance(namedRootNodeProvider, visitedBranches.slice()) - ); - } - }), - WAIT: (): WaitAstNode => ({ - type: "wait", - attributes: [], - duration: null, - durationMin: null, - durationMax: null, - validate() { - if (this.duration !== null) { - // If an explict duration was defined then it must be a positive number. - if (this.duration < 0) { - throw new Error("a wait node must have a positive duration"); - } - } else if (this.durationMin !== null && this.durationMax !== null) { - // A wait node must have a positive min and max duration. - if (this.durationMin < 0 || this.durationMax < 0) { - throw new Error("a wait node must have a positive minimum and maximum duration"); - } - - // A wait node must not have a minimum duration that exceeds the maximum duration. - if (this.durationMin > this.durationMax) { - throw new Error("a wait node must not have a minimum duration that exceeds the maximum duration"); - } - } else { - // If we have no explicit duration or duration bounds set then we are dealing with a wait node that waits indefinitely. - } - }, - createNodeInstance() { - return new Wait(this.attributes, this.duration, this.durationMin, this.durationMax); - } - }), - ACTION: (): ActionAstNode => ({ - type: "action", - attributes: [], - actionName: "", - actionArguments: [], - validate() {}, - createNodeInstance() { - return new Action(this.attributes, this.actionName!, this.actionArguments!); - } - }), - CONDITION: (): ConditionAstNode => ({ - type: "condition", - attributes: [], - conditionName: "", - conditionArguments: [], - validate() {}, - createNodeInstance() { - return new Condition(this.attributes, this.conditionName!, this.conditionArguments!); - } - }) -}; - -type OtherAstNodes = AstNode[]; - -/** - * 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[] { - // Swap out any node/attribute argument string literals with a placeholder and get a mapping of placeholders to original values as well as the processed definition. - const { placeholders, processedDefinition } = substituteStringLiterals(definition); - - // Convert the processed definition (with substituted string literals) into an array of raw tokens. - const tokens = parseTokensFromDefinition(processedDefinition); - - // There must be at least 3 tokens for the tree definition to be valid. 'ROOT', '{' and '}'. - if (tokens.length < 3) { - throw new Error("invalid token count"); - } - - // We should have a matching number of '{' and '}' tokens. If not, then there are scopes that have not been properly closed. - if (tokens.filter((token) => token === "{").length !== tokens.filter((token) => token === "}").length) { - throw new Error("scope character mismatch"); - } - - // Create a stack of node children arrays, starting with a definition scope. - const stack: [RootAstNode[], ...OtherAstNodes[]] = [[]]; - const rootScope = stack[0]; - - // We should keep processing the raw tokens until we run out of them. - while (tokens.length) { - // Grab the next token. - const token = tokens.shift(); - - const currentScope = stack[stack.length - 1] as OtherAstNodes; - - // How we create the next AST token depends on the current raw token value. - switch (token!.toUpperCase()) { - case "ROOT": { - // Create a ROOT AST node. - const node = ASTNodeFactories.ROOT(); - - // Push the ROOT node into the current scope. - rootScope.push(node); - - // We may have a root node name defined as an argument. - if (tokens[0] === "[") { - const rootArguments = getArguments(tokens, placeholders); - - // We should have only a single argument that is not an empty string for a root node, which is the root name identifier. - if (rootArguments.length === 1 && rootArguments[0].type === "identifier") { - // The root name will be the first and only node argument. - node.name = rootArguments[0].value as string; - } else { - throw new Error("expected single root name argument"); - } - } - - // Try to pick any attributes off of the token stack. - node.attributes = getAttributes(tokens, placeholders); - - popAndCheck(tokens, "{"); - - // The new scope is that of the new ROOT nodes children. - stack.push(node.children!); - break; - } - - case "BRANCH": { - // Create a BRANCH AST node. - const node = ASTNodeFactories.BRANCH(); - - // Push the BRANCH node into the current scope. - currentScope.push(node); - - // We must have arguments defined, as we require a branch name argument. - if (tokens[0] !== "[") { - throw new Error("expected single branch name argument"); - } - - // The branch name will be defined as a node argument. - const branchArguments = getArguments(tokens, placeholders); - - // We should have only a single identifer argument for a branch node, which is the branch name. - if (branchArguments.length === 1 && branchArguments[0].type === "identifier") { - // The branch name will be the first and only node argument. - node.branchName = branchArguments[0].value as string; - } else { - throw new Error("expected single branch name argument"); - } - break; - } - - case "SELECTOR": { - // Create a SELECTOR AST node. - const node = ASTNodeFactories.SELECTOR(); - - // Push the SELECTOR node into the current scope. - currentScope.push(node); - - // Try to pick any attributes off of the token stack. - node.attributes = getAttributes(tokens, placeholders); - - popAndCheck(tokens, "{"); - - // The new scope is that of the new SELECTOR nodes children. - stack.push(node.children!); - break; - } - - case "SEQUENCE": { - // Create a SEQUENCE AST node. - const node = ASTNodeFactories.SEQUENCE(); - - // Push the SEQUENCE node into the current scope. - currentScope.push(node); - - // Try to pick any attributes off of the token stack. - node.attributes = getAttributes(tokens, placeholders); - - popAndCheck(tokens, "{"); - - // The new scope is that of the new SEQUENCE nodes children. - stack.push(node.children!); - break; - } - - case "PARALLEL": { - // Create a PARALLEL AST node. - const node = ASTNodeFactories.PARALLEL(); - - // Push the PARALLEL node into the current scope. - currentScope.push(node); - - // Try to pick any attributes off of the token stack. - node.attributes = getAttributes(tokens, placeholders); - - popAndCheck(tokens, "{"); - - // The new scope is that of the new PARALLEL nodes children. - stack.push(node.children!); - break; - } - - case "LOTTO": { - // Create a LOTTO AST node. - const node = ASTNodeFactories.LOTTO(); - - // Push the LOTTO node into the current scope. - currentScope.push(node); - - // If the next token is a '[' character then some ticket counts have been defined as arguments. - if (tokens[0] === "[") { - // Get the ticket count arguments, each argument must be a number. - node.tickets = getArguments( - tokens, - placeholders, - (arg) => arg.type === "number" && !!arg.isInteger, - "lotto node ticket counts must be integer values" - ).map((argument) => argument.value as number); - } - - // Try to pick any attributes off of the token stack. - node.attributes = getAttributes(tokens, placeholders); - - popAndCheck(tokens, "{"); - - // The new scope is that of the new LOTTO nodes children. - stack.push(node.children!); - break; - } - - case "CONDITION": { - // Create a CONDITION AST node. - const node = ASTNodeFactories.CONDITION(); - - // Push the CONDITION node into the current scope. - currentScope.push(node); - - // We must have arguments defined, as we require a condition function name argument. - if (tokens[0] !== "[") { - throw new Error("expected condition name identifier argument"); - } - - // Grab the condition node arguments. - const conditionArguments = getArguments(tokens, placeholders); - - // We should have at least a single identifier argument for a condition node, which is the condition function name. - if (conditionArguments.length && conditionArguments[0].type === "identifier") { - // The condition function name will be the first node argument. - node.conditionName = conditionArguments.shift()!.value as string; - } else { - throw new Error("expected condition name identifier argument"); - } - - // Only the first argument should have been an identifier, all following arguments must be string, number, boolean or null. - conditionArguments - .filter((arg) => arg.type === "identifier") - .forEach((arg) => { - throw new Error( - "invalid condition node argument value '" + - arg.value + - "', must be string, number, boolean or null" - ); - }); - - // Any node arguments that follow the condition name identifier will be treated as condition function arguments. - node.conditionArguments = conditionArguments; - - // Try to pick any attributes off of the token stack. - node.attributes = getAttributes(tokens, placeholders); - break; - } - - case "FLIP": { - // Create a FLIP AST node. - const node = ASTNodeFactories.FLIP(); - - // Push the Flip node into the current scope. - currentScope.push(node); - - // Try to pick any attributes off of the token stack. - node.attributes = getAttributes(tokens, placeholders); - - popAndCheck(tokens, "{"); - - // The new scope is that of the new FLIP nodes children. - stack.push(node.children!); - break; - } - - case "SUCCEED": { - // Create a SUCCEED AST node. - const node = ASTNodeFactories.SUCCEED(); - - // Push the Succeed node into the current scope. - currentScope.push(node); - - // Try to pick any attributes off of the token stack. - node.attributes = getAttributes(tokens, placeholders); - - popAndCheck(tokens, "{"); - - // The new scope is that of the new Succeed nodes children. - stack.push(node.children!); - break; - } - - case "FAIL": { - // Create a FAIL AST node. - const node = ASTNodeFactories.FAIL(); - - // Push the Fail node into the current scope. - currentScope.push(node); - - // Try to pick any attributes off of the token stack. - node.attributes = getAttributes(tokens, placeholders); - - popAndCheck(tokens, "{"); - - // The new scope is that of the new Fail nodes children. - stack.push(node.children!); - break; - } - - case "WAIT": { - // Create a WAIT AST node. - const node = ASTNodeFactories.WAIT(); - - // Push the WAIT node into the current scope. - currentScope.push(node); - - // The arguments of a wait node are optional. We may have: - // - No node arguments, in which case the wait will be indefinite until it is aborted. - // - One node argument which will be the explicit duration of the wait. - // - Two node arguments which define the min and max duration bounds from which a random duration will be picked. - if (tokens[0] === "[") { - // Get the optional duration and longest duration of the wait. - const nodeArguments = getArguments( - tokens, - placeholders, - (arg) => arg.type === "number" && !!arg.isInteger, - "wait node durations must be integer values" - ).map((argument) => argument.value); - - // We may have: - // - One node argument which will be the explicit duration of the wait. - // - Two node arguments which define the min and max duration bounds from which a random duration will be picked. - // - Too many arguments, which is not valid. - if (nodeArguments.length === 1) { - // An explicit duration was defined. - node.duration = nodeArguments[0] as number; - } else if (nodeArguments.length === 2) { - // Min and max duration bounds were defined from which a random duration will be picked. - node.durationMin = nodeArguments[0] as number; - node.durationMax = nodeArguments[1] as number; - } else if (nodeArguments.length > 2) { - // An incorrect number of durations was defined. - throw new Error("invalid number of wait node duration arguments defined"); - } - } - - // Try to pick any attributes off of the token stack. - node.attributes = getAttributes(tokens, placeholders); - break; - } - - case "REPEAT": { - // Create a REPEAT AST node. - const node = ASTNodeFactories.REPEAT(); - - // Push the REPEAT node into the current scope. - currentScope.push(node); - - // The arguments of a repeat node are optional. We may have: - // - No node arguments, in which case the repeat note will iterate indefinitely. - // - One node argument which will be the explicit number of iterations to make. - // - Two node arguments which define the min and max iteration bounds from which a random iteration count will be picked. - if (tokens[0] === "[") { - // An iteration count has been defined. Get the iteration and potential maximum iteration of the wait. - const nodeArguments = getArguments( - tokens, - placeholders, - (arg) => arg.type === "number" && !!arg.isInteger, - "repeat node iteration counts must be integer values" - ).map((argument) => argument.value); - - // We should have got one or two iteration counts. - if (nodeArguments.length === 1) { - // A static iteration count was defined. - node.iterations = nodeArguments[0] as number; - } else if (nodeArguments.length === 2) { - // A minimum and maximum iteration count was defined. - node.iterationsMin = nodeArguments[0] as number; - node.iterationsMax = nodeArguments[1] as number; - } else { - // An incorrect number of iteration counts was defined. - throw new Error("invalid number of repeat node iteration count arguments defined"); - } - } - - // Try to pick any attributes off of the token stack. - node.attributes = getAttributes(tokens, placeholders); - - popAndCheck(tokens, "{"); - - // The new scope is that of the new REPEAT nodes children. - stack.push(node.children!); - break; - } - - case "RETRY": { - // Create a RETRY AST node. - const node = ASTNodeFactories.RETRY(); - - // Push the RETRY node into the current scope. - currentScope.push(node); - - // The arguments of a retry node are optional. We may have: - // - No node arguments, in which case the retry note will attempt indefinitely. - // - One node argument which will be the explicit number of attempts to make. - // - Two node arguments which define the min and max attempt bounds from which a random attempt count will be picked. - if (tokens[0] === "[") { - // An attempt count has been defined. Get the attempt count and potential maximum attempt count of the wait. - const nodeArguments = getArguments( - tokens, - placeholders, - (arg) => arg.type === "number" && !!arg.isInteger, - "retry node attempt counts must be integer values" - ).map((argument) => argument.value); - - // We should have got one or two attempt counts. - if (nodeArguments.length === 1) { - // A static attempt count was defined. - node.attempts = nodeArguments[0] as number; - } else if (nodeArguments.length === 2) { - // A minimum and maximum attempt count was defined. - node.attemptsMin = nodeArguments[0] as number; - node.attemptsMax = nodeArguments[1] as number; - } else { - // An incorrect number of attempt counts was defined. - throw new Error("invalid number of retry node attempt count arguments defined"); - } - } - - // Try to pick any attributes off of the token stack. - node.attributes = getAttributes(tokens, placeholders); - - popAndCheck(tokens, "{"); - - // The new scope is that of the new RETRY nodes children. - stack.push(node.children!); - break; - } - - case "ACTION": { - // Create a ACTION AST node. - const node = ASTNodeFactories.ACTION(); - - // Push the ACTION node into the current scope. - currentScope.push(node); - - // We must have arguments defined, as we require an action name argument. - if (tokens[0] !== "[") { - throw new Error("expected action name identifier argument"); - } - - // The action name will be defined as a node argument. - const actionArguments = getArguments(tokens, placeholders); - - // We should have at least one identifer argument for an action node, which is the action name. - if (actionArguments.length && actionArguments[0].type === "identifier") { - // The action name will be the first and only node argument. - node.actionName = actionArguments.shift()!.value as string; - } else { - throw new Error("expected action name identifier argument"); - } - - // Only the first argument should have been an identifier, all following arguments must be string, number, boolean or null. - actionArguments - .filter((arg) => arg.type === "identifier") - .forEach((arg) => { - throw new Error( - "invalid action node argument value '" + - arg.value + - "', must be string, number, boolean or null" - ); - }); - - // Any node arguments that follow the action name identifier will be treated as action function arguments. - node.actionArguments = actionArguments; - - // Try to pick any attributes off of the token stack. - node.attributes = getAttributes(tokens, placeholders); - break; - } - - case "}": { - // The '}' character closes the current scope. - stack.pop(); - break; - } - - default: { - throw new Error(`unexpected token '${token}'`); - } - } - } - - // A function to recursively validate each of the nodes in the AST. - const validateASTNode = (node: Validatable, depth: number): void => { - // Validate the node. - node.validate(depth); - - // Validate each child of the node. - (node.children || []).forEach((child) => validateASTNode(child, depth + 1)); - }; - - // Start node validation from the definition root. - validateASTNode( - { - children: stack[0] as RootAstNode[], - validate(this: { children: RootAstNode[] }) { - // We must have at least one node defined as the definition scope, which should be a root node. - if (this.children.length === 0) { - throw new Error("expected root node to have been defined"); - } - - // Each node at the base of the definition scope MUST be a root node. - for (const definitionLevelNode of this.children) { - if (definitionLevelNode.type !== "root") { - throw new Error("expected root node at base of definition"); - } - } - - // Exactly one root node must not have a name defined. This will be the main root, others will have to be referenced via branch nodes. - if (this.children.filter((definitionLevelNode) => definitionLevelNode.name === null).length !== 1) { - throw new Error("expected single unnamed root node at base of definition to act as main root"); - } - - // No two named root nodes can have matching names. - const rootNodeNames: string[] = []; - for (const definitionLevelNode of this.children) { - if (rootNodeNames.indexOf(definitionLevelNode.name!) !== -1) { - throw new Error(`multiple root nodes found with duplicate name '${definitionLevelNode.name}'`); - } else { - rootNodeNames.push(definitionLevelNode.name!); - } - } - } - }, - 0 - ); - - // Return the root AST nodes. - return stack[0]; -} - -/** - * Pop the next raw token off of the stack and throw an error if it wasn't the expected one. - * @param tokens The array of remaining tokens. - * @param expected An optional string or array or items, one of which must match the next popped token. - * @returns The popped token. - */ -function popAndCheck(tokens: string[], expected: string | string[]) { - // Get and remove the next token. - const popped = tokens.shift(); - - // We were expecting another token. - if (popped === undefined) { - throw new Error("unexpected end of definition"); - } - - // Do we have an expected token/tokens array? - if (expected !== undefined) { - // Check whether the popped token matches at least one of our expected items. - var tokenMatchesExpectation = ([] as string[]) - .concat(expected) - .some((item) => popped.toUpperCase() === item.toUpperCase()); - - // Throw an error if the popped token didn't match any of our expected items. - if (!tokenMatchesExpectation) { - const expectationString = ([] as string[]) - .concat(expected) - .map((item) => "'" + item + "'") - .join(" or "); - - throw new Error(`unexpected token found. Expected '${expectationString}' but got '${popped}'`); - } - } - - // Return the popped token. - return popped; -} - -type StringPlaceholders = { [key: string]: string }; - -/** - * Pull an argument definition list off of the token stack. - * @param tokens The array of remaining tokens. - * @param stringArgumentPlaceholders The mapping of string literal node argument placeholders to original values. - * @param argumentValidator The argument validator function. - * @param validationFailedMessage The exception message to throw if argument validation fails. - * @returns The argument definition list. - */ -function getArguments( - tokens: string[], - stringArgumentPlaceholders: StringPlaceholders, - argumentValidator?: (arg: AnyArgument) => boolean, - validationFailedMessage?: string -) { - // Any lists of arguments will always be wrapped in '[]' for node arguments or '()' for attribute arguments. - // We are looking for a '[' or '(' opener that wraps the argument tokens and the relevant closer. - const closer = popAndCheck(tokens, ["[", "("]) === "[" ? "]" : ")"; - - const argumentListTokens: string[] = []; - const argumentList: AnyArgument[] = []; - - // Grab all tokens between the '[' and ']' or '(' and ')'. - while (tokens.length && tokens[0] !== closer) { - // The next token is part of our arguments list. - argumentListTokens.push(tokens.shift()!); - } - - // Validate the order of the argument tokens. Each token must either be a ',' or a single argument that satisfies the validator. - argumentListTokens.forEach((token, index) => { - // Get whether this token should be an actual argument. - const shouldBeArgumentToken = !(index & 1); - - // If the current token should be an actual argument then validate it,otherwise it should be a ',' token. - if (shouldBeArgumentToken) { - // Get the argument definition. - const argumentDefinition = getArgumentDefinition(token!, stringArgumentPlaceholders); - - // Try to validate the argument. - if (argumentValidator && !argumentValidator(argumentDefinition)) { - throw new Error(validationFailedMessage); - } - - // This is a valid argument! - argumentList.push(argumentDefinition); - } else { - // The current token should be a ',' token. - if (token !== ",") { - throw new Error(`invalid argument list, expected ',' or ']' but got '${token}'`); - } - } - }); - - // The arguments list should terminate with a ']' or ')' token, depending on the opener. - popAndCheck(tokens, closer); - - // Return the argument list. - return argumentList; -} - -/** - * Gets an argument value definition. - * @param token The argument token. - * @param stringArgumentPlaceholders The mapping of string literal node argument placeholders to original values. - * @returns An argument value definition. - */ -function getArgumentDefinition(token: string, stringArgumentPlaceholders: StringPlaceholders): AnyArgument { - // Check whether the token represents a null value. - if (token === "null") { - return { - value: null, - type: "null" - } as NullArgument; - } - - // Check whether the token represents a boolean value. - if (token === "true" || token === "false") { - return { - value: token === "true", - type: "boolean" - } as BooleanArgument; - } - - // Check whether the token represents a number value. - // TODO: Relies on broken isNaN - see MDN. - // if (!Number.isNaN(token)) { - if (!isNaN(token as any)) { - return { - value: parseFloat(token), - isInteger: parseFloat(token) === parseInt(token, 10), - type: "number" - } as NumberArgument; - } - - // Check whether the token is a placeholder (e.g. @@0@@) representing a string literal. - if (token.match(/^@@\d+@@$/g)) { - return { - value: stringArgumentPlaceholders[token].replace('\\"', '"'), - type: "string" - } as StringPlaceholderArgument; - } - - // The only remaining option is that the argument value is an identifier. - return { - value: token, - type: "identifier" - } as IdentifierArgument; -} - -/** - * Pull any attributes off of the token stack. - * @param tokens The array of remaining tokens. - * @param stringArgumentPlaceholders The mapping of string literal node argument placeholders to original values. - * @returns An array of attributes defined by any directly following tokens. - */ -function getAttributes(tokens: string[], stringArgumentPlaceholders: StringPlaceholders) { - // Create an array to hold any attributes found. - const attributes: Attribute[] = []; - - // Keep track of names of attribute that we have found on the token stack, as we cannot have duplicates. - const attributesFound: string[] = []; - - // Try to get the attribute factory for the next token. - let attributeFactory = AttributeFactories[(tokens[0] || "").toUpperCase()]; - - // Pull attribute tokens off of the tokens stack until we have no more. - while (attributeFactory) { - // Check to make sure that we have not already created a attribute of this type for this node. - if (attributesFound.indexOf(tokens[0].toUpperCase()) !== -1) { - throw new Error(`duplicate attribute '${tokens[0].toUpperCase()}' found for node`); - } - - // Add the current attribute type to our array of found attributes. - attributesFound.push(tokens.shift()!.toUpperCase()); - - // Grab any attribute arguments. - const attributeArguments = getArguments(tokens, stringArgumentPlaceholders); - - // The first attribute argument has to be an identifer, this will reference an agent function. - if (attributeArguments.length === 0 || attributeArguments[0].type !== "identifier") { - throw new Error("expected agent function name identifier argument for attribute"); - } - - // Grab the first attribute which is an identifier that will reference an agent function. - const attributeFunctionName = attributeArguments.shift()! as IdentifierArgument; - - // Any remaining attribute arguments must have a type of string, number, boolean or null. - attributeArguments - .filter((arg) => arg.type === "identifier") - .forEach((arg) => { - throw new Error( - "invalid attribute argument value '" + arg.value + "', must be string, number, boolean or null" - ); - }); - - // Create the attribute and add it to the array of attributes found. - attributes.push(attributeFactory(attributeFunctionName.value, attributeArguments)); - - // Try to get the next attribute name token, as there could be multiple. - attributeFactory = AttributeFactories[(tokens[0] || "").toUpperCase()]; - } - - return attributes; -} - -/** - * Swaps out any node/attribute argument string literals with placeholders. - * @param definition The definition. - * @returns An object containing a mapping of placeholders to original string values as well as the processed definition string. - */ -function substituteStringLiterals(definition: string): { - placeholders: { [key: string]: string }; - processedDefinition: string; -} { - // Create an object to hold the mapping of placeholders to original string values. - const placeholders: StringPlaceholders = {}; - - // Replace any string literals wrapped with double quotes in our definition with placeholders to be processed later. - const processedDefinition = definition.replace(/\"(\\.|[^"\\])*\"/g, (match) => { - var strippedMatch = match.substring(1, match.length - 1); - var placeholder = Object.keys(placeholders).find((key) => placeholders[key] === strippedMatch); - - // If we have no existing string literal match then create a new placeholder. - if (!placeholder) { - placeholder = `@@${Object.keys(placeholders).length}@@`; - placeholders[placeholder] = strippedMatch; - } - - return placeholder; - }); - - return { placeholders, processedDefinition }; -} - -/** - * Parse the tree definition into an array of raw tokens. - * @param definition The definition. - * @returns An array of tokens parsed from the definition. - */ -function parseTokensFromDefinition(definition: string): string[] { - // Add some space around various important characters so that they can be plucked out easier as individual tokens. - definition = definition.replace(/\(/g, " ( "); - definition = definition.replace(/\)/g, " ) "); - definition = definition.replace(/\{/g, " { "); - definition = definition.replace(/\}/g, " } "); - definition = definition.replace(/\]/g, " ] "); - definition = definition.replace(/\[/g, " [ "); - definition = definition.replace(/\,/g, " , "); - - // Split the definition into raw token form and return it. - return definition.replace(/\s+/g, " ").trim().split(" "); -} diff --git a/src/attributes/Attribute.ts b/src/attributes/Attribute.ts index e72953f..82803f0 100644 --- a/src/attributes/Attribute.ts +++ b/src/attributes/Attribute.ts @@ -1,4 +1,3 @@ -import { AnyArgument } from "../RootAstNodesBuilder"; import Guard from "./guards/Guard"; export type AttributeDetails = { @@ -6,7 +5,7 @@ export type AttributeDetails = { type: string; /** The attribute arguments. */ - args: AnyArgument[]; + args: any[]; }; /** @@ -15,19 +14,9 @@ export type AttributeDetails = { export default abstract class Attribute { /** * @param type The node attribute type. - * @param args The array of attribute argument definitions. + * @param args The array of attribute arguments. */ - constructor(protected type: string, protected args: AnyArgument[]) {} - - /** - * Gets the type of the attribute. - */ - getType = () => this.type; - - /** - * Gets the array of attribute argument definitions. - */ - getArguments = () => this.args; + constructor(public type: string, public args: any[]) {} /** * Gets the attribute details. diff --git a/src/attributes/callbacks/Callback.ts b/src/attributes/callbacks/Callback.ts index b8b9707..c262690 100644 --- a/src/attributes/callbacks/Callback.ts +++ b/src/attributes/callbacks/Callback.ts @@ -1,5 +1,4 @@ import { Agent } from "../../Agent"; -import { AnyArgument } from "../../RootAstNodesBuilder"; import Attribute, { AttributeDetails } from "../Attribute"; export type CallbackAttributeDetails = { @@ -16,7 +15,7 @@ export default abstract class Callback extends Attribute { * @param args The array of decorator argument definitions. * @param condition The name of the condition function that determines whether the guard is satisfied. */ - constructor(type: string, args: AnyArgument[], private condition: string) { + constructor(type: string, args: any[], private condition: string) { super(type, args); } @@ -35,8 +34,8 @@ export default abstract class Guard extends Attribute { */ getDetails(): GuardAttributeDetails { return { - type: this.getType(), - args: this.getArguments(), + type: this.type, + args: this.args, condition: this.getCondition() }; } diff --git a/src/attributes/guards/Until.ts b/src/attributes/guards/Until.ts index bc9f313..4152bc9 100644 --- a/src/attributes/guards/Until.ts +++ b/src/attributes/guards/Until.ts @@ -1,7 +1,6 @@ import Guard from "./Guard"; import Lookup from "../../Lookup"; import { Agent } from "../../Agent"; -import { AnyArgument } from "../../RootAstNodesBuilder"; /** * An UNTIL guard which is satisfied as long as the given condition remains false. @@ -11,7 +10,7 @@ export default class Until extends Guard { * @param condition The name of the condition function that determines whether the guard is satisfied. * @param args The array of decorator argument definitions. */ - constructor(condition: string, args: AnyArgument[]) { + constructor(condition: string, args: any[]) { super("until", args, condition); } diff --git a/src/attributes/guards/While.ts b/src/attributes/guards/While.ts index 564277a..13be8dc 100644 --- a/src/attributes/guards/While.ts +++ b/src/attributes/guards/While.ts @@ -1,7 +1,6 @@ import Guard from "./Guard"; import Lookup from "../../Lookup"; import { Agent } from "../../Agent"; -import { AnyArgument } from "../../RootAstNodesBuilder"; /** * A WHILE guard which is satisfied as long as the given condition remains true. @@ -11,7 +10,7 @@ export default class While extends Guard { * @param condition The name of the condition function that determines whether the guard is satisfied. * @param args The array of decorator argument definitions. */ - constructor(condition: string, args: AnyArgument[]) { + constructor(condition: string, args: any[]) { super("while", args, condition); } diff --git a/src/mdsl/MDSLNodeArgumentParser.ts b/src/mdsl/MDSLNodeArgumentParser.ts index 2c700e2..84e8523 100644 --- a/src/mdsl/MDSLNodeArgumentParser.ts +++ b/src/mdsl/MDSLNodeArgumentParser.ts @@ -1,39 +1,47 @@ import { StringLiteralPlaceholders, popAndCheck } from "./MDSLUtilities"; -export type Argument = { - /** The argument value. */ +/** + * A type representing any node function argument. + */ +type Argument = { + /** + * The argument value. + */ value: T; - /** The argument type, used for validation. */ + /** + * The argument type, used for validation. + */ type: string; }; -export type NullArgument = Argument & { +type NullArgument = Argument & { type: "null"; }; -export type BooleanArgument = Argument & { +type BooleanArgument = Argument & { type: "boolean"; }; -export type NumberArgument = Argument & { +type NumberArgument = Argument & { type: "number"; - isInteger: boolean; // Used for validation. + /** + * A flag defining whether the number argument value is a valid integer. (used for validation) + */ + isInteger: boolean; }; -export type StringPlaceholderArgument = Argument & { +type StringPlaceholderArgument = Argument & { type: "string"; }; -export type IdentifierArgument = Argument & { +type IdentifierArgument = Argument & { type: "identifier"; }; -export type AnyArgument = - | NullArgument - | BooleanArgument - | NumberArgument - | StringPlaceholderArgument - | IdentifierArgument; +/** + * A type representing a reference to any node function argument. + */ +type AnyArgument = NullArgument | BooleanArgument | NumberArgument | StringPlaceholderArgument | IdentifierArgument; /** * Parse an array of argument definitions from the specified tokens array. diff --git a/src/nodes/Node.ts b/src/nodes/Node.ts index e1f87e5..67ee974 100644 --- a/src/nodes/Node.ts +++ b/src/nodes/Node.ts @@ -1,4 +1,7 @@ +import { BehaviourTreeOptions } from "../BehaviourTreeOptions"; +import State, { AnyState } from "../State"; import { Agent } from "../Agent"; +import Leaf from "./leaf/Leaf"; import Attribute from "../attributes/Attribute"; import Entry from "../attributes/callbacks/Entry"; import Exit from "../attributes/callbacks/Exit"; @@ -6,10 +9,6 @@ import Step from "../attributes/callbacks/Step"; import Guard from "../attributes/guards/Guard"; import GuardPath from "../attributes/guards/GuardPath"; import GuardUnsatisifedException from "../attributes/guards/GuardUnsatisifedException"; -import { BehaviourTreeOptions } from "../BehaviourTreeOptions"; -import { AnyArgument } from "../RootAstNodesBuilder"; -import State, { AnyState } from "../State"; -import Leaf from "./leaf/Leaf"; /** * A base node. @@ -33,7 +32,7 @@ export default abstract class Node { * @param attributes The node attributes. * @param args The node argument definitions. */ - constructor(private type: string, private attributes: Attribute[], private args: AnyArgument[]) {} + constructor(private type: string, private attributes: Attribute[], private args: any[]) {} /** * Called when the node is being updated. @@ -88,8 +87,7 @@ export default abstract class Node { getAttribute(type: "step" | "STEP"): Step; getAttribute(type: string): Attribute { return ( - this.getAttributes().filter((decorator) => decorator.getType().toUpperCase() === type.toUpperCase())[0] || - null + this.getAttributes().filter((decorator) => decorator.type.toUpperCase() === type.toUpperCase())[0] || null ); } diff --git a/src/nodes/leaf/Action.ts b/src/nodes/leaf/Action.ts index 3292910..a35387a 100644 --- a/src/nodes/leaf/Action.ts +++ b/src/nodes/leaf/Action.ts @@ -1,10 +1,9 @@ -import Leaf from "./Leaf"; +import { BehaviourTreeOptions } from "../../BehaviourTreeOptions"; import State, { CompleteState } from "../../State"; -import Lookup from "../../Lookup"; import { Agent } from "../../Agent"; +import Leaf from "./Leaf"; +import Lookup from "../../Lookup"; import Attribute from "../../attributes/Attribute"; -import { AnyArgument } from "../../RootAstNodesBuilder"; -import { BehaviourTreeOptions } from "../../BehaviourTreeOptions"; /** * An Action leaf node. @@ -16,7 +15,7 @@ export default class Action extends Leaf { * @param actionName The action name. * @param actionArguments The array of action argument definitions. */ - constructor(attributes: Attribute[], private actionName: string, private actionArguments: AnyArgument[]) { + constructor(attributes: Attribute[], private actionName: string, private actionArguments: any[]) { super("action", attributes, actionArguments); } diff --git a/src/nodes/leaf/Condition.ts b/src/nodes/leaf/Condition.ts index f9358d1..bb00971 100644 --- a/src/nodes/leaf/Condition.ts +++ b/src/nodes/leaf/Condition.ts @@ -1,10 +1,9 @@ -import Leaf from "./Leaf"; +import { BehaviourTreeOptions } from "../../BehaviourTreeOptions"; import State from "../../State"; -import Lookup from "../../Lookup"; import { Agent } from "../../Agent"; +import Leaf from "./Leaf"; +import Lookup from "../../Lookup"; import Attribute from "../../attributes/Attribute"; -import { AnyArgument } from "../../RootAstNodesBuilder"; -import { BehaviourTreeOptions } from "../../BehaviourTreeOptions"; /** * A Condition leaf node. @@ -16,7 +15,7 @@ export default class Condition extends Leaf { * @param conditionName The name of the condition function. * @param conditionArguments The array of condition argument definitions. */ - constructor(attributes: Attribute[], private conditionName: string, private conditionArguments: AnyArgument[]) { + constructor(attributes: Attribute[], private conditionName: string, private conditionArguments: any[]) { super("condition", attributes, conditionArguments); } From 3b6062970d3dbb336c74c815588687023938f0d9 Mon Sep 17 00:00:00 2001 From: Nikolas Howard Date: Wed, 7 Feb 2024 12:56:47 +0000 Subject: [PATCH 21/48] worked on mdsl and json validation --- dist/BehaviourTreeDefinitionUtilities.d.ts | 6 + dist/bundle.js | 926 ++++++++++++++++++++- dist/bundle.js.map | 8 +- dist/index.js | 926 ++++++++++++++++++++- dist/index.js.map | 8 +- dist/nodes/composite/Lotto.d.ts | 6 +- src/BehaviourTreeBuilder.ts | 108 ++- src/BehaviourTreeDefinitionUtilities.ts | 9 + src/BehaviourTreeDefinitionValidator.ts | 69 +- src/mdsl/MDSLDefinitionParser.ts | 97 ++- src/nodes/composite/Lotto.ts | 8 +- 11 files changed, 2121 insertions(+), 50 deletions(-) diff --git a/dist/BehaviourTreeDefinitionUtilities.d.ts b/dist/BehaviourTreeDefinitionUtilities.d.ts index 212778a..bbf6b0e 100644 --- a/dist/BehaviourTreeDefinitionUtilities.d.ts +++ b/dist/BehaviourTreeDefinitionUtilities.d.ts @@ -41,3 +41,9 @@ export declare function flattenDefinition(nodeDefinition: AnyNodeDefinition): An * @returns Whether the passed value is an integer. */ export declare function isInteger(value: unknown): boolean; +/** + * Determines whether the passed value is null or undefined. + * @param value The value to check. + * @returns Whether the passed value is null or undefined. + */ +export declare function isNullOrUndefined(value: unknown): boolean; diff --git a/dist/bundle.js b/dist/bundle.js index 8ca7544..18715e2 100644 --- a/dist/bundle.js +++ b/dist/bundle.js @@ -1,10 +1,15 @@ "use strict"; var mistreevous = (() => { + var __create = Object.create; var __defProp = Object.defineProperty; var __getOwnPropDesc = Object.getOwnPropertyDescriptor; var __getOwnPropNames = Object.getOwnPropertyNames; + var __getProtoOf = Object.getPrototypeOf; var __hasOwnProp = Object.prototype.hasOwnProperty; var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value; + var __commonJS = (cb, mod) => function __require() { + return mod || (0, cb[__getOwnPropNames(cb)[0]])((mod = { exports: {} }).exports, mod), mod.exports; + }; var __export = (target, all) => { for (var name in all) __defProp(target, name, { get: all[name], enumerable: true }); @@ -17,12 +22,232 @@ var mistreevous = (() => { } return to; }; + var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps( + isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target, + mod + )); var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod); var __publicField = (obj, key, value) => { __defNormalProp(obj, typeof key !== "symbol" ? key + "" : key, value); return value; }; + // node_modules/lotto-draw/dist/Participant.js + var require_Participant = __commonJS({ + "node_modules/lotto-draw/dist/Participant.js"(exports) { + "use strict"; + Object.defineProperty(exports, "__esModule", { value: true }); + exports.Participant = void 0; + var Participant = function() { + function Participant2(participant, tickets) { + if (tickets === void 0) { + tickets = 1; + } + this._participant = participant; + this._tickets = tickets; + } + Object.defineProperty(Participant2.prototype, "participant", { + get: function() { + return this._participant; + }, + enumerable: false, + configurable: true + }); + Object.defineProperty(Participant2.prototype, "tickets", { + get: function() { + return this._tickets; + }, + set: function(value) { + this._tickets = value; + }, + enumerable: false, + configurable: true + }); + return Participant2; + }(); + exports.Participant = Participant; + } + }); + + // node_modules/lotto-draw/dist/Utilities.js + var require_Utilities = __commonJS({ + "node_modules/lotto-draw/dist/Utilities.js"(exports) { + "use strict"; + Object.defineProperty(exports, "__esModule", { value: true }); + exports.isNaturalNumber = exports.isNullOrUndefined = void 0; + function isNullOrUndefined2(value) { + return value === null || value === void 0; + } + exports.isNullOrUndefined = isNullOrUndefined2; + function isNaturalNumber(value) { + return typeof value === "number" && value >= 1 && Math.floor(value) === value; + } + exports.isNaturalNumber = isNaturalNumber; + } + }); + + // node_modules/lotto-draw/dist/Lotto.js + var require_Lotto = __commonJS({ + "node_modules/lotto-draw/dist/Lotto.js"(exports) { + "use strict"; + Object.defineProperty(exports, "__esModule", { value: true }); + exports.Lotto = void 0; + var Participant_1 = require_Participant(); + var Utilities_1 = require_Utilities(); + var Lotto2 = function() { + function Lotto3(customRandom) { + this._participants = []; + this._customRandom = customRandom; + } + Lotto3.prototype.add = function(participant, tickets) { + if (tickets === void 0) { + tickets = 1; + } + if (!(0, Utilities_1.isNaturalNumber)(tickets)) { + throw new Error("tickets value must be a natural number"); + } + var existingParticipant = this._participants.find(function(part) { + return part.participant === participant; + }); + if (existingParticipant) { + existingParticipant.tickets += tickets; + } else { + this._participants.push(new Participant_1.Participant(participant, tickets)); + } + return this; + }; + Lotto3.prototype.remove = function(participant, tickets) { + var existingParticipant = this._participants.find(function(part) { + return part.participant === participant; + }); + if (!existingParticipant) { + return this; + } + if (tickets !== void 0) { + if (!(0, Utilities_1.isNaturalNumber)(tickets)) { + throw new Error("tickets value must be a natural number"); + } + existingParticipant.tickets -= tickets; + if (existingParticipant.tickets < 1) { + this._participants = this._participants.filter(function(part) { + return part !== existingParticipant; + }); + } + } else { + this._participants = this._participants.filter(function(part) { + return part !== existingParticipant; + }); + } + return this; + }; + Lotto3.prototype.draw = function(options) { + if (options === void 0) { + options = {}; + } + if (this._participants.length === 0) { + return null; + } + var redrawable = (0, Utilities_1.isNullOrUndefined)(options.redrawable) ? true : options.redrawable; + var pickable = []; + this._participants.forEach(function(_a) { + var participant = _a.participant, tickets = _a.tickets; + for (var ticketCount = 0; ticketCount < tickets; ticketCount++) { + pickable.push(participant); + } + }); + var random; + if (this._customRandom) { + random = this._customRandom(); + if (typeof random !== "number" || random < 0 || random >= 1) { + throw new Error("the 'random' function provided did not return a number between 0 (inclusive) and 1"); + } + } else { + random = Math.random(); + } + var winner = pickable[Math.floor(random * pickable.length)]; + if (!redrawable) { + this.remove(winner, 1); + } + return winner; + }; + Lotto3.prototype.drawMultiple = function(tickets, options) { + if (options === void 0) { + options = {}; + } + var uniqueResults = (0, Utilities_1.isNullOrUndefined)(options.unique) ? false : options.unique; + if (tickets === 0) { + return []; + } + if (!(0, Utilities_1.isNaturalNumber)(tickets)) { + throw new Error("tickets value must be a natural number"); + } + var result = []; + while (result.length < tickets && this._participants.length > 0) { + result.push(this.draw(options)); + } + if (uniqueResults) { + var unique = []; + for (var _i = 0, result_1 = result; _i < result_1.length; _i++) { + var participant = result_1[_i]; + if (unique.indexOf(participant) === -1) { + unique.push(participant); + } + } + result = unique; + } + return result; + }; + return Lotto3; + }(); + exports.Lotto = Lotto2; + } + }); + + // node_modules/lotto-draw/dist/createLotto.js + var require_createLotto = __commonJS({ + "node_modules/lotto-draw/dist/createLotto.js"(exports) { + "use strict"; + Object.defineProperty(exports, "__esModule", { value: true }); + exports.createLotto = void 0; + var Lotto_1 = require_Lotto(); + function createLotto2(participantsOrOptions) { + if (!participantsOrOptions) { + return new Lotto_1.Lotto(); + } + if (Array.isArray(participantsOrOptions)) { + var participants = participantsOrOptions; + var lotto_1 = new Lotto_1.Lotto(); + participants.forEach(function(_a) { + var participant = _a[0], tokens = _a[1]; + return lotto_1.add(participant, tokens); + }); + return lotto_1; + } else { + var random = participantsOrOptions.random, participants = participantsOrOptions.participants; + var lotto_2 = new Lotto_1.Lotto(random); + if (participants) { + participants.forEach(function(_a) { + var participant = _a[0], tokens = _a[1]; + return lotto_2.add(participant, tokens); + }); + } + return lotto_2; + } + } + exports.createLotto = createLotto2; + } + }); + + // node_modules/lotto-draw/dist/index.js + var require_dist = __commonJS({ + "node_modules/lotto-draw/dist/index.js"(exports) { + "use strict"; + Object.defineProperty(exports, "__esModule", { value: true }); + var createLotto_1 = require_createLotto(); + exports.default = createLotto_1.createLotto; + } + }); + // src/index.ts var src_exports = {}; __export(src_exports, { @@ -73,6 +298,9 @@ var mistreevous = (() => { function isInteger(value) { return typeof value === "number" && Math.floor(value) === value; } + function isNullOrUndefined(value) { + return typeof value === "undefined" || value === null; + } // src/mdsl/MDSLUtilities.ts function popAndCheck(tokens, expected) { @@ -219,6 +447,9 @@ var mistreevous = (() => { const rootNodes = []; const pushNode = (node) => { if (isRootNode(node)) { + if (treeStacks[treeStacks.length - 1]?.length) { + throw new Error("a root node cannot be the child of another node"); + } rootNodes.push(node); treeStacks.push([node]); return; @@ -242,13 +473,15 @@ var mistreevous = (() => { } }; const popNode = () => { + let poppedNode = null; const topTreeStack = treeStacks[treeStacks.length - 1]; if (topTreeStack.length) { - topTreeStack.pop(); + poppedNode = topTreeStack.pop(); } if (!topTreeStack.length) { treeStacks.pop(); } + return poppedNode; }; while (tokens.length) { const token = tokens.shift(); @@ -310,7 +543,10 @@ var mistreevous = (() => { break; } case "}": { - popNode(); + const poppedNode = popNode(); + if (poppedNode) { + validatePoppedNode(poppedNode); + } break; } default: { @@ -370,8 +606,19 @@ var mistreevous = (() => { }); if (nodeArguments.length === 1) { node.iterations = nodeArguments[0].value; + if (node.iterations < 0) { + throw new Error("a repeat node must have a positive number of iterations if defined"); + } } else if (nodeArguments.length === 2) { node.iterations = [nodeArguments[0].value, nodeArguments[1].value]; + if (node.iterations[0] < 0 || node.iterations[1] < 0) { + throw new Error("a repeat node must have a positive minimum and maximum iteration count if defined"); + } + if (node.iterations[0] > node.iterations[1]) { + throw new Error( + "a repeat node must not have a minimum iteration count that exceeds the maximum iteration count" + ); + } } else { throw new Error("invalid number of repeat node iteration count arguments defined"); } @@ -389,8 +636,19 @@ var mistreevous = (() => { }); if (nodeArguments.length === 1) { node.attempts = nodeArguments[0].value; + if (node.attempts < 0) { + throw new Error("a retry node must have a positive number of attempts if defined"); + } } else if (nodeArguments.length === 2) { node.attempts = [nodeArguments[0].value, nodeArguments[1].value]; + if (node.attempts[0] < 0 || node.attempts[1] < 0) { + throw new Error("a retry node must have a positive minimum and maximum attempt count if defined"); + } + if (node.attempts[0] > node.attempts[1]) { + throw new Error( + "a retry node must not have a minimum attempt count that exceeds the maximum attempt count" + ); + } } else { throw new Error("invalid number of retry node attempt count arguments defined"); } @@ -479,8 +737,17 @@ var mistreevous = (() => { }); if (nodeArguments.length === 1) { node.duration = nodeArguments[0].value; + if (node.duration < 0) { + throw new Error("a wait node must have a positive duration"); + } } else if (nodeArguments.length === 2) { node.duration = [nodeArguments[0].value, nodeArguments[1].value]; + if (node.duration[0] < 0 || node.duration[1] < 0) { + throw new Error("a wait node must have a positive minimum and maximum duration"); + } + if (node.duration[0] > node.duration[1]) { + throw new Error("a wait node must not have a minimum duration that exceeds the maximum duration"); + } } else if (nodeArguments.length > 2) { throw new Error("invalid number of wait node duration arguments defined"); } @@ -494,6 +761,14 @@ var mistreevous = (() => { } return { type: "branch", ref: nodeArguments[0].value }; } + function validatePoppedNode(node) { + if (isDecoratorNode(node) && isNullOrUndefined(node.child)) { + throw new Error(`a ${node.type} node must have a single child node defined`); + } + if (isCompositeNode(node) && !node.children?.length) { + throw new Error(`a ${node.type} node must have at least a single child node defined`); + } + } // src/BehaviourTreeDefinitionValidator.ts function validateDefinition(definition) { @@ -729,7 +1004,23 @@ var mistreevous = (() => { `expected array containing two integer values for 'iterations' property if defined for repeat node at depth '${depth}'` ); } - } else if (!isInteger(definition.iterations)) { + if (definition.iterations[0] < 0 || definition.iterations[1] < 0) { + throw new Error( + `expected positive minimum and maximum iterations count for 'iterations' property if defined for repeat node at depth '${depth}'` + ); + } + if (definition.iterations[0] > definition.iterations[1]) { + throw new Error( + `expected minimum iterations count that does not exceed the maximum iterations count for 'iterations' property if defined for repeat node at depth '${depth}'` + ); + } + } else if (isInteger(definition.iterations)) { + if (definition.iterations < 0) { + throw new Error( + `expected positive iterations count for 'iterations' property if defined for repeat node at depth '${depth}'` + ); + } + } else { throw new Error( `expected integer value or array containing two integer values for 'iterations' property if defined for repeat node at depth '${depth}'` ); @@ -753,7 +1044,23 @@ var mistreevous = (() => { `expected array containing two integer values for 'attempts' property if defined for retry node at depth '${depth}'` ); } - } else if (!isInteger(definition.attempts)) { + if (definition.attempts[0] < 0 || definition.attempts[1] < 0) { + throw new Error( + `expected positive minimum and maximum attempts count for 'attempts' property if defined for retry node at depth '${depth}'` + ); + } + if (definition.attempts[0] > definition.attempts[1]) { + throw new Error( + `expected minimum attempts count that does not exceed the maximum attempts count for 'attempts' property if defined for retry node at depth '${depth}'` + ); + } + } else if (isInteger(definition.attempts)) { + if (definition.attempts < 0) { + throw new Error( + `expected positive attempts count for 'attempts' property if defined for retry node at depth '${depth}'` + ); + } + } else { throw new Error( `expected integer value or array containing two integer values for 'attempts' property if defined for retry node at depth '${depth}'` ); @@ -820,7 +1127,23 @@ var mistreevous = (() => { `expected array containing two integer values for 'duration' property if defined for wait node at depth '${depth}'` ); } - } else if (!isInteger(definition.duration)) { + if (definition.duration[0] < 0 || definition.duration[1] < 0) { + throw new Error( + `expected positive minimum and maximum duration for 'duration' property if defined for wait node at depth '${depth}'` + ); + } + if (definition.duration[0] > definition.duration[1]) { + throw new Error( + `expected minimum duration value that does not exceed the maximum duration value for 'duration' property if defined for wait node at depth '${depth}'` + ); + } + } else if (isInteger(definition.duration)) { + if (definition.duration < 0) { + throw new Error( + `expected positive duration value for 'duration' property if defined for wait node at depth '${depth}'` + ); + } + } else { throw new Error( `expected integer value or array containing two integer values for 'duration' property if defined for wait node at depth '${depth}'` ); @@ -991,6 +1314,159 @@ var mistreevous = (() => { return S4() + S4() + "-" + S4() + "-" + S4() + "-" + S4() + "-" + S4() + S4() + S4(); } + // src/nodes/composite/Composite.ts + var Composite = class extends Node { + constructor(type, attributes, children) { + super(type, attributes, []); + this.children = children; + } + isLeafNode = () => false; + getChildren = () => this.children; + reset = () => { + this.setState("mistreevous.ready" /* READY */); + this.getChildren().forEach((child) => child.reset()); + }; + abort = (agent) => { + if (!this.is("mistreevous.running" /* RUNNING */)) { + return; + } + this.getChildren().forEach((child) => child.abort(agent)); + this.reset(); + this.getAttribute("exit")?.callAgentFunction(agent, false, true); + }; + }; + + // src/nodes/composite/Parallel.ts + var Parallel = class extends Composite { + constructor(attributes, children) { + super("parallel", attributes, children); + } + onUpdate(agent, options) { + let succeededCount = 0; + let hasChildFailed = false; + for (const child of this.children) { + if (child.getState() === "mistreevous.ready" /* READY */ || child.getState() === "mistreevous.running" /* RUNNING */) { + child.update(agent, options); + } + if (child.getState() === "mistreevous.succeeded" /* SUCCEEDED */) { + succeededCount++; + continue; + } + if (child.getState() === "mistreevous.failed" /* FAILED */) { + hasChildFailed = true; + break; + } + if (child.getState() !== "mistreevous.running" /* RUNNING */) { + throw new Error("child node was not in an expected state."); + } + } + if (hasChildFailed) { + this.setState("mistreevous.failed" /* FAILED */); + for (const child of this.children) { + if (child.getState() === "mistreevous.running" /* RUNNING */) { + child.abort(agent); + } + } + } else { + this.setState(succeededCount === this.children.length ? "mistreevous.succeeded" /* SUCCEEDED */ : "mistreevous.running" /* RUNNING */); + } + } + getName = () => "PARALLEL"; + }; + + // src/nodes/composite/Selector.ts + var Selector = class extends Composite { + constructor(attributes, children) { + super("selector", attributes, children); + this.children = children; + } + onUpdate(agent, options) { + for (const child of this.children) { + if (child.getState() === "mistreevous.ready" /* READY */ || child.getState() === "mistreevous.running" /* RUNNING */) { + child.update(agent, options); + } + if (child.getState() === "mistreevous.succeeded" /* SUCCEEDED */) { + this.setState("mistreevous.succeeded" /* SUCCEEDED */); + return; + } + if (child.getState() === "mistreevous.failed" /* FAILED */) { + if (this.children.indexOf(child) === this.children.length - 1) { + this.setState("mistreevous.failed" /* FAILED */); + return; + } else { + continue; + } + } + if (child.getState() === "mistreevous.running" /* RUNNING */) { + this.setState("mistreevous.running" /* RUNNING */); + return; + } + throw new Error("child node was not in an expected state."); + } + } + getName = () => "SELECTOR"; + }; + + // src/nodes/composite/Sequence.ts + var Sequence = class extends Composite { + constructor(attributes, children) { + super("sequence", attributes, children); + this.children = children; + } + onUpdate(agent, options) { + for (const child of this.children) { + if (child.getState() === "mistreevous.ready" /* READY */ || child.getState() === "mistreevous.running" /* RUNNING */) { + child.update(agent, options); + } + if (child.getState() === "mistreevous.succeeded" /* SUCCEEDED */) { + if (this.children.indexOf(child) === this.children.length - 1) { + this.setState("mistreevous.succeeded" /* SUCCEEDED */); + return; + } else { + continue; + } + } + if (child.getState() === "mistreevous.failed" /* FAILED */) { + this.setState("mistreevous.failed" /* FAILED */); + return; + } + if (child.getState() === "mistreevous.running" /* RUNNING */) { + this.setState("mistreevous.running" /* RUNNING */); + return; + } + throw new Error("child node was not in an expected state."); + } + } + getName = () => "SEQUENCE"; + }; + + // src/nodes/composite/Lotto.ts + var import_lotto_draw = __toESM(require_dist()); + var Lotto = class extends Composite { + constructor(attributes, weights, children) { + super("lotto", attributes, children); + this.weights = weights; + } + selectedChild; + onUpdate(agent, options) { + if (this.is("mistreevous.ready" /* READY */)) { + const lottoDraw = (0, import_lotto_draw.default)({ + random: options.random, + participants: this.children.map((child, index) => [child, this.weights?.[index] || 1]) + }); + this.selectedChild = lottoDraw.draw() || void 0; + } + if (!this.selectedChild) { + throw new Error("failed to update lotto node as it has no active child"); + } + if (this.selectedChild.getState() === "mistreevous.ready" /* READY */ || this.selectedChild.getState() === "mistreevous.running" /* RUNNING */) { + this.selectedChild.update(agent, options); + } + this.setState(this.selectedChild.getState()); + } + getName = () => this.weights ? `LOTTO [${this.weights.join(",")}]` : "LOTTO"; + }; + // src/nodes/decorator/Decorator.ts var Decorator = class extends Node { constructor(type, attributes, child) { @@ -1013,6 +1489,188 @@ var mistreevous = (() => { }; }; + // src/nodes/decorator/Fail.ts + var Fail = class extends Decorator { + constructor(attributes, child) { + super("fail", attributes, child); + } + onUpdate(agent, options) { + if (this.child.getState() === "mistreevous.ready" /* READY */ || this.child.getState() === "mistreevous.running" /* RUNNING */) { + this.child.update(agent, options); + } + switch (this.child.getState()) { + case "mistreevous.running" /* RUNNING */: + this.setState("mistreevous.running" /* RUNNING */); + break; + case "mistreevous.succeeded" /* SUCCEEDED */: + case "mistreevous.failed" /* FAILED */: + this.setState("mistreevous.failed" /* FAILED */); + break; + default: + this.setState("mistreevous.ready" /* READY */); + } + } + getName = () => "FAIL"; + }; + + // src/nodes/decorator/Flip.ts + var Flip = class extends Decorator { + constructor(attributes, child) { + super("flip", attributes, child); + } + onUpdate(agent, options) { + if (this.child.getState() === "mistreevous.ready" /* READY */ || this.child.getState() === "mistreevous.running" /* RUNNING */) { + this.child.update(agent, options); + } + switch (this.child.getState()) { + case "mistreevous.running" /* RUNNING */: + this.setState("mistreevous.running" /* RUNNING */); + break; + case "mistreevous.succeeded" /* SUCCEEDED */: + this.setState("mistreevous.failed" /* FAILED */); + break; + case "mistreevous.failed" /* FAILED */: + this.setState("mistreevous.succeeded" /* SUCCEEDED */); + break; + default: + this.setState("mistreevous.ready" /* READY */); + } + } + getName = () => "FLIP"; + }; + + // src/nodes/decorator/Repeat.ts + var Repeat = class extends Decorator { + constructor(attributes, iterations, iterationsMin, iterationsMax, child) { + super("repeat", attributes, child); + this.iterations = iterations; + this.iterationsMin = iterationsMin; + this.iterationsMax = iterationsMax; + } + targetIterationCount = null; + currentIterationCount = 0; + onUpdate(agent, options) { + if (this.is("mistreevous.ready" /* READY */)) { + this.child.reset(); + this.currentIterationCount = 0; + this.setTargetIterationCount(options); + } + if (this.canIterate()) { + this.setState("mistreevous.running" /* RUNNING */); + if (this.child.getState() === "mistreevous.succeeded" /* SUCCEEDED */) { + this.child.reset(); + } + this.child.update(agent, options); + if (this.child.getState() === "mistreevous.failed" /* FAILED */) { + this.setState("mistreevous.failed" /* FAILED */); + return; + } else if (this.child.getState() === "mistreevous.succeeded" /* SUCCEEDED */) { + this.currentIterationCount += 1; + } + } else { + this.setState("mistreevous.succeeded" /* SUCCEEDED */); + } + } + getName = () => { + if (this.iterations !== null) { + return `REPEAT ${this.iterations}x`; + } else if (this.iterationsMin !== null && this.iterationsMax !== null) { + return `REPEAT ${this.iterationsMin}x-${this.iterationsMax}x`; + } else { + return "REPEAT"; + } + }; + reset = () => { + this.setState("mistreevous.ready" /* READY */); + this.currentIterationCount = 0; + this.child.reset(); + }; + canIterate = () => { + if (this.targetIterationCount !== null) { + return this.currentIterationCount < this.targetIterationCount; + } + return true; + }; + setTargetIterationCount = (options) => { + if (this.iterations !== null) { + this.targetIterationCount = this.iterations; + } else if (this.iterationsMin !== null && this.iterationsMax !== null) { + const random = typeof options.random === "function" ? options.random : Math.random; + this.targetIterationCount = Math.floor( + random() * (this.iterationsMax - this.iterationsMin + 1) + this.iterationsMin + ); + } else { + this.targetIterationCount = null; + } + }; + }; + + // src/nodes/decorator/Retry.ts + var Retry = class extends Decorator { + constructor(attributes, attempts, attemptsMin, attemptsMax, child) { + super("retry", attributes, child); + this.attempts = attempts; + this.attemptsMin = attemptsMin; + this.attemptsMax = attemptsMax; + } + targetAttemptCount = null; + currentAttemptCount = 0; + onUpdate(agent, options) { + if (this.is("mistreevous.ready" /* READY */)) { + this.child.reset(); + this.currentAttemptCount = 0; + this.setTargetAttemptCount(options); + } + if (this.canAttempt()) { + this.setState("mistreevous.running" /* RUNNING */); + if (this.child.getState() === "mistreevous.failed" /* FAILED */) { + this.child.reset(); + } + this.child.update(agent, options); + if (this.child.getState() === "mistreevous.succeeded" /* SUCCEEDED */) { + this.setState("mistreevous.succeeded" /* SUCCEEDED */); + return; + } else if (this.child.getState() === "mistreevous.failed" /* FAILED */) { + this.currentAttemptCount += 1; + } + } else { + this.setState("mistreevous.failed" /* FAILED */); + } + } + getName = () => { + if (this.attempts !== null) { + return `RETRY ${this.attempts}x`; + } else if (this.attemptsMin !== null && this.attemptsMax !== null) { + return `RETRY ${this.attemptsMin}x-${this.attemptsMax}x`; + } else { + return "RETRY"; + } + }; + reset = () => { + this.setState("mistreevous.ready" /* READY */); + this.currentAttemptCount = 0; + this.child.reset(); + }; + canAttempt = () => { + if (this.targetAttemptCount !== null) { + return this.currentAttemptCount < this.targetAttemptCount; + } + return true; + }; + setTargetAttemptCount = (options) => { + if (this.attempts !== null) { + this.targetAttemptCount = this.attempts; + } else if (this.attemptsMin !== null && this.attemptsMax !== null) { + const random = typeof options.random === "function" ? options.random : Math.random; + this.targetAttemptCount = Math.floor( + random() * (this.attemptsMax - this.attemptsMin + 1) + this.attemptsMin + ); + } else { + this.targetAttemptCount = null; + } + }; + }; + // src/nodes/decorator/Root.ts var Root = class extends Decorator { constructor(attributes, child) { @@ -1027,6 +1685,178 @@ var mistreevous = (() => { getName = () => "ROOT"; }; + // src/nodes/decorator/Succeed.ts + var Succeed = class extends Decorator { + constructor(attributes, child) { + super("succeed", attributes, child); + } + onUpdate(agent, options) { + if (this.child.getState() === "mistreevous.ready" /* READY */ || this.child.getState() === "mistreevous.running" /* RUNNING */) { + this.child.update(agent, options); + } + switch (this.child.getState()) { + case "mistreevous.running" /* RUNNING */: + this.setState("mistreevous.running" /* RUNNING */); + break; + case "mistreevous.succeeded" /* SUCCEEDED */: + case "mistreevous.failed" /* FAILED */: + this.setState("mistreevous.succeeded" /* SUCCEEDED */); + break; + default: + this.setState("mistreevous.ready" /* READY */); + } + } + getName = () => "SUCCEED"; + }; + + // src/nodes/leaf/Leaf.ts + var Leaf = class extends Node { + isLeafNode = () => true; + }; + + // src/nodes/leaf/Action.ts + var Action = class extends Leaf { + constructor(attributes, actionName, actionArguments) { + super("action", attributes, actionArguments); + this.actionName = actionName; + this.actionArguments = actionArguments; + } + isUsingUpdatePromise = false; + updatePromiseStateResult = null; + onUpdate(agent, options) { + if (this.isUsingUpdatePromise) { + if (this.updatePromiseStateResult) { + this.setState(this.updatePromiseStateResult); + } + return; + } + const actionFuncInvoker = Lookup.getFuncInvoker(agent, this.actionName); + if (actionFuncInvoker === null) { + throw new Error( + `cannot update action node as the action '${this.actionName}' function is not defined on the agent and has not been registered` + ); + } + const updateResult = actionFuncInvoker(this.actionArguments); + if (updateResult instanceof Promise) { + updateResult.then( + (result) => { + if (!this.isUsingUpdatePromise) { + return; + } + if (result !== "mistreevous.succeeded" /* SUCCEEDED */ && result !== "mistreevous.failed" /* FAILED */) { + throw new Error( + "action node promise resolved with an invalid value, expected a State.SUCCEEDED or State.FAILED value to be returned" + ); + } + this.updatePromiseStateResult = result; + }, + (reason) => { + if (!this.isUsingUpdatePromise) { + return; + } + throw new Error(reason); + } + ); + this.setState("mistreevous.running" /* RUNNING */); + this.isUsingUpdatePromise = true; + } else { + this.validateUpdateResult(updateResult); + this.setState(updateResult || "mistreevous.running" /* RUNNING */); + } + } + getName = () => this.actionName; + reset = () => { + this.setState("mistreevous.ready" /* READY */); + this.isUsingUpdatePromise = false; + this.updatePromiseStateResult = null; + }; + validateUpdateResult = (result) => { + switch (result) { + case "mistreevous.succeeded" /* SUCCEEDED */: + case "mistreevous.failed" /* FAILED */: + case void 0: + return; + default: + throw new Error( + `action '${this.actionName}' 'onUpdate' returned an invalid response, expected an optional State.SUCCEEDED or State.FAILED value to be returned` + ); + } + }; + }; + + // src/nodes/leaf/Condition.ts + var Condition = class extends Leaf { + constructor(attributes, conditionName, conditionArguments) { + super("condition", attributes, conditionArguments); + this.conditionName = conditionName; + this.conditionArguments = conditionArguments; + } + onUpdate(agent, options) { + const conditionFuncInvoker = Lookup.getFuncInvoker(agent, this.conditionName); + if (conditionFuncInvoker === null) { + throw new Error( + `cannot update condition node as the condition '${this.conditionName}' function is not defined on the agent and has not been registered` + ); + } + this.setState(!!conditionFuncInvoker(this.conditionArguments) ? "mistreevous.succeeded" /* SUCCEEDED */ : "mistreevous.failed" /* FAILED */); + } + getName = () => this.conditionName; + }; + + // src/nodes/leaf/Wait.ts + var Wait = class extends Leaf { + constructor(attributes, duration, durationMin, durationMax) { + super("wait", attributes, []); + this.duration = duration; + this.durationMin = durationMin; + this.durationMax = durationMax; + } + initialUpdateTime = 0; + totalDuration = null; + waitedDuration = 0; + onUpdate(agent, options) { + if (this.is("mistreevous.ready" /* READY */)) { + this.initialUpdateTime = new Date().getTime(); + this.waitedDuration = 0; + if (this.duration !== null) { + this.totalDuration = this.duration; + } else if (this.durationMin !== null && this.durationMax !== null) { + const random = typeof options.random === "function" ? options.random : Math.random; + this.totalDuration = Math.floor( + random() * (this.durationMax - this.durationMin + 1) + this.durationMin + ); + } else { + this.totalDuration = null; + } + this.setState("mistreevous.running" /* RUNNING */); + } + if (this.totalDuration === null) { + return; + } + if (typeof options.getDeltaTime === "function") { + const deltaTime = options.getDeltaTime(); + if (typeof deltaTime !== "number" || isNaN(deltaTime)) { + throw new Error("The delta time must be a valid number and not NaN."); + } + this.waitedDuration += deltaTime * 1e3; + } else { + this.waitedDuration = new Date().getTime() - this.initialUpdateTime; + } + if (this.waitedDuration >= this.totalDuration) { + this.setState("mistreevous.succeeded" /* SUCCEEDED */); + } + } + getName = () => { + if (this.duration !== null) { + return `WAIT ${this.duration}ms`; + } else if (this.durationMin !== null && this.durationMax !== null) { + return `WAIT ${this.durationMin}ms-${this.durationMax}ms`; + } else { + return "WAIT"; + } + }; + }; + // src/attributes/Attribute.ts var Attribute = class { constructor(type, args) { @@ -1154,17 +1984,93 @@ var mistreevous = (() => { function buildRootNode(definition) { const rootNodeDefinitionMap = createRootNodeDefinitionMap(definition); validateBranchSubtreeLinks(definition, true); - const rootNode = nodeFactory(rootNodeDefinitionMap[MAIN_ROOT_NODE_KEY]); + const rootNode = nodeFactory(rootNodeDefinitionMap[MAIN_ROOT_NODE_KEY], rootNodeDefinitionMap); applyLeafNodeGuardPaths(rootNode); return rootNode; } - function nodeFactory(definition) { + function nodeFactory(definition, rootNodeDefinitionMap) { const attributes = nodeAttributesFactory(definition); switch (definition.type) { case "root": - return new Root(attributes, nodeFactory(definition.child)); - default: - throw new Error(`unexpected node type of '${definition.type}'`); + return new Root(attributes, nodeFactory(definition.child, rootNodeDefinitionMap)); + case "repeat": + let iterations = null; + let iterationsMin = null; + let iterationsMax = null; + if (Array.isArray(definition.iterations)) { + iterationsMin = definition.iterations[0]; + iterationsMax = definition.iterations[1]; + } else if (isInteger(definition.iterations)) { + iterations = definition.iterations; + } + return new Repeat( + attributes, + iterations, + iterationsMin, + iterationsMax, + nodeFactory(definition.child, rootNodeDefinitionMap) + ); + case "retry": + let attempts = null; + let attemptsMin = null; + let attemptsMax = null; + if (Array.isArray(definition.attempts)) { + attemptsMin = definition.attempts[0]; + attemptsMax = definition.attempts[1]; + } else if (isInteger(definition.attempts)) { + attempts = definition.attempts; + } + return new Retry( + attributes, + attempts, + attemptsMin, + attemptsMax, + nodeFactory(definition.child, rootNodeDefinitionMap) + ); + case "flip": + return new Flip(attributes, nodeFactory(definition.child, rootNodeDefinitionMap)); + case "succeed": + return new Succeed(attributes, nodeFactory(definition.child, rootNodeDefinitionMap)); + case "fail": + return new Fail(attributes, nodeFactory(definition.child, rootNodeDefinitionMap)); + case "sequence": + return new Sequence( + attributes, + definition.children.map((child) => nodeFactory(child, rootNodeDefinitionMap)) + ); + case "selector": + return new Selector( + attributes, + definition.children.map((child) => nodeFactory(child, rootNodeDefinitionMap)) + ); + case "parallel": + return new Parallel( + attributes, + definition.children.map((child) => nodeFactory(child, rootNodeDefinitionMap)) + ); + case "lotto": + return new Lotto( + attributes, + definition.weights, + definition.children.map((child) => nodeFactory(child, rootNodeDefinitionMap)) + ); + case "branch": + return nodeFactory(rootNodeDefinitionMap[definition.ref].child, rootNodeDefinitionMap); + case "action": + return new Action(attributes, definition.call, definition.args || []); + case "condition": + return new Condition(attributes, definition.call, definition.args || []); + case "wait": + let duration = null; + let durationMin = null; + let durationMax = null; + if (Array.isArray(definition.duration)) { + durationMin = definition.duration[0]; + durationMax = definition.duration[1]; + } else if (isInteger(definition.duration)) { + duration = definition.duration; + } + return new Wait(attributes, duration, durationMin, durationMax); } } function nodeAttributesFactory(definition) { diff --git a/dist/bundle.js.map b/dist/bundle.js.map index 99b85ef..deae203 100644 --- a/dist/bundle.js.map +++ b/dist/bundle.js.map @@ -1,7 +1,7 @@ { "version": 3, - "sources": ["../src/index.ts", "../src/State.ts", "../src/BehaviourTreeDefinitionUtilities.ts", "../src/mdsl/MDSLUtilities.ts", "../src/mdsl/MDSLNodeArgumentParser.ts", "../src/mdsl/MDSLNodeAttributeParser.ts", "../src/mdsl/MDSLDefinitionParser.ts", "../src/BehaviourTreeDefinitionValidator.ts", "../src/Lookup.ts", "../src/attributes/guards/GuardUnsatisifedException.ts", "../src/attributes/guards/GuardPath.ts", "../src/nodes/Node.ts", "../src/nodes/decorator/Decorator.ts", "../src/nodes/decorator/Root.ts", "../src/attributes/Attribute.ts", "../src/attributes/guards/Guard.ts", "../src/attributes/guards/While.ts", "../src/attributes/guards/Until.ts", "../src/attributes/callbacks/Callback.ts", "../src/attributes/callbacks/Entry.ts", "../src/attributes/callbacks/Step.ts", "../src/attributes/callbacks/Exit.ts", "../src/BehaviourTreeBuilder.ts", "../src/BehaviourTree.ts"], - "sourcesContent": ["import State from \"./State\";\nimport { validateDefinition } from \"./BehaviourTreeDefinitionValidator\";\nimport { convertMDSLToJSON } from \"./mdsl/MDSLDefinitionParser\";\nimport { BehaviourTree, FlattenedTreeNode } from \"./BehaviourTree\";\n\nexport { BehaviourTree, State, convertMDSLToJSON, validateDefinition };\nexport type { FlattenedTreeNode };\n", "/**\n * Enumeration of node state types.\n */\nexport enum State {\n READY = \"mistreevous.ready\",\n RUNNING = \"mistreevous.running\",\n SUCCEEDED = \"mistreevous.succeeded\",\n FAILED = \"mistreevous.failed\"\n}\n\nexport { State as default };\n\nexport type CompleteState = State.SUCCEEDED | State.FAILED;\nexport type AnyState = State.READY | State.RUNNING | CompleteState;\n", "import {\n NodeDefinition,\n RootNodeDefinition,\n DecoratorNodeDefinition,\n CompositeNodeDefinition,\n AnyNodeDefinition,\n BranchNodeDefinition\n} from \"./BehaviourTreeDefinition\";\n\n/**\n * A type guard function that returns true if the specified node satisfies the RootNodeDefinition type.\n * @param node The node.\n * @returns A value of true if the specified node satisfies the RootNodeDefinition type.\n */\nexport function isRootNode(node: NodeDefinition): node is RootNodeDefinition {\n return node.type === \"root\";\n}\n\n/**\n * A type guard function that returns true if the specified node satisfies the BranchNodeDefinition type.\n * @param node The node.\n * @returns A value of true if the specified node satisfies the BranchNodeDefinition type.\n */\nexport function isBranchNode(node: NodeDefinition): node is BranchNodeDefinition {\n return node.type === \"branch\";\n}\n\n/**\n * A type guard function that returns true if the specified node satisfies the NodeDefinition type.\n * @param node The node.\n * @returns A value of true if the specified node satisfies the NodeDefinition type.\n */\nexport function isLeafNode(node: NodeDefinition): node is NodeDefinition {\n return [\"branch\", \"action\", \"condition\", \"wait\"].includes(node.type);\n}\n\n/**\n * A type guard function that returns true if the specified node satisfies the DecoratorNodeDefinition type.\n * @param node The node.\n * @returns A value of true if the specified node satisfies the DecoratorNodeDefinition type.\n */\nexport function isDecoratorNode(node: NodeDefinition): node is DecoratorNodeDefinition {\n return [\"root\", \"repeat\", \"retry\", \"flip\", \"succeed\", \"fail\"].includes(node.type);\n}\n\n/**\n * A type guard function that returns true if the specified node satisfies the CompositeNodeDefinition type.\n * @param node The node.\n * @returns A value of true if the specified node satisfies the CompositeNodeDefinition type.\n */\nexport function isCompositeNode(node: NodeDefinition): node is CompositeNodeDefinition {\n return [\"sequence\", \"selector\", \"lotto\", \"parallel\"].includes(node.type);\n}\n\n/**\n * Flatten a node definition into an array of all of its nested node definitions.\n * @param nodeDefinition The node definition to flatten.\n * @returns An array of all of nested node definitions.\n */\nexport function flattenDefinition(nodeDefinition: AnyNodeDefinition): AnyNodeDefinition[] {\n const nodes: AnyNodeDefinition[] = [];\n\n const processNode = (currentNodeDefinition: AnyNodeDefinition) => {\n nodes.push(currentNodeDefinition);\n\n if (isCompositeNode(currentNodeDefinition)) {\n currentNodeDefinition.children.forEach(processNode);\n } else if (isDecoratorNode(currentNodeDefinition)) {\n processNode(currentNodeDefinition.child);\n }\n };\n\n processNode(nodeDefinition);\n\n return nodes;\n}\n\n/**\n * Determines whether the passed value is an integer.\n * @param value The value to check.\n * @returns Whether the passed value is an integer.\n */\nexport function isInteger(value: unknown): boolean {\n return typeof value === \"number\" && Math.floor(value) === value;\n}\n", "/**\n * A type defining an object that holds a reference to substitued string literals parsed from the definition.\n */\nexport type StringLiteralPlaceholders = { [key: string]: string };\n\n/**\n * Pop the next raw token from the specified array of tokens and throw an error if it wasn't the expected one.\n * @param tokens The array of tokens.\n * @param expected An optional string or array or items, one of which must match the next popped token.\n * @returns The popped token.\n */\nexport function popAndCheck(tokens: string[], expected?: string | string[]): string {\n // Get and remove the next token.\n const popped = tokens.shift();\n\n // We were expecting another token but there aren't any.\n if (popped === undefined) {\n throw new Error(\"unexpected end of definition\");\n }\n\n // Do we have an expected token/tokens array?\n if (expected != undefined) {\n // Get an array of expected values, if the popped token matches any then we are all good.\n const expectedValues = typeof expected === \"string\" ? [expected] : expected;\n\n // Check whether the popped token matches at least one of our expected items.\n var tokenMatchesExpectation = expectedValues.some((item) => popped.toUpperCase() === item.toUpperCase());\n\n // Throw an error if the popped token didn't match any of our expected items.\n if (!tokenMatchesExpectation) {\n const expectationString = expectedValues.map((item) => \"'\" + item + \"'\").join(\" or \");\n throw new Error(\"unexpected token found. Expected \" + expectationString + \" but got '\" + popped + \"'\");\n }\n }\n\n // Return the popped token.\n return popped;\n}\n\n/**\n * Swaps out any node/attribute argument string literals with placeholders.\n * @param definition The definition.\n * @returns An object containing a mapping of placeholders to original string values as well as the processed definition string.\n */\nexport function substituteStringLiterals(definition: string): {\n placeholders: StringLiteralPlaceholders;\n processedDefinition: string;\n} {\n // Create an object to hold the mapping of placeholders to original string values.\n const placeholders: StringLiteralPlaceholders = {};\n\n // Replace any string literals wrapped with double quotes in our definition with placeholders to be processed later.\n const processedDefinition = definition.replace(/\\\"(\\\\.|[^\"\\\\])*\\\"/g, (match) => {\n var strippedMatch = match.substring(1, match.length - 1);\n var placeholder = Object.keys(placeholders).find((key) => placeholders[key] === strippedMatch);\n\n // If we have no existing string literal match then create a new placeholder.\n if (!placeholder) {\n placeholder = `@@${Object.keys(placeholders).length}@@`;\n placeholders[placeholder] = strippedMatch;\n }\n\n return placeholder;\n });\n\n return { placeholders, processedDefinition };\n}\n\n/**\n * Parse the tree definition into an array of raw tokens.\n * @param definition The definition.\n * @returns An array of tokens parsed from the definition.\n */\nexport function parseTokensFromDefinition(definition: string): string[] {\n // Add some space around various important characters so that they can be plucked out easier as individual tokens.\n definition = definition.replace(/\\(/g, \" ( \");\n definition = definition.replace(/\\)/g, \" ) \");\n definition = definition.replace(/\\{/g, \" { \");\n definition = definition.replace(/\\}/g, \" } \");\n definition = definition.replace(/\\]/g, \" ] \");\n definition = definition.replace(/\\[/g, \" [ \");\n definition = definition.replace(/\\,/g, \" , \");\n\n // Split the definition into raw token form and return it.\n return definition.replace(/\\s+/g, \" \").trim().split(\" \");\n}\n", "import { StringLiteralPlaceholders, popAndCheck } from \"./MDSLUtilities\";\n\n/**\n * A type representing any node function argument.\n */\ntype Argument = {\n /**\n * The argument value.\n */\n value: T;\n /**\n * The argument type, used for validation.\n */\n type: string;\n};\n\ntype NullArgument = Argument & {\n type: \"null\";\n};\n\ntype BooleanArgument = Argument & {\n type: \"boolean\";\n};\n\ntype NumberArgument = Argument & {\n type: \"number\";\n /**\n * A flag defining whether the number argument value is a valid integer. (used for validation)\n */\n isInteger: boolean;\n};\n\ntype StringPlaceholderArgument = Argument & {\n type: \"string\";\n};\n\ntype IdentifierArgument = Argument & {\n type: \"identifier\";\n};\n\n/**\n * A type representing a reference to any node function argument.\n */\ntype AnyArgument = NullArgument | BooleanArgument | NumberArgument | StringPlaceholderArgument | IdentifierArgument;\n\n/**\n * Parse an array of argument definitions from the specified tokens array.\n * @param tokens The array tokens to parse the argument definitions from.\n * @param stringArgumentPlaceholders The mapping of string literal node argument placeholders to original values.\n * @param argumentValidator The argument validator function.\n * @param validationFailedMessage The exception message to throw if argument validation fails.\n * @returns An array of argument definitions parsed from the specified tokens array.\n */\nexport function parseArgumentTokens(\n tokens: string[],\n stringArgumentPlaceholders: StringLiteralPlaceholders\n): AnyArgument[] {\n const argumentList: AnyArgument[] = [];\n\n // If the next token is not a '[' or '(' then we have no arguments to parse.\n if (![\"[\", \"(\"].includes(tokens[0])) {\n return argumentList;\n }\n\n // Any lists of arguments will always be wrapped in '[]' for node arguments or '()' for attribute arguments.\n // We are looking for a '[' or '(' opener that wraps the argument tokens and the relevant closer.\n const closingToken = popAndCheck(tokens, [\"[\", \"(\"]) === \"[\" ? \"]\" : \")\";\n\n const argumentListTokens: string[] = [];\n\n // Grab all tokens between the '[' and ']' or '(' and ')'.\n while (tokens.length && tokens[0] !== closingToken) {\n // The next token is part of our arguments list.\n argumentListTokens.push(tokens.shift()!);\n }\n\n // Validate the order of the argument tokens. Each token must either be a ',' or a single argument that satisfies the validator.\n argumentListTokens.forEach((token, index) => {\n // Get whether this token should be an actual argument.\n const shouldBeArgumentToken = !(index & 1);\n\n // If the current token should be an actual argument then validate it, otherwise it should be a ',' token.\n if (shouldBeArgumentToken) {\n // Get the argument definition.\n const argumentDefinition = getArgumentDefinition(token, stringArgumentPlaceholders);\n\n // This is a valid argument!\n argumentList.push(argumentDefinition);\n } else {\n // The current token should be a ',' token.\n if (token !== \",\") {\n throw new Error(`invalid argument list, expected ',' or ']' but got '${token}'`);\n }\n }\n });\n\n // The arguments list should terminate with a ']' or ')' token, depending on the opener.\n popAndCheck(tokens, closingToken);\n\n // Return the arguments.\n return argumentList;\n}\n\n/**\n * Gets an argument value definition.\n * @param token The argument token.\n * @param stringArgumentPlaceholders The mapping of string literal node argument placeholders to original values.\n * @returns An argument value definition.\n */\nfunction getArgumentDefinition(token: string, stringArgumentPlaceholders: StringLiteralPlaceholders): AnyArgument {\n // Check whether the token represents a null value.\n if (token === \"null\") {\n return {\n value: null,\n type: \"null\"\n } as NullArgument;\n }\n\n // Check whether the token represents a boolean value.\n if (token === \"true\" || token === \"false\") {\n return {\n value: token === \"true\",\n type: \"boolean\"\n } as BooleanArgument;\n }\n\n // Check whether the token represents a number value.\n // TODO: Relies on broken isNaN - see MDN.\n // if (!Number.isNaN(token)) {\n if (!isNaN(token as any)) {\n return {\n value: parseFloat(token),\n isInteger: parseFloat(token) === parseInt(token, 10),\n type: \"number\"\n } as NumberArgument;\n }\n\n // Check whether the token is a placeholder (e.g. @@0@@) representing a string literal.\n if (token.match(/^@@\\d+@@$/g)) {\n return {\n value: stringArgumentPlaceholders[token].replace('\\\\\"', '\"'),\n type: \"string\"\n } as StringPlaceholderArgument;\n }\n\n // The only remaining option is that the argument value is an identifier.\n return {\n value: token,\n type: \"identifier\"\n } as IdentifierArgument;\n}\n", "import { NodeAttributeDefinition } from \"../BehaviourTreeDefinition\";\nimport { parseArgumentTokens } from \"./MDSLNodeArgumentParser\";\nimport { StringLiteralPlaceholders } from \"./MDSLUtilities\";\n\n/**\n * A type defining the attribute definitions of a node.\n */\ntype NodeAttributes = {\n while?: NodeAttributeDefinition;\n until?: NodeAttributeDefinition;\n entry?: NodeAttributeDefinition;\n exit?: NodeAttributeDefinition;\n step?: NodeAttributeDefinition;\n};\n\n/**\n * Parse any node attribute definitions from the specified tokens array.\n * @param tokens The array of remaining tokens.\n * @param stringArgumentPlaceholders The mapping of string literal node argument placeholders to original values.\n * @returns An object of attribute definitions defined by any directly following tokens.\n */\nexport function parseAttributeTokens(\n tokens: string[],\n stringArgumentPlaceholders: StringLiteralPlaceholders\n): NodeAttributes {\n const nodeAttributeNames: (keyof NodeAttributes)[] = [\"while\", \"until\", \"entry\", \"exit\", \"step\"];\n\n // Create an object to hold any attributes found.\n const attributes: NodeAttributes = {};\n\n // Try to get the name of the attribute for the next token.\n let nextAttributeName = tokens[0]?.toLowerCase() as keyof NodeAttributes;\n\n // Pull attribute tokens as well as their arguments off of the tokens stack until we have no more.\n while (nodeAttributeNames.includes(nextAttributeName)) {\n // Check to make sure that we have not already created an attribute definition of this type.\n if (attributes[nextAttributeName]) {\n throw new Error(`duplicate attribute '${tokens[0].toUpperCase()}' found for node`);\n }\n\n // Remove the attribute name token from the array of tokens.\n tokens.shift();\n\n // Grab the attribute arguments, assuming the first to be an identifier.\n const [attributeCallIdentifier, ...attributeArguments] = parseArgumentTokens(\n tokens,\n stringArgumentPlaceholders\n );\n\n // The first attribute argument has to be an identifer, this will reference an agent function.\n if (attributeCallIdentifier?.type !== \"identifier\") {\n throw new Error(\"expected agent function name identifier argument for attribute\");\n }\n\n // Any attribute arguments (other than the expected call identifier) must have a type of string, number, boolean or null.\n attributeArguments\n .filter((arg) => arg.type === \"identifier\")\n .forEach((arg) => {\n throw new Error(\n `invalid attribute argument value '${arg.value}', must be string, number, boolean or null`\n );\n });\n\n // Create the attribute definition and add it to the object of attribute definitions found.\n attributes[nextAttributeName] = {\n call: attributeCallIdentifier.value,\n args: attributeArguments.map(({ value }) => value)\n };\n\n // Try to get the next attribute name token, as there could be multiple.\n nextAttributeName = tokens[0]?.toLowerCase() as keyof NodeAttributes;\n }\n\n return attributes;\n}\n", "import {\n ActionNodeDefinition,\n AnyChildNodeDefinition,\n AnyNodeDefinition,\n BranchNodeDefinition,\n ConditionNodeDefinition,\n FailNodeDefinition,\n FlipNodeDefinition,\n LottoNodeDefinition,\n ParallelNodeDefinition,\n RepeatNodeDefinition,\n RetryNodeDefinition,\n RootNodeDefinition,\n SelectorNodeDefinition,\n SequenceNodeDefinition,\n SucceedNodeDefinition,\n WaitNodeDefinition\n} from \"../BehaviourTreeDefinition\";\nimport { isCompositeNode, isDecoratorNode, isLeafNode, isRootNode } from \"../BehaviourTreeDefinitionUtilities\";\nimport { parseArgumentTokens } from \"./MDSLNodeArgumentParser\";\nimport { parseAttributeTokens } from \"./MDSLNodeAttributeParser\";\nimport {\n StringLiteralPlaceholders,\n parseTokensFromDefinition,\n popAndCheck,\n substituteStringLiterals\n} from \"./MDSLUtilities\";\n\n/**\n * Convert the MDSL tree definition string into an equivalent JSON definition.\n * @param definition The tree definition string as MDSL.\n * @returns The root node JSON definitions.\n */\nexport function convertMDSLToJSON(definition: string): RootNodeDefinition[] {\n // Swap out any node/attribute argument string literals with a placeholder and get a mapping of placeholders to original values as well as the processed definition.\n const { placeholders, processedDefinition } = substituteStringLiterals(definition);\n\n // Parse our definition definition string into an array of raw tokens.\n const tokens = parseTokensFromDefinition(processedDefinition);\n\n return convertTokensToJSONDefinition(tokens, placeholders);\n}\n\n/**\n * Converts the specified tree definition tokens into a JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The root node JSON definitions.\n */\nfunction convertTokensToJSONDefinition(\n tokens: string[],\n stringLiteralPlaceholders: StringLiteralPlaceholders\n): RootNodeDefinition[] {\n // There must be at least 3 tokens for the tree definition to be valid. 'ROOT', '{' and '}'.\n if (tokens.length < 3) {\n throw new Error(\"invalid token count\");\n }\n\n // We should have a matching number of '{' and '}' tokens. If not, then there are scopes that have not been properly closed.\n if (tokens.filter((token) => token === \"{\").length !== tokens.filter((token) => token === \"}\").length) {\n throw new Error(\"scope character mismatch\");\n }\n\n // Create an array of tree stack arrays where root nodes will always be at the botton and the current composite/decorator node at the top.\n // There should be an element in this array for every root node defined and every element should be an array with a root note as the first element.\n // E.g. A definition with two root nodes defined:\n // [\n // [root, lotto, sequence],\n // [root, selector]\n // ]\n const treeStacks: [Partial, ...Partial[]][] = [];\n\n // Create an array of all root node definitions that we create.\n const rootNodes: Partial[] = [];\n\n // A helper function used to push node definitions onto the tree stack.\n const pushNode = (node: AnyNodeDefinition) => {\n // If the node is a root node then we need to create a new tree stack array with the root node at the root.\n if (isRootNode(node)) {\n // Add the root node definition to our array of all parsed root node definitions.\n rootNodes.push(node);\n\n // Add the root node definition to the root of a new tree stack.\n treeStacks.push([node]);\n\n return;\n }\n\n // All non-root nodes should be pushed after their root nodes so handle cases\n // where we may not have any tree stacks or our top-most tree stack is empty.\n if (!treeStacks.length || !treeStacks[treeStacks.length - 1].length) {\n throw new Error(\"expected root node at base of definition\");\n }\n\n // Get the current tree stack that we are populating.\n const topTreeStack = treeStacks[treeStacks.length - 1];\n\n // Get the top-most node in the current tree stack, this will be a composite/decorator node\n // for which we will populate its children array if composite or setting its child if a decorator.\n const topTreeStackTopNode = topTreeStack[topTreeStack.length - 1] as AnyNodeDefinition;\n\n // If the top-most node in the current root stack is a composite or decorator\n // node then the current node should be added as a child of the top-most node.\n if (isCompositeNode(topTreeStackTopNode)) {\n topTreeStackTopNode.children = topTreeStackTopNode.children || [];\n topTreeStackTopNode.children.push(node);\n } else if (isDecoratorNode(topTreeStackTopNode)) {\n // If the top node already has a child node set then throw an error as a decorator should only have a single child.\n if (topTreeStackTopNode.child) {\n throw new Error(\"a decorator node must only have a single child node\");\n }\n\n topTreeStackTopNode.child = node;\n }\n\n // If the node we are adding is also a composite or decorator node, then we should push it\n // onto the current tree stack, as subsequent nodes will be added as its child/children.\n if (!isLeafNode(node)) {\n topTreeStack.push(node);\n }\n };\n\n // A helper function used to pop node definitions off of the stack.\n const popNode = () => {\n // Get the current tree stack that we are populating.\n const topTreeStack = treeStacks[treeStacks.length - 1];\n\n // Pop the top-most node in the current tree stack if there is one.\n if (topTreeStack.length) {\n topTreeStack.pop();\n }\n\n // We don't want any empty tree stacks in our stack of tree stacks.\n if (!topTreeStack.length) {\n treeStacks.pop();\n }\n };\n\n // We should keep processing the raw tokens until we run out of them.\n while (tokens.length) {\n // Grab the next token.\n const token = tokens.shift()!;\n\n // How we create the next node depends on the current raw token value.\n switch (token.toUpperCase()) {\n case \"ROOT\": {\n pushNode(createRootNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"SUCCEED\": {\n pushNode(createSucceedNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"FAIL\": {\n pushNode(createFailNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"FLIP\": {\n pushNode(createFlipNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"REPEAT\": {\n pushNode(createRepeatNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"RETRY\": {\n pushNode(createRetryNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"SEQUENCE\": {\n pushNode(createSequenceNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"SELECTOR\": {\n pushNode(createSelectorNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"PARALLEL\": {\n pushNode(createParallelNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"LOTTO\": {\n pushNode(createLottoNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"ACTION\": {\n pushNode(createActionNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"CONDITION\": {\n pushNode(createConditionNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"WAIT\": {\n pushNode(createWaitNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"BRANCH\": {\n pushNode(createBranchNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"}\": {\n // The '}' character closes the current scope and means that we have to pop a node off of the current stack.\n popNode();\n break;\n }\n\n default: {\n throw new Error(`unexpected token: ${token}`);\n }\n }\n }\n\n return rootNodes as RootNodeDefinition[];\n}\n\n/**\n * Creates a root node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The root node JSON definition.\n */\nfunction createRootNode(tokens: string[], stringLiteralPlaceholders: StringLiteralPlaceholders): RootNodeDefinition {\n // Create the root node definition.\n let node = {\n type: \"root\",\n id: undefined\n } as RootNodeDefinition;\n\n // Parse any node arguments, we should only have one if any which will be an identifier argument for the root identifier.\n const nodeArguments = parseArgumentTokens(tokens, stringLiteralPlaceholders);\n\n // Check whether any node arguments were defined.\n if (nodeArguments.length) {\n // We should only have one argument, if any, which will be an identifier argument for the root identifier.\n if (nodeArguments.length === 1 && nodeArguments[0].type === \"identifier\") {\n // The root node identifier will be the first and only node argument value.\n node.id = nodeArguments[0].value as string;\n } else {\n throw new Error(\"expected single root name argument\");\n }\n }\n\n // Grab any node attribute definitions and spread them into the node definition.\n node = { ...node, ...parseAttributeTokens(tokens, stringLiteralPlaceholders) };\n\n // This is a decorator node, so we expect an opening '{'.\n popAndCheck(tokens, \"{\");\n\n // Return the root node definition.\n return node;\n}\n\n/**\n * Creates a succeed node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The succeed node JSON definition.\n */\nfunction createSucceedNode(\n tokens: string[],\n stringLiteralPlaceholders: StringLiteralPlaceholders\n): SucceedNodeDefinition {\n const node = {\n type: \"succeed\",\n ...parseAttributeTokens(tokens, stringLiteralPlaceholders)\n } as SucceedNodeDefinition;\n\n // This is a decorator node, so we expect an opening '{'.\n popAndCheck(tokens, \"{\");\n\n // Return the succeed node definition.\n return node;\n}\n\n/**\n * Creates a fail node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The fail node JSON definition.\n */\nfunction createFailNode(tokens: string[], stringLiteralPlaceholders: StringLiteralPlaceholders): FailNodeDefinition {\n const node = {\n type: \"fail\",\n ...parseAttributeTokens(tokens, stringLiteralPlaceholders)\n } as FailNodeDefinition;\n\n // This is a decorator node, so we expect an opening '{'.\n popAndCheck(tokens, \"{\");\n\n // Return the fail node definition.\n return node;\n}\n\n/**\n * Creates a flip node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The flip node JSON definition.\n */\nfunction createFlipNode(tokens: string[], stringLiteralPlaceholders: StringLiteralPlaceholders): FlipNodeDefinition {\n const node = {\n type: \"flip\",\n ...parseAttributeTokens(tokens, stringLiteralPlaceholders)\n } as FlipNodeDefinition;\n\n // This is a decorator node, so we expect an opening '{'.\n popAndCheck(tokens, \"{\");\n\n // Return the flip node definition.\n return node;\n}\n\n/**\n * Creates a repeat node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The repeat node JSON definition.\n */\nfunction createRepeatNode(\n tokens: string[],\n stringLiteralPlaceholders: StringLiteralPlaceholders\n): RepeatNodeDefinition {\n let node = { type: \"repeat\" } as RepeatNodeDefinition;\n\n // Get the node arguments.\n const nodeArguments = parseArgumentTokens(tokens, stringLiteralPlaceholders);\n\n // The arguments of a repeat node are optional. We may have:\n // - No node arguments, in which case the repeat note will iterate indefinitely.\n // - One node argument which will be the explicit number of iterations to make.\n // - Two node arguments which define the min and max iteration bounds from which a random iteration count will be picked.\n if (nodeArguments.length) {\n // All repeat node arguments MUST be of type number and must be integer.\n nodeArguments\n .filter((arg) => arg.type !== \"number\" || !arg.isInteger)\n .forEach(() => {\n throw new Error(`repeat node iteration counts must be integer values`);\n });\n\n // We should have got one or two iteration counts.\n if (nodeArguments.length === 1) {\n // A static iteration count was defined.\n node.iterations = nodeArguments[0].value as number;\n } else if (nodeArguments.length === 2) {\n // A minimum and maximum iteration count was defined.\n node.iterations = [nodeArguments[0].value as number, nodeArguments[1].value as number];\n } else {\n // An incorrect number of iteration counts was defined.\n throw new Error(\"invalid number of repeat node iteration count arguments defined\");\n }\n }\n\n // Grab any node attribute definitions and spread them into the node definition.\n node = { ...node, ...parseAttributeTokens(tokens, stringLiteralPlaceholders) };\n\n // This is a decorator node, so we expect an opening '{'.\n popAndCheck(tokens, \"{\");\n\n // Return the repeat node definition.\n return node;\n}\n\n/**\n * Creates a retry node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The retry node JSON definition.\n */\nfunction createRetryNode(tokens: string[], stringLiteralPlaceholders: StringLiteralPlaceholders): RetryNodeDefinition {\n let node = { type: \"retry\" } as RetryNodeDefinition;\n\n // Get the node arguments.\n const nodeArguments = parseArgumentTokens(tokens, stringLiteralPlaceholders);\n\n // The arguments of a retry node are optional. We may have:\n // - No node arguments, in which case the retry note will attempt indefinitely.\n // - One node argument which will be the explicit number of attempts to make.\n // - Two node arguments which define the min and max attempt bounds from which a random attempt count will be picked.\n if (nodeArguments.length) {\n // All retry node arguments MUST be of type number and must be integer.\n nodeArguments\n .filter((arg) => arg.type !== \"number\" || !arg.isInteger)\n .forEach(() => {\n throw new Error(`retry node attempt counts must be integer values`);\n });\n\n // We should have got one or two attempt counts.\n if (nodeArguments.length === 1) {\n // A static attempt count was defined.\n node.attempts = nodeArguments[0].value as number;\n } else if (nodeArguments.length === 2) {\n // A minimum and maximum attempt count was defined.\n node.attempts = [nodeArguments[0].value as number, nodeArguments[1].value as number];\n } else {\n // An incorrect number of attempt counts was defined.\n throw new Error(\"invalid number of retry node attempt count arguments defined\");\n }\n }\n\n // Grab any node attribute definitions and spread them into the node definition.\n node = { ...node, ...parseAttributeTokens(tokens, stringLiteralPlaceholders) };\n\n // This is a decorator node, so we expect an opening '{'.\n popAndCheck(tokens, \"{\");\n\n // Return the retry node definition.\n return node;\n}\n\n/**\n * Creates a sequence node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The sequence node JSON definition.\n */\nfunction createSequenceNode(\n tokens: string[],\n stringLiteralPlaceholders: StringLiteralPlaceholders\n): SequenceNodeDefinition {\n const node = {\n type: \"sequence\",\n ...parseAttributeTokens(tokens, stringLiteralPlaceholders)\n } as SequenceNodeDefinition;\n\n // This is a composite node, so we expect an opening '{'.\n popAndCheck(tokens, \"{\");\n\n // Return the sequence node definition.\n return node;\n}\n\n/**\n * Creates a selector node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The selector node JSON definition.\n */\nfunction createSelectorNode(\n tokens: string[],\n stringLiteralPlaceholders: StringLiteralPlaceholders\n): SelectorNodeDefinition {\n const node = {\n type: \"selector\",\n ...parseAttributeTokens(tokens, stringLiteralPlaceholders)\n } as SelectorNodeDefinition;\n\n // This is a composite node, so we expect an opening '{'.\n popAndCheck(tokens, \"{\");\n\n // Return the selector node definition.\n return node;\n}\n\n/**\n * Creates a parallel node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The parallel node JSON definition.\n */\nfunction createParallelNode(\n tokens: string[],\n stringLiteralPlaceholders: StringLiteralPlaceholders\n): ParallelNodeDefinition {\n const node = {\n type: \"parallel\",\n ...parseAttributeTokens(tokens, stringLiteralPlaceholders)\n } as ParallelNodeDefinition;\n\n // This is a composite node, so we expect an opening '{'.\n popAndCheck(tokens, \"{\");\n\n // Return the parallel node definition.\n return node;\n}\n\n/**\n * Creates a lotto node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The lotto node JSON definition.\n */\nfunction createLottoNode(tokens: string[], stringLiteralPlaceholders: StringLiteralPlaceholders): LottoNodeDefinition {\n // If any node arguments have been defined then they must be our weights.\n const nodeArguments = parseArgumentTokens(tokens, stringLiteralPlaceholders);\n\n // All lotto node arguments MUST be of type number and must be integer.\n nodeArguments\n .filter((arg) => arg.type !== \"number\" || !arg.isInteger)\n .forEach(() => {\n throw new Error(`lotto node weight arguments must be integer values`);\n });\n\n const node = {\n type: \"lotto\",\n weights: nodeArguments.map(({ value }) => value),\n ...parseAttributeTokens(tokens, stringLiteralPlaceholders)\n } as LottoNodeDefinition;\n\n // This is a composite node, so we expect an opening '{'.\n popAndCheck(tokens, \"{\");\n\n // Return the lotto node definition.\n return node;\n}\n\n/**\n * Creates an action node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The action node JSON definition.\n */\nfunction createActionNode(\n tokens: string[],\n stringLiteralPlaceholders: StringLiteralPlaceholders\n): ActionNodeDefinition {\n // Parse any node arguments, we should have at least one which will be an identifier argument for the action name\n // and agent function to invoke for the action, all other arguments are to be passed as arguments to that function.\n const [actionNameIdentifier, ...agentFunctionArgs] = parseArgumentTokens(tokens, stringLiteralPlaceholders);\n\n // Our first argument MUST be defined and be an identifier as we require an action name argument.\n if (actionNameIdentifier?.type !== \"identifier\") {\n throw new Error(\"expected action name identifier argument\");\n }\n\n // Only the first argument should have been an identifier, all agent function arguments must be string, number, boolean or null.\n agentFunctionArgs\n .filter((arg) => arg.type === \"identifier\")\n .forEach((arg) => {\n throw new Error(\n `invalid action node argument value '${arg.value}', must be string, number, boolean or null`\n );\n });\n\n // Return the action node definition.\n return {\n type: \"action\",\n call: actionNameIdentifier.value,\n args: agentFunctionArgs.map(({ value }) => value),\n ...parseAttributeTokens(tokens, stringLiteralPlaceholders)\n };\n}\n\n/**\n * Creates a condition node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The condition node JSON definition.\n */\nfunction createConditionNode(\n tokens: string[],\n stringLiteralPlaceholders: StringLiteralPlaceholders\n): ConditionNodeDefinition {\n // Parse any node arguments, we should have at least one which will be an identifier argument for the condition name\n // and agent function to invoke for the condition, all other arguments are to be passed as arguments to that function.\n const [conditionNameIdentifier, ...agentFunctionArgs] = parseArgumentTokens(tokens, stringLiteralPlaceholders);\n\n // Our first argument MUST be defined and be an identifier as we require a condition name argument.\n if (conditionNameIdentifier?.type !== \"identifier\") {\n throw new Error(\"expected condition name identifier argument\");\n }\n\n // Only the first argument should have been an identifier, all agent function arguments must be string, number, boolean or null.\n agentFunctionArgs\n .filter((arg) => arg.type === \"identifier\")\n .forEach((arg) => {\n throw new Error(\n `invalid condition node argument value '${arg.value}', must be string, number, boolean or null`\n );\n });\n\n // Return the condition node definition.\n return {\n type: \"condition\",\n call: conditionNameIdentifier.value,\n args: agentFunctionArgs.map(({ value }) => value),\n ...parseAttributeTokens(tokens, stringLiteralPlaceholders)\n };\n}\n\n/**\n * Creates a wait node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The wait node JSON definition.\n */\nfunction createWaitNode(tokens: string[], stringLiteralPlaceholders: StringLiteralPlaceholders): WaitNodeDefinition {\n let node = { type: \"wait\" } as WaitNodeDefinition;\n\n // Get the node arguments.\n const nodeArguments = parseArgumentTokens(tokens, stringLiteralPlaceholders);\n\n // The arguments of a wait node are optional. We may have:\n // - No node arguments, in which case the wait will be indefinite until it is aborted.\n // - One node argument which will be the explicit duration of the wait.\n // - Two node arguments which define the min and max duration bounds from which a random duration will be picked.\n if (nodeArguments.length) {\n // All wait node arguments MUST be of type number and must be integer.\n nodeArguments\n .filter((arg) => arg.type !== \"number\" || !arg.isInteger)\n .forEach(() => {\n throw new Error(`wait node duration arguments must be integer values`);\n });\n\n // We may have:\n // - One node argument which will be the explicit duration of the wait.\n // - Two node arguments which define the min and max duration bounds from which a random duration will be picked.\n // - Too many arguments, which is not valid.\n if (nodeArguments.length === 1) {\n // An explicit duration was defined.\n node.duration = nodeArguments[0].value as number;\n } else if (nodeArguments.length === 2) {\n // Min and max duration bounds were defined from which a random duration will be picked.\n node.duration = [nodeArguments[0].value as number, nodeArguments[1].value as number];\n } else if (nodeArguments.length > 2) {\n // An incorrect number of duration arguments were defined.\n throw new Error(\"invalid number of wait node duration arguments defined\");\n }\n }\n\n // Return the wait node definition.\n return { ...node, ...parseAttributeTokens(tokens, stringLiteralPlaceholders) };\n}\n\n/**\n * Creates a branch node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The branch node JSON definition.\n */\nfunction createBranchNode(\n tokens: string[],\n stringLiteralPlaceholders: StringLiteralPlaceholders\n): BranchNodeDefinition {\n // Parse any node arguments, we should have one which will be an identifier argument for the root ref.\n const nodeArguments = parseArgumentTokens(tokens, stringLiteralPlaceholders);\n\n // We should have only a single identifer argument for a branch node, which is the root ref.\n if (nodeArguments.length !== 1 || nodeArguments[0].type !== \"identifier\") {\n throw new Error(\"expected single branch name argument\");\n }\n\n // Return the branch node definition.\n return { type: \"branch\", ref: nodeArguments[0].value };\n}\n", "import { RootNodeDefinition } from \"./BehaviourTreeDefinition\";\nimport { flattenDefinition, isBranchNode, isInteger } from \"./BehaviourTreeDefinitionUtilities\";\nimport { convertMDSLToJSON } from \"./mdsl/MDSLDefinitionParser\";\n\n/**\n * An object representing the result of validating a tree definition.\n */\nexport type DefinitionValidationResult = {\n /**\n * A flag defining whether validation succeeded.\n */\n succeeded: boolean;\n /**\n * A string containing the error message if validation did not succeed.\n */\n errorMessage?: string;\n};\n\n/**\n * Validates the specified behaviour tree definition in the form of JSON or MDSL, not taking any globally registered subtrees into consideration.\n * @param definition The behaviour tree definition in the form of JSON or MDSL.\n * @returns An object representing the result of validating the given tree definition.\n */\nexport function validateDefinition(definition: any): DefinitionValidationResult {\n // The definition must be defined.\n if (definition === null || typeof definition === \"undefined\") {\n return createValidationFailureResult(\"definition is null or undefined\");\n }\n\n // We are expecting a definition in one of three different forms:\n // - A string which we will assume is MDSL and we will parse this to JSON before validation.\n // - An array which we will assume is an array of root node definitions with at least one being the primary root node (no 'id' property)\n // - An object which we will assume is the primary root node and should not have an 'id' property.\n if (typeof definition === \"string\") {\n // The definition is a string which we can assume is MDSL, so attempt to validate it.\n return validateMDSLDefinition(definition);\n } else if (typeof definition === \"object\") {\n // The definition will either be an array (of root node definitions) or an object (the single primary root node definition).\n return validateJSONDefinition(definition);\n } else {\n return createValidationFailureResult(`unexpected definition type of '${typeof definition}'`);\n }\n}\n\n/**\n * Validates the specified behaviour tree definition in the form of MDSL.\n * @param definition The behaviour tree definition in the form of MDSL.\n * @returns An object representing the result of validating the given tree definition.\n */\nexport function validateMDSLDefinition(definition: string): DefinitionValidationResult {\n let rootNodeDefinitions;\n\n // The first thing the we need to do is to attempt to convert our MDSL into JSON.\n try {\n // The definition is a string which we can assume is MDSL, so attempt to parse it to a JSON definition in the form of an array of root node definitions.\n rootNodeDefinitions = convertMDSLToJSON(definition);\n } catch (error) {\n // We failed to parse the JSON from the MDSL, this is likely to be the result of it not being a valid MDSL string.\n return createValidationFailureResult(`invalid MDSL: ${error}`);\n }\n\n // Unpack all of the root node definitions into arrays of main ('id' defined) and sub ('id' not defined) root node definitions.\n const mainRootNodeDefinitions = rootNodeDefinitions.filter(({ id }) => typeof id === \"undefined\");\n const subRootNodeDefinitions = rootNodeDefinitions.filter(({ id }) => typeof id === \"string\" && id.length > 0);\n\n // We should ALWAYS have exactly one root node definition without an 'id' property defined, which is out main root node definition.\n if (mainRootNodeDefinitions.length !== 1) {\n return createValidationFailureResult(\n \"expected single unnamed root node at base of definition to act as main root\"\n );\n }\n\n // We should never have duplicate 'id' properties across our sub root node definitions.\n const subRootNodeIdenitifers: string[] = [];\n for (const { id } of subRootNodeDefinitions) {\n // Have we already come across this 'id' property value?\n if (subRootNodeIdenitifers.includes(id!)) {\n return createValidationFailureResult(`multiple root nodes found with duplicate name '${id}'`);\n }\n\n subRootNodeIdenitifers.push(id!);\n }\n\n try {\n // Validate our branch -> subtree links and check for any circular dependencies, we don't care about checking for broken subtree links here.\n validateBranchSubtreeLinks(rootNodeDefinitions, false);\n } catch (exception) {\n return createValidationFailureResult((exception as Error).message);\n }\n\n // Our definition was valid!\n return { succeeded: true };\n}\n\n/**\n * Validates the specified behaviour tree definition in the form of JSON.\n * @param definition The behaviour tree definition in the form of JSON.\n * @returns An object representing the result of validating the given tree definition.\n */\nexport function validateJSONDefinition(\n definition: RootNodeDefinition | RootNodeDefinition[]\n): DefinitionValidationResult {\n // The definition will either be an array (of root node definitions) or an object (the single primary root node definition).\n const rootNodeDefinitions = Array.isArray(definition) ? definition : [definition];\n\n // Iterate over our array of root nodes and call validateNode for each, passing an initial depth of 0, wrapped in a try catch to handle validation failures.\n try {\n rootNodeDefinitions.forEach((rootNodeDefinition) => validateNode(rootNodeDefinition, 0));\n } catch (error) {\n // Handle cases where we have caught a thrown Error and return a failure result with the error message.\n if (error instanceof Error) {\n return createValidationFailureResult(error.message);\n }\n\n // No idea what happened here!\n return createValidationFailureResult(`unexpected error: ${error}`);\n }\n\n // Unpack all of the root node definitions into arrays of main ('id' defined) and sub ('id' not defined) root node definitions.\n const mainRootNodeDefinitions = rootNodeDefinitions.filter(({ id }) => typeof id === \"undefined\");\n const subRootNodeDefinitions = rootNodeDefinitions.filter(({ id }) => typeof id === \"string\" && id.length > 0);\n\n // We should ALWAYS have exactly one root node definition without an 'id' property defined, which is out main root node definition.\n if (mainRootNodeDefinitions.length !== 1) {\n return createValidationFailureResult(\n \"expected single root node without 'id' property defined to act as main root\"\n );\n }\n\n // We should never have duplicate 'id' properties across our sub root node definitions.\n const subRootNodeIdenitifers: string[] = [];\n for (const { id } of subRootNodeDefinitions) {\n // Have we already come across this 'id' property value?\n if (subRootNodeIdenitifers.includes(id!)) {\n return createValidationFailureResult(\n `multiple root nodes found with duplicate 'id' property value of '${id}'`\n );\n }\n\n subRootNodeIdenitifers.push(id!);\n }\n\n try {\n // Validate our branch -> subtree links and check for any circular dependencies, we don't care about checking for broken subtree links here.\n validateBranchSubtreeLinks(rootNodeDefinitions, false);\n } catch (exception) {\n return createValidationFailureResult((exception as Error).message);\n }\n\n // Our definition was valid!\n return { succeeded: true };\n}\n\n/**\n * Validates the branch -> subtree links across all provided root node definitions.\n * This will not consider branch nodes that reference any globally registered subtrees unless includesGlobalSubtrees\n * is set to true, in which case we will also verify that there are no broken branch -> subtree links.\n * @param rootNodeDefinitions The array of root node definitions.\n * @param includesGlobalSubtrees A flag defining whether the array includes all global subtree root node definitions.\n */\nexport function validateBranchSubtreeLinks(rootNodeDefinitions: RootNodeDefinition[], includesGlobalSubtrees: boolean) {\n // Create a mapping of root node identifiers to other root nodes that they reference via branch nodes.\n // Below is an example of a mapping that includes a circular dependency (root => a => b => c => a)\n // [{ refs: [\"a\", \"b\"] }, { id: \"a\", refs: [\"b\"] }, { id: \"b\", refs: [\"c\"] }, { id: \"c\", refs: [\"a\"] }]\n const rootNodeMappings: { id: string | undefined; refs: string[] }[] = rootNodeDefinitions.map(\n (rootNodeDefinition) => ({\n id: rootNodeDefinition.id,\n refs: flattenDefinition(rootNodeDefinition)\n .filter(isBranchNode)\n .map(({ ref }) => ref)\n })\n );\n\n // A recursive function to walk through the mappings, keeping track of which root nodes we have visited in the form of a path of root node identifiers.\n const followRefs = (mapping: { id: string | undefined; refs: string[] }, path: (string | undefined)[] = []) => {\n // Have we found a circular dependency?\n if (path.includes(mapping.id)) {\n // We found a circular dependency! Get the bad path of root node identifiers.\n const badPath = [...path, mapping.id];\n\n // Create the formatted path value. [undefined, \"a\", \"b\", \"c\", \"a\"] would be formatted as \"a -> b -> c -> a\".\n const badPathFormatted = badPath.filter((element) => !!element).join(\" => \");\n\n // No need to continue, we found a circular dependency.\n throw new Error(`circular dependency found in branch node references: ${badPathFormatted}`);\n }\n\n for (const ref of mapping.refs) {\n // Find the mapping for the root node with an identifer matching the current ref.\n const subMapping = rootNodeMappings.find(({ id }) => id === ref);\n\n // We may not have a mapping for this ref, which is normal when we aren't considering all globally registered subtrees.\n if (subMapping) {\n followRefs(subMapping, [...path, mapping.id]);\n } else if (includesGlobalSubtrees) {\n // We found a reference to a root node that doesn't exist, which is a problem seeing as the root node definitons includes all globally registered subtrees.\n throw new Error(\n mapping.id\n ? `subtree '${mapping.id}' has branch node that references root node '${ref}' which has not been defined`\n : `primary tree has branch node that references root node '${ref}' which has not been defined`\n );\n }\n }\n };\n\n // Start looking for circular dependencies and broken references from the primary root node definition.\n followRefs(rootNodeMappings.find((mapping) => typeof mapping.id === \"undefined\")!);\n}\n\n/**\n * Validate an object that we expect to be a node definition.\n * @param definition An object that we expect to be a node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateNode(definition: any, depth: number): void {\n // Every node must be valid object and have a non-empty 'type' string property.\n if (typeof definition !== \"object\" || typeof definition.type !== \"string\" || definition.type.length === 0) {\n throw new Error(\n `node definition is not an object or 'type' property is not a non-empty string at depth '${depth}'`\n );\n }\n\n // How we validate this node definition will depend on its type.\n switch (definition.type) {\n case \"action\":\n validateActionNode(definition, depth);\n break;\n\n case \"condition\":\n validateConditionNode(definition, depth);\n break;\n\n case \"wait\":\n validateWaitNode(definition, depth);\n break;\n\n case \"branch\":\n validateBranchNode(definition, depth);\n break;\n\n case \"root\":\n validateRootNode(definition, depth);\n break;\n\n case \"success\":\n validateSuccessNode(definition, depth);\n break;\n\n case \"fail\":\n validateFailNode(definition, depth);\n break;\n\n case \"flip\":\n validateFlipNode(definition, depth);\n break;\n\n case \"repeat\":\n validateRepeatNode(definition, depth);\n break;\n\n case \"retry\":\n validateRetryNode(definition, depth);\n break;\n\n case \"sequence\":\n validateSequenceNode(definition, depth);\n break;\n\n case \"selector\":\n validateSelectorNode(definition, depth);\n break;\n\n case \"parallel\":\n validateParallelNode(definition, depth);\n break;\n\n default:\n throw new Error(`unexpected node type of '${definition.type}' at depth '${depth}'`);\n }\n}\n\n/**\n * Validate any attributes for a given node definition.\n * @param definition The node definition.\n * @param depth The depth of the node in the behaviour tree definition.\n */\nfunction validateNodeAttributes(definition: any, depth: number): void {\n // Validate each of the attribute types for this node.\n [\"while\", \"until\", \"entry\", \"exit\", \"step\"].forEach((attributeName) => {\n // Attempt to grab the definition for the current attribute from the node definition.\n const attributeDefinition = definition[attributeName];\n\n // All node attributes are optional, so there is nothing to do if the current attribute is not defined.\n if (typeof attributeDefinition === \"undefined\") {\n return;\n }\n\n // The attribute definition must be an object.\n if (typeof attributeDefinition !== \"object\") {\n throw new Error(\n `expected attribute '${attributeName}' to be an object for '${definition.type}' node at depth '${depth}'`\n );\n }\n\n // The 'call' property must be defined for any attribute definition.\n if (typeof attributeDefinition.call !== \"string\" || attributeDefinition.call.length === 0) {\n throw new Error(\n `expected 'call' property for attribute '${attributeName}' to be a non-empty string for '${definition.type}' node at depth '${depth}'`\n );\n }\n\n // If any node attribute arguments have been defined then they must have been defined in an array.\n if (typeof attributeDefinition.args !== \"undefined\" && !Array.isArray(attributeDefinition.args)) {\n throw new Error(\n `expected 'args' property for attribute '${attributeName}' to be an array for '${definition.type}' node at depth '${depth}'`\n );\n }\n });\n}\n\n/**\n * Validate an object that we expect to be a root node definition.\n * @param definition An object that we expect to be a root node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateRootNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"root\") {\n throw new Error(\"expected node type of 'root' for root node\");\n }\n\n // A root node cannot be the child of another node.\n if (depth > 0) {\n throw new Error(\"a root node cannot be the child of another node\");\n }\n\n // Check that, if the root node 'id' property is defined, it is a non-empty string.\n if (typeof definition.id !== \"undefined\" && (typeof definition.id !== \"string\" || definition.id.length === 0)) {\n throw new Error(\"expected non-empty string for 'id' property if defined for root node\");\n }\n\n // A root node is a decorator node, so must have a child node defined.\n if (typeof definition.child === \"undefined\") {\n throw new Error(\"expected property 'child' to be defined for root node\");\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n\n // Validate the child node of this decorator node.\n validateNode(definition.child, depth + 1);\n}\n\n/**\n * Validate an object that we expect to be a success node definition.\n * @param definition An object that we expect to be a success node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateSuccessNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"success\") {\n throw new Error(`expected node type of 'success' for success node at depth '${depth}'`);\n }\n\n // A success node is a decorator node, so must have a child node defined.\n if (typeof definition.child === \"undefined\") {\n throw new Error(`expected property 'child' to be defined for success node at depth '${depth}'`);\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n\n // Validate the child node of this decorator node.\n validateNode(definition.child, depth + 1);\n}\n\n/**\n * Validate an object that we expect to be a fail node definition.\n * @param definition An object that we expect to be a fail node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateFailNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"fail\") {\n throw new Error(`expected node type of 'fail' for fail node at depth '${depth}'`);\n }\n\n // A fail node is a decorator node, so must have a child node defined.\n if (typeof definition.child === \"undefined\") {\n throw new Error(`expected property 'child' to be defined for fail node at depth '${depth}'`);\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n\n // Validate the child node of this decorator node.\n validateNode(definition.child, depth + 1);\n}\n\n/**\n * Validate an object that we expect to be a flip node definition.\n * @param definition An object that we expect to be a flip node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateFlipNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"flip\") {\n throw new Error(`expected node type of 'flip' for flip node at depth '${depth}'`);\n }\n\n // A flip node is a decorator node, so must have a child node defined.\n if (typeof definition.child === \"undefined\") {\n throw new Error(`expected property 'child' to be defined for flip node at depth '${depth}'`);\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n\n // Validate the child node of this decorator node.\n validateNode(definition.child, depth + 1);\n}\n\n/**\n * Validate an object that we expect to be a repeat node definition.\n * @param definition An object that we expect to be a repeat node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateRepeatNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"repeat\") {\n throw new Error(`expected node type of 'repeat' for repeat node at depth '${depth}'`);\n }\n\n // A repeat node is a decorator node, so must have a child node defined.\n if (typeof definition.child === \"undefined\") {\n throw new Error(`expected property 'child' to be defined for repeat node at depth '${depth}'`);\n }\n\n // Check whether an 'iterations' property has been defined, it may not have been if this node is to repeat indefinitely.\n if (typeof definition.iterations !== \"undefined\") {\n if (Array.isArray(definition.iterations)) {\n // Check whether any elements of the array are not integer values.\n const containsNonInteger = !!definition.iterations.find((value: unknown) => !isInteger(value));\n\n // If the 'iterations' property is an array then it MUST contain two integer values.\n if (definition.iterations.length !== 2 || containsNonInteger) {\n throw new Error(\n `expected array containing two integer values for 'iterations' property if defined for repeat node at depth '${depth}'`\n );\n }\n } else if (!isInteger(definition.iterations)) {\n throw new Error(\n `expected integer value or array containing two integer values for 'iterations' property if defined for repeat node at depth '${depth}'`\n );\n }\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n\n // Validate the child node of this decorator node.\n validateNode(definition.child, depth + 1);\n}\n\n/**\n * Validate an object that we expect to be a retry node definition.\n * @param definition An object that we expect to be a retry node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateRetryNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"retry\") {\n throw new Error(`expected node type of 'retry' for retry node at depth '${depth}'`);\n }\n\n // A retry node is a decorator node, so must have a child node defined.\n if (typeof definition.child === \"undefined\") {\n throw new Error(`expected property 'child' to be defined for retry node at depth '${depth}'`);\n }\n\n // Check whether an 'attempts' property has been defined, it may not have been if this node is to retry indefinitely.\n if (typeof definition.attempts !== \"undefined\") {\n if (Array.isArray(definition.attempts)) {\n // Check whether any elements of the array are not integer values.\n const containsNonInteger = !!definition.attempts.find((value: unknown) => !isInteger(value));\n\n // If the 'attempts' property is an array then it MUST contain two integer values.\n if (definition.attempts.length !== 2 || containsNonInteger) {\n throw new Error(\n `expected array containing two integer values for 'attempts' property if defined for retry node at depth '${depth}'`\n );\n }\n } else if (!isInteger(definition.attempts)) {\n throw new Error(\n `expected integer value or array containing two integer values for 'attempts' property if defined for retry node at depth '${depth}'`\n );\n }\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n\n // Validate the child node of this decorator node.\n validateNode(definition.child, depth + 1);\n}\n\n/**\n * Validate an object that we expect to be a branch node definition.\n * @param definition An object that we expect to be a branch node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateBranchNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"branch\") {\n throw new Error(`expected node type of 'branch' for branch node at depth '${depth}'`);\n }\n\n // Check that the branch node 'ref' property is defined and is a non-empty string.\n if (typeof definition.ref !== \"string\" || definition.ref.length === 0) {\n throw new Error(`expected non-empty string for 'ref' property for branch node at depth '${depth}'`);\n }\n\n // It is invalid to define guard attributes for a branch node as they should be defined on the referenced root node.\n [\"while\", \"until\"].forEach((attributeName) => {\n if (typeof definition[attributeName] !== \"undefined\") {\n throw new Error(\n `guards should not be defined for branch nodes but guard '${attributeName}' was defined for branch node at depth '${depth}'`\n );\n }\n });\n\n // It is invalid to define callback attributes for a branch node as they should be defined on the referenced root node.\n [\"entry\", \"exit\", \"step\"].forEach((attributeName) => {\n if (typeof definition[attributeName] !== \"undefined\") {\n throw new Error(\n `callbacks should not be defined for branch nodes but callback '${attributeName}' was defined for branch node at depth '${depth}'`\n );\n }\n });\n}\n\n/**\n * Validate an object that we expect to be a action node definition.\n * @param definition An object that we expect to be a action node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateActionNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"action\") {\n throw new Error(`expected node type of 'action' for action node at depth '${depth}'`);\n }\n\n // The 'call' property must be defined for a action node definition.\n if (typeof definition.call !== \"string\" || definition.call.length === 0) {\n throw new Error(`expected non-empty string for 'call' property of action node at depth '${depth}'`);\n }\n\n // If any action function arguments have been defined then they must have been defined in an array.\n if (typeof definition.args !== \"undefined\" && !Array.isArray(definition.args)) {\n throw new Error(`expected array for 'args' property if defined for action node at depth '${depth}'`);\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n}\n\n/**\n * Validate an object that we expect to be a condition node definition.\n * @param definition An object that we expect to be a condition node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateConditionNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"condition\") {\n throw new Error(`expected node type of 'condition' for condition node at depth '${depth}'`);\n }\n\n // The 'call' property must be defined for a condition node definition.\n if (typeof definition.call !== \"string\" || definition.call.length === 0) {\n throw new Error(`expected non-empty string for 'call' property of condition node at depth '${depth}'`);\n }\n\n // If any condition function arguments have been defined then they must have been defined in an array.\n if (typeof definition.args !== \"undefined\" && !Array.isArray(definition.args)) {\n throw new Error(`expected array for 'args' property if defined for condition node at depth '${depth}'`);\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n}\n\n/**\n * Validate an object that we expect to be a wait node definition.\n * @param definition An object that we expect to be a wait node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateWaitNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"wait\") {\n throw new Error(`expected node type of 'wait' for wait node at depth '${depth}'`);\n }\n\n // Check whether a 'duration' property has been defined, it may not have been if this node is to wait indefinitely.\n if (typeof definition.duration !== \"undefined\") {\n if (Array.isArray(definition.duration)) {\n // Check whether any elements of the array are not integer values.\n const containsNonInteger = !!definition.duration.find((value: unknown) => !isInteger(value));\n\n // If the 'duration' property is an array then it MUST contain two integer values.\n if (definition.duration.length !== 2 || containsNonInteger) {\n throw new Error(\n `expected array containing two integer values for 'duration' property if defined for wait node at depth '${depth}'`\n );\n }\n } else if (!isInteger(definition.duration)) {\n throw new Error(\n `expected integer value or array containing two integer values for 'duration' property if defined for wait node at depth '${depth}'`\n );\n }\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n}\n\n/**\n * Validate an object that we expect to be a sequence node definition.\n * @param definition An object that we expect to be a sequence node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateSequenceNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"sequence\") {\n throw new Error(`expected node type of 'sequence' for sequence node at depth '${depth}'`);\n }\n\n // A sequence node is a composite node, so must have a children nodes array defined.\n if (!Array.isArray(definition.children) || definition.children.length === 0) {\n throw new Error(`expected non-empty 'children' array to be defined for sequence node at depth '${depth}'`);\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n\n // Validate the child nodes of this composite node.\n definition.children.forEach((child: any) => validateNode(child, depth + 1));\n}\n\n/**\n * Validate an object that we expect to be a selector node definition.\n * @param definition An object that we expect to be a selector node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateSelectorNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"selector\") {\n throw new Error(`expected node type of 'selector' for selector node at depth '${depth}'`);\n }\n\n // A selector node is a composite node, so must have a children nodes array defined.\n if (!Array.isArray(definition.children) || definition.children.length === 0) {\n throw new Error(`expected non-empty 'children' array to be defined for selector node at depth '${depth}'`);\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n\n // Validate the child nodes of this composite node.\n definition.children.forEach((child: any) => validateNode(child, depth + 1));\n}\n\n/**\n * Validate an object that we expect to be a parallel node definition.\n * @param definition An object that we expect to be a parallel node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateParallelNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"parallel\") {\n throw new Error(`expected node type of 'parallel' for parallel node at depth '${depth}'`);\n }\n\n // A parallel node is a composite node, so must have a children nodes array defined.\n if (!Array.isArray(definition.children) || definition.children.length === 0) {\n throw new Error(`expected non-empty 'children' array to be defined for parallel node at depth '${depth}'`);\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n\n // Validate the child nodes of this composite node.\n definition.children.forEach((child: any) => validateNode(child, depth + 1));\n}\n\n/**\n * A helper function to create a failure validation result with the given error message.\n * @param errorMessage The validation failure error message.\n * @returns A failure validation result with the given error message.\n */\nfunction createValidationFailureResult(errorMessage: string): DefinitionValidationResult {\n return { succeeded: false, errorMessage };\n}\n", "import { ActionResult, Agent, GlobalFunction } from \"./Agent\";\nimport { RootNodeDefinition } from \"./BehaviourTreeDefinition\";\n\nexport type InvokerFunction = (args: any[]) => ActionResult;\n\n/**\n * A singleton used to store and lookup registered functions and subtrees.\n */\nexport default class Lookup {\n /**\n * The object holding any registered functions keyed on function name.\n */\n private static functionTable: { [key: string]: GlobalFunction } = {};\n /**\n * The object holding any registered subtree root node definitions keyed on tree name.\n */\n private static subtreeTable: { [key: string]: RootNodeDefinition } = {};\n\n /**\n * Gets the function with the specified name.\n * @param name The name of the function.\n * @returns The function with the specified name.\n */\n public static getFunc(name: string): GlobalFunction {\n return this.functionTable[name];\n }\n\n /**\n * Sets the function with the specified name for later lookup.\n * @param name The name of the function.\n * @param func The function.\n */\n public static setFunc(name: string, func: GlobalFunction): void {\n this.functionTable[name] = func;\n }\n\n /**\n * Gets the function invoker for the specified agent and function name.\n * If a function with the specified name exists on the agent object then it will\n * be returned, otherwise we will then check the registered functions for a match.\n * @param agent The agent instance that this behaviour tree is modelling behaviour for.\n * @param name The function name.\n * @returns The function invoker for the specified agent and function name.\n */\n static getFuncInvoker(agent: Agent, name: string): InvokerFunction | null {\n // Check whether the agent contains the specified function.\n const foundOnAgent = agent[name];\n if (foundOnAgent && typeof foundOnAgent === \"function\") {\n return (args: any[]): boolean | ActionResult => foundOnAgent.apply(agent, args);\n }\n\n // The agent does not contain the specified function but it may have been registered at some point.\n if (this.functionTable[name] && typeof this.functionTable[name] === \"function\") {\n return (args: any[]) => this.functionTable[name](agent, ...args.map((arg) => arg.value));\n }\n\n // We have no function to invoke.\n return null;\n }\n\n /**\n * Gets all registered subtree root node definitions.\n */\n static getSubtrees(): { [key: string]: RootNodeDefinition } {\n return this.subtreeTable;\n }\n\n /**\n * Sets the subtree with the specified name for later lookup.\n * @param name The name of the subtree.\n * @param subtree The subtree.\n */\n static setSubtree(name: string, subtree: RootNodeDefinition) {\n this.subtreeTable[name] = subtree;\n }\n\n /**\n * Removes the registered function or subtree with the specified name.\n * @param name The name of the registered function or subtree.\n */\n static remove(name: string) {\n delete this.functionTable[name];\n delete this.subtreeTable[name];\n }\n\n /**\n * Remove all registered functions and subtrees.\n */\n static empty() {\n this.functionTable = {};\n this.subtreeTable = {};\n }\n}\n", "import Node from \"../../nodes/Node\";\n\n/**\n * An exception thrown when evaluating node guard path conditions and a conditions fails.\n */\nexport default class GuardUnsatisifedException extends Error {\n /**\n * @param source The node at which a guard condition failed.\n */\n constructor(private source: Node) {\n super(\"A guard path condition has failed\");\n }\n\n /**\n * Gets whether the specified node is the node at which a guard condition failed.\n * @param node The node to check against the source node.\n * @returns Whether the specified node is the node at which a guard condition failed.\n */\n isSourceNode = (node: Node) => node === this.source;\n}\n", "import { Agent } from \"../../Agent\";\nimport Guard from \"./Guard\";\nimport Node from \"../../nodes/Node\";\nimport GuardUnsatisifedException from \"./GuardUnsatisifedException\";\n\nexport type GuardPathPart = {\n node: Node;\n guards: Guard[];\n};\n\n/**\n * Represents a path of node guards along a root-to-leaf tree path.\n */\nexport default class GuardPath {\n /**\n * @param nodes An array of objects defining a node instance -> guard link, ordered by node depth.\n */\n constructor(private nodes: GuardPathPart[]) {}\n\n /**\n * Evaluate guard conditions for all guards in the tree path, moving outwards from the root.\n * @param agent The agent, required for guard evaluation.\n * @returns An evaluation results object.\n */\n evaluate = (agent: Agent) => {\n // We need to evaluate guard conditions for nodes up the tree, moving outwards from the root.\n for (const details of this.nodes) {\n // There can be multiple guards per node.\n for (const guard of details.guards) {\n // Check whether the guard condition passes, and throw an exception if not.\n if (!guard.isSatisfied(agent)) {\n throw new GuardUnsatisifedException(details.node);\n }\n }\n }\n };\n}\n", "import { BehaviourTreeOptions } from \"../BehaviourTreeOptions\";\nimport State, { AnyState } from \"../State\";\nimport { Agent } from \"../Agent\";\nimport Leaf from \"./leaf/Leaf\";\nimport Attribute from \"../attributes/Attribute\";\nimport Entry from \"../attributes/callbacks/Entry\";\nimport Exit from \"../attributes/callbacks/Exit\";\nimport Step from \"../attributes/callbacks/Step\";\nimport Guard from \"../attributes/guards/Guard\";\nimport GuardPath from \"../attributes/guards/GuardPath\";\nimport GuardUnsatisifedException from \"../attributes/guards/GuardUnsatisifedException\";\n\n/**\n * A base node.\n */\nexport default abstract class Node {\n /**\n * The node uid.\n */\n private readonly uid: string = createNodeUid();\n /**\n * The node state.\n */\n private state: AnyState = State.READY;\n /**\n * The guard path to evaluate as part of a node update.\n */\n private guardPath: GuardPath | undefined;\n\n /**\n * @param type The node type.\n * @param attributes The node attributes.\n * @param args The node argument definitions.\n */\n constructor(private type: string, private attributes: Attribute[], private args: any[]) {}\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected abstract onUpdate(agent: Agent, options: BehaviourTreeOptions): void;\n\n /**\n * Gets the name of the node.\n */\n public abstract getName(): string;\n\n /**\n * Gets whether this node is a leaf node.\n */\n public abstract isLeafNode: () => this is Leaf;\n\n /**\n * Gets/Sets the state of the node.\n */\n getState = (): AnyState => this.state;\n setState = (value: AnyState): void => {\n this.state = value;\n };\n\n /**\n * Gets the unique id of the node.\n */\n getUid = () => this.uid;\n\n /**\n * Gets the type of the node.\n */\n getType = () => this.type;\n\n /**\n * Gets the node attributes.\n */\n getAttributes = () => this.attributes;\n\n /**\n * Gets the node arguments.\n */\n getArguments = () => this.args;\n\n /**\n * Gets the node attribute with the specified type, or null if it does not exist.\n */\n getAttribute(type: \"entry\" | \"ENTRY\"): Entry;\n getAttribute(type: \"exit\" | \"EXIT\"): Exit;\n getAttribute(type: \"step\" | \"STEP\"): Step;\n getAttribute(type: string): Attribute {\n return (\n this.getAttributes().filter((decorator) => decorator.type.toUpperCase() === type.toUpperCase())[0] || null\n );\n }\n\n /**\n * Gets the node attributes.\n */\n getGuardAttributes = (): Guard[] => this.getAttributes().filter((decorator) => decorator.isGuard()) as Guard[];\n\n /**\n * Sets the guard path to evaluate as part of a node update.\n */\n setGuardPath = (value: GuardPath) => (this.guardPath = value);\n\n /**\n * Gets whether a guard path is assigned to this node.\n */\n hasGuardPath = () => !!this.guardPath;\n\n /**\n * Gets whether this node is in the specified state.\n * @param value The value to compare to the node state.\n */\n public is(value: AnyState): boolean {\n return this.state === value;\n }\n\n /**\n * Reset the state of the node.\n */\n public reset(): void {\n this.setState(State.READY);\n }\n\n /**\n * Abort the running of this node.\n * @param agent The agent.\n */\n public abort(agent: Agent): void {\n // There is nothing to do if this node is not in the running state.\n if (!this.is(State.RUNNING)) {\n return;\n }\n\n // Reset the state of this node.\n this.reset();\n\n this.getAttribute(\"exit\")?.callAgentFunction(agent, false, true);\n }\n\n /**\n * Update the node.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n * @returns The result of the update.\n */\n public update(agent: Agent, options: BehaviourTreeOptions): void {\n // If this node is already in a 'SUCCEEDED' or 'FAILED' state then there is nothing to do.\n if (this.is(State.SUCCEEDED) || this.is(State.FAILED)) {\n return;\n }\n\n try {\n // Evaluate all of the guard path conditions for the current tree path.\n this.guardPath!.evaluate(agent);\n\n // If this node is in the READY state then call the ENTRY for this node if it exists.\n if (this.is(State.READY)) {\n this.getAttribute(\"entry\")?.callAgentFunction(agent);\n }\n\n this.getAttribute(\"step\")?.callAgentFunction(agent);\n\n // Do the actual update.\n this.onUpdate(agent, options);\n\n // If this node is now in a 'SUCCEEDED' or 'FAILED' state then call the EXIT for this node if it exists.\n if (this.is(State.SUCCEEDED) || this.is(State.FAILED)) {\n this.getAttribute(\"exit\")?.callAgentFunction(agent, this.is(State.SUCCEEDED), false);\n }\n } catch (error) {\n // If the error is a GuardUnsatisfiedException then we need to determine if this node is the source.\n if (error instanceof GuardUnsatisifedException && error.isSourceNode(this)) {\n // Abort the current node.\n this.abort(agent);\n\n // Any node that is the source of an abort will be a failed node.\n this.setState(State.FAILED);\n } else {\n throw error;\n }\n }\n }\n}\n\n/**\n * Create a randomly generated node uid.\n * @returns A randomly generated node uid.\n */\nfunction createNodeUid(): string {\n var S4 = function () {\n return (((1 + Math.random()) * 0x10000) | 0).toString(16).substring(1);\n };\n return S4() + S4() + \"-\" + S4() + \"-\" + S4() + \"-\" + S4() + \"-\" + S4() + S4() + S4();\n}\n", "import Node from \"../Node\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\n\n/**\n * A decorator node that wraps a single child node.\n */\nexport default abstract class Decorator extends Node {\n /**\n * @param type The node type.\n * @param attributes The node attributes.\n * @param child The child node.\n */\n constructor(type: string, attributes: Attribute[], protected child: Node) {\n super(type, attributes, []);\n }\n\n /**\n * Gets whether this node is a leaf node.\n */\n isLeafNode = () => false;\n\n /**\n * Gets the children of this node.\n */\n getChildren = () => [this.child];\n\n /**\n * Reset the state of the node.\n */\n reset = () => {\n // Reset the state of this node.\n this.setState(State.READY);\n\n // Reset the state of the child node.\n this.child.reset();\n };\n\n /**\n * Abort the running of this node.\n * @param agent The agent.\n */\n abort = (agent: Agent) => {\n // There is nothing to do if this node is not in the running state.\n if (!this.is(State.RUNNING)) {\n return;\n }\n\n // Abort the child node.\n this.child.abort(agent);\n\n // Reset the state of this node.\n this.reset();\n\n this.getAttribute(\"exit\")?.callAgentFunction(agent, false, true);\n };\n}\n", "import Node from \"../Node\";\nimport Decorator from \"./Decorator\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A Root node.\n * The root node will have a single child.\n */\nexport default class Root extends Decorator {\n /**\n * @param attributes The node attributes.\n * @param child The child node.\n */\n constructor(attributes: Attribute[], child: Node) {\n super(\"root\", attributes, child);\n }\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // If the child has never been updated or is running then we will need to update it now.\n if (this.child.getState() === State.READY || this.child.getState() === State.RUNNING) {\n // Update the child of this node.\n this.child.update(agent, options);\n }\n\n // The state of the root node is the state of its child.\n this.setState(this.child.getState());\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => \"ROOT\";\n}\n", "import Guard from \"./guards/Guard\";\n\nexport type AttributeDetails = {\n /** The attribute type. */\n type: string;\n\n /** The attribute arguments. */\n args: any[];\n};\n\n/**\n * A base node attribute.\n */\nexport default abstract class Attribute {\n /**\n * @param type The node attribute type.\n * @param args The array of attribute arguments.\n */\n constructor(public type: string, public args: any[]) {}\n\n /**\n * Gets the attribute details.\n */\n abstract getDetails(): TAttributeDetails;\n\n /**\n * Gets whether this attribute is a guard.\n */\n abstract isGuard: () => this is Guard;\n}\n", "import { Agent } from \"../../Agent\";\nimport Attribute, { AttributeDetails } from \"../Attribute\";\n\nexport type GuardAttributeDetails = {\n /** The name of the condition function that determines whether the guard is satisfied. */\n condition: string;\n} & AttributeDetails;\n\n/**\n * A base node guard attribute.\n */\nexport default abstract class Guard extends Attribute {\n /**\n * @param type The node attribute type.\n * @param args The array of decorator argument definitions.\n * @param condition The name of the condition function that determines whether the guard is satisfied.\n */\n constructor(type: string, args: any[], private condition: string) {\n super(type, args);\n }\n\n /**\n * Gets the name of the condition function that determines whether the guard is satisfied.\n */\n getCondition = () => this.condition;\n\n /**\n * Gets whether this attribute is a guard.\n */\n isGuard = () => true;\n\n /**\n * Gets the attribute details.\n */\n getDetails(): GuardAttributeDetails {\n return {\n type: this.type,\n args: this.args,\n condition: this.getCondition()\n };\n }\n\n /**\n * Gets whether the guard is satisfied.\n * @param agent The agent.\n * @returns Whether the guard is satisfied.\n */\n abstract isSatisfied(agent: Agent): boolean;\n}\n", "import Guard from \"./Guard\";\nimport Lookup from \"../../Lookup\";\nimport { Agent } from \"../../Agent\";\n\n/**\n * A WHILE guard which is satisfied as long as the given condition remains true.\n */\nexport default class While extends Guard {\n /**\n * @param condition The name of the condition function that determines whether the guard is satisfied.\n * @param args The array of decorator argument definitions.\n */\n constructor(condition: string, args: any[]) {\n super(\"while\", args, condition);\n }\n\n /**\n * Gets whether the guard is satisfied.\n * @param agent The agent.\n * @returns Whether the guard is satisfied.\n */\n isSatisfied = (agent: Agent) => {\n // Attempt to get the invoker for the condition function.\n const conditionFuncInvoker = Lookup.getFuncInvoker(agent, this.getCondition());\n\n // The condition function should be defined.\n if (conditionFuncInvoker === null) {\n throw new Error(\n `cannot evaluate node guard as the condition '${this.getCondition()}' function is not defined on the agent and has not been registered`\n );\n }\n\n // Call the condition function to determine whether this guard is satisfied.\n return !!conditionFuncInvoker(this.args);\n };\n}\n", "import Guard from \"./Guard\";\nimport Lookup from \"../../Lookup\";\nimport { Agent } from \"../../Agent\";\n\n/**\n * An UNTIL guard which is satisfied as long as the given condition remains false.\n */\nexport default class Until extends Guard {\n /**\n * @param condition The name of the condition function that determines whether the guard is satisfied.\n * @param args The array of decorator argument definitions.\n */\n constructor(condition: string, args: any[]) {\n super(\"until\", args, condition);\n }\n\n /**\n * Gets whether the guard is satisfied.\n * @param agent The agent.\n * @returns Whether the guard is satisfied.\n */\n isSatisfied = (agent: Agent) => {\n // Attempt to get the invoker for the condition function.\n const conditionFuncInvoker = Lookup.getFuncInvoker(agent, this.getCondition());\n\n // The condition function should be defined.\n if (conditionFuncInvoker === null) {\n throw new Error(\n `cannot evaluate node guard as the condition '${this.getCondition()}' function is not defined on the agent and has not been registered`\n );\n }\n\n // Call the condition function to determine whether this guard is satisfied.\n return !!!conditionFuncInvoker(this.args);\n };\n}\n", "import { Agent } from \"../../Agent\";\nimport Attribute, { AttributeDetails } from \"../Attribute\";\n\nexport type CallbackAttributeDetails = {\n /** The name of the agent function that is called. */\n functionName: string;\n} & AttributeDetails;\n\n/**\n * A base node callback attribute.\n */\nexport default abstract class Callback extends Attribute {\n /**\n * @param type The node attribute type.\n * @param args The array of decorator argument definitions.\n * @param functionName The name of the agent function to call.\n */\n constructor(type: string, args: any[], private functionName: string) {\n super(type, args);\n }\n\n /**\n * Gets the name of the agent function to call.\n */\n getFunctionName = () => this.functionName;\n\n /**\n * Gets whether this attribute is a guard.\n */\n isGuard = () => false;\n\n /**\n * Gets the attribute details.\n */\n getDetails(): CallbackAttributeDetails {\n return {\n type: this.type,\n args: this.args,\n functionName: this.getFunctionName()\n };\n }\n\n /**\n * Attempt to call the agent function that this callback refers to.\n * @param agent The agent.\n */\n abstract callAgentFunction: (agent: Agent, isSuccess: boolean, isAborted: boolean) => void;\n}\n", "import Callback from \"./Callback\";\nimport Lookup from \"../../Lookup\";\nimport { Agent } from \"../../Agent\";\n\n/**\n * An ENTRY callback which defines an agent function to call when the associated node is updated and moves out of running state.\n */\nexport default class Entry extends Callback {\n /**\n * @param functionName The name of the agent function to call.\n * @param args The array of callback argument definitions.\n */\n constructor(functionName: string, args: any[]) {\n super(\"entry\", args, functionName);\n }\n\n /**\n * Attempt to call the agent function that this callback refers to.\n * @param agent The agent.\n */\n callAgentFunction = (agent: Agent) => {\n // Attempt to get the invoker for the callback function.\n const callbackFuncInvoker = Lookup.getFuncInvoker(agent, this.getFunctionName());\n\n // The callback function should be defined.\n if (callbackFuncInvoker === null) {\n throw new Error(\n `cannot call entry function '${this.getFunctionName()}' as is not defined on the agent and has not been registered`\n );\n }\n\n // Call the callback function.\n callbackFuncInvoker(this.args);\n };\n}\n", "import Callback from \"./Callback\";\nimport Lookup from \"../../Lookup\";\nimport { Agent } from \"../../Agent\";\n\n/**\n * A STEP callback which defines an agent function to call when the associated node is updated.\n */\nexport default class Step extends Callback {\n /**\n * @param functionName The name of the agent function to call.\n * @param args The array of callback argument definitions.\n */\n constructor(functionName: string, args: any[]) {\n super(\"step\", args, functionName);\n }\n\n /**\n * Attempt to call the agent function that this callback refers to.\n * @param agent The agent.\n */\n callAgentFunction = (agent: Agent) => {\n // Attempt to get the invoker for the callback function.\n const callbackFuncInvoker = Lookup.getFuncInvoker(agent, this.getFunctionName());\n\n // The callback function should be defined.\n if (callbackFuncInvoker === null) {\n throw new Error(\n `cannot call step function '${this.getFunctionName()}' as is not defined on the agent and has not been registered`\n );\n }\n\n // Call the callback function.\n callbackFuncInvoker(this.args);\n };\n}\n", "import Callback from \"./Callback\";\nimport Lookup from \"../../Lookup\";\nimport { Agent } from \"../../Agent\";\n\n/**\n * An EXIT callback which defines an agent function to call when the associated node is updated and moves to a finished state or is aborted.\n */\nexport default class Exit extends Callback {\n /**\n * @param functionName The name of the agent function to call.\n * @param args The array of callback argument definitions.\n */\n constructor(functionName: string, args: any[]) {\n super(\"exit\", args, functionName);\n }\n\n /**\n * Attempt to call the agent function that this callback refers to.\n * @param agent The agent.\n * @param isSuccess Whether the decorated node was left with a success state.\n * @param isAborted Whether the decorated node was aborted.\n */\n callAgentFunction = (agent: Agent, isSuccess: boolean, isAborted: boolean) => {\n // Attempt to get the invoker for the callback function.\n const callbackFuncInvoker = Lookup.getFuncInvoker(agent, this.getFunctionName());\n\n // The callback function should be defined.\n if (callbackFuncInvoker === null) {\n throw new Error(\n `cannot call exit function '${this.getFunctionName()}' as is not defined on the agent and has not been registered`\n );\n }\n\n // Call the callback function\n callbackFuncInvoker([{ value: { succeeded: isSuccess, aborted: isAborted } }, ...this.args]);\n };\n}\n", "import { AnyNodeDefinition, RootNodeDefinition } from \"./BehaviourTreeDefinition\";\nimport GuardPath, { GuardPathPart } from \"./attributes/guards/GuardPath\";\nimport { validateBranchSubtreeLinks } from \"./BehaviourTreeDefinitionValidator\";\nimport Node from \"./nodes/Node\";\nimport Composite from \"./nodes/composite/Composite\";\nimport Decorator from \"./nodes/decorator/Decorator\";\nimport Parallel from \"./nodes/composite/Parallel\";\nimport Selector from \"./nodes/composite/Selector\";\nimport Sequence from \"./nodes/composite/Sequence\";\nimport Lotto from \"./nodes/composite/Lotto\";\nimport Fail from \"./nodes/decorator/Fail\";\nimport Flip from \"./nodes/decorator/Flip\";\nimport Repeat from \"./nodes/decorator/Repeat\";\nimport Retry from \"./nodes/decorator/Retry\";\nimport Root from \"./nodes/decorator/Root\";\nimport Succeed from \"./nodes/decorator/Succeed\";\nimport Action from \"./nodes/leaf/Action\";\nimport Condition from \"./nodes/leaf/Condition\";\nimport Wait from \"./nodes/leaf/Wait\";\nimport Lookup from \"./Lookup\";\nimport Attribute from \"./attributes/Attribute\";\nimport While from \"./attributes/guards/While\";\nimport Until from \"./attributes/guards/Until\";\nimport Entry from \"./attributes/callbacks/Entry\";\nimport Step from \"./attributes/callbacks/Step\";\nimport Exit from \"./attributes/callbacks/Exit\";\n\n/**\n * A type representing any node instance in a behaviour tree.\n */\ntype AnyNode =\n | Root\n | Action\n | Condition\n | Wait\n | Sequence\n | Selector\n | Lotto\n | Parallel\n | Repeat\n | Retry\n | Flip\n | Succeed\n | Fail;\n\n/**\n * A type defining a mapping of root node identifiers to root node definitions.\n */\ntype RootNodeDefinitionMap = { [key: string | symbol]: RootNodeDefinition };\n\n/**\n * A symbol to use as the main root key in any root node mappings.\n */\nconst MAIN_ROOT_NODE_KEY = Symbol(\"__root__\");\n\n/**\n * Build and populate the root nodes based on the provided definition, assuming that the definition has been validated.\n * @param definition The root node definitions.\n * @returns The built and populated root node definitions.\n */\nexport default function buildRootNode(definition: RootNodeDefinition[]): Root {\n // Create a mapping of root node identifers to root node definitions, including globally registered subtree root node definitions.\n const rootNodeDefinitionMap = createRootNodeDefinitionMap(definition);\n\n // Now that we have all of our root node definitons (those part of the tree definition and those globally\n // registered) we should validate the definition. This will also double-check that we dont have any circular\n // dependencies in our branch -> subtree references and that we have no broken branch -> subtree links.\n validateBranchSubtreeLinks(definition, true);\n\n // Create our populated tree of node instances, starting with our main root node.\n const rootNode = nodeFactory(rootNodeDefinitionMap[MAIN_ROOT_NODE_KEY]) as Root;\n\n // Set a guard path on every leaf of the tree to evaluate as part of its update.\n applyLeafNodeGuardPaths(rootNode);\n\n // We only need to return the main root node.\n return rootNode;\n}\n\n/**\n * A factory function which creates a node instance based on the specified definition.\n * @param definition The node definition.\n * @returns A node instance based on the specified definition.\n */\nfunction nodeFactory(definition: AnyNodeDefinition): AnyNode {\n // Get the attributes for the node.\n const attributes = nodeAttributesFactory(definition);\n\n // Create the node instance based on the definition type.\n switch (definition.type) {\n case \"root\":\n return new Root(attributes, nodeFactory(definition.child));\n\n // ...\n\n default:\n throw new Error(`unexpected node type of '${definition.type}'`);\n }\n}\n\n/**\n * Creates an array of node attribute instances based on the specified node definition.\n * @param definition The node definition.\n * @returns An array of node attribute instances based on the specified node definition.\n */\nfunction nodeAttributesFactory(definition: AnyNodeDefinition): Attribute[] {\n const attributes: Attribute[] = [];\n\n if (definition.while) {\n attributes.push(new While(definition.while.call, definition.while.args ?? []));\n }\n\n if (definition.until) {\n attributes.push(new Until(definition.until.call, definition.until.args ?? []));\n }\n\n if (definition.entry) {\n attributes.push(new Entry(definition.entry.call, definition.entry.args ?? []));\n }\n\n if (definition.step) {\n attributes.push(new Step(definition.step.call, definition.step.args ?? []));\n }\n\n if (definition.exit) {\n attributes.push(new Exit(definition.exit.call, definition.exit.args ?? []));\n }\n\n return attributes;\n}\n\n/**\n * Creates a mapping of root node identifers to root node definitions, mixing in globally registered subtree root node definitions.\n * @param definition The root node definitions.\n * @returns A mapping of root node identifers to root node definitions, including globally registered subtree root node definitions.\n */\nfunction createRootNodeDefinitionMap(definition: RootNodeDefinition[]): RootNodeDefinitionMap {\n // Create a mapping of root node identifers to root node definitions.\n const rootNodeMap: RootNodeDefinitionMap = {};\n\n // Add in any registered subtree root node definitions.\n for (const [name, rootNodeDefinition] of Object.entries(Lookup.getSubtrees())) {\n // The name used when registering the subtree will be used as the root node identifier.\n rootNodeMap[name] = { ...rootNodeDefinition, id: name };\n }\n\n // Populate the map with the root node definitions that were included with the tree definition.\n // We do this after adding any registered subtrees as we want these to take presedence.\n for (const rootNodeDefinition of definition) {\n rootNodeMap[rootNodeDefinition.id ?? MAIN_ROOT_NODE_KEY] = rootNodeDefinition;\n }\n\n return rootNodeMap;\n}\n\n/**\n * Applies a guard path to every leaf of the tree to evaluate as part of each update.\n * @param root The main root tree node.\n */\nfunction applyLeafNodeGuardPaths(root: Root) {\n const nodePaths: Node[][] = [];\n\n const findLeafNodes = (path: Node[], node: Node) => {\n // Add the current node to the path.\n path = path.concat(node);\n\n // Check whether the current node is a leaf node.\n if (node.isLeafNode()) {\n nodePaths.push(path);\n } else {\n (node as Composite | Decorator).getChildren().forEach((child) => findLeafNodes(path, child));\n }\n };\n\n // Find all leaf node paths, starting from the root.\n findLeafNodes([], root);\n\n nodePaths.forEach((path) => {\n // Each node in the current path will have to be assigned a guard path, working from the root outwards.\n for (let depth = 0; depth < path.length; depth++) {\n // Get the node in the path at the current depth.\n const currentNode = path[depth];\n\n // The node may already have been assigned a guard path, if so just skip it.\n if (currentNode.hasGuardPath()) {\n continue;\n }\n\n // Create the guard path for the current node.\n const guardPath = new GuardPath(\n path\n .slice(0, depth + 1)\n .map((node) => ({ node, guards: node.getGuardAttributes() }))\n .filter((details) => details.guards.length > 0)\n );\n\n // Assign the guard path to the current node.\n currentNode.setGuardPath(guardPath);\n }\n });\n}\n", "import State, { AnyState } from \"./State\";\nimport Lookup from \"./Lookup\";\nimport Node from \"./nodes/Node\";\nimport Root from \"./nodes/decorator/Root\";\nimport Composite from \"./nodes/composite/Composite\";\nimport Decorator from \"./nodes/decorator/Decorator\";\nimport { Agent, GlobalFunction } from \"./Agent\";\nimport { CallbackAttributeDetails } from \"./attributes/callbacks/Callback\";\nimport { GuardAttributeDetails } from \"./attributes/guards/Guard\";\nimport { BehaviourTreeOptions } from \"./BehaviourTreeOptions\";\nimport { convertMDSLToJSON } from \"./mdsl/MDSLDefinitionParser\";\nimport { RootNodeDefinition } from \"./BehaviourTreeDefinition\";\nimport { validateJSONDefinition } from \"./BehaviourTreeDefinitionValidator\";\nimport buildRootNode from \"./BehaviourTreeBuilder\";\n\n// Purely for outside inspection of the tree.\nexport type FlattenedTreeNode = {\n id: string;\n type: string;\n caption: string;\n state: AnyState;\n guards: GuardAttributeDetails[];\n callbacks: CallbackAttributeDetails[];\n args: any[];\n parentId: string | null;\n};\n\n/**\n * A representation of a behaviour tree.\n */\nexport class BehaviourTree {\n /**\n * The main root tree node.\n */\n public readonly rootNode: Root;\n\n /**\n * Creates a new instance of the BehaviourTree class.\n * @param definition The behaviour tree definition.\n * @param agent The agent instance that this behaviour tree is modelling behaviour for.\n * @param options The behaviour tree options object.\n */\n constructor(\n definition: string | RootNodeDefinition | RootNodeDefinition[],\n private agent: Agent,\n private options: BehaviourTreeOptions = {}\n ) {\n // The tree definition must be defined.\n if (!definition) {\n throw new Error(\"the tree definition must be a string ro\");\n }\n\n // The agent must be defined and not null.\n if (typeof agent !== \"object\" || agent === null) {\n throw new Error(\"the agent must be defined and not null\");\n }\n\n try {\n // Parse the behaviour tree definition, create the populated tree of behaviour tree nodes, and get the root.\n this.rootNode = this._createRootNode(definition);\n } catch (exception) {\n // There was an issue in trying build and populate the behaviour tree.\n throw new Error(`error building tree: ${(exception as Error).message}`);\n }\n }\n\n /**\n * Gets whether the tree is in the RUNNING state.\n * @returns true if the tree is in the RUNNING state, otherwise false.\n */\n isRunning() {\n return this.rootNode.getState() === State.RUNNING;\n }\n\n /**\n * Gets the current tree state of SUCCEEDED, FAILED, READY or RUNNING.\n * @returns The current tree state.\n */\n getState() {\n return this.rootNode.getState();\n }\n\n /**\n * Step the tree.\n * 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.\n * 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\n * 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.\n *\n * 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.\n */\n step() {\n // If the root node has already been stepped to completion then we need to reset it.\n if (this.rootNode.getState() === State.SUCCEEDED || this.rootNode.getState() === State.FAILED) {\n this.rootNode.reset();\n }\n\n try {\n this.rootNode.update(this.agent, this.options);\n } catch (exception) {\n throw new Error(`error stepping tree: ${(exception as Error).message}`);\n }\n }\n\n /**\n * Resets the tree from the root node outwards to each nested node, giving each a state of READY.\n */\n reset() {\n this.rootNode.reset();\n }\n\n /**\n * Gets the flattened details of every node in the tree.\n * @returns The flattened details of every node in the tree.\n */\n getFlattenedNodeDetails(): FlattenedTreeNode[] {\n // Create an empty flattened array of tree nodes.\n const flattenedTreeNodes: FlattenedTreeNode[] = [];\n\n /**\n * Helper function to process a node instance and push details into the flattened tree nodes array.\n * @param node The current node.\n * @param parentUid The UID of the node parent, or null if the node is the main root node.\n */\n const processNode = (node: Node, parentUid: string | null) => {\n // Get the guard and callback attribute details for this node.\n const guards = node\n .getAttributes()\n .filter((attribute) => attribute.isGuard())\n .map((attribute) => attribute.getDetails()) as GuardAttributeDetails[];\n const callbacks = node\n .getAttributes()\n .filter((attribute) => !attribute.isGuard())\n .map((attribute) => attribute.getDetails()) as CallbackAttributeDetails[];\n\n // Push the current node into the flattened nodes array.\n flattenedTreeNodes.push({\n id: node.getUid(),\n type: node.getType(),\n caption: node.getName(),\n state: node.getState(),\n guards,\n callbacks,\n args: node.getArguments(),\n parentId: parentUid\n });\n\n // Process each of the nodes children if it is not a leaf node.\n if (!node.isLeafNode()) {\n (node as Composite | Decorator)\n .getChildren()\n .forEach((child) => processNode(child, (node as Composite | Decorator).getUid()));\n }\n };\n\n // Convert the nested node structure into a flattened array of node details.\n processNode(this.rootNode, null);\n\n return flattenedTreeNodes;\n }\n\n /**\n * Registers the action/condition/guard/callback function or subtree with the given name.\n * @param name The name of the function or subtree to register.\n * @param value The function or subtree definition to register.\n */\n static register(name: string, value: GlobalFunction | string | RootNodeDefinition) {\n // Are we going to register a action/condition/guard/callback function?\n if (typeof value === \"function\") {\n Lookup.setFunc(name, value);\n return;\n }\n\n // We are not registering an action/condition/guard/callback function, so we must be registering a subtree.\n if (typeof value === \"string\") {\n let rootNodeDefinitions: RootNodeDefinition[];\n\n // We will assume that any string passed in will be a mdsl definition.\n try {\n rootNodeDefinitions = convertMDSLToJSON(value);\n } catch (exception) {\n throw new Error(`error registering definition, invalid MDSL: ${(exception as Error).message}`);\n }\n\n // This function should only ever be called with a definition containing a single unnamed root node.\n if (rootNodeDefinitions.length != 1 || rootNodeDefinitions[0].id !== null) {\n throw new Error(\"error registering definition: expected a single unnamed root node\");\n }\n\n try {\n // We should validate the subtree as we don't want invalid subtrees available via the lookup.\n const { succeeded, errorMessage } = validateJSONDefinition(rootNodeDefinitions[0]);\n\n // Did our validation fail without error?\n if (!succeeded) {\n throw new Error(errorMessage);\n }\n } catch (exception) {\n throw new Error(`error registering definition: ${(exception as Error).message}`);\n }\n\n // Everything seems hunky-dory, register the subtree.\n Lookup.setSubtree(name, rootNodeDefinitions[0]);\n } else if (typeof value === \"object\" && !Array.isArray(value)) {\n // We will assume that any object passed in is a root node definition.\n\n try {\n // We should validate the subtree as we don't want invalid subtrees available via the lookup.\n const { succeeded, errorMessage } = validateJSONDefinition(value);\n\n // Did our validation fail without error?\n if (!succeeded) {\n throw new Error(errorMessage);\n }\n } catch (exception) {\n throw new Error(`error registering definition: ${(exception as Error).message}`);\n }\n\n // Everything seems hunky-dory, register the subtree.\n Lookup.setSubtree(name, value);\n } else {\n throw new Error(\"unexpected value, expected string mdsl definition, root node json definition or function\");\n }\n }\n\n /**\n * Unregisters the registered action/condition/guard/callback function or subtree with the given name.\n * @param name The name of the registered action/condition/guard/callback function or subtree to unregister.\n */\n static unregister(name: string): void {\n Lookup.remove(name);\n }\n\n /**\n * Unregister all registered action/condition/guard/callback functions and subtrees.\n */\n static unregisterAll(): void {\n Lookup.empty();\n }\n\n /**\n * Parses a behaviour tree definition and creates a tree of behaviour tree nodes populated at a root.\n * @param {string | RootNodeDefinition | RootNodeDefinition[]} definition The behaviour tree definition.\n * @returns The root behaviour tree node.\n */\n private _createRootNode(definition: string | RootNodeDefinition | RootNodeDefinition[]): Root {\n let resolvedDefinition: RootNodeDefinition | RootNodeDefinition[];\n\n // If the definition is a string then we will assume that it is an mdsl string which needs to be converted to a JSON definition.\n if (typeof definition === \"string\") {\n try {\n resolvedDefinition = convertMDSLToJSON(definition);\n } catch (exception) {\n throw new Error(`invalid mdsl definition: ${(exception as Error).message}`);\n }\n } else {\n // The definition is not a string, so we should assume that it is already a JSON definition.\n resolvedDefinition = definition;\n }\n\n // Build and populate the root node.\n return buildRootNode(Array.isArray(resolvedDefinition) ? resolvedDefinition : [resolvedDefinition]);\n }\n}\n"], - "mappings": "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", - "names": ["State"] + "sources": ["../node_modules/lotto-draw/dist/Participant.js", "../node_modules/lotto-draw/dist/Utilities.js", "../node_modules/lotto-draw/dist/Lotto.js", "../node_modules/lotto-draw/dist/createLotto.js", "../node_modules/lotto-draw/dist/index.js", "../src/index.ts", "../src/State.ts", "../src/BehaviourTreeDefinitionUtilities.ts", "../src/mdsl/MDSLUtilities.ts", "../src/mdsl/MDSLNodeArgumentParser.ts", "../src/mdsl/MDSLNodeAttributeParser.ts", "../src/mdsl/MDSLDefinitionParser.ts", "../src/BehaviourTreeDefinitionValidator.ts", "../src/Lookup.ts", "../src/attributes/guards/GuardUnsatisifedException.ts", "../src/attributes/guards/GuardPath.ts", "../src/nodes/Node.ts", "../src/nodes/composite/Composite.ts", "../src/nodes/composite/Parallel.ts", "../src/nodes/composite/Selector.ts", "../src/nodes/composite/Sequence.ts", "../src/nodes/composite/Lotto.ts", "../src/nodes/decorator/Decorator.ts", "../src/nodes/decorator/Fail.ts", "../src/nodes/decorator/Flip.ts", "../src/nodes/decorator/Repeat.ts", "../src/nodes/decorator/Retry.ts", "../src/nodes/decorator/Root.ts", "../src/nodes/decorator/Succeed.ts", "../src/nodes/leaf/Leaf.ts", "../src/nodes/leaf/Action.ts", "../src/nodes/leaf/Condition.ts", "../src/nodes/leaf/Wait.ts", "../src/attributes/Attribute.ts", "../src/attributes/guards/Guard.ts", "../src/attributes/guards/While.ts", "../src/attributes/guards/Until.ts", "../src/attributes/callbacks/Callback.ts", "../src/attributes/callbacks/Entry.ts", "../src/attributes/callbacks/Step.ts", "../src/attributes/callbacks/Exit.ts", "../src/BehaviourTreeBuilder.ts", "../src/BehaviourTree.ts"], + "sourcesContent": ["\"use strict\";\r\nObject.defineProperty(exports, \"__esModule\", { value: true });\r\nexports.Participant = void 0;\r\n/**\r\n * A participant that holds a number of tickets.\r\n */\r\nvar Participant = /** @class */ (function () {\r\n /**\r\n * Creates an instance of the Participant class.\r\n * @param participant The actual participant.\r\n * @param tickets The number of tickets held by the participant.\r\n */\r\n function Participant(participant, tickets) {\r\n if (tickets === void 0) { tickets = 1; }\r\n this._participant = participant;\r\n this._tickets = tickets;\r\n }\r\n Object.defineProperty(Participant.prototype, \"participant\", {\r\n /** Gets the actual participant. */\r\n get: function () {\r\n return this._participant;\r\n },\r\n enumerable: false,\r\n configurable: true\r\n });\r\n Object.defineProperty(Participant.prototype, \"tickets\", {\r\n /** Gets or sets the number of tickets held by the participant. */\r\n get: function () {\r\n return this._tickets;\r\n },\r\n set: function (value) {\r\n this._tickets = value;\r\n },\r\n enumerable: false,\r\n configurable: true\r\n });\r\n return Participant;\r\n}());\r\nexports.Participant = Participant;\r\n", "\"use strict\";\r\nObject.defineProperty(exports, \"__esModule\", { value: true });\r\nexports.isNaturalNumber = exports.isNullOrUndefined = void 0;\r\n/**\r\n * Gets whether the value provided is null or undefined.\r\n * @param value The value to check.\r\n * @returns Whether the value provided is null or undefined.\r\n */\r\nfunction isNullOrUndefined(value) {\r\n return value === null || value === undefined;\r\n}\r\nexports.isNullOrUndefined = isNullOrUndefined;\r\n/**\r\n * Gets whether the value provided is a natural number.\r\n * @param value The value to check.\r\n * @returns Whether the value provided is a natural number.\r\n */\r\nfunction isNaturalNumber(value) {\r\n return typeof value === \"number\" && value >= 1 && Math.floor(value) === value;\r\n}\r\nexports.isNaturalNumber = isNaturalNumber;\r\n", "\"use strict\";\r\nObject.defineProperty(exports, \"__esModule\", { value: true });\r\nexports.Lotto = void 0;\r\nvar Participant_1 = require(\"./Participant\");\r\nvar Utilities_1 = require(\"./Utilities\");\r\n/**\r\n * Represents a lotto consisting of a number of pickable ticket-holding participants.\r\n */\r\nvar Lotto = /** @class */ (function () {\r\n /**\r\n * Creates a new instance of Lotto.\r\n * @param customRandom The custom RNG to use in place of Math.random().\r\n */\r\n function Lotto(customRandom) {\r\n /** The array of participants that are holding tickets in the lotto. */\r\n this._participants = [];\r\n this._customRandom = customRandom;\r\n }\r\n /**\r\n * Adds a participant with the specified number of tickets, or adds to the participant ticket count if the participant already holds tickets.\r\n * @param participant The participant to add or to increase the ticket count for if they already hold tickets.\r\n * @param tickets The number of tickets, defaults to 1.\r\n * @returns The Lotto instance.\r\n */\r\n Lotto.prototype.add = function (participant, tickets) {\r\n if (tickets === void 0) { tickets = 1; }\r\n // Check that we have a valid ticket count.\r\n if (!(0, Utilities_1.isNaturalNumber)(tickets)) {\r\n throw new Error(\"tickets value must be a natural number\");\r\n }\r\n // Check whether this participant has already been added.\r\n var existingParticipant = this._participants.find(function (part) { return part.participant === participant; });\r\n if (existingParticipant) {\r\n // The participant has already been added to the lotto so just add to their ticket count.\r\n existingParticipant.tickets += tickets;\r\n }\r\n else {\r\n // The participant is not part of the lotto so we should add them.\r\n this._participants.push(new Participant_1.Participant(participant, tickets));\r\n }\r\n return this;\r\n };\r\n /**\r\n * Removes the specified number of tickets for the given participant from the draw, or all tickets if a ticket number is not defined.\r\n * @param participant The participant to remove tickets for.\r\n * @param tickets The number of tickets to remove, or undefined if all tickets are to be removed.\r\n * @returns The Lotto instance.\r\n */\r\n Lotto.prototype.remove = function (participant, tickets) {\r\n // Attempt to get the existing participant.\r\n var existingParticipant = this._participants.find(function (part) { return part.participant === participant; });\r\n // There is nothing to do if the specified participant isn't even part of the lotto.\r\n if (!existingParticipant) {\r\n return this;\r\n }\r\n // Check whether a tickets value was given.\r\n if (tickets !== undefined) {\r\n // Check that we have a valid ticket count.\r\n if (!(0, Utilities_1.isNaturalNumber)(tickets)) {\r\n throw new Error(\"tickets value must be a natural number\");\r\n }\r\n existingParticipant.tickets -= tickets;\r\n // If the participant no longer holds any tickets then they should be removed.\r\n if (existingParticipant.tickets < 1) {\r\n this._participants = this._participants.filter(function (part) { return part !== existingParticipant; });\r\n }\r\n }\r\n else {\r\n // We are removing all tickets for the participant so just remove them from the lotto.\r\n this._participants = this._participants.filter(function (part) { return part !== existingParticipant; });\r\n }\r\n return this;\r\n };\r\n /**\r\n * Draw a winning ticket and return the participant that holds the ticket.\r\n * @param options The draw options.\r\n * @returns The participant that holds the winning ticket.\r\n */\r\n Lotto.prototype.draw = function (options) {\r\n if (options === void 0) { options = {}; }\r\n // If we have no participants then just return null.\r\n if (this._participants.length === 0) {\r\n return null;\r\n }\r\n var redrawable = (0, Utilities_1.isNullOrUndefined)(options.redrawable) ? true : options.redrawable;\r\n var pickable = [];\r\n this._participants.forEach(function (_a) {\r\n var participant = _a.participant, tickets = _a.tickets;\r\n for (var ticketCount = 0; ticketCount < tickets; ticketCount++) {\r\n pickable.push(participant);\r\n }\r\n });\r\n var random;\r\n // We need a random floating-point number between 0 (inclusive) and 1 to scale up to pick our winner.\r\n // If a custom random function exists then we should use that or fall back to Math.random().\r\n if (this._customRandom) {\r\n // Call our custom random function to get a random floating-point number.\r\n random = this._customRandom();\r\n // Verify that the result of calling our custom random function is a number between 0 (inclusive) and 1.\r\n if (typeof random !== \"number\" || random < 0 || random >= 1) {\r\n throw new Error(\"the 'random' function provided did not return a number between 0 (inclusive) and 1\");\r\n }\r\n }\r\n else {\r\n // No custom random function was defined so just use good ol' Math.random().\r\n random = Math.random();\r\n }\r\n // Pick a winning participant.\r\n var winner = pickable[Math.floor(random * pickable.length)];\r\n // If the ticket isn't redrawable then we should remove a ticket from the winning participants ticket count.\r\n if (!redrawable) {\r\n this.remove(winner, 1);\r\n }\r\n // Return the winning participant.\r\n return winner;\r\n };\r\n /**\r\n * Draws multiple winning tickets and return an array of the participants that hold the winning tickets.\r\n * @param tickets The number of winning tickets to draw.\r\n * @param options The draw multiple options.\r\n * @returns An array of the participants that hold the winning tickets.\r\n */\r\n Lotto.prototype.drawMultiple = function (tickets, options) {\r\n if (options === void 0) { options = {}; }\r\n var uniqueResults = (0, Utilities_1.isNullOrUndefined)(options.unique) ? false : options.unique;\r\n // Handle cases where the user has asked for zero tickets (no idea why they would do this be we should trust them).\r\n if (tickets === 0) {\r\n return [];\r\n }\r\n // Now that we know out tickets value is not zero we should check that it is a valid natural number.\r\n if (!(0, Utilities_1.isNaturalNumber)(tickets)) {\r\n throw new Error(\"tickets value must be a natural number\");\r\n }\r\n var result = [];\r\n // Keep drawing tickets until we either reach the number of required tickets or we simply run out of tickets to draw.\r\n // We can run out of tickets to draw if 'options.redrawable' is explicity 'false' or we just had no participants when 'drawMultiple' was called.\r\n while (result.length < tickets && this._participants.length > 0) {\r\n result.push(this.draw(options));\r\n }\r\n // If the 'unique' draw option is set then we need to remove duplicates from the result list.\r\n if (uniqueResults) {\r\n // Create an array to store our unique results.\r\n var unique = [];\r\n // Iterate over all of our participants (with potential duplicates) and populate our array of unique values.\r\n for (var _i = 0, result_1 = result; _i < result_1.length; _i++) {\r\n var participant = result_1[_i];\r\n if (unique.indexOf(participant) === -1) {\r\n unique.push(participant);\r\n }\r\n }\r\n result = unique;\r\n }\r\n return result;\r\n };\r\n return Lotto;\r\n}());\r\nexports.Lotto = Lotto;\r\n", "\"use strict\";\r\nObject.defineProperty(exports, \"__esModule\", { value: true });\r\nexports.createLotto = void 0;\r\nvar Lotto_1 = require(\"./Lotto\");\r\n/**\r\n * A function that creates and returns a Lotto instance.\r\n * @param participantsOrOptions An array of initial participants or options relating to the creation of a Lotto instance.\r\n * @returns A new Lotto instance.\r\n */\r\nfunction createLotto(participantsOrOptions) {\r\n // If no initial participants or lotto options were provided as an argument then we can just return a new lotto instance now.\r\n if (!participantsOrOptions) {\r\n return new Lotto_1.Lotto();\r\n }\r\n // Check whether we were provided with an array of initial participants or a lotto options object.\r\n if (Array.isArray(participantsOrOptions)) {\r\n // We are dealing with a pre-defined array of participants.\r\n var participants = participantsOrOptions;\r\n var lotto_1 = new Lotto_1.Lotto();\r\n // If the lotto participants have been defined upfront then we will need to add them all to our lotto instance now.\r\n participants.forEach(function (_a) {\r\n var participant = _a[0], tokens = _a[1];\r\n return lotto_1.add(participant, tokens);\r\n });\r\n // Return the Lotto instance.\r\n return lotto_1;\r\n }\r\n else {\r\n // We are dealing with some lotto options.\r\n var random = participantsOrOptions.random, participants = participantsOrOptions.participants;\r\n // Create a Lotto instance passing the custom RNG function to use in place of Math.random() (which could be undefined).\r\n var lotto_2 = new Lotto_1.Lotto(random);\r\n // If the lotto participants have been defined upfront as part of the options then we will need to add them all to our lotto instance now.\r\n if (participants) {\r\n participants.forEach(function (_a) {\r\n var participant = _a[0], tokens = _a[1];\r\n return lotto_2.add(participant, tokens);\r\n });\r\n }\r\n // Return the Lotto instance.\r\n return lotto_2;\r\n }\r\n}\r\nexports.createLotto = createLotto;\r\n", "\"use strict\";\r\nObject.defineProperty(exports, \"__esModule\", { value: true });\r\nvar createLotto_1 = require(\"./createLotto\");\r\nexports.default = createLotto_1.createLotto;\r\n", "import State from \"./State\";\nimport { validateDefinition } from \"./BehaviourTreeDefinitionValidator\";\nimport { convertMDSLToJSON } from \"./mdsl/MDSLDefinitionParser\";\nimport { BehaviourTree, FlattenedTreeNode } from \"./BehaviourTree\";\n\nexport { BehaviourTree, State, convertMDSLToJSON, validateDefinition };\nexport type { FlattenedTreeNode };\n", "/**\n * Enumeration of node state types.\n */\nexport enum State {\n READY = \"mistreevous.ready\",\n RUNNING = \"mistreevous.running\",\n SUCCEEDED = \"mistreevous.succeeded\",\n FAILED = \"mistreevous.failed\"\n}\n\nexport { State as default };\n\nexport type CompleteState = State.SUCCEEDED | State.FAILED;\nexport type AnyState = State.READY | State.RUNNING | CompleteState;\n", "import {\n NodeDefinition,\n RootNodeDefinition,\n DecoratorNodeDefinition,\n CompositeNodeDefinition,\n AnyNodeDefinition,\n BranchNodeDefinition\n} from \"./BehaviourTreeDefinition\";\n\n/**\n * A type guard function that returns true if the specified node satisfies the RootNodeDefinition type.\n * @param node The node.\n * @returns A value of true if the specified node satisfies the RootNodeDefinition type.\n */\nexport function isRootNode(node: NodeDefinition): node is RootNodeDefinition {\n return node.type === \"root\";\n}\n\n/**\n * A type guard function that returns true if the specified node satisfies the BranchNodeDefinition type.\n * @param node The node.\n * @returns A value of true if the specified node satisfies the BranchNodeDefinition type.\n */\nexport function isBranchNode(node: NodeDefinition): node is BranchNodeDefinition {\n return node.type === \"branch\";\n}\n\n/**\n * A type guard function that returns true if the specified node satisfies the NodeDefinition type.\n * @param node The node.\n * @returns A value of true if the specified node satisfies the NodeDefinition type.\n */\nexport function isLeafNode(node: NodeDefinition): node is NodeDefinition {\n return [\"branch\", \"action\", \"condition\", \"wait\"].includes(node.type);\n}\n\n/**\n * A type guard function that returns true if the specified node satisfies the DecoratorNodeDefinition type.\n * @param node The node.\n * @returns A value of true if the specified node satisfies the DecoratorNodeDefinition type.\n */\nexport function isDecoratorNode(node: NodeDefinition): node is DecoratorNodeDefinition {\n return [\"root\", \"repeat\", \"retry\", \"flip\", \"succeed\", \"fail\"].includes(node.type);\n}\n\n/**\n * A type guard function that returns true if the specified node satisfies the CompositeNodeDefinition type.\n * @param node The node.\n * @returns A value of true if the specified node satisfies the CompositeNodeDefinition type.\n */\nexport function isCompositeNode(node: NodeDefinition): node is CompositeNodeDefinition {\n return [\"sequence\", \"selector\", \"lotto\", \"parallel\"].includes(node.type);\n}\n\n/**\n * Flatten a node definition into an array of all of its nested node definitions.\n * @param nodeDefinition The node definition to flatten.\n * @returns An array of all of nested node definitions.\n */\nexport function flattenDefinition(nodeDefinition: AnyNodeDefinition): AnyNodeDefinition[] {\n const nodes: AnyNodeDefinition[] = [];\n\n const processNode = (currentNodeDefinition: AnyNodeDefinition) => {\n nodes.push(currentNodeDefinition);\n\n if (isCompositeNode(currentNodeDefinition)) {\n currentNodeDefinition.children.forEach(processNode);\n } else if (isDecoratorNode(currentNodeDefinition)) {\n processNode(currentNodeDefinition.child);\n }\n };\n\n processNode(nodeDefinition);\n\n return nodes;\n}\n\n/**\n * Determines whether the passed value is an integer.\n * @param value The value to check.\n * @returns Whether the passed value is an integer.\n */\nexport function isInteger(value: unknown): boolean {\n return typeof value === \"number\" && Math.floor(value) === value;\n}\n\n/**\n * Determines whether the passed value is null or undefined.\n * @param value The value to check.\n * @returns Whether the passed value is null or undefined.\n */\nexport function isNullOrUndefined(value: unknown): boolean {\n return typeof value === \"undefined\" || value === null;\n}\n", "/**\n * A type defining an object that holds a reference to substitued string literals parsed from the definition.\n */\nexport type StringLiteralPlaceholders = { [key: string]: string };\n\n/**\n * Pop the next raw token from the specified array of tokens and throw an error if it wasn't the expected one.\n * @param tokens The array of tokens.\n * @param expected An optional string or array or items, one of which must match the next popped token.\n * @returns The popped token.\n */\nexport function popAndCheck(tokens: string[], expected?: string | string[]): string {\n // Get and remove the next token.\n const popped = tokens.shift();\n\n // We were expecting another token but there aren't any.\n if (popped === undefined) {\n throw new Error(\"unexpected end of definition\");\n }\n\n // Do we have an expected token/tokens array?\n if (expected != undefined) {\n // Get an array of expected values, if the popped token matches any then we are all good.\n const expectedValues = typeof expected === \"string\" ? [expected] : expected;\n\n // Check whether the popped token matches at least one of our expected items.\n var tokenMatchesExpectation = expectedValues.some((item) => popped.toUpperCase() === item.toUpperCase());\n\n // Throw an error if the popped token didn't match any of our expected items.\n if (!tokenMatchesExpectation) {\n const expectationString = expectedValues.map((item) => \"'\" + item + \"'\").join(\" or \");\n throw new Error(\"unexpected token found. Expected \" + expectationString + \" but got '\" + popped + \"'\");\n }\n }\n\n // Return the popped token.\n return popped;\n}\n\n/**\n * Swaps out any node/attribute argument string literals with placeholders.\n * @param definition The definition.\n * @returns An object containing a mapping of placeholders to original string values as well as the processed definition string.\n */\nexport function substituteStringLiterals(definition: string): {\n placeholders: StringLiteralPlaceholders;\n processedDefinition: string;\n} {\n // Create an object to hold the mapping of placeholders to original string values.\n const placeholders: StringLiteralPlaceholders = {};\n\n // Replace any string literals wrapped with double quotes in our definition with placeholders to be processed later.\n const processedDefinition = definition.replace(/\\\"(\\\\.|[^\"\\\\])*\\\"/g, (match) => {\n var strippedMatch = match.substring(1, match.length - 1);\n var placeholder = Object.keys(placeholders).find((key) => placeholders[key] === strippedMatch);\n\n // If we have no existing string literal match then create a new placeholder.\n if (!placeholder) {\n placeholder = `@@${Object.keys(placeholders).length}@@`;\n placeholders[placeholder] = strippedMatch;\n }\n\n return placeholder;\n });\n\n return { placeholders, processedDefinition };\n}\n\n/**\n * Parse the tree definition into an array of raw tokens.\n * @param definition The definition.\n * @returns An array of tokens parsed from the definition.\n */\nexport function parseTokensFromDefinition(definition: string): string[] {\n // Add some space around various important characters so that they can be plucked out easier as individual tokens.\n definition = definition.replace(/\\(/g, \" ( \");\n definition = definition.replace(/\\)/g, \" ) \");\n definition = definition.replace(/\\{/g, \" { \");\n definition = definition.replace(/\\}/g, \" } \");\n definition = definition.replace(/\\]/g, \" ] \");\n definition = definition.replace(/\\[/g, \" [ \");\n definition = definition.replace(/\\,/g, \" , \");\n\n // Split the definition into raw token form and return it.\n return definition.replace(/\\s+/g, \" \").trim().split(\" \");\n}\n", "import { StringLiteralPlaceholders, popAndCheck } from \"./MDSLUtilities\";\n\n/**\n * A type representing any node function argument.\n */\ntype Argument = {\n /**\n * The argument value.\n */\n value: T;\n /**\n * The argument type, used for validation.\n */\n type: string;\n};\n\ntype NullArgument = Argument & {\n type: \"null\";\n};\n\ntype BooleanArgument = Argument & {\n type: \"boolean\";\n};\n\ntype NumberArgument = Argument & {\n type: \"number\";\n /**\n * A flag defining whether the number argument value is a valid integer. (used for validation)\n */\n isInteger: boolean;\n};\n\ntype StringPlaceholderArgument = Argument & {\n type: \"string\";\n};\n\ntype IdentifierArgument = Argument & {\n type: \"identifier\";\n};\n\n/**\n * A type representing a reference to any node function argument.\n */\ntype AnyArgument = NullArgument | BooleanArgument | NumberArgument | StringPlaceholderArgument | IdentifierArgument;\n\n/**\n * Parse an array of argument definitions from the specified tokens array.\n * @param tokens The array tokens to parse the argument definitions from.\n * @param stringArgumentPlaceholders The mapping of string literal node argument placeholders to original values.\n * @param argumentValidator The argument validator function.\n * @param validationFailedMessage The exception message to throw if argument validation fails.\n * @returns An array of argument definitions parsed from the specified tokens array.\n */\nexport function parseArgumentTokens(\n tokens: string[],\n stringArgumentPlaceholders: StringLiteralPlaceholders\n): AnyArgument[] {\n const argumentList: AnyArgument[] = [];\n\n // If the next token is not a '[' or '(' then we have no arguments to parse.\n if (![\"[\", \"(\"].includes(tokens[0])) {\n return argumentList;\n }\n\n // Any lists of arguments will always be wrapped in '[]' for node arguments or '()' for attribute arguments.\n // We are looking for a '[' or '(' opener that wraps the argument tokens and the relevant closer.\n const closingToken = popAndCheck(tokens, [\"[\", \"(\"]) === \"[\" ? \"]\" : \")\";\n\n const argumentListTokens: string[] = [];\n\n // Grab all tokens between the '[' and ']' or '(' and ')'.\n while (tokens.length && tokens[0] !== closingToken) {\n // The next token is part of our arguments list.\n argumentListTokens.push(tokens.shift()!);\n }\n\n // Validate the order of the argument tokens. Each token must either be a ',' or a single argument that satisfies the validator.\n argumentListTokens.forEach((token, index) => {\n // Get whether this token should be an actual argument.\n const shouldBeArgumentToken = !(index & 1);\n\n // If the current token should be an actual argument then validate it, otherwise it should be a ',' token.\n if (shouldBeArgumentToken) {\n // Get the argument definition.\n const argumentDefinition = getArgumentDefinition(token, stringArgumentPlaceholders);\n\n // This is a valid argument!\n argumentList.push(argumentDefinition);\n } else {\n // The current token should be a ',' token.\n if (token !== \",\") {\n throw new Error(`invalid argument list, expected ',' or ']' but got '${token}'`);\n }\n }\n });\n\n // The arguments list should terminate with a ']' or ')' token, depending on the opener.\n popAndCheck(tokens, closingToken);\n\n // Return the arguments.\n return argumentList;\n}\n\n/**\n * Gets an argument value definition.\n * @param token The argument token.\n * @param stringArgumentPlaceholders The mapping of string literal node argument placeholders to original values.\n * @returns An argument value definition.\n */\nfunction getArgumentDefinition(token: string, stringArgumentPlaceholders: StringLiteralPlaceholders): AnyArgument {\n // Check whether the token represents a null value.\n if (token === \"null\") {\n return {\n value: null,\n type: \"null\"\n } as NullArgument;\n }\n\n // Check whether the token represents a boolean value.\n if (token === \"true\" || token === \"false\") {\n return {\n value: token === \"true\",\n type: \"boolean\"\n } as BooleanArgument;\n }\n\n // Check whether the token represents a number value.\n // TODO: Relies on broken isNaN - see MDN.\n // if (!Number.isNaN(token)) {\n if (!isNaN(token as any)) {\n return {\n value: parseFloat(token),\n isInteger: parseFloat(token) === parseInt(token, 10),\n type: \"number\"\n } as NumberArgument;\n }\n\n // Check whether the token is a placeholder (e.g. @@0@@) representing a string literal.\n if (token.match(/^@@\\d+@@$/g)) {\n return {\n value: stringArgumentPlaceholders[token].replace('\\\\\"', '\"'),\n type: \"string\"\n } as StringPlaceholderArgument;\n }\n\n // The only remaining option is that the argument value is an identifier.\n return {\n value: token,\n type: \"identifier\"\n } as IdentifierArgument;\n}\n", "import { NodeAttributeDefinition } from \"../BehaviourTreeDefinition\";\nimport { parseArgumentTokens } from \"./MDSLNodeArgumentParser\";\nimport { StringLiteralPlaceholders } from \"./MDSLUtilities\";\n\n/**\n * A type defining the attribute definitions of a node.\n */\ntype NodeAttributes = {\n while?: NodeAttributeDefinition;\n until?: NodeAttributeDefinition;\n entry?: NodeAttributeDefinition;\n exit?: NodeAttributeDefinition;\n step?: NodeAttributeDefinition;\n};\n\n/**\n * Parse any node attribute definitions from the specified tokens array.\n * @param tokens The array of remaining tokens.\n * @param stringArgumentPlaceholders The mapping of string literal node argument placeholders to original values.\n * @returns An object of attribute definitions defined by any directly following tokens.\n */\nexport function parseAttributeTokens(\n tokens: string[],\n stringArgumentPlaceholders: StringLiteralPlaceholders\n): NodeAttributes {\n const nodeAttributeNames: (keyof NodeAttributes)[] = [\"while\", \"until\", \"entry\", \"exit\", \"step\"];\n\n // Create an object to hold any attributes found.\n const attributes: NodeAttributes = {};\n\n // Try to get the name of the attribute for the next token.\n let nextAttributeName = tokens[0]?.toLowerCase() as keyof NodeAttributes;\n\n // Pull attribute tokens as well as their arguments off of the tokens stack until we have no more.\n while (nodeAttributeNames.includes(nextAttributeName)) {\n // Check to make sure that we have not already created an attribute definition of this type.\n if (attributes[nextAttributeName]) {\n throw new Error(`duplicate attribute '${tokens[0].toUpperCase()}' found for node`);\n }\n\n // Remove the attribute name token from the array of tokens.\n tokens.shift();\n\n // Grab the attribute arguments, assuming the first to be an identifier.\n const [attributeCallIdentifier, ...attributeArguments] = parseArgumentTokens(\n tokens,\n stringArgumentPlaceholders\n );\n\n // The first attribute argument has to be an identifer, this will reference an agent function.\n if (attributeCallIdentifier?.type !== \"identifier\") {\n throw new Error(\"expected agent function name identifier argument for attribute\");\n }\n\n // Any attribute arguments (other than the expected call identifier) must have a type of string, number, boolean or null.\n attributeArguments\n .filter((arg) => arg.type === \"identifier\")\n .forEach((arg) => {\n throw new Error(\n `invalid attribute argument value '${arg.value}', must be string, number, boolean or null`\n );\n });\n\n // Create the attribute definition and add it to the object of attribute definitions found.\n attributes[nextAttributeName] = {\n call: attributeCallIdentifier.value,\n args: attributeArguments.map(({ value }) => value)\n };\n\n // Try to get the next attribute name token, as there could be multiple.\n nextAttributeName = tokens[0]?.toLowerCase() as keyof NodeAttributes;\n }\n\n return attributes;\n}\n", "import {\n ActionNodeDefinition,\n AnyChildNodeDefinition,\n AnyNodeDefinition,\n BranchNodeDefinition,\n ConditionNodeDefinition,\n FailNodeDefinition,\n FlipNodeDefinition,\n LottoNodeDefinition,\n ParallelNodeDefinition,\n RepeatNodeDefinition,\n RetryNodeDefinition,\n RootNodeDefinition,\n SelectorNodeDefinition,\n SequenceNodeDefinition,\n SucceedNodeDefinition,\n WaitNodeDefinition\n} from \"../BehaviourTreeDefinition\";\nimport {\n isCompositeNode,\n isDecoratorNode,\n isLeafNode,\n isNullOrUndefined,\n isRootNode\n} from \"../BehaviourTreeDefinitionUtilities\";\nimport { parseArgumentTokens } from \"./MDSLNodeArgumentParser\";\nimport { parseAttributeTokens } from \"./MDSLNodeAttributeParser\";\nimport {\n StringLiteralPlaceholders,\n parseTokensFromDefinition,\n popAndCheck,\n substituteStringLiterals\n} from \"./MDSLUtilities\";\n\n/**\n * Convert the MDSL tree definition string into an equivalent JSON definition.\n * @param definition The tree definition string as MDSL.\n * @returns The root node JSON definitions.\n */\nexport function convertMDSLToJSON(definition: string): RootNodeDefinition[] {\n // Swap out any node/attribute argument string literals with a placeholder and get a mapping of placeholders to original values as well as the processed definition.\n const { placeholders, processedDefinition } = substituteStringLiterals(definition);\n\n // Parse our definition definition string into an array of raw tokens.\n const tokens = parseTokensFromDefinition(processedDefinition);\n\n return convertTokensToJSONDefinition(tokens, placeholders);\n}\n\n/**\n * Converts the specified tree definition tokens into a JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The root node JSON definitions.\n */\nfunction convertTokensToJSONDefinition(\n tokens: string[],\n stringLiteralPlaceholders: StringLiteralPlaceholders\n): RootNodeDefinition[] {\n // There must be at least 3 tokens for the tree definition to be valid. 'ROOT', '{' and '}'.\n if (tokens.length < 3) {\n throw new Error(\"invalid token count\");\n }\n\n // We should have a matching number of '{' and '}' tokens. If not, then there are scopes that have not been properly closed.\n if (tokens.filter((token) => token === \"{\").length !== tokens.filter((token) => token === \"}\").length) {\n throw new Error(\"scope character mismatch\");\n }\n\n // Create an array of tree stack arrays where root nodes will always be at the botton and the current composite/decorator node at the top.\n // There should be an element in this array for every root node defined and every element should be an array with a root note as the first element.\n // E.g. A definition with two root nodes defined:\n // [\n // [root, lotto, sequence],\n // [root, selector]\n // ]\n const treeStacks: [Partial, ...Partial[]][] = [];\n\n // Create an array of all root node definitions that we create.\n const rootNodes: Partial[] = [];\n\n // A helper function used to push node definitions onto the tree stack.\n const pushNode = (node: AnyNodeDefinition) => {\n // If the node is a root node then we need to create a new tree stack array with the root node at the root.\n if (isRootNode(node)) {\n // We need to double-check that this root node is not the child of another node.\n // We can do this by checking whether the top tree stack is not empty (contains an existing node)\n if (treeStacks[treeStacks.length - 1]?.length) {\n throw new Error(\"a root node cannot be the child of another node\");\n }\n\n // Add the root node definition to our array of all parsed root node definitions.\n rootNodes.push(node);\n\n // Add the root node definition to the root of a new tree stack.\n treeStacks.push([node]);\n\n return;\n }\n\n // All non-root nodes should be pushed after their root nodes so handle cases\n // where we may not have any tree stacks or our top-most tree stack is empty.\n if (!treeStacks.length || !treeStacks[treeStacks.length - 1].length) {\n throw new Error(\"expected root node at base of definition\");\n }\n\n // Get the current tree stack that we are populating.\n const topTreeStack = treeStacks[treeStacks.length - 1];\n\n // Get the top-most node in the current tree stack, this will be a composite/decorator node\n // for which we will populate its children array if composite or setting its child if a decorator.\n const topTreeStackTopNode = topTreeStack[topTreeStack.length - 1] as AnyNodeDefinition;\n\n // If the top-most node in the current root stack is a composite or decorator\n // node then the current node should be added as a child of the top-most node.\n if (isCompositeNode(topTreeStackTopNode)) {\n topTreeStackTopNode.children = topTreeStackTopNode.children || [];\n topTreeStackTopNode.children.push(node);\n } else if (isDecoratorNode(topTreeStackTopNode)) {\n // If the top node already has a child node set then throw an error as a decorator should only have a single child.\n if (topTreeStackTopNode.child) {\n throw new Error(\"a decorator node must only have a single child node\");\n }\n\n topTreeStackTopNode.child = node;\n }\n\n // If the node we are adding is also a composite or decorator node, then we should push it\n // onto the current tree stack, as subsequent nodes will be added as its child/children.\n if (!isLeafNode(node)) {\n topTreeStack.push(node);\n }\n };\n\n // A helper function used to pop the top-most node definition off of the tree stack and return it.\n const popNode = (): AnyNodeDefinition | null => {\n let poppedNode: AnyNodeDefinition | null = null;\n\n // Get the current tree stack that we are populating.\n const topTreeStack = treeStacks[treeStacks.length - 1];\n\n // Pop the top-most node in the current tree stack if there is one.\n if (topTreeStack.length) {\n poppedNode = topTreeStack.pop() as AnyNodeDefinition;\n }\n\n // We don't want any empty tree stacks in our stack of tree stacks.\n if (!topTreeStack.length) {\n treeStacks.pop();\n }\n\n return poppedNode;\n };\n\n // We should keep processing the raw tokens until we run out of them.\n while (tokens.length) {\n // Grab the next token.\n const token = tokens.shift()!;\n\n // How we create the next node depends on the current raw token value.\n switch (token.toUpperCase()) {\n case \"ROOT\": {\n pushNode(createRootNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"SUCCEED\": {\n pushNode(createSucceedNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"FAIL\": {\n pushNode(createFailNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"FLIP\": {\n pushNode(createFlipNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"REPEAT\": {\n pushNode(createRepeatNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"RETRY\": {\n pushNode(createRetryNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"SEQUENCE\": {\n pushNode(createSequenceNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"SELECTOR\": {\n pushNode(createSelectorNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"PARALLEL\": {\n pushNode(createParallelNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"LOTTO\": {\n pushNode(createLottoNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"ACTION\": {\n pushNode(createActionNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"CONDITION\": {\n pushNode(createConditionNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"WAIT\": {\n pushNode(createWaitNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"BRANCH\": {\n pushNode(createBranchNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"}\": {\n // The '}' character closes the current scope and means that we have to pop a node off of the current stack.\n const poppedNode = popNode();\n\n // Now that we have a node definition we can carry out any validation that may require the node to be fully populated.\n if (poppedNode) {\n validatePoppedNode(poppedNode);\n }\n\n break;\n }\n\n default: {\n throw new Error(`unexpected token: ${token}`);\n }\n }\n }\n\n return rootNodes as RootNodeDefinition[];\n}\n\n/**\n * Creates a root node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The root node JSON definition.\n */\nfunction createRootNode(tokens: string[], stringLiteralPlaceholders: StringLiteralPlaceholders): RootNodeDefinition {\n // Create the root node definition.\n let node = {\n type: \"root\",\n id: undefined\n } as RootNodeDefinition;\n\n // Parse any node arguments, we should only have one if any which will be an identifier argument for the root identifier.\n const nodeArguments = parseArgumentTokens(tokens, stringLiteralPlaceholders);\n\n // Check whether any node arguments were defined.\n if (nodeArguments.length) {\n // We should only have one argument, if any, which will be an identifier argument for the root identifier.\n if (nodeArguments.length === 1 && nodeArguments[0].type === \"identifier\") {\n // The root node identifier will be the first and only node argument value.\n node.id = nodeArguments[0].value as string;\n } else {\n throw new Error(\"expected single root name argument\");\n }\n }\n\n // Grab any node attribute definitions and spread them into the node definition.\n node = { ...node, ...parseAttributeTokens(tokens, stringLiteralPlaceholders) };\n\n // This is a decorator node, so we expect an opening '{'.\n popAndCheck(tokens, \"{\");\n\n // Return the root node definition.\n return node;\n}\n\n/**\n * Creates a succeed node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The succeed node JSON definition.\n */\nfunction createSucceedNode(\n tokens: string[],\n stringLiteralPlaceholders: StringLiteralPlaceholders\n): SucceedNodeDefinition {\n const node = {\n type: \"succeed\",\n ...parseAttributeTokens(tokens, stringLiteralPlaceholders)\n } as SucceedNodeDefinition;\n\n // This is a decorator node, so we expect an opening '{'.\n popAndCheck(tokens, \"{\");\n\n // Return the succeed node definition.\n return node;\n}\n\n/**\n * Creates a fail node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The fail node JSON definition.\n */\nfunction createFailNode(tokens: string[], stringLiteralPlaceholders: StringLiteralPlaceholders): FailNodeDefinition {\n const node = {\n type: \"fail\",\n ...parseAttributeTokens(tokens, stringLiteralPlaceholders)\n } as FailNodeDefinition;\n\n // This is a decorator node, so we expect an opening '{'.\n popAndCheck(tokens, \"{\");\n\n // Return the fail node definition.\n return node;\n}\n\n/**\n * Creates a flip node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The flip node JSON definition.\n */\nfunction createFlipNode(tokens: string[], stringLiteralPlaceholders: StringLiteralPlaceholders): FlipNodeDefinition {\n const node = {\n type: \"flip\",\n ...parseAttributeTokens(tokens, stringLiteralPlaceholders)\n } as FlipNodeDefinition;\n\n // This is a decorator node, so we expect an opening '{'.\n popAndCheck(tokens, \"{\");\n\n // Return the flip node definition.\n return node;\n}\n\n/**\n * Creates a repeat node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The repeat node JSON definition.\n */\nfunction createRepeatNode(\n tokens: string[],\n stringLiteralPlaceholders: StringLiteralPlaceholders\n): RepeatNodeDefinition {\n let node = { type: \"repeat\" } as RepeatNodeDefinition;\n\n // Get the node arguments.\n const nodeArguments = parseArgumentTokens(tokens, stringLiteralPlaceholders);\n\n // The arguments of a repeat node are optional. We may have:\n // - No node arguments, in which case the repeat note will iterate indefinitely.\n // - One node argument which will be the explicit number of iterations to make.\n // - Two node arguments which define the min and max iteration bounds from which a random iteration count will be picked.\n if (nodeArguments.length) {\n // All repeat node arguments MUST be of type number and must be integer.\n nodeArguments\n .filter((arg) => arg.type !== \"number\" || !arg.isInteger)\n .forEach(() => {\n throw new Error(`repeat node iteration counts must be integer values`);\n });\n\n // We should have got one or two iteration counts.\n if (nodeArguments.length === 1) {\n // A static iteration count was defined.\n node.iterations = nodeArguments[0].value as number;\n\n // A repeat node must have a positive number of iterations if defined.\n if (node.iterations < 0) {\n throw new Error(\"a repeat node must have a positive number of iterations if defined\");\n }\n } else if (nodeArguments.length === 2) {\n // A minimum and maximum iteration count was defined.\n node.iterations = [nodeArguments[0].value as number, nodeArguments[1].value as number];\n\n // A repeat node must have a positive min and max iteration count if they are defined.\n if (node.iterations[0] < 0 || node.iterations[1] < 0) {\n throw new Error(\"a repeat node must have a positive minimum and maximum iteration count if defined\");\n }\n\n // A repeat node must not have an minimum iteration count that exceeds the maximum iteration count.\n if (node.iterations[0] > node.iterations[1]) {\n throw new Error(\n \"a repeat node must not have a minimum iteration count that exceeds the maximum iteration count\"\n );\n }\n } else {\n // An incorrect number of iteration counts was defined.\n throw new Error(\"invalid number of repeat node iteration count arguments defined\");\n }\n }\n\n // Grab any node attribute definitions and spread them into the node definition.\n node = { ...node, ...parseAttributeTokens(tokens, stringLiteralPlaceholders) };\n\n // This is a decorator node, so we expect an opening '{'.\n popAndCheck(tokens, \"{\");\n\n // Return the repeat node definition.\n return node;\n}\n\n/**\n * Creates a retry node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The retry node JSON definition.\n */\nfunction createRetryNode(tokens: string[], stringLiteralPlaceholders: StringLiteralPlaceholders): RetryNodeDefinition {\n let node = { type: \"retry\" } as RetryNodeDefinition;\n\n // Get the node arguments.\n const nodeArguments = parseArgumentTokens(tokens, stringLiteralPlaceholders);\n\n // The arguments of a retry node are optional. We may have:\n // - No node arguments, in which case the retry note will attempt indefinitely.\n // - One node argument which will be the explicit number of attempts to make.\n // - Two node arguments which define the min and max attempt bounds from which a random attempt count will be picked.\n if (nodeArguments.length) {\n // All retry node arguments MUST be of type number and must be integer.\n nodeArguments\n .filter((arg) => arg.type !== \"number\" || !arg.isInteger)\n .forEach(() => {\n throw new Error(`retry node attempt counts must be integer values`);\n });\n\n // We should have got one or two attempt counts.\n if (nodeArguments.length === 1) {\n // A static attempt count was defined.\n node.attempts = nodeArguments[0].value as number;\n\n // A retry node must have a positive number of attempts if defined.\n if (node.attempts < 0) {\n throw new Error(\"a retry node must have a positive number of attempts if defined\");\n }\n } else if (nodeArguments.length === 2) {\n // A minimum and maximum attempt count was defined.\n node.attempts = [nodeArguments[0].value as number, nodeArguments[1].value as number];\n\n // A retry node must have a positive min and max attempts count if they are defined.\n if (node.attempts[0] < 0 || node.attempts[1] < 0) {\n throw new Error(\"a retry node must have a positive minimum and maximum attempt count if defined\");\n }\n\n // A retry node must not have a minimum attempt count that exceeds the maximum attempt count.\n if (node.attempts[0] > node.attempts[1]) {\n throw new Error(\n \"a retry node must not have a minimum attempt count that exceeds the maximum attempt count\"\n );\n }\n } else {\n // An incorrect number of attempt counts was defined.\n throw new Error(\"invalid number of retry node attempt count arguments defined\");\n }\n }\n\n // Grab any node attribute definitions and spread them into the node definition.\n node = { ...node, ...parseAttributeTokens(tokens, stringLiteralPlaceholders) };\n\n // This is a decorator node, so we expect an opening '{'.\n popAndCheck(tokens, \"{\");\n\n // Return the retry node definition.\n return node;\n}\n\n/**\n * Creates a sequence node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The sequence node JSON definition.\n */\nfunction createSequenceNode(\n tokens: string[],\n stringLiteralPlaceholders: StringLiteralPlaceholders\n): SequenceNodeDefinition {\n const node = {\n type: \"sequence\",\n ...parseAttributeTokens(tokens, stringLiteralPlaceholders)\n } as SequenceNodeDefinition;\n\n // This is a composite node, so we expect an opening '{'.\n popAndCheck(tokens, \"{\");\n\n // Return the sequence node definition.\n return node;\n}\n\n/**\n * Creates a selector node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The selector node JSON definition.\n */\nfunction createSelectorNode(\n tokens: string[],\n stringLiteralPlaceholders: StringLiteralPlaceholders\n): SelectorNodeDefinition {\n const node = {\n type: \"selector\",\n ...parseAttributeTokens(tokens, stringLiteralPlaceholders)\n } as SelectorNodeDefinition;\n\n // This is a composite node, so we expect an opening '{'.\n popAndCheck(tokens, \"{\");\n\n // Return the selector node definition.\n return node;\n}\n\n/**\n * Creates a parallel node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The parallel node JSON definition.\n */\nfunction createParallelNode(\n tokens: string[],\n stringLiteralPlaceholders: StringLiteralPlaceholders\n): ParallelNodeDefinition {\n const node = {\n type: \"parallel\",\n ...parseAttributeTokens(tokens, stringLiteralPlaceholders)\n } as ParallelNodeDefinition;\n\n // This is a composite node, so we expect an opening '{'.\n popAndCheck(tokens, \"{\");\n\n // Return the parallel node definition.\n return node;\n}\n\n/**\n * Creates a lotto node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The lotto node JSON definition.\n */\nfunction createLottoNode(tokens: string[], stringLiteralPlaceholders: StringLiteralPlaceholders): LottoNodeDefinition {\n // If any node arguments have been defined then they must be our weights.\n const nodeArguments = parseArgumentTokens(tokens, stringLiteralPlaceholders);\n\n // All lotto node arguments MUST be of type number and must be integer.\n nodeArguments\n .filter((arg) => arg.type !== \"number\" || !arg.isInteger)\n .forEach(() => {\n throw new Error(`lotto node weight arguments must be integer values`);\n });\n\n const node = {\n type: \"lotto\",\n weights: nodeArguments.map(({ value }) => value),\n ...parseAttributeTokens(tokens, stringLiteralPlaceholders)\n } as LottoNodeDefinition;\n\n // This is a composite node, so we expect an opening '{'.\n popAndCheck(tokens, \"{\");\n\n // Return the lotto node definition.\n return node;\n}\n\n/**\n * Creates an action node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The action node JSON definition.\n */\nfunction createActionNode(\n tokens: string[],\n stringLiteralPlaceholders: StringLiteralPlaceholders\n): ActionNodeDefinition {\n // Parse any node arguments, we should have at least one which will be an identifier argument for the action name\n // and agent function to invoke for the action, all other arguments are to be passed as arguments to that function.\n const [actionNameIdentifier, ...agentFunctionArgs] = parseArgumentTokens(tokens, stringLiteralPlaceholders);\n\n // Our first argument MUST be defined and be an identifier as we require an action name argument.\n if (actionNameIdentifier?.type !== \"identifier\") {\n throw new Error(\"expected action name identifier argument\");\n }\n\n // Only the first argument should have been an identifier, all agent function arguments must be string, number, boolean or null.\n agentFunctionArgs\n .filter((arg) => arg.type === \"identifier\")\n .forEach((arg) => {\n throw new Error(\n `invalid action node argument value '${arg.value}', must be string, number, boolean or null`\n );\n });\n\n // Return the action node definition.\n return {\n type: \"action\",\n call: actionNameIdentifier.value,\n args: agentFunctionArgs.map(({ value }) => value),\n ...parseAttributeTokens(tokens, stringLiteralPlaceholders)\n };\n}\n\n/**\n * Creates a condition node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The condition node JSON definition.\n */\nfunction createConditionNode(\n tokens: string[],\n stringLiteralPlaceholders: StringLiteralPlaceholders\n): ConditionNodeDefinition {\n // Parse any node arguments, we should have at least one which will be an identifier argument for the condition name\n // and agent function to invoke for the condition, all other arguments are to be passed as arguments to that function.\n const [conditionNameIdentifier, ...agentFunctionArgs] = parseArgumentTokens(tokens, stringLiteralPlaceholders);\n\n // Our first argument MUST be defined and be an identifier as we require a condition name argument.\n if (conditionNameIdentifier?.type !== \"identifier\") {\n throw new Error(\"expected condition name identifier argument\");\n }\n\n // Only the first argument should have been an identifier, all agent function arguments must be string, number, boolean or null.\n agentFunctionArgs\n .filter((arg) => arg.type === \"identifier\")\n .forEach((arg) => {\n throw new Error(\n `invalid condition node argument value '${arg.value}', must be string, number, boolean or null`\n );\n });\n\n // Return the condition node definition.\n return {\n type: \"condition\",\n call: conditionNameIdentifier.value,\n args: agentFunctionArgs.map(({ value }) => value),\n ...parseAttributeTokens(tokens, stringLiteralPlaceholders)\n };\n}\n\n/**\n * Creates a wait node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The wait node JSON definition.\n */\nfunction createWaitNode(tokens: string[], stringLiteralPlaceholders: StringLiteralPlaceholders): WaitNodeDefinition {\n let node = { type: \"wait\" } as WaitNodeDefinition;\n\n // Get the node arguments.\n const nodeArguments = parseArgumentTokens(tokens, stringLiteralPlaceholders);\n\n // The arguments of a wait node are optional. We may have:\n // - No node arguments, in which case the wait will be indefinite until it is aborted.\n // - One node argument which will be the explicit duration of the wait.\n // - Two node arguments which define the min and max duration bounds from which a random duration will be picked.\n if (nodeArguments.length) {\n // All wait node arguments MUST be of type number and must be integer.\n nodeArguments\n .filter((arg) => arg.type !== \"number\" || !arg.isInteger)\n .forEach(() => {\n throw new Error(`wait node duration arguments must be integer values`);\n });\n\n // We may have:\n // - One node argument which will be the explicit duration of the wait.\n // - Two node arguments which define the min and max duration bounds from which a random duration will be picked.\n // - Too many arguments, which is not valid.\n if (nodeArguments.length === 1) {\n // An explicit duration was defined.\n node.duration = nodeArguments[0].value as number;\n\n // If an explict duration was defined then it must be a positive number.\n if (node.duration < 0) {\n throw new Error(\"a wait node must have a positive duration\");\n }\n } else if (nodeArguments.length === 2) {\n // Min and max duration bounds were defined from which a random duration will be picked.\n node.duration = [nodeArguments[0].value as number, nodeArguments[1].value as number];\n\n // A wait node must have a positive min and max duration.\n if (node.duration[0] < 0 || node.duration[1] < 0) {\n throw new Error(\"a wait node must have a positive minimum and maximum duration\");\n }\n\n // A wait node must not have a minimum duration that exceeds the maximum duration.\n if (node.duration[0] > node.duration[1]) {\n throw new Error(\"a wait node must not have a minimum duration that exceeds the maximum duration\");\n }\n } else if (nodeArguments.length > 2) {\n // An incorrect number of duration arguments were defined.\n throw new Error(\"invalid number of wait node duration arguments defined\");\n }\n }\n\n // Return the wait node definition.\n return { ...node, ...parseAttributeTokens(tokens, stringLiteralPlaceholders) };\n}\n\n/**\n * Creates a branch node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The branch node JSON definition.\n */\nfunction createBranchNode(\n tokens: string[],\n stringLiteralPlaceholders: StringLiteralPlaceholders\n): BranchNodeDefinition {\n // Parse any node arguments, we should have one which will be an identifier argument for the root ref.\n const nodeArguments = parseArgumentTokens(tokens, stringLiteralPlaceholders);\n\n // We should have only a single identifer argument for a branch node, which is the root ref.\n if (nodeArguments.length !== 1 || nodeArguments[0].type !== \"identifier\") {\n throw new Error(\"expected single branch name argument\");\n }\n\n // Return the branch node definition.\n return { type: \"branch\", ref: nodeArguments[0].value };\n}\n\n/**\n * Validate a fully-populated node definition that was popped off of the tree stack.\n * @param node The popped node to validate.\n */\nfunction validatePoppedNode(node: AnyNodeDefinition): void {\n // Decorators MUST have a child defined.\n if (isDecoratorNode(node) && isNullOrUndefined(node.child)) {\n throw new Error(`a ${node.type} node must have a single child node defined`);\n }\n\n // Composites MUST have at least one child defined.\n if (isCompositeNode(node) && !node.children?.length) {\n throw new Error(`a ${node.type} node must have at least a single child node defined`);\n }\n}\n", "import { RootNodeDefinition } from \"./BehaviourTreeDefinition\";\nimport { flattenDefinition, isBranchNode, isInteger } from \"./BehaviourTreeDefinitionUtilities\";\nimport { convertMDSLToJSON } from \"./mdsl/MDSLDefinitionParser\";\n\n/**\n * An object representing the result of validating a tree definition.\n */\nexport type DefinitionValidationResult = {\n /**\n * A flag defining whether validation succeeded.\n */\n succeeded: boolean;\n /**\n * A string containing the error message if validation did not succeed.\n */\n errorMessage?: string;\n};\n\n/**\n * Validates the specified behaviour tree definition in the form of JSON or MDSL, not taking any globally registered subtrees into consideration.\n * @param definition The behaviour tree definition in the form of JSON or MDSL.\n * @returns An object representing the result of validating the given tree definition.\n */\nexport function validateDefinition(definition: any): DefinitionValidationResult {\n // The definition must be defined.\n if (definition === null || typeof definition === \"undefined\") {\n return createValidationFailureResult(\"definition is null or undefined\");\n }\n\n // We are expecting a definition in one of three different forms:\n // - A string which we will assume is MDSL and we will parse this to JSON before validation.\n // - An array which we will assume is an array of root node definitions with at least one being the primary root node (no 'id' property)\n // - An object which we will assume is the primary root node and should not have an 'id' property.\n if (typeof definition === \"string\") {\n // The definition is a string which we can assume is MDSL, so attempt to validate it.\n return validateMDSLDefinition(definition);\n } else if (typeof definition === \"object\") {\n // The definition will either be an array (of root node definitions) or an object (the single primary root node definition).\n return validateJSONDefinition(definition);\n } else {\n return createValidationFailureResult(`unexpected definition type of '${typeof definition}'`);\n }\n}\n\n/**\n * Validates the specified behaviour tree definition in the form of MDSL.\n * @param definition The behaviour tree definition in the form of MDSL.\n * @returns An object representing the result of validating the given tree definition.\n */\nexport function validateMDSLDefinition(definition: string): DefinitionValidationResult {\n let rootNodeDefinitions;\n\n // The first thing the we need to do is to attempt to convert our MDSL into JSON.\n try {\n // The definition is a string which we can assume is MDSL, so attempt to parse it to a JSON definition in the form of an array of root node definitions.\n rootNodeDefinitions = convertMDSLToJSON(definition);\n } catch (error) {\n // We failed to parse the JSON from the MDSL, this is likely to be the result of it not being a valid MDSL string.\n return createValidationFailureResult(`invalid MDSL: ${error}`);\n }\n\n // Unpack all of the root node definitions into arrays of main ('id' defined) and sub ('id' not defined) root node definitions.\n const mainRootNodeDefinitions = rootNodeDefinitions.filter(({ id }) => typeof id === \"undefined\");\n const subRootNodeDefinitions = rootNodeDefinitions.filter(({ id }) => typeof id === \"string\" && id.length > 0);\n\n // We should ALWAYS have exactly one root node definition without an 'id' property defined, which is out main root node definition.\n if (mainRootNodeDefinitions.length !== 1) {\n return createValidationFailureResult(\n \"expected single unnamed root node at base of definition to act as main root\"\n );\n }\n\n // We should never have duplicate 'id' properties across our sub root node definitions.\n const subRootNodeIdenitifers: string[] = [];\n for (const { id } of subRootNodeDefinitions) {\n // Have we already come across this 'id' property value?\n if (subRootNodeIdenitifers.includes(id!)) {\n return createValidationFailureResult(`multiple root nodes found with duplicate name '${id}'`);\n }\n\n subRootNodeIdenitifers.push(id!);\n }\n\n try {\n // Validate our branch -> subtree links and check for any circular dependencies, we don't care about checking for broken subtree links here.\n validateBranchSubtreeLinks(rootNodeDefinitions, false);\n } catch (exception) {\n return createValidationFailureResult((exception as Error).message);\n }\n\n // Our definition was valid!\n return { succeeded: true };\n}\n\n/**\n * Validates the specified behaviour tree definition in the form of JSON.\n * @param definition The behaviour tree definition in the form of JSON.\n * @returns An object representing the result of validating the given tree definition.\n */\nexport function validateJSONDefinition(\n definition: RootNodeDefinition | RootNodeDefinition[]\n): DefinitionValidationResult {\n // The definition will either be an array (of root node definitions) or an object (the single primary root node definition).\n const rootNodeDefinitions = Array.isArray(definition) ? definition : [definition];\n\n // Iterate over our array of root nodes and call validateNode for each, passing an initial depth of 0, wrapped in a try catch to handle validation failures.\n try {\n rootNodeDefinitions.forEach((rootNodeDefinition) => validateNode(rootNodeDefinition, 0));\n } catch (error) {\n // Handle cases where we have caught a thrown Error and return a failure result with the error message.\n if (error instanceof Error) {\n return createValidationFailureResult(error.message);\n }\n\n // No idea what happened here!\n return createValidationFailureResult(`unexpected error: ${error}`);\n }\n\n // Unpack all of the root node definitions into arrays of main ('id' defined) and sub ('id' not defined) root node definitions.\n const mainRootNodeDefinitions = rootNodeDefinitions.filter(({ id }) => typeof id === \"undefined\");\n const subRootNodeDefinitions = rootNodeDefinitions.filter(({ id }) => typeof id === \"string\" && id.length > 0);\n\n // We should ALWAYS have exactly one root node definition without an 'id' property defined, which is out main root node definition.\n if (mainRootNodeDefinitions.length !== 1) {\n return createValidationFailureResult(\n \"expected single root node without 'id' property defined to act as main root\"\n );\n }\n\n // We should never have duplicate 'id' properties across our sub root node definitions.\n const subRootNodeIdenitifers: string[] = [];\n for (const { id } of subRootNodeDefinitions) {\n // Have we already come across this 'id' property value?\n if (subRootNodeIdenitifers.includes(id!)) {\n return createValidationFailureResult(\n `multiple root nodes found with duplicate 'id' property value of '${id}'`\n );\n }\n\n subRootNodeIdenitifers.push(id!);\n }\n\n try {\n // Validate our branch -> subtree links and check for any circular dependencies, we don't care about checking for broken subtree links here.\n validateBranchSubtreeLinks(rootNodeDefinitions, false);\n } catch (exception) {\n return createValidationFailureResult((exception as Error).message);\n }\n\n // Our definition was valid!\n return { succeeded: true };\n}\n\n/**\n * Validates the branch -> subtree links across all provided root node definitions.\n * This will not consider branch nodes that reference any globally registered subtrees unless includesGlobalSubtrees\n * is set to true, in which case we will also verify that there are no broken branch -> subtree links.\n * @param rootNodeDefinitions The array of root node definitions.\n * @param includesGlobalSubtrees A flag defining whether the array includes all global subtree root node definitions.\n */\nexport function validateBranchSubtreeLinks(rootNodeDefinitions: RootNodeDefinition[], includesGlobalSubtrees: boolean) {\n // Create a mapping of root node identifiers to other root nodes that they reference via branch nodes.\n // Below is an example of a mapping that includes a circular dependency (root => a => b => c => a)\n // [{ refs: [\"a\", \"b\"] }, { id: \"a\", refs: [\"b\"] }, { id: \"b\", refs: [\"c\"] }, { id: \"c\", refs: [\"a\"] }]\n const rootNodeMappings: { id: string | undefined; refs: string[] }[] = rootNodeDefinitions.map(\n (rootNodeDefinition) => ({\n id: rootNodeDefinition.id,\n refs: flattenDefinition(rootNodeDefinition)\n .filter(isBranchNode)\n .map(({ ref }) => ref)\n })\n );\n\n // A recursive function to walk through the mappings, keeping track of which root nodes we have visited in the form of a path of root node identifiers.\n const followRefs = (mapping: { id: string | undefined; refs: string[] }, path: (string | undefined)[] = []) => {\n // Have we found a circular dependency?\n if (path.includes(mapping.id)) {\n // We found a circular dependency! Get the bad path of root node identifiers.\n const badPath = [...path, mapping.id];\n\n // Create the formatted path value. [undefined, \"a\", \"b\", \"c\", \"a\"] would be formatted as \"a -> b -> c -> a\".\n const badPathFormatted = badPath.filter((element) => !!element).join(\" => \");\n\n // No need to continue, we found a circular dependency.\n throw new Error(`circular dependency found in branch node references: ${badPathFormatted}`);\n }\n\n for (const ref of mapping.refs) {\n // Find the mapping for the root node with an identifer matching the current ref.\n const subMapping = rootNodeMappings.find(({ id }) => id === ref);\n\n // We may not have a mapping for this ref, which is normal when we aren't considering all globally registered subtrees.\n if (subMapping) {\n followRefs(subMapping, [...path, mapping.id]);\n } else if (includesGlobalSubtrees) {\n // We found a reference to a root node that doesn't exist, which is a problem seeing as the root node definitons includes all globally registered subtrees.\n throw new Error(\n mapping.id\n ? `subtree '${mapping.id}' has branch node that references root node '${ref}' which has not been defined`\n : `primary tree has branch node that references root node '${ref}' which has not been defined`\n );\n }\n }\n };\n\n // Start looking for circular dependencies and broken references from the primary root node definition.\n followRefs(rootNodeMappings.find((mapping) => typeof mapping.id === \"undefined\")!);\n}\n\n/**\n * Validate an object that we expect to be a node definition.\n * @param definition An object that we expect to be a node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateNode(definition: any, depth: number): void {\n // Every node must be valid object and have a non-empty 'type' string property.\n if (typeof definition !== \"object\" || typeof definition.type !== \"string\" || definition.type.length === 0) {\n throw new Error(\n `node definition is not an object or 'type' property is not a non-empty string at depth '${depth}'`\n );\n }\n\n // How we validate this node definition will depend on its type.\n switch (definition.type) {\n case \"action\":\n validateActionNode(definition, depth);\n break;\n\n case \"condition\":\n validateConditionNode(definition, depth);\n break;\n\n case \"wait\":\n validateWaitNode(definition, depth);\n break;\n\n case \"branch\":\n validateBranchNode(definition, depth);\n break;\n\n case \"root\":\n validateRootNode(definition, depth);\n break;\n\n case \"success\":\n validateSuccessNode(definition, depth);\n break;\n\n case \"fail\":\n validateFailNode(definition, depth);\n break;\n\n case \"flip\":\n validateFlipNode(definition, depth);\n break;\n\n case \"repeat\":\n validateRepeatNode(definition, depth);\n break;\n\n case \"retry\":\n validateRetryNode(definition, depth);\n break;\n\n case \"sequence\":\n validateSequenceNode(definition, depth);\n break;\n\n case \"selector\":\n validateSelectorNode(definition, depth);\n break;\n\n case \"parallel\":\n validateParallelNode(definition, depth);\n break;\n\n default:\n throw new Error(`unexpected node type of '${definition.type}' at depth '${depth}'`);\n }\n}\n\n/**\n * Validate any attributes for a given node definition.\n * @param definition The node definition.\n * @param depth The depth of the node in the behaviour tree definition.\n */\nfunction validateNodeAttributes(definition: any, depth: number): void {\n // Validate each of the attribute types for this node.\n [\"while\", \"until\", \"entry\", \"exit\", \"step\"].forEach((attributeName) => {\n // Attempt to grab the definition for the current attribute from the node definition.\n const attributeDefinition = definition[attributeName];\n\n // All node attributes are optional, so there is nothing to do if the current attribute is not defined.\n if (typeof attributeDefinition === \"undefined\") {\n return;\n }\n\n // The attribute definition must be an object.\n if (typeof attributeDefinition !== \"object\") {\n throw new Error(\n `expected attribute '${attributeName}' to be an object for '${definition.type}' node at depth '${depth}'`\n );\n }\n\n // The 'call' property must be defined for any attribute definition.\n if (typeof attributeDefinition.call !== \"string\" || attributeDefinition.call.length === 0) {\n throw new Error(\n `expected 'call' property for attribute '${attributeName}' to be a non-empty string for '${definition.type}' node at depth '${depth}'`\n );\n }\n\n // If any node attribute arguments have been defined then they must have been defined in an array.\n if (typeof attributeDefinition.args !== \"undefined\" && !Array.isArray(attributeDefinition.args)) {\n throw new Error(\n `expected 'args' property for attribute '${attributeName}' to be an array for '${definition.type}' node at depth '${depth}'`\n );\n }\n });\n}\n\n/**\n * Validate an object that we expect to be a root node definition.\n * @param definition An object that we expect to be a root node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateRootNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"root\") {\n throw new Error(\"expected node type of 'root' for root node\");\n }\n\n // A root node cannot be the child of another node.\n if (depth > 0) {\n throw new Error(\"a root node cannot be the child of another node\");\n }\n\n // Check that, if the root node 'id' property is defined, it is a non-empty string.\n if (typeof definition.id !== \"undefined\" && (typeof definition.id !== \"string\" || definition.id.length === 0)) {\n throw new Error(\"expected non-empty string for 'id' property if defined for root node\");\n }\n\n // A root node is a decorator node, so must have a child node defined.\n if (typeof definition.child === \"undefined\") {\n throw new Error(\"expected property 'child' to be defined for root node\");\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n\n // Validate the child node of this decorator node.\n validateNode(definition.child, depth + 1);\n}\n\n/**\n * Validate an object that we expect to be a success node definition.\n * @param definition An object that we expect to be a success node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateSuccessNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"success\") {\n throw new Error(`expected node type of 'success' for success node at depth '${depth}'`);\n }\n\n // A success node is a decorator node, so must have a child node defined.\n if (typeof definition.child === \"undefined\") {\n throw new Error(`expected property 'child' to be defined for success node at depth '${depth}'`);\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n\n // Validate the child node of this decorator node.\n validateNode(definition.child, depth + 1);\n}\n\n/**\n * Validate an object that we expect to be a fail node definition.\n * @param definition An object that we expect to be a fail node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateFailNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"fail\") {\n throw new Error(`expected node type of 'fail' for fail node at depth '${depth}'`);\n }\n\n // A fail node is a decorator node, so must have a child node defined.\n if (typeof definition.child === \"undefined\") {\n throw new Error(`expected property 'child' to be defined for fail node at depth '${depth}'`);\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n\n // Validate the child node of this decorator node.\n validateNode(definition.child, depth + 1);\n}\n\n/**\n * Validate an object that we expect to be a flip node definition.\n * @param definition An object that we expect to be a flip node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateFlipNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"flip\") {\n throw new Error(`expected node type of 'flip' for flip node at depth '${depth}'`);\n }\n\n // A flip node is a decorator node, so must have a child node defined.\n if (typeof definition.child === \"undefined\") {\n throw new Error(`expected property 'child' to be defined for flip node at depth '${depth}'`);\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n\n // Validate the child node of this decorator node.\n validateNode(definition.child, depth + 1);\n}\n\n/**\n * Validate an object that we expect to be a repeat node definition.\n * @param definition An object that we expect to be a repeat node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateRepeatNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"repeat\") {\n throw new Error(`expected node type of 'repeat' for repeat node at depth '${depth}'`);\n }\n\n // A repeat node is a decorator node, so must have a child node defined.\n if (typeof definition.child === \"undefined\") {\n throw new Error(`expected property 'child' to be defined for repeat node at depth '${depth}'`);\n }\n\n // Check whether an 'iterations' property has been defined, it may not have been if this node is to repeat indefinitely.\n if (typeof definition.iterations !== \"undefined\") {\n if (Array.isArray(definition.iterations)) {\n // Check whether any elements of the array are not integer values.\n const containsNonInteger = !!definition.iterations.find((value: unknown) => !isInteger(value));\n\n // If the 'iterations' property is an array then it MUST contain two integer values.\n if (definition.iterations.length !== 2 || containsNonInteger) {\n throw new Error(\n `expected array containing two integer values for 'iterations' property if defined for repeat node at depth '${depth}'`\n );\n }\n\n // A repeat node must have a positive min and max iterations count if they are defined.\n if (definition.iterations[0] < 0 || definition.iterations[1] < 0) {\n throw new Error(\n `expected positive minimum and maximum iterations count for 'iterations' property if defined for repeat node at depth '${depth}'`\n );\n }\n\n // A repeat node must not have a minimum iterations count that exceeds the maximum iterations count.\n if (definition.iterations[0] > definition.iterations[1]) {\n throw new Error(\n `expected minimum iterations count that does not exceed the maximum iterations count for 'iterations' property if defined for repeat node at depth '${depth}'`\n );\n }\n } else if (isInteger(definition.iterations)) {\n // A repeat node must have a positive number of iterations if defined.\n if (definition.iterations < 0) {\n throw new Error(\n `expected positive iterations count for 'iterations' property if defined for repeat node at depth '${depth}'`\n );\n }\n } else {\n throw new Error(\n `expected integer value or array containing two integer values for 'iterations' property if defined for repeat node at depth '${depth}'`\n );\n }\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n\n // Validate the child node of this decorator node.\n validateNode(definition.child, depth + 1);\n}\n\n/**\n * Validate an object that we expect to be a retry node definition.\n * @param definition An object that we expect to be a retry node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateRetryNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"retry\") {\n throw new Error(`expected node type of 'retry' for retry node at depth '${depth}'`);\n }\n\n // A retry node is a decorator node, so must have a child node defined.\n if (typeof definition.child === \"undefined\") {\n throw new Error(`expected property 'child' to be defined for retry node at depth '${depth}'`);\n }\n\n // Check whether an 'attempts' property has been defined, it may not have been if this node is to retry indefinitely.\n if (typeof definition.attempts !== \"undefined\") {\n if (Array.isArray(definition.attempts)) {\n // Check whether any elements of the array are not integer values.\n const containsNonInteger = !!definition.attempts.find((value: unknown) => !isInteger(value));\n\n // If the 'attempts' property is an array then it MUST contain two integer values.\n if (definition.attempts.length !== 2 || containsNonInteger) {\n throw new Error(\n `expected array containing two integer values for 'attempts' property if defined for retry node at depth '${depth}'`\n );\n }\n\n // A retry node must have a positive min and max attempts count if they are defined.\n if (definition.attempts[0] < 0 || definition.attempts[1] < 0) {\n throw new Error(\n `expected positive minimum and maximum attempts count for 'attempts' property if defined for retry node at depth '${depth}'`\n );\n }\n\n // A retry node must not have a minimum attempts count that exceeds the maximum attempts count.\n if (definition.attempts[0] > definition.attempts[1]) {\n throw new Error(\n `expected minimum attempts count that does not exceed the maximum attempts count for 'attempts' property if defined for retry node at depth '${depth}'`\n );\n }\n } else if (isInteger(definition.attempts)) {\n // A retry node must have a positive number of attempts if defined.\n if (definition.attempts < 0) {\n throw new Error(\n `expected positive attempts count for 'attempts' property if defined for retry node at depth '${depth}'`\n );\n }\n } else {\n throw new Error(\n `expected integer value or array containing two integer values for 'attempts' property if defined for retry node at depth '${depth}'`\n );\n }\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n\n // Validate the child node of this decorator node.\n validateNode(definition.child, depth + 1);\n}\n\n/**\n * Validate an object that we expect to be a branch node definition.\n * @param definition An object that we expect to be a branch node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateBranchNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"branch\") {\n throw new Error(`expected node type of 'branch' for branch node at depth '${depth}'`);\n }\n\n // Check that the branch node 'ref' property is defined and is a non-empty string.\n if (typeof definition.ref !== \"string\" || definition.ref.length === 0) {\n throw new Error(`expected non-empty string for 'ref' property for branch node at depth '${depth}'`);\n }\n\n // It is invalid to define guard attributes for a branch node as they should be defined on the referenced root node.\n [\"while\", \"until\"].forEach((attributeName) => {\n if (typeof definition[attributeName] !== \"undefined\") {\n throw new Error(\n `guards should not be defined for branch nodes but guard '${attributeName}' was defined for branch node at depth '${depth}'`\n );\n }\n });\n\n // It is invalid to define callback attributes for a branch node as they should be defined on the referenced root node.\n [\"entry\", \"exit\", \"step\"].forEach((attributeName) => {\n if (typeof definition[attributeName] !== \"undefined\") {\n throw new Error(\n `callbacks should not be defined for branch nodes but callback '${attributeName}' was defined for branch node at depth '${depth}'`\n );\n }\n });\n}\n\n/**\n * Validate an object that we expect to be a action node definition.\n * @param definition An object that we expect to be a action node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateActionNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"action\") {\n throw new Error(`expected node type of 'action' for action node at depth '${depth}'`);\n }\n\n // The 'call' property must be defined for a action node definition.\n if (typeof definition.call !== \"string\" || definition.call.length === 0) {\n throw new Error(`expected non-empty string for 'call' property of action node at depth '${depth}'`);\n }\n\n // If any action function arguments have been defined then they must have been defined in an array.\n if (typeof definition.args !== \"undefined\" && !Array.isArray(definition.args)) {\n throw new Error(`expected array for 'args' property if defined for action node at depth '${depth}'`);\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n}\n\n/**\n * Validate an object that we expect to be a condition node definition.\n * @param definition An object that we expect to be a condition node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateConditionNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"condition\") {\n throw new Error(`expected node type of 'condition' for condition node at depth '${depth}'`);\n }\n\n // The 'call' property must be defined for a condition node definition.\n if (typeof definition.call !== \"string\" || definition.call.length === 0) {\n throw new Error(`expected non-empty string for 'call' property of condition node at depth '${depth}'`);\n }\n\n // If any condition function arguments have been defined then they must have been defined in an array.\n if (typeof definition.args !== \"undefined\" && !Array.isArray(definition.args)) {\n throw new Error(`expected array for 'args' property if defined for condition node at depth '${depth}'`);\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n}\n\n/**\n * Validate an object that we expect to be a wait node definition.\n * @param definition An object that we expect to be a wait node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateWaitNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"wait\") {\n throw new Error(`expected node type of 'wait' for wait node at depth '${depth}'`);\n }\n\n // Check whether a 'duration' property has been defined, it may not have been if this node is to wait indefinitely.\n if (typeof definition.duration !== \"undefined\") {\n if (Array.isArray(definition.duration)) {\n // Check whether any elements of the array are not integer values.\n const containsNonInteger = !!definition.duration.find((value: unknown) => !isInteger(value));\n\n // If the 'duration' property is an array then it MUST contain two integer values.\n if (definition.duration.length !== 2 || containsNonInteger) {\n throw new Error(\n `expected array containing two integer values for 'duration' property if defined for wait node at depth '${depth}'`\n );\n }\n\n // A wait node must have a positive min and max duration value if they are defined.\n if (definition.duration[0] < 0 || definition.duration[1] < 0) {\n throw new Error(\n `expected positive minimum and maximum duration for 'duration' property if defined for wait node at depth '${depth}'`\n );\n }\n\n // A wait node must not have a minimum duration value that exceeds the maximum duration value.\n if (definition.duration[0] > definition.duration[1]) {\n throw new Error(\n `expected minimum duration value that does not exceed the maximum duration value for 'duration' property if defined for wait node at depth '${depth}'`\n );\n }\n } else if (isInteger(definition.duration)) {\n // A wait node must have a positive duration value if defined.\n if (definition.duration < 0) {\n throw new Error(\n `expected positive duration value for 'duration' property if defined for wait node at depth '${depth}'`\n );\n }\n } else {\n throw new Error(\n `expected integer value or array containing two integer values for 'duration' property if defined for wait node at depth '${depth}'`\n );\n }\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n}\n\n/**\n * Validate an object that we expect to be a sequence node definition.\n * @param definition An object that we expect to be a sequence node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateSequenceNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"sequence\") {\n throw new Error(`expected node type of 'sequence' for sequence node at depth '${depth}'`);\n }\n\n // A sequence node is a composite node, so must have a children nodes array defined.\n if (!Array.isArray(definition.children) || definition.children.length === 0) {\n throw new Error(`expected non-empty 'children' array to be defined for sequence node at depth '${depth}'`);\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n\n // Validate the child nodes of this composite node.\n definition.children.forEach((child: any) => validateNode(child, depth + 1));\n}\n\n/**\n * Validate an object that we expect to be a selector node definition.\n * @param definition An object that we expect to be a selector node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateSelectorNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"selector\") {\n throw new Error(`expected node type of 'selector' for selector node at depth '${depth}'`);\n }\n\n // A selector node is a composite node, so must have a children nodes array defined.\n if (!Array.isArray(definition.children) || definition.children.length === 0) {\n throw new Error(`expected non-empty 'children' array to be defined for selector node at depth '${depth}'`);\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n\n // Validate the child nodes of this composite node.\n definition.children.forEach((child: any) => validateNode(child, depth + 1));\n}\n\n/**\n * Validate an object that we expect to be a parallel node definition.\n * @param definition An object that we expect to be a parallel node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateParallelNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"parallel\") {\n throw new Error(`expected node type of 'parallel' for parallel node at depth '${depth}'`);\n }\n\n // A parallel node is a composite node, so must have a children nodes array defined.\n if (!Array.isArray(definition.children) || definition.children.length === 0) {\n throw new Error(`expected non-empty 'children' array to be defined for parallel node at depth '${depth}'`);\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n\n // Validate the child nodes of this composite node.\n definition.children.forEach((child: any) => validateNode(child, depth + 1));\n}\n\n/**\n * A helper function to create a failure validation result with the given error message.\n * @param errorMessage The validation failure error message.\n * @returns A failure validation result with the given error message.\n */\nfunction createValidationFailureResult(errorMessage: string): DefinitionValidationResult {\n return { succeeded: false, errorMessage };\n}\n", "import { ActionResult, Agent, GlobalFunction } from \"./Agent\";\nimport { RootNodeDefinition } from \"./BehaviourTreeDefinition\";\n\nexport type InvokerFunction = (args: any[]) => ActionResult;\n\n/**\n * A singleton used to store and lookup registered functions and subtrees.\n */\nexport default class Lookup {\n /**\n * The object holding any registered functions keyed on function name.\n */\n private static functionTable: { [key: string]: GlobalFunction } = {};\n /**\n * The object holding any registered subtree root node definitions keyed on tree name.\n */\n private static subtreeTable: { [key: string]: RootNodeDefinition } = {};\n\n /**\n * Gets the function with the specified name.\n * @param name The name of the function.\n * @returns The function with the specified name.\n */\n public static getFunc(name: string): GlobalFunction {\n return this.functionTable[name];\n }\n\n /**\n * Sets the function with the specified name for later lookup.\n * @param name The name of the function.\n * @param func The function.\n */\n public static setFunc(name: string, func: GlobalFunction): void {\n this.functionTable[name] = func;\n }\n\n /**\n * Gets the function invoker for the specified agent and function name.\n * If a function with the specified name exists on the agent object then it will\n * be returned, otherwise we will then check the registered functions for a match.\n * @param agent The agent instance that this behaviour tree is modelling behaviour for.\n * @param name The function name.\n * @returns The function invoker for the specified agent and function name.\n */\n static getFuncInvoker(agent: Agent, name: string): InvokerFunction | null {\n // Check whether the agent contains the specified function.\n const foundOnAgent = agent[name];\n if (foundOnAgent && typeof foundOnAgent === \"function\") {\n return (args: any[]): boolean | ActionResult => foundOnAgent.apply(agent, args);\n }\n\n // The agent does not contain the specified function but it may have been registered at some point.\n if (this.functionTable[name] && typeof this.functionTable[name] === \"function\") {\n return (args: any[]) => this.functionTable[name](agent, ...args.map((arg) => arg.value));\n }\n\n // We have no function to invoke.\n return null;\n }\n\n /**\n * Gets all registered subtree root node definitions.\n */\n static getSubtrees(): { [key: string]: RootNodeDefinition } {\n return this.subtreeTable;\n }\n\n /**\n * Sets the subtree with the specified name for later lookup.\n * @param name The name of the subtree.\n * @param subtree The subtree.\n */\n static setSubtree(name: string, subtree: RootNodeDefinition) {\n this.subtreeTable[name] = subtree;\n }\n\n /**\n * Removes the registered function or subtree with the specified name.\n * @param name The name of the registered function or subtree.\n */\n static remove(name: string) {\n delete this.functionTable[name];\n delete this.subtreeTable[name];\n }\n\n /**\n * Remove all registered functions and subtrees.\n */\n static empty() {\n this.functionTable = {};\n this.subtreeTable = {};\n }\n}\n", "import Node from \"../../nodes/Node\";\n\n/**\n * An exception thrown when evaluating node guard path conditions and a conditions fails.\n */\nexport default class GuardUnsatisifedException extends Error {\n /**\n * @param source The node at which a guard condition failed.\n */\n constructor(private source: Node) {\n super(\"A guard path condition has failed\");\n }\n\n /**\n * Gets whether the specified node is the node at which a guard condition failed.\n * @param node The node to check against the source node.\n * @returns Whether the specified node is the node at which a guard condition failed.\n */\n isSourceNode = (node: Node) => node === this.source;\n}\n", "import { Agent } from \"../../Agent\";\nimport Guard from \"./Guard\";\nimport Node from \"../../nodes/Node\";\nimport GuardUnsatisifedException from \"./GuardUnsatisifedException\";\n\nexport type GuardPathPart = {\n node: Node;\n guards: Guard[];\n};\n\n/**\n * Represents a path of node guards along a root-to-leaf tree path.\n */\nexport default class GuardPath {\n /**\n * @param nodes An array of objects defining a node instance -> guard link, ordered by node depth.\n */\n constructor(private nodes: GuardPathPart[]) {}\n\n /**\n * Evaluate guard conditions for all guards in the tree path, moving outwards from the root.\n * @param agent The agent, required for guard evaluation.\n * @returns An evaluation results object.\n */\n evaluate = (agent: Agent) => {\n // We need to evaluate guard conditions for nodes up the tree, moving outwards from the root.\n for (const details of this.nodes) {\n // There can be multiple guards per node.\n for (const guard of details.guards) {\n // Check whether the guard condition passes, and throw an exception if not.\n if (!guard.isSatisfied(agent)) {\n throw new GuardUnsatisifedException(details.node);\n }\n }\n }\n };\n}\n", "import { BehaviourTreeOptions } from \"../BehaviourTreeOptions\";\nimport State, { AnyState } from \"../State\";\nimport { Agent } from \"../Agent\";\nimport Leaf from \"./leaf/Leaf\";\nimport Attribute from \"../attributes/Attribute\";\nimport Entry from \"../attributes/callbacks/Entry\";\nimport Exit from \"../attributes/callbacks/Exit\";\nimport Step from \"../attributes/callbacks/Step\";\nimport Guard from \"../attributes/guards/Guard\";\nimport GuardPath from \"../attributes/guards/GuardPath\";\nimport GuardUnsatisifedException from \"../attributes/guards/GuardUnsatisifedException\";\n\n/**\n * A base node.\n */\nexport default abstract class Node {\n /**\n * The node uid.\n */\n private readonly uid: string = createNodeUid();\n /**\n * The node state.\n */\n private state: AnyState = State.READY;\n /**\n * The guard path to evaluate as part of a node update.\n */\n private guardPath: GuardPath | undefined;\n\n /**\n * @param type The node type.\n * @param attributes The node attributes.\n * @param args The node argument definitions.\n */\n constructor(private type: string, private attributes: Attribute[], private args: any[]) {}\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected abstract onUpdate(agent: Agent, options: BehaviourTreeOptions): void;\n\n /**\n * Gets the name of the node.\n */\n public abstract getName(): string;\n\n /**\n * Gets whether this node is a leaf node.\n */\n public abstract isLeafNode: () => this is Leaf;\n\n /**\n * Gets/Sets the state of the node.\n */\n getState = (): AnyState => this.state;\n setState = (value: AnyState): void => {\n this.state = value;\n };\n\n /**\n * Gets the unique id of the node.\n */\n getUid = () => this.uid;\n\n /**\n * Gets the type of the node.\n */\n getType = () => this.type;\n\n /**\n * Gets the node attributes.\n */\n getAttributes = () => this.attributes;\n\n /**\n * Gets the node arguments.\n */\n getArguments = () => this.args;\n\n /**\n * Gets the node attribute with the specified type, or null if it does not exist.\n */\n getAttribute(type: \"entry\" | \"ENTRY\"): Entry;\n getAttribute(type: \"exit\" | \"EXIT\"): Exit;\n getAttribute(type: \"step\" | \"STEP\"): Step;\n getAttribute(type: string): Attribute {\n return (\n this.getAttributes().filter((decorator) => decorator.type.toUpperCase() === type.toUpperCase())[0] || null\n );\n }\n\n /**\n * Gets the node attributes.\n */\n getGuardAttributes = (): Guard[] => this.getAttributes().filter((decorator) => decorator.isGuard()) as Guard[];\n\n /**\n * Sets the guard path to evaluate as part of a node update.\n */\n setGuardPath = (value: GuardPath) => (this.guardPath = value);\n\n /**\n * Gets whether a guard path is assigned to this node.\n */\n hasGuardPath = () => !!this.guardPath;\n\n /**\n * Gets whether this node is in the specified state.\n * @param value The value to compare to the node state.\n */\n public is(value: AnyState): boolean {\n return this.state === value;\n }\n\n /**\n * Reset the state of the node.\n */\n public reset(): void {\n this.setState(State.READY);\n }\n\n /**\n * Abort the running of this node.\n * @param agent The agent.\n */\n public abort(agent: Agent): void {\n // There is nothing to do if this node is not in the running state.\n if (!this.is(State.RUNNING)) {\n return;\n }\n\n // Reset the state of this node.\n this.reset();\n\n this.getAttribute(\"exit\")?.callAgentFunction(agent, false, true);\n }\n\n /**\n * Update the node.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n * @returns The result of the update.\n */\n public update(agent: Agent, options: BehaviourTreeOptions): void {\n // If this node is already in a 'SUCCEEDED' or 'FAILED' state then there is nothing to do.\n if (this.is(State.SUCCEEDED) || this.is(State.FAILED)) {\n return;\n }\n\n try {\n // Evaluate all of the guard path conditions for the current tree path.\n this.guardPath!.evaluate(agent);\n\n // If this node is in the READY state then call the ENTRY for this node if it exists.\n if (this.is(State.READY)) {\n this.getAttribute(\"entry\")?.callAgentFunction(agent);\n }\n\n this.getAttribute(\"step\")?.callAgentFunction(agent);\n\n // Do the actual update.\n this.onUpdate(agent, options);\n\n // If this node is now in a 'SUCCEEDED' or 'FAILED' state then call the EXIT for this node if it exists.\n if (this.is(State.SUCCEEDED) || this.is(State.FAILED)) {\n this.getAttribute(\"exit\")?.callAgentFunction(agent, this.is(State.SUCCEEDED), false);\n }\n } catch (error) {\n // If the error is a GuardUnsatisfiedException then we need to determine if this node is the source.\n if (error instanceof GuardUnsatisifedException && error.isSourceNode(this)) {\n // Abort the current node.\n this.abort(agent);\n\n // Any node that is the source of an abort will be a failed node.\n this.setState(State.FAILED);\n } else {\n throw error;\n }\n }\n }\n}\n\n/**\n * Create a randomly generated node uid.\n * @returns A randomly generated node uid.\n */\nfunction createNodeUid(): string {\n var S4 = function () {\n return (((1 + Math.random()) * 0x10000) | 0).toString(16).substring(1);\n };\n return S4() + S4() + \"-\" + S4() + \"-\" + S4() + \"-\" + S4() + \"-\" + S4() + S4() + S4();\n}\n", "import Node from \"../Node\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\n\n/**\n * A composite node that wraps child nodes.\n */\nexport default abstract class Composite extends Node {\n /**\n * @param type The node type.\n * @param attributes The node attributes.\n * @param children The child nodes.\n */\n constructor(type: string, attributes: Attribute[], protected children: Node[]) {\n super(type, attributes, []);\n }\n\n /**\n * Gets whether this node is a leaf node.\n */\n isLeafNode = () => false;\n\n /**\n * Gets the children of this node.\n */\n getChildren = () => this.children;\n\n /**\n * Reset the state of the node.\n */\n reset = () => {\n // Reset the state of this node.\n this.setState(State.READY);\n\n // Reset the state of any child nodes.\n this.getChildren().forEach((child) => child.reset());\n };\n\n /**\n * Abort the running of this node.\n * @param agent The agent.\n */\n abort = (agent: Agent) => {\n // There is nothing to do if this node is not in the running state.\n if (!this.is(State.RUNNING)) {\n return;\n }\n\n // Abort any child nodes.\n this.getChildren().forEach((child) => child.abort(agent));\n\n // Reset the state of this node.\n this.reset();\n\n this.getAttribute(\"exit\")?.callAgentFunction(agent, false, true);\n };\n}\n", "import Composite from \"./Composite\";\nimport State from \"../../State\";\nimport Node from \"../Node\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A PARALLEL node.\n * The child nodes are executed concurrently until one fails or all succeed.\n */\nexport default class Parallel extends Composite {\n /**\n * @param attributes The node attributes.\n * @param children The child nodes.\n */\n constructor(attributes: Attribute[], children: Node[]) {\n super(\"parallel\", attributes, children);\n }\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // Keep a count of the number of succeeded child nodes.\n let succeededCount = 0;\n\n let hasChildFailed = false;\n\n // Iterate over all of the children of this node.\n for (const child of this.children) {\n // If the child has never been updated or is running then we will need to update it now.\n if (child.getState() === State.READY || child.getState() === State.RUNNING) {\n // Update the child of this node.\n child.update(agent, options);\n }\n\n // If the current child has a state of 'SUCCEEDED' then we should move on to the next child.\n if (child.getState() === State.SUCCEEDED) {\n // The child node has succeeded, keep track of this to determine if all children have.\n succeededCount++;\n\n // The child node succeeded, but we have not finished checking every child node yet.\n continue;\n }\n\n // If the current child has a state of 'FAILED' then this node is also a 'FAILED' node.\n if (child.getState() === State.FAILED) {\n hasChildFailed = true;\n\n // There is no need to check the rest of the children.\n break;\n }\n\n // The node should be in the 'RUNNING' state.\n if (child.getState() !== State.RUNNING) {\n // The child node was not in an expected state.\n throw new Error(\"child node was not in an expected state.\");\n }\n }\n\n if (hasChildFailed) {\n // This node is a 'FAILED' node.\n this.setState(State.FAILED);\n\n // Abort every running child.\n for (const child of this.children) {\n if (child.getState() === State.RUNNING) {\n child.abort(agent);\n }\n }\n } else {\n // If all children have succeeded then this node has also succeeded, otherwise it is still running.\n this.setState(succeededCount === this.children.length ? State.SUCCEEDED : State.RUNNING);\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => \"PARALLEL\";\n}\n", "import Composite from \"./Composite\";\nimport Node from \"../Node\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A SELECTOR node.\n * The child nodes are executed in sequence until one succeeds or all fail.\n */\nexport default class Selector extends Composite {\n /**\n * @param attributes The node attributes.\n * @param children The child nodes.\n */\n constructor(attributes: Attribute[], protected children: Node[]) {\n super(\"selector\", attributes, children);\n }\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // Iterate over all of the children of this node.\n for (const child of this.children) {\n // If the child has never been updated or is running then we will need to update it now.\n if (child.getState() === State.READY || child.getState() === State.RUNNING) {\n // Update the child of this node.\n child.update(agent, options);\n }\n\n // If the current child has a state of 'SUCCEEDED' then this node is also a 'SUCCEEDED' node.\n if (child.getState() === State.SUCCEEDED) {\n // This node is a 'SUCCEEDED' node.\n this.setState(State.SUCCEEDED);\n\n // There is no need to check the rest of the selector nodes.\n return;\n }\n\n // If the current child has a state of 'FAILED' then we should move on to the next child.\n if (child.getState() === State.FAILED) {\n // Find out if the current child is the last one in the selector.\n // If it is then this sequence node has also failed.\n if (this.children.indexOf(child) === this.children.length - 1) {\n // This node is a 'FAILED' node.\n this.setState(State.FAILED);\n\n // There is no need to check the rest of the selector as we have completed it.\n return;\n } else {\n // The child node failed, try the next one.\n continue;\n }\n }\n\n // The node should be in the 'RUNNING' state.\n if (child.getState() === State.RUNNING) {\n // This node is a 'RUNNING' node.\n this.setState(State.RUNNING);\n\n // There is no need to check the rest of the selector as the current child is still running.\n return;\n }\n\n // The child node was not in an expected state.\n throw new Error(\"child node was not in an expected state.\");\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => \"SELECTOR\";\n}\n", "import Composite from \"./Composite\";\nimport Node from \"../Node\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A SEQUENCE node.\n * The child nodes are executed in sequence until one fails or all succeed.\n */\nexport default class Sequence extends Composite {\n /**\n * @param attributes The node attributes.\n * @param children The child nodes.\n */\n constructor(attributes: Attribute[], protected children: Node[]) {\n super(\"sequence\", attributes, children);\n }\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // Iterate over all of the children of this node.\n for (const child of this.children) {\n // If the child has never been updated or is running then we will need to update it now.\n if (child.getState() === State.READY || child.getState() === State.RUNNING) {\n // Update the child of this node.\n child.update(agent, options);\n }\n\n // If the current child has a state of 'SUCCEEDED' then we should move on to the next child.\n if (child.getState() === State.SUCCEEDED) {\n // Find out if the current child is the last one in the sequence.\n // If it is then this sequence node has also succeeded.\n if (this.children.indexOf(child) === this.children.length - 1) {\n // This node is a 'SUCCEEDED' node.\n this.setState(State.SUCCEEDED);\n\n // There is no need to check the rest of the sequence as we have completed it.\n return;\n } else {\n // The child node succeeded, but we have not finished the sequence yet.\n continue;\n }\n }\n\n // If the current child has a state of 'FAILED' then this node is also a 'FAILED' node.\n if (child.getState() === State.FAILED) {\n // This node is a 'FAILED' node.\n this.setState(State.FAILED);\n\n // There is no need to check the rest of the sequence.\n return;\n }\n\n // The node should be in the 'RUNNING' state.\n if (child.getState() === State.RUNNING) {\n // This node is a 'RUNNING' node.\n this.setState(State.RUNNING);\n\n // There is no need to check the rest of the sequence as the current child is still running.\n return;\n }\n\n // The child node was not in an expected state.\n throw new Error(\"child node was not in an expected state.\");\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => \"SEQUENCE\";\n}\n", "import createLotto from \"lotto-draw\";\n\nimport Node from \"../Node\";\nimport Composite from \"./Composite\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A LOTTO node.\n * A winning child is picked on the initial update of this node, based on ticket weighting.\n * The state of this node will match the state of the winning child.\n */\nexport default class Lotto extends Composite {\n /**\n * @param attributes The node attributes.\n * @param weights The child node weights.\n * @param children The child nodes.\n */\n constructor(attributes: Attribute[], private weights: number[] | undefined, children: Node[]) {\n super(\"lotto\", attributes, children);\n }\n\n /**\n * The child node selected to be the active one.\n */\n private selectedChild: Node | undefined;\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // If this node is in the READY state then we need to pick a winning child node.\n if (this.is(State.READY)) {\n // Create a lotto draw with which to randomly pick a child node to become the active one.\n const lottoDraw = createLotto({\n // Hook up the optional 'random' behaviour tree function option to the one used by 'lotto-draw'.\n random: options.random,\n // Pass in each child node as a participant in the lotto draw with their respective ticket count.\n participants: this.children.map((child, index) => [child, this.weights?.[index] || 1])\n });\n\n // Randomly pick a child based on ticket weighting, this will become the active child for this composite node.\n this.selectedChild = lottoDraw.draw() || undefined;\n }\n\n // If something went wrong and we don't have an active child then we should throw an error.\n if (!this.selectedChild) {\n throw new Error(\"failed to update lotto node as it has no active child\");\n }\n\n // If the selected child has never been updated or is running then we will need to update it now.\n if (this.selectedChild.getState() === State.READY || this.selectedChild.getState() === State.RUNNING) {\n this.selectedChild.update(agent, options);\n }\n\n // The state of the lotto node is the state of its selected child.\n this.setState(this.selectedChild.getState());\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => (this.weights ? `LOTTO [${this.weights.join(\",\")}]` : \"LOTTO\");\n}\n", "import Node from \"../Node\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\n\n/**\n * A decorator node that wraps a single child node.\n */\nexport default abstract class Decorator extends Node {\n /**\n * @param type The node type.\n * @param attributes The node attributes.\n * @param child The child node.\n */\n constructor(type: string, attributes: Attribute[], protected child: Node) {\n super(type, attributes, []);\n }\n\n /**\n * Gets whether this node is a leaf node.\n */\n isLeafNode = () => false;\n\n /**\n * Gets the children of this node.\n */\n getChildren = () => [this.child];\n\n /**\n * Reset the state of the node.\n */\n reset = () => {\n // Reset the state of this node.\n this.setState(State.READY);\n\n // Reset the state of the child node.\n this.child.reset();\n };\n\n /**\n * Abort the running of this node.\n * @param agent The agent.\n */\n abort = (agent: Agent) => {\n // There is nothing to do if this node is not in the running state.\n if (!this.is(State.RUNNING)) {\n return;\n }\n\n // Abort the child node.\n this.child.abort(agent);\n\n // Reset the state of this node.\n this.reset();\n\n this.getAttribute(\"exit\")?.callAgentFunction(agent, false, true);\n };\n}\n", "import Node from \"../Node\";\nimport Decorator from \"./Decorator\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A Fail node.\n * This node wraps a single child and will always move to the 'FAILED' state when the child moves to a 'SUCCEEDED' or 'FAILED' state.\n */\nexport default class Fail extends Decorator {\n /**\n * @param attributes The node attributes.\n * @param child The child node.\n */\n constructor(attributes: Attribute[], child: Node) {\n super(\"fail\", attributes, child);\n }\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // If the child has never been updated or is running then we will need to update it now.\n if (this.child.getState() === State.READY || this.child.getState() === State.RUNNING) {\n this.child.update(agent, options);\n }\n\n // The state of this node will depend in the state of its child.\n switch (this.child.getState()) {\n case State.RUNNING:\n this.setState(State.RUNNING);\n break;\n\n case State.SUCCEEDED:\n case State.FAILED:\n this.setState(State.FAILED);\n break;\n\n default:\n this.setState(State.READY);\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => \"FAIL\";\n}\n", "import Decorator from \"./Decorator\";\nimport State from \"../../State\";\nimport Node from \"../Node\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A Flip node.\n * This node wraps a single child and will flip the state of the child state.\n */\nexport default class Flip extends Decorator {\n /**\n * @param attributes The node attributes.\n * @param child The child node.\n */\n constructor(attributes: Attribute[], child: Node) {\n super(\"flip\", attributes, child);\n }\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // If the child has never been updated or is running then we will need to update it now.\n if (this.child.getState() === State.READY || this.child.getState() === State.RUNNING) {\n this.child.update(agent, options);\n }\n\n // The state of this node will depend in the state of its child.\n switch (this.child.getState()) {\n case State.RUNNING:\n this.setState(State.RUNNING);\n break;\n\n case State.SUCCEEDED:\n this.setState(State.FAILED);\n break;\n\n case State.FAILED:\n this.setState(State.SUCCEEDED);\n break;\n\n default:\n this.setState(State.READY);\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => \"FLIP\";\n}\n", "import Node from \"../Node\";\nimport Decorator from \"./Decorator\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A REPEAT node.\n * The node has a single child which can have:\n * -- A number of iterations for which to repeat the child node.\n * -- An infinite repeat loop if neither an iteration count or a condition function is defined.\n * The REPEAT node will stop and have a 'FAILED' state if its child is ever in a 'FAILED' state after an update.\n * The REPEAT node will attempt to move on to the next iteration if its child is ever in a 'SUCCEEDED' state.\n */\nexport default class Repeat extends Decorator {\n /**\n * @param attributes The node attributes.\n * @param iterations The number of iterations to repeat the child node.\n * @param iterationsMin The minimum possible number of iterations to repeat the child node.\n * @param iterationsMax The maximum possible number of iterations to repeat the child node.\n * @param child The child node.\n */\n constructor(\n attributes: Attribute[],\n private iterations: number | null,\n private iterationsMin: number | null,\n private iterationsMax: number | null,\n child: Node\n ) {\n super(\"repeat\", attributes, child);\n }\n\n /**\n * The number of target iterations to make.\n */\n private targetIterationCount: number | null = null;\n\n /**\n * The current iteration count.\n */\n private currentIterationCount: number = 0;\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // If this node is in the READY state then we need to reset the child and the target iteration count.\n if (this.is(State.READY)) {\n // Reset the child node.\n this.child.reset();\n\n // Reset the current iteration count.\n this.currentIterationCount = 0;\n\n // Set the target iteration count.\n this.setTargetIterationCount(options);\n }\n\n // Do a check to see if we can iterate. If we can then this node will move into the 'RUNNING' state.\n // If we cannot iterate then we have hit our target iteration count, which means that the node has succeeded.\n if (this.canIterate()) {\n // This node is in the running state and can do its initial iteration.\n this.setState(State.RUNNING);\n\n // We may have already completed an iteration, meaning that the child node will be in the SUCCEEDED state.\n // If this is the case then we will have to reset the child node now.\n if (this.child.getState() === State.SUCCEEDED) {\n this.child.reset();\n }\n\n // Update the child of this node.\n this.child.update(agent, options);\n\n // If the child moved into the FAILED state when we updated it then there is nothing left to do and this node has also failed.\n // If it has moved into the SUCCEEDED state then we have completed the current iteration.\n if (this.child.getState() === State.FAILED) {\n // The child has failed, meaning that this node has failed.\n this.setState(State.FAILED);\n\n return;\n } else if (this.child.getState() === State.SUCCEEDED) {\n // We have completed an iteration.\n this.currentIterationCount += 1;\n }\n } else {\n // This node is in the 'SUCCEEDED' state as we cannot iterate any more.\n this.setState(State.SUCCEEDED);\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => {\n if (this.iterations !== null) {\n return `REPEAT ${this.iterations}x`;\n } else if (this.iterationsMin !== null && this.iterationsMax !== null) {\n return `REPEAT ${this.iterationsMin}x-${this.iterationsMax}x`;\n } else {\n return \"REPEAT\";\n }\n };\n\n /**\n * Reset the state of the node.\n */\n reset = () => {\n // Reset the state of this node.\n this.setState(State.READY);\n\n // Reset the current iteration count.\n this.currentIterationCount = 0;\n\n // Reset the child node.\n this.child.reset();\n };\n\n /**\n * Gets whether an iteration can be made.\n * @returns Whether an iteration can be made.\n */\n private canIterate = () => {\n if (this.targetIterationCount !== null) {\n // We can iterate as long as we have not reached our target iteration count.\n return this.currentIterationCount < this.targetIterationCount;\n }\n\n // If neither an iteration count or a condition function were defined then we can iterate indefinitely.\n return true;\n };\n\n /**\n * Sets the target iteration count.\n * @param options The behaviour tree options object.\n */\n private setTargetIterationCount = (options: BehaviourTreeOptions) => {\n // Are we dealing with an explicit iteration count or will we be randomly picking a iteration count between the min and max iteration count.\n if (this.iterations !== null) {\n this.targetIterationCount = this.iterations;\n } else if (this.iterationsMin !== null && this.iterationsMax !== null) {\n // We will be picking a random iteration count between a min and max iteration count, if the optional 'random'\n // behaviour tree function option is defined then we will be using that, otherwise we will fall back to using Math.random.\n const random = typeof options.random === \"function\" ? options.random : Math.random;\n\n // Pick a random iteration count between a min and max iteration count.\n this.targetIterationCount = Math.floor(\n random() * (this.iterationsMax - this.iterationsMin + 1) + this.iterationsMin\n );\n } else {\n this.targetIterationCount = null;\n }\n };\n}\n", "import Node from \"../Node\";\nimport Decorator from \"./Decorator\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A RETRY node.\n * The node has a single child which can have:\n * -- A number of iterations for which to repeat the child node.\n * -- An infinite repeat loop if neither an iteration count or a condition function is defined.\n * The RETRY node will stop and have a 'SUCCEEDED' state if its child is ever in a 'SUCCEEDED' state after an update.\n * The RETRY node will attempt to move on to the next iteration if its child is ever in a 'FAILED' state.\n */\nexport default class Retry extends Decorator {\n /**\n * @param attributes The node attributes.\n * @param attempts The number of attempts to retry the child node.\n * @param attemptsMin The minimum possible number of attempts to retry the child node.\n * @param attemptsMax The maximum possible number of attempts to retry the child node.\n * @param child The child node.\n */\n constructor(\n attributes: Attribute[],\n private attempts: number | null,\n private attemptsMin: number | null,\n private attemptsMax: number | null,\n child: Node\n ) {\n super(\"retry\", attributes, child);\n }\n\n /**\n * The number of target attempts to make.\n */\n private targetAttemptCount: number | null = null;\n\n /**\n * The current attempt count.\n */\n private currentAttemptCount: number = 0;\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // If this node is in the READY state then we need to reset the child and the target attempt count.\n if (this.is(State.READY)) {\n // Reset the child node.\n this.child.reset();\n\n // Reset the current attempt count.\n this.currentAttemptCount = 0;\n\n // Set the target attempt count.\n this.setTargetAttemptCount(options);\n }\n\n // Do a check to see if we can attempt. If we can then this node will move into the 'RUNNING' state.\n // If we cannot attempt then we have hit our target attempt count, which means that the node has succeeded.\n if (this.canAttempt()) {\n // This node is in the running state and can do its initial attempt.\n this.setState(State.RUNNING);\n\n // We may have already completed an attempt, meaning that the child node will be in the FAILED state.\n // If this is the case then we will have to reset the child node now.\n if (this.child.getState() === State.FAILED) {\n this.child.reset();\n }\n\n // Update the child of this node.\n this.child.update(agent, options);\n\n // If the child moved into the SUCCEEDED state when we updated it then there is nothing left to do and this node has also succeeded.\n // If it has moved into the FAILED state then we have completed the current attempt.\n if (this.child.getState() === State.SUCCEEDED) {\n // The child has succeeded, meaning that this node has succeeded.\n this.setState(State.SUCCEEDED);\n\n return;\n } else if (this.child.getState() === State.FAILED) {\n // We have completed an attempt.\n this.currentAttemptCount += 1;\n }\n } else {\n // This node is in the 'FAILED' state as we cannot iterate any more.\n this.setState(State.FAILED);\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => {\n if (this.attempts !== null) {\n return `RETRY ${this.attempts}x`;\n } else if (this.attemptsMin !== null && this.attemptsMax !== null) {\n return `RETRY ${this.attemptsMin}x-${this.attemptsMax}x`;\n } else {\n return \"RETRY\";\n }\n };\n\n /**\n * Reset the state of the node.\n */\n reset = () => {\n // Reset the state of this node.\n this.setState(State.READY);\n\n // Reset the current attempt count.\n this.currentAttemptCount = 0;\n\n // Reset the child node.\n this.child.reset();\n };\n\n /**\n * Gets whether an attempt can be made.\n * @returns Whether an attempt can be made.\n */\n canAttempt = () => {\n if (this.targetAttemptCount !== null) {\n // We can attempt as long as we have not reached our target attempt count.\n return this.currentAttemptCount < this.targetAttemptCount;\n }\n\n // If neither an attempt count or a condition function were defined then we can attempt indefinitely.\n return true;\n };\n\n /**\n * Sets the target attempt count.\n * @param options The behaviour tree options object.\n */\n setTargetAttemptCount = (options: BehaviourTreeOptions) => {\n // Are we dealing with an explicit attempt count or will we be randomly picking an attempt count between the min and max attempt count.\n if (this.attempts !== null) {\n this.targetAttemptCount = this.attempts;\n } else if (this.attemptsMin !== null && this.attemptsMax !== null) {\n // We will be picking a random attempt count between a min and max attempt count, if the optional 'random'\n // behaviour tree function option is defined then we will be using that, otherwise we will fall back to using Math.random.\n const random = typeof options.random === \"function\" ? options.random : Math.random;\n\n // Pick a random attempt count between a min and max attempt count.\n this.targetAttemptCount = Math.floor(\n random() * (this.attemptsMax - this.attemptsMin + 1) + this.attemptsMin\n );\n } else {\n this.targetAttemptCount = null;\n }\n };\n}\n", "import Node from \"../Node\";\nimport Decorator from \"./Decorator\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A Root node.\n * The root node will have a single child.\n */\nexport default class Root extends Decorator {\n /**\n * @param attributes The node attributes.\n * @param child The child node.\n */\n constructor(attributes: Attribute[], child: Node) {\n super(\"root\", attributes, child);\n }\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // If the child has never been updated or is running then we will need to update it now.\n if (this.child.getState() === State.READY || this.child.getState() === State.RUNNING) {\n // Update the child of this node.\n this.child.update(agent, options);\n }\n\n // The state of the root node is the state of its child.\n this.setState(this.child.getState());\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => \"ROOT\";\n}\n", "import Node from \"../Node\";\nimport Decorator from \"./Decorator\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A Succeed node.\n * This node wraps a single child and will always move to the 'SUCCEEDED' state when the child moves to a 'SUCCEEDED' or 'FAILED' state.\n */\nexport default class Succeed extends Decorator {\n /**\n * @param attributes The node attributes.\n * @param child The child node.\n */\n constructor(attributes: Attribute[], child: Node) {\n super(\"succeed\", attributes, child);\n }\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // If the child has never been updated or is running then we will need to update it now.\n if (this.child.getState() === State.READY || this.child.getState() === State.RUNNING) {\n this.child.update(agent, options);\n }\n\n // The state of this node will depend in the state of its child.\n switch (this.child.getState()) {\n case State.RUNNING:\n this.setState(State.RUNNING);\n break;\n\n case State.SUCCEEDED:\n case State.FAILED:\n this.setState(State.SUCCEEDED);\n break;\n\n default:\n this.setState(State.READY);\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => \"SUCCEED\";\n}\n", "import Node from \"../Node\";\n\n/**\n * A leaf node.\n */\nexport default abstract class Leaf extends Node {\n /**\n * Gets whether this node is a leaf node.\n */\n isLeafNode = () => true;\n}\n", "import { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\nimport State, { CompleteState } from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Leaf from \"./Leaf\";\nimport Lookup from \"../../Lookup\";\nimport Attribute from \"../../attributes/Attribute\";\n\n/**\n * An Action leaf node.\n * This represents an immediate or ongoing state of behaviour.\n */\nexport default class Action extends Leaf {\n /**\n * @param attributes The node attributes.\n * @param actionName The action name.\n * @param actionArguments The array of action argument definitions.\n */\n constructor(attributes: Attribute[], private actionName: string, private actionArguments: any[]) {\n super(\"action\", attributes, actionArguments);\n }\n\n /**\n * Whether there is a pending update promise.\n */\n private isUsingUpdatePromise = false;\n\n /**\n * The finished state result of an update promise.\n */\n private updatePromiseStateResult: CompleteState | null = null;\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // If the result of this action depends on an update promise then there is nothing to do until\n // it resolves, unless there has been a value set as a result of the update promise resolving.\n if (this.isUsingUpdatePromise) {\n // Check whether the update promise has resolved with a state value.\n if (this.updatePromiseStateResult) {\n // Set the state of this node to match the state returned by the promise.\n this.setState(this.updatePromiseStateResult);\n }\n\n return;\n }\n\n // Attempt to get the invoker for the action function.\n const actionFuncInvoker = Lookup.getFuncInvoker(agent, this.actionName);\n\n // The action function should be defined.\n if (actionFuncInvoker === null) {\n throw new Error(\n `cannot update action node as the action '${this.actionName}' function is not defined on the agent and has not been registered`\n );\n }\n\n // Call the action function, the result of which may be:\n // - The finished state of this action node.\n // - A promise to return a finished node state.\n // - Undefined if the node should remain in the running state.\n const updateResult = actionFuncInvoker(this.actionArguments) as CompleteState | Promise;\n\n if (updateResult instanceof Promise) {\n updateResult.then(\n (result) => {\n // If 'isUpdatePromisePending' is null then the promise was cleared as it was resolving, probably via an abort of reset.\n if (!this.isUsingUpdatePromise) {\n return;\n }\n\n // Check to make sure the result is a valid finished state.\n if (result !== State.SUCCEEDED && result !== State.FAILED) {\n throw new Error(\n \"action node promise resolved with an invalid value, expected a State.SUCCEEDED or State.FAILED value to be returned\"\n );\n }\n\n // Set pending update promise state result to be processed on next update.\n this.updatePromiseStateResult = result;\n },\n (reason) => {\n // If 'isUpdatePromisePending' is null then the promise was cleared as it was resolving, probably via an abort of reset.\n if (!this.isUsingUpdatePromise) {\n return;\n }\n\n // Just throw whatever was returned as the rejection argument.\n throw new Error(reason);\n }\n );\n\n // This node will be in the 'RUNNING' state until the update promise resolves.\n this.setState(State.RUNNING);\n\n // We are now waiting for the promise returned by the use to resolve before we know what state this node is in.\n this.isUsingUpdatePromise = true;\n } else {\n // Validate the returned value.\n this.validateUpdateResult(updateResult);\n\n // Set the state of this node, this may be undefined, which just means that the node is still in the 'RUNNING' state.\n this.setState(updateResult || State.RUNNING);\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => this.actionName;\n\n /**\n * Reset the state of the node.\n */\n reset = () => {\n // Reset the state of this node.\n this.setState(State.READY);\n\n // There is no longer an update promise that we care about.\n this.isUsingUpdatePromise = false;\n this.updatePromiseStateResult = null;\n };\n\n /**\n * Validate the result of an update function call.\n * @param result The result of an update function call.\n */\n private validateUpdateResult = (result: CompleteState | boolean) => {\n switch (result) {\n case State.SUCCEEDED:\n case State.FAILED:\n case undefined:\n return;\n default:\n throw new Error(\n `action '${this.actionName}' 'onUpdate' returned an invalid response, expected an optional State.SUCCEEDED or State.FAILED value to be returned`\n );\n }\n };\n}\n", "import { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Leaf from \"./Leaf\";\nimport Lookup from \"../../Lookup\";\nimport Attribute from \"../../attributes/Attribute\";\n\n/**\n * A Condition leaf node.\n * This will succeed or fail immediately based on an agent predicate, without moving to the 'RUNNING' state.\n */\nexport default class Condition extends Leaf {\n /**\n * @param attributes The node attributes.\n * @param conditionName The name of the condition function.\n * @param conditionArguments The array of condition argument definitions.\n */\n constructor(attributes: Attribute[], private conditionName: string, private conditionArguments: any[]) {\n super(\"condition\", attributes, conditionArguments);\n }\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // Attempt to get the invoker for the condition function.\n const conditionFuncInvoker = Lookup.getFuncInvoker(agent, this.conditionName);\n\n // The condition function should be defined.\n if (conditionFuncInvoker === null) {\n throw new Error(\n `cannot update condition node as the condition '${this.conditionName}' function is not defined on the agent and has not been registered`\n );\n }\n\n // Call the condition function to determine the state of this node.\n this.setState(!!conditionFuncInvoker(this.conditionArguments) ? State.SUCCEEDED : State.FAILED);\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => this.conditionName;\n}\n", "import Leaf from \"./Leaf\";\nimport State from \"../../State\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { Agent } from \"../../Agent\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A WAIT node.\n * The state of this node will change to SUCCEEDED after a duration of time\n */\nexport default class Wait extends Leaf {\n /**\n * @param attributes The node attributes.\n * @param duration The duration that this node will wait to succeed in milliseconds.\n * @param durationMin The minimum possible duration in milliseconds that this node will wait to succeed.\n * @param durationMax The maximum possible duration in milliseconds that this node will wait to succeed.\n */\n constructor(\n attributes: Attribute[],\n private duration: number | null,\n private durationMin: number | null,\n private durationMax: number | null\n ) {\n super(\"wait\", attributes, []);\n }\n\n /**\n * The time in milliseconds at which this node was first updated.\n */\n private initialUpdateTime: number = 0;\n\n /**\n * The total duration in milliseconds that this node will be waiting for.\n */\n private totalDuration: number | null = null;\n\n /**\n * The duration in milliseconds that this node has been waiting for.\n */\n private waitedDuration: number = 0;\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // If this node is in the READY state then we need to set the initial update time.\n if (this.is(State.READY)) {\n // Set the initial update time.\n this.initialUpdateTime = new Date().getTime();\n\n // Set the initial waited duration.\n this.waitedDuration = 0;\n\n // Are we dealing with an explicit duration or will we be randomly picking a duration between the min and max duration.\n if (this.duration !== null) {\n this.totalDuration = this.duration;\n } else if (this.durationMin !== null && this.durationMax !== null) {\n // We will be picking a random duration between a min and max duration, if the optional 'random' behaviour tree\n // function option is defined then we will be using that, otherwise we will fall back to using Math.random.\n const random = typeof options.random === \"function\" ? options.random : Math.random;\n\n // Pick a random duration between a min and max duration.\n this.totalDuration = Math.floor(\n random() * (this.durationMax - this.durationMin + 1) + this.durationMin\n );\n } else {\n this.totalDuration = null;\n }\n\n // The node is now running until we finish waiting.\n this.setState(State.RUNNING);\n }\n\n // If we have no total duration then this wait node will wait indefinitely until it is aborted.\n if (this.totalDuration === null) {\n return;\n }\n\n // If we have a 'getDeltaTime' function defined as part of our options then we will use it to figure out how long we have waited for.\n if (typeof options.getDeltaTime === \"function\") {\n // Get the delta time.\n const deltaTime = options.getDeltaTime();\n\n // Our delta time must be a valid number and cannot be NaN.\n if (typeof deltaTime !== \"number\" || isNaN(deltaTime)) {\n throw new Error(\"The delta time must be a valid number and not NaN.\");\n }\n\n // Update the amount of time that this node has been waiting for based on the delta time.\n this.waitedDuration += deltaTime * 1000;\n } else {\n // We are not using a delta time, so we will just work out hom much time has passed since the first update.\n this.waitedDuration = new Date().getTime() - this.initialUpdateTime;\n }\n\n // Have we waited long enough?\n if (this.waitedDuration >= this.totalDuration) {\n // We have finished waiting!\n this.setState(State.SUCCEEDED);\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => {\n if (this.duration !== null) {\n return `WAIT ${this.duration}ms`;\n } else if (this.durationMin !== null && this.durationMax !== null) {\n return `WAIT ${this.durationMin}ms-${this.durationMax}ms`;\n } else {\n return \"WAIT\";\n }\n };\n}\n", "import Guard from \"./guards/Guard\";\n\nexport type AttributeDetails = {\n /** The attribute type. */\n type: string;\n\n /** The attribute arguments. */\n args: any[];\n};\n\n/**\n * A base node attribute.\n */\nexport default abstract class Attribute {\n /**\n * @param type The node attribute type.\n * @param args The array of attribute arguments.\n */\n constructor(public type: string, public args: any[]) {}\n\n /**\n * Gets the attribute details.\n */\n abstract getDetails(): TAttributeDetails;\n\n /**\n * Gets whether this attribute is a guard.\n */\n abstract isGuard: () => this is Guard;\n}\n", "import { Agent } from \"../../Agent\";\nimport Attribute, { AttributeDetails } from \"../Attribute\";\n\nexport type GuardAttributeDetails = {\n /** The name of the condition function that determines whether the guard is satisfied. */\n condition: string;\n} & AttributeDetails;\n\n/**\n * A base node guard attribute.\n */\nexport default abstract class Guard extends Attribute {\n /**\n * @param type The node attribute type.\n * @param args The array of decorator argument definitions.\n * @param condition The name of the condition function that determines whether the guard is satisfied.\n */\n constructor(type: string, args: any[], private condition: string) {\n super(type, args);\n }\n\n /**\n * Gets the name of the condition function that determines whether the guard is satisfied.\n */\n getCondition = () => this.condition;\n\n /**\n * Gets whether this attribute is a guard.\n */\n isGuard = () => true;\n\n /**\n * Gets the attribute details.\n */\n getDetails(): GuardAttributeDetails {\n return {\n type: this.type,\n args: this.args,\n condition: this.getCondition()\n };\n }\n\n /**\n * Gets whether the guard is satisfied.\n * @param agent The agent.\n * @returns Whether the guard is satisfied.\n */\n abstract isSatisfied(agent: Agent): boolean;\n}\n", "import Guard from \"./Guard\";\nimport Lookup from \"../../Lookup\";\nimport { Agent } from \"../../Agent\";\n\n/**\n * A WHILE guard which is satisfied as long as the given condition remains true.\n */\nexport default class While extends Guard {\n /**\n * @param condition The name of the condition function that determines whether the guard is satisfied.\n * @param args The array of decorator argument definitions.\n */\n constructor(condition: string, args: any[]) {\n super(\"while\", args, condition);\n }\n\n /**\n * Gets whether the guard is satisfied.\n * @param agent The agent.\n * @returns Whether the guard is satisfied.\n */\n isSatisfied = (agent: Agent) => {\n // Attempt to get the invoker for the condition function.\n const conditionFuncInvoker = Lookup.getFuncInvoker(agent, this.getCondition());\n\n // The condition function should be defined.\n if (conditionFuncInvoker === null) {\n throw new Error(\n `cannot evaluate node guard as the condition '${this.getCondition()}' function is not defined on the agent and has not been registered`\n );\n }\n\n // Call the condition function to determine whether this guard is satisfied.\n return !!conditionFuncInvoker(this.args);\n };\n}\n", "import Guard from \"./Guard\";\nimport Lookup from \"../../Lookup\";\nimport { Agent } from \"../../Agent\";\n\n/**\n * An UNTIL guard which is satisfied as long as the given condition remains false.\n */\nexport default class Until extends Guard {\n /**\n * @param condition The name of the condition function that determines whether the guard is satisfied.\n * @param args The array of decorator argument definitions.\n */\n constructor(condition: string, args: any[]) {\n super(\"until\", args, condition);\n }\n\n /**\n * Gets whether the guard is satisfied.\n * @param agent The agent.\n * @returns Whether the guard is satisfied.\n */\n isSatisfied = (agent: Agent) => {\n // Attempt to get the invoker for the condition function.\n const conditionFuncInvoker = Lookup.getFuncInvoker(agent, this.getCondition());\n\n // The condition function should be defined.\n if (conditionFuncInvoker === null) {\n throw new Error(\n `cannot evaluate node guard as the condition '${this.getCondition()}' function is not defined on the agent and has not been registered`\n );\n }\n\n // Call the condition function to determine whether this guard is satisfied.\n return !!!conditionFuncInvoker(this.args);\n };\n}\n", "import { Agent } from \"../../Agent\";\nimport Attribute, { AttributeDetails } from \"../Attribute\";\n\nexport type CallbackAttributeDetails = {\n /** The name of the agent function that is called. */\n functionName: string;\n} & AttributeDetails;\n\n/**\n * A base node callback attribute.\n */\nexport default abstract class Callback extends Attribute {\n /**\n * @param type The node attribute type.\n * @param args The array of decorator argument definitions.\n * @param functionName The name of the agent function to call.\n */\n constructor(type: string, args: any[], private functionName: string) {\n super(type, args);\n }\n\n /**\n * Gets the name of the agent function to call.\n */\n getFunctionName = () => this.functionName;\n\n /**\n * Gets whether this attribute is a guard.\n */\n isGuard = () => false;\n\n /**\n * Gets the attribute details.\n */\n getDetails(): CallbackAttributeDetails {\n return {\n type: this.type,\n args: this.args,\n functionName: this.getFunctionName()\n };\n }\n\n /**\n * Attempt to call the agent function that this callback refers to.\n * @param agent The agent.\n */\n abstract callAgentFunction: (agent: Agent, isSuccess: boolean, isAborted: boolean) => void;\n}\n", "import Callback from \"./Callback\";\nimport Lookup from \"../../Lookup\";\nimport { Agent } from \"../../Agent\";\n\n/**\n * An ENTRY callback which defines an agent function to call when the associated node is updated and moves out of running state.\n */\nexport default class Entry extends Callback {\n /**\n * @param functionName The name of the agent function to call.\n * @param args The array of callback argument definitions.\n */\n constructor(functionName: string, args: any[]) {\n super(\"entry\", args, functionName);\n }\n\n /**\n * Attempt to call the agent function that this callback refers to.\n * @param agent The agent.\n */\n callAgentFunction = (agent: Agent) => {\n // Attempt to get the invoker for the callback function.\n const callbackFuncInvoker = Lookup.getFuncInvoker(agent, this.getFunctionName());\n\n // The callback function should be defined.\n if (callbackFuncInvoker === null) {\n throw new Error(\n `cannot call entry function '${this.getFunctionName()}' as is not defined on the agent and has not been registered`\n );\n }\n\n // Call the callback function.\n callbackFuncInvoker(this.args);\n };\n}\n", "import Callback from \"./Callback\";\nimport Lookup from \"../../Lookup\";\nimport { Agent } from \"../../Agent\";\n\n/**\n * A STEP callback which defines an agent function to call when the associated node is updated.\n */\nexport default class Step extends Callback {\n /**\n * @param functionName The name of the agent function to call.\n * @param args The array of callback argument definitions.\n */\n constructor(functionName: string, args: any[]) {\n super(\"step\", args, functionName);\n }\n\n /**\n * Attempt to call the agent function that this callback refers to.\n * @param agent The agent.\n */\n callAgentFunction = (agent: Agent) => {\n // Attempt to get the invoker for the callback function.\n const callbackFuncInvoker = Lookup.getFuncInvoker(agent, this.getFunctionName());\n\n // The callback function should be defined.\n if (callbackFuncInvoker === null) {\n throw new Error(\n `cannot call step function '${this.getFunctionName()}' as is not defined on the agent and has not been registered`\n );\n }\n\n // Call the callback function.\n callbackFuncInvoker(this.args);\n };\n}\n", "import Callback from \"./Callback\";\nimport Lookup from \"../../Lookup\";\nimport { Agent } from \"../../Agent\";\n\n/**\n * An EXIT callback which defines an agent function to call when the associated node is updated and moves to a finished state or is aborted.\n */\nexport default class Exit extends Callback {\n /**\n * @param functionName The name of the agent function to call.\n * @param args The array of callback argument definitions.\n */\n constructor(functionName: string, args: any[]) {\n super(\"exit\", args, functionName);\n }\n\n /**\n * Attempt to call the agent function that this callback refers to.\n * @param agent The agent.\n * @param isSuccess Whether the decorated node was left with a success state.\n * @param isAborted Whether the decorated node was aborted.\n */\n callAgentFunction = (agent: Agent, isSuccess: boolean, isAborted: boolean) => {\n // Attempt to get the invoker for the callback function.\n const callbackFuncInvoker = Lookup.getFuncInvoker(agent, this.getFunctionName());\n\n // The callback function should be defined.\n if (callbackFuncInvoker === null) {\n throw new Error(\n `cannot call exit function '${this.getFunctionName()}' as is not defined on the agent and has not been registered`\n );\n }\n\n // Call the callback function\n callbackFuncInvoker([{ value: { succeeded: isSuccess, aborted: isAborted } }, ...this.args]);\n };\n}\n", "import { AnyNodeDefinition, RootNodeDefinition } from \"./BehaviourTreeDefinition\";\nimport GuardPath, { GuardPathPart } from \"./attributes/guards/GuardPath\";\nimport { validateBranchSubtreeLinks } from \"./BehaviourTreeDefinitionValidator\";\nimport { isInteger } from \"./BehaviourTreeDefinitionUtilities\";\nimport Node from \"./nodes/Node\";\nimport Composite from \"./nodes/composite/Composite\";\nimport Decorator from \"./nodes/decorator/Decorator\";\nimport Parallel from \"./nodes/composite/Parallel\";\nimport Selector from \"./nodes/composite/Selector\";\nimport Sequence from \"./nodes/composite/Sequence\";\nimport Lotto from \"./nodes/composite/Lotto\";\nimport Fail from \"./nodes/decorator/Fail\";\nimport Flip from \"./nodes/decorator/Flip\";\nimport Repeat from \"./nodes/decorator/Repeat\";\nimport Retry from \"./nodes/decorator/Retry\";\nimport Root from \"./nodes/decorator/Root\";\nimport Succeed from \"./nodes/decorator/Succeed\";\nimport Action from \"./nodes/leaf/Action\";\nimport Condition from \"./nodes/leaf/Condition\";\nimport Wait from \"./nodes/leaf/Wait\";\nimport Lookup from \"./Lookup\";\nimport Attribute from \"./attributes/Attribute\";\nimport While from \"./attributes/guards/While\";\nimport Until from \"./attributes/guards/Until\";\nimport Entry from \"./attributes/callbacks/Entry\";\nimport Step from \"./attributes/callbacks/Step\";\nimport Exit from \"./attributes/callbacks/Exit\";\n\n/**\n * A type representing any node instance in a behaviour tree.\n */\ntype AnyNode =\n | Root\n | Action\n | Condition\n | Wait\n | Sequence\n | Selector\n | Lotto\n | Parallel\n | Repeat\n | Retry\n | Flip\n | Succeed\n | Fail;\n\n/**\n * A type defining a mapping of root node identifiers to root node definitions.\n */\ntype RootNodeDefinitionMap = { [key: string | symbol]: RootNodeDefinition };\n\n/**\n * A symbol to use as the main root key in any root node mappings.\n */\nconst MAIN_ROOT_NODE_KEY = Symbol(\"__root__\");\n\n/**\n * Build and populate the root nodes based on the provided definition, assuming that the definition has been validated.\n * @param definition The root node definitions.\n * @returns The built and populated root node definitions.\n */\nexport default function buildRootNode(definition: RootNodeDefinition[]): Root {\n // Create a mapping of root node identifers to root node definitions, including globally registered subtree root node definitions.\n const rootNodeDefinitionMap = createRootNodeDefinitionMap(definition);\n\n // Now that we have all of our root node definitons (those part of the tree definition and those globally\n // registered) we should validate the definition. This will also double-check that we dont have any circular\n // dependencies in our branch -> subtree references and that we have no broken branch -> subtree links.\n validateBranchSubtreeLinks(definition, true);\n\n // Create our populated tree of node instances, starting with our main root node.\n const rootNode = nodeFactory(rootNodeDefinitionMap[MAIN_ROOT_NODE_KEY], rootNodeDefinitionMap) as Root;\n\n // Set a guard path on every leaf of the tree to evaluate as part of each update.\n applyLeafNodeGuardPaths(rootNode);\n\n // We only need to return the main root node.\n return rootNode;\n}\n\n/**\n * A factory function which creates a node instance based on the specified definition.\n * @param definition The node definition.\n * @param rootNodeDefinitionMap The mapping of root node identifers to root node definitions, including globally registered subtree root node definitions.\n * @returns A node instance based on the specified definition.\n */\nfunction nodeFactory(definition: AnyNodeDefinition, rootNodeDefinitionMap: RootNodeDefinitionMap): AnyNode {\n // Get the attributes for the node.\n const attributes = nodeAttributesFactory(definition);\n\n // Create the node instance based on the definition type.\n switch (definition.type) {\n case \"root\":\n return new Root(attributes, nodeFactory(definition.child, rootNodeDefinitionMap));\n\n case \"repeat\":\n let iterations: number | null = null;\n let iterationsMin: number | null = null;\n let iterationsMax: number | null = null;\n\n if (Array.isArray(definition.iterations)) {\n iterationsMin = definition.iterations[0];\n iterationsMax = definition.iterations[1];\n } else if (isInteger(definition.iterations)) {\n iterations = definition.iterations!;\n }\n\n return new Repeat(\n attributes,\n iterations,\n iterationsMin,\n iterationsMax,\n nodeFactory(definition.child, rootNodeDefinitionMap)\n );\n\n case \"retry\":\n let attempts: number | null = null;\n let attemptsMin: number | null = null;\n let attemptsMax: number | null = null;\n\n if (Array.isArray(definition.attempts)) {\n attemptsMin = definition.attempts[0];\n attemptsMax = definition.attempts[1];\n } else if (isInteger(definition.attempts)) {\n attempts = definition.attempts!;\n }\n\n return new Retry(\n attributes,\n attempts,\n attemptsMin,\n attemptsMax,\n nodeFactory(definition.child, rootNodeDefinitionMap)\n );\n\n case \"flip\":\n return new Flip(attributes, nodeFactory(definition.child, rootNodeDefinitionMap));\n\n case \"succeed\":\n return new Succeed(attributes, nodeFactory(definition.child, rootNodeDefinitionMap));\n\n case \"fail\":\n return new Fail(attributes, nodeFactory(definition.child, rootNodeDefinitionMap));\n\n case \"sequence\":\n return new Sequence(\n attributes,\n definition.children.map((child) => nodeFactory(child, rootNodeDefinitionMap))\n );\n\n case \"selector\":\n return new Selector(\n attributes,\n definition.children.map((child) => nodeFactory(child, rootNodeDefinitionMap))\n );\n\n case \"parallel\":\n return new Parallel(\n attributes,\n definition.children.map((child) => nodeFactory(child, rootNodeDefinitionMap))\n );\n\n case \"lotto\":\n return new Lotto(\n attributes,\n definition.weights,\n definition.children.map((child) => nodeFactory(child, rootNodeDefinitionMap))\n );\n\n case \"branch\":\n return nodeFactory(rootNodeDefinitionMap[definition.ref].child, rootNodeDefinitionMap);\n\n case \"action\":\n return new Action(attributes, definition.call, definition.args || []);\n\n case \"condition\":\n return new Condition(attributes, definition.call, definition.args || []);\n\n case \"wait\":\n let duration: number | null = null;\n let durationMin: number | null = null;\n let durationMax: number | null = null;\n\n if (Array.isArray(definition.duration)) {\n durationMin = definition.duration[0];\n durationMax = definition.duration[1];\n } else if (isInteger(definition.duration)) {\n duration = definition.duration!;\n }\n\n return new Wait(attributes, duration, durationMin, durationMax);\n }\n}\n\n/**\n * Creates an array of node attribute instances based on the specified node definition.\n * @param definition The node definition.\n * @returns An array of node attribute instances based on the specified node definition.\n */\nfunction nodeAttributesFactory(definition: AnyNodeDefinition): Attribute[] {\n const attributes: Attribute[] = [];\n\n if (definition.while) {\n attributes.push(new While(definition.while.call, definition.while.args ?? []));\n }\n\n if (definition.until) {\n attributes.push(new Until(definition.until.call, definition.until.args ?? []));\n }\n\n if (definition.entry) {\n attributes.push(new Entry(definition.entry.call, definition.entry.args ?? []));\n }\n\n if (definition.step) {\n attributes.push(new Step(definition.step.call, definition.step.args ?? []));\n }\n\n if (definition.exit) {\n attributes.push(new Exit(definition.exit.call, definition.exit.args ?? []));\n }\n\n return attributes;\n}\n\n/**\n * Creates a mapping of root node identifers to root node definitions, mixing in globally registered subtree root node definitions.\n * @param definition The root node definitions.\n * @returns A mapping of root node identifers to root node definitions, including globally registered subtree root node definitions.\n */\nfunction createRootNodeDefinitionMap(definition: RootNodeDefinition[]): RootNodeDefinitionMap {\n // Create a mapping of root node identifers to root node definitions.\n const rootNodeMap: RootNodeDefinitionMap = {};\n\n // Add in any registered subtree root node definitions.\n for (const [name, rootNodeDefinition] of Object.entries(Lookup.getSubtrees())) {\n // The name used when registering the subtree will be used as the root node identifier.\n rootNodeMap[name] = { ...rootNodeDefinition, id: name };\n }\n\n // Populate the map with the root node definitions that were included with the tree definition.\n // We do this after adding any registered subtrees as we want these to take presedence.\n for (const rootNodeDefinition of definition) {\n rootNodeMap[rootNodeDefinition.id ?? MAIN_ROOT_NODE_KEY] = rootNodeDefinition;\n }\n\n return rootNodeMap;\n}\n\n/**\n * Applies a guard path to every leaf of the tree to evaluate as part of each update.\n * @param root The main root tree node.\n */\nfunction applyLeafNodeGuardPaths(root: Root) {\n const nodePaths: Node[][] = [];\n\n const findLeafNodes = (path: Node[], node: Node) => {\n // Add the current node to the path.\n path = path.concat(node);\n\n // Check whether the current node is a leaf node.\n if (node.isLeafNode()) {\n nodePaths.push(path);\n } else {\n (node as Composite | Decorator).getChildren().forEach((child) => findLeafNodes(path, child));\n }\n };\n\n // Find all leaf node paths, starting from the root.\n findLeafNodes([], root);\n\n nodePaths.forEach((path) => {\n // Each node in the current path will have to be assigned a guard path, working from the root outwards.\n for (let depth = 0; depth < path.length; depth++) {\n // Get the node in the path at the current depth.\n const currentNode = path[depth];\n\n // The node may already have been assigned a guard path, if so just skip it.\n if (currentNode.hasGuardPath()) {\n continue;\n }\n\n // Create the guard path for the current node.\n const guardPath = new GuardPath(\n path\n .slice(0, depth + 1)\n .map((node) => ({ node, guards: node.getGuardAttributes() }))\n .filter((details) => details.guards.length > 0)\n );\n\n // Assign the guard path to the current node.\n currentNode.setGuardPath(guardPath);\n }\n });\n}\n", "import State, { AnyState } from \"./State\";\nimport Lookup from \"./Lookup\";\nimport Node from \"./nodes/Node\";\nimport Root from \"./nodes/decorator/Root\";\nimport Composite from \"./nodes/composite/Composite\";\nimport Decorator from \"./nodes/decorator/Decorator\";\nimport { Agent, GlobalFunction } from \"./Agent\";\nimport { CallbackAttributeDetails } from \"./attributes/callbacks/Callback\";\nimport { GuardAttributeDetails } from \"./attributes/guards/Guard\";\nimport { BehaviourTreeOptions } from \"./BehaviourTreeOptions\";\nimport { convertMDSLToJSON } from \"./mdsl/MDSLDefinitionParser\";\nimport { RootNodeDefinition } from \"./BehaviourTreeDefinition\";\nimport { validateJSONDefinition } from \"./BehaviourTreeDefinitionValidator\";\nimport buildRootNode from \"./BehaviourTreeBuilder\";\n\n// Purely for outside inspection of the tree.\nexport type FlattenedTreeNode = {\n id: string;\n type: string;\n caption: string;\n state: AnyState;\n guards: GuardAttributeDetails[];\n callbacks: CallbackAttributeDetails[];\n args: any[];\n parentId: string | null;\n};\n\n/**\n * A representation of a behaviour tree.\n */\nexport class BehaviourTree {\n /**\n * The main root tree node.\n */\n public readonly rootNode: Root;\n\n /**\n * Creates a new instance of the BehaviourTree class.\n * @param definition The behaviour tree definition.\n * @param agent The agent instance that this behaviour tree is modelling behaviour for.\n * @param options The behaviour tree options object.\n */\n constructor(\n definition: string | RootNodeDefinition | RootNodeDefinition[],\n private agent: Agent,\n private options: BehaviourTreeOptions = {}\n ) {\n // The tree definition must be defined.\n if (!definition) {\n throw new Error(\"the tree definition must be a string ro\");\n }\n\n // The agent must be defined and not null.\n if (typeof agent !== \"object\" || agent === null) {\n throw new Error(\"the agent must be defined and not null\");\n }\n\n try {\n // Parse the behaviour tree definition, create the populated tree of behaviour tree nodes, and get the root.\n this.rootNode = this._createRootNode(definition);\n } catch (exception) {\n // There was an issue in trying build and populate the behaviour tree.\n throw new Error(`error building tree: ${(exception as Error).message}`);\n }\n }\n\n /**\n * Gets whether the tree is in the RUNNING state.\n * @returns true if the tree is in the RUNNING state, otherwise false.\n */\n isRunning() {\n return this.rootNode.getState() === State.RUNNING;\n }\n\n /**\n * Gets the current tree state of SUCCEEDED, FAILED, READY or RUNNING.\n * @returns The current tree state.\n */\n getState() {\n return this.rootNode.getState();\n }\n\n /**\n * Step the tree.\n * 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.\n * 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\n * 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.\n *\n * 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.\n */\n step() {\n // If the root node has already been stepped to completion then we need to reset it.\n if (this.rootNode.getState() === State.SUCCEEDED || this.rootNode.getState() === State.FAILED) {\n this.rootNode.reset();\n }\n\n try {\n this.rootNode.update(this.agent, this.options);\n } catch (exception) {\n throw new Error(`error stepping tree: ${(exception as Error).message}`);\n }\n }\n\n /**\n * Resets the tree from the root node outwards to each nested node, giving each a state of READY.\n */\n reset() {\n this.rootNode.reset();\n }\n\n /**\n * Gets the flattened details of every node in the tree.\n * @returns The flattened details of every node in the tree.\n */\n getFlattenedNodeDetails(): FlattenedTreeNode[] {\n // Create an empty flattened array of tree nodes.\n const flattenedTreeNodes: FlattenedTreeNode[] = [];\n\n /**\n * Helper function to process a node instance and push details into the flattened tree nodes array.\n * @param node The current node.\n * @param parentUid The UID of the node parent, or null if the node is the main root node.\n */\n const processNode = (node: Node, parentUid: string | null) => {\n // Get the guard and callback attribute details for this node.\n const guards = node\n .getAttributes()\n .filter((attribute) => attribute.isGuard())\n .map((attribute) => attribute.getDetails()) as GuardAttributeDetails[];\n const callbacks = node\n .getAttributes()\n .filter((attribute) => !attribute.isGuard())\n .map((attribute) => attribute.getDetails()) as CallbackAttributeDetails[];\n\n // Push the current node into the flattened nodes array.\n flattenedTreeNodes.push({\n id: node.getUid(),\n type: node.getType(),\n caption: node.getName(),\n state: node.getState(),\n guards,\n callbacks,\n args: node.getArguments(),\n parentId: parentUid\n });\n\n // Process each of the nodes children if it is not a leaf node.\n if (!node.isLeafNode()) {\n (node as Composite | Decorator)\n .getChildren()\n .forEach((child) => processNode(child, (node as Composite | Decorator).getUid()));\n }\n };\n\n // Convert the nested node structure into a flattened array of node details.\n processNode(this.rootNode, null);\n\n return flattenedTreeNodes;\n }\n\n /**\n * Registers the action/condition/guard/callback function or subtree with the given name.\n * @param name The name of the function or subtree to register.\n * @param value The function or subtree definition to register.\n */\n static register(name: string, value: GlobalFunction | string | RootNodeDefinition) {\n // Are we going to register a action/condition/guard/callback function?\n if (typeof value === \"function\") {\n Lookup.setFunc(name, value);\n return;\n }\n\n // We are not registering an action/condition/guard/callback function, so we must be registering a subtree.\n if (typeof value === \"string\") {\n let rootNodeDefinitions: RootNodeDefinition[];\n\n // We will assume that any string passed in will be a mdsl definition.\n try {\n rootNodeDefinitions = convertMDSLToJSON(value);\n } catch (exception) {\n throw new Error(`error registering definition, invalid MDSL: ${(exception as Error).message}`);\n }\n\n // This function should only ever be called with a definition containing a single unnamed root node.\n if (rootNodeDefinitions.length != 1 || rootNodeDefinitions[0].id !== null) {\n throw new Error(\"error registering definition: expected a single unnamed root node\");\n }\n\n try {\n // We should validate the subtree as we don't want invalid subtrees available via the lookup.\n const { succeeded, errorMessage } = validateJSONDefinition(rootNodeDefinitions[0]);\n\n // Did our validation fail without error?\n if (!succeeded) {\n throw new Error(errorMessage);\n }\n } catch (exception) {\n throw new Error(`error registering definition: ${(exception as Error).message}`);\n }\n\n // Everything seems hunky-dory, register the subtree.\n Lookup.setSubtree(name, rootNodeDefinitions[0]);\n } else if (typeof value === \"object\" && !Array.isArray(value)) {\n // We will assume that any object passed in is a root node definition.\n\n try {\n // We should validate the subtree as we don't want invalid subtrees available via the lookup.\n const { succeeded, errorMessage } = validateJSONDefinition(value);\n\n // Did our validation fail without error?\n if (!succeeded) {\n throw new Error(errorMessage);\n }\n } catch (exception) {\n throw new Error(`error registering definition: ${(exception as Error).message}`);\n }\n\n // Everything seems hunky-dory, register the subtree.\n Lookup.setSubtree(name, value);\n } else {\n throw new Error(\"unexpected value, expected string mdsl definition, root node json definition or function\");\n }\n }\n\n /**\n * Unregisters the registered action/condition/guard/callback function or subtree with the given name.\n * @param name The name of the registered action/condition/guard/callback function or subtree to unregister.\n */\n static unregister(name: string): void {\n Lookup.remove(name);\n }\n\n /**\n * Unregister all registered action/condition/guard/callback functions and subtrees.\n */\n static unregisterAll(): void {\n Lookup.empty();\n }\n\n /**\n * Parses a behaviour tree definition and creates a tree of behaviour tree nodes populated at a root.\n * @param {string | RootNodeDefinition | RootNodeDefinition[]} definition The behaviour tree definition.\n * @returns The root behaviour tree node.\n */\n private _createRootNode(definition: string | RootNodeDefinition | RootNodeDefinition[]): Root {\n let resolvedDefinition: RootNodeDefinition | RootNodeDefinition[];\n\n // If the definition is a string then we will assume that it is an mdsl string which needs to be converted to a JSON definition.\n if (typeof definition === \"string\") {\n try {\n resolvedDefinition = convertMDSLToJSON(definition);\n } catch (exception) {\n throw new Error(`invalid mdsl definition: ${(exception as Error).message}`);\n }\n } else {\n // The definition is not a string, so we should assume that it is already a JSON definition.\n resolvedDefinition = definition;\n }\n\n // Build and populate the root node.\n return buildRootNode(Array.isArray(resolvedDefinition) ? resolvedDefinition : [resolvedDefinition]);\n }\n}\n"], + "mappings": "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", + "names": ["Participant", "isNullOrUndefined", "Lotto", "createLotto", "State", "createLotto"] } diff --git a/dist/index.js b/dist/index.js index 6be62c4..11ca653 100644 --- a/dist/index.js +++ b/dist/index.js @@ -1,9 +1,14 @@ "use strict"; +var __create = Object.create; var __defProp = Object.defineProperty; var __getOwnPropDesc = Object.getOwnPropertyDescriptor; var __getOwnPropNames = Object.getOwnPropertyNames; +var __getProtoOf = Object.getPrototypeOf; var __hasOwnProp = Object.prototype.hasOwnProperty; var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value; +var __commonJS = (cb, mod) => function __require() { + return mod || (0, cb[__getOwnPropNames(cb)[0]])((mod = { exports: {} }).exports, mod), mod.exports; +}; var __export = (target, all) => { for (var name in all) __defProp(target, name, { get: all[name], enumerable: true }); @@ -16,12 +21,232 @@ var __copyProps = (to, from, except, desc) => { } return to; }; +var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps( + isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target, + mod +)); var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod); var __publicField = (obj, key, value) => { __defNormalProp(obj, typeof key !== "symbol" ? key + "" : key, value); return value; }; +// node_modules/lotto-draw/dist/Participant.js +var require_Participant = __commonJS({ + "node_modules/lotto-draw/dist/Participant.js"(exports) { + "use strict"; + Object.defineProperty(exports, "__esModule", { value: true }); + exports.Participant = void 0; + var Participant = function() { + function Participant2(participant, tickets) { + if (tickets === void 0) { + tickets = 1; + } + this._participant = participant; + this._tickets = tickets; + } + Object.defineProperty(Participant2.prototype, "participant", { + get: function() { + return this._participant; + }, + enumerable: false, + configurable: true + }); + Object.defineProperty(Participant2.prototype, "tickets", { + get: function() { + return this._tickets; + }, + set: function(value) { + this._tickets = value; + }, + enumerable: false, + configurable: true + }); + return Participant2; + }(); + exports.Participant = Participant; + } +}); + +// node_modules/lotto-draw/dist/Utilities.js +var require_Utilities = __commonJS({ + "node_modules/lotto-draw/dist/Utilities.js"(exports) { + "use strict"; + Object.defineProperty(exports, "__esModule", { value: true }); + exports.isNaturalNumber = exports.isNullOrUndefined = void 0; + function isNullOrUndefined2(value) { + return value === null || value === void 0; + } + exports.isNullOrUndefined = isNullOrUndefined2; + function isNaturalNumber(value) { + return typeof value === "number" && value >= 1 && Math.floor(value) === value; + } + exports.isNaturalNumber = isNaturalNumber; + } +}); + +// node_modules/lotto-draw/dist/Lotto.js +var require_Lotto = __commonJS({ + "node_modules/lotto-draw/dist/Lotto.js"(exports) { + "use strict"; + Object.defineProperty(exports, "__esModule", { value: true }); + exports.Lotto = void 0; + var Participant_1 = require_Participant(); + var Utilities_1 = require_Utilities(); + var Lotto2 = function() { + function Lotto3(customRandom) { + this._participants = []; + this._customRandom = customRandom; + } + Lotto3.prototype.add = function(participant, tickets) { + if (tickets === void 0) { + tickets = 1; + } + if (!(0, Utilities_1.isNaturalNumber)(tickets)) { + throw new Error("tickets value must be a natural number"); + } + var existingParticipant = this._participants.find(function(part) { + return part.participant === participant; + }); + if (existingParticipant) { + existingParticipant.tickets += tickets; + } else { + this._participants.push(new Participant_1.Participant(participant, tickets)); + } + return this; + }; + Lotto3.prototype.remove = function(participant, tickets) { + var existingParticipant = this._participants.find(function(part) { + return part.participant === participant; + }); + if (!existingParticipant) { + return this; + } + if (tickets !== void 0) { + if (!(0, Utilities_1.isNaturalNumber)(tickets)) { + throw new Error("tickets value must be a natural number"); + } + existingParticipant.tickets -= tickets; + if (existingParticipant.tickets < 1) { + this._participants = this._participants.filter(function(part) { + return part !== existingParticipant; + }); + } + } else { + this._participants = this._participants.filter(function(part) { + return part !== existingParticipant; + }); + } + return this; + }; + Lotto3.prototype.draw = function(options) { + if (options === void 0) { + options = {}; + } + if (this._participants.length === 0) { + return null; + } + var redrawable = (0, Utilities_1.isNullOrUndefined)(options.redrawable) ? true : options.redrawable; + var pickable = []; + this._participants.forEach(function(_a) { + var participant = _a.participant, tickets = _a.tickets; + for (var ticketCount = 0; ticketCount < tickets; ticketCount++) { + pickable.push(participant); + } + }); + var random; + if (this._customRandom) { + random = this._customRandom(); + if (typeof random !== "number" || random < 0 || random >= 1) { + throw new Error("the 'random' function provided did not return a number between 0 (inclusive) and 1"); + } + } else { + random = Math.random(); + } + var winner = pickable[Math.floor(random * pickable.length)]; + if (!redrawable) { + this.remove(winner, 1); + } + return winner; + }; + Lotto3.prototype.drawMultiple = function(tickets, options) { + if (options === void 0) { + options = {}; + } + var uniqueResults = (0, Utilities_1.isNullOrUndefined)(options.unique) ? false : options.unique; + if (tickets === 0) { + return []; + } + if (!(0, Utilities_1.isNaturalNumber)(tickets)) { + throw new Error("tickets value must be a natural number"); + } + var result = []; + while (result.length < tickets && this._participants.length > 0) { + result.push(this.draw(options)); + } + if (uniqueResults) { + var unique = []; + for (var _i = 0, result_1 = result; _i < result_1.length; _i++) { + var participant = result_1[_i]; + if (unique.indexOf(participant) === -1) { + unique.push(participant); + } + } + result = unique; + } + return result; + }; + return Lotto3; + }(); + exports.Lotto = Lotto2; + } +}); + +// node_modules/lotto-draw/dist/createLotto.js +var require_createLotto = __commonJS({ + "node_modules/lotto-draw/dist/createLotto.js"(exports) { + "use strict"; + Object.defineProperty(exports, "__esModule", { value: true }); + exports.createLotto = void 0; + var Lotto_1 = require_Lotto(); + function createLotto2(participantsOrOptions) { + if (!participantsOrOptions) { + return new Lotto_1.Lotto(); + } + if (Array.isArray(participantsOrOptions)) { + var participants = participantsOrOptions; + var lotto_1 = new Lotto_1.Lotto(); + participants.forEach(function(_a) { + var participant = _a[0], tokens = _a[1]; + return lotto_1.add(participant, tokens); + }); + return lotto_1; + } else { + var random = participantsOrOptions.random, participants = participantsOrOptions.participants; + var lotto_2 = new Lotto_1.Lotto(random); + if (participants) { + participants.forEach(function(_a) { + var participant = _a[0], tokens = _a[1]; + return lotto_2.add(participant, tokens); + }); + } + return lotto_2; + } + } + exports.createLotto = createLotto2; + } +}); + +// node_modules/lotto-draw/dist/index.js +var require_dist = __commonJS({ + "node_modules/lotto-draw/dist/index.js"(exports) { + "use strict"; + Object.defineProperty(exports, "__esModule", { value: true }); + var createLotto_1 = require_createLotto(); + exports.default = createLotto_1.createLotto; + } +}); + // src/index.ts var src_exports = {}; __export(src_exports, { @@ -73,6 +298,9 @@ function flattenDefinition(nodeDefinition) { function isInteger(value) { return typeof value === "number" && Math.floor(value) === value; } +function isNullOrUndefined(value) { + return typeof value === "undefined" || value === null; +} // src/mdsl/MDSLUtilities.ts function popAndCheck(tokens, expected) { @@ -219,6 +447,9 @@ function convertTokensToJSONDefinition(tokens, stringLiteralPlaceholders) { const rootNodes = []; const pushNode = (node) => { if (isRootNode(node)) { + if (treeStacks[treeStacks.length - 1]?.length) { + throw new Error("a root node cannot be the child of another node"); + } rootNodes.push(node); treeStacks.push([node]); return; @@ -242,13 +473,15 @@ function convertTokensToJSONDefinition(tokens, stringLiteralPlaceholders) { } }; const popNode = () => { + let poppedNode = null; const topTreeStack = treeStacks[treeStacks.length - 1]; if (topTreeStack.length) { - topTreeStack.pop(); + poppedNode = topTreeStack.pop(); } if (!topTreeStack.length) { treeStacks.pop(); } + return poppedNode; }; while (tokens.length) { const token = tokens.shift(); @@ -310,7 +543,10 @@ function convertTokensToJSONDefinition(tokens, stringLiteralPlaceholders) { break; } case "}": { - popNode(); + const poppedNode = popNode(); + if (poppedNode) { + validatePoppedNode(poppedNode); + } break; } default: { @@ -370,8 +606,19 @@ function createRepeatNode(tokens, stringLiteralPlaceholders) { }); if (nodeArguments.length === 1) { node.iterations = nodeArguments[0].value; + if (node.iterations < 0) { + throw new Error("a repeat node must have a positive number of iterations if defined"); + } } else if (nodeArguments.length === 2) { node.iterations = [nodeArguments[0].value, nodeArguments[1].value]; + if (node.iterations[0] < 0 || node.iterations[1] < 0) { + throw new Error("a repeat node must have a positive minimum and maximum iteration count if defined"); + } + if (node.iterations[0] > node.iterations[1]) { + throw new Error( + "a repeat node must not have a minimum iteration count that exceeds the maximum iteration count" + ); + } } else { throw new Error("invalid number of repeat node iteration count arguments defined"); } @@ -389,8 +636,19 @@ function createRetryNode(tokens, stringLiteralPlaceholders) { }); if (nodeArguments.length === 1) { node.attempts = nodeArguments[0].value; + if (node.attempts < 0) { + throw new Error("a retry node must have a positive number of attempts if defined"); + } } else if (nodeArguments.length === 2) { node.attempts = [nodeArguments[0].value, nodeArguments[1].value]; + if (node.attempts[0] < 0 || node.attempts[1] < 0) { + throw new Error("a retry node must have a positive minimum and maximum attempt count if defined"); + } + if (node.attempts[0] > node.attempts[1]) { + throw new Error( + "a retry node must not have a minimum attempt count that exceeds the maximum attempt count" + ); + } } else { throw new Error("invalid number of retry node attempt count arguments defined"); } @@ -479,8 +737,17 @@ function createWaitNode(tokens, stringLiteralPlaceholders) { }); if (nodeArguments.length === 1) { node.duration = nodeArguments[0].value; + if (node.duration < 0) { + throw new Error("a wait node must have a positive duration"); + } } else if (nodeArguments.length === 2) { node.duration = [nodeArguments[0].value, nodeArguments[1].value]; + if (node.duration[0] < 0 || node.duration[1] < 0) { + throw new Error("a wait node must have a positive minimum and maximum duration"); + } + if (node.duration[0] > node.duration[1]) { + throw new Error("a wait node must not have a minimum duration that exceeds the maximum duration"); + } } else if (nodeArguments.length > 2) { throw new Error("invalid number of wait node duration arguments defined"); } @@ -494,6 +761,14 @@ function createBranchNode(tokens, stringLiteralPlaceholders) { } return { type: "branch", ref: nodeArguments[0].value }; } +function validatePoppedNode(node) { + if (isDecoratorNode(node) && isNullOrUndefined(node.child)) { + throw new Error(`a ${node.type} node must have a single child node defined`); + } + if (isCompositeNode(node) && !node.children?.length) { + throw new Error(`a ${node.type} node must have at least a single child node defined`); + } +} // src/BehaviourTreeDefinitionValidator.ts function validateDefinition(definition) { @@ -729,7 +1004,23 @@ function validateRepeatNode(definition, depth) { `expected array containing two integer values for 'iterations' property if defined for repeat node at depth '${depth}'` ); } - } else if (!isInteger(definition.iterations)) { + if (definition.iterations[0] < 0 || definition.iterations[1] < 0) { + throw new Error( + `expected positive minimum and maximum iterations count for 'iterations' property if defined for repeat node at depth '${depth}'` + ); + } + if (definition.iterations[0] > definition.iterations[1]) { + throw new Error( + `expected minimum iterations count that does not exceed the maximum iterations count for 'iterations' property if defined for repeat node at depth '${depth}'` + ); + } + } else if (isInteger(definition.iterations)) { + if (definition.iterations < 0) { + throw new Error( + `expected positive iterations count for 'iterations' property if defined for repeat node at depth '${depth}'` + ); + } + } else { throw new Error( `expected integer value or array containing two integer values for 'iterations' property if defined for repeat node at depth '${depth}'` ); @@ -753,7 +1044,23 @@ function validateRetryNode(definition, depth) { `expected array containing two integer values for 'attempts' property if defined for retry node at depth '${depth}'` ); } - } else if (!isInteger(definition.attempts)) { + if (definition.attempts[0] < 0 || definition.attempts[1] < 0) { + throw new Error( + `expected positive minimum and maximum attempts count for 'attempts' property if defined for retry node at depth '${depth}'` + ); + } + if (definition.attempts[0] > definition.attempts[1]) { + throw new Error( + `expected minimum attempts count that does not exceed the maximum attempts count for 'attempts' property if defined for retry node at depth '${depth}'` + ); + } + } else if (isInteger(definition.attempts)) { + if (definition.attempts < 0) { + throw new Error( + `expected positive attempts count for 'attempts' property if defined for retry node at depth '${depth}'` + ); + } + } else { throw new Error( `expected integer value or array containing two integer values for 'attempts' property if defined for retry node at depth '${depth}'` ); @@ -820,7 +1127,23 @@ function validateWaitNode(definition, depth) { `expected array containing two integer values for 'duration' property if defined for wait node at depth '${depth}'` ); } - } else if (!isInteger(definition.duration)) { + if (definition.duration[0] < 0 || definition.duration[1] < 0) { + throw new Error( + `expected positive minimum and maximum duration for 'duration' property if defined for wait node at depth '${depth}'` + ); + } + if (definition.duration[0] > definition.duration[1]) { + throw new Error( + `expected minimum duration value that does not exceed the maximum duration value for 'duration' property if defined for wait node at depth '${depth}'` + ); + } + } else if (isInteger(definition.duration)) { + if (definition.duration < 0) { + throw new Error( + `expected positive duration value for 'duration' property if defined for wait node at depth '${depth}'` + ); + } + } else { throw new Error( `expected integer value or array containing two integer values for 'duration' property if defined for wait node at depth '${depth}'` ); @@ -991,6 +1314,159 @@ function createNodeUid() { return S4() + S4() + "-" + S4() + "-" + S4() + "-" + S4() + "-" + S4() + S4() + S4(); } +// src/nodes/composite/Composite.ts +var Composite = class extends Node { + constructor(type, attributes, children) { + super(type, attributes, []); + this.children = children; + } + isLeafNode = () => false; + getChildren = () => this.children; + reset = () => { + this.setState("mistreevous.ready" /* READY */); + this.getChildren().forEach((child) => child.reset()); + }; + abort = (agent) => { + if (!this.is("mistreevous.running" /* RUNNING */)) { + return; + } + this.getChildren().forEach((child) => child.abort(agent)); + this.reset(); + this.getAttribute("exit")?.callAgentFunction(agent, false, true); + }; +}; + +// src/nodes/composite/Parallel.ts +var Parallel = class extends Composite { + constructor(attributes, children) { + super("parallel", attributes, children); + } + onUpdate(agent, options) { + let succeededCount = 0; + let hasChildFailed = false; + for (const child of this.children) { + if (child.getState() === "mistreevous.ready" /* READY */ || child.getState() === "mistreevous.running" /* RUNNING */) { + child.update(agent, options); + } + if (child.getState() === "mistreevous.succeeded" /* SUCCEEDED */) { + succeededCount++; + continue; + } + if (child.getState() === "mistreevous.failed" /* FAILED */) { + hasChildFailed = true; + break; + } + if (child.getState() !== "mistreevous.running" /* RUNNING */) { + throw new Error("child node was not in an expected state."); + } + } + if (hasChildFailed) { + this.setState("mistreevous.failed" /* FAILED */); + for (const child of this.children) { + if (child.getState() === "mistreevous.running" /* RUNNING */) { + child.abort(agent); + } + } + } else { + this.setState(succeededCount === this.children.length ? "mistreevous.succeeded" /* SUCCEEDED */ : "mistreevous.running" /* RUNNING */); + } + } + getName = () => "PARALLEL"; +}; + +// src/nodes/composite/Selector.ts +var Selector = class extends Composite { + constructor(attributes, children) { + super("selector", attributes, children); + this.children = children; + } + onUpdate(agent, options) { + for (const child of this.children) { + if (child.getState() === "mistreevous.ready" /* READY */ || child.getState() === "mistreevous.running" /* RUNNING */) { + child.update(agent, options); + } + if (child.getState() === "mistreevous.succeeded" /* SUCCEEDED */) { + this.setState("mistreevous.succeeded" /* SUCCEEDED */); + return; + } + if (child.getState() === "mistreevous.failed" /* FAILED */) { + if (this.children.indexOf(child) === this.children.length - 1) { + this.setState("mistreevous.failed" /* FAILED */); + return; + } else { + continue; + } + } + if (child.getState() === "mistreevous.running" /* RUNNING */) { + this.setState("mistreevous.running" /* RUNNING */); + return; + } + throw new Error("child node was not in an expected state."); + } + } + getName = () => "SELECTOR"; +}; + +// src/nodes/composite/Sequence.ts +var Sequence = class extends Composite { + constructor(attributes, children) { + super("sequence", attributes, children); + this.children = children; + } + onUpdate(agent, options) { + for (const child of this.children) { + if (child.getState() === "mistreevous.ready" /* READY */ || child.getState() === "mistreevous.running" /* RUNNING */) { + child.update(agent, options); + } + if (child.getState() === "mistreevous.succeeded" /* SUCCEEDED */) { + if (this.children.indexOf(child) === this.children.length - 1) { + this.setState("mistreevous.succeeded" /* SUCCEEDED */); + return; + } else { + continue; + } + } + if (child.getState() === "mistreevous.failed" /* FAILED */) { + this.setState("mistreevous.failed" /* FAILED */); + return; + } + if (child.getState() === "mistreevous.running" /* RUNNING */) { + this.setState("mistreevous.running" /* RUNNING */); + return; + } + throw new Error("child node was not in an expected state."); + } + } + getName = () => "SEQUENCE"; +}; + +// src/nodes/composite/Lotto.ts +var import_lotto_draw = __toESM(require_dist()); +var Lotto = class extends Composite { + constructor(attributes, weights, children) { + super("lotto", attributes, children); + this.weights = weights; + } + selectedChild; + onUpdate(agent, options) { + if (this.is("mistreevous.ready" /* READY */)) { + const lottoDraw = (0, import_lotto_draw.default)({ + random: options.random, + participants: this.children.map((child, index) => [child, this.weights?.[index] || 1]) + }); + this.selectedChild = lottoDraw.draw() || void 0; + } + if (!this.selectedChild) { + throw new Error("failed to update lotto node as it has no active child"); + } + if (this.selectedChild.getState() === "mistreevous.ready" /* READY */ || this.selectedChild.getState() === "mistreevous.running" /* RUNNING */) { + this.selectedChild.update(agent, options); + } + this.setState(this.selectedChild.getState()); + } + getName = () => this.weights ? `LOTTO [${this.weights.join(",")}]` : "LOTTO"; +}; + // src/nodes/decorator/Decorator.ts var Decorator = class extends Node { constructor(type, attributes, child) { @@ -1013,6 +1489,188 @@ var Decorator = class extends Node { }; }; +// src/nodes/decorator/Fail.ts +var Fail = class extends Decorator { + constructor(attributes, child) { + super("fail", attributes, child); + } + onUpdate(agent, options) { + if (this.child.getState() === "mistreevous.ready" /* READY */ || this.child.getState() === "mistreevous.running" /* RUNNING */) { + this.child.update(agent, options); + } + switch (this.child.getState()) { + case "mistreevous.running" /* RUNNING */: + this.setState("mistreevous.running" /* RUNNING */); + break; + case "mistreevous.succeeded" /* SUCCEEDED */: + case "mistreevous.failed" /* FAILED */: + this.setState("mistreevous.failed" /* FAILED */); + break; + default: + this.setState("mistreevous.ready" /* READY */); + } + } + getName = () => "FAIL"; +}; + +// src/nodes/decorator/Flip.ts +var Flip = class extends Decorator { + constructor(attributes, child) { + super("flip", attributes, child); + } + onUpdate(agent, options) { + if (this.child.getState() === "mistreevous.ready" /* READY */ || this.child.getState() === "mistreevous.running" /* RUNNING */) { + this.child.update(agent, options); + } + switch (this.child.getState()) { + case "mistreevous.running" /* RUNNING */: + this.setState("mistreevous.running" /* RUNNING */); + break; + case "mistreevous.succeeded" /* SUCCEEDED */: + this.setState("mistreevous.failed" /* FAILED */); + break; + case "mistreevous.failed" /* FAILED */: + this.setState("mistreevous.succeeded" /* SUCCEEDED */); + break; + default: + this.setState("mistreevous.ready" /* READY */); + } + } + getName = () => "FLIP"; +}; + +// src/nodes/decorator/Repeat.ts +var Repeat = class extends Decorator { + constructor(attributes, iterations, iterationsMin, iterationsMax, child) { + super("repeat", attributes, child); + this.iterations = iterations; + this.iterationsMin = iterationsMin; + this.iterationsMax = iterationsMax; + } + targetIterationCount = null; + currentIterationCount = 0; + onUpdate(agent, options) { + if (this.is("mistreevous.ready" /* READY */)) { + this.child.reset(); + this.currentIterationCount = 0; + this.setTargetIterationCount(options); + } + if (this.canIterate()) { + this.setState("mistreevous.running" /* RUNNING */); + if (this.child.getState() === "mistreevous.succeeded" /* SUCCEEDED */) { + this.child.reset(); + } + this.child.update(agent, options); + if (this.child.getState() === "mistreevous.failed" /* FAILED */) { + this.setState("mistreevous.failed" /* FAILED */); + return; + } else if (this.child.getState() === "mistreevous.succeeded" /* SUCCEEDED */) { + this.currentIterationCount += 1; + } + } else { + this.setState("mistreevous.succeeded" /* SUCCEEDED */); + } + } + getName = () => { + if (this.iterations !== null) { + return `REPEAT ${this.iterations}x`; + } else if (this.iterationsMin !== null && this.iterationsMax !== null) { + return `REPEAT ${this.iterationsMin}x-${this.iterationsMax}x`; + } else { + return "REPEAT"; + } + }; + reset = () => { + this.setState("mistreevous.ready" /* READY */); + this.currentIterationCount = 0; + this.child.reset(); + }; + canIterate = () => { + if (this.targetIterationCount !== null) { + return this.currentIterationCount < this.targetIterationCount; + } + return true; + }; + setTargetIterationCount = (options) => { + if (this.iterations !== null) { + this.targetIterationCount = this.iterations; + } else if (this.iterationsMin !== null && this.iterationsMax !== null) { + const random = typeof options.random === "function" ? options.random : Math.random; + this.targetIterationCount = Math.floor( + random() * (this.iterationsMax - this.iterationsMin + 1) + this.iterationsMin + ); + } else { + this.targetIterationCount = null; + } + }; +}; + +// src/nodes/decorator/Retry.ts +var Retry = class extends Decorator { + constructor(attributes, attempts, attemptsMin, attemptsMax, child) { + super("retry", attributes, child); + this.attempts = attempts; + this.attemptsMin = attemptsMin; + this.attemptsMax = attemptsMax; + } + targetAttemptCount = null; + currentAttemptCount = 0; + onUpdate(agent, options) { + if (this.is("mistreevous.ready" /* READY */)) { + this.child.reset(); + this.currentAttemptCount = 0; + this.setTargetAttemptCount(options); + } + if (this.canAttempt()) { + this.setState("mistreevous.running" /* RUNNING */); + if (this.child.getState() === "mistreevous.failed" /* FAILED */) { + this.child.reset(); + } + this.child.update(agent, options); + if (this.child.getState() === "mistreevous.succeeded" /* SUCCEEDED */) { + this.setState("mistreevous.succeeded" /* SUCCEEDED */); + return; + } else if (this.child.getState() === "mistreevous.failed" /* FAILED */) { + this.currentAttemptCount += 1; + } + } else { + this.setState("mistreevous.failed" /* FAILED */); + } + } + getName = () => { + if (this.attempts !== null) { + return `RETRY ${this.attempts}x`; + } else if (this.attemptsMin !== null && this.attemptsMax !== null) { + return `RETRY ${this.attemptsMin}x-${this.attemptsMax}x`; + } else { + return "RETRY"; + } + }; + reset = () => { + this.setState("mistreevous.ready" /* READY */); + this.currentAttemptCount = 0; + this.child.reset(); + }; + canAttempt = () => { + if (this.targetAttemptCount !== null) { + return this.currentAttemptCount < this.targetAttemptCount; + } + return true; + }; + setTargetAttemptCount = (options) => { + if (this.attempts !== null) { + this.targetAttemptCount = this.attempts; + } else if (this.attemptsMin !== null && this.attemptsMax !== null) { + const random = typeof options.random === "function" ? options.random : Math.random; + this.targetAttemptCount = Math.floor( + random() * (this.attemptsMax - this.attemptsMin + 1) + this.attemptsMin + ); + } else { + this.targetAttemptCount = null; + } + }; +}; + // src/nodes/decorator/Root.ts var Root = class extends Decorator { constructor(attributes, child) { @@ -1027,6 +1685,178 @@ var Root = class extends Decorator { getName = () => "ROOT"; }; +// src/nodes/decorator/Succeed.ts +var Succeed = class extends Decorator { + constructor(attributes, child) { + super("succeed", attributes, child); + } + onUpdate(agent, options) { + if (this.child.getState() === "mistreevous.ready" /* READY */ || this.child.getState() === "mistreevous.running" /* RUNNING */) { + this.child.update(agent, options); + } + switch (this.child.getState()) { + case "mistreevous.running" /* RUNNING */: + this.setState("mistreevous.running" /* RUNNING */); + break; + case "mistreevous.succeeded" /* SUCCEEDED */: + case "mistreevous.failed" /* FAILED */: + this.setState("mistreevous.succeeded" /* SUCCEEDED */); + break; + default: + this.setState("mistreevous.ready" /* READY */); + } + } + getName = () => "SUCCEED"; +}; + +// src/nodes/leaf/Leaf.ts +var Leaf = class extends Node { + isLeafNode = () => true; +}; + +// src/nodes/leaf/Action.ts +var Action = class extends Leaf { + constructor(attributes, actionName, actionArguments) { + super("action", attributes, actionArguments); + this.actionName = actionName; + this.actionArguments = actionArguments; + } + isUsingUpdatePromise = false; + updatePromiseStateResult = null; + onUpdate(agent, options) { + if (this.isUsingUpdatePromise) { + if (this.updatePromiseStateResult) { + this.setState(this.updatePromiseStateResult); + } + return; + } + const actionFuncInvoker = Lookup.getFuncInvoker(agent, this.actionName); + if (actionFuncInvoker === null) { + throw new Error( + `cannot update action node as the action '${this.actionName}' function is not defined on the agent and has not been registered` + ); + } + const updateResult = actionFuncInvoker(this.actionArguments); + if (updateResult instanceof Promise) { + updateResult.then( + (result) => { + if (!this.isUsingUpdatePromise) { + return; + } + if (result !== "mistreevous.succeeded" /* SUCCEEDED */ && result !== "mistreevous.failed" /* FAILED */) { + throw new Error( + "action node promise resolved with an invalid value, expected a State.SUCCEEDED or State.FAILED value to be returned" + ); + } + this.updatePromiseStateResult = result; + }, + (reason) => { + if (!this.isUsingUpdatePromise) { + return; + } + throw new Error(reason); + } + ); + this.setState("mistreevous.running" /* RUNNING */); + this.isUsingUpdatePromise = true; + } else { + this.validateUpdateResult(updateResult); + this.setState(updateResult || "mistreevous.running" /* RUNNING */); + } + } + getName = () => this.actionName; + reset = () => { + this.setState("mistreevous.ready" /* READY */); + this.isUsingUpdatePromise = false; + this.updatePromiseStateResult = null; + }; + validateUpdateResult = (result) => { + switch (result) { + case "mistreevous.succeeded" /* SUCCEEDED */: + case "mistreevous.failed" /* FAILED */: + case void 0: + return; + default: + throw new Error( + `action '${this.actionName}' 'onUpdate' returned an invalid response, expected an optional State.SUCCEEDED or State.FAILED value to be returned` + ); + } + }; +}; + +// src/nodes/leaf/Condition.ts +var Condition = class extends Leaf { + constructor(attributes, conditionName, conditionArguments) { + super("condition", attributes, conditionArguments); + this.conditionName = conditionName; + this.conditionArguments = conditionArguments; + } + onUpdate(agent, options) { + const conditionFuncInvoker = Lookup.getFuncInvoker(agent, this.conditionName); + if (conditionFuncInvoker === null) { + throw new Error( + `cannot update condition node as the condition '${this.conditionName}' function is not defined on the agent and has not been registered` + ); + } + this.setState(!!conditionFuncInvoker(this.conditionArguments) ? "mistreevous.succeeded" /* SUCCEEDED */ : "mistreevous.failed" /* FAILED */); + } + getName = () => this.conditionName; +}; + +// src/nodes/leaf/Wait.ts +var Wait = class extends Leaf { + constructor(attributes, duration, durationMin, durationMax) { + super("wait", attributes, []); + this.duration = duration; + this.durationMin = durationMin; + this.durationMax = durationMax; + } + initialUpdateTime = 0; + totalDuration = null; + waitedDuration = 0; + onUpdate(agent, options) { + if (this.is("mistreevous.ready" /* READY */)) { + this.initialUpdateTime = new Date().getTime(); + this.waitedDuration = 0; + if (this.duration !== null) { + this.totalDuration = this.duration; + } else if (this.durationMin !== null && this.durationMax !== null) { + const random = typeof options.random === "function" ? options.random : Math.random; + this.totalDuration = Math.floor( + random() * (this.durationMax - this.durationMin + 1) + this.durationMin + ); + } else { + this.totalDuration = null; + } + this.setState("mistreevous.running" /* RUNNING */); + } + if (this.totalDuration === null) { + return; + } + if (typeof options.getDeltaTime === "function") { + const deltaTime = options.getDeltaTime(); + if (typeof deltaTime !== "number" || isNaN(deltaTime)) { + throw new Error("The delta time must be a valid number and not NaN."); + } + this.waitedDuration += deltaTime * 1e3; + } else { + this.waitedDuration = new Date().getTime() - this.initialUpdateTime; + } + if (this.waitedDuration >= this.totalDuration) { + this.setState("mistreevous.succeeded" /* SUCCEEDED */); + } + } + getName = () => { + if (this.duration !== null) { + return `WAIT ${this.duration}ms`; + } else if (this.durationMin !== null && this.durationMax !== null) { + return `WAIT ${this.durationMin}ms-${this.durationMax}ms`; + } else { + return "WAIT"; + } + }; +}; + // src/attributes/Attribute.ts var Attribute = class { constructor(type, args) { @@ -1154,17 +1984,93 @@ var MAIN_ROOT_NODE_KEY = Symbol("__root__"); function buildRootNode(definition) { const rootNodeDefinitionMap = createRootNodeDefinitionMap(definition); validateBranchSubtreeLinks(definition, true); - const rootNode = nodeFactory(rootNodeDefinitionMap[MAIN_ROOT_NODE_KEY]); + const rootNode = nodeFactory(rootNodeDefinitionMap[MAIN_ROOT_NODE_KEY], rootNodeDefinitionMap); applyLeafNodeGuardPaths(rootNode); return rootNode; } -function nodeFactory(definition) { +function nodeFactory(definition, rootNodeDefinitionMap) { const attributes = nodeAttributesFactory(definition); switch (definition.type) { case "root": - return new Root(attributes, nodeFactory(definition.child)); - default: - throw new Error(`unexpected node type of '${definition.type}'`); + return new Root(attributes, nodeFactory(definition.child, rootNodeDefinitionMap)); + case "repeat": + let iterations = null; + let iterationsMin = null; + let iterationsMax = null; + if (Array.isArray(definition.iterations)) { + iterationsMin = definition.iterations[0]; + iterationsMax = definition.iterations[1]; + } else if (isInteger(definition.iterations)) { + iterations = definition.iterations; + } + return new Repeat( + attributes, + iterations, + iterationsMin, + iterationsMax, + nodeFactory(definition.child, rootNodeDefinitionMap) + ); + case "retry": + let attempts = null; + let attemptsMin = null; + let attemptsMax = null; + if (Array.isArray(definition.attempts)) { + attemptsMin = definition.attempts[0]; + attemptsMax = definition.attempts[1]; + } else if (isInteger(definition.attempts)) { + attempts = definition.attempts; + } + return new Retry( + attributes, + attempts, + attemptsMin, + attemptsMax, + nodeFactory(definition.child, rootNodeDefinitionMap) + ); + case "flip": + return new Flip(attributes, nodeFactory(definition.child, rootNodeDefinitionMap)); + case "succeed": + return new Succeed(attributes, nodeFactory(definition.child, rootNodeDefinitionMap)); + case "fail": + return new Fail(attributes, nodeFactory(definition.child, rootNodeDefinitionMap)); + case "sequence": + return new Sequence( + attributes, + definition.children.map((child) => nodeFactory(child, rootNodeDefinitionMap)) + ); + case "selector": + return new Selector( + attributes, + definition.children.map((child) => nodeFactory(child, rootNodeDefinitionMap)) + ); + case "parallel": + return new Parallel( + attributes, + definition.children.map((child) => nodeFactory(child, rootNodeDefinitionMap)) + ); + case "lotto": + return new Lotto( + attributes, + definition.weights, + definition.children.map((child) => nodeFactory(child, rootNodeDefinitionMap)) + ); + case "branch": + return nodeFactory(rootNodeDefinitionMap[definition.ref].child, rootNodeDefinitionMap); + case "action": + return new Action(attributes, definition.call, definition.args || []); + case "condition": + return new Condition(attributes, definition.call, definition.args || []); + case "wait": + let duration = null; + let durationMin = null; + let durationMax = null; + if (Array.isArray(definition.duration)) { + durationMin = definition.duration[0]; + durationMax = definition.duration[1]; + } else if (isInteger(definition.duration)) { + duration = definition.duration; + } + return new Wait(attributes, duration, durationMin, durationMax); } } function nodeAttributesFactory(definition) { diff --git a/dist/index.js.map b/dist/index.js.map index 3dd1e21..be14773 100644 --- a/dist/index.js.map +++ b/dist/index.js.map @@ -1,7 +1,7 @@ { "version": 3, - "sources": ["../src/index.ts", "../src/State.ts", "../src/BehaviourTreeDefinitionUtilities.ts", "../src/mdsl/MDSLUtilities.ts", "../src/mdsl/MDSLNodeArgumentParser.ts", "../src/mdsl/MDSLNodeAttributeParser.ts", "../src/mdsl/MDSLDefinitionParser.ts", "../src/BehaviourTreeDefinitionValidator.ts", "../src/Lookup.ts", "../src/attributes/guards/GuardUnsatisifedException.ts", "../src/attributes/guards/GuardPath.ts", "../src/nodes/Node.ts", "../src/nodes/decorator/Decorator.ts", "../src/nodes/decorator/Root.ts", "../src/attributes/Attribute.ts", "../src/attributes/guards/Guard.ts", "../src/attributes/guards/While.ts", "../src/attributes/guards/Until.ts", "../src/attributes/callbacks/Callback.ts", "../src/attributes/callbacks/Entry.ts", "../src/attributes/callbacks/Step.ts", "../src/attributes/callbacks/Exit.ts", "../src/BehaviourTreeBuilder.ts", "../src/BehaviourTree.ts"], - "sourcesContent": ["import State from \"./State\";\nimport { validateDefinition } from \"./BehaviourTreeDefinitionValidator\";\nimport { convertMDSLToJSON } from \"./mdsl/MDSLDefinitionParser\";\nimport { BehaviourTree, FlattenedTreeNode } from \"./BehaviourTree\";\n\nexport { BehaviourTree, State, convertMDSLToJSON, validateDefinition };\nexport type { FlattenedTreeNode };\n", "/**\n * Enumeration of node state types.\n */\nexport enum State {\n READY = \"mistreevous.ready\",\n RUNNING = \"mistreevous.running\",\n SUCCEEDED = \"mistreevous.succeeded\",\n FAILED = \"mistreevous.failed\"\n}\n\nexport { State as default };\n\nexport type CompleteState = State.SUCCEEDED | State.FAILED;\nexport type AnyState = State.READY | State.RUNNING | CompleteState;\n", "import {\n NodeDefinition,\n RootNodeDefinition,\n DecoratorNodeDefinition,\n CompositeNodeDefinition,\n AnyNodeDefinition,\n BranchNodeDefinition\n} from \"./BehaviourTreeDefinition\";\n\n/**\n * A type guard function that returns true if the specified node satisfies the RootNodeDefinition type.\n * @param node The node.\n * @returns A value of true if the specified node satisfies the RootNodeDefinition type.\n */\nexport function isRootNode(node: NodeDefinition): node is RootNodeDefinition {\n return node.type === \"root\";\n}\n\n/**\n * A type guard function that returns true if the specified node satisfies the BranchNodeDefinition type.\n * @param node The node.\n * @returns A value of true if the specified node satisfies the BranchNodeDefinition type.\n */\nexport function isBranchNode(node: NodeDefinition): node is BranchNodeDefinition {\n return node.type === \"branch\";\n}\n\n/**\n * A type guard function that returns true if the specified node satisfies the NodeDefinition type.\n * @param node The node.\n * @returns A value of true if the specified node satisfies the NodeDefinition type.\n */\nexport function isLeafNode(node: NodeDefinition): node is NodeDefinition {\n return [\"branch\", \"action\", \"condition\", \"wait\"].includes(node.type);\n}\n\n/**\n * A type guard function that returns true if the specified node satisfies the DecoratorNodeDefinition type.\n * @param node The node.\n * @returns A value of true if the specified node satisfies the DecoratorNodeDefinition type.\n */\nexport function isDecoratorNode(node: NodeDefinition): node is DecoratorNodeDefinition {\n return [\"root\", \"repeat\", \"retry\", \"flip\", \"succeed\", \"fail\"].includes(node.type);\n}\n\n/**\n * A type guard function that returns true if the specified node satisfies the CompositeNodeDefinition type.\n * @param node The node.\n * @returns A value of true if the specified node satisfies the CompositeNodeDefinition type.\n */\nexport function isCompositeNode(node: NodeDefinition): node is CompositeNodeDefinition {\n return [\"sequence\", \"selector\", \"lotto\", \"parallel\"].includes(node.type);\n}\n\n/**\n * Flatten a node definition into an array of all of its nested node definitions.\n * @param nodeDefinition The node definition to flatten.\n * @returns An array of all of nested node definitions.\n */\nexport function flattenDefinition(nodeDefinition: AnyNodeDefinition): AnyNodeDefinition[] {\n const nodes: AnyNodeDefinition[] = [];\n\n const processNode = (currentNodeDefinition: AnyNodeDefinition) => {\n nodes.push(currentNodeDefinition);\n\n if (isCompositeNode(currentNodeDefinition)) {\n currentNodeDefinition.children.forEach(processNode);\n } else if (isDecoratorNode(currentNodeDefinition)) {\n processNode(currentNodeDefinition.child);\n }\n };\n\n processNode(nodeDefinition);\n\n return nodes;\n}\n\n/**\n * Determines whether the passed value is an integer.\n * @param value The value to check.\n * @returns Whether the passed value is an integer.\n */\nexport function isInteger(value: unknown): boolean {\n return typeof value === \"number\" && Math.floor(value) === value;\n}\n", "/**\n * A type defining an object that holds a reference to substitued string literals parsed from the definition.\n */\nexport type StringLiteralPlaceholders = { [key: string]: string };\n\n/**\n * Pop the next raw token from the specified array of tokens and throw an error if it wasn't the expected one.\n * @param tokens The array of tokens.\n * @param expected An optional string or array or items, one of which must match the next popped token.\n * @returns The popped token.\n */\nexport function popAndCheck(tokens: string[], expected?: string | string[]): string {\n // Get and remove the next token.\n const popped = tokens.shift();\n\n // We were expecting another token but there aren't any.\n if (popped === undefined) {\n throw new Error(\"unexpected end of definition\");\n }\n\n // Do we have an expected token/tokens array?\n if (expected != undefined) {\n // Get an array of expected values, if the popped token matches any then we are all good.\n const expectedValues = typeof expected === \"string\" ? [expected] : expected;\n\n // Check whether the popped token matches at least one of our expected items.\n var tokenMatchesExpectation = expectedValues.some((item) => popped.toUpperCase() === item.toUpperCase());\n\n // Throw an error if the popped token didn't match any of our expected items.\n if (!tokenMatchesExpectation) {\n const expectationString = expectedValues.map((item) => \"'\" + item + \"'\").join(\" or \");\n throw new Error(\"unexpected token found. Expected \" + expectationString + \" but got '\" + popped + \"'\");\n }\n }\n\n // Return the popped token.\n return popped;\n}\n\n/**\n * Swaps out any node/attribute argument string literals with placeholders.\n * @param definition The definition.\n * @returns An object containing a mapping of placeholders to original string values as well as the processed definition string.\n */\nexport function substituteStringLiterals(definition: string): {\n placeholders: StringLiteralPlaceholders;\n processedDefinition: string;\n} {\n // Create an object to hold the mapping of placeholders to original string values.\n const placeholders: StringLiteralPlaceholders = {};\n\n // Replace any string literals wrapped with double quotes in our definition with placeholders to be processed later.\n const processedDefinition = definition.replace(/\\\"(\\\\.|[^\"\\\\])*\\\"/g, (match) => {\n var strippedMatch = match.substring(1, match.length - 1);\n var placeholder = Object.keys(placeholders).find((key) => placeholders[key] === strippedMatch);\n\n // If we have no existing string literal match then create a new placeholder.\n if (!placeholder) {\n placeholder = `@@${Object.keys(placeholders).length}@@`;\n placeholders[placeholder] = strippedMatch;\n }\n\n return placeholder;\n });\n\n return { placeholders, processedDefinition };\n}\n\n/**\n * Parse the tree definition into an array of raw tokens.\n * @param definition The definition.\n * @returns An array of tokens parsed from the definition.\n */\nexport function parseTokensFromDefinition(definition: string): string[] {\n // Add some space around various important characters so that they can be plucked out easier as individual tokens.\n definition = definition.replace(/\\(/g, \" ( \");\n definition = definition.replace(/\\)/g, \" ) \");\n definition = definition.replace(/\\{/g, \" { \");\n definition = definition.replace(/\\}/g, \" } \");\n definition = definition.replace(/\\]/g, \" ] \");\n definition = definition.replace(/\\[/g, \" [ \");\n definition = definition.replace(/\\,/g, \" , \");\n\n // Split the definition into raw token form and return it.\n return definition.replace(/\\s+/g, \" \").trim().split(\" \");\n}\n", "import { StringLiteralPlaceholders, popAndCheck } from \"./MDSLUtilities\";\n\n/**\n * A type representing any node function argument.\n */\ntype Argument = {\n /**\n * The argument value.\n */\n value: T;\n /**\n * The argument type, used for validation.\n */\n type: string;\n};\n\ntype NullArgument = Argument & {\n type: \"null\";\n};\n\ntype BooleanArgument = Argument & {\n type: \"boolean\";\n};\n\ntype NumberArgument = Argument & {\n type: \"number\";\n /**\n * A flag defining whether the number argument value is a valid integer. (used for validation)\n */\n isInteger: boolean;\n};\n\ntype StringPlaceholderArgument = Argument & {\n type: \"string\";\n};\n\ntype IdentifierArgument = Argument & {\n type: \"identifier\";\n};\n\n/**\n * A type representing a reference to any node function argument.\n */\ntype AnyArgument = NullArgument | BooleanArgument | NumberArgument | StringPlaceholderArgument | IdentifierArgument;\n\n/**\n * Parse an array of argument definitions from the specified tokens array.\n * @param tokens The array tokens to parse the argument definitions from.\n * @param stringArgumentPlaceholders The mapping of string literal node argument placeholders to original values.\n * @param argumentValidator The argument validator function.\n * @param validationFailedMessage The exception message to throw if argument validation fails.\n * @returns An array of argument definitions parsed from the specified tokens array.\n */\nexport function parseArgumentTokens(\n tokens: string[],\n stringArgumentPlaceholders: StringLiteralPlaceholders\n): AnyArgument[] {\n const argumentList: AnyArgument[] = [];\n\n // If the next token is not a '[' or '(' then we have no arguments to parse.\n if (![\"[\", \"(\"].includes(tokens[0])) {\n return argumentList;\n }\n\n // Any lists of arguments will always be wrapped in '[]' for node arguments or '()' for attribute arguments.\n // We are looking for a '[' or '(' opener that wraps the argument tokens and the relevant closer.\n const closingToken = popAndCheck(tokens, [\"[\", \"(\"]) === \"[\" ? \"]\" : \")\";\n\n const argumentListTokens: string[] = [];\n\n // Grab all tokens between the '[' and ']' or '(' and ')'.\n while (tokens.length && tokens[0] !== closingToken) {\n // The next token is part of our arguments list.\n argumentListTokens.push(tokens.shift()!);\n }\n\n // Validate the order of the argument tokens. Each token must either be a ',' or a single argument that satisfies the validator.\n argumentListTokens.forEach((token, index) => {\n // Get whether this token should be an actual argument.\n const shouldBeArgumentToken = !(index & 1);\n\n // If the current token should be an actual argument then validate it, otherwise it should be a ',' token.\n if (shouldBeArgumentToken) {\n // Get the argument definition.\n const argumentDefinition = getArgumentDefinition(token, stringArgumentPlaceholders);\n\n // This is a valid argument!\n argumentList.push(argumentDefinition);\n } else {\n // The current token should be a ',' token.\n if (token !== \",\") {\n throw new Error(`invalid argument list, expected ',' or ']' but got '${token}'`);\n }\n }\n });\n\n // The arguments list should terminate with a ']' or ')' token, depending on the opener.\n popAndCheck(tokens, closingToken);\n\n // Return the arguments.\n return argumentList;\n}\n\n/**\n * Gets an argument value definition.\n * @param token The argument token.\n * @param stringArgumentPlaceholders The mapping of string literal node argument placeholders to original values.\n * @returns An argument value definition.\n */\nfunction getArgumentDefinition(token: string, stringArgumentPlaceholders: StringLiteralPlaceholders): AnyArgument {\n // Check whether the token represents a null value.\n if (token === \"null\") {\n return {\n value: null,\n type: \"null\"\n } as NullArgument;\n }\n\n // Check whether the token represents a boolean value.\n if (token === \"true\" || token === \"false\") {\n return {\n value: token === \"true\",\n type: \"boolean\"\n } as BooleanArgument;\n }\n\n // Check whether the token represents a number value.\n // TODO: Relies on broken isNaN - see MDN.\n // if (!Number.isNaN(token)) {\n if (!isNaN(token as any)) {\n return {\n value: parseFloat(token),\n isInteger: parseFloat(token) === parseInt(token, 10),\n type: \"number\"\n } as NumberArgument;\n }\n\n // Check whether the token is a placeholder (e.g. @@0@@) representing a string literal.\n if (token.match(/^@@\\d+@@$/g)) {\n return {\n value: stringArgumentPlaceholders[token].replace('\\\\\"', '\"'),\n type: \"string\"\n } as StringPlaceholderArgument;\n }\n\n // The only remaining option is that the argument value is an identifier.\n return {\n value: token,\n type: \"identifier\"\n } as IdentifierArgument;\n}\n", "import { NodeAttributeDefinition } from \"../BehaviourTreeDefinition\";\nimport { parseArgumentTokens } from \"./MDSLNodeArgumentParser\";\nimport { StringLiteralPlaceholders } from \"./MDSLUtilities\";\n\n/**\n * A type defining the attribute definitions of a node.\n */\ntype NodeAttributes = {\n while?: NodeAttributeDefinition;\n until?: NodeAttributeDefinition;\n entry?: NodeAttributeDefinition;\n exit?: NodeAttributeDefinition;\n step?: NodeAttributeDefinition;\n};\n\n/**\n * Parse any node attribute definitions from the specified tokens array.\n * @param tokens The array of remaining tokens.\n * @param stringArgumentPlaceholders The mapping of string literal node argument placeholders to original values.\n * @returns An object of attribute definitions defined by any directly following tokens.\n */\nexport function parseAttributeTokens(\n tokens: string[],\n stringArgumentPlaceholders: StringLiteralPlaceholders\n): NodeAttributes {\n const nodeAttributeNames: (keyof NodeAttributes)[] = [\"while\", \"until\", \"entry\", \"exit\", \"step\"];\n\n // Create an object to hold any attributes found.\n const attributes: NodeAttributes = {};\n\n // Try to get the name of the attribute for the next token.\n let nextAttributeName = tokens[0]?.toLowerCase() as keyof NodeAttributes;\n\n // Pull attribute tokens as well as their arguments off of the tokens stack until we have no more.\n while (nodeAttributeNames.includes(nextAttributeName)) {\n // Check to make sure that we have not already created an attribute definition of this type.\n if (attributes[nextAttributeName]) {\n throw new Error(`duplicate attribute '${tokens[0].toUpperCase()}' found for node`);\n }\n\n // Remove the attribute name token from the array of tokens.\n tokens.shift();\n\n // Grab the attribute arguments, assuming the first to be an identifier.\n const [attributeCallIdentifier, ...attributeArguments] = parseArgumentTokens(\n tokens,\n stringArgumentPlaceholders\n );\n\n // The first attribute argument has to be an identifer, this will reference an agent function.\n if (attributeCallIdentifier?.type !== \"identifier\") {\n throw new Error(\"expected agent function name identifier argument for attribute\");\n }\n\n // Any attribute arguments (other than the expected call identifier) must have a type of string, number, boolean or null.\n attributeArguments\n .filter((arg) => arg.type === \"identifier\")\n .forEach((arg) => {\n throw new Error(\n `invalid attribute argument value '${arg.value}', must be string, number, boolean or null`\n );\n });\n\n // Create the attribute definition and add it to the object of attribute definitions found.\n attributes[nextAttributeName] = {\n call: attributeCallIdentifier.value,\n args: attributeArguments.map(({ value }) => value)\n };\n\n // Try to get the next attribute name token, as there could be multiple.\n nextAttributeName = tokens[0]?.toLowerCase() as keyof NodeAttributes;\n }\n\n return attributes;\n}\n", "import {\n ActionNodeDefinition,\n AnyChildNodeDefinition,\n AnyNodeDefinition,\n BranchNodeDefinition,\n ConditionNodeDefinition,\n FailNodeDefinition,\n FlipNodeDefinition,\n LottoNodeDefinition,\n ParallelNodeDefinition,\n RepeatNodeDefinition,\n RetryNodeDefinition,\n RootNodeDefinition,\n SelectorNodeDefinition,\n SequenceNodeDefinition,\n SucceedNodeDefinition,\n WaitNodeDefinition\n} from \"../BehaviourTreeDefinition\";\nimport { isCompositeNode, isDecoratorNode, isLeafNode, isRootNode } from \"../BehaviourTreeDefinitionUtilities\";\nimport { parseArgumentTokens } from \"./MDSLNodeArgumentParser\";\nimport { parseAttributeTokens } from \"./MDSLNodeAttributeParser\";\nimport {\n StringLiteralPlaceholders,\n parseTokensFromDefinition,\n popAndCheck,\n substituteStringLiterals\n} from \"./MDSLUtilities\";\n\n/**\n * Convert the MDSL tree definition string into an equivalent JSON definition.\n * @param definition The tree definition string as MDSL.\n * @returns The root node JSON definitions.\n */\nexport function convertMDSLToJSON(definition: string): RootNodeDefinition[] {\n // Swap out any node/attribute argument string literals with a placeholder and get a mapping of placeholders to original values as well as the processed definition.\n const { placeholders, processedDefinition } = substituteStringLiterals(definition);\n\n // Parse our definition definition string into an array of raw tokens.\n const tokens = parseTokensFromDefinition(processedDefinition);\n\n return convertTokensToJSONDefinition(tokens, placeholders);\n}\n\n/**\n * Converts the specified tree definition tokens into a JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The root node JSON definitions.\n */\nfunction convertTokensToJSONDefinition(\n tokens: string[],\n stringLiteralPlaceholders: StringLiteralPlaceholders\n): RootNodeDefinition[] {\n // There must be at least 3 tokens for the tree definition to be valid. 'ROOT', '{' and '}'.\n if (tokens.length < 3) {\n throw new Error(\"invalid token count\");\n }\n\n // We should have a matching number of '{' and '}' tokens. If not, then there are scopes that have not been properly closed.\n if (tokens.filter((token) => token === \"{\").length !== tokens.filter((token) => token === \"}\").length) {\n throw new Error(\"scope character mismatch\");\n }\n\n // Create an array of tree stack arrays where root nodes will always be at the botton and the current composite/decorator node at the top.\n // There should be an element in this array for every root node defined and every element should be an array with a root note as the first element.\n // E.g. A definition with two root nodes defined:\n // [\n // [root, lotto, sequence],\n // [root, selector]\n // ]\n const treeStacks: [Partial, ...Partial[]][] = [];\n\n // Create an array of all root node definitions that we create.\n const rootNodes: Partial[] = [];\n\n // A helper function used to push node definitions onto the tree stack.\n const pushNode = (node: AnyNodeDefinition) => {\n // If the node is a root node then we need to create a new tree stack array with the root node at the root.\n if (isRootNode(node)) {\n // Add the root node definition to our array of all parsed root node definitions.\n rootNodes.push(node);\n\n // Add the root node definition to the root of a new tree stack.\n treeStacks.push([node]);\n\n return;\n }\n\n // All non-root nodes should be pushed after their root nodes so handle cases\n // where we may not have any tree stacks or our top-most tree stack is empty.\n if (!treeStacks.length || !treeStacks[treeStacks.length - 1].length) {\n throw new Error(\"expected root node at base of definition\");\n }\n\n // Get the current tree stack that we are populating.\n const topTreeStack = treeStacks[treeStacks.length - 1];\n\n // Get the top-most node in the current tree stack, this will be a composite/decorator node\n // for which we will populate its children array if composite or setting its child if a decorator.\n const topTreeStackTopNode = topTreeStack[topTreeStack.length - 1] as AnyNodeDefinition;\n\n // If the top-most node in the current root stack is a composite or decorator\n // node then the current node should be added as a child of the top-most node.\n if (isCompositeNode(topTreeStackTopNode)) {\n topTreeStackTopNode.children = topTreeStackTopNode.children || [];\n topTreeStackTopNode.children.push(node);\n } else if (isDecoratorNode(topTreeStackTopNode)) {\n // If the top node already has a child node set then throw an error as a decorator should only have a single child.\n if (topTreeStackTopNode.child) {\n throw new Error(\"a decorator node must only have a single child node\");\n }\n\n topTreeStackTopNode.child = node;\n }\n\n // If the node we are adding is also a composite or decorator node, then we should push it\n // onto the current tree stack, as subsequent nodes will be added as its child/children.\n if (!isLeafNode(node)) {\n topTreeStack.push(node);\n }\n };\n\n // A helper function used to pop node definitions off of the stack.\n const popNode = () => {\n // Get the current tree stack that we are populating.\n const topTreeStack = treeStacks[treeStacks.length - 1];\n\n // Pop the top-most node in the current tree stack if there is one.\n if (topTreeStack.length) {\n topTreeStack.pop();\n }\n\n // We don't want any empty tree stacks in our stack of tree stacks.\n if (!topTreeStack.length) {\n treeStacks.pop();\n }\n };\n\n // We should keep processing the raw tokens until we run out of them.\n while (tokens.length) {\n // Grab the next token.\n const token = tokens.shift()!;\n\n // How we create the next node depends on the current raw token value.\n switch (token.toUpperCase()) {\n case \"ROOT\": {\n pushNode(createRootNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"SUCCEED\": {\n pushNode(createSucceedNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"FAIL\": {\n pushNode(createFailNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"FLIP\": {\n pushNode(createFlipNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"REPEAT\": {\n pushNode(createRepeatNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"RETRY\": {\n pushNode(createRetryNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"SEQUENCE\": {\n pushNode(createSequenceNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"SELECTOR\": {\n pushNode(createSelectorNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"PARALLEL\": {\n pushNode(createParallelNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"LOTTO\": {\n pushNode(createLottoNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"ACTION\": {\n pushNode(createActionNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"CONDITION\": {\n pushNode(createConditionNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"WAIT\": {\n pushNode(createWaitNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"BRANCH\": {\n pushNode(createBranchNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"}\": {\n // The '}' character closes the current scope and means that we have to pop a node off of the current stack.\n popNode();\n break;\n }\n\n default: {\n throw new Error(`unexpected token: ${token}`);\n }\n }\n }\n\n return rootNodes as RootNodeDefinition[];\n}\n\n/**\n * Creates a root node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The root node JSON definition.\n */\nfunction createRootNode(tokens: string[], stringLiteralPlaceholders: StringLiteralPlaceholders): RootNodeDefinition {\n // Create the root node definition.\n let node = {\n type: \"root\",\n id: undefined\n } as RootNodeDefinition;\n\n // Parse any node arguments, we should only have one if any which will be an identifier argument for the root identifier.\n const nodeArguments = parseArgumentTokens(tokens, stringLiteralPlaceholders);\n\n // Check whether any node arguments were defined.\n if (nodeArguments.length) {\n // We should only have one argument, if any, which will be an identifier argument for the root identifier.\n if (nodeArguments.length === 1 && nodeArguments[0].type === \"identifier\") {\n // The root node identifier will be the first and only node argument value.\n node.id = nodeArguments[0].value as string;\n } else {\n throw new Error(\"expected single root name argument\");\n }\n }\n\n // Grab any node attribute definitions and spread them into the node definition.\n node = { ...node, ...parseAttributeTokens(tokens, stringLiteralPlaceholders) };\n\n // This is a decorator node, so we expect an opening '{'.\n popAndCheck(tokens, \"{\");\n\n // Return the root node definition.\n return node;\n}\n\n/**\n * Creates a succeed node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The succeed node JSON definition.\n */\nfunction createSucceedNode(\n tokens: string[],\n stringLiteralPlaceholders: StringLiteralPlaceholders\n): SucceedNodeDefinition {\n const node = {\n type: \"succeed\",\n ...parseAttributeTokens(tokens, stringLiteralPlaceholders)\n } as SucceedNodeDefinition;\n\n // This is a decorator node, so we expect an opening '{'.\n popAndCheck(tokens, \"{\");\n\n // Return the succeed node definition.\n return node;\n}\n\n/**\n * Creates a fail node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The fail node JSON definition.\n */\nfunction createFailNode(tokens: string[], stringLiteralPlaceholders: StringLiteralPlaceholders): FailNodeDefinition {\n const node = {\n type: \"fail\",\n ...parseAttributeTokens(tokens, stringLiteralPlaceholders)\n } as FailNodeDefinition;\n\n // This is a decorator node, so we expect an opening '{'.\n popAndCheck(tokens, \"{\");\n\n // Return the fail node definition.\n return node;\n}\n\n/**\n * Creates a flip node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The flip node JSON definition.\n */\nfunction createFlipNode(tokens: string[], stringLiteralPlaceholders: StringLiteralPlaceholders): FlipNodeDefinition {\n const node = {\n type: \"flip\",\n ...parseAttributeTokens(tokens, stringLiteralPlaceholders)\n } as FlipNodeDefinition;\n\n // This is a decorator node, so we expect an opening '{'.\n popAndCheck(tokens, \"{\");\n\n // Return the flip node definition.\n return node;\n}\n\n/**\n * Creates a repeat node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The repeat node JSON definition.\n */\nfunction createRepeatNode(\n tokens: string[],\n stringLiteralPlaceholders: StringLiteralPlaceholders\n): RepeatNodeDefinition {\n let node = { type: \"repeat\" } as RepeatNodeDefinition;\n\n // Get the node arguments.\n const nodeArguments = parseArgumentTokens(tokens, stringLiteralPlaceholders);\n\n // The arguments of a repeat node are optional. We may have:\n // - No node arguments, in which case the repeat note will iterate indefinitely.\n // - One node argument which will be the explicit number of iterations to make.\n // - Two node arguments which define the min and max iteration bounds from which a random iteration count will be picked.\n if (nodeArguments.length) {\n // All repeat node arguments MUST be of type number and must be integer.\n nodeArguments\n .filter((arg) => arg.type !== \"number\" || !arg.isInteger)\n .forEach(() => {\n throw new Error(`repeat node iteration counts must be integer values`);\n });\n\n // We should have got one or two iteration counts.\n if (nodeArguments.length === 1) {\n // A static iteration count was defined.\n node.iterations = nodeArguments[0].value as number;\n } else if (nodeArguments.length === 2) {\n // A minimum and maximum iteration count was defined.\n node.iterations = [nodeArguments[0].value as number, nodeArguments[1].value as number];\n } else {\n // An incorrect number of iteration counts was defined.\n throw new Error(\"invalid number of repeat node iteration count arguments defined\");\n }\n }\n\n // Grab any node attribute definitions and spread them into the node definition.\n node = { ...node, ...parseAttributeTokens(tokens, stringLiteralPlaceholders) };\n\n // This is a decorator node, so we expect an opening '{'.\n popAndCheck(tokens, \"{\");\n\n // Return the repeat node definition.\n return node;\n}\n\n/**\n * Creates a retry node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The retry node JSON definition.\n */\nfunction createRetryNode(tokens: string[], stringLiteralPlaceholders: StringLiteralPlaceholders): RetryNodeDefinition {\n let node = { type: \"retry\" } as RetryNodeDefinition;\n\n // Get the node arguments.\n const nodeArguments = parseArgumentTokens(tokens, stringLiteralPlaceholders);\n\n // The arguments of a retry node are optional. We may have:\n // - No node arguments, in which case the retry note will attempt indefinitely.\n // - One node argument which will be the explicit number of attempts to make.\n // - Two node arguments which define the min and max attempt bounds from which a random attempt count will be picked.\n if (nodeArguments.length) {\n // All retry node arguments MUST be of type number and must be integer.\n nodeArguments\n .filter((arg) => arg.type !== \"number\" || !arg.isInteger)\n .forEach(() => {\n throw new Error(`retry node attempt counts must be integer values`);\n });\n\n // We should have got one or two attempt counts.\n if (nodeArguments.length === 1) {\n // A static attempt count was defined.\n node.attempts = nodeArguments[0].value as number;\n } else if (nodeArguments.length === 2) {\n // A minimum and maximum attempt count was defined.\n node.attempts = [nodeArguments[0].value as number, nodeArguments[1].value as number];\n } else {\n // An incorrect number of attempt counts was defined.\n throw new Error(\"invalid number of retry node attempt count arguments defined\");\n }\n }\n\n // Grab any node attribute definitions and spread them into the node definition.\n node = { ...node, ...parseAttributeTokens(tokens, stringLiteralPlaceholders) };\n\n // This is a decorator node, so we expect an opening '{'.\n popAndCheck(tokens, \"{\");\n\n // Return the retry node definition.\n return node;\n}\n\n/**\n * Creates a sequence node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The sequence node JSON definition.\n */\nfunction createSequenceNode(\n tokens: string[],\n stringLiteralPlaceholders: StringLiteralPlaceholders\n): SequenceNodeDefinition {\n const node = {\n type: \"sequence\",\n ...parseAttributeTokens(tokens, stringLiteralPlaceholders)\n } as SequenceNodeDefinition;\n\n // This is a composite node, so we expect an opening '{'.\n popAndCheck(tokens, \"{\");\n\n // Return the sequence node definition.\n return node;\n}\n\n/**\n * Creates a selector node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The selector node JSON definition.\n */\nfunction createSelectorNode(\n tokens: string[],\n stringLiteralPlaceholders: StringLiteralPlaceholders\n): SelectorNodeDefinition {\n const node = {\n type: \"selector\",\n ...parseAttributeTokens(tokens, stringLiteralPlaceholders)\n } as SelectorNodeDefinition;\n\n // This is a composite node, so we expect an opening '{'.\n popAndCheck(tokens, \"{\");\n\n // Return the selector node definition.\n return node;\n}\n\n/**\n * Creates a parallel node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The parallel node JSON definition.\n */\nfunction createParallelNode(\n tokens: string[],\n stringLiteralPlaceholders: StringLiteralPlaceholders\n): ParallelNodeDefinition {\n const node = {\n type: \"parallel\",\n ...parseAttributeTokens(tokens, stringLiteralPlaceholders)\n } as ParallelNodeDefinition;\n\n // This is a composite node, so we expect an opening '{'.\n popAndCheck(tokens, \"{\");\n\n // Return the parallel node definition.\n return node;\n}\n\n/**\n * Creates a lotto node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The lotto node JSON definition.\n */\nfunction createLottoNode(tokens: string[], stringLiteralPlaceholders: StringLiteralPlaceholders): LottoNodeDefinition {\n // If any node arguments have been defined then they must be our weights.\n const nodeArguments = parseArgumentTokens(tokens, stringLiteralPlaceholders);\n\n // All lotto node arguments MUST be of type number and must be integer.\n nodeArguments\n .filter((arg) => arg.type !== \"number\" || !arg.isInteger)\n .forEach(() => {\n throw new Error(`lotto node weight arguments must be integer values`);\n });\n\n const node = {\n type: \"lotto\",\n weights: nodeArguments.map(({ value }) => value),\n ...parseAttributeTokens(tokens, stringLiteralPlaceholders)\n } as LottoNodeDefinition;\n\n // This is a composite node, so we expect an opening '{'.\n popAndCheck(tokens, \"{\");\n\n // Return the lotto node definition.\n return node;\n}\n\n/**\n * Creates an action node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The action node JSON definition.\n */\nfunction createActionNode(\n tokens: string[],\n stringLiteralPlaceholders: StringLiteralPlaceholders\n): ActionNodeDefinition {\n // Parse any node arguments, we should have at least one which will be an identifier argument for the action name\n // and agent function to invoke for the action, all other arguments are to be passed as arguments to that function.\n const [actionNameIdentifier, ...agentFunctionArgs] = parseArgumentTokens(tokens, stringLiteralPlaceholders);\n\n // Our first argument MUST be defined and be an identifier as we require an action name argument.\n if (actionNameIdentifier?.type !== \"identifier\") {\n throw new Error(\"expected action name identifier argument\");\n }\n\n // Only the first argument should have been an identifier, all agent function arguments must be string, number, boolean or null.\n agentFunctionArgs\n .filter((arg) => arg.type === \"identifier\")\n .forEach((arg) => {\n throw new Error(\n `invalid action node argument value '${arg.value}', must be string, number, boolean or null`\n );\n });\n\n // Return the action node definition.\n return {\n type: \"action\",\n call: actionNameIdentifier.value,\n args: agentFunctionArgs.map(({ value }) => value),\n ...parseAttributeTokens(tokens, stringLiteralPlaceholders)\n };\n}\n\n/**\n * Creates a condition node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The condition node JSON definition.\n */\nfunction createConditionNode(\n tokens: string[],\n stringLiteralPlaceholders: StringLiteralPlaceholders\n): ConditionNodeDefinition {\n // Parse any node arguments, we should have at least one which will be an identifier argument for the condition name\n // and agent function to invoke for the condition, all other arguments are to be passed as arguments to that function.\n const [conditionNameIdentifier, ...agentFunctionArgs] = parseArgumentTokens(tokens, stringLiteralPlaceholders);\n\n // Our first argument MUST be defined and be an identifier as we require a condition name argument.\n if (conditionNameIdentifier?.type !== \"identifier\") {\n throw new Error(\"expected condition name identifier argument\");\n }\n\n // Only the first argument should have been an identifier, all agent function arguments must be string, number, boolean or null.\n agentFunctionArgs\n .filter((arg) => arg.type === \"identifier\")\n .forEach((arg) => {\n throw new Error(\n `invalid condition node argument value '${arg.value}', must be string, number, boolean or null`\n );\n });\n\n // Return the condition node definition.\n return {\n type: \"condition\",\n call: conditionNameIdentifier.value,\n args: agentFunctionArgs.map(({ value }) => value),\n ...parseAttributeTokens(tokens, stringLiteralPlaceholders)\n };\n}\n\n/**\n * Creates a wait node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The wait node JSON definition.\n */\nfunction createWaitNode(tokens: string[], stringLiteralPlaceholders: StringLiteralPlaceholders): WaitNodeDefinition {\n let node = { type: \"wait\" } as WaitNodeDefinition;\n\n // Get the node arguments.\n const nodeArguments = parseArgumentTokens(tokens, stringLiteralPlaceholders);\n\n // The arguments of a wait node are optional. We may have:\n // - No node arguments, in which case the wait will be indefinite until it is aborted.\n // - One node argument which will be the explicit duration of the wait.\n // - Two node arguments which define the min and max duration bounds from which a random duration will be picked.\n if (nodeArguments.length) {\n // All wait node arguments MUST be of type number and must be integer.\n nodeArguments\n .filter((arg) => arg.type !== \"number\" || !arg.isInteger)\n .forEach(() => {\n throw new Error(`wait node duration arguments must be integer values`);\n });\n\n // We may have:\n // - One node argument which will be the explicit duration of the wait.\n // - Two node arguments which define the min and max duration bounds from which a random duration will be picked.\n // - Too many arguments, which is not valid.\n if (nodeArguments.length === 1) {\n // An explicit duration was defined.\n node.duration = nodeArguments[0].value as number;\n } else if (nodeArguments.length === 2) {\n // Min and max duration bounds were defined from which a random duration will be picked.\n node.duration = [nodeArguments[0].value as number, nodeArguments[1].value as number];\n } else if (nodeArguments.length > 2) {\n // An incorrect number of duration arguments were defined.\n throw new Error(\"invalid number of wait node duration arguments defined\");\n }\n }\n\n // Return the wait node definition.\n return { ...node, ...parseAttributeTokens(tokens, stringLiteralPlaceholders) };\n}\n\n/**\n * Creates a branch node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The branch node JSON definition.\n */\nfunction createBranchNode(\n tokens: string[],\n stringLiteralPlaceholders: StringLiteralPlaceholders\n): BranchNodeDefinition {\n // Parse any node arguments, we should have one which will be an identifier argument for the root ref.\n const nodeArguments = parseArgumentTokens(tokens, stringLiteralPlaceholders);\n\n // We should have only a single identifer argument for a branch node, which is the root ref.\n if (nodeArguments.length !== 1 || nodeArguments[0].type !== \"identifier\") {\n throw new Error(\"expected single branch name argument\");\n }\n\n // Return the branch node definition.\n return { type: \"branch\", ref: nodeArguments[0].value };\n}\n", "import { RootNodeDefinition } from \"./BehaviourTreeDefinition\";\nimport { flattenDefinition, isBranchNode, isInteger } from \"./BehaviourTreeDefinitionUtilities\";\nimport { convertMDSLToJSON } from \"./mdsl/MDSLDefinitionParser\";\n\n/**\n * An object representing the result of validating a tree definition.\n */\nexport type DefinitionValidationResult = {\n /**\n * A flag defining whether validation succeeded.\n */\n succeeded: boolean;\n /**\n * A string containing the error message if validation did not succeed.\n */\n errorMessage?: string;\n};\n\n/**\n * Validates the specified behaviour tree definition in the form of JSON or MDSL, not taking any globally registered subtrees into consideration.\n * @param definition The behaviour tree definition in the form of JSON or MDSL.\n * @returns An object representing the result of validating the given tree definition.\n */\nexport function validateDefinition(definition: any): DefinitionValidationResult {\n // The definition must be defined.\n if (definition === null || typeof definition === \"undefined\") {\n return createValidationFailureResult(\"definition is null or undefined\");\n }\n\n // We are expecting a definition in one of three different forms:\n // - A string which we will assume is MDSL and we will parse this to JSON before validation.\n // - An array which we will assume is an array of root node definitions with at least one being the primary root node (no 'id' property)\n // - An object which we will assume is the primary root node and should not have an 'id' property.\n if (typeof definition === \"string\") {\n // The definition is a string which we can assume is MDSL, so attempt to validate it.\n return validateMDSLDefinition(definition);\n } else if (typeof definition === \"object\") {\n // The definition will either be an array (of root node definitions) or an object (the single primary root node definition).\n return validateJSONDefinition(definition);\n } else {\n return createValidationFailureResult(`unexpected definition type of '${typeof definition}'`);\n }\n}\n\n/**\n * Validates the specified behaviour tree definition in the form of MDSL.\n * @param definition The behaviour tree definition in the form of MDSL.\n * @returns An object representing the result of validating the given tree definition.\n */\nexport function validateMDSLDefinition(definition: string): DefinitionValidationResult {\n let rootNodeDefinitions;\n\n // The first thing the we need to do is to attempt to convert our MDSL into JSON.\n try {\n // The definition is a string which we can assume is MDSL, so attempt to parse it to a JSON definition in the form of an array of root node definitions.\n rootNodeDefinitions = convertMDSLToJSON(definition);\n } catch (error) {\n // We failed to parse the JSON from the MDSL, this is likely to be the result of it not being a valid MDSL string.\n return createValidationFailureResult(`invalid MDSL: ${error}`);\n }\n\n // Unpack all of the root node definitions into arrays of main ('id' defined) and sub ('id' not defined) root node definitions.\n const mainRootNodeDefinitions = rootNodeDefinitions.filter(({ id }) => typeof id === \"undefined\");\n const subRootNodeDefinitions = rootNodeDefinitions.filter(({ id }) => typeof id === \"string\" && id.length > 0);\n\n // We should ALWAYS have exactly one root node definition without an 'id' property defined, which is out main root node definition.\n if (mainRootNodeDefinitions.length !== 1) {\n return createValidationFailureResult(\n \"expected single unnamed root node at base of definition to act as main root\"\n );\n }\n\n // We should never have duplicate 'id' properties across our sub root node definitions.\n const subRootNodeIdenitifers: string[] = [];\n for (const { id } of subRootNodeDefinitions) {\n // Have we already come across this 'id' property value?\n if (subRootNodeIdenitifers.includes(id!)) {\n return createValidationFailureResult(`multiple root nodes found with duplicate name '${id}'`);\n }\n\n subRootNodeIdenitifers.push(id!);\n }\n\n try {\n // Validate our branch -> subtree links and check for any circular dependencies, we don't care about checking for broken subtree links here.\n validateBranchSubtreeLinks(rootNodeDefinitions, false);\n } catch (exception) {\n return createValidationFailureResult((exception as Error).message);\n }\n\n // Our definition was valid!\n return { succeeded: true };\n}\n\n/**\n * Validates the specified behaviour tree definition in the form of JSON.\n * @param definition The behaviour tree definition in the form of JSON.\n * @returns An object representing the result of validating the given tree definition.\n */\nexport function validateJSONDefinition(\n definition: RootNodeDefinition | RootNodeDefinition[]\n): DefinitionValidationResult {\n // The definition will either be an array (of root node definitions) or an object (the single primary root node definition).\n const rootNodeDefinitions = Array.isArray(definition) ? definition : [definition];\n\n // Iterate over our array of root nodes and call validateNode for each, passing an initial depth of 0, wrapped in a try catch to handle validation failures.\n try {\n rootNodeDefinitions.forEach((rootNodeDefinition) => validateNode(rootNodeDefinition, 0));\n } catch (error) {\n // Handle cases where we have caught a thrown Error and return a failure result with the error message.\n if (error instanceof Error) {\n return createValidationFailureResult(error.message);\n }\n\n // No idea what happened here!\n return createValidationFailureResult(`unexpected error: ${error}`);\n }\n\n // Unpack all of the root node definitions into arrays of main ('id' defined) and sub ('id' not defined) root node definitions.\n const mainRootNodeDefinitions = rootNodeDefinitions.filter(({ id }) => typeof id === \"undefined\");\n const subRootNodeDefinitions = rootNodeDefinitions.filter(({ id }) => typeof id === \"string\" && id.length > 0);\n\n // We should ALWAYS have exactly one root node definition without an 'id' property defined, which is out main root node definition.\n if (mainRootNodeDefinitions.length !== 1) {\n return createValidationFailureResult(\n \"expected single root node without 'id' property defined to act as main root\"\n );\n }\n\n // We should never have duplicate 'id' properties across our sub root node definitions.\n const subRootNodeIdenitifers: string[] = [];\n for (const { id } of subRootNodeDefinitions) {\n // Have we already come across this 'id' property value?\n if (subRootNodeIdenitifers.includes(id!)) {\n return createValidationFailureResult(\n `multiple root nodes found with duplicate 'id' property value of '${id}'`\n );\n }\n\n subRootNodeIdenitifers.push(id!);\n }\n\n try {\n // Validate our branch -> subtree links and check for any circular dependencies, we don't care about checking for broken subtree links here.\n validateBranchSubtreeLinks(rootNodeDefinitions, false);\n } catch (exception) {\n return createValidationFailureResult((exception as Error).message);\n }\n\n // Our definition was valid!\n return { succeeded: true };\n}\n\n/**\n * Validates the branch -> subtree links across all provided root node definitions.\n * This will not consider branch nodes that reference any globally registered subtrees unless includesGlobalSubtrees\n * is set to true, in which case we will also verify that there are no broken branch -> subtree links.\n * @param rootNodeDefinitions The array of root node definitions.\n * @param includesGlobalSubtrees A flag defining whether the array includes all global subtree root node definitions.\n */\nexport function validateBranchSubtreeLinks(rootNodeDefinitions: RootNodeDefinition[], includesGlobalSubtrees: boolean) {\n // Create a mapping of root node identifiers to other root nodes that they reference via branch nodes.\n // Below is an example of a mapping that includes a circular dependency (root => a => b => c => a)\n // [{ refs: [\"a\", \"b\"] }, { id: \"a\", refs: [\"b\"] }, { id: \"b\", refs: [\"c\"] }, { id: \"c\", refs: [\"a\"] }]\n const rootNodeMappings: { id: string | undefined; refs: string[] }[] = rootNodeDefinitions.map(\n (rootNodeDefinition) => ({\n id: rootNodeDefinition.id,\n refs: flattenDefinition(rootNodeDefinition)\n .filter(isBranchNode)\n .map(({ ref }) => ref)\n })\n );\n\n // A recursive function to walk through the mappings, keeping track of which root nodes we have visited in the form of a path of root node identifiers.\n const followRefs = (mapping: { id: string | undefined; refs: string[] }, path: (string | undefined)[] = []) => {\n // Have we found a circular dependency?\n if (path.includes(mapping.id)) {\n // We found a circular dependency! Get the bad path of root node identifiers.\n const badPath = [...path, mapping.id];\n\n // Create the formatted path value. [undefined, \"a\", \"b\", \"c\", \"a\"] would be formatted as \"a -> b -> c -> a\".\n const badPathFormatted = badPath.filter((element) => !!element).join(\" => \");\n\n // No need to continue, we found a circular dependency.\n throw new Error(`circular dependency found in branch node references: ${badPathFormatted}`);\n }\n\n for (const ref of mapping.refs) {\n // Find the mapping for the root node with an identifer matching the current ref.\n const subMapping = rootNodeMappings.find(({ id }) => id === ref);\n\n // We may not have a mapping for this ref, which is normal when we aren't considering all globally registered subtrees.\n if (subMapping) {\n followRefs(subMapping, [...path, mapping.id]);\n } else if (includesGlobalSubtrees) {\n // We found a reference to a root node that doesn't exist, which is a problem seeing as the root node definitons includes all globally registered subtrees.\n throw new Error(\n mapping.id\n ? `subtree '${mapping.id}' has branch node that references root node '${ref}' which has not been defined`\n : `primary tree has branch node that references root node '${ref}' which has not been defined`\n );\n }\n }\n };\n\n // Start looking for circular dependencies and broken references from the primary root node definition.\n followRefs(rootNodeMappings.find((mapping) => typeof mapping.id === \"undefined\")!);\n}\n\n/**\n * Validate an object that we expect to be a node definition.\n * @param definition An object that we expect to be a node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateNode(definition: any, depth: number): void {\n // Every node must be valid object and have a non-empty 'type' string property.\n if (typeof definition !== \"object\" || typeof definition.type !== \"string\" || definition.type.length === 0) {\n throw new Error(\n `node definition is not an object or 'type' property is not a non-empty string at depth '${depth}'`\n );\n }\n\n // How we validate this node definition will depend on its type.\n switch (definition.type) {\n case \"action\":\n validateActionNode(definition, depth);\n break;\n\n case \"condition\":\n validateConditionNode(definition, depth);\n break;\n\n case \"wait\":\n validateWaitNode(definition, depth);\n break;\n\n case \"branch\":\n validateBranchNode(definition, depth);\n break;\n\n case \"root\":\n validateRootNode(definition, depth);\n break;\n\n case \"success\":\n validateSuccessNode(definition, depth);\n break;\n\n case \"fail\":\n validateFailNode(definition, depth);\n break;\n\n case \"flip\":\n validateFlipNode(definition, depth);\n break;\n\n case \"repeat\":\n validateRepeatNode(definition, depth);\n break;\n\n case \"retry\":\n validateRetryNode(definition, depth);\n break;\n\n case \"sequence\":\n validateSequenceNode(definition, depth);\n break;\n\n case \"selector\":\n validateSelectorNode(definition, depth);\n break;\n\n case \"parallel\":\n validateParallelNode(definition, depth);\n break;\n\n default:\n throw new Error(`unexpected node type of '${definition.type}' at depth '${depth}'`);\n }\n}\n\n/**\n * Validate any attributes for a given node definition.\n * @param definition The node definition.\n * @param depth The depth of the node in the behaviour tree definition.\n */\nfunction validateNodeAttributes(definition: any, depth: number): void {\n // Validate each of the attribute types for this node.\n [\"while\", \"until\", \"entry\", \"exit\", \"step\"].forEach((attributeName) => {\n // Attempt to grab the definition for the current attribute from the node definition.\n const attributeDefinition = definition[attributeName];\n\n // All node attributes are optional, so there is nothing to do if the current attribute is not defined.\n if (typeof attributeDefinition === \"undefined\") {\n return;\n }\n\n // The attribute definition must be an object.\n if (typeof attributeDefinition !== \"object\") {\n throw new Error(\n `expected attribute '${attributeName}' to be an object for '${definition.type}' node at depth '${depth}'`\n );\n }\n\n // The 'call' property must be defined for any attribute definition.\n if (typeof attributeDefinition.call !== \"string\" || attributeDefinition.call.length === 0) {\n throw new Error(\n `expected 'call' property for attribute '${attributeName}' to be a non-empty string for '${definition.type}' node at depth '${depth}'`\n );\n }\n\n // If any node attribute arguments have been defined then they must have been defined in an array.\n if (typeof attributeDefinition.args !== \"undefined\" && !Array.isArray(attributeDefinition.args)) {\n throw new Error(\n `expected 'args' property for attribute '${attributeName}' to be an array for '${definition.type}' node at depth '${depth}'`\n );\n }\n });\n}\n\n/**\n * Validate an object that we expect to be a root node definition.\n * @param definition An object that we expect to be a root node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateRootNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"root\") {\n throw new Error(\"expected node type of 'root' for root node\");\n }\n\n // A root node cannot be the child of another node.\n if (depth > 0) {\n throw new Error(\"a root node cannot be the child of another node\");\n }\n\n // Check that, if the root node 'id' property is defined, it is a non-empty string.\n if (typeof definition.id !== \"undefined\" && (typeof definition.id !== \"string\" || definition.id.length === 0)) {\n throw new Error(\"expected non-empty string for 'id' property if defined for root node\");\n }\n\n // A root node is a decorator node, so must have a child node defined.\n if (typeof definition.child === \"undefined\") {\n throw new Error(\"expected property 'child' to be defined for root node\");\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n\n // Validate the child node of this decorator node.\n validateNode(definition.child, depth + 1);\n}\n\n/**\n * Validate an object that we expect to be a success node definition.\n * @param definition An object that we expect to be a success node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateSuccessNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"success\") {\n throw new Error(`expected node type of 'success' for success node at depth '${depth}'`);\n }\n\n // A success node is a decorator node, so must have a child node defined.\n if (typeof definition.child === \"undefined\") {\n throw new Error(`expected property 'child' to be defined for success node at depth '${depth}'`);\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n\n // Validate the child node of this decorator node.\n validateNode(definition.child, depth + 1);\n}\n\n/**\n * Validate an object that we expect to be a fail node definition.\n * @param definition An object that we expect to be a fail node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateFailNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"fail\") {\n throw new Error(`expected node type of 'fail' for fail node at depth '${depth}'`);\n }\n\n // A fail node is a decorator node, so must have a child node defined.\n if (typeof definition.child === \"undefined\") {\n throw new Error(`expected property 'child' to be defined for fail node at depth '${depth}'`);\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n\n // Validate the child node of this decorator node.\n validateNode(definition.child, depth + 1);\n}\n\n/**\n * Validate an object that we expect to be a flip node definition.\n * @param definition An object that we expect to be a flip node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateFlipNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"flip\") {\n throw new Error(`expected node type of 'flip' for flip node at depth '${depth}'`);\n }\n\n // A flip node is a decorator node, so must have a child node defined.\n if (typeof definition.child === \"undefined\") {\n throw new Error(`expected property 'child' to be defined for flip node at depth '${depth}'`);\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n\n // Validate the child node of this decorator node.\n validateNode(definition.child, depth + 1);\n}\n\n/**\n * Validate an object that we expect to be a repeat node definition.\n * @param definition An object that we expect to be a repeat node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateRepeatNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"repeat\") {\n throw new Error(`expected node type of 'repeat' for repeat node at depth '${depth}'`);\n }\n\n // A repeat node is a decorator node, so must have a child node defined.\n if (typeof definition.child === \"undefined\") {\n throw new Error(`expected property 'child' to be defined for repeat node at depth '${depth}'`);\n }\n\n // Check whether an 'iterations' property has been defined, it may not have been if this node is to repeat indefinitely.\n if (typeof definition.iterations !== \"undefined\") {\n if (Array.isArray(definition.iterations)) {\n // Check whether any elements of the array are not integer values.\n const containsNonInteger = !!definition.iterations.find((value: unknown) => !isInteger(value));\n\n // If the 'iterations' property is an array then it MUST contain two integer values.\n if (definition.iterations.length !== 2 || containsNonInteger) {\n throw new Error(\n `expected array containing two integer values for 'iterations' property if defined for repeat node at depth '${depth}'`\n );\n }\n } else if (!isInteger(definition.iterations)) {\n throw new Error(\n `expected integer value or array containing two integer values for 'iterations' property if defined for repeat node at depth '${depth}'`\n );\n }\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n\n // Validate the child node of this decorator node.\n validateNode(definition.child, depth + 1);\n}\n\n/**\n * Validate an object that we expect to be a retry node definition.\n * @param definition An object that we expect to be a retry node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateRetryNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"retry\") {\n throw new Error(`expected node type of 'retry' for retry node at depth '${depth}'`);\n }\n\n // A retry node is a decorator node, so must have a child node defined.\n if (typeof definition.child === \"undefined\") {\n throw new Error(`expected property 'child' to be defined for retry node at depth '${depth}'`);\n }\n\n // Check whether an 'attempts' property has been defined, it may not have been if this node is to retry indefinitely.\n if (typeof definition.attempts !== \"undefined\") {\n if (Array.isArray(definition.attempts)) {\n // Check whether any elements of the array are not integer values.\n const containsNonInteger = !!definition.attempts.find((value: unknown) => !isInteger(value));\n\n // If the 'attempts' property is an array then it MUST contain two integer values.\n if (definition.attempts.length !== 2 || containsNonInteger) {\n throw new Error(\n `expected array containing two integer values for 'attempts' property if defined for retry node at depth '${depth}'`\n );\n }\n } else if (!isInteger(definition.attempts)) {\n throw new Error(\n `expected integer value or array containing two integer values for 'attempts' property if defined for retry node at depth '${depth}'`\n );\n }\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n\n // Validate the child node of this decorator node.\n validateNode(definition.child, depth + 1);\n}\n\n/**\n * Validate an object that we expect to be a branch node definition.\n * @param definition An object that we expect to be a branch node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateBranchNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"branch\") {\n throw new Error(`expected node type of 'branch' for branch node at depth '${depth}'`);\n }\n\n // Check that the branch node 'ref' property is defined and is a non-empty string.\n if (typeof definition.ref !== \"string\" || definition.ref.length === 0) {\n throw new Error(`expected non-empty string for 'ref' property for branch node at depth '${depth}'`);\n }\n\n // It is invalid to define guard attributes for a branch node as they should be defined on the referenced root node.\n [\"while\", \"until\"].forEach((attributeName) => {\n if (typeof definition[attributeName] !== \"undefined\") {\n throw new Error(\n `guards should not be defined for branch nodes but guard '${attributeName}' was defined for branch node at depth '${depth}'`\n );\n }\n });\n\n // It is invalid to define callback attributes for a branch node as they should be defined on the referenced root node.\n [\"entry\", \"exit\", \"step\"].forEach((attributeName) => {\n if (typeof definition[attributeName] !== \"undefined\") {\n throw new Error(\n `callbacks should not be defined for branch nodes but callback '${attributeName}' was defined for branch node at depth '${depth}'`\n );\n }\n });\n}\n\n/**\n * Validate an object that we expect to be a action node definition.\n * @param definition An object that we expect to be a action node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateActionNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"action\") {\n throw new Error(`expected node type of 'action' for action node at depth '${depth}'`);\n }\n\n // The 'call' property must be defined for a action node definition.\n if (typeof definition.call !== \"string\" || definition.call.length === 0) {\n throw new Error(`expected non-empty string for 'call' property of action node at depth '${depth}'`);\n }\n\n // If any action function arguments have been defined then they must have been defined in an array.\n if (typeof definition.args !== \"undefined\" && !Array.isArray(definition.args)) {\n throw new Error(`expected array for 'args' property if defined for action node at depth '${depth}'`);\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n}\n\n/**\n * Validate an object that we expect to be a condition node definition.\n * @param definition An object that we expect to be a condition node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateConditionNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"condition\") {\n throw new Error(`expected node type of 'condition' for condition node at depth '${depth}'`);\n }\n\n // The 'call' property must be defined for a condition node definition.\n if (typeof definition.call !== \"string\" || definition.call.length === 0) {\n throw new Error(`expected non-empty string for 'call' property of condition node at depth '${depth}'`);\n }\n\n // If any condition function arguments have been defined then they must have been defined in an array.\n if (typeof definition.args !== \"undefined\" && !Array.isArray(definition.args)) {\n throw new Error(`expected array for 'args' property if defined for condition node at depth '${depth}'`);\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n}\n\n/**\n * Validate an object that we expect to be a wait node definition.\n * @param definition An object that we expect to be a wait node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateWaitNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"wait\") {\n throw new Error(`expected node type of 'wait' for wait node at depth '${depth}'`);\n }\n\n // Check whether a 'duration' property has been defined, it may not have been if this node is to wait indefinitely.\n if (typeof definition.duration !== \"undefined\") {\n if (Array.isArray(definition.duration)) {\n // Check whether any elements of the array are not integer values.\n const containsNonInteger = !!definition.duration.find((value: unknown) => !isInteger(value));\n\n // If the 'duration' property is an array then it MUST contain two integer values.\n if (definition.duration.length !== 2 || containsNonInteger) {\n throw new Error(\n `expected array containing two integer values for 'duration' property if defined for wait node at depth '${depth}'`\n );\n }\n } else if (!isInteger(definition.duration)) {\n throw new Error(\n `expected integer value or array containing two integer values for 'duration' property if defined for wait node at depth '${depth}'`\n );\n }\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n}\n\n/**\n * Validate an object that we expect to be a sequence node definition.\n * @param definition An object that we expect to be a sequence node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateSequenceNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"sequence\") {\n throw new Error(`expected node type of 'sequence' for sequence node at depth '${depth}'`);\n }\n\n // A sequence node is a composite node, so must have a children nodes array defined.\n if (!Array.isArray(definition.children) || definition.children.length === 0) {\n throw new Error(`expected non-empty 'children' array to be defined for sequence node at depth '${depth}'`);\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n\n // Validate the child nodes of this composite node.\n definition.children.forEach((child: any) => validateNode(child, depth + 1));\n}\n\n/**\n * Validate an object that we expect to be a selector node definition.\n * @param definition An object that we expect to be a selector node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateSelectorNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"selector\") {\n throw new Error(`expected node type of 'selector' for selector node at depth '${depth}'`);\n }\n\n // A selector node is a composite node, so must have a children nodes array defined.\n if (!Array.isArray(definition.children) || definition.children.length === 0) {\n throw new Error(`expected non-empty 'children' array to be defined for selector node at depth '${depth}'`);\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n\n // Validate the child nodes of this composite node.\n definition.children.forEach((child: any) => validateNode(child, depth + 1));\n}\n\n/**\n * Validate an object that we expect to be a parallel node definition.\n * @param definition An object that we expect to be a parallel node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateParallelNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"parallel\") {\n throw new Error(`expected node type of 'parallel' for parallel node at depth '${depth}'`);\n }\n\n // A parallel node is a composite node, so must have a children nodes array defined.\n if (!Array.isArray(definition.children) || definition.children.length === 0) {\n throw new Error(`expected non-empty 'children' array to be defined for parallel node at depth '${depth}'`);\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n\n // Validate the child nodes of this composite node.\n definition.children.forEach((child: any) => validateNode(child, depth + 1));\n}\n\n/**\n * A helper function to create a failure validation result with the given error message.\n * @param errorMessage The validation failure error message.\n * @returns A failure validation result with the given error message.\n */\nfunction createValidationFailureResult(errorMessage: string): DefinitionValidationResult {\n return { succeeded: false, errorMessage };\n}\n", "import { ActionResult, Agent, GlobalFunction } from \"./Agent\";\nimport { RootNodeDefinition } from \"./BehaviourTreeDefinition\";\n\nexport type InvokerFunction = (args: any[]) => ActionResult;\n\n/**\n * A singleton used to store and lookup registered functions and subtrees.\n */\nexport default class Lookup {\n /**\n * The object holding any registered functions keyed on function name.\n */\n private static functionTable: { [key: string]: GlobalFunction } = {};\n /**\n * The object holding any registered subtree root node definitions keyed on tree name.\n */\n private static subtreeTable: { [key: string]: RootNodeDefinition } = {};\n\n /**\n * Gets the function with the specified name.\n * @param name The name of the function.\n * @returns The function with the specified name.\n */\n public static getFunc(name: string): GlobalFunction {\n return this.functionTable[name];\n }\n\n /**\n * Sets the function with the specified name for later lookup.\n * @param name The name of the function.\n * @param func The function.\n */\n public static setFunc(name: string, func: GlobalFunction): void {\n this.functionTable[name] = func;\n }\n\n /**\n * Gets the function invoker for the specified agent and function name.\n * If a function with the specified name exists on the agent object then it will\n * be returned, otherwise we will then check the registered functions for a match.\n * @param agent The agent instance that this behaviour tree is modelling behaviour for.\n * @param name The function name.\n * @returns The function invoker for the specified agent and function name.\n */\n static getFuncInvoker(agent: Agent, name: string): InvokerFunction | null {\n // Check whether the agent contains the specified function.\n const foundOnAgent = agent[name];\n if (foundOnAgent && typeof foundOnAgent === \"function\") {\n return (args: any[]): boolean | ActionResult => foundOnAgent.apply(agent, args);\n }\n\n // The agent does not contain the specified function but it may have been registered at some point.\n if (this.functionTable[name] && typeof this.functionTable[name] === \"function\") {\n return (args: any[]) => this.functionTable[name](agent, ...args.map((arg) => arg.value));\n }\n\n // We have no function to invoke.\n return null;\n }\n\n /**\n * Gets all registered subtree root node definitions.\n */\n static getSubtrees(): { [key: string]: RootNodeDefinition } {\n return this.subtreeTable;\n }\n\n /**\n * Sets the subtree with the specified name for later lookup.\n * @param name The name of the subtree.\n * @param subtree The subtree.\n */\n static setSubtree(name: string, subtree: RootNodeDefinition) {\n this.subtreeTable[name] = subtree;\n }\n\n /**\n * Removes the registered function or subtree with the specified name.\n * @param name The name of the registered function or subtree.\n */\n static remove(name: string) {\n delete this.functionTable[name];\n delete this.subtreeTable[name];\n }\n\n /**\n * Remove all registered functions and subtrees.\n */\n static empty() {\n this.functionTable = {};\n this.subtreeTable = {};\n }\n}\n", "import Node from \"../../nodes/Node\";\n\n/**\n * An exception thrown when evaluating node guard path conditions and a conditions fails.\n */\nexport default class GuardUnsatisifedException extends Error {\n /**\n * @param source The node at which a guard condition failed.\n */\n constructor(private source: Node) {\n super(\"A guard path condition has failed\");\n }\n\n /**\n * Gets whether the specified node is the node at which a guard condition failed.\n * @param node The node to check against the source node.\n * @returns Whether the specified node is the node at which a guard condition failed.\n */\n isSourceNode = (node: Node) => node === this.source;\n}\n", "import { Agent } from \"../../Agent\";\nimport Guard from \"./Guard\";\nimport Node from \"../../nodes/Node\";\nimport GuardUnsatisifedException from \"./GuardUnsatisifedException\";\n\nexport type GuardPathPart = {\n node: Node;\n guards: Guard[];\n};\n\n/**\n * Represents a path of node guards along a root-to-leaf tree path.\n */\nexport default class GuardPath {\n /**\n * @param nodes An array of objects defining a node instance -> guard link, ordered by node depth.\n */\n constructor(private nodes: GuardPathPart[]) {}\n\n /**\n * Evaluate guard conditions for all guards in the tree path, moving outwards from the root.\n * @param agent The agent, required for guard evaluation.\n * @returns An evaluation results object.\n */\n evaluate = (agent: Agent) => {\n // We need to evaluate guard conditions for nodes up the tree, moving outwards from the root.\n for (const details of this.nodes) {\n // There can be multiple guards per node.\n for (const guard of details.guards) {\n // Check whether the guard condition passes, and throw an exception if not.\n if (!guard.isSatisfied(agent)) {\n throw new GuardUnsatisifedException(details.node);\n }\n }\n }\n };\n}\n", "import { BehaviourTreeOptions } from \"../BehaviourTreeOptions\";\nimport State, { AnyState } from \"../State\";\nimport { Agent } from \"../Agent\";\nimport Leaf from \"./leaf/Leaf\";\nimport Attribute from \"../attributes/Attribute\";\nimport Entry from \"../attributes/callbacks/Entry\";\nimport Exit from \"../attributes/callbacks/Exit\";\nimport Step from \"../attributes/callbacks/Step\";\nimport Guard from \"../attributes/guards/Guard\";\nimport GuardPath from \"../attributes/guards/GuardPath\";\nimport GuardUnsatisifedException from \"../attributes/guards/GuardUnsatisifedException\";\n\n/**\n * A base node.\n */\nexport default abstract class Node {\n /**\n * The node uid.\n */\n private readonly uid: string = createNodeUid();\n /**\n * The node state.\n */\n private state: AnyState = State.READY;\n /**\n * The guard path to evaluate as part of a node update.\n */\n private guardPath: GuardPath | undefined;\n\n /**\n * @param type The node type.\n * @param attributes The node attributes.\n * @param args The node argument definitions.\n */\n constructor(private type: string, private attributes: Attribute[], private args: any[]) {}\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected abstract onUpdate(agent: Agent, options: BehaviourTreeOptions): void;\n\n /**\n * Gets the name of the node.\n */\n public abstract getName(): string;\n\n /**\n * Gets whether this node is a leaf node.\n */\n public abstract isLeafNode: () => this is Leaf;\n\n /**\n * Gets/Sets the state of the node.\n */\n getState = (): AnyState => this.state;\n setState = (value: AnyState): void => {\n this.state = value;\n };\n\n /**\n * Gets the unique id of the node.\n */\n getUid = () => this.uid;\n\n /**\n * Gets the type of the node.\n */\n getType = () => this.type;\n\n /**\n * Gets the node attributes.\n */\n getAttributes = () => this.attributes;\n\n /**\n * Gets the node arguments.\n */\n getArguments = () => this.args;\n\n /**\n * Gets the node attribute with the specified type, or null if it does not exist.\n */\n getAttribute(type: \"entry\" | \"ENTRY\"): Entry;\n getAttribute(type: \"exit\" | \"EXIT\"): Exit;\n getAttribute(type: \"step\" | \"STEP\"): Step;\n getAttribute(type: string): Attribute {\n return (\n this.getAttributes().filter((decorator) => decorator.type.toUpperCase() === type.toUpperCase())[0] || null\n );\n }\n\n /**\n * Gets the node attributes.\n */\n getGuardAttributes = (): Guard[] => this.getAttributes().filter((decorator) => decorator.isGuard()) as Guard[];\n\n /**\n * Sets the guard path to evaluate as part of a node update.\n */\n setGuardPath = (value: GuardPath) => (this.guardPath = value);\n\n /**\n * Gets whether a guard path is assigned to this node.\n */\n hasGuardPath = () => !!this.guardPath;\n\n /**\n * Gets whether this node is in the specified state.\n * @param value The value to compare to the node state.\n */\n public is(value: AnyState): boolean {\n return this.state === value;\n }\n\n /**\n * Reset the state of the node.\n */\n public reset(): void {\n this.setState(State.READY);\n }\n\n /**\n * Abort the running of this node.\n * @param agent The agent.\n */\n public abort(agent: Agent): void {\n // There is nothing to do if this node is not in the running state.\n if (!this.is(State.RUNNING)) {\n return;\n }\n\n // Reset the state of this node.\n this.reset();\n\n this.getAttribute(\"exit\")?.callAgentFunction(agent, false, true);\n }\n\n /**\n * Update the node.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n * @returns The result of the update.\n */\n public update(agent: Agent, options: BehaviourTreeOptions): void {\n // If this node is already in a 'SUCCEEDED' or 'FAILED' state then there is nothing to do.\n if (this.is(State.SUCCEEDED) || this.is(State.FAILED)) {\n return;\n }\n\n try {\n // Evaluate all of the guard path conditions for the current tree path.\n this.guardPath!.evaluate(agent);\n\n // If this node is in the READY state then call the ENTRY for this node if it exists.\n if (this.is(State.READY)) {\n this.getAttribute(\"entry\")?.callAgentFunction(agent);\n }\n\n this.getAttribute(\"step\")?.callAgentFunction(agent);\n\n // Do the actual update.\n this.onUpdate(agent, options);\n\n // If this node is now in a 'SUCCEEDED' or 'FAILED' state then call the EXIT for this node if it exists.\n if (this.is(State.SUCCEEDED) || this.is(State.FAILED)) {\n this.getAttribute(\"exit\")?.callAgentFunction(agent, this.is(State.SUCCEEDED), false);\n }\n } catch (error) {\n // If the error is a GuardUnsatisfiedException then we need to determine if this node is the source.\n if (error instanceof GuardUnsatisifedException && error.isSourceNode(this)) {\n // Abort the current node.\n this.abort(agent);\n\n // Any node that is the source of an abort will be a failed node.\n this.setState(State.FAILED);\n } else {\n throw error;\n }\n }\n }\n}\n\n/**\n * Create a randomly generated node uid.\n * @returns A randomly generated node uid.\n */\nfunction createNodeUid(): string {\n var S4 = function () {\n return (((1 + Math.random()) * 0x10000) | 0).toString(16).substring(1);\n };\n return S4() + S4() + \"-\" + S4() + \"-\" + S4() + \"-\" + S4() + \"-\" + S4() + S4() + S4();\n}\n", "import Node from \"../Node\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\n\n/**\n * A decorator node that wraps a single child node.\n */\nexport default abstract class Decorator extends Node {\n /**\n * @param type The node type.\n * @param attributes The node attributes.\n * @param child The child node.\n */\n constructor(type: string, attributes: Attribute[], protected child: Node) {\n super(type, attributes, []);\n }\n\n /**\n * Gets whether this node is a leaf node.\n */\n isLeafNode = () => false;\n\n /**\n * Gets the children of this node.\n */\n getChildren = () => [this.child];\n\n /**\n * Reset the state of the node.\n */\n reset = () => {\n // Reset the state of this node.\n this.setState(State.READY);\n\n // Reset the state of the child node.\n this.child.reset();\n };\n\n /**\n * Abort the running of this node.\n * @param agent The agent.\n */\n abort = (agent: Agent) => {\n // There is nothing to do if this node is not in the running state.\n if (!this.is(State.RUNNING)) {\n return;\n }\n\n // Abort the child node.\n this.child.abort(agent);\n\n // Reset the state of this node.\n this.reset();\n\n this.getAttribute(\"exit\")?.callAgentFunction(agent, false, true);\n };\n}\n", "import Node from \"../Node\";\nimport Decorator from \"./Decorator\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A Root node.\n * The root node will have a single child.\n */\nexport default class Root extends Decorator {\n /**\n * @param attributes The node attributes.\n * @param child The child node.\n */\n constructor(attributes: Attribute[], child: Node) {\n super(\"root\", attributes, child);\n }\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // If the child has never been updated or is running then we will need to update it now.\n if (this.child.getState() === State.READY || this.child.getState() === State.RUNNING) {\n // Update the child of this node.\n this.child.update(agent, options);\n }\n\n // The state of the root node is the state of its child.\n this.setState(this.child.getState());\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => \"ROOT\";\n}\n", "import Guard from \"./guards/Guard\";\n\nexport type AttributeDetails = {\n /** The attribute type. */\n type: string;\n\n /** The attribute arguments. */\n args: any[];\n};\n\n/**\n * A base node attribute.\n */\nexport default abstract class Attribute {\n /**\n * @param type The node attribute type.\n * @param args The array of attribute arguments.\n */\n constructor(public type: string, public args: any[]) {}\n\n /**\n * Gets the attribute details.\n */\n abstract getDetails(): TAttributeDetails;\n\n /**\n * Gets whether this attribute is a guard.\n */\n abstract isGuard: () => this is Guard;\n}\n", "import { Agent } from \"../../Agent\";\nimport Attribute, { AttributeDetails } from \"../Attribute\";\n\nexport type GuardAttributeDetails = {\n /** The name of the condition function that determines whether the guard is satisfied. */\n condition: string;\n} & AttributeDetails;\n\n/**\n * A base node guard attribute.\n */\nexport default abstract class Guard extends Attribute {\n /**\n * @param type The node attribute type.\n * @param args The array of decorator argument definitions.\n * @param condition The name of the condition function that determines whether the guard is satisfied.\n */\n constructor(type: string, args: any[], private condition: string) {\n super(type, args);\n }\n\n /**\n * Gets the name of the condition function that determines whether the guard is satisfied.\n */\n getCondition = () => this.condition;\n\n /**\n * Gets whether this attribute is a guard.\n */\n isGuard = () => true;\n\n /**\n * Gets the attribute details.\n */\n getDetails(): GuardAttributeDetails {\n return {\n type: this.type,\n args: this.args,\n condition: this.getCondition()\n };\n }\n\n /**\n * Gets whether the guard is satisfied.\n * @param agent The agent.\n * @returns Whether the guard is satisfied.\n */\n abstract isSatisfied(agent: Agent): boolean;\n}\n", "import Guard from \"./Guard\";\nimport Lookup from \"../../Lookup\";\nimport { Agent } from \"../../Agent\";\n\n/**\n * A WHILE guard which is satisfied as long as the given condition remains true.\n */\nexport default class While extends Guard {\n /**\n * @param condition The name of the condition function that determines whether the guard is satisfied.\n * @param args The array of decorator argument definitions.\n */\n constructor(condition: string, args: any[]) {\n super(\"while\", args, condition);\n }\n\n /**\n * Gets whether the guard is satisfied.\n * @param agent The agent.\n * @returns Whether the guard is satisfied.\n */\n isSatisfied = (agent: Agent) => {\n // Attempt to get the invoker for the condition function.\n const conditionFuncInvoker = Lookup.getFuncInvoker(agent, this.getCondition());\n\n // The condition function should be defined.\n if (conditionFuncInvoker === null) {\n throw new Error(\n `cannot evaluate node guard as the condition '${this.getCondition()}' function is not defined on the agent and has not been registered`\n );\n }\n\n // Call the condition function to determine whether this guard is satisfied.\n return !!conditionFuncInvoker(this.args);\n };\n}\n", "import Guard from \"./Guard\";\nimport Lookup from \"../../Lookup\";\nimport { Agent } from \"../../Agent\";\n\n/**\n * An UNTIL guard which is satisfied as long as the given condition remains false.\n */\nexport default class Until extends Guard {\n /**\n * @param condition The name of the condition function that determines whether the guard is satisfied.\n * @param args The array of decorator argument definitions.\n */\n constructor(condition: string, args: any[]) {\n super(\"until\", args, condition);\n }\n\n /**\n * Gets whether the guard is satisfied.\n * @param agent The agent.\n * @returns Whether the guard is satisfied.\n */\n isSatisfied = (agent: Agent) => {\n // Attempt to get the invoker for the condition function.\n const conditionFuncInvoker = Lookup.getFuncInvoker(agent, this.getCondition());\n\n // The condition function should be defined.\n if (conditionFuncInvoker === null) {\n throw new Error(\n `cannot evaluate node guard as the condition '${this.getCondition()}' function is not defined on the agent and has not been registered`\n );\n }\n\n // Call the condition function to determine whether this guard is satisfied.\n return !!!conditionFuncInvoker(this.args);\n };\n}\n", "import { Agent } from \"../../Agent\";\nimport Attribute, { AttributeDetails } from \"../Attribute\";\n\nexport type CallbackAttributeDetails = {\n /** The name of the agent function that is called. */\n functionName: string;\n} & AttributeDetails;\n\n/**\n * A base node callback attribute.\n */\nexport default abstract class Callback extends Attribute {\n /**\n * @param type The node attribute type.\n * @param args The array of decorator argument definitions.\n * @param functionName The name of the agent function to call.\n */\n constructor(type: string, args: any[], private functionName: string) {\n super(type, args);\n }\n\n /**\n * Gets the name of the agent function to call.\n */\n getFunctionName = () => this.functionName;\n\n /**\n * Gets whether this attribute is a guard.\n */\n isGuard = () => false;\n\n /**\n * Gets the attribute details.\n */\n getDetails(): CallbackAttributeDetails {\n return {\n type: this.type,\n args: this.args,\n functionName: this.getFunctionName()\n };\n }\n\n /**\n * Attempt to call the agent function that this callback refers to.\n * @param agent The agent.\n */\n abstract callAgentFunction: (agent: Agent, isSuccess: boolean, isAborted: boolean) => void;\n}\n", "import Callback from \"./Callback\";\nimport Lookup from \"../../Lookup\";\nimport { Agent } from \"../../Agent\";\n\n/**\n * An ENTRY callback which defines an agent function to call when the associated node is updated and moves out of running state.\n */\nexport default class Entry extends Callback {\n /**\n * @param functionName The name of the agent function to call.\n * @param args The array of callback argument definitions.\n */\n constructor(functionName: string, args: any[]) {\n super(\"entry\", args, functionName);\n }\n\n /**\n * Attempt to call the agent function that this callback refers to.\n * @param agent The agent.\n */\n callAgentFunction = (agent: Agent) => {\n // Attempt to get the invoker for the callback function.\n const callbackFuncInvoker = Lookup.getFuncInvoker(agent, this.getFunctionName());\n\n // The callback function should be defined.\n if (callbackFuncInvoker === null) {\n throw new Error(\n `cannot call entry function '${this.getFunctionName()}' as is not defined on the agent and has not been registered`\n );\n }\n\n // Call the callback function.\n callbackFuncInvoker(this.args);\n };\n}\n", "import Callback from \"./Callback\";\nimport Lookup from \"../../Lookup\";\nimport { Agent } from \"../../Agent\";\n\n/**\n * A STEP callback which defines an agent function to call when the associated node is updated.\n */\nexport default class Step extends Callback {\n /**\n * @param functionName The name of the agent function to call.\n * @param args The array of callback argument definitions.\n */\n constructor(functionName: string, args: any[]) {\n super(\"step\", args, functionName);\n }\n\n /**\n * Attempt to call the agent function that this callback refers to.\n * @param agent The agent.\n */\n callAgentFunction = (agent: Agent) => {\n // Attempt to get the invoker for the callback function.\n const callbackFuncInvoker = Lookup.getFuncInvoker(agent, this.getFunctionName());\n\n // The callback function should be defined.\n if (callbackFuncInvoker === null) {\n throw new Error(\n `cannot call step function '${this.getFunctionName()}' as is not defined on the agent and has not been registered`\n );\n }\n\n // Call the callback function.\n callbackFuncInvoker(this.args);\n };\n}\n", "import Callback from \"./Callback\";\nimport Lookup from \"../../Lookup\";\nimport { Agent } from \"../../Agent\";\n\n/**\n * An EXIT callback which defines an agent function to call when the associated node is updated and moves to a finished state or is aborted.\n */\nexport default class Exit extends Callback {\n /**\n * @param functionName The name of the agent function to call.\n * @param args The array of callback argument definitions.\n */\n constructor(functionName: string, args: any[]) {\n super(\"exit\", args, functionName);\n }\n\n /**\n * Attempt to call the agent function that this callback refers to.\n * @param agent The agent.\n * @param isSuccess Whether the decorated node was left with a success state.\n * @param isAborted Whether the decorated node was aborted.\n */\n callAgentFunction = (agent: Agent, isSuccess: boolean, isAborted: boolean) => {\n // Attempt to get the invoker for the callback function.\n const callbackFuncInvoker = Lookup.getFuncInvoker(agent, this.getFunctionName());\n\n // The callback function should be defined.\n if (callbackFuncInvoker === null) {\n throw new Error(\n `cannot call exit function '${this.getFunctionName()}' as is not defined on the agent and has not been registered`\n );\n }\n\n // Call the callback function\n callbackFuncInvoker([{ value: { succeeded: isSuccess, aborted: isAborted } }, ...this.args]);\n };\n}\n", "import { AnyNodeDefinition, RootNodeDefinition } from \"./BehaviourTreeDefinition\";\nimport GuardPath, { GuardPathPart } from \"./attributes/guards/GuardPath\";\nimport { validateBranchSubtreeLinks } from \"./BehaviourTreeDefinitionValidator\";\nimport Node from \"./nodes/Node\";\nimport Composite from \"./nodes/composite/Composite\";\nimport Decorator from \"./nodes/decorator/Decorator\";\nimport Parallel from \"./nodes/composite/Parallel\";\nimport Selector from \"./nodes/composite/Selector\";\nimport Sequence from \"./nodes/composite/Sequence\";\nimport Lotto from \"./nodes/composite/Lotto\";\nimport Fail from \"./nodes/decorator/Fail\";\nimport Flip from \"./nodes/decorator/Flip\";\nimport Repeat from \"./nodes/decorator/Repeat\";\nimport Retry from \"./nodes/decorator/Retry\";\nimport Root from \"./nodes/decorator/Root\";\nimport Succeed from \"./nodes/decorator/Succeed\";\nimport Action from \"./nodes/leaf/Action\";\nimport Condition from \"./nodes/leaf/Condition\";\nimport Wait from \"./nodes/leaf/Wait\";\nimport Lookup from \"./Lookup\";\nimport Attribute from \"./attributes/Attribute\";\nimport While from \"./attributes/guards/While\";\nimport Until from \"./attributes/guards/Until\";\nimport Entry from \"./attributes/callbacks/Entry\";\nimport Step from \"./attributes/callbacks/Step\";\nimport Exit from \"./attributes/callbacks/Exit\";\n\n/**\n * A type representing any node instance in a behaviour tree.\n */\ntype AnyNode =\n | Root\n | Action\n | Condition\n | Wait\n | Sequence\n | Selector\n | Lotto\n | Parallel\n | Repeat\n | Retry\n | Flip\n | Succeed\n | Fail;\n\n/**\n * A type defining a mapping of root node identifiers to root node definitions.\n */\ntype RootNodeDefinitionMap = { [key: string | symbol]: RootNodeDefinition };\n\n/**\n * A symbol to use as the main root key in any root node mappings.\n */\nconst MAIN_ROOT_NODE_KEY = Symbol(\"__root__\");\n\n/**\n * Build and populate the root nodes based on the provided definition, assuming that the definition has been validated.\n * @param definition The root node definitions.\n * @returns The built and populated root node definitions.\n */\nexport default function buildRootNode(definition: RootNodeDefinition[]): Root {\n // Create a mapping of root node identifers to root node definitions, including globally registered subtree root node definitions.\n const rootNodeDefinitionMap = createRootNodeDefinitionMap(definition);\n\n // Now that we have all of our root node definitons (those part of the tree definition and those globally\n // registered) we should validate the definition. This will also double-check that we dont have any circular\n // dependencies in our branch -> subtree references and that we have no broken branch -> subtree links.\n validateBranchSubtreeLinks(definition, true);\n\n // Create our populated tree of node instances, starting with our main root node.\n const rootNode = nodeFactory(rootNodeDefinitionMap[MAIN_ROOT_NODE_KEY]) as Root;\n\n // Set a guard path on every leaf of the tree to evaluate as part of its update.\n applyLeafNodeGuardPaths(rootNode);\n\n // We only need to return the main root node.\n return rootNode;\n}\n\n/**\n * A factory function which creates a node instance based on the specified definition.\n * @param definition The node definition.\n * @returns A node instance based on the specified definition.\n */\nfunction nodeFactory(definition: AnyNodeDefinition): AnyNode {\n // Get the attributes for the node.\n const attributes = nodeAttributesFactory(definition);\n\n // Create the node instance based on the definition type.\n switch (definition.type) {\n case \"root\":\n return new Root(attributes, nodeFactory(definition.child));\n\n // ...\n\n default:\n throw new Error(`unexpected node type of '${definition.type}'`);\n }\n}\n\n/**\n * Creates an array of node attribute instances based on the specified node definition.\n * @param definition The node definition.\n * @returns An array of node attribute instances based on the specified node definition.\n */\nfunction nodeAttributesFactory(definition: AnyNodeDefinition): Attribute[] {\n const attributes: Attribute[] = [];\n\n if (definition.while) {\n attributes.push(new While(definition.while.call, definition.while.args ?? []));\n }\n\n if (definition.until) {\n attributes.push(new Until(definition.until.call, definition.until.args ?? []));\n }\n\n if (definition.entry) {\n attributes.push(new Entry(definition.entry.call, definition.entry.args ?? []));\n }\n\n if (definition.step) {\n attributes.push(new Step(definition.step.call, definition.step.args ?? []));\n }\n\n if (definition.exit) {\n attributes.push(new Exit(definition.exit.call, definition.exit.args ?? []));\n }\n\n return attributes;\n}\n\n/**\n * Creates a mapping of root node identifers to root node definitions, mixing in globally registered subtree root node definitions.\n * @param definition The root node definitions.\n * @returns A mapping of root node identifers to root node definitions, including globally registered subtree root node definitions.\n */\nfunction createRootNodeDefinitionMap(definition: RootNodeDefinition[]): RootNodeDefinitionMap {\n // Create a mapping of root node identifers to root node definitions.\n const rootNodeMap: RootNodeDefinitionMap = {};\n\n // Add in any registered subtree root node definitions.\n for (const [name, rootNodeDefinition] of Object.entries(Lookup.getSubtrees())) {\n // The name used when registering the subtree will be used as the root node identifier.\n rootNodeMap[name] = { ...rootNodeDefinition, id: name };\n }\n\n // Populate the map with the root node definitions that were included with the tree definition.\n // We do this after adding any registered subtrees as we want these to take presedence.\n for (const rootNodeDefinition of definition) {\n rootNodeMap[rootNodeDefinition.id ?? MAIN_ROOT_NODE_KEY] = rootNodeDefinition;\n }\n\n return rootNodeMap;\n}\n\n/**\n * Applies a guard path to every leaf of the tree to evaluate as part of each update.\n * @param root The main root tree node.\n */\nfunction applyLeafNodeGuardPaths(root: Root) {\n const nodePaths: Node[][] = [];\n\n const findLeafNodes = (path: Node[], node: Node) => {\n // Add the current node to the path.\n path = path.concat(node);\n\n // Check whether the current node is a leaf node.\n if (node.isLeafNode()) {\n nodePaths.push(path);\n } else {\n (node as Composite | Decorator).getChildren().forEach((child) => findLeafNodes(path, child));\n }\n };\n\n // Find all leaf node paths, starting from the root.\n findLeafNodes([], root);\n\n nodePaths.forEach((path) => {\n // Each node in the current path will have to be assigned a guard path, working from the root outwards.\n for (let depth = 0; depth < path.length; depth++) {\n // Get the node in the path at the current depth.\n const currentNode = path[depth];\n\n // The node may already have been assigned a guard path, if so just skip it.\n if (currentNode.hasGuardPath()) {\n continue;\n }\n\n // Create the guard path for the current node.\n const guardPath = new GuardPath(\n path\n .slice(0, depth + 1)\n .map((node) => ({ node, guards: node.getGuardAttributes() }))\n .filter((details) => details.guards.length > 0)\n );\n\n // Assign the guard path to the current node.\n currentNode.setGuardPath(guardPath);\n }\n });\n}\n", "import State, { AnyState } from \"./State\";\nimport Lookup from \"./Lookup\";\nimport Node from \"./nodes/Node\";\nimport Root from \"./nodes/decorator/Root\";\nimport Composite from \"./nodes/composite/Composite\";\nimport Decorator from \"./nodes/decorator/Decorator\";\nimport { Agent, GlobalFunction } from \"./Agent\";\nimport { CallbackAttributeDetails } from \"./attributes/callbacks/Callback\";\nimport { GuardAttributeDetails } from \"./attributes/guards/Guard\";\nimport { BehaviourTreeOptions } from \"./BehaviourTreeOptions\";\nimport { convertMDSLToJSON } from \"./mdsl/MDSLDefinitionParser\";\nimport { RootNodeDefinition } from \"./BehaviourTreeDefinition\";\nimport { validateJSONDefinition } from \"./BehaviourTreeDefinitionValidator\";\nimport buildRootNode from \"./BehaviourTreeBuilder\";\n\n// Purely for outside inspection of the tree.\nexport type FlattenedTreeNode = {\n id: string;\n type: string;\n caption: string;\n state: AnyState;\n guards: GuardAttributeDetails[];\n callbacks: CallbackAttributeDetails[];\n args: any[];\n parentId: string | null;\n};\n\n/**\n * A representation of a behaviour tree.\n */\nexport class BehaviourTree {\n /**\n * The main root tree node.\n */\n public readonly rootNode: Root;\n\n /**\n * Creates a new instance of the BehaviourTree class.\n * @param definition The behaviour tree definition.\n * @param agent The agent instance that this behaviour tree is modelling behaviour for.\n * @param options The behaviour tree options object.\n */\n constructor(\n definition: string | RootNodeDefinition | RootNodeDefinition[],\n private agent: Agent,\n private options: BehaviourTreeOptions = {}\n ) {\n // The tree definition must be defined.\n if (!definition) {\n throw new Error(\"the tree definition must be a string ro\");\n }\n\n // The agent must be defined and not null.\n if (typeof agent !== \"object\" || agent === null) {\n throw new Error(\"the agent must be defined and not null\");\n }\n\n try {\n // Parse the behaviour tree definition, create the populated tree of behaviour tree nodes, and get the root.\n this.rootNode = this._createRootNode(definition);\n } catch (exception) {\n // There was an issue in trying build and populate the behaviour tree.\n throw new Error(`error building tree: ${(exception as Error).message}`);\n }\n }\n\n /**\n * Gets whether the tree is in the RUNNING state.\n * @returns true if the tree is in the RUNNING state, otherwise false.\n */\n isRunning() {\n return this.rootNode.getState() === State.RUNNING;\n }\n\n /**\n * Gets the current tree state of SUCCEEDED, FAILED, READY or RUNNING.\n * @returns The current tree state.\n */\n getState() {\n return this.rootNode.getState();\n }\n\n /**\n * Step the tree.\n * 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.\n * 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\n * 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.\n *\n * 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.\n */\n step() {\n // If the root node has already been stepped to completion then we need to reset it.\n if (this.rootNode.getState() === State.SUCCEEDED || this.rootNode.getState() === State.FAILED) {\n this.rootNode.reset();\n }\n\n try {\n this.rootNode.update(this.agent, this.options);\n } catch (exception) {\n throw new Error(`error stepping tree: ${(exception as Error).message}`);\n }\n }\n\n /**\n * Resets the tree from the root node outwards to each nested node, giving each a state of READY.\n */\n reset() {\n this.rootNode.reset();\n }\n\n /**\n * Gets the flattened details of every node in the tree.\n * @returns The flattened details of every node in the tree.\n */\n getFlattenedNodeDetails(): FlattenedTreeNode[] {\n // Create an empty flattened array of tree nodes.\n const flattenedTreeNodes: FlattenedTreeNode[] = [];\n\n /**\n * Helper function to process a node instance and push details into the flattened tree nodes array.\n * @param node The current node.\n * @param parentUid The UID of the node parent, or null if the node is the main root node.\n */\n const processNode = (node: Node, parentUid: string | null) => {\n // Get the guard and callback attribute details for this node.\n const guards = node\n .getAttributes()\n .filter((attribute) => attribute.isGuard())\n .map((attribute) => attribute.getDetails()) as GuardAttributeDetails[];\n const callbacks = node\n .getAttributes()\n .filter((attribute) => !attribute.isGuard())\n .map((attribute) => attribute.getDetails()) as CallbackAttributeDetails[];\n\n // Push the current node into the flattened nodes array.\n flattenedTreeNodes.push({\n id: node.getUid(),\n type: node.getType(),\n caption: node.getName(),\n state: node.getState(),\n guards,\n callbacks,\n args: node.getArguments(),\n parentId: parentUid\n });\n\n // Process each of the nodes children if it is not a leaf node.\n if (!node.isLeafNode()) {\n (node as Composite | Decorator)\n .getChildren()\n .forEach((child) => processNode(child, (node as Composite | Decorator).getUid()));\n }\n };\n\n // Convert the nested node structure into a flattened array of node details.\n processNode(this.rootNode, null);\n\n return flattenedTreeNodes;\n }\n\n /**\n * Registers the action/condition/guard/callback function or subtree with the given name.\n * @param name The name of the function or subtree to register.\n * @param value The function or subtree definition to register.\n */\n static register(name: string, value: GlobalFunction | string | RootNodeDefinition) {\n // Are we going to register a action/condition/guard/callback function?\n if (typeof value === \"function\") {\n Lookup.setFunc(name, value);\n return;\n }\n\n // We are not registering an action/condition/guard/callback function, so we must be registering a subtree.\n if (typeof value === \"string\") {\n let rootNodeDefinitions: RootNodeDefinition[];\n\n // We will assume that any string passed in will be a mdsl definition.\n try {\n rootNodeDefinitions = convertMDSLToJSON(value);\n } catch (exception) {\n throw new Error(`error registering definition, invalid MDSL: ${(exception as Error).message}`);\n }\n\n // This function should only ever be called with a definition containing a single unnamed root node.\n if (rootNodeDefinitions.length != 1 || rootNodeDefinitions[0].id !== null) {\n throw new Error(\"error registering definition: expected a single unnamed root node\");\n }\n\n try {\n // We should validate the subtree as we don't want invalid subtrees available via the lookup.\n const { succeeded, errorMessage } = validateJSONDefinition(rootNodeDefinitions[0]);\n\n // Did our validation fail without error?\n if (!succeeded) {\n throw new Error(errorMessage);\n }\n } catch (exception) {\n throw new Error(`error registering definition: ${(exception as Error).message}`);\n }\n\n // Everything seems hunky-dory, register the subtree.\n Lookup.setSubtree(name, rootNodeDefinitions[0]);\n } else if (typeof value === \"object\" && !Array.isArray(value)) {\n // We will assume that any object passed in is a root node definition.\n\n try {\n // We should validate the subtree as we don't want invalid subtrees available via the lookup.\n const { succeeded, errorMessage } = validateJSONDefinition(value);\n\n // Did our validation fail without error?\n if (!succeeded) {\n throw new Error(errorMessage);\n }\n } catch (exception) {\n throw new Error(`error registering definition: ${(exception as Error).message}`);\n }\n\n // Everything seems hunky-dory, register the subtree.\n Lookup.setSubtree(name, value);\n } else {\n throw new Error(\"unexpected value, expected string mdsl definition, root node json definition or function\");\n }\n }\n\n /**\n * Unregisters the registered action/condition/guard/callback function or subtree with the given name.\n * @param name The name of the registered action/condition/guard/callback function or subtree to unregister.\n */\n static unregister(name: string): void {\n Lookup.remove(name);\n }\n\n /**\n * Unregister all registered action/condition/guard/callback functions and subtrees.\n */\n static unregisterAll(): void {\n Lookup.empty();\n }\n\n /**\n * Parses a behaviour tree definition and creates a tree of behaviour tree nodes populated at a root.\n * @param {string | RootNodeDefinition | RootNodeDefinition[]} definition The behaviour tree definition.\n * @returns The root behaviour tree node.\n */\n private _createRootNode(definition: string | RootNodeDefinition | RootNodeDefinition[]): Root {\n let resolvedDefinition: RootNodeDefinition | RootNodeDefinition[];\n\n // If the definition is a string then we will assume that it is an mdsl string which needs to be converted to a JSON definition.\n if (typeof definition === \"string\") {\n try {\n resolvedDefinition = convertMDSLToJSON(definition);\n } catch (exception) {\n throw new Error(`invalid mdsl definition: ${(exception as Error).message}`);\n }\n } else {\n // The definition is not a string, so we should assume that it is already a JSON definition.\n resolvedDefinition = definition;\n }\n\n // Build and populate the root node.\n return buildRootNode(Array.isArray(resolvedDefinition) ? resolvedDefinition : [resolvedDefinition]);\n }\n}\n"], - "mappings": ";;;;;;;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;;ACGO,IAAK,QAAL,kBAAKA,WAAL;AACH,EAAAA,OAAA,WAAQ;AACR,EAAAA,OAAA,aAAU;AACV,EAAAA,OAAA,eAAY;AACZ,EAAAA,OAAA,YAAS;AAJD,SAAAA;AAAA,GAAA;;;ACWL,SAAS,WAAW,MAAkD;AACzE,SAAO,KAAK,SAAS;AACzB;AAOO,SAAS,aAAa,MAAoD;AAC7E,SAAO,KAAK,SAAS;AACzB;AAOO,SAAS,WAAW,MAA8C;AACrE,SAAO,CAAC,UAAU,UAAU,aAAa,MAAM,EAAE,SAAS,KAAK,IAAI;AACvE;AAOO,SAAS,gBAAgB,MAAuD;AACnF,SAAO,CAAC,QAAQ,UAAU,SAAS,QAAQ,WAAW,MAAM,EAAE,SAAS,KAAK,IAAI;AACpF;AAOO,SAAS,gBAAgB,MAAuD;AACnF,SAAO,CAAC,YAAY,YAAY,SAAS,UAAU,EAAE,SAAS,KAAK,IAAI;AAC3E;AAOO,SAAS,kBAAkB,gBAAwD;AACtF,QAAM,QAA6B,CAAC;AAEpC,QAAM,cAAc,CAAC,0BAA6C;AAC9D,UAAM,KAAK,qBAAqB;AAEhC,QAAI,gBAAgB,qBAAqB,GAAG;AACxC,4BAAsB,SAAS,QAAQ,WAAW;AAAA,IACtD,WAAW,gBAAgB,qBAAqB,GAAG;AAC/C,kBAAY,sBAAsB,KAAK;AAAA,IAC3C;AAAA,EACJ;AAEA,cAAY,cAAc;AAE1B,SAAO;AACX;AAOO,SAAS,UAAU,OAAyB;AAC/C,SAAO,OAAO,UAAU,YAAY,KAAK,MAAM,KAAK,MAAM;AAC9D;;;ACzEO,SAAS,YAAY,QAAkB,UAAsC;AAEhF,QAAM,SAAS,OAAO,MAAM;AAG5B,MAAI,WAAW,QAAW;AACtB,UAAM,IAAI,MAAM,8BAA8B;AAAA,EAClD;AAGA,MAAI,YAAY,QAAW;AAEvB,UAAM,iBAAiB,OAAO,aAAa,WAAW,CAAC,QAAQ,IAAI;AAGnE,QAAI,0BAA0B,eAAe,KAAK,CAAC,SAAS,OAAO,YAAY,MAAM,KAAK,YAAY,CAAC;AAGvG,QAAI,CAAC,yBAAyB;AAC1B,YAAM,oBAAoB,eAAe,IAAI,CAAC,SAAS,MAAM,OAAO,GAAG,EAAE,KAAK,MAAM;AACpF,YAAM,IAAI,MAAM,sCAAsC,oBAAoB,eAAe,SAAS,GAAG;AAAA,IACzG;AAAA,EACJ;AAGA,SAAO;AACX;AAOO,SAAS,yBAAyB,YAGvC;AAEE,QAAM,eAA0C,CAAC;AAGjD,QAAM,sBAAsB,WAAW,QAAQ,sBAAsB,CAAC,UAAU;AAC5E,QAAI,gBAAgB,MAAM,UAAU,GAAG,MAAM,SAAS,CAAC;AACvD,QAAI,cAAc,OAAO,KAAK,YAAY,EAAE,KAAK,CAAC,QAAQ,aAAa,SAAS,aAAa;AAG7F,QAAI,CAAC,aAAa;AACd,oBAAc,KAAK,OAAO,KAAK,YAAY,EAAE;AAC7C,mBAAa,eAAe;AAAA,IAChC;AAEA,WAAO;AAAA,EACX,CAAC;AAED,SAAO,EAAE,cAAc,oBAAoB;AAC/C;AAOO,SAAS,0BAA0B,YAA8B;AAEpE,eAAa,WAAW,QAAQ,OAAO,KAAK;AAC5C,eAAa,WAAW,QAAQ,OAAO,KAAK;AAC5C,eAAa,WAAW,QAAQ,OAAO,KAAK;AAC5C,eAAa,WAAW,QAAQ,OAAO,KAAK;AAC5C,eAAa,WAAW,QAAQ,OAAO,KAAK;AAC5C,eAAa,WAAW,QAAQ,OAAO,KAAK;AAC5C,eAAa,WAAW,QAAQ,OAAO,KAAK;AAG5C,SAAO,WAAW,QAAQ,QAAQ,GAAG,EAAE,KAAK,EAAE,MAAM,GAAG;AAC3D;;;AChCO,SAAS,oBACZ,QACA,4BACa;AACb,QAAM,eAA8B,CAAC;AAGrC,MAAI,CAAC,CAAC,KAAK,GAAG,EAAE,SAAS,OAAO,EAAE,GAAG;AACjC,WAAO;AAAA,EACX;AAIA,QAAM,eAAe,YAAY,QAAQ,CAAC,KAAK,GAAG,CAAC,MAAM,MAAM,MAAM;AAErE,QAAM,qBAA+B,CAAC;AAGtC,SAAO,OAAO,UAAU,OAAO,OAAO,cAAc;AAEhD,uBAAmB,KAAK,OAAO,MAAM,CAAE;AAAA,EAC3C;AAGA,qBAAmB,QAAQ,CAAC,OAAO,UAAU;AAEzC,UAAM,wBAAwB,EAAE,QAAQ;AAGxC,QAAI,uBAAuB;AAEvB,YAAM,qBAAqB,sBAAsB,OAAO,0BAA0B;AAGlF,mBAAa,KAAK,kBAAkB;AAAA,IACxC,OAAO;AAEH,UAAI,UAAU,KAAK;AACf,cAAM,IAAI,MAAM,uDAAuD,QAAQ;AAAA,MACnF;AAAA,IACJ;AAAA,EACJ,CAAC;AAGD,cAAY,QAAQ,YAAY;AAGhC,SAAO;AACX;AAQA,SAAS,sBAAsB,OAAe,4BAAoE;AAE9G,MAAI,UAAU,QAAQ;AAClB,WAAO;AAAA,MACH,OAAO;AAAA,MACP,MAAM;AAAA,IACV;AAAA,EACJ;AAGA,MAAI,UAAU,UAAU,UAAU,SAAS;AACvC,WAAO;AAAA,MACH,OAAO,UAAU;AAAA,MACjB,MAAM;AAAA,IACV;AAAA,EACJ;AAKA,MAAI,CAAC,MAAM,KAAY,GAAG;AACtB,WAAO;AAAA,MACH,OAAO,WAAW,KAAK;AAAA,MACvB,WAAW,WAAW,KAAK,MAAM,SAAS,OAAO,EAAE;AAAA,MACnD,MAAM;AAAA,IACV;AAAA,EACJ;AAGA,MAAI,MAAM,MAAM,YAAY,GAAG;AAC3B,WAAO;AAAA,MACH,OAAO,2BAA2B,OAAO,QAAQ,OAAO,GAAG;AAAA,MAC3D,MAAM;AAAA,IACV;AAAA,EACJ;AAGA,SAAO;AAAA,IACH,OAAO;AAAA,IACP,MAAM;AAAA,EACV;AACJ;;;ACjIO,SAAS,qBACZ,QACA,4BACc;AACd,QAAM,qBAA+C,CAAC,SAAS,SAAS,SAAS,QAAQ,MAAM;AAG/F,QAAM,aAA6B,CAAC;AAGpC,MAAI,oBAAoB,OAAO,IAAI,YAAY;AAG/C,SAAO,mBAAmB,SAAS,iBAAiB,GAAG;AAEnD,QAAI,WAAW,oBAAoB;AAC/B,YAAM,IAAI,MAAM,wBAAwB,OAAO,GAAG,YAAY,mBAAmB;AAAA,IACrF;AAGA,WAAO,MAAM;AAGb,UAAM,CAAC,4BAA4B,kBAAkB,IAAI;AAAA,MACrD;AAAA,MACA;AAAA,IACJ;AAGA,QAAI,yBAAyB,SAAS,cAAc;AAChD,YAAM,IAAI,MAAM,gEAAgE;AAAA,IACpF;AAGA,uBACK,OAAO,CAAC,QAAQ,IAAI,SAAS,YAAY,EACzC,QAAQ,CAAC,QAAQ;AACd,YAAM,IAAI;AAAA,QACN,qCAAqC,IAAI;AAAA,MAC7C;AAAA,IACJ,CAAC;AAGL,eAAW,qBAAqB;AAAA,MAC5B,MAAM,wBAAwB;AAAA,MAC9B,MAAM,mBAAmB,IAAI,CAAC,EAAE,MAAM,MAAM,KAAK;AAAA,IACrD;AAGA,wBAAoB,OAAO,IAAI,YAAY;AAAA,EAC/C;AAEA,SAAO;AACX;;;ACzCO,SAAS,kBAAkB,YAA0C;AAExE,QAAM,EAAE,cAAc,oBAAoB,IAAI,yBAAyB,UAAU;AAGjF,QAAM,SAAS,0BAA0B,mBAAmB;AAE5D,SAAO,8BAA8B,QAAQ,YAAY;AAC7D;AAQA,SAAS,8BACL,QACA,2BACoB;AAEpB,MAAI,OAAO,SAAS,GAAG;AACnB,UAAM,IAAI,MAAM,qBAAqB;AAAA,EACzC;AAGA,MAAI,OAAO,OAAO,CAAC,UAAU,UAAU,GAAG,EAAE,WAAW,OAAO,OAAO,CAAC,UAAU,UAAU,GAAG,EAAE,QAAQ;AACnG,UAAM,IAAI,MAAM,0BAA0B;AAAA,EAC9C;AASA,QAAM,aAAoF,CAAC;AAG3F,QAAM,YAA2C,CAAC;AAGlD,QAAM,WAAW,CAAC,SAA4B;AAE1C,QAAI,WAAW,IAAI,GAAG;AAElB,gBAAU,KAAK,IAAI;AAGnB,iBAAW,KAAK,CAAC,IAAI,CAAC;AAEtB;AAAA,IACJ;AAIA,QAAI,CAAC,WAAW,UAAU,CAAC,WAAW,WAAW,SAAS,GAAG,QAAQ;AACjE,YAAM,IAAI,MAAM,0CAA0C;AAAA,IAC9D;AAGA,UAAM,eAAe,WAAW,WAAW,SAAS;AAIpD,UAAM,sBAAsB,aAAa,aAAa,SAAS;AAI/D,QAAI,gBAAgB,mBAAmB,GAAG;AACtC,0BAAoB,WAAW,oBAAoB,YAAY,CAAC;AAChE,0BAAoB,SAAS,KAAK,IAAI;AAAA,IAC1C,WAAW,gBAAgB,mBAAmB,GAAG;AAE7C,UAAI,oBAAoB,OAAO;AAC3B,cAAM,IAAI,MAAM,qDAAqD;AAAA,MACzE;AAEA,0BAAoB,QAAQ;AAAA,IAChC;AAIA,QAAI,CAAC,WAAW,IAAI,GAAG;AACnB,mBAAa,KAAK,IAAI;AAAA,IAC1B;AAAA,EACJ;AAGA,QAAM,UAAU,MAAM;AAElB,UAAM,eAAe,WAAW,WAAW,SAAS;AAGpD,QAAI,aAAa,QAAQ;AACrB,mBAAa,IAAI;AAAA,IACrB;AAGA,QAAI,CAAC,aAAa,QAAQ;AACtB,iBAAW,IAAI;AAAA,IACnB;AAAA,EACJ;AAGA,SAAO,OAAO,QAAQ;AAElB,UAAM,QAAQ,OAAO,MAAM;AAG3B,YAAQ,MAAM,YAAY,GAAG;AAAA,MACzB,KAAK,QAAQ;AACT,iBAAS,eAAe,QAAQ,yBAAyB,CAAC;AAC1D;AAAA,MACJ;AAAA,MAEA,KAAK,WAAW;AACZ,iBAAS,kBAAkB,QAAQ,yBAAyB,CAAC;AAC7D;AAAA,MACJ;AAAA,MAEA,KAAK,QAAQ;AACT,iBAAS,eAAe,QAAQ,yBAAyB,CAAC;AAC1D;AAAA,MACJ;AAAA,MAEA,KAAK,QAAQ;AACT,iBAAS,eAAe,QAAQ,yBAAyB,CAAC;AAC1D;AAAA,MACJ;AAAA,MAEA,KAAK,UAAU;AACX,iBAAS,iBAAiB,QAAQ,yBAAyB,CAAC;AAC5D;AAAA,MACJ;AAAA,MAEA,KAAK,SAAS;AACV,iBAAS,gBAAgB,QAAQ,yBAAyB,CAAC;AAC3D;AAAA,MACJ;AAAA,MAEA,KAAK,YAAY;AACb,iBAAS,mBAAmB,QAAQ,yBAAyB,CAAC;AAC9D;AAAA,MACJ;AAAA,MAEA,KAAK,YAAY;AACb,iBAAS,mBAAmB,QAAQ,yBAAyB,CAAC;AAC9D;AAAA,MACJ;AAAA,MAEA,KAAK,YAAY;AACb,iBAAS,mBAAmB,QAAQ,yBAAyB,CAAC;AAC9D;AAAA,MACJ;AAAA,MAEA,KAAK,SAAS;AACV,iBAAS,gBAAgB,QAAQ,yBAAyB,CAAC;AAC3D;AAAA,MACJ;AAAA,MAEA,KAAK,UAAU;AACX,iBAAS,iBAAiB,QAAQ,yBAAyB,CAAC;AAC5D;AAAA,MACJ;AAAA,MAEA,KAAK,aAAa;AACd,iBAAS,oBAAoB,QAAQ,yBAAyB,CAAC;AAC/D;AAAA,MACJ;AAAA,MAEA,KAAK,QAAQ;AACT,iBAAS,eAAe,QAAQ,yBAAyB,CAAC;AAC1D;AAAA,MACJ;AAAA,MAEA,KAAK,UAAU;AACX,iBAAS,iBAAiB,QAAQ,yBAAyB,CAAC;AAC5D;AAAA,MACJ;AAAA,MAEA,KAAK,KAAK;AAEN,gBAAQ;AACR;AAAA,MACJ;AAAA,MAEA,SAAS;AACL,cAAM,IAAI,MAAM,qBAAqB,OAAO;AAAA,MAChD;AAAA,IACJ;AAAA,EACJ;AAEA,SAAO;AACX;AAQA,SAAS,eAAe,QAAkB,2BAA0E;AAEhH,MAAI,OAAO;AAAA,IACP,MAAM;AAAA,IACN,IAAI;AAAA,EACR;AAGA,QAAM,gBAAgB,oBAAoB,QAAQ,yBAAyB;AAG3E,MAAI,cAAc,QAAQ;AAEtB,QAAI,cAAc,WAAW,KAAK,cAAc,GAAG,SAAS,cAAc;AAEtE,WAAK,KAAK,cAAc,GAAG;AAAA,IAC/B,OAAO;AACH,YAAM,IAAI,MAAM,oCAAoC;AAAA,IACxD;AAAA,EACJ;AAGA,SAAO,EAAE,GAAG,MAAM,GAAG,qBAAqB,QAAQ,yBAAyB,EAAE;AAG7E,cAAY,QAAQ,GAAG;AAGvB,SAAO;AACX;AAQA,SAAS,kBACL,QACA,2BACqB;AACrB,QAAM,OAAO;AAAA,IACT,MAAM;AAAA,IACN,GAAG,qBAAqB,QAAQ,yBAAyB;AAAA,EAC7D;AAGA,cAAY,QAAQ,GAAG;AAGvB,SAAO;AACX;AAQA,SAAS,eAAe,QAAkB,2BAA0E;AAChH,QAAM,OAAO;AAAA,IACT,MAAM;AAAA,IACN,GAAG,qBAAqB,QAAQ,yBAAyB;AAAA,EAC7D;AAGA,cAAY,QAAQ,GAAG;AAGvB,SAAO;AACX;AAQA,SAAS,eAAe,QAAkB,2BAA0E;AAChH,QAAM,OAAO;AAAA,IACT,MAAM;AAAA,IACN,GAAG,qBAAqB,QAAQ,yBAAyB;AAAA,EAC7D;AAGA,cAAY,QAAQ,GAAG;AAGvB,SAAO;AACX;AAQA,SAAS,iBACL,QACA,2BACoB;AACpB,MAAI,OAAO,EAAE,MAAM,SAAS;AAG5B,QAAM,gBAAgB,oBAAoB,QAAQ,yBAAyB;AAM3E,MAAI,cAAc,QAAQ;AAEtB,kBACK,OAAO,CAAC,QAAQ,IAAI,SAAS,YAAY,CAAC,IAAI,SAAS,EACvD,QAAQ,MAAM;AACX,YAAM,IAAI,MAAM,qDAAqD;AAAA,IACzE,CAAC;AAGL,QAAI,cAAc,WAAW,GAAG;AAE5B,WAAK,aAAa,cAAc,GAAG;AAAA,IACvC,WAAW,cAAc,WAAW,GAAG;AAEnC,WAAK,aAAa,CAAC,cAAc,GAAG,OAAiB,cAAc,GAAG,KAAe;AAAA,IACzF,OAAO;AAEH,YAAM,IAAI,MAAM,iEAAiE;AAAA,IACrF;AAAA,EACJ;AAGA,SAAO,EAAE,GAAG,MAAM,GAAG,qBAAqB,QAAQ,yBAAyB,EAAE;AAG7E,cAAY,QAAQ,GAAG;AAGvB,SAAO;AACX;AAQA,SAAS,gBAAgB,QAAkB,2BAA2E;AAClH,MAAI,OAAO,EAAE,MAAM,QAAQ;AAG3B,QAAM,gBAAgB,oBAAoB,QAAQ,yBAAyB;AAM3E,MAAI,cAAc,QAAQ;AAEtB,kBACK,OAAO,CAAC,QAAQ,IAAI,SAAS,YAAY,CAAC,IAAI,SAAS,EACvD,QAAQ,MAAM;AACX,YAAM,IAAI,MAAM,kDAAkD;AAAA,IACtE,CAAC;AAGL,QAAI,cAAc,WAAW,GAAG;AAE5B,WAAK,WAAW,cAAc,GAAG;AAAA,IACrC,WAAW,cAAc,WAAW,GAAG;AAEnC,WAAK,WAAW,CAAC,cAAc,GAAG,OAAiB,cAAc,GAAG,KAAe;AAAA,IACvF,OAAO;AAEH,YAAM,IAAI,MAAM,8DAA8D;AAAA,IAClF;AAAA,EACJ;AAGA,SAAO,EAAE,GAAG,MAAM,GAAG,qBAAqB,QAAQ,yBAAyB,EAAE;AAG7E,cAAY,QAAQ,GAAG;AAGvB,SAAO;AACX;AAQA,SAAS,mBACL,QACA,2BACsB;AACtB,QAAM,OAAO;AAAA,IACT,MAAM;AAAA,IACN,GAAG,qBAAqB,QAAQ,yBAAyB;AAAA,EAC7D;AAGA,cAAY,QAAQ,GAAG;AAGvB,SAAO;AACX;AAQA,SAAS,mBACL,QACA,2BACsB;AACtB,QAAM,OAAO;AAAA,IACT,MAAM;AAAA,IACN,GAAG,qBAAqB,QAAQ,yBAAyB;AAAA,EAC7D;AAGA,cAAY,QAAQ,GAAG;AAGvB,SAAO;AACX;AAQA,SAAS,mBACL,QACA,2BACsB;AACtB,QAAM,OAAO;AAAA,IACT,MAAM;AAAA,IACN,GAAG,qBAAqB,QAAQ,yBAAyB;AAAA,EAC7D;AAGA,cAAY,QAAQ,GAAG;AAGvB,SAAO;AACX;AAQA,SAAS,gBAAgB,QAAkB,2BAA2E;AAElH,QAAM,gBAAgB,oBAAoB,QAAQ,yBAAyB;AAG3E,gBACK,OAAO,CAAC,QAAQ,IAAI,SAAS,YAAY,CAAC,IAAI,SAAS,EACvD,QAAQ,MAAM;AACX,UAAM,IAAI,MAAM,oDAAoD;AAAA,EACxE,CAAC;AAEL,QAAM,OAAO;AAAA,IACT,MAAM;AAAA,IACN,SAAS,cAAc,IAAI,CAAC,EAAE,MAAM,MAAM,KAAK;AAAA,IAC/C,GAAG,qBAAqB,QAAQ,yBAAyB;AAAA,EAC7D;AAGA,cAAY,QAAQ,GAAG;AAGvB,SAAO;AACX;AAQA,SAAS,iBACL,QACA,2BACoB;AAGpB,QAAM,CAAC,yBAAyB,iBAAiB,IAAI,oBAAoB,QAAQ,yBAAyB;AAG1G,MAAI,sBAAsB,SAAS,cAAc;AAC7C,UAAM,IAAI,MAAM,0CAA0C;AAAA,EAC9D;AAGA,oBACK,OAAO,CAAC,QAAQ,IAAI,SAAS,YAAY,EACzC,QAAQ,CAAC,QAAQ;AACd,UAAM,IAAI;AAAA,MACN,uCAAuC,IAAI;AAAA,IAC/C;AAAA,EACJ,CAAC;AAGL,SAAO;AAAA,IACH,MAAM;AAAA,IACN,MAAM,qBAAqB;AAAA,IAC3B,MAAM,kBAAkB,IAAI,CAAC,EAAE,MAAM,MAAM,KAAK;AAAA,IAChD,GAAG,qBAAqB,QAAQ,yBAAyB;AAAA,EAC7D;AACJ;AAQA,SAAS,oBACL,QACA,2BACuB;AAGvB,QAAM,CAAC,4BAA4B,iBAAiB,IAAI,oBAAoB,QAAQ,yBAAyB;AAG7G,MAAI,yBAAyB,SAAS,cAAc;AAChD,UAAM,IAAI,MAAM,6CAA6C;AAAA,EACjE;AAGA,oBACK,OAAO,CAAC,QAAQ,IAAI,SAAS,YAAY,EACzC,QAAQ,CAAC,QAAQ;AACd,UAAM,IAAI;AAAA,MACN,0CAA0C,IAAI;AAAA,IAClD;AAAA,EACJ,CAAC;AAGL,SAAO;AAAA,IACH,MAAM;AAAA,IACN,MAAM,wBAAwB;AAAA,IAC9B,MAAM,kBAAkB,IAAI,CAAC,EAAE,MAAM,MAAM,KAAK;AAAA,IAChD,GAAG,qBAAqB,QAAQ,yBAAyB;AAAA,EAC7D;AACJ;AAQA,SAAS,eAAe,QAAkB,2BAA0E;AAChH,MAAI,OAAO,EAAE,MAAM,OAAO;AAG1B,QAAM,gBAAgB,oBAAoB,QAAQ,yBAAyB;AAM3E,MAAI,cAAc,QAAQ;AAEtB,kBACK,OAAO,CAAC,QAAQ,IAAI,SAAS,YAAY,CAAC,IAAI,SAAS,EACvD,QAAQ,MAAM;AACX,YAAM,IAAI,MAAM,qDAAqD;AAAA,IACzE,CAAC;AAML,QAAI,cAAc,WAAW,GAAG;AAE5B,WAAK,WAAW,cAAc,GAAG;AAAA,IACrC,WAAW,cAAc,WAAW,GAAG;AAEnC,WAAK,WAAW,CAAC,cAAc,GAAG,OAAiB,cAAc,GAAG,KAAe;AAAA,IACvF,WAAW,cAAc,SAAS,GAAG;AAEjC,YAAM,IAAI,MAAM,wDAAwD;AAAA,IAC5E;AAAA,EACJ;AAGA,SAAO,EAAE,GAAG,MAAM,GAAG,qBAAqB,QAAQ,yBAAyB,EAAE;AACjF;AAQA,SAAS,iBACL,QACA,2BACoB;AAEpB,QAAM,gBAAgB,oBAAoB,QAAQ,yBAAyB;AAG3E,MAAI,cAAc,WAAW,KAAK,cAAc,GAAG,SAAS,cAAc;AACtE,UAAM,IAAI,MAAM,sCAAsC;AAAA,EAC1D;AAGA,SAAO,EAAE,MAAM,UAAU,KAAK,cAAc,GAAG,MAAM;AACzD;;;AC3nBO,SAAS,mBAAmB,YAA6C;AAE5E,MAAI,eAAe,QAAQ,OAAO,eAAe,aAAa;AAC1D,WAAO,8BAA8B,iCAAiC;AAAA,EAC1E;AAMA,MAAI,OAAO,eAAe,UAAU;AAEhC,WAAO,uBAAuB,UAAU;AAAA,EAC5C,WAAW,OAAO,eAAe,UAAU;AAEvC,WAAO,uBAAuB,UAAU;AAAA,EAC5C,OAAO;AACH,WAAO,8BAA8B,kCAAkC,OAAO,aAAa;AAAA,EAC/F;AACJ;AAOO,SAAS,uBAAuB,YAAgD;AACnF,MAAI;AAGJ,MAAI;AAEA,0BAAsB,kBAAkB,UAAU;AAAA,EACtD,SAAS,OAAP;AAEE,WAAO,8BAA8B,iBAAiB,OAAO;AAAA,EACjE;AAGA,QAAM,0BAA0B,oBAAoB,OAAO,CAAC,EAAE,GAAG,MAAM,OAAO,OAAO,WAAW;AAChG,QAAM,yBAAyB,oBAAoB,OAAO,CAAC,EAAE,GAAG,MAAM,OAAO,OAAO,YAAY,GAAG,SAAS,CAAC;AAG7G,MAAI,wBAAwB,WAAW,GAAG;AACtC,WAAO;AAAA,MACH;AAAA,IACJ;AAAA,EACJ;AAGA,QAAM,yBAAmC,CAAC;AAC1C,aAAW,EAAE,GAAG,KAAK,wBAAwB;AAEzC,QAAI,uBAAuB,SAAS,EAAG,GAAG;AACtC,aAAO,8BAA8B,kDAAkD,KAAK;AAAA,IAChG;AAEA,2BAAuB,KAAK,EAAG;AAAA,EACnC;AAEA,MAAI;AAEA,+BAA2B,qBAAqB,KAAK;AAAA,EACzD,SAAS,WAAP;AACE,WAAO,8BAA+B,UAAoB,OAAO;AAAA,EACrE;AAGA,SAAO,EAAE,WAAW,KAAK;AAC7B;AAOO,SAAS,uBACZ,YAC0B;AAE1B,QAAM,sBAAsB,MAAM,QAAQ,UAAU,IAAI,aAAa,CAAC,UAAU;AAGhF,MAAI;AACA,wBAAoB,QAAQ,CAAC,uBAAuB,aAAa,oBAAoB,CAAC,CAAC;AAAA,EAC3F,SAAS,OAAP;AAEE,QAAI,iBAAiB,OAAO;AACxB,aAAO,8BAA8B,MAAM,OAAO;AAAA,IACtD;AAGA,WAAO,8BAA8B,qBAAqB,OAAO;AAAA,EACrE;AAGA,QAAM,0BAA0B,oBAAoB,OAAO,CAAC,EAAE,GAAG,MAAM,OAAO,OAAO,WAAW;AAChG,QAAM,yBAAyB,oBAAoB,OAAO,CAAC,EAAE,GAAG,MAAM,OAAO,OAAO,YAAY,GAAG,SAAS,CAAC;AAG7G,MAAI,wBAAwB,WAAW,GAAG;AACtC,WAAO;AAAA,MACH;AAAA,IACJ;AAAA,EACJ;AAGA,QAAM,yBAAmC,CAAC;AAC1C,aAAW,EAAE,GAAG,KAAK,wBAAwB;AAEzC,QAAI,uBAAuB,SAAS,EAAG,GAAG;AACtC,aAAO;AAAA,QACH,oEAAoE;AAAA,MACxE;AAAA,IACJ;AAEA,2BAAuB,KAAK,EAAG;AAAA,EACnC;AAEA,MAAI;AAEA,+BAA2B,qBAAqB,KAAK;AAAA,EACzD,SAAS,WAAP;AACE,WAAO,8BAA+B,UAAoB,OAAO;AAAA,EACrE;AAGA,SAAO,EAAE,WAAW,KAAK;AAC7B;AASO,SAAS,2BAA2B,qBAA2C,wBAAiC;AAInH,QAAM,mBAAiE,oBAAoB;AAAA,IACvF,CAAC,wBAAwB;AAAA,MACrB,IAAI,mBAAmB;AAAA,MACvB,MAAM,kBAAkB,kBAAkB,EACrC,OAAO,YAAY,EACnB,IAAI,CAAC,EAAE,IAAI,MAAM,GAAG;AAAA,IAC7B;AAAA,EACJ;AAGA,QAAM,aAAa,CAAC,SAAqD,OAA+B,CAAC,MAAM;AAE3G,QAAI,KAAK,SAAS,QAAQ,EAAE,GAAG;AAE3B,YAAM,UAAU,CAAC,GAAG,MAAM,QAAQ,EAAE;AAGpC,YAAM,mBAAmB,QAAQ,OAAO,CAAC,YAAY,CAAC,CAAC,OAAO,EAAE,KAAK,MAAM;AAG3E,YAAM,IAAI,MAAM,wDAAwD,kBAAkB;AAAA,IAC9F;AAEA,eAAW,OAAO,QAAQ,MAAM;AAE5B,YAAM,aAAa,iBAAiB,KAAK,CAAC,EAAE,GAAG,MAAM,OAAO,GAAG;AAG/D,UAAI,YAAY;AACZ,mBAAW,YAAY,CAAC,GAAG,MAAM,QAAQ,EAAE,CAAC;AAAA,MAChD,WAAW,wBAAwB;AAE/B,cAAM,IAAI;AAAA,UACN,QAAQ,KACF,YAAY,QAAQ,kDAAkD,oCACtE,2DAA2D;AAAA,QACrE;AAAA,MACJ;AAAA,IACJ;AAAA,EACJ;AAGA,aAAW,iBAAiB,KAAK,CAAC,YAAY,OAAO,QAAQ,OAAO,WAAW,CAAE;AACrF;AAOA,SAAS,aAAa,YAAiB,OAAqB;AAExD,MAAI,OAAO,eAAe,YAAY,OAAO,WAAW,SAAS,YAAY,WAAW,KAAK,WAAW,GAAG;AACvG,UAAM,IAAI;AAAA,MACN,2FAA2F;AAAA,IAC/F;AAAA,EACJ;AAGA,UAAQ,WAAW,MAAM;AAAA,IACrB,KAAK;AACD,yBAAmB,YAAY,KAAK;AACpC;AAAA,IAEJ,KAAK;AACD,4BAAsB,YAAY,KAAK;AACvC;AAAA,IAEJ,KAAK;AACD,uBAAiB,YAAY,KAAK;AAClC;AAAA,IAEJ,KAAK;AACD,yBAAmB,YAAY,KAAK;AACpC;AAAA,IAEJ,KAAK;AACD,uBAAiB,YAAY,KAAK;AAClC;AAAA,IAEJ,KAAK;AACD,0BAAoB,YAAY,KAAK;AACrC;AAAA,IAEJ,KAAK;AACD,uBAAiB,YAAY,KAAK;AAClC;AAAA,IAEJ,KAAK;AACD,uBAAiB,YAAY,KAAK;AAClC;AAAA,IAEJ,KAAK;AACD,yBAAmB,YAAY,KAAK;AACpC;AAAA,IAEJ,KAAK;AACD,wBAAkB,YAAY,KAAK;AACnC;AAAA,IAEJ,KAAK;AACD,2BAAqB,YAAY,KAAK;AACtC;AAAA,IAEJ,KAAK;AACD,2BAAqB,YAAY,KAAK;AACtC;AAAA,IAEJ,KAAK;AACD,2BAAqB,YAAY,KAAK;AACtC;AAAA,IAEJ;AACI,YAAM,IAAI,MAAM,4BAA4B,WAAW,mBAAmB,QAAQ;AAAA,EAC1F;AACJ;AAOA,SAAS,uBAAuB,YAAiB,OAAqB;AAElE,GAAC,SAAS,SAAS,SAAS,QAAQ,MAAM,EAAE,QAAQ,CAAC,kBAAkB;AAEnE,UAAM,sBAAsB,WAAW;AAGvC,QAAI,OAAO,wBAAwB,aAAa;AAC5C;AAAA,IACJ;AAGA,QAAI,OAAO,wBAAwB,UAAU;AACzC,YAAM,IAAI;AAAA,QACN,uBAAuB,uCAAuC,WAAW,wBAAwB;AAAA,MACrG;AAAA,IACJ;AAGA,QAAI,OAAO,oBAAoB,SAAS,YAAY,oBAAoB,KAAK,WAAW,GAAG;AACvF,YAAM,IAAI;AAAA,QACN,2CAA2C,gDAAgD,WAAW,wBAAwB;AAAA,MAClI;AAAA,IACJ;AAGA,QAAI,OAAO,oBAAoB,SAAS,eAAe,CAAC,MAAM,QAAQ,oBAAoB,IAAI,GAAG;AAC7F,YAAM,IAAI;AAAA,QACN,2CAA2C,sCAAsC,WAAW,wBAAwB;AAAA,MACxH;AAAA,IACJ;AAAA,EACJ,CAAC;AACL;AAOA,SAAS,iBAAiB,YAAiB,OAAqB;AAE5D,MAAI,WAAW,SAAS,QAAQ;AAC5B,UAAM,IAAI,MAAM,4CAA4C;AAAA,EAChE;AAGA,MAAI,QAAQ,GAAG;AACX,UAAM,IAAI,MAAM,iDAAiD;AAAA,EACrE;AAGA,MAAI,OAAO,WAAW,OAAO,gBAAgB,OAAO,WAAW,OAAO,YAAY,WAAW,GAAG,WAAW,IAAI;AAC3G,UAAM,IAAI,MAAM,sEAAsE;AAAA,EAC1F;AAGA,MAAI,OAAO,WAAW,UAAU,aAAa;AACzC,UAAM,IAAI,MAAM,uDAAuD;AAAA,EAC3E;AAGA,yBAAuB,YAAY,KAAK;AAGxC,eAAa,WAAW,OAAO,QAAQ,CAAC;AAC5C;AAOA,SAAS,oBAAoB,YAAiB,OAAqB;AAE/D,MAAI,WAAW,SAAS,WAAW;AAC/B,UAAM,IAAI,MAAM,8DAA8D,QAAQ;AAAA,EAC1F;AAGA,MAAI,OAAO,WAAW,UAAU,aAAa;AACzC,UAAM,IAAI,MAAM,sEAAsE,QAAQ;AAAA,EAClG;AAGA,yBAAuB,YAAY,KAAK;AAGxC,eAAa,WAAW,OAAO,QAAQ,CAAC;AAC5C;AAOA,SAAS,iBAAiB,YAAiB,OAAqB;AAE5D,MAAI,WAAW,SAAS,QAAQ;AAC5B,UAAM,IAAI,MAAM,wDAAwD,QAAQ;AAAA,EACpF;AAGA,MAAI,OAAO,WAAW,UAAU,aAAa;AACzC,UAAM,IAAI,MAAM,mEAAmE,QAAQ;AAAA,EAC/F;AAGA,yBAAuB,YAAY,KAAK;AAGxC,eAAa,WAAW,OAAO,QAAQ,CAAC;AAC5C;AAOA,SAAS,iBAAiB,YAAiB,OAAqB;AAE5D,MAAI,WAAW,SAAS,QAAQ;AAC5B,UAAM,IAAI,MAAM,wDAAwD,QAAQ;AAAA,EACpF;AAGA,MAAI,OAAO,WAAW,UAAU,aAAa;AACzC,UAAM,IAAI,MAAM,mEAAmE,QAAQ;AAAA,EAC/F;AAGA,yBAAuB,YAAY,KAAK;AAGxC,eAAa,WAAW,OAAO,QAAQ,CAAC;AAC5C;AAOA,SAAS,mBAAmB,YAAiB,OAAqB;AAE9D,MAAI,WAAW,SAAS,UAAU;AAC9B,UAAM,IAAI,MAAM,4DAA4D,QAAQ;AAAA,EACxF;AAGA,MAAI,OAAO,WAAW,UAAU,aAAa;AACzC,UAAM,IAAI,MAAM,qEAAqE,QAAQ;AAAA,EACjG;AAGA,MAAI,OAAO,WAAW,eAAe,aAAa;AAC9C,QAAI,MAAM,QAAQ,WAAW,UAAU,GAAG;AAEtC,YAAM,qBAAqB,CAAC,CAAC,WAAW,WAAW,KAAK,CAAC,UAAmB,CAAC,UAAU,KAAK,CAAC;AAG7F,UAAI,WAAW,WAAW,WAAW,KAAK,oBAAoB;AAC1D,cAAM,IAAI;AAAA,UACN,+GAA+G;AAAA,QACnH;AAAA,MACJ;AAAA,IACJ,WAAW,CAAC,UAAU,WAAW,UAAU,GAAG;AAC1C,YAAM,IAAI;AAAA,QACN,gIAAgI;AAAA,MACpI;AAAA,IACJ;AAAA,EACJ;AAGA,yBAAuB,YAAY,KAAK;AAGxC,eAAa,WAAW,OAAO,QAAQ,CAAC;AAC5C;AAOA,SAAS,kBAAkB,YAAiB,OAAqB;AAE7D,MAAI,WAAW,SAAS,SAAS;AAC7B,UAAM,IAAI,MAAM,0DAA0D,QAAQ;AAAA,EACtF;AAGA,MAAI,OAAO,WAAW,UAAU,aAAa;AACzC,UAAM,IAAI,MAAM,oEAAoE,QAAQ;AAAA,EAChG;AAGA,MAAI,OAAO,WAAW,aAAa,aAAa;AAC5C,QAAI,MAAM,QAAQ,WAAW,QAAQ,GAAG;AAEpC,YAAM,qBAAqB,CAAC,CAAC,WAAW,SAAS,KAAK,CAAC,UAAmB,CAAC,UAAU,KAAK,CAAC;AAG3F,UAAI,WAAW,SAAS,WAAW,KAAK,oBAAoB;AACxD,cAAM,IAAI;AAAA,UACN,4GAA4G;AAAA,QAChH;AAAA,MACJ;AAAA,IACJ,WAAW,CAAC,UAAU,WAAW,QAAQ,GAAG;AACxC,YAAM,IAAI;AAAA,QACN,6HAA6H;AAAA,MACjI;AAAA,IACJ;AAAA,EACJ;AAGA,yBAAuB,YAAY,KAAK;AAGxC,eAAa,WAAW,OAAO,QAAQ,CAAC;AAC5C;AAOA,SAAS,mBAAmB,YAAiB,OAAqB;AAE9D,MAAI,WAAW,SAAS,UAAU;AAC9B,UAAM,IAAI,MAAM,4DAA4D,QAAQ;AAAA,EACxF;AAGA,MAAI,OAAO,WAAW,QAAQ,YAAY,WAAW,IAAI,WAAW,GAAG;AACnE,UAAM,IAAI,MAAM,0EAA0E,QAAQ;AAAA,EACtG;AAGA,GAAC,SAAS,OAAO,EAAE,QAAQ,CAAC,kBAAkB;AAC1C,QAAI,OAAO,WAAW,mBAAmB,aAAa;AAClD,YAAM,IAAI;AAAA,QACN,4DAA4D,wDAAwD;AAAA,MACxH;AAAA,IACJ;AAAA,EACJ,CAAC;AAGD,GAAC,SAAS,QAAQ,MAAM,EAAE,QAAQ,CAAC,kBAAkB;AACjD,QAAI,OAAO,WAAW,mBAAmB,aAAa;AAClD,YAAM,IAAI;AAAA,QACN,kEAAkE,wDAAwD;AAAA,MAC9H;AAAA,IACJ;AAAA,EACJ,CAAC;AACL;AAOA,SAAS,mBAAmB,YAAiB,OAAqB;AAE9D,MAAI,WAAW,SAAS,UAAU;AAC9B,UAAM,IAAI,MAAM,4DAA4D,QAAQ;AAAA,EACxF;AAGA,MAAI,OAAO,WAAW,SAAS,YAAY,WAAW,KAAK,WAAW,GAAG;AACrE,UAAM,IAAI,MAAM,0EAA0E,QAAQ;AAAA,EACtG;AAGA,MAAI,OAAO,WAAW,SAAS,eAAe,CAAC,MAAM,QAAQ,WAAW,IAAI,GAAG;AAC3E,UAAM,IAAI,MAAM,2EAA2E,QAAQ;AAAA,EACvG;AAGA,yBAAuB,YAAY,KAAK;AAC5C;AAOA,SAAS,sBAAsB,YAAiB,OAAqB;AAEjE,MAAI,WAAW,SAAS,aAAa;AACjC,UAAM,IAAI,MAAM,kEAAkE,QAAQ;AAAA,EAC9F;AAGA,MAAI,OAAO,WAAW,SAAS,YAAY,WAAW,KAAK,WAAW,GAAG;AACrE,UAAM,IAAI,MAAM,6EAA6E,QAAQ;AAAA,EACzG;AAGA,MAAI,OAAO,WAAW,SAAS,eAAe,CAAC,MAAM,QAAQ,WAAW,IAAI,GAAG;AAC3E,UAAM,IAAI,MAAM,8EAA8E,QAAQ;AAAA,EAC1G;AAGA,yBAAuB,YAAY,KAAK;AAC5C;AAOA,SAAS,iBAAiB,YAAiB,OAAqB;AAE5D,MAAI,WAAW,SAAS,QAAQ;AAC5B,UAAM,IAAI,MAAM,wDAAwD,QAAQ;AAAA,EACpF;AAGA,MAAI,OAAO,WAAW,aAAa,aAAa;AAC5C,QAAI,MAAM,QAAQ,WAAW,QAAQ,GAAG;AAEpC,YAAM,qBAAqB,CAAC,CAAC,WAAW,SAAS,KAAK,CAAC,UAAmB,CAAC,UAAU,KAAK,CAAC;AAG3F,UAAI,WAAW,SAAS,WAAW,KAAK,oBAAoB;AACxD,cAAM,IAAI;AAAA,UACN,2GAA2G;AAAA,QAC/G;AAAA,MACJ;AAAA,IACJ,WAAW,CAAC,UAAU,WAAW,QAAQ,GAAG;AACxC,YAAM,IAAI;AAAA,QACN,4HAA4H;AAAA,MAChI;AAAA,IACJ;AAAA,EACJ;AAGA,yBAAuB,YAAY,KAAK;AAC5C;AAOA,SAAS,qBAAqB,YAAiB,OAAqB;AAEhE,MAAI,WAAW,SAAS,YAAY;AAChC,UAAM,IAAI,MAAM,gEAAgE,QAAQ;AAAA,EAC5F;AAGA,MAAI,CAAC,MAAM,QAAQ,WAAW,QAAQ,KAAK,WAAW,SAAS,WAAW,GAAG;AACzE,UAAM,IAAI,MAAM,iFAAiF,QAAQ;AAAA,EAC7G;AAGA,yBAAuB,YAAY,KAAK;AAGxC,aAAW,SAAS,QAAQ,CAAC,UAAe,aAAa,OAAO,QAAQ,CAAC,CAAC;AAC9E;AAOA,SAAS,qBAAqB,YAAiB,OAAqB;AAEhE,MAAI,WAAW,SAAS,YAAY;AAChC,UAAM,IAAI,MAAM,gEAAgE,QAAQ;AAAA,EAC5F;AAGA,MAAI,CAAC,MAAM,QAAQ,WAAW,QAAQ,KAAK,WAAW,SAAS,WAAW,GAAG;AACzE,UAAM,IAAI,MAAM,iFAAiF,QAAQ;AAAA,EAC7G;AAGA,yBAAuB,YAAY,KAAK;AAGxC,aAAW,SAAS,QAAQ,CAAC,UAAe,aAAa,OAAO,QAAQ,CAAC,CAAC;AAC9E;AAOA,SAAS,qBAAqB,YAAiB,OAAqB;AAEhE,MAAI,WAAW,SAAS,YAAY;AAChC,UAAM,IAAI,MAAM,gEAAgE,QAAQ;AAAA,EAC5F;AAGA,MAAI,CAAC,MAAM,QAAQ,WAAW,QAAQ,KAAK,WAAW,SAAS,WAAW,GAAG;AACzE,UAAM,IAAI,MAAM,iFAAiF,QAAQ;AAAA,EAC7G;AAGA,yBAAuB,YAAY,KAAK;AAGxC,aAAW,SAAS,QAAQ,CAAC,UAAe,aAAa,OAAO,QAAQ,CAAC,CAAC;AAC9E;AAOA,SAAS,8BAA8B,cAAkD;AACrF,SAAO,EAAE,WAAW,OAAO,aAAa;AAC5C;;;ACrrBA,IAAqB,SAArB,MAA4B;AAAA,EAexB,OAAc,QAAQ,MAA8B;AAChD,WAAO,KAAK,cAAc;AAAA,EAC9B;AAAA,EAOA,OAAc,QAAQ,MAAc,MAA4B;AAC5D,SAAK,cAAc,QAAQ;AAAA,EAC/B;AAAA,EAUA,OAAO,eAAe,OAAc,MAAsC;AAEtE,UAAM,eAAe,MAAM;AAC3B,QAAI,gBAAgB,OAAO,iBAAiB,YAAY;AACpD,aAAO,CAAC,SAAwC,aAAa,MAAM,OAAO,IAAI;AAAA,IAClF;AAGA,QAAI,KAAK,cAAc,SAAS,OAAO,KAAK,cAAc,UAAU,YAAY;AAC5E,aAAO,CAAC,SAAgB,KAAK,cAAc,MAAM,OAAO,GAAG,KAAK,IAAI,CAAC,QAAQ,IAAI,KAAK,CAAC;AAAA,IAC3F;AAGA,WAAO;AAAA,EACX;AAAA,EAKA,OAAO,cAAqD;AACxD,WAAO,KAAK;AAAA,EAChB;AAAA,EAOA,OAAO,WAAW,MAAc,SAA6B;AACzD,SAAK,aAAa,QAAQ;AAAA,EAC9B;AAAA,EAMA,OAAO,OAAO,MAAc;AACxB,WAAO,KAAK,cAAc;AAC1B,WAAO,KAAK,aAAa;AAAA,EAC7B;AAAA,EAKA,OAAO,QAAQ;AACX,SAAK,gBAAgB,CAAC;AACtB,SAAK,eAAe,CAAC;AAAA,EACzB;AACJ;AAhFI,cAJiB,QAIF,iBAAmD,CAAC;AAInE,cARiB,QAQF,gBAAsD,CAAC;;;ACX1E,IAAqB,4BAArB,cAAuD,MAAM;AAAA,EAIzD,YAAoB,QAAc;AAC9B,UAAM,mCAAmC;AADzB;AAAA,EAEpB;AAAA,EAOA,eAAe,CAAC,SAAe,SAAS,KAAK;AACjD;;;ACNA,IAAqB,YAArB,MAA+B;AAAA,EAI3B,YAAoB,OAAwB;AAAxB;AAAA,EAAyB;AAAA,EAO7C,WAAW,CAAC,UAAiB;AAEzB,eAAW,WAAW,KAAK,OAAO;AAE9B,iBAAW,SAAS,QAAQ,QAAQ;AAEhC,YAAI,CAAC,MAAM,YAAY,KAAK,GAAG;AAC3B,gBAAM,IAAI,0BAA0B,QAAQ,IAAI;AAAA,QACpD;AAAA,MACJ;AAAA,IACJ;AAAA,EACJ;AACJ;;;ACrBA,IAA8B,OAA9B,MAAmC;AAAA,EAmB/B,YAAoB,MAAsB,YAAiC,MAAa;AAApE;AAAsB;AAAiC;AAAA,EAAc;AAAA,EAfxE,MAAc,cAAc;AAAA,EAIrC;AAAA,EAIA;AAAA,EA6BR,WAAW,MAAgB,KAAK;AAAA,EAChC,WAAW,CAAC,UAA0B;AAClC,SAAK,QAAQ;AAAA,EACjB;AAAA,EAKA,SAAS,MAAM,KAAK;AAAA,EAKpB,UAAU,MAAM,KAAK;AAAA,EAKrB,gBAAgB,MAAM,KAAK;AAAA,EAK3B,eAAe,MAAM,KAAK;AAAA,EAQ1B,aAAa,MAAyB;AAClC,WACI,KAAK,cAAc,EAAE,OAAO,CAAC,cAAc,UAAU,KAAK,YAAY,MAAM,KAAK,YAAY,CAAC,EAAE,MAAM;AAAA,EAE9G;AAAA,EAKA,qBAAqB,MAAe,KAAK,cAAc,EAAE,OAAO,CAAC,cAAc,UAAU,QAAQ,CAAC;AAAA,EAKlG,eAAe,CAAC,UAAsB,KAAK,YAAY;AAAA,EAKvD,eAAe,MAAM,CAAC,CAAC,KAAK;AAAA,EAMrB,GAAG,OAA0B;AAChC,WAAO,KAAK,UAAU;AAAA,EAC1B;AAAA,EAKO,QAAc;AACjB,SAAK,wCAAoB;AAAA,EAC7B;AAAA,EAMO,MAAM,OAAoB;AAE7B,QAAI,CAAC,KAAK,sCAAgB,GAAG;AACzB;AAAA,IACJ;AAGA,SAAK,MAAM;AAEX,SAAK,aAAa,MAAM,GAAG,kBAAkB,OAAO,OAAO,IAAI;AAAA,EACnE;AAAA,EAQO,OAAO,OAAc,SAAqC;AAE7D,QAAI,KAAK,0CAAkB,KAAK,KAAK,oCAAe,GAAG;AACnD;AAAA,IACJ;AAEA,QAAI;AAEA,WAAK,UAAW,SAAS,KAAK;AAG9B,UAAI,KAAK,kCAAc,GAAG;AACtB,aAAK,aAAa,OAAO,GAAG,kBAAkB,KAAK;AAAA,MACvD;AAEA,WAAK,aAAa,MAAM,GAAG,kBAAkB,KAAK;AAGlD,WAAK,SAAS,OAAO,OAAO;AAG5B,UAAI,KAAK,0CAAkB,KAAK,KAAK,oCAAe,GAAG;AACnD,aAAK,aAAa,MAAM,GAAG,kBAAkB,OAAO,KAAK,0CAAkB,GAAG,KAAK;AAAA,MACvF;AAAA,IACJ,SAAS,OAAP;AAEE,UAAI,iBAAiB,6BAA6B,MAAM,aAAa,IAAI,GAAG;AAExE,aAAK,MAAM,KAAK;AAGhB,aAAK,0CAAqB;AAAA,MAC9B,OAAO;AACH,cAAM;AAAA,MACV;AAAA,IACJ;AAAA,EACJ;AACJ;AAMA,SAAS,gBAAwB;AAC7B,MAAI,KAAK,WAAY;AACjB,aAAU,IAAI,KAAK,OAAO,KAAK,QAAW,GAAG,SAAS,EAAE,EAAE,UAAU,CAAC;AAAA,EACzE;AACA,SAAO,GAAG,IAAI,GAAG,IAAI,MAAM,GAAG,IAAI,MAAM,GAAG,IAAI,MAAM,GAAG,IAAI,MAAM,GAAG,IAAI,GAAG,IAAI,GAAG;AACvF;;;ACzLA,IAA8B,YAA9B,cAAgD,KAAK;AAAA,EAMjD,YAAY,MAAc,YAAmC,OAAa;AACtE,UAAM,MAAM,YAAY,CAAC,CAAC;AAD+B;AAAA,EAE7D;AAAA,EAKA,aAAa,MAAM;AAAA,EAKnB,cAAc,MAAM,CAAC,KAAK,KAAK;AAAA,EAK/B,QAAQ,MAAM;AAEV,SAAK,wCAAoB;AAGzB,SAAK,MAAM,MAAM;AAAA,EACrB;AAAA,EAMA,QAAQ,CAAC,UAAiB;AAEtB,QAAI,CAAC,KAAK,sCAAgB,GAAG;AACzB;AAAA,IACJ;AAGA,SAAK,MAAM,MAAM,KAAK;AAGtB,SAAK,MAAM;AAEX,SAAK,aAAa,MAAM,GAAG,kBAAkB,OAAO,OAAO,IAAI;AAAA,EACnE;AACJ;;;AC9CA,IAAqB,OAArB,cAAkC,UAAU;AAAA,EAKxC,YAAY,YAAyB,OAAa;AAC9C,UAAM,QAAQ,YAAY,KAAK;AAAA,EACnC;AAAA,EAOU,SAAS,OAAc,SAAqC;AAElE,QAAI,KAAK,MAAM,SAAS,yCAAqB,KAAK,MAAM,SAAS,2CAAqB;AAElF,WAAK,MAAM,OAAO,OAAO,OAAO;AAAA,IACpC;AAGA,SAAK,SAAS,KAAK,MAAM,SAAS,CAAC;AAAA,EACvC;AAAA,EAKA,UAAU,MAAM;AACpB;;;AC3BA,IAA8B,YAA9B,MAAuG;AAAA,EAKnG,YAAmB,MAAqB,MAAa;AAAlC;AAAqB;AAAA,EAAc;AAW1D;;;AClBA,IAA8B,QAA9B,cAA4C,UAAiC;AAAA,EAMzE,YAAY,MAAc,MAAqB,WAAmB;AAC9D,UAAM,MAAM,IAAI;AAD2B;AAAA,EAE/C;AAAA,EAKA,eAAe,MAAM,KAAK;AAAA,EAK1B,UAAU,MAAM;AAAA,EAKhB,aAAoC;AAChC,WAAO;AAAA,MACH,MAAM,KAAK;AAAA,MACX,MAAM,KAAK;AAAA,MACX,WAAW,KAAK,aAAa;AAAA,IACjC;AAAA,EACJ;AAQJ;;;ACzCA,IAAqB,QAArB,cAAmC,MAAM;AAAA,EAKrC,YAAY,WAAmB,MAAa;AACxC,UAAM,SAAS,MAAM,SAAS;AAAA,EAClC;AAAA,EAOA,cAAc,CAAC,UAAiB;AAE5B,UAAM,uBAAuB,OAAO,eAAe,OAAO,KAAK,aAAa,CAAC;AAG7E,QAAI,yBAAyB,MAAM;AAC/B,YAAM,IAAI;AAAA,QACN,gDAAgD,KAAK,aAAa;AAAA,MACtE;AAAA,IACJ;AAGA,WAAO,CAAC,CAAC,qBAAqB,KAAK,IAAI;AAAA,EAC3C;AACJ;;;AC5BA,IAAqB,QAArB,cAAmC,MAAM;AAAA,EAKrC,YAAY,WAAmB,MAAa;AACxC,UAAM,SAAS,MAAM,SAAS;AAAA,EAClC;AAAA,EAOA,cAAc,CAAC,UAAiB;AAE5B,UAAM,uBAAuB,OAAO,eAAe,OAAO,KAAK,aAAa,CAAC;AAG7E,QAAI,yBAAyB,MAAM;AAC/B,YAAM,IAAI;AAAA,QACN,gDAAgD,KAAK,aAAa;AAAA,MACtE;AAAA,IACJ;AAGA,WAAO,CAAC,CAAC,CAAC,qBAAqB,KAAK,IAAI;AAAA,EAC5C;AACJ;;;ACxBA,IAA8B,WAA9B,cAA+C,UAAoC;AAAA,EAM/E,YAAY,MAAc,MAAqB,cAAsB;AACjE,UAAM,MAAM,IAAI;AAD2B;AAAA,EAE/C;AAAA,EAKA,kBAAkB,MAAM,KAAK;AAAA,EAK7B,UAAU,MAAM;AAAA,EAKhB,aAAuC;AACnC,WAAO;AAAA,MACH,MAAM,KAAK;AAAA,MACX,MAAM,KAAK;AAAA,MACX,cAAc,KAAK,gBAAgB;AAAA,IACvC;AAAA,EACJ;AAOJ;;;ACxCA,IAAqB,QAArB,cAAmC,SAAS;AAAA,EAKxC,YAAY,cAAsB,MAAa;AAC3C,UAAM,SAAS,MAAM,YAAY;AAAA,EACrC;AAAA,EAMA,oBAAoB,CAAC,UAAiB;AAElC,UAAM,sBAAsB,OAAO,eAAe,OAAO,KAAK,gBAAgB,CAAC;AAG/E,QAAI,wBAAwB,MAAM;AAC9B,YAAM,IAAI;AAAA,QACN,+BAA+B,KAAK,gBAAgB;AAAA,MACxD;AAAA,IACJ;AAGA,wBAAoB,KAAK,IAAI;AAAA,EACjC;AACJ;;;AC3BA,IAAqB,OAArB,cAAkC,SAAS;AAAA,EAKvC,YAAY,cAAsB,MAAa;AAC3C,UAAM,QAAQ,MAAM,YAAY;AAAA,EACpC;AAAA,EAMA,oBAAoB,CAAC,UAAiB;AAElC,UAAM,sBAAsB,OAAO,eAAe,OAAO,KAAK,gBAAgB,CAAC;AAG/E,QAAI,wBAAwB,MAAM;AAC9B,YAAM,IAAI;AAAA,QACN,8BAA8B,KAAK,gBAAgB;AAAA,MACvD;AAAA,IACJ;AAGA,wBAAoB,KAAK,IAAI;AAAA,EACjC;AACJ;;;AC3BA,IAAqB,OAArB,cAAkC,SAAS;AAAA,EAKvC,YAAY,cAAsB,MAAa;AAC3C,UAAM,QAAQ,MAAM,YAAY;AAAA,EACpC;AAAA,EAQA,oBAAoB,CAAC,OAAc,WAAoB,cAAuB;AAE1E,UAAM,sBAAsB,OAAO,eAAe,OAAO,KAAK,gBAAgB,CAAC;AAG/E,QAAI,wBAAwB,MAAM;AAC9B,YAAM,IAAI;AAAA,QACN,8BAA8B,KAAK,gBAAgB;AAAA,MACvD;AAAA,IACJ;AAGA,wBAAoB,CAAC,EAAE,OAAO,EAAE,WAAW,WAAW,SAAS,UAAU,EAAE,GAAG,GAAG,KAAK,IAAI,CAAC;AAAA,EAC/F;AACJ;;;ACiBA,IAAM,qBAAqB,OAAO,UAAU;AAO7B,SAAR,cAA+B,YAAwC;AAE1E,QAAM,wBAAwB,4BAA4B,UAAU;AAKpE,6BAA2B,YAAY,IAAI;AAG3C,QAAM,WAAW,YAAY,sBAAsB,mBAAmB;AAGtE,0BAAwB,QAAQ;AAGhC,SAAO;AACX;AAOA,SAAS,YAAY,YAAwC;AAEzD,QAAM,aAAa,sBAAsB,UAAU;AAGnD,UAAQ,WAAW,MAAM;AAAA,IACrB,KAAK;AACD,aAAO,IAAI,KAAK,YAAY,YAAY,WAAW,KAAK,CAAC;AAAA,IAI7D;AACI,YAAM,IAAI,MAAM,4BAA4B,WAAW,OAAO;AAAA,EACtE;AACJ;AAOA,SAAS,sBAAsB,YAA4C;AACvE,QAAM,aAA0B,CAAC;AAEjC,MAAI,WAAW,OAAO;AAClB,eAAW,KAAK,IAAI,MAAM,WAAW,MAAM,MAAM,WAAW,MAAM,QAAQ,CAAC,CAAC,CAAC;AAAA,EACjF;AAEA,MAAI,WAAW,OAAO;AAClB,eAAW,KAAK,IAAI,MAAM,WAAW,MAAM,MAAM,WAAW,MAAM,QAAQ,CAAC,CAAC,CAAC;AAAA,EACjF;AAEA,MAAI,WAAW,OAAO;AAClB,eAAW,KAAK,IAAI,MAAM,WAAW,MAAM,MAAM,WAAW,MAAM,QAAQ,CAAC,CAAC,CAAC;AAAA,EACjF;AAEA,MAAI,WAAW,MAAM;AACjB,eAAW,KAAK,IAAI,KAAK,WAAW,KAAK,MAAM,WAAW,KAAK,QAAQ,CAAC,CAAC,CAAC;AAAA,EAC9E;AAEA,MAAI,WAAW,MAAM;AACjB,eAAW,KAAK,IAAI,KAAK,WAAW,KAAK,MAAM,WAAW,KAAK,QAAQ,CAAC,CAAC,CAAC;AAAA,EAC9E;AAEA,SAAO;AACX;AAOA,SAAS,4BAA4B,YAAyD;AAE1F,QAAM,cAAqC,CAAC;AAG5C,aAAW,CAAC,MAAM,kBAAkB,KAAK,OAAO,QAAQ,OAAO,YAAY,CAAC,GAAG;AAE3E,gBAAY,QAAQ,EAAE,GAAG,oBAAoB,IAAI,KAAK;AAAA,EAC1D;AAIA,aAAW,sBAAsB,YAAY;AACzC,gBAAY,mBAAmB,MAAM,sBAAsB;AAAA,EAC/D;AAEA,SAAO;AACX;AAMA,SAAS,wBAAwB,MAAY;AACzC,QAAM,YAAsB,CAAC;AAE7B,QAAM,gBAAgB,CAAC,MAAc,SAAe;AAEhD,WAAO,KAAK,OAAO,IAAI;AAGvB,QAAI,KAAK,WAAW,GAAG;AACnB,gBAAU,KAAK,IAAI;AAAA,IACvB,OAAO;AACH,MAAC,KAA+B,YAAY,EAAE,QAAQ,CAAC,UAAU,cAAc,MAAM,KAAK,CAAC;AAAA,IAC/F;AAAA,EACJ;AAGA,gBAAc,CAAC,GAAG,IAAI;AAEtB,YAAU,QAAQ,CAAC,SAAS;AAExB,aAAS,QAAQ,GAAG,QAAQ,KAAK,QAAQ,SAAS;AAE9C,YAAM,cAAc,KAAK;AAGzB,UAAI,YAAY,aAAa,GAAG;AAC5B;AAAA,MACJ;AAGA,YAAM,YAAY,IAAI;AAAA,QAClB,KACK,MAAM,GAAG,QAAQ,CAAC,EAClB,IAAmB,CAAC,UAAU,EAAE,MAAM,QAAQ,KAAK,mBAAmB,EAAE,EAAE,EAC1E,OAAO,CAAC,YAAY,QAAQ,OAAO,SAAS,CAAC;AAAA,MACtD;AAGA,kBAAY,aAAa,SAAS;AAAA,IACtC;AAAA,EACJ,CAAC;AACL;;;AC1KO,IAAM,gBAAN,MAAoB;AAAA,EAYvB,YACI,YACQ,OACA,UAAgC,CAAC,GAC3C;AAFU;AACA;AAGR,QAAI,CAAC,YAAY;AACb,YAAM,IAAI,MAAM,yCAAyC;AAAA,IAC7D;AAGA,QAAI,OAAO,UAAU,YAAY,UAAU,MAAM;AAC7C,YAAM,IAAI,MAAM,wCAAwC;AAAA,IAC5D;AAEA,QAAI;AAEA,WAAK,WAAW,KAAK,gBAAgB,UAAU;AAAA,IACnD,SAAS,WAAP;AAEE,YAAM,IAAI,MAAM,wBAAyB,UAAoB,SAAS;AAAA,IAC1E;AAAA,EACJ;AAAA,EA9BgB;AAAA,EAoChB,YAAY;AACR,WAAO,KAAK,SAAS,SAAS;AAAA,EAClC;AAAA,EAMA,WAAW;AACP,WAAO,KAAK,SAAS,SAAS;AAAA,EAClC;AAAA,EAUA,OAAO;AAEH,QAAI,KAAK,SAAS,SAAS,iDAAyB,KAAK,SAAS,SAAS,yCAAoB;AAC3F,WAAK,SAAS,MAAM;AAAA,IACxB;AAEA,QAAI;AACA,WAAK,SAAS,OAAO,KAAK,OAAO,KAAK,OAAO;AAAA,IACjD,SAAS,WAAP;AACE,YAAM,IAAI,MAAM,wBAAyB,UAAoB,SAAS;AAAA,IAC1E;AAAA,EACJ;AAAA,EAKA,QAAQ;AACJ,SAAK,SAAS,MAAM;AAAA,EACxB;AAAA,EAMA,0BAA+C;AAE3C,UAAM,qBAA0C,CAAC;AAOjD,UAAM,cAAc,CAAC,MAAY,cAA6B;AAE1D,YAAM,SAAS,KACV,cAAc,EACd,OAAO,CAAC,cAAc,UAAU,QAAQ,CAAC,EACzC,IAAI,CAAC,cAAc,UAAU,WAAW,CAAC;AAC9C,YAAM,YAAY,KACb,cAAc,EACd,OAAO,CAAC,cAAc,CAAC,UAAU,QAAQ,CAAC,EAC1C,IAAI,CAAC,cAAc,UAAU,WAAW,CAAC;AAG9C,yBAAmB,KAAK;AAAA,QACpB,IAAI,KAAK,OAAO;AAAA,QAChB,MAAM,KAAK,QAAQ;AAAA,QACnB,SAAS,KAAK,QAAQ;AAAA,QACtB,OAAO,KAAK,SAAS;AAAA,QACrB;AAAA,QACA;AAAA,QACA,MAAM,KAAK,aAAa;AAAA,QACxB,UAAU;AAAA,MACd,CAAC;AAGD,UAAI,CAAC,KAAK,WAAW,GAAG;AACpB,QAAC,KACI,YAAY,EACZ,QAAQ,CAAC,UAAU,YAAY,OAAQ,KAA+B,OAAO,CAAC,CAAC;AAAA,MACxF;AAAA,IACJ;AAGA,gBAAY,KAAK,UAAU,IAAI;AAE/B,WAAO;AAAA,EACX;AAAA,EAOA,OAAO,SAAS,MAAc,OAAqD;AAE/E,QAAI,OAAO,UAAU,YAAY;AAC7B,aAAO,QAAQ,MAAM,KAAK;AAC1B;AAAA,IACJ;AAGA,QAAI,OAAO,UAAU,UAAU;AAC3B,UAAI;AAGJ,UAAI;AACA,8BAAsB,kBAAkB,KAAK;AAAA,MACjD,SAAS,WAAP;AACE,cAAM,IAAI,MAAM,+CAAgD,UAAoB,SAAS;AAAA,MACjG;AAGA,UAAI,oBAAoB,UAAU,KAAK,oBAAoB,GAAG,OAAO,MAAM;AACvE,cAAM,IAAI,MAAM,mEAAmE;AAAA,MACvF;AAEA,UAAI;AAEA,cAAM,EAAE,WAAW,aAAa,IAAI,uBAAuB,oBAAoB,EAAE;AAGjF,YAAI,CAAC,WAAW;AACZ,gBAAM,IAAI,MAAM,YAAY;AAAA,QAChC;AAAA,MACJ,SAAS,WAAP;AACE,cAAM,IAAI,MAAM,iCAAkC,UAAoB,SAAS;AAAA,MACnF;AAGA,aAAO,WAAW,MAAM,oBAAoB,EAAE;AAAA,IAClD,WAAW,OAAO,UAAU,YAAY,CAAC,MAAM,QAAQ,KAAK,GAAG;AAG3D,UAAI;AAEA,cAAM,EAAE,WAAW,aAAa,IAAI,uBAAuB,KAAK;AAGhE,YAAI,CAAC,WAAW;AACZ,gBAAM,IAAI,MAAM,YAAY;AAAA,QAChC;AAAA,MACJ,SAAS,WAAP;AACE,cAAM,IAAI,MAAM,iCAAkC,UAAoB,SAAS;AAAA,MACnF;AAGA,aAAO,WAAW,MAAM,KAAK;AAAA,IACjC,OAAO;AACH,YAAM,IAAI,MAAM,0FAA0F;AAAA,IAC9G;AAAA,EACJ;AAAA,EAMA,OAAO,WAAW,MAAoB;AAClC,WAAO,OAAO,IAAI;AAAA,EACtB;AAAA,EAKA,OAAO,gBAAsB;AACzB,WAAO,MAAM;AAAA,EACjB;AAAA,EAOQ,gBAAgB,YAAsE;AAC1F,QAAI;AAGJ,QAAI,OAAO,eAAe,UAAU;AAChC,UAAI;AACA,6BAAqB,kBAAkB,UAAU;AAAA,MACrD,SAAS,WAAP;AACE,cAAM,IAAI,MAAM,4BAA6B,UAAoB,SAAS;AAAA,MAC9E;AAAA,IACJ,OAAO;AAEH,2BAAqB;AAAA,IACzB;AAGA,WAAO,cAAc,MAAM,QAAQ,kBAAkB,IAAI,qBAAqB,CAAC,kBAAkB,CAAC;AAAA,EACtG;AACJ;", - "names": ["State"] + "sources": ["../node_modules/lotto-draw/dist/Participant.js", "../node_modules/lotto-draw/dist/Utilities.js", "../node_modules/lotto-draw/dist/Lotto.js", "../node_modules/lotto-draw/dist/createLotto.js", "../node_modules/lotto-draw/dist/index.js", "../src/index.ts", "../src/State.ts", "../src/BehaviourTreeDefinitionUtilities.ts", "../src/mdsl/MDSLUtilities.ts", "../src/mdsl/MDSLNodeArgumentParser.ts", "../src/mdsl/MDSLNodeAttributeParser.ts", "../src/mdsl/MDSLDefinitionParser.ts", "../src/BehaviourTreeDefinitionValidator.ts", "../src/Lookup.ts", "../src/attributes/guards/GuardUnsatisifedException.ts", "../src/attributes/guards/GuardPath.ts", "../src/nodes/Node.ts", "../src/nodes/composite/Composite.ts", "../src/nodes/composite/Parallel.ts", "../src/nodes/composite/Selector.ts", "../src/nodes/composite/Sequence.ts", "../src/nodes/composite/Lotto.ts", "../src/nodes/decorator/Decorator.ts", "../src/nodes/decorator/Fail.ts", "../src/nodes/decorator/Flip.ts", "../src/nodes/decorator/Repeat.ts", "../src/nodes/decorator/Retry.ts", "../src/nodes/decorator/Root.ts", "../src/nodes/decorator/Succeed.ts", "../src/nodes/leaf/Leaf.ts", "../src/nodes/leaf/Action.ts", "../src/nodes/leaf/Condition.ts", "../src/nodes/leaf/Wait.ts", "../src/attributes/Attribute.ts", "../src/attributes/guards/Guard.ts", "../src/attributes/guards/While.ts", "../src/attributes/guards/Until.ts", "../src/attributes/callbacks/Callback.ts", "../src/attributes/callbacks/Entry.ts", "../src/attributes/callbacks/Step.ts", "../src/attributes/callbacks/Exit.ts", "../src/BehaviourTreeBuilder.ts", "../src/BehaviourTree.ts"], + "sourcesContent": ["\"use strict\";\r\nObject.defineProperty(exports, \"__esModule\", { value: true });\r\nexports.Participant = void 0;\r\n/**\r\n * A participant that holds a number of tickets.\r\n */\r\nvar Participant = /** @class */ (function () {\r\n /**\r\n * Creates an instance of the Participant class.\r\n * @param participant The actual participant.\r\n * @param tickets The number of tickets held by the participant.\r\n */\r\n function Participant(participant, tickets) {\r\n if (tickets === void 0) { tickets = 1; }\r\n this._participant = participant;\r\n this._tickets = tickets;\r\n }\r\n Object.defineProperty(Participant.prototype, \"participant\", {\r\n /** Gets the actual participant. */\r\n get: function () {\r\n return this._participant;\r\n },\r\n enumerable: false,\r\n configurable: true\r\n });\r\n Object.defineProperty(Participant.prototype, \"tickets\", {\r\n /** Gets or sets the number of tickets held by the participant. */\r\n get: function () {\r\n return this._tickets;\r\n },\r\n set: function (value) {\r\n this._tickets = value;\r\n },\r\n enumerable: false,\r\n configurable: true\r\n });\r\n return Participant;\r\n}());\r\nexports.Participant = Participant;\r\n", "\"use strict\";\r\nObject.defineProperty(exports, \"__esModule\", { value: true });\r\nexports.isNaturalNumber = exports.isNullOrUndefined = void 0;\r\n/**\r\n * Gets whether the value provided is null or undefined.\r\n * @param value The value to check.\r\n * @returns Whether the value provided is null or undefined.\r\n */\r\nfunction isNullOrUndefined(value) {\r\n return value === null || value === undefined;\r\n}\r\nexports.isNullOrUndefined = isNullOrUndefined;\r\n/**\r\n * Gets whether the value provided is a natural number.\r\n * @param value The value to check.\r\n * @returns Whether the value provided is a natural number.\r\n */\r\nfunction isNaturalNumber(value) {\r\n return typeof value === \"number\" && value >= 1 && Math.floor(value) === value;\r\n}\r\nexports.isNaturalNumber = isNaturalNumber;\r\n", "\"use strict\";\r\nObject.defineProperty(exports, \"__esModule\", { value: true });\r\nexports.Lotto = void 0;\r\nvar Participant_1 = require(\"./Participant\");\r\nvar Utilities_1 = require(\"./Utilities\");\r\n/**\r\n * Represents a lotto consisting of a number of pickable ticket-holding participants.\r\n */\r\nvar Lotto = /** @class */ (function () {\r\n /**\r\n * Creates a new instance of Lotto.\r\n * @param customRandom The custom RNG to use in place of Math.random().\r\n */\r\n function Lotto(customRandom) {\r\n /** The array of participants that are holding tickets in the lotto. */\r\n this._participants = [];\r\n this._customRandom = customRandom;\r\n }\r\n /**\r\n * Adds a participant with the specified number of tickets, or adds to the participant ticket count if the participant already holds tickets.\r\n * @param participant The participant to add or to increase the ticket count for if they already hold tickets.\r\n * @param tickets The number of tickets, defaults to 1.\r\n * @returns The Lotto instance.\r\n */\r\n Lotto.prototype.add = function (participant, tickets) {\r\n if (tickets === void 0) { tickets = 1; }\r\n // Check that we have a valid ticket count.\r\n if (!(0, Utilities_1.isNaturalNumber)(tickets)) {\r\n throw new Error(\"tickets value must be a natural number\");\r\n }\r\n // Check whether this participant has already been added.\r\n var existingParticipant = this._participants.find(function (part) { return part.participant === participant; });\r\n if (existingParticipant) {\r\n // The participant has already been added to the lotto so just add to their ticket count.\r\n existingParticipant.tickets += tickets;\r\n }\r\n else {\r\n // The participant is not part of the lotto so we should add them.\r\n this._participants.push(new Participant_1.Participant(participant, tickets));\r\n }\r\n return this;\r\n };\r\n /**\r\n * Removes the specified number of tickets for the given participant from the draw, or all tickets if a ticket number is not defined.\r\n * @param participant The participant to remove tickets for.\r\n * @param tickets The number of tickets to remove, or undefined if all tickets are to be removed.\r\n * @returns The Lotto instance.\r\n */\r\n Lotto.prototype.remove = function (participant, tickets) {\r\n // Attempt to get the existing participant.\r\n var existingParticipant = this._participants.find(function (part) { return part.participant === participant; });\r\n // There is nothing to do if the specified participant isn't even part of the lotto.\r\n if (!existingParticipant) {\r\n return this;\r\n }\r\n // Check whether a tickets value was given.\r\n if (tickets !== undefined) {\r\n // Check that we have a valid ticket count.\r\n if (!(0, Utilities_1.isNaturalNumber)(tickets)) {\r\n throw new Error(\"tickets value must be a natural number\");\r\n }\r\n existingParticipant.tickets -= tickets;\r\n // If the participant no longer holds any tickets then they should be removed.\r\n if (existingParticipant.tickets < 1) {\r\n this._participants = this._participants.filter(function (part) { return part !== existingParticipant; });\r\n }\r\n }\r\n else {\r\n // We are removing all tickets for the participant so just remove them from the lotto.\r\n this._participants = this._participants.filter(function (part) { return part !== existingParticipant; });\r\n }\r\n return this;\r\n };\r\n /**\r\n * Draw a winning ticket and return the participant that holds the ticket.\r\n * @param options The draw options.\r\n * @returns The participant that holds the winning ticket.\r\n */\r\n Lotto.prototype.draw = function (options) {\r\n if (options === void 0) { options = {}; }\r\n // If we have no participants then just return null.\r\n if (this._participants.length === 0) {\r\n return null;\r\n }\r\n var redrawable = (0, Utilities_1.isNullOrUndefined)(options.redrawable) ? true : options.redrawable;\r\n var pickable = [];\r\n this._participants.forEach(function (_a) {\r\n var participant = _a.participant, tickets = _a.tickets;\r\n for (var ticketCount = 0; ticketCount < tickets; ticketCount++) {\r\n pickable.push(participant);\r\n }\r\n });\r\n var random;\r\n // We need a random floating-point number between 0 (inclusive) and 1 to scale up to pick our winner.\r\n // If a custom random function exists then we should use that or fall back to Math.random().\r\n if (this._customRandom) {\r\n // Call our custom random function to get a random floating-point number.\r\n random = this._customRandom();\r\n // Verify that the result of calling our custom random function is a number between 0 (inclusive) and 1.\r\n if (typeof random !== \"number\" || random < 0 || random >= 1) {\r\n throw new Error(\"the 'random' function provided did not return a number between 0 (inclusive) and 1\");\r\n }\r\n }\r\n else {\r\n // No custom random function was defined so just use good ol' Math.random().\r\n random = Math.random();\r\n }\r\n // Pick a winning participant.\r\n var winner = pickable[Math.floor(random * pickable.length)];\r\n // If the ticket isn't redrawable then we should remove a ticket from the winning participants ticket count.\r\n if (!redrawable) {\r\n this.remove(winner, 1);\r\n }\r\n // Return the winning participant.\r\n return winner;\r\n };\r\n /**\r\n * Draws multiple winning tickets and return an array of the participants that hold the winning tickets.\r\n * @param tickets The number of winning tickets to draw.\r\n * @param options The draw multiple options.\r\n * @returns An array of the participants that hold the winning tickets.\r\n */\r\n Lotto.prototype.drawMultiple = function (tickets, options) {\r\n if (options === void 0) { options = {}; }\r\n var uniqueResults = (0, Utilities_1.isNullOrUndefined)(options.unique) ? false : options.unique;\r\n // Handle cases where the user has asked for zero tickets (no idea why they would do this be we should trust them).\r\n if (tickets === 0) {\r\n return [];\r\n }\r\n // Now that we know out tickets value is not zero we should check that it is a valid natural number.\r\n if (!(0, Utilities_1.isNaturalNumber)(tickets)) {\r\n throw new Error(\"tickets value must be a natural number\");\r\n }\r\n var result = [];\r\n // Keep drawing tickets until we either reach the number of required tickets or we simply run out of tickets to draw.\r\n // We can run out of tickets to draw if 'options.redrawable' is explicity 'false' or we just had no participants when 'drawMultiple' was called.\r\n while (result.length < tickets && this._participants.length > 0) {\r\n result.push(this.draw(options));\r\n }\r\n // If the 'unique' draw option is set then we need to remove duplicates from the result list.\r\n if (uniqueResults) {\r\n // Create an array to store our unique results.\r\n var unique = [];\r\n // Iterate over all of our participants (with potential duplicates) and populate our array of unique values.\r\n for (var _i = 0, result_1 = result; _i < result_1.length; _i++) {\r\n var participant = result_1[_i];\r\n if (unique.indexOf(participant) === -1) {\r\n unique.push(participant);\r\n }\r\n }\r\n result = unique;\r\n }\r\n return result;\r\n };\r\n return Lotto;\r\n}());\r\nexports.Lotto = Lotto;\r\n", "\"use strict\";\r\nObject.defineProperty(exports, \"__esModule\", { value: true });\r\nexports.createLotto = void 0;\r\nvar Lotto_1 = require(\"./Lotto\");\r\n/**\r\n * A function that creates and returns a Lotto instance.\r\n * @param participantsOrOptions An array of initial participants or options relating to the creation of a Lotto instance.\r\n * @returns A new Lotto instance.\r\n */\r\nfunction createLotto(participantsOrOptions) {\r\n // If no initial participants or lotto options were provided as an argument then we can just return a new lotto instance now.\r\n if (!participantsOrOptions) {\r\n return new Lotto_1.Lotto();\r\n }\r\n // Check whether we were provided with an array of initial participants or a lotto options object.\r\n if (Array.isArray(participantsOrOptions)) {\r\n // We are dealing with a pre-defined array of participants.\r\n var participants = participantsOrOptions;\r\n var lotto_1 = new Lotto_1.Lotto();\r\n // If the lotto participants have been defined upfront then we will need to add them all to our lotto instance now.\r\n participants.forEach(function (_a) {\r\n var participant = _a[0], tokens = _a[1];\r\n return lotto_1.add(participant, tokens);\r\n });\r\n // Return the Lotto instance.\r\n return lotto_1;\r\n }\r\n else {\r\n // We are dealing with some lotto options.\r\n var random = participantsOrOptions.random, participants = participantsOrOptions.participants;\r\n // Create a Lotto instance passing the custom RNG function to use in place of Math.random() (which could be undefined).\r\n var lotto_2 = new Lotto_1.Lotto(random);\r\n // If the lotto participants have been defined upfront as part of the options then we will need to add them all to our lotto instance now.\r\n if (participants) {\r\n participants.forEach(function (_a) {\r\n var participant = _a[0], tokens = _a[1];\r\n return lotto_2.add(participant, tokens);\r\n });\r\n }\r\n // Return the Lotto instance.\r\n return lotto_2;\r\n }\r\n}\r\nexports.createLotto = createLotto;\r\n", "\"use strict\";\r\nObject.defineProperty(exports, \"__esModule\", { value: true });\r\nvar createLotto_1 = require(\"./createLotto\");\r\nexports.default = createLotto_1.createLotto;\r\n", "import State from \"./State\";\nimport { validateDefinition } from \"./BehaviourTreeDefinitionValidator\";\nimport { convertMDSLToJSON } from \"./mdsl/MDSLDefinitionParser\";\nimport { BehaviourTree, FlattenedTreeNode } from \"./BehaviourTree\";\n\nexport { BehaviourTree, State, convertMDSLToJSON, validateDefinition };\nexport type { FlattenedTreeNode };\n", "/**\n * Enumeration of node state types.\n */\nexport enum State {\n READY = \"mistreevous.ready\",\n RUNNING = \"mistreevous.running\",\n SUCCEEDED = \"mistreevous.succeeded\",\n FAILED = \"mistreevous.failed\"\n}\n\nexport { State as default };\n\nexport type CompleteState = State.SUCCEEDED | State.FAILED;\nexport type AnyState = State.READY | State.RUNNING | CompleteState;\n", "import {\n NodeDefinition,\n RootNodeDefinition,\n DecoratorNodeDefinition,\n CompositeNodeDefinition,\n AnyNodeDefinition,\n BranchNodeDefinition\n} from \"./BehaviourTreeDefinition\";\n\n/**\n * A type guard function that returns true if the specified node satisfies the RootNodeDefinition type.\n * @param node The node.\n * @returns A value of true if the specified node satisfies the RootNodeDefinition type.\n */\nexport function isRootNode(node: NodeDefinition): node is RootNodeDefinition {\n return node.type === \"root\";\n}\n\n/**\n * A type guard function that returns true if the specified node satisfies the BranchNodeDefinition type.\n * @param node The node.\n * @returns A value of true if the specified node satisfies the BranchNodeDefinition type.\n */\nexport function isBranchNode(node: NodeDefinition): node is BranchNodeDefinition {\n return node.type === \"branch\";\n}\n\n/**\n * A type guard function that returns true if the specified node satisfies the NodeDefinition type.\n * @param node The node.\n * @returns A value of true if the specified node satisfies the NodeDefinition type.\n */\nexport function isLeafNode(node: NodeDefinition): node is NodeDefinition {\n return [\"branch\", \"action\", \"condition\", \"wait\"].includes(node.type);\n}\n\n/**\n * A type guard function that returns true if the specified node satisfies the DecoratorNodeDefinition type.\n * @param node The node.\n * @returns A value of true if the specified node satisfies the DecoratorNodeDefinition type.\n */\nexport function isDecoratorNode(node: NodeDefinition): node is DecoratorNodeDefinition {\n return [\"root\", \"repeat\", \"retry\", \"flip\", \"succeed\", \"fail\"].includes(node.type);\n}\n\n/**\n * A type guard function that returns true if the specified node satisfies the CompositeNodeDefinition type.\n * @param node The node.\n * @returns A value of true if the specified node satisfies the CompositeNodeDefinition type.\n */\nexport function isCompositeNode(node: NodeDefinition): node is CompositeNodeDefinition {\n return [\"sequence\", \"selector\", \"lotto\", \"parallel\"].includes(node.type);\n}\n\n/**\n * Flatten a node definition into an array of all of its nested node definitions.\n * @param nodeDefinition The node definition to flatten.\n * @returns An array of all of nested node definitions.\n */\nexport function flattenDefinition(nodeDefinition: AnyNodeDefinition): AnyNodeDefinition[] {\n const nodes: AnyNodeDefinition[] = [];\n\n const processNode = (currentNodeDefinition: AnyNodeDefinition) => {\n nodes.push(currentNodeDefinition);\n\n if (isCompositeNode(currentNodeDefinition)) {\n currentNodeDefinition.children.forEach(processNode);\n } else if (isDecoratorNode(currentNodeDefinition)) {\n processNode(currentNodeDefinition.child);\n }\n };\n\n processNode(nodeDefinition);\n\n return nodes;\n}\n\n/**\n * Determines whether the passed value is an integer.\n * @param value The value to check.\n * @returns Whether the passed value is an integer.\n */\nexport function isInteger(value: unknown): boolean {\n return typeof value === \"number\" && Math.floor(value) === value;\n}\n\n/**\n * Determines whether the passed value is null or undefined.\n * @param value The value to check.\n * @returns Whether the passed value is null or undefined.\n */\nexport function isNullOrUndefined(value: unknown): boolean {\n return typeof value === \"undefined\" || value === null;\n}\n", "/**\n * A type defining an object that holds a reference to substitued string literals parsed from the definition.\n */\nexport type StringLiteralPlaceholders = { [key: string]: string };\n\n/**\n * Pop the next raw token from the specified array of tokens and throw an error if it wasn't the expected one.\n * @param tokens The array of tokens.\n * @param expected An optional string or array or items, one of which must match the next popped token.\n * @returns The popped token.\n */\nexport function popAndCheck(tokens: string[], expected?: string | string[]): string {\n // Get and remove the next token.\n const popped = tokens.shift();\n\n // We were expecting another token but there aren't any.\n if (popped === undefined) {\n throw new Error(\"unexpected end of definition\");\n }\n\n // Do we have an expected token/tokens array?\n if (expected != undefined) {\n // Get an array of expected values, if the popped token matches any then we are all good.\n const expectedValues = typeof expected === \"string\" ? [expected] : expected;\n\n // Check whether the popped token matches at least one of our expected items.\n var tokenMatchesExpectation = expectedValues.some((item) => popped.toUpperCase() === item.toUpperCase());\n\n // Throw an error if the popped token didn't match any of our expected items.\n if (!tokenMatchesExpectation) {\n const expectationString = expectedValues.map((item) => \"'\" + item + \"'\").join(\" or \");\n throw new Error(\"unexpected token found. Expected \" + expectationString + \" but got '\" + popped + \"'\");\n }\n }\n\n // Return the popped token.\n return popped;\n}\n\n/**\n * Swaps out any node/attribute argument string literals with placeholders.\n * @param definition The definition.\n * @returns An object containing a mapping of placeholders to original string values as well as the processed definition string.\n */\nexport function substituteStringLiterals(definition: string): {\n placeholders: StringLiteralPlaceholders;\n processedDefinition: string;\n} {\n // Create an object to hold the mapping of placeholders to original string values.\n const placeholders: StringLiteralPlaceholders = {};\n\n // Replace any string literals wrapped with double quotes in our definition with placeholders to be processed later.\n const processedDefinition = definition.replace(/\\\"(\\\\.|[^\"\\\\])*\\\"/g, (match) => {\n var strippedMatch = match.substring(1, match.length - 1);\n var placeholder = Object.keys(placeholders).find((key) => placeholders[key] === strippedMatch);\n\n // If we have no existing string literal match then create a new placeholder.\n if (!placeholder) {\n placeholder = `@@${Object.keys(placeholders).length}@@`;\n placeholders[placeholder] = strippedMatch;\n }\n\n return placeholder;\n });\n\n return { placeholders, processedDefinition };\n}\n\n/**\n * Parse the tree definition into an array of raw tokens.\n * @param definition The definition.\n * @returns An array of tokens parsed from the definition.\n */\nexport function parseTokensFromDefinition(definition: string): string[] {\n // Add some space around various important characters so that they can be plucked out easier as individual tokens.\n definition = definition.replace(/\\(/g, \" ( \");\n definition = definition.replace(/\\)/g, \" ) \");\n definition = definition.replace(/\\{/g, \" { \");\n definition = definition.replace(/\\}/g, \" } \");\n definition = definition.replace(/\\]/g, \" ] \");\n definition = definition.replace(/\\[/g, \" [ \");\n definition = definition.replace(/\\,/g, \" , \");\n\n // Split the definition into raw token form and return it.\n return definition.replace(/\\s+/g, \" \").trim().split(\" \");\n}\n", "import { StringLiteralPlaceholders, popAndCheck } from \"./MDSLUtilities\";\n\n/**\n * A type representing any node function argument.\n */\ntype Argument = {\n /**\n * The argument value.\n */\n value: T;\n /**\n * The argument type, used for validation.\n */\n type: string;\n};\n\ntype NullArgument = Argument & {\n type: \"null\";\n};\n\ntype BooleanArgument = Argument & {\n type: \"boolean\";\n};\n\ntype NumberArgument = Argument & {\n type: \"number\";\n /**\n * A flag defining whether the number argument value is a valid integer. (used for validation)\n */\n isInteger: boolean;\n};\n\ntype StringPlaceholderArgument = Argument & {\n type: \"string\";\n};\n\ntype IdentifierArgument = Argument & {\n type: \"identifier\";\n};\n\n/**\n * A type representing a reference to any node function argument.\n */\ntype AnyArgument = NullArgument | BooleanArgument | NumberArgument | StringPlaceholderArgument | IdentifierArgument;\n\n/**\n * Parse an array of argument definitions from the specified tokens array.\n * @param tokens The array tokens to parse the argument definitions from.\n * @param stringArgumentPlaceholders The mapping of string literal node argument placeholders to original values.\n * @param argumentValidator The argument validator function.\n * @param validationFailedMessage The exception message to throw if argument validation fails.\n * @returns An array of argument definitions parsed from the specified tokens array.\n */\nexport function parseArgumentTokens(\n tokens: string[],\n stringArgumentPlaceholders: StringLiteralPlaceholders\n): AnyArgument[] {\n const argumentList: AnyArgument[] = [];\n\n // If the next token is not a '[' or '(' then we have no arguments to parse.\n if (![\"[\", \"(\"].includes(tokens[0])) {\n return argumentList;\n }\n\n // Any lists of arguments will always be wrapped in '[]' for node arguments or '()' for attribute arguments.\n // We are looking for a '[' or '(' opener that wraps the argument tokens and the relevant closer.\n const closingToken = popAndCheck(tokens, [\"[\", \"(\"]) === \"[\" ? \"]\" : \")\";\n\n const argumentListTokens: string[] = [];\n\n // Grab all tokens between the '[' and ']' or '(' and ')'.\n while (tokens.length && tokens[0] !== closingToken) {\n // The next token is part of our arguments list.\n argumentListTokens.push(tokens.shift()!);\n }\n\n // Validate the order of the argument tokens. Each token must either be a ',' or a single argument that satisfies the validator.\n argumentListTokens.forEach((token, index) => {\n // Get whether this token should be an actual argument.\n const shouldBeArgumentToken = !(index & 1);\n\n // If the current token should be an actual argument then validate it, otherwise it should be a ',' token.\n if (shouldBeArgumentToken) {\n // Get the argument definition.\n const argumentDefinition = getArgumentDefinition(token, stringArgumentPlaceholders);\n\n // This is a valid argument!\n argumentList.push(argumentDefinition);\n } else {\n // The current token should be a ',' token.\n if (token !== \",\") {\n throw new Error(`invalid argument list, expected ',' or ']' but got '${token}'`);\n }\n }\n });\n\n // The arguments list should terminate with a ']' or ')' token, depending on the opener.\n popAndCheck(tokens, closingToken);\n\n // Return the arguments.\n return argumentList;\n}\n\n/**\n * Gets an argument value definition.\n * @param token The argument token.\n * @param stringArgumentPlaceholders The mapping of string literal node argument placeholders to original values.\n * @returns An argument value definition.\n */\nfunction getArgumentDefinition(token: string, stringArgumentPlaceholders: StringLiteralPlaceholders): AnyArgument {\n // Check whether the token represents a null value.\n if (token === \"null\") {\n return {\n value: null,\n type: \"null\"\n } as NullArgument;\n }\n\n // Check whether the token represents a boolean value.\n if (token === \"true\" || token === \"false\") {\n return {\n value: token === \"true\",\n type: \"boolean\"\n } as BooleanArgument;\n }\n\n // Check whether the token represents a number value.\n // TODO: Relies on broken isNaN - see MDN.\n // if (!Number.isNaN(token)) {\n if (!isNaN(token as any)) {\n return {\n value: parseFloat(token),\n isInteger: parseFloat(token) === parseInt(token, 10),\n type: \"number\"\n } as NumberArgument;\n }\n\n // Check whether the token is a placeholder (e.g. @@0@@) representing a string literal.\n if (token.match(/^@@\\d+@@$/g)) {\n return {\n value: stringArgumentPlaceholders[token].replace('\\\\\"', '\"'),\n type: \"string\"\n } as StringPlaceholderArgument;\n }\n\n // The only remaining option is that the argument value is an identifier.\n return {\n value: token,\n type: \"identifier\"\n } as IdentifierArgument;\n}\n", "import { NodeAttributeDefinition } from \"../BehaviourTreeDefinition\";\nimport { parseArgumentTokens } from \"./MDSLNodeArgumentParser\";\nimport { StringLiteralPlaceholders } from \"./MDSLUtilities\";\n\n/**\n * A type defining the attribute definitions of a node.\n */\ntype NodeAttributes = {\n while?: NodeAttributeDefinition;\n until?: NodeAttributeDefinition;\n entry?: NodeAttributeDefinition;\n exit?: NodeAttributeDefinition;\n step?: NodeAttributeDefinition;\n};\n\n/**\n * Parse any node attribute definitions from the specified tokens array.\n * @param tokens The array of remaining tokens.\n * @param stringArgumentPlaceholders The mapping of string literal node argument placeholders to original values.\n * @returns An object of attribute definitions defined by any directly following tokens.\n */\nexport function parseAttributeTokens(\n tokens: string[],\n stringArgumentPlaceholders: StringLiteralPlaceholders\n): NodeAttributes {\n const nodeAttributeNames: (keyof NodeAttributes)[] = [\"while\", \"until\", \"entry\", \"exit\", \"step\"];\n\n // Create an object to hold any attributes found.\n const attributes: NodeAttributes = {};\n\n // Try to get the name of the attribute for the next token.\n let nextAttributeName = tokens[0]?.toLowerCase() as keyof NodeAttributes;\n\n // Pull attribute tokens as well as their arguments off of the tokens stack until we have no more.\n while (nodeAttributeNames.includes(nextAttributeName)) {\n // Check to make sure that we have not already created an attribute definition of this type.\n if (attributes[nextAttributeName]) {\n throw new Error(`duplicate attribute '${tokens[0].toUpperCase()}' found for node`);\n }\n\n // Remove the attribute name token from the array of tokens.\n tokens.shift();\n\n // Grab the attribute arguments, assuming the first to be an identifier.\n const [attributeCallIdentifier, ...attributeArguments] = parseArgumentTokens(\n tokens,\n stringArgumentPlaceholders\n );\n\n // The first attribute argument has to be an identifer, this will reference an agent function.\n if (attributeCallIdentifier?.type !== \"identifier\") {\n throw new Error(\"expected agent function name identifier argument for attribute\");\n }\n\n // Any attribute arguments (other than the expected call identifier) must have a type of string, number, boolean or null.\n attributeArguments\n .filter((arg) => arg.type === \"identifier\")\n .forEach((arg) => {\n throw new Error(\n `invalid attribute argument value '${arg.value}', must be string, number, boolean or null`\n );\n });\n\n // Create the attribute definition and add it to the object of attribute definitions found.\n attributes[nextAttributeName] = {\n call: attributeCallIdentifier.value,\n args: attributeArguments.map(({ value }) => value)\n };\n\n // Try to get the next attribute name token, as there could be multiple.\n nextAttributeName = tokens[0]?.toLowerCase() as keyof NodeAttributes;\n }\n\n return attributes;\n}\n", "import {\n ActionNodeDefinition,\n AnyChildNodeDefinition,\n AnyNodeDefinition,\n BranchNodeDefinition,\n ConditionNodeDefinition,\n FailNodeDefinition,\n FlipNodeDefinition,\n LottoNodeDefinition,\n ParallelNodeDefinition,\n RepeatNodeDefinition,\n RetryNodeDefinition,\n RootNodeDefinition,\n SelectorNodeDefinition,\n SequenceNodeDefinition,\n SucceedNodeDefinition,\n WaitNodeDefinition\n} from \"../BehaviourTreeDefinition\";\nimport {\n isCompositeNode,\n isDecoratorNode,\n isLeafNode,\n isNullOrUndefined,\n isRootNode\n} from \"../BehaviourTreeDefinitionUtilities\";\nimport { parseArgumentTokens } from \"./MDSLNodeArgumentParser\";\nimport { parseAttributeTokens } from \"./MDSLNodeAttributeParser\";\nimport {\n StringLiteralPlaceholders,\n parseTokensFromDefinition,\n popAndCheck,\n substituteStringLiterals\n} from \"./MDSLUtilities\";\n\n/**\n * Convert the MDSL tree definition string into an equivalent JSON definition.\n * @param definition The tree definition string as MDSL.\n * @returns The root node JSON definitions.\n */\nexport function convertMDSLToJSON(definition: string): RootNodeDefinition[] {\n // Swap out any node/attribute argument string literals with a placeholder and get a mapping of placeholders to original values as well as the processed definition.\n const { placeholders, processedDefinition } = substituteStringLiterals(definition);\n\n // Parse our definition definition string into an array of raw tokens.\n const tokens = parseTokensFromDefinition(processedDefinition);\n\n return convertTokensToJSONDefinition(tokens, placeholders);\n}\n\n/**\n * Converts the specified tree definition tokens into a JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The root node JSON definitions.\n */\nfunction convertTokensToJSONDefinition(\n tokens: string[],\n stringLiteralPlaceholders: StringLiteralPlaceholders\n): RootNodeDefinition[] {\n // There must be at least 3 tokens for the tree definition to be valid. 'ROOT', '{' and '}'.\n if (tokens.length < 3) {\n throw new Error(\"invalid token count\");\n }\n\n // We should have a matching number of '{' and '}' tokens. If not, then there are scopes that have not been properly closed.\n if (tokens.filter((token) => token === \"{\").length !== tokens.filter((token) => token === \"}\").length) {\n throw new Error(\"scope character mismatch\");\n }\n\n // Create an array of tree stack arrays where root nodes will always be at the botton and the current composite/decorator node at the top.\n // There should be an element in this array for every root node defined and every element should be an array with a root note as the first element.\n // E.g. A definition with two root nodes defined:\n // [\n // [root, lotto, sequence],\n // [root, selector]\n // ]\n const treeStacks: [Partial, ...Partial[]][] = [];\n\n // Create an array of all root node definitions that we create.\n const rootNodes: Partial[] = [];\n\n // A helper function used to push node definitions onto the tree stack.\n const pushNode = (node: AnyNodeDefinition) => {\n // If the node is a root node then we need to create a new tree stack array with the root node at the root.\n if (isRootNode(node)) {\n // We need to double-check that this root node is not the child of another node.\n // We can do this by checking whether the top tree stack is not empty (contains an existing node)\n if (treeStacks[treeStacks.length - 1]?.length) {\n throw new Error(\"a root node cannot be the child of another node\");\n }\n\n // Add the root node definition to our array of all parsed root node definitions.\n rootNodes.push(node);\n\n // Add the root node definition to the root of a new tree stack.\n treeStacks.push([node]);\n\n return;\n }\n\n // All non-root nodes should be pushed after their root nodes so handle cases\n // where we may not have any tree stacks or our top-most tree stack is empty.\n if (!treeStacks.length || !treeStacks[treeStacks.length - 1].length) {\n throw new Error(\"expected root node at base of definition\");\n }\n\n // Get the current tree stack that we are populating.\n const topTreeStack = treeStacks[treeStacks.length - 1];\n\n // Get the top-most node in the current tree stack, this will be a composite/decorator node\n // for which we will populate its children array if composite or setting its child if a decorator.\n const topTreeStackTopNode = topTreeStack[topTreeStack.length - 1] as AnyNodeDefinition;\n\n // If the top-most node in the current root stack is a composite or decorator\n // node then the current node should be added as a child of the top-most node.\n if (isCompositeNode(topTreeStackTopNode)) {\n topTreeStackTopNode.children = topTreeStackTopNode.children || [];\n topTreeStackTopNode.children.push(node);\n } else if (isDecoratorNode(topTreeStackTopNode)) {\n // If the top node already has a child node set then throw an error as a decorator should only have a single child.\n if (topTreeStackTopNode.child) {\n throw new Error(\"a decorator node must only have a single child node\");\n }\n\n topTreeStackTopNode.child = node;\n }\n\n // If the node we are adding is also a composite or decorator node, then we should push it\n // onto the current tree stack, as subsequent nodes will be added as its child/children.\n if (!isLeafNode(node)) {\n topTreeStack.push(node);\n }\n };\n\n // A helper function used to pop the top-most node definition off of the tree stack and return it.\n const popNode = (): AnyNodeDefinition | null => {\n let poppedNode: AnyNodeDefinition | null = null;\n\n // Get the current tree stack that we are populating.\n const topTreeStack = treeStacks[treeStacks.length - 1];\n\n // Pop the top-most node in the current tree stack if there is one.\n if (topTreeStack.length) {\n poppedNode = topTreeStack.pop() as AnyNodeDefinition;\n }\n\n // We don't want any empty tree stacks in our stack of tree stacks.\n if (!topTreeStack.length) {\n treeStacks.pop();\n }\n\n return poppedNode;\n };\n\n // We should keep processing the raw tokens until we run out of them.\n while (tokens.length) {\n // Grab the next token.\n const token = tokens.shift()!;\n\n // How we create the next node depends on the current raw token value.\n switch (token.toUpperCase()) {\n case \"ROOT\": {\n pushNode(createRootNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"SUCCEED\": {\n pushNode(createSucceedNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"FAIL\": {\n pushNode(createFailNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"FLIP\": {\n pushNode(createFlipNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"REPEAT\": {\n pushNode(createRepeatNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"RETRY\": {\n pushNode(createRetryNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"SEQUENCE\": {\n pushNode(createSequenceNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"SELECTOR\": {\n pushNode(createSelectorNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"PARALLEL\": {\n pushNode(createParallelNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"LOTTO\": {\n pushNode(createLottoNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"ACTION\": {\n pushNode(createActionNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"CONDITION\": {\n pushNode(createConditionNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"WAIT\": {\n pushNode(createWaitNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"BRANCH\": {\n pushNode(createBranchNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"}\": {\n // The '}' character closes the current scope and means that we have to pop a node off of the current stack.\n const poppedNode = popNode();\n\n // Now that we have a node definition we can carry out any validation that may require the node to be fully populated.\n if (poppedNode) {\n validatePoppedNode(poppedNode);\n }\n\n break;\n }\n\n default: {\n throw new Error(`unexpected token: ${token}`);\n }\n }\n }\n\n return rootNodes as RootNodeDefinition[];\n}\n\n/**\n * Creates a root node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The root node JSON definition.\n */\nfunction createRootNode(tokens: string[], stringLiteralPlaceholders: StringLiteralPlaceholders): RootNodeDefinition {\n // Create the root node definition.\n let node = {\n type: \"root\",\n id: undefined\n } as RootNodeDefinition;\n\n // Parse any node arguments, we should only have one if any which will be an identifier argument for the root identifier.\n const nodeArguments = parseArgumentTokens(tokens, stringLiteralPlaceholders);\n\n // Check whether any node arguments were defined.\n if (nodeArguments.length) {\n // We should only have one argument, if any, which will be an identifier argument for the root identifier.\n if (nodeArguments.length === 1 && nodeArguments[0].type === \"identifier\") {\n // The root node identifier will be the first and only node argument value.\n node.id = nodeArguments[0].value as string;\n } else {\n throw new Error(\"expected single root name argument\");\n }\n }\n\n // Grab any node attribute definitions and spread them into the node definition.\n node = { ...node, ...parseAttributeTokens(tokens, stringLiteralPlaceholders) };\n\n // This is a decorator node, so we expect an opening '{'.\n popAndCheck(tokens, \"{\");\n\n // Return the root node definition.\n return node;\n}\n\n/**\n * Creates a succeed node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The succeed node JSON definition.\n */\nfunction createSucceedNode(\n tokens: string[],\n stringLiteralPlaceholders: StringLiteralPlaceholders\n): SucceedNodeDefinition {\n const node = {\n type: \"succeed\",\n ...parseAttributeTokens(tokens, stringLiteralPlaceholders)\n } as SucceedNodeDefinition;\n\n // This is a decorator node, so we expect an opening '{'.\n popAndCheck(tokens, \"{\");\n\n // Return the succeed node definition.\n return node;\n}\n\n/**\n * Creates a fail node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The fail node JSON definition.\n */\nfunction createFailNode(tokens: string[], stringLiteralPlaceholders: StringLiteralPlaceholders): FailNodeDefinition {\n const node = {\n type: \"fail\",\n ...parseAttributeTokens(tokens, stringLiteralPlaceholders)\n } as FailNodeDefinition;\n\n // This is a decorator node, so we expect an opening '{'.\n popAndCheck(tokens, \"{\");\n\n // Return the fail node definition.\n return node;\n}\n\n/**\n * Creates a flip node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The flip node JSON definition.\n */\nfunction createFlipNode(tokens: string[], stringLiteralPlaceholders: StringLiteralPlaceholders): FlipNodeDefinition {\n const node = {\n type: \"flip\",\n ...parseAttributeTokens(tokens, stringLiteralPlaceholders)\n } as FlipNodeDefinition;\n\n // This is a decorator node, so we expect an opening '{'.\n popAndCheck(tokens, \"{\");\n\n // Return the flip node definition.\n return node;\n}\n\n/**\n * Creates a repeat node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The repeat node JSON definition.\n */\nfunction createRepeatNode(\n tokens: string[],\n stringLiteralPlaceholders: StringLiteralPlaceholders\n): RepeatNodeDefinition {\n let node = { type: \"repeat\" } as RepeatNodeDefinition;\n\n // Get the node arguments.\n const nodeArguments = parseArgumentTokens(tokens, stringLiteralPlaceholders);\n\n // The arguments of a repeat node are optional. We may have:\n // - No node arguments, in which case the repeat note will iterate indefinitely.\n // - One node argument which will be the explicit number of iterations to make.\n // - Two node arguments which define the min and max iteration bounds from which a random iteration count will be picked.\n if (nodeArguments.length) {\n // All repeat node arguments MUST be of type number and must be integer.\n nodeArguments\n .filter((arg) => arg.type !== \"number\" || !arg.isInteger)\n .forEach(() => {\n throw new Error(`repeat node iteration counts must be integer values`);\n });\n\n // We should have got one or two iteration counts.\n if (nodeArguments.length === 1) {\n // A static iteration count was defined.\n node.iterations = nodeArguments[0].value as number;\n\n // A repeat node must have a positive number of iterations if defined.\n if (node.iterations < 0) {\n throw new Error(\"a repeat node must have a positive number of iterations if defined\");\n }\n } else if (nodeArguments.length === 2) {\n // A minimum and maximum iteration count was defined.\n node.iterations = [nodeArguments[0].value as number, nodeArguments[1].value as number];\n\n // A repeat node must have a positive min and max iteration count if they are defined.\n if (node.iterations[0] < 0 || node.iterations[1] < 0) {\n throw new Error(\"a repeat node must have a positive minimum and maximum iteration count if defined\");\n }\n\n // A repeat node must not have an minimum iteration count that exceeds the maximum iteration count.\n if (node.iterations[0] > node.iterations[1]) {\n throw new Error(\n \"a repeat node must not have a minimum iteration count that exceeds the maximum iteration count\"\n );\n }\n } else {\n // An incorrect number of iteration counts was defined.\n throw new Error(\"invalid number of repeat node iteration count arguments defined\");\n }\n }\n\n // Grab any node attribute definitions and spread them into the node definition.\n node = { ...node, ...parseAttributeTokens(tokens, stringLiteralPlaceholders) };\n\n // This is a decorator node, so we expect an opening '{'.\n popAndCheck(tokens, \"{\");\n\n // Return the repeat node definition.\n return node;\n}\n\n/**\n * Creates a retry node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The retry node JSON definition.\n */\nfunction createRetryNode(tokens: string[], stringLiteralPlaceholders: StringLiteralPlaceholders): RetryNodeDefinition {\n let node = { type: \"retry\" } as RetryNodeDefinition;\n\n // Get the node arguments.\n const nodeArguments = parseArgumentTokens(tokens, stringLiteralPlaceholders);\n\n // The arguments of a retry node are optional. We may have:\n // - No node arguments, in which case the retry note will attempt indefinitely.\n // - One node argument which will be the explicit number of attempts to make.\n // - Two node arguments which define the min and max attempt bounds from which a random attempt count will be picked.\n if (nodeArguments.length) {\n // All retry node arguments MUST be of type number and must be integer.\n nodeArguments\n .filter((arg) => arg.type !== \"number\" || !arg.isInteger)\n .forEach(() => {\n throw new Error(`retry node attempt counts must be integer values`);\n });\n\n // We should have got one or two attempt counts.\n if (nodeArguments.length === 1) {\n // A static attempt count was defined.\n node.attempts = nodeArguments[0].value as number;\n\n // A retry node must have a positive number of attempts if defined.\n if (node.attempts < 0) {\n throw new Error(\"a retry node must have a positive number of attempts if defined\");\n }\n } else if (nodeArguments.length === 2) {\n // A minimum and maximum attempt count was defined.\n node.attempts = [nodeArguments[0].value as number, nodeArguments[1].value as number];\n\n // A retry node must have a positive min and max attempts count if they are defined.\n if (node.attempts[0] < 0 || node.attempts[1] < 0) {\n throw new Error(\"a retry node must have a positive minimum and maximum attempt count if defined\");\n }\n\n // A retry node must not have a minimum attempt count that exceeds the maximum attempt count.\n if (node.attempts[0] > node.attempts[1]) {\n throw new Error(\n \"a retry node must not have a minimum attempt count that exceeds the maximum attempt count\"\n );\n }\n } else {\n // An incorrect number of attempt counts was defined.\n throw new Error(\"invalid number of retry node attempt count arguments defined\");\n }\n }\n\n // Grab any node attribute definitions and spread them into the node definition.\n node = { ...node, ...parseAttributeTokens(tokens, stringLiteralPlaceholders) };\n\n // This is a decorator node, so we expect an opening '{'.\n popAndCheck(tokens, \"{\");\n\n // Return the retry node definition.\n return node;\n}\n\n/**\n * Creates a sequence node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The sequence node JSON definition.\n */\nfunction createSequenceNode(\n tokens: string[],\n stringLiteralPlaceholders: StringLiteralPlaceholders\n): SequenceNodeDefinition {\n const node = {\n type: \"sequence\",\n ...parseAttributeTokens(tokens, stringLiteralPlaceholders)\n } as SequenceNodeDefinition;\n\n // This is a composite node, so we expect an opening '{'.\n popAndCheck(tokens, \"{\");\n\n // Return the sequence node definition.\n return node;\n}\n\n/**\n * Creates a selector node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The selector node JSON definition.\n */\nfunction createSelectorNode(\n tokens: string[],\n stringLiteralPlaceholders: StringLiteralPlaceholders\n): SelectorNodeDefinition {\n const node = {\n type: \"selector\",\n ...parseAttributeTokens(tokens, stringLiteralPlaceholders)\n } as SelectorNodeDefinition;\n\n // This is a composite node, so we expect an opening '{'.\n popAndCheck(tokens, \"{\");\n\n // Return the selector node definition.\n return node;\n}\n\n/**\n * Creates a parallel node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The parallel node JSON definition.\n */\nfunction createParallelNode(\n tokens: string[],\n stringLiteralPlaceholders: StringLiteralPlaceholders\n): ParallelNodeDefinition {\n const node = {\n type: \"parallel\",\n ...parseAttributeTokens(tokens, stringLiteralPlaceholders)\n } as ParallelNodeDefinition;\n\n // This is a composite node, so we expect an opening '{'.\n popAndCheck(tokens, \"{\");\n\n // Return the parallel node definition.\n return node;\n}\n\n/**\n * Creates a lotto node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The lotto node JSON definition.\n */\nfunction createLottoNode(tokens: string[], stringLiteralPlaceholders: StringLiteralPlaceholders): LottoNodeDefinition {\n // If any node arguments have been defined then they must be our weights.\n const nodeArguments = parseArgumentTokens(tokens, stringLiteralPlaceholders);\n\n // All lotto node arguments MUST be of type number and must be integer.\n nodeArguments\n .filter((arg) => arg.type !== \"number\" || !arg.isInteger)\n .forEach(() => {\n throw new Error(`lotto node weight arguments must be integer values`);\n });\n\n const node = {\n type: \"lotto\",\n weights: nodeArguments.map(({ value }) => value),\n ...parseAttributeTokens(tokens, stringLiteralPlaceholders)\n } as LottoNodeDefinition;\n\n // This is a composite node, so we expect an opening '{'.\n popAndCheck(tokens, \"{\");\n\n // Return the lotto node definition.\n return node;\n}\n\n/**\n * Creates an action node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The action node JSON definition.\n */\nfunction createActionNode(\n tokens: string[],\n stringLiteralPlaceholders: StringLiteralPlaceholders\n): ActionNodeDefinition {\n // Parse any node arguments, we should have at least one which will be an identifier argument for the action name\n // and agent function to invoke for the action, all other arguments are to be passed as arguments to that function.\n const [actionNameIdentifier, ...agentFunctionArgs] = parseArgumentTokens(tokens, stringLiteralPlaceholders);\n\n // Our first argument MUST be defined and be an identifier as we require an action name argument.\n if (actionNameIdentifier?.type !== \"identifier\") {\n throw new Error(\"expected action name identifier argument\");\n }\n\n // Only the first argument should have been an identifier, all agent function arguments must be string, number, boolean or null.\n agentFunctionArgs\n .filter((arg) => arg.type === \"identifier\")\n .forEach((arg) => {\n throw new Error(\n `invalid action node argument value '${arg.value}', must be string, number, boolean or null`\n );\n });\n\n // Return the action node definition.\n return {\n type: \"action\",\n call: actionNameIdentifier.value,\n args: agentFunctionArgs.map(({ value }) => value),\n ...parseAttributeTokens(tokens, stringLiteralPlaceholders)\n };\n}\n\n/**\n * Creates a condition node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The condition node JSON definition.\n */\nfunction createConditionNode(\n tokens: string[],\n stringLiteralPlaceholders: StringLiteralPlaceholders\n): ConditionNodeDefinition {\n // Parse any node arguments, we should have at least one which will be an identifier argument for the condition name\n // and agent function to invoke for the condition, all other arguments are to be passed as arguments to that function.\n const [conditionNameIdentifier, ...agentFunctionArgs] = parseArgumentTokens(tokens, stringLiteralPlaceholders);\n\n // Our first argument MUST be defined and be an identifier as we require a condition name argument.\n if (conditionNameIdentifier?.type !== \"identifier\") {\n throw new Error(\"expected condition name identifier argument\");\n }\n\n // Only the first argument should have been an identifier, all agent function arguments must be string, number, boolean or null.\n agentFunctionArgs\n .filter((arg) => arg.type === \"identifier\")\n .forEach((arg) => {\n throw new Error(\n `invalid condition node argument value '${arg.value}', must be string, number, boolean or null`\n );\n });\n\n // Return the condition node definition.\n return {\n type: \"condition\",\n call: conditionNameIdentifier.value,\n args: agentFunctionArgs.map(({ value }) => value),\n ...parseAttributeTokens(tokens, stringLiteralPlaceholders)\n };\n}\n\n/**\n * Creates a wait node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The wait node JSON definition.\n */\nfunction createWaitNode(tokens: string[], stringLiteralPlaceholders: StringLiteralPlaceholders): WaitNodeDefinition {\n let node = { type: \"wait\" } as WaitNodeDefinition;\n\n // Get the node arguments.\n const nodeArguments = parseArgumentTokens(tokens, stringLiteralPlaceholders);\n\n // The arguments of a wait node are optional. We may have:\n // - No node arguments, in which case the wait will be indefinite until it is aborted.\n // - One node argument which will be the explicit duration of the wait.\n // - Two node arguments which define the min and max duration bounds from which a random duration will be picked.\n if (nodeArguments.length) {\n // All wait node arguments MUST be of type number and must be integer.\n nodeArguments\n .filter((arg) => arg.type !== \"number\" || !arg.isInteger)\n .forEach(() => {\n throw new Error(`wait node duration arguments must be integer values`);\n });\n\n // We may have:\n // - One node argument which will be the explicit duration of the wait.\n // - Two node arguments which define the min and max duration bounds from which a random duration will be picked.\n // - Too many arguments, which is not valid.\n if (nodeArguments.length === 1) {\n // An explicit duration was defined.\n node.duration = nodeArguments[0].value as number;\n\n // If an explict duration was defined then it must be a positive number.\n if (node.duration < 0) {\n throw new Error(\"a wait node must have a positive duration\");\n }\n } else if (nodeArguments.length === 2) {\n // Min and max duration bounds were defined from which a random duration will be picked.\n node.duration = [nodeArguments[0].value as number, nodeArguments[1].value as number];\n\n // A wait node must have a positive min and max duration.\n if (node.duration[0] < 0 || node.duration[1] < 0) {\n throw new Error(\"a wait node must have a positive minimum and maximum duration\");\n }\n\n // A wait node must not have a minimum duration that exceeds the maximum duration.\n if (node.duration[0] > node.duration[1]) {\n throw new Error(\"a wait node must not have a minimum duration that exceeds the maximum duration\");\n }\n } else if (nodeArguments.length > 2) {\n // An incorrect number of duration arguments were defined.\n throw new Error(\"invalid number of wait node duration arguments defined\");\n }\n }\n\n // Return the wait node definition.\n return { ...node, ...parseAttributeTokens(tokens, stringLiteralPlaceholders) };\n}\n\n/**\n * Creates a branch node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The branch node JSON definition.\n */\nfunction createBranchNode(\n tokens: string[],\n stringLiteralPlaceholders: StringLiteralPlaceholders\n): BranchNodeDefinition {\n // Parse any node arguments, we should have one which will be an identifier argument for the root ref.\n const nodeArguments = parseArgumentTokens(tokens, stringLiteralPlaceholders);\n\n // We should have only a single identifer argument for a branch node, which is the root ref.\n if (nodeArguments.length !== 1 || nodeArguments[0].type !== \"identifier\") {\n throw new Error(\"expected single branch name argument\");\n }\n\n // Return the branch node definition.\n return { type: \"branch\", ref: nodeArguments[0].value };\n}\n\n/**\n * Validate a fully-populated node definition that was popped off of the tree stack.\n * @param node The popped node to validate.\n */\nfunction validatePoppedNode(node: AnyNodeDefinition): void {\n // Decorators MUST have a child defined.\n if (isDecoratorNode(node) && isNullOrUndefined(node.child)) {\n throw new Error(`a ${node.type} node must have a single child node defined`);\n }\n\n // Composites MUST have at least one child defined.\n if (isCompositeNode(node) && !node.children?.length) {\n throw new Error(`a ${node.type} node must have at least a single child node defined`);\n }\n}\n", "import { RootNodeDefinition } from \"./BehaviourTreeDefinition\";\nimport { flattenDefinition, isBranchNode, isInteger } from \"./BehaviourTreeDefinitionUtilities\";\nimport { convertMDSLToJSON } from \"./mdsl/MDSLDefinitionParser\";\n\n/**\n * An object representing the result of validating a tree definition.\n */\nexport type DefinitionValidationResult = {\n /**\n * A flag defining whether validation succeeded.\n */\n succeeded: boolean;\n /**\n * A string containing the error message if validation did not succeed.\n */\n errorMessage?: string;\n};\n\n/**\n * Validates the specified behaviour tree definition in the form of JSON or MDSL, not taking any globally registered subtrees into consideration.\n * @param definition The behaviour tree definition in the form of JSON or MDSL.\n * @returns An object representing the result of validating the given tree definition.\n */\nexport function validateDefinition(definition: any): DefinitionValidationResult {\n // The definition must be defined.\n if (definition === null || typeof definition === \"undefined\") {\n return createValidationFailureResult(\"definition is null or undefined\");\n }\n\n // We are expecting a definition in one of three different forms:\n // - A string which we will assume is MDSL and we will parse this to JSON before validation.\n // - An array which we will assume is an array of root node definitions with at least one being the primary root node (no 'id' property)\n // - An object which we will assume is the primary root node and should not have an 'id' property.\n if (typeof definition === \"string\") {\n // The definition is a string which we can assume is MDSL, so attempt to validate it.\n return validateMDSLDefinition(definition);\n } else if (typeof definition === \"object\") {\n // The definition will either be an array (of root node definitions) or an object (the single primary root node definition).\n return validateJSONDefinition(definition);\n } else {\n return createValidationFailureResult(`unexpected definition type of '${typeof definition}'`);\n }\n}\n\n/**\n * Validates the specified behaviour tree definition in the form of MDSL.\n * @param definition The behaviour tree definition in the form of MDSL.\n * @returns An object representing the result of validating the given tree definition.\n */\nexport function validateMDSLDefinition(definition: string): DefinitionValidationResult {\n let rootNodeDefinitions;\n\n // The first thing the we need to do is to attempt to convert our MDSL into JSON.\n try {\n // The definition is a string which we can assume is MDSL, so attempt to parse it to a JSON definition in the form of an array of root node definitions.\n rootNodeDefinitions = convertMDSLToJSON(definition);\n } catch (error) {\n // We failed to parse the JSON from the MDSL, this is likely to be the result of it not being a valid MDSL string.\n return createValidationFailureResult(`invalid MDSL: ${error}`);\n }\n\n // Unpack all of the root node definitions into arrays of main ('id' defined) and sub ('id' not defined) root node definitions.\n const mainRootNodeDefinitions = rootNodeDefinitions.filter(({ id }) => typeof id === \"undefined\");\n const subRootNodeDefinitions = rootNodeDefinitions.filter(({ id }) => typeof id === \"string\" && id.length > 0);\n\n // We should ALWAYS have exactly one root node definition without an 'id' property defined, which is out main root node definition.\n if (mainRootNodeDefinitions.length !== 1) {\n return createValidationFailureResult(\n \"expected single unnamed root node at base of definition to act as main root\"\n );\n }\n\n // We should never have duplicate 'id' properties across our sub root node definitions.\n const subRootNodeIdenitifers: string[] = [];\n for (const { id } of subRootNodeDefinitions) {\n // Have we already come across this 'id' property value?\n if (subRootNodeIdenitifers.includes(id!)) {\n return createValidationFailureResult(`multiple root nodes found with duplicate name '${id}'`);\n }\n\n subRootNodeIdenitifers.push(id!);\n }\n\n try {\n // Validate our branch -> subtree links and check for any circular dependencies, we don't care about checking for broken subtree links here.\n validateBranchSubtreeLinks(rootNodeDefinitions, false);\n } catch (exception) {\n return createValidationFailureResult((exception as Error).message);\n }\n\n // Our definition was valid!\n return { succeeded: true };\n}\n\n/**\n * Validates the specified behaviour tree definition in the form of JSON.\n * @param definition The behaviour tree definition in the form of JSON.\n * @returns An object representing the result of validating the given tree definition.\n */\nexport function validateJSONDefinition(\n definition: RootNodeDefinition | RootNodeDefinition[]\n): DefinitionValidationResult {\n // The definition will either be an array (of root node definitions) or an object (the single primary root node definition).\n const rootNodeDefinitions = Array.isArray(definition) ? definition : [definition];\n\n // Iterate over our array of root nodes and call validateNode for each, passing an initial depth of 0, wrapped in a try catch to handle validation failures.\n try {\n rootNodeDefinitions.forEach((rootNodeDefinition) => validateNode(rootNodeDefinition, 0));\n } catch (error) {\n // Handle cases where we have caught a thrown Error and return a failure result with the error message.\n if (error instanceof Error) {\n return createValidationFailureResult(error.message);\n }\n\n // No idea what happened here!\n return createValidationFailureResult(`unexpected error: ${error}`);\n }\n\n // Unpack all of the root node definitions into arrays of main ('id' defined) and sub ('id' not defined) root node definitions.\n const mainRootNodeDefinitions = rootNodeDefinitions.filter(({ id }) => typeof id === \"undefined\");\n const subRootNodeDefinitions = rootNodeDefinitions.filter(({ id }) => typeof id === \"string\" && id.length > 0);\n\n // We should ALWAYS have exactly one root node definition without an 'id' property defined, which is out main root node definition.\n if (mainRootNodeDefinitions.length !== 1) {\n return createValidationFailureResult(\n \"expected single root node without 'id' property defined to act as main root\"\n );\n }\n\n // We should never have duplicate 'id' properties across our sub root node definitions.\n const subRootNodeIdenitifers: string[] = [];\n for (const { id } of subRootNodeDefinitions) {\n // Have we already come across this 'id' property value?\n if (subRootNodeIdenitifers.includes(id!)) {\n return createValidationFailureResult(\n `multiple root nodes found with duplicate 'id' property value of '${id}'`\n );\n }\n\n subRootNodeIdenitifers.push(id!);\n }\n\n try {\n // Validate our branch -> subtree links and check for any circular dependencies, we don't care about checking for broken subtree links here.\n validateBranchSubtreeLinks(rootNodeDefinitions, false);\n } catch (exception) {\n return createValidationFailureResult((exception as Error).message);\n }\n\n // Our definition was valid!\n return { succeeded: true };\n}\n\n/**\n * Validates the branch -> subtree links across all provided root node definitions.\n * This will not consider branch nodes that reference any globally registered subtrees unless includesGlobalSubtrees\n * is set to true, in which case we will also verify that there are no broken branch -> subtree links.\n * @param rootNodeDefinitions The array of root node definitions.\n * @param includesGlobalSubtrees A flag defining whether the array includes all global subtree root node definitions.\n */\nexport function validateBranchSubtreeLinks(rootNodeDefinitions: RootNodeDefinition[], includesGlobalSubtrees: boolean) {\n // Create a mapping of root node identifiers to other root nodes that they reference via branch nodes.\n // Below is an example of a mapping that includes a circular dependency (root => a => b => c => a)\n // [{ refs: [\"a\", \"b\"] }, { id: \"a\", refs: [\"b\"] }, { id: \"b\", refs: [\"c\"] }, { id: \"c\", refs: [\"a\"] }]\n const rootNodeMappings: { id: string | undefined; refs: string[] }[] = rootNodeDefinitions.map(\n (rootNodeDefinition) => ({\n id: rootNodeDefinition.id,\n refs: flattenDefinition(rootNodeDefinition)\n .filter(isBranchNode)\n .map(({ ref }) => ref)\n })\n );\n\n // A recursive function to walk through the mappings, keeping track of which root nodes we have visited in the form of a path of root node identifiers.\n const followRefs = (mapping: { id: string | undefined; refs: string[] }, path: (string | undefined)[] = []) => {\n // Have we found a circular dependency?\n if (path.includes(mapping.id)) {\n // We found a circular dependency! Get the bad path of root node identifiers.\n const badPath = [...path, mapping.id];\n\n // Create the formatted path value. [undefined, \"a\", \"b\", \"c\", \"a\"] would be formatted as \"a -> b -> c -> a\".\n const badPathFormatted = badPath.filter((element) => !!element).join(\" => \");\n\n // No need to continue, we found a circular dependency.\n throw new Error(`circular dependency found in branch node references: ${badPathFormatted}`);\n }\n\n for (const ref of mapping.refs) {\n // Find the mapping for the root node with an identifer matching the current ref.\n const subMapping = rootNodeMappings.find(({ id }) => id === ref);\n\n // We may not have a mapping for this ref, which is normal when we aren't considering all globally registered subtrees.\n if (subMapping) {\n followRefs(subMapping, [...path, mapping.id]);\n } else if (includesGlobalSubtrees) {\n // We found a reference to a root node that doesn't exist, which is a problem seeing as the root node definitons includes all globally registered subtrees.\n throw new Error(\n mapping.id\n ? `subtree '${mapping.id}' has branch node that references root node '${ref}' which has not been defined`\n : `primary tree has branch node that references root node '${ref}' which has not been defined`\n );\n }\n }\n };\n\n // Start looking for circular dependencies and broken references from the primary root node definition.\n followRefs(rootNodeMappings.find((mapping) => typeof mapping.id === \"undefined\")!);\n}\n\n/**\n * Validate an object that we expect to be a node definition.\n * @param definition An object that we expect to be a node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateNode(definition: any, depth: number): void {\n // Every node must be valid object and have a non-empty 'type' string property.\n if (typeof definition !== \"object\" || typeof definition.type !== \"string\" || definition.type.length === 0) {\n throw new Error(\n `node definition is not an object or 'type' property is not a non-empty string at depth '${depth}'`\n );\n }\n\n // How we validate this node definition will depend on its type.\n switch (definition.type) {\n case \"action\":\n validateActionNode(definition, depth);\n break;\n\n case \"condition\":\n validateConditionNode(definition, depth);\n break;\n\n case \"wait\":\n validateWaitNode(definition, depth);\n break;\n\n case \"branch\":\n validateBranchNode(definition, depth);\n break;\n\n case \"root\":\n validateRootNode(definition, depth);\n break;\n\n case \"success\":\n validateSuccessNode(definition, depth);\n break;\n\n case \"fail\":\n validateFailNode(definition, depth);\n break;\n\n case \"flip\":\n validateFlipNode(definition, depth);\n break;\n\n case \"repeat\":\n validateRepeatNode(definition, depth);\n break;\n\n case \"retry\":\n validateRetryNode(definition, depth);\n break;\n\n case \"sequence\":\n validateSequenceNode(definition, depth);\n break;\n\n case \"selector\":\n validateSelectorNode(definition, depth);\n break;\n\n case \"parallel\":\n validateParallelNode(definition, depth);\n break;\n\n default:\n throw new Error(`unexpected node type of '${definition.type}' at depth '${depth}'`);\n }\n}\n\n/**\n * Validate any attributes for a given node definition.\n * @param definition The node definition.\n * @param depth The depth of the node in the behaviour tree definition.\n */\nfunction validateNodeAttributes(definition: any, depth: number): void {\n // Validate each of the attribute types for this node.\n [\"while\", \"until\", \"entry\", \"exit\", \"step\"].forEach((attributeName) => {\n // Attempt to grab the definition for the current attribute from the node definition.\n const attributeDefinition = definition[attributeName];\n\n // All node attributes are optional, so there is nothing to do if the current attribute is not defined.\n if (typeof attributeDefinition === \"undefined\") {\n return;\n }\n\n // The attribute definition must be an object.\n if (typeof attributeDefinition !== \"object\") {\n throw new Error(\n `expected attribute '${attributeName}' to be an object for '${definition.type}' node at depth '${depth}'`\n );\n }\n\n // The 'call' property must be defined for any attribute definition.\n if (typeof attributeDefinition.call !== \"string\" || attributeDefinition.call.length === 0) {\n throw new Error(\n `expected 'call' property for attribute '${attributeName}' to be a non-empty string for '${definition.type}' node at depth '${depth}'`\n );\n }\n\n // If any node attribute arguments have been defined then they must have been defined in an array.\n if (typeof attributeDefinition.args !== \"undefined\" && !Array.isArray(attributeDefinition.args)) {\n throw new Error(\n `expected 'args' property for attribute '${attributeName}' to be an array for '${definition.type}' node at depth '${depth}'`\n );\n }\n });\n}\n\n/**\n * Validate an object that we expect to be a root node definition.\n * @param definition An object that we expect to be a root node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateRootNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"root\") {\n throw new Error(\"expected node type of 'root' for root node\");\n }\n\n // A root node cannot be the child of another node.\n if (depth > 0) {\n throw new Error(\"a root node cannot be the child of another node\");\n }\n\n // Check that, if the root node 'id' property is defined, it is a non-empty string.\n if (typeof definition.id !== \"undefined\" && (typeof definition.id !== \"string\" || definition.id.length === 0)) {\n throw new Error(\"expected non-empty string for 'id' property if defined for root node\");\n }\n\n // A root node is a decorator node, so must have a child node defined.\n if (typeof definition.child === \"undefined\") {\n throw new Error(\"expected property 'child' to be defined for root node\");\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n\n // Validate the child node of this decorator node.\n validateNode(definition.child, depth + 1);\n}\n\n/**\n * Validate an object that we expect to be a success node definition.\n * @param definition An object that we expect to be a success node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateSuccessNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"success\") {\n throw new Error(`expected node type of 'success' for success node at depth '${depth}'`);\n }\n\n // A success node is a decorator node, so must have a child node defined.\n if (typeof definition.child === \"undefined\") {\n throw new Error(`expected property 'child' to be defined for success node at depth '${depth}'`);\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n\n // Validate the child node of this decorator node.\n validateNode(definition.child, depth + 1);\n}\n\n/**\n * Validate an object that we expect to be a fail node definition.\n * @param definition An object that we expect to be a fail node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateFailNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"fail\") {\n throw new Error(`expected node type of 'fail' for fail node at depth '${depth}'`);\n }\n\n // A fail node is a decorator node, so must have a child node defined.\n if (typeof definition.child === \"undefined\") {\n throw new Error(`expected property 'child' to be defined for fail node at depth '${depth}'`);\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n\n // Validate the child node of this decorator node.\n validateNode(definition.child, depth + 1);\n}\n\n/**\n * Validate an object that we expect to be a flip node definition.\n * @param definition An object that we expect to be a flip node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateFlipNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"flip\") {\n throw new Error(`expected node type of 'flip' for flip node at depth '${depth}'`);\n }\n\n // A flip node is a decorator node, so must have a child node defined.\n if (typeof definition.child === \"undefined\") {\n throw new Error(`expected property 'child' to be defined for flip node at depth '${depth}'`);\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n\n // Validate the child node of this decorator node.\n validateNode(definition.child, depth + 1);\n}\n\n/**\n * Validate an object that we expect to be a repeat node definition.\n * @param definition An object that we expect to be a repeat node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateRepeatNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"repeat\") {\n throw new Error(`expected node type of 'repeat' for repeat node at depth '${depth}'`);\n }\n\n // A repeat node is a decorator node, so must have a child node defined.\n if (typeof definition.child === \"undefined\") {\n throw new Error(`expected property 'child' to be defined for repeat node at depth '${depth}'`);\n }\n\n // Check whether an 'iterations' property has been defined, it may not have been if this node is to repeat indefinitely.\n if (typeof definition.iterations !== \"undefined\") {\n if (Array.isArray(definition.iterations)) {\n // Check whether any elements of the array are not integer values.\n const containsNonInteger = !!definition.iterations.find((value: unknown) => !isInteger(value));\n\n // If the 'iterations' property is an array then it MUST contain two integer values.\n if (definition.iterations.length !== 2 || containsNonInteger) {\n throw new Error(\n `expected array containing two integer values for 'iterations' property if defined for repeat node at depth '${depth}'`\n );\n }\n\n // A repeat node must have a positive min and max iterations count if they are defined.\n if (definition.iterations[0] < 0 || definition.iterations[1] < 0) {\n throw new Error(\n `expected positive minimum and maximum iterations count for 'iterations' property if defined for repeat node at depth '${depth}'`\n );\n }\n\n // A repeat node must not have a minimum iterations count that exceeds the maximum iterations count.\n if (definition.iterations[0] > definition.iterations[1]) {\n throw new Error(\n `expected minimum iterations count that does not exceed the maximum iterations count for 'iterations' property if defined for repeat node at depth '${depth}'`\n );\n }\n } else if (isInteger(definition.iterations)) {\n // A repeat node must have a positive number of iterations if defined.\n if (definition.iterations < 0) {\n throw new Error(\n `expected positive iterations count for 'iterations' property if defined for repeat node at depth '${depth}'`\n );\n }\n } else {\n throw new Error(\n `expected integer value or array containing two integer values for 'iterations' property if defined for repeat node at depth '${depth}'`\n );\n }\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n\n // Validate the child node of this decorator node.\n validateNode(definition.child, depth + 1);\n}\n\n/**\n * Validate an object that we expect to be a retry node definition.\n * @param definition An object that we expect to be a retry node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateRetryNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"retry\") {\n throw new Error(`expected node type of 'retry' for retry node at depth '${depth}'`);\n }\n\n // A retry node is a decorator node, so must have a child node defined.\n if (typeof definition.child === \"undefined\") {\n throw new Error(`expected property 'child' to be defined for retry node at depth '${depth}'`);\n }\n\n // Check whether an 'attempts' property has been defined, it may not have been if this node is to retry indefinitely.\n if (typeof definition.attempts !== \"undefined\") {\n if (Array.isArray(definition.attempts)) {\n // Check whether any elements of the array are not integer values.\n const containsNonInteger = !!definition.attempts.find((value: unknown) => !isInteger(value));\n\n // If the 'attempts' property is an array then it MUST contain two integer values.\n if (definition.attempts.length !== 2 || containsNonInteger) {\n throw new Error(\n `expected array containing two integer values for 'attempts' property if defined for retry node at depth '${depth}'`\n );\n }\n\n // A retry node must have a positive min and max attempts count if they are defined.\n if (definition.attempts[0] < 0 || definition.attempts[1] < 0) {\n throw new Error(\n `expected positive minimum and maximum attempts count for 'attempts' property if defined for retry node at depth '${depth}'`\n );\n }\n\n // A retry node must not have a minimum attempts count that exceeds the maximum attempts count.\n if (definition.attempts[0] > definition.attempts[1]) {\n throw new Error(\n `expected minimum attempts count that does not exceed the maximum attempts count for 'attempts' property if defined for retry node at depth '${depth}'`\n );\n }\n } else if (isInteger(definition.attempts)) {\n // A retry node must have a positive number of attempts if defined.\n if (definition.attempts < 0) {\n throw new Error(\n `expected positive attempts count for 'attempts' property if defined for retry node at depth '${depth}'`\n );\n }\n } else {\n throw new Error(\n `expected integer value or array containing two integer values for 'attempts' property if defined for retry node at depth '${depth}'`\n );\n }\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n\n // Validate the child node of this decorator node.\n validateNode(definition.child, depth + 1);\n}\n\n/**\n * Validate an object that we expect to be a branch node definition.\n * @param definition An object that we expect to be a branch node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateBranchNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"branch\") {\n throw new Error(`expected node type of 'branch' for branch node at depth '${depth}'`);\n }\n\n // Check that the branch node 'ref' property is defined and is a non-empty string.\n if (typeof definition.ref !== \"string\" || definition.ref.length === 0) {\n throw new Error(`expected non-empty string for 'ref' property for branch node at depth '${depth}'`);\n }\n\n // It is invalid to define guard attributes for a branch node as they should be defined on the referenced root node.\n [\"while\", \"until\"].forEach((attributeName) => {\n if (typeof definition[attributeName] !== \"undefined\") {\n throw new Error(\n `guards should not be defined for branch nodes but guard '${attributeName}' was defined for branch node at depth '${depth}'`\n );\n }\n });\n\n // It is invalid to define callback attributes for a branch node as they should be defined on the referenced root node.\n [\"entry\", \"exit\", \"step\"].forEach((attributeName) => {\n if (typeof definition[attributeName] !== \"undefined\") {\n throw new Error(\n `callbacks should not be defined for branch nodes but callback '${attributeName}' was defined for branch node at depth '${depth}'`\n );\n }\n });\n}\n\n/**\n * Validate an object that we expect to be a action node definition.\n * @param definition An object that we expect to be a action node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateActionNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"action\") {\n throw new Error(`expected node type of 'action' for action node at depth '${depth}'`);\n }\n\n // The 'call' property must be defined for a action node definition.\n if (typeof definition.call !== \"string\" || definition.call.length === 0) {\n throw new Error(`expected non-empty string for 'call' property of action node at depth '${depth}'`);\n }\n\n // If any action function arguments have been defined then they must have been defined in an array.\n if (typeof definition.args !== \"undefined\" && !Array.isArray(definition.args)) {\n throw new Error(`expected array for 'args' property if defined for action node at depth '${depth}'`);\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n}\n\n/**\n * Validate an object that we expect to be a condition node definition.\n * @param definition An object that we expect to be a condition node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateConditionNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"condition\") {\n throw new Error(`expected node type of 'condition' for condition node at depth '${depth}'`);\n }\n\n // The 'call' property must be defined for a condition node definition.\n if (typeof definition.call !== \"string\" || definition.call.length === 0) {\n throw new Error(`expected non-empty string for 'call' property of condition node at depth '${depth}'`);\n }\n\n // If any condition function arguments have been defined then they must have been defined in an array.\n if (typeof definition.args !== \"undefined\" && !Array.isArray(definition.args)) {\n throw new Error(`expected array for 'args' property if defined for condition node at depth '${depth}'`);\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n}\n\n/**\n * Validate an object that we expect to be a wait node definition.\n * @param definition An object that we expect to be a wait node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateWaitNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"wait\") {\n throw new Error(`expected node type of 'wait' for wait node at depth '${depth}'`);\n }\n\n // Check whether a 'duration' property has been defined, it may not have been if this node is to wait indefinitely.\n if (typeof definition.duration !== \"undefined\") {\n if (Array.isArray(definition.duration)) {\n // Check whether any elements of the array are not integer values.\n const containsNonInteger = !!definition.duration.find((value: unknown) => !isInteger(value));\n\n // If the 'duration' property is an array then it MUST contain two integer values.\n if (definition.duration.length !== 2 || containsNonInteger) {\n throw new Error(\n `expected array containing two integer values for 'duration' property if defined for wait node at depth '${depth}'`\n );\n }\n\n // A wait node must have a positive min and max duration value if they are defined.\n if (definition.duration[0] < 0 || definition.duration[1] < 0) {\n throw new Error(\n `expected positive minimum and maximum duration for 'duration' property if defined for wait node at depth '${depth}'`\n );\n }\n\n // A wait node must not have a minimum duration value that exceeds the maximum duration value.\n if (definition.duration[0] > definition.duration[1]) {\n throw new Error(\n `expected minimum duration value that does not exceed the maximum duration value for 'duration' property if defined for wait node at depth '${depth}'`\n );\n }\n } else if (isInteger(definition.duration)) {\n // A wait node must have a positive duration value if defined.\n if (definition.duration < 0) {\n throw new Error(\n `expected positive duration value for 'duration' property if defined for wait node at depth '${depth}'`\n );\n }\n } else {\n throw new Error(\n `expected integer value or array containing two integer values for 'duration' property if defined for wait node at depth '${depth}'`\n );\n }\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n}\n\n/**\n * Validate an object that we expect to be a sequence node definition.\n * @param definition An object that we expect to be a sequence node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateSequenceNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"sequence\") {\n throw new Error(`expected node type of 'sequence' for sequence node at depth '${depth}'`);\n }\n\n // A sequence node is a composite node, so must have a children nodes array defined.\n if (!Array.isArray(definition.children) || definition.children.length === 0) {\n throw new Error(`expected non-empty 'children' array to be defined for sequence node at depth '${depth}'`);\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n\n // Validate the child nodes of this composite node.\n definition.children.forEach((child: any) => validateNode(child, depth + 1));\n}\n\n/**\n * Validate an object that we expect to be a selector node definition.\n * @param definition An object that we expect to be a selector node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateSelectorNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"selector\") {\n throw new Error(`expected node type of 'selector' for selector node at depth '${depth}'`);\n }\n\n // A selector node is a composite node, so must have a children nodes array defined.\n if (!Array.isArray(definition.children) || definition.children.length === 0) {\n throw new Error(`expected non-empty 'children' array to be defined for selector node at depth '${depth}'`);\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n\n // Validate the child nodes of this composite node.\n definition.children.forEach((child: any) => validateNode(child, depth + 1));\n}\n\n/**\n * Validate an object that we expect to be a parallel node definition.\n * @param definition An object that we expect to be a parallel node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateParallelNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"parallel\") {\n throw new Error(`expected node type of 'parallel' for parallel node at depth '${depth}'`);\n }\n\n // A parallel node is a composite node, so must have a children nodes array defined.\n if (!Array.isArray(definition.children) || definition.children.length === 0) {\n throw new Error(`expected non-empty 'children' array to be defined for parallel node at depth '${depth}'`);\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n\n // Validate the child nodes of this composite node.\n definition.children.forEach((child: any) => validateNode(child, depth + 1));\n}\n\n/**\n * A helper function to create a failure validation result with the given error message.\n * @param errorMessage The validation failure error message.\n * @returns A failure validation result with the given error message.\n */\nfunction createValidationFailureResult(errorMessage: string): DefinitionValidationResult {\n return { succeeded: false, errorMessage };\n}\n", "import { ActionResult, Agent, GlobalFunction } from \"./Agent\";\nimport { RootNodeDefinition } from \"./BehaviourTreeDefinition\";\n\nexport type InvokerFunction = (args: any[]) => ActionResult;\n\n/**\n * A singleton used to store and lookup registered functions and subtrees.\n */\nexport default class Lookup {\n /**\n * The object holding any registered functions keyed on function name.\n */\n private static functionTable: { [key: string]: GlobalFunction } = {};\n /**\n * The object holding any registered subtree root node definitions keyed on tree name.\n */\n private static subtreeTable: { [key: string]: RootNodeDefinition } = {};\n\n /**\n * Gets the function with the specified name.\n * @param name The name of the function.\n * @returns The function with the specified name.\n */\n public static getFunc(name: string): GlobalFunction {\n return this.functionTable[name];\n }\n\n /**\n * Sets the function with the specified name for later lookup.\n * @param name The name of the function.\n * @param func The function.\n */\n public static setFunc(name: string, func: GlobalFunction): void {\n this.functionTable[name] = func;\n }\n\n /**\n * Gets the function invoker for the specified agent and function name.\n * If a function with the specified name exists on the agent object then it will\n * be returned, otherwise we will then check the registered functions for a match.\n * @param agent The agent instance that this behaviour tree is modelling behaviour for.\n * @param name The function name.\n * @returns The function invoker for the specified agent and function name.\n */\n static getFuncInvoker(agent: Agent, name: string): InvokerFunction | null {\n // Check whether the agent contains the specified function.\n const foundOnAgent = agent[name];\n if (foundOnAgent && typeof foundOnAgent === \"function\") {\n return (args: any[]): boolean | ActionResult => foundOnAgent.apply(agent, args);\n }\n\n // The agent does not contain the specified function but it may have been registered at some point.\n if (this.functionTable[name] && typeof this.functionTable[name] === \"function\") {\n return (args: any[]) => this.functionTable[name](agent, ...args.map((arg) => arg.value));\n }\n\n // We have no function to invoke.\n return null;\n }\n\n /**\n * Gets all registered subtree root node definitions.\n */\n static getSubtrees(): { [key: string]: RootNodeDefinition } {\n return this.subtreeTable;\n }\n\n /**\n * Sets the subtree with the specified name for later lookup.\n * @param name The name of the subtree.\n * @param subtree The subtree.\n */\n static setSubtree(name: string, subtree: RootNodeDefinition) {\n this.subtreeTable[name] = subtree;\n }\n\n /**\n * Removes the registered function or subtree with the specified name.\n * @param name The name of the registered function or subtree.\n */\n static remove(name: string) {\n delete this.functionTable[name];\n delete this.subtreeTable[name];\n }\n\n /**\n * Remove all registered functions and subtrees.\n */\n static empty() {\n this.functionTable = {};\n this.subtreeTable = {};\n }\n}\n", "import Node from \"../../nodes/Node\";\n\n/**\n * An exception thrown when evaluating node guard path conditions and a conditions fails.\n */\nexport default class GuardUnsatisifedException extends Error {\n /**\n * @param source The node at which a guard condition failed.\n */\n constructor(private source: Node) {\n super(\"A guard path condition has failed\");\n }\n\n /**\n * Gets whether the specified node is the node at which a guard condition failed.\n * @param node The node to check against the source node.\n * @returns Whether the specified node is the node at which a guard condition failed.\n */\n isSourceNode = (node: Node) => node === this.source;\n}\n", "import { Agent } from \"../../Agent\";\nimport Guard from \"./Guard\";\nimport Node from \"../../nodes/Node\";\nimport GuardUnsatisifedException from \"./GuardUnsatisifedException\";\n\nexport type GuardPathPart = {\n node: Node;\n guards: Guard[];\n};\n\n/**\n * Represents a path of node guards along a root-to-leaf tree path.\n */\nexport default class GuardPath {\n /**\n * @param nodes An array of objects defining a node instance -> guard link, ordered by node depth.\n */\n constructor(private nodes: GuardPathPart[]) {}\n\n /**\n * Evaluate guard conditions for all guards in the tree path, moving outwards from the root.\n * @param agent The agent, required for guard evaluation.\n * @returns An evaluation results object.\n */\n evaluate = (agent: Agent) => {\n // We need to evaluate guard conditions for nodes up the tree, moving outwards from the root.\n for (const details of this.nodes) {\n // There can be multiple guards per node.\n for (const guard of details.guards) {\n // Check whether the guard condition passes, and throw an exception if not.\n if (!guard.isSatisfied(agent)) {\n throw new GuardUnsatisifedException(details.node);\n }\n }\n }\n };\n}\n", "import { BehaviourTreeOptions } from \"../BehaviourTreeOptions\";\nimport State, { AnyState } from \"../State\";\nimport { Agent } from \"../Agent\";\nimport Leaf from \"./leaf/Leaf\";\nimport Attribute from \"../attributes/Attribute\";\nimport Entry from \"../attributes/callbacks/Entry\";\nimport Exit from \"../attributes/callbacks/Exit\";\nimport Step from \"../attributes/callbacks/Step\";\nimport Guard from \"../attributes/guards/Guard\";\nimport GuardPath from \"../attributes/guards/GuardPath\";\nimport GuardUnsatisifedException from \"../attributes/guards/GuardUnsatisifedException\";\n\n/**\n * A base node.\n */\nexport default abstract class Node {\n /**\n * The node uid.\n */\n private readonly uid: string = createNodeUid();\n /**\n * The node state.\n */\n private state: AnyState = State.READY;\n /**\n * The guard path to evaluate as part of a node update.\n */\n private guardPath: GuardPath | undefined;\n\n /**\n * @param type The node type.\n * @param attributes The node attributes.\n * @param args The node argument definitions.\n */\n constructor(private type: string, private attributes: Attribute[], private args: any[]) {}\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected abstract onUpdate(agent: Agent, options: BehaviourTreeOptions): void;\n\n /**\n * Gets the name of the node.\n */\n public abstract getName(): string;\n\n /**\n * Gets whether this node is a leaf node.\n */\n public abstract isLeafNode: () => this is Leaf;\n\n /**\n * Gets/Sets the state of the node.\n */\n getState = (): AnyState => this.state;\n setState = (value: AnyState): void => {\n this.state = value;\n };\n\n /**\n * Gets the unique id of the node.\n */\n getUid = () => this.uid;\n\n /**\n * Gets the type of the node.\n */\n getType = () => this.type;\n\n /**\n * Gets the node attributes.\n */\n getAttributes = () => this.attributes;\n\n /**\n * Gets the node arguments.\n */\n getArguments = () => this.args;\n\n /**\n * Gets the node attribute with the specified type, or null if it does not exist.\n */\n getAttribute(type: \"entry\" | \"ENTRY\"): Entry;\n getAttribute(type: \"exit\" | \"EXIT\"): Exit;\n getAttribute(type: \"step\" | \"STEP\"): Step;\n getAttribute(type: string): Attribute {\n return (\n this.getAttributes().filter((decorator) => decorator.type.toUpperCase() === type.toUpperCase())[0] || null\n );\n }\n\n /**\n * Gets the node attributes.\n */\n getGuardAttributes = (): Guard[] => this.getAttributes().filter((decorator) => decorator.isGuard()) as Guard[];\n\n /**\n * Sets the guard path to evaluate as part of a node update.\n */\n setGuardPath = (value: GuardPath) => (this.guardPath = value);\n\n /**\n * Gets whether a guard path is assigned to this node.\n */\n hasGuardPath = () => !!this.guardPath;\n\n /**\n * Gets whether this node is in the specified state.\n * @param value The value to compare to the node state.\n */\n public is(value: AnyState): boolean {\n return this.state === value;\n }\n\n /**\n * Reset the state of the node.\n */\n public reset(): void {\n this.setState(State.READY);\n }\n\n /**\n * Abort the running of this node.\n * @param agent The agent.\n */\n public abort(agent: Agent): void {\n // There is nothing to do if this node is not in the running state.\n if (!this.is(State.RUNNING)) {\n return;\n }\n\n // Reset the state of this node.\n this.reset();\n\n this.getAttribute(\"exit\")?.callAgentFunction(agent, false, true);\n }\n\n /**\n * Update the node.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n * @returns The result of the update.\n */\n public update(agent: Agent, options: BehaviourTreeOptions): void {\n // If this node is already in a 'SUCCEEDED' or 'FAILED' state then there is nothing to do.\n if (this.is(State.SUCCEEDED) || this.is(State.FAILED)) {\n return;\n }\n\n try {\n // Evaluate all of the guard path conditions for the current tree path.\n this.guardPath!.evaluate(agent);\n\n // If this node is in the READY state then call the ENTRY for this node if it exists.\n if (this.is(State.READY)) {\n this.getAttribute(\"entry\")?.callAgentFunction(agent);\n }\n\n this.getAttribute(\"step\")?.callAgentFunction(agent);\n\n // Do the actual update.\n this.onUpdate(agent, options);\n\n // If this node is now in a 'SUCCEEDED' or 'FAILED' state then call the EXIT for this node if it exists.\n if (this.is(State.SUCCEEDED) || this.is(State.FAILED)) {\n this.getAttribute(\"exit\")?.callAgentFunction(agent, this.is(State.SUCCEEDED), false);\n }\n } catch (error) {\n // If the error is a GuardUnsatisfiedException then we need to determine if this node is the source.\n if (error instanceof GuardUnsatisifedException && error.isSourceNode(this)) {\n // Abort the current node.\n this.abort(agent);\n\n // Any node that is the source of an abort will be a failed node.\n this.setState(State.FAILED);\n } else {\n throw error;\n }\n }\n }\n}\n\n/**\n * Create a randomly generated node uid.\n * @returns A randomly generated node uid.\n */\nfunction createNodeUid(): string {\n var S4 = function () {\n return (((1 + Math.random()) * 0x10000) | 0).toString(16).substring(1);\n };\n return S4() + S4() + \"-\" + S4() + \"-\" + S4() + \"-\" + S4() + \"-\" + S4() + S4() + S4();\n}\n", "import Node from \"../Node\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\n\n/**\n * A composite node that wraps child nodes.\n */\nexport default abstract class Composite extends Node {\n /**\n * @param type The node type.\n * @param attributes The node attributes.\n * @param children The child nodes.\n */\n constructor(type: string, attributes: Attribute[], protected children: Node[]) {\n super(type, attributes, []);\n }\n\n /**\n * Gets whether this node is a leaf node.\n */\n isLeafNode = () => false;\n\n /**\n * Gets the children of this node.\n */\n getChildren = () => this.children;\n\n /**\n * Reset the state of the node.\n */\n reset = () => {\n // Reset the state of this node.\n this.setState(State.READY);\n\n // Reset the state of any child nodes.\n this.getChildren().forEach((child) => child.reset());\n };\n\n /**\n * Abort the running of this node.\n * @param agent The agent.\n */\n abort = (agent: Agent) => {\n // There is nothing to do if this node is not in the running state.\n if (!this.is(State.RUNNING)) {\n return;\n }\n\n // Abort any child nodes.\n this.getChildren().forEach((child) => child.abort(agent));\n\n // Reset the state of this node.\n this.reset();\n\n this.getAttribute(\"exit\")?.callAgentFunction(agent, false, true);\n };\n}\n", "import Composite from \"./Composite\";\nimport State from \"../../State\";\nimport Node from \"../Node\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A PARALLEL node.\n * The child nodes are executed concurrently until one fails or all succeed.\n */\nexport default class Parallel extends Composite {\n /**\n * @param attributes The node attributes.\n * @param children The child nodes.\n */\n constructor(attributes: Attribute[], children: Node[]) {\n super(\"parallel\", attributes, children);\n }\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // Keep a count of the number of succeeded child nodes.\n let succeededCount = 0;\n\n let hasChildFailed = false;\n\n // Iterate over all of the children of this node.\n for (const child of this.children) {\n // If the child has never been updated or is running then we will need to update it now.\n if (child.getState() === State.READY || child.getState() === State.RUNNING) {\n // Update the child of this node.\n child.update(agent, options);\n }\n\n // If the current child has a state of 'SUCCEEDED' then we should move on to the next child.\n if (child.getState() === State.SUCCEEDED) {\n // The child node has succeeded, keep track of this to determine if all children have.\n succeededCount++;\n\n // The child node succeeded, but we have not finished checking every child node yet.\n continue;\n }\n\n // If the current child has a state of 'FAILED' then this node is also a 'FAILED' node.\n if (child.getState() === State.FAILED) {\n hasChildFailed = true;\n\n // There is no need to check the rest of the children.\n break;\n }\n\n // The node should be in the 'RUNNING' state.\n if (child.getState() !== State.RUNNING) {\n // The child node was not in an expected state.\n throw new Error(\"child node was not in an expected state.\");\n }\n }\n\n if (hasChildFailed) {\n // This node is a 'FAILED' node.\n this.setState(State.FAILED);\n\n // Abort every running child.\n for (const child of this.children) {\n if (child.getState() === State.RUNNING) {\n child.abort(agent);\n }\n }\n } else {\n // If all children have succeeded then this node has also succeeded, otherwise it is still running.\n this.setState(succeededCount === this.children.length ? State.SUCCEEDED : State.RUNNING);\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => \"PARALLEL\";\n}\n", "import Composite from \"./Composite\";\nimport Node from \"../Node\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A SELECTOR node.\n * The child nodes are executed in sequence until one succeeds or all fail.\n */\nexport default class Selector extends Composite {\n /**\n * @param attributes The node attributes.\n * @param children The child nodes.\n */\n constructor(attributes: Attribute[], protected children: Node[]) {\n super(\"selector\", attributes, children);\n }\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // Iterate over all of the children of this node.\n for (const child of this.children) {\n // If the child has never been updated or is running then we will need to update it now.\n if (child.getState() === State.READY || child.getState() === State.RUNNING) {\n // Update the child of this node.\n child.update(agent, options);\n }\n\n // If the current child has a state of 'SUCCEEDED' then this node is also a 'SUCCEEDED' node.\n if (child.getState() === State.SUCCEEDED) {\n // This node is a 'SUCCEEDED' node.\n this.setState(State.SUCCEEDED);\n\n // There is no need to check the rest of the selector nodes.\n return;\n }\n\n // If the current child has a state of 'FAILED' then we should move on to the next child.\n if (child.getState() === State.FAILED) {\n // Find out if the current child is the last one in the selector.\n // If it is then this sequence node has also failed.\n if (this.children.indexOf(child) === this.children.length - 1) {\n // This node is a 'FAILED' node.\n this.setState(State.FAILED);\n\n // There is no need to check the rest of the selector as we have completed it.\n return;\n } else {\n // The child node failed, try the next one.\n continue;\n }\n }\n\n // The node should be in the 'RUNNING' state.\n if (child.getState() === State.RUNNING) {\n // This node is a 'RUNNING' node.\n this.setState(State.RUNNING);\n\n // There is no need to check the rest of the selector as the current child is still running.\n return;\n }\n\n // The child node was not in an expected state.\n throw new Error(\"child node was not in an expected state.\");\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => \"SELECTOR\";\n}\n", "import Composite from \"./Composite\";\nimport Node from \"../Node\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A SEQUENCE node.\n * The child nodes are executed in sequence until one fails or all succeed.\n */\nexport default class Sequence extends Composite {\n /**\n * @param attributes The node attributes.\n * @param children The child nodes.\n */\n constructor(attributes: Attribute[], protected children: Node[]) {\n super(\"sequence\", attributes, children);\n }\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // Iterate over all of the children of this node.\n for (const child of this.children) {\n // If the child has never been updated or is running then we will need to update it now.\n if (child.getState() === State.READY || child.getState() === State.RUNNING) {\n // Update the child of this node.\n child.update(agent, options);\n }\n\n // If the current child has a state of 'SUCCEEDED' then we should move on to the next child.\n if (child.getState() === State.SUCCEEDED) {\n // Find out if the current child is the last one in the sequence.\n // If it is then this sequence node has also succeeded.\n if (this.children.indexOf(child) === this.children.length - 1) {\n // This node is a 'SUCCEEDED' node.\n this.setState(State.SUCCEEDED);\n\n // There is no need to check the rest of the sequence as we have completed it.\n return;\n } else {\n // The child node succeeded, but we have not finished the sequence yet.\n continue;\n }\n }\n\n // If the current child has a state of 'FAILED' then this node is also a 'FAILED' node.\n if (child.getState() === State.FAILED) {\n // This node is a 'FAILED' node.\n this.setState(State.FAILED);\n\n // There is no need to check the rest of the sequence.\n return;\n }\n\n // The node should be in the 'RUNNING' state.\n if (child.getState() === State.RUNNING) {\n // This node is a 'RUNNING' node.\n this.setState(State.RUNNING);\n\n // There is no need to check the rest of the sequence as the current child is still running.\n return;\n }\n\n // The child node was not in an expected state.\n throw new Error(\"child node was not in an expected state.\");\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => \"SEQUENCE\";\n}\n", "import createLotto from \"lotto-draw\";\n\nimport Node from \"../Node\";\nimport Composite from \"./Composite\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A LOTTO node.\n * A winning child is picked on the initial update of this node, based on ticket weighting.\n * The state of this node will match the state of the winning child.\n */\nexport default class Lotto extends Composite {\n /**\n * @param attributes The node attributes.\n * @param weights The child node weights.\n * @param children The child nodes.\n */\n constructor(attributes: Attribute[], private weights: number[] | undefined, children: Node[]) {\n super(\"lotto\", attributes, children);\n }\n\n /**\n * The child node selected to be the active one.\n */\n private selectedChild: Node | undefined;\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // If this node is in the READY state then we need to pick a winning child node.\n if (this.is(State.READY)) {\n // Create a lotto draw with which to randomly pick a child node to become the active one.\n const lottoDraw = createLotto({\n // Hook up the optional 'random' behaviour tree function option to the one used by 'lotto-draw'.\n random: options.random,\n // Pass in each child node as a participant in the lotto draw with their respective ticket count.\n participants: this.children.map((child, index) => [child, this.weights?.[index] || 1])\n });\n\n // Randomly pick a child based on ticket weighting, this will become the active child for this composite node.\n this.selectedChild = lottoDraw.draw() || undefined;\n }\n\n // If something went wrong and we don't have an active child then we should throw an error.\n if (!this.selectedChild) {\n throw new Error(\"failed to update lotto node as it has no active child\");\n }\n\n // If the selected child has never been updated or is running then we will need to update it now.\n if (this.selectedChild.getState() === State.READY || this.selectedChild.getState() === State.RUNNING) {\n this.selectedChild.update(agent, options);\n }\n\n // The state of the lotto node is the state of its selected child.\n this.setState(this.selectedChild.getState());\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => (this.weights ? `LOTTO [${this.weights.join(\",\")}]` : \"LOTTO\");\n}\n", "import Node from \"../Node\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\n\n/**\n * A decorator node that wraps a single child node.\n */\nexport default abstract class Decorator extends Node {\n /**\n * @param type The node type.\n * @param attributes The node attributes.\n * @param child The child node.\n */\n constructor(type: string, attributes: Attribute[], protected child: Node) {\n super(type, attributes, []);\n }\n\n /**\n * Gets whether this node is a leaf node.\n */\n isLeafNode = () => false;\n\n /**\n * Gets the children of this node.\n */\n getChildren = () => [this.child];\n\n /**\n * Reset the state of the node.\n */\n reset = () => {\n // Reset the state of this node.\n this.setState(State.READY);\n\n // Reset the state of the child node.\n this.child.reset();\n };\n\n /**\n * Abort the running of this node.\n * @param agent The agent.\n */\n abort = (agent: Agent) => {\n // There is nothing to do if this node is not in the running state.\n if (!this.is(State.RUNNING)) {\n return;\n }\n\n // Abort the child node.\n this.child.abort(agent);\n\n // Reset the state of this node.\n this.reset();\n\n this.getAttribute(\"exit\")?.callAgentFunction(agent, false, true);\n };\n}\n", "import Node from \"../Node\";\nimport Decorator from \"./Decorator\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A Fail node.\n * This node wraps a single child and will always move to the 'FAILED' state when the child moves to a 'SUCCEEDED' or 'FAILED' state.\n */\nexport default class Fail extends Decorator {\n /**\n * @param attributes The node attributes.\n * @param child The child node.\n */\n constructor(attributes: Attribute[], child: Node) {\n super(\"fail\", attributes, child);\n }\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // If the child has never been updated or is running then we will need to update it now.\n if (this.child.getState() === State.READY || this.child.getState() === State.RUNNING) {\n this.child.update(agent, options);\n }\n\n // The state of this node will depend in the state of its child.\n switch (this.child.getState()) {\n case State.RUNNING:\n this.setState(State.RUNNING);\n break;\n\n case State.SUCCEEDED:\n case State.FAILED:\n this.setState(State.FAILED);\n break;\n\n default:\n this.setState(State.READY);\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => \"FAIL\";\n}\n", "import Decorator from \"./Decorator\";\nimport State from \"../../State\";\nimport Node from \"../Node\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A Flip node.\n * This node wraps a single child and will flip the state of the child state.\n */\nexport default class Flip extends Decorator {\n /**\n * @param attributes The node attributes.\n * @param child The child node.\n */\n constructor(attributes: Attribute[], child: Node) {\n super(\"flip\", attributes, child);\n }\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // If the child has never been updated or is running then we will need to update it now.\n if (this.child.getState() === State.READY || this.child.getState() === State.RUNNING) {\n this.child.update(agent, options);\n }\n\n // The state of this node will depend in the state of its child.\n switch (this.child.getState()) {\n case State.RUNNING:\n this.setState(State.RUNNING);\n break;\n\n case State.SUCCEEDED:\n this.setState(State.FAILED);\n break;\n\n case State.FAILED:\n this.setState(State.SUCCEEDED);\n break;\n\n default:\n this.setState(State.READY);\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => \"FLIP\";\n}\n", "import Node from \"../Node\";\nimport Decorator from \"./Decorator\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A REPEAT node.\n * The node has a single child which can have:\n * -- A number of iterations for which to repeat the child node.\n * -- An infinite repeat loop if neither an iteration count or a condition function is defined.\n * The REPEAT node will stop and have a 'FAILED' state if its child is ever in a 'FAILED' state after an update.\n * The REPEAT node will attempt to move on to the next iteration if its child is ever in a 'SUCCEEDED' state.\n */\nexport default class Repeat extends Decorator {\n /**\n * @param attributes The node attributes.\n * @param iterations The number of iterations to repeat the child node.\n * @param iterationsMin The minimum possible number of iterations to repeat the child node.\n * @param iterationsMax The maximum possible number of iterations to repeat the child node.\n * @param child The child node.\n */\n constructor(\n attributes: Attribute[],\n private iterations: number | null,\n private iterationsMin: number | null,\n private iterationsMax: number | null,\n child: Node\n ) {\n super(\"repeat\", attributes, child);\n }\n\n /**\n * The number of target iterations to make.\n */\n private targetIterationCount: number | null = null;\n\n /**\n * The current iteration count.\n */\n private currentIterationCount: number = 0;\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // If this node is in the READY state then we need to reset the child and the target iteration count.\n if (this.is(State.READY)) {\n // Reset the child node.\n this.child.reset();\n\n // Reset the current iteration count.\n this.currentIterationCount = 0;\n\n // Set the target iteration count.\n this.setTargetIterationCount(options);\n }\n\n // Do a check to see if we can iterate. If we can then this node will move into the 'RUNNING' state.\n // If we cannot iterate then we have hit our target iteration count, which means that the node has succeeded.\n if (this.canIterate()) {\n // This node is in the running state and can do its initial iteration.\n this.setState(State.RUNNING);\n\n // We may have already completed an iteration, meaning that the child node will be in the SUCCEEDED state.\n // If this is the case then we will have to reset the child node now.\n if (this.child.getState() === State.SUCCEEDED) {\n this.child.reset();\n }\n\n // Update the child of this node.\n this.child.update(agent, options);\n\n // If the child moved into the FAILED state when we updated it then there is nothing left to do and this node has also failed.\n // If it has moved into the SUCCEEDED state then we have completed the current iteration.\n if (this.child.getState() === State.FAILED) {\n // The child has failed, meaning that this node has failed.\n this.setState(State.FAILED);\n\n return;\n } else if (this.child.getState() === State.SUCCEEDED) {\n // We have completed an iteration.\n this.currentIterationCount += 1;\n }\n } else {\n // This node is in the 'SUCCEEDED' state as we cannot iterate any more.\n this.setState(State.SUCCEEDED);\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => {\n if (this.iterations !== null) {\n return `REPEAT ${this.iterations}x`;\n } else if (this.iterationsMin !== null && this.iterationsMax !== null) {\n return `REPEAT ${this.iterationsMin}x-${this.iterationsMax}x`;\n } else {\n return \"REPEAT\";\n }\n };\n\n /**\n * Reset the state of the node.\n */\n reset = () => {\n // Reset the state of this node.\n this.setState(State.READY);\n\n // Reset the current iteration count.\n this.currentIterationCount = 0;\n\n // Reset the child node.\n this.child.reset();\n };\n\n /**\n * Gets whether an iteration can be made.\n * @returns Whether an iteration can be made.\n */\n private canIterate = () => {\n if (this.targetIterationCount !== null) {\n // We can iterate as long as we have not reached our target iteration count.\n return this.currentIterationCount < this.targetIterationCount;\n }\n\n // If neither an iteration count or a condition function were defined then we can iterate indefinitely.\n return true;\n };\n\n /**\n * Sets the target iteration count.\n * @param options The behaviour tree options object.\n */\n private setTargetIterationCount = (options: BehaviourTreeOptions) => {\n // Are we dealing with an explicit iteration count or will we be randomly picking a iteration count between the min and max iteration count.\n if (this.iterations !== null) {\n this.targetIterationCount = this.iterations;\n } else if (this.iterationsMin !== null && this.iterationsMax !== null) {\n // We will be picking a random iteration count between a min and max iteration count, if the optional 'random'\n // behaviour tree function option is defined then we will be using that, otherwise we will fall back to using Math.random.\n const random = typeof options.random === \"function\" ? options.random : Math.random;\n\n // Pick a random iteration count between a min and max iteration count.\n this.targetIterationCount = Math.floor(\n random() * (this.iterationsMax - this.iterationsMin + 1) + this.iterationsMin\n );\n } else {\n this.targetIterationCount = null;\n }\n };\n}\n", "import Node from \"../Node\";\nimport Decorator from \"./Decorator\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A RETRY node.\n * The node has a single child which can have:\n * -- A number of iterations for which to repeat the child node.\n * -- An infinite repeat loop if neither an iteration count or a condition function is defined.\n * The RETRY node will stop and have a 'SUCCEEDED' state if its child is ever in a 'SUCCEEDED' state after an update.\n * The RETRY node will attempt to move on to the next iteration if its child is ever in a 'FAILED' state.\n */\nexport default class Retry extends Decorator {\n /**\n * @param attributes The node attributes.\n * @param attempts The number of attempts to retry the child node.\n * @param attemptsMin The minimum possible number of attempts to retry the child node.\n * @param attemptsMax The maximum possible number of attempts to retry the child node.\n * @param child The child node.\n */\n constructor(\n attributes: Attribute[],\n private attempts: number | null,\n private attemptsMin: number | null,\n private attemptsMax: number | null,\n child: Node\n ) {\n super(\"retry\", attributes, child);\n }\n\n /**\n * The number of target attempts to make.\n */\n private targetAttemptCount: number | null = null;\n\n /**\n * The current attempt count.\n */\n private currentAttemptCount: number = 0;\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // If this node is in the READY state then we need to reset the child and the target attempt count.\n if (this.is(State.READY)) {\n // Reset the child node.\n this.child.reset();\n\n // Reset the current attempt count.\n this.currentAttemptCount = 0;\n\n // Set the target attempt count.\n this.setTargetAttemptCount(options);\n }\n\n // Do a check to see if we can attempt. If we can then this node will move into the 'RUNNING' state.\n // If we cannot attempt then we have hit our target attempt count, which means that the node has succeeded.\n if (this.canAttempt()) {\n // This node is in the running state and can do its initial attempt.\n this.setState(State.RUNNING);\n\n // We may have already completed an attempt, meaning that the child node will be in the FAILED state.\n // If this is the case then we will have to reset the child node now.\n if (this.child.getState() === State.FAILED) {\n this.child.reset();\n }\n\n // Update the child of this node.\n this.child.update(agent, options);\n\n // If the child moved into the SUCCEEDED state when we updated it then there is nothing left to do and this node has also succeeded.\n // If it has moved into the FAILED state then we have completed the current attempt.\n if (this.child.getState() === State.SUCCEEDED) {\n // The child has succeeded, meaning that this node has succeeded.\n this.setState(State.SUCCEEDED);\n\n return;\n } else if (this.child.getState() === State.FAILED) {\n // We have completed an attempt.\n this.currentAttemptCount += 1;\n }\n } else {\n // This node is in the 'FAILED' state as we cannot iterate any more.\n this.setState(State.FAILED);\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => {\n if (this.attempts !== null) {\n return `RETRY ${this.attempts}x`;\n } else if (this.attemptsMin !== null && this.attemptsMax !== null) {\n return `RETRY ${this.attemptsMin}x-${this.attemptsMax}x`;\n } else {\n return \"RETRY\";\n }\n };\n\n /**\n * Reset the state of the node.\n */\n reset = () => {\n // Reset the state of this node.\n this.setState(State.READY);\n\n // Reset the current attempt count.\n this.currentAttemptCount = 0;\n\n // Reset the child node.\n this.child.reset();\n };\n\n /**\n * Gets whether an attempt can be made.\n * @returns Whether an attempt can be made.\n */\n canAttempt = () => {\n if (this.targetAttemptCount !== null) {\n // We can attempt as long as we have not reached our target attempt count.\n return this.currentAttemptCount < this.targetAttemptCount;\n }\n\n // If neither an attempt count or a condition function were defined then we can attempt indefinitely.\n return true;\n };\n\n /**\n * Sets the target attempt count.\n * @param options The behaviour tree options object.\n */\n setTargetAttemptCount = (options: BehaviourTreeOptions) => {\n // Are we dealing with an explicit attempt count or will we be randomly picking an attempt count between the min and max attempt count.\n if (this.attempts !== null) {\n this.targetAttemptCount = this.attempts;\n } else if (this.attemptsMin !== null && this.attemptsMax !== null) {\n // We will be picking a random attempt count between a min and max attempt count, if the optional 'random'\n // behaviour tree function option is defined then we will be using that, otherwise we will fall back to using Math.random.\n const random = typeof options.random === \"function\" ? options.random : Math.random;\n\n // Pick a random attempt count between a min and max attempt count.\n this.targetAttemptCount = Math.floor(\n random() * (this.attemptsMax - this.attemptsMin + 1) + this.attemptsMin\n );\n } else {\n this.targetAttemptCount = null;\n }\n };\n}\n", "import Node from \"../Node\";\nimport Decorator from \"./Decorator\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A Root node.\n * The root node will have a single child.\n */\nexport default class Root extends Decorator {\n /**\n * @param attributes The node attributes.\n * @param child The child node.\n */\n constructor(attributes: Attribute[], child: Node) {\n super(\"root\", attributes, child);\n }\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // If the child has never been updated or is running then we will need to update it now.\n if (this.child.getState() === State.READY || this.child.getState() === State.RUNNING) {\n // Update the child of this node.\n this.child.update(agent, options);\n }\n\n // The state of the root node is the state of its child.\n this.setState(this.child.getState());\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => \"ROOT\";\n}\n", "import Node from \"../Node\";\nimport Decorator from \"./Decorator\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A Succeed node.\n * This node wraps a single child and will always move to the 'SUCCEEDED' state when the child moves to a 'SUCCEEDED' or 'FAILED' state.\n */\nexport default class Succeed extends Decorator {\n /**\n * @param attributes The node attributes.\n * @param child The child node.\n */\n constructor(attributes: Attribute[], child: Node) {\n super(\"succeed\", attributes, child);\n }\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // If the child has never been updated or is running then we will need to update it now.\n if (this.child.getState() === State.READY || this.child.getState() === State.RUNNING) {\n this.child.update(agent, options);\n }\n\n // The state of this node will depend in the state of its child.\n switch (this.child.getState()) {\n case State.RUNNING:\n this.setState(State.RUNNING);\n break;\n\n case State.SUCCEEDED:\n case State.FAILED:\n this.setState(State.SUCCEEDED);\n break;\n\n default:\n this.setState(State.READY);\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => \"SUCCEED\";\n}\n", "import Node from \"../Node\";\n\n/**\n * A leaf node.\n */\nexport default abstract class Leaf extends Node {\n /**\n * Gets whether this node is a leaf node.\n */\n isLeafNode = () => true;\n}\n", "import { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\nimport State, { CompleteState } from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Leaf from \"./Leaf\";\nimport Lookup from \"../../Lookup\";\nimport Attribute from \"../../attributes/Attribute\";\n\n/**\n * An Action leaf node.\n * This represents an immediate or ongoing state of behaviour.\n */\nexport default class Action extends Leaf {\n /**\n * @param attributes The node attributes.\n * @param actionName The action name.\n * @param actionArguments The array of action argument definitions.\n */\n constructor(attributes: Attribute[], private actionName: string, private actionArguments: any[]) {\n super(\"action\", attributes, actionArguments);\n }\n\n /**\n * Whether there is a pending update promise.\n */\n private isUsingUpdatePromise = false;\n\n /**\n * The finished state result of an update promise.\n */\n private updatePromiseStateResult: CompleteState | null = null;\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // If the result of this action depends on an update promise then there is nothing to do until\n // it resolves, unless there has been a value set as a result of the update promise resolving.\n if (this.isUsingUpdatePromise) {\n // Check whether the update promise has resolved with a state value.\n if (this.updatePromiseStateResult) {\n // Set the state of this node to match the state returned by the promise.\n this.setState(this.updatePromiseStateResult);\n }\n\n return;\n }\n\n // Attempt to get the invoker for the action function.\n const actionFuncInvoker = Lookup.getFuncInvoker(agent, this.actionName);\n\n // The action function should be defined.\n if (actionFuncInvoker === null) {\n throw new Error(\n `cannot update action node as the action '${this.actionName}' function is not defined on the agent and has not been registered`\n );\n }\n\n // Call the action function, the result of which may be:\n // - The finished state of this action node.\n // - A promise to return a finished node state.\n // - Undefined if the node should remain in the running state.\n const updateResult = actionFuncInvoker(this.actionArguments) as CompleteState | Promise;\n\n if (updateResult instanceof Promise) {\n updateResult.then(\n (result) => {\n // If 'isUpdatePromisePending' is null then the promise was cleared as it was resolving, probably via an abort of reset.\n if (!this.isUsingUpdatePromise) {\n return;\n }\n\n // Check to make sure the result is a valid finished state.\n if (result !== State.SUCCEEDED && result !== State.FAILED) {\n throw new Error(\n \"action node promise resolved with an invalid value, expected a State.SUCCEEDED or State.FAILED value to be returned\"\n );\n }\n\n // Set pending update promise state result to be processed on next update.\n this.updatePromiseStateResult = result;\n },\n (reason) => {\n // If 'isUpdatePromisePending' is null then the promise was cleared as it was resolving, probably via an abort of reset.\n if (!this.isUsingUpdatePromise) {\n return;\n }\n\n // Just throw whatever was returned as the rejection argument.\n throw new Error(reason);\n }\n );\n\n // This node will be in the 'RUNNING' state until the update promise resolves.\n this.setState(State.RUNNING);\n\n // We are now waiting for the promise returned by the use to resolve before we know what state this node is in.\n this.isUsingUpdatePromise = true;\n } else {\n // Validate the returned value.\n this.validateUpdateResult(updateResult);\n\n // Set the state of this node, this may be undefined, which just means that the node is still in the 'RUNNING' state.\n this.setState(updateResult || State.RUNNING);\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => this.actionName;\n\n /**\n * Reset the state of the node.\n */\n reset = () => {\n // Reset the state of this node.\n this.setState(State.READY);\n\n // There is no longer an update promise that we care about.\n this.isUsingUpdatePromise = false;\n this.updatePromiseStateResult = null;\n };\n\n /**\n * Validate the result of an update function call.\n * @param result The result of an update function call.\n */\n private validateUpdateResult = (result: CompleteState | boolean) => {\n switch (result) {\n case State.SUCCEEDED:\n case State.FAILED:\n case undefined:\n return;\n default:\n throw new Error(\n `action '${this.actionName}' 'onUpdate' returned an invalid response, expected an optional State.SUCCEEDED or State.FAILED value to be returned`\n );\n }\n };\n}\n", "import { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Leaf from \"./Leaf\";\nimport Lookup from \"../../Lookup\";\nimport Attribute from \"../../attributes/Attribute\";\n\n/**\n * A Condition leaf node.\n * This will succeed or fail immediately based on an agent predicate, without moving to the 'RUNNING' state.\n */\nexport default class Condition extends Leaf {\n /**\n * @param attributes The node attributes.\n * @param conditionName The name of the condition function.\n * @param conditionArguments The array of condition argument definitions.\n */\n constructor(attributes: Attribute[], private conditionName: string, private conditionArguments: any[]) {\n super(\"condition\", attributes, conditionArguments);\n }\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // Attempt to get the invoker for the condition function.\n const conditionFuncInvoker = Lookup.getFuncInvoker(agent, this.conditionName);\n\n // The condition function should be defined.\n if (conditionFuncInvoker === null) {\n throw new Error(\n `cannot update condition node as the condition '${this.conditionName}' function is not defined on the agent and has not been registered`\n );\n }\n\n // Call the condition function to determine the state of this node.\n this.setState(!!conditionFuncInvoker(this.conditionArguments) ? State.SUCCEEDED : State.FAILED);\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => this.conditionName;\n}\n", "import Leaf from \"./Leaf\";\nimport State from \"../../State\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { Agent } from \"../../Agent\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A WAIT node.\n * The state of this node will change to SUCCEEDED after a duration of time\n */\nexport default class Wait extends Leaf {\n /**\n * @param attributes The node attributes.\n * @param duration The duration that this node will wait to succeed in milliseconds.\n * @param durationMin The minimum possible duration in milliseconds that this node will wait to succeed.\n * @param durationMax The maximum possible duration in milliseconds that this node will wait to succeed.\n */\n constructor(\n attributes: Attribute[],\n private duration: number | null,\n private durationMin: number | null,\n private durationMax: number | null\n ) {\n super(\"wait\", attributes, []);\n }\n\n /**\n * The time in milliseconds at which this node was first updated.\n */\n private initialUpdateTime: number = 0;\n\n /**\n * The total duration in milliseconds that this node will be waiting for.\n */\n private totalDuration: number | null = null;\n\n /**\n * The duration in milliseconds that this node has been waiting for.\n */\n private waitedDuration: number = 0;\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // If this node is in the READY state then we need to set the initial update time.\n if (this.is(State.READY)) {\n // Set the initial update time.\n this.initialUpdateTime = new Date().getTime();\n\n // Set the initial waited duration.\n this.waitedDuration = 0;\n\n // Are we dealing with an explicit duration or will we be randomly picking a duration between the min and max duration.\n if (this.duration !== null) {\n this.totalDuration = this.duration;\n } else if (this.durationMin !== null && this.durationMax !== null) {\n // We will be picking a random duration between a min and max duration, if the optional 'random' behaviour tree\n // function option is defined then we will be using that, otherwise we will fall back to using Math.random.\n const random = typeof options.random === \"function\" ? options.random : Math.random;\n\n // Pick a random duration between a min and max duration.\n this.totalDuration = Math.floor(\n random() * (this.durationMax - this.durationMin + 1) + this.durationMin\n );\n } else {\n this.totalDuration = null;\n }\n\n // The node is now running until we finish waiting.\n this.setState(State.RUNNING);\n }\n\n // If we have no total duration then this wait node will wait indefinitely until it is aborted.\n if (this.totalDuration === null) {\n return;\n }\n\n // If we have a 'getDeltaTime' function defined as part of our options then we will use it to figure out how long we have waited for.\n if (typeof options.getDeltaTime === \"function\") {\n // Get the delta time.\n const deltaTime = options.getDeltaTime();\n\n // Our delta time must be a valid number and cannot be NaN.\n if (typeof deltaTime !== \"number\" || isNaN(deltaTime)) {\n throw new Error(\"The delta time must be a valid number and not NaN.\");\n }\n\n // Update the amount of time that this node has been waiting for based on the delta time.\n this.waitedDuration += deltaTime * 1000;\n } else {\n // We are not using a delta time, so we will just work out hom much time has passed since the first update.\n this.waitedDuration = new Date().getTime() - this.initialUpdateTime;\n }\n\n // Have we waited long enough?\n if (this.waitedDuration >= this.totalDuration) {\n // We have finished waiting!\n this.setState(State.SUCCEEDED);\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => {\n if (this.duration !== null) {\n return `WAIT ${this.duration}ms`;\n } else if (this.durationMin !== null && this.durationMax !== null) {\n return `WAIT ${this.durationMin}ms-${this.durationMax}ms`;\n } else {\n return \"WAIT\";\n }\n };\n}\n", "import Guard from \"./guards/Guard\";\n\nexport type AttributeDetails = {\n /** The attribute type. */\n type: string;\n\n /** The attribute arguments. */\n args: any[];\n};\n\n/**\n * A base node attribute.\n */\nexport default abstract class Attribute {\n /**\n * @param type The node attribute type.\n * @param args The array of attribute arguments.\n */\n constructor(public type: string, public args: any[]) {}\n\n /**\n * Gets the attribute details.\n */\n abstract getDetails(): TAttributeDetails;\n\n /**\n * Gets whether this attribute is a guard.\n */\n abstract isGuard: () => this is Guard;\n}\n", "import { Agent } from \"../../Agent\";\nimport Attribute, { AttributeDetails } from \"../Attribute\";\n\nexport type GuardAttributeDetails = {\n /** The name of the condition function that determines whether the guard is satisfied. */\n condition: string;\n} & AttributeDetails;\n\n/**\n * A base node guard attribute.\n */\nexport default abstract class Guard extends Attribute {\n /**\n * @param type The node attribute type.\n * @param args The array of decorator argument definitions.\n * @param condition The name of the condition function that determines whether the guard is satisfied.\n */\n constructor(type: string, args: any[], private condition: string) {\n super(type, args);\n }\n\n /**\n * Gets the name of the condition function that determines whether the guard is satisfied.\n */\n getCondition = () => this.condition;\n\n /**\n * Gets whether this attribute is a guard.\n */\n isGuard = () => true;\n\n /**\n * Gets the attribute details.\n */\n getDetails(): GuardAttributeDetails {\n return {\n type: this.type,\n args: this.args,\n condition: this.getCondition()\n };\n }\n\n /**\n * Gets whether the guard is satisfied.\n * @param agent The agent.\n * @returns Whether the guard is satisfied.\n */\n abstract isSatisfied(agent: Agent): boolean;\n}\n", "import Guard from \"./Guard\";\nimport Lookup from \"../../Lookup\";\nimport { Agent } from \"../../Agent\";\n\n/**\n * A WHILE guard which is satisfied as long as the given condition remains true.\n */\nexport default class While extends Guard {\n /**\n * @param condition The name of the condition function that determines whether the guard is satisfied.\n * @param args The array of decorator argument definitions.\n */\n constructor(condition: string, args: any[]) {\n super(\"while\", args, condition);\n }\n\n /**\n * Gets whether the guard is satisfied.\n * @param agent The agent.\n * @returns Whether the guard is satisfied.\n */\n isSatisfied = (agent: Agent) => {\n // Attempt to get the invoker for the condition function.\n const conditionFuncInvoker = Lookup.getFuncInvoker(agent, this.getCondition());\n\n // The condition function should be defined.\n if (conditionFuncInvoker === null) {\n throw new Error(\n `cannot evaluate node guard as the condition '${this.getCondition()}' function is not defined on the agent and has not been registered`\n );\n }\n\n // Call the condition function to determine whether this guard is satisfied.\n return !!conditionFuncInvoker(this.args);\n };\n}\n", "import Guard from \"./Guard\";\nimport Lookup from \"../../Lookup\";\nimport { Agent } from \"../../Agent\";\n\n/**\n * An UNTIL guard which is satisfied as long as the given condition remains false.\n */\nexport default class Until extends Guard {\n /**\n * @param condition The name of the condition function that determines whether the guard is satisfied.\n * @param args The array of decorator argument definitions.\n */\n constructor(condition: string, args: any[]) {\n super(\"until\", args, condition);\n }\n\n /**\n * Gets whether the guard is satisfied.\n * @param agent The agent.\n * @returns Whether the guard is satisfied.\n */\n isSatisfied = (agent: Agent) => {\n // Attempt to get the invoker for the condition function.\n const conditionFuncInvoker = Lookup.getFuncInvoker(agent, this.getCondition());\n\n // The condition function should be defined.\n if (conditionFuncInvoker === null) {\n throw new Error(\n `cannot evaluate node guard as the condition '${this.getCondition()}' function is not defined on the agent and has not been registered`\n );\n }\n\n // Call the condition function to determine whether this guard is satisfied.\n return !!!conditionFuncInvoker(this.args);\n };\n}\n", "import { Agent } from \"../../Agent\";\nimport Attribute, { AttributeDetails } from \"../Attribute\";\n\nexport type CallbackAttributeDetails = {\n /** The name of the agent function that is called. */\n functionName: string;\n} & AttributeDetails;\n\n/**\n * A base node callback attribute.\n */\nexport default abstract class Callback extends Attribute {\n /**\n * @param type The node attribute type.\n * @param args The array of decorator argument definitions.\n * @param functionName The name of the agent function to call.\n */\n constructor(type: string, args: any[], private functionName: string) {\n super(type, args);\n }\n\n /**\n * Gets the name of the agent function to call.\n */\n getFunctionName = () => this.functionName;\n\n /**\n * Gets whether this attribute is a guard.\n */\n isGuard = () => false;\n\n /**\n * Gets the attribute details.\n */\n getDetails(): CallbackAttributeDetails {\n return {\n type: this.type,\n args: this.args,\n functionName: this.getFunctionName()\n };\n }\n\n /**\n * Attempt to call the agent function that this callback refers to.\n * @param agent The agent.\n */\n abstract callAgentFunction: (agent: Agent, isSuccess: boolean, isAborted: boolean) => void;\n}\n", "import Callback from \"./Callback\";\nimport Lookup from \"../../Lookup\";\nimport { Agent } from \"../../Agent\";\n\n/**\n * An ENTRY callback which defines an agent function to call when the associated node is updated and moves out of running state.\n */\nexport default class Entry extends Callback {\n /**\n * @param functionName The name of the agent function to call.\n * @param args The array of callback argument definitions.\n */\n constructor(functionName: string, args: any[]) {\n super(\"entry\", args, functionName);\n }\n\n /**\n * Attempt to call the agent function that this callback refers to.\n * @param agent The agent.\n */\n callAgentFunction = (agent: Agent) => {\n // Attempt to get the invoker for the callback function.\n const callbackFuncInvoker = Lookup.getFuncInvoker(agent, this.getFunctionName());\n\n // The callback function should be defined.\n if (callbackFuncInvoker === null) {\n throw new Error(\n `cannot call entry function '${this.getFunctionName()}' as is not defined on the agent and has not been registered`\n );\n }\n\n // Call the callback function.\n callbackFuncInvoker(this.args);\n };\n}\n", "import Callback from \"./Callback\";\nimport Lookup from \"../../Lookup\";\nimport { Agent } from \"../../Agent\";\n\n/**\n * A STEP callback which defines an agent function to call when the associated node is updated.\n */\nexport default class Step extends Callback {\n /**\n * @param functionName The name of the agent function to call.\n * @param args The array of callback argument definitions.\n */\n constructor(functionName: string, args: any[]) {\n super(\"step\", args, functionName);\n }\n\n /**\n * Attempt to call the agent function that this callback refers to.\n * @param agent The agent.\n */\n callAgentFunction = (agent: Agent) => {\n // Attempt to get the invoker for the callback function.\n const callbackFuncInvoker = Lookup.getFuncInvoker(agent, this.getFunctionName());\n\n // The callback function should be defined.\n if (callbackFuncInvoker === null) {\n throw new Error(\n `cannot call step function '${this.getFunctionName()}' as is not defined on the agent and has not been registered`\n );\n }\n\n // Call the callback function.\n callbackFuncInvoker(this.args);\n };\n}\n", "import Callback from \"./Callback\";\nimport Lookup from \"../../Lookup\";\nimport { Agent } from \"../../Agent\";\n\n/**\n * An EXIT callback which defines an agent function to call when the associated node is updated and moves to a finished state or is aborted.\n */\nexport default class Exit extends Callback {\n /**\n * @param functionName The name of the agent function to call.\n * @param args The array of callback argument definitions.\n */\n constructor(functionName: string, args: any[]) {\n super(\"exit\", args, functionName);\n }\n\n /**\n * Attempt to call the agent function that this callback refers to.\n * @param agent The agent.\n * @param isSuccess Whether the decorated node was left with a success state.\n * @param isAborted Whether the decorated node was aborted.\n */\n callAgentFunction = (agent: Agent, isSuccess: boolean, isAborted: boolean) => {\n // Attempt to get the invoker for the callback function.\n const callbackFuncInvoker = Lookup.getFuncInvoker(agent, this.getFunctionName());\n\n // The callback function should be defined.\n if (callbackFuncInvoker === null) {\n throw new Error(\n `cannot call exit function '${this.getFunctionName()}' as is not defined on the agent and has not been registered`\n );\n }\n\n // Call the callback function\n callbackFuncInvoker([{ value: { succeeded: isSuccess, aborted: isAborted } }, ...this.args]);\n };\n}\n", "import { AnyNodeDefinition, RootNodeDefinition } from \"./BehaviourTreeDefinition\";\nimport GuardPath, { GuardPathPart } from \"./attributes/guards/GuardPath\";\nimport { validateBranchSubtreeLinks } from \"./BehaviourTreeDefinitionValidator\";\nimport { isInteger } from \"./BehaviourTreeDefinitionUtilities\";\nimport Node from \"./nodes/Node\";\nimport Composite from \"./nodes/composite/Composite\";\nimport Decorator from \"./nodes/decorator/Decorator\";\nimport Parallel from \"./nodes/composite/Parallel\";\nimport Selector from \"./nodes/composite/Selector\";\nimport Sequence from \"./nodes/composite/Sequence\";\nimport Lotto from \"./nodes/composite/Lotto\";\nimport Fail from \"./nodes/decorator/Fail\";\nimport Flip from \"./nodes/decorator/Flip\";\nimport Repeat from \"./nodes/decorator/Repeat\";\nimport Retry from \"./nodes/decorator/Retry\";\nimport Root from \"./nodes/decorator/Root\";\nimport Succeed from \"./nodes/decorator/Succeed\";\nimport Action from \"./nodes/leaf/Action\";\nimport Condition from \"./nodes/leaf/Condition\";\nimport Wait from \"./nodes/leaf/Wait\";\nimport Lookup from \"./Lookup\";\nimport Attribute from \"./attributes/Attribute\";\nimport While from \"./attributes/guards/While\";\nimport Until from \"./attributes/guards/Until\";\nimport Entry from \"./attributes/callbacks/Entry\";\nimport Step from \"./attributes/callbacks/Step\";\nimport Exit from \"./attributes/callbacks/Exit\";\n\n/**\n * A type representing any node instance in a behaviour tree.\n */\ntype AnyNode =\n | Root\n | Action\n | Condition\n | Wait\n | Sequence\n | Selector\n | Lotto\n | Parallel\n | Repeat\n | Retry\n | Flip\n | Succeed\n | Fail;\n\n/**\n * A type defining a mapping of root node identifiers to root node definitions.\n */\ntype RootNodeDefinitionMap = { [key: string | symbol]: RootNodeDefinition };\n\n/**\n * A symbol to use as the main root key in any root node mappings.\n */\nconst MAIN_ROOT_NODE_KEY = Symbol(\"__root__\");\n\n/**\n * Build and populate the root nodes based on the provided definition, assuming that the definition has been validated.\n * @param definition The root node definitions.\n * @returns The built and populated root node definitions.\n */\nexport default function buildRootNode(definition: RootNodeDefinition[]): Root {\n // Create a mapping of root node identifers to root node definitions, including globally registered subtree root node definitions.\n const rootNodeDefinitionMap = createRootNodeDefinitionMap(definition);\n\n // Now that we have all of our root node definitons (those part of the tree definition and those globally\n // registered) we should validate the definition. This will also double-check that we dont have any circular\n // dependencies in our branch -> subtree references and that we have no broken branch -> subtree links.\n validateBranchSubtreeLinks(definition, true);\n\n // Create our populated tree of node instances, starting with our main root node.\n const rootNode = nodeFactory(rootNodeDefinitionMap[MAIN_ROOT_NODE_KEY], rootNodeDefinitionMap) as Root;\n\n // Set a guard path on every leaf of the tree to evaluate as part of each update.\n applyLeafNodeGuardPaths(rootNode);\n\n // We only need to return the main root node.\n return rootNode;\n}\n\n/**\n * A factory function which creates a node instance based on the specified definition.\n * @param definition The node definition.\n * @param rootNodeDefinitionMap The mapping of root node identifers to root node definitions, including globally registered subtree root node definitions.\n * @returns A node instance based on the specified definition.\n */\nfunction nodeFactory(definition: AnyNodeDefinition, rootNodeDefinitionMap: RootNodeDefinitionMap): AnyNode {\n // Get the attributes for the node.\n const attributes = nodeAttributesFactory(definition);\n\n // Create the node instance based on the definition type.\n switch (definition.type) {\n case \"root\":\n return new Root(attributes, nodeFactory(definition.child, rootNodeDefinitionMap));\n\n case \"repeat\":\n let iterations: number | null = null;\n let iterationsMin: number | null = null;\n let iterationsMax: number | null = null;\n\n if (Array.isArray(definition.iterations)) {\n iterationsMin = definition.iterations[0];\n iterationsMax = definition.iterations[1];\n } else if (isInteger(definition.iterations)) {\n iterations = definition.iterations!;\n }\n\n return new Repeat(\n attributes,\n iterations,\n iterationsMin,\n iterationsMax,\n nodeFactory(definition.child, rootNodeDefinitionMap)\n );\n\n case \"retry\":\n let attempts: number | null = null;\n let attemptsMin: number | null = null;\n let attemptsMax: number | null = null;\n\n if (Array.isArray(definition.attempts)) {\n attemptsMin = definition.attempts[0];\n attemptsMax = definition.attempts[1];\n } else if (isInteger(definition.attempts)) {\n attempts = definition.attempts!;\n }\n\n return new Retry(\n attributes,\n attempts,\n attemptsMin,\n attemptsMax,\n nodeFactory(definition.child, rootNodeDefinitionMap)\n );\n\n case \"flip\":\n return new Flip(attributes, nodeFactory(definition.child, rootNodeDefinitionMap));\n\n case \"succeed\":\n return new Succeed(attributes, nodeFactory(definition.child, rootNodeDefinitionMap));\n\n case \"fail\":\n return new Fail(attributes, nodeFactory(definition.child, rootNodeDefinitionMap));\n\n case \"sequence\":\n return new Sequence(\n attributes,\n definition.children.map((child) => nodeFactory(child, rootNodeDefinitionMap))\n );\n\n case \"selector\":\n return new Selector(\n attributes,\n definition.children.map((child) => nodeFactory(child, rootNodeDefinitionMap))\n );\n\n case \"parallel\":\n return new Parallel(\n attributes,\n definition.children.map((child) => nodeFactory(child, rootNodeDefinitionMap))\n );\n\n case \"lotto\":\n return new Lotto(\n attributes,\n definition.weights,\n definition.children.map((child) => nodeFactory(child, rootNodeDefinitionMap))\n );\n\n case \"branch\":\n return nodeFactory(rootNodeDefinitionMap[definition.ref].child, rootNodeDefinitionMap);\n\n case \"action\":\n return new Action(attributes, definition.call, definition.args || []);\n\n case \"condition\":\n return new Condition(attributes, definition.call, definition.args || []);\n\n case \"wait\":\n let duration: number | null = null;\n let durationMin: number | null = null;\n let durationMax: number | null = null;\n\n if (Array.isArray(definition.duration)) {\n durationMin = definition.duration[0];\n durationMax = definition.duration[1];\n } else if (isInteger(definition.duration)) {\n duration = definition.duration!;\n }\n\n return new Wait(attributes, duration, durationMin, durationMax);\n }\n}\n\n/**\n * Creates an array of node attribute instances based on the specified node definition.\n * @param definition The node definition.\n * @returns An array of node attribute instances based on the specified node definition.\n */\nfunction nodeAttributesFactory(definition: AnyNodeDefinition): Attribute[] {\n const attributes: Attribute[] = [];\n\n if (definition.while) {\n attributes.push(new While(definition.while.call, definition.while.args ?? []));\n }\n\n if (definition.until) {\n attributes.push(new Until(definition.until.call, definition.until.args ?? []));\n }\n\n if (definition.entry) {\n attributes.push(new Entry(definition.entry.call, definition.entry.args ?? []));\n }\n\n if (definition.step) {\n attributes.push(new Step(definition.step.call, definition.step.args ?? []));\n }\n\n if (definition.exit) {\n attributes.push(new Exit(definition.exit.call, definition.exit.args ?? []));\n }\n\n return attributes;\n}\n\n/**\n * Creates a mapping of root node identifers to root node definitions, mixing in globally registered subtree root node definitions.\n * @param definition The root node definitions.\n * @returns A mapping of root node identifers to root node definitions, including globally registered subtree root node definitions.\n */\nfunction createRootNodeDefinitionMap(definition: RootNodeDefinition[]): RootNodeDefinitionMap {\n // Create a mapping of root node identifers to root node definitions.\n const rootNodeMap: RootNodeDefinitionMap = {};\n\n // Add in any registered subtree root node definitions.\n for (const [name, rootNodeDefinition] of Object.entries(Lookup.getSubtrees())) {\n // The name used when registering the subtree will be used as the root node identifier.\n rootNodeMap[name] = { ...rootNodeDefinition, id: name };\n }\n\n // Populate the map with the root node definitions that were included with the tree definition.\n // We do this after adding any registered subtrees as we want these to take presedence.\n for (const rootNodeDefinition of definition) {\n rootNodeMap[rootNodeDefinition.id ?? MAIN_ROOT_NODE_KEY] = rootNodeDefinition;\n }\n\n return rootNodeMap;\n}\n\n/**\n * Applies a guard path to every leaf of the tree to evaluate as part of each update.\n * @param root The main root tree node.\n */\nfunction applyLeafNodeGuardPaths(root: Root) {\n const nodePaths: Node[][] = [];\n\n const findLeafNodes = (path: Node[], node: Node) => {\n // Add the current node to the path.\n path = path.concat(node);\n\n // Check whether the current node is a leaf node.\n if (node.isLeafNode()) {\n nodePaths.push(path);\n } else {\n (node as Composite | Decorator).getChildren().forEach((child) => findLeafNodes(path, child));\n }\n };\n\n // Find all leaf node paths, starting from the root.\n findLeafNodes([], root);\n\n nodePaths.forEach((path) => {\n // Each node in the current path will have to be assigned a guard path, working from the root outwards.\n for (let depth = 0; depth < path.length; depth++) {\n // Get the node in the path at the current depth.\n const currentNode = path[depth];\n\n // The node may already have been assigned a guard path, if so just skip it.\n if (currentNode.hasGuardPath()) {\n continue;\n }\n\n // Create the guard path for the current node.\n const guardPath = new GuardPath(\n path\n .slice(0, depth + 1)\n .map((node) => ({ node, guards: node.getGuardAttributes() }))\n .filter((details) => details.guards.length > 0)\n );\n\n // Assign the guard path to the current node.\n currentNode.setGuardPath(guardPath);\n }\n });\n}\n", "import State, { AnyState } from \"./State\";\nimport Lookup from \"./Lookup\";\nimport Node from \"./nodes/Node\";\nimport Root from \"./nodes/decorator/Root\";\nimport Composite from \"./nodes/composite/Composite\";\nimport Decorator from \"./nodes/decorator/Decorator\";\nimport { Agent, GlobalFunction } from \"./Agent\";\nimport { CallbackAttributeDetails } from \"./attributes/callbacks/Callback\";\nimport { GuardAttributeDetails } from \"./attributes/guards/Guard\";\nimport { BehaviourTreeOptions } from \"./BehaviourTreeOptions\";\nimport { convertMDSLToJSON } from \"./mdsl/MDSLDefinitionParser\";\nimport { RootNodeDefinition } from \"./BehaviourTreeDefinition\";\nimport { validateJSONDefinition } from \"./BehaviourTreeDefinitionValidator\";\nimport buildRootNode from \"./BehaviourTreeBuilder\";\n\n// Purely for outside inspection of the tree.\nexport type FlattenedTreeNode = {\n id: string;\n type: string;\n caption: string;\n state: AnyState;\n guards: GuardAttributeDetails[];\n callbacks: CallbackAttributeDetails[];\n args: any[];\n parentId: string | null;\n};\n\n/**\n * A representation of a behaviour tree.\n */\nexport class BehaviourTree {\n /**\n * The main root tree node.\n */\n public readonly rootNode: Root;\n\n /**\n * Creates a new instance of the BehaviourTree class.\n * @param definition The behaviour tree definition.\n * @param agent The agent instance that this behaviour tree is modelling behaviour for.\n * @param options The behaviour tree options object.\n */\n constructor(\n definition: string | RootNodeDefinition | RootNodeDefinition[],\n private agent: Agent,\n private options: BehaviourTreeOptions = {}\n ) {\n // The tree definition must be defined.\n if (!definition) {\n throw new Error(\"the tree definition must be a string ro\");\n }\n\n // The agent must be defined and not null.\n if (typeof agent !== \"object\" || agent === null) {\n throw new Error(\"the agent must be defined and not null\");\n }\n\n try {\n // Parse the behaviour tree definition, create the populated tree of behaviour tree nodes, and get the root.\n this.rootNode = this._createRootNode(definition);\n } catch (exception) {\n // There was an issue in trying build and populate the behaviour tree.\n throw new Error(`error building tree: ${(exception as Error).message}`);\n }\n }\n\n /**\n * Gets whether the tree is in the RUNNING state.\n * @returns true if the tree is in the RUNNING state, otherwise false.\n */\n isRunning() {\n return this.rootNode.getState() === State.RUNNING;\n }\n\n /**\n * Gets the current tree state of SUCCEEDED, FAILED, READY or RUNNING.\n * @returns The current tree state.\n */\n getState() {\n return this.rootNode.getState();\n }\n\n /**\n * Step the tree.\n * 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.\n * 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\n * 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.\n *\n * 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.\n */\n step() {\n // If the root node has already been stepped to completion then we need to reset it.\n if (this.rootNode.getState() === State.SUCCEEDED || this.rootNode.getState() === State.FAILED) {\n this.rootNode.reset();\n }\n\n try {\n this.rootNode.update(this.agent, this.options);\n } catch (exception) {\n throw new Error(`error stepping tree: ${(exception as Error).message}`);\n }\n }\n\n /**\n * Resets the tree from the root node outwards to each nested node, giving each a state of READY.\n */\n reset() {\n this.rootNode.reset();\n }\n\n /**\n * Gets the flattened details of every node in the tree.\n * @returns The flattened details of every node in the tree.\n */\n getFlattenedNodeDetails(): FlattenedTreeNode[] {\n // Create an empty flattened array of tree nodes.\n const flattenedTreeNodes: FlattenedTreeNode[] = [];\n\n /**\n * Helper function to process a node instance and push details into the flattened tree nodes array.\n * @param node The current node.\n * @param parentUid The UID of the node parent, or null if the node is the main root node.\n */\n const processNode = (node: Node, parentUid: string | null) => {\n // Get the guard and callback attribute details for this node.\n const guards = node\n .getAttributes()\n .filter((attribute) => attribute.isGuard())\n .map((attribute) => attribute.getDetails()) as GuardAttributeDetails[];\n const callbacks = node\n .getAttributes()\n .filter((attribute) => !attribute.isGuard())\n .map((attribute) => attribute.getDetails()) as CallbackAttributeDetails[];\n\n // Push the current node into the flattened nodes array.\n flattenedTreeNodes.push({\n id: node.getUid(),\n type: node.getType(),\n caption: node.getName(),\n state: node.getState(),\n guards,\n callbacks,\n args: node.getArguments(),\n parentId: parentUid\n });\n\n // Process each of the nodes children if it is not a leaf node.\n if (!node.isLeafNode()) {\n (node as Composite | Decorator)\n .getChildren()\n .forEach((child) => processNode(child, (node as Composite | Decorator).getUid()));\n }\n };\n\n // Convert the nested node structure into a flattened array of node details.\n processNode(this.rootNode, null);\n\n return flattenedTreeNodes;\n }\n\n /**\n * Registers the action/condition/guard/callback function or subtree with the given name.\n * @param name The name of the function or subtree to register.\n * @param value The function or subtree definition to register.\n */\n static register(name: string, value: GlobalFunction | string | RootNodeDefinition) {\n // Are we going to register a action/condition/guard/callback function?\n if (typeof value === \"function\") {\n Lookup.setFunc(name, value);\n return;\n }\n\n // We are not registering an action/condition/guard/callback function, so we must be registering a subtree.\n if (typeof value === \"string\") {\n let rootNodeDefinitions: RootNodeDefinition[];\n\n // We will assume that any string passed in will be a mdsl definition.\n try {\n rootNodeDefinitions = convertMDSLToJSON(value);\n } catch (exception) {\n throw new Error(`error registering definition, invalid MDSL: ${(exception as Error).message}`);\n }\n\n // This function should only ever be called with a definition containing a single unnamed root node.\n if (rootNodeDefinitions.length != 1 || rootNodeDefinitions[0].id !== null) {\n throw new Error(\"error registering definition: expected a single unnamed root node\");\n }\n\n try {\n // We should validate the subtree as we don't want invalid subtrees available via the lookup.\n const { succeeded, errorMessage } = validateJSONDefinition(rootNodeDefinitions[0]);\n\n // Did our validation fail without error?\n if (!succeeded) {\n throw new Error(errorMessage);\n }\n } catch (exception) {\n throw new Error(`error registering definition: ${(exception as Error).message}`);\n }\n\n // Everything seems hunky-dory, register the subtree.\n Lookup.setSubtree(name, rootNodeDefinitions[0]);\n } else if (typeof value === \"object\" && !Array.isArray(value)) {\n // We will assume that any object passed in is a root node definition.\n\n try {\n // We should validate the subtree as we don't want invalid subtrees available via the lookup.\n const { succeeded, errorMessage } = validateJSONDefinition(value);\n\n // Did our validation fail without error?\n if (!succeeded) {\n throw new Error(errorMessage);\n }\n } catch (exception) {\n throw new Error(`error registering definition: ${(exception as Error).message}`);\n }\n\n // Everything seems hunky-dory, register the subtree.\n Lookup.setSubtree(name, value);\n } else {\n throw new Error(\"unexpected value, expected string mdsl definition, root node json definition or function\");\n }\n }\n\n /**\n * Unregisters the registered action/condition/guard/callback function or subtree with the given name.\n * @param name The name of the registered action/condition/guard/callback function or subtree to unregister.\n */\n static unregister(name: string): void {\n Lookup.remove(name);\n }\n\n /**\n * Unregister all registered action/condition/guard/callback functions and subtrees.\n */\n static unregisterAll(): void {\n Lookup.empty();\n }\n\n /**\n * Parses a behaviour tree definition and creates a tree of behaviour tree nodes populated at a root.\n * @param {string | RootNodeDefinition | RootNodeDefinition[]} definition The behaviour tree definition.\n * @returns The root behaviour tree node.\n */\n private _createRootNode(definition: string | RootNodeDefinition | RootNodeDefinition[]): Root {\n let resolvedDefinition: RootNodeDefinition | RootNodeDefinition[];\n\n // If the definition is a string then we will assume that it is an mdsl string which needs to be converted to a JSON definition.\n if (typeof definition === \"string\") {\n try {\n resolvedDefinition = convertMDSLToJSON(definition);\n } catch (exception) {\n throw new Error(`invalid mdsl definition: ${(exception as Error).message}`);\n }\n } else {\n // The definition is not a string, so we should assume that it is already a JSON definition.\n resolvedDefinition = definition;\n }\n\n // Build and populate the root node.\n return buildRootNode(Array.isArray(resolvedDefinition) ? resolvedDefinition : [resolvedDefinition]);\n }\n}\n"], + "mappings": "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", + "names": ["Participant", "isNullOrUndefined", "Lotto", "createLotto", "State", "createLotto"] } diff --git a/dist/nodes/composite/Lotto.d.ts b/dist/nodes/composite/Lotto.d.ts index 2a2a001..a374d86 100644 --- a/dist/nodes/composite/Lotto.d.ts +++ b/dist/nodes/composite/Lotto.d.ts @@ -9,13 +9,13 @@ import { BehaviourTreeOptions } from "../../BehaviourTreeOptions"; * The state of this node will match the state of the winning child. */ export default class Lotto extends Composite { - private tickets; + private weights; /** * @param attributes The node attributes. - * @param tickets The child node tickets. + * @param weights The child node weights. * @param children The child nodes. */ - constructor(attributes: Attribute[], tickets: number[], children: Node[]); + constructor(attributes: Attribute[], weights: number[] | undefined, children: Node[]); /** * The child node selected to be the active one. */ diff --git a/src/BehaviourTreeBuilder.ts b/src/BehaviourTreeBuilder.ts index 0329023..56b129a 100644 --- a/src/BehaviourTreeBuilder.ts +++ b/src/BehaviourTreeBuilder.ts @@ -1,6 +1,7 @@ import { AnyNodeDefinition, RootNodeDefinition } from "./BehaviourTreeDefinition"; import GuardPath, { GuardPathPart } from "./attributes/guards/GuardPath"; import { validateBranchSubtreeLinks } from "./BehaviourTreeDefinitionValidator"; +import { isInteger } from "./BehaviourTreeDefinitionUtilities"; import Node from "./nodes/Node"; import Composite from "./nodes/composite/Composite"; import Decorator from "./nodes/decorator/Decorator"; @@ -68,9 +69,9 @@ export default function buildRootNode(definition: RootNodeDefinition[]): Root { validateBranchSubtreeLinks(definition, true); // Create our populated tree of node instances, starting with our main root node. - const rootNode = nodeFactory(rootNodeDefinitionMap[MAIN_ROOT_NODE_KEY]) as Root; + const rootNode = nodeFactory(rootNodeDefinitionMap[MAIN_ROOT_NODE_KEY], rootNodeDefinitionMap) as Root; - // Set a guard path on every leaf of the tree to evaluate as part of its update. + // Set a guard path on every leaf of the tree to evaluate as part of each update. applyLeafNodeGuardPaths(rootNode); // We only need to return the main root node. @@ -80,21 +81,114 @@ export default function buildRootNode(definition: RootNodeDefinition[]): Root { /** * A factory function which creates a node instance based on the specified definition. * @param definition The node definition. + * @param rootNodeDefinitionMap The mapping of root node identifers to root node definitions, including globally registered subtree root node definitions. * @returns A node instance based on the specified definition. */ -function nodeFactory(definition: AnyNodeDefinition): AnyNode { +function nodeFactory(definition: AnyNodeDefinition, rootNodeDefinitionMap: RootNodeDefinitionMap): AnyNode { // Get the attributes for the node. const attributes = nodeAttributesFactory(definition); // Create the node instance based on the definition type. switch (definition.type) { case "root": - return new Root(attributes, nodeFactory(definition.child)); + return new Root(attributes, nodeFactory(definition.child, rootNodeDefinitionMap)); - // ... + case "repeat": + let iterations: number | null = null; + let iterationsMin: number | null = null; + let iterationsMax: number | null = null; - default: - throw new Error(`unexpected node type of '${definition.type}'`); + if (Array.isArray(definition.iterations)) { + iterationsMin = definition.iterations[0]; + iterationsMax = definition.iterations[1]; + } else if (isInteger(definition.iterations)) { + iterations = definition.iterations!; + } + + return new Repeat( + attributes, + iterations, + iterationsMin, + iterationsMax, + nodeFactory(definition.child, rootNodeDefinitionMap) + ); + + case "retry": + let attempts: number | null = null; + let attemptsMin: number | null = null; + let attemptsMax: number | null = null; + + if (Array.isArray(definition.attempts)) { + attemptsMin = definition.attempts[0]; + attemptsMax = definition.attempts[1]; + } else if (isInteger(definition.attempts)) { + attempts = definition.attempts!; + } + + return new Retry( + attributes, + attempts, + attemptsMin, + attemptsMax, + nodeFactory(definition.child, rootNodeDefinitionMap) + ); + + case "flip": + return new Flip(attributes, nodeFactory(definition.child, rootNodeDefinitionMap)); + + case "succeed": + return new Succeed(attributes, nodeFactory(definition.child, rootNodeDefinitionMap)); + + case "fail": + return new Fail(attributes, nodeFactory(definition.child, rootNodeDefinitionMap)); + + case "sequence": + return new Sequence( + attributes, + definition.children.map((child) => nodeFactory(child, rootNodeDefinitionMap)) + ); + + case "selector": + return new Selector( + attributes, + definition.children.map((child) => nodeFactory(child, rootNodeDefinitionMap)) + ); + + case "parallel": + return new Parallel( + attributes, + definition.children.map((child) => nodeFactory(child, rootNodeDefinitionMap)) + ); + + case "lotto": + return new Lotto( + attributes, + definition.weights, + definition.children.map((child) => nodeFactory(child, rootNodeDefinitionMap)) + ); + + case "branch": + return nodeFactory(rootNodeDefinitionMap[definition.ref].child, rootNodeDefinitionMap); + + case "action": + return new Action(attributes, definition.call, definition.args || []); + + case "condition": + return new Condition(attributes, definition.call, definition.args || []); + + case "wait": + let duration: number | null = null; + let durationMin: number | null = null; + let durationMax: number | null = null; + + if (Array.isArray(definition.duration)) { + durationMin = definition.duration[0]; + durationMax = definition.duration[1]; + } else if (isInteger(definition.duration)) { + duration = definition.duration!; + } + + return new Wait(attributes, duration, durationMin, durationMax); } } diff --git a/src/BehaviourTreeDefinitionUtilities.ts b/src/BehaviourTreeDefinitionUtilities.ts index 165e8eb..780e9c5 100644 --- a/src/BehaviourTreeDefinitionUtilities.ts +++ b/src/BehaviourTreeDefinitionUtilities.ts @@ -83,3 +83,12 @@ export function flattenDefinition(nodeDefinition: AnyNodeDefinition): AnyNodeDef export function isInteger(value: unknown): boolean { return typeof value === "number" && Math.floor(value) === value; } + +/** + * Determines whether the passed value is null or undefined. + * @param value The value to check. + * @returns Whether the passed value is null or undefined. + */ +export function isNullOrUndefined(value: unknown): boolean { + return typeof value === "undefined" || value === null; +} diff --git a/src/BehaviourTreeDefinitionValidator.ts b/src/BehaviourTreeDefinitionValidator.ts index 7006acb..7a5fe3d 100644 --- a/src/BehaviourTreeDefinitionValidator.ts +++ b/src/BehaviourTreeDefinitionValidator.ts @@ -448,7 +448,28 @@ function validateRepeatNode(definition: any, depth: number): void { `expected array containing two integer values for 'iterations' property if defined for repeat node at depth '${depth}'` ); } - } else if (!isInteger(definition.iterations)) { + + // A repeat node must have a positive min and max iterations count if they are defined. + if (definition.iterations[0] < 0 || definition.iterations[1] < 0) { + throw new Error( + `expected positive minimum and maximum iterations count for 'iterations' property if defined for repeat node at depth '${depth}'` + ); + } + + // A repeat node must not have a minimum iterations count that exceeds the maximum iterations count. + if (definition.iterations[0] > definition.iterations[1]) { + throw new Error( + `expected minimum iterations count that does not exceed the maximum iterations count for 'iterations' property if defined for repeat node at depth '${depth}'` + ); + } + } else if (isInteger(definition.iterations)) { + // A repeat node must have a positive number of iterations if defined. + if (definition.iterations < 0) { + throw new Error( + `expected positive iterations count for 'iterations' property if defined for repeat node at depth '${depth}'` + ); + } + } else { throw new Error( `expected integer value or array containing two integer values for 'iterations' property if defined for repeat node at depth '${depth}'` ); @@ -490,7 +511,28 @@ function validateRetryNode(definition: any, depth: number): void { `expected array containing two integer values for 'attempts' property if defined for retry node at depth '${depth}'` ); } - } else if (!isInteger(definition.attempts)) { + + // A retry node must have a positive min and max attempts count if they are defined. + if (definition.attempts[0] < 0 || definition.attempts[1] < 0) { + throw new Error( + `expected positive minimum and maximum attempts count for 'attempts' property if defined for retry node at depth '${depth}'` + ); + } + + // A retry node must not have a minimum attempts count that exceeds the maximum attempts count. + if (definition.attempts[0] > definition.attempts[1]) { + throw new Error( + `expected minimum attempts count that does not exceed the maximum attempts count for 'attempts' property if defined for retry node at depth '${depth}'` + ); + } + } else if (isInteger(definition.attempts)) { + // A retry node must have a positive number of attempts if defined. + if (definition.attempts < 0) { + throw new Error( + `expected positive attempts count for 'attempts' property if defined for retry node at depth '${depth}'` + ); + } + } else { throw new Error( `expected integer value or array containing two integer values for 'attempts' property if defined for retry node at depth '${depth}'` ); @@ -612,7 +654,28 @@ function validateWaitNode(definition: any, depth: number): void { `expected array containing two integer values for 'duration' property if defined for wait node at depth '${depth}'` ); } - } else if (!isInteger(definition.duration)) { + + // A wait node must have a positive min and max duration value if they are defined. + if (definition.duration[0] < 0 || definition.duration[1] < 0) { + throw new Error( + `expected positive minimum and maximum duration for 'duration' property if defined for wait node at depth '${depth}'` + ); + } + + // A wait node must not have a minimum duration value that exceeds the maximum duration value. + if (definition.duration[0] > definition.duration[1]) { + throw new Error( + `expected minimum duration value that does not exceed the maximum duration value for 'duration' property if defined for wait node at depth '${depth}'` + ); + } + } else if (isInteger(definition.duration)) { + // A wait node must have a positive duration value if defined. + if (definition.duration < 0) { + throw new Error( + `expected positive duration value for 'duration' property if defined for wait node at depth '${depth}'` + ); + } + } else { throw new Error( `expected integer value or array containing two integer values for 'duration' property if defined for wait node at depth '${depth}'` ); diff --git a/src/mdsl/MDSLDefinitionParser.ts b/src/mdsl/MDSLDefinitionParser.ts index 3f870b4..03e4337 100644 --- a/src/mdsl/MDSLDefinitionParser.ts +++ b/src/mdsl/MDSLDefinitionParser.ts @@ -16,7 +16,13 @@ import { SucceedNodeDefinition, WaitNodeDefinition } from "../BehaviourTreeDefinition"; -import { isCompositeNode, isDecoratorNode, isLeafNode, isRootNode } from "../BehaviourTreeDefinitionUtilities"; +import { + isCompositeNode, + isDecoratorNode, + isLeafNode, + isNullOrUndefined, + isRootNode +} from "../BehaviourTreeDefinitionUtilities"; import { parseArgumentTokens } from "./MDSLNodeArgumentParser"; import { parseAttributeTokens } from "./MDSLNodeAttributeParser"; import { @@ -77,6 +83,12 @@ function convertTokensToJSONDefinition( const pushNode = (node: AnyNodeDefinition) => { // If the node is a root node then we need to create a new tree stack array with the root node at the root. if (isRootNode(node)) { + // We need to double-check that this root node is not the child of another node. + // We can do this by checking whether the top tree stack is not empty (contains an existing node) + if (treeStacks[treeStacks.length - 1]?.length) { + throw new Error("a root node cannot be the child of another node"); + } + // Add the root node definition to our array of all parsed root node definitions. rootNodes.push(node); @@ -120,20 +132,24 @@ function convertTokensToJSONDefinition( } }; - // A helper function used to pop node definitions off of the stack. - const popNode = () => { + // A helper function used to pop the top-most node definition off of the tree stack and return it. + const popNode = (): AnyNodeDefinition | null => { + let poppedNode: AnyNodeDefinition | null = null; + // Get the current tree stack that we are populating. const topTreeStack = treeStacks[treeStacks.length - 1]; // Pop the top-most node in the current tree stack if there is one. if (topTreeStack.length) { - topTreeStack.pop(); + poppedNode = topTreeStack.pop() as AnyNodeDefinition; } // We don't want any empty tree stacks in our stack of tree stacks. if (!topTreeStack.length) { treeStacks.pop(); } + + return poppedNode; }; // We should keep processing the raw tokens until we run out of them. @@ -215,7 +231,13 @@ function convertTokensToJSONDefinition( case "}": { // The '}' character closes the current scope and means that we have to pop a node off of the current stack. - popNode(); + const poppedNode = popNode(); + + // Now that we have a node definition we can carry out any validation that may require the node to be fully populated. + if (poppedNode) { + validatePoppedNode(poppedNode); + } + break; } @@ -356,9 +378,26 @@ function createRepeatNode( if (nodeArguments.length === 1) { // A static iteration count was defined. node.iterations = nodeArguments[0].value as number; + + // A repeat node must have a positive number of iterations if defined. + if (node.iterations < 0) { + throw new Error("a repeat node must have a positive number of iterations if defined"); + } } else if (nodeArguments.length === 2) { // A minimum and maximum iteration count was defined. node.iterations = [nodeArguments[0].value as number, nodeArguments[1].value as number]; + + // A repeat node must have a positive min and max iteration count if they are defined. + if (node.iterations[0] < 0 || node.iterations[1] < 0) { + throw new Error("a repeat node must have a positive minimum and maximum iteration count if defined"); + } + + // A repeat node must not have an minimum iteration count that exceeds the maximum iteration count. + if (node.iterations[0] > node.iterations[1]) { + throw new Error( + "a repeat node must not have a minimum iteration count that exceeds the maximum iteration count" + ); + } } else { // An incorrect number of iteration counts was defined. throw new Error("invalid number of repeat node iteration count arguments defined"); @@ -403,9 +442,26 @@ function createRetryNode(tokens: string[], stringLiteralPlaceholders: StringLite if (nodeArguments.length === 1) { // A static attempt count was defined. node.attempts = nodeArguments[0].value as number; + + // A retry node must have a positive number of attempts if defined. + if (node.attempts < 0) { + throw new Error("a retry node must have a positive number of attempts if defined"); + } } else if (nodeArguments.length === 2) { // A minimum and maximum attempt count was defined. node.attempts = [nodeArguments[0].value as number, nodeArguments[1].value as number]; + + // A retry node must have a positive min and max attempts count if they are defined. + if (node.attempts[0] < 0 || node.attempts[1] < 0) { + throw new Error("a retry node must have a positive minimum and maximum attempt count if defined"); + } + + // A retry node must not have a minimum attempt count that exceeds the maximum attempt count. + if (node.attempts[0] > node.attempts[1]) { + throw new Error( + "a retry node must not have a minimum attempt count that exceeds the maximum attempt count" + ); + } } else { // An incorrect number of attempt counts was defined. throw new Error("invalid number of retry node attempt count arguments defined"); @@ -623,9 +679,24 @@ function createWaitNode(tokens: string[], stringLiteralPlaceholders: StringLiter if (nodeArguments.length === 1) { // An explicit duration was defined. node.duration = nodeArguments[0].value as number; + + // If an explict duration was defined then it must be a positive number. + if (node.duration < 0) { + throw new Error("a wait node must have a positive duration"); + } } else if (nodeArguments.length === 2) { // Min and max duration bounds were defined from which a random duration will be picked. node.duration = [nodeArguments[0].value as number, nodeArguments[1].value as number]; + + // A wait node must have a positive min and max duration. + if (node.duration[0] < 0 || node.duration[1] < 0) { + throw new Error("a wait node must have a positive minimum and maximum duration"); + } + + // A wait node must not have a minimum duration that exceeds the maximum duration. + if (node.duration[0] > node.duration[1]) { + throw new Error("a wait node must not have a minimum duration that exceeds the maximum duration"); + } } else if (nodeArguments.length > 2) { // An incorrect number of duration arguments were defined. throw new Error("invalid number of wait node duration arguments defined"); @@ -657,3 +728,19 @@ function createBranchNode( // Return the branch node definition. return { type: "branch", ref: nodeArguments[0].value }; } + +/** + * Validate a fully-populated node definition that was popped off of the tree stack. + * @param node The popped node to validate. + */ +function validatePoppedNode(node: AnyNodeDefinition): void { + // Decorators MUST have a child defined. + if (isDecoratorNode(node) && isNullOrUndefined(node.child)) { + throw new Error(`a ${node.type} node must have a single child node defined`); + } + + // Composites MUST have at least one child defined. + if (isCompositeNode(node) && !node.children?.length) { + throw new Error(`a ${node.type} node must have at least a single child node defined`); + } +} diff --git a/src/nodes/composite/Lotto.ts b/src/nodes/composite/Lotto.ts index d41823a..46d586d 100644 --- a/src/nodes/composite/Lotto.ts +++ b/src/nodes/composite/Lotto.ts @@ -15,10 +15,10 @@ import { BehaviourTreeOptions } from "../../BehaviourTreeOptions"; export default class Lotto extends Composite { /** * @param attributes The node attributes. - * @param tickets The child node tickets. + * @param weights The child node weights. * @param children The child nodes. */ - constructor(attributes: Attribute[], private tickets: number[], children: Node[]) { + constructor(attributes: Attribute[], private weights: number[] | undefined, children: Node[]) { super("lotto", attributes, children); } @@ -40,7 +40,7 @@ export default class Lotto extends Composite { // Hook up the optional 'random' behaviour tree function option to the one used by 'lotto-draw'. random: options.random, // Pass in each child node as a participant in the lotto draw with their respective ticket count. - participants: this.children.map((child, index) => [child, this.tickets[index] || 1]) + participants: this.children.map((child, index) => [child, this.weights?.[index] || 1]) }); // Randomly pick a child based on ticket weighting, this will become the active child for this composite node. @@ -64,5 +64,5 @@ export default class Lotto extends Composite { /** * Gets the name of the node. */ - getName = () => (this.tickets.length ? `LOTTO [${this.tickets.join(",")}]` : "LOTTO"); + getName = () => (this.weights ? `LOTTO [${this.weights.join(",")}]` : "LOTTO"); } From a9bc8435054419dc6d2d1193657c586136a4bc8f Mon Sep 17 00:00:00 2001 From: Nikolas Howard Date: Wed, 7 Feb 2024 17:36:08 +0000 Subject: [PATCH 22/48] playing around with test file format for mdsl and json split --- dist/bundle.js | 6 ++--- dist/bundle.js.map | 4 ++-- dist/index.d.ts | 3 ++- dist/index.js | 6 ++--- dist/index.js.map | 4 ++-- src/BehaviourTree.ts | 7 +++--- src/index.ts | 3 ++- test/behaviourTree.test.js | 45 +++++++++++++++++++++++--------------- 8 files changed, 45 insertions(+), 33 deletions(-) diff --git a/dist/bundle.js b/dist/bundle.js index 18715e2..4604e83 100644 --- a/dist/bundle.js +++ b/dist/bundle.js @@ -2132,11 +2132,11 @@ var mistreevous = (() => { constructor(definition, agent, options = {}) { this.agent = agent; this.options = options; - if (!definition) { - throw new Error("the tree definition must be a string ro"); + if (isNullOrUndefined(definition)) { + throw new Error("tree definition not defined"); } if (typeof agent !== "object" || agent === null) { - throw new Error("the agent must be defined and not null"); + throw new Error("the agent must be an object and not null"); } try { this.rootNode = this._createRootNode(definition); diff --git a/dist/bundle.js.map b/dist/bundle.js.map index deae203..1418261 100644 --- a/dist/bundle.js.map +++ b/dist/bundle.js.map @@ -1,7 +1,7 @@ { "version": 3, "sources": ["../node_modules/lotto-draw/dist/Participant.js", "../node_modules/lotto-draw/dist/Utilities.js", "../node_modules/lotto-draw/dist/Lotto.js", "../node_modules/lotto-draw/dist/createLotto.js", "../node_modules/lotto-draw/dist/index.js", "../src/index.ts", "../src/State.ts", "../src/BehaviourTreeDefinitionUtilities.ts", "../src/mdsl/MDSLUtilities.ts", "../src/mdsl/MDSLNodeArgumentParser.ts", "../src/mdsl/MDSLNodeAttributeParser.ts", "../src/mdsl/MDSLDefinitionParser.ts", "../src/BehaviourTreeDefinitionValidator.ts", "../src/Lookup.ts", "../src/attributes/guards/GuardUnsatisifedException.ts", "../src/attributes/guards/GuardPath.ts", "../src/nodes/Node.ts", "../src/nodes/composite/Composite.ts", "../src/nodes/composite/Parallel.ts", "../src/nodes/composite/Selector.ts", "../src/nodes/composite/Sequence.ts", "../src/nodes/composite/Lotto.ts", "../src/nodes/decorator/Decorator.ts", "../src/nodes/decorator/Fail.ts", "../src/nodes/decorator/Flip.ts", "../src/nodes/decorator/Repeat.ts", "../src/nodes/decorator/Retry.ts", "../src/nodes/decorator/Root.ts", "../src/nodes/decorator/Succeed.ts", "../src/nodes/leaf/Leaf.ts", "../src/nodes/leaf/Action.ts", "../src/nodes/leaf/Condition.ts", "../src/nodes/leaf/Wait.ts", "../src/attributes/Attribute.ts", "../src/attributes/guards/Guard.ts", "../src/attributes/guards/While.ts", "../src/attributes/guards/Until.ts", "../src/attributes/callbacks/Callback.ts", "../src/attributes/callbacks/Entry.ts", "../src/attributes/callbacks/Step.ts", "../src/attributes/callbacks/Exit.ts", "../src/BehaviourTreeBuilder.ts", "../src/BehaviourTree.ts"], - "sourcesContent": ["\"use strict\";\r\nObject.defineProperty(exports, \"__esModule\", { value: true });\r\nexports.Participant = void 0;\r\n/**\r\n * A participant that holds a number of tickets.\r\n */\r\nvar Participant = /** @class */ (function () {\r\n /**\r\n * Creates an instance of the Participant class.\r\n * @param participant The actual participant.\r\n * @param tickets The number of tickets held by the participant.\r\n */\r\n function Participant(participant, tickets) {\r\n if (tickets === void 0) { tickets = 1; }\r\n this._participant = participant;\r\n this._tickets = tickets;\r\n }\r\n Object.defineProperty(Participant.prototype, \"participant\", {\r\n /** Gets the actual participant. */\r\n get: function () {\r\n return this._participant;\r\n },\r\n enumerable: false,\r\n configurable: true\r\n });\r\n Object.defineProperty(Participant.prototype, \"tickets\", {\r\n /** Gets or sets the number of tickets held by the participant. */\r\n get: function () {\r\n return this._tickets;\r\n },\r\n set: function (value) {\r\n this._tickets = value;\r\n },\r\n enumerable: false,\r\n configurable: true\r\n });\r\n return Participant;\r\n}());\r\nexports.Participant = Participant;\r\n", "\"use strict\";\r\nObject.defineProperty(exports, \"__esModule\", { value: true });\r\nexports.isNaturalNumber = exports.isNullOrUndefined = void 0;\r\n/**\r\n * Gets whether the value provided is null or undefined.\r\n * @param value The value to check.\r\n * @returns Whether the value provided is null or undefined.\r\n */\r\nfunction isNullOrUndefined(value) {\r\n return value === null || value === undefined;\r\n}\r\nexports.isNullOrUndefined = isNullOrUndefined;\r\n/**\r\n * Gets whether the value provided is a natural number.\r\n * @param value The value to check.\r\n * @returns Whether the value provided is a natural number.\r\n */\r\nfunction isNaturalNumber(value) {\r\n return typeof value === \"number\" && value >= 1 && Math.floor(value) === value;\r\n}\r\nexports.isNaturalNumber = isNaturalNumber;\r\n", "\"use strict\";\r\nObject.defineProperty(exports, \"__esModule\", { value: true });\r\nexports.Lotto = void 0;\r\nvar Participant_1 = require(\"./Participant\");\r\nvar Utilities_1 = require(\"./Utilities\");\r\n/**\r\n * Represents a lotto consisting of a number of pickable ticket-holding participants.\r\n */\r\nvar Lotto = /** @class */ (function () {\r\n /**\r\n * Creates a new instance of Lotto.\r\n * @param customRandom The custom RNG to use in place of Math.random().\r\n */\r\n function Lotto(customRandom) {\r\n /** The array of participants that are holding tickets in the lotto. */\r\n this._participants = [];\r\n this._customRandom = customRandom;\r\n }\r\n /**\r\n * Adds a participant with the specified number of tickets, or adds to the participant ticket count if the participant already holds tickets.\r\n * @param participant The participant to add or to increase the ticket count for if they already hold tickets.\r\n * @param tickets The number of tickets, defaults to 1.\r\n * @returns The Lotto instance.\r\n */\r\n Lotto.prototype.add = function (participant, tickets) {\r\n if (tickets === void 0) { tickets = 1; }\r\n // Check that we have a valid ticket count.\r\n if (!(0, Utilities_1.isNaturalNumber)(tickets)) {\r\n throw new Error(\"tickets value must be a natural number\");\r\n }\r\n // Check whether this participant has already been added.\r\n var existingParticipant = this._participants.find(function (part) { return part.participant === participant; });\r\n if (existingParticipant) {\r\n // The participant has already been added to the lotto so just add to their ticket count.\r\n existingParticipant.tickets += tickets;\r\n }\r\n else {\r\n // The participant is not part of the lotto so we should add them.\r\n this._participants.push(new Participant_1.Participant(participant, tickets));\r\n }\r\n return this;\r\n };\r\n /**\r\n * Removes the specified number of tickets for the given participant from the draw, or all tickets if a ticket number is not defined.\r\n * @param participant The participant to remove tickets for.\r\n * @param tickets The number of tickets to remove, or undefined if all tickets are to be removed.\r\n * @returns The Lotto instance.\r\n */\r\n Lotto.prototype.remove = function (participant, tickets) {\r\n // Attempt to get the existing participant.\r\n var existingParticipant = this._participants.find(function (part) { return part.participant === participant; });\r\n // There is nothing to do if the specified participant isn't even part of the lotto.\r\n if (!existingParticipant) {\r\n return this;\r\n }\r\n // Check whether a tickets value was given.\r\n if (tickets !== undefined) {\r\n // Check that we have a valid ticket count.\r\n if (!(0, Utilities_1.isNaturalNumber)(tickets)) {\r\n throw new Error(\"tickets value must be a natural number\");\r\n }\r\n existingParticipant.tickets -= tickets;\r\n // If the participant no longer holds any tickets then they should be removed.\r\n if (existingParticipant.tickets < 1) {\r\n this._participants = this._participants.filter(function (part) { return part !== existingParticipant; });\r\n }\r\n }\r\n else {\r\n // We are removing all tickets for the participant so just remove them from the lotto.\r\n this._participants = this._participants.filter(function (part) { return part !== existingParticipant; });\r\n }\r\n return this;\r\n };\r\n /**\r\n * Draw a winning ticket and return the participant that holds the ticket.\r\n * @param options The draw options.\r\n * @returns The participant that holds the winning ticket.\r\n */\r\n Lotto.prototype.draw = function (options) {\r\n if (options === void 0) { options = {}; }\r\n // If we have no participants then just return null.\r\n if (this._participants.length === 0) {\r\n return null;\r\n }\r\n var redrawable = (0, Utilities_1.isNullOrUndefined)(options.redrawable) ? true : options.redrawable;\r\n var pickable = [];\r\n this._participants.forEach(function (_a) {\r\n var participant = _a.participant, tickets = _a.tickets;\r\n for (var ticketCount = 0; ticketCount < tickets; ticketCount++) {\r\n pickable.push(participant);\r\n }\r\n });\r\n var random;\r\n // We need a random floating-point number between 0 (inclusive) and 1 to scale up to pick our winner.\r\n // If a custom random function exists then we should use that or fall back to Math.random().\r\n if (this._customRandom) {\r\n // Call our custom random function to get a random floating-point number.\r\n random = this._customRandom();\r\n // Verify that the result of calling our custom random function is a number between 0 (inclusive) and 1.\r\n if (typeof random !== \"number\" || random < 0 || random >= 1) {\r\n throw new Error(\"the 'random' function provided did not return a number between 0 (inclusive) and 1\");\r\n }\r\n }\r\n else {\r\n // No custom random function was defined so just use good ol' Math.random().\r\n random = Math.random();\r\n }\r\n // Pick a winning participant.\r\n var winner = pickable[Math.floor(random * pickable.length)];\r\n // If the ticket isn't redrawable then we should remove a ticket from the winning participants ticket count.\r\n if (!redrawable) {\r\n this.remove(winner, 1);\r\n }\r\n // Return the winning participant.\r\n return winner;\r\n };\r\n /**\r\n * Draws multiple winning tickets and return an array of the participants that hold the winning tickets.\r\n * @param tickets The number of winning tickets to draw.\r\n * @param options The draw multiple options.\r\n * @returns An array of the participants that hold the winning tickets.\r\n */\r\n Lotto.prototype.drawMultiple = function (tickets, options) {\r\n if (options === void 0) { options = {}; }\r\n var uniqueResults = (0, Utilities_1.isNullOrUndefined)(options.unique) ? false : options.unique;\r\n // Handle cases where the user has asked for zero tickets (no idea why they would do this be we should trust them).\r\n if (tickets === 0) {\r\n return [];\r\n }\r\n // Now that we know out tickets value is not zero we should check that it is a valid natural number.\r\n if (!(0, Utilities_1.isNaturalNumber)(tickets)) {\r\n throw new Error(\"tickets value must be a natural number\");\r\n }\r\n var result = [];\r\n // Keep drawing tickets until we either reach the number of required tickets or we simply run out of tickets to draw.\r\n // We can run out of tickets to draw if 'options.redrawable' is explicity 'false' or we just had no participants when 'drawMultiple' was called.\r\n while (result.length < tickets && this._participants.length > 0) {\r\n result.push(this.draw(options));\r\n }\r\n // If the 'unique' draw option is set then we need to remove duplicates from the result list.\r\n if (uniqueResults) {\r\n // Create an array to store our unique results.\r\n var unique = [];\r\n // Iterate over all of our participants (with potential duplicates) and populate our array of unique values.\r\n for (var _i = 0, result_1 = result; _i < result_1.length; _i++) {\r\n var participant = result_1[_i];\r\n if (unique.indexOf(participant) === -1) {\r\n unique.push(participant);\r\n }\r\n }\r\n result = unique;\r\n }\r\n return result;\r\n };\r\n return Lotto;\r\n}());\r\nexports.Lotto = Lotto;\r\n", "\"use strict\";\r\nObject.defineProperty(exports, \"__esModule\", { value: true });\r\nexports.createLotto = void 0;\r\nvar Lotto_1 = require(\"./Lotto\");\r\n/**\r\n * A function that creates and returns a Lotto instance.\r\n * @param participantsOrOptions An array of initial participants or options relating to the creation of a Lotto instance.\r\n * @returns A new Lotto instance.\r\n */\r\nfunction createLotto(participantsOrOptions) {\r\n // If no initial participants or lotto options were provided as an argument then we can just return a new lotto instance now.\r\n if (!participantsOrOptions) {\r\n return new Lotto_1.Lotto();\r\n }\r\n // Check whether we were provided with an array of initial participants or a lotto options object.\r\n if (Array.isArray(participantsOrOptions)) {\r\n // We are dealing with a pre-defined array of participants.\r\n var participants = participantsOrOptions;\r\n var lotto_1 = new Lotto_1.Lotto();\r\n // If the lotto participants have been defined upfront then we will need to add them all to our lotto instance now.\r\n participants.forEach(function (_a) {\r\n var participant = _a[0], tokens = _a[1];\r\n return lotto_1.add(participant, tokens);\r\n });\r\n // Return the Lotto instance.\r\n return lotto_1;\r\n }\r\n else {\r\n // We are dealing with some lotto options.\r\n var random = participantsOrOptions.random, participants = participantsOrOptions.participants;\r\n // Create a Lotto instance passing the custom RNG function to use in place of Math.random() (which could be undefined).\r\n var lotto_2 = new Lotto_1.Lotto(random);\r\n // If the lotto participants have been defined upfront as part of the options then we will need to add them all to our lotto instance now.\r\n if (participants) {\r\n participants.forEach(function (_a) {\r\n var participant = _a[0], tokens = _a[1];\r\n return lotto_2.add(participant, tokens);\r\n });\r\n }\r\n // Return the Lotto instance.\r\n return lotto_2;\r\n }\r\n}\r\nexports.createLotto = createLotto;\r\n", "\"use strict\";\r\nObject.defineProperty(exports, \"__esModule\", { value: true });\r\nvar createLotto_1 = require(\"./createLotto\");\r\nexports.default = createLotto_1.createLotto;\r\n", "import State from \"./State\";\nimport { validateDefinition } from \"./BehaviourTreeDefinitionValidator\";\nimport { convertMDSLToJSON } from \"./mdsl/MDSLDefinitionParser\";\nimport { BehaviourTree, FlattenedTreeNode } from \"./BehaviourTree\";\n\nexport { BehaviourTree, State, convertMDSLToJSON, validateDefinition };\nexport type { FlattenedTreeNode };\n", "/**\n * Enumeration of node state types.\n */\nexport enum State {\n READY = \"mistreevous.ready\",\n RUNNING = \"mistreevous.running\",\n SUCCEEDED = \"mistreevous.succeeded\",\n FAILED = \"mistreevous.failed\"\n}\n\nexport { State as default };\n\nexport type CompleteState = State.SUCCEEDED | State.FAILED;\nexport type AnyState = State.READY | State.RUNNING | CompleteState;\n", "import {\n NodeDefinition,\n RootNodeDefinition,\n DecoratorNodeDefinition,\n CompositeNodeDefinition,\n AnyNodeDefinition,\n BranchNodeDefinition\n} from \"./BehaviourTreeDefinition\";\n\n/**\n * A type guard function that returns true if the specified node satisfies the RootNodeDefinition type.\n * @param node The node.\n * @returns A value of true if the specified node satisfies the RootNodeDefinition type.\n */\nexport function isRootNode(node: NodeDefinition): node is RootNodeDefinition {\n return node.type === \"root\";\n}\n\n/**\n * A type guard function that returns true if the specified node satisfies the BranchNodeDefinition type.\n * @param node The node.\n * @returns A value of true if the specified node satisfies the BranchNodeDefinition type.\n */\nexport function isBranchNode(node: NodeDefinition): node is BranchNodeDefinition {\n return node.type === \"branch\";\n}\n\n/**\n * A type guard function that returns true if the specified node satisfies the NodeDefinition type.\n * @param node The node.\n * @returns A value of true if the specified node satisfies the NodeDefinition type.\n */\nexport function isLeafNode(node: NodeDefinition): node is NodeDefinition {\n return [\"branch\", \"action\", \"condition\", \"wait\"].includes(node.type);\n}\n\n/**\n * A type guard function that returns true if the specified node satisfies the DecoratorNodeDefinition type.\n * @param node The node.\n * @returns A value of true if the specified node satisfies the DecoratorNodeDefinition type.\n */\nexport function isDecoratorNode(node: NodeDefinition): node is DecoratorNodeDefinition {\n return [\"root\", \"repeat\", \"retry\", \"flip\", \"succeed\", \"fail\"].includes(node.type);\n}\n\n/**\n * A type guard function that returns true if the specified node satisfies the CompositeNodeDefinition type.\n * @param node The node.\n * @returns A value of true if the specified node satisfies the CompositeNodeDefinition type.\n */\nexport function isCompositeNode(node: NodeDefinition): node is CompositeNodeDefinition {\n return [\"sequence\", \"selector\", \"lotto\", \"parallel\"].includes(node.type);\n}\n\n/**\n * Flatten a node definition into an array of all of its nested node definitions.\n * @param nodeDefinition The node definition to flatten.\n * @returns An array of all of nested node definitions.\n */\nexport function flattenDefinition(nodeDefinition: AnyNodeDefinition): AnyNodeDefinition[] {\n const nodes: AnyNodeDefinition[] = [];\n\n const processNode = (currentNodeDefinition: AnyNodeDefinition) => {\n nodes.push(currentNodeDefinition);\n\n if (isCompositeNode(currentNodeDefinition)) {\n currentNodeDefinition.children.forEach(processNode);\n } else if (isDecoratorNode(currentNodeDefinition)) {\n processNode(currentNodeDefinition.child);\n }\n };\n\n processNode(nodeDefinition);\n\n return nodes;\n}\n\n/**\n * Determines whether the passed value is an integer.\n * @param value The value to check.\n * @returns Whether the passed value is an integer.\n */\nexport function isInteger(value: unknown): boolean {\n return typeof value === \"number\" && Math.floor(value) === value;\n}\n\n/**\n * Determines whether the passed value is null or undefined.\n * @param value The value to check.\n * @returns Whether the passed value is null or undefined.\n */\nexport function isNullOrUndefined(value: unknown): boolean {\n return typeof value === \"undefined\" || value === null;\n}\n", "/**\n * A type defining an object that holds a reference to substitued string literals parsed from the definition.\n */\nexport type StringLiteralPlaceholders = { [key: string]: string };\n\n/**\n * Pop the next raw token from the specified array of tokens and throw an error if it wasn't the expected one.\n * @param tokens The array of tokens.\n * @param expected An optional string or array or items, one of which must match the next popped token.\n * @returns The popped token.\n */\nexport function popAndCheck(tokens: string[], expected?: string | string[]): string {\n // Get and remove the next token.\n const popped = tokens.shift();\n\n // We were expecting another token but there aren't any.\n if (popped === undefined) {\n throw new Error(\"unexpected end of definition\");\n }\n\n // Do we have an expected token/tokens array?\n if (expected != undefined) {\n // Get an array of expected values, if the popped token matches any then we are all good.\n const expectedValues = typeof expected === \"string\" ? [expected] : expected;\n\n // Check whether the popped token matches at least one of our expected items.\n var tokenMatchesExpectation = expectedValues.some((item) => popped.toUpperCase() === item.toUpperCase());\n\n // Throw an error if the popped token didn't match any of our expected items.\n if (!tokenMatchesExpectation) {\n const expectationString = expectedValues.map((item) => \"'\" + item + \"'\").join(\" or \");\n throw new Error(\"unexpected token found. Expected \" + expectationString + \" but got '\" + popped + \"'\");\n }\n }\n\n // Return the popped token.\n return popped;\n}\n\n/**\n * Swaps out any node/attribute argument string literals with placeholders.\n * @param definition The definition.\n * @returns An object containing a mapping of placeholders to original string values as well as the processed definition string.\n */\nexport function substituteStringLiterals(definition: string): {\n placeholders: StringLiteralPlaceholders;\n processedDefinition: string;\n} {\n // Create an object to hold the mapping of placeholders to original string values.\n const placeholders: StringLiteralPlaceholders = {};\n\n // Replace any string literals wrapped with double quotes in our definition with placeholders to be processed later.\n const processedDefinition = definition.replace(/\\\"(\\\\.|[^\"\\\\])*\\\"/g, (match) => {\n var strippedMatch = match.substring(1, match.length - 1);\n var placeholder = Object.keys(placeholders).find((key) => placeholders[key] === strippedMatch);\n\n // If we have no existing string literal match then create a new placeholder.\n if (!placeholder) {\n placeholder = `@@${Object.keys(placeholders).length}@@`;\n placeholders[placeholder] = strippedMatch;\n }\n\n return placeholder;\n });\n\n return { placeholders, processedDefinition };\n}\n\n/**\n * Parse the tree definition into an array of raw tokens.\n * @param definition The definition.\n * @returns An array of tokens parsed from the definition.\n */\nexport function parseTokensFromDefinition(definition: string): string[] {\n // Add some space around various important characters so that they can be plucked out easier as individual tokens.\n definition = definition.replace(/\\(/g, \" ( \");\n definition = definition.replace(/\\)/g, \" ) \");\n definition = definition.replace(/\\{/g, \" { \");\n definition = definition.replace(/\\}/g, \" } \");\n definition = definition.replace(/\\]/g, \" ] \");\n definition = definition.replace(/\\[/g, \" [ \");\n definition = definition.replace(/\\,/g, \" , \");\n\n // Split the definition into raw token form and return it.\n return definition.replace(/\\s+/g, \" \").trim().split(\" \");\n}\n", "import { StringLiteralPlaceholders, popAndCheck } from \"./MDSLUtilities\";\n\n/**\n * A type representing any node function argument.\n */\ntype Argument = {\n /**\n * The argument value.\n */\n value: T;\n /**\n * The argument type, used for validation.\n */\n type: string;\n};\n\ntype NullArgument = Argument & {\n type: \"null\";\n};\n\ntype BooleanArgument = Argument & {\n type: \"boolean\";\n};\n\ntype NumberArgument = Argument & {\n type: \"number\";\n /**\n * A flag defining whether the number argument value is a valid integer. (used for validation)\n */\n isInteger: boolean;\n};\n\ntype StringPlaceholderArgument = Argument & {\n type: \"string\";\n};\n\ntype IdentifierArgument = Argument & {\n type: \"identifier\";\n};\n\n/**\n * A type representing a reference to any node function argument.\n */\ntype AnyArgument = NullArgument | BooleanArgument | NumberArgument | StringPlaceholderArgument | IdentifierArgument;\n\n/**\n * Parse an array of argument definitions from the specified tokens array.\n * @param tokens The array tokens to parse the argument definitions from.\n * @param stringArgumentPlaceholders The mapping of string literal node argument placeholders to original values.\n * @param argumentValidator The argument validator function.\n * @param validationFailedMessage The exception message to throw if argument validation fails.\n * @returns An array of argument definitions parsed from the specified tokens array.\n */\nexport function parseArgumentTokens(\n tokens: string[],\n stringArgumentPlaceholders: StringLiteralPlaceholders\n): AnyArgument[] {\n const argumentList: AnyArgument[] = [];\n\n // If the next token is not a '[' or '(' then we have no arguments to parse.\n if (![\"[\", \"(\"].includes(tokens[0])) {\n return argumentList;\n }\n\n // Any lists of arguments will always be wrapped in '[]' for node arguments or '()' for attribute arguments.\n // We are looking for a '[' or '(' opener that wraps the argument tokens and the relevant closer.\n const closingToken = popAndCheck(tokens, [\"[\", \"(\"]) === \"[\" ? \"]\" : \")\";\n\n const argumentListTokens: string[] = [];\n\n // Grab all tokens between the '[' and ']' or '(' and ')'.\n while (tokens.length && tokens[0] !== closingToken) {\n // The next token is part of our arguments list.\n argumentListTokens.push(tokens.shift()!);\n }\n\n // Validate the order of the argument tokens. Each token must either be a ',' or a single argument that satisfies the validator.\n argumentListTokens.forEach((token, index) => {\n // Get whether this token should be an actual argument.\n const shouldBeArgumentToken = !(index & 1);\n\n // If the current token should be an actual argument then validate it, otherwise it should be a ',' token.\n if (shouldBeArgumentToken) {\n // Get the argument definition.\n const argumentDefinition = getArgumentDefinition(token, stringArgumentPlaceholders);\n\n // This is a valid argument!\n argumentList.push(argumentDefinition);\n } else {\n // The current token should be a ',' token.\n if (token !== \",\") {\n throw new Error(`invalid argument list, expected ',' or ']' but got '${token}'`);\n }\n }\n });\n\n // The arguments list should terminate with a ']' or ')' token, depending on the opener.\n popAndCheck(tokens, closingToken);\n\n // Return the arguments.\n return argumentList;\n}\n\n/**\n * Gets an argument value definition.\n * @param token The argument token.\n * @param stringArgumentPlaceholders The mapping of string literal node argument placeholders to original values.\n * @returns An argument value definition.\n */\nfunction getArgumentDefinition(token: string, stringArgumentPlaceholders: StringLiteralPlaceholders): AnyArgument {\n // Check whether the token represents a null value.\n if (token === \"null\") {\n return {\n value: null,\n type: \"null\"\n } as NullArgument;\n }\n\n // Check whether the token represents a boolean value.\n if (token === \"true\" || token === \"false\") {\n return {\n value: token === \"true\",\n type: \"boolean\"\n } as BooleanArgument;\n }\n\n // Check whether the token represents a number value.\n // TODO: Relies on broken isNaN - see MDN.\n // if (!Number.isNaN(token)) {\n if (!isNaN(token as any)) {\n return {\n value: parseFloat(token),\n isInteger: parseFloat(token) === parseInt(token, 10),\n type: \"number\"\n } as NumberArgument;\n }\n\n // Check whether the token is a placeholder (e.g. @@0@@) representing a string literal.\n if (token.match(/^@@\\d+@@$/g)) {\n return {\n value: stringArgumentPlaceholders[token].replace('\\\\\"', '\"'),\n type: \"string\"\n } as StringPlaceholderArgument;\n }\n\n // The only remaining option is that the argument value is an identifier.\n return {\n value: token,\n type: \"identifier\"\n } as IdentifierArgument;\n}\n", "import { NodeAttributeDefinition } from \"../BehaviourTreeDefinition\";\nimport { parseArgumentTokens } from \"./MDSLNodeArgumentParser\";\nimport { StringLiteralPlaceholders } from \"./MDSLUtilities\";\n\n/**\n * A type defining the attribute definitions of a node.\n */\ntype NodeAttributes = {\n while?: NodeAttributeDefinition;\n until?: NodeAttributeDefinition;\n entry?: NodeAttributeDefinition;\n exit?: NodeAttributeDefinition;\n step?: NodeAttributeDefinition;\n};\n\n/**\n * Parse any node attribute definitions from the specified tokens array.\n * @param tokens The array of remaining tokens.\n * @param stringArgumentPlaceholders The mapping of string literal node argument placeholders to original values.\n * @returns An object of attribute definitions defined by any directly following tokens.\n */\nexport function parseAttributeTokens(\n tokens: string[],\n stringArgumentPlaceholders: StringLiteralPlaceholders\n): NodeAttributes {\n const nodeAttributeNames: (keyof NodeAttributes)[] = [\"while\", \"until\", \"entry\", \"exit\", \"step\"];\n\n // Create an object to hold any attributes found.\n const attributes: NodeAttributes = {};\n\n // Try to get the name of the attribute for the next token.\n let nextAttributeName = tokens[0]?.toLowerCase() as keyof NodeAttributes;\n\n // Pull attribute tokens as well as their arguments off of the tokens stack until we have no more.\n while (nodeAttributeNames.includes(nextAttributeName)) {\n // Check to make sure that we have not already created an attribute definition of this type.\n if (attributes[nextAttributeName]) {\n throw new Error(`duplicate attribute '${tokens[0].toUpperCase()}' found for node`);\n }\n\n // Remove the attribute name token from the array of tokens.\n tokens.shift();\n\n // Grab the attribute arguments, assuming the first to be an identifier.\n const [attributeCallIdentifier, ...attributeArguments] = parseArgumentTokens(\n tokens,\n stringArgumentPlaceholders\n );\n\n // The first attribute argument has to be an identifer, this will reference an agent function.\n if (attributeCallIdentifier?.type !== \"identifier\") {\n throw new Error(\"expected agent function name identifier argument for attribute\");\n }\n\n // Any attribute arguments (other than the expected call identifier) must have a type of string, number, boolean or null.\n attributeArguments\n .filter((arg) => arg.type === \"identifier\")\n .forEach((arg) => {\n throw new Error(\n `invalid attribute argument value '${arg.value}', must be string, number, boolean or null`\n );\n });\n\n // Create the attribute definition and add it to the object of attribute definitions found.\n attributes[nextAttributeName] = {\n call: attributeCallIdentifier.value,\n args: attributeArguments.map(({ value }) => value)\n };\n\n // Try to get the next attribute name token, as there could be multiple.\n nextAttributeName = tokens[0]?.toLowerCase() as keyof NodeAttributes;\n }\n\n return attributes;\n}\n", "import {\n ActionNodeDefinition,\n AnyChildNodeDefinition,\n AnyNodeDefinition,\n BranchNodeDefinition,\n ConditionNodeDefinition,\n FailNodeDefinition,\n FlipNodeDefinition,\n LottoNodeDefinition,\n ParallelNodeDefinition,\n RepeatNodeDefinition,\n RetryNodeDefinition,\n RootNodeDefinition,\n SelectorNodeDefinition,\n SequenceNodeDefinition,\n SucceedNodeDefinition,\n WaitNodeDefinition\n} from \"../BehaviourTreeDefinition\";\nimport {\n isCompositeNode,\n isDecoratorNode,\n isLeafNode,\n isNullOrUndefined,\n isRootNode\n} from \"../BehaviourTreeDefinitionUtilities\";\nimport { parseArgumentTokens } from \"./MDSLNodeArgumentParser\";\nimport { parseAttributeTokens } from \"./MDSLNodeAttributeParser\";\nimport {\n StringLiteralPlaceholders,\n parseTokensFromDefinition,\n popAndCheck,\n substituteStringLiterals\n} from \"./MDSLUtilities\";\n\n/**\n * Convert the MDSL tree definition string into an equivalent JSON definition.\n * @param definition The tree definition string as MDSL.\n * @returns The root node JSON definitions.\n */\nexport function convertMDSLToJSON(definition: string): RootNodeDefinition[] {\n // Swap out any node/attribute argument string literals with a placeholder and get a mapping of placeholders to original values as well as the processed definition.\n const { placeholders, processedDefinition } = substituteStringLiterals(definition);\n\n // Parse our definition definition string into an array of raw tokens.\n const tokens = parseTokensFromDefinition(processedDefinition);\n\n return convertTokensToJSONDefinition(tokens, placeholders);\n}\n\n/**\n * Converts the specified tree definition tokens into a JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The root node JSON definitions.\n */\nfunction convertTokensToJSONDefinition(\n tokens: string[],\n stringLiteralPlaceholders: StringLiteralPlaceholders\n): RootNodeDefinition[] {\n // There must be at least 3 tokens for the tree definition to be valid. 'ROOT', '{' and '}'.\n if (tokens.length < 3) {\n throw new Error(\"invalid token count\");\n }\n\n // We should have a matching number of '{' and '}' tokens. If not, then there are scopes that have not been properly closed.\n if (tokens.filter((token) => token === \"{\").length !== tokens.filter((token) => token === \"}\").length) {\n throw new Error(\"scope character mismatch\");\n }\n\n // Create an array of tree stack arrays where root nodes will always be at the botton and the current composite/decorator node at the top.\n // There should be an element in this array for every root node defined and every element should be an array with a root note as the first element.\n // E.g. A definition with two root nodes defined:\n // [\n // [root, lotto, sequence],\n // [root, selector]\n // ]\n const treeStacks: [Partial, ...Partial[]][] = [];\n\n // Create an array of all root node definitions that we create.\n const rootNodes: Partial[] = [];\n\n // A helper function used to push node definitions onto the tree stack.\n const pushNode = (node: AnyNodeDefinition) => {\n // If the node is a root node then we need to create a new tree stack array with the root node at the root.\n if (isRootNode(node)) {\n // We need to double-check that this root node is not the child of another node.\n // We can do this by checking whether the top tree stack is not empty (contains an existing node)\n if (treeStacks[treeStacks.length - 1]?.length) {\n throw new Error(\"a root node cannot be the child of another node\");\n }\n\n // Add the root node definition to our array of all parsed root node definitions.\n rootNodes.push(node);\n\n // Add the root node definition to the root of a new tree stack.\n treeStacks.push([node]);\n\n return;\n }\n\n // All non-root nodes should be pushed after their root nodes so handle cases\n // where we may not have any tree stacks or our top-most tree stack is empty.\n if (!treeStacks.length || !treeStacks[treeStacks.length - 1].length) {\n throw new Error(\"expected root node at base of definition\");\n }\n\n // Get the current tree stack that we are populating.\n const topTreeStack = treeStacks[treeStacks.length - 1];\n\n // Get the top-most node in the current tree stack, this will be a composite/decorator node\n // for which we will populate its children array if composite or setting its child if a decorator.\n const topTreeStackTopNode = topTreeStack[topTreeStack.length - 1] as AnyNodeDefinition;\n\n // If the top-most node in the current root stack is a composite or decorator\n // node then the current node should be added as a child of the top-most node.\n if (isCompositeNode(topTreeStackTopNode)) {\n topTreeStackTopNode.children = topTreeStackTopNode.children || [];\n topTreeStackTopNode.children.push(node);\n } else if (isDecoratorNode(topTreeStackTopNode)) {\n // If the top node already has a child node set then throw an error as a decorator should only have a single child.\n if (topTreeStackTopNode.child) {\n throw new Error(\"a decorator node must only have a single child node\");\n }\n\n topTreeStackTopNode.child = node;\n }\n\n // If the node we are adding is also a composite or decorator node, then we should push it\n // onto the current tree stack, as subsequent nodes will be added as its child/children.\n if (!isLeafNode(node)) {\n topTreeStack.push(node);\n }\n };\n\n // A helper function used to pop the top-most node definition off of the tree stack and return it.\n const popNode = (): AnyNodeDefinition | null => {\n let poppedNode: AnyNodeDefinition | null = null;\n\n // Get the current tree stack that we are populating.\n const topTreeStack = treeStacks[treeStacks.length - 1];\n\n // Pop the top-most node in the current tree stack if there is one.\n if (topTreeStack.length) {\n poppedNode = topTreeStack.pop() as AnyNodeDefinition;\n }\n\n // We don't want any empty tree stacks in our stack of tree stacks.\n if (!topTreeStack.length) {\n treeStacks.pop();\n }\n\n return poppedNode;\n };\n\n // We should keep processing the raw tokens until we run out of them.\n while (tokens.length) {\n // Grab the next token.\n const token = tokens.shift()!;\n\n // How we create the next node depends on the current raw token value.\n switch (token.toUpperCase()) {\n case \"ROOT\": {\n pushNode(createRootNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"SUCCEED\": {\n pushNode(createSucceedNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"FAIL\": {\n pushNode(createFailNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"FLIP\": {\n pushNode(createFlipNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"REPEAT\": {\n pushNode(createRepeatNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"RETRY\": {\n pushNode(createRetryNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"SEQUENCE\": {\n pushNode(createSequenceNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"SELECTOR\": {\n pushNode(createSelectorNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"PARALLEL\": {\n pushNode(createParallelNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"LOTTO\": {\n pushNode(createLottoNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"ACTION\": {\n pushNode(createActionNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"CONDITION\": {\n pushNode(createConditionNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"WAIT\": {\n pushNode(createWaitNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"BRANCH\": {\n pushNode(createBranchNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"}\": {\n // The '}' character closes the current scope and means that we have to pop a node off of the current stack.\n const poppedNode = popNode();\n\n // Now that we have a node definition we can carry out any validation that may require the node to be fully populated.\n if (poppedNode) {\n validatePoppedNode(poppedNode);\n }\n\n break;\n }\n\n default: {\n throw new Error(`unexpected token: ${token}`);\n }\n }\n }\n\n return rootNodes as RootNodeDefinition[];\n}\n\n/**\n * Creates a root node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The root node JSON definition.\n */\nfunction createRootNode(tokens: string[], stringLiteralPlaceholders: StringLiteralPlaceholders): RootNodeDefinition {\n // Create the root node definition.\n let node = {\n type: \"root\",\n id: undefined\n } as RootNodeDefinition;\n\n // Parse any node arguments, we should only have one if any which will be an identifier argument for the root identifier.\n const nodeArguments = parseArgumentTokens(tokens, stringLiteralPlaceholders);\n\n // Check whether any node arguments were defined.\n if (nodeArguments.length) {\n // We should only have one argument, if any, which will be an identifier argument for the root identifier.\n if (nodeArguments.length === 1 && nodeArguments[0].type === \"identifier\") {\n // The root node identifier will be the first and only node argument value.\n node.id = nodeArguments[0].value as string;\n } else {\n throw new Error(\"expected single root name argument\");\n }\n }\n\n // Grab any node attribute definitions and spread them into the node definition.\n node = { ...node, ...parseAttributeTokens(tokens, stringLiteralPlaceholders) };\n\n // This is a decorator node, so we expect an opening '{'.\n popAndCheck(tokens, \"{\");\n\n // Return the root node definition.\n return node;\n}\n\n/**\n * Creates a succeed node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The succeed node JSON definition.\n */\nfunction createSucceedNode(\n tokens: string[],\n stringLiteralPlaceholders: StringLiteralPlaceholders\n): SucceedNodeDefinition {\n const node = {\n type: \"succeed\",\n ...parseAttributeTokens(tokens, stringLiteralPlaceholders)\n } as SucceedNodeDefinition;\n\n // This is a decorator node, so we expect an opening '{'.\n popAndCheck(tokens, \"{\");\n\n // Return the succeed node definition.\n return node;\n}\n\n/**\n * Creates a fail node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The fail node JSON definition.\n */\nfunction createFailNode(tokens: string[], stringLiteralPlaceholders: StringLiteralPlaceholders): FailNodeDefinition {\n const node = {\n type: \"fail\",\n ...parseAttributeTokens(tokens, stringLiteralPlaceholders)\n } as FailNodeDefinition;\n\n // This is a decorator node, so we expect an opening '{'.\n popAndCheck(tokens, \"{\");\n\n // Return the fail node definition.\n return node;\n}\n\n/**\n * Creates a flip node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The flip node JSON definition.\n */\nfunction createFlipNode(tokens: string[], stringLiteralPlaceholders: StringLiteralPlaceholders): FlipNodeDefinition {\n const node = {\n type: \"flip\",\n ...parseAttributeTokens(tokens, stringLiteralPlaceholders)\n } as FlipNodeDefinition;\n\n // This is a decorator node, so we expect an opening '{'.\n popAndCheck(tokens, \"{\");\n\n // Return the flip node definition.\n return node;\n}\n\n/**\n * Creates a repeat node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The repeat node JSON definition.\n */\nfunction createRepeatNode(\n tokens: string[],\n stringLiteralPlaceholders: StringLiteralPlaceholders\n): RepeatNodeDefinition {\n let node = { type: \"repeat\" } as RepeatNodeDefinition;\n\n // Get the node arguments.\n const nodeArguments = parseArgumentTokens(tokens, stringLiteralPlaceholders);\n\n // The arguments of a repeat node are optional. We may have:\n // - No node arguments, in which case the repeat note will iterate indefinitely.\n // - One node argument which will be the explicit number of iterations to make.\n // - Two node arguments which define the min and max iteration bounds from which a random iteration count will be picked.\n if (nodeArguments.length) {\n // All repeat node arguments MUST be of type number and must be integer.\n nodeArguments\n .filter((arg) => arg.type !== \"number\" || !arg.isInteger)\n .forEach(() => {\n throw new Error(`repeat node iteration counts must be integer values`);\n });\n\n // We should have got one or two iteration counts.\n if (nodeArguments.length === 1) {\n // A static iteration count was defined.\n node.iterations = nodeArguments[0].value as number;\n\n // A repeat node must have a positive number of iterations if defined.\n if (node.iterations < 0) {\n throw new Error(\"a repeat node must have a positive number of iterations if defined\");\n }\n } else if (nodeArguments.length === 2) {\n // A minimum and maximum iteration count was defined.\n node.iterations = [nodeArguments[0].value as number, nodeArguments[1].value as number];\n\n // A repeat node must have a positive min and max iteration count if they are defined.\n if (node.iterations[0] < 0 || node.iterations[1] < 0) {\n throw new Error(\"a repeat node must have a positive minimum and maximum iteration count if defined\");\n }\n\n // A repeat node must not have an minimum iteration count that exceeds the maximum iteration count.\n if (node.iterations[0] > node.iterations[1]) {\n throw new Error(\n \"a repeat node must not have a minimum iteration count that exceeds the maximum iteration count\"\n );\n }\n } else {\n // An incorrect number of iteration counts was defined.\n throw new Error(\"invalid number of repeat node iteration count arguments defined\");\n }\n }\n\n // Grab any node attribute definitions and spread them into the node definition.\n node = { ...node, ...parseAttributeTokens(tokens, stringLiteralPlaceholders) };\n\n // This is a decorator node, so we expect an opening '{'.\n popAndCheck(tokens, \"{\");\n\n // Return the repeat node definition.\n return node;\n}\n\n/**\n * Creates a retry node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The retry node JSON definition.\n */\nfunction createRetryNode(tokens: string[], stringLiteralPlaceholders: StringLiteralPlaceholders): RetryNodeDefinition {\n let node = { type: \"retry\" } as RetryNodeDefinition;\n\n // Get the node arguments.\n const nodeArguments = parseArgumentTokens(tokens, stringLiteralPlaceholders);\n\n // The arguments of a retry node are optional. We may have:\n // - No node arguments, in which case the retry note will attempt indefinitely.\n // - One node argument which will be the explicit number of attempts to make.\n // - Two node arguments which define the min and max attempt bounds from which a random attempt count will be picked.\n if (nodeArguments.length) {\n // All retry node arguments MUST be of type number and must be integer.\n nodeArguments\n .filter((arg) => arg.type !== \"number\" || !arg.isInteger)\n .forEach(() => {\n throw new Error(`retry node attempt counts must be integer values`);\n });\n\n // We should have got one or two attempt counts.\n if (nodeArguments.length === 1) {\n // A static attempt count was defined.\n node.attempts = nodeArguments[0].value as number;\n\n // A retry node must have a positive number of attempts if defined.\n if (node.attempts < 0) {\n throw new Error(\"a retry node must have a positive number of attempts if defined\");\n }\n } else if (nodeArguments.length === 2) {\n // A minimum and maximum attempt count was defined.\n node.attempts = [nodeArguments[0].value as number, nodeArguments[1].value as number];\n\n // A retry node must have a positive min and max attempts count if they are defined.\n if (node.attempts[0] < 0 || node.attempts[1] < 0) {\n throw new Error(\"a retry node must have a positive minimum and maximum attempt count if defined\");\n }\n\n // A retry node must not have a minimum attempt count that exceeds the maximum attempt count.\n if (node.attempts[0] > node.attempts[1]) {\n throw new Error(\n \"a retry node must not have a minimum attempt count that exceeds the maximum attempt count\"\n );\n }\n } else {\n // An incorrect number of attempt counts was defined.\n throw new Error(\"invalid number of retry node attempt count arguments defined\");\n }\n }\n\n // Grab any node attribute definitions and spread them into the node definition.\n node = { ...node, ...parseAttributeTokens(tokens, stringLiteralPlaceholders) };\n\n // This is a decorator node, so we expect an opening '{'.\n popAndCheck(tokens, \"{\");\n\n // Return the retry node definition.\n return node;\n}\n\n/**\n * Creates a sequence node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The sequence node JSON definition.\n */\nfunction createSequenceNode(\n tokens: string[],\n stringLiteralPlaceholders: StringLiteralPlaceholders\n): SequenceNodeDefinition {\n const node = {\n type: \"sequence\",\n ...parseAttributeTokens(tokens, stringLiteralPlaceholders)\n } as SequenceNodeDefinition;\n\n // This is a composite node, so we expect an opening '{'.\n popAndCheck(tokens, \"{\");\n\n // Return the sequence node definition.\n return node;\n}\n\n/**\n * Creates a selector node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The selector node JSON definition.\n */\nfunction createSelectorNode(\n tokens: string[],\n stringLiteralPlaceholders: StringLiteralPlaceholders\n): SelectorNodeDefinition {\n const node = {\n type: \"selector\",\n ...parseAttributeTokens(tokens, stringLiteralPlaceholders)\n } as SelectorNodeDefinition;\n\n // This is a composite node, so we expect an opening '{'.\n popAndCheck(tokens, \"{\");\n\n // Return the selector node definition.\n return node;\n}\n\n/**\n * Creates a parallel node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The parallel node JSON definition.\n */\nfunction createParallelNode(\n tokens: string[],\n stringLiteralPlaceholders: StringLiteralPlaceholders\n): ParallelNodeDefinition {\n const node = {\n type: \"parallel\",\n ...parseAttributeTokens(tokens, stringLiteralPlaceholders)\n } as ParallelNodeDefinition;\n\n // This is a composite node, so we expect an opening '{'.\n popAndCheck(tokens, \"{\");\n\n // Return the parallel node definition.\n return node;\n}\n\n/**\n * Creates a lotto node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The lotto node JSON definition.\n */\nfunction createLottoNode(tokens: string[], stringLiteralPlaceholders: StringLiteralPlaceholders): LottoNodeDefinition {\n // If any node arguments have been defined then they must be our weights.\n const nodeArguments = parseArgumentTokens(tokens, stringLiteralPlaceholders);\n\n // All lotto node arguments MUST be of type number and must be integer.\n nodeArguments\n .filter((arg) => arg.type !== \"number\" || !arg.isInteger)\n .forEach(() => {\n throw new Error(`lotto node weight arguments must be integer values`);\n });\n\n const node = {\n type: \"lotto\",\n weights: nodeArguments.map(({ value }) => value),\n ...parseAttributeTokens(tokens, stringLiteralPlaceholders)\n } as LottoNodeDefinition;\n\n // This is a composite node, so we expect an opening '{'.\n popAndCheck(tokens, \"{\");\n\n // Return the lotto node definition.\n return node;\n}\n\n/**\n * Creates an action node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The action node JSON definition.\n */\nfunction createActionNode(\n tokens: string[],\n stringLiteralPlaceholders: StringLiteralPlaceholders\n): ActionNodeDefinition {\n // Parse any node arguments, we should have at least one which will be an identifier argument for the action name\n // and agent function to invoke for the action, all other arguments are to be passed as arguments to that function.\n const [actionNameIdentifier, ...agentFunctionArgs] = parseArgumentTokens(tokens, stringLiteralPlaceholders);\n\n // Our first argument MUST be defined and be an identifier as we require an action name argument.\n if (actionNameIdentifier?.type !== \"identifier\") {\n throw new Error(\"expected action name identifier argument\");\n }\n\n // Only the first argument should have been an identifier, all agent function arguments must be string, number, boolean or null.\n agentFunctionArgs\n .filter((arg) => arg.type === \"identifier\")\n .forEach((arg) => {\n throw new Error(\n `invalid action node argument value '${arg.value}', must be string, number, boolean or null`\n );\n });\n\n // Return the action node definition.\n return {\n type: \"action\",\n call: actionNameIdentifier.value,\n args: agentFunctionArgs.map(({ value }) => value),\n ...parseAttributeTokens(tokens, stringLiteralPlaceholders)\n };\n}\n\n/**\n * Creates a condition node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The condition node JSON definition.\n */\nfunction createConditionNode(\n tokens: string[],\n stringLiteralPlaceholders: StringLiteralPlaceholders\n): ConditionNodeDefinition {\n // Parse any node arguments, we should have at least one which will be an identifier argument for the condition name\n // and agent function to invoke for the condition, all other arguments are to be passed as arguments to that function.\n const [conditionNameIdentifier, ...agentFunctionArgs] = parseArgumentTokens(tokens, stringLiteralPlaceholders);\n\n // Our first argument MUST be defined and be an identifier as we require a condition name argument.\n if (conditionNameIdentifier?.type !== \"identifier\") {\n throw new Error(\"expected condition name identifier argument\");\n }\n\n // Only the first argument should have been an identifier, all agent function arguments must be string, number, boolean or null.\n agentFunctionArgs\n .filter((arg) => arg.type === \"identifier\")\n .forEach((arg) => {\n throw new Error(\n `invalid condition node argument value '${arg.value}', must be string, number, boolean or null`\n );\n });\n\n // Return the condition node definition.\n return {\n type: \"condition\",\n call: conditionNameIdentifier.value,\n args: agentFunctionArgs.map(({ value }) => value),\n ...parseAttributeTokens(tokens, stringLiteralPlaceholders)\n };\n}\n\n/**\n * Creates a wait node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The wait node JSON definition.\n */\nfunction createWaitNode(tokens: string[], stringLiteralPlaceholders: StringLiteralPlaceholders): WaitNodeDefinition {\n let node = { type: \"wait\" } as WaitNodeDefinition;\n\n // Get the node arguments.\n const nodeArguments = parseArgumentTokens(tokens, stringLiteralPlaceholders);\n\n // The arguments of a wait node are optional. We may have:\n // - No node arguments, in which case the wait will be indefinite until it is aborted.\n // - One node argument which will be the explicit duration of the wait.\n // - Two node arguments which define the min and max duration bounds from which a random duration will be picked.\n if (nodeArguments.length) {\n // All wait node arguments MUST be of type number and must be integer.\n nodeArguments\n .filter((arg) => arg.type !== \"number\" || !arg.isInteger)\n .forEach(() => {\n throw new Error(`wait node duration arguments must be integer values`);\n });\n\n // We may have:\n // - One node argument which will be the explicit duration of the wait.\n // - Two node arguments which define the min and max duration bounds from which a random duration will be picked.\n // - Too many arguments, which is not valid.\n if (nodeArguments.length === 1) {\n // An explicit duration was defined.\n node.duration = nodeArguments[0].value as number;\n\n // If an explict duration was defined then it must be a positive number.\n if (node.duration < 0) {\n throw new Error(\"a wait node must have a positive duration\");\n }\n } else if (nodeArguments.length === 2) {\n // Min and max duration bounds were defined from which a random duration will be picked.\n node.duration = [nodeArguments[0].value as number, nodeArguments[1].value as number];\n\n // A wait node must have a positive min and max duration.\n if (node.duration[0] < 0 || node.duration[1] < 0) {\n throw new Error(\"a wait node must have a positive minimum and maximum duration\");\n }\n\n // A wait node must not have a minimum duration that exceeds the maximum duration.\n if (node.duration[0] > node.duration[1]) {\n throw new Error(\"a wait node must not have a minimum duration that exceeds the maximum duration\");\n }\n } else if (nodeArguments.length > 2) {\n // An incorrect number of duration arguments were defined.\n throw new Error(\"invalid number of wait node duration arguments defined\");\n }\n }\n\n // Return the wait node definition.\n return { ...node, ...parseAttributeTokens(tokens, stringLiteralPlaceholders) };\n}\n\n/**\n * Creates a branch node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The branch node JSON definition.\n */\nfunction createBranchNode(\n tokens: string[],\n stringLiteralPlaceholders: StringLiteralPlaceholders\n): BranchNodeDefinition {\n // Parse any node arguments, we should have one which will be an identifier argument for the root ref.\n const nodeArguments = parseArgumentTokens(tokens, stringLiteralPlaceholders);\n\n // We should have only a single identifer argument for a branch node, which is the root ref.\n if (nodeArguments.length !== 1 || nodeArguments[0].type !== \"identifier\") {\n throw new Error(\"expected single branch name argument\");\n }\n\n // Return the branch node definition.\n return { type: \"branch\", ref: nodeArguments[0].value };\n}\n\n/**\n * Validate a fully-populated node definition that was popped off of the tree stack.\n * @param node The popped node to validate.\n */\nfunction validatePoppedNode(node: AnyNodeDefinition): void {\n // Decorators MUST have a child defined.\n if (isDecoratorNode(node) && isNullOrUndefined(node.child)) {\n throw new Error(`a ${node.type} node must have a single child node defined`);\n }\n\n // Composites MUST have at least one child defined.\n if (isCompositeNode(node) && !node.children?.length) {\n throw new Error(`a ${node.type} node must have at least a single child node defined`);\n }\n}\n", "import { RootNodeDefinition } from \"./BehaviourTreeDefinition\";\nimport { flattenDefinition, isBranchNode, isInteger } from \"./BehaviourTreeDefinitionUtilities\";\nimport { convertMDSLToJSON } from \"./mdsl/MDSLDefinitionParser\";\n\n/**\n * An object representing the result of validating a tree definition.\n */\nexport type DefinitionValidationResult = {\n /**\n * A flag defining whether validation succeeded.\n */\n succeeded: boolean;\n /**\n * A string containing the error message if validation did not succeed.\n */\n errorMessage?: string;\n};\n\n/**\n * Validates the specified behaviour tree definition in the form of JSON or MDSL, not taking any globally registered subtrees into consideration.\n * @param definition The behaviour tree definition in the form of JSON or MDSL.\n * @returns An object representing the result of validating the given tree definition.\n */\nexport function validateDefinition(definition: any): DefinitionValidationResult {\n // The definition must be defined.\n if (definition === null || typeof definition === \"undefined\") {\n return createValidationFailureResult(\"definition is null or undefined\");\n }\n\n // We are expecting a definition in one of three different forms:\n // - A string which we will assume is MDSL and we will parse this to JSON before validation.\n // - An array which we will assume is an array of root node definitions with at least one being the primary root node (no 'id' property)\n // - An object which we will assume is the primary root node and should not have an 'id' property.\n if (typeof definition === \"string\") {\n // The definition is a string which we can assume is MDSL, so attempt to validate it.\n return validateMDSLDefinition(definition);\n } else if (typeof definition === \"object\") {\n // The definition will either be an array (of root node definitions) or an object (the single primary root node definition).\n return validateJSONDefinition(definition);\n } else {\n return createValidationFailureResult(`unexpected definition type of '${typeof definition}'`);\n }\n}\n\n/**\n * Validates the specified behaviour tree definition in the form of MDSL.\n * @param definition The behaviour tree definition in the form of MDSL.\n * @returns An object representing the result of validating the given tree definition.\n */\nexport function validateMDSLDefinition(definition: string): DefinitionValidationResult {\n let rootNodeDefinitions;\n\n // The first thing the we need to do is to attempt to convert our MDSL into JSON.\n try {\n // The definition is a string which we can assume is MDSL, so attempt to parse it to a JSON definition in the form of an array of root node definitions.\n rootNodeDefinitions = convertMDSLToJSON(definition);\n } catch (error) {\n // We failed to parse the JSON from the MDSL, this is likely to be the result of it not being a valid MDSL string.\n return createValidationFailureResult(`invalid MDSL: ${error}`);\n }\n\n // Unpack all of the root node definitions into arrays of main ('id' defined) and sub ('id' not defined) root node definitions.\n const mainRootNodeDefinitions = rootNodeDefinitions.filter(({ id }) => typeof id === \"undefined\");\n const subRootNodeDefinitions = rootNodeDefinitions.filter(({ id }) => typeof id === \"string\" && id.length > 0);\n\n // We should ALWAYS have exactly one root node definition without an 'id' property defined, which is out main root node definition.\n if (mainRootNodeDefinitions.length !== 1) {\n return createValidationFailureResult(\n \"expected single unnamed root node at base of definition to act as main root\"\n );\n }\n\n // We should never have duplicate 'id' properties across our sub root node definitions.\n const subRootNodeIdenitifers: string[] = [];\n for (const { id } of subRootNodeDefinitions) {\n // Have we already come across this 'id' property value?\n if (subRootNodeIdenitifers.includes(id!)) {\n return createValidationFailureResult(`multiple root nodes found with duplicate name '${id}'`);\n }\n\n subRootNodeIdenitifers.push(id!);\n }\n\n try {\n // Validate our branch -> subtree links and check for any circular dependencies, we don't care about checking for broken subtree links here.\n validateBranchSubtreeLinks(rootNodeDefinitions, false);\n } catch (exception) {\n return createValidationFailureResult((exception as Error).message);\n }\n\n // Our definition was valid!\n return { succeeded: true };\n}\n\n/**\n * Validates the specified behaviour tree definition in the form of JSON.\n * @param definition The behaviour tree definition in the form of JSON.\n * @returns An object representing the result of validating the given tree definition.\n */\nexport function validateJSONDefinition(\n definition: RootNodeDefinition | RootNodeDefinition[]\n): DefinitionValidationResult {\n // The definition will either be an array (of root node definitions) or an object (the single primary root node definition).\n const rootNodeDefinitions = Array.isArray(definition) ? definition : [definition];\n\n // Iterate over our array of root nodes and call validateNode for each, passing an initial depth of 0, wrapped in a try catch to handle validation failures.\n try {\n rootNodeDefinitions.forEach((rootNodeDefinition) => validateNode(rootNodeDefinition, 0));\n } catch (error) {\n // Handle cases where we have caught a thrown Error and return a failure result with the error message.\n if (error instanceof Error) {\n return createValidationFailureResult(error.message);\n }\n\n // No idea what happened here!\n return createValidationFailureResult(`unexpected error: ${error}`);\n }\n\n // Unpack all of the root node definitions into arrays of main ('id' defined) and sub ('id' not defined) root node definitions.\n const mainRootNodeDefinitions = rootNodeDefinitions.filter(({ id }) => typeof id === \"undefined\");\n const subRootNodeDefinitions = rootNodeDefinitions.filter(({ id }) => typeof id === \"string\" && id.length > 0);\n\n // We should ALWAYS have exactly one root node definition without an 'id' property defined, which is out main root node definition.\n if (mainRootNodeDefinitions.length !== 1) {\n return createValidationFailureResult(\n \"expected single root node without 'id' property defined to act as main root\"\n );\n }\n\n // We should never have duplicate 'id' properties across our sub root node definitions.\n const subRootNodeIdenitifers: string[] = [];\n for (const { id } of subRootNodeDefinitions) {\n // Have we already come across this 'id' property value?\n if (subRootNodeIdenitifers.includes(id!)) {\n return createValidationFailureResult(\n `multiple root nodes found with duplicate 'id' property value of '${id}'`\n );\n }\n\n subRootNodeIdenitifers.push(id!);\n }\n\n try {\n // Validate our branch -> subtree links and check for any circular dependencies, we don't care about checking for broken subtree links here.\n validateBranchSubtreeLinks(rootNodeDefinitions, false);\n } catch (exception) {\n return createValidationFailureResult((exception as Error).message);\n }\n\n // Our definition was valid!\n return { succeeded: true };\n}\n\n/**\n * Validates the branch -> subtree links across all provided root node definitions.\n * This will not consider branch nodes that reference any globally registered subtrees unless includesGlobalSubtrees\n * is set to true, in which case we will also verify that there are no broken branch -> subtree links.\n * @param rootNodeDefinitions The array of root node definitions.\n * @param includesGlobalSubtrees A flag defining whether the array includes all global subtree root node definitions.\n */\nexport function validateBranchSubtreeLinks(rootNodeDefinitions: RootNodeDefinition[], includesGlobalSubtrees: boolean) {\n // Create a mapping of root node identifiers to other root nodes that they reference via branch nodes.\n // Below is an example of a mapping that includes a circular dependency (root => a => b => c => a)\n // [{ refs: [\"a\", \"b\"] }, { id: \"a\", refs: [\"b\"] }, { id: \"b\", refs: [\"c\"] }, { id: \"c\", refs: [\"a\"] }]\n const rootNodeMappings: { id: string | undefined; refs: string[] }[] = rootNodeDefinitions.map(\n (rootNodeDefinition) => ({\n id: rootNodeDefinition.id,\n refs: flattenDefinition(rootNodeDefinition)\n .filter(isBranchNode)\n .map(({ ref }) => ref)\n })\n );\n\n // A recursive function to walk through the mappings, keeping track of which root nodes we have visited in the form of a path of root node identifiers.\n const followRefs = (mapping: { id: string | undefined; refs: string[] }, path: (string | undefined)[] = []) => {\n // Have we found a circular dependency?\n if (path.includes(mapping.id)) {\n // We found a circular dependency! Get the bad path of root node identifiers.\n const badPath = [...path, mapping.id];\n\n // Create the formatted path value. [undefined, \"a\", \"b\", \"c\", \"a\"] would be formatted as \"a -> b -> c -> a\".\n const badPathFormatted = badPath.filter((element) => !!element).join(\" => \");\n\n // No need to continue, we found a circular dependency.\n throw new Error(`circular dependency found in branch node references: ${badPathFormatted}`);\n }\n\n for (const ref of mapping.refs) {\n // Find the mapping for the root node with an identifer matching the current ref.\n const subMapping = rootNodeMappings.find(({ id }) => id === ref);\n\n // We may not have a mapping for this ref, which is normal when we aren't considering all globally registered subtrees.\n if (subMapping) {\n followRefs(subMapping, [...path, mapping.id]);\n } else if (includesGlobalSubtrees) {\n // We found a reference to a root node that doesn't exist, which is a problem seeing as the root node definitons includes all globally registered subtrees.\n throw new Error(\n mapping.id\n ? `subtree '${mapping.id}' has branch node that references root node '${ref}' which has not been defined`\n : `primary tree has branch node that references root node '${ref}' which has not been defined`\n );\n }\n }\n };\n\n // Start looking for circular dependencies and broken references from the primary root node definition.\n followRefs(rootNodeMappings.find((mapping) => typeof mapping.id === \"undefined\")!);\n}\n\n/**\n * Validate an object that we expect to be a node definition.\n * @param definition An object that we expect to be a node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateNode(definition: any, depth: number): void {\n // Every node must be valid object and have a non-empty 'type' string property.\n if (typeof definition !== \"object\" || typeof definition.type !== \"string\" || definition.type.length === 0) {\n throw new Error(\n `node definition is not an object or 'type' property is not a non-empty string at depth '${depth}'`\n );\n }\n\n // How we validate this node definition will depend on its type.\n switch (definition.type) {\n case \"action\":\n validateActionNode(definition, depth);\n break;\n\n case \"condition\":\n validateConditionNode(definition, depth);\n break;\n\n case \"wait\":\n validateWaitNode(definition, depth);\n break;\n\n case \"branch\":\n validateBranchNode(definition, depth);\n break;\n\n case \"root\":\n validateRootNode(definition, depth);\n break;\n\n case \"success\":\n validateSuccessNode(definition, depth);\n break;\n\n case \"fail\":\n validateFailNode(definition, depth);\n break;\n\n case \"flip\":\n validateFlipNode(definition, depth);\n break;\n\n case \"repeat\":\n validateRepeatNode(definition, depth);\n break;\n\n case \"retry\":\n validateRetryNode(definition, depth);\n break;\n\n case \"sequence\":\n validateSequenceNode(definition, depth);\n break;\n\n case \"selector\":\n validateSelectorNode(definition, depth);\n break;\n\n case \"parallel\":\n validateParallelNode(definition, depth);\n break;\n\n default:\n throw new Error(`unexpected node type of '${definition.type}' at depth '${depth}'`);\n }\n}\n\n/**\n * Validate any attributes for a given node definition.\n * @param definition The node definition.\n * @param depth The depth of the node in the behaviour tree definition.\n */\nfunction validateNodeAttributes(definition: any, depth: number): void {\n // Validate each of the attribute types for this node.\n [\"while\", \"until\", \"entry\", \"exit\", \"step\"].forEach((attributeName) => {\n // Attempt to grab the definition for the current attribute from the node definition.\n const attributeDefinition = definition[attributeName];\n\n // All node attributes are optional, so there is nothing to do if the current attribute is not defined.\n if (typeof attributeDefinition === \"undefined\") {\n return;\n }\n\n // The attribute definition must be an object.\n if (typeof attributeDefinition !== \"object\") {\n throw new Error(\n `expected attribute '${attributeName}' to be an object for '${definition.type}' node at depth '${depth}'`\n );\n }\n\n // The 'call' property must be defined for any attribute definition.\n if (typeof attributeDefinition.call !== \"string\" || attributeDefinition.call.length === 0) {\n throw new Error(\n `expected 'call' property for attribute '${attributeName}' to be a non-empty string for '${definition.type}' node at depth '${depth}'`\n );\n }\n\n // If any node attribute arguments have been defined then they must have been defined in an array.\n if (typeof attributeDefinition.args !== \"undefined\" && !Array.isArray(attributeDefinition.args)) {\n throw new Error(\n `expected 'args' property for attribute '${attributeName}' to be an array for '${definition.type}' node at depth '${depth}'`\n );\n }\n });\n}\n\n/**\n * Validate an object that we expect to be a root node definition.\n * @param definition An object that we expect to be a root node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateRootNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"root\") {\n throw new Error(\"expected node type of 'root' for root node\");\n }\n\n // A root node cannot be the child of another node.\n if (depth > 0) {\n throw new Error(\"a root node cannot be the child of another node\");\n }\n\n // Check that, if the root node 'id' property is defined, it is a non-empty string.\n if (typeof definition.id !== \"undefined\" && (typeof definition.id !== \"string\" || definition.id.length === 0)) {\n throw new Error(\"expected non-empty string for 'id' property if defined for root node\");\n }\n\n // A root node is a decorator node, so must have a child node defined.\n if (typeof definition.child === \"undefined\") {\n throw new Error(\"expected property 'child' to be defined for root node\");\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n\n // Validate the child node of this decorator node.\n validateNode(definition.child, depth + 1);\n}\n\n/**\n * Validate an object that we expect to be a success node definition.\n * @param definition An object that we expect to be a success node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateSuccessNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"success\") {\n throw new Error(`expected node type of 'success' for success node at depth '${depth}'`);\n }\n\n // A success node is a decorator node, so must have a child node defined.\n if (typeof definition.child === \"undefined\") {\n throw new Error(`expected property 'child' to be defined for success node at depth '${depth}'`);\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n\n // Validate the child node of this decorator node.\n validateNode(definition.child, depth + 1);\n}\n\n/**\n * Validate an object that we expect to be a fail node definition.\n * @param definition An object that we expect to be a fail node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateFailNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"fail\") {\n throw new Error(`expected node type of 'fail' for fail node at depth '${depth}'`);\n }\n\n // A fail node is a decorator node, so must have a child node defined.\n if (typeof definition.child === \"undefined\") {\n throw new Error(`expected property 'child' to be defined for fail node at depth '${depth}'`);\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n\n // Validate the child node of this decorator node.\n validateNode(definition.child, depth + 1);\n}\n\n/**\n * Validate an object that we expect to be a flip node definition.\n * @param definition An object that we expect to be a flip node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateFlipNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"flip\") {\n throw new Error(`expected node type of 'flip' for flip node at depth '${depth}'`);\n }\n\n // A flip node is a decorator node, so must have a child node defined.\n if (typeof definition.child === \"undefined\") {\n throw new Error(`expected property 'child' to be defined for flip node at depth '${depth}'`);\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n\n // Validate the child node of this decorator node.\n validateNode(definition.child, depth + 1);\n}\n\n/**\n * Validate an object that we expect to be a repeat node definition.\n * @param definition An object that we expect to be a repeat node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateRepeatNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"repeat\") {\n throw new Error(`expected node type of 'repeat' for repeat node at depth '${depth}'`);\n }\n\n // A repeat node is a decorator node, so must have a child node defined.\n if (typeof definition.child === \"undefined\") {\n throw new Error(`expected property 'child' to be defined for repeat node at depth '${depth}'`);\n }\n\n // Check whether an 'iterations' property has been defined, it may not have been if this node is to repeat indefinitely.\n if (typeof definition.iterations !== \"undefined\") {\n if (Array.isArray(definition.iterations)) {\n // Check whether any elements of the array are not integer values.\n const containsNonInteger = !!definition.iterations.find((value: unknown) => !isInteger(value));\n\n // If the 'iterations' property is an array then it MUST contain two integer values.\n if (definition.iterations.length !== 2 || containsNonInteger) {\n throw new Error(\n `expected array containing two integer values for 'iterations' property if defined for repeat node at depth '${depth}'`\n );\n }\n\n // A repeat node must have a positive min and max iterations count if they are defined.\n if (definition.iterations[0] < 0 || definition.iterations[1] < 0) {\n throw new Error(\n `expected positive minimum and maximum iterations count for 'iterations' property if defined for repeat node at depth '${depth}'`\n );\n }\n\n // A repeat node must not have a minimum iterations count that exceeds the maximum iterations count.\n if (definition.iterations[0] > definition.iterations[1]) {\n throw new Error(\n `expected minimum iterations count that does not exceed the maximum iterations count for 'iterations' property if defined for repeat node at depth '${depth}'`\n );\n }\n } else if (isInteger(definition.iterations)) {\n // A repeat node must have a positive number of iterations if defined.\n if (definition.iterations < 0) {\n throw new Error(\n `expected positive iterations count for 'iterations' property if defined for repeat node at depth '${depth}'`\n );\n }\n } else {\n throw new Error(\n `expected integer value or array containing two integer values for 'iterations' property if defined for repeat node at depth '${depth}'`\n );\n }\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n\n // Validate the child node of this decorator node.\n validateNode(definition.child, depth + 1);\n}\n\n/**\n * Validate an object that we expect to be a retry node definition.\n * @param definition An object that we expect to be a retry node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateRetryNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"retry\") {\n throw new Error(`expected node type of 'retry' for retry node at depth '${depth}'`);\n }\n\n // A retry node is a decorator node, so must have a child node defined.\n if (typeof definition.child === \"undefined\") {\n throw new Error(`expected property 'child' to be defined for retry node at depth '${depth}'`);\n }\n\n // Check whether an 'attempts' property has been defined, it may not have been if this node is to retry indefinitely.\n if (typeof definition.attempts !== \"undefined\") {\n if (Array.isArray(definition.attempts)) {\n // Check whether any elements of the array are not integer values.\n const containsNonInteger = !!definition.attempts.find((value: unknown) => !isInteger(value));\n\n // If the 'attempts' property is an array then it MUST contain two integer values.\n if (definition.attempts.length !== 2 || containsNonInteger) {\n throw new Error(\n `expected array containing two integer values for 'attempts' property if defined for retry node at depth '${depth}'`\n );\n }\n\n // A retry node must have a positive min and max attempts count if they are defined.\n if (definition.attempts[0] < 0 || definition.attempts[1] < 0) {\n throw new Error(\n `expected positive minimum and maximum attempts count for 'attempts' property if defined for retry node at depth '${depth}'`\n );\n }\n\n // A retry node must not have a minimum attempts count that exceeds the maximum attempts count.\n if (definition.attempts[0] > definition.attempts[1]) {\n throw new Error(\n `expected minimum attempts count that does not exceed the maximum attempts count for 'attempts' property if defined for retry node at depth '${depth}'`\n );\n }\n } else if (isInteger(definition.attempts)) {\n // A retry node must have a positive number of attempts if defined.\n if (definition.attempts < 0) {\n throw new Error(\n `expected positive attempts count for 'attempts' property if defined for retry node at depth '${depth}'`\n );\n }\n } else {\n throw new Error(\n `expected integer value or array containing two integer values for 'attempts' property if defined for retry node at depth '${depth}'`\n );\n }\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n\n // Validate the child node of this decorator node.\n validateNode(definition.child, depth + 1);\n}\n\n/**\n * Validate an object that we expect to be a branch node definition.\n * @param definition An object that we expect to be a branch node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateBranchNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"branch\") {\n throw new Error(`expected node type of 'branch' for branch node at depth '${depth}'`);\n }\n\n // Check that the branch node 'ref' property is defined and is a non-empty string.\n if (typeof definition.ref !== \"string\" || definition.ref.length === 0) {\n throw new Error(`expected non-empty string for 'ref' property for branch node at depth '${depth}'`);\n }\n\n // It is invalid to define guard attributes for a branch node as they should be defined on the referenced root node.\n [\"while\", \"until\"].forEach((attributeName) => {\n if (typeof definition[attributeName] !== \"undefined\") {\n throw new Error(\n `guards should not be defined for branch nodes but guard '${attributeName}' was defined for branch node at depth '${depth}'`\n );\n }\n });\n\n // It is invalid to define callback attributes for a branch node as they should be defined on the referenced root node.\n [\"entry\", \"exit\", \"step\"].forEach((attributeName) => {\n if (typeof definition[attributeName] !== \"undefined\") {\n throw new Error(\n `callbacks should not be defined for branch nodes but callback '${attributeName}' was defined for branch node at depth '${depth}'`\n );\n }\n });\n}\n\n/**\n * Validate an object that we expect to be a action node definition.\n * @param definition An object that we expect to be a action node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateActionNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"action\") {\n throw new Error(`expected node type of 'action' for action node at depth '${depth}'`);\n }\n\n // The 'call' property must be defined for a action node definition.\n if (typeof definition.call !== \"string\" || definition.call.length === 0) {\n throw new Error(`expected non-empty string for 'call' property of action node at depth '${depth}'`);\n }\n\n // If any action function arguments have been defined then they must have been defined in an array.\n if (typeof definition.args !== \"undefined\" && !Array.isArray(definition.args)) {\n throw new Error(`expected array for 'args' property if defined for action node at depth '${depth}'`);\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n}\n\n/**\n * Validate an object that we expect to be a condition node definition.\n * @param definition An object that we expect to be a condition node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateConditionNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"condition\") {\n throw new Error(`expected node type of 'condition' for condition node at depth '${depth}'`);\n }\n\n // The 'call' property must be defined for a condition node definition.\n if (typeof definition.call !== \"string\" || definition.call.length === 0) {\n throw new Error(`expected non-empty string for 'call' property of condition node at depth '${depth}'`);\n }\n\n // If any condition function arguments have been defined then they must have been defined in an array.\n if (typeof definition.args !== \"undefined\" && !Array.isArray(definition.args)) {\n throw new Error(`expected array for 'args' property if defined for condition node at depth '${depth}'`);\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n}\n\n/**\n * Validate an object that we expect to be a wait node definition.\n * @param definition An object that we expect to be a wait node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateWaitNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"wait\") {\n throw new Error(`expected node type of 'wait' for wait node at depth '${depth}'`);\n }\n\n // Check whether a 'duration' property has been defined, it may not have been if this node is to wait indefinitely.\n if (typeof definition.duration !== \"undefined\") {\n if (Array.isArray(definition.duration)) {\n // Check whether any elements of the array are not integer values.\n const containsNonInteger = !!definition.duration.find((value: unknown) => !isInteger(value));\n\n // If the 'duration' property is an array then it MUST contain two integer values.\n if (definition.duration.length !== 2 || containsNonInteger) {\n throw new Error(\n `expected array containing two integer values for 'duration' property if defined for wait node at depth '${depth}'`\n );\n }\n\n // A wait node must have a positive min and max duration value if they are defined.\n if (definition.duration[0] < 0 || definition.duration[1] < 0) {\n throw new Error(\n `expected positive minimum and maximum duration for 'duration' property if defined for wait node at depth '${depth}'`\n );\n }\n\n // A wait node must not have a minimum duration value that exceeds the maximum duration value.\n if (definition.duration[0] > definition.duration[1]) {\n throw new Error(\n `expected minimum duration value that does not exceed the maximum duration value for 'duration' property if defined for wait node at depth '${depth}'`\n );\n }\n } else if (isInteger(definition.duration)) {\n // A wait node must have a positive duration value if defined.\n if (definition.duration < 0) {\n throw new Error(\n `expected positive duration value for 'duration' property if defined for wait node at depth '${depth}'`\n );\n }\n } else {\n throw new Error(\n `expected integer value or array containing two integer values for 'duration' property if defined for wait node at depth '${depth}'`\n );\n }\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n}\n\n/**\n * Validate an object that we expect to be a sequence node definition.\n * @param definition An object that we expect to be a sequence node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateSequenceNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"sequence\") {\n throw new Error(`expected node type of 'sequence' for sequence node at depth '${depth}'`);\n }\n\n // A sequence node is a composite node, so must have a children nodes array defined.\n if (!Array.isArray(definition.children) || definition.children.length === 0) {\n throw new Error(`expected non-empty 'children' array to be defined for sequence node at depth '${depth}'`);\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n\n // Validate the child nodes of this composite node.\n definition.children.forEach((child: any) => validateNode(child, depth + 1));\n}\n\n/**\n * Validate an object that we expect to be a selector node definition.\n * @param definition An object that we expect to be a selector node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateSelectorNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"selector\") {\n throw new Error(`expected node type of 'selector' for selector node at depth '${depth}'`);\n }\n\n // A selector node is a composite node, so must have a children nodes array defined.\n if (!Array.isArray(definition.children) || definition.children.length === 0) {\n throw new Error(`expected non-empty 'children' array to be defined for selector node at depth '${depth}'`);\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n\n // Validate the child nodes of this composite node.\n definition.children.forEach((child: any) => validateNode(child, depth + 1));\n}\n\n/**\n * Validate an object that we expect to be a parallel node definition.\n * @param definition An object that we expect to be a parallel node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateParallelNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"parallel\") {\n throw new Error(`expected node type of 'parallel' for parallel node at depth '${depth}'`);\n }\n\n // A parallel node is a composite node, so must have a children nodes array defined.\n if (!Array.isArray(definition.children) || definition.children.length === 0) {\n throw new Error(`expected non-empty 'children' array to be defined for parallel node at depth '${depth}'`);\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n\n // Validate the child nodes of this composite node.\n definition.children.forEach((child: any) => validateNode(child, depth + 1));\n}\n\n/**\n * A helper function to create a failure validation result with the given error message.\n * @param errorMessage The validation failure error message.\n * @returns A failure validation result with the given error message.\n */\nfunction createValidationFailureResult(errorMessage: string): DefinitionValidationResult {\n return { succeeded: false, errorMessage };\n}\n", "import { ActionResult, Agent, GlobalFunction } from \"./Agent\";\nimport { RootNodeDefinition } from \"./BehaviourTreeDefinition\";\n\nexport type InvokerFunction = (args: any[]) => ActionResult;\n\n/**\n * A singleton used to store and lookup registered functions and subtrees.\n */\nexport default class Lookup {\n /**\n * The object holding any registered functions keyed on function name.\n */\n private static functionTable: { [key: string]: GlobalFunction } = {};\n /**\n * The object holding any registered subtree root node definitions keyed on tree name.\n */\n private static subtreeTable: { [key: string]: RootNodeDefinition } = {};\n\n /**\n * Gets the function with the specified name.\n * @param name The name of the function.\n * @returns The function with the specified name.\n */\n public static getFunc(name: string): GlobalFunction {\n return this.functionTable[name];\n }\n\n /**\n * Sets the function with the specified name for later lookup.\n * @param name The name of the function.\n * @param func The function.\n */\n public static setFunc(name: string, func: GlobalFunction): void {\n this.functionTable[name] = func;\n }\n\n /**\n * Gets the function invoker for the specified agent and function name.\n * If a function with the specified name exists on the agent object then it will\n * be returned, otherwise we will then check the registered functions for a match.\n * @param agent The agent instance that this behaviour tree is modelling behaviour for.\n * @param name The function name.\n * @returns The function invoker for the specified agent and function name.\n */\n static getFuncInvoker(agent: Agent, name: string): InvokerFunction | null {\n // Check whether the agent contains the specified function.\n const foundOnAgent = agent[name];\n if (foundOnAgent && typeof foundOnAgent === \"function\") {\n return (args: any[]): boolean | ActionResult => foundOnAgent.apply(agent, args);\n }\n\n // The agent does not contain the specified function but it may have been registered at some point.\n if (this.functionTable[name] && typeof this.functionTable[name] === \"function\") {\n return (args: any[]) => this.functionTable[name](agent, ...args.map((arg) => arg.value));\n }\n\n // We have no function to invoke.\n return null;\n }\n\n /**\n * Gets all registered subtree root node definitions.\n */\n static getSubtrees(): { [key: string]: RootNodeDefinition } {\n return this.subtreeTable;\n }\n\n /**\n * Sets the subtree with the specified name for later lookup.\n * @param name The name of the subtree.\n * @param subtree The subtree.\n */\n static setSubtree(name: string, subtree: RootNodeDefinition) {\n this.subtreeTable[name] = subtree;\n }\n\n /**\n * Removes the registered function or subtree with the specified name.\n * @param name The name of the registered function or subtree.\n */\n static remove(name: string) {\n delete this.functionTable[name];\n delete this.subtreeTable[name];\n }\n\n /**\n * Remove all registered functions and subtrees.\n */\n static empty() {\n this.functionTable = {};\n this.subtreeTable = {};\n }\n}\n", "import Node from \"../../nodes/Node\";\n\n/**\n * An exception thrown when evaluating node guard path conditions and a conditions fails.\n */\nexport default class GuardUnsatisifedException extends Error {\n /**\n * @param source The node at which a guard condition failed.\n */\n constructor(private source: Node) {\n super(\"A guard path condition has failed\");\n }\n\n /**\n * Gets whether the specified node is the node at which a guard condition failed.\n * @param node The node to check against the source node.\n * @returns Whether the specified node is the node at which a guard condition failed.\n */\n isSourceNode = (node: Node) => node === this.source;\n}\n", "import { Agent } from \"../../Agent\";\nimport Guard from \"./Guard\";\nimport Node from \"../../nodes/Node\";\nimport GuardUnsatisifedException from \"./GuardUnsatisifedException\";\n\nexport type GuardPathPart = {\n node: Node;\n guards: Guard[];\n};\n\n/**\n * Represents a path of node guards along a root-to-leaf tree path.\n */\nexport default class GuardPath {\n /**\n * @param nodes An array of objects defining a node instance -> guard link, ordered by node depth.\n */\n constructor(private nodes: GuardPathPart[]) {}\n\n /**\n * Evaluate guard conditions for all guards in the tree path, moving outwards from the root.\n * @param agent The agent, required for guard evaluation.\n * @returns An evaluation results object.\n */\n evaluate = (agent: Agent) => {\n // We need to evaluate guard conditions for nodes up the tree, moving outwards from the root.\n for (const details of this.nodes) {\n // There can be multiple guards per node.\n for (const guard of details.guards) {\n // Check whether the guard condition passes, and throw an exception if not.\n if (!guard.isSatisfied(agent)) {\n throw new GuardUnsatisifedException(details.node);\n }\n }\n }\n };\n}\n", "import { BehaviourTreeOptions } from \"../BehaviourTreeOptions\";\nimport State, { AnyState } from \"../State\";\nimport { Agent } from \"../Agent\";\nimport Leaf from \"./leaf/Leaf\";\nimport Attribute from \"../attributes/Attribute\";\nimport Entry from \"../attributes/callbacks/Entry\";\nimport Exit from \"../attributes/callbacks/Exit\";\nimport Step from \"../attributes/callbacks/Step\";\nimport Guard from \"../attributes/guards/Guard\";\nimport GuardPath from \"../attributes/guards/GuardPath\";\nimport GuardUnsatisifedException from \"../attributes/guards/GuardUnsatisifedException\";\n\n/**\n * A base node.\n */\nexport default abstract class Node {\n /**\n * The node uid.\n */\n private readonly uid: string = createNodeUid();\n /**\n * The node state.\n */\n private state: AnyState = State.READY;\n /**\n * The guard path to evaluate as part of a node update.\n */\n private guardPath: GuardPath | undefined;\n\n /**\n * @param type The node type.\n * @param attributes The node attributes.\n * @param args The node argument definitions.\n */\n constructor(private type: string, private attributes: Attribute[], private args: any[]) {}\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected abstract onUpdate(agent: Agent, options: BehaviourTreeOptions): void;\n\n /**\n * Gets the name of the node.\n */\n public abstract getName(): string;\n\n /**\n * Gets whether this node is a leaf node.\n */\n public abstract isLeafNode: () => this is Leaf;\n\n /**\n * Gets/Sets the state of the node.\n */\n getState = (): AnyState => this.state;\n setState = (value: AnyState): void => {\n this.state = value;\n };\n\n /**\n * Gets the unique id of the node.\n */\n getUid = () => this.uid;\n\n /**\n * Gets the type of the node.\n */\n getType = () => this.type;\n\n /**\n * Gets the node attributes.\n */\n getAttributes = () => this.attributes;\n\n /**\n * Gets the node arguments.\n */\n getArguments = () => this.args;\n\n /**\n * Gets the node attribute with the specified type, or null if it does not exist.\n */\n getAttribute(type: \"entry\" | \"ENTRY\"): Entry;\n getAttribute(type: \"exit\" | \"EXIT\"): Exit;\n getAttribute(type: \"step\" | \"STEP\"): Step;\n getAttribute(type: string): Attribute {\n return (\n this.getAttributes().filter((decorator) => decorator.type.toUpperCase() === type.toUpperCase())[0] || null\n );\n }\n\n /**\n * Gets the node attributes.\n */\n getGuardAttributes = (): Guard[] => this.getAttributes().filter((decorator) => decorator.isGuard()) as Guard[];\n\n /**\n * Sets the guard path to evaluate as part of a node update.\n */\n setGuardPath = (value: GuardPath) => (this.guardPath = value);\n\n /**\n * Gets whether a guard path is assigned to this node.\n */\n hasGuardPath = () => !!this.guardPath;\n\n /**\n * Gets whether this node is in the specified state.\n * @param value The value to compare to the node state.\n */\n public is(value: AnyState): boolean {\n return this.state === value;\n }\n\n /**\n * Reset the state of the node.\n */\n public reset(): void {\n this.setState(State.READY);\n }\n\n /**\n * Abort the running of this node.\n * @param agent The agent.\n */\n public abort(agent: Agent): void {\n // There is nothing to do if this node is not in the running state.\n if (!this.is(State.RUNNING)) {\n return;\n }\n\n // Reset the state of this node.\n this.reset();\n\n this.getAttribute(\"exit\")?.callAgentFunction(agent, false, true);\n }\n\n /**\n * Update the node.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n * @returns The result of the update.\n */\n public update(agent: Agent, options: BehaviourTreeOptions): void {\n // If this node is already in a 'SUCCEEDED' or 'FAILED' state then there is nothing to do.\n if (this.is(State.SUCCEEDED) || this.is(State.FAILED)) {\n return;\n }\n\n try {\n // Evaluate all of the guard path conditions for the current tree path.\n this.guardPath!.evaluate(agent);\n\n // If this node is in the READY state then call the ENTRY for this node if it exists.\n if (this.is(State.READY)) {\n this.getAttribute(\"entry\")?.callAgentFunction(agent);\n }\n\n this.getAttribute(\"step\")?.callAgentFunction(agent);\n\n // Do the actual update.\n this.onUpdate(agent, options);\n\n // If this node is now in a 'SUCCEEDED' or 'FAILED' state then call the EXIT for this node if it exists.\n if (this.is(State.SUCCEEDED) || this.is(State.FAILED)) {\n this.getAttribute(\"exit\")?.callAgentFunction(agent, this.is(State.SUCCEEDED), false);\n }\n } catch (error) {\n // If the error is a GuardUnsatisfiedException then we need to determine if this node is the source.\n if (error instanceof GuardUnsatisifedException && error.isSourceNode(this)) {\n // Abort the current node.\n this.abort(agent);\n\n // Any node that is the source of an abort will be a failed node.\n this.setState(State.FAILED);\n } else {\n throw error;\n }\n }\n }\n}\n\n/**\n * Create a randomly generated node uid.\n * @returns A randomly generated node uid.\n */\nfunction createNodeUid(): string {\n var S4 = function () {\n return (((1 + Math.random()) * 0x10000) | 0).toString(16).substring(1);\n };\n return S4() + S4() + \"-\" + S4() + \"-\" + S4() + \"-\" + S4() + \"-\" + S4() + S4() + S4();\n}\n", "import Node from \"../Node\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\n\n/**\n * A composite node that wraps child nodes.\n */\nexport default abstract class Composite extends Node {\n /**\n * @param type The node type.\n * @param attributes The node attributes.\n * @param children The child nodes.\n */\n constructor(type: string, attributes: Attribute[], protected children: Node[]) {\n super(type, attributes, []);\n }\n\n /**\n * Gets whether this node is a leaf node.\n */\n isLeafNode = () => false;\n\n /**\n * Gets the children of this node.\n */\n getChildren = () => this.children;\n\n /**\n * Reset the state of the node.\n */\n reset = () => {\n // Reset the state of this node.\n this.setState(State.READY);\n\n // Reset the state of any child nodes.\n this.getChildren().forEach((child) => child.reset());\n };\n\n /**\n * Abort the running of this node.\n * @param agent The agent.\n */\n abort = (agent: Agent) => {\n // There is nothing to do if this node is not in the running state.\n if (!this.is(State.RUNNING)) {\n return;\n }\n\n // Abort any child nodes.\n this.getChildren().forEach((child) => child.abort(agent));\n\n // Reset the state of this node.\n this.reset();\n\n this.getAttribute(\"exit\")?.callAgentFunction(agent, false, true);\n };\n}\n", "import Composite from \"./Composite\";\nimport State from \"../../State\";\nimport Node from \"../Node\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A PARALLEL node.\n * The child nodes are executed concurrently until one fails or all succeed.\n */\nexport default class Parallel extends Composite {\n /**\n * @param attributes The node attributes.\n * @param children The child nodes.\n */\n constructor(attributes: Attribute[], children: Node[]) {\n super(\"parallel\", attributes, children);\n }\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // Keep a count of the number of succeeded child nodes.\n let succeededCount = 0;\n\n let hasChildFailed = false;\n\n // Iterate over all of the children of this node.\n for (const child of this.children) {\n // If the child has never been updated or is running then we will need to update it now.\n if (child.getState() === State.READY || child.getState() === State.RUNNING) {\n // Update the child of this node.\n child.update(agent, options);\n }\n\n // If the current child has a state of 'SUCCEEDED' then we should move on to the next child.\n if (child.getState() === State.SUCCEEDED) {\n // The child node has succeeded, keep track of this to determine if all children have.\n succeededCount++;\n\n // The child node succeeded, but we have not finished checking every child node yet.\n continue;\n }\n\n // If the current child has a state of 'FAILED' then this node is also a 'FAILED' node.\n if (child.getState() === State.FAILED) {\n hasChildFailed = true;\n\n // There is no need to check the rest of the children.\n break;\n }\n\n // The node should be in the 'RUNNING' state.\n if (child.getState() !== State.RUNNING) {\n // The child node was not in an expected state.\n throw new Error(\"child node was not in an expected state.\");\n }\n }\n\n if (hasChildFailed) {\n // This node is a 'FAILED' node.\n this.setState(State.FAILED);\n\n // Abort every running child.\n for (const child of this.children) {\n if (child.getState() === State.RUNNING) {\n child.abort(agent);\n }\n }\n } else {\n // If all children have succeeded then this node has also succeeded, otherwise it is still running.\n this.setState(succeededCount === this.children.length ? State.SUCCEEDED : State.RUNNING);\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => \"PARALLEL\";\n}\n", "import Composite from \"./Composite\";\nimport Node from \"../Node\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A SELECTOR node.\n * The child nodes are executed in sequence until one succeeds or all fail.\n */\nexport default class Selector extends Composite {\n /**\n * @param attributes The node attributes.\n * @param children The child nodes.\n */\n constructor(attributes: Attribute[], protected children: Node[]) {\n super(\"selector\", attributes, children);\n }\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // Iterate over all of the children of this node.\n for (const child of this.children) {\n // If the child has never been updated or is running then we will need to update it now.\n if (child.getState() === State.READY || child.getState() === State.RUNNING) {\n // Update the child of this node.\n child.update(agent, options);\n }\n\n // If the current child has a state of 'SUCCEEDED' then this node is also a 'SUCCEEDED' node.\n if (child.getState() === State.SUCCEEDED) {\n // This node is a 'SUCCEEDED' node.\n this.setState(State.SUCCEEDED);\n\n // There is no need to check the rest of the selector nodes.\n return;\n }\n\n // If the current child has a state of 'FAILED' then we should move on to the next child.\n if (child.getState() === State.FAILED) {\n // Find out if the current child is the last one in the selector.\n // If it is then this sequence node has also failed.\n if (this.children.indexOf(child) === this.children.length - 1) {\n // This node is a 'FAILED' node.\n this.setState(State.FAILED);\n\n // There is no need to check the rest of the selector as we have completed it.\n return;\n } else {\n // The child node failed, try the next one.\n continue;\n }\n }\n\n // The node should be in the 'RUNNING' state.\n if (child.getState() === State.RUNNING) {\n // This node is a 'RUNNING' node.\n this.setState(State.RUNNING);\n\n // There is no need to check the rest of the selector as the current child is still running.\n return;\n }\n\n // The child node was not in an expected state.\n throw new Error(\"child node was not in an expected state.\");\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => \"SELECTOR\";\n}\n", "import Composite from \"./Composite\";\nimport Node from \"../Node\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A SEQUENCE node.\n * The child nodes are executed in sequence until one fails or all succeed.\n */\nexport default class Sequence extends Composite {\n /**\n * @param attributes The node attributes.\n * @param children The child nodes.\n */\n constructor(attributes: Attribute[], protected children: Node[]) {\n super(\"sequence\", attributes, children);\n }\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // Iterate over all of the children of this node.\n for (const child of this.children) {\n // If the child has never been updated or is running then we will need to update it now.\n if (child.getState() === State.READY || child.getState() === State.RUNNING) {\n // Update the child of this node.\n child.update(agent, options);\n }\n\n // If the current child has a state of 'SUCCEEDED' then we should move on to the next child.\n if (child.getState() === State.SUCCEEDED) {\n // Find out if the current child is the last one in the sequence.\n // If it is then this sequence node has also succeeded.\n if (this.children.indexOf(child) === this.children.length - 1) {\n // This node is a 'SUCCEEDED' node.\n this.setState(State.SUCCEEDED);\n\n // There is no need to check the rest of the sequence as we have completed it.\n return;\n } else {\n // The child node succeeded, but we have not finished the sequence yet.\n continue;\n }\n }\n\n // If the current child has a state of 'FAILED' then this node is also a 'FAILED' node.\n if (child.getState() === State.FAILED) {\n // This node is a 'FAILED' node.\n this.setState(State.FAILED);\n\n // There is no need to check the rest of the sequence.\n return;\n }\n\n // The node should be in the 'RUNNING' state.\n if (child.getState() === State.RUNNING) {\n // This node is a 'RUNNING' node.\n this.setState(State.RUNNING);\n\n // There is no need to check the rest of the sequence as the current child is still running.\n return;\n }\n\n // The child node was not in an expected state.\n throw new Error(\"child node was not in an expected state.\");\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => \"SEQUENCE\";\n}\n", "import createLotto from \"lotto-draw\";\n\nimport Node from \"../Node\";\nimport Composite from \"./Composite\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A LOTTO node.\n * A winning child is picked on the initial update of this node, based on ticket weighting.\n * The state of this node will match the state of the winning child.\n */\nexport default class Lotto extends Composite {\n /**\n * @param attributes The node attributes.\n * @param weights The child node weights.\n * @param children The child nodes.\n */\n constructor(attributes: Attribute[], private weights: number[] | undefined, children: Node[]) {\n super(\"lotto\", attributes, children);\n }\n\n /**\n * The child node selected to be the active one.\n */\n private selectedChild: Node | undefined;\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // If this node is in the READY state then we need to pick a winning child node.\n if (this.is(State.READY)) {\n // Create a lotto draw with which to randomly pick a child node to become the active one.\n const lottoDraw = createLotto({\n // Hook up the optional 'random' behaviour tree function option to the one used by 'lotto-draw'.\n random: options.random,\n // Pass in each child node as a participant in the lotto draw with their respective ticket count.\n participants: this.children.map((child, index) => [child, this.weights?.[index] || 1])\n });\n\n // Randomly pick a child based on ticket weighting, this will become the active child for this composite node.\n this.selectedChild = lottoDraw.draw() || undefined;\n }\n\n // If something went wrong and we don't have an active child then we should throw an error.\n if (!this.selectedChild) {\n throw new Error(\"failed to update lotto node as it has no active child\");\n }\n\n // If the selected child has never been updated or is running then we will need to update it now.\n if (this.selectedChild.getState() === State.READY || this.selectedChild.getState() === State.RUNNING) {\n this.selectedChild.update(agent, options);\n }\n\n // The state of the lotto node is the state of its selected child.\n this.setState(this.selectedChild.getState());\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => (this.weights ? `LOTTO [${this.weights.join(\",\")}]` : \"LOTTO\");\n}\n", "import Node from \"../Node\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\n\n/**\n * A decorator node that wraps a single child node.\n */\nexport default abstract class Decorator extends Node {\n /**\n * @param type The node type.\n * @param attributes The node attributes.\n * @param child The child node.\n */\n constructor(type: string, attributes: Attribute[], protected child: Node) {\n super(type, attributes, []);\n }\n\n /**\n * Gets whether this node is a leaf node.\n */\n isLeafNode = () => false;\n\n /**\n * Gets the children of this node.\n */\n getChildren = () => [this.child];\n\n /**\n * Reset the state of the node.\n */\n reset = () => {\n // Reset the state of this node.\n this.setState(State.READY);\n\n // Reset the state of the child node.\n this.child.reset();\n };\n\n /**\n * Abort the running of this node.\n * @param agent The agent.\n */\n abort = (agent: Agent) => {\n // There is nothing to do if this node is not in the running state.\n if (!this.is(State.RUNNING)) {\n return;\n }\n\n // Abort the child node.\n this.child.abort(agent);\n\n // Reset the state of this node.\n this.reset();\n\n this.getAttribute(\"exit\")?.callAgentFunction(agent, false, true);\n };\n}\n", "import Node from \"../Node\";\nimport Decorator from \"./Decorator\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A Fail node.\n * This node wraps a single child and will always move to the 'FAILED' state when the child moves to a 'SUCCEEDED' or 'FAILED' state.\n */\nexport default class Fail extends Decorator {\n /**\n * @param attributes The node attributes.\n * @param child The child node.\n */\n constructor(attributes: Attribute[], child: Node) {\n super(\"fail\", attributes, child);\n }\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // If the child has never been updated or is running then we will need to update it now.\n if (this.child.getState() === State.READY || this.child.getState() === State.RUNNING) {\n this.child.update(agent, options);\n }\n\n // The state of this node will depend in the state of its child.\n switch (this.child.getState()) {\n case State.RUNNING:\n this.setState(State.RUNNING);\n break;\n\n case State.SUCCEEDED:\n case State.FAILED:\n this.setState(State.FAILED);\n break;\n\n default:\n this.setState(State.READY);\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => \"FAIL\";\n}\n", "import Decorator from \"./Decorator\";\nimport State from \"../../State\";\nimport Node from \"../Node\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A Flip node.\n * This node wraps a single child and will flip the state of the child state.\n */\nexport default class Flip extends Decorator {\n /**\n * @param attributes The node attributes.\n * @param child The child node.\n */\n constructor(attributes: Attribute[], child: Node) {\n super(\"flip\", attributes, child);\n }\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // If the child has never been updated or is running then we will need to update it now.\n if (this.child.getState() === State.READY || this.child.getState() === State.RUNNING) {\n this.child.update(agent, options);\n }\n\n // The state of this node will depend in the state of its child.\n switch (this.child.getState()) {\n case State.RUNNING:\n this.setState(State.RUNNING);\n break;\n\n case State.SUCCEEDED:\n this.setState(State.FAILED);\n break;\n\n case State.FAILED:\n this.setState(State.SUCCEEDED);\n break;\n\n default:\n this.setState(State.READY);\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => \"FLIP\";\n}\n", "import Node from \"../Node\";\nimport Decorator from \"./Decorator\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A REPEAT node.\n * The node has a single child which can have:\n * -- A number of iterations for which to repeat the child node.\n * -- An infinite repeat loop if neither an iteration count or a condition function is defined.\n * The REPEAT node will stop and have a 'FAILED' state if its child is ever in a 'FAILED' state after an update.\n * The REPEAT node will attempt to move on to the next iteration if its child is ever in a 'SUCCEEDED' state.\n */\nexport default class Repeat extends Decorator {\n /**\n * @param attributes The node attributes.\n * @param iterations The number of iterations to repeat the child node.\n * @param iterationsMin The minimum possible number of iterations to repeat the child node.\n * @param iterationsMax The maximum possible number of iterations to repeat the child node.\n * @param child The child node.\n */\n constructor(\n attributes: Attribute[],\n private iterations: number | null,\n private iterationsMin: number | null,\n private iterationsMax: number | null,\n child: Node\n ) {\n super(\"repeat\", attributes, child);\n }\n\n /**\n * The number of target iterations to make.\n */\n private targetIterationCount: number | null = null;\n\n /**\n * The current iteration count.\n */\n private currentIterationCount: number = 0;\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // If this node is in the READY state then we need to reset the child and the target iteration count.\n if (this.is(State.READY)) {\n // Reset the child node.\n this.child.reset();\n\n // Reset the current iteration count.\n this.currentIterationCount = 0;\n\n // Set the target iteration count.\n this.setTargetIterationCount(options);\n }\n\n // Do a check to see if we can iterate. If we can then this node will move into the 'RUNNING' state.\n // If we cannot iterate then we have hit our target iteration count, which means that the node has succeeded.\n if (this.canIterate()) {\n // This node is in the running state and can do its initial iteration.\n this.setState(State.RUNNING);\n\n // We may have already completed an iteration, meaning that the child node will be in the SUCCEEDED state.\n // If this is the case then we will have to reset the child node now.\n if (this.child.getState() === State.SUCCEEDED) {\n this.child.reset();\n }\n\n // Update the child of this node.\n this.child.update(agent, options);\n\n // If the child moved into the FAILED state when we updated it then there is nothing left to do and this node has also failed.\n // If it has moved into the SUCCEEDED state then we have completed the current iteration.\n if (this.child.getState() === State.FAILED) {\n // The child has failed, meaning that this node has failed.\n this.setState(State.FAILED);\n\n return;\n } else if (this.child.getState() === State.SUCCEEDED) {\n // We have completed an iteration.\n this.currentIterationCount += 1;\n }\n } else {\n // This node is in the 'SUCCEEDED' state as we cannot iterate any more.\n this.setState(State.SUCCEEDED);\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => {\n if (this.iterations !== null) {\n return `REPEAT ${this.iterations}x`;\n } else if (this.iterationsMin !== null && this.iterationsMax !== null) {\n return `REPEAT ${this.iterationsMin}x-${this.iterationsMax}x`;\n } else {\n return \"REPEAT\";\n }\n };\n\n /**\n * Reset the state of the node.\n */\n reset = () => {\n // Reset the state of this node.\n this.setState(State.READY);\n\n // Reset the current iteration count.\n this.currentIterationCount = 0;\n\n // Reset the child node.\n this.child.reset();\n };\n\n /**\n * Gets whether an iteration can be made.\n * @returns Whether an iteration can be made.\n */\n private canIterate = () => {\n if (this.targetIterationCount !== null) {\n // We can iterate as long as we have not reached our target iteration count.\n return this.currentIterationCount < this.targetIterationCount;\n }\n\n // If neither an iteration count or a condition function were defined then we can iterate indefinitely.\n return true;\n };\n\n /**\n * Sets the target iteration count.\n * @param options The behaviour tree options object.\n */\n private setTargetIterationCount = (options: BehaviourTreeOptions) => {\n // Are we dealing with an explicit iteration count or will we be randomly picking a iteration count between the min and max iteration count.\n if (this.iterations !== null) {\n this.targetIterationCount = this.iterations;\n } else if (this.iterationsMin !== null && this.iterationsMax !== null) {\n // We will be picking a random iteration count between a min and max iteration count, if the optional 'random'\n // behaviour tree function option is defined then we will be using that, otherwise we will fall back to using Math.random.\n const random = typeof options.random === \"function\" ? options.random : Math.random;\n\n // Pick a random iteration count between a min and max iteration count.\n this.targetIterationCount = Math.floor(\n random() * (this.iterationsMax - this.iterationsMin + 1) + this.iterationsMin\n );\n } else {\n this.targetIterationCount = null;\n }\n };\n}\n", "import Node from \"../Node\";\nimport Decorator from \"./Decorator\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A RETRY node.\n * The node has a single child which can have:\n * -- A number of iterations for which to repeat the child node.\n * -- An infinite repeat loop if neither an iteration count or a condition function is defined.\n * The RETRY node will stop and have a 'SUCCEEDED' state if its child is ever in a 'SUCCEEDED' state after an update.\n * The RETRY node will attempt to move on to the next iteration if its child is ever in a 'FAILED' state.\n */\nexport default class Retry extends Decorator {\n /**\n * @param attributes The node attributes.\n * @param attempts The number of attempts to retry the child node.\n * @param attemptsMin The minimum possible number of attempts to retry the child node.\n * @param attemptsMax The maximum possible number of attempts to retry the child node.\n * @param child The child node.\n */\n constructor(\n attributes: Attribute[],\n private attempts: number | null,\n private attemptsMin: number | null,\n private attemptsMax: number | null,\n child: Node\n ) {\n super(\"retry\", attributes, child);\n }\n\n /**\n * The number of target attempts to make.\n */\n private targetAttemptCount: number | null = null;\n\n /**\n * The current attempt count.\n */\n private currentAttemptCount: number = 0;\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // If this node is in the READY state then we need to reset the child and the target attempt count.\n if (this.is(State.READY)) {\n // Reset the child node.\n this.child.reset();\n\n // Reset the current attempt count.\n this.currentAttemptCount = 0;\n\n // Set the target attempt count.\n this.setTargetAttemptCount(options);\n }\n\n // Do a check to see if we can attempt. If we can then this node will move into the 'RUNNING' state.\n // If we cannot attempt then we have hit our target attempt count, which means that the node has succeeded.\n if (this.canAttempt()) {\n // This node is in the running state and can do its initial attempt.\n this.setState(State.RUNNING);\n\n // We may have already completed an attempt, meaning that the child node will be in the FAILED state.\n // If this is the case then we will have to reset the child node now.\n if (this.child.getState() === State.FAILED) {\n this.child.reset();\n }\n\n // Update the child of this node.\n this.child.update(agent, options);\n\n // If the child moved into the SUCCEEDED state when we updated it then there is nothing left to do and this node has also succeeded.\n // If it has moved into the FAILED state then we have completed the current attempt.\n if (this.child.getState() === State.SUCCEEDED) {\n // The child has succeeded, meaning that this node has succeeded.\n this.setState(State.SUCCEEDED);\n\n return;\n } else if (this.child.getState() === State.FAILED) {\n // We have completed an attempt.\n this.currentAttemptCount += 1;\n }\n } else {\n // This node is in the 'FAILED' state as we cannot iterate any more.\n this.setState(State.FAILED);\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => {\n if (this.attempts !== null) {\n return `RETRY ${this.attempts}x`;\n } else if (this.attemptsMin !== null && this.attemptsMax !== null) {\n return `RETRY ${this.attemptsMin}x-${this.attemptsMax}x`;\n } else {\n return \"RETRY\";\n }\n };\n\n /**\n * Reset the state of the node.\n */\n reset = () => {\n // Reset the state of this node.\n this.setState(State.READY);\n\n // Reset the current attempt count.\n this.currentAttemptCount = 0;\n\n // Reset the child node.\n this.child.reset();\n };\n\n /**\n * Gets whether an attempt can be made.\n * @returns Whether an attempt can be made.\n */\n canAttempt = () => {\n if (this.targetAttemptCount !== null) {\n // We can attempt as long as we have not reached our target attempt count.\n return this.currentAttemptCount < this.targetAttemptCount;\n }\n\n // If neither an attempt count or a condition function were defined then we can attempt indefinitely.\n return true;\n };\n\n /**\n * Sets the target attempt count.\n * @param options The behaviour tree options object.\n */\n setTargetAttemptCount = (options: BehaviourTreeOptions) => {\n // Are we dealing with an explicit attempt count or will we be randomly picking an attempt count between the min and max attempt count.\n if (this.attempts !== null) {\n this.targetAttemptCount = this.attempts;\n } else if (this.attemptsMin !== null && this.attemptsMax !== null) {\n // We will be picking a random attempt count between a min and max attempt count, if the optional 'random'\n // behaviour tree function option is defined then we will be using that, otherwise we will fall back to using Math.random.\n const random = typeof options.random === \"function\" ? options.random : Math.random;\n\n // Pick a random attempt count between a min and max attempt count.\n this.targetAttemptCount = Math.floor(\n random() * (this.attemptsMax - this.attemptsMin + 1) + this.attemptsMin\n );\n } else {\n this.targetAttemptCount = null;\n }\n };\n}\n", "import Node from \"../Node\";\nimport Decorator from \"./Decorator\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A Root node.\n * The root node will have a single child.\n */\nexport default class Root extends Decorator {\n /**\n * @param attributes The node attributes.\n * @param child The child node.\n */\n constructor(attributes: Attribute[], child: Node) {\n super(\"root\", attributes, child);\n }\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // If the child has never been updated or is running then we will need to update it now.\n if (this.child.getState() === State.READY || this.child.getState() === State.RUNNING) {\n // Update the child of this node.\n this.child.update(agent, options);\n }\n\n // The state of the root node is the state of its child.\n this.setState(this.child.getState());\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => \"ROOT\";\n}\n", "import Node from \"../Node\";\nimport Decorator from \"./Decorator\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A Succeed node.\n * This node wraps a single child and will always move to the 'SUCCEEDED' state when the child moves to a 'SUCCEEDED' or 'FAILED' state.\n */\nexport default class Succeed extends Decorator {\n /**\n * @param attributes The node attributes.\n * @param child The child node.\n */\n constructor(attributes: Attribute[], child: Node) {\n super(\"succeed\", attributes, child);\n }\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // If the child has never been updated or is running then we will need to update it now.\n if (this.child.getState() === State.READY || this.child.getState() === State.RUNNING) {\n this.child.update(agent, options);\n }\n\n // The state of this node will depend in the state of its child.\n switch (this.child.getState()) {\n case State.RUNNING:\n this.setState(State.RUNNING);\n break;\n\n case State.SUCCEEDED:\n case State.FAILED:\n this.setState(State.SUCCEEDED);\n break;\n\n default:\n this.setState(State.READY);\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => \"SUCCEED\";\n}\n", "import Node from \"../Node\";\n\n/**\n * A leaf node.\n */\nexport default abstract class Leaf extends Node {\n /**\n * Gets whether this node is a leaf node.\n */\n isLeafNode = () => true;\n}\n", "import { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\nimport State, { CompleteState } from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Leaf from \"./Leaf\";\nimport Lookup from \"../../Lookup\";\nimport Attribute from \"../../attributes/Attribute\";\n\n/**\n * An Action leaf node.\n * This represents an immediate or ongoing state of behaviour.\n */\nexport default class Action extends Leaf {\n /**\n * @param attributes The node attributes.\n * @param actionName The action name.\n * @param actionArguments The array of action argument definitions.\n */\n constructor(attributes: Attribute[], private actionName: string, private actionArguments: any[]) {\n super(\"action\", attributes, actionArguments);\n }\n\n /**\n * Whether there is a pending update promise.\n */\n private isUsingUpdatePromise = false;\n\n /**\n * The finished state result of an update promise.\n */\n private updatePromiseStateResult: CompleteState | null = null;\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // If the result of this action depends on an update promise then there is nothing to do until\n // it resolves, unless there has been a value set as a result of the update promise resolving.\n if (this.isUsingUpdatePromise) {\n // Check whether the update promise has resolved with a state value.\n if (this.updatePromiseStateResult) {\n // Set the state of this node to match the state returned by the promise.\n this.setState(this.updatePromiseStateResult);\n }\n\n return;\n }\n\n // Attempt to get the invoker for the action function.\n const actionFuncInvoker = Lookup.getFuncInvoker(agent, this.actionName);\n\n // The action function should be defined.\n if (actionFuncInvoker === null) {\n throw new Error(\n `cannot update action node as the action '${this.actionName}' function is not defined on the agent and has not been registered`\n );\n }\n\n // Call the action function, the result of which may be:\n // - The finished state of this action node.\n // - A promise to return a finished node state.\n // - Undefined if the node should remain in the running state.\n const updateResult = actionFuncInvoker(this.actionArguments) as CompleteState | Promise;\n\n if (updateResult instanceof Promise) {\n updateResult.then(\n (result) => {\n // If 'isUpdatePromisePending' is null then the promise was cleared as it was resolving, probably via an abort of reset.\n if (!this.isUsingUpdatePromise) {\n return;\n }\n\n // Check to make sure the result is a valid finished state.\n if (result !== State.SUCCEEDED && result !== State.FAILED) {\n throw new Error(\n \"action node promise resolved with an invalid value, expected a State.SUCCEEDED or State.FAILED value to be returned\"\n );\n }\n\n // Set pending update promise state result to be processed on next update.\n this.updatePromiseStateResult = result;\n },\n (reason) => {\n // If 'isUpdatePromisePending' is null then the promise was cleared as it was resolving, probably via an abort of reset.\n if (!this.isUsingUpdatePromise) {\n return;\n }\n\n // Just throw whatever was returned as the rejection argument.\n throw new Error(reason);\n }\n );\n\n // This node will be in the 'RUNNING' state until the update promise resolves.\n this.setState(State.RUNNING);\n\n // We are now waiting for the promise returned by the use to resolve before we know what state this node is in.\n this.isUsingUpdatePromise = true;\n } else {\n // Validate the returned value.\n this.validateUpdateResult(updateResult);\n\n // Set the state of this node, this may be undefined, which just means that the node is still in the 'RUNNING' state.\n this.setState(updateResult || State.RUNNING);\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => this.actionName;\n\n /**\n * Reset the state of the node.\n */\n reset = () => {\n // Reset the state of this node.\n this.setState(State.READY);\n\n // There is no longer an update promise that we care about.\n this.isUsingUpdatePromise = false;\n this.updatePromiseStateResult = null;\n };\n\n /**\n * Validate the result of an update function call.\n * @param result The result of an update function call.\n */\n private validateUpdateResult = (result: CompleteState | boolean) => {\n switch (result) {\n case State.SUCCEEDED:\n case State.FAILED:\n case undefined:\n return;\n default:\n throw new Error(\n `action '${this.actionName}' 'onUpdate' returned an invalid response, expected an optional State.SUCCEEDED or State.FAILED value to be returned`\n );\n }\n };\n}\n", "import { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Leaf from \"./Leaf\";\nimport Lookup from \"../../Lookup\";\nimport Attribute from \"../../attributes/Attribute\";\n\n/**\n * A Condition leaf node.\n * This will succeed or fail immediately based on an agent predicate, without moving to the 'RUNNING' state.\n */\nexport default class Condition extends Leaf {\n /**\n * @param attributes The node attributes.\n * @param conditionName The name of the condition function.\n * @param conditionArguments The array of condition argument definitions.\n */\n constructor(attributes: Attribute[], private conditionName: string, private conditionArguments: any[]) {\n super(\"condition\", attributes, conditionArguments);\n }\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // Attempt to get the invoker for the condition function.\n const conditionFuncInvoker = Lookup.getFuncInvoker(agent, this.conditionName);\n\n // The condition function should be defined.\n if (conditionFuncInvoker === null) {\n throw new Error(\n `cannot update condition node as the condition '${this.conditionName}' function is not defined on the agent and has not been registered`\n );\n }\n\n // Call the condition function to determine the state of this node.\n this.setState(!!conditionFuncInvoker(this.conditionArguments) ? State.SUCCEEDED : State.FAILED);\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => this.conditionName;\n}\n", "import Leaf from \"./Leaf\";\nimport State from \"../../State\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { Agent } from \"../../Agent\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A WAIT node.\n * The state of this node will change to SUCCEEDED after a duration of time\n */\nexport default class Wait extends Leaf {\n /**\n * @param attributes The node attributes.\n * @param duration The duration that this node will wait to succeed in milliseconds.\n * @param durationMin The minimum possible duration in milliseconds that this node will wait to succeed.\n * @param durationMax The maximum possible duration in milliseconds that this node will wait to succeed.\n */\n constructor(\n attributes: Attribute[],\n private duration: number | null,\n private durationMin: number | null,\n private durationMax: number | null\n ) {\n super(\"wait\", attributes, []);\n }\n\n /**\n * The time in milliseconds at which this node was first updated.\n */\n private initialUpdateTime: number = 0;\n\n /**\n * The total duration in milliseconds that this node will be waiting for.\n */\n private totalDuration: number | null = null;\n\n /**\n * The duration in milliseconds that this node has been waiting for.\n */\n private waitedDuration: number = 0;\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // If this node is in the READY state then we need to set the initial update time.\n if (this.is(State.READY)) {\n // Set the initial update time.\n this.initialUpdateTime = new Date().getTime();\n\n // Set the initial waited duration.\n this.waitedDuration = 0;\n\n // Are we dealing with an explicit duration or will we be randomly picking a duration between the min and max duration.\n if (this.duration !== null) {\n this.totalDuration = this.duration;\n } else if (this.durationMin !== null && this.durationMax !== null) {\n // We will be picking a random duration between a min and max duration, if the optional 'random' behaviour tree\n // function option is defined then we will be using that, otherwise we will fall back to using Math.random.\n const random = typeof options.random === \"function\" ? options.random : Math.random;\n\n // Pick a random duration between a min and max duration.\n this.totalDuration = Math.floor(\n random() * (this.durationMax - this.durationMin + 1) + this.durationMin\n );\n } else {\n this.totalDuration = null;\n }\n\n // The node is now running until we finish waiting.\n this.setState(State.RUNNING);\n }\n\n // If we have no total duration then this wait node will wait indefinitely until it is aborted.\n if (this.totalDuration === null) {\n return;\n }\n\n // If we have a 'getDeltaTime' function defined as part of our options then we will use it to figure out how long we have waited for.\n if (typeof options.getDeltaTime === \"function\") {\n // Get the delta time.\n const deltaTime = options.getDeltaTime();\n\n // Our delta time must be a valid number and cannot be NaN.\n if (typeof deltaTime !== \"number\" || isNaN(deltaTime)) {\n throw new Error(\"The delta time must be a valid number and not NaN.\");\n }\n\n // Update the amount of time that this node has been waiting for based on the delta time.\n this.waitedDuration += deltaTime * 1000;\n } else {\n // We are not using a delta time, so we will just work out hom much time has passed since the first update.\n this.waitedDuration = new Date().getTime() - this.initialUpdateTime;\n }\n\n // Have we waited long enough?\n if (this.waitedDuration >= this.totalDuration) {\n // We have finished waiting!\n this.setState(State.SUCCEEDED);\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => {\n if (this.duration !== null) {\n return `WAIT ${this.duration}ms`;\n } else if (this.durationMin !== null && this.durationMax !== null) {\n return `WAIT ${this.durationMin}ms-${this.durationMax}ms`;\n } else {\n return \"WAIT\";\n }\n };\n}\n", "import Guard from \"./guards/Guard\";\n\nexport type AttributeDetails = {\n /** The attribute type. */\n type: string;\n\n /** The attribute arguments. */\n args: any[];\n};\n\n/**\n * A base node attribute.\n */\nexport default abstract class Attribute {\n /**\n * @param type The node attribute type.\n * @param args The array of attribute arguments.\n */\n constructor(public type: string, public args: any[]) {}\n\n /**\n * Gets the attribute details.\n */\n abstract getDetails(): TAttributeDetails;\n\n /**\n * Gets whether this attribute is a guard.\n */\n abstract isGuard: () => this is Guard;\n}\n", "import { Agent } from \"../../Agent\";\nimport Attribute, { AttributeDetails } from \"../Attribute\";\n\nexport type GuardAttributeDetails = {\n /** The name of the condition function that determines whether the guard is satisfied. */\n condition: string;\n} & AttributeDetails;\n\n/**\n * A base node guard attribute.\n */\nexport default abstract class Guard extends Attribute {\n /**\n * @param type The node attribute type.\n * @param args The array of decorator argument definitions.\n * @param condition The name of the condition function that determines whether the guard is satisfied.\n */\n constructor(type: string, args: any[], private condition: string) {\n super(type, args);\n }\n\n /**\n * Gets the name of the condition function that determines whether the guard is satisfied.\n */\n getCondition = () => this.condition;\n\n /**\n * Gets whether this attribute is a guard.\n */\n isGuard = () => true;\n\n /**\n * Gets the attribute details.\n */\n getDetails(): GuardAttributeDetails {\n return {\n type: this.type,\n args: this.args,\n condition: this.getCondition()\n };\n }\n\n /**\n * Gets whether the guard is satisfied.\n * @param agent The agent.\n * @returns Whether the guard is satisfied.\n */\n abstract isSatisfied(agent: Agent): boolean;\n}\n", "import Guard from \"./Guard\";\nimport Lookup from \"../../Lookup\";\nimport { Agent } from \"../../Agent\";\n\n/**\n * A WHILE guard which is satisfied as long as the given condition remains true.\n */\nexport default class While extends Guard {\n /**\n * @param condition The name of the condition function that determines whether the guard is satisfied.\n * @param args The array of decorator argument definitions.\n */\n constructor(condition: string, args: any[]) {\n super(\"while\", args, condition);\n }\n\n /**\n * Gets whether the guard is satisfied.\n * @param agent The agent.\n * @returns Whether the guard is satisfied.\n */\n isSatisfied = (agent: Agent) => {\n // Attempt to get the invoker for the condition function.\n const conditionFuncInvoker = Lookup.getFuncInvoker(agent, this.getCondition());\n\n // The condition function should be defined.\n if (conditionFuncInvoker === null) {\n throw new Error(\n `cannot evaluate node guard as the condition '${this.getCondition()}' function is not defined on the agent and has not been registered`\n );\n }\n\n // Call the condition function to determine whether this guard is satisfied.\n return !!conditionFuncInvoker(this.args);\n };\n}\n", "import Guard from \"./Guard\";\nimport Lookup from \"../../Lookup\";\nimport { Agent } from \"../../Agent\";\n\n/**\n * An UNTIL guard which is satisfied as long as the given condition remains false.\n */\nexport default class Until extends Guard {\n /**\n * @param condition The name of the condition function that determines whether the guard is satisfied.\n * @param args The array of decorator argument definitions.\n */\n constructor(condition: string, args: any[]) {\n super(\"until\", args, condition);\n }\n\n /**\n * Gets whether the guard is satisfied.\n * @param agent The agent.\n * @returns Whether the guard is satisfied.\n */\n isSatisfied = (agent: Agent) => {\n // Attempt to get the invoker for the condition function.\n const conditionFuncInvoker = Lookup.getFuncInvoker(agent, this.getCondition());\n\n // The condition function should be defined.\n if (conditionFuncInvoker === null) {\n throw new Error(\n `cannot evaluate node guard as the condition '${this.getCondition()}' function is not defined on the agent and has not been registered`\n );\n }\n\n // Call the condition function to determine whether this guard is satisfied.\n return !!!conditionFuncInvoker(this.args);\n };\n}\n", "import { Agent } from \"../../Agent\";\nimport Attribute, { AttributeDetails } from \"../Attribute\";\n\nexport type CallbackAttributeDetails = {\n /** The name of the agent function that is called. */\n functionName: string;\n} & AttributeDetails;\n\n/**\n * A base node callback attribute.\n */\nexport default abstract class Callback extends Attribute {\n /**\n * @param type The node attribute type.\n * @param args The array of decorator argument definitions.\n * @param functionName The name of the agent function to call.\n */\n constructor(type: string, args: any[], private functionName: string) {\n super(type, args);\n }\n\n /**\n * Gets the name of the agent function to call.\n */\n getFunctionName = () => this.functionName;\n\n /**\n * Gets whether this attribute is a guard.\n */\n isGuard = () => false;\n\n /**\n * Gets the attribute details.\n */\n getDetails(): CallbackAttributeDetails {\n return {\n type: this.type,\n args: this.args,\n functionName: this.getFunctionName()\n };\n }\n\n /**\n * Attempt to call the agent function that this callback refers to.\n * @param agent The agent.\n */\n abstract callAgentFunction: (agent: Agent, isSuccess: boolean, isAborted: boolean) => void;\n}\n", "import Callback from \"./Callback\";\nimport Lookup from \"../../Lookup\";\nimport { Agent } from \"../../Agent\";\n\n/**\n * An ENTRY callback which defines an agent function to call when the associated node is updated and moves out of running state.\n */\nexport default class Entry extends Callback {\n /**\n * @param functionName The name of the agent function to call.\n * @param args The array of callback argument definitions.\n */\n constructor(functionName: string, args: any[]) {\n super(\"entry\", args, functionName);\n }\n\n /**\n * Attempt to call the agent function that this callback refers to.\n * @param agent The agent.\n */\n callAgentFunction = (agent: Agent) => {\n // Attempt to get the invoker for the callback function.\n const callbackFuncInvoker = Lookup.getFuncInvoker(agent, this.getFunctionName());\n\n // The callback function should be defined.\n if (callbackFuncInvoker === null) {\n throw new Error(\n `cannot call entry function '${this.getFunctionName()}' as is not defined on the agent and has not been registered`\n );\n }\n\n // Call the callback function.\n callbackFuncInvoker(this.args);\n };\n}\n", "import Callback from \"./Callback\";\nimport Lookup from \"../../Lookup\";\nimport { Agent } from \"../../Agent\";\n\n/**\n * A STEP callback which defines an agent function to call when the associated node is updated.\n */\nexport default class Step extends Callback {\n /**\n * @param functionName The name of the agent function to call.\n * @param args The array of callback argument definitions.\n */\n constructor(functionName: string, args: any[]) {\n super(\"step\", args, functionName);\n }\n\n /**\n * Attempt to call the agent function that this callback refers to.\n * @param agent The agent.\n */\n callAgentFunction = (agent: Agent) => {\n // Attempt to get the invoker for the callback function.\n const callbackFuncInvoker = Lookup.getFuncInvoker(agent, this.getFunctionName());\n\n // The callback function should be defined.\n if (callbackFuncInvoker === null) {\n throw new Error(\n `cannot call step function '${this.getFunctionName()}' as is not defined on the agent and has not been registered`\n );\n }\n\n // Call the callback function.\n callbackFuncInvoker(this.args);\n };\n}\n", "import Callback from \"./Callback\";\nimport Lookup from \"../../Lookup\";\nimport { Agent } from \"../../Agent\";\n\n/**\n * An EXIT callback which defines an agent function to call when the associated node is updated and moves to a finished state or is aborted.\n */\nexport default class Exit extends Callback {\n /**\n * @param functionName The name of the agent function to call.\n * @param args The array of callback argument definitions.\n */\n constructor(functionName: string, args: any[]) {\n super(\"exit\", args, functionName);\n }\n\n /**\n * Attempt to call the agent function that this callback refers to.\n * @param agent The agent.\n * @param isSuccess Whether the decorated node was left with a success state.\n * @param isAborted Whether the decorated node was aborted.\n */\n callAgentFunction = (agent: Agent, isSuccess: boolean, isAborted: boolean) => {\n // Attempt to get the invoker for the callback function.\n const callbackFuncInvoker = Lookup.getFuncInvoker(agent, this.getFunctionName());\n\n // The callback function should be defined.\n if (callbackFuncInvoker === null) {\n throw new Error(\n `cannot call exit function '${this.getFunctionName()}' as is not defined on the agent and has not been registered`\n );\n }\n\n // Call the callback function\n callbackFuncInvoker([{ value: { succeeded: isSuccess, aborted: isAborted } }, ...this.args]);\n };\n}\n", "import { AnyNodeDefinition, RootNodeDefinition } from \"./BehaviourTreeDefinition\";\nimport GuardPath, { GuardPathPart } from \"./attributes/guards/GuardPath\";\nimport { validateBranchSubtreeLinks } from \"./BehaviourTreeDefinitionValidator\";\nimport { isInteger } from \"./BehaviourTreeDefinitionUtilities\";\nimport Node from \"./nodes/Node\";\nimport Composite from \"./nodes/composite/Composite\";\nimport Decorator from \"./nodes/decorator/Decorator\";\nimport Parallel from \"./nodes/composite/Parallel\";\nimport Selector from \"./nodes/composite/Selector\";\nimport Sequence from \"./nodes/composite/Sequence\";\nimport Lotto from \"./nodes/composite/Lotto\";\nimport Fail from \"./nodes/decorator/Fail\";\nimport Flip from \"./nodes/decorator/Flip\";\nimport Repeat from \"./nodes/decorator/Repeat\";\nimport Retry from \"./nodes/decorator/Retry\";\nimport Root from \"./nodes/decorator/Root\";\nimport Succeed from \"./nodes/decorator/Succeed\";\nimport Action from \"./nodes/leaf/Action\";\nimport Condition from \"./nodes/leaf/Condition\";\nimport Wait from \"./nodes/leaf/Wait\";\nimport Lookup from \"./Lookup\";\nimport Attribute from \"./attributes/Attribute\";\nimport While from \"./attributes/guards/While\";\nimport Until from \"./attributes/guards/Until\";\nimport Entry from \"./attributes/callbacks/Entry\";\nimport Step from \"./attributes/callbacks/Step\";\nimport Exit from \"./attributes/callbacks/Exit\";\n\n/**\n * A type representing any node instance in a behaviour tree.\n */\ntype AnyNode =\n | Root\n | Action\n | Condition\n | Wait\n | Sequence\n | Selector\n | Lotto\n | Parallel\n | Repeat\n | Retry\n | Flip\n | Succeed\n | Fail;\n\n/**\n * A type defining a mapping of root node identifiers to root node definitions.\n */\ntype RootNodeDefinitionMap = { [key: string | symbol]: RootNodeDefinition };\n\n/**\n * A symbol to use as the main root key in any root node mappings.\n */\nconst MAIN_ROOT_NODE_KEY = Symbol(\"__root__\");\n\n/**\n * Build and populate the root nodes based on the provided definition, assuming that the definition has been validated.\n * @param definition The root node definitions.\n * @returns The built and populated root node definitions.\n */\nexport default function buildRootNode(definition: RootNodeDefinition[]): Root {\n // Create a mapping of root node identifers to root node definitions, including globally registered subtree root node definitions.\n const rootNodeDefinitionMap = createRootNodeDefinitionMap(definition);\n\n // Now that we have all of our root node definitons (those part of the tree definition and those globally\n // registered) we should validate the definition. This will also double-check that we dont have any circular\n // dependencies in our branch -> subtree references and that we have no broken branch -> subtree links.\n validateBranchSubtreeLinks(definition, true);\n\n // Create our populated tree of node instances, starting with our main root node.\n const rootNode = nodeFactory(rootNodeDefinitionMap[MAIN_ROOT_NODE_KEY], rootNodeDefinitionMap) as Root;\n\n // Set a guard path on every leaf of the tree to evaluate as part of each update.\n applyLeafNodeGuardPaths(rootNode);\n\n // We only need to return the main root node.\n return rootNode;\n}\n\n/**\n * A factory function which creates a node instance based on the specified definition.\n * @param definition The node definition.\n * @param rootNodeDefinitionMap The mapping of root node identifers to root node definitions, including globally registered subtree root node definitions.\n * @returns A node instance based on the specified definition.\n */\nfunction nodeFactory(definition: AnyNodeDefinition, rootNodeDefinitionMap: RootNodeDefinitionMap): AnyNode {\n // Get the attributes for the node.\n const attributes = nodeAttributesFactory(definition);\n\n // Create the node instance based on the definition type.\n switch (definition.type) {\n case \"root\":\n return new Root(attributes, nodeFactory(definition.child, rootNodeDefinitionMap));\n\n case \"repeat\":\n let iterations: number | null = null;\n let iterationsMin: number | null = null;\n let iterationsMax: number | null = null;\n\n if (Array.isArray(definition.iterations)) {\n iterationsMin = definition.iterations[0];\n iterationsMax = definition.iterations[1];\n } else if (isInteger(definition.iterations)) {\n iterations = definition.iterations!;\n }\n\n return new Repeat(\n attributes,\n iterations,\n iterationsMin,\n iterationsMax,\n nodeFactory(definition.child, rootNodeDefinitionMap)\n );\n\n case \"retry\":\n let attempts: number | null = null;\n let attemptsMin: number | null = null;\n let attemptsMax: number | null = null;\n\n if (Array.isArray(definition.attempts)) {\n attemptsMin = definition.attempts[0];\n attemptsMax = definition.attempts[1];\n } else if (isInteger(definition.attempts)) {\n attempts = definition.attempts!;\n }\n\n return new Retry(\n attributes,\n attempts,\n attemptsMin,\n attemptsMax,\n nodeFactory(definition.child, rootNodeDefinitionMap)\n );\n\n case \"flip\":\n return new Flip(attributes, nodeFactory(definition.child, rootNodeDefinitionMap));\n\n case \"succeed\":\n return new Succeed(attributes, nodeFactory(definition.child, rootNodeDefinitionMap));\n\n case \"fail\":\n return new Fail(attributes, nodeFactory(definition.child, rootNodeDefinitionMap));\n\n case \"sequence\":\n return new Sequence(\n attributes,\n definition.children.map((child) => nodeFactory(child, rootNodeDefinitionMap))\n );\n\n case \"selector\":\n return new Selector(\n attributes,\n definition.children.map((child) => nodeFactory(child, rootNodeDefinitionMap))\n );\n\n case \"parallel\":\n return new Parallel(\n attributes,\n definition.children.map((child) => nodeFactory(child, rootNodeDefinitionMap))\n );\n\n case \"lotto\":\n return new Lotto(\n attributes,\n definition.weights,\n definition.children.map((child) => nodeFactory(child, rootNodeDefinitionMap))\n );\n\n case \"branch\":\n return nodeFactory(rootNodeDefinitionMap[definition.ref].child, rootNodeDefinitionMap);\n\n case \"action\":\n return new Action(attributes, definition.call, definition.args || []);\n\n case \"condition\":\n return new Condition(attributes, definition.call, definition.args || []);\n\n case \"wait\":\n let duration: number | null = null;\n let durationMin: number | null = null;\n let durationMax: number | null = null;\n\n if (Array.isArray(definition.duration)) {\n durationMin = definition.duration[0];\n durationMax = definition.duration[1];\n } else if (isInteger(definition.duration)) {\n duration = definition.duration!;\n }\n\n return new Wait(attributes, duration, durationMin, durationMax);\n }\n}\n\n/**\n * Creates an array of node attribute instances based on the specified node definition.\n * @param definition The node definition.\n * @returns An array of node attribute instances based on the specified node definition.\n */\nfunction nodeAttributesFactory(definition: AnyNodeDefinition): Attribute[] {\n const attributes: Attribute[] = [];\n\n if (definition.while) {\n attributes.push(new While(definition.while.call, definition.while.args ?? []));\n }\n\n if (definition.until) {\n attributes.push(new Until(definition.until.call, definition.until.args ?? []));\n }\n\n if (definition.entry) {\n attributes.push(new Entry(definition.entry.call, definition.entry.args ?? []));\n }\n\n if (definition.step) {\n attributes.push(new Step(definition.step.call, definition.step.args ?? []));\n }\n\n if (definition.exit) {\n attributes.push(new Exit(definition.exit.call, definition.exit.args ?? []));\n }\n\n return attributes;\n}\n\n/**\n * Creates a mapping of root node identifers to root node definitions, mixing in globally registered subtree root node definitions.\n * @param definition The root node definitions.\n * @returns A mapping of root node identifers to root node definitions, including globally registered subtree root node definitions.\n */\nfunction createRootNodeDefinitionMap(definition: RootNodeDefinition[]): RootNodeDefinitionMap {\n // Create a mapping of root node identifers to root node definitions.\n const rootNodeMap: RootNodeDefinitionMap = {};\n\n // Add in any registered subtree root node definitions.\n for (const [name, rootNodeDefinition] of Object.entries(Lookup.getSubtrees())) {\n // The name used when registering the subtree will be used as the root node identifier.\n rootNodeMap[name] = { ...rootNodeDefinition, id: name };\n }\n\n // Populate the map with the root node definitions that were included with the tree definition.\n // We do this after adding any registered subtrees as we want these to take presedence.\n for (const rootNodeDefinition of definition) {\n rootNodeMap[rootNodeDefinition.id ?? MAIN_ROOT_NODE_KEY] = rootNodeDefinition;\n }\n\n return rootNodeMap;\n}\n\n/**\n * Applies a guard path to every leaf of the tree to evaluate as part of each update.\n * @param root The main root tree node.\n */\nfunction applyLeafNodeGuardPaths(root: Root) {\n const nodePaths: Node[][] = [];\n\n const findLeafNodes = (path: Node[], node: Node) => {\n // Add the current node to the path.\n path = path.concat(node);\n\n // Check whether the current node is a leaf node.\n if (node.isLeafNode()) {\n nodePaths.push(path);\n } else {\n (node as Composite | Decorator).getChildren().forEach((child) => findLeafNodes(path, child));\n }\n };\n\n // Find all leaf node paths, starting from the root.\n findLeafNodes([], root);\n\n nodePaths.forEach((path) => {\n // Each node in the current path will have to be assigned a guard path, working from the root outwards.\n for (let depth = 0; depth < path.length; depth++) {\n // Get the node in the path at the current depth.\n const currentNode = path[depth];\n\n // The node may already have been assigned a guard path, if so just skip it.\n if (currentNode.hasGuardPath()) {\n continue;\n }\n\n // Create the guard path for the current node.\n const guardPath = new GuardPath(\n path\n .slice(0, depth + 1)\n .map((node) => ({ node, guards: node.getGuardAttributes() }))\n .filter((details) => details.guards.length > 0)\n );\n\n // Assign the guard path to the current node.\n currentNode.setGuardPath(guardPath);\n }\n });\n}\n", "import State, { AnyState } from \"./State\";\nimport Lookup from \"./Lookup\";\nimport Node from \"./nodes/Node\";\nimport Root from \"./nodes/decorator/Root\";\nimport Composite from \"./nodes/composite/Composite\";\nimport Decorator from \"./nodes/decorator/Decorator\";\nimport { Agent, GlobalFunction } from \"./Agent\";\nimport { CallbackAttributeDetails } from \"./attributes/callbacks/Callback\";\nimport { GuardAttributeDetails } from \"./attributes/guards/Guard\";\nimport { BehaviourTreeOptions } from \"./BehaviourTreeOptions\";\nimport { convertMDSLToJSON } from \"./mdsl/MDSLDefinitionParser\";\nimport { RootNodeDefinition } from \"./BehaviourTreeDefinition\";\nimport { validateJSONDefinition } from \"./BehaviourTreeDefinitionValidator\";\nimport buildRootNode from \"./BehaviourTreeBuilder\";\n\n// Purely for outside inspection of the tree.\nexport type FlattenedTreeNode = {\n id: string;\n type: string;\n caption: string;\n state: AnyState;\n guards: GuardAttributeDetails[];\n callbacks: CallbackAttributeDetails[];\n args: any[];\n parentId: string | null;\n};\n\n/**\n * A representation of a behaviour tree.\n */\nexport class BehaviourTree {\n /**\n * The main root tree node.\n */\n public readonly rootNode: Root;\n\n /**\n * Creates a new instance of the BehaviourTree class.\n * @param definition The behaviour tree definition.\n * @param agent The agent instance that this behaviour tree is modelling behaviour for.\n * @param options The behaviour tree options object.\n */\n constructor(\n definition: string | RootNodeDefinition | RootNodeDefinition[],\n private agent: Agent,\n private options: BehaviourTreeOptions = {}\n ) {\n // The tree definition must be defined.\n if (!definition) {\n throw new Error(\"the tree definition must be a string ro\");\n }\n\n // The agent must be defined and not null.\n if (typeof agent !== \"object\" || agent === null) {\n throw new Error(\"the agent must be defined and not null\");\n }\n\n try {\n // Parse the behaviour tree definition, create the populated tree of behaviour tree nodes, and get the root.\n this.rootNode = this._createRootNode(definition);\n } catch (exception) {\n // There was an issue in trying build and populate the behaviour tree.\n throw new Error(`error building tree: ${(exception as Error).message}`);\n }\n }\n\n /**\n * Gets whether the tree is in the RUNNING state.\n * @returns true if the tree is in the RUNNING state, otherwise false.\n */\n isRunning() {\n return this.rootNode.getState() === State.RUNNING;\n }\n\n /**\n * Gets the current tree state of SUCCEEDED, FAILED, READY or RUNNING.\n * @returns The current tree state.\n */\n getState() {\n return this.rootNode.getState();\n }\n\n /**\n * Step the tree.\n * 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.\n * 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\n * 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.\n *\n * 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.\n */\n step() {\n // If the root node has already been stepped to completion then we need to reset it.\n if (this.rootNode.getState() === State.SUCCEEDED || this.rootNode.getState() === State.FAILED) {\n this.rootNode.reset();\n }\n\n try {\n this.rootNode.update(this.agent, this.options);\n } catch (exception) {\n throw new Error(`error stepping tree: ${(exception as Error).message}`);\n }\n }\n\n /**\n * Resets the tree from the root node outwards to each nested node, giving each a state of READY.\n */\n reset() {\n this.rootNode.reset();\n }\n\n /**\n * Gets the flattened details of every node in the tree.\n * @returns The flattened details of every node in the tree.\n */\n getFlattenedNodeDetails(): FlattenedTreeNode[] {\n // Create an empty flattened array of tree nodes.\n const flattenedTreeNodes: FlattenedTreeNode[] = [];\n\n /**\n * Helper function to process a node instance and push details into the flattened tree nodes array.\n * @param node The current node.\n * @param parentUid The UID of the node parent, or null if the node is the main root node.\n */\n const processNode = (node: Node, parentUid: string | null) => {\n // Get the guard and callback attribute details for this node.\n const guards = node\n .getAttributes()\n .filter((attribute) => attribute.isGuard())\n .map((attribute) => attribute.getDetails()) as GuardAttributeDetails[];\n const callbacks = node\n .getAttributes()\n .filter((attribute) => !attribute.isGuard())\n .map((attribute) => attribute.getDetails()) as CallbackAttributeDetails[];\n\n // Push the current node into the flattened nodes array.\n flattenedTreeNodes.push({\n id: node.getUid(),\n type: node.getType(),\n caption: node.getName(),\n state: node.getState(),\n guards,\n callbacks,\n args: node.getArguments(),\n parentId: parentUid\n });\n\n // Process each of the nodes children if it is not a leaf node.\n if (!node.isLeafNode()) {\n (node as Composite | Decorator)\n .getChildren()\n .forEach((child) => processNode(child, (node as Composite | Decorator).getUid()));\n }\n };\n\n // Convert the nested node structure into a flattened array of node details.\n processNode(this.rootNode, null);\n\n return flattenedTreeNodes;\n }\n\n /**\n * Registers the action/condition/guard/callback function or subtree with the given name.\n * @param name The name of the function or subtree to register.\n * @param value The function or subtree definition to register.\n */\n static register(name: string, value: GlobalFunction | string | RootNodeDefinition) {\n // Are we going to register a action/condition/guard/callback function?\n if (typeof value === \"function\") {\n Lookup.setFunc(name, value);\n return;\n }\n\n // We are not registering an action/condition/guard/callback function, so we must be registering a subtree.\n if (typeof value === \"string\") {\n let rootNodeDefinitions: RootNodeDefinition[];\n\n // We will assume that any string passed in will be a mdsl definition.\n try {\n rootNodeDefinitions = convertMDSLToJSON(value);\n } catch (exception) {\n throw new Error(`error registering definition, invalid MDSL: ${(exception as Error).message}`);\n }\n\n // This function should only ever be called with a definition containing a single unnamed root node.\n if (rootNodeDefinitions.length != 1 || rootNodeDefinitions[0].id !== null) {\n throw new Error(\"error registering definition: expected a single unnamed root node\");\n }\n\n try {\n // We should validate the subtree as we don't want invalid subtrees available via the lookup.\n const { succeeded, errorMessage } = validateJSONDefinition(rootNodeDefinitions[0]);\n\n // Did our validation fail without error?\n if (!succeeded) {\n throw new Error(errorMessage);\n }\n } catch (exception) {\n throw new Error(`error registering definition: ${(exception as Error).message}`);\n }\n\n // Everything seems hunky-dory, register the subtree.\n Lookup.setSubtree(name, rootNodeDefinitions[0]);\n } else if (typeof value === \"object\" && !Array.isArray(value)) {\n // We will assume that any object passed in is a root node definition.\n\n try {\n // We should validate the subtree as we don't want invalid subtrees available via the lookup.\n const { succeeded, errorMessage } = validateJSONDefinition(value);\n\n // Did our validation fail without error?\n if (!succeeded) {\n throw new Error(errorMessage);\n }\n } catch (exception) {\n throw new Error(`error registering definition: ${(exception as Error).message}`);\n }\n\n // Everything seems hunky-dory, register the subtree.\n Lookup.setSubtree(name, value);\n } else {\n throw new Error(\"unexpected value, expected string mdsl definition, root node json definition or function\");\n }\n }\n\n /**\n * Unregisters the registered action/condition/guard/callback function or subtree with the given name.\n * @param name The name of the registered action/condition/guard/callback function or subtree to unregister.\n */\n static unregister(name: string): void {\n Lookup.remove(name);\n }\n\n /**\n * Unregister all registered action/condition/guard/callback functions and subtrees.\n */\n static unregisterAll(): void {\n Lookup.empty();\n }\n\n /**\n * Parses a behaviour tree definition and creates a tree of behaviour tree nodes populated at a root.\n * @param {string | RootNodeDefinition | RootNodeDefinition[]} definition The behaviour tree definition.\n * @returns The root behaviour tree node.\n */\n private _createRootNode(definition: string | RootNodeDefinition | RootNodeDefinition[]): Root {\n let resolvedDefinition: RootNodeDefinition | RootNodeDefinition[];\n\n // If the definition is a string then we will assume that it is an mdsl string which needs to be converted to a JSON definition.\n if (typeof definition === \"string\") {\n try {\n resolvedDefinition = convertMDSLToJSON(definition);\n } catch (exception) {\n throw new Error(`invalid mdsl definition: ${(exception as Error).message}`);\n }\n } else {\n // The definition is not a string, so we should assume that it is already a JSON definition.\n resolvedDefinition = definition;\n }\n\n // Build and populate the root node.\n return buildRootNode(Array.isArray(resolvedDefinition) ? resolvedDefinition : [resolvedDefinition]);\n }\n}\n"], - "mappings": "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", + "sourcesContent": ["\"use strict\";\r\nObject.defineProperty(exports, \"__esModule\", { value: true });\r\nexports.Participant = void 0;\r\n/**\r\n * A participant that holds a number of tickets.\r\n */\r\nvar Participant = /** @class */ (function () {\r\n /**\r\n * Creates an instance of the Participant class.\r\n * @param participant The actual participant.\r\n * @param tickets The number of tickets held by the participant.\r\n */\r\n function Participant(participant, tickets) {\r\n if (tickets === void 0) { tickets = 1; }\r\n this._participant = participant;\r\n this._tickets = tickets;\r\n }\r\n Object.defineProperty(Participant.prototype, \"participant\", {\r\n /** Gets the actual participant. */\r\n get: function () {\r\n return this._participant;\r\n },\r\n enumerable: false,\r\n configurable: true\r\n });\r\n Object.defineProperty(Participant.prototype, \"tickets\", {\r\n /** Gets or sets the number of tickets held by the participant. */\r\n get: function () {\r\n return this._tickets;\r\n },\r\n set: function (value) {\r\n this._tickets = value;\r\n },\r\n enumerable: false,\r\n configurable: true\r\n });\r\n return Participant;\r\n}());\r\nexports.Participant = Participant;\r\n", "\"use strict\";\r\nObject.defineProperty(exports, \"__esModule\", { value: true });\r\nexports.isNaturalNumber = exports.isNullOrUndefined = void 0;\r\n/**\r\n * Gets whether the value provided is null or undefined.\r\n * @param value The value to check.\r\n * @returns Whether the value provided is null or undefined.\r\n */\r\nfunction isNullOrUndefined(value) {\r\n return value === null || value === undefined;\r\n}\r\nexports.isNullOrUndefined = isNullOrUndefined;\r\n/**\r\n * Gets whether the value provided is a natural number.\r\n * @param value The value to check.\r\n * @returns Whether the value provided is a natural number.\r\n */\r\nfunction isNaturalNumber(value) {\r\n return typeof value === \"number\" && value >= 1 && Math.floor(value) === value;\r\n}\r\nexports.isNaturalNumber = isNaturalNumber;\r\n", "\"use strict\";\r\nObject.defineProperty(exports, \"__esModule\", { value: true });\r\nexports.Lotto = void 0;\r\nvar Participant_1 = require(\"./Participant\");\r\nvar Utilities_1 = require(\"./Utilities\");\r\n/**\r\n * Represents a lotto consisting of a number of pickable ticket-holding participants.\r\n */\r\nvar Lotto = /** @class */ (function () {\r\n /**\r\n * Creates a new instance of Lotto.\r\n * @param customRandom The custom RNG to use in place of Math.random().\r\n */\r\n function Lotto(customRandom) {\r\n /** The array of participants that are holding tickets in the lotto. */\r\n this._participants = [];\r\n this._customRandom = customRandom;\r\n }\r\n /**\r\n * Adds a participant with the specified number of tickets, or adds to the participant ticket count if the participant already holds tickets.\r\n * @param participant The participant to add or to increase the ticket count for if they already hold tickets.\r\n * @param tickets The number of tickets, defaults to 1.\r\n * @returns The Lotto instance.\r\n */\r\n Lotto.prototype.add = function (participant, tickets) {\r\n if (tickets === void 0) { tickets = 1; }\r\n // Check that we have a valid ticket count.\r\n if (!(0, Utilities_1.isNaturalNumber)(tickets)) {\r\n throw new Error(\"tickets value must be a natural number\");\r\n }\r\n // Check whether this participant has already been added.\r\n var existingParticipant = this._participants.find(function (part) { return part.participant === participant; });\r\n if (existingParticipant) {\r\n // The participant has already been added to the lotto so just add to their ticket count.\r\n existingParticipant.tickets += tickets;\r\n }\r\n else {\r\n // The participant is not part of the lotto so we should add them.\r\n this._participants.push(new Participant_1.Participant(participant, tickets));\r\n }\r\n return this;\r\n };\r\n /**\r\n * Removes the specified number of tickets for the given participant from the draw, or all tickets if a ticket number is not defined.\r\n * @param participant The participant to remove tickets for.\r\n * @param tickets The number of tickets to remove, or undefined if all tickets are to be removed.\r\n * @returns The Lotto instance.\r\n */\r\n Lotto.prototype.remove = function (participant, tickets) {\r\n // Attempt to get the existing participant.\r\n var existingParticipant = this._participants.find(function (part) { return part.participant === participant; });\r\n // There is nothing to do if the specified participant isn't even part of the lotto.\r\n if (!existingParticipant) {\r\n return this;\r\n }\r\n // Check whether a tickets value was given.\r\n if (tickets !== undefined) {\r\n // Check that we have a valid ticket count.\r\n if (!(0, Utilities_1.isNaturalNumber)(tickets)) {\r\n throw new Error(\"tickets value must be a natural number\");\r\n }\r\n existingParticipant.tickets -= tickets;\r\n // If the participant no longer holds any tickets then they should be removed.\r\n if (existingParticipant.tickets < 1) {\r\n this._participants = this._participants.filter(function (part) { return part !== existingParticipant; });\r\n }\r\n }\r\n else {\r\n // We are removing all tickets for the participant so just remove them from the lotto.\r\n this._participants = this._participants.filter(function (part) { return part !== existingParticipant; });\r\n }\r\n return this;\r\n };\r\n /**\r\n * Draw a winning ticket and return the participant that holds the ticket.\r\n * @param options The draw options.\r\n * @returns The participant that holds the winning ticket.\r\n */\r\n Lotto.prototype.draw = function (options) {\r\n if (options === void 0) { options = {}; }\r\n // If we have no participants then just return null.\r\n if (this._participants.length === 0) {\r\n return null;\r\n }\r\n var redrawable = (0, Utilities_1.isNullOrUndefined)(options.redrawable) ? true : options.redrawable;\r\n var pickable = [];\r\n this._participants.forEach(function (_a) {\r\n var participant = _a.participant, tickets = _a.tickets;\r\n for (var ticketCount = 0; ticketCount < tickets; ticketCount++) {\r\n pickable.push(participant);\r\n }\r\n });\r\n var random;\r\n // We need a random floating-point number between 0 (inclusive) and 1 to scale up to pick our winner.\r\n // If a custom random function exists then we should use that or fall back to Math.random().\r\n if (this._customRandom) {\r\n // Call our custom random function to get a random floating-point number.\r\n random = this._customRandom();\r\n // Verify that the result of calling our custom random function is a number between 0 (inclusive) and 1.\r\n if (typeof random !== \"number\" || random < 0 || random >= 1) {\r\n throw new Error(\"the 'random' function provided did not return a number between 0 (inclusive) and 1\");\r\n }\r\n }\r\n else {\r\n // No custom random function was defined so just use good ol' Math.random().\r\n random = Math.random();\r\n }\r\n // Pick a winning participant.\r\n var winner = pickable[Math.floor(random * pickable.length)];\r\n // If the ticket isn't redrawable then we should remove a ticket from the winning participants ticket count.\r\n if (!redrawable) {\r\n this.remove(winner, 1);\r\n }\r\n // Return the winning participant.\r\n return winner;\r\n };\r\n /**\r\n * Draws multiple winning tickets and return an array of the participants that hold the winning tickets.\r\n * @param tickets The number of winning tickets to draw.\r\n * @param options The draw multiple options.\r\n * @returns An array of the participants that hold the winning tickets.\r\n */\r\n Lotto.prototype.drawMultiple = function (tickets, options) {\r\n if (options === void 0) { options = {}; }\r\n var uniqueResults = (0, Utilities_1.isNullOrUndefined)(options.unique) ? false : options.unique;\r\n // Handle cases where the user has asked for zero tickets (no idea why they would do this be we should trust them).\r\n if (tickets === 0) {\r\n return [];\r\n }\r\n // Now that we know out tickets value is not zero we should check that it is a valid natural number.\r\n if (!(0, Utilities_1.isNaturalNumber)(tickets)) {\r\n throw new Error(\"tickets value must be a natural number\");\r\n }\r\n var result = [];\r\n // Keep drawing tickets until we either reach the number of required tickets or we simply run out of tickets to draw.\r\n // We can run out of tickets to draw if 'options.redrawable' is explicity 'false' or we just had no participants when 'drawMultiple' was called.\r\n while (result.length < tickets && this._participants.length > 0) {\r\n result.push(this.draw(options));\r\n }\r\n // If the 'unique' draw option is set then we need to remove duplicates from the result list.\r\n if (uniqueResults) {\r\n // Create an array to store our unique results.\r\n var unique = [];\r\n // Iterate over all of our participants (with potential duplicates) and populate our array of unique values.\r\n for (var _i = 0, result_1 = result; _i < result_1.length; _i++) {\r\n var participant = result_1[_i];\r\n if (unique.indexOf(participant) === -1) {\r\n unique.push(participant);\r\n }\r\n }\r\n result = unique;\r\n }\r\n return result;\r\n };\r\n return Lotto;\r\n}());\r\nexports.Lotto = Lotto;\r\n", "\"use strict\";\r\nObject.defineProperty(exports, \"__esModule\", { value: true });\r\nexports.createLotto = void 0;\r\nvar Lotto_1 = require(\"./Lotto\");\r\n/**\r\n * A function that creates and returns a Lotto instance.\r\n * @param participantsOrOptions An array of initial participants or options relating to the creation of a Lotto instance.\r\n * @returns A new Lotto instance.\r\n */\r\nfunction createLotto(participantsOrOptions) {\r\n // If no initial participants or lotto options were provided as an argument then we can just return a new lotto instance now.\r\n if (!participantsOrOptions) {\r\n return new Lotto_1.Lotto();\r\n }\r\n // Check whether we were provided with an array of initial participants or a lotto options object.\r\n if (Array.isArray(participantsOrOptions)) {\r\n // We are dealing with a pre-defined array of participants.\r\n var participants = participantsOrOptions;\r\n var lotto_1 = new Lotto_1.Lotto();\r\n // If the lotto participants have been defined upfront then we will need to add them all to our lotto instance now.\r\n participants.forEach(function (_a) {\r\n var participant = _a[0], tokens = _a[1];\r\n return lotto_1.add(participant, tokens);\r\n });\r\n // Return the Lotto instance.\r\n return lotto_1;\r\n }\r\n else {\r\n // We are dealing with some lotto options.\r\n var random = participantsOrOptions.random, participants = participantsOrOptions.participants;\r\n // Create a Lotto instance passing the custom RNG function to use in place of Math.random() (which could be undefined).\r\n var lotto_2 = new Lotto_1.Lotto(random);\r\n // If the lotto participants have been defined upfront as part of the options then we will need to add them all to our lotto instance now.\r\n if (participants) {\r\n participants.forEach(function (_a) {\r\n var participant = _a[0], tokens = _a[1];\r\n return lotto_2.add(participant, tokens);\r\n });\r\n }\r\n // Return the Lotto instance.\r\n return lotto_2;\r\n }\r\n}\r\nexports.createLotto = createLotto;\r\n", "\"use strict\";\r\nObject.defineProperty(exports, \"__esModule\", { value: true });\r\nvar createLotto_1 = require(\"./createLotto\");\r\nexports.default = createLotto_1.createLotto;\r\n", "import State from \"./State\";\nimport { validateDefinition } from \"./BehaviourTreeDefinitionValidator\";\nimport { convertMDSLToJSON } from \"./mdsl/MDSLDefinitionParser\";\nimport { BehaviourTree, FlattenedTreeNode } from \"./BehaviourTree\";\nimport { BehaviourTreeOptions } from \"./BehaviourTreeOptions\";\n\nexport { BehaviourTree, State, convertMDSLToJSON, validateDefinition };\nexport type { FlattenedTreeNode, BehaviourTreeOptions };\n", "/**\n * Enumeration of node state types.\n */\nexport enum State {\n READY = \"mistreevous.ready\",\n RUNNING = \"mistreevous.running\",\n SUCCEEDED = \"mistreevous.succeeded\",\n FAILED = \"mistreevous.failed\"\n}\n\nexport { State as default };\n\nexport type CompleteState = State.SUCCEEDED | State.FAILED;\nexport type AnyState = State.READY | State.RUNNING | CompleteState;\n", "import {\n NodeDefinition,\n RootNodeDefinition,\n DecoratorNodeDefinition,\n CompositeNodeDefinition,\n AnyNodeDefinition,\n BranchNodeDefinition\n} from \"./BehaviourTreeDefinition\";\n\n/**\n * A type guard function that returns true if the specified node satisfies the RootNodeDefinition type.\n * @param node The node.\n * @returns A value of true if the specified node satisfies the RootNodeDefinition type.\n */\nexport function isRootNode(node: NodeDefinition): node is RootNodeDefinition {\n return node.type === \"root\";\n}\n\n/**\n * A type guard function that returns true if the specified node satisfies the BranchNodeDefinition type.\n * @param node The node.\n * @returns A value of true if the specified node satisfies the BranchNodeDefinition type.\n */\nexport function isBranchNode(node: NodeDefinition): node is BranchNodeDefinition {\n return node.type === \"branch\";\n}\n\n/**\n * A type guard function that returns true if the specified node satisfies the NodeDefinition type.\n * @param node The node.\n * @returns A value of true if the specified node satisfies the NodeDefinition type.\n */\nexport function isLeafNode(node: NodeDefinition): node is NodeDefinition {\n return [\"branch\", \"action\", \"condition\", \"wait\"].includes(node.type);\n}\n\n/**\n * A type guard function that returns true if the specified node satisfies the DecoratorNodeDefinition type.\n * @param node The node.\n * @returns A value of true if the specified node satisfies the DecoratorNodeDefinition type.\n */\nexport function isDecoratorNode(node: NodeDefinition): node is DecoratorNodeDefinition {\n return [\"root\", \"repeat\", \"retry\", \"flip\", \"succeed\", \"fail\"].includes(node.type);\n}\n\n/**\n * A type guard function that returns true if the specified node satisfies the CompositeNodeDefinition type.\n * @param node The node.\n * @returns A value of true if the specified node satisfies the CompositeNodeDefinition type.\n */\nexport function isCompositeNode(node: NodeDefinition): node is CompositeNodeDefinition {\n return [\"sequence\", \"selector\", \"lotto\", \"parallel\"].includes(node.type);\n}\n\n/**\n * Flatten a node definition into an array of all of its nested node definitions.\n * @param nodeDefinition The node definition to flatten.\n * @returns An array of all of nested node definitions.\n */\nexport function flattenDefinition(nodeDefinition: AnyNodeDefinition): AnyNodeDefinition[] {\n const nodes: AnyNodeDefinition[] = [];\n\n const processNode = (currentNodeDefinition: AnyNodeDefinition) => {\n nodes.push(currentNodeDefinition);\n\n if (isCompositeNode(currentNodeDefinition)) {\n currentNodeDefinition.children.forEach(processNode);\n } else if (isDecoratorNode(currentNodeDefinition)) {\n processNode(currentNodeDefinition.child);\n }\n };\n\n processNode(nodeDefinition);\n\n return nodes;\n}\n\n/**\n * Determines whether the passed value is an integer.\n * @param value The value to check.\n * @returns Whether the passed value is an integer.\n */\nexport function isInteger(value: unknown): boolean {\n return typeof value === \"number\" && Math.floor(value) === value;\n}\n\n/**\n * Determines whether the passed value is null or undefined.\n * @param value The value to check.\n * @returns Whether the passed value is null or undefined.\n */\nexport function isNullOrUndefined(value: unknown): boolean {\n return typeof value === \"undefined\" || value === null;\n}\n", "/**\n * A type defining an object that holds a reference to substitued string literals parsed from the definition.\n */\nexport type StringLiteralPlaceholders = { [key: string]: string };\n\n/**\n * Pop the next raw token from the specified array of tokens and throw an error if it wasn't the expected one.\n * @param tokens The array of tokens.\n * @param expected An optional string or array or items, one of which must match the next popped token.\n * @returns The popped token.\n */\nexport function popAndCheck(tokens: string[], expected?: string | string[]): string {\n // Get and remove the next token.\n const popped = tokens.shift();\n\n // We were expecting another token but there aren't any.\n if (popped === undefined) {\n throw new Error(\"unexpected end of definition\");\n }\n\n // Do we have an expected token/tokens array?\n if (expected != undefined) {\n // Get an array of expected values, if the popped token matches any then we are all good.\n const expectedValues = typeof expected === \"string\" ? [expected] : expected;\n\n // Check whether the popped token matches at least one of our expected items.\n var tokenMatchesExpectation = expectedValues.some((item) => popped.toUpperCase() === item.toUpperCase());\n\n // Throw an error if the popped token didn't match any of our expected items.\n if (!tokenMatchesExpectation) {\n const expectationString = expectedValues.map((item) => \"'\" + item + \"'\").join(\" or \");\n throw new Error(\"unexpected token found. Expected \" + expectationString + \" but got '\" + popped + \"'\");\n }\n }\n\n // Return the popped token.\n return popped;\n}\n\n/**\n * Swaps out any node/attribute argument string literals with placeholders.\n * @param definition The definition.\n * @returns An object containing a mapping of placeholders to original string values as well as the processed definition string.\n */\nexport function substituteStringLiterals(definition: string): {\n placeholders: StringLiteralPlaceholders;\n processedDefinition: string;\n} {\n // Create an object to hold the mapping of placeholders to original string values.\n const placeholders: StringLiteralPlaceholders = {};\n\n // Replace any string literals wrapped with double quotes in our definition with placeholders to be processed later.\n const processedDefinition = definition.replace(/\\\"(\\\\.|[^\"\\\\])*\\\"/g, (match) => {\n var strippedMatch = match.substring(1, match.length - 1);\n var placeholder = Object.keys(placeholders).find((key) => placeholders[key] === strippedMatch);\n\n // If we have no existing string literal match then create a new placeholder.\n if (!placeholder) {\n placeholder = `@@${Object.keys(placeholders).length}@@`;\n placeholders[placeholder] = strippedMatch;\n }\n\n return placeholder;\n });\n\n return { placeholders, processedDefinition };\n}\n\n/**\n * Parse the tree definition into an array of raw tokens.\n * @param definition The definition.\n * @returns An array of tokens parsed from the definition.\n */\nexport function parseTokensFromDefinition(definition: string): string[] {\n // Add some space around various important characters so that they can be plucked out easier as individual tokens.\n definition = definition.replace(/\\(/g, \" ( \");\n definition = definition.replace(/\\)/g, \" ) \");\n definition = definition.replace(/\\{/g, \" { \");\n definition = definition.replace(/\\}/g, \" } \");\n definition = definition.replace(/\\]/g, \" ] \");\n definition = definition.replace(/\\[/g, \" [ \");\n definition = definition.replace(/\\,/g, \" , \");\n\n // Split the definition into raw token form and return it.\n return definition.replace(/\\s+/g, \" \").trim().split(\" \");\n}\n", "import { StringLiteralPlaceholders, popAndCheck } from \"./MDSLUtilities\";\n\n/**\n * A type representing any node function argument.\n */\ntype Argument = {\n /**\n * The argument value.\n */\n value: T;\n /**\n * The argument type, used for validation.\n */\n type: string;\n};\n\ntype NullArgument = Argument & {\n type: \"null\";\n};\n\ntype BooleanArgument = Argument & {\n type: \"boolean\";\n};\n\ntype NumberArgument = Argument & {\n type: \"number\";\n /**\n * A flag defining whether the number argument value is a valid integer. (used for validation)\n */\n isInteger: boolean;\n};\n\ntype StringPlaceholderArgument = Argument & {\n type: \"string\";\n};\n\ntype IdentifierArgument = Argument & {\n type: \"identifier\";\n};\n\n/**\n * A type representing a reference to any node function argument.\n */\ntype AnyArgument = NullArgument | BooleanArgument | NumberArgument | StringPlaceholderArgument | IdentifierArgument;\n\n/**\n * Parse an array of argument definitions from the specified tokens array.\n * @param tokens The array tokens to parse the argument definitions from.\n * @param stringArgumentPlaceholders The mapping of string literal node argument placeholders to original values.\n * @param argumentValidator The argument validator function.\n * @param validationFailedMessage The exception message to throw if argument validation fails.\n * @returns An array of argument definitions parsed from the specified tokens array.\n */\nexport function parseArgumentTokens(\n tokens: string[],\n stringArgumentPlaceholders: StringLiteralPlaceholders\n): AnyArgument[] {\n const argumentList: AnyArgument[] = [];\n\n // If the next token is not a '[' or '(' then we have no arguments to parse.\n if (![\"[\", \"(\"].includes(tokens[0])) {\n return argumentList;\n }\n\n // Any lists of arguments will always be wrapped in '[]' for node arguments or '()' for attribute arguments.\n // We are looking for a '[' or '(' opener that wraps the argument tokens and the relevant closer.\n const closingToken = popAndCheck(tokens, [\"[\", \"(\"]) === \"[\" ? \"]\" : \")\";\n\n const argumentListTokens: string[] = [];\n\n // Grab all tokens between the '[' and ']' or '(' and ')'.\n while (tokens.length && tokens[0] !== closingToken) {\n // The next token is part of our arguments list.\n argumentListTokens.push(tokens.shift()!);\n }\n\n // Validate the order of the argument tokens. Each token must either be a ',' or a single argument that satisfies the validator.\n argumentListTokens.forEach((token, index) => {\n // Get whether this token should be an actual argument.\n const shouldBeArgumentToken = !(index & 1);\n\n // If the current token should be an actual argument then validate it, otherwise it should be a ',' token.\n if (shouldBeArgumentToken) {\n // Get the argument definition.\n const argumentDefinition = getArgumentDefinition(token, stringArgumentPlaceholders);\n\n // This is a valid argument!\n argumentList.push(argumentDefinition);\n } else {\n // The current token should be a ',' token.\n if (token !== \",\") {\n throw new Error(`invalid argument list, expected ',' or ']' but got '${token}'`);\n }\n }\n });\n\n // The arguments list should terminate with a ']' or ')' token, depending on the opener.\n popAndCheck(tokens, closingToken);\n\n // Return the arguments.\n return argumentList;\n}\n\n/**\n * Gets an argument value definition.\n * @param token The argument token.\n * @param stringArgumentPlaceholders The mapping of string literal node argument placeholders to original values.\n * @returns An argument value definition.\n */\nfunction getArgumentDefinition(token: string, stringArgumentPlaceholders: StringLiteralPlaceholders): AnyArgument {\n // Check whether the token represents a null value.\n if (token === \"null\") {\n return {\n value: null,\n type: \"null\"\n } as NullArgument;\n }\n\n // Check whether the token represents a boolean value.\n if (token === \"true\" || token === \"false\") {\n return {\n value: token === \"true\",\n type: \"boolean\"\n } as BooleanArgument;\n }\n\n // Check whether the token represents a number value.\n // TODO: Relies on broken isNaN - see MDN.\n // if (!Number.isNaN(token)) {\n if (!isNaN(token as any)) {\n return {\n value: parseFloat(token),\n isInteger: parseFloat(token) === parseInt(token, 10),\n type: \"number\"\n } as NumberArgument;\n }\n\n // Check whether the token is a placeholder (e.g. @@0@@) representing a string literal.\n if (token.match(/^@@\\d+@@$/g)) {\n return {\n value: stringArgumentPlaceholders[token].replace('\\\\\"', '\"'),\n type: \"string\"\n } as StringPlaceholderArgument;\n }\n\n // The only remaining option is that the argument value is an identifier.\n return {\n value: token,\n type: \"identifier\"\n } as IdentifierArgument;\n}\n", "import { NodeAttributeDefinition } from \"../BehaviourTreeDefinition\";\nimport { parseArgumentTokens } from \"./MDSLNodeArgumentParser\";\nimport { StringLiteralPlaceholders } from \"./MDSLUtilities\";\n\n/**\n * A type defining the attribute definitions of a node.\n */\ntype NodeAttributes = {\n while?: NodeAttributeDefinition;\n until?: NodeAttributeDefinition;\n entry?: NodeAttributeDefinition;\n exit?: NodeAttributeDefinition;\n step?: NodeAttributeDefinition;\n};\n\n/**\n * Parse any node attribute definitions from the specified tokens array.\n * @param tokens The array of remaining tokens.\n * @param stringArgumentPlaceholders The mapping of string literal node argument placeholders to original values.\n * @returns An object of attribute definitions defined by any directly following tokens.\n */\nexport function parseAttributeTokens(\n tokens: string[],\n stringArgumentPlaceholders: StringLiteralPlaceholders\n): NodeAttributes {\n const nodeAttributeNames: (keyof NodeAttributes)[] = [\"while\", \"until\", \"entry\", \"exit\", \"step\"];\n\n // Create an object to hold any attributes found.\n const attributes: NodeAttributes = {};\n\n // Try to get the name of the attribute for the next token.\n let nextAttributeName = tokens[0]?.toLowerCase() as keyof NodeAttributes;\n\n // Pull attribute tokens as well as their arguments off of the tokens stack until we have no more.\n while (nodeAttributeNames.includes(nextAttributeName)) {\n // Check to make sure that we have not already created an attribute definition of this type.\n if (attributes[nextAttributeName]) {\n throw new Error(`duplicate attribute '${tokens[0].toUpperCase()}' found for node`);\n }\n\n // Remove the attribute name token from the array of tokens.\n tokens.shift();\n\n // Grab the attribute arguments, assuming the first to be an identifier.\n const [attributeCallIdentifier, ...attributeArguments] = parseArgumentTokens(\n tokens,\n stringArgumentPlaceholders\n );\n\n // The first attribute argument has to be an identifer, this will reference an agent function.\n if (attributeCallIdentifier?.type !== \"identifier\") {\n throw new Error(\"expected agent function name identifier argument for attribute\");\n }\n\n // Any attribute arguments (other than the expected call identifier) must have a type of string, number, boolean or null.\n attributeArguments\n .filter((arg) => arg.type === \"identifier\")\n .forEach((arg) => {\n throw new Error(\n `invalid attribute argument value '${arg.value}', must be string, number, boolean or null`\n );\n });\n\n // Create the attribute definition and add it to the object of attribute definitions found.\n attributes[nextAttributeName] = {\n call: attributeCallIdentifier.value,\n args: attributeArguments.map(({ value }) => value)\n };\n\n // Try to get the next attribute name token, as there could be multiple.\n nextAttributeName = tokens[0]?.toLowerCase() as keyof NodeAttributes;\n }\n\n return attributes;\n}\n", "import {\n ActionNodeDefinition,\n AnyChildNodeDefinition,\n AnyNodeDefinition,\n BranchNodeDefinition,\n ConditionNodeDefinition,\n FailNodeDefinition,\n FlipNodeDefinition,\n LottoNodeDefinition,\n ParallelNodeDefinition,\n RepeatNodeDefinition,\n RetryNodeDefinition,\n RootNodeDefinition,\n SelectorNodeDefinition,\n SequenceNodeDefinition,\n SucceedNodeDefinition,\n WaitNodeDefinition\n} from \"../BehaviourTreeDefinition\";\nimport {\n isCompositeNode,\n isDecoratorNode,\n isLeafNode,\n isNullOrUndefined,\n isRootNode\n} from \"../BehaviourTreeDefinitionUtilities\";\nimport { parseArgumentTokens } from \"./MDSLNodeArgumentParser\";\nimport { parseAttributeTokens } from \"./MDSLNodeAttributeParser\";\nimport {\n StringLiteralPlaceholders,\n parseTokensFromDefinition,\n popAndCheck,\n substituteStringLiterals\n} from \"./MDSLUtilities\";\n\n/**\n * Convert the MDSL tree definition string into an equivalent JSON definition.\n * @param definition The tree definition string as MDSL.\n * @returns The root node JSON definitions.\n */\nexport function convertMDSLToJSON(definition: string): RootNodeDefinition[] {\n // Swap out any node/attribute argument string literals with a placeholder and get a mapping of placeholders to original values as well as the processed definition.\n const { placeholders, processedDefinition } = substituteStringLiterals(definition);\n\n // Parse our definition definition string into an array of raw tokens.\n const tokens = parseTokensFromDefinition(processedDefinition);\n\n return convertTokensToJSONDefinition(tokens, placeholders);\n}\n\n/**\n * Converts the specified tree definition tokens into a JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The root node JSON definitions.\n */\nfunction convertTokensToJSONDefinition(\n tokens: string[],\n stringLiteralPlaceholders: StringLiteralPlaceholders\n): RootNodeDefinition[] {\n // There must be at least 3 tokens for the tree definition to be valid. 'ROOT', '{' and '}'.\n if (tokens.length < 3) {\n throw new Error(\"invalid token count\");\n }\n\n // We should have a matching number of '{' and '}' tokens. If not, then there are scopes that have not been properly closed.\n if (tokens.filter((token) => token === \"{\").length !== tokens.filter((token) => token === \"}\").length) {\n throw new Error(\"scope character mismatch\");\n }\n\n // Create an array of tree stack arrays where root nodes will always be at the botton and the current composite/decorator node at the top.\n // There should be an element in this array for every root node defined and every element should be an array with a root note as the first element.\n // E.g. A definition with two root nodes defined:\n // [\n // [root, lotto, sequence],\n // [root, selector]\n // ]\n const treeStacks: [Partial, ...Partial[]][] = [];\n\n // Create an array of all root node definitions that we create.\n const rootNodes: Partial[] = [];\n\n // A helper function used to push node definitions onto the tree stack.\n const pushNode = (node: AnyNodeDefinition) => {\n // If the node is a root node then we need to create a new tree stack array with the root node at the root.\n if (isRootNode(node)) {\n // We need to double-check that this root node is not the child of another node.\n // We can do this by checking whether the top tree stack is not empty (contains an existing node)\n if (treeStacks[treeStacks.length - 1]?.length) {\n throw new Error(\"a root node cannot be the child of another node\");\n }\n\n // Add the root node definition to our array of all parsed root node definitions.\n rootNodes.push(node);\n\n // Add the root node definition to the root of a new tree stack.\n treeStacks.push([node]);\n\n return;\n }\n\n // All non-root nodes should be pushed after their root nodes so handle cases\n // where we may not have any tree stacks or our top-most tree stack is empty.\n if (!treeStacks.length || !treeStacks[treeStacks.length - 1].length) {\n throw new Error(\"expected root node at base of definition\");\n }\n\n // Get the current tree stack that we are populating.\n const topTreeStack = treeStacks[treeStacks.length - 1];\n\n // Get the top-most node in the current tree stack, this will be a composite/decorator node\n // for which we will populate its children array if composite or setting its child if a decorator.\n const topTreeStackTopNode = topTreeStack[topTreeStack.length - 1] as AnyNodeDefinition;\n\n // If the top-most node in the current root stack is a composite or decorator\n // node then the current node should be added as a child of the top-most node.\n if (isCompositeNode(topTreeStackTopNode)) {\n topTreeStackTopNode.children = topTreeStackTopNode.children || [];\n topTreeStackTopNode.children.push(node);\n } else if (isDecoratorNode(topTreeStackTopNode)) {\n // If the top node already has a child node set then throw an error as a decorator should only have a single child.\n if (topTreeStackTopNode.child) {\n throw new Error(\"a decorator node must only have a single child node\");\n }\n\n topTreeStackTopNode.child = node;\n }\n\n // If the node we are adding is also a composite or decorator node, then we should push it\n // onto the current tree stack, as subsequent nodes will be added as its child/children.\n if (!isLeafNode(node)) {\n topTreeStack.push(node);\n }\n };\n\n // A helper function used to pop the top-most node definition off of the tree stack and return it.\n const popNode = (): AnyNodeDefinition | null => {\n let poppedNode: AnyNodeDefinition | null = null;\n\n // Get the current tree stack that we are populating.\n const topTreeStack = treeStacks[treeStacks.length - 1];\n\n // Pop the top-most node in the current tree stack if there is one.\n if (topTreeStack.length) {\n poppedNode = topTreeStack.pop() as AnyNodeDefinition;\n }\n\n // We don't want any empty tree stacks in our stack of tree stacks.\n if (!topTreeStack.length) {\n treeStacks.pop();\n }\n\n return poppedNode;\n };\n\n // We should keep processing the raw tokens until we run out of them.\n while (tokens.length) {\n // Grab the next token.\n const token = tokens.shift()!;\n\n // How we create the next node depends on the current raw token value.\n switch (token.toUpperCase()) {\n case \"ROOT\": {\n pushNode(createRootNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"SUCCEED\": {\n pushNode(createSucceedNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"FAIL\": {\n pushNode(createFailNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"FLIP\": {\n pushNode(createFlipNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"REPEAT\": {\n pushNode(createRepeatNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"RETRY\": {\n pushNode(createRetryNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"SEQUENCE\": {\n pushNode(createSequenceNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"SELECTOR\": {\n pushNode(createSelectorNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"PARALLEL\": {\n pushNode(createParallelNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"LOTTO\": {\n pushNode(createLottoNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"ACTION\": {\n pushNode(createActionNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"CONDITION\": {\n pushNode(createConditionNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"WAIT\": {\n pushNode(createWaitNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"BRANCH\": {\n pushNode(createBranchNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"}\": {\n // The '}' character closes the current scope and means that we have to pop a node off of the current stack.\n const poppedNode = popNode();\n\n // Now that we have a node definition we can carry out any validation that may require the node to be fully populated.\n if (poppedNode) {\n validatePoppedNode(poppedNode);\n }\n\n break;\n }\n\n default: {\n throw new Error(`unexpected token: ${token}`);\n }\n }\n }\n\n return rootNodes as RootNodeDefinition[];\n}\n\n/**\n * Creates a root node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The root node JSON definition.\n */\nfunction createRootNode(tokens: string[], stringLiteralPlaceholders: StringLiteralPlaceholders): RootNodeDefinition {\n // Create the root node definition.\n let node = {\n type: \"root\",\n id: undefined\n } as RootNodeDefinition;\n\n // Parse any node arguments, we should only have one if any which will be an identifier argument for the root identifier.\n const nodeArguments = parseArgumentTokens(tokens, stringLiteralPlaceholders);\n\n // Check whether any node arguments were defined.\n if (nodeArguments.length) {\n // We should only have one argument, if any, which will be an identifier argument for the root identifier.\n if (nodeArguments.length === 1 && nodeArguments[0].type === \"identifier\") {\n // The root node identifier will be the first and only node argument value.\n node.id = nodeArguments[0].value as string;\n } else {\n throw new Error(\"expected single root name argument\");\n }\n }\n\n // Grab any node attribute definitions and spread them into the node definition.\n node = { ...node, ...parseAttributeTokens(tokens, stringLiteralPlaceholders) };\n\n // This is a decorator node, so we expect an opening '{'.\n popAndCheck(tokens, \"{\");\n\n // Return the root node definition.\n return node;\n}\n\n/**\n * Creates a succeed node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The succeed node JSON definition.\n */\nfunction createSucceedNode(\n tokens: string[],\n stringLiteralPlaceholders: StringLiteralPlaceholders\n): SucceedNodeDefinition {\n const node = {\n type: \"succeed\",\n ...parseAttributeTokens(tokens, stringLiteralPlaceholders)\n } as SucceedNodeDefinition;\n\n // This is a decorator node, so we expect an opening '{'.\n popAndCheck(tokens, \"{\");\n\n // Return the succeed node definition.\n return node;\n}\n\n/**\n * Creates a fail node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The fail node JSON definition.\n */\nfunction createFailNode(tokens: string[], stringLiteralPlaceholders: StringLiteralPlaceholders): FailNodeDefinition {\n const node = {\n type: \"fail\",\n ...parseAttributeTokens(tokens, stringLiteralPlaceholders)\n } as FailNodeDefinition;\n\n // This is a decorator node, so we expect an opening '{'.\n popAndCheck(tokens, \"{\");\n\n // Return the fail node definition.\n return node;\n}\n\n/**\n * Creates a flip node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The flip node JSON definition.\n */\nfunction createFlipNode(tokens: string[], stringLiteralPlaceholders: StringLiteralPlaceholders): FlipNodeDefinition {\n const node = {\n type: \"flip\",\n ...parseAttributeTokens(tokens, stringLiteralPlaceholders)\n } as FlipNodeDefinition;\n\n // This is a decorator node, so we expect an opening '{'.\n popAndCheck(tokens, \"{\");\n\n // Return the flip node definition.\n return node;\n}\n\n/**\n * Creates a repeat node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The repeat node JSON definition.\n */\nfunction createRepeatNode(\n tokens: string[],\n stringLiteralPlaceholders: StringLiteralPlaceholders\n): RepeatNodeDefinition {\n let node = { type: \"repeat\" } as RepeatNodeDefinition;\n\n // Get the node arguments.\n const nodeArguments = parseArgumentTokens(tokens, stringLiteralPlaceholders);\n\n // The arguments of a repeat node are optional. We may have:\n // - No node arguments, in which case the repeat note will iterate indefinitely.\n // - One node argument which will be the explicit number of iterations to make.\n // - Two node arguments which define the min and max iteration bounds from which a random iteration count will be picked.\n if (nodeArguments.length) {\n // All repeat node arguments MUST be of type number and must be integer.\n nodeArguments\n .filter((arg) => arg.type !== \"number\" || !arg.isInteger)\n .forEach(() => {\n throw new Error(`repeat node iteration counts must be integer values`);\n });\n\n // We should have got one or two iteration counts.\n if (nodeArguments.length === 1) {\n // A static iteration count was defined.\n node.iterations = nodeArguments[0].value as number;\n\n // A repeat node must have a positive number of iterations if defined.\n if (node.iterations < 0) {\n throw new Error(\"a repeat node must have a positive number of iterations if defined\");\n }\n } else if (nodeArguments.length === 2) {\n // A minimum and maximum iteration count was defined.\n node.iterations = [nodeArguments[0].value as number, nodeArguments[1].value as number];\n\n // A repeat node must have a positive min and max iteration count if they are defined.\n if (node.iterations[0] < 0 || node.iterations[1] < 0) {\n throw new Error(\"a repeat node must have a positive minimum and maximum iteration count if defined\");\n }\n\n // A repeat node must not have an minimum iteration count that exceeds the maximum iteration count.\n if (node.iterations[0] > node.iterations[1]) {\n throw new Error(\n \"a repeat node must not have a minimum iteration count that exceeds the maximum iteration count\"\n );\n }\n } else {\n // An incorrect number of iteration counts was defined.\n throw new Error(\"invalid number of repeat node iteration count arguments defined\");\n }\n }\n\n // Grab any node attribute definitions and spread them into the node definition.\n node = { ...node, ...parseAttributeTokens(tokens, stringLiteralPlaceholders) };\n\n // This is a decorator node, so we expect an opening '{'.\n popAndCheck(tokens, \"{\");\n\n // Return the repeat node definition.\n return node;\n}\n\n/**\n * Creates a retry node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The retry node JSON definition.\n */\nfunction createRetryNode(tokens: string[], stringLiteralPlaceholders: StringLiteralPlaceholders): RetryNodeDefinition {\n let node = { type: \"retry\" } as RetryNodeDefinition;\n\n // Get the node arguments.\n const nodeArguments = parseArgumentTokens(tokens, stringLiteralPlaceholders);\n\n // The arguments of a retry node are optional. We may have:\n // - No node arguments, in which case the retry note will attempt indefinitely.\n // - One node argument which will be the explicit number of attempts to make.\n // - Two node arguments which define the min and max attempt bounds from which a random attempt count will be picked.\n if (nodeArguments.length) {\n // All retry node arguments MUST be of type number and must be integer.\n nodeArguments\n .filter((arg) => arg.type !== \"number\" || !arg.isInteger)\n .forEach(() => {\n throw new Error(`retry node attempt counts must be integer values`);\n });\n\n // We should have got one or two attempt counts.\n if (nodeArguments.length === 1) {\n // A static attempt count was defined.\n node.attempts = nodeArguments[0].value as number;\n\n // A retry node must have a positive number of attempts if defined.\n if (node.attempts < 0) {\n throw new Error(\"a retry node must have a positive number of attempts if defined\");\n }\n } else if (nodeArguments.length === 2) {\n // A minimum and maximum attempt count was defined.\n node.attempts = [nodeArguments[0].value as number, nodeArguments[1].value as number];\n\n // A retry node must have a positive min and max attempts count if they are defined.\n if (node.attempts[0] < 0 || node.attempts[1] < 0) {\n throw new Error(\"a retry node must have a positive minimum and maximum attempt count if defined\");\n }\n\n // A retry node must not have a minimum attempt count that exceeds the maximum attempt count.\n if (node.attempts[0] > node.attempts[1]) {\n throw new Error(\n \"a retry node must not have a minimum attempt count that exceeds the maximum attempt count\"\n );\n }\n } else {\n // An incorrect number of attempt counts was defined.\n throw new Error(\"invalid number of retry node attempt count arguments defined\");\n }\n }\n\n // Grab any node attribute definitions and spread them into the node definition.\n node = { ...node, ...parseAttributeTokens(tokens, stringLiteralPlaceholders) };\n\n // This is a decorator node, so we expect an opening '{'.\n popAndCheck(tokens, \"{\");\n\n // Return the retry node definition.\n return node;\n}\n\n/**\n * Creates a sequence node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The sequence node JSON definition.\n */\nfunction createSequenceNode(\n tokens: string[],\n stringLiteralPlaceholders: StringLiteralPlaceholders\n): SequenceNodeDefinition {\n const node = {\n type: \"sequence\",\n ...parseAttributeTokens(tokens, stringLiteralPlaceholders)\n } as SequenceNodeDefinition;\n\n // This is a composite node, so we expect an opening '{'.\n popAndCheck(tokens, \"{\");\n\n // Return the sequence node definition.\n return node;\n}\n\n/**\n * Creates a selector node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The selector node JSON definition.\n */\nfunction createSelectorNode(\n tokens: string[],\n stringLiteralPlaceholders: StringLiteralPlaceholders\n): SelectorNodeDefinition {\n const node = {\n type: \"selector\",\n ...parseAttributeTokens(tokens, stringLiteralPlaceholders)\n } as SelectorNodeDefinition;\n\n // This is a composite node, so we expect an opening '{'.\n popAndCheck(tokens, \"{\");\n\n // Return the selector node definition.\n return node;\n}\n\n/**\n * Creates a parallel node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The parallel node JSON definition.\n */\nfunction createParallelNode(\n tokens: string[],\n stringLiteralPlaceholders: StringLiteralPlaceholders\n): ParallelNodeDefinition {\n const node = {\n type: \"parallel\",\n ...parseAttributeTokens(tokens, stringLiteralPlaceholders)\n } as ParallelNodeDefinition;\n\n // This is a composite node, so we expect an opening '{'.\n popAndCheck(tokens, \"{\");\n\n // Return the parallel node definition.\n return node;\n}\n\n/**\n * Creates a lotto node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The lotto node JSON definition.\n */\nfunction createLottoNode(tokens: string[], stringLiteralPlaceholders: StringLiteralPlaceholders): LottoNodeDefinition {\n // If any node arguments have been defined then they must be our weights.\n const nodeArguments = parseArgumentTokens(tokens, stringLiteralPlaceholders);\n\n // All lotto node arguments MUST be of type number and must be integer.\n nodeArguments\n .filter((arg) => arg.type !== \"number\" || !arg.isInteger)\n .forEach(() => {\n throw new Error(`lotto node weight arguments must be integer values`);\n });\n\n const node = {\n type: \"lotto\",\n weights: nodeArguments.map(({ value }) => value),\n ...parseAttributeTokens(tokens, stringLiteralPlaceholders)\n } as LottoNodeDefinition;\n\n // This is a composite node, so we expect an opening '{'.\n popAndCheck(tokens, \"{\");\n\n // Return the lotto node definition.\n return node;\n}\n\n/**\n * Creates an action node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The action node JSON definition.\n */\nfunction createActionNode(\n tokens: string[],\n stringLiteralPlaceholders: StringLiteralPlaceholders\n): ActionNodeDefinition {\n // Parse any node arguments, we should have at least one which will be an identifier argument for the action name\n // and agent function to invoke for the action, all other arguments are to be passed as arguments to that function.\n const [actionNameIdentifier, ...agentFunctionArgs] = parseArgumentTokens(tokens, stringLiteralPlaceholders);\n\n // Our first argument MUST be defined and be an identifier as we require an action name argument.\n if (actionNameIdentifier?.type !== \"identifier\") {\n throw new Error(\"expected action name identifier argument\");\n }\n\n // Only the first argument should have been an identifier, all agent function arguments must be string, number, boolean or null.\n agentFunctionArgs\n .filter((arg) => arg.type === \"identifier\")\n .forEach((arg) => {\n throw new Error(\n `invalid action node argument value '${arg.value}', must be string, number, boolean or null`\n );\n });\n\n // Return the action node definition.\n return {\n type: \"action\",\n call: actionNameIdentifier.value,\n args: agentFunctionArgs.map(({ value }) => value),\n ...parseAttributeTokens(tokens, stringLiteralPlaceholders)\n };\n}\n\n/**\n * Creates a condition node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The condition node JSON definition.\n */\nfunction createConditionNode(\n tokens: string[],\n stringLiteralPlaceholders: StringLiteralPlaceholders\n): ConditionNodeDefinition {\n // Parse any node arguments, we should have at least one which will be an identifier argument for the condition name\n // and agent function to invoke for the condition, all other arguments are to be passed as arguments to that function.\n const [conditionNameIdentifier, ...agentFunctionArgs] = parseArgumentTokens(tokens, stringLiteralPlaceholders);\n\n // Our first argument MUST be defined and be an identifier as we require a condition name argument.\n if (conditionNameIdentifier?.type !== \"identifier\") {\n throw new Error(\"expected condition name identifier argument\");\n }\n\n // Only the first argument should have been an identifier, all agent function arguments must be string, number, boolean or null.\n agentFunctionArgs\n .filter((arg) => arg.type === \"identifier\")\n .forEach((arg) => {\n throw new Error(\n `invalid condition node argument value '${arg.value}', must be string, number, boolean or null`\n );\n });\n\n // Return the condition node definition.\n return {\n type: \"condition\",\n call: conditionNameIdentifier.value,\n args: agentFunctionArgs.map(({ value }) => value),\n ...parseAttributeTokens(tokens, stringLiteralPlaceholders)\n };\n}\n\n/**\n * Creates a wait node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The wait node JSON definition.\n */\nfunction createWaitNode(tokens: string[], stringLiteralPlaceholders: StringLiteralPlaceholders): WaitNodeDefinition {\n let node = { type: \"wait\" } as WaitNodeDefinition;\n\n // Get the node arguments.\n const nodeArguments = parseArgumentTokens(tokens, stringLiteralPlaceholders);\n\n // The arguments of a wait node are optional. We may have:\n // - No node arguments, in which case the wait will be indefinite until it is aborted.\n // - One node argument which will be the explicit duration of the wait.\n // - Two node arguments which define the min and max duration bounds from which a random duration will be picked.\n if (nodeArguments.length) {\n // All wait node arguments MUST be of type number and must be integer.\n nodeArguments\n .filter((arg) => arg.type !== \"number\" || !arg.isInteger)\n .forEach(() => {\n throw new Error(`wait node duration arguments must be integer values`);\n });\n\n // We may have:\n // - One node argument which will be the explicit duration of the wait.\n // - Two node arguments which define the min and max duration bounds from which a random duration will be picked.\n // - Too many arguments, which is not valid.\n if (nodeArguments.length === 1) {\n // An explicit duration was defined.\n node.duration = nodeArguments[0].value as number;\n\n // If an explict duration was defined then it must be a positive number.\n if (node.duration < 0) {\n throw new Error(\"a wait node must have a positive duration\");\n }\n } else if (nodeArguments.length === 2) {\n // Min and max duration bounds were defined from which a random duration will be picked.\n node.duration = [nodeArguments[0].value as number, nodeArguments[1].value as number];\n\n // A wait node must have a positive min and max duration.\n if (node.duration[0] < 0 || node.duration[1] < 0) {\n throw new Error(\"a wait node must have a positive minimum and maximum duration\");\n }\n\n // A wait node must not have a minimum duration that exceeds the maximum duration.\n if (node.duration[0] > node.duration[1]) {\n throw new Error(\"a wait node must not have a minimum duration that exceeds the maximum duration\");\n }\n } else if (nodeArguments.length > 2) {\n // An incorrect number of duration arguments were defined.\n throw new Error(\"invalid number of wait node duration arguments defined\");\n }\n }\n\n // Return the wait node definition.\n return { ...node, ...parseAttributeTokens(tokens, stringLiteralPlaceholders) };\n}\n\n/**\n * Creates a branch node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The branch node JSON definition.\n */\nfunction createBranchNode(\n tokens: string[],\n stringLiteralPlaceholders: StringLiteralPlaceholders\n): BranchNodeDefinition {\n // Parse any node arguments, we should have one which will be an identifier argument for the root ref.\n const nodeArguments = parseArgumentTokens(tokens, stringLiteralPlaceholders);\n\n // We should have only a single identifer argument for a branch node, which is the root ref.\n if (nodeArguments.length !== 1 || nodeArguments[0].type !== \"identifier\") {\n throw new Error(\"expected single branch name argument\");\n }\n\n // Return the branch node definition.\n return { type: \"branch\", ref: nodeArguments[0].value };\n}\n\n/**\n * Validate a fully-populated node definition that was popped off of the tree stack.\n * @param node The popped node to validate.\n */\nfunction validatePoppedNode(node: AnyNodeDefinition): void {\n // Decorators MUST have a child defined.\n if (isDecoratorNode(node) && isNullOrUndefined(node.child)) {\n throw new Error(`a ${node.type} node must have a single child node defined`);\n }\n\n // Composites MUST have at least one child defined.\n if (isCompositeNode(node) && !node.children?.length) {\n throw new Error(`a ${node.type} node must have at least a single child node defined`);\n }\n}\n", "import { RootNodeDefinition } from \"./BehaviourTreeDefinition\";\nimport { flattenDefinition, isBranchNode, isInteger } from \"./BehaviourTreeDefinitionUtilities\";\nimport { convertMDSLToJSON } from \"./mdsl/MDSLDefinitionParser\";\n\n/**\n * An object representing the result of validating a tree definition.\n */\nexport type DefinitionValidationResult = {\n /**\n * A flag defining whether validation succeeded.\n */\n succeeded: boolean;\n /**\n * A string containing the error message if validation did not succeed.\n */\n errorMessage?: string;\n};\n\n/**\n * Validates the specified behaviour tree definition in the form of JSON or MDSL, not taking any globally registered subtrees into consideration.\n * @param definition The behaviour tree definition in the form of JSON or MDSL.\n * @returns An object representing the result of validating the given tree definition.\n */\nexport function validateDefinition(definition: any): DefinitionValidationResult {\n // The definition must be defined.\n if (definition === null || typeof definition === \"undefined\") {\n return createValidationFailureResult(\"definition is null or undefined\");\n }\n\n // We are expecting a definition in one of three different forms:\n // - A string which we will assume is MDSL and we will parse this to JSON before validation.\n // - An array which we will assume is an array of root node definitions with at least one being the primary root node (no 'id' property)\n // - An object which we will assume is the primary root node and should not have an 'id' property.\n if (typeof definition === \"string\") {\n // The definition is a string which we can assume is MDSL, so attempt to validate it.\n return validateMDSLDefinition(definition);\n } else if (typeof definition === \"object\") {\n // The definition will either be an array (of root node definitions) or an object (the single primary root node definition).\n return validateJSONDefinition(definition);\n } else {\n return createValidationFailureResult(`unexpected definition type of '${typeof definition}'`);\n }\n}\n\n/**\n * Validates the specified behaviour tree definition in the form of MDSL.\n * @param definition The behaviour tree definition in the form of MDSL.\n * @returns An object representing the result of validating the given tree definition.\n */\nexport function validateMDSLDefinition(definition: string): DefinitionValidationResult {\n let rootNodeDefinitions;\n\n // The first thing the we need to do is to attempt to convert our MDSL into JSON.\n try {\n // The definition is a string which we can assume is MDSL, so attempt to parse it to a JSON definition in the form of an array of root node definitions.\n rootNodeDefinitions = convertMDSLToJSON(definition);\n } catch (error) {\n // We failed to parse the JSON from the MDSL, this is likely to be the result of it not being a valid MDSL string.\n return createValidationFailureResult(`invalid MDSL: ${error}`);\n }\n\n // Unpack all of the root node definitions into arrays of main ('id' defined) and sub ('id' not defined) root node definitions.\n const mainRootNodeDefinitions = rootNodeDefinitions.filter(({ id }) => typeof id === \"undefined\");\n const subRootNodeDefinitions = rootNodeDefinitions.filter(({ id }) => typeof id === \"string\" && id.length > 0);\n\n // We should ALWAYS have exactly one root node definition without an 'id' property defined, which is out main root node definition.\n if (mainRootNodeDefinitions.length !== 1) {\n return createValidationFailureResult(\n \"expected single unnamed root node at base of definition to act as main root\"\n );\n }\n\n // We should never have duplicate 'id' properties across our sub root node definitions.\n const subRootNodeIdenitifers: string[] = [];\n for (const { id } of subRootNodeDefinitions) {\n // Have we already come across this 'id' property value?\n if (subRootNodeIdenitifers.includes(id!)) {\n return createValidationFailureResult(`multiple root nodes found with duplicate name '${id}'`);\n }\n\n subRootNodeIdenitifers.push(id!);\n }\n\n try {\n // Validate our branch -> subtree links and check for any circular dependencies, we don't care about checking for broken subtree links here.\n validateBranchSubtreeLinks(rootNodeDefinitions, false);\n } catch (exception) {\n return createValidationFailureResult((exception as Error).message);\n }\n\n // Our definition was valid!\n return { succeeded: true };\n}\n\n/**\n * Validates the specified behaviour tree definition in the form of JSON.\n * @param definition The behaviour tree definition in the form of JSON.\n * @returns An object representing the result of validating the given tree definition.\n */\nexport function validateJSONDefinition(\n definition: RootNodeDefinition | RootNodeDefinition[]\n): DefinitionValidationResult {\n // The definition will either be an array (of root node definitions) or an object (the single primary root node definition).\n const rootNodeDefinitions = Array.isArray(definition) ? definition : [definition];\n\n // Iterate over our array of root nodes and call validateNode for each, passing an initial depth of 0, wrapped in a try catch to handle validation failures.\n try {\n rootNodeDefinitions.forEach((rootNodeDefinition) => validateNode(rootNodeDefinition, 0));\n } catch (error) {\n // Handle cases where we have caught a thrown Error and return a failure result with the error message.\n if (error instanceof Error) {\n return createValidationFailureResult(error.message);\n }\n\n // No idea what happened here!\n return createValidationFailureResult(`unexpected error: ${error}`);\n }\n\n // Unpack all of the root node definitions into arrays of main ('id' defined) and sub ('id' not defined) root node definitions.\n const mainRootNodeDefinitions = rootNodeDefinitions.filter(({ id }) => typeof id === \"undefined\");\n const subRootNodeDefinitions = rootNodeDefinitions.filter(({ id }) => typeof id === \"string\" && id.length > 0);\n\n // We should ALWAYS have exactly one root node definition without an 'id' property defined, which is out main root node definition.\n if (mainRootNodeDefinitions.length !== 1) {\n return createValidationFailureResult(\n \"expected single root node without 'id' property defined to act as main root\"\n );\n }\n\n // We should never have duplicate 'id' properties across our sub root node definitions.\n const subRootNodeIdenitifers: string[] = [];\n for (const { id } of subRootNodeDefinitions) {\n // Have we already come across this 'id' property value?\n if (subRootNodeIdenitifers.includes(id!)) {\n return createValidationFailureResult(\n `multiple root nodes found with duplicate 'id' property value of '${id}'`\n );\n }\n\n subRootNodeIdenitifers.push(id!);\n }\n\n try {\n // Validate our branch -> subtree links and check for any circular dependencies, we don't care about checking for broken subtree links here.\n validateBranchSubtreeLinks(rootNodeDefinitions, false);\n } catch (exception) {\n return createValidationFailureResult((exception as Error).message);\n }\n\n // Our definition was valid!\n return { succeeded: true };\n}\n\n/**\n * Validates the branch -> subtree links across all provided root node definitions.\n * This will not consider branch nodes that reference any globally registered subtrees unless includesGlobalSubtrees\n * is set to true, in which case we will also verify that there are no broken branch -> subtree links.\n * @param rootNodeDefinitions The array of root node definitions.\n * @param includesGlobalSubtrees A flag defining whether the array includes all global subtree root node definitions.\n */\nexport function validateBranchSubtreeLinks(rootNodeDefinitions: RootNodeDefinition[], includesGlobalSubtrees: boolean) {\n // Create a mapping of root node identifiers to other root nodes that they reference via branch nodes.\n // Below is an example of a mapping that includes a circular dependency (root => a => b => c => a)\n // [{ refs: [\"a\", \"b\"] }, { id: \"a\", refs: [\"b\"] }, { id: \"b\", refs: [\"c\"] }, { id: \"c\", refs: [\"a\"] }]\n const rootNodeMappings: { id: string | undefined; refs: string[] }[] = rootNodeDefinitions.map(\n (rootNodeDefinition) => ({\n id: rootNodeDefinition.id,\n refs: flattenDefinition(rootNodeDefinition)\n .filter(isBranchNode)\n .map(({ ref }) => ref)\n })\n );\n\n // A recursive function to walk through the mappings, keeping track of which root nodes we have visited in the form of a path of root node identifiers.\n const followRefs = (mapping: { id: string | undefined; refs: string[] }, path: (string | undefined)[] = []) => {\n // Have we found a circular dependency?\n if (path.includes(mapping.id)) {\n // We found a circular dependency! Get the bad path of root node identifiers.\n const badPath = [...path, mapping.id];\n\n // Create the formatted path value. [undefined, \"a\", \"b\", \"c\", \"a\"] would be formatted as \"a -> b -> c -> a\".\n const badPathFormatted = badPath.filter((element) => !!element).join(\" => \");\n\n // No need to continue, we found a circular dependency.\n throw new Error(`circular dependency found in branch node references: ${badPathFormatted}`);\n }\n\n for (const ref of mapping.refs) {\n // Find the mapping for the root node with an identifer matching the current ref.\n const subMapping = rootNodeMappings.find(({ id }) => id === ref);\n\n // We may not have a mapping for this ref, which is normal when we aren't considering all globally registered subtrees.\n if (subMapping) {\n followRefs(subMapping, [...path, mapping.id]);\n } else if (includesGlobalSubtrees) {\n // We found a reference to a root node that doesn't exist, which is a problem seeing as the root node definitons includes all globally registered subtrees.\n throw new Error(\n mapping.id\n ? `subtree '${mapping.id}' has branch node that references root node '${ref}' which has not been defined`\n : `primary tree has branch node that references root node '${ref}' which has not been defined`\n );\n }\n }\n };\n\n // Start looking for circular dependencies and broken references from the primary root node definition.\n followRefs(rootNodeMappings.find((mapping) => typeof mapping.id === \"undefined\")!);\n}\n\n/**\n * Validate an object that we expect to be a node definition.\n * @param definition An object that we expect to be a node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateNode(definition: any, depth: number): void {\n // Every node must be valid object and have a non-empty 'type' string property.\n if (typeof definition !== \"object\" || typeof definition.type !== \"string\" || definition.type.length === 0) {\n throw new Error(\n `node definition is not an object or 'type' property is not a non-empty string at depth '${depth}'`\n );\n }\n\n // How we validate this node definition will depend on its type.\n switch (definition.type) {\n case \"action\":\n validateActionNode(definition, depth);\n break;\n\n case \"condition\":\n validateConditionNode(definition, depth);\n break;\n\n case \"wait\":\n validateWaitNode(definition, depth);\n break;\n\n case \"branch\":\n validateBranchNode(definition, depth);\n break;\n\n case \"root\":\n validateRootNode(definition, depth);\n break;\n\n case \"success\":\n validateSuccessNode(definition, depth);\n break;\n\n case \"fail\":\n validateFailNode(definition, depth);\n break;\n\n case \"flip\":\n validateFlipNode(definition, depth);\n break;\n\n case \"repeat\":\n validateRepeatNode(definition, depth);\n break;\n\n case \"retry\":\n validateRetryNode(definition, depth);\n break;\n\n case \"sequence\":\n validateSequenceNode(definition, depth);\n break;\n\n case \"selector\":\n validateSelectorNode(definition, depth);\n break;\n\n case \"parallel\":\n validateParallelNode(definition, depth);\n break;\n\n default:\n throw new Error(`unexpected node type of '${definition.type}' at depth '${depth}'`);\n }\n}\n\n/**\n * Validate any attributes for a given node definition.\n * @param definition The node definition.\n * @param depth The depth of the node in the behaviour tree definition.\n */\nfunction validateNodeAttributes(definition: any, depth: number): void {\n // Validate each of the attribute types for this node.\n [\"while\", \"until\", \"entry\", \"exit\", \"step\"].forEach((attributeName) => {\n // Attempt to grab the definition for the current attribute from the node definition.\n const attributeDefinition = definition[attributeName];\n\n // All node attributes are optional, so there is nothing to do if the current attribute is not defined.\n if (typeof attributeDefinition === \"undefined\") {\n return;\n }\n\n // The attribute definition must be an object.\n if (typeof attributeDefinition !== \"object\") {\n throw new Error(\n `expected attribute '${attributeName}' to be an object for '${definition.type}' node at depth '${depth}'`\n );\n }\n\n // The 'call' property must be defined for any attribute definition.\n if (typeof attributeDefinition.call !== \"string\" || attributeDefinition.call.length === 0) {\n throw new Error(\n `expected 'call' property for attribute '${attributeName}' to be a non-empty string for '${definition.type}' node at depth '${depth}'`\n );\n }\n\n // If any node attribute arguments have been defined then they must have been defined in an array.\n if (typeof attributeDefinition.args !== \"undefined\" && !Array.isArray(attributeDefinition.args)) {\n throw new Error(\n `expected 'args' property for attribute '${attributeName}' to be an array for '${definition.type}' node at depth '${depth}'`\n );\n }\n });\n}\n\n/**\n * Validate an object that we expect to be a root node definition.\n * @param definition An object that we expect to be a root node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateRootNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"root\") {\n throw new Error(\"expected node type of 'root' for root node\");\n }\n\n // A root node cannot be the child of another node.\n if (depth > 0) {\n throw new Error(\"a root node cannot be the child of another node\");\n }\n\n // Check that, if the root node 'id' property is defined, it is a non-empty string.\n if (typeof definition.id !== \"undefined\" && (typeof definition.id !== \"string\" || definition.id.length === 0)) {\n throw new Error(\"expected non-empty string for 'id' property if defined for root node\");\n }\n\n // A root node is a decorator node, so must have a child node defined.\n if (typeof definition.child === \"undefined\") {\n throw new Error(\"expected property 'child' to be defined for root node\");\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n\n // Validate the child node of this decorator node.\n validateNode(definition.child, depth + 1);\n}\n\n/**\n * Validate an object that we expect to be a success node definition.\n * @param definition An object that we expect to be a success node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateSuccessNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"success\") {\n throw new Error(`expected node type of 'success' for success node at depth '${depth}'`);\n }\n\n // A success node is a decorator node, so must have a child node defined.\n if (typeof definition.child === \"undefined\") {\n throw new Error(`expected property 'child' to be defined for success node at depth '${depth}'`);\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n\n // Validate the child node of this decorator node.\n validateNode(definition.child, depth + 1);\n}\n\n/**\n * Validate an object that we expect to be a fail node definition.\n * @param definition An object that we expect to be a fail node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateFailNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"fail\") {\n throw new Error(`expected node type of 'fail' for fail node at depth '${depth}'`);\n }\n\n // A fail node is a decorator node, so must have a child node defined.\n if (typeof definition.child === \"undefined\") {\n throw new Error(`expected property 'child' to be defined for fail node at depth '${depth}'`);\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n\n // Validate the child node of this decorator node.\n validateNode(definition.child, depth + 1);\n}\n\n/**\n * Validate an object that we expect to be a flip node definition.\n * @param definition An object that we expect to be a flip node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateFlipNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"flip\") {\n throw new Error(`expected node type of 'flip' for flip node at depth '${depth}'`);\n }\n\n // A flip node is a decorator node, so must have a child node defined.\n if (typeof definition.child === \"undefined\") {\n throw new Error(`expected property 'child' to be defined for flip node at depth '${depth}'`);\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n\n // Validate the child node of this decorator node.\n validateNode(definition.child, depth + 1);\n}\n\n/**\n * Validate an object that we expect to be a repeat node definition.\n * @param definition An object that we expect to be a repeat node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateRepeatNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"repeat\") {\n throw new Error(`expected node type of 'repeat' for repeat node at depth '${depth}'`);\n }\n\n // A repeat node is a decorator node, so must have a child node defined.\n if (typeof definition.child === \"undefined\") {\n throw new Error(`expected property 'child' to be defined for repeat node at depth '${depth}'`);\n }\n\n // Check whether an 'iterations' property has been defined, it may not have been if this node is to repeat indefinitely.\n if (typeof definition.iterations !== \"undefined\") {\n if (Array.isArray(definition.iterations)) {\n // Check whether any elements of the array are not integer values.\n const containsNonInteger = !!definition.iterations.find((value: unknown) => !isInteger(value));\n\n // If the 'iterations' property is an array then it MUST contain two integer values.\n if (definition.iterations.length !== 2 || containsNonInteger) {\n throw new Error(\n `expected array containing two integer values for 'iterations' property if defined for repeat node at depth '${depth}'`\n );\n }\n\n // A repeat node must have a positive min and max iterations count if they are defined.\n if (definition.iterations[0] < 0 || definition.iterations[1] < 0) {\n throw new Error(\n `expected positive minimum and maximum iterations count for 'iterations' property if defined for repeat node at depth '${depth}'`\n );\n }\n\n // A repeat node must not have a minimum iterations count that exceeds the maximum iterations count.\n if (definition.iterations[0] > definition.iterations[1]) {\n throw new Error(\n `expected minimum iterations count that does not exceed the maximum iterations count for 'iterations' property if defined for repeat node at depth '${depth}'`\n );\n }\n } else if (isInteger(definition.iterations)) {\n // A repeat node must have a positive number of iterations if defined.\n if (definition.iterations < 0) {\n throw new Error(\n `expected positive iterations count for 'iterations' property if defined for repeat node at depth '${depth}'`\n );\n }\n } else {\n throw new Error(\n `expected integer value or array containing two integer values for 'iterations' property if defined for repeat node at depth '${depth}'`\n );\n }\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n\n // Validate the child node of this decorator node.\n validateNode(definition.child, depth + 1);\n}\n\n/**\n * Validate an object that we expect to be a retry node definition.\n * @param definition An object that we expect to be a retry node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateRetryNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"retry\") {\n throw new Error(`expected node type of 'retry' for retry node at depth '${depth}'`);\n }\n\n // A retry node is a decorator node, so must have a child node defined.\n if (typeof definition.child === \"undefined\") {\n throw new Error(`expected property 'child' to be defined for retry node at depth '${depth}'`);\n }\n\n // Check whether an 'attempts' property has been defined, it may not have been if this node is to retry indefinitely.\n if (typeof definition.attempts !== \"undefined\") {\n if (Array.isArray(definition.attempts)) {\n // Check whether any elements of the array are not integer values.\n const containsNonInteger = !!definition.attempts.find((value: unknown) => !isInteger(value));\n\n // If the 'attempts' property is an array then it MUST contain two integer values.\n if (definition.attempts.length !== 2 || containsNonInteger) {\n throw new Error(\n `expected array containing two integer values for 'attempts' property if defined for retry node at depth '${depth}'`\n );\n }\n\n // A retry node must have a positive min and max attempts count if they are defined.\n if (definition.attempts[0] < 0 || definition.attempts[1] < 0) {\n throw new Error(\n `expected positive minimum and maximum attempts count for 'attempts' property if defined for retry node at depth '${depth}'`\n );\n }\n\n // A retry node must not have a minimum attempts count that exceeds the maximum attempts count.\n if (definition.attempts[0] > definition.attempts[1]) {\n throw new Error(\n `expected minimum attempts count that does not exceed the maximum attempts count for 'attempts' property if defined for retry node at depth '${depth}'`\n );\n }\n } else if (isInteger(definition.attempts)) {\n // A retry node must have a positive number of attempts if defined.\n if (definition.attempts < 0) {\n throw new Error(\n `expected positive attempts count for 'attempts' property if defined for retry node at depth '${depth}'`\n );\n }\n } else {\n throw new Error(\n `expected integer value or array containing two integer values for 'attempts' property if defined for retry node at depth '${depth}'`\n );\n }\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n\n // Validate the child node of this decorator node.\n validateNode(definition.child, depth + 1);\n}\n\n/**\n * Validate an object that we expect to be a branch node definition.\n * @param definition An object that we expect to be a branch node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateBranchNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"branch\") {\n throw new Error(`expected node type of 'branch' for branch node at depth '${depth}'`);\n }\n\n // Check that the branch node 'ref' property is defined and is a non-empty string.\n if (typeof definition.ref !== \"string\" || definition.ref.length === 0) {\n throw new Error(`expected non-empty string for 'ref' property for branch node at depth '${depth}'`);\n }\n\n // It is invalid to define guard attributes for a branch node as they should be defined on the referenced root node.\n [\"while\", \"until\"].forEach((attributeName) => {\n if (typeof definition[attributeName] !== \"undefined\") {\n throw new Error(\n `guards should not be defined for branch nodes but guard '${attributeName}' was defined for branch node at depth '${depth}'`\n );\n }\n });\n\n // It is invalid to define callback attributes for a branch node as they should be defined on the referenced root node.\n [\"entry\", \"exit\", \"step\"].forEach((attributeName) => {\n if (typeof definition[attributeName] !== \"undefined\") {\n throw new Error(\n `callbacks should not be defined for branch nodes but callback '${attributeName}' was defined for branch node at depth '${depth}'`\n );\n }\n });\n}\n\n/**\n * Validate an object that we expect to be a action node definition.\n * @param definition An object that we expect to be a action node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateActionNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"action\") {\n throw new Error(`expected node type of 'action' for action node at depth '${depth}'`);\n }\n\n // The 'call' property must be defined for a action node definition.\n if (typeof definition.call !== \"string\" || definition.call.length === 0) {\n throw new Error(`expected non-empty string for 'call' property of action node at depth '${depth}'`);\n }\n\n // If any action function arguments have been defined then they must have been defined in an array.\n if (typeof definition.args !== \"undefined\" && !Array.isArray(definition.args)) {\n throw new Error(`expected array for 'args' property if defined for action node at depth '${depth}'`);\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n}\n\n/**\n * Validate an object that we expect to be a condition node definition.\n * @param definition An object that we expect to be a condition node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateConditionNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"condition\") {\n throw new Error(`expected node type of 'condition' for condition node at depth '${depth}'`);\n }\n\n // The 'call' property must be defined for a condition node definition.\n if (typeof definition.call !== \"string\" || definition.call.length === 0) {\n throw new Error(`expected non-empty string for 'call' property of condition node at depth '${depth}'`);\n }\n\n // If any condition function arguments have been defined then they must have been defined in an array.\n if (typeof definition.args !== \"undefined\" && !Array.isArray(definition.args)) {\n throw new Error(`expected array for 'args' property if defined for condition node at depth '${depth}'`);\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n}\n\n/**\n * Validate an object that we expect to be a wait node definition.\n * @param definition An object that we expect to be a wait node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateWaitNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"wait\") {\n throw new Error(`expected node type of 'wait' for wait node at depth '${depth}'`);\n }\n\n // Check whether a 'duration' property has been defined, it may not have been if this node is to wait indefinitely.\n if (typeof definition.duration !== \"undefined\") {\n if (Array.isArray(definition.duration)) {\n // Check whether any elements of the array are not integer values.\n const containsNonInteger = !!definition.duration.find((value: unknown) => !isInteger(value));\n\n // If the 'duration' property is an array then it MUST contain two integer values.\n if (definition.duration.length !== 2 || containsNonInteger) {\n throw new Error(\n `expected array containing two integer values for 'duration' property if defined for wait node at depth '${depth}'`\n );\n }\n\n // A wait node must have a positive min and max duration value if they are defined.\n if (definition.duration[0] < 0 || definition.duration[1] < 0) {\n throw new Error(\n `expected positive minimum and maximum duration for 'duration' property if defined for wait node at depth '${depth}'`\n );\n }\n\n // A wait node must not have a minimum duration value that exceeds the maximum duration value.\n if (definition.duration[0] > definition.duration[1]) {\n throw new Error(\n `expected minimum duration value that does not exceed the maximum duration value for 'duration' property if defined for wait node at depth '${depth}'`\n );\n }\n } else if (isInteger(definition.duration)) {\n // A wait node must have a positive duration value if defined.\n if (definition.duration < 0) {\n throw new Error(\n `expected positive duration value for 'duration' property if defined for wait node at depth '${depth}'`\n );\n }\n } else {\n throw new Error(\n `expected integer value or array containing two integer values for 'duration' property if defined for wait node at depth '${depth}'`\n );\n }\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n}\n\n/**\n * Validate an object that we expect to be a sequence node definition.\n * @param definition An object that we expect to be a sequence node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateSequenceNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"sequence\") {\n throw new Error(`expected node type of 'sequence' for sequence node at depth '${depth}'`);\n }\n\n // A sequence node is a composite node, so must have a children nodes array defined.\n if (!Array.isArray(definition.children) || definition.children.length === 0) {\n throw new Error(`expected non-empty 'children' array to be defined for sequence node at depth '${depth}'`);\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n\n // Validate the child nodes of this composite node.\n definition.children.forEach((child: any) => validateNode(child, depth + 1));\n}\n\n/**\n * Validate an object that we expect to be a selector node definition.\n * @param definition An object that we expect to be a selector node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateSelectorNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"selector\") {\n throw new Error(`expected node type of 'selector' for selector node at depth '${depth}'`);\n }\n\n // A selector node is a composite node, so must have a children nodes array defined.\n if (!Array.isArray(definition.children) || definition.children.length === 0) {\n throw new Error(`expected non-empty 'children' array to be defined for selector node at depth '${depth}'`);\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n\n // Validate the child nodes of this composite node.\n definition.children.forEach((child: any) => validateNode(child, depth + 1));\n}\n\n/**\n * Validate an object that we expect to be a parallel node definition.\n * @param definition An object that we expect to be a parallel node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateParallelNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"parallel\") {\n throw new Error(`expected node type of 'parallel' for parallel node at depth '${depth}'`);\n }\n\n // A parallel node is a composite node, so must have a children nodes array defined.\n if (!Array.isArray(definition.children) || definition.children.length === 0) {\n throw new Error(`expected non-empty 'children' array to be defined for parallel node at depth '${depth}'`);\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n\n // Validate the child nodes of this composite node.\n definition.children.forEach((child: any) => validateNode(child, depth + 1));\n}\n\n/**\n * A helper function to create a failure validation result with the given error message.\n * @param errorMessage The validation failure error message.\n * @returns A failure validation result with the given error message.\n */\nfunction createValidationFailureResult(errorMessage: string): DefinitionValidationResult {\n return { succeeded: false, errorMessage };\n}\n", "import { ActionResult, Agent, GlobalFunction } from \"./Agent\";\nimport { RootNodeDefinition } from \"./BehaviourTreeDefinition\";\n\nexport type InvokerFunction = (args: any[]) => ActionResult;\n\n/**\n * A singleton used to store and lookup registered functions and subtrees.\n */\nexport default class Lookup {\n /**\n * The object holding any registered functions keyed on function name.\n */\n private static functionTable: { [key: string]: GlobalFunction } = {};\n /**\n * The object holding any registered subtree root node definitions keyed on tree name.\n */\n private static subtreeTable: { [key: string]: RootNodeDefinition } = {};\n\n /**\n * Gets the function with the specified name.\n * @param name The name of the function.\n * @returns The function with the specified name.\n */\n public static getFunc(name: string): GlobalFunction {\n return this.functionTable[name];\n }\n\n /**\n * Sets the function with the specified name for later lookup.\n * @param name The name of the function.\n * @param func The function.\n */\n public static setFunc(name: string, func: GlobalFunction): void {\n this.functionTable[name] = func;\n }\n\n /**\n * Gets the function invoker for the specified agent and function name.\n * If a function with the specified name exists on the agent object then it will\n * be returned, otherwise we will then check the registered functions for a match.\n * @param agent The agent instance that this behaviour tree is modelling behaviour for.\n * @param name The function name.\n * @returns The function invoker for the specified agent and function name.\n */\n static getFuncInvoker(agent: Agent, name: string): InvokerFunction | null {\n // Check whether the agent contains the specified function.\n const foundOnAgent = agent[name];\n if (foundOnAgent && typeof foundOnAgent === \"function\") {\n return (args: any[]): boolean | ActionResult => foundOnAgent.apply(agent, args);\n }\n\n // The agent does not contain the specified function but it may have been registered at some point.\n if (this.functionTable[name] && typeof this.functionTable[name] === \"function\") {\n return (args: any[]) => this.functionTable[name](agent, ...args.map((arg) => arg.value));\n }\n\n // We have no function to invoke.\n return null;\n }\n\n /**\n * Gets all registered subtree root node definitions.\n */\n static getSubtrees(): { [key: string]: RootNodeDefinition } {\n return this.subtreeTable;\n }\n\n /**\n * Sets the subtree with the specified name for later lookup.\n * @param name The name of the subtree.\n * @param subtree The subtree.\n */\n static setSubtree(name: string, subtree: RootNodeDefinition) {\n this.subtreeTable[name] = subtree;\n }\n\n /**\n * Removes the registered function or subtree with the specified name.\n * @param name The name of the registered function or subtree.\n */\n static remove(name: string) {\n delete this.functionTable[name];\n delete this.subtreeTable[name];\n }\n\n /**\n * Remove all registered functions and subtrees.\n */\n static empty() {\n this.functionTable = {};\n this.subtreeTable = {};\n }\n}\n", "import Node from \"../../nodes/Node\";\n\n/**\n * An exception thrown when evaluating node guard path conditions and a conditions fails.\n */\nexport default class GuardUnsatisifedException extends Error {\n /**\n * @param source The node at which a guard condition failed.\n */\n constructor(private source: Node) {\n super(\"A guard path condition has failed\");\n }\n\n /**\n * Gets whether the specified node is the node at which a guard condition failed.\n * @param node The node to check against the source node.\n * @returns Whether the specified node is the node at which a guard condition failed.\n */\n isSourceNode = (node: Node) => node === this.source;\n}\n", "import { Agent } from \"../../Agent\";\nimport Guard from \"./Guard\";\nimport Node from \"../../nodes/Node\";\nimport GuardUnsatisifedException from \"./GuardUnsatisifedException\";\n\nexport type GuardPathPart = {\n node: Node;\n guards: Guard[];\n};\n\n/**\n * Represents a path of node guards along a root-to-leaf tree path.\n */\nexport default class GuardPath {\n /**\n * @param nodes An array of objects defining a node instance -> guard link, ordered by node depth.\n */\n constructor(private nodes: GuardPathPart[]) {}\n\n /**\n * Evaluate guard conditions for all guards in the tree path, moving outwards from the root.\n * @param agent The agent, required for guard evaluation.\n * @returns An evaluation results object.\n */\n evaluate = (agent: Agent) => {\n // We need to evaluate guard conditions for nodes up the tree, moving outwards from the root.\n for (const details of this.nodes) {\n // There can be multiple guards per node.\n for (const guard of details.guards) {\n // Check whether the guard condition passes, and throw an exception if not.\n if (!guard.isSatisfied(agent)) {\n throw new GuardUnsatisifedException(details.node);\n }\n }\n }\n };\n}\n", "import { BehaviourTreeOptions } from \"../BehaviourTreeOptions\";\nimport State, { AnyState } from \"../State\";\nimport { Agent } from \"../Agent\";\nimport Leaf from \"./leaf/Leaf\";\nimport Attribute from \"../attributes/Attribute\";\nimport Entry from \"../attributes/callbacks/Entry\";\nimport Exit from \"../attributes/callbacks/Exit\";\nimport Step from \"../attributes/callbacks/Step\";\nimport Guard from \"../attributes/guards/Guard\";\nimport GuardPath from \"../attributes/guards/GuardPath\";\nimport GuardUnsatisifedException from \"../attributes/guards/GuardUnsatisifedException\";\n\n/**\n * A base node.\n */\nexport default abstract class Node {\n /**\n * The node uid.\n */\n private readonly uid: string = createNodeUid();\n /**\n * The node state.\n */\n private state: AnyState = State.READY;\n /**\n * The guard path to evaluate as part of a node update.\n */\n private guardPath: GuardPath | undefined;\n\n /**\n * @param type The node type.\n * @param attributes The node attributes.\n * @param args The node argument definitions.\n */\n constructor(private type: string, private attributes: Attribute[], private args: any[]) {}\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected abstract onUpdate(agent: Agent, options: BehaviourTreeOptions): void;\n\n /**\n * Gets the name of the node.\n */\n public abstract getName(): string;\n\n /**\n * Gets whether this node is a leaf node.\n */\n public abstract isLeafNode: () => this is Leaf;\n\n /**\n * Gets/Sets the state of the node.\n */\n getState = (): AnyState => this.state;\n setState = (value: AnyState): void => {\n this.state = value;\n };\n\n /**\n * Gets the unique id of the node.\n */\n getUid = () => this.uid;\n\n /**\n * Gets the type of the node.\n */\n getType = () => this.type;\n\n /**\n * Gets the node attributes.\n */\n getAttributes = () => this.attributes;\n\n /**\n * Gets the node arguments.\n */\n getArguments = () => this.args;\n\n /**\n * Gets the node attribute with the specified type, or null if it does not exist.\n */\n getAttribute(type: \"entry\" | \"ENTRY\"): Entry;\n getAttribute(type: \"exit\" | \"EXIT\"): Exit;\n getAttribute(type: \"step\" | \"STEP\"): Step;\n getAttribute(type: string): Attribute {\n return (\n this.getAttributes().filter((decorator) => decorator.type.toUpperCase() === type.toUpperCase())[0] || null\n );\n }\n\n /**\n * Gets the node attributes.\n */\n getGuardAttributes = (): Guard[] => this.getAttributes().filter((decorator) => decorator.isGuard()) as Guard[];\n\n /**\n * Sets the guard path to evaluate as part of a node update.\n */\n setGuardPath = (value: GuardPath) => (this.guardPath = value);\n\n /**\n * Gets whether a guard path is assigned to this node.\n */\n hasGuardPath = () => !!this.guardPath;\n\n /**\n * Gets whether this node is in the specified state.\n * @param value The value to compare to the node state.\n */\n public is(value: AnyState): boolean {\n return this.state === value;\n }\n\n /**\n * Reset the state of the node.\n */\n public reset(): void {\n this.setState(State.READY);\n }\n\n /**\n * Abort the running of this node.\n * @param agent The agent.\n */\n public abort(agent: Agent): void {\n // There is nothing to do if this node is not in the running state.\n if (!this.is(State.RUNNING)) {\n return;\n }\n\n // Reset the state of this node.\n this.reset();\n\n this.getAttribute(\"exit\")?.callAgentFunction(agent, false, true);\n }\n\n /**\n * Update the node.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n * @returns The result of the update.\n */\n public update(agent: Agent, options: BehaviourTreeOptions): void {\n // If this node is already in a 'SUCCEEDED' or 'FAILED' state then there is nothing to do.\n if (this.is(State.SUCCEEDED) || this.is(State.FAILED)) {\n return;\n }\n\n try {\n // Evaluate all of the guard path conditions for the current tree path.\n this.guardPath!.evaluate(agent);\n\n // If this node is in the READY state then call the ENTRY for this node if it exists.\n if (this.is(State.READY)) {\n this.getAttribute(\"entry\")?.callAgentFunction(agent);\n }\n\n this.getAttribute(\"step\")?.callAgentFunction(agent);\n\n // Do the actual update.\n this.onUpdate(agent, options);\n\n // If this node is now in a 'SUCCEEDED' or 'FAILED' state then call the EXIT for this node if it exists.\n if (this.is(State.SUCCEEDED) || this.is(State.FAILED)) {\n this.getAttribute(\"exit\")?.callAgentFunction(agent, this.is(State.SUCCEEDED), false);\n }\n } catch (error) {\n // If the error is a GuardUnsatisfiedException then we need to determine if this node is the source.\n if (error instanceof GuardUnsatisifedException && error.isSourceNode(this)) {\n // Abort the current node.\n this.abort(agent);\n\n // Any node that is the source of an abort will be a failed node.\n this.setState(State.FAILED);\n } else {\n throw error;\n }\n }\n }\n}\n\n/**\n * Create a randomly generated node uid.\n * @returns A randomly generated node uid.\n */\nfunction createNodeUid(): string {\n var S4 = function () {\n return (((1 + Math.random()) * 0x10000) | 0).toString(16).substring(1);\n };\n return S4() + S4() + \"-\" + S4() + \"-\" + S4() + \"-\" + S4() + \"-\" + S4() + S4() + S4();\n}\n", "import Node from \"../Node\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\n\n/**\n * A composite node that wraps child nodes.\n */\nexport default abstract class Composite extends Node {\n /**\n * @param type The node type.\n * @param attributes The node attributes.\n * @param children The child nodes.\n */\n constructor(type: string, attributes: Attribute[], protected children: Node[]) {\n super(type, attributes, []);\n }\n\n /**\n * Gets whether this node is a leaf node.\n */\n isLeafNode = () => false;\n\n /**\n * Gets the children of this node.\n */\n getChildren = () => this.children;\n\n /**\n * Reset the state of the node.\n */\n reset = () => {\n // Reset the state of this node.\n this.setState(State.READY);\n\n // Reset the state of any child nodes.\n this.getChildren().forEach((child) => child.reset());\n };\n\n /**\n * Abort the running of this node.\n * @param agent The agent.\n */\n abort = (agent: Agent) => {\n // There is nothing to do if this node is not in the running state.\n if (!this.is(State.RUNNING)) {\n return;\n }\n\n // Abort any child nodes.\n this.getChildren().forEach((child) => child.abort(agent));\n\n // Reset the state of this node.\n this.reset();\n\n this.getAttribute(\"exit\")?.callAgentFunction(agent, false, true);\n };\n}\n", "import Composite from \"./Composite\";\nimport State from \"../../State\";\nimport Node from \"../Node\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A PARALLEL node.\n * The child nodes are executed concurrently until one fails or all succeed.\n */\nexport default class Parallel extends Composite {\n /**\n * @param attributes The node attributes.\n * @param children The child nodes.\n */\n constructor(attributes: Attribute[], children: Node[]) {\n super(\"parallel\", attributes, children);\n }\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // Keep a count of the number of succeeded child nodes.\n let succeededCount = 0;\n\n let hasChildFailed = false;\n\n // Iterate over all of the children of this node.\n for (const child of this.children) {\n // If the child has never been updated or is running then we will need to update it now.\n if (child.getState() === State.READY || child.getState() === State.RUNNING) {\n // Update the child of this node.\n child.update(agent, options);\n }\n\n // If the current child has a state of 'SUCCEEDED' then we should move on to the next child.\n if (child.getState() === State.SUCCEEDED) {\n // The child node has succeeded, keep track of this to determine if all children have.\n succeededCount++;\n\n // The child node succeeded, but we have not finished checking every child node yet.\n continue;\n }\n\n // If the current child has a state of 'FAILED' then this node is also a 'FAILED' node.\n if (child.getState() === State.FAILED) {\n hasChildFailed = true;\n\n // There is no need to check the rest of the children.\n break;\n }\n\n // The node should be in the 'RUNNING' state.\n if (child.getState() !== State.RUNNING) {\n // The child node was not in an expected state.\n throw new Error(\"child node was not in an expected state.\");\n }\n }\n\n if (hasChildFailed) {\n // This node is a 'FAILED' node.\n this.setState(State.FAILED);\n\n // Abort every running child.\n for (const child of this.children) {\n if (child.getState() === State.RUNNING) {\n child.abort(agent);\n }\n }\n } else {\n // If all children have succeeded then this node has also succeeded, otherwise it is still running.\n this.setState(succeededCount === this.children.length ? State.SUCCEEDED : State.RUNNING);\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => \"PARALLEL\";\n}\n", "import Composite from \"./Composite\";\nimport Node from \"../Node\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A SELECTOR node.\n * The child nodes are executed in sequence until one succeeds or all fail.\n */\nexport default class Selector extends Composite {\n /**\n * @param attributes The node attributes.\n * @param children The child nodes.\n */\n constructor(attributes: Attribute[], protected children: Node[]) {\n super(\"selector\", attributes, children);\n }\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // Iterate over all of the children of this node.\n for (const child of this.children) {\n // If the child has never been updated or is running then we will need to update it now.\n if (child.getState() === State.READY || child.getState() === State.RUNNING) {\n // Update the child of this node.\n child.update(agent, options);\n }\n\n // If the current child has a state of 'SUCCEEDED' then this node is also a 'SUCCEEDED' node.\n if (child.getState() === State.SUCCEEDED) {\n // This node is a 'SUCCEEDED' node.\n this.setState(State.SUCCEEDED);\n\n // There is no need to check the rest of the selector nodes.\n return;\n }\n\n // If the current child has a state of 'FAILED' then we should move on to the next child.\n if (child.getState() === State.FAILED) {\n // Find out if the current child is the last one in the selector.\n // If it is then this sequence node has also failed.\n if (this.children.indexOf(child) === this.children.length - 1) {\n // This node is a 'FAILED' node.\n this.setState(State.FAILED);\n\n // There is no need to check the rest of the selector as we have completed it.\n return;\n } else {\n // The child node failed, try the next one.\n continue;\n }\n }\n\n // The node should be in the 'RUNNING' state.\n if (child.getState() === State.RUNNING) {\n // This node is a 'RUNNING' node.\n this.setState(State.RUNNING);\n\n // There is no need to check the rest of the selector as the current child is still running.\n return;\n }\n\n // The child node was not in an expected state.\n throw new Error(\"child node was not in an expected state.\");\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => \"SELECTOR\";\n}\n", "import Composite from \"./Composite\";\nimport Node from \"../Node\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A SEQUENCE node.\n * The child nodes are executed in sequence until one fails or all succeed.\n */\nexport default class Sequence extends Composite {\n /**\n * @param attributes The node attributes.\n * @param children The child nodes.\n */\n constructor(attributes: Attribute[], protected children: Node[]) {\n super(\"sequence\", attributes, children);\n }\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // Iterate over all of the children of this node.\n for (const child of this.children) {\n // If the child has never been updated or is running then we will need to update it now.\n if (child.getState() === State.READY || child.getState() === State.RUNNING) {\n // Update the child of this node.\n child.update(agent, options);\n }\n\n // If the current child has a state of 'SUCCEEDED' then we should move on to the next child.\n if (child.getState() === State.SUCCEEDED) {\n // Find out if the current child is the last one in the sequence.\n // If it is then this sequence node has also succeeded.\n if (this.children.indexOf(child) === this.children.length - 1) {\n // This node is a 'SUCCEEDED' node.\n this.setState(State.SUCCEEDED);\n\n // There is no need to check the rest of the sequence as we have completed it.\n return;\n } else {\n // The child node succeeded, but we have not finished the sequence yet.\n continue;\n }\n }\n\n // If the current child has a state of 'FAILED' then this node is also a 'FAILED' node.\n if (child.getState() === State.FAILED) {\n // This node is a 'FAILED' node.\n this.setState(State.FAILED);\n\n // There is no need to check the rest of the sequence.\n return;\n }\n\n // The node should be in the 'RUNNING' state.\n if (child.getState() === State.RUNNING) {\n // This node is a 'RUNNING' node.\n this.setState(State.RUNNING);\n\n // There is no need to check the rest of the sequence as the current child is still running.\n return;\n }\n\n // The child node was not in an expected state.\n throw new Error(\"child node was not in an expected state.\");\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => \"SEQUENCE\";\n}\n", "import createLotto from \"lotto-draw\";\n\nimport Node from \"../Node\";\nimport Composite from \"./Composite\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A LOTTO node.\n * A winning child is picked on the initial update of this node, based on ticket weighting.\n * The state of this node will match the state of the winning child.\n */\nexport default class Lotto extends Composite {\n /**\n * @param attributes The node attributes.\n * @param weights The child node weights.\n * @param children The child nodes.\n */\n constructor(attributes: Attribute[], private weights: number[] | undefined, children: Node[]) {\n super(\"lotto\", attributes, children);\n }\n\n /**\n * The child node selected to be the active one.\n */\n private selectedChild: Node | undefined;\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // If this node is in the READY state then we need to pick a winning child node.\n if (this.is(State.READY)) {\n // Create a lotto draw with which to randomly pick a child node to become the active one.\n const lottoDraw = createLotto({\n // Hook up the optional 'random' behaviour tree function option to the one used by 'lotto-draw'.\n random: options.random,\n // Pass in each child node as a participant in the lotto draw with their respective ticket count.\n participants: this.children.map((child, index) => [child, this.weights?.[index] || 1])\n });\n\n // Randomly pick a child based on ticket weighting, this will become the active child for this composite node.\n this.selectedChild = lottoDraw.draw() || undefined;\n }\n\n // If something went wrong and we don't have an active child then we should throw an error.\n if (!this.selectedChild) {\n throw new Error(\"failed to update lotto node as it has no active child\");\n }\n\n // If the selected child has never been updated or is running then we will need to update it now.\n if (this.selectedChild.getState() === State.READY || this.selectedChild.getState() === State.RUNNING) {\n this.selectedChild.update(agent, options);\n }\n\n // The state of the lotto node is the state of its selected child.\n this.setState(this.selectedChild.getState());\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => (this.weights ? `LOTTO [${this.weights.join(\",\")}]` : \"LOTTO\");\n}\n", "import Node from \"../Node\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\n\n/**\n * A decorator node that wraps a single child node.\n */\nexport default abstract class Decorator extends Node {\n /**\n * @param type The node type.\n * @param attributes The node attributes.\n * @param child The child node.\n */\n constructor(type: string, attributes: Attribute[], protected child: Node) {\n super(type, attributes, []);\n }\n\n /**\n * Gets whether this node is a leaf node.\n */\n isLeafNode = () => false;\n\n /**\n * Gets the children of this node.\n */\n getChildren = () => [this.child];\n\n /**\n * Reset the state of the node.\n */\n reset = () => {\n // Reset the state of this node.\n this.setState(State.READY);\n\n // Reset the state of the child node.\n this.child.reset();\n };\n\n /**\n * Abort the running of this node.\n * @param agent The agent.\n */\n abort = (agent: Agent) => {\n // There is nothing to do if this node is not in the running state.\n if (!this.is(State.RUNNING)) {\n return;\n }\n\n // Abort the child node.\n this.child.abort(agent);\n\n // Reset the state of this node.\n this.reset();\n\n this.getAttribute(\"exit\")?.callAgentFunction(agent, false, true);\n };\n}\n", "import Node from \"../Node\";\nimport Decorator from \"./Decorator\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A Fail node.\n * This node wraps a single child and will always move to the 'FAILED' state when the child moves to a 'SUCCEEDED' or 'FAILED' state.\n */\nexport default class Fail extends Decorator {\n /**\n * @param attributes The node attributes.\n * @param child The child node.\n */\n constructor(attributes: Attribute[], child: Node) {\n super(\"fail\", attributes, child);\n }\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // If the child has never been updated or is running then we will need to update it now.\n if (this.child.getState() === State.READY || this.child.getState() === State.RUNNING) {\n this.child.update(agent, options);\n }\n\n // The state of this node will depend in the state of its child.\n switch (this.child.getState()) {\n case State.RUNNING:\n this.setState(State.RUNNING);\n break;\n\n case State.SUCCEEDED:\n case State.FAILED:\n this.setState(State.FAILED);\n break;\n\n default:\n this.setState(State.READY);\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => \"FAIL\";\n}\n", "import Decorator from \"./Decorator\";\nimport State from \"../../State\";\nimport Node from \"../Node\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A Flip node.\n * This node wraps a single child and will flip the state of the child state.\n */\nexport default class Flip extends Decorator {\n /**\n * @param attributes The node attributes.\n * @param child The child node.\n */\n constructor(attributes: Attribute[], child: Node) {\n super(\"flip\", attributes, child);\n }\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // If the child has never been updated or is running then we will need to update it now.\n if (this.child.getState() === State.READY || this.child.getState() === State.RUNNING) {\n this.child.update(agent, options);\n }\n\n // The state of this node will depend in the state of its child.\n switch (this.child.getState()) {\n case State.RUNNING:\n this.setState(State.RUNNING);\n break;\n\n case State.SUCCEEDED:\n this.setState(State.FAILED);\n break;\n\n case State.FAILED:\n this.setState(State.SUCCEEDED);\n break;\n\n default:\n this.setState(State.READY);\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => \"FLIP\";\n}\n", "import Node from \"../Node\";\nimport Decorator from \"./Decorator\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A REPEAT node.\n * The node has a single child which can have:\n * -- A number of iterations for which to repeat the child node.\n * -- An infinite repeat loop if neither an iteration count or a condition function is defined.\n * The REPEAT node will stop and have a 'FAILED' state if its child is ever in a 'FAILED' state after an update.\n * The REPEAT node will attempt to move on to the next iteration if its child is ever in a 'SUCCEEDED' state.\n */\nexport default class Repeat extends Decorator {\n /**\n * @param attributes The node attributes.\n * @param iterations The number of iterations to repeat the child node.\n * @param iterationsMin The minimum possible number of iterations to repeat the child node.\n * @param iterationsMax The maximum possible number of iterations to repeat the child node.\n * @param child The child node.\n */\n constructor(\n attributes: Attribute[],\n private iterations: number | null,\n private iterationsMin: number | null,\n private iterationsMax: number | null,\n child: Node\n ) {\n super(\"repeat\", attributes, child);\n }\n\n /**\n * The number of target iterations to make.\n */\n private targetIterationCount: number | null = null;\n\n /**\n * The current iteration count.\n */\n private currentIterationCount: number = 0;\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // If this node is in the READY state then we need to reset the child and the target iteration count.\n if (this.is(State.READY)) {\n // Reset the child node.\n this.child.reset();\n\n // Reset the current iteration count.\n this.currentIterationCount = 0;\n\n // Set the target iteration count.\n this.setTargetIterationCount(options);\n }\n\n // Do a check to see if we can iterate. If we can then this node will move into the 'RUNNING' state.\n // If we cannot iterate then we have hit our target iteration count, which means that the node has succeeded.\n if (this.canIterate()) {\n // This node is in the running state and can do its initial iteration.\n this.setState(State.RUNNING);\n\n // We may have already completed an iteration, meaning that the child node will be in the SUCCEEDED state.\n // If this is the case then we will have to reset the child node now.\n if (this.child.getState() === State.SUCCEEDED) {\n this.child.reset();\n }\n\n // Update the child of this node.\n this.child.update(agent, options);\n\n // If the child moved into the FAILED state when we updated it then there is nothing left to do and this node has also failed.\n // If it has moved into the SUCCEEDED state then we have completed the current iteration.\n if (this.child.getState() === State.FAILED) {\n // The child has failed, meaning that this node has failed.\n this.setState(State.FAILED);\n\n return;\n } else if (this.child.getState() === State.SUCCEEDED) {\n // We have completed an iteration.\n this.currentIterationCount += 1;\n }\n } else {\n // This node is in the 'SUCCEEDED' state as we cannot iterate any more.\n this.setState(State.SUCCEEDED);\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => {\n if (this.iterations !== null) {\n return `REPEAT ${this.iterations}x`;\n } else if (this.iterationsMin !== null && this.iterationsMax !== null) {\n return `REPEAT ${this.iterationsMin}x-${this.iterationsMax}x`;\n } else {\n return \"REPEAT\";\n }\n };\n\n /**\n * Reset the state of the node.\n */\n reset = () => {\n // Reset the state of this node.\n this.setState(State.READY);\n\n // Reset the current iteration count.\n this.currentIterationCount = 0;\n\n // Reset the child node.\n this.child.reset();\n };\n\n /**\n * Gets whether an iteration can be made.\n * @returns Whether an iteration can be made.\n */\n private canIterate = () => {\n if (this.targetIterationCount !== null) {\n // We can iterate as long as we have not reached our target iteration count.\n return this.currentIterationCount < this.targetIterationCount;\n }\n\n // If neither an iteration count or a condition function were defined then we can iterate indefinitely.\n return true;\n };\n\n /**\n * Sets the target iteration count.\n * @param options The behaviour tree options object.\n */\n private setTargetIterationCount = (options: BehaviourTreeOptions) => {\n // Are we dealing with an explicit iteration count or will we be randomly picking a iteration count between the min and max iteration count.\n if (this.iterations !== null) {\n this.targetIterationCount = this.iterations;\n } else if (this.iterationsMin !== null && this.iterationsMax !== null) {\n // We will be picking a random iteration count between a min and max iteration count, if the optional 'random'\n // behaviour tree function option is defined then we will be using that, otherwise we will fall back to using Math.random.\n const random = typeof options.random === \"function\" ? options.random : Math.random;\n\n // Pick a random iteration count between a min and max iteration count.\n this.targetIterationCount = Math.floor(\n random() * (this.iterationsMax - this.iterationsMin + 1) + this.iterationsMin\n );\n } else {\n this.targetIterationCount = null;\n }\n };\n}\n", "import Node from \"../Node\";\nimport Decorator from \"./Decorator\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A RETRY node.\n * The node has a single child which can have:\n * -- A number of iterations for which to repeat the child node.\n * -- An infinite repeat loop if neither an iteration count or a condition function is defined.\n * The RETRY node will stop and have a 'SUCCEEDED' state if its child is ever in a 'SUCCEEDED' state after an update.\n * The RETRY node will attempt to move on to the next iteration if its child is ever in a 'FAILED' state.\n */\nexport default class Retry extends Decorator {\n /**\n * @param attributes The node attributes.\n * @param attempts The number of attempts to retry the child node.\n * @param attemptsMin The minimum possible number of attempts to retry the child node.\n * @param attemptsMax The maximum possible number of attempts to retry the child node.\n * @param child The child node.\n */\n constructor(\n attributes: Attribute[],\n private attempts: number | null,\n private attemptsMin: number | null,\n private attemptsMax: number | null,\n child: Node\n ) {\n super(\"retry\", attributes, child);\n }\n\n /**\n * The number of target attempts to make.\n */\n private targetAttemptCount: number | null = null;\n\n /**\n * The current attempt count.\n */\n private currentAttemptCount: number = 0;\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // If this node is in the READY state then we need to reset the child and the target attempt count.\n if (this.is(State.READY)) {\n // Reset the child node.\n this.child.reset();\n\n // Reset the current attempt count.\n this.currentAttemptCount = 0;\n\n // Set the target attempt count.\n this.setTargetAttemptCount(options);\n }\n\n // Do a check to see if we can attempt. If we can then this node will move into the 'RUNNING' state.\n // If we cannot attempt then we have hit our target attempt count, which means that the node has succeeded.\n if (this.canAttempt()) {\n // This node is in the running state and can do its initial attempt.\n this.setState(State.RUNNING);\n\n // We may have already completed an attempt, meaning that the child node will be in the FAILED state.\n // If this is the case then we will have to reset the child node now.\n if (this.child.getState() === State.FAILED) {\n this.child.reset();\n }\n\n // Update the child of this node.\n this.child.update(agent, options);\n\n // If the child moved into the SUCCEEDED state when we updated it then there is nothing left to do and this node has also succeeded.\n // If it has moved into the FAILED state then we have completed the current attempt.\n if (this.child.getState() === State.SUCCEEDED) {\n // The child has succeeded, meaning that this node has succeeded.\n this.setState(State.SUCCEEDED);\n\n return;\n } else if (this.child.getState() === State.FAILED) {\n // We have completed an attempt.\n this.currentAttemptCount += 1;\n }\n } else {\n // This node is in the 'FAILED' state as we cannot iterate any more.\n this.setState(State.FAILED);\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => {\n if (this.attempts !== null) {\n return `RETRY ${this.attempts}x`;\n } else if (this.attemptsMin !== null && this.attemptsMax !== null) {\n return `RETRY ${this.attemptsMin}x-${this.attemptsMax}x`;\n } else {\n return \"RETRY\";\n }\n };\n\n /**\n * Reset the state of the node.\n */\n reset = () => {\n // Reset the state of this node.\n this.setState(State.READY);\n\n // Reset the current attempt count.\n this.currentAttemptCount = 0;\n\n // Reset the child node.\n this.child.reset();\n };\n\n /**\n * Gets whether an attempt can be made.\n * @returns Whether an attempt can be made.\n */\n canAttempt = () => {\n if (this.targetAttemptCount !== null) {\n // We can attempt as long as we have not reached our target attempt count.\n return this.currentAttemptCount < this.targetAttemptCount;\n }\n\n // If neither an attempt count or a condition function were defined then we can attempt indefinitely.\n return true;\n };\n\n /**\n * Sets the target attempt count.\n * @param options The behaviour tree options object.\n */\n setTargetAttemptCount = (options: BehaviourTreeOptions) => {\n // Are we dealing with an explicit attempt count or will we be randomly picking an attempt count between the min and max attempt count.\n if (this.attempts !== null) {\n this.targetAttemptCount = this.attempts;\n } else if (this.attemptsMin !== null && this.attemptsMax !== null) {\n // We will be picking a random attempt count between a min and max attempt count, if the optional 'random'\n // behaviour tree function option is defined then we will be using that, otherwise we will fall back to using Math.random.\n const random = typeof options.random === \"function\" ? options.random : Math.random;\n\n // Pick a random attempt count between a min and max attempt count.\n this.targetAttemptCount = Math.floor(\n random() * (this.attemptsMax - this.attemptsMin + 1) + this.attemptsMin\n );\n } else {\n this.targetAttemptCount = null;\n }\n };\n}\n", "import Node from \"../Node\";\nimport Decorator from \"./Decorator\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A Root node.\n * The root node will have a single child.\n */\nexport default class Root extends Decorator {\n /**\n * @param attributes The node attributes.\n * @param child The child node.\n */\n constructor(attributes: Attribute[], child: Node) {\n super(\"root\", attributes, child);\n }\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // If the child has never been updated or is running then we will need to update it now.\n if (this.child.getState() === State.READY || this.child.getState() === State.RUNNING) {\n // Update the child of this node.\n this.child.update(agent, options);\n }\n\n // The state of the root node is the state of its child.\n this.setState(this.child.getState());\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => \"ROOT\";\n}\n", "import Node from \"../Node\";\nimport Decorator from \"./Decorator\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A Succeed node.\n * This node wraps a single child and will always move to the 'SUCCEEDED' state when the child moves to a 'SUCCEEDED' or 'FAILED' state.\n */\nexport default class Succeed extends Decorator {\n /**\n * @param attributes The node attributes.\n * @param child The child node.\n */\n constructor(attributes: Attribute[], child: Node) {\n super(\"succeed\", attributes, child);\n }\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // If the child has never been updated or is running then we will need to update it now.\n if (this.child.getState() === State.READY || this.child.getState() === State.RUNNING) {\n this.child.update(agent, options);\n }\n\n // The state of this node will depend in the state of its child.\n switch (this.child.getState()) {\n case State.RUNNING:\n this.setState(State.RUNNING);\n break;\n\n case State.SUCCEEDED:\n case State.FAILED:\n this.setState(State.SUCCEEDED);\n break;\n\n default:\n this.setState(State.READY);\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => \"SUCCEED\";\n}\n", "import Node from \"../Node\";\n\n/**\n * A leaf node.\n */\nexport default abstract class Leaf extends Node {\n /**\n * Gets whether this node is a leaf node.\n */\n isLeafNode = () => true;\n}\n", "import { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\nimport State, { CompleteState } from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Leaf from \"./Leaf\";\nimport Lookup from \"../../Lookup\";\nimport Attribute from \"../../attributes/Attribute\";\n\n/**\n * An Action leaf node.\n * This represents an immediate or ongoing state of behaviour.\n */\nexport default class Action extends Leaf {\n /**\n * @param attributes The node attributes.\n * @param actionName The action name.\n * @param actionArguments The array of action argument definitions.\n */\n constructor(attributes: Attribute[], private actionName: string, private actionArguments: any[]) {\n super(\"action\", attributes, actionArguments);\n }\n\n /**\n * Whether there is a pending update promise.\n */\n private isUsingUpdatePromise = false;\n\n /**\n * The finished state result of an update promise.\n */\n private updatePromiseStateResult: CompleteState | null = null;\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // If the result of this action depends on an update promise then there is nothing to do until\n // it resolves, unless there has been a value set as a result of the update promise resolving.\n if (this.isUsingUpdatePromise) {\n // Check whether the update promise has resolved with a state value.\n if (this.updatePromiseStateResult) {\n // Set the state of this node to match the state returned by the promise.\n this.setState(this.updatePromiseStateResult);\n }\n\n return;\n }\n\n // Attempt to get the invoker for the action function.\n const actionFuncInvoker = Lookup.getFuncInvoker(agent, this.actionName);\n\n // The action function should be defined.\n if (actionFuncInvoker === null) {\n throw new Error(\n `cannot update action node as the action '${this.actionName}' function is not defined on the agent and has not been registered`\n );\n }\n\n // Call the action function, the result of which may be:\n // - The finished state of this action node.\n // - A promise to return a finished node state.\n // - Undefined if the node should remain in the running state.\n const updateResult = actionFuncInvoker(this.actionArguments) as CompleteState | Promise;\n\n if (updateResult instanceof Promise) {\n updateResult.then(\n (result) => {\n // If 'isUpdatePromisePending' is null then the promise was cleared as it was resolving, probably via an abort of reset.\n if (!this.isUsingUpdatePromise) {\n return;\n }\n\n // Check to make sure the result is a valid finished state.\n if (result !== State.SUCCEEDED && result !== State.FAILED) {\n throw new Error(\n \"action node promise resolved with an invalid value, expected a State.SUCCEEDED or State.FAILED value to be returned\"\n );\n }\n\n // Set pending update promise state result to be processed on next update.\n this.updatePromiseStateResult = result;\n },\n (reason) => {\n // If 'isUpdatePromisePending' is null then the promise was cleared as it was resolving, probably via an abort of reset.\n if (!this.isUsingUpdatePromise) {\n return;\n }\n\n // Just throw whatever was returned as the rejection argument.\n throw new Error(reason);\n }\n );\n\n // This node will be in the 'RUNNING' state until the update promise resolves.\n this.setState(State.RUNNING);\n\n // We are now waiting for the promise returned by the use to resolve before we know what state this node is in.\n this.isUsingUpdatePromise = true;\n } else {\n // Validate the returned value.\n this.validateUpdateResult(updateResult);\n\n // Set the state of this node, this may be undefined, which just means that the node is still in the 'RUNNING' state.\n this.setState(updateResult || State.RUNNING);\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => this.actionName;\n\n /**\n * Reset the state of the node.\n */\n reset = () => {\n // Reset the state of this node.\n this.setState(State.READY);\n\n // There is no longer an update promise that we care about.\n this.isUsingUpdatePromise = false;\n this.updatePromiseStateResult = null;\n };\n\n /**\n * Validate the result of an update function call.\n * @param result The result of an update function call.\n */\n private validateUpdateResult = (result: CompleteState | boolean) => {\n switch (result) {\n case State.SUCCEEDED:\n case State.FAILED:\n case undefined:\n return;\n default:\n throw new Error(\n `action '${this.actionName}' 'onUpdate' returned an invalid response, expected an optional State.SUCCEEDED or State.FAILED value to be returned`\n );\n }\n };\n}\n", "import { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Leaf from \"./Leaf\";\nimport Lookup from \"../../Lookup\";\nimport Attribute from \"../../attributes/Attribute\";\n\n/**\n * A Condition leaf node.\n * This will succeed or fail immediately based on an agent predicate, without moving to the 'RUNNING' state.\n */\nexport default class Condition extends Leaf {\n /**\n * @param attributes The node attributes.\n * @param conditionName The name of the condition function.\n * @param conditionArguments The array of condition argument definitions.\n */\n constructor(attributes: Attribute[], private conditionName: string, private conditionArguments: any[]) {\n super(\"condition\", attributes, conditionArguments);\n }\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // Attempt to get the invoker for the condition function.\n const conditionFuncInvoker = Lookup.getFuncInvoker(agent, this.conditionName);\n\n // The condition function should be defined.\n if (conditionFuncInvoker === null) {\n throw new Error(\n `cannot update condition node as the condition '${this.conditionName}' function is not defined on the agent and has not been registered`\n );\n }\n\n // Call the condition function to determine the state of this node.\n this.setState(!!conditionFuncInvoker(this.conditionArguments) ? State.SUCCEEDED : State.FAILED);\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => this.conditionName;\n}\n", "import Leaf from \"./Leaf\";\nimport State from \"../../State\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { Agent } from \"../../Agent\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A WAIT node.\n * The state of this node will change to SUCCEEDED after a duration of time\n */\nexport default class Wait extends Leaf {\n /**\n * @param attributes The node attributes.\n * @param duration The duration that this node will wait to succeed in milliseconds.\n * @param durationMin The minimum possible duration in milliseconds that this node will wait to succeed.\n * @param durationMax The maximum possible duration in milliseconds that this node will wait to succeed.\n */\n constructor(\n attributes: Attribute[],\n private duration: number | null,\n private durationMin: number | null,\n private durationMax: number | null\n ) {\n super(\"wait\", attributes, []);\n }\n\n /**\n * The time in milliseconds at which this node was first updated.\n */\n private initialUpdateTime: number = 0;\n\n /**\n * The total duration in milliseconds that this node will be waiting for.\n */\n private totalDuration: number | null = null;\n\n /**\n * The duration in milliseconds that this node has been waiting for.\n */\n private waitedDuration: number = 0;\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // If this node is in the READY state then we need to set the initial update time.\n if (this.is(State.READY)) {\n // Set the initial update time.\n this.initialUpdateTime = new Date().getTime();\n\n // Set the initial waited duration.\n this.waitedDuration = 0;\n\n // Are we dealing with an explicit duration or will we be randomly picking a duration between the min and max duration.\n if (this.duration !== null) {\n this.totalDuration = this.duration;\n } else if (this.durationMin !== null && this.durationMax !== null) {\n // We will be picking a random duration between a min and max duration, if the optional 'random' behaviour tree\n // function option is defined then we will be using that, otherwise we will fall back to using Math.random.\n const random = typeof options.random === \"function\" ? options.random : Math.random;\n\n // Pick a random duration between a min and max duration.\n this.totalDuration = Math.floor(\n random() * (this.durationMax - this.durationMin + 1) + this.durationMin\n );\n } else {\n this.totalDuration = null;\n }\n\n // The node is now running until we finish waiting.\n this.setState(State.RUNNING);\n }\n\n // If we have no total duration then this wait node will wait indefinitely until it is aborted.\n if (this.totalDuration === null) {\n return;\n }\n\n // If we have a 'getDeltaTime' function defined as part of our options then we will use it to figure out how long we have waited for.\n if (typeof options.getDeltaTime === \"function\") {\n // Get the delta time.\n const deltaTime = options.getDeltaTime();\n\n // Our delta time must be a valid number and cannot be NaN.\n if (typeof deltaTime !== \"number\" || isNaN(deltaTime)) {\n throw new Error(\"The delta time must be a valid number and not NaN.\");\n }\n\n // Update the amount of time that this node has been waiting for based on the delta time.\n this.waitedDuration += deltaTime * 1000;\n } else {\n // We are not using a delta time, so we will just work out hom much time has passed since the first update.\n this.waitedDuration = new Date().getTime() - this.initialUpdateTime;\n }\n\n // Have we waited long enough?\n if (this.waitedDuration >= this.totalDuration) {\n // We have finished waiting!\n this.setState(State.SUCCEEDED);\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => {\n if (this.duration !== null) {\n return `WAIT ${this.duration}ms`;\n } else if (this.durationMin !== null && this.durationMax !== null) {\n return `WAIT ${this.durationMin}ms-${this.durationMax}ms`;\n } else {\n return \"WAIT\";\n }\n };\n}\n", "import Guard from \"./guards/Guard\";\n\nexport type AttributeDetails = {\n /** The attribute type. */\n type: string;\n\n /** The attribute arguments. */\n args: any[];\n};\n\n/**\n * A base node attribute.\n */\nexport default abstract class Attribute {\n /**\n * @param type The node attribute type.\n * @param args The array of attribute arguments.\n */\n constructor(public type: string, public args: any[]) {}\n\n /**\n * Gets the attribute details.\n */\n abstract getDetails(): TAttributeDetails;\n\n /**\n * Gets whether this attribute is a guard.\n */\n abstract isGuard: () => this is Guard;\n}\n", "import { Agent } from \"../../Agent\";\nimport Attribute, { AttributeDetails } from \"../Attribute\";\n\nexport type GuardAttributeDetails = {\n /** The name of the condition function that determines whether the guard is satisfied. */\n condition: string;\n} & AttributeDetails;\n\n/**\n * A base node guard attribute.\n */\nexport default abstract class Guard extends Attribute {\n /**\n * @param type The node attribute type.\n * @param args The array of decorator argument definitions.\n * @param condition The name of the condition function that determines whether the guard is satisfied.\n */\n constructor(type: string, args: any[], private condition: string) {\n super(type, args);\n }\n\n /**\n * Gets the name of the condition function that determines whether the guard is satisfied.\n */\n getCondition = () => this.condition;\n\n /**\n * Gets whether this attribute is a guard.\n */\n isGuard = () => true;\n\n /**\n * Gets the attribute details.\n */\n getDetails(): GuardAttributeDetails {\n return {\n type: this.type,\n args: this.args,\n condition: this.getCondition()\n };\n }\n\n /**\n * Gets whether the guard is satisfied.\n * @param agent The agent.\n * @returns Whether the guard is satisfied.\n */\n abstract isSatisfied(agent: Agent): boolean;\n}\n", "import Guard from \"./Guard\";\nimport Lookup from \"../../Lookup\";\nimport { Agent } from \"../../Agent\";\n\n/**\n * A WHILE guard which is satisfied as long as the given condition remains true.\n */\nexport default class While extends Guard {\n /**\n * @param condition The name of the condition function that determines whether the guard is satisfied.\n * @param args The array of decorator argument definitions.\n */\n constructor(condition: string, args: any[]) {\n super(\"while\", args, condition);\n }\n\n /**\n * Gets whether the guard is satisfied.\n * @param agent The agent.\n * @returns Whether the guard is satisfied.\n */\n isSatisfied = (agent: Agent) => {\n // Attempt to get the invoker for the condition function.\n const conditionFuncInvoker = Lookup.getFuncInvoker(agent, this.getCondition());\n\n // The condition function should be defined.\n if (conditionFuncInvoker === null) {\n throw new Error(\n `cannot evaluate node guard as the condition '${this.getCondition()}' function is not defined on the agent and has not been registered`\n );\n }\n\n // Call the condition function to determine whether this guard is satisfied.\n return !!conditionFuncInvoker(this.args);\n };\n}\n", "import Guard from \"./Guard\";\nimport Lookup from \"../../Lookup\";\nimport { Agent } from \"../../Agent\";\n\n/**\n * An UNTIL guard which is satisfied as long as the given condition remains false.\n */\nexport default class Until extends Guard {\n /**\n * @param condition The name of the condition function that determines whether the guard is satisfied.\n * @param args The array of decorator argument definitions.\n */\n constructor(condition: string, args: any[]) {\n super(\"until\", args, condition);\n }\n\n /**\n * Gets whether the guard is satisfied.\n * @param agent The agent.\n * @returns Whether the guard is satisfied.\n */\n isSatisfied = (agent: Agent) => {\n // Attempt to get the invoker for the condition function.\n const conditionFuncInvoker = Lookup.getFuncInvoker(agent, this.getCondition());\n\n // The condition function should be defined.\n if (conditionFuncInvoker === null) {\n throw new Error(\n `cannot evaluate node guard as the condition '${this.getCondition()}' function is not defined on the agent and has not been registered`\n );\n }\n\n // Call the condition function to determine whether this guard is satisfied.\n return !!!conditionFuncInvoker(this.args);\n };\n}\n", "import { Agent } from \"../../Agent\";\nimport Attribute, { AttributeDetails } from \"../Attribute\";\n\nexport type CallbackAttributeDetails = {\n /** The name of the agent function that is called. */\n functionName: string;\n} & AttributeDetails;\n\n/**\n * A base node callback attribute.\n */\nexport default abstract class Callback extends Attribute {\n /**\n * @param type The node attribute type.\n * @param args The array of decorator argument definitions.\n * @param functionName The name of the agent function to call.\n */\n constructor(type: string, args: any[], private functionName: string) {\n super(type, args);\n }\n\n /**\n * Gets the name of the agent function to call.\n */\n getFunctionName = () => this.functionName;\n\n /**\n * Gets whether this attribute is a guard.\n */\n isGuard = () => false;\n\n /**\n * Gets the attribute details.\n */\n getDetails(): CallbackAttributeDetails {\n return {\n type: this.type,\n args: this.args,\n functionName: this.getFunctionName()\n };\n }\n\n /**\n * Attempt to call the agent function that this callback refers to.\n * @param agent The agent.\n */\n abstract callAgentFunction: (agent: Agent, isSuccess: boolean, isAborted: boolean) => void;\n}\n", "import Callback from \"./Callback\";\nimport Lookup from \"../../Lookup\";\nimport { Agent } from \"../../Agent\";\n\n/**\n * An ENTRY callback which defines an agent function to call when the associated node is updated and moves out of running state.\n */\nexport default class Entry extends Callback {\n /**\n * @param functionName The name of the agent function to call.\n * @param args The array of callback argument definitions.\n */\n constructor(functionName: string, args: any[]) {\n super(\"entry\", args, functionName);\n }\n\n /**\n * Attempt to call the agent function that this callback refers to.\n * @param agent The agent.\n */\n callAgentFunction = (agent: Agent) => {\n // Attempt to get the invoker for the callback function.\n const callbackFuncInvoker = Lookup.getFuncInvoker(agent, this.getFunctionName());\n\n // The callback function should be defined.\n if (callbackFuncInvoker === null) {\n throw new Error(\n `cannot call entry function '${this.getFunctionName()}' as is not defined on the agent and has not been registered`\n );\n }\n\n // Call the callback function.\n callbackFuncInvoker(this.args);\n };\n}\n", "import Callback from \"./Callback\";\nimport Lookup from \"../../Lookup\";\nimport { Agent } from \"../../Agent\";\n\n/**\n * A STEP callback which defines an agent function to call when the associated node is updated.\n */\nexport default class Step extends Callback {\n /**\n * @param functionName The name of the agent function to call.\n * @param args The array of callback argument definitions.\n */\n constructor(functionName: string, args: any[]) {\n super(\"step\", args, functionName);\n }\n\n /**\n * Attempt to call the agent function that this callback refers to.\n * @param agent The agent.\n */\n callAgentFunction = (agent: Agent) => {\n // Attempt to get the invoker for the callback function.\n const callbackFuncInvoker = Lookup.getFuncInvoker(agent, this.getFunctionName());\n\n // The callback function should be defined.\n if (callbackFuncInvoker === null) {\n throw new Error(\n `cannot call step function '${this.getFunctionName()}' as is not defined on the agent and has not been registered`\n );\n }\n\n // Call the callback function.\n callbackFuncInvoker(this.args);\n };\n}\n", "import Callback from \"./Callback\";\nimport Lookup from \"../../Lookup\";\nimport { Agent } from \"../../Agent\";\n\n/**\n * An EXIT callback which defines an agent function to call when the associated node is updated and moves to a finished state or is aborted.\n */\nexport default class Exit extends Callback {\n /**\n * @param functionName The name of the agent function to call.\n * @param args The array of callback argument definitions.\n */\n constructor(functionName: string, args: any[]) {\n super(\"exit\", args, functionName);\n }\n\n /**\n * Attempt to call the agent function that this callback refers to.\n * @param agent The agent.\n * @param isSuccess Whether the decorated node was left with a success state.\n * @param isAborted Whether the decorated node was aborted.\n */\n callAgentFunction = (agent: Agent, isSuccess: boolean, isAborted: boolean) => {\n // Attempt to get the invoker for the callback function.\n const callbackFuncInvoker = Lookup.getFuncInvoker(agent, this.getFunctionName());\n\n // The callback function should be defined.\n if (callbackFuncInvoker === null) {\n throw new Error(\n `cannot call exit function '${this.getFunctionName()}' as is not defined on the agent and has not been registered`\n );\n }\n\n // Call the callback function\n callbackFuncInvoker([{ value: { succeeded: isSuccess, aborted: isAborted } }, ...this.args]);\n };\n}\n", "import { AnyNodeDefinition, RootNodeDefinition } from \"./BehaviourTreeDefinition\";\nimport GuardPath, { GuardPathPart } from \"./attributes/guards/GuardPath\";\nimport { validateBranchSubtreeLinks } from \"./BehaviourTreeDefinitionValidator\";\nimport { isInteger } from \"./BehaviourTreeDefinitionUtilities\";\nimport Node from \"./nodes/Node\";\nimport Composite from \"./nodes/composite/Composite\";\nimport Decorator from \"./nodes/decorator/Decorator\";\nimport Parallel from \"./nodes/composite/Parallel\";\nimport Selector from \"./nodes/composite/Selector\";\nimport Sequence from \"./nodes/composite/Sequence\";\nimport Lotto from \"./nodes/composite/Lotto\";\nimport Fail from \"./nodes/decorator/Fail\";\nimport Flip from \"./nodes/decorator/Flip\";\nimport Repeat from \"./nodes/decorator/Repeat\";\nimport Retry from \"./nodes/decorator/Retry\";\nimport Root from \"./nodes/decorator/Root\";\nimport Succeed from \"./nodes/decorator/Succeed\";\nimport Action from \"./nodes/leaf/Action\";\nimport Condition from \"./nodes/leaf/Condition\";\nimport Wait from \"./nodes/leaf/Wait\";\nimport Lookup from \"./Lookup\";\nimport Attribute from \"./attributes/Attribute\";\nimport While from \"./attributes/guards/While\";\nimport Until from \"./attributes/guards/Until\";\nimport Entry from \"./attributes/callbacks/Entry\";\nimport Step from \"./attributes/callbacks/Step\";\nimport Exit from \"./attributes/callbacks/Exit\";\n\n/**\n * A type representing any node instance in a behaviour tree.\n */\ntype AnyNode =\n | Root\n | Action\n | Condition\n | Wait\n | Sequence\n | Selector\n | Lotto\n | Parallel\n | Repeat\n | Retry\n | Flip\n | Succeed\n | Fail;\n\n/**\n * A type defining a mapping of root node identifiers to root node definitions.\n */\ntype RootNodeDefinitionMap = { [key: string | symbol]: RootNodeDefinition };\n\n/**\n * A symbol to use as the main root key in any root node mappings.\n */\nconst MAIN_ROOT_NODE_KEY = Symbol(\"__root__\");\n\n/**\n * Build and populate the root nodes based on the provided definition, assuming that the definition has been validated.\n * @param definition The root node definitions.\n * @returns The built and populated root node definitions.\n */\nexport default function buildRootNode(definition: RootNodeDefinition[]): Root {\n // Create a mapping of root node identifers to root node definitions, including globally registered subtree root node definitions.\n const rootNodeDefinitionMap = createRootNodeDefinitionMap(definition);\n\n // Now that we have all of our root node definitons (those part of the tree definition and those globally\n // registered) we should validate the definition. This will also double-check that we dont have any circular\n // dependencies in our branch -> subtree references and that we have no broken branch -> subtree links.\n validateBranchSubtreeLinks(definition, true);\n\n // Create our populated tree of node instances, starting with our main root node.\n const rootNode = nodeFactory(rootNodeDefinitionMap[MAIN_ROOT_NODE_KEY], rootNodeDefinitionMap) as Root;\n\n // Set a guard path on every leaf of the tree to evaluate as part of each update.\n applyLeafNodeGuardPaths(rootNode);\n\n // We only need to return the main root node.\n return rootNode;\n}\n\n/**\n * A factory function which creates a node instance based on the specified definition.\n * @param definition The node definition.\n * @param rootNodeDefinitionMap The mapping of root node identifers to root node definitions, including globally registered subtree root node definitions.\n * @returns A node instance based on the specified definition.\n */\nfunction nodeFactory(definition: AnyNodeDefinition, rootNodeDefinitionMap: RootNodeDefinitionMap): AnyNode {\n // Get the attributes for the node.\n const attributes = nodeAttributesFactory(definition);\n\n // Create the node instance based on the definition type.\n switch (definition.type) {\n case \"root\":\n return new Root(attributes, nodeFactory(definition.child, rootNodeDefinitionMap));\n\n case \"repeat\":\n let iterations: number | null = null;\n let iterationsMin: number | null = null;\n let iterationsMax: number | null = null;\n\n if (Array.isArray(definition.iterations)) {\n iterationsMin = definition.iterations[0];\n iterationsMax = definition.iterations[1];\n } else if (isInteger(definition.iterations)) {\n iterations = definition.iterations!;\n }\n\n return new Repeat(\n attributes,\n iterations,\n iterationsMin,\n iterationsMax,\n nodeFactory(definition.child, rootNodeDefinitionMap)\n );\n\n case \"retry\":\n let attempts: number | null = null;\n let attemptsMin: number | null = null;\n let attemptsMax: number | null = null;\n\n if (Array.isArray(definition.attempts)) {\n attemptsMin = definition.attempts[0];\n attemptsMax = definition.attempts[1];\n } else if (isInteger(definition.attempts)) {\n attempts = definition.attempts!;\n }\n\n return new Retry(\n attributes,\n attempts,\n attemptsMin,\n attemptsMax,\n nodeFactory(definition.child, rootNodeDefinitionMap)\n );\n\n case \"flip\":\n return new Flip(attributes, nodeFactory(definition.child, rootNodeDefinitionMap));\n\n case \"succeed\":\n return new Succeed(attributes, nodeFactory(definition.child, rootNodeDefinitionMap));\n\n case \"fail\":\n return new Fail(attributes, nodeFactory(definition.child, rootNodeDefinitionMap));\n\n case \"sequence\":\n return new Sequence(\n attributes,\n definition.children.map((child) => nodeFactory(child, rootNodeDefinitionMap))\n );\n\n case \"selector\":\n return new Selector(\n attributes,\n definition.children.map((child) => nodeFactory(child, rootNodeDefinitionMap))\n );\n\n case \"parallel\":\n return new Parallel(\n attributes,\n definition.children.map((child) => nodeFactory(child, rootNodeDefinitionMap))\n );\n\n case \"lotto\":\n return new Lotto(\n attributes,\n definition.weights,\n definition.children.map((child) => nodeFactory(child, rootNodeDefinitionMap))\n );\n\n case \"branch\":\n return nodeFactory(rootNodeDefinitionMap[definition.ref].child, rootNodeDefinitionMap);\n\n case \"action\":\n return new Action(attributes, definition.call, definition.args || []);\n\n case \"condition\":\n return new Condition(attributes, definition.call, definition.args || []);\n\n case \"wait\":\n let duration: number | null = null;\n let durationMin: number | null = null;\n let durationMax: number | null = null;\n\n if (Array.isArray(definition.duration)) {\n durationMin = definition.duration[0];\n durationMax = definition.duration[1];\n } else if (isInteger(definition.duration)) {\n duration = definition.duration!;\n }\n\n return new Wait(attributes, duration, durationMin, durationMax);\n }\n}\n\n/**\n * Creates an array of node attribute instances based on the specified node definition.\n * @param definition The node definition.\n * @returns An array of node attribute instances based on the specified node definition.\n */\nfunction nodeAttributesFactory(definition: AnyNodeDefinition): Attribute[] {\n const attributes: Attribute[] = [];\n\n if (definition.while) {\n attributes.push(new While(definition.while.call, definition.while.args ?? []));\n }\n\n if (definition.until) {\n attributes.push(new Until(definition.until.call, definition.until.args ?? []));\n }\n\n if (definition.entry) {\n attributes.push(new Entry(definition.entry.call, definition.entry.args ?? []));\n }\n\n if (definition.step) {\n attributes.push(new Step(definition.step.call, definition.step.args ?? []));\n }\n\n if (definition.exit) {\n attributes.push(new Exit(definition.exit.call, definition.exit.args ?? []));\n }\n\n return attributes;\n}\n\n/**\n * Creates a mapping of root node identifers to root node definitions, mixing in globally registered subtree root node definitions.\n * @param definition The root node definitions.\n * @returns A mapping of root node identifers to root node definitions, including globally registered subtree root node definitions.\n */\nfunction createRootNodeDefinitionMap(definition: RootNodeDefinition[]): RootNodeDefinitionMap {\n // Create a mapping of root node identifers to root node definitions.\n const rootNodeMap: RootNodeDefinitionMap = {};\n\n // Add in any registered subtree root node definitions.\n for (const [name, rootNodeDefinition] of Object.entries(Lookup.getSubtrees())) {\n // The name used when registering the subtree will be used as the root node identifier.\n rootNodeMap[name] = { ...rootNodeDefinition, id: name };\n }\n\n // Populate the map with the root node definitions that were included with the tree definition.\n // We do this after adding any registered subtrees as we want these to take presedence.\n for (const rootNodeDefinition of definition) {\n rootNodeMap[rootNodeDefinition.id ?? MAIN_ROOT_NODE_KEY] = rootNodeDefinition;\n }\n\n return rootNodeMap;\n}\n\n/**\n * Applies a guard path to every leaf of the tree to evaluate as part of each update.\n * @param root The main root tree node.\n */\nfunction applyLeafNodeGuardPaths(root: Root) {\n const nodePaths: Node[][] = [];\n\n const findLeafNodes = (path: Node[], node: Node) => {\n // Add the current node to the path.\n path = path.concat(node);\n\n // Check whether the current node is a leaf node.\n if (node.isLeafNode()) {\n nodePaths.push(path);\n } else {\n (node as Composite | Decorator).getChildren().forEach((child) => findLeafNodes(path, child));\n }\n };\n\n // Find all leaf node paths, starting from the root.\n findLeafNodes([], root);\n\n nodePaths.forEach((path) => {\n // Each node in the current path will have to be assigned a guard path, working from the root outwards.\n for (let depth = 0; depth < path.length; depth++) {\n // Get the node in the path at the current depth.\n const currentNode = path[depth];\n\n // The node may already have been assigned a guard path, if so just skip it.\n if (currentNode.hasGuardPath()) {\n continue;\n }\n\n // Create the guard path for the current node.\n const guardPath = new GuardPath(\n path\n .slice(0, depth + 1)\n .map((node) => ({ node, guards: node.getGuardAttributes() }))\n .filter((details) => details.guards.length > 0)\n );\n\n // Assign the guard path to the current node.\n currentNode.setGuardPath(guardPath);\n }\n });\n}\n", "import State, { AnyState } from \"./State\";\nimport Lookup from \"./Lookup\";\nimport Node from \"./nodes/Node\";\nimport Root from \"./nodes/decorator/Root\";\nimport Composite from \"./nodes/composite/Composite\";\nimport Decorator from \"./nodes/decorator/Decorator\";\nimport { Agent, GlobalFunction } from \"./Agent\";\nimport { CallbackAttributeDetails } from \"./attributes/callbacks/Callback\";\nimport { GuardAttributeDetails } from \"./attributes/guards/Guard\";\nimport { BehaviourTreeOptions } from \"./BehaviourTreeOptions\";\nimport { convertMDSLToJSON } from \"./mdsl/MDSLDefinitionParser\";\nimport { RootNodeDefinition } from \"./BehaviourTreeDefinition\";\nimport { validateJSONDefinition } from \"./BehaviourTreeDefinitionValidator\";\nimport buildRootNode from \"./BehaviourTreeBuilder\";\nimport { isNullOrUndefined } from \"./BehaviourTreeDefinitionUtilities\";\n\n// Purely for outside inspection of the tree.\nexport type FlattenedTreeNode = {\n id: string;\n type: string;\n caption: string;\n state: AnyState;\n guards: GuardAttributeDetails[];\n callbacks: CallbackAttributeDetails[];\n args: any[];\n parentId: string | null;\n};\n\n/**\n * A representation of a behaviour tree.\n */\nexport class BehaviourTree {\n /**\n * The main root tree node.\n */\n public readonly rootNode: Root;\n\n /**\n * Creates a new instance of the BehaviourTree class.\n * @param definition The behaviour tree definition.\n * @param agent The agent instance that this behaviour tree is modelling behaviour for.\n * @param options The behaviour tree options object.\n */\n constructor(\n definition: string | RootNodeDefinition | RootNodeDefinition[],\n private agent: Agent,\n private options: BehaviourTreeOptions = {}\n ) {\n // The tree definition must be defined.\n if (isNullOrUndefined(definition)) {\n throw new Error(\"tree definition not defined\");\n }\n\n // The agent must be defined and not null.\n if (typeof agent !== \"object\" || agent === null) {\n throw new Error(\"the agent must be an object and not null\");\n }\n\n try {\n // Parse the behaviour tree definition, create the populated tree of behaviour tree nodes, and get the root.\n this.rootNode = this._createRootNode(definition);\n } catch (exception) {\n // There was an issue in trying build and populate the behaviour tree.\n throw new Error(`error building tree: ${(exception as Error).message}`);\n }\n }\n\n /**\n * Gets whether the tree is in the RUNNING state.\n * @returns true if the tree is in the RUNNING state, otherwise false.\n */\n isRunning() {\n return this.rootNode.getState() === State.RUNNING;\n }\n\n /**\n * Gets the current tree state of SUCCEEDED, FAILED, READY or RUNNING.\n * @returns The current tree state.\n */\n getState() {\n return this.rootNode.getState();\n }\n\n /**\n * Step the tree.\n * 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.\n * 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\n * 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.\n *\n * 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.\n */\n step() {\n // If the root node has already been stepped to completion then we need to reset it.\n if (this.rootNode.getState() === State.SUCCEEDED || this.rootNode.getState() === State.FAILED) {\n this.rootNode.reset();\n }\n\n try {\n this.rootNode.update(this.agent, this.options);\n } catch (exception) {\n throw new Error(`error stepping tree: ${(exception as Error).message}`);\n }\n }\n\n /**\n * Resets the tree from the root node outwards to each nested node, giving each a state of READY.\n */\n reset() {\n this.rootNode.reset();\n }\n\n /**\n * Gets the flattened details of every node in the tree.\n * @returns The flattened details of every node in the tree.\n */\n getFlattenedNodeDetails(): FlattenedTreeNode[] {\n // Create an empty flattened array of tree nodes.\n const flattenedTreeNodes: FlattenedTreeNode[] = [];\n\n /**\n * Helper function to process a node instance and push details into the flattened tree nodes array.\n * @param node The current node.\n * @param parentUid The UID of the node parent, or null if the node is the main root node.\n */\n const processNode = (node: Node, parentUid: string | null) => {\n // Get the guard and callback attribute details for this node.\n const guards = node\n .getAttributes()\n .filter((attribute) => attribute.isGuard())\n .map((attribute) => attribute.getDetails()) as GuardAttributeDetails[];\n const callbacks = node\n .getAttributes()\n .filter((attribute) => !attribute.isGuard())\n .map((attribute) => attribute.getDetails()) as CallbackAttributeDetails[];\n\n // Push the current node into the flattened nodes array.\n flattenedTreeNodes.push({\n id: node.getUid(),\n type: node.getType(),\n caption: node.getName(),\n state: node.getState(),\n guards,\n callbacks,\n args: node.getArguments(),\n parentId: parentUid\n });\n\n // Process each of the nodes children if it is not a leaf node.\n if (!node.isLeafNode()) {\n (node as Composite | Decorator)\n .getChildren()\n .forEach((child) => processNode(child, (node as Composite | Decorator).getUid()));\n }\n };\n\n // Convert the nested node structure into a flattened array of node details.\n processNode(this.rootNode, null);\n\n return flattenedTreeNodes;\n }\n\n /**\n * Registers the action/condition/guard/callback function or subtree with the given name.\n * @param name The name of the function or subtree to register.\n * @param value The function or subtree definition to register.\n */\n static register(name: string, value: GlobalFunction | string | RootNodeDefinition) {\n // Are we going to register a action/condition/guard/callback function?\n if (typeof value === \"function\") {\n Lookup.setFunc(name, value);\n return;\n }\n\n // We are not registering an action/condition/guard/callback function, so we must be registering a subtree.\n if (typeof value === \"string\") {\n let rootNodeDefinitions: RootNodeDefinition[];\n\n // We will assume that any string passed in will be a mdsl definition.\n try {\n rootNodeDefinitions = convertMDSLToJSON(value);\n } catch (exception) {\n throw new Error(`error registering definition, invalid MDSL: ${(exception as Error).message}`);\n }\n\n // This function should only ever be called with a definition containing a single unnamed root node.\n if (rootNodeDefinitions.length != 1 || rootNodeDefinitions[0].id !== null) {\n throw new Error(\"error registering definition: expected a single unnamed root node\");\n }\n\n try {\n // We should validate the subtree as we don't want invalid subtrees available via the lookup.\n const { succeeded, errorMessage } = validateJSONDefinition(rootNodeDefinitions[0]);\n\n // Did our validation fail without error?\n if (!succeeded) {\n throw new Error(errorMessage);\n }\n } catch (exception) {\n throw new Error(`error registering definition: ${(exception as Error).message}`);\n }\n\n // Everything seems hunky-dory, register the subtree.\n Lookup.setSubtree(name, rootNodeDefinitions[0]);\n } else if (typeof value === \"object\" && !Array.isArray(value)) {\n // We will assume that any object passed in is a root node definition.\n\n try {\n // We should validate the subtree as we don't want invalid subtrees available via the lookup.\n const { succeeded, errorMessage } = validateJSONDefinition(value);\n\n // Did our validation fail without error?\n if (!succeeded) {\n throw new Error(errorMessage);\n }\n } catch (exception) {\n throw new Error(`error registering definition: ${(exception as Error).message}`);\n }\n\n // Everything seems hunky-dory, register the subtree.\n Lookup.setSubtree(name, value);\n } else {\n throw new Error(\"unexpected value, expected string mdsl definition, root node json definition or function\");\n }\n }\n\n /**\n * Unregisters the registered action/condition/guard/callback function or subtree with the given name.\n * @param name The name of the registered action/condition/guard/callback function or subtree to unregister.\n */\n static unregister(name: string): void {\n Lookup.remove(name);\n }\n\n /**\n * Unregister all registered action/condition/guard/callback functions and subtrees.\n */\n static unregisterAll(): void {\n Lookup.empty();\n }\n\n /**\n * Parses a behaviour tree definition and creates a tree of behaviour tree nodes populated at a root.\n * @param {string | RootNodeDefinition | RootNodeDefinition[]} definition The behaviour tree definition.\n * @returns The root behaviour tree node.\n */\n private _createRootNode(definition: string | RootNodeDefinition | RootNodeDefinition[]): Root {\n let resolvedDefinition: RootNodeDefinition | RootNodeDefinition[];\n\n // If the definition is a string then we will assume that it is an mdsl string which needs to be converted to a JSON definition.\n if (typeof definition === \"string\") {\n try {\n resolvedDefinition = convertMDSLToJSON(definition);\n } catch (exception) {\n throw new Error(`invalid mdsl definition: ${(exception as Error).message}`);\n }\n } else {\n // The definition is not a string, so we should assume that it is already a JSON definition.\n resolvedDefinition = definition;\n }\n\n // Build and populate the root node.\n return buildRootNode(Array.isArray(resolvedDefinition) ? resolvedDefinition : [resolvedDefinition]);\n }\n}\n"], + "mappings": "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", "names": ["Participant", "isNullOrUndefined", "Lotto", "createLotto", "State", "createLotto"] } diff --git a/dist/index.d.ts b/dist/index.d.ts index f58269e..c5ce7d0 100644 --- a/dist/index.d.ts +++ b/dist/index.d.ts @@ -2,5 +2,6 @@ import State from "./State"; import { validateDefinition } from "./BehaviourTreeDefinitionValidator"; import { convertMDSLToJSON } from "./mdsl/MDSLDefinitionParser"; import { BehaviourTree, FlattenedTreeNode } from "./BehaviourTree"; +import { BehaviourTreeOptions } from "./BehaviourTreeOptions"; export { BehaviourTree, State, convertMDSLToJSON, validateDefinition }; -export type { FlattenedTreeNode }; +export type { FlattenedTreeNode, BehaviourTreeOptions }; diff --git a/dist/index.js b/dist/index.js index 11ca653..a4d2910 100644 --- a/dist/index.js +++ b/dist/index.js @@ -2132,11 +2132,11 @@ var BehaviourTree = class { constructor(definition, agent, options = {}) { this.agent = agent; this.options = options; - if (!definition) { - throw new Error("the tree definition must be a string ro"); + if (isNullOrUndefined(definition)) { + throw new Error("tree definition not defined"); } if (typeof agent !== "object" || agent === null) { - throw new Error("the agent must be defined and not null"); + throw new Error("the agent must be an object and not null"); } try { this.rootNode = this._createRootNode(definition); diff --git a/dist/index.js.map b/dist/index.js.map index be14773..f1cfc8e 100644 --- a/dist/index.js.map +++ b/dist/index.js.map @@ -1,7 +1,7 @@ { "version": 3, "sources": ["../node_modules/lotto-draw/dist/Participant.js", "../node_modules/lotto-draw/dist/Utilities.js", "../node_modules/lotto-draw/dist/Lotto.js", "../node_modules/lotto-draw/dist/createLotto.js", "../node_modules/lotto-draw/dist/index.js", "../src/index.ts", "../src/State.ts", "../src/BehaviourTreeDefinitionUtilities.ts", "../src/mdsl/MDSLUtilities.ts", "../src/mdsl/MDSLNodeArgumentParser.ts", "../src/mdsl/MDSLNodeAttributeParser.ts", "../src/mdsl/MDSLDefinitionParser.ts", "../src/BehaviourTreeDefinitionValidator.ts", "../src/Lookup.ts", "../src/attributes/guards/GuardUnsatisifedException.ts", "../src/attributes/guards/GuardPath.ts", "../src/nodes/Node.ts", "../src/nodes/composite/Composite.ts", "../src/nodes/composite/Parallel.ts", "../src/nodes/composite/Selector.ts", "../src/nodes/composite/Sequence.ts", "../src/nodes/composite/Lotto.ts", "../src/nodes/decorator/Decorator.ts", "../src/nodes/decorator/Fail.ts", "../src/nodes/decorator/Flip.ts", "../src/nodes/decorator/Repeat.ts", "../src/nodes/decorator/Retry.ts", "../src/nodes/decorator/Root.ts", "../src/nodes/decorator/Succeed.ts", "../src/nodes/leaf/Leaf.ts", "../src/nodes/leaf/Action.ts", "../src/nodes/leaf/Condition.ts", "../src/nodes/leaf/Wait.ts", "../src/attributes/Attribute.ts", "../src/attributes/guards/Guard.ts", "../src/attributes/guards/While.ts", "../src/attributes/guards/Until.ts", "../src/attributes/callbacks/Callback.ts", "../src/attributes/callbacks/Entry.ts", "../src/attributes/callbacks/Step.ts", "../src/attributes/callbacks/Exit.ts", "../src/BehaviourTreeBuilder.ts", "../src/BehaviourTree.ts"], - "sourcesContent": ["\"use strict\";\r\nObject.defineProperty(exports, \"__esModule\", { value: true });\r\nexports.Participant = void 0;\r\n/**\r\n * A participant that holds a number of tickets.\r\n */\r\nvar Participant = /** @class */ (function () {\r\n /**\r\n * Creates an instance of the Participant class.\r\n * @param participant The actual participant.\r\n * @param tickets The number of tickets held by the participant.\r\n */\r\n function Participant(participant, tickets) {\r\n if (tickets === void 0) { tickets = 1; }\r\n this._participant = participant;\r\n this._tickets = tickets;\r\n }\r\n Object.defineProperty(Participant.prototype, \"participant\", {\r\n /** Gets the actual participant. */\r\n get: function () {\r\n return this._participant;\r\n },\r\n enumerable: false,\r\n configurable: true\r\n });\r\n Object.defineProperty(Participant.prototype, \"tickets\", {\r\n /** Gets or sets the number of tickets held by the participant. */\r\n get: function () {\r\n return this._tickets;\r\n },\r\n set: function (value) {\r\n this._tickets = value;\r\n },\r\n enumerable: false,\r\n configurable: true\r\n });\r\n return Participant;\r\n}());\r\nexports.Participant = Participant;\r\n", "\"use strict\";\r\nObject.defineProperty(exports, \"__esModule\", { value: true });\r\nexports.isNaturalNumber = exports.isNullOrUndefined = void 0;\r\n/**\r\n * Gets whether the value provided is null or undefined.\r\n * @param value The value to check.\r\n * @returns Whether the value provided is null or undefined.\r\n */\r\nfunction isNullOrUndefined(value) {\r\n return value === null || value === undefined;\r\n}\r\nexports.isNullOrUndefined = isNullOrUndefined;\r\n/**\r\n * Gets whether the value provided is a natural number.\r\n * @param value The value to check.\r\n * @returns Whether the value provided is a natural number.\r\n */\r\nfunction isNaturalNumber(value) {\r\n return typeof value === \"number\" && value >= 1 && Math.floor(value) === value;\r\n}\r\nexports.isNaturalNumber = isNaturalNumber;\r\n", "\"use strict\";\r\nObject.defineProperty(exports, \"__esModule\", { value: true });\r\nexports.Lotto = void 0;\r\nvar Participant_1 = require(\"./Participant\");\r\nvar Utilities_1 = require(\"./Utilities\");\r\n/**\r\n * Represents a lotto consisting of a number of pickable ticket-holding participants.\r\n */\r\nvar Lotto = /** @class */ (function () {\r\n /**\r\n * Creates a new instance of Lotto.\r\n * @param customRandom The custom RNG to use in place of Math.random().\r\n */\r\n function Lotto(customRandom) {\r\n /** The array of participants that are holding tickets in the lotto. */\r\n this._participants = [];\r\n this._customRandom = customRandom;\r\n }\r\n /**\r\n * Adds a participant with the specified number of tickets, or adds to the participant ticket count if the participant already holds tickets.\r\n * @param participant The participant to add or to increase the ticket count for if they already hold tickets.\r\n * @param tickets The number of tickets, defaults to 1.\r\n * @returns The Lotto instance.\r\n */\r\n Lotto.prototype.add = function (participant, tickets) {\r\n if (tickets === void 0) { tickets = 1; }\r\n // Check that we have a valid ticket count.\r\n if (!(0, Utilities_1.isNaturalNumber)(tickets)) {\r\n throw new Error(\"tickets value must be a natural number\");\r\n }\r\n // Check whether this participant has already been added.\r\n var existingParticipant = this._participants.find(function (part) { return part.participant === participant; });\r\n if (existingParticipant) {\r\n // The participant has already been added to the lotto so just add to their ticket count.\r\n existingParticipant.tickets += tickets;\r\n }\r\n else {\r\n // The participant is not part of the lotto so we should add them.\r\n this._participants.push(new Participant_1.Participant(participant, tickets));\r\n }\r\n return this;\r\n };\r\n /**\r\n * Removes the specified number of tickets for the given participant from the draw, or all tickets if a ticket number is not defined.\r\n * @param participant The participant to remove tickets for.\r\n * @param tickets The number of tickets to remove, or undefined if all tickets are to be removed.\r\n * @returns The Lotto instance.\r\n */\r\n Lotto.prototype.remove = function (participant, tickets) {\r\n // Attempt to get the existing participant.\r\n var existingParticipant = this._participants.find(function (part) { return part.participant === participant; });\r\n // There is nothing to do if the specified participant isn't even part of the lotto.\r\n if (!existingParticipant) {\r\n return this;\r\n }\r\n // Check whether a tickets value was given.\r\n if (tickets !== undefined) {\r\n // Check that we have a valid ticket count.\r\n if (!(0, Utilities_1.isNaturalNumber)(tickets)) {\r\n throw new Error(\"tickets value must be a natural number\");\r\n }\r\n existingParticipant.tickets -= tickets;\r\n // If the participant no longer holds any tickets then they should be removed.\r\n if (existingParticipant.tickets < 1) {\r\n this._participants = this._participants.filter(function (part) { return part !== existingParticipant; });\r\n }\r\n }\r\n else {\r\n // We are removing all tickets for the participant so just remove them from the lotto.\r\n this._participants = this._participants.filter(function (part) { return part !== existingParticipant; });\r\n }\r\n return this;\r\n };\r\n /**\r\n * Draw a winning ticket and return the participant that holds the ticket.\r\n * @param options The draw options.\r\n * @returns The participant that holds the winning ticket.\r\n */\r\n Lotto.prototype.draw = function (options) {\r\n if (options === void 0) { options = {}; }\r\n // If we have no participants then just return null.\r\n if (this._participants.length === 0) {\r\n return null;\r\n }\r\n var redrawable = (0, Utilities_1.isNullOrUndefined)(options.redrawable) ? true : options.redrawable;\r\n var pickable = [];\r\n this._participants.forEach(function (_a) {\r\n var participant = _a.participant, tickets = _a.tickets;\r\n for (var ticketCount = 0; ticketCount < tickets; ticketCount++) {\r\n pickable.push(participant);\r\n }\r\n });\r\n var random;\r\n // We need a random floating-point number between 0 (inclusive) and 1 to scale up to pick our winner.\r\n // If a custom random function exists then we should use that or fall back to Math.random().\r\n if (this._customRandom) {\r\n // Call our custom random function to get a random floating-point number.\r\n random = this._customRandom();\r\n // Verify that the result of calling our custom random function is a number between 0 (inclusive) and 1.\r\n if (typeof random !== \"number\" || random < 0 || random >= 1) {\r\n throw new Error(\"the 'random' function provided did not return a number between 0 (inclusive) and 1\");\r\n }\r\n }\r\n else {\r\n // No custom random function was defined so just use good ol' Math.random().\r\n random = Math.random();\r\n }\r\n // Pick a winning participant.\r\n var winner = pickable[Math.floor(random * pickable.length)];\r\n // If the ticket isn't redrawable then we should remove a ticket from the winning participants ticket count.\r\n if (!redrawable) {\r\n this.remove(winner, 1);\r\n }\r\n // Return the winning participant.\r\n return winner;\r\n };\r\n /**\r\n * Draws multiple winning tickets and return an array of the participants that hold the winning tickets.\r\n * @param tickets The number of winning tickets to draw.\r\n * @param options The draw multiple options.\r\n * @returns An array of the participants that hold the winning tickets.\r\n */\r\n Lotto.prototype.drawMultiple = function (tickets, options) {\r\n if (options === void 0) { options = {}; }\r\n var uniqueResults = (0, Utilities_1.isNullOrUndefined)(options.unique) ? false : options.unique;\r\n // Handle cases where the user has asked for zero tickets (no idea why they would do this be we should trust them).\r\n if (tickets === 0) {\r\n return [];\r\n }\r\n // Now that we know out tickets value is not zero we should check that it is a valid natural number.\r\n if (!(0, Utilities_1.isNaturalNumber)(tickets)) {\r\n throw new Error(\"tickets value must be a natural number\");\r\n }\r\n var result = [];\r\n // Keep drawing tickets until we either reach the number of required tickets or we simply run out of tickets to draw.\r\n // We can run out of tickets to draw if 'options.redrawable' is explicity 'false' or we just had no participants when 'drawMultiple' was called.\r\n while (result.length < tickets && this._participants.length > 0) {\r\n result.push(this.draw(options));\r\n }\r\n // If the 'unique' draw option is set then we need to remove duplicates from the result list.\r\n if (uniqueResults) {\r\n // Create an array to store our unique results.\r\n var unique = [];\r\n // Iterate over all of our participants (with potential duplicates) and populate our array of unique values.\r\n for (var _i = 0, result_1 = result; _i < result_1.length; _i++) {\r\n var participant = result_1[_i];\r\n if (unique.indexOf(participant) === -1) {\r\n unique.push(participant);\r\n }\r\n }\r\n result = unique;\r\n }\r\n return result;\r\n };\r\n return Lotto;\r\n}());\r\nexports.Lotto = Lotto;\r\n", "\"use strict\";\r\nObject.defineProperty(exports, \"__esModule\", { value: true });\r\nexports.createLotto = void 0;\r\nvar Lotto_1 = require(\"./Lotto\");\r\n/**\r\n * A function that creates and returns a Lotto instance.\r\n * @param participantsOrOptions An array of initial participants or options relating to the creation of a Lotto instance.\r\n * @returns A new Lotto instance.\r\n */\r\nfunction createLotto(participantsOrOptions) {\r\n // If no initial participants or lotto options were provided as an argument then we can just return a new lotto instance now.\r\n if (!participantsOrOptions) {\r\n return new Lotto_1.Lotto();\r\n }\r\n // Check whether we were provided with an array of initial participants or a lotto options object.\r\n if (Array.isArray(participantsOrOptions)) {\r\n // We are dealing with a pre-defined array of participants.\r\n var participants = participantsOrOptions;\r\n var lotto_1 = new Lotto_1.Lotto();\r\n // If the lotto participants have been defined upfront then we will need to add them all to our lotto instance now.\r\n participants.forEach(function (_a) {\r\n var participant = _a[0], tokens = _a[1];\r\n return lotto_1.add(participant, tokens);\r\n });\r\n // Return the Lotto instance.\r\n return lotto_1;\r\n }\r\n else {\r\n // We are dealing with some lotto options.\r\n var random = participantsOrOptions.random, participants = participantsOrOptions.participants;\r\n // Create a Lotto instance passing the custom RNG function to use in place of Math.random() (which could be undefined).\r\n var lotto_2 = new Lotto_1.Lotto(random);\r\n // If the lotto participants have been defined upfront as part of the options then we will need to add them all to our lotto instance now.\r\n if (participants) {\r\n participants.forEach(function (_a) {\r\n var participant = _a[0], tokens = _a[1];\r\n return lotto_2.add(participant, tokens);\r\n });\r\n }\r\n // Return the Lotto instance.\r\n return lotto_2;\r\n }\r\n}\r\nexports.createLotto = createLotto;\r\n", "\"use strict\";\r\nObject.defineProperty(exports, \"__esModule\", { value: true });\r\nvar createLotto_1 = require(\"./createLotto\");\r\nexports.default = createLotto_1.createLotto;\r\n", "import State from \"./State\";\nimport { validateDefinition } from \"./BehaviourTreeDefinitionValidator\";\nimport { convertMDSLToJSON } from \"./mdsl/MDSLDefinitionParser\";\nimport { BehaviourTree, FlattenedTreeNode } from \"./BehaviourTree\";\n\nexport { BehaviourTree, State, convertMDSLToJSON, validateDefinition };\nexport type { FlattenedTreeNode };\n", "/**\n * Enumeration of node state types.\n */\nexport enum State {\n READY = \"mistreevous.ready\",\n RUNNING = \"mistreevous.running\",\n SUCCEEDED = \"mistreevous.succeeded\",\n FAILED = \"mistreevous.failed\"\n}\n\nexport { State as default };\n\nexport type CompleteState = State.SUCCEEDED | State.FAILED;\nexport type AnyState = State.READY | State.RUNNING | CompleteState;\n", "import {\n NodeDefinition,\n RootNodeDefinition,\n DecoratorNodeDefinition,\n CompositeNodeDefinition,\n AnyNodeDefinition,\n BranchNodeDefinition\n} from \"./BehaviourTreeDefinition\";\n\n/**\n * A type guard function that returns true if the specified node satisfies the RootNodeDefinition type.\n * @param node The node.\n * @returns A value of true if the specified node satisfies the RootNodeDefinition type.\n */\nexport function isRootNode(node: NodeDefinition): node is RootNodeDefinition {\n return node.type === \"root\";\n}\n\n/**\n * A type guard function that returns true if the specified node satisfies the BranchNodeDefinition type.\n * @param node The node.\n * @returns A value of true if the specified node satisfies the BranchNodeDefinition type.\n */\nexport function isBranchNode(node: NodeDefinition): node is BranchNodeDefinition {\n return node.type === \"branch\";\n}\n\n/**\n * A type guard function that returns true if the specified node satisfies the NodeDefinition type.\n * @param node The node.\n * @returns A value of true if the specified node satisfies the NodeDefinition type.\n */\nexport function isLeafNode(node: NodeDefinition): node is NodeDefinition {\n return [\"branch\", \"action\", \"condition\", \"wait\"].includes(node.type);\n}\n\n/**\n * A type guard function that returns true if the specified node satisfies the DecoratorNodeDefinition type.\n * @param node The node.\n * @returns A value of true if the specified node satisfies the DecoratorNodeDefinition type.\n */\nexport function isDecoratorNode(node: NodeDefinition): node is DecoratorNodeDefinition {\n return [\"root\", \"repeat\", \"retry\", \"flip\", \"succeed\", \"fail\"].includes(node.type);\n}\n\n/**\n * A type guard function that returns true if the specified node satisfies the CompositeNodeDefinition type.\n * @param node The node.\n * @returns A value of true if the specified node satisfies the CompositeNodeDefinition type.\n */\nexport function isCompositeNode(node: NodeDefinition): node is CompositeNodeDefinition {\n return [\"sequence\", \"selector\", \"lotto\", \"parallel\"].includes(node.type);\n}\n\n/**\n * Flatten a node definition into an array of all of its nested node definitions.\n * @param nodeDefinition The node definition to flatten.\n * @returns An array of all of nested node definitions.\n */\nexport function flattenDefinition(nodeDefinition: AnyNodeDefinition): AnyNodeDefinition[] {\n const nodes: AnyNodeDefinition[] = [];\n\n const processNode = (currentNodeDefinition: AnyNodeDefinition) => {\n nodes.push(currentNodeDefinition);\n\n if (isCompositeNode(currentNodeDefinition)) {\n currentNodeDefinition.children.forEach(processNode);\n } else if (isDecoratorNode(currentNodeDefinition)) {\n processNode(currentNodeDefinition.child);\n }\n };\n\n processNode(nodeDefinition);\n\n return nodes;\n}\n\n/**\n * Determines whether the passed value is an integer.\n * @param value The value to check.\n * @returns Whether the passed value is an integer.\n */\nexport function isInteger(value: unknown): boolean {\n return typeof value === \"number\" && Math.floor(value) === value;\n}\n\n/**\n * Determines whether the passed value is null or undefined.\n * @param value The value to check.\n * @returns Whether the passed value is null or undefined.\n */\nexport function isNullOrUndefined(value: unknown): boolean {\n return typeof value === \"undefined\" || value === null;\n}\n", "/**\n * A type defining an object that holds a reference to substitued string literals parsed from the definition.\n */\nexport type StringLiteralPlaceholders = { [key: string]: string };\n\n/**\n * Pop the next raw token from the specified array of tokens and throw an error if it wasn't the expected one.\n * @param tokens The array of tokens.\n * @param expected An optional string or array or items, one of which must match the next popped token.\n * @returns The popped token.\n */\nexport function popAndCheck(tokens: string[], expected?: string | string[]): string {\n // Get and remove the next token.\n const popped = tokens.shift();\n\n // We were expecting another token but there aren't any.\n if (popped === undefined) {\n throw new Error(\"unexpected end of definition\");\n }\n\n // Do we have an expected token/tokens array?\n if (expected != undefined) {\n // Get an array of expected values, if the popped token matches any then we are all good.\n const expectedValues = typeof expected === \"string\" ? [expected] : expected;\n\n // Check whether the popped token matches at least one of our expected items.\n var tokenMatchesExpectation = expectedValues.some((item) => popped.toUpperCase() === item.toUpperCase());\n\n // Throw an error if the popped token didn't match any of our expected items.\n if (!tokenMatchesExpectation) {\n const expectationString = expectedValues.map((item) => \"'\" + item + \"'\").join(\" or \");\n throw new Error(\"unexpected token found. Expected \" + expectationString + \" but got '\" + popped + \"'\");\n }\n }\n\n // Return the popped token.\n return popped;\n}\n\n/**\n * Swaps out any node/attribute argument string literals with placeholders.\n * @param definition The definition.\n * @returns An object containing a mapping of placeholders to original string values as well as the processed definition string.\n */\nexport function substituteStringLiterals(definition: string): {\n placeholders: StringLiteralPlaceholders;\n processedDefinition: string;\n} {\n // Create an object to hold the mapping of placeholders to original string values.\n const placeholders: StringLiteralPlaceholders = {};\n\n // Replace any string literals wrapped with double quotes in our definition with placeholders to be processed later.\n const processedDefinition = definition.replace(/\\\"(\\\\.|[^\"\\\\])*\\\"/g, (match) => {\n var strippedMatch = match.substring(1, match.length - 1);\n var placeholder = Object.keys(placeholders).find((key) => placeholders[key] === strippedMatch);\n\n // If we have no existing string literal match then create a new placeholder.\n if (!placeholder) {\n placeholder = `@@${Object.keys(placeholders).length}@@`;\n placeholders[placeholder] = strippedMatch;\n }\n\n return placeholder;\n });\n\n return { placeholders, processedDefinition };\n}\n\n/**\n * Parse the tree definition into an array of raw tokens.\n * @param definition The definition.\n * @returns An array of tokens parsed from the definition.\n */\nexport function parseTokensFromDefinition(definition: string): string[] {\n // Add some space around various important characters so that they can be plucked out easier as individual tokens.\n definition = definition.replace(/\\(/g, \" ( \");\n definition = definition.replace(/\\)/g, \" ) \");\n definition = definition.replace(/\\{/g, \" { \");\n definition = definition.replace(/\\}/g, \" } \");\n definition = definition.replace(/\\]/g, \" ] \");\n definition = definition.replace(/\\[/g, \" [ \");\n definition = definition.replace(/\\,/g, \" , \");\n\n // Split the definition into raw token form and return it.\n return definition.replace(/\\s+/g, \" \").trim().split(\" \");\n}\n", "import { StringLiteralPlaceholders, popAndCheck } from \"./MDSLUtilities\";\n\n/**\n * A type representing any node function argument.\n */\ntype Argument = {\n /**\n * The argument value.\n */\n value: T;\n /**\n * The argument type, used for validation.\n */\n type: string;\n};\n\ntype NullArgument = Argument & {\n type: \"null\";\n};\n\ntype BooleanArgument = Argument & {\n type: \"boolean\";\n};\n\ntype NumberArgument = Argument & {\n type: \"number\";\n /**\n * A flag defining whether the number argument value is a valid integer. (used for validation)\n */\n isInteger: boolean;\n};\n\ntype StringPlaceholderArgument = Argument & {\n type: \"string\";\n};\n\ntype IdentifierArgument = Argument & {\n type: \"identifier\";\n};\n\n/**\n * A type representing a reference to any node function argument.\n */\ntype AnyArgument = NullArgument | BooleanArgument | NumberArgument | StringPlaceholderArgument | IdentifierArgument;\n\n/**\n * Parse an array of argument definitions from the specified tokens array.\n * @param tokens The array tokens to parse the argument definitions from.\n * @param stringArgumentPlaceholders The mapping of string literal node argument placeholders to original values.\n * @param argumentValidator The argument validator function.\n * @param validationFailedMessage The exception message to throw if argument validation fails.\n * @returns An array of argument definitions parsed from the specified tokens array.\n */\nexport function parseArgumentTokens(\n tokens: string[],\n stringArgumentPlaceholders: StringLiteralPlaceholders\n): AnyArgument[] {\n const argumentList: AnyArgument[] = [];\n\n // If the next token is not a '[' or '(' then we have no arguments to parse.\n if (![\"[\", \"(\"].includes(tokens[0])) {\n return argumentList;\n }\n\n // Any lists of arguments will always be wrapped in '[]' for node arguments or '()' for attribute arguments.\n // We are looking for a '[' or '(' opener that wraps the argument tokens and the relevant closer.\n const closingToken = popAndCheck(tokens, [\"[\", \"(\"]) === \"[\" ? \"]\" : \")\";\n\n const argumentListTokens: string[] = [];\n\n // Grab all tokens between the '[' and ']' or '(' and ')'.\n while (tokens.length && tokens[0] !== closingToken) {\n // The next token is part of our arguments list.\n argumentListTokens.push(tokens.shift()!);\n }\n\n // Validate the order of the argument tokens. Each token must either be a ',' or a single argument that satisfies the validator.\n argumentListTokens.forEach((token, index) => {\n // Get whether this token should be an actual argument.\n const shouldBeArgumentToken = !(index & 1);\n\n // If the current token should be an actual argument then validate it, otherwise it should be a ',' token.\n if (shouldBeArgumentToken) {\n // Get the argument definition.\n const argumentDefinition = getArgumentDefinition(token, stringArgumentPlaceholders);\n\n // This is a valid argument!\n argumentList.push(argumentDefinition);\n } else {\n // The current token should be a ',' token.\n if (token !== \",\") {\n throw new Error(`invalid argument list, expected ',' or ']' but got '${token}'`);\n }\n }\n });\n\n // The arguments list should terminate with a ']' or ')' token, depending on the opener.\n popAndCheck(tokens, closingToken);\n\n // Return the arguments.\n return argumentList;\n}\n\n/**\n * Gets an argument value definition.\n * @param token The argument token.\n * @param stringArgumentPlaceholders The mapping of string literal node argument placeholders to original values.\n * @returns An argument value definition.\n */\nfunction getArgumentDefinition(token: string, stringArgumentPlaceholders: StringLiteralPlaceholders): AnyArgument {\n // Check whether the token represents a null value.\n if (token === \"null\") {\n return {\n value: null,\n type: \"null\"\n } as NullArgument;\n }\n\n // Check whether the token represents a boolean value.\n if (token === \"true\" || token === \"false\") {\n return {\n value: token === \"true\",\n type: \"boolean\"\n } as BooleanArgument;\n }\n\n // Check whether the token represents a number value.\n // TODO: Relies on broken isNaN - see MDN.\n // if (!Number.isNaN(token)) {\n if (!isNaN(token as any)) {\n return {\n value: parseFloat(token),\n isInteger: parseFloat(token) === parseInt(token, 10),\n type: \"number\"\n } as NumberArgument;\n }\n\n // Check whether the token is a placeholder (e.g. @@0@@) representing a string literal.\n if (token.match(/^@@\\d+@@$/g)) {\n return {\n value: stringArgumentPlaceholders[token].replace('\\\\\"', '\"'),\n type: \"string\"\n } as StringPlaceholderArgument;\n }\n\n // The only remaining option is that the argument value is an identifier.\n return {\n value: token,\n type: \"identifier\"\n } as IdentifierArgument;\n}\n", "import { NodeAttributeDefinition } from \"../BehaviourTreeDefinition\";\nimport { parseArgumentTokens } from \"./MDSLNodeArgumentParser\";\nimport { StringLiteralPlaceholders } from \"./MDSLUtilities\";\n\n/**\n * A type defining the attribute definitions of a node.\n */\ntype NodeAttributes = {\n while?: NodeAttributeDefinition;\n until?: NodeAttributeDefinition;\n entry?: NodeAttributeDefinition;\n exit?: NodeAttributeDefinition;\n step?: NodeAttributeDefinition;\n};\n\n/**\n * Parse any node attribute definitions from the specified tokens array.\n * @param tokens The array of remaining tokens.\n * @param stringArgumentPlaceholders The mapping of string literal node argument placeholders to original values.\n * @returns An object of attribute definitions defined by any directly following tokens.\n */\nexport function parseAttributeTokens(\n tokens: string[],\n stringArgumentPlaceholders: StringLiteralPlaceholders\n): NodeAttributes {\n const nodeAttributeNames: (keyof NodeAttributes)[] = [\"while\", \"until\", \"entry\", \"exit\", \"step\"];\n\n // Create an object to hold any attributes found.\n const attributes: NodeAttributes = {};\n\n // Try to get the name of the attribute for the next token.\n let nextAttributeName = tokens[0]?.toLowerCase() as keyof NodeAttributes;\n\n // Pull attribute tokens as well as their arguments off of the tokens stack until we have no more.\n while (nodeAttributeNames.includes(nextAttributeName)) {\n // Check to make sure that we have not already created an attribute definition of this type.\n if (attributes[nextAttributeName]) {\n throw new Error(`duplicate attribute '${tokens[0].toUpperCase()}' found for node`);\n }\n\n // Remove the attribute name token from the array of tokens.\n tokens.shift();\n\n // Grab the attribute arguments, assuming the first to be an identifier.\n const [attributeCallIdentifier, ...attributeArguments] = parseArgumentTokens(\n tokens,\n stringArgumentPlaceholders\n );\n\n // The first attribute argument has to be an identifer, this will reference an agent function.\n if (attributeCallIdentifier?.type !== \"identifier\") {\n throw new Error(\"expected agent function name identifier argument for attribute\");\n }\n\n // Any attribute arguments (other than the expected call identifier) must have a type of string, number, boolean or null.\n attributeArguments\n .filter((arg) => arg.type === \"identifier\")\n .forEach((arg) => {\n throw new Error(\n `invalid attribute argument value '${arg.value}', must be string, number, boolean or null`\n );\n });\n\n // Create the attribute definition and add it to the object of attribute definitions found.\n attributes[nextAttributeName] = {\n call: attributeCallIdentifier.value,\n args: attributeArguments.map(({ value }) => value)\n };\n\n // Try to get the next attribute name token, as there could be multiple.\n nextAttributeName = tokens[0]?.toLowerCase() as keyof NodeAttributes;\n }\n\n return attributes;\n}\n", "import {\n ActionNodeDefinition,\n AnyChildNodeDefinition,\n AnyNodeDefinition,\n BranchNodeDefinition,\n ConditionNodeDefinition,\n FailNodeDefinition,\n FlipNodeDefinition,\n LottoNodeDefinition,\n ParallelNodeDefinition,\n RepeatNodeDefinition,\n RetryNodeDefinition,\n RootNodeDefinition,\n SelectorNodeDefinition,\n SequenceNodeDefinition,\n SucceedNodeDefinition,\n WaitNodeDefinition\n} from \"../BehaviourTreeDefinition\";\nimport {\n isCompositeNode,\n isDecoratorNode,\n isLeafNode,\n isNullOrUndefined,\n isRootNode\n} from \"../BehaviourTreeDefinitionUtilities\";\nimport { parseArgumentTokens } from \"./MDSLNodeArgumentParser\";\nimport { parseAttributeTokens } from \"./MDSLNodeAttributeParser\";\nimport {\n StringLiteralPlaceholders,\n parseTokensFromDefinition,\n popAndCheck,\n substituteStringLiterals\n} from \"./MDSLUtilities\";\n\n/**\n * Convert the MDSL tree definition string into an equivalent JSON definition.\n * @param definition The tree definition string as MDSL.\n * @returns The root node JSON definitions.\n */\nexport function convertMDSLToJSON(definition: string): RootNodeDefinition[] {\n // Swap out any node/attribute argument string literals with a placeholder and get a mapping of placeholders to original values as well as the processed definition.\n const { placeholders, processedDefinition } = substituteStringLiterals(definition);\n\n // Parse our definition definition string into an array of raw tokens.\n const tokens = parseTokensFromDefinition(processedDefinition);\n\n return convertTokensToJSONDefinition(tokens, placeholders);\n}\n\n/**\n * Converts the specified tree definition tokens into a JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The root node JSON definitions.\n */\nfunction convertTokensToJSONDefinition(\n tokens: string[],\n stringLiteralPlaceholders: StringLiteralPlaceholders\n): RootNodeDefinition[] {\n // There must be at least 3 tokens for the tree definition to be valid. 'ROOT', '{' and '}'.\n if (tokens.length < 3) {\n throw new Error(\"invalid token count\");\n }\n\n // We should have a matching number of '{' and '}' tokens. If not, then there are scopes that have not been properly closed.\n if (tokens.filter((token) => token === \"{\").length !== tokens.filter((token) => token === \"}\").length) {\n throw new Error(\"scope character mismatch\");\n }\n\n // Create an array of tree stack arrays where root nodes will always be at the botton and the current composite/decorator node at the top.\n // There should be an element in this array for every root node defined and every element should be an array with a root note as the first element.\n // E.g. A definition with two root nodes defined:\n // [\n // [root, lotto, sequence],\n // [root, selector]\n // ]\n const treeStacks: [Partial, ...Partial[]][] = [];\n\n // Create an array of all root node definitions that we create.\n const rootNodes: Partial[] = [];\n\n // A helper function used to push node definitions onto the tree stack.\n const pushNode = (node: AnyNodeDefinition) => {\n // If the node is a root node then we need to create a new tree stack array with the root node at the root.\n if (isRootNode(node)) {\n // We need to double-check that this root node is not the child of another node.\n // We can do this by checking whether the top tree stack is not empty (contains an existing node)\n if (treeStacks[treeStacks.length - 1]?.length) {\n throw new Error(\"a root node cannot be the child of another node\");\n }\n\n // Add the root node definition to our array of all parsed root node definitions.\n rootNodes.push(node);\n\n // Add the root node definition to the root of a new tree stack.\n treeStacks.push([node]);\n\n return;\n }\n\n // All non-root nodes should be pushed after their root nodes so handle cases\n // where we may not have any tree stacks or our top-most tree stack is empty.\n if (!treeStacks.length || !treeStacks[treeStacks.length - 1].length) {\n throw new Error(\"expected root node at base of definition\");\n }\n\n // Get the current tree stack that we are populating.\n const topTreeStack = treeStacks[treeStacks.length - 1];\n\n // Get the top-most node in the current tree stack, this will be a composite/decorator node\n // for which we will populate its children array if composite or setting its child if a decorator.\n const topTreeStackTopNode = topTreeStack[topTreeStack.length - 1] as AnyNodeDefinition;\n\n // If the top-most node in the current root stack is a composite or decorator\n // node then the current node should be added as a child of the top-most node.\n if (isCompositeNode(topTreeStackTopNode)) {\n topTreeStackTopNode.children = topTreeStackTopNode.children || [];\n topTreeStackTopNode.children.push(node);\n } else if (isDecoratorNode(topTreeStackTopNode)) {\n // If the top node already has a child node set then throw an error as a decorator should only have a single child.\n if (topTreeStackTopNode.child) {\n throw new Error(\"a decorator node must only have a single child node\");\n }\n\n topTreeStackTopNode.child = node;\n }\n\n // If the node we are adding is also a composite or decorator node, then we should push it\n // onto the current tree stack, as subsequent nodes will be added as its child/children.\n if (!isLeafNode(node)) {\n topTreeStack.push(node);\n }\n };\n\n // A helper function used to pop the top-most node definition off of the tree stack and return it.\n const popNode = (): AnyNodeDefinition | null => {\n let poppedNode: AnyNodeDefinition | null = null;\n\n // Get the current tree stack that we are populating.\n const topTreeStack = treeStacks[treeStacks.length - 1];\n\n // Pop the top-most node in the current tree stack if there is one.\n if (topTreeStack.length) {\n poppedNode = topTreeStack.pop() as AnyNodeDefinition;\n }\n\n // We don't want any empty tree stacks in our stack of tree stacks.\n if (!topTreeStack.length) {\n treeStacks.pop();\n }\n\n return poppedNode;\n };\n\n // We should keep processing the raw tokens until we run out of them.\n while (tokens.length) {\n // Grab the next token.\n const token = tokens.shift()!;\n\n // How we create the next node depends on the current raw token value.\n switch (token.toUpperCase()) {\n case \"ROOT\": {\n pushNode(createRootNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"SUCCEED\": {\n pushNode(createSucceedNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"FAIL\": {\n pushNode(createFailNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"FLIP\": {\n pushNode(createFlipNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"REPEAT\": {\n pushNode(createRepeatNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"RETRY\": {\n pushNode(createRetryNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"SEQUENCE\": {\n pushNode(createSequenceNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"SELECTOR\": {\n pushNode(createSelectorNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"PARALLEL\": {\n pushNode(createParallelNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"LOTTO\": {\n pushNode(createLottoNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"ACTION\": {\n pushNode(createActionNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"CONDITION\": {\n pushNode(createConditionNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"WAIT\": {\n pushNode(createWaitNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"BRANCH\": {\n pushNode(createBranchNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"}\": {\n // The '}' character closes the current scope and means that we have to pop a node off of the current stack.\n const poppedNode = popNode();\n\n // Now that we have a node definition we can carry out any validation that may require the node to be fully populated.\n if (poppedNode) {\n validatePoppedNode(poppedNode);\n }\n\n break;\n }\n\n default: {\n throw new Error(`unexpected token: ${token}`);\n }\n }\n }\n\n return rootNodes as RootNodeDefinition[];\n}\n\n/**\n * Creates a root node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The root node JSON definition.\n */\nfunction createRootNode(tokens: string[], stringLiteralPlaceholders: StringLiteralPlaceholders): RootNodeDefinition {\n // Create the root node definition.\n let node = {\n type: \"root\",\n id: undefined\n } as RootNodeDefinition;\n\n // Parse any node arguments, we should only have one if any which will be an identifier argument for the root identifier.\n const nodeArguments = parseArgumentTokens(tokens, stringLiteralPlaceholders);\n\n // Check whether any node arguments were defined.\n if (nodeArguments.length) {\n // We should only have one argument, if any, which will be an identifier argument for the root identifier.\n if (nodeArguments.length === 1 && nodeArguments[0].type === \"identifier\") {\n // The root node identifier will be the first and only node argument value.\n node.id = nodeArguments[0].value as string;\n } else {\n throw new Error(\"expected single root name argument\");\n }\n }\n\n // Grab any node attribute definitions and spread them into the node definition.\n node = { ...node, ...parseAttributeTokens(tokens, stringLiteralPlaceholders) };\n\n // This is a decorator node, so we expect an opening '{'.\n popAndCheck(tokens, \"{\");\n\n // Return the root node definition.\n return node;\n}\n\n/**\n * Creates a succeed node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The succeed node JSON definition.\n */\nfunction createSucceedNode(\n tokens: string[],\n stringLiteralPlaceholders: StringLiteralPlaceholders\n): SucceedNodeDefinition {\n const node = {\n type: \"succeed\",\n ...parseAttributeTokens(tokens, stringLiteralPlaceholders)\n } as SucceedNodeDefinition;\n\n // This is a decorator node, so we expect an opening '{'.\n popAndCheck(tokens, \"{\");\n\n // Return the succeed node definition.\n return node;\n}\n\n/**\n * Creates a fail node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The fail node JSON definition.\n */\nfunction createFailNode(tokens: string[], stringLiteralPlaceholders: StringLiteralPlaceholders): FailNodeDefinition {\n const node = {\n type: \"fail\",\n ...parseAttributeTokens(tokens, stringLiteralPlaceholders)\n } as FailNodeDefinition;\n\n // This is a decorator node, so we expect an opening '{'.\n popAndCheck(tokens, \"{\");\n\n // Return the fail node definition.\n return node;\n}\n\n/**\n * Creates a flip node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The flip node JSON definition.\n */\nfunction createFlipNode(tokens: string[], stringLiteralPlaceholders: StringLiteralPlaceholders): FlipNodeDefinition {\n const node = {\n type: \"flip\",\n ...parseAttributeTokens(tokens, stringLiteralPlaceholders)\n } as FlipNodeDefinition;\n\n // This is a decorator node, so we expect an opening '{'.\n popAndCheck(tokens, \"{\");\n\n // Return the flip node definition.\n return node;\n}\n\n/**\n * Creates a repeat node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The repeat node JSON definition.\n */\nfunction createRepeatNode(\n tokens: string[],\n stringLiteralPlaceholders: StringLiteralPlaceholders\n): RepeatNodeDefinition {\n let node = { type: \"repeat\" } as RepeatNodeDefinition;\n\n // Get the node arguments.\n const nodeArguments = parseArgumentTokens(tokens, stringLiteralPlaceholders);\n\n // The arguments of a repeat node are optional. We may have:\n // - No node arguments, in which case the repeat note will iterate indefinitely.\n // - One node argument which will be the explicit number of iterations to make.\n // - Two node arguments which define the min and max iteration bounds from which a random iteration count will be picked.\n if (nodeArguments.length) {\n // All repeat node arguments MUST be of type number and must be integer.\n nodeArguments\n .filter((arg) => arg.type !== \"number\" || !arg.isInteger)\n .forEach(() => {\n throw new Error(`repeat node iteration counts must be integer values`);\n });\n\n // We should have got one or two iteration counts.\n if (nodeArguments.length === 1) {\n // A static iteration count was defined.\n node.iterations = nodeArguments[0].value as number;\n\n // A repeat node must have a positive number of iterations if defined.\n if (node.iterations < 0) {\n throw new Error(\"a repeat node must have a positive number of iterations if defined\");\n }\n } else if (nodeArguments.length === 2) {\n // A minimum and maximum iteration count was defined.\n node.iterations = [nodeArguments[0].value as number, nodeArguments[1].value as number];\n\n // A repeat node must have a positive min and max iteration count if they are defined.\n if (node.iterations[0] < 0 || node.iterations[1] < 0) {\n throw new Error(\"a repeat node must have a positive minimum and maximum iteration count if defined\");\n }\n\n // A repeat node must not have an minimum iteration count that exceeds the maximum iteration count.\n if (node.iterations[0] > node.iterations[1]) {\n throw new Error(\n \"a repeat node must not have a minimum iteration count that exceeds the maximum iteration count\"\n );\n }\n } else {\n // An incorrect number of iteration counts was defined.\n throw new Error(\"invalid number of repeat node iteration count arguments defined\");\n }\n }\n\n // Grab any node attribute definitions and spread them into the node definition.\n node = { ...node, ...parseAttributeTokens(tokens, stringLiteralPlaceholders) };\n\n // This is a decorator node, so we expect an opening '{'.\n popAndCheck(tokens, \"{\");\n\n // Return the repeat node definition.\n return node;\n}\n\n/**\n * Creates a retry node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The retry node JSON definition.\n */\nfunction createRetryNode(tokens: string[], stringLiteralPlaceholders: StringLiteralPlaceholders): RetryNodeDefinition {\n let node = { type: \"retry\" } as RetryNodeDefinition;\n\n // Get the node arguments.\n const nodeArguments = parseArgumentTokens(tokens, stringLiteralPlaceholders);\n\n // The arguments of a retry node are optional. We may have:\n // - No node arguments, in which case the retry note will attempt indefinitely.\n // - One node argument which will be the explicit number of attempts to make.\n // - Two node arguments which define the min and max attempt bounds from which a random attempt count will be picked.\n if (nodeArguments.length) {\n // All retry node arguments MUST be of type number and must be integer.\n nodeArguments\n .filter((arg) => arg.type !== \"number\" || !arg.isInteger)\n .forEach(() => {\n throw new Error(`retry node attempt counts must be integer values`);\n });\n\n // We should have got one or two attempt counts.\n if (nodeArguments.length === 1) {\n // A static attempt count was defined.\n node.attempts = nodeArguments[0].value as number;\n\n // A retry node must have a positive number of attempts if defined.\n if (node.attempts < 0) {\n throw new Error(\"a retry node must have a positive number of attempts if defined\");\n }\n } else if (nodeArguments.length === 2) {\n // A minimum and maximum attempt count was defined.\n node.attempts = [nodeArguments[0].value as number, nodeArguments[1].value as number];\n\n // A retry node must have a positive min and max attempts count if they are defined.\n if (node.attempts[0] < 0 || node.attempts[1] < 0) {\n throw new Error(\"a retry node must have a positive minimum and maximum attempt count if defined\");\n }\n\n // A retry node must not have a minimum attempt count that exceeds the maximum attempt count.\n if (node.attempts[0] > node.attempts[1]) {\n throw new Error(\n \"a retry node must not have a minimum attempt count that exceeds the maximum attempt count\"\n );\n }\n } else {\n // An incorrect number of attempt counts was defined.\n throw new Error(\"invalid number of retry node attempt count arguments defined\");\n }\n }\n\n // Grab any node attribute definitions and spread them into the node definition.\n node = { ...node, ...parseAttributeTokens(tokens, stringLiteralPlaceholders) };\n\n // This is a decorator node, so we expect an opening '{'.\n popAndCheck(tokens, \"{\");\n\n // Return the retry node definition.\n return node;\n}\n\n/**\n * Creates a sequence node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The sequence node JSON definition.\n */\nfunction createSequenceNode(\n tokens: string[],\n stringLiteralPlaceholders: StringLiteralPlaceholders\n): SequenceNodeDefinition {\n const node = {\n type: \"sequence\",\n ...parseAttributeTokens(tokens, stringLiteralPlaceholders)\n } as SequenceNodeDefinition;\n\n // This is a composite node, so we expect an opening '{'.\n popAndCheck(tokens, \"{\");\n\n // Return the sequence node definition.\n return node;\n}\n\n/**\n * Creates a selector node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The selector node JSON definition.\n */\nfunction createSelectorNode(\n tokens: string[],\n stringLiteralPlaceholders: StringLiteralPlaceholders\n): SelectorNodeDefinition {\n const node = {\n type: \"selector\",\n ...parseAttributeTokens(tokens, stringLiteralPlaceholders)\n } as SelectorNodeDefinition;\n\n // This is a composite node, so we expect an opening '{'.\n popAndCheck(tokens, \"{\");\n\n // Return the selector node definition.\n return node;\n}\n\n/**\n * Creates a parallel node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The parallel node JSON definition.\n */\nfunction createParallelNode(\n tokens: string[],\n stringLiteralPlaceholders: StringLiteralPlaceholders\n): ParallelNodeDefinition {\n const node = {\n type: \"parallel\",\n ...parseAttributeTokens(tokens, stringLiteralPlaceholders)\n } as ParallelNodeDefinition;\n\n // This is a composite node, so we expect an opening '{'.\n popAndCheck(tokens, \"{\");\n\n // Return the parallel node definition.\n return node;\n}\n\n/**\n * Creates a lotto node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The lotto node JSON definition.\n */\nfunction createLottoNode(tokens: string[], stringLiteralPlaceholders: StringLiteralPlaceholders): LottoNodeDefinition {\n // If any node arguments have been defined then they must be our weights.\n const nodeArguments = parseArgumentTokens(tokens, stringLiteralPlaceholders);\n\n // All lotto node arguments MUST be of type number and must be integer.\n nodeArguments\n .filter((arg) => arg.type !== \"number\" || !arg.isInteger)\n .forEach(() => {\n throw new Error(`lotto node weight arguments must be integer values`);\n });\n\n const node = {\n type: \"lotto\",\n weights: nodeArguments.map(({ value }) => value),\n ...parseAttributeTokens(tokens, stringLiteralPlaceholders)\n } as LottoNodeDefinition;\n\n // This is a composite node, so we expect an opening '{'.\n popAndCheck(tokens, \"{\");\n\n // Return the lotto node definition.\n return node;\n}\n\n/**\n * Creates an action node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The action node JSON definition.\n */\nfunction createActionNode(\n tokens: string[],\n stringLiteralPlaceholders: StringLiteralPlaceholders\n): ActionNodeDefinition {\n // Parse any node arguments, we should have at least one which will be an identifier argument for the action name\n // and agent function to invoke for the action, all other arguments are to be passed as arguments to that function.\n const [actionNameIdentifier, ...agentFunctionArgs] = parseArgumentTokens(tokens, stringLiteralPlaceholders);\n\n // Our first argument MUST be defined and be an identifier as we require an action name argument.\n if (actionNameIdentifier?.type !== \"identifier\") {\n throw new Error(\"expected action name identifier argument\");\n }\n\n // Only the first argument should have been an identifier, all agent function arguments must be string, number, boolean or null.\n agentFunctionArgs\n .filter((arg) => arg.type === \"identifier\")\n .forEach((arg) => {\n throw new Error(\n `invalid action node argument value '${arg.value}', must be string, number, boolean or null`\n );\n });\n\n // Return the action node definition.\n return {\n type: \"action\",\n call: actionNameIdentifier.value,\n args: agentFunctionArgs.map(({ value }) => value),\n ...parseAttributeTokens(tokens, stringLiteralPlaceholders)\n };\n}\n\n/**\n * Creates a condition node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The condition node JSON definition.\n */\nfunction createConditionNode(\n tokens: string[],\n stringLiteralPlaceholders: StringLiteralPlaceholders\n): ConditionNodeDefinition {\n // Parse any node arguments, we should have at least one which will be an identifier argument for the condition name\n // and agent function to invoke for the condition, all other arguments are to be passed as arguments to that function.\n const [conditionNameIdentifier, ...agentFunctionArgs] = parseArgumentTokens(tokens, stringLiteralPlaceholders);\n\n // Our first argument MUST be defined and be an identifier as we require a condition name argument.\n if (conditionNameIdentifier?.type !== \"identifier\") {\n throw new Error(\"expected condition name identifier argument\");\n }\n\n // Only the first argument should have been an identifier, all agent function arguments must be string, number, boolean or null.\n agentFunctionArgs\n .filter((arg) => arg.type === \"identifier\")\n .forEach((arg) => {\n throw new Error(\n `invalid condition node argument value '${arg.value}', must be string, number, boolean or null`\n );\n });\n\n // Return the condition node definition.\n return {\n type: \"condition\",\n call: conditionNameIdentifier.value,\n args: agentFunctionArgs.map(({ value }) => value),\n ...parseAttributeTokens(tokens, stringLiteralPlaceholders)\n };\n}\n\n/**\n * Creates a wait node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The wait node JSON definition.\n */\nfunction createWaitNode(tokens: string[], stringLiteralPlaceholders: StringLiteralPlaceholders): WaitNodeDefinition {\n let node = { type: \"wait\" } as WaitNodeDefinition;\n\n // Get the node arguments.\n const nodeArguments = parseArgumentTokens(tokens, stringLiteralPlaceholders);\n\n // The arguments of a wait node are optional. We may have:\n // - No node arguments, in which case the wait will be indefinite until it is aborted.\n // - One node argument which will be the explicit duration of the wait.\n // - Two node arguments which define the min and max duration bounds from which a random duration will be picked.\n if (nodeArguments.length) {\n // All wait node arguments MUST be of type number and must be integer.\n nodeArguments\n .filter((arg) => arg.type !== \"number\" || !arg.isInteger)\n .forEach(() => {\n throw new Error(`wait node duration arguments must be integer values`);\n });\n\n // We may have:\n // - One node argument which will be the explicit duration of the wait.\n // - Two node arguments which define the min and max duration bounds from which a random duration will be picked.\n // - Too many arguments, which is not valid.\n if (nodeArguments.length === 1) {\n // An explicit duration was defined.\n node.duration = nodeArguments[0].value as number;\n\n // If an explict duration was defined then it must be a positive number.\n if (node.duration < 0) {\n throw new Error(\"a wait node must have a positive duration\");\n }\n } else if (nodeArguments.length === 2) {\n // Min and max duration bounds were defined from which a random duration will be picked.\n node.duration = [nodeArguments[0].value as number, nodeArguments[1].value as number];\n\n // A wait node must have a positive min and max duration.\n if (node.duration[0] < 0 || node.duration[1] < 0) {\n throw new Error(\"a wait node must have a positive minimum and maximum duration\");\n }\n\n // A wait node must not have a minimum duration that exceeds the maximum duration.\n if (node.duration[0] > node.duration[1]) {\n throw new Error(\"a wait node must not have a minimum duration that exceeds the maximum duration\");\n }\n } else if (nodeArguments.length > 2) {\n // An incorrect number of duration arguments were defined.\n throw new Error(\"invalid number of wait node duration arguments defined\");\n }\n }\n\n // Return the wait node definition.\n return { ...node, ...parseAttributeTokens(tokens, stringLiteralPlaceholders) };\n}\n\n/**\n * Creates a branch node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The branch node JSON definition.\n */\nfunction createBranchNode(\n tokens: string[],\n stringLiteralPlaceholders: StringLiteralPlaceholders\n): BranchNodeDefinition {\n // Parse any node arguments, we should have one which will be an identifier argument for the root ref.\n const nodeArguments = parseArgumentTokens(tokens, stringLiteralPlaceholders);\n\n // We should have only a single identifer argument for a branch node, which is the root ref.\n if (nodeArguments.length !== 1 || nodeArguments[0].type !== \"identifier\") {\n throw new Error(\"expected single branch name argument\");\n }\n\n // Return the branch node definition.\n return { type: \"branch\", ref: nodeArguments[0].value };\n}\n\n/**\n * Validate a fully-populated node definition that was popped off of the tree stack.\n * @param node The popped node to validate.\n */\nfunction validatePoppedNode(node: AnyNodeDefinition): void {\n // Decorators MUST have a child defined.\n if (isDecoratorNode(node) && isNullOrUndefined(node.child)) {\n throw new Error(`a ${node.type} node must have a single child node defined`);\n }\n\n // Composites MUST have at least one child defined.\n if (isCompositeNode(node) && !node.children?.length) {\n throw new Error(`a ${node.type} node must have at least a single child node defined`);\n }\n}\n", "import { RootNodeDefinition } from \"./BehaviourTreeDefinition\";\nimport { flattenDefinition, isBranchNode, isInteger } from \"./BehaviourTreeDefinitionUtilities\";\nimport { convertMDSLToJSON } from \"./mdsl/MDSLDefinitionParser\";\n\n/**\n * An object representing the result of validating a tree definition.\n */\nexport type DefinitionValidationResult = {\n /**\n * A flag defining whether validation succeeded.\n */\n succeeded: boolean;\n /**\n * A string containing the error message if validation did not succeed.\n */\n errorMessage?: string;\n};\n\n/**\n * Validates the specified behaviour tree definition in the form of JSON or MDSL, not taking any globally registered subtrees into consideration.\n * @param definition The behaviour tree definition in the form of JSON or MDSL.\n * @returns An object representing the result of validating the given tree definition.\n */\nexport function validateDefinition(definition: any): DefinitionValidationResult {\n // The definition must be defined.\n if (definition === null || typeof definition === \"undefined\") {\n return createValidationFailureResult(\"definition is null or undefined\");\n }\n\n // We are expecting a definition in one of three different forms:\n // - A string which we will assume is MDSL and we will parse this to JSON before validation.\n // - An array which we will assume is an array of root node definitions with at least one being the primary root node (no 'id' property)\n // - An object which we will assume is the primary root node and should not have an 'id' property.\n if (typeof definition === \"string\") {\n // The definition is a string which we can assume is MDSL, so attempt to validate it.\n return validateMDSLDefinition(definition);\n } else if (typeof definition === \"object\") {\n // The definition will either be an array (of root node definitions) or an object (the single primary root node definition).\n return validateJSONDefinition(definition);\n } else {\n return createValidationFailureResult(`unexpected definition type of '${typeof definition}'`);\n }\n}\n\n/**\n * Validates the specified behaviour tree definition in the form of MDSL.\n * @param definition The behaviour tree definition in the form of MDSL.\n * @returns An object representing the result of validating the given tree definition.\n */\nexport function validateMDSLDefinition(definition: string): DefinitionValidationResult {\n let rootNodeDefinitions;\n\n // The first thing the we need to do is to attempt to convert our MDSL into JSON.\n try {\n // The definition is a string which we can assume is MDSL, so attempt to parse it to a JSON definition in the form of an array of root node definitions.\n rootNodeDefinitions = convertMDSLToJSON(definition);\n } catch (error) {\n // We failed to parse the JSON from the MDSL, this is likely to be the result of it not being a valid MDSL string.\n return createValidationFailureResult(`invalid MDSL: ${error}`);\n }\n\n // Unpack all of the root node definitions into arrays of main ('id' defined) and sub ('id' not defined) root node definitions.\n const mainRootNodeDefinitions = rootNodeDefinitions.filter(({ id }) => typeof id === \"undefined\");\n const subRootNodeDefinitions = rootNodeDefinitions.filter(({ id }) => typeof id === \"string\" && id.length > 0);\n\n // We should ALWAYS have exactly one root node definition without an 'id' property defined, which is out main root node definition.\n if (mainRootNodeDefinitions.length !== 1) {\n return createValidationFailureResult(\n \"expected single unnamed root node at base of definition to act as main root\"\n );\n }\n\n // We should never have duplicate 'id' properties across our sub root node definitions.\n const subRootNodeIdenitifers: string[] = [];\n for (const { id } of subRootNodeDefinitions) {\n // Have we already come across this 'id' property value?\n if (subRootNodeIdenitifers.includes(id!)) {\n return createValidationFailureResult(`multiple root nodes found with duplicate name '${id}'`);\n }\n\n subRootNodeIdenitifers.push(id!);\n }\n\n try {\n // Validate our branch -> subtree links and check for any circular dependencies, we don't care about checking for broken subtree links here.\n validateBranchSubtreeLinks(rootNodeDefinitions, false);\n } catch (exception) {\n return createValidationFailureResult((exception as Error).message);\n }\n\n // Our definition was valid!\n return { succeeded: true };\n}\n\n/**\n * Validates the specified behaviour tree definition in the form of JSON.\n * @param definition The behaviour tree definition in the form of JSON.\n * @returns An object representing the result of validating the given tree definition.\n */\nexport function validateJSONDefinition(\n definition: RootNodeDefinition | RootNodeDefinition[]\n): DefinitionValidationResult {\n // The definition will either be an array (of root node definitions) or an object (the single primary root node definition).\n const rootNodeDefinitions = Array.isArray(definition) ? definition : [definition];\n\n // Iterate over our array of root nodes and call validateNode for each, passing an initial depth of 0, wrapped in a try catch to handle validation failures.\n try {\n rootNodeDefinitions.forEach((rootNodeDefinition) => validateNode(rootNodeDefinition, 0));\n } catch (error) {\n // Handle cases where we have caught a thrown Error and return a failure result with the error message.\n if (error instanceof Error) {\n return createValidationFailureResult(error.message);\n }\n\n // No idea what happened here!\n return createValidationFailureResult(`unexpected error: ${error}`);\n }\n\n // Unpack all of the root node definitions into arrays of main ('id' defined) and sub ('id' not defined) root node definitions.\n const mainRootNodeDefinitions = rootNodeDefinitions.filter(({ id }) => typeof id === \"undefined\");\n const subRootNodeDefinitions = rootNodeDefinitions.filter(({ id }) => typeof id === \"string\" && id.length > 0);\n\n // We should ALWAYS have exactly one root node definition without an 'id' property defined, which is out main root node definition.\n if (mainRootNodeDefinitions.length !== 1) {\n return createValidationFailureResult(\n \"expected single root node without 'id' property defined to act as main root\"\n );\n }\n\n // We should never have duplicate 'id' properties across our sub root node definitions.\n const subRootNodeIdenitifers: string[] = [];\n for (const { id } of subRootNodeDefinitions) {\n // Have we already come across this 'id' property value?\n if (subRootNodeIdenitifers.includes(id!)) {\n return createValidationFailureResult(\n `multiple root nodes found with duplicate 'id' property value of '${id}'`\n );\n }\n\n subRootNodeIdenitifers.push(id!);\n }\n\n try {\n // Validate our branch -> subtree links and check for any circular dependencies, we don't care about checking for broken subtree links here.\n validateBranchSubtreeLinks(rootNodeDefinitions, false);\n } catch (exception) {\n return createValidationFailureResult((exception as Error).message);\n }\n\n // Our definition was valid!\n return { succeeded: true };\n}\n\n/**\n * Validates the branch -> subtree links across all provided root node definitions.\n * This will not consider branch nodes that reference any globally registered subtrees unless includesGlobalSubtrees\n * is set to true, in which case we will also verify that there are no broken branch -> subtree links.\n * @param rootNodeDefinitions The array of root node definitions.\n * @param includesGlobalSubtrees A flag defining whether the array includes all global subtree root node definitions.\n */\nexport function validateBranchSubtreeLinks(rootNodeDefinitions: RootNodeDefinition[], includesGlobalSubtrees: boolean) {\n // Create a mapping of root node identifiers to other root nodes that they reference via branch nodes.\n // Below is an example of a mapping that includes a circular dependency (root => a => b => c => a)\n // [{ refs: [\"a\", \"b\"] }, { id: \"a\", refs: [\"b\"] }, { id: \"b\", refs: [\"c\"] }, { id: \"c\", refs: [\"a\"] }]\n const rootNodeMappings: { id: string | undefined; refs: string[] }[] = rootNodeDefinitions.map(\n (rootNodeDefinition) => ({\n id: rootNodeDefinition.id,\n refs: flattenDefinition(rootNodeDefinition)\n .filter(isBranchNode)\n .map(({ ref }) => ref)\n })\n );\n\n // A recursive function to walk through the mappings, keeping track of which root nodes we have visited in the form of a path of root node identifiers.\n const followRefs = (mapping: { id: string | undefined; refs: string[] }, path: (string | undefined)[] = []) => {\n // Have we found a circular dependency?\n if (path.includes(mapping.id)) {\n // We found a circular dependency! Get the bad path of root node identifiers.\n const badPath = [...path, mapping.id];\n\n // Create the formatted path value. [undefined, \"a\", \"b\", \"c\", \"a\"] would be formatted as \"a -> b -> c -> a\".\n const badPathFormatted = badPath.filter((element) => !!element).join(\" => \");\n\n // No need to continue, we found a circular dependency.\n throw new Error(`circular dependency found in branch node references: ${badPathFormatted}`);\n }\n\n for (const ref of mapping.refs) {\n // Find the mapping for the root node with an identifer matching the current ref.\n const subMapping = rootNodeMappings.find(({ id }) => id === ref);\n\n // We may not have a mapping for this ref, which is normal when we aren't considering all globally registered subtrees.\n if (subMapping) {\n followRefs(subMapping, [...path, mapping.id]);\n } else if (includesGlobalSubtrees) {\n // We found a reference to a root node that doesn't exist, which is a problem seeing as the root node definitons includes all globally registered subtrees.\n throw new Error(\n mapping.id\n ? `subtree '${mapping.id}' has branch node that references root node '${ref}' which has not been defined`\n : `primary tree has branch node that references root node '${ref}' which has not been defined`\n );\n }\n }\n };\n\n // Start looking for circular dependencies and broken references from the primary root node definition.\n followRefs(rootNodeMappings.find((mapping) => typeof mapping.id === \"undefined\")!);\n}\n\n/**\n * Validate an object that we expect to be a node definition.\n * @param definition An object that we expect to be a node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateNode(definition: any, depth: number): void {\n // Every node must be valid object and have a non-empty 'type' string property.\n if (typeof definition !== \"object\" || typeof definition.type !== \"string\" || definition.type.length === 0) {\n throw new Error(\n `node definition is not an object or 'type' property is not a non-empty string at depth '${depth}'`\n );\n }\n\n // How we validate this node definition will depend on its type.\n switch (definition.type) {\n case \"action\":\n validateActionNode(definition, depth);\n break;\n\n case \"condition\":\n validateConditionNode(definition, depth);\n break;\n\n case \"wait\":\n validateWaitNode(definition, depth);\n break;\n\n case \"branch\":\n validateBranchNode(definition, depth);\n break;\n\n case \"root\":\n validateRootNode(definition, depth);\n break;\n\n case \"success\":\n validateSuccessNode(definition, depth);\n break;\n\n case \"fail\":\n validateFailNode(definition, depth);\n break;\n\n case \"flip\":\n validateFlipNode(definition, depth);\n break;\n\n case \"repeat\":\n validateRepeatNode(definition, depth);\n break;\n\n case \"retry\":\n validateRetryNode(definition, depth);\n break;\n\n case \"sequence\":\n validateSequenceNode(definition, depth);\n break;\n\n case \"selector\":\n validateSelectorNode(definition, depth);\n break;\n\n case \"parallel\":\n validateParallelNode(definition, depth);\n break;\n\n default:\n throw new Error(`unexpected node type of '${definition.type}' at depth '${depth}'`);\n }\n}\n\n/**\n * Validate any attributes for a given node definition.\n * @param definition The node definition.\n * @param depth The depth of the node in the behaviour tree definition.\n */\nfunction validateNodeAttributes(definition: any, depth: number): void {\n // Validate each of the attribute types for this node.\n [\"while\", \"until\", \"entry\", \"exit\", \"step\"].forEach((attributeName) => {\n // Attempt to grab the definition for the current attribute from the node definition.\n const attributeDefinition = definition[attributeName];\n\n // All node attributes are optional, so there is nothing to do if the current attribute is not defined.\n if (typeof attributeDefinition === \"undefined\") {\n return;\n }\n\n // The attribute definition must be an object.\n if (typeof attributeDefinition !== \"object\") {\n throw new Error(\n `expected attribute '${attributeName}' to be an object for '${definition.type}' node at depth '${depth}'`\n );\n }\n\n // The 'call' property must be defined for any attribute definition.\n if (typeof attributeDefinition.call !== \"string\" || attributeDefinition.call.length === 0) {\n throw new Error(\n `expected 'call' property for attribute '${attributeName}' to be a non-empty string for '${definition.type}' node at depth '${depth}'`\n );\n }\n\n // If any node attribute arguments have been defined then they must have been defined in an array.\n if (typeof attributeDefinition.args !== \"undefined\" && !Array.isArray(attributeDefinition.args)) {\n throw new Error(\n `expected 'args' property for attribute '${attributeName}' to be an array for '${definition.type}' node at depth '${depth}'`\n );\n }\n });\n}\n\n/**\n * Validate an object that we expect to be a root node definition.\n * @param definition An object that we expect to be a root node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateRootNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"root\") {\n throw new Error(\"expected node type of 'root' for root node\");\n }\n\n // A root node cannot be the child of another node.\n if (depth > 0) {\n throw new Error(\"a root node cannot be the child of another node\");\n }\n\n // Check that, if the root node 'id' property is defined, it is a non-empty string.\n if (typeof definition.id !== \"undefined\" && (typeof definition.id !== \"string\" || definition.id.length === 0)) {\n throw new Error(\"expected non-empty string for 'id' property if defined for root node\");\n }\n\n // A root node is a decorator node, so must have a child node defined.\n if (typeof definition.child === \"undefined\") {\n throw new Error(\"expected property 'child' to be defined for root node\");\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n\n // Validate the child node of this decorator node.\n validateNode(definition.child, depth + 1);\n}\n\n/**\n * Validate an object that we expect to be a success node definition.\n * @param definition An object that we expect to be a success node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateSuccessNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"success\") {\n throw new Error(`expected node type of 'success' for success node at depth '${depth}'`);\n }\n\n // A success node is a decorator node, so must have a child node defined.\n if (typeof definition.child === \"undefined\") {\n throw new Error(`expected property 'child' to be defined for success node at depth '${depth}'`);\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n\n // Validate the child node of this decorator node.\n validateNode(definition.child, depth + 1);\n}\n\n/**\n * Validate an object that we expect to be a fail node definition.\n * @param definition An object that we expect to be a fail node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateFailNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"fail\") {\n throw new Error(`expected node type of 'fail' for fail node at depth '${depth}'`);\n }\n\n // A fail node is a decorator node, so must have a child node defined.\n if (typeof definition.child === \"undefined\") {\n throw new Error(`expected property 'child' to be defined for fail node at depth '${depth}'`);\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n\n // Validate the child node of this decorator node.\n validateNode(definition.child, depth + 1);\n}\n\n/**\n * Validate an object that we expect to be a flip node definition.\n * @param definition An object that we expect to be a flip node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateFlipNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"flip\") {\n throw new Error(`expected node type of 'flip' for flip node at depth '${depth}'`);\n }\n\n // A flip node is a decorator node, so must have a child node defined.\n if (typeof definition.child === \"undefined\") {\n throw new Error(`expected property 'child' to be defined for flip node at depth '${depth}'`);\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n\n // Validate the child node of this decorator node.\n validateNode(definition.child, depth + 1);\n}\n\n/**\n * Validate an object that we expect to be a repeat node definition.\n * @param definition An object that we expect to be a repeat node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateRepeatNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"repeat\") {\n throw new Error(`expected node type of 'repeat' for repeat node at depth '${depth}'`);\n }\n\n // A repeat node is a decorator node, so must have a child node defined.\n if (typeof definition.child === \"undefined\") {\n throw new Error(`expected property 'child' to be defined for repeat node at depth '${depth}'`);\n }\n\n // Check whether an 'iterations' property has been defined, it may not have been if this node is to repeat indefinitely.\n if (typeof definition.iterations !== \"undefined\") {\n if (Array.isArray(definition.iterations)) {\n // Check whether any elements of the array are not integer values.\n const containsNonInteger = !!definition.iterations.find((value: unknown) => !isInteger(value));\n\n // If the 'iterations' property is an array then it MUST contain two integer values.\n if (definition.iterations.length !== 2 || containsNonInteger) {\n throw new Error(\n `expected array containing two integer values for 'iterations' property if defined for repeat node at depth '${depth}'`\n );\n }\n\n // A repeat node must have a positive min and max iterations count if they are defined.\n if (definition.iterations[0] < 0 || definition.iterations[1] < 0) {\n throw new Error(\n `expected positive minimum and maximum iterations count for 'iterations' property if defined for repeat node at depth '${depth}'`\n );\n }\n\n // A repeat node must not have a minimum iterations count that exceeds the maximum iterations count.\n if (definition.iterations[0] > definition.iterations[1]) {\n throw new Error(\n `expected minimum iterations count that does not exceed the maximum iterations count for 'iterations' property if defined for repeat node at depth '${depth}'`\n );\n }\n } else if (isInteger(definition.iterations)) {\n // A repeat node must have a positive number of iterations if defined.\n if (definition.iterations < 0) {\n throw new Error(\n `expected positive iterations count for 'iterations' property if defined for repeat node at depth '${depth}'`\n );\n }\n } else {\n throw new Error(\n `expected integer value or array containing two integer values for 'iterations' property if defined for repeat node at depth '${depth}'`\n );\n }\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n\n // Validate the child node of this decorator node.\n validateNode(definition.child, depth + 1);\n}\n\n/**\n * Validate an object that we expect to be a retry node definition.\n * @param definition An object that we expect to be a retry node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateRetryNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"retry\") {\n throw new Error(`expected node type of 'retry' for retry node at depth '${depth}'`);\n }\n\n // A retry node is a decorator node, so must have a child node defined.\n if (typeof definition.child === \"undefined\") {\n throw new Error(`expected property 'child' to be defined for retry node at depth '${depth}'`);\n }\n\n // Check whether an 'attempts' property has been defined, it may not have been if this node is to retry indefinitely.\n if (typeof definition.attempts !== \"undefined\") {\n if (Array.isArray(definition.attempts)) {\n // Check whether any elements of the array are not integer values.\n const containsNonInteger = !!definition.attempts.find((value: unknown) => !isInteger(value));\n\n // If the 'attempts' property is an array then it MUST contain two integer values.\n if (definition.attempts.length !== 2 || containsNonInteger) {\n throw new Error(\n `expected array containing two integer values for 'attempts' property if defined for retry node at depth '${depth}'`\n );\n }\n\n // A retry node must have a positive min and max attempts count if they are defined.\n if (definition.attempts[0] < 0 || definition.attempts[1] < 0) {\n throw new Error(\n `expected positive minimum and maximum attempts count for 'attempts' property if defined for retry node at depth '${depth}'`\n );\n }\n\n // A retry node must not have a minimum attempts count that exceeds the maximum attempts count.\n if (definition.attempts[0] > definition.attempts[1]) {\n throw new Error(\n `expected minimum attempts count that does not exceed the maximum attempts count for 'attempts' property if defined for retry node at depth '${depth}'`\n );\n }\n } else if (isInteger(definition.attempts)) {\n // A retry node must have a positive number of attempts if defined.\n if (definition.attempts < 0) {\n throw new Error(\n `expected positive attempts count for 'attempts' property if defined for retry node at depth '${depth}'`\n );\n }\n } else {\n throw new Error(\n `expected integer value or array containing two integer values for 'attempts' property if defined for retry node at depth '${depth}'`\n );\n }\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n\n // Validate the child node of this decorator node.\n validateNode(definition.child, depth + 1);\n}\n\n/**\n * Validate an object that we expect to be a branch node definition.\n * @param definition An object that we expect to be a branch node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateBranchNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"branch\") {\n throw new Error(`expected node type of 'branch' for branch node at depth '${depth}'`);\n }\n\n // Check that the branch node 'ref' property is defined and is a non-empty string.\n if (typeof definition.ref !== \"string\" || definition.ref.length === 0) {\n throw new Error(`expected non-empty string for 'ref' property for branch node at depth '${depth}'`);\n }\n\n // It is invalid to define guard attributes for a branch node as they should be defined on the referenced root node.\n [\"while\", \"until\"].forEach((attributeName) => {\n if (typeof definition[attributeName] !== \"undefined\") {\n throw new Error(\n `guards should not be defined for branch nodes but guard '${attributeName}' was defined for branch node at depth '${depth}'`\n );\n }\n });\n\n // It is invalid to define callback attributes for a branch node as they should be defined on the referenced root node.\n [\"entry\", \"exit\", \"step\"].forEach((attributeName) => {\n if (typeof definition[attributeName] !== \"undefined\") {\n throw new Error(\n `callbacks should not be defined for branch nodes but callback '${attributeName}' was defined for branch node at depth '${depth}'`\n );\n }\n });\n}\n\n/**\n * Validate an object that we expect to be a action node definition.\n * @param definition An object that we expect to be a action node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateActionNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"action\") {\n throw new Error(`expected node type of 'action' for action node at depth '${depth}'`);\n }\n\n // The 'call' property must be defined for a action node definition.\n if (typeof definition.call !== \"string\" || definition.call.length === 0) {\n throw new Error(`expected non-empty string for 'call' property of action node at depth '${depth}'`);\n }\n\n // If any action function arguments have been defined then they must have been defined in an array.\n if (typeof definition.args !== \"undefined\" && !Array.isArray(definition.args)) {\n throw new Error(`expected array for 'args' property if defined for action node at depth '${depth}'`);\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n}\n\n/**\n * Validate an object that we expect to be a condition node definition.\n * @param definition An object that we expect to be a condition node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateConditionNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"condition\") {\n throw new Error(`expected node type of 'condition' for condition node at depth '${depth}'`);\n }\n\n // The 'call' property must be defined for a condition node definition.\n if (typeof definition.call !== \"string\" || definition.call.length === 0) {\n throw new Error(`expected non-empty string for 'call' property of condition node at depth '${depth}'`);\n }\n\n // If any condition function arguments have been defined then they must have been defined in an array.\n if (typeof definition.args !== \"undefined\" && !Array.isArray(definition.args)) {\n throw new Error(`expected array for 'args' property if defined for condition node at depth '${depth}'`);\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n}\n\n/**\n * Validate an object that we expect to be a wait node definition.\n * @param definition An object that we expect to be a wait node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateWaitNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"wait\") {\n throw new Error(`expected node type of 'wait' for wait node at depth '${depth}'`);\n }\n\n // Check whether a 'duration' property has been defined, it may not have been if this node is to wait indefinitely.\n if (typeof definition.duration !== \"undefined\") {\n if (Array.isArray(definition.duration)) {\n // Check whether any elements of the array are not integer values.\n const containsNonInteger = !!definition.duration.find((value: unknown) => !isInteger(value));\n\n // If the 'duration' property is an array then it MUST contain two integer values.\n if (definition.duration.length !== 2 || containsNonInteger) {\n throw new Error(\n `expected array containing two integer values for 'duration' property if defined for wait node at depth '${depth}'`\n );\n }\n\n // A wait node must have a positive min and max duration value if they are defined.\n if (definition.duration[0] < 0 || definition.duration[1] < 0) {\n throw new Error(\n `expected positive minimum and maximum duration for 'duration' property if defined for wait node at depth '${depth}'`\n );\n }\n\n // A wait node must not have a minimum duration value that exceeds the maximum duration value.\n if (definition.duration[0] > definition.duration[1]) {\n throw new Error(\n `expected minimum duration value that does not exceed the maximum duration value for 'duration' property if defined for wait node at depth '${depth}'`\n );\n }\n } else if (isInteger(definition.duration)) {\n // A wait node must have a positive duration value if defined.\n if (definition.duration < 0) {\n throw new Error(\n `expected positive duration value for 'duration' property if defined for wait node at depth '${depth}'`\n );\n }\n } else {\n throw new Error(\n `expected integer value or array containing two integer values for 'duration' property if defined for wait node at depth '${depth}'`\n );\n }\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n}\n\n/**\n * Validate an object that we expect to be a sequence node definition.\n * @param definition An object that we expect to be a sequence node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateSequenceNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"sequence\") {\n throw new Error(`expected node type of 'sequence' for sequence node at depth '${depth}'`);\n }\n\n // A sequence node is a composite node, so must have a children nodes array defined.\n if (!Array.isArray(definition.children) || definition.children.length === 0) {\n throw new Error(`expected non-empty 'children' array to be defined for sequence node at depth '${depth}'`);\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n\n // Validate the child nodes of this composite node.\n definition.children.forEach((child: any) => validateNode(child, depth + 1));\n}\n\n/**\n * Validate an object that we expect to be a selector node definition.\n * @param definition An object that we expect to be a selector node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateSelectorNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"selector\") {\n throw new Error(`expected node type of 'selector' for selector node at depth '${depth}'`);\n }\n\n // A selector node is a composite node, so must have a children nodes array defined.\n if (!Array.isArray(definition.children) || definition.children.length === 0) {\n throw new Error(`expected non-empty 'children' array to be defined for selector node at depth '${depth}'`);\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n\n // Validate the child nodes of this composite node.\n definition.children.forEach((child: any) => validateNode(child, depth + 1));\n}\n\n/**\n * Validate an object that we expect to be a parallel node definition.\n * @param definition An object that we expect to be a parallel node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateParallelNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"parallel\") {\n throw new Error(`expected node type of 'parallel' for parallel node at depth '${depth}'`);\n }\n\n // A parallel node is a composite node, so must have a children nodes array defined.\n if (!Array.isArray(definition.children) || definition.children.length === 0) {\n throw new Error(`expected non-empty 'children' array to be defined for parallel node at depth '${depth}'`);\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n\n // Validate the child nodes of this composite node.\n definition.children.forEach((child: any) => validateNode(child, depth + 1));\n}\n\n/**\n * A helper function to create a failure validation result with the given error message.\n * @param errorMessage The validation failure error message.\n * @returns A failure validation result with the given error message.\n */\nfunction createValidationFailureResult(errorMessage: string): DefinitionValidationResult {\n return { succeeded: false, errorMessage };\n}\n", "import { ActionResult, Agent, GlobalFunction } from \"./Agent\";\nimport { RootNodeDefinition } from \"./BehaviourTreeDefinition\";\n\nexport type InvokerFunction = (args: any[]) => ActionResult;\n\n/**\n * A singleton used to store and lookup registered functions and subtrees.\n */\nexport default class Lookup {\n /**\n * The object holding any registered functions keyed on function name.\n */\n private static functionTable: { [key: string]: GlobalFunction } = {};\n /**\n * The object holding any registered subtree root node definitions keyed on tree name.\n */\n private static subtreeTable: { [key: string]: RootNodeDefinition } = {};\n\n /**\n * Gets the function with the specified name.\n * @param name The name of the function.\n * @returns The function with the specified name.\n */\n public static getFunc(name: string): GlobalFunction {\n return this.functionTable[name];\n }\n\n /**\n * Sets the function with the specified name for later lookup.\n * @param name The name of the function.\n * @param func The function.\n */\n public static setFunc(name: string, func: GlobalFunction): void {\n this.functionTable[name] = func;\n }\n\n /**\n * Gets the function invoker for the specified agent and function name.\n * If a function with the specified name exists on the agent object then it will\n * be returned, otherwise we will then check the registered functions for a match.\n * @param agent The agent instance that this behaviour tree is modelling behaviour for.\n * @param name The function name.\n * @returns The function invoker for the specified agent and function name.\n */\n static getFuncInvoker(agent: Agent, name: string): InvokerFunction | null {\n // Check whether the agent contains the specified function.\n const foundOnAgent = agent[name];\n if (foundOnAgent && typeof foundOnAgent === \"function\") {\n return (args: any[]): boolean | ActionResult => foundOnAgent.apply(agent, args);\n }\n\n // The agent does not contain the specified function but it may have been registered at some point.\n if (this.functionTable[name] && typeof this.functionTable[name] === \"function\") {\n return (args: any[]) => this.functionTable[name](agent, ...args.map((arg) => arg.value));\n }\n\n // We have no function to invoke.\n return null;\n }\n\n /**\n * Gets all registered subtree root node definitions.\n */\n static getSubtrees(): { [key: string]: RootNodeDefinition } {\n return this.subtreeTable;\n }\n\n /**\n * Sets the subtree with the specified name for later lookup.\n * @param name The name of the subtree.\n * @param subtree The subtree.\n */\n static setSubtree(name: string, subtree: RootNodeDefinition) {\n this.subtreeTable[name] = subtree;\n }\n\n /**\n * Removes the registered function or subtree with the specified name.\n * @param name The name of the registered function or subtree.\n */\n static remove(name: string) {\n delete this.functionTable[name];\n delete this.subtreeTable[name];\n }\n\n /**\n * Remove all registered functions and subtrees.\n */\n static empty() {\n this.functionTable = {};\n this.subtreeTable = {};\n }\n}\n", "import Node from \"../../nodes/Node\";\n\n/**\n * An exception thrown when evaluating node guard path conditions and a conditions fails.\n */\nexport default class GuardUnsatisifedException extends Error {\n /**\n * @param source The node at which a guard condition failed.\n */\n constructor(private source: Node) {\n super(\"A guard path condition has failed\");\n }\n\n /**\n * Gets whether the specified node is the node at which a guard condition failed.\n * @param node The node to check against the source node.\n * @returns Whether the specified node is the node at which a guard condition failed.\n */\n isSourceNode = (node: Node) => node === this.source;\n}\n", "import { Agent } from \"../../Agent\";\nimport Guard from \"./Guard\";\nimport Node from \"../../nodes/Node\";\nimport GuardUnsatisifedException from \"./GuardUnsatisifedException\";\n\nexport type GuardPathPart = {\n node: Node;\n guards: Guard[];\n};\n\n/**\n * Represents a path of node guards along a root-to-leaf tree path.\n */\nexport default class GuardPath {\n /**\n * @param nodes An array of objects defining a node instance -> guard link, ordered by node depth.\n */\n constructor(private nodes: GuardPathPart[]) {}\n\n /**\n * Evaluate guard conditions for all guards in the tree path, moving outwards from the root.\n * @param agent The agent, required for guard evaluation.\n * @returns An evaluation results object.\n */\n evaluate = (agent: Agent) => {\n // We need to evaluate guard conditions for nodes up the tree, moving outwards from the root.\n for (const details of this.nodes) {\n // There can be multiple guards per node.\n for (const guard of details.guards) {\n // Check whether the guard condition passes, and throw an exception if not.\n if (!guard.isSatisfied(agent)) {\n throw new GuardUnsatisifedException(details.node);\n }\n }\n }\n };\n}\n", "import { BehaviourTreeOptions } from \"../BehaviourTreeOptions\";\nimport State, { AnyState } from \"../State\";\nimport { Agent } from \"../Agent\";\nimport Leaf from \"./leaf/Leaf\";\nimport Attribute from \"../attributes/Attribute\";\nimport Entry from \"../attributes/callbacks/Entry\";\nimport Exit from \"../attributes/callbacks/Exit\";\nimport Step from \"../attributes/callbacks/Step\";\nimport Guard from \"../attributes/guards/Guard\";\nimport GuardPath from \"../attributes/guards/GuardPath\";\nimport GuardUnsatisifedException from \"../attributes/guards/GuardUnsatisifedException\";\n\n/**\n * A base node.\n */\nexport default abstract class Node {\n /**\n * The node uid.\n */\n private readonly uid: string = createNodeUid();\n /**\n * The node state.\n */\n private state: AnyState = State.READY;\n /**\n * The guard path to evaluate as part of a node update.\n */\n private guardPath: GuardPath | undefined;\n\n /**\n * @param type The node type.\n * @param attributes The node attributes.\n * @param args The node argument definitions.\n */\n constructor(private type: string, private attributes: Attribute[], private args: any[]) {}\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected abstract onUpdate(agent: Agent, options: BehaviourTreeOptions): void;\n\n /**\n * Gets the name of the node.\n */\n public abstract getName(): string;\n\n /**\n * Gets whether this node is a leaf node.\n */\n public abstract isLeafNode: () => this is Leaf;\n\n /**\n * Gets/Sets the state of the node.\n */\n getState = (): AnyState => this.state;\n setState = (value: AnyState): void => {\n this.state = value;\n };\n\n /**\n * Gets the unique id of the node.\n */\n getUid = () => this.uid;\n\n /**\n * Gets the type of the node.\n */\n getType = () => this.type;\n\n /**\n * Gets the node attributes.\n */\n getAttributes = () => this.attributes;\n\n /**\n * Gets the node arguments.\n */\n getArguments = () => this.args;\n\n /**\n * Gets the node attribute with the specified type, or null if it does not exist.\n */\n getAttribute(type: \"entry\" | \"ENTRY\"): Entry;\n getAttribute(type: \"exit\" | \"EXIT\"): Exit;\n getAttribute(type: \"step\" | \"STEP\"): Step;\n getAttribute(type: string): Attribute {\n return (\n this.getAttributes().filter((decorator) => decorator.type.toUpperCase() === type.toUpperCase())[0] || null\n );\n }\n\n /**\n * Gets the node attributes.\n */\n getGuardAttributes = (): Guard[] => this.getAttributes().filter((decorator) => decorator.isGuard()) as Guard[];\n\n /**\n * Sets the guard path to evaluate as part of a node update.\n */\n setGuardPath = (value: GuardPath) => (this.guardPath = value);\n\n /**\n * Gets whether a guard path is assigned to this node.\n */\n hasGuardPath = () => !!this.guardPath;\n\n /**\n * Gets whether this node is in the specified state.\n * @param value The value to compare to the node state.\n */\n public is(value: AnyState): boolean {\n return this.state === value;\n }\n\n /**\n * Reset the state of the node.\n */\n public reset(): void {\n this.setState(State.READY);\n }\n\n /**\n * Abort the running of this node.\n * @param agent The agent.\n */\n public abort(agent: Agent): void {\n // There is nothing to do if this node is not in the running state.\n if (!this.is(State.RUNNING)) {\n return;\n }\n\n // Reset the state of this node.\n this.reset();\n\n this.getAttribute(\"exit\")?.callAgentFunction(agent, false, true);\n }\n\n /**\n * Update the node.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n * @returns The result of the update.\n */\n public update(agent: Agent, options: BehaviourTreeOptions): void {\n // If this node is already in a 'SUCCEEDED' or 'FAILED' state then there is nothing to do.\n if (this.is(State.SUCCEEDED) || this.is(State.FAILED)) {\n return;\n }\n\n try {\n // Evaluate all of the guard path conditions for the current tree path.\n this.guardPath!.evaluate(agent);\n\n // If this node is in the READY state then call the ENTRY for this node if it exists.\n if (this.is(State.READY)) {\n this.getAttribute(\"entry\")?.callAgentFunction(agent);\n }\n\n this.getAttribute(\"step\")?.callAgentFunction(agent);\n\n // Do the actual update.\n this.onUpdate(agent, options);\n\n // If this node is now in a 'SUCCEEDED' or 'FAILED' state then call the EXIT for this node if it exists.\n if (this.is(State.SUCCEEDED) || this.is(State.FAILED)) {\n this.getAttribute(\"exit\")?.callAgentFunction(agent, this.is(State.SUCCEEDED), false);\n }\n } catch (error) {\n // If the error is a GuardUnsatisfiedException then we need to determine if this node is the source.\n if (error instanceof GuardUnsatisifedException && error.isSourceNode(this)) {\n // Abort the current node.\n this.abort(agent);\n\n // Any node that is the source of an abort will be a failed node.\n this.setState(State.FAILED);\n } else {\n throw error;\n }\n }\n }\n}\n\n/**\n * Create a randomly generated node uid.\n * @returns A randomly generated node uid.\n */\nfunction createNodeUid(): string {\n var S4 = function () {\n return (((1 + Math.random()) * 0x10000) | 0).toString(16).substring(1);\n };\n return S4() + S4() + \"-\" + S4() + \"-\" + S4() + \"-\" + S4() + \"-\" + S4() + S4() + S4();\n}\n", "import Node from \"../Node\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\n\n/**\n * A composite node that wraps child nodes.\n */\nexport default abstract class Composite extends Node {\n /**\n * @param type The node type.\n * @param attributes The node attributes.\n * @param children The child nodes.\n */\n constructor(type: string, attributes: Attribute[], protected children: Node[]) {\n super(type, attributes, []);\n }\n\n /**\n * Gets whether this node is a leaf node.\n */\n isLeafNode = () => false;\n\n /**\n * Gets the children of this node.\n */\n getChildren = () => this.children;\n\n /**\n * Reset the state of the node.\n */\n reset = () => {\n // Reset the state of this node.\n this.setState(State.READY);\n\n // Reset the state of any child nodes.\n this.getChildren().forEach((child) => child.reset());\n };\n\n /**\n * Abort the running of this node.\n * @param agent The agent.\n */\n abort = (agent: Agent) => {\n // There is nothing to do if this node is not in the running state.\n if (!this.is(State.RUNNING)) {\n return;\n }\n\n // Abort any child nodes.\n this.getChildren().forEach((child) => child.abort(agent));\n\n // Reset the state of this node.\n this.reset();\n\n this.getAttribute(\"exit\")?.callAgentFunction(agent, false, true);\n };\n}\n", "import Composite from \"./Composite\";\nimport State from \"../../State\";\nimport Node from \"../Node\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A PARALLEL node.\n * The child nodes are executed concurrently until one fails or all succeed.\n */\nexport default class Parallel extends Composite {\n /**\n * @param attributes The node attributes.\n * @param children The child nodes.\n */\n constructor(attributes: Attribute[], children: Node[]) {\n super(\"parallel\", attributes, children);\n }\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // Keep a count of the number of succeeded child nodes.\n let succeededCount = 0;\n\n let hasChildFailed = false;\n\n // Iterate over all of the children of this node.\n for (const child of this.children) {\n // If the child has never been updated or is running then we will need to update it now.\n if (child.getState() === State.READY || child.getState() === State.RUNNING) {\n // Update the child of this node.\n child.update(agent, options);\n }\n\n // If the current child has a state of 'SUCCEEDED' then we should move on to the next child.\n if (child.getState() === State.SUCCEEDED) {\n // The child node has succeeded, keep track of this to determine if all children have.\n succeededCount++;\n\n // The child node succeeded, but we have not finished checking every child node yet.\n continue;\n }\n\n // If the current child has a state of 'FAILED' then this node is also a 'FAILED' node.\n if (child.getState() === State.FAILED) {\n hasChildFailed = true;\n\n // There is no need to check the rest of the children.\n break;\n }\n\n // The node should be in the 'RUNNING' state.\n if (child.getState() !== State.RUNNING) {\n // The child node was not in an expected state.\n throw new Error(\"child node was not in an expected state.\");\n }\n }\n\n if (hasChildFailed) {\n // This node is a 'FAILED' node.\n this.setState(State.FAILED);\n\n // Abort every running child.\n for (const child of this.children) {\n if (child.getState() === State.RUNNING) {\n child.abort(agent);\n }\n }\n } else {\n // If all children have succeeded then this node has also succeeded, otherwise it is still running.\n this.setState(succeededCount === this.children.length ? State.SUCCEEDED : State.RUNNING);\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => \"PARALLEL\";\n}\n", "import Composite from \"./Composite\";\nimport Node from \"../Node\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A SELECTOR node.\n * The child nodes are executed in sequence until one succeeds or all fail.\n */\nexport default class Selector extends Composite {\n /**\n * @param attributes The node attributes.\n * @param children The child nodes.\n */\n constructor(attributes: Attribute[], protected children: Node[]) {\n super(\"selector\", attributes, children);\n }\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // Iterate over all of the children of this node.\n for (const child of this.children) {\n // If the child has never been updated or is running then we will need to update it now.\n if (child.getState() === State.READY || child.getState() === State.RUNNING) {\n // Update the child of this node.\n child.update(agent, options);\n }\n\n // If the current child has a state of 'SUCCEEDED' then this node is also a 'SUCCEEDED' node.\n if (child.getState() === State.SUCCEEDED) {\n // This node is a 'SUCCEEDED' node.\n this.setState(State.SUCCEEDED);\n\n // There is no need to check the rest of the selector nodes.\n return;\n }\n\n // If the current child has a state of 'FAILED' then we should move on to the next child.\n if (child.getState() === State.FAILED) {\n // Find out if the current child is the last one in the selector.\n // If it is then this sequence node has also failed.\n if (this.children.indexOf(child) === this.children.length - 1) {\n // This node is a 'FAILED' node.\n this.setState(State.FAILED);\n\n // There is no need to check the rest of the selector as we have completed it.\n return;\n } else {\n // The child node failed, try the next one.\n continue;\n }\n }\n\n // The node should be in the 'RUNNING' state.\n if (child.getState() === State.RUNNING) {\n // This node is a 'RUNNING' node.\n this.setState(State.RUNNING);\n\n // There is no need to check the rest of the selector as the current child is still running.\n return;\n }\n\n // The child node was not in an expected state.\n throw new Error(\"child node was not in an expected state.\");\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => \"SELECTOR\";\n}\n", "import Composite from \"./Composite\";\nimport Node from \"../Node\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A SEQUENCE node.\n * The child nodes are executed in sequence until one fails or all succeed.\n */\nexport default class Sequence extends Composite {\n /**\n * @param attributes The node attributes.\n * @param children The child nodes.\n */\n constructor(attributes: Attribute[], protected children: Node[]) {\n super(\"sequence\", attributes, children);\n }\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // Iterate over all of the children of this node.\n for (const child of this.children) {\n // If the child has never been updated or is running then we will need to update it now.\n if (child.getState() === State.READY || child.getState() === State.RUNNING) {\n // Update the child of this node.\n child.update(agent, options);\n }\n\n // If the current child has a state of 'SUCCEEDED' then we should move on to the next child.\n if (child.getState() === State.SUCCEEDED) {\n // Find out if the current child is the last one in the sequence.\n // If it is then this sequence node has also succeeded.\n if (this.children.indexOf(child) === this.children.length - 1) {\n // This node is a 'SUCCEEDED' node.\n this.setState(State.SUCCEEDED);\n\n // There is no need to check the rest of the sequence as we have completed it.\n return;\n } else {\n // The child node succeeded, but we have not finished the sequence yet.\n continue;\n }\n }\n\n // If the current child has a state of 'FAILED' then this node is also a 'FAILED' node.\n if (child.getState() === State.FAILED) {\n // This node is a 'FAILED' node.\n this.setState(State.FAILED);\n\n // There is no need to check the rest of the sequence.\n return;\n }\n\n // The node should be in the 'RUNNING' state.\n if (child.getState() === State.RUNNING) {\n // This node is a 'RUNNING' node.\n this.setState(State.RUNNING);\n\n // There is no need to check the rest of the sequence as the current child is still running.\n return;\n }\n\n // The child node was not in an expected state.\n throw new Error(\"child node was not in an expected state.\");\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => \"SEQUENCE\";\n}\n", "import createLotto from \"lotto-draw\";\n\nimport Node from \"../Node\";\nimport Composite from \"./Composite\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A LOTTO node.\n * A winning child is picked on the initial update of this node, based on ticket weighting.\n * The state of this node will match the state of the winning child.\n */\nexport default class Lotto extends Composite {\n /**\n * @param attributes The node attributes.\n * @param weights The child node weights.\n * @param children The child nodes.\n */\n constructor(attributes: Attribute[], private weights: number[] | undefined, children: Node[]) {\n super(\"lotto\", attributes, children);\n }\n\n /**\n * The child node selected to be the active one.\n */\n private selectedChild: Node | undefined;\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // If this node is in the READY state then we need to pick a winning child node.\n if (this.is(State.READY)) {\n // Create a lotto draw with which to randomly pick a child node to become the active one.\n const lottoDraw = createLotto({\n // Hook up the optional 'random' behaviour tree function option to the one used by 'lotto-draw'.\n random: options.random,\n // Pass in each child node as a participant in the lotto draw with their respective ticket count.\n participants: this.children.map((child, index) => [child, this.weights?.[index] || 1])\n });\n\n // Randomly pick a child based on ticket weighting, this will become the active child for this composite node.\n this.selectedChild = lottoDraw.draw() || undefined;\n }\n\n // If something went wrong and we don't have an active child then we should throw an error.\n if (!this.selectedChild) {\n throw new Error(\"failed to update lotto node as it has no active child\");\n }\n\n // If the selected child has never been updated or is running then we will need to update it now.\n if (this.selectedChild.getState() === State.READY || this.selectedChild.getState() === State.RUNNING) {\n this.selectedChild.update(agent, options);\n }\n\n // The state of the lotto node is the state of its selected child.\n this.setState(this.selectedChild.getState());\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => (this.weights ? `LOTTO [${this.weights.join(\",\")}]` : \"LOTTO\");\n}\n", "import Node from \"../Node\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\n\n/**\n * A decorator node that wraps a single child node.\n */\nexport default abstract class Decorator extends Node {\n /**\n * @param type The node type.\n * @param attributes The node attributes.\n * @param child The child node.\n */\n constructor(type: string, attributes: Attribute[], protected child: Node) {\n super(type, attributes, []);\n }\n\n /**\n * Gets whether this node is a leaf node.\n */\n isLeafNode = () => false;\n\n /**\n * Gets the children of this node.\n */\n getChildren = () => [this.child];\n\n /**\n * Reset the state of the node.\n */\n reset = () => {\n // Reset the state of this node.\n this.setState(State.READY);\n\n // Reset the state of the child node.\n this.child.reset();\n };\n\n /**\n * Abort the running of this node.\n * @param agent The agent.\n */\n abort = (agent: Agent) => {\n // There is nothing to do if this node is not in the running state.\n if (!this.is(State.RUNNING)) {\n return;\n }\n\n // Abort the child node.\n this.child.abort(agent);\n\n // Reset the state of this node.\n this.reset();\n\n this.getAttribute(\"exit\")?.callAgentFunction(agent, false, true);\n };\n}\n", "import Node from \"../Node\";\nimport Decorator from \"./Decorator\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A Fail node.\n * This node wraps a single child and will always move to the 'FAILED' state when the child moves to a 'SUCCEEDED' or 'FAILED' state.\n */\nexport default class Fail extends Decorator {\n /**\n * @param attributes The node attributes.\n * @param child The child node.\n */\n constructor(attributes: Attribute[], child: Node) {\n super(\"fail\", attributes, child);\n }\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // If the child has never been updated or is running then we will need to update it now.\n if (this.child.getState() === State.READY || this.child.getState() === State.RUNNING) {\n this.child.update(agent, options);\n }\n\n // The state of this node will depend in the state of its child.\n switch (this.child.getState()) {\n case State.RUNNING:\n this.setState(State.RUNNING);\n break;\n\n case State.SUCCEEDED:\n case State.FAILED:\n this.setState(State.FAILED);\n break;\n\n default:\n this.setState(State.READY);\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => \"FAIL\";\n}\n", "import Decorator from \"./Decorator\";\nimport State from \"../../State\";\nimport Node from \"../Node\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A Flip node.\n * This node wraps a single child and will flip the state of the child state.\n */\nexport default class Flip extends Decorator {\n /**\n * @param attributes The node attributes.\n * @param child The child node.\n */\n constructor(attributes: Attribute[], child: Node) {\n super(\"flip\", attributes, child);\n }\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // If the child has never been updated or is running then we will need to update it now.\n if (this.child.getState() === State.READY || this.child.getState() === State.RUNNING) {\n this.child.update(agent, options);\n }\n\n // The state of this node will depend in the state of its child.\n switch (this.child.getState()) {\n case State.RUNNING:\n this.setState(State.RUNNING);\n break;\n\n case State.SUCCEEDED:\n this.setState(State.FAILED);\n break;\n\n case State.FAILED:\n this.setState(State.SUCCEEDED);\n break;\n\n default:\n this.setState(State.READY);\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => \"FLIP\";\n}\n", "import Node from \"../Node\";\nimport Decorator from \"./Decorator\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A REPEAT node.\n * The node has a single child which can have:\n * -- A number of iterations for which to repeat the child node.\n * -- An infinite repeat loop if neither an iteration count or a condition function is defined.\n * The REPEAT node will stop and have a 'FAILED' state if its child is ever in a 'FAILED' state after an update.\n * The REPEAT node will attempt to move on to the next iteration if its child is ever in a 'SUCCEEDED' state.\n */\nexport default class Repeat extends Decorator {\n /**\n * @param attributes The node attributes.\n * @param iterations The number of iterations to repeat the child node.\n * @param iterationsMin The minimum possible number of iterations to repeat the child node.\n * @param iterationsMax The maximum possible number of iterations to repeat the child node.\n * @param child The child node.\n */\n constructor(\n attributes: Attribute[],\n private iterations: number | null,\n private iterationsMin: number | null,\n private iterationsMax: number | null,\n child: Node\n ) {\n super(\"repeat\", attributes, child);\n }\n\n /**\n * The number of target iterations to make.\n */\n private targetIterationCount: number | null = null;\n\n /**\n * The current iteration count.\n */\n private currentIterationCount: number = 0;\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // If this node is in the READY state then we need to reset the child and the target iteration count.\n if (this.is(State.READY)) {\n // Reset the child node.\n this.child.reset();\n\n // Reset the current iteration count.\n this.currentIterationCount = 0;\n\n // Set the target iteration count.\n this.setTargetIterationCount(options);\n }\n\n // Do a check to see if we can iterate. If we can then this node will move into the 'RUNNING' state.\n // If we cannot iterate then we have hit our target iteration count, which means that the node has succeeded.\n if (this.canIterate()) {\n // This node is in the running state and can do its initial iteration.\n this.setState(State.RUNNING);\n\n // We may have already completed an iteration, meaning that the child node will be in the SUCCEEDED state.\n // If this is the case then we will have to reset the child node now.\n if (this.child.getState() === State.SUCCEEDED) {\n this.child.reset();\n }\n\n // Update the child of this node.\n this.child.update(agent, options);\n\n // If the child moved into the FAILED state when we updated it then there is nothing left to do and this node has also failed.\n // If it has moved into the SUCCEEDED state then we have completed the current iteration.\n if (this.child.getState() === State.FAILED) {\n // The child has failed, meaning that this node has failed.\n this.setState(State.FAILED);\n\n return;\n } else if (this.child.getState() === State.SUCCEEDED) {\n // We have completed an iteration.\n this.currentIterationCount += 1;\n }\n } else {\n // This node is in the 'SUCCEEDED' state as we cannot iterate any more.\n this.setState(State.SUCCEEDED);\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => {\n if (this.iterations !== null) {\n return `REPEAT ${this.iterations}x`;\n } else if (this.iterationsMin !== null && this.iterationsMax !== null) {\n return `REPEAT ${this.iterationsMin}x-${this.iterationsMax}x`;\n } else {\n return \"REPEAT\";\n }\n };\n\n /**\n * Reset the state of the node.\n */\n reset = () => {\n // Reset the state of this node.\n this.setState(State.READY);\n\n // Reset the current iteration count.\n this.currentIterationCount = 0;\n\n // Reset the child node.\n this.child.reset();\n };\n\n /**\n * Gets whether an iteration can be made.\n * @returns Whether an iteration can be made.\n */\n private canIterate = () => {\n if (this.targetIterationCount !== null) {\n // We can iterate as long as we have not reached our target iteration count.\n return this.currentIterationCount < this.targetIterationCount;\n }\n\n // If neither an iteration count or a condition function were defined then we can iterate indefinitely.\n return true;\n };\n\n /**\n * Sets the target iteration count.\n * @param options The behaviour tree options object.\n */\n private setTargetIterationCount = (options: BehaviourTreeOptions) => {\n // Are we dealing with an explicit iteration count or will we be randomly picking a iteration count between the min and max iteration count.\n if (this.iterations !== null) {\n this.targetIterationCount = this.iterations;\n } else if (this.iterationsMin !== null && this.iterationsMax !== null) {\n // We will be picking a random iteration count between a min and max iteration count, if the optional 'random'\n // behaviour tree function option is defined then we will be using that, otherwise we will fall back to using Math.random.\n const random = typeof options.random === \"function\" ? options.random : Math.random;\n\n // Pick a random iteration count between a min and max iteration count.\n this.targetIterationCount = Math.floor(\n random() * (this.iterationsMax - this.iterationsMin + 1) + this.iterationsMin\n );\n } else {\n this.targetIterationCount = null;\n }\n };\n}\n", "import Node from \"../Node\";\nimport Decorator from \"./Decorator\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A RETRY node.\n * The node has a single child which can have:\n * -- A number of iterations for which to repeat the child node.\n * -- An infinite repeat loop if neither an iteration count or a condition function is defined.\n * The RETRY node will stop and have a 'SUCCEEDED' state if its child is ever in a 'SUCCEEDED' state after an update.\n * The RETRY node will attempt to move on to the next iteration if its child is ever in a 'FAILED' state.\n */\nexport default class Retry extends Decorator {\n /**\n * @param attributes The node attributes.\n * @param attempts The number of attempts to retry the child node.\n * @param attemptsMin The minimum possible number of attempts to retry the child node.\n * @param attemptsMax The maximum possible number of attempts to retry the child node.\n * @param child The child node.\n */\n constructor(\n attributes: Attribute[],\n private attempts: number | null,\n private attemptsMin: number | null,\n private attemptsMax: number | null,\n child: Node\n ) {\n super(\"retry\", attributes, child);\n }\n\n /**\n * The number of target attempts to make.\n */\n private targetAttemptCount: number | null = null;\n\n /**\n * The current attempt count.\n */\n private currentAttemptCount: number = 0;\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // If this node is in the READY state then we need to reset the child and the target attempt count.\n if (this.is(State.READY)) {\n // Reset the child node.\n this.child.reset();\n\n // Reset the current attempt count.\n this.currentAttemptCount = 0;\n\n // Set the target attempt count.\n this.setTargetAttemptCount(options);\n }\n\n // Do a check to see if we can attempt. If we can then this node will move into the 'RUNNING' state.\n // If we cannot attempt then we have hit our target attempt count, which means that the node has succeeded.\n if (this.canAttempt()) {\n // This node is in the running state and can do its initial attempt.\n this.setState(State.RUNNING);\n\n // We may have already completed an attempt, meaning that the child node will be in the FAILED state.\n // If this is the case then we will have to reset the child node now.\n if (this.child.getState() === State.FAILED) {\n this.child.reset();\n }\n\n // Update the child of this node.\n this.child.update(agent, options);\n\n // If the child moved into the SUCCEEDED state when we updated it then there is nothing left to do and this node has also succeeded.\n // If it has moved into the FAILED state then we have completed the current attempt.\n if (this.child.getState() === State.SUCCEEDED) {\n // The child has succeeded, meaning that this node has succeeded.\n this.setState(State.SUCCEEDED);\n\n return;\n } else if (this.child.getState() === State.FAILED) {\n // We have completed an attempt.\n this.currentAttemptCount += 1;\n }\n } else {\n // This node is in the 'FAILED' state as we cannot iterate any more.\n this.setState(State.FAILED);\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => {\n if (this.attempts !== null) {\n return `RETRY ${this.attempts}x`;\n } else if (this.attemptsMin !== null && this.attemptsMax !== null) {\n return `RETRY ${this.attemptsMin}x-${this.attemptsMax}x`;\n } else {\n return \"RETRY\";\n }\n };\n\n /**\n * Reset the state of the node.\n */\n reset = () => {\n // Reset the state of this node.\n this.setState(State.READY);\n\n // Reset the current attempt count.\n this.currentAttemptCount = 0;\n\n // Reset the child node.\n this.child.reset();\n };\n\n /**\n * Gets whether an attempt can be made.\n * @returns Whether an attempt can be made.\n */\n canAttempt = () => {\n if (this.targetAttemptCount !== null) {\n // We can attempt as long as we have not reached our target attempt count.\n return this.currentAttemptCount < this.targetAttemptCount;\n }\n\n // If neither an attempt count or a condition function were defined then we can attempt indefinitely.\n return true;\n };\n\n /**\n * Sets the target attempt count.\n * @param options The behaviour tree options object.\n */\n setTargetAttemptCount = (options: BehaviourTreeOptions) => {\n // Are we dealing with an explicit attempt count or will we be randomly picking an attempt count between the min and max attempt count.\n if (this.attempts !== null) {\n this.targetAttemptCount = this.attempts;\n } else if (this.attemptsMin !== null && this.attemptsMax !== null) {\n // We will be picking a random attempt count between a min and max attempt count, if the optional 'random'\n // behaviour tree function option is defined then we will be using that, otherwise we will fall back to using Math.random.\n const random = typeof options.random === \"function\" ? options.random : Math.random;\n\n // Pick a random attempt count between a min and max attempt count.\n this.targetAttemptCount = Math.floor(\n random() * (this.attemptsMax - this.attemptsMin + 1) + this.attemptsMin\n );\n } else {\n this.targetAttemptCount = null;\n }\n };\n}\n", "import Node from \"../Node\";\nimport Decorator from \"./Decorator\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A Root node.\n * The root node will have a single child.\n */\nexport default class Root extends Decorator {\n /**\n * @param attributes The node attributes.\n * @param child The child node.\n */\n constructor(attributes: Attribute[], child: Node) {\n super(\"root\", attributes, child);\n }\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // If the child has never been updated or is running then we will need to update it now.\n if (this.child.getState() === State.READY || this.child.getState() === State.RUNNING) {\n // Update the child of this node.\n this.child.update(agent, options);\n }\n\n // The state of the root node is the state of its child.\n this.setState(this.child.getState());\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => \"ROOT\";\n}\n", "import Node from \"../Node\";\nimport Decorator from \"./Decorator\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A Succeed node.\n * This node wraps a single child and will always move to the 'SUCCEEDED' state when the child moves to a 'SUCCEEDED' or 'FAILED' state.\n */\nexport default class Succeed extends Decorator {\n /**\n * @param attributes The node attributes.\n * @param child The child node.\n */\n constructor(attributes: Attribute[], child: Node) {\n super(\"succeed\", attributes, child);\n }\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // If the child has never been updated or is running then we will need to update it now.\n if (this.child.getState() === State.READY || this.child.getState() === State.RUNNING) {\n this.child.update(agent, options);\n }\n\n // The state of this node will depend in the state of its child.\n switch (this.child.getState()) {\n case State.RUNNING:\n this.setState(State.RUNNING);\n break;\n\n case State.SUCCEEDED:\n case State.FAILED:\n this.setState(State.SUCCEEDED);\n break;\n\n default:\n this.setState(State.READY);\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => \"SUCCEED\";\n}\n", "import Node from \"../Node\";\n\n/**\n * A leaf node.\n */\nexport default abstract class Leaf extends Node {\n /**\n * Gets whether this node is a leaf node.\n */\n isLeafNode = () => true;\n}\n", "import { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\nimport State, { CompleteState } from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Leaf from \"./Leaf\";\nimport Lookup from \"../../Lookup\";\nimport Attribute from \"../../attributes/Attribute\";\n\n/**\n * An Action leaf node.\n * This represents an immediate or ongoing state of behaviour.\n */\nexport default class Action extends Leaf {\n /**\n * @param attributes The node attributes.\n * @param actionName The action name.\n * @param actionArguments The array of action argument definitions.\n */\n constructor(attributes: Attribute[], private actionName: string, private actionArguments: any[]) {\n super(\"action\", attributes, actionArguments);\n }\n\n /**\n * Whether there is a pending update promise.\n */\n private isUsingUpdatePromise = false;\n\n /**\n * The finished state result of an update promise.\n */\n private updatePromiseStateResult: CompleteState | null = null;\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // If the result of this action depends on an update promise then there is nothing to do until\n // it resolves, unless there has been a value set as a result of the update promise resolving.\n if (this.isUsingUpdatePromise) {\n // Check whether the update promise has resolved with a state value.\n if (this.updatePromiseStateResult) {\n // Set the state of this node to match the state returned by the promise.\n this.setState(this.updatePromiseStateResult);\n }\n\n return;\n }\n\n // Attempt to get the invoker for the action function.\n const actionFuncInvoker = Lookup.getFuncInvoker(agent, this.actionName);\n\n // The action function should be defined.\n if (actionFuncInvoker === null) {\n throw new Error(\n `cannot update action node as the action '${this.actionName}' function is not defined on the agent and has not been registered`\n );\n }\n\n // Call the action function, the result of which may be:\n // - The finished state of this action node.\n // - A promise to return a finished node state.\n // - Undefined if the node should remain in the running state.\n const updateResult = actionFuncInvoker(this.actionArguments) as CompleteState | Promise;\n\n if (updateResult instanceof Promise) {\n updateResult.then(\n (result) => {\n // If 'isUpdatePromisePending' is null then the promise was cleared as it was resolving, probably via an abort of reset.\n if (!this.isUsingUpdatePromise) {\n return;\n }\n\n // Check to make sure the result is a valid finished state.\n if (result !== State.SUCCEEDED && result !== State.FAILED) {\n throw new Error(\n \"action node promise resolved with an invalid value, expected a State.SUCCEEDED or State.FAILED value to be returned\"\n );\n }\n\n // Set pending update promise state result to be processed on next update.\n this.updatePromiseStateResult = result;\n },\n (reason) => {\n // If 'isUpdatePromisePending' is null then the promise was cleared as it was resolving, probably via an abort of reset.\n if (!this.isUsingUpdatePromise) {\n return;\n }\n\n // Just throw whatever was returned as the rejection argument.\n throw new Error(reason);\n }\n );\n\n // This node will be in the 'RUNNING' state until the update promise resolves.\n this.setState(State.RUNNING);\n\n // We are now waiting for the promise returned by the use to resolve before we know what state this node is in.\n this.isUsingUpdatePromise = true;\n } else {\n // Validate the returned value.\n this.validateUpdateResult(updateResult);\n\n // Set the state of this node, this may be undefined, which just means that the node is still in the 'RUNNING' state.\n this.setState(updateResult || State.RUNNING);\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => this.actionName;\n\n /**\n * Reset the state of the node.\n */\n reset = () => {\n // Reset the state of this node.\n this.setState(State.READY);\n\n // There is no longer an update promise that we care about.\n this.isUsingUpdatePromise = false;\n this.updatePromiseStateResult = null;\n };\n\n /**\n * Validate the result of an update function call.\n * @param result The result of an update function call.\n */\n private validateUpdateResult = (result: CompleteState | boolean) => {\n switch (result) {\n case State.SUCCEEDED:\n case State.FAILED:\n case undefined:\n return;\n default:\n throw new Error(\n `action '${this.actionName}' 'onUpdate' returned an invalid response, expected an optional State.SUCCEEDED or State.FAILED value to be returned`\n );\n }\n };\n}\n", "import { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Leaf from \"./Leaf\";\nimport Lookup from \"../../Lookup\";\nimport Attribute from \"../../attributes/Attribute\";\n\n/**\n * A Condition leaf node.\n * This will succeed or fail immediately based on an agent predicate, without moving to the 'RUNNING' state.\n */\nexport default class Condition extends Leaf {\n /**\n * @param attributes The node attributes.\n * @param conditionName The name of the condition function.\n * @param conditionArguments The array of condition argument definitions.\n */\n constructor(attributes: Attribute[], private conditionName: string, private conditionArguments: any[]) {\n super(\"condition\", attributes, conditionArguments);\n }\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // Attempt to get the invoker for the condition function.\n const conditionFuncInvoker = Lookup.getFuncInvoker(agent, this.conditionName);\n\n // The condition function should be defined.\n if (conditionFuncInvoker === null) {\n throw new Error(\n `cannot update condition node as the condition '${this.conditionName}' function is not defined on the agent and has not been registered`\n );\n }\n\n // Call the condition function to determine the state of this node.\n this.setState(!!conditionFuncInvoker(this.conditionArguments) ? State.SUCCEEDED : State.FAILED);\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => this.conditionName;\n}\n", "import Leaf from \"./Leaf\";\nimport State from \"../../State\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { Agent } from \"../../Agent\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A WAIT node.\n * The state of this node will change to SUCCEEDED after a duration of time\n */\nexport default class Wait extends Leaf {\n /**\n * @param attributes The node attributes.\n * @param duration The duration that this node will wait to succeed in milliseconds.\n * @param durationMin The minimum possible duration in milliseconds that this node will wait to succeed.\n * @param durationMax The maximum possible duration in milliseconds that this node will wait to succeed.\n */\n constructor(\n attributes: Attribute[],\n private duration: number | null,\n private durationMin: number | null,\n private durationMax: number | null\n ) {\n super(\"wait\", attributes, []);\n }\n\n /**\n * The time in milliseconds at which this node was first updated.\n */\n private initialUpdateTime: number = 0;\n\n /**\n * The total duration in milliseconds that this node will be waiting for.\n */\n private totalDuration: number | null = null;\n\n /**\n * The duration in milliseconds that this node has been waiting for.\n */\n private waitedDuration: number = 0;\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // If this node is in the READY state then we need to set the initial update time.\n if (this.is(State.READY)) {\n // Set the initial update time.\n this.initialUpdateTime = new Date().getTime();\n\n // Set the initial waited duration.\n this.waitedDuration = 0;\n\n // Are we dealing with an explicit duration or will we be randomly picking a duration between the min and max duration.\n if (this.duration !== null) {\n this.totalDuration = this.duration;\n } else if (this.durationMin !== null && this.durationMax !== null) {\n // We will be picking a random duration between a min and max duration, if the optional 'random' behaviour tree\n // function option is defined then we will be using that, otherwise we will fall back to using Math.random.\n const random = typeof options.random === \"function\" ? options.random : Math.random;\n\n // Pick a random duration between a min and max duration.\n this.totalDuration = Math.floor(\n random() * (this.durationMax - this.durationMin + 1) + this.durationMin\n );\n } else {\n this.totalDuration = null;\n }\n\n // The node is now running until we finish waiting.\n this.setState(State.RUNNING);\n }\n\n // If we have no total duration then this wait node will wait indefinitely until it is aborted.\n if (this.totalDuration === null) {\n return;\n }\n\n // If we have a 'getDeltaTime' function defined as part of our options then we will use it to figure out how long we have waited for.\n if (typeof options.getDeltaTime === \"function\") {\n // Get the delta time.\n const deltaTime = options.getDeltaTime();\n\n // Our delta time must be a valid number and cannot be NaN.\n if (typeof deltaTime !== \"number\" || isNaN(deltaTime)) {\n throw new Error(\"The delta time must be a valid number and not NaN.\");\n }\n\n // Update the amount of time that this node has been waiting for based on the delta time.\n this.waitedDuration += deltaTime * 1000;\n } else {\n // We are not using a delta time, so we will just work out hom much time has passed since the first update.\n this.waitedDuration = new Date().getTime() - this.initialUpdateTime;\n }\n\n // Have we waited long enough?\n if (this.waitedDuration >= this.totalDuration) {\n // We have finished waiting!\n this.setState(State.SUCCEEDED);\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => {\n if (this.duration !== null) {\n return `WAIT ${this.duration}ms`;\n } else if (this.durationMin !== null && this.durationMax !== null) {\n return `WAIT ${this.durationMin}ms-${this.durationMax}ms`;\n } else {\n return \"WAIT\";\n }\n };\n}\n", "import Guard from \"./guards/Guard\";\n\nexport type AttributeDetails = {\n /** The attribute type. */\n type: string;\n\n /** The attribute arguments. */\n args: any[];\n};\n\n/**\n * A base node attribute.\n */\nexport default abstract class Attribute {\n /**\n * @param type The node attribute type.\n * @param args The array of attribute arguments.\n */\n constructor(public type: string, public args: any[]) {}\n\n /**\n * Gets the attribute details.\n */\n abstract getDetails(): TAttributeDetails;\n\n /**\n * Gets whether this attribute is a guard.\n */\n abstract isGuard: () => this is Guard;\n}\n", "import { Agent } from \"../../Agent\";\nimport Attribute, { AttributeDetails } from \"../Attribute\";\n\nexport type GuardAttributeDetails = {\n /** The name of the condition function that determines whether the guard is satisfied. */\n condition: string;\n} & AttributeDetails;\n\n/**\n * A base node guard attribute.\n */\nexport default abstract class Guard extends Attribute {\n /**\n * @param type The node attribute type.\n * @param args The array of decorator argument definitions.\n * @param condition The name of the condition function that determines whether the guard is satisfied.\n */\n constructor(type: string, args: any[], private condition: string) {\n super(type, args);\n }\n\n /**\n * Gets the name of the condition function that determines whether the guard is satisfied.\n */\n getCondition = () => this.condition;\n\n /**\n * Gets whether this attribute is a guard.\n */\n isGuard = () => true;\n\n /**\n * Gets the attribute details.\n */\n getDetails(): GuardAttributeDetails {\n return {\n type: this.type,\n args: this.args,\n condition: this.getCondition()\n };\n }\n\n /**\n * Gets whether the guard is satisfied.\n * @param agent The agent.\n * @returns Whether the guard is satisfied.\n */\n abstract isSatisfied(agent: Agent): boolean;\n}\n", "import Guard from \"./Guard\";\nimport Lookup from \"../../Lookup\";\nimport { Agent } from \"../../Agent\";\n\n/**\n * A WHILE guard which is satisfied as long as the given condition remains true.\n */\nexport default class While extends Guard {\n /**\n * @param condition The name of the condition function that determines whether the guard is satisfied.\n * @param args The array of decorator argument definitions.\n */\n constructor(condition: string, args: any[]) {\n super(\"while\", args, condition);\n }\n\n /**\n * Gets whether the guard is satisfied.\n * @param agent The agent.\n * @returns Whether the guard is satisfied.\n */\n isSatisfied = (agent: Agent) => {\n // Attempt to get the invoker for the condition function.\n const conditionFuncInvoker = Lookup.getFuncInvoker(agent, this.getCondition());\n\n // The condition function should be defined.\n if (conditionFuncInvoker === null) {\n throw new Error(\n `cannot evaluate node guard as the condition '${this.getCondition()}' function is not defined on the agent and has not been registered`\n );\n }\n\n // Call the condition function to determine whether this guard is satisfied.\n return !!conditionFuncInvoker(this.args);\n };\n}\n", "import Guard from \"./Guard\";\nimport Lookup from \"../../Lookup\";\nimport { Agent } from \"../../Agent\";\n\n/**\n * An UNTIL guard which is satisfied as long as the given condition remains false.\n */\nexport default class Until extends Guard {\n /**\n * @param condition The name of the condition function that determines whether the guard is satisfied.\n * @param args The array of decorator argument definitions.\n */\n constructor(condition: string, args: any[]) {\n super(\"until\", args, condition);\n }\n\n /**\n * Gets whether the guard is satisfied.\n * @param agent The agent.\n * @returns Whether the guard is satisfied.\n */\n isSatisfied = (agent: Agent) => {\n // Attempt to get the invoker for the condition function.\n const conditionFuncInvoker = Lookup.getFuncInvoker(agent, this.getCondition());\n\n // The condition function should be defined.\n if (conditionFuncInvoker === null) {\n throw new Error(\n `cannot evaluate node guard as the condition '${this.getCondition()}' function is not defined on the agent and has not been registered`\n );\n }\n\n // Call the condition function to determine whether this guard is satisfied.\n return !!!conditionFuncInvoker(this.args);\n };\n}\n", "import { Agent } from \"../../Agent\";\nimport Attribute, { AttributeDetails } from \"../Attribute\";\n\nexport type CallbackAttributeDetails = {\n /** The name of the agent function that is called. */\n functionName: string;\n} & AttributeDetails;\n\n/**\n * A base node callback attribute.\n */\nexport default abstract class Callback extends Attribute {\n /**\n * @param type The node attribute type.\n * @param args The array of decorator argument definitions.\n * @param functionName The name of the agent function to call.\n */\n constructor(type: string, args: any[], private functionName: string) {\n super(type, args);\n }\n\n /**\n * Gets the name of the agent function to call.\n */\n getFunctionName = () => this.functionName;\n\n /**\n * Gets whether this attribute is a guard.\n */\n isGuard = () => false;\n\n /**\n * Gets the attribute details.\n */\n getDetails(): CallbackAttributeDetails {\n return {\n type: this.type,\n args: this.args,\n functionName: this.getFunctionName()\n };\n }\n\n /**\n * Attempt to call the agent function that this callback refers to.\n * @param agent The agent.\n */\n abstract callAgentFunction: (agent: Agent, isSuccess: boolean, isAborted: boolean) => void;\n}\n", "import Callback from \"./Callback\";\nimport Lookup from \"../../Lookup\";\nimport { Agent } from \"../../Agent\";\n\n/**\n * An ENTRY callback which defines an agent function to call when the associated node is updated and moves out of running state.\n */\nexport default class Entry extends Callback {\n /**\n * @param functionName The name of the agent function to call.\n * @param args The array of callback argument definitions.\n */\n constructor(functionName: string, args: any[]) {\n super(\"entry\", args, functionName);\n }\n\n /**\n * Attempt to call the agent function that this callback refers to.\n * @param agent The agent.\n */\n callAgentFunction = (agent: Agent) => {\n // Attempt to get the invoker for the callback function.\n const callbackFuncInvoker = Lookup.getFuncInvoker(agent, this.getFunctionName());\n\n // The callback function should be defined.\n if (callbackFuncInvoker === null) {\n throw new Error(\n `cannot call entry function '${this.getFunctionName()}' as is not defined on the agent and has not been registered`\n );\n }\n\n // Call the callback function.\n callbackFuncInvoker(this.args);\n };\n}\n", "import Callback from \"./Callback\";\nimport Lookup from \"../../Lookup\";\nimport { Agent } from \"../../Agent\";\n\n/**\n * A STEP callback which defines an agent function to call when the associated node is updated.\n */\nexport default class Step extends Callback {\n /**\n * @param functionName The name of the agent function to call.\n * @param args The array of callback argument definitions.\n */\n constructor(functionName: string, args: any[]) {\n super(\"step\", args, functionName);\n }\n\n /**\n * Attempt to call the agent function that this callback refers to.\n * @param agent The agent.\n */\n callAgentFunction = (agent: Agent) => {\n // Attempt to get the invoker for the callback function.\n const callbackFuncInvoker = Lookup.getFuncInvoker(agent, this.getFunctionName());\n\n // The callback function should be defined.\n if (callbackFuncInvoker === null) {\n throw new Error(\n `cannot call step function '${this.getFunctionName()}' as is not defined on the agent and has not been registered`\n );\n }\n\n // Call the callback function.\n callbackFuncInvoker(this.args);\n };\n}\n", "import Callback from \"./Callback\";\nimport Lookup from \"../../Lookup\";\nimport { Agent } from \"../../Agent\";\n\n/**\n * An EXIT callback which defines an agent function to call when the associated node is updated and moves to a finished state or is aborted.\n */\nexport default class Exit extends Callback {\n /**\n * @param functionName The name of the agent function to call.\n * @param args The array of callback argument definitions.\n */\n constructor(functionName: string, args: any[]) {\n super(\"exit\", args, functionName);\n }\n\n /**\n * Attempt to call the agent function that this callback refers to.\n * @param agent The agent.\n * @param isSuccess Whether the decorated node was left with a success state.\n * @param isAborted Whether the decorated node was aborted.\n */\n callAgentFunction = (agent: Agent, isSuccess: boolean, isAborted: boolean) => {\n // Attempt to get the invoker for the callback function.\n const callbackFuncInvoker = Lookup.getFuncInvoker(agent, this.getFunctionName());\n\n // The callback function should be defined.\n if (callbackFuncInvoker === null) {\n throw new Error(\n `cannot call exit function '${this.getFunctionName()}' as is not defined on the agent and has not been registered`\n );\n }\n\n // Call the callback function\n callbackFuncInvoker([{ value: { succeeded: isSuccess, aborted: isAborted } }, ...this.args]);\n };\n}\n", "import { AnyNodeDefinition, RootNodeDefinition } from \"./BehaviourTreeDefinition\";\nimport GuardPath, { GuardPathPart } from \"./attributes/guards/GuardPath\";\nimport { validateBranchSubtreeLinks } from \"./BehaviourTreeDefinitionValidator\";\nimport { isInteger } from \"./BehaviourTreeDefinitionUtilities\";\nimport Node from \"./nodes/Node\";\nimport Composite from \"./nodes/composite/Composite\";\nimport Decorator from \"./nodes/decorator/Decorator\";\nimport Parallel from \"./nodes/composite/Parallel\";\nimport Selector from \"./nodes/composite/Selector\";\nimport Sequence from \"./nodes/composite/Sequence\";\nimport Lotto from \"./nodes/composite/Lotto\";\nimport Fail from \"./nodes/decorator/Fail\";\nimport Flip from \"./nodes/decorator/Flip\";\nimport Repeat from \"./nodes/decorator/Repeat\";\nimport Retry from \"./nodes/decorator/Retry\";\nimport Root from \"./nodes/decorator/Root\";\nimport Succeed from \"./nodes/decorator/Succeed\";\nimport Action from \"./nodes/leaf/Action\";\nimport Condition from \"./nodes/leaf/Condition\";\nimport Wait from \"./nodes/leaf/Wait\";\nimport Lookup from \"./Lookup\";\nimport Attribute from \"./attributes/Attribute\";\nimport While from \"./attributes/guards/While\";\nimport Until from \"./attributes/guards/Until\";\nimport Entry from \"./attributes/callbacks/Entry\";\nimport Step from \"./attributes/callbacks/Step\";\nimport Exit from \"./attributes/callbacks/Exit\";\n\n/**\n * A type representing any node instance in a behaviour tree.\n */\ntype AnyNode =\n | Root\n | Action\n | Condition\n | Wait\n | Sequence\n | Selector\n | Lotto\n | Parallel\n | Repeat\n | Retry\n | Flip\n | Succeed\n | Fail;\n\n/**\n * A type defining a mapping of root node identifiers to root node definitions.\n */\ntype RootNodeDefinitionMap = { [key: string | symbol]: RootNodeDefinition };\n\n/**\n * A symbol to use as the main root key in any root node mappings.\n */\nconst MAIN_ROOT_NODE_KEY = Symbol(\"__root__\");\n\n/**\n * Build and populate the root nodes based on the provided definition, assuming that the definition has been validated.\n * @param definition The root node definitions.\n * @returns The built and populated root node definitions.\n */\nexport default function buildRootNode(definition: RootNodeDefinition[]): Root {\n // Create a mapping of root node identifers to root node definitions, including globally registered subtree root node definitions.\n const rootNodeDefinitionMap = createRootNodeDefinitionMap(definition);\n\n // Now that we have all of our root node definitons (those part of the tree definition and those globally\n // registered) we should validate the definition. This will also double-check that we dont have any circular\n // dependencies in our branch -> subtree references and that we have no broken branch -> subtree links.\n validateBranchSubtreeLinks(definition, true);\n\n // Create our populated tree of node instances, starting with our main root node.\n const rootNode = nodeFactory(rootNodeDefinitionMap[MAIN_ROOT_NODE_KEY], rootNodeDefinitionMap) as Root;\n\n // Set a guard path on every leaf of the tree to evaluate as part of each update.\n applyLeafNodeGuardPaths(rootNode);\n\n // We only need to return the main root node.\n return rootNode;\n}\n\n/**\n * A factory function which creates a node instance based on the specified definition.\n * @param definition The node definition.\n * @param rootNodeDefinitionMap The mapping of root node identifers to root node definitions, including globally registered subtree root node definitions.\n * @returns A node instance based on the specified definition.\n */\nfunction nodeFactory(definition: AnyNodeDefinition, rootNodeDefinitionMap: RootNodeDefinitionMap): AnyNode {\n // Get the attributes for the node.\n const attributes = nodeAttributesFactory(definition);\n\n // Create the node instance based on the definition type.\n switch (definition.type) {\n case \"root\":\n return new Root(attributes, nodeFactory(definition.child, rootNodeDefinitionMap));\n\n case \"repeat\":\n let iterations: number | null = null;\n let iterationsMin: number | null = null;\n let iterationsMax: number | null = null;\n\n if (Array.isArray(definition.iterations)) {\n iterationsMin = definition.iterations[0];\n iterationsMax = definition.iterations[1];\n } else if (isInteger(definition.iterations)) {\n iterations = definition.iterations!;\n }\n\n return new Repeat(\n attributes,\n iterations,\n iterationsMin,\n iterationsMax,\n nodeFactory(definition.child, rootNodeDefinitionMap)\n );\n\n case \"retry\":\n let attempts: number | null = null;\n let attemptsMin: number | null = null;\n let attemptsMax: number | null = null;\n\n if (Array.isArray(definition.attempts)) {\n attemptsMin = definition.attempts[0];\n attemptsMax = definition.attempts[1];\n } else if (isInteger(definition.attempts)) {\n attempts = definition.attempts!;\n }\n\n return new Retry(\n attributes,\n attempts,\n attemptsMin,\n attemptsMax,\n nodeFactory(definition.child, rootNodeDefinitionMap)\n );\n\n case \"flip\":\n return new Flip(attributes, nodeFactory(definition.child, rootNodeDefinitionMap));\n\n case \"succeed\":\n return new Succeed(attributes, nodeFactory(definition.child, rootNodeDefinitionMap));\n\n case \"fail\":\n return new Fail(attributes, nodeFactory(definition.child, rootNodeDefinitionMap));\n\n case \"sequence\":\n return new Sequence(\n attributes,\n definition.children.map((child) => nodeFactory(child, rootNodeDefinitionMap))\n );\n\n case \"selector\":\n return new Selector(\n attributes,\n definition.children.map((child) => nodeFactory(child, rootNodeDefinitionMap))\n );\n\n case \"parallel\":\n return new Parallel(\n attributes,\n definition.children.map((child) => nodeFactory(child, rootNodeDefinitionMap))\n );\n\n case \"lotto\":\n return new Lotto(\n attributes,\n definition.weights,\n definition.children.map((child) => nodeFactory(child, rootNodeDefinitionMap))\n );\n\n case \"branch\":\n return nodeFactory(rootNodeDefinitionMap[definition.ref].child, rootNodeDefinitionMap);\n\n case \"action\":\n return new Action(attributes, definition.call, definition.args || []);\n\n case \"condition\":\n return new Condition(attributes, definition.call, definition.args || []);\n\n case \"wait\":\n let duration: number | null = null;\n let durationMin: number | null = null;\n let durationMax: number | null = null;\n\n if (Array.isArray(definition.duration)) {\n durationMin = definition.duration[0];\n durationMax = definition.duration[1];\n } else if (isInteger(definition.duration)) {\n duration = definition.duration!;\n }\n\n return new Wait(attributes, duration, durationMin, durationMax);\n }\n}\n\n/**\n * Creates an array of node attribute instances based on the specified node definition.\n * @param definition The node definition.\n * @returns An array of node attribute instances based on the specified node definition.\n */\nfunction nodeAttributesFactory(definition: AnyNodeDefinition): Attribute[] {\n const attributes: Attribute[] = [];\n\n if (definition.while) {\n attributes.push(new While(definition.while.call, definition.while.args ?? []));\n }\n\n if (definition.until) {\n attributes.push(new Until(definition.until.call, definition.until.args ?? []));\n }\n\n if (definition.entry) {\n attributes.push(new Entry(definition.entry.call, definition.entry.args ?? []));\n }\n\n if (definition.step) {\n attributes.push(new Step(definition.step.call, definition.step.args ?? []));\n }\n\n if (definition.exit) {\n attributes.push(new Exit(definition.exit.call, definition.exit.args ?? []));\n }\n\n return attributes;\n}\n\n/**\n * Creates a mapping of root node identifers to root node definitions, mixing in globally registered subtree root node definitions.\n * @param definition The root node definitions.\n * @returns A mapping of root node identifers to root node definitions, including globally registered subtree root node definitions.\n */\nfunction createRootNodeDefinitionMap(definition: RootNodeDefinition[]): RootNodeDefinitionMap {\n // Create a mapping of root node identifers to root node definitions.\n const rootNodeMap: RootNodeDefinitionMap = {};\n\n // Add in any registered subtree root node definitions.\n for (const [name, rootNodeDefinition] of Object.entries(Lookup.getSubtrees())) {\n // The name used when registering the subtree will be used as the root node identifier.\n rootNodeMap[name] = { ...rootNodeDefinition, id: name };\n }\n\n // Populate the map with the root node definitions that were included with the tree definition.\n // We do this after adding any registered subtrees as we want these to take presedence.\n for (const rootNodeDefinition of definition) {\n rootNodeMap[rootNodeDefinition.id ?? MAIN_ROOT_NODE_KEY] = rootNodeDefinition;\n }\n\n return rootNodeMap;\n}\n\n/**\n * Applies a guard path to every leaf of the tree to evaluate as part of each update.\n * @param root The main root tree node.\n */\nfunction applyLeafNodeGuardPaths(root: Root) {\n const nodePaths: Node[][] = [];\n\n const findLeafNodes = (path: Node[], node: Node) => {\n // Add the current node to the path.\n path = path.concat(node);\n\n // Check whether the current node is a leaf node.\n if (node.isLeafNode()) {\n nodePaths.push(path);\n } else {\n (node as Composite | Decorator).getChildren().forEach((child) => findLeafNodes(path, child));\n }\n };\n\n // Find all leaf node paths, starting from the root.\n findLeafNodes([], root);\n\n nodePaths.forEach((path) => {\n // Each node in the current path will have to be assigned a guard path, working from the root outwards.\n for (let depth = 0; depth < path.length; depth++) {\n // Get the node in the path at the current depth.\n const currentNode = path[depth];\n\n // The node may already have been assigned a guard path, if so just skip it.\n if (currentNode.hasGuardPath()) {\n continue;\n }\n\n // Create the guard path for the current node.\n const guardPath = new GuardPath(\n path\n .slice(0, depth + 1)\n .map((node) => ({ node, guards: node.getGuardAttributes() }))\n .filter((details) => details.guards.length > 0)\n );\n\n // Assign the guard path to the current node.\n currentNode.setGuardPath(guardPath);\n }\n });\n}\n", "import State, { AnyState } from \"./State\";\nimport Lookup from \"./Lookup\";\nimport Node from \"./nodes/Node\";\nimport Root from \"./nodes/decorator/Root\";\nimport Composite from \"./nodes/composite/Composite\";\nimport Decorator from \"./nodes/decorator/Decorator\";\nimport { Agent, GlobalFunction } from \"./Agent\";\nimport { CallbackAttributeDetails } from \"./attributes/callbacks/Callback\";\nimport { GuardAttributeDetails } from \"./attributes/guards/Guard\";\nimport { BehaviourTreeOptions } from \"./BehaviourTreeOptions\";\nimport { convertMDSLToJSON } from \"./mdsl/MDSLDefinitionParser\";\nimport { RootNodeDefinition } from \"./BehaviourTreeDefinition\";\nimport { validateJSONDefinition } from \"./BehaviourTreeDefinitionValidator\";\nimport buildRootNode from \"./BehaviourTreeBuilder\";\n\n// Purely for outside inspection of the tree.\nexport type FlattenedTreeNode = {\n id: string;\n type: string;\n caption: string;\n state: AnyState;\n guards: GuardAttributeDetails[];\n callbacks: CallbackAttributeDetails[];\n args: any[];\n parentId: string | null;\n};\n\n/**\n * A representation of a behaviour tree.\n */\nexport class BehaviourTree {\n /**\n * The main root tree node.\n */\n public readonly rootNode: Root;\n\n /**\n * Creates a new instance of the BehaviourTree class.\n * @param definition The behaviour tree definition.\n * @param agent The agent instance that this behaviour tree is modelling behaviour for.\n * @param options The behaviour tree options object.\n */\n constructor(\n definition: string | RootNodeDefinition | RootNodeDefinition[],\n private agent: Agent,\n private options: BehaviourTreeOptions = {}\n ) {\n // The tree definition must be defined.\n if (!definition) {\n throw new Error(\"the tree definition must be a string ro\");\n }\n\n // The agent must be defined and not null.\n if (typeof agent !== \"object\" || agent === null) {\n throw new Error(\"the agent must be defined and not null\");\n }\n\n try {\n // Parse the behaviour tree definition, create the populated tree of behaviour tree nodes, and get the root.\n this.rootNode = this._createRootNode(definition);\n } catch (exception) {\n // There was an issue in trying build and populate the behaviour tree.\n throw new Error(`error building tree: ${(exception as Error).message}`);\n }\n }\n\n /**\n * Gets whether the tree is in the RUNNING state.\n * @returns true if the tree is in the RUNNING state, otherwise false.\n */\n isRunning() {\n return this.rootNode.getState() === State.RUNNING;\n }\n\n /**\n * Gets the current tree state of SUCCEEDED, FAILED, READY or RUNNING.\n * @returns The current tree state.\n */\n getState() {\n return this.rootNode.getState();\n }\n\n /**\n * Step the tree.\n * 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.\n * 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\n * 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.\n *\n * 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.\n */\n step() {\n // If the root node has already been stepped to completion then we need to reset it.\n if (this.rootNode.getState() === State.SUCCEEDED || this.rootNode.getState() === State.FAILED) {\n this.rootNode.reset();\n }\n\n try {\n this.rootNode.update(this.agent, this.options);\n } catch (exception) {\n throw new Error(`error stepping tree: ${(exception as Error).message}`);\n }\n }\n\n /**\n * Resets the tree from the root node outwards to each nested node, giving each a state of READY.\n */\n reset() {\n this.rootNode.reset();\n }\n\n /**\n * Gets the flattened details of every node in the tree.\n * @returns The flattened details of every node in the tree.\n */\n getFlattenedNodeDetails(): FlattenedTreeNode[] {\n // Create an empty flattened array of tree nodes.\n const flattenedTreeNodes: FlattenedTreeNode[] = [];\n\n /**\n * Helper function to process a node instance and push details into the flattened tree nodes array.\n * @param node The current node.\n * @param parentUid The UID of the node parent, or null if the node is the main root node.\n */\n const processNode = (node: Node, parentUid: string | null) => {\n // Get the guard and callback attribute details for this node.\n const guards = node\n .getAttributes()\n .filter((attribute) => attribute.isGuard())\n .map((attribute) => attribute.getDetails()) as GuardAttributeDetails[];\n const callbacks = node\n .getAttributes()\n .filter((attribute) => !attribute.isGuard())\n .map((attribute) => attribute.getDetails()) as CallbackAttributeDetails[];\n\n // Push the current node into the flattened nodes array.\n flattenedTreeNodes.push({\n id: node.getUid(),\n type: node.getType(),\n caption: node.getName(),\n state: node.getState(),\n guards,\n callbacks,\n args: node.getArguments(),\n parentId: parentUid\n });\n\n // Process each of the nodes children if it is not a leaf node.\n if (!node.isLeafNode()) {\n (node as Composite | Decorator)\n .getChildren()\n .forEach((child) => processNode(child, (node as Composite | Decorator).getUid()));\n }\n };\n\n // Convert the nested node structure into a flattened array of node details.\n processNode(this.rootNode, null);\n\n return flattenedTreeNodes;\n }\n\n /**\n * Registers the action/condition/guard/callback function or subtree with the given name.\n * @param name The name of the function or subtree to register.\n * @param value The function or subtree definition to register.\n */\n static register(name: string, value: GlobalFunction | string | RootNodeDefinition) {\n // Are we going to register a action/condition/guard/callback function?\n if (typeof value === \"function\") {\n Lookup.setFunc(name, value);\n return;\n }\n\n // We are not registering an action/condition/guard/callback function, so we must be registering a subtree.\n if (typeof value === \"string\") {\n let rootNodeDefinitions: RootNodeDefinition[];\n\n // We will assume that any string passed in will be a mdsl definition.\n try {\n rootNodeDefinitions = convertMDSLToJSON(value);\n } catch (exception) {\n throw new Error(`error registering definition, invalid MDSL: ${(exception as Error).message}`);\n }\n\n // This function should only ever be called with a definition containing a single unnamed root node.\n if (rootNodeDefinitions.length != 1 || rootNodeDefinitions[0].id !== null) {\n throw new Error(\"error registering definition: expected a single unnamed root node\");\n }\n\n try {\n // We should validate the subtree as we don't want invalid subtrees available via the lookup.\n const { succeeded, errorMessage } = validateJSONDefinition(rootNodeDefinitions[0]);\n\n // Did our validation fail without error?\n if (!succeeded) {\n throw new Error(errorMessage);\n }\n } catch (exception) {\n throw new Error(`error registering definition: ${(exception as Error).message}`);\n }\n\n // Everything seems hunky-dory, register the subtree.\n Lookup.setSubtree(name, rootNodeDefinitions[0]);\n } else if (typeof value === \"object\" && !Array.isArray(value)) {\n // We will assume that any object passed in is a root node definition.\n\n try {\n // We should validate the subtree as we don't want invalid subtrees available via the lookup.\n const { succeeded, errorMessage } = validateJSONDefinition(value);\n\n // Did our validation fail without error?\n if (!succeeded) {\n throw new Error(errorMessage);\n }\n } catch (exception) {\n throw new Error(`error registering definition: ${(exception as Error).message}`);\n }\n\n // Everything seems hunky-dory, register the subtree.\n Lookup.setSubtree(name, value);\n } else {\n throw new Error(\"unexpected value, expected string mdsl definition, root node json definition or function\");\n }\n }\n\n /**\n * Unregisters the registered action/condition/guard/callback function or subtree with the given name.\n * @param name The name of the registered action/condition/guard/callback function or subtree to unregister.\n */\n static unregister(name: string): void {\n Lookup.remove(name);\n }\n\n /**\n * Unregister all registered action/condition/guard/callback functions and subtrees.\n */\n static unregisterAll(): void {\n Lookup.empty();\n }\n\n /**\n * Parses a behaviour tree definition and creates a tree of behaviour tree nodes populated at a root.\n * @param {string | RootNodeDefinition | RootNodeDefinition[]} definition The behaviour tree definition.\n * @returns The root behaviour tree node.\n */\n private _createRootNode(definition: string | RootNodeDefinition | RootNodeDefinition[]): Root {\n let resolvedDefinition: RootNodeDefinition | RootNodeDefinition[];\n\n // If the definition is a string then we will assume that it is an mdsl string which needs to be converted to a JSON definition.\n if (typeof definition === \"string\") {\n try {\n resolvedDefinition = convertMDSLToJSON(definition);\n } catch (exception) {\n throw new Error(`invalid mdsl definition: ${(exception as Error).message}`);\n }\n } else {\n // The definition is not a string, so we should assume that it is already a JSON definition.\n resolvedDefinition = definition;\n }\n\n // Build and populate the root node.\n return buildRootNode(Array.isArray(resolvedDefinition) ? resolvedDefinition : [resolvedDefinition]);\n }\n}\n"], - "mappings": "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", + "sourcesContent": ["\"use strict\";\r\nObject.defineProperty(exports, \"__esModule\", { value: true });\r\nexports.Participant = void 0;\r\n/**\r\n * A participant that holds a number of tickets.\r\n */\r\nvar Participant = /** @class */ (function () {\r\n /**\r\n * Creates an instance of the Participant class.\r\n * @param participant The actual participant.\r\n * @param tickets The number of tickets held by the participant.\r\n */\r\n function Participant(participant, tickets) {\r\n if (tickets === void 0) { tickets = 1; }\r\n this._participant = participant;\r\n this._tickets = tickets;\r\n }\r\n Object.defineProperty(Participant.prototype, \"participant\", {\r\n /** Gets the actual participant. */\r\n get: function () {\r\n return this._participant;\r\n },\r\n enumerable: false,\r\n configurable: true\r\n });\r\n Object.defineProperty(Participant.prototype, \"tickets\", {\r\n /** Gets or sets the number of tickets held by the participant. */\r\n get: function () {\r\n return this._tickets;\r\n },\r\n set: function (value) {\r\n this._tickets = value;\r\n },\r\n enumerable: false,\r\n configurable: true\r\n });\r\n return Participant;\r\n}());\r\nexports.Participant = Participant;\r\n", "\"use strict\";\r\nObject.defineProperty(exports, \"__esModule\", { value: true });\r\nexports.isNaturalNumber = exports.isNullOrUndefined = void 0;\r\n/**\r\n * Gets whether the value provided is null or undefined.\r\n * @param value The value to check.\r\n * @returns Whether the value provided is null or undefined.\r\n */\r\nfunction isNullOrUndefined(value) {\r\n return value === null || value === undefined;\r\n}\r\nexports.isNullOrUndefined = isNullOrUndefined;\r\n/**\r\n * Gets whether the value provided is a natural number.\r\n * @param value The value to check.\r\n * @returns Whether the value provided is a natural number.\r\n */\r\nfunction isNaturalNumber(value) {\r\n return typeof value === \"number\" && value >= 1 && Math.floor(value) === value;\r\n}\r\nexports.isNaturalNumber = isNaturalNumber;\r\n", "\"use strict\";\r\nObject.defineProperty(exports, \"__esModule\", { value: true });\r\nexports.Lotto = void 0;\r\nvar Participant_1 = require(\"./Participant\");\r\nvar Utilities_1 = require(\"./Utilities\");\r\n/**\r\n * Represents a lotto consisting of a number of pickable ticket-holding participants.\r\n */\r\nvar Lotto = /** @class */ (function () {\r\n /**\r\n * Creates a new instance of Lotto.\r\n * @param customRandom The custom RNG to use in place of Math.random().\r\n */\r\n function Lotto(customRandom) {\r\n /** The array of participants that are holding tickets in the lotto. */\r\n this._participants = [];\r\n this._customRandom = customRandom;\r\n }\r\n /**\r\n * Adds a participant with the specified number of tickets, or adds to the participant ticket count if the participant already holds tickets.\r\n * @param participant The participant to add or to increase the ticket count for if they already hold tickets.\r\n * @param tickets The number of tickets, defaults to 1.\r\n * @returns The Lotto instance.\r\n */\r\n Lotto.prototype.add = function (participant, tickets) {\r\n if (tickets === void 0) { tickets = 1; }\r\n // Check that we have a valid ticket count.\r\n if (!(0, Utilities_1.isNaturalNumber)(tickets)) {\r\n throw new Error(\"tickets value must be a natural number\");\r\n }\r\n // Check whether this participant has already been added.\r\n var existingParticipant = this._participants.find(function (part) { return part.participant === participant; });\r\n if (existingParticipant) {\r\n // The participant has already been added to the lotto so just add to their ticket count.\r\n existingParticipant.tickets += tickets;\r\n }\r\n else {\r\n // The participant is not part of the lotto so we should add them.\r\n this._participants.push(new Participant_1.Participant(participant, tickets));\r\n }\r\n return this;\r\n };\r\n /**\r\n * Removes the specified number of tickets for the given participant from the draw, or all tickets if a ticket number is not defined.\r\n * @param participant The participant to remove tickets for.\r\n * @param tickets The number of tickets to remove, or undefined if all tickets are to be removed.\r\n * @returns The Lotto instance.\r\n */\r\n Lotto.prototype.remove = function (participant, tickets) {\r\n // Attempt to get the existing participant.\r\n var existingParticipant = this._participants.find(function (part) { return part.participant === participant; });\r\n // There is nothing to do if the specified participant isn't even part of the lotto.\r\n if (!existingParticipant) {\r\n return this;\r\n }\r\n // Check whether a tickets value was given.\r\n if (tickets !== undefined) {\r\n // Check that we have a valid ticket count.\r\n if (!(0, Utilities_1.isNaturalNumber)(tickets)) {\r\n throw new Error(\"tickets value must be a natural number\");\r\n }\r\n existingParticipant.tickets -= tickets;\r\n // If the participant no longer holds any tickets then they should be removed.\r\n if (existingParticipant.tickets < 1) {\r\n this._participants = this._participants.filter(function (part) { return part !== existingParticipant; });\r\n }\r\n }\r\n else {\r\n // We are removing all tickets for the participant so just remove them from the lotto.\r\n this._participants = this._participants.filter(function (part) { return part !== existingParticipant; });\r\n }\r\n return this;\r\n };\r\n /**\r\n * Draw a winning ticket and return the participant that holds the ticket.\r\n * @param options The draw options.\r\n * @returns The participant that holds the winning ticket.\r\n */\r\n Lotto.prototype.draw = function (options) {\r\n if (options === void 0) { options = {}; }\r\n // If we have no participants then just return null.\r\n if (this._participants.length === 0) {\r\n return null;\r\n }\r\n var redrawable = (0, Utilities_1.isNullOrUndefined)(options.redrawable) ? true : options.redrawable;\r\n var pickable = [];\r\n this._participants.forEach(function (_a) {\r\n var participant = _a.participant, tickets = _a.tickets;\r\n for (var ticketCount = 0; ticketCount < tickets; ticketCount++) {\r\n pickable.push(participant);\r\n }\r\n });\r\n var random;\r\n // We need a random floating-point number between 0 (inclusive) and 1 to scale up to pick our winner.\r\n // If a custom random function exists then we should use that or fall back to Math.random().\r\n if (this._customRandom) {\r\n // Call our custom random function to get a random floating-point number.\r\n random = this._customRandom();\r\n // Verify that the result of calling our custom random function is a number between 0 (inclusive) and 1.\r\n if (typeof random !== \"number\" || random < 0 || random >= 1) {\r\n throw new Error(\"the 'random' function provided did not return a number between 0 (inclusive) and 1\");\r\n }\r\n }\r\n else {\r\n // No custom random function was defined so just use good ol' Math.random().\r\n random = Math.random();\r\n }\r\n // Pick a winning participant.\r\n var winner = pickable[Math.floor(random * pickable.length)];\r\n // If the ticket isn't redrawable then we should remove a ticket from the winning participants ticket count.\r\n if (!redrawable) {\r\n this.remove(winner, 1);\r\n }\r\n // Return the winning participant.\r\n return winner;\r\n };\r\n /**\r\n * Draws multiple winning tickets and return an array of the participants that hold the winning tickets.\r\n * @param tickets The number of winning tickets to draw.\r\n * @param options The draw multiple options.\r\n * @returns An array of the participants that hold the winning tickets.\r\n */\r\n Lotto.prototype.drawMultiple = function (tickets, options) {\r\n if (options === void 0) { options = {}; }\r\n var uniqueResults = (0, Utilities_1.isNullOrUndefined)(options.unique) ? false : options.unique;\r\n // Handle cases where the user has asked for zero tickets (no idea why they would do this be we should trust them).\r\n if (tickets === 0) {\r\n return [];\r\n }\r\n // Now that we know out tickets value is not zero we should check that it is a valid natural number.\r\n if (!(0, Utilities_1.isNaturalNumber)(tickets)) {\r\n throw new Error(\"tickets value must be a natural number\");\r\n }\r\n var result = [];\r\n // Keep drawing tickets until we either reach the number of required tickets or we simply run out of tickets to draw.\r\n // We can run out of tickets to draw if 'options.redrawable' is explicity 'false' or we just had no participants when 'drawMultiple' was called.\r\n while (result.length < tickets && this._participants.length > 0) {\r\n result.push(this.draw(options));\r\n }\r\n // If the 'unique' draw option is set then we need to remove duplicates from the result list.\r\n if (uniqueResults) {\r\n // Create an array to store our unique results.\r\n var unique = [];\r\n // Iterate over all of our participants (with potential duplicates) and populate our array of unique values.\r\n for (var _i = 0, result_1 = result; _i < result_1.length; _i++) {\r\n var participant = result_1[_i];\r\n if (unique.indexOf(participant) === -1) {\r\n unique.push(participant);\r\n }\r\n }\r\n result = unique;\r\n }\r\n return result;\r\n };\r\n return Lotto;\r\n}());\r\nexports.Lotto = Lotto;\r\n", "\"use strict\";\r\nObject.defineProperty(exports, \"__esModule\", { value: true });\r\nexports.createLotto = void 0;\r\nvar Lotto_1 = require(\"./Lotto\");\r\n/**\r\n * A function that creates and returns a Lotto instance.\r\n * @param participantsOrOptions An array of initial participants or options relating to the creation of a Lotto instance.\r\n * @returns A new Lotto instance.\r\n */\r\nfunction createLotto(participantsOrOptions) {\r\n // If no initial participants or lotto options were provided as an argument then we can just return a new lotto instance now.\r\n if (!participantsOrOptions) {\r\n return new Lotto_1.Lotto();\r\n }\r\n // Check whether we were provided with an array of initial participants or a lotto options object.\r\n if (Array.isArray(participantsOrOptions)) {\r\n // We are dealing with a pre-defined array of participants.\r\n var participants = participantsOrOptions;\r\n var lotto_1 = new Lotto_1.Lotto();\r\n // If the lotto participants have been defined upfront then we will need to add them all to our lotto instance now.\r\n participants.forEach(function (_a) {\r\n var participant = _a[0], tokens = _a[1];\r\n return lotto_1.add(participant, tokens);\r\n });\r\n // Return the Lotto instance.\r\n return lotto_1;\r\n }\r\n else {\r\n // We are dealing with some lotto options.\r\n var random = participantsOrOptions.random, participants = participantsOrOptions.participants;\r\n // Create a Lotto instance passing the custom RNG function to use in place of Math.random() (which could be undefined).\r\n var lotto_2 = new Lotto_1.Lotto(random);\r\n // If the lotto participants have been defined upfront as part of the options then we will need to add them all to our lotto instance now.\r\n if (participants) {\r\n participants.forEach(function (_a) {\r\n var participant = _a[0], tokens = _a[1];\r\n return lotto_2.add(participant, tokens);\r\n });\r\n }\r\n // Return the Lotto instance.\r\n return lotto_2;\r\n }\r\n}\r\nexports.createLotto = createLotto;\r\n", "\"use strict\";\r\nObject.defineProperty(exports, \"__esModule\", { value: true });\r\nvar createLotto_1 = require(\"./createLotto\");\r\nexports.default = createLotto_1.createLotto;\r\n", "import State from \"./State\";\nimport { validateDefinition } from \"./BehaviourTreeDefinitionValidator\";\nimport { convertMDSLToJSON } from \"./mdsl/MDSLDefinitionParser\";\nimport { BehaviourTree, FlattenedTreeNode } from \"./BehaviourTree\";\nimport { BehaviourTreeOptions } from \"./BehaviourTreeOptions\";\n\nexport { BehaviourTree, State, convertMDSLToJSON, validateDefinition };\nexport type { FlattenedTreeNode, BehaviourTreeOptions };\n", "/**\n * Enumeration of node state types.\n */\nexport enum State {\n READY = \"mistreevous.ready\",\n RUNNING = \"mistreevous.running\",\n SUCCEEDED = \"mistreevous.succeeded\",\n FAILED = \"mistreevous.failed\"\n}\n\nexport { State as default };\n\nexport type CompleteState = State.SUCCEEDED | State.FAILED;\nexport type AnyState = State.READY | State.RUNNING | CompleteState;\n", "import {\n NodeDefinition,\n RootNodeDefinition,\n DecoratorNodeDefinition,\n CompositeNodeDefinition,\n AnyNodeDefinition,\n BranchNodeDefinition\n} from \"./BehaviourTreeDefinition\";\n\n/**\n * A type guard function that returns true if the specified node satisfies the RootNodeDefinition type.\n * @param node The node.\n * @returns A value of true if the specified node satisfies the RootNodeDefinition type.\n */\nexport function isRootNode(node: NodeDefinition): node is RootNodeDefinition {\n return node.type === \"root\";\n}\n\n/**\n * A type guard function that returns true if the specified node satisfies the BranchNodeDefinition type.\n * @param node The node.\n * @returns A value of true if the specified node satisfies the BranchNodeDefinition type.\n */\nexport function isBranchNode(node: NodeDefinition): node is BranchNodeDefinition {\n return node.type === \"branch\";\n}\n\n/**\n * A type guard function that returns true if the specified node satisfies the NodeDefinition type.\n * @param node The node.\n * @returns A value of true if the specified node satisfies the NodeDefinition type.\n */\nexport function isLeafNode(node: NodeDefinition): node is NodeDefinition {\n return [\"branch\", \"action\", \"condition\", \"wait\"].includes(node.type);\n}\n\n/**\n * A type guard function that returns true if the specified node satisfies the DecoratorNodeDefinition type.\n * @param node The node.\n * @returns A value of true if the specified node satisfies the DecoratorNodeDefinition type.\n */\nexport function isDecoratorNode(node: NodeDefinition): node is DecoratorNodeDefinition {\n return [\"root\", \"repeat\", \"retry\", \"flip\", \"succeed\", \"fail\"].includes(node.type);\n}\n\n/**\n * A type guard function that returns true if the specified node satisfies the CompositeNodeDefinition type.\n * @param node The node.\n * @returns A value of true if the specified node satisfies the CompositeNodeDefinition type.\n */\nexport function isCompositeNode(node: NodeDefinition): node is CompositeNodeDefinition {\n return [\"sequence\", \"selector\", \"lotto\", \"parallel\"].includes(node.type);\n}\n\n/**\n * Flatten a node definition into an array of all of its nested node definitions.\n * @param nodeDefinition The node definition to flatten.\n * @returns An array of all of nested node definitions.\n */\nexport function flattenDefinition(nodeDefinition: AnyNodeDefinition): AnyNodeDefinition[] {\n const nodes: AnyNodeDefinition[] = [];\n\n const processNode = (currentNodeDefinition: AnyNodeDefinition) => {\n nodes.push(currentNodeDefinition);\n\n if (isCompositeNode(currentNodeDefinition)) {\n currentNodeDefinition.children.forEach(processNode);\n } else if (isDecoratorNode(currentNodeDefinition)) {\n processNode(currentNodeDefinition.child);\n }\n };\n\n processNode(nodeDefinition);\n\n return nodes;\n}\n\n/**\n * Determines whether the passed value is an integer.\n * @param value The value to check.\n * @returns Whether the passed value is an integer.\n */\nexport function isInteger(value: unknown): boolean {\n return typeof value === \"number\" && Math.floor(value) === value;\n}\n\n/**\n * Determines whether the passed value is null or undefined.\n * @param value The value to check.\n * @returns Whether the passed value is null or undefined.\n */\nexport function isNullOrUndefined(value: unknown): boolean {\n return typeof value === \"undefined\" || value === null;\n}\n", "/**\n * A type defining an object that holds a reference to substitued string literals parsed from the definition.\n */\nexport type StringLiteralPlaceholders = { [key: string]: string };\n\n/**\n * Pop the next raw token from the specified array of tokens and throw an error if it wasn't the expected one.\n * @param tokens The array of tokens.\n * @param expected An optional string or array or items, one of which must match the next popped token.\n * @returns The popped token.\n */\nexport function popAndCheck(tokens: string[], expected?: string | string[]): string {\n // Get and remove the next token.\n const popped = tokens.shift();\n\n // We were expecting another token but there aren't any.\n if (popped === undefined) {\n throw new Error(\"unexpected end of definition\");\n }\n\n // Do we have an expected token/tokens array?\n if (expected != undefined) {\n // Get an array of expected values, if the popped token matches any then we are all good.\n const expectedValues = typeof expected === \"string\" ? [expected] : expected;\n\n // Check whether the popped token matches at least one of our expected items.\n var tokenMatchesExpectation = expectedValues.some((item) => popped.toUpperCase() === item.toUpperCase());\n\n // Throw an error if the popped token didn't match any of our expected items.\n if (!tokenMatchesExpectation) {\n const expectationString = expectedValues.map((item) => \"'\" + item + \"'\").join(\" or \");\n throw new Error(\"unexpected token found. Expected \" + expectationString + \" but got '\" + popped + \"'\");\n }\n }\n\n // Return the popped token.\n return popped;\n}\n\n/**\n * Swaps out any node/attribute argument string literals with placeholders.\n * @param definition The definition.\n * @returns An object containing a mapping of placeholders to original string values as well as the processed definition string.\n */\nexport function substituteStringLiterals(definition: string): {\n placeholders: StringLiteralPlaceholders;\n processedDefinition: string;\n} {\n // Create an object to hold the mapping of placeholders to original string values.\n const placeholders: StringLiteralPlaceholders = {};\n\n // Replace any string literals wrapped with double quotes in our definition with placeholders to be processed later.\n const processedDefinition = definition.replace(/\\\"(\\\\.|[^\"\\\\])*\\\"/g, (match) => {\n var strippedMatch = match.substring(1, match.length - 1);\n var placeholder = Object.keys(placeholders).find((key) => placeholders[key] === strippedMatch);\n\n // If we have no existing string literal match then create a new placeholder.\n if (!placeholder) {\n placeholder = `@@${Object.keys(placeholders).length}@@`;\n placeholders[placeholder] = strippedMatch;\n }\n\n return placeholder;\n });\n\n return { placeholders, processedDefinition };\n}\n\n/**\n * Parse the tree definition into an array of raw tokens.\n * @param definition The definition.\n * @returns An array of tokens parsed from the definition.\n */\nexport function parseTokensFromDefinition(definition: string): string[] {\n // Add some space around various important characters so that they can be plucked out easier as individual tokens.\n definition = definition.replace(/\\(/g, \" ( \");\n definition = definition.replace(/\\)/g, \" ) \");\n definition = definition.replace(/\\{/g, \" { \");\n definition = definition.replace(/\\}/g, \" } \");\n definition = definition.replace(/\\]/g, \" ] \");\n definition = definition.replace(/\\[/g, \" [ \");\n definition = definition.replace(/\\,/g, \" , \");\n\n // Split the definition into raw token form and return it.\n return definition.replace(/\\s+/g, \" \").trim().split(\" \");\n}\n", "import { StringLiteralPlaceholders, popAndCheck } from \"./MDSLUtilities\";\n\n/**\n * A type representing any node function argument.\n */\ntype Argument = {\n /**\n * The argument value.\n */\n value: T;\n /**\n * The argument type, used for validation.\n */\n type: string;\n};\n\ntype NullArgument = Argument & {\n type: \"null\";\n};\n\ntype BooleanArgument = Argument & {\n type: \"boolean\";\n};\n\ntype NumberArgument = Argument & {\n type: \"number\";\n /**\n * A flag defining whether the number argument value is a valid integer. (used for validation)\n */\n isInteger: boolean;\n};\n\ntype StringPlaceholderArgument = Argument & {\n type: \"string\";\n};\n\ntype IdentifierArgument = Argument & {\n type: \"identifier\";\n};\n\n/**\n * A type representing a reference to any node function argument.\n */\ntype AnyArgument = NullArgument | BooleanArgument | NumberArgument | StringPlaceholderArgument | IdentifierArgument;\n\n/**\n * Parse an array of argument definitions from the specified tokens array.\n * @param tokens The array tokens to parse the argument definitions from.\n * @param stringArgumentPlaceholders The mapping of string literal node argument placeholders to original values.\n * @param argumentValidator The argument validator function.\n * @param validationFailedMessage The exception message to throw if argument validation fails.\n * @returns An array of argument definitions parsed from the specified tokens array.\n */\nexport function parseArgumentTokens(\n tokens: string[],\n stringArgumentPlaceholders: StringLiteralPlaceholders\n): AnyArgument[] {\n const argumentList: AnyArgument[] = [];\n\n // If the next token is not a '[' or '(' then we have no arguments to parse.\n if (![\"[\", \"(\"].includes(tokens[0])) {\n return argumentList;\n }\n\n // Any lists of arguments will always be wrapped in '[]' for node arguments or '()' for attribute arguments.\n // We are looking for a '[' or '(' opener that wraps the argument tokens and the relevant closer.\n const closingToken = popAndCheck(tokens, [\"[\", \"(\"]) === \"[\" ? \"]\" : \")\";\n\n const argumentListTokens: string[] = [];\n\n // Grab all tokens between the '[' and ']' or '(' and ')'.\n while (tokens.length && tokens[0] !== closingToken) {\n // The next token is part of our arguments list.\n argumentListTokens.push(tokens.shift()!);\n }\n\n // Validate the order of the argument tokens. Each token must either be a ',' or a single argument that satisfies the validator.\n argumentListTokens.forEach((token, index) => {\n // Get whether this token should be an actual argument.\n const shouldBeArgumentToken = !(index & 1);\n\n // If the current token should be an actual argument then validate it, otherwise it should be a ',' token.\n if (shouldBeArgumentToken) {\n // Get the argument definition.\n const argumentDefinition = getArgumentDefinition(token, stringArgumentPlaceholders);\n\n // This is a valid argument!\n argumentList.push(argumentDefinition);\n } else {\n // The current token should be a ',' token.\n if (token !== \",\") {\n throw new Error(`invalid argument list, expected ',' or ']' but got '${token}'`);\n }\n }\n });\n\n // The arguments list should terminate with a ']' or ')' token, depending on the opener.\n popAndCheck(tokens, closingToken);\n\n // Return the arguments.\n return argumentList;\n}\n\n/**\n * Gets an argument value definition.\n * @param token The argument token.\n * @param stringArgumentPlaceholders The mapping of string literal node argument placeholders to original values.\n * @returns An argument value definition.\n */\nfunction getArgumentDefinition(token: string, stringArgumentPlaceholders: StringLiteralPlaceholders): AnyArgument {\n // Check whether the token represents a null value.\n if (token === \"null\") {\n return {\n value: null,\n type: \"null\"\n } as NullArgument;\n }\n\n // Check whether the token represents a boolean value.\n if (token === \"true\" || token === \"false\") {\n return {\n value: token === \"true\",\n type: \"boolean\"\n } as BooleanArgument;\n }\n\n // Check whether the token represents a number value.\n // TODO: Relies on broken isNaN - see MDN.\n // if (!Number.isNaN(token)) {\n if (!isNaN(token as any)) {\n return {\n value: parseFloat(token),\n isInteger: parseFloat(token) === parseInt(token, 10),\n type: \"number\"\n } as NumberArgument;\n }\n\n // Check whether the token is a placeholder (e.g. @@0@@) representing a string literal.\n if (token.match(/^@@\\d+@@$/g)) {\n return {\n value: stringArgumentPlaceholders[token].replace('\\\\\"', '\"'),\n type: \"string\"\n } as StringPlaceholderArgument;\n }\n\n // The only remaining option is that the argument value is an identifier.\n return {\n value: token,\n type: \"identifier\"\n } as IdentifierArgument;\n}\n", "import { NodeAttributeDefinition } from \"../BehaviourTreeDefinition\";\nimport { parseArgumentTokens } from \"./MDSLNodeArgumentParser\";\nimport { StringLiteralPlaceholders } from \"./MDSLUtilities\";\n\n/**\n * A type defining the attribute definitions of a node.\n */\ntype NodeAttributes = {\n while?: NodeAttributeDefinition;\n until?: NodeAttributeDefinition;\n entry?: NodeAttributeDefinition;\n exit?: NodeAttributeDefinition;\n step?: NodeAttributeDefinition;\n};\n\n/**\n * Parse any node attribute definitions from the specified tokens array.\n * @param tokens The array of remaining tokens.\n * @param stringArgumentPlaceholders The mapping of string literal node argument placeholders to original values.\n * @returns An object of attribute definitions defined by any directly following tokens.\n */\nexport function parseAttributeTokens(\n tokens: string[],\n stringArgumentPlaceholders: StringLiteralPlaceholders\n): NodeAttributes {\n const nodeAttributeNames: (keyof NodeAttributes)[] = [\"while\", \"until\", \"entry\", \"exit\", \"step\"];\n\n // Create an object to hold any attributes found.\n const attributes: NodeAttributes = {};\n\n // Try to get the name of the attribute for the next token.\n let nextAttributeName = tokens[0]?.toLowerCase() as keyof NodeAttributes;\n\n // Pull attribute tokens as well as their arguments off of the tokens stack until we have no more.\n while (nodeAttributeNames.includes(nextAttributeName)) {\n // Check to make sure that we have not already created an attribute definition of this type.\n if (attributes[nextAttributeName]) {\n throw new Error(`duplicate attribute '${tokens[0].toUpperCase()}' found for node`);\n }\n\n // Remove the attribute name token from the array of tokens.\n tokens.shift();\n\n // Grab the attribute arguments, assuming the first to be an identifier.\n const [attributeCallIdentifier, ...attributeArguments] = parseArgumentTokens(\n tokens,\n stringArgumentPlaceholders\n );\n\n // The first attribute argument has to be an identifer, this will reference an agent function.\n if (attributeCallIdentifier?.type !== \"identifier\") {\n throw new Error(\"expected agent function name identifier argument for attribute\");\n }\n\n // Any attribute arguments (other than the expected call identifier) must have a type of string, number, boolean or null.\n attributeArguments\n .filter((arg) => arg.type === \"identifier\")\n .forEach((arg) => {\n throw new Error(\n `invalid attribute argument value '${arg.value}', must be string, number, boolean or null`\n );\n });\n\n // Create the attribute definition and add it to the object of attribute definitions found.\n attributes[nextAttributeName] = {\n call: attributeCallIdentifier.value,\n args: attributeArguments.map(({ value }) => value)\n };\n\n // Try to get the next attribute name token, as there could be multiple.\n nextAttributeName = tokens[0]?.toLowerCase() as keyof NodeAttributes;\n }\n\n return attributes;\n}\n", "import {\n ActionNodeDefinition,\n AnyChildNodeDefinition,\n AnyNodeDefinition,\n BranchNodeDefinition,\n ConditionNodeDefinition,\n FailNodeDefinition,\n FlipNodeDefinition,\n LottoNodeDefinition,\n ParallelNodeDefinition,\n RepeatNodeDefinition,\n RetryNodeDefinition,\n RootNodeDefinition,\n SelectorNodeDefinition,\n SequenceNodeDefinition,\n SucceedNodeDefinition,\n WaitNodeDefinition\n} from \"../BehaviourTreeDefinition\";\nimport {\n isCompositeNode,\n isDecoratorNode,\n isLeafNode,\n isNullOrUndefined,\n isRootNode\n} from \"../BehaviourTreeDefinitionUtilities\";\nimport { parseArgumentTokens } from \"./MDSLNodeArgumentParser\";\nimport { parseAttributeTokens } from \"./MDSLNodeAttributeParser\";\nimport {\n StringLiteralPlaceholders,\n parseTokensFromDefinition,\n popAndCheck,\n substituteStringLiterals\n} from \"./MDSLUtilities\";\n\n/**\n * Convert the MDSL tree definition string into an equivalent JSON definition.\n * @param definition The tree definition string as MDSL.\n * @returns The root node JSON definitions.\n */\nexport function convertMDSLToJSON(definition: string): RootNodeDefinition[] {\n // Swap out any node/attribute argument string literals with a placeholder and get a mapping of placeholders to original values as well as the processed definition.\n const { placeholders, processedDefinition } = substituteStringLiterals(definition);\n\n // Parse our definition definition string into an array of raw tokens.\n const tokens = parseTokensFromDefinition(processedDefinition);\n\n return convertTokensToJSONDefinition(tokens, placeholders);\n}\n\n/**\n * Converts the specified tree definition tokens into a JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The root node JSON definitions.\n */\nfunction convertTokensToJSONDefinition(\n tokens: string[],\n stringLiteralPlaceholders: StringLiteralPlaceholders\n): RootNodeDefinition[] {\n // There must be at least 3 tokens for the tree definition to be valid. 'ROOT', '{' and '}'.\n if (tokens.length < 3) {\n throw new Error(\"invalid token count\");\n }\n\n // We should have a matching number of '{' and '}' tokens. If not, then there are scopes that have not been properly closed.\n if (tokens.filter((token) => token === \"{\").length !== tokens.filter((token) => token === \"}\").length) {\n throw new Error(\"scope character mismatch\");\n }\n\n // Create an array of tree stack arrays where root nodes will always be at the botton and the current composite/decorator node at the top.\n // There should be an element in this array for every root node defined and every element should be an array with a root note as the first element.\n // E.g. A definition with two root nodes defined:\n // [\n // [root, lotto, sequence],\n // [root, selector]\n // ]\n const treeStacks: [Partial, ...Partial[]][] = [];\n\n // Create an array of all root node definitions that we create.\n const rootNodes: Partial[] = [];\n\n // A helper function used to push node definitions onto the tree stack.\n const pushNode = (node: AnyNodeDefinition) => {\n // If the node is a root node then we need to create a new tree stack array with the root node at the root.\n if (isRootNode(node)) {\n // We need to double-check that this root node is not the child of another node.\n // We can do this by checking whether the top tree stack is not empty (contains an existing node)\n if (treeStacks[treeStacks.length - 1]?.length) {\n throw new Error(\"a root node cannot be the child of another node\");\n }\n\n // Add the root node definition to our array of all parsed root node definitions.\n rootNodes.push(node);\n\n // Add the root node definition to the root of a new tree stack.\n treeStacks.push([node]);\n\n return;\n }\n\n // All non-root nodes should be pushed after their root nodes so handle cases\n // where we may not have any tree stacks or our top-most tree stack is empty.\n if (!treeStacks.length || !treeStacks[treeStacks.length - 1].length) {\n throw new Error(\"expected root node at base of definition\");\n }\n\n // Get the current tree stack that we are populating.\n const topTreeStack = treeStacks[treeStacks.length - 1];\n\n // Get the top-most node in the current tree stack, this will be a composite/decorator node\n // for which we will populate its children array if composite or setting its child if a decorator.\n const topTreeStackTopNode = topTreeStack[topTreeStack.length - 1] as AnyNodeDefinition;\n\n // If the top-most node in the current root stack is a composite or decorator\n // node then the current node should be added as a child of the top-most node.\n if (isCompositeNode(topTreeStackTopNode)) {\n topTreeStackTopNode.children = topTreeStackTopNode.children || [];\n topTreeStackTopNode.children.push(node);\n } else if (isDecoratorNode(topTreeStackTopNode)) {\n // If the top node already has a child node set then throw an error as a decorator should only have a single child.\n if (topTreeStackTopNode.child) {\n throw new Error(\"a decorator node must only have a single child node\");\n }\n\n topTreeStackTopNode.child = node;\n }\n\n // If the node we are adding is also a composite or decorator node, then we should push it\n // onto the current tree stack, as subsequent nodes will be added as its child/children.\n if (!isLeafNode(node)) {\n topTreeStack.push(node);\n }\n };\n\n // A helper function used to pop the top-most node definition off of the tree stack and return it.\n const popNode = (): AnyNodeDefinition | null => {\n let poppedNode: AnyNodeDefinition | null = null;\n\n // Get the current tree stack that we are populating.\n const topTreeStack = treeStacks[treeStacks.length - 1];\n\n // Pop the top-most node in the current tree stack if there is one.\n if (topTreeStack.length) {\n poppedNode = topTreeStack.pop() as AnyNodeDefinition;\n }\n\n // We don't want any empty tree stacks in our stack of tree stacks.\n if (!topTreeStack.length) {\n treeStacks.pop();\n }\n\n return poppedNode;\n };\n\n // We should keep processing the raw tokens until we run out of them.\n while (tokens.length) {\n // Grab the next token.\n const token = tokens.shift()!;\n\n // How we create the next node depends on the current raw token value.\n switch (token.toUpperCase()) {\n case \"ROOT\": {\n pushNode(createRootNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"SUCCEED\": {\n pushNode(createSucceedNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"FAIL\": {\n pushNode(createFailNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"FLIP\": {\n pushNode(createFlipNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"REPEAT\": {\n pushNode(createRepeatNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"RETRY\": {\n pushNode(createRetryNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"SEQUENCE\": {\n pushNode(createSequenceNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"SELECTOR\": {\n pushNode(createSelectorNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"PARALLEL\": {\n pushNode(createParallelNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"LOTTO\": {\n pushNode(createLottoNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"ACTION\": {\n pushNode(createActionNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"CONDITION\": {\n pushNode(createConditionNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"WAIT\": {\n pushNode(createWaitNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"BRANCH\": {\n pushNode(createBranchNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"}\": {\n // The '}' character closes the current scope and means that we have to pop a node off of the current stack.\n const poppedNode = popNode();\n\n // Now that we have a node definition we can carry out any validation that may require the node to be fully populated.\n if (poppedNode) {\n validatePoppedNode(poppedNode);\n }\n\n break;\n }\n\n default: {\n throw new Error(`unexpected token: ${token}`);\n }\n }\n }\n\n return rootNodes as RootNodeDefinition[];\n}\n\n/**\n * Creates a root node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The root node JSON definition.\n */\nfunction createRootNode(tokens: string[], stringLiteralPlaceholders: StringLiteralPlaceholders): RootNodeDefinition {\n // Create the root node definition.\n let node = {\n type: \"root\",\n id: undefined\n } as RootNodeDefinition;\n\n // Parse any node arguments, we should only have one if any which will be an identifier argument for the root identifier.\n const nodeArguments = parseArgumentTokens(tokens, stringLiteralPlaceholders);\n\n // Check whether any node arguments were defined.\n if (nodeArguments.length) {\n // We should only have one argument, if any, which will be an identifier argument for the root identifier.\n if (nodeArguments.length === 1 && nodeArguments[0].type === \"identifier\") {\n // The root node identifier will be the first and only node argument value.\n node.id = nodeArguments[0].value as string;\n } else {\n throw new Error(\"expected single root name argument\");\n }\n }\n\n // Grab any node attribute definitions and spread them into the node definition.\n node = { ...node, ...parseAttributeTokens(tokens, stringLiteralPlaceholders) };\n\n // This is a decorator node, so we expect an opening '{'.\n popAndCheck(tokens, \"{\");\n\n // Return the root node definition.\n return node;\n}\n\n/**\n * Creates a succeed node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The succeed node JSON definition.\n */\nfunction createSucceedNode(\n tokens: string[],\n stringLiteralPlaceholders: StringLiteralPlaceholders\n): SucceedNodeDefinition {\n const node = {\n type: \"succeed\",\n ...parseAttributeTokens(tokens, stringLiteralPlaceholders)\n } as SucceedNodeDefinition;\n\n // This is a decorator node, so we expect an opening '{'.\n popAndCheck(tokens, \"{\");\n\n // Return the succeed node definition.\n return node;\n}\n\n/**\n * Creates a fail node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The fail node JSON definition.\n */\nfunction createFailNode(tokens: string[], stringLiteralPlaceholders: StringLiteralPlaceholders): FailNodeDefinition {\n const node = {\n type: \"fail\",\n ...parseAttributeTokens(tokens, stringLiteralPlaceholders)\n } as FailNodeDefinition;\n\n // This is a decorator node, so we expect an opening '{'.\n popAndCheck(tokens, \"{\");\n\n // Return the fail node definition.\n return node;\n}\n\n/**\n * Creates a flip node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The flip node JSON definition.\n */\nfunction createFlipNode(tokens: string[], stringLiteralPlaceholders: StringLiteralPlaceholders): FlipNodeDefinition {\n const node = {\n type: \"flip\",\n ...parseAttributeTokens(tokens, stringLiteralPlaceholders)\n } as FlipNodeDefinition;\n\n // This is a decorator node, so we expect an opening '{'.\n popAndCheck(tokens, \"{\");\n\n // Return the flip node definition.\n return node;\n}\n\n/**\n * Creates a repeat node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The repeat node JSON definition.\n */\nfunction createRepeatNode(\n tokens: string[],\n stringLiteralPlaceholders: StringLiteralPlaceholders\n): RepeatNodeDefinition {\n let node = { type: \"repeat\" } as RepeatNodeDefinition;\n\n // Get the node arguments.\n const nodeArguments = parseArgumentTokens(tokens, stringLiteralPlaceholders);\n\n // The arguments of a repeat node are optional. We may have:\n // - No node arguments, in which case the repeat note will iterate indefinitely.\n // - One node argument which will be the explicit number of iterations to make.\n // - Two node arguments which define the min and max iteration bounds from which a random iteration count will be picked.\n if (nodeArguments.length) {\n // All repeat node arguments MUST be of type number and must be integer.\n nodeArguments\n .filter((arg) => arg.type !== \"number\" || !arg.isInteger)\n .forEach(() => {\n throw new Error(`repeat node iteration counts must be integer values`);\n });\n\n // We should have got one or two iteration counts.\n if (nodeArguments.length === 1) {\n // A static iteration count was defined.\n node.iterations = nodeArguments[0].value as number;\n\n // A repeat node must have a positive number of iterations if defined.\n if (node.iterations < 0) {\n throw new Error(\"a repeat node must have a positive number of iterations if defined\");\n }\n } else if (nodeArguments.length === 2) {\n // A minimum and maximum iteration count was defined.\n node.iterations = [nodeArguments[0].value as number, nodeArguments[1].value as number];\n\n // A repeat node must have a positive min and max iteration count if they are defined.\n if (node.iterations[0] < 0 || node.iterations[1] < 0) {\n throw new Error(\"a repeat node must have a positive minimum and maximum iteration count if defined\");\n }\n\n // A repeat node must not have an minimum iteration count that exceeds the maximum iteration count.\n if (node.iterations[0] > node.iterations[1]) {\n throw new Error(\n \"a repeat node must not have a minimum iteration count that exceeds the maximum iteration count\"\n );\n }\n } else {\n // An incorrect number of iteration counts was defined.\n throw new Error(\"invalid number of repeat node iteration count arguments defined\");\n }\n }\n\n // Grab any node attribute definitions and spread them into the node definition.\n node = { ...node, ...parseAttributeTokens(tokens, stringLiteralPlaceholders) };\n\n // This is a decorator node, so we expect an opening '{'.\n popAndCheck(tokens, \"{\");\n\n // Return the repeat node definition.\n return node;\n}\n\n/**\n * Creates a retry node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The retry node JSON definition.\n */\nfunction createRetryNode(tokens: string[], stringLiteralPlaceholders: StringLiteralPlaceholders): RetryNodeDefinition {\n let node = { type: \"retry\" } as RetryNodeDefinition;\n\n // Get the node arguments.\n const nodeArguments = parseArgumentTokens(tokens, stringLiteralPlaceholders);\n\n // The arguments of a retry node are optional. We may have:\n // - No node arguments, in which case the retry note will attempt indefinitely.\n // - One node argument which will be the explicit number of attempts to make.\n // - Two node arguments which define the min and max attempt bounds from which a random attempt count will be picked.\n if (nodeArguments.length) {\n // All retry node arguments MUST be of type number and must be integer.\n nodeArguments\n .filter((arg) => arg.type !== \"number\" || !arg.isInteger)\n .forEach(() => {\n throw new Error(`retry node attempt counts must be integer values`);\n });\n\n // We should have got one or two attempt counts.\n if (nodeArguments.length === 1) {\n // A static attempt count was defined.\n node.attempts = nodeArguments[0].value as number;\n\n // A retry node must have a positive number of attempts if defined.\n if (node.attempts < 0) {\n throw new Error(\"a retry node must have a positive number of attempts if defined\");\n }\n } else if (nodeArguments.length === 2) {\n // A minimum and maximum attempt count was defined.\n node.attempts = [nodeArguments[0].value as number, nodeArguments[1].value as number];\n\n // A retry node must have a positive min and max attempts count if they are defined.\n if (node.attempts[0] < 0 || node.attempts[1] < 0) {\n throw new Error(\"a retry node must have a positive minimum and maximum attempt count if defined\");\n }\n\n // A retry node must not have a minimum attempt count that exceeds the maximum attempt count.\n if (node.attempts[0] > node.attempts[1]) {\n throw new Error(\n \"a retry node must not have a minimum attempt count that exceeds the maximum attempt count\"\n );\n }\n } else {\n // An incorrect number of attempt counts was defined.\n throw new Error(\"invalid number of retry node attempt count arguments defined\");\n }\n }\n\n // Grab any node attribute definitions and spread them into the node definition.\n node = { ...node, ...parseAttributeTokens(tokens, stringLiteralPlaceholders) };\n\n // This is a decorator node, so we expect an opening '{'.\n popAndCheck(tokens, \"{\");\n\n // Return the retry node definition.\n return node;\n}\n\n/**\n * Creates a sequence node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The sequence node JSON definition.\n */\nfunction createSequenceNode(\n tokens: string[],\n stringLiteralPlaceholders: StringLiteralPlaceholders\n): SequenceNodeDefinition {\n const node = {\n type: \"sequence\",\n ...parseAttributeTokens(tokens, stringLiteralPlaceholders)\n } as SequenceNodeDefinition;\n\n // This is a composite node, so we expect an opening '{'.\n popAndCheck(tokens, \"{\");\n\n // Return the sequence node definition.\n return node;\n}\n\n/**\n * Creates a selector node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The selector node JSON definition.\n */\nfunction createSelectorNode(\n tokens: string[],\n stringLiteralPlaceholders: StringLiteralPlaceholders\n): SelectorNodeDefinition {\n const node = {\n type: \"selector\",\n ...parseAttributeTokens(tokens, stringLiteralPlaceholders)\n } as SelectorNodeDefinition;\n\n // This is a composite node, so we expect an opening '{'.\n popAndCheck(tokens, \"{\");\n\n // Return the selector node definition.\n return node;\n}\n\n/**\n * Creates a parallel node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The parallel node JSON definition.\n */\nfunction createParallelNode(\n tokens: string[],\n stringLiteralPlaceholders: StringLiteralPlaceholders\n): ParallelNodeDefinition {\n const node = {\n type: \"parallel\",\n ...parseAttributeTokens(tokens, stringLiteralPlaceholders)\n } as ParallelNodeDefinition;\n\n // This is a composite node, so we expect an opening '{'.\n popAndCheck(tokens, \"{\");\n\n // Return the parallel node definition.\n return node;\n}\n\n/**\n * Creates a lotto node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The lotto node JSON definition.\n */\nfunction createLottoNode(tokens: string[], stringLiteralPlaceholders: StringLiteralPlaceholders): LottoNodeDefinition {\n // If any node arguments have been defined then they must be our weights.\n const nodeArguments = parseArgumentTokens(tokens, stringLiteralPlaceholders);\n\n // All lotto node arguments MUST be of type number and must be integer.\n nodeArguments\n .filter((arg) => arg.type !== \"number\" || !arg.isInteger)\n .forEach(() => {\n throw new Error(`lotto node weight arguments must be integer values`);\n });\n\n const node = {\n type: \"lotto\",\n weights: nodeArguments.map(({ value }) => value),\n ...parseAttributeTokens(tokens, stringLiteralPlaceholders)\n } as LottoNodeDefinition;\n\n // This is a composite node, so we expect an opening '{'.\n popAndCheck(tokens, \"{\");\n\n // Return the lotto node definition.\n return node;\n}\n\n/**\n * Creates an action node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The action node JSON definition.\n */\nfunction createActionNode(\n tokens: string[],\n stringLiteralPlaceholders: StringLiteralPlaceholders\n): ActionNodeDefinition {\n // Parse any node arguments, we should have at least one which will be an identifier argument for the action name\n // and agent function to invoke for the action, all other arguments are to be passed as arguments to that function.\n const [actionNameIdentifier, ...agentFunctionArgs] = parseArgumentTokens(tokens, stringLiteralPlaceholders);\n\n // Our first argument MUST be defined and be an identifier as we require an action name argument.\n if (actionNameIdentifier?.type !== \"identifier\") {\n throw new Error(\"expected action name identifier argument\");\n }\n\n // Only the first argument should have been an identifier, all agent function arguments must be string, number, boolean or null.\n agentFunctionArgs\n .filter((arg) => arg.type === \"identifier\")\n .forEach((arg) => {\n throw new Error(\n `invalid action node argument value '${arg.value}', must be string, number, boolean or null`\n );\n });\n\n // Return the action node definition.\n return {\n type: \"action\",\n call: actionNameIdentifier.value,\n args: agentFunctionArgs.map(({ value }) => value),\n ...parseAttributeTokens(tokens, stringLiteralPlaceholders)\n };\n}\n\n/**\n * Creates a condition node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The condition node JSON definition.\n */\nfunction createConditionNode(\n tokens: string[],\n stringLiteralPlaceholders: StringLiteralPlaceholders\n): ConditionNodeDefinition {\n // Parse any node arguments, we should have at least one which will be an identifier argument for the condition name\n // and agent function to invoke for the condition, all other arguments are to be passed as arguments to that function.\n const [conditionNameIdentifier, ...agentFunctionArgs] = parseArgumentTokens(tokens, stringLiteralPlaceholders);\n\n // Our first argument MUST be defined and be an identifier as we require a condition name argument.\n if (conditionNameIdentifier?.type !== \"identifier\") {\n throw new Error(\"expected condition name identifier argument\");\n }\n\n // Only the first argument should have been an identifier, all agent function arguments must be string, number, boolean or null.\n agentFunctionArgs\n .filter((arg) => arg.type === \"identifier\")\n .forEach((arg) => {\n throw new Error(\n `invalid condition node argument value '${arg.value}', must be string, number, boolean or null`\n );\n });\n\n // Return the condition node definition.\n return {\n type: \"condition\",\n call: conditionNameIdentifier.value,\n args: agentFunctionArgs.map(({ value }) => value),\n ...parseAttributeTokens(tokens, stringLiteralPlaceholders)\n };\n}\n\n/**\n * Creates a wait node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The wait node JSON definition.\n */\nfunction createWaitNode(tokens: string[], stringLiteralPlaceholders: StringLiteralPlaceholders): WaitNodeDefinition {\n let node = { type: \"wait\" } as WaitNodeDefinition;\n\n // Get the node arguments.\n const nodeArguments = parseArgumentTokens(tokens, stringLiteralPlaceholders);\n\n // The arguments of a wait node are optional. We may have:\n // - No node arguments, in which case the wait will be indefinite until it is aborted.\n // - One node argument which will be the explicit duration of the wait.\n // - Two node arguments which define the min and max duration bounds from which a random duration will be picked.\n if (nodeArguments.length) {\n // All wait node arguments MUST be of type number and must be integer.\n nodeArguments\n .filter((arg) => arg.type !== \"number\" || !arg.isInteger)\n .forEach(() => {\n throw new Error(`wait node duration arguments must be integer values`);\n });\n\n // We may have:\n // - One node argument which will be the explicit duration of the wait.\n // - Two node arguments which define the min and max duration bounds from which a random duration will be picked.\n // - Too many arguments, which is not valid.\n if (nodeArguments.length === 1) {\n // An explicit duration was defined.\n node.duration = nodeArguments[0].value as number;\n\n // If an explict duration was defined then it must be a positive number.\n if (node.duration < 0) {\n throw new Error(\"a wait node must have a positive duration\");\n }\n } else if (nodeArguments.length === 2) {\n // Min and max duration bounds were defined from which a random duration will be picked.\n node.duration = [nodeArguments[0].value as number, nodeArguments[1].value as number];\n\n // A wait node must have a positive min and max duration.\n if (node.duration[0] < 0 || node.duration[1] < 0) {\n throw new Error(\"a wait node must have a positive minimum and maximum duration\");\n }\n\n // A wait node must not have a minimum duration that exceeds the maximum duration.\n if (node.duration[0] > node.duration[1]) {\n throw new Error(\"a wait node must not have a minimum duration that exceeds the maximum duration\");\n }\n } else if (nodeArguments.length > 2) {\n // An incorrect number of duration arguments were defined.\n throw new Error(\"invalid number of wait node duration arguments defined\");\n }\n }\n\n // Return the wait node definition.\n return { ...node, ...parseAttributeTokens(tokens, stringLiteralPlaceholders) };\n}\n\n/**\n * Creates a branch node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The branch node JSON definition.\n */\nfunction createBranchNode(\n tokens: string[],\n stringLiteralPlaceholders: StringLiteralPlaceholders\n): BranchNodeDefinition {\n // Parse any node arguments, we should have one which will be an identifier argument for the root ref.\n const nodeArguments = parseArgumentTokens(tokens, stringLiteralPlaceholders);\n\n // We should have only a single identifer argument for a branch node, which is the root ref.\n if (nodeArguments.length !== 1 || nodeArguments[0].type !== \"identifier\") {\n throw new Error(\"expected single branch name argument\");\n }\n\n // Return the branch node definition.\n return { type: \"branch\", ref: nodeArguments[0].value };\n}\n\n/**\n * Validate a fully-populated node definition that was popped off of the tree stack.\n * @param node The popped node to validate.\n */\nfunction validatePoppedNode(node: AnyNodeDefinition): void {\n // Decorators MUST have a child defined.\n if (isDecoratorNode(node) && isNullOrUndefined(node.child)) {\n throw new Error(`a ${node.type} node must have a single child node defined`);\n }\n\n // Composites MUST have at least one child defined.\n if (isCompositeNode(node) && !node.children?.length) {\n throw new Error(`a ${node.type} node must have at least a single child node defined`);\n }\n}\n", "import { RootNodeDefinition } from \"./BehaviourTreeDefinition\";\nimport { flattenDefinition, isBranchNode, isInteger } from \"./BehaviourTreeDefinitionUtilities\";\nimport { convertMDSLToJSON } from \"./mdsl/MDSLDefinitionParser\";\n\n/**\n * An object representing the result of validating a tree definition.\n */\nexport type DefinitionValidationResult = {\n /**\n * A flag defining whether validation succeeded.\n */\n succeeded: boolean;\n /**\n * A string containing the error message if validation did not succeed.\n */\n errorMessage?: string;\n};\n\n/**\n * Validates the specified behaviour tree definition in the form of JSON or MDSL, not taking any globally registered subtrees into consideration.\n * @param definition The behaviour tree definition in the form of JSON or MDSL.\n * @returns An object representing the result of validating the given tree definition.\n */\nexport function validateDefinition(definition: any): DefinitionValidationResult {\n // The definition must be defined.\n if (definition === null || typeof definition === \"undefined\") {\n return createValidationFailureResult(\"definition is null or undefined\");\n }\n\n // We are expecting a definition in one of three different forms:\n // - A string which we will assume is MDSL and we will parse this to JSON before validation.\n // - An array which we will assume is an array of root node definitions with at least one being the primary root node (no 'id' property)\n // - An object which we will assume is the primary root node and should not have an 'id' property.\n if (typeof definition === \"string\") {\n // The definition is a string which we can assume is MDSL, so attempt to validate it.\n return validateMDSLDefinition(definition);\n } else if (typeof definition === \"object\") {\n // The definition will either be an array (of root node definitions) or an object (the single primary root node definition).\n return validateJSONDefinition(definition);\n } else {\n return createValidationFailureResult(`unexpected definition type of '${typeof definition}'`);\n }\n}\n\n/**\n * Validates the specified behaviour tree definition in the form of MDSL.\n * @param definition The behaviour tree definition in the form of MDSL.\n * @returns An object representing the result of validating the given tree definition.\n */\nexport function validateMDSLDefinition(definition: string): DefinitionValidationResult {\n let rootNodeDefinitions;\n\n // The first thing the we need to do is to attempt to convert our MDSL into JSON.\n try {\n // The definition is a string which we can assume is MDSL, so attempt to parse it to a JSON definition in the form of an array of root node definitions.\n rootNodeDefinitions = convertMDSLToJSON(definition);\n } catch (error) {\n // We failed to parse the JSON from the MDSL, this is likely to be the result of it not being a valid MDSL string.\n return createValidationFailureResult(`invalid MDSL: ${error}`);\n }\n\n // Unpack all of the root node definitions into arrays of main ('id' defined) and sub ('id' not defined) root node definitions.\n const mainRootNodeDefinitions = rootNodeDefinitions.filter(({ id }) => typeof id === \"undefined\");\n const subRootNodeDefinitions = rootNodeDefinitions.filter(({ id }) => typeof id === \"string\" && id.length > 0);\n\n // We should ALWAYS have exactly one root node definition without an 'id' property defined, which is out main root node definition.\n if (mainRootNodeDefinitions.length !== 1) {\n return createValidationFailureResult(\n \"expected single unnamed root node at base of definition to act as main root\"\n );\n }\n\n // We should never have duplicate 'id' properties across our sub root node definitions.\n const subRootNodeIdenitifers: string[] = [];\n for (const { id } of subRootNodeDefinitions) {\n // Have we already come across this 'id' property value?\n if (subRootNodeIdenitifers.includes(id!)) {\n return createValidationFailureResult(`multiple root nodes found with duplicate name '${id}'`);\n }\n\n subRootNodeIdenitifers.push(id!);\n }\n\n try {\n // Validate our branch -> subtree links and check for any circular dependencies, we don't care about checking for broken subtree links here.\n validateBranchSubtreeLinks(rootNodeDefinitions, false);\n } catch (exception) {\n return createValidationFailureResult((exception as Error).message);\n }\n\n // Our definition was valid!\n return { succeeded: true };\n}\n\n/**\n * Validates the specified behaviour tree definition in the form of JSON.\n * @param definition The behaviour tree definition in the form of JSON.\n * @returns An object representing the result of validating the given tree definition.\n */\nexport function validateJSONDefinition(\n definition: RootNodeDefinition | RootNodeDefinition[]\n): DefinitionValidationResult {\n // The definition will either be an array (of root node definitions) or an object (the single primary root node definition).\n const rootNodeDefinitions = Array.isArray(definition) ? definition : [definition];\n\n // Iterate over our array of root nodes and call validateNode for each, passing an initial depth of 0, wrapped in a try catch to handle validation failures.\n try {\n rootNodeDefinitions.forEach((rootNodeDefinition) => validateNode(rootNodeDefinition, 0));\n } catch (error) {\n // Handle cases where we have caught a thrown Error and return a failure result with the error message.\n if (error instanceof Error) {\n return createValidationFailureResult(error.message);\n }\n\n // No idea what happened here!\n return createValidationFailureResult(`unexpected error: ${error}`);\n }\n\n // Unpack all of the root node definitions into arrays of main ('id' defined) and sub ('id' not defined) root node definitions.\n const mainRootNodeDefinitions = rootNodeDefinitions.filter(({ id }) => typeof id === \"undefined\");\n const subRootNodeDefinitions = rootNodeDefinitions.filter(({ id }) => typeof id === \"string\" && id.length > 0);\n\n // We should ALWAYS have exactly one root node definition without an 'id' property defined, which is out main root node definition.\n if (mainRootNodeDefinitions.length !== 1) {\n return createValidationFailureResult(\n \"expected single root node without 'id' property defined to act as main root\"\n );\n }\n\n // We should never have duplicate 'id' properties across our sub root node definitions.\n const subRootNodeIdenitifers: string[] = [];\n for (const { id } of subRootNodeDefinitions) {\n // Have we already come across this 'id' property value?\n if (subRootNodeIdenitifers.includes(id!)) {\n return createValidationFailureResult(\n `multiple root nodes found with duplicate 'id' property value of '${id}'`\n );\n }\n\n subRootNodeIdenitifers.push(id!);\n }\n\n try {\n // Validate our branch -> subtree links and check for any circular dependencies, we don't care about checking for broken subtree links here.\n validateBranchSubtreeLinks(rootNodeDefinitions, false);\n } catch (exception) {\n return createValidationFailureResult((exception as Error).message);\n }\n\n // Our definition was valid!\n return { succeeded: true };\n}\n\n/**\n * Validates the branch -> subtree links across all provided root node definitions.\n * This will not consider branch nodes that reference any globally registered subtrees unless includesGlobalSubtrees\n * is set to true, in which case we will also verify that there are no broken branch -> subtree links.\n * @param rootNodeDefinitions The array of root node definitions.\n * @param includesGlobalSubtrees A flag defining whether the array includes all global subtree root node definitions.\n */\nexport function validateBranchSubtreeLinks(rootNodeDefinitions: RootNodeDefinition[], includesGlobalSubtrees: boolean) {\n // Create a mapping of root node identifiers to other root nodes that they reference via branch nodes.\n // Below is an example of a mapping that includes a circular dependency (root => a => b => c => a)\n // [{ refs: [\"a\", \"b\"] }, { id: \"a\", refs: [\"b\"] }, { id: \"b\", refs: [\"c\"] }, { id: \"c\", refs: [\"a\"] }]\n const rootNodeMappings: { id: string | undefined; refs: string[] }[] = rootNodeDefinitions.map(\n (rootNodeDefinition) => ({\n id: rootNodeDefinition.id,\n refs: flattenDefinition(rootNodeDefinition)\n .filter(isBranchNode)\n .map(({ ref }) => ref)\n })\n );\n\n // A recursive function to walk through the mappings, keeping track of which root nodes we have visited in the form of a path of root node identifiers.\n const followRefs = (mapping: { id: string | undefined; refs: string[] }, path: (string | undefined)[] = []) => {\n // Have we found a circular dependency?\n if (path.includes(mapping.id)) {\n // We found a circular dependency! Get the bad path of root node identifiers.\n const badPath = [...path, mapping.id];\n\n // Create the formatted path value. [undefined, \"a\", \"b\", \"c\", \"a\"] would be formatted as \"a -> b -> c -> a\".\n const badPathFormatted = badPath.filter((element) => !!element).join(\" => \");\n\n // No need to continue, we found a circular dependency.\n throw new Error(`circular dependency found in branch node references: ${badPathFormatted}`);\n }\n\n for (const ref of mapping.refs) {\n // Find the mapping for the root node with an identifer matching the current ref.\n const subMapping = rootNodeMappings.find(({ id }) => id === ref);\n\n // We may not have a mapping for this ref, which is normal when we aren't considering all globally registered subtrees.\n if (subMapping) {\n followRefs(subMapping, [...path, mapping.id]);\n } else if (includesGlobalSubtrees) {\n // We found a reference to a root node that doesn't exist, which is a problem seeing as the root node definitons includes all globally registered subtrees.\n throw new Error(\n mapping.id\n ? `subtree '${mapping.id}' has branch node that references root node '${ref}' which has not been defined`\n : `primary tree has branch node that references root node '${ref}' which has not been defined`\n );\n }\n }\n };\n\n // Start looking for circular dependencies and broken references from the primary root node definition.\n followRefs(rootNodeMappings.find((mapping) => typeof mapping.id === \"undefined\")!);\n}\n\n/**\n * Validate an object that we expect to be a node definition.\n * @param definition An object that we expect to be a node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateNode(definition: any, depth: number): void {\n // Every node must be valid object and have a non-empty 'type' string property.\n if (typeof definition !== \"object\" || typeof definition.type !== \"string\" || definition.type.length === 0) {\n throw new Error(\n `node definition is not an object or 'type' property is not a non-empty string at depth '${depth}'`\n );\n }\n\n // How we validate this node definition will depend on its type.\n switch (definition.type) {\n case \"action\":\n validateActionNode(definition, depth);\n break;\n\n case \"condition\":\n validateConditionNode(definition, depth);\n break;\n\n case \"wait\":\n validateWaitNode(definition, depth);\n break;\n\n case \"branch\":\n validateBranchNode(definition, depth);\n break;\n\n case \"root\":\n validateRootNode(definition, depth);\n break;\n\n case \"success\":\n validateSuccessNode(definition, depth);\n break;\n\n case \"fail\":\n validateFailNode(definition, depth);\n break;\n\n case \"flip\":\n validateFlipNode(definition, depth);\n break;\n\n case \"repeat\":\n validateRepeatNode(definition, depth);\n break;\n\n case \"retry\":\n validateRetryNode(definition, depth);\n break;\n\n case \"sequence\":\n validateSequenceNode(definition, depth);\n break;\n\n case \"selector\":\n validateSelectorNode(definition, depth);\n break;\n\n case \"parallel\":\n validateParallelNode(definition, depth);\n break;\n\n default:\n throw new Error(`unexpected node type of '${definition.type}' at depth '${depth}'`);\n }\n}\n\n/**\n * Validate any attributes for a given node definition.\n * @param definition The node definition.\n * @param depth The depth of the node in the behaviour tree definition.\n */\nfunction validateNodeAttributes(definition: any, depth: number): void {\n // Validate each of the attribute types for this node.\n [\"while\", \"until\", \"entry\", \"exit\", \"step\"].forEach((attributeName) => {\n // Attempt to grab the definition for the current attribute from the node definition.\n const attributeDefinition = definition[attributeName];\n\n // All node attributes are optional, so there is nothing to do if the current attribute is not defined.\n if (typeof attributeDefinition === \"undefined\") {\n return;\n }\n\n // The attribute definition must be an object.\n if (typeof attributeDefinition !== \"object\") {\n throw new Error(\n `expected attribute '${attributeName}' to be an object for '${definition.type}' node at depth '${depth}'`\n );\n }\n\n // The 'call' property must be defined for any attribute definition.\n if (typeof attributeDefinition.call !== \"string\" || attributeDefinition.call.length === 0) {\n throw new Error(\n `expected 'call' property for attribute '${attributeName}' to be a non-empty string for '${definition.type}' node at depth '${depth}'`\n );\n }\n\n // If any node attribute arguments have been defined then they must have been defined in an array.\n if (typeof attributeDefinition.args !== \"undefined\" && !Array.isArray(attributeDefinition.args)) {\n throw new Error(\n `expected 'args' property for attribute '${attributeName}' to be an array for '${definition.type}' node at depth '${depth}'`\n );\n }\n });\n}\n\n/**\n * Validate an object that we expect to be a root node definition.\n * @param definition An object that we expect to be a root node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateRootNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"root\") {\n throw new Error(\"expected node type of 'root' for root node\");\n }\n\n // A root node cannot be the child of another node.\n if (depth > 0) {\n throw new Error(\"a root node cannot be the child of another node\");\n }\n\n // Check that, if the root node 'id' property is defined, it is a non-empty string.\n if (typeof definition.id !== \"undefined\" && (typeof definition.id !== \"string\" || definition.id.length === 0)) {\n throw new Error(\"expected non-empty string for 'id' property if defined for root node\");\n }\n\n // A root node is a decorator node, so must have a child node defined.\n if (typeof definition.child === \"undefined\") {\n throw new Error(\"expected property 'child' to be defined for root node\");\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n\n // Validate the child node of this decorator node.\n validateNode(definition.child, depth + 1);\n}\n\n/**\n * Validate an object that we expect to be a success node definition.\n * @param definition An object that we expect to be a success node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateSuccessNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"success\") {\n throw new Error(`expected node type of 'success' for success node at depth '${depth}'`);\n }\n\n // A success node is a decorator node, so must have a child node defined.\n if (typeof definition.child === \"undefined\") {\n throw new Error(`expected property 'child' to be defined for success node at depth '${depth}'`);\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n\n // Validate the child node of this decorator node.\n validateNode(definition.child, depth + 1);\n}\n\n/**\n * Validate an object that we expect to be a fail node definition.\n * @param definition An object that we expect to be a fail node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateFailNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"fail\") {\n throw new Error(`expected node type of 'fail' for fail node at depth '${depth}'`);\n }\n\n // A fail node is a decorator node, so must have a child node defined.\n if (typeof definition.child === \"undefined\") {\n throw new Error(`expected property 'child' to be defined for fail node at depth '${depth}'`);\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n\n // Validate the child node of this decorator node.\n validateNode(definition.child, depth + 1);\n}\n\n/**\n * Validate an object that we expect to be a flip node definition.\n * @param definition An object that we expect to be a flip node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateFlipNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"flip\") {\n throw new Error(`expected node type of 'flip' for flip node at depth '${depth}'`);\n }\n\n // A flip node is a decorator node, so must have a child node defined.\n if (typeof definition.child === \"undefined\") {\n throw new Error(`expected property 'child' to be defined for flip node at depth '${depth}'`);\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n\n // Validate the child node of this decorator node.\n validateNode(definition.child, depth + 1);\n}\n\n/**\n * Validate an object that we expect to be a repeat node definition.\n * @param definition An object that we expect to be a repeat node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateRepeatNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"repeat\") {\n throw new Error(`expected node type of 'repeat' for repeat node at depth '${depth}'`);\n }\n\n // A repeat node is a decorator node, so must have a child node defined.\n if (typeof definition.child === \"undefined\") {\n throw new Error(`expected property 'child' to be defined for repeat node at depth '${depth}'`);\n }\n\n // Check whether an 'iterations' property has been defined, it may not have been if this node is to repeat indefinitely.\n if (typeof definition.iterations !== \"undefined\") {\n if (Array.isArray(definition.iterations)) {\n // Check whether any elements of the array are not integer values.\n const containsNonInteger = !!definition.iterations.find((value: unknown) => !isInteger(value));\n\n // If the 'iterations' property is an array then it MUST contain two integer values.\n if (definition.iterations.length !== 2 || containsNonInteger) {\n throw new Error(\n `expected array containing two integer values for 'iterations' property if defined for repeat node at depth '${depth}'`\n );\n }\n\n // A repeat node must have a positive min and max iterations count if they are defined.\n if (definition.iterations[0] < 0 || definition.iterations[1] < 0) {\n throw new Error(\n `expected positive minimum and maximum iterations count for 'iterations' property if defined for repeat node at depth '${depth}'`\n );\n }\n\n // A repeat node must not have a minimum iterations count that exceeds the maximum iterations count.\n if (definition.iterations[0] > definition.iterations[1]) {\n throw new Error(\n `expected minimum iterations count that does not exceed the maximum iterations count for 'iterations' property if defined for repeat node at depth '${depth}'`\n );\n }\n } else if (isInteger(definition.iterations)) {\n // A repeat node must have a positive number of iterations if defined.\n if (definition.iterations < 0) {\n throw new Error(\n `expected positive iterations count for 'iterations' property if defined for repeat node at depth '${depth}'`\n );\n }\n } else {\n throw new Error(\n `expected integer value or array containing two integer values for 'iterations' property if defined for repeat node at depth '${depth}'`\n );\n }\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n\n // Validate the child node of this decorator node.\n validateNode(definition.child, depth + 1);\n}\n\n/**\n * Validate an object that we expect to be a retry node definition.\n * @param definition An object that we expect to be a retry node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateRetryNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"retry\") {\n throw new Error(`expected node type of 'retry' for retry node at depth '${depth}'`);\n }\n\n // A retry node is a decorator node, so must have a child node defined.\n if (typeof definition.child === \"undefined\") {\n throw new Error(`expected property 'child' to be defined for retry node at depth '${depth}'`);\n }\n\n // Check whether an 'attempts' property has been defined, it may not have been if this node is to retry indefinitely.\n if (typeof definition.attempts !== \"undefined\") {\n if (Array.isArray(definition.attempts)) {\n // Check whether any elements of the array are not integer values.\n const containsNonInteger = !!definition.attempts.find((value: unknown) => !isInteger(value));\n\n // If the 'attempts' property is an array then it MUST contain two integer values.\n if (definition.attempts.length !== 2 || containsNonInteger) {\n throw new Error(\n `expected array containing two integer values for 'attempts' property if defined for retry node at depth '${depth}'`\n );\n }\n\n // A retry node must have a positive min and max attempts count if they are defined.\n if (definition.attempts[0] < 0 || definition.attempts[1] < 0) {\n throw new Error(\n `expected positive minimum and maximum attempts count for 'attempts' property if defined for retry node at depth '${depth}'`\n );\n }\n\n // A retry node must not have a minimum attempts count that exceeds the maximum attempts count.\n if (definition.attempts[0] > definition.attempts[1]) {\n throw new Error(\n `expected minimum attempts count that does not exceed the maximum attempts count for 'attempts' property if defined for retry node at depth '${depth}'`\n );\n }\n } else if (isInteger(definition.attempts)) {\n // A retry node must have a positive number of attempts if defined.\n if (definition.attempts < 0) {\n throw new Error(\n `expected positive attempts count for 'attempts' property if defined for retry node at depth '${depth}'`\n );\n }\n } else {\n throw new Error(\n `expected integer value or array containing two integer values for 'attempts' property if defined for retry node at depth '${depth}'`\n );\n }\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n\n // Validate the child node of this decorator node.\n validateNode(definition.child, depth + 1);\n}\n\n/**\n * Validate an object that we expect to be a branch node definition.\n * @param definition An object that we expect to be a branch node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateBranchNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"branch\") {\n throw new Error(`expected node type of 'branch' for branch node at depth '${depth}'`);\n }\n\n // Check that the branch node 'ref' property is defined and is a non-empty string.\n if (typeof definition.ref !== \"string\" || definition.ref.length === 0) {\n throw new Error(`expected non-empty string for 'ref' property for branch node at depth '${depth}'`);\n }\n\n // It is invalid to define guard attributes for a branch node as they should be defined on the referenced root node.\n [\"while\", \"until\"].forEach((attributeName) => {\n if (typeof definition[attributeName] !== \"undefined\") {\n throw new Error(\n `guards should not be defined for branch nodes but guard '${attributeName}' was defined for branch node at depth '${depth}'`\n );\n }\n });\n\n // It is invalid to define callback attributes for a branch node as they should be defined on the referenced root node.\n [\"entry\", \"exit\", \"step\"].forEach((attributeName) => {\n if (typeof definition[attributeName] !== \"undefined\") {\n throw new Error(\n `callbacks should not be defined for branch nodes but callback '${attributeName}' was defined for branch node at depth '${depth}'`\n );\n }\n });\n}\n\n/**\n * Validate an object that we expect to be a action node definition.\n * @param definition An object that we expect to be a action node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateActionNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"action\") {\n throw new Error(`expected node type of 'action' for action node at depth '${depth}'`);\n }\n\n // The 'call' property must be defined for a action node definition.\n if (typeof definition.call !== \"string\" || definition.call.length === 0) {\n throw new Error(`expected non-empty string for 'call' property of action node at depth '${depth}'`);\n }\n\n // If any action function arguments have been defined then they must have been defined in an array.\n if (typeof definition.args !== \"undefined\" && !Array.isArray(definition.args)) {\n throw new Error(`expected array for 'args' property if defined for action node at depth '${depth}'`);\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n}\n\n/**\n * Validate an object that we expect to be a condition node definition.\n * @param definition An object that we expect to be a condition node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateConditionNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"condition\") {\n throw new Error(`expected node type of 'condition' for condition node at depth '${depth}'`);\n }\n\n // The 'call' property must be defined for a condition node definition.\n if (typeof definition.call !== \"string\" || definition.call.length === 0) {\n throw new Error(`expected non-empty string for 'call' property of condition node at depth '${depth}'`);\n }\n\n // If any condition function arguments have been defined then they must have been defined in an array.\n if (typeof definition.args !== \"undefined\" && !Array.isArray(definition.args)) {\n throw new Error(`expected array for 'args' property if defined for condition node at depth '${depth}'`);\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n}\n\n/**\n * Validate an object that we expect to be a wait node definition.\n * @param definition An object that we expect to be a wait node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateWaitNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"wait\") {\n throw new Error(`expected node type of 'wait' for wait node at depth '${depth}'`);\n }\n\n // Check whether a 'duration' property has been defined, it may not have been if this node is to wait indefinitely.\n if (typeof definition.duration !== \"undefined\") {\n if (Array.isArray(definition.duration)) {\n // Check whether any elements of the array are not integer values.\n const containsNonInteger = !!definition.duration.find((value: unknown) => !isInteger(value));\n\n // If the 'duration' property is an array then it MUST contain two integer values.\n if (definition.duration.length !== 2 || containsNonInteger) {\n throw new Error(\n `expected array containing two integer values for 'duration' property if defined for wait node at depth '${depth}'`\n );\n }\n\n // A wait node must have a positive min and max duration value if they are defined.\n if (definition.duration[0] < 0 || definition.duration[1] < 0) {\n throw new Error(\n `expected positive minimum and maximum duration for 'duration' property if defined for wait node at depth '${depth}'`\n );\n }\n\n // A wait node must not have a minimum duration value that exceeds the maximum duration value.\n if (definition.duration[0] > definition.duration[1]) {\n throw new Error(\n `expected minimum duration value that does not exceed the maximum duration value for 'duration' property if defined for wait node at depth '${depth}'`\n );\n }\n } else if (isInteger(definition.duration)) {\n // A wait node must have a positive duration value if defined.\n if (definition.duration < 0) {\n throw new Error(\n `expected positive duration value for 'duration' property if defined for wait node at depth '${depth}'`\n );\n }\n } else {\n throw new Error(\n `expected integer value or array containing two integer values for 'duration' property if defined for wait node at depth '${depth}'`\n );\n }\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n}\n\n/**\n * Validate an object that we expect to be a sequence node definition.\n * @param definition An object that we expect to be a sequence node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateSequenceNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"sequence\") {\n throw new Error(`expected node type of 'sequence' for sequence node at depth '${depth}'`);\n }\n\n // A sequence node is a composite node, so must have a children nodes array defined.\n if (!Array.isArray(definition.children) || definition.children.length === 0) {\n throw new Error(`expected non-empty 'children' array to be defined for sequence node at depth '${depth}'`);\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n\n // Validate the child nodes of this composite node.\n definition.children.forEach((child: any) => validateNode(child, depth + 1));\n}\n\n/**\n * Validate an object that we expect to be a selector node definition.\n * @param definition An object that we expect to be a selector node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateSelectorNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"selector\") {\n throw new Error(`expected node type of 'selector' for selector node at depth '${depth}'`);\n }\n\n // A selector node is a composite node, so must have a children nodes array defined.\n if (!Array.isArray(definition.children) || definition.children.length === 0) {\n throw new Error(`expected non-empty 'children' array to be defined for selector node at depth '${depth}'`);\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n\n // Validate the child nodes of this composite node.\n definition.children.forEach((child: any) => validateNode(child, depth + 1));\n}\n\n/**\n * Validate an object that we expect to be a parallel node definition.\n * @param definition An object that we expect to be a parallel node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateParallelNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"parallel\") {\n throw new Error(`expected node type of 'parallel' for parallel node at depth '${depth}'`);\n }\n\n // A parallel node is a composite node, so must have a children nodes array defined.\n if (!Array.isArray(definition.children) || definition.children.length === 0) {\n throw new Error(`expected non-empty 'children' array to be defined for parallel node at depth '${depth}'`);\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n\n // Validate the child nodes of this composite node.\n definition.children.forEach((child: any) => validateNode(child, depth + 1));\n}\n\n/**\n * A helper function to create a failure validation result with the given error message.\n * @param errorMessage The validation failure error message.\n * @returns A failure validation result with the given error message.\n */\nfunction createValidationFailureResult(errorMessage: string): DefinitionValidationResult {\n return { succeeded: false, errorMessage };\n}\n", "import { ActionResult, Agent, GlobalFunction } from \"./Agent\";\nimport { RootNodeDefinition } from \"./BehaviourTreeDefinition\";\n\nexport type InvokerFunction = (args: any[]) => ActionResult;\n\n/**\n * A singleton used to store and lookup registered functions and subtrees.\n */\nexport default class Lookup {\n /**\n * The object holding any registered functions keyed on function name.\n */\n private static functionTable: { [key: string]: GlobalFunction } = {};\n /**\n * The object holding any registered subtree root node definitions keyed on tree name.\n */\n private static subtreeTable: { [key: string]: RootNodeDefinition } = {};\n\n /**\n * Gets the function with the specified name.\n * @param name The name of the function.\n * @returns The function with the specified name.\n */\n public static getFunc(name: string): GlobalFunction {\n return this.functionTable[name];\n }\n\n /**\n * Sets the function with the specified name for later lookup.\n * @param name The name of the function.\n * @param func The function.\n */\n public static setFunc(name: string, func: GlobalFunction): void {\n this.functionTable[name] = func;\n }\n\n /**\n * Gets the function invoker for the specified agent and function name.\n * If a function with the specified name exists on the agent object then it will\n * be returned, otherwise we will then check the registered functions for a match.\n * @param agent The agent instance that this behaviour tree is modelling behaviour for.\n * @param name The function name.\n * @returns The function invoker for the specified agent and function name.\n */\n static getFuncInvoker(agent: Agent, name: string): InvokerFunction | null {\n // Check whether the agent contains the specified function.\n const foundOnAgent = agent[name];\n if (foundOnAgent && typeof foundOnAgent === \"function\") {\n return (args: any[]): boolean | ActionResult => foundOnAgent.apply(agent, args);\n }\n\n // The agent does not contain the specified function but it may have been registered at some point.\n if (this.functionTable[name] && typeof this.functionTable[name] === \"function\") {\n return (args: any[]) => this.functionTable[name](agent, ...args.map((arg) => arg.value));\n }\n\n // We have no function to invoke.\n return null;\n }\n\n /**\n * Gets all registered subtree root node definitions.\n */\n static getSubtrees(): { [key: string]: RootNodeDefinition } {\n return this.subtreeTable;\n }\n\n /**\n * Sets the subtree with the specified name for later lookup.\n * @param name The name of the subtree.\n * @param subtree The subtree.\n */\n static setSubtree(name: string, subtree: RootNodeDefinition) {\n this.subtreeTable[name] = subtree;\n }\n\n /**\n * Removes the registered function or subtree with the specified name.\n * @param name The name of the registered function or subtree.\n */\n static remove(name: string) {\n delete this.functionTable[name];\n delete this.subtreeTable[name];\n }\n\n /**\n * Remove all registered functions and subtrees.\n */\n static empty() {\n this.functionTable = {};\n this.subtreeTable = {};\n }\n}\n", "import Node from \"../../nodes/Node\";\n\n/**\n * An exception thrown when evaluating node guard path conditions and a conditions fails.\n */\nexport default class GuardUnsatisifedException extends Error {\n /**\n * @param source The node at which a guard condition failed.\n */\n constructor(private source: Node) {\n super(\"A guard path condition has failed\");\n }\n\n /**\n * Gets whether the specified node is the node at which a guard condition failed.\n * @param node The node to check against the source node.\n * @returns Whether the specified node is the node at which a guard condition failed.\n */\n isSourceNode = (node: Node) => node === this.source;\n}\n", "import { Agent } from \"../../Agent\";\nimport Guard from \"./Guard\";\nimport Node from \"../../nodes/Node\";\nimport GuardUnsatisifedException from \"./GuardUnsatisifedException\";\n\nexport type GuardPathPart = {\n node: Node;\n guards: Guard[];\n};\n\n/**\n * Represents a path of node guards along a root-to-leaf tree path.\n */\nexport default class GuardPath {\n /**\n * @param nodes An array of objects defining a node instance -> guard link, ordered by node depth.\n */\n constructor(private nodes: GuardPathPart[]) {}\n\n /**\n * Evaluate guard conditions for all guards in the tree path, moving outwards from the root.\n * @param agent The agent, required for guard evaluation.\n * @returns An evaluation results object.\n */\n evaluate = (agent: Agent) => {\n // We need to evaluate guard conditions for nodes up the tree, moving outwards from the root.\n for (const details of this.nodes) {\n // There can be multiple guards per node.\n for (const guard of details.guards) {\n // Check whether the guard condition passes, and throw an exception if not.\n if (!guard.isSatisfied(agent)) {\n throw new GuardUnsatisifedException(details.node);\n }\n }\n }\n };\n}\n", "import { BehaviourTreeOptions } from \"../BehaviourTreeOptions\";\nimport State, { AnyState } from \"../State\";\nimport { Agent } from \"../Agent\";\nimport Leaf from \"./leaf/Leaf\";\nimport Attribute from \"../attributes/Attribute\";\nimport Entry from \"../attributes/callbacks/Entry\";\nimport Exit from \"../attributes/callbacks/Exit\";\nimport Step from \"../attributes/callbacks/Step\";\nimport Guard from \"../attributes/guards/Guard\";\nimport GuardPath from \"../attributes/guards/GuardPath\";\nimport GuardUnsatisifedException from \"../attributes/guards/GuardUnsatisifedException\";\n\n/**\n * A base node.\n */\nexport default abstract class Node {\n /**\n * The node uid.\n */\n private readonly uid: string = createNodeUid();\n /**\n * The node state.\n */\n private state: AnyState = State.READY;\n /**\n * The guard path to evaluate as part of a node update.\n */\n private guardPath: GuardPath | undefined;\n\n /**\n * @param type The node type.\n * @param attributes The node attributes.\n * @param args The node argument definitions.\n */\n constructor(private type: string, private attributes: Attribute[], private args: any[]) {}\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected abstract onUpdate(agent: Agent, options: BehaviourTreeOptions): void;\n\n /**\n * Gets the name of the node.\n */\n public abstract getName(): string;\n\n /**\n * Gets whether this node is a leaf node.\n */\n public abstract isLeafNode: () => this is Leaf;\n\n /**\n * Gets/Sets the state of the node.\n */\n getState = (): AnyState => this.state;\n setState = (value: AnyState): void => {\n this.state = value;\n };\n\n /**\n * Gets the unique id of the node.\n */\n getUid = () => this.uid;\n\n /**\n * Gets the type of the node.\n */\n getType = () => this.type;\n\n /**\n * Gets the node attributes.\n */\n getAttributes = () => this.attributes;\n\n /**\n * Gets the node arguments.\n */\n getArguments = () => this.args;\n\n /**\n * Gets the node attribute with the specified type, or null if it does not exist.\n */\n getAttribute(type: \"entry\" | \"ENTRY\"): Entry;\n getAttribute(type: \"exit\" | \"EXIT\"): Exit;\n getAttribute(type: \"step\" | \"STEP\"): Step;\n getAttribute(type: string): Attribute {\n return (\n this.getAttributes().filter((decorator) => decorator.type.toUpperCase() === type.toUpperCase())[0] || null\n );\n }\n\n /**\n * Gets the node attributes.\n */\n getGuardAttributes = (): Guard[] => this.getAttributes().filter((decorator) => decorator.isGuard()) as Guard[];\n\n /**\n * Sets the guard path to evaluate as part of a node update.\n */\n setGuardPath = (value: GuardPath) => (this.guardPath = value);\n\n /**\n * Gets whether a guard path is assigned to this node.\n */\n hasGuardPath = () => !!this.guardPath;\n\n /**\n * Gets whether this node is in the specified state.\n * @param value The value to compare to the node state.\n */\n public is(value: AnyState): boolean {\n return this.state === value;\n }\n\n /**\n * Reset the state of the node.\n */\n public reset(): void {\n this.setState(State.READY);\n }\n\n /**\n * Abort the running of this node.\n * @param agent The agent.\n */\n public abort(agent: Agent): void {\n // There is nothing to do if this node is not in the running state.\n if (!this.is(State.RUNNING)) {\n return;\n }\n\n // Reset the state of this node.\n this.reset();\n\n this.getAttribute(\"exit\")?.callAgentFunction(agent, false, true);\n }\n\n /**\n * Update the node.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n * @returns The result of the update.\n */\n public update(agent: Agent, options: BehaviourTreeOptions): void {\n // If this node is already in a 'SUCCEEDED' or 'FAILED' state then there is nothing to do.\n if (this.is(State.SUCCEEDED) || this.is(State.FAILED)) {\n return;\n }\n\n try {\n // Evaluate all of the guard path conditions for the current tree path.\n this.guardPath!.evaluate(agent);\n\n // If this node is in the READY state then call the ENTRY for this node if it exists.\n if (this.is(State.READY)) {\n this.getAttribute(\"entry\")?.callAgentFunction(agent);\n }\n\n this.getAttribute(\"step\")?.callAgentFunction(agent);\n\n // Do the actual update.\n this.onUpdate(agent, options);\n\n // If this node is now in a 'SUCCEEDED' or 'FAILED' state then call the EXIT for this node if it exists.\n if (this.is(State.SUCCEEDED) || this.is(State.FAILED)) {\n this.getAttribute(\"exit\")?.callAgentFunction(agent, this.is(State.SUCCEEDED), false);\n }\n } catch (error) {\n // If the error is a GuardUnsatisfiedException then we need to determine if this node is the source.\n if (error instanceof GuardUnsatisifedException && error.isSourceNode(this)) {\n // Abort the current node.\n this.abort(agent);\n\n // Any node that is the source of an abort will be a failed node.\n this.setState(State.FAILED);\n } else {\n throw error;\n }\n }\n }\n}\n\n/**\n * Create a randomly generated node uid.\n * @returns A randomly generated node uid.\n */\nfunction createNodeUid(): string {\n var S4 = function () {\n return (((1 + Math.random()) * 0x10000) | 0).toString(16).substring(1);\n };\n return S4() + S4() + \"-\" + S4() + \"-\" + S4() + \"-\" + S4() + \"-\" + S4() + S4() + S4();\n}\n", "import Node from \"../Node\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\n\n/**\n * A composite node that wraps child nodes.\n */\nexport default abstract class Composite extends Node {\n /**\n * @param type The node type.\n * @param attributes The node attributes.\n * @param children The child nodes.\n */\n constructor(type: string, attributes: Attribute[], protected children: Node[]) {\n super(type, attributes, []);\n }\n\n /**\n * Gets whether this node is a leaf node.\n */\n isLeafNode = () => false;\n\n /**\n * Gets the children of this node.\n */\n getChildren = () => this.children;\n\n /**\n * Reset the state of the node.\n */\n reset = () => {\n // Reset the state of this node.\n this.setState(State.READY);\n\n // Reset the state of any child nodes.\n this.getChildren().forEach((child) => child.reset());\n };\n\n /**\n * Abort the running of this node.\n * @param agent The agent.\n */\n abort = (agent: Agent) => {\n // There is nothing to do if this node is not in the running state.\n if (!this.is(State.RUNNING)) {\n return;\n }\n\n // Abort any child nodes.\n this.getChildren().forEach((child) => child.abort(agent));\n\n // Reset the state of this node.\n this.reset();\n\n this.getAttribute(\"exit\")?.callAgentFunction(agent, false, true);\n };\n}\n", "import Composite from \"./Composite\";\nimport State from \"../../State\";\nimport Node from \"../Node\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A PARALLEL node.\n * The child nodes are executed concurrently until one fails or all succeed.\n */\nexport default class Parallel extends Composite {\n /**\n * @param attributes The node attributes.\n * @param children The child nodes.\n */\n constructor(attributes: Attribute[], children: Node[]) {\n super(\"parallel\", attributes, children);\n }\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // Keep a count of the number of succeeded child nodes.\n let succeededCount = 0;\n\n let hasChildFailed = false;\n\n // Iterate over all of the children of this node.\n for (const child of this.children) {\n // If the child has never been updated or is running then we will need to update it now.\n if (child.getState() === State.READY || child.getState() === State.RUNNING) {\n // Update the child of this node.\n child.update(agent, options);\n }\n\n // If the current child has a state of 'SUCCEEDED' then we should move on to the next child.\n if (child.getState() === State.SUCCEEDED) {\n // The child node has succeeded, keep track of this to determine if all children have.\n succeededCount++;\n\n // The child node succeeded, but we have not finished checking every child node yet.\n continue;\n }\n\n // If the current child has a state of 'FAILED' then this node is also a 'FAILED' node.\n if (child.getState() === State.FAILED) {\n hasChildFailed = true;\n\n // There is no need to check the rest of the children.\n break;\n }\n\n // The node should be in the 'RUNNING' state.\n if (child.getState() !== State.RUNNING) {\n // The child node was not in an expected state.\n throw new Error(\"child node was not in an expected state.\");\n }\n }\n\n if (hasChildFailed) {\n // This node is a 'FAILED' node.\n this.setState(State.FAILED);\n\n // Abort every running child.\n for (const child of this.children) {\n if (child.getState() === State.RUNNING) {\n child.abort(agent);\n }\n }\n } else {\n // If all children have succeeded then this node has also succeeded, otherwise it is still running.\n this.setState(succeededCount === this.children.length ? State.SUCCEEDED : State.RUNNING);\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => \"PARALLEL\";\n}\n", "import Composite from \"./Composite\";\nimport Node from \"../Node\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A SELECTOR node.\n * The child nodes are executed in sequence until one succeeds or all fail.\n */\nexport default class Selector extends Composite {\n /**\n * @param attributes The node attributes.\n * @param children The child nodes.\n */\n constructor(attributes: Attribute[], protected children: Node[]) {\n super(\"selector\", attributes, children);\n }\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // Iterate over all of the children of this node.\n for (const child of this.children) {\n // If the child has never been updated or is running then we will need to update it now.\n if (child.getState() === State.READY || child.getState() === State.RUNNING) {\n // Update the child of this node.\n child.update(agent, options);\n }\n\n // If the current child has a state of 'SUCCEEDED' then this node is also a 'SUCCEEDED' node.\n if (child.getState() === State.SUCCEEDED) {\n // This node is a 'SUCCEEDED' node.\n this.setState(State.SUCCEEDED);\n\n // There is no need to check the rest of the selector nodes.\n return;\n }\n\n // If the current child has a state of 'FAILED' then we should move on to the next child.\n if (child.getState() === State.FAILED) {\n // Find out if the current child is the last one in the selector.\n // If it is then this sequence node has also failed.\n if (this.children.indexOf(child) === this.children.length - 1) {\n // This node is a 'FAILED' node.\n this.setState(State.FAILED);\n\n // There is no need to check the rest of the selector as we have completed it.\n return;\n } else {\n // The child node failed, try the next one.\n continue;\n }\n }\n\n // The node should be in the 'RUNNING' state.\n if (child.getState() === State.RUNNING) {\n // This node is a 'RUNNING' node.\n this.setState(State.RUNNING);\n\n // There is no need to check the rest of the selector as the current child is still running.\n return;\n }\n\n // The child node was not in an expected state.\n throw new Error(\"child node was not in an expected state.\");\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => \"SELECTOR\";\n}\n", "import Composite from \"./Composite\";\nimport Node from \"../Node\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A SEQUENCE node.\n * The child nodes are executed in sequence until one fails or all succeed.\n */\nexport default class Sequence extends Composite {\n /**\n * @param attributes The node attributes.\n * @param children The child nodes.\n */\n constructor(attributes: Attribute[], protected children: Node[]) {\n super(\"sequence\", attributes, children);\n }\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // Iterate over all of the children of this node.\n for (const child of this.children) {\n // If the child has never been updated or is running then we will need to update it now.\n if (child.getState() === State.READY || child.getState() === State.RUNNING) {\n // Update the child of this node.\n child.update(agent, options);\n }\n\n // If the current child has a state of 'SUCCEEDED' then we should move on to the next child.\n if (child.getState() === State.SUCCEEDED) {\n // Find out if the current child is the last one in the sequence.\n // If it is then this sequence node has also succeeded.\n if (this.children.indexOf(child) === this.children.length - 1) {\n // This node is a 'SUCCEEDED' node.\n this.setState(State.SUCCEEDED);\n\n // There is no need to check the rest of the sequence as we have completed it.\n return;\n } else {\n // The child node succeeded, but we have not finished the sequence yet.\n continue;\n }\n }\n\n // If the current child has a state of 'FAILED' then this node is also a 'FAILED' node.\n if (child.getState() === State.FAILED) {\n // This node is a 'FAILED' node.\n this.setState(State.FAILED);\n\n // There is no need to check the rest of the sequence.\n return;\n }\n\n // The node should be in the 'RUNNING' state.\n if (child.getState() === State.RUNNING) {\n // This node is a 'RUNNING' node.\n this.setState(State.RUNNING);\n\n // There is no need to check the rest of the sequence as the current child is still running.\n return;\n }\n\n // The child node was not in an expected state.\n throw new Error(\"child node was not in an expected state.\");\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => \"SEQUENCE\";\n}\n", "import createLotto from \"lotto-draw\";\n\nimport Node from \"../Node\";\nimport Composite from \"./Composite\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A LOTTO node.\n * A winning child is picked on the initial update of this node, based on ticket weighting.\n * The state of this node will match the state of the winning child.\n */\nexport default class Lotto extends Composite {\n /**\n * @param attributes The node attributes.\n * @param weights The child node weights.\n * @param children The child nodes.\n */\n constructor(attributes: Attribute[], private weights: number[] | undefined, children: Node[]) {\n super(\"lotto\", attributes, children);\n }\n\n /**\n * The child node selected to be the active one.\n */\n private selectedChild: Node | undefined;\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // If this node is in the READY state then we need to pick a winning child node.\n if (this.is(State.READY)) {\n // Create a lotto draw with which to randomly pick a child node to become the active one.\n const lottoDraw = createLotto({\n // Hook up the optional 'random' behaviour tree function option to the one used by 'lotto-draw'.\n random: options.random,\n // Pass in each child node as a participant in the lotto draw with their respective ticket count.\n participants: this.children.map((child, index) => [child, this.weights?.[index] || 1])\n });\n\n // Randomly pick a child based on ticket weighting, this will become the active child for this composite node.\n this.selectedChild = lottoDraw.draw() || undefined;\n }\n\n // If something went wrong and we don't have an active child then we should throw an error.\n if (!this.selectedChild) {\n throw new Error(\"failed to update lotto node as it has no active child\");\n }\n\n // If the selected child has never been updated or is running then we will need to update it now.\n if (this.selectedChild.getState() === State.READY || this.selectedChild.getState() === State.RUNNING) {\n this.selectedChild.update(agent, options);\n }\n\n // The state of the lotto node is the state of its selected child.\n this.setState(this.selectedChild.getState());\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => (this.weights ? `LOTTO [${this.weights.join(\",\")}]` : \"LOTTO\");\n}\n", "import Node from \"../Node\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\n\n/**\n * A decorator node that wraps a single child node.\n */\nexport default abstract class Decorator extends Node {\n /**\n * @param type The node type.\n * @param attributes The node attributes.\n * @param child The child node.\n */\n constructor(type: string, attributes: Attribute[], protected child: Node) {\n super(type, attributes, []);\n }\n\n /**\n * Gets whether this node is a leaf node.\n */\n isLeafNode = () => false;\n\n /**\n * Gets the children of this node.\n */\n getChildren = () => [this.child];\n\n /**\n * Reset the state of the node.\n */\n reset = () => {\n // Reset the state of this node.\n this.setState(State.READY);\n\n // Reset the state of the child node.\n this.child.reset();\n };\n\n /**\n * Abort the running of this node.\n * @param agent The agent.\n */\n abort = (agent: Agent) => {\n // There is nothing to do if this node is not in the running state.\n if (!this.is(State.RUNNING)) {\n return;\n }\n\n // Abort the child node.\n this.child.abort(agent);\n\n // Reset the state of this node.\n this.reset();\n\n this.getAttribute(\"exit\")?.callAgentFunction(agent, false, true);\n };\n}\n", "import Node from \"../Node\";\nimport Decorator from \"./Decorator\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A Fail node.\n * This node wraps a single child and will always move to the 'FAILED' state when the child moves to a 'SUCCEEDED' or 'FAILED' state.\n */\nexport default class Fail extends Decorator {\n /**\n * @param attributes The node attributes.\n * @param child The child node.\n */\n constructor(attributes: Attribute[], child: Node) {\n super(\"fail\", attributes, child);\n }\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // If the child has never been updated or is running then we will need to update it now.\n if (this.child.getState() === State.READY || this.child.getState() === State.RUNNING) {\n this.child.update(agent, options);\n }\n\n // The state of this node will depend in the state of its child.\n switch (this.child.getState()) {\n case State.RUNNING:\n this.setState(State.RUNNING);\n break;\n\n case State.SUCCEEDED:\n case State.FAILED:\n this.setState(State.FAILED);\n break;\n\n default:\n this.setState(State.READY);\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => \"FAIL\";\n}\n", "import Decorator from \"./Decorator\";\nimport State from \"../../State\";\nimport Node from \"../Node\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A Flip node.\n * This node wraps a single child and will flip the state of the child state.\n */\nexport default class Flip extends Decorator {\n /**\n * @param attributes The node attributes.\n * @param child The child node.\n */\n constructor(attributes: Attribute[], child: Node) {\n super(\"flip\", attributes, child);\n }\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // If the child has never been updated or is running then we will need to update it now.\n if (this.child.getState() === State.READY || this.child.getState() === State.RUNNING) {\n this.child.update(agent, options);\n }\n\n // The state of this node will depend in the state of its child.\n switch (this.child.getState()) {\n case State.RUNNING:\n this.setState(State.RUNNING);\n break;\n\n case State.SUCCEEDED:\n this.setState(State.FAILED);\n break;\n\n case State.FAILED:\n this.setState(State.SUCCEEDED);\n break;\n\n default:\n this.setState(State.READY);\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => \"FLIP\";\n}\n", "import Node from \"../Node\";\nimport Decorator from \"./Decorator\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A REPEAT node.\n * The node has a single child which can have:\n * -- A number of iterations for which to repeat the child node.\n * -- An infinite repeat loop if neither an iteration count or a condition function is defined.\n * The REPEAT node will stop and have a 'FAILED' state if its child is ever in a 'FAILED' state after an update.\n * The REPEAT node will attempt to move on to the next iteration if its child is ever in a 'SUCCEEDED' state.\n */\nexport default class Repeat extends Decorator {\n /**\n * @param attributes The node attributes.\n * @param iterations The number of iterations to repeat the child node.\n * @param iterationsMin The minimum possible number of iterations to repeat the child node.\n * @param iterationsMax The maximum possible number of iterations to repeat the child node.\n * @param child The child node.\n */\n constructor(\n attributes: Attribute[],\n private iterations: number | null,\n private iterationsMin: number | null,\n private iterationsMax: number | null,\n child: Node\n ) {\n super(\"repeat\", attributes, child);\n }\n\n /**\n * The number of target iterations to make.\n */\n private targetIterationCount: number | null = null;\n\n /**\n * The current iteration count.\n */\n private currentIterationCount: number = 0;\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // If this node is in the READY state then we need to reset the child and the target iteration count.\n if (this.is(State.READY)) {\n // Reset the child node.\n this.child.reset();\n\n // Reset the current iteration count.\n this.currentIterationCount = 0;\n\n // Set the target iteration count.\n this.setTargetIterationCount(options);\n }\n\n // Do a check to see if we can iterate. If we can then this node will move into the 'RUNNING' state.\n // If we cannot iterate then we have hit our target iteration count, which means that the node has succeeded.\n if (this.canIterate()) {\n // This node is in the running state and can do its initial iteration.\n this.setState(State.RUNNING);\n\n // We may have already completed an iteration, meaning that the child node will be in the SUCCEEDED state.\n // If this is the case then we will have to reset the child node now.\n if (this.child.getState() === State.SUCCEEDED) {\n this.child.reset();\n }\n\n // Update the child of this node.\n this.child.update(agent, options);\n\n // If the child moved into the FAILED state when we updated it then there is nothing left to do and this node has also failed.\n // If it has moved into the SUCCEEDED state then we have completed the current iteration.\n if (this.child.getState() === State.FAILED) {\n // The child has failed, meaning that this node has failed.\n this.setState(State.FAILED);\n\n return;\n } else if (this.child.getState() === State.SUCCEEDED) {\n // We have completed an iteration.\n this.currentIterationCount += 1;\n }\n } else {\n // This node is in the 'SUCCEEDED' state as we cannot iterate any more.\n this.setState(State.SUCCEEDED);\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => {\n if (this.iterations !== null) {\n return `REPEAT ${this.iterations}x`;\n } else if (this.iterationsMin !== null && this.iterationsMax !== null) {\n return `REPEAT ${this.iterationsMin}x-${this.iterationsMax}x`;\n } else {\n return \"REPEAT\";\n }\n };\n\n /**\n * Reset the state of the node.\n */\n reset = () => {\n // Reset the state of this node.\n this.setState(State.READY);\n\n // Reset the current iteration count.\n this.currentIterationCount = 0;\n\n // Reset the child node.\n this.child.reset();\n };\n\n /**\n * Gets whether an iteration can be made.\n * @returns Whether an iteration can be made.\n */\n private canIterate = () => {\n if (this.targetIterationCount !== null) {\n // We can iterate as long as we have not reached our target iteration count.\n return this.currentIterationCount < this.targetIterationCount;\n }\n\n // If neither an iteration count or a condition function were defined then we can iterate indefinitely.\n return true;\n };\n\n /**\n * Sets the target iteration count.\n * @param options The behaviour tree options object.\n */\n private setTargetIterationCount = (options: BehaviourTreeOptions) => {\n // Are we dealing with an explicit iteration count or will we be randomly picking a iteration count between the min and max iteration count.\n if (this.iterations !== null) {\n this.targetIterationCount = this.iterations;\n } else if (this.iterationsMin !== null && this.iterationsMax !== null) {\n // We will be picking a random iteration count between a min and max iteration count, if the optional 'random'\n // behaviour tree function option is defined then we will be using that, otherwise we will fall back to using Math.random.\n const random = typeof options.random === \"function\" ? options.random : Math.random;\n\n // Pick a random iteration count between a min and max iteration count.\n this.targetIterationCount = Math.floor(\n random() * (this.iterationsMax - this.iterationsMin + 1) + this.iterationsMin\n );\n } else {\n this.targetIterationCount = null;\n }\n };\n}\n", "import Node from \"../Node\";\nimport Decorator from \"./Decorator\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A RETRY node.\n * The node has a single child which can have:\n * -- A number of iterations for which to repeat the child node.\n * -- An infinite repeat loop if neither an iteration count or a condition function is defined.\n * The RETRY node will stop and have a 'SUCCEEDED' state if its child is ever in a 'SUCCEEDED' state after an update.\n * The RETRY node will attempt to move on to the next iteration if its child is ever in a 'FAILED' state.\n */\nexport default class Retry extends Decorator {\n /**\n * @param attributes The node attributes.\n * @param attempts The number of attempts to retry the child node.\n * @param attemptsMin The minimum possible number of attempts to retry the child node.\n * @param attemptsMax The maximum possible number of attempts to retry the child node.\n * @param child The child node.\n */\n constructor(\n attributes: Attribute[],\n private attempts: number | null,\n private attemptsMin: number | null,\n private attemptsMax: number | null,\n child: Node\n ) {\n super(\"retry\", attributes, child);\n }\n\n /**\n * The number of target attempts to make.\n */\n private targetAttemptCount: number | null = null;\n\n /**\n * The current attempt count.\n */\n private currentAttemptCount: number = 0;\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // If this node is in the READY state then we need to reset the child and the target attempt count.\n if (this.is(State.READY)) {\n // Reset the child node.\n this.child.reset();\n\n // Reset the current attempt count.\n this.currentAttemptCount = 0;\n\n // Set the target attempt count.\n this.setTargetAttemptCount(options);\n }\n\n // Do a check to see if we can attempt. If we can then this node will move into the 'RUNNING' state.\n // If we cannot attempt then we have hit our target attempt count, which means that the node has succeeded.\n if (this.canAttempt()) {\n // This node is in the running state and can do its initial attempt.\n this.setState(State.RUNNING);\n\n // We may have already completed an attempt, meaning that the child node will be in the FAILED state.\n // If this is the case then we will have to reset the child node now.\n if (this.child.getState() === State.FAILED) {\n this.child.reset();\n }\n\n // Update the child of this node.\n this.child.update(agent, options);\n\n // If the child moved into the SUCCEEDED state when we updated it then there is nothing left to do and this node has also succeeded.\n // If it has moved into the FAILED state then we have completed the current attempt.\n if (this.child.getState() === State.SUCCEEDED) {\n // The child has succeeded, meaning that this node has succeeded.\n this.setState(State.SUCCEEDED);\n\n return;\n } else if (this.child.getState() === State.FAILED) {\n // We have completed an attempt.\n this.currentAttemptCount += 1;\n }\n } else {\n // This node is in the 'FAILED' state as we cannot iterate any more.\n this.setState(State.FAILED);\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => {\n if (this.attempts !== null) {\n return `RETRY ${this.attempts}x`;\n } else if (this.attemptsMin !== null && this.attemptsMax !== null) {\n return `RETRY ${this.attemptsMin}x-${this.attemptsMax}x`;\n } else {\n return \"RETRY\";\n }\n };\n\n /**\n * Reset the state of the node.\n */\n reset = () => {\n // Reset the state of this node.\n this.setState(State.READY);\n\n // Reset the current attempt count.\n this.currentAttemptCount = 0;\n\n // Reset the child node.\n this.child.reset();\n };\n\n /**\n * Gets whether an attempt can be made.\n * @returns Whether an attempt can be made.\n */\n canAttempt = () => {\n if (this.targetAttemptCount !== null) {\n // We can attempt as long as we have not reached our target attempt count.\n return this.currentAttemptCount < this.targetAttemptCount;\n }\n\n // If neither an attempt count or a condition function were defined then we can attempt indefinitely.\n return true;\n };\n\n /**\n * Sets the target attempt count.\n * @param options The behaviour tree options object.\n */\n setTargetAttemptCount = (options: BehaviourTreeOptions) => {\n // Are we dealing with an explicit attempt count or will we be randomly picking an attempt count between the min and max attempt count.\n if (this.attempts !== null) {\n this.targetAttemptCount = this.attempts;\n } else if (this.attemptsMin !== null && this.attemptsMax !== null) {\n // We will be picking a random attempt count between a min and max attempt count, if the optional 'random'\n // behaviour tree function option is defined then we will be using that, otherwise we will fall back to using Math.random.\n const random = typeof options.random === \"function\" ? options.random : Math.random;\n\n // Pick a random attempt count between a min and max attempt count.\n this.targetAttemptCount = Math.floor(\n random() * (this.attemptsMax - this.attemptsMin + 1) + this.attemptsMin\n );\n } else {\n this.targetAttemptCount = null;\n }\n };\n}\n", "import Node from \"../Node\";\nimport Decorator from \"./Decorator\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A Root node.\n * The root node will have a single child.\n */\nexport default class Root extends Decorator {\n /**\n * @param attributes The node attributes.\n * @param child The child node.\n */\n constructor(attributes: Attribute[], child: Node) {\n super(\"root\", attributes, child);\n }\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // If the child has never been updated or is running then we will need to update it now.\n if (this.child.getState() === State.READY || this.child.getState() === State.RUNNING) {\n // Update the child of this node.\n this.child.update(agent, options);\n }\n\n // The state of the root node is the state of its child.\n this.setState(this.child.getState());\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => \"ROOT\";\n}\n", "import Node from \"../Node\";\nimport Decorator from \"./Decorator\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A Succeed node.\n * This node wraps a single child and will always move to the 'SUCCEEDED' state when the child moves to a 'SUCCEEDED' or 'FAILED' state.\n */\nexport default class Succeed extends Decorator {\n /**\n * @param attributes The node attributes.\n * @param child The child node.\n */\n constructor(attributes: Attribute[], child: Node) {\n super(\"succeed\", attributes, child);\n }\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // If the child has never been updated or is running then we will need to update it now.\n if (this.child.getState() === State.READY || this.child.getState() === State.RUNNING) {\n this.child.update(agent, options);\n }\n\n // The state of this node will depend in the state of its child.\n switch (this.child.getState()) {\n case State.RUNNING:\n this.setState(State.RUNNING);\n break;\n\n case State.SUCCEEDED:\n case State.FAILED:\n this.setState(State.SUCCEEDED);\n break;\n\n default:\n this.setState(State.READY);\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => \"SUCCEED\";\n}\n", "import Node from \"../Node\";\n\n/**\n * A leaf node.\n */\nexport default abstract class Leaf extends Node {\n /**\n * Gets whether this node is a leaf node.\n */\n isLeafNode = () => true;\n}\n", "import { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\nimport State, { CompleteState } from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Leaf from \"./Leaf\";\nimport Lookup from \"../../Lookup\";\nimport Attribute from \"../../attributes/Attribute\";\n\n/**\n * An Action leaf node.\n * This represents an immediate or ongoing state of behaviour.\n */\nexport default class Action extends Leaf {\n /**\n * @param attributes The node attributes.\n * @param actionName The action name.\n * @param actionArguments The array of action argument definitions.\n */\n constructor(attributes: Attribute[], private actionName: string, private actionArguments: any[]) {\n super(\"action\", attributes, actionArguments);\n }\n\n /**\n * Whether there is a pending update promise.\n */\n private isUsingUpdatePromise = false;\n\n /**\n * The finished state result of an update promise.\n */\n private updatePromiseStateResult: CompleteState | null = null;\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // If the result of this action depends on an update promise then there is nothing to do until\n // it resolves, unless there has been a value set as a result of the update promise resolving.\n if (this.isUsingUpdatePromise) {\n // Check whether the update promise has resolved with a state value.\n if (this.updatePromiseStateResult) {\n // Set the state of this node to match the state returned by the promise.\n this.setState(this.updatePromiseStateResult);\n }\n\n return;\n }\n\n // Attempt to get the invoker for the action function.\n const actionFuncInvoker = Lookup.getFuncInvoker(agent, this.actionName);\n\n // The action function should be defined.\n if (actionFuncInvoker === null) {\n throw new Error(\n `cannot update action node as the action '${this.actionName}' function is not defined on the agent and has not been registered`\n );\n }\n\n // Call the action function, the result of which may be:\n // - The finished state of this action node.\n // - A promise to return a finished node state.\n // - Undefined if the node should remain in the running state.\n const updateResult = actionFuncInvoker(this.actionArguments) as CompleteState | Promise;\n\n if (updateResult instanceof Promise) {\n updateResult.then(\n (result) => {\n // If 'isUpdatePromisePending' is null then the promise was cleared as it was resolving, probably via an abort of reset.\n if (!this.isUsingUpdatePromise) {\n return;\n }\n\n // Check to make sure the result is a valid finished state.\n if (result !== State.SUCCEEDED && result !== State.FAILED) {\n throw new Error(\n \"action node promise resolved with an invalid value, expected a State.SUCCEEDED or State.FAILED value to be returned\"\n );\n }\n\n // Set pending update promise state result to be processed on next update.\n this.updatePromiseStateResult = result;\n },\n (reason) => {\n // If 'isUpdatePromisePending' is null then the promise was cleared as it was resolving, probably via an abort of reset.\n if (!this.isUsingUpdatePromise) {\n return;\n }\n\n // Just throw whatever was returned as the rejection argument.\n throw new Error(reason);\n }\n );\n\n // This node will be in the 'RUNNING' state until the update promise resolves.\n this.setState(State.RUNNING);\n\n // We are now waiting for the promise returned by the use to resolve before we know what state this node is in.\n this.isUsingUpdatePromise = true;\n } else {\n // Validate the returned value.\n this.validateUpdateResult(updateResult);\n\n // Set the state of this node, this may be undefined, which just means that the node is still in the 'RUNNING' state.\n this.setState(updateResult || State.RUNNING);\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => this.actionName;\n\n /**\n * Reset the state of the node.\n */\n reset = () => {\n // Reset the state of this node.\n this.setState(State.READY);\n\n // There is no longer an update promise that we care about.\n this.isUsingUpdatePromise = false;\n this.updatePromiseStateResult = null;\n };\n\n /**\n * Validate the result of an update function call.\n * @param result The result of an update function call.\n */\n private validateUpdateResult = (result: CompleteState | boolean) => {\n switch (result) {\n case State.SUCCEEDED:\n case State.FAILED:\n case undefined:\n return;\n default:\n throw new Error(\n `action '${this.actionName}' 'onUpdate' returned an invalid response, expected an optional State.SUCCEEDED or State.FAILED value to be returned`\n );\n }\n };\n}\n", "import { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Leaf from \"./Leaf\";\nimport Lookup from \"../../Lookup\";\nimport Attribute from \"../../attributes/Attribute\";\n\n/**\n * A Condition leaf node.\n * This will succeed or fail immediately based on an agent predicate, without moving to the 'RUNNING' state.\n */\nexport default class Condition extends Leaf {\n /**\n * @param attributes The node attributes.\n * @param conditionName The name of the condition function.\n * @param conditionArguments The array of condition argument definitions.\n */\n constructor(attributes: Attribute[], private conditionName: string, private conditionArguments: any[]) {\n super(\"condition\", attributes, conditionArguments);\n }\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // Attempt to get the invoker for the condition function.\n const conditionFuncInvoker = Lookup.getFuncInvoker(agent, this.conditionName);\n\n // The condition function should be defined.\n if (conditionFuncInvoker === null) {\n throw new Error(\n `cannot update condition node as the condition '${this.conditionName}' function is not defined on the agent and has not been registered`\n );\n }\n\n // Call the condition function to determine the state of this node.\n this.setState(!!conditionFuncInvoker(this.conditionArguments) ? State.SUCCEEDED : State.FAILED);\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => this.conditionName;\n}\n", "import Leaf from \"./Leaf\";\nimport State from \"../../State\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { Agent } from \"../../Agent\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A WAIT node.\n * The state of this node will change to SUCCEEDED after a duration of time\n */\nexport default class Wait extends Leaf {\n /**\n * @param attributes The node attributes.\n * @param duration The duration that this node will wait to succeed in milliseconds.\n * @param durationMin The minimum possible duration in milliseconds that this node will wait to succeed.\n * @param durationMax The maximum possible duration in milliseconds that this node will wait to succeed.\n */\n constructor(\n attributes: Attribute[],\n private duration: number | null,\n private durationMin: number | null,\n private durationMax: number | null\n ) {\n super(\"wait\", attributes, []);\n }\n\n /**\n * The time in milliseconds at which this node was first updated.\n */\n private initialUpdateTime: number = 0;\n\n /**\n * The total duration in milliseconds that this node will be waiting for.\n */\n private totalDuration: number | null = null;\n\n /**\n * The duration in milliseconds that this node has been waiting for.\n */\n private waitedDuration: number = 0;\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // If this node is in the READY state then we need to set the initial update time.\n if (this.is(State.READY)) {\n // Set the initial update time.\n this.initialUpdateTime = new Date().getTime();\n\n // Set the initial waited duration.\n this.waitedDuration = 0;\n\n // Are we dealing with an explicit duration or will we be randomly picking a duration between the min and max duration.\n if (this.duration !== null) {\n this.totalDuration = this.duration;\n } else if (this.durationMin !== null && this.durationMax !== null) {\n // We will be picking a random duration between a min and max duration, if the optional 'random' behaviour tree\n // function option is defined then we will be using that, otherwise we will fall back to using Math.random.\n const random = typeof options.random === \"function\" ? options.random : Math.random;\n\n // Pick a random duration between a min and max duration.\n this.totalDuration = Math.floor(\n random() * (this.durationMax - this.durationMin + 1) + this.durationMin\n );\n } else {\n this.totalDuration = null;\n }\n\n // The node is now running until we finish waiting.\n this.setState(State.RUNNING);\n }\n\n // If we have no total duration then this wait node will wait indefinitely until it is aborted.\n if (this.totalDuration === null) {\n return;\n }\n\n // If we have a 'getDeltaTime' function defined as part of our options then we will use it to figure out how long we have waited for.\n if (typeof options.getDeltaTime === \"function\") {\n // Get the delta time.\n const deltaTime = options.getDeltaTime();\n\n // Our delta time must be a valid number and cannot be NaN.\n if (typeof deltaTime !== \"number\" || isNaN(deltaTime)) {\n throw new Error(\"The delta time must be a valid number and not NaN.\");\n }\n\n // Update the amount of time that this node has been waiting for based on the delta time.\n this.waitedDuration += deltaTime * 1000;\n } else {\n // We are not using a delta time, so we will just work out hom much time has passed since the first update.\n this.waitedDuration = new Date().getTime() - this.initialUpdateTime;\n }\n\n // Have we waited long enough?\n if (this.waitedDuration >= this.totalDuration) {\n // We have finished waiting!\n this.setState(State.SUCCEEDED);\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => {\n if (this.duration !== null) {\n return `WAIT ${this.duration}ms`;\n } else if (this.durationMin !== null && this.durationMax !== null) {\n return `WAIT ${this.durationMin}ms-${this.durationMax}ms`;\n } else {\n return \"WAIT\";\n }\n };\n}\n", "import Guard from \"./guards/Guard\";\n\nexport type AttributeDetails = {\n /** The attribute type. */\n type: string;\n\n /** The attribute arguments. */\n args: any[];\n};\n\n/**\n * A base node attribute.\n */\nexport default abstract class Attribute {\n /**\n * @param type The node attribute type.\n * @param args The array of attribute arguments.\n */\n constructor(public type: string, public args: any[]) {}\n\n /**\n * Gets the attribute details.\n */\n abstract getDetails(): TAttributeDetails;\n\n /**\n * Gets whether this attribute is a guard.\n */\n abstract isGuard: () => this is Guard;\n}\n", "import { Agent } from \"../../Agent\";\nimport Attribute, { AttributeDetails } from \"../Attribute\";\n\nexport type GuardAttributeDetails = {\n /** The name of the condition function that determines whether the guard is satisfied. */\n condition: string;\n} & AttributeDetails;\n\n/**\n * A base node guard attribute.\n */\nexport default abstract class Guard extends Attribute {\n /**\n * @param type The node attribute type.\n * @param args The array of decorator argument definitions.\n * @param condition The name of the condition function that determines whether the guard is satisfied.\n */\n constructor(type: string, args: any[], private condition: string) {\n super(type, args);\n }\n\n /**\n * Gets the name of the condition function that determines whether the guard is satisfied.\n */\n getCondition = () => this.condition;\n\n /**\n * Gets whether this attribute is a guard.\n */\n isGuard = () => true;\n\n /**\n * Gets the attribute details.\n */\n getDetails(): GuardAttributeDetails {\n return {\n type: this.type,\n args: this.args,\n condition: this.getCondition()\n };\n }\n\n /**\n * Gets whether the guard is satisfied.\n * @param agent The agent.\n * @returns Whether the guard is satisfied.\n */\n abstract isSatisfied(agent: Agent): boolean;\n}\n", "import Guard from \"./Guard\";\nimport Lookup from \"../../Lookup\";\nimport { Agent } from \"../../Agent\";\n\n/**\n * A WHILE guard which is satisfied as long as the given condition remains true.\n */\nexport default class While extends Guard {\n /**\n * @param condition The name of the condition function that determines whether the guard is satisfied.\n * @param args The array of decorator argument definitions.\n */\n constructor(condition: string, args: any[]) {\n super(\"while\", args, condition);\n }\n\n /**\n * Gets whether the guard is satisfied.\n * @param agent The agent.\n * @returns Whether the guard is satisfied.\n */\n isSatisfied = (agent: Agent) => {\n // Attempt to get the invoker for the condition function.\n const conditionFuncInvoker = Lookup.getFuncInvoker(agent, this.getCondition());\n\n // The condition function should be defined.\n if (conditionFuncInvoker === null) {\n throw new Error(\n `cannot evaluate node guard as the condition '${this.getCondition()}' function is not defined on the agent and has not been registered`\n );\n }\n\n // Call the condition function to determine whether this guard is satisfied.\n return !!conditionFuncInvoker(this.args);\n };\n}\n", "import Guard from \"./Guard\";\nimport Lookup from \"../../Lookup\";\nimport { Agent } from \"../../Agent\";\n\n/**\n * An UNTIL guard which is satisfied as long as the given condition remains false.\n */\nexport default class Until extends Guard {\n /**\n * @param condition The name of the condition function that determines whether the guard is satisfied.\n * @param args The array of decorator argument definitions.\n */\n constructor(condition: string, args: any[]) {\n super(\"until\", args, condition);\n }\n\n /**\n * Gets whether the guard is satisfied.\n * @param agent The agent.\n * @returns Whether the guard is satisfied.\n */\n isSatisfied = (agent: Agent) => {\n // Attempt to get the invoker for the condition function.\n const conditionFuncInvoker = Lookup.getFuncInvoker(agent, this.getCondition());\n\n // The condition function should be defined.\n if (conditionFuncInvoker === null) {\n throw new Error(\n `cannot evaluate node guard as the condition '${this.getCondition()}' function is not defined on the agent and has not been registered`\n );\n }\n\n // Call the condition function to determine whether this guard is satisfied.\n return !!!conditionFuncInvoker(this.args);\n };\n}\n", "import { Agent } from \"../../Agent\";\nimport Attribute, { AttributeDetails } from \"../Attribute\";\n\nexport type CallbackAttributeDetails = {\n /** The name of the agent function that is called. */\n functionName: string;\n} & AttributeDetails;\n\n/**\n * A base node callback attribute.\n */\nexport default abstract class Callback extends Attribute {\n /**\n * @param type The node attribute type.\n * @param args The array of decorator argument definitions.\n * @param functionName The name of the agent function to call.\n */\n constructor(type: string, args: any[], private functionName: string) {\n super(type, args);\n }\n\n /**\n * Gets the name of the agent function to call.\n */\n getFunctionName = () => this.functionName;\n\n /**\n * Gets whether this attribute is a guard.\n */\n isGuard = () => false;\n\n /**\n * Gets the attribute details.\n */\n getDetails(): CallbackAttributeDetails {\n return {\n type: this.type,\n args: this.args,\n functionName: this.getFunctionName()\n };\n }\n\n /**\n * Attempt to call the agent function that this callback refers to.\n * @param agent The agent.\n */\n abstract callAgentFunction: (agent: Agent, isSuccess: boolean, isAborted: boolean) => void;\n}\n", "import Callback from \"./Callback\";\nimport Lookup from \"../../Lookup\";\nimport { Agent } from \"../../Agent\";\n\n/**\n * An ENTRY callback which defines an agent function to call when the associated node is updated and moves out of running state.\n */\nexport default class Entry extends Callback {\n /**\n * @param functionName The name of the agent function to call.\n * @param args The array of callback argument definitions.\n */\n constructor(functionName: string, args: any[]) {\n super(\"entry\", args, functionName);\n }\n\n /**\n * Attempt to call the agent function that this callback refers to.\n * @param agent The agent.\n */\n callAgentFunction = (agent: Agent) => {\n // Attempt to get the invoker for the callback function.\n const callbackFuncInvoker = Lookup.getFuncInvoker(agent, this.getFunctionName());\n\n // The callback function should be defined.\n if (callbackFuncInvoker === null) {\n throw new Error(\n `cannot call entry function '${this.getFunctionName()}' as is not defined on the agent and has not been registered`\n );\n }\n\n // Call the callback function.\n callbackFuncInvoker(this.args);\n };\n}\n", "import Callback from \"./Callback\";\nimport Lookup from \"../../Lookup\";\nimport { Agent } from \"../../Agent\";\n\n/**\n * A STEP callback which defines an agent function to call when the associated node is updated.\n */\nexport default class Step extends Callback {\n /**\n * @param functionName The name of the agent function to call.\n * @param args The array of callback argument definitions.\n */\n constructor(functionName: string, args: any[]) {\n super(\"step\", args, functionName);\n }\n\n /**\n * Attempt to call the agent function that this callback refers to.\n * @param agent The agent.\n */\n callAgentFunction = (agent: Agent) => {\n // Attempt to get the invoker for the callback function.\n const callbackFuncInvoker = Lookup.getFuncInvoker(agent, this.getFunctionName());\n\n // The callback function should be defined.\n if (callbackFuncInvoker === null) {\n throw new Error(\n `cannot call step function '${this.getFunctionName()}' as is not defined on the agent and has not been registered`\n );\n }\n\n // Call the callback function.\n callbackFuncInvoker(this.args);\n };\n}\n", "import Callback from \"./Callback\";\nimport Lookup from \"../../Lookup\";\nimport { Agent } from \"../../Agent\";\n\n/**\n * An EXIT callback which defines an agent function to call when the associated node is updated and moves to a finished state or is aborted.\n */\nexport default class Exit extends Callback {\n /**\n * @param functionName The name of the agent function to call.\n * @param args The array of callback argument definitions.\n */\n constructor(functionName: string, args: any[]) {\n super(\"exit\", args, functionName);\n }\n\n /**\n * Attempt to call the agent function that this callback refers to.\n * @param agent The agent.\n * @param isSuccess Whether the decorated node was left with a success state.\n * @param isAborted Whether the decorated node was aborted.\n */\n callAgentFunction = (agent: Agent, isSuccess: boolean, isAborted: boolean) => {\n // Attempt to get the invoker for the callback function.\n const callbackFuncInvoker = Lookup.getFuncInvoker(agent, this.getFunctionName());\n\n // The callback function should be defined.\n if (callbackFuncInvoker === null) {\n throw new Error(\n `cannot call exit function '${this.getFunctionName()}' as is not defined on the agent and has not been registered`\n );\n }\n\n // Call the callback function\n callbackFuncInvoker([{ value: { succeeded: isSuccess, aborted: isAborted } }, ...this.args]);\n };\n}\n", "import { AnyNodeDefinition, RootNodeDefinition } from \"./BehaviourTreeDefinition\";\nimport GuardPath, { GuardPathPart } from \"./attributes/guards/GuardPath\";\nimport { validateBranchSubtreeLinks } from \"./BehaviourTreeDefinitionValidator\";\nimport { isInteger } from \"./BehaviourTreeDefinitionUtilities\";\nimport Node from \"./nodes/Node\";\nimport Composite from \"./nodes/composite/Composite\";\nimport Decorator from \"./nodes/decorator/Decorator\";\nimport Parallel from \"./nodes/composite/Parallel\";\nimport Selector from \"./nodes/composite/Selector\";\nimport Sequence from \"./nodes/composite/Sequence\";\nimport Lotto from \"./nodes/composite/Lotto\";\nimport Fail from \"./nodes/decorator/Fail\";\nimport Flip from \"./nodes/decorator/Flip\";\nimport Repeat from \"./nodes/decorator/Repeat\";\nimport Retry from \"./nodes/decorator/Retry\";\nimport Root from \"./nodes/decorator/Root\";\nimport Succeed from \"./nodes/decorator/Succeed\";\nimport Action from \"./nodes/leaf/Action\";\nimport Condition from \"./nodes/leaf/Condition\";\nimport Wait from \"./nodes/leaf/Wait\";\nimport Lookup from \"./Lookup\";\nimport Attribute from \"./attributes/Attribute\";\nimport While from \"./attributes/guards/While\";\nimport Until from \"./attributes/guards/Until\";\nimport Entry from \"./attributes/callbacks/Entry\";\nimport Step from \"./attributes/callbacks/Step\";\nimport Exit from \"./attributes/callbacks/Exit\";\n\n/**\n * A type representing any node instance in a behaviour tree.\n */\ntype AnyNode =\n | Root\n | Action\n | Condition\n | Wait\n | Sequence\n | Selector\n | Lotto\n | Parallel\n | Repeat\n | Retry\n | Flip\n | Succeed\n | Fail;\n\n/**\n * A type defining a mapping of root node identifiers to root node definitions.\n */\ntype RootNodeDefinitionMap = { [key: string | symbol]: RootNodeDefinition };\n\n/**\n * A symbol to use as the main root key in any root node mappings.\n */\nconst MAIN_ROOT_NODE_KEY = Symbol(\"__root__\");\n\n/**\n * Build and populate the root nodes based on the provided definition, assuming that the definition has been validated.\n * @param definition The root node definitions.\n * @returns The built and populated root node definitions.\n */\nexport default function buildRootNode(definition: RootNodeDefinition[]): Root {\n // Create a mapping of root node identifers to root node definitions, including globally registered subtree root node definitions.\n const rootNodeDefinitionMap = createRootNodeDefinitionMap(definition);\n\n // Now that we have all of our root node definitons (those part of the tree definition and those globally\n // registered) we should validate the definition. This will also double-check that we dont have any circular\n // dependencies in our branch -> subtree references and that we have no broken branch -> subtree links.\n validateBranchSubtreeLinks(definition, true);\n\n // Create our populated tree of node instances, starting with our main root node.\n const rootNode = nodeFactory(rootNodeDefinitionMap[MAIN_ROOT_NODE_KEY], rootNodeDefinitionMap) as Root;\n\n // Set a guard path on every leaf of the tree to evaluate as part of each update.\n applyLeafNodeGuardPaths(rootNode);\n\n // We only need to return the main root node.\n return rootNode;\n}\n\n/**\n * A factory function which creates a node instance based on the specified definition.\n * @param definition The node definition.\n * @param rootNodeDefinitionMap The mapping of root node identifers to root node definitions, including globally registered subtree root node definitions.\n * @returns A node instance based on the specified definition.\n */\nfunction nodeFactory(definition: AnyNodeDefinition, rootNodeDefinitionMap: RootNodeDefinitionMap): AnyNode {\n // Get the attributes for the node.\n const attributes = nodeAttributesFactory(definition);\n\n // Create the node instance based on the definition type.\n switch (definition.type) {\n case \"root\":\n return new Root(attributes, nodeFactory(definition.child, rootNodeDefinitionMap));\n\n case \"repeat\":\n let iterations: number | null = null;\n let iterationsMin: number | null = null;\n let iterationsMax: number | null = null;\n\n if (Array.isArray(definition.iterations)) {\n iterationsMin = definition.iterations[0];\n iterationsMax = definition.iterations[1];\n } else if (isInteger(definition.iterations)) {\n iterations = definition.iterations!;\n }\n\n return new Repeat(\n attributes,\n iterations,\n iterationsMin,\n iterationsMax,\n nodeFactory(definition.child, rootNodeDefinitionMap)\n );\n\n case \"retry\":\n let attempts: number | null = null;\n let attemptsMin: number | null = null;\n let attemptsMax: number | null = null;\n\n if (Array.isArray(definition.attempts)) {\n attemptsMin = definition.attempts[0];\n attemptsMax = definition.attempts[1];\n } else if (isInteger(definition.attempts)) {\n attempts = definition.attempts!;\n }\n\n return new Retry(\n attributes,\n attempts,\n attemptsMin,\n attemptsMax,\n nodeFactory(definition.child, rootNodeDefinitionMap)\n );\n\n case \"flip\":\n return new Flip(attributes, nodeFactory(definition.child, rootNodeDefinitionMap));\n\n case \"succeed\":\n return new Succeed(attributes, nodeFactory(definition.child, rootNodeDefinitionMap));\n\n case \"fail\":\n return new Fail(attributes, nodeFactory(definition.child, rootNodeDefinitionMap));\n\n case \"sequence\":\n return new Sequence(\n attributes,\n definition.children.map((child) => nodeFactory(child, rootNodeDefinitionMap))\n );\n\n case \"selector\":\n return new Selector(\n attributes,\n definition.children.map((child) => nodeFactory(child, rootNodeDefinitionMap))\n );\n\n case \"parallel\":\n return new Parallel(\n attributes,\n definition.children.map((child) => nodeFactory(child, rootNodeDefinitionMap))\n );\n\n case \"lotto\":\n return new Lotto(\n attributes,\n definition.weights,\n definition.children.map((child) => nodeFactory(child, rootNodeDefinitionMap))\n );\n\n case \"branch\":\n return nodeFactory(rootNodeDefinitionMap[definition.ref].child, rootNodeDefinitionMap);\n\n case \"action\":\n return new Action(attributes, definition.call, definition.args || []);\n\n case \"condition\":\n return new Condition(attributes, definition.call, definition.args || []);\n\n case \"wait\":\n let duration: number | null = null;\n let durationMin: number | null = null;\n let durationMax: number | null = null;\n\n if (Array.isArray(definition.duration)) {\n durationMin = definition.duration[0];\n durationMax = definition.duration[1];\n } else if (isInteger(definition.duration)) {\n duration = definition.duration!;\n }\n\n return new Wait(attributes, duration, durationMin, durationMax);\n }\n}\n\n/**\n * Creates an array of node attribute instances based on the specified node definition.\n * @param definition The node definition.\n * @returns An array of node attribute instances based on the specified node definition.\n */\nfunction nodeAttributesFactory(definition: AnyNodeDefinition): Attribute[] {\n const attributes: Attribute[] = [];\n\n if (definition.while) {\n attributes.push(new While(definition.while.call, definition.while.args ?? []));\n }\n\n if (definition.until) {\n attributes.push(new Until(definition.until.call, definition.until.args ?? []));\n }\n\n if (definition.entry) {\n attributes.push(new Entry(definition.entry.call, definition.entry.args ?? []));\n }\n\n if (definition.step) {\n attributes.push(new Step(definition.step.call, definition.step.args ?? []));\n }\n\n if (definition.exit) {\n attributes.push(new Exit(definition.exit.call, definition.exit.args ?? []));\n }\n\n return attributes;\n}\n\n/**\n * Creates a mapping of root node identifers to root node definitions, mixing in globally registered subtree root node definitions.\n * @param definition The root node definitions.\n * @returns A mapping of root node identifers to root node definitions, including globally registered subtree root node definitions.\n */\nfunction createRootNodeDefinitionMap(definition: RootNodeDefinition[]): RootNodeDefinitionMap {\n // Create a mapping of root node identifers to root node definitions.\n const rootNodeMap: RootNodeDefinitionMap = {};\n\n // Add in any registered subtree root node definitions.\n for (const [name, rootNodeDefinition] of Object.entries(Lookup.getSubtrees())) {\n // The name used when registering the subtree will be used as the root node identifier.\n rootNodeMap[name] = { ...rootNodeDefinition, id: name };\n }\n\n // Populate the map with the root node definitions that were included with the tree definition.\n // We do this after adding any registered subtrees as we want these to take presedence.\n for (const rootNodeDefinition of definition) {\n rootNodeMap[rootNodeDefinition.id ?? MAIN_ROOT_NODE_KEY] = rootNodeDefinition;\n }\n\n return rootNodeMap;\n}\n\n/**\n * Applies a guard path to every leaf of the tree to evaluate as part of each update.\n * @param root The main root tree node.\n */\nfunction applyLeafNodeGuardPaths(root: Root) {\n const nodePaths: Node[][] = [];\n\n const findLeafNodes = (path: Node[], node: Node) => {\n // Add the current node to the path.\n path = path.concat(node);\n\n // Check whether the current node is a leaf node.\n if (node.isLeafNode()) {\n nodePaths.push(path);\n } else {\n (node as Composite | Decorator).getChildren().forEach((child) => findLeafNodes(path, child));\n }\n };\n\n // Find all leaf node paths, starting from the root.\n findLeafNodes([], root);\n\n nodePaths.forEach((path) => {\n // Each node in the current path will have to be assigned a guard path, working from the root outwards.\n for (let depth = 0; depth < path.length; depth++) {\n // Get the node in the path at the current depth.\n const currentNode = path[depth];\n\n // The node may already have been assigned a guard path, if so just skip it.\n if (currentNode.hasGuardPath()) {\n continue;\n }\n\n // Create the guard path for the current node.\n const guardPath = new GuardPath(\n path\n .slice(0, depth + 1)\n .map((node) => ({ node, guards: node.getGuardAttributes() }))\n .filter((details) => details.guards.length > 0)\n );\n\n // Assign the guard path to the current node.\n currentNode.setGuardPath(guardPath);\n }\n });\n}\n", "import State, { AnyState } from \"./State\";\nimport Lookup from \"./Lookup\";\nimport Node from \"./nodes/Node\";\nimport Root from \"./nodes/decorator/Root\";\nimport Composite from \"./nodes/composite/Composite\";\nimport Decorator from \"./nodes/decorator/Decorator\";\nimport { Agent, GlobalFunction } from \"./Agent\";\nimport { CallbackAttributeDetails } from \"./attributes/callbacks/Callback\";\nimport { GuardAttributeDetails } from \"./attributes/guards/Guard\";\nimport { BehaviourTreeOptions } from \"./BehaviourTreeOptions\";\nimport { convertMDSLToJSON } from \"./mdsl/MDSLDefinitionParser\";\nimport { RootNodeDefinition } from \"./BehaviourTreeDefinition\";\nimport { validateJSONDefinition } from \"./BehaviourTreeDefinitionValidator\";\nimport buildRootNode from \"./BehaviourTreeBuilder\";\nimport { isNullOrUndefined } from \"./BehaviourTreeDefinitionUtilities\";\n\n// Purely for outside inspection of the tree.\nexport type FlattenedTreeNode = {\n id: string;\n type: string;\n caption: string;\n state: AnyState;\n guards: GuardAttributeDetails[];\n callbacks: CallbackAttributeDetails[];\n args: any[];\n parentId: string | null;\n};\n\n/**\n * A representation of a behaviour tree.\n */\nexport class BehaviourTree {\n /**\n * The main root tree node.\n */\n public readonly rootNode: Root;\n\n /**\n * Creates a new instance of the BehaviourTree class.\n * @param definition The behaviour tree definition.\n * @param agent The agent instance that this behaviour tree is modelling behaviour for.\n * @param options The behaviour tree options object.\n */\n constructor(\n definition: string | RootNodeDefinition | RootNodeDefinition[],\n private agent: Agent,\n private options: BehaviourTreeOptions = {}\n ) {\n // The tree definition must be defined.\n if (isNullOrUndefined(definition)) {\n throw new Error(\"tree definition not defined\");\n }\n\n // The agent must be defined and not null.\n if (typeof agent !== \"object\" || agent === null) {\n throw new Error(\"the agent must be an object and not null\");\n }\n\n try {\n // Parse the behaviour tree definition, create the populated tree of behaviour tree nodes, and get the root.\n this.rootNode = this._createRootNode(definition);\n } catch (exception) {\n // There was an issue in trying build and populate the behaviour tree.\n throw new Error(`error building tree: ${(exception as Error).message}`);\n }\n }\n\n /**\n * Gets whether the tree is in the RUNNING state.\n * @returns true if the tree is in the RUNNING state, otherwise false.\n */\n isRunning() {\n return this.rootNode.getState() === State.RUNNING;\n }\n\n /**\n * Gets the current tree state of SUCCEEDED, FAILED, READY or RUNNING.\n * @returns The current tree state.\n */\n getState() {\n return this.rootNode.getState();\n }\n\n /**\n * Step the tree.\n * 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.\n * 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\n * 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.\n *\n * 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.\n */\n step() {\n // If the root node has already been stepped to completion then we need to reset it.\n if (this.rootNode.getState() === State.SUCCEEDED || this.rootNode.getState() === State.FAILED) {\n this.rootNode.reset();\n }\n\n try {\n this.rootNode.update(this.agent, this.options);\n } catch (exception) {\n throw new Error(`error stepping tree: ${(exception as Error).message}`);\n }\n }\n\n /**\n * Resets the tree from the root node outwards to each nested node, giving each a state of READY.\n */\n reset() {\n this.rootNode.reset();\n }\n\n /**\n * Gets the flattened details of every node in the tree.\n * @returns The flattened details of every node in the tree.\n */\n getFlattenedNodeDetails(): FlattenedTreeNode[] {\n // Create an empty flattened array of tree nodes.\n const flattenedTreeNodes: FlattenedTreeNode[] = [];\n\n /**\n * Helper function to process a node instance and push details into the flattened tree nodes array.\n * @param node The current node.\n * @param parentUid The UID of the node parent, or null if the node is the main root node.\n */\n const processNode = (node: Node, parentUid: string | null) => {\n // Get the guard and callback attribute details for this node.\n const guards = node\n .getAttributes()\n .filter((attribute) => attribute.isGuard())\n .map((attribute) => attribute.getDetails()) as GuardAttributeDetails[];\n const callbacks = node\n .getAttributes()\n .filter((attribute) => !attribute.isGuard())\n .map((attribute) => attribute.getDetails()) as CallbackAttributeDetails[];\n\n // Push the current node into the flattened nodes array.\n flattenedTreeNodes.push({\n id: node.getUid(),\n type: node.getType(),\n caption: node.getName(),\n state: node.getState(),\n guards,\n callbacks,\n args: node.getArguments(),\n parentId: parentUid\n });\n\n // Process each of the nodes children if it is not a leaf node.\n if (!node.isLeafNode()) {\n (node as Composite | Decorator)\n .getChildren()\n .forEach((child) => processNode(child, (node as Composite | Decorator).getUid()));\n }\n };\n\n // Convert the nested node structure into a flattened array of node details.\n processNode(this.rootNode, null);\n\n return flattenedTreeNodes;\n }\n\n /**\n * Registers the action/condition/guard/callback function or subtree with the given name.\n * @param name The name of the function or subtree to register.\n * @param value The function or subtree definition to register.\n */\n static register(name: string, value: GlobalFunction | string | RootNodeDefinition) {\n // Are we going to register a action/condition/guard/callback function?\n if (typeof value === \"function\") {\n Lookup.setFunc(name, value);\n return;\n }\n\n // We are not registering an action/condition/guard/callback function, so we must be registering a subtree.\n if (typeof value === \"string\") {\n let rootNodeDefinitions: RootNodeDefinition[];\n\n // We will assume that any string passed in will be a mdsl definition.\n try {\n rootNodeDefinitions = convertMDSLToJSON(value);\n } catch (exception) {\n throw new Error(`error registering definition, invalid MDSL: ${(exception as Error).message}`);\n }\n\n // This function should only ever be called with a definition containing a single unnamed root node.\n if (rootNodeDefinitions.length != 1 || rootNodeDefinitions[0].id !== null) {\n throw new Error(\"error registering definition: expected a single unnamed root node\");\n }\n\n try {\n // We should validate the subtree as we don't want invalid subtrees available via the lookup.\n const { succeeded, errorMessage } = validateJSONDefinition(rootNodeDefinitions[0]);\n\n // Did our validation fail without error?\n if (!succeeded) {\n throw new Error(errorMessage);\n }\n } catch (exception) {\n throw new Error(`error registering definition: ${(exception as Error).message}`);\n }\n\n // Everything seems hunky-dory, register the subtree.\n Lookup.setSubtree(name, rootNodeDefinitions[0]);\n } else if (typeof value === \"object\" && !Array.isArray(value)) {\n // We will assume that any object passed in is a root node definition.\n\n try {\n // We should validate the subtree as we don't want invalid subtrees available via the lookup.\n const { succeeded, errorMessage } = validateJSONDefinition(value);\n\n // Did our validation fail without error?\n if (!succeeded) {\n throw new Error(errorMessage);\n }\n } catch (exception) {\n throw new Error(`error registering definition: ${(exception as Error).message}`);\n }\n\n // Everything seems hunky-dory, register the subtree.\n Lookup.setSubtree(name, value);\n } else {\n throw new Error(\"unexpected value, expected string mdsl definition, root node json definition or function\");\n }\n }\n\n /**\n * Unregisters the registered action/condition/guard/callback function or subtree with the given name.\n * @param name The name of the registered action/condition/guard/callback function or subtree to unregister.\n */\n static unregister(name: string): void {\n Lookup.remove(name);\n }\n\n /**\n * Unregister all registered action/condition/guard/callback functions and subtrees.\n */\n static unregisterAll(): void {\n Lookup.empty();\n }\n\n /**\n * Parses a behaviour tree definition and creates a tree of behaviour tree nodes populated at a root.\n * @param {string | RootNodeDefinition | RootNodeDefinition[]} definition The behaviour tree definition.\n * @returns The root behaviour tree node.\n */\n private _createRootNode(definition: string | RootNodeDefinition | RootNodeDefinition[]): Root {\n let resolvedDefinition: RootNodeDefinition | RootNodeDefinition[];\n\n // If the definition is a string then we will assume that it is an mdsl string which needs to be converted to a JSON definition.\n if (typeof definition === \"string\") {\n try {\n resolvedDefinition = convertMDSLToJSON(definition);\n } catch (exception) {\n throw new Error(`invalid mdsl definition: ${(exception as Error).message}`);\n }\n } else {\n // The definition is not a string, so we should assume that it is already a JSON definition.\n resolvedDefinition = definition;\n }\n\n // Build and populate the root node.\n return buildRootNode(Array.isArray(resolvedDefinition) ? resolvedDefinition : [resolvedDefinition]);\n }\n}\n"], + "mappings": "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", "names": ["Participant", "isNullOrUndefined", "Lotto", "createLotto", "State", "createLotto"] } diff --git a/src/BehaviourTree.ts b/src/BehaviourTree.ts index 608e974..022d216 100644 --- a/src/BehaviourTree.ts +++ b/src/BehaviourTree.ts @@ -12,6 +12,7 @@ import { convertMDSLToJSON } from "./mdsl/MDSLDefinitionParser"; import { RootNodeDefinition } from "./BehaviourTreeDefinition"; import { validateJSONDefinition } from "./BehaviourTreeDefinitionValidator"; import buildRootNode from "./BehaviourTreeBuilder"; +import { isNullOrUndefined } from "./BehaviourTreeDefinitionUtilities"; // Purely for outside inspection of the tree. export type FlattenedTreeNode = { @@ -46,13 +47,13 @@ export class BehaviourTree { private options: BehaviourTreeOptions = {} ) { // The tree definition must be defined. - if (!definition) { - throw new Error("the tree definition must be a string ro"); + if (isNullOrUndefined(definition)) { + throw new Error("tree definition not defined"); } // The agent must be defined and not null. if (typeof agent !== "object" || agent === null) { - throw new Error("the agent must be defined and not null"); + throw new Error("the agent must be an object and not null"); } try { diff --git a/src/index.ts b/src/index.ts index 82fc8ea..b47a3fa 100644 --- a/src/index.ts +++ b/src/index.ts @@ -2,6 +2,7 @@ import State from "./State"; import { validateDefinition } from "./BehaviourTreeDefinitionValidator"; import { convertMDSLToJSON } from "./mdsl/MDSLDefinitionParser"; import { BehaviourTree, FlattenedTreeNode } from "./BehaviourTree"; +import { BehaviourTreeOptions } from "./BehaviourTreeOptions"; export { BehaviourTree, State, convertMDSLToJSON, validateDefinition }; -export type { FlattenedTreeNode }; +export type { FlattenedTreeNode, BehaviourTreeOptions }; diff --git a/test/behaviourTree.test.js b/test/behaviourTree.test.js index cd35a6e..89c0f2c 100644 --- a/test/behaviourTree.test.js +++ b/test/behaviourTree.test.js @@ -9,37 +9,46 @@ const findNode = (tree, type, caption) => describe("A BehaviourTree instance", () => { describe("has initialisation logic that", () => { describe("should error when", () => { - it("the tree definition argument is not a string", () => { + it("the tree definition argument is not defined", () => { + assert.throws(() => new mistreevous.BehaviourTree(null, {}), Error, "tree definition not defined"); + assert.throws(() => new mistreevous.BehaviourTree(undefined, {}), Error, "tree definition not defined"); + }); + + it("the agent object is not defined", () => { assert.throws( - () => new mistreevous.BehaviourTree(null, {}), + () => new mistreevous.BehaviourTree("", undefined), Error, - "the tree definition must be a string" + "the agent must be an object and not null" ); - }); - - it("the tree definition argument is not a valid tree definition", () => { assert.throws( - () => new mistreevous.BehaviourTree("", {}), + () => new mistreevous.BehaviourTree("", null), Error, - "error parsing tree: invalid token count" + "the agent must be an object and not null" ); - }); - - it("the tree definition argument contains unexpected tokens", () => { assert.throws( - () => new mistreevous.BehaviourTree("invalid-token { }", {}), + () => new mistreevous.BehaviourTree("", 42), Error, - "error parsing tree: unexpected token 'invalid-token'" + "the agent must be an object and not null" ); }); + }); - it("the agent object is not defined", () => { - assert.throws(() => new mistreevous.BehaviourTree("", undefined), Error, "the agent must be defined"); + describe("should not error when the tree definition argument is a valid definition", () => { + it("(MDSL)", () => { + const definition = "root { action [test] }"; + assert.doesNotThrow(() => new mistreevous.BehaviourTree(definition, {}), Error); }); - }); - it("should not error when the tree definition argument is a valid definition", () => { - assert.doesNotThrow(() => new mistreevous.BehaviourTree("root { action [test] }", {}), Error); + it("(JSON)", () => { + const definition = { + type: "root", + child: { + type: "action", + call: "test" + } + }; + assert.doesNotThrow(() => new mistreevous.BehaviourTree(definition, {}), Error); + }); }); }); From 66d46724ef23b3936297943029a010c78f14519a Mon Sep 17 00:00:00 2001 From: Nikolas Howard Date: Thu, 8 Feb 2024 18:36:18 +0000 Subject: [PATCH 23/48] Fixed broken tests and added vs code mocha debugging --- .vscode/launch.json | 32 ++ dist/bundle.js | 21 +- dist/bundle.js.map | 4 +- dist/index.js | 21 +- dist/index.js.map | 4 +- package.json | 4 +- src/BehaviourTree.ts | 26 +- src/BehaviourTreeDefinitionValidator.ts | 4 +- src/mdsl/MDSLDefinitionParser.ts | 2 +- test/BehaviourTreeDefinitionValidator.test.js | 4 +- test/behaviourTree.test.js | 287 ++++++++++++++---- test/nodes/composite/Lotto.test.js | 2 +- test/nodes/decorator/fail.test.js | 2 +- test/nodes/decorator/flip.test.js | 2 +- test/nodes/decorator/repeat.test.js | 2 +- test/nodes/decorator/retry.test.js | 2 +- test/nodes/decorator/succeed.test.js | 2 +- test/nodes/leaf/action.test.js | 2 +- test/nodes/leaf/condition.test.js | 2 +- test/nodes/leaf/wait.test.js | 8 +- 20 files changed, 308 insertions(+), 125 deletions(-) create mode 100644 .vscode/launch.json diff --git a/.vscode/launch.json b/.vscode/launch.json new file mode 100644 index 0000000..220954a --- /dev/null +++ b/.vscode/launch.json @@ -0,0 +1,32 @@ +{ + // Use IntelliSense to learn about possible attributes. + // Hover to view descriptions of existing attributes. + // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 + "version": "0.2.0", + "configurations": [ + { + "type": "node", + "request": "launch", + "name": "Launch Program", + "skipFiles": [ + "/**" + ], + "program": "${workspaceFolder}\\dist\\index.js" + }, { + "args": [ + "--timeout", + "999999", + "--colors", + "${workspaceFolder}/test/**/*.js" + ], + "internalConsoleOptions": "openOnSessionStart", + "name": "Mocha Tests", + "program": "${workspaceFolder}/node_modules/mocha/bin/_mocha", + "request": "launch", + "skipFiles": [ + "/**" + ], + "type": "node" + } + ] +} \ No newline at end of file diff --git a/dist/bundle.js b/dist/bundle.js index 4604e83..7bb095a 100644 --- a/dist/bundle.js +++ b/dist/bundle.js @@ -733,7 +733,7 @@ var mistreevous = (() => { const nodeArguments = parseArgumentTokens(tokens, stringLiteralPlaceholders); if (nodeArguments.length) { nodeArguments.filter((arg) => arg.type !== "number" || !arg.isInteger).forEach(() => { - throw new Error(`wait node duration arguments must be integer values`); + throw new Error(`wait node durations must be integer values`); }); if (nodeArguments.length === 1) { node.duration = nodeArguments[0].value; @@ -787,8 +787,8 @@ var mistreevous = (() => { let rootNodeDefinitions; try { rootNodeDefinitions = convertMDSLToJSON(definition); - } catch (error) { - return createValidationFailureResult(`invalid MDSL: ${error}`); + } catch (exception) { + return createValidationFailureResult(exception.message); } const mainRootNodeDefinitions = rootNodeDefinitions.filter(({ id }) => typeof id === "undefined"); const subRootNodeDefinitions = rootNodeDefinitions.filter(({ id }) => typeof id === "string" && id.length > 0); @@ -2138,6 +2138,10 @@ var mistreevous = (() => { if (typeof agent !== "object" || agent === null) { throw new Error("the agent must be an object and not null"); } + const { succeeded, errorMessage } = validateDefinition(definition); + if (!succeeded) { + throw new Error(`invalid definition: ${errorMessage}`); + } try { this.rootNode = this._createRootNode(definition); } catch (exception) { @@ -2231,16 +2235,7 @@ var mistreevous = (() => { Lookup.empty(); } _createRootNode(definition) { - let resolvedDefinition; - if (typeof definition === "string") { - try { - resolvedDefinition = convertMDSLToJSON(definition); - } catch (exception) { - throw new Error(`invalid mdsl definition: ${exception.message}`); - } - } else { - resolvedDefinition = definition; - } + const resolvedDefinition = typeof definition === "string" ? convertMDSLToJSON(definition) : definition; return buildRootNode(Array.isArray(resolvedDefinition) ? resolvedDefinition : [resolvedDefinition]); } }; diff --git a/dist/bundle.js.map b/dist/bundle.js.map index 1418261..077677c 100644 --- a/dist/bundle.js.map +++ b/dist/bundle.js.map @@ -1,7 +1,7 @@ { "version": 3, "sources": ["../node_modules/lotto-draw/dist/Participant.js", "../node_modules/lotto-draw/dist/Utilities.js", "../node_modules/lotto-draw/dist/Lotto.js", "../node_modules/lotto-draw/dist/createLotto.js", "../node_modules/lotto-draw/dist/index.js", "../src/index.ts", "../src/State.ts", "../src/BehaviourTreeDefinitionUtilities.ts", "../src/mdsl/MDSLUtilities.ts", "../src/mdsl/MDSLNodeArgumentParser.ts", "../src/mdsl/MDSLNodeAttributeParser.ts", "../src/mdsl/MDSLDefinitionParser.ts", "../src/BehaviourTreeDefinitionValidator.ts", "../src/Lookup.ts", "../src/attributes/guards/GuardUnsatisifedException.ts", "../src/attributes/guards/GuardPath.ts", "../src/nodes/Node.ts", "../src/nodes/composite/Composite.ts", "../src/nodes/composite/Parallel.ts", "../src/nodes/composite/Selector.ts", "../src/nodes/composite/Sequence.ts", "../src/nodes/composite/Lotto.ts", "../src/nodes/decorator/Decorator.ts", "../src/nodes/decorator/Fail.ts", "../src/nodes/decorator/Flip.ts", "../src/nodes/decorator/Repeat.ts", "../src/nodes/decorator/Retry.ts", "../src/nodes/decorator/Root.ts", "../src/nodes/decorator/Succeed.ts", "../src/nodes/leaf/Leaf.ts", "../src/nodes/leaf/Action.ts", "../src/nodes/leaf/Condition.ts", "../src/nodes/leaf/Wait.ts", "../src/attributes/Attribute.ts", "../src/attributes/guards/Guard.ts", "../src/attributes/guards/While.ts", "../src/attributes/guards/Until.ts", "../src/attributes/callbacks/Callback.ts", "../src/attributes/callbacks/Entry.ts", "../src/attributes/callbacks/Step.ts", "../src/attributes/callbacks/Exit.ts", "../src/BehaviourTreeBuilder.ts", "../src/BehaviourTree.ts"], - "sourcesContent": ["\"use strict\";\r\nObject.defineProperty(exports, \"__esModule\", { value: true });\r\nexports.Participant = void 0;\r\n/**\r\n * A participant that holds a number of tickets.\r\n */\r\nvar Participant = /** @class */ (function () {\r\n /**\r\n * Creates an instance of the Participant class.\r\n * @param participant The actual participant.\r\n * @param tickets The number of tickets held by the participant.\r\n */\r\n function Participant(participant, tickets) {\r\n if (tickets === void 0) { tickets = 1; }\r\n this._participant = participant;\r\n this._tickets = tickets;\r\n }\r\n Object.defineProperty(Participant.prototype, \"participant\", {\r\n /** Gets the actual participant. */\r\n get: function () {\r\n return this._participant;\r\n },\r\n enumerable: false,\r\n configurable: true\r\n });\r\n Object.defineProperty(Participant.prototype, \"tickets\", {\r\n /** Gets or sets the number of tickets held by the participant. */\r\n get: function () {\r\n return this._tickets;\r\n },\r\n set: function (value) {\r\n this._tickets = value;\r\n },\r\n enumerable: false,\r\n configurable: true\r\n });\r\n return Participant;\r\n}());\r\nexports.Participant = Participant;\r\n", "\"use strict\";\r\nObject.defineProperty(exports, \"__esModule\", { value: true });\r\nexports.isNaturalNumber = exports.isNullOrUndefined = void 0;\r\n/**\r\n * Gets whether the value provided is null or undefined.\r\n * @param value The value to check.\r\n * @returns Whether the value provided is null or undefined.\r\n */\r\nfunction isNullOrUndefined(value) {\r\n return value === null || value === undefined;\r\n}\r\nexports.isNullOrUndefined = isNullOrUndefined;\r\n/**\r\n * Gets whether the value provided is a natural number.\r\n * @param value The value to check.\r\n * @returns Whether the value provided is a natural number.\r\n */\r\nfunction isNaturalNumber(value) {\r\n return typeof value === \"number\" && value >= 1 && Math.floor(value) === value;\r\n}\r\nexports.isNaturalNumber = isNaturalNumber;\r\n", "\"use strict\";\r\nObject.defineProperty(exports, \"__esModule\", { value: true });\r\nexports.Lotto = void 0;\r\nvar Participant_1 = require(\"./Participant\");\r\nvar Utilities_1 = require(\"./Utilities\");\r\n/**\r\n * Represents a lotto consisting of a number of pickable ticket-holding participants.\r\n */\r\nvar Lotto = /** @class */ (function () {\r\n /**\r\n * Creates a new instance of Lotto.\r\n * @param customRandom The custom RNG to use in place of Math.random().\r\n */\r\n function Lotto(customRandom) {\r\n /** The array of participants that are holding tickets in the lotto. */\r\n this._participants = [];\r\n this._customRandom = customRandom;\r\n }\r\n /**\r\n * Adds a participant with the specified number of tickets, or adds to the participant ticket count if the participant already holds tickets.\r\n * @param participant The participant to add or to increase the ticket count for if they already hold tickets.\r\n * @param tickets The number of tickets, defaults to 1.\r\n * @returns The Lotto instance.\r\n */\r\n Lotto.prototype.add = function (participant, tickets) {\r\n if (tickets === void 0) { tickets = 1; }\r\n // Check that we have a valid ticket count.\r\n if (!(0, Utilities_1.isNaturalNumber)(tickets)) {\r\n throw new Error(\"tickets value must be a natural number\");\r\n }\r\n // Check whether this participant has already been added.\r\n var existingParticipant = this._participants.find(function (part) { return part.participant === participant; });\r\n if (existingParticipant) {\r\n // The participant has already been added to the lotto so just add to their ticket count.\r\n existingParticipant.tickets += tickets;\r\n }\r\n else {\r\n // The participant is not part of the lotto so we should add them.\r\n this._participants.push(new Participant_1.Participant(participant, tickets));\r\n }\r\n return this;\r\n };\r\n /**\r\n * Removes the specified number of tickets for the given participant from the draw, or all tickets if a ticket number is not defined.\r\n * @param participant The participant to remove tickets for.\r\n * @param tickets The number of tickets to remove, or undefined if all tickets are to be removed.\r\n * @returns The Lotto instance.\r\n */\r\n Lotto.prototype.remove = function (participant, tickets) {\r\n // Attempt to get the existing participant.\r\n var existingParticipant = this._participants.find(function (part) { return part.participant === participant; });\r\n // There is nothing to do if the specified participant isn't even part of the lotto.\r\n if (!existingParticipant) {\r\n return this;\r\n }\r\n // Check whether a tickets value was given.\r\n if (tickets !== undefined) {\r\n // Check that we have a valid ticket count.\r\n if (!(0, Utilities_1.isNaturalNumber)(tickets)) {\r\n throw new Error(\"tickets value must be a natural number\");\r\n }\r\n existingParticipant.tickets -= tickets;\r\n // If the participant no longer holds any tickets then they should be removed.\r\n if (existingParticipant.tickets < 1) {\r\n this._participants = this._participants.filter(function (part) { return part !== existingParticipant; });\r\n }\r\n }\r\n else {\r\n // We are removing all tickets for the participant so just remove them from the lotto.\r\n this._participants = this._participants.filter(function (part) { return part !== existingParticipant; });\r\n }\r\n return this;\r\n };\r\n /**\r\n * Draw a winning ticket and return the participant that holds the ticket.\r\n * @param options The draw options.\r\n * @returns The participant that holds the winning ticket.\r\n */\r\n Lotto.prototype.draw = function (options) {\r\n if (options === void 0) { options = {}; }\r\n // If we have no participants then just return null.\r\n if (this._participants.length === 0) {\r\n return null;\r\n }\r\n var redrawable = (0, Utilities_1.isNullOrUndefined)(options.redrawable) ? true : options.redrawable;\r\n var pickable = [];\r\n this._participants.forEach(function (_a) {\r\n var participant = _a.participant, tickets = _a.tickets;\r\n for (var ticketCount = 0; ticketCount < tickets; ticketCount++) {\r\n pickable.push(participant);\r\n }\r\n });\r\n var random;\r\n // We need a random floating-point number between 0 (inclusive) and 1 to scale up to pick our winner.\r\n // If a custom random function exists then we should use that or fall back to Math.random().\r\n if (this._customRandom) {\r\n // Call our custom random function to get a random floating-point number.\r\n random = this._customRandom();\r\n // Verify that the result of calling our custom random function is a number between 0 (inclusive) and 1.\r\n if (typeof random !== \"number\" || random < 0 || random >= 1) {\r\n throw new Error(\"the 'random' function provided did not return a number between 0 (inclusive) and 1\");\r\n }\r\n }\r\n else {\r\n // No custom random function was defined so just use good ol' Math.random().\r\n random = Math.random();\r\n }\r\n // Pick a winning participant.\r\n var winner = pickable[Math.floor(random * pickable.length)];\r\n // If the ticket isn't redrawable then we should remove a ticket from the winning participants ticket count.\r\n if (!redrawable) {\r\n this.remove(winner, 1);\r\n }\r\n // Return the winning participant.\r\n return winner;\r\n };\r\n /**\r\n * Draws multiple winning tickets and return an array of the participants that hold the winning tickets.\r\n * @param tickets The number of winning tickets to draw.\r\n * @param options The draw multiple options.\r\n * @returns An array of the participants that hold the winning tickets.\r\n */\r\n Lotto.prototype.drawMultiple = function (tickets, options) {\r\n if (options === void 0) { options = {}; }\r\n var uniqueResults = (0, Utilities_1.isNullOrUndefined)(options.unique) ? false : options.unique;\r\n // Handle cases where the user has asked for zero tickets (no idea why they would do this be we should trust them).\r\n if (tickets === 0) {\r\n return [];\r\n }\r\n // Now that we know out tickets value is not zero we should check that it is a valid natural number.\r\n if (!(0, Utilities_1.isNaturalNumber)(tickets)) {\r\n throw new Error(\"tickets value must be a natural number\");\r\n }\r\n var result = [];\r\n // Keep drawing tickets until we either reach the number of required tickets or we simply run out of tickets to draw.\r\n // We can run out of tickets to draw if 'options.redrawable' is explicity 'false' or we just had no participants when 'drawMultiple' was called.\r\n while (result.length < tickets && this._participants.length > 0) {\r\n result.push(this.draw(options));\r\n }\r\n // If the 'unique' draw option is set then we need to remove duplicates from the result list.\r\n if (uniqueResults) {\r\n // Create an array to store our unique results.\r\n var unique = [];\r\n // Iterate over all of our participants (with potential duplicates) and populate our array of unique values.\r\n for (var _i = 0, result_1 = result; _i < result_1.length; _i++) {\r\n var participant = result_1[_i];\r\n if (unique.indexOf(participant) === -1) {\r\n unique.push(participant);\r\n }\r\n }\r\n result = unique;\r\n }\r\n return result;\r\n };\r\n return Lotto;\r\n}());\r\nexports.Lotto = Lotto;\r\n", "\"use strict\";\r\nObject.defineProperty(exports, \"__esModule\", { value: true });\r\nexports.createLotto = void 0;\r\nvar Lotto_1 = require(\"./Lotto\");\r\n/**\r\n * A function that creates and returns a Lotto instance.\r\n * @param participantsOrOptions An array of initial participants or options relating to the creation of a Lotto instance.\r\n * @returns A new Lotto instance.\r\n */\r\nfunction createLotto(participantsOrOptions) {\r\n // If no initial participants or lotto options were provided as an argument then we can just return a new lotto instance now.\r\n if (!participantsOrOptions) {\r\n return new Lotto_1.Lotto();\r\n }\r\n // Check whether we were provided with an array of initial participants or a lotto options object.\r\n if (Array.isArray(participantsOrOptions)) {\r\n // We are dealing with a pre-defined array of participants.\r\n var participants = participantsOrOptions;\r\n var lotto_1 = new Lotto_1.Lotto();\r\n // If the lotto participants have been defined upfront then we will need to add them all to our lotto instance now.\r\n participants.forEach(function (_a) {\r\n var participant = _a[0], tokens = _a[1];\r\n return lotto_1.add(participant, tokens);\r\n });\r\n // Return the Lotto instance.\r\n return lotto_1;\r\n }\r\n else {\r\n // We are dealing with some lotto options.\r\n var random = participantsOrOptions.random, participants = participantsOrOptions.participants;\r\n // Create a Lotto instance passing the custom RNG function to use in place of Math.random() (which could be undefined).\r\n var lotto_2 = new Lotto_1.Lotto(random);\r\n // If the lotto participants have been defined upfront as part of the options then we will need to add them all to our lotto instance now.\r\n if (participants) {\r\n participants.forEach(function (_a) {\r\n var participant = _a[0], tokens = _a[1];\r\n return lotto_2.add(participant, tokens);\r\n });\r\n }\r\n // Return the Lotto instance.\r\n return lotto_2;\r\n }\r\n}\r\nexports.createLotto = createLotto;\r\n", "\"use strict\";\r\nObject.defineProperty(exports, \"__esModule\", { value: true });\r\nvar createLotto_1 = require(\"./createLotto\");\r\nexports.default = createLotto_1.createLotto;\r\n", "import State from \"./State\";\nimport { validateDefinition } from \"./BehaviourTreeDefinitionValidator\";\nimport { convertMDSLToJSON } from \"./mdsl/MDSLDefinitionParser\";\nimport { BehaviourTree, FlattenedTreeNode } from \"./BehaviourTree\";\nimport { BehaviourTreeOptions } from \"./BehaviourTreeOptions\";\n\nexport { BehaviourTree, State, convertMDSLToJSON, validateDefinition };\nexport type { FlattenedTreeNode, BehaviourTreeOptions };\n", "/**\n * Enumeration of node state types.\n */\nexport enum State {\n READY = \"mistreevous.ready\",\n RUNNING = \"mistreevous.running\",\n SUCCEEDED = \"mistreevous.succeeded\",\n FAILED = \"mistreevous.failed\"\n}\n\nexport { State as default };\n\nexport type CompleteState = State.SUCCEEDED | State.FAILED;\nexport type AnyState = State.READY | State.RUNNING | CompleteState;\n", "import {\n NodeDefinition,\n RootNodeDefinition,\n DecoratorNodeDefinition,\n CompositeNodeDefinition,\n AnyNodeDefinition,\n BranchNodeDefinition\n} from \"./BehaviourTreeDefinition\";\n\n/**\n * A type guard function that returns true if the specified node satisfies the RootNodeDefinition type.\n * @param node The node.\n * @returns A value of true if the specified node satisfies the RootNodeDefinition type.\n */\nexport function isRootNode(node: NodeDefinition): node is RootNodeDefinition {\n return node.type === \"root\";\n}\n\n/**\n * A type guard function that returns true if the specified node satisfies the BranchNodeDefinition type.\n * @param node The node.\n * @returns A value of true if the specified node satisfies the BranchNodeDefinition type.\n */\nexport function isBranchNode(node: NodeDefinition): node is BranchNodeDefinition {\n return node.type === \"branch\";\n}\n\n/**\n * A type guard function that returns true if the specified node satisfies the NodeDefinition type.\n * @param node The node.\n * @returns A value of true if the specified node satisfies the NodeDefinition type.\n */\nexport function isLeafNode(node: NodeDefinition): node is NodeDefinition {\n return [\"branch\", \"action\", \"condition\", \"wait\"].includes(node.type);\n}\n\n/**\n * A type guard function that returns true if the specified node satisfies the DecoratorNodeDefinition type.\n * @param node The node.\n * @returns A value of true if the specified node satisfies the DecoratorNodeDefinition type.\n */\nexport function isDecoratorNode(node: NodeDefinition): node is DecoratorNodeDefinition {\n return [\"root\", \"repeat\", \"retry\", \"flip\", \"succeed\", \"fail\"].includes(node.type);\n}\n\n/**\n * A type guard function that returns true if the specified node satisfies the CompositeNodeDefinition type.\n * @param node The node.\n * @returns A value of true if the specified node satisfies the CompositeNodeDefinition type.\n */\nexport function isCompositeNode(node: NodeDefinition): node is CompositeNodeDefinition {\n return [\"sequence\", \"selector\", \"lotto\", \"parallel\"].includes(node.type);\n}\n\n/**\n * Flatten a node definition into an array of all of its nested node definitions.\n * @param nodeDefinition The node definition to flatten.\n * @returns An array of all of nested node definitions.\n */\nexport function flattenDefinition(nodeDefinition: AnyNodeDefinition): AnyNodeDefinition[] {\n const nodes: AnyNodeDefinition[] = [];\n\n const processNode = (currentNodeDefinition: AnyNodeDefinition) => {\n nodes.push(currentNodeDefinition);\n\n if (isCompositeNode(currentNodeDefinition)) {\n currentNodeDefinition.children.forEach(processNode);\n } else if (isDecoratorNode(currentNodeDefinition)) {\n processNode(currentNodeDefinition.child);\n }\n };\n\n processNode(nodeDefinition);\n\n return nodes;\n}\n\n/**\n * Determines whether the passed value is an integer.\n * @param value The value to check.\n * @returns Whether the passed value is an integer.\n */\nexport function isInteger(value: unknown): boolean {\n return typeof value === \"number\" && Math.floor(value) === value;\n}\n\n/**\n * Determines whether the passed value is null or undefined.\n * @param value The value to check.\n * @returns Whether the passed value is null or undefined.\n */\nexport function isNullOrUndefined(value: unknown): boolean {\n return typeof value === \"undefined\" || value === null;\n}\n", "/**\n * A type defining an object that holds a reference to substitued string literals parsed from the definition.\n */\nexport type StringLiteralPlaceholders = { [key: string]: string };\n\n/**\n * Pop the next raw token from the specified array of tokens and throw an error if it wasn't the expected one.\n * @param tokens The array of tokens.\n * @param expected An optional string or array or items, one of which must match the next popped token.\n * @returns The popped token.\n */\nexport function popAndCheck(tokens: string[], expected?: string | string[]): string {\n // Get and remove the next token.\n const popped = tokens.shift();\n\n // We were expecting another token but there aren't any.\n if (popped === undefined) {\n throw new Error(\"unexpected end of definition\");\n }\n\n // Do we have an expected token/tokens array?\n if (expected != undefined) {\n // Get an array of expected values, if the popped token matches any then we are all good.\n const expectedValues = typeof expected === \"string\" ? [expected] : expected;\n\n // Check whether the popped token matches at least one of our expected items.\n var tokenMatchesExpectation = expectedValues.some((item) => popped.toUpperCase() === item.toUpperCase());\n\n // Throw an error if the popped token didn't match any of our expected items.\n if (!tokenMatchesExpectation) {\n const expectationString = expectedValues.map((item) => \"'\" + item + \"'\").join(\" or \");\n throw new Error(\"unexpected token found. Expected \" + expectationString + \" but got '\" + popped + \"'\");\n }\n }\n\n // Return the popped token.\n return popped;\n}\n\n/**\n * Swaps out any node/attribute argument string literals with placeholders.\n * @param definition The definition.\n * @returns An object containing a mapping of placeholders to original string values as well as the processed definition string.\n */\nexport function substituteStringLiterals(definition: string): {\n placeholders: StringLiteralPlaceholders;\n processedDefinition: string;\n} {\n // Create an object to hold the mapping of placeholders to original string values.\n const placeholders: StringLiteralPlaceholders = {};\n\n // Replace any string literals wrapped with double quotes in our definition with placeholders to be processed later.\n const processedDefinition = definition.replace(/\\\"(\\\\.|[^\"\\\\])*\\\"/g, (match) => {\n var strippedMatch = match.substring(1, match.length - 1);\n var placeholder = Object.keys(placeholders).find((key) => placeholders[key] === strippedMatch);\n\n // If we have no existing string literal match then create a new placeholder.\n if (!placeholder) {\n placeholder = `@@${Object.keys(placeholders).length}@@`;\n placeholders[placeholder] = strippedMatch;\n }\n\n return placeholder;\n });\n\n return { placeholders, processedDefinition };\n}\n\n/**\n * Parse the tree definition into an array of raw tokens.\n * @param definition The definition.\n * @returns An array of tokens parsed from the definition.\n */\nexport function parseTokensFromDefinition(definition: string): string[] {\n // Add some space around various important characters so that they can be plucked out easier as individual tokens.\n definition = definition.replace(/\\(/g, \" ( \");\n definition = definition.replace(/\\)/g, \" ) \");\n definition = definition.replace(/\\{/g, \" { \");\n definition = definition.replace(/\\}/g, \" } \");\n definition = definition.replace(/\\]/g, \" ] \");\n definition = definition.replace(/\\[/g, \" [ \");\n definition = definition.replace(/\\,/g, \" , \");\n\n // Split the definition into raw token form and return it.\n return definition.replace(/\\s+/g, \" \").trim().split(\" \");\n}\n", "import { StringLiteralPlaceholders, popAndCheck } from \"./MDSLUtilities\";\n\n/**\n * A type representing any node function argument.\n */\ntype Argument = {\n /**\n * The argument value.\n */\n value: T;\n /**\n * The argument type, used for validation.\n */\n type: string;\n};\n\ntype NullArgument = Argument & {\n type: \"null\";\n};\n\ntype BooleanArgument = Argument & {\n type: \"boolean\";\n};\n\ntype NumberArgument = Argument & {\n type: \"number\";\n /**\n * A flag defining whether the number argument value is a valid integer. (used for validation)\n */\n isInteger: boolean;\n};\n\ntype StringPlaceholderArgument = Argument & {\n type: \"string\";\n};\n\ntype IdentifierArgument = Argument & {\n type: \"identifier\";\n};\n\n/**\n * A type representing a reference to any node function argument.\n */\ntype AnyArgument = NullArgument | BooleanArgument | NumberArgument | StringPlaceholderArgument | IdentifierArgument;\n\n/**\n * Parse an array of argument definitions from the specified tokens array.\n * @param tokens The array tokens to parse the argument definitions from.\n * @param stringArgumentPlaceholders The mapping of string literal node argument placeholders to original values.\n * @param argumentValidator The argument validator function.\n * @param validationFailedMessage The exception message to throw if argument validation fails.\n * @returns An array of argument definitions parsed from the specified tokens array.\n */\nexport function parseArgumentTokens(\n tokens: string[],\n stringArgumentPlaceholders: StringLiteralPlaceholders\n): AnyArgument[] {\n const argumentList: AnyArgument[] = [];\n\n // If the next token is not a '[' or '(' then we have no arguments to parse.\n if (![\"[\", \"(\"].includes(tokens[0])) {\n return argumentList;\n }\n\n // Any lists of arguments will always be wrapped in '[]' for node arguments or '()' for attribute arguments.\n // We are looking for a '[' or '(' opener that wraps the argument tokens and the relevant closer.\n const closingToken = popAndCheck(tokens, [\"[\", \"(\"]) === \"[\" ? \"]\" : \")\";\n\n const argumentListTokens: string[] = [];\n\n // Grab all tokens between the '[' and ']' or '(' and ')'.\n while (tokens.length && tokens[0] !== closingToken) {\n // The next token is part of our arguments list.\n argumentListTokens.push(tokens.shift()!);\n }\n\n // Validate the order of the argument tokens. Each token must either be a ',' or a single argument that satisfies the validator.\n argumentListTokens.forEach((token, index) => {\n // Get whether this token should be an actual argument.\n const shouldBeArgumentToken = !(index & 1);\n\n // If the current token should be an actual argument then validate it, otherwise it should be a ',' token.\n if (shouldBeArgumentToken) {\n // Get the argument definition.\n const argumentDefinition = getArgumentDefinition(token, stringArgumentPlaceholders);\n\n // This is a valid argument!\n argumentList.push(argumentDefinition);\n } else {\n // The current token should be a ',' token.\n if (token !== \",\") {\n throw new Error(`invalid argument list, expected ',' or ']' but got '${token}'`);\n }\n }\n });\n\n // The arguments list should terminate with a ']' or ')' token, depending on the opener.\n popAndCheck(tokens, closingToken);\n\n // Return the arguments.\n return argumentList;\n}\n\n/**\n * Gets an argument value definition.\n * @param token The argument token.\n * @param stringArgumentPlaceholders The mapping of string literal node argument placeholders to original values.\n * @returns An argument value definition.\n */\nfunction getArgumentDefinition(token: string, stringArgumentPlaceholders: StringLiteralPlaceholders): AnyArgument {\n // Check whether the token represents a null value.\n if (token === \"null\") {\n return {\n value: null,\n type: \"null\"\n } as NullArgument;\n }\n\n // Check whether the token represents a boolean value.\n if (token === \"true\" || token === \"false\") {\n return {\n value: token === \"true\",\n type: \"boolean\"\n } as BooleanArgument;\n }\n\n // Check whether the token represents a number value.\n // TODO: Relies on broken isNaN - see MDN.\n // if (!Number.isNaN(token)) {\n if (!isNaN(token as any)) {\n return {\n value: parseFloat(token),\n isInteger: parseFloat(token) === parseInt(token, 10),\n type: \"number\"\n } as NumberArgument;\n }\n\n // Check whether the token is a placeholder (e.g. @@0@@) representing a string literal.\n if (token.match(/^@@\\d+@@$/g)) {\n return {\n value: stringArgumentPlaceholders[token].replace('\\\\\"', '\"'),\n type: \"string\"\n } as StringPlaceholderArgument;\n }\n\n // The only remaining option is that the argument value is an identifier.\n return {\n value: token,\n type: \"identifier\"\n } as IdentifierArgument;\n}\n", "import { NodeAttributeDefinition } from \"../BehaviourTreeDefinition\";\nimport { parseArgumentTokens } from \"./MDSLNodeArgumentParser\";\nimport { StringLiteralPlaceholders } from \"./MDSLUtilities\";\n\n/**\n * A type defining the attribute definitions of a node.\n */\ntype NodeAttributes = {\n while?: NodeAttributeDefinition;\n until?: NodeAttributeDefinition;\n entry?: NodeAttributeDefinition;\n exit?: NodeAttributeDefinition;\n step?: NodeAttributeDefinition;\n};\n\n/**\n * Parse any node attribute definitions from the specified tokens array.\n * @param tokens The array of remaining tokens.\n * @param stringArgumentPlaceholders The mapping of string literal node argument placeholders to original values.\n * @returns An object of attribute definitions defined by any directly following tokens.\n */\nexport function parseAttributeTokens(\n tokens: string[],\n stringArgumentPlaceholders: StringLiteralPlaceholders\n): NodeAttributes {\n const nodeAttributeNames: (keyof NodeAttributes)[] = [\"while\", \"until\", \"entry\", \"exit\", \"step\"];\n\n // Create an object to hold any attributes found.\n const attributes: NodeAttributes = {};\n\n // Try to get the name of the attribute for the next token.\n let nextAttributeName = tokens[0]?.toLowerCase() as keyof NodeAttributes;\n\n // Pull attribute tokens as well as their arguments off of the tokens stack until we have no more.\n while (nodeAttributeNames.includes(nextAttributeName)) {\n // Check to make sure that we have not already created an attribute definition of this type.\n if (attributes[nextAttributeName]) {\n throw new Error(`duplicate attribute '${tokens[0].toUpperCase()}' found for node`);\n }\n\n // Remove the attribute name token from the array of tokens.\n tokens.shift();\n\n // Grab the attribute arguments, assuming the first to be an identifier.\n const [attributeCallIdentifier, ...attributeArguments] = parseArgumentTokens(\n tokens,\n stringArgumentPlaceholders\n );\n\n // The first attribute argument has to be an identifer, this will reference an agent function.\n if (attributeCallIdentifier?.type !== \"identifier\") {\n throw new Error(\"expected agent function name identifier argument for attribute\");\n }\n\n // Any attribute arguments (other than the expected call identifier) must have a type of string, number, boolean or null.\n attributeArguments\n .filter((arg) => arg.type === \"identifier\")\n .forEach((arg) => {\n throw new Error(\n `invalid attribute argument value '${arg.value}', must be string, number, boolean or null`\n );\n });\n\n // Create the attribute definition and add it to the object of attribute definitions found.\n attributes[nextAttributeName] = {\n call: attributeCallIdentifier.value,\n args: attributeArguments.map(({ value }) => value)\n };\n\n // Try to get the next attribute name token, as there could be multiple.\n nextAttributeName = tokens[0]?.toLowerCase() as keyof NodeAttributes;\n }\n\n return attributes;\n}\n", "import {\n ActionNodeDefinition,\n AnyChildNodeDefinition,\n AnyNodeDefinition,\n BranchNodeDefinition,\n ConditionNodeDefinition,\n FailNodeDefinition,\n FlipNodeDefinition,\n LottoNodeDefinition,\n ParallelNodeDefinition,\n RepeatNodeDefinition,\n RetryNodeDefinition,\n RootNodeDefinition,\n SelectorNodeDefinition,\n SequenceNodeDefinition,\n SucceedNodeDefinition,\n WaitNodeDefinition\n} from \"../BehaviourTreeDefinition\";\nimport {\n isCompositeNode,\n isDecoratorNode,\n isLeafNode,\n isNullOrUndefined,\n isRootNode\n} from \"../BehaviourTreeDefinitionUtilities\";\nimport { parseArgumentTokens } from \"./MDSLNodeArgumentParser\";\nimport { parseAttributeTokens } from \"./MDSLNodeAttributeParser\";\nimport {\n StringLiteralPlaceholders,\n parseTokensFromDefinition,\n popAndCheck,\n substituteStringLiterals\n} from \"./MDSLUtilities\";\n\n/**\n * Convert the MDSL tree definition string into an equivalent JSON definition.\n * @param definition The tree definition string as MDSL.\n * @returns The root node JSON definitions.\n */\nexport function convertMDSLToJSON(definition: string): RootNodeDefinition[] {\n // Swap out any node/attribute argument string literals with a placeholder and get a mapping of placeholders to original values as well as the processed definition.\n const { placeholders, processedDefinition } = substituteStringLiterals(definition);\n\n // Parse our definition definition string into an array of raw tokens.\n const tokens = parseTokensFromDefinition(processedDefinition);\n\n return convertTokensToJSONDefinition(tokens, placeholders);\n}\n\n/**\n * Converts the specified tree definition tokens into a JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The root node JSON definitions.\n */\nfunction convertTokensToJSONDefinition(\n tokens: string[],\n stringLiteralPlaceholders: StringLiteralPlaceholders\n): RootNodeDefinition[] {\n // There must be at least 3 tokens for the tree definition to be valid. 'ROOT', '{' and '}'.\n if (tokens.length < 3) {\n throw new Error(\"invalid token count\");\n }\n\n // We should have a matching number of '{' and '}' tokens. If not, then there are scopes that have not been properly closed.\n if (tokens.filter((token) => token === \"{\").length !== tokens.filter((token) => token === \"}\").length) {\n throw new Error(\"scope character mismatch\");\n }\n\n // Create an array of tree stack arrays where root nodes will always be at the botton and the current composite/decorator node at the top.\n // There should be an element in this array for every root node defined and every element should be an array with a root note as the first element.\n // E.g. A definition with two root nodes defined:\n // [\n // [root, lotto, sequence],\n // [root, selector]\n // ]\n const treeStacks: [Partial, ...Partial[]][] = [];\n\n // Create an array of all root node definitions that we create.\n const rootNodes: Partial[] = [];\n\n // A helper function used to push node definitions onto the tree stack.\n const pushNode = (node: AnyNodeDefinition) => {\n // If the node is a root node then we need to create a new tree stack array with the root node at the root.\n if (isRootNode(node)) {\n // We need to double-check that this root node is not the child of another node.\n // We can do this by checking whether the top tree stack is not empty (contains an existing node)\n if (treeStacks[treeStacks.length - 1]?.length) {\n throw new Error(\"a root node cannot be the child of another node\");\n }\n\n // Add the root node definition to our array of all parsed root node definitions.\n rootNodes.push(node);\n\n // Add the root node definition to the root of a new tree stack.\n treeStacks.push([node]);\n\n return;\n }\n\n // All non-root nodes should be pushed after their root nodes so handle cases\n // where we may not have any tree stacks or our top-most tree stack is empty.\n if (!treeStacks.length || !treeStacks[treeStacks.length - 1].length) {\n throw new Error(\"expected root node at base of definition\");\n }\n\n // Get the current tree stack that we are populating.\n const topTreeStack = treeStacks[treeStacks.length - 1];\n\n // Get the top-most node in the current tree stack, this will be a composite/decorator node\n // for which we will populate its children array if composite or setting its child if a decorator.\n const topTreeStackTopNode = topTreeStack[topTreeStack.length - 1] as AnyNodeDefinition;\n\n // If the top-most node in the current root stack is a composite or decorator\n // node then the current node should be added as a child of the top-most node.\n if (isCompositeNode(topTreeStackTopNode)) {\n topTreeStackTopNode.children = topTreeStackTopNode.children || [];\n topTreeStackTopNode.children.push(node);\n } else if (isDecoratorNode(topTreeStackTopNode)) {\n // If the top node already has a child node set then throw an error as a decorator should only have a single child.\n if (topTreeStackTopNode.child) {\n throw new Error(\"a decorator node must only have a single child node\");\n }\n\n topTreeStackTopNode.child = node;\n }\n\n // If the node we are adding is also a composite or decorator node, then we should push it\n // onto the current tree stack, as subsequent nodes will be added as its child/children.\n if (!isLeafNode(node)) {\n topTreeStack.push(node);\n }\n };\n\n // A helper function used to pop the top-most node definition off of the tree stack and return it.\n const popNode = (): AnyNodeDefinition | null => {\n let poppedNode: AnyNodeDefinition | null = null;\n\n // Get the current tree stack that we are populating.\n const topTreeStack = treeStacks[treeStacks.length - 1];\n\n // Pop the top-most node in the current tree stack if there is one.\n if (topTreeStack.length) {\n poppedNode = topTreeStack.pop() as AnyNodeDefinition;\n }\n\n // We don't want any empty tree stacks in our stack of tree stacks.\n if (!topTreeStack.length) {\n treeStacks.pop();\n }\n\n return poppedNode;\n };\n\n // We should keep processing the raw tokens until we run out of them.\n while (tokens.length) {\n // Grab the next token.\n const token = tokens.shift()!;\n\n // How we create the next node depends on the current raw token value.\n switch (token.toUpperCase()) {\n case \"ROOT\": {\n pushNode(createRootNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"SUCCEED\": {\n pushNode(createSucceedNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"FAIL\": {\n pushNode(createFailNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"FLIP\": {\n pushNode(createFlipNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"REPEAT\": {\n pushNode(createRepeatNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"RETRY\": {\n pushNode(createRetryNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"SEQUENCE\": {\n pushNode(createSequenceNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"SELECTOR\": {\n pushNode(createSelectorNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"PARALLEL\": {\n pushNode(createParallelNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"LOTTO\": {\n pushNode(createLottoNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"ACTION\": {\n pushNode(createActionNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"CONDITION\": {\n pushNode(createConditionNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"WAIT\": {\n pushNode(createWaitNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"BRANCH\": {\n pushNode(createBranchNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"}\": {\n // The '}' character closes the current scope and means that we have to pop a node off of the current stack.\n const poppedNode = popNode();\n\n // Now that we have a node definition we can carry out any validation that may require the node to be fully populated.\n if (poppedNode) {\n validatePoppedNode(poppedNode);\n }\n\n break;\n }\n\n default: {\n throw new Error(`unexpected token: ${token}`);\n }\n }\n }\n\n return rootNodes as RootNodeDefinition[];\n}\n\n/**\n * Creates a root node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The root node JSON definition.\n */\nfunction createRootNode(tokens: string[], stringLiteralPlaceholders: StringLiteralPlaceholders): RootNodeDefinition {\n // Create the root node definition.\n let node = {\n type: \"root\",\n id: undefined\n } as RootNodeDefinition;\n\n // Parse any node arguments, we should only have one if any which will be an identifier argument for the root identifier.\n const nodeArguments = parseArgumentTokens(tokens, stringLiteralPlaceholders);\n\n // Check whether any node arguments were defined.\n if (nodeArguments.length) {\n // We should only have one argument, if any, which will be an identifier argument for the root identifier.\n if (nodeArguments.length === 1 && nodeArguments[0].type === \"identifier\") {\n // The root node identifier will be the first and only node argument value.\n node.id = nodeArguments[0].value as string;\n } else {\n throw new Error(\"expected single root name argument\");\n }\n }\n\n // Grab any node attribute definitions and spread them into the node definition.\n node = { ...node, ...parseAttributeTokens(tokens, stringLiteralPlaceholders) };\n\n // This is a decorator node, so we expect an opening '{'.\n popAndCheck(tokens, \"{\");\n\n // Return the root node definition.\n return node;\n}\n\n/**\n * Creates a succeed node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The succeed node JSON definition.\n */\nfunction createSucceedNode(\n tokens: string[],\n stringLiteralPlaceholders: StringLiteralPlaceholders\n): SucceedNodeDefinition {\n const node = {\n type: \"succeed\",\n ...parseAttributeTokens(tokens, stringLiteralPlaceholders)\n } as SucceedNodeDefinition;\n\n // This is a decorator node, so we expect an opening '{'.\n popAndCheck(tokens, \"{\");\n\n // Return the succeed node definition.\n return node;\n}\n\n/**\n * Creates a fail node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The fail node JSON definition.\n */\nfunction createFailNode(tokens: string[], stringLiteralPlaceholders: StringLiteralPlaceholders): FailNodeDefinition {\n const node = {\n type: \"fail\",\n ...parseAttributeTokens(tokens, stringLiteralPlaceholders)\n } as FailNodeDefinition;\n\n // This is a decorator node, so we expect an opening '{'.\n popAndCheck(tokens, \"{\");\n\n // Return the fail node definition.\n return node;\n}\n\n/**\n * Creates a flip node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The flip node JSON definition.\n */\nfunction createFlipNode(tokens: string[], stringLiteralPlaceholders: StringLiteralPlaceholders): FlipNodeDefinition {\n const node = {\n type: \"flip\",\n ...parseAttributeTokens(tokens, stringLiteralPlaceholders)\n } as FlipNodeDefinition;\n\n // This is a decorator node, so we expect an opening '{'.\n popAndCheck(tokens, \"{\");\n\n // Return the flip node definition.\n return node;\n}\n\n/**\n * Creates a repeat node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The repeat node JSON definition.\n */\nfunction createRepeatNode(\n tokens: string[],\n stringLiteralPlaceholders: StringLiteralPlaceholders\n): RepeatNodeDefinition {\n let node = { type: \"repeat\" } as RepeatNodeDefinition;\n\n // Get the node arguments.\n const nodeArguments = parseArgumentTokens(tokens, stringLiteralPlaceholders);\n\n // The arguments of a repeat node are optional. We may have:\n // - No node arguments, in which case the repeat note will iterate indefinitely.\n // - One node argument which will be the explicit number of iterations to make.\n // - Two node arguments which define the min and max iteration bounds from which a random iteration count will be picked.\n if (nodeArguments.length) {\n // All repeat node arguments MUST be of type number and must be integer.\n nodeArguments\n .filter((arg) => arg.type !== \"number\" || !arg.isInteger)\n .forEach(() => {\n throw new Error(`repeat node iteration counts must be integer values`);\n });\n\n // We should have got one or two iteration counts.\n if (nodeArguments.length === 1) {\n // A static iteration count was defined.\n node.iterations = nodeArguments[0].value as number;\n\n // A repeat node must have a positive number of iterations if defined.\n if (node.iterations < 0) {\n throw new Error(\"a repeat node must have a positive number of iterations if defined\");\n }\n } else if (nodeArguments.length === 2) {\n // A minimum and maximum iteration count was defined.\n node.iterations = [nodeArguments[0].value as number, nodeArguments[1].value as number];\n\n // A repeat node must have a positive min and max iteration count if they are defined.\n if (node.iterations[0] < 0 || node.iterations[1] < 0) {\n throw new Error(\"a repeat node must have a positive minimum and maximum iteration count if defined\");\n }\n\n // A repeat node must not have an minimum iteration count that exceeds the maximum iteration count.\n if (node.iterations[0] > node.iterations[1]) {\n throw new Error(\n \"a repeat node must not have a minimum iteration count that exceeds the maximum iteration count\"\n );\n }\n } else {\n // An incorrect number of iteration counts was defined.\n throw new Error(\"invalid number of repeat node iteration count arguments defined\");\n }\n }\n\n // Grab any node attribute definitions and spread them into the node definition.\n node = { ...node, ...parseAttributeTokens(tokens, stringLiteralPlaceholders) };\n\n // This is a decorator node, so we expect an opening '{'.\n popAndCheck(tokens, \"{\");\n\n // Return the repeat node definition.\n return node;\n}\n\n/**\n * Creates a retry node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The retry node JSON definition.\n */\nfunction createRetryNode(tokens: string[], stringLiteralPlaceholders: StringLiteralPlaceholders): RetryNodeDefinition {\n let node = { type: \"retry\" } as RetryNodeDefinition;\n\n // Get the node arguments.\n const nodeArguments = parseArgumentTokens(tokens, stringLiteralPlaceholders);\n\n // The arguments of a retry node are optional. We may have:\n // - No node arguments, in which case the retry note will attempt indefinitely.\n // - One node argument which will be the explicit number of attempts to make.\n // - Two node arguments which define the min and max attempt bounds from which a random attempt count will be picked.\n if (nodeArguments.length) {\n // All retry node arguments MUST be of type number and must be integer.\n nodeArguments\n .filter((arg) => arg.type !== \"number\" || !arg.isInteger)\n .forEach(() => {\n throw new Error(`retry node attempt counts must be integer values`);\n });\n\n // We should have got one or two attempt counts.\n if (nodeArguments.length === 1) {\n // A static attempt count was defined.\n node.attempts = nodeArguments[0].value as number;\n\n // A retry node must have a positive number of attempts if defined.\n if (node.attempts < 0) {\n throw new Error(\"a retry node must have a positive number of attempts if defined\");\n }\n } else if (nodeArguments.length === 2) {\n // A minimum and maximum attempt count was defined.\n node.attempts = [nodeArguments[0].value as number, nodeArguments[1].value as number];\n\n // A retry node must have a positive min and max attempts count if they are defined.\n if (node.attempts[0] < 0 || node.attempts[1] < 0) {\n throw new Error(\"a retry node must have a positive minimum and maximum attempt count if defined\");\n }\n\n // A retry node must not have a minimum attempt count that exceeds the maximum attempt count.\n if (node.attempts[0] > node.attempts[1]) {\n throw new Error(\n \"a retry node must not have a minimum attempt count that exceeds the maximum attempt count\"\n );\n }\n } else {\n // An incorrect number of attempt counts was defined.\n throw new Error(\"invalid number of retry node attempt count arguments defined\");\n }\n }\n\n // Grab any node attribute definitions and spread them into the node definition.\n node = { ...node, ...parseAttributeTokens(tokens, stringLiteralPlaceholders) };\n\n // This is a decorator node, so we expect an opening '{'.\n popAndCheck(tokens, \"{\");\n\n // Return the retry node definition.\n return node;\n}\n\n/**\n * Creates a sequence node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The sequence node JSON definition.\n */\nfunction createSequenceNode(\n tokens: string[],\n stringLiteralPlaceholders: StringLiteralPlaceholders\n): SequenceNodeDefinition {\n const node = {\n type: \"sequence\",\n ...parseAttributeTokens(tokens, stringLiteralPlaceholders)\n } as SequenceNodeDefinition;\n\n // This is a composite node, so we expect an opening '{'.\n popAndCheck(tokens, \"{\");\n\n // Return the sequence node definition.\n return node;\n}\n\n/**\n * Creates a selector node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The selector node JSON definition.\n */\nfunction createSelectorNode(\n tokens: string[],\n stringLiteralPlaceholders: StringLiteralPlaceholders\n): SelectorNodeDefinition {\n const node = {\n type: \"selector\",\n ...parseAttributeTokens(tokens, stringLiteralPlaceholders)\n } as SelectorNodeDefinition;\n\n // This is a composite node, so we expect an opening '{'.\n popAndCheck(tokens, \"{\");\n\n // Return the selector node definition.\n return node;\n}\n\n/**\n * Creates a parallel node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The parallel node JSON definition.\n */\nfunction createParallelNode(\n tokens: string[],\n stringLiteralPlaceholders: StringLiteralPlaceholders\n): ParallelNodeDefinition {\n const node = {\n type: \"parallel\",\n ...parseAttributeTokens(tokens, stringLiteralPlaceholders)\n } as ParallelNodeDefinition;\n\n // This is a composite node, so we expect an opening '{'.\n popAndCheck(tokens, \"{\");\n\n // Return the parallel node definition.\n return node;\n}\n\n/**\n * Creates a lotto node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The lotto node JSON definition.\n */\nfunction createLottoNode(tokens: string[], stringLiteralPlaceholders: StringLiteralPlaceholders): LottoNodeDefinition {\n // If any node arguments have been defined then they must be our weights.\n const nodeArguments = parseArgumentTokens(tokens, stringLiteralPlaceholders);\n\n // All lotto node arguments MUST be of type number and must be integer.\n nodeArguments\n .filter((arg) => arg.type !== \"number\" || !arg.isInteger)\n .forEach(() => {\n throw new Error(`lotto node weight arguments must be integer values`);\n });\n\n const node = {\n type: \"lotto\",\n weights: nodeArguments.map(({ value }) => value),\n ...parseAttributeTokens(tokens, stringLiteralPlaceholders)\n } as LottoNodeDefinition;\n\n // This is a composite node, so we expect an opening '{'.\n popAndCheck(tokens, \"{\");\n\n // Return the lotto node definition.\n return node;\n}\n\n/**\n * Creates an action node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The action node JSON definition.\n */\nfunction createActionNode(\n tokens: string[],\n stringLiteralPlaceholders: StringLiteralPlaceholders\n): ActionNodeDefinition {\n // Parse any node arguments, we should have at least one which will be an identifier argument for the action name\n // and agent function to invoke for the action, all other arguments are to be passed as arguments to that function.\n const [actionNameIdentifier, ...agentFunctionArgs] = parseArgumentTokens(tokens, stringLiteralPlaceholders);\n\n // Our first argument MUST be defined and be an identifier as we require an action name argument.\n if (actionNameIdentifier?.type !== \"identifier\") {\n throw new Error(\"expected action name identifier argument\");\n }\n\n // Only the first argument should have been an identifier, all agent function arguments must be string, number, boolean or null.\n agentFunctionArgs\n .filter((arg) => arg.type === \"identifier\")\n .forEach((arg) => {\n throw new Error(\n `invalid action node argument value '${arg.value}', must be string, number, boolean or null`\n );\n });\n\n // Return the action node definition.\n return {\n type: \"action\",\n call: actionNameIdentifier.value,\n args: agentFunctionArgs.map(({ value }) => value),\n ...parseAttributeTokens(tokens, stringLiteralPlaceholders)\n };\n}\n\n/**\n * Creates a condition node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The condition node JSON definition.\n */\nfunction createConditionNode(\n tokens: string[],\n stringLiteralPlaceholders: StringLiteralPlaceholders\n): ConditionNodeDefinition {\n // Parse any node arguments, we should have at least one which will be an identifier argument for the condition name\n // and agent function to invoke for the condition, all other arguments are to be passed as arguments to that function.\n const [conditionNameIdentifier, ...agentFunctionArgs] = parseArgumentTokens(tokens, stringLiteralPlaceholders);\n\n // Our first argument MUST be defined and be an identifier as we require a condition name argument.\n if (conditionNameIdentifier?.type !== \"identifier\") {\n throw new Error(\"expected condition name identifier argument\");\n }\n\n // Only the first argument should have been an identifier, all agent function arguments must be string, number, boolean or null.\n agentFunctionArgs\n .filter((arg) => arg.type === \"identifier\")\n .forEach((arg) => {\n throw new Error(\n `invalid condition node argument value '${arg.value}', must be string, number, boolean or null`\n );\n });\n\n // Return the condition node definition.\n return {\n type: \"condition\",\n call: conditionNameIdentifier.value,\n args: agentFunctionArgs.map(({ value }) => value),\n ...parseAttributeTokens(tokens, stringLiteralPlaceholders)\n };\n}\n\n/**\n * Creates a wait node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The wait node JSON definition.\n */\nfunction createWaitNode(tokens: string[], stringLiteralPlaceholders: StringLiteralPlaceholders): WaitNodeDefinition {\n let node = { type: \"wait\" } as WaitNodeDefinition;\n\n // Get the node arguments.\n const nodeArguments = parseArgumentTokens(tokens, stringLiteralPlaceholders);\n\n // The arguments of a wait node are optional. We may have:\n // - No node arguments, in which case the wait will be indefinite until it is aborted.\n // - One node argument which will be the explicit duration of the wait.\n // - Two node arguments which define the min and max duration bounds from which a random duration will be picked.\n if (nodeArguments.length) {\n // All wait node arguments MUST be of type number and must be integer.\n nodeArguments\n .filter((arg) => arg.type !== \"number\" || !arg.isInteger)\n .forEach(() => {\n throw new Error(`wait node duration arguments must be integer values`);\n });\n\n // We may have:\n // - One node argument which will be the explicit duration of the wait.\n // - Two node arguments which define the min and max duration bounds from which a random duration will be picked.\n // - Too many arguments, which is not valid.\n if (nodeArguments.length === 1) {\n // An explicit duration was defined.\n node.duration = nodeArguments[0].value as number;\n\n // If an explict duration was defined then it must be a positive number.\n if (node.duration < 0) {\n throw new Error(\"a wait node must have a positive duration\");\n }\n } else if (nodeArguments.length === 2) {\n // Min and max duration bounds were defined from which a random duration will be picked.\n node.duration = [nodeArguments[0].value as number, nodeArguments[1].value as number];\n\n // A wait node must have a positive min and max duration.\n if (node.duration[0] < 0 || node.duration[1] < 0) {\n throw new Error(\"a wait node must have a positive minimum and maximum duration\");\n }\n\n // A wait node must not have a minimum duration that exceeds the maximum duration.\n if (node.duration[0] > node.duration[1]) {\n throw new Error(\"a wait node must not have a minimum duration that exceeds the maximum duration\");\n }\n } else if (nodeArguments.length > 2) {\n // An incorrect number of duration arguments were defined.\n throw new Error(\"invalid number of wait node duration arguments defined\");\n }\n }\n\n // Return the wait node definition.\n return { ...node, ...parseAttributeTokens(tokens, stringLiteralPlaceholders) };\n}\n\n/**\n * Creates a branch node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The branch node JSON definition.\n */\nfunction createBranchNode(\n tokens: string[],\n stringLiteralPlaceholders: StringLiteralPlaceholders\n): BranchNodeDefinition {\n // Parse any node arguments, we should have one which will be an identifier argument for the root ref.\n const nodeArguments = parseArgumentTokens(tokens, stringLiteralPlaceholders);\n\n // We should have only a single identifer argument for a branch node, which is the root ref.\n if (nodeArguments.length !== 1 || nodeArguments[0].type !== \"identifier\") {\n throw new Error(\"expected single branch name argument\");\n }\n\n // Return the branch node definition.\n return { type: \"branch\", ref: nodeArguments[0].value };\n}\n\n/**\n * Validate a fully-populated node definition that was popped off of the tree stack.\n * @param node The popped node to validate.\n */\nfunction validatePoppedNode(node: AnyNodeDefinition): void {\n // Decorators MUST have a child defined.\n if (isDecoratorNode(node) && isNullOrUndefined(node.child)) {\n throw new Error(`a ${node.type} node must have a single child node defined`);\n }\n\n // Composites MUST have at least one child defined.\n if (isCompositeNode(node) && !node.children?.length) {\n throw new Error(`a ${node.type} node must have at least a single child node defined`);\n }\n}\n", "import { RootNodeDefinition } from \"./BehaviourTreeDefinition\";\nimport { flattenDefinition, isBranchNode, isInteger } from \"./BehaviourTreeDefinitionUtilities\";\nimport { convertMDSLToJSON } from \"./mdsl/MDSLDefinitionParser\";\n\n/**\n * An object representing the result of validating a tree definition.\n */\nexport type DefinitionValidationResult = {\n /**\n * A flag defining whether validation succeeded.\n */\n succeeded: boolean;\n /**\n * A string containing the error message if validation did not succeed.\n */\n errorMessage?: string;\n};\n\n/**\n * Validates the specified behaviour tree definition in the form of JSON or MDSL, not taking any globally registered subtrees into consideration.\n * @param definition The behaviour tree definition in the form of JSON or MDSL.\n * @returns An object representing the result of validating the given tree definition.\n */\nexport function validateDefinition(definition: any): DefinitionValidationResult {\n // The definition must be defined.\n if (definition === null || typeof definition === \"undefined\") {\n return createValidationFailureResult(\"definition is null or undefined\");\n }\n\n // We are expecting a definition in one of three different forms:\n // - A string which we will assume is MDSL and we will parse this to JSON before validation.\n // - An array which we will assume is an array of root node definitions with at least one being the primary root node (no 'id' property)\n // - An object which we will assume is the primary root node and should not have an 'id' property.\n if (typeof definition === \"string\") {\n // The definition is a string which we can assume is MDSL, so attempt to validate it.\n return validateMDSLDefinition(definition);\n } else if (typeof definition === \"object\") {\n // The definition will either be an array (of root node definitions) or an object (the single primary root node definition).\n return validateJSONDefinition(definition);\n } else {\n return createValidationFailureResult(`unexpected definition type of '${typeof definition}'`);\n }\n}\n\n/**\n * Validates the specified behaviour tree definition in the form of MDSL.\n * @param definition The behaviour tree definition in the form of MDSL.\n * @returns An object representing the result of validating the given tree definition.\n */\nexport function validateMDSLDefinition(definition: string): DefinitionValidationResult {\n let rootNodeDefinitions;\n\n // The first thing the we need to do is to attempt to convert our MDSL into JSON.\n try {\n // The definition is a string which we can assume is MDSL, so attempt to parse it to a JSON definition in the form of an array of root node definitions.\n rootNodeDefinitions = convertMDSLToJSON(definition);\n } catch (error) {\n // We failed to parse the JSON from the MDSL, this is likely to be the result of it not being a valid MDSL string.\n return createValidationFailureResult(`invalid MDSL: ${error}`);\n }\n\n // Unpack all of the root node definitions into arrays of main ('id' defined) and sub ('id' not defined) root node definitions.\n const mainRootNodeDefinitions = rootNodeDefinitions.filter(({ id }) => typeof id === \"undefined\");\n const subRootNodeDefinitions = rootNodeDefinitions.filter(({ id }) => typeof id === \"string\" && id.length > 0);\n\n // We should ALWAYS have exactly one root node definition without an 'id' property defined, which is out main root node definition.\n if (mainRootNodeDefinitions.length !== 1) {\n return createValidationFailureResult(\n \"expected single unnamed root node at base of definition to act as main root\"\n );\n }\n\n // We should never have duplicate 'id' properties across our sub root node definitions.\n const subRootNodeIdenitifers: string[] = [];\n for (const { id } of subRootNodeDefinitions) {\n // Have we already come across this 'id' property value?\n if (subRootNodeIdenitifers.includes(id!)) {\n return createValidationFailureResult(`multiple root nodes found with duplicate name '${id}'`);\n }\n\n subRootNodeIdenitifers.push(id!);\n }\n\n try {\n // Validate our branch -> subtree links and check for any circular dependencies, we don't care about checking for broken subtree links here.\n validateBranchSubtreeLinks(rootNodeDefinitions, false);\n } catch (exception) {\n return createValidationFailureResult((exception as Error).message);\n }\n\n // Our definition was valid!\n return { succeeded: true };\n}\n\n/**\n * Validates the specified behaviour tree definition in the form of JSON.\n * @param definition The behaviour tree definition in the form of JSON.\n * @returns An object representing the result of validating the given tree definition.\n */\nexport function validateJSONDefinition(\n definition: RootNodeDefinition | RootNodeDefinition[]\n): DefinitionValidationResult {\n // The definition will either be an array (of root node definitions) or an object (the single primary root node definition).\n const rootNodeDefinitions = Array.isArray(definition) ? definition : [definition];\n\n // Iterate over our array of root nodes and call validateNode for each, passing an initial depth of 0, wrapped in a try catch to handle validation failures.\n try {\n rootNodeDefinitions.forEach((rootNodeDefinition) => validateNode(rootNodeDefinition, 0));\n } catch (error) {\n // Handle cases where we have caught a thrown Error and return a failure result with the error message.\n if (error instanceof Error) {\n return createValidationFailureResult(error.message);\n }\n\n // No idea what happened here!\n return createValidationFailureResult(`unexpected error: ${error}`);\n }\n\n // Unpack all of the root node definitions into arrays of main ('id' defined) and sub ('id' not defined) root node definitions.\n const mainRootNodeDefinitions = rootNodeDefinitions.filter(({ id }) => typeof id === \"undefined\");\n const subRootNodeDefinitions = rootNodeDefinitions.filter(({ id }) => typeof id === \"string\" && id.length > 0);\n\n // We should ALWAYS have exactly one root node definition without an 'id' property defined, which is out main root node definition.\n if (mainRootNodeDefinitions.length !== 1) {\n return createValidationFailureResult(\n \"expected single root node without 'id' property defined to act as main root\"\n );\n }\n\n // We should never have duplicate 'id' properties across our sub root node definitions.\n const subRootNodeIdenitifers: string[] = [];\n for (const { id } of subRootNodeDefinitions) {\n // Have we already come across this 'id' property value?\n if (subRootNodeIdenitifers.includes(id!)) {\n return createValidationFailureResult(\n `multiple root nodes found with duplicate 'id' property value of '${id}'`\n );\n }\n\n subRootNodeIdenitifers.push(id!);\n }\n\n try {\n // Validate our branch -> subtree links and check for any circular dependencies, we don't care about checking for broken subtree links here.\n validateBranchSubtreeLinks(rootNodeDefinitions, false);\n } catch (exception) {\n return createValidationFailureResult((exception as Error).message);\n }\n\n // Our definition was valid!\n return { succeeded: true };\n}\n\n/**\n * Validates the branch -> subtree links across all provided root node definitions.\n * This will not consider branch nodes that reference any globally registered subtrees unless includesGlobalSubtrees\n * is set to true, in which case we will also verify that there are no broken branch -> subtree links.\n * @param rootNodeDefinitions The array of root node definitions.\n * @param includesGlobalSubtrees A flag defining whether the array includes all global subtree root node definitions.\n */\nexport function validateBranchSubtreeLinks(rootNodeDefinitions: RootNodeDefinition[], includesGlobalSubtrees: boolean) {\n // Create a mapping of root node identifiers to other root nodes that they reference via branch nodes.\n // Below is an example of a mapping that includes a circular dependency (root => a => b => c => a)\n // [{ refs: [\"a\", \"b\"] }, { id: \"a\", refs: [\"b\"] }, { id: \"b\", refs: [\"c\"] }, { id: \"c\", refs: [\"a\"] }]\n const rootNodeMappings: { id: string | undefined; refs: string[] }[] = rootNodeDefinitions.map(\n (rootNodeDefinition) => ({\n id: rootNodeDefinition.id,\n refs: flattenDefinition(rootNodeDefinition)\n .filter(isBranchNode)\n .map(({ ref }) => ref)\n })\n );\n\n // A recursive function to walk through the mappings, keeping track of which root nodes we have visited in the form of a path of root node identifiers.\n const followRefs = (mapping: { id: string | undefined; refs: string[] }, path: (string | undefined)[] = []) => {\n // Have we found a circular dependency?\n if (path.includes(mapping.id)) {\n // We found a circular dependency! Get the bad path of root node identifiers.\n const badPath = [...path, mapping.id];\n\n // Create the formatted path value. [undefined, \"a\", \"b\", \"c\", \"a\"] would be formatted as \"a -> b -> c -> a\".\n const badPathFormatted = badPath.filter((element) => !!element).join(\" => \");\n\n // No need to continue, we found a circular dependency.\n throw new Error(`circular dependency found in branch node references: ${badPathFormatted}`);\n }\n\n for (const ref of mapping.refs) {\n // Find the mapping for the root node with an identifer matching the current ref.\n const subMapping = rootNodeMappings.find(({ id }) => id === ref);\n\n // We may not have a mapping for this ref, which is normal when we aren't considering all globally registered subtrees.\n if (subMapping) {\n followRefs(subMapping, [...path, mapping.id]);\n } else if (includesGlobalSubtrees) {\n // We found a reference to a root node that doesn't exist, which is a problem seeing as the root node definitons includes all globally registered subtrees.\n throw new Error(\n mapping.id\n ? `subtree '${mapping.id}' has branch node that references root node '${ref}' which has not been defined`\n : `primary tree has branch node that references root node '${ref}' which has not been defined`\n );\n }\n }\n };\n\n // Start looking for circular dependencies and broken references from the primary root node definition.\n followRefs(rootNodeMappings.find((mapping) => typeof mapping.id === \"undefined\")!);\n}\n\n/**\n * Validate an object that we expect to be a node definition.\n * @param definition An object that we expect to be a node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateNode(definition: any, depth: number): void {\n // Every node must be valid object and have a non-empty 'type' string property.\n if (typeof definition !== \"object\" || typeof definition.type !== \"string\" || definition.type.length === 0) {\n throw new Error(\n `node definition is not an object or 'type' property is not a non-empty string at depth '${depth}'`\n );\n }\n\n // How we validate this node definition will depend on its type.\n switch (definition.type) {\n case \"action\":\n validateActionNode(definition, depth);\n break;\n\n case \"condition\":\n validateConditionNode(definition, depth);\n break;\n\n case \"wait\":\n validateWaitNode(definition, depth);\n break;\n\n case \"branch\":\n validateBranchNode(definition, depth);\n break;\n\n case \"root\":\n validateRootNode(definition, depth);\n break;\n\n case \"success\":\n validateSuccessNode(definition, depth);\n break;\n\n case \"fail\":\n validateFailNode(definition, depth);\n break;\n\n case \"flip\":\n validateFlipNode(definition, depth);\n break;\n\n case \"repeat\":\n validateRepeatNode(definition, depth);\n break;\n\n case \"retry\":\n validateRetryNode(definition, depth);\n break;\n\n case \"sequence\":\n validateSequenceNode(definition, depth);\n break;\n\n case \"selector\":\n validateSelectorNode(definition, depth);\n break;\n\n case \"parallel\":\n validateParallelNode(definition, depth);\n break;\n\n default:\n throw new Error(`unexpected node type of '${definition.type}' at depth '${depth}'`);\n }\n}\n\n/**\n * Validate any attributes for a given node definition.\n * @param definition The node definition.\n * @param depth The depth of the node in the behaviour tree definition.\n */\nfunction validateNodeAttributes(definition: any, depth: number): void {\n // Validate each of the attribute types for this node.\n [\"while\", \"until\", \"entry\", \"exit\", \"step\"].forEach((attributeName) => {\n // Attempt to grab the definition for the current attribute from the node definition.\n const attributeDefinition = definition[attributeName];\n\n // All node attributes are optional, so there is nothing to do if the current attribute is not defined.\n if (typeof attributeDefinition === \"undefined\") {\n return;\n }\n\n // The attribute definition must be an object.\n if (typeof attributeDefinition !== \"object\") {\n throw new Error(\n `expected attribute '${attributeName}' to be an object for '${definition.type}' node at depth '${depth}'`\n );\n }\n\n // The 'call' property must be defined for any attribute definition.\n if (typeof attributeDefinition.call !== \"string\" || attributeDefinition.call.length === 0) {\n throw new Error(\n `expected 'call' property for attribute '${attributeName}' to be a non-empty string for '${definition.type}' node at depth '${depth}'`\n );\n }\n\n // If any node attribute arguments have been defined then they must have been defined in an array.\n if (typeof attributeDefinition.args !== \"undefined\" && !Array.isArray(attributeDefinition.args)) {\n throw new Error(\n `expected 'args' property for attribute '${attributeName}' to be an array for '${definition.type}' node at depth '${depth}'`\n );\n }\n });\n}\n\n/**\n * Validate an object that we expect to be a root node definition.\n * @param definition An object that we expect to be a root node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateRootNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"root\") {\n throw new Error(\"expected node type of 'root' for root node\");\n }\n\n // A root node cannot be the child of another node.\n if (depth > 0) {\n throw new Error(\"a root node cannot be the child of another node\");\n }\n\n // Check that, if the root node 'id' property is defined, it is a non-empty string.\n if (typeof definition.id !== \"undefined\" && (typeof definition.id !== \"string\" || definition.id.length === 0)) {\n throw new Error(\"expected non-empty string for 'id' property if defined for root node\");\n }\n\n // A root node is a decorator node, so must have a child node defined.\n if (typeof definition.child === \"undefined\") {\n throw new Error(\"expected property 'child' to be defined for root node\");\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n\n // Validate the child node of this decorator node.\n validateNode(definition.child, depth + 1);\n}\n\n/**\n * Validate an object that we expect to be a success node definition.\n * @param definition An object that we expect to be a success node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateSuccessNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"success\") {\n throw new Error(`expected node type of 'success' for success node at depth '${depth}'`);\n }\n\n // A success node is a decorator node, so must have a child node defined.\n if (typeof definition.child === \"undefined\") {\n throw new Error(`expected property 'child' to be defined for success node at depth '${depth}'`);\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n\n // Validate the child node of this decorator node.\n validateNode(definition.child, depth + 1);\n}\n\n/**\n * Validate an object that we expect to be a fail node definition.\n * @param definition An object that we expect to be a fail node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateFailNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"fail\") {\n throw new Error(`expected node type of 'fail' for fail node at depth '${depth}'`);\n }\n\n // A fail node is a decorator node, so must have a child node defined.\n if (typeof definition.child === \"undefined\") {\n throw new Error(`expected property 'child' to be defined for fail node at depth '${depth}'`);\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n\n // Validate the child node of this decorator node.\n validateNode(definition.child, depth + 1);\n}\n\n/**\n * Validate an object that we expect to be a flip node definition.\n * @param definition An object that we expect to be a flip node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateFlipNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"flip\") {\n throw new Error(`expected node type of 'flip' for flip node at depth '${depth}'`);\n }\n\n // A flip node is a decorator node, so must have a child node defined.\n if (typeof definition.child === \"undefined\") {\n throw new Error(`expected property 'child' to be defined for flip node at depth '${depth}'`);\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n\n // Validate the child node of this decorator node.\n validateNode(definition.child, depth + 1);\n}\n\n/**\n * Validate an object that we expect to be a repeat node definition.\n * @param definition An object that we expect to be a repeat node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateRepeatNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"repeat\") {\n throw new Error(`expected node type of 'repeat' for repeat node at depth '${depth}'`);\n }\n\n // A repeat node is a decorator node, so must have a child node defined.\n if (typeof definition.child === \"undefined\") {\n throw new Error(`expected property 'child' to be defined for repeat node at depth '${depth}'`);\n }\n\n // Check whether an 'iterations' property has been defined, it may not have been if this node is to repeat indefinitely.\n if (typeof definition.iterations !== \"undefined\") {\n if (Array.isArray(definition.iterations)) {\n // Check whether any elements of the array are not integer values.\n const containsNonInteger = !!definition.iterations.find((value: unknown) => !isInteger(value));\n\n // If the 'iterations' property is an array then it MUST contain two integer values.\n if (definition.iterations.length !== 2 || containsNonInteger) {\n throw new Error(\n `expected array containing two integer values for 'iterations' property if defined for repeat node at depth '${depth}'`\n );\n }\n\n // A repeat node must have a positive min and max iterations count if they are defined.\n if (definition.iterations[0] < 0 || definition.iterations[1] < 0) {\n throw new Error(\n `expected positive minimum and maximum iterations count for 'iterations' property if defined for repeat node at depth '${depth}'`\n );\n }\n\n // A repeat node must not have a minimum iterations count that exceeds the maximum iterations count.\n if (definition.iterations[0] > definition.iterations[1]) {\n throw new Error(\n `expected minimum iterations count that does not exceed the maximum iterations count for 'iterations' property if defined for repeat node at depth '${depth}'`\n );\n }\n } else if (isInteger(definition.iterations)) {\n // A repeat node must have a positive number of iterations if defined.\n if (definition.iterations < 0) {\n throw new Error(\n `expected positive iterations count for 'iterations' property if defined for repeat node at depth '${depth}'`\n );\n }\n } else {\n throw new Error(\n `expected integer value or array containing two integer values for 'iterations' property if defined for repeat node at depth '${depth}'`\n );\n }\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n\n // Validate the child node of this decorator node.\n validateNode(definition.child, depth + 1);\n}\n\n/**\n * Validate an object that we expect to be a retry node definition.\n * @param definition An object that we expect to be a retry node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateRetryNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"retry\") {\n throw new Error(`expected node type of 'retry' for retry node at depth '${depth}'`);\n }\n\n // A retry node is a decorator node, so must have a child node defined.\n if (typeof definition.child === \"undefined\") {\n throw new Error(`expected property 'child' to be defined for retry node at depth '${depth}'`);\n }\n\n // Check whether an 'attempts' property has been defined, it may not have been if this node is to retry indefinitely.\n if (typeof definition.attempts !== \"undefined\") {\n if (Array.isArray(definition.attempts)) {\n // Check whether any elements of the array are not integer values.\n const containsNonInteger = !!definition.attempts.find((value: unknown) => !isInteger(value));\n\n // If the 'attempts' property is an array then it MUST contain two integer values.\n if (definition.attempts.length !== 2 || containsNonInteger) {\n throw new Error(\n `expected array containing two integer values for 'attempts' property if defined for retry node at depth '${depth}'`\n );\n }\n\n // A retry node must have a positive min and max attempts count if they are defined.\n if (definition.attempts[0] < 0 || definition.attempts[1] < 0) {\n throw new Error(\n `expected positive minimum and maximum attempts count for 'attempts' property if defined for retry node at depth '${depth}'`\n );\n }\n\n // A retry node must not have a minimum attempts count that exceeds the maximum attempts count.\n if (definition.attempts[0] > definition.attempts[1]) {\n throw new Error(\n `expected minimum attempts count that does not exceed the maximum attempts count for 'attempts' property if defined for retry node at depth '${depth}'`\n );\n }\n } else if (isInteger(definition.attempts)) {\n // A retry node must have a positive number of attempts if defined.\n if (definition.attempts < 0) {\n throw new Error(\n `expected positive attempts count for 'attempts' property if defined for retry node at depth '${depth}'`\n );\n }\n } else {\n throw new Error(\n `expected integer value or array containing two integer values for 'attempts' property if defined for retry node at depth '${depth}'`\n );\n }\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n\n // Validate the child node of this decorator node.\n validateNode(definition.child, depth + 1);\n}\n\n/**\n * Validate an object that we expect to be a branch node definition.\n * @param definition An object that we expect to be a branch node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateBranchNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"branch\") {\n throw new Error(`expected node type of 'branch' for branch node at depth '${depth}'`);\n }\n\n // Check that the branch node 'ref' property is defined and is a non-empty string.\n if (typeof definition.ref !== \"string\" || definition.ref.length === 0) {\n throw new Error(`expected non-empty string for 'ref' property for branch node at depth '${depth}'`);\n }\n\n // It is invalid to define guard attributes for a branch node as they should be defined on the referenced root node.\n [\"while\", \"until\"].forEach((attributeName) => {\n if (typeof definition[attributeName] !== \"undefined\") {\n throw new Error(\n `guards should not be defined for branch nodes but guard '${attributeName}' was defined for branch node at depth '${depth}'`\n );\n }\n });\n\n // It is invalid to define callback attributes for a branch node as they should be defined on the referenced root node.\n [\"entry\", \"exit\", \"step\"].forEach((attributeName) => {\n if (typeof definition[attributeName] !== \"undefined\") {\n throw new Error(\n `callbacks should not be defined for branch nodes but callback '${attributeName}' was defined for branch node at depth '${depth}'`\n );\n }\n });\n}\n\n/**\n * Validate an object that we expect to be a action node definition.\n * @param definition An object that we expect to be a action node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateActionNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"action\") {\n throw new Error(`expected node type of 'action' for action node at depth '${depth}'`);\n }\n\n // The 'call' property must be defined for a action node definition.\n if (typeof definition.call !== \"string\" || definition.call.length === 0) {\n throw new Error(`expected non-empty string for 'call' property of action node at depth '${depth}'`);\n }\n\n // If any action function arguments have been defined then they must have been defined in an array.\n if (typeof definition.args !== \"undefined\" && !Array.isArray(definition.args)) {\n throw new Error(`expected array for 'args' property if defined for action node at depth '${depth}'`);\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n}\n\n/**\n * Validate an object that we expect to be a condition node definition.\n * @param definition An object that we expect to be a condition node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateConditionNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"condition\") {\n throw new Error(`expected node type of 'condition' for condition node at depth '${depth}'`);\n }\n\n // The 'call' property must be defined for a condition node definition.\n if (typeof definition.call !== \"string\" || definition.call.length === 0) {\n throw new Error(`expected non-empty string for 'call' property of condition node at depth '${depth}'`);\n }\n\n // If any condition function arguments have been defined then they must have been defined in an array.\n if (typeof definition.args !== \"undefined\" && !Array.isArray(definition.args)) {\n throw new Error(`expected array for 'args' property if defined for condition node at depth '${depth}'`);\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n}\n\n/**\n * Validate an object that we expect to be a wait node definition.\n * @param definition An object that we expect to be a wait node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateWaitNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"wait\") {\n throw new Error(`expected node type of 'wait' for wait node at depth '${depth}'`);\n }\n\n // Check whether a 'duration' property has been defined, it may not have been if this node is to wait indefinitely.\n if (typeof definition.duration !== \"undefined\") {\n if (Array.isArray(definition.duration)) {\n // Check whether any elements of the array are not integer values.\n const containsNonInteger = !!definition.duration.find((value: unknown) => !isInteger(value));\n\n // If the 'duration' property is an array then it MUST contain two integer values.\n if (definition.duration.length !== 2 || containsNonInteger) {\n throw new Error(\n `expected array containing two integer values for 'duration' property if defined for wait node at depth '${depth}'`\n );\n }\n\n // A wait node must have a positive min and max duration value if they are defined.\n if (definition.duration[0] < 0 || definition.duration[1] < 0) {\n throw new Error(\n `expected positive minimum and maximum duration for 'duration' property if defined for wait node at depth '${depth}'`\n );\n }\n\n // A wait node must not have a minimum duration value that exceeds the maximum duration value.\n if (definition.duration[0] > definition.duration[1]) {\n throw new Error(\n `expected minimum duration value that does not exceed the maximum duration value for 'duration' property if defined for wait node at depth '${depth}'`\n );\n }\n } else if (isInteger(definition.duration)) {\n // A wait node must have a positive duration value if defined.\n if (definition.duration < 0) {\n throw new Error(\n `expected positive duration value for 'duration' property if defined for wait node at depth '${depth}'`\n );\n }\n } else {\n throw new Error(\n `expected integer value or array containing two integer values for 'duration' property if defined for wait node at depth '${depth}'`\n );\n }\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n}\n\n/**\n * Validate an object that we expect to be a sequence node definition.\n * @param definition An object that we expect to be a sequence node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateSequenceNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"sequence\") {\n throw new Error(`expected node type of 'sequence' for sequence node at depth '${depth}'`);\n }\n\n // A sequence node is a composite node, so must have a children nodes array defined.\n if (!Array.isArray(definition.children) || definition.children.length === 0) {\n throw new Error(`expected non-empty 'children' array to be defined for sequence node at depth '${depth}'`);\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n\n // Validate the child nodes of this composite node.\n definition.children.forEach((child: any) => validateNode(child, depth + 1));\n}\n\n/**\n * Validate an object that we expect to be a selector node definition.\n * @param definition An object that we expect to be a selector node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateSelectorNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"selector\") {\n throw new Error(`expected node type of 'selector' for selector node at depth '${depth}'`);\n }\n\n // A selector node is a composite node, so must have a children nodes array defined.\n if (!Array.isArray(definition.children) || definition.children.length === 0) {\n throw new Error(`expected non-empty 'children' array to be defined for selector node at depth '${depth}'`);\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n\n // Validate the child nodes of this composite node.\n definition.children.forEach((child: any) => validateNode(child, depth + 1));\n}\n\n/**\n * Validate an object that we expect to be a parallel node definition.\n * @param definition An object that we expect to be a parallel node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateParallelNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"parallel\") {\n throw new Error(`expected node type of 'parallel' for parallel node at depth '${depth}'`);\n }\n\n // A parallel node is a composite node, so must have a children nodes array defined.\n if (!Array.isArray(definition.children) || definition.children.length === 0) {\n throw new Error(`expected non-empty 'children' array to be defined for parallel node at depth '${depth}'`);\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n\n // Validate the child nodes of this composite node.\n definition.children.forEach((child: any) => validateNode(child, depth + 1));\n}\n\n/**\n * A helper function to create a failure validation result with the given error message.\n * @param errorMessage The validation failure error message.\n * @returns A failure validation result with the given error message.\n */\nfunction createValidationFailureResult(errorMessage: string): DefinitionValidationResult {\n return { succeeded: false, errorMessage };\n}\n", "import { ActionResult, Agent, GlobalFunction } from \"./Agent\";\nimport { RootNodeDefinition } from \"./BehaviourTreeDefinition\";\n\nexport type InvokerFunction = (args: any[]) => ActionResult;\n\n/**\n * A singleton used to store and lookup registered functions and subtrees.\n */\nexport default class Lookup {\n /**\n * The object holding any registered functions keyed on function name.\n */\n private static functionTable: { [key: string]: GlobalFunction } = {};\n /**\n * The object holding any registered subtree root node definitions keyed on tree name.\n */\n private static subtreeTable: { [key: string]: RootNodeDefinition } = {};\n\n /**\n * Gets the function with the specified name.\n * @param name The name of the function.\n * @returns The function with the specified name.\n */\n public static getFunc(name: string): GlobalFunction {\n return this.functionTable[name];\n }\n\n /**\n * Sets the function with the specified name for later lookup.\n * @param name The name of the function.\n * @param func The function.\n */\n public static setFunc(name: string, func: GlobalFunction): void {\n this.functionTable[name] = func;\n }\n\n /**\n * Gets the function invoker for the specified agent and function name.\n * If a function with the specified name exists on the agent object then it will\n * be returned, otherwise we will then check the registered functions for a match.\n * @param agent The agent instance that this behaviour tree is modelling behaviour for.\n * @param name The function name.\n * @returns The function invoker for the specified agent and function name.\n */\n static getFuncInvoker(agent: Agent, name: string): InvokerFunction | null {\n // Check whether the agent contains the specified function.\n const foundOnAgent = agent[name];\n if (foundOnAgent && typeof foundOnAgent === \"function\") {\n return (args: any[]): boolean | ActionResult => foundOnAgent.apply(agent, args);\n }\n\n // The agent does not contain the specified function but it may have been registered at some point.\n if (this.functionTable[name] && typeof this.functionTable[name] === \"function\") {\n return (args: any[]) => this.functionTable[name](agent, ...args.map((arg) => arg.value));\n }\n\n // We have no function to invoke.\n return null;\n }\n\n /**\n * Gets all registered subtree root node definitions.\n */\n static getSubtrees(): { [key: string]: RootNodeDefinition } {\n return this.subtreeTable;\n }\n\n /**\n * Sets the subtree with the specified name for later lookup.\n * @param name The name of the subtree.\n * @param subtree The subtree.\n */\n static setSubtree(name: string, subtree: RootNodeDefinition) {\n this.subtreeTable[name] = subtree;\n }\n\n /**\n * Removes the registered function or subtree with the specified name.\n * @param name The name of the registered function or subtree.\n */\n static remove(name: string) {\n delete this.functionTable[name];\n delete this.subtreeTable[name];\n }\n\n /**\n * Remove all registered functions and subtrees.\n */\n static empty() {\n this.functionTable = {};\n this.subtreeTable = {};\n }\n}\n", "import Node from \"../../nodes/Node\";\n\n/**\n * An exception thrown when evaluating node guard path conditions and a conditions fails.\n */\nexport default class GuardUnsatisifedException extends Error {\n /**\n * @param source The node at which a guard condition failed.\n */\n constructor(private source: Node) {\n super(\"A guard path condition has failed\");\n }\n\n /**\n * Gets whether the specified node is the node at which a guard condition failed.\n * @param node The node to check against the source node.\n * @returns Whether the specified node is the node at which a guard condition failed.\n */\n isSourceNode = (node: Node) => node === this.source;\n}\n", "import { Agent } from \"../../Agent\";\nimport Guard from \"./Guard\";\nimport Node from \"../../nodes/Node\";\nimport GuardUnsatisifedException from \"./GuardUnsatisifedException\";\n\nexport type GuardPathPart = {\n node: Node;\n guards: Guard[];\n};\n\n/**\n * Represents a path of node guards along a root-to-leaf tree path.\n */\nexport default class GuardPath {\n /**\n * @param nodes An array of objects defining a node instance -> guard link, ordered by node depth.\n */\n constructor(private nodes: GuardPathPart[]) {}\n\n /**\n * Evaluate guard conditions for all guards in the tree path, moving outwards from the root.\n * @param agent The agent, required for guard evaluation.\n * @returns An evaluation results object.\n */\n evaluate = (agent: Agent) => {\n // We need to evaluate guard conditions for nodes up the tree, moving outwards from the root.\n for (const details of this.nodes) {\n // There can be multiple guards per node.\n for (const guard of details.guards) {\n // Check whether the guard condition passes, and throw an exception if not.\n if (!guard.isSatisfied(agent)) {\n throw new GuardUnsatisifedException(details.node);\n }\n }\n }\n };\n}\n", "import { BehaviourTreeOptions } from \"../BehaviourTreeOptions\";\nimport State, { AnyState } from \"../State\";\nimport { Agent } from \"../Agent\";\nimport Leaf from \"./leaf/Leaf\";\nimport Attribute from \"../attributes/Attribute\";\nimport Entry from \"../attributes/callbacks/Entry\";\nimport Exit from \"../attributes/callbacks/Exit\";\nimport Step from \"../attributes/callbacks/Step\";\nimport Guard from \"../attributes/guards/Guard\";\nimport GuardPath from \"../attributes/guards/GuardPath\";\nimport GuardUnsatisifedException from \"../attributes/guards/GuardUnsatisifedException\";\n\n/**\n * A base node.\n */\nexport default abstract class Node {\n /**\n * The node uid.\n */\n private readonly uid: string = createNodeUid();\n /**\n * The node state.\n */\n private state: AnyState = State.READY;\n /**\n * The guard path to evaluate as part of a node update.\n */\n private guardPath: GuardPath | undefined;\n\n /**\n * @param type The node type.\n * @param attributes The node attributes.\n * @param args The node argument definitions.\n */\n constructor(private type: string, private attributes: Attribute[], private args: any[]) {}\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected abstract onUpdate(agent: Agent, options: BehaviourTreeOptions): void;\n\n /**\n * Gets the name of the node.\n */\n public abstract getName(): string;\n\n /**\n * Gets whether this node is a leaf node.\n */\n public abstract isLeafNode: () => this is Leaf;\n\n /**\n * Gets/Sets the state of the node.\n */\n getState = (): AnyState => this.state;\n setState = (value: AnyState): void => {\n this.state = value;\n };\n\n /**\n * Gets the unique id of the node.\n */\n getUid = () => this.uid;\n\n /**\n * Gets the type of the node.\n */\n getType = () => this.type;\n\n /**\n * Gets the node attributes.\n */\n getAttributes = () => this.attributes;\n\n /**\n * Gets the node arguments.\n */\n getArguments = () => this.args;\n\n /**\n * Gets the node attribute with the specified type, or null if it does not exist.\n */\n getAttribute(type: \"entry\" | \"ENTRY\"): Entry;\n getAttribute(type: \"exit\" | \"EXIT\"): Exit;\n getAttribute(type: \"step\" | \"STEP\"): Step;\n getAttribute(type: string): Attribute {\n return (\n this.getAttributes().filter((decorator) => decorator.type.toUpperCase() === type.toUpperCase())[0] || null\n );\n }\n\n /**\n * Gets the node attributes.\n */\n getGuardAttributes = (): Guard[] => this.getAttributes().filter((decorator) => decorator.isGuard()) as Guard[];\n\n /**\n * Sets the guard path to evaluate as part of a node update.\n */\n setGuardPath = (value: GuardPath) => (this.guardPath = value);\n\n /**\n * Gets whether a guard path is assigned to this node.\n */\n hasGuardPath = () => !!this.guardPath;\n\n /**\n * Gets whether this node is in the specified state.\n * @param value The value to compare to the node state.\n */\n public is(value: AnyState): boolean {\n return this.state === value;\n }\n\n /**\n * Reset the state of the node.\n */\n public reset(): void {\n this.setState(State.READY);\n }\n\n /**\n * Abort the running of this node.\n * @param agent The agent.\n */\n public abort(agent: Agent): void {\n // There is nothing to do if this node is not in the running state.\n if (!this.is(State.RUNNING)) {\n return;\n }\n\n // Reset the state of this node.\n this.reset();\n\n this.getAttribute(\"exit\")?.callAgentFunction(agent, false, true);\n }\n\n /**\n * Update the node.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n * @returns The result of the update.\n */\n public update(agent: Agent, options: BehaviourTreeOptions): void {\n // If this node is already in a 'SUCCEEDED' or 'FAILED' state then there is nothing to do.\n if (this.is(State.SUCCEEDED) || this.is(State.FAILED)) {\n return;\n }\n\n try {\n // Evaluate all of the guard path conditions for the current tree path.\n this.guardPath!.evaluate(agent);\n\n // If this node is in the READY state then call the ENTRY for this node if it exists.\n if (this.is(State.READY)) {\n this.getAttribute(\"entry\")?.callAgentFunction(agent);\n }\n\n this.getAttribute(\"step\")?.callAgentFunction(agent);\n\n // Do the actual update.\n this.onUpdate(agent, options);\n\n // If this node is now in a 'SUCCEEDED' or 'FAILED' state then call the EXIT for this node if it exists.\n if (this.is(State.SUCCEEDED) || this.is(State.FAILED)) {\n this.getAttribute(\"exit\")?.callAgentFunction(agent, this.is(State.SUCCEEDED), false);\n }\n } catch (error) {\n // If the error is a GuardUnsatisfiedException then we need to determine if this node is the source.\n if (error instanceof GuardUnsatisifedException && error.isSourceNode(this)) {\n // Abort the current node.\n this.abort(agent);\n\n // Any node that is the source of an abort will be a failed node.\n this.setState(State.FAILED);\n } else {\n throw error;\n }\n }\n }\n}\n\n/**\n * Create a randomly generated node uid.\n * @returns A randomly generated node uid.\n */\nfunction createNodeUid(): string {\n var S4 = function () {\n return (((1 + Math.random()) * 0x10000) | 0).toString(16).substring(1);\n };\n return S4() + S4() + \"-\" + S4() + \"-\" + S4() + \"-\" + S4() + \"-\" + S4() + S4() + S4();\n}\n", "import Node from \"../Node\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\n\n/**\n * A composite node that wraps child nodes.\n */\nexport default abstract class Composite extends Node {\n /**\n * @param type The node type.\n * @param attributes The node attributes.\n * @param children The child nodes.\n */\n constructor(type: string, attributes: Attribute[], protected children: Node[]) {\n super(type, attributes, []);\n }\n\n /**\n * Gets whether this node is a leaf node.\n */\n isLeafNode = () => false;\n\n /**\n * Gets the children of this node.\n */\n getChildren = () => this.children;\n\n /**\n * Reset the state of the node.\n */\n reset = () => {\n // Reset the state of this node.\n this.setState(State.READY);\n\n // Reset the state of any child nodes.\n this.getChildren().forEach((child) => child.reset());\n };\n\n /**\n * Abort the running of this node.\n * @param agent The agent.\n */\n abort = (agent: Agent) => {\n // There is nothing to do if this node is not in the running state.\n if (!this.is(State.RUNNING)) {\n return;\n }\n\n // Abort any child nodes.\n this.getChildren().forEach((child) => child.abort(agent));\n\n // Reset the state of this node.\n this.reset();\n\n this.getAttribute(\"exit\")?.callAgentFunction(agent, false, true);\n };\n}\n", "import Composite from \"./Composite\";\nimport State from \"../../State\";\nimport Node from \"../Node\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A PARALLEL node.\n * The child nodes are executed concurrently until one fails or all succeed.\n */\nexport default class Parallel extends Composite {\n /**\n * @param attributes The node attributes.\n * @param children The child nodes.\n */\n constructor(attributes: Attribute[], children: Node[]) {\n super(\"parallel\", attributes, children);\n }\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // Keep a count of the number of succeeded child nodes.\n let succeededCount = 0;\n\n let hasChildFailed = false;\n\n // Iterate over all of the children of this node.\n for (const child of this.children) {\n // If the child has never been updated or is running then we will need to update it now.\n if (child.getState() === State.READY || child.getState() === State.RUNNING) {\n // Update the child of this node.\n child.update(agent, options);\n }\n\n // If the current child has a state of 'SUCCEEDED' then we should move on to the next child.\n if (child.getState() === State.SUCCEEDED) {\n // The child node has succeeded, keep track of this to determine if all children have.\n succeededCount++;\n\n // The child node succeeded, but we have not finished checking every child node yet.\n continue;\n }\n\n // If the current child has a state of 'FAILED' then this node is also a 'FAILED' node.\n if (child.getState() === State.FAILED) {\n hasChildFailed = true;\n\n // There is no need to check the rest of the children.\n break;\n }\n\n // The node should be in the 'RUNNING' state.\n if (child.getState() !== State.RUNNING) {\n // The child node was not in an expected state.\n throw new Error(\"child node was not in an expected state.\");\n }\n }\n\n if (hasChildFailed) {\n // This node is a 'FAILED' node.\n this.setState(State.FAILED);\n\n // Abort every running child.\n for (const child of this.children) {\n if (child.getState() === State.RUNNING) {\n child.abort(agent);\n }\n }\n } else {\n // If all children have succeeded then this node has also succeeded, otherwise it is still running.\n this.setState(succeededCount === this.children.length ? State.SUCCEEDED : State.RUNNING);\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => \"PARALLEL\";\n}\n", "import Composite from \"./Composite\";\nimport Node from \"../Node\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A SELECTOR node.\n * The child nodes are executed in sequence until one succeeds or all fail.\n */\nexport default class Selector extends Composite {\n /**\n * @param attributes The node attributes.\n * @param children The child nodes.\n */\n constructor(attributes: Attribute[], protected children: Node[]) {\n super(\"selector\", attributes, children);\n }\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // Iterate over all of the children of this node.\n for (const child of this.children) {\n // If the child has never been updated or is running then we will need to update it now.\n if (child.getState() === State.READY || child.getState() === State.RUNNING) {\n // Update the child of this node.\n child.update(agent, options);\n }\n\n // If the current child has a state of 'SUCCEEDED' then this node is also a 'SUCCEEDED' node.\n if (child.getState() === State.SUCCEEDED) {\n // This node is a 'SUCCEEDED' node.\n this.setState(State.SUCCEEDED);\n\n // There is no need to check the rest of the selector nodes.\n return;\n }\n\n // If the current child has a state of 'FAILED' then we should move on to the next child.\n if (child.getState() === State.FAILED) {\n // Find out if the current child is the last one in the selector.\n // If it is then this sequence node has also failed.\n if (this.children.indexOf(child) === this.children.length - 1) {\n // This node is a 'FAILED' node.\n this.setState(State.FAILED);\n\n // There is no need to check the rest of the selector as we have completed it.\n return;\n } else {\n // The child node failed, try the next one.\n continue;\n }\n }\n\n // The node should be in the 'RUNNING' state.\n if (child.getState() === State.RUNNING) {\n // This node is a 'RUNNING' node.\n this.setState(State.RUNNING);\n\n // There is no need to check the rest of the selector as the current child is still running.\n return;\n }\n\n // The child node was not in an expected state.\n throw new Error(\"child node was not in an expected state.\");\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => \"SELECTOR\";\n}\n", "import Composite from \"./Composite\";\nimport Node from \"../Node\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A SEQUENCE node.\n * The child nodes are executed in sequence until one fails or all succeed.\n */\nexport default class Sequence extends Composite {\n /**\n * @param attributes The node attributes.\n * @param children The child nodes.\n */\n constructor(attributes: Attribute[], protected children: Node[]) {\n super(\"sequence\", attributes, children);\n }\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // Iterate over all of the children of this node.\n for (const child of this.children) {\n // If the child has never been updated or is running then we will need to update it now.\n if (child.getState() === State.READY || child.getState() === State.RUNNING) {\n // Update the child of this node.\n child.update(agent, options);\n }\n\n // If the current child has a state of 'SUCCEEDED' then we should move on to the next child.\n if (child.getState() === State.SUCCEEDED) {\n // Find out if the current child is the last one in the sequence.\n // If it is then this sequence node has also succeeded.\n if (this.children.indexOf(child) === this.children.length - 1) {\n // This node is a 'SUCCEEDED' node.\n this.setState(State.SUCCEEDED);\n\n // There is no need to check the rest of the sequence as we have completed it.\n return;\n } else {\n // The child node succeeded, but we have not finished the sequence yet.\n continue;\n }\n }\n\n // If the current child has a state of 'FAILED' then this node is also a 'FAILED' node.\n if (child.getState() === State.FAILED) {\n // This node is a 'FAILED' node.\n this.setState(State.FAILED);\n\n // There is no need to check the rest of the sequence.\n return;\n }\n\n // The node should be in the 'RUNNING' state.\n if (child.getState() === State.RUNNING) {\n // This node is a 'RUNNING' node.\n this.setState(State.RUNNING);\n\n // There is no need to check the rest of the sequence as the current child is still running.\n return;\n }\n\n // The child node was not in an expected state.\n throw new Error(\"child node was not in an expected state.\");\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => \"SEQUENCE\";\n}\n", "import createLotto from \"lotto-draw\";\n\nimport Node from \"../Node\";\nimport Composite from \"./Composite\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A LOTTO node.\n * A winning child is picked on the initial update of this node, based on ticket weighting.\n * The state of this node will match the state of the winning child.\n */\nexport default class Lotto extends Composite {\n /**\n * @param attributes The node attributes.\n * @param weights The child node weights.\n * @param children The child nodes.\n */\n constructor(attributes: Attribute[], private weights: number[] | undefined, children: Node[]) {\n super(\"lotto\", attributes, children);\n }\n\n /**\n * The child node selected to be the active one.\n */\n private selectedChild: Node | undefined;\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // If this node is in the READY state then we need to pick a winning child node.\n if (this.is(State.READY)) {\n // Create a lotto draw with which to randomly pick a child node to become the active one.\n const lottoDraw = createLotto({\n // Hook up the optional 'random' behaviour tree function option to the one used by 'lotto-draw'.\n random: options.random,\n // Pass in each child node as a participant in the lotto draw with their respective ticket count.\n participants: this.children.map((child, index) => [child, this.weights?.[index] || 1])\n });\n\n // Randomly pick a child based on ticket weighting, this will become the active child for this composite node.\n this.selectedChild = lottoDraw.draw() || undefined;\n }\n\n // If something went wrong and we don't have an active child then we should throw an error.\n if (!this.selectedChild) {\n throw new Error(\"failed to update lotto node as it has no active child\");\n }\n\n // If the selected child has never been updated or is running then we will need to update it now.\n if (this.selectedChild.getState() === State.READY || this.selectedChild.getState() === State.RUNNING) {\n this.selectedChild.update(agent, options);\n }\n\n // The state of the lotto node is the state of its selected child.\n this.setState(this.selectedChild.getState());\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => (this.weights ? `LOTTO [${this.weights.join(\",\")}]` : \"LOTTO\");\n}\n", "import Node from \"../Node\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\n\n/**\n * A decorator node that wraps a single child node.\n */\nexport default abstract class Decorator extends Node {\n /**\n * @param type The node type.\n * @param attributes The node attributes.\n * @param child The child node.\n */\n constructor(type: string, attributes: Attribute[], protected child: Node) {\n super(type, attributes, []);\n }\n\n /**\n * Gets whether this node is a leaf node.\n */\n isLeafNode = () => false;\n\n /**\n * Gets the children of this node.\n */\n getChildren = () => [this.child];\n\n /**\n * Reset the state of the node.\n */\n reset = () => {\n // Reset the state of this node.\n this.setState(State.READY);\n\n // Reset the state of the child node.\n this.child.reset();\n };\n\n /**\n * Abort the running of this node.\n * @param agent The agent.\n */\n abort = (agent: Agent) => {\n // There is nothing to do if this node is not in the running state.\n if (!this.is(State.RUNNING)) {\n return;\n }\n\n // Abort the child node.\n this.child.abort(agent);\n\n // Reset the state of this node.\n this.reset();\n\n this.getAttribute(\"exit\")?.callAgentFunction(agent, false, true);\n };\n}\n", "import Node from \"../Node\";\nimport Decorator from \"./Decorator\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A Fail node.\n * This node wraps a single child and will always move to the 'FAILED' state when the child moves to a 'SUCCEEDED' or 'FAILED' state.\n */\nexport default class Fail extends Decorator {\n /**\n * @param attributes The node attributes.\n * @param child The child node.\n */\n constructor(attributes: Attribute[], child: Node) {\n super(\"fail\", attributes, child);\n }\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // If the child has never been updated or is running then we will need to update it now.\n if (this.child.getState() === State.READY || this.child.getState() === State.RUNNING) {\n this.child.update(agent, options);\n }\n\n // The state of this node will depend in the state of its child.\n switch (this.child.getState()) {\n case State.RUNNING:\n this.setState(State.RUNNING);\n break;\n\n case State.SUCCEEDED:\n case State.FAILED:\n this.setState(State.FAILED);\n break;\n\n default:\n this.setState(State.READY);\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => \"FAIL\";\n}\n", "import Decorator from \"./Decorator\";\nimport State from \"../../State\";\nimport Node from \"../Node\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A Flip node.\n * This node wraps a single child and will flip the state of the child state.\n */\nexport default class Flip extends Decorator {\n /**\n * @param attributes The node attributes.\n * @param child The child node.\n */\n constructor(attributes: Attribute[], child: Node) {\n super(\"flip\", attributes, child);\n }\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // If the child has never been updated or is running then we will need to update it now.\n if (this.child.getState() === State.READY || this.child.getState() === State.RUNNING) {\n this.child.update(agent, options);\n }\n\n // The state of this node will depend in the state of its child.\n switch (this.child.getState()) {\n case State.RUNNING:\n this.setState(State.RUNNING);\n break;\n\n case State.SUCCEEDED:\n this.setState(State.FAILED);\n break;\n\n case State.FAILED:\n this.setState(State.SUCCEEDED);\n break;\n\n default:\n this.setState(State.READY);\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => \"FLIP\";\n}\n", "import Node from \"../Node\";\nimport Decorator from \"./Decorator\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A REPEAT node.\n * The node has a single child which can have:\n * -- A number of iterations for which to repeat the child node.\n * -- An infinite repeat loop if neither an iteration count or a condition function is defined.\n * The REPEAT node will stop and have a 'FAILED' state if its child is ever in a 'FAILED' state after an update.\n * The REPEAT node will attempt to move on to the next iteration if its child is ever in a 'SUCCEEDED' state.\n */\nexport default class Repeat extends Decorator {\n /**\n * @param attributes The node attributes.\n * @param iterations The number of iterations to repeat the child node.\n * @param iterationsMin The minimum possible number of iterations to repeat the child node.\n * @param iterationsMax The maximum possible number of iterations to repeat the child node.\n * @param child The child node.\n */\n constructor(\n attributes: Attribute[],\n private iterations: number | null,\n private iterationsMin: number | null,\n private iterationsMax: number | null,\n child: Node\n ) {\n super(\"repeat\", attributes, child);\n }\n\n /**\n * The number of target iterations to make.\n */\n private targetIterationCount: number | null = null;\n\n /**\n * The current iteration count.\n */\n private currentIterationCount: number = 0;\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // If this node is in the READY state then we need to reset the child and the target iteration count.\n if (this.is(State.READY)) {\n // Reset the child node.\n this.child.reset();\n\n // Reset the current iteration count.\n this.currentIterationCount = 0;\n\n // Set the target iteration count.\n this.setTargetIterationCount(options);\n }\n\n // Do a check to see if we can iterate. If we can then this node will move into the 'RUNNING' state.\n // If we cannot iterate then we have hit our target iteration count, which means that the node has succeeded.\n if (this.canIterate()) {\n // This node is in the running state and can do its initial iteration.\n this.setState(State.RUNNING);\n\n // We may have already completed an iteration, meaning that the child node will be in the SUCCEEDED state.\n // If this is the case then we will have to reset the child node now.\n if (this.child.getState() === State.SUCCEEDED) {\n this.child.reset();\n }\n\n // Update the child of this node.\n this.child.update(agent, options);\n\n // If the child moved into the FAILED state when we updated it then there is nothing left to do and this node has also failed.\n // If it has moved into the SUCCEEDED state then we have completed the current iteration.\n if (this.child.getState() === State.FAILED) {\n // The child has failed, meaning that this node has failed.\n this.setState(State.FAILED);\n\n return;\n } else if (this.child.getState() === State.SUCCEEDED) {\n // We have completed an iteration.\n this.currentIterationCount += 1;\n }\n } else {\n // This node is in the 'SUCCEEDED' state as we cannot iterate any more.\n this.setState(State.SUCCEEDED);\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => {\n if (this.iterations !== null) {\n return `REPEAT ${this.iterations}x`;\n } else if (this.iterationsMin !== null && this.iterationsMax !== null) {\n return `REPEAT ${this.iterationsMin}x-${this.iterationsMax}x`;\n } else {\n return \"REPEAT\";\n }\n };\n\n /**\n * Reset the state of the node.\n */\n reset = () => {\n // Reset the state of this node.\n this.setState(State.READY);\n\n // Reset the current iteration count.\n this.currentIterationCount = 0;\n\n // Reset the child node.\n this.child.reset();\n };\n\n /**\n * Gets whether an iteration can be made.\n * @returns Whether an iteration can be made.\n */\n private canIterate = () => {\n if (this.targetIterationCount !== null) {\n // We can iterate as long as we have not reached our target iteration count.\n return this.currentIterationCount < this.targetIterationCount;\n }\n\n // If neither an iteration count or a condition function were defined then we can iterate indefinitely.\n return true;\n };\n\n /**\n * Sets the target iteration count.\n * @param options The behaviour tree options object.\n */\n private setTargetIterationCount = (options: BehaviourTreeOptions) => {\n // Are we dealing with an explicit iteration count or will we be randomly picking a iteration count between the min and max iteration count.\n if (this.iterations !== null) {\n this.targetIterationCount = this.iterations;\n } else if (this.iterationsMin !== null && this.iterationsMax !== null) {\n // We will be picking a random iteration count between a min and max iteration count, if the optional 'random'\n // behaviour tree function option is defined then we will be using that, otherwise we will fall back to using Math.random.\n const random = typeof options.random === \"function\" ? options.random : Math.random;\n\n // Pick a random iteration count between a min and max iteration count.\n this.targetIterationCount = Math.floor(\n random() * (this.iterationsMax - this.iterationsMin + 1) + this.iterationsMin\n );\n } else {\n this.targetIterationCount = null;\n }\n };\n}\n", "import Node from \"../Node\";\nimport Decorator from \"./Decorator\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A RETRY node.\n * The node has a single child which can have:\n * -- A number of iterations for which to repeat the child node.\n * -- An infinite repeat loop if neither an iteration count or a condition function is defined.\n * The RETRY node will stop and have a 'SUCCEEDED' state if its child is ever in a 'SUCCEEDED' state after an update.\n * The RETRY node will attempt to move on to the next iteration if its child is ever in a 'FAILED' state.\n */\nexport default class Retry extends Decorator {\n /**\n * @param attributes The node attributes.\n * @param attempts The number of attempts to retry the child node.\n * @param attemptsMin The minimum possible number of attempts to retry the child node.\n * @param attemptsMax The maximum possible number of attempts to retry the child node.\n * @param child The child node.\n */\n constructor(\n attributes: Attribute[],\n private attempts: number | null,\n private attemptsMin: number | null,\n private attemptsMax: number | null,\n child: Node\n ) {\n super(\"retry\", attributes, child);\n }\n\n /**\n * The number of target attempts to make.\n */\n private targetAttemptCount: number | null = null;\n\n /**\n * The current attempt count.\n */\n private currentAttemptCount: number = 0;\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // If this node is in the READY state then we need to reset the child and the target attempt count.\n if (this.is(State.READY)) {\n // Reset the child node.\n this.child.reset();\n\n // Reset the current attempt count.\n this.currentAttemptCount = 0;\n\n // Set the target attempt count.\n this.setTargetAttemptCount(options);\n }\n\n // Do a check to see if we can attempt. If we can then this node will move into the 'RUNNING' state.\n // If we cannot attempt then we have hit our target attempt count, which means that the node has succeeded.\n if (this.canAttempt()) {\n // This node is in the running state and can do its initial attempt.\n this.setState(State.RUNNING);\n\n // We may have already completed an attempt, meaning that the child node will be in the FAILED state.\n // If this is the case then we will have to reset the child node now.\n if (this.child.getState() === State.FAILED) {\n this.child.reset();\n }\n\n // Update the child of this node.\n this.child.update(agent, options);\n\n // If the child moved into the SUCCEEDED state when we updated it then there is nothing left to do and this node has also succeeded.\n // If it has moved into the FAILED state then we have completed the current attempt.\n if (this.child.getState() === State.SUCCEEDED) {\n // The child has succeeded, meaning that this node has succeeded.\n this.setState(State.SUCCEEDED);\n\n return;\n } else if (this.child.getState() === State.FAILED) {\n // We have completed an attempt.\n this.currentAttemptCount += 1;\n }\n } else {\n // This node is in the 'FAILED' state as we cannot iterate any more.\n this.setState(State.FAILED);\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => {\n if (this.attempts !== null) {\n return `RETRY ${this.attempts}x`;\n } else if (this.attemptsMin !== null && this.attemptsMax !== null) {\n return `RETRY ${this.attemptsMin}x-${this.attemptsMax}x`;\n } else {\n return \"RETRY\";\n }\n };\n\n /**\n * Reset the state of the node.\n */\n reset = () => {\n // Reset the state of this node.\n this.setState(State.READY);\n\n // Reset the current attempt count.\n this.currentAttemptCount = 0;\n\n // Reset the child node.\n this.child.reset();\n };\n\n /**\n * Gets whether an attempt can be made.\n * @returns Whether an attempt can be made.\n */\n canAttempt = () => {\n if (this.targetAttemptCount !== null) {\n // We can attempt as long as we have not reached our target attempt count.\n return this.currentAttemptCount < this.targetAttemptCount;\n }\n\n // If neither an attempt count or a condition function were defined then we can attempt indefinitely.\n return true;\n };\n\n /**\n * Sets the target attempt count.\n * @param options The behaviour tree options object.\n */\n setTargetAttemptCount = (options: BehaviourTreeOptions) => {\n // Are we dealing with an explicit attempt count or will we be randomly picking an attempt count between the min and max attempt count.\n if (this.attempts !== null) {\n this.targetAttemptCount = this.attempts;\n } else if (this.attemptsMin !== null && this.attemptsMax !== null) {\n // We will be picking a random attempt count between a min and max attempt count, if the optional 'random'\n // behaviour tree function option is defined then we will be using that, otherwise we will fall back to using Math.random.\n const random = typeof options.random === \"function\" ? options.random : Math.random;\n\n // Pick a random attempt count between a min and max attempt count.\n this.targetAttemptCount = Math.floor(\n random() * (this.attemptsMax - this.attemptsMin + 1) + this.attemptsMin\n );\n } else {\n this.targetAttemptCount = null;\n }\n };\n}\n", "import Node from \"../Node\";\nimport Decorator from \"./Decorator\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A Root node.\n * The root node will have a single child.\n */\nexport default class Root extends Decorator {\n /**\n * @param attributes The node attributes.\n * @param child The child node.\n */\n constructor(attributes: Attribute[], child: Node) {\n super(\"root\", attributes, child);\n }\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // If the child has never been updated or is running then we will need to update it now.\n if (this.child.getState() === State.READY || this.child.getState() === State.RUNNING) {\n // Update the child of this node.\n this.child.update(agent, options);\n }\n\n // The state of the root node is the state of its child.\n this.setState(this.child.getState());\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => \"ROOT\";\n}\n", "import Node from \"../Node\";\nimport Decorator from \"./Decorator\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A Succeed node.\n * This node wraps a single child and will always move to the 'SUCCEEDED' state when the child moves to a 'SUCCEEDED' or 'FAILED' state.\n */\nexport default class Succeed extends Decorator {\n /**\n * @param attributes The node attributes.\n * @param child The child node.\n */\n constructor(attributes: Attribute[], child: Node) {\n super(\"succeed\", attributes, child);\n }\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // If the child has never been updated or is running then we will need to update it now.\n if (this.child.getState() === State.READY || this.child.getState() === State.RUNNING) {\n this.child.update(agent, options);\n }\n\n // The state of this node will depend in the state of its child.\n switch (this.child.getState()) {\n case State.RUNNING:\n this.setState(State.RUNNING);\n break;\n\n case State.SUCCEEDED:\n case State.FAILED:\n this.setState(State.SUCCEEDED);\n break;\n\n default:\n this.setState(State.READY);\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => \"SUCCEED\";\n}\n", "import Node from \"../Node\";\n\n/**\n * A leaf node.\n */\nexport default abstract class Leaf extends Node {\n /**\n * Gets whether this node is a leaf node.\n */\n isLeafNode = () => true;\n}\n", "import { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\nimport State, { CompleteState } from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Leaf from \"./Leaf\";\nimport Lookup from \"../../Lookup\";\nimport Attribute from \"../../attributes/Attribute\";\n\n/**\n * An Action leaf node.\n * This represents an immediate or ongoing state of behaviour.\n */\nexport default class Action extends Leaf {\n /**\n * @param attributes The node attributes.\n * @param actionName The action name.\n * @param actionArguments The array of action argument definitions.\n */\n constructor(attributes: Attribute[], private actionName: string, private actionArguments: any[]) {\n super(\"action\", attributes, actionArguments);\n }\n\n /**\n * Whether there is a pending update promise.\n */\n private isUsingUpdatePromise = false;\n\n /**\n * The finished state result of an update promise.\n */\n private updatePromiseStateResult: CompleteState | null = null;\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // If the result of this action depends on an update promise then there is nothing to do until\n // it resolves, unless there has been a value set as a result of the update promise resolving.\n if (this.isUsingUpdatePromise) {\n // Check whether the update promise has resolved with a state value.\n if (this.updatePromiseStateResult) {\n // Set the state of this node to match the state returned by the promise.\n this.setState(this.updatePromiseStateResult);\n }\n\n return;\n }\n\n // Attempt to get the invoker for the action function.\n const actionFuncInvoker = Lookup.getFuncInvoker(agent, this.actionName);\n\n // The action function should be defined.\n if (actionFuncInvoker === null) {\n throw new Error(\n `cannot update action node as the action '${this.actionName}' function is not defined on the agent and has not been registered`\n );\n }\n\n // Call the action function, the result of which may be:\n // - The finished state of this action node.\n // - A promise to return a finished node state.\n // - Undefined if the node should remain in the running state.\n const updateResult = actionFuncInvoker(this.actionArguments) as CompleteState | Promise;\n\n if (updateResult instanceof Promise) {\n updateResult.then(\n (result) => {\n // If 'isUpdatePromisePending' is null then the promise was cleared as it was resolving, probably via an abort of reset.\n if (!this.isUsingUpdatePromise) {\n return;\n }\n\n // Check to make sure the result is a valid finished state.\n if (result !== State.SUCCEEDED && result !== State.FAILED) {\n throw new Error(\n \"action node promise resolved with an invalid value, expected a State.SUCCEEDED or State.FAILED value to be returned\"\n );\n }\n\n // Set pending update promise state result to be processed on next update.\n this.updatePromiseStateResult = result;\n },\n (reason) => {\n // If 'isUpdatePromisePending' is null then the promise was cleared as it was resolving, probably via an abort of reset.\n if (!this.isUsingUpdatePromise) {\n return;\n }\n\n // Just throw whatever was returned as the rejection argument.\n throw new Error(reason);\n }\n );\n\n // This node will be in the 'RUNNING' state until the update promise resolves.\n this.setState(State.RUNNING);\n\n // We are now waiting for the promise returned by the use to resolve before we know what state this node is in.\n this.isUsingUpdatePromise = true;\n } else {\n // Validate the returned value.\n this.validateUpdateResult(updateResult);\n\n // Set the state of this node, this may be undefined, which just means that the node is still in the 'RUNNING' state.\n this.setState(updateResult || State.RUNNING);\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => this.actionName;\n\n /**\n * Reset the state of the node.\n */\n reset = () => {\n // Reset the state of this node.\n this.setState(State.READY);\n\n // There is no longer an update promise that we care about.\n this.isUsingUpdatePromise = false;\n this.updatePromiseStateResult = null;\n };\n\n /**\n * Validate the result of an update function call.\n * @param result The result of an update function call.\n */\n private validateUpdateResult = (result: CompleteState | boolean) => {\n switch (result) {\n case State.SUCCEEDED:\n case State.FAILED:\n case undefined:\n return;\n default:\n throw new Error(\n `action '${this.actionName}' 'onUpdate' returned an invalid response, expected an optional State.SUCCEEDED or State.FAILED value to be returned`\n );\n }\n };\n}\n", "import { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Leaf from \"./Leaf\";\nimport Lookup from \"../../Lookup\";\nimport Attribute from \"../../attributes/Attribute\";\n\n/**\n * A Condition leaf node.\n * This will succeed or fail immediately based on an agent predicate, without moving to the 'RUNNING' state.\n */\nexport default class Condition extends Leaf {\n /**\n * @param attributes The node attributes.\n * @param conditionName The name of the condition function.\n * @param conditionArguments The array of condition argument definitions.\n */\n constructor(attributes: Attribute[], private conditionName: string, private conditionArguments: any[]) {\n super(\"condition\", attributes, conditionArguments);\n }\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // Attempt to get the invoker for the condition function.\n const conditionFuncInvoker = Lookup.getFuncInvoker(agent, this.conditionName);\n\n // The condition function should be defined.\n if (conditionFuncInvoker === null) {\n throw new Error(\n `cannot update condition node as the condition '${this.conditionName}' function is not defined on the agent and has not been registered`\n );\n }\n\n // Call the condition function to determine the state of this node.\n this.setState(!!conditionFuncInvoker(this.conditionArguments) ? State.SUCCEEDED : State.FAILED);\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => this.conditionName;\n}\n", "import Leaf from \"./Leaf\";\nimport State from \"../../State\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { Agent } from \"../../Agent\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A WAIT node.\n * The state of this node will change to SUCCEEDED after a duration of time\n */\nexport default class Wait extends Leaf {\n /**\n * @param attributes The node attributes.\n * @param duration The duration that this node will wait to succeed in milliseconds.\n * @param durationMin The minimum possible duration in milliseconds that this node will wait to succeed.\n * @param durationMax The maximum possible duration in milliseconds that this node will wait to succeed.\n */\n constructor(\n attributes: Attribute[],\n private duration: number | null,\n private durationMin: number | null,\n private durationMax: number | null\n ) {\n super(\"wait\", attributes, []);\n }\n\n /**\n * The time in milliseconds at which this node was first updated.\n */\n private initialUpdateTime: number = 0;\n\n /**\n * The total duration in milliseconds that this node will be waiting for.\n */\n private totalDuration: number | null = null;\n\n /**\n * The duration in milliseconds that this node has been waiting for.\n */\n private waitedDuration: number = 0;\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // If this node is in the READY state then we need to set the initial update time.\n if (this.is(State.READY)) {\n // Set the initial update time.\n this.initialUpdateTime = new Date().getTime();\n\n // Set the initial waited duration.\n this.waitedDuration = 0;\n\n // Are we dealing with an explicit duration or will we be randomly picking a duration between the min and max duration.\n if (this.duration !== null) {\n this.totalDuration = this.duration;\n } else if (this.durationMin !== null && this.durationMax !== null) {\n // We will be picking a random duration between a min and max duration, if the optional 'random' behaviour tree\n // function option is defined then we will be using that, otherwise we will fall back to using Math.random.\n const random = typeof options.random === \"function\" ? options.random : Math.random;\n\n // Pick a random duration between a min and max duration.\n this.totalDuration = Math.floor(\n random() * (this.durationMax - this.durationMin + 1) + this.durationMin\n );\n } else {\n this.totalDuration = null;\n }\n\n // The node is now running until we finish waiting.\n this.setState(State.RUNNING);\n }\n\n // If we have no total duration then this wait node will wait indefinitely until it is aborted.\n if (this.totalDuration === null) {\n return;\n }\n\n // If we have a 'getDeltaTime' function defined as part of our options then we will use it to figure out how long we have waited for.\n if (typeof options.getDeltaTime === \"function\") {\n // Get the delta time.\n const deltaTime = options.getDeltaTime();\n\n // Our delta time must be a valid number and cannot be NaN.\n if (typeof deltaTime !== \"number\" || isNaN(deltaTime)) {\n throw new Error(\"The delta time must be a valid number and not NaN.\");\n }\n\n // Update the amount of time that this node has been waiting for based on the delta time.\n this.waitedDuration += deltaTime * 1000;\n } else {\n // We are not using a delta time, so we will just work out hom much time has passed since the first update.\n this.waitedDuration = new Date().getTime() - this.initialUpdateTime;\n }\n\n // Have we waited long enough?\n if (this.waitedDuration >= this.totalDuration) {\n // We have finished waiting!\n this.setState(State.SUCCEEDED);\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => {\n if (this.duration !== null) {\n return `WAIT ${this.duration}ms`;\n } else if (this.durationMin !== null && this.durationMax !== null) {\n return `WAIT ${this.durationMin}ms-${this.durationMax}ms`;\n } else {\n return \"WAIT\";\n }\n };\n}\n", "import Guard from \"./guards/Guard\";\n\nexport type AttributeDetails = {\n /** The attribute type. */\n type: string;\n\n /** The attribute arguments. */\n args: any[];\n};\n\n/**\n * A base node attribute.\n */\nexport default abstract class Attribute {\n /**\n * @param type The node attribute type.\n * @param args The array of attribute arguments.\n */\n constructor(public type: string, public args: any[]) {}\n\n /**\n * Gets the attribute details.\n */\n abstract getDetails(): TAttributeDetails;\n\n /**\n * Gets whether this attribute is a guard.\n */\n abstract isGuard: () => this is Guard;\n}\n", "import { Agent } from \"../../Agent\";\nimport Attribute, { AttributeDetails } from \"../Attribute\";\n\nexport type GuardAttributeDetails = {\n /** The name of the condition function that determines whether the guard is satisfied. */\n condition: string;\n} & AttributeDetails;\n\n/**\n * A base node guard attribute.\n */\nexport default abstract class Guard extends Attribute {\n /**\n * @param type The node attribute type.\n * @param args The array of decorator argument definitions.\n * @param condition The name of the condition function that determines whether the guard is satisfied.\n */\n constructor(type: string, args: any[], private condition: string) {\n super(type, args);\n }\n\n /**\n * Gets the name of the condition function that determines whether the guard is satisfied.\n */\n getCondition = () => this.condition;\n\n /**\n * Gets whether this attribute is a guard.\n */\n isGuard = () => true;\n\n /**\n * Gets the attribute details.\n */\n getDetails(): GuardAttributeDetails {\n return {\n type: this.type,\n args: this.args,\n condition: this.getCondition()\n };\n }\n\n /**\n * Gets whether the guard is satisfied.\n * @param agent The agent.\n * @returns Whether the guard is satisfied.\n */\n abstract isSatisfied(agent: Agent): boolean;\n}\n", "import Guard from \"./Guard\";\nimport Lookup from \"../../Lookup\";\nimport { Agent } from \"../../Agent\";\n\n/**\n * A WHILE guard which is satisfied as long as the given condition remains true.\n */\nexport default class While extends Guard {\n /**\n * @param condition The name of the condition function that determines whether the guard is satisfied.\n * @param args The array of decorator argument definitions.\n */\n constructor(condition: string, args: any[]) {\n super(\"while\", args, condition);\n }\n\n /**\n * Gets whether the guard is satisfied.\n * @param agent The agent.\n * @returns Whether the guard is satisfied.\n */\n isSatisfied = (agent: Agent) => {\n // Attempt to get the invoker for the condition function.\n const conditionFuncInvoker = Lookup.getFuncInvoker(agent, this.getCondition());\n\n // The condition function should be defined.\n if (conditionFuncInvoker === null) {\n throw new Error(\n `cannot evaluate node guard as the condition '${this.getCondition()}' function is not defined on the agent and has not been registered`\n );\n }\n\n // Call the condition function to determine whether this guard is satisfied.\n return !!conditionFuncInvoker(this.args);\n };\n}\n", "import Guard from \"./Guard\";\nimport Lookup from \"../../Lookup\";\nimport { Agent } from \"../../Agent\";\n\n/**\n * An UNTIL guard which is satisfied as long as the given condition remains false.\n */\nexport default class Until extends Guard {\n /**\n * @param condition The name of the condition function that determines whether the guard is satisfied.\n * @param args The array of decorator argument definitions.\n */\n constructor(condition: string, args: any[]) {\n super(\"until\", args, condition);\n }\n\n /**\n * Gets whether the guard is satisfied.\n * @param agent The agent.\n * @returns Whether the guard is satisfied.\n */\n isSatisfied = (agent: Agent) => {\n // Attempt to get the invoker for the condition function.\n const conditionFuncInvoker = Lookup.getFuncInvoker(agent, this.getCondition());\n\n // The condition function should be defined.\n if (conditionFuncInvoker === null) {\n throw new Error(\n `cannot evaluate node guard as the condition '${this.getCondition()}' function is not defined on the agent and has not been registered`\n );\n }\n\n // Call the condition function to determine whether this guard is satisfied.\n return !!!conditionFuncInvoker(this.args);\n };\n}\n", "import { Agent } from \"../../Agent\";\nimport Attribute, { AttributeDetails } from \"../Attribute\";\n\nexport type CallbackAttributeDetails = {\n /** The name of the agent function that is called. */\n functionName: string;\n} & AttributeDetails;\n\n/**\n * A base node callback attribute.\n */\nexport default abstract class Callback extends Attribute {\n /**\n * @param type The node attribute type.\n * @param args The array of decorator argument definitions.\n * @param functionName The name of the agent function to call.\n */\n constructor(type: string, args: any[], private functionName: string) {\n super(type, args);\n }\n\n /**\n * Gets the name of the agent function to call.\n */\n getFunctionName = () => this.functionName;\n\n /**\n * Gets whether this attribute is a guard.\n */\n isGuard = () => false;\n\n /**\n * Gets the attribute details.\n */\n getDetails(): CallbackAttributeDetails {\n return {\n type: this.type,\n args: this.args,\n functionName: this.getFunctionName()\n };\n }\n\n /**\n * Attempt to call the agent function that this callback refers to.\n * @param agent The agent.\n */\n abstract callAgentFunction: (agent: Agent, isSuccess: boolean, isAborted: boolean) => void;\n}\n", "import Callback from \"./Callback\";\nimport Lookup from \"../../Lookup\";\nimport { Agent } from \"../../Agent\";\n\n/**\n * An ENTRY callback which defines an agent function to call when the associated node is updated and moves out of running state.\n */\nexport default class Entry extends Callback {\n /**\n * @param functionName The name of the agent function to call.\n * @param args The array of callback argument definitions.\n */\n constructor(functionName: string, args: any[]) {\n super(\"entry\", args, functionName);\n }\n\n /**\n * Attempt to call the agent function that this callback refers to.\n * @param agent The agent.\n */\n callAgentFunction = (agent: Agent) => {\n // Attempt to get the invoker for the callback function.\n const callbackFuncInvoker = Lookup.getFuncInvoker(agent, this.getFunctionName());\n\n // The callback function should be defined.\n if (callbackFuncInvoker === null) {\n throw new Error(\n `cannot call entry function '${this.getFunctionName()}' as is not defined on the agent and has not been registered`\n );\n }\n\n // Call the callback function.\n callbackFuncInvoker(this.args);\n };\n}\n", "import Callback from \"./Callback\";\nimport Lookup from \"../../Lookup\";\nimport { Agent } from \"../../Agent\";\n\n/**\n * A STEP callback which defines an agent function to call when the associated node is updated.\n */\nexport default class Step extends Callback {\n /**\n * @param functionName The name of the agent function to call.\n * @param args The array of callback argument definitions.\n */\n constructor(functionName: string, args: any[]) {\n super(\"step\", args, functionName);\n }\n\n /**\n * Attempt to call the agent function that this callback refers to.\n * @param agent The agent.\n */\n callAgentFunction = (agent: Agent) => {\n // Attempt to get the invoker for the callback function.\n const callbackFuncInvoker = Lookup.getFuncInvoker(agent, this.getFunctionName());\n\n // The callback function should be defined.\n if (callbackFuncInvoker === null) {\n throw new Error(\n `cannot call step function '${this.getFunctionName()}' as is not defined on the agent and has not been registered`\n );\n }\n\n // Call the callback function.\n callbackFuncInvoker(this.args);\n };\n}\n", "import Callback from \"./Callback\";\nimport Lookup from \"../../Lookup\";\nimport { Agent } from \"../../Agent\";\n\n/**\n * An EXIT callback which defines an agent function to call when the associated node is updated and moves to a finished state or is aborted.\n */\nexport default class Exit extends Callback {\n /**\n * @param functionName The name of the agent function to call.\n * @param args The array of callback argument definitions.\n */\n constructor(functionName: string, args: any[]) {\n super(\"exit\", args, functionName);\n }\n\n /**\n * Attempt to call the agent function that this callback refers to.\n * @param agent The agent.\n * @param isSuccess Whether the decorated node was left with a success state.\n * @param isAborted Whether the decorated node was aborted.\n */\n callAgentFunction = (agent: Agent, isSuccess: boolean, isAborted: boolean) => {\n // Attempt to get the invoker for the callback function.\n const callbackFuncInvoker = Lookup.getFuncInvoker(agent, this.getFunctionName());\n\n // The callback function should be defined.\n if (callbackFuncInvoker === null) {\n throw new Error(\n `cannot call exit function '${this.getFunctionName()}' as is not defined on the agent and has not been registered`\n );\n }\n\n // Call the callback function\n callbackFuncInvoker([{ value: { succeeded: isSuccess, aborted: isAborted } }, ...this.args]);\n };\n}\n", "import { AnyNodeDefinition, RootNodeDefinition } from \"./BehaviourTreeDefinition\";\nimport GuardPath, { GuardPathPart } from \"./attributes/guards/GuardPath\";\nimport { validateBranchSubtreeLinks } from \"./BehaviourTreeDefinitionValidator\";\nimport { isInteger } from \"./BehaviourTreeDefinitionUtilities\";\nimport Node from \"./nodes/Node\";\nimport Composite from \"./nodes/composite/Composite\";\nimport Decorator from \"./nodes/decorator/Decorator\";\nimport Parallel from \"./nodes/composite/Parallel\";\nimport Selector from \"./nodes/composite/Selector\";\nimport Sequence from \"./nodes/composite/Sequence\";\nimport Lotto from \"./nodes/composite/Lotto\";\nimport Fail from \"./nodes/decorator/Fail\";\nimport Flip from \"./nodes/decorator/Flip\";\nimport Repeat from \"./nodes/decorator/Repeat\";\nimport Retry from \"./nodes/decorator/Retry\";\nimport Root from \"./nodes/decorator/Root\";\nimport Succeed from \"./nodes/decorator/Succeed\";\nimport Action from \"./nodes/leaf/Action\";\nimport Condition from \"./nodes/leaf/Condition\";\nimport Wait from \"./nodes/leaf/Wait\";\nimport Lookup from \"./Lookup\";\nimport Attribute from \"./attributes/Attribute\";\nimport While from \"./attributes/guards/While\";\nimport Until from \"./attributes/guards/Until\";\nimport Entry from \"./attributes/callbacks/Entry\";\nimport Step from \"./attributes/callbacks/Step\";\nimport Exit from \"./attributes/callbacks/Exit\";\n\n/**\n * A type representing any node instance in a behaviour tree.\n */\ntype AnyNode =\n | Root\n | Action\n | Condition\n | Wait\n | Sequence\n | Selector\n | Lotto\n | Parallel\n | Repeat\n | Retry\n | Flip\n | Succeed\n | Fail;\n\n/**\n * A type defining a mapping of root node identifiers to root node definitions.\n */\ntype RootNodeDefinitionMap = { [key: string | symbol]: RootNodeDefinition };\n\n/**\n * A symbol to use as the main root key in any root node mappings.\n */\nconst MAIN_ROOT_NODE_KEY = Symbol(\"__root__\");\n\n/**\n * Build and populate the root nodes based on the provided definition, assuming that the definition has been validated.\n * @param definition The root node definitions.\n * @returns The built and populated root node definitions.\n */\nexport default function buildRootNode(definition: RootNodeDefinition[]): Root {\n // Create a mapping of root node identifers to root node definitions, including globally registered subtree root node definitions.\n const rootNodeDefinitionMap = createRootNodeDefinitionMap(definition);\n\n // Now that we have all of our root node definitons (those part of the tree definition and those globally\n // registered) we should validate the definition. This will also double-check that we dont have any circular\n // dependencies in our branch -> subtree references and that we have no broken branch -> subtree links.\n validateBranchSubtreeLinks(definition, true);\n\n // Create our populated tree of node instances, starting with our main root node.\n const rootNode = nodeFactory(rootNodeDefinitionMap[MAIN_ROOT_NODE_KEY], rootNodeDefinitionMap) as Root;\n\n // Set a guard path on every leaf of the tree to evaluate as part of each update.\n applyLeafNodeGuardPaths(rootNode);\n\n // We only need to return the main root node.\n return rootNode;\n}\n\n/**\n * A factory function which creates a node instance based on the specified definition.\n * @param definition The node definition.\n * @param rootNodeDefinitionMap The mapping of root node identifers to root node definitions, including globally registered subtree root node definitions.\n * @returns A node instance based on the specified definition.\n */\nfunction nodeFactory(definition: AnyNodeDefinition, rootNodeDefinitionMap: RootNodeDefinitionMap): AnyNode {\n // Get the attributes for the node.\n const attributes = nodeAttributesFactory(definition);\n\n // Create the node instance based on the definition type.\n switch (definition.type) {\n case \"root\":\n return new Root(attributes, nodeFactory(definition.child, rootNodeDefinitionMap));\n\n case \"repeat\":\n let iterations: number | null = null;\n let iterationsMin: number | null = null;\n let iterationsMax: number | null = null;\n\n if (Array.isArray(definition.iterations)) {\n iterationsMin = definition.iterations[0];\n iterationsMax = definition.iterations[1];\n } else if (isInteger(definition.iterations)) {\n iterations = definition.iterations!;\n }\n\n return new Repeat(\n attributes,\n iterations,\n iterationsMin,\n iterationsMax,\n nodeFactory(definition.child, rootNodeDefinitionMap)\n );\n\n case \"retry\":\n let attempts: number | null = null;\n let attemptsMin: number | null = null;\n let attemptsMax: number | null = null;\n\n if (Array.isArray(definition.attempts)) {\n attemptsMin = definition.attempts[0];\n attemptsMax = definition.attempts[1];\n } else if (isInteger(definition.attempts)) {\n attempts = definition.attempts!;\n }\n\n return new Retry(\n attributes,\n attempts,\n attemptsMin,\n attemptsMax,\n nodeFactory(definition.child, rootNodeDefinitionMap)\n );\n\n case \"flip\":\n return new Flip(attributes, nodeFactory(definition.child, rootNodeDefinitionMap));\n\n case \"succeed\":\n return new Succeed(attributes, nodeFactory(definition.child, rootNodeDefinitionMap));\n\n case \"fail\":\n return new Fail(attributes, nodeFactory(definition.child, rootNodeDefinitionMap));\n\n case \"sequence\":\n return new Sequence(\n attributes,\n definition.children.map((child) => nodeFactory(child, rootNodeDefinitionMap))\n );\n\n case \"selector\":\n return new Selector(\n attributes,\n definition.children.map((child) => nodeFactory(child, rootNodeDefinitionMap))\n );\n\n case \"parallel\":\n return new Parallel(\n attributes,\n definition.children.map((child) => nodeFactory(child, rootNodeDefinitionMap))\n );\n\n case \"lotto\":\n return new Lotto(\n attributes,\n definition.weights,\n definition.children.map((child) => nodeFactory(child, rootNodeDefinitionMap))\n );\n\n case \"branch\":\n return nodeFactory(rootNodeDefinitionMap[definition.ref].child, rootNodeDefinitionMap);\n\n case \"action\":\n return new Action(attributes, definition.call, definition.args || []);\n\n case \"condition\":\n return new Condition(attributes, definition.call, definition.args || []);\n\n case \"wait\":\n let duration: number | null = null;\n let durationMin: number | null = null;\n let durationMax: number | null = null;\n\n if (Array.isArray(definition.duration)) {\n durationMin = definition.duration[0];\n durationMax = definition.duration[1];\n } else if (isInteger(definition.duration)) {\n duration = definition.duration!;\n }\n\n return new Wait(attributes, duration, durationMin, durationMax);\n }\n}\n\n/**\n * Creates an array of node attribute instances based on the specified node definition.\n * @param definition The node definition.\n * @returns An array of node attribute instances based on the specified node definition.\n */\nfunction nodeAttributesFactory(definition: AnyNodeDefinition): Attribute[] {\n const attributes: Attribute[] = [];\n\n if (definition.while) {\n attributes.push(new While(definition.while.call, definition.while.args ?? []));\n }\n\n if (definition.until) {\n attributes.push(new Until(definition.until.call, definition.until.args ?? []));\n }\n\n if (definition.entry) {\n attributes.push(new Entry(definition.entry.call, definition.entry.args ?? []));\n }\n\n if (definition.step) {\n attributes.push(new Step(definition.step.call, definition.step.args ?? []));\n }\n\n if (definition.exit) {\n attributes.push(new Exit(definition.exit.call, definition.exit.args ?? []));\n }\n\n return attributes;\n}\n\n/**\n * Creates a mapping of root node identifers to root node definitions, mixing in globally registered subtree root node definitions.\n * @param definition The root node definitions.\n * @returns A mapping of root node identifers to root node definitions, including globally registered subtree root node definitions.\n */\nfunction createRootNodeDefinitionMap(definition: RootNodeDefinition[]): RootNodeDefinitionMap {\n // Create a mapping of root node identifers to root node definitions.\n const rootNodeMap: RootNodeDefinitionMap = {};\n\n // Add in any registered subtree root node definitions.\n for (const [name, rootNodeDefinition] of Object.entries(Lookup.getSubtrees())) {\n // The name used when registering the subtree will be used as the root node identifier.\n rootNodeMap[name] = { ...rootNodeDefinition, id: name };\n }\n\n // Populate the map with the root node definitions that were included with the tree definition.\n // We do this after adding any registered subtrees as we want these to take presedence.\n for (const rootNodeDefinition of definition) {\n rootNodeMap[rootNodeDefinition.id ?? MAIN_ROOT_NODE_KEY] = rootNodeDefinition;\n }\n\n return rootNodeMap;\n}\n\n/**\n * Applies a guard path to every leaf of the tree to evaluate as part of each update.\n * @param root The main root tree node.\n */\nfunction applyLeafNodeGuardPaths(root: Root) {\n const nodePaths: Node[][] = [];\n\n const findLeafNodes = (path: Node[], node: Node) => {\n // Add the current node to the path.\n path = path.concat(node);\n\n // Check whether the current node is a leaf node.\n if (node.isLeafNode()) {\n nodePaths.push(path);\n } else {\n (node as Composite | Decorator).getChildren().forEach((child) => findLeafNodes(path, child));\n }\n };\n\n // Find all leaf node paths, starting from the root.\n findLeafNodes([], root);\n\n nodePaths.forEach((path) => {\n // Each node in the current path will have to be assigned a guard path, working from the root outwards.\n for (let depth = 0; depth < path.length; depth++) {\n // Get the node in the path at the current depth.\n const currentNode = path[depth];\n\n // The node may already have been assigned a guard path, if so just skip it.\n if (currentNode.hasGuardPath()) {\n continue;\n }\n\n // Create the guard path for the current node.\n const guardPath = new GuardPath(\n path\n .slice(0, depth + 1)\n .map((node) => ({ node, guards: node.getGuardAttributes() }))\n .filter((details) => details.guards.length > 0)\n );\n\n // Assign the guard path to the current node.\n currentNode.setGuardPath(guardPath);\n }\n });\n}\n", "import State, { AnyState } from \"./State\";\nimport Lookup from \"./Lookup\";\nimport Node from \"./nodes/Node\";\nimport Root from \"./nodes/decorator/Root\";\nimport Composite from \"./nodes/composite/Composite\";\nimport Decorator from \"./nodes/decorator/Decorator\";\nimport { Agent, GlobalFunction } from \"./Agent\";\nimport { CallbackAttributeDetails } from \"./attributes/callbacks/Callback\";\nimport { GuardAttributeDetails } from \"./attributes/guards/Guard\";\nimport { BehaviourTreeOptions } from \"./BehaviourTreeOptions\";\nimport { convertMDSLToJSON } from \"./mdsl/MDSLDefinitionParser\";\nimport { RootNodeDefinition } from \"./BehaviourTreeDefinition\";\nimport { validateJSONDefinition } from \"./BehaviourTreeDefinitionValidator\";\nimport buildRootNode from \"./BehaviourTreeBuilder\";\nimport { isNullOrUndefined } from \"./BehaviourTreeDefinitionUtilities\";\n\n// Purely for outside inspection of the tree.\nexport type FlattenedTreeNode = {\n id: string;\n type: string;\n caption: string;\n state: AnyState;\n guards: GuardAttributeDetails[];\n callbacks: CallbackAttributeDetails[];\n args: any[];\n parentId: string | null;\n};\n\n/**\n * A representation of a behaviour tree.\n */\nexport class BehaviourTree {\n /**\n * The main root tree node.\n */\n public readonly rootNode: Root;\n\n /**\n * Creates a new instance of the BehaviourTree class.\n * @param definition The behaviour tree definition.\n * @param agent The agent instance that this behaviour tree is modelling behaviour for.\n * @param options The behaviour tree options object.\n */\n constructor(\n definition: string | RootNodeDefinition | RootNodeDefinition[],\n private agent: Agent,\n private options: BehaviourTreeOptions = {}\n ) {\n // The tree definition must be defined.\n if (isNullOrUndefined(definition)) {\n throw new Error(\"tree definition not defined\");\n }\n\n // The agent must be defined and not null.\n if (typeof agent !== \"object\" || agent === null) {\n throw new Error(\"the agent must be an object and not null\");\n }\n\n try {\n // Parse the behaviour tree definition, create the populated tree of behaviour tree nodes, and get the root.\n this.rootNode = this._createRootNode(definition);\n } catch (exception) {\n // There was an issue in trying build and populate the behaviour tree.\n throw new Error(`error building tree: ${(exception as Error).message}`);\n }\n }\n\n /**\n * Gets whether the tree is in the RUNNING state.\n * @returns true if the tree is in the RUNNING state, otherwise false.\n */\n isRunning() {\n return this.rootNode.getState() === State.RUNNING;\n }\n\n /**\n * Gets the current tree state of SUCCEEDED, FAILED, READY or RUNNING.\n * @returns The current tree state.\n */\n getState() {\n return this.rootNode.getState();\n }\n\n /**\n * Step the tree.\n * 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.\n * 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\n * 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.\n *\n * 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.\n */\n step() {\n // If the root node has already been stepped to completion then we need to reset it.\n if (this.rootNode.getState() === State.SUCCEEDED || this.rootNode.getState() === State.FAILED) {\n this.rootNode.reset();\n }\n\n try {\n this.rootNode.update(this.agent, this.options);\n } catch (exception) {\n throw new Error(`error stepping tree: ${(exception as Error).message}`);\n }\n }\n\n /**\n * Resets the tree from the root node outwards to each nested node, giving each a state of READY.\n */\n reset() {\n this.rootNode.reset();\n }\n\n /**\n * Gets the flattened details of every node in the tree.\n * @returns The flattened details of every node in the tree.\n */\n getFlattenedNodeDetails(): FlattenedTreeNode[] {\n // Create an empty flattened array of tree nodes.\n const flattenedTreeNodes: FlattenedTreeNode[] = [];\n\n /**\n * Helper function to process a node instance and push details into the flattened tree nodes array.\n * @param node The current node.\n * @param parentUid The UID of the node parent, or null if the node is the main root node.\n */\n const processNode = (node: Node, parentUid: string | null) => {\n // Get the guard and callback attribute details for this node.\n const guards = node\n .getAttributes()\n .filter((attribute) => attribute.isGuard())\n .map((attribute) => attribute.getDetails()) as GuardAttributeDetails[];\n const callbacks = node\n .getAttributes()\n .filter((attribute) => !attribute.isGuard())\n .map((attribute) => attribute.getDetails()) as CallbackAttributeDetails[];\n\n // Push the current node into the flattened nodes array.\n flattenedTreeNodes.push({\n id: node.getUid(),\n type: node.getType(),\n caption: node.getName(),\n state: node.getState(),\n guards,\n callbacks,\n args: node.getArguments(),\n parentId: parentUid\n });\n\n // Process each of the nodes children if it is not a leaf node.\n if (!node.isLeafNode()) {\n (node as Composite | Decorator)\n .getChildren()\n .forEach((child) => processNode(child, (node as Composite | Decorator).getUid()));\n }\n };\n\n // Convert the nested node structure into a flattened array of node details.\n processNode(this.rootNode, null);\n\n return flattenedTreeNodes;\n }\n\n /**\n * Registers the action/condition/guard/callback function or subtree with the given name.\n * @param name The name of the function or subtree to register.\n * @param value The function or subtree definition to register.\n */\n static register(name: string, value: GlobalFunction | string | RootNodeDefinition) {\n // Are we going to register a action/condition/guard/callback function?\n if (typeof value === \"function\") {\n Lookup.setFunc(name, value);\n return;\n }\n\n // We are not registering an action/condition/guard/callback function, so we must be registering a subtree.\n if (typeof value === \"string\") {\n let rootNodeDefinitions: RootNodeDefinition[];\n\n // We will assume that any string passed in will be a mdsl definition.\n try {\n rootNodeDefinitions = convertMDSLToJSON(value);\n } catch (exception) {\n throw new Error(`error registering definition, invalid MDSL: ${(exception as Error).message}`);\n }\n\n // This function should only ever be called with a definition containing a single unnamed root node.\n if (rootNodeDefinitions.length != 1 || rootNodeDefinitions[0].id !== null) {\n throw new Error(\"error registering definition: expected a single unnamed root node\");\n }\n\n try {\n // We should validate the subtree as we don't want invalid subtrees available via the lookup.\n const { succeeded, errorMessage } = validateJSONDefinition(rootNodeDefinitions[0]);\n\n // Did our validation fail without error?\n if (!succeeded) {\n throw new Error(errorMessage);\n }\n } catch (exception) {\n throw new Error(`error registering definition: ${(exception as Error).message}`);\n }\n\n // Everything seems hunky-dory, register the subtree.\n Lookup.setSubtree(name, rootNodeDefinitions[0]);\n } else if (typeof value === \"object\" && !Array.isArray(value)) {\n // We will assume that any object passed in is a root node definition.\n\n try {\n // We should validate the subtree as we don't want invalid subtrees available via the lookup.\n const { succeeded, errorMessage } = validateJSONDefinition(value);\n\n // Did our validation fail without error?\n if (!succeeded) {\n throw new Error(errorMessage);\n }\n } catch (exception) {\n throw new Error(`error registering definition: ${(exception as Error).message}`);\n }\n\n // Everything seems hunky-dory, register the subtree.\n Lookup.setSubtree(name, value);\n } else {\n throw new Error(\"unexpected value, expected string mdsl definition, root node json definition or function\");\n }\n }\n\n /**\n * Unregisters the registered action/condition/guard/callback function or subtree with the given name.\n * @param name The name of the registered action/condition/guard/callback function or subtree to unregister.\n */\n static unregister(name: string): void {\n Lookup.remove(name);\n }\n\n /**\n * Unregister all registered action/condition/guard/callback functions and subtrees.\n */\n static unregisterAll(): void {\n Lookup.empty();\n }\n\n /**\n * Parses a behaviour tree definition and creates a tree of behaviour tree nodes populated at a root.\n * @param {string | RootNodeDefinition | RootNodeDefinition[]} definition The behaviour tree definition.\n * @returns The root behaviour tree node.\n */\n private _createRootNode(definition: string | RootNodeDefinition | RootNodeDefinition[]): Root {\n let resolvedDefinition: RootNodeDefinition | RootNodeDefinition[];\n\n // If the definition is a string then we will assume that it is an mdsl string which needs to be converted to a JSON definition.\n if (typeof definition === \"string\") {\n try {\n resolvedDefinition = convertMDSLToJSON(definition);\n } catch (exception) {\n throw new Error(`invalid mdsl definition: ${(exception as Error).message}`);\n }\n } else {\n // The definition is not a string, so we should assume that it is already a JSON definition.\n resolvedDefinition = definition;\n }\n\n // Build and populate the root node.\n return buildRootNode(Array.isArray(resolvedDefinition) ? resolvedDefinition : [resolvedDefinition]);\n }\n}\n"], - "mappings": "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", + "sourcesContent": ["\"use strict\";\r\nObject.defineProperty(exports, \"__esModule\", { value: true });\r\nexports.Participant = void 0;\r\n/**\r\n * A participant that holds a number of tickets.\r\n */\r\nvar Participant = /** @class */ (function () {\r\n /**\r\n * Creates an instance of the Participant class.\r\n * @param participant The actual participant.\r\n * @param tickets The number of tickets held by the participant.\r\n */\r\n function Participant(participant, tickets) {\r\n if (tickets === void 0) { tickets = 1; }\r\n this._participant = participant;\r\n this._tickets = tickets;\r\n }\r\n Object.defineProperty(Participant.prototype, \"participant\", {\r\n /** Gets the actual participant. */\r\n get: function () {\r\n return this._participant;\r\n },\r\n enumerable: false,\r\n configurable: true\r\n });\r\n Object.defineProperty(Participant.prototype, \"tickets\", {\r\n /** Gets or sets the number of tickets held by the participant. */\r\n get: function () {\r\n return this._tickets;\r\n },\r\n set: function (value) {\r\n this._tickets = value;\r\n },\r\n enumerable: false,\r\n configurable: true\r\n });\r\n return Participant;\r\n}());\r\nexports.Participant = Participant;\r\n", "\"use strict\";\r\nObject.defineProperty(exports, \"__esModule\", { value: true });\r\nexports.isNaturalNumber = exports.isNullOrUndefined = void 0;\r\n/**\r\n * Gets whether the value provided is null or undefined.\r\n * @param value The value to check.\r\n * @returns Whether the value provided is null or undefined.\r\n */\r\nfunction isNullOrUndefined(value) {\r\n return value === null || value === undefined;\r\n}\r\nexports.isNullOrUndefined = isNullOrUndefined;\r\n/**\r\n * Gets whether the value provided is a natural number.\r\n * @param value The value to check.\r\n * @returns Whether the value provided is a natural number.\r\n */\r\nfunction isNaturalNumber(value) {\r\n return typeof value === \"number\" && value >= 1 && Math.floor(value) === value;\r\n}\r\nexports.isNaturalNumber = isNaturalNumber;\r\n", "\"use strict\";\r\nObject.defineProperty(exports, \"__esModule\", { value: true });\r\nexports.Lotto = void 0;\r\nvar Participant_1 = require(\"./Participant\");\r\nvar Utilities_1 = require(\"./Utilities\");\r\n/**\r\n * Represents a lotto consisting of a number of pickable ticket-holding participants.\r\n */\r\nvar Lotto = /** @class */ (function () {\r\n /**\r\n * Creates a new instance of Lotto.\r\n * @param customRandom The custom RNG to use in place of Math.random().\r\n */\r\n function Lotto(customRandom) {\r\n /** The array of participants that are holding tickets in the lotto. */\r\n this._participants = [];\r\n this._customRandom = customRandom;\r\n }\r\n /**\r\n * Adds a participant with the specified number of tickets, or adds to the participant ticket count if the participant already holds tickets.\r\n * @param participant The participant to add or to increase the ticket count for if they already hold tickets.\r\n * @param tickets The number of tickets, defaults to 1.\r\n * @returns The Lotto instance.\r\n */\r\n Lotto.prototype.add = function (participant, tickets) {\r\n if (tickets === void 0) { tickets = 1; }\r\n // Check that we have a valid ticket count.\r\n if (!(0, Utilities_1.isNaturalNumber)(tickets)) {\r\n throw new Error(\"tickets value must be a natural number\");\r\n }\r\n // Check whether this participant has already been added.\r\n var existingParticipant = this._participants.find(function (part) { return part.participant === participant; });\r\n if (existingParticipant) {\r\n // The participant has already been added to the lotto so just add to their ticket count.\r\n existingParticipant.tickets += tickets;\r\n }\r\n else {\r\n // The participant is not part of the lotto so we should add them.\r\n this._participants.push(new Participant_1.Participant(participant, tickets));\r\n }\r\n return this;\r\n };\r\n /**\r\n * Removes the specified number of tickets for the given participant from the draw, or all tickets if a ticket number is not defined.\r\n * @param participant The participant to remove tickets for.\r\n * @param tickets The number of tickets to remove, or undefined if all tickets are to be removed.\r\n * @returns The Lotto instance.\r\n */\r\n Lotto.prototype.remove = function (participant, tickets) {\r\n // Attempt to get the existing participant.\r\n var existingParticipant = this._participants.find(function (part) { return part.participant === participant; });\r\n // There is nothing to do if the specified participant isn't even part of the lotto.\r\n if (!existingParticipant) {\r\n return this;\r\n }\r\n // Check whether a tickets value was given.\r\n if (tickets !== undefined) {\r\n // Check that we have a valid ticket count.\r\n if (!(0, Utilities_1.isNaturalNumber)(tickets)) {\r\n throw new Error(\"tickets value must be a natural number\");\r\n }\r\n existingParticipant.tickets -= tickets;\r\n // If the participant no longer holds any tickets then they should be removed.\r\n if (existingParticipant.tickets < 1) {\r\n this._participants = this._participants.filter(function (part) { return part !== existingParticipant; });\r\n }\r\n }\r\n else {\r\n // We are removing all tickets for the participant so just remove them from the lotto.\r\n this._participants = this._participants.filter(function (part) { return part !== existingParticipant; });\r\n }\r\n return this;\r\n };\r\n /**\r\n * Draw a winning ticket and return the participant that holds the ticket.\r\n * @param options The draw options.\r\n * @returns The participant that holds the winning ticket.\r\n */\r\n Lotto.prototype.draw = function (options) {\r\n if (options === void 0) { options = {}; }\r\n // If we have no participants then just return null.\r\n if (this._participants.length === 0) {\r\n return null;\r\n }\r\n var redrawable = (0, Utilities_1.isNullOrUndefined)(options.redrawable) ? true : options.redrawable;\r\n var pickable = [];\r\n this._participants.forEach(function (_a) {\r\n var participant = _a.participant, tickets = _a.tickets;\r\n for (var ticketCount = 0; ticketCount < tickets; ticketCount++) {\r\n pickable.push(participant);\r\n }\r\n });\r\n var random;\r\n // We need a random floating-point number between 0 (inclusive) and 1 to scale up to pick our winner.\r\n // If a custom random function exists then we should use that or fall back to Math.random().\r\n if (this._customRandom) {\r\n // Call our custom random function to get a random floating-point number.\r\n random = this._customRandom();\r\n // Verify that the result of calling our custom random function is a number between 0 (inclusive) and 1.\r\n if (typeof random !== \"number\" || random < 0 || random >= 1) {\r\n throw new Error(\"the 'random' function provided did not return a number between 0 (inclusive) and 1\");\r\n }\r\n }\r\n else {\r\n // No custom random function was defined so just use good ol' Math.random().\r\n random = Math.random();\r\n }\r\n // Pick a winning participant.\r\n var winner = pickable[Math.floor(random * pickable.length)];\r\n // If the ticket isn't redrawable then we should remove a ticket from the winning participants ticket count.\r\n if (!redrawable) {\r\n this.remove(winner, 1);\r\n }\r\n // Return the winning participant.\r\n return winner;\r\n };\r\n /**\r\n * Draws multiple winning tickets and return an array of the participants that hold the winning tickets.\r\n * @param tickets The number of winning tickets to draw.\r\n * @param options The draw multiple options.\r\n * @returns An array of the participants that hold the winning tickets.\r\n */\r\n Lotto.prototype.drawMultiple = function (tickets, options) {\r\n if (options === void 0) { options = {}; }\r\n var uniqueResults = (0, Utilities_1.isNullOrUndefined)(options.unique) ? false : options.unique;\r\n // Handle cases where the user has asked for zero tickets (no idea why they would do this be we should trust them).\r\n if (tickets === 0) {\r\n return [];\r\n }\r\n // Now that we know out tickets value is not zero we should check that it is a valid natural number.\r\n if (!(0, Utilities_1.isNaturalNumber)(tickets)) {\r\n throw new Error(\"tickets value must be a natural number\");\r\n }\r\n var result = [];\r\n // Keep drawing tickets until we either reach the number of required tickets or we simply run out of tickets to draw.\r\n // We can run out of tickets to draw if 'options.redrawable' is explicity 'false' or we just had no participants when 'drawMultiple' was called.\r\n while (result.length < tickets && this._participants.length > 0) {\r\n result.push(this.draw(options));\r\n }\r\n // If the 'unique' draw option is set then we need to remove duplicates from the result list.\r\n if (uniqueResults) {\r\n // Create an array to store our unique results.\r\n var unique = [];\r\n // Iterate over all of our participants (with potential duplicates) and populate our array of unique values.\r\n for (var _i = 0, result_1 = result; _i < result_1.length; _i++) {\r\n var participant = result_1[_i];\r\n if (unique.indexOf(participant) === -1) {\r\n unique.push(participant);\r\n }\r\n }\r\n result = unique;\r\n }\r\n return result;\r\n };\r\n return Lotto;\r\n}());\r\nexports.Lotto = Lotto;\r\n", "\"use strict\";\r\nObject.defineProperty(exports, \"__esModule\", { value: true });\r\nexports.createLotto = void 0;\r\nvar Lotto_1 = require(\"./Lotto\");\r\n/**\r\n * A function that creates and returns a Lotto instance.\r\n * @param participantsOrOptions An array of initial participants or options relating to the creation of a Lotto instance.\r\n * @returns A new Lotto instance.\r\n */\r\nfunction createLotto(participantsOrOptions) {\r\n // If no initial participants or lotto options were provided as an argument then we can just return a new lotto instance now.\r\n if (!participantsOrOptions) {\r\n return new Lotto_1.Lotto();\r\n }\r\n // Check whether we were provided with an array of initial participants or a lotto options object.\r\n if (Array.isArray(participantsOrOptions)) {\r\n // We are dealing with a pre-defined array of participants.\r\n var participants = participantsOrOptions;\r\n var lotto_1 = new Lotto_1.Lotto();\r\n // If the lotto participants have been defined upfront then we will need to add them all to our lotto instance now.\r\n participants.forEach(function (_a) {\r\n var participant = _a[0], tokens = _a[1];\r\n return lotto_1.add(participant, tokens);\r\n });\r\n // Return the Lotto instance.\r\n return lotto_1;\r\n }\r\n else {\r\n // We are dealing with some lotto options.\r\n var random = participantsOrOptions.random, participants = participantsOrOptions.participants;\r\n // Create a Lotto instance passing the custom RNG function to use in place of Math.random() (which could be undefined).\r\n var lotto_2 = new Lotto_1.Lotto(random);\r\n // If the lotto participants have been defined upfront as part of the options then we will need to add them all to our lotto instance now.\r\n if (participants) {\r\n participants.forEach(function (_a) {\r\n var participant = _a[0], tokens = _a[1];\r\n return lotto_2.add(participant, tokens);\r\n });\r\n }\r\n // Return the Lotto instance.\r\n return lotto_2;\r\n }\r\n}\r\nexports.createLotto = createLotto;\r\n", "\"use strict\";\r\nObject.defineProperty(exports, \"__esModule\", { value: true });\r\nvar createLotto_1 = require(\"./createLotto\");\r\nexports.default = createLotto_1.createLotto;\r\n", "import State from \"./State\";\nimport { validateDefinition } from \"./BehaviourTreeDefinitionValidator\";\nimport { convertMDSLToJSON } from \"./mdsl/MDSLDefinitionParser\";\nimport { BehaviourTree, FlattenedTreeNode } from \"./BehaviourTree\";\nimport { BehaviourTreeOptions } from \"./BehaviourTreeOptions\";\n\nexport { BehaviourTree, State, convertMDSLToJSON, validateDefinition };\nexport type { FlattenedTreeNode, BehaviourTreeOptions };\n", "/**\n * Enumeration of node state types.\n */\nexport enum State {\n READY = \"mistreevous.ready\",\n RUNNING = \"mistreevous.running\",\n SUCCEEDED = \"mistreevous.succeeded\",\n FAILED = \"mistreevous.failed\"\n}\n\nexport { State as default };\n\nexport type CompleteState = State.SUCCEEDED | State.FAILED;\nexport type AnyState = State.READY | State.RUNNING | CompleteState;\n", "import {\n NodeDefinition,\n RootNodeDefinition,\n DecoratorNodeDefinition,\n CompositeNodeDefinition,\n AnyNodeDefinition,\n BranchNodeDefinition\n} from \"./BehaviourTreeDefinition\";\n\n/**\n * A type guard function that returns true if the specified node satisfies the RootNodeDefinition type.\n * @param node The node.\n * @returns A value of true if the specified node satisfies the RootNodeDefinition type.\n */\nexport function isRootNode(node: NodeDefinition): node is RootNodeDefinition {\n return node.type === \"root\";\n}\n\n/**\n * A type guard function that returns true if the specified node satisfies the BranchNodeDefinition type.\n * @param node The node.\n * @returns A value of true if the specified node satisfies the BranchNodeDefinition type.\n */\nexport function isBranchNode(node: NodeDefinition): node is BranchNodeDefinition {\n return node.type === \"branch\";\n}\n\n/**\n * A type guard function that returns true if the specified node satisfies the NodeDefinition type.\n * @param node The node.\n * @returns A value of true if the specified node satisfies the NodeDefinition type.\n */\nexport function isLeafNode(node: NodeDefinition): node is NodeDefinition {\n return [\"branch\", \"action\", \"condition\", \"wait\"].includes(node.type);\n}\n\n/**\n * A type guard function that returns true if the specified node satisfies the DecoratorNodeDefinition type.\n * @param node The node.\n * @returns A value of true if the specified node satisfies the DecoratorNodeDefinition type.\n */\nexport function isDecoratorNode(node: NodeDefinition): node is DecoratorNodeDefinition {\n return [\"root\", \"repeat\", \"retry\", \"flip\", \"succeed\", \"fail\"].includes(node.type);\n}\n\n/**\n * A type guard function that returns true if the specified node satisfies the CompositeNodeDefinition type.\n * @param node The node.\n * @returns A value of true if the specified node satisfies the CompositeNodeDefinition type.\n */\nexport function isCompositeNode(node: NodeDefinition): node is CompositeNodeDefinition {\n return [\"sequence\", \"selector\", \"lotto\", \"parallel\"].includes(node.type);\n}\n\n/**\n * Flatten a node definition into an array of all of its nested node definitions.\n * @param nodeDefinition The node definition to flatten.\n * @returns An array of all of nested node definitions.\n */\nexport function flattenDefinition(nodeDefinition: AnyNodeDefinition): AnyNodeDefinition[] {\n const nodes: AnyNodeDefinition[] = [];\n\n const processNode = (currentNodeDefinition: AnyNodeDefinition) => {\n nodes.push(currentNodeDefinition);\n\n if (isCompositeNode(currentNodeDefinition)) {\n currentNodeDefinition.children.forEach(processNode);\n } else if (isDecoratorNode(currentNodeDefinition)) {\n processNode(currentNodeDefinition.child);\n }\n };\n\n processNode(nodeDefinition);\n\n return nodes;\n}\n\n/**\n * Determines whether the passed value is an integer.\n * @param value The value to check.\n * @returns Whether the passed value is an integer.\n */\nexport function isInteger(value: unknown): boolean {\n return typeof value === \"number\" && Math.floor(value) === value;\n}\n\n/**\n * Determines whether the passed value is null or undefined.\n * @param value The value to check.\n * @returns Whether the passed value is null or undefined.\n */\nexport function isNullOrUndefined(value: unknown): boolean {\n return typeof value === \"undefined\" || value === null;\n}\n", "/**\n * A type defining an object that holds a reference to substitued string literals parsed from the definition.\n */\nexport type StringLiteralPlaceholders = { [key: string]: string };\n\n/**\n * Pop the next raw token from the specified array of tokens and throw an error if it wasn't the expected one.\n * @param tokens The array of tokens.\n * @param expected An optional string or array or items, one of which must match the next popped token.\n * @returns The popped token.\n */\nexport function popAndCheck(tokens: string[], expected?: string | string[]): string {\n // Get and remove the next token.\n const popped = tokens.shift();\n\n // We were expecting another token but there aren't any.\n if (popped === undefined) {\n throw new Error(\"unexpected end of definition\");\n }\n\n // Do we have an expected token/tokens array?\n if (expected != undefined) {\n // Get an array of expected values, if the popped token matches any then we are all good.\n const expectedValues = typeof expected === \"string\" ? [expected] : expected;\n\n // Check whether the popped token matches at least one of our expected items.\n var tokenMatchesExpectation = expectedValues.some((item) => popped.toUpperCase() === item.toUpperCase());\n\n // Throw an error if the popped token didn't match any of our expected items.\n if (!tokenMatchesExpectation) {\n const expectationString = expectedValues.map((item) => \"'\" + item + \"'\").join(\" or \");\n throw new Error(\"unexpected token found. Expected \" + expectationString + \" but got '\" + popped + \"'\");\n }\n }\n\n // Return the popped token.\n return popped;\n}\n\n/**\n * Swaps out any node/attribute argument string literals with placeholders.\n * @param definition The definition.\n * @returns An object containing a mapping of placeholders to original string values as well as the processed definition string.\n */\nexport function substituteStringLiterals(definition: string): {\n placeholders: StringLiteralPlaceholders;\n processedDefinition: string;\n} {\n // Create an object to hold the mapping of placeholders to original string values.\n const placeholders: StringLiteralPlaceholders = {};\n\n // Replace any string literals wrapped with double quotes in our definition with placeholders to be processed later.\n const processedDefinition = definition.replace(/\\\"(\\\\.|[^\"\\\\])*\\\"/g, (match) => {\n var strippedMatch = match.substring(1, match.length - 1);\n var placeholder = Object.keys(placeholders).find((key) => placeholders[key] === strippedMatch);\n\n // If we have no existing string literal match then create a new placeholder.\n if (!placeholder) {\n placeholder = `@@${Object.keys(placeholders).length}@@`;\n placeholders[placeholder] = strippedMatch;\n }\n\n return placeholder;\n });\n\n return { placeholders, processedDefinition };\n}\n\n/**\n * Parse the tree definition into an array of raw tokens.\n * @param definition The definition.\n * @returns An array of tokens parsed from the definition.\n */\nexport function parseTokensFromDefinition(definition: string): string[] {\n // Add some space around various important characters so that they can be plucked out easier as individual tokens.\n definition = definition.replace(/\\(/g, \" ( \");\n definition = definition.replace(/\\)/g, \" ) \");\n definition = definition.replace(/\\{/g, \" { \");\n definition = definition.replace(/\\}/g, \" } \");\n definition = definition.replace(/\\]/g, \" ] \");\n definition = definition.replace(/\\[/g, \" [ \");\n definition = definition.replace(/\\,/g, \" , \");\n\n // Split the definition into raw token form and return it.\n return definition.replace(/\\s+/g, \" \").trim().split(\" \");\n}\n", "import { StringLiteralPlaceholders, popAndCheck } from \"./MDSLUtilities\";\n\n/**\n * A type representing any node function argument.\n */\ntype Argument = {\n /**\n * The argument value.\n */\n value: T;\n /**\n * The argument type, used for validation.\n */\n type: string;\n};\n\ntype NullArgument = Argument & {\n type: \"null\";\n};\n\ntype BooleanArgument = Argument & {\n type: \"boolean\";\n};\n\ntype NumberArgument = Argument & {\n type: \"number\";\n /**\n * A flag defining whether the number argument value is a valid integer. (used for validation)\n */\n isInteger: boolean;\n};\n\ntype StringPlaceholderArgument = Argument & {\n type: \"string\";\n};\n\ntype IdentifierArgument = Argument & {\n type: \"identifier\";\n};\n\n/**\n * A type representing a reference to any node function argument.\n */\ntype AnyArgument = NullArgument | BooleanArgument | NumberArgument | StringPlaceholderArgument | IdentifierArgument;\n\n/**\n * Parse an array of argument definitions from the specified tokens array.\n * @param tokens The array tokens to parse the argument definitions from.\n * @param stringArgumentPlaceholders The mapping of string literal node argument placeholders to original values.\n * @param argumentValidator The argument validator function.\n * @param validationFailedMessage The exception message to throw if argument validation fails.\n * @returns An array of argument definitions parsed from the specified tokens array.\n */\nexport function parseArgumentTokens(\n tokens: string[],\n stringArgumentPlaceholders: StringLiteralPlaceholders\n): AnyArgument[] {\n const argumentList: AnyArgument[] = [];\n\n // If the next token is not a '[' or '(' then we have no arguments to parse.\n if (![\"[\", \"(\"].includes(tokens[0])) {\n return argumentList;\n }\n\n // Any lists of arguments will always be wrapped in '[]' for node arguments or '()' for attribute arguments.\n // We are looking for a '[' or '(' opener that wraps the argument tokens and the relevant closer.\n const closingToken = popAndCheck(tokens, [\"[\", \"(\"]) === \"[\" ? \"]\" : \")\";\n\n const argumentListTokens: string[] = [];\n\n // Grab all tokens between the '[' and ']' or '(' and ')'.\n while (tokens.length && tokens[0] !== closingToken) {\n // The next token is part of our arguments list.\n argumentListTokens.push(tokens.shift()!);\n }\n\n // Validate the order of the argument tokens. Each token must either be a ',' or a single argument that satisfies the validator.\n argumentListTokens.forEach((token, index) => {\n // Get whether this token should be an actual argument.\n const shouldBeArgumentToken = !(index & 1);\n\n // If the current token should be an actual argument then validate it, otherwise it should be a ',' token.\n if (shouldBeArgumentToken) {\n // Get the argument definition.\n const argumentDefinition = getArgumentDefinition(token, stringArgumentPlaceholders);\n\n // This is a valid argument!\n argumentList.push(argumentDefinition);\n } else {\n // The current token should be a ',' token.\n if (token !== \",\") {\n throw new Error(`invalid argument list, expected ',' or ']' but got '${token}'`);\n }\n }\n });\n\n // The arguments list should terminate with a ']' or ')' token, depending on the opener.\n popAndCheck(tokens, closingToken);\n\n // Return the arguments.\n return argumentList;\n}\n\n/**\n * Gets an argument value definition.\n * @param token The argument token.\n * @param stringArgumentPlaceholders The mapping of string literal node argument placeholders to original values.\n * @returns An argument value definition.\n */\nfunction getArgumentDefinition(token: string, stringArgumentPlaceholders: StringLiteralPlaceholders): AnyArgument {\n // Check whether the token represents a null value.\n if (token === \"null\") {\n return {\n value: null,\n type: \"null\"\n } as NullArgument;\n }\n\n // Check whether the token represents a boolean value.\n if (token === \"true\" || token === \"false\") {\n return {\n value: token === \"true\",\n type: \"boolean\"\n } as BooleanArgument;\n }\n\n // Check whether the token represents a number value.\n // TODO: Relies on broken isNaN - see MDN.\n // if (!Number.isNaN(token)) {\n if (!isNaN(token as any)) {\n return {\n value: parseFloat(token),\n isInteger: parseFloat(token) === parseInt(token, 10),\n type: \"number\"\n } as NumberArgument;\n }\n\n // Check whether the token is a placeholder (e.g. @@0@@) representing a string literal.\n if (token.match(/^@@\\d+@@$/g)) {\n return {\n value: stringArgumentPlaceholders[token].replace('\\\\\"', '\"'),\n type: \"string\"\n } as StringPlaceholderArgument;\n }\n\n // The only remaining option is that the argument value is an identifier.\n return {\n value: token,\n type: \"identifier\"\n } as IdentifierArgument;\n}\n", "import { NodeAttributeDefinition } from \"../BehaviourTreeDefinition\";\nimport { parseArgumentTokens } from \"./MDSLNodeArgumentParser\";\nimport { StringLiteralPlaceholders } from \"./MDSLUtilities\";\n\n/**\n * A type defining the attribute definitions of a node.\n */\ntype NodeAttributes = {\n while?: NodeAttributeDefinition;\n until?: NodeAttributeDefinition;\n entry?: NodeAttributeDefinition;\n exit?: NodeAttributeDefinition;\n step?: NodeAttributeDefinition;\n};\n\n/**\n * Parse any node attribute definitions from the specified tokens array.\n * @param tokens The array of remaining tokens.\n * @param stringArgumentPlaceholders The mapping of string literal node argument placeholders to original values.\n * @returns An object of attribute definitions defined by any directly following tokens.\n */\nexport function parseAttributeTokens(\n tokens: string[],\n stringArgumentPlaceholders: StringLiteralPlaceholders\n): NodeAttributes {\n const nodeAttributeNames: (keyof NodeAttributes)[] = [\"while\", \"until\", \"entry\", \"exit\", \"step\"];\n\n // Create an object to hold any attributes found.\n const attributes: NodeAttributes = {};\n\n // Try to get the name of the attribute for the next token.\n let nextAttributeName = tokens[0]?.toLowerCase() as keyof NodeAttributes;\n\n // Pull attribute tokens as well as their arguments off of the tokens stack until we have no more.\n while (nodeAttributeNames.includes(nextAttributeName)) {\n // Check to make sure that we have not already created an attribute definition of this type.\n if (attributes[nextAttributeName]) {\n throw new Error(`duplicate attribute '${tokens[0].toUpperCase()}' found for node`);\n }\n\n // Remove the attribute name token from the array of tokens.\n tokens.shift();\n\n // Grab the attribute arguments, assuming the first to be an identifier.\n const [attributeCallIdentifier, ...attributeArguments] = parseArgumentTokens(\n tokens,\n stringArgumentPlaceholders\n );\n\n // The first attribute argument has to be an identifer, this will reference an agent function.\n if (attributeCallIdentifier?.type !== \"identifier\") {\n throw new Error(\"expected agent function name identifier argument for attribute\");\n }\n\n // Any attribute arguments (other than the expected call identifier) must have a type of string, number, boolean or null.\n attributeArguments\n .filter((arg) => arg.type === \"identifier\")\n .forEach((arg) => {\n throw new Error(\n `invalid attribute argument value '${arg.value}', must be string, number, boolean or null`\n );\n });\n\n // Create the attribute definition and add it to the object of attribute definitions found.\n attributes[nextAttributeName] = {\n call: attributeCallIdentifier.value,\n args: attributeArguments.map(({ value }) => value)\n };\n\n // Try to get the next attribute name token, as there could be multiple.\n nextAttributeName = tokens[0]?.toLowerCase() as keyof NodeAttributes;\n }\n\n return attributes;\n}\n", "import {\n ActionNodeDefinition,\n AnyChildNodeDefinition,\n AnyNodeDefinition,\n BranchNodeDefinition,\n ConditionNodeDefinition,\n FailNodeDefinition,\n FlipNodeDefinition,\n LottoNodeDefinition,\n ParallelNodeDefinition,\n RepeatNodeDefinition,\n RetryNodeDefinition,\n RootNodeDefinition,\n SelectorNodeDefinition,\n SequenceNodeDefinition,\n SucceedNodeDefinition,\n WaitNodeDefinition\n} from \"../BehaviourTreeDefinition\";\nimport {\n isCompositeNode,\n isDecoratorNode,\n isLeafNode,\n isNullOrUndefined,\n isRootNode\n} from \"../BehaviourTreeDefinitionUtilities\";\nimport { parseArgumentTokens } from \"./MDSLNodeArgumentParser\";\nimport { parseAttributeTokens } from \"./MDSLNodeAttributeParser\";\nimport {\n StringLiteralPlaceholders,\n parseTokensFromDefinition,\n popAndCheck,\n substituteStringLiterals\n} from \"./MDSLUtilities\";\n\n/**\n * Convert the MDSL tree definition string into an equivalent JSON definition.\n * @param definition The tree definition string as MDSL.\n * @returns The root node JSON definitions.\n */\nexport function convertMDSLToJSON(definition: string): RootNodeDefinition[] {\n // Swap out any node/attribute argument string literals with a placeholder and get a mapping of placeholders to original values as well as the processed definition.\n const { placeholders, processedDefinition } = substituteStringLiterals(definition);\n\n // Parse our definition definition string into an array of raw tokens.\n const tokens = parseTokensFromDefinition(processedDefinition);\n\n return convertTokensToJSONDefinition(tokens, placeholders);\n}\n\n/**\n * Converts the specified tree definition tokens into a JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The root node JSON definitions.\n */\nfunction convertTokensToJSONDefinition(\n tokens: string[],\n stringLiteralPlaceholders: StringLiteralPlaceholders\n): RootNodeDefinition[] {\n // There must be at least 3 tokens for the tree definition to be valid. 'ROOT', '{' and '}'.\n if (tokens.length < 3) {\n throw new Error(\"invalid token count\");\n }\n\n // We should have a matching number of '{' and '}' tokens. If not, then there are scopes that have not been properly closed.\n if (tokens.filter((token) => token === \"{\").length !== tokens.filter((token) => token === \"}\").length) {\n throw new Error(\"scope character mismatch\");\n }\n\n // Create an array of tree stack arrays where root nodes will always be at the botton and the current composite/decorator node at the top.\n // There should be an element in this array for every root node defined and every element should be an array with a root note as the first element.\n // E.g. A definition with two root nodes defined:\n // [\n // [root, lotto, sequence],\n // [root, selector]\n // ]\n const treeStacks: [Partial, ...Partial[]][] = [];\n\n // Create an array of all root node definitions that we create.\n const rootNodes: Partial[] = [];\n\n // A helper function used to push node definitions onto the tree stack.\n const pushNode = (node: AnyNodeDefinition) => {\n // If the node is a root node then we need to create a new tree stack array with the root node at the root.\n if (isRootNode(node)) {\n // We need to double-check that this root node is not the child of another node.\n // We can do this by checking whether the top tree stack is not empty (contains an existing node)\n if (treeStacks[treeStacks.length - 1]?.length) {\n throw new Error(\"a root node cannot be the child of another node\");\n }\n\n // Add the root node definition to our array of all parsed root node definitions.\n rootNodes.push(node);\n\n // Add the root node definition to the root of a new tree stack.\n treeStacks.push([node]);\n\n return;\n }\n\n // All non-root nodes should be pushed after their root nodes so handle cases\n // where we may not have any tree stacks or our top-most tree stack is empty.\n if (!treeStacks.length || !treeStacks[treeStacks.length - 1].length) {\n throw new Error(\"expected root node at base of definition\");\n }\n\n // Get the current tree stack that we are populating.\n const topTreeStack = treeStacks[treeStacks.length - 1];\n\n // Get the top-most node in the current tree stack, this will be a composite/decorator node\n // for which we will populate its children array if composite or setting its child if a decorator.\n const topTreeStackTopNode = topTreeStack[topTreeStack.length - 1] as AnyNodeDefinition;\n\n // If the top-most node in the current root stack is a composite or decorator\n // node then the current node should be added as a child of the top-most node.\n if (isCompositeNode(topTreeStackTopNode)) {\n topTreeStackTopNode.children = topTreeStackTopNode.children || [];\n topTreeStackTopNode.children.push(node);\n } else if (isDecoratorNode(topTreeStackTopNode)) {\n // If the top node already has a child node set then throw an error as a decorator should only have a single child.\n if (topTreeStackTopNode.child) {\n throw new Error(\"a decorator node must only have a single child node\");\n }\n\n topTreeStackTopNode.child = node;\n }\n\n // If the node we are adding is also a composite or decorator node, then we should push it\n // onto the current tree stack, as subsequent nodes will be added as its child/children.\n if (!isLeafNode(node)) {\n topTreeStack.push(node);\n }\n };\n\n // A helper function used to pop the top-most node definition off of the tree stack and return it.\n const popNode = (): AnyNodeDefinition | null => {\n let poppedNode: AnyNodeDefinition | null = null;\n\n // Get the current tree stack that we are populating.\n const topTreeStack = treeStacks[treeStacks.length - 1];\n\n // Pop the top-most node in the current tree stack if there is one.\n if (topTreeStack.length) {\n poppedNode = topTreeStack.pop() as AnyNodeDefinition;\n }\n\n // We don't want any empty tree stacks in our stack of tree stacks.\n if (!topTreeStack.length) {\n treeStacks.pop();\n }\n\n return poppedNode;\n };\n\n // We should keep processing the raw tokens until we run out of them.\n while (tokens.length) {\n // Grab the next token.\n const token = tokens.shift()!;\n\n // How we create the next node depends on the current raw token value.\n switch (token.toUpperCase()) {\n case \"ROOT\": {\n pushNode(createRootNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"SUCCEED\": {\n pushNode(createSucceedNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"FAIL\": {\n pushNode(createFailNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"FLIP\": {\n pushNode(createFlipNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"REPEAT\": {\n pushNode(createRepeatNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"RETRY\": {\n pushNode(createRetryNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"SEQUENCE\": {\n pushNode(createSequenceNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"SELECTOR\": {\n pushNode(createSelectorNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"PARALLEL\": {\n pushNode(createParallelNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"LOTTO\": {\n pushNode(createLottoNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"ACTION\": {\n pushNode(createActionNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"CONDITION\": {\n pushNode(createConditionNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"WAIT\": {\n pushNode(createWaitNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"BRANCH\": {\n pushNode(createBranchNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"}\": {\n // The '}' character closes the current scope and means that we have to pop a node off of the current stack.\n const poppedNode = popNode();\n\n // Now that we have a node definition we can carry out any validation that may require the node to be fully populated.\n if (poppedNode) {\n validatePoppedNode(poppedNode);\n }\n\n break;\n }\n\n default: {\n throw new Error(`unexpected token: ${token}`);\n }\n }\n }\n\n return rootNodes as RootNodeDefinition[];\n}\n\n/**\n * Creates a root node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The root node JSON definition.\n */\nfunction createRootNode(tokens: string[], stringLiteralPlaceholders: StringLiteralPlaceholders): RootNodeDefinition {\n // Create the root node definition.\n let node = {\n type: \"root\",\n id: undefined\n } as RootNodeDefinition;\n\n // Parse any node arguments, we should only have one if any which will be an identifier argument for the root identifier.\n const nodeArguments = parseArgumentTokens(tokens, stringLiteralPlaceholders);\n\n // Check whether any node arguments were defined.\n if (nodeArguments.length) {\n // We should only have one argument, if any, which will be an identifier argument for the root identifier.\n if (nodeArguments.length === 1 && nodeArguments[0].type === \"identifier\") {\n // The root node identifier will be the first and only node argument value.\n node.id = nodeArguments[0].value as string;\n } else {\n throw new Error(\"expected single root name argument\");\n }\n }\n\n // Grab any node attribute definitions and spread them into the node definition.\n node = { ...node, ...parseAttributeTokens(tokens, stringLiteralPlaceholders) };\n\n // This is a decorator node, so we expect an opening '{'.\n popAndCheck(tokens, \"{\");\n\n // Return the root node definition.\n return node;\n}\n\n/**\n * Creates a succeed node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The succeed node JSON definition.\n */\nfunction createSucceedNode(\n tokens: string[],\n stringLiteralPlaceholders: StringLiteralPlaceholders\n): SucceedNodeDefinition {\n const node = {\n type: \"succeed\",\n ...parseAttributeTokens(tokens, stringLiteralPlaceholders)\n } as SucceedNodeDefinition;\n\n // This is a decorator node, so we expect an opening '{'.\n popAndCheck(tokens, \"{\");\n\n // Return the succeed node definition.\n return node;\n}\n\n/**\n * Creates a fail node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The fail node JSON definition.\n */\nfunction createFailNode(tokens: string[], stringLiteralPlaceholders: StringLiteralPlaceholders): FailNodeDefinition {\n const node = {\n type: \"fail\",\n ...parseAttributeTokens(tokens, stringLiteralPlaceholders)\n } as FailNodeDefinition;\n\n // This is a decorator node, so we expect an opening '{'.\n popAndCheck(tokens, \"{\");\n\n // Return the fail node definition.\n return node;\n}\n\n/**\n * Creates a flip node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The flip node JSON definition.\n */\nfunction createFlipNode(tokens: string[], stringLiteralPlaceholders: StringLiteralPlaceholders): FlipNodeDefinition {\n const node = {\n type: \"flip\",\n ...parseAttributeTokens(tokens, stringLiteralPlaceholders)\n } as FlipNodeDefinition;\n\n // This is a decorator node, so we expect an opening '{'.\n popAndCheck(tokens, \"{\");\n\n // Return the flip node definition.\n return node;\n}\n\n/**\n * Creates a repeat node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The repeat node JSON definition.\n */\nfunction createRepeatNode(\n tokens: string[],\n stringLiteralPlaceholders: StringLiteralPlaceholders\n): RepeatNodeDefinition {\n let node = { type: \"repeat\" } as RepeatNodeDefinition;\n\n // Get the node arguments.\n const nodeArguments = parseArgumentTokens(tokens, stringLiteralPlaceholders);\n\n // The arguments of a repeat node are optional. We may have:\n // - No node arguments, in which case the repeat note will iterate indefinitely.\n // - One node argument which will be the explicit number of iterations to make.\n // - Two node arguments which define the min and max iteration bounds from which a random iteration count will be picked.\n if (nodeArguments.length) {\n // All repeat node arguments MUST be of type number and must be integer.\n nodeArguments\n .filter((arg) => arg.type !== \"number\" || !arg.isInteger)\n .forEach(() => {\n throw new Error(`repeat node iteration counts must be integer values`);\n });\n\n // We should have got one or two iteration counts.\n if (nodeArguments.length === 1) {\n // A static iteration count was defined.\n node.iterations = nodeArguments[0].value as number;\n\n // A repeat node must have a positive number of iterations if defined.\n if (node.iterations < 0) {\n throw new Error(\"a repeat node must have a positive number of iterations if defined\");\n }\n } else if (nodeArguments.length === 2) {\n // A minimum and maximum iteration count was defined.\n node.iterations = [nodeArguments[0].value as number, nodeArguments[1].value as number];\n\n // A repeat node must have a positive min and max iteration count if they are defined.\n if (node.iterations[0] < 0 || node.iterations[1] < 0) {\n throw new Error(\"a repeat node must have a positive minimum and maximum iteration count if defined\");\n }\n\n // A repeat node must not have an minimum iteration count that exceeds the maximum iteration count.\n if (node.iterations[0] > node.iterations[1]) {\n throw new Error(\n \"a repeat node must not have a minimum iteration count that exceeds the maximum iteration count\"\n );\n }\n } else {\n // An incorrect number of iteration counts was defined.\n throw new Error(\"invalid number of repeat node iteration count arguments defined\");\n }\n }\n\n // Grab any node attribute definitions and spread them into the node definition.\n node = { ...node, ...parseAttributeTokens(tokens, stringLiteralPlaceholders) };\n\n // This is a decorator node, so we expect an opening '{'.\n popAndCheck(tokens, \"{\");\n\n // Return the repeat node definition.\n return node;\n}\n\n/**\n * Creates a retry node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The retry node JSON definition.\n */\nfunction createRetryNode(tokens: string[], stringLiteralPlaceholders: StringLiteralPlaceholders): RetryNodeDefinition {\n let node = { type: \"retry\" } as RetryNodeDefinition;\n\n // Get the node arguments.\n const nodeArguments = parseArgumentTokens(tokens, stringLiteralPlaceholders);\n\n // The arguments of a retry node are optional. We may have:\n // - No node arguments, in which case the retry note will attempt indefinitely.\n // - One node argument which will be the explicit number of attempts to make.\n // - Two node arguments which define the min and max attempt bounds from which a random attempt count will be picked.\n if (nodeArguments.length) {\n // All retry node arguments MUST be of type number and must be integer.\n nodeArguments\n .filter((arg) => arg.type !== \"number\" || !arg.isInteger)\n .forEach(() => {\n throw new Error(`retry node attempt counts must be integer values`);\n });\n\n // We should have got one or two attempt counts.\n if (nodeArguments.length === 1) {\n // A static attempt count was defined.\n node.attempts = nodeArguments[0].value as number;\n\n // A retry node must have a positive number of attempts if defined.\n if (node.attempts < 0) {\n throw new Error(\"a retry node must have a positive number of attempts if defined\");\n }\n } else if (nodeArguments.length === 2) {\n // A minimum and maximum attempt count was defined.\n node.attempts = [nodeArguments[0].value as number, nodeArguments[1].value as number];\n\n // A retry node must have a positive min and max attempts count if they are defined.\n if (node.attempts[0] < 0 || node.attempts[1] < 0) {\n throw new Error(\"a retry node must have a positive minimum and maximum attempt count if defined\");\n }\n\n // A retry node must not have a minimum attempt count that exceeds the maximum attempt count.\n if (node.attempts[0] > node.attempts[1]) {\n throw new Error(\n \"a retry node must not have a minimum attempt count that exceeds the maximum attempt count\"\n );\n }\n } else {\n // An incorrect number of attempt counts was defined.\n throw new Error(\"invalid number of retry node attempt count arguments defined\");\n }\n }\n\n // Grab any node attribute definitions and spread them into the node definition.\n node = { ...node, ...parseAttributeTokens(tokens, stringLiteralPlaceholders) };\n\n // This is a decorator node, so we expect an opening '{'.\n popAndCheck(tokens, \"{\");\n\n // Return the retry node definition.\n return node;\n}\n\n/**\n * Creates a sequence node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The sequence node JSON definition.\n */\nfunction createSequenceNode(\n tokens: string[],\n stringLiteralPlaceholders: StringLiteralPlaceholders\n): SequenceNodeDefinition {\n const node = {\n type: \"sequence\",\n ...parseAttributeTokens(tokens, stringLiteralPlaceholders)\n } as SequenceNodeDefinition;\n\n // This is a composite node, so we expect an opening '{'.\n popAndCheck(tokens, \"{\");\n\n // Return the sequence node definition.\n return node;\n}\n\n/**\n * Creates a selector node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The selector node JSON definition.\n */\nfunction createSelectorNode(\n tokens: string[],\n stringLiteralPlaceholders: StringLiteralPlaceholders\n): SelectorNodeDefinition {\n const node = {\n type: \"selector\",\n ...parseAttributeTokens(tokens, stringLiteralPlaceholders)\n } as SelectorNodeDefinition;\n\n // This is a composite node, so we expect an opening '{'.\n popAndCheck(tokens, \"{\");\n\n // Return the selector node definition.\n return node;\n}\n\n/**\n * Creates a parallel node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The parallel node JSON definition.\n */\nfunction createParallelNode(\n tokens: string[],\n stringLiteralPlaceholders: StringLiteralPlaceholders\n): ParallelNodeDefinition {\n const node = {\n type: \"parallel\",\n ...parseAttributeTokens(tokens, stringLiteralPlaceholders)\n } as ParallelNodeDefinition;\n\n // This is a composite node, so we expect an opening '{'.\n popAndCheck(tokens, \"{\");\n\n // Return the parallel node definition.\n return node;\n}\n\n/**\n * Creates a lotto node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The lotto node JSON definition.\n */\nfunction createLottoNode(tokens: string[], stringLiteralPlaceholders: StringLiteralPlaceholders): LottoNodeDefinition {\n // If any node arguments have been defined then they must be our weights.\n const nodeArguments = parseArgumentTokens(tokens, stringLiteralPlaceholders);\n\n // All lotto node arguments MUST be of type number and must be integer.\n nodeArguments\n .filter((arg) => arg.type !== \"number\" || !arg.isInteger)\n .forEach(() => {\n throw new Error(`lotto node weight arguments must be integer values`);\n });\n\n const node = {\n type: \"lotto\",\n weights: nodeArguments.map(({ value }) => value),\n ...parseAttributeTokens(tokens, stringLiteralPlaceholders)\n } as LottoNodeDefinition;\n\n // This is a composite node, so we expect an opening '{'.\n popAndCheck(tokens, \"{\");\n\n // Return the lotto node definition.\n return node;\n}\n\n/**\n * Creates an action node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The action node JSON definition.\n */\nfunction createActionNode(\n tokens: string[],\n stringLiteralPlaceholders: StringLiteralPlaceholders\n): ActionNodeDefinition {\n // Parse any node arguments, we should have at least one which will be an identifier argument for the action name\n // and agent function to invoke for the action, all other arguments are to be passed as arguments to that function.\n const [actionNameIdentifier, ...agentFunctionArgs] = parseArgumentTokens(tokens, stringLiteralPlaceholders);\n\n // Our first argument MUST be defined and be an identifier as we require an action name argument.\n if (actionNameIdentifier?.type !== \"identifier\") {\n throw new Error(\"expected action name identifier argument\");\n }\n\n // Only the first argument should have been an identifier, all agent function arguments must be string, number, boolean or null.\n agentFunctionArgs\n .filter((arg) => arg.type === \"identifier\")\n .forEach((arg) => {\n throw new Error(\n `invalid action node argument value '${arg.value}', must be string, number, boolean or null`\n );\n });\n\n // Return the action node definition.\n return {\n type: \"action\",\n call: actionNameIdentifier.value,\n args: agentFunctionArgs.map(({ value }) => value),\n ...parseAttributeTokens(tokens, stringLiteralPlaceholders)\n };\n}\n\n/**\n * Creates a condition node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The condition node JSON definition.\n */\nfunction createConditionNode(\n tokens: string[],\n stringLiteralPlaceholders: StringLiteralPlaceholders\n): ConditionNodeDefinition {\n // Parse any node arguments, we should have at least one which will be an identifier argument for the condition name\n // and agent function to invoke for the condition, all other arguments are to be passed as arguments to that function.\n const [conditionNameIdentifier, ...agentFunctionArgs] = parseArgumentTokens(tokens, stringLiteralPlaceholders);\n\n // Our first argument MUST be defined and be an identifier as we require a condition name argument.\n if (conditionNameIdentifier?.type !== \"identifier\") {\n throw new Error(\"expected condition name identifier argument\");\n }\n\n // Only the first argument should have been an identifier, all agent function arguments must be string, number, boolean or null.\n agentFunctionArgs\n .filter((arg) => arg.type === \"identifier\")\n .forEach((arg) => {\n throw new Error(\n `invalid condition node argument value '${arg.value}', must be string, number, boolean or null`\n );\n });\n\n // Return the condition node definition.\n return {\n type: \"condition\",\n call: conditionNameIdentifier.value,\n args: agentFunctionArgs.map(({ value }) => value),\n ...parseAttributeTokens(tokens, stringLiteralPlaceholders)\n };\n}\n\n/**\n * Creates a wait node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The wait node JSON definition.\n */\nfunction createWaitNode(tokens: string[], stringLiteralPlaceholders: StringLiteralPlaceholders): WaitNodeDefinition {\n let node = { type: \"wait\" } as WaitNodeDefinition;\n\n // Get the node arguments.\n const nodeArguments = parseArgumentTokens(tokens, stringLiteralPlaceholders);\n\n // The arguments of a wait node are optional. We may have:\n // - No node arguments, in which case the wait will be indefinite until it is aborted.\n // - One node argument which will be the explicit duration of the wait.\n // - Two node arguments which define the min and max duration bounds from which a random duration will be picked.\n if (nodeArguments.length) {\n // All wait node arguments MUST be of type number and must be integer.\n nodeArguments\n .filter((arg) => arg.type !== \"number\" || !arg.isInteger)\n .forEach(() => {\n throw new Error(`wait node durations must be integer values`);\n });\n\n // We may have:\n // - One node argument which will be the explicit duration of the wait.\n // - Two node arguments which define the min and max duration bounds from which a random duration will be picked.\n // - Too many arguments, which is not valid.\n if (nodeArguments.length === 1) {\n // An explicit duration was defined.\n node.duration = nodeArguments[0].value as number;\n\n // If an explict duration was defined then it must be a positive number.\n if (node.duration < 0) {\n throw new Error(\"a wait node must have a positive duration\");\n }\n } else if (nodeArguments.length === 2) {\n // Min and max duration bounds were defined from which a random duration will be picked.\n node.duration = [nodeArguments[0].value as number, nodeArguments[1].value as number];\n\n // A wait node must have a positive min and max duration.\n if (node.duration[0] < 0 || node.duration[1] < 0) {\n throw new Error(\"a wait node must have a positive minimum and maximum duration\");\n }\n\n // A wait node must not have a minimum duration that exceeds the maximum duration.\n if (node.duration[0] > node.duration[1]) {\n throw new Error(\"a wait node must not have a minimum duration that exceeds the maximum duration\");\n }\n } else if (nodeArguments.length > 2) {\n // An incorrect number of duration arguments were defined.\n throw new Error(\"invalid number of wait node duration arguments defined\");\n }\n }\n\n // Return the wait node definition.\n return { ...node, ...parseAttributeTokens(tokens, stringLiteralPlaceholders) };\n}\n\n/**\n * Creates a branch node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The branch node JSON definition.\n */\nfunction createBranchNode(\n tokens: string[],\n stringLiteralPlaceholders: StringLiteralPlaceholders\n): BranchNodeDefinition {\n // Parse any node arguments, we should have one which will be an identifier argument for the root ref.\n const nodeArguments = parseArgumentTokens(tokens, stringLiteralPlaceholders);\n\n // We should have only a single identifer argument for a branch node, which is the root ref.\n if (nodeArguments.length !== 1 || nodeArguments[0].type !== \"identifier\") {\n throw new Error(\"expected single branch name argument\");\n }\n\n // Return the branch node definition.\n return { type: \"branch\", ref: nodeArguments[0].value };\n}\n\n/**\n * Validate a fully-populated node definition that was popped off of the tree stack.\n * @param node The popped node to validate.\n */\nfunction validatePoppedNode(node: AnyNodeDefinition): void {\n // Decorators MUST have a child defined.\n if (isDecoratorNode(node) && isNullOrUndefined(node.child)) {\n throw new Error(`a ${node.type} node must have a single child node defined`);\n }\n\n // Composites MUST have at least one child defined.\n if (isCompositeNode(node) && !node.children?.length) {\n throw new Error(`a ${node.type} node must have at least a single child node defined`);\n }\n}\n", "import { RootNodeDefinition } from \"./BehaviourTreeDefinition\";\nimport { flattenDefinition, isBranchNode, isInteger } from \"./BehaviourTreeDefinitionUtilities\";\nimport { convertMDSLToJSON } from \"./mdsl/MDSLDefinitionParser\";\n\n/**\n * An object representing the result of validating a tree definition.\n */\nexport type DefinitionValidationResult = {\n /**\n * A flag defining whether validation succeeded.\n */\n succeeded: boolean;\n /**\n * A string containing the error message if validation did not succeed.\n */\n errorMessage?: string;\n};\n\n/**\n * Validates the specified behaviour tree definition in the form of JSON or MDSL, not taking any globally registered subtrees into consideration.\n * @param definition The behaviour tree definition in the form of JSON or MDSL.\n * @returns An object representing the result of validating the given tree definition.\n */\nexport function validateDefinition(definition: any): DefinitionValidationResult {\n // The definition must be defined.\n if (definition === null || typeof definition === \"undefined\") {\n return createValidationFailureResult(\"definition is null or undefined\");\n }\n\n // We are expecting a definition in one of three different forms:\n // - A string which we will assume is MDSL and we will parse this to JSON before validation.\n // - An array which we will assume is an array of root node definitions with at least one being the primary root node (no 'id' property)\n // - An object which we will assume is the primary root node and should not have an 'id' property.\n if (typeof definition === \"string\") {\n // The definition is a string which we can assume is MDSL, so attempt to validate it.\n return validateMDSLDefinition(definition);\n } else if (typeof definition === \"object\") {\n // The definition will either be an array (of root node definitions) or an object (the single primary root node definition).\n return validateJSONDefinition(definition);\n } else {\n return createValidationFailureResult(`unexpected definition type of '${typeof definition}'`);\n }\n}\n\n/**\n * Validates the specified behaviour tree definition in the form of MDSL.\n * @param definition The behaviour tree definition in the form of MDSL.\n * @returns An object representing the result of validating the given tree definition.\n */\nexport function validateMDSLDefinition(definition: string): DefinitionValidationResult {\n let rootNodeDefinitions;\n\n // The first thing the we need to do is to attempt to convert our MDSL into JSON.\n try {\n // The definition is a string which we can assume is MDSL, so attempt to parse it to a JSON definition in the form of an array of root node definitions.\n rootNodeDefinitions = convertMDSLToJSON(definition);\n } catch (exception) {\n // We failed to parse the JSON from the MDSL, this is likely to be the result of it not being a valid MDSL string.\n return createValidationFailureResult((exception as Error).message);\n }\n\n // Unpack all of the root node definitions into arrays of main ('id' defined) and sub ('id' not defined) root node definitions.\n const mainRootNodeDefinitions = rootNodeDefinitions.filter(({ id }) => typeof id === \"undefined\");\n const subRootNodeDefinitions = rootNodeDefinitions.filter(({ id }) => typeof id === \"string\" && id.length > 0);\n\n // We should ALWAYS have exactly one root node definition without an 'id' property defined, which is out main root node definition.\n if (mainRootNodeDefinitions.length !== 1) {\n return createValidationFailureResult(\n \"expected single unnamed root node at base of definition to act as main root\"\n );\n }\n\n // We should never have duplicate 'id' properties across our sub root node definitions.\n const subRootNodeIdenitifers: string[] = [];\n for (const { id } of subRootNodeDefinitions) {\n // Have we already come across this 'id' property value?\n if (subRootNodeIdenitifers.includes(id!)) {\n return createValidationFailureResult(`multiple root nodes found with duplicate name '${id}'`);\n }\n\n subRootNodeIdenitifers.push(id!);\n }\n\n try {\n // Validate our branch -> subtree links and check for any circular dependencies, we don't care about checking for broken subtree links here.\n validateBranchSubtreeLinks(rootNodeDefinitions, false);\n } catch (exception) {\n return createValidationFailureResult((exception as Error).message);\n }\n\n // Our definition was valid!\n return { succeeded: true };\n}\n\n/**\n * Validates the specified behaviour tree definition in the form of JSON.\n * @param definition The behaviour tree definition in the form of JSON.\n * @returns An object representing the result of validating the given tree definition.\n */\nexport function validateJSONDefinition(\n definition: RootNodeDefinition | RootNodeDefinition[]\n): DefinitionValidationResult {\n // The definition will either be an array (of root node definitions) or an object (the single primary root node definition).\n const rootNodeDefinitions = Array.isArray(definition) ? definition : [definition];\n\n // Iterate over our array of root nodes and call validateNode for each, passing an initial depth of 0, wrapped in a try catch to handle validation failures.\n try {\n rootNodeDefinitions.forEach((rootNodeDefinition) => validateNode(rootNodeDefinition, 0));\n } catch (error) {\n // Handle cases where we have caught a thrown Error and return a failure result with the error message.\n if (error instanceof Error) {\n return createValidationFailureResult(error.message);\n }\n\n // No idea what happened here!\n return createValidationFailureResult(`unexpected error: ${error}`);\n }\n\n // Unpack all of the root node definitions into arrays of main ('id' defined) and sub ('id' not defined) root node definitions.\n const mainRootNodeDefinitions = rootNodeDefinitions.filter(({ id }) => typeof id === \"undefined\");\n const subRootNodeDefinitions = rootNodeDefinitions.filter(({ id }) => typeof id === \"string\" && id.length > 0);\n\n // We should ALWAYS have exactly one root node definition without an 'id' property defined, which is out main root node definition.\n if (mainRootNodeDefinitions.length !== 1) {\n return createValidationFailureResult(\n \"expected single root node without 'id' property defined to act as main root\"\n );\n }\n\n // We should never have duplicate 'id' properties across our sub root node definitions.\n const subRootNodeIdenitifers: string[] = [];\n for (const { id } of subRootNodeDefinitions) {\n // Have we already come across this 'id' property value?\n if (subRootNodeIdenitifers.includes(id!)) {\n return createValidationFailureResult(\n `multiple root nodes found with duplicate 'id' property value of '${id}'`\n );\n }\n\n subRootNodeIdenitifers.push(id!);\n }\n\n try {\n // Validate our branch -> subtree links and check for any circular dependencies, we don't care about checking for broken subtree links here.\n validateBranchSubtreeLinks(rootNodeDefinitions, false);\n } catch (exception) {\n return createValidationFailureResult((exception as Error).message);\n }\n\n // Our definition was valid!\n return { succeeded: true };\n}\n\n/**\n * Validates the branch -> subtree links across all provided root node definitions.\n * This will not consider branch nodes that reference any globally registered subtrees unless includesGlobalSubtrees\n * is set to true, in which case we will also verify that there are no broken branch -> subtree links.\n * @param rootNodeDefinitions The array of root node definitions.\n * @param includesGlobalSubtrees A flag defining whether the array includes all global subtree root node definitions.\n */\nexport function validateBranchSubtreeLinks(rootNodeDefinitions: RootNodeDefinition[], includesGlobalSubtrees: boolean) {\n // Create a mapping of root node identifiers to other root nodes that they reference via branch nodes.\n // Below is an example of a mapping that includes a circular dependency (root => a => b => c => a)\n // [{ refs: [\"a\", \"b\"] }, { id: \"a\", refs: [\"b\"] }, { id: \"b\", refs: [\"c\"] }, { id: \"c\", refs: [\"a\"] }]\n const rootNodeMappings: { id: string | undefined; refs: string[] }[] = rootNodeDefinitions.map(\n (rootNodeDefinition) => ({\n id: rootNodeDefinition.id,\n refs: flattenDefinition(rootNodeDefinition)\n .filter(isBranchNode)\n .map(({ ref }) => ref)\n })\n );\n\n // A recursive function to walk through the mappings, keeping track of which root nodes we have visited in the form of a path of root node identifiers.\n const followRefs = (mapping: { id: string | undefined; refs: string[] }, path: (string | undefined)[] = []) => {\n // Have we found a circular dependency?\n if (path.includes(mapping.id)) {\n // We found a circular dependency! Get the bad path of root node identifiers.\n const badPath = [...path, mapping.id];\n\n // Create the formatted path value. [undefined, \"a\", \"b\", \"c\", \"a\"] would be formatted as \"a -> b -> c -> a\".\n const badPathFormatted = badPath.filter((element) => !!element).join(\" => \");\n\n // No need to continue, we found a circular dependency.\n throw new Error(`circular dependency found in branch node references: ${badPathFormatted}`);\n }\n\n for (const ref of mapping.refs) {\n // Find the mapping for the root node with an identifer matching the current ref.\n const subMapping = rootNodeMappings.find(({ id }) => id === ref);\n\n // We may not have a mapping for this ref, which is normal when we aren't considering all globally registered subtrees.\n if (subMapping) {\n followRefs(subMapping, [...path, mapping.id]);\n } else if (includesGlobalSubtrees) {\n // We found a reference to a root node that doesn't exist, which is a problem seeing as the root node definitons includes all globally registered subtrees.\n throw new Error(\n mapping.id\n ? `subtree '${mapping.id}' has branch node that references root node '${ref}' which has not been defined`\n : `primary tree has branch node that references root node '${ref}' which has not been defined`\n );\n }\n }\n };\n\n // Start looking for circular dependencies and broken references from the primary root node definition.\n followRefs(rootNodeMappings.find((mapping) => typeof mapping.id === \"undefined\")!);\n}\n\n/**\n * Validate an object that we expect to be a node definition.\n * @param definition An object that we expect to be a node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateNode(definition: any, depth: number): void {\n // Every node must be valid object and have a non-empty 'type' string property.\n if (typeof definition !== \"object\" || typeof definition.type !== \"string\" || definition.type.length === 0) {\n throw new Error(\n `node definition is not an object or 'type' property is not a non-empty string at depth '${depth}'`\n );\n }\n\n // How we validate this node definition will depend on its type.\n switch (definition.type) {\n case \"action\":\n validateActionNode(definition, depth);\n break;\n\n case \"condition\":\n validateConditionNode(definition, depth);\n break;\n\n case \"wait\":\n validateWaitNode(definition, depth);\n break;\n\n case \"branch\":\n validateBranchNode(definition, depth);\n break;\n\n case \"root\":\n validateRootNode(definition, depth);\n break;\n\n case \"success\":\n validateSuccessNode(definition, depth);\n break;\n\n case \"fail\":\n validateFailNode(definition, depth);\n break;\n\n case \"flip\":\n validateFlipNode(definition, depth);\n break;\n\n case \"repeat\":\n validateRepeatNode(definition, depth);\n break;\n\n case \"retry\":\n validateRetryNode(definition, depth);\n break;\n\n case \"sequence\":\n validateSequenceNode(definition, depth);\n break;\n\n case \"selector\":\n validateSelectorNode(definition, depth);\n break;\n\n case \"parallel\":\n validateParallelNode(definition, depth);\n break;\n\n default:\n throw new Error(`unexpected node type of '${definition.type}' at depth '${depth}'`);\n }\n}\n\n/**\n * Validate any attributes for a given node definition.\n * @param definition The node definition.\n * @param depth The depth of the node in the behaviour tree definition.\n */\nfunction validateNodeAttributes(definition: any, depth: number): void {\n // Validate each of the attribute types for this node.\n [\"while\", \"until\", \"entry\", \"exit\", \"step\"].forEach((attributeName) => {\n // Attempt to grab the definition for the current attribute from the node definition.\n const attributeDefinition = definition[attributeName];\n\n // All node attributes are optional, so there is nothing to do if the current attribute is not defined.\n if (typeof attributeDefinition === \"undefined\") {\n return;\n }\n\n // The attribute definition must be an object.\n if (typeof attributeDefinition !== \"object\") {\n throw new Error(\n `expected attribute '${attributeName}' to be an object for '${definition.type}' node at depth '${depth}'`\n );\n }\n\n // The 'call' property must be defined for any attribute definition.\n if (typeof attributeDefinition.call !== \"string\" || attributeDefinition.call.length === 0) {\n throw new Error(\n `expected 'call' property for attribute '${attributeName}' to be a non-empty string for '${definition.type}' node at depth '${depth}'`\n );\n }\n\n // If any node attribute arguments have been defined then they must have been defined in an array.\n if (typeof attributeDefinition.args !== \"undefined\" && !Array.isArray(attributeDefinition.args)) {\n throw new Error(\n `expected 'args' property for attribute '${attributeName}' to be an array for '${definition.type}' node at depth '${depth}'`\n );\n }\n });\n}\n\n/**\n * Validate an object that we expect to be a root node definition.\n * @param definition An object that we expect to be a root node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateRootNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"root\") {\n throw new Error(\"expected node type of 'root' for root node\");\n }\n\n // A root node cannot be the child of another node.\n if (depth > 0) {\n throw new Error(\"a root node cannot be the child of another node\");\n }\n\n // Check that, if the root node 'id' property is defined, it is a non-empty string.\n if (typeof definition.id !== \"undefined\" && (typeof definition.id !== \"string\" || definition.id.length === 0)) {\n throw new Error(\"expected non-empty string for 'id' property if defined for root node\");\n }\n\n // A root node is a decorator node, so must have a child node defined.\n if (typeof definition.child === \"undefined\") {\n throw new Error(\"expected property 'child' to be defined for root node\");\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n\n // Validate the child node of this decorator node.\n validateNode(definition.child, depth + 1);\n}\n\n/**\n * Validate an object that we expect to be a success node definition.\n * @param definition An object that we expect to be a success node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateSuccessNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"success\") {\n throw new Error(`expected node type of 'success' for success node at depth '${depth}'`);\n }\n\n // A success node is a decorator node, so must have a child node defined.\n if (typeof definition.child === \"undefined\") {\n throw new Error(`expected property 'child' to be defined for success node at depth '${depth}'`);\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n\n // Validate the child node of this decorator node.\n validateNode(definition.child, depth + 1);\n}\n\n/**\n * Validate an object that we expect to be a fail node definition.\n * @param definition An object that we expect to be a fail node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateFailNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"fail\") {\n throw new Error(`expected node type of 'fail' for fail node at depth '${depth}'`);\n }\n\n // A fail node is a decorator node, so must have a child node defined.\n if (typeof definition.child === \"undefined\") {\n throw new Error(`expected property 'child' to be defined for fail node at depth '${depth}'`);\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n\n // Validate the child node of this decorator node.\n validateNode(definition.child, depth + 1);\n}\n\n/**\n * Validate an object that we expect to be a flip node definition.\n * @param definition An object that we expect to be a flip node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateFlipNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"flip\") {\n throw new Error(`expected node type of 'flip' for flip node at depth '${depth}'`);\n }\n\n // A flip node is a decorator node, so must have a child node defined.\n if (typeof definition.child === \"undefined\") {\n throw new Error(`expected property 'child' to be defined for flip node at depth '${depth}'`);\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n\n // Validate the child node of this decorator node.\n validateNode(definition.child, depth + 1);\n}\n\n/**\n * Validate an object that we expect to be a repeat node definition.\n * @param definition An object that we expect to be a repeat node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateRepeatNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"repeat\") {\n throw new Error(`expected node type of 'repeat' for repeat node at depth '${depth}'`);\n }\n\n // A repeat node is a decorator node, so must have a child node defined.\n if (typeof definition.child === \"undefined\") {\n throw new Error(`expected property 'child' to be defined for repeat node at depth '${depth}'`);\n }\n\n // Check whether an 'iterations' property has been defined, it may not have been if this node is to repeat indefinitely.\n if (typeof definition.iterations !== \"undefined\") {\n if (Array.isArray(definition.iterations)) {\n // Check whether any elements of the array are not integer values.\n const containsNonInteger = !!definition.iterations.find((value: unknown) => !isInteger(value));\n\n // If the 'iterations' property is an array then it MUST contain two integer values.\n if (definition.iterations.length !== 2 || containsNonInteger) {\n throw new Error(\n `expected array containing two integer values for 'iterations' property if defined for repeat node at depth '${depth}'`\n );\n }\n\n // A repeat node must have a positive min and max iterations count if they are defined.\n if (definition.iterations[0] < 0 || definition.iterations[1] < 0) {\n throw new Error(\n `expected positive minimum and maximum iterations count for 'iterations' property if defined for repeat node at depth '${depth}'`\n );\n }\n\n // A repeat node must not have a minimum iterations count that exceeds the maximum iterations count.\n if (definition.iterations[0] > definition.iterations[1]) {\n throw new Error(\n `expected minimum iterations count that does not exceed the maximum iterations count for 'iterations' property if defined for repeat node at depth '${depth}'`\n );\n }\n } else if (isInteger(definition.iterations)) {\n // A repeat node must have a positive number of iterations if defined.\n if (definition.iterations < 0) {\n throw new Error(\n `expected positive iterations count for 'iterations' property if defined for repeat node at depth '${depth}'`\n );\n }\n } else {\n throw new Error(\n `expected integer value or array containing two integer values for 'iterations' property if defined for repeat node at depth '${depth}'`\n );\n }\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n\n // Validate the child node of this decorator node.\n validateNode(definition.child, depth + 1);\n}\n\n/**\n * Validate an object that we expect to be a retry node definition.\n * @param definition An object that we expect to be a retry node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateRetryNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"retry\") {\n throw new Error(`expected node type of 'retry' for retry node at depth '${depth}'`);\n }\n\n // A retry node is a decorator node, so must have a child node defined.\n if (typeof definition.child === \"undefined\") {\n throw new Error(`expected property 'child' to be defined for retry node at depth '${depth}'`);\n }\n\n // Check whether an 'attempts' property has been defined, it may not have been if this node is to retry indefinitely.\n if (typeof definition.attempts !== \"undefined\") {\n if (Array.isArray(definition.attempts)) {\n // Check whether any elements of the array are not integer values.\n const containsNonInteger = !!definition.attempts.find((value: unknown) => !isInteger(value));\n\n // If the 'attempts' property is an array then it MUST contain two integer values.\n if (definition.attempts.length !== 2 || containsNonInteger) {\n throw new Error(\n `expected array containing two integer values for 'attempts' property if defined for retry node at depth '${depth}'`\n );\n }\n\n // A retry node must have a positive min and max attempts count if they are defined.\n if (definition.attempts[0] < 0 || definition.attempts[1] < 0) {\n throw new Error(\n `expected positive minimum and maximum attempts count for 'attempts' property if defined for retry node at depth '${depth}'`\n );\n }\n\n // A retry node must not have a minimum attempts count that exceeds the maximum attempts count.\n if (definition.attempts[0] > definition.attempts[1]) {\n throw new Error(\n `expected minimum attempts count that does not exceed the maximum attempts count for 'attempts' property if defined for retry node at depth '${depth}'`\n );\n }\n } else if (isInteger(definition.attempts)) {\n // A retry node must have a positive number of attempts if defined.\n if (definition.attempts < 0) {\n throw new Error(\n `expected positive attempts count for 'attempts' property if defined for retry node at depth '${depth}'`\n );\n }\n } else {\n throw new Error(\n `expected integer value or array containing two integer values for 'attempts' property if defined for retry node at depth '${depth}'`\n );\n }\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n\n // Validate the child node of this decorator node.\n validateNode(definition.child, depth + 1);\n}\n\n/**\n * Validate an object that we expect to be a branch node definition.\n * @param definition An object that we expect to be a branch node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateBranchNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"branch\") {\n throw new Error(`expected node type of 'branch' for branch node at depth '${depth}'`);\n }\n\n // Check that the branch node 'ref' property is defined and is a non-empty string.\n if (typeof definition.ref !== \"string\" || definition.ref.length === 0) {\n throw new Error(`expected non-empty string for 'ref' property for branch node at depth '${depth}'`);\n }\n\n // It is invalid to define guard attributes for a branch node as they should be defined on the referenced root node.\n [\"while\", \"until\"].forEach((attributeName) => {\n if (typeof definition[attributeName] !== \"undefined\") {\n throw new Error(\n `guards should not be defined for branch nodes but guard '${attributeName}' was defined for branch node at depth '${depth}'`\n );\n }\n });\n\n // It is invalid to define callback attributes for a branch node as they should be defined on the referenced root node.\n [\"entry\", \"exit\", \"step\"].forEach((attributeName) => {\n if (typeof definition[attributeName] !== \"undefined\") {\n throw new Error(\n `callbacks should not be defined for branch nodes but callback '${attributeName}' was defined for branch node at depth '${depth}'`\n );\n }\n });\n}\n\n/**\n * Validate an object that we expect to be a action node definition.\n * @param definition An object that we expect to be a action node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateActionNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"action\") {\n throw new Error(`expected node type of 'action' for action node at depth '${depth}'`);\n }\n\n // The 'call' property must be defined for a action node definition.\n if (typeof definition.call !== \"string\" || definition.call.length === 0) {\n throw new Error(`expected non-empty string for 'call' property of action node at depth '${depth}'`);\n }\n\n // If any action function arguments have been defined then they must have been defined in an array.\n if (typeof definition.args !== \"undefined\" && !Array.isArray(definition.args)) {\n throw new Error(`expected array for 'args' property if defined for action node at depth '${depth}'`);\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n}\n\n/**\n * Validate an object that we expect to be a condition node definition.\n * @param definition An object that we expect to be a condition node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateConditionNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"condition\") {\n throw new Error(`expected node type of 'condition' for condition node at depth '${depth}'`);\n }\n\n // The 'call' property must be defined for a condition node definition.\n if (typeof definition.call !== \"string\" || definition.call.length === 0) {\n throw new Error(`expected non-empty string for 'call' property of condition node at depth '${depth}'`);\n }\n\n // If any condition function arguments have been defined then they must have been defined in an array.\n if (typeof definition.args !== \"undefined\" && !Array.isArray(definition.args)) {\n throw new Error(`expected array for 'args' property if defined for condition node at depth '${depth}'`);\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n}\n\n/**\n * Validate an object that we expect to be a wait node definition.\n * @param definition An object that we expect to be a wait node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateWaitNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"wait\") {\n throw new Error(`expected node type of 'wait' for wait node at depth '${depth}'`);\n }\n\n // Check whether a 'duration' property has been defined, it may not have been if this node is to wait indefinitely.\n if (typeof definition.duration !== \"undefined\") {\n if (Array.isArray(definition.duration)) {\n // Check whether any elements of the array are not integer values.\n const containsNonInteger = !!definition.duration.find((value: unknown) => !isInteger(value));\n\n // If the 'duration' property is an array then it MUST contain two integer values.\n if (definition.duration.length !== 2 || containsNonInteger) {\n throw new Error(\n `expected array containing two integer values for 'duration' property if defined for wait node at depth '${depth}'`\n );\n }\n\n // A wait node must have a positive min and max duration value if they are defined.\n if (definition.duration[0] < 0 || definition.duration[1] < 0) {\n throw new Error(\n `expected positive minimum and maximum duration for 'duration' property if defined for wait node at depth '${depth}'`\n );\n }\n\n // A wait node must not have a minimum duration value that exceeds the maximum duration value.\n if (definition.duration[0] > definition.duration[1]) {\n throw new Error(\n `expected minimum duration value that does not exceed the maximum duration value for 'duration' property if defined for wait node at depth '${depth}'`\n );\n }\n } else if (isInteger(definition.duration)) {\n // A wait node must have a positive duration value if defined.\n if (definition.duration < 0) {\n throw new Error(\n `expected positive duration value for 'duration' property if defined for wait node at depth '${depth}'`\n );\n }\n } else {\n throw new Error(\n `expected integer value or array containing two integer values for 'duration' property if defined for wait node at depth '${depth}'`\n );\n }\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n}\n\n/**\n * Validate an object that we expect to be a sequence node definition.\n * @param definition An object that we expect to be a sequence node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateSequenceNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"sequence\") {\n throw new Error(`expected node type of 'sequence' for sequence node at depth '${depth}'`);\n }\n\n // A sequence node is a composite node, so must have a children nodes array defined.\n if (!Array.isArray(definition.children) || definition.children.length === 0) {\n throw new Error(`expected non-empty 'children' array to be defined for sequence node at depth '${depth}'`);\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n\n // Validate the child nodes of this composite node.\n definition.children.forEach((child: any) => validateNode(child, depth + 1));\n}\n\n/**\n * Validate an object that we expect to be a selector node definition.\n * @param definition An object that we expect to be a selector node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateSelectorNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"selector\") {\n throw new Error(`expected node type of 'selector' for selector node at depth '${depth}'`);\n }\n\n // A selector node is a composite node, so must have a children nodes array defined.\n if (!Array.isArray(definition.children) || definition.children.length === 0) {\n throw new Error(`expected non-empty 'children' array to be defined for selector node at depth '${depth}'`);\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n\n // Validate the child nodes of this composite node.\n definition.children.forEach((child: any) => validateNode(child, depth + 1));\n}\n\n/**\n * Validate an object that we expect to be a parallel node definition.\n * @param definition An object that we expect to be a parallel node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateParallelNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"parallel\") {\n throw new Error(`expected node type of 'parallel' for parallel node at depth '${depth}'`);\n }\n\n // A parallel node is a composite node, so must have a children nodes array defined.\n if (!Array.isArray(definition.children) || definition.children.length === 0) {\n throw new Error(`expected non-empty 'children' array to be defined for parallel node at depth '${depth}'`);\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n\n // Validate the child nodes of this composite node.\n definition.children.forEach((child: any) => validateNode(child, depth + 1));\n}\n\n/**\n * A helper function to create a failure validation result with the given error message.\n * @param errorMessage The validation failure error message.\n * @returns A failure validation result with the given error message.\n */\nfunction createValidationFailureResult(errorMessage: string): DefinitionValidationResult {\n return { succeeded: false, errorMessage };\n}\n", "import { ActionResult, Agent, GlobalFunction } from \"./Agent\";\nimport { RootNodeDefinition } from \"./BehaviourTreeDefinition\";\n\nexport type InvokerFunction = (args: any[]) => ActionResult;\n\n/**\n * A singleton used to store and lookup registered functions and subtrees.\n */\nexport default class Lookup {\n /**\n * The object holding any registered functions keyed on function name.\n */\n private static functionTable: { [key: string]: GlobalFunction } = {};\n /**\n * The object holding any registered subtree root node definitions keyed on tree name.\n */\n private static subtreeTable: { [key: string]: RootNodeDefinition } = {};\n\n /**\n * Gets the function with the specified name.\n * @param name The name of the function.\n * @returns The function with the specified name.\n */\n public static getFunc(name: string): GlobalFunction {\n return this.functionTable[name];\n }\n\n /**\n * Sets the function with the specified name for later lookup.\n * @param name The name of the function.\n * @param func The function.\n */\n public static setFunc(name: string, func: GlobalFunction): void {\n this.functionTable[name] = func;\n }\n\n /**\n * Gets the function invoker for the specified agent and function name.\n * If a function with the specified name exists on the agent object then it will\n * be returned, otherwise we will then check the registered functions for a match.\n * @param agent The agent instance that this behaviour tree is modelling behaviour for.\n * @param name The function name.\n * @returns The function invoker for the specified agent and function name.\n */\n static getFuncInvoker(agent: Agent, name: string): InvokerFunction | null {\n // Check whether the agent contains the specified function.\n const foundOnAgent = agent[name];\n if (foundOnAgent && typeof foundOnAgent === \"function\") {\n return (args: any[]): boolean | ActionResult => foundOnAgent.apply(agent, args);\n }\n\n // The agent does not contain the specified function but it may have been registered at some point.\n if (this.functionTable[name] && typeof this.functionTable[name] === \"function\") {\n return (args: any[]) => this.functionTable[name](agent, ...args.map((arg) => arg.value));\n }\n\n // We have no function to invoke.\n return null;\n }\n\n /**\n * Gets all registered subtree root node definitions.\n */\n static getSubtrees(): { [key: string]: RootNodeDefinition } {\n return this.subtreeTable;\n }\n\n /**\n * Sets the subtree with the specified name for later lookup.\n * @param name The name of the subtree.\n * @param subtree The subtree.\n */\n static setSubtree(name: string, subtree: RootNodeDefinition) {\n this.subtreeTable[name] = subtree;\n }\n\n /**\n * Removes the registered function or subtree with the specified name.\n * @param name The name of the registered function or subtree.\n */\n static remove(name: string) {\n delete this.functionTable[name];\n delete this.subtreeTable[name];\n }\n\n /**\n * Remove all registered functions and subtrees.\n */\n static empty() {\n this.functionTable = {};\n this.subtreeTable = {};\n }\n}\n", "import Node from \"../../nodes/Node\";\n\n/**\n * An exception thrown when evaluating node guard path conditions and a conditions fails.\n */\nexport default class GuardUnsatisifedException extends Error {\n /**\n * @param source The node at which a guard condition failed.\n */\n constructor(private source: Node) {\n super(\"A guard path condition has failed\");\n }\n\n /**\n * Gets whether the specified node is the node at which a guard condition failed.\n * @param node The node to check against the source node.\n * @returns Whether the specified node is the node at which a guard condition failed.\n */\n isSourceNode = (node: Node) => node === this.source;\n}\n", "import { Agent } from \"../../Agent\";\nimport Guard from \"./Guard\";\nimport Node from \"../../nodes/Node\";\nimport GuardUnsatisifedException from \"./GuardUnsatisifedException\";\n\nexport type GuardPathPart = {\n node: Node;\n guards: Guard[];\n};\n\n/**\n * Represents a path of node guards along a root-to-leaf tree path.\n */\nexport default class GuardPath {\n /**\n * @param nodes An array of objects defining a node instance -> guard link, ordered by node depth.\n */\n constructor(private nodes: GuardPathPart[]) {}\n\n /**\n * Evaluate guard conditions for all guards in the tree path, moving outwards from the root.\n * @param agent The agent, required for guard evaluation.\n * @returns An evaluation results object.\n */\n evaluate = (agent: Agent) => {\n // We need to evaluate guard conditions for nodes up the tree, moving outwards from the root.\n for (const details of this.nodes) {\n // There can be multiple guards per node.\n for (const guard of details.guards) {\n // Check whether the guard condition passes, and throw an exception if not.\n if (!guard.isSatisfied(agent)) {\n throw new GuardUnsatisifedException(details.node);\n }\n }\n }\n };\n}\n", "import { BehaviourTreeOptions } from \"../BehaviourTreeOptions\";\nimport State, { AnyState } from \"../State\";\nimport { Agent } from \"../Agent\";\nimport Leaf from \"./leaf/Leaf\";\nimport Attribute from \"../attributes/Attribute\";\nimport Entry from \"../attributes/callbacks/Entry\";\nimport Exit from \"../attributes/callbacks/Exit\";\nimport Step from \"../attributes/callbacks/Step\";\nimport Guard from \"../attributes/guards/Guard\";\nimport GuardPath from \"../attributes/guards/GuardPath\";\nimport GuardUnsatisifedException from \"../attributes/guards/GuardUnsatisifedException\";\n\n/**\n * A base node.\n */\nexport default abstract class Node {\n /**\n * The node uid.\n */\n private readonly uid: string = createNodeUid();\n /**\n * The node state.\n */\n private state: AnyState = State.READY;\n /**\n * The guard path to evaluate as part of a node update.\n */\n private guardPath: GuardPath | undefined;\n\n /**\n * @param type The node type.\n * @param attributes The node attributes.\n * @param args The node argument definitions.\n */\n constructor(private type: string, private attributes: Attribute[], private args: any[]) {}\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected abstract onUpdate(agent: Agent, options: BehaviourTreeOptions): void;\n\n /**\n * Gets the name of the node.\n */\n public abstract getName(): string;\n\n /**\n * Gets whether this node is a leaf node.\n */\n public abstract isLeafNode: () => this is Leaf;\n\n /**\n * Gets/Sets the state of the node.\n */\n getState = (): AnyState => this.state;\n setState = (value: AnyState): void => {\n this.state = value;\n };\n\n /**\n * Gets the unique id of the node.\n */\n getUid = () => this.uid;\n\n /**\n * Gets the type of the node.\n */\n getType = () => this.type;\n\n /**\n * Gets the node attributes.\n */\n getAttributes = () => this.attributes;\n\n /**\n * Gets the node arguments.\n */\n getArguments = () => this.args;\n\n /**\n * Gets the node attribute with the specified type, or null if it does not exist.\n */\n getAttribute(type: \"entry\" | \"ENTRY\"): Entry;\n getAttribute(type: \"exit\" | \"EXIT\"): Exit;\n getAttribute(type: \"step\" | \"STEP\"): Step;\n getAttribute(type: string): Attribute {\n return (\n this.getAttributes().filter((decorator) => decorator.type.toUpperCase() === type.toUpperCase())[0] || null\n );\n }\n\n /**\n * Gets the node attributes.\n */\n getGuardAttributes = (): Guard[] => this.getAttributes().filter((decorator) => decorator.isGuard()) as Guard[];\n\n /**\n * Sets the guard path to evaluate as part of a node update.\n */\n setGuardPath = (value: GuardPath) => (this.guardPath = value);\n\n /**\n * Gets whether a guard path is assigned to this node.\n */\n hasGuardPath = () => !!this.guardPath;\n\n /**\n * Gets whether this node is in the specified state.\n * @param value The value to compare to the node state.\n */\n public is(value: AnyState): boolean {\n return this.state === value;\n }\n\n /**\n * Reset the state of the node.\n */\n public reset(): void {\n this.setState(State.READY);\n }\n\n /**\n * Abort the running of this node.\n * @param agent The agent.\n */\n public abort(agent: Agent): void {\n // There is nothing to do if this node is not in the running state.\n if (!this.is(State.RUNNING)) {\n return;\n }\n\n // Reset the state of this node.\n this.reset();\n\n this.getAttribute(\"exit\")?.callAgentFunction(agent, false, true);\n }\n\n /**\n * Update the node.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n * @returns The result of the update.\n */\n public update(agent: Agent, options: BehaviourTreeOptions): void {\n // If this node is already in a 'SUCCEEDED' or 'FAILED' state then there is nothing to do.\n if (this.is(State.SUCCEEDED) || this.is(State.FAILED)) {\n return;\n }\n\n try {\n // Evaluate all of the guard path conditions for the current tree path.\n this.guardPath!.evaluate(agent);\n\n // If this node is in the READY state then call the ENTRY for this node if it exists.\n if (this.is(State.READY)) {\n this.getAttribute(\"entry\")?.callAgentFunction(agent);\n }\n\n this.getAttribute(\"step\")?.callAgentFunction(agent);\n\n // Do the actual update.\n this.onUpdate(agent, options);\n\n // If this node is now in a 'SUCCEEDED' or 'FAILED' state then call the EXIT for this node if it exists.\n if (this.is(State.SUCCEEDED) || this.is(State.FAILED)) {\n this.getAttribute(\"exit\")?.callAgentFunction(agent, this.is(State.SUCCEEDED), false);\n }\n } catch (error) {\n // If the error is a GuardUnsatisfiedException then we need to determine if this node is the source.\n if (error instanceof GuardUnsatisifedException && error.isSourceNode(this)) {\n // Abort the current node.\n this.abort(agent);\n\n // Any node that is the source of an abort will be a failed node.\n this.setState(State.FAILED);\n } else {\n throw error;\n }\n }\n }\n}\n\n/**\n * Create a randomly generated node uid.\n * @returns A randomly generated node uid.\n */\nfunction createNodeUid(): string {\n var S4 = function () {\n return (((1 + Math.random()) * 0x10000) | 0).toString(16).substring(1);\n };\n return S4() + S4() + \"-\" + S4() + \"-\" + S4() + \"-\" + S4() + \"-\" + S4() + S4() + S4();\n}\n", "import Node from \"../Node\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\n\n/**\n * A composite node that wraps child nodes.\n */\nexport default abstract class Composite extends Node {\n /**\n * @param type The node type.\n * @param attributes The node attributes.\n * @param children The child nodes.\n */\n constructor(type: string, attributes: Attribute[], protected children: Node[]) {\n super(type, attributes, []);\n }\n\n /**\n * Gets whether this node is a leaf node.\n */\n isLeafNode = () => false;\n\n /**\n * Gets the children of this node.\n */\n getChildren = () => this.children;\n\n /**\n * Reset the state of the node.\n */\n reset = () => {\n // Reset the state of this node.\n this.setState(State.READY);\n\n // Reset the state of any child nodes.\n this.getChildren().forEach((child) => child.reset());\n };\n\n /**\n * Abort the running of this node.\n * @param agent The agent.\n */\n abort = (agent: Agent) => {\n // There is nothing to do if this node is not in the running state.\n if (!this.is(State.RUNNING)) {\n return;\n }\n\n // Abort any child nodes.\n this.getChildren().forEach((child) => child.abort(agent));\n\n // Reset the state of this node.\n this.reset();\n\n this.getAttribute(\"exit\")?.callAgentFunction(agent, false, true);\n };\n}\n", "import Composite from \"./Composite\";\nimport State from \"../../State\";\nimport Node from \"../Node\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A PARALLEL node.\n * The child nodes are executed concurrently until one fails or all succeed.\n */\nexport default class Parallel extends Composite {\n /**\n * @param attributes The node attributes.\n * @param children The child nodes.\n */\n constructor(attributes: Attribute[], children: Node[]) {\n super(\"parallel\", attributes, children);\n }\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // Keep a count of the number of succeeded child nodes.\n let succeededCount = 0;\n\n let hasChildFailed = false;\n\n // Iterate over all of the children of this node.\n for (const child of this.children) {\n // If the child has never been updated or is running then we will need to update it now.\n if (child.getState() === State.READY || child.getState() === State.RUNNING) {\n // Update the child of this node.\n child.update(agent, options);\n }\n\n // If the current child has a state of 'SUCCEEDED' then we should move on to the next child.\n if (child.getState() === State.SUCCEEDED) {\n // The child node has succeeded, keep track of this to determine if all children have.\n succeededCount++;\n\n // The child node succeeded, but we have not finished checking every child node yet.\n continue;\n }\n\n // If the current child has a state of 'FAILED' then this node is also a 'FAILED' node.\n if (child.getState() === State.FAILED) {\n hasChildFailed = true;\n\n // There is no need to check the rest of the children.\n break;\n }\n\n // The node should be in the 'RUNNING' state.\n if (child.getState() !== State.RUNNING) {\n // The child node was not in an expected state.\n throw new Error(\"child node was not in an expected state.\");\n }\n }\n\n if (hasChildFailed) {\n // This node is a 'FAILED' node.\n this.setState(State.FAILED);\n\n // Abort every running child.\n for (const child of this.children) {\n if (child.getState() === State.RUNNING) {\n child.abort(agent);\n }\n }\n } else {\n // If all children have succeeded then this node has also succeeded, otherwise it is still running.\n this.setState(succeededCount === this.children.length ? State.SUCCEEDED : State.RUNNING);\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => \"PARALLEL\";\n}\n", "import Composite from \"./Composite\";\nimport Node from \"../Node\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A SELECTOR node.\n * The child nodes are executed in sequence until one succeeds or all fail.\n */\nexport default class Selector extends Composite {\n /**\n * @param attributes The node attributes.\n * @param children The child nodes.\n */\n constructor(attributes: Attribute[], protected children: Node[]) {\n super(\"selector\", attributes, children);\n }\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // Iterate over all of the children of this node.\n for (const child of this.children) {\n // If the child has never been updated or is running then we will need to update it now.\n if (child.getState() === State.READY || child.getState() === State.RUNNING) {\n // Update the child of this node.\n child.update(agent, options);\n }\n\n // If the current child has a state of 'SUCCEEDED' then this node is also a 'SUCCEEDED' node.\n if (child.getState() === State.SUCCEEDED) {\n // This node is a 'SUCCEEDED' node.\n this.setState(State.SUCCEEDED);\n\n // There is no need to check the rest of the selector nodes.\n return;\n }\n\n // If the current child has a state of 'FAILED' then we should move on to the next child.\n if (child.getState() === State.FAILED) {\n // Find out if the current child is the last one in the selector.\n // If it is then this sequence node has also failed.\n if (this.children.indexOf(child) === this.children.length - 1) {\n // This node is a 'FAILED' node.\n this.setState(State.FAILED);\n\n // There is no need to check the rest of the selector as we have completed it.\n return;\n } else {\n // The child node failed, try the next one.\n continue;\n }\n }\n\n // The node should be in the 'RUNNING' state.\n if (child.getState() === State.RUNNING) {\n // This node is a 'RUNNING' node.\n this.setState(State.RUNNING);\n\n // There is no need to check the rest of the selector as the current child is still running.\n return;\n }\n\n // The child node was not in an expected state.\n throw new Error(\"child node was not in an expected state.\");\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => \"SELECTOR\";\n}\n", "import Composite from \"./Composite\";\nimport Node from \"../Node\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A SEQUENCE node.\n * The child nodes are executed in sequence until one fails or all succeed.\n */\nexport default class Sequence extends Composite {\n /**\n * @param attributes The node attributes.\n * @param children The child nodes.\n */\n constructor(attributes: Attribute[], protected children: Node[]) {\n super(\"sequence\", attributes, children);\n }\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // Iterate over all of the children of this node.\n for (const child of this.children) {\n // If the child has never been updated or is running then we will need to update it now.\n if (child.getState() === State.READY || child.getState() === State.RUNNING) {\n // Update the child of this node.\n child.update(agent, options);\n }\n\n // If the current child has a state of 'SUCCEEDED' then we should move on to the next child.\n if (child.getState() === State.SUCCEEDED) {\n // Find out if the current child is the last one in the sequence.\n // If it is then this sequence node has also succeeded.\n if (this.children.indexOf(child) === this.children.length - 1) {\n // This node is a 'SUCCEEDED' node.\n this.setState(State.SUCCEEDED);\n\n // There is no need to check the rest of the sequence as we have completed it.\n return;\n } else {\n // The child node succeeded, but we have not finished the sequence yet.\n continue;\n }\n }\n\n // If the current child has a state of 'FAILED' then this node is also a 'FAILED' node.\n if (child.getState() === State.FAILED) {\n // This node is a 'FAILED' node.\n this.setState(State.FAILED);\n\n // There is no need to check the rest of the sequence.\n return;\n }\n\n // The node should be in the 'RUNNING' state.\n if (child.getState() === State.RUNNING) {\n // This node is a 'RUNNING' node.\n this.setState(State.RUNNING);\n\n // There is no need to check the rest of the sequence as the current child is still running.\n return;\n }\n\n // The child node was not in an expected state.\n throw new Error(\"child node was not in an expected state.\");\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => \"SEQUENCE\";\n}\n", "import createLotto from \"lotto-draw\";\n\nimport Node from \"../Node\";\nimport Composite from \"./Composite\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A LOTTO node.\n * A winning child is picked on the initial update of this node, based on ticket weighting.\n * The state of this node will match the state of the winning child.\n */\nexport default class Lotto extends Composite {\n /**\n * @param attributes The node attributes.\n * @param weights The child node weights.\n * @param children The child nodes.\n */\n constructor(attributes: Attribute[], private weights: number[] | undefined, children: Node[]) {\n super(\"lotto\", attributes, children);\n }\n\n /**\n * The child node selected to be the active one.\n */\n private selectedChild: Node | undefined;\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // If this node is in the READY state then we need to pick a winning child node.\n if (this.is(State.READY)) {\n // Create a lotto draw with which to randomly pick a child node to become the active one.\n const lottoDraw = createLotto({\n // Hook up the optional 'random' behaviour tree function option to the one used by 'lotto-draw'.\n random: options.random,\n // Pass in each child node as a participant in the lotto draw with their respective ticket count.\n participants: this.children.map((child, index) => [child, this.weights?.[index] || 1])\n });\n\n // Randomly pick a child based on ticket weighting, this will become the active child for this composite node.\n this.selectedChild = lottoDraw.draw() || undefined;\n }\n\n // If something went wrong and we don't have an active child then we should throw an error.\n if (!this.selectedChild) {\n throw new Error(\"failed to update lotto node as it has no active child\");\n }\n\n // If the selected child has never been updated or is running then we will need to update it now.\n if (this.selectedChild.getState() === State.READY || this.selectedChild.getState() === State.RUNNING) {\n this.selectedChild.update(agent, options);\n }\n\n // The state of the lotto node is the state of its selected child.\n this.setState(this.selectedChild.getState());\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => (this.weights ? `LOTTO [${this.weights.join(\",\")}]` : \"LOTTO\");\n}\n", "import Node from \"../Node\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\n\n/**\n * A decorator node that wraps a single child node.\n */\nexport default abstract class Decorator extends Node {\n /**\n * @param type The node type.\n * @param attributes The node attributes.\n * @param child The child node.\n */\n constructor(type: string, attributes: Attribute[], protected child: Node) {\n super(type, attributes, []);\n }\n\n /**\n * Gets whether this node is a leaf node.\n */\n isLeafNode = () => false;\n\n /**\n * Gets the children of this node.\n */\n getChildren = () => [this.child];\n\n /**\n * Reset the state of the node.\n */\n reset = () => {\n // Reset the state of this node.\n this.setState(State.READY);\n\n // Reset the state of the child node.\n this.child.reset();\n };\n\n /**\n * Abort the running of this node.\n * @param agent The agent.\n */\n abort = (agent: Agent) => {\n // There is nothing to do if this node is not in the running state.\n if (!this.is(State.RUNNING)) {\n return;\n }\n\n // Abort the child node.\n this.child.abort(agent);\n\n // Reset the state of this node.\n this.reset();\n\n this.getAttribute(\"exit\")?.callAgentFunction(agent, false, true);\n };\n}\n", "import Node from \"../Node\";\nimport Decorator from \"./Decorator\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A Fail node.\n * This node wraps a single child and will always move to the 'FAILED' state when the child moves to a 'SUCCEEDED' or 'FAILED' state.\n */\nexport default class Fail extends Decorator {\n /**\n * @param attributes The node attributes.\n * @param child The child node.\n */\n constructor(attributes: Attribute[], child: Node) {\n super(\"fail\", attributes, child);\n }\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // If the child has never been updated or is running then we will need to update it now.\n if (this.child.getState() === State.READY || this.child.getState() === State.RUNNING) {\n this.child.update(agent, options);\n }\n\n // The state of this node will depend in the state of its child.\n switch (this.child.getState()) {\n case State.RUNNING:\n this.setState(State.RUNNING);\n break;\n\n case State.SUCCEEDED:\n case State.FAILED:\n this.setState(State.FAILED);\n break;\n\n default:\n this.setState(State.READY);\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => \"FAIL\";\n}\n", "import Decorator from \"./Decorator\";\nimport State from \"../../State\";\nimport Node from \"../Node\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A Flip node.\n * This node wraps a single child and will flip the state of the child state.\n */\nexport default class Flip extends Decorator {\n /**\n * @param attributes The node attributes.\n * @param child The child node.\n */\n constructor(attributes: Attribute[], child: Node) {\n super(\"flip\", attributes, child);\n }\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // If the child has never been updated or is running then we will need to update it now.\n if (this.child.getState() === State.READY || this.child.getState() === State.RUNNING) {\n this.child.update(agent, options);\n }\n\n // The state of this node will depend in the state of its child.\n switch (this.child.getState()) {\n case State.RUNNING:\n this.setState(State.RUNNING);\n break;\n\n case State.SUCCEEDED:\n this.setState(State.FAILED);\n break;\n\n case State.FAILED:\n this.setState(State.SUCCEEDED);\n break;\n\n default:\n this.setState(State.READY);\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => \"FLIP\";\n}\n", "import Node from \"../Node\";\nimport Decorator from \"./Decorator\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A REPEAT node.\n * The node has a single child which can have:\n * -- A number of iterations for which to repeat the child node.\n * -- An infinite repeat loop if neither an iteration count or a condition function is defined.\n * The REPEAT node will stop and have a 'FAILED' state if its child is ever in a 'FAILED' state after an update.\n * The REPEAT node will attempt to move on to the next iteration if its child is ever in a 'SUCCEEDED' state.\n */\nexport default class Repeat extends Decorator {\n /**\n * @param attributes The node attributes.\n * @param iterations The number of iterations to repeat the child node.\n * @param iterationsMin The minimum possible number of iterations to repeat the child node.\n * @param iterationsMax The maximum possible number of iterations to repeat the child node.\n * @param child The child node.\n */\n constructor(\n attributes: Attribute[],\n private iterations: number | null,\n private iterationsMin: number | null,\n private iterationsMax: number | null,\n child: Node\n ) {\n super(\"repeat\", attributes, child);\n }\n\n /**\n * The number of target iterations to make.\n */\n private targetIterationCount: number | null = null;\n\n /**\n * The current iteration count.\n */\n private currentIterationCount: number = 0;\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // If this node is in the READY state then we need to reset the child and the target iteration count.\n if (this.is(State.READY)) {\n // Reset the child node.\n this.child.reset();\n\n // Reset the current iteration count.\n this.currentIterationCount = 0;\n\n // Set the target iteration count.\n this.setTargetIterationCount(options);\n }\n\n // Do a check to see if we can iterate. If we can then this node will move into the 'RUNNING' state.\n // If we cannot iterate then we have hit our target iteration count, which means that the node has succeeded.\n if (this.canIterate()) {\n // This node is in the running state and can do its initial iteration.\n this.setState(State.RUNNING);\n\n // We may have already completed an iteration, meaning that the child node will be in the SUCCEEDED state.\n // If this is the case then we will have to reset the child node now.\n if (this.child.getState() === State.SUCCEEDED) {\n this.child.reset();\n }\n\n // Update the child of this node.\n this.child.update(agent, options);\n\n // If the child moved into the FAILED state when we updated it then there is nothing left to do and this node has also failed.\n // If it has moved into the SUCCEEDED state then we have completed the current iteration.\n if (this.child.getState() === State.FAILED) {\n // The child has failed, meaning that this node has failed.\n this.setState(State.FAILED);\n\n return;\n } else if (this.child.getState() === State.SUCCEEDED) {\n // We have completed an iteration.\n this.currentIterationCount += 1;\n }\n } else {\n // This node is in the 'SUCCEEDED' state as we cannot iterate any more.\n this.setState(State.SUCCEEDED);\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => {\n if (this.iterations !== null) {\n return `REPEAT ${this.iterations}x`;\n } else if (this.iterationsMin !== null && this.iterationsMax !== null) {\n return `REPEAT ${this.iterationsMin}x-${this.iterationsMax}x`;\n } else {\n return \"REPEAT\";\n }\n };\n\n /**\n * Reset the state of the node.\n */\n reset = () => {\n // Reset the state of this node.\n this.setState(State.READY);\n\n // Reset the current iteration count.\n this.currentIterationCount = 0;\n\n // Reset the child node.\n this.child.reset();\n };\n\n /**\n * Gets whether an iteration can be made.\n * @returns Whether an iteration can be made.\n */\n private canIterate = () => {\n if (this.targetIterationCount !== null) {\n // We can iterate as long as we have not reached our target iteration count.\n return this.currentIterationCount < this.targetIterationCount;\n }\n\n // If neither an iteration count or a condition function were defined then we can iterate indefinitely.\n return true;\n };\n\n /**\n * Sets the target iteration count.\n * @param options The behaviour tree options object.\n */\n private setTargetIterationCount = (options: BehaviourTreeOptions) => {\n // Are we dealing with an explicit iteration count or will we be randomly picking a iteration count between the min and max iteration count.\n if (this.iterations !== null) {\n this.targetIterationCount = this.iterations;\n } else if (this.iterationsMin !== null && this.iterationsMax !== null) {\n // We will be picking a random iteration count between a min and max iteration count, if the optional 'random'\n // behaviour tree function option is defined then we will be using that, otherwise we will fall back to using Math.random.\n const random = typeof options.random === \"function\" ? options.random : Math.random;\n\n // Pick a random iteration count between a min and max iteration count.\n this.targetIterationCount = Math.floor(\n random() * (this.iterationsMax - this.iterationsMin + 1) + this.iterationsMin\n );\n } else {\n this.targetIterationCount = null;\n }\n };\n}\n", "import Node from \"../Node\";\nimport Decorator from \"./Decorator\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A RETRY node.\n * The node has a single child which can have:\n * -- A number of iterations for which to repeat the child node.\n * -- An infinite repeat loop if neither an iteration count or a condition function is defined.\n * The RETRY node will stop and have a 'SUCCEEDED' state if its child is ever in a 'SUCCEEDED' state after an update.\n * The RETRY node will attempt to move on to the next iteration if its child is ever in a 'FAILED' state.\n */\nexport default class Retry extends Decorator {\n /**\n * @param attributes The node attributes.\n * @param attempts The number of attempts to retry the child node.\n * @param attemptsMin The minimum possible number of attempts to retry the child node.\n * @param attemptsMax The maximum possible number of attempts to retry the child node.\n * @param child The child node.\n */\n constructor(\n attributes: Attribute[],\n private attempts: number | null,\n private attemptsMin: number | null,\n private attemptsMax: number | null,\n child: Node\n ) {\n super(\"retry\", attributes, child);\n }\n\n /**\n * The number of target attempts to make.\n */\n private targetAttemptCount: number | null = null;\n\n /**\n * The current attempt count.\n */\n private currentAttemptCount: number = 0;\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // If this node is in the READY state then we need to reset the child and the target attempt count.\n if (this.is(State.READY)) {\n // Reset the child node.\n this.child.reset();\n\n // Reset the current attempt count.\n this.currentAttemptCount = 0;\n\n // Set the target attempt count.\n this.setTargetAttemptCount(options);\n }\n\n // Do a check to see if we can attempt. If we can then this node will move into the 'RUNNING' state.\n // If we cannot attempt then we have hit our target attempt count, which means that the node has succeeded.\n if (this.canAttempt()) {\n // This node is in the running state and can do its initial attempt.\n this.setState(State.RUNNING);\n\n // We may have already completed an attempt, meaning that the child node will be in the FAILED state.\n // If this is the case then we will have to reset the child node now.\n if (this.child.getState() === State.FAILED) {\n this.child.reset();\n }\n\n // Update the child of this node.\n this.child.update(agent, options);\n\n // If the child moved into the SUCCEEDED state when we updated it then there is nothing left to do and this node has also succeeded.\n // If it has moved into the FAILED state then we have completed the current attempt.\n if (this.child.getState() === State.SUCCEEDED) {\n // The child has succeeded, meaning that this node has succeeded.\n this.setState(State.SUCCEEDED);\n\n return;\n } else if (this.child.getState() === State.FAILED) {\n // We have completed an attempt.\n this.currentAttemptCount += 1;\n }\n } else {\n // This node is in the 'FAILED' state as we cannot iterate any more.\n this.setState(State.FAILED);\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => {\n if (this.attempts !== null) {\n return `RETRY ${this.attempts}x`;\n } else if (this.attemptsMin !== null && this.attemptsMax !== null) {\n return `RETRY ${this.attemptsMin}x-${this.attemptsMax}x`;\n } else {\n return \"RETRY\";\n }\n };\n\n /**\n * Reset the state of the node.\n */\n reset = () => {\n // Reset the state of this node.\n this.setState(State.READY);\n\n // Reset the current attempt count.\n this.currentAttemptCount = 0;\n\n // Reset the child node.\n this.child.reset();\n };\n\n /**\n * Gets whether an attempt can be made.\n * @returns Whether an attempt can be made.\n */\n canAttempt = () => {\n if (this.targetAttemptCount !== null) {\n // We can attempt as long as we have not reached our target attempt count.\n return this.currentAttemptCount < this.targetAttemptCount;\n }\n\n // If neither an attempt count or a condition function were defined then we can attempt indefinitely.\n return true;\n };\n\n /**\n * Sets the target attempt count.\n * @param options The behaviour tree options object.\n */\n setTargetAttemptCount = (options: BehaviourTreeOptions) => {\n // Are we dealing with an explicit attempt count or will we be randomly picking an attempt count between the min and max attempt count.\n if (this.attempts !== null) {\n this.targetAttemptCount = this.attempts;\n } else if (this.attemptsMin !== null && this.attemptsMax !== null) {\n // We will be picking a random attempt count between a min and max attempt count, if the optional 'random'\n // behaviour tree function option is defined then we will be using that, otherwise we will fall back to using Math.random.\n const random = typeof options.random === \"function\" ? options.random : Math.random;\n\n // Pick a random attempt count between a min and max attempt count.\n this.targetAttemptCount = Math.floor(\n random() * (this.attemptsMax - this.attemptsMin + 1) + this.attemptsMin\n );\n } else {\n this.targetAttemptCount = null;\n }\n };\n}\n", "import Node from \"../Node\";\nimport Decorator from \"./Decorator\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A Root node.\n * The root node will have a single child.\n */\nexport default class Root extends Decorator {\n /**\n * @param attributes The node attributes.\n * @param child The child node.\n */\n constructor(attributes: Attribute[], child: Node) {\n super(\"root\", attributes, child);\n }\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // If the child has never been updated or is running then we will need to update it now.\n if (this.child.getState() === State.READY || this.child.getState() === State.RUNNING) {\n // Update the child of this node.\n this.child.update(agent, options);\n }\n\n // The state of the root node is the state of its child.\n this.setState(this.child.getState());\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => \"ROOT\";\n}\n", "import Node from \"../Node\";\nimport Decorator from \"./Decorator\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A Succeed node.\n * This node wraps a single child and will always move to the 'SUCCEEDED' state when the child moves to a 'SUCCEEDED' or 'FAILED' state.\n */\nexport default class Succeed extends Decorator {\n /**\n * @param attributes The node attributes.\n * @param child The child node.\n */\n constructor(attributes: Attribute[], child: Node) {\n super(\"succeed\", attributes, child);\n }\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // If the child has never been updated or is running then we will need to update it now.\n if (this.child.getState() === State.READY || this.child.getState() === State.RUNNING) {\n this.child.update(agent, options);\n }\n\n // The state of this node will depend in the state of its child.\n switch (this.child.getState()) {\n case State.RUNNING:\n this.setState(State.RUNNING);\n break;\n\n case State.SUCCEEDED:\n case State.FAILED:\n this.setState(State.SUCCEEDED);\n break;\n\n default:\n this.setState(State.READY);\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => \"SUCCEED\";\n}\n", "import Node from \"../Node\";\n\n/**\n * A leaf node.\n */\nexport default abstract class Leaf extends Node {\n /**\n * Gets whether this node is a leaf node.\n */\n isLeafNode = () => true;\n}\n", "import { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\nimport State, { CompleteState } from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Leaf from \"./Leaf\";\nimport Lookup from \"../../Lookup\";\nimport Attribute from \"../../attributes/Attribute\";\n\n/**\n * An Action leaf node.\n * This represents an immediate or ongoing state of behaviour.\n */\nexport default class Action extends Leaf {\n /**\n * @param attributes The node attributes.\n * @param actionName The action name.\n * @param actionArguments The array of action argument definitions.\n */\n constructor(attributes: Attribute[], private actionName: string, private actionArguments: any[]) {\n super(\"action\", attributes, actionArguments);\n }\n\n /**\n * Whether there is a pending update promise.\n */\n private isUsingUpdatePromise = false;\n\n /**\n * The finished state result of an update promise.\n */\n private updatePromiseStateResult: CompleteState | null = null;\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // If the result of this action depends on an update promise then there is nothing to do until\n // it resolves, unless there has been a value set as a result of the update promise resolving.\n if (this.isUsingUpdatePromise) {\n // Check whether the update promise has resolved with a state value.\n if (this.updatePromiseStateResult) {\n // Set the state of this node to match the state returned by the promise.\n this.setState(this.updatePromiseStateResult);\n }\n\n return;\n }\n\n // Attempt to get the invoker for the action function.\n const actionFuncInvoker = Lookup.getFuncInvoker(agent, this.actionName);\n\n // The action function should be defined.\n if (actionFuncInvoker === null) {\n throw new Error(\n `cannot update action node as the action '${this.actionName}' function is not defined on the agent and has not been registered`\n );\n }\n\n // Call the action function, the result of which may be:\n // - The finished state of this action node.\n // - A promise to return a finished node state.\n // - Undefined if the node should remain in the running state.\n const updateResult = actionFuncInvoker(this.actionArguments) as CompleteState | Promise;\n\n if (updateResult instanceof Promise) {\n updateResult.then(\n (result) => {\n // If 'isUpdatePromisePending' is null then the promise was cleared as it was resolving, probably via an abort of reset.\n if (!this.isUsingUpdatePromise) {\n return;\n }\n\n // Check to make sure the result is a valid finished state.\n if (result !== State.SUCCEEDED && result !== State.FAILED) {\n throw new Error(\n \"action node promise resolved with an invalid value, expected a State.SUCCEEDED or State.FAILED value to be returned\"\n );\n }\n\n // Set pending update promise state result to be processed on next update.\n this.updatePromiseStateResult = result;\n },\n (reason) => {\n // If 'isUpdatePromisePending' is null then the promise was cleared as it was resolving, probably via an abort of reset.\n if (!this.isUsingUpdatePromise) {\n return;\n }\n\n // Just throw whatever was returned as the rejection argument.\n throw new Error(reason);\n }\n );\n\n // This node will be in the 'RUNNING' state until the update promise resolves.\n this.setState(State.RUNNING);\n\n // We are now waiting for the promise returned by the use to resolve before we know what state this node is in.\n this.isUsingUpdatePromise = true;\n } else {\n // Validate the returned value.\n this.validateUpdateResult(updateResult);\n\n // Set the state of this node, this may be undefined, which just means that the node is still in the 'RUNNING' state.\n this.setState(updateResult || State.RUNNING);\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => this.actionName;\n\n /**\n * Reset the state of the node.\n */\n reset = () => {\n // Reset the state of this node.\n this.setState(State.READY);\n\n // There is no longer an update promise that we care about.\n this.isUsingUpdatePromise = false;\n this.updatePromiseStateResult = null;\n };\n\n /**\n * Validate the result of an update function call.\n * @param result The result of an update function call.\n */\n private validateUpdateResult = (result: CompleteState | boolean) => {\n switch (result) {\n case State.SUCCEEDED:\n case State.FAILED:\n case undefined:\n return;\n default:\n throw new Error(\n `action '${this.actionName}' 'onUpdate' returned an invalid response, expected an optional State.SUCCEEDED or State.FAILED value to be returned`\n );\n }\n };\n}\n", "import { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Leaf from \"./Leaf\";\nimport Lookup from \"../../Lookup\";\nimport Attribute from \"../../attributes/Attribute\";\n\n/**\n * A Condition leaf node.\n * This will succeed or fail immediately based on an agent predicate, without moving to the 'RUNNING' state.\n */\nexport default class Condition extends Leaf {\n /**\n * @param attributes The node attributes.\n * @param conditionName The name of the condition function.\n * @param conditionArguments The array of condition argument definitions.\n */\n constructor(attributes: Attribute[], private conditionName: string, private conditionArguments: any[]) {\n super(\"condition\", attributes, conditionArguments);\n }\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // Attempt to get the invoker for the condition function.\n const conditionFuncInvoker = Lookup.getFuncInvoker(agent, this.conditionName);\n\n // The condition function should be defined.\n if (conditionFuncInvoker === null) {\n throw new Error(\n `cannot update condition node as the condition '${this.conditionName}' function is not defined on the agent and has not been registered`\n );\n }\n\n // Call the condition function to determine the state of this node.\n this.setState(!!conditionFuncInvoker(this.conditionArguments) ? State.SUCCEEDED : State.FAILED);\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => this.conditionName;\n}\n", "import Leaf from \"./Leaf\";\nimport State from \"../../State\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { Agent } from \"../../Agent\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A WAIT node.\n * The state of this node will change to SUCCEEDED after a duration of time\n */\nexport default class Wait extends Leaf {\n /**\n * @param attributes The node attributes.\n * @param duration The duration that this node will wait to succeed in milliseconds.\n * @param durationMin The minimum possible duration in milliseconds that this node will wait to succeed.\n * @param durationMax The maximum possible duration in milliseconds that this node will wait to succeed.\n */\n constructor(\n attributes: Attribute[],\n private duration: number | null,\n private durationMin: number | null,\n private durationMax: number | null\n ) {\n super(\"wait\", attributes, []);\n }\n\n /**\n * The time in milliseconds at which this node was first updated.\n */\n private initialUpdateTime: number = 0;\n\n /**\n * The total duration in milliseconds that this node will be waiting for.\n */\n private totalDuration: number | null = null;\n\n /**\n * The duration in milliseconds that this node has been waiting for.\n */\n private waitedDuration: number = 0;\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // If this node is in the READY state then we need to set the initial update time.\n if (this.is(State.READY)) {\n // Set the initial update time.\n this.initialUpdateTime = new Date().getTime();\n\n // Set the initial waited duration.\n this.waitedDuration = 0;\n\n // Are we dealing with an explicit duration or will we be randomly picking a duration between the min and max duration.\n if (this.duration !== null) {\n this.totalDuration = this.duration;\n } else if (this.durationMin !== null && this.durationMax !== null) {\n // We will be picking a random duration between a min and max duration, if the optional 'random' behaviour tree\n // function option is defined then we will be using that, otherwise we will fall back to using Math.random.\n const random = typeof options.random === \"function\" ? options.random : Math.random;\n\n // Pick a random duration between a min and max duration.\n this.totalDuration = Math.floor(\n random() * (this.durationMax - this.durationMin + 1) + this.durationMin\n );\n } else {\n this.totalDuration = null;\n }\n\n // The node is now running until we finish waiting.\n this.setState(State.RUNNING);\n }\n\n // If we have no total duration then this wait node will wait indefinitely until it is aborted.\n if (this.totalDuration === null) {\n return;\n }\n\n // If we have a 'getDeltaTime' function defined as part of our options then we will use it to figure out how long we have waited for.\n if (typeof options.getDeltaTime === \"function\") {\n // Get the delta time.\n const deltaTime = options.getDeltaTime();\n\n // Our delta time must be a valid number and cannot be NaN.\n if (typeof deltaTime !== \"number\" || isNaN(deltaTime)) {\n throw new Error(\"The delta time must be a valid number and not NaN.\");\n }\n\n // Update the amount of time that this node has been waiting for based on the delta time.\n this.waitedDuration += deltaTime * 1000;\n } else {\n // We are not using a delta time, so we will just work out hom much time has passed since the first update.\n this.waitedDuration = new Date().getTime() - this.initialUpdateTime;\n }\n\n // Have we waited long enough?\n if (this.waitedDuration >= this.totalDuration) {\n // We have finished waiting!\n this.setState(State.SUCCEEDED);\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => {\n if (this.duration !== null) {\n return `WAIT ${this.duration}ms`;\n } else if (this.durationMin !== null && this.durationMax !== null) {\n return `WAIT ${this.durationMin}ms-${this.durationMax}ms`;\n } else {\n return \"WAIT\";\n }\n };\n}\n", "import Guard from \"./guards/Guard\";\n\nexport type AttributeDetails = {\n /** The attribute type. */\n type: string;\n\n /** The attribute arguments. */\n args: any[];\n};\n\n/**\n * A base node attribute.\n */\nexport default abstract class Attribute {\n /**\n * @param type The node attribute type.\n * @param args The array of attribute arguments.\n */\n constructor(public type: string, public args: any[]) {}\n\n /**\n * Gets the attribute details.\n */\n abstract getDetails(): TAttributeDetails;\n\n /**\n * Gets whether this attribute is a guard.\n */\n abstract isGuard: () => this is Guard;\n}\n", "import { Agent } from \"../../Agent\";\nimport Attribute, { AttributeDetails } from \"../Attribute\";\n\nexport type GuardAttributeDetails = {\n /** The name of the condition function that determines whether the guard is satisfied. */\n condition: string;\n} & AttributeDetails;\n\n/**\n * A base node guard attribute.\n */\nexport default abstract class Guard extends Attribute {\n /**\n * @param type The node attribute type.\n * @param args The array of decorator argument definitions.\n * @param condition The name of the condition function that determines whether the guard is satisfied.\n */\n constructor(type: string, args: any[], private condition: string) {\n super(type, args);\n }\n\n /**\n * Gets the name of the condition function that determines whether the guard is satisfied.\n */\n getCondition = () => this.condition;\n\n /**\n * Gets whether this attribute is a guard.\n */\n isGuard = () => true;\n\n /**\n * Gets the attribute details.\n */\n getDetails(): GuardAttributeDetails {\n return {\n type: this.type,\n args: this.args,\n condition: this.getCondition()\n };\n }\n\n /**\n * Gets whether the guard is satisfied.\n * @param agent The agent.\n * @returns Whether the guard is satisfied.\n */\n abstract isSatisfied(agent: Agent): boolean;\n}\n", "import Guard from \"./Guard\";\nimport Lookup from \"../../Lookup\";\nimport { Agent } from \"../../Agent\";\n\n/**\n * A WHILE guard which is satisfied as long as the given condition remains true.\n */\nexport default class While extends Guard {\n /**\n * @param condition The name of the condition function that determines whether the guard is satisfied.\n * @param args The array of decorator argument definitions.\n */\n constructor(condition: string, args: any[]) {\n super(\"while\", args, condition);\n }\n\n /**\n * Gets whether the guard is satisfied.\n * @param agent The agent.\n * @returns Whether the guard is satisfied.\n */\n isSatisfied = (agent: Agent) => {\n // Attempt to get the invoker for the condition function.\n const conditionFuncInvoker = Lookup.getFuncInvoker(agent, this.getCondition());\n\n // The condition function should be defined.\n if (conditionFuncInvoker === null) {\n throw new Error(\n `cannot evaluate node guard as the condition '${this.getCondition()}' function is not defined on the agent and has not been registered`\n );\n }\n\n // Call the condition function to determine whether this guard is satisfied.\n return !!conditionFuncInvoker(this.args);\n };\n}\n", "import Guard from \"./Guard\";\nimport Lookup from \"../../Lookup\";\nimport { Agent } from \"../../Agent\";\n\n/**\n * An UNTIL guard which is satisfied as long as the given condition remains false.\n */\nexport default class Until extends Guard {\n /**\n * @param condition The name of the condition function that determines whether the guard is satisfied.\n * @param args The array of decorator argument definitions.\n */\n constructor(condition: string, args: any[]) {\n super(\"until\", args, condition);\n }\n\n /**\n * Gets whether the guard is satisfied.\n * @param agent The agent.\n * @returns Whether the guard is satisfied.\n */\n isSatisfied = (agent: Agent) => {\n // Attempt to get the invoker for the condition function.\n const conditionFuncInvoker = Lookup.getFuncInvoker(agent, this.getCondition());\n\n // The condition function should be defined.\n if (conditionFuncInvoker === null) {\n throw new Error(\n `cannot evaluate node guard as the condition '${this.getCondition()}' function is not defined on the agent and has not been registered`\n );\n }\n\n // Call the condition function to determine whether this guard is satisfied.\n return !!!conditionFuncInvoker(this.args);\n };\n}\n", "import { Agent } from \"../../Agent\";\nimport Attribute, { AttributeDetails } from \"../Attribute\";\n\nexport type CallbackAttributeDetails = {\n /** The name of the agent function that is called. */\n functionName: string;\n} & AttributeDetails;\n\n/**\n * A base node callback attribute.\n */\nexport default abstract class Callback extends Attribute {\n /**\n * @param type The node attribute type.\n * @param args The array of decorator argument definitions.\n * @param functionName The name of the agent function to call.\n */\n constructor(type: string, args: any[], private functionName: string) {\n super(type, args);\n }\n\n /**\n * Gets the name of the agent function to call.\n */\n getFunctionName = () => this.functionName;\n\n /**\n * Gets whether this attribute is a guard.\n */\n isGuard = () => false;\n\n /**\n * Gets the attribute details.\n */\n getDetails(): CallbackAttributeDetails {\n return {\n type: this.type,\n args: this.args,\n functionName: this.getFunctionName()\n };\n }\n\n /**\n * Attempt to call the agent function that this callback refers to.\n * @param agent The agent.\n */\n abstract callAgentFunction: (agent: Agent, isSuccess: boolean, isAborted: boolean) => void;\n}\n", "import Callback from \"./Callback\";\nimport Lookup from \"../../Lookup\";\nimport { Agent } from \"../../Agent\";\n\n/**\n * An ENTRY callback which defines an agent function to call when the associated node is updated and moves out of running state.\n */\nexport default class Entry extends Callback {\n /**\n * @param functionName The name of the agent function to call.\n * @param args The array of callback argument definitions.\n */\n constructor(functionName: string, args: any[]) {\n super(\"entry\", args, functionName);\n }\n\n /**\n * Attempt to call the agent function that this callback refers to.\n * @param agent The agent.\n */\n callAgentFunction = (agent: Agent) => {\n // Attempt to get the invoker for the callback function.\n const callbackFuncInvoker = Lookup.getFuncInvoker(agent, this.getFunctionName());\n\n // The callback function should be defined.\n if (callbackFuncInvoker === null) {\n throw new Error(\n `cannot call entry function '${this.getFunctionName()}' as is not defined on the agent and has not been registered`\n );\n }\n\n // Call the callback function.\n callbackFuncInvoker(this.args);\n };\n}\n", "import Callback from \"./Callback\";\nimport Lookup from \"../../Lookup\";\nimport { Agent } from \"../../Agent\";\n\n/**\n * A STEP callback which defines an agent function to call when the associated node is updated.\n */\nexport default class Step extends Callback {\n /**\n * @param functionName The name of the agent function to call.\n * @param args The array of callback argument definitions.\n */\n constructor(functionName: string, args: any[]) {\n super(\"step\", args, functionName);\n }\n\n /**\n * Attempt to call the agent function that this callback refers to.\n * @param agent The agent.\n */\n callAgentFunction = (agent: Agent) => {\n // Attempt to get the invoker for the callback function.\n const callbackFuncInvoker = Lookup.getFuncInvoker(agent, this.getFunctionName());\n\n // The callback function should be defined.\n if (callbackFuncInvoker === null) {\n throw new Error(\n `cannot call step function '${this.getFunctionName()}' as is not defined on the agent and has not been registered`\n );\n }\n\n // Call the callback function.\n callbackFuncInvoker(this.args);\n };\n}\n", "import Callback from \"./Callback\";\nimport Lookup from \"../../Lookup\";\nimport { Agent } from \"../../Agent\";\n\n/**\n * An EXIT callback which defines an agent function to call when the associated node is updated and moves to a finished state or is aborted.\n */\nexport default class Exit extends Callback {\n /**\n * @param functionName The name of the agent function to call.\n * @param args The array of callback argument definitions.\n */\n constructor(functionName: string, args: any[]) {\n super(\"exit\", args, functionName);\n }\n\n /**\n * Attempt to call the agent function that this callback refers to.\n * @param agent The agent.\n * @param isSuccess Whether the decorated node was left with a success state.\n * @param isAborted Whether the decorated node was aborted.\n */\n callAgentFunction = (agent: Agent, isSuccess: boolean, isAborted: boolean) => {\n // Attempt to get the invoker for the callback function.\n const callbackFuncInvoker = Lookup.getFuncInvoker(agent, this.getFunctionName());\n\n // The callback function should be defined.\n if (callbackFuncInvoker === null) {\n throw new Error(\n `cannot call exit function '${this.getFunctionName()}' as is not defined on the agent and has not been registered`\n );\n }\n\n // Call the callback function\n callbackFuncInvoker([{ value: { succeeded: isSuccess, aborted: isAborted } }, ...this.args]);\n };\n}\n", "import { AnyNodeDefinition, RootNodeDefinition } from \"./BehaviourTreeDefinition\";\nimport GuardPath, { GuardPathPart } from \"./attributes/guards/GuardPath\";\nimport { validateBranchSubtreeLinks } from \"./BehaviourTreeDefinitionValidator\";\nimport { isInteger } from \"./BehaviourTreeDefinitionUtilities\";\nimport Node from \"./nodes/Node\";\nimport Composite from \"./nodes/composite/Composite\";\nimport Decorator from \"./nodes/decorator/Decorator\";\nimport Parallel from \"./nodes/composite/Parallel\";\nimport Selector from \"./nodes/composite/Selector\";\nimport Sequence from \"./nodes/composite/Sequence\";\nimport Lotto from \"./nodes/composite/Lotto\";\nimport Fail from \"./nodes/decorator/Fail\";\nimport Flip from \"./nodes/decorator/Flip\";\nimport Repeat from \"./nodes/decorator/Repeat\";\nimport Retry from \"./nodes/decorator/Retry\";\nimport Root from \"./nodes/decorator/Root\";\nimport Succeed from \"./nodes/decorator/Succeed\";\nimport Action from \"./nodes/leaf/Action\";\nimport Condition from \"./nodes/leaf/Condition\";\nimport Wait from \"./nodes/leaf/Wait\";\nimport Lookup from \"./Lookup\";\nimport Attribute from \"./attributes/Attribute\";\nimport While from \"./attributes/guards/While\";\nimport Until from \"./attributes/guards/Until\";\nimport Entry from \"./attributes/callbacks/Entry\";\nimport Step from \"./attributes/callbacks/Step\";\nimport Exit from \"./attributes/callbacks/Exit\";\n\n/**\n * A type representing any node instance in a behaviour tree.\n */\ntype AnyNode =\n | Root\n | Action\n | Condition\n | Wait\n | Sequence\n | Selector\n | Lotto\n | Parallel\n | Repeat\n | Retry\n | Flip\n | Succeed\n | Fail;\n\n/**\n * A type defining a mapping of root node identifiers to root node definitions.\n */\ntype RootNodeDefinitionMap = { [key: string | symbol]: RootNodeDefinition };\n\n/**\n * A symbol to use as the main root key in any root node mappings.\n */\nconst MAIN_ROOT_NODE_KEY = Symbol(\"__root__\");\n\n/**\n * Build and populate the root nodes based on the provided definition, assuming that the definition has been validated.\n * @param definition The root node definitions.\n * @returns The built and populated root node definitions.\n */\nexport default function buildRootNode(definition: RootNodeDefinition[]): Root {\n // Create a mapping of root node identifers to root node definitions, including globally registered subtree root node definitions.\n const rootNodeDefinitionMap = createRootNodeDefinitionMap(definition);\n\n // Now that we have all of our root node definitons (those part of the tree definition and those globally\n // registered) we should validate the definition. This will also double-check that we dont have any circular\n // dependencies in our branch -> subtree references and that we have no broken branch -> subtree links.\n validateBranchSubtreeLinks(definition, true);\n\n // Create our populated tree of node instances, starting with our main root node.\n const rootNode = nodeFactory(rootNodeDefinitionMap[MAIN_ROOT_NODE_KEY], rootNodeDefinitionMap) as Root;\n\n // Set a guard path on every leaf of the tree to evaluate as part of each update.\n applyLeafNodeGuardPaths(rootNode);\n\n // We only need to return the main root node.\n return rootNode;\n}\n\n/**\n * A factory function which creates a node instance based on the specified definition.\n * @param definition The node definition.\n * @param rootNodeDefinitionMap The mapping of root node identifers to root node definitions, including globally registered subtree root node definitions.\n * @returns A node instance based on the specified definition.\n */\nfunction nodeFactory(definition: AnyNodeDefinition, rootNodeDefinitionMap: RootNodeDefinitionMap): AnyNode {\n // Get the attributes for the node.\n const attributes = nodeAttributesFactory(definition);\n\n // Create the node instance based on the definition type.\n switch (definition.type) {\n case \"root\":\n return new Root(attributes, nodeFactory(definition.child, rootNodeDefinitionMap));\n\n case \"repeat\":\n let iterations: number | null = null;\n let iterationsMin: number | null = null;\n let iterationsMax: number | null = null;\n\n if (Array.isArray(definition.iterations)) {\n iterationsMin = definition.iterations[0];\n iterationsMax = definition.iterations[1];\n } else if (isInteger(definition.iterations)) {\n iterations = definition.iterations!;\n }\n\n return new Repeat(\n attributes,\n iterations,\n iterationsMin,\n iterationsMax,\n nodeFactory(definition.child, rootNodeDefinitionMap)\n );\n\n case \"retry\":\n let attempts: number | null = null;\n let attemptsMin: number | null = null;\n let attemptsMax: number | null = null;\n\n if (Array.isArray(definition.attempts)) {\n attemptsMin = definition.attempts[0];\n attemptsMax = definition.attempts[1];\n } else if (isInteger(definition.attempts)) {\n attempts = definition.attempts!;\n }\n\n return new Retry(\n attributes,\n attempts,\n attemptsMin,\n attemptsMax,\n nodeFactory(definition.child, rootNodeDefinitionMap)\n );\n\n case \"flip\":\n return new Flip(attributes, nodeFactory(definition.child, rootNodeDefinitionMap));\n\n case \"succeed\":\n return new Succeed(attributes, nodeFactory(definition.child, rootNodeDefinitionMap));\n\n case \"fail\":\n return new Fail(attributes, nodeFactory(definition.child, rootNodeDefinitionMap));\n\n case \"sequence\":\n return new Sequence(\n attributes,\n definition.children.map((child) => nodeFactory(child, rootNodeDefinitionMap))\n );\n\n case \"selector\":\n return new Selector(\n attributes,\n definition.children.map((child) => nodeFactory(child, rootNodeDefinitionMap))\n );\n\n case \"parallel\":\n return new Parallel(\n attributes,\n definition.children.map((child) => nodeFactory(child, rootNodeDefinitionMap))\n );\n\n case \"lotto\":\n return new Lotto(\n attributes,\n definition.weights,\n definition.children.map((child) => nodeFactory(child, rootNodeDefinitionMap))\n );\n\n case \"branch\":\n return nodeFactory(rootNodeDefinitionMap[definition.ref].child, rootNodeDefinitionMap);\n\n case \"action\":\n return new Action(attributes, definition.call, definition.args || []);\n\n case \"condition\":\n return new Condition(attributes, definition.call, definition.args || []);\n\n case \"wait\":\n let duration: number | null = null;\n let durationMin: number | null = null;\n let durationMax: number | null = null;\n\n if (Array.isArray(definition.duration)) {\n durationMin = definition.duration[0];\n durationMax = definition.duration[1];\n } else if (isInteger(definition.duration)) {\n duration = definition.duration!;\n }\n\n return new Wait(attributes, duration, durationMin, durationMax);\n }\n}\n\n/**\n * Creates an array of node attribute instances based on the specified node definition.\n * @param definition The node definition.\n * @returns An array of node attribute instances based on the specified node definition.\n */\nfunction nodeAttributesFactory(definition: AnyNodeDefinition): Attribute[] {\n const attributes: Attribute[] = [];\n\n if (definition.while) {\n attributes.push(new While(definition.while.call, definition.while.args ?? []));\n }\n\n if (definition.until) {\n attributes.push(new Until(definition.until.call, definition.until.args ?? []));\n }\n\n if (definition.entry) {\n attributes.push(new Entry(definition.entry.call, definition.entry.args ?? []));\n }\n\n if (definition.step) {\n attributes.push(new Step(definition.step.call, definition.step.args ?? []));\n }\n\n if (definition.exit) {\n attributes.push(new Exit(definition.exit.call, definition.exit.args ?? []));\n }\n\n return attributes;\n}\n\n/**\n * Creates a mapping of root node identifers to root node definitions, mixing in globally registered subtree root node definitions.\n * @param definition The root node definitions.\n * @returns A mapping of root node identifers to root node definitions, including globally registered subtree root node definitions.\n */\nfunction createRootNodeDefinitionMap(definition: RootNodeDefinition[]): RootNodeDefinitionMap {\n // Create a mapping of root node identifers to root node definitions.\n const rootNodeMap: RootNodeDefinitionMap = {};\n\n // Add in any registered subtree root node definitions.\n for (const [name, rootNodeDefinition] of Object.entries(Lookup.getSubtrees())) {\n // The name used when registering the subtree will be used as the root node identifier.\n rootNodeMap[name] = { ...rootNodeDefinition, id: name };\n }\n\n // Populate the map with the root node definitions that were included with the tree definition.\n // We do this after adding any registered subtrees as we want these to take presedence.\n for (const rootNodeDefinition of definition) {\n rootNodeMap[rootNodeDefinition.id ?? MAIN_ROOT_NODE_KEY] = rootNodeDefinition;\n }\n\n return rootNodeMap;\n}\n\n/**\n * Applies a guard path to every leaf of the tree to evaluate as part of each update.\n * @param root The main root tree node.\n */\nfunction applyLeafNodeGuardPaths(root: Root) {\n const nodePaths: Node[][] = [];\n\n const findLeafNodes = (path: Node[], node: Node) => {\n // Add the current node to the path.\n path = path.concat(node);\n\n // Check whether the current node is a leaf node.\n if (node.isLeafNode()) {\n nodePaths.push(path);\n } else {\n (node as Composite | Decorator).getChildren().forEach((child) => findLeafNodes(path, child));\n }\n };\n\n // Find all leaf node paths, starting from the root.\n findLeafNodes([], root);\n\n nodePaths.forEach((path) => {\n // Each node in the current path will have to be assigned a guard path, working from the root outwards.\n for (let depth = 0; depth < path.length; depth++) {\n // Get the node in the path at the current depth.\n const currentNode = path[depth];\n\n // The node may already have been assigned a guard path, if so just skip it.\n if (currentNode.hasGuardPath()) {\n continue;\n }\n\n // Create the guard path for the current node.\n const guardPath = new GuardPath(\n path\n .slice(0, depth + 1)\n .map((node) => ({ node, guards: node.getGuardAttributes() }))\n .filter((details) => details.guards.length > 0)\n );\n\n // Assign the guard path to the current node.\n currentNode.setGuardPath(guardPath);\n }\n });\n}\n", "import State, { AnyState } from \"./State\";\nimport Lookup from \"./Lookup\";\nimport Node from \"./nodes/Node\";\nimport Root from \"./nodes/decorator/Root\";\nimport Composite from \"./nodes/composite/Composite\";\nimport Decorator from \"./nodes/decorator/Decorator\";\nimport { Agent, GlobalFunction } from \"./Agent\";\nimport { CallbackAttributeDetails } from \"./attributes/callbacks/Callback\";\nimport { GuardAttributeDetails } from \"./attributes/guards/Guard\";\nimport { BehaviourTreeOptions } from \"./BehaviourTreeOptions\";\nimport { convertMDSLToJSON } from \"./mdsl/MDSLDefinitionParser\";\nimport { RootNodeDefinition } from \"./BehaviourTreeDefinition\";\nimport { validateDefinition, validateJSONDefinition } from \"./BehaviourTreeDefinitionValidator\";\nimport buildRootNode from \"./BehaviourTreeBuilder\";\nimport { isNullOrUndefined } from \"./BehaviourTreeDefinitionUtilities\";\n\n// Purely for outside inspection of the tree.\nexport type FlattenedTreeNode = {\n id: string;\n type: string;\n caption: string;\n state: AnyState;\n guards: GuardAttributeDetails[];\n callbacks: CallbackAttributeDetails[];\n args: any[];\n parentId: string | null;\n};\n\n/**\n * A representation of a behaviour tree.\n */\nexport class BehaviourTree {\n /**\n * The main root tree node.\n */\n public readonly rootNode: Root;\n\n /**\n * Creates a new instance of the BehaviourTree class.\n * @param definition The behaviour tree definition.\n * @param agent The agent instance that this behaviour tree is modelling behaviour for.\n * @param options The behaviour tree options object.\n */\n constructor(\n definition: string | RootNodeDefinition | RootNodeDefinition[],\n private agent: Agent,\n private options: BehaviourTreeOptions = {}\n ) {\n // The tree definition must be defined.\n if (isNullOrUndefined(definition)) {\n throw new Error(\"tree definition not defined\");\n }\n\n // The agent must be defined and not null.\n if (typeof agent !== \"object\" || agent === null) {\n throw new Error(\"the agent must be an object and not null\");\n }\n\n // We should validate the definition before we try to build the tree nodes.\n const { succeeded, errorMessage } = validateDefinition(definition);\n\n // Did our validation fail without error?\n if (!succeeded) {\n throw new Error(`invalid definition: ${errorMessage}`);\n }\n\n try {\n // Parse the behaviour tree definition, create the populated tree of behaviour tree nodes, and get the root.\n this.rootNode = this._createRootNode(definition);\n } catch (exception) {\n // There was an issue in trying build and populate the behaviour tree.\n throw new Error(`error building tree: ${(exception as Error).message}`);\n }\n }\n\n /**\n * Gets whether the tree is in the RUNNING state.\n * @returns true if the tree is in the RUNNING state, otherwise false.\n */\n isRunning() {\n return this.rootNode.getState() === State.RUNNING;\n }\n\n /**\n * Gets the current tree state of SUCCEEDED, FAILED, READY or RUNNING.\n * @returns The current tree state.\n */\n getState() {\n return this.rootNode.getState();\n }\n\n /**\n * Step the tree.\n * 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.\n * 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\n * 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.\n *\n * 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.\n */\n step() {\n // If the root node has already been stepped to completion then we need to reset it.\n if (this.rootNode.getState() === State.SUCCEEDED || this.rootNode.getState() === State.FAILED) {\n this.rootNode.reset();\n }\n\n try {\n this.rootNode.update(this.agent, this.options);\n } catch (exception) {\n throw new Error(`error stepping tree: ${(exception as Error).message}`);\n }\n }\n\n /**\n * Resets the tree from the root node outwards to each nested node, giving each a state of READY.\n */\n reset() {\n this.rootNode.reset();\n }\n\n /**\n * Gets the flattened details of every node in the tree.\n * @returns The flattened details of every node in the tree.\n */\n getFlattenedNodeDetails(): FlattenedTreeNode[] {\n // Create an empty flattened array of tree nodes.\n const flattenedTreeNodes: FlattenedTreeNode[] = [];\n\n /**\n * Helper function to process a node instance and push details into the flattened tree nodes array.\n * @param node The current node.\n * @param parentUid The UID of the node parent, or null if the node is the main root node.\n */\n const processNode = (node: Node, parentUid: string | null) => {\n // Get the guard and callback attribute details for this node.\n const guards = node\n .getAttributes()\n .filter((attribute) => attribute.isGuard())\n .map((attribute) => attribute.getDetails()) as GuardAttributeDetails[];\n const callbacks = node\n .getAttributes()\n .filter((attribute) => !attribute.isGuard())\n .map((attribute) => attribute.getDetails()) as CallbackAttributeDetails[];\n\n // Push the current node into the flattened nodes array.\n flattenedTreeNodes.push({\n id: node.getUid(),\n type: node.getType(),\n caption: node.getName(),\n state: node.getState(),\n guards,\n callbacks,\n args: node.getArguments(),\n parentId: parentUid\n });\n\n // Process each of the nodes children if it is not a leaf node.\n if (!node.isLeafNode()) {\n (node as Composite | Decorator)\n .getChildren()\n .forEach((child) => processNode(child, (node as Composite | Decorator).getUid()));\n }\n };\n\n // Convert the nested node structure into a flattened array of node details.\n processNode(this.rootNode, null);\n\n return flattenedTreeNodes;\n }\n\n /**\n * Registers the action/condition/guard/callback function or subtree with the given name.\n * @param name The name of the function or subtree to register.\n * @param value The function or subtree definition to register.\n */\n static register(name: string, value: GlobalFunction | string | RootNodeDefinition) {\n // Are we going to register a action/condition/guard/callback function?\n if (typeof value === \"function\") {\n Lookup.setFunc(name, value);\n return;\n }\n\n // We are not registering an action/condition/guard/callback function, so we must be registering a subtree.\n if (typeof value === \"string\") {\n let rootNodeDefinitions: RootNodeDefinition[];\n\n // We will assume that any string passed in will be a mdsl definition.\n try {\n rootNodeDefinitions = convertMDSLToJSON(value);\n } catch (exception) {\n throw new Error(`error registering definition, invalid MDSL: ${(exception as Error).message}`);\n }\n\n // This function should only ever be called with a definition containing a single unnamed root node.\n if (rootNodeDefinitions.length != 1 || rootNodeDefinitions[0].id !== null) {\n throw new Error(\"error registering definition: expected a single unnamed root node\");\n }\n\n try {\n // We should validate the subtree as we don't want invalid subtrees available via the lookup.\n const { succeeded, errorMessage } = validateJSONDefinition(rootNodeDefinitions[0]);\n\n // Did our validation fail without error?\n if (!succeeded) {\n throw new Error(errorMessage);\n }\n } catch (exception) {\n throw new Error(`error registering definition: ${(exception as Error).message}`);\n }\n\n // Everything seems hunky-dory, register the subtree.\n Lookup.setSubtree(name, rootNodeDefinitions[0]);\n } else if (typeof value === \"object\" && !Array.isArray(value)) {\n // We will assume that any object passed in is a root node definition.\n\n try {\n // We should validate the subtree as we don't want invalid subtrees available via the lookup.\n const { succeeded, errorMessage } = validateJSONDefinition(value);\n\n // Did our validation fail without error?\n if (!succeeded) {\n throw new Error(errorMessage);\n }\n } catch (exception) {\n throw new Error(`error registering definition: ${(exception as Error).message}`);\n }\n\n // Everything seems hunky-dory, register the subtree.\n Lookup.setSubtree(name, value);\n } else {\n throw new Error(\"unexpected value, expected string mdsl definition, root node json definition or function\");\n }\n }\n\n /**\n * Unregisters the registered action/condition/guard/callback function or subtree with the given name.\n * @param name The name of the registered action/condition/guard/callback function or subtree to unregister.\n */\n static unregister(name: string): void {\n Lookup.remove(name);\n }\n\n /**\n * Unregister all registered action/condition/guard/callback functions and subtrees.\n */\n static unregisterAll(): void {\n Lookup.empty();\n }\n\n /**\n * Parses a behaviour tree definition and creates a tree of behaviour tree nodes populated at a root.\n * @param {string | RootNodeDefinition | RootNodeDefinition[]} definition The behaviour tree definition.\n * @returns The root behaviour tree node.\n */\n private _createRootNode(definition: string | RootNodeDefinition | RootNodeDefinition[]): Root {\n // Our definition will have to be converted to JSON if it is a MDSL string.\n // TODO convertMDSLToJSON is called TWICE, once for validation and once here. Maybe return the JSON as part of the validation result?\n const resolvedDefinition = typeof definition === \"string\" ? convertMDSLToJSON(definition) : definition;\n\n // Build and populate the root node.\n return buildRootNode(Array.isArray(resolvedDefinition) ? resolvedDefinition : [resolvedDefinition]);\n }\n}\n"], + "mappings": "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", "names": ["Participant", "isNullOrUndefined", "Lotto", "createLotto", "State", "createLotto"] } diff --git a/dist/index.js b/dist/index.js index a4d2910..89bbd56 100644 --- a/dist/index.js +++ b/dist/index.js @@ -733,7 +733,7 @@ function createWaitNode(tokens, stringLiteralPlaceholders) { const nodeArguments = parseArgumentTokens(tokens, stringLiteralPlaceholders); if (nodeArguments.length) { nodeArguments.filter((arg) => arg.type !== "number" || !arg.isInteger).forEach(() => { - throw new Error(`wait node duration arguments must be integer values`); + throw new Error(`wait node durations must be integer values`); }); if (nodeArguments.length === 1) { node.duration = nodeArguments[0].value; @@ -787,8 +787,8 @@ function validateMDSLDefinition(definition) { let rootNodeDefinitions; try { rootNodeDefinitions = convertMDSLToJSON(definition); - } catch (error) { - return createValidationFailureResult(`invalid MDSL: ${error}`); + } catch (exception) { + return createValidationFailureResult(exception.message); } const mainRootNodeDefinitions = rootNodeDefinitions.filter(({ id }) => typeof id === "undefined"); const subRootNodeDefinitions = rootNodeDefinitions.filter(({ id }) => typeof id === "string" && id.length > 0); @@ -2138,6 +2138,10 @@ var BehaviourTree = class { if (typeof agent !== "object" || agent === null) { throw new Error("the agent must be an object and not null"); } + const { succeeded, errorMessage } = validateDefinition(definition); + if (!succeeded) { + throw new Error(`invalid definition: ${errorMessage}`); + } try { this.rootNode = this._createRootNode(definition); } catch (exception) { @@ -2231,16 +2235,7 @@ var BehaviourTree = class { Lookup.empty(); } _createRootNode(definition) { - let resolvedDefinition; - if (typeof definition === "string") { - try { - resolvedDefinition = convertMDSLToJSON(definition); - } catch (exception) { - throw new Error(`invalid mdsl definition: ${exception.message}`); - } - } else { - resolvedDefinition = definition; - } + const resolvedDefinition = typeof definition === "string" ? convertMDSLToJSON(definition) : definition; return buildRootNode(Array.isArray(resolvedDefinition) ? resolvedDefinition : [resolvedDefinition]); } }; diff --git a/dist/index.js.map b/dist/index.js.map index f1cfc8e..3d56922 100644 --- a/dist/index.js.map +++ b/dist/index.js.map @@ -1,7 +1,7 @@ { "version": 3, "sources": ["../node_modules/lotto-draw/dist/Participant.js", "../node_modules/lotto-draw/dist/Utilities.js", "../node_modules/lotto-draw/dist/Lotto.js", "../node_modules/lotto-draw/dist/createLotto.js", "../node_modules/lotto-draw/dist/index.js", "../src/index.ts", "../src/State.ts", "../src/BehaviourTreeDefinitionUtilities.ts", "../src/mdsl/MDSLUtilities.ts", "../src/mdsl/MDSLNodeArgumentParser.ts", "../src/mdsl/MDSLNodeAttributeParser.ts", "../src/mdsl/MDSLDefinitionParser.ts", "../src/BehaviourTreeDefinitionValidator.ts", "../src/Lookup.ts", "../src/attributes/guards/GuardUnsatisifedException.ts", "../src/attributes/guards/GuardPath.ts", "../src/nodes/Node.ts", "../src/nodes/composite/Composite.ts", "../src/nodes/composite/Parallel.ts", "../src/nodes/composite/Selector.ts", "../src/nodes/composite/Sequence.ts", "../src/nodes/composite/Lotto.ts", "../src/nodes/decorator/Decorator.ts", "../src/nodes/decorator/Fail.ts", "../src/nodes/decorator/Flip.ts", "../src/nodes/decorator/Repeat.ts", "../src/nodes/decorator/Retry.ts", "../src/nodes/decorator/Root.ts", "../src/nodes/decorator/Succeed.ts", "../src/nodes/leaf/Leaf.ts", "../src/nodes/leaf/Action.ts", "../src/nodes/leaf/Condition.ts", "../src/nodes/leaf/Wait.ts", "../src/attributes/Attribute.ts", "../src/attributes/guards/Guard.ts", "../src/attributes/guards/While.ts", "../src/attributes/guards/Until.ts", "../src/attributes/callbacks/Callback.ts", "../src/attributes/callbacks/Entry.ts", "../src/attributes/callbacks/Step.ts", "../src/attributes/callbacks/Exit.ts", "../src/BehaviourTreeBuilder.ts", "../src/BehaviourTree.ts"], - "sourcesContent": ["\"use strict\";\r\nObject.defineProperty(exports, \"__esModule\", { value: true });\r\nexports.Participant = void 0;\r\n/**\r\n * A participant that holds a number of tickets.\r\n */\r\nvar Participant = /** @class */ (function () {\r\n /**\r\n * Creates an instance of the Participant class.\r\n * @param participant The actual participant.\r\n * @param tickets The number of tickets held by the participant.\r\n */\r\n function Participant(participant, tickets) {\r\n if (tickets === void 0) { tickets = 1; }\r\n this._participant = participant;\r\n this._tickets = tickets;\r\n }\r\n Object.defineProperty(Participant.prototype, \"participant\", {\r\n /** Gets the actual participant. */\r\n get: function () {\r\n return this._participant;\r\n },\r\n enumerable: false,\r\n configurable: true\r\n });\r\n Object.defineProperty(Participant.prototype, \"tickets\", {\r\n /** Gets or sets the number of tickets held by the participant. */\r\n get: function () {\r\n return this._tickets;\r\n },\r\n set: function (value) {\r\n this._tickets = value;\r\n },\r\n enumerable: false,\r\n configurable: true\r\n });\r\n return Participant;\r\n}());\r\nexports.Participant = Participant;\r\n", "\"use strict\";\r\nObject.defineProperty(exports, \"__esModule\", { value: true });\r\nexports.isNaturalNumber = exports.isNullOrUndefined = void 0;\r\n/**\r\n * Gets whether the value provided is null or undefined.\r\n * @param value The value to check.\r\n * @returns Whether the value provided is null or undefined.\r\n */\r\nfunction isNullOrUndefined(value) {\r\n return value === null || value === undefined;\r\n}\r\nexports.isNullOrUndefined = isNullOrUndefined;\r\n/**\r\n * Gets whether the value provided is a natural number.\r\n * @param value The value to check.\r\n * @returns Whether the value provided is a natural number.\r\n */\r\nfunction isNaturalNumber(value) {\r\n return typeof value === \"number\" && value >= 1 && Math.floor(value) === value;\r\n}\r\nexports.isNaturalNumber = isNaturalNumber;\r\n", "\"use strict\";\r\nObject.defineProperty(exports, \"__esModule\", { value: true });\r\nexports.Lotto = void 0;\r\nvar Participant_1 = require(\"./Participant\");\r\nvar Utilities_1 = require(\"./Utilities\");\r\n/**\r\n * Represents a lotto consisting of a number of pickable ticket-holding participants.\r\n */\r\nvar Lotto = /** @class */ (function () {\r\n /**\r\n * Creates a new instance of Lotto.\r\n * @param customRandom The custom RNG to use in place of Math.random().\r\n */\r\n function Lotto(customRandom) {\r\n /** The array of participants that are holding tickets in the lotto. */\r\n this._participants = [];\r\n this._customRandom = customRandom;\r\n }\r\n /**\r\n * Adds a participant with the specified number of tickets, or adds to the participant ticket count if the participant already holds tickets.\r\n * @param participant The participant to add or to increase the ticket count for if they already hold tickets.\r\n * @param tickets The number of tickets, defaults to 1.\r\n * @returns The Lotto instance.\r\n */\r\n Lotto.prototype.add = function (participant, tickets) {\r\n if (tickets === void 0) { tickets = 1; }\r\n // Check that we have a valid ticket count.\r\n if (!(0, Utilities_1.isNaturalNumber)(tickets)) {\r\n throw new Error(\"tickets value must be a natural number\");\r\n }\r\n // Check whether this participant has already been added.\r\n var existingParticipant = this._participants.find(function (part) { return part.participant === participant; });\r\n if (existingParticipant) {\r\n // The participant has already been added to the lotto so just add to their ticket count.\r\n existingParticipant.tickets += tickets;\r\n }\r\n else {\r\n // The participant is not part of the lotto so we should add them.\r\n this._participants.push(new Participant_1.Participant(participant, tickets));\r\n }\r\n return this;\r\n };\r\n /**\r\n * Removes the specified number of tickets for the given participant from the draw, or all tickets if a ticket number is not defined.\r\n * @param participant The participant to remove tickets for.\r\n * @param tickets The number of tickets to remove, or undefined if all tickets are to be removed.\r\n * @returns The Lotto instance.\r\n */\r\n Lotto.prototype.remove = function (participant, tickets) {\r\n // Attempt to get the existing participant.\r\n var existingParticipant = this._participants.find(function (part) { return part.participant === participant; });\r\n // There is nothing to do if the specified participant isn't even part of the lotto.\r\n if (!existingParticipant) {\r\n return this;\r\n }\r\n // Check whether a tickets value was given.\r\n if (tickets !== undefined) {\r\n // Check that we have a valid ticket count.\r\n if (!(0, Utilities_1.isNaturalNumber)(tickets)) {\r\n throw new Error(\"tickets value must be a natural number\");\r\n }\r\n existingParticipant.tickets -= tickets;\r\n // If the participant no longer holds any tickets then they should be removed.\r\n if (existingParticipant.tickets < 1) {\r\n this._participants = this._participants.filter(function (part) { return part !== existingParticipant; });\r\n }\r\n }\r\n else {\r\n // We are removing all tickets for the participant so just remove them from the lotto.\r\n this._participants = this._participants.filter(function (part) { return part !== existingParticipant; });\r\n }\r\n return this;\r\n };\r\n /**\r\n * Draw a winning ticket and return the participant that holds the ticket.\r\n * @param options The draw options.\r\n * @returns The participant that holds the winning ticket.\r\n */\r\n Lotto.prototype.draw = function (options) {\r\n if (options === void 0) { options = {}; }\r\n // If we have no participants then just return null.\r\n if (this._participants.length === 0) {\r\n return null;\r\n }\r\n var redrawable = (0, Utilities_1.isNullOrUndefined)(options.redrawable) ? true : options.redrawable;\r\n var pickable = [];\r\n this._participants.forEach(function (_a) {\r\n var participant = _a.participant, tickets = _a.tickets;\r\n for (var ticketCount = 0; ticketCount < tickets; ticketCount++) {\r\n pickable.push(participant);\r\n }\r\n });\r\n var random;\r\n // We need a random floating-point number between 0 (inclusive) and 1 to scale up to pick our winner.\r\n // If a custom random function exists then we should use that or fall back to Math.random().\r\n if (this._customRandom) {\r\n // Call our custom random function to get a random floating-point number.\r\n random = this._customRandom();\r\n // Verify that the result of calling our custom random function is a number between 0 (inclusive) and 1.\r\n if (typeof random !== \"number\" || random < 0 || random >= 1) {\r\n throw new Error(\"the 'random' function provided did not return a number between 0 (inclusive) and 1\");\r\n }\r\n }\r\n else {\r\n // No custom random function was defined so just use good ol' Math.random().\r\n random = Math.random();\r\n }\r\n // Pick a winning participant.\r\n var winner = pickable[Math.floor(random * pickable.length)];\r\n // If the ticket isn't redrawable then we should remove a ticket from the winning participants ticket count.\r\n if (!redrawable) {\r\n this.remove(winner, 1);\r\n }\r\n // Return the winning participant.\r\n return winner;\r\n };\r\n /**\r\n * Draws multiple winning tickets and return an array of the participants that hold the winning tickets.\r\n * @param tickets The number of winning tickets to draw.\r\n * @param options The draw multiple options.\r\n * @returns An array of the participants that hold the winning tickets.\r\n */\r\n Lotto.prototype.drawMultiple = function (tickets, options) {\r\n if (options === void 0) { options = {}; }\r\n var uniqueResults = (0, Utilities_1.isNullOrUndefined)(options.unique) ? false : options.unique;\r\n // Handle cases where the user has asked for zero tickets (no idea why they would do this be we should trust them).\r\n if (tickets === 0) {\r\n return [];\r\n }\r\n // Now that we know out tickets value is not zero we should check that it is a valid natural number.\r\n if (!(0, Utilities_1.isNaturalNumber)(tickets)) {\r\n throw new Error(\"tickets value must be a natural number\");\r\n }\r\n var result = [];\r\n // Keep drawing tickets until we either reach the number of required tickets or we simply run out of tickets to draw.\r\n // We can run out of tickets to draw if 'options.redrawable' is explicity 'false' or we just had no participants when 'drawMultiple' was called.\r\n while (result.length < tickets && this._participants.length > 0) {\r\n result.push(this.draw(options));\r\n }\r\n // If the 'unique' draw option is set then we need to remove duplicates from the result list.\r\n if (uniqueResults) {\r\n // Create an array to store our unique results.\r\n var unique = [];\r\n // Iterate over all of our participants (with potential duplicates) and populate our array of unique values.\r\n for (var _i = 0, result_1 = result; _i < result_1.length; _i++) {\r\n var participant = result_1[_i];\r\n if (unique.indexOf(participant) === -1) {\r\n unique.push(participant);\r\n }\r\n }\r\n result = unique;\r\n }\r\n return result;\r\n };\r\n return Lotto;\r\n}());\r\nexports.Lotto = Lotto;\r\n", "\"use strict\";\r\nObject.defineProperty(exports, \"__esModule\", { value: true });\r\nexports.createLotto = void 0;\r\nvar Lotto_1 = require(\"./Lotto\");\r\n/**\r\n * A function that creates and returns a Lotto instance.\r\n * @param participantsOrOptions An array of initial participants or options relating to the creation of a Lotto instance.\r\n * @returns A new Lotto instance.\r\n */\r\nfunction createLotto(participantsOrOptions) {\r\n // If no initial participants or lotto options were provided as an argument then we can just return a new lotto instance now.\r\n if (!participantsOrOptions) {\r\n return new Lotto_1.Lotto();\r\n }\r\n // Check whether we were provided with an array of initial participants or a lotto options object.\r\n if (Array.isArray(participantsOrOptions)) {\r\n // We are dealing with a pre-defined array of participants.\r\n var participants = participantsOrOptions;\r\n var lotto_1 = new Lotto_1.Lotto();\r\n // If the lotto participants have been defined upfront then we will need to add them all to our lotto instance now.\r\n participants.forEach(function (_a) {\r\n var participant = _a[0], tokens = _a[1];\r\n return lotto_1.add(participant, tokens);\r\n });\r\n // Return the Lotto instance.\r\n return lotto_1;\r\n }\r\n else {\r\n // We are dealing with some lotto options.\r\n var random = participantsOrOptions.random, participants = participantsOrOptions.participants;\r\n // Create a Lotto instance passing the custom RNG function to use in place of Math.random() (which could be undefined).\r\n var lotto_2 = new Lotto_1.Lotto(random);\r\n // If the lotto participants have been defined upfront as part of the options then we will need to add them all to our lotto instance now.\r\n if (participants) {\r\n participants.forEach(function (_a) {\r\n var participant = _a[0], tokens = _a[1];\r\n return lotto_2.add(participant, tokens);\r\n });\r\n }\r\n // Return the Lotto instance.\r\n return lotto_2;\r\n }\r\n}\r\nexports.createLotto = createLotto;\r\n", "\"use strict\";\r\nObject.defineProperty(exports, \"__esModule\", { value: true });\r\nvar createLotto_1 = require(\"./createLotto\");\r\nexports.default = createLotto_1.createLotto;\r\n", "import State from \"./State\";\nimport { validateDefinition } from \"./BehaviourTreeDefinitionValidator\";\nimport { convertMDSLToJSON } from \"./mdsl/MDSLDefinitionParser\";\nimport { BehaviourTree, FlattenedTreeNode } from \"./BehaviourTree\";\nimport { BehaviourTreeOptions } from \"./BehaviourTreeOptions\";\n\nexport { BehaviourTree, State, convertMDSLToJSON, validateDefinition };\nexport type { FlattenedTreeNode, BehaviourTreeOptions };\n", "/**\n * Enumeration of node state types.\n */\nexport enum State {\n READY = \"mistreevous.ready\",\n RUNNING = \"mistreevous.running\",\n SUCCEEDED = \"mistreevous.succeeded\",\n FAILED = \"mistreevous.failed\"\n}\n\nexport { State as default };\n\nexport type CompleteState = State.SUCCEEDED | State.FAILED;\nexport type AnyState = State.READY | State.RUNNING | CompleteState;\n", "import {\n NodeDefinition,\n RootNodeDefinition,\n DecoratorNodeDefinition,\n CompositeNodeDefinition,\n AnyNodeDefinition,\n BranchNodeDefinition\n} from \"./BehaviourTreeDefinition\";\n\n/**\n * A type guard function that returns true if the specified node satisfies the RootNodeDefinition type.\n * @param node The node.\n * @returns A value of true if the specified node satisfies the RootNodeDefinition type.\n */\nexport function isRootNode(node: NodeDefinition): node is RootNodeDefinition {\n return node.type === \"root\";\n}\n\n/**\n * A type guard function that returns true if the specified node satisfies the BranchNodeDefinition type.\n * @param node The node.\n * @returns A value of true if the specified node satisfies the BranchNodeDefinition type.\n */\nexport function isBranchNode(node: NodeDefinition): node is BranchNodeDefinition {\n return node.type === \"branch\";\n}\n\n/**\n * A type guard function that returns true if the specified node satisfies the NodeDefinition type.\n * @param node The node.\n * @returns A value of true if the specified node satisfies the NodeDefinition type.\n */\nexport function isLeafNode(node: NodeDefinition): node is NodeDefinition {\n return [\"branch\", \"action\", \"condition\", \"wait\"].includes(node.type);\n}\n\n/**\n * A type guard function that returns true if the specified node satisfies the DecoratorNodeDefinition type.\n * @param node The node.\n * @returns A value of true if the specified node satisfies the DecoratorNodeDefinition type.\n */\nexport function isDecoratorNode(node: NodeDefinition): node is DecoratorNodeDefinition {\n return [\"root\", \"repeat\", \"retry\", \"flip\", \"succeed\", \"fail\"].includes(node.type);\n}\n\n/**\n * A type guard function that returns true if the specified node satisfies the CompositeNodeDefinition type.\n * @param node The node.\n * @returns A value of true if the specified node satisfies the CompositeNodeDefinition type.\n */\nexport function isCompositeNode(node: NodeDefinition): node is CompositeNodeDefinition {\n return [\"sequence\", \"selector\", \"lotto\", \"parallel\"].includes(node.type);\n}\n\n/**\n * Flatten a node definition into an array of all of its nested node definitions.\n * @param nodeDefinition The node definition to flatten.\n * @returns An array of all of nested node definitions.\n */\nexport function flattenDefinition(nodeDefinition: AnyNodeDefinition): AnyNodeDefinition[] {\n const nodes: AnyNodeDefinition[] = [];\n\n const processNode = (currentNodeDefinition: AnyNodeDefinition) => {\n nodes.push(currentNodeDefinition);\n\n if (isCompositeNode(currentNodeDefinition)) {\n currentNodeDefinition.children.forEach(processNode);\n } else if (isDecoratorNode(currentNodeDefinition)) {\n processNode(currentNodeDefinition.child);\n }\n };\n\n processNode(nodeDefinition);\n\n return nodes;\n}\n\n/**\n * Determines whether the passed value is an integer.\n * @param value The value to check.\n * @returns Whether the passed value is an integer.\n */\nexport function isInteger(value: unknown): boolean {\n return typeof value === \"number\" && Math.floor(value) === value;\n}\n\n/**\n * Determines whether the passed value is null or undefined.\n * @param value The value to check.\n * @returns Whether the passed value is null or undefined.\n */\nexport function isNullOrUndefined(value: unknown): boolean {\n return typeof value === \"undefined\" || value === null;\n}\n", "/**\n * A type defining an object that holds a reference to substitued string literals parsed from the definition.\n */\nexport type StringLiteralPlaceholders = { [key: string]: string };\n\n/**\n * Pop the next raw token from the specified array of tokens and throw an error if it wasn't the expected one.\n * @param tokens The array of tokens.\n * @param expected An optional string or array or items, one of which must match the next popped token.\n * @returns The popped token.\n */\nexport function popAndCheck(tokens: string[], expected?: string | string[]): string {\n // Get and remove the next token.\n const popped = tokens.shift();\n\n // We were expecting another token but there aren't any.\n if (popped === undefined) {\n throw new Error(\"unexpected end of definition\");\n }\n\n // Do we have an expected token/tokens array?\n if (expected != undefined) {\n // Get an array of expected values, if the popped token matches any then we are all good.\n const expectedValues = typeof expected === \"string\" ? [expected] : expected;\n\n // Check whether the popped token matches at least one of our expected items.\n var tokenMatchesExpectation = expectedValues.some((item) => popped.toUpperCase() === item.toUpperCase());\n\n // Throw an error if the popped token didn't match any of our expected items.\n if (!tokenMatchesExpectation) {\n const expectationString = expectedValues.map((item) => \"'\" + item + \"'\").join(\" or \");\n throw new Error(\"unexpected token found. Expected \" + expectationString + \" but got '\" + popped + \"'\");\n }\n }\n\n // Return the popped token.\n return popped;\n}\n\n/**\n * Swaps out any node/attribute argument string literals with placeholders.\n * @param definition The definition.\n * @returns An object containing a mapping of placeholders to original string values as well as the processed definition string.\n */\nexport function substituteStringLiterals(definition: string): {\n placeholders: StringLiteralPlaceholders;\n processedDefinition: string;\n} {\n // Create an object to hold the mapping of placeholders to original string values.\n const placeholders: StringLiteralPlaceholders = {};\n\n // Replace any string literals wrapped with double quotes in our definition with placeholders to be processed later.\n const processedDefinition = definition.replace(/\\\"(\\\\.|[^\"\\\\])*\\\"/g, (match) => {\n var strippedMatch = match.substring(1, match.length - 1);\n var placeholder = Object.keys(placeholders).find((key) => placeholders[key] === strippedMatch);\n\n // If we have no existing string literal match then create a new placeholder.\n if (!placeholder) {\n placeholder = `@@${Object.keys(placeholders).length}@@`;\n placeholders[placeholder] = strippedMatch;\n }\n\n return placeholder;\n });\n\n return { placeholders, processedDefinition };\n}\n\n/**\n * Parse the tree definition into an array of raw tokens.\n * @param definition The definition.\n * @returns An array of tokens parsed from the definition.\n */\nexport function parseTokensFromDefinition(definition: string): string[] {\n // Add some space around various important characters so that they can be plucked out easier as individual tokens.\n definition = definition.replace(/\\(/g, \" ( \");\n definition = definition.replace(/\\)/g, \" ) \");\n definition = definition.replace(/\\{/g, \" { \");\n definition = definition.replace(/\\}/g, \" } \");\n definition = definition.replace(/\\]/g, \" ] \");\n definition = definition.replace(/\\[/g, \" [ \");\n definition = definition.replace(/\\,/g, \" , \");\n\n // Split the definition into raw token form and return it.\n return definition.replace(/\\s+/g, \" \").trim().split(\" \");\n}\n", "import { StringLiteralPlaceholders, popAndCheck } from \"./MDSLUtilities\";\n\n/**\n * A type representing any node function argument.\n */\ntype Argument = {\n /**\n * The argument value.\n */\n value: T;\n /**\n * The argument type, used for validation.\n */\n type: string;\n};\n\ntype NullArgument = Argument & {\n type: \"null\";\n};\n\ntype BooleanArgument = Argument & {\n type: \"boolean\";\n};\n\ntype NumberArgument = Argument & {\n type: \"number\";\n /**\n * A flag defining whether the number argument value is a valid integer. (used for validation)\n */\n isInteger: boolean;\n};\n\ntype StringPlaceholderArgument = Argument & {\n type: \"string\";\n};\n\ntype IdentifierArgument = Argument & {\n type: \"identifier\";\n};\n\n/**\n * A type representing a reference to any node function argument.\n */\ntype AnyArgument = NullArgument | BooleanArgument | NumberArgument | StringPlaceholderArgument | IdentifierArgument;\n\n/**\n * Parse an array of argument definitions from the specified tokens array.\n * @param tokens The array tokens to parse the argument definitions from.\n * @param stringArgumentPlaceholders The mapping of string literal node argument placeholders to original values.\n * @param argumentValidator The argument validator function.\n * @param validationFailedMessage The exception message to throw if argument validation fails.\n * @returns An array of argument definitions parsed from the specified tokens array.\n */\nexport function parseArgumentTokens(\n tokens: string[],\n stringArgumentPlaceholders: StringLiteralPlaceholders\n): AnyArgument[] {\n const argumentList: AnyArgument[] = [];\n\n // If the next token is not a '[' or '(' then we have no arguments to parse.\n if (![\"[\", \"(\"].includes(tokens[0])) {\n return argumentList;\n }\n\n // Any lists of arguments will always be wrapped in '[]' for node arguments or '()' for attribute arguments.\n // We are looking for a '[' or '(' opener that wraps the argument tokens and the relevant closer.\n const closingToken = popAndCheck(tokens, [\"[\", \"(\"]) === \"[\" ? \"]\" : \")\";\n\n const argumentListTokens: string[] = [];\n\n // Grab all tokens between the '[' and ']' or '(' and ')'.\n while (tokens.length && tokens[0] !== closingToken) {\n // The next token is part of our arguments list.\n argumentListTokens.push(tokens.shift()!);\n }\n\n // Validate the order of the argument tokens. Each token must either be a ',' or a single argument that satisfies the validator.\n argumentListTokens.forEach((token, index) => {\n // Get whether this token should be an actual argument.\n const shouldBeArgumentToken = !(index & 1);\n\n // If the current token should be an actual argument then validate it, otherwise it should be a ',' token.\n if (shouldBeArgumentToken) {\n // Get the argument definition.\n const argumentDefinition = getArgumentDefinition(token, stringArgumentPlaceholders);\n\n // This is a valid argument!\n argumentList.push(argumentDefinition);\n } else {\n // The current token should be a ',' token.\n if (token !== \",\") {\n throw new Error(`invalid argument list, expected ',' or ']' but got '${token}'`);\n }\n }\n });\n\n // The arguments list should terminate with a ']' or ')' token, depending on the opener.\n popAndCheck(tokens, closingToken);\n\n // Return the arguments.\n return argumentList;\n}\n\n/**\n * Gets an argument value definition.\n * @param token The argument token.\n * @param stringArgumentPlaceholders The mapping of string literal node argument placeholders to original values.\n * @returns An argument value definition.\n */\nfunction getArgumentDefinition(token: string, stringArgumentPlaceholders: StringLiteralPlaceholders): AnyArgument {\n // Check whether the token represents a null value.\n if (token === \"null\") {\n return {\n value: null,\n type: \"null\"\n } as NullArgument;\n }\n\n // Check whether the token represents a boolean value.\n if (token === \"true\" || token === \"false\") {\n return {\n value: token === \"true\",\n type: \"boolean\"\n } as BooleanArgument;\n }\n\n // Check whether the token represents a number value.\n // TODO: Relies on broken isNaN - see MDN.\n // if (!Number.isNaN(token)) {\n if (!isNaN(token as any)) {\n return {\n value: parseFloat(token),\n isInteger: parseFloat(token) === parseInt(token, 10),\n type: \"number\"\n } as NumberArgument;\n }\n\n // Check whether the token is a placeholder (e.g. @@0@@) representing a string literal.\n if (token.match(/^@@\\d+@@$/g)) {\n return {\n value: stringArgumentPlaceholders[token].replace('\\\\\"', '\"'),\n type: \"string\"\n } as StringPlaceholderArgument;\n }\n\n // The only remaining option is that the argument value is an identifier.\n return {\n value: token,\n type: \"identifier\"\n } as IdentifierArgument;\n}\n", "import { NodeAttributeDefinition } from \"../BehaviourTreeDefinition\";\nimport { parseArgumentTokens } from \"./MDSLNodeArgumentParser\";\nimport { StringLiteralPlaceholders } from \"./MDSLUtilities\";\n\n/**\n * A type defining the attribute definitions of a node.\n */\ntype NodeAttributes = {\n while?: NodeAttributeDefinition;\n until?: NodeAttributeDefinition;\n entry?: NodeAttributeDefinition;\n exit?: NodeAttributeDefinition;\n step?: NodeAttributeDefinition;\n};\n\n/**\n * Parse any node attribute definitions from the specified tokens array.\n * @param tokens The array of remaining tokens.\n * @param stringArgumentPlaceholders The mapping of string literal node argument placeholders to original values.\n * @returns An object of attribute definitions defined by any directly following tokens.\n */\nexport function parseAttributeTokens(\n tokens: string[],\n stringArgumentPlaceholders: StringLiteralPlaceholders\n): NodeAttributes {\n const nodeAttributeNames: (keyof NodeAttributes)[] = [\"while\", \"until\", \"entry\", \"exit\", \"step\"];\n\n // Create an object to hold any attributes found.\n const attributes: NodeAttributes = {};\n\n // Try to get the name of the attribute for the next token.\n let nextAttributeName = tokens[0]?.toLowerCase() as keyof NodeAttributes;\n\n // Pull attribute tokens as well as their arguments off of the tokens stack until we have no more.\n while (nodeAttributeNames.includes(nextAttributeName)) {\n // Check to make sure that we have not already created an attribute definition of this type.\n if (attributes[nextAttributeName]) {\n throw new Error(`duplicate attribute '${tokens[0].toUpperCase()}' found for node`);\n }\n\n // Remove the attribute name token from the array of tokens.\n tokens.shift();\n\n // Grab the attribute arguments, assuming the first to be an identifier.\n const [attributeCallIdentifier, ...attributeArguments] = parseArgumentTokens(\n tokens,\n stringArgumentPlaceholders\n );\n\n // The first attribute argument has to be an identifer, this will reference an agent function.\n if (attributeCallIdentifier?.type !== \"identifier\") {\n throw new Error(\"expected agent function name identifier argument for attribute\");\n }\n\n // Any attribute arguments (other than the expected call identifier) must have a type of string, number, boolean or null.\n attributeArguments\n .filter((arg) => arg.type === \"identifier\")\n .forEach((arg) => {\n throw new Error(\n `invalid attribute argument value '${arg.value}', must be string, number, boolean or null`\n );\n });\n\n // Create the attribute definition and add it to the object of attribute definitions found.\n attributes[nextAttributeName] = {\n call: attributeCallIdentifier.value,\n args: attributeArguments.map(({ value }) => value)\n };\n\n // Try to get the next attribute name token, as there could be multiple.\n nextAttributeName = tokens[0]?.toLowerCase() as keyof NodeAttributes;\n }\n\n return attributes;\n}\n", "import {\n ActionNodeDefinition,\n AnyChildNodeDefinition,\n AnyNodeDefinition,\n BranchNodeDefinition,\n ConditionNodeDefinition,\n FailNodeDefinition,\n FlipNodeDefinition,\n LottoNodeDefinition,\n ParallelNodeDefinition,\n RepeatNodeDefinition,\n RetryNodeDefinition,\n RootNodeDefinition,\n SelectorNodeDefinition,\n SequenceNodeDefinition,\n SucceedNodeDefinition,\n WaitNodeDefinition\n} from \"../BehaviourTreeDefinition\";\nimport {\n isCompositeNode,\n isDecoratorNode,\n isLeafNode,\n isNullOrUndefined,\n isRootNode\n} from \"../BehaviourTreeDefinitionUtilities\";\nimport { parseArgumentTokens } from \"./MDSLNodeArgumentParser\";\nimport { parseAttributeTokens } from \"./MDSLNodeAttributeParser\";\nimport {\n StringLiteralPlaceholders,\n parseTokensFromDefinition,\n popAndCheck,\n substituteStringLiterals\n} from \"./MDSLUtilities\";\n\n/**\n * Convert the MDSL tree definition string into an equivalent JSON definition.\n * @param definition The tree definition string as MDSL.\n * @returns The root node JSON definitions.\n */\nexport function convertMDSLToJSON(definition: string): RootNodeDefinition[] {\n // Swap out any node/attribute argument string literals with a placeholder and get a mapping of placeholders to original values as well as the processed definition.\n const { placeholders, processedDefinition } = substituteStringLiterals(definition);\n\n // Parse our definition definition string into an array of raw tokens.\n const tokens = parseTokensFromDefinition(processedDefinition);\n\n return convertTokensToJSONDefinition(tokens, placeholders);\n}\n\n/**\n * Converts the specified tree definition tokens into a JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The root node JSON definitions.\n */\nfunction convertTokensToJSONDefinition(\n tokens: string[],\n stringLiteralPlaceholders: StringLiteralPlaceholders\n): RootNodeDefinition[] {\n // There must be at least 3 tokens for the tree definition to be valid. 'ROOT', '{' and '}'.\n if (tokens.length < 3) {\n throw new Error(\"invalid token count\");\n }\n\n // We should have a matching number of '{' and '}' tokens. If not, then there are scopes that have not been properly closed.\n if (tokens.filter((token) => token === \"{\").length !== tokens.filter((token) => token === \"}\").length) {\n throw new Error(\"scope character mismatch\");\n }\n\n // Create an array of tree stack arrays where root nodes will always be at the botton and the current composite/decorator node at the top.\n // There should be an element in this array for every root node defined and every element should be an array with a root note as the first element.\n // E.g. A definition with two root nodes defined:\n // [\n // [root, lotto, sequence],\n // [root, selector]\n // ]\n const treeStacks: [Partial, ...Partial[]][] = [];\n\n // Create an array of all root node definitions that we create.\n const rootNodes: Partial[] = [];\n\n // A helper function used to push node definitions onto the tree stack.\n const pushNode = (node: AnyNodeDefinition) => {\n // If the node is a root node then we need to create a new tree stack array with the root node at the root.\n if (isRootNode(node)) {\n // We need to double-check that this root node is not the child of another node.\n // We can do this by checking whether the top tree stack is not empty (contains an existing node)\n if (treeStacks[treeStacks.length - 1]?.length) {\n throw new Error(\"a root node cannot be the child of another node\");\n }\n\n // Add the root node definition to our array of all parsed root node definitions.\n rootNodes.push(node);\n\n // Add the root node definition to the root of a new tree stack.\n treeStacks.push([node]);\n\n return;\n }\n\n // All non-root nodes should be pushed after their root nodes so handle cases\n // where we may not have any tree stacks or our top-most tree stack is empty.\n if (!treeStacks.length || !treeStacks[treeStacks.length - 1].length) {\n throw new Error(\"expected root node at base of definition\");\n }\n\n // Get the current tree stack that we are populating.\n const topTreeStack = treeStacks[treeStacks.length - 1];\n\n // Get the top-most node in the current tree stack, this will be a composite/decorator node\n // for which we will populate its children array if composite or setting its child if a decorator.\n const topTreeStackTopNode = topTreeStack[topTreeStack.length - 1] as AnyNodeDefinition;\n\n // If the top-most node in the current root stack is a composite or decorator\n // node then the current node should be added as a child of the top-most node.\n if (isCompositeNode(topTreeStackTopNode)) {\n topTreeStackTopNode.children = topTreeStackTopNode.children || [];\n topTreeStackTopNode.children.push(node);\n } else if (isDecoratorNode(topTreeStackTopNode)) {\n // If the top node already has a child node set then throw an error as a decorator should only have a single child.\n if (topTreeStackTopNode.child) {\n throw new Error(\"a decorator node must only have a single child node\");\n }\n\n topTreeStackTopNode.child = node;\n }\n\n // If the node we are adding is also a composite or decorator node, then we should push it\n // onto the current tree stack, as subsequent nodes will be added as its child/children.\n if (!isLeafNode(node)) {\n topTreeStack.push(node);\n }\n };\n\n // A helper function used to pop the top-most node definition off of the tree stack and return it.\n const popNode = (): AnyNodeDefinition | null => {\n let poppedNode: AnyNodeDefinition | null = null;\n\n // Get the current tree stack that we are populating.\n const topTreeStack = treeStacks[treeStacks.length - 1];\n\n // Pop the top-most node in the current tree stack if there is one.\n if (topTreeStack.length) {\n poppedNode = topTreeStack.pop() as AnyNodeDefinition;\n }\n\n // We don't want any empty tree stacks in our stack of tree stacks.\n if (!topTreeStack.length) {\n treeStacks.pop();\n }\n\n return poppedNode;\n };\n\n // We should keep processing the raw tokens until we run out of them.\n while (tokens.length) {\n // Grab the next token.\n const token = tokens.shift()!;\n\n // How we create the next node depends on the current raw token value.\n switch (token.toUpperCase()) {\n case \"ROOT\": {\n pushNode(createRootNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"SUCCEED\": {\n pushNode(createSucceedNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"FAIL\": {\n pushNode(createFailNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"FLIP\": {\n pushNode(createFlipNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"REPEAT\": {\n pushNode(createRepeatNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"RETRY\": {\n pushNode(createRetryNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"SEQUENCE\": {\n pushNode(createSequenceNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"SELECTOR\": {\n pushNode(createSelectorNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"PARALLEL\": {\n pushNode(createParallelNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"LOTTO\": {\n pushNode(createLottoNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"ACTION\": {\n pushNode(createActionNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"CONDITION\": {\n pushNode(createConditionNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"WAIT\": {\n pushNode(createWaitNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"BRANCH\": {\n pushNode(createBranchNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"}\": {\n // The '}' character closes the current scope and means that we have to pop a node off of the current stack.\n const poppedNode = popNode();\n\n // Now that we have a node definition we can carry out any validation that may require the node to be fully populated.\n if (poppedNode) {\n validatePoppedNode(poppedNode);\n }\n\n break;\n }\n\n default: {\n throw new Error(`unexpected token: ${token}`);\n }\n }\n }\n\n return rootNodes as RootNodeDefinition[];\n}\n\n/**\n * Creates a root node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The root node JSON definition.\n */\nfunction createRootNode(tokens: string[], stringLiteralPlaceholders: StringLiteralPlaceholders): RootNodeDefinition {\n // Create the root node definition.\n let node = {\n type: \"root\",\n id: undefined\n } as RootNodeDefinition;\n\n // Parse any node arguments, we should only have one if any which will be an identifier argument for the root identifier.\n const nodeArguments = parseArgumentTokens(tokens, stringLiteralPlaceholders);\n\n // Check whether any node arguments were defined.\n if (nodeArguments.length) {\n // We should only have one argument, if any, which will be an identifier argument for the root identifier.\n if (nodeArguments.length === 1 && nodeArguments[0].type === \"identifier\") {\n // The root node identifier will be the first and only node argument value.\n node.id = nodeArguments[0].value as string;\n } else {\n throw new Error(\"expected single root name argument\");\n }\n }\n\n // Grab any node attribute definitions and spread them into the node definition.\n node = { ...node, ...parseAttributeTokens(tokens, stringLiteralPlaceholders) };\n\n // This is a decorator node, so we expect an opening '{'.\n popAndCheck(tokens, \"{\");\n\n // Return the root node definition.\n return node;\n}\n\n/**\n * Creates a succeed node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The succeed node JSON definition.\n */\nfunction createSucceedNode(\n tokens: string[],\n stringLiteralPlaceholders: StringLiteralPlaceholders\n): SucceedNodeDefinition {\n const node = {\n type: \"succeed\",\n ...parseAttributeTokens(tokens, stringLiteralPlaceholders)\n } as SucceedNodeDefinition;\n\n // This is a decorator node, so we expect an opening '{'.\n popAndCheck(tokens, \"{\");\n\n // Return the succeed node definition.\n return node;\n}\n\n/**\n * Creates a fail node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The fail node JSON definition.\n */\nfunction createFailNode(tokens: string[], stringLiteralPlaceholders: StringLiteralPlaceholders): FailNodeDefinition {\n const node = {\n type: \"fail\",\n ...parseAttributeTokens(tokens, stringLiteralPlaceholders)\n } as FailNodeDefinition;\n\n // This is a decorator node, so we expect an opening '{'.\n popAndCheck(tokens, \"{\");\n\n // Return the fail node definition.\n return node;\n}\n\n/**\n * Creates a flip node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The flip node JSON definition.\n */\nfunction createFlipNode(tokens: string[], stringLiteralPlaceholders: StringLiteralPlaceholders): FlipNodeDefinition {\n const node = {\n type: \"flip\",\n ...parseAttributeTokens(tokens, stringLiteralPlaceholders)\n } as FlipNodeDefinition;\n\n // This is a decorator node, so we expect an opening '{'.\n popAndCheck(tokens, \"{\");\n\n // Return the flip node definition.\n return node;\n}\n\n/**\n * Creates a repeat node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The repeat node JSON definition.\n */\nfunction createRepeatNode(\n tokens: string[],\n stringLiteralPlaceholders: StringLiteralPlaceholders\n): RepeatNodeDefinition {\n let node = { type: \"repeat\" } as RepeatNodeDefinition;\n\n // Get the node arguments.\n const nodeArguments = parseArgumentTokens(tokens, stringLiteralPlaceholders);\n\n // The arguments of a repeat node are optional. We may have:\n // - No node arguments, in which case the repeat note will iterate indefinitely.\n // - One node argument which will be the explicit number of iterations to make.\n // - Two node arguments which define the min and max iteration bounds from which a random iteration count will be picked.\n if (nodeArguments.length) {\n // All repeat node arguments MUST be of type number and must be integer.\n nodeArguments\n .filter((arg) => arg.type !== \"number\" || !arg.isInteger)\n .forEach(() => {\n throw new Error(`repeat node iteration counts must be integer values`);\n });\n\n // We should have got one or two iteration counts.\n if (nodeArguments.length === 1) {\n // A static iteration count was defined.\n node.iterations = nodeArguments[0].value as number;\n\n // A repeat node must have a positive number of iterations if defined.\n if (node.iterations < 0) {\n throw new Error(\"a repeat node must have a positive number of iterations if defined\");\n }\n } else if (nodeArguments.length === 2) {\n // A minimum and maximum iteration count was defined.\n node.iterations = [nodeArguments[0].value as number, nodeArguments[1].value as number];\n\n // A repeat node must have a positive min and max iteration count if they are defined.\n if (node.iterations[0] < 0 || node.iterations[1] < 0) {\n throw new Error(\"a repeat node must have a positive minimum and maximum iteration count if defined\");\n }\n\n // A repeat node must not have an minimum iteration count that exceeds the maximum iteration count.\n if (node.iterations[0] > node.iterations[1]) {\n throw new Error(\n \"a repeat node must not have a minimum iteration count that exceeds the maximum iteration count\"\n );\n }\n } else {\n // An incorrect number of iteration counts was defined.\n throw new Error(\"invalid number of repeat node iteration count arguments defined\");\n }\n }\n\n // Grab any node attribute definitions and spread them into the node definition.\n node = { ...node, ...parseAttributeTokens(tokens, stringLiteralPlaceholders) };\n\n // This is a decorator node, so we expect an opening '{'.\n popAndCheck(tokens, \"{\");\n\n // Return the repeat node definition.\n return node;\n}\n\n/**\n * Creates a retry node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The retry node JSON definition.\n */\nfunction createRetryNode(tokens: string[], stringLiteralPlaceholders: StringLiteralPlaceholders): RetryNodeDefinition {\n let node = { type: \"retry\" } as RetryNodeDefinition;\n\n // Get the node arguments.\n const nodeArguments = parseArgumentTokens(tokens, stringLiteralPlaceholders);\n\n // The arguments of a retry node are optional. We may have:\n // - No node arguments, in which case the retry note will attempt indefinitely.\n // - One node argument which will be the explicit number of attempts to make.\n // - Two node arguments which define the min and max attempt bounds from which a random attempt count will be picked.\n if (nodeArguments.length) {\n // All retry node arguments MUST be of type number and must be integer.\n nodeArguments\n .filter((arg) => arg.type !== \"number\" || !arg.isInteger)\n .forEach(() => {\n throw new Error(`retry node attempt counts must be integer values`);\n });\n\n // We should have got one or two attempt counts.\n if (nodeArguments.length === 1) {\n // A static attempt count was defined.\n node.attempts = nodeArguments[0].value as number;\n\n // A retry node must have a positive number of attempts if defined.\n if (node.attempts < 0) {\n throw new Error(\"a retry node must have a positive number of attempts if defined\");\n }\n } else if (nodeArguments.length === 2) {\n // A minimum and maximum attempt count was defined.\n node.attempts = [nodeArguments[0].value as number, nodeArguments[1].value as number];\n\n // A retry node must have a positive min and max attempts count if they are defined.\n if (node.attempts[0] < 0 || node.attempts[1] < 0) {\n throw new Error(\"a retry node must have a positive minimum and maximum attempt count if defined\");\n }\n\n // A retry node must not have a minimum attempt count that exceeds the maximum attempt count.\n if (node.attempts[0] > node.attempts[1]) {\n throw new Error(\n \"a retry node must not have a minimum attempt count that exceeds the maximum attempt count\"\n );\n }\n } else {\n // An incorrect number of attempt counts was defined.\n throw new Error(\"invalid number of retry node attempt count arguments defined\");\n }\n }\n\n // Grab any node attribute definitions and spread them into the node definition.\n node = { ...node, ...parseAttributeTokens(tokens, stringLiteralPlaceholders) };\n\n // This is a decorator node, so we expect an opening '{'.\n popAndCheck(tokens, \"{\");\n\n // Return the retry node definition.\n return node;\n}\n\n/**\n * Creates a sequence node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The sequence node JSON definition.\n */\nfunction createSequenceNode(\n tokens: string[],\n stringLiteralPlaceholders: StringLiteralPlaceholders\n): SequenceNodeDefinition {\n const node = {\n type: \"sequence\",\n ...parseAttributeTokens(tokens, stringLiteralPlaceholders)\n } as SequenceNodeDefinition;\n\n // This is a composite node, so we expect an opening '{'.\n popAndCheck(tokens, \"{\");\n\n // Return the sequence node definition.\n return node;\n}\n\n/**\n * Creates a selector node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The selector node JSON definition.\n */\nfunction createSelectorNode(\n tokens: string[],\n stringLiteralPlaceholders: StringLiteralPlaceholders\n): SelectorNodeDefinition {\n const node = {\n type: \"selector\",\n ...parseAttributeTokens(tokens, stringLiteralPlaceholders)\n } as SelectorNodeDefinition;\n\n // This is a composite node, so we expect an opening '{'.\n popAndCheck(tokens, \"{\");\n\n // Return the selector node definition.\n return node;\n}\n\n/**\n * Creates a parallel node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The parallel node JSON definition.\n */\nfunction createParallelNode(\n tokens: string[],\n stringLiteralPlaceholders: StringLiteralPlaceholders\n): ParallelNodeDefinition {\n const node = {\n type: \"parallel\",\n ...parseAttributeTokens(tokens, stringLiteralPlaceholders)\n } as ParallelNodeDefinition;\n\n // This is a composite node, so we expect an opening '{'.\n popAndCheck(tokens, \"{\");\n\n // Return the parallel node definition.\n return node;\n}\n\n/**\n * Creates a lotto node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The lotto node JSON definition.\n */\nfunction createLottoNode(tokens: string[], stringLiteralPlaceholders: StringLiteralPlaceholders): LottoNodeDefinition {\n // If any node arguments have been defined then they must be our weights.\n const nodeArguments = parseArgumentTokens(tokens, stringLiteralPlaceholders);\n\n // All lotto node arguments MUST be of type number and must be integer.\n nodeArguments\n .filter((arg) => arg.type !== \"number\" || !arg.isInteger)\n .forEach(() => {\n throw new Error(`lotto node weight arguments must be integer values`);\n });\n\n const node = {\n type: \"lotto\",\n weights: nodeArguments.map(({ value }) => value),\n ...parseAttributeTokens(tokens, stringLiteralPlaceholders)\n } as LottoNodeDefinition;\n\n // This is a composite node, so we expect an opening '{'.\n popAndCheck(tokens, \"{\");\n\n // Return the lotto node definition.\n return node;\n}\n\n/**\n * Creates an action node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The action node JSON definition.\n */\nfunction createActionNode(\n tokens: string[],\n stringLiteralPlaceholders: StringLiteralPlaceholders\n): ActionNodeDefinition {\n // Parse any node arguments, we should have at least one which will be an identifier argument for the action name\n // and agent function to invoke for the action, all other arguments are to be passed as arguments to that function.\n const [actionNameIdentifier, ...agentFunctionArgs] = parseArgumentTokens(tokens, stringLiteralPlaceholders);\n\n // Our first argument MUST be defined and be an identifier as we require an action name argument.\n if (actionNameIdentifier?.type !== \"identifier\") {\n throw new Error(\"expected action name identifier argument\");\n }\n\n // Only the first argument should have been an identifier, all agent function arguments must be string, number, boolean or null.\n agentFunctionArgs\n .filter((arg) => arg.type === \"identifier\")\n .forEach((arg) => {\n throw new Error(\n `invalid action node argument value '${arg.value}', must be string, number, boolean or null`\n );\n });\n\n // Return the action node definition.\n return {\n type: \"action\",\n call: actionNameIdentifier.value,\n args: agentFunctionArgs.map(({ value }) => value),\n ...parseAttributeTokens(tokens, stringLiteralPlaceholders)\n };\n}\n\n/**\n * Creates a condition node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The condition node JSON definition.\n */\nfunction createConditionNode(\n tokens: string[],\n stringLiteralPlaceholders: StringLiteralPlaceholders\n): ConditionNodeDefinition {\n // Parse any node arguments, we should have at least one which will be an identifier argument for the condition name\n // and agent function to invoke for the condition, all other arguments are to be passed as arguments to that function.\n const [conditionNameIdentifier, ...agentFunctionArgs] = parseArgumentTokens(tokens, stringLiteralPlaceholders);\n\n // Our first argument MUST be defined and be an identifier as we require a condition name argument.\n if (conditionNameIdentifier?.type !== \"identifier\") {\n throw new Error(\"expected condition name identifier argument\");\n }\n\n // Only the first argument should have been an identifier, all agent function arguments must be string, number, boolean or null.\n agentFunctionArgs\n .filter((arg) => arg.type === \"identifier\")\n .forEach((arg) => {\n throw new Error(\n `invalid condition node argument value '${arg.value}', must be string, number, boolean or null`\n );\n });\n\n // Return the condition node definition.\n return {\n type: \"condition\",\n call: conditionNameIdentifier.value,\n args: agentFunctionArgs.map(({ value }) => value),\n ...parseAttributeTokens(tokens, stringLiteralPlaceholders)\n };\n}\n\n/**\n * Creates a wait node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The wait node JSON definition.\n */\nfunction createWaitNode(tokens: string[], stringLiteralPlaceholders: StringLiteralPlaceholders): WaitNodeDefinition {\n let node = { type: \"wait\" } as WaitNodeDefinition;\n\n // Get the node arguments.\n const nodeArguments = parseArgumentTokens(tokens, stringLiteralPlaceholders);\n\n // The arguments of a wait node are optional. We may have:\n // - No node arguments, in which case the wait will be indefinite until it is aborted.\n // - One node argument which will be the explicit duration of the wait.\n // - Two node arguments which define the min and max duration bounds from which a random duration will be picked.\n if (nodeArguments.length) {\n // All wait node arguments MUST be of type number and must be integer.\n nodeArguments\n .filter((arg) => arg.type !== \"number\" || !arg.isInteger)\n .forEach(() => {\n throw new Error(`wait node duration arguments must be integer values`);\n });\n\n // We may have:\n // - One node argument which will be the explicit duration of the wait.\n // - Two node arguments which define the min and max duration bounds from which a random duration will be picked.\n // - Too many arguments, which is not valid.\n if (nodeArguments.length === 1) {\n // An explicit duration was defined.\n node.duration = nodeArguments[0].value as number;\n\n // If an explict duration was defined then it must be a positive number.\n if (node.duration < 0) {\n throw new Error(\"a wait node must have a positive duration\");\n }\n } else if (nodeArguments.length === 2) {\n // Min and max duration bounds were defined from which a random duration will be picked.\n node.duration = [nodeArguments[0].value as number, nodeArguments[1].value as number];\n\n // A wait node must have a positive min and max duration.\n if (node.duration[0] < 0 || node.duration[1] < 0) {\n throw new Error(\"a wait node must have a positive minimum and maximum duration\");\n }\n\n // A wait node must not have a minimum duration that exceeds the maximum duration.\n if (node.duration[0] > node.duration[1]) {\n throw new Error(\"a wait node must not have a minimum duration that exceeds the maximum duration\");\n }\n } else if (nodeArguments.length > 2) {\n // An incorrect number of duration arguments were defined.\n throw new Error(\"invalid number of wait node duration arguments defined\");\n }\n }\n\n // Return the wait node definition.\n return { ...node, ...parseAttributeTokens(tokens, stringLiteralPlaceholders) };\n}\n\n/**\n * Creates a branch node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The branch node JSON definition.\n */\nfunction createBranchNode(\n tokens: string[],\n stringLiteralPlaceholders: StringLiteralPlaceholders\n): BranchNodeDefinition {\n // Parse any node arguments, we should have one which will be an identifier argument for the root ref.\n const nodeArguments = parseArgumentTokens(tokens, stringLiteralPlaceholders);\n\n // We should have only a single identifer argument for a branch node, which is the root ref.\n if (nodeArguments.length !== 1 || nodeArguments[0].type !== \"identifier\") {\n throw new Error(\"expected single branch name argument\");\n }\n\n // Return the branch node definition.\n return { type: \"branch\", ref: nodeArguments[0].value };\n}\n\n/**\n * Validate a fully-populated node definition that was popped off of the tree stack.\n * @param node The popped node to validate.\n */\nfunction validatePoppedNode(node: AnyNodeDefinition): void {\n // Decorators MUST have a child defined.\n if (isDecoratorNode(node) && isNullOrUndefined(node.child)) {\n throw new Error(`a ${node.type} node must have a single child node defined`);\n }\n\n // Composites MUST have at least one child defined.\n if (isCompositeNode(node) && !node.children?.length) {\n throw new Error(`a ${node.type} node must have at least a single child node defined`);\n }\n}\n", "import { RootNodeDefinition } from \"./BehaviourTreeDefinition\";\nimport { flattenDefinition, isBranchNode, isInteger } from \"./BehaviourTreeDefinitionUtilities\";\nimport { convertMDSLToJSON } from \"./mdsl/MDSLDefinitionParser\";\n\n/**\n * An object representing the result of validating a tree definition.\n */\nexport type DefinitionValidationResult = {\n /**\n * A flag defining whether validation succeeded.\n */\n succeeded: boolean;\n /**\n * A string containing the error message if validation did not succeed.\n */\n errorMessage?: string;\n};\n\n/**\n * Validates the specified behaviour tree definition in the form of JSON or MDSL, not taking any globally registered subtrees into consideration.\n * @param definition The behaviour tree definition in the form of JSON or MDSL.\n * @returns An object representing the result of validating the given tree definition.\n */\nexport function validateDefinition(definition: any): DefinitionValidationResult {\n // The definition must be defined.\n if (definition === null || typeof definition === \"undefined\") {\n return createValidationFailureResult(\"definition is null or undefined\");\n }\n\n // We are expecting a definition in one of three different forms:\n // - A string which we will assume is MDSL and we will parse this to JSON before validation.\n // - An array which we will assume is an array of root node definitions with at least one being the primary root node (no 'id' property)\n // - An object which we will assume is the primary root node and should not have an 'id' property.\n if (typeof definition === \"string\") {\n // The definition is a string which we can assume is MDSL, so attempt to validate it.\n return validateMDSLDefinition(definition);\n } else if (typeof definition === \"object\") {\n // The definition will either be an array (of root node definitions) or an object (the single primary root node definition).\n return validateJSONDefinition(definition);\n } else {\n return createValidationFailureResult(`unexpected definition type of '${typeof definition}'`);\n }\n}\n\n/**\n * Validates the specified behaviour tree definition in the form of MDSL.\n * @param definition The behaviour tree definition in the form of MDSL.\n * @returns An object representing the result of validating the given tree definition.\n */\nexport function validateMDSLDefinition(definition: string): DefinitionValidationResult {\n let rootNodeDefinitions;\n\n // The first thing the we need to do is to attempt to convert our MDSL into JSON.\n try {\n // The definition is a string which we can assume is MDSL, so attempt to parse it to a JSON definition in the form of an array of root node definitions.\n rootNodeDefinitions = convertMDSLToJSON(definition);\n } catch (error) {\n // We failed to parse the JSON from the MDSL, this is likely to be the result of it not being a valid MDSL string.\n return createValidationFailureResult(`invalid MDSL: ${error}`);\n }\n\n // Unpack all of the root node definitions into arrays of main ('id' defined) and sub ('id' not defined) root node definitions.\n const mainRootNodeDefinitions = rootNodeDefinitions.filter(({ id }) => typeof id === \"undefined\");\n const subRootNodeDefinitions = rootNodeDefinitions.filter(({ id }) => typeof id === \"string\" && id.length > 0);\n\n // We should ALWAYS have exactly one root node definition without an 'id' property defined, which is out main root node definition.\n if (mainRootNodeDefinitions.length !== 1) {\n return createValidationFailureResult(\n \"expected single unnamed root node at base of definition to act as main root\"\n );\n }\n\n // We should never have duplicate 'id' properties across our sub root node definitions.\n const subRootNodeIdenitifers: string[] = [];\n for (const { id } of subRootNodeDefinitions) {\n // Have we already come across this 'id' property value?\n if (subRootNodeIdenitifers.includes(id!)) {\n return createValidationFailureResult(`multiple root nodes found with duplicate name '${id}'`);\n }\n\n subRootNodeIdenitifers.push(id!);\n }\n\n try {\n // Validate our branch -> subtree links and check for any circular dependencies, we don't care about checking for broken subtree links here.\n validateBranchSubtreeLinks(rootNodeDefinitions, false);\n } catch (exception) {\n return createValidationFailureResult((exception as Error).message);\n }\n\n // Our definition was valid!\n return { succeeded: true };\n}\n\n/**\n * Validates the specified behaviour tree definition in the form of JSON.\n * @param definition The behaviour tree definition in the form of JSON.\n * @returns An object representing the result of validating the given tree definition.\n */\nexport function validateJSONDefinition(\n definition: RootNodeDefinition | RootNodeDefinition[]\n): DefinitionValidationResult {\n // The definition will either be an array (of root node definitions) or an object (the single primary root node definition).\n const rootNodeDefinitions = Array.isArray(definition) ? definition : [definition];\n\n // Iterate over our array of root nodes and call validateNode for each, passing an initial depth of 0, wrapped in a try catch to handle validation failures.\n try {\n rootNodeDefinitions.forEach((rootNodeDefinition) => validateNode(rootNodeDefinition, 0));\n } catch (error) {\n // Handle cases where we have caught a thrown Error and return a failure result with the error message.\n if (error instanceof Error) {\n return createValidationFailureResult(error.message);\n }\n\n // No idea what happened here!\n return createValidationFailureResult(`unexpected error: ${error}`);\n }\n\n // Unpack all of the root node definitions into arrays of main ('id' defined) and sub ('id' not defined) root node definitions.\n const mainRootNodeDefinitions = rootNodeDefinitions.filter(({ id }) => typeof id === \"undefined\");\n const subRootNodeDefinitions = rootNodeDefinitions.filter(({ id }) => typeof id === \"string\" && id.length > 0);\n\n // We should ALWAYS have exactly one root node definition without an 'id' property defined, which is out main root node definition.\n if (mainRootNodeDefinitions.length !== 1) {\n return createValidationFailureResult(\n \"expected single root node without 'id' property defined to act as main root\"\n );\n }\n\n // We should never have duplicate 'id' properties across our sub root node definitions.\n const subRootNodeIdenitifers: string[] = [];\n for (const { id } of subRootNodeDefinitions) {\n // Have we already come across this 'id' property value?\n if (subRootNodeIdenitifers.includes(id!)) {\n return createValidationFailureResult(\n `multiple root nodes found with duplicate 'id' property value of '${id}'`\n );\n }\n\n subRootNodeIdenitifers.push(id!);\n }\n\n try {\n // Validate our branch -> subtree links and check for any circular dependencies, we don't care about checking for broken subtree links here.\n validateBranchSubtreeLinks(rootNodeDefinitions, false);\n } catch (exception) {\n return createValidationFailureResult((exception as Error).message);\n }\n\n // Our definition was valid!\n return { succeeded: true };\n}\n\n/**\n * Validates the branch -> subtree links across all provided root node definitions.\n * This will not consider branch nodes that reference any globally registered subtrees unless includesGlobalSubtrees\n * is set to true, in which case we will also verify that there are no broken branch -> subtree links.\n * @param rootNodeDefinitions The array of root node definitions.\n * @param includesGlobalSubtrees A flag defining whether the array includes all global subtree root node definitions.\n */\nexport function validateBranchSubtreeLinks(rootNodeDefinitions: RootNodeDefinition[], includesGlobalSubtrees: boolean) {\n // Create a mapping of root node identifiers to other root nodes that they reference via branch nodes.\n // Below is an example of a mapping that includes a circular dependency (root => a => b => c => a)\n // [{ refs: [\"a\", \"b\"] }, { id: \"a\", refs: [\"b\"] }, { id: \"b\", refs: [\"c\"] }, { id: \"c\", refs: [\"a\"] }]\n const rootNodeMappings: { id: string | undefined; refs: string[] }[] = rootNodeDefinitions.map(\n (rootNodeDefinition) => ({\n id: rootNodeDefinition.id,\n refs: flattenDefinition(rootNodeDefinition)\n .filter(isBranchNode)\n .map(({ ref }) => ref)\n })\n );\n\n // A recursive function to walk through the mappings, keeping track of which root nodes we have visited in the form of a path of root node identifiers.\n const followRefs = (mapping: { id: string | undefined; refs: string[] }, path: (string | undefined)[] = []) => {\n // Have we found a circular dependency?\n if (path.includes(mapping.id)) {\n // We found a circular dependency! Get the bad path of root node identifiers.\n const badPath = [...path, mapping.id];\n\n // Create the formatted path value. [undefined, \"a\", \"b\", \"c\", \"a\"] would be formatted as \"a -> b -> c -> a\".\n const badPathFormatted = badPath.filter((element) => !!element).join(\" => \");\n\n // No need to continue, we found a circular dependency.\n throw new Error(`circular dependency found in branch node references: ${badPathFormatted}`);\n }\n\n for (const ref of mapping.refs) {\n // Find the mapping for the root node with an identifer matching the current ref.\n const subMapping = rootNodeMappings.find(({ id }) => id === ref);\n\n // We may not have a mapping for this ref, which is normal when we aren't considering all globally registered subtrees.\n if (subMapping) {\n followRefs(subMapping, [...path, mapping.id]);\n } else if (includesGlobalSubtrees) {\n // We found a reference to a root node that doesn't exist, which is a problem seeing as the root node definitons includes all globally registered subtrees.\n throw new Error(\n mapping.id\n ? `subtree '${mapping.id}' has branch node that references root node '${ref}' which has not been defined`\n : `primary tree has branch node that references root node '${ref}' which has not been defined`\n );\n }\n }\n };\n\n // Start looking for circular dependencies and broken references from the primary root node definition.\n followRefs(rootNodeMappings.find((mapping) => typeof mapping.id === \"undefined\")!);\n}\n\n/**\n * Validate an object that we expect to be a node definition.\n * @param definition An object that we expect to be a node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateNode(definition: any, depth: number): void {\n // Every node must be valid object and have a non-empty 'type' string property.\n if (typeof definition !== \"object\" || typeof definition.type !== \"string\" || definition.type.length === 0) {\n throw new Error(\n `node definition is not an object or 'type' property is not a non-empty string at depth '${depth}'`\n );\n }\n\n // How we validate this node definition will depend on its type.\n switch (definition.type) {\n case \"action\":\n validateActionNode(definition, depth);\n break;\n\n case \"condition\":\n validateConditionNode(definition, depth);\n break;\n\n case \"wait\":\n validateWaitNode(definition, depth);\n break;\n\n case \"branch\":\n validateBranchNode(definition, depth);\n break;\n\n case \"root\":\n validateRootNode(definition, depth);\n break;\n\n case \"success\":\n validateSuccessNode(definition, depth);\n break;\n\n case \"fail\":\n validateFailNode(definition, depth);\n break;\n\n case \"flip\":\n validateFlipNode(definition, depth);\n break;\n\n case \"repeat\":\n validateRepeatNode(definition, depth);\n break;\n\n case \"retry\":\n validateRetryNode(definition, depth);\n break;\n\n case \"sequence\":\n validateSequenceNode(definition, depth);\n break;\n\n case \"selector\":\n validateSelectorNode(definition, depth);\n break;\n\n case \"parallel\":\n validateParallelNode(definition, depth);\n break;\n\n default:\n throw new Error(`unexpected node type of '${definition.type}' at depth '${depth}'`);\n }\n}\n\n/**\n * Validate any attributes for a given node definition.\n * @param definition The node definition.\n * @param depth The depth of the node in the behaviour tree definition.\n */\nfunction validateNodeAttributes(definition: any, depth: number): void {\n // Validate each of the attribute types for this node.\n [\"while\", \"until\", \"entry\", \"exit\", \"step\"].forEach((attributeName) => {\n // Attempt to grab the definition for the current attribute from the node definition.\n const attributeDefinition = definition[attributeName];\n\n // All node attributes are optional, so there is nothing to do if the current attribute is not defined.\n if (typeof attributeDefinition === \"undefined\") {\n return;\n }\n\n // The attribute definition must be an object.\n if (typeof attributeDefinition !== \"object\") {\n throw new Error(\n `expected attribute '${attributeName}' to be an object for '${definition.type}' node at depth '${depth}'`\n );\n }\n\n // The 'call' property must be defined for any attribute definition.\n if (typeof attributeDefinition.call !== \"string\" || attributeDefinition.call.length === 0) {\n throw new Error(\n `expected 'call' property for attribute '${attributeName}' to be a non-empty string for '${definition.type}' node at depth '${depth}'`\n );\n }\n\n // If any node attribute arguments have been defined then they must have been defined in an array.\n if (typeof attributeDefinition.args !== \"undefined\" && !Array.isArray(attributeDefinition.args)) {\n throw new Error(\n `expected 'args' property for attribute '${attributeName}' to be an array for '${definition.type}' node at depth '${depth}'`\n );\n }\n });\n}\n\n/**\n * Validate an object that we expect to be a root node definition.\n * @param definition An object that we expect to be a root node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateRootNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"root\") {\n throw new Error(\"expected node type of 'root' for root node\");\n }\n\n // A root node cannot be the child of another node.\n if (depth > 0) {\n throw new Error(\"a root node cannot be the child of another node\");\n }\n\n // Check that, if the root node 'id' property is defined, it is a non-empty string.\n if (typeof definition.id !== \"undefined\" && (typeof definition.id !== \"string\" || definition.id.length === 0)) {\n throw new Error(\"expected non-empty string for 'id' property if defined for root node\");\n }\n\n // A root node is a decorator node, so must have a child node defined.\n if (typeof definition.child === \"undefined\") {\n throw new Error(\"expected property 'child' to be defined for root node\");\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n\n // Validate the child node of this decorator node.\n validateNode(definition.child, depth + 1);\n}\n\n/**\n * Validate an object that we expect to be a success node definition.\n * @param definition An object that we expect to be a success node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateSuccessNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"success\") {\n throw new Error(`expected node type of 'success' for success node at depth '${depth}'`);\n }\n\n // A success node is a decorator node, so must have a child node defined.\n if (typeof definition.child === \"undefined\") {\n throw new Error(`expected property 'child' to be defined for success node at depth '${depth}'`);\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n\n // Validate the child node of this decorator node.\n validateNode(definition.child, depth + 1);\n}\n\n/**\n * Validate an object that we expect to be a fail node definition.\n * @param definition An object that we expect to be a fail node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateFailNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"fail\") {\n throw new Error(`expected node type of 'fail' for fail node at depth '${depth}'`);\n }\n\n // A fail node is a decorator node, so must have a child node defined.\n if (typeof definition.child === \"undefined\") {\n throw new Error(`expected property 'child' to be defined for fail node at depth '${depth}'`);\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n\n // Validate the child node of this decorator node.\n validateNode(definition.child, depth + 1);\n}\n\n/**\n * Validate an object that we expect to be a flip node definition.\n * @param definition An object that we expect to be a flip node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateFlipNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"flip\") {\n throw new Error(`expected node type of 'flip' for flip node at depth '${depth}'`);\n }\n\n // A flip node is a decorator node, so must have a child node defined.\n if (typeof definition.child === \"undefined\") {\n throw new Error(`expected property 'child' to be defined for flip node at depth '${depth}'`);\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n\n // Validate the child node of this decorator node.\n validateNode(definition.child, depth + 1);\n}\n\n/**\n * Validate an object that we expect to be a repeat node definition.\n * @param definition An object that we expect to be a repeat node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateRepeatNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"repeat\") {\n throw new Error(`expected node type of 'repeat' for repeat node at depth '${depth}'`);\n }\n\n // A repeat node is a decorator node, so must have a child node defined.\n if (typeof definition.child === \"undefined\") {\n throw new Error(`expected property 'child' to be defined for repeat node at depth '${depth}'`);\n }\n\n // Check whether an 'iterations' property has been defined, it may not have been if this node is to repeat indefinitely.\n if (typeof definition.iterations !== \"undefined\") {\n if (Array.isArray(definition.iterations)) {\n // Check whether any elements of the array are not integer values.\n const containsNonInteger = !!definition.iterations.find((value: unknown) => !isInteger(value));\n\n // If the 'iterations' property is an array then it MUST contain two integer values.\n if (definition.iterations.length !== 2 || containsNonInteger) {\n throw new Error(\n `expected array containing two integer values for 'iterations' property if defined for repeat node at depth '${depth}'`\n );\n }\n\n // A repeat node must have a positive min and max iterations count if they are defined.\n if (definition.iterations[0] < 0 || definition.iterations[1] < 0) {\n throw new Error(\n `expected positive minimum and maximum iterations count for 'iterations' property if defined for repeat node at depth '${depth}'`\n );\n }\n\n // A repeat node must not have a minimum iterations count that exceeds the maximum iterations count.\n if (definition.iterations[0] > definition.iterations[1]) {\n throw new Error(\n `expected minimum iterations count that does not exceed the maximum iterations count for 'iterations' property if defined for repeat node at depth '${depth}'`\n );\n }\n } else if (isInteger(definition.iterations)) {\n // A repeat node must have a positive number of iterations if defined.\n if (definition.iterations < 0) {\n throw new Error(\n `expected positive iterations count for 'iterations' property if defined for repeat node at depth '${depth}'`\n );\n }\n } else {\n throw new Error(\n `expected integer value or array containing two integer values for 'iterations' property if defined for repeat node at depth '${depth}'`\n );\n }\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n\n // Validate the child node of this decorator node.\n validateNode(definition.child, depth + 1);\n}\n\n/**\n * Validate an object that we expect to be a retry node definition.\n * @param definition An object that we expect to be a retry node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateRetryNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"retry\") {\n throw new Error(`expected node type of 'retry' for retry node at depth '${depth}'`);\n }\n\n // A retry node is a decorator node, so must have a child node defined.\n if (typeof definition.child === \"undefined\") {\n throw new Error(`expected property 'child' to be defined for retry node at depth '${depth}'`);\n }\n\n // Check whether an 'attempts' property has been defined, it may not have been if this node is to retry indefinitely.\n if (typeof definition.attempts !== \"undefined\") {\n if (Array.isArray(definition.attempts)) {\n // Check whether any elements of the array are not integer values.\n const containsNonInteger = !!definition.attempts.find((value: unknown) => !isInteger(value));\n\n // If the 'attempts' property is an array then it MUST contain two integer values.\n if (definition.attempts.length !== 2 || containsNonInteger) {\n throw new Error(\n `expected array containing two integer values for 'attempts' property if defined for retry node at depth '${depth}'`\n );\n }\n\n // A retry node must have a positive min and max attempts count if they are defined.\n if (definition.attempts[0] < 0 || definition.attempts[1] < 0) {\n throw new Error(\n `expected positive minimum and maximum attempts count for 'attempts' property if defined for retry node at depth '${depth}'`\n );\n }\n\n // A retry node must not have a minimum attempts count that exceeds the maximum attempts count.\n if (definition.attempts[0] > definition.attempts[1]) {\n throw new Error(\n `expected minimum attempts count that does not exceed the maximum attempts count for 'attempts' property if defined for retry node at depth '${depth}'`\n );\n }\n } else if (isInteger(definition.attempts)) {\n // A retry node must have a positive number of attempts if defined.\n if (definition.attempts < 0) {\n throw new Error(\n `expected positive attempts count for 'attempts' property if defined for retry node at depth '${depth}'`\n );\n }\n } else {\n throw new Error(\n `expected integer value or array containing two integer values for 'attempts' property if defined for retry node at depth '${depth}'`\n );\n }\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n\n // Validate the child node of this decorator node.\n validateNode(definition.child, depth + 1);\n}\n\n/**\n * Validate an object that we expect to be a branch node definition.\n * @param definition An object that we expect to be a branch node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateBranchNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"branch\") {\n throw new Error(`expected node type of 'branch' for branch node at depth '${depth}'`);\n }\n\n // Check that the branch node 'ref' property is defined and is a non-empty string.\n if (typeof definition.ref !== \"string\" || definition.ref.length === 0) {\n throw new Error(`expected non-empty string for 'ref' property for branch node at depth '${depth}'`);\n }\n\n // It is invalid to define guard attributes for a branch node as they should be defined on the referenced root node.\n [\"while\", \"until\"].forEach((attributeName) => {\n if (typeof definition[attributeName] !== \"undefined\") {\n throw new Error(\n `guards should not be defined for branch nodes but guard '${attributeName}' was defined for branch node at depth '${depth}'`\n );\n }\n });\n\n // It is invalid to define callback attributes for a branch node as they should be defined on the referenced root node.\n [\"entry\", \"exit\", \"step\"].forEach((attributeName) => {\n if (typeof definition[attributeName] !== \"undefined\") {\n throw new Error(\n `callbacks should not be defined for branch nodes but callback '${attributeName}' was defined for branch node at depth '${depth}'`\n );\n }\n });\n}\n\n/**\n * Validate an object that we expect to be a action node definition.\n * @param definition An object that we expect to be a action node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateActionNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"action\") {\n throw new Error(`expected node type of 'action' for action node at depth '${depth}'`);\n }\n\n // The 'call' property must be defined for a action node definition.\n if (typeof definition.call !== \"string\" || definition.call.length === 0) {\n throw new Error(`expected non-empty string for 'call' property of action node at depth '${depth}'`);\n }\n\n // If any action function arguments have been defined then they must have been defined in an array.\n if (typeof definition.args !== \"undefined\" && !Array.isArray(definition.args)) {\n throw new Error(`expected array for 'args' property if defined for action node at depth '${depth}'`);\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n}\n\n/**\n * Validate an object that we expect to be a condition node definition.\n * @param definition An object that we expect to be a condition node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateConditionNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"condition\") {\n throw new Error(`expected node type of 'condition' for condition node at depth '${depth}'`);\n }\n\n // The 'call' property must be defined for a condition node definition.\n if (typeof definition.call !== \"string\" || definition.call.length === 0) {\n throw new Error(`expected non-empty string for 'call' property of condition node at depth '${depth}'`);\n }\n\n // If any condition function arguments have been defined then they must have been defined in an array.\n if (typeof definition.args !== \"undefined\" && !Array.isArray(definition.args)) {\n throw new Error(`expected array for 'args' property if defined for condition node at depth '${depth}'`);\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n}\n\n/**\n * Validate an object that we expect to be a wait node definition.\n * @param definition An object that we expect to be a wait node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateWaitNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"wait\") {\n throw new Error(`expected node type of 'wait' for wait node at depth '${depth}'`);\n }\n\n // Check whether a 'duration' property has been defined, it may not have been if this node is to wait indefinitely.\n if (typeof definition.duration !== \"undefined\") {\n if (Array.isArray(definition.duration)) {\n // Check whether any elements of the array are not integer values.\n const containsNonInteger = !!definition.duration.find((value: unknown) => !isInteger(value));\n\n // If the 'duration' property is an array then it MUST contain two integer values.\n if (definition.duration.length !== 2 || containsNonInteger) {\n throw new Error(\n `expected array containing two integer values for 'duration' property if defined for wait node at depth '${depth}'`\n );\n }\n\n // A wait node must have a positive min and max duration value if they are defined.\n if (definition.duration[0] < 0 || definition.duration[1] < 0) {\n throw new Error(\n `expected positive minimum and maximum duration for 'duration' property if defined for wait node at depth '${depth}'`\n );\n }\n\n // A wait node must not have a minimum duration value that exceeds the maximum duration value.\n if (definition.duration[0] > definition.duration[1]) {\n throw new Error(\n `expected minimum duration value that does not exceed the maximum duration value for 'duration' property if defined for wait node at depth '${depth}'`\n );\n }\n } else if (isInteger(definition.duration)) {\n // A wait node must have a positive duration value if defined.\n if (definition.duration < 0) {\n throw new Error(\n `expected positive duration value for 'duration' property if defined for wait node at depth '${depth}'`\n );\n }\n } else {\n throw new Error(\n `expected integer value or array containing two integer values for 'duration' property if defined for wait node at depth '${depth}'`\n );\n }\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n}\n\n/**\n * Validate an object that we expect to be a sequence node definition.\n * @param definition An object that we expect to be a sequence node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateSequenceNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"sequence\") {\n throw new Error(`expected node type of 'sequence' for sequence node at depth '${depth}'`);\n }\n\n // A sequence node is a composite node, so must have a children nodes array defined.\n if (!Array.isArray(definition.children) || definition.children.length === 0) {\n throw new Error(`expected non-empty 'children' array to be defined for sequence node at depth '${depth}'`);\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n\n // Validate the child nodes of this composite node.\n definition.children.forEach((child: any) => validateNode(child, depth + 1));\n}\n\n/**\n * Validate an object that we expect to be a selector node definition.\n * @param definition An object that we expect to be a selector node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateSelectorNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"selector\") {\n throw new Error(`expected node type of 'selector' for selector node at depth '${depth}'`);\n }\n\n // A selector node is a composite node, so must have a children nodes array defined.\n if (!Array.isArray(definition.children) || definition.children.length === 0) {\n throw new Error(`expected non-empty 'children' array to be defined for selector node at depth '${depth}'`);\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n\n // Validate the child nodes of this composite node.\n definition.children.forEach((child: any) => validateNode(child, depth + 1));\n}\n\n/**\n * Validate an object that we expect to be a parallel node definition.\n * @param definition An object that we expect to be a parallel node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateParallelNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"parallel\") {\n throw new Error(`expected node type of 'parallel' for parallel node at depth '${depth}'`);\n }\n\n // A parallel node is a composite node, so must have a children nodes array defined.\n if (!Array.isArray(definition.children) || definition.children.length === 0) {\n throw new Error(`expected non-empty 'children' array to be defined for parallel node at depth '${depth}'`);\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n\n // Validate the child nodes of this composite node.\n definition.children.forEach((child: any) => validateNode(child, depth + 1));\n}\n\n/**\n * A helper function to create a failure validation result with the given error message.\n * @param errorMessage The validation failure error message.\n * @returns A failure validation result with the given error message.\n */\nfunction createValidationFailureResult(errorMessage: string): DefinitionValidationResult {\n return { succeeded: false, errorMessage };\n}\n", "import { ActionResult, Agent, GlobalFunction } from \"./Agent\";\nimport { RootNodeDefinition } from \"./BehaviourTreeDefinition\";\n\nexport type InvokerFunction = (args: any[]) => ActionResult;\n\n/**\n * A singleton used to store and lookup registered functions and subtrees.\n */\nexport default class Lookup {\n /**\n * The object holding any registered functions keyed on function name.\n */\n private static functionTable: { [key: string]: GlobalFunction } = {};\n /**\n * The object holding any registered subtree root node definitions keyed on tree name.\n */\n private static subtreeTable: { [key: string]: RootNodeDefinition } = {};\n\n /**\n * Gets the function with the specified name.\n * @param name The name of the function.\n * @returns The function with the specified name.\n */\n public static getFunc(name: string): GlobalFunction {\n return this.functionTable[name];\n }\n\n /**\n * Sets the function with the specified name for later lookup.\n * @param name The name of the function.\n * @param func The function.\n */\n public static setFunc(name: string, func: GlobalFunction): void {\n this.functionTable[name] = func;\n }\n\n /**\n * Gets the function invoker for the specified agent and function name.\n * If a function with the specified name exists on the agent object then it will\n * be returned, otherwise we will then check the registered functions for a match.\n * @param agent The agent instance that this behaviour tree is modelling behaviour for.\n * @param name The function name.\n * @returns The function invoker for the specified agent and function name.\n */\n static getFuncInvoker(agent: Agent, name: string): InvokerFunction | null {\n // Check whether the agent contains the specified function.\n const foundOnAgent = agent[name];\n if (foundOnAgent && typeof foundOnAgent === \"function\") {\n return (args: any[]): boolean | ActionResult => foundOnAgent.apply(agent, args);\n }\n\n // The agent does not contain the specified function but it may have been registered at some point.\n if (this.functionTable[name] && typeof this.functionTable[name] === \"function\") {\n return (args: any[]) => this.functionTable[name](agent, ...args.map((arg) => arg.value));\n }\n\n // We have no function to invoke.\n return null;\n }\n\n /**\n * Gets all registered subtree root node definitions.\n */\n static getSubtrees(): { [key: string]: RootNodeDefinition } {\n return this.subtreeTable;\n }\n\n /**\n * Sets the subtree with the specified name for later lookup.\n * @param name The name of the subtree.\n * @param subtree The subtree.\n */\n static setSubtree(name: string, subtree: RootNodeDefinition) {\n this.subtreeTable[name] = subtree;\n }\n\n /**\n * Removes the registered function or subtree with the specified name.\n * @param name The name of the registered function or subtree.\n */\n static remove(name: string) {\n delete this.functionTable[name];\n delete this.subtreeTable[name];\n }\n\n /**\n * Remove all registered functions and subtrees.\n */\n static empty() {\n this.functionTable = {};\n this.subtreeTable = {};\n }\n}\n", "import Node from \"../../nodes/Node\";\n\n/**\n * An exception thrown when evaluating node guard path conditions and a conditions fails.\n */\nexport default class GuardUnsatisifedException extends Error {\n /**\n * @param source The node at which a guard condition failed.\n */\n constructor(private source: Node) {\n super(\"A guard path condition has failed\");\n }\n\n /**\n * Gets whether the specified node is the node at which a guard condition failed.\n * @param node The node to check against the source node.\n * @returns Whether the specified node is the node at which a guard condition failed.\n */\n isSourceNode = (node: Node) => node === this.source;\n}\n", "import { Agent } from \"../../Agent\";\nimport Guard from \"./Guard\";\nimport Node from \"../../nodes/Node\";\nimport GuardUnsatisifedException from \"./GuardUnsatisifedException\";\n\nexport type GuardPathPart = {\n node: Node;\n guards: Guard[];\n};\n\n/**\n * Represents a path of node guards along a root-to-leaf tree path.\n */\nexport default class GuardPath {\n /**\n * @param nodes An array of objects defining a node instance -> guard link, ordered by node depth.\n */\n constructor(private nodes: GuardPathPart[]) {}\n\n /**\n * Evaluate guard conditions for all guards in the tree path, moving outwards from the root.\n * @param agent The agent, required for guard evaluation.\n * @returns An evaluation results object.\n */\n evaluate = (agent: Agent) => {\n // We need to evaluate guard conditions for nodes up the tree, moving outwards from the root.\n for (const details of this.nodes) {\n // There can be multiple guards per node.\n for (const guard of details.guards) {\n // Check whether the guard condition passes, and throw an exception if not.\n if (!guard.isSatisfied(agent)) {\n throw new GuardUnsatisifedException(details.node);\n }\n }\n }\n };\n}\n", "import { BehaviourTreeOptions } from \"../BehaviourTreeOptions\";\nimport State, { AnyState } from \"../State\";\nimport { Agent } from \"../Agent\";\nimport Leaf from \"./leaf/Leaf\";\nimport Attribute from \"../attributes/Attribute\";\nimport Entry from \"../attributes/callbacks/Entry\";\nimport Exit from \"../attributes/callbacks/Exit\";\nimport Step from \"../attributes/callbacks/Step\";\nimport Guard from \"../attributes/guards/Guard\";\nimport GuardPath from \"../attributes/guards/GuardPath\";\nimport GuardUnsatisifedException from \"../attributes/guards/GuardUnsatisifedException\";\n\n/**\n * A base node.\n */\nexport default abstract class Node {\n /**\n * The node uid.\n */\n private readonly uid: string = createNodeUid();\n /**\n * The node state.\n */\n private state: AnyState = State.READY;\n /**\n * The guard path to evaluate as part of a node update.\n */\n private guardPath: GuardPath | undefined;\n\n /**\n * @param type The node type.\n * @param attributes The node attributes.\n * @param args The node argument definitions.\n */\n constructor(private type: string, private attributes: Attribute[], private args: any[]) {}\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected abstract onUpdate(agent: Agent, options: BehaviourTreeOptions): void;\n\n /**\n * Gets the name of the node.\n */\n public abstract getName(): string;\n\n /**\n * Gets whether this node is a leaf node.\n */\n public abstract isLeafNode: () => this is Leaf;\n\n /**\n * Gets/Sets the state of the node.\n */\n getState = (): AnyState => this.state;\n setState = (value: AnyState): void => {\n this.state = value;\n };\n\n /**\n * Gets the unique id of the node.\n */\n getUid = () => this.uid;\n\n /**\n * Gets the type of the node.\n */\n getType = () => this.type;\n\n /**\n * Gets the node attributes.\n */\n getAttributes = () => this.attributes;\n\n /**\n * Gets the node arguments.\n */\n getArguments = () => this.args;\n\n /**\n * Gets the node attribute with the specified type, or null if it does not exist.\n */\n getAttribute(type: \"entry\" | \"ENTRY\"): Entry;\n getAttribute(type: \"exit\" | \"EXIT\"): Exit;\n getAttribute(type: \"step\" | \"STEP\"): Step;\n getAttribute(type: string): Attribute {\n return (\n this.getAttributes().filter((decorator) => decorator.type.toUpperCase() === type.toUpperCase())[0] || null\n );\n }\n\n /**\n * Gets the node attributes.\n */\n getGuardAttributes = (): Guard[] => this.getAttributes().filter((decorator) => decorator.isGuard()) as Guard[];\n\n /**\n * Sets the guard path to evaluate as part of a node update.\n */\n setGuardPath = (value: GuardPath) => (this.guardPath = value);\n\n /**\n * Gets whether a guard path is assigned to this node.\n */\n hasGuardPath = () => !!this.guardPath;\n\n /**\n * Gets whether this node is in the specified state.\n * @param value The value to compare to the node state.\n */\n public is(value: AnyState): boolean {\n return this.state === value;\n }\n\n /**\n * Reset the state of the node.\n */\n public reset(): void {\n this.setState(State.READY);\n }\n\n /**\n * Abort the running of this node.\n * @param agent The agent.\n */\n public abort(agent: Agent): void {\n // There is nothing to do if this node is not in the running state.\n if (!this.is(State.RUNNING)) {\n return;\n }\n\n // Reset the state of this node.\n this.reset();\n\n this.getAttribute(\"exit\")?.callAgentFunction(agent, false, true);\n }\n\n /**\n * Update the node.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n * @returns The result of the update.\n */\n public update(agent: Agent, options: BehaviourTreeOptions): void {\n // If this node is already in a 'SUCCEEDED' or 'FAILED' state then there is nothing to do.\n if (this.is(State.SUCCEEDED) || this.is(State.FAILED)) {\n return;\n }\n\n try {\n // Evaluate all of the guard path conditions for the current tree path.\n this.guardPath!.evaluate(agent);\n\n // If this node is in the READY state then call the ENTRY for this node if it exists.\n if (this.is(State.READY)) {\n this.getAttribute(\"entry\")?.callAgentFunction(agent);\n }\n\n this.getAttribute(\"step\")?.callAgentFunction(agent);\n\n // Do the actual update.\n this.onUpdate(agent, options);\n\n // If this node is now in a 'SUCCEEDED' or 'FAILED' state then call the EXIT for this node if it exists.\n if (this.is(State.SUCCEEDED) || this.is(State.FAILED)) {\n this.getAttribute(\"exit\")?.callAgentFunction(agent, this.is(State.SUCCEEDED), false);\n }\n } catch (error) {\n // If the error is a GuardUnsatisfiedException then we need to determine if this node is the source.\n if (error instanceof GuardUnsatisifedException && error.isSourceNode(this)) {\n // Abort the current node.\n this.abort(agent);\n\n // Any node that is the source of an abort will be a failed node.\n this.setState(State.FAILED);\n } else {\n throw error;\n }\n }\n }\n}\n\n/**\n * Create a randomly generated node uid.\n * @returns A randomly generated node uid.\n */\nfunction createNodeUid(): string {\n var S4 = function () {\n return (((1 + Math.random()) * 0x10000) | 0).toString(16).substring(1);\n };\n return S4() + S4() + \"-\" + S4() + \"-\" + S4() + \"-\" + S4() + \"-\" + S4() + S4() + S4();\n}\n", "import Node from \"../Node\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\n\n/**\n * A composite node that wraps child nodes.\n */\nexport default abstract class Composite extends Node {\n /**\n * @param type The node type.\n * @param attributes The node attributes.\n * @param children The child nodes.\n */\n constructor(type: string, attributes: Attribute[], protected children: Node[]) {\n super(type, attributes, []);\n }\n\n /**\n * Gets whether this node is a leaf node.\n */\n isLeafNode = () => false;\n\n /**\n * Gets the children of this node.\n */\n getChildren = () => this.children;\n\n /**\n * Reset the state of the node.\n */\n reset = () => {\n // Reset the state of this node.\n this.setState(State.READY);\n\n // Reset the state of any child nodes.\n this.getChildren().forEach((child) => child.reset());\n };\n\n /**\n * Abort the running of this node.\n * @param agent The agent.\n */\n abort = (agent: Agent) => {\n // There is nothing to do if this node is not in the running state.\n if (!this.is(State.RUNNING)) {\n return;\n }\n\n // Abort any child nodes.\n this.getChildren().forEach((child) => child.abort(agent));\n\n // Reset the state of this node.\n this.reset();\n\n this.getAttribute(\"exit\")?.callAgentFunction(agent, false, true);\n };\n}\n", "import Composite from \"./Composite\";\nimport State from \"../../State\";\nimport Node from \"../Node\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A PARALLEL node.\n * The child nodes are executed concurrently until one fails or all succeed.\n */\nexport default class Parallel extends Composite {\n /**\n * @param attributes The node attributes.\n * @param children The child nodes.\n */\n constructor(attributes: Attribute[], children: Node[]) {\n super(\"parallel\", attributes, children);\n }\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // Keep a count of the number of succeeded child nodes.\n let succeededCount = 0;\n\n let hasChildFailed = false;\n\n // Iterate over all of the children of this node.\n for (const child of this.children) {\n // If the child has never been updated or is running then we will need to update it now.\n if (child.getState() === State.READY || child.getState() === State.RUNNING) {\n // Update the child of this node.\n child.update(agent, options);\n }\n\n // If the current child has a state of 'SUCCEEDED' then we should move on to the next child.\n if (child.getState() === State.SUCCEEDED) {\n // The child node has succeeded, keep track of this to determine if all children have.\n succeededCount++;\n\n // The child node succeeded, but we have not finished checking every child node yet.\n continue;\n }\n\n // If the current child has a state of 'FAILED' then this node is also a 'FAILED' node.\n if (child.getState() === State.FAILED) {\n hasChildFailed = true;\n\n // There is no need to check the rest of the children.\n break;\n }\n\n // The node should be in the 'RUNNING' state.\n if (child.getState() !== State.RUNNING) {\n // The child node was not in an expected state.\n throw new Error(\"child node was not in an expected state.\");\n }\n }\n\n if (hasChildFailed) {\n // This node is a 'FAILED' node.\n this.setState(State.FAILED);\n\n // Abort every running child.\n for (const child of this.children) {\n if (child.getState() === State.RUNNING) {\n child.abort(agent);\n }\n }\n } else {\n // If all children have succeeded then this node has also succeeded, otherwise it is still running.\n this.setState(succeededCount === this.children.length ? State.SUCCEEDED : State.RUNNING);\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => \"PARALLEL\";\n}\n", "import Composite from \"./Composite\";\nimport Node from \"../Node\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A SELECTOR node.\n * The child nodes are executed in sequence until one succeeds or all fail.\n */\nexport default class Selector extends Composite {\n /**\n * @param attributes The node attributes.\n * @param children The child nodes.\n */\n constructor(attributes: Attribute[], protected children: Node[]) {\n super(\"selector\", attributes, children);\n }\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // Iterate over all of the children of this node.\n for (const child of this.children) {\n // If the child has never been updated or is running then we will need to update it now.\n if (child.getState() === State.READY || child.getState() === State.RUNNING) {\n // Update the child of this node.\n child.update(agent, options);\n }\n\n // If the current child has a state of 'SUCCEEDED' then this node is also a 'SUCCEEDED' node.\n if (child.getState() === State.SUCCEEDED) {\n // This node is a 'SUCCEEDED' node.\n this.setState(State.SUCCEEDED);\n\n // There is no need to check the rest of the selector nodes.\n return;\n }\n\n // If the current child has a state of 'FAILED' then we should move on to the next child.\n if (child.getState() === State.FAILED) {\n // Find out if the current child is the last one in the selector.\n // If it is then this sequence node has also failed.\n if (this.children.indexOf(child) === this.children.length - 1) {\n // This node is a 'FAILED' node.\n this.setState(State.FAILED);\n\n // There is no need to check the rest of the selector as we have completed it.\n return;\n } else {\n // The child node failed, try the next one.\n continue;\n }\n }\n\n // The node should be in the 'RUNNING' state.\n if (child.getState() === State.RUNNING) {\n // This node is a 'RUNNING' node.\n this.setState(State.RUNNING);\n\n // There is no need to check the rest of the selector as the current child is still running.\n return;\n }\n\n // The child node was not in an expected state.\n throw new Error(\"child node was not in an expected state.\");\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => \"SELECTOR\";\n}\n", "import Composite from \"./Composite\";\nimport Node from \"../Node\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A SEQUENCE node.\n * The child nodes are executed in sequence until one fails or all succeed.\n */\nexport default class Sequence extends Composite {\n /**\n * @param attributes The node attributes.\n * @param children The child nodes.\n */\n constructor(attributes: Attribute[], protected children: Node[]) {\n super(\"sequence\", attributes, children);\n }\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // Iterate over all of the children of this node.\n for (const child of this.children) {\n // If the child has never been updated or is running then we will need to update it now.\n if (child.getState() === State.READY || child.getState() === State.RUNNING) {\n // Update the child of this node.\n child.update(agent, options);\n }\n\n // If the current child has a state of 'SUCCEEDED' then we should move on to the next child.\n if (child.getState() === State.SUCCEEDED) {\n // Find out if the current child is the last one in the sequence.\n // If it is then this sequence node has also succeeded.\n if (this.children.indexOf(child) === this.children.length - 1) {\n // This node is a 'SUCCEEDED' node.\n this.setState(State.SUCCEEDED);\n\n // There is no need to check the rest of the sequence as we have completed it.\n return;\n } else {\n // The child node succeeded, but we have not finished the sequence yet.\n continue;\n }\n }\n\n // If the current child has a state of 'FAILED' then this node is also a 'FAILED' node.\n if (child.getState() === State.FAILED) {\n // This node is a 'FAILED' node.\n this.setState(State.FAILED);\n\n // There is no need to check the rest of the sequence.\n return;\n }\n\n // The node should be in the 'RUNNING' state.\n if (child.getState() === State.RUNNING) {\n // This node is a 'RUNNING' node.\n this.setState(State.RUNNING);\n\n // There is no need to check the rest of the sequence as the current child is still running.\n return;\n }\n\n // The child node was not in an expected state.\n throw new Error(\"child node was not in an expected state.\");\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => \"SEQUENCE\";\n}\n", "import createLotto from \"lotto-draw\";\n\nimport Node from \"../Node\";\nimport Composite from \"./Composite\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A LOTTO node.\n * A winning child is picked on the initial update of this node, based on ticket weighting.\n * The state of this node will match the state of the winning child.\n */\nexport default class Lotto extends Composite {\n /**\n * @param attributes The node attributes.\n * @param weights The child node weights.\n * @param children The child nodes.\n */\n constructor(attributes: Attribute[], private weights: number[] | undefined, children: Node[]) {\n super(\"lotto\", attributes, children);\n }\n\n /**\n * The child node selected to be the active one.\n */\n private selectedChild: Node | undefined;\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // If this node is in the READY state then we need to pick a winning child node.\n if (this.is(State.READY)) {\n // Create a lotto draw with which to randomly pick a child node to become the active one.\n const lottoDraw = createLotto({\n // Hook up the optional 'random' behaviour tree function option to the one used by 'lotto-draw'.\n random: options.random,\n // Pass in each child node as a participant in the lotto draw with their respective ticket count.\n participants: this.children.map((child, index) => [child, this.weights?.[index] || 1])\n });\n\n // Randomly pick a child based on ticket weighting, this will become the active child for this composite node.\n this.selectedChild = lottoDraw.draw() || undefined;\n }\n\n // If something went wrong and we don't have an active child then we should throw an error.\n if (!this.selectedChild) {\n throw new Error(\"failed to update lotto node as it has no active child\");\n }\n\n // If the selected child has never been updated or is running then we will need to update it now.\n if (this.selectedChild.getState() === State.READY || this.selectedChild.getState() === State.RUNNING) {\n this.selectedChild.update(agent, options);\n }\n\n // The state of the lotto node is the state of its selected child.\n this.setState(this.selectedChild.getState());\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => (this.weights ? `LOTTO [${this.weights.join(\",\")}]` : \"LOTTO\");\n}\n", "import Node from \"../Node\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\n\n/**\n * A decorator node that wraps a single child node.\n */\nexport default abstract class Decorator extends Node {\n /**\n * @param type The node type.\n * @param attributes The node attributes.\n * @param child The child node.\n */\n constructor(type: string, attributes: Attribute[], protected child: Node) {\n super(type, attributes, []);\n }\n\n /**\n * Gets whether this node is a leaf node.\n */\n isLeafNode = () => false;\n\n /**\n * Gets the children of this node.\n */\n getChildren = () => [this.child];\n\n /**\n * Reset the state of the node.\n */\n reset = () => {\n // Reset the state of this node.\n this.setState(State.READY);\n\n // Reset the state of the child node.\n this.child.reset();\n };\n\n /**\n * Abort the running of this node.\n * @param agent The agent.\n */\n abort = (agent: Agent) => {\n // There is nothing to do if this node is not in the running state.\n if (!this.is(State.RUNNING)) {\n return;\n }\n\n // Abort the child node.\n this.child.abort(agent);\n\n // Reset the state of this node.\n this.reset();\n\n this.getAttribute(\"exit\")?.callAgentFunction(agent, false, true);\n };\n}\n", "import Node from \"../Node\";\nimport Decorator from \"./Decorator\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A Fail node.\n * This node wraps a single child and will always move to the 'FAILED' state when the child moves to a 'SUCCEEDED' or 'FAILED' state.\n */\nexport default class Fail extends Decorator {\n /**\n * @param attributes The node attributes.\n * @param child The child node.\n */\n constructor(attributes: Attribute[], child: Node) {\n super(\"fail\", attributes, child);\n }\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // If the child has never been updated or is running then we will need to update it now.\n if (this.child.getState() === State.READY || this.child.getState() === State.RUNNING) {\n this.child.update(agent, options);\n }\n\n // The state of this node will depend in the state of its child.\n switch (this.child.getState()) {\n case State.RUNNING:\n this.setState(State.RUNNING);\n break;\n\n case State.SUCCEEDED:\n case State.FAILED:\n this.setState(State.FAILED);\n break;\n\n default:\n this.setState(State.READY);\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => \"FAIL\";\n}\n", "import Decorator from \"./Decorator\";\nimport State from \"../../State\";\nimport Node from \"../Node\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A Flip node.\n * This node wraps a single child and will flip the state of the child state.\n */\nexport default class Flip extends Decorator {\n /**\n * @param attributes The node attributes.\n * @param child The child node.\n */\n constructor(attributes: Attribute[], child: Node) {\n super(\"flip\", attributes, child);\n }\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // If the child has never been updated or is running then we will need to update it now.\n if (this.child.getState() === State.READY || this.child.getState() === State.RUNNING) {\n this.child.update(agent, options);\n }\n\n // The state of this node will depend in the state of its child.\n switch (this.child.getState()) {\n case State.RUNNING:\n this.setState(State.RUNNING);\n break;\n\n case State.SUCCEEDED:\n this.setState(State.FAILED);\n break;\n\n case State.FAILED:\n this.setState(State.SUCCEEDED);\n break;\n\n default:\n this.setState(State.READY);\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => \"FLIP\";\n}\n", "import Node from \"../Node\";\nimport Decorator from \"./Decorator\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A REPEAT node.\n * The node has a single child which can have:\n * -- A number of iterations for which to repeat the child node.\n * -- An infinite repeat loop if neither an iteration count or a condition function is defined.\n * The REPEAT node will stop and have a 'FAILED' state if its child is ever in a 'FAILED' state after an update.\n * The REPEAT node will attempt to move on to the next iteration if its child is ever in a 'SUCCEEDED' state.\n */\nexport default class Repeat extends Decorator {\n /**\n * @param attributes The node attributes.\n * @param iterations The number of iterations to repeat the child node.\n * @param iterationsMin The minimum possible number of iterations to repeat the child node.\n * @param iterationsMax The maximum possible number of iterations to repeat the child node.\n * @param child The child node.\n */\n constructor(\n attributes: Attribute[],\n private iterations: number | null,\n private iterationsMin: number | null,\n private iterationsMax: number | null,\n child: Node\n ) {\n super(\"repeat\", attributes, child);\n }\n\n /**\n * The number of target iterations to make.\n */\n private targetIterationCount: number | null = null;\n\n /**\n * The current iteration count.\n */\n private currentIterationCount: number = 0;\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // If this node is in the READY state then we need to reset the child and the target iteration count.\n if (this.is(State.READY)) {\n // Reset the child node.\n this.child.reset();\n\n // Reset the current iteration count.\n this.currentIterationCount = 0;\n\n // Set the target iteration count.\n this.setTargetIterationCount(options);\n }\n\n // Do a check to see if we can iterate. If we can then this node will move into the 'RUNNING' state.\n // If we cannot iterate then we have hit our target iteration count, which means that the node has succeeded.\n if (this.canIterate()) {\n // This node is in the running state and can do its initial iteration.\n this.setState(State.RUNNING);\n\n // We may have already completed an iteration, meaning that the child node will be in the SUCCEEDED state.\n // If this is the case then we will have to reset the child node now.\n if (this.child.getState() === State.SUCCEEDED) {\n this.child.reset();\n }\n\n // Update the child of this node.\n this.child.update(agent, options);\n\n // If the child moved into the FAILED state when we updated it then there is nothing left to do and this node has also failed.\n // If it has moved into the SUCCEEDED state then we have completed the current iteration.\n if (this.child.getState() === State.FAILED) {\n // The child has failed, meaning that this node has failed.\n this.setState(State.FAILED);\n\n return;\n } else if (this.child.getState() === State.SUCCEEDED) {\n // We have completed an iteration.\n this.currentIterationCount += 1;\n }\n } else {\n // This node is in the 'SUCCEEDED' state as we cannot iterate any more.\n this.setState(State.SUCCEEDED);\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => {\n if (this.iterations !== null) {\n return `REPEAT ${this.iterations}x`;\n } else if (this.iterationsMin !== null && this.iterationsMax !== null) {\n return `REPEAT ${this.iterationsMin}x-${this.iterationsMax}x`;\n } else {\n return \"REPEAT\";\n }\n };\n\n /**\n * Reset the state of the node.\n */\n reset = () => {\n // Reset the state of this node.\n this.setState(State.READY);\n\n // Reset the current iteration count.\n this.currentIterationCount = 0;\n\n // Reset the child node.\n this.child.reset();\n };\n\n /**\n * Gets whether an iteration can be made.\n * @returns Whether an iteration can be made.\n */\n private canIterate = () => {\n if (this.targetIterationCount !== null) {\n // We can iterate as long as we have not reached our target iteration count.\n return this.currentIterationCount < this.targetIterationCount;\n }\n\n // If neither an iteration count or a condition function were defined then we can iterate indefinitely.\n return true;\n };\n\n /**\n * Sets the target iteration count.\n * @param options The behaviour tree options object.\n */\n private setTargetIterationCount = (options: BehaviourTreeOptions) => {\n // Are we dealing with an explicit iteration count or will we be randomly picking a iteration count between the min and max iteration count.\n if (this.iterations !== null) {\n this.targetIterationCount = this.iterations;\n } else if (this.iterationsMin !== null && this.iterationsMax !== null) {\n // We will be picking a random iteration count between a min and max iteration count, if the optional 'random'\n // behaviour tree function option is defined then we will be using that, otherwise we will fall back to using Math.random.\n const random = typeof options.random === \"function\" ? options.random : Math.random;\n\n // Pick a random iteration count between a min and max iteration count.\n this.targetIterationCount = Math.floor(\n random() * (this.iterationsMax - this.iterationsMin + 1) + this.iterationsMin\n );\n } else {\n this.targetIterationCount = null;\n }\n };\n}\n", "import Node from \"../Node\";\nimport Decorator from \"./Decorator\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A RETRY node.\n * The node has a single child which can have:\n * -- A number of iterations for which to repeat the child node.\n * -- An infinite repeat loop if neither an iteration count or a condition function is defined.\n * The RETRY node will stop and have a 'SUCCEEDED' state if its child is ever in a 'SUCCEEDED' state after an update.\n * The RETRY node will attempt to move on to the next iteration if its child is ever in a 'FAILED' state.\n */\nexport default class Retry extends Decorator {\n /**\n * @param attributes The node attributes.\n * @param attempts The number of attempts to retry the child node.\n * @param attemptsMin The minimum possible number of attempts to retry the child node.\n * @param attemptsMax The maximum possible number of attempts to retry the child node.\n * @param child The child node.\n */\n constructor(\n attributes: Attribute[],\n private attempts: number | null,\n private attemptsMin: number | null,\n private attemptsMax: number | null,\n child: Node\n ) {\n super(\"retry\", attributes, child);\n }\n\n /**\n * The number of target attempts to make.\n */\n private targetAttemptCount: number | null = null;\n\n /**\n * The current attempt count.\n */\n private currentAttemptCount: number = 0;\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // If this node is in the READY state then we need to reset the child and the target attempt count.\n if (this.is(State.READY)) {\n // Reset the child node.\n this.child.reset();\n\n // Reset the current attempt count.\n this.currentAttemptCount = 0;\n\n // Set the target attempt count.\n this.setTargetAttemptCount(options);\n }\n\n // Do a check to see if we can attempt. If we can then this node will move into the 'RUNNING' state.\n // If we cannot attempt then we have hit our target attempt count, which means that the node has succeeded.\n if (this.canAttempt()) {\n // This node is in the running state and can do its initial attempt.\n this.setState(State.RUNNING);\n\n // We may have already completed an attempt, meaning that the child node will be in the FAILED state.\n // If this is the case then we will have to reset the child node now.\n if (this.child.getState() === State.FAILED) {\n this.child.reset();\n }\n\n // Update the child of this node.\n this.child.update(agent, options);\n\n // If the child moved into the SUCCEEDED state when we updated it then there is nothing left to do and this node has also succeeded.\n // If it has moved into the FAILED state then we have completed the current attempt.\n if (this.child.getState() === State.SUCCEEDED) {\n // The child has succeeded, meaning that this node has succeeded.\n this.setState(State.SUCCEEDED);\n\n return;\n } else if (this.child.getState() === State.FAILED) {\n // We have completed an attempt.\n this.currentAttemptCount += 1;\n }\n } else {\n // This node is in the 'FAILED' state as we cannot iterate any more.\n this.setState(State.FAILED);\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => {\n if (this.attempts !== null) {\n return `RETRY ${this.attempts}x`;\n } else if (this.attemptsMin !== null && this.attemptsMax !== null) {\n return `RETRY ${this.attemptsMin}x-${this.attemptsMax}x`;\n } else {\n return \"RETRY\";\n }\n };\n\n /**\n * Reset the state of the node.\n */\n reset = () => {\n // Reset the state of this node.\n this.setState(State.READY);\n\n // Reset the current attempt count.\n this.currentAttemptCount = 0;\n\n // Reset the child node.\n this.child.reset();\n };\n\n /**\n * Gets whether an attempt can be made.\n * @returns Whether an attempt can be made.\n */\n canAttempt = () => {\n if (this.targetAttemptCount !== null) {\n // We can attempt as long as we have not reached our target attempt count.\n return this.currentAttemptCount < this.targetAttemptCount;\n }\n\n // If neither an attempt count or a condition function were defined then we can attempt indefinitely.\n return true;\n };\n\n /**\n * Sets the target attempt count.\n * @param options The behaviour tree options object.\n */\n setTargetAttemptCount = (options: BehaviourTreeOptions) => {\n // Are we dealing with an explicit attempt count or will we be randomly picking an attempt count between the min and max attempt count.\n if (this.attempts !== null) {\n this.targetAttemptCount = this.attempts;\n } else if (this.attemptsMin !== null && this.attemptsMax !== null) {\n // We will be picking a random attempt count between a min and max attempt count, if the optional 'random'\n // behaviour tree function option is defined then we will be using that, otherwise we will fall back to using Math.random.\n const random = typeof options.random === \"function\" ? options.random : Math.random;\n\n // Pick a random attempt count between a min and max attempt count.\n this.targetAttemptCount = Math.floor(\n random() * (this.attemptsMax - this.attemptsMin + 1) + this.attemptsMin\n );\n } else {\n this.targetAttemptCount = null;\n }\n };\n}\n", "import Node from \"../Node\";\nimport Decorator from \"./Decorator\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A Root node.\n * The root node will have a single child.\n */\nexport default class Root extends Decorator {\n /**\n * @param attributes The node attributes.\n * @param child The child node.\n */\n constructor(attributes: Attribute[], child: Node) {\n super(\"root\", attributes, child);\n }\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // If the child has never been updated or is running then we will need to update it now.\n if (this.child.getState() === State.READY || this.child.getState() === State.RUNNING) {\n // Update the child of this node.\n this.child.update(agent, options);\n }\n\n // The state of the root node is the state of its child.\n this.setState(this.child.getState());\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => \"ROOT\";\n}\n", "import Node from \"../Node\";\nimport Decorator from \"./Decorator\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A Succeed node.\n * This node wraps a single child and will always move to the 'SUCCEEDED' state when the child moves to a 'SUCCEEDED' or 'FAILED' state.\n */\nexport default class Succeed extends Decorator {\n /**\n * @param attributes The node attributes.\n * @param child The child node.\n */\n constructor(attributes: Attribute[], child: Node) {\n super(\"succeed\", attributes, child);\n }\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // If the child has never been updated or is running then we will need to update it now.\n if (this.child.getState() === State.READY || this.child.getState() === State.RUNNING) {\n this.child.update(agent, options);\n }\n\n // The state of this node will depend in the state of its child.\n switch (this.child.getState()) {\n case State.RUNNING:\n this.setState(State.RUNNING);\n break;\n\n case State.SUCCEEDED:\n case State.FAILED:\n this.setState(State.SUCCEEDED);\n break;\n\n default:\n this.setState(State.READY);\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => \"SUCCEED\";\n}\n", "import Node from \"../Node\";\n\n/**\n * A leaf node.\n */\nexport default abstract class Leaf extends Node {\n /**\n * Gets whether this node is a leaf node.\n */\n isLeafNode = () => true;\n}\n", "import { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\nimport State, { CompleteState } from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Leaf from \"./Leaf\";\nimport Lookup from \"../../Lookup\";\nimport Attribute from \"../../attributes/Attribute\";\n\n/**\n * An Action leaf node.\n * This represents an immediate or ongoing state of behaviour.\n */\nexport default class Action extends Leaf {\n /**\n * @param attributes The node attributes.\n * @param actionName The action name.\n * @param actionArguments The array of action argument definitions.\n */\n constructor(attributes: Attribute[], private actionName: string, private actionArguments: any[]) {\n super(\"action\", attributes, actionArguments);\n }\n\n /**\n * Whether there is a pending update promise.\n */\n private isUsingUpdatePromise = false;\n\n /**\n * The finished state result of an update promise.\n */\n private updatePromiseStateResult: CompleteState | null = null;\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // If the result of this action depends on an update promise then there is nothing to do until\n // it resolves, unless there has been a value set as a result of the update promise resolving.\n if (this.isUsingUpdatePromise) {\n // Check whether the update promise has resolved with a state value.\n if (this.updatePromiseStateResult) {\n // Set the state of this node to match the state returned by the promise.\n this.setState(this.updatePromiseStateResult);\n }\n\n return;\n }\n\n // Attempt to get the invoker for the action function.\n const actionFuncInvoker = Lookup.getFuncInvoker(agent, this.actionName);\n\n // The action function should be defined.\n if (actionFuncInvoker === null) {\n throw new Error(\n `cannot update action node as the action '${this.actionName}' function is not defined on the agent and has not been registered`\n );\n }\n\n // Call the action function, the result of which may be:\n // - The finished state of this action node.\n // - A promise to return a finished node state.\n // - Undefined if the node should remain in the running state.\n const updateResult = actionFuncInvoker(this.actionArguments) as CompleteState | Promise;\n\n if (updateResult instanceof Promise) {\n updateResult.then(\n (result) => {\n // If 'isUpdatePromisePending' is null then the promise was cleared as it was resolving, probably via an abort of reset.\n if (!this.isUsingUpdatePromise) {\n return;\n }\n\n // Check to make sure the result is a valid finished state.\n if (result !== State.SUCCEEDED && result !== State.FAILED) {\n throw new Error(\n \"action node promise resolved with an invalid value, expected a State.SUCCEEDED or State.FAILED value to be returned\"\n );\n }\n\n // Set pending update promise state result to be processed on next update.\n this.updatePromiseStateResult = result;\n },\n (reason) => {\n // If 'isUpdatePromisePending' is null then the promise was cleared as it was resolving, probably via an abort of reset.\n if (!this.isUsingUpdatePromise) {\n return;\n }\n\n // Just throw whatever was returned as the rejection argument.\n throw new Error(reason);\n }\n );\n\n // This node will be in the 'RUNNING' state until the update promise resolves.\n this.setState(State.RUNNING);\n\n // We are now waiting for the promise returned by the use to resolve before we know what state this node is in.\n this.isUsingUpdatePromise = true;\n } else {\n // Validate the returned value.\n this.validateUpdateResult(updateResult);\n\n // Set the state of this node, this may be undefined, which just means that the node is still in the 'RUNNING' state.\n this.setState(updateResult || State.RUNNING);\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => this.actionName;\n\n /**\n * Reset the state of the node.\n */\n reset = () => {\n // Reset the state of this node.\n this.setState(State.READY);\n\n // There is no longer an update promise that we care about.\n this.isUsingUpdatePromise = false;\n this.updatePromiseStateResult = null;\n };\n\n /**\n * Validate the result of an update function call.\n * @param result The result of an update function call.\n */\n private validateUpdateResult = (result: CompleteState | boolean) => {\n switch (result) {\n case State.SUCCEEDED:\n case State.FAILED:\n case undefined:\n return;\n default:\n throw new Error(\n `action '${this.actionName}' 'onUpdate' returned an invalid response, expected an optional State.SUCCEEDED or State.FAILED value to be returned`\n );\n }\n };\n}\n", "import { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Leaf from \"./Leaf\";\nimport Lookup from \"../../Lookup\";\nimport Attribute from \"../../attributes/Attribute\";\n\n/**\n * A Condition leaf node.\n * This will succeed or fail immediately based on an agent predicate, without moving to the 'RUNNING' state.\n */\nexport default class Condition extends Leaf {\n /**\n * @param attributes The node attributes.\n * @param conditionName The name of the condition function.\n * @param conditionArguments The array of condition argument definitions.\n */\n constructor(attributes: Attribute[], private conditionName: string, private conditionArguments: any[]) {\n super(\"condition\", attributes, conditionArguments);\n }\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // Attempt to get the invoker for the condition function.\n const conditionFuncInvoker = Lookup.getFuncInvoker(agent, this.conditionName);\n\n // The condition function should be defined.\n if (conditionFuncInvoker === null) {\n throw new Error(\n `cannot update condition node as the condition '${this.conditionName}' function is not defined on the agent and has not been registered`\n );\n }\n\n // Call the condition function to determine the state of this node.\n this.setState(!!conditionFuncInvoker(this.conditionArguments) ? State.SUCCEEDED : State.FAILED);\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => this.conditionName;\n}\n", "import Leaf from \"./Leaf\";\nimport State from \"../../State\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { Agent } from \"../../Agent\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A WAIT node.\n * The state of this node will change to SUCCEEDED after a duration of time\n */\nexport default class Wait extends Leaf {\n /**\n * @param attributes The node attributes.\n * @param duration The duration that this node will wait to succeed in milliseconds.\n * @param durationMin The minimum possible duration in milliseconds that this node will wait to succeed.\n * @param durationMax The maximum possible duration in milliseconds that this node will wait to succeed.\n */\n constructor(\n attributes: Attribute[],\n private duration: number | null,\n private durationMin: number | null,\n private durationMax: number | null\n ) {\n super(\"wait\", attributes, []);\n }\n\n /**\n * The time in milliseconds at which this node was first updated.\n */\n private initialUpdateTime: number = 0;\n\n /**\n * The total duration in milliseconds that this node will be waiting for.\n */\n private totalDuration: number | null = null;\n\n /**\n * The duration in milliseconds that this node has been waiting for.\n */\n private waitedDuration: number = 0;\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // If this node is in the READY state then we need to set the initial update time.\n if (this.is(State.READY)) {\n // Set the initial update time.\n this.initialUpdateTime = new Date().getTime();\n\n // Set the initial waited duration.\n this.waitedDuration = 0;\n\n // Are we dealing with an explicit duration or will we be randomly picking a duration between the min and max duration.\n if (this.duration !== null) {\n this.totalDuration = this.duration;\n } else if (this.durationMin !== null && this.durationMax !== null) {\n // We will be picking a random duration between a min and max duration, if the optional 'random' behaviour tree\n // function option is defined then we will be using that, otherwise we will fall back to using Math.random.\n const random = typeof options.random === \"function\" ? options.random : Math.random;\n\n // Pick a random duration between a min and max duration.\n this.totalDuration = Math.floor(\n random() * (this.durationMax - this.durationMin + 1) + this.durationMin\n );\n } else {\n this.totalDuration = null;\n }\n\n // The node is now running until we finish waiting.\n this.setState(State.RUNNING);\n }\n\n // If we have no total duration then this wait node will wait indefinitely until it is aborted.\n if (this.totalDuration === null) {\n return;\n }\n\n // If we have a 'getDeltaTime' function defined as part of our options then we will use it to figure out how long we have waited for.\n if (typeof options.getDeltaTime === \"function\") {\n // Get the delta time.\n const deltaTime = options.getDeltaTime();\n\n // Our delta time must be a valid number and cannot be NaN.\n if (typeof deltaTime !== \"number\" || isNaN(deltaTime)) {\n throw new Error(\"The delta time must be a valid number and not NaN.\");\n }\n\n // Update the amount of time that this node has been waiting for based on the delta time.\n this.waitedDuration += deltaTime * 1000;\n } else {\n // We are not using a delta time, so we will just work out hom much time has passed since the first update.\n this.waitedDuration = new Date().getTime() - this.initialUpdateTime;\n }\n\n // Have we waited long enough?\n if (this.waitedDuration >= this.totalDuration) {\n // We have finished waiting!\n this.setState(State.SUCCEEDED);\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => {\n if (this.duration !== null) {\n return `WAIT ${this.duration}ms`;\n } else if (this.durationMin !== null && this.durationMax !== null) {\n return `WAIT ${this.durationMin}ms-${this.durationMax}ms`;\n } else {\n return \"WAIT\";\n }\n };\n}\n", "import Guard from \"./guards/Guard\";\n\nexport type AttributeDetails = {\n /** The attribute type. */\n type: string;\n\n /** The attribute arguments. */\n args: any[];\n};\n\n/**\n * A base node attribute.\n */\nexport default abstract class Attribute {\n /**\n * @param type The node attribute type.\n * @param args The array of attribute arguments.\n */\n constructor(public type: string, public args: any[]) {}\n\n /**\n * Gets the attribute details.\n */\n abstract getDetails(): TAttributeDetails;\n\n /**\n * Gets whether this attribute is a guard.\n */\n abstract isGuard: () => this is Guard;\n}\n", "import { Agent } from \"../../Agent\";\nimport Attribute, { AttributeDetails } from \"../Attribute\";\n\nexport type GuardAttributeDetails = {\n /** The name of the condition function that determines whether the guard is satisfied. */\n condition: string;\n} & AttributeDetails;\n\n/**\n * A base node guard attribute.\n */\nexport default abstract class Guard extends Attribute {\n /**\n * @param type The node attribute type.\n * @param args The array of decorator argument definitions.\n * @param condition The name of the condition function that determines whether the guard is satisfied.\n */\n constructor(type: string, args: any[], private condition: string) {\n super(type, args);\n }\n\n /**\n * Gets the name of the condition function that determines whether the guard is satisfied.\n */\n getCondition = () => this.condition;\n\n /**\n * Gets whether this attribute is a guard.\n */\n isGuard = () => true;\n\n /**\n * Gets the attribute details.\n */\n getDetails(): GuardAttributeDetails {\n return {\n type: this.type,\n args: this.args,\n condition: this.getCondition()\n };\n }\n\n /**\n * Gets whether the guard is satisfied.\n * @param agent The agent.\n * @returns Whether the guard is satisfied.\n */\n abstract isSatisfied(agent: Agent): boolean;\n}\n", "import Guard from \"./Guard\";\nimport Lookup from \"../../Lookup\";\nimport { Agent } from \"../../Agent\";\n\n/**\n * A WHILE guard which is satisfied as long as the given condition remains true.\n */\nexport default class While extends Guard {\n /**\n * @param condition The name of the condition function that determines whether the guard is satisfied.\n * @param args The array of decorator argument definitions.\n */\n constructor(condition: string, args: any[]) {\n super(\"while\", args, condition);\n }\n\n /**\n * Gets whether the guard is satisfied.\n * @param agent The agent.\n * @returns Whether the guard is satisfied.\n */\n isSatisfied = (agent: Agent) => {\n // Attempt to get the invoker for the condition function.\n const conditionFuncInvoker = Lookup.getFuncInvoker(agent, this.getCondition());\n\n // The condition function should be defined.\n if (conditionFuncInvoker === null) {\n throw new Error(\n `cannot evaluate node guard as the condition '${this.getCondition()}' function is not defined on the agent and has not been registered`\n );\n }\n\n // Call the condition function to determine whether this guard is satisfied.\n return !!conditionFuncInvoker(this.args);\n };\n}\n", "import Guard from \"./Guard\";\nimport Lookup from \"../../Lookup\";\nimport { Agent } from \"../../Agent\";\n\n/**\n * An UNTIL guard which is satisfied as long as the given condition remains false.\n */\nexport default class Until extends Guard {\n /**\n * @param condition The name of the condition function that determines whether the guard is satisfied.\n * @param args The array of decorator argument definitions.\n */\n constructor(condition: string, args: any[]) {\n super(\"until\", args, condition);\n }\n\n /**\n * Gets whether the guard is satisfied.\n * @param agent The agent.\n * @returns Whether the guard is satisfied.\n */\n isSatisfied = (agent: Agent) => {\n // Attempt to get the invoker for the condition function.\n const conditionFuncInvoker = Lookup.getFuncInvoker(agent, this.getCondition());\n\n // The condition function should be defined.\n if (conditionFuncInvoker === null) {\n throw new Error(\n `cannot evaluate node guard as the condition '${this.getCondition()}' function is not defined on the agent and has not been registered`\n );\n }\n\n // Call the condition function to determine whether this guard is satisfied.\n return !!!conditionFuncInvoker(this.args);\n };\n}\n", "import { Agent } from \"../../Agent\";\nimport Attribute, { AttributeDetails } from \"../Attribute\";\n\nexport type CallbackAttributeDetails = {\n /** The name of the agent function that is called. */\n functionName: string;\n} & AttributeDetails;\n\n/**\n * A base node callback attribute.\n */\nexport default abstract class Callback extends Attribute {\n /**\n * @param type The node attribute type.\n * @param args The array of decorator argument definitions.\n * @param functionName The name of the agent function to call.\n */\n constructor(type: string, args: any[], private functionName: string) {\n super(type, args);\n }\n\n /**\n * Gets the name of the agent function to call.\n */\n getFunctionName = () => this.functionName;\n\n /**\n * Gets whether this attribute is a guard.\n */\n isGuard = () => false;\n\n /**\n * Gets the attribute details.\n */\n getDetails(): CallbackAttributeDetails {\n return {\n type: this.type,\n args: this.args,\n functionName: this.getFunctionName()\n };\n }\n\n /**\n * Attempt to call the agent function that this callback refers to.\n * @param agent The agent.\n */\n abstract callAgentFunction: (agent: Agent, isSuccess: boolean, isAborted: boolean) => void;\n}\n", "import Callback from \"./Callback\";\nimport Lookup from \"../../Lookup\";\nimport { Agent } from \"../../Agent\";\n\n/**\n * An ENTRY callback which defines an agent function to call when the associated node is updated and moves out of running state.\n */\nexport default class Entry extends Callback {\n /**\n * @param functionName The name of the agent function to call.\n * @param args The array of callback argument definitions.\n */\n constructor(functionName: string, args: any[]) {\n super(\"entry\", args, functionName);\n }\n\n /**\n * Attempt to call the agent function that this callback refers to.\n * @param agent The agent.\n */\n callAgentFunction = (agent: Agent) => {\n // Attempt to get the invoker for the callback function.\n const callbackFuncInvoker = Lookup.getFuncInvoker(agent, this.getFunctionName());\n\n // The callback function should be defined.\n if (callbackFuncInvoker === null) {\n throw new Error(\n `cannot call entry function '${this.getFunctionName()}' as is not defined on the agent and has not been registered`\n );\n }\n\n // Call the callback function.\n callbackFuncInvoker(this.args);\n };\n}\n", "import Callback from \"./Callback\";\nimport Lookup from \"../../Lookup\";\nimport { Agent } from \"../../Agent\";\n\n/**\n * A STEP callback which defines an agent function to call when the associated node is updated.\n */\nexport default class Step extends Callback {\n /**\n * @param functionName The name of the agent function to call.\n * @param args The array of callback argument definitions.\n */\n constructor(functionName: string, args: any[]) {\n super(\"step\", args, functionName);\n }\n\n /**\n * Attempt to call the agent function that this callback refers to.\n * @param agent The agent.\n */\n callAgentFunction = (agent: Agent) => {\n // Attempt to get the invoker for the callback function.\n const callbackFuncInvoker = Lookup.getFuncInvoker(agent, this.getFunctionName());\n\n // The callback function should be defined.\n if (callbackFuncInvoker === null) {\n throw new Error(\n `cannot call step function '${this.getFunctionName()}' as is not defined on the agent and has not been registered`\n );\n }\n\n // Call the callback function.\n callbackFuncInvoker(this.args);\n };\n}\n", "import Callback from \"./Callback\";\nimport Lookup from \"../../Lookup\";\nimport { Agent } from \"../../Agent\";\n\n/**\n * An EXIT callback which defines an agent function to call when the associated node is updated and moves to a finished state or is aborted.\n */\nexport default class Exit extends Callback {\n /**\n * @param functionName The name of the agent function to call.\n * @param args The array of callback argument definitions.\n */\n constructor(functionName: string, args: any[]) {\n super(\"exit\", args, functionName);\n }\n\n /**\n * Attempt to call the agent function that this callback refers to.\n * @param agent The agent.\n * @param isSuccess Whether the decorated node was left with a success state.\n * @param isAborted Whether the decorated node was aborted.\n */\n callAgentFunction = (agent: Agent, isSuccess: boolean, isAborted: boolean) => {\n // Attempt to get the invoker for the callback function.\n const callbackFuncInvoker = Lookup.getFuncInvoker(agent, this.getFunctionName());\n\n // The callback function should be defined.\n if (callbackFuncInvoker === null) {\n throw new Error(\n `cannot call exit function '${this.getFunctionName()}' as is not defined on the agent and has not been registered`\n );\n }\n\n // Call the callback function\n callbackFuncInvoker([{ value: { succeeded: isSuccess, aborted: isAborted } }, ...this.args]);\n };\n}\n", "import { AnyNodeDefinition, RootNodeDefinition } from \"./BehaviourTreeDefinition\";\nimport GuardPath, { GuardPathPart } from \"./attributes/guards/GuardPath\";\nimport { validateBranchSubtreeLinks } from \"./BehaviourTreeDefinitionValidator\";\nimport { isInteger } from \"./BehaviourTreeDefinitionUtilities\";\nimport Node from \"./nodes/Node\";\nimport Composite from \"./nodes/composite/Composite\";\nimport Decorator from \"./nodes/decorator/Decorator\";\nimport Parallel from \"./nodes/composite/Parallel\";\nimport Selector from \"./nodes/composite/Selector\";\nimport Sequence from \"./nodes/composite/Sequence\";\nimport Lotto from \"./nodes/composite/Lotto\";\nimport Fail from \"./nodes/decorator/Fail\";\nimport Flip from \"./nodes/decorator/Flip\";\nimport Repeat from \"./nodes/decorator/Repeat\";\nimport Retry from \"./nodes/decorator/Retry\";\nimport Root from \"./nodes/decorator/Root\";\nimport Succeed from \"./nodes/decorator/Succeed\";\nimport Action from \"./nodes/leaf/Action\";\nimport Condition from \"./nodes/leaf/Condition\";\nimport Wait from \"./nodes/leaf/Wait\";\nimport Lookup from \"./Lookup\";\nimport Attribute from \"./attributes/Attribute\";\nimport While from \"./attributes/guards/While\";\nimport Until from \"./attributes/guards/Until\";\nimport Entry from \"./attributes/callbacks/Entry\";\nimport Step from \"./attributes/callbacks/Step\";\nimport Exit from \"./attributes/callbacks/Exit\";\n\n/**\n * A type representing any node instance in a behaviour tree.\n */\ntype AnyNode =\n | Root\n | Action\n | Condition\n | Wait\n | Sequence\n | Selector\n | Lotto\n | Parallel\n | Repeat\n | Retry\n | Flip\n | Succeed\n | Fail;\n\n/**\n * A type defining a mapping of root node identifiers to root node definitions.\n */\ntype RootNodeDefinitionMap = { [key: string | symbol]: RootNodeDefinition };\n\n/**\n * A symbol to use as the main root key in any root node mappings.\n */\nconst MAIN_ROOT_NODE_KEY = Symbol(\"__root__\");\n\n/**\n * Build and populate the root nodes based on the provided definition, assuming that the definition has been validated.\n * @param definition The root node definitions.\n * @returns The built and populated root node definitions.\n */\nexport default function buildRootNode(definition: RootNodeDefinition[]): Root {\n // Create a mapping of root node identifers to root node definitions, including globally registered subtree root node definitions.\n const rootNodeDefinitionMap = createRootNodeDefinitionMap(definition);\n\n // Now that we have all of our root node definitons (those part of the tree definition and those globally\n // registered) we should validate the definition. This will also double-check that we dont have any circular\n // dependencies in our branch -> subtree references and that we have no broken branch -> subtree links.\n validateBranchSubtreeLinks(definition, true);\n\n // Create our populated tree of node instances, starting with our main root node.\n const rootNode = nodeFactory(rootNodeDefinitionMap[MAIN_ROOT_NODE_KEY], rootNodeDefinitionMap) as Root;\n\n // Set a guard path on every leaf of the tree to evaluate as part of each update.\n applyLeafNodeGuardPaths(rootNode);\n\n // We only need to return the main root node.\n return rootNode;\n}\n\n/**\n * A factory function which creates a node instance based on the specified definition.\n * @param definition The node definition.\n * @param rootNodeDefinitionMap The mapping of root node identifers to root node definitions, including globally registered subtree root node definitions.\n * @returns A node instance based on the specified definition.\n */\nfunction nodeFactory(definition: AnyNodeDefinition, rootNodeDefinitionMap: RootNodeDefinitionMap): AnyNode {\n // Get the attributes for the node.\n const attributes = nodeAttributesFactory(definition);\n\n // Create the node instance based on the definition type.\n switch (definition.type) {\n case \"root\":\n return new Root(attributes, nodeFactory(definition.child, rootNodeDefinitionMap));\n\n case \"repeat\":\n let iterations: number | null = null;\n let iterationsMin: number | null = null;\n let iterationsMax: number | null = null;\n\n if (Array.isArray(definition.iterations)) {\n iterationsMin = definition.iterations[0];\n iterationsMax = definition.iterations[1];\n } else if (isInteger(definition.iterations)) {\n iterations = definition.iterations!;\n }\n\n return new Repeat(\n attributes,\n iterations,\n iterationsMin,\n iterationsMax,\n nodeFactory(definition.child, rootNodeDefinitionMap)\n );\n\n case \"retry\":\n let attempts: number | null = null;\n let attemptsMin: number | null = null;\n let attemptsMax: number | null = null;\n\n if (Array.isArray(definition.attempts)) {\n attemptsMin = definition.attempts[0];\n attemptsMax = definition.attempts[1];\n } else if (isInteger(definition.attempts)) {\n attempts = definition.attempts!;\n }\n\n return new Retry(\n attributes,\n attempts,\n attemptsMin,\n attemptsMax,\n nodeFactory(definition.child, rootNodeDefinitionMap)\n );\n\n case \"flip\":\n return new Flip(attributes, nodeFactory(definition.child, rootNodeDefinitionMap));\n\n case \"succeed\":\n return new Succeed(attributes, nodeFactory(definition.child, rootNodeDefinitionMap));\n\n case \"fail\":\n return new Fail(attributes, nodeFactory(definition.child, rootNodeDefinitionMap));\n\n case \"sequence\":\n return new Sequence(\n attributes,\n definition.children.map((child) => nodeFactory(child, rootNodeDefinitionMap))\n );\n\n case \"selector\":\n return new Selector(\n attributes,\n definition.children.map((child) => nodeFactory(child, rootNodeDefinitionMap))\n );\n\n case \"parallel\":\n return new Parallel(\n attributes,\n definition.children.map((child) => nodeFactory(child, rootNodeDefinitionMap))\n );\n\n case \"lotto\":\n return new Lotto(\n attributes,\n definition.weights,\n definition.children.map((child) => nodeFactory(child, rootNodeDefinitionMap))\n );\n\n case \"branch\":\n return nodeFactory(rootNodeDefinitionMap[definition.ref].child, rootNodeDefinitionMap);\n\n case \"action\":\n return new Action(attributes, definition.call, definition.args || []);\n\n case \"condition\":\n return new Condition(attributes, definition.call, definition.args || []);\n\n case \"wait\":\n let duration: number | null = null;\n let durationMin: number | null = null;\n let durationMax: number | null = null;\n\n if (Array.isArray(definition.duration)) {\n durationMin = definition.duration[0];\n durationMax = definition.duration[1];\n } else if (isInteger(definition.duration)) {\n duration = definition.duration!;\n }\n\n return new Wait(attributes, duration, durationMin, durationMax);\n }\n}\n\n/**\n * Creates an array of node attribute instances based on the specified node definition.\n * @param definition The node definition.\n * @returns An array of node attribute instances based on the specified node definition.\n */\nfunction nodeAttributesFactory(definition: AnyNodeDefinition): Attribute[] {\n const attributes: Attribute[] = [];\n\n if (definition.while) {\n attributes.push(new While(definition.while.call, definition.while.args ?? []));\n }\n\n if (definition.until) {\n attributes.push(new Until(definition.until.call, definition.until.args ?? []));\n }\n\n if (definition.entry) {\n attributes.push(new Entry(definition.entry.call, definition.entry.args ?? []));\n }\n\n if (definition.step) {\n attributes.push(new Step(definition.step.call, definition.step.args ?? []));\n }\n\n if (definition.exit) {\n attributes.push(new Exit(definition.exit.call, definition.exit.args ?? []));\n }\n\n return attributes;\n}\n\n/**\n * Creates a mapping of root node identifers to root node definitions, mixing in globally registered subtree root node definitions.\n * @param definition The root node definitions.\n * @returns A mapping of root node identifers to root node definitions, including globally registered subtree root node definitions.\n */\nfunction createRootNodeDefinitionMap(definition: RootNodeDefinition[]): RootNodeDefinitionMap {\n // Create a mapping of root node identifers to root node definitions.\n const rootNodeMap: RootNodeDefinitionMap = {};\n\n // Add in any registered subtree root node definitions.\n for (const [name, rootNodeDefinition] of Object.entries(Lookup.getSubtrees())) {\n // The name used when registering the subtree will be used as the root node identifier.\n rootNodeMap[name] = { ...rootNodeDefinition, id: name };\n }\n\n // Populate the map with the root node definitions that were included with the tree definition.\n // We do this after adding any registered subtrees as we want these to take presedence.\n for (const rootNodeDefinition of definition) {\n rootNodeMap[rootNodeDefinition.id ?? MAIN_ROOT_NODE_KEY] = rootNodeDefinition;\n }\n\n return rootNodeMap;\n}\n\n/**\n * Applies a guard path to every leaf of the tree to evaluate as part of each update.\n * @param root The main root tree node.\n */\nfunction applyLeafNodeGuardPaths(root: Root) {\n const nodePaths: Node[][] = [];\n\n const findLeafNodes = (path: Node[], node: Node) => {\n // Add the current node to the path.\n path = path.concat(node);\n\n // Check whether the current node is a leaf node.\n if (node.isLeafNode()) {\n nodePaths.push(path);\n } else {\n (node as Composite | Decorator).getChildren().forEach((child) => findLeafNodes(path, child));\n }\n };\n\n // Find all leaf node paths, starting from the root.\n findLeafNodes([], root);\n\n nodePaths.forEach((path) => {\n // Each node in the current path will have to be assigned a guard path, working from the root outwards.\n for (let depth = 0; depth < path.length; depth++) {\n // Get the node in the path at the current depth.\n const currentNode = path[depth];\n\n // The node may already have been assigned a guard path, if so just skip it.\n if (currentNode.hasGuardPath()) {\n continue;\n }\n\n // Create the guard path for the current node.\n const guardPath = new GuardPath(\n path\n .slice(0, depth + 1)\n .map((node) => ({ node, guards: node.getGuardAttributes() }))\n .filter((details) => details.guards.length > 0)\n );\n\n // Assign the guard path to the current node.\n currentNode.setGuardPath(guardPath);\n }\n });\n}\n", "import State, { AnyState } from \"./State\";\nimport Lookup from \"./Lookup\";\nimport Node from \"./nodes/Node\";\nimport Root from \"./nodes/decorator/Root\";\nimport Composite from \"./nodes/composite/Composite\";\nimport Decorator from \"./nodes/decorator/Decorator\";\nimport { Agent, GlobalFunction } from \"./Agent\";\nimport { CallbackAttributeDetails } from \"./attributes/callbacks/Callback\";\nimport { GuardAttributeDetails } from \"./attributes/guards/Guard\";\nimport { BehaviourTreeOptions } from \"./BehaviourTreeOptions\";\nimport { convertMDSLToJSON } from \"./mdsl/MDSLDefinitionParser\";\nimport { RootNodeDefinition } from \"./BehaviourTreeDefinition\";\nimport { validateJSONDefinition } from \"./BehaviourTreeDefinitionValidator\";\nimport buildRootNode from \"./BehaviourTreeBuilder\";\nimport { isNullOrUndefined } from \"./BehaviourTreeDefinitionUtilities\";\n\n// Purely for outside inspection of the tree.\nexport type FlattenedTreeNode = {\n id: string;\n type: string;\n caption: string;\n state: AnyState;\n guards: GuardAttributeDetails[];\n callbacks: CallbackAttributeDetails[];\n args: any[];\n parentId: string | null;\n};\n\n/**\n * A representation of a behaviour tree.\n */\nexport class BehaviourTree {\n /**\n * The main root tree node.\n */\n public readonly rootNode: Root;\n\n /**\n * Creates a new instance of the BehaviourTree class.\n * @param definition The behaviour tree definition.\n * @param agent The agent instance that this behaviour tree is modelling behaviour for.\n * @param options The behaviour tree options object.\n */\n constructor(\n definition: string | RootNodeDefinition | RootNodeDefinition[],\n private agent: Agent,\n private options: BehaviourTreeOptions = {}\n ) {\n // The tree definition must be defined.\n if (isNullOrUndefined(definition)) {\n throw new Error(\"tree definition not defined\");\n }\n\n // The agent must be defined and not null.\n if (typeof agent !== \"object\" || agent === null) {\n throw new Error(\"the agent must be an object and not null\");\n }\n\n try {\n // Parse the behaviour tree definition, create the populated tree of behaviour tree nodes, and get the root.\n this.rootNode = this._createRootNode(definition);\n } catch (exception) {\n // There was an issue in trying build and populate the behaviour tree.\n throw new Error(`error building tree: ${(exception as Error).message}`);\n }\n }\n\n /**\n * Gets whether the tree is in the RUNNING state.\n * @returns true if the tree is in the RUNNING state, otherwise false.\n */\n isRunning() {\n return this.rootNode.getState() === State.RUNNING;\n }\n\n /**\n * Gets the current tree state of SUCCEEDED, FAILED, READY or RUNNING.\n * @returns The current tree state.\n */\n getState() {\n return this.rootNode.getState();\n }\n\n /**\n * Step the tree.\n * 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.\n * 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\n * 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.\n *\n * 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.\n */\n step() {\n // If the root node has already been stepped to completion then we need to reset it.\n if (this.rootNode.getState() === State.SUCCEEDED || this.rootNode.getState() === State.FAILED) {\n this.rootNode.reset();\n }\n\n try {\n this.rootNode.update(this.agent, this.options);\n } catch (exception) {\n throw new Error(`error stepping tree: ${(exception as Error).message}`);\n }\n }\n\n /**\n * Resets the tree from the root node outwards to each nested node, giving each a state of READY.\n */\n reset() {\n this.rootNode.reset();\n }\n\n /**\n * Gets the flattened details of every node in the tree.\n * @returns The flattened details of every node in the tree.\n */\n getFlattenedNodeDetails(): FlattenedTreeNode[] {\n // Create an empty flattened array of tree nodes.\n const flattenedTreeNodes: FlattenedTreeNode[] = [];\n\n /**\n * Helper function to process a node instance and push details into the flattened tree nodes array.\n * @param node The current node.\n * @param parentUid The UID of the node parent, or null if the node is the main root node.\n */\n const processNode = (node: Node, parentUid: string | null) => {\n // Get the guard and callback attribute details for this node.\n const guards = node\n .getAttributes()\n .filter((attribute) => attribute.isGuard())\n .map((attribute) => attribute.getDetails()) as GuardAttributeDetails[];\n const callbacks = node\n .getAttributes()\n .filter((attribute) => !attribute.isGuard())\n .map((attribute) => attribute.getDetails()) as CallbackAttributeDetails[];\n\n // Push the current node into the flattened nodes array.\n flattenedTreeNodes.push({\n id: node.getUid(),\n type: node.getType(),\n caption: node.getName(),\n state: node.getState(),\n guards,\n callbacks,\n args: node.getArguments(),\n parentId: parentUid\n });\n\n // Process each of the nodes children if it is not a leaf node.\n if (!node.isLeafNode()) {\n (node as Composite | Decorator)\n .getChildren()\n .forEach((child) => processNode(child, (node as Composite | Decorator).getUid()));\n }\n };\n\n // Convert the nested node structure into a flattened array of node details.\n processNode(this.rootNode, null);\n\n return flattenedTreeNodes;\n }\n\n /**\n * Registers the action/condition/guard/callback function or subtree with the given name.\n * @param name The name of the function or subtree to register.\n * @param value The function or subtree definition to register.\n */\n static register(name: string, value: GlobalFunction | string | RootNodeDefinition) {\n // Are we going to register a action/condition/guard/callback function?\n if (typeof value === \"function\") {\n Lookup.setFunc(name, value);\n return;\n }\n\n // We are not registering an action/condition/guard/callback function, so we must be registering a subtree.\n if (typeof value === \"string\") {\n let rootNodeDefinitions: RootNodeDefinition[];\n\n // We will assume that any string passed in will be a mdsl definition.\n try {\n rootNodeDefinitions = convertMDSLToJSON(value);\n } catch (exception) {\n throw new Error(`error registering definition, invalid MDSL: ${(exception as Error).message}`);\n }\n\n // This function should only ever be called with a definition containing a single unnamed root node.\n if (rootNodeDefinitions.length != 1 || rootNodeDefinitions[0].id !== null) {\n throw new Error(\"error registering definition: expected a single unnamed root node\");\n }\n\n try {\n // We should validate the subtree as we don't want invalid subtrees available via the lookup.\n const { succeeded, errorMessage } = validateJSONDefinition(rootNodeDefinitions[0]);\n\n // Did our validation fail without error?\n if (!succeeded) {\n throw new Error(errorMessage);\n }\n } catch (exception) {\n throw new Error(`error registering definition: ${(exception as Error).message}`);\n }\n\n // Everything seems hunky-dory, register the subtree.\n Lookup.setSubtree(name, rootNodeDefinitions[0]);\n } else if (typeof value === \"object\" && !Array.isArray(value)) {\n // We will assume that any object passed in is a root node definition.\n\n try {\n // We should validate the subtree as we don't want invalid subtrees available via the lookup.\n const { succeeded, errorMessage } = validateJSONDefinition(value);\n\n // Did our validation fail without error?\n if (!succeeded) {\n throw new Error(errorMessage);\n }\n } catch (exception) {\n throw new Error(`error registering definition: ${(exception as Error).message}`);\n }\n\n // Everything seems hunky-dory, register the subtree.\n Lookup.setSubtree(name, value);\n } else {\n throw new Error(\"unexpected value, expected string mdsl definition, root node json definition or function\");\n }\n }\n\n /**\n * Unregisters the registered action/condition/guard/callback function or subtree with the given name.\n * @param name The name of the registered action/condition/guard/callback function or subtree to unregister.\n */\n static unregister(name: string): void {\n Lookup.remove(name);\n }\n\n /**\n * Unregister all registered action/condition/guard/callback functions and subtrees.\n */\n static unregisterAll(): void {\n Lookup.empty();\n }\n\n /**\n * Parses a behaviour tree definition and creates a tree of behaviour tree nodes populated at a root.\n * @param {string | RootNodeDefinition | RootNodeDefinition[]} definition The behaviour tree definition.\n * @returns The root behaviour tree node.\n */\n private _createRootNode(definition: string | RootNodeDefinition | RootNodeDefinition[]): Root {\n let resolvedDefinition: RootNodeDefinition | RootNodeDefinition[];\n\n // If the definition is a string then we will assume that it is an mdsl string which needs to be converted to a JSON definition.\n if (typeof definition === \"string\") {\n try {\n resolvedDefinition = convertMDSLToJSON(definition);\n } catch (exception) {\n throw new Error(`invalid mdsl definition: ${(exception as Error).message}`);\n }\n } else {\n // The definition is not a string, so we should assume that it is already a JSON definition.\n resolvedDefinition = definition;\n }\n\n // Build and populate the root node.\n return buildRootNode(Array.isArray(resolvedDefinition) ? resolvedDefinition : [resolvedDefinition]);\n }\n}\n"], - "mappings": "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", + "sourcesContent": ["\"use strict\";\r\nObject.defineProperty(exports, \"__esModule\", { value: true });\r\nexports.Participant = void 0;\r\n/**\r\n * A participant that holds a number of tickets.\r\n */\r\nvar Participant = /** @class */ (function () {\r\n /**\r\n * Creates an instance of the Participant class.\r\n * @param participant The actual participant.\r\n * @param tickets The number of tickets held by the participant.\r\n */\r\n function Participant(participant, tickets) {\r\n if (tickets === void 0) { tickets = 1; }\r\n this._participant = participant;\r\n this._tickets = tickets;\r\n }\r\n Object.defineProperty(Participant.prototype, \"participant\", {\r\n /** Gets the actual participant. */\r\n get: function () {\r\n return this._participant;\r\n },\r\n enumerable: false,\r\n configurable: true\r\n });\r\n Object.defineProperty(Participant.prototype, \"tickets\", {\r\n /** Gets or sets the number of tickets held by the participant. */\r\n get: function () {\r\n return this._tickets;\r\n },\r\n set: function (value) {\r\n this._tickets = value;\r\n },\r\n enumerable: false,\r\n configurable: true\r\n });\r\n return Participant;\r\n}());\r\nexports.Participant = Participant;\r\n", "\"use strict\";\r\nObject.defineProperty(exports, \"__esModule\", { value: true });\r\nexports.isNaturalNumber = exports.isNullOrUndefined = void 0;\r\n/**\r\n * Gets whether the value provided is null or undefined.\r\n * @param value The value to check.\r\n * @returns Whether the value provided is null or undefined.\r\n */\r\nfunction isNullOrUndefined(value) {\r\n return value === null || value === undefined;\r\n}\r\nexports.isNullOrUndefined = isNullOrUndefined;\r\n/**\r\n * Gets whether the value provided is a natural number.\r\n * @param value The value to check.\r\n * @returns Whether the value provided is a natural number.\r\n */\r\nfunction isNaturalNumber(value) {\r\n return typeof value === \"number\" && value >= 1 && Math.floor(value) === value;\r\n}\r\nexports.isNaturalNumber = isNaturalNumber;\r\n", "\"use strict\";\r\nObject.defineProperty(exports, \"__esModule\", { value: true });\r\nexports.Lotto = void 0;\r\nvar Participant_1 = require(\"./Participant\");\r\nvar Utilities_1 = require(\"./Utilities\");\r\n/**\r\n * Represents a lotto consisting of a number of pickable ticket-holding participants.\r\n */\r\nvar Lotto = /** @class */ (function () {\r\n /**\r\n * Creates a new instance of Lotto.\r\n * @param customRandom The custom RNG to use in place of Math.random().\r\n */\r\n function Lotto(customRandom) {\r\n /** The array of participants that are holding tickets in the lotto. */\r\n this._participants = [];\r\n this._customRandom = customRandom;\r\n }\r\n /**\r\n * Adds a participant with the specified number of tickets, or adds to the participant ticket count if the participant already holds tickets.\r\n * @param participant The participant to add or to increase the ticket count for if they already hold tickets.\r\n * @param tickets The number of tickets, defaults to 1.\r\n * @returns The Lotto instance.\r\n */\r\n Lotto.prototype.add = function (participant, tickets) {\r\n if (tickets === void 0) { tickets = 1; }\r\n // Check that we have a valid ticket count.\r\n if (!(0, Utilities_1.isNaturalNumber)(tickets)) {\r\n throw new Error(\"tickets value must be a natural number\");\r\n }\r\n // Check whether this participant has already been added.\r\n var existingParticipant = this._participants.find(function (part) { return part.participant === participant; });\r\n if (existingParticipant) {\r\n // The participant has already been added to the lotto so just add to their ticket count.\r\n existingParticipant.tickets += tickets;\r\n }\r\n else {\r\n // The participant is not part of the lotto so we should add them.\r\n this._participants.push(new Participant_1.Participant(participant, tickets));\r\n }\r\n return this;\r\n };\r\n /**\r\n * Removes the specified number of tickets for the given participant from the draw, or all tickets if a ticket number is not defined.\r\n * @param participant The participant to remove tickets for.\r\n * @param tickets The number of tickets to remove, or undefined if all tickets are to be removed.\r\n * @returns The Lotto instance.\r\n */\r\n Lotto.prototype.remove = function (participant, tickets) {\r\n // Attempt to get the existing participant.\r\n var existingParticipant = this._participants.find(function (part) { return part.participant === participant; });\r\n // There is nothing to do if the specified participant isn't even part of the lotto.\r\n if (!existingParticipant) {\r\n return this;\r\n }\r\n // Check whether a tickets value was given.\r\n if (tickets !== undefined) {\r\n // Check that we have a valid ticket count.\r\n if (!(0, Utilities_1.isNaturalNumber)(tickets)) {\r\n throw new Error(\"tickets value must be a natural number\");\r\n }\r\n existingParticipant.tickets -= tickets;\r\n // If the participant no longer holds any tickets then they should be removed.\r\n if (existingParticipant.tickets < 1) {\r\n this._participants = this._participants.filter(function (part) { return part !== existingParticipant; });\r\n }\r\n }\r\n else {\r\n // We are removing all tickets for the participant so just remove them from the lotto.\r\n this._participants = this._participants.filter(function (part) { return part !== existingParticipant; });\r\n }\r\n return this;\r\n };\r\n /**\r\n * Draw a winning ticket and return the participant that holds the ticket.\r\n * @param options The draw options.\r\n * @returns The participant that holds the winning ticket.\r\n */\r\n Lotto.prototype.draw = function (options) {\r\n if (options === void 0) { options = {}; }\r\n // If we have no participants then just return null.\r\n if (this._participants.length === 0) {\r\n return null;\r\n }\r\n var redrawable = (0, Utilities_1.isNullOrUndefined)(options.redrawable) ? true : options.redrawable;\r\n var pickable = [];\r\n this._participants.forEach(function (_a) {\r\n var participant = _a.participant, tickets = _a.tickets;\r\n for (var ticketCount = 0; ticketCount < tickets; ticketCount++) {\r\n pickable.push(participant);\r\n }\r\n });\r\n var random;\r\n // We need a random floating-point number between 0 (inclusive) and 1 to scale up to pick our winner.\r\n // If a custom random function exists then we should use that or fall back to Math.random().\r\n if (this._customRandom) {\r\n // Call our custom random function to get a random floating-point number.\r\n random = this._customRandom();\r\n // Verify that the result of calling our custom random function is a number between 0 (inclusive) and 1.\r\n if (typeof random !== \"number\" || random < 0 || random >= 1) {\r\n throw new Error(\"the 'random' function provided did not return a number between 0 (inclusive) and 1\");\r\n }\r\n }\r\n else {\r\n // No custom random function was defined so just use good ol' Math.random().\r\n random = Math.random();\r\n }\r\n // Pick a winning participant.\r\n var winner = pickable[Math.floor(random * pickable.length)];\r\n // If the ticket isn't redrawable then we should remove a ticket from the winning participants ticket count.\r\n if (!redrawable) {\r\n this.remove(winner, 1);\r\n }\r\n // Return the winning participant.\r\n return winner;\r\n };\r\n /**\r\n * Draws multiple winning tickets and return an array of the participants that hold the winning tickets.\r\n * @param tickets The number of winning tickets to draw.\r\n * @param options The draw multiple options.\r\n * @returns An array of the participants that hold the winning tickets.\r\n */\r\n Lotto.prototype.drawMultiple = function (tickets, options) {\r\n if (options === void 0) { options = {}; }\r\n var uniqueResults = (0, Utilities_1.isNullOrUndefined)(options.unique) ? false : options.unique;\r\n // Handle cases where the user has asked for zero tickets (no idea why they would do this be we should trust them).\r\n if (tickets === 0) {\r\n return [];\r\n }\r\n // Now that we know out tickets value is not zero we should check that it is a valid natural number.\r\n if (!(0, Utilities_1.isNaturalNumber)(tickets)) {\r\n throw new Error(\"tickets value must be a natural number\");\r\n }\r\n var result = [];\r\n // Keep drawing tickets until we either reach the number of required tickets or we simply run out of tickets to draw.\r\n // We can run out of tickets to draw if 'options.redrawable' is explicity 'false' or we just had no participants when 'drawMultiple' was called.\r\n while (result.length < tickets && this._participants.length > 0) {\r\n result.push(this.draw(options));\r\n }\r\n // If the 'unique' draw option is set then we need to remove duplicates from the result list.\r\n if (uniqueResults) {\r\n // Create an array to store our unique results.\r\n var unique = [];\r\n // Iterate over all of our participants (with potential duplicates) and populate our array of unique values.\r\n for (var _i = 0, result_1 = result; _i < result_1.length; _i++) {\r\n var participant = result_1[_i];\r\n if (unique.indexOf(participant) === -1) {\r\n unique.push(participant);\r\n }\r\n }\r\n result = unique;\r\n }\r\n return result;\r\n };\r\n return Lotto;\r\n}());\r\nexports.Lotto = Lotto;\r\n", "\"use strict\";\r\nObject.defineProperty(exports, \"__esModule\", { value: true });\r\nexports.createLotto = void 0;\r\nvar Lotto_1 = require(\"./Lotto\");\r\n/**\r\n * A function that creates and returns a Lotto instance.\r\n * @param participantsOrOptions An array of initial participants or options relating to the creation of a Lotto instance.\r\n * @returns A new Lotto instance.\r\n */\r\nfunction createLotto(participantsOrOptions) {\r\n // If no initial participants or lotto options were provided as an argument then we can just return a new lotto instance now.\r\n if (!participantsOrOptions) {\r\n return new Lotto_1.Lotto();\r\n }\r\n // Check whether we were provided with an array of initial participants or a lotto options object.\r\n if (Array.isArray(participantsOrOptions)) {\r\n // We are dealing with a pre-defined array of participants.\r\n var participants = participantsOrOptions;\r\n var lotto_1 = new Lotto_1.Lotto();\r\n // If the lotto participants have been defined upfront then we will need to add them all to our lotto instance now.\r\n participants.forEach(function (_a) {\r\n var participant = _a[0], tokens = _a[1];\r\n return lotto_1.add(participant, tokens);\r\n });\r\n // Return the Lotto instance.\r\n return lotto_1;\r\n }\r\n else {\r\n // We are dealing with some lotto options.\r\n var random = participantsOrOptions.random, participants = participantsOrOptions.participants;\r\n // Create a Lotto instance passing the custom RNG function to use in place of Math.random() (which could be undefined).\r\n var lotto_2 = new Lotto_1.Lotto(random);\r\n // If the lotto participants have been defined upfront as part of the options then we will need to add them all to our lotto instance now.\r\n if (participants) {\r\n participants.forEach(function (_a) {\r\n var participant = _a[0], tokens = _a[1];\r\n return lotto_2.add(participant, tokens);\r\n });\r\n }\r\n // Return the Lotto instance.\r\n return lotto_2;\r\n }\r\n}\r\nexports.createLotto = createLotto;\r\n", "\"use strict\";\r\nObject.defineProperty(exports, \"__esModule\", { value: true });\r\nvar createLotto_1 = require(\"./createLotto\");\r\nexports.default = createLotto_1.createLotto;\r\n", "import State from \"./State\";\nimport { validateDefinition } from \"./BehaviourTreeDefinitionValidator\";\nimport { convertMDSLToJSON } from \"./mdsl/MDSLDefinitionParser\";\nimport { BehaviourTree, FlattenedTreeNode } from \"./BehaviourTree\";\nimport { BehaviourTreeOptions } from \"./BehaviourTreeOptions\";\n\nexport { BehaviourTree, State, convertMDSLToJSON, validateDefinition };\nexport type { FlattenedTreeNode, BehaviourTreeOptions };\n", "/**\n * Enumeration of node state types.\n */\nexport enum State {\n READY = \"mistreevous.ready\",\n RUNNING = \"mistreevous.running\",\n SUCCEEDED = \"mistreevous.succeeded\",\n FAILED = \"mistreevous.failed\"\n}\n\nexport { State as default };\n\nexport type CompleteState = State.SUCCEEDED | State.FAILED;\nexport type AnyState = State.READY | State.RUNNING | CompleteState;\n", "import {\n NodeDefinition,\n RootNodeDefinition,\n DecoratorNodeDefinition,\n CompositeNodeDefinition,\n AnyNodeDefinition,\n BranchNodeDefinition\n} from \"./BehaviourTreeDefinition\";\n\n/**\n * A type guard function that returns true if the specified node satisfies the RootNodeDefinition type.\n * @param node The node.\n * @returns A value of true if the specified node satisfies the RootNodeDefinition type.\n */\nexport function isRootNode(node: NodeDefinition): node is RootNodeDefinition {\n return node.type === \"root\";\n}\n\n/**\n * A type guard function that returns true if the specified node satisfies the BranchNodeDefinition type.\n * @param node The node.\n * @returns A value of true if the specified node satisfies the BranchNodeDefinition type.\n */\nexport function isBranchNode(node: NodeDefinition): node is BranchNodeDefinition {\n return node.type === \"branch\";\n}\n\n/**\n * A type guard function that returns true if the specified node satisfies the NodeDefinition type.\n * @param node The node.\n * @returns A value of true if the specified node satisfies the NodeDefinition type.\n */\nexport function isLeafNode(node: NodeDefinition): node is NodeDefinition {\n return [\"branch\", \"action\", \"condition\", \"wait\"].includes(node.type);\n}\n\n/**\n * A type guard function that returns true if the specified node satisfies the DecoratorNodeDefinition type.\n * @param node The node.\n * @returns A value of true if the specified node satisfies the DecoratorNodeDefinition type.\n */\nexport function isDecoratorNode(node: NodeDefinition): node is DecoratorNodeDefinition {\n return [\"root\", \"repeat\", \"retry\", \"flip\", \"succeed\", \"fail\"].includes(node.type);\n}\n\n/**\n * A type guard function that returns true if the specified node satisfies the CompositeNodeDefinition type.\n * @param node The node.\n * @returns A value of true if the specified node satisfies the CompositeNodeDefinition type.\n */\nexport function isCompositeNode(node: NodeDefinition): node is CompositeNodeDefinition {\n return [\"sequence\", \"selector\", \"lotto\", \"parallel\"].includes(node.type);\n}\n\n/**\n * Flatten a node definition into an array of all of its nested node definitions.\n * @param nodeDefinition The node definition to flatten.\n * @returns An array of all of nested node definitions.\n */\nexport function flattenDefinition(nodeDefinition: AnyNodeDefinition): AnyNodeDefinition[] {\n const nodes: AnyNodeDefinition[] = [];\n\n const processNode = (currentNodeDefinition: AnyNodeDefinition) => {\n nodes.push(currentNodeDefinition);\n\n if (isCompositeNode(currentNodeDefinition)) {\n currentNodeDefinition.children.forEach(processNode);\n } else if (isDecoratorNode(currentNodeDefinition)) {\n processNode(currentNodeDefinition.child);\n }\n };\n\n processNode(nodeDefinition);\n\n return nodes;\n}\n\n/**\n * Determines whether the passed value is an integer.\n * @param value The value to check.\n * @returns Whether the passed value is an integer.\n */\nexport function isInteger(value: unknown): boolean {\n return typeof value === \"number\" && Math.floor(value) === value;\n}\n\n/**\n * Determines whether the passed value is null or undefined.\n * @param value The value to check.\n * @returns Whether the passed value is null or undefined.\n */\nexport function isNullOrUndefined(value: unknown): boolean {\n return typeof value === \"undefined\" || value === null;\n}\n", "/**\n * A type defining an object that holds a reference to substitued string literals parsed from the definition.\n */\nexport type StringLiteralPlaceholders = { [key: string]: string };\n\n/**\n * Pop the next raw token from the specified array of tokens and throw an error if it wasn't the expected one.\n * @param tokens The array of tokens.\n * @param expected An optional string or array or items, one of which must match the next popped token.\n * @returns The popped token.\n */\nexport function popAndCheck(tokens: string[], expected?: string | string[]): string {\n // Get and remove the next token.\n const popped = tokens.shift();\n\n // We were expecting another token but there aren't any.\n if (popped === undefined) {\n throw new Error(\"unexpected end of definition\");\n }\n\n // Do we have an expected token/tokens array?\n if (expected != undefined) {\n // Get an array of expected values, if the popped token matches any then we are all good.\n const expectedValues = typeof expected === \"string\" ? [expected] : expected;\n\n // Check whether the popped token matches at least one of our expected items.\n var tokenMatchesExpectation = expectedValues.some((item) => popped.toUpperCase() === item.toUpperCase());\n\n // Throw an error if the popped token didn't match any of our expected items.\n if (!tokenMatchesExpectation) {\n const expectationString = expectedValues.map((item) => \"'\" + item + \"'\").join(\" or \");\n throw new Error(\"unexpected token found. Expected \" + expectationString + \" but got '\" + popped + \"'\");\n }\n }\n\n // Return the popped token.\n return popped;\n}\n\n/**\n * Swaps out any node/attribute argument string literals with placeholders.\n * @param definition The definition.\n * @returns An object containing a mapping of placeholders to original string values as well as the processed definition string.\n */\nexport function substituteStringLiterals(definition: string): {\n placeholders: StringLiteralPlaceholders;\n processedDefinition: string;\n} {\n // Create an object to hold the mapping of placeholders to original string values.\n const placeholders: StringLiteralPlaceholders = {};\n\n // Replace any string literals wrapped with double quotes in our definition with placeholders to be processed later.\n const processedDefinition = definition.replace(/\\\"(\\\\.|[^\"\\\\])*\\\"/g, (match) => {\n var strippedMatch = match.substring(1, match.length - 1);\n var placeholder = Object.keys(placeholders).find((key) => placeholders[key] === strippedMatch);\n\n // If we have no existing string literal match then create a new placeholder.\n if (!placeholder) {\n placeholder = `@@${Object.keys(placeholders).length}@@`;\n placeholders[placeholder] = strippedMatch;\n }\n\n return placeholder;\n });\n\n return { placeholders, processedDefinition };\n}\n\n/**\n * Parse the tree definition into an array of raw tokens.\n * @param definition The definition.\n * @returns An array of tokens parsed from the definition.\n */\nexport function parseTokensFromDefinition(definition: string): string[] {\n // Add some space around various important characters so that they can be plucked out easier as individual tokens.\n definition = definition.replace(/\\(/g, \" ( \");\n definition = definition.replace(/\\)/g, \" ) \");\n definition = definition.replace(/\\{/g, \" { \");\n definition = definition.replace(/\\}/g, \" } \");\n definition = definition.replace(/\\]/g, \" ] \");\n definition = definition.replace(/\\[/g, \" [ \");\n definition = definition.replace(/\\,/g, \" , \");\n\n // Split the definition into raw token form and return it.\n return definition.replace(/\\s+/g, \" \").trim().split(\" \");\n}\n", "import { StringLiteralPlaceholders, popAndCheck } from \"./MDSLUtilities\";\n\n/**\n * A type representing any node function argument.\n */\ntype Argument = {\n /**\n * The argument value.\n */\n value: T;\n /**\n * The argument type, used for validation.\n */\n type: string;\n};\n\ntype NullArgument = Argument & {\n type: \"null\";\n};\n\ntype BooleanArgument = Argument & {\n type: \"boolean\";\n};\n\ntype NumberArgument = Argument & {\n type: \"number\";\n /**\n * A flag defining whether the number argument value is a valid integer. (used for validation)\n */\n isInteger: boolean;\n};\n\ntype StringPlaceholderArgument = Argument & {\n type: \"string\";\n};\n\ntype IdentifierArgument = Argument & {\n type: \"identifier\";\n};\n\n/**\n * A type representing a reference to any node function argument.\n */\ntype AnyArgument = NullArgument | BooleanArgument | NumberArgument | StringPlaceholderArgument | IdentifierArgument;\n\n/**\n * Parse an array of argument definitions from the specified tokens array.\n * @param tokens The array tokens to parse the argument definitions from.\n * @param stringArgumentPlaceholders The mapping of string literal node argument placeholders to original values.\n * @param argumentValidator The argument validator function.\n * @param validationFailedMessage The exception message to throw if argument validation fails.\n * @returns An array of argument definitions parsed from the specified tokens array.\n */\nexport function parseArgumentTokens(\n tokens: string[],\n stringArgumentPlaceholders: StringLiteralPlaceholders\n): AnyArgument[] {\n const argumentList: AnyArgument[] = [];\n\n // If the next token is not a '[' or '(' then we have no arguments to parse.\n if (![\"[\", \"(\"].includes(tokens[0])) {\n return argumentList;\n }\n\n // Any lists of arguments will always be wrapped in '[]' for node arguments or '()' for attribute arguments.\n // We are looking for a '[' or '(' opener that wraps the argument tokens and the relevant closer.\n const closingToken = popAndCheck(tokens, [\"[\", \"(\"]) === \"[\" ? \"]\" : \")\";\n\n const argumentListTokens: string[] = [];\n\n // Grab all tokens between the '[' and ']' or '(' and ')'.\n while (tokens.length && tokens[0] !== closingToken) {\n // The next token is part of our arguments list.\n argumentListTokens.push(tokens.shift()!);\n }\n\n // Validate the order of the argument tokens. Each token must either be a ',' or a single argument that satisfies the validator.\n argumentListTokens.forEach((token, index) => {\n // Get whether this token should be an actual argument.\n const shouldBeArgumentToken = !(index & 1);\n\n // If the current token should be an actual argument then validate it, otherwise it should be a ',' token.\n if (shouldBeArgumentToken) {\n // Get the argument definition.\n const argumentDefinition = getArgumentDefinition(token, stringArgumentPlaceholders);\n\n // This is a valid argument!\n argumentList.push(argumentDefinition);\n } else {\n // The current token should be a ',' token.\n if (token !== \",\") {\n throw new Error(`invalid argument list, expected ',' or ']' but got '${token}'`);\n }\n }\n });\n\n // The arguments list should terminate with a ']' or ')' token, depending on the opener.\n popAndCheck(tokens, closingToken);\n\n // Return the arguments.\n return argumentList;\n}\n\n/**\n * Gets an argument value definition.\n * @param token The argument token.\n * @param stringArgumentPlaceholders The mapping of string literal node argument placeholders to original values.\n * @returns An argument value definition.\n */\nfunction getArgumentDefinition(token: string, stringArgumentPlaceholders: StringLiteralPlaceholders): AnyArgument {\n // Check whether the token represents a null value.\n if (token === \"null\") {\n return {\n value: null,\n type: \"null\"\n } as NullArgument;\n }\n\n // Check whether the token represents a boolean value.\n if (token === \"true\" || token === \"false\") {\n return {\n value: token === \"true\",\n type: \"boolean\"\n } as BooleanArgument;\n }\n\n // Check whether the token represents a number value.\n // TODO: Relies on broken isNaN - see MDN.\n // if (!Number.isNaN(token)) {\n if (!isNaN(token as any)) {\n return {\n value: parseFloat(token),\n isInteger: parseFloat(token) === parseInt(token, 10),\n type: \"number\"\n } as NumberArgument;\n }\n\n // Check whether the token is a placeholder (e.g. @@0@@) representing a string literal.\n if (token.match(/^@@\\d+@@$/g)) {\n return {\n value: stringArgumentPlaceholders[token].replace('\\\\\"', '\"'),\n type: \"string\"\n } as StringPlaceholderArgument;\n }\n\n // The only remaining option is that the argument value is an identifier.\n return {\n value: token,\n type: \"identifier\"\n } as IdentifierArgument;\n}\n", "import { NodeAttributeDefinition } from \"../BehaviourTreeDefinition\";\nimport { parseArgumentTokens } from \"./MDSLNodeArgumentParser\";\nimport { StringLiteralPlaceholders } from \"./MDSLUtilities\";\n\n/**\n * A type defining the attribute definitions of a node.\n */\ntype NodeAttributes = {\n while?: NodeAttributeDefinition;\n until?: NodeAttributeDefinition;\n entry?: NodeAttributeDefinition;\n exit?: NodeAttributeDefinition;\n step?: NodeAttributeDefinition;\n};\n\n/**\n * Parse any node attribute definitions from the specified tokens array.\n * @param tokens The array of remaining tokens.\n * @param stringArgumentPlaceholders The mapping of string literal node argument placeholders to original values.\n * @returns An object of attribute definitions defined by any directly following tokens.\n */\nexport function parseAttributeTokens(\n tokens: string[],\n stringArgumentPlaceholders: StringLiteralPlaceholders\n): NodeAttributes {\n const nodeAttributeNames: (keyof NodeAttributes)[] = [\"while\", \"until\", \"entry\", \"exit\", \"step\"];\n\n // Create an object to hold any attributes found.\n const attributes: NodeAttributes = {};\n\n // Try to get the name of the attribute for the next token.\n let nextAttributeName = tokens[0]?.toLowerCase() as keyof NodeAttributes;\n\n // Pull attribute tokens as well as their arguments off of the tokens stack until we have no more.\n while (nodeAttributeNames.includes(nextAttributeName)) {\n // Check to make sure that we have not already created an attribute definition of this type.\n if (attributes[nextAttributeName]) {\n throw new Error(`duplicate attribute '${tokens[0].toUpperCase()}' found for node`);\n }\n\n // Remove the attribute name token from the array of tokens.\n tokens.shift();\n\n // Grab the attribute arguments, assuming the first to be an identifier.\n const [attributeCallIdentifier, ...attributeArguments] = parseArgumentTokens(\n tokens,\n stringArgumentPlaceholders\n );\n\n // The first attribute argument has to be an identifer, this will reference an agent function.\n if (attributeCallIdentifier?.type !== \"identifier\") {\n throw new Error(\"expected agent function name identifier argument for attribute\");\n }\n\n // Any attribute arguments (other than the expected call identifier) must have a type of string, number, boolean or null.\n attributeArguments\n .filter((arg) => arg.type === \"identifier\")\n .forEach((arg) => {\n throw new Error(\n `invalid attribute argument value '${arg.value}', must be string, number, boolean or null`\n );\n });\n\n // Create the attribute definition and add it to the object of attribute definitions found.\n attributes[nextAttributeName] = {\n call: attributeCallIdentifier.value,\n args: attributeArguments.map(({ value }) => value)\n };\n\n // Try to get the next attribute name token, as there could be multiple.\n nextAttributeName = tokens[0]?.toLowerCase() as keyof NodeAttributes;\n }\n\n return attributes;\n}\n", "import {\n ActionNodeDefinition,\n AnyChildNodeDefinition,\n AnyNodeDefinition,\n BranchNodeDefinition,\n ConditionNodeDefinition,\n FailNodeDefinition,\n FlipNodeDefinition,\n LottoNodeDefinition,\n ParallelNodeDefinition,\n RepeatNodeDefinition,\n RetryNodeDefinition,\n RootNodeDefinition,\n SelectorNodeDefinition,\n SequenceNodeDefinition,\n SucceedNodeDefinition,\n WaitNodeDefinition\n} from \"../BehaviourTreeDefinition\";\nimport {\n isCompositeNode,\n isDecoratorNode,\n isLeafNode,\n isNullOrUndefined,\n isRootNode\n} from \"../BehaviourTreeDefinitionUtilities\";\nimport { parseArgumentTokens } from \"./MDSLNodeArgumentParser\";\nimport { parseAttributeTokens } from \"./MDSLNodeAttributeParser\";\nimport {\n StringLiteralPlaceholders,\n parseTokensFromDefinition,\n popAndCheck,\n substituteStringLiterals\n} from \"./MDSLUtilities\";\n\n/**\n * Convert the MDSL tree definition string into an equivalent JSON definition.\n * @param definition The tree definition string as MDSL.\n * @returns The root node JSON definitions.\n */\nexport function convertMDSLToJSON(definition: string): RootNodeDefinition[] {\n // Swap out any node/attribute argument string literals with a placeholder and get a mapping of placeholders to original values as well as the processed definition.\n const { placeholders, processedDefinition } = substituteStringLiterals(definition);\n\n // Parse our definition definition string into an array of raw tokens.\n const tokens = parseTokensFromDefinition(processedDefinition);\n\n return convertTokensToJSONDefinition(tokens, placeholders);\n}\n\n/**\n * Converts the specified tree definition tokens into a JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The root node JSON definitions.\n */\nfunction convertTokensToJSONDefinition(\n tokens: string[],\n stringLiteralPlaceholders: StringLiteralPlaceholders\n): RootNodeDefinition[] {\n // There must be at least 3 tokens for the tree definition to be valid. 'ROOT', '{' and '}'.\n if (tokens.length < 3) {\n throw new Error(\"invalid token count\");\n }\n\n // We should have a matching number of '{' and '}' tokens. If not, then there are scopes that have not been properly closed.\n if (tokens.filter((token) => token === \"{\").length !== tokens.filter((token) => token === \"}\").length) {\n throw new Error(\"scope character mismatch\");\n }\n\n // Create an array of tree stack arrays where root nodes will always be at the botton and the current composite/decorator node at the top.\n // There should be an element in this array for every root node defined and every element should be an array with a root note as the first element.\n // E.g. A definition with two root nodes defined:\n // [\n // [root, lotto, sequence],\n // [root, selector]\n // ]\n const treeStacks: [Partial, ...Partial[]][] = [];\n\n // Create an array of all root node definitions that we create.\n const rootNodes: Partial[] = [];\n\n // A helper function used to push node definitions onto the tree stack.\n const pushNode = (node: AnyNodeDefinition) => {\n // If the node is a root node then we need to create a new tree stack array with the root node at the root.\n if (isRootNode(node)) {\n // We need to double-check that this root node is not the child of another node.\n // We can do this by checking whether the top tree stack is not empty (contains an existing node)\n if (treeStacks[treeStacks.length - 1]?.length) {\n throw new Error(\"a root node cannot be the child of another node\");\n }\n\n // Add the root node definition to our array of all parsed root node definitions.\n rootNodes.push(node);\n\n // Add the root node definition to the root of a new tree stack.\n treeStacks.push([node]);\n\n return;\n }\n\n // All non-root nodes should be pushed after their root nodes so handle cases\n // where we may not have any tree stacks or our top-most tree stack is empty.\n if (!treeStacks.length || !treeStacks[treeStacks.length - 1].length) {\n throw new Error(\"expected root node at base of definition\");\n }\n\n // Get the current tree stack that we are populating.\n const topTreeStack = treeStacks[treeStacks.length - 1];\n\n // Get the top-most node in the current tree stack, this will be a composite/decorator node\n // for which we will populate its children array if composite or setting its child if a decorator.\n const topTreeStackTopNode = topTreeStack[topTreeStack.length - 1] as AnyNodeDefinition;\n\n // If the top-most node in the current root stack is a composite or decorator\n // node then the current node should be added as a child of the top-most node.\n if (isCompositeNode(topTreeStackTopNode)) {\n topTreeStackTopNode.children = topTreeStackTopNode.children || [];\n topTreeStackTopNode.children.push(node);\n } else if (isDecoratorNode(topTreeStackTopNode)) {\n // If the top node already has a child node set then throw an error as a decorator should only have a single child.\n if (topTreeStackTopNode.child) {\n throw new Error(\"a decorator node must only have a single child node\");\n }\n\n topTreeStackTopNode.child = node;\n }\n\n // If the node we are adding is also a composite or decorator node, then we should push it\n // onto the current tree stack, as subsequent nodes will be added as its child/children.\n if (!isLeafNode(node)) {\n topTreeStack.push(node);\n }\n };\n\n // A helper function used to pop the top-most node definition off of the tree stack and return it.\n const popNode = (): AnyNodeDefinition | null => {\n let poppedNode: AnyNodeDefinition | null = null;\n\n // Get the current tree stack that we are populating.\n const topTreeStack = treeStacks[treeStacks.length - 1];\n\n // Pop the top-most node in the current tree stack if there is one.\n if (topTreeStack.length) {\n poppedNode = topTreeStack.pop() as AnyNodeDefinition;\n }\n\n // We don't want any empty tree stacks in our stack of tree stacks.\n if (!topTreeStack.length) {\n treeStacks.pop();\n }\n\n return poppedNode;\n };\n\n // We should keep processing the raw tokens until we run out of them.\n while (tokens.length) {\n // Grab the next token.\n const token = tokens.shift()!;\n\n // How we create the next node depends on the current raw token value.\n switch (token.toUpperCase()) {\n case \"ROOT\": {\n pushNode(createRootNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"SUCCEED\": {\n pushNode(createSucceedNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"FAIL\": {\n pushNode(createFailNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"FLIP\": {\n pushNode(createFlipNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"REPEAT\": {\n pushNode(createRepeatNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"RETRY\": {\n pushNode(createRetryNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"SEQUENCE\": {\n pushNode(createSequenceNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"SELECTOR\": {\n pushNode(createSelectorNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"PARALLEL\": {\n pushNode(createParallelNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"LOTTO\": {\n pushNode(createLottoNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"ACTION\": {\n pushNode(createActionNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"CONDITION\": {\n pushNode(createConditionNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"WAIT\": {\n pushNode(createWaitNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"BRANCH\": {\n pushNode(createBranchNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"}\": {\n // The '}' character closes the current scope and means that we have to pop a node off of the current stack.\n const poppedNode = popNode();\n\n // Now that we have a node definition we can carry out any validation that may require the node to be fully populated.\n if (poppedNode) {\n validatePoppedNode(poppedNode);\n }\n\n break;\n }\n\n default: {\n throw new Error(`unexpected token: ${token}`);\n }\n }\n }\n\n return rootNodes as RootNodeDefinition[];\n}\n\n/**\n * Creates a root node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The root node JSON definition.\n */\nfunction createRootNode(tokens: string[], stringLiteralPlaceholders: StringLiteralPlaceholders): RootNodeDefinition {\n // Create the root node definition.\n let node = {\n type: \"root\",\n id: undefined\n } as RootNodeDefinition;\n\n // Parse any node arguments, we should only have one if any which will be an identifier argument for the root identifier.\n const nodeArguments = parseArgumentTokens(tokens, stringLiteralPlaceholders);\n\n // Check whether any node arguments were defined.\n if (nodeArguments.length) {\n // We should only have one argument, if any, which will be an identifier argument for the root identifier.\n if (nodeArguments.length === 1 && nodeArguments[0].type === \"identifier\") {\n // The root node identifier will be the first and only node argument value.\n node.id = nodeArguments[0].value as string;\n } else {\n throw new Error(\"expected single root name argument\");\n }\n }\n\n // Grab any node attribute definitions and spread them into the node definition.\n node = { ...node, ...parseAttributeTokens(tokens, stringLiteralPlaceholders) };\n\n // This is a decorator node, so we expect an opening '{'.\n popAndCheck(tokens, \"{\");\n\n // Return the root node definition.\n return node;\n}\n\n/**\n * Creates a succeed node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The succeed node JSON definition.\n */\nfunction createSucceedNode(\n tokens: string[],\n stringLiteralPlaceholders: StringLiteralPlaceholders\n): SucceedNodeDefinition {\n const node = {\n type: \"succeed\",\n ...parseAttributeTokens(tokens, stringLiteralPlaceholders)\n } as SucceedNodeDefinition;\n\n // This is a decorator node, so we expect an opening '{'.\n popAndCheck(tokens, \"{\");\n\n // Return the succeed node definition.\n return node;\n}\n\n/**\n * Creates a fail node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The fail node JSON definition.\n */\nfunction createFailNode(tokens: string[], stringLiteralPlaceholders: StringLiteralPlaceholders): FailNodeDefinition {\n const node = {\n type: \"fail\",\n ...parseAttributeTokens(tokens, stringLiteralPlaceholders)\n } as FailNodeDefinition;\n\n // This is a decorator node, so we expect an opening '{'.\n popAndCheck(tokens, \"{\");\n\n // Return the fail node definition.\n return node;\n}\n\n/**\n * Creates a flip node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The flip node JSON definition.\n */\nfunction createFlipNode(tokens: string[], stringLiteralPlaceholders: StringLiteralPlaceholders): FlipNodeDefinition {\n const node = {\n type: \"flip\",\n ...parseAttributeTokens(tokens, stringLiteralPlaceholders)\n } as FlipNodeDefinition;\n\n // This is a decorator node, so we expect an opening '{'.\n popAndCheck(tokens, \"{\");\n\n // Return the flip node definition.\n return node;\n}\n\n/**\n * Creates a repeat node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The repeat node JSON definition.\n */\nfunction createRepeatNode(\n tokens: string[],\n stringLiteralPlaceholders: StringLiteralPlaceholders\n): RepeatNodeDefinition {\n let node = { type: \"repeat\" } as RepeatNodeDefinition;\n\n // Get the node arguments.\n const nodeArguments = parseArgumentTokens(tokens, stringLiteralPlaceholders);\n\n // The arguments of a repeat node are optional. We may have:\n // - No node arguments, in which case the repeat note will iterate indefinitely.\n // - One node argument which will be the explicit number of iterations to make.\n // - Two node arguments which define the min and max iteration bounds from which a random iteration count will be picked.\n if (nodeArguments.length) {\n // All repeat node arguments MUST be of type number and must be integer.\n nodeArguments\n .filter((arg) => arg.type !== \"number\" || !arg.isInteger)\n .forEach(() => {\n throw new Error(`repeat node iteration counts must be integer values`);\n });\n\n // We should have got one or two iteration counts.\n if (nodeArguments.length === 1) {\n // A static iteration count was defined.\n node.iterations = nodeArguments[0].value as number;\n\n // A repeat node must have a positive number of iterations if defined.\n if (node.iterations < 0) {\n throw new Error(\"a repeat node must have a positive number of iterations if defined\");\n }\n } else if (nodeArguments.length === 2) {\n // A minimum and maximum iteration count was defined.\n node.iterations = [nodeArguments[0].value as number, nodeArguments[1].value as number];\n\n // A repeat node must have a positive min and max iteration count if they are defined.\n if (node.iterations[0] < 0 || node.iterations[1] < 0) {\n throw new Error(\"a repeat node must have a positive minimum and maximum iteration count if defined\");\n }\n\n // A repeat node must not have an minimum iteration count that exceeds the maximum iteration count.\n if (node.iterations[0] > node.iterations[1]) {\n throw new Error(\n \"a repeat node must not have a minimum iteration count that exceeds the maximum iteration count\"\n );\n }\n } else {\n // An incorrect number of iteration counts was defined.\n throw new Error(\"invalid number of repeat node iteration count arguments defined\");\n }\n }\n\n // Grab any node attribute definitions and spread them into the node definition.\n node = { ...node, ...parseAttributeTokens(tokens, stringLiteralPlaceholders) };\n\n // This is a decorator node, so we expect an opening '{'.\n popAndCheck(tokens, \"{\");\n\n // Return the repeat node definition.\n return node;\n}\n\n/**\n * Creates a retry node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The retry node JSON definition.\n */\nfunction createRetryNode(tokens: string[], stringLiteralPlaceholders: StringLiteralPlaceholders): RetryNodeDefinition {\n let node = { type: \"retry\" } as RetryNodeDefinition;\n\n // Get the node arguments.\n const nodeArguments = parseArgumentTokens(tokens, stringLiteralPlaceholders);\n\n // The arguments of a retry node are optional. We may have:\n // - No node arguments, in which case the retry note will attempt indefinitely.\n // - One node argument which will be the explicit number of attempts to make.\n // - Two node arguments which define the min and max attempt bounds from which a random attempt count will be picked.\n if (nodeArguments.length) {\n // All retry node arguments MUST be of type number and must be integer.\n nodeArguments\n .filter((arg) => arg.type !== \"number\" || !arg.isInteger)\n .forEach(() => {\n throw new Error(`retry node attempt counts must be integer values`);\n });\n\n // We should have got one or two attempt counts.\n if (nodeArguments.length === 1) {\n // A static attempt count was defined.\n node.attempts = nodeArguments[0].value as number;\n\n // A retry node must have a positive number of attempts if defined.\n if (node.attempts < 0) {\n throw new Error(\"a retry node must have a positive number of attempts if defined\");\n }\n } else if (nodeArguments.length === 2) {\n // A minimum and maximum attempt count was defined.\n node.attempts = [nodeArguments[0].value as number, nodeArguments[1].value as number];\n\n // A retry node must have a positive min and max attempts count if they are defined.\n if (node.attempts[0] < 0 || node.attempts[1] < 0) {\n throw new Error(\"a retry node must have a positive minimum and maximum attempt count if defined\");\n }\n\n // A retry node must not have a minimum attempt count that exceeds the maximum attempt count.\n if (node.attempts[0] > node.attempts[1]) {\n throw new Error(\n \"a retry node must not have a minimum attempt count that exceeds the maximum attempt count\"\n );\n }\n } else {\n // An incorrect number of attempt counts was defined.\n throw new Error(\"invalid number of retry node attempt count arguments defined\");\n }\n }\n\n // Grab any node attribute definitions and spread them into the node definition.\n node = { ...node, ...parseAttributeTokens(tokens, stringLiteralPlaceholders) };\n\n // This is a decorator node, so we expect an opening '{'.\n popAndCheck(tokens, \"{\");\n\n // Return the retry node definition.\n return node;\n}\n\n/**\n * Creates a sequence node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The sequence node JSON definition.\n */\nfunction createSequenceNode(\n tokens: string[],\n stringLiteralPlaceholders: StringLiteralPlaceholders\n): SequenceNodeDefinition {\n const node = {\n type: \"sequence\",\n ...parseAttributeTokens(tokens, stringLiteralPlaceholders)\n } as SequenceNodeDefinition;\n\n // This is a composite node, so we expect an opening '{'.\n popAndCheck(tokens, \"{\");\n\n // Return the sequence node definition.\n return node;\n}\n\n/**\n * Creates a selector node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The selector node JSON definition.\n */\nfunction createSelectorNode(\n tokens: string[],\n stringLiteralPlaceholders: StringLiteralPlaceholders\n): SelectorNodeDefinition {\n const node = {\n type: \"selector\",\n ...parseAttributeTokens(tokens, stringLiteralPlaceholders)\n } as SelectorNodeDefinition;\n\n // This is a composite node, so we expect an opening '{'.\n popAndCheck(tokens, \"{\");\n\n // Return the selector node definition.\n return node;\n}\n\n/**\n * Creates a parallel node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The parallel node JSON definition.\n */\nfunction createParallelNode(\n tokens: string[],\n stringLiteralPlaceholders: StringLiteralPlaceholders\n): ParallelNodeDefinition {\n const node = {\n type: \"parallel\",\n ...parseAttributeTokens(tokens, stringLiteralPlaceholders)\n } as ParallelNodeDefinition;\n\n // This is a composite node, so we expect an opening '{'.\n popAndCheck(tokens, \"{\");\n\n // Return the parallel node definition.\n return node;\n}\n\n/**\n * Creates a lotto node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The lotto node JSON definition.\n */\nfunction createLottoNode(tokens: string[], stringLiteralPlaceholders: StringLiteralPlaceholders): LottoNodeDefinition {\n // If any node arguments have been defined then they must be our weights.\n const nodeArguments = parseArgumentTokens(tokens, stringLiteralPlaceholders);\n\n // All lotto node arguments MUST be of type number and must be integer.\n nodeArguments\n .filter((arg) => arg.type !== \"number\" || !arg.isInteger)\n .forEach(() => {\n throw new Error(`lotto node weight arguments must be integer values`);\n });\n\n const node = {\n type: \"lotto\",\n weights: nodeArguments.map(({ value }) => value),\n ...parseAttributeTokens(tokens, stringLiteralPlaceholders)\n } as LottoNodeDefinition;\n\n // This is a composite node, so we expect an opening '{'.\n popAndCheck(tokens, \"{\");\n\n // Return the lotto node definition.\n return node;\n}\n\n/**\n * Creates an action node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The action node JSON definition.\n */\nfunction createActionNode(\n tokens: string[],\n stringLiteralPlaceholders: StringLiteralPlaceholders\n): ActionNodeDefinition {\n // Parse any node arguments, we should have at least one which will be an identifier argument for the action name\n // and agent function to invoke for the action, all other arguments are to be passed as arguments to that function.\n const [actionNameIdentifier, ...agentFunctionArgs] = parseArgumentTokens(tokens, stringLiteralPlaceholders);\n\n // Our first argument MUST be defined and be an identifier as we require an action name argument.\n if (actionNameIdentifier?.type !== \"identifier\") {\n throw new Error(\"expected action name identifier argument\");\n }\n\n // Only the first argument should have been an identifier, all agent function arguments must be string, number, boolean or null.\n agentFunctionArgs\n .filter((arg) => arg.type === \"identifier\")\n .forEach((arg) => {\n throw new Error(\n `invalid action node argument value '${arg.value}', must be string, number, boolean or null`\n );\n });\n\n // Return the action node definition.\n return {\n type: \"action\",\n call: actionNameIdentifier.value,\n args: agentFunctionArgs.map(({ value }) => value),\n ...parseAttributeTokens(tokens, stringLiteralPlaceholders)\n };\n}\n\n/**\n * Creates a condition node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The condition node JSON definition.\n */\nfunction createConditionNode(\n tokens: string[],\n stringLiteralPlaceholders: StringLiteralPlaceholders\n): ConditionNodeDefinition {\n // Parse any node arguments, we should have at least one which will be an identifier argument for the condition name\n // and agent function to invoke for the condition, all other arguments are to be passed as arguments to that function.\n const [conditionNameIdentifier, ...agentFunctionArgs] = parseArgumentTokens(tokens, stringLiteralPlaceholders);\n\n // Our first argument MUST be defined and be an identifier as we require a condition name argument.\n if (conditionNameIdentifier?.type !== \"identifier\") {\n throw new Error(\"expected condition name identifier argument\");\n }\n\n // Only the first argument should have been an identifier, all agent function arguments must be string, number, boolean or null.\n agentFunctionArgs\n .filter((arg) => arg.type === \"identifier\")\n .forEach((arg) => {\n throw new Error(\n `invalid condition node argument value '${arg.value}', must be string, number, boolean or null`\n );\n });\n\n // Return the condition node definition.\n return {\n type: \"condition\",\n call: conditionNameIdentifier.value,\n args: agentFunctionArgs.map(({ value }) => value),\n ...parseAttributeTokens(tokens, stringLiteralPlaceholders)\n };\n}\n\n/**\n * Creates a wait node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The wait node JSON definition.\n */\nfunction createWaitNode(tokens: string[], stringLiteralPlaceholders: StringLiteralPlaceholders): WaitNodeDefinition {\n let node = { type: \"wait\" } as WaitNodeDefinition;\n\n // Get the node arguments.\n const nodeArguments = parseArgumentTokens(tokens, stringLiteralPlaceholders);\n\n // The arguments of a wait node are optional. We may have:\n // - No node arguments, in which case the wait will be indefinite until it is aborted.\n // - One node argument which will be the explicit duration of the wait.\n // - Two node arguments which define the min and max duration bounds from which a random duration will be picked.\n if (nodeArguments.length) {\n // All wait node arguments MUST be of type number and must be integer.\n nodeArguments\n .filter((arg) => arg.type !== \"number\" || !arg.isInteger)\n .forEach(() => {\n throw new Error(`wait node durations must be integer values`);\n });\n\n // We may have:\n // - One node argument which will be the explicit duration of the wait.\n // - Two node arguments which define the min and max duration bounds from which a random duration will be picked.\n // - Too many arguments, which is not valid.\n if (nodeArguments.length === 1) {\n // An explicit duration was defined.\n node.duration = nodeArguments[0].value as number;\n\n // If an explict duration was defined then it must be a positive number.\n if (node.duration < 0) {\n throw new Error(\"a wait node must have a positive duration\");\n }\n } else if (nodeArguments.length === 2) {\n // Min and max duration bounds were defined from which a random duration will be picked.\n node.duration = [nodeArguments[0].value as number, nodeArguments[1].value as number];\n\n // A wait node must have a positive min and max duration.\n if (node.duration[0] < 0 || node.duration[1] < 0) {\n throw new Error(\"a wait node must have a positive minimum and maximum duration\");\n }\n\n // A wait node must not have a minimum duration that exceeds the maximum duration.\n if (node.duration[0] > node.duration[1]) {\n throw new Error(\"a wait node must not have a minimum duration that exceeds the maximum duration\");\n }\n } else if (nodeArguments.length > 2) {\n // An incorrect number of duration arguments were defined.\n throw new Error(\"invalid number of wait node duration arguments defined\");\n }\n }\n\n // Return the wait node definition.\n return { ...node, ...parseAttributeTokens(tokens, stringLiteralPlaceholders) };\n}\n\n/**\n * Creates a branch node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The branch node JSON definition.\n */\nfunction createBranchNode(\n tokens: string[],\n stringLiteralPlaceholders: StringLiteralPlaceholders\n): BranchNodeDefinition {\n // Parse any node arguments, we should have one which will be an identifier argument for the root ref.\n const nodeArguments = parseArgumentTokens(tokens, stringLiteralPlaceholders);\n\n // We should have only a single identifer argument for a branch node, which is the root ref.\n if (nodeArguments.length !== 1 || nodeArguments[0].type !== \"identifier\") {\n throw new Error(\"expected single branch name argument\");\n }\n\n // Return the branch node definition.\n return { type: \"branch\", ref: nodeArguments[0].value };\n}\n\n/**\n * Validate a fully-populated node definition that was popped off of the tree stack.\n * @param node The popped node to validate.\n */\nfunction validatePoppedNode(node: AnyNodeDefinition): void {\n // Decorators MUST have a child defined.\n if (isDecoratorNode(node) && isNullOrUndefined(node.child)) {\n throw new Error(`a ${node.type} node must have a single child node defined`);\n }\n\n // Composites MUST have at least one child defined.\n if (isCompositeNode(node) && !node.children?.length) {\n throw new Error(`a ${node.type} node must have at least a single child node defined`);\n }\n}\n", "import { RootNodeDefinition } from \"./BehaviourTreeDefinition\";\nimport { flattenDefinition, isBranchNode, isInteger } from \"./BehaviourTreeDefinitionUtilities\";\nimport { convertMDSLToJSON } from \"./mdsl/MDSLDefinitionParser\";\n\n/**\n * An object representing the result of validating a tree definition.\n */\nexport type DefinitionValidationResult = {\n /**\n * A flag defining whether validation succeeded.\n */\n succeeded: boolean;\n /**\n * A string containing the error message if validation did not succeed.\n */\n errorMessage?: string;\n};\n\n/**\n * Validates the specified behaviour tree definition in the form of JSON or MDSL, not taking any globally registered subtrees into consideration.\n * @param definition The behaviour tree definition in the form of JSON or MDSL.\n * @returns An object representing the result of validating the given tree definition.\n */\nexport function validateDefinition(definition: any): DefinitionValidationResult {\n // The definition must be defined.\n if (definition === null || typeof definition === \"undefined\") {\n return createValidationFailureResult(\"definition is null or undefined\");\n }\n\n // We are expecting a definition in one of three different forms:\n // - A string which we will assume is MDSL and we will parse this to JSON before validation.\n // - An array which we will assume is an array of root node definitions with at least one being the primary root node (no 'id' property)\n // - An object which we will assume is the primary root node and should not have an 'id' property.\n if (typeof definition === \"string\") {\n // The definition is a string which we can assume is MDSL, so attempt to validate it.\n return validateMDSLDefinition(definition);\n } else if (typeof definition === \"object\") {\n // The definition will either be an array (of root node definitions) or an object (the single primary root node definition).\n return validateJSONDefinition(definition);\n } else {\n return createValidationFailureResult(`unexpected definition type of '${typeof definition}'`);\n }\n}\n\n/**\n * Validates the specified behaviour tree definition in the form of MDSL.\n * @param definition The behaviour tree definition in the form of MDSL.\n * @returns An object representing the result of validating the given tree definition.\n */\nexport function validateMDSLDefinition(definition: string): DefinitionValidationResult {\n let rootNodeDefinitions;\n\n // The first thing the we need to do is to attempt to convert our MDSL into JSON.\n try {\n // The definition is a string which we can assume is MDSL, so attempt to parse it to a JSON definition in the form of an array of root node definitions.\n rootNodeDefinitions = convertMDSLToJSON(definition);\n } catch (exception) {\n // We failed to parse the JSON from the MDSL, this is likely to be the result of it not being a valid MDSL string.\n return createValidationFailureResult((exception as Error).message);\n }\n\n // Unpack all of the root node definitions into arrays of main ('id' defined) and sub ('id' not defined) root node definitions.\n const mainRootNodeDefinitions = rootNodeDefinitions.filter(({ id }) => typeof id === \"undefined\");\n const subRootNodeDefinitions = rootNodeDefinitions.filter(({ id }) => typeof id === \"string\" && id.length > 0);\n\n // We should ALWAYS have exactly one root node definition without an 'id' property defined, which is out main root node definition.\n if (mainRootNodeDefinitions.length !== 1) {\n return createValidationFailureResult(\n \"expected single unnamed root node at base of definition to act as main root\"\n );\n }\n\n // We should never have duplicate 'id' properties across our sub root node definitions.\n const subRootNodeIdenitifers: string[] = [];\n for (const { id } of subRootNodeDefinitions) {\n // Have we already come across this 'id' property value?\n if (subRootNodeIdenitifers.includes(id!)) {\n return createValidationFailureResult(`multiple root nodes found with duplicate name '${id}'`);\n }\n\n subRootNodeIdenitifers.push(id!);\n }\n\n try {\n // Validate our branch -> subtree links and check for any circular dependencies, we don't care about checking for broken subtree links here.\n validateBranchSubtreeLinks(rootNodeDefinitions, false);\n } catch (exception) {\n return createValidationFailureResult((exception as Error).message);\n }\n\n // Our definition was valid!\n return { succeeded: true };\n}\n\n/**\n * Validates the specified behaviour tree definition in the form of JSON.\n * @param definition The behaviour tree definition in the form of JSON.\n * @returns An object representing the result of validating the given tree definition.\n */\nexport function validateJSONDefinition(\n definition: RootNodeDefinition | RootNodeDefinition[]\n): DefinitionValidationResult {\n // The definition will either be an array (of root node definitions) or an object (the single primary root node definition).\n const rootNodeDefinitions = Array.isArray(definition) ? definition : [definition];\n\n // Iterate over our array of root nodes and call validateNode for each, passing an initial depth of 0, wrapped in a try catch to handle validation failures.\n try {\n rootNodeDefinitions.forEach((rootNodeDefinition) => validateNode(rootNodeDefinition, 0));\n } catch (error) {\n // Handle cases where we have caught a thrown Error and return a failure result with the error message.\n if (error instanceof Error) {\n return createValidationFailureResult(error.message);\n }\n\n // No idea what happened here!\n return createValidationFailureResult(`unexpected error: ${error}`);\n }\n\n // Unpack all of the root node definitions into arrays of main ('id' defined) and sub ('id' not defined) root node definitions.\n const mainRootNodeDefinitions = rootNodeDefinitions.filter(({ id }) => typeof id === \"undefined\");\n const subRootNodeDefinitions = rootNodeDefinitions.filter(({ id }) => typeof id === \"string\" && id.length > 0);\n\n // We should ALWAYS have exactly one root node definition without an 'id' property defined, which is out main root node definition.\n if (mainRootNodeDefinitions.length !== 1) {\n return createValidationFailureResult(\n \"expected single root node without 'id' property defined to act as main root\"\n );\n }\n\n // We should never have duplicate 'id' properties across our sub root node definitions.\n const subRootNodeIdenitifers: string[] = [];\n for (const { id } of subRootNodeDefinitions) {\n // Have we already come across this 'id' property value?\n if (subRootNodeIdenitifers.includes(id!)) {\n return createValidationFailureResult(\n `multiple root nodes found with duplicate 'id' property value of '${id}'`\n );\n }\n\n subRootNodeIdenitifers.push(id!);\n }\n\n try {\n // Validate our branch -> subtree links and check for any circular dependencies, we don't care about checking for broken subtree links here.\n validateBranchSubtreeLinks(rootNodeDefinitions, false);\n } catch (exception) {\n return createValidationFailureResult((exception as Error).message);\n }\n\n // Our definition was valid!\n return { succeeded: true };\n}\n\n/**\n * Validates the branch -> subtree links across all provided root node definitions.\n * This will not consider branch nodes that reference any globally registered subtrees unless includesGlobalSubtrees\n * is set to true, in which case we will also verify that there are no broken branch -> subtree links.\n * @param rootNodeDefinitions The array of root node definitions.\n * @param includesGlobalSubtrees A flag defining whether the array includes all global subtree root node definitions.\n */\nexport function validateBranchSubtreeLinks(rootNodeDefinitions: RootNodeDefinition[], includesGlobalSubtrees: boolean) {\n // Create a mapping of root node identifiers to other root nodes that they reference via branch nodes.\n // Below is an example of a mapping that includes a circular dependency (root => a => b => c => a)\n // [{ refs: [\"a\", \"b\"] }, { id: \"a\", refs: [\"b\"] }, { id: \"b\", refs: [\"c\"] }, { id: \"c\", refs: [\"a\"] }]\n const rootNodeMappings: { id: string | undefined; refs: string[] }[] = rootNodeDefinitions.map(\n (rootNodeDefinition) => ({\n id: rootNodeDefinition.id,\n refs: flattenDefinition(rootNodeDefinition)\n .filter(isBranchNode)\n .map(({ ref }) => ref)\n })\n );\n\n // A recursive function to walk through the mappings, keeping track of which root nodes we have visited in the form of a path of root node identifiers.\n const followRefs = (mapping: { id: string | undefined; refs: string[] }, path: (string | undefined)[] = []) => {\n // Have we found a circular dependency?\n if (path.includes(mapping.id)) {\n // We found a circular dependency! Get the bad path of root node identifiers.\n const badPath = [...path, mapping.id];\n\n // Create the formatted path value. [undefined, \"a\", \"b\", \"c\", \"a\"] would be formatted as \"a -> b -> c -> a\".\n const badPathFormatted = badPath.filter((element) => !!element).join(\" => \");\n\n // No need to continue, we found a circular dependency.\n throw new Error(`circular dependency found in branch node references: ${badPathFormatted}`);\n }\n\n for (const ref of mapping.refs) {\n // Find the mapping for the root node with an identifer matching the current ref.\n const subMapping = rootNodeMappings.find(({ id }) => id === ref);\n\n // We may not have a mapping for this ref, which is normal when we aren't considering all globally registered subtrees.\n if (subMapping) {\n followRefs(subMapping, [...path, mapping.id]);\n } else if (includesGlobalSubtrees) {\n // We found a reference to a root node that doesn't exist, which is a problem seeing as the root node definitons includes all globally registered subtrees.\n throw new Error(\n mapping.id\n ? `subtree '${mapping.id}' has branch node that references root node '${ref}' which has not been defined`\n : `primary tree has branch node that references root node '${ref}' which has not been defined`\n );\n }\n }\n };\n\n // Start looking for circular dependencies and broken references from the primary root node definition.\n followRefs(rootNodeMappings.find((mapping) => typeof mapping.id === \"undefined\")!);\n}\n\n/**\n * Validate an object that we expect to be a node definition.\n * @param definition An object that we expect to be a node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateNode(definition: any, depth: number): void {\n // Every node must be valid object and have a non-empty 'type' string property.\n if (typeof definition !== \"object\" || typeof definition.type !== \"string\" || definition.type.length === 0) {\n throw new Error(\n `node definition is not an object or 'type' property is not a non-empty string at depth '${depth}'`\n );\n }\n\n // How we validate this node definition will depend on its type.\n switch (definition.type) {\n case \"action\":\n validateActionNode(definition, depth);\n break;\n\n case \"condition\":\n validateConditionNode(definition, depth);\n break;\n\n case \"wait\":\n validateWaitNode(definition, depth);\n break;\n\n case \"branch\":\n validateBranchNode(definition, depth);\n break;\n\n case \"root\":\n validateRootNode(definition, depth);\n break;\n\n case \"success\":\n validateSuccessNode(definition, depth);\n break;\n\n case \"fail\":\n validateFailNode(definition, depth);\n break;\n\n case \"flip\":\n validateFlipNode(definition, depth);\n break;\n\n case \"repeat\":\n validateRepeatNode(definition, depth);\n break;\n\n case \"retry\":\n validateRetryNode(definition, depth);\n break;\n\n case \"sequence\":\n validateSequenceNode(definition, depth);\n break;\n\n case \"selector\":\n validateSelectorNode(definition, depth);\n break;\n\n case \"parallel\":\n validateParallelNode(definition, depth);\n break;\n\n default:\n throw new Error(`unexpected node type of '${definition.type}' at depth '${depth}'`);\n }\n}\n\n/**\n * Validate any attributes for a given node definition.\n * @param definition The node definition.\n * @param depth The depth of the node in the behaviour tree definition.\n */\nfunction validateNodeAttributes(definition: any, depth: number): void {\n // Validate each of the attribute types for this node.\n [\"while\", \"until\", \"entry\", \"exit\", \"step\"].forEach((attributeName) => {\n // Attempt to grab the definition for the current attribute from the node definition.\n const attributeDefinition = definition[attributeName];\n\n // All node attributes are optional, so there is nothing to do if the current attribute is not defined.\n if (typeof attributeDefinition === \"undefined\") {\n return;\n }\n\n // The attribute definition must be an object.\n if (typeof attributeDefinition !== \"object\") {\n throw new Error(\n `expected attribute '${attributeName}' to be an object for '${definition.type}' node at depth '${depth}'`\n );\n }\n\n // The 'call' property must be defined for any attribute definition.\n if (typeof attributeDefinition.call !== \"string\" || attributeDefinition.call.length === 0) {\n throw new Error(\n `expected 'call' property for attribute '${attributeName}' to be a non-empty string for '${definition.type}' node at depth '${depth}'`\n );\n }\n\n // If any node attribute arguments have been defined then they must have been defined in an array.\n if (typeof attributeDefinition.args !== \"undefined\" && !Array.isArray(attributeDefinition.args)) {\n throw new Error(\n `expected 'args' property for attribute '${attributeName}' to be an array for '${definition.type}' node at depth '${depth}'`\n );\n }\n });\n}\n\n/**\n * Validate an object that we expect to be a root node definition.\n * @param definition An object that we expect to be a root node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateRootNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"root\") {\n throw new Error(\"expected node type of 'root' for root node\");\n }\n\n // A root node cannot be the child of another node.\n if (depth > 0) {\n throw new Error(\"a root node cannot be the child of another node\");\n }\n\n // Check that, if the root node 'id' property is defined, it is a non-empty string.\n if (typeof definition.id !== \"undefined\" && (typeof definition.id !== \"string\" || definition.id.length === 0)) {\n throw new Error(\"expected non-empty string for 'id' property if defined for root node\");\n }\n\n // A root node is a decorator node, so must have a child node defined.\n if (typeof definition.child === \"undefined\") {\n throw new Error(\"expected property 'child' to be defined for root node\");\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n\n // Validate the child node of this decorator node.\n validateNode(definition.child, depth + 1);\n}\n\n/**\n * Validate an object that we expect to be a success node definition.\n * @param definition An object that we expect to be a success node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateSuccessNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"success\") {\n throw new Error(`expected node type of 'success' for success node at depth '${depth}'`);\n }\n\n // A success node is a decorator node, so must have a child node defined.\n if (typeof definition.child === \"undefined\") {\n throw new Error(`expected property 'child' to be defined for success node at depth '${depth}'`);\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n\n // Validate the child node of this decorator node.\n validateNode(definition.child, depth + 1);\n}\n\n/**\n * Validate an object that we expect to be a fail node definition.\n * @param definition An object that we expect to be a fail node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateFailNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"fail\") {\n throw new Error(`expected node type of 'fail' for fail node at depth '${depth}'`);\n }\n\n // A fail node is a decorator node, so must have a child node defined.\n if (typeof definition.child === \"undefined\") {\n throw new Error(`expected property 'child' to be defined for fail node at depth '${depth}'`);\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n\n // Validate the child node of this decorator node.\n validateNode(definition.child, depth + 1);\n}\n\n/**\n * Validate an object that we expect to be a flip node definition.\n * @param definition An object that we expect to be a flip node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateFlipNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"flip\") {\n throw new Error(`expected node type of 'flip' for flip node at depth '${depth}'`);\n }\n\n // A flip node is a decorator node, so must have a child node defined.\n if (typeof definition.child === \"undefined\") {\n throw new Error(`expected property 'child' to be defined for flip node at depth '${depth}'`);\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n\n // Validate the child node of this decorator node.\n validateNode(definition.child, depth + 1);\n}\n\n/**\n * Validate an object that we expect to be a repeat node definition.\n * @param definition An object that we expect to be a repeat node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateRepeatNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"repeat\") {\n throw new Error(`expected node type of 'repeat' for repeat node at depth '${depth}'`);\n }\n\n // A repeat node is a decorator node, so must have a child node defined.\n if (typeof definition.child === \"undefined\") {\n throw new Error(`expected property 'child' to be defined for repeat node at depth '${depth}'`);\n }\n\n // Check whether an 'iterations' property has been defined, it may not have been if this node is to repeat indefinitely.\n if (typeof definition.iterations !== \"undefined\") {\n if (Array.isArray(definition.iterations)) {\n // Check whether any elements of the array are not integer values.\n const containsNonInteger = !!definition.iterations.find((value: unknown) => !isInteger(value));\n\n // If the 'iterations' property is an array then it MUST contain two integer values.\n if (definition.iterations.length !== 2 || containsNonInteger) {\n throw new Error(\n `expected array containing two integer values for 'iterations' property if defined for repeat node at depth '${depth}'`\n );\n }\n\n // A repeat node must have a positive min and max iterations count if they are defined.\n if (definition.iterations[0] < 0 || definition.iterations[1] < 0) {\n throw new Error(\n `expected positive minimum and maximum iterations count for 'iterations' property if defined for repeat node at depth '${depth}'`\n );\n }\n\n // A repeat node must not have a minimum iterations count that exceeds the maximum iterations count.\n if (definition.iterations[0] > definition.iterations[1]) {\n throw new Error(\n `expected minimum iterations count that does not exceed the maximum iterations count for 'iterations' property if defined for repeat node at depth '${depth}'`\n );\n }\n } else if (isInteger(definition.iterations)) {\n // A repeat node must have a positive number of iterations if defined.\n if (definition.iterations < 0) {\n throw new Error(\n `expected positive iterations count for 'iterations' property if defined for repeat node at depth '${depth}'`\n );\n }\n } else {\n throw new Error(\n `expected integer value or array containing two integer values for 'iterations' property if defined for repeat node at depth '${depth}'`\n );\n }\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n\n // Validate the child node of this decorator node.\n validateNode(definition.child, depth + 1);\n}\n\n/**\n * Validate an object that we expect to be a retry node definition.\n * @param definition An object that we expect to be a retry node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateRetryNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"retry\") {\n throw new Error(`expected node type of 'retry' for retry node at depth '${depth}'`);\n }\n\n // A retry node is a decorator node, so must have a child node defined.\n if (typeof definition.child === \"undefined\") {\n throw new Error(`expected property 'child' to be defined for retry node at depth '${depth}'`);\n }\n\n // Check whether an 'attempts' property has been defined, it may not have been if this node is to retry indefinitely.\n if (typeof definition.attempts !== \"undefined\") {\n if (Array.isArray(definition.attempts)) {\n // Check whether any elements of the array are not integer values.\n const containsNonInteger = !!definition.attempts.find((value: unknown) => !isInteger(value));\n\n // If the 'attempts' property is an array then it MUST contain two integer values.\n if (definition.attempts.length !== 2 || containsNonInteger) {\n throw new Error(\n `expected array containing two integer values for 'attempts' property if defined for retry node at depth '${depth}'`\n );\n }\n\n // A retry node must have a positive min and max attempts count if they are defined.\n if (definition.attempts[0] < 0 || definition.attempts[1] < 0) {\n throw new Error(\n `expected positive minimum and maximum attempts count for 'attempts' property if defined for retry node at depth '${depth}'`\n );\n }\n\n // A retry node must not have a minimum attempts count that exceeds the maximum attempts count.\n if (definition.attempts[0] > definition.attempts[1]) {\n throw new Error(\n `expected minimum attempts count that does not exceed the maximum attempts count for 'attempts' property if defined for retry node at depth '${depth}'`\n );\n }\n } else if (isInteger(definition.attempts)) {\n // A retry node must have a positive number of attempts if defined.\n if (definition.attempts < 0) {\n throw new Error(\n `expected positive attempts count for 'attempts' property if defined for retry node at depth '${depth}'`\n );\n }\n } else {\n throw new Error(\n `expected integer value or array containing two integer values for 'attempts' property if defined for retry node at depth '${depth}'`\n );\n }\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n\n // Validate the child node of this decorator node.\n validateNode(definition.child, depth + 1);\n}\n\n/**\n * Validate an object that we expect to be a branch node definition.\n * @param definition An object that we expect to be a branch node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateBranchNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"branch\") {\n throw new Error(`expected node type of 'branch' for branch node at depth '${depth}'`);\n }\n\n // Check that the branch node 'ref' property is defined and is a non-empty string.\n if (typeof definition.ref !== \"string\" || definition.ref.length === 0) {\n throw new Error(`expected non-empty string for 'ref' property for branch node at depth '${depth}'`);\n }\n\n // It is invalid to define guard attributes for a branch node as they should be defined on the referenced root node.\n [\"while\", \"until\"].forEach((attributeName) => {\n if (typeof definition[attributeName] !== \"undefined\") {\n throw new Error(\n `guards should not be defined for branch nodes but guard '${attributeName}' was defined for branch node at depth '${depth}'`\n );\n }\n });\n\n // It is invalid to define callback attributes for a branch node as they should be defined on the referenced root node.\n [\"entry\", \"exit\", \"step\"].forEach((attributeName) => {\n if (typeof definition[attributeName] !== \"undefined\") {\n throw new Error(\n `callbacks should not be defined for branch nodes but callback '${attributeName}' was defined for branch node at depth '${depth}'`\n );\n }\n });\n}\n\n/**\n * Validate an object that we expect to be a action node definition.\n * @param definition An object that we expect to be a action node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateActionNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"action\") {\n throw new Error(`expected node type of 'action' for action node at depth '${depth}'`);\n }\n\n // The 'call' property must be defined for a action node definition.\n if (typeof definition.call !== \"string\" || definition.call.length === 0) {\n throw new Error(`expected non-empty string for 'call' property of action node at depth '${depth}'`);\n }\n\n // If any action function arguments have been defined then they must have been defined in an array.\n if (typeof definition.args !== \"undefined\" && !Array.isArray(definition.args)) {\n throw new Error(`expected array for 'args' property if defined for action node at depth '${depth}'`);\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n}\n\n/**\n * Validate an object that we expect to be a condition node definition.\n * @param definition An object that we expect to be a condition node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateConditionNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"condition\") {\n throw new Error(`expected node type of 'condition' for condition node at depth '${depth}'`);\n }\n\n // The 'call' property must be defined for a condition node definition.\n if (typeof definition.call !== \"string\" || definition.call.length === 0) {\n throw new Error(`expected non-empty string for 'call' property of condition node at depth '${depth}'`);\n }\n\n // If any condition function arguments have been defined then they must have been defined in an array.\n if (typeof definition.args !== \"undefined\" && !Array.isArray(definition.args)) {\n throw new Error(`expected array for 'args' property if defined for condition node at depth '${depth}'`);\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n}\n\n/**\n * Validate an object that we expect to be a wait node definition.\n * @param definition An object that we expect to be a wait node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateWaitNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"wait\") {\n throw new Error(`expected node type of 'wait' for wait node at depth '${depth}'`);\n }\n\n // Check whether a 'duration' property has been defined, it may not have been if this node is to wait indefinitely.\n if (typeof definition.duration !== \"undefined\") {\n if (Array.isArray(definition.duration)) {\n // Check whether any elements of the array are not integer values.\n const containsNonInteger = !!definition.duration.find((value: unknown) => !isInteger(value));\n\n // If the 'duration' property is an array then it MUST contain two integer values.\n if (definition.duration.length !== 2 || containsNonInteger) {\n throw new Error(\n `expected array containing two integer values for 'duration' property if defined for wait node at depth '${depth}'`\n );\n }\n\n // A wait node must have a positive min and max duration value if they are defined.\n if (definition.duration[0] < 0 || definition.duration[1] < 0) {\n throw new Error(\n `expected positive minimum and maximum duration for 'duration' property if defined for wait node at depth '${depth}'`\n );\n }\n\n // A wait node must not have a minimum duration value that exceeds the maximum duration value.\n if (definition.duration[0] > definition.duration[1]) {\n throw new Error(\n `expected minimum duration value that does not exceed the maximum duration value for 'duration' property if defined for wait node at depth '${depth}'`\n );\n }\n } else if (isInteger(definition.duration)) {\n // A wait node must have a positive duration value if defined.\n if (definition.duration < 0) {\n throw new Error(\n `expected positive duration value for 'duration' property if defined for wait node at depth '${depth}'`\n );\n }\n } else {\n throw new Error(\n `expected integer value or array containing two integer values for 'duration' property if defined for wait node at depth '${depth}'`\n );\n }\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n}\n\n/**\n * Validate an object that we expect to be a sequence node definition.\n * @param definition An object that we expect to be a sequence node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateSequenceNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"sequence\") {\n throw new Error(`expected node type of 'sequence' for sequence node at depth '${depth}'`);\n }\n\n // A sequence node is a composite node, so must have a children nodes array defined.\n if (!Array.isArray(definition.children) || definition.children.length === 0) {\n throw new Error(`expected non-empty 'children' array to be defined for sequence node at depth '${depth}'`);\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n\n // Validate the child nodes of this composite node.\n definition.children.forEach((child: any) => validateNode(child, depth + 1));\n}\n\n/**\n * Validate an object that we expect to be a selector node definition.\n * @param definition An object that we expect to be a selector node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateSelectorNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"selector\") {\n throw new Error(`expected node type of 'selector' for selector node at depth '${depth}'`);\n }\n\n // A selector node is a composite node, so must have a children nodes array defined.\n if (!Array.isArray(definition.children) || definition.children.length === 0) {\n throw new Error(`expected non-empty 'children' array to be defined for selector node at depth '${depth}'`);\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n\n // Validate the child nodes of this composite node.\n definition.children.forEach((child: any) => validateNode(child, depth + 1));\n}\n\n/**\n * Validate an object that we expect to be a parallel node definition.\n * @param definition An object that we expect to be a parallel node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateParallelNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"parallel\") {\n throw new Error(`expected node type of 'parallel' for parallel node at depth '${depth}'`);\n }\n\n // A parallel node is a composite node, so must have a children nodes array defined.\n if (!Array.isArray(definition.children) || definition.children.length === 0) {\n throw new Error(`expected non-empty 'children' array to be defined for parallel node at depth '${depth}'`);\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n\n // Validate the child nodes of this composite node.\n definition.children.forEach((child: any) => validateNode(child, depth + 1));\n}\n\n/**\n * A helper function to create a failure validation result with the given error message.\n * @param errorMessage The validation failure error message.\n * @returns A failure validation result with the given error message.\n */\nfunction createValidationFailureResult(errorMessage: string): DefinitionValidationResult {\n return { succeeded: false, errorMessage };\n}\n", "import { ActionResult, Agent, GlobalFunction } from \"./Agent\";\nimport { RootNodeDefinition } from \"./BehaviourTreeDefinition\";\n\nexport type InvokerFunction = (args: any[]) => ActionResult;\n\n/**\n * A singleton used to store and lookup registered functions and subtrees.\n */\nexport default class Lookup {\n /**\n * The object holding any registered functions keyed on function name.\n */\n private static functionTable: { [key: string]: GlobalFunction } = {};\n /**\n * The object holding any registered subtree root node definitions keyed on tree name.\n */\n private static subtreeTable: { [key: string]: RootNodeDefinition } = {};\n\n /**\n * Gets the function with the specified name.\n * @param name The name of the function.\n * @returns The function with the specified name.\n */\n public static getFunc(name: string): GlobalFunction {\n return this.functionTable[name];\n }\n\n /**\n * Sets the function with the specified name for later lookup.\n * @param name The name of the function.\n * @param func The function.\n */\n public static setFunc(name: string, func: GlobalFunction): void {\n this.functionTable[name] = func;\n }\n\n /**\n * Gets the function invoker for the specified agent and function name.\n * If a function with the specified name exists on the agent object then it will\n * be returned, otherwise we will then check the registered functions for a match.\n * @param agent The agent instance that this behaviour tree is modelling behaviour for.\n * @param name The function name.\n * @returns The function invoker for the specified agent and function name.\n */\n static getFuncInvoker(agent: Agent, name: string): InvokerFunction | null {\n // Check whether the agent contains the specified function.\n const foundOnAgent = agent[name];\n if (foundOnAgent && typeof foundOnAgent === \"function\") {\n return (args: any[]): boolean | ActionResult => foundOnAgent.apply(agent, args);\n }\n\n // The agent does not contain the specified function but it may have been registered at some point.\n if (this.functionTable[name] && typeof this.functionTable[name] === \"function\") {\n return (args: any[]) => this.functionTable[name](agent, ...args.map((arg) => arg.value));\n }\n\n // We have no function to invoke.\n return null;\n }\n\n /**\n * Gets all registered subtree root node definitions.\n */\n static getSubtrees(): { [key: string]: RootNodeDefinition } {\n return this.subtreeTable;\n }\n\n /**\n * Sets the subtree with the specified name for later lookup.\n * @param name The name of the subtree.\n * @param subtree The subtree.\n */\n static setSubtree(name: string, subtree: RootNodeDefinition) {\n this.subtreeTable[name] = subtree;\n }\n\n /**\n * Removes the registered function or subtree with the specified name.\n * @param name The name of the registered function or subtree.\n */\n static remove(name: string) {\n delete this.functionTable[name];\n delete this.subtreeTable[name];\n }\n\n /**\n * Remove all registered functions and subtrees.\n */\n static empty() {\n this.functionTable = {};\n this.subtreeTable = {};\n }\n}\n", "import Node from \"../../nodes/Node\";\n\n/**\n * An exception thrown when evaluating node guard path conditions and a conditions fails.\n */\nexport default class GuardUnsatisifedException extends Error {\n /**\n * @param source The node at which a guard condition failed.\n */\n constructor(private source: Node) {\n super(\"A guard path condition has failed\");\n }\n\n /**\n * Gets whether the specified node is the node at which a guard condition failed.\n * @param node The node to check against the source node.\n * @returns Whether the specified node is the node at which a guard condition failed.\n */\n isSourceNode = (node: Node) => node === this.source;\n}\n", "import { Agent } from \"../../Agent\";\nimport Guard from \"./Guard\";\nimport Node from \"../../nodes/Node\";\nimport GuardUnsatisifedException from \"./GuardUnsatisifedException\";\n\nexport type GuardPathPart = {\n node: Node;\n guards: Guard[];\n};\n\n/**\n * Represents a path of node guards along a root-to-leaf tree path.\n */\nexport default class GuardPath {\n /**\n * @param nodes An array of objects defining a node instance -> guard link, ordered by node depth.\n */\n constructor(private nodes: GuardPathPart[]) {}\n\n /**\n * Evaluate guard conditions for all guards in the tree path, moving outwards from the root.\n * @param agent The agent, required for guard evaluation.\n * @returns An evaluation results object.\n */\n evaluate = (agent: Agent) => {\n // We need to evaluate guard conditions for nodes up the tree, moving outwards from the root.\n for (const details of this.nodes) {\n // There can be multiple guards per node.\n for (const guard of details.guards) {\n // Check whether the guard condition passes, and throw an exception if not.\n if (!guard.isSatisfied(agent)) {\n throw new GuardUnsatisifedException(details.node);\n }\n }\n }\n };\n}\n", "import { BehaviourTreeOptions } from \"../BehaviourTreeOptions\";\nimport State, { AnyState } from \"../State\";\nimport { Agent } from \"../Agent\";\nimport Leaf from \"./leaf/Leaf\";\nimport Attribute from \"../attributes/Attribute\";\nimport Entry from \"../attributes/callbacks/Entry\";\nimport Exit from \"../attributes/callbacks/Exit\";\nimport Step from \"../attributes/callbacks/Step\";\nimport Guard from \"../attributes/guards/Guard\";\nimport GuardPath from \"../attributes/guards/GuardPath\";\nimport GuardUnsatisifedException from \"../attributes/guards/GuardUnsatisifedException\";\n\n/**\n * A base node.\n */\nexport default abstract class Node {\n /**\n * The node uid.\n */\n private readonly uid: string = createNodeUid();\n /**\n * The node state.\n */\n private state: AnyState = State.READY;\n /**\n * The guard path to evaluate as part of a node update.\n */\n private guardPath: GuardPath | undefined;\n\n /**\n * @param type The node type.\n * @param attributes The node attributes.\n * @param args The node argument definitions.\n */\n constructor(private type: string, private attributes: Attribute[], private args: any[]) {}\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected abstract onUpdate(agent: Agent, options: BehaviourTreeOptions): void;\n\n /**\n * Gets the name of the node.\n */\n public abstract getName(): string;\n\n /**\n * Gets whether this node is a leaf node.\n */\n public abstract isLeafNode: () => this is Leaf;\n\n /**\n * Gets/Sets the state of the node.\n */\n getState = (): AnyState => this.state;\n setState = (value: AnyState): void => {\n this.state = value;\n };\n\n /**\n * Gets the unique id of the node.\n */\n getUid = () => this.uid;\n\n /**\n * Gets the type of the node.\n */\n getType = () => this.type;\n\n /**\n * Gets the node attributes.\n */\n getAttributes = () => this.attributes;\n\n /**\n * Gets the node arguments.\n */\n getArguments = () => this.args;\n\n /**\n * Gets the node attribute with the specified type, or null if it does not exist.\n */\n getAttribute(type: \"entry\" | \"ENTRY\"): Entry;\n getAttribute(type: \"exit\" | \"EXIT\"): Exit;\n getAttribute(type: \"step\" | \"STEP\"): Step;\n getAttribute(type: string): Attribute {\n return (\n this.getAttributes().filter((decorator) => decorator.type.toUpperCase() === type.toUpperCase())[0] || null\n );\n }\n\n /**\n * Gets the node attributes.\n */\n getGuardAttributes = (): Guard[] => this.getAttributes().filter((decorator) => decorator.isGuard()) as Guard[];\n\n /**\n * Sets the guard path to evaluate as part of a node update.\n */\n setGuardPath = (value: GuardPath) => (this.guardPath = value);\n\n /**\n * Gets whether a guard path is assigned to this node.\n */\n hasGuardPath = () => !!this.guardPath;\n\n /**\n * Gets whether this node is in the specified state.\n * @param value The value to compare to the node state.\n */\n public is(value: AnyState): boolean {\n return this.state === value;\n }\n\n /**\n * Reset the state of the node.\n */\n public reset(): void {\n this.setState(State.READY);\n }\n\n /**\n * Abort the running of this node.\n * @param agent The agent.\n */\n public abort(agent: Agent): void {\n // There is nothing to do if this node is not in the running state.\n if (!this.is(State.RUNNING)) {\n return;\n }\n\n // Reset the state of this node.\n this.reset();\n\n this.getAttribute(\"exit\")?.callAgentFunction(agent, false, true);\n }\n\n /**\n * Update the node.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n * @returns The result of the update.\n */\n public update(agent: Agent, options: BehaviourTreeOptions): void {\n // If this node is already in a 'SUCCEEDED' or 'FAILED' state then there is nothing to do.\n if (this.is(State.SUCCEEDED) || this.is(State.FAILED)) {\n return;\n }\n\n try {\n // Evaluate all of the guard path conditions for the current tree path.\n this.guardPath!.evaluate(agent);\n\n // If this node is in the READY state then call the ENTRY for this node if it exists.\n if (this.is(State.READY)) {\n this.getAttribute(\"entry\")?.callAgentFunction(agent);\n }\n\n this.getAttribute(\"step\")?.callAgentFunction(agent);\n\n // Do the actual update.\n this.onUpdate(agent, options);\n\n // If this node is now in a 'SUCCEEDED' or 'FAILED' state then call the EXIT for this node if it exists.\n if (this.is(State.SUCCEEDED) || this.is(State.FAILED)) {\n this.getAttribute(\"exit\")?.callAgentFunction(agent, this.is(State.SUCCEEDED), false);\n }\n } catch (error) {\n // If the error is a GuardUnsatisfiedException then we need to determine if this node is the source.\n if (error instanceof GuardUnsatisifedException && error.isSourceNode(this)) {\n // Abort the current node.\n this.abort(agent);\n\n // Any node that is the source of an abort will be a failed node.\n this.setState(State.FAILED);\n } else {\n throw error;\n }\n }\n }\n}\n\n/**\n * Create a randomly generated node uid.\n * @returns A randomly generated node uid.\n */\nfunction createNodeUid(): string {\n var S4 = function () {\n return (((1 + Math.random()) * 0x10000) | 0).toString(16).substring(1);\n };\n return S4() + S4() + \"-\" + S4() + \"-\" + S4() + \"-\" + S4() + \"-\" + S4() + S4() + S4();\n}\n", "import Node from \"../Node\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\n\n/**\n * A composite node that wraps child nodes.\n */\nexport default abstract class Composite extends Node {\n /**\n * @param type The node type.\n * @param attributes The node attributes.\n * @param children The child nodes.\n */\n constructor(type: string, attributes: Attribute[], protected children: Node[]) {\n super(type, attributes, []);\n }\n\n /**\n * Gets whether this node is a leaf node.\n */\n isLeafNode = () => false;\n\n /**\n * Gets the children of this node.\n */\n getChildren = () => this.children;\n\n /**\n * Reset the state of the node.\n */\n reset = () => {\n // Reset the state of this node.\n this.setState(State.READY);\n\n // Reset the state of any child nodes.\n this.getChildren().forEach((child) => child.reset());\n };\n\n /**\n * Abort the running of this node.\n * @param agent The agent.\n */\n abort = (agent: Agent) => {\n // There is nothing to do if this node is not in the running state.\n if (!this.is(State.RUNNING)) {\n return;\n }\n\n // Abort any child nodes.\n this.getChildren().forEach((child) => child.abort(agent));\n\n // Reset the state of this node.\n this.reset();\n\n this.getAttribute(\"exit\")?.callAgentFunction(agent, false, true);\n };\n}\n", "import Composite from \"./Composite\";\nimport State from \"../../State\";\nimport Node from \"../Node\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A PARALLEL node.\n * The child nodes are executed concurrently until one fails or all succeed.\n */\nexport default class Parallel extends Composite {\n /**\n * @param attributes The node attributes.\n * @param children The child nodes.\n */\n constructor(attributes: Attribute[], children: Node[]) {\n super(\"parallel\", attributes, children);\n }\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // Keep a count of the number of succeeded child nodes.\n let succeededCount = 0;\n\n let hasChildFailed = false;\n\n // Iterate over all of the children of this node.\n for (const child of this.children) {\n // If the child has never been updated or is running then we will need to update it now.\n if (child.getState() === State.READY || child.getState() === State.RUNNING) {\n // Update the child of this node.\n child.update(agent, options);\n }\n\n // If the current child has a state of 'SUCCEEDED' then we should move on to the next child.\n if (child.getState() === State.SUCCEEDED) {\n // The child node has succeeded, keep track of this to determine if all children have.\n succeededCount++;\n\n // The child node succeeded, but we have not finished checking every child node yet.\n continue;\n }\n\n // If the current child has a state of 'FAILED' then this node is also a 'FAILED' node.\n if (child.getState() === State.FAILED) {\n hasChildFailed = true;\n\n // There is no need to check the rest of the children.\n break;\n }\n\n // The node should be in the 'RUNNING' state.\n if (child.getState() !== State.RUNNING) {\n // The child node was not in an expected state.\n throw new Error(\"child node was not in an expected state.\");\n }\n }\n\n if (hasChildFailed) {\n // This node is a 'FAILED' node.\n this.setState(State.FAILED);\n\n // Abort every running child.\n for (const child of this.children) {\n if (child.getState() === State.RUNNING) {\n child.abort(agent);\n }\n }\n } else {\n // If all children have succeeded then this node has also succeeded, otherwise it is still running.\n this.setState(succeededCount === this.children.length ? State.SUCCEEDED : State.RUNNING);\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => \"PARALLEL\";\n}\n", "import Composite from \"./Composite\";\nimport Node from \"../Node\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A SELECTOR node.\n * The child nodes are executed in sequence until one succeeds or all fail.\n */\nexport default class Selector extends Composite {\n /**\n * @param attributes The node attributes.\n * @param children The child nodes.\n */\n constructor(attributes: Attribute[], protected children: Node[]) {\n super(\"selector\", attributes, children);\n }\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // Iterate over all of the children of this node.\n for (const child of this.children) {\n // If the child has never been updated or is running then we will need to update it now.\n if (child.getState() === State.READY || child.getState() === State.RUNNING) {\n // Update the child of this node.\n child.update(agent, options);\n }\n\n // If the current child has a state of 'SUCCEEDED' then this node is also a 'SUCCEEDED' node.\n if (child.getState() === State.SUCCEEDED) {\n // This node is a 'SUCCEEDED' node.\n this.setState(State.SUCCEEDED);\n\n // There is no need to check the rest of the selector nodes.\n return;\n }\n\n // If the current child has a state of 'FAILED' then we should move on to the next child.\n if (child.getState() === State.FAILED) {\n // Find out if the current child is the last one in the selector.\n // If it is then this sequence node has also failed.\n if (this.children.indexOf(child) === this.children.length - 1) {\n // This node is a 'FAILED' node.\n this.setState(State.FAILED);\n\n // There is no need to check the rest of the selector as we have completed it.\n return;\n } else {\n // The child node failed, try the next one.\n continue;\n }\n }\n\n // The node should be in the 'RUNNING' state.\n if (child.getState() === State.RUNNING) {\n // This node is a 'RUNNING' node.\n this.setState(State.RUNNING);\n\n // There is no need to check the rest of the selector as the current child is still running.\n return;\n }\n\n // The child node was not in an expected state.\n throw new Error(\"child node was not in an expected state.\");\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => \"SELECTOR\";\n}\n", "import Composite from \"./Composite\";\nimport Node from \"../Node\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A SEQUENCE node.\n * The child nodes are executed in sequence until one fails or all succeed.\n */\nexport default class Sequence extends Composite {\n /**\n * @param attributes The node attributes.\n * @param children The child nodes.\n */\n constructor(attributes: Attribute[], protected children: Node[]) {\n super(\"sequence\", attributes, children);\n }\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // Iterate over all of the children of this node.\n for (const child of this.children) {\n // If the child has never been updated or is running then we will need to update it now.\n if (child.getState() === State.READY || child.getState() === State.RUNNING) {\n // Update the child of this node.\n child.update(agent, options);\n }\n\n // If the current child has a state of 'SUCCEEDED' then we should move on to the next child.\n if (child.getState() === State.SUCCEEDED) {\n // Find out if the current child is the last one in the sequence.\n // If it is then this sequence node has also succeeded.\n if (this.children.indexOf(child) === this.children.length - 1) {\n // This node is a 'SUCCEEDED' node.\n this.setState(State.SUCCEEDED);\n\n // There is no need to check the rest of the sequence as we have completed it.\n return;\n } else {\n // The child node succeeded, but we have not finished the sequence yet.\n continue;\n }\n }\n\n // If the current child has a state of 'FAILED' then this node is also a 'FAILED' node.\n if (child.getState() === State.FAILED) {\n // This node is a 'FAILED' node.\n this.setState(State.FAILED);\n\n // There is no need to check the rest of the sequence.\n return;\n }\n\n // The node should be in the 'RUNNING' state.\n if (child.getState() === State.RUNNING) {\n // This node is a 'RUNNING' node.\n this.setState(State.RUNNING);\n\n // There is no need to check the rest of the sequence as the current child is still running.\n return;\n }\n\n // The child node was not in an expected state.\n throw new Error(\"child node was not in an expected state.\");\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => \"SEQUENCE\";\n}\n", "import createLotto from \"lotto-draw\";\n\nimport Node from \"../Node\";\nimport Composite from \"./Composite\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A LOTTO node.\n * A winning child is picked on the initial update of this node, based on ticket weighting.\n * The state of this node will match the state of the winning child.\n */\nexport default class Lotto extends Composite {\n /**\n * @param attributes The node attributes.\n * @param weights The child node weights.\n * @param children The child nodes.\n */\n constructor(attributes: Attribute[], private weights: number[] | undefined, children: Node[]) {\n super(\"lotto\", attributes, children);\n }\n\n /**\n * The child node selected to be the active one.\n */\n private selectedChild: Node | undefined;\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // If this node is in the READY state then we need to pick a winning child node.\n if (this.is(State.READY)) {\n // Create a lotto draw with which to randomly pick a child node to become the active one.\n const lottoDraw = createLotto({\n // Hook up the optional 'random' behaviour tree function option to the one used by 'lotto-draw'.\n random: options.random,\n // Pass in each child node as a participant in the lotto draw with their respective ticket count.\n participants: this.children.map((child, index) => [child, this.weights?.[index] || 1])\n });\n\n // Randomly pick a child based on ticket weighting, this will become the active child for this composite node.\n this.selectedChild = lottoDraw.draw() || undefined;\n }\n\n // If something went wrong and we don't have an active child then we should throw an error.\n if (!this.selectedChild) {\n throw new Error(\"failed to update lotto node as it has no active child\");\n }\n\n // If the selected child has never been updated or is running then we will need to update it now.\n if (this.selectedChild.getState() === State.READY || this.selectedChild.getState() === State.RUNNING) {\n this.selectedChild.update(agent, options);\n }\n\n // The state of the lotto node is the state of its selected child.\n this.setState(this.selectedChild.getState());\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => (this.weights ? `LOTTO [${this.weights.join(\",\")}]` : \"LOTTO\");\n}\n", "import Node from \"../Node\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\n\n/**\n * A decorator node that wraps a single child node.\n */\nexport default abstract class Decorator extends Node {\n /**\n * @param type The node type.\n * @param attributes The node attributes.\n * @param child The child node.\n */\n constructor(type: string, attributes: Attribute[], protected child: Node) {\n super(type, attributes, []);\n }\n\n /**\n * Gets whether this node is a leaf node.\n */\n isLeafNode = () => false;\n\n /**\n * Gets the children of this node.\n */\n getChildren = () => [this.child];\n\n /**\n * Reset the state of the node.\n */\n reset = () => {\n // Reset the state of this node.\n this.setState(State.READY);\n\n // Reset the state of the child node.\n this.child.reset();\n };\n\n /**\n * Abort the running of this node.\n * @param agent The agent.\n */\n abort = (agent: Agent) => {\n // There is nothing to do if this node is not in the running state.\n if (!this.is(State.RUNNING)) {\n return;\n }\n\n // Abort the child node.\n this.child.abort(agent);\n\n // Reset the state of this node.\n this.reset();\n\n this.getAttribute(\"exit\")?.callAgentFunction(agent, false, true);\n };\n}\n", "import Node from \"../Node\";\nimport Decorator from \"./Decorator\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A Fail node.\n * This node wraps a single child and will always move to the 'FAILED' state when the child moves to a 'SUCCEEDED' or 'FAILED' state.\n */\nexport default class Fail extends Decorator {\n /**\n * @param attributes The node attributes.\n * @param child The child node.\n */\n constructor(attributes: Attribute[], child: Node) {\n super(\"fail\", attributes, child);\n }\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // If the child has never been updated or is running then we will need to update it now.\n if (this.child.getState() === State.READY || this.child.getState() === State.RUNNING) {\n this.child.update(agent, options);\n }\n\n // The state of this node will depend in the state of its child.\n switch (this.child.getState()) {\n case State.RUNNING:\n this.setState(State.RUNNING);\n break;\n\n case State.SUCCEEDED:\n case State.FAILED:\n this.setState(State.FAILED);\n break;\n\n default:\n this.setState(State.READY);\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => \"FAIL\";\n}\n", "import Decorator from \"./Decorator\";\nimport State from \"../../State\";\nimport Node from \"../Node\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A Flip node.\n * This node wraps a single child and will flip the state of the child state.\n */\nexport default class Flip extends Decorator {\n /**\n * @param attributes The node attributes.\n * @param child The child node.\n */\n constructor(attributes: Attribute[], child: Node) {\n super(\"flip\", attributes, child);\n }\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // If the child has never been updated or is running then we will need to update it now.\n if (this.child.getState() === State.READY || this.child.getState() === State.RUNNING) {\n this.child.update(agent, options);\n }\n\n // The state of this node will depend in the state of its child.\n switch (this.child.getState()) {\n case State.RUNNING:\n this.setState(State.RUNNING);\n break;\n\n case State.SUCCEEDED:\n this.setState(State.FAILED);\n break;\n\n case State.FAILED:\n this.setState(State.SUCCEEDED);\n break;\n\n default:\n this.setState(State.READY);\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => \"FLIP\";\n}\n", "import Node from \"../Node\";\nimport Decorator from \"./Decorator\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A REPEAT node.\n * The node has a single child which can have:\n * -- A number of iterations for which to repeat the child node.\n * -- An infinite repeat loop if neither an iteration count or a condition function is defined.\n * The REPEAT node will stop and have a 'FAILED' state if its child is ever in a 'FAILED' state after an update.\n * The REPEAT node will attempt to move on to the next iteration if its child is ever in a 'SUCCEEDED' state.\n */\nexport default class Repeat extends Decorator {\n /**\n * @param attributes The node attributes.\n * @param iterations The number of iterations to repeat the child node.\n * @param iterationsMin The minimum possible number of iterations to repeat the child node.\n * @param iterationsMax The maximum possible number of iterations to repeat the child node.\n * @param child The child node.\n */\n constructor(\n attributes: Attribute[],\n private iterations: number | null,\n private iterationsMin: number | null,\n private iterationsMax: number | null,\n child: Node\n ) {\n super(\"repeat\", attributes, child);\n }\n\n /**\n * The number of target iterations to make.\n */\n private targetIterationCount: number | null = null;\n\n /**\n * The current iteration count.\n */\n private currentIterationCount: number = 0;\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // If this node is in the READY state then we need to reset the child and the target iteration count.\n if (this.is(State.READY)) {\n // Reset the child node.\n this.child.reset();\n\n // Reset the current iteration count.\n this.currentIterationCount = 0;\n\n // Set the target iteration count.\n this.setTargetIterationCount(options);\n }\n\n // Do a check to see if we can iterate. If we can then this node will move into the 'RUNNING' state.\n // If we cannot iterate then we have hit our target iteration count, which means that the node has succeeded.\n if (this.canIterate()) {\n // This node is in the running state and can do its initial iteration.\n this.setState(State.RUNNING);\n\n // We may have already completed an iteration, meaning that the child node will be in the SUCCEEDED state.\n // If this is the case then we will have to reset the child node now.\n if (this.child.getState() === State.SUCCEEDED) {\n this.child.reset();\n }\n\n // Update the child of this node.\n this.child.update(agent, options);\n\n // If the child moved into the FAILED state when we updated it then there is nothing left to do and this node has also failed.\n // If it has moved into the SUCCEEDED state then we have completed the current iteration.\n if (this.child.getState() === State.FAILED) {\n // The child has failed, meaning that this node has failed.\n this.setState(State.FAILED);\n\n return;\n } else if (this.child.getState() === State.SUCCEEDED) {\n // We have completed an iteration.\n this.currentIterationCount += 1;\n }\n } else {\n // This node is in the 'SUCCEEDED' state as we cannot iterate any more.\n this.setState(State.SUCCEEDED);\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => {\n if (this.iterations !== null) {\n return `REPEAT ${this.iterations}x`;\n } else if (this.iterationsMin !== null && this.iterationsMax !== null) {\n return `REPEAT ${this.iterationsMin}x-${this.iterationsMax}x`;\n } else {\n return \"REPEAT\";\n }\n };\n\n /**\n * Reset the state of the node.\n */\n reset = () => {\n // Reset the state of this node.\n this.setState(State.READY);\n\n // Reset the current iteration count.\n this.currentIterationCount = 0;\n\n // Reset the child node.\n this.child.reset();\n };\n\n /**\n * Gets whether an iteration can be made.\n * @returns Whether an iteration can be made.\n */\n private canIterate = () => {\n if (this.targetIterationCount !== null) {\n // We can iterate as long as we have not reached our target iteration count.\n return this.currentIterationCount < this.targetIterationCount;\n }\n\n // If neither an iteration count or a condition function were defined then we can iterate indefinitely.\n return true;\n };\n\n /**\n * Sets the target iteration count.\n * @param options The behaviour tree options object.\n */\n private setTargetIterationCount = (options: BehaviourTreeOptions) => {\n // Are we dealing with an explicit iteration count or will we be randomly picking a iteration count between the min and max iteration count.\n if (this.iterations !== null) {\n this.targetIterationCount = this.iterations;\n } else if (this.iterationsMin !== null && this.iterationsMax !== null) {\n // We will be picking a random iteration count between a min and max iteration count, if the optional 'random'\n // behaviour tree function option is defined then we will be using that, otherwise we will fall back to using Math.random.\n const random = typeof options.random === \"function\" ? options.random : Math.random;\n\n // Pick a random iteration count between a min and max iteration count.\n this.targetIterationCount = Math.floor(\n random() * (this.iterationsMax - this.iterationsMin + 1) + this.iterationsMin\n );\n } else {\n this.targetIterationCount = null;\n }\n };\n}\n", "import Node from \"../Node\";\nimport Decorator from \"./Decorator\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A RETRY node.\n * The node has a single child which can have:\n * -- A number of iterations for which to repeat the child node.\n * -- An infinite repeat loop if neither an iteration count or a condition function is defined.\n * The RETRY node will stop and have a 'SUCCEEDED' state if its child is ever in a 'SUCCEEDED' state after an update.\n * The RETRY node will attempt to move on to the next iteration if its child is ever in a 'FAILED' state.\n */\nexport default class Retry extends Decorator {\n /**\n * @param attributes The node attributes.\n * @param attempts The number of attempts to retry the child node.\n * @param attemptsMin The minimum possible number of attempts to retry the child node.\n * @param attemptsMax The maximum possible number of attempts to retry the child node.\n * @param child The child node.\n */\n constructor(\n attributes: Attribute[],\n private attempts: number | null,\n private attemptsMin: number | null,\n private attemptsMax: number | null,\n child: Node\n ) {\n super(\"retry\", attributes, child);\n }\n\n /**\n * The number of target attempts to make.\n */\n private targetAttemptCount: number | null = null;\n\n /**\n * The current attempt count.\n */\n private currentAttemptCount: number = 0;\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // If this node is in the READY state then we need to reset the child and the target attempt count.\n if (this.is(State.READY)) {\n // Reset the child node.\n this.child.reset();\n\n // Reset the current attempt count.\n this.currentAttemptCount = 0;\n\n // Set the target attempt count.\n this.setTargetAttemptCount(options);\n }\n\n // Do a check to see if we can attempt. If we can then this node will move into the 'RUNNING' state.\n // If we cannot attempt then we have hit our target attempt count, which means that the node has succeeded.\n if (this.canAttempt()) {\n // This node is in the running state and can do its initial attempt.\n this.setState(State.RUNNING);\n\n // We may have already completed an attempt, meaning that the child node will be in the FAILED state.\n // If this is the case then we will have to reset the child node now.\n if (this.child.getState() === State.FAILED) {\n this.child.reset();\n }\n\n // Update the child of this node.\n this.child.update(agent, options);\n\n // If the child moved into the SUCCEEDED state when we updated it then there is nothing left to do and this node has also succeeded.\n // If it has moved into the FAILED state then we have completed the current attempt.\n if (this.child.getState() === State.SUCCEEDED) {\n // The child has succeeded, meaning that this node has succeeded.\n this.setState(State.SUCCEEDED);\n\n return;\n } else if (this.child.getState() === State.FAILED) {\n // We have completed an attempt.\n this.currentAttemptCount += 1;\n }\n } else {\n // This node is in the 'FAILED' state as we cannot iterate any more.\n this.setState(State.FAILED);\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => {\n if (this.attempts !== null) {\n return `RETRY ${this.attempts}x`;\n } else if (this.attemptsMin !== null && this.attemptsMax !== null) {\n return `RETRY ${this.attemptsMin}x-${this.attemptsMax}x`;\n } else {\n return \"RETRY\";\n }\n };\n\n /**\n * Reset the state of the node.\n */\n reset = () => {\n // Reset the state of this node.\n this.setState(State.READY);\n\n // Reset the current attempt count.\n this.currentAttemptCount = 0;\n\n // Reset the child node.\n this.child.reset();\n };\n\n /**\n * Gets whether an attempt can be made.\n * @returns Whether an attempt can be made.\n */\n canAttempt = () => {\n if (this.targetAttemptCount !== null) {\n // We can attempt as long as we have not reached our target attempt count.\n return this.currentAttemptCount < this.targetAttemptCount;\n }\n\n // If neither an attempt count or a condition function were defined then we can attempt indefinitely.\n return true;\n };\n\n /**\n * Sets the target attempt count.\n * @param options The behaviour tree options object.\n */\n setTargetAttemptCount = (options: BehaviourTreeOptions) => {\n // Are we dealing with an explicit attempt count or will we be randomly picking an attempt count between the min and max attempt count.\n if (this.attempts !== null) {\n this.targetAttemptCount = this.attempts;\n } else if (this.attemptsMin !== null && this.attemptsMax !== null) {\n // We will be picking a random attempt count between a min and max attempt count, if the optional 'random'\n // behaviour tree function option is defined then we will be using that, otherwise we will fall back to using Math.random.\n const random = typeof options.random === \"function\" ? options.random : Math.random;\n\n // Pick a random attempt count between a min and max attempt count.\n this.targetAttemptCount = Math.floor(\n random() * (this.attemptsMax - this.attemptsMin + 1) + this.attemptsMin\n );\n } else {\n this.targetAttemptCount = null;\n }\n };\n}\n", "import Node from \"../Node\";\nimport Decorator from \"./Decorator\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A Root node.\n * The root node will have a single child.\n */\nexport default class Root extends Decorator {\n /**\n * @param attributes The node attributes.\n * @param child The child node.\n */\n constructor(attributes: Attribute[], child: Node) {\n super(\"root\", attributes, child);\n }\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // If the child has never been updated or is running then we will need to update it now.\n if (this.child.getState() === State.READY || this.child.getState() === State.RUNNING) {\n // Update the child of this node.\n this.child.update(agent, options);\n }\n\n // The state of the root node is the state of its child.\n this.setState(this.child.getState());\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => \"ROOT\";\n}\n", "import Node from \"../Node\";\nimport Decorator from \"./Decorator\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A Succeed node.\n * This node wraps a single child and will always move to the 'SUCCEEDED' state when the child moves to a 'SUCCEEDED' or 'FAILED' state.\n */\nexport default class Succeed extends Decorator {\n /**\n * @param attributes The node attributes.\n * @param child The child node.\n */\n constructor(attributes: Attribute[], child: Node) {\n super(\"succeed\", attributes, child);\n }\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // If the child has never been updated or is running then we will need to update it now.\n if (this.child.getState() === State.READY || this.child.getState() === State.RUNNING) {\n this.child.update(agent, options);\n }\n\n // The state of this node will depend in the state of its child.\n switch (this.child.getState()) {\n case State.RUNNING:\n this.setState(State.RUNNING);\n break;\n\n case State.SUCCEEDED:\n case State.FAILED:\n this.setState(State.SUCCEEDED);\n break;\n\n default:\n this.setState(State.READY);\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => \"SUCCEED\";\n}\n", "import Node from \"../Node\";\n\n/**\n * A leaf node.\n */\nexport default abstract class Leaf extends Node {\n /**\n * Gets whether this node is a leaf node.\n */\n isLeafNode = () => true;\n}\n", "import { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\nimport State, { CompleteState } from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Leaf from \"./Leaf\";\nimport Lookup from \"../../Lookup\";\nimport Attribute from \"../../attributes/Attribute\";\n\n/**\n * An Action leaf node.\n * This represents an immediate or ongoing state of behaviour.\n */\nexport default class Action extends Leaf {\n /**\n * @param attributes The node attributes.\n * @param actionName The action name.\n * @param actionArguments The array of action argument definitions.\n */\n constructor(attributes: Attribute[], private actionName: string, private actionArguments: any[]) {\n super(\"action\", attributes, actionArguments);\n }\n\n /**\n * Whether there is a pending update promise.\n */\n private isUsingUpdatePromise = false;\n\n /**\n * The finished state result of an update promise.\n */\n private updatePromiseStateResult: CompleteState | null = null;\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // If the result of this action depends on an update promise then there is nothing to do until\n // it resolves, unless there has been a value set as a result of the update promise resolving.\n if (this.isUsingUpdatePromise) {\n // Check whether the update promise has resolved with a state value.\n if (this.updatePromiseStateResult) {\n // Set the state of this node to match the state returned by the promise.\n this.setState(this.updatePromiseStateResult);\n }\n\n return;\n }\n\n // Attempt to get the invoker for the action function.\n const actionFuncInvoker = Lookup.getFuncInvoker(agent, this.actionName);\n\n // The action function should be defined.\n if (actionFuncInvoker === null) {\n throw new Error(\n `cannot update action node as the action '${this.actionName}' function is not defined on the agent and has not been registered`\n );\n }\n\n // Call the action function, the result of which may be:\n // - The finished state of this action node.\n // - A promise to return a finished node state.\n // - Undefined if the node should remain in the running state.\n const updateResult = actionFuncInvoker(this.actionArguments) as CompleteState | Promise;\n\n if (updateResult instanceof Promise) {\n updateResult.then(\n (result) => {\n // If 'isUpdatePromisePending' is null then the promise was cleared as it was resolving, probably via an abort of reset.\n if (!this.isUsingUpdatePromise) {\n return;\n }\n\n // Check to make sure the result is a valid finished state.\n if (result !== State.SUCCEEDED && result !== State.FAILED) {\n throw new Error(\n \"action node promise resolved with an invalid value, expected a State.SUCCEEDED or State.FAILED value to be returned\"\n );\n }\n\n // Set pending update promise state result to be processed on next update.\n this.updatePromiseStateResult = result;\n },\n (reason) => {\n // If 'isUpdatePromisePending' is null then the promise was cleared as it was resolving, probably via an abort of reset.\n if (!this.isUsingUpdatePromise) {\n return;\n }\n\n // Just throw whatever was returned as the rejection argument.\n throw new Error(reason);\n }\n );\n\n // This node will be in the 'RUNNING' state until the update promise resolves.\n this.setState(State.RUNNING);\n\n // We are now waiting for the promise returned by the use to resolve before we know what state this node is in.\n this.isUsingUpdatePromise = true;\n } else {\n // Validate the returned value.\n this.validateUpdateResult(updateResult);\n\n // Set the state of this node, this may be undefined, which just means that the node is still in the 'RUNNING' state.\n this.setState(updateResult || State.RUNNING);\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => this.actionName;\n\n /**\n * Reset the state of the node.\n */\n reset = () => {\n // Reset the state of this node.\n this.setState(State.READY);\n\n // There is no longer an update promise that we care about.\n this.isUsingUpdatePromise = false;\n this.updatePromiseStateResult = null;\n };\n\n /**\n * Validate the result of an update function call.\n * @param result The result of an update function call.\n */\n private validateUpdateResult = (result: CompleteState | boolean) => {\n switch (result) {\n case State.SUCCEEDED:\n case State.FAILED:\n case undefined:\n return;\n default:\n throw new Error(\n `action '${this.actionName}' 'onUpdate' returned an invalid response, expected an optional State.SUCCEEDED or State.FAILED value to be returned`\n );\n }\n };\n}\n", "import { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Leaf from \"./Leaf\";\nimport Lookup from \"../../Lookup\";\nimport Attribute from \"../../attributes/Attribute\";\n\n/**\n * A Condition leaf node.\n * This will succeed or fail immediately based on an agent predicate, without moving to the 'RUNNING' state.\n */\nexport default class Condition extends Leaf {\n /**\n * @param attributes The node attributes.\n * @param conditionName The name of the condition function.\n * @param conditionArguments The array of condition argument definitions.\n */\n constructor(attributes: Attribute[], private conditionName: string, private conditionArguments: any[]) {\n super(\"condition\", attributes, conditionArguments);\n }\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // Attempt to get the invoker for the condition function.\n const conditionFuncInvoker = Lookup.getFuncInvoker(agent, this.conditionName);\n\n // The condition function should be defined.\n if (conditionFuncInvoker === null) {\n throw new Error(\n `cannot update condition node as the condition '${this.conditionName}' function is not defined on the agent and has not been registered`\n );\n }\n\n // Call the condition function to determine the state of this node.\n this.setState(!!conditionFuncInvoker(this.conditionArguments) ? State.SUCCEEDED : State.FAILED);\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => this.conditionName;\n}\n", "import Leaf from \"./Leaf\";\nimport State from \"../../State\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { Agent } from \"../../Agent\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A WAIT node.\n * The state of this node will change to SUCCEEDED after a duration of time\n */\nexport default class Wait extends Leaf {\n /**\n * @param attributes The node attributes.\n * @param duration The duration that this node will wait to succeed in milliseconds.\n * @param durationMin The minimum possible duration in milliseconds that this node will wait to succeed.\n * @param durationMax The maximum possible duration in milliseconds that this node will wait to succeed.\n */\n constructor(\n attributes: Attribute[],\n private duration: number | null,\n private durationMin: number | null,\n private durationMax: number | null\n ) {\n super(\"wait\", attributes, []);\n }\n\n /**\n * The time in milliseconds at which this node was first updated.\n */\n private initialUpdateTime: number = 0;\n\n /**\n * The total duration in milliseconds that this node will be waiting for.\n */\n private totalDuration: number | null = null;\n\n /**\n * The duration in milliseconds that this node has been waiting for.\n */\n private waitedDuration: number = 0;\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // If this node is in the READY state then we need to set the initial update time.\n if (this.is(State.READY)) {\n // Set the initial update time.\n this.initialUpdateTime = new Date().getTime();\n\n // Set the initial waited duration.\n this.waitedDuration = 0;\n\n // Are we dealing with an explicit duration or will we be randomly picking a duration between the min and max duration.\n if (this.duration !== null) {\n this.totalDuration = this.duration;\n } else if (this.durationMin !== null && this.durationMax !== null) {\n // We will be picking a random duration between a min and max duration, if the optional 'random' behaviour tree\n // function option is defined then we will be using that, otherwise we will fall back to using Math.random.\n const random = typeof options.random === \"function\" ? options.random : Math.random;\n\n // Pick a random duration between a min and max duration.\n this.totalDuration = Math.floor(\n random() * (this.durationMax - this.durationMin + 1) + this.durationMin\n );\n } else {\n this.totalDuration = null;\n }\n\n // The node is now running until we finish waiting.\n this.setState(State.RUNNING);\n }\n\n // If we have no total duration then this wait node will wait indefinitely until it is aborted.\n if (this.totalDuration === null) {\n return;\n }\n\n // If we have a 'getDeltaTime' function defined as part of our options then we will use it to figure out how long we have waited for.\n if (typeof options.getDeltaTime === \"function\") {\n // Get the delta time.\n const deltaTime = options.getDeltaTime();\n\n // Our delta time must be a valid number and cannot be NaN.\n if (typeof deltaTime !== \"number\" || isNaN(deltaTime)) {\n throw new Error(\"The delta time must be a valid number and not NaN.\");\n }\n\n // Update the amount of time that this node has been waiting for based on the delta time.\n this.waitedDuration += deltaTime * 1000;\n } else {\n // We are not using a delta time, so we will just work out hom much time has passed since the first update.\n this.waitedDuration = new Date().getTime() - this.initialUpdateTime;\n }\n\n // Have we waited long enough?\n if (this.waitedDuration >= this.totalDuration) {\n // We have finished waiting!\n this.setState(State.SUCCEEDED);\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => {\n if (this.duration !== null) {\n return `WAIT ${this.duration}ms`;\n } else if (this.durationMin !== null && this.durationMax !== null) {\n return `WAIT ${this.durationMin}ms-${this.durationMax}ms`;\n } else {\n return \"WAIT\";\n }\n };\n}\n", "import Guard from \"./guards/Guard\";\n\nexport type AttributeDetails = {\n /** The attribute type. */\n type: string;\n\n /** The attribute arguments. */\n args: any[];\n};\n\n/**\n * A base node attribute.\n */\nexport default abstract class Attribute {\n /**\n * @param type The node attribute type.\n * @param args The array of attribute arguments.\n */\n constructor(public type: string, public args: any[]) {}\n\n /**\n * Gets the attribute details.\n */\n abstract getDetails(): TAttributeDetails;\n\n /**\n * Gets whether this attribute is a guard.\n */\n abstract isGuard: () => this is Guard;\n}\n", "import { Agent } from \"../../Agent\";\nimport Attribute, { AttributeDetails } from \"../Attribute\";\n\nexport type GuardAttributeDetails = {\n /** The name of the condition function that determines whether the guard is satisfied. */\n condition: string;\n} & AttributeDetails;\n\n/**\n * A base node guard attribute.\n */\nexport default abstract class Guard extends Attribute {\n /**\n * @param type The node attribute type.\n * @param args The array of decorator argument definitions.\n * @param condition The name of the condition function that determines whether the guard is satisfied.\n */\n constructor(type: string, args: any[], private condition: string) {\n super(type, args);\n }\n\n /**\n * Gets the name of the condition function that determines whether the guard is satisfied.\n */\n getCondition = () => this.condition;\n\n /**\n * Gets whether this attribute is a guard.\n */\n isGuard = () => true;\n\n /**\n * Gets the attribute details.\n */\n getDetails(): GuardAttributeDetails {\n return {\n type: this.type,\n args: this.args,\n condition: this.getCondition()\n };\n }\n\n /**\n * Gets whether the guard is satisfied.\n * @param agent The agent.\n * @returns Whether the guard is satisfied.\n */\n abstract isSatisfied(agent: Agent): boolean;\n}\n", "import Guard from \"./Guard\";\nimport Lookup from \"../../Lookup\";\nimport { Agent } from \"../../Agent\";\n\n/**\n * A WHILE guard which is satisfied as long as the given condition remains true.\n */\nexport default class While extends Guard {\n /**\n * @param condition The name of the condition function that determines whether the guard is satisfied.\n * @param args The array of decorator argument definitions.\n */\n constructor(condition: string, args: any[]) {\n super(\"while\", args, condition);\n }\n\n /**\n * Gets whether the guard is satisfied.\n * @param agent The agent.\n * @returns Whether the guard is satisfied.\n */\n isSatisfied = (agent: Agent) => {\n // Attempt to get the invoker for the condition function.\n const conditionFuncInvoker = Lookup.getFuncInvoker(agent, this.getCondition());\n\n // The condition function should be defined.\n if (conditionFuncInvoker === null) {\n throw new Error(\n `cannot evaluate node guard as the condition '${this.getCondition()}' function is not defined on the agent and has not been registered`\n );\n }\n\n // Call the condition function to determine whether this guard is satisfied.\n return !!conditionFuncInvoker(this.args);\n };\n}\n", "import Guard from \"./Guard\";\nimport Lookup from \"../../Lookup\";\nimport { Agent } from \"../../Agent\";\n\n/**\n * An UNTIL guard which is satisfied as long as the given condition remains false.\n */\nexport default class Until extends Guard {\n /**\n * @param condition The name of the condition function that determines whether the guard is satisfied.\n * @param args The array of decorator argument definitions.\n */\n constructor(condition: string, args: any[]) {\n super(\"until\", args, condition);\n }\n\n /**\n * Gets whether the guard is satisfied.\n * @param agent The agent.\n * @returns Whether the guard is satisfied.\n */\n isSatisfied = (agent: Agent) => {\n // Attempt to get the invoker for the condition function.\n const conditionFuncInvoker = Lookup.getFuncInvoker(agent, this.getCondition());\n\n // The condition function should be defined.\n if (conditionFuncInvoker === null) {\n throw new Error(\n `cannot evaluate node guard as the condition '${this.getCondition()}' function is not defined on the agent and has not been registered`\n );\n }\n\n // Call the condition function to determine whether this guard is satisfied.\n return !!!conditionFuncInvoker(this.args);\n };\n}\n", "import { Agent } from \"../../Agent\";\nimport Attribute, { AttributeDetails } from \"../Attribute\";\n\nexport type CallbackAttributeDetails = {\n /** The name of the agent function that is called. */\n functionName: string;\n} & AttributeDetails;\n\n/**\n * A base node callback attribute.\n */\nexport default abstract class Callback extends Attribute {\n /**\n * @param type The node attribute type.\n * @param args The array of decorator argument definitions.\n * @param functionName The name of the agent function to call.\n */\n constructor(type: string, args: any[], private functionName: string) {\n super(type, args);\n }\n\n /**\n * Gets the name of the agent function to call.\n */\n getFunctionName = () => this.functionName;\n\n /**\n * Gets whether this attribute is a guard.\n */\n isGuard = () => false;\n\n /**\n * Gets the attribute details.\n */\n getDetails(): CallbackAttributeDetails {\n return {\n type: this.type,\n args: this.args,\n functionName: this.getFunctionName()\n };\n }\n\n /**\n * Attempt to call the agent function that this callback refers to.\n * @param agent The agent.\n */\n abstract callAgentFunction: (agent: Agent, isSuccess: boolean, isAborted: boolean) => void;\n}\n", "import Callback from \"./Callback\";\nimport Lookup from \"../../Lookup\";\nimport { Agent } from \"../../Agent\";\n\n/**\n * An ENTRY callback which defines an agent function to call when the associated node is updated and moves out of running state.\n */\nexport default class Entry extends Callback {\n /**\n * @param functionName The name of the agent function to call.\n * @param args The array of callback argument definitions.\n */\n constructor(functionName: string, args: any[]) {\n super(\"entry\", args, functionName);\n }\n\n /**\n * Attempt to call the agent function that this callback refers to.\n * @param agent The agent.\n */\n callAgentFunction = (agent: Agent) => {\n // Attempt to get the invoker for the callback function.\n const callbackFuncInvoker = Lookup.getFuncInvoker(agent, this.getFunctionName());\n\n // The callback function should be defined.\n if (callbackFuncInvoker === null) {\n throw new Error(\n `cannot call entry function '${this.getFunctionName()}' as is not defined on the agent and has not been registered`\n );\n }\n\n // Call the callback function.\n callbackFuncInvoker(this.args);\n };\n}\n", "import Callback from \"./Callback\";\nimport Lookup from \"../../Lookup\";\nimport { Agent } from \"../../Agent\";\n\n/**\n * A STEP callback which defines an agent function to call when the associated node is updated.\n */\nexport default class Step extends Callback {\n /**\n * @param functionName The name of the agent function to call.\n * @param args The array of callback argument definitions.\n */\n constructor(functionName: string, args: any[]) {\n super(\"step\", args, functionName);\n }\n\n /**\n * Attempt to call the agent function that this callback refers to.\n * @param agent The agent.\n */\n callAgentFunction = (agent: Agent) => {\n // Attempt to get the invoker for the callback function.\n const callbackFuncInvoker = Lookup.getFuncInvoker(agent, this.getFunctionName());\n\n // The callback function should be defined.\n if (callbackFuncInvoker === null) {\n throw new Error(\n `cannot call step function '${this.getFunctionName()}' as is not defined on the agent and has not been registered`\n );\n }\n\n // Call the callback function.\n callbackFuncInvoker(this.args);\n };\n}\n", "import Callback from \"./Callback\";\nimport Lookup from \"../../Lookup\";\nimport { Agent } from \"../../Agent\";\n\n/**\n * An EXIT callback which defines an agent function to call when the associated node is updated and moves to a finished state or is aborted.\n */\nexport default class Exit extends Callback {\n /**\n * @param functionName The name of the agent function to call.\n * @param args The array of callback argument definitions.\n */\n constructor(functionName: string, args: any[]) {\n super(\"exit\", args, functionName);\n }\n\n /**\n * Attempt to call the agent function that this callback refers to.\n * @param agent The agent.\n * @param isSuccess Whether the decorated node was left with a success state.\n * @param isAborted Whether the decorated node was aborted.\n */\n callAgentFunction = (agent: Agent, isSuccess: boolean, isAborted: boolean) => {\n // Attempt to get the invoker for the callback function.\n const callbackFuncInvoker = Lookup.getFuncInvoker(agent, this.getFunctionName());\n\n // The callback function should be defined.\n if (callbackFuncInvoker === null) {\n throw new Error(\n `cannot call exit function '${this.getFunctionName()}' as is not defined on the agent and has not been registered`\n );\n }\n\n // Call the callback function\n callbackFuncInvoker([{ value: { succeeded: isSuccess, aborted: isAborted } }, ...this.args]);\n };\n}\n", "import { AnyNodeDefinition, RootNodeDefinition } from \"./BehaviourTreeDefinition\";\nimport GuardPath, { GuardPathPart } from \"./attributes/guards/GuardPath\";\nimport { validateBranchSubtreeLinks } from \"./BehaviourTreeDefinitionValidator\";\nimport { isInteger } from \"./BehaviourTreeDefinitionUtilities\";\nimport Node from \"./nodes/Node\";\nimport Composite from \"./nodes/composite/Composite\";\nimport Decorator from \"./nodes/decorator/Decorator\";\nimport Parallel from \"./nodes/composite/Parallel\";\nimport Selector from \"./nodes/composite/Selector\";\nimport Sequence from \"./nodes/composite/Sequence\";\nimport Lotto from \"./nodes/composite/Lotto\";\nimport Fail from \"./nodes/decorator/Fail\";\nimport Flip from \"./nodes/decorator/Flip\";\nimport Repeat from \"./nodes/decorator/Repeat\";\nimport Retry from \"./nodes/decorator/Retry\";\nimport Root from \"./nodes/decorator/Root\";\nimport Succeed from \"./nodes/decorator/Succeed\";\nimport Action from \"./nodes/leaf/Action\";\nimport Condition from \"./nodes/leaf/Condition\";\nimport Wait from \"./nodes/leaf/Wait\";\nimport Lookup from \"./Lookup\";\nimport Attribute from \"./attributes/Attribute\";\nimport While from \"./attributes/guards/While\";\nimport Until from \"./attributes/guards/Until\";\nimport Entry from \"./attributes/callbacks/Entry\";\nimport Step from \"./attributes/callbacks/Step\";\nimport Exit from \"./attributes/callbacks/Exit\";\n\n/**\n * A type representing any node instance in a behaviour tree.\n */\ntype AnyNode =\n | Root\n | Action\n | Condition\n | Wait\n | Sequence\n | Selector\n | Lotto\n | Parallel\n | Repeat\n | Retry\n | Flip\n | Succeed\n | Fail;\n\n/**\n * A type defining a mapping of root node identifiers to root node definitions.\n */\ntype RootNodeDefinitionMap = { [key: string | symbol]: RootNodeDefinition };\n\n/**\n * A symbol to use as the main root key in any root node mappings.\n */\nconst MAIN_ROOT_NODE_KEY = Symbol(\"__root__\");\n\n/**\n * Build and populate the root nodes based on the provided definition, assuming that the definition has been validated.\n * @param definition The root node definitions.\n * @returns The built and populated root node definitions.\n */\nexport default function buildRootNode(definition: RootNodeDefinition[]): Root {\n // Create a mapping of root node identifers to root node definitions, including globally registered subtree root node definitions.\n const rootNodeDefinitionMap = createRootNodeDefinitionMap(definition);\n\n // Now that we have all of our root node definitons (those part of the tree definition and those globally\n // registered) we should validate the definition. This will also double-check that we dont have any circular\n // dependencies in our branch -> subtree references and that we have no broken branch -> subtree links.\n validateBranchSubtreeLinks(definition, true);\n\n // Create our populated tree of node instances, starting with our main root node.\n const rootNode = nodeFactory(rootNodeDefinitionMap[MAIN_ROOT_NODE_KEY], rootNodeDefinitionMap) as Root;\n\n // Set a guard path on every leaf of the tree to evaluate as part of each update.\n applyLeafNodeGuardPaths(rootNode);\n\n // We only need to return the main root node.\n return rootNode;\n}\n\n/**\n * A factory function which creates a node instance based on the specified definition.\n * @param definition The node definition.\n * @param rootNodeDefinitionMap The mapping of root node identifers to root node definitions, including globally registered subtree root node definitions.\n * @returns A node instance based on the specified definition.\n */\nfunction nodeFactory(definition: AnyNodeDefinition, rootNodeDefinitionMap: RootNodeDefinitionMap): AnyNode {\n // Get the attributes for the node.\n const attributes = nodeAttributesFactory(definition);\n\n // Create the node instance based on the definition type.\n switch (definition.type) {\n case \"root\":\n return new Root(attributes, nodeFactory(definition.child, rootNodeDefinitionMap));\n\n case \"repeat\":\n let iterations: number | null = null;\n let iterationsMin: number | null = null;\n let iterationsMax: number | null = null;\n\n if (Array.isArray(definition.iterations)) {\n iterationsMin = definition.iterations[0];\n iterationsMax = definition.iterations[1];\n } else if (isInteger(definition.iterations)) {\n iterations = definition.iterations!;\n }\n\n return new Repeat(\n attributes,\n iterations,\n iterationsMin,\n iterationsMax,\n nodeFactory(definition.child, rootNodeDefinitionMap)\n );\n\n case \"retry\":\n let attempts: number | null = null;\n let attemptsMin: number | null = null;\n let attemptsMax: number | null = null;\n\n if (Array.isArray(definition.attempts)) {\n attemptsMin = definition.attempts[0];\n attemptsMax = definition.attempts[1];\n } else if (isInteger(definition.attempts)) {\n attempts = definition.attempts!;\n }\n\n return new Retry(\n attributes,\n attempts,\n attemptsMin,\n attemptsMax,\n nodeFactory(definition.child, rootNodeDefinitionMap)\n );\n\n case \"flip\":\n return new Flip(attributes, nodeFactory(definition.child, rootNodeDefinitionMap));\n\n case \"succeed\":\n return new Succeed(attributes, nodeFactory(definition.child, rootNodeDefinitionMap));\n\n case \"fail\":\n return new Fail(attributes, nodeFactory(definition.child, rootNodeDefinitionMap));\n\n case \"sequence\":\n return new Sequence(\n attributes,\n definition.children.map((child) => nodeFactory(child, rootNodeDefinitionMap))\n );\n\n case \"selector\":\n return new Selector(\n attributes,\n definition.children.map((child) => nodeFactory(child, rootNodeDefinitionMap))\n );\n\n case \"parallel\":\n return new Parallel(\n attributes,\n definition.children.map((child) => nodeFactory(child, rootNodeDefinitionMap))\n );\n\n case \"lotto\":\n return new Lotto(\n attributes,\n definition.weights,\n definition.children.map((child) => nodeFactory(child, rootNodeDefinitionMap))\n );\n\n case \"branch\":\n return nodeFactory(rootNodeDefinitionMap[definition.ref].child, rootNodeDefinitionMap);\n\n case \"action\":\n return new Action(attributes, definition.call, definition.args || []);\n\n case \"condition\":\n return new Condition(attributes, definition.call, definition.args || []);\n\n case \"wait\":\n let duration: number | null = null;\n let durationMin: number | null = null;\n let durationMax: number | null = null;\n\n if (Array.isArray(definition.duration)) {\n durationMin = definition.duration[0];\n durationMax = definition.duration[1];\n } else if (isInteger(definition.duration)) {\n duration = definition.duration!;\n }\n\n return new Wait(attributes, duration, durationMin, durationMax);\n }\n}\n\n/**\n * Creates an array of node attribute instances based on the specified node definition.\n * @param definition The node definition.\n * @returns An array of node attribute instances based on the specified node definition.\n */\nfunction nodeAttributesFactory(definition: AnyNodeDefinition): Attribute[] {\n const attributes: Attribute[] = [];\n\n if (definition.while) {\n attributes.push(new While(definition.while.call, definition.while.args ?? []));\n }\n\n if (definition.until) {\n attributes.push(new Until(definition.until.call, definition.until.args ?? []));\n }\n\n if (definition.entry) {\n attributes.push(new Entry(definition.entry.call, definition.entry.args ?? []));\n }\n\n if (definition.step) {\n attributes.push(new Step(definition.step.call, definition.step.args ?? []));\n }\n\n if (definition.exit) {\n attributes.push(new Exit(definition.exit.call, definition.exit.args ?? []));\n }\n\n return attributes;\n}\n\n/**\n * Creates a mapping of root node identifers to root node definitions, mixing in globally registered subtree root node definitions.\n * @param definition The root node definitions.\n * @returns A mapping of root node identifers to root node definitions, including globally registered subtree root node definitions.\n */\nfunction createRootNodeDefinitionMap(definition: RootNodeDefinition[]): RootNodeDefinitionMap {\n // Create a mapping of root node identifers to root node definitions.\n const rootNodeMap: RootNodeDefinitionMap = {};\n\n // Add in any registered subtree root node definitions.\n for (const [name, rootNodeDefinition] of Object.entries(Lookup.getSubtrees())) {\n // The name used when registering the subtree will be used as the root node identifier.\n rootNodeMap[name] = { ...rootNodeDefinition, id: name };\n }\n\n // Populate the map with the root node definitions that were included with the tree definition.\n // We do this after adding any registered subtrees as we want these to take presedence.\n for (const rootNodeDefinition of definition) {\n rootNodeMap[rootNodeDefinition.id ?? MAIN_ROOT_NODE_KEY] = rootNodeDefinition;\n }\n\n return rootNodeMap;\n}\n\n/**\n * Applies a guard path to every leaf of the tree to evaluate as part of each update.\n * @param root The main root tree node.\n */\nfunction applyLeafNodeGuardPaths(root: Root) {\n const nodePaths: Node[][] = [];\n\n const findLeafNodes = (path: Node[], node: Node) => {\n // Add the current node to the path.\n path = path.concat(node);\n\n // Check whether the current node is a leaf node.\n if (node.isLeafNode()) {\n nodePaths.push(path);\n } else {\n (node as Composite | Decorator).getChildren().forEach((child) => findLeafNodes(path, child));\n }\n };\n\n // Find all leaf node paths, starting from the root.\n findLeafNodes([], root);\n\n nodePaths.forEach((path) => {\n // Each node in the current path will have to be assigned a guard path, working from the root outwards.\n for (let depth = 0; depth < path.length; depth++) {\n // Get the node in the path at the current depth.\n const currentNode = path[depth];\n\n // The node may already have been assigned a guard path, if so just skip it.\n if (currentNode.hasGuardPath()) {\n continue;\n }\n\n // Create the guard path for the current node.\n const guardPath = new GuardPath(\n path\n .slice(0, depth + 1)\n .map((node) => ({ node, guards: node.getGuardAttributes() }))\n .filter((details) => details.guards.length > 0)\n );\n\n // Assign the guard path to the current node.\n currentNode.setGuardPath(guardPath);\n }\n });\n}\n", "import State, { AnyState } from \"./State\";\nimport Lookup from \"./Lookup\";\nimport Node from \"./nodes/Node\";\nimport Root from \"./nodes/decorator/Root\";\nimport Composite from \"./nodes/composite/Composite\";\nimport Decorator from \"./nodes/decorator/Decorator\";\nimport { Agent, GlobalFunction } from \"./Agent\";\nimport { CallbackAttributeDetails } from \"./attributes/callbacks/Callback\";\nimport { GuardAttributeDetails } from \"./attributes/guards/Guard\";\nimport { BehaviourTreeOptions } from \"./BehaviourTreeOptions\";\nimport { convertMDSLToJSON } from \"./mdsl/MDSLDefinitionParser\";\nimport { RootNodeDefinition } from \"./BehaviourTreeDefinition\";\nimport { validateDefinition, validateJSONDefinition } from \"./BehaviourTreeDefinitionValidator\";\nimport buildRootNode from \"./BehaviourTreeBuilder\";\nimport { isNullOrUndefined } from \"./BehaviourTreeDefinitionUtilities\";\n\n// Purely for outside inspection of the tree.\nexport type FlattenedTreeNode = {\n id: string;\n type: string;\n caption: string;\n state: AnyState;\n guards: GuardAttributeDetails[];\n callbacks: CallbackAttributeDetails[];\n args: any[];\n parentId: string | null;\n};\n\n/**\n * A representation of a behaviour tree.\n */\nexport class BehaviourTree {\n /**\n * The main root tree node.\n */\n public readonly rootNode: Root;\n\n /**\n * Creates a new instance of the BehaviourTree class.\n * @param definition The behaviour tree definition.\n * @param agent The agent instance that this behaviour tree is modelling behaviour for.\n * @param options The behaviour tree options object.\n */\n constructor(\n definition: string | RootNodeDefinition | RootNodeDefinition[],\n private agent: Agent,\n private options: BehaviourTreeOptions = {}\n ) {\n // The tree definition must be defined.\n if (isNullOrUndefined(definition)) {\n throw new Error(\"tree definition not defined\");\n }\n\n // The agent must be defined and not null.\n if (typeof agent !== \"object\" || agent === null) {\n throw new Error(\"the agent must be an object and not null\");\n }\n\n // We should validate the definition before we try to build the tree nodes.\n const { succeeded, errorMessage } = validateDefinition(definition);\n\n // Did our validation fail without error?\n if (!succeeded) {\n throw new Error(`invalid definition: ${errorMessage}`);\n }\n\n try {\n // Parse the behaviour tree definition, create the populated tree of behaviour tree nodes, and get the root.\n this.rootNode = this._createRootNode(definition);\n } catch (exception) {\n // There was an issue in trying build and populate the behaviour tree.\n throw new Error(`error building tree: ${(exception as Error).message}`);\n }\n }\n\n /**\n * Gets whether the tree is in the RUNNING state.\n * @returns true if the tree is in the RUNNING state, otherwise false.\n */\n isRunning() {\n return this.rootNode.getState() === State.RUNNING;\n }\n\n /**\n * Gets the current tree state of SUCCEEDED, FAILED, READY or RUNNING.\n * @returns The current tree state.\n */\n getState() {\n return this.rootNode.getState();\n }\n\n /**\n * Step the tree.\n * 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.\n * 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\n * 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.\n *\n * 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.\n */\n step() {\n // If the root node has already been stepped to completion then we need to reset it.\n if (this.rootNode.getState() === State.SUCCEEDED || this.rootNode.getState() === State.FAILED) {\n this.rootNode.reset();\n }\n\n try {\n this.rootNode.update(this.agent, this.options);\n } catch (exception) {\n throw new Error(`error stepping tree: ${(exception as Error).message}`);\n }\n }\n\n /**\n * Resets the tree from the root node outwards to each nested node, giving each a state of READY.\n */\n reset() {\n this.rootNode.reset();\n }\n\n /**\n * Gets the flattened details of every node in the tree.\n * @returns The flattened details of every node in the tree.\n */\n getFlattenedNodeDetails(): FlattenedTreeNode[] {\n // Create an empty flattened array of tree nodes.\n const flattenedTreeNodes: FlattenedTreeNode[] = [];\n\n /**\n * Helper function to process a node instance and push details into the flattened tree nodes array.\n * @param node The current node.\n * @param parentUid The UID of the node parent, or null if the node is the main root node.\n */\n const processNode = (node: Node, parentUid: string | null) => {\n // Get the guard and callback attribute details for this node.\n const guards = node\n .getAttributes()\n .filter((attribute) => attribute.isGuard())\n .map((attribute) => attribute.getDetails()) as GuardAttributeDetails[];\n const callbacks = node\n .getAttributes()\n .filter((attribute) => !attribute.isGuard())\n .map((attribute) => attribute.getDetails()) as CallbackAttributeDetails[];\n\n // Push the current node into the flattened nodes array.\n flattenedTreeNodes.push({\n id: node.getUid(),\n type: node.getType(),\n caption: node.getName(),\n state: node.getState(),\n guards,\n callbacks,\n args: node.getArguments(),\n parentId: parentUid\n });\n\n // Process each of the nodes children if it is not a leaf node.\n if (!node.isLeafNode()) {\n (node as Composite | Decorator)\n .getChildren()\n .forEach((child) => processNode(child, (node as Composite | Decorator).getUid()));\n }\n };\n\n // Convert the nested node structure into a flattened array of node details.\n processNode(this.rootNode, null);\n\n return flattenedTreeNodes;\n }\n\n /**\n * Registers the action/condition/guard/callback function or subtree with the given name.\n * @param name The name of the function or subtree to register.\n * @param value The function or subtree definition to register.\n */\n static register(name: string, value: GlobalFunction | string | RootNodeDefinition) {\n // Are we going to register a action/condition/guard/callback function?\n if (typeof value === \"function\") {\n Lookup.setFunc(name, value);\n return;\n }\n\n // We are not registering an action/condition/guard/callback function, so we must be registering a subtree.\n if (typeof value === \"string\") {\n let rootNodeDefinitions: RootNodeDefinition[];\n\n // We will assume that any string passed in will be a mdsl definition.\n try {\n rootNodeDefinitions = convertMDSLToJSON(value);\n } catch (exception) {\n throw new Error(`error registering definition, invalid MDSL: ${(exception as Error).message}`);\n }\n\n // This function should only ever be called with a definition containing a single unnamed root node.\n if (rootNodeDefinitions.length != 1 || rootNodeDefinitions[0].id !== null) {\n throw new Error(\"error registering definition: expected a single unnamed root node\");\n }\n\n try {\n // We should validate the subtree as we don't want invalid subtrees available via the lookup.\n const { succeeded, errorMessage } = validateJSONDefinition(rootNodeDefinitions[0]);\n\n // Did our validation fail without error?\n if (!succeeded) {\n throw new Error(errorMessage);\n }\n } catch (exception) {\n throw new Error(`error registering definition: ${(exception as Error).message}`);\n }\n\n // Everything seems hunky-dory, register the subtree.\n Lookup.setSubtree(name, rootNodeDefinitions[0]);\n } else if (typeof value === \"object\" && !Array.isArray(value)) {\n // We will assume that any object passed in is a root node definition.\n\n try {\n // We should validate the subtree as we don't want invalid subtrees available via the lookup.\n const { succeeded, errorMessage } = validateJSONDefinition(value);\n\n // Did our validation fail without error?\n if (!succeeded) {\n throw new Error(errorMessage);\n }\n } catch (exception) {\n throw new Error(`error registering definition: ${(exception as Error).message}`);\n }\n\n // Everything seems hunky-dory, register the subtree.\n Lookup.setSubtree(name, value);\n } else {\n throw new Error(\"unexpected value, expected string mdsl definition, root node json definition or function\");\n }\n }\n\n /**\n * Unregisters the registered action/condition/guard/callback function or subtree with the given name.\n * @param name The name of the registered action/condition/guard/callback function or subtree to unregister.\n */\n static unregister(name: string): void {\n Lookup.remove(name);\n }\n\n /**\n * Unregister all registered action/condition/guard/callback functions and subtrees.\n */\n static unregisterAll(): void {\n Lookup.empty();\n }\n\n /**\n * Parses a behaviour tree definition and creates a tree of behaviour tree nodes populated at a root.\n * @param {string | RootNodeDefinition | RootNodeDefinition[]} definition The behaviour tree definition.\n * @returns The root behaviour tree node.\n */\n private _createRootNode(definition: string | RootNodeDefinition | RootNodeDefinition[]): Root {\n // Our definition will have to be converted to JSON if it is a MDSL string.\n // TODO convertMDSLToJSON is called TWICE, once for validation and once here. Maybe return the JSON as part of the validation result?\n const resolvedDefinition = typeof definition === \"string\" ? convertMDSLToJSON(definition) : definition;\n\n // Build and populate the root node.\n return buildRootNode(Array.isArray(resolvedDefinition) ? resolvedDefinition : [resolvedDefinition]);\n }\n}\n"], + "mappings": "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", "names": ["Participant", "isNullOrUndefined", "Lotto", "createLotto", "State", "createLotto"] } diff --git a/package.json b/package.json index edf7641..4f55f1e 100644 --- a/package.json +++ b/package.json @@ -18,9 +18,9 @@ "sinon": "^14.0.1" }, "scripts": { - "build": "npm-run-all build:node build:web build:typecheck", + "build": "npm-run-all build:format build:node build:web build:typecheck", "watch": "npm run build:node -- --watch", - "test": "npm-run-all build:format build test:unit-test", + "test": "npm-run-all build test:unit-test", "build:format": "prettier --write \"src/**/*.ts\" \"test/**/*.js\"", "build:node": "esbuild ./src/index.js --bundle --sourcemap --outdir=dist --platform=node", "build:web": "esbuild ./src/index.js --bundle --sourcemap --platform=browser --global-name=mistreevous --outfile=dist/bundle.js", diff --git a/src/BehaviourTree.ts b/src/BehaviourTree.ts index 022d216..b6174f4 100644 --- a/src/BehaviourTree.ts +++ b/src/BehaviourTree.ts @@ -10,7 +10,7 @@ import { GuardAttributeDetails } from "./attributes/guards/Guard"; import { BehaviourTreeOptions } from "./BehaviourTreeOptions"; import { convertMDSLToJSON } from "./mdsl/MDSLDefinitionParser"; import { RootNodeDefinition } from "./BehaviourTreeDefinition"; -import { validateJSONDefinition } from "./BehaviourTreeDefinitionValidator"; +import { validateDefinition, validateJSONDefinition } from "./BehaviourTreeDefinitionValidator"; import buildRootNode from "./BehaviourTreeBuilder"; import { isNullOrUndefined } from "./BehaviourTreeDefinitionUtilities"; @@ -56,6 +56,14 @@ export class BehaviourTree { throw new Error("the agent must be an object and not null"); } + // We should validate the definition before we try to build the tree nodes. + const { succeeded, errorMessage } = validateDefinition(definition); + + // Did our validation fail without error? + if (!succeeded) { + throw new Error(`invalid definition: ${errorMessage}`); + } + try { // Parse the behaviour tree definition, create the populated tree of behaviour tree nodes, and get the root. this.rootNode = this._createRootNode(definition); @@ -244,19 +252,9 @@ export class BehaviourTree { * @returns The root behaviour tree node. */ private _createRootNode(definition: string | RootNodeDefinition | RootNodeDefinition[]): Root { - let resolvedDefinition: RootNodeDefinition | RootNodeDefinition[]; - - // If the definition is a string then we will assume that it is an mdsl string which needs to be converted to a JSON definition. - if (typeof definition === "string") { - try { - resolvedDefinition = convertMDSLToJSON(definition); - } catch (exception) { - throw new Error(`invalid mdsl definition: ${(exception as Error).message}`); - } - } else { - // The definition is not a string, so we should assume that it is already a JSON definition. - resolvedDefinition = definition; - } + // Our definition will have to be converted to JSON if it is a MDSL string. + // TODO convertMDSLToJSON is called TWICE, once for validation and once here. Maybe return the JSON as part of the validation result? + const resolvedDefinition = typeof definition === "string" ? convertMDSLToJSON(definition) : definition; // Build and populate the root node. return buildRootNode(Array.isArray(resolvedDefinition) ? resolvedDefinition : [resolvedDefinition]); diff --git a/src/BehaviourTreeDefinitionValidator.ts b/src/BehaviourTreeDefinitionValidator.ts index 7a5fe3d..6194931 100644 --- a/src/BehaviourTreeDefinitionValidator.ts +++ b/src/BehaviourTreeDefinitionValidator.ts @@ -54,9 +54,9 @@ export function validateMDSLDefinition(definition: string): DefinitionValidation try { // The definition is a string which we can assume is MDSL, so attempt to parse it to a JSON definition in the form of an array of root node definitions. rootNodeDefinitions = convertMDSLToJSON(definition); - } catch (error) { + } catch (exception) { // We failed to parse the JSON from the MDSL, this is likely to be the result of it not being a valid MDSL string. - return createValidationFailureResult(`invalid MDSL: ${error}`); + return createValidationFailureResult((exception as Error).message); } // Unpack all of the root node definitions into arrays of main ('id' defined) and sub ('id' not defined) root node definitions. diff --git a/src/mdsl/MDSLDefinitionParser.ts b/src/mdsl/MDSLDefinitionParser.ts index 03e4337..a0208ca 100644 --- a/src/mdsl/MDSLDefinitionParser.ts +++ b/src/mdsl/MDSLDefinitionParser.ts @@ -669,7 +669,7 @@ function createWaitNode(tokens: string[], stringLiteralPlaceholders: StringLiter nodeArguments .filter((arg) => arg.type !== "number" || !arg.isInteger) .forEach(() => { - throw new Error(`wait node duration arguments must be integer values`); + throw new Error(`wait node durations must be integer values`); }); // We may have: diff --git a/test/BehaviourTreeDefinitionValidator.test.js b/test/BehaviourTreeDefinitionValidator.test.js index 95cd9b7..b1ee0b6 100644 --- a/test/BehaviourTreeDefinitionValidator.test.js +++ b/test/BehaviourTreeDefinitionValidator.test.js @@ -14,11 +14,11 @@ describe("The validateDefinition function takes a tree definition as an argument }; describe("where the type of that definition is", () => { - describe("mdsl", () => { + describe("MDSL", () => { // TODO Add better validation to mdsl parsing to better match the json validation. }); - describe("json", () => { + describe("JSON", () => { describe("returns a validation failure when", () => { it("the definition doesn't contain a main root node (has no root node identifier defined)", () => { const definition = { diff --git a/test/behaviourTree.test.js b/test/behaviourTree.test.js index 89c0f2c..ac78600 100644 --- a/test/behaviourTree.test.js +++ b/test/behaviourTree.test.js @@ -52,101 +52,264 @@ describe("A BehaviourTree instance", () => { }); }); - it("has a 'getState' function that returns the state of the root node", () => { - let actionResult = undefined; + describe("has a 'getState' function that returns the state of the root node", () => { + it("(MDSL)", () => { + let actionResult = undefined; - const definition = "root { action [getActionResult] }"; - const agent = { getActionResult: () => actionResult }; - const tree = new mistreevous.BehaviourTree(definition, agent); + const definition = "root { action [getActionResult] }"; + const agent = { getActionResult: () => actionResult }; + const tree = new mistreevous.BehaviourTree(definition, agent); - assert.strictEqual(tree.getState(), mistreevous.State.READY); + assert.strictEqual(tree.getState(), mistreevous.State.READY); - tree.step(); + tree.step(); - assert.strictEqual(tree.getState(), mistreevous.State.RUNNING); + assert.strictEqual(tree.getState(), mistreevous.State.RUNNING); - actionResult = mistreevous.State.SUCCEEDED; + actionResult = mistreevous.State.SUCCEEDED; - tree.step(); + tree.step(); - assert.strictEqual(tree.getState(), mistreevous.State.SUCCEEDED); + assert.strictEqual(tree.getState(), mistreevous.State.SUCCEEDED); + }); + + it("(JSON)", () => { + let actionResult = undefined; + + const definition = { + type: "root", + child: { + type: "action", + call: "getActionResult" + } + }; + const agent = { getActionResult: () => actionResult }; + const tree = new mistreevous.BehaviourTree(definition, agent); + + assert.strictEqual(tree.getState(), mistreevous.State.READY); + + tree.step(); + + assert.strictEqual(tree.getState(), mistreevous.State.RUNNING); + + actionResult = mistreevous.State.SUCCEEDED; + + tree.step(); + + assert.strictEqual(tree.getState(), mistreevous.State.SUCCEEDED); + }); }); - it("has an 'isRunning' function that returns a flag defining whether the tree is in a running state", () => { - let actionResult = undefined; + describe("has an 'isRunning' function that returns a flag defining whether the tree is in a running state", () => { + it("(MDSL)", () => { + let actionResult = undefined; + + const definition = "root { action [getActionResult] }"; + const agent = { getActionResult: () => actionResult }; + const tree = new mistreevous.BehaviourTree(definition, agent); + + assert.strictEqual(tree.isRunning(), false); + + tree.step(); - const definition = "root { action [getActionResult] }"; - const agent = { getActionResult: () => actionResult }; - const tree = new mistreevous.BehaviourTree(definition, agent); + assert.strictEqual(tree.isRunning(), true); - assert.strictEqual(tree.isRunning(), false); + actionResult = mistreevous.State.SUCCEEDED; - tree.step(); + tree.step(); - assert.strictEqual(tree.isRunning(), true); + assert.strictEqual(tree.isRunning(), false); + }); + + it("(JSON)", () => { + let actionResult = undefined; + + const definition = { + type: "root", + child: { + type: "action", + call: "getActionResult" + } + }; + const agent = { getActionResult: () => actionResult }; + const tree = new mistreevous.BehaviourTree(definition, agent); + + assert.strictEqual(tree.isRunning(), false); - actionResult = mistreevous.State.SUCCEEDED; + tree.step(); - tree.step(); + assert.strictEqual(tree.isRunning(), true); - assert.strictEqual(tree.isRunning(), false); + actionResult = mistreevous.State.SUCCEEDED; + + tree.step(); + + assert.strictEqual(tree.isRunning(), false); + }); }); - it("has a 'reset' function that resets the tree from the root node outwards to each nested node, giving each a state of READY", () => { - const definition = "root { action [getActionResult] }"; - const agent = { getActionResult: () => mistreevous.State.SUCCEEDED }; - const tree = new mistreevous.BehaviourTree(definition, agent); + describe("has a 'reset' function that resets the tree from the root node outwards to each nested node, giving each a state of READY", () => { + it("(MDSL)", () => { + const definition = "root { sequence { action [getActionResult] } }"; + const agent = { getActionResult: () => mistreevous.State.SUCCEEDED }; + const tree = new mistreevous.BehaviourTree(definition, agent); - assert.strictEqual(tree.getState(), mistreevous.State.READY); + assert.strictEqual(findNode(tree, "root", "ROOT").state, mistreevous.State.READY); + assert.strictEqual(findNode(tree, "sequence", "SEQUENCE").state, mistreevous.State.READY); + assert.strictEqual(findNode(tree, "action", "getActionResult").state, mistreevous.State.READY); - tree.step(); + tree.step(); - assert.strictEqual(tree.getState(), mistreevous.State.SUCCEEDED); + assert.strictEqual(findNode(tree, "root", "ROOT").state, mistreevous.State.SUCCEEDED); + assert.strictEqual(findNode(tree, "sequence", "SEQUENCE").state, mistreevous.State.SUCCEEDED); + assert.strictEqual(findNode(tree, "action", "getActionResult").state, mistreevous.State.SUCCEEDED); - tree.reset(); + tree.reset(); - assert.strictEqual(tree.getState(), mistreevous.State.READY); + assert.strictEqual(findNode(tree, "root", "ROOT").state, mistreevous.State.READY); + assert.strictEqual(findNode(tree, "sequence", "SEQUENCE").state, mistreevous.State.READY); + assert.strictEqual(findNode(tree, "action", "getActionResult").state, mistreevous.State.READY); + }); + + it("(JSON)", () => { + const definition = { + type: "root", + child: { + type: "sequence", + children: [ + { + type: "action", + call: "getActionResult" + } + ] + } + }; + const agent = { getActionResult: () => mistreevous.State.SUCCEEDED }; + const tree = new mistreevous.BehaviourTree(definition, agent); + + assert.strictEqual(findNode(tree, "root", "ROOT").state, mistreevous.State.READY); + assert.strictEqual(findNode(tree, "sequence", "SEQUENCE").state, mistreevous.State.READY); + assert.strictEqual(findNode(tree, "action", "getActionResult").state, mistreevous.State.READY); + + tree.step(); + + assert.strictEqual(findNode(tree, "root", "ROOT").state, mistreevous.State.SUCCEEDED); + assert.strictEqual(findNode(tree, "sequence", "SEQUENCE").state, mistreevous.State.SUCCEEDED); + assert.strictEqual(findNode(tree, "action", "getActionResult").state, mistreevous.State.SUCCEEDED); + + tree.reset(); + + assert.strictEqual(findNode(tree, "root", "ROOT").state, mistreevous.State.READY); + assert.strictEqual(findNode(tree, "sequence", "SEQUENCE").state, mistreevous.State.READY); + assert.strictEqual(findNode(tree, "action", "getActionResult").state, mistreevous.State.READY); + }); }); - it("has a 'step' function that .....", () => { - const definition = - "root { sequence { action [getActionResult0] action [getActionResult1] action [getActionResult2] action [getActionResult3] } }"; - const agent = { - getActionResult0: () => mistreevous.State.SUCCEEDED, - getActionResult1: () => mistreevous.State.SUCCEEDED, - getActionResult2: () => undefined, - getActionResult3: () => mistreevous.State.SUCCEEDED - }; - const tree = new mistreevous.BehaviourTree(definition, agent); + describe("has a 'step' function that updates all nodes in sequence unless a node is left in the running state", () => { + it("(MDSL)", () => { + const definition = + "root { sequence { action [getActionResult0] action [getActionResult1] action [getActionResult2] action [getActionResult3] } }"; + const agent = { + getActionResult0: () => mistreevous.State.SUCCEEDED, + getActionResult1: () => mistreevous.State.SUCCEEDED, + getActionResult2: () => undefined, + getActionResult3: () => mistreevous.State.SUCCEEDED + }; + const tree = new mistreevous.BehaviourTree(definition, agent); - assert.strictEqual(findNode(tree, "action", "getActionResult0").state, mistreevous.State.READY); - assert.strictEqual(findNode(tree, "action", "getActionResult1").state, mistreevous.State.READY); - assert.strictEqual(findNode(tree, "action", "getActionResult2").state, mistreevous.State.READY); - assert.strictEqual(findNode(tree, "action", "getActionResult3").state, mistreevous.State.READY); + assert.strictEqual(findNode(tree, "action", "getActionResult0").state, mistreevous.State.READY); + assert.strictEqual(findNode(tree, "action", "getActionResult1").state, mistreevous.State.READY); + assert.strictEqual(findNode(tree, "action", "getActionResult2").state, mistreevous.State.READY); + assert.strictEqual(findNode(tree, "action", "getActionResult3").state, mistreevous.State.READY); - tree.step(); + tree.step(); - assert.strictEqual(findNode(tree, "action", "getActionResult0").state, mistreevous.State.SUCCEEDED); - assert.strictEqual(findNode(tree, "action", "getActionResult1").state, mistreevous.State.SUCCEEDED); - assert.strictEqual(findNode(tree, "action", "getActionResult2").state, mistreevous.State.RUNNING); - assert.strictEqual(findNode(tree, "action", "getActionResult3").state, mistreevous.State.READY); + assert.strictEqual(findNode(tree, "action", "getActionResult0").state, mistreevous.State.SUCCEEDED); + assert.strictEqual(findNode(tree, "action", "getActionResult1").state, mistreevous.State.SUCCEEDED); + assert.strictEqual(findNode(tree, "action", "getActionResult2").state, mistreevous.State.RUNNING); + assert.strictEqual(findNode(tree, "action", "getActionResult3").state, mistreevous.State.READY); - agent.getActionResult2 = () => mistreevous.State.SUCCEEDED; + agent.getActionResult2 = () => mistreevous.State.SUCCEEDED; - tree.step(); + tree.step(); - assert.strictEqual(findNode(tree, "action", "getActionResult0").state, mistreevous.State.SUCCEEDED); - assert.strictEqual(findNode(tree, "action", "getActionResult1").state, mistreevous.State.SUCCEEDED); - assert.strictEqual(findNode(tree, "action", "getActionResult2").state, mistreevous.State.SUCCEEDED); - assert.strictEqual(findNode(tree, "action", "getActionResult3").state, mistreevous.State.SUCCEEDED); + assert.strictEqual(findNode(tree, "action", "getActionResult0").state, mistreevous.State.SUCCEEDED); + assert.strictEqual(findNode(tree, "action", "getActionResult1").state, mistreevous.State.SUCCEEDED); + assert.strictEqual(findNode(tree, "action", "getActionResult2").state, mistreevous.State.SUCCEEDED); + assert.strictEqual(findNode(tree, "action", "getActionResult3").state, mistreevous.State.SUCCEEDED); - agent.getActionResult2 = () => undefined; + agent.getActionResult2 = () => undefined; - tree.step(); + tree.step(); - assert.strictEqual(findNode(tree, "action", "getActionResult0").state, mistreevous.State.SUCCEEDED); - assert.strictEqual(findNode(tree, "action", "getActionResult1").state, mistreevous.State.SUCCEEDED); - assert.strictEqual(findNode(tree, "action", "getActionResult2").state, mistreevous.State.RUNNING); - assert.strictEqual(findNode(tree, "action", "getActionResult3").state, mistreevous.State.READY); + assert.strictEqual(findNode(tree, "action", "getActionResult0").state, mistreevous.State.SUCCEEDED); + assert.strictEqual(findNode(tree, "action", "getActionResult1").state, mistreevous.State.SUCCEEDED); + assert.strictEqual(findNode(tree, "action", "getActionResult2").state, mistreevous.State.RUNNING); + assert.strictEqual(findNode(tree, "action", "getActionResult3").state, mistreevous.State.READY); + }); + + it("(JSON)", () => { + const definition = { + type: "root", + child: { + type: "sequence", + children: [ + { + type: "action", + call: "getActionResult0" + }, + { + type: "action", + call: "getActionResult1" + }, + { + type: "action", + call: "getActionResult2" + }, + { + type: "action", + call: "getActionResult3" + } + ] + } + }; + const agent = { + getActionResult0: () => mistreevous.State.SUCCEEDED, + getActionResult1: () => mistreevous.State.SUCCEEDED, + getActionResult2: () => undefined, + getActionResult3: () => mistreevous.State.SUCCEEDED + }; + const tree = new mistreevous.BehaviourTree(definition, agent); + + assert.strictEqual(findNode(tree, "action", "getActionResult0").state, mistreevous.State.READY); + assert.strictEqual(findNode(tree, "action", "getActionResult1").state, mistreevous.State.READY); + assert.strictEqual(findNode(tree, "action", "getActionResult2").state, mistreevous.State.READY); + assert.strictEqual(findNode(tree, "action", "getActionResult3").state, mistreevous.State.READY); + + tree.step(); + + assert.strictEqual(findNode(tree, "action", "getActionResult0").state, mistreevous.State.SUCCEEDED); + assert.strictEqual(findNode(tree, "action", "getActionResult1").state, mistreevous.State.SUCCEEDED); + assert.strictEqual(findNode(tree, "action", "getActionResult2").state, mistreevous.State.RUNNING); + assert.strictEqual(findNode(tree, "action", "getActionResult3").state, mistreevous.State.READY); + + agent.getActionResult2 = () => mistreevous.State.SUCCEEDED; + + tree.step(); + + assert.strictEqual(findNode(tree, "action", "getActionResult0").state, mistreevous.State.SUCCEEDED); + assert.strictEqual(findNode(tree, "action", "getActionResult1").state, mistreevous.State.SUCCEEDED); + assert.strictEqual(findNode(tree, "action", "getActionResult2").state, mistreevous.State.SUCCEEDED); + assert.strictEqual(findNode(tree, "action", "getActionResult3").state, mistreevous.State.SUCCEEDED); + + agent.getActionResult2 = () => undefined; + + tree.step(); + + assert.strictEqual(findNode(tree, "action", "getActionResult0").state, mistreevous.State.SUCCEEDED); + assert.strictEqual(findNode(tree, "action", "getActionResult1").state, mistreevous.State.SUCCEEDED); + assert.strictEqual(findNode(tree, "action", "getActionResult2").state, mistreevous.State.RUNNING); + assert.strictEqual(findNode(tree, "action", "getActionResult3").state, mistreevous.State.READY); + }); }); }); diff --git a/test/nodes/composite/Lotto.test.js b/test/nodes/composite/Lotto.test.js index b0d580c..a8f00e1 100644 --- a/test/nodes/composite/Lotto.test.js +++ b/test/nodes/composite/Lotto.test.js @@ -12,7 +12,7 @@ describe("A Lotto node", () => { assert.throws( () => new mistreevous.BehaviourTree(definition, {}), Error, - "error parsing tree: a lotto node must have at least a single child" + "invalid definition: a lotto node must have at least a single child" ); }); }); diff --git a/test/nodes/decorator/fail.test.js b/test/nodes/decorator/fail.test.js index bad5278..a4fceee 100644 --- a/test/nodes/decorator/fail.test.js +++ b/test/nodes/decorator/fail.test.js @@ -13,7 +13,7 @@ describe("A Fail node", () => { assert.throws( () => new mistreevous.BehaviourTree(definition, {}), Error, - "error parsing tree: a fail node must have a single child" + "invalid definition: a fail node must have a single child" ); }); }); diff --git a/test/nodes/decorator/flip.test.js b/test/nodes/decorator/flip.test.js index 33f8d66..003c091 100644 --- a/test/nodes/decorator/flip.test.js +++ b/test/nodes/decorator/flip.test.js @@ -13,7 +13,7 @@ describe("A Flip node", () => { assert.throws( () => new mistreevous.BehaviourTree(definition, {}), Error, - "error parsing tree: a flip node must have a single child" + "invalid definition: a flip node must have a single child" ); }); }); diff --git a/test/nodes/decorator/repeat.test.js b/test/nodes/decorator/repeat.test.js index a61cd8f..764cc33 100644 --- a/test/nodes/decorator/repeat.test.js +++ b/test/nodes/decorator/repeat.test.js @@ -14,7 +14,7 @@ describe("A Repeat node", () => { assert.throws( () => new mistreevous.BehaviourTree(definition, {}), Error, - "error parsing tree: a repeat node must have a single child" + "invalid definition: a repeat node must have a single child" ); }); }); diff --git a/test/nodes/decorator/retry.test.js b/test/nodes/decorator/retry.test.js index 5076c76..791b517 100644 --- a/test/nodes/decorator/retry.test.js +++ b/test/nodes/decorator/retry.test.js @@ -14,7 +14,7 @@ describe("A Retry node", () => { assert.throws( () => new mistreevous.BehaviourTree(definition, {}), Error, - "error parsing tree: a retry node must have a single child" + "invalid definition: a retry node must have a single child" ); }); }); diff --git a/test/nodes/decorator/succeed.test.js b/test/nodes/decorator/succeed.test.js index d5723dc..bf456cf 100644 --- a/test/nodes/decorator/succeed.test.js +++ b/test/nodes/decorator/succeed.test.js @@ -13,7 +13,7 @@ describe("A Succeed node", () => { assert.throws( () => new mistreevous.BehaviourTree(definition, {}), Error, - "error parsing tree: a succeed node must have a single child" + "invalid definition: a succeed node must have a single child" ); }); }); diff --git a/test/nodes/leaf/action.test.js b/test/nodes/leaf/action.test.js index c4f274d..68354c9 100644 --- a/test/nodes/leaf/action.test.js +++ b/test/nodes/leaf/action.test.js @@ -13,7 +13,7 @@ describe("An Action node", () => { assert.throws( () => new mistreevous.BehaviourTree(definition, {}), Error, - "error parsing tree: expected action name identifier argument" + "invalid definition: expected action name identifier argument" ); }); }); diff --git a/test/nodes/leaf/condition.test.js b/test/nodes/leaf/condition.test.js index 939d172..8494805 100644 --- a/test/nodes/leaf/condition.test.js +++ b/test/nodes/leaf/condition.test.js @@ -13,7 +13,7 @@ describe("A Condition node", () => { assert.throws( () => new mistreevous.BehaviourTree(definition, {}), Error, - "error parsing tree: expected condition name identifier argument" + "invalid definition: expected condition name identifier argument" ); }); }); diff --git a/test/nodes/leaf/wait.test.js b/test/nodes/leaf/wait.test.js index 0dc3e1b..c960ac7 100644 --- a/test/nodes/leaf/wait.test.js +++ b/test/nodes/leaf/wait.test.js @@ -15,7 +15,7 @@ describe("A Wait node", () => { assert.throws( () => new mistreevous.BehaviourTree(definition, {}), Error, - "error parsing tree: wait node durations must be integer values" + "invalid definition: wait node durations must be integer values" ); }); @@ -24,7 +24,7 @@ describe("A Wait node", () => { assert.throws( () => new mistreevous.BehaviourTree(definition, {}), Error, - "error parsing tree: a wait node must have a positive duration" + "invalid definition: a wait node must have a positive duration" ); }); @@ -33,7 +33,7 @@ describe("A Wait node", () => { assert.throws( () => new mistreevous.BehaviourTree(definition, {}), Error, - "error parsing tree: invalid number of wait node duration arguments defined" + "invalid definition: invalid number of wait node duration arguments defined" ); }); @@ -42,7 +42,7 @@ describe("A Wait node", () => { assert.throws( () => new mistreevous.BehaviourTree(definition, {}), Error, - "error parsing tree: a wait node must not have a minimum duration that exceeds the maximum duration" + "invalid definition: a wait node must not have a minimum duration that exceeds the maximum duration" ); }); }); From 92dfa55a3ca8a90ece18e36faab7c36452b592bd Mon Sep 17 00:00:00 2001 From: Nikolas Howard Date: Fri, 9 Feb 2024 17:33:44 +0000 Subject: [PATCH 24/48] tests --- dist/bundle.js | 63 ++- dist/bundle.js.map | 4 +- dist/index.js | 63 ++- dist/index.js.map | 4 +- src/BehaviourTreeDefinitionValidator.ts | 66 ++- src/mdsl/MDSLDefinitionParser.ts | 33 +- ...iourTree.test.js => BehaviourTree.test.js} | 0 test/nodes/composite/Lotto.test.js | 523 +++++++++++++++--- test/nodes/composite/Parallel.test.js | 36 ++ test/nodes/composite/Selector.test.js | 36 ++ test/nodes/composite/Sequence.test.js | 36 ++ test/nodes/decorator/Fail.test.js | 157 ++++++ test/nodes/decorator/Flip.test.js | 155 ++++++ .../{repeat.test.js => Repeat.test.js} | 0 .../{retry.test.js => Retry.test.js} | 0 test/nodes/decorator/Succeed.test.js | 157 ++++++ test/nodes/decorator/fail.test.js | 66 --- test/nodes/decorator/flip.test.js | 64 --- test/nodes/decorator/succeed.test.js | 66 --- .../leaf/{action.test.js => Action.test.js} | 0 .../{condition.test.js => Condition.test.js} | 0 .../nodes/leaf/{wait.test.js => Wait.test.js} | 0 22 files changed, 1187 insertions(+), 342 deletions(-) rename test/{behaviourTree.test.js => BehaviourTree.test.js} (100%) create mode 100644 test/nodes/composite/Parallel.test.js create mode 100644 test/nodes/composite/Selector.test.js create mode 100644 test/nodes/composite/Sequence.test.js create mode 100644 test/nodes/decorator/Fail.test.js create mode 100644 test/nodes/decorator/Flip.test.js rename test/nodes/decorator/{repeat.test.js => Repeat.test.js} (100%) rename test/nodes/decorator/{retry.test.js => Retry.test.js} (100%) create mode 100644 test/nodes/decorator/Succeed.test.js delete mode 100644 test/nodes/decorator/fail.test.js delete mode 100644 test/nodes/decorator/flip.test.js delete mode 100644 test/nodes/decorator/succeed.test.js rename test/nodes/leaf/{action.test.js => Action.test.js} (100%) rename test/nodes/leaf/{condition.test.js => Condition.test.js} (100%) rename test/nodes/leaf/{wait.test.js => Wait.test.js} (100%) diff --git a/dist/bundle.js b/dist/bundle.js index 7bb095a..f956834 100644 --- a/dist/bundle.js +++ b/dist/bundle.js @@ -683,12 +683,12 @@ var mistreevous = (() => { } function createLottoNode(tokens, stringLiteralPlaceholders) { const nodeArguments = parseArgumentTokens(tokens, stringLiteralPlaceholders); - nodeArguments.filter((arg) => arg.type !== "number" || !arg.isInteger).forEach(() => { - throw new Error(`lotto node weight arguments must be integer values`); + nodeArguments.filter((arg) => arg.type !== "number" || !arg.isInteger || arg.value < 0).forEach(() => { + throw new Error(`lotto node weight arguments must be positive integer values`); }); const node = { type: "lotto", - weights: nodeArguments.map(({ value }) => value), + weights: nodeArguments.length ? nodeArguments.map(({ value }) => value) : void 0, ...parseAttributeTokens(tokens, stringLiteralPlaceholders) }; popAndCheck(tokens, "{"); @@ -761,12 +761,21 @@ var mistreevous = (() => { } return { type: "branch", ref: nodeArguments[0].value }; } - function validatePoppedNode(node) { - if (isDecoratorNode(node) && isNullOrUndefined(node.child)) { - throw new Error(`a ${node.type} node must have a single child node defined`); + function validatePoppedNode(definition) { + if (isDecoratorNode(definition) && isNullOrUndefined(definition.child)) { + throw new Error(`a ${definition.type} node must have a single child node defined`); } - if (isCompositeNode(node) && !node.children?.length) { - throw new Error(`a ${node.type} node must have at least a single child node defined`); + if (isCompositeNode(definition) && !definition.children?.length) { + throw new Error(`a ${definition.type} node must have at least a single child node defined`); + } + if (definition.type === "lotto") { + if (typeof definition.weights !== "undefined") { + if (definition.weights.length !== definition.children.length) { + throw new Error( + "expected a number of weight arguments matching the number of child nodes for lotto node" + ); + } + } } } @@ -892,8 +901,8 @@ var mistreevous = (() => { case "root": validateRootNode(definition, depth); break; - case "success": - validateSuccessNode(definition, depth); + case "succeed": + validateSucceedNode(definition, depth); break; case "fail": validateFailNode(definition, depth); @@ -916,6 +925,9 @@ var mistreevous = (() => { case "parallel": validateParallelNode(definition, depth); break; + case "lotto": + validateLottoNode(definition, depth); + break; default: throw new Error(`unexpected node type of '${definition.type}' at depth '${depth}'`); } @@ -959,12 +971,12 @@ var mistreevous = (() => { validateNodeAttributes(definition, depth); validateNode(definition.child, depth + 1); } - function validateSuccessNode(definition, depth) { - if (definition.type !== "success") { - throw new Error(`expected node type of 'success' for success node at depth '${depth}'`); + function validateSucceedNode(definition, depth) { + if (definition.type !== "succeed") { + throw new Error(`expected node type of 'succeed' for succeed node at depth '${depth}'`); } if (typeof definition.child === "undefined") { - throw new Error(`expected property 'child' to be defined for success node at depth '${depth}'`); + throw new Error(`expected property 'child' to be defined for succeed node at depth '${depth}'`); } validateNodeAttributes(definition, depth); validateNode(definition.child, depth + 1); @@ -998,7 +1010,7 @@ var mistreevous = (() => { } if (typeof definition.iterations !== "undefined") { if (Array.isArray(definition.iterations)) { - const containsNonInteger = !!definition.iterations.find((value) => !isInteger(value)); + const containsNonInteger = !!definition.iterations.filter((value) => !isInteger(value)).length; if (definition.iterations.length !== 2 || containsNonInteger) { throw new Error( `expected array containing two integer values for 'iterations' property if defined for repeat node at depth '${depth}'` @@ -1038,7 +1050,7 @@ var mistreevous = (() => { } if (typeof definition.attempts !== "undefined") { if (Array.isArray(definition.attempts)) { - const containsNonInteger = !!definition.attempts.find((value) => !isInteger(value)); + const containsNonInteger = !!definition.attempts.filter((value) => !isInteger(value)).length; if (definition.attempts.length !== 2 || containsNonInteger) { throw new Error( `expected array containing two integer values for 'attempts' property if defined for retry node at depth '${depth}'` @@ -1121,7 +1133,7 @@ var mistreevous = (() => { } if (typeof definition.duration !== "undefined") { if (Array.isArray(definition.duration)) { - const containsNonInteger = !!definition.duration.find((value) => !isInteger(value)); + const containsNonInteger = !!definition.duration.filter((value) => !isInteger(value)).length; if (definition.duration.length !== 2 || containsNonInteger) { throw new Error( `expected array containing two integer values for 'duration' property if defined for wait node at depth '${depth}'` @@ -1181,6 +1193,23 @@ var mistreevous = (() => { validateNodeAttributes(definition, depth); definition.children.forEach((child) => validateNode(child, depth + 1)); } + function validateLottoNode(definition, depth) { + if (definition.type !== "lotto") { + throw new Error(`expected node type of 'lotto' for lotto node at depth '${depth}'`); + } + if (!Array.isArray(definition.children) || definition.children.length === 0) { + throw new Error(`expected non-empty 'children' array to be defined for lotto node at depth '${depth}'`); + } + if (typeof definition.weights !== "undefined") { + if (!Array.isArray(definition.weights) || definition.weights.length !== definition.children.length || definition.weights.filter((value) => !isInteger(value)).length || definition.weights.filter((value) => value < 0).length) { + throw new Error( + `expected an array of positive integer weight values with a length matching the number of child nodes for 'weights' property if defined for lotto node at depth '${depth}'` + ); + } + } + validateNodeAttributes(definition, depth); + definition.children.forEach((child) => validateNode(child, depth + 1)); + } function createValidationFailureResult(errorMessage) { return { succeeded: false, errorMessage }; } diff --git a/dist/bundle.js.map b/dist/bundle.js.map index 077677c..62f213c 100644 --- a/dist/bundle.js.map +++ b/dist/bundle.js.map @@ -1,7 +1,7 @@ { "version": 3, "sources": ["../node_modules/lotto-draw/dist/Participant.js", "../node_modules/lotto-draw/dist/Utilities.js", "../node_modules/lotto-draw/dist/Lotto.js", "../node_modules/lotto-draw/dist/createLotto.js", "../node_modules/lotto-draw/dist/index.js", "../src/index.ts", "../src/State.ts", "../src/BehaviourTreeDefinitionUtilities.ts", "../src/mdsl/MDSLUtilities.ts", "../src/mdsl/MDSLNodeArgumentParser.ts", "../src/mdsl/MDSLNodeAttributeParser.ts", "../src/mdsl/MDSLDefinitionParser.ts", "../src/BehaviourTreeDefinitionValidator.ts", "../src/Lookup.ts", "../src/attributes/guards/GuardUnsatisifedException.ts", "../src/attributes/guards/GuardPath.ts", "../src/nodes/Node.ts", "../src/nodes/composite/Composite.ts", "../src/nodes/composite/Parallel.ts", "../src/nodes/composite/Selector.ts", "../src/nodes/composite/Sequence.ts", "../src/nodes/composite/Lotto.ts", "../src/nodes/decorator/Decorator.ts", "../src/nodes/decorator/Fail.ts", "../src/nodes/decorator/Flip.ts", "../src/nodes/decorator/Repeat.ts", "../src/nodes/decorator/Retry.ts", "../src/nodes/decorator/Root.ts", "../src/nodes/decorator/Succeed.ts", "../src/nodes/leaf/Leaf.ts", "../src/nodes/leaf/Action.ts", "../src/nodes/leaf/Condition.ts", "../src/nodes/leaf/Wait.ts", "../src/attributes/Attribute.ts", "../src/attributes/guards/Guard.ts", "../src/attributes/guards/While.ts", "../src/attributes/guards/Until.ts", "../src/attributes/callbacks/Callback.ts", "../src/attributes/callbacks/Entry.ts", "../src/attributes/callbacks/Step.ts", "../src/attributes/callbacks/Exit.ts", "../src/BehaviourTreeBuilder.ts", "../src/BehaviourTree.ts"], - "sourcesContent": ["\"use strict\";\r\nObject.defineProperty(exports, \"__esModule\", { value: true });\r\nexports.Participant = void 0;\r\n/**\r\n * A participant that holds a number of tickets.\r\n */\r\nvar Participant = /** @class */ (function () {\r\n /**\r\n * Creates an instance of the Participant class.\r\n * @param participant The actual participant.\r\n * @param tickets The number of tickets held by the participant.\r\n */\r\n function Participant(participant, tickets) {\r\n if (tickets === void 0) { tickets = 1; }\r\n this._participant = participant;\r\n this._tickets = tickets;\r\n }\r\n Object.defineProperty(Participant.prototype, \"participant\", {\r\n /** Gets the actual participant. */\r\n get: function () {\r\n return this._participant;\r\n },\r\n enumerable: false,\r\n configurable: true\r\n });\r\n Object.defineProperty(Participant.prototype, \"tickets\", {\r\n /** Gets or sets the number of tickets held by the participant. */\r\n get: function () {\r\n return this._tickets;\r\n },\r\n set: function (value) {\r\n this._tickets = value;\r\n },\r\n enumerable: false,\r\n configurable: true\r\n });\r\n return Participant;\r\n}());\r\nexports.Participant = Participant;\r\n", "\"use strict\";\r\nObject.defineProperty(exports, \"__esModule\", { value: true });\r\nexports.isNaturalNumber = exports.isNullOrUndefined = void 0;\r\n/**\r\n * Gets whether the value provided is null or undefined.\r\n * @param value The value to check.\r\n * @returns Whether the value provided is null or undefined.\r\n */\r\nfunction isNullOrUndefined(value) {\r\n return value === null || value === undefined;\r\n}\r\nexports.isNullOrUndefined = isNullOrUndefined;\r\n/**\r\n * Gets whether the value provided is a natural number.\r\n * @param value The value to check.\r\n * @returns Whether the value provided is a natural number.\r\n */\r\nfunction isNaturalNumber(value) {\r\n return typeof value === \"number\" && value >= 1 && Math.floor(value) === value;\r\n}\r\nexports.isNaturalNumber = isNaturalNumber;\r\n", "\"use strict\";\r\nObject.defineProperty(exports, \"__esModule\", { value: true });\r\nexports.Lotto = void 0;\r\nvar Participant_1 = require(\"./Participant\");\r\nvar Utilities_1 = require(\"./Utilities\");\r\n/**\r\n * Represents a lotto consisting of a number of pickable ticket-holding participants.\r\n */\r\nvar Lotto = /** @class */ (function () {\r\n /**\r\n * Creates a new instance of Lotto.\r\n * @param customRandom The custom RNG to use in place of Math.random().\r\n */\r\n function Lotto(customRandom) {\r\n /** The array of participants that are holding tickets in the lotto. */\r\n this._participants = [];\r\n this._customRandom = customRandom;\r\n }\r\n /**\r\n * Adds a participant with the specified number of tickets, or adds to the participant ticket count if the participant already holds tickets.\r\n * @param participant The participant to add or to increase the ticket count for if they already hold tickets.\r\n * @param tickets The number of tickets, defaults to 1.\r\n * @returns The Lotto instance.\r\n */\r\n Lotto.prototype.add = function (participant, tickets) {\r\n if (tickets === void 0) { tickets = 1; }\r\n // Check that we have a valid ticket count.\r\n if (!(0, Utilities_1.isNaturalNumber)(tickets)) {\r\n throw new Error(\"tickets value must be a natural number\");\r\n }\r\n // Check whether this participant has already been added.\r\n var existingParticipant = this._participants.find(function (part) { return part.participant === participant; });\r\n if (existingParticipant) {\r\n // The participant has already been added to the lotto so just add to their ticket count.\r\n existingParticipant.tickets += tickets;\r\n }\r\n else {\r\n // The participant is not part of the lotto so we should add them.\r\n this._participants.push(new Participant_1.Participant(participant, tickets));\r\n }\r\n return this;\r\n };\r\n /**\r\n * Removes the specified number of tickets for the given participant from the draw, or all tickets if a ticket number is not defined.\r\n * @param participant The participant to remove tickets for.\r\n * @param tickets The number of tickets to remove, or undefined if all tickets are to be removed.\r\n * @returns The Lotto instance.\r\n */\r\n Lotto.prototype.remove = function (participant, tickets) {\r\n // Attempt to get the existing participant.\r\n var existingParticipant = this._participants.find(function (part) { return part.participant === participant; });\r\n // There is nothing to do if the specified participant isn't even part of the lotto.\r\n if (!existingParticipant) {\r\n return this;\r\n }\r\n // Check whether a tickets value was given.\r\n if (tickets !== undefined) {\r\n // Check that we have a valid ticket count.\r\n if (!(0, Utilities_1.isNaturalNumber)(tickets)) {\r\n throw new Error(\"tickets value must be a natural number\");\r\n }\r\n existingParticipant.tickets -= tickets;\r\n // If the participant no longer holds any tickets then they should be removed.\r\n if (existingParticipant.tickets < 1) {\r\n this._participants = this._participants.filter(function (part) { return part !== existingParticipant; });\r\n }\r\n }\r\n else {\r\n // We are removing all tickets for the participant so just remove them from the lotto.\r\n this._participants = this._participants.filter(function (part) { return part !== existingParticipant; });\r\n }\r\n return this;\r\n };\r\n /**\r\n * Draw a winning ticket and return the participant that holds the ticket.\r\n * @param options The draw options.\r\n * @returns The participant that holds the winning ticket.\r\n */\r\n Lotto.prototype.draw = function (options) {\r\n if (options === void 0) { options = {}; }\r\n // If we have no participants then just return null.\r\n if (this._participants.length === 0) {\r\n return null;\r\n }\r\n var redrawable = (0, Utilities_1.isNullOrUndefined)(options.redrawable) ? true : options.redrawable;\r\n var pickable = [];\r\n this._participants.forEach(function (_a) {\r\n var participant = _a.participant, tickets = _a.tickets;\r\n for (var ticketCount = 0; ticketCount < tickets; ticketCount++) {\r\n pickable.push(participant);\r\n }\r\n });\r\n var random;\r\n // We need a random floating-point number between 0 (inclusive) and 1 to scale up to pick our winner.\r\n // If a custom random function exists then we should use that or fall back to Math.random().\r\n if (this._customRandom) {\r\n // Call our custom random function to get a random floating-point number.\r\n random = this._customRandom();\r\n // Verify that the result of calling our custom random function is a number between 0 (inclusive) and 1.\r\n if (typeof random !== \"number\" || random < 0 || random >= 1) {\r\n throw new Error(\"the 'random' function provided did not return a number between 0 (inclusive) and 1\");\r\n }\r\n }\r\n else {\r\n // No custom random function was defined so just use good ol' Math.random().\r\n random = Math.random();\r\n }\r\n // Pick a winning participant.\r\n var winner = pickable[Math.floor(random * pickable.length)];\r\n // If the ticket isn't redrawable then we should remove a ticket from the winning participants ticket count.\r\n if (!redrawable) {\r\n this.remove(winner, 1);\r\n }\r\n // Return the winning participant.\r\n return winner;\r\n };\r\n /**\r\n * Draws multiple winning tickets and return an array of the participants that hold the winning tickets.\r\n * @param tickets The number of winning tickets to draw.\r\n * @param options The draw multiple options.\r\n * @returns An array of the participants that hold the winning tickets.\r\n */\r\n Lotto.prototype.drawMultiple = function (tickets, options) {\r\n if (options === void 0) { options = {}; }\r\n var uniqueResults = (0, Utilities_1.isNullOrUndefined)(options.unique) ? false : options.unique;\r\n // Handle cases where the user has asked for zero tickets (no idea why they would do this be we should trust them).\r\n if (tickets === 0) {\r\n return [];\r\n }\r\n // Now that we know out tickets value is not zero we should check that it is a valid natural number.\r\n if (!(0, Utilities_1.isNaturalNumber)(tickets)) {\r\n throw new Error(\"tickets value must be a natural number\");\r\n }\r\n var result = [];\r\n // Keep drawing tickets until we either reach the number of required tickets or we simply run out of tickets to draw.\r\n // We can run out of tickets to draw if 'options.redrawable' is explicity 'false' or we just had no participants when 'drawMultiple' was called.\r\n while (result.length < tickets && this._participants.length > 0) {\r\n result.push(this.draw(options));\r\n }\r\n // If the 'unique' draw option is set then we need to remove duplicates from the result list.\r\n if (uniqueResults) {\r\n // Create an array to store our unique results.\r\n var unique = [];\r\n // Iterate over all of our participants (with potential duplicates) and populate our array of unique values.\r\n for (var _i = 0, result_1 = result; _i < result_1.length; _i++) {\r\n var participant = result_1[_i];\r\n if (unique.indexOf(participant) === -1) {\r\n unique.push(participant);\r\n }\r\n }\r\n result = unique;\r\n }\r\n return result;\r\n };\r\n return Lotto;\r\n}());\r\nexports.Lotto = Lotto;\r\n", "\"use strict\";\r\nObject.defineProperty(exports, \"__esModule\", { value: true });\r\nexports.createLotto = void 0;\r\nvar Lotto_1 = require(\"./Lotto\");\r\n/**\r\n * A function that creates and returns a Lotto instance.\r\n * @param participantsOrOptions An array of initial participants or options relating to the creation of a Lotto instance.\r\n * @returns A new Lotto instance.\r\n */\r\nfunction createLotto(participantsOrOptions) {\r\n // If no initial participants or lotto options were provided as an argument then we can just return a new lotto instance now.\r\n if (!participantsOrOptions) {\r\n return new Lotto_1.Lotto();\r\n }\r\n // Check whether we were provided with an array of initial participants or a lotto options object.\r\n if (Array.isArray(participantsOrOptions)) {\r\n // We are dealing with a pre-defined array of participants.\r\n var participants = participantsOrOptions;\r\n var lotto_1 = new Lotto_1.Lotto();\r\n // If the lotto participants have been defined upfront then we will need to add them all to our lotto instance now.\r\n participants.forEach(function (_a) {\r\n var participant = _a[0], tokens = _a[1];\r\n return lotto_1.add(participant, tokens);\r\n });\r\n // Return the Lotto instance.\r\n return lotto_1;\r\n }\r\n else {\r\n // We are dealing with some lotto options.\r\n var random = participantsOrOptions.random, participants = participantsOrOptions.participants;\r\n // Create a Lotto instance passing the custom RNG function to use in place of Math.random() (which could be undefined).\r\n var lotto_2 = new Lotto_1.Lotto(random);\r\n // If the lotto participants have been defined upfront as part of the options then we will need to add them all to our lotto instance now.\r\n if (participants) {\r\n participants.forEach(function (_a) {\r\n var participant = _a[0], tokens = _a[1];\r\n return lotto_2.add(participant, tokens);\r\n });\r\n }\r\n // Return the Lotto instance.\r\n return lotto_2;\r\n }\r\n}\r\nexports.createLotto = createLotto;\r\n", "\"use strict\";\r\nObject.defineProperty(exports, \"__esModule\", { value: true });\r\nvar createLotto_1 = require(\"./createLotto\");\r\nexports.default = createLotto_1.createLotto;\r\n", "import State from \"./State\";\nimport { validateDefinition } from \"./BehaviourTreeDefinitionValidator\";\nimport { convertMDSLToJSON } from \"./mdsl/MDSLDefinitionParser\";\nimport { BehaviourTree, FlattenedTreeNode } from \"./BehaviourTree\";\nimport { BehaviourTreeOptions } from \"./BehaviourTreeOptions\";\n\nexport { BehaviourTree, State, convertMDSLToJSON, validateDefinition };\nexport type { FlattenedTreeNode, BehaviourTreeOptions };\n", "/**\n * Enumeration of node state types.\n */\nexport enum State {\n READY = \"mistreevous.ready\",\n RUNNING = \"mistreevous.running\",\n SUCCEEDED = \"mistreevous.succeeded\",\n FAILED = \"mistreevous.failed\"\n}\n\nexport { State as default };\n\nexport type CompleteState = State.SUCCEEDED | State.FAILED;\nexport type AnyState = State.READY | State.RUNNING | CompleteState;\n", "import {\n NodeDefinition,\n RootNodeDefinition,\n DecoratorNodeDefinition,\n CompositeNodeDefinition,\n AnyNodeDefinition,\n BranchNodeDefinition\n} from \"./BehaviourTreeDefinition\";\n\n/**\n * A type guard function that returns true if the specified node satisfies the RootNodeDefinition type.\n * @param node The node.\n * @returns A value of true if the specified node satisfies the RootNodeDefinition type.\n */\nexport function isRootNode(node: NodeDefinition): node is RootNodeDefinition {\n return node.type === \"root\";\n}\n\n/**\n * A type guard function that returns true if the specified node satisfies the BranchNodeDefinition type.\n * @param node The node.\n * @returns A value of true if the specified node satisfies the BranchNodeDefinition type.\n */\nexport function isBranchNode(node: NodeDefinition): node is BranchNodeDefinition {\n return node.type === \"branch\";\n}\n\n/**\n * A type guard function that returns true if the specified node satisfies the NodeDefinition type.\n * @param node The node.\n * @returns A value of true if the specified node satisfies the NodeDefinition type.\n */\nexport function isLeafNode(node: NodeDefinition): node is NodeDefinition {\n return [\"branch\", \"action\", \"condition\", \"wait\"].includes(node.type);\n}\n\n/**\n * A type guard function that returns true if the specified node satisfies the DecoratorNodeDefinition type.\n * @param node The node.\n * @returns A value of true if the specified node satisfies the DecoratorNodeDefinition type.\n */\nexport function isDecoratorNode(node: NodeDefinition): node is DecoratorNodeDefinition {\n return [\"root\", \"repeat\", \"retry\", \"flip\", \"succeed\", \"fail\"].includes(node.type);\n}\n\n/**\n * A type guard function that returns true if the specified node satisfies the CompositeNodeDefinition type.\n * @param node The node.\n * @returns A value of true if the specified node satisfies the CompositeNodeDefinition type.\n */\nexport function isCompositeNode(node: NodeDefinition): node is CompositeNodeDefinition {\n return [\"sequence\", \"selector\", \"lotto\", \"parallel\"].includes(node.type);\n}\n\n/**\n * Flatten a node definition into an array of all of its nested node definitions.\n * @param nodeDefinition The node definition to flatten.\n * @returns An array of all of nested node definitions.\n */\nexport function flattenDefinition(nodeDefinition: AnyNodeDefinition): AnyNodeDefinition[] {\n const nodes: AnyNodeDefinition[] = [];\n\n const processNode = (currentNodeDefinition: AnyNodeDefinition) => {\n nodes.push(currentNodeDefinition);\n\n if (isCompositeNode(currentNodeDefinition)) {\n currentNodeDefinition.children.forEach(processNode);\n } else if (isDecoratorNode(currentNodeDefinition)) {\n processNode(currentNodeDefinition.child);\n }\n };\n\n processNode(nodeDefinition);\n\n return nodes;\n}\n\n/**\n * Determines whether the passed value is an integer.\n * @param value The value to check.\n * @returns Whether the passed value is an integer.\n */\nexport function isInteger(value: unknown): boolean {\n return typeof value === \"number\" && Math.floor(value) === value;\n}\n\n/**\n * Determines whether the passed value is null or undefined.\n * @param value The value to check.\n * @returns Whether the passed value is null or undefined.\n */\nexport function isNullOrUndefined(value: unknown): boolean {\n return typeof value === \"undefined\" || value === null;\n}\n", "/**\n * A type defining an object that holds a reference to substitued string literals parsed from the definition.\n */\nexport type StringLiteralPlaceholders = { [key: string]: string };\n\n/**\n * Pop the next raw token from the specified array of tokens and throw an error if it wasn't the expected one.\n * @param tokens The array of tokens.\n * @param expected An optional string or array or items, one of which must match the next popped token.\n * @returns The popped token.\n */\nexport function popAndCheck(tokens: string[], expected?: string | string[]): string {\n // Get and remove the next token.\n const popped = tokens.shift();\n\n // We were expecting another token but there aren't any.\n if (popped === undefined) {\n throw new Error(\"unexpected end of definition\");\n }\n\n // Do we have an expected token/tokens array?\n if (expected != undefined) {\n // Get an array of expected values, if the popped token matches any then we are all good.\n const expectedValues = typeof expected === \"string\" ? [expected] : expected;\n\n // Check whether the popped token matches at least one of our expected items.\n var tokenMatchesExpectation = expectedValues.some((item) => popped.toUpperCase() === item.toUpperCase());\n\n // Throw an error if the popped token didn't match any of our expected items.\n if (!tokenMatchesExpectation) {\n const expectationString = expectedValues.map((item) => \"'\" + item + \"'\").join(\" or \");\n throw new Error(\"unexpected token found. Expected \" + expectationString + \" but got '\" + popped + \"'\");\n }\n }\n\n // Return the popped token.\n return popped;\n}\n\n/**\n * Swaps out any node/attribute argument string literals with placeholders.\n * @param definition The definition.\n * @returns An object containing a mapping of placeholders to original string values as well as the processed definition string.\n */\nexport function substituteStringLiterals(definition: string): {\n placeholders: StringLiteralPlaceholders;\n processedDefinition: string;\n} {\n // Create an object to hold the mapping of placeholders to original string values.\n const placeholders: StringLiteralPlaceholders = {};\n\n // Replace any string literals wrapped with double quotes in our definition with placeholders to be processed later.\n const processedDefinition = definition.replace(/\\\"(\\\\.|[^\"\\\\])*\\\"/g, (match) => {\n var strippedMatch = match.substring(1, match.length - 1);\n var placeholder = Object.keys(placeholders).find((key) => placeholders[key] === strippedMatch);\n\n // If we have no existing string literal match then create a new placeholder.\n if (!placeholder) {\n placeholder = `@@${Object.keys(placeholders).length}@@`;\n placeholders[placeholder] = strippedMatch;\n }\n\n return placeholder;\n });\n\n return { placeholders, processedDefinition };\n}\n\n/**\n * Parse the tree definition into an array of raw tokens.\n * @param definition The definition.\n * @returns An array of tokens parsed from the definition.\n */\nexport function parseTokensFromDefinition(definition: string): string[] {\n // Add some space around various important characters so that they can be plucked out easier as individual tokens.\n definition = definition.replace(/\\(/g, \" ( \");\n definition = definition.replace(/\\)/g, \" ) \");\n definition = definition.replace(/\\{/g, \" { \");\n definition = definition.replace(/\\}/g, \" } \");\n definition = definition.replace(/\\]/g, \" ] \");\n definition = definition.replace(/\\[/g, \" [ \");\n definition = definition.replace(/\\,/g, \" , \");\n\n // Split the definition into raw token form and return it.\n return definition.replace(/\\s+/g, \" \").trim().split(\" \");\n}\n", "import { StringLiteralPlaceholders, popAndCheck } from \"./MDSLUtilities\";\n\n/**\n * A type representing any node function argument.\n */\ntype Argument = {\n /**\n * The argument value.\n */\n value: T;\n /**\n * The argument type, used for validation.\n */\n type: string;\n};\n\ntype NullArgument = Argument & {\n type: \"null\";\n};\n\ntype BooleanArgument = Argument & {\n type: \"boolean\";\n};\n\ntype NumberArgument = Argument & {\n type: \"number\";\n /**\n * A flag defining whether the number argument value is a valid integer. (used for validation)\n */\n isInteger: boolean;\n};\n\ntype StringPlaceholderArgument = Argument & {\n type: \"string\";\n};\n\ntype IdentifierArgument = Argument & {\n type: \"identifier\";\n};\n\n/**\n * A type representing a reference to any node function argument.\n */\ntype AnyArgument = NullArgument | BooleanArgument | NumberArgument | StringPlaceholderArgument | IdentifierArgument;\n\n/**\n * Parse an array of argument definitions from the specified tokens array.\n * @param tokens The array tokens to parse the argument definitions from.\n * @param stringArgumentPlaceholders The mapping of string literal node argument placeholders to original values.\n * @param argumentValidator The argument validator function.\n * @param validationFailedMessage The exception message to throw if argument validation fails.\n * @returns An array of argument definitions parsed from the specified tokens array.\n */\nexport function parseArgumentTokens(\n tokens: string[],\n stringArgumentPlaceholders: StringLiteralPlaceholders\n): AnyArgument[] {\n const argumentList: AnyArgument[] = [];\n\n // If the next token is not a '[' or '(' then we have no arguments to parse.\n if (![\"[\", \"(\"].includes(tokens[0])) {\n return argumentList;\n }\n\n // Any lists of arguments will always be wrapped in '[]' for node arguments or '()' for attribute arguments.\n // We are looking for a '[' or '(' opener that wraps the argument tokens and the relevant closer.\n const closingToken = popAndCheck(tokens, [\"[\", \"(\"]) === \"[\" ? \"]\" : \")\";\n\n const argumentListTokens: string[] = [];\n\n // Grab all tokens between the '[' and ']' or '(' and ')'.\n while (tokens.length && tokens[0] !== closingToken) {\n // The next token is part of our arguments list.\n argumentListTokens.push(tokens.shift()!);\n }\n\n // Validate the order of the argument tokens. Each token must either be a ',' or a single argument that satisfies the validator.\n argumentListTokens.forEach((token, index) => {\n // Get whether this token should be an actual argument.\n const shouldBeArgumentToken = !(index & 1);\n\n // If the current token should be an actual argument then validate it, otherwise it should be a ',' token.\n if (shouldBeArgumentToken) {\n // Get the argument definition.\n const argumentDefinition = getArgumentDefinition(token, stringArgumentPlaceholders);\n\n // This is a valid argument!\n argumentList.push(argumentDefinition);\n } else {\n // The current token should be a ',' token.\n if (token !== \",\") {\n throw new Error(`invalid argument list, expected ',' or ']' but got '${token}'`);\n }\n }\n });\n\n // The arguments list should terminate with a ']' or ')' token, depending on the opener.\n popAndCheck(tokens, closingToken);\n\n // Return the arguments.\n return argumentList;\n}\n\n/**\n * Gets an argument value definition.\n * @param token The argument token.\n * @param stringArgumentPlaceholders The mapping of string literal node argument placeholders to original values.\n * @returns An argument value definition.\n */\nfunction getArgumentDefinition(token: string, stringArgumentPlaceholders: StringLiteralPlaceholders): AnyArgument {\n // Check whether the token represents a null value.\n if (token === \"null\") {\n return {\n value: null,\n type: \"null\"\n } as NullArgument;\n }\n\n // Check whether the token represents a boolean value.\n if (token === \"true\" || token === \"false\") {\n return {\n value: token === \"true\",\n type: \"boolean\"\n } as BooleanArgument;\n }\n\n // Check whether the token represents a number value.\n // TODO: Relies on broken isNaN - see MDN.\n // if (!Number.isNaN(token)) {\n if (!isNaN(token as any)) {\n return {\n value: parseFloat(token),\n isInteger: parseFloat(token) === parseInt(token, 10),\n type: \"number\"\n } as NumberArgument;\n }\n\n // Check whether the token is a placeholder (e.g. @@0@@) representing a string literal.\n if (token.match(/^@@\\d+@@$/g)) {\n return {\n value: stringArgumentPlaceholders[token].replace('\\\\\"', '\"'),\n type: \"string\"\n } as StringPlaceholderArgument;\n }\n\n // The only remaining option is that the argument value is an identifier.\n return {\n value: token,\n type: \"identifier\"\n } as IdentifierArgument;\n}\n", "import { NodeAttributeDefinition } from \"../BehaviourTreeDefinition\";\nimport { parseArgumentTokens } from \"./MDSLNodeArgumentParser\";\nimport { StringLiteralPlaceholders } from \"./MDSLUtilities\";\n\n/**\n * A type defining the attribute definitions of a node.\n */\ntype NodeAttributes = {\n while?: NodeAttributeDefinition;\n until?: NodeAttributeDefinition;\n entry?: NodeAttributeDefinition;\n exit?: NodeAttributeDefinition;\n step?: NodeAttributeDefinition;\n};\n\n/**\n * Parse any node attribute definitions from the specified tokens array.\n * @param tokens The array of remaining tokens.\n * @param stringArgumentPlaceholders The mapping of string literal node argument placeholders to original values.\n * @returns An object of attribute definitions defined by any directly following tokens.\n */\nexport function parseAttributeTokens(\n tokens: string[],\n stringArgumentPlaceholders: StringLiteralPlaceholders\n): NodeAttributes {\n const nodeAttributeNames: (keyof NodeAttributes)[] = [\"while\", \"until\", \"entry\", \"exit\", \"step\"];\n\n // Create an object to hold any attributes found.\n const attributes: NodeAttributes = {};\n\n // Try to get the name of the attribute for the next token.\n let nextAttributeName = tokens[0]?.toLowerCase() as keyof NodeAttributes;\n\n // Pull attribute tokens as well as their arguments off of the tokens stack until we have no more.\n while (nodeAttributeNames.includes(nextAttributeName)) {\n // Check to make sure that we have not already created an attribute definition of this type.\n if (attributes[nextAttributeName]) {\n throw new Error(`duplicate attribute '${tokens[0].toUpperCase()}' found for node`);\n }\n\n // Remove the attribute name token from the array of tokens.\n tokens.shift();\n\n // Grab the attribute arguments, assuming the first to be an identifier.\n const [attributeCallIdentifier, ...attributeArguments] = parseArgumentTokens(\n tokens,\n stringArgumentPlaceholders\n );\n\n // The first attribute argument has to be an identifer, this will reference an agent function.\n if (attributeCallIdentifier?.type !== \"identifier\") {\n throw new Error(\"expected agent function name identifier argument for attribute\");\n }\n\n // Any attribute arguments (other than the expected call identifier) must have a type of string, number, boolean or null.\n attributeArguments\n .filter((arg) => arg.type === \"identifier\")\n .forEach((arg) => {\n throw new Error(\n `invalid attribute argument value '${arg.value}', must be string, number, boolean or null`\n );\n });\n\n // Create the attribute definition and add it to the object of attribute definitions found.\n attributes[nextAttributeName] = {\n call: attributeCallIdentifier.value,\n args: attributeArguments.map(({ value }) => value)\n };\n\n // Try to get the next attribute name token, as there could be multiple.\n nextAttributeName = tokens[0]?.toLowerCase() as keyof NodeAttributes;\n }\n\n return attributes;\n}\n", "import {\n ActionNodeDefinition,\n AnyChildNodeDefinition,\n AnyNodeDefinition,\n BranchNodeDefinition,\n ConditionNodeDefinition,\n FailNodeDefinition,\n FlipNodeDefinition,\n LottoNodeDefinition,\n ParallelNodeDefinition,\n RepeatNodeDefinition,\n RetryNodeDefinition,\n RootNodeDefinition,\n SelectorNodeDefinition,\n SequenceNodeDefinition,\n SucceedNodeDefinition,\n WaitNodeDefinition\n} from \"../BehaviourTreeDefinition\";\nimport {\n isCompositeNode,\n isDecoratorNode,\n isLeafNode,\n isNullOrUndefined,\n isRootNode\n} from \"../BehaviourTreeDefinitionUtilities\";\nimport { parseArgumentTokens } from \"./MDSLNodeArgumentParser\";\nimport { parseAttributeTokens } from \"./MDSLNodeAttributeParser\";\nimport {\n StringLiteralPlaceholders,\n parseTokensFromDefinition,\n popAndCheck,\n substituteStringLiterals\n} from \"./MDSLUtilities\";\n\n/**\n * Convert the MDSL tree definition string into an equivalent JSON definition.\n * @param definition The tree definition string as MDSL.\n * @returns The root node JSON definitions.\n */\nexport function convertMDSLToJSON(definition: string): RootNodeDefinition[] {\n // Swap out any node/attribute argument string literals with a placeholder and get a mapping of placeholders to original values as well as the processed definition.\n const { placeholders, processedDefinition } = substituteStringLiterals(definition);\n\n // Parse our definition definition string into an array of raw tokens.\n const tokens = parseTokensFromDefinition(processedDefinition);\n\n return convertTokensToJSONDefinition(tokens, placeholders);\n}\n\n/**\n * Converts the specified tree definition tokens into a JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The root node JSON definitions.\n */\nfunction convertTokensToJSONDefinition(\n tokens: string[],\n stringLiteralPlaceholders: StringLiteralPlaceholders\n): RootNodeDefinition[] {\n // There must be at least 3 tokens for the tree definition to be valid. 'ROOT', '{' and '}'.\n if (tokens.length < 3) {\n throw new Error(\"invalid token count\");\n }\n\n // We should have a matching number of '{' and '}' tokens. If not, then there are scopes that have not been properly closed.\n if (tokens.filter((token) => token === \"{\").length !== tokens.filter((token) => token === \"}\").length) {\n throw new Error(\"scope character mismatch\");\n }\n\n // Create an array of tree stack arrays where root nodes will always be at the botton and the current composite/decorator node at the top.\n // There should be an element in this array for every root node defined and every element should be an array with a root note as the first element.\n // E.g. A definition with two root nodes defined:\n // [\n // [root, lotto, sequence],\n // [root, selector]\n // ]\n const treeStacks: [Partial, ...Partial[]][] = [];\n\n // Create an array of all root node definitions that we create.\n const rootNodes: Partial[] = [];\n\n // A helper function used to push node definitions onto the tree stack.\n const pushNode = (node: AnyNodeDefinition) => {\n // If the node is a root node then we need to create a new tree stack array with the root node at the root.\n if (isRootNode(node)) {\n // We need to double-check that this root node is not the child of another node.\n // We can do this by checking whether the top tree stack is not empty (contains an existing node)\n if (treeStacks[treeStacks.length - 1]?.length) {\n throw new Error(\"a root node cannot be the child of another node\");\n }\n\n // Add the root node definition to our array of all parsed root node definitions.\n rootNodes.push(node);\n\n // Add the root node definition to the root of a new tree stack.\n treeStacks.push([node]);\n\n return;\n }\n\n // All non-root nodes should be pushed after their root nodes so handle cases\n // where we may not have any tree stacks or our top-most tree stack is empty.\n if (!treeStacks.length || !treeStacks[treeStacks.length - 1].length) {\n throw new Error(\"expected root node at base of definition\");\n }\n\n // Get the current tree stack that we are populating.\n const topTreeStack = treeStacks[treeStacks.length - 1];\n\n // Get the top-most node in the current tree stack, this will be a composite/decorator node\n // for which we will populate its children array if composite or setting its child if a decorator.\n const topTreeStackTopNode = topTreeStack[topTreeStack.length - 1] as AnyNodeDefinition;\n\n // If the top-most node in the current root stack is a composite or decorator\n // node then the current node should be added as a child of the top-most node.\n if (isCompositeNode(topTreeStackTopNode)) {\n topTreeStackTopNode.children = topTreeStackTopNode.children || [];\n topTreeStackTopNode.children.push(node);\n } else if (isDecoratorNode(topTreeStackTopNode)) {\n // If the top node already has a child node set then throw an error as a decorator should only have a single child.\n if (topTreeStackTopNode.child) {\n throw new Error(\"a decorator node must only have a single child node\");\n }\n\n topTreeStackTopNode.child = node;\n }\n\n // If the node we are adding is also a composite or decorator node, then we should push it\n // onto the current tree stack, as subsequent nodes will be added as its child/children.\n if (!isLeafNode(node)) {\n topTreeStack.push(node);\n }\n };\n\n // A helper function used to pop the top-most node definition off of the tree stack and return it.\n const popNode = (): AnyNodeDefinition | null => {\n let poppedNode: AnyNodeDefinition | null = null;\n\n // Get the current tree stack that we are populating.\n const topTreeStack = treeStacks[treeStacks.length - 1];\n\n // Pop the top-most node in the current tree stack if there is one.\n if (topTreeStack.length) {\n poppedNode = topTreeStack.pop() as AnyNodeDefinition;\n }\n\n // We don't want any empty tree stacks in our stack of tree stacks.\n if (!topTreeStack.length) {\n treeStacks.pop();\n }\n\n return poppedNode;\n };\n\n // We should keep processing the raw tokens until we run out of them.\n while (tokens.length) {\n // Grab the next token.\n const token = tokens.shift()!;\n\n // How we create the next node depends on the current raw token value.\n switch (token.toUpperCase()) {\n case \"ROOT\": {\n pushNode(createRootNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"SUCCEED\": {\n pushNode(createSucceedNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"FAIL\": {\n pushNode(createFailNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"FLIP\": {\n pushNode(createFlipNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"REPEAT\": {\n pushNode(createRepeatNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"RETRY\": {\n pushNode(createRetryNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"SEQUENCE\": {\n pushNode(createSequenceNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"SELECTOR\": {\n pushNode(createSelectorNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"PARALLEL\": {\n pushNode(createParallelNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"LOTTO\": {\n pushNode(createLottoNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"ACTION\": {\n pushNode(createActionNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"CONDITION\": {\n pushNode(createConditionNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"WAIT\": {\n pushNode(createWaitNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"BRANCH\": {\n pushNode(createBranchNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"}\": {\n // The '}' character closes the current scope and means that we have to pop a node off of the current stack.\n const poppedNode = popNode();\n\n // Now that we have a node definition we can carry out any validation that may require the node to be fully populated.\n if (poppedNode) {\n validatePoppedNode(poppedNode);\n }\n\n break;\n }\n\n default: {\n throw new Error(`unexpected token: ${token}`);\n }\n }\n }\n\n return rootNodes as RootNodeDefinition[];\n}\n\n/**\n * Creates a root node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The root node JSON definition.\n */\nfunction createRootNode(tokens: string[], stringLiteralPlaceholders: StringLiteralPlaceholders): RootNodeDefinition {\n // Create the root node definition.\n let node = {\n type: \"root\",\n id: undefined\n } as RootNodeDefinition;\n\n // Parse any node arguments, we should only have one if any which will be an identifier argument for the root identifier.\n const nodeArguments = parseArgumentTokens(tokens, stringLiteralPlaceholders);\n\n // Check whether any node arguments were defined.\n if (nodeArguments.length) {\n // We should only have one argument, if any, which will be an identifier argument for the root identifier.\n if (nodeArguments.length === 1 && nodeArguments[0].type === \"identifier\") {\n // The root node identifier will be the first and only node argument value.\n node.id = nodeArguments[0].value as string;\n } else {\n throw new Error(\"expected single root name argument\");\n }\n }\n\n // Grab any node attribute definitions and spread them into the node definition.\n node = { ...node, ...parseAttributeTokens(tokens, stringLiteralPlaceholders) };\n\n // This is a decorator node, so we expect an opening '{'.\n popAndCheck(tokens, \"{\");\n\n // Return the root node definition.\n return node;\n}\n\n/**\n * Creates a succeed node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The succeed node JSON definition.\n */\nfunction createSucceedNode(\n tokens: string[],\n stringLiteralPlaceholders: StringLiteralPlaceholders\n): SucceedNodeDefinition {\n const node = {\n type: \"succeed\",\n ...parseAttributeTokens(tokens, stringLiteralPlaceholders)\n } as SucceedNodeDefinition;\n\n // This is a decorator node, so we expect an opening '{'.\n popAndCheck(tokens, \"{\");\n\n // Return the succeed node definition.\n return node;\n}\n\n/**\n * Creates a fail node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The fail node JSON definition.\n */\nfunction createFailNode(tokens: string[], stringLiteralPlaceholders: StringLiteralPlaceholders): FailNodeDefinition {\n const node = {\n type: \"fail\",\n ...parseAttributeTokens(tokens, stringLiteralPlaceholders)\n } as FailNodeDefinition;\n\n // This is a decorator node, so we expect an opening '{'.\n popAndCheck(tokens, \"{\");\n\n // Return the fail node definition.\n return node;\n}\n\n/**\n * Creates a flip node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The flip node JSON definition.\n */\nfunction createFlipNode(tokens: string[], stringLiteralPlaceholders: StringLiteralPlaceholders): FlipNodeDefinition {\n const node = {\n type: \"flip\",\n ...parseAttributeTokens(tokens, stringLiteralPlaceholders)\n } as FlipNodeDefinition;\n\n // This is a decorator node, so we expect an opening '{'.\n popAndCheck(tokens, \"{\");\n\n // Return the flip node definition.\n return node;\n}\n\n/**\n * Creates a repeat node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The repeat node JSON definition.\n */\nfunction createRepeatNode(\n tokens: string[],\n stringLiteralPlaceholders: StringLiteralPlaceholders\n): RepeatNodeDefinition {\n let node = { type: \"repeat\" } as RepeatNodeDefinition;\n\n // Get the node arguments.\n const nodeArguments = parseArgumentTokens(tokens, stringLiteralPlaceholders);\n\n // The arguments of a repeat node are optional. We may have:\n // - No node arguments, in which case the repeat note will iterate indefinitely.\n // - One node argument which will be the explicit number of iterations to make.\n // - Two node arguments which define the min and max iteration bounds from which a random iteration count will be picked.\n if (nodeArguments.length) {\n // All repeat node arguments MUST be of type number and must be integer.\n nodeArguments\n .filter((arg) => arg.type !== \"number\" || !arg.isInteger)\n .forEach(() => {\n throw new Error(`repeat node iteration counts must be integer values`);\n });\n\n // We should have got one or two iteration counts.\n if (nodeArguments.length === 1) {\n // A static iteration count was defined.\n node.iterations = nodeArguments[0].value as number;\n\n // A repeat node must have a positive number of iterations if defined.\n if (node.iterations < 0) {\n throw new Error(\"a repeat node must have a positive number of iterations if defined\");\n }\n } else if (nodeArguments.length === 2) {\n // A minimum and maximum iteration count was defined.\n node.iterations = [nodeArguments[0].value as number, nodeArguments[1].value as number];\n\n // A repeat node must have a positive min and max iteration count if they are defined.\n if (node.iterations[0] < 0 || node.iterations[1] < 0) {\n throw new Error(\"a repeat node must have a positive minimum and maximum iteration count if defined\");\n }\n\n // A repeat node must not have an minimum iteration count that exceeds the maximum iteration count.\n if (node.iterations[0] > node.iterations[1]) {\n throw new Error(\n \"a repeat node must not have a minimum iteration count that exceeds the maximum iteration count\"\n );\n }\n } else {\n // An incorrect number of iteration counts was defined.\n throw new Error(\"invalid number of repeat node iteration count arguments defined\");\n }\n }\n\n // Grab any node attribute definitions and spread them into the node definition.\n node = { ...node, ...parseAttributeTokens(tokens, stringLiteralPlaceholders) };\n\n // This is a decorator node, so we expect an opening '{'.\n popAndCheck(tokens, \"{\");\n\n // Return the repeat node definition.\n return node;\n}\n\n/**\n * Creates a retry node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The retry node JSON definition.\n */\nfunction createRetryNode(tokens: string[], stringLiteralPlaceholders: StringLiteralPlaceholders): RetryNodeDefinition {\n let node = { type: \"retry\" } as RetryNodeDefinition;\n\n // Get the node arguments.\n const nodeArguments = parseArgumentTokens(tokens, stringLiteralPlaceholders);\n\n // The arguments of a retry node are optional. We may have:\n // - No node arguments, in which case the retry note will attempt indefinitely.\n // - One node argument which will be the explicit number of attempts to make.\n // - Two node arguments which define the min and max attempt bounds from which a random attempt count will be picked.\n if (nodeArguments.length) {\n // All retry node arguments MUST be of type number and must be integer.\n nodeArguments\n .filter((arg) => arg.type !== \"number\" || !arg.isInteger)\n .forEach(() => {\n throw new Error(`retry node attempt counts must be integer values`);\n });\n\n // We should have got one or two attempt counts.\n if (nodeArguments.length === 1) {\n // A static attempt count was defined.\n node.attempts = nodeArguments[0].value as number;\n\n // A retry node must have a positive number of attempts if defined.\n if (node.attempts < 0) {\n throw new Error(\"a retry node must have a positive number of attempts if defined\");\n }\n } else if (nodeArguments.length === 2) {\n // A minimum and maximum attempt count was defined.\n node.attempts = [nodeArguments[0].value as number, nodeArguments[1].value as number];\n\n // A retry node must have a positive min and max attempts count if they are defined.\n if (node.attempts[0] < 0 || node.attempts[1] < 0) {\n throw new Error(\"a retry node must have a positive minimum and maximum attempt count if defined\");\n }\n\n // A retry node must not have a minimum attempt count that exceeds the maximum attempt count.\n if (node.attempts[0] > node.attempts[1]) {\n throw new Error(\n \"a retry node must not have a minimum attempt count that exceeds the maximum attempt count\"\n );\n }\n } else {\n // An incorrect number of attempt counts was defined.\n throw new Error(\"invalid number of retry node attempt count arguments defined\");\n }\n }\n\n // Grab any node attribute definitions and spread them into the node definition.\n node = { ...node, ...parseAttributeTokens(tokens, stringLiteralPlaceholders) };\n\n // This is a decorator node, so we expect an opening '{'.\n popAndCheck(tokens, \"{\");\n\n // Return the retry node definition.\n return node;\n}\n\n/**\n * Creates a sequence node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The sequence node JSON definition.\n */\nfunction createSequenceNode(\n tokens: string[],\n stringLiteralPlaceholders: StringLiteralPlaceholders\n): SequenceNodeDefinition {\n const node = {\n type: \"sequence\",\n ...parseAttributeTokens(tokens, stringLiteralPlaceholders)\n } as SequenceNodeDefinition;\n\n // This is a composite node, so we expect an opening '{'.\n popAndCheck(tokens, \"{\");\n\n // Return the sequence node definition.\n return node;\n}\n\n/**\n * Creates a selector node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The selector node JSON definition.\n */\nfunction createSelectorNode(\n tokens: string[],\n stringLiteralPlaceholders: StringLiteralPlaceholders\n): SelectorNodeDefinition {\n const node = {\n type: \"selector\",\n ...parseAttributeTokens(tokens, stringLiteralPlaceholders)\n } as SelectorNodeDefinition;\n\n // This is a composite node, so we expect an opening '{'.\n popAndCheck(tokens, \"{\");\n\n // Return the selector node definition.\n return node;\n}\n\n/**\n * Creates a parallel node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The parallel node JSON definition.\n */\nfunction createParallelNode(\n tokens: string[],\n stringLiteralPlaceholders: StringLiteralPlaceholders\n): ParallelNodeDefinition {\n const node = {\n type: \"parallel\",\n ...parseAttributeTokens(tokens, stringLiteralPlaceholders)\n } as ParallelNodeDefinition;\n\n // This is a composite node, so we expect an opening '{'.\n popAndCheck(tokens, \"{\");\n\n // Return the parallel node definition.\n return node;\n}\n\n/**\n * Creates a lotto node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The lotto node JSON definition.\n */\nfunction createLottoNode(tokens: string[], stringLiteralPlaceholders: StringLiteralPlaceholders): LottoNodeDefinition {\n // If any node arguments have been defined then they must be our weights.\n const nodeArguments = parseArgumentTokens(tokens, stringLiteralPlaceholders);\n\n // All lotto node arguments MUST be of type number and must be integer.\n nodeArguments\n .filter((arg) => arg.type !== \"number\" || !arg.isInteger)\n .forEach(() => {\n throw new Error(`lotto node weight arguments must be integer values`);\n });\n\n const node = {\n type: \"lotto\",\n weights: nodeArguments.map(({ value }) => value),\n ...parseAttributeTokens(tokens, stringLiteralPlaceholders)\n } as LottoNodeDefinition;\n\n // This is a composite node, so we expect an opening '{'.\n popAndCheck(tokens, \"{\");\n\n // Return the lotto node definition.\n return node;\n}\n\n/**\n * Creates an action node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The action node JSON definition.\n */\nfunction createActionNode(\n tokens: string[],\n stringLiteralPlaceholders: StringLiteralPlaceholders\n): ActionNodeDefinition {\n // Parse any node arguments, we should have at least one which will be an identifier argument for the action name\n // and agent function to invoke for the action, all other arguments are to be passed as arguments to that function.\n const [actionNameIdentifier, ...agentFunctionArgs] = parseArgumentTokens(tokens, stringLiteralPlaceholders);\n\n // Our first argument MUST be defined and be an identifier as we require an action name argument.\n if (actionNameIdentifier?.type !== \"identifier\") {\n throw new Error(\"expected action name identifier argument\");\n }\n\n // Only the first argument should have been an identifier, all agent function arguments must be string, number, boolean or null.\n agentFunctionArgs\n .filter((arg) => arg.type === \"identifier\")\n .forEach((arg) => {\n throw new Error(\n `invalid action node argument value '${arg.value}', must be string, number, boolean or null`\n );\n });\n\n // Return the action node definition.\n return {\n type: \"action\",\n call: actionNameIdentifier.value,\n args: agentFunctionArgs.map(({ value }) => value),\n ...parseAttributeTokens(tokens, stringLiteralPlaceholders)\n };\n}\n\n/**\n * Creates a condition node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The condition node JSON definition.\n */\nfunction createConditionNode(\n tokens: string[],\n stringLiteralPlaceholders: StringLiteralPlaceholders\n): ConditionNodeDefinition {\n // Parse any node arguments, we should have at least one which will be an identifier argument for the condition name\n // and agent function to invoke for the condition, all other arguments are to be passed as arguments to that function.\n const [conditionNameIdentifier, ...agentFunctionArgs] = parseArgumentTokens(tokens, stringLiteralPlaceholders);\n\n // Our first argument MUST be defined and be an identifier as we require a condition name argument.\n if (conditionNameIdentifier?.type !== \"identifier\") {\n throw new Error(\"expected condition name identifier argument\");\n }\n\n // Only the first argument should have been an identifier, all agent function arguments must be string, number, boolean or null.\n agentFunctionArgs\n .filter((arg) => arg.type === \"identifier\")\n .forEach((arg) => {\n throw new Error(\n `invalid condition node argument value '${arg.value}', must be string, number, boolean or null`\n );\n });\n\n // Return the condition node definition.\n return {\n type: \"condition\",\n call: conditionNameIdentifier.value,\n args: agentFunctionArgs.map(({ value }) => value),\n ...parseAttributeTokens(tokens, stringLiteralPlaceholders)\n };\n}\n\n/**\n * Creates a wait node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The wait node JSON definition.\n */\nfunction createWaitNode(tokens: string[], stringLiteralPlaceholders: StringLiteralPlaceholders): WaitNodeDefinition {\n let node = { type: \"wait\" } as WaitNodeDefinition;\n\n // Get the node arguments.\n const nodeArguments = parseArgumentTokens(tokens, stringLiteralPlaceholders);\n\n // The arguments of a wait node are optional. We may have:\n // - No node arguments, in which case the wait will be indefinite until it is aborted.\n // - One node argument which will be the explicit duration of the wait.\n // - Two node arguments which define the min and max duration bounds from which a random duration will be picked.\n if (nodeArguments.length) {\n // All wait node arguments MUST be of type number and must be integer.\n nodeArguments\n .filter((arg) => arg.type !== \"number\" || !arg.isInteger)\n .forEach(() => {\n throw new Error(`wait node durations must be integer values`);\n });\n\n // We may have:\n // - One node argument which will be the explicit duration of the wait.\n // - Two node arguments which define the min and max duration bounds from which a random duration will be picked.\n // - Too many arguments, which is not valid.\n if (nodeArguments.length === 1) {\n // An explicit duration was defined.\n node.duration = nodeArguments[0].value as number;\n\n // If an explict duration was defined then it must be a positive number.\n if (node.duration < 0) {\n throw new Error(\"a wait node must have a positive duration\");\n }\n } else if (nodeArguments.length === 2) {\n // Min and max duration bounds were defined from which a random duration will be picked.\n node.duration = [nodeArguments[0].value as number, nodeArguments[1].value as number];\n\n // A wait node must have a positive min and max duration.\n if (node.duration[0] < 0 || node.duration[1] < 0) {\n throw new Error(\"a wait node must have a positive minimum and maximum duration\");\n }\n\n // A wait node must not have a minimum duration that exceeds the maximum duration.\n if (node.duration[0] > node.duration[1]) {\n throw new Error(\"a wait node must not have a minimum duration that exceeds the maximum duration\");\n }\n } else if (nodeArguments.length > 2) {\n // An incorrect number of duration arguments were defined.\n throw new Error(\"invalid number of wait node duration arguments defined\");\n }\n }\n\n // Return the wait node definition.\n return { ...node, ...parseAttributeTokens(tokens, stringLiteralPlaceholders) };\n}\n\n/**\n * Creates a branch node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The branch node JSON definition.\n */\nfunction createBranchNode(\n tokens: string[],\n stringLiteralPlaceholders: StringLiteralPlaceholders\n): BranchNodeDefinition {\n // Parse any node arguments, we should have one which will be an identifier argument for the root ref.\n const nodeArguments = parseArgumentTokens(tokens, stringLiteralPlaceholders);\n\n // We should have only a single identifer argument for a branch node, which is the root ref.\n if (nodeArguments.length !== 1 || nodeArguments[0].type !== \"identifier\") {\n throw new Error(\"expected single branch name argument\");\n }\n\n // Return the branch node definition.\n return { type: \"branch\", ref: nodeArguments[0].value };\n}\n\n/**\n * Validate a fully-populated node definition that was popped off of the tree stack.\n * @param node The popped node to validate.\n */\nfunction validatePoppedNode(node: AnyNodeDefinition): void {\n // Decorators MUST have a child defined.\n if (isDecoratorNode(node) && isNullOrUndefined(node.child)) {\n throw new Error(`a ${node.type} node must have a single child node defined`);\n }\n\n // Composites MUST have at least one child defined.\n if (isCompositeNode(node) && !node.children?.length) {\n throw new Error(`a ${node.type} node must have at least a single child node defined`);\n }\n}\n", "import { RootNodeDefinition } from \"./BehaviourTreeDefinition\";\nimport { flattenDefinition, isBranchNode, isInteger } from \"./BehaviourTreeDefinitionUtilities\";\nimport { convertMDSLToJSON } from \"./mdsl/MDSLDefinitionParser\";\n\n/**\n * An object representing the result of validating a tree definition.\n */\nexport type DefinitionValidationResult = {\n /**\n * A flag defining whether validation succeeded.\n */\n succeeded: boolean;\n /**\n * A string containing the error message if validation did not succeed.\n */\n errorMessage?: string;\n};\n\n/**\n * Validates the specified behaviour tree definition in the form of JSON or MDSL, not taking any globally registered subtrees into consideration.\n * @param definition The behaviour tree definition in the form of JSON or MDSL.\n * @returns An object representing the result of validating the given tree definition.\n */\nexport function validateDefinition(definition: any): DefinitionValidationResult {\n // The definition must be defined.\n if (definition === null || typeof definition === \"undefined\") {\n return createValidationFailureResult(\"definition is null or undefined\");\n }\n\n // We are expecting a definition in one of three different forms:\n // - A string which we will assume is MDSL and we will parse this to JSON before validation.\n // - An array which we will assume is an array of root node definitions with at least one being the primary root node (no 'id' property)\n // - An object which we will assume is the primary root node and should not have an 'id' property.\n if (typeof definition === \"string\") {\n // The definition is a string which we can assume is MDSL, so attempt to validate it.\n return validateMDSLDefinition(definition);\n } else if (typeof definition === \"object\") {\n // The definition will either be an array (of root node definitions) or an object (the single primary root node definition).\n return validateJSONDefinition(definition);\n } else {\n return createValidationFailureResult(`unexpected definition type of '${typeof definition}'`);\n }\n}\n\n/**\n * Validates the specified behaviour tree definition in the form of MDSL.\n * @param definition The behaviour tree definition in the form of MDSL.\n * @returns An object representing the result of validating the given tree definition.\n */\nexport function validateMDSLDefinition(definition: string): DefinitionValidationResult {\n let rootNodeDefinitions;\n\n // The first thing the we need to do is to attempt to convert our MDSL into JSON.\n try {\n // The definition is a string which we can assume is MDSL, so attempt to parse it to a JSON definition in the form of an array of root node definitions.\n rootNodeDefinitions = convertMDSLToJSON(definition);\n } catch (exception) {\n // We failed to parse the JSON from the MDSL, this is likely to be the result of it not being a valid MDSL string.\n return createValidationFailureResult((exception as Error).message);\n }\n\n // Unpack all of the root node definitions into arrays of main ('id' defined) and sub ('id' not defined) root node definitions.\n const mainRootNodeDefinitions = rootNodeDefinitions.filter(({ id }) => typeof id === \"undefined\");\n const subRootNodeDefinitions = rootNodeDefinitions.filter(({ id }) => typeof id === \"string\" && id.length > 0);\n\n // We should ALWAYS have exactly one root node definition without an 'id' property defined, which is out main root node definition.\n if (mainRootNodeDefinitions.length !== 1) {\n return createValidationFailureResult(\n \"expected single unnamed root node at base of definition to act as main root\"\n );\n }\n\n // We should never have duplicate 'id' properties across our sub root node definitions.\n const subRootNodeIdenitifers: string[] = [];\n for (const { id } of subRootNodeDefinitions) {\n // Have we already come across this 'id' property value?\n if (subRootNodeIdenitifers.includes(id!)) {\n return createValidationFailureResult(`multiple root nodes found with duplicate name '${id}'`);\n }\n\n subRootNodeIdenitifers.push(id!);\n }\n\n try {\n // Validate our branch -> subtree links and check for any circular dependencies, we don't care about checking for broken subtree links here.\n validateBranchSubtreeLinks(rootNodeDefinitions, false);\n } catch (exception) {\n return createValidationFailureResult((exception as Error).message);\n }\n\n // Our definition was valid!\n return { succeeded: true };\n}\n\n/**\n * Validates the specified behaviour tree definition in the form of JSON.\n * @param definition The behaviour tree definition in the form of JSON.\n * @returns An object representing the result of validating the given tree definition.\n */\nexport function validateJSONDefinition(\n definition: RootNodeDefinition | RootNodeDefinition[]\n): DefinitionValidationResult {\n // The definition will either be an array (of root node definitions) or an object (the single primary root node definition).\n const rootNodeDefinitions = Array.isArray(definition) ? definition : [definition];\n\n // Iterate over our array of root nodes and call validateNode for each, passing an initial depth of 0, wrapped in a try catch to handle validation failures.\n try {\n rootNodeDefinitions.forEach((rootNodeDefinition) => validateNode(rootNodeDefinition, 0));\n } catch (error) {\n // Handle cases where we have caught a thrown Error and return a failure result with the error message.\n if (error instanceof Error) {\n return createValidationFailureResult(error.message);\n }\n\n // No idea what happened here!\n return createValidationFailureResult(`unexpected error: ${error}`);\n }\n\n // Unpack all of the root node definitions into arrays of main ('id' defined) and sub ('id' not defined) root node definitions.\n const mainRootNodeDefinitions = rootNodeDefinitions.filter(({ id }) => typeof id === \"undefined\");\n const subRootNodeDefinitions = rootNodeDefinitions.filter(({ id }) => typeof id === \"string\" && id.length > 0);\n\n // We should ALWAYS have exactly one root node definition without an 'id' property defined, which is out main root node definition.\n if (mainRootNodeDefinitions.length !== 1) {\n return createValidationFailureResult(\n \"expected single root node without 'id' property defined to act as main root\"\n );\n }\n\n // We should never have duplicate 'id' properties across our sub root node definitions.\n const subRootNodeIdenitifers: string[] = [];\n for (const { id } of subRootNodeDefinitions) {\n // Have we already come across this 'id' property value?\n if (subRootNodeIdenitifers.includes(id!)) {\n return createValidationFailureResult(\n `multiple root nodes found with duplicate 'id' property value of '${id}'`\n );\n }\n\n subRootNodeIdenitifers.push(id!);\n }\n\n try {\n // Validate our branch -> subtree links and check for any circular dependencies, we don't care about checking for broken subtree links here.\n validateBranchSubtreeLinks(rootNodeDefinitions, false);\n } catch (exception) {\n return createValidationFailureResult((exception as Error).message);\n }\n\n // Our definition was valid!\n return { succeeded: true };\n}\n\n/**\n * Validates the branch -> subtree links across all provided root node definitions.\n * This will not consider branch nodes that reference any globally registered subtrees unless includesGlobalSubtrees\n * is set to true, in which case we will also verify that there are no broken branch -> subtree links.\n * @param rootNodeDefinitions The array of root node definitions.\n * @param includesGlobalSubtrees A flag defining whether the array includes all global subtree root node definitions.\n */\nexport function validateBranchSubtreeLinks(rootNodeDefinitions: RootNodeDefinition[], includesGlobalSubtrees: boolean) {\n // Create a mapping of root node identifiers to other root nodes that they reference via branch nodes.\n // Below is an example of a mapping that includes a circular dependency (root => a => b => c => a)\n // [{ refs: [\"a\", \"b\"] }, { id: \"a\", refs: [\"b\"] }, { id: \"b\", refs: [\"c\"] }, { id: \"c\", refs: [\"a\"] }]\n const rootNodeMappings: { id: string | undefined; refs: string[] }[] = rootNodeDefinitions.map(\n (rootNodeDefinition) => ({\n id: rootNodeDefinition.id,\n refs: flattenDefinition(rootNodeDefinition)\n .filter(isBranchNode)\n .map(({ ref }) => ref)\n })\n );\n\n // A recursive function to walk through the mappings, keeping track of which root nodes we have visited in the form of a path of root node identifiers.\n const followRefs = (mapping: { id: string | undefined; refs: string[] }, path: (string | undefined)[] = []) => {\n // Have we found a circular dependency?\n if (path.includes(mapping.id)) {\n // We found a circular dependency! Get the bad path of root node identifiers.\n const badPath = [...path, mapping.id];\n\n // Create the formatted path value. [undefined, \"a\", \"b\", \"c\", \"a\"] would be formatted as \"a -> b -> c -> a\".\n const badPathFormatted = badPath.filter((element) => !!element).join(\" => \");\n\n // No need to continue, we found a circular dependency.\n throw new Error(`circular dependency found in branch node references: ${badPathFormatted}`);\n }\n\n for (const ref of mapping.refs) {\n // Find the mapping for the root node with an identifer matching the current ref.\n const subMapping = rootNodeMappings.find(({ id }) => id === ref);\n\n // We may not have a mapping for this ref, which is normal when we aren't considering all globally registered subtrees.\n if (subMapping) {\n followRefs(subMapping, [...path, mapping.id]);\n } else if (includesGlobalSubtrees) {\n // We found a reference to a root node that doesn't exist, which is a problem seeing as the root node definitons includes all globally registered subtrees.\n throw new Error(\n mapping.id\n ? `subtree '${mapping.id}' has branch node that references root node '${ref}' which has not been defined`\n : `primary tree has branch node that references root node '${ref}' which has not been defined`\n );\n }\n }\n };\n\n // Start looking for circular dependencies and broken references from the primary root node definition.\n followRefs(rootNodeMappings.find((mapping) => typeof mapping.id === \"undefined\")!);\n}\n\n/**\n * Validate an object that we expect to be a node definition.\n * @param definition An object that we expect to be a node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateNode(definition: any, depth: number): void {\n // Every node must be valid object and have a non-empty 'type' string property.\n if (typeof definition !== \"object\" || typeof definition.type !== \"string\" || definition.type.length === 0) {\n throw new Error(\n `node definition is not an object or 'type' property is not a non-empty string at depth '${depth}'`\n );\n }\n\n // How we validate this node definition will depend on its type.\n switch (definition.type) {\n case \"action\":\n validateActionNode(definition, depth);\n break;\n\n case \"condition\":\n validateConditionNode(definition, depth);\n break;\n\n case \"wait\":\n validateWaitNode(definition, depth);\n break;\n\n case \"branch\":\n validateBranchNode(definition, depth);\n break;\n\n case \"root\":\n validateRootNode(definition, depth);\n break;\n\n case \"success\":\n validateSuccessNode(definition, depth);\n break;\n\n case \"fail\":\n validateFailNode(definition, depth);\n break;\n\n case \"flip\":\n validateFlipNode(definition, depth);\n break;\n\n case \"repeat\":\n validateRepeatNode(definition, depth);\n break;\n\n case \"retry\":\n validateRetryNode(definition, depth);\n break;\n\n case \"sequence\":\n validateSequenceNode(definition, depth);\n break;\n\n case \"selector\":\n validateSelectorNode(definition, depth);\n break;\n\n case \"parallel\":\n validateParallelNode(definition, depth);\n break;\n\n default:\n throw new Error(`unexpected node type of '${definition.type}' at depth '${depth}'`);\n }\n}\n\n/**\n * Validate any attributes for a given node definition.\n * @param definition The node definition.\n * @param depth The depth of the node in the behaviour tree definition.\n */\nfunction validateNodeAttributes(definition: any, depth: number): void {\n // Validate each of the attribute types for this node.\n [\"while\", \"until\", \"entry\", \"exit\", \"step\"].forEach((attributeName) => {\n // Attempt to grab the definition for the current attribute from the node definition.\n const attributeDefinition = definition[attributeName];\n\n // All node attributes are optional, so there is nothing to do if the current attribute is not defined.\n if (typeof attributeDefinition === \"undefined\") {\n return;\n }\n\n // The attribute definition must be an object.\n if (typeof attributeDefinition !== \"object\") {\n throw new Error(\n `expected attribute '${attributeName}' to be an object for '${definition.type}' node at depth '${depth}'`\n );\n }\n\n // The 'call' property must be defined for any attribute definition.\n if (typeof attributeDefinition.call !== \"string\" || attributeDefinition.call.length === 0) {\n throw new Error(\n `expected 'call' property for attribute '${attributeName}' to be a non-empty string for '${definition.type}' node at depth '${depth}'`\n );\n }\n\n // If any node attribute arguments have been defined then they must have been defined in an array.\n if (typeof attributeDefinition.args !== \"undefined\" && !Array.isArray(attributeDefinition.args)) {\n throw new Error(\n `expected 'args' property for attribute '${attributeName}' to be an array for '${definition.type}' node at depth '${depth}'`\n );\n }\n });\n}\n\n/**\n * Validate an object that we expect to be a root node definition.\n * @param definition An object that we expect to be a root node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateRootNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"root\") {\n throw new Error(\"expected node type of 'root' for root node\");\n }\n\n // A root node cannot be the child of another node.\n if (depth > 0) {\n throw new Error(\"a root node cannot be the child of another node\");\n }\n\n // Check that, if the root node 'id' property is defined, it is a non-empty string.\n if (typeof definition.id !== \"undefined\" && (typeof definition.id !== \"string\" || definition.id.length === 0)) {\n throw new Error(\"expected non-empty string for 'id' property if defined for root node\");\n }\n\n // A root node is a decorator node, so must have a child node defined.\n if (typeof definition.child === \"undefined\") {\n throw new Error(\"expected property 'child' to be defined for root node\");\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n\n // Validate the child node of this decorator node.\n validateNode(definition.child, depth + 1);\n}\n\n/**\n * Validate an object that we expect to be a success node definition.\n * @param definition An object that we expect to be a success node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateSuccessNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"success\") {\n throw new Error(`expected node type of 'success' for success node at depth '${depth}'`);\n }\n\n // A success node is a decorator node, so must have a child node defined.\n if (typeof definition.child === \"undefined\") {\n throw new Error(`expected property 'child' to be defined for success node at depth '${depth}'`);\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n\n // Validate the child node of this decorator node.\n validateNode(definition.child, depth + 1);\n}\n\n/**\n * Validate an object that we expect to be a fail node definition.\n * @param definition An object that we expect to be a fail node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateFailNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"fail\") {\n throw new Error(`expected node type of 'fail' for fail node at depth '${depth}'`);\n }\n\n // A fail node is a decorator node, so must have a child node defined.\n if (typeof definition.child === \"undefined\") {\n throw new Error(`expected property 'child' to be defined for fail node at depth '${depth}'`);\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n\n // Validate the child node of this decorator node.\n validateNode(definition.child, depth + 1);\n}\n\n/**\n * Validate an object that we expect to be a flip node definition.\n * @param definition An object that we expect to be a flip node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateFlipNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"flip\") {\n throw new Error(`expected node type of 'flip' for flip node at depth '${depth}'`);\n }\n\n // A flip node is a decorator node, so must have a child node defined.\n if (typeof definition.child === \"undefined\") {\n throw new Error(`expected property 'child' to be defined for flip node at depth '${depth}'`);\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n\n // Validate the child node of this decorator node.\n validateNode(definition.child, depth + 1);\n}\n\n/**\n * Validate an object that we expect to be a repeat node definition.\n * @param definition An object that we expect to be a repeat node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateRepeatNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"repeat\") {\n throw new Error(`expected node type of 'repeat' for repeat node at depth '${depth}'`);\n }\n\n // A repeat node is a decorator node, so must have a child node defined.\n if (typeof definition.child === \"undefined\") {\n throw new Error(`expected property 'child' to be defined for repeat node at depth '${depth}'`);\n }\n\n // Check whether an 'iterations' property has been defined, it may not have been if this node is to repeat indefinitely.\n if (typeof definition.iterations !== \"undefined\") {\n if (Array.isArray(definition.iterations)) {\n // Check whether any elements of the array are not integer values.\n const containsNonInteger = !!definition.iterations.find((value: unknown) => !isInteger(value));\n\n // If the 'iterations' property is an array then it MUST contain two integer values.\n if (definition.iterations.length !== 2 || containsNonInteger) {\n throw new Error(\n `expected array containing two integer values for 'iterations' property if defined for repeat node at depth '${depth}'`\n );\n }\n\n // A repeat node must have a positive min and max iterations count if they are defined.\n if (definition.iterations[0] < 0 || definition.iterations[1] < 0) {\n throw new Error(\n `expected positive minimum and maximum iterations count for 'iterations' property if defined for repeat node at depth '${depth}'`\n );\n }\n\n // A repeat node must not have a minimum iterations count that exceeds the maximum iterations count.\n if (definition.iterations[0] > definition.iterations[1]) {\n throw new Error(\n `expected minimum iterations count that does not exceed the maximum iterations count for 'iterations' property if defined for repeat node at depth '${depth}'`\n );\n }\n } else if (isInteger(definition.iterations)) {\n // A repeat node must have a positive number of iterations if defined.\n if (definition.iterations < 0) {\n throw new Error(\n `expected positive iterations count for 'iterations' property if defined for repeat node at depth '${depth}'`\n );\n }\n } else {\n throw new Error(\n `expected integer value or array containing two integer values for 'iterations' property if defined for repeat node at depth '${depth}'`\n );\n }\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n\n // Validate the child node of this decorator node.\n validateNode(definition.child, depth + 1);\n}\n\n/**\n * Validate an object that we expect to be a retry node definition.\n * @param definition An object that we expect to be a retry node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateRetryNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"retry\") {\n throw new Error(`expected node type of 'retry' for retry node at depth '${depth}'`);\n }\n\n // A retry node is a decorator node, so must have a child node defined.\n if (typeof definition.child === \"undefined\") {\n throw new Error(`expected property 'child' to be defined for retry node at depth '${depth}'`);\n }\n\n // Check whether an 'attempts' property has been defined, it may not have been if this node is to retry indefinitely.\n if (typeof definition.attempts !== \"undefined\") {\n if (Array.isArray(definition.attempts)) {\n // Check whether any elements of the array are not integer values.\n const containsNonInteger = !!definition.attempts.find((value: unknown) => !isInteger(value));\n\n // If the 'attempts' property is an array then it MUST contain two integer values.\n if (definition.attempts.length !== 2 || containsNonInteger) {\n throw new Error(\n `expected array containing two integer values for 'attempts' property if defined for retry node at depth '${depth}'`\n );\n }\n\n // A retry node must have a positive min and max attempts count if they are defined.\n if (definition.attempts[0] < 0 || definition.attempts[1] < 0) {\n throw new Error(\n `expected positive minimum and maximum attempts count for 'attempts' property if defined for retry node at depth '${depth}'`\n );\n }\n\n // A retry node must not have a minimum attempts count that exceeds the maximum attempts count.\n if (definition.attempts[0] > definition.attempts[1]) {\n throw new Error(\n `expected minimum attempts count that does not exceed the maximum attempts count for 'attempts' property if defined for retry node at depth '${depth}'`\n );\n }\n } else if (isInteger(definition.attempts)) {\n // A retry node must have a positive number of attempts if defined.\n if (definition.attempts < 0) {\n throw new Error(\n `expected positive attempts count for 'attempts' property if defined for retry node at depth '${depth}'`\n );\n }\n } else {\n throw new Error(\n `expected integer value or array containing two integer values for 'attempts' property if defined for retry node at depth '${depth}'`\n );\n }\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n\n // Validate the child node of this decorator node.\n validateNode(definition.child, depth + 1);\n}\n\n/**\n * Validate an object that we expect to be a branch node definition.\n * @param definition An object that we expect to be a branch node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateBranchNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"branch\") {\n throw new Error(`expected node type of 'branch' for branch node at depth '${depth}'`);\n }\n\n // Check that the branch node 'ref' property is defined and is a non-empty string.\n if (typeof definition.ref !== \"string\" || definition.ref.length === 0) {\n throw new Error(`expected non-empty string for 'ref' property for branch node at depth '${depth}'`);\n }\n\n // It is invalid to define guard attributes for a branch node as they should be defined on the referenced root node.\n [\"while\", \"until\"].forEach((attributeName) => {\n if (typeof definition[attributeName] !== \"undefined\") {\n throw new Error(\n `guards should not be defined for branch nodes but guard '${attributeName}' was defined for branch node at depth '${depth}'`\n );\n }\n });\n\n // It is invalid to define callback attributes for a branch node as they should be defined on the referenced root node.\n [\"entry\", \"exit\", \"step\"].forEach((attributeName) => {\n if (typeof definition[attributeName] !== \"undefined\") {\n throw new Error(\n `callbacks should not be defined for branch nodes but callback '${attributeName}' was defined for branch node at depth '${depth}'`\n );\n }\n });\n}\n\n/**\n * Validate an object that we expect to be a action node definition.\n * @param definition An object that we expect to be a action node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateActionNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"action\") {\n throw new Error(`expected node type of 'action' for action node at depth '${depth}'`);\n }\n\n // The 'call' property must be defined for a action node definition.\n if (typeof definition.call !== \"string\" || definition.call.length === 0) {\n throw new Error(`expected non-empty string for 'call' property of action node at depth '${depth}'`);\n }\n\n // If any action function arguments have been defined then they must have been defined in an array.\n if (typeof definition.args !== \"undefined\" && !Array.isArray(definition.args)) {\n throw new Error(`expected array for 'args' property if defined for action node at depth '${depth}'`);\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n}\n\n/**\n * Validate an object that we expect to be a condition node definition.\n * @param definition An object that we expect to be a condition node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateConditionNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"condition\") {\n throw new Error(`expected node type of 'condition' for condition node at depth '${depth}'`);\n }\n\n // The 'call' property must be defined for a condition node definition.\n if (typeof definition.call !== \"string\" || definition.call.length === 0) {\n throw new Error(`expected non-empty string for 'call' property of condition node at depth '${depth}'`);\n }\n\n // If any condition function arguments have been defined then they must have been defined in an array.\n if (typeof definition.args !== \"undefined\" && !Array.isArray(definition.args)) {\n throw new Error(`expected array for 'args' property if defined for condition node at depth '${depth}'`);\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n}\n\n/**\n * Validate an object that we expect to be a wait node definition.\n * @param definition An object that we expect to be a wait node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateWaitNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"wait\") {\n throw new Error(`expected node type of 'wait' for wait node at depth '${depth}'`);\n }\n\n // Check whether a 'duration' property has been defined, it may not have been if this node is to wait indefinitely.\n if (typeof definition.duration !== \"undefined\") {\n if (Array.isArray(definition.duration)) {\n // Check whether any elements of the array are not integer values.\n const containsNonInteger = !!definition.duration.find((value: unknown) => !isInteger(value));\n\n // If the 'duration' property is an array then it MUST contain two integer values.\n if (definition.duration.length !== 2 || containsNonInteger) {\n throw new Error(\n `expected array containing two integer values for 'duration' property if defined for wait node at depth '${depth}'`\n );\n }\n\n // A wait node must have a positive min and max duration value if they are defined.\n if (definition.duration[0] < 0 || definition.duration[1] < 0) {\n throw new Error(\n `expected positive minimum and maximum duration for 'duration' property if defined for wait node at depth '${depth}'`\n );\n }\n\n // A wait node must not have a minimum duration value that exceeds the maximum duration value.\n if (definition.duration[0] > definition.duration[1]) {\n throw new Error(\n `expected minimum duration value that does not exceed the maximum duration value for 'duration' property if defined for wait node at depth '${depth}'`\n );\n }\n } else if (isInteger(definition.duration)) {\n // A wait node must have a positive duration value if defined.\n if (definition.duration < 0) {\n throw new Error(\n `expected positive duration value for 'duration' property if defined for wait node at depth '${depth}'`\n );\n }\n } else {\n throw new Error(\n `expected integer value or array containing two integer values for 'duration' property if defined for wait node at depth '${depth}'`\n );\n }\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n}\n\n/**\n * Validate an object that we expect to be a sequence node definition.\n * @param definition An object that we expect to be a sequence node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateSequenceNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"sequence\") {\n throw new Error(`expected node type of 'sequence' for sequence node at depth '${depth}'`);\n }\n\n // A sequence node is a composite node, so must have a children nodes array defined.\n if (!Array.isArray(definition.children) || definition.children.length === 0) {\n throw new Error(`expected non-empty 'children' array to be defined for sequence node at depth '${depth}'`);\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n\n // Validate the child nodes of this composite node.\n definition.children.forEach((child: any) => validateNode(child, depth + 1));\n}\n\n/**\n * Validate an object that we expect to be a selector node definition.\n * @param definition An object that we expect to be a selector node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateSelectorNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"selector\") {\n throw new Error(`expected node type of 'selector' for selector node at depth '${depth}'`);\n }\n\n // A selector node is a composite node, so must have a children nodes array defined.\n if (!Array.isArray(definition.children) || definition.children.length === 0) {\n throw new Error(`expected non-empty 'children' array to be defined for selector node at depth '${depth}'`);\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n\n // Validate the child nodes of this composite node.\n definition.children.forEach((child: any) => validateNode(child, depth + 1));\n}\n\n/**\n * Validate an object that we expect to be a parallel node definition.\n * @param definition An object that we expect to be a parallel node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateParallelNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"parallel\") {\n throw new Error(`expected node type of 'parallel' for parallel node at depth '${depth}'`);\n }\n\n // A parallel node is a composite node, so must have a children nodes array defined.\n if (!Array.isArray(definition.children) || definition.children.length === 0) {\n throw new Error(`expected non-empty 'children' array to be defined for parallel node at depth '${depth}'`);\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n\n // Validate the child nodes of this composite node.\n definition.children.forEach((child: any) => validateNode(child, depth + 1));\n}\n\n/**\n * A helper function to create a failure validation result with the given error message.\n * @param errorMessage The validation failure error message.\n * @returns A failure validation result with the given error message.\n */\nfunction createValidationFailureResult(errorMessage: string): DefinitionValidationResult {\n return { succeeded: false, errorMessage };\n}\n", "import { ActionResult, Agent, GlobalFunction } from \"./Agent\";\nimport { RootNodeDefinition } from \"./BehaviourTreeDefinition\";\n\nexport type InvokerFunction = (args: any[]) => ActionResult;\n\n/**\n * A singleton used to store and lookup registered functions and subtrees.\n */\nexport default class Lookup {\n /**\n * The object holding any registered functions keyed on function name.\n */\n private static functionTable: { [key: string]: GlobalFunction } = {};\n /**\n * The object holding any registered subtree root node definitions keyed on tree name.\n */\n private static subtreeTable: { [key: string]: RootNodeDefinition } = {};\n\n /**\n * Gets the function with the specified name.\n * @param name The name of the function.\n * @returns The function with the specified name.\n */\n public static getFunc(name: string): GlobalFunction {\n return this.functionTable[name];\n }\n\n /**\n * Sets the function with the specified name for later lookup.\n * @param name The name of the function.\n * @param func The function.\n */\n public static setFunc(name: string, func: GlobalFunction): void {\n this.functionTable[name] = func;\n }\n\n /**\n * Gets the function invoker for the specified agent and function name.\n * If a function with the specified name exists on the agent object then it will\n * be returned, otherwise we will then check the registered functions for a match.\n * @param agent The agent instance that this behaviour tree is modelling behaviour for.\n * @param name The function name.\n * @returns The function invoker for the specified agent and function name.\n */\n static getFuncInvoker(agent: Agent, name: string): InvokerFunction | null {\n // Check whether the agent contains the specified function.\n const foundOnAgent = agent[name];\n if (foundOnAgent && typeof foundOnAgent === \"function\") {\n return (args: any[]): boolean | ActionResult => foundOnAgent.apply(agent, args);\n }\n\n // The agent does not contain the specified function but it may have been registered at some point.\n if (this.functionTable[name] && typeof this.functionTable[name] === \"function\") {\n return (args: any[]) => this.functionTable[name](agent, ...args.map((arg) => arg.value));\n }\n\n // We have no function to invoke.\n return null;\n }\n\n /**\n * Gets all registered subtree root node definitions.\n */\n static getSubtrees(): { [key: string]: RootNodeDefinition } {\n return this.subtreeTable;\n }\n\n /**\n * Sets the subtree with the specified name for later lookup.\n * @param name The name of the subtree.\n * @param subtree The subtree.\n */\n static setSubtree(name: string, subtree: RootNodeDefinition) {\n this.subtreeTable[name] = subtree;\n }\n\n /**\n * Removes the registered function or subtree with the specified name.\n * @param name The name of the registered function or subtree.\n */\n static remove(name: string) {\n delete this.functionTable[name];\n delete this.subtreeTable[name];\n }\n\n /**\n * Remove all registered functions and subtrees.\n */\n static empty() {\n this.functionTable = {};\n this.subtreeTable = {};\n }\n}\n", "import Node from \"../../nodes/Node\";\n\n/**\n * An exception thrown when evaluating node guard path conditions and a conditions fails.\n */\nexport default class GuardUnsatisifedException extends Error {\n /**\n * @param source The node at which a guard condition failed.\n */\n constructor(private source: Node) {\n super(\"A guard path condition has failed\");\n }\n\n /**\n * Gets whether the specified node is the node at which a guard condition failed.\n * @param node The node to check against the source node.\n * @returns Whether the specified node is the node at which a guard condition failed.\n */\n isSourceNode = (node: Node) => node === this.source;\n}\n", "import { Agent } from \"../../Agent\";\nimport Guard from \"./Guard\";\nimport Node from \"../../nodes/Node\";\nimport GuardUnsatisifedException from \"./GuardUnsatisifedException\";\n\nexport type GuardPathPart = {\n node: Node;\n guards: Guard[];\n};\n\n/**\n * Represents a path of node guards along a root-to-leaf tree path.\n */\nexport default class GuardPath {\n /**\n * @param nodes An array of objects defining a node instance -> guard link, ordered by node depth.\n */\n constructor(private nodes: GuardPathPart[]) {}\n\n /**\n * Evaluate guard conditions for all guards in the tree path, moving outwards from the root.\n * @param agent The agent, required for guard evaluation.\n * @returns An evaluation results object.\n */\n evaluate = (agent: Agent) => {\n // We need to evaluate guard conditions for nodes up the tree, moving outwards from the root.\n for (const details of this.nodes) {\n // There can be multiple guards per node.\n for (const guard of details.guards) {\n // Check whether the guard condition passes, and throw an exception if not.\n if (!guard.isSatisfied(agent)) {\n throw new GuardUnsatisifedException(details.node);\n }\n }\n }\n };\n}\n", "import { BehaviourTreeOptions } from \"../BehaviourTreeOptions\";\nimport State, { AnyState } from \"../State\";\nimport { Agent } from \"../Agent\";\nimport Leaf from \"./leaf/Leaf\";\nimport Attribute from \"../attributes/Attribute\";\nimport Entry from \"../attributes/callbacks/Entry\";\nimport Exit from \"../attributes/callbacks/Exit\";\nimport Step from \"../attributes/callbacks/Step\";\nimport Guard from \"../attributes/guards/Guard\";\nimport GuardPath from \"../attributes/guards/GuardPath\";\nimport GuardUnsatisifedException from \"../attributes/guards/GuardUnsatisifedException\";\n\n/**\n * A base node.\n */\nexport default abstract class Node {\n /**\n * The node uid.\n */\n private readonly uid: string = createNodeUid();\n /**\n * The node state.\n */\n private state: AnyState = State.READY;\n /**\n * The guard path to evaluate as part of a node update.\n */\n private guardPath: GuardPath | undefined;\n\n /**\n * @param type The node type.\n * @param attributes The node attributes.\n * @param args The node argument definitions.\n */\n constructor(private type: string, private attributes: Attribute[], private args: any[]) {}\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected abstract onUpdate(agent: Agent, options: BehaviourTreeOptions): void;\n\n /**\n * Gets the name of the node.\n */\n public abstract getName(): string;\n\n /**\n * Gets whether this node is a leaf node.\n */\n public abstract isLeafNode: () => this is Leaf;\n\n /**\n * Gets/Sets the state of the node.\n */\n getState = (): AnyState => this.state;\n setState = (value: AnyState): void => {\n this.state = value;\n };\n\n /**\n * Gets the unique id of the node.\n */\n getUid = () => this.uid;\n\n /**\n * Gets the type of the node.\n */\n getType = () => this.type;\n\n /**\n * Gets the node attributes.\n */\n getAttributes = () => this.attributes;\n\n /**\n * Gets the node arguments.\n */\n getArguments = () => this.args;\n\n /**\n * Gets the node attribute with the specified type, or null if it does not exist.\n */\n getAttribute(type: \"entry\" | \"ENTRY\"): Entry;\n getAttribute(type: \"exit\" | \"EXIT\"): Exit;\n getAttribute(type: \"step\" | \"STEP\"): Step;\n getAttribute(type: string): Attribute {\n return (\n this.getAttributes().filter((decorator) => decorator.type.toUpperCase() === type.toUpperCase())[0] || null\n );\n }\n\n /**\n * Gets the node attributes.\n */\n getGuardAttributes = (): Guard[] => this.getAttributes().filter((decorator) => decorator.isGuard()) as Guard[];\n\n /**\n * Sets the guard path to evaluate as part of a node update.\n */\n setGuardPath = (value: GuardPath) => (this.guardPath = value);\n\n /**\n * Gets whether a guard path is assigned to this node.\n */\n hasGuardPath = () => !!this.guardPath;\n\n /**\n * Gets whether this node is in the specified state.\n * @param value The value to compare to the node state.\n */\n public is(value: AnyState): boolean {\n return this.state === value;\n }\n\n /**\n * Reset the state of the node.\n */\n public reset(): void {\n this.setState(State.READY);\n }\n\n /**\n * Abort the running of this node.\n * @param agent The agent.\n */\n public abort(agent: Agent): void {\n // There is nothing to do if this node is not in the running state.\n if (!this.is(State.RUNNING)) {\n return;\n }\n\n // Reset the state of this node.\n this.reset();\n\n this.getAttribute(\"exit\")?.callAgentFunction(agent, false, true);\n }\n\n /**\n * Update the node.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n * @returns The result of the update.\n */\n public update(agent: Agent, options: BehaviourTreeOptions): void {\n // If this node is already in a 'SUCCEEDED' or 'FAILED' state then there is nothing to do.\n if (this.is(State.SUCCEEDED) || this.is(State.FAILED)) {\n return;\n }\n\n try {\n // Evaluate all of the guard path conditions for the current tree path.\n this.guardPath!.evaluate(agent);\n\n // If this node is in the READY state then call the ENTRY for this node if it exists.\n if (this.is(State.READY)) {\n this.getAttribute(\"entry\")?.callAgentFunction(agent);\n }\n\n this.getAttribute(\"step\")?.callAgentFunction(agent);\n\n // Do the actual update.\n this.onUpdate(agent, options);\n\n // If this node is now in a 'SUCCEEDED' or 'FAILED' state then call the EXIT for this node if it exists.\n if (this.is(State.SUCCEEDED) || this.is(State.FAILED)) {\n this.getAttribute(\"exit\")?.callAgentFunction(agent, this.is(State.SUCCEEDED), false);\n }\n } catch (error) {\n // If the error is a GuardUnsatisfiedException then we need to determine if this node is the source.\n if (error instanceof GuardUnsatisifedException && error.isSourceNode(this)) {\n // Abort the current node.\n this.abort(agent);\n\n // Any node that is the source of an abort will be a failed node.\n this.setState(State.FAILED);\n } else {\n throw error;\n }\n }\n }\n}\n\n/**\n * Create a randomly generated node uid.\n * @returns A randomly generated node uid.\n */\nfunction createNodeUid(): string {\n var S4 = function () {\n return (((1 + Math.random()) * 0x10000) | 0).toString(16).substring(1);\n };\n return S4() + S4() + \"-\" + S4() + \"-\" + S4() + \"-\" + S4() + \"-\" + S4() + S4() + S4();\n}\n", "import Node from \"../Node\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\n\n/**\n * A composite node that wraps child nodes.\n */\nexport default abstract class Composite extends Node {\n /**\n * @param type The node type.\n * @param attributes The node attributes.\n * @param children The child nodes.\n */\n constructor(type: string, attributes: Attribute[], protected children: Node[]) {\n super(type, attributes, []);\n }\n\n /**\n * Gets whether this node is a leaf node.\n */\n isLeafNode = () => false;\n\n /**\n * Gets the children of this node.\n */\n getChildren = () => this.children;\n\n /**\n * Reset the state of the node.\n */\n reset = () => {\n // Reset the state of this node.\n this.setState(State.READY);\n\n // Reset the state of any child nodes.\n this.getChildren().forEach((child) => child.reset());\n };\n\n /**\n * Abort the running of this node.\n * @param agent The agent.\n */\n abort = (agent: Agent) => {\n // There is nothing to do if this node is not in the running state.\n if (!this.is(State.RUNNING)) {\n return;\n }\n\n // Abort any child nodes.\n this.getChildren().forEach((child) => child.abort(agent));\n\n // Reset the state of this node.\n this.reset();\n\n this.getAttribute(\"exit\")?.callAgentFunction(agent, false, true);\n };\n}\n", "import Composite from \"./Composite\";\nimport State from \"../../State\";\nimport Node from \"../Node\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A PARALLEL node.\n * The child nodes are executed concurrently until one fails or all succeed.\n */\nexport default class Parallel extends Composite {\n /**\n * @param attributes The node attributes.\n * @param children The child nodes.\n */\n constructor(attributes: Attribute[], children: Node[]) {\n super(\"parallel\", attributes, children);\n }\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // Keep a count of the number of succeeded child nodes.\n let succeededCount = 0;\n\n let hasChildFailed = false;\n\n // Iterate over all of the children of this node.\n for (const child of this.children) {\n // If the child has never been updated or is running then we will need to update it now.\n if (child.getState() === State.READY || child.getState() === State.RUNNING) {\n // Update the child of this node.\n child.update(agent, options);\n }\n\n // If the current child has a state of 'SUCCEEDED' then we should move on to the next child.\n if (child.getState() === State.SUCCEEDED) {\n // The child node has succeeded, keep track of this to determine if all children have.\n succeededCount++;\n\n // The child node succeeded, but we have not finished checking every child node yet.\n continue;\n }\n\n // If the current child has a state of 'FAILED' then this node is also a 'FAILED' node.\n if (child.getState() === State.FAILED) {\n hasChildFailed = true;\n\n // There is no need to check the rest of the children.\n break;\n }\n\n // The node should be in the 'RUNNING' state.\n if (child.getState() !== State.RUNNING) {\n // The child node was not in an expected state.\n throw new Error(\"child node was not in an expected state.\");\n }\n }\n\n if (hasChildFailed) {\n // This node is a 'FAILED' node.\n this.setState(State.FAILED);\n\n // Abort every running child.\n for (const child of this.children) {\n if (child.getState() === State.RUNNING) {\n child.abort(agent);\n }\n }\n } else {\n // If all children have succeeded then this node has also succeeded, otherwise it is still running.\n this.setState(succeededCount === this.children.length ? State.SUCCEEDED : State.RUNNING);\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => \"PARALLEL\";\n}\n", "import Composite from \"./Composite\";\nimport Node from \"../Node\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A SELECTOR node.\n * The child nodes are executed in sequence until one succeeds or all fail.\n */\nexport default class Selector extends Composite {\n /**\n * @param attributes The node attributes.\n * @param children The child nodes.\n */\n constructor(attributes: Attribute[], protected children: Node[]) {\n super(\"selector\", attributes, children);\n }\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // Iterate over all of the children of this node.\n for (const child of this.children) {\n // If the child has never been updated or is running then we will need to update it now.\n if (child.getState() === State.READY || child.getState() === State.RUNNING) {\n // Update the child of this node.\n child.update(agent, options);\n }\n\n // If the current child has a state of 'SUCCEEDED' then this node is also a 'SUCCEEDED' node.\n if (child.getState() === State.SUCCEEDED) {\n // This node is a 'SUCCEEDED' node.\n this.setState(State.SUCCEEDED);\n\n // There is no need to check the rest of the selector nodes.\n return;\n }\n\n // If the current child has a state of 'FAILED' then we should move on to the next child.\n if (child.getState() === State.FAILED) {\n // Find out if the current child is the last one in the selector.\n // If it is then this sequence node has also failed.\n if (this.children.indexOf(child) === this.children.length - 1) {\n // This node is a 'FAILED' node.\n this.setState(State.FAILED);\n\n // There is no need to check the rest of the selector as we have completed it.\n return;\n } else {\n // The child node failed, try the next one.\n continue;\n }\n }\n\n // The node should be in the 'RUNNING' state.\n if (child.getState() === State.RUNNING) {\n // This node is a 'RUNNING' node.\n this.setState(State.RUNNING);\n\n // There is no need to check the rest of the selector as the current child is still running.\n return;\n }\n\n // The child node was not in an expected state.\n throw new Error(\"child node was not in an expected state.\");\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => \"SELECTOR\";\n}\n", "import Composite from \"./Composite\";\nimport Node from \"../Node\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A SEQUENCE node.\n * The child nodes are executed in sequence until one fails or all succeed.\n */\nexport default class Sequence extends Composite {\n /**\n * @param attributes The node attributes.\n * @param children The child nodes.\n */\n constructor(attributes: Attribute[], protected children: Node[]) {\n super(\"sequence\", attributes, children);\n }\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // Iterate over all of the children of this node.\n for (const child of this.children) {\n // If the child has never been updated or is running then we will need to update it now.\n if (child.getState() === State.READY || child.getState() === State.RUNNING) {\n // Update the child of this node.\n child.update(agent, options);\n }\n\n // If the current child has a state of 'SUCCEEDED' then we should move on to the next child.\n if (child.getState() === State.SUCCEEDED) {\n // Find out if the current child is the last one in the sequence.\n // If it is then this sequence node has also succeeded.\n if (this.children.indexOf(child) === this.children.length - 1) {\n // This node is a 'SUCCEEDED' node.\n this.setState(State.SUCCEEDED);\n\n // There is no need to check the rest of the sequence as we have completed it.\n return;\n } else {\n // The child node succeeded, but we have not finished the sequence yet.\n continue;\n }\n }\n\n // If the current child has a state of 'FAILED' then this node is also a 'FAILED' node.\n if (child.getState() === State.FAILED) {\n // This node is a 'FAILED' node.\n this.setState(State.FAILED);\n\n // There is no need to check the rest of the sequence.\n return;\n }\n\n // The node should be in the 'RUNNING' state.\n if (child.getState() === State.RUNNING) {\n // This node is a 'RUNNING' node.\n this.setState(State.RUNNING);\n\n // There is no need to check the rest of the sequence as the current child is still running.\n return;\n }\n\n // The child node was not in an expected state.\n throw new Error(\"child node was not in an expected state.\");\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => \"SEQUENCE\";\n}\n", "import createLotto from \"lotto-draw\";\n\nimport Node from \"../Node\";\nimport Composite from \"./Composite\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A LOTTO node.\n * A winning child is picked on the initial update of this node, based on ticket weighting.\n * The state of this node will match the state of the winning child.\n */\nexport default class Lotto extends Composite {\n /**\n * @param attributes The node attributes.\n * @param weights The child node weights.\n * @param children The child nodes.\n */\n constructor(attributes: Attribute[], private weights: number[] | undefined, children: Node[]) {\n super(\"lotto\", attributes, children);\n }\n\n /**\n * The child node selected to be the active one.\n */\n private selectedChild: Node | undefined;\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // If this node is in the READY state then we need to pick a winning child node.\n if (this.is(State.READY)) {\n // Create a lotto draw with which to randomly pick a child node to become the active one.\n const lottoDraw = createLotto({\n // Hook up the optional 'random' behaviour tree function option to the one used by 'lotto-draw'.\n random: options.random,\n // Pass in each child node as a participant in the lotto draw with their respective ticket count.\n participants: this.children.map((child, index) => [child, this.weights?.[index] || 1])\n });\n\n // Randomly pick a child based on ticket weighting, this will become the active child for this composite node.\n this.selectedChild = lottoDraw.draw() || undefined;\n }\n\n // If something went wrong and we don't have an active child then we should throw an error.\n if (!this.selectedChild) {\n throw new Error(\"failed to update lotto node as it has no active child\");\n }\n\n // If the selected child has never been updated or is running then we will need to update it now.\n if (this.selectedChild.getState() === State.READY || this.selectedChild.getState() === State.RUNNING) {\n this.selectedChild.update(agent, options);\n }\n\n // The state of the lotto node is the state of its selected child.\n this.setState(this.selectedChild.getState());\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => (this.weights ? `LOTTO [${this.weights.join(\",\")}]` : \"LOTTO\");\n}\n", "import Node from \"../Node\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\n\n/**\n * A decorator node that wraps a single child node.\n */\nexport default abstract class Decorator extends Node {\n /**\n * @param type The node type.\n * @param attributes The node attributes.\n * @param child The child node.\n */\n constructor(type: string, attributes: Attribute[], protected child: Node) {\n super(type, attributes, []);\n }\n\n /**\n * Gets whether this node is a leaf node.\n */\n isLeafNode = () => false;\n\n /**\n * Gets the children of this node.\n */\n getChildren = () => [this.child];\n\n /**\n * Reset the state of the node.\n */\n reset = () => {\n // Reset the state of this node.\n this.setState(State.READY);\n\n // Reset the state of the child node.\n this.child.reset();\n };\n\n /**\n * Abort the running of this node.\n * @param agent The agent.\n */\n abort = (agent: Agent) => {\n // There is nothing to do if this node is not in the running state.\n if (!this.is(State.RUNNING)) {\n return;\n }\n\n // Abort the child node.\n this.child.abort(agent);\n\n // Reset the state of this node.\n this.reset();\n\n this.getAttribute(\"exit\")?.callAgentFunction(agent, false, true);\n };\n}\n", "import Node from \"../Node\";\nimport Decorator from \"./Decorator\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A Fail node.\n * This node wraps a single child and will always move to the 'FAILED' state when the child moves to a 'SUCCEEDED' or 'FAILED' state.\n */\nexport default class Fail extends Decorator {\n /**\n * @param attributes The node attributes.\n * @param child The child node.\n */\n constructor(attributes: Attribute[], child: Node) {\n super(\"fail\", attributes, child);\n }\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // If the child has never been updated or is running then we will need to update it now.\n if (this.child.getState() === State.READY || this.child.getState() === State.RUNNING) {\n this.child.update(agent, options);\n }\n\n // The state of this node will depend in the state of its child.\n switch (this.child.getState()) {\n case State.RUNNING:\n this.setState(State.RUNNING);\n break;\n\n case State.SUCCEEDED:\n case State.FAILED:\n this.setState(State.FAILED);\n break;\n\n default:\n this.setState(State.READY);\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => \"FAIL\";\n}\n", "import Decorator from \"./Decorator\";\nimport State from \"../../State\";\nimport Node from \"../Node\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A Flip node.\n * This node wraps a single child and will flip the state of the child state.\n */\nexport default class Flip extends Decorator {\n /**\n * @param attributes The node attributes.\n * @param child The child node.\n */\n constructor(attributes: Attribute[], child: Node) {\n super(\"flip\", attributes, child);\n }\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // If the child has never been updated or is running then we will need to update it now.\n if (this.child.getState() === State.READY || this.child.getState() === State.RUNNING) {\n this.child.update(agent, options);\n }\n\n // The state of this node will depend in the state of its child.\n switch (this.child.getState()) {\n case State.RUNNING:\n this.setState(State.RUNNING);\n break;\n\n case State.SUCCEEDED:\n this.setState(State.FAILED);\n break;\n\n case State.FAILED:\n this.setState(State.SUCCEEDED);\n break;\n\n default:\n this.setState(State.READY);\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => \"FLIP\";\n}\n", "import Node from \"../Node\";\nimport Decorator from \"./Decorator\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A REPEAT node.\n * The node has a single child which can have:\n * -- A number of iterations for which to repeat the child node.\n * -- An infinite repeat loop if neither an iteration count or a condition function is defined.\n * The REPEAT node will stop and have a 'FAILED' state if its child is ever in a 'FAILED' state after an update.\n * The REPEAT node will attempt to move on to the next iteration if its child is ever in a 'SUCCEEDED' state.\n */\nexport default class Repeat extends Decorator {\n /**\n * @param attributes The node attributes.\n * @param iterations The number of iterations to repeat the child node.\n * @param iterationsMin The minimum possible number of iterations to repeat the child node.\n * @param iterationsMax The maximum possible number of iterations to repeat the child node.\n * @param child The child node.\n */\n constructor(\n attributes: Attribute[],\n private iterations: number | null,\n private iterationsMin: number | null,\n private iterationsMax: number | null,\n child: Node\n ) {\n super(\"repeat\", attributes, child);\n }\n\n /**\n * The number of target iterations to make.\n */\n private targetIterationCount: number | null = null;\n\n /**\n * The current iteration count.\n */\n private currentIterationCount: number = 0;\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // If this node is in the READY state then we need to reset the child and the target iteration count.\n if (this.is(State.READY)) {\n // Reset the child node.\n this.child.reset();\n\n // Reset the current iteration count.\n this.currentIterationCount = 0;\n\n // Set the target iteration count.\n this.setTargetIterationCount(options);\n }\n\n // Do a check to see if we can iterate. If we can then this node will move into the 'RUNNING' state.\n // If we cannot iterate then we have hit our target iteration count, which means that the node has succeeded.\n if (this.canIterate()) {\n // This node is in the running state and can do its initial iteration.\n this.setState(State.RUNNING);\n\n // We may have already completed an iteration, meaning that the child node will be in the SUCCEEDED state.\n // If this is the case then we will have to reset the child node now.\n if (this.child.getState() === State.SUCCEEDED) {\n this.child.reset();\n }\n\n // Update the child of this node.\n this.child.update(agent, options);\n\n // If the child moved into the FAILED state when we updated it then there is nothing left to do and this node has also failed.\n // If it has moved into the SUCCEEDED state then we have completed the current iteration.\n if (this.child.getState() === State.FAILED) {\n // The child has failed, meaning that this node has failed.\n this.setState(State.FAILED);\n\n return;\n } else if (this.child.getState() === State.SUCCEEDED) {\n // We have completed an iteration.\n this.currentIterationCount += 1;\n }\n } else {\n // This node is in the 'SUCCEEDED' state as we cannot iterate any more.\n this.setState(State.SUCCEEDED);\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => {\n if (this.iterations !== null) {\n return `REPEAT ${this.iterations}x`;\n } else if (this.iterationsMin !== null && this.iterationsMax !== null) {\n return `REPEAT ${this.iterationsMin}x-${this.iterationsMax}x`;\n } else {\n return \"REPEAT\";\n }\n };\n\n /**\n * Reset the state of the node.\n */\n reset = () => {\n // Reset the state of this node.\n this.setState(State.READY);\n\n // Reset the current iteration count.\n this.currentIterationCount = 0;\n\n // Reset the child node.\n this.child.reset();\n };\n\n /**\n * Gets whether an iteration can be made.\n * @returns Whether an iteration can be made.\n */\n private canIterate = () => {\n if (this.targetIterationCount !== null) {\n // We can iterate as long as we have not reached our target iteration count.\n return this.currentIterationCount < this.targetIterationCount;\n }\n\n // If neither an iteration count or a condition function were defined then we can iterate indefinitely.\n return true;\n };\n\n /**\n * Sets the target iteration count.\n * @param options The behaviour tree options object.\n */\n private setTargetIterationCount = (options: BehaviourTreeOptions) => {\n // Are we dealing with an explicit iteration count or will we be randomly picking a iteration count between the min and max iteration count.\n if (this.iterations !== null) {\n this.targetIterationCount = this.iterations;\n } else if (this.iterationsMin !== null && this.iterationsMax !== null) {\n // We will be picking a random iteration count between a min and max iteration count, if the optional 'random'\n // behaviour tree function option is defined then we will be using that, otherwise we will fall back to using Math.random.\n const random = typeof options.random === \"function\" ? options.random : Math.random;\n\n // Pick a random iteration count between a min and max iteration count.\n this.targetIterationCount = Math.floor(\n random() * (this.iterationsMax - this.iterationsMin + 1) + this.iterationsMin\n );\n } else {\n this.targetIterationCount = null;\n }\n };\n}\n", "import Node from \"../Node\";\nimport Decorator from \"./Decorator\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A RETRY node.\n * The node has a single child which can have:\n * -- A number of iterations for which to repeat the child node.\n * -- An infinite repeat loop if neither an iteration count or a condition function is defined.\n * The RETRY node will stop and have a 'SUCCEEDED' state if its child is ever in a 'SUCCEEDED' state after an update.\n * The RETRY node will attempt to move on to the next iteration if its child is ever in a 'FAILED' state.\n */\nexport default class Retry extends Decorator {\n /**\n * @param attributes The node attributes.\n * @param attempts The number of attempts to retry the child node.\n * @param attemptsMin The minimum possible number of attempts to retry the child node.\n * @param attemptsMax The maximum possible number of attempts to retry the child node.\n * @param child The child node.\n */\n constructor(\n attributes: Attribute[],\n private attempts: number | null,\n private attemptsMin: number | null,\n private attemptsMax: number | null,\n child: Node\n ) {\n super(\"retry\", attributes, child);\n }\n\n /**\n * The number of target attempts to make.\n */\n private targetAttemptCount: number | null = null;\n\n /**\n * The current attempt count.\n */\n private currentAttemptCount: number = 0;\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // If this node is in the READY state then we need to reset the child and the target attempt count.\n if (this.is(State.READY)) {\n // Reset the child node.\n this.child.reset();\n\n // Reset the current attempt count.\n this.currentAttemptCount = 0;\n\n // Set the target attempt count.\n this.setTargetAttemptCount(options);\n }\n\n // Do a check to see if we can attempt. If we can then this node will move into the 'RUNNING' state.\n // If we cannot attempt then we have hit our target attempt count, which means that the node has succeeded.\n if (this.canAttempt()) {\n // This node is in the running state and can do its initial attempt.\n this.setState(State.RUNNING);\n\n // We may have already completed an attempt, meaning that the child node will be in the FAILED state.\n // If this is the case then we will have to reset the child node now.\n if (this.child.getState() === State.FAILED) {\n this.child.reset();\n }\n\n // Update the child of this node.\n this.child.update(agent, options);\n\n // If the child moved into the SUCCEEDED state when we updated it then there is nothing left to do and this node has also succeeded.\n // If it has moved into the FAILED state then we have completed the current attempt.\n if (this.child.getState() === State.SUCCEEDED) {\n // The child has succeeded, meaning that this node has succeeded.\n this.setState(State.SUCCEEDED);\n\n return;\n } else if (this.child.getState() === State.FAILED) {\n // We have completed an attempt.\n this.currentAttemptCount += 1;\n }\n } else {\n // This node is in the 'FAILED' state as we cannot iterate any more.\n this.setState(State.FAILED);\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => {\n if (this.attempts !== null) {\n return `RETRY ${this.attempts}x`;\n } else if (this.attemptsMin !== null && this.attemptsMax !== null) {\n return `RETRY ${this.attemptsMin}x-${this.attemptsMax}x`;\n } else {\n return \"RETRY\";\n }\n };\n\n /**\n * Reset the state of the node.\n */\n reset = () => {\n // Reset the state of this node.\n this.setState(State.READY);\n\n // Reset the current attempt count.\n this.currentAttemptCount = 0;\n\n // Reset the child node.\n this.child.reset();\n };\n\n /**\n * Gets whether an attempt can be made.\n * @returns Whether an attempt can be made.\n */\n canAttempt = () => {\n if (this.targetAttemptCount !== null) {\n // We can attempt as long as we have not reached our target attempt count.\n return this.currentAttemptCount < this.targetAttemptCount;\n }\n\n // If neither an attempt count or a condition function were defined then we can attempt indefinitely.\n return true;\n };\n\n /**\n * Sets the target attempt count.\n * @param options The behaviour tree options object.\n */\n setTargetAttemptCount = (options: BehaviourTreeOptions) => {\n // Are we dealing with an explicit attempt count or will we be randomly picking an attempt count between the min and max attempt count.\n if (this.attempts !== null) {\n this.targetAttemptCount = this.attempts;\n } else if (this.attemptsMin !== null && this.attemptsMax !== null) {\n // We will be picking a random attempt count between a min and max attempt count, if the optional 'random'\n // behaviour tree function option is defined then we will be using that, otherwise we will fall back to using Math.random.\n const random = typeof options.random === \"function\" ? options.random : Math.random;\n\n // Pick a random attempt count between a min and max attempt count.\n this.targetAttemptCount = Math.floor(\n random() * (this.attemptsMax - this.attemptsMin + 1) + this.attemptsMin\n );\n } else {\n this.targetAttemptCount = null;\n }\n };\n}\n", "import Node from \"../Node\";\nimport Decorator from \"./Decorator\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A Root node.\n * The root node will have a single child.\n */\nexport default class Root extends Decorator {\n /**\n * @param attributes The node attributes.\n * @param child The child node.\n */\n constructor(attributes: Attribute[], child: Node) {\n super(\"root\", attributes, child);\n }\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // If the child has never been updated or is running then we will need to update it now.\n if (this.child.getState() === State.READY || this.child.getState() === State.RUNNING) {\n // Update the child of this node.\n this.child.update(agent, options);\n }\n\n // The state of the root node is the state of its child.\n this.setState(this.child.getState());\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => \"ROOT\";\n}\n", "import Node from \"../Node\";\nimport Decorator from \"./Decorator\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A Succeed node.\n * This node wraps a single child and will always move to the 'SUCCEEDED' state when the child moves to a 'SUCCEEDED' or 'FAILED' state.\n */\nexport default class Succeed extends Decorator {\n /**\n * @param attributes The node attributes.\n * @param child The child node.\n */\n constructor(attributes: Attribute[], child: Node) {\n super(\"succeed\", attributes, child);\n }\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // If the child has never been updated or is running then we will need to update it now.\n if (this.child.getState() === State.READY || this.child.getState() === State.RUNNING) {\n this.child.update(agent, options);\n }\n\n // The state of this node will depend in the state of its child.\n switch (this.child.getState()) {\n case State.RUNNING:\n this.setState(State.RUNNING);\n break;\n\n case State.SUCCEEDED:\n case State.FAILED:\n this.setState(State.SUCCEEDED);\n break;\n\n default:\n this.setState(State.READY);\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => \"SUCCEED\";\n}\n", "import Node from \"../Node\";\n\n/**\n * A leaf node.\n */\nexport default abstract class Leaf extends Node {\n /**\n * Gets whether this node is a leaf node.\n */\n isLeafNode = () => true;\n}\n", "import { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\nimport State, { CompleteState } from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Leaf from \"./Leaf\";\nimport Lookup from \"../../Lookup\";\nimport Attribute from \"../../attributes/Attribute\";\n\n/**\n * An Action leaf node.\n * This represents an immediate or ongoing state of behaviour.\n */\nexport default class Action extends Leaf {\n /**\n * @param attributes The node attributes.\n * @param actionName The action name.\n * @param actionArguments The array of action argument definitions.\n */\n constructor(attributes: Attribute[], private actionName: string, private actionArguments: any[]) {\n super(\"action\", attributes, actionArguments);\n }\n\n /**\n * Whether there is a pending update promise.\n */\n private isUsingUpdatePromise = false;\n\n /**\n * The finished state result of an update promise.\n */\n private updatePromiseStateResult: CompleteState | null = null;\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // If the result of this action depends on an update promise then there is nothing to do until\n // it resolves, unless there has been a value set as a result of the update promise resolving.\n if (this.isUsingUpdatePromise) {\n // Check whether the update promise has resolved with a state value.\n if (this.updatePromiseStateResult) {\n // Set the state of this node to match the state returned by the promise.\n this.setState(this.updatePromiseStateResult);\n }\n\n return;\n }\n\n // Attempt to get the invoker for the action function.\n const actionFuncInvoker = Lookup.getFuncInvoker(agent, this.actionName);\n\n // The action function should be defined.\n if (actionFuncInvoker === null) {\n throw new Error(\n `cannot update action node as the action '${this.actionName}' function is not defined on the agent and has not been registered`\n );\n }\n\n // Call the action function, the result of which may be:\n // - The finished state of this action node.\n // - A promise to return a finished node state.\n // - Undefined if the node should remain in the running state.\n const updateResult = actionFuncInvoker(this.actionArguments) as CompleteState | Promise;\n\n if (updateResult instanceof Promise) {\n updateResult.then(\n (result) => {\n // If 'isUpdatePromisePending' is null then the promise was cleared as it was resolving, probably via an abort of reset.\n if (!this.isUsingUpdatePromise) {\n return;\n }\n\n // Check to make sure the result is a valid finished state.\n if (result !== State.SUCCEEDED && result !== State.FAILED) {\n throw new Error(\n \"action node promise resolved with an invalid value, expected a State.SUCCEEDED or State.FAILED value to be returned\"\n );\n }\n\n // Set pending update promise state result to be processed on next update.\n this.updatePromiseStateResult = result;\n },\n (reason) => {\n // If 'isUpdatePromisePending' is null then the promise was cleared as it was resolving, probably via an abort of reset.\n if (!this.isUsingUpdatePromise) {\n return;\n }\n\n // Just throw whatever was returned as the rejection argument.\n throw new Error(reason);\n }\n );\n\n // This node will be in the 'RUNNING' state until the update promise resolves.\n this.setState(State.RUNNING);\n\n // We are now waiting for the promise returned by the use to resolve before we know what state this node is in.\n this.isUsingUpdatePromise = true;\n } else {\n // Validate the returned value.\n this.validateUpdateResult(updateResult);\n\n // Set the state of this node, this may be undefined, which just means that the node is still in the 'RUNNING' state.\n this.setState(updateResult || State.RUNNING);\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => this.actionName;\n\n /**\n * Reset the state of the node.\n */\n reset = () => {\n // Reset the state of this node.\n this.setState(State.READY);\n\n // There is no longer an update promise that we care about.\n this.isUsingUpdatePromise = false;\n this.updatePromiseStateResult = null;\n };\n\n /**\n * Validate the result of an update function call.\n * @param result The result of an update function call.\n */\n private validateUpdateResult = (result: CompleteState | boolean) => {\n switch (result) {\n case State.SUCCEEDED:\n case State.FAILED:\n case undefined:\n return;\n default:\n throw new Error(\n `action '${this.actionName}' 'onUpdate' returned an invalid response, expected an optional State.SUCCEEDED or State.FAILED value to be returned`\n );\n }\n };\n}\n", "import { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Leaf from \"./Leaf\";\nimport Lookup from \"../../Lookup\";\nimport Attribute from \"../../attributes/Attribute\";\n\n/**\n * A Condition leaf node.\n * This will succeed or fail immediately based on an agent predicate, without moving to the 'RUNNING' state.\n */\nexport default class Condition extends Leaf {\n /**\n * @param attributes The node attributes.\n * @param conditionName The name of the condition function.\n * @param conditionArguments The array of condition argument definitions.\n */\n constructor(attributes: Attribute[], private conditionName: string, private conditionArguments: any[]) {\n super(\"condition\", attributes, conditionArguments);\n }\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // Attempt to get the invoker for the condition function.\n const conditionFuncInvoker = Lookup.getFuncInvoker(agent, this.conditionName);\n\n // The condition function should be defined.\n if (conditionFuncInvoker === null) {\n throw new Error(\n `cannot update condition node as the condition '${this.conditionName}' function is not defined on the agent and has not been registered`\n );\n }\n\n // Call the condition function to determine the state of this node.\n this.setState(!!conditionFuncInvoker(this.conditionArguments) ? State.SUCCEEDED : State.FAILED);\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => this.conditionName;\n}\n", "import Leaf from \"./Leaf\";\nimport State from \"../../State\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { Agent } from \"../../Agent\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A WAIT node.\n * The state of this node will change to SUCCEEDED after a duration of time\n */\nexport default class Wait extends Leaf {\n /**\n * @param attributes The node attributes.\n * @param duration The duration that this node will wait to succeed in milliseconds.\n * @param durationMin The minimum possible duration in milliseconds that this node will wait to succeed.\n * @param durationMax The maximum possible duration in milliseconds that this node will wait to succeed.\n */\n constructor(\n attributes: Attribute[],\n private duration: number | null,\n private durationMin: number | null,\n private durationMax: number | null\n ) {\n super(\"wait\", attributes, []);\n }\n\n /**\n * The time in milliseconds at which this node was first updated.\n */\n private initialUpdateTime: number = 0;\n\n /**\n * The total duration in milliseconds that this node will be waiting for.\n */\n private totalDuration: number | null = null;\n\n /**\n * The duration in milliseconds that this node has been waiting for.\n */\n private waitedDuration: number = 0;\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // If this node is in the READY state then we need to set the initial update time.\n if (this.is(State.READY)) {\n // Set the initial update time.\n this.initialUpdateTime = new Date().getTime();\n\n // Set the initial waited duration.\n this.waitedDuration = 0;\n\n // Are we dealing with an explicit duration or will we be randomly picking a duration between the min and max duration.\n if (this.duration !== null) {\n this.totalDuration = this.duration;\n } else if (this.durationMin !== null && this.durationMax !== null) {\n // We will be picking a random duration between a min and max duration, if the optional 'random' behaviour tree\n // function option is defined then we will be using that, otherwise we will fall back to using Math.random.\n const random = typeof options.random === \"function\" ? options.random : Math.random;\n\n // Pick a random duration between a min and max duration.\n this.totalDuration = Math.floor(\n random() * (this.durationMax - this.durationMin + 1) + this.durationMin\n );\n } else {\n this.totalDuration = null;\n }\n\n // The node is now running until we finish waiting.\n this.setState(State.RUNNING);\n }\n\n // If we have no total duration then this wait node will wait indefinitely until it is aborted.\n if (this.totalDuration === null) {\n return;\n }\n\n // If we have a 'getDeltaTime' function defined as part of our options then we will use it to figure out how long we have waited for.\n if (typeof options.getDeltaTime === \"function\") {\n // Get the delta time.\n const deltaTime = options.getDeltaTime();\n\n // Our delta time must be a valid number and cannot be NaN.\n if (typeof deltaTime !== \"number\" || isNaN(deltaTime)) {\n throw new Error(\"The delta time must be a valid number and not NaN.\");\n }\n\n // Update the amount of time that this node has been waiting for based on the delta time.\n this.waitedDuration += deltaTime * 1000;\n } else {\n // We are not using a delta time, so we will just work out hom much time has passed since the first update.\n this.waitedDuration = new Date().getTime() - this.initialUpdateTime;\n }\n\n // Have we waited long enough?\n if (this.waitedDuration >= this.totalDuration) {\n // We have finished waiting!\n this.setState(State.SUCCEEDED);\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => {\n if (this.duration !== null) {\n return `WAIT ${this.duration}ms`;\n } else if (this.durationMin !== null && this.durationMax !== null) {\n return `WAIT ${this.durationMin}ms-${this.durationMax}ms`;\n } else {\n return \"WAIT\";\n }\n };\n}\n", "import Guard from \"./guards/Guard\";\n\nexport type AttributeDetails = {\n /** The attribute type. */\n type: string;\n\n /** The attribute arguments. */\n args: any[];\n};\n\n/**\n * A base node attribute.\n */\nexport default abstract class Attribute {\n /**\n * @param type The node attribute type.\n * @param args The array of attribute arguments.\n */\n constructor(public type: string, public args: any[]) {}\n\n /**\n * Gets the attribute details.\n */\n abstract getDetails(): TAttributeDetails;\n\n /**\n * Gets whether this attribute is a guard.\n */\n abstract isGuard: () => this is Guard;\n}\n", "import { Agent } from \"../../Agent\";\nimport Attribute, { AttributeDetails } from \"../Attribute\";\n\nexport type GuardAttributeDetails = {\n /** The name of the condition function that determines whether the guard is satisfied. */\n condition: string;\n} & AttributeDetails;\n\n/**\n * A base node guard attribute.\n */\nexport default abstract class Guard extends Attribute {\n /**\n * @param type The node attribute type.\n * @param args The array of decorator argument definitions.\n * @param condition The name of the condition function that determines whether the guard is satisfied.\n */\n constructor(type: string, args: any[], private condition: string) {\n super(type, args);\n }\n\n /**\n * Gets the name of the condition function that determines whether the guard is satisfied.\n */\n getCondition = () => this.condition;\n\n /**\n * Gets whether this attribute is a guard.\n */\n isGuard = () => true;\n\n /**\n * Gets the attribute details.\n */\n getDetails(): GuardAttributeDetails {\n return {\n type: this.type,\n args: this.args,\n condition: this.getCondition()\n };\n }\n\n /**\n * Gets whether the guard is satisfied.\n * @param agent The agent.\n * @returns Whether the guard is satisfied.\n */\n abstract isSatisfied(agent: Agent): boolean;\n}\n", "import Guard from \"./Guard\";\nimport Lookup from \"../../Lookup\";\nimport { Agent } from \"../../Agent\";\n\n/**\n * A WHILE guard which is satisfied as long as the given condition remains true.\n */\nexport default class While extends Guard {\n /**\n * @param condition The name of the condition function that determines whether the guard is satisfied.\n * @param args The array of decorator argument definitions.\n */\n constructor(condition: string, args: any[]) {\n super(\"while\", args, condition);\n }\n\n /**\n * Gets whether the guard is satisfied.\n * @param agent The agent.\n * @returns Whether the guard is satisfied.\n */\n isSatisfied = (agent: Agent) => {\n // Attempt to get the invoker for the condition function.\n const conditionFuncInvoker = Lookup.getFuncInvoker(agent, this.getCondition());\n\n // The condition function should be defined.\n if (conditionFuncInvoker === null) {\n throw new Error(\n `cannot evaluate node guard as the condition '${this.getCondition()}' function is not defined on the agent and has not been registered`\n );\n }\n\n // Call the condition function to determine whether this guard is satisfied.\n return !!conditionFuncInvoker(this.args);\n };\n}\n", "import Guard from \"./Guard\";\nimport Lookup from \"../../Lookup\";\nimport { Agent } from \"../../Agent\";\n\n/**\n * An UNTIL guard which is satisfied as long as the given condition remains false.\n */\nexport default class Until extends Guard {\n /**\n * @param condition The name of the condition function that determines whether the guard is satisfied.\n * @param args The array of decorator argument definitions.\n */\n constructor(condition: string, args: any[]) {\n super(\"until\", args, condition);\n }\n\n /**\n * Gets whether the guard is satisfied.\n * @param agent The agent.\n * @returns Whether the guard is satisfied.\n */\n isSatisfied = (agent: Agent) => {\n // Attempt to get the invoker for the condition function.\n const conditionFuncInvoker = Lookup.getFuncInvoker(agent, this.getCondition());\n\n // The condition function should be defined.\n if (conditionFuncInvoker === null) {\n throw new Error(\n `cannot evaluate node guard as the condition '${this.getCondition()}' function is not defined on the agent and has not been registered`\n );\n }\n\n // Call the condition function to determine whether this guard is satisfied.\n return !!!conditionFuncInvoker(this.args);\n };\n}\n", "import { Agent } from \"../../Agent\";\nimport Attribute, { AttributeDetails } from \"../Attribute\";\n\nexport type CallbackAttributeDetails = {\n /** The name of the agent function that is called. */\n functionName: string;\n} & AttributeDetails;\n\n/**\n * A base node callback attribute.\n */\nexport default abstract class Callback extends Attribute {\n /**\n * @param type The node attribute type.\n * @param args The array of decorator argument definitions.\n * @param functionName The name of the agent function to call.\n */\n constructor(type: string, args: any[], private functionName: string) {\n super(type, args);\n }\n\n /**\n * Gets the name of the agent function to call.\n */\n getFunctionName = () => this.functionName;\n\n /**\n * Gets whether this attribute is a guard.\n */\n isGuard = () => false;\n\n /**\n * Gets the attribute details.\n */\n getDetails(): CallbackAttributeDetails {\n return {\n type: this.type,\n args: this.args,\n functionName: this.getFunctionName()\n };\n }\n\n /**\n * Attempt to call the agent function that this callback refers to.\n * @param agent The agent.\n */\n abstract callAgentFunction: (agent: Agent, isSuccess: boolean, isAborted: boolean) => void;\n}\n", "import Callback from \"./Callback\";\nimport Lookup from \"../../Lookup\";\nimport { Agent } from \"../../Agent\";\n\n/**\n * An ENTRY callback which defines an agent function to call when the associated node is updated and moves out of running state.\n */\nexport default class Entry extends Callback {\n /**\n * @param functionName The name of the agent function to call.\n * @param args The array of callback argument definitions.\n */\n constructor(functionName: string, args: any[]) {\n super(\"entry\", args, functionName);\n }\n\n /**\n * Attempt to call the agent function that this callback refers to.\n * @param agent The agent.\n */\n callAgentFunction = (agent: Agent) => {\n // Attempt to get the invoker for the callback function.\n const callbackFuncInvoker = Lookup.getFuncInvoker(agent, this.getFunctionName());\n\n // The callback function should be defined.\n if (callbackFuncInvoker === null) {\n throw new Error(\n `cannot call entry function '${this.getFunctionName()}' as is not defined on the agent and has not been registered`\n );\n }\n\n // Call the callback function.\n callbackFuncInvoker(this.args);\n };\n}\n", "import Callback from \"./Callback\";\nimport Lookup from \"../../Lookup\";\nimport { Agent } from \"../../Agent\";\n\n/**\n * A STEP callback which defines an agent function to call when the associated node is updated.\n */\nexport default class Step extends Callback {\n /**\n * @param functionName The name of the agent function to call.\n * @param args The array of callback argument definitions.\n */\n constructor(functionName: string, args: any[]) {\n super(\"step\", args, functionName);\n }\n\n /**\n * Attempt to call the agent function that this callback refers to.\n * @param agent The agent.\n */\n callAgentFunction = (agent: Agent) => {\n // Attempt to get the invoker for the callback function.\n const callbackFuncInvoker = Lookup.getFuncInvoker(agent, this.getFunctionName());\n\n // The callback function should be defined.\n if (callbackFuncInvoker === null) {\n throw new Error(\n `cannot call step function '${this.getFunctionName()}' as is not defined on the agent and has not been registered`\n );\n }\n\n // Call the callback function.\n callbackFuncInvoker(this.args);\n };\n}\n", "import Callback from \"./Callback\";\nimport Lookup from \"../../Lookup\";\nimport { Agent } from \"../../Agent\";\n\n/**\n * An EXIT callback which defines an agent function to call when the associated node is updated and moves to a finished state or is aborted.\n */\nexport default class Exit extends Callback {\n /**\n * @param functionName The name of the agent function to call.\n * @param args The array of callback argument definitions.\n */\n constructor(functionName: string, args: any[]) {\n super(\"exit\", args, functionName);\n }\n\n /**\n * Attempt to call the agent function that this callback refers to.\n * @param agent The agent.\n * @param isSuccess Whether the decorated node was left with a success state.\n * @param isAborted Whether the decorated node was aborted.\n */\n callAgentFunction = (agent: Agent, isSuccess: boolean, isAborted: boolean) => {\n // Attempt to get the invoker for the callback function.\n const callbackFuncInvoker = Lookup.getFuncInvoker(agent, this.getFunctionName());\n\n // The callback function should be defined.\n if (callbackFuncInvoker === null) {\n throw new Error(\n `cannot call exit function '${this.getFunctionName()}' as is not defined on the agent and has not been registered`\n );\n }\n\n // Call the callback function\n callbackFuncInvoker([{ value: { succeeded: isSuccess, aborted: isAborted } }, ...this.args]);\n };\n}\n", "import { AnyNodeDefinition, RootNodeDefinition } from \"./BehaviourTreeDefinition\";\nimport GuardPath, { GuardPathPart } from \"./attributes/guards/GuardPath\";\nimport { validateBranchSubtreeLinks } from \"./BehaviourTreeDefinitionValidator\";\nimport { isInteger } from \"./BehaviourTreeDefinitionUtilities\";\nimport Node from \"./nodes/Node\";\nimport Composite from \"./nodes/composite/Composite\";\nimport Decorator from \"./nodes/decorator/Decorator\";\nimport Parallel from \"./nodes/composite/Parallel\";\nimport Selector from \"./nodes/composite/Selector\";\nimport Sequence from \"./nodes/composite/Sequence\";\nimport Lotto from \"./nodes/composite/Lotto\";\nimport Fail from \"./nodes/decorator/Fail\";\nimport Flip from \"./nodes/decorator/Flip\";\nimport Repeat from \"./nodes/decorator/Repeat\";\nimport Retry from \"./nodes/decorator/Retry\";\nimport Root from \"./nodes/decorator/Root\";\nimport Succeed from \"./nodes/decorator/Succeed\";\nimport Action from \"./nodes/leaf/Action\";\nimport Condition from \"./nodes/leaf/Condition\";\nimport Wait from \"./nodes/leaf/Wait\";\nimport Lookup from \"./Lookup\";\nimport Attribute from \"./attributes/Attribute\";\nimport While from \"./attributes/guards/While\";\nimport Until from \"./attributes/guards/Until\";\nimport Entry from \"./attributes/callbacks/Entry\";\nimport Step from \"./attributes/callbacks/Step\";\nimport Exit from \"./attributes/callbacks/Exit\";\n\n/**\n * A type representing any node instance in a behaviour tree.\n */\ntype AnyNode =\n | Root\n | Action\n | Condition\n | Wait\n | Sequence\n | Selector\n | Lotto\n | Parallel\n | Repeat\n | Retry\n | Flip\n | Succeed\n | Fail;\n\n/**\n * A type defining a mapping of root node identifiers to root node definitions.\n */\ntype RootNodeDefinitionMap = { [key: string | symbol]: RootNodeDefinition };\n\n/**\n * A symbol to use as the main root key in any root node mappings.\n */\nconst MAIN_ROOT_NODE_KEY = Symbol(\"__root__\");\n\n/**\n * Build and populate the root nodes based on the provided definition, assuming that the definition has been validated.\n * @param definition The root node definitions.\n * @returns The built and populated root node definitions.\n */\nexport default function buildRootNode(definition: RootNodeDefinition[]): Root {\n // Create a mapping of root node identifers to root node definitions, including globally registered subtree root node definitions.\n const rootNodeDefinitionMap = createRootNodeDefinitionMap(definition);\n\n // Now that we have all of our root node definitons (those part of the tree definition and those globally\n // registered) we should validate the definition. This will also double-check that we dont have any circular\n // dependencies in our branch -> subtree references and that we have no broken branch -> subtree links.\n validateBranchSubtreeLinks(definition, true);\n\n // Create our populated tree of node instances, starting with our main root node.\n const rootNode = nodeFactory(rootNodeDefinitionMap[MAIN_ROOT_NODE_KEY], rootNodeDefinitionMap) as Root;\n\n // Set a guard path on every leaf of the tree to evaluate as part of each update.\n applyLeafNodeGuardPaths(rootNode);\n\n // We only need to return the main root node.\n return rootNode;\n}\n\n/**\n * A factory function which creates a node instance based on the specified definition.\n * @param definition The node definition.\n * @param rootNodeDefinitionMap The mapping of root node identifers to root node definitions, including globally registered subtree root node definitions.\n * @returns A node instance based on the specified definition.\n */\nfunction nodeFactory(definition: AnyNodeDefinition, rootNodeDefinitionMap: RootNodeDefinitionMap): AnyNode {\n // Get the attributes for the node.\n const attributes = nodeAttributesFactory(definition);\n\n // Create the node instance based on the definition type.\n switch (definition.type) {\n case \"root\":\n return new Root(attributes, nodeFactory(definition.child, rootNodeDefinitionMap));\n\n case \"repeat\":\n let iterations: number | null = null;\n let iterationsMin: number | null = null;\n let iterationsMax: number | null = null;\n\n if (Array.isArray(definition.iterations)) {\n iterationsMin = definition.iterations[0];\n iterationsMax = definition.iterations[1];\n } else if (isInteger(definition.iterations)) {\n iterations = definition.iterations!;\n }\n\n return new Repeat(\n attributes,\n iterations,\n iterationsMin,\n iterationsMax,\n nodeFactory(definition.child, rootNodeDefinitionMap)\n );\n\n case \"retry\":\n let attempts: number | null = null;\n let attemptsMin: number | null = null;\n let attemptsMax: number | null = null;\n\n if (Array.isArray(definition.attempts)) {\n attemptsMin = definition.attempts[0];\n attemptsMax = definition.attempts[1];\n } else if (isInteger(definition.attempts)) {\n attempts = definition.attempts!;\n }\n\n return new Retry(\n attributes,\n attempts,\n attemptsMin,\n attemptsMax,\n nodeFactory(definition.child, rootNodeDefinitionMap)\n );\n\n case \"flip\":\n return new Flip(attributes, nodeFactory(definition.child, rootNodeDefinitionMap));\n\n case \"succeed\":\n return new Succeed(attributes, nodeFactory(definition.child, rootNodeDefinitionMap));\n\n case \"fail\":\n return new Fail(attributes, nodeFactory(definition.child, rootNodeDefinitionMap));\n\n case \"sequence\":\n return new Sequence(\n attributes,\n definition.children.map((child) => nodeFactory(child, rootNodeDefinitionMap))\n );\n\n case \"selector\":\n return new Selector(\n attributes,\n definition.children.map((child) => nodeFactory(child, rootNodeDefinitionMap))\n );\n\n case \"parallel\":\n return new Parallel(\n attributes,\n definition.children.map((child) => nodeFactory(child, rootNodeDefinitionMap))\n );\n\n case \"lotto\":\n return new Lotto(\n attributes,\n definition.weights,\n definition.children.map((child) => nodeFactory(child, rootNodeDefinitionMap))\n );\n\n case \"branch\":\n return nodeFactory(rootNodeDefinitionMap[definition.ref].child, rootNodeDefinitionMap);\n\n case \"action\":\n return new Action(attributes, definition.call, definition.args || []);\n\n case \"condition\":\n return new Condition(attributes, definition.call, definition.args || []);\n\n case \"wait\":\n let duration: number | null = null;\n let durationMin: number | null = null;\n let durationMax: number | null = null;\n\n if (Array.isArray(definition.duration)) {\n durationMin = definition.duration[0];\n durationMax = definition.duration[1];\n } else if (isInteger(definition.duration)) {\n duration = definition.duration!;\n }\n\n return new Wait(attributes, duration, durationMin, durationMax);\n }\n}\n\n/**\n * Creates an array of node attribute instances based on the specified node definition.\n * @param definition The node definition.\n * @returns An array of node attribute instances based on the specified node definition.\n */\nfunction nodeAttributesFactory(definition: AnyNodeDefinition): Attribute[] {\n const attributes: Attribute[] = [];\n\n if (definition.while) {\n attributes.push(new While(definition.while.call, definition.while.args ?? []));\n }\n\n if (definition.until) {\n attributes.push(new Until(definition.until.call, definition.until.args ?? []));\n }\n\n if (definition.entry) {\n attributes.push(new Entry(definition.entry.call, definition.entry.args ?? []));\n }\n\n if (definition.step) {\n attributes.push(new Step(definition.step.call, definition.step.args ?? []));\n }\n\n if (definition.exit) {\n attributes.push(new Exit(definition.exit.call, definition.exit.args ?? []));\n }\n\n return attributes;\n}\n\n/**\n * Creates a mapping of root node identifers to root node definitions, mixing in globally registered subtree root node definitions.\n * @param definition The root node definitions.\n * @returns A mapping of root node identifers to root node definitions, including globally registered subtree root node definitions.\n */\nfunction createRootNodeDefinitionMap(definition: RootNodeDefinition[]): RootNodeDefinitionMap {\n // Create a mapping of root node identifers to root node definitions.\n const rootNodeMap: RootNodeDefinitionMap = {};\n\n // Add in any registered subtree root node definitions.\n for (const [name, rootNodeDefinition] of Object.entries(Lookup.getSubtrees())) {\n // The name used when registering the subtree will be used as the root node identifier.\n rootNodeMap[name] = { ...rootNodeDefinition, id: name };\n }\n\n // Populate the map with the root node definitions that were included with the tree definition.\n // We do this after adding any registered subtrees as we want these to take presedence.\n for (const rootNodeDefinition of definition) {\n rootNodeMap[rootNodeDefinition.id ?? MAIN_ROOT_NODE_KEY] = rootNodeDefinition;\n }\n\n return rootNodeMap;\n}\n\n/**\n * Applies a guard path to every leaf of the tree to evaluate as part of each update.\n * @param root The main root tree node.\n */\nfunction applyLeafNodeGuardPaths(root: Root) {\n const nodePaths: Node[][] = [];\n\n const findLeafNodes = (path: Node[], node: Node) => {\n // Add the current node to the path.\n path = path.concat(node);\n\n // Check whether the current node is a leaf node.\n if (node.isLeafNode()) {\n nodePaths.push(path);\n } else {\n (node as Composite | Decorator).getChildren().forEach((child) => findLeafNodes(path, child));\n }\n };\n\n // Find all leaf node paths, starting from the root.\n findLeafNodes([], root);\n\n nodePaths.forEach((path) => {\n // Each node in the current path will have to be assigned a guard path, working from the root outwards.\n for (let depth = 0; depth < path.length; depth++) {\n // Get the node in the path at the current depth.\n const currentNode = path[depth];\n\n // The node may already have been assigned a guard path, if so just skip it.\n if (currentNode.hasGuardPath()) {\n continue;\n }\n\n // Create the guard path for the current node.\n const guardPath = new GuardPath(\n path\n .slice(0, depth + 1)\n .map((node) => ({ node, guards: node.getGuardAttributes() }))\n .filter((details) => details.guards.length > 0)\n );\n\n // Assign the guard path to the current node.\n currentNode.setGuardPath(guardPath);\n }\n });\n}\n", "import State, { AnyState } from \"./State\";\nimport Lookup from \"./Lookup\";\nimport Node from \"./nodes/Node\";\nimport Root from \"./nodes/decorator/Root\";\nimport Composite from \"./nodes/composite/Composite\";\nimport Decorator from \"./nodes/decorator/Decorator\";\nimport { Agent, GlobalFunction } from \"./Agent\";\nimport { CallbackAttributeDetails } from \"./attributes/callbacks/Callback\";\nimport { GuardAttributeDetails } from \"./attributes/guards/Guard\";\nimport { BehaviourTreeOptions } from \"./BehaviourTreeOptions\";\nimport { convertMDSLToJSON } from \"./mdsl/MDSLDefinitionParser\";\nimport { RootNodeDefinition } from \"./BehaviourTreeDefinition\";\nimport { validateDefinition, validateJSONDefinition } from \"./BehaviourTreeDefinitionValidator\";\nimport buildRootNode from \"./BehaviourTreeBuilder\";\nimport { isNullOrUndefined } from \"./BehaviourTreeDefinitionUtilities\";\n\n// Purely for outside inspection of the tree.\nexport type FlattenedTreeNode = {\n id: string;\n type: string;\n caption: string;\n state: AnyState;\n guards: GuardAttributeDetails[];\n callbacks: CallbackAttributeDetails[];\n args: any[];\n parentId: string | null;\n};\n\n/**\n * A representation of a behaviour tree.\n */\nexport class BehaviourTree {\n /**\n * The main root tree node.\n */\n public readonly rootNode: Root;\n\n /**\n * Creates a new instance of the BehaviourTree class.\n * @param definition The behaviour tree definition.\n * @param agent The agent instance that this behaviour tree is modelling behaviour for.\n * @param options The behaviour tree options object.\n */\n constructor(\n definition: string | RootNodeDefinition | RootNodeDefinition[],\n private agent: Agent,\n private options: BehaviourTreeOptions = {}\n ) {\n // The tree definition must be defined.\n if (isNullOrUndefined(definition)) {\n throw new Error(\"tree definition not defined\");\n }\n\n // The agent must be defined and not null.\n if (typeof agent !== \"object\" || agent === null) {\n throw new Error(\"the agent must be an object and not null\");\n }\n\n // We should validate the definition before we try to build the tree nodes.\n const { succeeded, errorMessage } = validateDefinition(definition);\n\n // Did our validation fail without error?\n if (!succeeded) {\n throw new Error(`invalid definition: ${errorMessage}`);\n }\n\n try {\n // Parse the behaviour tree definition, create the populated tree of behaviour tree nodes, and get the root.\n this.rootNode = this._createRootNode(definition);\n } catch (exception) {\n // There was an issue in trying build and populate the behaviour tree.\n throw new Error(`error building tree: ${(exception as Error).message}`);\n }\n }\n\n /**\n * Gets whether the tree is in the RUNNING state.\n * @returns true if the tree is in the RUNNING state, otherwise false.\n */\n isRunning() {\n return this.rootNode.getState() === State.RUNNING;\n }\n\n /**\n * Gets the current tree state of SUCCEEDED, FAILED, READY or RUNNING.\n * @returns The current tree state.\n */\n getState() {\n return this.rootNode.getState();\n }\n\n /**\n * Step the tree.\n * 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.\n * 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\n * 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.\n *\n * 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.\n */\n step() {\n // If the root node has already been stepped to completion then we need to reset it.\n if (this.rootNode.getState() === State.SUCCEEDED || this.rootNode.getState() === State.FAILED) {\n this.rootNode.reset();\n }\n\n try {\n this.rootNode.update(this.agent, this.options);\n } catch (exception) {\n throw new Error(`error stepping tree: ${(exception as Error).message}`);\n }\n }\n\n /**\n * Resets the tree from the root node outwards to each nested node, giving each a state of READY.\n */\n reset() {\n this.rootNode.reset();\n }\n\n /**\n * Gets the flattened details of every node in the tree.\n * @returns The flattened details of every node in the tree.\n */\n getFlattenedNodeDetails(): FlattenedTreeNode[] {\n // Create an empty flattened array of tree nodes.\n const flattenedTreeNodes: FlattenedTreeNode[] = [];\n\n /**\n * Helper function to process a node instance and push details into the flattened tree nodes array.\n * @param node The current node.\n * @param parentUid The UID of the node parent, or null if the node is the main root node.\n */\n const processNode = (node: Node, parentUid: string | null) => {\n // Get the guard and callback attribute details for this node.\n const guards = node\n .getAttributes()\n .filter((attribute) => attribute.isGuard())\n .map((attribute) => attribute.getDetails()) as GuardAttributeDetails[];\n const callbacks = node\n .getAttributes()\n .filter((attribute) => !attribute.isGuard())\n .map((attribute) => attribute.getDetails()) as CallbackAttributeDetails[];\n\n // Push the current node into the flattened nodes array.\n flattenedTreeNodes.push({\n id: node.getUid(),\n type: node.getType(),\n caption: node.getName(),\n state: node.getState(),\n guards,\n callbacks,\n args: node.getArguments(),\n parentId: parentUid\n });\n\n // Process each of the nodes children if it is not a leaf node.\n if (!node.isLeafNode()) {\n (node as Composite | Decorator)\n .getChildren()\n .forEach((child) => processNode(child, (node as Composite | Decorator).getUid()));\n }\n };\n\n // Convert the nested node structure into a flattened array of node details.\n processNode(this.rootNode, null);\n\n return flattenedTreeNodes;\n }\n\n /**\n * Registers the action/condition/guard/callback function or subtree with the given name.\n * @param name The name of the function or subtree to register.\n * @param value The function or subtree definition to register.\n */\n static register(name: string, value: GlobalFunction | string | RootNodeDefinition) {\n // Are we going to register a action/condition/guard/callback function?\n if (typeof value === \"function\") {\n Lookup.setFunc(name, value);\n return;\n }\n\n // We are not registering an action/condition/guard/callback function, so we must be registering a subtree.\n if (typeof value === \"string\") {\n let rootNodeDefinitions: RootNodeDefinition[];\n\n // We will assume that any string passed in will be a mdsl definition.\n try {\n rootNodeDefinitions = convertMDSLToJSON(value);\n } catch (exception) {\n throw new Error(`error registering definition, invalid MDSL: ${(exception as Error).message}`);\n }\n\n // This function should only ever be called with a definition containing a single unnamed root node.\n if (rootNodeDefinitions.length != 1 || rootNodeDefinitions[0].id !== null) {\n throw new Error(\"error registering definition: expected a single unnamed root node\");\n }\n\n try {\n // We should validate the subtree as we don't want invalid subtrees available via the lookup.\n const { succeeded, errorMessage } = validateJSONDefinition(rootNodeDefinitions[0]);\n\n // Did our validation fail without error?\n if (!succeeded) {\n throw new Error(errorMessage);\n }\n } catch (exception) {\n throw new Error(`error registering definition: ${(exception as Error).message}`);\n }\n\n // Everything seems hunky-dory, register the subtree.\n Lookup.setSubtree(name, rootNodeDefinitions[0]);\n } else if (typeof value === \"object\" && !Array.isArray(value)) {\n // We will assume that any object passed in is a root node definition.\n\n try {\n // We should validate the subtree as we don't want invalid subtrees available via the lookup.\n const { succeeded, errorMessage } = validateJSONDefinition(value);\n\n // Did our validation fail without error?\n if (!succeeded) {\n throw new Error(errorMessage);\n }\n } catch (exception) {\n throw new Error(`error registering definition: ${(exception as Error).message}`);\n }\n\n // Everything seems hunky-dory, register the subtree.\n Lookup.setSubtree(name, value);\n } else {\n throw new Error(\"unexpected value, expected string mdsl definition, root node json definition or function\");\n }\n }\n\n /**\n * Unregisters the registered action/condition/guard/callback function or subtree with the given name.\n * @param name The name of the registered action/condition/guard/callback function or subtree to unregister.\n */\n static unregister(name: string): void {\n Lookup.remove(name);\n }\n\n /**\n * Unregister all registered action/condition/guard/callback functions and subtrees.\n */\n static unregisterAll(): void {\n Lookup.empty();\n }\n\n /**\n * Parses a behaviour tree definition and creates a tree of behaviour tree nodes populated at a root.\n * @param {string | RootNodeDefinition | RootNodeDefinition[]} definition The behaviour tree definition.\n * @returns The root behaviour tree node.\n */\n private _createRootNode(definition: string | RootNodeDefinition | RootNodeDefinition[]): Root {\n // Our definition will have to be converted to JSON if it is a MDSL string.\n // TODO convertMDSLToJSON is called TWICE, once for validation and once here. Maybe return the JSON as part of the validation result?\n const resolvedDefinition = typeof definition === \"string\" ? convertMDSLToJSON(definition) : definition;\n\n // Build and populate the root node.\n return buildRootNode(Array.isArray(resolvedDefinition) ? resolvedDefinition : [resolvedDefinition]);\n }\n}\n"], - "mappings": "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", + "sourcesContent": ["\"use strict\";\r\nObject.defineProperty(exports, \"__esModule\", { value: true });\r\nexports.Participant = void 0;\r\n/**\r\n * A participant that holds a number of tickets.\r\n */\r\nvar Participant = /** @class */ (function () {\r\n /**\r\n * Creates an instance of the Participant class.\r\n * @param participant The actual participant.\r\n * @param tickets The number of tickets held by the participant.\r\n */\r\n function Participant(participant, tickets) {\r\n if (tickets === void 0) { tickets = 1; }\r\n this._participant = participant;\r\n this._tickets = tickets;\r\n }\r\n Object.defineProperty(Participant.prototype, \"participant\", {\r\n /** Gets the actual participant. */\r\n get: function () {\r\n return this._participant;\r\n },\r\n enumerable: false,\r\n configurable: true\r\n });\r\n Object.defineProperty(Participant.prototype, \"tickets\", {\r\n /** Gets or sets the number of tickets held by the participant. */\r\n get: function () {\r\n return this._tickets;\r\n },\r\n set: function (value) {\r\n this._tickets = value;\r\n },\r\n enumerable: false,\r\n configurable: true\r\n });\r\n return Participant;\r\n}());\r\nexports.Participant = Participant;\r\n", "\"use strict\";\r\nObject.defineProperty(exports, \"__esModule\", { value: true });\r\nexports.isNaturalNumber = exports.isNullOrUndefined = void 0;\r\n/**\r\n * Gets whether the value provided is null or undefined.\r\n * @param value The value to check.\r\n * @returns Whether the value provided is null or undefined.\r\n */\r\nfunction isNullOrUndefined(value) {\r\n return value === null || value === undefined;\r\n}\r\nexports.isNullOrUndefined = isNullOrUndefined;\r\n/**\r\n * Gets whether the value provided is a natural number.\r\n * @param value The value to check.\r\n * @returns Whether the value provided is a natural number.\r\n */\r\nfunction isNaturalNumber(value) {\r\n return typeof value === \"number\" && value >= 1 && Math.floor(value) === value;\r\n}\r\nexports.isNaturalNumber = isNaturalNumber;\r\n", "\"use strict\";\r\nObject.defineProperty(exports, \"__esModule\", { value: true });\r\nexports.Lotto = void 0;\r\nvar Participant_1 = require(\"./Participant\");\r\nvar Utilities_1 = require(\"./Utilities\");\r\n/**\r\n * Represents a lotto consisting of a number of pickable ticket-holding participants.\r\n */\r\nvar Lotto = /** @class */ (function () {\r\n /**\r\n * Creates a new instance of Lotto.\r\n * @param customRandom The custom RNG to use in place of Math.random().\r\n */\r\n function Lotto(customRandom) {\r\n /** The array of participants that are holding tickets in the lotto. */\r\n this._participants = [];\r\n this._customRandom = customRandom;\r\n }\r\n /**\r\n * Adds a participant with the specified number of tickets, or adds to the participant ticket count if the participant already holds tickets.\r\n * @param participant The participant to add or to increase the ticket count for if they already hold tickets.\r\n * @param tickets The number of tickets, defaults to 1.\r\n * @returns The Lotto instance.\r\n */\r\n Lotto.prototype.add = function (participant, tickets) {\r\n if (tickets === void 0) { tickets = 1; }\r\n // Check that we have a valid ticket count.\r\n if (!(0, Utilities_1.isNaturalNumber)(tickets)) {\r\n throw new Error(\"tickets value must be a natural number\");\r\n }\r\n // Check whether this participant has already been added.\r\n var existingParticipant = this._participants.find(function (part) { return part.participant === participant; });\r\n if (existingParticipant) {\r\n // The participant has already been added to the lotto so just add to their ticket count.\r\n existingParticipant.tickets += tickets;\r\n }\r\n else {\r\n // The participant is not part of the lotto so we should add them.\r\n this._participants.push(new Participant_1.Participant(participant, tickets));\r\n }\r\n return this;\r\n };\r\n /**\r\n * Removes the specified number of tickets for the given participant from the draw, or all tickets if a ticket number is not defined.\r\n * @param participant The participant to remove tickets for.\r\n * @param tickets The number of tickets to remove, or undefined if all tickets are to be removed.\r\n * @returns The Lotto instance.\r\n */\r\n Lotto.prototype.remove = function (participant, tickets) {\r\n // Attempt to get the existing participant.\r\n var existingParticipant = this._participants.find(function (part) { return part.participant === participant; });\r\n // There is nothing to do if the specified participant isn't even part of the lotto.\r\n if (!existingParticipant) {\r\n return this;\r\n }\r\n // Check whether a tickets value was given.\r\n if (tickets !== undefined) {\r\n // Check that we have a valid ticket count.\r\n if (!(0, Utilities_1.isNaturalNumber)(tickets)) {\r\n throw new Error(\"tickets value must be a natural number\");\r\n }\r\n existingParticipant.tickets -= tickets;\r\n // If the participant no longer holds any tickets then they should be removed.\r\n if (existingParticipant.tickets < 1) {\r\n this._participants = this._participants.filter(function (part) { return part !== existingParticipant; });\r\n }\r\n }\r\n else {\r\n // We are removing all tickets for the participant so just remove them from the lotto.\r\n this._participants = this._participants.filter(function (part) { return part !== existingParticipant; });\r\n }\r\n return this;\r\n };\r\n /**\r\n * Draw a winning ticket and return the participant that holds the ticket.\r\n * @param options The draw options.\r\n * @returns The participant that holds the winning ticket.\r\n */\r\n Lotto.prototype.draw = function (options) {\r\n if (options === void 0) { options = {}; }\r\n // If we have no participants then just return null.\r\n if (this._participants.length === 0) {\r\n return null;\r\n }\r\n var redrawable = (0, Utilities_1.isNullOrUndefined)(options.redrawable) ? true : options.redrawable;\r\n var pickable = [];\r\n this._participants.forEach(function (_a) {\r\n var participant = _a.participant, tickets = _a.tickets;\r\n for (var ticketCount = 0; ticketCount < tickets; ticketCount++) {\r\n pickable.push(participant);\r\n }\r\n });\r\n var random;\r\n // We need a random floating-point number between 0 (inclusive) and 1 to scale up to pick our winner.\r\n // If a custom random function exists then we should use that or fall back to Math.random().\r\n if (this._customRandom) {\r\n // Call our custom random function to get a random floating-point number.\r\n random = this._customRandom();\r\n // Verify that the result of calling our custom random function is a number between 0 (inclusive) and 1.\r\n if (typeof random !== \"number\" || random < 0 || random >= 1) {\r\n throw new Error(\"the 'random' function provided did not return a number between 0 (inclusive) and 1\");\r\n }\r\n }\r\n else {\r\n // No custom random function was defined so just use good ol' Math.random().\r\n random = Math.random();\r\n }\r\n // Pick a winning participant.\r\n var winner = pickable[Math.floor(random * pickable.length)];\r\n // If the ticket isn't redrawable then we should remove a ticket from the winning participants ticket count.\r\n if (!redrawable) {\r\n this.remove(winner, 1);\r\n }\r\n // Return the winning participant.\r\n return winner;\r\n };\r\n /**\r\n * Draws multiple winning tickets and return an array of the participants that hold the winning tickets.\r\n * @param tickets The number of winning tickets to draw.\r\n * @param options The draw multiple options.\r\n * @returns An array of the participants that hold the winning tickets.\r\n */\r\n Lotto.prototype.drawMultiple = function (tickets, options) {\r\n if (options === void 0) { options = {}; }\r\n var uniqueResults = (0, Utilities_1.isNullOrUndefined)(options.unique) ? false : options.unique;\r\n // Handle cases where the user has asked for zero tickets (no idea why they would do this be we should trust them).\r\n if (tickets === 0) {\r\n return [];\r\n }\r\n // Now that we know out tickets value is not zero we should check that it is a valid natural number.\r\n if (!(0, Utilities_1.isNaturalNumber)(tickets)) {\r\n throw new Error(\"tickets value must be a natural number\");\r\n }\r\n var result = [];\r\n // Keep drawing tickets until we either reach the number of required tickets or we simply run out of tickets to draw.\r\n // We can run out of tickets to draw if 'options.redrawable' is explicity 'false' or we just had no participants when 'drawMultiple' was called.\r\n while (result.length < tickets && this._participants.length > 0) {\r\n result.push(this.draw(options));\r\n }\r\n // If the 'unique' draw option is set then we need to remove duplicates from the result list.\r\n if (uniqueResults) {\r\n // Create an array to store our unique results.\r\n var unique = [];\r\n // Iterate over all of our participants (with potential duplicates) and populate our array of unique values.\r\n for (var _i = 0, result_1 = result; _i < result_1.length; _i++) {\r\n var participant = result_1[_i];\r\n if (unique.indexOf(participant) === -1) {\r\n unique.push(participant);\r\n }\r\n }\r\n result = unique;\r\n }\r\n return result;\r\n };\r\n return Lotto;\r\n}());\r\nexports.Lotto = Lotto;\r\n", "\"use strict\";\r\nObject.defineProperty(exports, \"__esModule\", { value: true });\r\nexports.createLotto = void 0;\r\nvar Lotto_1 = require(\"./Lotto\");\r\n/**\r\n * A function that creates and returns a Lotto instance.\r\n * @param participantsOrOptions An array of initial participants or options relating to the creation of a Lotto instance.\r\n * @returns A new Lotto instance.\r\n */\r\nfunction createLotto(participantsOrOptions) {\r\n // If no initial participants or lotto options were provided as an argument then we can just return a new lotto instance now.\r\n if (!participantsOrOptions) {\r\n return new Lotto_1.Lotto();\r\n }\r\n // Check whether we were provided with an array of initial participants or a lotto options object.\r\n if (Array.isArray(participantsOrOptions)) {\r\n // We are dealing with a pre-defined array of participants.\r\n var participants = participantsOrOptions;\r\n var lotto_1 = new Lotto_1.Lotto();\r\n // If the lotto participants have been defined upfront then we will need to add them all to our lotto instance now.\r\n participants.forEach(function (_a) {\r\n var participant = _a[0], tokens = _a[1];\r\n return lotto_1.add(participant, tokens);\r\n });\r\n // Return the Lotto instance.\r\n return lotto_1;\r\n }\r\n else {\r\n // We are dealing with some lotto options.\r\n var random = participantsOrOptions.random, participants = participantsOrOptions.participants;\r\n // Create a Lotto instance passing the custom RNG function to use in place of Math.random() (which could be undefined).\r\n var lotto_2 = new Lotto_1.Lotto(random);\r\n // If the lotto participants have been defined upfront as part of the options then we will need to add them all to our lotto instance now.\r\n if (participants) {\r\n participants.forEach(function (_a) {\r\n var participant = _a[0], tokens = _a[1];\r\n return lotto_2.add(participant, tokens);\r\n });\r\n }\r\n // Return the Lotto instance.\r\n return lotto_2;\r\n }\r\n}\r\nexports.createLotto = createLotto;\r\n", "\"use strict\";\r\nObject.defineProperty(exports, \"__esModule\", { value: true });\r\nvar createLotto_1 = require(\"./createLotto\");\r\nexports.default = createLotto_1.createLotto;\r\n", "import State from \"./State\";\nimport { validateDefinition } from \"./BehaviourTreeDefinitionValidator\";\nimport { convertMDSLToJSON } from \"./mdsl/MDSLDefinitionParser\";\nimport { BehaviourTree, FlattenedTreeNode } from \"./BehaviourTree\";\nimport { BehaviourTreeOptions } from \"./BehaviourTreeOptions\";\n\nexport { BehaviourTree, State, convertMDSLToJSON, validateDefinition };\nexport type { FlattenedTreeNode, BehaviourTreeOptions };\n", "/**\n * Enumeration of node state types.\n */\nexport enum State {\n READY = \"mistreevous.ready\",\n RUNNING = \"mistreevous.running\",\n SUCCEEDED = \"mistreevous.succeeded\",\n FAILED = \"mistreevous.failed\"\n}\n\nexport { State as default };\n\nexport type CompleteState = State.SUCCEEDED | State.FAILED;\nexport type AnyState = State.READY | State.RUNNING | CompleteState;\n", "import {\n NodeDefinition,\n RootNodeDefinition,\n DecoratorNodeDefinition,\n CompositeNodeDefinition,\n AnyNodeDefinition,\n BranchNodeDefinition\n} from \"./BehaviourTreeDefinition\";\n\n/**\n * A type guard function that returns true if the specified node satisfies the RootNodeDefinition type.\n * @param node The node.\n * @returns A value of true if the specified node satisfies the RootNodeDefinition type.\n */\nexport function isRootNode(node: NodeDefinition): node is RootNodeDefinition {\n return node.type === \"root\";\n}\n\n/**\n * A type guard function that returns true if the specified node satisfies the BranchNodeDefinition type.\n * @param node The node.\n * @returns A value of true if the specified node satisfies the BranchNodeDefinition type.\n */\nexport function isBranchNode(node: NodeDefinition): node is BranchNodeDefinition {\n return node.type === \"branch\";\n}\n\n/**\n * A type guard function that returns true if the specified node satisfies the NodeDefinition type.\n * @param node The node.\n * @returns A value of true if the specified node satisfies the NodeDefinition type.\n */\nexport function isLeafNode(node: NodeDefinition): node is NodeDefinition {\n return [\"branch\", \"action\", \"condition\", \"wait\"].includes(node.type);\n}\n\n/**\n * A type guard function that returns true if the specified node satisfies the DecoratorNodeDefinition type.\n * @param node The node.\n * @returns A value of true if the specified node satisfies the DecoratorNodeDefinition type.\n */\nexport function isDecoratorNode(node: NodeDefinition): node is DecoratorNodeDefinition {\n return [\"root\", \"repeat\", \"retry\", \"flip\", \"succeed\", \"fail\"].includes(node.type);\n}\n\n/**\n * A type guard function that returns true if the specified node satisfies the CompositeNodeDefinition type.\n * @param node The node.\n * @returns A value of true if the specified node satisfies the CompositeNodeDefinition type.\n */\nexport function isCompositeNode(node: NodeDefinition): node is CompositeNodeDefinition {\n return [\"sequence\", \"selector\", \"lotto\", \"parallel\"].includes(node.type);\n}\n\n/**\n * Flatten a node definition into an array of all of its nested node definitions.\n * @param nodeDefinition The node definition to flatten.\n * @returns An array of all of nested node definitions.\n */\nexport function flattenDefinition(nodeDefinition: AnyNodeDefinition): AnyNodeDefinition[] {\n const nodes: AnyNodeDefinition[] = [];\n\n const processNode = (currentNodeDefinition: AnyNodeDefinition) => {\n nodes.push(currentNodeDefinition);\n\n if (isCompositeNode(currentNodeDefinition)) {\n currentNodeDefinition.children.forEach(processNode);\n } else if (isDecoratorNode(currentNodeDefinition)) {\n processNode(currentNodeDefinition.child);\n }\n };\n\n processNode(nodeDefinition);\n\n return nodes;\n}\n\n/**\n * Determines whether the passed value is an integer.\n * @param value The value to check.\n * @returns Whether the passed value is an integer.\n */\nexport function isInteger(value: unknown): boolean {\n return typeof value === \"number\" && Math.floor(value) === value;\n}\n\n/**\n * Determines whether the passed value is null or undefined.\n * @param value The value to check.\n * @returns Whether the passed value is null or undefined.\n */\nexport function isNullOrUndefined(value: unknown): boolean {\n return typeof value === \"undefined\" || value === null;\n}\n", "/**\n * A type defining an object that holds a reference to substitued string literals parsed from the definition.\n */\nexport type StringLiteralPlaceholders = { [key: string]: string };\n\n/**\n * Pop the next raw token from the specified array of tokens and throw an error if it wasn't the expected one.\n * @param tokens The array of tokens.\n * @param expected An optional string or array or items, one of which must match the next popped token.\n * @returns The popped token.\n */\nexport function popAndCheck(tokens: string[], expected?: string | string[]): string {\n // Get and remove the next token.\n const popped = tokens.shift();\n\n // We were expecting another token but there aren't any.\n if (popped === undefined) {\n throw new Error(\"unexpected end of definition\");\n }\n\n // Do we have an expected token/tokens array?\n if (expected != undefined) {\n // Get an array of expected values, if the popped token matches any then we are all good.\n const expectedValues = typeof expected === \"string\" ? [expected] : expected;\n\n // Check whether the popped token matches at least one of our expected items.\n var tokenMatchesExpectation = expectedValues.some((item) => popped.toUpperCase() === item.toUpperCase());\n\n // Throw an error if the popped token didn't match any of our expected items.\n if (!tokenMatchesExpectation) {\n const expectationString = expectedValues.map((item) => \"'\" + item + \"'\").join(\" or \");\n throw new Error(\"unexpected token found. Expected \" + expectationString + \" but got '\" + popped + \"'\");\n }\n }\n\n // Return the popped token.\n return popped;\n}\n\n/**\n * Swaps out any node/attribute argument string literals with placeholders.\n * @param definition The definition.\n * @returns An object containing a mapping of placeholders to original string values as well as the processed definition string.\n */\nexport function substituteStringLiterals(definition: string): {\n placeholders: StringLiteralPlaceholders;\n processedDefinition: string;\n} {\n // Create an object to hold the mapping of placeholders to original string values.\n const placeholders: StringLiteralPlaceholders = {};\n\n // Replace any string literals wrapped with double quotes in our definition with placeholders to be processed later.\n const processedDefinition = definition.replace(/\\\"(\\\\.|[^\"\\\\])*\\\"/g, (match) => {\n var strippedMatch = match.substring(1, match.length - 1);\n var placeholder = Object.keys(placeholders).find((key) => placeholders[key] === strippedMatch);\n\n // If we have no existing string literal match then create a new placeholder.\n if (!placeholder) {\n placeholder = `@@${Object.keys(placeholders).length}@@`;\n placeholders[placeholder] = strippedMatch;\n }\n\n return placeholder;\n });\n\n return { placeholders, processedDefinition };\n}\n\n/**\n * Parse the tree definition into an array of raw tokens.\n * @param definition The definition.\n * @returns An array of tokens parsed from the definition.\n */\nexport function parseTokensFromDefinition(definition: string): string[] {\n // Add some space around various important characters so that they can be plucked out easier as individual tokens.\n definition = definition.replace(/\\(/g, \" ( \");\n definition = definition.replace(/\\)/g, \" ) \");\n definition = definition.replace(/\\{/g, \" { \");\n definition = definition.replace(/\\}/g, \" } \");\n definition = definition.replace(/\\]/g, \" ] \");\n definition = definition.replace(/\\[/g, \" [ \");\n definition = definition.replace(/\\,/g, \" , \");\n\n // Split the definition into raw token form and return it.\n return definition.replace(/\\s+/g, \" \").trim().split(\" \");\n}\n", "import { StringLiteralPlaceholders, popAndCheck } from \"./MDSLUtilities\";\n\n/**\n * A type representing any node function argument.\n */\ntype Argument = {\n /**\n * The argument value.\n */\n value: T;\n /**\n * The argument type, used for validation.\n */\n type: string;\n};\n\ntype NullArgument = Argument & {\n type: \"null\";\n};\n\ntype BooleanArgument = Argument & {\n type: \"boolean\";\n};\n\ntype NumberArgument = Argument & {\n type: \"number\";\n /**\n * A flag defining whether the number argument value is a valid integer. (used for validation)\n */\n isInteger: boolean;\n};\n\ntype StringPlaceholderArgument = Argument & {\n type: \"string\";\n};\n\ntype IdentifierArgument = Argument & {\n type: \"identifier\";\n};\n\n/**\n * A type representing a reference to any node function argument.\n */\ntype AnyArgument = NullArgument | BooleanArgument | NumberArgument | StringPlaceholderArgument | IdentifierArgument;\n\n/**\n * Parse an array of argument definitions from the specified tokens array.\n * @param tokens The array tokens to parse the argument definitions from.\n * @param stringArgumentPlaceholders The mapping of string literal node argument placeholders to original values.\n * @param argumentValidator The argument validator function.\n * @param validationFailedMessage The exception message to throw if argument validation fails.\n * @returns An array of argument definitions parsed from the specified tokens array.\n */\nexport function parseArgumentTokens(\n tokens: string[],\n stringArgumentPlaceholders: StringLiteralPlaceholders\n): AnyArgument[] {\n const argumentList: AnyArgument[] = [];\n\n // If the next token is not a '[' or '(' then we have no arguments to parse.\n if (![\"[\", \"(\"].includes(tokens[0])) {\n return argumentList;\n }\n\n // Any lists of arguments will always be wrapped in '[]' for node arguments or '()' for attribute arguments.\n // We are looking for a '[' or '(' opener that wraps the argument tokens and the relevant closer.\n const closingToken = popAndCheck(tokens, [\"[\", \"(\"]) === \"[\" ? \"]\" : \")\";\n\n const argumentListTokens: string[] = [];\n\n // Grab all tokens between the '[' and ']' or '(' and ')'.\n while (tokens.length && tokens[0] !== closingToken) {\n // The next token is part of our arguments list.\n argumentListTokens.push(tokens.shift()!);\n }\n\n // Validate the order of the argument tokens. Each token must either be a ',' or a single argument that satisfies the validator.\n argumentListTokens.forEach((token, index) => {\n // Get whether this token should be an actual argument.\n const shouldBeArgumentToken = !(index & 1);\n\n // If the current token should be an actual argument then validate it, otherwise it should be a ',' token.\n if (shouldBeArgumentToken) {\n // Get the argument definition.\n const argumentDefinition = getArgumentDefinition(token, stringArgumentPlaceholders);\n\n // This is a valid argument!\n argumentList.push(argumentDefinition);\n } else {\n // The current token should be a ',' token.\n if (token !== \",\") {\n throw new Error(`invalid argument list, expected ',' or ']' but got '${token}'`);\n }\n }\n });\n\n // The arguments list should terminate with a ']' or ')' token, depending on the opener.\n popAndCheck(tokens, closingToken);\n\n // Return the arguments.\n return argumentList;\n}\n\n/**\n * Gets an argument value definition.\n * @param token The argument token.\n * @param stringArgumentPlaceholders The mapping of string literal node argument placeholders to original values.\n * @returns An argument value definition.\n */\nfunction getArgumentDefinition(token: string, stringArgumentPlaceholders: StringLiteralPlaceholders): AnyArgument {\n // Check whether the token represents a null value.\n if (token === \"null\") {\n return {\n value: null,\n type: \"null\"\n } as NullArgument;\n }\n\n // Check whether the token represents a boolean value.\n if (token === \"true\" || token === \"false\") {\n return {\n value: token === \"true\",\n type: \"boolean\"\n } as BooleanArgument;\n }\n\n // Check whether the token represents a number value.\n // TODO: Relies on broken isNaN - see MDN.\n // if (!Number.isNaN(token)) {\n if (!isNaN(token as any)) {\n return {\n value: parseFloat(token),\n isInteger: parseFloat(token) === parseInt(token, 10),\n type: \"number\"\n } as NumberArgument;\n }\n\n // Check whether the token is a placeholder (e.g. @@0@@) representing a string literal.\n if (token.match(/^@@\\d+@@$/g)) {\n return {\n value: stringArgumentPlaceholders[token].replace('\\\\\"', '\"'),\n type: \"string\"\n } as StringPlaceholderArgument;\n }\n\n // The only remaining option is that the argument value is an identifier.\n return {\n value: token,\n type: \"identifier\"\n } as IdentifierArgument;\n}\n", "import { NodeAttributeDefinition } from \"../BehaviourTreeDefinition\";\nimport { parseArgumentTokens } from \"./MDSLNodeArgumentParser\";\nimport { StringLiteralPlaceholders } from \"./MDSLUtilities\";\n\n/**\n * A type defining the attribute definitions of a node.\n */\ntype NodeAttributes = {\n while?: NodeAttributeDefinition;\n until?: NodeAttributeDefinition;\n entry?: NodeAttributeDefinition;\n exit?: NodeAttributeDefinition;\n step?: NodeAttributeDefinition;\n};\n\n/**\n * Parse any node attribute definitions from the specified tokens array.\n * @param tokens The array of remaining tokens.\n * @param stringArgumentPlaceholders The mapping of string literal node argument placeholders to original values.\n * @returns An object of attribute definitions defined by any directly following tokens.\n */\nexport function parseAttributeTokens(\n tokens: string[],\n stringArgumentPlaceholders: StringLiteralPlaceholders\n): NodeAttributes {\n const nodeAttributeNames: (keyof NodeAttributes)[] = [\"while\", \"until\", \"entry\", \"exit\", \"step\"];\n\n // Create an object to hold any attributes found.\n const attributes: NodeAttributes = {};\n\n // Try to get the name of the attribute for the next token.\n let nextAttributeName = tokens[0]?.toLowerCase() as keyof NodeAttributes;\n\n // Pull attribute tokens as well as their arguments off of the tokens stack until we have no more.\n while (nodeAttributeNames.includes(nextAttributeName)) {\n // Check to make sure that we have not already created an attribute definition of this type.\n if (attributes[nextAttributeName]) {\n throw new Error(`duplicate attribute '${tokens[0].toUpperCase()}' found for node`);\n }\n\n // Remove the attribute name token from the array of tokens.\n tokens.shift();\n\n // Grab the attribute arguments, assuming the first to be an identifier.\n const [attributeCallIdentifier, ...attributeArguments] = parseArgumentTokens(\n tokens,\n stringArgumentPlaceholders\n );\n\n // The first attribute argument has to be an identifer, this will reference an agent function.\n if (attributeCallIdentifier?.type !== \"identifier\") {\n throw new Error(\"expected agent function name identifier argument for attribute\");\n }\n\n // Any attribute arguments (other than the expected call identifier) must have a type of string, number, boolean or null.\n attributeArguments\n .filter((arg) => arg.type === \"identifier\")\n .forEach((arg) => {\n throw new Error(\n `invalid attribute argument value '${arg.value}', must be string, number, boolean or null`\n );\n });\n\n // Create the attribute definition and add it to the object of attribute definitions found.\n attributes[nextAttributeName] = {\n call: attributeCallIdentifier.value,\n args: attributeArguments.map(({ value }) => value)\n };\n\n // Try to get the next attribute name token, as there could be multiple.\n nextAttributeName = tokens[0]?.toLowerCase() as keyof NodeAttributes;\n }\n\n return attributes;\n}\n", "import {\n ActionNodeDefinition,\n AnyChildNodeDefinition,\n AnyNodeDefinition,\n BranchNodeDefinition,\n ConditionNodeDefinition,\n FailNodeDefinition,\n FlipNodeDefinition,\n LottoNodeDefinition,\n ParallelNodeDefinition,\n RepeatNodeDefinition,\n RetryNodeDefinition,\n RootNodeDefinition,\n SelectorNodeDefinition,\n SequenceNodeDefinition,\n SucceedNodeDefinition,\n WaitNodeDefinition\n} from \"../BehaviourTreeDefinition\";\nimport {\n isCompositeNode,\n isDecoratorNode,\n isLeafNode,\n isNullOrUndefined,\n isRootNode\n} from \"../BehaviourTreeDefinitionUtilities\";\nimport { parseArgumentTokens } from \"./MDSLNodeArgumentParser\";\nimport { parseAttributeTokens } from \"./MDSLNodeAttributeParser\";\nimport {\n StringLiteralPlaceholders,\n parseTokensFromDefinition,\n popAndCheck,\n substituteStringLiterals\n} from \"./MDSLUtilities\";\n\n/**\n * Convert the MDSL tree definition string into an equivalent JSON definition.\n * @param definition The tree definition string as MDSL.\n * @returns The root node JSON definitions.\n */\nexport function convertMDSLToJSON(definition: string): RootNodeDefinition[] {\n // Swap out any node/attribute argument string literals with a placeholder and get a mapping of placeholders to original values as well as the processed definition.\n const { placeholders, processedDefinition } = substituteStringLiterals(definition);\n\n // Parse our definition definition string into an array of raw tokens.\n const tokens = parseTokensFromDefinition(processedDefinition);\n\n return convertTokensToJSONDefinition(tokens, placeholders);\n}\n\n/**\n * Converts the specified tree definition tokens into a JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The root node JSON definitions.\n */\nfunction convertTokensToJSONDefinition(\n tokens: string[],\n stringLiteralPlaceholders: StringLiteralPlaceholders\n): RootNodeDefinition[] {\n // There must be at least 3 tokens for the tree definition to be valid. 'ROOT', '{' and '}'.\n if (tokens.length < 3) {\n throw new Error(\"invalid token count\");\n }\n\n // We should have a matching number of '{' and '}' tokens. If not, then there are scopes that have not been properly closed.\n if (tokens.filter((token) => token === \"{\").length !== tokens.filter((token) => token === \"}\").length) {\n throw new Error(\"scope character mismatch\");\n }\n\n // Create an array of tree stack arrays where root nodes will always be at the botton and the current composite/decorator node at the top.\n // There should be an element in this array for every root node defined and every element should be an array with a root note as the first element.\n // E.g. A definition with two root nodes defined:\n // [\n // [root, lotto, sequence],\n // [root, selector]\n // ]\n const treeStacks: [Partial, ...Partial[]][] = [];\n\n // Create an array of all root node definitions that we create.\n const rootNodes: Partial[] = [];\n\n // A helper function used to push node definitions onto the tree stack.\n const pushNode = (node: AnyNodeDefinition) => {\n // If the node is a root node then we need to create a new tree stack array with the root node at the root.\n if (isRootNode(node)) {\n // We need to double-check that this root node is not the child of another node.\n // We can do this by checking whether the top tree stack is not empty (contains an existing node)\n if (treeStacks[treeStacks.length - 1]?.length) {\n throw new Error(\"a root node cannot be the child of another node\");\n }\n\n // Add the root node definition to our array of all parsed root node definitions.\n rootNodes.push(node);\n\n // Add the root node definition to the root of a new tree stack.\n treeStacks.push([node]);\n\n return;\n }\n\n // All non-root nodes should be pushed after their root nodes so handle cases\n // where we may not have any tree stacks or our top-most tree stack is empty.\n if (!treeStacks.length || !treeStacks[treeStacks.length - 1].length) {\n throw new Error(\"expected root node at base of definition\");\n }\n\n // Get the current tree stack that we are populating.\n const topTreeStack = treeStacks[treeStacks.length - 1];\n\n // Get the top-most node in the current tree stack, this will be a composite/decorator node\n // for which we will populate its children array if composite or setting its child if a decorator.\n const topTreeStackTopNode = topTreeStack[topTreeStack.length - 1] as AnyNodeDefinition;\n\n // If the top-most node in the current root stack is a composite or decorator\n // node then the current node should be added as a child of the top-most node.\n if (isCompositeNode(topTreeStackTopNode)) {\n topTreeStackTopNode.children = topTreeStackTopNode.children || [];\n topTreeStackTopNode.children.push(node);\n } else if (isDecoratorNode(topTreeStackTopNode)) {\n // If the top node already has a child node set then throw an error as a decorator should only have a single child.\n if (topTreeStackTopNode.child) {\n throw new Error(\"a decorator node must only have a single child node\");\n }\n\n topTreeStackTopNode.child = node;\n }\n\n // If the node we are adding is also a composite or decorator node, then we should push it\n // onto the current tree stack, as subsequent nodes will be added as its child/children.\n if (!isLeafNode(node)) {\n topTreeStack.push(node);\n }\n };\n\n // A helper function used to pop the top-most node definition off of the tree stack and return it.\n const popNode = (): AnyNodeDefinition | null => {\n let poppedNode: AnyNodeDefinition | null = null;\n\n // Get the current tree stack that we are populating.\n const topTreeStack = treeStacks[treeStacks.length - 1];\n\n // Pop the top-most node in the current tree stack if there is one.\n if (topTreeStack.length) {\n poppedNode = topTreeStack.pop() as AnyNodeDefinition;\n }\n\n // We don't want any empty tree stacks in our stack of tree stacks.\n if (!topTreeStack.length) {\n treeStacks.pop();\n }\n\n return poppedNode;\n };\n\n // We should keep processing the raw tokens until we run out of them.\n while (tokens.length) {\n // Grab the next token.\n const token = tokens.shift()!;\n\n // How we create the next node depends on the current raw token value.\n switch (token.toUpperCase()) {\n case \"ROOT\": {\n pushNode(createRootNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"SUCCEED\": {\n pushNode(createSucceedNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"FAIL\": {\n pushNode(createFailNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"FLIP\": {\n pushNode(createFlipNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"REPEAT\": {\n pushNode(createRepeatNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"RETRY\": {\n pushNode(createRetryNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"SEQUENCE\": {\n pushNode(createSequenceNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"SELECTOR\": {\n pushNode(createSelectorNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"PARALLEL\": {\n pushNode(createParallelNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"LOTTO\": {\n pushNode(createLottoNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"ACTION\": {\n pushNode(createActionNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"CONDITION\": {\n pushNode(createConditionNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"WAIT\": {\n pushNode(createWaitNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"BRANCH\": {\n pushNode(createBranchNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"}\": {\n // The '}' character closes the current scope and means that we have to pop a node off of the current stack.\n const poppedNode = popNode();\n\n // Now that we have a node definition we can carry out any validation that may require the node to be fully populated.\n if (poppedNode) {\n validatePoppedNode(poppedNode);\n }\n\n break;\n }\n\n default: {\n throw new Error(`unexpected token: ${token}`);\n }\n }\n }\n\n return rootNodes as RootNodeDefinition[];\n}\n\n/**\n * Creates a root node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The root node JSON definition.\n */\nfunction createRootNode(tokens: string[], stringLiteralPlaceholders: StringLiteralPlaceholders): RootNodeDefinition {\n // Create the root node definition.\n let node = {\n type: \"root\",\n id: undefined\n } as RootNodeDefinition;\n\n // Parse any node arguments, we should only have one if any which will be an identifier argument for the root identifier.\n const nodeArguments = parseArgumentTokens(tokens, stringLiteralPlaceholders);\n\n // Check whether any node arguments were defined.\n if (nodeArguments.length) {\n // We should only have one argument, if any, which will be an identifier argument for the root identifier.\n if (nodeArguments.length === 1 && nodeArguments[0].type === \"identifier\") {\n // The root node identifier will be the first and only node argument value.\n node.id = nodeArguments[0].value as string;\n } else {\n throw new Error(\"expected single root name argument\");\n }\n }\n\n // Grab any node attribute definitions and spread them into the node definition.\n node = { ...node, ...parseAttributeTokens(tokens, stringLiteralPlaceholders) };\n\n // This is a decorator node, so we expect an opening '{'.\n popAndCheck(tokens, \"{\");\n\n // Return the root node definition.\n return node;\n}\n\n/**\n * Creates a succeed node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The succeed node JSON definition.\n */\nfunction createSucceedNode(\n tokens: string[],\n stringLiteralPlaceholders: StringLiteralPlaceholders\n): SucceedNodeDefinition {\n const node = {\n type: \"succeed\",\n ...parseAttributeTokens(tokens, stringLiteralPlaceholders)\n } as SucceedNodeDefinition;\n\n // This is a decorator node, so we expect an opening '{'.\n popAndCheck(tokens, \"{\");\n\n // Return the succeed node definition.\n return node;\n}\n\n/**\n * Creates a fail node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The fail node JSON definition.\n */\nfunction createFailNode(tokens: string[], stringLiteralPlaceholders: StringLiteralPlaceholders): FailNodeDefinition {\n const node = {\n type: \"fail\",\n ...parseAttributeTokens(tokens, stringLiteralPlaceholders)\n } as FailNodeDefinition;\n\n // This is a decorator node, so we expect an opening '{'.\n popAndCheck(tokens, \"{\");\n\n // Return the fail node definition.\n return node;\n}\n\n/**\n * Creates a flip node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The flip node JSON definition.\n */\nfunction createFlipNode(tokens: string[], stringLiteralPlaceholders: StringLiteralPlaceholders): FlipNodeDefinition {\n const node = {\n type: \"flip\",\n ...parseAttributeTokens(tokens, stringLiteralPlaceholders)\n } as FlipNodeDefinition;\n\n // This is a decorator node, so we expect an opening '{'.\n popAndCheck(tokens, \"{\");\n\n // Return the flip node definition.\n return node;\n}\n\n/**\n * Creates a repeat node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The repeat node JSON definition.\n */\nfunction createRepeatNode(\n tokens: string[],\n stringLiteralPlaceholders: StringLiteralPlaceholders\n): RepeatNodeDefinition {\n let node = { type: \"repeat\" } as RepeatNodeDefinition;\n\n // Get the node arguments.\n const nodeArguments = parseArgumentTokens(tokens, stringLiteralPlaceholders);\n\n // The arguments of a repeat node are optional. We may have:\n // - No node arguments, in which case the repeat note will iterate indefinitely.\n // - One node argument which will be the explicit number of iterations to make.\n // - Two node arguments which define the min and max iteration bounds from which a random iteration count will be picked.\n if (nodeArguments.length) {\n // All repeat node arguments MUST be of type number and must be integer.\n nodeArguments\n .filter((arg) => arg.type !== \"number\" || !arg.isInteger)\n .forEach(() => {\n throw new Error(`repeat node iteration counts must be integer values`);\n });\n\n // We should have got one or two iteration counts.\n if (nodeArguments.length === 1) {\n // A static iteration count was defined.\n node.iterations = nodeArguments[0].value as number;\n\n // A repeat node must have a positive number of iterations if defined.\n if (node.iterations < 0) {\n throw new Error(\"a repeat node must have a positive number of iterations if defined\");\n }\n } else if (nodeArguments.length === 2) {\n // A minimum and maximum iteration count was defined.\n node.iterations = [nodeArguments[0].value as number, nodeArguments[1].value as number];\n\n // A repeat node must have a positive min and max iteration count if they are defined.\n if (node.iterations[0] < 0 || node.iterations[1] < 0) {\n throw new Error(\"a repeat node must have a positive minimum and maximum iteration count if defined\");\n }\n\n // A repeat node must not have an minimum iteration count that exceeds the maximum iteration count.\n if (node.iterations[0] > node.iterations[1]) {\n throw new Error(\n \"a repeat node must not have a minimum iteration count that exceeds the maximum iteration count\"\n );\n }\n } else {\n // An incorrect number of iteration counts was defined.\n throw new Error(\"invalid number of repeat node iteration count arguments defined\");\n }\n }\n\n // Grab any node attribute definitions and spread them into the node definition.\n node = { ...node, ...parseAttributeTokens(tokens, stringLiteralPlaceholders) };\n\n // This is a decorator node, so we expect an opening '{'.\n popAndCheck(tokens, \"{\");\n\n // Return the repeat node definition.\n return node;\n}\n\n/**\n * Creates a retry node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The retry node JSON definition.\n */\nfunction createRetryNode(tokens: string[], stringLiteralPlaceholders: StringLiteralPlaceholders): RetryNodeDefinition {\n let node = { type: \"retry\" } as RetryNodeDefinition;\n\n // Get the node arguments.\n const nodeArguments = parseArgumentTokens(tokens, stringLiteralPlaceholders);\n\n // The arguments of a retry node are optional. We may have:\n // - No node arguments, in which case the retry note will attempt indefinitely.\n // - One node argument which will be the explicit number of attempts to make.\n // - Two node arguments which define the min and max attempt bounds from which a random attempt count will be picked.\n if (nodeArguments.length) {\n // All retry node arguments MUST be of type number and must be integer.\n nodeArguments\n .filter((arg) => arg.type !== \"number\" || !arg.isInteger)\n .forEach(() => {\n throw new Error(`retry node attempt counts must be integer values`);\n });\n\n // We should have got one or two attempt counts.\n if (nodeArguments.length === 1) {\n // A static attempt count was defined.\n node.attempts = nodeArguments[0].value as number;\n\n // A retry node must have a positive number of attempts if defined.\n if (node.attempts < 0) {\n throw new Error(\"a retry node must have a positive number of attempts if defined\");\n }\n } else if (nodeArguments.length === 2) {\n // A minimum and maximum attempt count was defined.\n node.attempts = [nodeArguments[0].value as number, nodeArguments[1].value as number];\n\n // A retry node must have a positive min and max attempts count if they are defined.\n if (node.attempts[0] < 0 || node.attempts[1] < 0) {\n throw new Error(\"a retry node must have a positive minimum and maximum attempt count if defined\");\n }\n\n // A retry node must not have a minimum attempt count that exceeds the maximum attempt count.\n if (node.attempts[0] > node.attempts[1]) {\n throw new Error(\n \"a retry node must not have a minimum attempt count that exceeds the maximum attempt count\"\n );\n }\n } else {\n // An incorrect number of attempt counts was defined.\n throw new Error(\"invalid number of retry node attempt count arguments defined\");\n }\n }\n\n // Grab any node attribute definitions and spread them into the node definition.\n node = { ...node, ...parseAttributeTokens(tokens, stringLiteralPlaceholders) };\n\n // This is a decorator node, so we expect an opening '{'.\n popAndCheck(tokens, \"{\");\n\n // Return the retry node definition.\n return node;\n}\n\n/**\n * Creates a sequence node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The sequence node JSON definition.\n */\nfunction createSequenceNode(\n tokens: string[],\n stringLiteralPlaceholders: StringLiteralPlaceholders\n): SequenceNodeDefinition {\n const node = {\n type: \"sequence\",\n ...parseAttributeTokens(tokens, stringLiteralPlaceholders)\n } as SequenceNodeDefinition;\n\n // This is a composite node, so we expect an opening '{'.\n popAndCheck(tokens, \"{\");\n\n // Return the sequence node definition.\n return node;\n}\n\n/**\n * Creates a selector node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The selector node JSON definition.\n */\nfunction createSelectorNode(\n tokens: string[],\n stringLiteralPlaceholders: StringLiteralPlaceholders\n): SelectorNodeDefinition {\n const node = {\n type: \"selector\",\n ...parseAttributeTokens(tokens, stringLiteralPlaceholders)\n } as SelectorNodeDefinition;\n\n // This is a composite node, so we expect an opening '{'.\n popAndCheck(tokens, \"{\");\n\n // Return the selector node definition.\n return node;\n}\n\n/**\n * Creates a parallel node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The parallel node JSON definition.\n */\nfunction createParallelNode(\n tokens: string[],\n stringLiteralPlaceholders: StringLiteralPlaceholders\n): ParallelNodeDefinition {\n const node = {\n type: \"parallel\",\n ...parseAttributeTokens(tokens, stringLiteralPlaceholders)\n } as ParallelNodeDefinition;\n\n // This is a composite node, so we expect an opening '{'.\n popAndCheck(tokens, \"{\");\n\n // Return the parallel node definition.\n return node;\n}\n\n/**\n * Creates a lotto node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The lotto node JSON definition.\n */\nfunction createLottoNode(tokens: string[], stringLiteralPlaceholders: StringLiteralPlaceholders): LottoNodeDefinition {\n // If any node arguments have been defined then they must be our weights.\n const nodeArguments = parseArgumentTokens(tokens, stringLiteralPlaceholders);\n\n // All lotto node arguments MUST be of type number and must be positive integers.\n nodeArguments\n .filter((arg) => arg.type !== \"number\" || !arg.isInteger || arg.value < 0)\n .forEach(() => {\n throw new Error(`lotto node weight arguments must be positive integer values`);\n });\n\n const node = {\n type: \"lotto\",\n weights: nodeArguments.length ? nodeArguments.map(({ value }) => value) : undefined,\n ...parseAttributeTokens(tokens, stringLiteralPlaceholders)\n } as LottoNodeDefinition;\n\n // This is a composite node, so we expect an opening '{'.\n popAndCheck(tokens, \"{\");\n\n // Return the lotto node definition.\n return node;\n}\n\n/**\n * Creates an action node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The action node JSON definition.\n */\nfunction createActionNode(\n tokens: string[],\n stringLiteralPlaceholders: StringLiteralPlaceholders\n): ActionNodeDefinition {\n // Parse any node arguments, we should have at least one which will be an identifier argument for the action name\n // and agent function to invoke for the action, all other arguments are to be passed as arguments to that function.\n const [actionNameIdentifier, ...agentFunctionArgs] = parseArgumentTokens(tokens, stringLiteralPlaceholders);\n\n // Our first argument MUST be defined and be an identifier as we require an action name argument.\n if (actionNameIdentifier?.type !== \"identifier\") {\n throw new Error(\"expected action name identifier argument\");\n }\n\n // Only the first argument should have been an identifier, all agent function arguments must be string, number, boolean or null.\n agentFunctionArgs\n .filter((arg) => arg.type === \"identifier\")\n .forEach((arg) => {\n throw new Error(\n `invalid action node argument value '${arg.value}', must be string, number, boolean or null`\n );\n });\n\n // Return the action node definition.\n return {\n type: \"action\",\n call: actionNameIdentifier.value,\n args: agentFunctionArgs.map(({ value }) => value),\n ...parseAttributeTokens(tokens, stringLiteralPlaceholders)\n };\n}\n\n/**\n * Creates a condition node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The condition node JSON definition.\n */\nfunction createConditionNode(\n tokens: string[],\n stringLiteralPlaceholders: StringLiteralPlaceholders\n): ConditionNodeDefinition {\n // Parse any node arguments, we should have at least one which will be an identifier argument for the condition name\n // and agent function to invoke for the condition, all other arguments are to be passed as arguments to that function.\n const [conditionNameIdentifier, ...agentFunctionArgs] = parseArgumentTokens(tokens, stringLiteralPlaceholders);\n\n // Our first argument MUST be defined and be an identifier as we require a condition name argument.\n if (conditionNameIdentifier?.type !== \"identifier\") {\n throw new Error(\"expected condition name identifier argument\");\n }\n\n // Only the first argument should have been an identifier, all agent function arguments must be string, number, boolean or null.\n agentFunctionArgs\n .filter((arg) => arg.type === \"identifier\")\n .forEach((arg) => {\n throw new Error(\n `invalid condition node argument value '${arg.value}', must be string, number, boolean or null`\n );\n });\n\n // Return the condition node definition.\n return {\n type: \"condition\",\n call: conditionNameIdentifier.value,\n args: agentFunctionArgs.map(({ value }) => value),\n ...parseAttributeTokens(tokens, stringLiteralPlaceholders)\n };\n}\n\n/**\n * Creates a wait node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The wait node JSON definition.\n */\nfunction createWaitNode(tokens: string[], stringLiteralPlaceholders: StringLiteralPlaceholders): WaitNodeDefinition {\n let node = { type: \"wait\" } as WaitNodeDefinition;\n\n // Get the node arguments.\n const nodeArguments = parseArgumentTokens(tokens, stringLiteralPlaceholders);\n\n // The arguments of a wait node are optional. We may have:\n // - No node arguments, in which case the wait will be indefinite until it is aborted.\n // - One node argument which will be the explicit duration of the wait.\n // - Two node arguments which define the min and max duration bounds from which a random duration will be picked.\n if (nodeArguments.length) {\n // All wait node arguments MUST be of type number and must be integer.\n nodeArguments\n .filter((arg) => arg.type !== \"number\" || !arg.isInteger)\n .forEach(() => {\n throw new Error(`wait node durations must be integer values`);\n });\n\n // We may have:\n // - One node argument which will be the explicit duration of the wait.\n // - Two node arguments which define the min and max duration bounds from which a random duration will be picked.\n // - Too many arguments, which is not valid.\n if (nodeArguments.length === 1) {\n // An explicit duration was defined.\n node.duration = nodeArguments[0].value as number;\n\n // If an explict duration was defined then it must be a positive number.\n if (node.duration < 0) {\n throw new Error(\"a wait node must have a positive duration\");\n }\n } else if (nodeArguments.length === 2) {\n // Min and max duration bounds were defined from which a random duration will be picked.\n node.duration = [nodeArguments[0].value as number, nodeArguments[1].value as number];\n\n // A wait node must have a positive min and max duration.\n if (node.duration[0] < 0 || node.duration[1] < 0) {\n throw new Error(\"a wait node must have a positive minimum and maximum duration\");\n }\n\n // A wait node must not have a minimum duration that exceeds the maximum duration.\n if (node.duration[0] > node.duration[1]) {\n throw new Error(\"a wait node must not have a minimum duration that exceeds the maximum duration\");\n }\n } else if (nodeArguments.length > 2) {\n // An incorrect number of duration arguments were defined.\n throw new Error(\"invalid number of wait node duration arguments defined\");\n }\n }\n\n // Return the wait node definition.\n return { ...node, ...parseAttributeTokens(tokens, stringLiteralPlaceholders) };\n}\n\n/**\n * Creates a branch node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The branch node JSON definition.\n */\nfunction createBranchNode(\n tokens: string[],\n stringLiteralPlaceholders: StringLiteralPlaceholders\n): BranchNodeDefinition {\n // Parse any node arguments, we should have one which will be an identifier argument for the root ref.\n const nodeArguments = parseArgumentTokens(tokens, stringLiteralPlaceholders);\n\n // We should have only a single identifer argument for a branch node, which is the root ref.\n if (nodeArguments.length !== 1 || nodeArguments[0].type !== \"identifier\") {\n throw new Error(\"expected single branch name argument\");\n }\n\n // Return the branch node definition.\n return { type: \"branch\", ref: nodeArguments[0].value };\n}\n\n/**\n * Validate a fully-populated node definition that was popped off of the tree stack.\n * @param definition The popped node to validate.\n */\nfunction validatePoppedNode(definition: AnyNodeDefinition): void {\n // Decorators MUST have a child defined.\n if (isDecoratorNode(definition) && isNullOrUndefined(definition.child)) {\n throw new Error(`a ${definition.type} node must have a single child node defined`);\n }\n\n // Composites MUST have at least one child defined.\n if (isCompositeNode(definition) && !definition.children?.length) {\n throw new Error(`a ${definition.type} node must have at least a single child node defined`);\n }\n\n // We need to make sure that lotto nodes that have weights defined have a number of weights matching the number of child nodes.\n if (definition.type === \"lotto\") {\n // Check whether a 'weights' property has been defined, if it has we expect it to be an array of weights.\n if (typeof definition.weights !== \"undefined\") {\n // Check that the weights property is an array of positive integers with an element for each child node element.\n if (definition.weights.length !== definition.children.length) {\n throw new Error(\n \"expected a number of weight arguments matching the number of child nodes for lotto node\"\n );\n }\n }\n }\n}\n", "import { RootNodeDefinition } from \"./BehaviourTreeDefinition\";\nimport { flattenDefinition, isBranchNode, isInteger } from \"./BehaviourTreeDefinitionUtilities\";\nimport { convertMDSLToJSON } from \"./mdsl/MDSLDefinitionParser\";\n\n/**\n * An object representing the result of validating a tree definition.\n */\nexport type DefinitionValidationResult = {\n /**\n * A flag defining whether validation succeeded.\n */\n succeeded: boolean;\n /**\n * A string containing the error message if validation did not succeed.\n */\n errorMessage?: string;\n};\n\n/**\n * Validates the specified behaviour tree definition in the form of JSON or MDSL, not taking any globally registered subtrees into consideration.\n * @param definition The behaviour tree definition in the form of JSON or MDSL.\n * @returns An object representing the result of validating the given tree definition.\n */\nexport function validateDefinition(definition: any): DefinitionValidationResult {\n // The definition must be defined.\n if (definition === null || typeof definition === \"undefined\") {\n return createValidationFailureResult(\"definition is null or undefined\");\n }\n\n // We are expecting a definition in one of three different forms:\n // - A string which we will assume is MDSL and we will parse this to JSON before validation.\n // - An array which we will assume is an array of root node definitions with at least one being the primary root node (no 'id' property)\n // - An object which we will assume is the primary root node and should not have an 'id' property.\n if (typeof definition === \"string\") {\n // The definition is a string which we can assume is MDSL, so attempt to validate it.\n return validateMDSLDefinition(definition);\n } else if (typeof definition === \"object\") {\n // The definition will either be an array (of root node definitions) or an object (the single primary root node definition).\n return validateJSONDefinition(definition);\n } else {\n return createValidationFailureResult(`unexpected definition type of '${typeof definition}'`);\n }\n}\n\n/**\n * Validates the specified behaviour tree definition in the form of MDSL.\n * @param definition The behaviour tree definition in the form of MDSL.\n * @returns An object representing the result of validating the given tree definition.\n */\nexport function validateMDSLDefinition(definition: string): DefinitionValidationResult {\n let rootNodeDefinitions;\n\n // The first thing the we need to do is to attempt to convert our MDSL into JSON.\n try {\n // The definition is a string which we can assume is MDSL, so attempt to parse it to a JSON definition in the form of an array of root node definitions.\n rootNodeDefinitions = convertMDSLToJSON(definition);\n } catch (exception) {\n // We failed to parse the JSON from the MDSL, this is likely to be the result of it not being a valid MDSL string.\n return createValidationFailureResult((exception as Error).message);\n }\n\n // Unpack all of the root node definitions into arrays of main ('id' defined) and sub ('id' not defined) root node definitions.\n const mainRootNodeDefinitions = rootNodeDefinitions.filter(({ id }) => typeof id === \"undefined\");\n const subRootNodeDefinitions = rootNodeDefinitions.filter(({ id }) => typeof id === \"string\" && id.length > 0);\n\n // We should ALWAYS have exactly one root node definition without an 'id' property defined, which is out main root node definition.\n if (mainRootNodeDefinitions.length !== 1) {\n return createValidationFailureResult(\n \"expected single unnamed root node at base of definition to act as main root\"\n );\n }\n\n // We should never have duplicate 'id' properties across our sub root node definitions.\n const subRootNodeIdenitifers: string[] = [];\n for (const { id } of subRootNodeDefinitions) {\n // Have we already come across this 'id' property value?\n if (subRootNodeIdenitifers.includes(id!)) {\n return createValidationFailureResult(`multiple root nodes found with duplicate name '${id}'`);\n }\n\n subRootNodeIdenitifers.push(id!);\n }\n\n try {\n // Validate our branch -> subtree links and check for any circular dependencies, we don't care about checking for broken subtree links here.\n validateBranchSubtreeLinks(rootNodeDefinitions, false);\n } catch (exception) {\n return createValidationFailureResult((exception as Error).message);\n }\n\n // Our definition was valid!\n return { succeeded: true };\n}\n\n/**\n * Validates the specified behaviour tree definition in the form of JSON.\n * @param definition The behaviour tree definition in the form of JSON.\n * @returns An object representing the result of validating the given tree definition.\n */\nexport function validateJSONDefinition(\n definition: RootNodeDefinition | RootNodeDefinition[]\n): DefinitionValidationResult {\n // The definition will either be an array (of root node definitions) or an object (the single primary root node definition).\n const rootNodeDefinitions = Array.isArray(definition) ? definition : [definition];\n\n // Iterate over our array of root nodes and call validateNode for each, passing an initial depth of 0, wrapped in a try catch to handle validation failures.\n try {\n rootNodeDefinitions.forEach((rootNodeDefinition) => validateNode(rootNodeDefinition, 0));\n } catch (error) {\n // Handle cases where we have caught a thrown Error and return a failure result with the error message.\n if (error instanceof Error) {\n return createValidationFailureResult(error.message);\n }\n\n // No idea what happened here!\n return createValidationFailureResult(`unexpected error: ${error}`);\n }\n\n // Unpack all of the root node definitions into arrays of main ('id' defined) and sub ('id' not defined) root node definitions.\n const mainRootNodeDefinitions = rootNodeDefinitions.filter(({ id }) => typeof id === \"undefined\");\n const subRootNodeDefinitions = rootNodeDefinitions.filter(({ id }) => typeof id === \"string\" && id.length > 0);\n\n // We should ALWAYS have exactly one root node definition without an 'id' property defined, which is out main root node definition.\n if (mainRootNodeDefinitions.length !== 1) {\n return createValidationFailureResult(\n \"expected single root node without 'id' property defined to act as main root\"\n );\n }\n\n // We should never have duplicate 'id' properties across our sub root node definitions.\n const subRootNodeIdenitifers: string[] = [];\n for (const { id } of subRootNodeDefinitions) {\n // Have we already come across this 'id' property value?\n if (subRootNodeIdenitifers.includes(id!)) {\n return createValidationFailureResult(\n `multiple root nodes found with duplicate 'id' property value of '${id}'`\n );\n }\n\n subRootNodeIdenitifers.push(id!);\n }\n\n try {\n // Validate our branch -> subtree links and check for any circular dependencies, we don't care about checking for broken subtree links here.\n validateBranchSubtreeLinks(rootNodeDefinitions, false);\n } catch (exception) {\n return createValidationFailureResult((exception as Error).message);\n }\n\n // Our definition was valid!\n return { succeeded: true };\n}\n\n/**\n * Validates the branch -> subtree links across all provided root node definitions.\n * This will not consider branch nodes that reference any globally registered subtrees unless includesGlobalSubtrees\n * is set to true, in which case we will also verify that there are no broken branch -> subtree links.\n * @param rootNodeDefinitions The array of root node definitions.\n * @param includesGlobalSubtrees A flag defining whether the array includes all global subtree root node definitions.\n */\nexport function validateBranchSubtreeLinks(rootNodeDefinitions: RootNodeDefinition[], includesGlobalSubtrees: boolean) {\n // Create a mapping of root node identifiers to other root nodes that they reference via branch nodes.\n // Below is an example of a mapping that includes a circular dependency (root => a => b => c => a)\n // [{ refs: [\"a\", \"b\"] }, { id: \"a\", refs: [\"b\"] }, { id: \"b\", refs: [\"c\"] }, { id: \"c\", refs: [\"a\"] }]\n const rootNodeMappings: { id: string | undefined; refs: string[] }[] = rootNodeDefinitions.map(\n (rootNodeDefinition) => ({\n id: rootNodeDefinition.id,\n refs: flattenDefinition(rootNodeDefinition)\n .filter(isBranchNode)\n .map(({ ref }) => ref)\n })\n );\n\n // A recursive function to walk through the mappings, keeping track of which root nodes we have visited in the form of a path of root node identifiers.\n const followRefs = (mapping: { id: string | undefined; refs: string[] }, path: (string | undefined)[] = []) => {\n // Have we found a circular dependency?\n if (path.includes(mapping.id)) {\n // We found a circular dependency! Get the bad path of root node identifiers.\n const badPath = [...path, mapping.id];\n\n // Create the formatted path value. [undefined, \"a\", \"b\", \"c\", \"a\"] would be formatted as \"a -> b -> c -> a\".\n const badPathFormatted = badPath.filter((element) => !!element).join(\" => \");\n\n // No need to continue, we found a circular dependency.\n throw new Error(`circular dependency found in branch node references: ${badPathFormatted}`);\n }\n\n for (const ref of mapping.refs) {\n // Find the mapping for the root node with an identifer matching the current ref.\n const subMapping = rootNodeMappings.find(({ id }) => id === ref);\n\n // We may not have a mapping for this ref, which is normal when we aren't considering all globally registered subtrees.\n if (subMapping) {\n followRefs(subMapping, [...path, mapping.id]);\n } else if (includesGlobalSubtrees) {\n // We found a reference to a root node that doesn't exist, which is a problem seeing as the root node definitons includes all globally registered subtrees.\n throw new Error(\n mapping.id\n ? `subtree '${mapping.id}' has branch node that references root node '${ref}' which has not been defined`\n : `primary tree has branch node that references root node '${ref}' which has not been defined`\n );\n }\n }\n };\n\n // Start looking for circular dependencies and broken references from the primary root node definition.\n followRefs(rootNodeMappings.find((mapping) => typeof mapping.id === \"undefined\")!);\n}\n\n/**\n * Validate an object that we expect to be a node definition.\n * @param definition An object that we expect to be a node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateNode(definition: any, depth: number): void {\n // Every node must be valid object and have a non-empty 'type' string property.\n if (typeof definition !== \"object\" || typeof definition.type !== \"string\" || definition.type.length === 0) {\n throw new Error(\n `node definition is not an object or 'type' property is not a non-empty string at depth '${depth}'`\n );\n }\n\n // How we validate this node definition will depend on its type.\n switch (definition.type) {\n case \"action\":\n validateActionNode(definition, depth);\n break;\n\n case \"condition\":\n validateConditionNode(definition, depth);\n break;\n\n case \"wait\":\n validateWaitNode(definition, depth);\n break;\n\n case \"branch\":\n validateBranchNode(definition, depth);\n break;\n\n case \"root\":\n validateRootNode(definition, depth);\n break;\n\n case \"succeed\":\n validateSucceedNode(definition, depth);\n break;\n\n case \"fail\":\n validateFailNode(definition, depth);\n break;\n\n case \"flip\":\n validateFlipNode(definition, depth);\n break;\n\n case \"repeat\":\n validateRepeatNode(definition, depth);\n break;\n\n case \"retry\":\n validateRetryNode(definition, depth);\n break;\n\n case \"sequence\":\n validateSequenceNode(definition, depth);\n break;\n\n case \"selector\":\n validateSelectorNode(definition, depth);\n break;\n\n case \"parallel\":\n validateParallelNode(definition, depth);\n break;\n\n case \"lotto\":\n validateLottoNode(definition, depth);\n break;\n\n default:\n throw new Error(`unexpected node type of '${definition.type}' at depth '${depth}'`);\n }\n}\n\n/**\n * Validate any attributes for a given node definition.\n * @param definition The node definition.\n * @param depth The depth of the node in the behaviour tree definition.\n */\nfunction validateNodeAttributes(definition: any, depth: number): void {\n // Validate each of the attribute types for this node.\n [\"while\", \"until\", \"entry\", \"exit\", \"step\"].forEach((attributeName) => {\n // Attempt to grab the definition for the current attribute from the node definition.\n const attributeDefinition = definition[attributeName];\n\n // All node attributes are optional, so there is nothing to do if the current attribute is not defined.\n if (typeof attributeDefinition === \"undefined\") {\n return;\n }\n\n // The attribute definition must be an object.\n if (typeof attributeDefinition !== \"object\") {\n throw new Error(\n `expected attribute '${attributeName}' to be an object for '${definition.type}' node at depth '${depth}'`\n );\n }\n\n // The 'call' property must be defined for any attribute definition.\n if (typeof attributeDefinition.call !== \"string\" || attributeDefinition.call.length === 0) {\n throw new Error(\n `expected 'call' property for attribute '${attributeName}' to be a non-empty string for '${definition.type}' node at depth '${depth}'`\n );\n }\n\n // If any node attribute arguments have been defined then they must have been defined in an array.\n if (typeof attributeDefinition.args !== \"undefined\" && !Array.isArray(attributeDefinition.args)) {\n throw new Error(\n `expected 'args' property for attribute '${attributeName}' to be an array for '${definition.type}' node at depth '${depth}'`\n );\n }\n });\n}\n\n/**\n * Validate an object that we expect to be a root node definition.\n * @param definition An object that we expect to be a root node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateRootNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"root\") {\n throw new Error(\"expected node type of 'root' for root node\");\n }\n\n // A root node cannot be the child of another node.\n if (depth > 0) {\n throw new Error(\"a root node cannot be the child of another node\");\n }\n\n // Check that, if the root node 'id' property is defined, it is a non-empty string.\n if (typeof definition.id !== \"undefined\" && (typeof definition.id !== \"string\" || definition.id.length === 0)) {\n throw new Error(\"expected non-empty string for 'id' property if defined for root node\");\n }\n\n // A root node is a decorator node, so must have a child node defined.\n if (typeof definition.child === \"undefined\") {\n throw new Error(\"expected property 'child' to be defined for root node\");\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n\n // Validate the child node of this decorator node.\n validateNode(definition.child, depth + 1);\n}\n\n/**\n * Validate an object that we expect to be a succeed node definition.\n * @param definition An object that we expect to be a succeed node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateSucceedNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"succeed\") {\n throw new Error(`expected node type of 'succeed' for succeed node at depth '${depth}'`);\n }\n\n // A succeed node is a decorator node, so must have a child node defined.\n if (typeof definition.child === \"undefined\") {\n throw new Error(`expected property 'child' to be defined for succeed node at depth '${depth}'`);\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n\n // Validate the child node of this decorator node.\n validateNode(definition.child, depth + 1);\n}\n\n/**\n * Validate an object that we expect to be a fail node definition.\n * @param definition An object that we expect to be a fail node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateFailNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"fail\") {\n throw new Error(`expected node type of 'fail' for fail node at depth '${depth}'`);\n }\n\n // A fail node is a decorator node, so must have a child node defined.\n if (typeof definition.child === \"undefined\") {\n throw new Error(`expected property 'child' to be defined for fail node at depth '${depth}'`);\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n\n // Validate the child node of this decorator node.\n validateNode(definition.child, depth + 1);\n}\n\n/**\n * Validate an object that we expect to be a flip node definition.\n * @param definition An object that we expect to be a flip node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateFlipNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"flip\") {\n throw new Error(`expected node type of 'flip' for flip node at depth '${depth}'`);\n }\n\n // A flip node is a decorator node, so must have a child node defined.\n if (typeof definition.child === \"undefined\") {\n throw new Error(`expected property 'child' to be defined for flip node at depth '${depth}'`);\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n\n // Validate the child node of this decorator node.\n validateNode(definition.child, depth + 1);\n}\n\n/**\n * Validate an object that we expect to be a repeat node definition.\n * @param definition An object that we expect to be a repeat node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateRepeatNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"repeat\") {\n throw new Error(`expected node type of 'repeat' for repeat node at depth '${depth}'`);\n }\n\n // A repeat node is a decorator node, so must have a child node defined.\n if (typeof definition.child === \"undefined\") {\n throw new Error(`expected property 'child' to be defined for repeat node at depth '${depth}'`);\n }\n\n // Check whether an 'iterations' property has been defined, it may not have been if this node is to repeat indefinitely.\n if (typeof definition.iterations !== \"undefined\") {\n if (Array.isArray(definition.iterations)) {\n // Check whether any elements of the array are not integer values.\n const containsNonInteger = !!definition.iterations.filter((value: unknown) => !isInteger(value)).length;\n\n // If the 'iterations' property is an array then it MUST contain two integer values.\n if (definition.iterations.length !== 2 || containsNonInteger) {\n throw new Error(\n `expected array containing two integer values for 'iterations' property if defined for repeat node at depth '${depth}'`\n );\n }\n\n // A repeat node must have a positive min and max iterations count if they are defined.\n if (definition.iterations[0] < 0 || definition.iterations[1] < 0) {\n throw new Error(\n `expected positive minimum and maximum iterations count for 'iterations' property if defined for repeat node at depth '${depth}'`\n );\n }\n\n // A repeat node must not have a minimum iterations count that exceeds the maximum iterations count.\n if (definition.iterations[0] > definition.iterations[1]) {\n throw new Error(\n `expected minimum iterations count that does not exceed the maximum iterations count for 'iterations' property if defined for repeat node at depth '${depth}'`\n );\n }\n } else if (isInteger(definition.iterations)) {\n // A repeat node must have a positive number of iterations if defined.\n if (definition.iterations < 0) {\n throw new Error(\n `expected positive iterations count for 'iterations' property if defined for repeat node at depth '${depth}'`\n );\n }\n } else {\n throw new Error(\n `expected integer value or array containing two integer values for 'iterations' property if defined for repeat node at depth '${depth}'`\n );\n }\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n\n // Validate the child node of this decorator node.\n validateNode(definition.child, depth + 1);\n}\n\n/**\n * Validate an object that we expect to be a retry node definition.\n * @param definition An object that we expect to be a retry node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateRetryNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"retry\") {\n throw new Error(`expected node type of 'retry' for retry node at depth '${depth}'`);\n }\n\n // A retry node is a decorator node, so must have a child node defined.\n if (typeof definition.child === \"undefined\") {\n throw new Error(`expected property 'child' to be defined for retry node at depth '${depth}'`);\n }\n\n // Check whether an 'attempts' property has been defined, it may not have been if this node is to retry indefinitely.\n if (typeof definition.attempts !== \"undefined\") {\n if (Array.isArray(definition.attempts)) {\n // Check whether any elements of the array are not integer values.\n const containsNonInteger = !!definition.attempts.filter((value: unknown) => !isInteger(value)).length;\n\n // If the 'attempts' property is an array then it MUST contain two integer values.\n if (definition.attempts.length !== 2 || containsNonInteger) {\n throw new Error(\n `expected array containing two integer values for 'attempts' property if defined for retry node at depth '${depth}'`\n );\n }\n\n // A retry node must have a positive min and max attempts count if they are defined.\n if (definition.attempts[0] < 0 || definition.attempts[1] < 0) {\n throw new Error(\n `expected positive minimum and maximum attempts count for 'attempts' property if defined for retry node at depth '${depth}'`\n );\n }\n\n // A retry node must not have a minimum attempts count that exceeds the maximum attempts count.\n if (definition.attempts[0] > definition.attempts[1]) {\n throw new Error(\n `expected minimum attempts count that does not exceed the maximum attempts count for 'attempts' property if defined for retry node at depth '${depth}'`\n );\n }\n } else if (isInteger(definition.attempts)) {\n // A retry node must have a positive number of attempts if defined.\n if (definition.attempts < 0) {\n throw new Error(\n `expected positive attempts count for 'attempts' property if defined for retry node at depth '${depth}'`\n );\n }\n } else {\n throw new Error(\n `expected integer value or array containing two integer values for 'attempts' property if defined for retry node at depth '${depth}'`\n );\n }\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n\n // Validate the child node of this decorator node.\n validateNode(definition.child, depth + 1);\n}\n\n/**\n * Validate an object that we expect to be a branch node definition.\n * @param definition An object that we expect to be a branch node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateBranchNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"branch\") {\n throw new Error(`expected node type of 'branch' for branch node at depth '${depth}'`);\n }\n\n // Check that the branch node 'ref' property is defined and is a non-empty string.\n if (typeof definition.ref !== \"string\" || definition.ref.length === 0) {\n throw new Error(`expected non-empty string for 'ref' property for branch node at depth '${depth}'`);\n }\n\n // It is invalid to define guard attributes for a branch node as they should be defined on the referenced root node.\n [\"while\", \"until\"].forEach((attributeName) => {\n if (typeof definition[attributeName] !== \"undefined\") {\n throw new Error(\n `guards should not be defined for branch nodes but guard '${attributeName}' was defined for branch node at depth '${depth}'`\n );\n }\n });\n\n // It is invalid to define callback attributes for a branch node as they should be defined on the referenced root node.\n [\"entry\", \"exit\", \"step\"].forEach((attributeName) => {\n if (typeof definition[attributeName] !== \"undefined\") {\n throw new Error(\n `callbacks should not be defined for branch nodes but callback '${attributeName}' was defined for branch node at depth '${depth}'`\n );\n }\n });\n}\n\n/**\n * Validate an object that we expect to be a action node definition.\n * @param definition An object that we expect to be a action node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateActionNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"action\") {\n throw new Error(`expected node type of 'action' for action node at depth '${depth}'`);\n }\n\n // The 'call' property must be defined for a action node definition.\n if (typeof definition.call !== \"string\" || definition.call.length === 0) {\n throw new Error(`expected non-empty string for 'call' property of action node at depth '${depth}'`);\n }\n\n // If any action function arguments have been defined then they must have been defined in an array.\n if (typeof definition.args !== \"undefined\" && !Array.isArray(definition.args)) {\n throw new Error(`expected array for 'args' property if defined for action node at depth '${depth}'`);\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n}\n\n/**\n * Validate an object that we expect to be a condition node definition.\n * @param definition An object that we expect to be a condition node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateConditionNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"condition\") {\n throw new Error(`expected node type of 'condition' for condition node at depth '${depth}'`);\n }\n\n // The 'call' property must be defined for a condition node definition.\n if (typeof definition.call !== \"string\" || definition.call.length === 0) {\n throw new Error(`expected non-empty string for 'call' property of condition node at depth '${depth}'`);\n }\n\n // If any condition function arguments have been defined then they must have been defined in an array.\n if (typeof definition.args !== \"undefined\" && !Array.isArray(definition.args)) {\n throw new Error(`expected array for 'args' property if defined for condition node at depth '${depth}'`);\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n}\n\n/**\n * Validate an object that we expect to be a wait node definition.\n * @param definition An object that we expect to be a wait node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateWaitNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"wait\") {\n throw new Error(`expected node type of 'wait' for wait node at depth '${depth}'`);\n }\n\n // Check whether a 'duration' property has been defined, it may not have been if this node is to wait indefinitely.\n if (typeof definition.duration !== \"undefined\") {\n if (Array.isArray(definition.duration)) {\n // Check whether any elements of the array are not integer values.\n const containsNonInteger = !!definition.duration.filter((value: unknown) => !isInteger(value)).length;\n\n // If the 'duration' property is an array then it MUST contain two integer values.\n if (definition.duration.length !== 2 || containsNonInteger) {\n throw new Error(\n `expected array containing two integer values for 'duration' property if defined for wait node at depth '${depth}'`\n );\n }\n\n // A wait node must have a positive min and max duration value if they are defined.\n if (definition.duration[0] < 0 || definition.duration[1] < 0) {\n throw new Error(\n `expected positive minimum and maximum duration for 'duration' property if defined for wait node at depth '${depth}'`\n );\n }\n\n // A wait node must not have a minimum duration value that exceeds the maximum duration value.\n if (definition.duration[0] > definition.duration[1]) {\n throw new Error(\n `expected minimum duration value that does not exceed the maximum duration value for 'duration' property if defined for wait node at depth '${depth}'`\n );\n }\n } else if (isInteger(definition.duration)) {\n // A wait node must have a positive duration value if defined.\n if (definition.duration < 0) {\n throw new Error(\n `expected positive duration value for 'duration' property if defined for wait node at depth '${depth}'`\n );\n }\n } else {\n throw new Error(\n `expected integer value or array containing two integer values for 'duration' property if defined for wait node at depth '${depth}'`\n );\n }\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n}\n\n/**\n * Validate an object that we expect to be a sequence node definition.\n * @param definition An object that we expect to be a sequence node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateSequenceNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"sequence\") {\n throw new Error(`expected node type of 'sequence' for sequence node at depth '${depth}'`);\n }\n\n // A sequence node is a composite node, so must have a children nodes array defined.\n if (!Array.isArray(definition.children) || definition.children.length === 0) {\n throw new Error(`expected non-empty 'children' array to be defined for sequence node at depth '${depth}'`);\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n\n // Validate the child nodes of this composite node.\n definition.children.forEach((child: any) => validateNode(child, depth + 1));\n}\n\n/**\n * Validate an object that we expect to be a selector node definition.\n * @param definition An object that we expect to be a selector node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateSelectorNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"selector\") {\n throw new Error(`expected node type of 'selector' for selector node at depth '${depth}'`);\n }\n\n // A selector node is a composite node, so must have a children nodes array defined.\n if (!Array.isArray(definition.children) || definition.children.length === 0) {\n throw new Error(`expected non-empty 'children' array to be defined for selector node at depth '${depth}'`);\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n\n // Validate the child nodes of this composite node.\n definition.children.forEach((child: any) => validateNode(child, depth + 1));\n}\n\n/**\n * Validate an object that we expect to be a parallel node definition.\n * @param definition An object that we expect to be a parallel node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateParallelNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"parallel\") {\n throw new Error(`expected node type of 'parallel' for parallel node at depth '${depth}'`);\n }\n\n // A parallel node is a composite node, so must have a children nodes array defined.\n if (!Array.isArray(definition.children) || definition.children.length === 0) {\n throw new Error(`expected non-empty 'children' array to be defined for parallel node at depth '${depth}'`);\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n\n // Validate the child nodes of this composite node.\n definition.children.forEach((child: any) => validateNode(child, depth + 1));\n}\n\n/**\n * Validate an object that we expect to be a lotto node definition.\n * @param definition An object that we expect to be a lotto node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateLottoNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"lotto\") {\n throw new Error(`expected node type of 'lotto' for lotto node at depth '${depth}'`);\n }\n\n // A lotto node is a composite node, so must have a children nodes array defined.\n if (!Array.isArray(definition.children) || definition.children.length === 0) {\n throw new Error(`expected non-empty 'children' array to be defined for lotto node at depth '${depth}'`);\n }\n\n // Check whether a 'weights' property has been defined, if it has we expect it to be an array of weights.\n if (typeof definition.weights !== \"undefined\") {\n // Check that the weights property is an array of positive integers with an element for each child node element.\n if (\n !Array.isArray(definition.weights) ||\n definition.weights.length !== definition.children.length ||\n definition.weights.filter((value: unknown) => !isInteger(value)).length ||\n definition.weights.filter((value: number) => value < 0).length\n ) {\n throw new Error(\n `expected an array of positive integer weight values with a length matching the number of child nodes for 'weights' property if defined for lotto node at depth '${depth}'`\n );\n }\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n\n // Validate the child nodes of this composite node.\n definition.children.forEach((child: any) => validateNode(child, depth + 1));\n}\n\n/**\n * A helper function to create a failure validation result with the given error message.\n * @param errorMessage The validation failure error message.\n * @returns A failure validation result with the given error message.\n */\nfunction createValidationFailureResult(errorMessage: string): DefinitionValidationResult {\n return { succeeded: false, errorMessage };\n}\n", "import { ActionResult, Agent, GlobalFunction } from \"./Agent\";\nimport { RootNodeDefinition } from \"./BehaviourTreeDefinition\";\n\nexport type InvokerFunction = (args: any[]) => ActionResult;\n\n/**\n * A singleton used to store and lookup registered functions and subtrees.\n */\nexport default class Lookup {\n /**\n * The object holding any registered functions keyed on function name.\n */\n private static functionTable: { [key: string]: GlobalFunction } = {};\n /**\n * The object holding any registered subtree root node definitions keyed on tree name.\n */\n private static subtreeTable: { [key: string]: RootNodeDefinition } = {};\n\n /**\n * Gets the function with the specified name.\n * @param name The name of the function.\n * @returns The function with the specified name.\n */\n public static getFunc(name: string): GlobalFunction {\n return this.functionTable[name];\n }\n\n /**\n * Sets the function with the specified name for later lookup.\n * @param name The name of the function.\n * @param func The function.\n */\n public static setFunc(name: string, func: GlobalFunction): void {\n this.functionTable[name] = func;\n }\n\n /**\n * Gets the function invoker for the specified agent and function name.\n * If a function with the specified name exists on the agent object then it will\n * be returned, otherwise we will then check the registered functions for a match.\n * @param agent The agent instance that this behaviour tree is modelling behaviour for.\n * @param name The function name.\n * @returns The function invoker for the specified agent and function name.\n */\n static getFuncInvoker(agent: Agent, name: string): InvokerFunction | null {\n // Check whether the agent contains the specified function.\n const foundOnAgent = agent[name];\n if (foundOnAgent && typeof foundOnAgent === \"function\") {\n return (args: any[]): boolean | ActionResult => foundOnAgent.apply(agent, args);\n }\n\n // The agent does not contain the specified function but it may have been registered at some point.\n if (this.functionTable[name] && typeof this.functionTable[name] === \"function\") {\n return (args: any[]) => this.functionTable[name](agent, ...args.map((arg) => arg.value));\n }\n\n // We have no function to invoke.\n return null;\n }\n\n /**\n * Gets all registered subtree root node definitions.\n */\n static getSubtrees(): { [key: string]: RootNodeDefinition } {\n return this.subtreeTable;\n }\n\n /**\n * Sets the subtree with the specified name for later lookup.\n * @param name The name of the subtree.\n * @param subtree The subtree.\n */\n static setSubtree(name: string, subtree: RootNodeDefinition) {\n this.subtreeTable[name] = subtree;\n }\n\n /**\n * Removes the registered function or subtree with the specified name.\n * @param name The name of the registered function or subtree.\n */\n static remove(name: string) {\n delete this.functionTable[name];\n delete this.subtreeTable[name];\n }\n\n /**\n * Remove all registered functions and subtrees.\n */\n static empty() {\n this.functionTable = {};\n this.subtreeTable = {};\n }\n}\n", "import Node from \"../../nodes/Node\";\n\n/**\n * An exception thrown when evaluating node guard path conditions and a conditions fails.\n */\nexport default class GuardUnsatisifedException extends Error {\n /**\n * @param source The node at which a guard condition failed.\n */\n constructor(private source: Node) {\n super(\"A guard path condition has failed\");\n }\n\n /**\n * Gets whether the specified node is the node at which a guard condition failed.\n * @param node The node to check against the source node.\n * @returns Whether the specified node is the node at which a guard condition failed.\n */\n isSourceNode = (node: Node) => node === this.source;\n}\n", "import { Agent } from \"../../Agent\";\nimport Guard from \"./Guard\";\nimport Node from \"../../nodes/Node\";\nimport GuardUnsatisifedException from \"./GuardUnsatisifedException\";\n\nexport type GuardPathPart = {\n node: Node;\n guards: Guard[];\n};\n\n/**\n * Represents a path of node guards along a root-to-leaf tree path.\n */\nexport default class GuardPath {\n /**\n * @param nodes An array of objects defining a node instance -> guard link, ordered by node depth.\n */\n constructor(private nodes: GuardPathPart[]) {}\n\n /**\n * Evaluate guard conditions for all guards in the tree path, moving outwards from the root.\n * @param agent The agent, required for guard evaluation.\n * @returns An evaluation results object.\n */\n evaluate = (agent: Agent) => {\n // We need to evaluate guard conditions for nodes up the tree, moving outwards from the root.\n for (const details of this.nodes) {\n // There can be multiple guards per node.\n for (const guard of details.guards) {\n // Check whether the guard condition passes, and throw an exception if not.\n if (!guard.isSatisfied(agent)) {\n throw new GuardUnsatisifedException(details.node);\n }\n }\n }\n };\n}\n", "import { BehaviourTreeOptions } from \"../BehaviourTreeOptions\";\nimport State, { AnyState } from \"../State\";\nimport { Agent } from \"../Agent\";\nimport Leaf from \"./leaf/Leaf\";\nimport Attribute from \"../attributes/Attribute\";\nimport Entry from \"../attributes/callbacks/Entry\";\nimport Exit from \"../attributes/callbacks/Exit\";\nimport Step from \"../attributes/callbacks/Step\";\nimport Guard from \"../attributes/guards/Guard\";\nimport GuardPath from \"../attributes/guards/GuardPath\";\nimport GuardUnsatisifedException from \"../attributes/guards/GuardUnsatisifedException\";\n\n/**\n * A base node.\n */\nexport default abstract class Node {\n /**\n * The node uid.\n */\n private readonly uid: string = createNodeUid();\n /**\n * The node state.\n */\n private state: AnyState = State.READY;\n /**\n * The guard path to evaluate as part of a node update.\n */\n private guardPath: GuardPath | undefined;\n\n /**\n * @param type The node type.\n * @param attributes The node attributes.\n * @param args The node argument definitions.\n */\n constructor(private type: string, private attributes: Attribute[], private args: any[]) {}\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected abstract onUpdate(agent: Agent, options: BehaviourTreeOptions): void;\n\n /**\n * Gets the name of the node.\n */\n public abstract getName(): string;\n\n /**\n * Gets whether this node is a leaf node.\n */\n public abstract isLeafNode: () => this is Leaf;\n\n /**\n * Gets/Sets the state of the node.\n */\n getState = (): AnyState => this.state;\n setState = (value: AnyState): void => {\n this.state = value;\n };\n\n /**\n * Gets the unique id of the node.\n */\n getUid = () => this.uid;\n\n /**\n * Gets the type of the node.\n */\n getType = () => this.type;\n\n /**\n * Gets the node attributes.\n */\n getAttributes = () => this.attributes;\n\n /**\n * Gets the node arguments.\n */\n getArguments = () => this.args;\n\n /**\n * Gets the node attribute with the specified type, or null if it does not exist.\n */\n getAttribute(type: \"entry\" | \"ENTRY\"): Entry;\n getAttribute(type: \"exit\" | \"EXIT\"): Exit;\n getAttribute(type: \"step\" | \"STEP\"): Step;\n getAttribute(type: string): Attribute {\n return (\n this.getAttributes().filter((decorator) => decorator.type.toUpperCase() === type.toUpperCase())[0] || null\n );\n }\n\n /**\n * Gets the node attributes.\n */\n getGuardAttributes = (): Guard[] => this.getAttributes().filter((decorator) => decorator.isGuard()) as Guard[];\n\n /**\n * Sets the guard path to evaluate as part of a node update.\n */\n setGuardPath = (value: GuardPath) => (this.guardPath = value);\n\n /**\n * Gets whether a guard path is assigned to this node.\n */\n hasGuardPath = () => !!this.guardPath;\n\n /**\n * Gets whether this node is in the specified state.\n * @param value The value to compare to the node state.\n */\n public is(value: AnyState): boolean {\n return this.state === value;\n }\n\n /**\n * Reset the state of the node.\n */\n public reset(): void {\n this.setState(State.READY);\n }\n\n /**\n * Abort the running of this node.\n * @param agent The agent.\n */\n public abort(agent: Agent): void {\n // There is nothing to do if this node is not in the running state.\n if (!this.is(State.RUNNING)) {\n return;\n }\n\n // Reset the state of this node.\n this.reset();\n\n this.getAttribute(\"exit\")?.callAgentFunction(agent, false, true);\n }\n\n /**\n * Update the node.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n * @returns The result of the update.\n */\n public update(agent: Agent, options: BehaviourTreeOptions): void {\n // If this node is already in a 'SUCCEEDED' or 'FAILED' state then there is nothing to do.\n if (this.is(State.SUCCEEDED) || this.is(State.FAILED)) {\n return;\n }\n\n try {\n // Evaluate all of the guard path conditions for the current tree path.\n this.guardPath!.evaluate(agent);\n\n // If this node is in the READY state then call the ENTRY for this node if it exists.\n if (this.is(State.READY)) {\n this.getAttribute(\"entry\")?.callAgentFunction(agent);\n }\n\n this.getAttribute(\"step\")?.callAgentFunction(agent);\n\n // Do the actual update.\n this.onUpdate(agent, options);\n\n // If this node is now in a 'SUCCEEDED' or 'FAILED' state then call the EXIT for this node if it exists.\n if (this.is(State.SUCCEEDED) || this.is(State.FAILED)) {\n this.getAttribute(\"exit\")?.callAgentFunction(agent, this.is(State.SUCCEEDED), false);\n }\n } catch (error) {\n // If the error is a GuardUnsatisfiedException then we need to determine if this node is the source.\n if (error instanceof GuardUnsatisifedException && error.isSourceNode(this)) {\n // Abort the current node.\n this.abort(agent);\n\n // Any node that is the source of an abort will be a failed node.\n this.setState(State.FAILED);\n } else {\n throw error;\n }\n }\n }\n}\n\n/**\n * Create a randomly generated node uid.\n * @returns A randomly generated node uid.\n */\nfunction createNodeUid(): string {\n var S4 = function () {\n return (((1 + Math.random()) * 0x10000) | 0).toString(16).substring(1);\n };\n return S4() + S4() + \"-\" + S4() + \"-\" + S4() + \"-\" + S4() + \"-\" + S4() + S4() + S4();\n}\n", "import Node from \"../Node\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\n\n/**\n * A composite node that wraps child nodes.\n */\nexport default abstract class Composite extends Node {\n /**\n * @param type The node type.\n * @param attributes The node attributes.\n * @param children The child nodes.\n */\n constructor(type: string, attributes: Attribute[], protected children: Node[]) {\n super(type, attributes, []);\n }\n\n /**\n * Gets whether this node is a leaf node.\n */\n isLeafNode = () => false;\n\n /**\n * Gets the children of this node.\n */\n getChildren = () => this.children;\n\n /**\n * Reset the state of the node.\n */\n reset = () => {\n // Reset the state of this node.\n this.setState(State.READY);\n\n // Reset the state of any child nodes.\n this.getChildren().forEach((child) => child.reset());\n };\n\n /**\n * Abort the running of this node.\n * @param agent The agent.\n */\n abort = (agent: Agent) => {\n // There is nothing to do if this node is not in the running state.\n if (!this.is(State.RUNNING)) {\n return;\n }\n\n // Abort any child nodes.\n this.getChildren().forEach((child) => child.abort(agent));\n\n // Reset the state of this node.\n this.reset();\n\n this.getAttribute(\"exit\")?.callAgentFunction(agent, false, true);\n };\n}\n", "import Composite from \"./Composite\";\nimport State from \"../../State\";\nimport Node from \"../Node\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A PARALLEL node.\n * The child nodes are executed concurrently until one fails or all succeed.\n */\nexport default class Parallel extends Composite {\n /**\n * @param attributes The node attributes.\n * @param children The child nodes.\n */\n constructor(attributes: Attribute[], children: Node[]) {\n super(\"parallel\", attributes, children);\n }\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // Keep a count of the number of succeeded child nodes.\n let succeededCount = 0;\n\n let hasChildFailed = false;\n\n // Iterate over all of the children of this node.\n for (const child of this.children) {\n // If the child has never been updated or is running then we will need to update it now.\n if (child.getState() === State.READY || child.getState() === State.RUNNING) {\n // Update the child of this node.\n child.update(agent, options);\n }\n\n // If the current child has a state of 'SUCCEEDED' then we should move on to the next child.\n if (child.getState() === State.SUCCEEDED) {\n // The child node has succeeded, keep track of this to determine if all children have.\n succeededCount++;\n\n // The child node succeeded, but we have not finished checking every child node yet.\n continue;\n }\n\n // If the current child has a state of 'FAILED' then this node is also a 'FAILED' node.\n if (child.getState() === State.FAILED) {\n hasChildFailed = true;\n\n // There is no need to check the rest of the children.\n break;\n }\n\n // The node should be in the 'RUNNING' state.\n if (child.getState() !== State.RUNNING) {\n // The child node was not in an expected state.\n throw new Error(\"child node was not in an expected state.\");\n }\n }\n\n if (hasChildFailed) {\n // This node is a 'FAILED' node.\n this.setState(State.FAILED);\n\n // Abort every running child.\n for (const child of this.children) {\n if (child.getState() === State.RUNNING) {\n child.abort(agent);\n }\n }\n } else {\n // If all children have succeeded then this node has also succeeded, otherwise it is still running.\n this.setState(succeededCount === this.children.length ? State.SUCCEEDED : State.RUNNING);\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => \"PARALLEL\";\n}\n", "import Composite from \"./Composite\";\nimport Node from \"../Node\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A SELECTOR node.\n * The child nodes are executed in sequence until one succeeds or all fail.\n */\nexport default class Selector extends Composite {\n /**\n * @param attributes The node attributes.\n * @param children The child nodes.\n */\n constructor(attributes: Attribute[], protected children: Node[]) {\n super(\"selector\", attributes, children);\n }\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // Iterate over all of the children of this node.\n for (const child of this.children) {\n // If the child has never been updated or is running then we will need to update it now.\n if (child.getState() === State.READY || child.getState() === State.RUNNING) {\n // Update the child of this node.\n child.update(agent, options);\n }\n\n // If the current child has a state of 'SUCCEEDED' then this node is also a 'SUCCEEDED' node.\n if (child.getState() === State.SUCCEEDED) {\n // This node is a 'SUCCEEDED' node.\n this.setState(State.SUCCEEDED);\n\n // There is no need to check the rest of the selector nodes.\n return;\n }\n\n // If the current child has a state of 'FAILED' then we should move on to the next child.\n if (child.getState() === State.FAILED) {\n // Find out if the current child is the last one in the selector.\n // If it is then this sequence node has also failed.\n if (this.children.indexOf(child) === this.children.length - 1) {\n // This node is a 'FAILED' node.\n this.setState(State.FAILED);\n\n // There is no need to check the rest of the selector as we have completed it.\n return;\n } else {\n // The child node failed, try the next one.\n continue;\n }\n }\n\n // The node should be in the 'RUNNING' state.\n if (child.getState() === State.RUNNING) {\n // This node is a 'RUNNING' node.\n this.setState(State.RUNNING);\n\n // There is no need to check the rest of the selector as the current child is still running.\n return;\n }\n\n // The child node was not in an expected state.\n throw new Error(\"child node was not in an expected state.\");\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => \"SELECTOR\";\n}\n", "import Composite from \"./Composite\";\nimport Node from \"../Node\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A SEQUENCE node.\n * The child nodes are executed in sequence until one fails or all succeed.\n */\nexport default class Sequence extends Composite {\n /**\n * @param attributes The node attributes.\n * @param children The child nodes.\n */\n constructor(attributes: Attribute[], protected children: Node[]) {\n super(\"sequence\", attributes, children);\n }\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // Iterate over all of the children of this node.\n for (const child of this.children) {\n // If the child has never been updated or is running then we will need to update it now.\n if (child.getState() === State.READY || child.getState() === State.RUNNING) {\n // Update the child of this node.\n child.update(agent, options);\n }\n\n // If the current child has a state of 'SUCCEEDED' then we should move on to the next child.\n if (child.getState() === State.SUCCEEDED) {\n // Find out if the current child is the last one in the sequence.\n // If it is then this sequence node has also succeeded.\n if (this.children.indexOf(child) === this.children.length - 1) {\n // This node is a 'SUCCEEDED' node.\n this.setState(State.SUCCEEDED);\n\n // There is no need to check the rest of the sequence as we have completed it.\n return;\n } else {\n // The child node succeeded, but we have not finished the sequence yet.\n continue;\n }\n }\n\n // If the current child has a state of 'FAILED' then this node is also a 'FAILED' node.\n if (child.getState() === State.FAILED) {\n // This node is a 'FAILED' node.\n this.setState(State.FAILED);\n\n // There is no need to check the rest of the sequence.\n return;\n }\n\n // The node should be in the 'RUNNING' state.\n if (child.getState() === State.RUNNING) {\n // This node is a 'RUNNING' node.\n this.setState(State.RUNNING);\n\n // There is no need to check the rest of the sequence as the current child is still running.\n return;\n }\n\n // The child node was not in an expected state.\n throw new Error(\"child node was not in an expected state.\");\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => \"SEQUENCE\";\n}\n", "import createLotto from \"lotto-draw\";\n\nimport Node from \"../Node\";\nimport Composite from \"./Composite\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A LOTTO node.\n * A winning child is picked on the initial update of this node, based on ticket weighting.\n * The state of this node will match the state of the winning child.\n */\nexport default class Lotto extends Composite {\n /**\n * @param attributes The node attributes.\n * @param weights The child node weights.\n * @param children The child nodes.\n */\n constructor(attributes: Attribute[], private weights: number[] | undefined, children: Node[]) {\n super(\"lotto\", attributes, children);\n }\n\n /**\n * The child node selected to be the active one.\n */\n private selectedChild: Node | undefined;\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // If this node is in the READY state then we need to pick a winning child node.\n if (this.is(State.READY)) {\n // Create a lotto draw with which to randomly pick a child node to become the active one.\n const lottoDraw = createLotto({\n // Hook up the optional 'random' behaviour tree function option to the one used by 'lotto-draw'.\n random: options.random,\n // Pass in each child node as a participant in the lotto draw with their respective ticket count.\n participants: this.children.map((child, index) => [child, this.weights?.[index] || 1])\n });\n\n // Randomly pick a child based on ticket weighting, this will become the active child for this composite node.\n this.selectedChild = lottoDraw.draw() || undefined;\n }\n\n // If something went wrong and we don't have an active child then we should throw an error.\n if (!this.selectedChild) {\n throw new Error(\"failed to update lotto node as it has no active child\");\n }\n\n // If the selected child has never been updated or is running then we will need to update it now.\n if (this.selectedChild.getState() === State.READY || this.selectedChild.getState() === State.RUNNING) {\n this.selectedChild.update(agent, options);\n }\n\n // The state of the lotto node is the state of its selected child.\n this.setState(this.selectedChild.getState());\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => (this.weights ? `LOTTO [${this.weights.join(\",\")}]` : \"LOTTO\");\n}\n", "import Node from \"../Node\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\n\n/**\n * A decorator node that wraps a single child node.\n */\nexport default abstract class Decorator extends Node {\n /**\n * @param type The node type.\n * @param attributes The node attributes.\n * @param child The child node.\n */\n constructor(type: string, attributes: Attribute[], protected child: Node) {\n super(type, attributes, []);\n }\n\n /**\n * Gets whether this node is a leaf node.\n */\n isLeafNode = () => false;\n\n /**\n * Gets the children of this node.\n */\n getChildren = () => [this.child];\n\n /**\n * Reset the state of the node.\n */\n reset = () => {\n // Reset the state of this node.\n this.setState(State.READY);\n\n // Reset the state of the child node.\n this.child.reset();\n };\n\n /**\n * Abort the running of this node.\n * @param agent The agent.\n */\n abort = (agent: Agent) => {\n // There is nothing to do if this node is not in the running state.\n if (!this.is(State.RUNNING)) {\n return;\n }\n\n // Abort the child node.\n this.child.abort(agent);\n\n // Reset the state of this node.\n this.reset();\n\n this.getAttribute(\"exit\")?.callAgentFunction(agent, false, true);\n };\n}\n", "import Node from \"../Node\";\nimport Decorator from \"./Decorator\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A Fail node.\n * This node wraps a single child and will always move to the 'FAILED' state when the child moves to a 'SUCCEEDED' or 'FAILED' state.\n */\nexport default class Fail extends Decorator {\n /**\n * @param attributes The node attributes.\n * @param child The child node.\n */\n constructor(attributes: Attribute[], child: Node) {\n super(\"fail\", attributes, child);\n }\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // If the child has never been updated or is running then we will need to update it now.\n if (this.child.getState() === State.READY || this.child.getState() === State.RUNNING) {\n this.child.update(agent, options);\n }\n\n // The state of this node will depend in the state of its child.\n switch (this.child.getState()) {\n case State.RUNNING:\n this.setState(State.RUNNING);\n break;\n\n case State.SUCCEEDED:\n case State.FAILED:\n this.setState(State.FAILED);\n break;\n\n default:\n this.setState(State.READY);\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => \"FAIL\";\n}\n", "import Decorator from \"./Decorator\";\nimport State from \"../../State\";\nimport Node from \"../Node\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A Flip node.\n * This node wraps a single child and will flip the state of the child state.\n */\nexport default class Flip extends Decorator {\n /**\n * @param attributes The node attributes.\n * @param child The child node.\n */\n constructor(attributes: Attribute[], child: Node) {\n super(\"flip\", attributes, child);\n }\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // If the child has never been updated or is running then we will need to update it now.\n if (this.child.getState() === State.READY || this.child.getState() === State.RUNNING) {\n this.child.update(agent, options);\n }\n\n // The state of this node will depend in the state of its child.\n switch (this.child.getState()) {\n case State.RUNNING:\n this.setState(State.RUNNING);\n break;\n\n case State.SUCCEEDED:\n this.setState(State.FAILED);\n break;\n\n case State.FAILED:\n this.setState(State.SUCCEEDED);\n break;\n\n default:\n this.setState(State.READY);\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => \"FLIP\";\n}\n", "import Node from \"../Node\";\nimport Decorator from \"./Decorator\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A REPEAT node.\n * The node has a single child which can have:\n * -- A number of iterations for which to repeat the child node.\n * -- An infinite repeat loop if neither an iteration count or a condition function is defined.\n * The REPEAT node will stop and have a 'FAILED' state if its child is ever in a 'FAILED' state after an update.\n * The REPEAT node will attempt to move on to the next iteration if its child is ever in a 'SUCCEEDED' state.\n */\nexport default class Repeat extends Decorator {\n /**\n * @param attributes The node attributes.\n * @param iterations The number of iterations to repeat the child node.\n * @param iterationsMin The minimum possible number of iterations to repeat the child node.\n * @param iterationsMax The maximum possible number of iterations to repeat the child node.\n * @param child The child node.\n */\n constructor(\n attributes: Attribute[],\n private iterations: number | null,\n private iterationsMin: number | null,\n private iterationsMax: number | null,\n child: Node\n ) {\n super(\"repeat\", attributes, child);\n }\n\n /**\n * The number of target iterations to make.\n */\n private targetIterationCount: number | null = null;\n\n /**\n * The current iteration count.\n */\n private currentIterationCount: number = 0;\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // If this node is in the READY state then we need to reset the child and the target iteration count.\n if (this.is(State.READY)) {\n // Reset the child node.\n this.child.reset();\n\n // Reset the current iteration count.\n this.currentIterationCount = 0;\n\n // Set the target iteration count.\n this.setTargetIterationCount(options);\n }\n\n // Do a check to see if we can iterate. If we can then this node will move into the 'RUNNING' state.\n // If we cannot iterate then we have hit our target iteration count, which means that the node has succeeded.\n if (this.canIterate()) {\n // This node is in the running state and can do its initial iteration.\n this.setState(State.RUNNING);\n\n // We may have already completed an iteration, meaning that the child node will be in the SUCCEEDED state.\n // If this is the case then we will have to reset the child node now.\n if (this.child.getState() === State.SUCCEEDED) {\n this.child.reset();\n }\n\n // Update the child of this node.\n this.child.update(agent, options);\n\n // If the child moved into the FAILED state when we updated it then there is nothing left to do and this node has also failed.\n // If it has moved into the SUCCEEDED state then we have completed the current iteration.\n if (this.child.getState() === State.FAILED) {\n // The child has failed, meaning that this node has failed.\n this.setState(State.FAILED);\n\n return;\n } else if (this.child.getState() === State.SUCCEEDED) {\n // We have completed an iteration.\n this.currentIterationCount += 1;\n }\n } else {\n // This node is in the 'SUCCEEDED' state as we cannot iterate any more.\n this.setState(State.SUCCEEDED);\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => {\n if (this.iterations !== null) {\n return `REPEAT ${this.iterations}x`;\n } else if (this.iterationsMin !== null && this.iterationsMax !== null) {\n return `REPEAT ${this.iterationsMin}x-${this.iterationsMax}x`;\n } else {\n return \"REPEAT\";\n }\n };\n\n /**\n * Reset the state of the node.\n */\n reset = () => {\n // Reset the state of this node.\n this.setState(State.READY);\n\n // Reset the current iteration count.\n this.currentIterationCount = 0;\n\n // Reset the child node.\n this.child.reset();\n };\n\n /**\n * Gets whether an iteration can be made.\n * @returns Whether an iteration can be made.\n */\n private canIterate = () => {\n if (this.targetIterationCount !== null) {\n // We can iterate as long as we have not reached our target iteration count.\n return this.currentIterationCount < this.targetIterationCount;\n }\n\n // If neither an iteration count or a condition function were defined then we can iterate indefinitely.\n return true;\n };\n\n /**\n * Sets the target iteration count.\n * @param options The behaviour tree options object.\n */\n private setTargetIterationCount = (options: BehaviourTreeOptions) => {\n // Are we dealing with an explicit iteration count or will we be randomly picking a iteration count between the min and max iteration count.\n if (this.iterations !== null) {\n this.targetIterationCount = this.iterations;\n } else if (this.iterationsMin !== null && this.iterationsMax !== null) {\n // We will be picking a random iteration count between a min and max iteration count, if the optional 'random'\n // behaviour tree function option is defined then we will be using that, otherwise we will fall back to using Math.random.\n const random = typeof options.random === \"function\" ? options.random : Math.random;\n\n // Pick a random iteration count between a min and max iteration count.\n this.targetIterationCount = Math.floor(\n random() * (this.iterationsMax - this.iterationsMin + 1) + this.iterationsMin\n );\n } else {\n this.targetIterationCount = null;\n }\n };\n}\n", "import Node from \"../Node\";\nimport Decorator from \"./Decorator\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A RETRY node.\n * The node has a single child which can have:\n * -- A number of iterations for which to repeat the child node.\n * -- An infinite repeat loop if neither an iteration count or a condition function is defined.\n * The RETRY node will stop and have a 'SUCCEEDED' state if its child is ever in a 'SUCCEEDED' state after an update.\n * The RETRY node will attempt to move on to the next iteration if its child is ever in a 'FAILED' state.\n */\nexport default class Retry extends Decorator {\n /**\n * @param attributes The node attributes.\n * @param attempts The number of attempts to retry the child node.\n * @param attemptsMin The minimum possible number of attempts to retry the child node.\n * @param attemptsMax The maximum possible number of attempts to retry the child node.\n * @param child The child node.\n */\n constructor(\n attributes: Attribute[],\n private attempts: number | null,\n private attemptsMin: number | null,\n private attemptsMax: number | null,\n child: Node\n ) {\n super(\"retry\", attributes, child);\n }\n\n /**\n * The number of target attempts to make.\n */\n private targetAttemptCount: number | null = null;\n\n /**\n * The current attempt count.\n */\n private currentAttemptCount: number = 0;\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // If this node is in the READY state then we need to reset the child and the target attempt count.\n if (this.is(State.READY)) {\n // Reset the child node.\n this.child.reset();\n\n // Reset the current attempt count.\n this.currentAttemptCount = 0;\n\n // Set the target attempt count.\n this.setTargetAttemptCount(options);\n }\n\n // Do a check to see if we can attempt. If we can then this node will move into the 'RUNNING' state.\n // If we cannot attempt then we have hit our target attempt count, which means that the node has succeeded.\n if (this.canAttempt()) {\n // This node is in the running state and can do its initial attempt.\n this.setState(State.RUNNING);\n\n // We may have already completed an attempt, meaning that the child node will be in the FAILED state.\n // If this is the case then we will have to reset the child node now.\n if (this.child.getState() === State.FAILED) {\n this.child.reset();\n }\n\n // Update the child of this node.\n this.child.update(agent, options);\n\n // If the child moved into the SUCCEEDED state when we updated it then there is nothing left to do and this node has also succeeded.\n // If it has moved into the FAILED state then we have completed the current attempt.\n if (this.child.getState() === State.SUCCEEDED) {\n // The child has succeeded, meaning that this node has succeeded.\n this.setState(State.SUCCEEDED);\n\n return;\n } else if (this.child.getState() === State.FAILED) {\n // We have completed an attempt.\n this.currentAttemptCount += 1;\n }\n } else {\n // This node is in the 'FAILED' state as we cannot iterate any more.\n this.setState(State.FAILED);\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => {\n if (this.attempts !== null) {\n return `RETRY ${this.attempts}x`;\n } else if (this.attemptsMin !== null && this.attemptsMax !== null) {\n return `RETRY ${this.attemptsMin}x-${this.attemptsMax}x`;\n } else {\n return \"RETRY\";\n }\n };\n\n /**\n * Reset the state of the node.\n */\n reset = () => {\n // Reset the state of this node.\n this.setState(State.READY);\n\n // Reset the current attempt count.\n this.currentAttemptCount = 0;\n\n // Reset the child node.\n this.child.reset();\n };\n\n /**\n * Gets whether an attempt can be made.\n * @returns Whether an attempt can be made.\n */\n canAttempt = () => {\n if (this.targetAttemptCount !== null) {\n // We can attempt as long as we have not reached our target attempt count.\n return this.currentAttemptCount < this.targetAttemptCount;\n }\n\n // If neither an attempt count or a condition function were defined then we can attempt indefinitely.\n return true;\n };\n\n /**\n * Sets the target attempt count.\n * @param options The behaviour tree options object.\n */\n setTargetAttemptCount = (options: BehaviourTreeOptions) => {\n // Are we dealing with an explicit attempt count or will we be randomly picking an attempt count between the min and max attempt count.\n if (this.attempts !== null) {\n this.targetAttemptCount = this.attempts;\n } else if (this.attemptsMin !== null && this.attemptsMax !== null) {\n // We will be picking a random attempt count between a min and max attempt count, if the optional 'random'\n // behaviour tree function option is defined then we will be using that, otherwise we will fall back to using Math.random.\n const random = typeof options.random === \"function\" ? options.random : Math.random;\n\n // Pick a random attempt count between a min and max attempt count.\n this.targetAttemptCount = Math.floor(\n random() * (this.attemptsMax - this.attemptsMin + 1) + this.attemptsMin\n );\n } else {\n this.targetAttemptCount = null;\n }\n };\n}\n", "import Node from \"../Node\";\nimport Decorator from \"./Decorator\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A Root node.\n * The root node will have a single child.\n */\nexport default class Root extends Decorator {\n /**\n * @param attributes The node attributes.\n * @param child The child node.\n */\n constructor(attributes: Attribute[], child: Node) {\n super(\"root\", attributes, child);\n }\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // If the child has never been updated or is running then we will need to update it now.\n if (this.child.getState() === State.READY || this.child.getState() === State.RUNNING) {\n // Update the child of this node.\n this.child.update(agent, options);\n }\n\n // The state of the root node is the state of its child.\n this.setState(this.child.getState());\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => \"ROOT\";\n}\n", "import Node from \"../Node\";\nimport Decorator from \"./Decorator\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A Succeed node.\n * This node wraps a single child and will always move to the 'SUCCEEDED' state when the child moves to a 'SUCCEEDED' or 'FAILED' state.\n */\nexport default class Succeed extends Decorator {\n /**\n * @param attributes The node attributes.\n * @param child The child node.\n */\n constructor(attributes: Attribute[], child: Node) {\n super(\"succeed\", attributes, child);\n }\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // If the child has never been updated or is running then we will need to update it now.\n if (this.child.getState() === State.READY || this.child.getState() === State.RUNNING) {\n this.child.update(agent, options);\n }\n\n // The state of this node will depend in the state of its child.\n switch (this.child.getState()) {\n case State.RUNNING:\n this.setState(State.RUNNING);\n break;\n\n case State.SUCCEEDED:\n case State.FAILED:\n this.setState(State.SUCCEEDED);\n break;\n\n default:\n this.setState(State.READY);\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => \"SUCCEED\";\n}\n", "import Node from \"../Node\";\n\n/**\n * A leaf node.\n */\nexport default abstract class Leaf extends Node {\n /**\n * Gets whether this node is a leaf node.\n */\n isLeafNode = () => true;\n}\n", "import { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\nimport State, { CompleteState } from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Leaf from \"./Leaf\";\nimport Lookup from \"../../Lookup\";\nimport Attribute from \"../../attributes/Attribute\";\n\n/**\n * An Action leaf node.\n * This represents an immediate or ongoing state of behaviour.\n */\nexport default class Action extends Leaf {\n /**\n * @param attributes The node attributes.\n * @param actionName The action name.\n * @param actionArguments The array of action argument definitions.\n */\n constructor(attributes: Attribute[], private actionName: string, private actionArguments: any[]) {\n super(\"action\", attributes, actionArguments);\n }\n\n /**\n * Whether there is a pending update promise.\n */\n private isUsingUpdatePromise = false;\n\n /**\n * The finished state result of an update promise.\n */\n private updatePromiseStateResult: CompleteState | null = null;\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // If the result of this action depends on an update promise then there is nothing to do until\n // it resolves, unless there has been a value set as a result of the update promise resolving.\n if (this.isUsingUpdatePromise) {\n // Check whether the update promise has resolved with a state value.\n if (this.updatePromiseStateResult) {\n // Set the state of this node to match the state returned by the promise.\n this.setState(this.updatePromiseStateResult);\n }\n\n return;\n }\n\n // Attempt to get the invoker for the action function.\n const actionFuncInvoker = Lookup.getFuncInvoker(agent, this.actionName);\n\n // The action function should be defined.\n if (actionFuncInvoker === null) {\n throw new Error(\n `cannot update action node as the action '${this.actionName}' function is not defined on the agent and has not been registered`\n );\n }\n\n // Call the action function, the result of which may be:\n // - The finished state of this action node.\n // - A promise to return a finished node state.\n // - Undefined if the node should remain in the running state.\n const updateResult = actionFuncInvoker(this.actionArguments) as CompleteState | Promise;\n\n if (updateResult instanceof Promise) {\n updateResult.then(\n (result) => {\n // If 'isUpdatePromisePending' is null then the promise was cleared as it was resolving, probably via an abort of reset.\n if (!this.isUsingUpdatePromise) {\n return;\n }\n\n // Check to make sure the result is a valid finished state.\n if (result !== State.SUCCEEDED && result !== State.FAILED) {\n throw new Error(\n \"action node promise resolved with an invalid value, expected a State.SUCCEEDED or State.FAILED value to be returned\"\n );\n }\n\n // Set pending update promise state result to be processed on next update.\n this.updatePromiseStateResult = result;\n },\n (reason) => {\n // If 'isUpdatePromisePending' is null then the promise was cleared as it was resolving, probably via an abort of reset.\n if (!this.isUsingUpdatePromise) {\n return;\n }\n\n // Just throw whatever was returned as the rejection argument.\n throw new Error(reason);\n }\n );\n\n // This node will be in the 'RUNNING' state until the update promise resolves.\n this.setState(State.RUNNING);\n\n // We are now waiting for the promise returned by the use to resolve before we know what state this node is in.\n this.isUsingUpdatePromise = true;\n } else {\n // Validate the returned value.\n this.validateUpdateResult(updateResult);\n\n // Set the state of this node, this may be undefined, which just means that the node is still in the 'RUNNING' state.\n this.setState(updateResult || State.RUNNING);\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => this.actionName;\n\n /**\n * Reset the state of the node.\n */\n reset = () => {\n // Reset the state of this node.\n this.setState(State.READY);\n\n // There is no longer an update promise that we care about.\n this.isUsingUpdatePromise = false;\n this.updatePromiseStateResult = null;\n };\n\n /**\n * Validate the result of an update function call.\n * @param result The result of an update function call.\n */\n private validateUpdateResult = (result: CompleteState | boolean) => {\n switch (result) {\n case State.SUCCEEDED:\n case State.FAILED:\n case undefined:\n return;\n default:\n throw new Error(\n `action '${this.actionName}' 'onUpdate' returned an invalid response, expected an optional State.SUCCEEDED or State.FAILED value to be returned`\n );\n }\n };\n}\n", "import { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Leaf from \"./Leaf\";\nimport Lookup from \"../../Lookup\";\nimport Attribute from \"../../attributes/Attribute\";\n\n/**\n * A Condition leaf node.\n * This will succeed or fail immediately based on an agent predicate, without moving to the 'RUNNING' state.\n */\nexport default class Condition extends Leaf {\n /**\n * @param attributes The node attributes.\n * @param conditionName The name of the condition function.\n * @param conditionArguments The array of condition argument definitions.\n */\n constructor(attributes: Attribute[], private conditionName: string, private conditionArguments: any[]) {\n super(\"condition\", attributes, conditionArguments);\n }\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // Attempt to get the invoker for the condition function.\n const conditionFuncInvoker = Lookup.getFuncInvoker(agent, this.conditionName);\n\n // The condition function should be defined.\n if (conditionFuncInvoker === null) {\n throw new Error(\n `cannot update condition node as the condition '${this.conditionName}' function is not defined on the agent and has not been registered`\n );\n }\n\n // Call the condition function to determine the state of this node.\n this.setState(!!conditionFuncInvoker(this.conditionArguments) ? State.SUCCEEDED : State.FAILED);\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => this.conditionName;\n}\n", "import Leaf from \"./Leaf\";\nimport State from \"../../State\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { Agent } from \"../../Agent\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A WAIT node.\n * The state of this node will change to SUCCEEDED after a duration of time\n */\nexport default class Wait extends Leaf {\n /**\n * @param attributes The node attributes.\n * @param duration The duration that this node will wait to succeed in milliseconds.\n * @param durationMin The minimum possible duration in milliseconds that this node will wait to succeed.\n * @param durationMax The maximum possible duration in milliseconds that this node will wait to succeed.\n */\n constructor(\n attributes: Attribute[],\n private duration: number | null,\n private durationMin: number | null,\n private durationMax: number | null\n ) {\n super(\"wait\", attributes, []);\n }\n\n /**\n * The time in milliseconds at which this node was first updated.\n */\n private initialUpdateTime: number = 0;\n\n /**\n * The total duration in milliseconds that this node will be waiting for.\n */\n private totalDuration: number | null = null;\n\n /**\n * The duration in milliseconds that this node has been waiting for.\n */\n private waitedDuration: number = 0;\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // If this node is in the READY state then we need to set the initial update time.\n if (this.is(State.READY)) {\n // Set the initial update time.\n this.initialUpdateTime = new Date().getTime();\n\n // Set the initial waited duration.\n this.waitedDuration = 0;\n\n // Are we dealing with an explicit duration or will we be randomly picking a duration between the min and max duration.\n if (this.duration !== null) {\n this.totalDuration = this.duration;\n } else if (this.durationMin !== null && this.durationMax !== null) {\n // We will be picking a random duration between a min and max duration, if the optional 'random' behaviour tree\n // function option is defined then we will be using that, otherwise we will fall back to using Math.random.\n const random = typeof options.random === \"function\" ? options.random : Math.random;\n\n // Pick a random duration between a min and max duration.\n this.totalDuration = Math.floor(\n random() * (this.durationMax - this.durationMin + 1) + this.durationMin\n );\n } else {\n this.totalDuration = null;\n }\n\n // The node is now running until we finish waiting.\n this.setState(State.RUNNING);\n }\n\n // If we have no total duration then this wait node will wait indefinitely until it is aborted.\n if (this.totalDuration === null) {\n return;\n }\n\n // If we have a 'getDeltaTime' function defined as part of our options then we will use it to figure out how long we have waited for.\n if (typeof options.getDeltaTime === \"function\") {\n // Get the delta time.\n const deltaTime = options.getDeltaTime();\n\n // Our delta time must be a valid number and cannot be NaN.\n if (typeof deltaTime !== \"number\" || isNaN(deltaTime)) {\n throw new Error(\"The delta time must be a valid number and not NaN.\");\n }\n\n // Update the amount of time that this node has been waiting for based on the delta time.\n this.waitedDuration += deltaTime * 1000;\n } else {\n // We are not using a delta time, so we will just work out hom much time has passed since the first update.\n this.waitedDuration = new Date().getTime() - this.initialUpdateTime;\n }\n\n // Have we waited long enough?\n if (this.waitedDuration >= this.totalDuration) {\n // We have finished waiting!\n this.setState(State.SUCCEEDED);\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => {\n if (this.duration !== null) {\n return `WAIT ${this.duration}ms`;\n } else if (this.durationMin !== null && this.durationMax !== null) {\n return `WAIT ${this.durationMin}ms-${this.durationMax}ms`;\n } else {\n return \"WAIT\";\n }\n };\n}\n", "import Guard from \"./guards/Guard\";\n\nexport type AttributeDetails = {\n /** The attribute type. */\n type: string;\n\n /** The attribute arguments. */\n args: any[];\n};\n\n/**\n * A base node attribute.\n */\nexport default abstract class Attribute {\n /**\n * @param type The node attribute type.\n * @param args The array of attribute arguments.\n */\n constructor(public type: string, public args: any[]) {}\n\n /**\n * Gets the attribute details.\n */\n abstract getDetails(): TAttributeDetails;\n\n /**\n * Gets whether this attribute is a guard.\n */\n abstract isGuard: () => this is Guard;\n}\n", "import { Agent } from \"../../Agent\";\nimport Attribute, { AttributeDetails } from \"../Attribute\";\n\nexport type GuardAttributeDetails = {\n /** The name of the condition function that determines whether the guard is satisfied. */\n condition: string;\n} & AttributeDetails;\n\n/**\n * A base node guard attribute.\n */\nexport default abstract class Guard extends Attribute {\n /**\n * @param type The node attribute type.\n * @param args The array of decorator argument definitions.\n * @param condition The name of the condition function that determines whether the guard is satisfied.\n */\n constructor(type: string, args: any[], private condition: string) {\n super(type, args);\n }\n\n /**\n * Gets the name of the condition function that determines whether the guard is satisfied.\n */\n getCondition = () => this.condition;\n\n /**\n * Gets whether this attribute is a guard.\n */\n isGuard = () => true;\n\n /**\n * Gets the attribute details.\n */\n getDetails(): GuardAttributeDetails {\n return {\n type: this.type,\n args: this.args,\n condition: this.getCondition()\n };\n }\n\n /**\n * Gets whether the guard is satisfied.\n * @param agent The agent.\n * @returns Whether the guard is satisfied.\n */\n abstract isSatisfied(agent: Agent): boolean;\n}\n", "import Guard from \"./Guard\";\nimport Lookup from \"../../Lookup\";\nimport { Agent } from \"../../Agent\";\n\n/**\n * A WHILE guard which is satisfied as long as the given condition remains true.\n */\nexport default class While extends Guard {\n /**\n * @param condition The name of the condition function that determines whether the guard is satisfied.\n * @param args The array of decorator argument definitions.\n */\n constructor(condition: string, args: any[]) {\n super(\"while\", args, condition);\n }\n\n /**\n * Gets whether the guard is satisfied.\n * @param agent The agent.\n * @returns Whether the guard is satisfied.\n */\n isSatisfied = (agent: Agent) => {\n // Attempt to get the invoker for the condition function.\n const conditionFuncInvoker = Lookup.getFuncInvoker(agent, this.getCondition());\n\n // The condition function should be defined.\n if (conditionFuncInvoker === null) {\n throw new Error(\n `cannot evaluate node guard as the condition '${this.getCondition()}' function is not defined on the agent and has not been registered`\n );\n }\n\n // Call the condition function to determine whether this guard is satisfied.\n return !!conditionFuncInvoker(this.args);\n };\n}\n", "import Guard from \"./Guard\";\nimport Lookup from \"../../Lookup\";\nimport { Agent } from \"../../Agent\";\n\n/**\n * An UNTIL guard which is satisfied as long as the given condition remains false.\n */\nexport default class Until extends Guard {\n /**\n * @param condition The name of the condition function that determines whether the guard is satisfied.\n * @param args The array of decorator argument definitions.\n */\n constructor(condition: string, args: any[]) {\n super(\"until\", args, condition);\n }\n\n /**\n * Gets whether the guard is satisfied.\n * @param agent The agent.\n * @returns Whether the guard is satisfied.\n */\n isSatisfied = (agent: Agent) => {\n // Attempt to get the invoker for the condition function.\n const conditionFuncInvoker = Lookup.getFuncInvoker(agent, this.getCondition());\n\n // The condition function should be defined.\n if (conditionFuncInvoker === null) {\n throw new Error(\n `cannot evaluate node guard as the condition '${this.getCondition()}' function is not defined on the agent and has not been registered`\n );\n }\n\n // Call the condition function to determine whether this guard is satisfied.\n return !!!conditionFuncInvoker(this.args);\n };\n}\n", "import { Agent } from \"../../Agent\";\nimport Attribute, { AttributeDetails } from \"../Attribute\";\n\nexport type CallbackAttributeDetails = {\n /** The name of the agent function that is called. */\n functionName: string;\n} & AttributeDetails;\n\n/**\n * A base node callback attribute.\n */\nexport default abstract class Callback extends Attribute {\n /**\n * @param type The node attribute type.\n * @param args The array of decorator argument definitions.\n * @param functionName The name of the agent function to call.\n */\n constructor(type: string, args: any[], private functionName: string) {\n super(type, args);\n }\n\n /**\n * Gets the name of the agent function to call.\n */\n getFunctionName = () => this.functionName;\n\n /**\n * Gets whether this attribute is a guard.\n */\n isGuard = () => false;\n\n /**\n * Gets the attribute details.\n */\n getDetails(): CallbackAttributeDetails {\n return {\n type: this.type,\n args: this.args,\n functionName: this.getFunctionName()\n };\n }\n\n /**\n * Attempt to call the agent function that this callback refers to.\n * @param agent The agent.\n */\n abstract callAgentFunction: (agent: Agent, isSuccess: boolean, isAborted: boolean) => void;\n}\n", "import Callback from \"./Callback\";\nimport Lookup from \"../../Lookup\";\nimport { Agent } from \"../../Agent\";\n\n/**\n * An ENTRY callback which defines an agent function to call when the associated node is updated and moves out of running state.\n */\nexport default class Entry extends Callback {\n /**\n * @param functionName The name of the agent function to call.\n * @param args The array of callback argument definitions.\n */\n constructor(functionName: string, args: any[]) {\n super(\"entry\", args, functionName);\n }\n\n /**\n * Attempt to call the agent function that this callback refers to.\n * @param agent The agent.\n */\n callAgentFunction = (agent: Agent) => {\n // Attempt to get the invoker for the callback function.\n const callbackFuncInvoker = Lookup.getFuncInvoker(agent, this.getFunctionName());\n\n // The callback function should be defined.\n if (callbackFuncInvoker === null) {\n throw new Error(\n `cannot call entry function '${this.getFunctionName()}' as is not defined on the agent and has not been registered`\n );\n }\n\n // Call the callback function.\n callbackFuncInvoker(this.args);\n };\n}\n", "import Callback from \"./Callback\";\nimport Lookup from \"../../Lookup\";\nimport { Agent } from \"../../Agent\";\n\n/**\n * A STEP callback which defines an agent function to call when the associated node is updated.\n */\nexport default class Step extends Callback {\n /**\n * @param functionName The name of the agent function to call.\n * @param args The array of callback argument definitions.\n */\n constructor(functionName: string, args: any[]) {\n super(\"step\", args, functionName);\n }\n\n /**\n * Attempt to call the agent function that this callback refers to.\n * @param agent The agent.\n */\n callAgentFunction = (agent: Agent) => {\n // Attempt to get the invoker for the callback function.\n const callbackFuncInvoker = Lookup.getFuncInvoker(agent, this.getFunctionName());\n\n // The callback function should be defined.\n if (callbackFuncInvoker === null) {\n throw new Error(\n `cannot call step function '${this.getFunctionName()}' as is not defined on the agent and has not been registered`\n );\n }\n\n // Call the callback function.\n callbackFuncInvoker(this.args);\n };\n}\n", "import Callback from \"./Callback\";\nimport Lookup from \"../../Lookup\";\nimport { Agent } from \"../../Agent\";\n\n/**\n * An EXIT callback which defines an agent function to call when the associated node is updated and moves to a finished state or is aborted.\n */\nexport default class Exit extends Callback {\n /**\n * @param functionName The name of the agent function to call.\n * @param args The array of callback argument definitions.\n */\n constructor(functionName: string, args: any[]) {\n super(\"exit\", args, functionName);\n }\n\n /**\n * Attempt to call the agent function that this callback refers to.\n * @param agent The agent.\n * @param isSuccess Whether the decorated node was left with a success state.\n * @param isAborted Whether the decorated node was aborted.\n */\n callAgentFunction = (agent: Agent, isSuccess: boolean, isAborted: boolean) => {\n // Attempt to get the invoker for the callback function.\n const callbackFuncInvoker = Lookup.getFuncInvoker(agent, this.getFunctionName());\n\n // The callback function should be defined.\n if (callbackFuncInvoker === null) {\n throw new Error(\n `cannot call exit function '${this.getFunctionName()}' as is not defined on the agent and has not been registered`\n );\n }\n\n // Call the callback function\n callbackFuncInvoker([{ value: { succeeded: isSuccess, aborted: isAborted } }, ...this.args]);\n };\n}\n", "import { AnyNodeDefinition, RootNodeDefinition } from \"./BehaviourTreeDefinition\";\nimport GuardPath, { GuardPathPart } from \"./attributes/guards/GuardPath\";\nimport { validateBranchSubtreeLinks } from \"./BehaviourTreeDefinitionValidator\";\nimport { isInteger } from \"./BehaviourTreeDefinitionUtilities\";\nimport Node from \"./nodes/Node\";\nimport Composite from \"./nodes/composite/Composite\";\nimport Decorator from \"./nodes/decorator/Decorator\";\nimport Parallel from \"./nodes/composite/Parallel\";\nimport Selector from \"./nodes/composite/Selector\";\nimport Sequence from \"./nodes/composite/Sequence\";\nimport Lotto from \"./nodes/composite/Lotto\";\nimport Fail from \"./nodes/decorator/Fail\";\nimport Flip from \"./nodes/decorator/Flip\";\nimport Repeat from \"./nodes/decorator/Repeat\";\nimport Retry from \"./nodes/decorator/Retry\";\nimport Root from \"./nodes/decorator/Root\";\nimport Succeed from \"./nodes/decorator/Succeed\";\nimport Action from \"./nodes/leaf/Action\";\nimport Condition from \"./nodes/leaf/Condition\";\nimport Wait from \"./nodes/leaf/Wait\";\nimport Lookup from \"./Lookup\";\nimport Attribute from \"./attributes/Attribute\";\nimport While from \"./attributes/guards/While\";\nimport Until from \"./attributes/guards/Until\";\nimport Entry from \"./attributes/callbacks/Entry\";\nimport Step from \"./attributes/callbacks/Step\";\nimport Exit from \"./attributes/callbacks/Exit\";\n\n/**\n * A type representing any node instance in a behaviour tree.\n */\ntype AnyNode =\n | Root\n | Action\n | Condition\n | Wait\n | Sequence\n | Selector\n | Lotto\n | Parallel\n | Repeat\n | Retry\n | Flip\n | Succeed\n | Fail;\n\n/**\n * A type defining a mapping of root node identifiers to root node definitions.\n */\ntype RootNodeDefinitionMap = { [key: string | symbol]: RootNodeDefinition };\n\n/**\n * A symbol to use as the main root key in any root node mappings.\n */\nconst MAIN_ROOT_NODE_KEY = Symbol(\"__root__\");\n\n/**\n * Build and populate the root nodes based on the provided definition, assuming that the definition has been validated.\n * @param definition The root node definitions.\n * @returns The built and populated root node definitions.\n */\nexport default function buildRootNode(definition: RootNodeDefinition[]): Root {\n // Create a mapping of root node identifers to root node definitions, including globally registered subtree root node definitions.\n const rootNodeDefinitionMap = createRootNodeDefinitionMap(definition);\n\n // Now that we have all of our root node definitons (those part of the tree definition and those globally\n // registered) we should validate the definition. This will also double-check that we dont have any circular\n // dependencies in our branch -> subtree references and that we have no broken branch -> subtree links.\n validateBranchSubtreeLinks(definition, true);\n\n // Create our populated tree of node instances, starting with our main root node.\n const rootNode = nodeFactory(rootNodeDefinitionMap[MAIN_ROOT_NODE_KEY], rootNodeDefinitionMap) as Root;\n\n // Set a guard path on every leaf of the tree to evaluate as part of each update.\n applyLeafNodeGuardPaths(rootNode);\n\n // We only need to return the main root node.\n return rootNode;\n}\n\n/**\n * A factory function which creates a node instance based on the specified definition.\n * @param definition The node definition.\n * @param rootNodeDefinitionMap The mapping of root node identifers to root node definitions, including globally registered subtree root node definitions.\n * @returns A node instance based on the specified definition.\n */\nfunction nodeFactory(definition: AnyNodeDefinition, rootNodeDefinitionMap: RootNodeDefinitionMap): AnyNode {\n // Get the attributes for the node.\n const attributes = nodeAttributesFactory(definition);\n\n // Create the node instance based on the definition type.\n switch (definition.type) {\n case \"root\":\n return new Root(attributes, nodeFactory(definition.child, rootNodeDefinitionMap));\n\n case \"repeat\":\n let iterations: number | null = null;\n let iterationsMin: number | null = null;\n let iterationsMax: number | null = null;\n\n if (Array.isArray(definition.iterations)) {\n iterationsMin = definition.iterations[0];\n iterationsMax = definition.iterations[1];\n } else if (isInteger(definition.iterations)) {\n iterations = definition.iterations!;\n }\n\n return new Repeat(\n attributes,\n iterations,\n iterationsMin,\n iterationsMax,\n nodeFactory(definition.child, rootNodeDefinitionMap)\n );\n\n case \"retry\":\n let attempts: number | null = null;\n let attemptsMin: number | null = null;\n let attemptsMax: number | null = null;\n\n if (Array.isArray(definition.attempts)) {\n attemptsMin = definition.attempts[0];\n attemptsMax = definition.attempts[1];\n } else if (isInteger(definition.attempts)) {\n attempts = definition.attempts!;\n }\n\n return new Retry(\n attributes,\n attempts,\n attemptsMin,\n attemptsMax,\n nodeFactory(definition.child, rootNodeDefinitionMap)\n );\n\n case \"flip\":\n return new Flip(attributes, nodeFactory(definition.child, rootNodeDefinitionMap));\n\n case \"succeed\":\n return new Succeed(attributes, nodeFactory(definition.child, rootNodeDefinitionMap));\n\n case \"fail\":\n return new Fail(attributes, nodeFactory(definition.child, rootNodeDefinitionMap));\n\n case \"sequence\":\n return new Sequence(\n attributes,\n definition.children.map((child) => nodeFactory(child, rootNodeDefinitionMap))\n );\n\n case \"selector\":\n return new Selector(\n attributes,\n definition.children.map((child) => nodeFactory(child, rootNodeDefinitionMap))\n );\n\n case \"parallel\":\n return new Parallel(\n attributes,\n definition.children.map((child) => nodeFactory(child, rootNodeDefinitionMap))\n );\n\n case \"lotto\":\n return new Lotto(\n attributes,\n definition.weights,\n definition.children.map((child) => nodeFactory(child, rootNodeDefinitionMap))\n );\n\n case \"branch\":\n return nodeFactory(rootNodeDefinitionMap[definition.ref].child, rootNodeDefinitionMap);\n\n case \"action\":\n return new Action(attributes, definition.call, definition.args || []);\n\n case \"condition\":\n return new Condition(attributes, definition.call, definition.args || []);\n\n case \"wait\":\n let duration: number | null = null;\n let durationMin: number | null = null;\n let durationMax: number | null = null;\n\n if (Array.isArray(definition.duration)) {\n durationMin = definition.duration[0];\n durationMax = definition.duration[1];\n } else if (isInteger(definition.duration)) {\n duration = definition.duration!;\n }\n\n return new Wait(attributes, duration, durationMin, durationMax);\n }\n}\n\n/**\n * Creates an array of node attribute instances based on the specified node definition.\n * @param definition The node definition.\n * @returns An array of node attribute instances based on the specified node definition.\n */\nfunction nodeAttributesFactory(definition: AnyNodeDefinition): Attribute[] {\n const attributes: Attribute[] = [];\n\n if (definition.while) {\n attributes.push(new While(definition.while.call, definition.while.args ?? []));\n }\n\n if (definition.until) {\n attributes.push(new Until(definition.until.call, definition.until.args ?? []));\n }\n\n if (definition.entry) {\n attributes.push(new Entry(definition.entry.call, definition.entry.args ?? []));\n }\n\n if (definition.step) {\n attributes.push(new Step(definition.step.call, definition.step.args ?? []));\n }\n\n if (definition.exit) {\n attributes.push(new Exit(definition.exit.call, definition.exit.args ?? []));\n }\n\n return attributes;\n}\n\n/**\n * Creates a mapping of root node identifers to root node definitions, mixing in globally registered subtree root node definitions.\n * @param definition The root node definitions.\n * @returns A mapping of root node identifers to root node definitions, including globally registered subtree root node definitions.\n */\nfunction createRootNodeDefinitionMap(definition: RootNodeDefinition[]): RootNodeDefinitionMap {\n // Create a mapping of root node identifers to root node definitions.\n const rootNodeMap: RootNodeDefinitionMap = {};\n\n // Add in any registered subtree root node definitions.\n for (const [name, rootNodeDefinition] of Object.entries(Lookup.getSubtrees())) {\n // The name used when registering the subtree will be used as the root node identifier.\n rootNodeMap[name] = { ...rootNodeDefinition, id: name };\n }\n\n // Populate the map with the root node definitions that were included with the tree definition.\n // We do this after adding any registered subtrees as we want these to take presedence.\n for (const rootNodeDefinition of definition) {\n rootNodeMap[rootNodeDefinition.id ?? MAIN_ROOT_NODE_KEY] = rootNodeDefinition;\n }\n\n return rootNodeMap;\n}\n\n/**\n * Applies a guard path to every leaf of the tree to evaluate as part of each update.\n * @param root The main root tree node.\n */\nfunction applyLeafNodeGuardPaths(root: Root) {\n const nodePaths: Node[][] = [];\n\n const findLeafNodes = (path: Node[], node: Node) => {\n // Add the current node to the path.\n path = path.concat(node);\n\n // Check whether the current node is a leaf node.\n if (node.isLeafNode()) {\n nodePaths.push(path);\n } else {\n (node as Composite | Decorator).getChildren().forEach((child) => findLeafNodes(path, child));\n }\n };\n\n // Find all leaf node paths, starting from the root.\n findLeafNodes([], root);\n\n nodePaths.forEach((path) => {\n // Each node in the current path will have to be assigned a guard path, working from the root outwards.\n for (let depth = 0; depth < path.length; depth++) {\n // Get the node in the path at the current depth.\n const currentNode = path[depth];\n\n // The node may already have been assigned a guard path, if so just skip it.\n if (currentNode.hasGuardPath()) {\n continue;\n }\n\n // Create the guard path for the current node.\n const guardPath = new GuardPath(\n path\n .slice(0, depth + 1)\n .map((node) => ({ node, guards: node.getGuardAttributes() }))\n .filter((details) => details.guards.length > 0)\n );\n\n // Assign the guard path to the current node.\n currentNode.setGuardPath(guardPath);\n }\n });\n}\n", "import State, { AnyState } from \"./State\";\nimport Lookup from \"./Lookup\";\nimport Node from \"./nodes/Node\";\nimport Root from \"./nodes/decorator/Root\";\nimport Composite from \"./nodes/composite/Composite\";\nimport Decorator from \"./nodes/decorator/Decorator\";\nimport { Agent, GlobalFunction } from \"./Agent\";\nimport { CallbackAttributeDetails } from \"./attributes/callbacks/Callback\";\nimport { GuardAttributeDetails } from \"./attributes/guards/Guard\";\nimport { BehaviourTreeOptions } from \"./BehaviourTreeOptions\";\nimport { convertMDSLToJSON } from \"./mdsl/MDSLDefinitionParser\";\nimport { RootNodeDefinition } from \"./BehaviourTreeDefinition\";\nimport { validateDefinition, validateJSONDefinition } from \"./BehaviourTreeDefinitionValidator\";\nimport buildRootNode from \"./BehaviourTreeBuilder\";\nimport { isNullOrUndefined } from \"./BehaviourTreeDefinitionUtilities\";\n\n// Purely for outside inspection of the tree.\nexport type FlattenedTreeNode = {\n id: string;\n type: string;\n caption: string;\n state: AnyState;\n guards: GuardAttributeDetails[];\n callbacks: CallbackAttributeDetails[];\n args: any[];\n parentId: string | null;\n};\n\n/**\n * A representation of a behaviour tree.\n */\nexport class BehaviourTree {\n /**\n * The main root tree node.\n */\n public readonly rootNode: Root;\n\n /**\n * Creates a new instance of the BehaviourTree class.\n * @param definition The behaviour tree definition.\n * @param agent The agent instance that this behaviour tree is modelling behaviour for.\n * @param options The behaviour tree options object.\n */\n constructor(\n definition: string | RootNodeDefinition | RootNodeDefinition[],\n private agent: Agent,\n private options: BehaviourTreeOptions = {}\n ) {\n // The tree definition must be defined.\n if (isNullOrUndefined(definition)) {\n throw new Error(\"tree definition not defined\");\n }\n\n // The agent must be defined and not null.\n if (typeof agent !== \"object\" || agent === null) {\n throw new Error(\"the agent must be an object and not null\");\n }\n\n // We should validate the definition before we try to build the tree nodes.\n const { succeeded, errorMessage } = validateDefinition(definition);\n\n // Did our validation fail without error?\n if (!succeeded) {\n throw new Error(`invalid definition: ${errorMessage}`);\n }\n\n try {\n // Parse the behaviour tree definition, create the populated tree of behaviour tree nodes, and get the root.\n this.rootNode = this._createRootNode(definition);\n } catch (exception) {\n // There was an issue in trying build and populate the behaviour tree.\n throw new Error(`error building tree: ${(exception as Error).message}`);\n }\n }\n\n /**\n * Gets whether the tree is in the RUNNING state.\n * @returns true if the tree is in the RUNNING state, otherwise false.\n */\n isRunning() {\n return this.rootNode.getState() === State.RUNNING;\n }\n\n /**\n * Gets the current tree state of SUCCEEDED, FAILED, READY or RUNNING.\n * @returns The current tree state.\n */\n getState() {\n return this.rootNode.getState();\n }\n\n /**\n * Step the tree.\n * 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.\n * 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\n * 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.\n *\n * 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.\n */\n step() {\n // If the root node has already been stepped to completion then we need to reset it.\n if (this.rootNode.getState() === State.SUCCEEDED || this.rootNode.getState() === State.FAILED) {\n this.rootNode.reset();\n }\n\n try {\n this.rootNode.update(this.agent, this.options);\n } catch (exception) {\n throw new Error(`error stepping tree: ${(exception as Error).message}`);\n }\n }\n\n /**\n * Resets the tree from the root node outwards to each nested node, giving each a state of READY.\n */\n reset() {\n this.rootNode.reset();\n }\n\n /**\n * Gets the flattened details of every node in the tree.\n * @returns The flattened details of every node in the tree.\n */\n getFlattenedNodeDetails(): FlattenedTreeNode[] {\n // Create an empty flattened array of tree nodes.\n const flattenedTreeNodes: FlattenedTreeNode[] = [];\n\n /**\n * Helper function to process a node instance and push details into the flattened tree nodes array.\n * @param node The current node.\n * @param parentUid The UID of the node parent, or null if the node is the main root node.\n */\n const processNode = (node: Node, parentUid: string | null) => {\n // Get the guard and callback attribute details for this node.\n const guards = node\n .getAttributes()\n .filter((attribute) => attribute.isGuard())\n .map((attribute) => attribute.getDetails()) as GuardAttributeDetails[];\n const callbacks = node\n .getAttributes()\n .filter((attribute) => !attribute.isGuard())\n .map((attribute) => attribute.getDetails()) as CallbackAttributeDetails[];\n\n // Push the current node into the flattened nodes array.\n flattenedTreeNodes.push({\n id: node.getUid(),\n type: node.getType(),\n caption: node.getName(),\n state: node.getState(),\n guards,\n callbacks,\n args: node.getArguments(),\n parentId: parentUid\n });\n\n // Process each of the nodes children if it is not a leaf node.\n if (!node.isLeafNode()) {\n (node as Composite | Decorator)\n .getChildren()\n .forEach((child) => processNode(child, (node as Composite | Decorator).getUid()));\n }\n };\n\n // Convert the nested node structure into a flattened array of node details.\n processNode(this.rootNode, null);\n\n return flattenedTreeNodes;\n }\n\n /**\n * Registers the action/condition/guard/callback function or subtree with the given name.\n * @param name The name of the function or subtree to register.\n * @param value The function or subtree definition to register.\n */\n static register(name: string, value: GlobalFunction | string | RootNodeDefinition) {\n // Are we going to register a action/condition/guard/callback function?\n if (typeof value === \"function\") {\n Lookup.setFunc(name, value);\n return;\n }\n\n // We are not registering an action/condition/guard/callback function, so we must be registering a subtree.\n if (typeof value === \"string\") {\n let rootNodeDefinitions: RootNodeDefinition[];\n\n // We will assume that any string passed in will be a mdsl definition.\n try {\n rootNodeDefinitions = convertMDSLToJSON(value);\n } catch (exception) {\n throw new Error(`error registering definition, invalid MDSL: ${(exception as Error).message}`);\n }\n\n // This function should only ever be called with a definition containing a single unnamed root node.\n if (rootNodeDefinitions.length != 1 || rootNodeDefinitions[0].id !== null) {\n throw new Error(\"error registering definition: expected a single unnamed root node\");\n }\n\n try {\n // We should validate the subtree as we don't want invalid subtrees available via the lookup.\n const { succeeded, errorMessage } = validateJSONDefinition(rootNodeDefinitions[0]);\n\n // Did our validation fail without error?\n if (!succeeded) {\n throw new Error(errorMessage);\n }\n } catch (exception) {\n throw new Error(`error registering definition: ${(exception as Error).message}`);\n }\n\n // Everything seems hunky-dory, register the subtree.\n Lookup.setSubtree(name, rootNodeDefinitions[0]);\n } else if (typeof value === \"object\" && !Array.isArray(value)) {\n // We will assume that any object passed in is a root node definition.\n\n try {\n // We should validate the subtree as we don't want invalid subtrees available via the lookup.\n const { succeeded, errorMessage } = validateJSONDefinition(value);\n\n // Did our validation fail without error?\n if (!succeeded) {\n throw new Error(errorMessage);\n }\n } catch (exception) {\n throw new Error(`error registering definition: ${(exception as Error).message}`);\n }\n\n // Everything seems hunky-dory, register the subtree.\n Lookup.setSubtree(name, value);\n } else {\n throw new Error(\"unexpected value, expected string mdsl definition, root node json definition or function\");\n }\n }\n\n /**\n * Unregisters the registered action/condition/guard/callback function or subtree with the given name.\n * @param name The name of the registered action/condition/guard/callback function or subtree to unregister.\n */\n static unregister(name: string): void {\n Lookup.remove(name);\n }\n\n /**\n * Unregister all registered action/condition/guard/callback functions and subtrees.\n */\n static unregisterAll(): void {\n Lookup.empty();\n }\n\n /**\n * Parses a behaviour tree definition and creates a tree of behaviour tree nodes populated at a root.\n * @param {string | RootNodeDefinition | RootNodeDefinition[]} definition The behaviour tree definition.\n * @returns The root behaviour tree node.\n */\n private _createRootNode(definition: string | RootNodeDefinition | RootNodeDefinition[]): Root {\n // Our definition will have to be converted to JSON if it is a MDSL string.\n // TODO convertMDSLToJSON is called TWICE, once for validation and once here. Maybe return the JSON as part of the validation result?\n const resolvedDefinition = typeof definition === \"string\" ? convertMDSLToJSON(definition) : definition;\n\n // Build and populate the root node.\n return buildRootNode(Array.isArray(resolvedDefinition) ? resolvedDefinition : [resolvedDefinition]);\n }\n}\n"], + "mappings": "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", "names": ["Participant", "isNullOrUndefined", "Lotto", "createLotto", "State", "createLotto"] } diff --git a/dist/index.js b/dist/index.js index 89bbd56..27e9ddb 100644 --- a/dist/index.js +++ b/dist/index.js @@ -683,12 +683,12 @@ function createParallelNode(tokens, stringLiteralPlaceholders) { } function createLottoNode(tokens, stringLiteralPlaceholders) { const nodeArguments = parseArgumentTokens(tokens, stringLiteralPlaceholders); - nodeArguments.filter((arg) => arg.type !== "number" || !arg.isInteger).forEach(() => { - throw new Error(`lotto node weight arguments must be integer values`); + nodeArguments.filter((arg) => arg.type !== "number" || !arg.isInteger || arg.value < 0).forEach(() => { + throw new Error(`lotto node weight arguments must be positive integer values`); }); const node = { type: "lotto", - weights: nodeArguments.map(({ value }) => value), + weights: nodeArguments.length ? nodeArguments.map(({ value }) => value) : void 0, ...parseAttributeTokens(tokens, stringLiteralPlaceholders) }; popAndCheck(tokens, "{"); @@ -761,12 +761,21 @@ function createBranchNode(tokens, stringLiteralPlaceholders) { } return { type: "branch", ref: nodeArguments[0].value }; } -function validatePoppedNode(node) { - if (isDecoratorNode(node) && isNullOrUndefined(node.child)) { - throw new Error(`a ${node.type} node must have a single child node defined`); +function validatePoppedNode(definition) { + if (isDecoratorNode(definition) && isNullOrUndefined(definition.child)) { + throw new Error(`a ${definition.type} node must have a single child node defined`); } - if (isCompositeNode(node) && !node.children?.length) { - throw new Error(`a ${node.type} node must have at least a single child node defined`); + if (isCompositeNode(definition) && !definition.children?.length) { + throw new Error(`a ${definition.type} node must have at least a single child node defined`); + } + if (definition.type === "lotto") { + if (typeof definition.weights !== "undefined") { + if (definition.weights.length !== definition.children.length) { + throw new Error( + "expected a number of weight arguments matching the number of child nodes for lotto node" + ); + } + } } } @@ -892,8 +901,8 @@ function validateNode(definition, depth) { case "root": validateRootNode(definition, depth); break; - case "success": - validateSuccessNode(definition, depth); + case "succeed": + validateSucceedNode(definition, depth); break; case "fail": validateFailNode(definition, depth); @@ -916,6 +925,9 @@ function validateNode(definition, depth) { case "parallel": validateParallelNode(definition, depth); break; + case "lotto": + validateLottoNode(definition, depth); + break; default: throw new Error(`unexpected node type of '${definition.type}' at depth '${depth}'`); } @@ -959,12 +971,12 @@ function validateRootNode(definition, depth) { validateNodeAttributes(definition, depth); validateNode(definition.child, depth + 1); } -function validateSuccessNode(definition, depth) { - if (definition.type !== "success") { - throw new Error(`expected node type of 'success' for success node at depth '${depth}'`); +function validateSucceedNode(definition, depth) { + if (definition.type !== "succeed") { + throw new Error(`expected node type of 'succeed' for succeed node at depth '${depth}'`); } if (typeof definition.child === "undefined") { - throw new Error(`expected property 'child' to be defined for success node at depth '${depth}'`); + throw new Error(`expected property 'child' to be defined for succeed node at depth '${depth}'`); } validateNodeAttributes(definition, depth); validateNode(definition.child, depth + 1); @@ -998,7 +1010,7 @@ function validateRepeatNode(definition, depth) { } if (typeof definition.iterations !== "undefined") { if (Array.isArray(definition.iterations)) { - const containsNonInteger = !!definition.iterations.find((value) => !isInteger(value)); + const containsNonInteger = !!definition.iterations.filter((value) => !isInteger(value)).length; if (definition.iterations.length !== 2 || containsNonInteger) { throw new Error( `expected array containing two integer values for 'iterations' property if defined for repeat node at depth '${depth}'` @@ -1038,7 +1050,7 @@ function validateRetryNode(definition, depth) { } if (typeof definition.attempts !== "undefined") { if (Array.isArray(definition.attempts)) { - const containsNonInteger = !!definition.attempts.find((value) => !isInteger(value)); + const containsNonInteger = !!definition.attempts.filter((value) => !isInteger(value)).length; if (definition.attempts.length !== 2 || containsNonInteger) { throw new Error( `expected array containing two integer values for 'attempts' property if defined for retry node at depth '${depth}'` @@ -1121,7 +1133,7 @@ function validateWaitNode(definition, depth) { } if (typeof definition.duration !== "undefined") { if (Array.isArray(definition.duration)) { - const containsNonInteger = !!definition.duration.find((value) => !isInteger(value)); + const containsNonInteger = !!definition.duration.filter((value) => !isInteger(value)).length; if (definition.duration.length !== 2 || containsNonInteger) { throw new Error( `expected array containing two integer values for 'duration' property if defined for wait node at depth '${depth}'` @@ -1181,6 +1193,23 @@ function validateParallelNode(definition, depth) { validateNodeAttributes(definition, depth); definition.children.forEach((child) => validateNode(child, depth + 1)); } +function validateLottoNode(definition, depth) { + if (definition.type !== "lotto") { + throw new Error(`expected node type of 'lotto' for lotto node at depth '${depth}'`); + } + if (!Array.isArray(definition.children) || definition.children.length === 0) { + throw new Error(`expected non-empty 'children' array to be defined for lotto node at depth '${depth}'`); + } + if (typeof definition.weights !== "undefined") { + if (!Array.isArray(definition.weights) || definition.weights.length !== definition.children.length || definition.weights.filter((value) => !isInteger(value)).length || definition.weights.filter((value) => value < 0).length) { + throw new Error( + `expected an array of positive integer weight values with a length matching the number of child nodes for 'weights' property if defined for lotto node at depth '${depth}'` + ); + } + } + validateNodeAttributes(definition, depth); + definition.children.forEach((child) => validateNode(child, depth + 1)); +} function createValidationFailureResult(errorMessage) { return { succeeded: false, errorMessage }; } diff --git a/dist/index.js.map b/dist/index.js.map index 3d56922..7828819 100644 --- a/dist/index.js.map +++ b/dist/index.js.map @@ -1,7 +1,7 @@ { "version": 3, "sources": ["../node_modules/lotto-draw/dist/Participant.js", "../node_modules/lotto-draw/dist/Utilities.js", "../node_modules/lotto-draw/dist/Lotto.js", "../node_modules/lotto-draw/dist/createLotto.js", "../node_modules/lotto-draw/dist/index.js", "../src/index.ts", "../src/State.ts", "../src/BehaviourTreeDefinitionUtilities.ts", "../src/mdsl/MDSLUtilities.ts", "../src/mdsl/MDSLNodeArgumentParser.ts", "../src/mdsl/MDSLNodeAttributeParser.ts", "../src/mdsl/MDSLDefinitionParser.ts", "../src/BehaviourTreeDefinitionValidator.ts", "../src/Lookup.ts", "../src/attributes/guards/GuardUnsatisifedException.ts", "../src/attributes/guards/GuardPath.ts", "../src/nodes/Node.ts", "../src/nodes/composite/Composite.ts", "../src/nodes/composite/Parallel.ts", "../src/nodes/composite/Selector.ts", "../src/nodes/composite/Sequence.ts", "../src/nodes/composite/Lotto.ts", "../src/nodes/decorator/Decorator.ts", "../src/nodes/decorator/Fail.ts", "../src/nodes/decorator/Flip.ts", "../src/nodes/decorator/Repeat.ts", "../src/nodes/decorator/Retry.ts", "../src/nodes/decorator/Root.ts", "../src/nodes/decorator/Succeed.ts", "../src/nodes/leaf/Leaf.ts", "../src/nodes/leaf/Action.ts", "../src/nodes/leaf/Condition.ts", "../src/nodes/leaf/Wait.ts", "../src/attributes/Attribute.ts", "../src/attributes/guards/Guard.ts", "../src/attributes/guards/While.ts", "../src/attributes/guards/Until.ts", "../src/attributes/callbacks/Callback.ts", "../src/attributes/callbacks/Entry.ts", "../src/attributes/callbacks/Step.ts", "../src/attributes/callbacks/Exit.ts", "../src/BehaviourTreeBuilder.ts", "../src/BehaviourTree.ts"], - "sourcesContent": ["\"use strict\";\r\nObject.defineProperty(exports, \"__esModule\", { value: true });\r\nexports.Participant = void 0;\r\n/**\r\n * A participant that holds a number of tickets.\r\n */\r\nvar Participant = /** @class */ (function () {\r\n /**\r\n * Creates an instance of the Participant class.\r\n * @param participant The actual participant.\r\n * @param tickets The number of tickets held by the participant.\r\n */\r\n function Participant(participant, tickets) {\r\n if (tickets === void 0) { tickets = 1; }\r\n this._participant = participant;\r\n this._tickets = tickets;\r\n }\r\n Object.defineProperty(Participant.prototype, \"participant\", {\r\n /** Gets the actual participant. */\r\n get: function () {\r\n return this._participant;\r\n },\r\n enumerable: false,\r\n configurable: true\r\n });\r\n Object.defineProperty(Participant.prototype, \"tickets\", {\r\n /** Gets or sets the number of tickets held by the participant. */\r\n get: function () {\r\n return this._tickets;\r\n },\r\n set: function (value) {\r\n this._tickets = value;\r\n },\r\n enumerable: false,\r\n configurable: true\r\n });\r\n return Participant;\r\n}());\r\nexports.Participant = Participant;\r\n", "\"use strict\";\r\nObject.defineProperty(exports, \"__esModule\", { value: true });\r\nexports.isNaturalNumber = exports.isNullOrUndefined = void 0;\r\n/**\r\n * Gets whether the value provided is null or undefined.\r\n * @param value The value to check.\r\n * @returns Whether the value provided is null or undefined.\r\n */\r\nfunction isNullOrUndefined(value) {\r\n return value === null || value === undefined;\r\n}\r\nexports.isNullOrUndefined = isNullOrUndefined;\r\n/**\r\n * Gets whether the value provided is a natural number.\r\n * @param value The value to check.\r\n * @returns Whether the value provided is a natural number.\r\n */\r\nfunction isNaturalNumber(value) {\r\n return typeof value === \"number\" && value >= 1 && Math.floor(value) === value;\r\n}\r\nexports.isNaturalNumber = isNaturalNumber;\r\n", "\"use strict\";\r\nObject.defineProperty(exports, \"__esModule\", { value: true });\r\nexports.Lotto = void 0;\r\nvar Participant_1 = require(\"./Participant\");\r\nvar Utilities_1 = require(\"./Utilities\");\r\n/**\r\n * Represents a lotto consisting of a number of pickable ticket-holding participants.\r\n */\r\nvar Lotto = /** @class */ (function () {\r\n /**\r\n * Creates a new instance of Lotto.\r\n * @param customRandom The custom RNG to use in place of Math.random().\r\n */\r\n function Lotto(customRandom) {\r\n /** The array of participants that are holding tickets in the lotto. */\r\n this._participants = [];\r\n this._customRandom = customRandom;\r\n }\r\n /**\r\n * Adds a participant with the specified number of tickets, or adds to the participant ticket count if the participant already holds tickets.\r\n * @param participant The participant to add or to increase the ticket count for if they already hold tickets.\r\n * @param tickets The number of tickets, defaults to 1.\r\n * @returns The Lotto instance.\r\n */\r\n Lotto.prototype.add = function (participant, tickets) {\r\n if (tickets === void 0) { tickets = 1; }\r\n // Check that we have a valid ticket count.\r\n if (!(0, Utilities_1.isNaturalNumber)(tickets)) {\r\n throw new Error(\"tickets value must be a natural number\");\r\n }\r\n // Check whether this participant has already been added.\r\n var existingParticipant = this._participants.find(function (part) { return part.participant === participant; });\r\n if (existingParticipant) {\r\n // The participant has already been added to the lotto so just add to their ticket count.\r\n existingParticipant.tickets += tickets;\r\n }\r\n else {\r\n // The participant is not part of the lotto so we should add them.\r\n this._participants.push(new Participant_1.Participant(participant, tickets));\r\n }\r\n return this;\r\n };\r\n /**\r\n * Removes the specified number of tickets for the given participant from the draw, or all tickets if a ticket number is not defined.\r\n * @param participant The participant to remove tickets for.\r\n * @param tickets The number of tickets to remove, or undefined if all tickets are to be removed.\r\n * @returns The Lotto instance.\r\n */\r\n Lotto.prototype.remove = function (participant, tickets) {\r\n // Attempt to get the existing participant.\r\n var existingParticipant = this._participants.find(function (part) { return part.participant === participant; });\r\n // There is nothing to do if the specified participant isn't even part of the lotto.\r\n if (!existingParticipant) {\r\n return this;\r\n }\r\n // Check whether a tickets value was given.\r\n if (tickets !== undefined) {\r\n // Check that we have a valid ticket count.\r\n if (!(0, Utilities_1.isNaturalNumber)(tickets)) {\r\n throw new Error(\"tickets value must be a natural number\");\r\n }\r\n existingParticipant.tickets -= tickets;\r\n // If the participant no longer holds any tickets then they should be removed.\r\n if (existingParticipant.tickets < 1) {\r\n this._participants = this._participants.filter(function (part) { return part !== existingParticipant; });\r\n }\r\n }\r\n else {\r\n // We are removing all tickets for the participant so just remove them from the lotto.\r\n this._participants = this._participants.filter(function (part) { return part !== existingParticipant; });\r\n }\r\n return this;\r\n };\r\n /**\r\n * Draw a winning ticket and return the participant that holds the ticket.\r\n * @param options The draw options.\r\n * @returns The participant that holds the winning ticket.\r\n */\r\n Lotto.prototype.draw = function (options) {\r\n if (options === void 0) { options = {}; }\r\n // If we have no participants then just return null.\r\n if (this._participants.length === 0) {\r\n return null;\r\n }\r\n var redrawable = (0, Utilities_1.isNullOrUndefined)(options.redrawable) ? true : options.redrawable;\r\n var pickable = [];\r\n this._participants.forEach(function (_a) {\r\n var participant = _a.participant, tickets = _a.tickets;\r\n for (var ticketCount = 0; ticketCount < tickets; ticketCount++) {\r\n pickable.push(participant);\r\n }\r\n });\r\n var random;\r\n // We need a random floating-point number between 0 (inclusive) and 1 to scale up to pick our winner.\r\n // If a custom random function exists then we should use that or fall back to Math.random().\r\n if (this._customRandom) {\r\n // Call our custom random function to get a random floating-point number.\r\n random = this._customRandom();\r\n // Verify that the result of calling our custom random function is a number between 0 (inclusive) and 1.\r\n if (typeof random !== \"number\" || random < 0 || random >= 1) {\r\n throw new Error(\"the 'random' function provided did not return a number between 0 (inclusive) and 1\");\r\n }\r\n }\r\n else {\r\n // No custom random function was defined so just use good ol' Math.random().\r\n random = Math.random();\r\n }\r\n // Pick a winning participant.\r\n var winner = pickable[Math.floor(random * pickable.length)];\r\n // If the ticket isn't redrawable then we should remove a ticket from the winning participants ticket count.\r\n if (!redrawable) {\r\n this.remove(winner, 1);\r\n }\r\n // Return the winning participant.\r\n return winner;\r\n };\r\n /**\r\n * Draws multiple winning tickets and return an array of the participants that hold the winning tickets.\r\n * @param tickets The number of winning tickets to draw.\r\n * @param options The draw multiple options.\r\n * @returns An array of the participants that hold the winning tickets.\r\n */\r\n Lotto.prototype.drawMultiple = function (tickets, options) {\r\n if (options === void 0) { options = {}; }\r\n var uniqueResults = (0, Utilities_1.isNullOrUndefined)(options.unique) ? false : options.unique;\r\n // Handle cases where the user has asked for zero tickets (no idea why they would do this be we should trust them).\r\n if (tickets === 0) {\r\n return [];\r\n }\r\n // Now that we know out tickets value is not zero we should check that it is a valid natural number.\r\n if (!(0, Utilities_1.isNaturalNumber)(tickets)) {\r\n throw new Error(\"tickets value must be a natural number\");\r\n }\r\n var result = [];\r\n // Keep drawing tickets until we either reach the number of required tickets or we simply run out of tickets to draw.\r\n // We can run out of tickets to draw if 'options.redrawable' is explicity 'false' or we just had no participants when 'drawMultiple' was called.\r\n while (result.length < tickets && this._participants.length > 0) {\r\n result.push(this.draw(options));\r\n }\r\n // If the 'unique' draw option is set then we need to remove duplicates from the result list.\r\n if (uniqueResults) {\r\n // Create an array to store our unique results.\r\n var unique = [];\r\n // Iterate over all of our participants (with potential duplicates) and populate our array of unique values.\r\n for (var _i = 0, result_1 = result; _i < result_1.length; _i++) {\r\n var participant = result_1[_i];\r\n if (unique.indexOf(participant) === -1) {\r\n unique.push(participant);\r\n }\r\n }\r\n result = unique;\r\n }\r\n return result;\r\n };\r\n return Lotto;\r\n}());\r\nexports.Lotto = Lotto;\r\n", "\"use strict\";\r\nObject.defineProperty(exports, \"__esModule\", { value: true });\r\nexports.createLotto = void 0;\r\nvar Lotto_1 = require(\"./Lotto\");\r\n/**\r\n * A function that creates and returns a Lotto instance.\r\n * @param participantsOrOptions An array of initial participants or options relating to the creation of a Lotto instance.\r\n * @returns A new Lotto instance.\r\n */\r\nfunction createLotto(participantsOrOptions) {\r\n // If no initial participants or lotto options were provided as an argument then we can just return a new lotto instance now.\r\n if (!participantsOrOptions) {\r\n return new Lotto_1.Lotto();\r\n }\r\n // Check whether we were provided with an array of initial participants or a lotto options object.\r\n if (Array.isArray(participantsOrOptions)) {\r\n // We are dealing with a pre-defined array of participants.\r\n var participants = participantsOrOptions;\r\n var lotto_1 = new Lotto_1.Lotto();\r\n // If the lotto participants have been defined upfront then we will need to add them all to our lotto instance now.\r\n participants.forEach(function (_a) {\r\n var participant = _a[0], tokens = _a[1];\r\n return lotto_1.add(participant, tokens);\r\n });\r\n // Return the Lotto instance.\r\n return lotto_1;\r\n }\r\n else {\r\n // We are dealing with some lotto options.\r\n var random = participantsOrOptions.random, participants = participantsOrOptions.participants;\r\n // Create a Lotto instance passing the custom RNG function to use in place of Math.random() (which could be undefined).\r\n var lotto_2 = new Lotto_1.Lotto(random);\r\n // If the lotto participants have been defined upfront as part of the options then we will need to add them all to our lotto instance now.\r\n if (participants) {\r\n participants.forEach(function (_a) {\r\n var participant = _a[0], tokens = _a[1];\r\n return lotto_2.add(participant, tokens);\r\n });\r\n }\r\n // Return the Lotto instance.\r\n return lotto_2;\r\n }\r\n}\r\nexports.createLotto = createLotto;\r\n", "\"use strict\";\r\nObject.defineProperty(exports, \"__esModule\", { value: true });\r\nvar createLotto_1 = require(\"./createLotto\");\r\nexports.default = createLotto_1.createLotto;\r\n", "import State from \"./State\";\nimport { validateDefinition } from \"./BehaviourTreeDefinitionValidator\";\nimport { convertMDSLToJSON } from \"./mdsl/MDSLDefinitionParser\";\nimport { BehaviourTree, FlattenedTreeNode } from \"./BehaviourTree\";\nimport { BehaviourTreeOptions } from \"./BehaviourTreeOptions\";\n\nexport { BehaviourTree, State, convertMDSLToJSON, validateDefinition };\nexport type { FlattenedTreeNode, BehaviourTreeOptions };\n", "/**\n * Enumeration of node state types.\n */\nexport enum State {\n READY = \"mistreevous.ready\",\n RUNNING = \"mistreevous.running\",\n SUCCEEDED = \"mistreevous.succeeded\",\n FAILED = \"mistreevous.failed\"\n}\n\nexport { State as default };\n\nexport type CompleteState = State.SUCCEEDED | State.FAILED;\nexport type AnyState = State.READY | State.RUNNING | CompleteState;\n", "import {\n NodeDefinition,\n RootNodeDefinition,\n DecoratorNodeDefinition,\n CompositeNodeDefinition,\n AnyNodeDefinition,\n BranchNodeDefinition\n} from \"./BehaviourTreeDefinition\";\n\n/**\n * A type guard function that returns true if the specified node satisfies the RootNodeDefinition type.\n * @param node The node.\n * @returns A value of true if the specified node satisfies the RootNodeDefinition type.\n */\nexport function isRootNode(node: NodeDefinition): node is RootNodeDefinition {\n return node.type === \"root\";\n}\n\n/**\n * A type guard function that returns true if the specified node satisfies the BranchNodeDefinition type.\n * @param node The node.\n * @returns A value of true if the specified node satisfies the BranchNodeDefinition type.\n */\nexport function isBranchNode(node: NodeDefinition): node is BranchNodeDefinition {\n return node.type === \"branch\";\n}\n\n/**\n * A type guard function that returns true if the specified node satisfies the NodeDefinition type.\n * @param node The node.\n * @returns A value of true if the specified node satisfies the NodeDefinition type.\n */\nexport function isLeafNode(node: NodeDefinition): node is NodeDefinition {\n return [\"branch\", \"action\", \"condition\", \"wait\"].includes(node.type);\n}\n\n/**\n * A type guard function that returns true if the specified node satisfies the DecoratorNodeDefinition type.\n * @param node The node.\n * @returns A value of true if the specified node satisfies the DecoratorNodeDefinition type.\n */\nexport function isDecoratorNode(node: NodeDefinition): node is DecoratorNodeDefinition {\n return [\"root\", \"repeat\", \"retry\", \"flip\", \"succeed\", \"fail\"].includes(node.type);\n}\n\n/**\n * A type guard function that returns true if the specified node satisfies the CompositeNodeDefinition type.\n * @param node The node.\n * @returns A value of true if the specified node satisfies the CompositeNodeDefinition type.\n */\nexport function isCompositeNode(node: NodeDefinition): node is CompositeNodeDefinition {\n return [\"sequence\", \"selector\", \"lotto\", \"parallel\"].includes(node.type);\n}\n\n/**\n * Flatten a node definition into an array of all of its nested node definitions.\n * @param nodeDefinition The node definition to flatten.\n * @returns An array of all of nested node definitions.\n */\nexport function flattenDefinition(nodeDefinition: AnyNodeDefinition): AnyNodeDefinition[] {\n const nodes: AnyNodeDefinition[] = [];\n\n const processNode = (currentNodeDefinition: AnyNodeDefinition) => {\n nodes.push(currentNodeDefinition);\n\n if (isCompositeNode(currentNodeDefinition)) {\n currentNodeDefinition.children.forEach(processNode);\n } else if (isDecoratorNode(currentNodeDefinition)) {\n processNode(currentNodeDefinition.child);\n }\n };\n\n processNode(nodeDefinition);\n\n return nodes;\n}\n\n/**\n * Determines whether the passed value is an integer.\n * @param value The value to check.\n * @returns Whether the passed value is an integer.\n */\nexport function isInteger(value: unknown): boolean {\n return typeof value === \"number\" && Math.floor(value) === value;\n}\n\n/**\n * Determines whether the passed value is null or undefined.\n * @param value The value to check.\n * @returns Whether the passed value is null or undefined.\n */\nexport function isNullOrUndefined(value: unknown): boolean {\n return typeof value === \"undefined\" || value === null;\n}\n", "/**\n * A type defining an object that holds a reference to substitued string literals parsed from the definition.\n */\nexport type StringLiteralPlaceholders = { [key: string]: string };\n\n/**\n * Pop the next raw token from the specified array of tokens and throw an error if it wasn't the expected one.\n * @param tokens The array of tokens.\n * @param expected An optional string or array or items, one of which must match the next popped token.\n * @returns The popped token.\n */\nexport function popAndCheck(tokens: string[], expected?: string | string[]): string {\n // Get and remove the next token.\n const popped = tokens.shift();\n\n // We were expecting another token but there aren't any.\n if (popped === undefined) {\n throw new Error(\"unexpected end of definition\");\n }\n\n // Do we have an expected token/tokens array?\n if (expected != undefined) {\n // Get an array of expected values, if the popped token matches any then we are all good.\n const expectedValues = typeof expected === \"string\" ? [expected] : expected;\n\n // Check whether the popped token matches at least one of our expected items.\n var tokenMatchesExpectation = expectedValues.some((item) => popped.toUpperCase() === item.toUpperCase());\n\n // Throw an error if the popped token didn't match any of our expected items.\n if (!tokenMatchesExpectation) {\n const expectationString = expectedValues.map((item) => \"'\" + item + \"'\").join(\" or \");\n throw new Error(\"unexpected token found. Expected \" + expectationString + \" but got '\" + popped + \"'\");\n }\n }\n\n // Return the popped token.\n return popped;\n}\n\n/**\n * Swaps out any node/attribute argument string literals with placeholders.\n * @param definition The definition.\n * @returns An object containing a mapping of placeholders to original string values as well as the processed definition string.\n */\nexport function substituteStringLiterals(definition: string): {\n placeholders: StringLiteralPlaceholders;\n processedDefinition: string;\n} {\n // Create an object to hold the mapping of placeholders to original string values.\n const placeholders: StringLiteralPlaceholders = {};\n\n // Replace any string literals wrapped with double quotes in our definition with placeholders to be processed later.\n const processedDefinition = definition.replace(/\\\"(\\\\.|[^\"\\\\])*\\\"/g, (match) => {\n var strippedMatch = match.substring(1, match.length - 1);\n var placeholder = Object.keys(placeholders).find((key) => placeholders[key] === strippedMatch);\n\n // If we have no existing string literal match then create a new placeholder.\n if (!placeholder) {\n placeholder = `@@${Object.keys(placeholders).length}@@`;\n placeholders[placeholder] = strippedMatch;\n }\n\n return placeholder;\n });\n\n return { placeholders, processedDefinition };\n}\n\n/**\n * Parse the tree definition into an array of raw tokens.\n * @param definition The definition.\n * @returns An array of tokens parsed from the definition.\n */\nexport function parseTokensFromDefinition(definition: string): string[] {\n // Add some space around various important characters so that they can be plucked out easier as individual tokens.\n definition = definition.replace(/\\(/g, \" ( \");\n definition = definition.replace(/\\)/g, \" ) \");\n definition = definition.replace(/\\{/g, \" { \");\n definition = definition.replace(/\\}/g, \" } \");\n definition = definition.replace(/\\]/g, \" ] \");\n definition = definition.replace(/\\[/g, \" [ \");\n definition = definition.replace(/\\,/g, \" , \");\n\n // Split the definition into raw token form and return it.\n return definition.replace(/\\s+/g, \" \").trim().split(\" \");\n}\n", "import { StringLiteralPlaceholders, popAndCheck } from \"./MDSLUtilities\";\n\n/**\n * A type representing any node function argument.\n */\ntype Argument = {\n /**\n * The argument value.\n */\n value: T;\n /**\n * The argument type, used for validation.\n */\n type: string;\n};\n\ntype NullArgument = Argument & {\n type: \"null\";\n};\n\ntype BooleanArgument = Argument & {\n type: \"boolean\";\n};\n\ntype NumberArgument = Argument & {\n type: \"number\";\n /**\n * A flag defining whether the number argument value is a valid integer. (used for validation)\n */\n isInteger: boolean;\n};\n\ntype StringPlaceholderArgument = Argument & {\n type: \"string\";\n};\n\ntype IdentifierArgument = Argument & {\n type: \"identifier\";\n};\n\n/**\n * A type representing a reference to any node function argument.\n */\ntype AnyArgument = NullArgument | BooleanArgument | NumberArgument | StringPlaceholderArgument | IdentifierArgument;\n\n/**\n * Parse an array of argument definitions from the specified tokens array.\n * @param tokens The array tokens to parse the argument definitions from.\n * @param stringArgumentPlaceholders The mapping of string literal node argument placeholders to original values.\n * @param argumentValidator The argument validator function.\n * @param validationFailedMessage The exception message to throw if argument validation fails.\n * @returns An array of argument definitions parsed from the specified tokens array.\n */\nexport function parseArgumentTokens(\n tokens: string[],\n stringArgumentPlaceholders: StringLiteralPlaceholders\n): AnyArgument[] {\n const argumentList: AnyArgument[] = [];\n\n // If the next token is not a '[' or '(' then we have no arguments to parse.\n if (![\"[\", \"(\"].includes(tokens[0])) {\n return argumentList;\n }\n\n // Any lists of arguments will always be wrapped in '[]' for node arguments or '()' for attribute arguments.\n // We are looking for a '[' or '(' opener that wraps the argument tokens and the relevant closer.\n const closingToken = popAndCheck(tokens, [\"[\", \"(\"]) === \"[\" ? \"]\" : \")\";\n\n const argumentListTokens: string[] = [];\n\n // Grab all tokens between the '[' and ']' or '(' and ')'.\n while (tokens.length && tokens[0] !== closingToken) {\n // The next token is part of our arguments list.\n argumentListTokens.push(tokens.shift()!);\n }\n\n // Validate the order of the argument tokens. Each token must either be a ',' or a single argument that satisfies the validator.\n argumentListTokens.forEach((token, index) => {\n // Get whether this token should be an actual argument.\n const shouldBeArgumentToken = !(index & 1);\n\n // If the current token should be an actual argument then validate it, otherwise it should be a ',' token.\n if (shouldBeArgumentToken) {\n // Get the argument definition.\n const argumentDefinition = getArgumentDefinition(token, stringArgumentPlaceholders);\n\n // This is a valid argument!\n argumentList.push(argumentDefinition);\n } else {\n // The current token should be a ',' token.\n if (token !== \",\") {\n throw new Error(`invalid argument list, expected ',' or ']' but got '${token}'`);\n }\n }\n });\n\n // The arguments list should terminate with a ']' or ')' token, depending on the opener.\n popAndCheck(tokens, closingToken);\n\n // Return the arguments.\n return argumentList;\n}\n\n/**\n * Gets an argument value definition.\n * @param token The argument token.\n * @param stringArgumentPlaceholders The mapping of string literal node argument placeholders to original values.\n * @returns An argument value definition.\n */\nfunction getArgumentDefinition(token: string, stringArgumentPlaceholders: StringLiteralPlaceholders): AnyArgument {\n // Check whether the token represents a null value.\n if (token === \"null\") {\n return {\n value: null,\n type: \"null\"\n } as NullArgument;\n }\n\n // Check whether the token represents a boolean value.\n if (token === \"true\" || token === \"false\") {\n return {\n value: token === \"true\",\n type: \"boolean\"\n } as BooleanArgument;\n }\n\n // Check whether the token represents a number value.\n // TODO: Relies on broken isNaN - see MDN.\n // if (!Number.isNaN(token)) {\n if (!isNaN(token as any)) {\n return {\n value: parseFloat(token),\n isInteger: parseFloat(token) === parseInt(token, 10),\n type: \"number\"\n } as NumberArgument;\n }\n\n // Check whether the token is a placeholder (e.g. @@0@@) representing a string literal.\n if (token.match(/^@@\\d+@@$/g)) {\n return {\n value: stringArgumentPlaceholders[token].replace('\\\\\"', '\"'),\n type: \"string\"\n } as StringPlaceholderArgument;\n }\n\n // The only remaining option is that the argument value is an identifier.\n return {\n value: token,\n type: \"identifier\"\n } as IdentifierArgument;\n}\n", "import { NodeAttributeDefinition } from \"../BehaviourTreeDefinition\";\nimport { parseArgumentTokens } from \"./MDSLNodeArgumentParser\";\nimport { StringLiteralPlaceholders } from \"./MDSLUtilities\";\n\n/**\n * A type defining the attribute definitions of a node.\n */\ntype NodeAttributes = {\n while?: NodeAttributeDefinition;\n until?: NodeAttributeDefinition;\n entry?: NodeAttributeDefinition;\n exit?: NodeAttributeDefinition;\n step?: NodeAttributeDefinition;\n};\n\n/**\n * Parse any node attribute definitions from the specified tokens array.\n * @param tokens The array of remaining tokens.\n * @param stringArgumentPlaceholders The mapping of string literal node argument placeholders to original values.\n * @returns An object of attribute definitions defined by any directly following tokens.\n */\nexport function parseAttributeTokens(\n tokens: string[],\n stringArgumentPlaceholders: StringLiteralPlaceholders\n): NodeAttributes {\n const nodeAttributeNames: (keyof NodeAttributes)[] = [\"while\", \"until\", \"entry\", \"exit\", \"step\"];\n\n // Create an object to hold any attributes found.\n const attributes: NodeAttributes = {};\n\n // Try to get the name of the attribute for the next token.\n let nextAttributeName = tokens[0]?.toLowerCase() as keyof NodeAttributes;\n\n // Pull attribute tokens as well as their arguments off of the tokens stack until we have no more.\n while (nodeAttributeNames.includes(nextAttributeName)) {\n // Check to make sure that we have not already created an attribute definition of this type.\n if (attributes[nextAttributeName]) {\n throw new Error(`duplicate attribute '${tokens[0].toUpperCase()}' found for node`);\n }\n\n // Remove the attribute name token from the array of tokens.\n tokens.shift();\n\n // Grab the attribute arguments, assuming the first to be an identifier.\n const [attributeCallIdentifier, ...attributeArguments] = parseArgumentTokens(\n tokens,\n stringArgumentPlaceholders\n );\n\n // The first attribute argument has to be an identifer, this will reference an agent function.\n if (attributeCallIdentifier?.type !== \"identifier\") {\n throw new Error(\"expected agent function name identifier argument for attribute\");\n }\n\n // Any attribute arguments (other than the expected call identifier) must have a type of string, number, boolean or null.\n attributeArguments\n .filter((arg) => arg.type === \"identifier\")\n .forEach((arg) => {\n throw new Error(\n `invalid attribute argument value '${arg.value}', must be string, number, boolean or null`\n );\n });\n\n // Create the attribute definition and add it to the object of attribute definitions found.\n attributes[nextAttributeName] = {\n call: attributeCallIdentifier.value,\n args: attributeArguments.map(({ value }) => value)\n };\n\n // Try to get the next attribute name token, as there could be multiple.\n nextAttributeName = tokens[0]?.toLowerCase() as keyof NodeAttributes;\n }\n\n return attributes;\n}\n", "import {\n ActionNodeDefinition,\n AnyChildNodeDefinition,\n AnyNodeDefinition,\n BranchNodeDefinition,\n ConditionNodeDefinition,\n FailNodeDefinition,\n FlipNodeDefinition,\n LottoNodeDefinition,\n ParallelNodeDefinition,\n RepeatNodeDefinition,\n RetryNodeDefinition,\n RootNodeDefinition,\n SelectorNodeDefinition,\n SequenceNodeDefinition,\n SucceedNodeDefinition,\n WaitNodeDefinition\n} from \"../BehaviourTreeDefinition\";\nimport {\n isCompositeNode,\n isDecoratorNode,\n isLeafNode,\n isNullOrUndefined,\n isRootNode\n} from \"../BehaviourTreeDefinitionUtilities\";\nimport { parseArgumentTokens } from \"./MDSLNodeArgumentParser\";\nimport { parseAttributeTokens } from \"./MDSLNodeAttributeParser\";\nimport {\n StringLiteralPlaceholders,\n parseTokensFromDefinition,\n popAndCheck,\n substituteStringLiterals\n} from \"./MDSLUtilities\";\n\n/**\n * Convert the MDSL tree definition string into an equivalent JSON definition.\n * @param definition The tree definition string as MDSL.\n * @returns The root node JSON definitions.\n */\nexport function convertMDSLToJSON(definition: string): RootNodeDefinition[] {\n // Swap out any node/attribute argument string literals with a placeholder and get a mapping of placeholders to original values as well as the processed definition.\n const { placeholders, processedDefinition } = substituteStringLiterals(definition);\n\n // Parse our definition definition string into an array of raw tokens.\n const tokens = parseTokensFromDefinition(processedDefinition);\n\n return convertTokensToJSONDefinition(tokens, placeholders);\n}\n\n/**\n * Converts the specified tree definition tokens into a JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The root node JSON definitions.\n */\nfunction convertTokensToJSONDefinition(\n tokens: string[],\n stringLiteralPlaceholders: StringLiteralPlaceholders\n): RootNodeDefinition[] {\n // There must be at least 3 tokens for the tree definition to be valid. 'ROOT', '{' and '}'.\n if (tokens.length < 3) {\n throw new Error(\"invalid token count\");\n }\n\n // We should have a matching number of '{' and '}' tokens. If not, then there are scopes that have not been properly closed.\n if (tokens.filter((token) => token === \"{\").length !== tokens.filter((token) => token === \"}\").length) {\n throw new Error(\"scope character mismatch\");\n }\n\n // Create an array of tree stack arrays where root nodes will always be at the botton and the current composite/decorator node at the top.\n // There should be an element in this array for every root node defined and every element should be an array with a root note as the first element.\n // E.g. A definition with two root nodes defined:\n // [\n // [root, lotto, sequence],\n // [root, selector]\n // ]\n const treeStacks: [Partial, ...Partial[]][] = [];\n\n // Create an array of all root node definitions that we create.\n const rootNodes: Partial[] = [];\n\n // A helper function used to push node definitions onto the tree stack.\n const pushNode = (node: AnyNodeDefinition) => {\n // If the node is a root node then we need to create a new tree stack array with the root node at the root.\n if (isRootNode(node)) {\n // We need to double-check that this root node is not the child of another node.\n // We can do this by checking whether the top tree stack is not empty (contains an existing node)\n if (treeStacks[treeStacks.length - 1]?.length) {\n throw new Error(\"a root node cannot be the child of another node\");\n }\n\n // Add the root node definition to our array of all parsed root node definitions.\n rootNodes.push(node);\n\n // Add the root node definition to the root of a new tree stack.\n treeStacks.push([node]);\n\n return;\n }\n\n // All non-root nodes should be pushed after their root nodes so handle cases\n // where we may not have any tree stacks or our top-most tree stack is empty.\n if (!treeStacks.length || !treeStacks[treeStacks.length - 1].length) {\n throw new Error(\"expected root node at base of definition\");\n }\n\n // Get the current tree stack that we are populating.\n const topTreeStack = treeStacks[treeStacks.length - 1];\n\n // Get the top-most node in the current tree stack, this will be a composite/decorator node\n // for which we will populate its children array if composite or setting its child if a decorator.\n const topTreeStackTopNode = topTreeStack[topTreeStack.length - 1] as AnyNodeDefinition;\n\n // If the top-most node in the current root stack is a composite or decorator\n // node then the current node should be added as a child of the top-most node.\n if (isCompositeNode(topTreeStackTopNode)) {\n topTreeStackTopNode.children = topTreeStackTopNode.children || [];\n topTreeStackTopNode.children.push(node);\n } else if (isDecoratorNode(topTreeStackTopNode)) {\n // If the top node already has a child node set then throw an error as a decorator should only have a single child.\n if (topTreeStackTopNode.child) {\n throw new Error(\"a decorator node must only have a single child node\");\n }\n\n topTreeStackTopNode.child = node;\n }\n\n // If the node we are adding is also a composite or decorator node, then we should push it\n // onto the current tree stack, as subsequent nodes will be added as its child/children.\n if (!isLeafNode(node)) {\n topTreeStack.push(node);\n }\n };\n\n // A helper function used to pop the top-most node definition off of the tree stack and return it.\n const popNode = (): AnyNodeDefinition | null => {\n let poppedNode: AnyNodeDefinition | null = null;\n\n // Get the current tree stack that we are populating.\n const topTreeStack = treeStacks[treeStacks.length - 1];\n\n // Pop the top-most node in the current tree stack if there is one.\n if (topTreeStack.length) {\n poppedNode = topTreeStack.pop() as AnyNodeDefinition;\n }\n\n // We don't want any empty tree stacks in our stack of tree stacks.\n if (!topTreeStack.length) {\n treeStacks.pop();\n }\n\n return poppedNode;\n };\n\n // We should keep processing the raw tokens until we run out of them.\n while (tokens.length) {\n // Grab the next token.\n const token = tokens.shift()!;\n\n // How we create the next node depends on the current raw token value.\n switch (token.toUpperCase()) {\n case \"ROOT\": {\n pushNode(createRootNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"SUCCEED\": {\n pushNode(createSucceedNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"FAIL\": {\n pushNode(createFailNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"FLIP\": {\n pushNode(createFlipNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"REPEAT\": {\n pushNode(createRepeatNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"RETRY\": {\n pushNode(createRetryNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"SEQUENCE\": {\n pushNode(createSequenceNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"SELECTOR\": {\n pushNode(createSelectorNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"PARALLEL\": {\n pushNode(createParallelNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"LOTTO\": {\n pushNode(createLottoNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"ACTION\": {\n pushNode(createActionNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"CONDITION\": {\n pushNode(createConditionNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"WAIT\": {\n pushNode(createWaitNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"BRANCH\": {\n pushNode(createBranchNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"}\": {\n // The '}' character closes the current scope and means that we have to pop a node off of the current stack.\n const poppedNode = popNode();\n\n // Now that we have a node definition we can carry out any validation that may require the node to be fully populated.\n if (poppedNode) {\n validatePoppedNode(poppedNode);\n }\n\n break;\n }\n\n default: {\n throw new Error(`unexpected token: ${token}`);\n }\n }\n }\n\n return rootNodes as RootNodeDefinition[];\n}\n\n/**\n * Creates a root node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The root node JSON definition.\n */\nfunction createRootNode(tokens: string[], stringLiteralPlaceholders: StringLiteralPlaceholders): RootNodeDefinition {\n // Create the root node definition.\n let node = {\n type: \"root\",\n id: undefined\n } as RootNodeDefinition;\n\n // Parse any node arguments, we should only have one if any which will be an identifier argument for the root identifier.\n const nodeArguments = parseArgumentTokens(tokens, stringLiteralPlaceholders);\n\n // Check whether any node arguments were defined.\n if (nodeArguments.length) {\n // We should only have one argument, if any, which will be an identifier argument for the root identifier.\n if (nodeArguments.length === 1 && nodeArguments[0].type === \"identifier\") {\n // The root node identifier will be the first and only node argument value.\n node.id = nodeArguments[0].value as string;\n } else {\n throw new Error(\"expected single root name argument\");\n }\n }\n\n // Grab any node attribute definitions and spread them into the node definition.\n node = { ...node, ...parseAttributeTokens(tokens, stringLiteralPlaceholders) };\n\n // This is a decorator node, so we expect an opening '{'.\n popAndCheck(tokens, \"{\");\n\n // Return the root node definition.\n return node;\n}\n\n/**\n * Creates a succeed node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The succeed node JSON definition.\n */\nfunction createSucceedNode(\n tokens: string[],\n stringLiteralPlaceholders: StringLiteralPlaceholders\n): SucceedNodeDefinition {\n const node = {\n type: \"succeed\",\n ...parseAttributeTokens(tokens, stringLiteralPlaceholders)\n } as SucceedNodeDefinition;\n\n // This is a decorator node, so we expect an opening '{'.\n popAndCheck(tokens, \"{\");\n\n // Return the succeed node definition.\n return node;\n}\n\n/**\n * Creates a fail node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The fail node JSON definition.\n */\nfunction createFailNode(tokens: string[], stringLiteralPlaceholders: StringLiteralPlaceholders): FailNodeDefinition {\n const node = {\n type: \"fail\",\n ...parseAttributeTokens(tokens, stringLiteralPlaceholders)\n } as FailNodeDefinition;\n\n // This is a decorator node, so we expect an opening '{'.\n popAndCheck(tokens, \"{\");\n\n // Return the fail node definition.\n return node;\n}\n\n/**\n * Creates a flip node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The flip node JSON definition.\n */\nfunction createFlipNode(tokens: string[], stringLiteralPlaceholders: StringLiteralPlaceholders): FlipNodeDefinition {\n const node = {\n type: \"flip\",\n ...parseAttributeTokens(tokens, stringLiteralPlaceholders)\n } as FlipNodeDefinition;\n\n // This is a decorator node, so we expect an opening '{'.\n popAndCheck(tokens, \"{\");\n\n // Return the flip node definition.\n return node;\n}\n\n/**\n * Creates a repeat node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The repeat node JSON definition.\n */\nfunction createRepeatNode(\n tokens: string[],\n stringLiteralPlaceholders: StringLiteralPlaceholders\n): RepeatNodeDefinition {\n let node = { type: \"repeat\" } as RepeatNodeDefinition;\n\n // Get the node arguments.\n const nodeArguments = parseArgumentTokens(tokens, stringLiteralPlaceholders);\n\n // The arguments of a repeat node are optional. We may have:\n // - No node arguments, in which case the repeat note will iterate indefinitely.\n // - One node argument which will be the explicit number of iterations to make.\n // - Two node arguments which define the min and max iteration bounds from which a random iteration count will be picked.\n if (nodeArguments.length) {\n // All repeat node arguments MUST be of type number and must be integer.\n nodeArguments\n .filter((arg) => arg.type !== \"number\" || !arg.isInteger)\n .forEach(() => {\n throw new Error(`repeat node iteration counts must be integer values`);\n });\n\n // We should have got one or two iteration counts.\n if (nodeArguments.length === 1) {\n // A static iteration count was defined.\n node.iterations = nodeArguments[0].value as number;\n\n // A repeat node must have a positive number of iterations if defined.\n if (node.iterations < 0) {\n throw new Error(\"a repeat node must have a positive number of iterations if defined\");\n }\n } else if (nodeArguments.length === 2) {\n // A minimum and maximum iteration count was defined.\n node.iterations = [nodeArguments[0].value as number, nodeArguments[1].value as number];\n\n // A repeat node must have a positive min and max iteration count if they are defined.\n if (node.iterations[0] < 0 || node.iterations[1] < 0) {\n throw new Error(\"a repeat node must have a positive minimum and maximum iteration count if defined\");\n }\n\n // A repeat node must not have an minimum iteration count that exceeds the maximum iteration count.\n if (node.iterations[0] > node.iterations[1]) {\n throw new Error(\n \"a repeat node must not have a minimum iteration count that exceeds the maximum iteration count\"\n );\n }\n } else {\n // An incorrect number of iteration counts was defined.\n throw new Error(\"invalid number of repeat node iteration count arguments defined\");\n }\n }\n\n // Grab any node attribute definitions and spread them into the node definition.\n node = { ...node, ...parseAttributeTokens(tokens, stringLiteralPlaceholders) };\n\n // This is a decorator node, so we expect an opening '{'.\n popAndCheck(tokens, \"{\");\n\n // Return the repeat node definition.\n return node;\n}\n\n/**\n * Creates a retry node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The retry node JSON definition.\n */\nfunction createRetryNode(tokens: string[], stringLiteralPlaceholders: StringLiteralPlaceholders): RetryNodeDefinition {\n let node = { type: \"retry\" } as RetryNodeDefinition;\n\n // Get the node arguments.\n const nodeArguments = parseArgumentTokens(tokens, stringLiteralPlaceholders);\n\n // The arguments of a retry node are optional. We may have:\n // - No node arguments, in which case the retry note will attempt indefinitely.\n // - One node argument which will be the explicit number of attempts to make.\n // - Two node arguments which define the min and max attempt bounds from which a random attempt count will be picked.\n if (nodeArguments.length) {\n // All retry node arguments MUST be of type number and must be integer.\n nodeArguments\n .filter((arg) => arg.type !== \"number\" || !arg.isInteger)\n .forEach(() => {\n throw new Error(`retry node attempt counts must be integer values`);\n });\n\n // We should have got one or two attempt counts.\n if (nodeArguments.length === 1) {\n // A static attempt count was defined.\n node.attempts = nodeArguments[0].value as number;\n\n // A retry node must have a positive number of attempts if defined.\n if (node.attempts < 0) {\n throw new Error(\"a retry node must have a positive number of attempts if defined\");\n }\n } else if (nodeArguments.length === 2) {\n // A minimum and maximum attempt count was defined.\n node.attempts = [nodeArguments[0].value as number, nodeArguments[1].value as number];\n\n // A retry node must have a positive min and max attempts count if they are defined.\n if (node.attempts[0] < 0 || node.attempts[1] < 0) {\n throw new Error(\"a retry node must have a positive minimum and maximum attempt count if defined\");\n }\n\n // A retry node must not have a minimum attempt count that exceeds the maximum attempt count.\n if (node.attempts[0] > node.attempts[1]) {\n throw new Error(\n \"a retry node must not have a minimum attempt count that exceeds the maximum attempt count\"\n );\n }\n } else {\n // An incorrect number of attempt counts was defined.\n throw new Error(\"invalid number of retry node attempt count arguments defined\");\n }\n }\n\n // Grab any node attribute definitions and spread them into the node definition.\n node = { ...node, ...parseAttributeTokens(tokens, stringLiteralPlaceholders) };\n\n // This is a decorator node, so we expect an opening '{'.\n popAndCheck(tokens, \"{\");\n\n // Return the retry node definition.\n return node;\n}\n\n/**\n * Creates a sequence node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The sequence node JSON definition.\n */\nfunction createSequenceNode(\n tokens: string[],\n stringLiteralPlaceholders: StringLiteralPlaceholders\n): SequenceNodeDefinition {\n const node = {\n type: \"sequence\",\n ...parseAttributeTokens(tokens, stringLiteralPlaceholders)\n } as SequenceNodeDefinition;\n\n // This is a composite node, so we expect an opening '{'.\n popAndCheck(tokens, \"{\");\n\n // Return the sequence node definition.\n return node;\n}\n\n/**\n * Creates a selector node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The selector node JSON definition.\n */\nfunction createSelectorNode(\n tokens: string[],\n stringLiteralPlaceholders: StringLiteralPlaceholders\n): SelectorNodeDefinition {\n const node = {\n type: \"selector\",\n ...parseAttributeTokens(tokens, stringLiteralPlaceholders)\n } as SelectorNodeDefinition;\n\n // This is a composite node, so we expect an opening '{'.\n popAndCheck(tokens, \"{\");\n\n // Return the selector node definition.\n return node;\n}\n\n/**\n * Creates a parallel node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The parallel node JSON definition.\n */\nfunction createParallelNode(\n tokens: string[],\n stringLiteralPlaceholders: StringLiteralPlaceholders\n): ParallelNodeDefinition {\n const node = {\n type: \"parallel\",\n ...parseAttributeTokens(tokens, stringLiteralPlaceholders)\n } as ParallelNodeDefinition;\n\n // This is a composite node, so we expect an opening '{'.\n popAndCheck(tokens, \"{\");\n\n // Return the parallel node definition.\n return node;\n}\n\n/**\n * Creates a lotto node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The lotto node JSON definition.\n */\nfunction createLottoNode(tokens: string[], stringLiteralPlaceholders: StringLiteralPlaceholders): LottoNodeDefinition {\n // If any node arguments have been defined then they must be our weights.\n const nodeArguments = parseArgumentTokens(tokens, stringLiteralPlaceholders);\n\n // All lotto node arguments MUST be of type number and must be integer.\n nodeArguments\n .filter((arg) => arg.type !== \"number\" || !arg.isInteger)\n .forEach(() => {\n throw new Error(`lotto node weight arguments must be integer values`);\n });\n\n const node = {\n type: \"lotto\",\n weights: nodeArguments.map(({ value }) => value),\n ...parseAttributeTokens(tokens, stringLiteralPlaceholders)\n } as LottoNodeDefinition;\n\n // This is a composite node, so we expect an opening '{'.\n popAndCheck(tokens, \"{\");\n\n // Return the lotto node definition.\n return node;\n}\n\n/**\n * Creates an action node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The action node JSON definition.\n */\nfunction createActionNode(\n tokens: string[],\n stringLiteralPlaceholders: StringLiteralPlaceholders\n): ActionNodeDefinition {\n // Parse any node arguments, we should have at least one which will be an identifier argument for the action name\n // and agent function to invoke for the action, all other arguments are to be passed as arguments to that function.\n const [actionNameIdentifier, ...agentFunctionArgs] = parseArgumentTokens(tokens, stringLiteralPlaceholders);\n\n // Our first argument MUST be defined and be an identifier as we require an action name argument.\n if (actionNameIdentifier?.type !== \"identifier\") {\n throw new Error(\"expected action name identifier argument\");\n }\n\n // Only the first argument should have been an identifier, all agent function arguments must be string, number, boolean or null.\n agentFunctionArgs\n .filter((arg) => arg.type === \"identifier\")\n .forEach((arg) => {\n throw new Error(\n `invalid action node argument value '${arg.value}', must be string, number, boolean or null`\n );\n });\n\n // Return the action node definition.\n return {\n type: \"action\",\n call: actionNameIdentifier.value,\n args: agentFunctionArgs.map(({ value }) => value),\n ...parseAttributeTokens(tokens, stringLiteralPlaceholders)\n };\n}\n\n/**\n * Creates a condition node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The condition node JSON definition.\n */\nfunction createConditionNode(\n tokens: string[],\n stringLiteralPlaceholders: StringLiteralPlaceholders\n): ConditionNodeDefinition {\n // Parse any node arguments, we should have at least one which will be an identifier argument for the condition name\n // and agent function to invoke for the condition, all other arguments are to be passed as arguments to that function.\n const [conditionNameIdentifier, ...agentFunctionArgs] = parseArgumentTokens(tokens, stringLiteralPlaceholders);\n\n // Our first argument MUST be defined and be an identifier as we require a condition name argument.\n if (conditionNameIdentifier?.type !== \"identifier\") {\n throw new Error(\"expected condition name identifier argument\");\n }\n\n // Only the first argument should have been an identifier, all agent function arguments must be string, number, boolean or null.\n agentFunctionArgs\n .filter((arg) => arg.type === \"identifier\")\n .forEach((arg) => {\n throw new Error(\n `invalid condition node argument value '${arg.value}', must be string, number, boolean or null`\n );\n });\n\n // Return the condition node definition.\n return {\n type: \"condition\",\n call: conditionNameIdentifier.value,\n args: agentFunctionArgs.map(({ value }) => value),\n ...parseAttributeTokens(tokens, stringLiteralPlaceholders)\n };\n}\n\n/**\n * Creates a wait node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The wait node JSON definition.\n */\nfunction createWaitNode(tokens: string[], stringLiteralPlaceholders: StringLiteralPlaceholders): WaitNodeDefinition {\n let node = { type: \"wait\" } as WaitNodeDefinition;\n\n // Get the node arguments.\n const nodeArguments = parseArgumentTokens(tokens, stringLiteralPlaceholders);\n\n // The arguments of a wait node are optional. We may have:\n // - No node arguments, in which case the wait will be indefinite until it is aborted.\n // - One node argument which will be the explicit duration of the wait.\n // - Two node arguments which define the min and max duration bounds from which a random duration will be picked.\n if (nodeArguments.length) {\n // All wait node arguments MUST be of type number and must be integer.\n nodeArguments\n .filter((arg) => arg.type !== \"number\" || !arg.isInteger)\n .forEach(() => {\n throw new Error(`wait node durations must be integer values`);\n });\n\n // We may have:\n // - One node argument which will be the explicit duration of the wait.\n // - Two node arguments which define the min and max duration bounds from which a random duration will be picked.\n // - Too many arguments, which is not valid.\n if (nodeArguments.length === 1) {\n // An explicit duration was defined.\n node.duration = nodeArguments[0].value as number;\n\n // If an explict duration was defined then it must be a positive number.\n if (node.duration < 0) {\n throw new Error(\"a wait node must have a positive duration\");\n }\n } else if (nodeArguments.length === 2) {\n // Min and max duration bounds were defined from which a random duration will be picked.\n node.duration = [nodeArguments[0].value as number, nodeArguments[1].value as number];\n\n // A wait node must have a positive min and max duration.\n if (node.duration[0] < 0 || node.duration[1] < 0) {\n throw new Error(\"a wait node must have a positive minimum and maximum duration\");\n }\n\n // A wait node must not have a minimum duration that exceeds the maximum duration.\n if (node.duration[0] > node.duration[1]) {\n throw new Error(\"a wait node must not have a minimum duration that exceeds the maximum duration\");\n }\n } else if (nodeArguments.length > 2) {\n // An incorrect number of duration arguments were defined.\n throw new Error(\"invalid number of wait node duration arguments defined\");\n }\n }\n\n // Return the wait node definition.\n return { ...node, ...parseAttributeTokens(tokens, stringLiteralPlaceholders) };\n}\n\n/**\n * Creates a branch node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The branch node JSON definition.\n */\nfunction createBranchNode(\n tokens: string[],\n stringLiteralPlaceholders: StringLiteralPlaceholders\n): BranchNodeDefinition {\n // Parse any node arguments, we should have one which will be an identifier argument for the root ref.\n const nodeArguments = parseArgumentTokens(tokens, stringLiteralPlaceholders);\n\n // We should have only a single identifer argument for a branch node, which is the root ref.\n if (nodeArguments.length !== 1 || nodeArguments[0].type !== \"identifier\") {\n throw new Error(\"expected single branch name argument\");\n }\n\n // Return the branch node definition.\n return { type: \"branch\", ref: nodeArguments[0].value };\n}\n\n/**\n * Validate a fully-populated node definition that was popped off of the tree stack.\n * @param node The popped node to validate.\n */\nfunction validatePoppedNode(node: AnyNodeDefinition): void {\n // Decorators MUST have a child defined.\n if (isDecoratorNode(node) && isNullOrUndefined(node.child)) {\n throw new Error(`a ${node.type} node must have a single child node defined`);\n }\n\n // Composites MUST have at least one child defined.\n if (isCompositeNode(node) && !node.children?.length) {\n throw new Error(`a ${node.type} node must have at least a single child node defined`);\n }\n}\n", "import { RootNodeDefinition } from \"./BehaviourTreeDefinition\";\nimport { flattenDefinition, isBranchNode, isInteger } from \"./BehaviourTreeDefinitionUtilities\";\nimport { convertMDSLToJSON } from \"./mdsl/MDSLDefinitionParser\";\n\n/**\n * An object representing the result of validating a tree definition.\n */\nexport type DefinitionValidationResult = {\n /**\n * A flag defining whether validation succeeded.\n */\n succeeded: boolean;\n /**\n * A string containing the error message if validation did not succeed.\n */\n errorMessage?: string;\n};\n\n/**\n * Validates the specified behaviour tree definition in the form of JSON or MDSL, not taking any globally registered subtrees into consideration.\n * @param definition The behaviour tree definition in the form of JSON or MDSL.\n * @returns An object representing the result of validating the given tree definition.\n */\nexport function validateDefinition(definition: any): DefinitionValidationResult {\n // The definition must be defined.\n if (definition === null || typeof definition === \"undefined\") {\n return createValidationFailureResult(\"definition is null or undefined\");\n }\n\n // We are expecting a definition in one of three different forms:\n // - A string which we will assume is MDSL and we will parse this to JSON before validation.\n // - An array which we will assume is an array of root node definitions with at least one being the primary root node (no 'id' property)\n // - An object which we will assume is the primary root node and should not have an 'id' property.\n if (typeof definition === \"string\") {\n // The definition is a string which we can assume is MDSL, so attempt to validate it.\n return validateMDSLDefinition(definition);\n } else if (typeof definition === \"object\") {\n // The definition will either be an array (of root node definitions) or an object (the single primary root node definition).\n return validateJSONDefinition(definition);\n } else {\n return createValidationFailureResult(`unexpected definition type of '${typeof definition}'`);\n }\n}\n\n/**\n * Validates the specified behaviour tree definition in the form of MDSL.\n * @param definition The behaviour tree definition in the form of MDSL.\n * @returns An object representing the result of validating the given tree definition.\n */\nexport function validateMDSLDefinition(definition: string): DefinitionValidationResult {\n let rootNodeDefinitions;\n\n // The first thing the we need to do is to attempt to convert our MDSL into JSON.\n try {\n // The definition is a string which we can assume is MDSL, so attempt to parse it to a JSON definition in the form of an array of root node definitions.\n rootNodeDefinitions = convertMDSLToJSON(definition);\n } catch (exception) {\n // We failed to parse the JSON from the MDSL, this is likely to be the result of it not being a valid MDSL string.\n return createValidationFailureResult((exception as Error).message);\n }\n\n // Unpack all of the root node definitions into arrays of main ('id' defined) and sub ('id' not defined) root node definitions.\n const mainRootNodeDefinitions = rootNodeDefinitions.filter(({ id }) => typeof id === \"undefined\");\n const subRootNodeDefinitions = rootNodeDefinitions.filter(({ id }) => typeof id === \"string\" && id.length > 0);\n\n // We should ALWAYS have exactly one root node definition without an 'id' property defined, which is out main root node definition.\n if (mainRootNodeDefinitions.length !== 1) {\n return createValidationFailureResult(\n \"expected single unnamed root node at base of definition to act as main root\"\n );\n }\n\n // We should never have duplicate 'id' properties across our sub root node definitions.\n const subRootNodeIdenitifers: string[] = [];\n for (const { id } of subRootNodeDefinitions) {\n // Have we already come across this 'id' property value?\n if (subRootNodeIdenitifers.includes(id!)) {\n return createValidationFailureResult(`multiple root nodes found with duplicate name '${id}'`);\n }\n\n subRootNodeIdenitifers.push(id!);\n }\n\n try {\n // Validate our branch -> subtree links and check for any circular dependencies, we don't care about checking for broken subtree links here.\n validateBranchSubtreeLinks(rootNodeDefinitions, false);\n } catch (exception) {\n return createValidationFailureResult((exception as Error).message);\n }\n\n // Our definition was valid!\n return { succeeded: true };\n}\n\n/**\n * Validates the specified behaviour tree definition in the form of JSON.\n * @param definition The behaviour tree definition in the form of JSON.\n * @returns An object representing the result of validating the given tree definition.\n */\nexport function validateJSONDefinition(\n definition: RootNodeDefinition | RootNodeDefinition[]\n): DefinitionValidationResult {\n // The definition will either be an array (of root node definitions) or an object (the single primary root node definition).\n const rootNodeDefinitions = Array.isArray(definition) ? definition : [definition];\n\n // Iterate over our array of root nodes and call validateNode for each, passing an initial depth of 0, wrapped in a try catch to handle validation failures.\n try {\n rootNodeDefinitions.forEach((rootNodeDefinition) => validateNode(rootNodeDefinition, 0));\n } catch (error) {\n // Handle cases where we have caught a thrown Error and return a failure result with the error message.\n if (error instanceof Error) {\n return createValidationFailureResult(error.message);\n }\n\n // No idea what happened here!\n return createValidationFailureResult(`unexpected error: ${error}`);\n }\n\n // Unpack all of the root node definitions into arrays of main ('id' defined) and sub ('id' not defined) root node definitions.\n const mainRootNodeDefinitions = rootNodeDefinitions.filter(({ id }) => typeof id === \"undefined\");\n const subRootNodeDefinitions = rootNodeDefinitions.filter(({ id }) => typeof id === \"string\" && id.length > 0);\n\n // We should ALWAYS have exactly one root node definition without an 'id' property defined, which is out main root node definition.\n if (mainRootNodeDefinitions.length !== 1) {\n return createValidationFailureResult(\n \"expected single root node without 'id' property defined to act as main root\"\n );\n }\n\n // We should never have duplicate 'id' properties across our sub root node definitions.\n const subRootNodeIdenitifers: string[] = [];\n for (const { id } of subRootNodeDefinitions) {\n // Have we already come across this 'id' property value?\n if (subRootNodeIdenitifers.includes(id!)) {\n return createValidationFailureResult(\n `multiple root nodes found with duplicate 'id' property value of '${id}'`\n );\n }\n\n subRootNodeIdenitifers.push(id!);\n }\n\n try {\n // Validate our branch -> subtree links and check for any circular dependencies, we don't care about checking for broken subtree links here.\n validateBranchSubtreeLinks(rootNodeDefinitions, false);\n } catch (exception) {\n return createValidationFailureResult((exception as Error).message);\n }\n\n // Our definition was valid!\n return { succeeded: true };\n}\n\n/**\n * Validates the branch -> subtree links across all provided root node definitions.\n * This will not consider branch nodes that reference any globally registered subtrees unless includesGlobalSubtrees\n * is set to true, in which case we will also verify that there are no broken branch -> subtree links.\n * @param rootNodeDefinitions The array of root node definitions.\n * @param includesGlobalSubtrees A flag defining whether the array includes all global subtree root node definitions.\n */\nexport function validateBranchSubtreeLinks(rootNodeDefinitions: RootNodeDefinition[], includesGlobalSubtrees: boolean) {\n // Create a mapping of root node identifiers to other root nodes that they reference via branch nodes.\n // Below is an example of a mapping that includes a circular dependency (root => a => b => c => a)\n // [{ refs: [\"a\", \"b\"] }, { id: \"a\", refs: [\"b\"] }, { id: \"b\", refs: [\"c\"] }, { id: \"c\", refs: [\"a\"] }]\n const rootNodeMappings: { id: string | undefined; refs: string[] }[] = rootNodeDefinitions.map(\n (rootNodeDefinition) => ({\n id: rootNodeDefinition.id,\n refs: flattenDefinition(rootNodeDefinition)\n .filter(isBranchNode)\n .map(({ ref }) => ref)\n })\n );\n\n // A recursive function to walk through the mappings, keeping track of which root nodes we have visited in the form of a path of root node identifiers.\n const followRefs = (mapping: { id: string | undefined; refs: string[] }, path: (string | undefined)[] = []) => {\n // Have we found a circular dependency?\n if (path.includes(mapping.id)) {\n // We found a circular dependency! Get the bad path of root node identifiers.\n const badPath = [...path, mapping.id];\n\n // Create the formatted path value. [undefined, \"a\", \"b\", \"c\", \"a\"] would be formatted as \"a -> b -> c -> a\".\n const badPathFormatted = badPath.filter((element) => !!element).join(\" => \");\n\n // No need to continue, we found a circular dependency.\n throw new Error(`circular dependency found in branch node references: ${badPathFormatted}`);\n }\n\n for (const ref of mapping.refs) {\n // Find the mapping for the root node with an identifer matching the current ref.\n const subMapping = rootNodeMappings.find(({ id }) => id === ref);\n\n // We may not have a mapping for this ref, which is normal when we aren't considering all globally registered subtrees.\n if (subMapping) {\n followRefs(subMapping, [...path, mapping.id]);\n } else if (includesGlobalSubtrees) {\n // We found a reference to a root node that doesn't exist, which is a problem seeing as the root node definitons includes all globally registered subtrees.\n throw new Error(\n mapping.id\n ? `subtree '${mapping.id}' has branch node that references root node '${ref}' which has not been defined`\n : `primary tree has branch node that references root node '${ref}' which has not been defined`\n );\n }\n }\n };\n\n // Start looking for circular dependencies and broken references from the primary root node definition.\n followRefs(rootNodeMappings.find((mapping) => typeof mapping.id === \"undefined\")!);\n}\n\n/**\n * Validate an object that we expect to be a node definition.\n * @param definition An object that we expect to be a node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateNode(definition: any, depth: number): void {\n // Every node must be valid object and have a non-empty 'type' string property.\n if (typeof definition !== \"object\" || typeof definition.type !== \"string\" || definition.type.length === 0) {\n throw new Error(\n `node definition is not an object or 'type' property is not a non-empty string at depth '${depth}'`\n );\n }\n\n // How we validate this node definition will depend on its type.\n switch (definition.type) {\n case \"action\":\n validateActionNode(definition, depth);\n break;\n\n case \"condition\":\n validateConditionNode(definition, depth);\n break;\n\n case \"wait\":\n validateWaitNode(definition, depth);\n break;\n\n case \"branch\":\n validateBranchNode(definition, depth);\n break;\n\n case \"root\":\n validateRootNode(definition, depth);\n break;\n\n case \"success\":\n validateSuccessNode(definition, depth);\n break;\n\n case \"fail\":\n validateFailNode(definition, depth);\n break;\n\n case \"flip\":\n validateFlipNode(definition, depth);\n break;\n\n case \"repeat\":\n validateRepeatNode(definition, depth);\n break;\n\n case \"retry\":\n validateRetryNode(definition, depth);\n break;\n\n case \"sequence\":\n validateSequenceNode(definition, depth);\n break;\n\n case \"selector\":\n validateSelectorNode(definition, depth);\n break;\n\n case \"parallel\":\n validateParallelNode(definition, depth);\n break;\n\n default:\n throw new Error(`unexpected node type of '${definition.type}' at depth '${depth}'`);\n }\n}\n\n/**\n * Validate any attributes for a given node definition.\n * @param definition The node definition.\n * @param depth The depth of the node in the behaviour tree definition.\n */\nfunction validateNodeAttributes(definition: any, depth: number): void {\n // Validate each of the attribute types for this node.\n [\"while\", \"until\", \"entry\", \"exit\", \"step\"].forEach((attributeName) => {\n // Attempt to grab the definition for the current attribute from the node definition.\n const attributeDefinition = definition[attributeName];\n\n // All node attributes are optional, so there is nothing to do if the current attribute is not defined.\n if (typeof attributeDefinition === \"undefined\") {\n return;\n }\n\n // The attribute definition must be an object.\n if (typeof attributeDefinition !== \"object\") {\n throw new Error(\n `expected attribute '${attributeName}' to be an object for '${definition.type}' node at depth '${depth}'`\n );\n }\n\n // The 'call' property must be defined for any attribute definition.\n if (typeof attributeDefinition.call !== \"string\" || attributeDefinition.call.length === 0) {\n throw new Error(\n `expected 'call' property for attribute '${attributeName}' to be a non-empty string for '${definition.type}' node at depth '${depth}'`\n );\n }\n\n // If any node attribute arguments have been defined then they must have been defined in an array.\n if (typeof attributeDefinition.args !== \"undefined\" && !Array.isArray(attributeDefinition.args)) {\n throw new Error(\n `expected 'args' property for attribute '${attributeName}' to be an array for '${definition.type}' node at depth '${depth}'`\n );\n }\n });\n}\n\n/**\n * Validate an object that we expect to be a root node definition.\n * @param definition An object that we expect to be a root node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateRootNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"root\") {\n throw new Error(\"expected node type of 'root' for root node\");\n }\n\n // A root node cannot be the child of another node.\n if (depth > 0) {\n throw new Error(\"a root node cannot be the child of another node\");\n }\n\n // Check that, if the root node 'id' property is defined, it is a non-empty string.\n if (typeof definition.id !== \"undefined\" && (typeof definition.id !== \"string\" || definition.id.length === 0)) {\n throw new Error(\"expected non-empty string for 'id' property if defined for root node\");\n }\n\n // A root node is a decorator node, so must have a child node defined.\n if (typeof definition.child === \"undefined\") {\n throw new Error(\"expected property 'child' to be defined for root node\");\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n\n // Validate the child node of this decorator node.\n validateNode(definition.child, depth + 1);\n}\n\n/**\n * Validate an object that we expect to be a success node definition.\n * @param definition An object that we expect to be a success node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateSuccessNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"success\") {\n throw new Error(`expected node type of 'success' for success node at depth '${depth}'`);\n }\n\n // A success node is a decorator node, so must have a child node defined.\n if (typeof definition.child === \"undefined\") {\n throw new Error(`expected property 'child' to be defined for success node at depth '${depth}'`);\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n\n // Validate the child node of this decorator node.\n validateNode(definition.child, depth + 1);\n}\n\n/**\n * Validate an object that we expect to be a fail node definition.\n * @param definition An object that we expect to be a fail node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateFailNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"fail\") {\n throw new Error(`expected node type of 'fail' for fail node at depth '${depth}'`);\n }\n\n // A fail node is a decorator node, so must have a child node defined.\n if (typeof definition.child === \"undefined\") {\n throw new Error(`expected property 'child' to be defined for fail node at depth '${depth}'`);\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n\n // Validate the child node of this decorator node.\n validateNode(definition.child, depth + 1);\n}\n\n/**\n * Validate an object that we expect to be a flip node definition.\n * @param definition An object that we expect to be a flip node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateFlipNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"flip\") {\n throw new Error(`expected node type of 'flip' for flip node at depth '${depth}'`);\n }\n\n // A flip node is a decorator node, so must have a child node defined.\n if (typeof definition.child === \"undefined\") {\n throw new Error(`expected property 'child' to be defined for flip node at depth '${depth}'`);\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n\n // Validate the child node of this decorator node.\n validateNode(definition.child, depth + 1);\n}\n\n/**\n * Validate an object that we expect to be a repeat node definition.\n * @param definition An object that we expect to be a repeat node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateRepeatNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"repeat\") {\n throw new Error(`expected node type of 'repeat' for repeat node at depth '${depth}'`);\n }\n\n // A repeat node is a decorator node, so must have a child node defined.\n if (typeof definition.child === \"undefined\") {\n throw new Error(`expected property 'child' to be defined for repeat node at depth '${depth}'`);\n }\n\n // Check whether an 'iterations' property has been defined, it may not have been if this node is to repeat indefinitely.\n if (typeof definition.iterations !== \"undefined\") {\n if (Array.isArray(definition.iterations)) {\n // Check whether any elements of the array are not integer values.\n const containsNonInteger = !!definition.iterations.find((value: unknown) => !isInteger(value));\n\n // If the 'iterations' property is an array then it MUST contain two integer values.\n if (definition.iterations.length !== 2 || containsNonInteger) {\n throw new Error(\n `expected array containing two integer values for 'iterations' property if defined for repeat node at depth '${depth}'`\n );\n }\n\n // A repeat node must have a positive min and max iterations count if they are defined.\n if (definition.iterations[0] < 0 || definition.iterations[1] < 0) {\n throw new Error(\n `expected positive minimum and maximum iterations count for 'iterations' property if defined for repeat node at depth '${depth}'`\n );\n }\n\n // A repeat node must not have a minimum iterations count that exceeds the maximum iterations count.\n if (definition.iterations[0] > definition.iterations[1]) {\n throw new Error(\n `expected minimum iterations count that does not exceed the maximum iterations count for 'iterations' property if defined for repeat node at depth '${depth}'`\n );\n }\n } else if (isInteger(definition.iterations)) {\n // A repeat node must have a positive number of iterations if defined.\n if (definition.iterations < 0) {\n throw new Error(\n `expected positive iterations count for 'iterations' property if defined for repeat node at depth '${depth}'`\n );\n }\n } else {\n throw new Error(\n `expected integer value or array containing two integer values for 'iterations' property if defined for repeat node at depth '${depth}'`\n );\n }\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n\n // Validate the child node of this decorator node.\n validateNode(definition.child, depth + 1);\n}\n\n/**\n * Validate an object that we expect to be a retry node definition.\n * @param definition An object that we expect to be a retry node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateRetryNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"retry\") {\n throw new Error(`expected node type of 'retry' for retry node at depth '${depth}'`);\n }\n\n // A retry node is a decorator node, so must have a child node defined.\n if (typeof definition.child === \"undefined\") {\n throw new Error(`expected property 'child' to be defined for retry node at depth '${depth}'`);\n }\n\n // Check whether an 'attempts' property has been defined, it may not have been if this node is to retry indefinitely.\n if (typeof definition.attempts !== \"undefined\") {\n if (Array.isArray(definition.attempts)) {\n // Check whether any elements of the array are not integer values.\n const containsNonInteger = !!definition.attempts.find((value: unknown) => !isInteger(value));\n\n // If the 'attempts' property is an array then it MUST contain two integer values.\n if (definition.attempts.length !== 2 || containsNonInteger) {\n throw new Error(\n `expected array containing two integer values for 'attempts' property if defined for retry node at depth '${depth}'`\n );\n }\n\n // A retry node must have a positive min and max attempts count if they are defined.\n if (definition.attempts[0] < 0 || definition.attempts[1] < 0) {\n throw new Error(\n `expected positive minimum and maximum attempts count for 'attempts' property if defined for retry node at depth '${depth}'`\n );\n }\n\n // A retry node must not have a minimum attempts count that exceeds the maximum attempts count.\n if (definition.attempts[0] > definition.attempts[1]) {\n throw new Error(\n `expected minimum attempts count that does not exceed the maximum attempts count for 'attempts' property if defined for retry node at depth '${depth}'`\n );\n }\n } else if (isInteger(definition.attempts)) {\n // A retry node must have a positive number of attempts if defined.\n if (definition.attempts < 0) {\n throw new Error(\n `expected positive attempts count for 'attempts' property if defined for retry node at depth '${depth}'`\n );\n }\n } else {\n throw new Error(\n `expected integer value or array containing two integer values for 'attempts' property if defined for retry node at depth '${depth}'`\n );\n }\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n\n // Validate the child node of this decorator node.\n validateNode(definition.child, depth + 1);\n}\n\n/**\n * Validate an object that we expect to be a branch node definition.\n * @param definition An object that we expect to be a branch node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateBranchNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"branch\") {\n throw new Error(`expected node type of 'branch' for branch node at depth '${depth}'`);\n }\n\n // Check that the branch node 'ref' property is defined and is a non-empty string.\n if (typeof definition.ref !== \"string\" || definition.ref.length === 0) {\n throw new Error(`expected non-empty string for 'ref' property for branch node at depth '${depth}'`);\n }\n\n // It is invalid to define guard attributes for a branch node as they should be defined on the referenced root node.\n [\"while\", \"until\"].forEach((attributeName) => {\n if (typeof definition[attributeName] !== \"undefined\") {\n throw new Error(\n `guards should not be defined for branch nodes but guard '${attributeName}' was defined for branch node at depth '${depth}'`\n );\n }\n });\n\n // It is invalid to define callback attributes for a branch node as they should be defined on the referenced root node.\n [\"entry\", \"exit\", \"step\"].forEach((attributeName) => {\n if (typeof definition[attributeName] !== \"undefined\") {\n throw new Error(\n `callbacks should not be defined for branch nodes but callback '${attributeName}' was defined for branch node at depth '${depth}'`\n );\n }\n });\n}\n\n/**\n * Validate an object that we expect to be a action node definition.\n * @param definition An object that we expect to be a action node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateActionNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"action\") {\n throw new Error(`expected node type of 'action' for action node at depth '${depth}'`);\n }\n\n // The 'call' property must be defined for a action node definition.\n if (typeof definition.call !== \"string\" || definition.call.length === 0) {\n throw new Error(`expected non-empty string for 'call' property of action node at depth '${depth}'`);\n }\n\n // If any action function arguments have been defined then they must have been defined in an array.\n if (typeof definition.args !== \"undefined\" && !Array.isArray(definition.args)) {\n throw new Error(`expected array for 'args' property if defined for action node at depth '${depth}'`);\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n}\n\n/**\n * Validate an object that we expect to be a condition node definition.\n * @param definition An object that we expect to be a condition node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateConditionNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"condition\") {\n throw new Error(`expected node type of 'condition' for condition node at depth '${depth}'`);\n }\n\n // The 'call' property must be defined for a condition node definition.\n if (typeof definition.call !== \"string\" || definition.call.length === 0) {\n throw new Error(`expected non-empty string for 'call' property of condition node at depth '${depth}'`);\n }\n\n // If any condition function arguments have been defined then they must have been defined in an array.\n if (typeof definition.args !== \"undefined\" && !Array.isArray(definition.args)) {\n throw new Error(`expected array for 'args' property if defined for condition node at depth '${depth}'`);\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n}\n\n/**\n * Validate an object that we expect to be a wait node definition.\n * @param definition An object that we expect to be a wait node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateWaitNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"wait\") {\n throw new Error(`expected node type of 'wait' for wait node at depth '${depth}'`);\n }\n\n // Check whether a 'duration' property has been defined, it may not have been if this node is to wait indefinitely.\n if (typeof definition.duration !== \"undefined\") {\n if (Array.isArray(definition.duration)) {\n // Check whether any elements of the array are not integer values.\n const containsNonInteger = !!definition.duration.find((value: unknown) => !isInteger(value));\n\n // If the 'duration' property is an array then it MUST contain two integer values.\n if (definition.duration.length !== 2 || containsNonInteger) {\n throw new Error(\n `expected array containing two integer values for 'duration' property if defined for wait node at depth '${depth}'`\n );\n }\n\n // A wait node must have a positive min and max duration value if they are defined.\n if (definition.duration[0] < 0 || definition.duration[1] < 0) {\n throw new Error(\n `expected positive minimum and maximum duration for 'duration' property if defined for wait node at depth '${depth}'`\n );\n }\n\n // A wait node must not have a minimum duration value that exceeds the maximum duration value.\n if (definition.duration[0] > definition.duration[1]) {\n throw new Error(\n `expected minimum duration value that does not exceed the maximum duration value for 'duration' property if defined for wait node at depth '${depth}'`\n );\n }\n } else if (isInteger(definition.duration)) {\n // A wait node must have a positive duration value if defined.\n if (definition.duration < 0) {\n throw new Error(\n `expected positive duration value for 'duration' property if defined for wait node at depth '${depth}'`\n );\n }\n } else {\n throw new Error(\n `expected integer value or array containing two integer values for 'duration' property if defined for wait node at depth '${depth}'`\n );\n }\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n}\n\n/**\n * Validate an object that we expect to be a sequence node definition.\n * @param definition An object that we expect to be a sequence node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateSequenceNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"sequence\") {\n throw new Error(`expected node type of 'sequence' for sequence node at depth '${depth}'`);\n }\n\n // A sequence node is a composite node, so must have a children nodes array defined.\n if (!Array.isArray(definition.children) || definition.children.length === 0) {\n throw new Error(`expected non-empty 'children' array to be defined for sequence node at depth '${depth}'`);\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n\n // Validate the child nodes of this composite node.\n definition.children.forEach((child: any) => validateNode(child, depth + 1));\n}\n\n/**\n * Validate an object that we expect to be a selector node definition.\n * @param definition An object that we expect to be a selector node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateSelectorNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"selector\") {\n throw new Error(`expected node type of 'selector' for selector node at depth '${depth}'`);\n }\n\n // A selector node is a composite node, so must have a children nodes array defined.\n if (!Array.isArray(definition.children) || definition.children.length === 0) {\n throw new Error(`expected non-empty 'children' array to be defined for selector node at depth '${depth}'`);\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n\n // Validate the child nodes of this composite node.\n definition.children.forEach((child: any) => validateNode(child, depth + 1));\n}\n\n/**\n * Validate an object that we expect to be a parallel node definition.\n * @param definition An object that we expect to be a parallel node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateParallelNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"parallel\") {\n throw new Error(`expected node type of 'parallel' for parallel node at depth '${depth}'`);\n }\n\n // A parallel node is a composite node, so must have a children nodes array defined.\n if (!Array.isArray(definition.children) || definition.children.length === 0) {\n throw new Error(`expected non-empty 'children' array to be defined for parallel node at depth '${depth}'`);\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n\n // Validate the child nodes of this composite node.\n definition.children.forEach((child: any) => validateNode(child, depth + 1));\n}\n\n/**\n * A helper function to create a failure validation result with the given error message.\n * @param errorMessage The validation failure error message.\n * @returns A failure validation result with the given error message.\n */\nfunction createValidationFailureResult(errorMessage: string): DefinitionValidationResult {\n return { succeeded: false, errorMessage };\n}\n", "import { ActionResult, Agent, GlobalFunction } from \"./Agent\";\nimport { RootNodeDefinition } from \"./BehaviourTreeDefinition\";\n\nexport type InvokerFunction = (args: any[]) => ActionResult;\n\n/**\n * A singleton used to store and lookup registered functions and subtrees.\n */\nexport default class Lookup {\n /**\n * The object holding any registered functions keyed on function name.\n */\n private static functionTable: { [key: string]: GlobalFunction } = {};\n /**\n * The object holding any registered subtree root node definitions keyed on tree name.\n */\n private static subtreeTable: { [key: string]: RootNodeDefinition } = {};\n\n /**\n * Gets the function with the specified name.\n * @param name The name of the function.\n * @returns The function with the specified name.\n */\n public static getFunc(name: string): GlobalFunction {\n return this.functionTable[name];\n }\n\n /**\n * Sets the function with the specified name for later lookup.\n * @param name The name of the function.\n * @param func The function.\n */\n public static setFunc(name: string, func: GlobalFunction): void {\n this.functionTable[name] = func;\n }\n\n /**\n * Gets the function invoker for the specified agent and function name.\n * If a function with the specified name exists on the agent object then it will\n * be returned, otherwise we will then check the registered functions for a match.\n * @param agent The agent instance that this behaviour tree is modelling behaviour for.\n * @param name The function name.\n * @returns The function invoker for the specified agent and function name.\n */\n static getFuncInvoker(agent: Agent, name: string): InvokerFunction | null {\n // Check whether the agent contains the specified function.\n const foundOnAgent = agent[name];\n if (foundOnAgent && typeof foundOnAgent === \"function\") {\n return (args: any[]): boolean | ActionResult => foundOnAgent.apply(agent, args);\n }\n\n // The agent does not contain the specified function but it may have been registered at some point.\n if (this.functionTable[name] && typeof this.functionTable[name] === \"function\") {\n return (args: any[]) => this.functionTable[name](agent, ...args.map((arg) => arg.value));\n }\n\n // We have no function to invoke.\n return null;\n }\n\n /**\n * Gets all registered subtree root node definitions.\n */\n static getSubtrees(): { [key: string]: RootNodeDefinition } {\n return this.subtreeTable;\n }\n\n /**\n * Sets the subtree with the specified name for later lookup.\n * @param name The name of the subtree.\n * @param subtree The subtree.\n */\n static setSubtree(name: string, subtree: RootNodeDefinition) {\n this.subtreeTable[name] = subtree;\n }\n\n /**\n * Removes the registered function or subtree with the specified name.\n * @param name The name of the registered function or subtree.\n */\n static remove(name: string) {\n delete this.functionTable[name];\n delete this.subtreeTable[name];\n }\n\n /**\n * Remove all registered functions and subtrees.\n */\n static empty() {\n this.functionTable = {};\n this.subtreeTable = {};\n }\n}\n", "import Node from \"../../nodes/Node\";\n\n/**\n * An exception thrown when evaluating node guard path conditions and a conditions fails.\n */\nexport default class GuardUnsatisifedException extends Error {\n /**\n * @param source The node at which a guard condition failed.\n */\n constructor(private source: Node) {\n super(\"A guard path condition has failed\");\n }\n\n /**\n * Gets whether the specified node is the node at which a guard condition failed.\n * @param node The node to check against the source node.\n * @returns Whether the specified node is the node at which a guard condition failed.\n */\n isSourceNode = (node: Node) => node === this.source;\n}\n", "import { Agent } from \"../../Agent\";\nimport Guard from \"./Guard\";\nimport Node from \"../../nodes/Node\";\nimport GuardUnsatisifedException from \"./GuardUnsatisifedException\";\n\nexport type GuardPathPart = {\n node: Node;\n guards: Guard[];\n};\n\n/**\n * Represents a path of node guards along a root-to-leaf tree path.\n */\nexport default class GuardPath {\n /**\n * @param nodes An array of objects defining a node instance -> guard link, ordered by node depth.\n */\n constructor(private nodes: GuardPathPart[]) {}\n\n /**\n * Evaluate guard conditions for all guards in the tree path, moving outwards from the root.\n * @param agent The agent, required for guard evaluation.\n * @returns An evaluation results object.\n */\n evaluate = (agent: Agent) => {\n // We need to evaluate guard conditions for nodes up the tree, moving outwards from the root.\n for (const details of this.nodes) {\n // There can be multiple guards per node.\n for (const guard of details.guards) {\n // Check whether the guard condition passes, and throw an exception if not.\n if (!guard.isSatisfied(agent)) {\n throw new GuardUnsatisifedException(details.node);\n }\n }\n }\n };\n}\n", "import { BehaviourTreeOptions } from \"../BehaviourTreeOptions\";\nimport State, { AnyState } from \"../State\";\nimport { Agent } from \"../Agent\";\nimport Leaf from \"./leaf/Leaf\";\nimport Attribute from \"../attributes/Attribute\";\nimport Entry from \"../attributes/callbacks/Entry\";\nimport Exit from \"../attributes/callbacks/Exit\";\nimport Step from \"../attributes/callbacks/Step\";\nimport Guard from \"../attributes/guards/Guard\";\nimport GuardPath from \"../attributes/guards/GuardPath\";\nimport GuardUnsatisifedException from \"../attributes/guards/GuardUnsatisifedException\";\n\n/**\n * A base node.\n */\nexport default abstract class Node {\n /**\n * The node uid.\n */\n private readonly uid: string = createNodeUid();\n /**\n * The node state.\n */\n private state: AnyState = State.READY;\n /**\n * The guard path to evaluate as part of a node update.\n */\n private guardPath: GuardPath | undefined;\n\n /**\n * @param type The node type.\n * @param attributes The node attributes.\n * @param args The node argument definitions.\n */\n constructor(private type: string, private attributes: Attribute[], private args: any[]) {}\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected abstract onUpdate(agent: Agent, options: BehaviourTreeOptions): void;\n\n /**\n * Gets the name of the node.\n */\n public abstract getName(): string;\n\n /**\n * Gets whether this node is a leaf node.\n */\n public abstract isLeafNode: () => this is Leaf;\n\n /**\n * Gets/Sets the state of the node.\n */\n getState = (): AnyState => this.state;\n setState = (value: AnyState): void => {\n this.state = value;\n };\n\n /**\n * Gets the unique id of the node.\n */\n getUid = () => this.uid;\n\n /**\n * Gets the type of the node.\n */\n getType = () => this.type;\n\n /**\n * Gets the node attributes.\n */\n getAttributes = () => this.attributes;\n\n /**\n * Gets the node arguments.\n */\n getArguments = () => this.args;\n\n /**\n * Gets the node attribute with the specified type, or null if it does not exist.\n */\n getAttribute(type: \"entry\" | \"ENTRY\"): Entry;\n getAttribute(type: \"exit\" | \"EXIT\"): Exit;\n getAttribute(type: \"step\" | \"STEP\"): Step;\n getAttribute(type: string): Attribute {\n return (\n this.getAttributes().filter((decorator) => decorator.type.toUpperCase() === type.toUpperCase())[0] || null\n );\n }\n\n /**\n * Gets the node attributes.\n */\n getGuardAttributes = (): Guard[] => this.getAttributes().filter((decorator) => decorator.isGuard()) as Guard[];\n\n /**\n * Sets the guard path to evaluate as part of a node update.\n */\n setGuardPath = (value: GuardPath) => (this.guardPath = value);\n\n /**\n * Gets whether a guard path is assigned to this node.\n */\n hasGuardPath = () => !!this.guardPath;\n\n /**\n * Gets whether this node is in the specified state.\n * @param value The value to compare to the node state.\n */\n public is(value: AnyState): boolean {\n return this.state === value;\n }\n\n /**\n * Reset the state of the node.\n */\n public reset(): void {\n this.setState(State.READY);\n }\n\n /**\n * Abort the running of this node.\n * @param agent The agent.\n */\n public abort(agent: Agent): void {\n // There is nothing to do if this node is not in the running state.\n if (!this.is(State.RUNNING)) {\n return;\n }\n\n // Reset the state of this node.\n this.reset();\n\n this.getAttribute(\"exit\")?.callAgentFunction(agent, false, true);\n }\n\n /**\n * Update the node.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n * @returns The result of the update.\n */\n public update(agent: Agent, options: BehaviourTreeOptions): void {\n // If this node is already in a 'SUCCEEDED' or 'FAILED' state then there is nothing to do.\n if (this.is(State.SUCCEEDED) || this.is(State.FAILED)) {\n return;\n }\n\n try {\n // Evaluate all of the guard path conditions for the current tree path.\n this.guardPath!.evaluate(agent);\n\n // If this node is in the READY state then call the ENTRY for this node if it exists.\n if (this.is(State.READY)) {\n this.getAttribute(\"entry\")?.callAgentFunction(agent);\n }\n\n this.getAttribute(\"step\")?.callAgentFunction(agent);\n\n // Do the actual update.\n this.onUpdate(agent, options);\n\n // If this node is now in a 'SUCCEEDED' or 'FAILED' state then call the EXIT for this node if it exists.\n if (this.is(State.SUCCEEDED) || this.is(State.FAILED)) {\n this.getAttribute(\"exit\")?.callAgentFunction(agent, this.is(State.SUCCEEDED), false);\n }\n } catch (error) {\n // If the error is a GuardUnsatisfiedException then we need to determine if this node is the source.\n if (error instanceof GuardUnsatisifedException && error.isSourceNode(this)) {\n // Abort the current node.\n this.abort(agent);\n\n // Any node that is the source of an abort will be a failed node.\n this.setState(State.FAILED);\n } else {\n throw error;\n }\n }\n }\n}\n\n/**\n * Create a randomly generated node uid.\n * @returns A randomly generated node uid.\n */\nfunction createNodeUid(): string {\n var S4 = function () {\n return (((1 + Math.random()) * 0x10000) | 0).toString(16).substring(1);\n };\n return S4() + S4() + \"-\" + S4() + \"-\" + S4() + \"-\" + S4() + \"-\" + S4() + S4() + S4();\n}\n", "import Node from \"../Node\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\n\n/**\n * A composite node that wraps child nodes.\n */\nexport default abstract class Composite extends Node {\n /**\n * @param type The node type.\n * @param attributes The node attributes.\n * @param children The child nodes.\n */\n constructor(type: string, attributes: Attribute[], protected children: Node[]) {\n super(type, attributes, []);\n }\n\n /**\n * Gets whether this node is a leaf node.\n */\n isLeafNode = () => false;\n\n /**\n * Gets the children of this node.\n */\n getChildren = () => this.children;\n\n /**\n * Reset the state of the node.\n */\n reset = () => {\n // Reset the state of this node.\n this.setState(State.READY);\n\n // Reset the state of any child nodes.\n this.getChildren().forEach((child) => child.reset());\n };\n\n /**\n * Abort the running of this node.\n * @param agent The agent.\n */\n abort = (agent: Agent) => {\n // There is nothing to do if this node is not in the running state.\n if (!this.is(State.RUNNING)) {\n return;\n }\n\n // Abort any child nodes.\n this.getChildren().forEach((child) => child.abort(agent));\n\n // Reset the state of this node.\n this.reset();\n\n this.getAttribute(\"exit\")?.callAgentFunction(agent, false, true);\n };\n}\n", "import Composite from \"./Composite\";\nimport State from \"../../State\";\nimport Node from \"../Node\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A PARALLEL node.\n * The child nodes are executed concurrently until one fails or all succeed.\n */\nexport default class Parallel extends Composite {\n /**\n * @param attributes The node attributes.\n * @param children The child nodes.\n */\n constructor(attributes: Attribute[], children: Node[]) {\n super(\"parallel\", attributes, children);\n }\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // Keep a count of the number of succeeded child nodes.\n let succeededCount = 0;\n\n let hasChildFailed = false;\n\n // Iterate over all of the children of this node.\n for (const child of this.children) {\n // If the child has never been updated or is running then we will need to update it now.\n if (child.getState() === State.READY || child.getState() === State.RUNNING) {\n // Update the child of this node.\n child.update(agent, options);\n }\n\n // If the current child has a state of 'SUCCEEDED' then we should move on to the next child.\n if (child.getState() === State.SUCCEEDED) {\n // The child node has succeeded, keep track of this to determine if all children have.\n succeededCount++;\n\n // The child node succeeded, but we have not finished checking every child node yet.\n continue;\n }\n\n // If the current child has a state of 'FAILED' then this node is also a 'FAILED' node.\n if (child.getState() === State.FAILED) {\n hasChildFailed = true;\n\n // There is no need to check the rest of the children.\n break;\n }\n\n // The node should be in the 'RUNNING' state.\n if (child.getState() !== State.RUNNING) {\n // The child node was not in an expected state.\n throw new Error(\"child node was not in an expected state.\");\n }\n }\n\n if (hasChildFailed) {\n // This node is a 'FAILED' node.\n this.setState(State.FAILED);\n\n // Abort every running child.\n for (const child of this.children) {\n if (child.getState() === State.RUNNING) {\n child.abort(agent);\n }\n }\n } else {\n // If all children have succeeded then this node has also succeeded, otherwise it is still running.\n this.setState(succeededCount === this.children.length ? State.SUCCEEDED : State.RUNNING);\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => \"PARALLEL\";\n}\n", "import Composite from \"./Composite\";\nimport Node from \"../Node\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A SELECTOR node.\n * The child nodes are executed in sequence until one succeeds or all fail.\n */\nexport default class Selector extends Composite {\n /**\n * @param attributes The node attributes.\n * @param children The child nodes.\n */\n constructor(attributes: Attribute[], protected children: Node[]) {\n super(\"selector\", attributes, children);\n }\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // Iterate over all of the children of this node.\n for (const child of this.children) {\n // If the child has never been updated or is running then we will need to update it now.\n if (child.getState() === State.READY || child.getState() === State.RUNNING) {\n // Update the child of this node.\n child.update(agent, options);\n }\n\n // If the current child has a state of 'SUCCEEDED' then this node is also a 'SUCCEEDED' node.\n if (child.getState() === State.SUCCEEDED) {\n // This node is a 'SUCCEEDED' node.\n this.setState(State.SUCCEEDED);\n\n // There is no need to check the rest of the selector nodes.\n return;\n }\n\n // If the current child has a state of 'FAILED' then we should move on to the next child.\n if (child.getState() === State.FAILED) {\n // Find out if the current child is the last one in the selector.\n // If it is then this sequence node has also failed.\n if (this.children.indexOf(child) === this.children.length - 1) {\n // This node is a 'FAILED' node.\n this.setState(State.FAILED);\n\n // There is no need to check the rest of the selector as we have completed it.\n return;\n } else {\n // The child node failed, try the next one.\n continue;\n }\n }\n\n // The node should be in the 'RUNNING' state.\n if (child.getState() === State.RUNNING) {\n // This node is a 'RUNNING' node.\n this.setState(State.RUNNING);\n\n // There is no need to check the rest of the selector as the current child is still running.\n return;\n }\n\n // The child node was not in an expected state.\n throw new Error(\"child node was not in an expected state.\");\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => \"SELECTOR\";\n}\n", "import Composite from \"./Composite\";\nimport Node from \"../Node\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A SEQUENCE node.\n * The child nodes are executed in sequence until one fails or all succeed.\n */\nexport default class Sequence extends Composite {\n /**\n * @param attributes The node attributes.\n * @param children The child nodes.\n */\n constructor(attributes: Attribute[], protected children: Node[]) {\n super(\"sequence\", attributes, children);\n }\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // Iterate over all of the children of this node.\n for (const child of this.children) {\n // If the child has never been updated or is running then we will need to update it now.\n if (child.getState() === State.READY || child.getState() === State.RUNNING) {\n // Update the child of this node.\n child.update(agent, options);\n }\n\n // If the current child has a state of 'SUCCEEDED' then we should move on to the next child.\n if (child.getState() === State.SUCCEEDED) {\n // Find out if the current child is the last one in the sequence.\n // If it is then this sequence node has also succeeded.\n if (this.children.indexOf(child) === this.children.length - 1) {\n // This node is a 'SUCCEEDED' node.\n this.setState(State.SUCCEEDED);\n\n // There is no need to check the rest of the sequence as we have completed it.\n return;\n } else {\n // The child node succeeded, but we have not finished the sequence yet.\n continue;\n }\n }\n\n // If the current child has a state of 'FAILED' then this node is also a 'FAILED' node.\n if (child.getState() === State.FAILED) {\n // This node is a 'FAILED' node.\n this.setState(State.FAILED);\n\n // There is no need to check the rest of the sequence.\n return;\n }\n\n // The node should be in the 'RUNNING' state.\n if (child.getState() === State.RUNNING) {\n // This node is a 'RUNNING' node.\n this.setState(State.RUNNING);\n\n // There is no need to check the rest of the sequence as the current child is still running.\n return;\n }\n\n // The child node was not in an expected state.\n throw new Error(\"child node was not in an expected state.\");\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => \"SEQUENCE\";\n}\n", "import createLotto from \"lotto-draw\";\n\nimport Node from \"../Node\";\nimport Composite from \"./Composite\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A LOTTO node.\n * A winning child is picked on the initial update of this node, based on ticket weighting.\n * The state of this node will match the state of the winning child.\n */\nexport default class Lotto extends Composite {\n /**\n * @param attributes The node attributes.\n * @param weights The child node weights.\n * @param children The child nodes.\n */\n constructor(attributes: Attribute[], private weights: number[] | undefined, children: Node[]) {\n super(\"lotto\", attributes, children);\n }\n\n /**\n * The child node selected to be the active one.\n */\n private selectedChild: Node | undefined;\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // If this node is in the READY state then we need to pick a winning child node.\n if (this.is(State.READY)) {\n // Create a lotto draw with which to randomly pick a child node to become the active one.\n const lottoDraw = createLotto({\n // Hook up the optional 'random' behaviour tree function option to the one used by 'lotto-draw'.\n random: options.random,\n // Pass in each child node as a participant in the lotto draw with their respective ticket count.\n participants: this.children.map((child, index) => [child, this.weights?.[index] || 1])\n });\n\n // Randomly pick a child based on ticket weighting, this will become the active child for this composite node.\n this.selectedChild = lottoDraw.draw() || undefined;\n }\n\n // If something went wrong and we don't have an active child then we should throw an error.\n if (!this.selectedChild) {\n throw new Error(\"failed to update lotto node as it has no active child\");\n }\n\n // If the selected child has never been updated or is running then we will need to update it now.\n if (this.selectedChild.getState() === State.READY || this.selectedChild.getState() === State.RUNNING) {\n this.selectedChild.update(agent, options);\n }\n\n // The state of the lotto node is the state of its selected child.\n this.setState(this.selectedChild.getState());\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => (this.weights ? `LOTTO [${this.weights.join(\",\")}]` : \"LOTTO\");\n}\n", "import Node from \"../Node\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\n\n/**\n * A decorator node that wraps a single child node.\n */\nexport default abstract class Decorator extends Node {\n /**\n * @param type The node type.\n * @param attributes The node attributes.\n * @param child The child node.\n */\n constructor(type: string, attributes: Attribute[], protected child: Node) {\n super(type, attributes, []);\n }\n\n /**\n * Gets whether this node is a leaf node.\n */\n isLeafNode = () => false;\n\n /**\n * Gets the children of this node.\n */\n getChildren = () => [this.child];\n\n /**\n * Reset the state of the node.\n */\n reset = () => {\n // Reset the state of this node.\n this.setState(State.READY);\n\n // Reset the state of the child node.\n this.child.reset();\n };\n\n /**\n * Abort the running of this node.\n * @param agent The agent.\n */\n abort = (agent: Agent) => {\n // There is nothing to do if this node is not in the running state.\n if (!this.is(State.RUNNING)) {\n return;\n }\n\n // Abort the child node.\n this.child.abort(agent);\n\n // Reset the state of this node.\n this.reset();\n\n this.getAttribute(\"exit\")?.callAgentFunction(agent, false, true);\n };\n}\n", "import Node from \"../Node\";\nimport Decorator from \"./Decorator\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A Fail node.\n * This node wraps a single child and will always move to the 'FAILED' state when the child moves to a 'SUCCEEDED' or 'FAILED' state.\n */\nexport default class Fail extends Decorator {\n /**\n * @param attributes The node attributes.\n * @param child The child node.\n */\n constructor(attributes: Attribute[], child: Node) {\n super(\"fail\", attributes, child);\n }\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // If the child has never been updated or is running then we will need to update it now.\n if (this.child.getState() === State.READY || this.child.getState() === State.RUNNING) {\n this.child.update(agent, options);\n }\n\n // The state of this node will depend in the state of its child.\n switch (this.child.getState()) {\n case State.RUNNING:\n this.setState(State.RUNNING);\n break;\n\n case State.SUCCEEDED:\n case State.FAILED:\n this.setState(State.FAILED);\n break;\n\n default:\n this.setState(State.READY);\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => \"FAIL\";\n}\n", "import Decorator from \"./Decorator\";\nimport State from \"../../State\";\nimport Node from \"../Node\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A Flip node.\n * This node wraps a single child and will flip the state of the child state.\n */\nexport default class Flip extends Decorator {\n /**\n * @param attributes The node attributes.\n * @param child The child node.\n */\n constructor(attributes: Attribute[], child: Node) {\n super(\"flip\", attributes, child);\n }\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // If the child has never been updated or is running then we will need to update it now.\n if (this.child.getState() === State.READY || this.child.getState() === State.RUNNING) {\n this.child.update(agent, options);\n }\n\n // The state of this node will depend in the state of its child.\n switch (this.child.getState()) {\n case State.RUNNING:\n this.setState(State.RUNNING);\n break;\n\n case State.SUCCEEDED:\n this.setState(State.FAILED);\n break;\n\n case State.FAILED:\n this.setState(State.SUCCEEDED);\n break;\n\n default:\n this.setState(State.READY);\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => \"FLIP\";\n}\n", "import Node from \"../Node\";\nimport Decorator from \"./Decorator\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A REPEAT node.\n * The node has a single child which can have:\n * -- A number of iterations for which to repeat the child node.\n * -- An infinite repeat loop if neither an iteration count or a condition function is defined.\n * The REPEAT node will stop and have a 'FAILED' state if its child is ever in a 'FAILED' state after an update.\n * The REPEAT node will attempt to move on to the next iteration if its child is ever in a 'SUCCEEDED' state.\n */\nexport default class Repeat extends Decorator {\n /**\n * @param attributes The node attributes.\n * @param iterations The number of iterations to repeat the child node.\n * @param iterationsMin The minimum possible number of iterations to repeat the child node.\n * @param iterationsMax The maximum possible number of iterations to repeat the child node.\n * @param child The child node.\n */\n constructor(\n attributes: Attribute[],\n private iterations: number | null,\n private iterationsMin: number | null,\n private iterationsMax: number | null,\n child: Node\n ) {\n super(\"repeat\", attributes, child);\n }\n\n /**\n * The number of target iterations to make.\n */\n private targetIterationCount: number | null = null;\n\n /**\n * The current iteration count.\n */\n private currentIterationCount: number = 0;\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // If this node is in the READY state then we need to reset the child and the target iteration count.\n if (this.is(State.READY)) {\n // Reset the child node.\n this.child.reset();\n\n // Reset the current iteration count.\n this.currentIterationCount = 0;\n\n // Set the target iteration count.\n this.setTargetIterationCount(options);\n }\n\n // Do a check to see if we can iterate. If we can then this node will move into the 'RUNNING' state.\n // If we cannot iterate then we have hit our target iteration count, which means that the node has succeeded.\n if (this.canIterate()) {\n // This node is in the running state and can do its initial iteration.\n this.setState(State.RUNNING);\n\n // We may have already completed an iteration, meaning that the child node will be in the SUCCEEDED state.\n // If this is the case then we will have to reset the child node now.\n if (this.child.getState() === State.SUCCEEDED) {\n this.child.reset();\n }\n\n // Update the child of this node.\n this.child.update(agent, options);\n\n // If the child moved into the FAILED state when we updated it then there is nothing left to do and this node has also failed.\n // If it has moved into the SUCCEEDED state then we have completed the current iteration.\n if (this.child.getState() === State.FAILED) {\n // The child has failed, meaning that this node has failed.\n this.setState(State.FAILED);\n\n return;\n } else if (this.child.getState() === State.SUCCEEDED) {\n // We have completed an iteration.\n this.currentIterationCount += 1;\n }\n } else {\n // This node is in the 'SUCCEEDED' state as we cannot iterate any more.\n this.setState(State.SUCCEEDED);\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => {\n if (this.iterations !== null) {\n return `REPEAT ${this.iterations}x`;\n } else if (this.iterationsMin !== null && this.iterationsMax !== null) {\n return `REPEAT ${this.iterationsMin}x-${this.iterationsMax}x`;\n } else {\n return \"REPEAT\";\n }\n };\n\n /**\n * Reset the state of the node.\n */\n reset = () => {\n // Reset the state of this node.\n this.setState(State.READY);\n\n // Reset the current iteration count.\n this.currentIterationCount = 0;\n\n // Reset the child node.\n this.child.reset();\n };\n\n /**\n * Gets whether an iteration can be made.\n * @returns Whether an iteration can be made.\n */\n private canIterate = () => {\n if (this.targetIterationCount !== null) {\n // We can iterate as long as we have not reached our target iteration count.\n return this.currentIterationCount < this.targetIterationCount;\n }\n\n // If neither an iteration count or a condition function were defined then we can iterate indefinitely.\n return true;\n };\n\n /**\n * Sets the target iteration count.\n * @param options The behaviour tree options object.\n */\n private setTargetIterationCount = (options: BehaviourTreeOptions) => {\n // Are we dealing with an explicit iteration count or will we be randomly picking a iteration count between the min and max iteration count.\n if (this.iterations !== null) {\n this.targetIterationCount = this.iterations;\n } else if (this.iterationsMin !== null && this.iterationsMax !== null) {\n // We will be picking a random iteration count between a min and max iteration count, if the optional 'random'\n // behaviour tree function option is defined then we will be using that, otherwise we will fall back to using Math.random.\n const random = typeof options.random === \"function\" ? options.random : Math.random;\n\n // Pick a random iteration count between a min and max iteration count.\n this.targetIterationCount = Math.floor(\n random() * (this.iterationsMax - this.iterationsMin + 1) + this.iterationsMin\n );\n } else {\n this.targetIterationCount = null;\n }\n };\n}\n", "import Node from \"../Node\";\nimport Decorator from \"./Decorator\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A RETRY node.\n * The node has a single child which can have:\n * -- A number of iterations for which to repeat the child node.\n * -- An infinite repeat loop if neither an iteration count or a condition function is defined.\n * The RETRY node will stop and have a 'SUCCEEDED' state if its child is ever in a 'SUCCEEDED' state after an update.\n * The RETRY node will attempt to move on to the next iteration if its child is ever in a 'FAILED' state.\n */\nexport default class Retry extends Decorator {\n /**\n * @param attributes The node attributes.\n * @param attempts The number of attempts to retry the child node.\n * @param attemptsMin The minimum possible number of attempts to retry the child node.\n * @param attemptsMax The maximum possible number of attempts to retry the child node.\n * @param child The child node.\n */\n constructor(\n attributes: Attribute[],\n private attempts: number | null,\n private attemptsMin: number | null,\n private attemptsMax: number | null,\n child: Node\n ) {\n super(\"retry\", attributes, child);\n }\n\n /**\n * The number of target attempts to make.\n */\n private targetAttemptCount: number | null = null;\n\n /**\n * The current attempt count.\n */\n private currentAttemptCount: number = 0;\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // If this node is in the READY state then we need to reset the child and the target attempt count.\n if (this.is(State.READY)) {\n // Reset the child node.\n this.child.reset();\n\n // Reset the current attempt count.\n this.currentAttemptCount = 0;\n\n // Set the target attempt count.\n this.setTargetAttemptCount(options);\n }\n\n // Do a check to see if we can attempt. If we can then this node will move into the 'RUNNING' state.\n // If we cannot attempt then we have hit our target attempt count, which means that the node has succeeded.\n if (this.canAttempt()) {\n // This node is in the running state and can do its initial attempt.\n this.setState(State.RUNNING);\n\n // We may have already completed an attempt, meaning that the child node will be in the FAILED state.\n // If this is the case then we will have to reset the child node now.\n if (this.child.getState() === State.FAILED) {\n this.child.reset();\n }\n\n // Update the child of this node.\n this.child.update(agent, options);\n\n // If the child moved into the SUCCEEDED state when we updated it then there is nothing left to do and this node has also succeeded.\n // If it has moved into the FAILED state then we have completed the current attempt.\n if (this.child.getState() === State.SUCCEEDED) {\n // The child has succeeded, meaning that this node has succeeded.\n this.setState(State.SUCCEEDED);\n\n return;\n } else if (this.child.getState() === State.FAILED) {\n // We have completed an attempt.\n this.currentAttemptCount += 1;\n }\n } else {\n // This node is in the 'FAILED' state as we cannot iterate any more.\n this.setState(State.FAILED);\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => {\n if (this.attempts !== null) {\n return `RETRY ${this.attempts}x`;\n } else if (this.attemptsMin !== null && this.attemptsMax !== null) {\n return `RETRY ${this.attemptsMin}x-${this.attemptsMax}x`;\n } else {\n return \"RETRY\";\n }\n };\n\n /**\n * Reset the state of the node.\n */\n reset = () => {\n // Reset the state of this node.\n this.setState(State.READY);\n\n // Reset the current attempt count.\n this.currentAttemptCount = 0;\n\n // Reset the child node.\n this.child.reset();\n };\n\n /**\n * Gets whether an attempt can be made.\n * @returns Whether an attempt can be made.\n */\n canAttempt = () => {\n if (this.targetAttemptCount !== null) {\n // We can attempt as long as we have not reached our target attempt count.\n return this.currentAttemptCount < this.targetAttemptCount;\n }\n\n // If neither an attempt count or a condition function were defined then we can attempt indefinitely.\n return true;\n };\n\n /**\n * Sets the target attempt count.\n * @param options The behaviour tree options object.\n */\n setTargetAttemptCount = (options: BehaviourTreeOptions) => {\n // Are we dealing with an explicit attempt count or will we be randomly picking an attempt count between the min and max attempt count.\n if (this.attempts !== null) {\n this.targetAttemptCount = this.attempts;\n } else if (this.attemptsMin !== null && this.attemptsMax !== null) {\n // We will be picking a random attempt count between a min and max attempt count, if the optional 'random'\n // behaviour tree function option is defined then we will be using that, otherwise we will fall back to using Math.random.\n const random = typeof options.random === \"function\" ? options.random : Math.random;\n\n // Pick a random attempt count between a min and max attempt count.\n this.targetAttemptCount = Math.floor(\n random() * (this.attemptsMax - this.attemptsMin + 1) + this.attemptsMin\n );\n } else {\n this.targetAttemptCount = null;\n }\n };\n}\n", "import Node from \"../Node\";\nimport Decorator from \"./Decorator\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A Root node.\n * The root node will have a single child.\n */\nexport default class Root extends Decorator {\n /**\n * @param attributes The node attributes.\n * @param child The child node.\n */\n constructor(attributes: Attribute[], child: Node) {\n super(\"root\", attributes, child);\n }\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // If the child has never been updated or is running then we will need to update it now.\n if (this.child.getState() === State.READY || this.child.getState() === State.RUNNING) {\n // Update the child of this node.\n this.child.update(agent, options);\n }\n\n // The state of the root node is the state of its child.\n this.setState(this.child.getState());\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => \"ROOT\";\n}\n", "import Node from \"../Node\";\nimport Decorator from \"./Decorator\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A Succeed node.\n * This node wraps a single child and will always move to the 'SUCCEEDED' state when the child moves to a 'SUCCEEDED' or 'FAILED' state.\n */\nexport default class Succeed extends Decorator {\n /**\n * @param attributes The node attributes.\n * @param child The child node.\n */\n constructor(attributes: Attribute[], child: Node) {\n super(\"succeed\", attributes, child);\n }\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // If the child has never been updated or is running then we will need to update it now.\n if (this.child.getState() === State.READY || this.child.getState() === State.RUNNING) {\n this.child.update(agent, options);\n }\n\n // The state of this node will depend in the state of its child.\n switch (this.child.getState()) {\n case State.RUNNING:\n this.setState(State.RUNNING);\n break;\n\n case State.SUCCEEDED:\n case State.FAILED:\n this.setState(State.SUCCEEDED);\n break;\n\n default:\n this.setState(State.READY);\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => \"SUCCEED\";\n}\n", "import Node from \"../Node\";\n\n/**\n * A leaf node.\n */\nexport default abstract class Leaf extends Node {\n /**\n * Gets whether this node is a leaf node.\n */\n isLeafNode = () => true;\n}\n", "import { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\nimport State, { CompleteState } from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Leaf from \"./Leaf\";\nimport Lookup from \"../../Lookup\";\nimport Attribute from \"../../attributes/Attribute\";\n\n/**\n * An Action leaf node.\n * This represents an immediate or ongoing state of behaviour.\n */\nexport default class Action extends Leaf {\n /**\n * @param attributes The node attributes.\n * @param actionName The action name.\n * @param actionArguments The array of action argument definitions.\n */\n constructor(attributes: Attribute[], private actionName: string, private actionArguments: any[]) {\n super(\"action\", attributes, actionArguments);\n }\n\n /**\n * Whether there is a pending update promise.\n */\n private isUsingUpdatePromise = false;\n\n /**\n * The finished state result of an update promise.\n */\n private updatePromiseStateResult: CompleteState | null = null;\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // If the result of this action depends on an update promise then there is nothing to do until\n // it resolves, unless there has been a value set as a result of the update promise resolving.\n if (this.isUsingUpdatePromise) {\n // Check whether the update promise has resolved with a state value.\n if (this.updatePromiseStateResult) {\n // Set the state of this node to match the state returned by the promise.\n this.setState(this.updatePromiseStateResult);\n }\n\n return;\n }\n\n // Attempt to get the invoker for the action function.\n const actionFuncInvoker = Lookup.getFuncInvoker(agent, this.actionName);\n\n // The action function should be defined.\n if (actionFuncInvoker === null) {\n throw new Error(\n `cannot update action node as the action '${this.actionName}' function is not defined on the agent and has not been registered`\n );\n }\n\n // Call the action function, the result of which may be:\n // - The finished state of this action node.\n // - A promise to return a finished node state.\n // - Undefined if the node should remain in the running state.\n const updateResult = actionFuncInvoker(this.actionArguments) as CompleteState | Promise;\n\n if (updateResult instanceof Promise) {\n updateResult.then(\n (result) => {\n // If 'isUpdatePromisePending' is null then the promise was cleared as it was resolving, probably via an abort of reset.\n if (!this.isUsingUpdatePromise) {\n return;\n }\n\n // Check to make sure the result is a valid finished state.\n if (result !== State.SUCCEEDED && result !== State.FAILED) {\n throw new Error(\n \"action node promise resolved with an invalid value, expected a State.SUCCEEDED or State.FAILED value to be returned\"\n );\n }\n\n // Set pending update promise state result to be processed on next update.\n this.updatePromiseStateResult = result;\n },\n (reason) => {\n // If 'isUpdatePromisePending' is null then the promise was cleared as it was resolving, probably via an abort of reset.\n if (!this.isUsingUpdatePromise) {\n return;\n }\n\n // Just throw whatever was returned as the rejection argument.\n throw new Error(reason);\n }\n );\n\n // This node will be in the 'RUNNING' state until the update promise resolves.\n this.setState(State.RUNNING);\n\n // We are now waiting for the promise returned by the use to resolve before we know what state this node is in.\n this.isUsingUpdatePromise = true;\n } else {\n // Validate the returned value.\n this.validateUpdateResult(updateResult);\n\n // Set the state of this node, this may be undefined, which just means that the node is still in the 'RUNNING' state.\n this.setState(updateResult || State.RUNNING);\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => this.actionName;\n\n /**\n * Reset the state of the node.\n */\n reset = () => {\n // Reset the state of this node.\n this.setState(State.READY);\n\n // There is no longer an update promise that we care about.\n this.isUsingUpdatePromise = false;\n this.updatePromiseStateResult = null;\n };\n\n /**\n * Validate the result of an update function call.\n * @param result The result of an update function call.\n */\n private validateUpdateResult = (result: CompleteState | boolean) => {\n switch (result) {\n case State.SUCCEEDED:\n case State.FAILED:\n case undefined:\n return;\n default:\n throw new Error(\n `action '${this.actionName}' 'onUpdate' returned an invalid response, expected an optional State.SUCCEEDED or State.FAILED value to be returned`\n );\n }\n };\n}\n", "import { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Leaf from \"./Leaf\";\nimport Lookup from \"../../Lookup\";\nimport Attribute from \"../../attributes/Attribute\";\n\n/**\n * A Condition leaf node.\n * This will succeed or fail immediately based on an agent predicate, without moving to the 'RUNNING' state.\n */\nexport default class Condition extends Leaf {\n /**\n * @param attributes The node attributes.\n * @param conditionName The name of the condition function.\n * @param conditionArguments The array of condition argument definitions.\n */\n constructor(attributes: Attribute[], private conditionName: string, private conditionArguments: any[]) {\n super(\"condition\", attributes, conditionArguments);\n }\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // Attempt to get the invoker for the condition function.\n const conditionFuncInvoker = Lookup.getFuncInvoker(agent, this.conditionName);\n\n // The condition function should be defined.\n if (conditionFuncInvoker === null) {\n throw new Error(\n `cannot update condition node as the condition '${this.conditionName}' function is not defined on the agent and has not been registered`\n );\n }\n\n // Call the condition function to determine the state of this node.\n this.setState(!!conditionFuncInvoker(this.conditionArguments) ? State.SUCCEEDED : State.FAILED);\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => this.conditionName;\n}\n", "import Leaf from \"./Leaf\";\nimport State from \"../../State\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { Agent } from \"../../Agent\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A WAIT node.\n * The state of this node will change to SUCCEEDED after a duration of time\n */\nexport default class Wait extends Leaf {\n /**\n * @param attributes The node attributes.\n * @param duration The duration that this node will wait to succeed in milliseconds.\n * @param durationMin The minimum possible duration in milliseconds that this node will wait to succeed.\n * @param durationMax The maximum possible duration in milliseconds that this node will wait to succeed.\n */\n constructor(\n attributes: Attribute[],\n private duration: number | null,\n private durationMin: number | null,\n private durationMax: number | null\n ) {\n super(\"wait\", attributes, []);\n }\n\n /**\n * The time in milliseconds at which this node was first updated.\n */\n private initialUpdateTime: number = 0;\n\n /**\n * The total duration in milliseconds that this node will be waiting for.\n */\n private totalDuration: number | null = null;\n\n /**\n * The duration in milliseconds that this node has been waiting for.\n */\n private waitedDuration: number = 0;\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // If this node is in the READY state then we need to set the initial update time.\n if (this.is(State.READY)) {\n // Set the initial update time.\n this.initialUpdateTime = new Date().getTime();\n\n // Set the initial waited duration.\n this.waitedDuration = 0;\n\n // Are we dealing with an explicit duration or will we be randomly picking a duration between the min and max duration.\n if (this.duration !== null) {\n this.totalDuration = this.duration;\n } else if (this.durationMin !== null && this.durationMax !== null) {\n // We will be picking a random duration between a min and max duration, if the optional 'random' behaviour tree\n // function option is defined then we will be using that, otherwise we will fall back to using Math.random.\n const random = typeof options.random === \"function\" ? options.random : Math.random;\n\n // Pick a random duration between a min and max duration.\n this.totalDuration = Math.floor(\n random() * (this.durationMax - this.durationMin + 1) + this.durationMin\n );\n } else {\n this.totalDuration = null;\n }\n\n // The node is now running until we finish waiting.\n this.setState(State.RUNNING);\n }\n\n // If we have no total duration then this wait node will wait indefinitely until it is aborted.\n if (this.totalDuration === null) {\n return;\n }\n\n // If we have a 'getDeltaTime' function defined as part of our options then we will use it to figure out how long we have waited for.\n if (typeof options.getDeltaTime === \"function\") {\n // Get the delta time.\n const deltaTime = options.getDeltaTime();\n\n // Our delta time must be a valid number and cannot be NaN.\n if (typeof deltaTime !== \"number\" || isNaN(deltaTime)) {\n throw new Error(\"The delta time must be a valid number and not NaN.\");\n }\n\n // Update the amount of time that this node has been waiting for based on the delta time.\n this.waitedDuration += deltaTime * 1000;\n } else {\n // We are not using a delta time, so we will just work out hom much time has passed since the first update.\n this.waitedDuration = new Date().getTime() - this.initialUpdateTime;\n }\n\n // Have we waited long enough?\n if (this.waitedDuration >= this.totalDuration) {\n // We have finished waiting!\n this.setState(State.SUCCEEDED);\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => {\n if (this.duration !== null) {\n return `WAIT ${this.duration}ms`;\n } else if (this.durationMin !== null && this.durationMax !== null) {\n return `WAIT ${this.durationMin}ms-${this.durationMax}ms`;\n } else {\n return \"WAIT\";\n }\n };\n}\n", "import Guard from \"./guards/Guard\";\n\nexport type AttributeDetails = {\n /** The attribute type. */\n type: string;\n\n /** The attribute arguments. */\n args: any[];\n};\n\n/**\n * A base node attribute.\n */\nexport default abstract class Attribute {\n /**\n * @param type The node attribute type.\n * @param args The array of attribute arguments.\n */\n constructor(public type: string, public args: any[]) {}\n\n /**\n * Gets the attribute details.\n */\n abstract getDetails(): TAttributeDetails;\n\n /**\n * Gets whether this attribute is a guard.\n */\n abstract isGuard: () => this is Guard;\n}\n", "import { Agent } from \"../../Agent\";\nimport Attribute, { AttributeDetails } from \"../Attribute\";\n\nexport type GuardAttributeDetails = {\n /** The name of the condition function that determines whether the guard is satisfied. */\n condition: string;\n} & AttributeDetails;\n\n/**\n * A base node guard attribute.\n */\nexport default abstract class Guard extends Attribute {\n /**\n * @param type The node attribute type.\n * @param args The array of decorator argument definitions.\n * @param condition The name of the condition function that determines whether the guard is satisfied.\n */\n constructor(type: string, args: any[], private condition: string) {\n super(type, args);\n }\n\n /**\n * Gets the name of the condition function that determines whether the guard is satisfied.\n */\n getCondition = () => this.condition;\n\n /**\n * Gets whether this attribute is a guard.\n */\n isGuard = () => true;\n\n /**\n * Gets the attribute details.\n */\n getDetails(): GuardAttributeDetails {\n return {\n type: this.type,\n args: this.args,\n condition: this.getCondition()\n };\n }\n\n /**\n * Gets whether the guard is satisfied.\n * @param agent The agent.\n * @returns Whether the guard is satisfied.\n */\n abstract isSatisfied(agent: Agent): boolean;\n}\n", "import Guard from \"./Guard\";\nimport Lookup from \"../../Lookup\";\nimport { Agent } from \"../../Agent\";\n\n/**\n * A WHILE guard which is satisfied as long as the given condition remains true.\n */\nexport default class While extends Guard {\n /**\n * @param condition The name of the condition function that determines whether the guard is satisfied.\n * @param args The array of decorator argument definitions.\n */\n constructor(condition: string, args: any[]) {\n super(\"while\", args, condition);\n }\n\n /**\n * Gets whether the guard is satisfied.\n * @param agent The agent.\n * @returns Whether the guard is satisfied.\n */\n isSatisfied = (agent: Agent) => {\n // Attempt to get the invoker for the condition function.\n const conditionFuncInvoker = Lookup.getFuncInvoker(agent, this.getCondition());\n\n // The condition function should be defined.\n if (conditionFuncInvoker === null) {\n throw new Error(\n `cannot evaluate node guard as the condition '${this.getCondition()}' function is not defined on the agent and has not been registered`\n );\n }\n\n // Call the condition function to determine whether this guard is satisfied.\n return !!conditionFuncInvoker(this.args);\n };\n}\n", "import Guard from \"./Guard\";\nimport Lookup from \"../../Lookup\";\nimport { Agent } from \"../../Agent\";\n\n/**\n * An UNTIL guard which is satisfied as long as the given condition remains false.\n */\nexport default class Until extends Guard {\n /**\n * @param condition The name of the condition function that determines whether the guard is satisfied.\n * @param args The array of decorator argument definitions.\n */\n constructor(condition: string, args: any[]) {\n super(\"until\", args, condition);\n }\n\n /**\n * Gets whether the guard is satisfied.\n * @param agent The agent.\n * @returns Whether the guard is satisfied.\n */\n isSatisfied = (agent: Agent) => {\n // Attempt to get the invoker for the condition function.\n const conditionFuncInvoker = Lookup.getFuncInvoker(agent, this.getCondition());\n\n // The condition function should be defined.\n if (conditionFuncInvoker === null) {\n throw new Error(\n `cannot evaluate node guard as the condition '${this.getCondition()}' function is not defined on the agent and has not been registered`\n );\n }\n\n // Call the condition function to determine whether this guard is satisfied.\n return !!!conditionFuncInvoker(this.args);\n };\n}\n", "import { Agent } from \"../../Agent\";\nimport Attribute, { AttributeDetails } from \"../Attribute\";\n\nexport type CallbackAttributeDetails = {\n /** The name of the agent function that is called. */\n functionName: string;\n} & AttributeDetails;\n\n/**\n * A base node callback attribute.\n */\nexport default abstract class Callback extends Attribute {\n /**\n * @param type The node attribute type.\n * @param args The array of decorator argument definitions.\n * @param functionName The name of the agent function to call.\n */\n constructor(type: string, args: any[], private functionName: string) {\n super(type, args);\n }\n\n /**\n * Gets the name of the agent function to call.\n */\n getFunctionName = () => this.functionName;\n\n /**\n * Gets whether this attribute is a guard.\n */\n isGuard = () => false;\n\n /**\n * Gets the attribute details.\n */\n getDetails(): CallbackAttributeDetails {\n return {\n type: this.type,\n args: this.args,\n functionName: this.getFunctionName()\n };\n }\n\n /**\n * Attempt to call the agent function that this callback refers to.\n * @param agent The agent.\n */\n abstract callAgentFunction: (agent: Agent, isSuccess: boolean, isAborted: boolean) => void;\n}\n", "import Callback from \"./Callback\";\nimport Lookup from \"../../Lookup\";\nimport { Agent } from \"../../Agent\";\n\n/**\n * An ENTRY callback which defines an agent function to call when the associated node is updated and moves out of running state.\n */\nexport default class Entry extends Callback {\n /**\n * @param functionName The name of the agent function to call.\n * @param args The array of callback argument definitions.\n */\n constructor(functionName: string, args: any[]) {\n super(\"entry\", args, functionName);\n }\n\n /**\n * Attempt to call the agent function that this callback refers to.\n * @param agent The agent.\n */\n callAgentFunction = (agent: Agent) => {\n // Attempt to get the invoker for the callback function.\n const callbackFuncInvoker = Lookup.getFuncInvoker(agent, this.getFunctionName());\n\n // The callback function should be defined.\n if (callbackFuncInvoker === null) {\n throw new Error(\n `cannot call entry function '${this.getFunctionName()}' as is not defined on the agent and has not been registered`\n );\n }\n\n // Call the callback function.\n callbackFuncInvoker(this.args);\n };\n}\n", "import Callback from \"./Callback\";\nimport Lookup from \"../../Lookup\";\nimport { Agent } from \"../../Agent\";\n\n/**\n * A STEP callback which defines an agent function to call when the associated node is updated.\n */\nexport default class Step extends Callback {\n /**\n * @param functionName The name of the agent function to call.\n * @param args The array of callback argument definitions.\n */\n constructor(functionName: string, args: any[]) {\n super(\"step\", args, functionName);\n }\n\n /**\n * Attempt to call the agent function that this callback refers to.\n * @param agent The agent.\n */\n callAgentFunction = (agent: Agent) => {\n // Attempt to get the invoker for the callback function.\n const callbackFuncInvoker = Lookup.getFuncInvoker(agent, this.getFunctionName());\n\n // The callback function should be defined.\n if (callbackFuncInvoker === null) {\n throw new Error(\n `cannot call step function '${this.getFunctionName()}' as is not defined on the agent and has not been registered`\n );\n }\n\n // Call the callback function.\n callbackFuncInvoker(this.args);\n };\n}\n", "import Callback from \"./Callback\";\nimport Lookup from \"../../Lookup\";\nimport { Agent } from \"../../Agent\";\n\n/**\n * An EXIT callback which defines an agent function to call when the associated node is updated and moves to a finished state or is aborted.\n */\nexport default class Exit extends Callback {\n /**\n * @param functionName The name of the agent function to call.\n * @param args The array of callback argument definitions.\n */\n constructor(functionName: string, args: any[]) {\n super(\"exit\", args, functionName);\n }\n\n /**\n * Attempt to call the agent function that this callback refers to.\n * @param agent The agent.\n * @param isSuccess Whether the decorated node was left with a success state.\n * @param isAborted Whether the decorated node was aborted.\n */\n callAgentFunction = (agent: Agent, isSuccess: boolean, isAborted: boolean) => {\n // Attempt to get the invoker for the callback function.\n const callbackFuncInvoker = Lookup.getFuncInvoker(agent, this.getFunctionName());\n\n // The callback function should be defined.\n if (callbackFuncInvoker === null) {\n throw new Error(\n `cannot call exit function '${this.getFunctionName()}' as is not defined on the agent and has not been registered`\n );\n }\n\n // Call the callback function\n callbackFuncInvoker([{ value: { succeeded: isSuccess, aborted: isAborted } }, ...this.args]);\n };\n}\n", "import { AnyNodeDefinition, RootNodeDefinition } from \"./BehaviourTreeDefinition\";\nimport GuardPath, { GuardPathPart } from \"./attributes/guards/GuardPath\";\nimport { validateBranchSubtreeLinks } from \"./BehaviourTreeDefinitionValidator\";\nimport { isInteger } from \"./BehaviourTreeDefinitionUtilities\";\nimport Node from \"./nodes/Node\";\nimport Composite from \"./nodes/composite/Composite\";\nimport Decorator from \"./nodes/decorator/Decorator\";\nimport Parallel from \"./nodes/composite/Parallel\";\nimport Selector from \"./nodes/composite/Selector\";\nimport Sequence from \"./nodes/composite/Sequence\";\nimport Lotto from \"./nodes/composite/Lotto\";\nimport Fail from \"./nodes/decorator/Fail\";\nimport Flip from \"./nodes/decorator/Flip\";\nimport Repeat from \"./nodes/decorator/Repeat\";\nimport Retry from \"./nodes/decorator/Retry\";\nimport Root from \"./nodes/decorator/Root\";\nimport Succeed from \"./nodes/decorator/Succeed\";\nimport Action from \"./nodes/leaf/Action\";\nimport Condition from \"./nodes/leaf/Condition\";\nimport Wait from \"./nodes/leaf/Wait\";\nimport Lookup from \"./Lookup\";\nimport Attribute from \"./attributes/Attribute\";\nimport While from \"./attributes/guards/While\";\nimport Until from \"./attributes/guards/Until\";\nimport Entry from \"./attributes/callbacks/Entry\";\nimport Step from \"./attributes/callbacks/Step\";\nimport Exit from \"./attributes/callbacks/Exit\";\n\n/**\n * A type representing any node instance in a behaviour tree.\n */\ntype AnyNode =\n | Root\n | Action\n | Condition\n | Wait\n | Sequence\n | Selector\n | Lotto\n | Parallel\n | Repeat\n | Retry\n | Flip\n | Succeed\n | Fail;\n\n/**\n * A type defining a mapping of root node identifiers to root node definitions.\n */\ntype RootNodeDefinitionMap = { [key: string | symbol]: RootNodeDefinition };\n\n/**\n * A symbol to use as the main root key in any root node mappings.\n */\nconst MAIN_ROOT_NODE_KEY = Symbol(\"__root__\");\n\n/**\n * Build and populate the root nodes based on the provided definition, assuming that the definition has been validated.\n * @param definition The root node definitions.\n * @returns The built and populated root node definitions.\n */\nexport default function buildRootNode(definition: RootNodeDefinition[]): Root {\n // Create a mapping of root node identifers to root node definitions, including globally registered subtree root node definitions.\n const rootNodeDefinitionMap = createRootNodeDefinitionMap(definition);\n\n // Now that we have all of our root node definitons (those part of the tree definition and those globally\n // registered) we should validate the definition. This will also double-check that we dont have any circular\n // dependencies in our branch -> subtree references and that we have no broken branch -> subtree links.\n validateBranchSubtreeLinks(definition, true);\n\n // Create our populated tree of node instances, starting with our main root node.\n const rootNode = nodeFactory(rootNodeDefinitionMap[MAIN_ROOT_NODE_KEY], rootNodeDefinitionMap) as Root;\n\n // Set a guard path on every leaf of the tree to evaluate as part of each update.\n applyLeafNodeGuardPaths(rootNode);\n\n // We only need to return the main root node.\n return rootNode;\n}\n\n/**\n * A factory function which creates a node instance based on the specified definition.\n * @param definition The node definition.\n * @param rootNodeDefinitionMap The mapping of root node identifers to root node definitions, including globally registered subtree root node definitions.\n * @returns A node instance based on the specified definition.\n */\nfunction nodeFactory(definition: AnyNodeDefinition, rootNodeDefinitionMap: RootNodeDefinitionMap): AnyNode {\n // Get the attributes for the node.\n const attributes = nodeAttributesFactory(definition);\n\n // Create the node instance based on the definition type.\n switch (definition.type) {\n case \"root\":\n return new Root(attributes, nodeFactory(definition.child, rootNodeDefinitionMap));\n\n case \"repeat\":\n let iterations: number | null = null;\n let iterationsMin: number | null = null;\n let iterationsMax: number | null = null;\n\n if (Array.isArray(definition.iterations)) {\n iterationsMin = definition.iterations[0];\n iterationsMax = definition.iterations[1];\n } else if (isInteger(definition.iterations)) {\n iterations = definition.iterations!;\n }\n\n return new Repeat(\n attributes,\n iterations,\n iterationsMin,\n iterationsMax,\n nodeFactory(definition.child, rootNodeDefinitionMap)\n );\n\n case \"retry\":\n let attempts: number | null = null;\n let attemptsMin: number | null = null;\n let attemptsMax: number | null = null;\n\n if (Array.isArray(definition.attempts)) {\n attemptsMin = definition.attempts[0];\n attemptsMax = definition.attempts[1];\n } else if (isInteger(definition.attempts)) {\n attempts = definition.attempts!;\n }\n\n return new Retry(\n attributes,\n attempts,\n attemptsMin,\n attemptsMax,\n nodeFactory(definition.child, rootNodeDefinitionMap)\n );\n\n case \"flip\":\n return new Flip(attributes, nodeFactory(definition.child, rootNodeDefinitionMap));\n\n case \"succeed\":\n return new Succeed(attributes, nodeFactory(definition.child, rootNodeDefinitionMap));\n\n case \"fail\":\n return new Fail(attributes, nodeFactory(definition.child, rootNodeDefinitionMap));\n\n case \"sequence\":\n return new Sequence(\n attributes,\n definition.children.map((child) => nodeFactory(child, rootNodeDefinitionMap))\n );\n\n case \"selector\":\n return new Selector(\n attributes,\n definition.children.map((child) => nodeFactory(child, rootNodeDefinitionMap))\n );\n\n case \"parallel\":\n return new Parallel(\n attributes,\n definition.children.map((child) => nodeFactory(child, rootNodeDefinitionMap))\n );\n\n case \"lotto\":\n return new Lotto(\n attributes,\n definition.weights,\n definition.children.map((child) => nodeFactory(child, rootNodeDefinitionMap))\n );\n\n case \"branch\":\n return nodeFactory(rootNodeDefinitionMap[definition.ref].child, rootNodeDefinitionMap);\n\n case \"action\":\n return new Action(attributes, definition.call, definition.args || []);\n\n case \"condition\":\n return new Condition(attributes, definition.call, definition.args || []);\n\n case \"wait\":\n let duration: number | null = null;\n let durationMin: number | null = null;\n let durationMax: number | null = null;\n\n if (Array.isArray(definition.duration)) {\n durationMin = definition.duration[0];\n durationMax = definition.duration[1];\n } else if (isInteger(definition.duration)) {\n duration = definition.duration!;\n }\n\n return new Wait(attributes, duration, durationMin, durationMax);\n }\n}\n\n/**\n * Creates an array of node attribute instances based on the specified node definition.\n * @param definition The node definition.\n * @returns An array of node attribute instances based on the specified node definition.\n */\nfunction nodeAttributesFactory(definition: AnyNodeDefinition): Attribute[] {\n const attributes: Attribute[] = [];\n\n if (definition.while) {\n attributes.push(new While(definition.while.call, definition.while.args ?? []));\n }\n\n if (definition.until) {\n attributes.push(new Until(definition.until.call, definition.until.args ?? []));\n }\n\n if (definition.entry) {\n attributes.push(new Entry(definition.entry.call, definition.entry.args ?? []));\n }\n\n if (definition.step) {\n attributes.push(new Step(definition.step.call, definition.step.args ?? []));\n }\n\n if (definition.exit) {\n attributes.push(new Exit(definition.exit.call, definition.exit.args ?? []));\n }\n\n return attributes;\n}\n\n/**\n * Creates a mapping of root node identifers to root node definitions, mixing in globally registered subtree root node definitions.\n * @param definition The root node definitions.\n * @returns A mapping of root node identifers to root node definitions, including globally registered subtree root node definitions.\n */\nfunction createRootNodeDefinitionMap(definition: RootNodeDefinition[]): RootNodeDefinitionMap {\n // Create a mapping of root node identifers to root node definitions.\n const rootNodeMap: RootNodeDefinitionMap = {};\n\n // Add in any registered subtree root node definitions.\n for (const [name, rootNodeDefinition] of Object.entries(Lookup.getSubtrees())) {\n // The name used when registering the subtree will be used as the root node identifier.\n rootNodeMap[name] = { ...rootNodeDefinition, id: name };\n }\n\n // Populate the map with the root node definitions that were included with the tree definition.\n // We do this after adding any registered subtrees as we want these to take presedence.\n for (const rootNodeDefinition of definition) {\n rootNodeMap[rootNodeDefinition.id ?? MAIN_ROOT_NODE_KEY] = rootNodeDefinition;\n }\n\n return rootNodeMap;\n}\n\n/**\n * Applies a guard path to every leaf of the tree to evaluate as part of each update.\n * @param root The main root tree node.\n */\nfunction applyLeafNodeGuardPaths(root: Root) {\n const nodePaths: Node[][] = [];\n\n const findLeafNodes = (path: Node[], node: Node) => {\n // Add the current node to the path.\n path = path.concat(node);\n\n // Check whether the current node is a leaf node.\n if (node.isLeafNode()) {\n nodePaths.push(path);\n } else {\n (node as Composite | Decorator).getChildren().forEach((child) => findLeafNodes(path, child));\n }\n };\n\n // Find all leaf node paths, starting from the root.\n findLeafNodes([], root);\n\n nodePaths.forEach((path) => {\n // Each node in the current path will have to be assigned a guard path, working from the root outwards.\n for (let depth = 0; depth < path.length; depth++) {\n // Get the node in the path at the current depth.\n const currentNode = path[depth];\n\n // The node may already have been assigned a guard path, if so just skip it.\n if (currentNode.hasGuardPath()) {\n continue;\n }\n\n // Create the guard path for the current node.\n const guardPath = new GuardPath(\n path\n .slice(0, depth + 1)\n .map((node) => ({ node, guards: node.getGuardAttributes() }))\n .filter((details) => details.guards.length > 0)\n );\n\n // Assign the guard path to the current node.\n currentNode.setGuardPath(guardPath);\n }\n });\n}\n", "import State, { AnyState } from \"./State\";\nimport Lookup from \"./Lookup\";\nimport Node from \"./nodes/Node\";\nimport Root from \"./nodes/decorator/Root\";\nimport Composite from \"./nodes/composite/Composite\";\nimport Decorator from \"./nodes/decorator/Decorator\";\nimport { Agent, GlobalFunction } from \"./Agent\";\nimport { CallbackAttributeDetails } from \"./attributes/callbacks/Callback\";\nimport { GuardAttributeDetails } from \"./attributes/guards/Guard\";\nimport { BehaviourTreeOptions } from \"./BehaviourTreeOptions\";\nimport { convertMDSLToJSON } from \"./mdsl/MDSLDefinitionParser\";\nimport { RootNodeDefinition } from \"./BehaviourTreeDefinition\";\nimport { validateDefinition, validateJSONDefinition } from \"./BehaviourTreeDefinitionValidator\";\nimport buildRootNode from \"./BehaviourTreeBuilder\";\nimport { isNullOrUndefined } from \"./BehaviourTreeDefinitionUtilities\";\n\n// Purely for outside inspection of the tree.\nexport type FlattenedTreeNode = {\n id: string;\n type: string;\n caption: string;\n state: AnyState;\n guards: GuardAttributeDetails[];\n callbacks: CallbackAttributeDetails[];\n args: any[];\n parentId: string | null;\n};\n\n/**\n * A representation of a behaviour tree.\n */\nexport class BehaviourTree {\n /**\n * The main root tree node.\n */\n public readonly rootNode: Root;\n\n /**\n * Creates a new instance of the BehaviourTree class.\n * @param definition The behaviour tree definition.\n * @param agent The agent instance that this behaviour tree is modelling behaviour for.\n * @param options The behaviour tree options object.\n */\n constructor(\n definition: string | RootNodeDefinition | RootNodeDefinition[],\n private agent: Agent,\n private options: BehaviourTreeOptions = {}\n ) {\n // The tree definition must be defined.\n if (isNullOrUndefined(definition)) {\n throw new Error(\"tree definition not defined\");\n }\n\n // The agent must be defined and not null.\n if (typeof agent !== \"object\" || agent === null) {\n throw new Error(\"the agent must be an object and not null\");\n }\n\n // We should validate the definition before we try to build the tree nodes.\n const { succeeded, errorMessage } = validateDefinition(definition);\n\n // Did our validation fail without error?\n if (!succeeded) {\n throw new Error(`invalid definition: ${errorMessage}`);\n }\n\n try {\n // Parse the behaviour tree definition, create the populated tree of behaviour tree nodes, and get the root.\n this.rootNode = this._createRootNode(definition);\n } catch (exception) {\n // There was an issue in trying build and populate the behaviour tree.\n throw new Error(`error building tree: ${(exception as Error).message}`);\n }\n }\n\n /**\n * Gets whether the tree is in the RUNNING state.\n * @returns true if the tree is in the RUNNING state, otherwise false.\n */\n isRunning() {\n return this.rootNode.getState() === State.RUNNING;\n }\n\n /**\n * Gets the current tree state of SUCCEEDED, FAILED, READY or RUNNING.\n * @returns The current tree state.\n */\n getState() {\n return this.rootNode.getState();\n }\n\n /**\n * Step the tree.\n * 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.\n * 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\n * 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.\n *\n * 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.\n */\n step() {\n // If the root node has already been stepped to completion then we need to reset it.\n if (this.rootNode.getState() === State.SUCCEEDED || this.rootNode.getState() === State.FAILED) {\n this.rootNode.reset();\n }\n\n try {\n this.rootNode.update(this.agent, this.options);\n } catch (exception) {\n throw new Error(`error stepping tree: ${(exception as Error).message}`);\n }\n }\n\n /**\n * Resets the tree from the root node outwards to each nested node, giving each a state of READY.\n */\n reset() {\n this.rootNode.reset();\n }\n\n /**\n * Gets the flattened details of every node in the tree.\n * @returns The flattened details of every node in the tree.\n */\n getFlattenedNodeDetails(): FlattenedTreeNode[] {\n // Create an empty flattened array of tree nodes.\n const flattenedTreeNodes: FlattenedTreeNode[] = [];\n\n /**\n * Helper function to process a node instance and push details into the flattened tree nodes array.\n * @param node The current node.\n * @param parentUid The UID of the node parent, or null if the node is the main root node.\n */\n const processNode = (node: Node, parentUid: string | null) => {\n // Get the guard and callback attribute details for this node.\n const guards = node\n .getAttributes()\n .filter((attribute) => attribute.isGuard())\n .map((attribute) => attribute.getDetails()) as GuardAttributeDetails[];\n const callbacks = node\n .getAttributes()\n .filter((attribute) => !attribute.isGuard())\n .map((attribute) => attribute.getDetails()) as CallbackAttributeDetails[];\n\n // Push the current node into the flattened nodes array.\n flattenedTreeNodes.push({\n id: node.getUid(),\n type: node.getType(),\n caption: node.getName(),\n state: node.getState(),\n guards,\n callbacks,\n args: node.getArguments(),\n parentId: parentUid\n });\n\n // Process each of the nodes children if it is not a leaf node.\n if (!node.isLeafNode()) {\n (node as Composite | Decorator)\n .getChildren()\n .forEach((child) => processNode(child, (node as Composite | Decorator).getUid()));\n }\n };\n\n // Convert the nested node structure into a flattened array of node details.\n processNode(this.rootNode, null);\n\n return flattenedTreeNodes;\n }\n\n /**\n * Registers the action/condition/guard/callback function or subtree with the given name.\n * @param name The name of the function or subtree to register.\n * @param value The function or subtree definition to register.\n */\n static register(name: string, value: GlobalFunction | string | RootNodeDefinition) {\n // Are we going to register a action/condition/guard/callback function?\n if (typeof value === \"function\") {\n Lookup.setFunc(name, value);\n return;\n }\n\n // We are not registering an action/condition/guard/callback function, so we must be registering a subtree.\n if (typeof value === \"string\") {\n let rootNodeDefinitions: RootNodeDefinition[];\n\n // We will assume that any string passed in will be a mdsl definition.\n try {\n rootNodeDefinitions = convertMDSLToJSON(value);\n } catch (exception) {\n throw new Error(`error registering definition, invalid MDSL: ${(exception as Error).message}`);\n }\n\n // This function should only ever be called with a definition containing a single unnamed root node.\n if (rootNodeDefinitions.length != 1 || rootNodeDefinitions[0].id !== null) {\n throw new Error(\"error registering definition: expected a single unnamed root node\");\n }\n\n try {\n // We should validate the subtree as we don't want invalid subtrees available via the lookup.\n const { succeeded, errorMessage } = validateJSONDefinition(rootNodeDefinitions[0]);\n\n // Did our validation fail without error?\n if (!succeeded) {\n throw new Error(errorMessage);\n }\n } catch (exception) {\n throw new Error(`error registering definition: ${(exception as Error).message}`);\n }\n\n // Everything seems hunky-dory, register the subtree.\n Lookup.setSubtree(name, rootNodeDefinitions[0]);\n } else if (typeof value === \"object\" && !Array.isArray(value)) {\n // We will assume that any object passed in is a root node definition.\n\n try {\n // We should validate the subtree as we don't want invalid subtrees available via the lookup.\n const { succeeded, errorMessage } = validateJSONDefinition(value);\n\n // Did our validation fail without error?\n if (!succeeded) {\n throw new Error(errorMessage);\n }\n } catch (exception) {\n throw new Error(`error registering definition: ${(exception as Error).message}`);\n }\n\n // Everything seems hunky-dory, register the subtree.\n Lookup.setSubtree(name, value);\n } else {\n throw new Error(\"unexpected value, expected string mdsl definition, root node json definition or function\");\n }\n }\n\n /**\n * Unregisters the registered action/condition/guard/callback function or subtree with the given name.\n * @param name The name of the registered action/condition/guard/callback function or subtree to unregister.\n */\n static unregister(name: string): void {\n Lookup.remove(name);\n }\n\n /**\n * Unregister all registered action/condition/guard/callback functions and subtrees.\n */\n static unregisterAll(): void {\n Lookup.empty();\n }\n\n /**\n * Parses a behaviour tree definition and creates a tree of behaviour tree nodes populated at a root.\n * @param {string | RootNodeDefinition | RootNodeDefinition[]} definition The behaviour tree definition.\n * @returns The root behaviour tree node.\n */\n private _createRootNode(definition: string | RootNodeDefinition | RootNodeDefinition[]): Root {\n // Our definition will have to be converted to JSON if it is a MDSL string.\n // TODO convertMDSLToJSON is called TWICE, once for validation and once here. Maybe return the JSON as part of the validation result?\n const resolvedDefinition = typeof definition === \"string\" ? convertMDSLToJSON(definition) : definition;\n\n // Build and populate the root node.\n return buildRootNode(Array.isArray(resolvedDefinition) ? resolvedDefinition : [resolvedDefinition]);\n }\n}\n"], - "mappings": "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", + "sourcesContent": ["\"use strict\";\r\nObject.defineProperty(exports, \"__esModule\", { value: true });\r\nexports.Participant = void 0;\r\n/**\r\n * A participant that holds a number of tickets.\r\n */\r\nvar Participant = /** @class */ (function () {\r\n /**\r\n * Creates an instance of the Participant class.\r\n * @param participant The actual participant.\r\n * @param tickets The number of tickets held by the participant.\r\n */\r\n function Participant(participant, tickets) {\r\n if (tickets === void 0) { tickets = 1; }\r\n this._participant = participant;\r\n this._tickets = tickets;\r\n }\r\n Object.defineProperty(Participant.prototype, \"participant\", {\r\n /** Gets the actual participant. */\r\n get: function () {\r\n return this._participant;\r\n },\r\n enumerable: false,\r\n configurable: true\r\n });\r\n Object.defineProperty(Participant.prototype, \"tickets\", {\r\n /** Gets or sets the number of tickets held by the participant. */\r\n get: function () {\r\n return this._tickets;\r\n },\r\n set: function (value) {\r\n this._tickets = value;\r\n },\r\n enumerable: false,\r\n configurable: true\r\n });\r\n return Participant;\r\n}());\r\nexports.Participant = Participant;\r\n", "\"use strict\";\r\nObject.defineProperty(exports, \"__esModule\", { value: true });\r\nexports.isNaturalNumber = exports.isNullOrUndefined = void 0;\r\n/**\r\n * Gets whether the value provided is null or undefined.\r\n * @param value The value to check.\r\n * @returns Whether the value provided is null or undefined.\r\n */\r\nfunction isNullOrUndefined(value) {\r\n return value === null || value === undefined;\r\n}\r\nexports.isNullOrUndefined = isNullOrUndefined;\r\n/**\r\n * Gets whether the value provided is a natural number.\r\n * @param value The value to check.\r\n * @returns Whether the value provided is a natural number.\r\n */\r\nfunction isNaturalNumber(value) {\r\n return typeof value === \"number\" && value >= 1 && Math.floor(value) === value;\r\n}\r\nexports.isNaturalNumber = isNaturalNumber;\r\n", "\"use strict\";\r\nObject.defineProperty(exports, \"__esModule\", { value: true });\r\nexports.Lotto = void 0;\r\nvar Participant_1 = require(\"./Participant\");\r\nvar Utilities_1 = require(\"./Utilities\");\r\n/**\r\n * Represents a lotto consisting of a number of pickable ticket-holding participants.\r\n */\r\nvar Lotto = /** @class */ (function () {\r\n /**\r\n * Creates a new instance of Lotto.\r\n * @param customRandom The custom RNG to use in place of Math.random().\r\n */\r\n function Lotto(customRandom) {\r\n /** The array of participants that are holding tickets in the lotto. */\r\n this._participants = [];\r\n this._customRandom = customRandom;\r\n }\r\n /**\r\n * Adds a participant with the specified number of tickets, or adds to the participant ticket count if the participant already holds tickets.\r\n * @param participant The participant to add or to increase the ticket count for if they already hold tickets.\r\n * @param tickets The number of tickets, defaults to 1.\r\n * @returns The Lotto instance.\r\n */\r\n Lotto.prototype.add = function (participant, tickets) {\r\n if (tickets === void 0) { tickets = 1; }\r\n // Check that we have a valid ticket count.\r\n if (!(0, Utilities_1.isNaturalNumber)(tickets)) {\r\n throw new Error(\"tickets value must be a natural number\");\r\n }\r\n // Check whether this participant has already been added.\r\n var existingParticipant = this._participants.find(function (part) { return part.participant === participant; });\r\n if (existingParticipant) {\r\n // The participant has already been added to the lotto so just add to their ticket count.\r\n existingParticipant.tickets += tickets;\r\n }\r\n else {\r\n // The participant is not part of the lotto so we should add them.\r\n this._participants.push(new Participant_1.Participant(participant, tickets));\r\n }\r\n return this;\r\n };\r\n /**\r\n * Removes the specified number of tickets for the given participant from the draw, or all tickets if a ticket number is not defined.\r\n * @param participant The participant to remove tickets for.\r\n * @param tickets The number of tickets to remove, or undefined if all tickets are to be removed.\r\n * @returns The Lotto instance.\r\n */\r\n Lotto.prototype.remove = function (participant, tickets) {\r\n // Attempt to get the existing participant.\r\n var existingParticipant = this._participants.find(function (part) { return part.participant === participant; });\r\n // There is nothing to do if the specified participant isn't even part of the lotto.\r\n if (!existingParticipant) {\r\n return this;\r\n }\r\n // Check whether a tickets value was given.\r\n if (tickets !== undefined) {\r\n // Check that we have a valid ticket count.\r\n if (!(0, Utilities_1.isNaturalNumber)(tickets)) {\r\n throw new Error(\"tickets value must be a natural number\");\r\n }\r\n existingParticipant.tickets -= tickets;\r\n // If the participant no longer holds any tickets then they should be removed.\r\n if (existingParticipant.tickets < 1) {\r\n this._participants = this._participants.filter(function (part) { return part !== existingParticipant; });\r\n }\r\n }\r\n else {\r\n // We are removing all tickets for the participant so just remove them from the lotto.\r\n this._participants = this._participants.filter(function (part) { return part !== existingParticipant; });\r\n }\r\n return this;\r\n };\r\n /**\r\n * Draw a winning ticket and return the participant that holds the ticket.\r\n * @param options The draw options.\r\n * @returns The participant that holds the winning ticket.\r\n */\r\n Lotto.prototype.draw = function (options) {\r\n if (options === void 0) { options = {}; }\r\n // If we have no participants then just return null.\r\n if (this._participants.length === 0) {\r\n return null;\r\n }\r\n var redrawable = (0, Utilities_1.isNullOrUndefined)(options.redrawable) ? true : options.redrawable;\r\n var pickable = [];\r\n this._participants.forEach(function (_a) {\r\n var participant = _a.participant, tickets = _a.tickets;\r\n for (var ticketCount = 0; ticketCount < tickets; ticketCount++) {\r\n pickable.push(participant);\r\n }\r\n });\r\n var random;\r\n // We need a random floating-point number between 0 (inclusive) and 1 to scale up to pick our winner.\r\n // If a custom random function exists then we should use that or fall back to Math.random().\r\n if (this._customRandom) {\r\n // Call our custom random function to get a random floating-point number.\r\n random = this._customRandom();\r\n // Verify that the result of calling our custom random function is a number between 0 (inclusive) and 1.\r\n if (typeof random !== \"number\" || random < 0 || random >= 1) {\r\n throw new Error(\"the 'random' function provided did not return a number between 0 (inclusive) and 1\");\r\n }\r\n }\r\n else {\r\n // No custom random function was defined so just use good ol' Math.random().\r\n random = Math.random();\r\n }\r\n // Pick a winning participant.\r\n var winner = pickable[Math.floor(random * pickable.length)];\r\n // If the ticket isn't redrawable then we should remove a ticket from the winning participants ticket count.\r\n if (!redrawable) {\r\n this.remove(winner, 1);\r\n }\r\n // Return the winning participant.\r\n return winner;\r\n };\r\n /**\r\n * Draws multiple winning tickets and return an array of the participants that hold the winning tickets.\r\n * @param tickets The number of winning tickets to draw.\r\n * @param options The draw multiple options.\r\n * @returns An array of the participants that hold the winning tickets.\r\n */\r\n Lotto.prototype.drawMultiple = function (tickets, options) {\r\n if (options === void 0) { options = {}; }\r\n var uniqueResults = (0, Utilities_1.isNullOrUndefined)(options.unique) ? false : options.unique;\r\n // Handle cases where the user has asked for zero tickets (no idea why they would do this be we should trust them).\r\n if (tickets === 0) {\r\n return [];\r\n }\r\n // Now that we know out tickets value is not zero we should check that it is a valid natural number.\r\n if (!(0, Utilities_1.isNaturalNumber)(tickets)) {\r\n throw new Error(\"tickets value must be a natural number\");\r\n }\r\n var result = [];\r\n // Keep drawing tickets until we either reach the number of required tickets or we simply run out of tickets to draw.\r\n // We can run out of tickets to draw if 'options.redrawable' is explicity 'false' or we just had no participants when 'drawMultiple' was called.\r\n while (result.length < tickets && this._participants.length > 0) {\r\n result.push(this.draw(options));\r\n }\r\n // If the 'unique' draw option is set then we need to remove duplicates from the result list.\r\n if (uniqueResults) {\r\n // Create an array to store our unique results.\r\n var unique = [];\r\n // Iterate over all of our participants (with potential duplicates) and populate our array of unique values.\r\n for (var _i = 0, result_1 = result; _i < result_1.length; _i++) {\r\n var participant = result_1[_i];\r\n if (unique.indexOf(participant) === -1) {\r\n unique.push(participant);\r\n }\r\n }\r\n result = unique;\r\n }\r\n return result;\r\n };\r\n return Lotto;\r\n}());\r\nexports.Lotto = Lotto;\r\n", "\"use strict\";\r\nObject.defineProperty(exports, \"__esModule\", { value: true });\r\nexports.createLotto = void 0;\r\nvar Lotto_1 = require(\"./Lotto\");\r\n/**\r\n * A function that creates and returns a Lotto instance.\r\n * @param participantsOrOptions An array of initial participants or options relating to the creation of a Lotto instance.\r\n * @returns A new Lotto instance.\r\n */\r\nfunction createLotto(participantsOrOptions) {\r\n // If no initial participants or lotto options were provided as an argument then we can just return a new lotto instance now.\r\n if (!participantsOrOptions) {\r\n return new Lotto_1.Lotto();\r\n }\r\n // Check whether we were provided with an array of initial participants or a lotto options object.\r\n if (Array.isArray(participantsOrOptions)) {\r\n // We are dealing with a pre-defined array of participants.\r\n var participants = participantsOrOptions;\r\n var lotto_1 = new Lotto_1.Lotto();\r\n // If the lotto participants have been defined upfront then we will need to add them all to our lotto instance now.\r\n participants.forEach(function (_a) {\r\n var participant = _a[0], tokens = _a[1];\r\n return lotto_1.add(participant, tokens);\r\n });\r\n // Return the Lotto instance.\r\n return lotto_1;\r\n }\r\n else {\r\n // We are dealing with some lotto options.\r\n var random = participantsOrOptions.random, participants = participantsOrOptions.participants;\r\n // Create a Lotto instance passing the custom RNG function to use in place of Math.random() (which could be undefined).\r\n var lotto_2 = new Lotto_1.Lotto(random);\r\n // If the lotto participants have been defined upfront as part of the options then we will need to add them all to our lotto instance now.\r\n if (participants) {\r\n participants.forEach(function (_a) {\r\n var participant = _a[0], tokens = _a[1];\r\n return lotto_2.add(participant, tokens);\r\n });\r\n }\r\n // Return the Lotto instance.\r\n return lotto_2;\r\n }\r\n}\r\nexports.createLotto = createLotto;\r\n", "\"use strict\";\r\nObject.defineProperty(exports, \"__esModule\", { value: true });\r\nvar createLotto_1 = require(\"./createLotto\");\r\nexports.default = createLotto_1.createLotto;\r\n", "import State from \"./State\";\nimport { validateDefinition } from \"./BehaviourTreeDefinitionValidator\";\nimport { convertMDSLToJSON } from \"./mdsl/MDSLDefinitionParser\";\nimport { BehaviourTree, FlattenedTreeNode } from \"./BehaviourTree\";\nimport { BehaviourTreeOptions } from \"./BehaviourTreeOptions\";\n\nexport { BehaviourTree, State, convertMDSLToJSON, validateDefinition };\nexport type { FlattenedTreeNode, BehaviourTreeOptions };\n", "/**\n * Enumeration of node state types.\n */\nexport enum State {\n READY = \"mistreevous.ready\",\n RUNNING = \"mistreevous.running\",\n SUCCEEDED = \"mistreevous.succeeded\",\n FAILED = \"mistreevous.failed\"\n}\n\nexport { State as default };\n\nexport type CompleteState = State.SUCCEEDED | State.FAILED;\nexport type AnyState = State.READY | State.RUNNING | CompleteState;\n", "import {\n NodeDefinition,\n RootNodeDefinition,\n DecoratorNodeDefinition,\n CompositeNodeDefinition,\n AnyNodeDefinition,\n BranchNodeDefinition\n} from \"./BehaviourTreeDefinition\";\n\n/**\n * A type guard function that returns true if the specified node satisfies the RootNodeDefinition type.\n * @param node The node.\n * @returns A value of true if the specified node satisfies the RootNodeDefinition type.\n */\nexport function isRootNode(node: NodeDefinition): node is RootNodeDefinition {\n return node.type === \"root\";\n}\n\n/**\n * A type guard function that returns true if the specified node satisfies the BranchNodeDefinition type.\n * @param node The node.\n * @returns A value of true if the specified node satisfies the BranchNodeDefinition type.\n */\nexport function isBranchNode(node: NodeDefinition): node is BranchNodeDefinition {\n return node.type === \"branch\";\n}\n\n/**\n * A type guard function that returns true if the specified node satisfies the NodeDefinition type.\n * @param node The node.\n * @returns A value of true if the specified node satisfies the NodeDefinition type.\n */\nexport function isLeafNode(node: NodeDefinition): node is NodeDefinition {\n return [\"branch\", \"action\", \"condition\", \"wait\"].includes(node.type);\n}\n\n/**\n * A type guard function that returns true if the specified node satisfies the DecoratorNodeDefinition type.\n * @param node The node.\n * @returns A value of true if the specified node satisfies the DecoratorNodeDefinition type.\n */\nexport function isDecoratorNode(node: NodeDefinition): node is DecoratorNodeDefinition {\n return [\"root\", \"repeat\", \"retry\", \"flip\", \"succeed\", \"fail\"].includes(node.type);\n}\n\n/**\n * A type guard function that returns true if the specified node satisfies the CompositeNodeDefinition type.\n * @param node The node.\n * @returns A value of true if the specified node satisfies the CompositeNodeDefinition type.\n */\nexport function isCompositeNode(node: NodeDefinition): node is CompositeNodeDefinition {\n return [\"sequence\", \"selector\", \"lotto\", \"parallel\"].includes(node.type);\n}\n\n/**\n * Flatten a node definition into an array of all of its nested node definitions.\n * @param nodeDefinition The node definition to flatten.\n * @returns An array of all of nested node definitions.\n */\nexport function flattenDefinition(nodeDefinition: AnyNodeDefinition): AnyNodeDefinition[] {\n const nodes: AnyNodeDefinition[] = [];\n\n const processNode = (currentNodeDefinition: AnyNodeDefinition) => {\n nodes.push(currentNodeDefinition);\n\n if (isCompositeNode(currentNodeDefinition)) {\n currentNodeDefinition.children.forEach(processNode);\n } else if (isDecoratorNode(currentNodeDefinition)) {\n processNode(currentNodeDefinition.child);\n }\n };\n\n processNode(nodeDefinition);\n\n return nodes;\n}\n\n/**\n * Determines whether the passed value is an integer.\n * @param value The value to check.\n * @returns Whether the passed value is an integer.\n */\nexport function isInteger(value: unknown): boolean {\n return typeof value === \"number\" && Math.floor(value) === value;\n}\n\n/**\n * Determines whether the passed value is null or undefined.\n * @param value The value to check.\n * @returns Whether the passed value is null or undefined.\n */\nexport function isNullOrUndefined(value: unknown): boolean {\n return typeof value === \"undefined\" || value === null;\n}\n", "/**\n * A type defining an object that holds a reference to substitued string literals parsed from the definition.\n */\nexport type StringLiteralPlaceholders = { [key: string]: string };\n\n/**\n * Pop the next raw token from the specified array of tokens and throw an error if it wasn't the expected one.\n * @param tokens The array of tokens.\n * @param expected An optional string or array or items, one of which must match the next popped token.\n * @returns The popped token.\n */\nexport function popAndCheck(tokens: string[], expected?: string | string[]): string {\n // Get and remove the next token.\n const popped = tokens.shift();\n\n // We were expecting another token but there aren't any.\n if (popped === undefined) {\n throw new Error(\"unexpected end of definition\");\n }\n\n // Do we have an expected token/tokens array?\n if (expected != undefined) {\n // Get an array of expected values, if the popped token matches any then we are all good.\n const expectedValues = typeof expected === \"string\" ? [expected] : expected;\n\n // Check whether the popped token matches at least one of our expected items.\n var tokenMatchesExpectation = expectedValues.some((item) => popped.toUpperCase() === item.toUpperCase());\n\n // Throw an error if the popped token didn't match any of our expected items.\n if (!tokenMatchesExpectation) {\n const expectationString = expectedValues.map((item) => \"'\" + item + \"'\").join(\" or \");\n throw new Error(\"unexpected token found. Expected \" + expectationString + \" but got '\" + popped + \"'\");\n }\n }\n\n // Return the popped token.\n return popped;\n}\n\n/**\n * Swaps out any node/attribute argument string literals with placeholders.\n * @param definition The definition.\n * @returns An object containing a mapping of placeholders to original string values as well as the processed definition string.\n */\nexport function substituteStringLiterals(definition: string): {\n placeholders: StringLiteralPlaceholders;\n processedDefinition: string;\n} {\n // Create an object to hold the mapping of placeholders to original string values.\n const placeholders: StringLiteralPlaceholders = {};\n\n // Replace any string literals wrapped with double quotes in our definition with placeholders to be processed later.\n const processedDefinition = definition.replace(/\\\"(\\\\.|[^\"\\\\])*\\\"/g, (match) => {\n var strippedMatch = match.substring(1, match.length - 1);\n var placeholder = Object.keys(placeholders).find((key) => placeholders[key] === strippedMatch);\n\n // If we have no existing string literal match then create a new placeholder.\n if (!placeholder) {\n placeholder = `@@${Object.keys(placeholders).length}@@`;\n placeholders[placeholder] = strippedMatch;\n }\n\n return placeholder;\n });\n\n return { placeholders, processedDefinition };\n}\n\n/**\n * Parse the tree definition into an array of raw tokens.\n * @param definition The definition.\n * @returns An array of tokens parsed from the definition.\n */\nexport function parseTokensFromDefinition(definition: string): string[] {\n // Add some space around various important characters so that they can be plucked out easier as individual tokens.\n definition = definition.replace(/\\(/g, \" ( \");\n definition = definition.replace(/\\)/g, \" ) \");\n definition = definition.replace(/\\{/g, \" { \");\n definition = definition.replace(/\\}/g, \" } \");\n definition = definition.replace(/\\]/g, \" ] \");\n definition = definition.replace(/\\[/g, \" [ \");\n definition = definition.replace(/\\,/g, \" , \");\n\n // Split the definition into raw token form and return it.\n return definition.replace(/\\s+/g, \" \").trim().split(\" \");\n}\n", "import { StringLiteralPlaceholders, popAndCheck } from \"./MDSLUtilities\";\n\n/**\n * A type representing any node function argument.\n */\ntype Argument = {\n /**\n * The argument value.\n */\n value: T;\n /**\n * The argument type, used for validation.\n */\n type: string;\n};\n\ntype NullArgument = Argument & {\n type: \"null\";\n};\n\ntype BooleanArgument = Argument & {\n type: \"boolean\";\n};\n\ntype NumberArgument = Argument & {\n type: \"number\";\n /**\n * A flag defining whether the number argument value is a valid integer. (used for validation)\n */\n isInteger: boolean;\n};\n\ntype StringPlaceholderArgument = Argument & {\n type: \"string\";\n};\n\ntype IdentifierArgument = Argument & {\n type: \"identifier\";\n};\n\n/**\n * A type representing a reference to any node function argument.\n */\ntype AnyArgument = NullArgument | BooleanArgument | NumberArgument | StringPlaceholderArgument | IdentifierArgument;\n\n/**\n * Parse an array of argument definitions from the specified tokens array.\n * @param tokens The array tokens to parse the argument definitions from.\n * @param stringArgumentPlaceholders The mapping of string literal node argument placeholders to original values.\n * @param argumentValidator The argument validator function.\n * @param validationFailedMessage The exception message to throw if argument validation fails.\n * @returns An array of argument definitions parsed from the specified tokens array.\n */\nexport function parseArgumentTokens(\n tokens: string[],\n stringArgumentPlaceholders: StringLiteralPlaceholders\n): AnyArgument[] {\n const argumentList: AnyArgument[] = [];\n\n // If the next token is not a '[' or '(' then we have no arguments to parse.\n if (![\"[\", \"(\"].includes(tokens[0])) {\n return argumentList;\n }\n\n // Any lists of arguments will always be wrapped in '[]' for node arguments or '()' for attribute arguments.\n // We are looking for a '[' or '(' opener that wraps the argument tokens and the relevant closer.\n const closingToken = popAndCheck(tokens, [\"[\", \"(\"]) === \"[\" ? \"]\" : \")\";\n\n const argumentListTokens: string[] = [];\n\n // Grab all tokens between the '[' and ']' or '(' and ')'.\n while (tokens.length && tokens[0] !== closingToken) {\n // The next token is part of our arguments list.\n argumentListTokens.push(tokens.shift()!);\n }\n\n // Validate the order of the argument tokens. Each token must either be a ',' or a single argument that satisfies the validator.\n argumentListTokens.forEach((token, index) => {\n // Get whether this token should be an actual argument.\n const shouldBeArgumentToken = !(index & 1);\n\n // If the current token should be an actual argument then validate it, otherwise it should be a ',' token.\n if (shouldBeArgumentToken) {\n // Get the argument definition.\n const argumentDefinition = getArgumentDefinition(token, stringArgumentPlaceholders);\n\n // This is a valid argument!\n argumentList.push(argumentDefinition);\n } else {\n // The current token should be a ',' token.\n if (token !== \",\") {\n throw new Error(`invalid argument list, expected ',' or ']' but got '${token}'`);\n }\n }\n });\n\n // The arguments list should terminate with a ']' or ')' token, depending on the opener.\n popAndCheck(tokens, closingToken);\n\n // Return the arguments.\n return argumentList;\n}\n\n/**\n * Gets an argument value definition.\n * @param token The argument token.\n * @param stringArgumentPlaceholders The mapping of string literal node argument placeholders to original values.\n * @returns An argument value definition.\n */\nfunction getArgumentDefinition(token: string, stringArgumentPlaceholders: StringLiteralPlaceholders): AnyArgument {\n // Check whether the token represents a null value.\n if (token === \"null\") {\n return {\n value: null,\n type: \"null\"\n } as NullArgument;\n }\n\n // Check whether the token represents a boolean value.\n if (token === \"true\" || token === \"false\") {\n return {\n value: token === \"true\",\n type: \"boolean\"\n } as BooleanArgument;\n }\n\n // Check whether the token represents a number value.\n // TODO: Relies on broken isNaN - see MDN.\n // if (!Number.isNaN(token)) {\n if (!isNaN(token as any)) {\n return {\n value: parseFloat(token),\n isInteger: parseFloat(token) === parseInt(token, 10),\n type: \"number\"\n } as NumberArgument;\n }\n\n // Check whether the token is a placeholder (e.g. @@0@@) representing a string literal.\n if (token.match(/^@@\\d+@@$/g)) {\n return {\n value: stringArgumentPlaceholders[token].replace('\\\\\"', '\"'),\n type: \"string\"\n } as StringPlaceholderArgument;\n }\n\n // The only remaining option is that the argument value is an identifier.\n return {\n value: token,\n type: \"identifier\"\n } as IdentifierArgument;\n}\n", "import { NodeAttributeDefinition } from \"../BehaviourTreeDefinition\";\nimport { parseArgumentTokens } from \"./MDSLNodeArgumentParser\";\nimport { StringLiteralPlaceholders } from \"./MDSLUtilities\";\n\n/**\n * A type defining the attribute definitions of a node.\n */\ntype NodeAttributes = {\n while?: NodeAttributeDefinition;\n until?: NodeAttributeDefinition;\n entry?: NodeAttributeDefinition;\n exit?: NodeAttributeDefinition;\n step?: NodeAttributeDefinition;\n};\n\n/**\n * Parse any node attribute definitions from the specified tokens array.\n * @param tokens The array of remaining tokens.\n * @param stringArgumentPlaceholders The mapping of string literal node argument placeholders to original values.\n * @returns An object of attribute definitions defined by any directly following tokens.\n */\nexport function parseAttributeTokens(\n tokens: string[],\n stringArgumentPlaceholders: StringLiteralPlaceholders\n): NodeAttributes {\n const nodeAttributeNames: (keyof NodeAttributes)[] = [\"while\", \"until\", \"entry\", \"exit\", \"step\"];\n\n // Create an object to hold any attributes found.\n const attributes: NodeAttributes = {};\n\n // Try to get the name of the attribute for the next token.\n let nextAttributeName = tokens[0]?.toLowerCase() as keyof NodeAttributes;\n\n // Pull attribute tokens as well as their arguments off of the tokens stack until we have no more.\n while (nodeAttributeNames.includes(nextAttributeName)) {\n // Check to make sure that we have not already created an attribute definition of this type.\n if (attributes[nextAttributeName]) {\n throw new Error(`duplicate attribute '${tokens[0].toUpperCase()}' found for node`);\n }\n\n // Remove the attribute name token from the array of tokens.\n tokens.shift();\n\n // Grab the attribute arguments, assuming the first to be an identifier.\n const [attributeCallIdentifier, ...attributeArguments] = parseArgumentTokens(\n tokens,\n stringArgumentPlaceholders\n );\n\n // The first attribute argument has to be an identifer, this will reference an agent function.\n if (attributeCallIdentifier?.type !== \"identifier\") {\n throw new Error(\"expected agent function name identifier argument for attribute\");\n }\n\n // Any attribute arguments (other than the expected call identifier) must have a type of string, number, boolean or null.\n attributeArguments\n .filter((arg) => arg.type === \"identifier\")\n .forEach((arg) => {\n throw new Error(\n `invalid attribute argument value '${arg.value}', must be string, number, boolean or null`\n );\n });\n\n // Create the attribute definition and add it to the object of attribute definitions found.\n attributes[nextAttributeName] = {\n call: attributeCallIdentifier.value,\n args: attributeArguments.map(({ value }) => value)\n };\n\n // Try to get the next attribute name token, as there could be multiple.\n nextAttributeName = tokens[0]?.toLowerCase() as keyof NodeAttributes;\n }\n\n return attributes;\n}\n", "import {\n ActionNodeDefinition,\n AnyChildNodeDefinition,\n AnyNodeDefinition,\n BranchNodeDefinition,\n ConditionNodeDefinition,\n FailNodeDefinition,\n FlipNodeDefinition,\n LottoNodeDefinition,\n ParallelNodeDefinition,\n RepeatNodeDefinition,\n RetryNodeDefinition,\n RootNodeDefinition,\n SelectorNodeDefinition,\n SequenceNodeDefinition,\n SucceedNodeDefinition,\n WaitNodeDefinition\n} from \"../BehaviourTreeDefinition\";\nimport {\n isCompositeNode,\n isDecoratorNode,\n isLeafNode,\n isNullOrUndefined,\n isRootNode\n} from \"../BehaviourTreeDefinitionUtilities\";\nimport { parseArgumentTokens } from \"./MDSLNodeArgumentParser\";\nimport { parseAttributeTokens } from \"./MDSLNodeAttributeParser\";\nimport {\n StringLiteralPlaceholders,\n parseTokensFromDefinition,\n popAndCheck,\n substituteStringLiterals\n} from \"./MDSLUtilities\";\n\n/**\n * Convert the MDSL tree definition string into an equivalent JSON definition.\n * @param definition The tree definition string as MDSL.\n * @returns The root node JSON definitions.\n */\nexport function convertMDSLToJSON(definition: string): RootNodeDefinition[] {\n // Swap out any node/attribute argument string literals with a placeholder and get a mapping of placeholders to original values as well as the processed definition.\n const { placeholders, processedDefinition } = substituteStringLiterals(definition);\n\n // Parse our definition definition string into an array of raw tokens.\n const tokens = parseTokensFromDefinition(processedDefinition);\n\n return convertTokensToJSONDefinition(tokens, placeholders);\n}\n\n/**\n * Converts the specified tree definition tokens into a JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The root node JSON definitions.\n */\nfunction convertTokensToJSONDefinition(\n tokens: string[],\n stringLiteralPlaceholders: StringLiteralPlaceholders\n): RootNodeDefinition[] {\n // There must be at least 3 tokens for the tree definition to be valid. 'ROOT', '{' and '}'.\n if (tokens.length < 3) {\n throw new Error(\"invalid token count\");\n }\n\n // We should have a matching number of '{' and '}' tokens. If not, then there are scopes that have not been properly closed.\n if (tokens.filter((token) => token === \"{\").length !== tokens.filter((token) => token === \"}\").length) {\n throw new Error(\"scope character mismatch\");\n }\n\n // Create an array of tree stack arrays where root nodes will always be at the botton and the current composite/decorator node at the top.\n // There should be an element in this array for every root node defined and every element should be an array with a root note as the first element.\n // E.g. A definition with two root nodes defined:\n // [\n // [root, lotto, sequence],\n // [root, selector]\n // ]\n const treeStacks: [Partial, ...Partial[]][] = [];\n\n // Create an array of all root node definitions that we create.\n const rootNodes: Partial[] = [];\n\n // A helper function used to push node definitions onto the tree stack.\n const pushNode = (node: AnyNodeDefinition) => {\n // If the node is a root node then we need to create a new tree stack array with the root node at the root.\n if (isRootNode(node)) {\n // We need to double-check that this root node is not the child of another node.\n // We can do this by checking whether the top tree stack is not empty (contains an existing node)\n if (treeStacks[treeStacks.length - 1]?.length) {\n throw new Error(\"a root node cannot be the child of another node\");\n }\n\n // Add the root node definition to our array of all parsed root node definitions.\n rootNodes.push(node);\n\n // Add the root node definition to the root of a new tree stack.\n treeStacks.push([node]);\n\n return;\n }\n\n // All non-root nodes should be pushed after their root nodes so handle cases\n // where we may not have any tree stacks or our top-most tree stack is empty.\n if (!treeStacks.length || !treeStacks[treeStacks.length - 1].length) {\n throw new Error(\"expected root node at base of definition\");\n }\n\n // Get the current tree stack that we are populating.\n const topTreeStack = treeStacks[treeStacks.length - 1];\n\n // Get the top-most node in the current tree stack, this will be a composite/decorator node\n // for which we will populate its children array if composite or setting its child if a decorator.\n const topTreeStackTopNode = topTreeStack[topTreeStack.length - 1] as AnyNodeDefinition;\n\n // If the top-most node in the current root stack is a composite or decorator\n // node then the current node should be added as a child of the top-most node.\n if (isCompositeNode(topTreeStackTopNode)) {\n topTreeStackTopNode.children = topTreeStackTopNode.children || [];\n topTreeStackTopNode.children.push(node);\n } else if (isDecoratorNode(topTreeStackTopNode)) {\n // If the top node already has a child node set then throw an error as a decorator should only have a single child.\n if (topTreeStackTopNode.child) {\n throw new Error(\"a decorator node must only have a single child node\");\n }\n\n topTreeStackTopNode.child = node;\n }\n\n // If the node we are adding is also a composite or decorator node, then we should push it\n // onto the current tree stack, as subsequent nodes will be added as its child/children.\n if (!isLeafNode(node)) {\n topTreeStack.push(node);\n }\n };\n\n // A helper function used to pop the top-most node definition off of the tree stack and return it.\n const popNode = (): AnyNodeDefinition | null => {\n let poppedNode: AnyNodeDefinition | null = null;\n\n // Get the current tree stack that we are populating.\n const topTreeStack = treeStacks[treeStacks.length - 1];\n\n // Pop the top-most node in the current tree stack if there is one.\n if (topTreeStack.length) {\n poppedNode = topTreeStack.pop() as AnyNodeDefinition;\n }\n\n // We don't want any empty tree stacks in our stack of tree stacks.\n if (!topTreeStack.length) {\n treeStacks.pop();\n }\n\n return poppedNode;\n };\n\n // We should keep processing the raw tokens until we run out of them.\n while (tokens.length) {\n // Grab the next token.\n const token = tokens.shift()!;\n\n // How we create the next node depends on the current raw token value.\n switch (token.toUpperCase()) {\n case \"ROOT\": {\n pushNode(createRootNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"SUCCEED\": {\n pushNode(createSucceedNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"FAIL\": {\n pushNode(createFailNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"FLIP\": {\n pushNode(createFlipNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"REPEAT\": {\n pushNode(createRepeatNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"RETRY\": {\n pushNode(createRetryNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"SEQUENCE\": {\n pushNode(createSequenceNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"SELECTOR\": {\n pushNode(createSelectorNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"PARALLEL\": {\n pushNode(createParallelNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"LOTTO\": {\n pushNode(createLottoNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"ACTION\": {\n pushNode(createActionNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"CONDITION\": {\n pushNode(createConditionNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"WAIT\": {\n pushNode(createWaitNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"BRANCH\": {\n pushNode(createBranchNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"}\": {\n // The '}' character closes the current scope and means that we have to pop a node off of the current stack.\n const poppedNode = popNode();\n\n // Now that we have a node definition we can carry out any validation that may require the node to be fully populated.\n if (poppedNode) {\n validatePoppedNode(poppedNode);\n }\n\n break;\n }\n\n default: {\n throw new Error(`unexpected token: ${token}`);\n }\n }\n }\n\n return rootNodes as RootNodeDefinition[];\n}\n\n/**\n * Creates a root node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The root node JSON definition.\n */\nfunction createRootNode(tokens: string[], stringLiteralPlaceholders: StringLiteralPlaceholders): RootNodeDefinition {\n // Create the root node definition.\n let node = {\n type: \"root\",\n id: undefined\n } as RootNodeDefinition;\n\n // Parse any node arguments, we should only have one if any which will be an identifier argument for the root identifier.\n const nodeArguments = parseArgumentTokens(tokens, stringLiteralPlaceholders);\n\n // Check whether any node arguments were defined.\n if (nodeArguments.length) {\n // We should only have one argument, if any, which will be an identifier argument for the root identifier.\n if (nodeArguments.length === 1 && nodeArguments[0].type === \"identifier\") {\n // The root node identifier will be the first and only node argument value.\n node.id = nodeArguments[0].value as string;\n } else {\n throw new Error(\"expected single root name argument\");\n }\n }\n\n // Grab any node attribute definitions and spread them into the node definition.\n node = { ...node, ...parseAttributeTokens(tokens, stringLiteralPlaceholders) };\n\n // This is a decorator node, so we expect an opening '{'.\n popAndCheck(tokens, \"{\");\n\n // Return the root node definition.\n return node;\n}\n\n/**\n * Creates a succeed node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The succeed node JSON definition.\n */\nfunction createSucceedNode(\n tokens: string[],\n stringLiteralPlaceholders: StringLiteralPlaceholders\n): SucceedNodeDefinition {\n const node = {\n type: \"succeed\",\n ...parseAttributeTokens(tokens, stringLiteralPlaceholders)\n } as SucceedNodeDefinition;\n\n // This is a decorator node, so we expect an opening '{'.\n popAndCheck(tokens, \"{\");\n\n // Return the succeed node definition.\n return node;\n}\n\n/**\n * Creates a fail node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The fail node JSON definition.\n */\nfunction createFailNode(tokens: string[], stringLiteralPlaceholders: StringLiteralPlaceholders): FailNodeDefinition {\n const node = {\n type: \"fail\",\n ...parseAttributeTokens(tokens, stringLiteralPlaceholders)\n } as FailNodeDefinition;\n\n // This is a decorator node, so we expect an opening '{'.\n popAndCheck(tokens, \"{\");\n\n // Return the fail node definition.\n return node;\n}\n\n/**\n * Creates a flip node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The flip node JSON definition.\n */\nfunction createFlipNode(tokens: string[], stringLiteralPlaceholders: StringLiteralPlaceholders): FlipNodeDefinition {\n const node = {\n type: \"flip\",\n ...parseAttributeTokens(tokens, stringLiteralPlaceholders)\n } as FlipNodeDefinition;\n\n // This is a decorator node, so we expect an opening '{'.\n popAndCheck(tokens, \"{\");\n\n // Return the flip node definition.\n return node;\n}\n\n/**\n * Creates a repeat node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The repeat node JSON definition.\n */\nfunction createRepeatNode(\n tokens: string[],\n stringLiteralPlaceholders: StringLiteralPlaceholders\n): RepeatNodeDefinition {\n let node = { type: \"repeat\" } as RepeatNodeDefinition;\n\n // Get the node arguments.\n const nodeArguments = parseArgumentTokens(tokens, stringLiteralPlaceholders);\n\n // The arguments of a repeat node are optional. We may have:\n // - No node arguments, in which case the repeat note will iterate indefinitely.\n // - One node argument which will be the explicit number of iterations to make.\n // - Two node arguments which define the min and max iteration bounds from which a random iteration count will be picked.\n if (nodeArguments.length) {\n // All repeat node arguments MUST be of type number and must be integer.\n nodeArguments\n .filter((arg) => arg.type !== \"number\" || !arg.isInteger)\n .forEach(() => {\n throw new Error(`repeat node iteration counts must be integer values`);\n });\n\n // We should have got one or two iteration counts.\n if (nodeArguments.length === 1) {\n // A static iteration count was defined.\n node.iterations = nodeArguments[0].value as number;\n\n // A repeat node must have a positive number of iterations if defined.\n if (node.iterations < 0) {\n throw new Error(\"a repeat node must have a positive number of iterations if defined\");\n }\n } else if (nodeArguments.length === 2) {\n // A minimum and maximum iteration count was defined.\n node.iterations = [nodeArguments[0].value as number, nodeArguments[1].value as number];\n\n // A repeat node must have a positive min and max iteration count if they are defined.\n if (node.iterations[0] < 0 || node.iterations[1] < 0) {\n throw new Error(\"a repeat node must have a positive minimum and maximum iteration count if defined\");\n }\n\n // A repeat node must not have an minimum iteration count that exceeds the maximum iteration count.\n if (node.iterations[0] > node.iterations[1]) {\n throw new Error(\n \"a repeat node must not have a minimum iteration count that exceeds the maximum iteration count\"\n );\n }\n } else {\n // An incorrect number of iteration counts was defined.\n throw new Error(\"invalid number of repeat node iteration count arguments defined\");\n }\n }\n\n // Grab any node attribute definitions and spread them into the node definition.\n node = { ...node, ...parseAttributeTokens(tokens, stringLiteralPlaceholders) };\n\n // This is a decorator node, so we expect an opening '{'.\n popAndCheck(tokens, \"{\");\n\n // Return the repeat node definition.\n return node;\n}\n\n/**\n * Creates a retry node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The retry node JSON definition.\n */\nfunction createRetryNode(tokens: string[], stringLiteralPlaceholders: StringLiteralPlaceholders): RetryNodeDefinition {\n let node = { type: \"retry\" } as RetryNodeDefinition;\n\n // Get the node arguments.\n const nodeArguments = parseArgumentTokens(tokens, stringLiteralPlaceholders);\n\n // The arguments of a retry node are optional. We may have:\n // - No node arguments, in which case the retry note will attempt indefinitely.\n // - One node argument which will be the explicit number of attempts to make.\n // - Two node arguments which define the min and max attempt bounds from which a random attempt count will be picked.\n if (nodeArguments.length) {\n // All retry node arguments MUST be of type number and must be integer.\n nodeArguments\n .filter((arg) => arg.type !== \"number\" || !arg.isInteger)\n .forEach(() => {\n throw new Error(`retry node attempt counts must be integer values`);\n });\n\n // We should have got one or two attempt counts.\n if (nodeArguments.length === 1) {\n // A static attempt count was defined.\n node.attempts = nodeArguments[0].value as number;\n\n // A retry node must have a positive number of attempts if defined.\n if (node.attempts < 0) {\n throw new Error(\"a retry node must have a positive number of attempts if defined\");\n }\n } else if (nodeArguments.length === 2) {\n // A minimum and maximum attempt count was defined.\n node.attempts = [nodeArguments[0].value as number, nodeArguments[1].value as number];\n\n // A retry node must have a positive min and max attempts count if they are defined.\n if (node.attempts[0] < 0 || node.attempts[1] < 0) {\n throw new Error(\"a retry node must have a positive minimum and maximum attempt count if defined\");\n }\n\n // A retry node must not have a minimum attempt count that exceeds the maximum attempt count.\n if (node.attempts[0] > node.attempts[1]) {\n throw new Error(\n \"a retry node must not have a minimum attempt count that exceeds the maximum attempt count\"\n );\n }\n } else {\n // An incorrect number of attempt counts was defined.\n throw new Error(\"invalid number of retry node attempt count arguments defined\");\n }\n }\n\n // Grab any node attribute definitions and spread them into the node definition.\n node = { ...node, ...parseAttributeTokens(tokens, stringLiteralPlaceholders) };\n\n // This is a decorator node, so we expect an opening '{'.\n popAndCheck(tokens, \"{\");\n\n // Return the retry node definition.\n return node;\n}\n\n/**\n * Creates a sequence node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The sequence node JSON definition.\n */\nfunction createSequenceNode(\n tokens: string[],\n stringLiteralPlaceholders: StringLiteralPlaceholders\n): SequenceNodeDefinition {\n const node = {\n type: \"sequence\",\n ...parseAttributeTokens(tokens, stringLiteralPlaceholders)\n } as SequenceNodeDefinition;\n\n // This is a composite node, so we expect an opening '{'.\n popAndCheck(tokens, \"{\");\n\n // Return the sequence node definition.\n return node;\n}\n\n/**\n * Creates a selector node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The selector node JSON definition.\n */\nfunction createSelectorNode(\n tokens: string[],\n stringLiteralPlaceholders: StringLiteralPlaceholders\n): SelectorNodeDefinition {\n const node = {\n type: \"selector\",\n ...parseAttributeTokens(tokens, stringLiteralPlaceholders)\n } as SelectorNodeDefinition;\n\n // This is a composite node, so we expect an opening '{'.\n popAndCheck(tokens, \"{\");\n\n // Return the selector node definition.\n return node;\n}\n\n/**\n * Creates a parallel node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The parallel node JSON definition.\n */\nfunction createParallelNode(\n tokens: string[],\n stringLiteralPlaceholders: StringLiteralPlaceholders\n): ParallelNodeDefinition {\n const node = {\n type: \"parallel\",\n ...parseAttributeTokens(tokens, stringLiteralPlaceholders)\n } as ParallelNodeDefinition;\n\n // This is a composite node, so we expect an opening '{'.\n popAndCheck(tokens, \"{\");\n\n // Return the parallel node definition.\n return node;\n}\n\n/**\n * Creates a lotto node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The lotto node JSON definition.\n */\nfunction createLottoNode(tokens: string[], stringLiteralPlaceholders: StringLiteralPlaceholders): LottoNodeDefinition {\n // If any node arguments have been defined then they must be our weights.\n const nodeArguments = parseArgumentTokens(tokens, stringLiteralPlaceholders);\n\n // All lotto node arguments MUST be of type number and must be positive integers.\n nodeArguments\n .filter((arg) => arg.type !== \"number\" || !arg.isInteger || arg.value < 0)\n .forEach(() => {\n throw new Error(`lotto node weight arguments must be positive integer values`);\n });\n\n const node = {\n type: \"lotto\",\n weights: nodeArguments.length ? nodeArguments.map(({ value }) => value) : undefined,\n ...parseAttributeTokens(tokens, stringLiteralPlaceholders)\n } as LottoNodeDefinition;\n\n // This is a composite node, so we expect an opening '{'.\n popAndCheck(tokens, \"{\");\n\n // Return the lotto node definition.\n return node;\n}\n\n/**\n * Creates an action node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The action node JSON definition.\n */\nfunction createActionNode(\n tokens: string[],\n stringLiteralPlaceholders: StringLiteralPlaceholders\n): ActionNodeDefinition {\n // Parse any node arguments, we should have at least one which will be an identifier argument for the action name\n // and agent function to invoke for the action, all other arguments are to be passed as arguments to that function.\n const [actionNameIdentifier, ...agentFunctionArgs] = parseArgumentTokens(tokens, stringLiteralPlaceholders);\n\n // Our first argument MUST be defined and be an identifier as we require an action name argument.\n if (actionNameIdentifier?.type !== \"identifier\") {\n throw new Error(\"expected action name identifier argument\");\n }\n\n // Only the first argument should have been an identifier, all agent function arguments must be string, number, boolean or null.\n agentFunctionArgs\n .filter((arg) => arg.type === \"identifier\")\n .forEach((arg) => {\n throw new Error(\n `invalid action node argument value '${arg.value}', must be string, number, boolean or null`\n );\n });\n\n // Return the action node definition.\n return {\n type: \"action\",\n call: actionNameIdentifier.value,\n args: agentFunctionArgs.map(({ value }) => value),\n ...parseAttributeTokens(tokens, stringLiteralPlaceholders)\n };\n}\n\n/**\n * Creates a condition node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The condition node JSON definition.\n */\nfunction createConditionNode(\n tokens: string[],\n stringLiteralPlaceholders: StringLiteralPlaceholders\n): ConditionNodeDefinition {\n // Parse any node arguments, we should have at least one which will be an identifier argument for the condition name\n // and agent function to invoke for the condition, all other arguments are to be passed as arguments to that function.\n const [conditionNameIdentifier, ...agentFunctionArgs] = parseArgumentTokens(tokens, stringLiteralPlaceholders);\n\n // Our first argument MUST be defined and be an identifier as we require a condition name argument.\n if (conditionNameIdentifier?.type !== \"identifier\") {\n throw new Error(\"expected condition name identifier argument\");\n }\n\n // Only the first argument should have been an identifier, all agent function arguments must be string, number, boolean or null.\n agentFunctionArgs\n .filter((arg) => arg.type === \"identifier\")\n .forEach((arg) => {\n throw new Error(\n `invalid condition node argument value '${arg.value}', must be string, number, boolean or null`\n );\n });\n\n // Return the condition node definition.\n return {\n type: \"condition\",\n call: conditionNameIdentifier.value,\n args: agentFunctionArgs.map(({ value }) => value),\n ...parseAttributeTokens(tokens, stringLiteralPlaceholders)\n };\n}\n\n/**\n * Creates a wait node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The wait node JSON definition.\n */\nfunction createWaitNode(tokens: string[], stringLiteralPlaceholders: StringLiteralPlaceholders): WaitNodeDefinition {\n let node = { type: \"wait\" } as WaitNodeDefinition;\n\n // Get the node arguments.\n const nodeArguments = parseArgumentTokens(tokens, stringLiteralPlaceholders);\n\n // The arguments of a wait node are optional. We may have:\n // - No node arguments, in which case the wait will be indefinite until it is aborted.\n // - One node argument which will be the explicit duration of the wait.\n // - Two node arguments which define the min and max duration bounds from which a random duration will be picked.\n if (nodeArguments.length) {\n // All wait node arguments MUST be of type number and must be integer.\n nodeArguments\n .filter((arg) => arg.type !== \"number\" || !arg.isInteger)\n .forEach(() => {\n throw new Error(`wait node durations must be integer values`);\n });\n\n // We may have:\n // - One node argument which will be the explicit duration of the wait.\n // - Two node arguments which define the min and max duration bounds from which a random duration will be picked.\n // - Too many arguments, which is not valid.\n if (nodeArguments.length === 1) {\n // An explicit duration was defined.\n node.duration = nodeArguments[0].value as number;\n\n // If an explict duration was defined then it must be a positive number.\n if (node.duration < 0) {\n throw new Error(\"a wait node must have a positive duration\");\n }\n } else if (nodeArguments.length === 2) {\n // Min and max duration bounds were defined from which a random duration will be picked.\n node.duration = [nodeArguments[0].value as number, nodeArguments[1].value as number];\n\n // A wait node must have a positive min and max duration.\n if (node.duration[0] < 0 || node.duration[1] < 0) {\n throw new Error(\"a wait node must have a positive minimum and maximum duration\");\n }\n\n // A wait node must not have a minimum duration that exceeds the maximum duration.\n if (node.duration[0] > node.duration[1]) {\n throw new Error(\"a wait node must not have a minimum duration that exceeds the maximum duration\");\n }\n } else if (nodeArguments.length > 2) {\n // An incorrect number of duration arguments were defined.\n throw new Error(\"invalid number of wait node duration arguments defined\");\n }\n }\n\n // Return the wait node definition.\n return { ...node, ...parseAttributeTokens(tokens, stringLiteralPlaceholders) };\n}\n\n/**\n * Creates a branch node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The branch node JSON definition.\n */\nfunction createBranchNode(\n tokens: string[],\n stringLiteralPlaceholders: StringLiteralPlaceholders\n): BranchNodeDefinition {\n // Parse any node arguments, we should have one which will be an identifier argument for the root ref.\n const nodeArguments = parseArgumentTokens(tokens, stringLiteralPlaceholders);\n\n // We should have only a single identifer argument for a branch node, which is the root ref.\n if (nodeArguments.length !== 1 || nodeArguments[0].type !== \"identifier\") {\n throw new Error(\"expected single branch name argument\");\n }\n\n // Return the branch node definition.\n return { type: \"branch\", ref: nodeArguments[0].value };\n}\n\n/**\n * Validate a fully-populated node definition that was popped off of the tree stack.\n * @param definition The popped node to validate.\n */\nfunction validatePoppedNode(definition: AnyNodeDefinition): void {\n // Decorators MUST have a child defined.\n if (isDecoratorNode(definition) && isNullOrUndefined(definition.child)) {\n throw new Error(`a ${definition.type} node must have a single child node defined`);\n }\n\n // Composites MUST have at least one child defined.\n if (isCompositeNode(definition) && !definition.children?.length) {\n throw new Error(`a ${definition.type} node must have at least a single child node defined`);\n }\n\n // We need to make sure that lotto nodes that have weights defined have a number of weights matching the number of child nodes.\n if (definition.type === \"lotto\") {\n // Check whether a 'weights' property has been defined, if it has we expect it to be an array of weights.\n if (typeof definition.weights !== \"undefined\") {\n // Check that the weights property is an array of positive integers with an element for each child node element.\n if (definition.weights.length !== definition.children.length) {\n throw new Error(\n \"expected a number of weight arguments matching the number of child nodes for lotto node\"\n );\n }\n }\n }\n}\n", "import { RootNodeDefinition } from \"./BehaviourTreeDefinition\";\nimport { flattenDefinition, isBranchNode, isInteger } from \"./BehaviourTreeDefinitionUtilities\";\nimport { convertMDSLToJSON } from \"./mdsl/MDSLDefinitionParser\";\n\n/**\n * An object representing the result of validating a tree definition.\n */\nexport type DefinitionValidationResult = {\n /**\n * A flag defining whether validation succeeded.\n */\n succeeded: boolean;\n /**\n * A string containing the error message if validation did not succeed.\n */\n errorMessage?: string;\n};\n\n/**\n * Validates the specified behaviour tree definition in the form of JSON or MDSL, not taking any globally registered subtrees into consideration.\n * @param definition The behaviour tree definition in the form of JSON or MDSL.\n * @returns An object representing the result of validating the given tree definition.\n */\nexport function validateDefinition(definition: any): DefinitionValidationResult {\n // The definition must be defined.\n if (definition === null || typeof definition === \"undefined\") {\n return createValidationFailureResult(\"definition is null or undefined\");\n }\n\n // We are expecting a definition in one of three different forms:\n // - A string which we will assume is MDSL and we will parse this to JSON before validation.\n // - An array which we will assume is an array of root node definitions with at least one being the primary root node (no 'id' property)\n // - An object which we will assume is the primary root node and should not have an 'id' property.\n if (typeof definition === \"string\") {\n // The definition is a string which we can assume is MDSL, so attempt to validate it.\n return validateMDSLDefinition(definition);\n } else if (typeof definition === \"object\") {\n // The definition will either be an array (of root node definitions) or an object (the single primary root node definition).\n return validateJSONDefinition(definition);\n } else {\n return createValidationFailureResult(`unexpected definition type of '${typeof definition}'`);\n }\n}\n\n/**\n * Validates the specified behaviour tree definition in the form of MDSL.\n * @param definition The behaviour tree definition in the form of MDSL.\n * @returns An object representing the result of validating the given tree definition.\n */\nexport function validateMDSLDefinition(definition: string): DefinitionValidationResult {\n let rootNodeDefinitions;\n\n // The first thing the we need to do is to attempt to convert our MDSL into JSON.\n try {\n // The definition is a string which we can assume is MDSL, so attempt to parse it to a JSON definition in the form of an array of root node definitions.\n rootNodeDefinitions = convertMDSLToJSON(definition);\n } catch (exception) {\n // We failed to parse the JSON from the MDSL, this is likely to be the result of it not being a valid MDSL string.\n return createValidationFailureResult((exception as Error).message);\n }\n\n // Unpack all of the root node definitions into arrays of main ('id' defined) and sub ('id' not defined) root node definitions.\n const mainRootNodeDefinitions = rootNodeDefinitions.filter(({ id }) => typeof id === \"undefined\");\n const subRootNodeDefinitions = rootNodeDefinitions.filter(({ id }) => typeof id === \"string\" && id.length > 0);\n\n // We should ALWAYS have exactly one root node definition without an 'id' property defined, which is out main root node definition.\n if (mainRootNodeDefinitions.length !== 1) {\n return createValidationFailureResult(\n \"expected single unnamed root node at base of definition to act as main root\"\n );\n }\n\n // We should never have duplicate 'id' properties across our sub root node definitions.\n const subRootNodeIdenitifers: string[] = [];\n for (const { id } of subRootNodeDefinitions) {\n // Have we already come across this 'id' property value?\n if (subRootNodeIdenitifers.includes(id!)) {\n return createValidationFailureResult(`multiple root nodes found with duplicate name '${id}'`);\n }\n\n subRootNodeIdenitifers.push(id!);\n }\n\n try {\n // Validate our branch -> subtree links and check for any circular dependencies, we don't care about checking for broken subtree links here.\n validateBranchSubtreeLinks(rootNodeDefinitions, false);\n } catch (exception) {\n return createValidationFailureResult((exception as Error).message);\n }\n\n // Our definition was valid!\n return { succeeded: true };\n}\n\n/**\n * Validates the specified behaviour tree definition in the form of JSON.\n * @param definition The behaviour tree definition in the form of JSON.\n * @returns An object representing the result of validating the given tree definition.\n */\nexport function validateJSONDefinition(\n definition: RootNodeDefinition | RootNodeDefinition[]\n): DefinitionValidationResult {\n // The definition will either be an array (of root node definitions) or an object (the single primary root node definition).\n const rootNodeDefinitions = Array.isArray(definition) ? definition : [definition];\n\n // Iterate over our array of root nodes and call validateNode for each, passing an initial depth of 0, wrapped in a try catch to handle validation failures.\n try {\n rootNodeDefinitions.forEach((rootNodeDefinition) => validateNode(rootNodeDefinition, 0));\n } catch (error) {\n // Handle cases where we have caught a thrown Error and return a failure result with the error message.\n if (error instanceof Error) {\n return createValidationFailureResult(error.message);\n }\n\n // No idea what happened here!\n return createValidationFailureResult(`unexpected error: ${error}`);\n }\n\n // Unpack all of the root node definitions into arrays of main ('id' defined) and sub ('id' not defined) root node definitions.\n const mainRootNodeDefinitions = rootNodeDefinitions.filter(({ id }) => typeof id === \"undefined\");\n const subRootNodeDefinitions = rootNodeDefinitions.filter(({ id }) => typeof id === \"string\" && id.length > 0);\n\n // We should ALWAYS have exactly one root node definition without an 'id' property defined, which is out main root node definition.\n if (mainRootNodeDefinitions.length !== 1) {\n return createValidationFailureResult(\n \"expected single root node without 'id' property defined to act as main root\"\n );\n }\n\n // We should never have duplicate 'id' properties across our sub root node definitions.\n const subRootNodeIdenitifers: string[] = [];\n for (const { id } of subRootNodeDefinitions) {\n // Have we already come across this 'id' property value?\n if (subRootNodeIdenitifers.includes(id!)) {\n return createValidationFailureResult(\n `multiple root nodes found with duplicate 'id' property value of '${id}'`\n );\n }\n\n subRootNodeIdenitifers.push(id!);\n }\n\n try {\n // Validate our branch -> subtree links and check for any circular dependencies, we don't care about checking for broken subtree links here.\n validateBranchSubtreeLinks(rootNodeDefinitions, false);\n } catch (exception) {\n return createValidationFailureResult((exception as Error).message);\n }\n\n // Our definition was valid!\n return { succeeded: true };\n}\n\n/**\n * Validates the branch -> subtree links across all provided root node definitions.\n * This will not consider branch nodes that reference any globally registered subtrees unless includesGlobalSubtrees\n * is set to true, in which case we will also verify that there are no broken branch -> subtree links.\n * @param rootNodeDefinitions The array of root node definitions.\n * @param includesGlobalSubtrees A flag defining whether the array includes all global subtree root node definitions.\n */\nexport function validateBranchSubtreeLinks(rootNodeDefinitions: RootNodeDefinition[], includesGlobalSubtrees: boolean) {\n // Create a mapping of root node identifiers to other root nodes that they reference via branch nodes.\n // Below is an example of a mapping that includes a circular dependency (root => a => b => c => a)\n // [{ refs: [\"a\", \"b\"] }, { id: \"a\", refs: [\"b\"] }, { id: \"b\", refs: [\"c\"] }, { id: \"c\", refs: [\"a\"] }]\n const rootNodeMappings: { id: string | undefined; refs: string[] }[] = rootNodeDefinitions.map(\n (rootNodeDefinition) => ({\n id: rootNodeDefinition.id,\n refs: flattenDefinition(rootNodeDefinition)\n .filter(isBranchNode)\n .map(({ ref }) => ref)\n })\n );\n\n // A recursive function to walk through the mappings, keeping track of which root nodes we have visited in the form of a path of root node identifiers.\n const followRefs = (mapping: { id: string | undefined; refs: string[] }, path: (string | undefined)[] = []) => {\n // Have we found a circular dependency?\n if (path.includes(mapping.id)) {\n // We found a circular dependency! Get the bad path of root node identifiers.\n const badPath = [...path, mapping.id];\n\n // Create the formatted path value. [undefined, \"a\", \"b\", \"c\", \"a\"] would be formatted as \"a -> b -> c -> a\".\n const badPathFormatted = badPath.filter((element) => !!element).join(\" => \");\n\n // No need to continue, we found a circular dependency.\n throw new Error(`circular dependency found in branch node references: ${badPathFormatted}`);\n }\n\n for (const ref of mapping.refs) {\n // Find the mapping for the root node with an identifer matching the current ref.\n const subMapping = rootNodeMappings.find(({ id }) => id === ref);\n\n // We may not have a mapping for this ref, which is normal when we aren't considering all globally registered subtrees.\n if (subMapping) {\n followRefs(subMapping, [...path, mapping.id]);\n } else if (includesGlobalSubtrees) {\n // We found a reference to a root node that doesn't exist, which is a problem seeing as the root node definitons includes all globally registered subtrees.\n throw new Error(\n mapping.id\n ? `subtree '${mapping.id}' has branch node that references root node '${ref}' which has not been defined`\n : `primary tree has branch node that references root node '${ref}' which has not been defined`\n );\n }\n }\n };\n\n // Start looking for circular dependencies and broken references from the primary root node definition.\n followRefs(rootNodeMappings.find((mapping) => typeof mapping.id === \"undefined\")!);\n}\n\n/**\n * Validate an object that we expect to be a node definition.\n * @param definition An object that we expect to be a node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateNode(definition: any, depth: number): void {\n // Every node must be valid object and have a non-empty 'type' string property.\n if (typeof definition !== \"object\" || typeof definition.type !== \"string\" || definition.type.length === 0) {\n throw new Error(\n `node definition is not an object or 'type' property is not a non-empty string at depth '${depth}'`\n );\n }\n\n // How we validate this node definition will depend on its type.\n switch (definition.type) {\n case \"action\":\n validateActionNode(definition, depth);\n break;\n\n case \"condition\":\n validateConditionNode(definition, depth);\n break;\n\n case \"wait\":\n validateWaitNode(definition, depth);\n break;\n\n case \"branch\":\n validateBranchNode(definition, depth);\n break;\n\n case \"root\":\n validateRootNode(definition, depth);\n break;\n\n case \"succeed\":\n validateSucceedNode(definition, depth);\n break;\n\n case \"fail\":\n validateFailNode(definition, depth);\n break;\n\n case \"flip\":\n validateFlipNode(definition, depth);\n break;\n\n case \"repeat\":\n validateRepeatNode(definition, depth);\n break;\n\n case \"retry\":\n validateRetryNode(definition, depth);\n break;\n\n case \"sequence\":\n validateSequenceNode(definition, depth);\n break;\n\n case \"selector\":\n validateSelectorNode(definition, depth);\n break;\n\n case \"parallel\":\n validateParallelNode(definition, depth);\n break;\n\n case \"lotto\":\n validateLottoNode(definition, depth);\n break;\n\n default:\n throw new Error(`unexpected node type of '${definition.type}' at depth '${depth}'`);\n }\n}\n\n/**\n * Validate any attributes for a given node definition.\n * @param definition The node definition.\n * @param depth The depth of the node in the behaviour tree definition.\n */\nfunction validateNodeAttributes(definition: any, depth: number): void {\n // Validate each of the attribute types for this node.\n [\"while\", \"until\", \"entry\", \"exit\", \"step\"].forEach((attributeName) => {\n // Attempt to grab the definition for the current attribute from the node definition.\n const attributeDefinition = definition[attributeName];\n\n // All node attributes are optional, so there is nothing to do if the current attribute is not defined.\n if (typeof attributeDefinition === \"undefined\") {\n return;\n }\n\n // The attribute definition must be an object.\n if (typeof attributeDefinition !== \"object\") {\n throw new Error(\n `expected attribute '${attributeName}' to be an object for '${definition.type}' node at depth '${depth}'`\n );\n }\n\n // The 'call' property must be defined for any attribute definition.\n if (typeof attributeDefinition.call !== \"string\" || attributeDefinition.call.length === 0) {\n throw new Error(\n `expected 'call' property for attribute '${attributeName}' to be a non-empty string for '${definition.type}' node at depth '${depth}'`\n );\n }\n\n // If any node attribute arguments have been defined then they must have been defined in an array.\n if (typeof attributeDefinition.args !== \"undefined\" && !Array.isArray(attributeDefinition.args)) {\n throw new Error(\n `expected 'args' property for attribute '${attributeName}' to be an array for '${definition.type}' node at depth '${depth}'`\n );\n }\n });\n}\n\n/**\n * Validate an object that we expect to be a root node definition.\n * @param definition An object that we expect to be a root node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateRootNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"root\") {\n throw new Error(\"expected node type of 'root' for root node\");\n }\n\n // A root node cannot be the child of another node.\n if (depth > 0) {\n throw new Error(\"a root node cannot be the child of another node\");\n }\n\n // Check that, if the root node 'id' property is defined, it is a non-empty string.\n if (typeof definition.id !== \"undefined\" && (typeof definition.id !== \"string\" || definition.id.length === 0)) {\n throw new Error(\"expected non-empty string for 'id' property if defined for root node\");\n }\n\n // A root node is a decorator node, so must have a child node defined.\n if (typeof definition.child === \"undefined\") {\n throw new Error(\"expected property 'child' to be defined for root node\");\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n\n // Validate the child node of this decorator node.\n validateNode(definition.child, depth + 1);\n}\n\n/**\n * Validate an object that we expect to be a succeed node definition.\n * @param definition An object that we expect to be a succeed node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateSucceedNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"succeed\") {\n throw new Error(`expected node type of 'succeed' for succeed node at depth '${depth}'`);\n }\n\n // A succeed node is a decorator node, so must have a child node defined.\n if (typeof definition.child === \"undefined\") {\n throw new Error(`expected property 'child' to be defined for succeed node at depth '${depth}'`);\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n\n // Validate the child node of this decorator node.\n validateNode(definition.child, depth + 1);\n}\n\n/**\n * Validate an object that we expect to be a fail node definition.\n * @param definition An object that we expect to be a fail node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateFailNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"fail\") {\n throw new Error(`expected node type of 'fail' for fail node at depth '${depth}'`);\n }\n\n // A fail node is a decorator node, so must have a child node defined.\n if (typeof definition.child === \"undefined\") {\n throw new Error(`expected property 'child' to be defined for fail node at depth '${depth}'`);\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n\n // Validate the child node of this decorator node.\n validateNode(definition.child, depth + 1);\n}\n\n/**\n * Validate an object that we expect to be a flip node definition.\n * @param definition An object that we expect to be a flip node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateFlipNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"flip\") {\n throw new Error(`expected node type of 'flip' for flip node at depth '${depth}'`);\n }\n\n // A flip node is a decorator node, so must have a child node defined.\n if (typeof definition.child === \"undefined\") {\n throw new Error(`expected property 'child' to be defined for flip node at depth '${depth}'`);\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n\n // Validate the child node of this decorator node.\n validateNode(definition.child, depth + 1);\n}\n\n/**\n * Validate an object that we expect to be a repeat node definition.\n * @param definition An object that we expect to be a repeat node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateRepeatNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"repeat\") {\n throw new Error(`expected node type of 'repeat' for repeat node at depth '${depth}'`);\n }\n\n // A repeat node is a decorator node, so must have a child node defined.\n if (typeof definition.child === \"undefined\") {\n throw new Error(`expected property 'child' to be defined for repeat node at depth '${depth}'`);\n }\n\n // Check whether an 'iterations' property has been defined, it may not have been if this node is to repeat indefinitely.\n if (typeof definition.iterations !== \"undefined\") {\n if (Array.isArray(definition.iterations)) {\n // Check whether any elements of the array are not integer values.\n const containsNonInteger = !!definition.iterations.filter((value: unknown) => !isInteger(value)).length;\n\n // If the 'iterations' property is an array then it MUST contain two integer values.\n if (definition.iterations.length !== 2 || containsNonInteger) {\n throw new Error(\n `expected array containing two integer values for 'iterations' property if defined for repeat node at depth '${depth}'`\n );\n }\n\n // A repeat node must have a positive min and max iterations count if they are defined.\n if (definition.iterations[0] < 0 || definition.iterations[1] < 0) {\n throw new Error(\n `expected positive minimum and maximum iterations count for 'iterations' property if defined for repeat node at depth '${depth}'`\n );\n }\n\n // A repeat node must not have a minimum iterations count that exceeds the maximum iterations count.\n if (definition.iterations[0] > definition.iterations[1]) {\n throw new Error(\n `expected minimum iterations count that does not exceed the maximum iterations count for 'iterations' property if defined for repeat node at depth '${depth}'`\n );\n }\n } else if (isInteger(definition.iterations)) {\n // A repeat node must have a positive number of iterations if defined.\n if (definition.iterations < 0) {\n throw new Error(\n `expected positive iterations count for 'iterations' property if defined for repeat node at depth '${depth}'`\n );\n }\n } else {\n throw new Error(\n `expected integer value or array containing two integer values for 'iterations' property if defined for repeat node at depth '${depth}'`\n );\n }\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n\n // Validate the child node of this decorator node.\n validateNode(definition.child, depth + 1);\n}\n\n/**\n * Validate an object that we expect to be a retry node definition.\n * @param definition An object that we expect to be a retry node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateRetryNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"retry\") {\n throw new Error(`expected node type of 'retry' for retry node at depth '${depth}'`);\n }\n\n // A retry node is a decorator node, so must have a child node defined.\n if (typeof definition.child === \"undefined\") {\n throw new Error(`expected property 'child' to be defined for retry node at depth '${depth}'`);\n }\n\n // Check whether an 'attempts' property has been defined, it may not have been if this node is to retry indefinitely.\n if (typeof definition.attempts !== \"undefined\") {\n if (Array.isArray(definition.attempts)) {\n // Check whether any elements of the array are not integer values.\n const containsNonInteger = !!definition.attempts.filter((value: unknown) => !isInteger(value)).length;\n\n // If the 'attempts' property is an array then it MUST contain two integer values.\n if (definition.attempts.length !== 2 || containsNonInteger) {\n throw new Error(\n `expected array containing two integer values for 'attempts' property if defined for retry node at depth '${depth}'`\n );\n }\n\n // A retry node must have a positive min and max attempts count if they are defined.\n if (definition.attempts[0] < 0 || definition.attempts[1] < 0) {\n throw new Error(\n `expected positive minimum and maximum attempts count for 'attempts' property if defined for retry node at depth '${depth}'`\n );\n }\n\n // A retry node must not have a minimum attempts count that exceeds the maximum attempts count.\n if (definition.attempts[0] > definition.attempts[1]) {\n throw new Error(\n `expected minimum attempts count that does not exceed the maximum attempts count for 'attempts' property if defined for retry node at depth '${depth}'`\n );\n }\n } else if (isInteger(definition.attempts)) {\n // A retry node must have a positive number of attempts if defined.\n if (definition.attempts < 0) {\n throw new Error(\n `expected positive attempts count for 'attempts' property if defined for retry node at depth '${depth}'`\n );\n }\n } else {\n throw new Error(\n `expected integer value or array containing two integer values for 'attempts' property if defined for retry node at depth '${depth}'`\n );\n }\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n\n // Validate the child node of this decorator node.\n validateNode(definition.child, depth + 1);\n}\n\n/**\n * Validate an object that we expect to be a branch node definition.\n * @param definition An object that we expect to be a branch node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateBranchNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"branch\") {\n throw new Error(`expected node type of 'branch' for branch node at depth '${depth}'`);\n }\n\n // Check that the branch node 'ref' property is defined and is a non-empty string.\n if (typeof definition.ref !== \"string\" || definition.ref.length === 0) {\n throw new Error(`expected non-empty string for 'ref' property for branch node at depth '${depth}'`);\n }\n\n // It is invalid to define guard attributes for a branch node as they should be defined on the referenced root node.\n [\"while\", \"until\"].forEach((attributeName) => {\n if (typeof definition[attributeName] !== \"undefined\") {\n throw new Error(\n `guards should not be defined for branch nodes but guard '${attributeName}' was defined for branch node at depth '${depth}'`\n );\n }\n });\n\n // It is invalid to define callback attributes for a branch node as they should be defined on the referenced root node.\n [\"entry\", \"exit\", \"step\"].forEach((attributeName) => {\n if (typeof definition[attributeName] !== \"undefined\") {\n throw new Error(\n `callbacks should not be defined for branch nodes but callback '${attributeName}' was defined for branch node at depth '${depth}'`\n );\n }\n });\n}\n\n/**\n * Validate an object that we expect to be a action node definition.\n * @param definition An object that we expect to be a action node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateActionNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"action\") {\n throw new Error(`expected node type of 'action' for action node at depth '${depth}'`);\n }\n\n // The 'call' property must be defined for a action node definition.\n if (typeof definition.call !== \"string\" || definition.call.length === 0) {\n throw new Error(`expected non-empty string for 'call' property of action node at depth '${depth}'`);\n }\n\n // If any action function arguments have been defined then they must have been defined in an array.\n if (typeof definition.args !== \"undefined\" && !Array.isArray(definition.args)) {\n throw new Error(`expected array for 'args' property if defined for action node at depth '${depth}'`);\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n}\n\n/**\n * Validate an object that we expect to be a condition node definition.\n * @param definition An object that we expect to be a condition node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateConditionNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"condition\") {\n throw new Error(`expected node type of 'condition' for condition node at depth '${depth}'`);\n }\n\n // The 'call' property must be defined for a condition node definition.\n if (typeof definition.call !== \"string\" || definition.call.length === 0) {\n throw new Error(`expected non-empty string for 'call' property of condition node at depth '${depth}'`);\n }\n\n // If any condition function arguments have been defined then they must have been defined in an array.\n if (typeof definition.args !== \"undefined\" && !Array.isArray(definition.args)) {\n throw new Error(`expected array for 'args' property if defined for condition node at depth '${depth}'`);\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n}\n\n/**\n * Validate an object that we expect to be a wait node definition.\n * @param definition An object that we expect to be a wait node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateWaitNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"wait\") {\n throw new Error(`expected node type of 'wait' for wait node at depth '${depth}'`);\n }\n\n // Check whether a 'duration' property has been defined, it may not have been if this node is to wait indefinitely.\n if (typeof definition.duration !== \"undefined\") {\n if (Array.isArray(definition.duration)) {\n // Check whether any elements of the array are not integer values.\n const containsNonInteger = !!definition.duration.filter((value: unknown) => !isInteger(value)).length;\n\n // If the 'duration' property is an array then it MUST contain two integer values.\n if (definition.duration.length !== 2 || containsNonInteger) {\n throw new Error(\n `expected array containing two integer values for 'duration' property if defined for wait node at depth '${depth}'`\n );\n }\n\n // A wait node must have a positive min and max duration value if they are defined.\n if (definition.duration[0] < 0 || definition.duration[1] < 0) {\n throw new Error(\n `expected positive minimum and maximum duration for 'duration' property if defined for wait node at depth '${depth}'`\n );\n }\n\n // A wait node must not have a minimum duration value that exceeds the maximum duration value.\n if (definition.duration[0] > definition.duration[1]) {\n throw new Error(\n `expected minimum duration value that does not exceed the maximum duration value for 'duration' property if defined for wait node at depth '${depth}'`\n );\n }\n } else if (isInteger(definition.duration)) {\n // A wait node must have a positive duration value if defined.\n if (definition.duration < 0) {\n throw new Error(\n `expected positive duration value for 'duration' property if defined for wait node at depth '${depth}'`\n );\n }\n } else {\n throw new Error(\n `expected integer value or array containing two integer values for 'duration' property if defined for wait node at depth '${depth}'`\n );\n }\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n}\n\n/**\n * Validate an object that we expect to be a sequence node definition.\n * @param definition An object that we expect to be a sequence node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateSequenceNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"sequence\") {\n throw new Error(`expected node type of 'sequence' for sequence node at depth '${depth}'`);\n }\n\n // A sequence node is a composite node, so must have a children nodes array defined.\n if (!Array.isArray(definition.children) || definition.children.length === 0) {\n throw new Error(`expected non-empty 'children' array to be defined for sequence node at depth '${depth}'`);\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n\n // Validate the child nodes of this composite node.\n definition.children.forEach((child: any) => validateNode(child, depth + 1));\n}\n\n/**\n * Validate an object that we expect to be a selector node definition.\n * @param definition An object that we expect to be a selector node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateSelectorNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"selector\") {\n throw new Error(`expected node type of 'selector' for selector node at depth '${depth}'`);\n }\n\n // A selector node is a composite node, so must have a children nodes array defined.\n if (!Array.isArray(definition.children) || definition.children.length === 0) {\n throw new Error(`expected non-empty 'children' array to be defined for selector node at depth '${depth}'`);\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n\n // Validate the child nodes of this composite node.\n definition.children.forEach((child: any) => validateNode(child, depth + 1));\n}\n\n/**\n * Validate an object that we expect to be a parallel node definition.\n * @param definition An object that we expect to be a parallel node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateParallelNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"parallel\") {\n throw new Error(`expected node type of 'parallel' for parallel node at depth '${depth}'`);\n }\n\n // A parallel node is a composite node, so must have a children nodes array defined.\n if (!Array.isArray(definition.children) || definition.children.length === 0) {\n throw new Error(`expected non-empty 'children' array to be defined for parallel node at depth '${depth}'`);\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n\n // Validate the child nodes of this composite node.\n definition.children.forEach((child: any) => validateNode(child, depth + 1));\n}\n\n/**\n * Validate an object that we expect to be a lotto node definition.\n * @param definition An object that we expect to be a lotto node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateLottoNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"lotto\") {\n throw new Error(`expected node type of 'lotto' for lotto node at depth '${depth}'`);\n }\n\n // A lotto node is a composite node, so must have a children nodes array defined.\n if (!Array.isArray(definition.children) || definition.children.length === 0) {\n throw new Error(`expected non-empty 'children' array to be defined for lotto node at depth '${depth}'`);\n }\n\n // Check whether a 'weights' property has been defined, if it has we expect it to be an array of weights.\n if (typeof definition.weights !== \"undefined\") {\n // Check that the weights property is an array of positive integers with an element for each child node element.\n if (\n !Array.isArray(definition.weights) ||\n definition.weights.length !== definition.children.length ||\n definition.weights.filter((value: unknown) => !isInteger(value)).length ||\n definition.weights.filter((value: number) => value < 0).length\n ) {\n throw new Error(\n `expected an array of positive integer weight values with a length matching the number of child nodes for 'weights' property if defined for lotto node at depth '${depth}'`\n );\n }\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n\n // Validate the child nodes of this composite node.\n definition.children.forEach((child: any) => validateNode(child, depth + 1));\n}\n\n/**\n * A helper function to create a failure validation result with the given error message.\n * @param errorMessage The validation failure error message.\n * @returns A failure validation result with the given error message.\n */\nfunction createValidationFailureResult(errorMessage: string): DefinitionValidationResult {\n return { succeeded: false, errorMessage };\n}\n", "import { ActionResult, Agent, GlobalFunction } from \"./Agent\";\nimport { RootNodeDefinition } from \"./BehaviourTreeDefinition\";\n\nexport type InvokerFunction = (args: any[]) => ActionResult;\n\n/**\n * A singleton used to store and lookup registered functions and subtrees.\n */\nexport default class Lookup {\n /**\n * The object holding any registered functions keyed on function name.\n */\n private static functionTable: { [key: string]: GlobalFunction } = {};\n /**\n * The object holding any registered subtree root node definitions keyed on tree name.\n */\n private static subtreeTable: { [key: string]: RootNodeDefinition } = {};\n\n /**\n * Gets the function with the specified name.\n * @param name The name of the function.\n * @returns The function with the specified name.\n */\n public static getFunc(name: string): GlobalFunction {\n return this.functionTable[name];\n }\n\n /**\n * Sets the function with the specified name for later lookup.\n * @param name The name of the function.\n * @param func The function.\n */\n public static setFunc(name: string, func: GlobalFunction): void {\n this.functionTable[name] = func;\n }\n\n /**\n * Gets the function invoker for the specified agent and function name.\n * If a function with the specified name exists on the agent object then it will\n * be returned, otherwise we will then check the registered functions for a match.\n * @param agent The agent instance that this behaviour tree is modelling behaviour for.\n * @param name The function name.\n * @returns The function invoker for the specified agent and function name.\n */\n static getFuncInvoker(agent: Agent, name: string): InvokerFunction | null {\n // Check whether the agent contains the specified function.\n const foundOnAgent = agent[name];\n if (foundOnAgent && typeof foundOnAgent === \"function\") {\n return (args: any[]): boolean | ActionResult => foundOnAgent.apply(agent, args);\n }\n\n // The agent does not contain the specified function but it may have been registered at some point.\n if (this.functionTable[name] && typeof this.functionTable[name] === \"function\") {\n return (args: any[]) => this.functionTable[name](agent, ...args.map((arg) => arg.value));\n }\n\n // We have no function to invoke.\n return null;\n }\n\n /**\n * Gets all registered subtree root node definitions.\n */\n static getSubtrees(): { [key: string]: RootNodeDefinition } {\n return this.subtreeTable;\n }\n\n /**\n * Sets the subtree with the specified name for later lookup.\n * @param name The name of the subtree.\n * @param subtree The subtree.\n */\n static setSubtree(name: string, subtree: RootNodeDefinition) {\n this.subtreeTable[name] = subtree;\n }\n\n /**\n * Removes the registered function or subtree with the specified name.\n * @param name The name of the registered function or subtree.\n */\n static remove(name: string) {\n delete this.functionTable[name];\n delete this.subtreeTable[name];\n }\n\n /**\n * Remove all registered functions and subtrees.\n */\n static empty() {\n this.functionTable = {};\n this.subtreeTable = {};\n }\n}\n", "import Node from \"../../nodes/Node\";\n\n/**\n * An exception thrown when evaluating node guard path conditions and a conditions fails.\n */\nexport default class GuardUnsatisifedException extends Error {\n /**\n * @param source The node at which a guard condition failed.\n */\n constructor(private source: Node) {\n super(\"A guard path condition has failed\");\n }\n\n /**\n * Gets whether the specified node is the node at which a guard condition failed.\n * @param node The node to check against the source node.\n * @returns Whether the specified node is the node at which a guard condition failed.\n */\n isSourceNode = (node: Node) => node === this.source;\n}\n", "import { Agent } from \"../../Agent\";\nimport Guard from \"./Guard\";\nimport Node from \"../../nodes/Node\";\nimport GuardUnsatisifedException from \"./GuardUnsatisifedException\";\n\nexport type GuardPathPart = {\n node: Node;\n guards: Guard[];\n};\n\n/**\n * Represents a path of node guards along a root-to-leaf tree path.\n */\nexport default class GuardPath {\n /**\n * @param nodes An array of objects defining a node instance -> guard link, ordered by node depth.\n */\n constructor(private nodes: GuardPathPart[]) {}\n\n /**\n * Evaluate guard conditions for all guards in the tree path, moving outwards from the root.\n * @param agent The agent, required for guard evaluation.\n * @returns An evaluation results object.\n */\n evaluate = (agent: Agent) => {\n // We need to evaluate guard conditions for nodes up the tree, moving outwards from the root.\n for (const details of this.nodes) {\n // There can be multiple guards per node.\n for (const guard of details.guards) {\n // Check whether the guard condition passes, and throw an exception if not.\n if (!guard.isSatisfied(agent)) {\n throw new GuardUnsatisifedException(details.node);\n }\n }\n }\n };\n}\n", "import { BehaviourTreeOptions } from \"../BehaviourTreeOptions\";\nimport State, { AnyState } from \"../State\";\nimport { Agent } from \"../Agent\";\nimport Leaf from \"./leaf/Leaf\";\nimport Attribute from \"../attributes/Attribute\";\nimport Entry from \"../attributes/callbacks/Entry\";\nimport Exit from \"../attributes/callbacks/Exit\";\nimport Step from \"../attributes/callbacks/Step\";\nimport Guard from \"../attributes/guards/Guard\";\nimport GuardPath from \"../attributes/guards/GuardPath\";\nimport GuardUnsatisifedException from \"../attributes/guards/GuardUnsatisifedException\";\n\n/**\n * A base node.\n */\nexport default abstract class Node {\n /**\n * The node uid.\n */\n private readonly uid: string = createNodeUid();\n /**\n * The node state.\n */\n private state: AnyState = State.READY;\n /**\n * The guard path to evaluate as part of a node update.\n */\n private guardPath: GuardPath | undefined;\n\n /**\n * @param type The node type.\n * @param attributes The node attributes.\n * @param args The node argument definitions.\n */\n constructor(private type: string, private attributes: Attribute[], private args: any[]) {}\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected abstract onUpdate(agent: Agent, options: BehaviourTreeOptions): void;\n\n /**\n * Gets the name of the node.\n */\n public abstract getName(): string;\n\n /**\n * Gets whether this node is a leaf node.\n */\n public abstract isLeafNode: () => this is Leaf;\n\n /**\n * Gets/Sets the state of the node.\n */\n getState = (): AnyState => this.state;\n setState = (value: AnyState): void => {\n this.state = value;\n };\n\n /**\n * Gets the unique id of the node.\n */\n getUid = () => this.uid;\n\n /**\n * Gets the type of the node.\n */\n getType = () => this.type;\n\n /**\n * Gets the node attributes.\n */\n getAttributes = () => this.attributes;\n\n /**\n * Gets the node arguments.\n */\n getArguments = () => this.args;\n\n /**\n * Gets the node attribute with the specified type, or null if it does not exist.\n */\n getAttribute(type: \"entry\" | \"ENTRY\"): Entry;\n getAttribute(type: \"exit\" | \"EXIT\"): Exit;\n getAttribute(type: \"step\" | \"STEP\"): Step;\n getAttribute(type: string): Attribute {\n return (\n this.getAttributes().filter((decorator) => decorator.type.toUpperCase() === type.toUpperCase())[0] || null\n );\n }\n\n /**\n * Gets the node attributes.\n */\n getGuardAttributes = (): Guard[] => this.getAttributes().filter((decorator) => decorator.isGuard()) as Guard[];\n\n /**\n * Sets the guard path to evaluate as part of a node update.\n */\n setGuardPath = (value: GuardPath) => (this.guardPath = value);\n\n /**\n * Gets whether a guard path is assigned to this node.\n */\n hasGuardPath = () => !!this.guardPath;\n\n /**\n * Gets whether this node is in the specified state.\n * @param value The value to compare to the node state.\n */\n public is(value: AnyState): boolean {\n return this.state === value;\n }\n\n /**\n * Reset the state of the node.\n */\n public reset(): void {\n this.setState(State.READY);\n }\n\n /**\n * Abort the running of this node.\n * @param agent The agent.\n */\n public abort(agent: Agent): void {\n // There is nothing to do if this node is not in the running state.\n if (!this.is(State.RUNNING)) {\n return;\n }\n\n // Reset the state of this node.\n this.reset();\n\n this.getAttribute(\"exit\")?.callAgentFunction(agent, false, true);\n }\n\n /**\n * Update the node.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n * @returns The result of the update.\n */\n public update(agent: Agent, options: BehaviourTreeOptions): void {\n // If this node is already in a 'SUCCEEDED' or 'FAILED' state then there is nothing to do.\n if (this.is(State.SUCCEEDED) || this.is(State.FAILED)) {\n return;\n }\n\n try {\n // Evaluate all of the guard path conditions for the current tree path.\n this.guardPath!.evaluate(agent);\n\n // If this node is in the READY state then call the ENTRY for this node if it exists.\n if (this.is(State.READY)) {\n this.getAttribute(\"entry\")?.callAgentFunction(agent);\n }\n\n this.getAttribute(\"step\")?.callAgentFunction(agent);\n\n // Do the actual update.\n this.onUpdate(agent, options);\n\n // If this node is now in a 'SUCCEEDED' or 'FAILED' state then call the EXIT for this node if it exists.\n if (this.is(State.SUCCEEDED) || this.is(State.FAILED)) {\n this.getAttribute(\"exit\")?.callAgentFunction(agent, this.is(State.SUCCEEDED), false);\n }\n } catch (error) {\n // If the error is a GuardUnsatisfiedException then we need to determine if this node is the source.\n if (error instanceof GuardUnsatisifedException && error.isSourceNode(this)) {\n // Abort the current node.\n this.abort(agent);\n\n // Any node that is the source of an abort will be a failed node.\n this.setState(State.FAILED);\n } else {\n throw error;\n }\n }\n }\n}\n\n/**\n * Create a randomly generated node uid.\n * @returns A randomly generated node uid.\n */\nfunction createNodeUid(): string {\n var S4 = function () {\n return (((1 + Math.random()) * 0x10000) | 0).toString(16).substring(1);\n };\n return S4() + S4() + \"-\" + S4() + \"-\" + S4() + \"-\" + S4() + \"-\" + S4() + S4() + S4();\n}\n", "import Node from \"../Node\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\n\n/**\n * A composite node that wraps child nodes.\n */\nexport default abstract class Composite extends Node {\n /**\n * @param type The node type.\n * @param attributes The node attributes.\n * @param children The child nodes.\n */\n constructor(type: string, attributes: Attribute[], protected children: Node[]) {\n super(type, attributes, []);\n }\n\n /**\n * Gets whether this node is a leaf node.\n */\n isLeafNode = () => false;\n\n /**\n * Gets the children of this node.\n */\n getChildren = () => this.children;\n\n /**\n * Reset the state of the node.\n */\n reset = () => {\n // Reset the state of this node.\n this.setState(State.READY);\n\n // Reset the state of any child nodes.\n this.getChildren().forEach((child) => child.reset());\n };\n\n /**\n * Abort the running of this node.\n * @param agent The agent.\n */\n abort = (agent: Agent) => {\n // There is nothing to do if this node is not in the running state.\n if (!this.is(State.RUNNING)) {\n return;\n }\n\n // Abort any child nodes.\n this.getChildren().forEach((child) => child.abort(agent));\n\n // Reset the state of this node.\n this.reset();\n\n this.getAttribute(\"exit\")?.callAgentFunction(agent, false, true);\n };\n}\n", "import Composite from \"./Composite\";\nimport State from \"../../State\";\nimport Node from \"../Node\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A PARALLEL node.\n * The child nodes are executed concurrently until one fails or all succeed.\n */\nexport default class Parallel extends Composite {\n /**\n * @param attributes The node attributes.\n * @param children The child nodes.\n */\n constructor(attributes: Attribute[], children: Node[]) {\n super(\"parallel\", attributes, children);\n }\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // Keep a count of the number of succeeded child nodes.\n let succeededCount = 0;\n\n let hasChildFailed = false;\n\n // Iterate over all of the children of this node.\n for (const child of this.children) {\n // If the child has never been updated or is running then we will need to update it now.\n if (child.getState() === State.READY || child.getState() === State.RUNNING) {\n // Update the child of this node.\n child.update(agent, options);\n }\n\n // If the current child has a state of 'SUCCEEDED' then we should move on to the next child.\n if (child.getState() === State.SUCCEEDED) {\n // The child node has succeeded, keep track of this to determine if all children have.\n succeededCount++;\n\n // The child node succeeded, but we have not finished checking every child node yet.\n continue;\n }\n\n // If the current child has a state of 'FAILED' then this node is also a 'FAILED' node.\n if (child.getState() === State.FAILED) {\n hasChildFailed = true;\n\n // There is no need to check the rest of the children.\n break;\n }\n\n // The node should be in the 'RUNNING' state.\n if (child.getState() !== State.RUNNING) {\n // The child node was not in an expected state.\n throw new Error(\"child node was not in an expected state.\");\n }\n }\n\n if (hasChildFailed) {\n // This node is a 'FAILED' node.\n this.setState(State.FAILED);\n\n // Abort every running child.\n for (const child of this.children) {\n if (child.getState() === State.RUNNING) {\n child.abort(agent);\n }\n }\n } else {\n // If all children have succeeded then this node has also succeeded, otherwise it is still running.\n this.setState(succeededCount === this.children.length ? State.SUCCEEDED : State.RUNNING);\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => \"PARALLEL\";\n}\n", "import Composite from \"./Composite\";\nimport Node from \"../Node\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A SELECTOR node.\n * The child nodes are executed in sequence until one succeeds or all fail.\n */\nexport default class Selector extends Composite {\n /**\n * @param attributes The node attributes.\n * @param children The child nodes.\n */\n constructor(attributes: Attribute[], protected children: Node[]) {\n super(\"selector\", attributes, children);\n }\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // Iterate over all of the children of this node.\n for (const child of this.children) {\n // If the child has never been updated or is running then we will need to update it now.\n if (child.getState() === State.READY || child.getState() === State.RUNNING) {\n // Update the child of this node.\n child.update(agent, options);\n }\n\n // If the current child has a state of 'SUCCEEDED' then this node is also a 'SUCCEEDED' node.\n if (child.getState() === State.SUCCEEDED) {\n // This node is a 'SUCCEEDED' node.\n this.setState(State.SUCCEEDED);\n\n // There is no need to check the rest of the selector nodes.\n return;\n }\n\n // If the current child has a state of 'FAILED' then we should move on to the next child.\n if (child.getState() === State.FAILED) {\n // Find out if the current child is the last one in the selector.\n // If it is then this sequence node has also failed.\n if (this.children.indexOf(child) === this.children.length - 1) {\n // This node is a 'FAILED' node.\n this.setState(State.FAILED);\n\n // There is no need to check the rest of the selector as we have completed it.\n return;\n } else {\n // The child node failed, try the next one.\n continue;\n }\n }\n\n // The node should be in the 'RUNNING' state.\n if (child.getState() === State.RUNNING) {\n // This node is a 'RUNNING' node.\n this.setState(State.RUNNING);\n\n // There is no need to check the rest of the selector as the current child is still running.\n return;\n }\n\n // The child node was not in an expected state.\n throw new Error(\"child node was not in an expected state.\");\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => \"SELECTOR\";\n}\n", "import Composite from \"./Composite\";\nimport Node from \"../Node\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A SEQUENCE node.\n * The child nodes are executed in sequence until one fails or all succeed.\n */\nexport default class Sequence extends Composite {\n /**\n * @param attributes The node attributes.\n * @param children The child nodes.\n */\n constructor(attributes: Attribute[], protected children: Node[]) {\n super(\"sequence\", attributes, children);\n }\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // Iterate over all of the children of this node.\n for (const child of this.children) {\n // If the child has never been updated or is running then we will need to update it now.\n if (child.getState() === State.READY || child.getState() === State.RUNNING) {\n // Update the child of this node.\n child.update(agent, options);\n }\n\n // If the current child has a state of 'SUCCEEDED' then we should move on to the next child.\n if (child.getState() === State.SUCCEEDED) {\n // Find out if the current child is the last one in the sequence.\n // If it is then this sequence node has also succeeded.\n if (this.children.indexOf(child) === this.children.length - 1) {\n // This node is a 'SUCCEEDED' node.\n this.setState(State.SUCCEEDED);\n\n // There is no need to check the rest of the sequence as we have completed it.\n return;\n } else {\n // The child node succeeded, but we have not finished the sequence yet.\n continue;\n }\n }\n\n // If the current child has a state of 'FAILED' then this node is also a 'FAILED' node.\n if (child.getState() === State.FAILED) {\n // This node is a 'FAILED' node.\n this.setState(State.FAILED);\n\n // There is no need to check the rest of the sequence.\n return;\n }\n\n // The node should be in the 'RUNNING' state.\n if (child.getState() === State.RUNNING) {\n // This node is a 'RUNNING' node.\n this.setState(State.RUNNING);\n\n // There is no need to check the rest of the sequence as the current child is still running.\n return;\n }\n\n // The child node was not in an expected state.\n throw new Error(\"child node was not in an expected state.\");\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => \"SEQUENCE\";\n}\n", "import createLotto from \"lotto-draw\";\n\nimport Node from \"../Node\";\nimport Composite from \"./Composite\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A LOTTO node.\n * A winning child is picked on the initial update of this node, based on ticket weighting.\n * The state of this node will match the state of the winning child.\n */\nexport default class Lotto extends Composite {\n /**\n * @param attributes The node attributes.\n * @param weights The child node weights.\n * @param children The child nodes.\n */\n constructor(attributes: Attribute[], private weights: number[] | undefined, children: Node[]) {\n super(\"lotto\", attributes, children);\n }\n\n /**\n * The child node selected to be the active one.\n */\n private selectedChild: Node | undefined;\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // If this node is in the READY state then we need to pick a winning child node.\n if (this.is(State.READY)) {\n // Create a lotto draw with which to randomly pick a child node to become the active one.\n const lottoDraw = createLotto({\n // Hook up the optional 'random' behaviour tree function option to the one used by 'lotto-draw'.\n random: options.random,\n // Pass in each child node as a participant in the lotto draw with their respective ticket count.\n participants: this.children.map((child, index) => [child, this.weights?.[index] || 1])\n });\n\n // Randomly pick a child based on ticket weighting, this will become the active child for this composite node.\n this.selectedChild = lottoDraw.draw() || undefined;\n }\n\n // If something went wrong and we don't have an active child then we should throw an error.\n if (!this.selectedChild) {\n throw new Error(\"failed to update lotto node as it has no active child\");\n }\n\n // If the selected child has never been updated or is running then we will need to update it now.\n if (this.selectedChild.getState() === State.READY || this.selectedChild.getState() === State.RUNNING) {\n this.selectedChild.update(agent, options);\n }\n\n // The state of the lotto node is the state of its selected child.\n this.setState(this.selectedChild.getState());\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => (this.weights ? `LOTTO [${this.weights.join(\",\")}]` : \"LOTTO\");\n}\n", "import Node from \"../Node\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\n\n/**\n * A decorator node that wraps a single child node.\n */\nexport default abstract class Decorator extends Node {\n /**\n * @param type The node type.\n * @param attributes The node attributes.\n * @param child The child node.\n */\n constructor(type: string, attributes: Attribute[], protected child: Node) {\n super(type, attributes, []);\n }\n\n /**\n * Gets whether this node is a leaf node.\n */\n isLeafNode = () => false;\n\n /**\n * Gets the children of this node.\n */\n getChildren = () => [this.child];\n\n /**\n * Reset the state of the node.\n */\n reset = () => {\n // Reset the state of this node.\n this.setState(State.READY);\n\n // Reset the state of the child node.\n this.child.reset();\n };\n\n /**\n * Abort the running of this node.\n * @param agent The agent.\n */\n abort = (agent: Agent) => {\n // There is nothing to do if this node is not in the running state.\n if (!this.is(State.RUNNING)) {\n return;\n }\n\n // Abort the child node.\n this.child.abort(agent);\n\n // Reset the state of this node.\n this.reset();\n\n this.getAttribute(\"exit\")?.callAgentFunction(agent, false, true);\n };\n}\n", "import Node from \"../Node\";\nimport Decorator from \"./Decorator\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A Fail node.\n * This node wraps a single child and will always move to the 'FAILED' state when the child moves to a 'SUCCEEDED' or 'FAILED' state.\n */\nexport default class Fail extends Decorator {\n /**\n * @param attributes The node attributes.\n * @param child The child node.\n */\n constructor(attributes: Attribute[], child: Node) {\n super(\"fail\", attributes, child);\n }\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // If the child has never been updated or is running then we will need to update it now.\n if (this.child.getState() === State.READY || this.child.getState() === State.RUNNING) {\n this.child.update(agent, options);\n }\n\n // The state of this node will depend in the state of its child.\n switch (this.child.getState()) {\n case State.RUNNING:\n this.setState(State.RUNNING);\n break;\n\n case State.SUCCEEDED:\n case State.FAILED:\n this.setState(State.FAILED);\n break;\n\n default:\n this.setState(State.READY);\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => \"FAIL\";\n}\n", "import Decorator from \"./Decorator\";\nimport State from \"../../State\";\nimport Node from \"../Node\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A Flip node.\n * This node wraps a single child and will flip the state of the child state.\n */\nexport default class Flip extends Decorator {\n /**\n * @param attributes The node attributes.\n * @param child The child node.\n */\n constructor(attributes: Attribute[], child: Node) {\n super(\"flip\", attributes, child);\n }\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // If the child has never been updated or is running then we will need to update it now.\n if (this.child.getState() === State.READY || this.child.getState() === State.RUNNING) {\n this.child.update(agent, options);\n }\n\n // The state of this node will depend in the state of its child.\n switch (this.child.getState()) {\n case State.RUNNING:\n this.setState(State.RUNNING);\n break;\n\n case State.SUCCEEDED:\n this.setState(State.FAILED);\n break;\n\n case State.FAILED:\n this.setState(State.SUCCEEDED);\n break;\n\n default:\n this.setState(State.READY);\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => \"FLIP\";\n}\n", "import Node from \"../Node\";\nimport Decorator from \"./Decorator\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A REPEAT node.\n * The node has a single child which can have:\n * -- A number of iterations for which to repeat the child node.\n * -- An infinite repeat loop if neither an iteration count or a condition function is defined.\n * The REPEAT node will stop and have a 'FAILED' state if its child is ever in a 'FAILED' state after an update.\n * The REPEAT node will attempt to move on to the next iteration if its child is ever in a 'SUCCEEDED' state.\n */\nexport default class Repeat extends Decorator {\n /**\n * @param attributes The node attributes.\n * @param iterations The number of iterations to repeat the child node.\n * @param iterationsMin The minimum possible number of iterations to repeat the child node.\n * @param iterationsMax The maximum possible number of iterations to repeat the child node.\n * @param child The child node.\n */\n constructor(\n attributes: Attribute[],\n private iterations: number | null,\n private iterationsMin: number | null,\n private iterationsMax: number | null,\n child: Node\n ) {\n super(\"repeat\", attributes, child);\n }\n\n /**\n * The number of target iterations to make.\n */\n private targetIterationCount: number | null = null;\n\n /**\n * The current iteration count.\n */\n private currentIterationCount: number = 0;\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // If this node is in the READY state then we need to reset the child and the target iteration count.\n if (this.is(State.READY)) {\n // Reset the child node.\n this.child.reset();\n\n // Reset the current iteration count.\n this.currentIterationCount = 0;\n\n // Set the target iteration count.\n this.setTargetIterationCount(options);\n }\n\n // Do a check to see if we can iterate. If we can then this node will move into the 'RUNNING' state.\n // If we cannot iterate then we have hit our target iteration count, which means that the node has succeeded.\n if (this.canIterate()) {\n // This node is in the running state and can do its initial iteration.\n this.setState(State.RUNNING);\n\n // We may have already completed an iteration, meaning that the child node will be in the SUCCEEDED state.\n // If this is the case then we will have to reset the child node now.\n if (this.child.getState() === State.SUCCEEDED) {\n this.child.reset();\n }\n\n // Update the child of this node.\n this.child.update(agent, options);\n\n // If the child moved into the FAILED state when we updated it then there is nothing left to do and this node has also failed.\n // If it has moved into the SUCCEEDED state then we have completed the current iteration.\n if (this.child.getState() === State.FAILED) {\n // The child has failed, meaning that this node has failed.\n this.setState(State.FAILED);\n\n return;\n } else if (this.child.getState() === State.SUCCEEDED) {\n // We have completed an iteration.\n this.currentIterationCount += 1;\n }\n } else {\n // This node is in the 'SUCCEEDED' state as we cannot iterate any more.\n this.setState(State.SUCCEEDED);\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => {\n if (this.iterations !== null) {\n return `REPEAT ${this.iterations}x`;\n } else if (this.iterationsMin !== null && this.iterationsMax !== null) {\n return `REPEAT ${this.iterationsMin}x-${this.iterationsMax}x`;\n } else {\n return \"REPEAT\";\n }\n };\n\n /**\n * Reset the state of the node.\n */\n reset = () => {\n // Reset the state of this node.\n this.setState(State.READY);\n\n // Reset the current iteration count.\n this.currentIterationCount = 0;\n\n // Reset the child node.\n this.child.reset();\n };\n\n /**\n * Gets whether an iteration can be made.\n * @returns Whether an iteration can be made.\n */\n private canIterate = () => {\n if (this.targetIterationCount !== null) {\n // We can iterate as long as we have not reached our target iteration count.\n return this.currentIterationCount < this.targetIterationCount;\n }\n\n // If neither an iteration count or a condition function were defined then we can iterate indefinitely.\n return true;\n };\n\n /**\n * Sets the target iteration count.\n * @param options The behaviour tree options object.\n */\n private setTargetIterationCount = (options: BehaviourTreeOptions) => {\n // Are we dealing with an explicit iteration count or will we be randomly picking a iteration count between the min and max iteration count.\n if (this.iterations !== null) {\n this.targetIterationCount = this.iterations;\n } else if (this.iterationsMin !== null && this.iterationsMax !== null) {\n // We will be picking a random iteration count between a min and max iteration count, if the optional 'random'\n // behaviour tree function option is defined then we will be using that, otherwise we will fall back to using Math.random.\n const random = typeof options.random === \"function\" ? options.random : Math.random;\n\n // Pick a random iteration count between a min and max iteration count.\n this.targetIterationCount = Math.floor(\n random() * (this.iterationsMax - this.iterationsMin + 1) + this.iterationsMin\n );\n } else {\n this.targetIterationCount = null;\n }\n };\n}\n", "import Node from \"../Node\";\nimport Decorator from \"./Decorator\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A RETRY node.\n * The node has a single child which can have:\n * -- A number of iterations for which to repeat the child node.\n * -- An infinite repeat loop if neither an iteration count or a condition function is defined.\n * The RETRY node will stop and have a 'SUCCEEDED' state if its child is ever in a 'SUCCEEDED' state after an update.\n * The RETRY node will attempt to move on to the next iteration if its child is ever in a 'FAILED' state.\n */\nexport default class Retry extends Decorator {\n /**\n * @param attributes The node attributes.\n * @param attempts The number of attempts to retry the child node.\n * @param attemptsMin The minimum possible number of attempts to retry the child node.\n * @param attemptsMax The maximum possible number of attempts to retry the child node.\n * @param child The child node.\n */\n constructor(\n attributes: Attribute[],\n private attempts: number | null,\n private attemptsMin: number | null,\n private attemptsMax: number | null,\n child: Node\n ) {\n super(\"retry\", attributes, child);\n }\n\n /**\n * The number of target attempts to make.\n */\n private targetAttemptCount: number | null = null;\n\n /**\n * The current attempt count.\n */\n private currentAttemptCount: number = 0;\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // If this node is in the READY state then we need to reset the child and the target attempt count.\n if (this.is(State.READY)) {\n // Reset the child node.\n this.child.reset();\n\n // Reset the current attempt count.\n this.currentAttemptCount = 0;\n\n // Set the target attempt count.\n this.setTargetAttemptCount(options);\n }\n\n // Do a check to see if we can attempt. If we can then this node will move into the 'RUNNING' state.\n // If we cannot attempt then we have hit our target attempt count, which means that the node has succeeded.\n if (this.canAttempt()) {\n // This node is in the running state and can do its initial attempt.\n this.setState(State.RUNNING);\n\n // We may have already completed an attempt, meaning that the child node will be in the FAILED state.\n // If this is the case then we will have to reset the child node now.\n if (this.child.getState() === State.FAILED) {\n this.child.reset();\n }\n\n // Update the child of this node.\n this.child.update(agent, options);\n\n // If the child moved into the SUCCEEDED state when we updated it then there is nothing left to do and this node has also succeeded.\n // If it has moved into the FAILED state then we have completed the current attempt.\n if (this.child.getState() === State.SUCCEEDED) {\n // The child has succeeded, meaning that this node has succeeded.\n this.setState(State.SUCCEEDED);\n\n return;\n } else if (this.child.getState() === State.FAILED) {\n // We have completed an attempt.\n this.currentAttemptCount += 1;\n }\n } else {\n // This node is in the 'FAILED' state as we cannot iterate any more.\n this.setState(State.FAILED);\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => {\n if (this.attempts !== null) {\n return `RETRY ${this.attempts}x`;\n } else if (this.attemptsMin !== null && this.attemptsMax !== null) {\n return `RETRY ${this.attemptsMin}x-${this.attemptsMax}x`;\n } else {\n return \"RETRY\";\n }\n };\n\n /**\n * Reset the state of the node.\n */\n reset = () => {\n // Reset the state of this node.\n this.setState(State.READY);\n\n // Reset the current attempt count.\n this.currentAttemptCount = 0;\n\n // Reset the child node.\n this.child.reset();\n };\n\n /**\n * Gets whether an attempt can be made.\n * @returns Whether an attempt can be made.\n */\n canAttempt = () => {\n if (this.targetAttemptCount !== null) {\n // We can attempt as long as we have not reached our target attempt count.\n return this.currentAttemptCount < this.targetAttemptCount;\n }\n\n // If neither an attempt count or a condition function were defined then we can attempt indefinitely.\n return true;\n };\n\n /**\n * Sets the target attempt count.\n * @param options The behaviour tree options object.\n */\n setTargetAttemptCount = (options: BehaviourTreeOptions) => {\n // Are we dealing with an explicit attempt count or will we be randomly picking an attempt count between the min and max attempt count.\n if (this.attempts !== null) {\n this.targetAttemptCount = this.attempts;\n } else if (this.attemptsMin !== null && this.attemptsMax !== null) {\n // We will be picking a random attempt count between a min and max attempt count, if the optional 'random'\n // behaviour tree function option is defined then we will be using that, otherwise we will fall back to using Math.random.\n const random = typeof options.random === \"function\" ? options.random : Math.random;\n\n // Pick a random attempt count between a min and max attempt count.\n this.targetAttemptCount = Math.floor(\n random() * (this.attemptsMax - this.attemptsMin + 1) + this.attemptsMin\n );\n } else {\n this.targetAttemptCount = null;\n }\n };\n}\n", "import Node from \"../Node\";\nimport Decorator from \"./Decorator\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A Root node.\n * The root node will have a single child.\n */\nexport default class Root extends Decorator {\n /**\n * @param attributes The node attributes.\n * @param child The child node.\n */\n constructor(attributes: Attribute[], child: Node) {\n super(\"root\", attributes, child);\n }\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // If the child has never been updated or is running then we will need to update it now.\n if (this.child.getState() === State.READY || this.child.getState() === State.RUNNING) {\n // Update the child of this node.\n this.child.update(agent, options);\n }\n\n // The state of the root node is the state of its child.\n this.setState(this.child.getState());\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => \"ROOT\";\n}\n", "import Node from \"../Node\";\nimport Decorator from \"./Decorator\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A Succeed node.\n * This node wraps a single child and will always move to the 'SUCCEEDED' state when the child moves to a 'SUCCEEDED' or 'FAILED' state.\n */\nexport default class Succeed extends Decorator {\n /**\n * @param attributes The node attributes.\n * @param child The child node.\n */\n constructor(attributes: Attribute[], child: Node) {\n super(\"succeed\", attributes, child);\n }\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // If the child has never been updated or is running then we will need to update it now.\n if (this.child.getState() === State.READY || this.child.getState() === State.RUNNING) {\n this.child.update(agent, options);\n }\n\n // The state of this node will depend in the state of its child.\n switch (this.child.getState()) {\n case State.RUNNING:\n this.setState(State.RUNNING);\n break;\n\n case State.SUCCEEDED:\n case State.FAILED:\n this.setState(State.SUCCEEDED);\n break;\n\n default:\n this.setState(State.READY);\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => \"SUCCEED\";\n}\n", "import Node from \"../Node\";\n\n/**\n * A leaf node.\n */\nexport default abstract class Leaf extends Node {\n /**\n * Gets whether this node is a leaf node.\n */\n isLeafNode = () => true;\n}\n", "import { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\nimport State, { CompleteState } from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Leaf from \"./Leaf\";\nimport Lookup from \"../../Lookup\";\nimport Attribute from \"../../attributes/Attribute\";\n\n/**\n * An Action leaf node.\n * This represents an immediate or ongoing state of behaviour.\n */\nexport default class Action extends Leaf {\n /**\n * @param attributes The node attributes.\n * @param actionName The action name.\n * @param actionArguments The array of action argument definitions.\n */\n constructor(attributes: Attribute[], private actionName: string, private actionArguments: any[]) {\n super(\"action\", attributes, actionArguments);\n }\n\n /**\n * Whether there is a pending update promise.\n */\n private isUsingUpdatePromise = false;\n\n /**\n * The finished state result of an update promise.\n */\n private updatePromiseStateResult: CompleteState | null = null;\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // If the result of this action depends on an update promise then there is nothing to do until\n // it resolves, unless there has been a value set as a result of the update promise resolving.\n if (this.isUsingUpdatePromise) {\n // Check whether the update promise has resolved with a state value.\n if (this.updatePromiseStateResult) {\n // Set the state of this node to match the state returned by the promise.\n this.setState(this.updatePromiseStateResult);\n }\n\n return;\n }\n\n // Attempt to get the invoker for the action function.\n const actionFuncInvoker = Lookup.getFuncInvoker(agent, this.actionName);\n\n // The action function should be defined.\n if (actionFuncInvoker === null) {\n throw new Error(\n `cannot update action node as the action '${this.actionName}' function is not defined on the agent and has not been registered`\n );\n }\n\n // Call the action function, the result of which may be:\n // - The finished state of this action node.\n // - A promise to return a finished node state.\n // - Undefined if the node should remain in the running state.\n const updateResult = actionFuncInvoker(this.actionArguments) as CompleteState | Promise;\n\n if (updateResult instanceof Promise) {\n updateResult.then(\n (result) => {\n // If 'isUpdatePromisePending' is null then the promise was cleared as it was resolving, probably via an abort of reset.\n if (!this.isUsingUpdatePromise) {\n return;\n }\n\n // Check to make sure the result is a valid finished state.\n if (result !== State.SUCCEEDED && result !== State.FAILED) {\n throw new Error(\n \"action node promise resolved with an invalid value, expected a State.SUCCEEDED or State.FAILED value to be returned\"\n );\n }\n\n // Set pending update promise state result to be processed on next update.\n this.updatePromiseStateResult = result;\n },\n (reason) => {\n // If 'isUpdatePromisePending' is null then the promise was cleared as it was resolving, probably via an abort of reset.\n if (!this.isUsingUpdatePromise) {\n return;\n }\n\n // Just throw whatever was returned as the rejection argument.\n throw new Error(reason);\n }\n );\n\n // This node will be in the 'RUNNING' state until the update promise resolves.\n this.setState(State.RUNNING);\n\n // We are now waiting for the promise returned by the use to resolve before we know what state this node is in.\n this.isUsingUpdatePromise = true;\n } else {\n // Validate the returned value.\n this.validateUpdateResult(updateResult);\n\n // Set the state of this node, this may be undefined, which just means that the node is still in the 'RUNNING' state.\n this.setState(updateResult || State.RUNNING);\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => this.actionName;\n\n /**\n * Reset the state of the node.\n */\n reset = () => {\n // Reset the state of this node.\n this.setState(State.READY);\n\n // There is no longer an update promise that we care about.\n this.isUsingUpdatePromise = false;\n this.updatePromiseStateResult = null;\n };\n\n /**\n * Validate the result of an update function call.\n * @param result The result of an update function call.\n */\n private validateUpdateResult = (result: CompleteState | boolean) => {\n switch (result) {\n case State.SUCCEEDED:\n case State.FAILED:\n case undefined:\n return;\n default:\n throw new Error(\n `action '${this.actionName}' 'onUpdate' returned an invalid response, expected an optional State.SUCCEEDED or State.FAILED value to be returned`\n );\n }\n };\n}\n", "import { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Leaf from \"./Leaf\";\nimport Lookup from \"../../Lookup\";\nimport Attribute from \"../../attributes/Attribute\";\n\n/**\n * A Condition leaf node.\n * This will succeed or fail immediately based on an agent predicate, without moving to the 'RUNNING' state.\n */\nexport default class Condition extends Leaf {\n /**\n * @param attributes The node attributes.\n * @param conditionName The name of the condition function.\n * @param conditionArguments The array of condition argument definitions.\n */\n constructor(attributes: Attribute[], private conditionName: string, private conditionArguments: any[]) {\n super(\"condition\", attributes, conditionArguments);\n }\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // Attempt to get the invoker for the condition function.\n const conditionFuncInvoker = Lookup.getFuncInvoker(agent, this.conditionName);\n\n // The condition function should be defined.\n if (conditionFuncInvoker === null) {\n throw new Error(\n `cannot update condition node as the condition '${this.conditionName}' function is not defined on the agent and has not been registered`\n );\n }\n\n // Call the condition function to determine the state of this node.\n this.setState(!!conditionFuncInvoker(this.conditionArguments) ? State.SUCCEEDED : State.FAILED);\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => this.conditionName;\n}\n", "import Leaf from \"./Leaf\";\nimport State from \"../../State\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { Agent } from \"../../Agent\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A WAIT node.\n * The state of this node will change to SUCCEEDED after a duration of time\n */\nexport default class Wait extends Leaf {\n /**\n * @param attributes The node attributes.\n * @param duration The duration that this node will wait to succeed in milliseconds.\n * @param durationMin The minimum possible duration in milliseconds that this node will wait to succeed.\n * @param durationMax The maximum possible duration in milliseconds that this node will wait to succeed.\n */\n constructor(\n attributes: Attribute[],\n private duration: number | null,\n private durationMin: number | null,\n private durationMax: number | null\n ) {\n super(\"wait\", attributes, []);\n }\n\n /**\n * The time in milliseconds at which this node was first updated.\n */\n private initialUpdateTime: number = 0;\n\n /**\n * The total duration in milliseconds that this node will be waiting for.\n */\n private totalDuration: number | null = null;\n\n /**\n * The duration in milliseconds that this node has been waiting for.\n */\n private waitedDuration: number = 0;\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // If this node is in the READY state then we need to set the initial update time.\n if (this.is(State.READY)) {\n // Set the initial update time.\n this.initialUpdateTime = new Date().getTime();\n\n // Set the initial waited duration.\n this.waitedDuration = 0;\n\n // Are we dealing with an explicit duration or will we be randomly picking a duration between the min and max duration.\n if (this.duration !== null) {\n this.totalDuration = this.duration;\n } else if (this.durationMin !== null && this.durationMax !== null) {\n // We will be picking a random duration between a min and max duration, if the optional 'random' behaviour tree\n // function option is defined then we will be using that, otherwise we will fall back to using Math.random.\n const random = typeof options.random === \"function\" ? options.random : Math.random;\n\n // Pick a random duration between a min and max duration.\n this.totalDuration = Math.floor(\n random() * (this.durationMax - this.durationMin + 1) + this.durationMin\n );\n } else {\n this.totalDuration = null;\n }\n\n // The node is now running until we finish waiting.\n this.setState(State.RUNNING);\n }\n\n // If we have no total duration then this wait node will wait indefinitely until it is aborted.\n if (this.totalDuration === null) {\n return;\n }\n\n // If we have a 'getDeltaTime' function defined as part of our options then we will use it to figure out how long we have waited for.\n if (typeof options.getDeltaTime === \"function\") {\n // Get the delta time.\n const deltaTime = options.getDeltaTime();\n\n // Our delta time must be a valid number and cannot be NaN.\n if (typeof deltaTime !== \"number\" || isNaN(deltaTime)) {\n throw new Error(\"The delta time must be a valid number and not NaN.\");\n }\n\n // Update the amount of time that this node has been waiting for based on the delta time.\n this.waitedDuration += deltaTime * 1000;\n } else {\n // We are not using a delta time, so we will just work out hom much time has passed since the first update.\n this.waitedDuration = new Date().getTime() - this.initialUpdateTime;\n }\n\n // Have we waited long enough?\n if (this.waitedDuration >= this.totalDuration) {\n // We have finished waiting!\n this.setState(State.SUCCEEDED);\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => {\n if (this.duration !== null) {\n return `WAIT ${this.duration}ms`;\n } else if (this.durationMin !== null && this.durationMax !== null) {\n return `WAIT ${this.durationMin}ms-${this.durationMax}ms`;\n } else {\n return \"WAIT\";\n }\n };\n}\n", "import Guard from \"./guards/Guard\";\n\nexport type AttributeDetails = {\n /** The attribute type. */\n type: string;\n\n /** The attribute arguments. */\n args: any[];\n};\n\n/**\n * A base node attribute.\n */\nexport default abstract class Attribute {\n /**\n * @param type The node attribute type.\n * @param args The array of attribute arguments.\n */\n constructor(public type: string, public args: any[]) {}\n\n /**\n * Gets the attribute details.\n */\n abstract getDetails(): TAttributeDetails;\n\n /**\n * Gets whether this attribute is a guard.\n */\n abstract isGuard: () => this is Guard;\n}\n", "import { Agent } from \"../../Agent\";\nimport Attribute, { AttributeDetails } from \"../Attribute\";\n\nexport type GuardAttributeDetails = {\n /** The name of the condition function that determines whether the guard is satisfied. */\n condition: string;\n} & AttributeDetails;\n\n/**\n * A base node guard attribute.\n */\nexport default abstract class Guard extends Attribute {\n /**\n * @param type The node attribute type.\n * @param args The array of decorator argument definitions.\n * @param condition The name of the condition function that determines whether the guard is satisfied.\n */\n constructor(type: string, args: any[], private condition: string) {\n super(type, args);\n }\n\n /**\n * Gets the name of the condition function that determines whether the guard is satisfied.\n */\n getCondition = () => this.condition;\n\n /**\n * Gets whether this attribute is a guard.\n */\n isGuard = () => true;\n\n /**\n * Gets the attribute details.\n */\n getDetails(): GuardAttributeDetails {\n return {\n type: this.type,\n args: this.args,\n condition: this.getCondition()\n };\n }\n\n /**\n * Gets whether the guard is satisfied.\n * @param agent The agent.\n * @returns Whether the guard is satisfied.\n */\n abstract isSatisfied(agent: Agent): boolean;\n}\n", "import Guard from \"./Guard\";\nimport Lookup from \"../../Lookup\";\nimport { Agent } from \"../../Agent\";\n\n/**\n * A WHILE guard which is satisfied as long as the given condition remains true.\n */\nexport default class While extends Guard {\n /**\n * @param condition The name of the condition function that determines whether the guard is satisfied.\n * @param args The array of decorator argument definitions.\n */\n constructor(condition: string, args: any[]) {\n super(\"while\", args, condition);\n }\n\n /**\n * Gets whether the guard is satisfied.\n * @param agent The agent.\n * @returns Whether the guard is satisfied.\n */\n isSatisfied = (agent: Agent) => {\n // Attempt to get the invoker for the condition function.\n const conditionFuncInvoker = Lookup.getFuncInvoker(agent, this.getCondition());\n\n // The condition function should be defined.\n if (conditionFuncInvoker === null) {\n throw new Error(\n `cannot evaluate node guard as the condition '${this.getCondition()}' function is not defined on the agent and has not been registered`\n );\n }\n\n // Call the condition function to determine whether this guard is satisfied.\n return !!conditionFuncInvoker(this.args);\n };\n}\n", "import Guard from \"./Guard\";\nimport Lookup from \"../../Lookup\";\nimport { Agent } from \"../../Agent\";\n\n/**\n * An UNTIL guard which is satisfied as long as the given condition remains false.\n */\nexport default class Until extends Guard {\n /**\n * @param condition The name of the condition function that determines whether the guard is satisfied.\n * @param args The array of decorator argument definitions.\n */\n constructor(condition: string, args: any[]) {\n super(\"until\", args, condition);\n }\n\n /**\n * Gets whether the guard is satisfied.\n * @param agent The agent.\n * @returns Whether the guard is satisfied.\n */\n isSatisfied = (agent: Agent) => {\n // Attempt to get the invoker for the condition function.\n const conditionFuncInvoker = Lookup.getFuncInvoker(agent, this.getCondition());\n\n // The condition function should be defined.\n if (conditionFuncInvoker === null) {\n throw new Error(\n `cannot evaluate node guard as the condition '${this.getCondition()}' function is not defined on the agent and has not been registered`\n );\n }\n\n // Call the condition function to determine whether this guard is satisfied.\n return !!!conditionFuncInvoker(this.args);\n };\n}\n", "import { Agent } from \"../../Agent\";\nimport Attribute, { AttributeDetails } from \"../Attribute\";\n\nexport type CallbackAttributeDetails = {\n /** The name of the agent function that is called. */\n functionName: string;\n} & AttributeDetails;\n\n/**\n * A base node callback attribute.\n */\nexport default abstract class Callback extends Attribute {\n /**\n * @param type The node attribute type.\n * @param args The array of decorator argument definitions.\n * @param functionName The name of the agent function to call.\n */\n constructor(type: string, args: any[], private functionName: string) {\n super(type, args);\n }\n\n /**\n * Gets the name of the agent function to call.\n */\n getFunctionName = () => this.functionName;\n\n /**\n * Gets whether this attribute is a guard.\n */\n isGuard = () => false;\n\n /**\n * Gets the attribute details.\n */\n getDetails(): CallbackAttributeDetails {\n return {\n type: this.type,\n args: this.args,\n functionName: this.getFunctionName()\n };\n }\n\n /**\n * Attempt to call the agent function that this callback refers to.\n * @param agent The agent.\n */\n abstract callAgentFunction: (agent: Agent, isSuccess: boolean, isAborted: boolean) => void;\n}\n", "import Callback from \"./Callback\";\nimport Lookup from \"../../Lookup\";\nimport { Agent } from \"../../Agent\";\n\n/**\n * An ENTRY callback which defines an agent function to call when the associated node is updated and moves out of running state.\n */\nexport default class Entry extends Callback {\n /**\n * @param functionName The name of the agent function to call.\n * @param args The array of callback argument definitions.\n */\n constructor(functionName: string, args: any[]) {\n super(\"entry\", args, functionName);\n }\n\n /**\n * Attempt to call the agent function that this callback refers to.\n * @param agent The agent.\n */\n callAgentFunction = (agent: Agent) => {\n // Attempt to get the invoker for the callback function.\n const callbackFuncInvoker = Lookup.getFuncInvoker(agent, this.getFunctionName());\n\n // The callback function should be defined.\n if (callbackFuncInvoker === null) {\n throw new Error(\n `cannot call entry function '${this.getFunctionName()}' as is not defined on the agent and has not been registered`\n );\n }\n\n // Call the callback function.\n callbackFuncInvoker(this.args);\n };\n}\n", "import Callback from \"./Callback\";\nimport Lookup from \"../../Lookup\";\nimport { Agent } from \"../../Agent\";\n\n/**\n * A STEP callback which defines an agent function to call when the associated node is updated.\n */\nexport default class Step extends Callback {\n /**\n * @param functionName The name of the agent function to call.\n * @param args The array of callback argument definitions.\n */\n constructor(functionName: string, args: any[]) {\n super(\"step\", args, functionName);\n }\n\n /**\n * Attempt to call the agent function that this callback refers to.\n * @param agent The agent.\n */\n callAgentFunction = (agent: Agent) => {\n // Attempt to get the invoker for the callback function.\n const callbackFuncInvoker = Lookup.getFuncInvoker(agent, this.getFunctionName());\n\n // The callback function should be defined.\n if (callbackFuncInvoker === null) {\n throw new Error(\n `cannot call step function '${this.getFunctionName()}' as is not defined on the agent and has not been registered`\n );\n }\n\n // Call the callback function.\n callbackFuncInvoker(this.args);\n };\n}\n", "import Callback from \"./Callback\";\nimport Lookup from \"../../Lookup\";\nimport { Agent } from \"../../Agent\";\n\n/**\n * An EXIT callback which defines an agent function to call when the associated node is updated and moves to a finished state or is aborted.\n */\nexport default class Exit extends Callback {\n /**\n * @param functionName The name of the agent function to call.\n * @param args The array of callback argument definitions.\n */\n constructor(functionName: string, args: any[]) {\n super(\"exit\", args, functionName);\n }\n\n /**\n * Attempt to call the agent function that this callback refers to.\n * @param agent The agent.\n * @param isSuccess Whether the decorated node was left with a success state.\n * @param isAborted Whether the decorated node was aborted.\n */\n callAgentFunction = (agent: Agent, isSuccess: boolean, isAborted: boolean) => {\n // Attempt to get the invoker for the callback function.\n const callbackFuncInvoker = Lookup.getFuncInvoker(agent, this.getFunctionName());\n\n // The callback function should be defined.\n if (callbackFuncInvoker === null) {\n throw new Error(\n `cannot call exit function '${this.getFunctionName()}' as is not defined on the agent and has not been registered`\n );\n }\n\n // Call the callback function\n callbackFuncInvoker([{ value: { succeeded: isSuccess, aborted: isAborted } }, ...this.args]);\n };\n}\n", "import { AnyNodeDefinition, RootNodeDefinition } from \"./BehaviourTreeDefinition\";\nimport GuardPath, { GuardPathPart } from \"./attributes/guards/GuardPath\";\nimport { validateBranchSubtreeLinks } from \"./BehaviourTreeDefinitionValidator\";\nimport { isInteger } from \"./BehaviourTreeDefinitionUtilities\";\nimport Node from \"./nodes/Node\";\nimport Composite from \"./nodes/composite/Composite\";\nimport Decorator from \"./nodes/decorator/Decorator\";\nimport Parallel from \"./nodes/composite/Parallel\";\nimport Selector from \"./nodes/composite/Selector\";\nimport Sequence from \"./nodes/composite/Sequence\";\nimport Lotto from \"./nodes/composite/Lotto\";\nimport Fail from \"./nodes/decorator/Fail\";\nimport Flip from \"./nodes/decorator/Flip\";\nimport Repeat from \"./nodes/decorator/Repeat\";\nimport Retry from \"./nodes/decorator/Retry\";\nimport Root from \"./nodes/decorator/Root\";\nimport Succeed from \"./nodes/decorator/Succeed\";\nimport Action from \"./nodes/leaf/Action\";\nimport Condition from \"./nodes/leaf/Condition\";\nimport Wait from \"./nodes/leaf/Wait\";\nimport Lookup from \"./Lookup\";\nimport Attribute from \"./attributes/Attribute\";\nimport While from \"./attributes/guards/While\";\nimport Until from \"./attributes/guards/Until\";\nimport Entry from \"./attributes/callbacks/Entry\";\nimport Step from \"./attributes/callbacks/Step\";\nimport Exit from \"./attributes/callbacks/Exit\";\n\n/**\n * A type representing any node instance in a behaviour tree.\n */\ntype AnyNode =\n | Root\n | Action\n | Condition\n | Wait\n | Sequence\n | Selector\n | Lotto\n | Parallel\n | Repeat\n | Retry\n | Flip\n | Succeed\n | Fail;\n\n/**\n * A type defining a mapping of root node identifiers to root node definitions.\n */\ntype RootNodeDefinitionMap = { [key: string | symbol]: RootNodeDefinition };\n\n/**\n * A symbol to use as the main root key in any root node mappings.\n */\nconst MAIN_ROOT_NODE_KEY = Symbol(\"__root__\");\n\n/**\n * Build and populate the root nodes based on the provided definition, assuming that the definition has been validated.\n * @param definition The root node definitions.\n * @returns The built and populated root node definitions.\n */\nexport default function buildRootNode(definition: RootNodeDefinition[]): Root {\n // Create a mapping of root node identifers to root node definitions, including globally registered subtree root node definitions.\n const rootNodeDefinitionMap = createRootNodeDefinitionMap(definition);\n\n // Now that we have all of our root node definitons (those part of the tree definition and those globally\n // registered) we should validate the definition. This will also double-check that we dont have any circular\n // dependencies in our branch -> subtree references and that we have no broken branch -> subtree links.\n validateBranchSubtreeLinks(definition, true);\n\n // Create our populated tree of node instances, starting with our main root node.\n const rootNode = nodeFactory(rootNodeDefinitionMap[MAIN_ROOT_NODE_KEY], rootNodeDefinitionMap) as Root;\n\n // Set a guard path on every leaf of the tree to evaluate as part of each update.\n applyLeafNodeGuardPaths(rootNode);\n\n // We only need to return the main root node.\n return rootNode;\n}\n\n/**\n * A factory function which creates a node instance based on the specified definition.\n * @param definition The node definition.\n * @param rootNodeDefinitionMap The mapping of root node identifers to root node definitions, including globally registered subtree root node definitions.\n * @returns A node instance based on the specified definition.\n */\nfunction nodeFactory(definition: AnyNodeDefinition, rootNodeDefinitionMap: RootNodeDefinitionMap): AnyNode {\n // Get the attributes for the node.\n const attributes = nodeAttributesFactory(definition);\n\n // Create the node instance based on the definition type.\n switch (definition.type) {\n case \"root\":\n return new Root(attributes, nodeFactory(definition.child, rootNodeDefinitionMap));\n\n case \"repeat\":\n let iterations: number | null = null;\n let iterationsMin: number | null = null;\n let iterationsMax: number | null = null;\n\n if (Array.isArray(definition.iterations)) {\n iterationsMin = definition.iterations[0];\n iterationsMax = definition.iterations[1];\n } else if (isInteger(definition.iterations)) {\n iterations = definition.iterations!;\n }\n\n return new Repeat(\n attributes,\n iterations,\n iterationsMin,\n iterationsMax,\n nodeFactory(definition.child, rootNodeDefinitionMap)\n );\n\n case \"retry\":\n let attempts: number | null = null;\n let attemptsMin: number | null = null;\n let attemptsMax: number | null = null;\n\n if (Array.isArray(definition.attempts)) {\n attemptsMin = definition.attempts[0];\n attemptsMax = definition.attempts[1];\n } else if (isInteger(definition.attempts)) {\n attempts = definition.attempts!;\n }\n\n return new Retry(\n attributes,\n attempts,\n attemptsMin,\n attemptsMax,\n nodeFactory(definition.child, rootNodeDefinitionMap)\n );\n\n case \"flip\":\n return new Flip(attributes, nodeFactory(definition.child, rootNodeDefinitionMap));\n\n case \"succeed\":\n return new Succeed(attributes, nodeFactory(definition.child, rootNodeDefinitionMap));\n\n case \"fail\":\n return new Fail(attributes, nodeFactory(definition.child, rootNodeDefinitionMap));\n\n case \"sequence\":\n return new Sequence(\n attributes,\n definition.children.map((child) => nodeFactory(child, rootNodeDefinitionMap))\n );\n\n case \"selector\":\n return new Selector(\n attributes,\n definition.children.map((child) => nodeFactory(child, rootNodeDefinitionMap))\n );\n\n case \"parallel\":\n return new Parallel(\n attributes,\n definition.children.map((child) => nodeFactory(child, rootNodeDefinitionMap))\n );\n\n case \"lotto\":\n return new Lotto(\n attributes,\n definition.weights,\n definition.children.map((child) => nodeFactory(child, rootNodeDefinitionMap))\n );\n\n case \"branch\":\n return nodeFactory(rootNodeDefinitionMap[definition.ref].child, rootNodeDefinitionMap);\n\n case \"action\":\n return new Action(attributes, definition.call, definition.args || []);\n\n case \"condition\":\n return new Condition(attributes, definition.call, definition.args || []);\n\n case \"wait\":\n let duration: number | null = null;\n let durationMin: number | null = null;\n let durationMax: number | null = null;\n\n if (Array.isArray(definition.duration)) {\n durationMin = definition.duration[0];\n durationMax = definition.duration[1];\n } else if (isInteger(definition.duration)) {\n duration = definition.duration!;\n }\n\n return new Wait(attributes, duration, durationMin, durationMax);\n }\n}\n\n/**\n * Creates an array of node attribute instances based on the specified node definition.\n * @param definition The node definition.\n * @returns An array of node attribute instances based on the specified node definition.\n */\nfunction nodeAttributesFactory(definition: AnyNodeDefinition): Attribute[] {\n const attributes: Attribute[] = [];\n\n if (definition.while) {\n attributes.push(new While(definition.while.call, definition.while.args ?? []));\n }\n\n if (definition.until) {\n attributes.push(new Until(definition.until.call, definition.until.args ?? []));\n }\n\n if (definition.entry) {\n attributes.push(new Entry(definition.entry.call, definition.entry.args ?? []));\n }\n\n if (definition.step) {\n attributes.push(new Step(definition.step.call, definition.step.args ?? []));\n }\n\n if (definition.exit) {\n attributes.push(new Exit(definition.exit.call, definition.exit.args ?? []));\n }\n\n return attributes;\n}\n\n/**\n * Creates a mapping of root node identifers to root node definitions, mixing in globally registered subtree root node definitions.\n * @param definition The root node definitions.\n * @returns A mapping of root node identifers to root node definitions, including globally registered subtree root node definitions.\n */\nfunction createRootNodeDefinitionMap(definition: RootNodeDefinition[]): RootNodeDefinitionMap {\n // Create a mapping of root node identifers to root node definitions.\n const rootNodeMap: RootNodeDefinitionMap = {};\n\n // Add in any registered subtree root node definitions.\n for (const [name, rootNodeDefinition] of Object.entries(Lookup.getSubtrees())) {\n // The name used when registering the subtree will be used as the root node identifier.\n rootNodeMap[name] = { ...rootNodeDefinition, id: name };\n }\n\n // Populate the map with the root node definitions that were included with the tree definition.\n // We do this after adding any registered subtrees as we want these to take presedence.\n for (const rootNodeDefinition of definition) {\n rootNodeMap[rootNodeDefinition.id ?? MAIN_ROOT_NODE_KEY] = rootNodeDefinition;\n }\n\n return rootNodeMap;\n}\n\n/**\n * Applies a guard path to every leaf of the tree to evaluate as part of each update.\n * @param root The main root tree node.\n */\nfunction applyLeafNodeGuardPaths(root: Root) {\n const nodePaths: Node[][] = [];\n\n const findLeafNodes = (path: Node[], node: Node) => {\n // Add the current node to the path.\n path = path.concat(node);\n\n // Check whether the current node is a leaf node.\n if (node.isLeafNode()) {\n nodePaths.push(path);\n } else {\n (node as Composite | Decorator).getChildren().forEach((child) => findLeafNodes(path, child));\n }\n };\n\n // Find all leaf node paths, starting from the root.\n findLeafNodes([], root);\n\n nodePaths.forEach((path) => {\n // Each node in the current path will have to be assigned a guard path, working from the root outwards.\n for (let depth = 0; depth < path.length; depth++) {\n // Get the node in the path at the current depth.\n const currentNode = path[depth];\n\n // The node may already have been assigned a guard path, if so just skip it.\n if (currentNode.hasGuardPath()) {\n continue;\n }\n\n // Create the guard path for the current node.\n const guardPath = new GuardPath(\n path\n .slice(0, depth + 1)\n .map((node) => ({ node, guards: node.getGuardAttributes() }))\n .filter((details) => details.guards.length > 0)\n );\n\n // Assign the guard path to the current node.\n currentNode.setGuardPath(guardPath);\n }\n });\n}\n", "import State, { AnyState } from \"./State\";\nimport Lookup from \"./Lookup\";\nimport Node from \"./nodes/Node\";\nimport Root from \"./nodes/decorator/Root\";\nimport Composite from \"./nodes/composite/Composite\";\nimport Decorator from \"./nodes/decorator/Decorator\";\nimport { Agent, GlobalFunction } from \"./Agent\";\nimport { CallbackAttributeDetails } from \"./attributes/callbacks/Callback\";\nimport { GuardAttributeDetails } from \"./attributes/guards/Guard\";\nimport { BehaviourTreeOptions } from \"./BehaviourTreeOptions\";\nimport { convertMDSLToJSON } from \"./mdsl/MDSLDefinitionParser\";\nimport { RootNodeDefinition } from \"./BehaviourTreeDefinition\";\nimport { validateDefinition, validateJSONDefinition } from \"./BehaviourTreeDefinitionValidator\";\nimport buildRootNode from \"./BehaviourTreeBuilder\";\nimport { isNullOrUndefined } from \"./BehaviourTreeDefinitionUtilities\";\n\n// Purely for outside inspection of the tree.\nexport type FlattenedTreeNode = {\n id: string;\n type: string;\n caption: string;\n state: AnyState;\n guards: GuardAttributeDetails[];\n callbacks: CallbackAttributeDetails[];\n args: any[];\n parentId: string | null;\n};\n\n/**\n * A representation of a behaviour tree.\n */\nexport class BehaviourTree {\n /**\n * The main root tree node.\n */\n public readonly rootNode: Root;\n\n /**\n * Creates a new instance of the BehaviourTree class.\n * @param definition The behaviour tree definition.\n * @param agent The agent instance that this behaviour tree is modelling behaviour for.\n * @param options The behaviour tree options object.\n */\n constructor(\n definition: string | RootNodeDefinition | RootNodeDefinition[],\n private agent: Agent,\n private options: BehaviourTreeOptions = {}\n ) {\n // The tree definition must be defined.\n if (isNullOrUndefined(definition)) {\n throw new Error(\"tree definition not defined\");\n }\n\n // The agent must be defined and not null.\n if (typeof agent !== \"object\" || agent === null) {\n throw new Error(\"the agent must be an object and not null\");\n }\n\n // We should validate the definition before we try to build the tree nodes.\n const { succeeded, errorMessage } = validateDefinition(definition);\n\n // Did our validation fail without error?\n if (!succeeded) {\n throw new Error(`invalid definition: ${errorMessage}`);\n }\n\n try {\n // Parse the behaviour tree definition, create the populated tree of behaviour tree nodes, and get the root.\n this.rootNode = this._createRootNode(definition);\n } catch (exception) {\n // There was an issue in trying build and populate the behaviour tree.\n throw new Error(`error building tree: ${(exception as Error).message}`);\n }\n }\n\n /**\n * Gets whether the tree is in the RUNNING state.\n * @returns true if the tree is in the RUNNING state, otherwise false.\n */\n isRunning() {\n return this.rootNode.getState() === State.RUNNING;\n }\n\n /**\n * Gets the current tree state of SUCCEEDED, FAILED, READY or RUNNING.\n * @returns The current tree state.\n */\n getState() {\n return this.rootNode.getState();\n }\n\n /**\n * Step the tree.\n * 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.\n * 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\n * 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.\n *\n * 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.\n */\n step() {\n // If the root node has already been stepped to completion then we need to reset it.\n if (this.rootNode.getState() === State.SUCCEEDED || this.rootNode.getState() === State.FAILED) {\n this.rootNode.reset();\n }\n\n try {\n this.rootNode.update(this.agent, this.options);\n } catch (exception) {\n throw new Error(`error stepping tree: ${(exception as Error).message}`);\n }\n }\n\n /**\n * Resets the tree from the root node outwards to each nested node, giving each a state of READY.\n */\n reset() {\n this.rootNode.reset();\n }\n\n /**\n * Gets the flattened details of every node in the tree.\n * @returns The flattened details of every node in the tree.\n */\n getFlattenedNodeDetails(): FlattenedTreeNode[] {\n // Create an empty flattened array of tree nodes.\n const flattenedTreeNodes: FlattenedTreeNode[] = [];\n\n /**\n * Helper function to process a node instance and push details into the flattened tree nodes array.\n * @param node The current node.\n * @param parentUid The UID of the node parent, or null if the node is the main root node.\n */\n const processNode = (node: Node, parentUid: string | null) => {\n // Get the guard and callback attribute details for this node.\n const guards = node\n .getAttributes()\n .filter((attribute) => attribute.isGuard())\n .map((attribute) => attribute.getDetails()) as GuardAttributeDetails[];\n const callbacks = node\n .getAttributes()\n .filter((attribute) => !attribute.isGuard())\n .map((attribute) => attribute.getDetails()) as CallbackAttributeDetails[];\n\n // Push the current node into the flattened nodes array.\n flattenedTreeNodes.push({\n id: node.getUid(),\n type: node.getType(),\n caption: node.getName(),\n state: node.getState(),\n guards,\n callbacks,\n args: node.getArguments(),\n parentId: parentUid\n });\n\n // Process each of the nodes children if it is not a leaf node.\n if (!node.isLeafNode()) {\n (node as Composite | Decorator)\n .getChildren()\n .forEach((child) => processNode(child, (node as Composite | Decorator).getUid()));\n }\n };\n\n // Convert the nested node structure into a flattened array of node details.\n processNode(this.rootNode, null);\n\n return flattenedTreeNodes;\n }\n\n /**\n * Registers the action/condition/guard/callback function or subtree with the given name.\n * @param name The name of the function or subtree to register.\n * @param value The function or subtree definition to register.\n */\n static register(name: string, value: GlobalFunction | string | RootNodeDefinition) {\n // Are we going to register a action/condition/guard/callback function?\n if (typeof value === \"function\") {\n Lookup.setFunc(name, value);\n return;\n }\n\n // We are not registering an action/condition/guard/callback function, so we must be registering a subtree.\n if (typeof value === \"string\") {\n let rootNodeDefinitions: RootNodeDefinition[];\n\n // We will assume that any string passed in will be a mdsl definition.\n try {\n rootNodeDefinitions = convertMDSLToJSON(value);\n } catch (exception) {\n throw new Error(`error registering definition, invalid MDSL: ${(exception as Error).message}`);\n }\n\n // This function should only ever be called with a definition containing a single unnamed root node.\n if (rootNodeDefinitions.length != 1 || rootNodeDefinitions[0].id !== null) {\n throw new Error(\"error registering definition: expected a single unnamed root node\");\n }\n\n try {\n // We should validate the subtree as we don't want invalid subtrees available via the lookup.\n const { succeeded, errorMessage } = validateJSONDefinition(rootNodeDefinitions[0]);\n\n // Did our validation fail without error?\n if (!succeeded) {\n throw new Error(errorMessage);\n }\n } catch (exception) {\n throw new Error(`error registering definition: ${(exception as Error).message}`);\n }\n\n // Everything seems hunky-dory, register the subtree.\n Lookup.setSubtree(name, rootNodeDefinitions[0]);\n } else if (typeof value === \"object\" && !Array.isArray(value)) {\n // We will assume that any object passed in is a root node definition.\n\n try {\n // We should validate the subtree as we don't want invalid subtrees available via the lookup.\n const { succeeded, errorMessage } = validateJSONDefinition(value);\n\n // Did our validation fail without error?\n if (!succeeded) {\n throw new Error(errorMessage);\n }\n } catch (exception) {\n throw new Error(`error registering definition: ${(exception as Error).message}`);\n }\n\n // Everything seems hunky-dory, register the subtree.\n Lookup.setSubtree(name, value);\n } else {\n throw new Error(\"unexpected value, expected string mdsl definition, root node json definition or function\");\n }\n }\n\n /**\n * Unregisters the registered action/condition/guard/callback function or subtree with the given name.\n * @param name The name of the registered action/condition/guard/callback function or subtree to unregister.\n */\n static unregister(name: string): void {\n Lookup.remove(name);\n }\n\n /**\n * Unregister all registered action/condition/guard/callback functions and subtrees.\n */\n static unregisterAll(): void {\n Lookup.empty();\n }\n\n /**\n * Parses a behaviour tree definition and creates a tree of behaviour tree nodes populated at a root.\n * @param {string | RootNodeDefinition | RootNodeDefinition[]} definition The behaviour tree definition.\n * @returns The root behaviour tree node.\n */\n private _createRootNode(definition: string | RootNodeDefinition | RootNodeDefinition[]): Root {\n // Our definition will have to be converted to JSON if it is a MDSL string.\n // TODO convertMDSLToJSON is called TWICE, once for validation and once here. Maybe return the JSON as part of the validation result?\n const resolvedDefinition = typeof definition === \"string\" ? convertMDSLToJSON(definition) : definition;\n\n // Build and populate the root node.\n return buildRootNode(Array.isArray(resolvedDefinition) ? resolvedDefinition : [resolvedDefinition]);\n }\n}\n"], + "mappings": "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", "names": ["Participant", "isNullOrUndefined", "Lotto", "createLotto", "State", "createLotto"] } diff --git a/src/BehaviourTreeDefinitionValidator.ts b/src/BehaviourTreeDefinitionValidator.ts index 6194931..52a75b9 100644 --- a/src/BehaviourTreeDefinitionValidator.ts +++ b/src/BehaviourTreeDefinitionValidator.ts @@ -242,8 +242,8 @@ function validateNode(definition: any, depth: number): void { validateRootNode(definition, depth); break; - case "success": - validateSuccessNode(definition, depth); + case "succeed": + validateSucceedNode(definition, depth); break; case "fail": @@ -274,6 +274,10 @@ function validateNode(definition: any, depth: number): void { validateParallelNode(definition, depth); break; + case "lotto": + validateLottoNode(definition, depth); + break; + default: throw new Error(`unexpected node type of '${definition.type}' at depth '${depth}'`); } @@ -352,19 +356,19 @@ function validateRootNode(definition: any, depth: number): void { } /** - * Validate an object that we expect to be a success node definition. - * @param definition An object that we expect to be a success node definition. + * Validate an object that we expect to be a succeed node definition. + * @param definition An object that we expect to be a succeed node definition. * @param depth The depth of the node in the definition tree. */ -function validateSuccessNode(definition: any, depth: number): void { +function validateSucceedNode(definition: any, depth: number): void { // Check that the node type is correct. - if (definition.type !== "success") { - throw new Error(`expected node type of 'success' for success node at depth '${depth}'`); + if (definition.type !== "succeed") { + throw new Error(`expected node type of 'succeed' for succeed node at depth '${depth}'`); } - // A success node is a decorator node, so must have a child node defined. + // A succeed node is a decorator node, so must have a child node defined. if (typeof definition.child === "undefined") { - throw new Error(`expected property 'child' to be defined for success node at depth '${depth}'`); + throw new Error(`expected property 'child' to be defined for succeed node at depth '${depth}'`); } // Validate the node attributes. @@ -440,7 +444,7 @@ function validateRepeatNode(definition: any, depth: number): void { if (typeof definition.iterations !== "undefined") { if (Array.isArray(definition.iterations)) { // Check whether any elements of the array are not integer values. - const containsNonInteger = !!definition.iterations.find((value: unknown) => !isInteger(value)); + const containsNonInteger = !!definition.iterations.filter((value: unknown) => !isInteger(value)).length; // If the 'iterations' property is an array then it MUST contain two integer values. if (definition.iterations.length !== 2 || containsNonInteger) { @@ -503,7 +507,7 @@ function validateRetryNode(definition: any, depth: number): void { if (typeof definition.attempts !== "undefined") { if (Array.isArray(definition.attempts)) { // Check whether any elements of the array are not integer values. - const containsNonInteger = !!definition.attempts.find((value: unknown) => !isInteger(value)); + const containsNonInteger = !!definition.attempts.filter((value: unknown) => !isInteger(value)).length; // If the 'attempts' property is an array then it MUST contain two integer values. if (definition.attempts.length !== 2 || containsNonInteger) { @@ -646,7 +650,7 @@ function validateWaitNode(definition: any, depth: number): void { if (typeof definition.duration !== "undefined") { if (Array.isArray(definition.duration)) { // Check whether any elements of the array are not integer values. - const containsNonInteger = !!definition.duration.find((value: unknown) => !isInteger(value)); + const containsNonInteger = !!definition.duration.filter((value: unknown) => !isInteger(value)).length; // If the 'duration' property is an array then it MUST contain two integer values. if (definition.duration.length !== 2 || containsNonInteger) { @@ -755,6 +759,44 @@ function validateParallelNode(definition: any, depth: number): void { definition.children.forEach((child: any) => validateNode(child, depth + 1)); } +/** + * Validate an object that we expect to be a lotto node definition. + * @param definition An object that we expect to be a lotto node definition. + * @param depth The depth of the node in the definition tree. + */ +function validateLottoNode(definition: any, depth: number): void { + // Check that the node type is correct. + if (definition.type !== "lotto") { + throw new Error(`expected node type of 'lotto' for lotto node at depth '${depth}'`); + } + + // A lotto node is a composite node, so must have a children nodes array defined. + if (!Array.isArray(definition.children) || definition.children.length === 0) { + throw new Error(`expected non-empty 'children' array to be defined for lotto node at depth '${depth}'`); + } + + // Check whether a 'weights' property has been defined, if it has we expect it to be an array of weights. + if (typeof definition.weights !== "undefined") { + // Check that the weights property is an array of positive integers with an element for each child node element. + if ( + !Array.isArray(definition.weights) || + definition.weights.length !== definition.children.length || + definition.weights.filter((value: unknown) => !isInteger(value)).length || + definition.weights.filter((value: number) => value < 0).length + ) { + throw new Error( + `expected an array of positive integer weight values with a length matching the number of child nodes for 'weights' property if defined for lotto node at depth '${depth}'` + ); + } + } + + // Validate the node attributes. + validateNodeAttributes(definition, depth); + + // Validate the child nodes of this composite node. + definition.children.forEach((child: any) => validateNode(child, depth + 1)); +} + /** * A helper function to create a failure validation result with the given error message. * @param errorMessage The validation failure error message. diff --git a/src/mdsl/MDSLDefinitionParser.ts b/src/mdsl/MDSLDefinitionParser.ts index a0208ca..25bcd20 100644 --- a/src/mdsl/MDSLDefinitionParser.ts +++ b/src/mdsl/MDSLDefinitionParser.ts @@ -554,16 +554,16 @@ function createLottoNode(tokens: string[], stringLiteralPlaceholders: StringLite // If any node arguments have been defined then they must be our weights. const nodeArguments = parseArgumentTokens(tokens, stringLiteralPlaceholders); - // All lotto node arguments MUST be of type number and must be integer. + // All lotto node arguments MUST be of type number and must be positive integers. nodeArguments - .filter((arg) => arg.type !== "number" || !arg.isInteger) + .filter((arg) => arg.type !== "number" || !arg.isInteger || arg.value < 0) .forEach(() => { - throw new Error(`lotto node weight arguments must be integer values`); + throw new Error(`lotto node weight arguments must be positive integer values`); }); const node = { type: "lotto", - weights: nodeArguments.map(({ value }) => value), + weights: nodeArguments.length ? nodeArguments.map(({ value }) => value) : undefined, ...parseAttributeTokens(tokens, stringLiteralPlaceholders) } as LottoNodeDefinition; @@ -731,16 +731,29 @@ function createBranchNode( /** * Validate a fully-populated node definition that was popped off of the tree stack. - * @param node The popped node to validate. + * @param definition The popped node to validate. */ -function validatePoppedNode(node: AnyNodeDefinition): void { +function validatePoppedNode(definition: AnyNodeDefinition): void { // Decorators MUST have a child defined. - if (isDecoratorNode(node) && isNullOrUndefined(node.child)) { - throw new Error(`a ${node.type} node must have a single child node defined`); + if (isDecoratorNode(definition) && isNullOrUndefined(definition.child)) { + throw new Error(`a ${definition.type} node must have a single child node defined`); } // Composites MUST have at least one child defined. - if (isCompositeNode(node) && !node.children?.length) { - throw new Error(`a ${node.type} node must have at least a single child node defined`); + if (isCompositeNode(definition) && !definition.children?.length) { + throw new Error(`a ${definition.type} node must have at least a single child node defined`); + } + + // We need to make sure that lotto nodes that have weights defined have a number of weights matching the number of child nodes. + if (definition.type === "lotto") { + // Check whether a 'weights' property has been defined, if it has we expect it to be an array of weights. + if (typeof definition.weights !== "undefined") { + // Check that the weights property is an array of positive integers with an element for each child node element. + if (definition.weights.length !== definition.children.length) { + throw new Error( + "expected a number of weight arguments matching the number of child nodes for lotto node" + ); + } + } } } diff --git a/test/behaviourTree.test.js b/test/BehaviourTree.test.js similarity index 100% rename from test/behaviourTree.test.js rename to test/BehaviourTree.test.js diff --git a/test/nodes/composite/Lotto.test.js b/test/nodes/composite/Lotto.test.js index a8f00e1..7376e31 100644 --- a/test/nodes/composite/Lotto.test.js +++ b/test/nodes/composite/Lotto.test.js @@ -7,113 +7,464 @@ const findNode = (tree, type, caption) => tree.getFlattenedNodeDetails().find((n describe("A Lotto node", () => { describe("on tree initialisation", () => { - it("will error if the node does not have at least one child", () => { - const definition = "root { lotto {} }"; - assert.throws( - () => new mistreevous.BehaviourTree(definition, {}), - Error, - "invalid definition: a lotto node must have at least a single child" - ); + describe("will error if the node does not have at least one child", () => { + it("(MDSL)", () => { + const definition = "root { lotto {} }"; + assert.throws( + () => new mistreevous.BehaviourTree(definition, {}), + Error, + "invalid definition: a lotto node must have at least a single child" + ); + }); + + it("(JSON)", () => { + const definition = { + type: "root", + child: { + type: "lotto", + children: [] + } + }; + assert.throws( + () => new mistreevous.BehaviourTree(definition, {}), + Error, + "invalid definition: expected non-empty 'children' array to be defined for lotto node at depth '1'" + ); + }); + }); + + describe("will error if any optional weights are defined and", () => { + describe("are not positive integer values", () => { + it("(MDSL)", () => { + let definition = "root { lotto [-1] { action [SomeAction] } }"; + assert.throws( + () => new mistreevous.BehaviourTree(definition, {}), + Error, + "invalid definition: lotto node weight arguments must be positive integer values" + ); + + definition = "root { lotto [1.234] { action [SomeAction] } }"; + assert.throws( + () => new mistreevous.BehaviourTree(definition, {}), + Error, + "invalid definition: lotto node weight arguments must be positive integer values" + ); + + definition = 'root { lotto ["some-string"] { action [SomeAction] } }'; + assert.throws( + () => new mistreevous.BehaviourTree(definition, {}), + Error, + "invalid definition: lotto node weight arguments must be positive integer values" + ); + + definition = "root { lotto [false] { action [SomeAction] } }"; + assert.throws( + () => new mistreevous.BehaviourTree(definition, {}), + Error, + "invalid definition: lotto node weight arguments must be positive integer values" + ); + }); + + it("(JSON)", () => { + let definition = { + type: "root", + child: { + type: "lotto", + weights: [-1], + children: [ + { + type: "action", + call: "SomeAction" + } + ] + } + }; + assert.throws( + () => new mistreevous.BehaviourTree(definition, {}), + Error, + "invalid definition: expected an array of positive integer weight values with a length matching the number of child nodes for 'weights' property if defined for lotto node at depth '1'" + ); + + definition = { + type: "root", + child: { + type: "lotto", + weights: [1.234], + children: [ + { + type: "action", + call: "SomeAction" + } + ] + } + }; + assert.throws( + () => new mistreevous.BehaviourTree(definition, {}), + Error, + "invalid definition: expected an array of positive integer weight values with a length matching the number of child nodes for 'weights' property if defined for lotto node at depth '1'" + ); + + definition = { + type: "root", + child: { + type: "lotto", + weights: ["some-string"], + children: [ + { + type: "action", + call: "SomeAction" + } + ] + } + }; + assert.throws( + () => new mistreevous.BehaviourTree(definition, {}), + Error, + "invalid definition: expected an array of positive integer weight values with a length matching the number of child nodes for 'weights' property if defined for lotto node at depth '1'" + ); + + definition = { + type: "root", + child: { + type: "lotto", + weights: [false], + children: [ + { + type: "action", + call: "SomeAction" + } + ] + } + }; + assert.throws( + () => new mistreevous.BehaviourTree(definition, {}), + Error, + "invalid definition: expected an array of positive integer weight values with a length matching the number of child nodes for 'weights' property if defined for lotto node at depth '1'" + ); + }); + }); + + describe("the number of weights does not match the number of child nodes", () => { + it("(MDSL)", () => { + const definition = "root { lotto [1] { action [SomeAction] action [SomeOtherAction] } }"; + assert.throws( + () => new mistreevous.BehaviourTree(definition, {}), + Error, + "invalid definition: expected a number of weight arguments matching the number of child nodes for lotto node" + ); + }); + + it("(JSON)", () => { + const definition = { + type: "root", + child: { + type: "lotto", + weights: [1], + children: [ + { + type: "action", + call: "SomeAction" + }, + { + type: "action", + call: "SomeOtherAction" + } + ] + } + }; + assert.throws( + () => new mistreevous.BehaviourTree(definition, {}), + Error, + "invalid definition: expected an array of positive integer weight values with a length matching the number of child nodes for 'weights' property if defined for lotto node at depth '1'" + ); + }); + }); }); }); describe("when updated as part of a tree step will", () => { - it("when initially in the READY state will select a child node at random to be the single active child node", () => { - const definition = "root { lotto { condition [IsTrue] } }"; - const agent = { IsTrue: () => true }; - const tree = new mistreevous.BehaviourTree(definition, agent); - - let lottoNode = findNode(tree, "lotto"); - let childNode = findNode(tree, "condition"); - assert.strictEqual(lottoNode.state, mistreevous.State.READY); - assert.strictEqual(childNode.state, mistreevous.State.READY); - - tree.step(); - - lottoNode = findNode(tree, "lotto"); - childNode = findNode(tree, "condition"); - assert.strictEqual(lottoNode.state, mistreevous.State.SUCCEEDED); - assert.strictEqual(childNode.state, mistreevous.State.SUCCEEDED); + describe("when initially in the READY state will select a child node at random to be the single active child node", () => { + it("(MDSL)", () => { + const definition = "root { lotto { condition [IsTrue] } }"; + const agent = { IsTrue: () => true }; + const tree = new mistreevous.BehaviourTree(definition, agent); + + let lottoNode = findNode(tree, "lotto"); + let childNode = findNode(tree, "condition"); + assert.strictEqual(lottoNode.state, mistreevous.State.READY); + assert.strictEqual(childNode.state, mistreevous.State.READY); + + tree.step(); + + lottoNode = findNode(tree, "lotto"); + childNode = findNode(tree, "condition"); + assert.strictEqual(lottoNode.state, mistreevous.State.SUCCEEDED); + assert.strictEqual(childNode.state, mistreevous.State.SUCCEEDED); + }); + + it("(JSON)", () => { + const definition = { + type: "root", + child: { + type: "lotto", + children: [ + { + type: "condition", + call: "IsTrue" + } + ] + } + }; + const agent = { IsTrue: () => true }; + const tree = new mistreevous.BehaviourTree(definition, agent); + + let lottoNode = findNode(tree, "lotto"); + let childNode = findNode(tree, "condition"); + assert.strictEqual(lottoNode.state, mistreevous.State.READY); + assert.strictEqual(childNode.state, mistreevous.State.READY); + + tree.step(); + + lottoNode = findNode(tree, "lotto"); + childNode = findNode(tree, "condition"); + assert.strictEqual(lottoNode.state, mistreevous.State.SUCCEEDED); + assert.strictEqual(childNode.state, mistreevous.State.SUCCEEDED); + }); + }); + + describe("will use the 'random' function to select the single active child if it was defined as a behaviour tree option", () => { + it("(MDSL)", () => { + const definition = + "root { lotto { condition [IsFalse] condition [IsFalse] condition [IsFalse] condition [IsTrue] condition [IsFalse] condition [IsFalse] } }"; + const agent = { + IsTrue: () => true, + IsFalse: () => false + }; + const options = { + // Usually this would return a new pseudo-random number each time, but for the sake of this test we + // just want to make sure that the number we return actually has an impact on which child node of the + // lotto node is selected. A value of 0.6 should always result in the fourth child out of six being picked. + random: () => 0.6 + }; + const tree = new mistreevous.BehaviourTree(definition, agent, options); + + let lottoNode = findNode(tree, "lotto"); + assert.strictEqual(lottoNode.state, mistreevous.State.READY); + + tree.step(); + + // Check that the lotto node has moved into the SUCCEEDED state. This would only + // have happened if the fourth condition node was selected by the lotto node. + lottoNode = findNode(tree, "lotto"); + assert.strictEqual(lottoNode.state, mistreevous.State.SUCCEEDED); + }); + + it("(JSON)", () => { + const definition = { + type: "root", + child: { + type: "lotto", + children: [ + { + type: "condition", + call: "IsFalse" + }, + { + type: "condition", + call: "IsFalse" + }, + { + type: "condition", + call: "IsFalse" + }, + { + type: "condition", + call: "IsTrue" + }, + { + type: "condition", + call: "IsFalse" + }, + { + type: "condition", + call: "IsFalse" + } + ] + } + }; + const agent = { + IsTrue: () => true, + IsFalse: () => false + }; + const options = { + // Usually this would return a new pseudo-random number each time, but for the sake of this test we + // just want to make sure that the number we return actually has an impact on which child node of the + // lotto node is selected. A value of 0.6 should always result in the fourth child out of six being picked. + random: () => 0.6 + }; + const tree = new mistreevous.BehaviourTree(definition, agent, options); + + let lottoNode = findNode(tree, "lotto"); + assert.strictEqual(lottoNode.state, mistreevous.State.READY); + + tree.step(); + + // Check that the lotto node has moved into the SUCCEEDED state. This would only + // have happened if the fourth condition node was selected by the lotto node. + lottoNode = findNode(tree, "lotto"); + assert.strictEqual(lottoNode.state, mistreevous.State.SUCCEEDED); + }); }); - it("will use the 'random' function to select the single active child if it was defined as a behaviour tree option", () => { - const definition = - "root { lotto { condition [IsFalse] condition [IsFalse] condition [IsFalse] condition [IsTrue] condition [IsFalse] condition [IsFalse] } }"; - const agent = { - IsTrue: () => true, - IsFalse: () => false - }; - const options = { - // Usually this would return a new pseudo-random number each time, but for the sake of this test we - // just want to make sure that the number we return actually has an impact on which child node of the - // lotto node is selected. A value of 0.6 should always result in the fourth child out of six being picked. - random: () => 0.6 - }; - const tree = new mistreevous.BehaviourTree(definition, agent, options); - - let lottoNode = findNode(tree, "lotto"); - assert.strictEqual(lottoNode.state, mistreevous.State.READY); - - tree.step(); - - // Check that the lotto node has moved into the SUCCEEDED state. This would only - // have happened if the fourth condition node was selected by the lotto node. - lottoNode = findNode(tree, "lotto"); - assert.strictEqual(lottoNode.state, mistreevous.State.SUCCEEDED); + it("can optionally have weights defined and will use them to influence the selection of the single active child", () => { + // TODO Need to figure out how to spy on createLotto as there is no other way to test this. }); - it("move to the SUCCESS state if the selected child node moves to the SUCCESS state", () => { - const definition = "root { lotto { condition [IsTrue] } }"; - const agent = { IsTrue: () => true }; - const tree = new mistreevous.BehaviourTree(definition, agent); + describe("move to the SUCCESS state if the selected child node moves to the SUCCESS state", () => { + it("(MDSL)", () => { + const definition = "root { lotto { condition [IsTrue] } }"; + const agent = { IsTrue: () => true }; + const tree = new mistreevous.BehaviourTree(definition, agent); + + let lottoNode = findNode(tree, "lotto"); + let childNode = findNode(tree, "condition"); + assert.strictEqual(lottoNode.state, mistreevous.State.READY); + assert.strictEqual(childNode.state, mistreevous.State.READY); + + tree.step(); - let lottoNode = findNode(tree, "lotto"); - let childNode = findNode(tree, "condition"); - assert.strictEqual(lottoNode.state, mistreevous.State.READY); - assert.strictEqual(childNode.state, mistreevous.State.READY); + lottoNode = findNode(tree, "lotto"); + childNode = findNode(tree, "condition"); + assert.strictEqual(lottoNode.state, mistreevous.State.SUCCEEDED); + assert.strictEqual(childNode.state, mistreevous.State.SUCCEEDED); + }); - tree.step(); + it("(JSON)", () => { + const definition = { + type: "root", + child: { + type: "lotto", + children: [ + { + type: "condition", + call: "IsTrue" + } + ] + } + }; + const agent = { IsTrue: () => true }; + const tree = new mistreevous.BehaviourTree(definition, agent); - lottoNode = findNode(tree, "lotto"); - childNode = findNode(tree, "condition"); - assert.strictEqual(lottoNode.state, mistreevous.State.SUCCEEDED); - assert.strictEqual(childNode.state, mistreevous.State.SUCCEEDED); + let lottoNode = findNode(tree, "lotto"); + let childNode = findNode(tree, "condition"); + assert.strictEqual(lottoNode.state, mistreevous.State.READY); + assert.strictEqual(childNode.state, mistreevous.State.READY); + + tree.step(); + + lottoNode = findNode(tree, "lotto"); + childNode = findNode(tree, "condition"); + assert.strictEqual(lottoNode.state, mistreevous.State.SUCCEEDED); + assert.strictEqual(childNode.state, mistreevous.State.SUCCEEDED); + }); }); - it("move to the FAILED state if the selected child node moves to the FAILED state", () => { - const definition = "root { lotto { condition [IsFalse] } }"; - const agent = { IsFalse: () => false }; - const tree = new mistreevous.BehaviourTree(definition, agent); + describe("move to the FAILED state if the selected child node moves to the FAILED state", () => { + it("(MDSL)", () => { + const definition = "root { lotto { condition [IsFalse] } }"; + const agent = { IsFalse: () => false }; + const tree = new mistreevous.BehaviourTree(definition, agent); + + let lottoNode = findNode(tree, "lotto"); + let childNode = findNode(tree, "condition"); + assert.strictEqual(lottoNode.state, mistreevous.State.READY); + assert.strictEqual(childNode.state, mistreevous.State.READY); + + tree.step(); + + lottoNode = findNode(tree, "lotto"); + childNode = findNode(tree, "condition"); + assert.strictEqual(lottoNode.state, mistreevous.State.FAILED); + assert.strictEqual(childNode.state, mistreevous.State.FAILED); + }); - let lottoNode = findNode(tree, "lotto"); - let childNode = findNode(tree, "condition"); - assert.strictEqual(lottoNode.state, mistreevous.State.READY); - assert.strictEqual(childNode.state, mistreevous.State.READY); + it("(JSON)", () => { + const definition = { + type: "root", + child: { + type: "lotto", + children: [ + { + type: "condition", + call: "IsFalse" + } + ] + } + }; + const agent = { IsFalse: () => false }; + const tree = new mistreevous.BehaviourTree(definition, agent); - tree.step(); + let lottoNode = findNode(tree, "lotto"); + let childNode = findNode(tree, "condition"); + assert.strictEqual(lottoNode.state, mistreevous.State.READY); + assert.strictEqual(childNode.state, mistreevous.State.READY); - lottoNode = findNode(tree, "lotto"); - childNode = findNode(tree, "condition"); - assert.strictEqual(lottoNode.state, mistreevous.State.FAILED); - assert.strictEqual(childNode.state, mistreevous.State.FAILED); + tree.step(); + + lottoNode = findNode(tree, "lotto"); + childNode = findNode(tree, "condition"); + assert.strictEqual(lottoNode.state, mistreevous.State.FAILED); + assert.strictEqual(childNode.state, mistreevous.State.FAILED); + }); }); - it("move to the RUNNING state if the selected child node does not move to the SUCCESS or FAILED state", () => { - const definition = "root { lotto { action [someAction] } }"; - const agent = { someAction: () => {} }; - const tree = new mistreevous.BehaviourTree(definition, agent); + describe("move to the RUNNING state if the selected child node does not move to the SUCCESS or FAILED state", () => { + it("(MDSL)", () => { + const definition = "root { lotto { action [someAction] } }"; + const agent = { someAction: () => {} }; + const tree = new mistreevous.BehaviourTree(definition, agent); + + let lottoNode = findNode(tree, "lotto"); + let actionNode = findNode(tree, "action"); + assert.strictEqual(lottoNode.state, mistreevous.State.READY); + assert.strictEqual(actionNode.state, mistreevous.State.READY); + + tree.step(); + + lottoNode = findNode(tree, "lotto"); + actionNode = findNode(tree, "action"); + assert.strictEqual(lottoNode.state, mistreevous.State.RUNNING); + assert.strictEqual(actionNode.state, mistreevous.State.RUNNING); + }); + + it("(JSON)", () => { + const definition = { + type: "root", + child: { + type: "lotto", + children: [ + { + type: "action", + call: "someAction" + } + ] + } + }; + const agent = { someAction: () => {} }; + const tree = new mistreevous.BehaviourTree(definition, agent); - let lottoNode = findNode(tree, "lotto"); - let actionNode = findNode(tree, "action"); - assert.strictEqual(lottoNode.state, mistreevous.State.READY); - assert.strictEqual(actionNode.state, mistreevous.State.READY); + let lottoNode = findNode(tree, "lotto"); + let actionNode = findNode(tree, "action"); + assert.strictEqual(lottoNode.state, mistreevous.State.READY); + assert.strictEqual(actionNode.state, mistreevous.State.READY); - tree.step(); + tree.step(); - lottoNode = findNode(tree, "lotto"); - actionNode = findNode(tree, "action"); - assert.strictEqual(lottoNode.state, mistreevous.State.RUNNING); - assert.strictEqual(actionNode.state, mistreevous.State.RUNNING); + lottoNode = findNode(tree, "lotto"); + actionNode = findNode(tree, "action"); + assert.strictEqual(lottoNode.state, mistreevous.State.RUNNING); + assert.strictEqual(actionNode.state, mistreevous.State.RUNNING); + }); }); }); }); diff --git a/test/nodes/composite/Parallel.test.js b/test/nodes/composite/Parallel.test.js new file mode 100644 index 0000000..4899487 --- /dev/null +++ b/test/nodes/composite/Parallel.test.js @@ -0,0 +1,36 @@ +const mistreevous = require("../../../dist/index"); +const chai = require("chai"); + +var assert = chai.assert; + +describe("A Parallel node", () => { + describe("on tree initialisation", () => { + describe("will error if the node does not have at least one child", () => { + it("(MDSL)", () => { + const definition = "root { parallel {} }"; + assert.throws( + () => new mistreevous.BehaviourTree(definition, {}), + Error, + "invalid definition: a parallel node must have at least a single child" + ); + }); + + it("(JSON)", () => { + const definition = { + type: "root", + child: { + type: "parallel", + children: [] + } + }; + assert.throws( + () => new mistreevous.BehaviourTree(definition, {}), + Error, + "invalid definition: expected non-empty 'children' array to be defined for parallel node at depth '1'" + ); + }); + }); + }); + + describe("when updated as part of a tree step will", () => {}); +}); diff --git a/test/nodes/composite/Selector.test.js b/test/nodes/composite/Selector.test.js new file mode 100644 index 0000000..e1cf352 --- /dev/null +++ b/test/nodes/composite/Selector.test.js @@ -0,0 +1,36 @@ +const mistreevous = require("../../../dist/index"); +const chai = require("chai"); + +var assert = chai.assert; + +describe("A Selector node", () => { + describe("on tree initialisation", () => { + describe("will error if the node does not have at least one child", () => { + it("(MDSL)", () => { + const definition = "root { selector {} }"; + assert.throws( + () => new mistreevous.BehaviourTree(definition, {}), + Error, + "invalid definition: a selector node must have at least a single child" + ); + }); + + it("(JSON)", () => { + const definition = { + type: "root", + child: { + type: "selector", + children: [] + } + }; + assert.throws( + () => new mistreevous.BehaviourTree(definition, {}), + Error, + "invalid definition: expected non-empty 'children' array to be defined for selector node at depth '1'" + ); + }); + }); + }); + + describe("when updated as part of a tree step will", () => {}); +}); diff --git a/test/nodes/composite/Sequence.test.js b/test/nodes/composite/Sequence.test.js new file mode 100644 index 0000000..4be3a2f --- /dev/null +++ b/test/nodes/composite/Sequence.test.js @@ -0,0 +1,36 @@ +const mistreevous = require("../../../dist/index"); +const chai = require("chai"); + +var assert = chai.assert; + +describe("A Sequence node", () => { + describe("on tree initialisation", () => { + describe("will error if the node does not have at least one child", () => { + it("(MDSL)", () => { + const definition = "root { sequence {} }"; + assert.throws( + () => new mistreevous.BehaviourTree(definition, {}), + Error, + "invalid definition: a sequence node must have at least a single child" + ); + }); + + it("(JSON)", () => { + const definition = { + type: "root", + child: { + type: "sequence", + children: [] + } + }; + assert.throws( + () => new mistreevous.BehaviourTree(definition, {}), + Error, + "invalid definition: expected non-empty 'children' array to be defined for sequence node at depth '1'" + ); + }); + }); + }); + + describe("when updated as part of a tree step will", () => {}); +}); diff --git a/test/nodes/decorator/Fail.test.js b/test/nodes/decorator/Fail.test.js new file mode 100644 index 0000000..eaac606 --- /dev/null +++ b/test/nodes/decorator/Fail.test.js @@ -0,0 +1,157 @@ +const mistreevous = require("../../../dist/index"); +const chai = require("chai"); + +var assert = chai.assert; + +const findNode = (tree, type, caption) => + tree.getFlattenedNodeDetails().find((node) => node.type === type && node.caption === caption); + +describe("A Fail node", () => { + describe("on tree initialisation", () => { + describe("will error if the node does not have a single child", () => { + it("(MDSL)", () => { + const definition = "root { fail {} }"; + assert.throws( + () => new mistreevous.BehaviourTree(definition, {}), + Error, + "invalid definition: a fail node must have a single child" + ); + }); + + it("(JSON)", () => { + const definition = { + type: "root", + child: { + type: "fail" + } + }; + assert.throws( + () => new mistreevous.BehaviourTree(definition, {}), + Error, + "invalid definition: expected property 'child' to be defined for fail node at depth '1'" + ); + }); + }); + }); + + describe("when updated as part of a tree step will", () => { + describe("move to the FAILED state if the child node moves to the", () => { + describe("FAILED state", () => { + it("(MDSL)", () => { + const definition = "root { fail { condition [someCondition] } }"; + const agent = { someCondition: () => false }; + const tree = new mistreevous.BehaviourTree(definition, agent); + + let node = findNode(tree, "fail", "FAIL"); + assert.strictEqual(node.state, mistreevous.State.READY); + + tree.step(); + + node = findNode(tree, "fail", "FAIL"); + assert.strictEqual(node.state, mistreevous.State.FAILED); + }); + + it("(JSON)", () => { + const definition = { + type: "root", + child: { + type: "fail", + child: { + type: "condition", + call: "someCondition" + } + } + }; + const agent = { someCondition: () => false }; + const tree = new mistreevous.BehaviourTree(definition, agent); + + let node = findNode(tree, "fail", "FAIL"); + assert.strictEqual(node.state, mistreevous.State.READY); + + tree.step(); + + node = findNode(tree, "fail", "FAIL"); + assert.strictEqual(node.state, mistreevous.State.FAILED); + }); + }); + + describe("SUCCESS state", () => { + it("(MDSL)", () => { + const definition = "root { fail { condition [someCondition] } }"; + const agent = { someCondition: () => true }; + const tree = new mistreevous.BehaviourTree(definition, agent); + + let node = findNode(tree, "fail", "FAIL"); + assert.strictEqual(node.state, mistreevous.State.READY); + + tree.step(); + + node = findNode(tree, "fail", "FAIL"); + assert.strictEqual(node.state, mistreevous.State.FAILED); + }); + + it("(JSON)", () => { + const definition = { + type: "root", + child: { + type: "fail", + child: { + type: "condition", + call: "someCondition" + } + } + }; + const agent = { someCondition: () => true }; + const tree = new mistreevous.BehaviourTree(definition, agent); + + let node = findNode(tree, "fail", "FAIL"); + assert.strictEqual(node.state, mistreevous.State.READY); + + tree.step(); + + node = findNode(tree, "fail", "FAIL"); + assert.strictEqual(node.state, mistreevous.State.FAILED); + }); + }); + }); + + describe("move to the RUNNING state if the child node does not move to the SUCCESS or FAILED state", () => { + it("(MDSL)", () => { + const definition = "root { fail { action [someAction] } }"; + const agent = { someAction: () => {} }; + const tree = new mistreevous.BehaviourTree(definition, agent); + + let node = findNode(tree, "fail", "FAIL"); + assert.strictEqual(node.state, mistreevous.State.READY); + + tree.step(); + + node = findNode(tree, "fail", "FAIL"); + assert.strictEqual(node.state, mistreevous.State.RUNNING); + }); + + it("(JSON)", () => { + const definition = { + type: "root", + child: { + type: "fail", + child: { + type: "action", + call: "someAction" + } + } + }; + const agent = { someAction: () => {} }; + const tree = new mistreevous.BehaviourTree(definition, agent); + + let node = findNode(tree, "fail", "FAIL"); + assert.strictEqual(node.state, mistreevous.State.READY); + + tree.step(); + + node = findNode(tree, "fail", "FAIL"); + assert.strictEqual(node.state, mistreevous.State.RUNNING); + }); + }); + }); +}); diff --git a/test/nodes/decorator/Flip.test.js b/test/nodes/decorator/Flip.test.js new file mode 100644 index 0000000..8cc05a5 --- /dev/null +++ b/test/nodes/decorator/Flip.test.js @@ -0,0 +1,155 @@ +const mistreevous = require("../../../dist/index"); +const chai = require("chai"); + +var assert = chai.assert; + +const findNode = (tree, type, caption) => + tree.getFlattenedNodeDetails().find((node) => node.type === type && node.caption === caption); + +describe("A Flip node", () => { + describe("on tree initialisation", () => { + describe("will error if the node does not have a single child", () => { + it("(MDSL)", () => { + const definition = "root { flip {} }"; + assert.throws( + () => new mistreevous.BehaviourTree(definition, {}), + Error, + "invalid definition: a flip node must have a single child" + ); + }); + + it("(JSON)", () => { + const definition = { + type: "root", + child: { + type: "flip" + } + }; + assert.throws( + () => new mistreevous.BehaviourTree(definition, {}), + Error, + "invalid definition: expected property 'child' to be defined for flip node at depth '1'" + ); + }); + }); + }); + + describe("when updated as part of a tree step will", () => { + describe("move to the SUCCESS state if the child node moves to the FAILED state", () => { + it("(MDSL)", () => { + const definition = "root { flip { condition [someCondition] } }"; + const agent = { someCondition: () => false }; + const tree = new mistreevous.BehaviourTree(definition, agent); + + let node = findNode(tree, "flip", "FLIP"); + assert.strictEqual(node.state, mistreevous.State.READY); + + tree.step(); + + node = findNode(tree, "flip", "FLIP"); + assert.strictEqual(node.state, mistreevous.State.SUCCEEDED); + }); + + it("(JSON)", () => { + const definition = { + type: "root", + child: { + type: "flip", + child: { + type: "condition", + call: "someCondition" + } + } + }; + const agent = { someCondition: () => false }; + const tree = new mistreevous.BehaviourTree(definition, agent); + + let node = findNode(tree, "flip", "FLIP"); + assert.strictEqual(node.state, mistreevous.State.READY); + + tree.step(); + + node = findNode(tree, "flip", "FLIP"); + assert.strictEqual(node.state, mistreevous.State.SUCCEEDED); + }); + }); + + describe("move to the FAILED state if the child node moves to the SUCCESS state", () => { + it("(MDSL)", () => { + const definition = "root { flip { condition [someCondition] } }"; + const agent = { someCondition: () => true }; + const tree = new mistreevous.BehaviourTree(definition, agent); + + let node = findNode(tree, "flip", "FLIP"); + assert.strictEqual(node.state, mistreevous.State.READY); + + tree.step(); + + node = findNode(tree, "flip", "FLIP"); + assert.strictEqual(node.state, mistreevous.State.FAILED); + }); + + it("(JSON)", () => { + const definition = { + type: "root", + child: { + type: "flip", + child: { + type: "condition", + call: "someCondition" + } + } + }; + const agent = { someCondition: () => true }; + const tree = new mistreevous.BehaviourTree(definition, agent); + + let node = findNode(tree, "flip", "FLIP"); + assert.strictEqual(node.state, mistreevous.State.READY); + + tree.step(); + + node = findNode(tree, "flip", "FLIP"); + assert.strictEqual(node.state, mistreevous.State.FAILED); + }); + }); + + describe("move to the RUNNING state if the child node does not move to the SUCCESS or FAILED state", () => { + it("(MDSL)", () => { + const definition = "root { flip { action [someAction] } }"; + const agent = { someAction: () => {} }; + const tree = new mistreevous.BehaviourTree(definition, agent); + + let node = findNode(tree, "flip", "FLIP"); + assert.strictEqual(node.state, mistreevous.State.READY); + + tree.step(); + + node = findNode(tree, "flip", "FLIP"); + assert.strictEqual(node.state, mistreevous.State.RUNNING); + }); + + it("(JSON)", () => { + const definition = { + type: "root", + child: { + type: "flip", + child: { + type: "action", + call: "someAction" + } + } + }; + const agent = { someAction: () => {} }; + const tree = new mistreevous.BehaviourTree(definition, agent); + + let node = findNode(tree, "flip", "FLIP"); + assert.strictEqual(node.state, mistreevous.State.READY); + + tree.step(); + + node = findNode(tree, "flip", "FLIP"); + assert.strictEqual(node.state, mistreevous.State.RUNNING); + }); + }); + }); +}); diff --git a/test/nodes/decorator/repeat.test.js b/test/nodes/decorator/Repeat.test.js similarity index 100% rename from test/nodes/decorator/repeat.test.js rename to test/nodes/decorator/Repeat.test.js diff --git a/test/nodes/decorator/retry.test.js b/test/nodes/decorator/Retry.test.js similarity index 100% rename from test/nodes/decorator/retry.test.js rename to test/nodes/decorator/Retry.test.js diff --git a/test/nodes/decorator/Succeed.test.js b/test/nodes/decorator/Succeed.test.js new file mode 100644 index 0000000..1296588 --- /dev/null +++ b/test/nodes/decorator/Succeed.test.js @@ -0,0 +1,157 @@ +const mistreevous = require("../../../dist/index"); +const chai = require("chai"); + +var assert = chai.assert; + +const findNode = (tree, type, caption) => + tree.getFlattenedNodeDetails().find((node) => node.type === type && node.caption === caption); + +describe("A Succeed node", () => { + describe("on tree initialisation", () => { + describe("will error if the node does not have a single child", () => { + it("(MDSL)", () => { + const definition = "root { succeed {} }"; + assert.throws( + () => new mistreevous.BehaviourTree(definition, {}), + Error, + "invalid definition: a succeed node must have a single child" + ); + }); + + it("(JSON)", () => { + const definition = { + type: "root", + child: { + type: "succeed" + } + }; + assert.throws( + () => new mistreevous.BehaviourTree(definition, {}), + Error, + "invalid definition: expected property 'child' to be defined for succeed node at depth '1'" + ); + }); + }); + }); + + describe("when updated as part of a tree step will", () => { + describe("move to the SUCCEEDED state if the child node moves to the", () => { + describe("FAILED state", () => { + it("(MDSL)", () => { + const definition = "root { succeed { condition [someCondition] } }"; + const agent = { someCondition: () => false }; + const tree = new mistreevous.BehaviourTree(definition, agent); + + let node = findNode(tree, "succeed", "SUCCEED"); + assert.strictEqual(node.state, mistreevous.State.READY); + + tree.step(); + + node = findNode(tree, "succeed", "SUCCEED"); + assert.strictEqual(node.state, mistreevous.State.SUCCEEDED); + }); + + it("(JSON)", () => { + const definition = { + type: "root", + child: { + type: "succeed", + child: { + type: "condition", + call: "someCondition" + } + } + }; + const agent = { someCondition: () => false }; + const tree = new mistreevous.BehaviourTree(definition, agent); + + let node = findNode(tree, "succeed", "SUCCEED"); + assert.strictEqual(node.state, mistreevous.State.READY); + + tree.step(); + + node = findNode(tree, "succeed", "SUCCEED"); + assert.strictEqual(node.state, mistreevous.State.SUCCEEDED); + }); + }); + + describe("SUCCESS state", () => { + it("(MDSL)", () => { + const definition = "root { succeed { condition [someCondition] } }"; + const agent = { someCondition: () => true }; + const tree = new mistreevous.BehaviourTree(definition, agent); + + let node = findNode(tree, "succeed", "SUCCEED"); + assert.strictEqual(node.state, mistreevous.State.READY); + + tree.step(); + + node = findNode(tree, "succeed", "SUCCEED"); + assert.strictEqual(node.state, mistreevous.State.SUCCEEDED); + }); + + it("(JSON)", () => { + const definition = { + type: "root", + child: { + type: "succeed", + child: { + type: "condition", + call: "someCondition" + } + } + }; + const agent = { someCondition: () => true }; + const tree = new mistreevous.BehaviourTree(definition, agent); + + let node = findNode(tree, "succeed", "SUCCEED"); + assert.strictEqual(node.state, mistreevous.State.READY); + + tree.step(); + + node = findNode(tree, "succeed", "SUCCEED"); + assert.strictEqual(node.state, mistreevous.State.SUCCEEDED); + }); + }); + }); + + describe("move to the RUNNING state if the child node does not move to the SUCCESS or FAILED state", () => { + it("(MDSL)", () => { + const definition = "root { succeed { action [someAction] } }"; + const agent = { someAction: () => {} }; + const tree = new mistreevous.BehaviourTree(definition, agent); + + let node = findNode(tree, "succeed", "SUCCEED"); + assert.strictEqual(node.state, mistreevous.State.READY); + + tree.step(); + + node = findNode(tree, "succeed", "SUCCEED"); + assert.strictEqual(node.state, mistreevous.State.RUNNING); + }); + + it("(JSON)", () => { + const definition = { + type: "root", + child: { + type: "succeed", + child: { + type: "action", + call: "someAction" + } + } + }; + const agent = { someAction: () => {} }; + const tree = new mistreevous.BehaviourTree(definition, agent); + + let node = findNode(tree, "succeed", "SUCCEED"); + assert.strictEqual(node.state, mistreevous.State.READY); + + tree.step(); + + node = findNode(tree, "succeed", "SUCCEED"); + assert.strictEqual(node.state, mistreevous.State.RUNNING); + }); + }); + }); +}); diff --git a/test/nodes/decorator/fail.test.js b/test/nodes/decorator/fail.test.js deleted file mode 100644 index a4fceee..0000000 --- a/test/nodes/decorator/fail.test.js +++ /dev/null @@ -1,66 +0,0 @@ -const mistreevous = require("../../../dist/index"); -const chai = require("chai"); - -var assert = chai.assert; - -const findNode = (tree, type, caption) => - tree.getFlattenedNodeDetails().find((node) => node.type === type && node.caption === caption); - -describe("A Fail node", () => { - describe("on tree initialisation", () => { - it("will error if the node does not have a single child", () => { - const definition = "root { fail {} }"; - assert.throws( - () => new mistreevous.BehaviourTree(definition, {}), - Error, - "invalid definition: a fail node must have a single child" - ); - }); - }); - - describe("when updated as part of a tree step will", () => { - describe("move to the FAILED state if the child node moves to the", () => { - it("FAILED state", () => { - const definition = "root { fail { condition [someCondition] } }"; - const agent = { someCondition: () => false }; - const tree = new mistreevous.BehaviourTree(definition, agent); - - let node = findNode(tree, "fail", "FAIL"); - assert.strictEqual(node.state, mistreevous.State.READY); - - tree.step(); - - node = findNode(tree, "fail", "FAIL"); - assert.strictEqual(node.state, mistreevous.State.FAILED); - }); - - it("SUCCESS state", () => { - const definition = "root { fail { condition [someCondition] } }"; - const agent = { someCondition: () => true }; - const tree = new mistreevous.BehaviourTree(definition, agent); - - let node = findNode(tree, "fail", "FAIL"); - assert.strictEqual(node.state, mistreevous.State.READY); - - tree.step(); - - node = findNode(tree, "fail", "FAIL"); - assert.strictEqual(node.state, mistreevous.State.FAILED); - }); - }); - - it("move to the RUNNING state if the child node does not move to the SUCCESS or FAILED state", () => { - const definition = "root { fail { action [someAction] } }"; - const agent = { someAction: () => {} }; - const tree = new mistreevous.BehaviourTree(definition, agent); - - let node = findNode(tree, "fail", "FAIL"); - assert.strictEqual(node.state, mistreevous.State.READY); - - tree.step(); - - node = findNode(tree, "fail", "FAIL"); - assert.strictEqual(node.state, mistreevous.State.RUNNING); - }); - }); -}); diff --git a/test/nodes/decorator/flip.test.js b/test/nodes/decorator/flip.test.js deleted file mode 100644 index 003c091..0000000 --- a/test/nodes/decorator/flip.test.js +++ /dev/null @@ -1,64 +0,0 @@ -const mistreevous = require("../../../dist/index"); -const chai = require("chai"); - -var assert = chai.assert; - -const findNode = (tree, type, caption) => - tree.getFlattenedNodeDetails().find((node) => node.type === type && node.caption === caption); - -describe("A Flip node", () => { - describe("on tree initialisation", () => { - it("will error if the node does not have a single child", () => { - const definition = "root { flip {} }"; - assert.throws( - () => new mistreevous.BehaviourTree(definition, {}), - Error, - "invalid definition: a flip node must have a single child" - ); - }); - }); - - describe("when updated as part of a tree step will", () => { - it("move to the SUCCESS state if the child node moves to the FAILED state", () => { - const definition = "root { flip { condition [someCondition] } }"; - const agent = { someCondition: () => false }; - const tree = new mistreevous.BehaviourTree(definition, agent); - - let node = findNode(tree, "flip", "FLIP"); - assert.strictEqual(node.state, mistreevous.State.READY); - - tree.step(); - - node = findNode(tree, "flip", "FLIP"); - assert.strictEqual(node.state, mistreevous.State.SUCCEEDED); - }); - - it("move to the FAILED state if the child node moves to the SUCCESS state", () => { - const definition = "root { flip { condition [someCondition] } }"; - const agent = { someCondition: () => true }; - const tree = new mistreevous.BehaviourTree(definition, agent); - - let node = findNode(tree, "flip", "FLIP"); - assert.strictEqual(node.state, mistreevous.State.READY); - - tree.step(); - - node = findNode(tree, "flip", "FLIP"); - assert.strictEqual(node.state, mistreevous.State.FAILED); - }); - - it("move to the RUNNING state if the child node does not move to the SUCCESS or FAILED state", () => { - const definition = "root { flip { action [someAction] } }"; - const agent = { someAction: () => {} }; - const tree = new mistreevous.BehaviourTree(definition, agent); - - let node = findNode(tree, "flip", "FLIP"); - assert.strictEqual(node.state, mistreevous.State.READY); - - tree.step(); - - node = findNode(tree, "flip", "FLIP"); - assert.strictEqual(node.state, mistreevous.State.RUNNING); - }); - }); -}); diff --git a/test/nodes/decorator/succeed.test.js b/test/nodes/decorator/succeed.test.js deleted file mode 100644 index bf456cf..0000000 --- a/test/nodes/decorator/succeed.test.js +++ /dev/null @@ -1,66 +0,0 @@ -const mistreevous = require("../../../dist/index"); -const chai = require("chai"); - -var assert = chai.assert; - -const findNode = (tree, type, caption) => - tree.getFlattenedNodeDetails().find((node) => node.type === type && node.caption === caption); - -describe("A Succeed node", () => { - describe("on tree initialisation", () => { - it("will error if the node does not have a single child", () => { - const definition = "root { succeed {} }"; - assert.throws( - () => new mistreevous.BehaviourTree(definition, {}), - Error, - "invalid definition: a succeed node must have a single child" - ); - }); - }); - - describe("when updated as part of a tree step will", () => { - describe("move to the SUCCEEDED state if the child node moves to the", () => { - it("FAILED state", () => { - const definition = "root { succeed { condition [someCondition] } }"; - const agent = { someCondition: () => false }; - const tree = new mistreevous.BehaviourTree(definition, agent); - - let node = findNode(tree, "succeed", "SUCCEED"); - assert.strictEqual(node.state, mistreevous.State.READY); - - tree.step(); - - node = findNode(tree, "succeed", "SUCCEED"); - assert.strictEqual(node.state, mistreevous.State.SUCCEEDED); - }); - - it("SUCCESS state", () => { - const definition = "root { succeed { condition [someCondition] } }"; - const agent = { someCondition: () => true }; - const tree = new mistreevous.BehaviourTree(definition, agent); - - let node = findNode(tree, "succeed", "SUCCEED"); - assert.strictEqual(node.state, mistreevous.State.READY); - - tree.step(); - - node = findNode(tree, "succeed", "SUCCEED"); - assert.strictEqual(node.state, mistreevous.State.SUCCEEDED); - }); - }); - - it("move to the RUNNING state if the child node does not move to the SUCCESS or FAILED state", () => { - const definition = "root { succeed { action [someAction] } }"; - const agent = { someAction: () => {} }; - const tree = new mistreevous.BehaviourTree(definition, agent); - - let node = findNode(tree, "succeed", "SUCCEED"); - assert.strictEqual(node.state, mistreevous.State.READY); - - tree.step(); - - node = findNode(tree, "succeed", "SUCCEED"); - assert.strictEqual(node.state, mistreevous.State.RUNNING); - }); - }); -}); diff --git a/test/nodes/leaf/action.test.js b/test/nodes/leaf/Action.test.js similarity index 100% rename from test/nodes/leaf/action.test.js rename to test/nodes/leaf/Action.test.js diff --git a/test/nodes/leaf/condition.test.js b/test/nodes/leaf/Condition.test.js similarity index 100% rename from test/nodes/leaf/condition.test.js rename to test/nodes/leaf/Condition.test.js diff --git a/test/nodes/leaf/wait.test.js b/test/nodes/leaf/Wait.test.js similarity index 100% rename from test/nodes/leaf/wait.test.js rename to test/nodes/leaf/Wait.test.js From 451515ca81e4765440bcfe898709ccdf2e2754e8 Mon Sep 17 00:00:00 2001 From: Nikolas Howard Date: Fri, 16 Feb 2024 17:35:27 +0000 Subject: [PATCH 25/48] working on specs --- package.json | 4 +- test/nodes/composite/Lotto.test.js | 2 +- test/nodes/composite/Selector.test.js | 79 ++++++++++++++++++++++++++- test/nodes/decorator/Fail.test.js | 2 +- test/nodes/decorator/Succeed.test.js | 2 +- 5 files changed, 83 insertions(+), 6 deletions(-) diff --git a/package.json b/package.json index 4f55f1e..585bb12 100644 --- a/package.json +++ b/package.json @@ -22,8 +22,8 @@ "watch": "npm run build:node -- --watch", "test": "npm-run-all build test:unit-test", "build:format": "prettier --write \"src/**/*.ts\" \"test/**/*.js\"", - "build:node": "esbuild ./src/index.js --bundle --sourcemap --outdir=dist --platform=node", - "build:web": "esbuild ./src/index.js --bundle --sourcemap --platform=browser --global-name=mistreevous --outfile=dist/bundle.js", + "build:node": "esbuild ./src/index.ts --bundle --sourcemap --outdir=dist --platform=node", + "build:web": "esbuild ./src/index.ts --bundle --sourcemap --platform=browser --global-name=mistreevous --outfile=dist/bundle.js", "build:typecheck": "tsc --emitDeclarationOnly", "test:unit-test": "mocha \"test/**/*.js\"" }, diff --git a/test/nodes/composite/Lotto.test.js b/test/nodes/composite/Lotto.test.js index 7376e31..83af99b 100644 --- a/test/nodes/composite/Lotto.test.js +++ b/test/nodes/composite/Lotto.test.js @@ -418,7 +418,7 @@ describe("A Lotto node", () => { }); }); - describe("move to the RUNNING state if the selected child node does not move to the SUCCESS or FAILED state", () => { + describe("move to the RUNNING state if the selected child node is in the RUNNING state", () => { it("(MDSL)", () => { const definition = "root { lotto { action [someAction] } }"; const agent = { someAction: () => {} }; diff --git a/test/nodes/composite/Selector.test.js b/test/nodes/composite/Selector.test.js index e1cf352..99cf463 100644 --- a/test/nodes/composite/Selector.test.js +++ b/test/nodes/composite/Selector.test.js @@ -3,6 +3,9 @@ const chai = require("chai"); var assert = chai.assert; +const findNode = (tree, type, caption) => + tree.getFlattenedNodeDetails().find((node) => node.type === type && node.caption === caption); + describe("A Selector node", () => { describe("on tree initialisation", () => { describe("will error if the node does not have at least one child", () => { @@ -32,5 +35,79 @@ describe("A Selector node", () => { }); }); - describe("when updated as part of a tree step will", () => {}); + describe("when updated as part of a tree step will", () => { + describe("move to the FAILED state if all child nodes move to the FAILED state", () => {}); + + describe("move to the SUCCEEDED state if any child node moves to the SUCCEEDED state", () => {}); + + describe("move to the RUNNING state if any child node is in the RUNNING state", () => { + it("(MDSL)", () => { + const definition = + "root { selector { action [actionFail] action [actionRunning] action [actionSucceed] } }"; + const agent = { + actionSucceed: () => mistreevous.State.SUCCEEDED, + actionRunning: () => {}, + actionFail: () => mistreevous.State.FAILED + }; + const tree = new mistreevous.BehaviourTree(definition, agent); + + assert.strictEqual(findNode(tree, "root", "ROOT").state, mistreevous.State.READY); + assert.strictEqual(findNode(tree, "selector", "SELECTOR").state, mistreevous.State.READY); + assert.strictEqual(findNode(tree, "action", "actionFail").state, mistreevous.State.READY); + assert.strictEqual(findNode(tree, "action", "actionRunning").state, mistreevous.State.READY); + assert.strictEqual(findNode(tree, "action", "actionSucceed").state, mistreevous.State.READY); + + tree.step(); + + assert.strictEqual(findNode(tree, "root", "ROOT").state, mistreevous.State.RUNNING); + assert.strictEqual(findNode(tree, "selector", "SELECTOR").state, mistreevous.State.RUNNING); + assert.strictEqual(findNode(tree, "action", "actionFail").state, mistreevous.State.FAILED); + assert.strictEqual(findNode(tree, "action", "actionRunning").state, mistreevous.State.RUNNING); + assert.strictEqual(findNode(tree, "action", "actionSucceed").state, mistreevous.State.READY); + }); + + it("(JSON)", () => { + const definition = { + type: "root", + child: { + type: "selector", + children: [ + { + type: "action", + call: "actionFail" + }, + { + type: "action", + call: "actionRunning" + }, + { + type: "action", + call: "actionSucceed" + } + ] + } + }; + const agent = { + actionSucceed: () => mistreevous.State.SUCCEEDED, + actionRunning: () => {}, + actionFail: () => mistreevous.State.FAILED + }; + const tree = new mistreevous.BehaviourTree(definition, agent); + + assert.strictEqual(findNode(tree, "root", "ROOT").state, mistreevous.State.READY); + assert.strictEqual(findNode(tree, "selector", "SELECTOR").state, mistreevous.State.READY); + assert.strictEqual(findNode(tree, "action", "actionFail").state, mistreevous.State.READY); + assert.strictEqual(findNode(tree, "action", "actionRunning").state, mistreevous.State.READY); + assert.strictEqual(findNode(tree, "action", "actionSucceed").state, mistreevous.State.READY); + + tree.step(); + + assert.strictEqual(findNode(tree, "root", "ROOT").state, mistreevous.State.RUNNING); + assert.strictEqual(findNode(tree, "selector", "SELECTOR").state, mistreevous.State.RUNNING); + assert.strictEqual(findNode(tree, "action", "actionFail").state, mistreevous.State.FAILED); + assert.strictEqual(findNode(tree, "action", "actionRunning").state, mistreevous.State.RUNNING); + assert.strictEqual(findNode(tree, "action", "actionSucceed").state, mistreevous.State.READY); + }); + }); + }); }); diff --git a/test/nodes/decorator/Fail.test.js b/test/nodes/decorator/Fail.test.js index eaac606..1f0bc00 100644 --- a/test/nodes/decorator/Fail.test.js +++ b/test/nodes/decorator/Fail.test.js @@ -115,7 +115,7 @@ describe("A Fail node", () => { }); }); - describe("move to the RUNNING state if the child node does not move to the SUCCESS or FAILED state", () => { + describe("move to the RUNNING state if the child node moves to the RUNNING state", () => { it("(MDSL)", () => { const definition = "root { fail { action [someAction] } }"; const agent = { someAction: () => {} }; diff --git a/test/nodes/decorator/Succeed.test.js b/test/nodes/decorator/Succeed.test.js index 1296588..1205a85 100644 --- a/test/nodes/decorator/Succeed.test.js +++ b/test/nodes/decorator/Succeed.test.js @@ -115,7 +115,7 @@ describe("A Succeed node", () => { }); }); - describe("move to the RUNNING state if the child node does not move to the SUCCESS or FAILED state", () => { + describe("move to the RUNNING state if the child node moves to the RUNNING state", () => { it("(MDSL)", () => { const definition = "root { succeed { action [someAction] } }"; const agent = { someAction: () => {} }; From b31c9dbb398aa98810b46817b3d9b92a132403fc Mon Sep 17 00:00:00 2001 From: Nikolas Howard Date: Sat, 17 Feb 2024 19:03:33 +0000 Subject: [PATCH 26/48] tree definition validation now returns json definition as part of successful validation response so that we don't have to parse MDSL twice --- dist/BehaviourTree.d.ts | 6 ----- dist/BehaviourTreeDefinitionValidator.d.ts | 10 ++++---- dist/bundle.js | 23 +++++++++++------- dist/bundle.js.map | 4 ++-- dist/index.js | 23 +++++++++++------- dist/index.js.map | 4 ++-- src/BehaviourTree.ts | 27 ++++++++-------------- src/BehaviourTreeDefinitionValidator.ts | 16 ++++++++++--- 8 files changed, 61 insertions(+), 52 deletions(-) diff --git a/dist/BehaviourTree.d.ts b/dist/BehaviourTree.d.ts index e31453d..8289ddf 100644 --- a/dist/BehaviourTree.d.ts +++ b/dist/BehaviourTree.d.ts @@ -75,10 +75,4 @@ export declare class BehaviourTree { * 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 populated at a root. - * @param {string | RootNodeDefinition | RootNodeDefinition[]} definition The behaviour tree definition. - * @returns The root behaviour tree node. - */ - private _createRootNode; } diff --git a/dist/BehaviourTreeDefinitionValidator.d.ts b/dist/BehaviourTreeDefinitionValidator.d.ts index 531d5f6..e8f7dba 100644 --- a/dist/BehaviourTreeDefinitionValidator.d.ts +++ b/dist/BehaviourTreeDefinitionValidator.d.ts @@ -11,6 +11,10 @@ export type DefinitionValidationResult = { * A string containing the error message if validation did not succeed. */ errorMessage?: string; + /** + * The definition as json if the validation was successful, or undefined if validation did not succeed. + */ + json?: RootNodeDefinition[]; }; /** * Validates the specified behaviour tree definition in the form of JSON or MDSL, not taking any globally registered subtrees into consideration. @@ -18,12 +22,6 @@ export type DefinitionValidationResult = { * @returns An object representing the result of validating the given tree definition. */ export declare function validateDefinition(definition: any): DefinitionValidationResult; -/** - * Validates the specified behaviour tree definition in the form of MDSL. - * @param definition The behaviour tree definition in the form of MDSL. - * @returns An object representing the result of validating the given tree definition. - */ -export declare function validateMDSLDefinition(definition: string): DefinitionValidationResult; /** * Validates the specified behaviour tree definition in the form of JSON. * @param definition The behaviour tree definition in the form of JSON. diff --git a/dist/bundle.js b/dist/bundle.js index f956834..5faad33 100644 --- a/dist/bundle.js +++ b/dist/bundle.js @@ -818,7 +818,10 @@ var mistreevous = (() => { } catch (exception) { return createValidationFailureResult(exception.message); } - return { succeeded: true }; + return { + succeeded: true, + json: rootNodeDefinitions + }; } function validateJSONDefinition(definition) { const rootNodeDefinitions = Array.isArray(definition) ? definition : [definition]; @@ -851,7 +854,10 @@ var mistreevous = (() => { } catch (exception) { return createValidationFailureResult(exception.message); } - return { succeeded: true }; + return { + succeeded: true, + json: rootNodeDefinitions + }; } function validateBranchSubtreeLinks(rootNodeDefinitions, includesGlobalSubtrees) { const rootNodeMappings = rootNodeDefinitions.map( @@ -2167,12 +2173,17 @@ var mistreevous = (() => { if (typeof agent !== "object" || agent === null) { throw new Error("the agent must be an object and not null"); } - const { succeeded, errorMessage } = validateDefinition(definition); + const { succeeded, errorMessage, json } = validateDefinition(definition); if (!succeeded) { throw new Error(`invalid definition: ${errorMessage}`); } + if (!json) { + throw new Error( + "expected json definition to be returned as part of successful definition validation response" + ); + } try { - this.rootNode = this._createRootNode(definition); + this.rootNode = buildRootNode(json); } catch (exception) { throw new Error(`error building tree: ${exception.message}`); } @@ -2263,10 +2274,6 @@ var mistreevous = (() => { static unregisterAll() { Lookup.empty(); } - _createRootNode(definition) { - const resolvedDefinition = typeof definition === "string" ? convertMDSLToJSON(definition) : definition; - return buildRootNode(Array.isArray(resolvedDefinition) ? resolvedDefinition : [resolvedDefinition]); - } }; return __toCommonJS(src_exports); })(); diff --git a/dist/bundle.js.map b/dist/bundle.js.map index 62f213c..5ea67a0 100644 --- a/dist/bundle.js.map +++ b/dist/bundle.js.map @@ -1,7 +1,7 @@ { "version": 3, "sources": ["../node_modules/lotto-draw/dist/Participant.js", "../node_modules/lotto-draw/dist/Utilities.js", "../node_modules/lotto-draw/dist/Lotto.js", "../node_modules/lotto-draw/dist/createLotto.js", "../node_modules/lotto-draw/dist/index.js", "../src/index.ts", "../src/State.ts", "../src/BehaviourTreeDefinitionUtilities.ts", "../src/mdsl/MDSLUtilities.ts", "../src/mdsl/MDSLNodeArgumentParser.ts", "../src/mdsl/MDSLNodeAttributeParser.ts", "../src/mdsl/MDSLDefinitionParser.ts", "../src/BehaviourTreeDefinitionValidator.ts", "../src/Lookup.ts", "../src/attributes/guards/GuardUnsatisifedException.ts", "../src/attributes/guards/GuardPath.ts", "../src/nodes/Node.ts", "../src/nodes/composite/Composite.ts", "../src/nodes/composite/Parallel.ts", "../src/nodes/composite/Selector.ts", "../src/nodes/composite/Sequence.ts", "../src/nodes/composite/Lotto.ts", "../src/nodes/decorator/Decorator.ts", "../src/nodes/decorator/Fail.ts", "../src/nodes/decorator/Flip.ts", "../src/nodes/decorator/Repeat.ts", "../src/nodes/decorator/Retry.ts", "../src/nodes/decorator/Root.ts", "../src/nodes/decorator/Succeed.ts", "../src/nodes/leaf/Leaf.ts", "../src/nodes/leaf/Action.ts", "../src/nodes/leaf/Condition.ts", "../src/nodes/leaf/Wait.ts", "../src/attributes/Attribute.ts", "../src/attributes/guards/Guard.ts", "../src/attributes/guards/While.ts", "../src/attributes/guards/Until.ts", "../src/attributes/callbacks/Callback.ts", "../src/attributes/callbacks/Entry.ts", "../src/attributes/callbacks/Step.ts", "../src/attributes/callbacks/Exit.ts", "../src/BehaviourTreeBuilder.ts", "../src/BehaviourTree.ts"], - "sourcesContent": ["\"use strict\";\r\nObject.defineProperty(exports, \"__esModule\", { value: true });\r\nexports.Participant = void 0;\r\n/**\r\n * A participant that holds a number of tickets.\r\n */\r\nvar Participant = /** @class */ (function () {\r\n /**\r\n * Creates an instance of the Participant class.\r\n * @param participant The actual participant.\r\n * @param tickets The number of tickets held by the participant.\r\n */\r\n function Participant(participant, tickets) {\r\n if (tickets === void 0) { tickets = 1; }\r\n this._participant = participant;\r\n this._tickets = tickets;\r\n }\r\n Object.defineProperty(Participant.prototype, \"participant\", {\r\n /** Gets the actual participant. */\r\n get: function () {\r\n return this._participant;\r\n },\r\n enumerable: false,\r\n configurable: true\r\n });\r\n Object.defineProperty(Participant.prototype, \"tickets\", {\r\n /** Gets or sets the number of tickets held by the participant. */\r\n get: function () {\r\n return this._tickets;\r\n },\r\n set: function (value) {\r\n this._tickets = value;\r\n },\r\n enumerable: false,\r\n configurable: true\r\n });\r\n return Participant;\r\n}());\r\nexports.Participant = Participant;\r\n", "\"use strict\";\r\nObject.defineProperty(exports, \"__esModule\", { value: true });\r\nexports.isNaturalNumber = exports.isNullOrUndefined = void 0;\r\n/**\r\n * Gets whether the value provided is null or undefined.\r\n * @param value The value to check.\r\n * @returns Whether the value provided is null or undefined.\r\n */\r\nfunction isNullOrUndefined(value) {\r\n return value === null || value === undefined;\r\n}\r\nexports.isNullOrUndefined = isNullOrUndefined;\r\n/**\r\n * Gets whether the value provided is a natural number.\r\n * @param value The value to check.\r\n * @returns Whether the value provided is a natural number.\r\n */\r\nfunction isNaturalNumber(value) {\r\n return typeof value === \"number\" && value >= 1 && Math.floor(value) === value;\r\n}\r\nexports.isNaturalNumber = isNaturalNumber;\r\n", "\"use strict\";\r\nObject.defineProperty(exports, \"__esModule\", { value: true });\r\nexports.Lotto = void 0;\r\nvar Participant_1 = require(\"./Participant\");\r\nvar Utilities_1 = require(\"./Utilities\");\r\n/**\r\n * Represents a lotto consisting of a number of pickable ticket-holding participants.\r\n */\r\nvar Lotto = /** @class */ (function () {\r\n /**\r\n * Creates a new instance of Lotto.\r\n * @param customRandom The custom RNG to use in place of Math.random().\r\n */\r\n function Lotto(customRandom) {\r\n /** The array of participants that are holding tickets in the lotto. */\r\n this._participants = [];\r\n this._customRandom = customRandom;\r\n }\r\n /**\r\n * Adds a participant with the specified number of tickets, or adds to the participant ticket count if the participant already holds tickets.\r\n * @param participant The participant to add or to increase the ticket count for if they already hold tickets.\r\n * @param tickets The number of tickets, defaults to 1.\r\n * @returns The Lotto instance.\r\n */\r\n Lotto.prototype.add = function (participant, tickets) {\r\n if (tickets === void 0) { tickets = 1; }\r\n // Check that we have a valid ticket count.\r\n if (!(0, Utilities_1.isNaturalNumber)(tickets)) {\r\n throw new Error(\"tickets value must be a natural number\");\r\n }\r\n // Check whether this participant has already been added.\r\n var existingParticipant = this._participants.find(function (part) { return part.participant === participant; });\r\n if (existingParticipant) {\r\n // The participant has already been added to the lotto so just add to their ticket count.\r\n existingParticipant.tickets += tickets;\r\n }\r\n else {\r\n // The participant is not part of the lotto so we should add them.\r\n this._participants.push(new Participant_1.Participant(participant, tickets));\r\n }\r\n return this;\r\n };\r\n /**\r\n * Removes the specified number of tickets for the given participant from the draw, or all tickets if a ticket number is not defined.\r\n * @param participant The participant to remove tickets for.\r\n * @param tickets The number of tickets to remove, or undefined if all tickets are to be removed.\r\n * @returns The Lotto instance.\r\n */\r\n Lotto.prototype.remove = function (participant, tickets) {\r\n // Attempt to get the existing participant.\r\n var existingParticipant = this._participants.find(function (part) { return part.participant === participant; });\r\n // There is nothing to do if the specified participant isn't even part of the lotto.\r\n if (!existingParticipant) {\r\n return this;\r\n }\r\n // Check whether a tickets value was given.\r\n if (tickets !== undefined) {\r\n // Check that we have a valid ticket count.\r\n if (!(0, Utilities_1.isNaturalNumber)(tickets)) {\r\n throw new Error(\"tickets value must be a natural number\");\r\n }\r\n existingParticipant.tickets -= tickets;\r\n // If the participant no longer holds any tickets then they should be removed.\r\n if (existingParticipant.tickets < 1) {\r\n this._participants = this._participants.filter(function (part) { return part !== existingParticipant; });\r\n }\r\n }\r\n else {\r\n // We are removing all tickets for the participant so just remove them from the lotto.\r\n this._participants = this._participants.filter(function (part) { return part !== existingParticipant; });\r\n }\r\n return this;\r\n };\r\n /**\r\n * Draw a winning ticket and return the participant that holds the ticket.\r\n * @param options The draw options.\r\n * @returns The participant that holds the winning ticket.\r\n */\r\n Lotto.prototype.draw = function (options) {\r\n if (options === void 0) { options = {}; }\r\n // If we have no participants then just return null.\r\n if (this._participants.length === 0) {\r\n return null;\r\n }\r\n var redrawable = (0, Utilities_1.isNullOrUndefined)(options.redrawable) ? true : options.redrawable;\r\n var pickable = [];\r\n this._participants.forEach(function (_a) {\r\n var participant = _a.participant, tickets = _a.tickets;\r\n for (var ticketCount = 0; ticketCount < tickets; ticketCount++) {\r\n pickable.push(participant);\r\n }\r\n });\r\n var random;\r\n // We need a random floating-point number between 0 (inclusive) and 1 to scale up to pick our winner.\r\n // If a custom random function exists then we should use that or fall back to Math.random().\r\n if (this._customRandom) {\r\n // Call our custom random function to get a random floating-point number.\r\n random = this._customRandom();\r\n // Verify that the result of calling our custom random function is a number between 0 (inclusive) and 1.\r\n if (typeof random !== \"number\" || random < 0 || random >= 1) {\r\n throw new Error(\"the 'random' function provided did not return a number between 0 (inclusive) and 1\");\r\n }\r\n }\r\n else {\r\n // No custom random function was defined so just use good ol' Math.random().\r\n random = Math.random();\r\n }\r\n // Pick a winning participant.\r\n var winner = pickable[Math.floor(random * pickable.length)];\r\n // If the ticket isn't redrawable then we should remove a ticket from the winning participants ticket count.\r\n if (!redrawable) {\r\n this.remove(winner, 1);\r\n }\r\n // Return the winning participant.\r\n return winner;\r\n };\r\n /**\r\n * Draws multiple winning tickets and return an array of the participants that hold the winning tickets.\r\n * @param tickets The number of winning tickets to draw.\r\n * @param options The draw multiple options.\r\n * @returns An array of the participants that hold the winning tickets.\r\n */\r\n Lotto.prototype.drawMultiple = function (tickets, options) {\r\n if (options === void 0) { options = {}; }\r\n var uniqueResults = (0, Utilities_1.isNullOrUndefined)(options.unique) ? false : options.unique;\r\n // Handle cases where the user has asked for zero tickets (no idea why they would do this be we should trust them).\r\n if (tickets === 0) {\r\n return [];\r\n }\r\n // Now that we know out tickets value is not zero we should check that it is a valid natural number.\r\n if (!(0, Utilities_1.isNaturalNumber)(tickets)) {\r\n throw new Error(\"tickets value must be a natural number\");\r\n }\r\n var result = [];\r\n // Keep drawing tickets until we either reach the number of required tickets or we simply run out of tickets to draw.\r\n // We can run out of tickets to draw if 'options.redrawable' is explicity 'false' or we just had no participants when 'drawMultiple' was called.\r\n while (result.length < tickets && this._participants.length > 0) {\r\n result.push(this.draw(options));\r\n }\r\n // If the 'unique' draw option is set then we need to remove duplicates from the result list.\r\n if (uniqueResults) {\r\n // Create an array to store our unique results.\r\n var unique = [];\r\n // Iterate over all of our participants (with potential duplicates) and populate our array of unique values.\r\n for (var _i = 0, result_1 = result; _i < result_1.length; _i++) {\r\n var participant = result_1[_i];\r\n if (unique.indexOf(participant) === -1) {\r\n unique.push(participant);\r\n }\r\n }\r\n result = unique;\r\n }\r\n return result;\r\n };\r\n return Lotto;\r\n}());\r\nexports.Lotto = Lotto;\r\n", "\"use strict\";\r\nObject.defineProperty(exports, \"__esModule\", { value: true });\r\nexports.createLotto = void 0;\r\nvar Lotto_1 = require(\"./Lotto\");\r\n/**\r\n * A function that creates and returns a Lotto instance.\r\n * @param participantsOrOptions An array of initial participants or options relating to the creation of a Lotto instance.\r\n * @returns A new Lotto instance.\r\n */\r\nfunction createLotto(participantsOrOptions) {\r\n // If no initial participants or lotto options were provided as an argument then we can just return a new lotto instance now.\r\n if (!participantsOrOptions) {\r\n return new Lotto_1.Lotto();\r\n }\r\n // Check whether we were provided with an array of initial participants or a lotto options object.\r\n if (Array.isArray(participantsOrOptions)) {\r\n // We are dealing with a pre-defined array of participants.\r\n var participants = participantsOrOptions;\r\n var lotto_1 = new Lotto_1.Lotto();\r\n // If the lotto participants have been defined upfront then we will need to add them all to our lotto instance now.\r\n participants.forEach(function (_a) {\r\n var participant = _a[0], tokens = _a[1];\r\n return lotto_1.add(participant, tokens);\r\n });\r\n // Return the Lotto instance.\r\n return lotto_1;\r\n }\r\n else {\r\n // We are dealing with some lotto options.\r\n var random = participantsOrOptions.random, participants = participantsOrOptions.participants;\r\n // Create a Lotto instance passing the custom RNG function to use in place of Math.random() (which could be undefined).\r\n var lotto_2 = new Lotto_1.Lotto(random);\r\n // If the lotto participants have been defined upfront as part of the options then we will need to add them all to our lotto instance now.\r\n if (participants) {\r\n participants.forEach(function (_a) {\r\n var participant = _a[0], tokens = _a[1];\r\n return lotto_2.add(participant, tokens);\r\n });\r\n }\r\n // Return the Lotto instance.\r\n return lotto_2;\r\n }\r\n}\r\nexports.createLotto = createLotto;\r\n", "\"use strict\";\r\nObject.defineProperty(exports, \"__esModule\", { value: true });\r\nvar createLotto_1 = require(\"./createLotto\");\r\nexports.default = createLotto_1.createLotto;\r\n", "import State from \"./State\";\nimport { validateDefinition } from \"./BehaviourTreeDefinitionValidator\";\nimport { convertMDSLToJSON } from \"./mdsl/MDSLDefinitionParser\";\nimport { BehaviourTree, FlattenedTreeNode } from \"./BehaviourTree\";\nimport { BehaviourTreeOptions } from \"./BehaviourTreeOptions\";\n\nexport { BehaviourTree, State, convertMDSLToJSON, validateDefinition };\nexport type { FlattenedTreeNode, BehaviourTreeOptions };\n", "/**\n * Enumeration of node state types.\n */\nexport enum State {\n READY = \"mistreevous.ready\",\n RUNNING = \"mistreevous.running\",\n SUCCEEDED = \"mistreevous.succeeded\",\n FAILED = \"mistreevous.failed\"\n}\n\nexport { State as default };\n\nexport type CompleteState = State.SUCCEEDED | State.FAILED;\nexport type AnyState = State.READY | State.RUNNING | CompleteState;\n", "import {\n NodeDefinition,\n RootNodeDefinition,\n DecoratorNodeDefinition,\n CompositeNodeDefinition,\n AnyNodeDefinition,\n BranchNodeDefinition\n} from \"./BehaviourTreeDefinition\";\n\n/**\n * A type guard function that returns true if the specified node satisfies the RootNodeDefinition type.\n * @param node The node.\n * @returns A value of true if the specified node satisfies the RootNodeDefinition type.\n */\nexport function isRootNode(node: NodeDefinition): node is RootNodeDefinition {\n return node.type === \"root\";\n}\n\n/**\n * A type guard function that returns true if the specified node satisfies the BranchNodeDefinition type.\n * @param node The node.\n * @returns A value of true if the specified node satisfies the BranchNodeDefinition type.\n */\nexport function isBranchNode(node: NodeDefinition): node is BranchNodeDefinition {\n return node.type === \"branch\";\n}\n\n/**\n * A type guard function that returns true if the specified node satisfies the NodeDefinition type.\n * @param node The node.\n * @returns A value of true if the specified node satisfies the NodeDefinition type.\n */\nexport function isLeafNode(node: NodeDefinition): node is NodeDefinition {\n return [\"branch\", \"action\", \"condition\", \"wait\"].includes(node.type);\n}\n\n/**\n * A type guard function that returns true if the specified node satisfies the DecoratorNodeDefinition type.\n * @param node The node.\n * @returns A value of true if the specified node satisfies the DecoratorNodeDefinition type.\n */\nexport function isDecoratorNode(node: NodeDefinition): node is DecoratorNodeDefinition {\n return [\"root\", \"repeat\", \"retry\", \"flip\", \"succeed\", \"fail\"].includes(node.type);\n}\n\n/**\n * A type guard function that returns true if the specified node satisfies the CompositeNodeDefinition type.\n * @param node The node.\n * @returns A value of true if the specified node satisfies the CompositeNodeDefinition type.\n */\nexport function isCompositeNode(node: NodeDefinition): node is CompositeNodeDefinition {\n return [\"sequence\", \"selector\", \"lotto\", \"parallel\"].includes(node.type);\n}\n\n/**\n * Flatten a node definition into an array of all of its nested node definitions.\n * @param nodeDefinition The node definition to flatten.\n * @returns An array of all of nested node definitions.\n */\nexport function flattenDefinition(nodeDefinition: AnyNodeDefinition): AnyNodeDefinition[] {\n const nodes: AnyNodeDefinition[] = [];\n\n const processNode = (currentNodeDefinition: AnyNodeDefinition) => {\n nodes.push(currentNodeDefinition);\n\n if (isCompositeNode(currentNodeDefinition)) {\n currentNodeDefinition.children.forEach(processNode);\n } else if (isDecoratorNode(currentNodeDefinition)) {\n processNode(currentNodeDefinition.child);\n }\n };\n\n processNode(nodeDefinition);\n\n return nodes;\n}\n\n/**\n * Determines whether the passed value is an integer.\n * @param value The value to check.\n * @returns Whether the passed value is an integer.\n */\nexport function isInteger(value: unknown): boolean {\n return typeof value === \"number\" && Math.floor(value) === value;\n}\n\n/**\n * Determines whether the passed value is null or undefined.\n * @param value The value to check.\n * @returns Whether the passed value is null or undefined.\n */\nexport function isNullOrUndefined(value: unknown): boolean {\n return typeof value === \"undefined\" || value === null;\n}\n", "/**\n * A type defining an object that holds a reference to substitued string literals parsed from the definition.\n */\nexport type StringLiteralPlaceholders = { [key: string]: string };\n\n/**\n * Pop the next raw token from the specified array of tokens and throw an error if it wasn't the expected one.\n * @param tokens The array of tokens.\n * @param expected An optional string or array or items, one of which must match the next popped token.\n * @returns The popped token.\n */\nexport function popAndCheck(tokens: string[], expected?: string | string[]): string {\n // Get and remove the next token.\n const popped = tokens.shift();\n\n // We were expecting another token but there aren't any.\n if (popped === undefined) {\n throw new Error(\"unexpected end of definition\");\n }\n\n // Do we have an expected token/tokens array?\n if (expected != undefined) {\n // Get an array of expected values, if the popped token matches any then we are all good.\n const expectedValues = typeof expected === \"string\" ? [expected] : expected;\n\n // Check whether the popped token matches at least one of our expected items.\n var tokenMatchesExpectation = expectedValues.some((item) => popped.toUpperCase() === item.toUpperCase());\n\n // Throw an error if the popped token didn't match any of our expected items.\n if (!tokenMatchesExpectation) {\n const expectationString = expectedValues.map((item) => \"'\" + item + \"'\").join(\" or \");\n throw new Error(\"unexpected token found. Expected \" + expectationString + \" but got '\" + popped + \"'\");\n }\n }\n\n // Return the popped token.\n return popped;\n}\n\n/**\n * Swaps out any node/attribute argument string literals with placeholders.\n * @param definition The definition.\n * @returns An object containing a mapping of placeholders to original string values as well as the processed definition string.\n */\nexport function substituteStringLiterals(definition: string): {\n placeholders: StringLiteralPlaceholders;\n processedDefinition: string;\n} {\n // Create an object to hold the mapping of placeholders to original string values.\n const placeholders: StringLiteralPlaceholders = {};\n\n // Replace any string literals wrapped with double quotes in our definition with placeholders to be processed later.\n const processedDefinition = definition.replace(/\\\"(\\\\.|[^\"\\\\])*\\\"/g, (match) => {\n var strippedMatch = match.substring(1, match.length - 1);\n var placeholder = Object.keys(placeholders).find((key) => placeholders[key] === strippedMatch);\n\n // If we have no existing string literal match then create a new placeholder.\n if (!placeholder) {\n placeholder = `@@${Object.keys(placeholders).length}@@`;\n placeholders[placeholder] = strippedMatch;\n }\n\n return placeholder;\n });\n\n return { placeholders, processedDefinition };\n}\n\n/**\n * Parse the tree definition into an array of raw tokens.\n * @param definition The definition.\n * @returns An array of tokens parsed from the definition.\n */\nexport function parseTokensFromDefinition(definition: string): string[] {\n // Add some space around various important characters so that they can be plucked out easier as individual tokens.\n definition = definition.replace(/\\(/g, \" ( \");\n definition = definition.replace(/\\)/g, \" ) \");\n definition = definition.replace(/\\{/g, \" { \");\n definition = definition.replace(/\\}/g, \" } \");\n definition = definition.replace(/\\]/g, \" ] \");\n definition = definition.replace(/\\[/g, \" [ \");\n definition = definition.replace(/\\,/g, \" , \");\n\n // Split the definition into raw token form and return it.\n return definition.replace(/\\s+/g, \" \").trim().split(\" \");\n}\n", "import { StringLiteralPlaceholders, popAndCheck } from \"./MDSLUtilities\";\n\n/**\n * A type representing any node function argument.\n */\ntype Argument = {\n /**\n * The argument value.\n */\n value: T;\n /**\n * The argument type, used for validation.\n */\n type: string;\n};\n\ntype NullArgument = Argument & {\n type: \"null\";\n};\n\ntype BooleanArgument = Argument & {\n type: \"boolean\";\n};\n\ntype NumberArgument = Argument & {\n type: \"number\";\n /**\n * A flag defining whether the number argument value is a valid integer. (used for validation)\n */\n isInteger: boolean;\n};\n\ntype StringPlaceholderArgument = Argument & {\n type: \"string\";\n};\n\ntype IdentifierArgument = Argument & {\n type: \"identifier\";\n};\n\n/**\n * A type representing a reference to any node function argument.\n */\ntype AnyArgument = NullArgument | BooleanArgument | NumberArgument | StringPlaceholderArgument | IdentifierArgument;\n\n/**\n * Parse an array of argument definitions from the specified tokens array.\n * @param tokens The array tokens to parse the argument definitions from.\n * @param stringArgumentPlaceholders The mapping of string literal node argument placeholders to original values.\n * @param argumentValidator The argument validator function.\n * @param validationFailedMessage The exception message to throw if argument validation fails.\n * @returns An array of argument definitions parsed from the specified tokens array.\n */\nexport function parseArgumentTokens(\n tokens: string[],\n stringArgumentPlaceholders: StringLiteralPlaceholders\n): AnyArgument[] {\n const argumentList: AnyArgument[] = [];\n\n // If the next token is not a '[' or '(' then we have no arguments to parse.\n if (![\"[\", \"(\"].includes(tokens[0])) {\n return argumentList;\n }\n\n // Any lists of arguments will always be wrapped in '[]' for node arguments or '()' for attribute arguments.\n // We are looking for a '[' or '(' opener that wraps the argument tokens and the relevant closer.\n const closingToken = popAndCheck(tokens, [\"[\", \"(\"]) === \"[\" ? \"]\" : \")\";\n\n const argumentListTokens: string[] = [];\n\n // Grab all tokens between the '[' and ']' or '(' and ')'.\n while (tokens.length && tokens[0] !== closingToken) {\n // The next token is part of our arguments list.\n argumentListTokens.push(tokens.shift()!);\n }\n\n // Validate the order of the argument tokens. Each token must either be a ',' or a single argument that satisfies the validator.\n argumentListTokens.forEach((token, index) => {\n // Get whether this token should be an actual argument.\n const shouldBeArgumentToken = !(index & 1);\n\n // If the current token should be an actual argument then validate it, otherwise it should be a ',' token.\n if (shouldBeArgumentToken) {\n // Get the argument definition.\n const argumentDefinition = getArgumentDefinition(token, stringArgumentPlaceholders);\n\n // This is a valid argument!\n argumentList.push(argumentDefinition);\n } else {\n // The current token should be a ',' token.\n if (token !== \",\") {\n throw new Error(`invalid argument list, expected ',' or ']' but got '${token}'`);\n }\n }\n });\n\n // The arguments list should terminate with a ']' or ')' token, depending on the opener.\n popAndCheck(tokens, closingToken);\n\n // Return the arguments.\n return argumentList;\n}\n\n/**\n * Gets an argument value definition.\n * @param token The argument token.\n * @param stringArgumentPlaceholders The mapping of string literal node argument placeholders to original values.\n * @returns An argument value definition.\n */\nfunction getArgumentDefinition(token: string, stringArgumentPlaceholders: StringLiteralPlaceholders): AnyArgument {\n // Check whether the token represents a null value.\n if (token === \"null\") {\n return {\n value: null,\n type: \"null\"\n } as NullArgument;\n }\n\n // Check whether the token represents a boolean value.\n if (token === \"true\" || token === \"false\") {\n return {\n value: token === \"true\",\n type: \"boolean\"\n } as BooleanArgument;\n }\n\n // Check whether the token represents a number value.\n // TODO: Relies on broken isNaN - see MDN.\n // if (!Number.isNaN(token)) {\n if (!isNaN(token as any)) {\n return {\n value: parseFloat(token),\n isInteger: parseFloat(token) === parseInt(token, 10),\n type: \"number\"\n } as NumberArgument;\n }\n\n // Check whether the token is a placeholder (e.g. @@0@@) representing a string literal.\n if (token.match(/^@@\\d+@@$/g)) {\n return {\n value: stringArgumentPlaceholders[token].replace('\\\\\"', '\"'),\n type: \"string\"\n } as StringPlaceholderArgument;\n }\n\n // The only remaining option is that the argument value is an identifier.\n return {\n value: token,\n type: \"identifier\"\n } as IdentifierArgument;\n}\n", "import { NodeAttributeDefinition } from \"../BehaviourTreeDefinition\";\nimport { parseArgumentTokens } from \"./MDSLNodeArgumentParser\";\nimport { StringLiteralPlaceholders } from \"./MDSLUtilities\";\n\n/**\n * A type defining the attribute definitions of a node.\n */\ntype NodeAttributes = {\n while?: NodeAttributeDefinition;\n until?: NodeAttributeDefinition;\n entry?: NodeAttributeDefinition;\n exit?: NodeAttributeDefinition;\n step?: NodeAttributeDefinition;\n};\n\n/**\n * Parse any node attribute definitions from the specified tokens array.\n * @param tokens The array of remaining tokens.\n * @param stringArgumentPlaceholders The mapping of string literal node argument placeholders to original values.\n * @returns An object of attribute definitions defined by any directly following tokens.\n */\nexport function parseAttributeTokens(\n tokens: string[],\n stringArgumentPlaceholders: StringLiteralPlaceholders\n): NodeAttributes {\n const nodeAttributeNames: (keyof NodeAttributes)[] = [\"while\", \"until\", \"entry\", \"exit\", \"step\"];\n\n // Create an object to hold any attributes found.\n const attributes: NodeAttributes = {};\n\n // Try to get the name of the attribute for the next token.\n let nextAttributeName = tokens[0]?.toLowerCase() as keyof NodeAttributes;\n\n // Pull attribute tokens as well as their arguments off of the tokens stack until we have no more.\n while (nodeAttributeNames.includes(nextAttributeName)) {\n // Check to make sure that we have not already created an attribute definition of this type.\n if (attributes[nextAttributeName]) {\n throw new Error(`duplicate attribute '${tokens[0].toUpperCase()}' found for node`);\n }\n\n // Remove the attribute name token from the array of tokens.\n tokens.shift();\n\n // Grab the attribute arguments, assuming the first to be an identifier.\n const [attributeCallIdentifier, ...attributeArguments] = parseArgumentTokens(\n tokens,\n stringArgumentPlaceholders\n );\n\n // The first attribute argument has to be an identifer, this will reference an agent function.\n if (attributeCallIdentifier?.type !== \"identifier\") {\n throw new Error(\"expected agent function name identifier argument for attribute\");\n }\n\n // Any attribute arguments (other than the expected call identifier) must have a type of string, number, boolean or null.\n attributeArguments\n .filter((arg) => arg.type === \"identifier\")\n .forEach((arg) => {\n throw new Error(\n `invalid attribute argument value '${arg.value}', must be string, number, boolean or null`\n );\n });\n\n // Create the attribute definition and add it to the object of attribute definitions found.\n attributes[nextAttributeName] = {\n call: attributeCallIdentifier.value,\n args: attributeArguments.map(({ value }) => value)\n };\n\n // Try to get the next attribute name token, as there could be multiple.\n nextAttributeName = tokens[0]?.toLowerCase() as keyof NodeAttributes;\n }\n\n return attributes;\n}\n", "import {\n ActionNodeDefinition,\n AnyChildNodeDefinition,\n AnyNodeDefinition,\n BranchNodeDefinition,\n ConditionNodeDefinition,\n FailNodeDefinition,\n FlipNodeDefinition,\n LottoNodeDefinition,\n ParallelNodeDefinition,\n RepeatNodeDefinition,\n RetryNodeDefinition,\n RootNodeDefinition,\n SelectorNodeDefinition,\n SequenceNodeDefinition,\n SucceedNodeDefinition,\n WaitNodeDefinition\n} from \"../BehaviourTreeDefinition\";\nimport {\n isCompositeNode,\n isDecoratorNode,\n isLeafNode,\n isNullOrUndefined,\n isRootNode\n} from \"../BehaviourTreeDefinitionUtilities\";\nimport { parseArgumentTokens } from \"./MDSLNodeArgumentParser\";\nimport { parseAttributeTokens } from \"./MDSLNodeAttributeParser\";\nimport {\n StringLiteralPlaceholders,\n parseTokensFromDefinition,\n popAndCheck,\n substituteStringLiterals\n} from \"./MDSLUtilities\";\n\n/**\n * Convert the MDSL tree definition string into an equivalent JSON definition.\n * @param definition The tree definition string as MDSL.\n * @returns The root node JSON definitions.\n */\nexport function convertMDSLToJSON(definition: string): RootNodeDefinition[] {\n // Swap out any node/attribute argument string literals with a placeholder and get a mapping of placeholders to original values as well as the processed definition.\n const { placeholders, processedDefinition } = substituteStringLiterals(definition);\n\n // Parse our definition definition string into an array of raw tokens.\n const tokens = parseTokensFromDefinition(processedDefinition);\n\n return convertTokensToJSONDefinition(tokens, placeholders);\n}\n\n/**\n * Converts the specified tree definition tokens into a JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The root node JSON definitions.\n */\nfunction convertTokensToJSONDefinition(\n tokens: string[],\n stringLiteralPlaceholders: StringLiteralPlaceholders\n): RootNodeDefinition[] {\n // There must be at least 3 tokens for the tree definition to be valid. 'ROOT', '{' and '}'.\n if (tokens.length < 3) {\n throw new Error(\"invalid token count\");\n }\n\n // We should have a matching number of '{' and '}' tokens. If not, then there are scopes that have not been properly closed.\n if (tokens.filter((token) => token === \"{\").length !== tokens.filter((token) => token === \"}\").length) {\n throw new Error(\"scope character mismatch\");\n }\n\n // Create an array of tree stack arrays where root nodes will always be at the botton and the current composite/decorator node at the top.\n // There should be an element in this array for every root node defined and every element should be an array with a root note as the first element.\n // E.g. A definition with two root nodes defined:\n // [\n // [root, lotto, sequence],\n // [root, selector]\n // ]\n const treeStacks: [Partial, ...Partial[]][] = [];\n\n // Create an array of all root node definitions that we create.\n const rootNodes: Partial[] = [];\n\n // A helper function used to push node definitions onto the tree stack.\n const pushNode = (node: AnyNodeDefinition) => {\n // If the node is a root node then we need to create a new tree stack array with the root node at the root.\n if (isRootNode(node)) {\n // We need to double-check that this root node is not the child of another node.\n // We can do this by checking whether the top tree stack is not empty (contains an existing node)\n if (treeStacks[treeStacks.length - 1]?.length) {\n throw new Error(\"a root node cannot be the child of another node\");\n }\n\n // Add the root node definition to our array of all parsed root node definitions.\n rootNodes.push(node);\n\n // Add the root node definition to the root of a new tree stack.\n treeStacks.push([node]);\n\n return;\n }\n\n // All non-root nodes should be pushed after their root nodes so handle cases\n // where we may not have any tree stacks or our top-most tree stack is empty.\n if (!treeStacks.length || !treeStacks[treeStacks.length - 1].length) {\n throw new Error(\"expected root node at base of definition\");\n }\n\n // Get the current tree stack that we are populating.\n const topTreeStack = treeStacks[treeStacks.length - 1];\n\n // Get the top-most node in the current tree stack, this will be a composite/decorator node\n // for which we will populate its children array if composite or setting its child if a decorator.\n const topTreeStackTopNode = topTreeStack[topTreeStack.length - 1] as AnyNodeDefinition;\n\n // If the top-most node in the current root stack is a composite or decorator\n // node then the current node should be added as a child of the top-most node.\n if (isCompositeNode(topTreeStackTopNode)) {\n topTreeStackTopNode.children = topTreeStackTopNode.children || [];\n topTreeStackTopNode.children.push(node);\n } else if (isDecoratorNode(topTreeStackTopNode)) {\n // If the top node already has a child node set then throw an error as a decorator should only have a single child.\n if (topTreeStackTopNode.child) {\n throw new Error(\"a decorator node must only have a single child node\");\n }\n\n topTreeStackTopNode.child = node;\n }\n\n // If the node we are adding is also a composite or decorator node, then we should push it\n // onto the current tree stack, as subsequent nodes will be added as its child/children.\n if (!isLeafNode(node)) {\n topTreeStack.push(node);\n }\n };\n\n // A helper function used to pop the top-most node definition off of the tree stack and return it.\n const popNode = (): AnyNodeDefinition | null => {\n let poppedNode: AnyNodeDefinition | null = null;\n\n // Get the current tree stack that we are populating.\n const topTreeStack = treeStacks[treeStacks.length - 1];\n\n // Pop the top-most node in the current tree stack if there is one.\n if (topTreeStack.length) {\n poppedNode = topTreeStack.pop() as AnyNodeDefinition;\n }\n\n // We don't want any empty tree stacks in our stack of tree stacks.\n if (!topTreeStack.length) {\n treeStacks.pop();\n }\n\n return poppedNode;\n };\n\n // We should keep processing the raw tokens until we run out of them.\n while (tokens.length) {\n // Grab the next token.\n const token = tokens.shift()!;\n\n // How we create the next node depends on the current raw token value.\n switch (token.toUpperCase()) {\n case \"ROOT\": {\n pushNode(createRootNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"SUCCEED\": {\n pushNode(createSucceedNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"FAIL\": {\n pushNode(createFailNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"FLIP\": {\n pushNode(createFlipNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"REPEAT\": {\n pushNode(createRepeatNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"RETRY\": {\n pushNode(createRetryNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"SEQUENCE\": {\n pushNode(createSequenceNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"SELECTOR\": {\n pushNode(createSelectorNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"PARALLEL\": {\n pushNode(createParallelNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"LOTTO\": {\n pushNode(createLottoNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"ACTION\": {\n pushNode(createActionNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"CONDITION\": {\n pushNode(createConditionNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"WAIT\": {\n pushNode(createWaitNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"BRANCH\": {\n pushNode(createBranchNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"}\": {\n // The '}' character closes the current scope and means that we have to pop a node off of the current stack.\n const poppedNode = popNode();\n\n // Now that we have a node definition we can carry out any validation that may require the node to be fully populated.\n if (poppedNode) {\n validatePoppedNode(poppedNode);\n }\n\n break;\n }\n\n default: {\n throw new Error(`unexpected token: ${token}`);\n }\n }\n }\n\n return rootNodes as RootNodeDefinition[];\n}\n\n/**\n * Creates a root node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The root node JSON definition.\n */\nfunction createRootNode(tokens: string[], stringLiteralPlaceholders: StringLiteralPlaceholders): RootNodeDefinition {\n // Create the root node definition.\n let node = {\n type: \"root\",\n id: undefined\n } as RootNodeDefinition;\n\n // Parse any node arguments, we should only have one if any which will be an identifier argument for the root identifier.\n const nodeArguments = parseArgumentTokens(tokens, stringLiteralPlaceholders);\n\n // Check whether any node arguments were defined.\n if (nodeArguments.length) {\n // We should only have one argument, if any, which will be an identifier argument for the root identifier.\n if (nodeArguments.length === 1 && nodeArguments[0].type === \"identifier\") {\n // The root node identifier will be the first and only node argument value.\n node.id = nodeArguments[0].value as string;\n } else {\n throw new Error(\"expected single root name argument\");\n }\n }\n\n // Grab any node attribute definitions and spread them into the node definition.\n node = { ...node, ...parseAttributeTokens(tokens, stringLiteralPlaceholders) };\n\n // This is a decorator node, so we expect an opening '{'.\n popAndCheck(tokens, \"{\");\n\n // Return the root node definition.\n return node;\n}\n\n/**\n * Creates a succeed node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The succeed node JSON definition.\n */\nfunction createSucceedNode(\n tokens: string[],\n stringLiteralPlaceholders: StringLiteralPlaceholders\n): SucceedNodeDefinition {\n const node = {\n type: \"succeed\",\n ...parseAttributeTokens(tokens, stringLiteralPlaceholders)\n } as SucceedNodeDefinition;\n\n // This is a decorator node, so we expect an opening '{'.\n popAndCheck(tokens, \"{\");\n\n // Return the succeed node definition.\n return node;\n}\n\n/**\n * Creates a fail node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The fail node JSON definition.\n */\nfunction createFailNode(tokens: string[], stringLiteralPlaceholders: StringLiteralPlaceholders): FailNodeDefinition {\n const node = {\n type: \"fail\",\n ...parseAttributeTokens(tokens, stringLiteralPlaceholders)\n } as FailNodeDefinition;\n\n // This is a decorator node, so we expect an opening '{'.\n popAndCheck(tokens, \"{\");\n\n // Return the fail node definition.\n return node;\n}\n\n/**\n * Creates a flip node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The flip node JSON definition.\n */\nfunction createFlipNode(tokens: string[], stringLiteralPlaceholders: StringLiteralPlaceholders): FlipNodeDefinition {\n const node = {\n type: \"flip\",\n ...parseAttributeTokens(tokens, stringLiteralPlaceholders)\n } as FlipNodeDefinition;\n\n // This is a decorator node, so we expect an opening '{'.\n popAndCheck(tokens, \"{\");\n\n // Return the flip node definition.\n return node;\n}\n\n/**\n * Creates a repeat node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The repeat node JSON definition.\n */\nfunction createRepeatNode(\n tokens: string[],\n stringLiteralPlaceholders: StringLiteralPlaceholders\n): RepeatNodeDefinition {\n let node = { type: \"repeat\" } as RepeatNodeDefinition;\n\n // Get the node arguments.\n const nodeArguments = parseArgumentTokens(tokens, stringLiteralPlaceholders);\n\n // The arguments of a repeat node are optional. We may have:\n // - No node arguments, in which case the repeat note will iterate indefinitely.\n // - One node argument which will be the explicit number of iterations to make.\n // - Two node arguments which define the min and max iteration bounds from which a random iteration count will be picked.\n if (nodeArguments.length) {\n // All repeat node arguments MUST be of type number and must be integer.\n nodeArguments\n .filter((arg) => arg.type !== \"number\" || !arg.isInteger)\n .forEach(() => {\n throw new Error(`repeat node iteration counts must be integer values`);\n });\n\n // We should have got one or two iteration counts.\n if (nodeArguments.length === 1) {\n // A static iteration count was defined.\n node.iterations = nodeArguments[0].value as number;\n\n // A repeat node must have a positive number of iterations if defined.\n if (node.iterations < 0) {\n throw new Error(\"a repeat node must have a positive number of iterations if defined\");\n }\n } else if (nodeArguments.length === 2) {\n // A minimum and maximum iteration count was defined.\n node.iterations = [nodeArguments[0].value as number, nodeArguments[1].value as number];\n\n // A repeat node must have a positive min and max iteration count if they are defined.\n if (node.iterations[0] < 0 || node.iterations[1] < 0) {\n throw new Error(\"a repeat node must have a positive minimum and maximum iteration count if defined\");\n }\n\n // A repeat node must not have an minimum iteration count that exceeds the maximum iteration count.\n if (node.iterations[0] > node.iterations[1]) {\n throw new Error(\n \"a repeat node must not have a minimum iteration count that exceeds the maximum iteration count\"\n );\n }\n } else {\n // An incorrect number of iteration counts was defined.\n throw new Error(\"invalid number of repeat node iteration count arguments defined\");\n }\n }\n\n // Grab any node attribute definitions and spread them into the node definition.\n node = { ...node, ...parseAttributeTokens(tokens, stringLiteralPlaceholders) };\n\n // This is a decorator node, so we expect an opening '{'.\n popAndCheck(tokens, \"{\");\n\n // Return the repeat node definition.\n return node;\n}\n\n/**\n * Creates a retry node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The retry node JSON definition.\n */\nfunction createRetryNode(tokens: string[], stringLiteralPlaceholders: StringLiteralPlaceholders): RetryNodeDefinition {\n let node = { type: \"retry\" } as RetryNodeDefinition;\n\n // Get the node arguments.\n const nodeArguments = parseArgumentTokens(tokens, stringLiteralPlaceholders);\n\n // The arguments of a retry node are optional. We may have:\n // - No node arguments, in which case the retry note will attempt indefinitely.\n // - One node argument which will be the explicit number of attempts to make.\n // - Two node arguments which define the min and max attempt bounds from which a random attempt count will be picked.\n if (nodeArguments.length) {\n // All retry node arguments MUST be of type number and must be integer.\n nodeArguments\n .filter((arg) => arg.type !== \"number\" || !arg.isInteger)\n .forEach(() => {\n throw new Error(`retry node attempt counts must be integer values`);\n });\n\n // We should have got one or two attempt counts.\n if (nodeArguments.length === 1) {\n // A static attempt count was defined.\n node.attempts = nodeArguments[0].value as number;\n\n // A retry node must have a positive number of attempts if defined.\n if (node.attempts < 0) {\n throw new Error(\"a retry node must have a positive number of attempts if defined\");\n }\n } else if (nodeArguments.length === 2) {\n // A minimum and maximum attempt count was defined.\n node.attempts = [nodeArguments[0].value as number, nodeArguments[1].value as number];\n\n // A retry node must have a positive min and max attempts count if they are defined.\n if (node.attempts[0] < 0 || node.attempts[1] < 0) {\n throw new Error(\"a retry node must have a positive minimum and maximum attempt count if defined\");\n }\n\n // A retry node must not have a minimum attempt count that exceeds the maximum attempt count.\n if (node.attempts[0] > node.attempts[1]) {\n throw new Error(\n \"a retry node must not have a minimum attempt count that exceeds the maximum attempt count\"\n );\n }\n } else {\n // An incorrect number of attempt counts was defined.\n throw new Error(\"invalid number of retry node attempt count arguments defined\");\n }\n }\n\n // Grab any node attribute definitions and spread them into the node definition.\n node = { ...node, ...parseAttributeTokens(tokens, stringLiteralPlaceholders) };\n\n // This is a decorator node, so we expect an opening '{'.\n popAndCheck(tokens, \"{\");\n\n // Return the retry node definition.\n return node;\n}\n\n/**\n * Creates a sequence node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The sequence node JSON definition.\n */\nfunction createSequenceNode(\n tokens: string[],\n stringLiteralPlaceholders: StringLiteralPlaceholders\n): SequenceNodeDefinition {\n const node = {\n type: \"sequence\",\n ...parseAttributeTokens(tokens, stringLiteralPlaceholders)\n } as SequenceNodeDefinition;\n\n // This is a composite node, so we expect an opening '{'.\n popAndCheck(tokens, \"{\");\n\n // Return the sequence node definition.\n return node;\n}\n\n/**\n * Creates a selector node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The selector node JSON definition.\n */\nfunction createSelectorNode(\n tokens: string[],\n stringLiteralPlaceholders: StringLiteralPlaceholders\n): SelectorNodeDefinition {\n const node = {\n type: \"selector\",\n ...parseAttributeTokens(tokens, stringLiteralPlaceholders)\n } as SelectorNodeDefinition;\n\n // This is a composite node, so we expect an opening '{'.\n popAndCheck(tokens, \"{\");\n\n // Return the selector node definition.\n return node;\n}\n\n/**\n * Creates a parallel node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The parallel node JSON definition.\n */\nfunction createParallelNode(\n tokens: string[],\n stringLiteralPlaceholders: StringLiteralPlaceholders\n): ParallelNodeDefinition {\n const node = {\n type: \"parallel\",\n ...parseAttributeTokens(tokens, stringLiteralPlaceholders)\n } as ParallelNodeDefinition;\n\n // This is a composite node, so we expect an opening '{'.\n popAndCheck(tokens, \"{\");\n\n // Return the parallel node definition.\n return node;\n}\n\n/**\n * Creates a lotto node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The lotto node JSON definition.\n */\nfunction createLottoNode(tokens: string[], stringLiteralPlaceholders: StringLiteralPlaceholders): LottoNodeDefinition {\n // If any node arguments have been defined then they must be our weights.\n const nodeArguments = parseArgumentTokens(tokens, stringLiteralPlaceholders);\n\n // All lotto node arguments MUST be of type number and must be positive integers.\n nodeArguments\n .filter((arg) => arg.type !== \"number\" || !arg.isInteger || arg.value < 0)\n .forEach(() => {\n throw new Error(`lotto node weight arguments must be positive integer values`);\n });\n\n const node = {\n type: \"lotto\",\n weights: nodeArguments.length ? nodeArguments.map(({ value }) => value) : undefined,\n ...parseAttributeTokens(tokens, stringLiteralPlaceholders)\n } as LottoNodeDefinition;\n\n // This is a composite node, so we expect an opening '{'.\n popAndCheck(tokens, \"{\");\n\n // Return the lotto node definition.\n return node;\n}\n\n/**\n * Creates an action node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The action node JSON definition.\n */\nfunction createActionNode(\n tokens: string[],\n stringLiteralPlaceholders: StringLiteralPlaceholders\n): ActionNodeDefinition {\n // Parse any node arguments, we should have at least one which will be an identifier argument for the action name\n // and agent function to invoke for the action, all other arguments are to be passed as arguments to that function.\n const [actionNameIdentifier, ...agentFunctionArgs] = parseArgumentTokens(tokens, stringLiteralPlaceholders);\n\n // Our first argument MUST be defined and be an identifier as we require an action name argument.\n if (actionNameIdentifier?.type !== \"identifier\") {\n throw new Error(\"expected action name identifier argument\");\n }\n\n // Only the first argument should have been an identifier, all agent function arguments must be string, number, boolean or null.\n agentFunctionArgs\n .filter((arg) => arg.type === \"identifier\")\n .forEach((arg) => {\n throw new Error(\n `invalid action node argument value '${arg.value}', must be string, number, boolean or null`\n );\n });\n\n // Return the action node definition.\n return {\n type: \"action\",\n call: actionNameIdentifier.value,\n args: agentFunctionArgs.map(({ value }) => value),\n ...parseAttributeTokens(tokens, stringLiteralPlaceholders)\n };\n}\n\n/**\n * Creates a condition node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The condition node JSON definition.\n */\nfunction createConditionNode(\n tokens: string[],\n stringLiteralPlaceholders: StringLiteralPlaceholders\n): ConditionNodeDefinition {\n // Parse any node arguments, we should have at least one which will be an identifier argument for the condition name\n // and agent function to invoke for the condition, all other arguments are to be passed as arguments to that function.\n const [conditionNameIdentifier, ...agentFunctionArgs] = parseArgumentTokens(tokens, stringLiteralPlaceholders);\n\n // Our first argument MUST be defined and be an identifier as we require a condition name argument.\n if (conditionNameIdentifier?.type !== \"identifier\") {\n throw new Error(\"expected condition name identifier argument\");\n }\n\n // Only the first argument should have been an identifier, all agent function arguments must be string, number, boolean or null.\n agentFunctionArgs\n .filter((arg) => arg.type === \"identifier\")\n .forEach((arg) => {\n throw new Error(\n `invalid condition node argument value '${arg.value}', must be string, number, boolean or null`\n );\n });\n\n // Return the condition node definition.\n return {\n type: \"condition\",\n call: conditionNameIdentifier.value,\n args: agentFunctionArgs.map(({ value }) => value),\n ...parseAttributeTokens(tokens, stringLiteralPlaceholders)\n };\n}\n\n/**\n * Creates a wait node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The wait node JSON definition.\n */\nfunction createWaitNode(tokens: string[], stringLiteralPlaceholders: StringLiteralPlaceholders): WaitNodeDefinition {\n let node = { type: \"wait\" } as WaitNodeDefinition;\n\n // Get the node arguments.\n const nodeArguments = parseArgumentTokens(tokens, stringLiteralPlaceholders);\n\n // The arguments of a wait node are optional. We may have:\n // - No node arguments, in which case the wait will be indefinite until it is aborted.\n // - One node argument which will be the explicit duration of the wait.\n // - Two node arguments which define the min and max duration bounds from which a random duration will be picked.\n if (nodeArguments.length) {\n // All wait node arguments MUST be of type number and must be integer.\n nodeArguments\n .filter((arg) => arg.type !== \"number\" || !arg.isInteger)\n .forEach(() => {\n throw new Error(`wait node durations must be integer values`);\n });\n\n // We may have:\n // - One node argument which will be the explicit duration of the wait.\n // - Two node arguments which define the min and max duration bounds from which a random duration will be picked.\n // - Too many arguments, which is not valid.\n if (nodeArguments.length === 1) {\n // An explicit duration was defined.\n node.duration = nodeArguments[0].value as number;\n\n // If an explict duration was defined then it must be a positive number.\n if (node.duration < 0) {\n throw new Error(\"a wait node must have a positive duration\");\n }\n } else if (nodeArguments.length === 2) {\n // Min and max duration bounds were defined from which a random duration will be picked.\n node.duration = [nodeArguments[0].value as number, nodeArguments[1].value as number];\n\n // A wait node must have a positive min and max duration.\n if (node.duration[0] < 0 || node.duration[1] < 0) {\n throw new Error(\"a wait node must have a positive minimum and maximum duration\");\n }\n\n // A wait node must not have a minimum duration that exceeds the maximum duration.\n if (node.duration[0] > node.duration[1]) {\n throw new Error(\"a wait node must not have a minimum duration that exceeds the maximum duration\");\n }\n } else if (nodeArguments.length > 2) {\n // An incorrect number of duration arguments were defined.\n throw new Error(\"invalid number of wait node duration arguments defined\");\n }\n }\n\n // Return the wait node definition.\n return { ...node, ...parseAttributeTokens(tokens, stringLiteralPlaceholders) };\n}\n\n/**\n * Creates a branch node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The branch node JSON definition.\n */\nfunction createBranchNode(\n tokens: string[],\n stringLiteralPlaceholders: StringLiteralPlaceholders\n): BranchNodeDefinition {\n // Parse any node arguments, we should have one which will be an identifier argument for the root ref.\n const nodeArguments = parseArgumentTokens(tokens, stringLiteralPlaceholders);\n\n // We should have only a single identifer argument for a branch node, which is the root ref.\n if (nodeArguments.length !== 1 || nodeArguments[0].type !== \"identifier\") {\n throw new Error(\"expected single branch name argument\");\n }\n\n // Return the branch node definition.\n return { type: \"branch\", ref: nodeArguments[0].value };\n}\n\n/**\n * Validate a fully-populated node definition that was popped off of the tree stack.\n * @param definition The popped node to validate.\n */\nfunction validatePoppedNode(definition: AnyNodeDefinition): void {\n // Decorators MUST have a child defined.\n if (isDecoratorNode(definition) && isNullOrUndefined(definition.child)) {\n throw new Error(`a ${definition.type} node must have a single child node defined`);\n }\n\n // Composites MUST have at least one child defined.\n if (isCompositeNode(definition) && !definition.children?.length) {\n throw new Error(`a ${definition.type} node must have at least a single child node defined`);\n }\n\n // We need to make sure that lotto nodes that have weights defined have a number of weights matching the number of child nodes.\n if (definition.type === \"lotto\") {\n // Check whether a 'weights' property has been defined, if it has we expect it to be an array of weights.\n if (typeof definition.weights !== \"undefined\") {\n // Check that the weights property is an array of positive integers with an element for each child node element.\n if (definition.weights.length !== definition.children.length) {\n throw new Error(\n \"expected a number of weight arguments matching the number of child nodes for lotto node\"\n );\n }\n }\n }\n}\n", "import { RootNodeDefinition } from \"./BehaviourTreeDefinition\";\nimport { flattenDefinition, isBranchNode, isInteger } from \"./BehaviourTreeDefinitionUtilities\";\nimport { convertMDSLToJSON } from \"./mdsl/MDSLDefinitionParser\";\n\n/**\n * An object representing the result of validating a tree definition.\n */\nexport type DefinitionValidationResult = {\n /**\n * A flag defining whether validation succeeded.\n */\n succeeded: boolean;\n /**\n * A string containing the error message if validation did not succeed.\n */\n errorMessage?: string;\n};\n\n/**\n * Validates the specified behaviour tree definition in the form of JSON or MDSL, not taking any globally registered subtrees into consideration.\n * @param definition The behaviour tree definition in the form of JSON or MDSL.\n * @returns An object representing the result of validating the given tree definition.\n */\nexport function validateDefinition(definition: any): DefinitionValidationResult {\n // The definition must be defined.\n if (definition === null || typeof definition === \"undefined\") {\n return createValidationFailureResult(\"definition is null or undefined\");\n }\n\n // We are expecting a definition in one of three different forms:\n // - A string which we will assume is MDSL and we will parse this to JSON before validation.\n // - An array which we will assume is an array of root node definitions with at least one being the primary root node (no 'id' property)\n // - An object which we will assume is the primary root node and should not have an 'id' property.\n if (typeof definition === \"string\") {\n // The definition is a string which we can assume is MDSL, so attempt to validate it.\n return validateMDSLDefinition(definition);\n } else if (typeof definition === \"object\") {\n // The definition will either be an array (of root node definitions) or an object (the single primary root node definition).\n return validateJSONDefinition(definition);\n } else {\n return createValidationFailureResult(`unexpected definition type of '${typeof definition}'`);\n }\n}\n\n/**\n * Validates the specified behaviour tree definition in the form of MDSL.\n * @param definition The behaviour tree definition in the form of MDSL.\n * @returns An object representing the result of validating the given tree definition.\n */\nexport function validateMDSLDefinition(definition: string): DefinitionValidationResult {\n let rootNodeDefinitions;\n\n // The first thing the we need to do is to attempt to convert our MDSL into JSON.\n try {\n // The definition is a string which we can assume is MDSL, so attempt to parse it to a JSON definition in the form of an array of root node definitions.\n rootNodeDefinitions = convertMDSLToJSON(definition);\n } catch (exception) {\n // We failed to parse the JSON from the MDSL, this is likely to be the result of it not being a valid MDSL string.\n return createValidationFailureResult((exception as Error).message);\n }\n\n // Unpack all of the root node definitions into arrays of main ('id' defined) and sub ('id' not defined) root node definitions.\n const mainRootNodeDefinitions = rootNodeDefinitions.filter(({ id }) => typeof id === \"undefined\");\n const subRootNodeDefinitions = rootNodeDefinitions.filter(({ id }) => typeof id === \"string\" && id.length > 0);\n\n // We should ALWAYS have exactly one root node definition without an 'id' property defined, which is out main root node definition.\n if (mainRootNodeDefinitions.length !== 1) {\n return createValidationFailureResult(\n \"expected single unnamed root node at base of definition to act as main root\"\n );\n }\n\n // We should never have duplicate 'id' properties across our sub root node definitions.\n const subRootNodeIdenitifers: string[] = [];\n for (const { id } of subRootNodeDefinitions) {\n // Have we already come across this 'id' property value?\n if (subRootNodeIdenitifers.includes(id!)) {\n return createValidationFailureResult(`multiple root nodes found with duplicate name '${id}'`);\n }\n\n subRootNodeIdenitifers.push(id!);\n }\n\n try {\n // Validate our branch -> subtree links and check for any circular dependencies, we don't care about checking for broken subtree links here.\n validateBranchSubtreeLinks(rootNodeDefinitions, false);\n } catch (exception) {\n return createValidationFailureResult((exception as Error).message);\n }\n\n // Our definition was valid!\n return { succeeded: true };\n}\n\n/**\n * Validates the specified behaviour tree definition in the form of JSON.\n * @param definition The behaviour tree definition in the form of JSON.\n * @returns An object representing the result of validating the given tree definition.\n */\nexport function validateJSONDefinition(\n definition: RootNodeDefinition | RootNodeDefinition[]\n): DefinitionValidationResult {\n // The definition will either be an array (of root node definitions) or an object (the single primary root node definition).\n const rootNodeDefinitions = Array.isArray(definition) ? definition : [definition];\n\n // Iterate over our array of root nodes and call validateNode for each, passing an initial depth of 0, wrapped in a try catch to handle validation failures.\n try {\n rootNodeDefinitions.forEach((rootNodeDefinition) => validateNode(rootNodeDefinition, 0));\n } catch (error) {\n // Handle cases where we have caught a thrown Error and return a failure result with the error message.\n if (error instanceof Error) {\n return createValidationFailureResult(error.message);\n }\n\n // No idea what happened here!\n return createValidationFailureResult(`unexpected error: ${error}`);\n }\n\n // Unpack all of the root node definitions into arrays of main ('id' defined) and sub ('id' not defined) root node definitions.\n const mainRootNodeDefinitions = rootNodeDefinitions.filter(({ id }) => typeof id === \"undefined\");\n const subRootNodeDefinitions = rootNodeDefinitions.filter(({ id }) => typeof id === \"string\" && id.length > 0);\n\n // We should ALWAYS have exactly one root node definition without an 'id' property defined, which is out main root node definition.\n if (mainRootNodeDefinitions.length !== 1) {\n return createValidationFailureResult(\n \"expected single root node without 'id' property defined to act as main root\"\n );\n }\n\n // We should never have duplicate 'id' properties across our sub root node definitions.\n const subRootNodeIdenitifers: string[] = [];\n for (const { id } of subRootNodeDefinitions) {\n // Have we already come across this 'id' property value?\n if (subRootNodeIdenitifers.includes(id!)) {\n return createValidationFailureResult(\n `multiple root nodes found with duplicate 'id' property value of '${id}'`\n );\n }\n\n subRootNodeIdenitifers.push(id!);\n }\n\n try {\n // Validate our branch -> subtree links and check for any circular dependencies, we don't care about checking for broken subtree links here.\n validateBranchSubtreeLinks(rootNodeDefinitions, false);\n } catch (exception) {\n return createValidationFailureResult((exception as Error).message);\n }\n\n // Our definition was valid!\n return { succeeded: true };\n}\n\n/**\n * Validates the branch -> subtree links across all provided root node definitions.\n * This will not consider branch nodes that reference any globally registered subtrees unless includesGlobalSubtrees\n * is set to true, in which case we will also verify that there are no broken branch -> subtree links.\n * @param rootNodeDefinitions The array of root node definitions.\n * @param includesGlobalSubtrees A flag defining whether the array includes all global subtree root node definitions.\n */\nexport function validateBranchSubtreeLinks(rootNodeDefinitions: RootNodeDefinition[], includesGlobalSubtrees: boolean) {\n // Create a mapping of root node identifiers to other root nodes that they reference via branch nodes.\n // Below is an example of a mapping that includes a circular dependency (root => a => b => c => a)\n // [{ refs: [\"a\", \"b\"] }, { id: \"a\", refs: [\"b\"] }, { id: \"b\", refs: [\"c\"] }, { id: \"c\", refs: [\"a\"] }]\n const rootNodeMappings: { id: string | undefined; refs: string[] }[] = rootNodeDefinitions.map(\n (rootNodeDefinition) => ({\n id: rootNodeDefinition.id,\n refs: flattenDefinition(rootNodeDefinition)\n .filter(isBranchNode)\n .map(({ ref }) => ref)\n })\n );\n\n // A recursive function to walk through the mappings, keeping track of which root nodes we have visited in the form of a path of root node identifiers.\n const followRefs = (mapping: { id: string | undefined; refs: string[] }, path: (string | undefined)[] = []) => {\n // Have we found a circular dependency?\n if (path.includes(mapping.id)) {\n // We found a circular dependency! Get the bad path of root node identifiers.\n const badPath = [...path, mapping.id];\n\n // Create the formatted path value. [undefined, \"a\", \"b\", \"c\", \"a\"] would be formatted as \"a -> b -> c -> a\".\n const badPathFormatted = badPath.filter((element) => !!element).join(\" => \");\n\n // No need to continue, we found a circular dependency.\n throw new Error(`circular dependency found in branch node references: ${badPathFormatted}`);\n }\n\n for (const ref of mapping.refs) {\n // Find the mapping for the root node with an identifer matching the current ref.\n const subMapping = rootNodeMappings.find(({ id }) => id === ref);\n\n // We may not have a mapping for this ref, which is normal when we aren't considering all globally registered subtrees.\n if (subMapping) {\n followRefs(subMapping, [...path, mapping.id]);\n } else if (includesGlobalSubtrees) {\n // We found a reference to a root node that doesn't exist, which is a problem seeing as the root node definitons includes all globally registered subtrees.\n throw new Error(\n mapping.id\n ? `subtree '${mapping.id}' has branch node that references root node '${ref}' which has not been defined`\n : `primary tree has branch node that references root node '${ref}' which has not been defined`\n );\n }\n }\n };\n\n // Start looking for circular dependencies and broken references from the primary root node definition.\n followRefs(rootNodeMappings.find((mapping) => typeof mapping.id === \"undefined\")!);\n}\n\n/**\n * Validate an object that we expect to be a node definition.\n * @param definition An object that we expect to be a node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateNode(definition: any, depth: number): void {\n // Every node must be valid object and have a non-empty 'type' string property.\n if (typeof definition !== \"object\" || typeof definition.type !== \"string\" || definition.type.length === 0) {\n throw new Error(\n `node definition is not an object or 'type' property is not a non-empty string at depth '${depth}'`\n );\n }\n\n // How we validate this node definition will depend on its type.\n switch (definition.type) {\n case \"action\":\n validateActionNode(definition, depth);\n break;\n\n case \"condition\":\n validateConditionNode(definition, depth);\n break;\n\n case \"wait\":\n validateWaitNode(definition, depth);\n break;\n\n case \"branch\":\n validateBranchNode(definition, depth);\n break;\n\n case \"root\":\n validateRootNode(definition, depth);\n break;\n\n case \"succeed\":\n validateSucceedNode(definition, depth);\n break;\n\n case \"fail\":\n validateFailNode(definition, depth);\n break;\n\n case \"flip\":\n validateFlipNode(definition, depth);\n break;\n\n case \"repeat\":\n validateRepeatNode(definition, depth);\n break;\n\n case \"retry\":\n validateRetryNode(definition, depth);\n break;\n\n case \"sequence\":\n validateSequenceNode(definition, depth);\n break;\n\n case \"selector\":\n validateSelectorNode(definition, depth);\n break;\n\n case \"parallel\":\n validateParallelNode(definition, depth);\n break;\n\n case \"lotto\":\n validateLottoNode(definition, depth);\n break;\n\n default:\n throw new Error(`unexpected node type of '${definition.type}' at depth '${depth}'`);\n }\n}\n\n/**\n * Validate any attributes for a given node definition.\n * @param definition The node definition.\n * @param depth The depth of the node in the behaviour tree definition.\n */\nfunction validateNodeAttributes(definition: any, depth: number): void {\n // Validate each of the attribute types for this node.\n [\"while\", \"until\", \"entry\", \"exit\", \"step\"].forEach((attributeName) => {\n // Attempt to grab the definition for the current attribute from the node definition.\n const attributeDefinition = definition[attributeName];\n\n // All node attributes are optional, so there is nothing to do if the current attribute is not defined.\n if (typeof attributeDefinition === \"undefined\") {\n return;\n }\n\n // The attribute definition must be an object.\n if (typeof attributeDefinition !== \"object\") {\n throw new Error(\n `expected attribute '${attributeName}' to be an object for '${definition.type}' node at depth '${depth}'`\n );\n }\n\n // The 'call' property must be defined for any attribute definition.\n if (typeof attributeDefinition.call !== \"string\" || attributeDefinition.call.length === 0) {\n throw new Error(\n `expected 'call' property for attribute '${attributeName}' to be a non-empty string for '${definition.type}' node at depth '${depth}'`\n );\n }\n\n // If any node attribute arguments have been defined then they must have been defined in an array.\n if (typeof attributeDefinition.args !== \"undefined\" && !Array.isArray(attributeDefinition.args)) {\n throw new Error(\n `expected 'args' property for attribute '${attributeName}' to be an array for '${definition.type}' node at depth '${depth}'`\n );\n }\n });\n}\n\n/**\n * Validate an object that we expect to be a root node definition.\n * @param definition An object that we expect to be a root node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateRootNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"root\") {\n throw new Error(\"expected node type of 'root' for root node\");\n }\n\n // A root node cannot be the child of another node.\n if (depth > 0) {\n throw new Error(\"a root node cannot be the child of another node\");\n }\n\n // Check that, if the root node 'id' property is defined, it is a non-empty string.\n if (typeof definition.id !== \"undefined\" && (typeof definition.id !== \"string\" || definition.id.length === 0)) {\n throw new Error(\"expected non-empty string for 'id' property if defined for root node\");\n }\n\n // A root node is a decorator node, so must have a child node defined.\n if (typeof definition.child === \"undefined\") {\n throw new Error(\"expected property 'child' to be defined for root node\");\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n\n // Validate the child node of this decorator node.\n validateNode(definition.child, depth + 1);\n}\n\n/**\n * Validate an object that we expect to be a succeed node definition.\n * @param definition An object that we expect to be a succeed node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateSucceedNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"succeed\") {\n throw new Error(`expected node type of 'succeed' for succeed node at depth '${depth}'`);\n }\n\n // A succeed node is a decorator node, so must have a child node defined.\n if (typeof definition.child === \"undefined\") {\n throw new Error(`expected property 'child' to be defined for succeed node at depth '${depth}'`);\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n\n // Validate the child node of this decorator node.\n validateNode(definition.child, depth + 1);\n}\n\n/**\n * Validate an object that we expect to be a fail node definition.\n * @param definition An object that we expect to be a fail node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateFailNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"fail\") {\n throw new Error(`expected node type of 'fail' for fail node at depth '${depth}'`);\n }\n\n // A fail node is a decorator node, so must have a child node defined.\n if (typeof definition.child === \"undefined\") {\n throw new Error(`expected property 'child' to be defined for fail node at depth '${depth}'`);\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n\n // Validate the child node of this decorator node.\n validateNode(definition.child, depth + 1);\n}\n\n/**\n * Validate an object that we expect to be a flip node definition.\n * @param definition An object that we expect to be a flip node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateFlipNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"flip\") {\n throw new Error(`expected node type of 'flip' for flip node at depth '${depth}'`);\n }\n\n // A flip node is a decorator node, so must have a child node defined.\n if (typeof definition.child === \"undefined\") {\n throw new Error(`expected property 'child' to be defined for flip node at depth '${depth}'`);\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n\n // Validate the child node of this decorator node.\n validateNode(definition.child, depth + 1);\n}\n\n/**\n * Validate an object that we expect to be a repeat node definition.\n * @param definition An object that we expect to be a repeat node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateRepeatNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"repeat\") {\n throw new Error(`expected node type of 'repeat' for repeat node at depth '${depth}'`);\n }\n\n // A repeat node is a decorator node, so must have a child node defined.\n if (typeof definition.child === \"undefined\") {\n throw new Error(`expected property 'child' to be defined for repeat node at depth '${depth}'`);\n }\n\n // Check whether an 'iterations' property has been defined, it may not have been if this node is to repeat indefinitely.\n if (typeof definition.iterations !== \"undefined\") {\n if (Array.isArray(definition.iterations)) {\n // Check whether any elements of the array are not integer values.\n const containsNonInteger = !!definition.iterations.filter((value: unknown) => !isInteger(value)).length;\n\n // If the 'iterations' property is an array then it MUST contain two integer values.\n if (definition.iterations.length !== 2 || containsNonInteger) {\n throw new Error(\n `expected array containing two integer values for 'iterations' property if defined for repeat node at depth '${depth}'`\n );\n }\n\n // A repeat node must have a positive min and max iterations count if they are defined.\n if (definition.iterations[0] < 0 || definition.iterations[1] < 0) {\n throw new Error(\n `expected positive minimum and maximum iterations count for 'iterations' property if defined for repeat node at depth '${depth}'`\n );\n }\n\n // A repeat node must not have a minimum iterations count that exceeds the maximum iterations count.\n if (definition.iterations[0] > definition.iterations[1]) {\n throw new Error(\n `expected minimum iterations count that does not exceed the maximum iterations count for 'iterations' property if defined for repeat node at depth '${depth}'`\n );\n }\n } else if (isInteger(definition.iterations)) {\n // A repeat node must have a positive number of iterations if defined.\n if (definition.iterations < 0) {\n throw new Error(\n `expected positive iterations count for 'iterations' property if defined for repeat node at depth '${depth}'`\n );\n }\n } else {\n throw new Error(\n `expected integer value or array containing two integer values for 'iterations' property if defined for repeat node at depth '${depth}'`\n );\n }\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n\n // Validate the child node of this decorator node.\n validateNode(definition.child, depth + 1);\n}\n\n/**\n * Validate an object that we expect to be a retry node definition.\n * @param definition An object that we expect to be a retry node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateRetryNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"retry\") {\n throw new Error(`expected node type of 'retry' for retry node at depth '${depth}'`);\n }\n\n // A retry node is a decorator node, so must have a child node defined.\n if (typeof definition.child === \"undefined\") {\n throw new Error(`expected property 'child' to be defined for retry node at depth '${depth}'`);\n }\n\n // Check whether an 'attempts' property has been defined, it may not have been if this node is to retry indefinitely.\n if (typeof definition.attempts !== \"undefined\") {\n if (Array.isArray(definition.attempts)) {\n // Check whether any elements of the array are not integer values.\n const containsNonInteger = !!definition.attempts.filter((value: unknown) => !isInteger(value)).length;\n\n // If the 'attempts' property is an array then it MUST contain two integer values.\n if (definition.attempts.length !== 2 || containsNonInteger) {\n throw new Error(\n `expected array containing two integer values for 'attempts' property if defined for retry node at depth '${depth}'`\n );\n }\n\n // A retry node must have a positive min and max attempts count if they are defined.\n if (definition.attempts[0] < 0 || definition.attempts[1] < 0) {\n throw new Error(\n `expected positive minimum and maximum attempts count for 'attempts' property if defined for retry node at depth '${depth}'`\n );\n }\n\n // A retry node must not have a minimum attempts count that exceeds the maximum attempts count.\n if (definition.attempts[0] > definition.attempts[1]) {\n throw new Error(\n `expected minimum attempts count that does not exceed the maximum attempts count for 'attempts' property if defined for retry node at depth '${depth}'`\n );\n }\n } else if (isInteger(definition.attempts)) {\n // A retry node must have a positive number of attempts if defined.\n if (definition.attempts < 0) {\n throw new Error(\n `expected positive attempts count for 'attempts' property if defined for retry node at depth '${depth}'`\n );\n }\n } else {\n throw new Error(\n `expected integer value or array containing two integer values for 'attempts' property if defined for retry node at depth '${depth}'`\n );\n }\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n\n // Validate the child node of this decorator node.\n validateNode(definition.child, depth + 1);\n}\n\n/**\n * Validate an object that we expect to be a branch node definition.\n * @param definition An object that we expect to be a branch node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateBranchNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"branch\") {\n throw new Error(`expected node type of 'branch' for branch node at depth '${depth}'`);\n }\n\n // Check that the branch node 'ref' property is defined and is a non-empty string.\n if (typeof definition.ref !== \"string\" || definition.ref.length === 0) {\n throw new Error(`expected non-empty string for 'ref' property for branch node at depth '${depth}'`);\n }\n\n // It is invalid to define guard attributes for a branch node as they should be defined on the referenced root node.\n [\"while\", \"until\"].forEach((attributeName) => {\n if (typeof definition[attributeName] !== \"undefined\") {\n throw new Error(\n `guards should not be defined for branch nodes but guard '${attributeName}' was defined for branch node at depth '${depth}'`\n );\n }\n });\n\n // It is invalid to define callback attributes for a branch node as they should be defined on the referenced root node.\n [\"entry\", \"exit\", \"step\"].forEach((attributeName) => {\n if (typeof definition[attributeName] !== \"undefined\") {\n throw new Error(\n `callbacks should not be defined for branch nodes but callback '${attributeName}' was defined for branch node at depth '${depth}'`\n );\n }\n });\n}\n\n/**\n * Validate an object that we expect to be a action node definition.\n * @param definition An object that we expect to be a action node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateActionNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"action\") {\n throw new Error(`expected node type of 'action' for action node at depth '${depth}'`);\n }\n\n // The 'call' property must be defined for a action node definition.\n if (typeof definition.call !== \"string\" || definition.call.length === 0) {\n throw new Error(`expected non-empty string for 'call' property of action node at depth '${depth}'`);\n }\n\n // If any action function arguments have been defined then they must have been defined in an array.\n if (typeof definition.args !== \"undefined\" && !Array.isArray(definition.args)) {\n throw new Error(`expected array for 'args' property if defined for action node at depth '${depth}'`);\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n}\n\n/**\n * Validate an object that we expect to be a condition node definition.\n * @param definition An object that we expect to be a condition node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateConditionNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"condition\") {\n throw new Error(`expected node type of 'condition' for condition node at depth '${depth}'`);\n }\n\n // The 'call' property must be defined for a condition node definition.\n if (typeof definition.call !== \"string\" || definition.call.length === 0) {\n throw new Error(`expected non-empty string for 'call' property of condition node at depth '${depth}'`);\n }\n\n // If any condition function arguments have been defined then they must have been defined in an array.\n if (typeof definition.args !== \"undefined\" && !Array.isArray(definition.args)) {\n throw new Error(`expected array for 'args' property if defined for condition node at depth '${depth}'`);\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n}\n\n/**\n * Validate an object that we expect to be a wait node definition.\n * @param definition An object that we expect to be a wait node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateWaitNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"wait\") {\n throw new Error(`expected node type of 'wait' for wait node at depth '${depth}'`);\n }\n\n // Check whether a 'duration' property has been defined, it may not have been if this node is to wait indefinitely.\n if (typeof definition.duration !== \"undefined\") {\n if (Array.isArray(definition.duration)) {\n // Check whether any elements of the array are not integer values.\n const containsNonInteger = !!definition.duration.filter((value: unknown) => !isInteger(value)).length;\n\n // If the 'duration' property is an array then it MUST contain two integer values.\n if (definition.duration.length !== 2 || containsNonInteger) {\n throw new Error(\n `expected array containing two integer values for 'duration' property if defined for wait node at depth '${depth}'`\n );\n }\n\n // A wait node must have a positive min and max duration value if they are defined.\n if (definition.duration[0] < 0 || definition.duration[1] < 0) {\n throw new Error(\n `expected positive minimum and maximum duration for 'duration' property if defined for wait node at depth '${depth}'`\n );\n }\n\n // A wait node must not have a minimum duration value that exceeds the maximum duration value.\n if (definition.duration[0] > definition.duration[1]) {\n throw new Error(\n `expected minimum duration value that does not exceed the maximum duration value for 'duration' property if defined for wait node at depth '${depth}'`\n );\n }\n } else if (isInteger(definition.duration)) {\n // A wait node must have a positive duration value if defined.\n if (definition.duration < 0) {\n throw new Error(\n `expected positive duration value for 'duration' property if defined for wait node at depth '${depth}'`\n );\n }\n } else {\n throw new Error(\n `expected integer value or array containing two integer values for 'duration' property if defined for wait node at depth '${depth}'`\n );\n }\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n}\n\n/**\n * Validate an object that we expect to be a sequence node definition.\n * @param definition An object that we expect to be a sequence node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateSequenceNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"sequence\") {\n throw new Error(`expected node type of 'sequence' for sequence node at depth '${depth}'`);\n }\n\n // A sequence node is a composite node, so must have a children nodes array defined.\n if (!Array.isArray(definition.children) || definition.children.length === 0) {\n throw new Error(`expected non-empty 'children' array to be defined for sequence node at depth '${depth}'`);\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n\n // Validate the child nodes of this composite node.\n definition.children.forEach((child: any) => validateNode(child, depth + 1));\n}\n\n/**\n * Validate an object that we expect to be a selector node definition.\n * @param definition An object that we expect to be a selector node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateSelectorNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"selector\") {\n throw new Error(`expected node type of 'selector' for selector node at depth '${depth}'`);\n }\n\n // A selector node is a composite node, so must have a children nodes array defined.\n if (!Array.isArray(definition.children) || definition.children.length === 0) {\n throw new Error(`expected non-empty 'children' array to be defined for selector node at depth '${depth}'`);\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n\n // Validate the child nodes of this composite node.\n definition.children.forEach((child: any) => validateNode(child, depth + 1));\n}\n\n/**\n * Validate an object that we expect to be a parallel node definition.\n * @param definition An object that we expect to be a parallel node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateParallelNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"parallel\") {\n throw new Error(`expected node type of 'parallel' for parallel node at depth '${depth}'`);\n }\n\n // A parallel node is a composite node, so must have a children nodes array defined.\n if (!Array.isArray(definition.children) || definition.children.length === 0) {\n throw new Error(`expected non-empty 'children' array to be defined for parallel node at depth '${depth}'`);\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n\n // Validate the child nodes of this composite node.\n definition.children.forEach((child: any) => validateNode(child, depth + 1));\n}\n\n/**\n * Validate an object that we expect to be a lotto node definition.\n * @param definition An object that we expect to be a lotto node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateLottoNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"lotto\") {\n throw new Error(`expected node type of 'lotto' for lotto node at depth '${depth}'`);\n }\n\n // A lotto node is a composite node, so must have a children nodes array defined.\n if (!Array.isArray(definition.children) || definition.children.length === 0) {\n throw new Error(`expected non-empty 'children' array to be defined for lotto node at depth '${depth}'`);\n }\n\n // Check whether a 'weights' property has been defined, if it has we expect it to be an array of weights.\n if (typeof definition.weights !== \"undefined\") {\n // Check that the weights property is an array of positive integers with an element for each child node element.\n if (\n !Array.isArray(definition.weights) ||\n definition.weights.length !== definition.children.length ||\n definition.weights.filter((value: unknown) => !isInteger(value)).length ||\n definition.weights.filter((value: number) => value < 0).length\n ) {\n throw new Error(\n `expected an array of positive integer weight values with a length matching the number of child nodes for 'weights' property if defined for lotto node at depth '${depth}'`\n );\n }\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n\n // Validate the child nodes of this composite node.\n definition.children.forEach((child: any) => validateNode(child, depth + 1));\n}\n\n/**\n * A helper function to create a failure validation result with the given error message.\n * @param errorMessage The validation failure error message.\n * @returns A failure validation result with the given error message.\n */\nfunction createValidationFailureResult(errorMessage: string): DefinitionValidationResult {\n return { succeeded: false, errorMessage };\n}\n", "import { ActionResult, Agent, GlobalFunction } from \"./Agent\";\nimport { RootNodeDefinition } from \"./BehaviourTreeDefinition\";\n\nexport type InvokerFunction = (args: any[]) => ActionResult;\n\n/**\n * A singleton used to store and lookup registered functions and subtrees.\n */\nexport default class Lookup {\n /**\n * The object holding any registered functions keyed on function name.\n */\n private static functionTable: { [key: string]: GlobalFunction } = {};\n /**\n * The object holding any registered subtree root node definitions keyed on tree name.\n */\n private static subtreeTable: { [key: string]: RootNodeDefinition } = {};\n\n /**\n * Gets the function with the specified name.\n * @param name The name of the function.\n * @returns The function with the specified name.\n */\n public static getFunc(name: string): GlobalFunction {\n return this.functionTable[name];\n }\n\n /**\n * Sets the function with the specified name for later lookup.\n * @param name The name of the function.\n * @param func The function.\n */\n public static setFunc(name: string, func: GlobalFunction): void {\n this.functionTable[name] = func;\n }\n\n /**\n * Gets the function invoker for the specified agent and function name.\n * If a function with the specified name exists on the agent object then it will\n * be returned, otherwise we will then check the registered functions for a match.\n * @param agent The agent instance that this behaviour tree is modelling behaviour for.\n * @param name The function name.\n * @returns The function invoker for the specified agent and function name.\n */\n static getFuncInvoker(agent: Agent, name: string): InvokerFunction | null {\n // Check whether the agent contains the specified function.\n const foundOnAgent = agent[name];\n if (foundOnAgent && typeof foundOnAgent === \"function\") {\n return (args: any[]): boolean | ActionResult => foundOnAgent.apply(agent, args);\n }\n\n // The agent does not contain the specified function but it may have been registered at some point.\n if (this.functionTable[name] && typeof this.functionTable[name] === \"function\") {\n return (args: any[]) => this.functionTable[name](agent, ...args.map((arg) => arg.value));\n }\n\n // We have no function to invoke.\n return null;\n }\n\n /**\n * Gets all registered subtree root node definitions.\n */\n static getSubtrees(): { [key: string]: RootNodeDefinition } {\n return this.subtreeTable;\n }\n\n /**\n * Sets the subtree with the specified name for later lookup.\n * @param name The name of the subtree.\n * @param subtree The subtree.\n */\n static setSubtree(name: string, subtree: RootNodeDefinition) {\n this.subtreeTable[name] = subtree;\n }\n\n /**\n * Removes the registered function or subtree with the specified name.\n * @param name The name of the registered function or subtree.\n */\n static remove(name: string) {\n delete this.functionTable[name];\n delete this.subtreeTable[name];\n }\n\n /**\n * Remove all registered functions and subtrees.\n */\n static empty() {\n this.functionTable = {};\n this.subtreeTable = {};\n }\n}\n", "import Node from \"../../nodes/Node\";\n\n/**\n * An exception thrown when evaluating node guard path conditions and a conditions fails.\n */\nexport default class GuardUnsatisifedException extends Error {\n /**\n * @param source The node at which a guard condition failed.\n */\n constructor(private source: Node) {\n super(\"A guard path condition has failed\");\n }\n\n /**\n * Gets whether the specified node is the node at which a guard condition failed.\n * @param node The node to check against the source node.\n * @returns Whether the specified node is the node at which a guard condition failed.\n */\n isSourceNode = (node: Node) => node === this.source;\n}\n", "import { Agent } from \"../../Agent\";\nimport Guard from \"./Guard\";\nimport Node from \"../../nodes/Node\";\nimport GuardUnsatisifedException from \"./GuardUnsatisifedException\";\n\nexport type GuardPathPart = {\n node: Node;\n guards: Guard[];\n};\n\n/**\n * Represents a path of node guards along a root-to-leaf tree path.\n */\nexport default class GuardPath {\n /**\n * @param nodes An array of objects defining a node instance -> guard link, ordered by node depth.\n */\n constructor(private nodes: GuardPathPart[]) {}\n\n /**\n * Evaluate guard conditions for all guards in the tree path, moving outwards from the root.\n * @param agent The agent, required for guard evaluation.\n * @returns An evaluation results object.\n */\n evaluate = (agent: Agent) => {\n // We need to evaluate guard conditions for nodes up the tree, moving outwards from the root.\n for (const details of this.nodes) {\n // There can be multiple guards per node.\n for (const guard of details.guards) {\n // Check whether the guard condition passes, and throw an exception if not.\n if (!guard.isSatisfied(agent)) {\n throw new GuardUnsatisifedException(details.node);\n }\n }\n }\n };\n}\n", "import { BehaviourTreeOptions } from \"../BehaviourTreeOptions\";\nimport State, { AnyState } from \"../State\";\nimport { Agent } from \"../Agent\";\nimport Leaf from \"./leaf/Leaf\";\nimport Attribute from \"../attributes/Attribute\";\nimport Entry from \"../attributes/callbacks/Entry\";\nimport Exit from \"../attributes/callbacks/Exit\";\nimport Step from \"../attributes/callbacks/Step\";\nimport Guard from \"../attributes/guards/Guard\";\nimport GuardPath from \"../attributes/guards/GuardPath\";\nimport GuardUnsatisifedException from \"../attributes/guards/GuardUnsatisifedException\";\n\n/**\n * A base node.\n */\nexport default abstract class Node {\n /**\n * The node uid.\n */\n private readonly uid: string = createNodeUid();\n /**\n * The node state.\n */\n private state: AnyState = State.READY;\n /**\n * The guard path to evaluate as part of a node update.\n */\n private guardPath: GuardPath | undefined;\n\n /**\n * @param type The node type.\n * @param attributes The node attributes.\n * @param args The node argument definitions.\n */\n constructor(private type: string, private attributes: Attribute[], private args: any[]) {}\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected abstract onUpdate(agent: Agent, options: BehaviourTreeOptions): void;\n\n /**\n * Gets the name of the node.\n */\n public abstract getName(): string;\n\n /**\n * Gets whether this node is a leaf node.\n */\n public abstract isLeafNode: () => this is Leaf;\n\n /**\n * Gets/Sets the state of the node.\n */\n getState = (): AnyState => this.state;\n setState = (value: AnyState): void => {\n this.state = value;\n };\n\n /**\n * Gets the unique id of the node.\n */\n getUid = () => this.uid;\n\n /**\n * Gets the type of the node.\n */\n getType = () => this.type;\n\n /**\n * Gets the node attributes.\n */\n getAttributes = () => this.attributes;\n\n /**\n * Gets the node arguments.\n */\n getArguments = () => this.args;\n\n /**\n * Gets the node attribute with the specified type, or null if it does not exist.\n */\n getAttribute(type: \"entry\" | \"ENTRY\"): Entry;\n getAttribute(type: \"exit\" | \"EXIT\"): Exit;\n getAttribute(type: \"step\" | \"STEP\"): Step;\n getAttribute(type: string): Attribute {\n return (\n this.getAttributes().filter((decorator) => decorator.type.toUpperCase() === type.toUpperCase())[0] || null\n );\n }\n\n /**\n * Gets the node attributes.\n */\n getGuardAttributes = (): Guard[] => this.getAttributes().filter((decorator) => decorator.isGuard()) as Guard[];\n\n /**\n * Sets the guard path to evaluate as part of a node update.\n */\n setGuardPath = (value: GuardPath) => (this.guardPath = value);\n\n /**\n * Gets whether a guard path is assigned to this node.\n */\n hasGuardPath = () => !!this.guardPath;\n\n /**\n * Gets whether this node is in the specified state.\n * @param value The value to compare to the node state.\n */\n public is(value: AnyState): boolean {\n return this.state === value;\n }\n\n /**\n * Reset the state of the node.\n */\n public reset(): void {\n this.setState(State.READY);\n }\n\n /**\n * Abort the running of this node.\n * @param agent The agent.\n */\n public abort(agent: Agent): void {\n // There is nothing to do if this node is not in the running state.\n if (!this.is(State.RUNNING)) {\n return;\n }\n\n // Reset the state of this node.\n this.reset();\n\n this.getAttribute(\"exit\")?.callAgentFunction(agent, false, true);\n }\n\n /**\n * Update the node.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n * @returns The result of the update.\n */\n public update(agent: Agent, options: BehaviourTreeOptions): void {\n // If this node is already in a 'SUCCEEDED' or 'FAILED' state then there is nothing to do.\n if (this.is(State.SUCCEEDED) || this.is(State.FAILED)) {\n return;\n }\n\n try {\n // Evaluate all of the guard path conditions for the current tree path.\n this.guardPath!.evaluate(agent);\n\n // If this node is in the READY state then call the ENTRY for this node if it exists.\n if (this.is(State.READY)) {\n this.getAttribute(\"entry\")?.callAgentFunction(agent);\n }\n\n this.getAttribute(\"step\")?.callAgentFunction(agent);\n\n // Do the actual update.\n this.onUpdate(agent, options);\n\n // If this node is now in a 'SUCCEEDED' or 'FAILED' state then call the EXIT for this node if it exists.\n if (this.is(State.SUCCEEDED) || this.is(State.FAILED)) {\n this.getAttribute(\"exit\")?.callAgentFunction(agent, this.is(State.SUCCEEDED), false);\n }\n } catch (error) {\n // If the error is a GuardUnsatisfiedException then we need to determine if this node is the source.\n if (error instanceof GuardUnsatisifedException && error.isSourceNode(this)) {\n // Abort the current node.\n this.abort(agent);\n\n // Any node that is the source of an abort will be a failed node.\n this.setState(State.FAILED);\n } else {\n throw error;\n }\n }\n }\n}\n\n/**\n * Create a randomly generated node uid.\n * @returns A randomly generated node uid.\n */\nfunction createNodeUid(): string {\n var S4 = function () {\n return (((1 + Math.random()) * 0x10000) | 0).toString(16).substring(1);\n };\n return S4() + S4() + \"-\" + S4() + \"-\" + S4() + \"-\" + S4() + \"-\" + S4() + S4() + S4();\n}\n", "import Node from \"../Node\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\n\n/**\n * A composite node that wraps child nodes.\n */\nexport default abstract class Composite extends Node {\n /**\n * @param type The node type.\n * @param attributes The node attributes.\n * @param children The child nodes.\n */\n constructor(type: string, attributes: Attribute[], protected children: Node[]) {\n super(type, attributes, []);\n }\n\n /**\n * Gets whether this node is a leaf node.\n */\n isLeafNode = () => false;\n\n /**\n * Gets the children of this node.\n */\n getChildren = () => this.children;\n\n /**\n * Reset the state of the node.\n */\n reset = () => {\n // Reset the state of this node.\n this.setState(State.READY);\n\n // Reset the state of any child nodes.\n this.getChildren().forEach((child) => child.reset());\n };\n\n /**\n * Abort the running of this node.\n * @param agent The agent.\n */\n abort = (agent: Agent) => {\n // There is nothing to do if this node is not in the running state.\n if (!this.is(State.RUNNING)) {\n return;\n }\n\n // Abort any child nodes.\n this.getChildren().forEach((child) => child.abort(agent));\n\n // Reset the state of this node.\n this.reset();\n\n this.getAttribute(\"exit\")?.callAgentFunction(agent, false, true);\n };\n}\n", "import Composite from \"./Composite\";\nimport State from \"../../State\";\nimport Node from \"../Node\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A PARALLEL node.\n * The child nodes are executed concurrently until one fails or all succeed.\n */\nexport default class Parallel extends Composite {\n /**\n * @param attributes The node attributes.\n * @param children The child nodes.\n */\n constructor(attributes: Attribute[], children: Node[]) {\n super(\"parallel\", attributes, children);\n }\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // Keep a count of the number of succeeded child nodes.\n let succeededCount = 0;\n\n let hasChildFailed = false;\n\n // Iterate over all of the children of this node.\n for (const child of this.children) {\n // If the child has never been updated or is running then we will need to update it now.\n if (child.getState() === State.READY || child.getState() === State.RUNNING) {\n // Update the child of this node.\n child.update(agent, options);\n }\n\n // If the current child has a state of 'SUCCEEDED' then we should move on to the next child.\n if (child.getState() === State.SUCCEEDED) {\n // The child node has succeeded, keep track of this to determine if all children have.\n succeededCount++;\n\n // The child node succeeded, but we have not finished checking every child node yet.\n continue;\n }\n\n // If the current child has a state of 'FAILED' then this node is also a 'FAILED' node.\n if (child.getState() === State.FAILED) {\n hasChildFailed = true;\n\n // There is no need to check the rest of the children.\n break;\n }\n\n // The node should be in the 'RUNNING' state.\n if (child.getState() !== State.RUNNING) {\n // The child node was not in an expected state.\n throw new Error(\"child node was not in an expected state.\");\n }\n }\n\n if (hasChildFailed) {\n // This node is a 'FAILED' node.\n this.setState(State.FAILED);\n\n // Abort every running child.\n for (const child of this.children) {\n if (child.getState() === State.RUNNING) {\n child.abort(agent);\n }\n }\n } else {\n // If all children have succeeded then this node has also succeeded, otherwise it is still running.\n this.setState(succeededCount === this.children.length ? State.SUCCEEDED : State.RUNNING);\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => \"PARALLEL\";\n}\n", "import Composite from \"./Composite\";\nimport Node from \"../Node\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A SELECTOR node.\n * The child nodes are executed in sequence until one succeeds or all fail.\n */\nexport default class Selector extends Composite {\n /**\n * @param attributes The node attributes.\n * @param children The child nodes.\n */\n constructor(attributes: Attribute[], protected children: Node[]) {\n super(\"selector\", attributes, children);\n }\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // Iterate over all of the children of this node.\n for (const child of this.children) {\n // If the child has never been updated or is running then we will need to update it now.\n if (child.getState() === State.READY || child.getState() === State.RUNNING) {\n // Update the child of this node.\n child.update(agent, options);\n }\n\n // If the current child has a state of 'SUCCEEDED' then this node is also a 'SUCCEEDED' node.\n if (child.getState() === State.SUCCEEDED) {\n // This node is a 'SUCCEEDED' node.\n this.setState(State.SUCCEEDED);\n\n // There is no need to check the rest of the selector nodes.\n return;\n }\n\n // If the current child has a state of 'FAILED' then we should move on to the next child.\n if (child.getState() === State.FAILED) {\n // Find out if the current child is the last one in the selector.\n // If it is then this sequence node has also failed.\n if (this.children.indexOf(child) === this.children.length - 1) {\n // This node is a 'FAILED' node.\n this.setState(State.FAILED);\n\n // There is no need to check the rest of the selector as we have completed it.\n return;\n } else {\n // The child node failed, try the next one.\n continue;\n }\n }\n\n // The node should be in the 'RUNNING' state.\n if (child.getState() === State.RUNNING) {\n // This node is a 'RUNNING' node.\n this.setState(State.RUNNING);\n\n // There is no need to check the rest of the selector as the current child is still running.\n return;\n }\n\n // The child node was not in an expected state.\n throw new Error(\"child node was not in an expected state.\");\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => \"SELECTOR\";\n}\n", "import Composite from \"./Composite\";\nimport Node from \"../Node\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A SEQUENCE node.\n * The child nodes are executed in sequence until one fails or all succeed.\n */\nexport default class Sequence extends Composite {\n /**\n * @param attributes The node attributes.\n * @param children The child nodes.\n */\n constructor(attributes: Attribute[], protected children: Node[]) {\n super(\"sequence\", attributes, children);\n }\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // Iterate over all of the children of this node.\n for (const child of this.children) {\n // If the child has never been updated or is running then we will need to update it now.\n if (child.getState() === State.READY || child.getState() === State.RUNNING) {\n // Update the child of this node.\n child.update(agent, options);\n }\n\n // If the current child has a state of 'SUCCEEDED' then we should move on to the next child.\n if (child.getState() === State.SUCCEEDED) {\n // Find out if the current child is the last one in the sequence.\n // If it is then this sequence node has also succeeded.\n if (this.children.indexOf(child) === this.children.length - 1) {\n // This node is a 'SUCCEEDED' node.\n this.setState(State.SUCCEEDED);\n\n // There is no need to check the rest of the sequence as we have completed it.\n return;\n } else {\n // The child node succeeded, but we have not finished the sequence yet.\n continue;\n }\n }\n\n // If the current child has a state of 'FAILED' then this node is also a 'FAILED' node.\n if (child.getState() === State.FAILED) {\n // This node is a 'FAILED' node.\n this.setState(State.FAILED);\n\n // There is no need to check the rest of the sequence.\n return;\n }\n\n // The node should be in the 'RUNNING' state.\n if (child.getState() === State.RUNNING) {\n // This node is a 'RUNNING' node.\n this.setState(State.RUNNING);\n\n // There is no need to check the rest of the sequence as the current child is still running.\n return;\n }\n\n // The child node was not in an expected state.\n throw new Error(\"child node was not in an expected state.\");\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => \"SEQUENCE\";\n}\n", "import createLotto from \"lotto-draw\";\n\nimport Node from \"../Node\";\nimport Composite from \"./Composite\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A LOTTO node.\n * A winning child is picked on the initial update of this node, based on ticket weighting.\n * The state of this node will match the state of the winning child.\n */\nexport default class Lotto extends Composite {\n /**\n * @param attributes The node attributes.\n * @param weights The child node weights.\n * @param children The child nodes.\n */\n constructor(attributes: Attribute[], private weights: number[] | undefined, children: Node[]) {\n super(\"lotto\", attributes, children);\n }\n\n /**\n * The child node selected to be the active one.\n */\n private selectedChild: Node | undefined;\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // If this node is in the READY state then we need to pick a winning child node.\n if (this.is(State.READY)) {\n // Create a lotto draw with which to randomly pick a child node to become the active one.\n const lottoDraw = createLotto({\n // Hook up the optional 'random' behaviour tree function option to the one used by 'lotto-draw'.\n random: options.random,\n // Pass in each child node as a participant in the lotto draw with their respective ticket count.\n participants: this.children.map((child, index) => [child, this.weights?.[index] || 1])\n });\n\n // Randomly pick a child based on ticket weighting, this will become the active child for this composite node.\n this.selectedChild = lottoDraw.draw() || undefined;\n }\n\n // If something went wrong and we don't have an active child then we should throw an error.\n if (!this.selectedChild) {\n throw new Error(\"failed to update lotto node as it has no active child\");\n }\n\n // If the selected child has never been updated or is running then we will need to update it now.\n if (this.selectedChild.getState() === State.READY || this.selectedChild.getState() === State.RUNNING) {\n this.selectedChild.update(agent, options);\n }\n\n // The state of the lotto node is the state of its selected child.\n this.setState(this.selectedChild.getState());\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => (this.weights ? `LOTTO [${this.weights.join(\",\")}]` : \"LOTTO\");\n}\n", "import Node from \"../Node\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\n\n/**\n * A decorator node that wraps a single child node.\n */\nexport default abstract class Decorator extends Node {\n /**\n * @param type The node type.\n * @param attributes The node attributes.\n * @param child The child node.\n */\n constructor(type: string, attributes: Attribute[], protected child: Node) {\n super(type, attributes, []);\n }\n\n /**\n * Gets whether this node is a leaf node.\n */\n isLeafNode = () => false;\n\n /**\n * Gets the children of this node.\n */\n getChildren = () => [this.child];\n\n /**\n * Reset the state of the node.\n */\n reset = () => {\n // Reset the state of this node.\n this.setState(State.READY);\n\n // Reset the state of the child node.\n this.child.reset();\n };\n\n /**\n * Abort the running of this node.\n * @param agent The agent.\n */\n abort = (agent: Agent) => {\n // There is nothing to do if this node is not in the running state.\n if (!this.is(State.RUNNING)) {\n return;\n }\n\n // Abort the child node.\n this.child.abort(agent);\n\n // Reset the state of this node.\n this.reset();\n\n this.getAttribute(\"exit\")?.callAgentFunction(agent, false, true);\n };\n}\n", "import Node from \"../Node\";\nimport Decorator from \"./Decorator\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A Fail node.\n * This node wraps a single child and will always move to the 'FAILED' state when the child moves to a 'SUCCEEDED' or 'FAILED' state.\n */\nexport default class Fail extends Decorator {\n /**\n * @param attributes The node attributes.\n * @param child The child node.\n */\n constructor(attributes: Attribute[], child: Node) {\n super(\"fail\", attributes, child);\n }\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // If the child has never been updated or is running then we will need to update it now.\n if (this.child.getState() === State.READY || this.child.getState() === State.RUNNING) {\n this.child.update(agent, options);\n }\n\n // The state of this node will depend in the state of its child.\n switch (this.child.getState()) {\n case State.RUNNING:\n this.setState(State.RUNNING);\n break;\n\n case State.SUCCEEDED:\n case State.FAILED:\n this.setState(State.FAILED);\n break;\n\n default:\n this.setState(State.READY);\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => \"FAIL\";\n}\n", "import Decorator from \"./Decorator\";\nimport State from \"../../State\";\nimport Node from \"../Node\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A Flip node.\n * This node wraps a single child and will flip the state of the child state.\n */\nexport default class Flip extends Decorator {\n /**\n * @param attributes The node attributes.\n * @param child The child node.\n */\n constructor(attributes: Attribute[], child: Node) {\n super(\"flip\", attributes, child);\n }\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // If the child has never been updated or is running then we will need to update it now.\n if (this.child.getState() === State.READY || this.child.getState() === State.RUNNING) {\n this.child.update(agent, options);\n }\n\n // The state of this node will depend in the state of its child.\n switch (this.child.getState()) {\n case State.RUNNING:\n this.setState(State.RUNNING);\n break;\n\n case State.SUCCEEDED:\n this.setState(State.FAILED);\n break;\n\n case State.FAILED:\n this.setState(State.SUCCEEDED);\n break;\n\n default:\n this.setState(State.READY);\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => \"FLIP\";\n}\n", "import Node from \"../Node\";\nimport Decorator from \"./Decorator\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A REPEAT node.\n * The node has a single child which can have:\n * -- A number of iterations for which to repeat the child node.\n * -- An infinite repeat loop if neither an iteration count or a condition function is defined.\n * The REPEAT node will stop and have a 'FAILED' state if its child is ever in a 'FAILED' state after an update.\n * The REPEAT node will attempt to move on to the next iteration if its child is ever in a 'SUCCEEDED' state.\n */\nexport default class Repeat extends Decorator {\n /**\n * @param attributes The node attributes.\n * @param iterations The number of iterations to repeat the child node.\n * @param iterationsMin The minimum possible number of iterations to repeat the child node.\n * @param iterationsMax The maximum possible number of iterations to repeat the child node.\n * @param child The child node.\n */\n constructor(\n attributes: Attribute[],\n private iterations: number | null,\n private iterationsMin: number | null,\n private iterationsMax: number | null,\n child: Node\n ) {\n super(\"repeat\", attributes, child);\n }\n\n /**\n * The number of target iterations to make.\n */\n private targetIterationCount: number | null = null;\n\n /**\n * The current iteration count.\n */\n private currentIterationCount: number = 0;\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // If this node is in the READY state then we need to reset the child and the target iteration count.\n if (this.is(State.READY)) {\n // Reset the child node.\n this.child.reset();\n\n // Reset the current iteration count.\n this.currentIterationCount = 0;\n\n // Set the target iteration count.\n this.setTargetIterationCount(options);\n }\n\n // Do a check to see if we can iterate. If we can then this node will move into the 'RUNNING' state.\n // If we cannot iterate then we have hit our target iteration count, which means that the node has succeeded.\n if (this.canIterate()) {\n // This node is in the running state and can do its initial iteration.\n this.setState(State.RUNNING);\n\n // We may have already completed an iteration, meaning that the child node will be in the SUCCEEDED state.\n // If this is the case then we will have to reset the child node now.\n if (this.child.getState() === State.SUCCEEDED) {\n this.child.reset();\n }\n\n // Update the child of this node.\n this.child.update(agent, options);\n\n // If the child moved into the FAILED state when we updated it then there is nothing left to do and this node has also failed.\n // If it has moved into the SUCCEEDED state then we have completed the current iteration.\n if (this.child.getState() === State.FAILED) {\n // The child has failed, meaning that this node has failed.\n this.setState(State.FAILED);\n\n return;\n } else if (this.child.getState() === State.SUCCEEDED) {\n // We have completed an iteration.\n this.currentIterationCount += 1;\n }\n } else {\n // This node is in the 'SUCCEEDED' state as we cannot iterate any more.\n this.setState(State.SUCCEEDED);\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => {\n if (this.iterations !== null) {\n return `REPEAT ${this.iterations}x`;\n } else if (this.iterationsMin !== null && this.iterationsMax !== null) {\n return `REPEAT ${this.iterationsMin}x-${this.iterationsMax}x`;\n } else {\n return \"REPEAT\";\n }\n };\n\n /**\n * Reset the state of the node.\n */\n reset = () => {\n // Reset the state of this node.\n this.setState(State.READY);\n\n // Reset the current iteration count.\n this.currentIterationCount = 0;\n\n // Reset the child node.\n this.child.reset();\n };\n\n /**\n * Gets whether an iteration can be made.\n * @returns Whether an iteration can be made.\n */\n private canIterate = () => {\n if (this.targetIterationCount !== null) {\n // We can iterate as long as we have not reached our target iteration count.\n return this.currentIterationCount < this.targetIterationCount;\n }\n\n // If neither an iteration count or a condition function were defined then we can iterate indefinitely.\n return true;\n };\n\n /**\n * Sets the target iteration count.\n * @param options The behaviour tree options object.\n */\n private setTargetIterationCount = (options: BehaviourTreeOptions) => {\n // Are we dealing with an explicit iteration count or will we be randomly picking a iteration count between the min and max iteration count.\n if (this.iterations !== null) {\n this.targetIterationCount = this.iterations;\n } else if (this.iterationsMin !== null && this.iterationsMax !== null) {\n // We will be picking a random iteration count between a min and max iteration count, if the optional 'random'\n // behaviour tree function option is defined then we will be using that, otherwise we will fall back to using Math.random.\n const random = typeof options.random === \"function\" ? options.random : Math.random;\n\n // Pick a random iteration count between a min and max iteration count.\n this.targetIterationCount = Math.floor(\n random() * (this.iterationsMax - this.iterationsMin + 1) + this.iterationsMin\n );\n } else {\n this.targetIterationCount = null;\n }\n };\n}\n", "import Node from \"../Node\";\nimport Decorator from \"./Decorator\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A RETRY node.\n * The node has a single child which can have:\n * -- A number of iterations for which to repeat the child node.\n * -- An infinite repeat loop if neither an iteration count or a condition function is defined.\n * The RETRY node will stop and have a 'SUCCEEDED' state if its child is ever in a 'SUCCEEDED' state after an update.\n * The RETRY node will attempt to move on to the next iteration if its child is ever in a 'FAILED' state.\n */\nexport default class Retry extends Decorator {\n /**\n * @param attributes The node attributes.\n * @param attempts The number of attempts to retry the child node.\n * @param attemptsMin The minimum possible number of attempts to retry the child node.\n * @param attemptsMax The maximum possible number of attempts to retry the child node.\n * @param child The child node.\n */\n constructor(\n attributes: Attribute[],\n private attempts: number | null,\n private attemptsMin: number | null,\n private attemptsMax: number | null,\n child: Node\n ) {\n super(\"retry\", attributes, child);\n }\n\n /**\n * The number of target attempts to make.\n */\n private targetAttemptCount: number | null = null;\n\n /**\n * The current attempt count.\n */\n private currentAttemptCount: number = 0;\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // If this node is in the READY state then we need to reset the child and the target attempt count.\n if (this.is(State.READY)) {\n // Reset the child node.\n this.child.reset();\n\n // Reset the current attempt count.\n this.currentAttemptCount = 0;\n\n // Set the target attempt count.\n this.setTargetAttemptCount(options);\n }\n\n // Do a check to see if we can attempt. If we can then this node will move into the 'RUNNING' state.\n // If we cannot attempt then we have hit our target attempt count, which means that the node has succeeded.\n if (this.canAttempt()) {\n // This node is in the running state and can do its initial attempt.\n this.setState(State.RUNNING);\n\n // We may have already completed an attempt, meaning that the child node will be in the FAILED state.\n // If this is the case then we will have to reset the child node now.\n if (this.child.getState() === State.FAILED) {\n this.child.reset();\n }\n\n // Update the child of this node.\n this.child.update(agent, options);\n\n // If the child moved into the SUCCEEDED state when we updated it then there is nothing left to do and this node has also succeeded.\n // If it has moved into the FAILED state then we have completed the current attempt.\n if (this.child.getState() === State.SUCCEEDED) {\n // The child has succeeded, meaning that this node has succeeded.\n this.setState(State.SUCCEEDED);\n\n return;\n } else if (this.child.getState() === State.FAILED) {\n // We have completed an attempt.\n this.currentAttemptCount += 1;\n }\n } else {\n // This node is in the 'FAILED' state as we cannot iterate any more.\n this.setState(State.FAILED);\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => {\n if (this.attempts !== null) {\n return `RETRY ${this.attempts}x`;\n } else if (this.attemptsMin !== null && this.attemptsMax !== null) {\n return `RETRY ${this.attemptsMin}x-${this.attemptsMax}x`;\n } else {\n return \"RETRY\";\n }\n };\n\n /**\n * Reset the state of the node.\n */\n reset = () => {\n // Reset the state of this node.\n this.setState(State.READY);\n\n // Reset the current attempt count.\n this.currentAttemptCount = 0;\n\n // Reset the child node.\n this.child.reset();\n };\n\n /**\n * Gets whether an attempt can be made.\n * @returns Whether an attempt can be made.\n */\n canAttempt = () => {\n if (this.targetAttemptCount !== null) {\n // We can attempt as long as we have not reached our target attempt count.\n return this.currentAttemptCount < this.targetAttemptCount;\n }\n\n // If neither an attempt count or a condition function were defined then we can attempt indefinitely.\n return true;\n };\n\n /**\n * Sets the target attempt count.\n * @param options The behaviour tree options object.\n */\n setTargetAttemptCount = (options: BehaviourTreeOptions) => {\n // Are we dealing with an explicit attempt count or will we be randomly picking an attempt count between the min and max attempt count.\n if (this.attempts !== null) {\n this.targetAttemptCount = this.attempts;\n } else if (this.attemptsMin !== null && this.attemptsMax !== null) {\n // We will be picking a random attempt count between a min and max attempt count, if the optional 'random'\n // behaviour tree function option is defined then we will be using that, otherwise we will fall back to using Math.random.\n const random = typeof options.random === \"function\" ? options.random : Math.random;\n\n // Pick a random attempt count between a min and max attempt count.\n this.targetAttemptCount = Math.floor(\n random() * (this.attemptsMax - this.attemptsMin + 1) + this.attemptsMin\n );\n } else {\n this.targetAttemptCount = null;\n }\n };\n}\n", "import Node from \"../Node\";\nimport Decorator from \"./Decorator\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A Root node.\n * The root node will have a single child.\n */\nexport default class Root extends Decorator {\n /**\n * @param attributes The node attributes.\n * @param child The child node.\n */\n constructor(attributes: Attribute[], child: Node) {\n super(\"root\", attributes, child);\n }\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // If the child has never been updated or is running then we will need to update it now.\n if (this.child.getState() === State.READY || this.child.getState() === State.RUNNING) {\n // Update the child of this node.\n this.child.update(agent, options);\n }\n\n // The state of the root node is the state of its child.\n this.setState(this.child.getState());\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => \"ROOT\";\n}\n", "import Node from \"../Node\";\nimport Decorator from \"./Decorator\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A Succeed node.\n * This node wraps a single child and will always move to the 'SUCCEEDED' state when the child moves to a 'SUCCEEDED' or 'FAILED' state.\n */\nexport default class Succeed extends Decorator {\n /**\n * @param attributes The node attributes.\n * @param child The child node.\n */\n constructor(attributes: Attribute[], child: Node) {\n super(\"succeed\", attributes, child);\n }\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // If the child has never been updated or is running then we will need to update it now.\n if (this.child.getState() === State.READY || this.child.getState() === State.RUNNING) {\n this.child.update(agent, options);\n }\n\n // The state of this node will depend in the state of its child.\n switch (this.child.getState()) {\n case State.RUNNING:\n this.setState(State.RUNNING);\n break;\n\n case State.SUCCEEDED:\n case State.FAILED:\n this.setState(State.SUCCEEDED);\n break;\n\n default:\n this.setState(State.READY);\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => \"SUCCEED\";\n}\n", "import Node from \"../Node\";\n\n/**\n * A leaf node.\n */\nexport default abstract class Leaf extends Node {\n /**\n * Gets whether this node is a leaf node.\n */\n isLeafNode = () => true;\n}\n", "import { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\nimport State, { CompleteState } from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Leaf from \"./Leaf\";\nimport Lookup from \"../../Lookup\";\nimport Attribute from \"../../attributes/Attribute\";\n\n/**\n * An Action leaf node.\n * This represents an immediate or ongoing state of behaviour.\n */\nexport default class Action extends Leaf {\n /**\n * @param attributes The node attributes.\n * @param actionName The action name.\n * @param actionArguments The array of action argument definitions.\n */\n constructor(attributes: Attribute[], private actionName: string, private actionArguments: any[]) {\n super(\"action\", attributes, actionArguments);\n }\n\n /**\n * Whether there is a pending update promise.\n */\n private isUsingUpdatePromise = false;\n\n /**\n * The finished state result of an update promise.\n */\n private updatePromiseStateResult: CompleteState | null = null;\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // If the result of this action depends on an update promise then there is nothing to do until\n // it resolves, unless there has been a value set as a result of the update promise resolving.\n if (this.isUsingUpdatePromise) {\n // Check whether the update promise has resolved with a state value.\n if (this.updatePromiseStateResult) {\n // Set the state of this node to match the state returned by the promise.\n this.setState(this.updatePromiseStateResult);\n }\n\n return;\n }\n\n // Attempt to get the invoker for the action function.\n const actionFuncInvoker = Lookup.getFuncInvoker(agent, this.actionName);\n\n // The action function should be defined.\n if (actionFuncInvoker === null) {\n throw new Error(\n `cannot update action node as the action '${this.actionName}' function is not defined on the agent and has not been registered`\n );\n }\n\n // Call the action function, the result of which may be:\n // - The finished state of this action node.\n // - A promise to return a finished node state.\n // - Undefined if the node should remain in the running state.\n const updateResult = actionFuncInvoker(this.actionArguments) as CompleteState | Promise;\n\n if (updateResult instanceof Promise) {\n updateResult.then(\n (result) => {\n // If 'isUpdatePromisePending' is null then the promise was cleared as it was resolving, probably via an abort of reset.\n if (!this.isUsingUpdatePromise) {\n return;\n }\n\n // Check to make sure the result is a valid finished state.\n if (result !== State.SUCCEEDED && result !== State.FAILED) {\n throw new Error(\n \"action node promise resolved with an invalid value, expected a State.SUCCEEDED or State.FAILED value to be returned\"\n );\n }\n\n // Set pending update promise state result to be processed on next update.\n this.updatePromiseStateResult = result;\n },\n (reason) => {\n // If 'isUpdatePromisePending' is null then the promise was cleared as it was resolving, probably via an abort of reset.\n if (!this.isUsingUpdatePromise) {\n return;\n }\n\n // Just throw whatever was returned as the rejection argument.\n throw new Error(reason);\n }\n );\n\n // This node will be in the 'RUNNING' state until the update promise resolves.\n this.setState(State.RUNNING);\n\n // We are now waiting for the promise returned by the use to resolve before we know what state this node is in.\n this.isUsingUpdatePromise = true;\n } else {\n // Validate the returned value.\n this.validateUpdateResult(updateResult);\n\n // Set the state of this node, this may be undefined, which just means that the node is still in the 'RUNNING' state.\n this.setState(updateResult || State.RUNNING);\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => this.actionName;\n\n /**\n * Reset the state of the node.\n */\n reset = () => {\n // Reset the state of this node.\n this.setState(State.READY);\n\n // There is no longer an update promise that we care about.\n this.isUsingUpdatePromise = false;\n this.updatePromiseStateResult = null;\n };\n\n /**\n * Validate the result of an update function call.\n * @param result The result of an update function call.\n */\n private validateUpdateResult = (result: CompleteState | boolean) => {\n switch (result) {\n case State.SUCCEEDED:\n case State.FAILED:\n case undefined:\n return;\n default:\n throw new Error(\n `action '${this.actionName}' 'onUpdate' returned an invalid response, expected an optional State.SUCCEEDED or State.FAILED value to be returned`\n );\n }\n };\n}\n", "import { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Leaf from \"./Leaf\";\nimport Lookup from \"../../Lookup\";\nimport Attribute from \"../../attributes/Attribute\";\n\n/**\n * A Condition leaf node.\n * This will succeed or fail immediately based on an agent predicate, without moving to the 'RUNNING' state.\n */\nexport default class Condition extends Leaf {\n /**\n * @param attributes The node attributes.\n * @param conditionName The name of the condition function.\n * @param conditionArguments The array of condition argument definitions.\n */\n constructor(attributes: Attribute[], private conditionName: string, private conditionArguments: any[]) {\n super(\"condition\", attributes, conditionArguments);\n }\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // Attempt to get the invoker for the condition function.\n const conditionFuncInvoker = Lookup.getFuncInvoker(agent, this.conditionName);\n\n // The condition function should be defined.\n if (conditionFuncInvoker === null) {\n throw new Error(\n `cannot update condition node as the condition '${this.conditionName}' function is not defined on the agent and has not been registered`\n );\n }\n\n // Call the condition function to determine the state of this node.\n this.setState(!!conditionFuncInvoker(this.conditionArguments) ? State.SUCCEEDED : State.FAILED);\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => this.conditionName;\n}\n", "import Leaf from \"./Leaf\";\nimport State from \"../../State\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { Agent } from \"../../Agent\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A WAIT node.\n * The state of this node will change to SUCCEEDED after a duration of time\n */\nexport default class Wait extends Leaf {\n /**\n * @param attributes The node attributes.\n * @param duration The duration that this node will wait to succeed in milliseconds.\n * @param durationMin The minimum possible duration in milliseconds that this node will wait to succeed.\n * @param durationMax The maximum possible duration in milliseconds that this node will wait to succeed.\n */\n constructor(\n attributes: Attribute[],\n private duration: number | null,\n private durationMin: number | null,\n private durationMax: number | null\n ) {\n super(\"wait\", attributes, []);\n }\n\n /**\n * The time in milliseconds at which this node was first updated.\n */\n private initialUpdateTime: number = 0;\n\n /**\n * The total duration in milliseconds that this node will be waiting for.\n */\n private totalDuration: number | null = null;\n\n /**\n * The duration in milliseconds that this node has been waiting for.\n */\n private waitedDuration: number = 0;\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // If this node is in the READY state then we need to set the initial update time.\n if (this.is(State.READY)) {\n // Set the initial update time.\n this.initialUpdateTime = new Date().getTime();\n\n // Set the initial waited duration.\n this.waitedDuration = 0;\n\n // Are we dealing with an explicit duration or will we be randomly picking a duration between the min and max duration.\n if (this.duration !== null) {\n this.totalDuration = this.duration;\n } else if (this.durationMin !== null && this.durationMax !== null) {\n // We will be picking a random duration between a min and max duration, if the optional 'random' behaviour tree\n // function option is defined then we will be using that, otherwise we will fall back to using Math.random.\n const random = typeof options.random === \"function\" ? options.random : Math.random;\n\n // Pick a random duration between a min and max duration.\n this.totalDuration = Math.floor(\n random() * (this.durationMax - this.durationMin + 1) + this.durationMin\n );\n } else {\n this.totalDuration = null;\n }\n\n // The node is now running until we finish waiting.\n this.setState(State.RUNNING);\n }\n\n // If we have no total duration then this wait node will wait indefinitely until it is aborted.\n if (this.totalDuration === null) {\n return;\n }\n\n // If we have a 'getDeltaTime' function defined as part of our options then we will use it to figure out how long we have waited for.\n if (typeof options.getDeltaTime === \"function\") {\n // Get the delta time.\n const deltaTime = options.getDeltaTime();\n\n // Our delta time must be a valid number and cannot be NaN.\n if (typeof deltaTime !== \"number\" || isNaN(deltaTime)) {\n throw new Error(\"The delta time must be a valid number and not NaN.\");\n }\n\n // Update the amount of time that this node has been waiting for based on the delta time.\n this.waitedDuration += deltaTime * 1000;\n } else {\n // We are not using a delta time, so we will just work out hom much time has passed since the first update.\n this.waitedDuration = new Date().getTime() - this.initialUpdateTime;\n }\n\n // Have we waited long enough?\n if (this.waitedDuration >= this.totalDuration) {\n // We have finished waiting!\n this.setState(State.SUCCEEDED);\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => {\n if (this.duration !== null) {\n return `WAIT ${this.duration}ms`;\n } else if (this.durationMin !== null && this.durationMax !== null) {\n return `WAIT ${this.durationMin}ms-${this.durationMax}ms`;\n } else {\n return \"WAIT\";\n }\n };\n}\n", "import Guard from \"./guards/Guard\";\n\nexport type AttributeDetails = {\n /** The attribute type. */\n type: string;\n\n /** The attribute arguments. */\n args: any[];\n};\n\n/**\n * A base node attribute.\n */\nexport default abstract class Attribute {\n /**\n * @param type The node attribute type.\n * @param args The array of attribute arguments.\n */\n constructor(public type: string, public args: any[]) {}\n\n /**\n * Gets the attribute details.\n */\n abstract getDetails(): TAttributeDetails;\n\n /**\n * Gets whether this attribute is a guard.\n */\n abstract isGuard: () => this is Guard;\n}\n", "import { Agent } from \"../../Agent\";\nimport Attribute, { AttributeDetails } from \"../Attribute\";\n\nexport type GuardAttributeDetails = {\n /** The name of the condition function that determines whether the guard is satisfied. */\n condition: string;\n} & AttributeDetails;\n\n/**\n * A base node guard attribute.\n */\nexport default abstract class Guard extends Attribute {\n /**\n * @param type The node attribute type.\n * @param args The array of decorator argument definitions.\n * @param condition The name of the condition function that determines whether the guard is satisfied.\n */\n constructor(type: string, args: any[], private condition: string) {\n super(type, args);\n }\n\n /**\n * Gets the name of the condition function that determines whether the guard is satisfied.\n */\n getCondition = () => this.condition;\n\n /**\n * Gets whether this attribute is a guard.\n */\n isGuard = () => true;\n\n /**\n * Gets the attribute details.\n */\n getDetails(): GuardAttributeDetails {\n return {\n type: this.type,\n args: this.args,\n condition: this.getCondition()\n };\n }\n\n /**\n * Gets whether the guard is satisfied.\n * @param agent The agent.\n * @returns Whether the guard is satisfied.\n */\n abstract isSatisfied(agent: Agent): boolean;\n}\n", "import Guard from \"./Guard\";\nimport Lookup from \"../../Lookup\";\nimport { Agent } from \"../../Agent\";\n\n/**\n * A WHILE guard which is satisfied as long as the given condition remains true.\n */\nexport default class While extends Guard {\n /**\n * @param condition The name of the condition function that determines whether the guard is satisfied.\n * @param args The array of decorator argument definitions.\n */\n constructor(condition: string, args: any[]) {\n super(\"while\", args, condition);\n }\n\n /**\n * Gets whether the guard is satisfied.\n * @param agent The agent.\n * @returns Whether the guard is satisfied.\n */\n isSatisfied = (agent: Agent) => {\n // Attempt to get the invoker for the condition function.\n const conditionFuncInvoker = Lookup.getFuncInvoker(agent, this.getCondition());\n\n // The condition function should be defined.\n if (conditionFuncInvoker === null) {\n throw new Error(\n `cannot evaluate node guard as the condition '${this.getCondition()}' function is not defined on the agent and has not been registered`\n );\n }\n\n // Call the condition function to determine whether this guard is satisfied.\n return !!conditionFuncInvoker(this.args);\n };\n}\n", "import Guard from \"./Guard\";\nimport Lookup from \"../../Lookup\";\nimport { Agent } from \"../../Agent\";\n\n/**\n * An UNTIL guard which is satisfied as long as the given condition remains false.\n */\nexport default class Until extends Guard {\n /**\n * @param condition The name of the condition function that determines whether the guard is satisfied.\n * @param args The array of decorator argument definitions.\n */\n constructor(condition: string, args: any[]) {\n super(\"until\", args, condition);\n }\n\n /**\n * Gets whether the guard is satisfied.\n * @param agent The agent.\n * @returns Whether the guard is satisfied.\n */\n isSatisfied = (agent: Agent) => {\n // Attempt to get the invoker for the condition function.\n const conditionFuncInvoker = Lookup.getFuncInvoker(agent, this.getCondition());\n\n // The condition function should be defined.\n if (conditionFuncInvoker === null) {\n throw new Error(\n `cannot evaluate node guard as the condition '${this.getCondition()}' function is not defined on the agent and has not been registered`\n );\n }\n\n // Call the condition function to determine whether this guard is satisfied.\n return !!!conditionFuncInvoker(this.args);\n };\n}\n", "import { Agent } from \"../../Agent\";\nimport Attribute, { AttributeDetails } from \"../Attribute\";\n\nexport type CallbackAttributeDetails = {\n /** The name of the agent function that is called. */\n functionName: string;\n} & AttributeDetails;\n\n/**\n * A base node callback attribute.\n */\nexport default abstract class Callback extends Attribute {\n /**\n * @param type The node attribute type.\n * @param args The array of decorator argument definitions.\n * @param functionName The name of the agent function to call.\n */\n constructor(type: string, args: any[], private functionName: string) {\n super(type, args);\n }\n\n /**\n * Gets the name of the agent function to call.\n */\n getFunctionName = () => this.functionName;\n\n /**\n * Gets whether this attribute is a guard.\n */\n isGuard = () => false;\n\n /**\n * Gets the attribute details.\n */\n getDetails(): CallbackAttributeDetails {\n return {\n type: this.type,\n args: this.args,\n functionName: this.getFunctionName()\n };\n }\n\n /**\n * Attempt to call the agent function that this callback refers to.\n * @param agent The agent.\n */\n abstract callAgentFunction: (agent: Agent, isSuccess: boolean, isAborted: boolean) => void;\n}\n", "import Callback from \"./Callback\";\nimport Lookup from \"../../Lookup\";\nimport { Agent } from \"../../Agent\";\n\n/**\n * An ENTRY callback which defines an agent function to call when the associated node is updated and moves out of running state.\n */\nexport default class Entry extends Callback {\n /**\n * @param functionName The name of the agent function to call.\n * @param args The array of callback argument definitions.\n */\n constructor(functionName: string, args: any[]) {\n super(\"entry\", args, functionName);\n }\n\n /**\n * Attempt to call the agent function that this callback refers to.\n * @param agent The agent.\n */\n callAgentFunction = (agent: Agent) => {\n // Attempt to get the invoker for the callback function.\n const callbackFuncInvoker = Lookup.getFuncInvoker(agent, this.getFunctionName());\n\n // The callback function should be defined.\n if (callbackFuncInvoker === null) {\n throw new Error(\n `cannot call entry function '${this.getFunctionName()}' as is not defined on the agent and has not been registered`\n );\n }\n\n // Call the callback function.\n callbackFuncInvoker(this.args);\n };\n}\n", "import Callback from \"./Callback\";\nimport Lookup from \"../../Lookup\";\nimport { Agent } from \"../../Agent\";\n\n/**\n * A STEP callback which defines an agent function to call when the associated node is updated.\n */\nexport default class Step extends Callback {\n /**\n * @param functionName The name of the agent function to call.\n * @param args The array of callback argument definitions.\n */\n constructor(functionName: string, args: any[]) {\n super(\"step\", args, functionName);\n }\n\n /**\n * Attempt to call the agent function that this callback refers to.\n * @param agent The agent.\n */\n callAgentFunction = (agent: Agent) => {\n // Attempt to get the invoker for the callback function.\n const callbackFuncInvoker = Lookup.getFuncInvoker(agent, this.getFunctionName());\n\n // The callback function should be defined.\n if (callbackFuncInvoker === null) {\n throw new Error(\n `cannot call step function '${this.getFunctionName()}' as is not defined on the agent and has not been registered`\n );\n }\n\n // Call the callback function.\n callbackFuncInvoker(this.args);\n };\n}\n", "import Callback from \"./Callback\";\nimport Lookup from \"../../Lookup\";\nimport { Agent } from \"../../Agent\";\n\n/**\n * An EXIT callback which defines an agent function to call when the associated node is updated and moves to a finished state or is aborted.\n */\nexport default class Exit extends Callback {\n /**\n * @param functionName The name of the agent function to call.\n * @param args The array of callback argument definitions.\n */\n constructor(functionName: string, args: any[]) {\n super(\"exit\", args, functionName);\n }\n\n /**\n * Attempt to call the agent function that this callback refers to.\n * @param agent The agent.\n * @param isSuccess Whether the decorated node was left with a success state.\n * @param isAborted Whether the decorated node was aborted.\n */\n callAgentFunction = (agent: Agent, isSuccess: boolean, isAborted: boolean) => {\n // Attempt to get the invoker for the callback function.\n const callbackFuncInvoker = Lookup.getFuncInvoker(agent, this.getFunctionName());\n\n // The callback function should be defined.\n if (callbackFuncInvoker === null) {\n throw new Error(\n `cannot call exit function '${this.getFunctionName()}' as is not defined on the agent and has not been registered`\n );\n }\n\n // Call the callback function\n callbackFuncInvoker([{ value: { succeeded: isSuccess, aborted: isAborted } }, ...this.args]);\n };\n}\n", "import { AnyNodeDefinition, RootNodeDefinition } from \"./BehaviourTreeDefinition\";\nimport GuardPath, { GuardPathPart } from \"./attributes/guards/GuardPath\";\nimport { validateBranchSubtreeLinks } from \"./BehaviourTreeDefinitionValidator\";\nimport { isInteger } from \"./BehaviourTreeDefinitionUtilities\";\nimport Node from \"./nodes/Node\";\nimport Composite from \"./nodes/composite/Composite\";\nimport Decorator from \"./nodes/decorator/Decorator\";\nimport Parallel from \"./nodes/composite/Parallel\";\nimport Selector from \"./nodes/composite/Selector\";\nimport Sequence from \"./nodes/composite/Sequence\";\nimport Lotto from \"./nodes/composite/Lotto\";\nimport Fail from \"./nodes/decorator/Fail\";\nimport Flip from \"./nodes/decorator/Flip\";\nimport Repeat from \"./nodes/decorator/Repeat\";\nimport Retry from \"./nodes/decorator/Retry\";\nimport Root from \"./nodes/decorator/Root\";\nimport Succeed from \"./nodes/decorator/Succeed\";\nimport Action from \"./nodes/leaf/Action\";\nimport Condition from \"./nodes/leaf/Condition\";\nimport Wait from \"./nodes/leaf/Wait\";\nimport Lookup from \"./Lookup\";\nimport Attribute from \"./attributes/Attribute\";\nimport While from \"./attributes/guards/While\";\nimport Until from \"./attributes/guards/Until\";\nimport Entry from \"./attributes/callbacks/Entry\";\nimport Step from \"./attributes/callbacks/Step\";\nimport Exit from \"./attributes/callbacks/Exit\";\n\n/**\n * A type representing any node instance in a behaviour tree.\n */\ntype AnyNode =\n | Root\n | Action\n | Condition\n | Wait\n | Sequence\n | Selector\n | Lotto\n | Parallel\n | Repeat\n | Retry\n | Flip\n | Succeed\n | Fail;\n\n/**\n * A type defining a mapping of root node identifiers to root node definitions.\n */\ntype RootNodeDefinitionMap = { [key: string | symbol]: RootNodeDefinition };\n\n/**\n * A symbol to use as the main root key in any root node mappings.\n */\nconst MAIN_ROOT_NODE_KEY = Symbol(\"__root__\");\n\n/**\n * Build and populate the root nodes based on the provided definition, assuming that the definition has been validated.\n * @param definition The root node definitions.\n * @returns The built and populated root node definitions.\n */\nexport default function buildRootNode(definition: RootNodeDefinition[]): Root {\n // Create a mapping of root node identifers to root node definitions, including globally registered subtree root node definitions.\n const rootNodeDefinitionMap = createRootNodeDefinitionMap(definition);\n\n // Now that we have all of our root node definitons (those part of the tree definition and those globally\n // registered) we should validate the definition. This will also double-check that we dont have any circular\n // dependencies in our branch -> subtree references and that we have no broken branch -> subtree links.\n validateBranchSubtreeLinks(definition, true);\n\n // Create our populated tree of node instances, starting with our main root node.\n const rootNode = nodeFactory(rootNodeDefinitionMap[MAIN_ROOT_NODE_KEY], rootNodeDefinitionMap) as Root;\n\n // Set a guard path on every leaf of the tree to evaluate as part of each update.\n applyLeafNodeGuardPaths(rootNode);\n\n // We only need to return the main root node.\n return rootNode;\n}\n\n/**\n * A factory function which creates a node instance based on the specified definition.\n * @param definition The node definition.\n * @param rootNodeDefinitionMap The mapping of root node identifers to root node definitions, including globally registered subtree root node definitions.\n * @returns A node instance based on the specified definition.\n */\nfunction nodeFactory(definition: AnyNodeDefinition, rootNodeDefinitionMap: RootNodeDefinitionMap): AnyNode {\n // Get the attributes for the node.\n const attributes = nodeAttributesFactory(definition);\n\n // Create the node instance based on the definition type.\n switch (definition.type) {\n case \"root\":\n return new Root(attributes, nodeFactory(definition.child, rootNodeDefinitionMap));\n\n case \"repeat\":\n let iterations: number | null = null;\n let iterationsMin: number | null = null;\n let iterationsMax: number | null = null;\n\n if (Array.isArray(definition.iterations)) {\n iterationsMin = definition.iterations[0];\n iterationsMax = definition.iterations[1];\n } else if (isInteger(definition.iterations)) {\n iterations = definition.iterations!;\n }\n\n return new Repeat(\n attributes,\n iterations,\n iterationsMin,\n iterationsMax,\n nodeFactory(definition.child, rootNodeDefinitionMap)\n );\n\n case \"retry\":\n let attempts: number | null = null;\n let attemptsMin: number | null = null;\n let attemptsMax: number | null = null;\n\n if (Array.isArray(definition.attempts)) {\n attemptsMin = definition.attempts[0];\n attemptsMax = definition.attempts[1];\n } else if (isInteger(definition.attempts)) {\n attempts = definition.attempts!;\n }\n\n return new Retry(\n attributes,\n attempts,\n attemptsMin,\n attemptsMax,\n nodeFactory(definition.child, rootNodeDefinitionMap)\n );\n\n case \"flip\":\n return new Flip(attributes, nodeFactory(definition.child, rootNodeDefinitionMap));\n\n case \"succeed\":\n return new Succeed(attributes, nodeFactory(definition.child, rootNodeDefinitionMap));\n\n case \"fail\":\n return new Fail(attributes, nodeFactory(definition.child, rootNodeDefinitionMap));\n\n case \"sequence\":\n return new Sequence(\n attributes,\n definition.children.map((child) => nodeFactory(child, rootNodeDefinitionMap))\n );\n\n case \"selector\":\n return new Selector(\n attributes,\n definition.children.map((child) => nodeFactory(child, rootNodeDefinitionMap))\n );\n\n case \"parallel\":\n return new Parallel(\n attributes,\n definition.children.map((child) => nodeFactory(child, rootNodeDefinitionMap))\n );\n\n case \"lotto\":\n return new Lotto(\n attributes,\n definition.weights,\n definition.children.map((child) => nodeFactory(child, rootNodeDefinitionMap))\n );\n\n case \"branch\":\n return nodeFactory(rootNodeDefinitionMap[definition.ref].child, rootNodeDefinitionMap);\n\n case \"action\":\n return new Action(attributes, definition.call, definition.args || []);\n\n case \"condition\":\n return new Condition(attributes, definition.call, definition.args || []);\n\n case \"wait\":\n let duration: number | null = null;\n let durationMin: number | null = null;\n let durationMax: number | null = null;\n\n if (Array.isArray(definition.duration)) {\n durationMin = definition.duration[0];\n durationMax = definition.duration[1];\n } else if (isInteger(definition.duration)) {\n duration = definition.duration!;\n }\n\n return new Wait(attributes, duration, durationMin, durationMax);\n }\n}\n\n/**\n * Creates an array of node attribute instances based on the specified node definition.\n * @param definition The node definition.\n * @returns An array of node attribute instances based on the specified node definition.\n */\nfunction nodeAttributesFactory(definition: AnyNodeDefinition): Attribute[] {\n const attributes: Attribute[] = [];\n\n if (definition.while) {\n attributes.push(new While(definition.while.call, definition.while.args ?? []));\n }\n\n if (definition.until) {\n attributes.push(new Until(definition.until.call, definition.until.args ?? []));\n }\n\n if (definition.entry) {\n attributes.push(new Entry(definition.entry.call, definition.entry.args ?? []));\n }\n\n if (definition.step) {\n attributes.push(new Step(definition.step.call, definition.step.args ?? []));\n }\n\n if (definition.exit) {\n attributes.push(new Exit(definition.exit.call, definition.exit.args ?? []));\n }\n\n return attributes;\n}\n\n/**\n * Creates a mapping of root node identifers to root node definitions, mixing in globally registered subtree root node definitions.\n * @param definition The root node definitions.\n * @returns A mapping of root node identifers to root node definitions, including globally registered subtree root node definitions.\n */\nfunction createRootNodeDefinitionMap(definition: RootNodeDefinition[]): RootNodeDefinitionMap {\n // Create a mapping of root node identifers to root node definitions.\n const rootNodeMap: RootNodeDefinitionMap = {};\n\n // Add in any registered subtree root node definitions.\n for (const [name, rootNodeDefinition] of Object.entries(Lookup.getSubtrees())) {\n // The name used when registering the subtree will be used as the root node identifier.\n rootNodeMap[name] = { ...rootNodeDefinition, id: name };\n }\n\n // Populate the map with the root node definitions that were included with the tree definition.\n // We do this after adding any registered subtrees as we want these to take presedence.\n for (const rootNodeDefinition of definition) {\n rootNodeMap[rootNodeDefinition.id ?? MAIN_ROOT_NODE_KEY] = rootNodeDefinition;\n }\n\n return rootNodeMap;\n}\n\n/**\n * Applies a guard path to every leaf of the tree to evaluate as part of each update.\n * @param root The main root tree node.\n */\nfunction applyLeafNodeGuardPaths(root: Root) {\n const nodePaths: Node[][] = [];\n\n const findLeafNodes = (path: Node[], node: Node) => {\n // Add the current node to the path.\n path = path.concat(node);\n\n // Check whether the current node is a leaf node.\n if (node.isLeafNode()) {\n nodePaths.push(path);\n } else {\n (node as Composite | Decorator).getChildren().forEach((child) => findLeafNodes(path, child));\n }\n };\n\n // Find all leaf node paths, starting from the root.\n findLeafNodes([], root);\n\n nodePaths.forEach((path) => {\n // Each node in the current path will have to be assigned a guard path, working from the root outwards.\n for (let depth = 0; depth < path.length; depth++) {\n // Get the node in the path at the current depth.\n const currentNode = path[depth];\n\n // The node may already have been assigned a guard path, if so just skip it.\n if (currentNode.hasGuardPath()) {\n continue;\n }\n\n // Create the guard path for the current node.\n const guardPath = new GuardPath(\n path\n .slice(0, depth + 1)\n .map((node) => ({ node, guards: node.getGuardAttributes() }))\n .filter((details) => details.guards.length > 0)\n );\n\n // Assign the guard path to the current node.\n currentNode.setGuardPath(guardPath);\n }\n });\n}\n", "import State, { AnyState } from \"./State\";\nimport Lookup from \"./Lookup\";\nimport Node from \"./nodes/Node\";\nimport Root from \"./nodes/decorator/Root\";\nimport Composite from \"./nodes/composite/Composite\";\nimport Decorator from \"./nodes/decorator/Decorator\";\nimport { Agent, GlobalFunction } from \"./Agent\";\nimport { CallbackAttributeDetails } from \"./attributes/callbacks/Callback\";\nimport { GuardAttributeDetails } from \"./attributes/guards/Guard\";\nimport { BehaviourTreeOptions } from \"./BehaviourTreeOptions\";\nimport { convertMDSLToJSON } from \"./mdsl/MDSLDefinitionParser\";\nimport { RootNodeDefinition } from \"./BehaviourTreeDefinition\";\nimport { validateDefinition, validateJSONDefinition } from \"./BehaviourTreeDefinitionValidator\";\nimport buildRootNode from \"./BehaviourTreeBuilder\";\nimport { isNullOrUndefined } from \"./BehaviourTreeDefinitionUtilities\";\n\n// Purely for outside inspection of the tree.\nexport type FlattenedTreeNode = {\n id: string;\n type: string;\n caption: string;\n state: AnyState;\n guards: GuardAttributeDetails[];\n callbacks: CallbackAttributeDetails[];\n args: any[];\n parentId: string | null;\n};\n\n/**\n * A representation of a behaviour tree.\n */\nexport class BehaviourTree {\n /**\n * The main root tree node.\n */\n public readonly rootNode: Root;\n\n /**\n * Creates a new instance of the BehaviourTree class.\n * @param definition The behaviour tree definition.\n * @param agent The agent instance that this behaviour tree is modelling behaviour for.\n * @param options The behaviour tree options object.\n */\n constructor(\n definition: string | RootNodeDefinition | RootNodeDefinition[],\n private agent: Agent,\n private options: BehaviourTreeOptions = {}\n ) {\n // The tree definition must be defined.\n if (isNullOrUndefined(definition)) {\n throw new Error(\"tree definition not defined\");\n }\n\n // The agent must be defined and not null.\n if (typeof agent !== \"object\" || agent === null) {\n throw new Error(\"the agent must be an object and not null\");\n }\n\n // We should validate the definition before we try to build the tree nodes.\n const { succeeded, errorMessage } = validateDefinition(definition);\n\n // Did our validation fail without error?\n if (!succeeded) {\n throw new Error(`invalid definition: ${errorMessage}`);\n }\n\n try {\n // Parse the behaviour tree definition, create the populated tree of behaviour tree nodes, and get the root.\n this.rootNode = this._createRootNode(definition);\n } catch (exception) {\n // There was an issue in trying build and populate the behaviour tree.\n throw new Error(`error building tree: ${(exception as Error).message}`);\n }\n }\n\n /**\n * Gets whether the tree is in the RUNNING state.\n * @returns true if the tree is in the RUNNING state, otherwise false.\n */\n isRunning() {\n return this.rootNode.getState() === State.RUNNING;\n }\n\n /**\n * Gets the current tree state of SUCCEEDED, FAILED, READY or RUNNING.\n * @returns The current tree state.\n */\n getState() {\n return this.rootNode.getState();\n }\n\n /**\n * Step the tree.\n * 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.\n * 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\n * 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.\n *\n * 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.\n */\n step() {\n // If the root node has already been stepped to completion then we need to reset it.\n if (this.rootNode.getState() === State.SUCCEEDED || this.rootNode.getState() === State.FAILED) {\n this.rootNode.reset();\n }\n\n try {\n this.rootNode.update(this.agent, this.options);\n } catch (exception) {\n throw new Error(`error stepping tree: ${(exception as Error).message}`);\n }\n }\n\n /**\n * Resets the tree from the root node outwards to each nested node, giving each a state of READY.\n */\n reset() {\n this.rootNode.reset();\n }\n\n /**\n * Gets the flattened details of every node in the tree.\n * @returns The flattened details of every node in the tree.\n */\n getFlattenedNodeDetails(): FlattenedTreeNode[] {\n // Create an empty flattened array of tree nodes.\n const flattenedTreeNodes: FlattenedTreeNode[] = [];\n\n /**\n * Helper function to process a node instance and push details into the flattened tree nodes array.\n * @param node The current node.\n * @param parentUid The UID of the node parent, or null if the node is the main root node.\n */\n const processNode = (node: Node, parentUid: string | null) => {\n // Get the guard and callback attribute details for this node.\n const guards = node\n .getAttributes()\n .filter((attribute) => attribute.isGuard())\n .map((attribute) => attribute.getDetails()) as GuardAttributeDetails[];\n const callbacks = node\n .getAttributes()\n .filter((attribute) => !attribute.isGuard())\n .map((attribute) => attribute.getDetails()) as CallbackAttributeDetails[];\n\n // Push the current node into the flattened nodes array.\n flattenedTreeNodes.push({\n id: node.getUid(),\n type: node.getType(),\n caption: node.getName(),\n state: node.getState(),\n guards,\n callbacks,\n args: node.getArguments(),\n parentId: parentUid\n });\n\n // Process each of the nodes children if it is not a leaf node.\n if (!node.isLeafNode()) {\n (node as Composite | Decorator)\n .getChildren()\n .forEach((child) => processNode(child, (node as Composite | Decorator).getUid()));\n }\n };\n\n // Convert the nested node structure into a flattened array of node details.\n processNode(this.rootNode, null);\n\n return flattenedTreeNodes;\n }\n\n /**\n * Registers the action/condition/guard/callback function or subtree with the given name.\n * @param name The name of the function or subtree to register.\n * @param value The function or subtree definition to register.\n */\n static register(name: string, value: GlobalFunction | string | RootNodeDefinition) {\n // Are we going to register a action/condition/guard/callback function?\n if (typeof value === \"function\") {\n Lookup.setFunc(name, value);\n return;\n }\n\n // We are not registering an action/condition/guard/callback function, so we must be registering a subtree.\n if (typeof value === \"string\") {\n let rootNodeDefinitions: RootNodeDefinition[];\n\n // We will assume that any string passed in will be a mdsl definition.\n try {\n rootNodeDefinitions = convertMDSLToJSON(value);\n } catch (exception) {\n throw new Error(`error registering definition, invalid MDSL: ${(exception as Error).message}`);\n }\n\n // This function should only ever be called with a definition containing a single unnamed root node.\n if (rootNodeDefinitions.length != 1 || rootNodeDefinitions[0].id !== null) {\n throw new Error(\"error registering definition: expected a single unnamed root node\");\n }\n\n try {\n // We should validate the subtree as we don't want invalid subtrees available via the lookup.\n const { succeeded, errorMessage } = validateJSONDefinition(rootNodeDefinitions[0]);\n\n // Did our validation fail without error?\n if (!succeeded) {\n throw new Error(errorMessage);\n }\n } catch (exception) {\n throw new Error(`error registering definition: ${(exception as Error).message}`);\n }\n\n // Everything seems hunky-dory, register the subtree.\n Lookup.setSubtree(name, rootNodeDefinitions[0]);\n } else if (typeof value === \"object\" && !Array.isArray(value)) {\n // We will assume that any object passed in is a root node definition.\n\n try {\n // We should validate the subtree as we don't want invalid subtrees available via the lookup.\n const { succeeded, errorMessage } = validateJSONDefinition(value);\n\n // Did our validation fail without error?\n if (!succeeded) {\n throw new Error(errorMessage);\n }\n } catch (exception) {\n throw new Error(`error registering definition: ${(exception as Error).message}`);\n }\n\n // Everything seems hunky-dory, register the subtree.\n Lookup.setSubtree(name, value);\n } else {\n throw new Error(\"unexpected value, expected string mdsl definition, root node json definition or function\");\n }\n }\n\n /**\n * Unregisters the registered action/condition/guard/callback function or subtree with the given name.\n * @param name The name of the registered action/condition/guard/callback function or subtree to unregister.\n */\n static unregister(name: string): void {\n Lookup.remove(name);\n }\n\n /**\n * Unregister all registered action/condition/guard/callback functions and subtrees.\n */\n static unregisterAll(): void {\n Lookup.empty();\n }\n\n /**\n * Parses a behaviour tree definition and creates a tree of behaviour tree nodes populated at a root.\n * @param {string | RootNodeDefinition | RootNodeDefinition[]} definition The behaviour tree definition.\n * @returns The root behaviour tree node.\n */\n private _createRootNode(definition: string | RootNodeDefinition | RootNodeDefinition[]): Root {\n // Our definition will have to be converted to JSON if it is a MDSL string.\n // TODO convertMDSLToJSON is called TWICE, once for validation and once here. Maybe return the JSON as part of the validation result?\n const resolvedDefinition = typeof definition === \"string\" ? convertMDSLToJSON(definition) : definition;\n\n // Build and populate the root node.\n return buildRootNode(Array.isArray(resolvedDefinition) ? resolvedDefinition : [resolvedDefinition]);\n }\n}\n"], - "mappings": "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", + "sourcesContent": ["\"use strict\";\r\nObject.defineProperty(exports, \"__esModule\", { value: true });\r\nexports.Participant = void 0;\r\n/**\r\n * A participant that holds a number of tickets.\r\n */\r\nvar Participant = /** @class */ (function () {\r\n /**\r\n * Creates an instance of the Participant class.\r\n * @param participant The actual participant.\r\n * @param tickets The number of tickets held by the participant.\r\n */\r\n function Participant(participant, tickets) {\r\n if (tickets === void 0) { tickets = 1; }\r\n this._participant = participant;\r\n this._tickets = tickets;\r\n }\r\n Object.defineProperty(Participant.prototype, \"participant\", {\r\n /** Gets the actual participant. */\r\n get: function () {\r\n return this._participant;\r\n },\r\n enumerable: false,\r\n configurable: true\r\n });\r\n Object.defineProperty(Participant.prototype, \"tickets\", {\r\n /** Gets or sets the number of tickets held by the participant. */\r\n get: function () {\r\n return this._tickets;\r\n },\r\n set: function (value) {\r\n this._tickets = value;\r\n },\r\n enumerable: false,\r\n configurable: true\r\n });\r\n return Participant;\r\n}());\r\nexports.Participant = Participant;\r\n", "\"use strict\";\r\nObject.defineProperty(exports, \"__esModule\", { value: true });\r\nexports.isNaturalNumber = exports.isNullOrUndefined = void 0;\r\n/**\r\n * Gets whether the value provided is null or undefined.\r\n * @param value The value to check.\r\n * @returns Whether the value provided is null or undefined.\r\n */\r\nfunction isNullOrUndefined(value) {\r\n return value === null || value === undefined;\r\n}\r\nexports.isNullOrUndefined = isNullOrUndefined;\r\n/**\r\n * Gets whether the value provided is a natural number.\r\n * @param value The value to check.\r\n * @returns Whether the value provided is a natural number.\r\n */\r\nfunction isNaturalNumber(value) {\r\n return typeof value === \"number\" && value >= 1 && Math.floor(value) === value;\r\n}\r\nexports.isNaturalNumber = isNaturalNumber;\r\n", "\"use strict\";\r\nObject.defineProperty(exports, \"__esModule\", { value: true });\r\nexports.Lotto = void 0;\r\nvar Participant_1 = require(\"./Participant\");\r\nvar Utilities_1 = require(\"./Utilities\");\r\n/**\r\n * Represents a lotto consisting of a number of pickable ticket-holding participants.\r\n */\r\nvar Lotto = /** @class */ (function () {\r\n /**\r\n * Creates a new instance of Lotto.\r\n * @param customRandom The custom RNG to use in place of Math.random().\r\n */\r\n function Lotto(customRandom) {\r\n /** The array of participants that are holding tickets in the lotto. */\r\n this._participants = [];\r\n this._customRandom = customRandom;\r\n }\r\n /**\r\n * Adds a participant with the specified number of tickets, or adds to the participant ticket count if the participant already holds tickets.\r\n * @param participant The participant to add or to increase the ticket count for if they already hold tickets.\r\n * @param tickets The number of tickets, defaults to 1.\r\n * @returns The Lotto instance.\r\n */\r\n Lotto.prototype.add = function (participant, tickets) {\r\n if (tickets === void 0) { tickets = 1; }\r\n // Check that we have a valid ticket count.\r\n if (!(0, Utilities_1.isNaturalNumber)(tickets)) {\r\n throw new Error(\"tickets value must be a natural number\");\r\n }\r\n // Check whether this participant has already been added.\r\n var existingParticipant = this._participants.find(function (part) { return part.participant === participant; });\r\n if (existingParticipant) {\r\n // The participant has already been added to the lotto so just add to their ticket count.\r\n existingParticipant.tickets += tickets;\r\n }\r\n else {\r\n // The participant is not part of the lotto so we should add them.\r\n this._participants.push(new Participant_1.Participant(participant, tickets));\r\n }\r\n return this;\r\n };\r\n /**\r\n * Removes the specified number of tickets for the given participant from the draw, or all tickets if a ticket number is not defined.\r\n * @param participant The participant to remove tickets for.\r\n * @param tickets The number of tickets to remove, or undefined if all tickets are to be removed.\r\n * @returns The Lotto instance.\r\n */\r\n Lotto.prototype.remove = function (participant, tickets) {\r\n // Attempt to get the existing participant.\r\n var existingParticipant = this._participants.find(function (part) { return part.participant === participant; });\r\n // There is nothing to do if the specified participant isn't even part of the lotto.\r\n if (!existingParticipant) {\r\n return this;\r\n }\r\n // Check whether a tickets value was given.\r\n if (tickets !== undefined) {\r\n // Check that we have a valid ticket count.\r\n if (!(0, Utilities_1.isNaturalNumber)(tickets)) {\r\n throw new Error(\"tickets value must be a natural number\");\r\n }\r\n existingParticipant.tickets -= tickets;\r\n // If the participant no longer holds any tickets then they should be removed.\r\n if (existingParticipant.tickets < 1) {\r\n this._participants = this._participants.filter(function (part) { return part !== existingParticipant; });\r\n }\r\n }\r\n else {\r\n // We are removing all tickets for the participant so just remove them from the lotto.\r\n this._participants = this._participants.filter(function (part) { return part !== existingParticipant; });\r\n }\r\n return this;\r\n };\r\n /**\r\n * Draw a winning ticket and return the participant that holds the ticket.\r\n * @param options The draw options.\r\n * @returns The participant that holds the winning ticket.\r\n */\r\n Lotto.prototype.draw = function (options) {\r\n if (options === void 0) { options = {}; }\r\n // If we have no participants then just return null.\r\n if (this._participants.length === 0) {\r\n return null;\r\n }\r\n var redrawable = (0, Utilities_1.isNullOrUndefined)(options.redrawable) ? true : options.redrawable;\r\n var pickable = [];\r\n this._participants.forEach(function (_a) {\r\n var participant = _a.participant, tickets = _a.tickets;\r\n for (var ticketCount = 0; ticketCount < tickets; ticketCount++) {\r\n pickable.push(participant);\r\n }\r\n });\r\n var random;\r\n // We need a random floating-point number between 0 (inclusive) and 1 to scale up to pick our winner.\r\n // If a custom random function exists then we should use that or fall back to Math.random().\r\n if (this._customRandom) {\r\n // Call our custom random function to get a random floating-point number.\r\n random = this._customRandom();\r\n // Verify that the result of calling our custom random function is a number between 0 (inclusive) and 1.\r\n if (typeof random !== \"number\" || random < 0 || random >= 1) {\r\n throw new Error(\"the 'random' function provided did not return a number between 0 (inclusive) and 1\");\r\n }\r\n }\r\n else {\r\n // No custom random function was defined so just use good ol' Math.random().\r\n random = Math.random();\r\n }\r\n // Pick a winning participant.\r\n var winner = pickable[Math.floor(random * pickable.length)];\r\n // If the ticket isn't redrawable then we should remove a ticket from the winning participants ticket count.\r\n if (!redrawable) {\r\n this.remove(winner, 1);\r\n }\r\n // Return the winning participant.\r\n return winner;\r\n };\r\n /**\r\n * Draws multiple winning tickets and return an array of the participants that hold the winning tickets.\r\n * @param tickets The number of winning tickets to draw.\r\n * @param options The draw multiple options.\r\n * @returns An array of the participants that hold the winning tickets.\r\n */\r\n Lotto.prototype.drawMultiple = function (tickets, options) {\r\n if (options === void 0) { options = {}; }\r\n var uniqueResults = (0, Utilities_1.isNullOrUndefined)(options.unique) ? false : options.unique;\r\n // Handle cases where the user has asked for zero tickets (no idea why they would do this be we should trust them).\r\n if (tickets === 0) {\r\n return [];\r\n }\r\n // Now that we know out tickets value is not zero we should check that it is a valid natural number.\r\n if (!(0, Utilities_1.isNaturalNumber)(tickets)) {\r\n throw new Error(\"tickets value must be a natural number\");\r\n }\r\n var result = [];\r\n // Keep drawing tickets until we either reach the number of required tickets or we simply run out of tickets to draw.\r\n // We can run out of tickets to draw if 'options.redrawable' is explicity 'false' or we just had no participants when 'drawMultiple' was called.\r\n while (result.length < tickets && this._participants.length > 0) {\r\n result.push(this.draw(options));\r\n }\r\n // If the 'unique' draw option is set then we need to remove duplicates from the result list.\r\n if (uniqueResults) {\r\n // Create an array to store our unique results.\r\n var unique = [];\r\n // Iterate over all of our participants (with potential duplicates) and populate our array of unique values.\r\n for (var _i = 0, result_1 = result; _i < result_1.length; _i++) {\r\n var participant = result_1[_i];\r\n if (unique.indexOf(participant) === -1) {\r\n unique.push(participant);\r\n }\r\n }\r\n result = unique;\r\n }\r\n return result;\r\n };\r\n return Lotto;\r\n}());\r\nexports.Lotto = Lotto;\r\n", "\"use strict\";\r\nObject.defineProperty(exports, \"__esModule\", { value: true });\r\nexports.createLotto = void 0;\r\nvar Lotto_1 = require(\"./Lotto\");\r\n/**\r\n * A function that creates and returns a Lotto instance.\r\n * @param participantsOrOptions An array of initial participants or options relating to the creation of a Lotto instance.\r\n * @returns A new Lotto instance.\r\n */\r\nfunction createLotto(participantsOrOptions) {\r\n // If no initial participants or lotto options were provided as an argument then we can just return a new lotto instance now.\r\n if (!participantsOrOptions) {\r\n return new Lotto_1.Lotto();\r\n }\r\n // Check whether we were provided with an array of initial participants or a lotto options object.\r\n if (Array.isArray(participantsOrOptions)) {\r\n // We are dealing with a pre-defined array of participants.\r\n var participants = participantsOrOptions;\r\n var lotto_1 = new Lotto_1.Lotto();\r\n // If the lotto participants have been defined upfront then we will need to add them all to our lotto instance now.\r\n participants.forEach(function (_a) {\r\n var participant = _a[0], tokens = _a[1];\r\n return lotto_1.add(participant, tokens);\r\n });\r\n // Return the Lotto instance.\r\n return lotto_1;\r\n }\r\n else {\r\n // We are dealing with some lotto options.\r\n var random = participantsOrOptions.random, participants = participantsOrOptions.participants;\r\n // Create a Lotto instance passing the custom RNG function to use in place of Math.random() (which could be undefined).\r\n var lotto_2 = new Lotto_1.Lotto(random);\r\n // If the lotto participants have been defined upfront as part of the options then we will need to add them all to our lotto instance now.\r\n if (participants) {\r\n participants.forEach(function (_a) {\r\n var participant = _a[0], tokens = _a[1];\r\n return lotto_2.add(participant, tokens);\r\n });\r\n }\r\n // Return the Lotto instance.\r\n return lotto_2;\r\n }\r\n}\r\nexports.createLotto = createLotto;\r\n", "\"use strict\";\r\nObject.defineProperty(exports, \"__esModule\", { value: true });\r\nvar createLotto_1 = require(\"./createLotto\");\r\nexports.default = createLotto_1.createLotto;\r\n", "import State from \"./State\";\nimport { validateDefinition } from \"./BehaviourTreeDefinitionValidator\";\nimport { convertMDSLToJSON } from \"./mdsl/MDSLDefinitionParser\";\nimport { BehaviourTree, FlattenedTreeNode } from \"./BehaviourTree\";\nimport { BehaviourTreeOptions } from \"./BehaviourTreeOptions\";\n\nexport { BehaviourTree, State, convertMDSLToJSON, validateDefinition };\nexport type { FlattenedTreeNode, BehaviourTreeOptions };\n", "/**\n * Enumeration of node state types.\n */\nexport enum State {\n READY = \"mistreevous.ready\",\n RUNNING = \"mistreevous.running\",\n SUCCEEDED = \"mistreevous.succeeded\",\n FAILED = \"mistreevous.failed\"\n}\n\nexport { State as default };\n\nexport type CompleteState = State.SUCCEEDED | State.FAILED;\nexport type AnyState = State.READY | State.RUNNING | CompleteState;\n", "import {\n NodeDefinition,\n RootNodeDefinition,\n DecoratorNodeDefinition,\n CompositeNodeDefinition,\n AnyNodeDefinition,\n BranchNodeDefinition\n} from \"./BehaviourTreeDefinition\";\n\n/**\n * A type guard function that returns true if the specified node satisfies the RootNodeDefinition type.\n * @param node The node.\n * @returns A value of true if the specified node satisfies the RootNodeDefinition type.\n */\nexport function isRootNode(node: NodeDefinition): node is RootNodeDefinition {\n return node.type === \"root\";\n}\n\n/**\n * A type guard function that returns true if the specified node satisfies the BranchNodeDefinition type.\n * @param node The node.\n * @returns A value of true if the specified node satisfies the BranchNodeDefinition type.\n */\nexport function isBranchNode(node: NodeDefinition): node is BranchNodeDefinition {\n return node.type === \"branch\";\n}\n\n/**\n * A type guard function that returns true if the specified node satisfies the NodeDefinition type.\n * @param node The node.\n * @returns A value of true if the specified node satisfies the NodeDefinition type.\n */\nexport function isLeafNode(node: NodeDefinition): node is NodeDefinition {\n return [\"branch\", \"action\", \"condition\", \"wait\"].includes(node.type);\n}\n\n/**\n * A type guard function that returns true if the specified node satisfies the DecoratorNodeDefinition type.\n * @param node The node.\n * @returns A value of true if the specified node satisfies the DecoratorNodeDefinition type.\n */\nexport function isDecoratorNode(node: NodeDefinition): node is DecoratorNodeDefinition {\n return [\"root\", \"repeat\", \"retry\", \"flip\", \"succeed\", \"fail\"].includes(node.type);\n}\n\n/**\n * A type guard function that returns true if the specified node satisfies the CompositeNodeDefinition type.\n * @param node The node.\n * @returns A value of true if the specified node satisfies the CompositeNodeDefinition type.\n */\nexport function isCompositeNode(node: NodeDefinition): node is CompositeNodeDefinition {\n return [\"sequence\", \"selector\", \"lotto\", \"parallel\"].includes(node.type);\n}\n\n/**\n * Flatten a node definition into an array of all of its nested node definitions.\n * @param nodeDefinition The node definition to flatten.\n * @returns An array of all of nested node definitions.\n */\nexport function flattenDefinition(nodeDefinition: AnyNodeDefinition): AnyNodeDefinition[] {\n const nodes: AnyNodeDefinition[] = [];\n\n const processNode = (currentNodeDefinition: AnyNodeDefinition) => {\n nodes.push(currentNodeDefinition);\n\n if (isCompositeNode(currentNodeDefinition)) {\n currentNodeDefinition.children.forEach(processNode);\n } else if (isDecoratorNode(currentNodeDefinition)) {\n processNode(currentNodeDefinition.child);\n }\n };\n\n processNode(nodeDefinition);\n\n return nodes;\n}\n\n/**\n * Determines whether the passed value is an integer.\n * @param value The value to check.\n * @returns Whether the passed value is an integer.\n */\nexport function isInteger(value: unknown): boolean {\n return typeof value === \"number\" && Math.floor(value) === value;\n}\n\n/**\n * Determines whether the passed value is null or undefined.\n * @param value The value to check.\n * @returns Whether the passed value is null or undefined.\n */\nexport function isNullOrUndefined(value: unknown): boolean {\n return typeof value === \"undefined\" || value === null;\n}\n", "/**\n * A type defining an object that holds a reference to substitued string literals parsed from the definition.\n */\nexport type StringLiteralPlaceholders = { [key: string]: string };\n\n/**\n * Pop the next raw token from the specified array of tokens and throw an error if it wasn't the expected one.\n * @param tokens The array of tokens.\n * @param expected An optional string or array or items, one of which must match the next popped token.\n * @returns The popped token.\n */\nexport function popAndCheck(tokens: string[], expected?: string | string[]): string {\n // Get and remove the next token.\n const popped = tokens.shift();\n\n // We were expecting another token but there aren't any.\n if (popped === undefined) {\n throw new Error(\"unexpected end of definition\");\n }\n\n // Do we have an expected token/tokens array?\n if (expected != undefined) {\n // Get an array of expected values, if the popped token matches any then we are all good.\n const expectedValues = typeof expected === \"string\" ? [expected] : expected;\n\n // Check whether the popped token matches at least one of our expected items.\n var tokenMatchesExpectation = expectedValues.some((item) => popped.toUpperCase() === item.toUpperCase());\n\n // Throw an error if the popped token didn't match any of our expected items.\n if (!tokenMatchesExpectation) {\n const expectationString = expectedValues.map((item) => \"'\" + item + \"'\").join(\" or \");\n throw new Error(\"unexpected token found. Expected \" + expectationString + \" but got '\" + popped + \"'\");\n }\n }\n\n // Return the popped token.\n return popped;\n}\n\n/**\n * Swaps out any node/attribute argument string literals with placeholders.\n * @param definition The definition.\n * @returns An object containing a mapping of placeholders to original string values as well as the processed definition string.\n */\nexport function substituteStringLiterals(definition: string): {\n placeholders: StringLiteralPlaceholders;\n processedDefinition: string;\n} {\n // Create an object to hold the mapping of placeholders to original string values.\n const placeholders: StringLiteralPlaceholders = {};\n\n // Replace any string literals wrapped with double quotes in our definition with placeholders to be processed later.\n const processedDefinition = definition.replace(/\\\"(\\\\.|[^\"\\\\])*\\\"/g, (match) => {\n var strippedMatch = match.substring(1, match.length - 1);\n var placeholder = Object.keys(placeholders).find((key) => placeholders[key] === strippedMatch);\n\n // If we have no existing string literal match then create a new placeholder.\n if (!placeholder) {\n placeholder = `@@${Object.keys(placeholders).length}@@`;\n placeholders[placeholder] = strippedMatch;\n }\n\n return placeholder;\n });\n\n return { placeholders, processedDefinition };\n}\n\n/**\n * Parse the tree definition into an array of raw tokens.\n * @param definition The definition.\n * @returns An array of tokens parsed from the definition.\n */\nexport function parseTokensFromDefinition(definition: string): string[] {\n // Add some space around various important characters so that they can be plucked out easier as individual tokens.\n definition = definition.replace(/\\(/g, \" ( \");\n definition = definition.replace(/\\)/g, \" ) \");\n definition = definition.replace(/\\{/g, \" { \");\n definition = definition.replace(/\\}/g, \" } \");\n definition = definition.replace(/\\]/g, \" ] \");\n definition = definition.replace(/\\[/g, \" [ \");\n definition = definition.replace(/\\,/g, \" , \");\n\n // Split the definition into raw token form and return it.\n return definition.replace(/\\s+/g, \" \").trim().split(\" \");\n}\n", "import { StringLiteralPlaceholders, popAndCheck } from \"./MDSLUtilities\";\n\n/**\n * A type representing any node function argument.\n */\ntype Argument = {\n /**\n * The argument value.\n */\n value: T;\n /**\n * The argument type, used for validation.\n */\n type: string;\n};\n\ntype NullArgument = Argument & {\n type: \"null\";\n};\n\ntype BooleanArgument = Argument & {\n type: \"boolean\";\n};\n\ntype NumberArgument = Argument & {\n type: \"number\";\n /**\n * A flag defining whether the number argument value is a valid integer. (used for validation)\n */\n isInteger: boolean;\n};\n\ntype StringPlaceholderArgument = Argument & {\n type: \"string\";\n};\n\ntype IdentifierArgument = Argument & {\n type: \"identifier\";\n};\n\n/**\n * A type representing a reference to any node function argument.\n */\ntype AnyArgument = NullArgument | BooleanArgument | NumberArgument | StringPlaceholderArgument | IdentifierArgument;\n\n/**\n * Parse an array of argument definitions from the specified tokens array.\n * @param tokens The array tokens to parse the argument definitions from.\n * @param stringArgumentPlaceholders The mapping of string literal node argument placeholders to original values.\n * @param argumentValidator The argument validator function.\n * @param validationFailedMessage The exception message to throw if argument validation fails.\n * @returns An array of argument definitions parsed from the specified tokens array.\n */\nexport function parseArgumentTokens(\n tokens: string[],\n stringArgumentPlaceholders: StringLiteralPlaceholders\n): AnyArgument[] {\n const argumentList: AnyArgument[] = [];\n\n // If the next token is not a '[' or '(' then we have no arguments to parse.\n if (![\"[\", \"(\"].includes(tokens[0])) {\n return argumentList;\n }\n\n // Any lists of arguments will always be wrapped in '[]' for node arguments or '()' for attribute arguments.\n // We are looking for a '[' or '(' opener that wraps the argument tokens and the relevant closer.\n const closingToken = popAndCheck(tokens, [\"[\", \"(\"]) === \"[\" ? \"]\" : \")\";\n\n const argumentListTokens: string[] = [];\n\n // Grab all tokens between the '[' and ']' or '(' and ')'.\n while (tokens.length && tokens[0] !== closingToken) {\n // The next token is part of our arguments list.\n argumentListTokens.push(tokens.shift()!);\n }\n\n // Validate the order of the argument tokens. Each token must either be a ',' or a single argument that satisfies the validator.\n argumentListTokens.forEach((token, index) => {\n // Get whether this token should be an actual argument.\n const shouldBeArgumentToken = !(index & 1);\n\n // If the current token should be an actual argument then validate it, otherwise it should be a ',' token.\n if (shouldBeArgumentToken) {\n // Get the argument definition.\n const argumentDefinition = getArgumentDefinition(token, stringArgumentPlaceholders);\n\n // This is a valid argument!\n argumentList.push(argumentDefinition);\n } else {\n // The current token should be a ',' token.\n if (token !== \",\") {\n throw new Error(`invalid argument list, expected ',' or ']' but got '${token}'`);\n }\n }\n });\n\n // The arguments list should terminate with a ']' or ')' token, depending on the opener.\n popAndCheck(tokens, closingToken);\n\n // Return the arguments.\n return argumentList;\n}\n\n/**\n * Gets an argument value definition.\n * @param token The argument token.\n * @param stringArgumentPlaceholders The mapping of string literal node argument placeholders to original values.\n * @returns An argument value definition.\n */\nfunction getArgumentDefinition(token: string, stringArgumentPlaceholders: StringLiteralPlaceholders): AnyArgument {\n // Check whether the token represents a null value.\n if (token === \"null\") {\n return {\n value: null,\n type: \"null\"\n } as NullArgument;\n }\n\n // Check whether the token represents a boolean value.\n if (token === \"true\" || token === \"false\") {\n return {\n value: token === \"true\",\n type: \"boolean\"\n } as BooleanArgument;\n }\n\n // Check whether the token represents a number value.\n // TODO: Relies on broken isNaN - see MDN.\n // if (!Number.isNaN(token)) {\n if (!isNaN(token as any)) {\n return {\n value: parseFloat(token),\n isInteger: parseFloat(token) === parseInt(token, 10),\n type: \"number\"\n } as NumberArgument;\n }\n\n // Check whether the token is a placeholder (e.g. @@0@@) representing a string literal.\n if (token.match(/^@@\\d+@@$/g)) {\n return {\n value: stringArgumentPlaceholders[token].replace('\\\\\"', '\"'),\n type: \"string\"\n } as StringPlaceholderArgument;\n }\n\n // The only remaining option is that the argument value is an identifier.\n return {\n value: token,\n type: \"identifier\"\n } as IdentifierArgument;\n}\n", "import { NodeAttributeDefinition } from \"../BehaviourTreeDefinition\";\nimport { parseArgumentTokens } from \"./MDSLNodeArgumentParser\";\nimport { StringLiteralPlaceholders } from \"./MDSLUtilities\";\n\n/**\n * A type defining the attribute definitions of a node.\n */\ntype NodeAttributes = {\n while?: NodeAttributeDefinition;\n until?: NodeAttributeDefinition;\n entry?: NodeAttributeDefinition;\n exit?: NodeAttributeDefinition;\n step?: NodeAttributeDefinition;\n};\n\n/**\n * Parse any node attribute definitions from the specified tokens array.\n * @param tokens The array of remaining tokens.\n * @param stringArgumentPlaceholders The mapping of string literal node argument placeholders to original values.\n * @returns An object of attribute definitions defined by any directly following tokens.\n */\nexport function parseAttributeTokens(\n tokens: string[],\n stringArgumentPlaceholders: StringLiteralPlaceholders\n): NodeAttributes {\n const nodeAttributeNames: (keyof NodeAttributes)[] = [\"while\", \"until\", \"entry\", \"exit\", \"step\"];\n\n // Create an object to hold any attributes found.\n const attributes: NodeAttributes = {};\n\n // Try to get the name of the attribute for the next token.\n let nextAttributeName = tokens[0]?.toLowerCase() as keyof NodeAttributes;\n\n // Pull attribute tokens as well as their arguments off of the tokens stack until we have no more.\n while (nodeAttributeNames.includes(nextAttributeName)) {\n // Check to make sure that we have not already created an attribute definition of this type.\n if (attributes[nextAttributeName]) {\n throw new Error(`duplicate attribute '${tokens[0].toUpperCase()}' found for node`);\n }\n\n // Remove the attribute name token from the array of tokens.\n tokens.shift();\n\n // Grab the attribute arguments, assuming the first to be an identifier.\n const [attributeCallIdentifier, ...attributeArguments] = parseArgumentTokens(\n tokens,\n stringArgumentPlaceholders\n );\n\n // The first attribute argument has to be an identifer, this will reference an agent function.\n if (attributeCallIdentifier?.type !== \"identifier\") {\n throw new Error(\"expected agent function name identifier argument for attribute\");\n }\n\n // Any attribute arguments (other than the expected call identifier) must have a type of string, number, boolean or null.\n attributeArguments\n .filter((arg) => arg.type === \"identifier\")\n .forEach((arg) => {\n throw new Error(\n `invalid attribute argument value '${arg.value}', must be string, number, boolean or null`\n );\n });\n\n // Create the attribute definition and add it to the object of attribute definitions found.\n attributes[nextAttributeName] = {\n call: attributeCallIdentifier.value,\n args: attributeArguments.map(({ value }) => value)\n };\n\n // Try to get the next attribute name token, as there could be multiple.\n nextAttributeName = tokens[0]?.toLowerCase() as keyof NodeAttributes;\n }\n\n return attributes;\n}\n", "import {\n ActionNodeDefinition,\n AnyChildNodeDefinition,\n AnyNodeDefinition,\n BranchNodeDefinition,\n ConditionNodeDefinition,\n FailNodeDefinition,\n FlipNodeDefinition,\n LottoNodeDefinition,\n ParallelNodeDefinition,\n RepeatNodeDefinition,\n RetryNodeDefinition,\n RootNodeDefinition,\n SelectorNodeDefinition,\n SequenceNodeDefinition,\n SucceedNodeDefinition,\n WaitNodeDefinition\n} from \"../BehaviourTreeDefinition\";\nimport {\n isCompositeNode,\n isDecoratorNode,\n isLeafNode,\n isNullOrUndefined,\n isRootNode\n} from \"../BehaviourTreeDefinitionUtilities\";\nimport { parseArgumentTokens } from \"./MDSLNodeArgumentParser\";\nimport { parseAttributeTokens } from \"./MDSLNodeAttributeParser\";\nimport {\n StringLiteralPlaceholders,\n parseTokensFromDefinition,\n popAndCheck,\n substituteStringLiterals\n} from \"./MDSLUtilities\";\n\n/**\n * Convert the MDSL tree definition string into an equivalent JSON definition.\n * @param definition The tree definition string as MDSL.\n * @returns The root node JSON definitions.\n */\nexport function convertMDSLToJSON(definition: string): RootNodeDefinition[] {\n // Swap out any node/attribute argument string literals with a placeholder and get a mapping of placeholders to original values as well as the processed definition.\n const { placeholders, processedDefinition } = substituteStringLiterals(definition);\n\n // Parse our definition definition string into an array of raw tokens.\n const tokens = parseTokensFromDefinition(processedDefinition);\n\n return convertTokensToJSONDefinition(tokens, placeholders);\n}\n\n/**\n * Converts the specified tree definition tokens into a JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The root node JSON definitions.\n */\nfunction convertTokensToJSONDefinition(\n tokens: string[],\n stringLiteralPlaceholders: StringLiteralPlaceholders\n): RootNodeDefinition[] {\n // There must be at least 3 tokens for the tree definition to be valid. 'ROOT', '{' and '}'.\n if (tokens.length < 3) {\n throw new Error(\"invalid token count\");\n }\n\n // We should have a matching number of '{' and '}' tokens. If not, then there are scopes that have not been properly closed.\n if (tokens.filter((token) => token === \"{\").length !== tokens.filter((token) => token === \"}\").length) {\n throw new Error(\"scope character mismatch\");\n }\n\n // Create an array of tree stack arrays where root nodes will always be at the botton and the current composite/decorator node at the top.\n // There should be an element in this array for every root node defined and every element should be an array with a root note as the first element.\n // E.g. A definition with two root nodes defined:\n // [\n // [root, lotto, sequence],\n // [root, selector]\n // ]\n const treeStacks: [Partial, ...Partial[]][] = [];\n\n // Create an array of all root node definitions that we create.\n const rootNodes: Partial[] = [];\n\n // A helper function used to push node definitions onto the tree stack.\n const pushNode = (node: AnyNodeDefinition) => {\n // If the node is a root node then we need to create a new tree stack array with the root node at the root.\n if (isRootNode(node)) {\n // We need to double-check that this root node is not the child of another node.\n // We can do this by checking whether the top tree stack is not empty (contains an existing node)\n if (treeStacks[treeStacks.length - 1]?.length) {\n throw new Error(\"a root node cannot be the child of another node\");\n }\n\n // Add the root node definition to our array of all parsed root node definitions.\n rootNodes.push(node);\n\n // Add the root node definition to the root of a new tree stack.\n treeStacks.push([node]);\n\n return;\n }\n\n // All non-root nodes should be pushed after their root nodes so handle cases\n // where we may not have any tree stacks or our top-most tree stack is empty.\n if (!treeStacks.length || !treeStacks[treeStacks.length - 1].length) {\n throw new Error(\"expected root node at base of definition\");\n }\n\n // Get the current tree stack that we are populating.\n const topTreeStack = treeStacks[treeStacks.length - 1];\n\n // Get the top-most node in the current tree stack, this will be a composite/decorator node\n // for which we will populate its children array if composite or setting its child if a decorator.\n const topTreeStackTopNode = topTreeStack[topTreeStack.length - 1] as AnyNodeDefinition;\n\n // If the top-most node in the current root stack is a composite or decorator\n // node then the current node should be added as a child of the top-most node.\n if (isCompositeNode(topTreeStackTopNode)) {\n topTreeStackTopNode.children = topTreeStackTopNode.children || [];\n topTreeStackTopNode.children.push(node);\n } else if (isDecoratorNode(topTreeStackTopNode)) {\n // If the top node already has a child node set then throw an error as a decorator should only have a single child.\n if (topTreeStackTopNode.child) {\n throw new Error(\"a decorator node must only have a single child node\");\n }\n\n topTreeStackTopNode.child = node;\n }\n\n // If the node we are adding is also a composite or decorator node, then we should push it\n // onto the current tree stack, as subsequent nodes will be added as its child/children.\n if (!isLeafNode(node)) {\n topTreeStack.push(node);\n }\n };\n\n // A helper function used to pop the top-most node definition off of the tree stack and return it.\n const popNode = (): AnyNodeDefinition | null => {\n let poppedNode: AnyNodeDefinition | null = null;\n\n // Get the current tree stack that we are populating.\n const topTreeStack = treeStacks[treeStacks.length - 1];\n\n // Pop the top-most node in the current tree stack if there is one.\n if (topTreeStack.length) {\n poppedNode = topTreeStack.pop() as AnyNodeDefinition;\n }\n\n // We don't want any empty tree stacks in our stack of tree stacks.\n if (!topTreeStack.length) {\n treeStacks.pop();\n }\n\n return poppedNode;\n };\n\n // We should keep processing the raw tokens until we run out of them.\n while (tokens.length) {\n // Grab the next token.\n const token = tokens.shift()!;\n\n // How we create the next node depends on the current raw token value.\n switch (token.toUpperCase()) {\n case \"ROOT\": {\n pushNode(createRootNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"SUCCEED\": {\n pushNode(createSucceedNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"FAIL\": {\n pushNode(createFailNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"FLIP\": {\n pushNode(createFlipNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"REPEAT\": {\n pushNode(createRepeatNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"RETRY\": {\n pushNode(createRetryNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"SEQUENCE\": {\n pushNode(createSequenceNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"SELECTOR\": {\n pushNode(createSelectorNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"PARALLEL\": {\n pushNode(createParallelNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"LOTTO\": {\n pushNode(createLottoNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"ACTION\": {\n pushNode(createActionNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"CONDITION\": {\n pushNode(createConditionNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"WAIT\": {\n pushNode(createWaitNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"BRANCH\": {\n pushNode(createBranchNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"}\": {\n // The '}' character closes the current scope and means that we have to pop a node off of the current stack.\n const poppedNode = popNode();\n\n // Now that we have a node definition we can carry out any validation that may require the node to be fully populated.\n if (poppedNode) {\n validatePoppedNode(poppedNode);\n }\n\n break;\n }\n\n default: {\n throw new Error(`unexpected token: ${token}`);\n }\n }\n }\n\n return rootNodes as RootNodeDefinition[];\n}\n\n/**\n * Creates a root node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The root node JSON definition.\n */\nfunction createRootNode(tokens: string[], stringLiteralPlaceholders: StringLiteralPlaceholders): RootNodeDefinition {\n // Create the root node definition.\n let node = {\n type: \"root\",\n id: undefined\n } as RootNodeDefinition;\n\n // Parse any node arguments, we should only have one if any which will be an identifier argument for the root identifier.\n const nodeArguments = parseArgumentTokens(tokens, stringLiteralPlaceholders);\n\n // Check whether any node arguments were defined.\n if (nodeArguments.length) {\n // We should only have one argument, if any, which will be an identifier argument for the root identifier.\n if (nodeArguments.length === 1 && nodeArguments[0].type === \"identifier\") {\n // The root node identifier will be the first and only node argument value.\n node.id = nodeArguments[0].value as string;\n } else {\n throw new Error(\"expected single root name argument\");\n }\n }\n\n // Grab any node attribute definitions and spread them into the node definition.\n node = { ...node, ...parseAttributeTokens(tokens, stringLiteralPlaceholders) };\n\n // This is a decorator node, so we expect an opening '{'.\n popAndCheck(tokens, \"{\");\n\n // Return the root node definition.\n return node;\n}\n\n/**\n * Creates a succeed node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The succeed node JSON definition.\n */\nfunction createSucceedNode(\n tokens: string[],\n stringLiteralPlaceholders: StringLiteralPlaceholders\n): SucceedNodeDefinition {\n const node = {\n type: \"succeed\",\n ...parseAttributeTokens(tokens, stringLiteralPlaceholders)\n } as SucceedNodeDefinition;\n\n // This is a decorator node, so we expect an opening '{'.\n popAndCheck(tokens, \"{\");\n\n // Return the succeed node definition.\n return node;\n}\n\n/**\n * Creates a fail node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The fail node JSON definition.\n */\nfunction createFailNode(tokens: string[], stringLiteralPlaceholders: StringLiteralPlaceholders): FailNodeDefinition {\n const node = {\n type: \"fail\",\n ...parseAttributeTokens(tokens, stringLiteralPlaceholders)\n } as FailNodeDefinition;\n\n // This is a decorator node, so we expect an opening '{'.\n popAndCheck(tokens, \"{\");\n\n // Return the fail node definition.\n return node;\n}\n\n/**\n * Creates a flip node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The flip node JSON definition.\n */\nfunction createFlipNode(tokens: string[], stringLiteralPlaceholders: StringLiteralPlaceholders): FlipNodeDefinition {\n const node = {\n type: \"flip\",\n ...parseAttributeTokens(tokens, stringLiteralPlaceholders)\n } as FlipNodeDefinition;\n\n // This is a decorator node, so we expect an opening '{'.\n popAndCheck(tokens, \"{\");\n\n // Return the flip node definition.\n return node;\n}\n\n/**\n * Creates a repeat node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The repeat node JSON definition.\n */\nfunction createRepeatNode(\n tokens: string[],\n stringLiteralPlaceholders: StringLiteralPlaceholders\n): RepeatNodeDefinition {\n let node = { type: \"repeat\" } as RepeatNodeDefinition;\n\n // Get the node arguments.\n const nodeArguments = parseArgumentTokens(tokens, stringLiteralPlaceholders);\n\n // The arguments of a repeat node are optional. We may have:\n // - No node arguments, in which case the repeat note will iterate indefinitely.\n // - One node argument which will be the explicit number of iterations to make.\n // - Two node arguments which define the min and max iteration bounds from which a random iteration count will be picked.\n if (nodeArguments.length) {\n // All repeat node arguments MUST be of type number and must be integer.\n nodeArguments\n .filter((arg) => arg.type !== \"number\" || !arg.isInteger)\n .forEach(() => {\n throw new Error(`repeat node iteration counts must be integer values`);\n });\n\n // We should have got one or two iteration counts.\n if (nodeArguments.length === 1) {\n // A static iteration count was defined.\n node.iterations = nodeArguments[0].value as number;\n\n // A repeat node must have a positive number of iterations if defined.\n if (node.iterations < 0) {\n throw new Error(\"a repeat node must have a positive number of iterations if defined\");\n }\n } else if (nodeArguments.length === 2) {\n // A minimum and maximum iteration count was defined.\n node.iterations = [nodeArguments[0].value as number, nodeArguments[1].value as number];\n\n // A repeat node must have a positive min and max iteration count if they are defined.\n if (node.iterations[0] < 0 || node.iterations[1] < 0) {\n throw new Error(\"a repeat node must have a positive minimum and maximum iteration count if defined\");\n }\n\n // A repeat node must not have an minimum iteration count that exceeds the maximum iteration count.\n if (node.iterations[0] > node.iterations[1]) {\n throw new Error(\n \"a repeat node must not have a minimum iteration count that exceeds the maximum iteration count\"\n );\n }\n } else {\n // An incorrect number of iteration counts was defined.\n throw new Error(\"invalid number of repeat node iteration count arguments defined\");\n }\n }\n\n // Grab any node attribute definitions and spread them into the node definition.\n node = { ...node, ...parseAttributeTokens(tokens, stringLiteralPlaceholders) };\n\n // This is a decorator node, so we expect an opening '{'.\n popAndCheck(tokens, \"{\");\n\n // Return the repeat node definition.\n return node;\n}\n\n/**\n * Creates a retry node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The retry node JSON definition.\n */\nfunction createRetryNode(tokens: string[], stringLiteralPlaceholders: StringLiteralPlaceholders): RetryNodeDefinition {\n let node = { type: \"retry\" } as RetryNodeDefinition;\n\n // Get the node arguments.\n const nodeArguments = parseArgumentTokens(tokens, stringLiteralPlaceholders);\n\n // The arguments of a retry node are optional. We may have:\n // - No node arguments, in which case the retry note will attempt indefinitely.\n // - One node argument which will be the explicit number of attempts to make.\n // - Two node arguments which define the min and max attempt bounds from which a random attempt count will be picked.\n if (nodeArguments.length) {\n // All retry node arguments MUST be of type number and must be integer.\n nodeArguments\n .filter((arg) => arg.type !== \"number\" || !arg.isInteger)\n .forEach(() => {\n throw new Error(`retry node attempt counts must be integer values`);\n });\n\n // We should have got one or two attempt counts.\n if (nodeArguments.length === 1) {\n // A static attempt count was defined.\n node.attempts = nodeArguments[0].value as number;\n\n // A retry node must have a positive number of attempts if defined.\n if (node.attempts < 0) {\n throw new Error(\"a retry node must have a positive number of attempts if defined\");\n }\n } else if (nodeArguments.length === 2) {\n // A minimum and maximum attempt count was defined.\n node.attempts = [nodeArguments[0].value as number, nodeArguments[1].value as number];\n\n // A retry node must have a positive min and max attempts count if they are defined.\n if (node.attempts[0] < 0 || node.attempts[1] < 0) {\n throw new Error(\"a retry node must have a positive minimum and maximum attempt count if defined\");\n }\n\n // A retry node must not have a minimum attempt count that exceeds the maximum attempt count.\n if (node.attempts[0] > node.attempts[1]) {\n throw new Error(\n \"a retry node must not have a minimum attempt count that exceeds the maximum attempt count\"\n );\n }\n } else {\n // An incorrect number of attempt counts was defined.\n throw new Error(\"invalid number of retry node attempt count arguments defined\");\n }\n }\n\n // Grab any node attribute definitions and spread them into the node definition.\n node = { ...node, ...parseAttributeTokens(tokens, stringLiteralPlaceholders) };\n\n // This is a decorator node, so we expect an opening '{'.\n popAndCheck(tokens, \"{\");\n\n // Return the retry node definition.\n return node;\n}\n\n/**\n * Creates a sequence node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The sequence node JSON definition.\n */\nfunction createSequenceNode(\n tokens: string[],\n stringLiteralPlaceholders: StringLiteralPlaceholders\n): SequenceNodeDefinition {\n const node = {\n type: \"sequence\",\n ...parseAttributeTokens(tokens, stringLiteralPlaceholders)\n } as SequenceNodeDefinition;\n\n // This is a composite node, so we expect an opening '{'.\n popAndCheck(tokens, \"{\");\n\n // Return the sequence node definition.\n return node;\n}\n\n/**\n * Creates a selector node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The selector node JSON definition.\n */\nfunction createSelectorNode(\n tokens: string[],\n stringLiteralPlaceholders: StringLiteralPlaceholders\n): SelectorNodeDefinition {\n const node = {\n type: \"selector\",\n ...parseAttributeTokens(tokens, stringLiteralPlaceholders)\n } as SelectorNodeDefinition;\n\n // This is a composite node, so we expect an opening '{'.\n popAndCheck(tokens, \"{\");\n\n // Return the selector node definition.\n return node;\n}\n\n/**\n * Creates a parallel node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The parallel node JSON definition.\n */\nfunction createParallelNode(\n tokens: string[],\n stringLiteralPlaceholders: StringLiteralPlaceholders\n): ParallelNodeDefinition {\n const node = {\n type: \"parallel\",\n ...parseAttributeTokens(tokens, stringLiteralPlaceholders)\n } as ParallelNodeDefinition;\n\n // This is a composite node, so we expect an opening '{'.\n popAndCheck(tokens, \"{\");\n\n // Return the parallel node definition.\n return node;\n}\n\n/**\n * Creates a lotto node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The lotto node JSON definition.\n */\nfunction createLottoNode(tokens: string[], stringLiteralPlaceholders: StringLiteralPlaceholders): LottoNodeDefinition {\n // If any node arguments have been defined then they must be our weights.\n const nodeArguments = parseArgumentTokens(tokens, stringLiteralPlaceholders);\n\n // All lotto node arguments MUST be of type number and must be positive integers.\n nodeArguments\n .filter((arg) => arg.type !== \"number\" || !arg.isInteger || arg.value < 0)\n .forEach(() => {\n throw new Error(`lotto node weight arguments must be positive integer values`);\n });\n\n const node = {\n type: \"lotto\",\n weights: nodeArguments.length ? nodeArguments.map(({ value }) => value) : undefined,\n ...parseAttributeTokens(tokens, stringLiteralPlaceholders)\n } as LottoNodeDefinition;\n\n // This is a composite node, so we expect an opening '{'.\n popAndCheck(tokens, \"{\");\n\n // Return the lotto node definition.\n return node;\n}\n\n/**\n * Creates an action node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The action node JSON definition.\n */\nfunction createActionNode(\n tokens: string[],\n stringLiteralPlaceholders: StringLiteralPlaceholders\n): ActionNodeDefinition {\n // Parse any node arguments, we should have at least one which will be an identifier argument for the action name\n // and agent function to invoke for the action, all other arguments are to be passed as arguments to that function.\n const [actionNameIdentifier, ...agentFunctionArgs] = parseArgumentTokens(tokens, stringLiteralPlaceholders);\n\n // Our first argument MUST be defined and be an identifier as we require an action name argument.\n if (actionNameIdentifier?.type !== \"identifier\") {\n throw new Error(\"expected action name identifier argument\");\n }\n\n // Only the first argument should have been an identifier, all agent function arguments must be string, number, boolean or null.\n agentFunctionArgs\n .filter((arg) => arg.type === \"identifier\")\n .forEach((arg) => {\n throw new Error(\n `invalid action node argument value '${arg.value}', must be string, number, boolean or null`\n );\n });\n\n // Return the action node definition.\n return {\n type: \"action\",\n call: actionNameIdentifier.value,\n args: agentFunctionArgs.map(({ value }) => value),\n ...parseAttributeTokens(tokens, stringLiteralPlaceholders)\n };\n}\n\n/**\n * Creates a condition node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The condition node JSON definition.\n */\nfunction createConditionNode(\n tokens: string[],\n stringLiteralPlaceholders: StringLiteralPlaceholders\n): ConditionNodeDefinition {\n // Parse any node arguments, we should have at least one which will be an identifier argument for the condition name\n // and agent function to invoke for the condition, all other arguments are to be passed as arguments to that function.\n const [conditionNameIdentifier, ...agentFunctionArgs] = parseArgumentTokens(tokens, stringLiteralPlaceholders);\n\n // Our first argument MUST be defined and be an identifier as we require a condition name argument.\n if (conditionNameIdentifier?.type !== \"identifier\") {\n throw new Error(\"expected condition name identifier argument\");\n }\n\n // Only the first argument should have been an identifier, all agent function arguments must be string, number, boolean or null.\n agentFunctionArgs\n .filter((arg) => arg.type === \"identifier\")\n .forEach((arg) => {\n throw new Error(\n `invalid condition node argument value '${arg.value}', must be string, number, boolean or null`\n );\n });\n\n // Return the condition node definition.\n return {\n type: \"condition\",\n call: conditionNameIdentifier.value,\n args: agentFunctionArgs.map(({ value }) => value),\n ...parseAttributeTokens(tokens, stringLiteralPlaceholders)\n };\n}\n\n/**\n * Creates a wait node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The wait node JSON definition.\n */\nfunction createWaitNode(tokens: string[], stringLiteralPlaceholders: StringLiteralPlaceholders): WaitNodeDefinition {\n let node = { type: \"wait\" } as WaitNodeDefinition;\n\n // Get the node arguments.\n const nodeArguments = parseArgumentTokens(tokens, stringLiteralPlaceholders);\n\n // The arguments of a wait node are optional. We may have:\n // - No node arguments, in which case the wait will be indefinite until it is aborted.\n // - One node argument which will be the explicit duration of the wait.\n // - Two node arguments which define the min and max duration bounds from which a random duration will be picked.\n if (nodeArguments.length) {\n // All wait node arguments MUST be of type number and must be integer.\n nodeArguments\n .filter((arg) => arg.type !== \"number\" || !arg.isInteger)\n .forEach(() => {\n throw new Error(`wait node durations must be integer values`);\n });\n\n // We may have:\n // - One node argument which will be the explicit duration of the wait.\n // - Two node arguments which define the min and max duration bounds from which a random duration will be picked.\n // - Too many arguments, which is not valid.\n if (nodeArguments.length === 1) {\n // An explicit duration was defined.\n node.duration = nodeArguments[0].value as number;\n\n // If an explict duration was defined then it must be a positive number.\n if (node.duration < 0) {\n throw new Error(\"a wait node must have a positive duration\");\n }\n } else if (nodeArguments.length === 2) {\n // Min and max duration bounds were defined from which a random duration will be picked.\n node.duration = [nodeArguments[0].value as number, nodeArguments[1].value as number];\n\n // A wait node must have a positive min and max duration.\n if (node.duration[0] < 0 || node.duration[1] < 0) {\n throw new Error(\"a wait node must have a positive minimum and maximum duration\");\n }\n\n // A wait node must not have a minimum duration that exceeds the maximum duration.\n if (node.duration[0] > node.duration[1]) {\n throw new Error(\"a wait node must not have a minimum duration that exceeds the maximum duration\");\n }\n } else if (nodeArguments.length > 2) {\n // An incorrect number of duration arguments were defined.\n throw new Error(\"invalid number of wait node duration arguments defined\");\n }\n }\n\n // Return the wait node definition.\n return { ...node, ...parseAttributeTokens(tokens, stringLiteralPlaceholders) };\n}\n\n/**\n * Creates a branch node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The branch node JSON definition.\n */\nfunction createBranchNode(\n tokens: string[],\n stringLiteralPlaceholders: StringLiteralPlaceholders\n): BranchNodeDefinition {\n // Parse any node arguments, we should have one which will be an identifier argument for the root ref.\n const nodeArguments = parseArgumentTokens(tokens, stringLiteralPlaceholders);\n\n // We should have only a single identifer argument for a branch node, which is the root ref.\n if (nodeArguments.length !== 1 || nodeArguments[0].type !== \"identifier\") {\n throw new Error(\"expected single branch name argument\");\n }\n\n // Return the branch node definition.\n return { type: \"branch\", ref: nodeArguments[0].value };\n}\n\n/**\n * Validate a fully-populated node definition that was popped off of the tree stack.\n * @param definition The popped node to validate.\n */\nfunction validatePoppedNode(definition: AnyNodeDefinition): void {\n // Decorators MUST have a child defined.\n if (isDecoratorNode(definition) && isNullOrUndefined(definition.child)) {\n throw new Error(`a ${definition.type} node must have a single child node defined`);\n }\n\n // Composites MUST have at least one child defined.\n if (isCompositeNode(definition) && !definition.children?.length) {\n throw new Error(`a ${definition.type} node must have at least a single child node defined`);\n }\n\n // We need to make sure that lotto nodes that have weights defined have a number of weights matching the number of child nodes.\n if (definition.type === \"lotto\") {\n // Check whether a 'weights' property has been defined, if it has we expect it to be an array of weights.\n if (typeof definition.weights !== \"undefined\") {\n // Check that the weights property is an array of positive integers with an element for each child node element.\n if (definition.weights.length !== definition.children.length) {\n throw new Error(\n \"expected a number of weight arguments matching the number of child nodes for lotto node\"\n );\n }\n }\n }\n}\n", "import { RootNodeDefinition } from \"./BehaviourTreeDefinition\";\nimport { flattenDefinition, isBranchNode, isInteger } from \"./BehaviourTreeDefinitionUtilities\";\nimport { convertMDSLToJSON } from \"./mdsl/MDSLDefinitionParser\";\n\n/**\n * An object representing the result of validating a tree definition.\n */\nexport type DefinitionValidationResult = {\n /**\n * A flag defining whether validation succeeded.\n */\n succeeded: boolean;\n /**\n * A string containing the error message if validation did not succeed.\n */\n errorMessage?: string;\n /**\n * The definition as json if the validation was successful, or undefined if validation did not succeed.\n */\n json?: RootNodeDefinition[];\n};\n\n/**\n * Validates the specified behaviour tree definition in the form of JSON or MDSL, not taking any globally registered subtrees into consideration.\n * @param definition The behaviour tree definition in the form of JSON or MDSL.\n * @returns An object representing the result of validating the given tree definition.\n */\nexport function validateDefinition(definition: any): DefinitionValidationResult {\n // The definition must be defined.\n if (definition === null || typeof definition === \"undefined\") {\n return createValidationFailureResult(\"definition is null or undefined\");\n }\n\n // We are expecting a definition in one of three different forms:\n // - A string which we will assume is MDSL and we will parse this to JSON before validation.\n // - An array which we will assume is an array of root node definitions with at least one being the primary root node (no 'id' property)\n // - An object which we will assume is the primary root node and should not have an 'id' property.\n if (typeof definition === \"string\") {\n // The definition is a string which we can assume is MDSL, so attempt to validate it.\n return validateMDSLDefinition(definition);\n } else if (typeof definition === \"object\") {\n // The definition will either be an array (of root node definitions) or an object (the single primary root node definition).\n return validateJSONDefinition(definition);\n } else {\n return createValidationFailureResult(`unexpected definition type of '${typeof definition}'`);\n }\n}\n\n/**\n * Validates the specified behaviour tree definition in the form of MDSL.\n * @param definition The behaviour tree definition in the form of MDSL.\n * @returns An object representing the result of validating the given tree definition.\n */\nfunction validateMDSLDefinition(definition: string): DefinitionValidationResult {\n let rootNodeDefinitions;\n\n // The first thing the we need to do is to attempt to convert our MDSL into JSON.\n try {\n // The definition is a string which we can assume is MDSL, so attempt to parse it to a JSON definition in the form of an array of root node definitions.\n rootNodeDefinitions = convertMDSLToJSON(definition);\n } catch (exception) {\n // We failed to parse the JSON from the MDSL, this is likely to be the result of it not being a valid MDSL string.\n return createValidationFailureResult((exception as Error).message);\n }\n\n // Unpack all of the root node definitions into arrays of main ('id' defined) and sub ('id' not defined) root node definitions.\n const mainRootNodeDefinitions = rootNodeDefinitions.filter(({ id }) => typeof id === \"undefined\");\n const subRootNodeDefinitions = rootNodeDefinitions.filter(({ id }) => typeof id === \"string\" && id.length > 0);\n\n // We should ALWAYS have exactly one root node definition without an 'id' property defined, which is out main root node definition.\n if (mainRootNodeDefinitions.length !== 1) {\n return createValidationFailureResult(\n \"expected single unnamed root node at base of definition to act as main root\"\n );\n }\n\n // We should never have duplicate 'id' properties across our sub root node definitions.\n const subRootNodeIdenitifers: string[] = [];\n for (const { id } of subRootNodeDefinitions) {\n // Have we already come across this 'id' property value?\n if (subRootNodeIdenitifers.includes(id!)) {\n return createValidationFailureResult(`multiple root nodes found with duplicate name '${id}'`);\n }\n\n subRootNodeIdenitifers.push(id!);\n }\n\n try {\n // Validate our branch -> subtree links and check for any circular dependencies, we don't care about checking for broken subtree links here.\n validateBranchSubtreeLinks(rootNodeDefinitions, false);\n } catch (exception) {\n return createValidationFailureResult((exception as Error).message);\n }\n\n // Our definition was valid!\n return {\n succeeded: true,\n json: rootNodeDefinitions\n };\n}\n\n/**\n * Validates the specified behaviour tree definition in the form of JSON.\n * @param definition The behaviour tree definition in the form of JSON.\n * @returns An object representing the result of validating the given tree definition.\n */\nexport function validateJSONDefinition(\n definition: RootNodeDefinition | RootNodeDefinition[]\n): DefinitionValidationResult {\n // The definition will either be an array (of root node definitions) or an object (the single primary root node definition).\n const rootNodeDefinitions = Array.isArray(definition) ? definition : [definition];\n\n // Iterate over our array of root nodes and call validateNode for each, passing an initial depth of 0, wrapped in a try catch to handle validation failures.\n try {\n rootNodeDefinitions.forEach((rootNodeDefinition) => validateNode(rootNodeDefinition, 0));\n } catch (error) {\n // Handle cases where we have caught a thrown Error and return a failure result with the error message.\n if (error instanceof Error) {\n return createValidationFailureResult(error.message);\n }\n\n // No idea what happened here!\n return createValidationFailureResult(`unexpected error: ${error}`);\n }\n\n // Unpack all of the root node definitions into arrays of main ('id' defined) and sub ('id' not defined) root node definitions.\n const mainRootNodeDefinitions = rootNodeDefinitions.filter(({ id }) => typeof id === \"undefined\");\n const subRootNodeDefinitions = rootNodeDefinitions.filter(({ id }) => typeof id === \"string\" && id.length > 0);\n\n // We should ALWAYS have exactly one root node definition without an 'id' property defined, which is out main root node definition.\n if (mainRootNodeDefinitions.length !== 1) {\n return createValidationFailureResult(\n \"expected single root node without 'id' property defined to act as main root\"\n );\n }\n\n // We should never have duplicate 'id' properties across our sub root node definitions.\n const subRootNodeIdenitifers: string[] = [];\n for (const { id } of subRootNodeDefinitions) {\n // Have we already come across this 'id' property value?\n if (subRootNodeIdenitifers.includes(id!)) {\n return createValidationFailureResult(\n `multiple root nodes found with duplicate 'id' property value of '${id}'`\n );\n }\n\n subRootNodeIdenitifers.push(id!);\n }\n\n try {\n // Validate our branch -> subtree links and check for any circular dependencies, we don't care about checking for broken subtree links here.\n validateBranchSubtreeLinks(rootNodeDefinitions, false);\n } catch (exception) {\n return createValidationFailureResult((exception as Error).message);\n }\n\n // Our definition was valid!\n return {\n succeeded: true,\n json: rootNodeDefinitions\n };\n}\n\n/**\n * Validates the branch -> subtree links across all provided root node definitions.\n * This will not consider branch nodes that reference any globally registered subtrees unless includesGlobalSubtrees\n * is set to true, in which case we will also verify that there are no broken branch -> subtree links.\n * @param rootNodeDefinitions The array of root node definitions.\n * @param includesGlobalSubtrees A flag defining whether the array includes all global subtree root node definitions.\n */\nexport function validateBranchSubtreeLinks(rootNodeDefinitions: RootNodeDefinition[], includesGlobalSubtrees: boolean) {\n // Create a mapping of root node identifiers to other root nodes that they reference via branch nodes.\n // Below is an example of a mapping that includes a circular dependency (root => a => b => c => a)\n // [{ refs: [\"a\", \"b\"] }, { id: \"a\", refs: [\"b\"] }, { id: \"b\", refs: [\"c\"] }, { id: \"c\", refs: [\"a\"] }]\n const rootNodeMappings: { id: string | undefined; refs: string[] }[] = rootNodeDefinitions.map(\n (rootNodeDefinition) => ({\n id: rootNodeDefinition.id,\n refs: flattenDefinition(rootNodeDefinition)\n .filter(isBranchNode)\n .map(({ ref }) => ref)\n })\n );\n\n // A recursive function to walk through the mappings, keeping track of which root nodes we have visited in the form of a path of root node identifiers.\n const followRefs = (mapping: { id: string | undefined; refs: string[] }, path: (string | undefined)[] = []) => {\n // Have we found a circular dependency?\n if (path.includes(mapping.id)) {\n // We found a circular dependency! Get the bad path of root node identifiers.\n const badPath = [...path, mapping.id];\n\n // Create the formatted path value. [undefined, \"a\", \"b\", \"c\", \"a\"] would be formatted as \"a -> b -> c -> a\".\n const badPathFormatted = badPath.filter((element) => !!element).join(\" => \");\n\n // No need to continue, we found a circular dependency.\n throw new Error(`circular dependency found in branch node references: ${badPathFormatted}`);\n }\n\n for (const ref of mapping.refs) {\n // Find the mapping for the root node with an identifer matching the current ref.\n const subMapping = rootNodeMappings.find(({ id }) => id === ref);\n\n // We may not have a mapping for this ref, which is normal when we aren't considering all globally registered subtrees.\n if (subMapping) {\n followRefs(subMapping, [...path, mapping.id]);\n } else if (includesGlobalSubtrees) {\n // We found a reference to a root node that doesn't exist, which is a problem seeing as the root node definitons includes all globally registered subtrees.\n throw new Error(\n mapping.id\n ? `subtree '${mapping.id}' has branch node that references root node '${ref}' which has not been defined`\n : `primary tree has branch node that references root node '${ref}' which has not been defined`\n );\n }\n }\n };\n\n // Start looking for circular dependencies and broken references from the primary root node definition.\n followRefs(rootNodeMappings.find((mapping) => typeof mapping.id === \"undefined\")!);\n}\n\n/**\n * Validate an object that we expect to be a node definition.\n * @param definition An object that we expect to be a node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateNode(definition: any, depth: number): void {\n // Every node must be valid object and have a non-empty 'type' string property.\n if (typeof definition !== \"object\" || typeof definition.type !== \"string\" || definition.type.length === 0) {\n throw new Error(\n `node definition is not an object or 'type' property is not a non-empty string at depth '${depth}'`\n );\n }\n\n // How we validate this node definition will depend on its type.\n switch (definition.type) {\n case \"action\":\n validateActionNode(definition, depth);\n break;\n\n case \"condition\":\n validateConditionNode(definition, depth);\n break;\n\n case \"wait\":\n validateWaitNode(definition, depth);\n break;\n\n case \"branch\":\n validateBranchNode(definition, depth);\n break;\n\n case \"root\":\n validateRootNode(definition, depth);\n break;\n\n case \"succeed\":\n validateSucceedNode(definition, depth);\n break;\n\n case \"fail\":\n validateFailNode(definition, depth);\n break;\n\n case \"flip\":\n validateFlipNode(definition, depth);\n break;\n\n case \"repeat\":\n validateRepeatNode(definition, depth);\n break;\n\n case \"retry\":\n validateRetryNode(definition, depth);\n break;\n\n case \"sequence\":\n validateSequenceNode(definition, depth);\n break;\n\n case \"selector\":\n validateSelectorNode(definition, depth);\n break;\n\n case \"parallel\":\n validateParallelNode(definition, depth);\n break;\n\n case \"lotto\":\n validateLottoNode(definition, depth);\n break;\n\n default:\n throw new Error(`unexpected node type of '${definition.type}' at depth '${depth}'`);\n }\n}\n\n/**\n * Validate any attributes for a given node definition.\n * @param definition The node definition.\n * @param depth The depth of the node in the behaviour tree definition.\n */\nfunction validateNodeAttributes(definition: any, depth: number): void {\n // Validate each of the attribute types for this node.\n [\"while\", \"until\", \"entry\", \"exit\", \"step\"].forEach((attributeName) => {\n // Attempt to grab the definition for the current attribute from the node definition.\n const attributeDefinition = definition[attributeName];\n\n // All node attributes are optional, so there is nothing to do if the current attribute is not defined.\n if (typeof attributeDefinition === \"undefined\") {\n return;\n }\n\n // The attribute definition must be an object.\n if (typeof attributeDefinition !== \"object\") {\n throw new Error(\n `expected attribute '${attributeName}' to be an object for '${definition.type}' node at depth '${depth}'`\n );\n }\n\n // The 'call' property must be defined for any attribute definition.\n if (typeof attributeDefinition.call !== \"string\" || attributeDefinition.call.length === 0) {\n throw new Error(\n `expected 'call' property for attribute '${attributeName}' to be a non-empty string for '${definition.type}' node at depth '${depth}'`\n );\n }\n\n // If any node attribute arguments have been defined then they must have been defined in an array.\n if (typeof attributeDefinition.args !== \"undefined\" && !Array.isArray(attributeDefinition.args)) {\n throw new Error(\n `expected 'args' property for attribute '${attributeName}' to be an array for '${definition.type}' node at depth '${depth}'`\n );\n }\n });\n}\n\n/**\n * Validate an object that we expect to be a root node definition.\n * @param definition An object that we expect to be a root node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateRootNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"root\") {\n throw new Error(\"expected node type of 'root' for root node\");\n }\n\n // A root node cannot be the child of another node.\n if (depth > 0) {\n throw new Error(\"a root node cannot be the child of another node\");\n }\n\n // Check that, if the root node 'id' property is defined, it is a non-empty string.\n if (typeof definition.id !== \"undefined\" && (typeof definition.id !== \"string\" || definition.id.length === 0)) {\n throw new Error(\"expected non-empty string for 'id' property if defined for root node\");\n }\n\n // A root node is a decorator node, so must have a child node defined.\n if (typeof definition.child === \"undefined\") {\n throw new Error(\"expected property 'child' to be defined for root node\");\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n\n // Validate the child node of this decorator node.\n validateNode(definition.child, depth + 1);\n}\n\n/**\n * Validate an object that we expect to be a succeed node definition.\n * @param definition An object that we expect to be a succeed node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateSucceedNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"succeed\") {\n throw new Error(`expected node type of 'succeed' for succeed node at depth '${depth}'`);\n }\n\n // A succeed node is a decorator node, so must have a child node defined.\n if (typeof definition.child === \"undefined\") {\n throw new Error(`expected property 'child' to be defined for succeed node at depth '${depth}'`);\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n\n // Validate the child node of this decorator node.\n validateNode(definition.child, depth + 1);\n}\n\n/**\n * Validate an object that we expect to be a fail node definition.\n * @param definition An object that we expect to be a fail node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateFailNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"fail\") {\n throw new Error(`expected node type of 'fail' for fail node at depth '${depth}'`);\n }\n\n // A fail node is a decorator node, so must have a child node defined.\n if (typeof definition.child === \"undefined\") {\n throw new Error(`expected property 'child' to be defined for fail node at depth '${depth}'`);\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n\n // Validate the child node of this decorator node.\n validateNode(definition.child, depth + 1);\n}\n\n/**\n * Validate an object that we expect to be a flip node definition.\n * @param definition An object that we expect to be a flip node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateFlipNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"flip\") {\n throw new Error(`expected node type of 'flip' for flip node at depth '${depth}'`);\n }\n\n // A flip node is a decorator node, so must have a child node defined.\n if (typeof definition.child === \"undefined\") {\n throw new Error(`expected property 'child' to be defined for flip node at depth '${depth}'`);\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n\n // Validate the child node of this decorator node.\n validateNode(definition.child, depth + 1);\n}\n\n/**\n * Validate an object that we expect to be a repeat node definition.\n * @param definition An object that we expect to be a repeat node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateRepeatNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"repeat\") {\n throw new Error(`expected node type of 'repeat' for repeat node at depth '${depth}'`);\n }\n\n // A repeat node is a decorator node, so must have a child node defined.\n if (typeof definition.child === \"undefined\") {\n throw new Error(`expected property 'child' to be defined for repeat node at depth '${depth}'`);\n }\n\n // Check whether an 'iterations' property has been defined, it may not have been if this node is to repeat indefinitely.\n if (typeof definition.iterations !== \"undefined\") {\n if (Array.isArray(definition.iterations)) {\n // Check whether any elements of the array are not integer values.\n const containsNonInteger = !!definition.iterations.filter((value: unknown) => !isInteger(value)).length;\n\n // If the 'iterations' property is an array then it MUST contain two integer values.\n if (definition.iterations.length !== 2 || containsNonInteger) {\n throw new Error(\n `expected array containing two integer values for 'iterations' property if defined for repeat node at depth '${depth}'`\n );\n }\n\n // A repeat node must have a positive min and max iterations count if they are defined.\n if (definition.iterations[0] < 0 || definition.iterations[1] < 0) {\n throw new Error(\n `expected positive minimum and maximum iterations count for 'iterations' property if defined for repeat node at depth '${depth}'`\n );\n }\n\n // A repeat node must not have a minimum iterations count that exceeds the maximum iterations count.\n if (definition.iterations[0] > definition.iterations[1]) {\n throw new Error(\n `expected minimum iterations count that does not exceed the maximum iterations count for 'iterations' property if defined for repeat node at depth '${depth}'`\n );\n }\n } else if (isInteger(definition.iterations)) {\n // A repeat node must have a positive number of iterations if defined.\n if (definition.iterations < 0) {\n throw new Error(\n `expected positive iterations count for 'iterations' property if defined for repeat node at depth '${depth}'`\n );\n }\n } else {\n throw new Error(\n `expected integer value or array containing two integer values for 'iterations' property if defined for repeat node at depth '${depth}'`\n );\n }\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n\n // Validate the child node of this decorator node.\n validateNode(definition.child, depth + 1);\n}\n\n/**\n * Validate an object that we expect to be a retry node definition.\n * @param definition An object that we expect to be a retry node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateRetryNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"retry\") {\n throw new Error(`expected node type of 'retry' for retry node at depth '${depth}'`);\n }\n\n // A retry node is a decorator node, so must have a child node defined.\n if (typeof definition.child === \"undefined\") {\n throw new Error(`expected property 'child' to be defined for retry node at depth '${depth}'`);\n }\n\n // Check whether an 'attempts' property has been defined, it may not have been if this node is to retry indefinitely.\n if (typeof definition.attempts !== \"undefined\") {\n if (Array.isArray(definition.attempts)) {\n // Check whether any elements of the array are not integer values.\n const containsNonInteger = !!definition.attempts.filter((value: unknown) => !isInteger(value)).length;\n\n // If the 'attempts' property is an array then it MUST contain two integer values.\n if (definition.attempts.length !== 2 || containsNonInteger) {\n throw new Error(\n `expected array containing two integer values for 'attempts' property if defined for retry node at depth '${depth}'`\n );\n }\n\n // A retry node must have a positive min and max attempts count if they are defined.\n if (definition.attempts[0] < 0 || definition.attempts[1] < 0) {\n throw new Error(\n `expected positive minimum and maximum attempts count for 'attempts' property if defined for retry node at depth '${depth}'`\n );\n }\n\n // A retry node must not have a minimum attempts count that exceeds the maximum attempts count.\n if (definition.attempts[0] > definition.attempts[1]) {\n throw new Error(\n `expected minimum attempts count that does not exceed the maximum attempts count for 'attempts' property if defined for retry node at depth '${depth}'`\n );\n }\n } else if (isInteger(definition.attempts)) {\n // A retry node must have a positive number of attempts if defined.\n if (definition.attempts < 0) {\n throw new Error(\n `expected positive attempts count for 'attempts' property if defined for retry node at depth '${depth}'`\n );\n }\n } else {\n throw new Error(\n `expected integer value or array containing two integer values for 'attempts' property if defined for retry node at depth '${depth}'`\n );\n }\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n\n // Validate the child node of this decorator node.\n validateNode(definition.child, depth + 1);\n}\n\n/**\n * Validate an object that we expect to be a branch node definition.\n * @param definition An object that we expect to be a branch node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateBranchNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"branch\") {\n throw new Error(`expected node type of 'branch' for branch node at depth '${depth}'`);\n }\n\n // Check that the branch node 'ref' property is defined and is a non-empty string.\n if (typeof definition.ref !== \"string\" || definition.ref.length === 0) {\n throw new Error(`expected non-empty string for 'ref' property for branch node at depth '${depth}'`);\n }\n\n // It is invalid to define guard attributes for a branch node as they should be defined on the referenced root node.\n [\"while\", \"until\"].forEach((attributeName) => {\n if (typeof definition[attributeName] !== \"undefined\") {\n throw new Error(\n `guards should not be defined for branch nodes but guard '${attributeName}' was defined for branch node at depth '${depth}'`\n );\n }\n });\n\n // It is invalid to define callback attributes for a branch node as they should be defined on the referenced root node.\n [\"entry\", \"exit\", \"step\"].forEach((attributeName) => {\n if (typeof definition[attributeName] !== \"undefined\") {\n throw new Error(\n `callbacks should not be defined for branch nodes but callback '${attributeName}' was defined for branch node at depth '${depth}'`\n );\n }\n });\n}\n\n/**\n * Validate an object that we expect to be a action node definition.\n * @param definition An object that we expect to be a action node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateActionNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"action\") {\n throw new Error(`expected node type of 'action' for action node at depth '${depth}'`);\n }\n\n // The 'call' property must be defined for a action node definition.\n if (typeof definition.call !== \"string\" || definition.call.length === 0) {\n throw new Error(`expected non-empty string for 'call' property of action node at depth '${depth}'`);\n }\n\n // If any action function arguments have been defined then they must have been defined in an array.\n if (typeof definition.args !== \"undefined\" && !Array.isArray(definition.args)) {\n throw new Error(`expected array for 'args' property if defined for action node at depth '${depth}'`);\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n}\n\n/**\n * Validate an object that we expect to be a condition node definition.\n * @param definition An object that we expect to be a condition node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateConditionNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"condition\") {\n throw new Error(`expected node type of 'condition' for condition node at depth '${depth}'`);\n }\n\n // The 'call' property must be defined for a condition node definition.\n if (typeof definition.call !== \"string\" || definition.call.length === 0) {\n throw new Error(`expected non-empty string for 'call' property of condition node at depth '${depth}'`);\n }\n\n // If any condition function arguments have been defined then they must have been defined in an array.\n if (typeof definition.args !== \"undefined\" && !Array.isArray(definition.args)) {\n throw new Error(`expected array for 'args' property if defined for condition node at depth '${depth}'`);\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n}\n\n/**\n * Validate an object that we expect to be a wait node definition.\n * @param definition An object that we expect to be a wait node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateWaitNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"wait\") {\n throw new Error(`expected node type of 'wait' for wait node at depth '${depth}'`);\n }\n\n // Check whether a 'duration' property has been defined, it may not have been if this node is to wait indefinitely.\n if (typeof definition.duration !== \"undefined\") {\n if (Array.isArray(definition.duration)) {\n // Check whether any elements of the array are not integer values.\n const containsNonInteger = !!definition.duration.filter((value: unknown) => !isInteger(value)).length;\n\n // If the 'duration' property is an array then it MUST contain two integer values.\n if (definition.duration.length !== 2 || containsNonInteger) {\n throw new Error(\n `expected array containing two integer values for 'duration' property if defined for wait node at depth '${depth}'`\n );\n }\n\n // A wait node must have a positive min and max duration value if they are defined.\n if (definition.duration[0] < 0 || definition.duration[1] < 0) {\n throw new Error(\n `expected positive minimum and maximum duration for 'duration' property if defined for wait node at depth '${depth}'`\n );\n }\n\n // A wait node must not have a minimum duration value that exceeds the maximum duration value.\n if (definition.duration[0] > definition.duration[1]) {\n throw new Error(\n `expected minimum duration value that does not exceed the maximum duration value for 'duration' property if defined for wait node at depth '${depth}'`\n );\n }\n } else if (isInteger(definition.duration)) {\n // A wait node must have a positive duration value if defined.\n if (definition.duration < 0) {\n throw new Error(\n `expected positive duration value for 'duration' property if defined for wait node at depth '${depth}'`\n );\n }\n } else {\n throw new Error(\n `expected integer value or array containing two integer values for 'duration' property if defined for wait node at depth '${depth}'`\n );\n }\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n}\n\n/**\n * Validate an object that we expect to be a sequence node definition.\n * @param definition An object that we expect to be a sequence node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateSequenceNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"sequence\") {\n throw new Error(`expected node type of 'sequence' for sequence node at depth '${depth}'`);\n }\n\n // A sequence node is a composite node, so must have a children nodes array defined.\n if (!Array.isArray(definition.children) || definition.children.length === 0) {\n throw new Error(`expected non-empty 'children' array to be defined for sequence node at depth '${depth}'`);\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n\n // Validate the child nodes of this composite node.\n definition.children.forEach((child: any) => validateNode(child, depth + 1));\n}\n\n/**\n * Validate an object that we expect to be a selector node definition.\n * @param definition An object that we expect to be a selector node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateSelectorNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"selector\") {\n throw new Error(`expected node type of 'selector' for selector node at depth '${depth}'`);\n }\n\n // A selector node is a composite node, so must have a children nodes array defined.\n if (!Array.isArray(definition.children) || definition.children.length === 0) {\n throw new Error(`expected non-empty 'children' array to be defined for selector node at depth '${depth}'`);\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n\n // Validate the child nodes of this composite node.\n definition.children.forEach((child: any) => validateNode(child, depth + 1));\n}\n\n/**\n * Validate an object that we expect to be a parallel node definition.\n * @param definition An object that we expect to be a parallel node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateParallelNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"parallel\") {\n throw new Error(`expected node type of 'parallel' for parallel node at depth '${depth}'`);\n }\n\n // A parallel node is a composite node, so must have a children nodes array defined.\n if (!Array.isArray(definition.children) || definition.children.length === 0) {\n throw new Error(`expected non-empty 'children' array to be defined for parallel node at depth '${depth}'`);\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n\n // Validate the child nodes of this composite node.\n definition.children.forEach((child: any) => validateNode(child, depth + 1));\n}\n\n/**\n * Validate an object that we expect to be a lotto node definition.\n * @param definition An object that we expect to be a lotto node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateLottoNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"lotto\") {\n throw new Error(`expected node type of 'lotto' for lotto node at depth '${depth}'`);\n }\n\n // A lotto node is a composite node, so must have a children nodes array defined.\n if (!Array.isArray(definition.children) || definition.children.length === 0) {\n throw new Error(`expected non-empty 'children' array to be defined for lotto node at depth '${depth}'`);\n }\n\n // Check whether a 'weights' property has been defined, if it has we expect it to be an array of weights.\n if (typeof definition.weights !== \"undefined\") {\n // Check that the weights property is an array of positive integers with an element for each child node element.\n if (\n !Array.isArray(definition.weights) ||\n definition.weights.length !== definition.children.length ||\n definition.weights.filter((value: unknown) => !isInteger(value)).length ||\n definition.weights.filter((value: number) => value < 0).length\n ) {\n throw new Error(\n `expected an array of positive integer weight values with a length matching the number of child nodes for 'weights' property if defined for lotto node at depth '${depth}'`\n );\n }\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n\n // Validate the child nodes of this composite node.\n definition.children.forEach((child: any) => validateNode(child, depth + 1));\n}\n\n/**\n * A helper function to create a failure validation result with the given error message.\n * @param errorMessage The validation failure error message.\n * @returns A failure validation result with the given error message.\n */\nfunction createValidationFailureResult(errorMessage: string): DefinitionValidationResult {\n return { succeeded: false, errorMessage };\n}\n", "import { ActionResult, Agent, GlobalFunction } from \"./Agent\";\nimport { RootNodeDefinition } from \"./BehaviourTreeDefinition\";\n\nexport type InvokerFunction = (args: any[]) => ActionResult;\n\n/**\n * A singleton used to store and lookup registered functions and subtrees.\n */\nexport default class Lookup {\n /**\n * The object holding any registered functions keyed on function name.\n */\n private static functionTable: { [key: string]: GlobalFunction } = {};\n /**\n * The object holding any registered subtree root node definitions keyed on tree name.\n */\n private static subtreeTable: { [key: string]: RootNodeDefinition } = {};\n\n /**\n * Gets the function with the specified name.\n * @param name The name of the function.\n * @returns The function with the specified name.\n */\n public static getFunc(name: string): GlobalFunction {\n return this.functionTable[name];\n }\n\n /**\n * Sets the function with the specified name for later lookup.\n * @param name The name of the function.\n * @param func The function.\n */\n public static setFunc(name: string, func: GlobalFunction): void {\n this.functionTable[name] = func;\n }\n\n /**\n * Gets the function invoker for the specified agent and function name.\n * If a function with the specified name exists on the agent object then it will\n * be returned, otherwise we will then check the registered functions for a match.\n * @param agent The agent instance that this behaviour tree is modelling behaviour for.\n * @param name The function name.\n * @returns The function invoker for the specified agent and function name.\n */\n static getFuncInvoker(agent: Agent, name: string): InvokerFunction | null {\n // Check whether the agent contains the specified function.\n const foundOnAgent = agent[name];\n if (foundOnAgent && typeof foundOnAgent === \"function\") {\n return (args: any[]): boolean | ActionResult => foundOnAgent.apply(agent, args);\n }\n\n // The agent does not contain the specified function but it may have been registered at some point.\n if (this.functionTable[name] && typeof this.functionTable[name] === \"function\") {\n return (args: any[]) => this.functionTable[name](agent, ...args.map((arg) => arg.value));\n }\n\n // We have no function to invoke.\n return null;\n }\n\n /**\n * Gets all registered subtree root node definitions.\n */\n static getSubtrees(): { [key: string]: RootNodeDefinition } {\n return this.subtreeTable;\n }\n\n /**\n * Sets the subtree with the specified name for later lookup.\n * @param name The name of the subtree.\n * @param subtree The subtree.\n */\n static setSubtree(name: string, subtree: RootNodeDefinition) {\n this.subtreeTable[name] = subtree;\n }\n\n /**\n * Removes the registered function or subtree with the specified name.\n * @param name The name of the registered function or subtree.\n */\n static remove(name: string) {\n delete this.functionTable[name];\n delete this.subtreeTable[name];\n }\n\n /**\n * Remove all registered functions and subtrees.\n */\n static empty() {\n this.functionTable = {};\n this.subtreeTable = {};\n }\n}\n", "import Node from \"../../nodes/Node\";\n\n/**\n * An exception thrown when evaluating node guard path conditions and a conditions fails.\n */\nexport default class GuardUnsatisifedException extends Error {\n /**\n * @param source The node at which a guard condition failed.\n */\n constructor(private source: Node) {\n super(\"A guard path condition has failed\");\n }\n\n /**\n * Gets whether the specified node is the node at which a guard condition failed.\n * @param node The node to check against the source node.\n * @returns Whether the specified node is the node at which a guard condition failed.\n */\n isSourceNode = (node: Node) => node === this.source;\n}\n", "import { Agent } from \"../../Agent\";\nimport Guard from \"./Guard\";\nimport Node from \"../../nodes/Node\";\nimport GuardUnsatisifedException from \"./GuardUnsatisifedException\";\n\nexport type GuardPathPart = {\n node: Node;\n guards: Guard[];\n};\n\n/**\n * Represents a path of node guards along a root-to-leaf tree path.\n */\nexport default class GuardPath {\n /**\n * @param nodes An array of objects defining a node instance -> guard link, ordered by node depth.\n */\n constructor(private nodes: GuardPathPart[]) {}\n\n /**\n * Evaluate guard conditions for all guards in the tree path, moving outwards from the root.\n * @param agent The agent, required for guard evaluation.\n * @returns An evaluation results object.\n */\n evaluate = (agent: Agent) => {\n // We need to evaluate guard conditions for nodes up the tree, moving outwards from the root.\n for (const details of this.nodes) {\n // There can be multiple guards per node.\n for (const guard of details.guards) {\n // Check whether the guard condition passes, and throw an exception if not.\n if (!guard.isSatisfied(agent)) {\n throw new GuardUnsatisifedException(details.node);\n }\n }\n }\n };\n}\n", "import { BehaviourTreeOptions } from \"../BehaviourTreeOptions\";\nimport State, { AnyState } from \"../State\";\nimport { Agent } from \"../Agent\";\nimport Leaf from \"./leaf/Leaf\";\nimport Attribute from \"../attributes/Attribute\";\nimport Entry from \"../attributes/callbacks/Entry\";\nimport Exit from \"../attributes/callbacks/Exit\";\nimport Step from \"../attributes/callbacks/Step\";\nimport Guard from \"../attributes/guards/Guard\";\nimport GuardPath from \"../attributes/guards/GuardPath\";\nimport GuardUnsatisifedException from \"../attributes/guards/GuardUnsatisifedException\";\n\n/**\n * A base node.\n */\nexport default abstract class Node {\n /**\n * The node uid.\n */\n private readonly uid: string = createNodeUid();\n /**\n * The node state.\n */\n private state: AnyState = State.READY;\n /**\n * The guard path to evaluate as part of a node update.\n */\n private guardPath: GuardPath | undefined;\n\n /**\n * @param type The node type.\n * @param attributes The node attributes.\n * @param args The node argument definitions.\n */\n constructor(private type: string, private attributes: Attribute[], private args: any[]) {}\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected abstract onUpdate(agent: Agent, options: BehaviourTreeOptions): void;\n\n /**\n * Gets the name of the node.\n */\n public abstract getName(): string;\n\n /**\n * Gets whether this node is a leaf node.\n */\n public abstract isLeafNode: () => this is Leaf;\n\n /**\n * Gets/Sets the state of the node.\n */\n getState = (): AnyState => this.state;\n setState = (value: AnyState): void => {\n this.state = value;\n };\n\n /**\n * Gets the unique id of the node.\n */\n getUid = () => this.uid;\n\n /**\n * Gets the type of the node.\n */\n getType = () => this.type;\n\n /**\n * Gets the node attributes.\n */\n getAttributes = () => this.attributes;\n\n /**\n * Gets the node arguments.\n */\n getArguments = () => this.args;\n\n /**\n * Gets the node attribute with the specified type, or null if it does not exist.\n */\n getAttribute(type: \"entry\" | \"ENTRY\"): Entry;\n getAttribute(type: \"exit\" | \"EXIT\"): Exit;\n getAttribute(type: \"step\" | \"STEP\"): Step;\n getAttribute(type: string): Attribute {\n return (\n this.getAttributes().filter((decorator) => decorator.type.toUpperCase() === type.toUpperCase())[0] || null\n );\n }\n\n /**\n * Gets the node attributes.\n */\n getGuardAttributes = (): Guard[] => this.getAttributes().filter((decorator) => decorator.isGuard()) as Guard[];\n\n /**\n * Sets the guard path to evaluate as part of a node update.\n */\n setGuardPath = (value: GuardPath) => (this.guardPath = value);\n\n /**\n * Gets whether a guard path is assigned to this node.\n */\n hasGuardPath = () => !!this.guardPath;\n\n /**\n * Gets whether this node is in the specified state.\n * @param value The value to compare to the node state.\n */\n public is(value: AnyState): boolean {\n return this.state === value;\n }\n\n /**\n * Reset the state of the node.\n */\n public reset(): void {\n this.setState(State.READY);\n }\n\n /**\n * Abort the running of this node.\n * @param agent The agent.\n */\n public abort(agent: Agent): void {\n // There is nothing to do if this node is not in the running state.\n if (!this.is(State.RUNNING)) {\n return;\n }\n\n // Reset the state of this node.\n this.reset();\n\n this.getAttribute(\"exit\")?.callAgentFunction(agent, false, true);\n }\n\n /**\n * Update the node.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n * @returns The result of the update.\n */\n public update(agent: Agent, options: BehaviourTreeOptions): void {\n // If this node is already in a 'SUCCEEDED' or 'FAILED' state then there is nothing to do.\n if (this.is(State.SUCCEEDED) || this.is(State.FAILED)) {\n return;\n }\n\n try {\n // Evaluate all of the guard path conditions for the current tree path.\n this.guardPath!.evaluate(agent);\n\n // If this node is in the READY state then call the ENTRY for this node if it exists.\n if (this.is(State.READY)) {\n this.getAttribute(\"entry\")?.callAgentFunction(agent);\n }\n\n this.getAttribute(\"step\")?.callAgentFunction(agent);\n\n // Do the actual update.\n this.onUpdate(agent, options);\n\n // If this node is now in a 'SUCCEEDED' or 'FAILED' state then call the EXIT for this node if it exists.\n if (this.is(State.SUCCEEDED) || this.is(State.FAILED)) {\n this.getAttribute(\"exit\")?.callAgentFunction(agent, this.is(State.SUCCEEDED), false);\n }\n } catch (error) {\n // If the error is a GuardUnsatisfiedException then we need to determine if this node is the source.\n if (error instanceof GuardUnsatisifedException && error.isSourceNode(this)) {\n // Abort the current node.\n this.abort(agent);\n\n // Any node that is the source of an abort will be a failed node.\n this.setState(State.FAILED);\n } else {\n throw error;\n }\n }\n }\n}\n\n/**\n * Create a randomly generated node uid.\n * @returns A randomly generated node uid.\n */\nfunction createNodeUid(): string {\n var S4 = function () {\n return (((1 + Math.random()) * 0x10000) | 0).toString(16).substring(1);\n };\n return S4() + S4() + \"-\" + S4() + \"-\" + S4() + \"-\" + S4() + \"-\" + S4() + S4() + S4();\n}\n", "import Node from \"../Node\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\n\n/**\n * A composite node that wraps child nodes.\n */\nexport default abstract class Composite extends Node {\n /**\n * @param type The node type.\n * @param attributes The node attributes.\n * @param children The child nodes.\n */\n constructor(type: string, attributes: Attribute[], protected children: Node[]) {\n super(type, attributes, []);\n }\n\n /**\n * Gets whether this node is a leaf node.\n */\n isLeafNode = () => false;\n\n /**\n * Gets the children of this node.\n */\n getChildren = () => this.children;\n\n /**\n * Reset the state of the node.\n */\n reset = () => {\n // Reset the state of this node.\n this.setState(State.READY);\n\n // Reset the state of any child nodes.\n this.getChildren().forEach((child) => child.reset());\n };\n\n /**\n * Abort the running of this node.\n * @param agent The agent.\n */\n abort = (agent: Agent) => {\n // There is nothing to do if this node is not in the running state.\n if (!this.is(State.RUNNING)) {\n return;\n }\n\n // Abort any child nodes.\n this.getChildren().forEach((child) => child.abort(agent));\n\n // Reset the state of this node.\n this.reset();\n\n this.getAttribute(\"exit\")?.callAgentFunction(agent, false, true);\n };\n}\n", "import Composite from \"./Composite\";\nimport State from \"../../State\";\nimport Node from \"../Node\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A PARALLEL node.\n * The child nodes are executed concurrently until one fails or all succeed.\n */\nexport default class Parallel extends Composite {\n /**\n * @param attributes The node attributes.\n * @param children The child nodes.\n */\n constructor(attributes: Attribute[], children: Node[]) {\n super(\"parallel\", attributes, children);\n }\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // Keep a count of the number of succeeded child nodes.\n let succeededCount = 0;\n\n let hasChildFailed = false;\n\n // Iterate over all of the children of this node.\n for (const child of this.children) {\n // If the child has never been updated or is running then we will need to update it now.\n if (child.getState() === State.READY || child.getState() === State.RUNNING) {\n // Update the child of this node.\n child.update(agent, options);\n }\n\n // If the current child has a state of 'SUCCEEDED' then we should move on to the next child.\n if (child.getState() === State.SUCCEEDED) {\n // The child node has succeeded, keep track of this to determine if all children have.\n succeededCount++;\n\n // The child node succeeded, but we have not finished checking every child node yet.\n continue;\n }\n\n // If the current child has a state of 'FAILED' then this node is also a 'FAILED' node.\n if (child.getState() === State.FAILED) {\n hasChildFailed = true;\n\n // There is no need to check the rest of the children.\n break;\n }\n\n // The node should be in the 'RUNNING' state.\n if (child.getState() !== State.RUNNING) {\n // The child node was not in an expected state.\n throw new Error(\"child node was not in an expected state.\");\n }\n }\n\n if (hasChildFailed) {\n // This node is a 'FAILED' node.\n this.setState(State.FAILED);\n\n // Abort every running child.\n for (const child of this.children) {\n if (child.getState() === State.RUNNING) {\n child.abort(agent);\n }\n }\n } else {\n // If all children have succeeded then this node has also succeeded, otherwise it is still running.\n this.setState(succeededCount === this.children.length ? State.SUCCEEDED : State.RUNNING);\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => \"PARALLEL\";\n}\n", "import Composite from \"./Composite\";\nimport Node from \"../Node\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A SELECTOR node.\n * The child nodes are executed in sequence until one succeeds or all fail.\n */\nexport default class Selector extends Composite {\n /**\n * @param attributes The node attributes.\n * @param children The child nodes.\n */\n constructor(attributes: Attribute[], protected children: Node[]) {\n super(\"selector\", attributes, children);\n }\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // Iterate over all of the children of this node.\n for (const child of this.children) {\n // If the child has never been updated or is running then we will need to update it now.\n if (child.getState() === State.READY || child.getState() === State.RUNNING) {\n // Update the child of this node.\n child.update(agent, options);\n }\n\n // If the current child has a state of 'SUCCEEDED' then this node is also a 'SUCCEEDED' node.\n if (child.getState() === State.SUCCEEDED) {\n // This node is a 'SUCCEEDED' node.\n this.setState(State.SUCCEEDED);\n\n // There is no need to check the rest of the selector nodes.\n return;\n }\n\n // If the current child has a state of 'FAILED' then we should move on to the next child.\n if (child.getState() === State.FAILED) {\n // Find out if the current child is the last one in the selector.\n // If it is then this sequence node has also failed.\n if (this.children.indexOf(child) === this.children.length - 1) {\n // This node is a 'FAILED' node.\n this.setState(State.FAILED);\n\n // There is no need to check the rest of the selector as we have completed it.\n return;\n } else {\n // The child node failed, try the next one.\n continue;\n }\n }\n\n // The node should be in the 'RUNNING' state.\n if (child.getState() === State.RUNNING) {\n // This node is a 'RUNNING' node.\n this.setState(State.RUNNING);\n\n // There is no need to check the rest of the selector as the current child is still running.\n return;\n }\n\n // The child node was not in an expected state.\n throw new Error(\"child node was not in an expected state.\");\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => \"SELECTOR\";\n}\n", "import Composite from \"./Composite\";\nimport Node from \"../Node\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A SEQUENCE node.\n * The child nodes are executed in sequence until one fails or all succeed.\n */\nexport default class Sequence extends Composite {\n /**\n * @param attributes The node attributes.\n * @param children The child nodes.\n */\n constructor(attributes: Attribute[], protected children: Node[]) {\n super(\"sequence\", attributes, children);\n }\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // Iterate over all of the children of this node.\n for (const child of this.children) {\n // If the child has never been updated or is running then we will need to update it now.\n if (child.getState() === State.READY || child.getState() === State.RUNNING) {\n // Update the child of this node.\n child.update(agent, options);\n }\n\n // If the current child has a state of 'SUCCEEDED' then we should move on to the next child.\n if (child.getState() === State.SUCCEEDED) {\n // Find out if the current child is the last one in the sequence.\n // If it is then this sequence node has also succeeded.\n if (this.children.indexOf(child) === this.children.length - 1) {\n // This node is a 'SUCCEEDED' node.\n this.setState(State.SUCCEEDED);\n\n // There is no need to check the rest of the sequence as we have completed it.\n return;\n } else {\n // The child node succeeded, but we have not finished the sequence yet.\n continue;\n }\n }\n\n // If the current child has a state of 'FAILED' then this node is also a 'FAILED' node.\n if (child.getState() === State.FAILED) {\n // This node is a 'FAILED' node.\n this.setState(State.FAILED);\n\n // There is no need to check the rest of the sequence.\n return;\n }\n\n // The node should be in the 'RUNNING' state.\n if (child.getState() === State.RUNNING) {\n // This node is a 'RUNNING' node.\n this.setState(State.RUNNING);\n\n // There is no need to check the rest of the sequence as the current child is still running.\n return;\n }\n\n // The child node was not in an expected state.\n throw new Error(\"child node was not in an expected state.\");\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => \"SEQUENCE\";\n}\n", "import createLotto from \"lotto-draw\";\n\nimport Node from \"../Node\";\nimport Composite from \"./Composite\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A LOTTO node.\n * A winning child is picked on the initial update of this node, based on ticket weighting.\n * The state of this node will match the state of the winning child.\n */\nexport default class Lotto extends Composite {\n /**\n * @param attributes The node attributes.\n * @param weights The child node weights.\n * @param children The child nodes.\n */\n constructor(attributes: Attribute[], private weights: number[] | undefined, children: Node[]) {\n super(\"lotto\", attributes, children);\n }\n\n /**\n * The child node selected to be the active one.\n */\n private selectedChild: Node | undefined;\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // If this node is in the READY state then we need to pick a winning child node.\n if (this.is(State.READY)) {\n // Create a lotto draw with which to randomly pick a child node to become the active one.\n const lottoDraw = createLotto({\n // Hook up the optional 'random' behaviour tree function option to the one used by 'lotto-draw'.\n random: options.random,\n // Pass in each child node as a participant in the lotto draw with their respective ticket count.\n participants: this.children.map((child, index) => [child, this.weights?.[index] || 1])\n });\n\n // Randomly pick a child based on ticket weighting, this will become the active child for this composite node.\n this.selectedChild = lottoDraw.draw() || undefined;\n }\n\n // If something went wrong and we don't have an active child then we should throw an error.\n if (!this.selectedChild) {\n throw new Error(\"failed to update lotto node as it has no active child\");\n }\n\n // If the selected child has never been updated or is running then we will need to update it now.\n if (this.selectedChild.getState() === State.READY || this.selectedChild.getState() === State.RUNNING) {\n this.selectedChild.update(agent, options);\n }\n\n // The state of the lotto node is the state of its selected child.\n this.setState(this.selectedChild.getState());\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => (this.weights ? `LOTTO [${this.weights.join(\",\")}]` : \"LOTTO\");\n}\n", "import Node from \"../Node\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\n\n/**\n * A decorator node that wraps a single child node.\n */\nexport default abstract class Decorator extends Node {\n /**\n * @param type The node type.\n * @param attributes The node attributes.\n * @param child The child node.\n */\n constructor(type: string, attributes: Attribute[], protected child: Node) {\n super(type, attributes, []);\n }\n\n /**\n * Gets whether this node is a leaf node.\n */\n isLeafNode = () => false;\n\n /**\n * Gets the children of this node.\n */\n getChildren = () => [this.child];\n\n /**\n * Reset the state of the node.\n */\n reset = () => {\n // Reset the state of this node.\n this.setState(State.READY);\n\n // Reset the state of the child node.\n this.child.reset();\n };\n\n /**\n * Abort the running of this node.\n * @param agent The agent.\n */\n abort = (agent: Agent) => {\n // There is nothing to do if this node is not in the running state.\n if (!this.is(State.RUNNING)) {\n return;\n }\n\n // Abort the child node.\n this.child.abort(agent);\n\n // Reset the state of this node.\n this.reset();\n\n this.getAttribute(\"exit\")?.callAgentFunction(agent, false, true);\n };\n}\n", "import Node from \"../Node\";\nimport Decorator from \"./Decorator\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A Fail node.\n * This node wraps a single child and will always move to the 'FAILED' state when the child moves to a 'SUCCEEDED' or 'FAILED' state.\n */\nexport default class Fail extends Decorator {\n /**\n * @param attributes The node attributes.\n * @param child The child node.\n */\n constructor(attributes: Attribute[], child: Node) {\n super(\"fail\", attributes, child);\n }\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // If the child has never been updated or is running then we will need to update it now.\n if (this.child.getState() === State.READY || this.child.getState() === State.RUNNING) {\n this.child.update(agent, options);\n }\n\n // The state of this node will depend in the state of its child.\n switch (this.child.getState()) {\n case State.RUNNING:\n this.setState(State.RUNNING);\n break;\n\n case State.SUCCEEDED:\n case State.FAILED:\n this.setState(State.FAILED);\n break;\n\n default:\n this.setState(State.READY);\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => \"FAIL\";\n}\n", "import Decorator from \"./Decorator\";\nimport State from \"../../State\";\nimport Node from \"../Node\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A Flip node.\n * This node wraps a single child and will flip the state of the child state.\n */\nexport default class Flip extends Decorator {\n /**\n * @param attributes The node attributes.\n * @param child The child node.\n */\n constructor(attributes: Attribute[], child: Node) {\n super(\"flip\", attributes, child);\n }\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // If the child has never been updated or is running then we will need to update it now.\n if (this.child.getState() === State.READY || this.child.getState() === State.RUNNING) {\n this.child.update(agent, options);\n }\n\n // The state of this node will depend in the state of its child.\n switch (this.child.getState()) {\n case State.RUNNING:\n this.setState(State.RUNNING);\n break;\n\n case State.SUCCEEDED:\n this.setState(State.FAILED);\n break;\n\n case State.FAILED:\n this.setState(State.SUCCEEDED);\n break;\n\n default:\n this.setState(State.READY);\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => \"FLIP\";\n}\n", "import Node from \"../Node\";\nimport Decorator from \"./Decorator\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A REPEAT node.\n * The node has a single child which can have:\n * -- A number of iterations for which to repeat the child node.\n * -- An infinite repeat loop if neither an iteration count or a condition function is defined.\n * The REPEAT node will stop and have a 'FAILED' state if its child is ever in a 'FAILED' state after an update.\n * The REPEAT node will attempt to move on to the next iteration if its child is ever in a 'SUCCEEDED' state.\n */\nexport default class Repeat extends Decorator {\n /**\n * @param attributes The node attributes.\n * @param iterations The number of iterations to repeat the child node.\n * @param iterationsMin The minimum possible number of iterations to repeat the child node.\n * @param iterationsMax The maximum possible number of iterations to repeat the child node.\n * @param child The child node.\n */\n constructor(\n attributes: Attribute[],\n private iterations: number | null,\n private iterationsMin: number | null,\n private iterationsMax: number | null,\n child: Node\n ) {\n super(\"repeat\", attributes, child);\n }\n\n /**\n * The number of target iterations to make.\n */\n private targetIterationCount: number | null = null;\n\n /**\n * The current iteration count.\n */\n private currentIterationCount: number = 0;\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // If this node is in the READY state then we need to reset the child and the target iteration count.\n if (this.is(State.READY)) {\n // Reset the child node.\n this.child.reset();\n\n // Reset the current iteration count.\n this.currentIterationCount = 0;\n\n // Set the target iteration count.\n this.setTargetIterationCount(options);\n }\n\n // Do a check to see if we can iterate. If we can then this node will move into the 'RUNNING' state.\n // If we cannot iterate then we have hit our target iteration count, which means that the node has succeeded.\n if (this.canIterate()) {\n // This node is in the running state and can do its initial iteration.\n this.setState(State.RUNNING);\n\n // We may have already completed an iteration, meaning that the child node will be in the SUCCEEDED state.\n // If this is the case then we will have to reset the child node now.\n if (this.child.getState() === State.SUCCEEDED) {\n this.child.reset();\n }\n\n // Update the child of this node.\n this.child.update(agent, options);\n\n // If the child moved into the FAILED state when we updated it then there is nothing left to do and this node has also failed.\n // If it has moved into the SUCCEEDED state then we have completed the current iteration.\n if (this.child.getState() === State.FAILED) {\n // The child has failed, meaning that this node has failed.\n this.setState(State.FAILED);\n\n return;\n } else if (this.child.getState() === State.SUCCEEDED) {\n // We have completed an iteration.\n this.currentIterationCount += 1;\n }\n } else {\n // This node is in the 'SUCCEEDED' state as we cannot iterate any more.\n this.setState(State.SUCCEEDED);\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => {\n if (this.iterations !== null) {\n return `REPEAT ${this.iterations}x`;\n } else if (this.iterationsMin !== null && this.iterationsMax !== null) {\n return `REPEAT ${this.iterationsMin}x-${this.iterationsMax}x`;\n } else {\n return \"REPEAT\";\n }\n };\n\n /**\n * Reset the state of the node.\n */\n reset = () => {\n // Reset the state of this node.\n this.setState(State.READY);\n\n // Reset the current iteration count.\n this.currentIterationCount = 0;\n\n // Reset the child node.\n this.child.reset();\n };\n\n /**\n * Gets whether an iteration can be made.\n * @returns Whether an iteration can be made.\n */\n private canIterate = () => {\n if (this.targetIterationCount !== null) {\n // We can iterate as long as we have not reached our target iteration count.\n return this.currentIterationCount < this.targetIterationCount;\n }\n\n // If neither an iteration count or a condition function were defined then we can iterate indefinitely.\n return true;\n };\n\n /**\n * Sets the target iteration count.\n * @param options The behaviour tree options object.\n */\n private setTargetIterationCount = (options: BehaviourTreeOptions) => {\n // Are we dealing with an explicit iteration count or will we be randomly picking a iteration count between the min and max iteration count.\n if (this.iterations !== null) {\n this.targetIterationCount = this.iterations;\n } else if (this.iterationsMin !== null && this.iterationsMax !== null) {\n // We will be picking a random iteration count between a min and max iteration count, if the optional 'random'\n // behaviour tree function option is defined then we will be using that, otherwise we will fall back to using Math.random.\n const random = typeof options.random === \"function\" ? options.random : Math.random;\n\n // Pick a random iteration count between a min and max iteration count.\n this.targetIterationCount = Math.floor(\n random() * (this.iterationsMax - this.iterationsMin + 1) + this.iterationsMin\n );\n } else {\n this.targetIterationCount = null;\n }\n };\n}\n", "import Node from \"../Node\";\nimport Decorator from \"./Decorator\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A RETRY node.\n * The node has a single child which can have:\n * -- A number of iterations for which to repeat the child node.\n * -- An infinite repeat loop if neither an iteration count or a condition function is defined.\n * The RETRY node will stop and have a 'SUCCEEDED' state if its child is ever in a 'SUCCEEDED' state after an update.\n * The RETRY node will attempt to move on to the next iteration if its child is ever in a 'FAILED' state.\n */\nexport default class Retry extends Decorator {\n /**\n * @param attributes The node attributes.\n * @param attempts The number of attempts to retry the child node.\n * @param attemptsMin The minimum possible number of attempts to retry the child node.\n * @param attemptsMax The maximum possible number of attempts to retry the child node.\n * @param child The child node.\n */\n constructor(\n attributes: Attribute[],\n private attempts: number | null,\n private attemptsMin: number | null,\n private attemptsMax: number | null,\n child: Node\n ) {\n super(\"retry\", attributes, child);\n }\n\n /**\n * The number of target attempts to make.\n */\n private targetAttemptCount: number | null = null;\n\n /**\n * The current attempt count.\n */\n private currentAttemptCount: number = 0;\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // If this node is in the READY state then we need to reset the child and the target attempt count.\n if (this.is(State.READY)) {\n // Reset the child node.\n this.child.reset();\n\n // Reset the current attempt count.\n this.currentAttemptCount = 0;\n\n // Set the target attempt count.\n this.setTargetAttemptCount(options);\n }\n\n // Do a check to see if we can attempt. If we can then this node will move into the 'RUNNING' state.\n // If we cannot attempt then we have hit our target attempt count, which means that the node has succeeded.\n if (this.canAttempt()) {\n // This node is in the running state and can do its initial attempt.\n this.setState(State.RUNNING);\n\n // We may have already completed an attempt, meaning that the child node will be in the FAILED state.\n // If this is the case then we will have to reset the child node now.\n if (this.child.getState() === State.FAILED) {\n this.child.reset();\n }\n\n // Update the child of this node.\n this.child.update(agent, options);\n\n // If the child moved into the SUCCEEDED state when we updated it then there is nothing left to do and this node has also succeeded.\n // If it has moved into the FAILED state then we have completed the current attempt.\n if (this.child.getState() === State.SUCCEEDED) {\n // The child has succeeded, meaning that this node has succeeded.\n this.setState(State.SUCCEEDED);\n\n return;\n } else if (this.child.getState() === State.FAILED) {\n // We have completed an attempt.\n this.currentAttemptCount += 1;\n }\n } else {\n // This node is in the 'FAILED' state as we cannot iterate any more.\n this.setState(State.FAILED);\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => {\n if (this.attempts !== null) {\n return `RETRY ${this.attempts}x`;\n } else if (this.attemptsMin !== null && this.attemptsMax !== null) {\n return `RETRY ${this.attemptsMin}x-${this.attemptsMax}x`;\n } else {\n return \"RETRY\";\n }\n };\n\n /**\n * Reset the state of the node.\n */\n reset = () => {\n // Reset the state of this node.\n this.setState(State.READY);\n\n // Reset the current attempt count.\n this.currentAttemptCount = 0;\n\n // Reset the child node.\n this.child.reset();\n };\n\n /**\n * Gets whether an attempt can be made.\n * @returns Whether an attempt can be made.\n */\n canAttempt = () => {\n if (this.targetAttemptCount !== null) {\n // We can attempt as long as we have not reached our target attempt count.\n return this.currentAttemptCount < this.targetAttemptCount;\n }\n\n // If neither an attempt count or a condition function were defined then we can attempt indefinitely.\n return true;\n };\n\n /**\n * Sets the target attempt count.\n * @param options The behaviour tree options object.\n */\n setTargetAttemptCount = (options: BehaviourTreeOptions) => {\n // Are we dealing with an explicit attempt count or will we be randomly picking an attempt count between the min and max attempt count.\n if (this.attempts !== null) {\n this.targetAttemptCount = this.attempts;\n } else if (this.attemptsMin !== null && this.attemptsMax !== null) {\n // We will be picking a random attempt count between a min and max attempt count, if the optional 'random'\n // behaviour tree function option is defined then we will be using that, otherwise we will fall back to using Math.random.\n const random = typeof options.random === \"function\" ? options.random : Math.random;\n\n // Pick a random attempt count between a min and max attempt count.\n this.targetAttemptCount = Math.floor(\n random() * (this.attemptsMax - this.attemptsMin + 1) + this.attemptsMin\n );\n } else {\n this.targetAttemptCount = null;\n }\n };\n}\n", "import Node from \"../Node\";\nimport Decorator from \"./Decorator\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A Root node.\n * The root node will have a single child.\n */\nexport default class Root extends Decorator {\n /**\n * @param attributes The node attributes.\n * @param child The child node.\n */\n constructor(attributes: Attribute[], child: Node) {\n super(\"root\", attributes, child);\n }\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // If the child has never been updated or is running then we will need to update it now.\n if (this.child.getState() === State.READY || this.child.getState() === State.RUNNING) {\n // Update the child of this node.\n this.child.update(agent, options);\n }\n\n // The state of the root node is the state of its child.\n this.setState(this.child.getState());\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => \"ROOT\";\n}\n", "import Node from \"../Node\";\nimport Decorator from \"./Decorator\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A Succeed node.\n * This node wraps a single child and will always move to the 'SUCCEEDED' state when the child moves to a 'SUCCEEDED' or 'FAILED' state.\n */\nexport default class Succeed extends Decorator {\n /**\n * @param attributes The node attributes.\n * @param child The child node.\n */\n constructor(attributes: Attribute[], child: Node) {\n super(\"succeed\", attributes, child);\n }\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // If the child has never been updated or is running then we will need to update it now.\n if (this.child.getState() === State.READY || this.child.getState() === State.RUNNING) {\n this.child.update(agent, options);\n }\n\n // The state of this node will depend in the state of its child.\n switch (this.child.getState()) {\n case State.RUNNING:\n this.setState(State.RUNNING);\n break;\n\n case State.SUCCEEDED:\n case State.FAILED:\n this.setState(State.SUCCEEDED);\n break;\n\n default:\n this.setState(State.READY);\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => \"SUCCEED\";\n}\n", "import Node from \"../Node\";\n\n/**\n * A leaf node.\n */\nexport default abstract class Leaf extends Node {\n /**\n * Gets whether this node is a leaf node.\n */\n isLeafNode = () => true;\n}\n", "import { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\nimport State, { CompleteState } from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Leaf from \"./Leaf\";\nimport Lookup from \"../../Lookup\";\nimport Attribute from \"../../attributes/Attribute\";\n\n/**\n * An Action leaf node.\n * This represents an immediate or ongoing state of behaviour.\n */\nexport default class Action extends Leaf {\n /**\n * @param attributes The node attributes.\n * @param actionName The action name.\n * @param actionArguments The array of action argument definitions.\n */\n constructor(attributes: Attribute[], private actionName: string, private actionArguments: any[]) {\n super(\"action\", attributes, actionArguments);\n }\n\n /**\n * Whether there is a pending update promise.\n */\n private isUsingUpdatePromise = false;\n\n /**\n * The finished state result of an update promise.\n */\n private updatePromiseStateResult: CompleteState | null = null;\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // If the result of this action depends on an update promise then there is nothing to do until\n // it resolves, unless there has been a value set as a result of the update promise resolving.\n if (this.isUsingUpdatePromise) {\n // Check whether the update promise has resolved with a state value.\n if (this.updatePromiseStateResult) {\n // Set the state of this node to match the state returned by the promise.\n this.setState(this.updatePromiseStateResult);\n }\n\n return;\n }\n\n // Attempt to get the invoker for the action function.\n const actionFuncInvoker = Lookup.getFuncInvoker(agent, this.actionName);\n\n // The action function should be defined.\n if (actionFuncInvoker === null) {\n throw new Error(\n `cannot update action node as the action '${this.actionName}' function is not defined on the agent and has not been registered`\n );\n }\n\n // Call the action function, the result of which may be:\n // - The finished state of this action node.\n // - A promise to return a finished node state.\n // - Undefined if the node should remain in the running state.\n const updateResult = actionFuncInvoker(this.actionArguments) as CompleteState | Promise;\n\n if (updateResult instanceof Promise) {\n updateResult.then(\n (result) => {\n // If 'isUpdatePromisePending' is null then the promise was cleared as it was resolving, probably via an abort of reset.\n if (!this.isUsingUpdatePromise) {\n return;\n }\n\n // Check to make sure the result is a valid finished state.\n if (result !== State.SUCCEEDED && result !== State.FAILED) {\n throw new Error(\n \"action node promise resolved with an invalid value, expected a State.SUCCEEDED or State.FAILED value to be returned\"\n );\n }\n\n // Set pending update promise state result to be processed on next update.\n this.updatePromiseStateResult = result;\n },\n (reason) => {\n // If 'isUpdatePromisePending' is null then the promise was cleared as it was resolving, probably via an abort of reset.\n if (!this.isUsingUpdatePromise) {\n return;\n }\n\n // Just throw whatever was returned as the rejection argument.\n throw new Error(reason);\n }\n );\n\n // This node will be in the 'RUNNING' state until the update promise resolves.\n this.setState(State.RUNNING);\n\n // We are now waiting for the promise returned by the use to resolve before we know what state this node is in.\n this.isUsingUpdatePromise = true;\n } else {\n // Validate the returned value.\n this.validateUpdateResult(updateResult);\n\n // Set the state of this node, this may be undefined, which just means that the node is still in the 'RUNNING' state.\n this.setState(updateResult || State.RUNNING);\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => this.actionName;\n\n /**\n * Reset the state of the node.\n */\n reset = () => {\n // Reset the state of this node.\n this.setState(State.READY);\n\n // There is no longer an update promise that we care about.\n this.isUsingUpdatePromise = false;\n this.updatePromiseStateResult = null;\n };\n\n /**\n * Validate the result of an update function call.\n * @param result The result of an update function call.\n */\n private validateUpdateResult = (result: CompleteState | boolean) => {\n switch (result) {\n case State.SUCCEEDED:\n case State.FAILED:\n case undefined:\n return;\n default:\n throw new Error(\n `action '${this.actionName}' 'onUpdate' returned an invalid response, expected an optional State.SUCCEEDED or State.FAILED value to be returned`\n );\n }\n };\n}\n", "import { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Leaf from \"./Leaf\";\nimport Lookup from \"../../Lookup\";\nimport Attribute from \"../../attributes/Attribute\";\n\n/**\n * A Condition leaf node.\n * This will succeed or fail immediately based on an agent predicate, without moving to the 'RUNNING' state.\n */\nexport default class Condition extends Leaf {\n /**\n * @param attributes The node attributes.\n * @param conditionName The name of the condition function.\n * @param conditionArguments The array of condition argument definitions.\n */\n constructor(attributes: Attribute[], private conditionName: string, private conditionArguments: any[]) {\n super(\"condition\", attributes, conditionArguments);\n }\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // Attempt to get the invoker for the condition function.\n const conditionFuncInvoker = Lookup.getFuncInvoker(agent, this.conditionName);\n\n // The condition function should be defined.\n if (conditionFuncInvoker === null) {\n throw new Error(\n `cannot update condition node as the condition '${this.conditionName}' function is not defined on the agent and has not been registered`\n );\n }\n\n // Call the condition function to determine the state of this node.\n this.setState(!!conditionFuncInvoker(this.conditionArguments) ? State.SUCCEEDED : State.FAILED);\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => this.conditionName;\n}\n", "import Leaf from \"./Leaf\";\nimport State from \"../../State\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { Agent } from \"../../Agent\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A WAIT node.\n * The state of this node will change to SUCCEEDED after a duration of time\n */\nexport default class Wait extends Leaf {\n /**\n * @param attributes The node attributes.\n * @param duration The duration that this node will wait to succeed in milliseconds.\n * @param durationMin The minimum possible duration in milliseconds that this node will wait to succeed.\n * @param durationMax The maximum possible duration in milliseconds that this node will wait to succeed.\n */\n constructor(\n attributes: Attribute[],\n private duration: number | null,\n private durationMin: number | null,\n private durationMax: number | null\n ) {\n super(\"wait\", attributes, []);\n }\n\n /**\n * The time in milliseconds at which this node was first updated.\n */\n private initialUpdateTime: number = 0;\n\n /**\n * The total duration in milliseconds that this node will be waiting for.\n */\n private totalDuration: number | null = null;\n\n /**\n * The duration in milliseconds that this node has been waiting for.\n */\n private waitedDuration: number = 0;\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // If this node is in the READY state then we need to set the initial update time.\n if (this.is(State.READY)) {\n // Set the initial update time.\n this.initialUpdateTime = new Date().getTime();\n\n // Set the initial waited duration.\n this.waitedDuration = 0;\n\n // Are we dealing with an explicit duration or will we be randomly picking a duration between the min and max duration.\n if (this.duration !== null) {\n this.totalDuration = this.duration;\n } else if (this.durationMin !== null && this.durationMax !== null) {\n // We will be picking a random duration between a min and max duration, if the optional 'random' behaviour tree\n // function option is defined then we will be using that, otherwise we will fall back to using Math.random.\n const random = typeof options.random === \"function\" ? options.random : Math.random;\n\n // Pick a random duration between a min and max duration.\n this.totalDuration = Math.floor(\n random() * (this.durationMax - this.durationMin + 1) + this.durationMin\n );\n } else {\n this.totalDuration = null;\n }\n\n // The node is now running until we finish waiting.\n this.setState(State.RUNNING);\n }\n\n // If we have no total duration then this wait node will wait indefinitely until it is aborted.\n if (this.totalDuration === null) {\n return;\n }\n\n // If we have a 'getDeltaTime' function defined as part of our options then we will use it to figure out how long we have waited for.\n if (typeof options.getDeltaTime === \"function\") {\n // Get the delta time.\n const deltaTime = options.getDeltaTime();\n\n // Our delta time must be a valid number and cannot be NaN.\n if (typeof deltaTime !== \"number\" || isNaN(deltaTime)) {\n throw new Error(\"The delta time must be a valid number and not NaN.\");\n }\n\n // Update the amount of time that this node has been waiting for based on the delta time.\n this.waitedDuration += deltaTime * 1000;\n } else {\n // We are not using a delta time, so we will just work out hom much time has passed since the first update.\n this.waitedDuration = new Date().getTime() - this.initialUpdateTime;\n }\n\n // Have we waited long enough?\n if (this.waitedDuration >= this.totalDuration) {\n // We have finished waiting!\n this.setState(State.SUCCEEDED);\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => {\n if (this.duration !== null) {\n return `WAIT ${this.duration}ms`;\n } else if (this.durationMin !== null && this.durationMax !== null) {\n return `WAIT ${this.durationMin}ms-${this.durationMax}ms`;\n } else {\n return \"WAIT\";\n }\n };\n}\n", "import Guard from \"./guards/Guard\";\n\nexport type AttributeDetails = {\n /** The attribute type. */\n type: string;\n\n /** The attribute arguments. */\n args: any[];\n};\n\n/**\n * A base node attribute.\n */\nexport default abstract class Attribute {\n /**\n * @param type The node attribute type.\n * @param args The array of attribute arguments.\n */\n constructor(public type: string, public args: any[]) {}\n\n /**\n * Gets the attribute details.\n */\n abstract getDetails(): TAttributeDetails;\n\n /**\n * Gets whether this attribute is a guard.\n */\n abstract isGuard: () => this is Guard;\n}\n", "import { Agent } from \"../../Agent\";\nimport Attribute, { AttributeDetails } from \"../Attribute\";\n\nexport type GuardAttributeDetails = {\n /** The name of the condition function that determines whether the guard is satisfied. */\n condition: string;\n} & AttributeDetails;\n\n/**\n * A base node guard attribute.\n */\nexport default abstract class Guard extends Attribute {\n /**\n * @param type The node attribute type.\n * @param args The array of decorator argument definitions.\n * @param condition The name of the condition function that determines whether the guard is satisfied.\n */\n constructor(type: string, args: any[], private condition: string) {\n super(type, args);\n }\n\n /**\n * Gets the name of the condition function that determines whether the guard is satisfied.\n */\n getCondition = () => this.condition;\n\n /**\n * Gets whether this attribute is a guard.\n */\n isGuard = () => true;\n\n /**\n * Gets the attribute details.\n */\n getDetails(): GuardAttributeDetails {\n return {\n type: this.type,\n args: this.args,\n condition: this.getCondition()\n };\n }\n\n /**\n * Gets whether the guard is satisfied.\n * @param agent The agent.\n * @returns Whether the guard is satisfied.\n */\n abstract isSatisfied(agent: Agent): boolean;\n}\n", "import Guard from \"./Guard\";\nimport Lookup from \"../../Lookup\";\nimport { Agent } from \"../../Agent\";\n\n/**\n * A WHILE guard which is satisfied as long as the given condition remains true.\n */\nexport default class While extends Guard {\n /**\n * @param condition The name of the condition function that determines whether the guard is satisfied.\n * @param args The array of decorator argument definitions.\n */\n constructor(condition: string, args: any[]) {\n super(\"while\", args, condition);\n }\n\n /**\n * Gets whether the guard is satisfied.\n * @param agent The agent.\n * @returns Whether the guard is satisfied.\n */\n isSatisfied = (agent: Agent) => {\n // Attempt to get the invoker for the condition function.\n const conditionFuncInvoker = Lookup.getFuncInvoker(agent, this.getCondition());\n\n // The condition function should be defined.\n if (conditionFuncInvoker === null) {\n throw new Error(\n `cannot evaluate node guard as the condition '${this.getCondition()}' function is not defined on the agent and has not been registered`\n );\n }\n\n // Call the condition function to determine whether this guard is satisfied.\n return !!conditionFuncInvoker(this.args);\n };\n}\n", "import Guard from \"./Guard\";\nimport Lookup from \"../../Lookup\";\nimport { Agent } from \"../../Agent\";\n\n/**\n * An UNTIL guard which is satisfied as long as the given condition remains false.\n */\nexport default class Until extends Guard {\n /**\n * @param condition The name of the condition function that determines whether the guard is satisfied.\n * @param args The array of decorator argument definitions.\n */\n constructor(condition: string, args: any[]) {\n super(\"until\", args, condition);\n }\n\n /**\n * Gets whether the guard is satisfied.\n * @param agent The agent.\n * @returns Whether the guard is satisfied.\n */\n isSatisfied = (agent: Agent) => {\n // Attempt to get the invoker for the condition function.\n const conditionFuncInvoker = Lookup.getFuncInvoker(agent, this.getCondition());\n\n // The condition function should be defined.\n if (conditionFuncInvoker === null) {\n throw new Error(\n `cannot evaluate node guard as the condition '${this.getCondition()}' function is not defined on the agent and has not been registered`\n );\n }\n\n // Call the condition function to determine whether this guard is satisfied.\n return !!!conditionFuncInvoker(this.args);\n };\n}\n", "import { Agent } from \"../../Agent\";\nimport Attribute, { AttributeDetails } from \"../Attribute\";\n\nexport type CallbackAttributeDetails = {\n /** The name of the agent function that is called. */\n functionName: string;\n} & AttributeDetails;\n\n/**\n * A base node callback attribute.\n */\nexport default abstract class Callback extends Attribute {\n /**\n * @param type The node attribute type.\n * @param args The array of decorator argument definitions.\n * @param functionName The name of the agent function to call.\n */\n constructor(type: string, args: any[], private functionName: string) {\n super(type, args);\n }\n\n /**\n * Gets the name of the agent function to call.\n */\n getFunctionName = () => this.functionName;\n\n /**\n * Gets whether this attribute is a guard.\n */\n isGuard = () => false;\n\n /**\n * Gets the attribute details.\n */\n getDetails(): CallbackAttributeDetails {\n return {\n type: this.type,\n args: this.args,\n functionName: this.getFunctionName()\n };\n }\n\n /**\n * Attempt to call the agent function that this callback refers to.\n * @param agent The agent.\n */\n abstract callAgentFunction: (agent: Agent, isSuccess: boolean, isAborted: boolean) => void;\n}\n", "import Callback from \"./Callback\";\nimport Lookup from \"../../Lookup\";\nimport { Agent } from \"../../Agent\";\n\n/**\n * An ENTRY callback which defines an agent function to call when the associated node is updated and moves out of running state.\n */\nexport default class Entry extends Callback {\n /**\n * @param functionName The name of the agent function to call.\n * @param args The array of callback argument definitions.\n */\n constructor(functionName: string, args: any[]) {\n super(\"entry\", args, functionName);\n }\n\n /**\n * Attempt to call the agent function that this callback refers to.\n * @param agent The agent.\n */\n callAgentFunction = (agent: Agent) => {\n // Attempt to get the invoker for the callback function.\n const callbackFuncInvoker = Lookup.getFuncInvoker(agent, this.getFunctionName());\n\n // The callback function should be defined.\n if (callbackFuncInvoker === null) {\n throw new Error(\n `cannot call entry function '${this.getFunctionName()}' as is not defined on the agent and has not been registered`\n );\n }\n\n // Call the callback function.\n callbackFuncInvoker(this.args);\n };\n}\n", "import Callback from \"./Callback\";\nimport Lookup from \"../../Lookup\";\nimport { Agent } from \"../../Agent\";\n\n/**\n * A STEP callback which defines an agent function to call when the associated node is updated.\n */\nexport default class Step extends Callback {\n /**\n * @param functionName The name of the agent function to call.\n * @param args The array of callback argument definitions.\n */\n constructor(functionName: string, args: any[]) {\n super(\"step\", args, functionName);\n }\n\n /**\n * Attempt to call the agent function that this callback refers to.\n * @param agent The agent.\n */\n callAgentFunction = (agent: Agent) => {\n // Attempt to get the invoker for the callback function.\n const callbackFuncInvoker = Lookup.getFuncInvoker(agent, this.getFunctionName());\n\n // The callback function should be defined.\n if (callbackFuncInvoker === null) {\n throw new Error(\n `cannot call step function '${this.getFunctionName()}' as is not defined on the agent and has not been registered`\n );\n }\n\n // Call the callback function.\n callbackFuncInvoker(this.args);\n };\n}\n", "import Callback from \"./Callback\";\nimport Lookup from \"../../Lookup\";\nimport { Agent } from \"../../Agent\";\n\n/**\n * An EXIT callback which defines an agent function to call when the associated node is updated and moves to a finished state or is aborted.\n */\nexport default class Exit extends Callback {\n /**\n * @param functionName The name of the agent function to call.\n * @param args The array of callback argument definitions.\n */\n constructor(functionName: string, args: any[]) {\n super(\"exit\", args, functionName);\n }\n\n /**\n * Attempt to call the agent function that this callback refers to.\n * @param agent The agent.\n * @param isSuccess Whether the decorated node was left with a success state.\n * @param isAborted Whether the decorated node was aborted.\n */\n callAgentFunction = (agent: Agent, isSuccess: boolean, isAborted: boolean) => {\n // Attempt to get the invoker for the callback function.\n const callbackFuncInvoker = Lookup.getFuncInvoker(agent, this.getFunctionName());\n\n // The callback function should be defined.\n if (callbackFuncInvoker === null) {\n throw new Error(\n `cannot call exit function '${this.getFunctionName()}' as is not defined on the agent and has not been registered`\n );\n }\n\n // Call the callback function\n callbackFuncInvoker([{ value: { succeeded: isSuccess, aborted: isAborted } }, ...this.args]);\n };\n}\n", "import { AnyNodeDefinition, RootNodeDefinition } from \"./BehaviourTreeDefinition\";\nimport GuardPath, { GuardPathPart } from \"./attributes/guards/GuardPath\";\nimport { validateBranchSubtreeLinks } from \"./BehaviourTreeDefinitionValidator\";\nimport { isInteger } from \"./BehaviourTreeDefinitionUtilities\";\nimport Node from \"./nodes/Node\";\nimport Composite from \"./nodes/composite/Composite\";\nimport Decorator from \"./nodes/decorator/Decorator\";\nimport Parallel from \"./nodes/composite/Parallel\";\nimport Selector from \"./nodes/composite/Selector\";\nimport Sequence from \"./nodes/composite/Sequence\";\nimport Lotto from \"./nodes/composite/Lotto\";\nimport Fail from \"./nodes/decorator/Fail\";\nimport Flip from \"./nodes/decorator/Flip\";\nimport Repeat from \"./nodes/decorator/Repeat\";\nimport Retry from \"./nodes/decorator/Retry\";\nimport Root from \"./nodes/decorator/Root\";\nimport Succeed from \"./nodes/decorator/Succeed\";\nimport Action from \"./nodes/leaf/Action\";\nimport Condition from \"./nodes/leaf/Condition\";\nimport Wait from \"./nodes/leaf/Wait\";\nimport Lookup from \"./Lookup\";\nimport Attribute from \"./attributes/Attribute\";\nimport While from \"./attributes/guards/While\";\nimport Until from \"./attributes/guards/Until\";\nimport Entry from \"./attributes/callbacks/Entry\";\nimport Step from \"./attributes/callbacks/Step\";\nimport Exit from \"./attributes/callbacks/Exit\";\n\n/**\n * A type representing any node instance in a behaviour tree.\n */\ntype AnyNode =\n | Root\n | Action\n | Condition\n | Wait\n | Sequence\n | Selector\n | Lotto\n | Parallel\n | Repeat\n | Retry\n | Flip\n | Succeed\n | Fail;\n\n/**\n * A type defining a mapping of root node identifiers to root node definitions.\n */\ntype RootNodeDefinitionMap = { [key: string | symbol]: RootNodeDefinition };\n\n/**\n * A symbol to use as the main root key in any root node mappings.\n */\nconst MAIN_ROOT_NODE_KEY = Symbol(\"__root__\");\n\n/**\n * Build and populate the root nodes based on the provided definition, assuming that the definition has been validated.\n * @param definition The root node definitions.\n * @returns The built and populated root node definitions.\n */\nexport default function buildRootNode(definition: RootNodeDefinition[]): Root {\n // Create a mapping of root node identifers to root node definitions, including globally registered subtree root node definitions.\n const rootNodeDefinitionMap = createRootNodeDefinitionMap(definition);\n\n // Now that we have all of our root node definitons (those part of the tree definition and those globally\n // registered) we should validate the definition. This will also double-check that we dont have any circular\n // dependencies in our branch -> subtree references and that we have no broken branch -> subtree links.\n validateBranchSubtreeLinks(definition, true);\n\n // Create our populated tree of node instances, starting with our main root node.\n const rootNode = nodeFactory(rootNodeDefinitionMap[MAIN_ROOT_NODE_KEY], rootNodeDefinitionMap) as Root;\n\n // Set a guard path on every leaf of the tree to evaluate as part of each update.\n applyLeafNodeGuardPaths(rootNode);\n\n // We only need to return the main root node.\n return rootNode;\n}\n\n/**\n * A factory function which creates a node instance based on the specified definition.\n * @param definition The node definition.\n * @param rootNodeDefinitionMap The mapping of root node identifers to root node definitions, including globally registered subtree root node definitions.\n * @returns A node instance based on the specified definition.\n */\nfunction nodeFactory(definition: AnyNodeDefinition, rootNodeDefinitionMap: RootNodeDefinitionMap): AnyNode {\n // Get the attributes for the node.\n const attributes = nodeAttributesFactory(definition);\n\n // Create the node instance based on the definition type.\n switch (definition.type) {\n case \"root\":\n return new Root(attributes, nodeFactory(definition.child, rootNodeDefinitionMap));\n\n case \"repeat\":\n let iterations: number | null = null;\n let iterationsMin: number | null = null;\n let iterationsMax: number | null = null;\n\n if (Array.isArray(definition.iterations)) {\n iterationsMin = definition.iterations[0];\n iterationsMax = definition.iterations[1];\n } else if (isInteger(definition.iterations)) {\n iterations = definition.iterations!;\n }\n\n return new Repeat(\n attributes,\n iterations,\n iterationsMin,\n iterationsMax,\n nodeFactory(definition.child, rootNodeDefinitionMap)\n );\n\n case \"retry\":\n let attempts: number | null = null;\n let attemptsMin: number | null = null;\n let attemptsMax: number | null = null;\n\n if (Array.isArray(definition.attempts)) {\n attemptsMin = definition.attempts[0];\n attemptsMax = definition.attempts[1];\n } else if (isInteger(definition.attempts)) {\n attempts = definition.attempts!;\n }\n\n return new Retry(\n attributes,\n attempts,\n attemptsMin,\n attemptsMax,\n nodeFactory(definition.child, rootNodeDefinitionMap)\n );\n\n case \"flip\":\n return new Flip(attributes, nodeFactory(definition.child, rootNodeDefinitionMap));\n\n case \"succeed\":\n return new Succeed(attributes, nodeFactory(definition.child, rootNodeDefinitionMap));\n\n case \"fail\":\n return new Fail(attributes, nodeFactory(definition.child, rootNodeDefinitionMap));\n\n case \"sequence\":\n return new Sequence(\n attributes,\n definition.children.map((child) => nodeFactory(child, rootNodeDefinitionMap))\n );\n\n case \"selector\":\n return new Selector(\n attributes,\n definition.children.map((child) => nodeFactory(child, rootNodeDefinitionMap))\n );\n\n case \"parallel\":\n return new Parallel(\n attributes,\n definition.children.map((child) => nodeFactory(child, rootNodeDefinitionMap))\n );\n\n case \"lotto\":\n return new Lotto(\n attributes,\n definition.weights,\n definition.children.map((child) => nodeFactory(child, rootNodeDefinitionMap))\n );\n\n case \"branch\":\n return nodeFactory(rootNodeDefinitionMap[definition.ref].child, rootNodeDefinitionMap);\n\n case \"action\":\n return new Action(attributes, definition.call, definition.args || []);\n\n case \"condition\":\n return new Condition(attributes, definition.call, definition.args || []);\n\n case \"wait\":\n let duration: number | null = null;\n let durationMin: number | null = null;\n let durationMax: number | null = null;\n\n if (Array.isArray(definition.duration)) {\n durationMin = definition.duration[0];\n durationMax = definition.duration[1];\n } else if (isInteger(definition.duration)) {\n duration = definition.duration!;\n }\n\n return new Wait(attributes, duration, durationMin, durationMax);\n }\n}\n\n/**\n * Creates an array of node attribute instances based on the specified node definition.\n * @param definition The node definition.\n * @returns An array of node attribute instances based on the specified node definition.\n */\nfunction nodeAttributesFactory(definition: AnyNodeDefinition): Attribute[] {\n const attributes: Attribute[] = [];\n\n if (definition.while) {\n attributes.push(new While(definition.while.call, definition.while.args ?? []));\n }\n\n if (definition.until) {\n attributes.push(new Until(definition.until.call, definition.until.args ?? []));\n }\n\n if (definition.entry) {\n attributes.push(new Entry(definition.entry.call, definition.entry.args ?? []));\n }\n\n if (definition.step) {\n attributes.push(new Step(definition.step.call, definition.step.args ?? []));\n }\n\n if (definition.exit) {\n attributes.push(new Exit(definition.exit.call, definition.exit.args ?? []));\n }\n\n return attributes;\n}\n\n/**\n * Creates a mapping of root node identifers to root node definitions, mixing in globally registered subtree root node definitions.\n * @param definition The root node definitions.\n * @returns A mapping of root node identifers to root node definitions, including globally registered subtree root node definitions.\n */\nfunction createRootNodeDefinitionMap(definition: RootNodeDefinition[]): RootNodeDefinitionMap {\n // Create a mapping of root node identifers to root node definitions.\n const rootNodeMap: RootNodeDefinitionMap = {};\n\n // Add in any registered subtree root node definitions.\n for (const [name, rootNodeDefinition] of Object.entries(Lookup.getSubtrees())) {\n // The name used when registering the subtree will be used as the root node identifier.\n rootNodeMap[name] = { ...rootNodeDefinition, id: name };\n }\n\n // Populate the map with the root node definitions that were included with the tree definition.\n // We do this after adding any registered subtrees as we want these to take presedence.\n for (const rootNodeDefinition of definition) {\n rootNodeMap[rootNodeDefinition.id ?? MAIN_ROOT_NODE_KEY] = rootNodeDefinition;\n }\n\n return rootNodeMap;\n}\n\n/**\n * Applies a guard path to every leaf of the tree to evaluate as part of each update.\n * @param root The main root tree node.\n */\nfunction applyLeafNodeGuardPaths(root: Root) {\n const nodePaths: Node[][] = [];\n\n const findLeafNodes = (path: Node[], node: Node) => {\n // Add the current node to the path.\n path = path.concat(node);\n\n // Check whether the current node is a leaf node.\n if (node.isLeafNode()) {\n nodePaths.push(path);\n } else {\n (node as Composite | Decorator).getChildren().forEach((child) => findLeafNodes(path, child));\n }\n };\n\n // Find all leaf node paths, starting from the root.\n findLeafNodes([], root);\n\n nodePaths.forEach((path) => {\n // Each node in the current path will have to be assigned a guard path, working from the root outwards.\n for (let depth = 0; depth < path.length; depth++) {\n // Get the node in the path at the current depth.\n const currentNode = path[depth];\n\n // The node may already have been assigned a guard path, if so just skip it.\n if (currentNode.hasGuardPath()) {\n continue;\n }\n\n // Create the guard path for the current node.\n const guardPath = new GuardPath(\n path\n .slice(0, depth + 1)\n .map((node) => ({ node, guards: node.getGuardAttributes() }))\n .filter((details) => details.guards.length > 0)\n );\n\n // Assign the guard path to the current node.\n currentNode.setGuardPath(guardPath);\n }\n });\n}\n", "import State, { AnyState } from \"./State\";\nimport Lookup from \"./Lookup\";\nimport Node from \"./nodes/Node\";\nimport Root from \"./nodes/decorator/Root\";\nimport Composite from \"./nodes/composite/Composite\";\nimport Decorator from \"./nodes/decorator/Decorator\";\nimport { Agent, GlobalFunction } from \"./Agent\";\nimport { CallbackAttributeDetails } from \"./attributes/callbacks/Callback\";\nimport { GuardAttributeDetails } from \"./attributes/guards/Guard\";\nimport { BehaviourTreeOptions } from \"./BehaviourTreeOptions\";\nimport { convertMDSLToJSON } from \"./mdsl/MDSLDefinitionParser\";\nimport { RootNodeDefinition } from \"./BehaviourTreeDefinition\";\nimport { validateDefinition, validateJSONDefinition } from \"./BehaviourTreeDefinitionValidator\";\nimport buildRootNode from \"./BehaviourTreeBuilder\";\nimport { isNullOrUndefined } from \"./BehaviourTreeDefinitionUtilities\";\n\n// Purely for outside inspection of the tree.\nexport type FlattenedTreeNode = {\n id: string;\n type: string;\n caption: string;\n state: AnyState;\n guards: GuardAttributeDetails[];\n callbacks: CallbackAttributeDetails[];\n args: any[];\n parentId: string | null;\n};\n\n/**\n * A representation of a behaviour tree.\n */\nexport class BehaviourTree {\n /**\n * The main root tree node.\n */\n public readonly rootNode: Root;\n\n /**\n * Creates a new instance of the BehaviourTree class.\n * @param definition The behaviour tree definition.\n * @param agent The agent instance that this behaviour tree is modelling behaviour for.\n * @param options The behaviour tree options object.\n */\n constructor(\n definition: string | RootNodeDefinition | RootNodeDefinition[],\n private agent: Agent,\n private options: BehaviourTreeOptions = {}\n ) {\n // The tree definition must be defined.\n if (isNullOrUndefined(definition)) {\n throw new Error(\"tree definition not defined\");\n }\n\n // The agent must be defined and not null.\n if (typeof agent !== \"object\" || agent === null) {\n throw new Error(\"the agent must be an object and not null\");\n }\n\n // We should validate the definition before we try to build the tree nodes.\n const { succeeded, errorMessage, json } = validateDefinition(definition);\n\n // Did our validation fail without error?\n if (!succeeded) {\n throw new Error(`invalid definition: ${errorMessage}`);\n }\n\n // Double check that we did actually get our json definition as part of our definition validtion.\n if (!json) {\n throw new Error(\n \"expected json definition to be returned as part of successful definition validation response\"\n );\n }\n\n try {\n // Create the populated tree of behaviour tree nodes and get the root node.\n this.rootNode = buildRootNode(json!);\n } catch (exception) {\n // There was an issue in trying build and populate the behaviour tree.\n throw new Error(`error building tree: ${(exception as Error).message}`);\n }\n }\n\n /**\n * Gets whether the tree is in the RUNNING state.\n * @returns true if the tree is in the RUNNING state, otherwise false.\n */\n isRunning() {\n return this.rootNode.getState() === State.RUNNING;\n }\n\n /**\n * Gets the current tree state of SUCCEEDED, FAILED, READY or RUNNING.\n * @returns The current tree state.\n */\n getState() {\n return this.rootNode.getState();\n }\n\n /**\n * Step the tree.\n * 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.\n * 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\n * 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.\n *\n * 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.\n */\n step() {\n // If the root node has already been stepped to completion then we need to reset it.\n if (this.rootNode.getState() === State.SUCCEEDED || this.rootNode.getState() === State.FAILED) {\n this.rootNode.reset();\n }\n\n try {\n this.rootNode.update(this.agent, this.options);\n } catch (exception) {\n throw new Error(`error stepping tree: ${(exception as Error).message}`);\n }\n }\n\n /**\n * Resets the tree from the root node outwards to each nested node, giving each a state of READY.\n */\n reset() {\n this.rootNode.reset();\n }\n\n /**\n * Gets the flattened details of every node in the tree.\n * @returns The flattened details of every node in the tree.\n */\n getFlattenedNodeDetails(): FlattenedTreeNode[] {\n // Create an empty flattened array of tree nodes.\n const flattenedTreeNodes: FlattenedTreeNode[] = [];\n\n /**\n * Helper function to process a node instance and push details into the flattened tree nodes array.\n * @param node The current node.\n * @param parentUid The UID of the node parent, or null if the node is the main root node.\n */\n const processNode = (node: Node, parentUid: string | null) => {\n // Get the guard and callback attribute details for this node.\n const guards = node\n .getAttributes()\n .filter((attribute) => attribute.isGuard())\n .map((attribute) => attribute.getDetails()) as GuardAttributeDetails[];\n const callbacks = node\n .getAttributes()\n .filter((attribute) => !attribute.isGuard())\n .map((attribute) => attribute.getDetails()) as CallbackAttributeDetails[];\n\n // Push the current node into the flattened nodes array.\n flattenedTreeNodes.push({\n id: node.getUid(),\n type: node.getType(),\n caption: node.getName(),\n state: node.getState(),\n guards,\n callbacks,\n args: node.getArguments(),\n parentId: parentUid\n });\n\n // Process each of the nodes children if it is not a leaf node.\n if (!node.isLeafNode()) {\n (node as Composite | Decorator)\n .getChildren()\n .forEach((child) => processNode(child, (node as Composite | Decorator).getUid()));\n }\n };\n\n // Convert the nested node structure into a flattened array of node details.\n processNode(this.rootNode, null);\n\n return flattenedTreeNodes;\n }\n\n /**\n * Registers the action/condition/guard/callback function or subtree with the given name.\n * @param name The name of the function or subtree to register.\n * @param value The function or subtree definition to register.\n */\n static register(name: string, value: GlobalFunction | string | RootNodeDefinition) {\n // Are we going to register a action/condition/guard/callback function?\n if (typeof value === \"function\") {\n Lookup.setFunc(name, value);\n return;\n }\n\n // We are not registering an action/condition/guard/callback function, so we must be registering a subtree.\n if (typeof value === \"string\") {\n let rootNodeDefinitions: RootNodeDefinition[];\n\n // We will assume that any string passed in will be a mdsl definition.\n try {\n rootNodeDefinitions = convertMDSLToJSON(value);\n } catch (exception) {\n throw new Error(`error registering definition, invalid MDSL: ${(exception as Error).message}`);\n }\n\n // This function should only ever be called with a definition containing a single unnamed root node.\n if (rootNodeDefinitions.length != 1 || rootNodeDefinitions[0].id !== null) {\n throw new Error(\"error registering definition: expected a single unnamed root node\");\n }\n\n try {\n // We should validate the subtree as we don't want invalid subtrees available via the lookup.\n const { succeeded, errorMessage } = validateJSONDefinition(rootNodeDefinitions[0]);\n\n // Did our validation fail without error?\n if (!succeeded) {\n throw new Error(errorMessage);\n }\n } catch (exception) {\n throw new Error(`error registering definition: ${(exception as Error).message}`);\n }\n\n // Everything seems hunky-dory, register the subtree.\n Lookup.setSubtree(name, rootNodeDefinitions[0]);\n } else if (typeof value === \"object\" && !Array.isArray(value)) {\n // We will assume that any object passed in is a root node definition.\n\n try {\n // We should validate the subtree as we don't want invalid subtrees available via the lookup.\n const { succeeded, errorMessage } = validateJSONDefinition(value);\n\n // Did our validation fail without error?\n if (!succeeded) {\n throw new Error(errorMessage);\n }\n } catch (exception) {\n throw new Error(`error registering definition: ${(exception as Error).message}`);\n }\n\n // Everything seems hunky-dory, register the subtree.\n Lookup.setSubtree(name, value);\n } else {\n throw new Error(\"unexpected value, expected string mdsl definition, root node json definition or function\");\n }\n }\n\n /**\n * Unregisters the registered action/condition/guard/callback function or subtree with the given name.\n * @param name The name of the registered action/condition/guard/callback function or subtree to unregister.\n */\n static unregister(name: string): void {\n Lookup.remove(name);\n }\n\n /**\n * Unregister all registered action/condition/guard/callback functions and subtrees.\n */\n static unregisterAll(): void {\n Lookup.empty();\n }\n}\n"], + "mappings": "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", "names": ["Participant", "isNullOrUndefined", "Lotto", "createLotto", "State", "createLotto"] } diff --git a/dist/index.js b/dist/index.js index 27e9ddb..f7cd245 100644 --- a/dist/index.js +++ b/dist/index.js @@ -818,7 +818,10 @@ function validateMDSLDefinition(definition) { } catch (exception) { return createValidationFailureResult(exception.message); } - return { succeeded: true }; + return { + succeeded: true, + json: rootNodeDefinitions + }; } function validateJSONDefinition(definition) { const rootNodeDefinitions = Array.isArray(definition) ? definition : [definition]; @@ -851,7 +854,10 @@ function validateJSONDefinition(definition) { } catch (exception) { return createValidationFailureResult(exception.message); } - return { succeeded: true }; + return { + succeeded: true, + json: rootNodeDefinitions + }; } function validateBranchSubtreeLinks(rootNodeDefinitions, includesGlobalSubtrees) { const rootNodeMappings = rootNodeDefinitions.map( @@ -2167,12 +2173,17 @@ var BehaviourTree = class { if (typeof agent !== "object" || agent === null) { throw new Error("the agent must be an object and not null"); } - const { succeeded, errorMessage } = validateDefinition(definition); + const { succeeded, errorMessage, json } = validateDefinition(definition); if (!succeeded) { throw new Error(`invalid definition: ${errorMessage}`); } + if (!json) { + throw new Error( + "expected json definition to be returned as part of successful definition validation response" + ); + } try { - this.rootNode = this._createRootNode(definition); + this.rootNode = buildRootNode(json); } catch (exception) { throw new Error(`error building tree: ${exception.message}`); } @@ -2263,10 +2274,6 @@ var BehaviourTree = class { static unregisterAll() { Lookup.empty(); } - _createRootNode(definition) { - const resolvedDefinition = typeof definition === "string" ? convertMDSLToJSON(definition) : definition; - return buildRootNode(Array.isArray(resolvedDefinition) ? resolvedDefinition : [resolvedDefinition]); - } }; // Annotate the CommonJS export names for ESM import in node: 0 && (module.exports = { diff --git a/dist/index.js.map b/dist/index.js.map index 7828819..6f0e041 100644 --- a/dist/index.js.map +++ b/dist/index.js.map @@ -1,7 +1,7 @@ { "version": 3, "sources": ["../node_modules/lotto-draw/dist/Participant.js", "../node_modules/lotto-draw/dist/Utilities.js", "../node_modules/lotto-draw/dist/Lotto.js", "../node_modules/lotto-draw/dist/createLotto.js", "../node_modules/lotto-draw/dist/index.js", "../src/index.ts", "../src/State.ts", "../src/BehaviourTreeDefinitionUtilities.ts", "../src/mdsl/MDSLUtilities.ts", "../src/mdsl/MDSLNodeArgumentParser.ts", "../src/mdsl/MDSLNodeAttributeParser.ts", "../src/mdsl/MDSLDefinitionParser.ts", "../src/BehaviourTreeDefinitionValidator.ts", "../src/Lookup.ts", "../src/attributes/guards/GuardUnsatisifedException.ts", "../src/attributes/guards/GuardPath.ts", "../src/nodes/Node.ts", "../src/nodes/composite/Composite.ts", "../src/nodes/composite/Parallel.ts", "../src/nodes/composite/Selector.ts", "../src/nodes/composite/Sequence.ts", "../src/nodes/composite/Lotto.ts", "../src/nodes/decorator/Decorator.ts", "../src/nodes/decorator/Fail.ts", "../src/nodes/decorator/Flip.ts", "../src/nodes/decorator/Repeat.ts", "../src/nodes/decorator/Retry.ts", "../src/nodes/decorator/Root.ts", "../src/nodes/decorator/Succeed.ts", "../src/nodes/leaf/Leaf.ts", "../src/nodes/leaf/Action.ts", "../src/nodes/leaf/Condition.ts", "../src/nodes/leaf/Wait.ts", "../src/attributes/Attribute.ts", "../src/attributes/guards/Guard.ts", "../src/attributes/guards/While.ts", "../src/attributes/guards/Until.ts", "../src/attributes/callbacks/Callback.ts", "../src/attributes/callbacks/Entry.ts", "../src/attributes/callbacks/Step.ts", "../src/attributes/callbacks/Exit.ts", "../src/BehaviourTreeBuilder.ts", "../src/BehaviourTree.ts"], - "sourcesContent": ["\"use strict\";\r\nObject.defineProperty(exports, \"__esModule\", { value: true });\r\nexports.Participant = void 0;\r\n/**\r\n * A participant that holds a number of tickets.\r\n */\r\nvar Participant = /** @class */ (function () {\r\n /**\r\n * Creates an instance of the Participant class.\r\n * @param participant The actual participant.\r\n * @param tickets The number of tickets held by the participant.\r\n */\r\n function Participant(participant, tickets) {\r\n if (tickets === void 0) { tickets = 1; }\r\n this._participant = participant;\r\n this._tickets = tickets;\r\n }\r\n Object.defineProperty(Participant.prototype, \"participant\", {\r\n /** Gets the actual participant. */\r\n get: function () {\r\n return this._participant;\r\n },\r\n enumerable: false,\r\n configurable: true\r\n });\r\n Object.defineProperty(Participant.prototype, \"tickets\", {\r\n /** Gets or sets the number of tickets held by the participant. */\r\n get: function () {\r\n return this._tickets;\r\n },\r\n set: function (value) {\r\n this._tickets = value;\r\n },\r\n enumerable: false,\r\n configurable: true\r\n });\r\n return Participant;\r\n}());\r\nexports.Participant = Participant;\r\n", "\"use strict\";\r\nObject.defineProperty(exports, \"__esModule\", { value: true });\r\nexports.isNaturalNumber = exports.isNullOrUndefined = void 0;\r\n/**\r\n * Gets whether the value provided is null or undefined.\r\n * @param value The value to check.\r\n * @returns Whether the value provided is null or undefined.\r\n */\r\nfunction isNullOrUndefined(value) {\r\n return value === null || value === undefined;\r\n}\r\nexports.isNullOrUndefined = isNullOrUndefined;\r\n/**\r\n * Gets whether the value provided is a natural number.\r\n * @param value The value to check.\r\n * @returns Whether the value provided is a natural number.\r\n */\r\nfunction isNaturalNumber(value) {\r\n return typeof value === \"number\" && value >= 1 && Math.floor(value) === value;\r\n}\r\nexports.isNaturalNumber = isNaturalNumber;\r\n", "\"use strict\";\r\nObject.defineProperty(exports, \"__esModule\", { value: true });\r\nexports.Lotto = void 0;\r\nvar Participant_1 = require(\"./Participant\");\r\nvar Utilities_1 = require(\"./Utilities\");\r\n/**\r\n * Represents a lotto consisting of a number of pickable ticket-holding participants.\r\n */\r\nvar Lotto = /** @class */ (function () {\r\n /**\r\n * Creates a new instance of Lotto.\r\n * @param customRandom The custom RNG to use in place of Math.random().\r\n */\r\n function Lotto(customRandom) {\r\n /** The array of participants that are holding tickets in the lotto. */\r\n this._participants = [];\r\n this._customRandom = customRandom;\r\n }\r\n /**\r\n * Adds a participant with the specified number of tickets, or adds to the participant ticket count if the participant already holds tickets.\r\n * @param participant The participant to add or to increase the ticket count for if they already hold tickets.\r\n * @param tickets The number of tickets, defaults to 1.\r\n * @returns The Lotto instance.\r\n */\r\n Lotto.prototype.add = function (participant, tickets) {\r\n if (tickets === void 0) { tickets = 1; }\r\n // Check that we have a valid ticket count.\r\n if (!(0, Utilities_1.isNaturalNumber)(tickets)) {\r\n throw new Error(\"tickets value must be a natural number\");\r\n }\r\n // Check whether this participant has already been added.\r\n var existingParticipant = this._participants.find(function (part) { return part.participant === participant; });\r\n if (existingParticipant) {\r\n // The participant has already been added to the lotto so just add to their ticket count.\r\n existingParticipant.tickets += tickets;\r\n }\r\n else {\r\n // The participant is not part of the lotto so we should add them.\r\n this._participants.push(new Participant_1.Participant(participant, tickets));\r\n }\r\n return this;\r\n };\r\n /**\r\n * Removes the specified number of tickets for the given participant from the draw, or all tickets if a ticket number is not defined.\r\n * @param participant The participant to remove tickets for.\r\n * @param tickets The number of tickets to remove, or undefined if all tickets are to be removed.\r\n * @returns The Lotto instance.\r\n */\r\n Lotto.prototype.remove = function (participant, tickets) {\r\n // Attempt to get the existing participant.\r\n var existingParticipant = this._participants.find(function (part) { return part.participant === participant; });\r\n // There is nothing to do if the specified participant isn't even part of the lotto.\r\n if (!existingParticipant) {\r\n return this;\r\n }\r\n // Check whether a tickets value was given.\r\n if (tickets !== undefined) {\r\n // Check that we have a valid ticket count.\r\n if (!(0, Utilities_1.isNaturalNumber)(tickets)) {\r\n throw new Error(\"tickets value must be a natural number\");\r\n }\r\n existingParticipant.tickets -= tickets;\r\n // If the participant no longer holds any tickets then they should be removed.\r\n if (existingParticipant.tickets < 1) {\r\n this._participants = this._participants.filter(function (part) { return part !== existingParticipant; });\r\n }\r\n }\r\n else {\r\n // We are removing all tickets for the participant so just remove them from the lotto.\r\n this._participants = this._participants.filter(function (part) { return part !== existingParticipant; });\r\n }\r\n return this;\r\n };\r\n /**\r\n * Draw a winning ticket and return the participant that holds the ticket.\r\n * @param options The draw options.\r\n * @returns The participant that holds the winning ticket.\r\n */\r\n Lotto.prototype.draw = function (options) {\r\n if (options === void 0) { options = {}; }\r\n // If we have no participants then just return null.\r\n if (this._participants.length === 0) {\r\n return null;\r\n }\r\n var redrawable = (0, Utilities_1.isNullOrUndefined)(options.redrawable) ? true : options.redrawable;\r\n var pickable = [];\r\n this._participants.forEach(function (_a) {\r\n var participant = _a.participant, tickets = _a.tickets;\r\n for (var ticketCount = 0; ticketCount < tickets; ticketCount++) {\r\n pickable.push(participant);\r\n }\r\n });\r\n var random;\r\n // We need a random floating-point number between 0 (inclusive) and 1 to scale up to pick our winner.\r\n // If a custom random function exists then we should use that or fall back to Math.random().\r\n if (this._customRandom) {\r\n // Call our custom random function to get a random floating-point number.\r\n random = this._customRandom();\r\n // Verify that the result of calling our custom random function is a number between 0 (inclusive) and 1.\r\n if (typeof random !== \"number\" || random < 0 || random >= 1) {\r\n throw new Error(\"the 'random' function provided did not return a number between 0 (inclusive) and 1\");\r\n }\r\n }\r\n else {\r\n // No custom random function was defined so just use good ol' Math.random().\r\n random = Math.random();\r\n }\r\n // Pick a winning participant.\r\n var winner = pickable[Math.floor(random * pickable.length)];\r\n // If the ticket isn't redrawable then we should remove a ticket from the winning participants ticket count.\r\n if (!redrawable) {\r\n this.remove(winner, 1);\r\n }\r\n // Return the winning participant.\r\n return winner;\r\n };\r\n /**\r\n * Draws multiple winning tickets and return an array of the participants that hold the winning tickets.\r\n * @param tickets The number of winning tickets to draw.\r\n * @param options The draw multiple options.\r\n * @returns An array of the participants that hold the winning tickets.\r\n */\r\n Lotto.prototype.drawMultiple = function (tickets, options) {\r\n if (options === void 0) { options = {}; }\r\n var uniqueResults = (0, Utilities_1.isNullOrUndefined)(options.unique) ? false : options.unique;\r\n // Handle cases where the user has asked for zero tickets (no idea why they would do this be we should trust them).\r\n if (tickets === 0) {\r\n return [];\r\n }\r\n // Now that we know out tickets value is not zero we should check that it is a valid natural number.\r\n if (!(0, Utilities_1.isNaturalNumber)(tickets)) {\r\n throw new Error(\"tickets value must be a natural number\");\r\n }\r\n var result = [];\r\n // Keep drawing tickets until we either reach the number of required tickets or we simply run out of tickets to draw.\r\n // We can run out of tickets to draw if 'options.redrawable' is explicity 'false' or we just had no participants when 'drawMultiple' was called.\r\n while (result.length < tickets && this._participants.length > 0) {\r\n result.push(this.draw(options));\r\n }\r\n // If the 'unique' draw option is set then we need to remove duplicates from the result list.\r\n if (uniqueResults) {\r\n // Create an array to store our unique results.\r\n var unique = [];\r\n // Iterate over all of our participants (with potential duplicates) and populate our array of unique values.\r\n for (var _i = 0, result_1 = result; _i < result_1.length; _i++) {\r\n var participant = result_1[_i];\r\n if (unique.indexOf(participant) === -1) {\r\n unique.push(participant);\r\n }\r\n }\r\n result = unique;\r\n }\r\n return result;\r\n };\r\n return Lotto;\r\n}());\r\nexports.Lotto = Lotto;\r\n", "\"use strict\";\r\nObject.defineProperty(exports, \"__esModule\", { value: true });\r\nexports.createLotto = void 0;\r\nvar Lotto_1 = require(\"./Lotto\");\r\n/**\r\n * A function that creates and returns a Lotto instance.\r\n * @param participantsOrOptions An array of initial participants or options relating to the creation of a Lotto instance.\r\n * @returns A new Lotto instance.\r\n */\r\nfunction createLotto(participantsOrOptions) {\r\n // If no initial participants or lotto options were provided as an argument then we can just return a new lotto instance now.\r\n if (!participantsOrOptions) {\r\n return new Lotto_1.Lotto();\r\n }\r\n // Check whether we were provided with an array of initial participants or a lotto options object.\r\n if (Array.isArray(participantsOrOptions)) {\r\n // We are dealing with a pre-defined array of participants.\r\n var participants = participantsOrOptions;\r\n var lotto_1 = new Lotto_1.Lotto();\r\n // If the lotto participants have been defined upfront then we will need to add them all to our lotto instance now.\r\n participants.forEach(function (_a) {\r\n var participant = _a[0], tokens = _a[1];\r\n return lotto_1.add(participant, tokens);\r\n });\r\n // Return the Lotto instance.\r\n return lotto_1;\r\n }\r\n else {\r\n // We are dealing with some lotto options.\r\n var random = participantsOrOptions.random, participants = participantsOrOptions.participants;\r\n // Create a Lotto instance passing the custom RNG function to use in place of Math.random() (which could be undefined).\r\n var lotto_2 = new Lotto_1.Lotto(random);\r\n // If the lotto participants have been defined upfront as part of the options then we will need to add them all to our lotto instance now.\r\n if (participants) {\r\n participants.forEach(function (_a) {\r\n var participant = _a[0], tokens = _a[1];\r\n return lotto_2.add(participant, tokens);\r\n });\r\n }\r\n // Return the Lotto instance.\r\n return lotto_2;\r\n }\r\n}\r\nexports.createLotto = createLotto;\r\n", "\"use strict\";\r\nObject.defineProperty(exports, \"__esModule\", { value: true });\r\nvar createLotto_1 = require(\"./createLotto\");\r\nexports.default = createLotto_1.createLotto;\r\n", "import State from \"./State\";\nimport { validateDefinition } from \"./BehaviourTreeDefinitionValidator\";\nimport { convertMDSLToJSON } from \"./mdsl/MDSLDefinitionParser\";\nimport { BehaviourTree, FlattenedTreeNode } from \"./BehaviourTree\";\nimport { BehaviourTreeOptions } from \"./BehaviourTreeOptions\";\n\nexport { BehaviourTree, State, convertMDSLToJSON, validateDefinition };\nexport type { FlattenedTreeNode, BehaviourTreeOptions };\n", "/**\n * Enumeration of node state types.\n */\nexport enum State {\n READY = \"mistreevous.ready\",\n RUNNING = \"mistreevous.running\",\n SUCCEEDED = \"mistreevous.succeeded\",\n FAILED = \"mistreevous.failed\"\n}\n\nexport { State as default };\n\nexport type CompleteState = State.SUCCEEDED | State.FAILED;\nexport type AnyState = State.READY | State.RUNNING | CompleteState;\n", "import {\n NodeDefinition,\n RootNodeDefinition,\n DecoratorNodeDefinition,\n CompositeNodeDefinition,\n AnyNodeDefinition,\n BranchNodeDefinition\n} from \"./BehaviourTreeDefinition\";\n\n/**\n * A type guard function that returns true if the specified node satisfies the RootNodeDefinition type.\n * @param node The node.\n * @returns A value of true if the specified node satisfies the RootNodeDefinition type.\n */\nexport function isRootNode(node: NodeDefinition): node is RootNodeDefinition {\n return node.type === \"root\";\n}\n\n/**\n * A type guard function that returns true if the specified node satisfies the BranchNodeDefinition type.\n * @param node The node.\n * @returns A value of true if the specified node satisfies the BranchNodeDefinition type.\n */\nexport function isBranchNode(node: NodeDefinition): node is BranchNodeDefinition {\n return node.type === \"branch\";\n}\n\n/**\n * A type guard function that returns true if the specified node satisfies the NodeDefinition type.\n * @param node The node.\n * @returns A value of true if the specified node satisfies the NodeDefinition type.\n */\nexport function isLeafNode(node: NodeDefinition): node is NodeDefinition {\n return [\"branch\", \"action\", \"condition\", \"wait\"].includes(node.type);\n}\n\n/**\n * A type guard function that returns true if the specified node satisfies the DecoratorNodeDefinition type.\n * @param node The node.\n * @returns A value of true if the specified node satisfies the DecoratorNodeDefinition type.\n */\nexport function isDecoratorNode(node: NodeDefinition): node is DecoratorNodeDefinition {\n return [\"root\", \"repeat\", \"retry\", \"flip\", \"succeed\", \"fail\"].includes(node.type);\n}\n\n/**\n * A type guard function that returns true if the specified node satisfies the CompositeNodeDefinition type.\n * @param node The node.\n * @returns A value of true if the specified node satisfies the CompositeNodeDefinition type.\n */\nexport function isCompositeNode(node: NodeDefinition): node is CompositeNodeDefinition {\n return [\"sequence\", \"selector\", \"lotto\", \"parallel\"].includes(node.type);\n}\n\n/**\n * Flatten a node definition into an array of all of its nested node definitions.\n * @param nodeDefinition The node definition to flatten.\n * @returns An array of all of nested node definitions.\n */\nexport function flattenDefinition(nodeDefinition: AnyNodeDefinition): AnyNodeDefinition[] {\n const nodes: AnyNodeDefinition[] = [];\n\n const processNode = (currentNodeDefinition: AnyNodeDefinition) => {\n nodes.push(currentNodeDefinition);\n\n if (isCompositeNode(currentNodeDefinition)) {\n currentNodeDefinition.children.forEach(processNode);\n } else if (isDecoratorNode(currentNodeDefinition)) {\n processNode(currentNodeDefinition.child);\n }\n };\n\n processNode(nodeDefinition);\n\n return nodes;\n}\n\n/**\n * Determines whether the passed value is an integer.\n * @param value The value to check.\n * @returns Whether the passed value is an integer.\n */\nexport function isInteger(value: unknown): boolean {\n return typeof value === \"number\" && Math.floor(value) === value;\n}\n\n/**\n * Determines whether the passed value is null or undefined.\n * @param value The value to check.\n * @returns Whether the passed value is null or undefined.\n */\nexport function isNullOrUndefined(value: unknown): boolean {\n return typeof value === \"undefined\" || value === null;\n}\n", "/**\n * A type defining an object that holds a reference to substitued string literals parsed from the definition.\n */\nexport type StringLiteralPlaceholders = { [key: string]: string };\n\n/**\n * Pop the next raw token from the specified array of tokens and throw an error if it wasn't the expected one.\n * @param tokens The array of tokens.\n * @param expected An optional string or array or items, one of which must match the next popped token.\n * @returns The popped token.\n */\nexport function popAndCheck(tokens: string[], expected?: string | string[]): string {\n // Get and remove the next token.\n const popped = tokens.shift();\n\n // We were expecting another token but there aren't any.\n if (popped === undefined) {\n throw new Error(\"unexpected end of definition\");\n }\n\n // Do we have an expected token/tokens array?\n if (expected != undefined) {\n // Get an array of expected values, if the popped token matches any then we are all good.\n const expectedValues = typeof expected === \"string\" ? [expected] : expected;\n\n // Check whether the popped token matches at least one of our expected items.\n var tokenMatchesExpectation = expectedValues.some((item) => popped.toUpperCase() === item.toUpperCase());\n\n // Throw an error if the popped token didn't match any of our expected items.\n if (!tokenMatchesExpectation) {\n const expectationString = expectedValues.map((item) => \"'\" + item + \"'\").join(\" or \");\n throw new Error(\"unexpected token found. Expected \" + expectationString + \" but got '\" + popped + \"'\");\n }\n }\n\n // Return the popped token.\n return popped;\n}\n\n/**\n * Swaps out any node/attribute argument string literals with placeholders.\n * @param definition The definition.\n * @returns An object containing a mapping of placeholders to original string values as well as the processed definition string.\n */\nexport function substituteStringLiterals(definition: string): {\n placeholders: StringLiteralPlaceholders;\n processedDefinition: string;\n} {\n // Create an object to hold the mapping of placeholders to original string values.\n const placeholders: StringLiteralPlaceholders = {};\n\n // Replace any string literals wrapped with double quotes in our definition with placeholders to be processed later.\n const processedDefinition = definition.replace(/\\\"(\\\\.|[^\"\\\\])*\\\"/g, (match) => {\n var strippedMatch = match.substring(1, match.length - 1);\n var placeholder = Object.keys(placeholders).find((key) => placeholders[key] === strippedMatch);\n\n // If we have no existing string literal match then create a new placeholder.\n if (!placeholder) {\n placeholder = `@@${Object.keys(placeholders).length}@@`;\n placeholders[placeholder] = strippedMatch;\n }\n\n return placeholder;\n });\n\n return { placeholders, processedDefinition };\n}\n\n/**\n * Parse the tree definition into an array of raw tokens.\n * @param definition The definition.\n * @returns An array of tokens parsed from the definition.\n */\nexport function parseTokensFromDefinition(definition: string): string[] {\n // Add some space around various important characters so that they can be plucked out easier as individual tokens.\n definition = definition.replace(/\\(/g, \" ( \");\n definition = definition.replace(/\\)/g, \" ) \");\n definition = definition.replace(/\\{/g, \" { \");\n definition = definition.replace(/\\}/g, \" } \");\n definition = definition.replace(/\\]/g, \" ] \");\n definition = definition.replace(/\\[/g, \" [ \");\n definition = definition.replace(/\\,/g, \" , \");\n\n // Split the definition into raw token form and return it.\n return definition.replace(/\\s+/g, \" \").trim().split(\" \");\n}\n", "import { StringLiteralPlaceholders, popAndCheck } from \"./MDSLUtilities\";\n\n/**\n * A type representing any node function argument.\n */\ntype Argument = {\n /**\n * The argument value.\n */\n value: T;\n /**\n * The argument type, used for validation.\n */\n type: string;\n};\n\ntype NullArgument = Argument & {\n type: \"null\";\n};\n\ntype BooleanArgument = Argument & {\n type: \"boolean\";\n};\n\ntype NumberArgument = Argument & {\n type: \"number\";\n /**\n * A flag defining whether the number argument value is a valid integer. (used for validation)\n */\n isInteger: boolean;\n};\n\ntype StringPlaceholderArgument = Argument & {\n type: \"string\";\n};\n\ntype IdentifierArgument = Argument & {\n type: \"identifier\";\n};\n\n/**\n * A type representing a reference to any node function argument.\n */\ntype AnyArgument = NullArgument | BooleanArgument | NumberArgument | StringPlaceholderArgument | IdentifierArgument;\n\n/**\n * Parse an array of argument definitions from the specified tokens array.\n * @param tokens The array tokens to parse the argument definitions from.\n * @param stringArgumentPlaceholders The mapping of string literal node argument placeholders to original values.\n * @param argumentValidator The argument validator function.\n * @param validationFailedMessage The exception message to throw if argument validation fails.\n * @returns An array of argument definitions parsed from the specified tokens array.\n */\nexport function parseArgumentTokens(\n tokens: string[],\n stringArgumentPlaceholders: StringLiteralPlaceholders\n): AnyArgument[] {\n const argumentList: AnyArgument[] = [];\n\n // If the next token is not a '[' or '(' then we have no arguments to parse.\n if (![\"[\", \"(\"].includes(tokens[0])) {\n return argumentList;\n }\n\n // Any lists of arguments will always be wrapped in '[]' for node arguments or '()' for attribute arguments.\n // We are looking for a '[' or '(' opener that wraps the argument tokens and the relevant closer.\n const closingToken = popAndCheck(tokens, [\"[\", \"(\"]) === \"[\" ? \"]\" : \")\";\n\n const argumentListTokens: string[] = [];\n\n // Grab all tokens between the '[' and ']' or '(' and ')'.\n while (tokens.length && tokens[0] !== closingToken) {\n // The next token is part of our arguments list.\n argumentListTokens.push(tokens.shift()!);\n }\n\n // Validate the order of the argument tokens. Each token must either be a ',' or a single argument that satisfies the validator.\n argumentListTokens.forEach((token, index) => {\n // Get whether this token should be an actual argument.\n const shouldBeArgumentToken = !(index & 1);\n\n // If the current token should be an actual argument then validate it, otherwise it should be a ',' token.\n if (shouldBeArgumentToken) {\n // Get the argument definition.\n const argumentDefinition = getArgumentDefinition(token, stringArgumentPlaceholders);\n\n // This is a valid argument!\n argumentList.push(argumentDefinition);\n } else {\n // The current token should be a ',' token.\n if (token !== \",\") {\n throw new Error(`invalid argument list, expected ',' or ']' but got '${token}'`);\n }\n }\n });\n\n // The arguments list should terminate with a ']' or ')' token, depending on the opener.\n popAndCheck(tokens, closingToken);\n\n // Return the arguments.\n return argumentList;\n}\n\n/**\n * Gets an argument value definition.\n * @param token The argument token.\n * @param stringArgumentPlaceholders The mapping of string literal node argument placeholders to original values.\n * @returns An argument value definition.\n */\nfunction getArgumentDefinition(token: string, stringArgumentPlaceholders: StringLiteralPlaceholders): AnyArgument {\n // Check whether the token represents a null value.\n if (token === \"null\") {\n return {\n value: null,\n type: \"null\"\n } as NullArgument;\n }\n\n // Check whether the token represents a boolean value.\n if (token === \"true\" || token === \"false\") {\n return {\n value: token === \"true\",\n type: \"boolean\"\n } as BooleanArgument;\n }\n\n // Check whether the token represents a number value.\n // TODO: Relies on broken isNaN - see MDN.\n // if (!Number.isNaN(token)) {\n if (!isNaN(token as any)) {\n return {\n value: parseFloat(token),\n isInteger: parseFloat(token) === parseInt(token, 10),\n type: \"number\"\n } as NumberArgument;\n }\n\n // Check whether the token is a placeholder (e.g. @@0@@) representing a string literal.\n if (token.match(/^@@\\d+@@$/g)) {\n return {\n value: stringArgumentPlaceholders[token].replace('\\\\\"', '\"'),\n type: \"string\"\n } as StringPlaceholderArgument;\n }\n\n // The only remaining option is that the argument value is an identifier.\n return {\n value: token,\n type: \"identifier\"\n } as IdentifierArgument;\n}\n", "import { NodeAttributeDefinition } from \"../BehaviourTreeDefinition\";\nimport { parseArgumentTokens } from \"./MDSLNodeArgumentParser\";\nimport { StringLiteralPlaceholders } from \"./MDSLUtilities\";\n\n/**\n * A type defining the attribute definitions of a node.\n */\ntype NodeAttributes = {\n while?: NodeAttributeDefinition;\n until?: NodeAttributeDefinition;\n entry?: NodeAttributeDefinition;\n exit?: NodeAttributeDefinition;\n step?: NodeAttributeDefinition;\n};\n\n/**\n * Parse any node attribute definitions from the specified tokens array.\n * @param tokens The array of remaining tokens.\n * @param stringArgumentPlaceholders The mapping of string literal node argument placeholders to original values.\n * @returns An object of attribute definitions defined by any directly following tokens.\n */\nexport function parseAttributeTokens(\n tokens: string[],\n stringArgumentPlaceholders: StringLiteralPlaceholders\n): NodeAttributes {\n const nodeAttributeNames: (keyof NodeAttributes)[] = [\"while\", \"until\", \"entry\", \"exit\", \"step\"];\n\n // Create an object to hold any attributes found.\n const attributes: NodeAttributes = {};\n\n // Try to get the name of the attribute for the next token.\n let nextAttributeName = tokens[0]?.toLowerCase() as keyof NodeAttributes;\n\n // Pull attribute tokens as well as their arguments off of the tokens stack until we have no more.\n while (nodeAttributeNames.includes(nextAttributeName)) {\n // Check to make sure that we have not already created an attribute definition of this type.\n if (attributes[nextAttributeName]) {\n throw new Error(`duplicate attribute '${tokens[0].toUpperCase()}' found for node`);\n }\n\n // Remove the attribute name token from the array of tokens.\n tokens.shift();\n\n // Grab the attribute arguments, assuming the first to be an identifier.\n const [attributeCallIdentifier, ...attributeArguments] = parseArgumentTokens(\n tokens,\n stringArgumentPlaceholders\n );\n\n // The first attribute argument has to be an identifer, this will reference an agent function.\n if (attributeCallIdentifier?.type !== \"identifier\") {\n throw new Error(\"expected agent function name identifier argument for attribute\");\n }\n\n // Any attribute arguments (other than the expected call identifier) must have a type of string, number, boolean or null.\n attributeArguments\n .filter((arg) => arg.type === \"identifier\")\n .forEach((arg) => {\n throw new Error(\n `invalid attribute argument value '${arg.value}', must be string, number, boolean or null`\n );\n });\n\n // Create the attribute definition and add it to the object of attribute definitions found.\n attributes[nextAttributeName] = {\n call: attributeCallIdentifier.value,\n args: attributeArguments.map(({ value }) => value)\n };\n\n // Try to get the next attribute name token, as there could be multiple.\n nextAttributeName = tokens[0]?.toLowerCase() as keyof NodeAttributes;\n }\n\n return attributes;\n}\n", "import {\n ActionNodeDefinition,\n AnyChildNodeDefinition,\n AnyNodeDefinition,\n BranchNodeDefinition,\n ConditionNodeDefinition,\n FailNodeDefinition,\n FlipNodeDefinition,\n LottoNodeDefinition,\n ParallelNodeDefinition,\n RepeatNodeDefinition,\n RetryNodeDefinition,\n RootNodeDefinition,\n SelectorNodeDefinition,\n SequenceNodeDefinition,\n SucceedNodeDefinition,\n WaitNodeDefinition\n} from \"../BehaviourTreeDefinition\";\nimport {\n isCompositeNode,\n isDecoratorNode,\n isLeafNode,\n isNullOrUndefined,\n isRootNode\n} from \"../BehaviourTreeDefinitionUtilities\";\nimport { parseArgumentTokens } from \"./MDSLNodeArgumentParser\";\nimport { parseAttributeTokens } from \"./MDSLNodeAttributeParser\";\nimport {\n StringLiteralPlaceholders,\n parseTokensFromDefinition,\n popAndCheck,\n substituteStringLiterals\n} from \"./MDSLUtilities\";\n\n/**\n * Convert the MDSL tree definition string into an equivalent JSON definition.\n * @param definition The tree definition string as MDSL.\n * @returns The root node JSON definitions.\n */\nexport function convertMDSLToJSON(definition: string): RootNodeDefinition[] {\n // Swap out any node/attribute argument string literals with a placeholder and get a mapping of placeholders to original values as well as the processed definition.\n const { placeholders, processedDefinition } = substituteStringLiterals(definition);\n\n // Parse our definition definition string into an array of raw tokens.\n const tokens = parseTokensFromDefinition(processedDefinition);\n\n return convertTokensToJSONDefinition(tokens, placeholders);\n}\n\n/**\n * Converts the specified tree definition tokens into a JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The root node JSON definitions.\n */\nfunction convertTokensToJSONDefinition(\n tokens: string[],\n stringLiteralPlaceholders: StringLiteralPlaceholders\n): RootNodeDefinition[] {\n // There must be at least 3 tokens for the tree definition to be valid. 'ROOT', '{' and '}'.\n if (tokens.length < 3) {\n throw new Error(\"invalid token count\");\n }\n\n // We should have a matching number of '{' and '}' tokens. If not, then there are scopes that have not been properly closed.\n if (tokens.filter((token) => token === \"{\").length !== tokens.filter((token) => token === \"}\").length) {\n throw new Error(\"scope character mismatch\");\n }\n\n // Create an array of tree stack arrays where root nodes will always be at the botton and the current composite/decorator node at the top.\n // There should be an element in this array for every root node defined and every element should be an array with a root note as the first element.\n // E.g. A definition with two root nodes defined:\n // [\n // [root, lotto, sequence],\n // [root, selector]\n // ]\n const treeStacks: [Partial, ...Partial[]][] = [];\n\n // Create an array of all root node definitions that we create.\n const rootNodes: Partial[] = [];\n\n // A helper function used to push node definitions onto the tree stack.\n const pushNode = (node: AnyNodeDefinition) => {\n // If the node is a root node then we need to create a new tree stack array with the root node at the root.\n if (isRootNode(node)) {\n // We need to double-check that this root node is not the child of another node.\n // We can do this by checking whether the top tree stack is not empty (contains an existing node)\n if (treeStacks[treeStacks.length - 1]?.length) {\n throw new Error(\"a root node cannot be the child of another node\");\n }\n\n // Add the root node definition to our array of all parsed root node definitions.\n rootNodes.push(node);\n\n // Add the root node definition to the root of a new tree stack.\n treeStacks.push([node]);\n\n return;\n }\n\n // All non-root nodes should be pushed after their root nodes so handle cases\n // where we may not have any tree stacks or our top-most tree stack is empty.\n if (!treeStacks.length || !treeStacks[treeStacks.length - 1].length) {\n throw new Error(\"expected root node at base of definition\");\n }\n\n // Get the current tree stack that we are populating.\n const topTreeStack = treeStacks[treeStacks.length - 1];\n\n // Get the top-most node in the current tree stack, this will be a composite/decorator node\n // for which we will populate its children array if composite or setting its child if a decorator.\n const topTreeStackTopNode = topTreeStack[topTreeStack.length - 1] as AnyNodeDefinition;\n\n // If the top-most node in the current root stack is a composite or decorator\n // node then the current node should be added as a child of the top-most node.\n if (isCompositeNode(topTreeStackTopNode)) {\n topTreeStackTopNode.children = topTreeStackTopNode.children || [];\n topTreeStackTopNode.children.push(node);\n } else if (isDecoratorNode(topTreeStackTopNode)) {\n // If the top node already has a child node set then throw an error as a decorator should only have a single child.\n if (topTreeStackTopNode.child) {\n throw new Error(\"a decorator node must only have a single child node\");\n }\n\n topTreeStackTopNode.child = node;\n }\n\n // If the node we are adding is also a composite or decorator node, then we should push it\n // onto the current tree stack, as subsequent nodes will be added as its child/children.\n if (!isLeafNode(node)) {\n topTreeStack.push(node);\n }\n };\n\n // A helper function used to pop the top-most node definition off of the tree stack and return it.\n const popNode = (): AnyNodeDefinition | null => {\n let poppedNode: AnyNodeDefinition | null = null;\n\n // Get the current tree stack that we are populating.\n const topTreeStack = treeStacks[treeStacks.length - 1];\n\n // Pop the top-most node in the current tree stack if there is one.\n if (topTreeStack.length) {\n poppedNode = topTreeStack.pop() as AnyNodeDefinition;\n }\n\n // We don't want any empty tree stacks in our stack of tree stacks.\n if (!topTreeStack.length) {\n treeStacks.pop();\n }\n\n return poppedNode;\n };\n\n // We should keep processing the raw tokens until we run out of them.\n while (tokens.length) {\n // Grab the next token.\n const token = tokens.shift()!;\n\n // How we create the next node depends on the current raw token value.\n switch (token.toUpperCase()) {\n case \"ROOT\": {\n pushNode(createRootNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"SUCCEED\": {\n pushNode(createSucceedNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"FAIL\": {\n pushNode(createFailNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"FLIP\": {\n pushNode(createFlipNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"REPEAT\": {\n pushNode(createRepeatNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"RETRY\": {\n pushNode(createRetryNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"SEQUENCE\": {\n pushNode(createSequenceNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"SELECTOR\": {\n pushNode(createSelectorNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"PARALLEL\": {\n pushNode(createParallelNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"LOTTO\": {\n pushNode(createLottoNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"ACTION\": {\n pushNode(createActionNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"CONDITION\": {\n pushNode(createConditionNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"WAIT\": {\n pushNode(createWaitNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"BRANCH\": {\n pushNode(createBranchNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"}\": {\n // The '}' character closes the current scope and means that we have to pop a node off of the current stack.\n const poppedNode = popNode();\n\n // Now that we have a node definition we can carry out any validation that may require the node to be fully populated.\n if (poppedNode) {\n validatePoppedNode(poppedNode);\n }\n\n break;\n }\n\n default: {\n throw new Error(`unexpected token: ${token}`);\n }\n }\n }\n\n return rootNodes as RootNodeDefinition[];\n}\n\n/**\n * Creates a root node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The root node JSON definition.\n */\nfunction createRootNode(tokens: string[], stringLiteralPlaceholders: StringLiteralPlaceholders): RootNodeDefinition {\n // Create the root node definition.\n let node = {\n type: \"root\",\n id: undefined\n } as RootNodeDefinition;\n\n // Parse any node arguments, we should only have one if any which will be an identifier argument for the root identifier.\n const nodeArguments = parseArgumentTokens(tokens, stringLiteralPlaceholders);\n\n // Check whether any node arguments were defined.\n if (nodeArguments.length) {\n // We should only have one argument, if any, which will be an identifier argument for the root identifier.\n if (nodeArguments.length === 1 && nodeArguments[0].type === \"identifier\") {\n // The root node identifier will be the first and only node argument value.\n node.id = nodeArguments[0].value as string;\n } else {\n throw new Error(\"expected single root name argument\");\n }\n }\n\n // Grab any node attribute definitions and spread them into the node definition.\n node = { ...node, ...parseAttributeTokens(tokens, stringLiteralPlaceholders) };\n\n // This is a decorator node, so we expect an opening '{'.\n popAndCheck(tokens, \"{\");\n\n // Return the root node definition.\n return node;\n}\n\n/**\n * Creates a succeed node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The succeed node JSON definition.\n */\nfunction createSucceedNode(\n tokens: string[],\n stringLiteralPlaceholders: StringLiteralPlaceholders\n): SucceedNodeDefinition {\n const node = {\n type: \"succeed\",\n ...parseAttributeTokens(tokens, stringLiteralPlaceholders)\n } as SucceedNodeDefinition;\n\n // This is a decorator node, so we expect an opening '{'.\n popAndCheck(tokens, \"{\");\n\n // Return the succeed node definition.\n return node;\n}\n\n/**\n * Creates a fail node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The fail node JSON definition.\n */\nfunction createFailNode(tokens: string[], stringLiteralPlaceholders: StringLiteralPlaceholders): FailNodeDefinition {\n const node = {\n type: \"fail\",\n ...parseAttributeTokens(tokens, stringLiteralPlaceholders)\n } as FailNodeDefinition;\n\n // This is a decorator node, so we expect an opening '{'.\n popAndCheck(tokens, \"{\");\n\n // Return the fail node definition.\n return node;\n}\n\n/**\n * Creates a flip node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The flip node JSON definition.\n */\nfunction createFlipNode(tokens: string[], stringLiteralPlaceholders: StringLiteralPlaceholders): FlipNodeDefinition {\n const node = {\n type: \"flip\",\n ...parseAttributeTokens(tokens, stringLiteralPlaceholders)\n } as FlipNodeDefinition;\n\n // This is a decorator node, so we expect an opening '{'.\n popAndCheck(tokens, \"{\");\n\n // Return the flip node definition.\n return node;\n}\n\n/**\n * Creates a repeat node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The repeat node JSON definition.\n */\nfunction createRepeatNode(\n tokens: string[],\n stringLiteralPlaceholders: StringLiteralPlaceholders\n): RepeatNodeDefinition {\n let node = { type: \"repeat\" } as RepeatNodeDefinition;\n\n // Get the node arguments.\n const nodeArguments = parseArgumentTokens(tokens, stringLiteralPlaceholders);\n\n // The arguments of a repeat node are optional. We may have:\n // - No node arguments, in which case the repeat note will iterate indefinitely.\n // - One node argument which will be the explicit number of iterations to make.\n // - Two node arguments which define the min and max iteration bounds from which a random iteration count will be picked.\n if (nodeArguments.length) {\n // All repeat node arguments MUST be of type number and must be integer.\n nodeArguments\n .filter((arg) => arg.type !== \"number\" || !arg.isInteger)\n .forEach(() => {\n throw new Error(`repeat node iteration counts must be integer values`);\n });\n\n // We should have got one or two iteration counts.\n if (nodeArguments.length === 1) {\n // A static iteration count was defined.\n node.iterations = nodeArguments[0].value as number;\n\n // A repeat node must have a positive number of iterations if defined.\n if (node.iterations < 0) {\n throw new Error(\"a repeat node must have a positive number of iterations if defined\");\n }\n } else if (nodeArguments.length === 2) {\n // A minimum and maximum iteration count was defined.\n node.iterations = [nodeArguments[0].value as number, nodeArguments[1].value as number];\n\n // A repeat node must have a positive min and max iteration count if they are defined.\n if (node.iterations[0] < 0 || node.iterations[1] < 0) {\n throw new Error(\"a repeat node must have a positive minimum and maximum iteration count if defined\");\n }\n\n // A repeat node must not have an minimum iteration count that exceeds the maximum iteration count.\n if (node.iterations[0] > node.iterations[1]) {\n throw new Error(\n \"a repeat node must not have a minimum iteration count that exceeds the maximum iteration count\"\n );\n }\n } else {\n // An incorrect number of iteration counts was defined.\n throw new Error(\"invalid number of repeat node iteration count arguments defined\");\n }\n }\n\n // Grab any node attribute definitions and spread them into the node definition.\n node = { ...node, ...parseAttributeTokens(tokens, stringLiteralPlaceholders) };\n\n // This is a decorator node, so we expect an opening '{'.\n popAndCheck(tokens, \"{\");\n\n // Return the repeat node definition.\n return node;\n}\n\n/**\n * Creates a retry node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The retry node JSON definition.\n */\nfunction createRetryNode(tokens: string[], stringLiteralPlaceholders: StringLiteralPlaceholders): RetryNodeDefinition {\n let node = { type: \"retry\" } as RetryNodeDefinition;\n\n // Get the node arguments.\n const nodeArguments = parseArgumentTokens(tokens, stringLiteralPlaceholders);\n\n // The arguments of a retry node are optional. We may have:\n // - No node arguments, in which case the retry note will attempt indefinitely.\n // - One node argument which will be the explicit number of attempts to make.\n // - Two node arguments which define the min and max attempt bounds from which a random attempt count will be picked.\n if (nodeArguments.length) {\n // All retry node arguments MUST be of type number and must be integer.\n nodeArguments\n .filter((arg) => arg.type !== \"number\" || !arg.isInteger)\n .forEach(() => {\n throw new Error(`retry node attempt counts must be integer values`);\n });\n\n // We should have got one or two attempt counts.\n if (nodeArguments.length === 1) {\n // A static attempt count was defined.\n node.attempts = nodeArguments[0].value as number;\n\n // A retry node must have a positive number of attempts if defined.\n if (node.attempts < 0) {\n throw new Error(\"a retry node must have a positive number of attempts if defined\");\n }\n } else if (nodeArguments.length === 2) {\n // A minimum and maximum attempt count was defined.\n node.attempts = [nodeArguments[0].value as number, nodeArguments[1].value as number];\n\n // A retry node must have a positive min and max attempts count if they are defined.\n if (node.attempts[0] < 0 || node.attempts[1] < 0) {\n throw new Error(\"a retry node must have a positive minimum and maximum attempt count if defined\");\n }\n\n // A retry node must not have a minimum attempt count that exceeds the maximum attempt count.\n if (node.attempts[0] > node.attempts[1]) {\n throw new Error(\n \"a retry node must not have a minimum attempt count that exceeds the maximum attempt count\"\n );\n }\n } else {\n // An incorrect number of attempt counts was defined.\n throw new Error(\"invalid number of retry node attempt count arguments defined\");\n }\n }\n\n // Grab any node attribute definitions and spread them into the node definition.\n node = { ...node, ...parseAttributeTokens(tokens, stringLiteralPlaceholders) };\n\n // This is a decorator node, so we expect an opening '{'.\n popAndCheck(tokens, \"{\");\n\n // Return the retry node definition.\n return node;\n}\n\n/**\n * Creates a sequence node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The sequence node JSON definition.\n */\nfunction createSequenceNode(\n tokens: string[],\n stringLiteralPlaceholders: StringLiteralPlaceholders\n): SequenceNodeDefinition {\n const node = {\n type: \"sequence\",\n ...parseAttributeTokens(tokens, stringLiteralPlaceholders)\n } as SequenceNodeDefinition;\n\n // This is a composite node, so we expect an opening '{'.\n popAndCheck(tokens, \"{\");\n\n // Return the sequence node definition.\n return node;\n}\n\n/**\n * Creates a selector node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The selector node JSON definition.\n */\nfunction createSelectorNode(\n tokens: string[],\n stringLiteralPlaceholders: StringLiteralPlaceholders\n): SelectorNodeDefinition {\n const node = {\n type: \"selector\",\n ...parseAttributeTokens(tokens, stringLiteralPlaceholders)\n } as SelectorNodeDefinition;\n\n // This is a composite node, so we expect an opening '{'.\n popAndCheck(tokens, \"{\");\n\n // Return the selector node definition.\n return node;\n}\n\n/**\n * Creates a parallel node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The parallel node JSON definition.\n */\nfunction createParallelNode(\n tokens: string[],\n stringLiteralPlaceholders: StringLiteralPlaceholders\n): ParallelNodeDefinition {\n const node = {\n type: \"parallel\",\n ...parseAttributeTokens(tokens, stringLiteralPlaceholders)\n } as ParallelNodeDefinition;\n\n // This is a composite node, so we expect an opening '{'.\n popAndCheck(tokens, \"{\");\n\n // Return the parallel node definition.\n return node;\n}\n\n/**\n * Creates a lotto node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The lotto node JSON definition.\n */\nfunction createLottoNode(tokens: string[], stringLiteralPlaceholders: StringLiteralPlaceholders): LottoNodeDefinition {\n // If any node arguments have been defined then they must be our weights.\n const nodeArguments = parseArgumentTokens(tokens, stringLiteralPlaceholders);\n\n // All lotto node arguments MUST be of type number and must be positive integers.\n nodeArguments\n .filter((arg) => arg.type !== \"number\" || !arg.isInteger || arg.value < 0)\n .forEach(() => {\n throw new Error(`lotto node weight arguments must be positive integer values`);\n });\n\n const node = {\n type: \"lotto\",\n weights: nodeArguments.length ? nodeArguments.map(({ value }) => value) : undefined,\n ...parseAttributeTokens(tokens, stringLiteralPlaceholders)\n } as LottoNodeDefinition;\n\n // This is a composite node, so we expect an opening '{'.\n popAndCheck(tokens, \"{\");\n\n // Return the lotto node definition.\n return node;\n}\n\n/**\n * Creates an action node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The action node JSON definition.\n */\nfunction createActionNode(\n tokens: string[],\n stringLiteralPlaceholders: StringLiteralPlaceholders\n): ActionNodeDefinition {\n // Parse any node arguments, we should have at least one which will be an identifier argument for the action name\n // and agent function to invoke for the action, all other arguments are to be passed as arguments to that function.\n const [actionNameIdentifier, ...agentFunctionArgs] = parseArgumentTokens(tokens, stringLiteralPlaceholders);\n\n // Our first argument MUST be defined and be an identifier as we require an action name argument.\n if (actionNameIdentifier?.type !== \"identifier\") {\n throw new Error(\"expected action name identifier argument\");\n }\n\n // Only the first argument should have been an identifier, all agent function arguments must be string, number, boolean or null.\n agentFunctionArgs\n .filter((arg) => arg.type === \"identifier\")\n .forEach((arg) => {\n throw new Error(\n `invalid action node argument value '${arg.value}', must be string, number, boolean or null`\n );\n });\n\n // Return the action node definition.\n return {\n type: \"action\",\n call: actionNameIdentifier.value,\n args: agentFunctionArgs.map(({ value }) => value),\n ...parseAttributeTokens(tokens, stringLiteralPlaceholders)\n };\n}\n\n/**\n * Creates a condition node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The condition node JSON definition.\n */\nfunction createConditionNode(\n tokens: string[],\n stringLiteralPlaceholders: StringLiteralPlaceholders\n): ConditionNodeDefinition {\n // Parse any node arguments, we should have at least one which will be an identifier argument for the condition name\n // and agent function to invoke for the condition, all other arguments are to be passed as arguments to that function.\n const [conditionNameIdentifier, ...agentFunctionArgs] = parseArgumentTokens(tokens, stringLiteralPlaceholders);\n\n // Our first argument MUST be defined and be an identifier as we require a condition name argument.\n if (conditionNameIdentifier?.type !== \"identifier\") {\n throw new Error(\"expected condition name identifier argument\");\n }\n\n // Only the first argument should have been an identifier, all agent function arguments must be string, number, boolean or null.\n agentFunctionArgs\n .filter((arg) => arg.type === \"identifier\")\n .forEach((arg) => {\n throw new Error(\n `invalid condition node argument value '${arg.value}', must be string, number, boolean or null`\n );\n });\n\n // Return the condition node definition.\n return {\n type: \"condition\",\n call: conditionNameIdentifier.value,\n args: agentFunctionArgs.map(({ value }) => value),\n ...parseAttributeTokens(tokens, stringLiteralPlaceholders)\n };\n}\n\n/**\n * Creates a wait node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The wait node JSON definition.\n */\nfunction createWaitNode(tokens: string[], stringLiteralPlaceholders: StringLiteralPlaceholders): WaitNodeDefinition {\n let node = { type: \"wait\" } as WaitNodeDefinition;\n\n // Get the node arguments.\n const nodeArguments = parseArgumentTokens(tokens, stringLiteralPlaceholders);\n\n // The arguments of a wait node are optional. We may have:\n // - No node arguments, in which case the wait will be indefinite until it is aborted.\n // - One node argument which will be the explicit duration of the wait.\n // - Two node arguments which define the min and max duration bounds from which a random duration will be picked.\n if (nodeArguments.length) {\n // All wait node arguments MUST be of type number and must be integer.\n nodeArguments\n .filter((arg) => arg.type !== \"number\" || !arg.isInteger)\n .forEach(() => {\n throw new Error(`wait node durations must be integer values`);\n });\n\n // We may have:\n // - One node argument which will be the explicit duration of the wait.\n // - Two node arguments which define the min and max duration bounds from which a random duration will be picked.\n // - Too many arguments, which is not valid.\n if (nodeArguments.length === 1) {\n // An explicit duration was defined.\n node.duration = nodeArguments[0].value as number;\n\n // If an explict duration was defined then it must be a positive number.\n if (node.duration < 0) {\n throw new Error(\"a wait node must have a positive duration\");\n }\n } else if (nodeArguments.length === 2) {\n // Min and max duration bounds were defined from which a random duration will be picked.\n node.duration = [nodeArguments[0].value as number, nodeArguments[1].value as number];\n\n // A wait node must have a positive min and max duration.\n if (node.duration[0] < 0 || node.duration[1] < 0) {\n throw new Error(\"a wait node must have a positive minimum and maximum duration\");\n }\n\n // A wait node must not have a minimum duration that exceeds the maximum duration.\n if (node.duration[0] > node.duration[1]) {\n throw new Error(\"a wait node must not have a minimum duration that exceeds the maximum duration\");\n }\n } else if (nodeArguments.length > 2) {\n // An incorrect number of duration arguments were defined.\n throw new Error(\"invalid number of wait node duration arguments defined\");\n }\n }\n\n // Return the wait node definition.\n return { ...node, ...parseAttributeTokens(tokens, stringLiteralPlaceholders) };\n}\n\n/**\n * Creates a branch node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The branch node JSON definition.\n */\nfunction createBranchNode(\n tokens: string[],\n stringLiteralPlaceholders: StringLiteralPlaceholders\n): BranchNodeDefinition {\n // Parse any node arguments, we should have one which will be an identifier argument for the root ref.\n const nodeArguments = parseArgumentTokens(tokens, stringLiteralPlaceholders);\n\n // We should have only a single identifer argument for a branch node, which is the root ref.\n if (nodeArguments.length !== 1 || nodeArguments[0].type !== \"identifier\") {\n throw new Error(\"expected single branch name argument\");\n }\n\n // Return the branch node definition.\n return { type: \"branch\", ref: nodeArguments[0].value };\n}\n\n/**\n * Validate a fully-populated node definition that was popped off of the tree stack.\n * @param definition The popped node to validate.\n */\nfunction validatePoppedNode(definition: AnyNodeDefinition): void {\n // Decorators MUST have a child defined.\n if (isDecoratorNode(definition) && isNullOrUndefined(definition.child)) {\n throw new Error(`a ${definition.type} node must have a single child node defined`);\n }\n\n // Composites MUST have at least one child defined.\n if (isCompositeNode(definition) && !definition.children?.length) {\n throw new Error(`a ${definition.type} node must have at least a single child node defined`);\n }\n\n // We need to make sure that lotto nodes that have weights defined have a number of weights matching the number of child nodes.\n if (definition.type === \"lotto\") {\n // Check whether a 'weights' property has been defined, if it has we expect it to be an array of weights.\n if (typeof definition.weights !== \"undefined\") {\n // Check that the weights property is an array of positive integers with an element for each child node element.\n if (definition.weights.length !== definition.children.length) {\n throw new Error(\n \"expected a number of weight arguments matching the number of child nodes for lotto node\"\n );\n }\n }\n }\n}\n", "import { RootNodeDefinition } from \"./BehaviourTreeDefinition\";\nimport { flattenDefinition, isBranchNode, isInteger } from \"./BehaviourTreeDefinitionUtilities\";\nimport { convertMDSLToJSON } from \"./mdsl/MDSLDefinitionParser\";\n\n/**\n * An object representing the result of validating a tree definition.\n */\nexport type DefinitionValidationResult = {\n /**\n * A flag defining whether validation succeeded.\n */\n succeeded: boolean;\n /**\n * A string containing the error message if validation did not succeed.\n */\n errorMessage?: string;\n};\n\n/**\n * Validates the specified behaviour tree definition in the form of JSON or MDSL, not taking any globally registered subtrees into consideration.\n * @param definition The behaviour tree definition in the form of JSON or MDSL.\n * @returns An object representing the result of validating the given tree definition.\n */\nexport function validateDefinition(definition: any): DefinitionValidationResult {\n // The definition must be defined.\n if (definition === null || typeof definition === \"undefined\") {\n return createValidationFailureResult(\"definition is null or undefined\");\n }\n\n // We are expecting a definition in one of three different forms:\n // - A string which we will assume is MDSL and we will parse this to JSON before validation.\n // - An array which we will assume is an array of root node definitions with at least one being the primary root node (no 'id' property)\n // - An object which we will assume is the primary root node and should not have an 'id' property.\n if (typeof definition === \"string\") {\n // The definition is a string which we can assume is MDSL, so attempt to validate it.\n return validateMDSLDefinition(definition);\n } else if (typeof definition === \"object\") {\n // The definition will either be an array (of root node definitions) or an object (the single primary root node definition).\n return validateJSONDefinition(definition);\n } else {\n return createValidationFailureResult(`unexpected definition type of '${typeof definition}'`);\n }\n}\n\n/**\n * Validates the specified behaviour tree definition in the form of MDSL.\n * @param definition The behaviour tree definition in the form of MDSL.\n * @returns An object representing the result of validating the given tree definition.\n */\nexport function validateMDSLDefinition(definition: string): DefinitionValidationResult {\n let rootNodeDefinitions;\n\n // The first thing the we need to do is to attempt to convert our MDSL into JSON.\n try {\n // The definition is a string which we can assume is MDSL, so attempt to parse it to a JSON definition in the form of an array of root node definitions.\n rootNodeDefinitions = convertMDSLToJSON(definition);\n } catch (exception) {\n // We failed to parse the JSON from the MDSL, this is likely to be the result of it not being a valid MDSL string.\n return createValidationFailureResult((exception as Error).message);\n }\n\n // Unpack all of the root node definitions into arrays of main ('id' defined) and sub ('id' not defined) root node definitions.\n const mainRootNodeDefinitions = rootNodeDefinitions.filter(({ id }) => typeof id === \"undefined\");\n const subRootNodeDefinitions = rootNodeDefinitions.filter(({ id }) => typeof id === \"string\" && id.length > 0);\n\n // We should ALWAYS have exactly one root node definition without an 'id' property defined, which is out main root node definition.\n if (mainRootNodeDefinitions.length !== 1) {\n return createValidationFailureResult(\n \"expected single unnamed root node at base of definition to act as main root\"\n );\n }\n\n // We should never have duplicate 'id' properties across our sub root node definitions.\n const subRootNodeIdenitifers: string[] = [];\n for (const { id } of subRootNodeDefinitions) {\n // Have we already come across this 'id' property value?\n if (subRootNodeIdenitifers.includes(id!)) {\n return createValidationFailureResult(`multiple root nodes found with duplicate name '${id}'`);\n }\n\n subRootNodeIdenitifers.push(id!);\n }\n\n try {\n // Validate our branch -> subtree links and check for any circular dependencies, we don't care about checking for broken subtree links here.\n validateBranchSubtreeLinks(rootNodeDefinitions, false);\n } catch (exception) {\n return createValidationFailureResult((exception as Error).message);\n }\n\n // Our definition was valid!\n return { succeeded: true };\n}\n\n/**\n * Validates the specified behaviour tree definition in the form of JSON.\n * @param definition The behaviour tree definition in the form of JSON.\n * @returns An object representing the result of validating the given tree definition.\n */\nexport function validateJSONDefinition(\n definition: RootNodeDefinition | RootNodeDefinition[]\n): DefinitionValidationResult {\n // The definition will either be an array (of root node definitions) or an object (the single primary root node definition).\n const rootNodeDefinitions = Array.isArray(definition) ? definition : [definition];\n\n // Iterate over our array of root nodes and call validateNode for each, passing an initial depth of 0, wrapped in a try catch to handle validation failures.\n try {\n rootNodeDefinitions.forEach((rootNodeDefinition) => validateNode(rootNodeDefinition, 0));\n } catch (error) {\n // Handle cases where we have caught a thrown Error and return a failure result with the error message.\n if (error instanceof Error) {\n return createValidationFailureResult(error.message);\n }\n\n // No idea what happened here!\n return createValidationFailureResult(`unexpected error: ${error}`);\n }\n\n // Unpack all of the root node definitions into arrays of main ('id' defined) and sub ('id' not defined) root node definitions.\n const mainRootNodeDefinitions = rootNodeDefinitions.filter(({ id }) => typeof id === \"undefined\");\n const subRootNodeDefinitions = rootNodeDefinitions.filter(({ id }) => typeof id === \"string\" && id.length > 0);\n\n // We should ALWAYS have exactly one root node definition without an 'id' property defined, which is out main root node definition.\n if (mainRootNodeDefinitions.length !== 1) {\n return createValidationFailureResult(\n \"expected single root node without 'id' property defined to act as main root\"\n );\n }\n\n // We should never have duplicate 'id' properties across our sub root node definitions.\n const subRootNodeIdenitifers: string[] = [];\n for (const { id } of subRootNodeDefinitions) {\n // Have we already come across this 'id' property value?\n if (subRootNodeIdenitifers.includes(id!)) {\n return createValidationFailureResult(\n `multiple root nodes found with duplicate 'id' property value of '${id}'`\n );\n }\n\n subRootNodeIdenitifers.push(id!);\n }\n\n try {\n // Validate our branch -> subtree links and check for any circular dependencies, we don't care about checking for broken subtree links here.\n validateBranchSubtreeLinks(rootNodeDefinitions, false);\n } catch (exception) {\n return createValidationFailureResult((exception as Error).message);\n }\n\n // Our definition was valid!\n return { succeeded: true };\n}\n\n/**\n * Validates the branch -> subtree links across all provided root node definitions.\n * This will not consider branch nodes that reference any globally registered subtrees unless includesGlobalSubtrees\n * is set to true, in which case we will also verify that there are no broken branch -> subtree links.\n * @param rootNodeDefinitions The array of root node definitions.\n * @param includesGlobalSubtrees A flag defining whether the array includes all global subtree root node definitions.\n */\nexport function validateBranchSubtreeLinks(rootNodeDefinitions: RootNodeDefinition[], includesGlobalSubtrees: boolean) {\n // Create a mapping of root node identifiers to other root nodes that they reference via branch nodes.\n // Below is an example of a mapping that includes a circular dependency (root => a => b => c => a)\n // [{ refs: [\"a\", \"b\"] }, { id: \"a\", refs: [\"b\"] }, { id: \"b\", refs: [\"c\"] }, { id: \"c\", refs: [\"a\"] }]\n const rootNodeMappings: { id: string | undefined; refs: string[] }[] = rootNodeDefinitions.map(\n (rootNodeDefinition) => ({\n id: rootNodeDefinition.id,\n refs: flattenDefinition(rootNodeDefinition)\n .filter(isBranchNode)\n .map(({ ref }) => ref)\n })\n );\n\n // A recursive function to walk through the mappings, keeping track of which root nodes we have visited in the form of a path of root node identifiers.\n const followRefs = (mapping: { id: string | undefined; refs: string[] }, path: (string | undefined)[] = []) => {\n // Have we found a circular dependency?\n if (path.includes(mapping.id)) {\n // We found a circular dependency! Get the bad path of root node identifiers.\n const badPath = [...path, mapping.id];\n\n // Create the formatted path value. [undefined, \"a\", \"b\", \"c\", \"a\"] would be formatted as \"a -> b -> c -> a\".\n const badPathFormatted = badPath.filter((element) => !!element).join(\" => \");\n\n // No need to continue, we found a circular dependency.\n throw new Error(`circular dependency found in branch node references: ${badPathFormatted}`);\n }\n\n for (const ref of mapping.refs) {\n // Find the mapping for the root node with an identifer matching the current ref.\n const subMapping = rootNodeMappings.find(({ id }) => id === ref);\n\n // We may not have a mapping for this ref, which is normal when we aren't considering all globally registered subtrees.\n if (subMapping) {\n followRefs(subMapping, [...path, mapping.id]);\n } else if (includesGlobalSubtrees) {\n // We found a reference to a root node that doesn't exist, which is a problem seeing as the root node definitons includes all globally registered subtrees.\n throw new Error(\n mapping.id\n ? `subtree '${mapping.id}' has branch node that references root node '${ref}' which has not been defined`\n : `primary tree has branch node that references root node '${ref}' which has not been defined`\n );\n }\n }\n };\n\n // Start looking for circular dependencies and broken references from the primary root node definition.\n followRefs(rootNodeMappings.find((mapping) => typeof mapping.id === \"undefined\")!);\n}\n\n/**\n * Validate an object that we expect to be a node definition.\n * @param definition An object that we expect to be a node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateNode(definition: any, depth: number): void {\n // Every node must be valid object and have a non-empty 'type' string property.\n if (typeof definition !== \"object\" || typeof definition.type !== \"string\" || definition.type.length === 0) {\n throw new Error(\n `node definition is not an object or 'type' property is not a non-empty string at depth '${depth}'`\n );\n }\n\n // How we validate this node definition will depend on its type.\n switch (definition.type) {\n case \"action\":\n validateActionNode(definition, depth);\n break;\n\n case \"condition\":\n validateConditionNode(definition, depth);\n break;\n\n case \"wait\":\n validateWaitNode(definition, depth);\n break;\n\n case \"branch\":\n validateBranchNode(definition, depth);\n break;\n\n case \"root\":\n validateRootNode(definition, depth);\n break;\n\n case \"succeed\":\n validateSucceedNode(definition, depth);\n break;\n\n case \"fail\":\n validateFailNode(definition, depth);\n break;\n\n case \"flip\":\n validateFlipNode(definition, depth);\n break;\n\n case \"repeat\":\n validateRepeatNode(definition, depth);\n break;\n\n case \"retry\":\n validateRetryNode(definition, depth);\n break;\n\n case \"sequence\":\n validateSequenceNode(definition, depth);\n break;\n\n case \"selector\":\n validateSelectorNode(definition, depth);\n break;\n\n case \"parallel\":\n validateParallelNode(definition, depth);\n break;\n\n case \"lotto\":\n validateLottoNode(definition, depth);\n break;\n\n default:\n throw new Error(`unexpected node type of '${definition.type}' at depth '${depth}'`);\n }\n}\n\n/**\n * Validate any attributes for a given node definition.\n * @param definition The node definition.\n * @param depth The depth of the node in the behaviour tree definition.\n */\nfunction validateNodeAttributes(definition: any, depth: number): void {\n // Validate each of the attribute types for this node.\n [\"while\", \"until\", \"entry\", \"exit\", \"step\"].forEach((attributeName) => {\n // Attempt to grab the definition for the current attribute from the node definition.\n const attributeDefinition = definition[attributeName];\n\n // All node attributes are optional, so there is nothing to do if the current attribute is not defined.\n if (typeof attributeDefinition === \"undefined\") {\n return;\n }\n\n // The attribute definition must be an object.\n if (typeof attributeDefinition !== \"object\") {\n throw new Error(\n `expected attribute '${attributeName}' to be an object for '${definition.type}' node at depth '${depth}'`\n );\n }\n\n // The 'call' property must be defined for any attribute definition.\n if (typeof attributeDefinition.call !== \"string\" || attributeDefinition.call.length === 0) {\n throw new Error(\n `expected 'call' property for attribute '${attributeName}' to be a non-empty string for '${definition.type}' node at depth '${depth}'`\n );\n }\n\n // If any node attribute arguments have been defined then they must have been defined in an array.\n if (typeof attributeDefinition.args !== \"undefined\" && !Array.isArray(attributeDefinition.args)) {\n throw new Error(\n `expected 'args' property for attribute '${attributeName}' to be an array for '${definition.type}' node at depth '${depth}'`\n );\n }\n });\n}\n\n/**\n * Validate an object that we expect to be a root node definition.\n * @param definition An object that we expect to be a root node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateRootNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"root\") {\n throw new Error(\"expected node type of 'root' for root node\");\n }\n\n // A root node cannot be the child of another node.\n if (depth > 0) {\n throw new Error(\"a root node cannot be the child of another node\");\n }\n\n // Check that, if the root node 'id' property is defined, it is a non-empty string.\n if (typeof definition.id !== \"undefined\" && (typeof definition.id !== \"string\" || definition.id.length === 0)) {\n throw new Error(\"expected non-empty string for 'id' property if defined for root node\");\n }\n\n // A root node is a decorator node, so must have a child node defined.\n if (typeof definition.child === \"undefined\") {\n throw new Error(\"expected property 'child' to be defined for root node\");\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n\n // Validate the child node of this decorator node.\n validateNode(definition.child, depth + 1);\n}\n\n/**\n * Validate an object that we expect to be a succeed node definition.\n * @param definition An object that we expect to be a succeed node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateSucceedNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"succeed\") {\n throw new Error(`expected node type of 'succeed' for succeed node at depth '${depth}'`);\n }\n\n // A succeed node is a decorator node, so must have a child node defined.\n if (typeof definition.child === \"undefined\") {\n throw new Error(`expected property 'child' to be defined for succeed node at depth '${depth}'`);\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n\n // Validate the child node of this decorator node.\n validateNode(definition.child, depth + 1);\n}\n\n/**\n * Validate an object that we expect to be a fail node definition.\n * @param definition An object that we expect to be a fail node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateFailNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"fail\") {\n throw new Error(`expected node type of 'fail' for fail node at depth '${depth}'`);\n }\n\n // A fail node is a decorator node, so must have a child node defined.\n if (typeof definition.child === \"undefined\") {\n throw new Error(`expected property 'child' to be defined for fail node at depth '${depth}'`);\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n\n // Validate the child node of this decorator node.\n validateNode(definition.child, depth + 1);\n}\n\n/**\n * Validate an object that we expect to be a flip node definition.\n * @param definition An object that we expect to be a flip node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateFlipNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"flip\") {\n throw new Error(`expected node type of 'flip' for flip node at depth '${depth}'`);\n }\n\n // A flip node is a decorator node, so must have a child node defined.\n if (typeof definition.child === \"undefined\") {\n throw new Error(`expected property 'child' to be defined for flip node at depth '${depth}'`);\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n\n // Validate the child node of this decorator node.\n validateNode(definition.child, depth + 1);\n}\n\n/**\n * Validate an object that we expect to be a repeat node definition.\n * @param definition An object that we expect to be a repeat node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateRepeatNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"repeat\") {\n throw new Error(`expected node type of 'repeat' for repeat node at depth '${depth}'`);\n }\n\n // A repeat node is a decorator node, so must have a child node defined.\n if (typeof definition.child === \"undefined\") {\n throw new Error(`expected property 'child' to be defined for repeat node at depth '${depth}'`);\n }\n\n // Check whether an 'iterations' property has been defined, it may not have been if this node is to repeat indefinitely.\n if (typeof definition.iterations !== \"undefined\") {\n if (Array.isArray(definition.iterations)) {\n // Check whether any elements of the array are not integer values.\n const containsNonInteger = !!definition.iterations.filter((value: unknown) => !isInteger(value)).length;\n\n // If the 'iterations' property is an array then it MUST contain two integer values.\n if (definition.iterations.length !== 2 || containsNonInteger) {\n throw new Error(\n `expected array containing two integer values for 'iterations' property if defined for repeat node at depth '${depth}'`\n );\n }\n\n // A repeat node must have a positive min and max iterations count if they are defined.\n if (definition.iterations[0] < 0 || definition.iterations[1] < 0) {\n throw new Error(\n `expected positive minimum and maximum iterations count for 'iterations' property if defined for repeat node at depth '${depth}'`\n );\n }\n\n // A repeat node must not have a minimum iterations count that exceeds the maximum iterations count.\n if (definition.iterations[0] > definition.iterations[1]) {\n throw new Error(\n `expected minimum iterations count that does not exceed the maximum iterations count for 'iterations' property if defined for repeat node at depth '${depth}'`\n );\n }\n } else if (isInteger(definition.iterations)) {\n // A repeat node must have a positive number of iterations if defined.\n if (definition.iterations < 0) {\n throw new Error(\n `expected positive iterations count for 'iterations' property if defined for repeat node at depth '${depth}'`\n );\n }\n } else {\n throw new Error(\n `expected integer value or array containing two integer values for 'iterations' property if defined for repeat node at depth '${depth}'`\n );\n }\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n\n // Validate the child node of this decorator node.\n validateNode(definition.child, depth + 1);\n}\n\n/**\n * Validate an object that we expect to be a retry node definition.\n * @param definition An object that we expect to be a retry node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateRetryNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"retry\") {\n throw new Error(`expected node type of 'retry' for retry node at depth '${depth}'`);\n }\n\n // A retry node is a decorator node, so must have a child node defined.\n if (typeof definition.child === \"undefined\") {\n throw new Error(`expected property 'child' to be defined for retry node at depth '${depth}'`);\n }\n\n // Check whether an 'attempts' property has been defined, it may not have been if this node is to retry indefinitely.\n if (typeof definition.attempts !== \"undefined\") {\n if (Array.isArray(definition.attempts)) {\n // Check whether any elements of the array are not integer values.\n const containsNonInteger = !!definition.attempts.filter((value: unknown) => !isInteger(value)).length;\n\n // If the 'attempts' property is an array then it MUST contain two integer values.\n if (definition.attempts.length !== 2 || containsNonInteger) {\n throw new Error(\n `expected array containing two integer values for 'attempts' property if defined for retry node at depth '${depth}'`\n );\n }\n\n // A retry node must have a positive min and max attempts count if they are defined.\n if (definition.attempts[0] < 0 || definition.attempts[1] < 0) {\n throw new Error(\n `expected positive minimum and maximum attempts count for 'attempts' property if defined for retry node at depth '${depth}'`\n );\n }\n\n // A retry node must not have a minimum attempts count that exceeds the maximum attempts count.\n if (definition.attempts[0] > definition.attempts[1]) {\n throw new Error(\n `expected minimum attempts count that does not exceed the maximum attempts count for 'attempts' property if defined for retry node at depth '${depth}'`\n );\n }\n } else if (isInteger(definition.attempts)) {\n // A retry node must have a positive number of attempts if defined.\n if (definition.attempts < 0) {\n throw new Error(\n `expected positive attempts count for 'attempts' property if defined for retry node at depth '${depth}'`\n );\n }\n } else {\n throw new Error(\n `expected integer value or array containing two integer values for 'attempts' property if defined for retry node at depth '${depth}'`\n );\n }\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n\n // Validate the child node of this decorator node.\n validateNode(definition.child, depth + 1);\n}\n\n/**\n * Validate an object that we expect to be a branch node definition.\n * @param definition An object that we expect to be a branch node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateBranchNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"branch\") {\n throw new Error(`expected node type of 'branch' for branch node at depth '${depth}'`);\n }\n\n // Check that the branch node 'ref' property is defined and is a non-empty string.\n if (typeof definition.ref !== \"string\" || definition.ref.length === 0) {\n throw new Error(`expected non-empty string for 'ref' property for branch node at depth '${depth}'`);\n }\n\n // It is invalid to define guard attributes for a branch node as they should be defined on the referenced root node.\n [\"while\", \"until\"].forEach((attributeName) => {\n if (typeof definition[attributeName] !== \"undefined\") {\n throw new Error(\n `guards should not be defined for branch nodes but guard '${attributeName}' was defined for branch node at depth '${depth}'`\n );\n }\n });\n\n // It is invalid to define callback attributes for a branch node as they should be defined on the referenced root node.\n [\"entry\", \"exit\", \"step\"].forEach((attributeName) => {\n if (typeof definition[attributeName] !== \"undefined\") {\n throw new Error(\n `callbacks should not be defined for branch nodes but callback '${attributeName}' was defined for branch node at depth '${depth}'`\n );\n }\n });\n}\n\n/**\n * Validate an object that we expect to be a action node definition.\n * @param definition An object that we expect to be a action node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateActionNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"action\") {\n throw new Error(`expected node type of 'action' for action node at depth '${depth}'`);\n }\n\n // The 'call' property must be defined for a action node definition.\n if (typeof definition.call !== \"string\" || definition.call.length === 0) {\n throw new Error(`expected non-empty string for 'call' property of action node at depth '${depth}'`);\n }\n\n // If any action function arguments have been defined then they must have been defined in an array.\n if (typeof definition.args !== \"undefined\" && !Array.isArray(definition.args)) {\n throw new Error(`expected array for 'args' property if defined for action node at depth '${depth}'`);\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n}\n\n/**\n * Validate an object that we expect to be a condition node definition.\n * @param definition An object that we expect to be a condition node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateConditionNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"condition\") {\n throw new Error(`expected node type of 'condition' for condition node at depth '${depth}'`);\n }\n\n // The 'call' property must be defined for a condition node definition.\n if (typeof definition.call !== \"string\" || definition.call.length === 0) {\n throw new Error(`expected non-empty string for 'call' property of condition node at depth '${depth}'`);\n }\n\n // If any condition function arguments have been defined then they must have been defined in an array.\n if (typeof definition.args !== \"undefined\" && !Array.isArray(definition.args)) {\n throw new Error(`expected array for 'args' property if defined for condition node at depth '${depth}'`);\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n}\n\n/**\n * Validate an object that we expect to be a wait node definition.\n * @param definition An object that we expect to be a wait node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateWaitNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"wait\") {\n throw new Error(`expected node type of 'wait' for wait node at depth '${depth}'`);\n }\n\n // Check whether a 'duration' property has been defined, it may not have been if this node is to wait indefinitely.\n if (typeof definition.duration !== \"undefined\") {\n if (Array.isArray(definition.duration)) {\n // Check whether any elements of the array are not integer values.\n const containsNonInteger = !!definition.duration.filter((value: unknown) => !isInteger(value)).length;\n\n // If the 'duration' property is an array then it MUST contain two integer values.\n if (definition.duration.length !== 2 || containsNonInteger) {\n throw new Error(\n `expected array containing two integer values for 'duration' property if defined for wait node at depth '${depth}'`\n );\n }\n\n // A wait node must have a positive min and max duration value if they are defined.\n if (definition.duration[0] < 0 || definition.duration[1] < 0) {\n throw new Error(\n `expected positive minimum and maximum duration for 'duration' property if defined for wait node at depth '${depth}'`\n );\n }\n\n // A wait node must not have a minimum duration value that exceeds the maximum duration value.\n if (definition.duration[0] > definition.duration[1]) {\n throw new Error(\n `expected minimum duration value that does not exceed the maximum duration value for 'duration' property if defined for wait node at depth '${depth}'`\n );\n }\n } else if (isInteger(definition.duration)) {\n // A wait node must have a positive duration value if defined.\n if (definition.duration < 0) {\n throw new Error(\n `expected positive duration value for 'duration' property if defined for wait node at depth '${depth}'`\n );\n }\n } else {\n throw new Error(\n `expected integer value or array containing two integer values for 'duration' property if defined for wait node at depth '${depth}'`\n );\n }\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n}\n\n/**\n * Validate an object that we expect to be a sequence node definition.\n * @param definition An object that we expect to be a sequence node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateSequenceNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"sequence\") {\n throw new Error(`expected node type of 'sequence' for sequence node at depth '${depth}'`);\n }\n\n // A sequence node is a composite node, so must have a children nodes array defined.\n if (!Array.isArray(definition.children) || definition.children.length === 0) {\n throw new Error(`expected non-empty 'children' array to be defined for sequence node at depth '${depth}'`);\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n\n // Validate the child nodes of this composite node.\n definition.children.forEach((child: any) => validateNode(child, depth + 1));\n}\n\n/**\n * Validate an object that we expect to be a selector node definition.\n * @param definition An object that we expect to be a selector node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateSelectorNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"selector\") {\n throw new Error(`expected node type of 'selector' for selector node at depth '${depth}'`);\n }\n\n // A selector node is a composite node, so must have a children nodes array defined.\n if (!Array.isArray(definition.children) || definition.children.length === 0) {\n throw new Error(`expected non-empty 'children' array to be defined for selector node at depth '${depth}'`);\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n\n // Validate the child nodes of this composite node.\n definition.children.forEach((child: any) => validateNode(child, depth + 1));\n}\n\n/**\n * Validate an object that we expect to be a parallel node definition.\n * @param definition An object that we expect to be a parallel node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateParallelNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"parallel\") {\n throw new Error(`expected node type of 'parallel' for parallel node at depth '${depth}'`);\n }\n\n // A parallel node is a composite node, so must have a children nodes array defined.\n if (!Array.isArray(definition.children) || definition.children.length === 0) {\n throw new Error(`expected non-empty 'children' array to be defined for parallel node at depth '${depth}'`);\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n\n // Validate the child nodes of this composite node.\n definition.children.forEach((child: any) => validateNode(child, depth + 1));\n}\n\n/**\n * Validate an object that we expect to be a lotto node definition.\n * @param definition An object that we expect to be a lotto node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateLottoNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"lotto\") {\n throw new Error(`expected node type of 'lotto' for lotto node at depth '${depth}'`);\n }\n\n // A lotto node is a composite node, so must have a children nodes array defined.\n if (!Array.isArray(definition.children) || definition.children.length === 0) {\n throw new Error(`expected non-empty 'children' array to be defined for lotto node at depth '${depth}'`);\n }\n\n // Check whether a 'weights' property has been defined, if it has we expect it to be an array of weights.\n if (typeof definition.weights !== \"undefined\") {\n // Check that the weights property is an array of positive integers with an element for each child node element.\n if (\n !Array.isArray(definition.weights) ||\n definition.weights.length !== definition.children.length ||\n definition.weights.filter((value: unknown) => !isInteger(value)).length ||\n definition.weights.filter((value: number) => value < 0).length\n ) {\n throw new Error(\n `expected an array of positive integer weight values with a length matching the number of child nodes for 'weights' property if defined for lotto node at depth '${depth}'`\n );\n }\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n\n // Validate the child nodes of this composite node.\n definition.children.forEach((child: any) => validateNode(child, depth + 1));\n}\n\n/**\n * A helper function to create a failure validation result with the given error message.\n * @param errorMessage The validation failure error message.\n * @returns A failure validation result with the given error message.\n */\nfunction createValidationFailureResult(errorMessage: string): DefinitionValidationResult {\n return { succeeded: false, errorMessage };\n}\n", "import { ActionResult, Agent, GlobalFunction } from \"./Agent\";\nimport { RootNodeDefinition } from \"./BehaviourTreeDefinition\";\n\nexport type InvokerFunction = (args: any[]) => ActionResult;\n\n/**\n * A singleton used to store and lookup registered functions and subtrees.\n */\nexport default class Lookup {\n /**\n * The object holding any registered functions keyed on function name.\n */\n private static functionTable: { [key: string]: GlobalFunction } = {};\n /**\n * The object holding any registered subtree root node definitions keyed on tree name.\n */\n private static subtreeTable: { [key: string]: RootNodeDefinition } = {};\n\n /**\n * Gets the function with the specified name.\n * @param name The name of the function.\n * @returns The function with the specified name.\n */\n public static getFunc(name: string): GlobalFunction {\n return this.functionTable[name];\n }\n\n /**\n * Sets the function with the specified name for later lookup.\n * @param name The name of the function.\n * @param func The function.\n */\n public static setFunc(name: string, func: GlobalFunction): void {\n this.functionTable[name] = func;\n }\n\n /**\n * Gets the function invoker for the specified agent and function name.\n * If a function with the specified name exists on the agent object then it will\n * be returned, otherwise we will then check the registered functions for a match.\n * @param agent The agent instance that this behaviour tree is modelling behaviour for.\n * @param name The function name.\n * @returns The function invoker for the specified agent and function name.\n */\n static getFuncInvoker(agent: Agent, name: string): InvokerFunction | null {\n // Check whether the agent contains the specified function.\n const foundOnAgent = agent[name];\n if (foundOnAgent && typeof foundOnAgent === \"function\") {\n return (args: any[]): boolean | ActionResult => foundOnAgent.apply(agent, args);\n }\n\n // The agent does not contain the specified function but it may have been registered at some point.\n if (this.functionTable[name] && typeof this.functionTable[name] === \"function\") {\n return (args: any[]) => this.functionTable[name](agent, ...args.map((arg) => arg.value));\n }\n\n // We have no function to invoke.\n return null;\n }\n\n /**\n * Gets all registered subtree root node definitions.\n */\n static getSubtrees(): { [key: string]: RootNodeDefinition } {\n return this.subtreeTable;\n }\n\n /**\n * Sets the subtree with the specified name for later lookup.\n * @param name The name of the subtree.\n * @param subtree The subtree.\n */\n static setSubtree(name: string, subtree: RootNodeDefinition) {\n this.subtreeTable[name] = subtree;\n }\n\n /**\n * Removes the registered function or subtree with the specified name.\n * @param name The name of the registered function or subtree.\n */\n static remove(name: string) {\n delete this.functionTable[name];\n delete this.subtreeTable[name];\n }\n\n /**\n * Remove all registered functions and subtrees.\n */\n static empty() {\n this.functionTable = {};\n this.subtreeTable = {};\n }\n}\n", "import Node from \"../../nodes/Node\";\n\n/**\n * An exception thrown when evaluating node guard path conditions and a conditions fails.\n */\nexport default class GuardUnsatisifedException extends Error {\n /**\n * @param source The node at which a guard condition failed.\n */\n constructor(private source: Node) {\n super(\"A guard path condition has failed\");\n }\n\n /**\n * Gets whether the specified node is the node at which a guard condition failed.\n * @param node The node to check against the source node.\n * @returns Whether the specified node is the node at which a guard condition failed.\n */\n isSourceNode = (node: Node) => node === this.source;\n}\n", "import { Agent } from \"../../Agent\";\nimport Guard from \"./Guard\";\nimport Node from \"../../nodes/Node\";\nimport GuardUnsatisifedException from \"./GuardUnsatisifedException\";\n\nexport type GuardPathPart = {\n node: Node;\n guards: Guard[];\n};\n\n/**\n * Represents a path of node guards along a root-to-leaf tree path.\n */\nexport default class GuardPath {\n /**\n * @param nodes An array of objects defining a node instance -> guard link, ordered by node depth.\n */\n constructor(private nodes: GuardPathPart[]) {}\n\n /**\n * Evaluate guard conditions for all guards in the tree path, moving outwards from the root.\n * @param agent The agent, required for guard evaluation.\n * @returns An evaluation results object.\n */\n evaluate = (agent: Agent) => {\n // We need to evaluate guard conditions for nodes up the tree, moving outwards from the root.\n for (const details of this.nodes) {\n // There can be multiple guards per node.\n for (const guard of details.guards) {\n // Check whether the guard condition passes, and throw an exception if not.\n if (!guard.isSatisfied(agent)) {\n throw new GuardUnsatisifedException(details.node);\n }\n }\n }\n };\n}\n", "import { BehaviourTreeOptions } from \"../BehaviourTreeOptions\";\nimport State, { AnyState } from \"../State\";\nimport { Agent } from \"../Agent\";\nimport Leaf from \"./leaf/Leaf\";\nimport Attribute from \"../attributes/Attribute\";\nimport Entry from \"../attributes/callbacks/Entry\";\nimport Exit from \"../attributes/callbacks/Exit\";\nimport Step from \"../attributes/callbacks/Step\";\nimport Guard from \"../attributes/guards/Guard\";\nimport GuardPath from \"../attributes/guards/GuardPath\";\nimport GuardUnsatisifedException from \"../attributes/guards/GuardUnsatisifedException\";\n\n/**\n * A base node.\n */\nexport default abstract class Node {\n /**\n * The node uid.\n */\n private readonly uid: string = createNodeUid();\n /**\n * The node state.\n */\n private state: AnyState = State.READY;\n /**\n * The guard path to evaluate as part of a node update.\n */\n private guardPath: GuardPath | undefined;\n\n /**\n * @param type The node type.\n * @param attributes The node attributes.\n * @param args The node argument definitions.\n */\n constructor(private type: string, private attributes: Attribute[], private args: any[]) {}\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected abstract onUpdate(agent: Agent, options: BehaviourTreeOptions): void;\n\n /**\n * Gets the name of the node.\n */\n public abstract getName(): string;\n\n /**\n * Gets whether this node is a leaf node.\n */\n public abstract isLeafNode: () => this is Leaf;\n\n /**\n * Gets/Sets the state of the node.\n */\n getState = (): AnyState => this.state;\n setState = (value: AnyState): void => {\n this.state = value;\n };\n\n /**\n * Gets the unique id of the node.\n */\n getUid = () => this.uid;\n\n /**\n * Gets the type of the node.\n */\n getType = () => this.type;\n\n /**\n * Gets the node attributes.\n */\n getAttributes = () => this.attributes;\n\n /**\n * Gets the node arguments.\n */\n getArguments = () => this.args;\n\n /**\n * Gets the node attribute with the specified type, or null if it does not exist.\n */\n getAttribute(type: \"entry\" | \"ENTRY\"): Entry;\n getAttribute(type: \"exit\" | \"EXIT\"): Exit;\n getAttribute(type: \"step\" | \"STEP\"): Step;\n getAttribute(type: string): Attribute {\n return (\n this.getAttributes().filter((decorator) => decorator.type.toUpperCase() === type.toUpperCase())[0] || null\n );\n }\n\n /**\n * Gets the node attributes.\n */\n getGuardAttributes = (): Guard[] => this.getAttributes().filter((decorator) => decorator.isGuard()) as Guard[];\n\n /**\n * Sets the guard path to evaluate as part of a node update.\n */\n setGuardPath = (value: GuardPath) => (this.guardPath = value);\n\n /**\n * Gets whether a guard path is assigned to this node.\n */\n hasGuardPath = () => !!this.guardPath;\n\n /**\n * Gets whether this node is in the specified state.\n * @param value The value to compare to the node state.\n */\n public is(value: AnyState): boolean {\n return this.state === value;\n }\n\n /**\n * Reset the state of the node.\n */\n public reset(): void {\n this.setState(State.READY);\n }\n\n /**\n * Abort the running of this node.\n * @param agent The agent.\n */\n public abort(agent: Agent): void {\n // There is nothing to do if this node is not in the running state.\n if (!this.is(State.RUNNING)) {\n return;\n }\n\n // Reset the state of this node.\n this.reset();\n\n this.getAttribute(\"exit\")?.callAgentFunction(agent, false, true);\n }\n\n /**\n * Update the node.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n * @returns The result of the update.\n */\n public update(agent: Agent, options: BehaviourTreeOptions): void {\n // If this node is already in a 'SUCCEEDED' or 'FAILED' state then there is nothing to do.\n if (this.is(State.SUCCEEDED) || this.is(State.FAILED)) {\n return;\n }\n\n try {\n // Evaluate all of the guard path conditions for the current tree path.\n this.guardPath!.evaluate(agent);\n\n // If this node is in the READY state then call the ENTRY for this node if it exists.\n if (this.is(State.READY)) {\n this.getAttribute(\"entry\")?.callAgentFunction(agent);\n }\n\n this.getAttribute(\"step\")?.callAgentFunction(agent);\n\n // Do the actual update.\n this.onUpdate(agent, options);\n\n // If this node is now in a 'SUCCEEDED' or 'FAILED' state then call the EXIT for this node if it exists.\n if (this.is(State.SUCCEEDED) || this.is(State.FAILED)) {\n this.getAttribute(\"exit\")?.callAgentFunction(agent, this.is(State.SUCCEEDED), false);\n }\n } catch (error) {\n // If the error is a GuardUnsatisfiedException then we need to determine if this node is the source.\n if (error instanceof GuardUnsatisifedException && error.isSourceNode(this)) {\n // Abort the current node.\n this.abort(agent);\n\n // Any node that is the source of an abort will be a failed node.\n this.setState(State.FAILED);\n } else {\n throw error;\n }\n }\n }\n}\n\n/**\n * Create a randomly generated node uid.\n * @returns A randomly generated node uid.\n */\nfunction createNodeUid(): string {\n var S4 = function () {\n return (((1 + Math.random()) * 0x10000) | 0).toString(16).substring(1);\n };\n return S4() + S4() + \"-\" + S4() + \"-\" + S4() + \"-\" + S4() + \"-\" + S4() + S4() + S4();\n}\n", "import Node from \"../Node\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\n\n/**\n * A composite node that wraps child nodes.\n */\nexport default abstract class Composite extends Node {\n /**\n * @param type The node type.\n * @param attributes The node attributes.\n * @param children The child nodes.\n */\n constructor(type: string, attributes: Attribute[], protected children: Node[]) {\n super(type, attributes, []);\n }\n\n /**\n * Gets whether this node is a leaf node.\n */\n isLeafNode = () => false;\n\n /**\n * Gets the children of this node.\n */\n getChildren = () => this.children;\n\n /**\n * Reset the state of the node.\n */\n reset = () => {\n // Reset the state of this node.\n this.setState(State.READY);\n\n // Reset the state of any child nodes.\n this.getChildren().forEach((child) => child.reset());\n };\n\n /**\n * Abort the running of this node.\n * @param agent The agent.\n */\n abort = (agent: Agent) => {\n // There is nothing to do if this node is not in the running state.\n if (!this.is(State.RUNNING)) {\n return;\n }\n\n // Abort any child nodes.\n this.getChildren().forEach((child) => child.abort(agent));\n\n // Reset the state of this node.\n this.reset();\n\n this.getAttribute(\"exit\")?.callAgentFunction(agent, false, true);\n };\n}\n", "import Composite from \"./Composite\";\nimport State from \"../../State\";\nimport Node from \"../Node\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A PARALLEL node.\n * The child nodes are executed concurrently until one fails or all succeed.\n */\nexport default class Parallel extends Composite {\n /**\n * @param attributes The node attributes.\n * @param children The child nodes.\n */\n constructor(attributes: Attribute[], children: Node[]) {\n super(\"parallel\", attributes, children);\n }\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // Keep a count of the number of succeeded child nodes.\n let succeededCount = 0;\n\n let hasChildFailed = false;\n\n // Iterate over all of the children of this node.\n for (const child of this.children) {\n // If the child has never been updated or is running then we will need to update it now.\n if (child.getState() === State.READY || child.getState() === State.RUNNING) {\n // Update the child of this node.\n child.update(agent, options);\n }\n\n // If the current child has a state of 'SUCCEEDED' then we should move on to the next child.\n if (child.getState() === State.SUCCEEDED) {\n // The child node has succeeded, keep track of this to determine if all children have.\n succeededCount++;\n\n // The child node succeeded, but we have not finished checking every child node yet.\n continue;\n }\n\n // If the current child has a state of 'FAILED' then this node is also a 'FAILED' node.\n if (child.getState() === State.FAILED) {\n hasChildFailed = true;\n\n // There is no need to check the rest of the children.\n break;\n }\n\n // The node should be in the 'RUNNING' state.\n if (child.getState() !== State.RUNNING) {\n // The child node was not in an expected state.\n throw new Error(\"child node was not in an expected state.\");\n }\n }\n\n if (hasChildFailed) {\n // This node is a 'FAILED' node.\n this.setState(State.FAILED);\n\n // Abort every running child.\n for (const child of this.children) {\n if (child.getState() === State.RUNNING) {\n child.abort(agent);\n }\n }\n } else {\n // If all children have succeeded then this node has also succeeded, otherwise it is still running.\n this.setState(succeededCount === this.children.length ? State.SUCCEEDED : State.RUNNING);\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => \"PARALLEL\";\n}\n", "import Composite from \"./Composite\";\nimport Node from \"../Node\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A SELECTOR node.\n * The child nodes are executed in sequence until one succeeds or all fail.\n */\nexport default class Selector extends Composite {\n /**\n * @param attributes The node attributes.\n * @param children The child nodes.\n */\n constructor(attributes: Attribute[], protected children: Node[]) {\n super(\"selector\", attributes, children);\n }\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // Iterate over all of the children of this node.\n for (const child of this.children) {\n // If the child has never been updated or is running then we will need to update it now.\n if (child.getState() === State.READY || child.getState() === State.RUNNING) {\n // Update the child of this node.\n child.update(agent, options);\n }\n\n // If the current child has a state of 'SUCCEEDED' then this node is also a 'SUCCEEDED' node.\n if (child.getState() === State.SUCCEEDED) {\n // This node is a 'SUCCEEDED' node.\n this.setState(State.SUCCEEDED);\n\n // There is no need to check the rest of the selector nodes.\n return;\n }\n\n // If the current child has a state of 'FAILED' then we should move on to the next child.\n if (child.getState() === State.FAILED) {\n // Find out if the current child is the last one in the selector.\n // If it is then this sequence node has also failed.\n if (this.children.indexOf(child) === this.children.length - 1) {\n // This node is a 'FAILED' node.\n this.setState(State.FAILED);\n\n // There is no need to check the rest of the selector as we have completed it.\n return;\n } else {\n // The child node failed, try the next one.\n continue;\n }\n }\n\n // The node should be in the 'RUNNING' state.\n if (child.getState() === State.RUNNING) {\n // This node is a 'RUNNING' node.\n this.setState(State.RUNNING);\n\n // There is no need to check the rest of the selector as the current child is still running.\n return;\n }\n\n // The child node was not in an expected state.\n throw new Error(\"child node was not in an expected state.\");\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => \"SELECTOR\";\n}\n", "import Composite from \"./Composite\";\nimport Node from \"../Node\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A SEQUENCE node.\n * The child nodes are executed in sequence until one fails or all succeed.\n */\nexport default class Sequence extends Composite {\n /**\n * @param attributes The node attributes.\n * @param children The child nodes.\n */\n constructor(attributes: Attribute[], protected children: Node[]) {\n super(\"sequence\", attributes, children);\n }\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // Iterate over all of the children of this node.\n for (const child of this.children) {\n // If the child has never been updated or is running then we will need to update it now.\n if (child.getState() === State.READY || child.getState() === State.RUNNING) {\n // Update the child of this node.\n child.update(agent, options);\n }\n\n // If the current child has a state of 'SUCCEEDED' then we should move on to the next child.\n if (child.getState() === State.SUCCEEDED) {\n // Find out if the current child is the last one in the sequence.\n // If it is then this sequence node has also succeeded.\n if (this.children.indexOf(child) === this.children.length - 1) {\n // This node is a 'SUCCEEDED' node.\n this.setState(State.SUCCEEDED);\n\n // There is no need to check the rest of the sequence as we have completed it.\n return;\n } else {\n // The child node succeeded, but we have not finished the sequence yet.\n continue;\n }\n }\n\n // If the current child has a state of 'FAILED' then this node is also a 'FAILED' node.\n if (child.getState() === State.FAILED) {\n // This node is a 'FAILED' node.\n this.setState(State.FAILED);\n\n // There is no need to check the rest of the sequence.\n return;\n }\n\n // The node should be in the 'RUNNING' state.\n if (child.getState() === State.RUNNING) {\n // This node is a 'RUNNING' node.\n this.setState(State.RUNNING);\n\n // There is no need to check the rest of the sequence as the current child is still running.\n return;\n }\n\n // The child node was not in an expected state.\n throw new Error(\"child node was not in an expected state.\");\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => \"SEQUENCE\";\n}\n", "import createLotto from \"lotto-draw\";\n\nimport Node from \"../Node\";\nimport Composite from \"./Composite\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A LOTTO node.\n * A winning child is picked on the initial update of this node, based on ticket weighting.\n * The state of this node will match the state of the winning child.\n */\nexport default class Lotto extends Composite {\n /**\n * @param attributes The node attributes.\n * @param weights The child node weights.\n * @param children The child nodes.\n */\n constructor(attributes: Attribute[], private weights: number[] | undefined, children: Node[]) {\n super(\"lotto\", attributes, children);\n }\n\n /**\n * The child node selected to be the active one.\n */\n private selectedChild: Node | undefined;\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // If this node is in the READY state then we need to pick a winning child node.\n if (this.is(State.READY)) {\n // Create a lotto draw with which to randomly pick a child node to become the active one.\n const lottoDraw = createLotto({\n // Hook up the optional 'random' behaviour tree function option to the one used by 'lotto-draw'.\n random: options.random,\n // Pass in each child node as a participant in the lotto draw with their respective ticket count.\n participants: this.children.map((child, index) => [child, this.weights?.[index] || 1])\n });\n\n // Randomly pick a child based on ticket weighting, this will become the active child for this composite node.\n this.selectedChild = lottoDraw.draw() || undefined;\n }\n\n // If something went wrong and we don't have an active child then we should throw an error.\n if (!this.selectedChild) {\n throw new Error(\"failed to update lotto node as it has no active child\");\n }\n\n // If the selected child has never been updated or is running then we will need to update it now.\n if (this.selectedChild.getState() === State.READY || this.selectedChild.getState() === State.RUNNING) {\n this.selectedChild.update(agent, options);\n }\n\n // The state of the lotto node is the state of its selected child.\n this.setState(this.selectedChild.getState());\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => (this.weights ? `LOTTO [${this.weights.join(\",\")}]` : \"LOTTO\");\n}\n", "import Node from \"../Node\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\n\n/**\n * A decorator node that wraps a single child node.\n */\nexport default abstract class Decorator extends Node {\n /**\n * @param type The node type.\n * @param attributes The node attributes.\n * @param child The child node.\n */\n constructor(type: string, attributes: Attribute[], protected child: Node) {\n super(type, attributes, []);\n }\n\n /**\n * Gets whether this node is a leaf node.\n */\n isLeafNode = () => false;\n\n /**\n * Gets the children of this node.\n */\n getChildren = () => [this.child];\n\n /**\n * Reset the state of the node.\n */\n reset = () => {\n // Reset the state of this node.\n this.setState(State.READY);\n\n // Reset the state of the child node.\n this.child.reset();\n };\n\n /**\n * Abort the running of this node.\n * @param agent The agent.\n */\n abort = (agent: Agent) => {\n // There is nothing to do if this node is not in the running state.\n if (!this.is(State.RUNNING)) {\n return;\n }\n\n // Abort the child node.\n this.child.abort(agent);\n\n // Reset the state of this node.\n this.reset();\n\n this.getAttribute(\"exit\")?.callAgentFunction(agent, false, true);\n };\n}\n", "import Node from \"../Node\";\nimport Decorator from \"./Decorator\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A Fail node.\n * This node wraps a single child and will always move to the 'FAILED' state when the child moves to a 'SUCCEEDED' or 'FAILED' state.\n */\nexport default class Fail extends Decorator {\n /**\n * @param attributes The node attributes.\n * @param child The child node.\n */\n constructor(attributes: Attribute[], child: Node) {\n super(\"fail\", attributes, child);\n }\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // If the child has never been updated or is running then we will need to update it now.\n if (this.child.getState() === State.READY || this.child.getState() === State.RUNNING) {\n this.child.update(agent, options);\n }\n\n // The state of this node will depend in the state of its child.\n switch (this.child.getState()) {\n case State.RUNNING:\n this.setState(State.RUNNING);\n break;\n\n case State.SUCCEEDED:\n case State.FAILED:\n this.setState(State.FAILED);\n break;\n\n default:\n this.setState(State.READY);\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => \"FAIL\";\n}\n", "import Decorator from \"./Decorator\";\nimport State from \"../../State\";\nimport Node from \"../Node\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A Flip node.\n * This node wraps a single child and will flip the state of the child state.\n */\nexport default class Flip extends Decorator {\n /**\n * @param attributes The node attributes.\n * @param child The child node.\n */\n constructor(attributes: Attribute[], child: Node) {\n super(\"flip\", attributes, child);\n }\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // If the child has never been updated or is running then we will need to update it now.\n if (this.child.getState() === State.READY || this.child.getState() === State.RUNNING) {\n this.child.update(agent, options);\n }\n\n // The state of this node will depend in the state of its child.\n switch (this.child.getState()) {\n case State.RUNNING:\n this.setState(State.RUNNING);\n break;\n\n case State.SUCCEEDED:\n this.setState(State.FAILED);\n break;\n\n case State.FAILED:\n this.setState(State.SUCCEEDED);\n break;\n\n default:\n this.setState(State.READY);\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => \"FLIP\";\n}\n", "import Node from \"../Node\";\nimport Decorator from \"./Decorator\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A REPEAT node.\n * The node has a single child which can have:\n * -- A number of iterations for which to repeat the child node.\n * -- An infinite repeat loop if neither an iteration count or a condition function is defined.\n * The REPEAT node will stop and have a 'FAILED' state if its child is ever in a 'FAILED' state after an update.\n * The REPEAT node will attempt to move on to the next iteration if its child is ever in a 'SUCCEEDED' state.\n */\nexport default class Repeat extends Decorator {\n /**\n * @param attributes The node attributes.\n * @param iterations The number of iterations to repeat the child node.\n * @param iterationsMin The minimum possible number of iterations to repeat the child node.\n * @param iterationsMax The maximum possible number of iterations to repeat the child node.\n * @param child The child node.\n */\n constructor(\n attributes: Attribute[],\n private iterations: number | null,\n private iterationsMin: number | null,\n private iterationsMax: number | null,\n child: Node\n ) {\n super(\"repeat\", attributes, child);\n }\n\n /**\n * The number of target iterations to make.\n */\n private targetIterationCount: number | null = null;\n\n /**\n * The current iteration count.\n */\n private currentIterationCount: number = 0;\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // If this node is in the READY state then we need to reset the child and the target iteration count.\n if (this.is(State.READY)) {\n // Reset the child node.\n this.child.reset();\n\n // Reset the current iteration count.\n this.currentIterationCount = 0;\n\n // Set the target iteration count.\n this.setTargetIterationCount(options);\n }\n\n // Do a check to see if we can iterate. If we can then this node will move into the 'RUNNING' state.\n // If we cannot iterate then we have hit our target iteration count, which means that the node has succeeded.\n if (this.canIterate()) {\n // This node is in the running state and can do its initial iteration.\n this.setState(State.RUNNING);\n\n // We may have already completed an iteration, meaning that the child node will be in the SUCCEEDED state.\n // If this is the case then we will have to reset the child node now.\n if (this.child.getState() === State.SUCCEEDED) {\n this.child.reset();\n }\n\n // Update the child of this node.\n this.child.update(agent, options);\n\n // If the child moved into the FAILED state when we updated it then there is nothing left to do and this node has also failed.\n // If it has moved into the SUCCEEDED state then we have completed the current iteration.\n if (this.child.getState() === State.FAILED) {\n // The child has failed, meaning that this node has failed.\n this.setState(State.FAILED);\n\n return;\n } else if (this.child.getState() === State.SUCCEEDED) {\n // We have completed an iteration.\n this.currentIterationCount += 1;\n }\n } else {\n // This node is in the 'SUCCEEDED' state as we cannot iterate any more.\n this.setState(State.SUCCEEDED);\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => {\n if (this.iterations !== null) {\n return `REPEAT ${this.iterations}x`;\n } else if (this.iterationsMin !== null && this.iterationsMax !== null) {\n return `REPEAT ${this.iterationsMin}x-${this.iterationsMax}x`;\n } else {\n return \"REPEAT\";\n }\n };\n\n /**\n * Reset the state of the node.\n */\n reset = () => {\n // Reset the state of this node.\n this.setState(State.READY);\n\n // Reset the current iteration count.\n this.currentIterationCount = 0;\n\n // Reset the child node.\n this.child.reset();\n };\n\n /**\n * Gets whether an iteration can be made.\n * @returns Whether an iteration can be made.\n */\n private canIterate = () => {\n if (this.targetIterationCount !== null) {\n // We can iterate as long as we have not reached our target iteration count.\n return this.currentIterationCount < this.targetIterationCount;\n }\n\n // If neither an iteration count or a condition function were defined then we can iterate indefinitely.\n return true;\n };\n\n /**\n * Sets the target iteration count.\n * @param options The behaviour tree options object.\n */\n private setTargetIterationCount = (options: BehaviourTreeOptions) => {\n // Are we dealing with an explicit iteration count or will we be randomly picking a iteration count between the min and max iteration count.\n if (this.iterations !== null) {\n this.targetIterationCount = this.iterations;\n } else if (this.iterationsMin !== null && this.iterationsMax !== null) {\n // We will be picking a random iteration count between a min and max iteration count, if the optional 'random'\n // behaviour tree function option is defined then we will be using that, otherwise we will fall back to using Math.random.\n const random = typeof options.random === \"function\" ? options.random : Math.random;\n\n // Pick a random iteration count between a min and max iteration count.\n this.targetIterationCount = Math.floor(\n random() * (this.iterationsMax - this.iterationsMin + 1) + this.iterationsMin\n );\n } else {\n this.targetIterationCount = null;\n }\n };\n}\n", "import Node from \"../Node\";\nimport Decorator from \"./Decorator\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A RETRY node.\n * The node has a single child which can have:\n * -- A number of iterations for which to repeat the child node.\n * -- An infinite repeat loop if neither an iteration count or a condition function is defined.\n * The RETRY node will stop and have a 'SUCCEEDED' state if its child is ever in a 'SUCCEEDED' state after an update.\n * The RETRY node will attempt to move on to the next iteration if its child is ever in a 'FAILED' state.\n */\nexport default class Retry extends Decorator {\n /**\n * @param attributes The node attributes.\n * @param attempts The number of attempts to retry the child node.\n * @param attemptsMin The minimum possible number of attempts to retry the child node.\n * @param attemptsMax The maximum possible number of attempts to retry the child node.\n * @param child The child node.\n */\n constructor(\n attributes: Attribute[],\n private attempts: number | null,\n private attemptsMin: number | null,\n private attemptsMax: number | null,\n child: Node\n ) {\n super(\"retry\", attributes, child);\n }\n\n /**\n * The number of target attempts to make.\n */\n private targetAttemptCount: number | null = null;\n\n /**\n * The current attempt count.\n */\n private currentAttemptCount: number = 0;\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // If this node is in the READY state then we need to reset the child and the target attempt count.\n if (this.is(State.READY)) {\n // Reset the child node.\n this.child.reset();\n\n // Reset the current attempt count.\n this.currentAttemptCount = 0;\n\n // Set the target attempt count.\n this.setTargetAttemptCount(options);\n }\n\n // Do a check to see if we can attempt. If we can then this node will move into the 'RUNNING' state.\n // If we cannot attempt then we have hit our target attempt count, which means that the node has succeeded.\n if (this.canAttempt()) {\n // This node is in the running state and can do its initial attempt.\n this.setState(State.RUNNING);\n\n // We may have already completed an attempt, meaning that the child node will be in the FAILED state.\n // If this is the case then we will have to reset the child node now.\n if (this.child.getState() === State.FAILED) {\n this.child.reset();\n }\n\n // Update the child of this node.\n this.child.update(agent, options);\n\n // If the child moved into the SUCCEEDED state when we updated it then there is nothing left to do and this node has also succeeded.\n // If it has moved into the FAILED state then we have completed the current attempt.\n if (this.child.getState() === State.SUCCEEDED) {\n // The child has succeeded, meaning that this node has succeeded.\n this.setState(State.SUCCEEDED);\n\n return;\n } else if (this.child.getState() === State.FAILED) {\n // We have completed an attempt.\n this.currentAttemptCount += 1;\n }\n } else {\n // This node is in the 'FAILED' state as we cannot iterate any more.\n this.setState(State.FAILED);\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => {\n if (this.attempts !== null) {\n return `RETRY ${this.attempts}x`;\n } else if (this.attemptsMin !== null && this.attemptsMax !== null) {\n return `RETRY ${this.attemptsMin}x-${this.attemptsMax}x`;\n } else {\n return \"RETRY\";\n }\n };\n\n /**\n * Reset the state of the node.\n */\n reset = () => {\n // Reset the state of this node.\n this.setState(State.READY);\n\n // Reset the current attempt count.\n this.currentAttemptCount = 0;\n\n // Reset the child node.\n this.child.reset();\n };\n\n /**\n * Gets whether an attempt can be made.\n * @returns Whether an attempt can be made.\n */\n canAttempt = () => {\n if (this.targetAttemptCount !== null) {\n // We can attempt as long as we have not reached our target attempt count.\n return this.currentAttemptCount < this.targetAttemptCount;\n }\n\n // If neither an attempt count or a condition function were defined then we can attempt indefinitely.\n return true;\n };\n\n /**\n * Sets the target attempt count.\n * @param options The behaviour tree options object.\n */\n setTargetAttemptCount = (options: BehaviourTreeOptions) => {\n // Are we dealing with an explicit attempt count or will we be randomly picking an attempt count between the min and max attempt count.\n if (this.attempts !== null) {\n this.targetAttemptCount = this.attempts;\n } else if (this.attemptsMin !== null && this.attemptsMax !== null) {\n // We will be picking a random attempt count between a min and max attempt count, if the optional 'random'\n // behaviour tree function option is defined then we will be using that, otherwise we will fall back to using Math.random.\n const random = typeof options.random === \"function\" ? options.random : Math.random;\n\n // Pick a random attempt count between a min and max attempt count.\n this.targetAttemptCount = Math.floor(\n random() * (this.attemptsMax - this.attemptsMin + 1) + this.attemptsMin\n );\n } else {\n this.targetAttemptCount = null;\n }\n };\n}\n", "import Node from \"../Node\";\nimport Decorator from \"./Decorator\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A Root node.\n * The root node will have a single child.\n */\nexport default class Root extends Decorator {\n /**\n * @param attributes The node attributes.\n * @param child The child node.\n */\n constructor(attributes: Attribute[], child: Node) {\n super(\"root\", attributes, child);\n }\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // If the child has never been updated or is running then we will need to update it now.\n if (this.child.getState() === State.READY || this.child.getState() === State.RUNNING) {\n // Update the child of this node.\n this.child.update(agent, options);\n }\n\n // The state of the root node is the state of its child.\n this.setState(this.child.getState());\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => \"ROOT\";\n}\n", "import Node from \"../Node\";\nimport Decorator from \"./Decorator\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A Succeed node.\n * This node wraps a single child and will always move to the 'SUCCEEDED' state when the child moves to a 'SUCCEEDED' or 'FAILED' state.\n */\nexport default class Succeed extends Decorator {\n /**\n * @param attributes The node attributes.\n * @param child The child node.\n */\n constructor(attributes: Attribute[], child: Node) {\n super(\"succeed\", attributes, child);\n }\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // If the child has never been updated or is running then we will need to update it now.\n if (this.child.getState() === State.READY || this.child.getState() === State.RUNNING) {\n this.child.update(agent, options);\n }\n\n // The state of this node will depend in the state of its child.\n switch (this.child.getState()) {\n case State.RUNNING:\n this.setState(State.RUNNING);\n break;\n\n case State.SUCCEEDED:\n case State.FAILED:\n this.setState(State.SUCCEEDED);\n break;\n\n default:\n this.setState(State.READY);\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => \"SUCCEED\";\n}\n", "import Node from \"../Node\";\n\n/**\n * A leaf node.\n */\nexport default abstract class Leaf extends Node {\n /**\n * Gets whether this node is a leaf node.\n */\n isLeafNode = () => true;\n}\n", "import { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\nimport State, { CompleteState } from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Leaf from \"./Leaf\";\nimport Lookup from \"../../Lookup\";\nimport Attribute from \"../../attributes/Attribute\";\n\n/**\n * An Action leaf node.\n * This represents an immediate or ongoing state of behaviour.\n */\nexport default class Action extends Leaf {\n /**\n * @param attributes The node attributes.\n * @param actionName The action name.\n * @param actionArguments The array of action argument definitions.\n */\n constructor(attributes: Attribute[], private actionName: string, private actionArguments: any[]) {\n super(\"action\", attributes, actionArguments);\n }\n\n /**\n * Whether there is a pending update promise.\n */\n private isUsingUpdatePromise = false;\n\n /**\n * The finished state result of an update promise.\n */\n private updatePromiseStateResult: CompleteState | null = null;\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // If the result of this action depends on an update promise then there is nothing to do until\n // it resolves, unless there has been a value set as a result of the update promise resolving.\n if (this.isUsingUpdatePromise) {\n // Check whether the update promise has resolved with a state value.\n if (this.updatePromiseStateResult) {\n // Set the state of this node to match the state returned by the promise.\n this.setState(this.updatePromiseStateResult);\n }\n\n return;\n }\n\n // Attempt to get the invoker for the action function.\n const actionFuncInvoker = Lookup.getFuncInvoker(agent, this.actionName);\n\n // The action function should be defined.\n if (actionFuncInvoker === null) {\n throw new Error(\n `cannot update action node as the action '${this.actionName}' function is not defined on the agent and has not been registered`\n );\n }\n\n // Call the action function, the result of which may be:\n // - The finished state of this action node.\n // - A promise to return a finished node state.\n // - Undefined if the node should remain in the running state.\n const updateResult = actionFuncInvoker(this.actionArguments) as CompleteState | Promise;\n\n if (updateResult instanceof Promise) {\n updateResult.then(\n (result) => {\n // If 'isUpdatePromisePending' is null then the promise was cleared as it was resolving, probably via an abort of reset.\n if (!this.isUsingUpdatePromise) {\n return;\n }\n\n // Check to make sure the result is a valid finished state.\n if (result !== State.SUCCEEDED && result !== State.FAILED) {\n throw new Error(\n \"action node promise resolved with an invalid value, expected a State.SUCCEEDED or State.FAILED value to be returned\"\n );\n }\n\n // Set pending update promise state result to be processed on next update.\n this.updatePromiseStateResult = result;\n },\n (reason) => {\n // If 'isUpdatePromisePending' is null then the promise was cleared as it was resolving, probably via an abort of reset.\n if (!this.isUsingUpdatePromise) {\n return;\n }\n\n // Just throw whatever was returned as the rejection argument.\n throw new Error(reason);\n }\n );\n\n // This node will be in the 'RUNNING' state until the update promise resolves.\n this.setState(State.RUNNING);\n\n // We are now waiting for the promise returned by the use to resolve before we know what state this node is in.\n this.isUsingUpdatePromise = true;\n } else {\n // Validate the returned value.\n this.validateUpdateResult(updateResult);\n\n // Set the state of this node, this may be undefined, which just means that the node is still in the 'RUNNING' state.\n this.setState(updateResult || State.RUNNING);\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => this.actionName;\n\n /**\n * Reset the state of the node.\n */\n reset = () => {\n // Reset the state of this node.\n this.setState(State.READY);\n\n // There is no longer an update promise that we care about.\n this.isUsingUpdatePromise = false;\n this.updatePromiseStateResult = null;\n };\n\n /**\n * Validate the result of an update function call.\n * @param result The result of an update function call.\n */\n private validateUpdateResult = (result: CompleteState | boolean) => {\n switch (result) {\n case State.SUCCEEDED:\n case State.FAILED:\n case undefined:\n return;\n default:\n throw new Error(\n `action '${this.actionName}' 'onUpdate' returned an invalid response, expected an optional State.SUCCEEDED or State.FAILED value to be returned`\n );\n }\n };\n}\n", "import { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Leaf from \"./Leaf\";\nimport Lookup from \"../../Lookup\";\nimport Attribute from \"../../attributes/Attribute\";\n\n/**\n * A Condition leaf node.\n * This will succeed or fail immediately based on an agent predicate, without moving to the 'RUNNING' state.\n */\nexport default class Condition extends Leaf {\n /**\n * @param attributes The node attributes.\n * @param conditionName The name of the condition function.\n * @param conditionArguments The array of condition argument definitions.\n */\n constructor(attributes: Attribute[], private conditionName: string, private conditionArguments: any[]) {\n super(\"condition\", attributes, conditionArguments);\n }\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // Attempt to get the invoker for the condition function.\n const conditionFuncInvoker = Lookup.getFuncInvoker(agent, this.conditionName);\n\n // The condition function should be defined.\n if (conditionFuncInvoker === null) {\n throw new Error(\n `cannot update condition node as the condition '${this.conditionName}' function is not defined on the agent and has not been registered`\n );\n }\n\n // Call the condition function to determine the state of this node.\n this.setState(!!conditionFuncInvoker(this.conditionArguments) ? State.SUCCEEDED : State.FAILED);\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => this.conditionName;\n}\n", "import Leaf from \"./Leaf\";\nimport State from \"../../State\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { Agent } from \"../../Agent\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A WAIT node.\n * The state of this node will change to SUCCEEDED after a duration of time\n */\nexport default class Wait extends Leaf {\n /**\n * @param attributes The node attributes.\n * @param duration The duration that this node will wait to succeed in milliseconds.\n * @param durationMin The minimum possible duration in milliseconds that this node will wait to succeed.\n * @param durationMax The maximum possible duration in milliseconds that this node will wait to succeed.\n */\n constructor(\n attributes: Attribute[],\n private duration: number | null,\n private durationMin: number | null,\n private durationMax: number | null\n ) {\n super(\"wait\", attributes, []);\n }\n\n /**\n * The time in milliseconds at which this node was first updated.\n */\n private initialUpdateTime: number = 0;\n\n /**\n * The total duration in milliseconds that this node will be waiting for.\n */\n private totalDuration: number | null = null;\n\n /**\n * The duration in milliseconds that this node has been waiting for.\n */\n private waitedDuration: number = 0;\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // If this node is in the READY state then we need to set the initial update time.\n if (this.is(State.READY)) {\n // Set the initial update time.\n this.initialUpdateTime = new Date().getTime();\n\n // Set the initial waited duration.\n this.waitedDuration = 0;\n\n // Are we dealing with an explicit duration or will we be randomly picking a duration between the min and max duration.\n if (this.duration !== null) {\n this.totalDuration = this.duration;\n } else if (this.durationMin !== null && this.durationMax !== null) {\n // We will be picking a random duration between a min and max duration, if the optional 'random' behaviour tree\n // function option is defined then we will be using that, otherwise we will fall back to using Math.random.\n const random = typeof options.random === \"function\" ? options.random : Math.random;\n\n // Pick a random duration between a min and max duration.\n this.totalDuration = Math.floor(\n random() * (this.durationMax - this.durationMin + 1) + this.durationMin\n );\n } else {\n this.totalDuration = null;\n }\n\n // The node is now running until we finish waiting.\n this.setState(State.RUNNING);\n }\n\n // If we have no total duration then this wait node will wait indefinitely until it is aborted.\n if (this.totalDuration === null) {\n return;\n }\n\n // If we have a 'getDeltaTime' function defined as part of our options then we will use it to figure out how long we have waited for.\n if (typeof options.getDeltaTime === \"function\") {\n // Get the delta time.\n const deltaTime = options.getDeltaTime();\n\n // Our delta time must be a valid number and cannot be NaN.\n if (typeof deltaTime !== \"number\" || isNaN(deltaTime)) {\n throw new Error(\"The delta time must be a valid number and not NaN.\");\n }\n\n // Update the amount of time that this node has been waiting for based on the delta time.\n this.waitedDuration += deltaTime * 1000;\n } else {\n // We are not using a delta time, so we will just work out hom much time has passed since the first update.\n this.waitedDuration = new Date().getTime() - this.initialUpdateTime;\n }\n\n // Have we waited long enough?\n if (this.waitedDuration >= this.totalDuration) {\n // We have finished waiting!\n this.setState(State.SUCCEEDED);\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => {\n if (this.duration !== null) {\n return `WAIT ${this.duration}ms`;\n } else if (this.durationMin !== null && this.durationMax !== null) {\n return `WAIT ${this.durationMin}ms-${this.durationMax}ms`;\n } else {\n return \"WAIT\";\n }\n };\n}\n", "import Guard from \"./guards/Guard\";\n\nexport type AttributeDetails = {\n /** The attribute type. */\n type: string;\n\n /** The attribute arguments. */\n args: any[];\n};\n\n/**\n * A base node attribute.\n */\nexport default abstract class Attribute {\n /**\n * @param type The node attribute type.\n * @param args The array of attribute arguments.\n */\n constructor(public type: string, public args: any[]) {}\n\n /**\n * Gets the attribute details.\n */\n abstract getDetails(): TAttributeDetails;\n\n /**\n * Gets whether this attribute is a guard.\n */\n abstract isGuard: () => this is Guard;\n}\n", "import { Agent } from \"../../Agent\";\nimport Attribute, { AttributeDetails } from \"../Attribute\";\n\nexport type GuardAttributeDetails = {\n /** The name of the condition function that determines whether the guard is satisfied. */\n condition: string;\n} & AttributeDetails;\n\n/**\n * A base node guard attribute.\n */\nexport default abstract class Guard extends Attribute {\n /**\n * @param type The node attribute type.\n * @param args The array of decorator argument definitions.\n * @param condition The name of the condition function that determines whether the guard is satisfied.\n */\n constructor(type: string, args: any[], private condition: string) {\n super(type, args);\n }\n\n /**\n * Gets the name of the condition function that determines whether the guard is satisfied.\n */\n getCondition = () => this.condition;\n\n /**\n * Gets whether this attribute is a guard.\n */\n isGuard = () => true;\n\n /**\n * Gets the attribute details.\n */\n getDetails(): GuardAttributeDetails {\n return {\n type: this.type,\n args: this.args,\n condition: this.getCondition()\n };\n }\n\n /**\n * Gets whether the guard is satisfied.\n * @param agent The agent.\n * @returns Whether the guard is satisfied.\n */\n abstract isSatisfied(agent: Agent): boolean;\n}\n", "import Guard from \"./Guard\";\nimport Lookup from \"../../Lookup\";\nimport { Agent } from \"../../Agent\";\n\n/**\n * A WHILE guard which is satisfied as long as the given condition remains true.\n */\nexport default class While extends Guard {\n /**\n * @param condition The name of the condition function that determines whether the guard is satisfied.\n * @param args The array of decorator argument definitions.\n */\n constructor(condition: string, args: any[]) {\n super(\"while\", args, condition);\n }\n\n /**\n * Gets whether the guard is satisfied.\n * @param agent The agent.\n * @returns Whether the guard is satisfied.\n */\n isSatisfied = (agent: Agent) => {\n // Attempt to get the invoker for the condition function.\n const conditionFuncInvoker = Lookup.getFuncInvoker(agent, this.getCondition());\n\n // The condition function should be defined.\n if (conditionFuncInvoker === null) {\n throw new Error(\n `cannot evaluate node guard as the condition '${this.getCondition()}' function is not defined on the agent and has not been registered`\n );\n }\n\n // Call the condition function to determine whether this guard is satisfied.\n return !!conditionFuncInvoker(this.args);\n };\n}\n", "import Guard from \"./Guard\";\nimport Lookup from \"../../Lookup\";\nimport { Agent } from \"../../Agent\";\n\n/**\n * An UNTIL guard which is satisfied as long as the given condition remains false.\n */\nexport default class Until extends Guard {\n /**\n * @param condition The name of the condition function that determines whether the guard is satisfied.\n * @param args The array of decorator argument definitions.\n */\n constructor(condition: string, args: any[]) {\n super(\"until\", args, condition);\n }\n\n /**\n * Gets whether the guard is satisfied.\n * @param agent The agent.\n * @returns Whether the guard is satisfied.\n */\n isSatisfied = (agent: Agent) => {\n // Attempt to get the invoker for the condition function.\n const conditionFuncInvoker = Lookup.getFuncInvoker(agent, this.getCondition());\n\n // The condition function should be defined.\n if (conditionFuncInvoker === null) {\n throw new Error(\n `cannot evaluate node guard as the condition '${this.getCondition()}' function is not defined on the agent and has not been registered`\n );\n }\n\n // Call the condition function to determine whether this guard is satisfied.\n return !!!conditionFuncInvoker(this.args);\n };\n}\n", "import { Agent } from \"../../Agent\";\nimport Attribute, { AttributeDetails } from \"../Attribute\";\n\nexport type CallbackAttributeDetails = {\n /** The name of the agent function that is called. */\n functionName: string;\n} & AttributeDetails;\n\n/**\n * A base node callback attribute.\n */\nexport default abstract class Callback extends Attribute {\n /**\n * @param type The node attribute type.\n * @param args The array of decorator argument definitions.\n * @param functionName The name of the agent function to call.\n */\n constructor(type: string, args: any[], private functionName: string) {\n super(type, args);\n }\n\n /**\n * Gets the name of the agent function to call.\n */\n getFunctionName = () => this.functionName;\n\n /**\n * Gets whether this attribute is a guard.\n */\n isGuard = () => false;\n\n /**\n * Gets the attribute details.\n */\n getDetails(): CallbackAttributeDetails {\n return {\n type: this.type,\n args: this.args,\n functionName: this.getFunctionName()\n };\n }\n\n /**\n * Attempt to call the agent function that this callback refers to.\n * @param agent The agent.\n */\n abstract callAgentFunction: (agent: Agent, isSuccess: boolean, isAborted: boolean) => void;\n}\n", "import Callback from \"./Callback\";\nimport Lookup from \"../../Lookup\";\nimport { Agent } from \"../../Agent\";\n\n/**\n * An ENTRY callback which defines an agent function to call when the associated node is updated and moves out of running state.\n */\nexport default class Entry extends Callback {\n /**\n * @param functionName The name of the agent function to call.\n * @param args The array of callback argument definitions.\n */\n constructor(functionName: string, args: any[]) {\n super(\"entry\", args, functionName);\n }\n\n /**\n * Attempt to call the agent function that this callback refers to.\n * @param agent The agent.\n */\n callAgentFunction = (agent: Agent) => {\n // Attempt to get the invoker for the callback function.\n const callbackFuncInvoker = Lookup.getFuncInvoker(agent, this.getFunctionName());\n\n // The callback function should be defined.\n if (callbackFuncInvoker === null) {\n throw new Error(\n `cannot call entry function '${this.getFunctionName()}' as is not defined on the agent and has not been registered`\n );\n }\n\n // Call the callback function.\n callbackFuncInvoker(this.args);\n };\n}\n", "import Callback from \"./Callback\";\nimport Lookup from \"../../Lookup\";\nimport { Agent } from \"../../Agent\";\n\n/**\n * A STEP callback which defines an agent function to call when the associated node is updated.\n */\nexport default class Step extends Callback {\n /**\n * @param functionName The name of the agent function to call.\n * @param args The array of callback argument definitions.\n */\n constructor(functionName: string, args: any[]) {\n super(\"step\", args, functionName);\n }\n\n /**\n * Attempt to call the agent function that this callback refers to.\n * @param agent The agent.\n */\n callAgentFunction = (agent: Agent) => {\n // Attempt to get the invoker for the callback function.\n const callbackFuncInvoker = Lookup.getFuncInvoker(agent, this.getFunctionName());\n\n // The callback function should be defined.\n if (callbackFuncInvoker === null) {\n throw new Error(\n `cannot call step function '${this.getFunctionName()}' as is not defined on the agent and has not been registered`\n );\n }\n\n // Call the callback function.\n callbackFuncInvoker(this.args);\n };\n}\n", "import Callback from \"./Callback\";\nimport Lookup from \"../../Lookup\";\nimport { Agent } from \"../../Agent\";\n\n/**\n * An EXIT callback which defines an agent function to call when the associated node is updated and moves to a finished state or is aborted.\n */\nexport default class Exit extends Callback {\n /**\n * @param functionName The name of the agent function to call.\n * @param args The array of callback argument definitions.\n */\n constructor(functionName: string, args: any[]) {\n super(\"exit\", args, functionName);\n }\n\n /**\n * Attempt to call the agent function that this callback refers to.\n * @param agent The agent.\n * @param isSuccess Whether the decorated node was left with a success state.\n * @param isAborted Whether the decorated node was aborted.\n */\n callAgentFunction = (agent: Agent, isSuccess: boolean, isAborted: boolean) => {\n // Attempt to get the invoker for the callback function.\n const callbackFuncInvoker = Lookup.getFuncInvoker(agent, this.getFunctionName());\n\n // The callback function should be defined.\n if (callbackFuncInvoker === null) {\n throw new Error(\n `cannot call exit function '${this.getFunctionName()}' as is not defined on the agent and has not been registered`\n );\n }\n\n // Call the callback function\n callbackFuncInvoker([{ value: { succeeded: isSuccess, aborted: isAborted } }, ...this.args]);\n };\n}\n", "import { AnyNodeDefinition, RootNodeDefinition } from \"./BehaviourTreeDefinition\";\nimport GuardPath, { GuardPathPart } from \"./attributes/guards/GuardPath\";\nimport { validateBranchSubtreeLinks } from \"./BehaviourTreeDefinitionValidator\";\nimport { isInteger } from \"./BehaviourTreeDefinitionUtilities\";\nimport Node from \"./nodes/Node\";\nimport Composite from \"./nodes/composite/Composite\";\nimport Decorator from \"./nodes/decorator/Decorator\";\nimport Parallel from \"./nodes/composite/Parallel\";\nimport Selector from \"./nodes/composite/Selector\";\nimport Sequence from \"./nodes/composite/Sequence\";\nimport Lotto from \"./nodes/composite/Lotto\";\nimport Fail from \"./nodes/decorator/Fail\";\nimport Flip from \"./nodes/decorator/Flip\";\nimport Repeat from \"./nodes/decorator/Repeat\";\nimport Retry from \"./nodes/decorator/Retry\";\nimport Root from \"./nodes/decorator/Root\";\nimport Succeed from \"./nodes/decorator/Succeed\";\nimport Action from \"./nodes/leaf/Action\";\nimport Condition from \"./nodes/leaf/Condition\";\nimport Wait from \"./nodes/leaf/Wait\";\nimport Lookup from \"./Lookup\";\nimport Attribute from \"./attributes/Attribute\";\nimport While from \"./attributes/guards/While\";\nimport Until from \"./attributes/guards/Until\";\nimport Entry from \"./attributes/callbacks/Entry\";\nimport Step from \"./attributes/callbacks/Step\";\nimport Exit from \"./attributes/callbacks/Exit\";\n\n/**\n * A type representing any node instance in a behaviour tree.\n */\ntype AnyNode =\n | Root\n | Action\n | Condition\n | Wait\n | Sequence\n | Selector\n | Lotto\n | Parallel\n | Repeat\n | Retry\n | Flip\n | Succeed\n | Fail;\n\n/**\n * A type defining a mapping of root node identifiers to root node definitions.\n */\ntype RootNodeDefinitionMap = { [key: string | symbol]: RootNodeDefinition };\n\n/**\n * A symbol to use as the main root key in any root node mappings.\n */\nconst MAIN_ROOT_NODE_KEY = Symbol(\"__root__\");\n\n/**\n * Build and populate the root nodes based on the provided definition, assuming that the definition has been validated.\n * @param definition The root node definitions.\n * @returns The built and populated root node definitions.\n */\nexport default function buildRootNode(definition: RootNodeDefinition[]): Root {\n // Create a mapping of root node identifers to root node definitions, including globally registered subtree root node definitions.\n const rootNodeDefinitionMap = createRootNodeDefinitionMap(definition);\n\n // Now that we have all of our root node definitons (those part of the tree definition and those globally\n // registered) we should validate the definition. This will also double-check that we dont have any circular\n // dependencies in our branch -> subtree references and that we have no broken branch -> subtree links.\n validateBranchSubtreeLinks(definition, true);\n\n // Create our populated tree of node instances, starting with our main root node.\n const rootNode = nodeFactory(rootNodeDefinitionMap[MAIN_ROOT_NODE_KEY], rootNodeDefinitionMap) as Root;\n\n // Set a guard path on every leaf of the tree to evaluate as part of each update.\n applyLeafNodeGuardPaths(rootNode);\n\n // We only need to return the main root node.\n return rootNode;\n}\n\n/**\n * A factory function which creates a node instance based on the specified definition.\n * @param definition The node definition.\n * @param rootNodeDefinitionMap The mapping of root node identifers to root node definitions, including globally registered subtree root node definitions.\n * @returns A node instance based on the specified definition.\n */\nfunction nodeFactory(definition: AnyNodeDefinition, rootNodeDefinitionMap: RootNodeDefinitionMap): AnyNode {\n // Get the attributes for the node.\n const attributes = nodeAttributesFactory(definition);\n\n // Create the node instance based on the definition type.\n switch (definition.type) {\n case \"root\":\n return new Root(attributes, nodeFactory(definition.child, rootNodeDefinitionMap));\n\n case \"repeat\":\n let iterations: number | null = null;\n let iterationsMin: number | null = null;\n let iterationsMax: number | null = null;\n\n if (Array.isArray(definition.iterations)) {\n iterationsMin = definition.iterations[0];\n iterationsMax = definition.iterations[1];\n } else if (isInteger(definition.iterations)) {\n iterations = definition.iterations!;\n }\n\n return new Repeat(\n attributes,\n iterations,\n iterationsMin,\n iterationsMax,\n nodeFactory(definition.child, rootNodeDefinitionMap)\n );\n\n case \"retry\":\n let attempts: number | null = null;\n let attemptsMin: number | null = null;\n let attemptsMax: number | null = null;\n\n if (Array.isArray(definition.attempts)) {\n attemptsMin = definition.attempts[0];\n attemptsMax = definition.attempts[1];\n } else if (isInteger(definition.attempts)) {\n attempts = definition.attempts!;\n }\n\n return new Retry(\n attributes,\n attempts,\n attemptsMin,\n attemptsMax,\n nodeFactory(definition.child, rootNodeDefinitionMap)\n );\n\n case \"flip\":\n return new Flip(attributes, nodeFactory(definition.child, rootNodeDefinitionMap));\n\n case \"succeed\":\n return new Succeed(attributes, nodeFactory(definition.child, rootNodeDefinitionMap));\n\n case \"fail\":\n return new Fail(attributes, nodeFactory(definition.child, rootNodeDefinitionMap));\n\n case \"sequence\":\n return new Sequence(\n attributes,\n definition.children.map((child) => nodeFactory(child, rootNodeDefinitionMap))\n );\n\n case \"selector\":\n return new Selector(\n attributes,\n definition.children.map((child) => nodeFactory(child, rootNodeDefinitionMap))\n );\n\n case \"parallel\":\n return new Parallel(\n attributes,\n definition.children.map((child) => nodeFactory(child, rootNodeDefinitionMap))\n );\n\n case \"lotto\":\n return new Lotto(\n attributes,\n definition.weights,\n definition.children.map((child) => nodeFactory(child, rootNodeDefinitionMap))\n );\n\n case \"branch\":\n return nodeFactory(rootNodeDefinitionMap[definition.ref].child, rootNodeDefinitionMap);\n\n case \"action\":\n return new Action(attributes, definition.call, definition.args || []);\n\n case \"condition\":\n return new Condition(attributes, definition.call, definition.args || []);\n\n case \"wait\":\n let duration: number | null = null;\n let durationMin: number | null = null;\n let durationMax: number | null = null;\n\n if (Array.isArray(definition.duration)) {\n durationMin = definition.duration[0];\n durationMax = definition.duration[1];\n } else if (isInteger(definition.duration)) {\n duration = definition.duration!;\n }\n\n return new Wait(attributes, duration, durationMin, durationMax);\n }\n}\n\n/**\n * Creates an array of node attribute instances based on the specified node definition.\n * @param definition The node definition.\n * @returns An array of node attribute instances based on the specified node definition.\n */\nfunction nodeAttributesFactory(definition: AnyNodeDefinition): Attribute[] {\n const attributes: Attribute[] = [];\n\n if (definition.while) {\n attributes.push(new While(definition.while.call, definition.while.args ?? []));\n }\n\n if (definition.until) {\n attributes.push(new Until(definition.until.call, definition.until.args ?? []));\n }\n\n if (definition.entry) {\n attributes.push(new Entry(definition.entry.call, definition.entry.args ?? []));\n }\n\n if (definition.step) {\n attributes.push(new Step(definition.step.call, definition.step.args ?? []));\n }\n\n if (definition.exit) {\n attributes.push(new Exit(definition.exit.call, definition.exit.args ?? []));\n }\n\n return attributes;\n}\n\n/**\n * Creates a mapping of root node identifers to root node definitions, mixing in globally registered subtree root node definitions.\n * @param definition The root node definitions.\n * @returns A mapping of root node identifers to root node definitions, including globally registered subtree root node definitions.\n */\nfunction createRootNodeDefinitionMap(definition: RootNodeDefinition[]): RootNodeDefinitionMap {\n // Create a mapping of root node identifers to root node definitions.\n const rootNodeMap: RootNodeDefinitionMap = {};\n\n // Add in any registered subtree root node definitions.\n for (const [name, rootNodeDefinition] of Object.entries(Lookup.getSubtrees())) {\n // The name used when registering the subtree will be used as the root node identifier.\n rootNodeMap[name] = { ...rootNodeDefinition, id: name };\n }\n\n // Populate the map with the root node definitions that were included with the tree definition.\n // We do this after adding any registered subtrees as we want these to take presedence.\n for (const rootNodeDefinition of definition) {\n rootNodeMap[rootNodeDefinition.id ?? MAIN_ROOT_NODE_KEY] = rootNodeDefinition;\n }\n\n return rootNodeMap;\n}\n\n/**\n * Applies a guard path to every leaf of the tree to evaluate as part of each update.\n * @param root The main root tree node.\n */\nfunction applyLeafNodeGuardPaths(root: Root) {\n const nodePaths: Node[][] = [];\n\n const findLeafNodes = (path: Node[], node: Node) => {\n // Add the current node to the path.\n path = path.concat(node);\n\n // Check whether the current node is a leaf node.\n if (node.isLeafNode()) {\n nodePaths.push(path);\n } else {\n (node as Composite | Decorator).getChildren().forEach((child) => findLeafNodes(path, child));\n }\n };\n\n // Find all leaf node paths, starting from the root.\n findLeafNodes([], root);\n\n nodePaths.forEach((path) => {\n // Each node in the current path will have to be assigned a guard path, working from the root outwards.\n for (let depth = 0; depth < path.length; depth++) {\n // Get the node in the path at the current depth.\n const currentNode = path[depth];\n\n // The node may already have been assigned a guard path, if so just skip it.\n if (currentNode.hasGuardPath()) {\n continue;\n }\n\n // Create the guard path for the current node.\n const guardPath = new GuardPath(\n path\n .slice(0, depth + 1)\n .map((node) => ({ node, guards: node.getGuardAttributes() }))\n .filter((details) => details.guards.length > 0)\n );\n\n // Assign the guard path to the current node.\n currentNode.setGuardPath(guardPath);\n }\n });\n}\n", "import State, { AnyState } from \"./State\";\nimport Lookup from \"./Lookup\";\nimport Node from \"./nodes/Node\";\nimport Root from \"./nodes/decorator/Root\";\nimport Composite from \"./nodes/composite/Composite\";\nimport Decorator from \"./nodes/decorator/Decorator\";\nimport { Agent, GlobalFunction } from \"./Agent\";\nimport { CallbackAttributeDetails } from \"./attributes/callbacks/Callback\";\nimport { GuardAttributeDetails } from \"./attributes/guards/Guard\";\nimport { BehaviourTreeOptions } from \"./BehaviourTreeOptions\";\nimport { convertMDSLToJSON } from \"./mdsl/MDSLDefinitionParser\";\nimport { RootNodeDefinition } from \"./BehaviourTreeDefinition\";\nimport { validateDefinition, validateJSONDefinition } from \"./BehaviourTreeDefinitionValidator\";\nimport buildRootNode from \"./BehaviourTreeBuilder\";\nimport { isNullOrUndefined } from \"./BehaviourTreeDefinitionUtilities\";\n\n// Purely for outside inspection of the tree.\nexport type FlattenedTreeNode = {\n id: string;\n type: string;\n caption: string;\n state: AnyState;\n guards: GuardAttributeDetails[];\n callbacks: CallbackAttributeDetails[];\n args: any[];\n parentId: string | null;\n};\n\n/**\n * A representation of a behaviour tree.\n */\nexport class BehaviourTree {\n /**\n * The main root tree node.\n */\n public readonly rootNode: Root;\n\n /**\n * Creates a new instance of the BehaviourTree class.\n * @param definition The behaviour tree definition.\n * @param agent The agent instance that this behaviour tree is modelling behaviour for.\n * @param options The behaviour tree options object.\n */\n constructor(\n definition: string | RootNodeDefinition | RootNodeDefinition[],\n private agent: Agent,\n private options: BehaviourTreeOptions = {}\n ) {\n // The tree definition must be defined.\n if (isNullOrUndefined(definition)) {\n throw new Error(\"tree definition not defined\");\n }\n\n // The agent must be defined and not null.\n if (typeof agent !== \"object\" || agent === null) {\n throw new Error(\"the agent must be an object and not null\");\n }\n\n // We should validate the definition before we try to build the tree nodes.\n const { succeeded, errorMessage } = validateDefinition(definition);\n\n // Did our validation fail without error?\n if (!succeeded) {\n throw new Error(`invalid definition: ${errorMessage}`);\n }\n\n try {\n // Parse the behaviour tree definition, create the populated tree of behaviour tree nodes, and get the root.\n this.rootNode = this._createRootNode(definition);\n } catch (exception) {\n // There was an issue in trying build and populate the behaviour tree.\n throw new Error(`error building tree: ${(exception as Error).message}`);\n }\n }\n\n /**\n * Gets whether the tree is in the RUNNING state.\n * @returns true if the tree is in the RUNNING state, otherwise false.\n */\n isRunning() {\n return this.rootNode.getState() === State.RUNNING;\n }\n\n /**\n * Gets the current tree state of SUCCEEDED, FAILED, READY or RUNNING.\n * @returns The current tree state.\n */\n getState() {\n return this.rootNode.getState();\n }\n\n /**\n * Step the tree.\n * 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.\n * 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\n * 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.\n *\n * 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.\n */\n step() {\n // If the root node has already been stepped to completion then we need to reset it.\n if (this.rootNode.getState() === State.SUCCEEDED || this.rootNode.getState() === State.FAILED) {\n this.rootNode.reset();\n }\n\n try {\n this.rootNode.update(this.agent, this.options);\n } catch (exception) {\n throw new Error(`error stepping tree: ${(exception as Error).message}`);\n }\n }\n\n /**\n * Resets the tree from the root node outwards to each nested node, giving each a state of READY.\n */\n reset() {\n this.rootNode.reset();\n }\n\n /**\n * Gets the flattened details of every node in the tree.\n * @returns The flattened details of every node in the tree.\n */\n getFlattenedNodeDetails(): FlattenedTreeNode[] {\n // Create an empty flattened array of tree nodes.\n const flattenedTreeNodes: FlattenedTreeNode[] = [];\n\n /**\n * Helper function to process a node instance and push details into the flattened tree nodes array.\n * @param node The current node.\n * @param parentUid The UID of the node parent, or null if the node is the main root node.\n */\n const processNode = (node: Node, parentUid: string | null) => {\n // Get the guard and callback attribute details for this node.\n const guards = node\n .getAttributes()\n .filter((attribute) => attribute.isGuard())\n .map((attribute) => attribute.getDetails()) as GuardAttributeDetails[];\n const callbacks = node\n .getAttributes()\n .filter((attribute) => !attribute.isGuard())\n .map((attribute) => attribute.getDetails()) as CallbackAttributeDetails[];\n\n // Push the current node into the flattened nodes array.\n flattenedTreeNodes.push({\n id: node.getUid(),\n type: node.getType(),\n caption: node.getName(),\n state: node.getState(),\n guards,\n callbacks,\n args: node.getArguments(),\n parentId: parentUid\n });\n\n // Process each of the nodes children if it is not a leaf node.\n if (!node.isLeafNode()) {\n (node as Composite | Decorator)\n .getChildren()\n .forEach((child) => processNode(child, (node as Composite | Decorator).getUid()));\n }\n };\n\n // Convert the nested node structure into a flattened array of node details.\n processNode(this.rootNode, null);\n\n return flattenedTreeNodes;\n }\n\n /**\n * Registers the action/condition/guard/callback function or subtree with the given name.\n * @param name The name of the function or subtree to register.\n * @param value The function or subtree definition to register.\n */\n static register(name: string, value: GlobalFunction | string | RootNodeDefinition) {\n // Are we going to register a action/condition/guard/callback function?\n if (typeof value === \"function\") {\n Lookup.setFunc(name, value);\n return;\n }\n\n // We are not registering an action/condition/guard/callback function, so we must be registering a subtree.\n if (typeof value === \"string\") {\n let rootNodeDefinitions: RootNodeDefinition[];\n\n // We will assume that any string passed in will be a mdsl definition.\n try {\n rootNodeDefinitions = convertMDSLToJSON(value);\n } catch (exception) {\n throw new Error(`error registering definition, invalid MDSL: ${(exception as Error).message}`);\n }\n\n // This function should only ever be called with a definition containing a single unnamed root node.\n if (rootNodeDefinitions.length != 1 || rootNodeDefinitions[0].id !== null) {\n throw new Error(\"error registering definition: expected a single unnamed root node\");\n }\n\n try {\n // We should validate the subtree as we don't want invalid subtrees available via the lookup.\n const { succeeded, errorMessage } = validateJSONDefinition(rootNodeDefinitions[0]);\n\n // Did our validation fail without error?\n if (!succeeded) {\n throw new Error(errorMessage);\n }\n } catch (exception) {\n throw new Error(`error registering definition: ${(exception as Error).message}`);\n }\n\n // Everything seems hunky-dory, register the subtree.\n Lookup.setSubtree(name, rootNodeDefinitions[0]);\n } else if (typeof value === \"object\" && !Array.isArray(value)) {\n // We will assume that any object passed in is a root node definition.\n\n try {\n // We should validate the subtree as we don't want invalid subtrees available via the lookup.\n const { succeeded, errorMessage } = validateJSONDefinition(value);\n\n // Did our validation fail without error?\n if (!succeeded) {\n throw new Error(errorMessage);\n }\n } catch (exception) {\n throw new Error(`error registering definition: ${(exception as Error).message}`);\n }\n\n // Everything seems hunky-dory, register the subtree.\n Lookup.setSubtree(name, value);\n } else {\n throw new Error(\"unexpected value, expected string mdsl definition, root node json definition or function\");\n }\n }\n\n /**\n * Unregisters the registered action/condition/guard/callback function or subtree with the given name.\n * @param name The name of the registered action/condition/guard/callback function or subtree to unregister.\n */\n static unregister(name: string): void {\n Lookup.remove(name);\n }\n\n /**\n * Unregister all registered action/condition/guard/callback functions and subtrees.\n */\n static unregisterAll(): void {\n Lookup.empty();\n }\n\n /**\n * Parses a behaviour tree definition and creates a tree of behaviour tree nodes populated at a root.\n * @param {string | RootNodeDefinition | RootNodeDefinition[]} definition The behaviour tree definition.\n * @returns The root behaviour tree node.\n */\n private _createRootNode(definition: string | RootNodeDefinition | RootNodeDefinition[]): Root {\n // Our definition will have to be converted to JSON if it is a MDSL string.\n // TODO convertMDSLToJSON is called TWICE, once for validation and once here. Maybe return the JSON as part of the validation result?\n const resolvedDefinition = typeof definition === \"string\" ? convertMDSLToJSON(definition) : definition;\n\n // Build and populate the root node.\n return buildRootNode(Array.isArray(resolvedDefinition) ? resolvedDefinition : [resolvedDefinition]);\n }\n}\n"], - "mappings": "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", + "sourcesContent": ["\"use strict\";\r\nObject.defineProperty(exports, \"__esModule\", { value: true });\r\nexports.Participant = void 0;\r\n/**\r\n * A participant that holds a number of tickets.\r\n */\r\nvar Participant = /** @class */ (function () {\r\n /**\r\n * Creates an instance of the Participant class.\r\n * @param participant The actual participant.\r\n * @param tickets The number of tickets held by the participant.\r\n */\r\n function Participant(participant, tickets) {\r\n if (tickets === void 0) { tickets = 1; }\r\n this._participant = participant;\r\n this._tickets = tickets;\r\n }\r\n Object.defineProperty(Participant.prototype, \"participant\", {\r\n /** Gets the actual participant. */\r\n get: function () {\r\n return this._participant;\r\n },\r\n enumerable: false,\r\n configurable: true\r\n });\r\n Object.defineProperty(Participant.prototype, \"tickets\", {\r\n /** Gets or sets the number of tickets held by the participant. */\r\n get: function () {\r\n return this._tickets;\r\n },\r\n set: function (value) {\r\n this._tickets = value;\r\n },\r\n enumerable: false,\r\n configurable: true\r\n });\r\n return Participant;\r\n}());\r\nexports.Participant = Participant;\r\n", "\"use strict\";\r\nObject.defineProperty(exports, \"__esModule\", { value: true });\r\nexports.isNaturalNumber = exports.isNullOrUndefined = void 0;\r\n/**\r\n * Gets whether the value provided is null or undefined.\r\n * @param value The value to check.\r\n * @returns Whether the value provided is null or undefined.\r\n */\r\nfunction isNullOrUndefined(value) {\r\n return value === null || value === undefined;\r\n}\r\nexports.isNullOrUndefined = isNullOrUndefined;\r\n/**\r\n * Gets whether the value provided is a natural number.\r\n * @param value The value to check.\r\n * @returns Whether the value provided is a natural number.\r\n */\r\nfunction isNaturalNumber(value) {\r\n return typeof value === \"number\" && value >= 1 && Math.floor(value) === value;\r\n}\r\nexports.isNaturalNumber = isNaturalNumber;\r\n", "\"use strict\";\r\nObject.defineProperty(exports, \"__esModule\", { value: true });\r\nexports.Lotto = void 0;\r\nvar Participant_1 = require(\"./Participant\");\r\nvar Utilities_1 = require(\"./Utilities\");\r\n/**\r\n * Represents a lotto consisting of a number of pickable ticket-holding participants.\r\n */\r\nvar Lotto = /** @class */ (function () {\r\n /**\r\n * Creates a new instance of Lotto.\r\n * @param customRandom The custom RNG to use in place of Math.random().\r\n */\r\n function Lotto(customRandom) {\r\n /** The array of participants that are holding tickets in the lotto. */\r\n this._participants = [];\r\n this._customRandom = customRandom;\r\n }\r\n /**\r\n * Adds a participant with the specified number of tickets, or adds to the participant ticket count if the participant already holds tickets.\r\n * @param participant The participant to add or to increase the ticket count for if they already hold tickets.\r\n * @param tickets The number of tickets, defaults to 1.\r\n * @returns The Lotto instance.\r\n */\r\n Lotto.prototype.add = function (participant, tickets) {\r\n if (tickets === void 0) { tickets = 1; }\r\n // Check that we have a valid ticket count.\r\n if (!(0, Utilities_1.isNaturalNumber)(tickets)) {\r\n throw new Error(\"tickets value must be a natural number\");\r\n }\r\n // Check whether this participant has already been added.\r\n var existingParticipant = this._participants.find(function (part) { return part.participant === participant; });\r\n if (existingParticipant) {\r\n // The participant has already been added to the lotto so just add to their ticket count.\r\n existingParticipant.tickets += tickets;\r\n }\r\n else {\r\n // The participant is not part of the lotto so we should add them.\r\n this._participants.push(new Participant_1.Participant(participant, tickets));\r\n }\r\n return this;\r\n };\r\n /**\r\n * Removes the specified number of tickets for the given participant from the draw, or all tickets if a ticket number is not defined.\r\n * @param participant The participant to remove tickets for.\r\n * @param tickets The number of tickets to remove, or undefined if all tickets are to be removed.\r\n * @returns The Lotto instance.\r\n */\r\n Lotto.prototype.remove = function (participant, tickets) {\r\n // Attempt to get the existing participant.\r\n var existingParticipant = this._participants.find(function (part) { return part.participant === participant; });\r\n // There is nothing to do if the specified participant isn't even part of the lotto.\r\n if (!existingParticipant) {\r\n return this;\r\n }\r\n // Check whether a tickets value was given.\r\n if (tickets !== undefined) {\r\n // Check that we have a valid ticket count.\r\n if (!(0, Utilities_1.isNaturalNumber)(tickets)) {\r\n throw new Error(\"tickets value must be a natural number\");\r\n }\r\n existingParticipant.tickets -= tickets;\r\n // If the participant no longer holds any tickets then they should be removed.\r\n if (existingParticipant.tickets < 1) {\r\n this._participants = this._participants.filter(function (part) { return part !== existingParticipant; });\r\n }\r\n }\r\n else {\r\n // We are removing all tickets for the participant so just remove them from the lotto.\r\n this._participants = this._participants.filter(function (part) { return part !== existingParticipant; });\r\n }\r\n return this;\r\n };\r\n /**\r\n * Draw a winning ticket and return the participant that holds the ticket.\r\n * @param options The draw options.\r\n * @returns The participant that holds the winning ticket.\r\n */\r\n Lotto.prototype.draw = function (options) {\r\n if (options === void 0) { options = {}; }\r\n // If we have no participants then just return null.\r\n if (this._participants.length === 0) {\r\n return null;\r\n }\r\n var redrawable = (0, Utilities_1.isNullOrUndefined)(options.redrawable) ? true : options.redrawable;\r\n var pickable = [];\r\n this._participants.forEach(function (_a) {\r\n var participant = _a.participant, tickets = _a.tickets;\r\n for (var ticketCount = 0; ticketCount < tickets; ticketCount++) {\r\n pickable.push(participant);\r\n }\r\n });\r\n var random;\r\n // We need a random floating-point number between 0 (inclusive) and 1 to scale up to pick our winner.\r\n // If a custom random function exists then we should use that or fall back to Math.random().\r\n if (this._customRandom) {\r\n // Call our custom random function to get a random floating-point number.\r\n random = this._customRandom();\r\n // Verify that the result of calling our custom random function is a number between 0 (inclusive) and 1.\r\n if (typeof random !== \"number\" || random < 0 || random >= 1) {\r\n throw new Error(\"the 'random' function provided did not return a number between 0 (inclusive) and 1\");\r\n }\r\n }\r\n else {\r\n // No custom random function was defined so just use good ol' Math.random().\r\n random = Math.random();\r\n }\r\n // Pick a winning participant.\r\n var winner = pickable[Math.floor(random * pickable.length)];\r\n // If the ticket isn't redrawable then we should remove a ticket from the winning participants ticket count.\r\n if (!redrawable) {\r\n this.remove(winner, 1);\r\n }\r\n // Return the winning participant.\r\n return winner;\r\n };\r\n /**\r\n * Draws multiple winning tickets and return an array of the participants that hold the winning tickets.\r\n * @param tickets The number of winning tickets to draw.\r\n * @param options The draw multiple options.\r\n * @returns An array of the participants that hold the winning tickets.\r\n */\r\n Lotto.prototype.drawMultiple = function (tickets, options) {\r\n if (options === void 0) { options = {}; }\r\n var uniqueResults = (0, Utilities_1.isNullOrUndefined)(options.unique) ? false : options.unique;\r\n // Handle cases where the user has asked for zero tickets (no idea why they would do this be we should trust them).\r\n if (tickets === 0) {\r\n return [];\r\n }\r\n // Now that we know out tickets value is not zero we should check that it is a valid natural number.\r\n if (!(0, Utilities_1.isNaturalNumber)(tickets)) {\r\n throw new Error(\"tickets value must be a natural number\");\r\n }\r\n var result = [];\r\n // Keep drawing tickets until we either reach the number of required tickets or we simply run out of tickets to draw.\r\n // We can run out of tickets to draw if 'options.redrawable' is explicity 'false' or we just had no participants when 'drawMultiple' was called.\r\n while (result.length < tickets && this._participants.length > 0) {\r\n result.push(this.draw(options));\r\n }\r\n // If the 'unique' draw option is set then we need to remove duplicates from the result list.\r\n if (uniqueResults) {\r\n // Create an array to store our unique results.\r\n var unique = [];\r\n // Iterate over all of our participants (with potential duplicates) and populate our array of unique values.\r\n for (var _i = 0, result_1 = result; _i < result_1.length; _i++) {\r\n var participant = result_1[_i];\r\n if (unique.indexOf(participant) === -1) {\r\n unique.push(participant);\r\n }\r\n }\r\n result = unique;\r\n }\r\n return result;\r\n };\r\n return Lotto;\r\n}());\r\nexports.Lotto = Lotto;\r\n", "\"use strict\";\r\nObject.defineProperty(exports, \"__esModule\", { value: true });\r\nexports.createLotto = void 0;\r\nvar Lotto_1 = require(\"./Lotto\");\r\n/**\r\n * A function that creates and returns a Lotto instance.\r\n * @param participantsOrOptions An array of initial participants or options relating to the creation of a Lotto instance.\r\n * @returns A new Lotto instance.\r\n */\r\nfunction createLotto(participantsOrOptions) {\r\n // If no initial participants or lotto options were provided as an argument then we can just return a new lotto instance now.\r\n if (!participantsOrOptions) {\r\n return new Lotto_1.Lotto();\r\n }\r\n // Check whether we were provided with an array of initial participants or a lotto options object.\r\n if (Array.isArray(participantsOrOptions)) {\r\n // We are dealing with a pre-defined array of participants.\r\n var participants = participantsOrOptions;\r\n var lotto_1 = new Lotto_1.Lotto();\r\n // If the lotto participants have been defined upfront then we will need to add them all to our lotto instance now.\r\n participants.forEach(function (_a) {\r\n var participant = _a[0], tokens = _a[1];\r\n return lotto_1.add(participant, tokens);\r\n });\r\n // Return the Lotto instance.\r\n return lotto_1;\r\n }\r\n else {\r\n // We are dealing with some lotto options.\r\n var random = participantsOrOptions.random, participants = participantsOrOptions.participants;\r\n // Create a Lotto instance passing the custom RNG function to use in place of Math.random() (which could be undefined).\r\n var lotto_2 = new Lotto_1.Lotto(random);\r\n // If the lotto participants have been defined upfront as part of the options then we will need to add them all to our lotto instance now.\r\n if (participants) {\r\n participants.forEach(function (_a) {\r\n var participant = _a[0], tokens = _a[1];\r\n return lotto_2.add(participant, tokens);\r\n });\r\n }\r\n // Return the Lotto instance.\r\n return lotto_2;\r\n }\r\n}\r\nexports.createLotto = createLotto;\r\n", "\"use strict\";\r\nObject.defineProperty(exports, \"__esModule\", { value: true });\r\nvar createLotto_1 = require(\"./createLotto\");\r\nexports.default = createLotto_1.createLotto;\r\n", "import State from \"./State\";\nimport { validateDefinition } from \"./BehaviourTreeDefinitionValidator\";\nimport { convertMDSLToJSON } from \"./mdsl/MDSLDefinitionParser\";\nimport { BehaviourTree, FlattenedTreeNode } from \"./BehaviourTree\";\nimport { BehaviourTreeOptions } from \"./BehaviourTreeOptions\";\n\nexport { BehaviourTree, State, convertMDSLToJSON, validateDefinition };\nexport type { FlattenedTreeNode, BehaviourTreeOptions };\n", "/**\n * Enumeration of node state types.\n */\nexport enum State {\n READY = \"mistreevous.ready\",\n RUNNING = \"mistreevous.running\",\n SUCCEEDED = \"mistreevous.succeeded\",\n FAILED = \"mistreevous.failed\"\n}\n\nexport { State as default };\n\nexport type CompleteState = State.SUCCEEDED | State.FAILED;\nexport type AnyState = State.READY | State.RUNNING | CompleteState;\n", "import {\n NodeDefinition,\n RootNodeDefinition,\n DecoratorNodeDefinition,\n CompositeNodeDefinition,\n AnyNodeDefinition,\n BranchNodeDefinition\n} from \"./BehaviourTreeDefinition\";\n\n/**\n * A type guard function that returns true if the specified node satisfies the RootNodeDefinition type.\n * @param node The node.\n * @returns A value of true if the specified node satisfies the RootNodeDefinition type.\n */\nexport function isRootNode(node: NodeDefinition): node is RootNodeDefinition {\n return node.type === \"root\";\n}\n\n/**\n * A type guard function that returns true if the specified node satisfies the BranchNodeDefinition type.\n * @param node The node.\n * @returns A value of true if the specified node satisfies the BranchNodeDefinition type.\n */\nexport function isBranchNode(node: NodeDefinition): node is BranchNodeDefinition {\n return node.type === \"branch\";\n}\n\n/**\n * A type guard function that returns true if the specified node satisfies the NodeDefinition type.\n * @param node The node.\n * @returns A value of true if the specified node satisfies the NodeDefinition type.\n */\nexport function isLeafNode(node: NodeDefinition): node is NodeDefinition {\n return [\"branch\", \"action\", \"condition\", \"wait\"].includes(node.type);\n}\n\n/**\n * A type guard function that returns true if the specified node satisfies the DecoratorNodeDefinition type.\n * @param node The node.\n * @returns A value of true if the specified node satisfies the DecoratorNodeDefinition type.\n */\nexport function isDecoratorNode(node: NodeDefinition): node is DecoratorNodeDefinition {\n return [\"root\", \"repeat\", \"retry\", \"flip\", \"succeed\", \"fail\"].includes(node.type);\n}\n\n/**\n * A type guard function that returns true if the specified node satisfies the CompositeNodeDefinition type.\n * @param node The node.\n * @returns A value of true if the specified node satisfies the CompositeNodeDefinition type.\n */\nexport function isCompositeNode(node: NodeDefinition): node is CompositeNodeDefinition {\n return [\"sequence\", \"selector\", \"lotto\", \"parallel\"].includes(node.type);\n}\n\n/**\n * Flatten a node definition into an array of all of its nested node definitions.\n * @param nodeDefinition The node definition to flatten.\n * @returns An array of all of nested node definitions.\n */\nexport function flattenDefinition(nodeDefinition: AnyNodeDefinition): AnyNodeDefinition[] {\n const nodes: AnyNodeDefinition[] = [];\n\n const processNode = (currentNodeDefinition: AnyNodeDefinition) => {\n nodes.push(currentNodeDefinition);\n\n if (isCompositeNode(currentNodeDefinition)) {\n currentNodeDefinition.children.forEach(processNode);\n } else if (isDecoratorNode(currentNodeDefinition)) {\n processNode(currentNodeDefinition.child);\n }\n };\n\n processNode(nodeDefinition);\n\n return nodes;\n}\n\n/**\n * Determines whether the passed value is an integer.\n * @param value The value to check.\n * @returns Whether the passed value is an integer.\n */\nexport function isInteger(value: unknown): boolean {\n return typeof value === \"number\" && Math.floor(value) === value;\n}\n\n/**\n * Determines whether the passed value is null or undefined.\n * @param value The value to check.\n * @returns Whether the passed value is null or undefined.\n */\nexport function isNullOrUndefined(value: unknown): boolean {\n return typeof value === \"undefined\" || value === null;\n}\n", "/**\n * A type defining an object that holds a reference to substitued string literals parsed from the definition.\n */\nexport type StringLiteralPlaceholders = { [key: string]: string };\n\n/**\n * Pop the next raw token from the specified array of tokens and throw an error if it wasn't the expected one.\n * @param tokens The array of tokens.\n * @param expected An optional string or array or items, one of which must match the next popped token.\n * @returns The popped token.\n */\nexport function popAndCheck(tokens: string[], expected?: string | string[]): string {\n // Get and remove the next token.\n const popped = tokens.shift();\n\n // We were expecting another token but there aren't any.\n if (popped === undefined) {\n throw new Error(\"unexpected end of definition\");\n }\n\n // Do we have an expected token/tokens array?\n if (expected != undefined) {\n // Get an array of expected values, if the popped token matches any then we are all good.\n const expectedValues = typeof expected === \"string\" ? [expected] : expected;\n\n // Check whether the popped token matches at least one of our expected items.\n var tokenMatchesExpectation = expectedValues.some((item) => popped.toUpperCase() === item.toUpperCase());\n\n // Throw an error if the popped token didn't match any of our expected items.\n if (!tokenMatchesExpectation) {\n const expectationString = expectedValues.map((item) => \"'\" + item + \"'\").join(\" or \");\n throw new Error(\"unexpected token found. Expected \" + expectationString + \" but got '\" + popped + \"'\");\n }\n }\n\n // Return the popped token.\n return popped;\n}\n\n/**\n * Swaps out any node/attribute argument string literals with placeholders.\n * @param definition The definition.\n * @returns An object containing a mapping of placeholders to original string values as well as the processed definition string.\n */\nexport function substituteStringLiterals(definition: string): {\n placeholders: StringLiteralPlaceholders;\n processedDefinition: string;\n} {\n // Create an object to hold the mapping of placeholders to original string values.\n const placeholders: StringLiteralPlaceholders = {};\n\n // Replace any string literals wrapped with double quotes in our definition with placeholders to be processed later.\n const processedDefinition = definition.replace(/\\\"(\\\\.|[^\"\\\\])*\\\"/g, (match) => {\n var strippedMatch = match.substring(1, match.length - 1);\n var placeholder = Object.keys(placeholders).find((key) => placeholders[key] === strippedMatch);\n\n // If we have no existing string literal match then create a new placeholder.\n if (!placeholder) {\n placeholder = `@@${Object.keys(placeholders).length}@@`;\n placeholders[placeholder] = strippedMatch;\n }\n\n return placeholder;\n });\n\n return { placeholders, processedDefinition };\n}\n\n/**\n * Parse the tree definition into an array of raw tokens.\n * @param definition The definition.\n * @returns An array of tokens parsed from the definition.\n */\nexport function parseTokensFromDefinition(definition: string): string[] {\n // Add some space around various important characters so that they can be plucked out easier as individual tokens.\n definition = definition.replace(/\\(/g, \" ( \");\n definition = definition.replace(/\\)/g, \" ) \");\n definition = definition.replace(/\\{/g, \" { \");\n definition = definition.replace(/\\}/g, \" } \");\n definition = definition.replace(/\\]/g, \" ] \");\n definition = definition.replace(/\\[/g, \" [ \");\n definition = definition.replace(/\\,/g, \" , \");\n\n // Split the definition into raw token form and return it.\n return definition.replace(/\\s+/g, \" \").trim().split(\" \");\n}\n", "import { StringLiteralPlaceholders, popAndCheck } from \"./MDSLUtilities\";\n\n/**\n * A type representing any node function argument.\n */\ntype Argument = {\n /**\n * The argument value.\n */\n value: T;\n /**\n * The argument type, used for validation.\n */\n type: string;\n};\n\ntype NullArgument = Argument & {\n type: \"null\";\n};\n\ntype BooleanArgument = Argument & {\n type: \"boolean\";\n};\n\ntype NumberArgument = Argument & {\n type: \"number\";\n /**\n * A flag defining whether the number argument value is a valid integer. (used for validation)\n */\n isInteger: boolean;\n};\n\ntype StringPlaceholderArgument = Argument & {\n type: \"string\";\n};\n\ntype IdentifierArgument = Argument & {\n type: \"identifier\";\n};\n\n/**\n * A type representing a reference to any node function argument.\n */\ntype AnyArgument = NullArgument | BooleanArgument | NumberArgument | StringPlaceholderArgument | IdentifierArgument;\n\n/**\n * Parse an array of argument definitions from the specified tokens array.\n * @param tokens The array tokens to parse the argument definitions from.\n * @param stringArgumentPlaceholders The mapping of string literal node argument placeholders to original values.\n * @param argumentValidator The argument validator function.\n * @param validationFailedMessage The exception message to throw if argument validation fails.\n * @returns An array of argument definitions parsed from the specified tokens array.\n */\nexport function parseArgumentTokens(\n tokens: string[],\n stringArgumentPlaceholders: StringLiteralPlaceholders\n): AnyArgument[] {\n const argumentList: AnyArgument[] = [];\n\n // If the next token is not a '[' or '(' then we have no arguments to parse.\n if (![\"[\", \"(\"].includes(tokens[0])) {\n return argumentList;\n }\n\n // Any lists of arguments will always be wrapped in '[]' for node arguments or '()' for attribute arguments.\n // We are looking for a '[' or '(' opener that wraps the argument tokens and the relevant closer.\n const closingToken = popAndCheck(tokens, [\"[\", \"(\"]) === \"[\" ? \"]\" : \")\";\n\n const argumentListTokens: string[] = [];\n\n // Grab all tokens between the '[' and ']' or '(' and ')'.\n while (tokens.length && tokens[0] !== closingToken) {\n // The next token is part of our arguments list.\n argumentListTokens.push(tokens.shift()!);\n }\n\n // Validate the order of the argument tokens. Each token must either be a ',' or a single argument that satisfies the validator.\n argumentListTokens.forEach((token, index) => {\n // Get whether this token should be an actual argument.\n const shouldBeArgumentToken = !(index & 1);\n\n // If the current token should be an actual argument then validate it, otherwise it should be a ',' token.\n if (shouldBeArgumentToken) {\n // Get the argument definition.\n const argumentDefinition = getArgumentDefinition(token, stringArgumentPlaceholders);\n\n // This is a valid argument!\n argumentList.push(argumentDefinition);\n } else {\n // The current token should be a ',' token.\n if (token !== \",\") {\n throw new Error(`invalid argument list, expected ',' or ']' but got '${token}'`);\n }\n }\n });\n\n // The arguments list should terminate with a ']' or ')' token, depending on the opener.\n popAndCheck(tokens, closingToken);\n\n // Return the arguments.\n return argumentList;\n}\n\n/**\n * Gets an argument value definition.\n * @param token The argument token.\n * @param stringArgumentPlaceholders The mapping of string literal node argument placeholders to original values.\n * @returns An argument value definition.\n */\nfunction getArgumentDefinition(token: string, stringArgumentPlaceholders: StringLiteralPlaceholders): AnyArgument {\n // Check whether the token represents a null value.\n if (token === \"null\") {\n return {\n value: null,\n type: \"null\"\n } as NullArgument;\n }\n\n // Check whether the token represents a boolean value.\n if (token === \"true\" || token === \"false\") {\n return {\n value: token === \"true\",\n type: \"boolean\"\n } as BooleanArgument;\n }\n\n // Check whether the token represents a number value.\n // TODO: Relies on broken isNaN - see MDN.\n // if (!Number.isNaN(token)) {\n if (!isNaN(token as any)) {\n return {\n value: parseFloat(token),\n isInteger: parseFloat(token) === parseInt(token, 10),\n type: \"number\"\n } as NumberArgument;\n }\n\n // Check whether the token is a placeholder (e.g. @@0@@) representing a string literal.\n if (token.match(/^@@\\d+@@$/g)) {\n return {\n value: stringArgumentPlaceholders[token].replace('\\\\\"', '\"'),\n type: \"string\"\n } as StringPlaceholderArgument;\n }\n\n // The only remaining option is that the argument value is an identifier.\n return {\n value: token,\n type: \"identifier\"\n } as IdentifierArgument;\n}\n", "import { NodeAttributeDefinition } from \"../BehaviourTreeDefinition\";\nimport { parseArgumentTokens } from \"./MDSLNodeArgumentParser\";\nimport { StringLiteralPlaceholders } from \"./MDSLUtilities\";\n\n/**\n * A type defining the attribute definitions of a node.\n */\ntype NodeAttributes = {\n while?: NodeAttributeDefinition;\n until?: NodeAttributeDefinition;\n entry?: NodeAttributeDefinition;\n exit?: NodeAttributeDefinition;\n step?: NodeAttributeDefinition;\n};\n\n/**\n * Parse any node attribute definitions from the specified tokens array.\n * @param tokens The array of remaining tokens.\n * @param stringArgumentPlaceholders The mapping of string literal node argument placeholders to original values.\n * @returns An object of attribute definitions defined by any directly following tokens.\n */\nexport function parseAttributeTokens(\n tokens: string[],\n stringArgumentPlaceholders: StringLiteralPlaceholders\n): NodeAttributes {\n const nodeAttributeNames: (keyof NodeAttributes)[] = [\"while\", \"until\", \"entry\", \"exit\", \"step\"];\n\n // Create an object to hold any attributes found.\n const attributes: NodeAttributes = {};\n\n // Try to get the name of the attribute for the next token.\n let nextAttributeName = tokens[0]?.toLowerCase() as keyof NodeAttributes;\n\n // Pull attribute tokens as well as their arguments off of the tokens stack until we have no more.\n while (nodeAttributeNames.includes(nextAttributeName)) {\n // Check to make sure that we have not already created an attribute definition of this type.\n if (attributes[nextAttributeName]) {\n throw new Error(`duplicate attribute '${tokens[0].toUpperCase()}' found for node`);\n }\n\n // Remove the attribute name token from the array of tokens.\n tokens.shift();\n\n // Grab the attribute arguments, assuming the first to be an identifier.\n const [attributeCallIdentifier, ...attributeArguments] = parseArgumentTokens(\n tokens,\n stringArgumentPlaceholders\n );\n\n // The first attribute argument has to be an identifer, this will reference an agent function.\n if (attributeCallIdentifier?.type !== \"identifier\") {\n throw new Error(\"expected agent function name identifier argument for attribute\");\n }\n\n // Any attribute arguments (other than the expected call identifier) must have a type of string, number, boolean or null.\n attributeArguments\n .filter((arg) => arg.type === \"identifier\")\n .forEach((arg) => {\n throw new Error(\n `invalid attribute argument value '${arg.value}', must be string, number, boolean or null`\n );\n });\n\n // Create the attribute definition and add it to the object of attribute definitions found.\n attributes[nextAttributeName] = {\n call: attributeCallIdentifier.value,\n args: attributeArguments.map(({ value }) => value)\n };\n\n // Try to get the next attribute name token, as there could be multiple.\n nextAttributeName = tokens[0]?.toLowerCase() as keyof NodeAttributes;\n }\n\n return attributes;\n}\n", "import {\n ActionNodeDefinition,\n AnyChildNodeDefinition,\n AnyNodeDefinition,\n BranchNodeDefinition,\n ConditionNodeDefinition,\n FailNodeDefinition,\n FlipNodeDefinition,\n LottoNodeDefinition,\n ParallelNodeDefinition,\n RepeatNodeDefinition,\n RetryNodeDefinition,\n RootNodeDefinition,\n SelectorNodeDefinition,\n SequenceNodeDefinition,\n SucceedNodeDefinition,\n WaitNodeDefinition\n} from \"../BehaviourTreeDefinition\";\nimport {\n isCompositeNode,\n isDecoratorNode,\n isLeafNode,\n isNullOrUndefined,\n isRootNode\n} from \"../BehaviourTreeDefinitionUtilities\";\nimport { parseArgumentTokens } from \"./MDSLNodeArgumentParser\";\nimport { parseAttributeTokens } from \"./MDSLNodeAttributeParser\";\nimport {\n StringLiteralPlaceholders,\n parseTokensFromDefinition,\n popAndCheck,\n substituteStringLiterals\n} from \"./MDSLUtilities\";\n\n/**\n * Convert the MDSL tree definition string into an equivalent JSON definition.\n * @param definition The tree definition string as MDSL.\n * @returns The root node JSON definitions.\n */\nexport function convertMDSLToJSON(definition: string): RootNodeDefinition[] {\n // Swap out any node/attribute argument string literals with a placeholder and get a mapping of placeholders to original values as well as the processed definition.\n const { placeholders, processedDefinition } = substituteStringLiterals(definition);\n\n // Parse our definition definition string into an array of raw tokens.\n const tokens = parseTokensFromDefinition(processedDefinition);\n\n return convertTokensToJSONDefinition(tokens, placeholders);\n}\n\n/**\n * Converts the specified tree definition tokens into a JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The root node JSON definitions.\n */\nfunction convertTokensToJSONDefinition(\n tokens: string[],\n stringLiteralPlaceholders: StringLiteralPlaceholders\n): RootNodeDefinition[] {\n // There must be at least 3 tokens for the tree definition to be valid. 'ROOT', '{' and '}'.\n if (tokens.length < 3) {\n throw new Error(\"invalid token count\");\n }\n\n // We should have a matching number of '{' and '}' tokens. If not, then there are scopes that have not been properly closed.\n if (tokens.filter((token) => token === \"{\").length !== tokens.filter((token) => token === \"}\").length) {\n throw new Error(\"scope character mismatch\");\n }\n\n // Create an array of tree stack arrays where root nodes will always be at the botton and the current composite/decorator node at the top.\n // There should be an element in this array for every root node defined and every element should be an array with a root note as the first element.\n // E.g. A definition with two root nodes defined:\n // [\n // [root, lotto, sequence],\n // [root, selector]\n // ]\n const treeStacks: [Partial, ...Partial[]][] = [];\n\n // Create an array of all root node definitions that we create.\n const rootNodes: Partial[] = [];\n\n // A helper function used to push node definitions onto the tree stack.\n const pushNode = (node: AnyNodeDefinition) => {\n // If the node is a root node then we need to create a new tree stack array with the root node at the root.\n if (isRootNode(node)) {\n // We need to double-check that this root node is not the child of another node.\n // We can do this by checking whether the top tree stack is not empty (contains an existing node)\n if (treeStacks[treeStacks.length - 1]?.length) {\n throw new Error(\"a root node cannot be the child of another node\");\n }\n\n // Add the root node definition to our array of all parsed root node definitions.\n rootNodes.push(node);\n\n // Add the root node definition to the root of a new tree stack.\n treeStacks.push([node]);\n\n return;\n }\n\n // All non-root nodes should be pushed after their root nodes so handle cases\n // where we may not have any tree stacks or our top-most tree stack is empty.\n if (!treeStacks.length || !treeStacks[treeStacks.length - 1].length) {\n throw new Error(\"expected root node at base of definition\");\n }\n\n // Get the current tree stack that we are populating.\n const topTreeStack = treeStacks[treeStacks.length - 1];\n\n // Get the top-most node in the current tree stack, this will be a composite/decorator node\n // for which we will populate its children array if composite or setting its child if a decorator.\n const topTreeStackTopNode = topTreeStack[topTreeStack.length - 1] as AnyNodeDefinition;\n\n // If the top-most node in the current root stack is a composite or decorator\n // node then the current node should be added as a child of the top-most node.\n if (isCompositeNode(topTreeStackTopNode)) {\n topTreeStackTopNode.children = topTreeStackTopNode.children || [];\n topTreeStackTopNode.children.push(node);\n } else if (isDecoratorNode(topTreeStackTopNode)) {\n // If the top node already has a child node set then throw an error as a decorator should only have a single child.\n if (topTreeStackTopNode.child) {\n throw new Error(\"a decorator node must only have a single child node\");\n }\n\n topTreeStackTopNode.child = node;\n }\n\n // If the node we are adding is also a composite or decorator node, then we should push it\n // onto the current tree stack, as subsequent nodes will be added as its child/children.\n if (!isLeafNode(node)) {\n topTreeStack.push(node);\n }\n };\n\n // A helper function used to pop the top-most node definition off of the tree stack and return it.\n const popNode = (): AnyNodeDefinition | null => {\n let poppedNode: AnyNodeDefinition | null = null;\n\n // Get the current tree stack that we are populating.\n const topTreeStack = treeStacks[treeStacks.length - 1];\n\n // Pop the top-most node in the current tree stack if there is one.\n if (topTreeStack.length) {\n poppedNode = topTreeStack.pop() as AnyNodeDefinition;\n }\n\n // We don't want any empty tree stacks in our stack of tree stacks.\n if (!topTreeStack.length) {\n treeStacks.pop();\n }\n\n return poppedNode;\n };\n\n // We should keep processing the raw tokens until we run out of them.\n while (tokens.length) {\n // Grab the next token.\n const token = tokens.shift()!;\n\n // How we create the next node depends on the current raw token value.\n switch (token.toUpperCase()) {\n case \"ROOT\": {\n pushNode(createRootNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"SUCCEED\": {\n pushNode(createSucceedNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"FAIL\": {\n pushNode(createFailNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"FLIP\": {\n pushNode(createFlipNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"REPEAT\": {\n pushNode(createRepeatNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"RETRY\": {\n pushNode(createRetryNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"SEQUENCE\": {\n pushNode(createSequenceNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"SELECTOR\": {\n pushNode(createSelectorNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"PARALLEL\": {\n pushNode(createParallelNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"LOTTO\": {\n pushNode(createLottoNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"ACTION\": {\n pushNode(createActionNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"CONDITION\": {\n pushNode(createConditionNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"WAIT\": {\n pushNode(createWaitNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"BRANCH\": {\n pushNode(createBranchNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"}\": {\n // The '}' character closes the current scope and means that we have to pop a node off of the current stack.\n const poppedNode = popNode();\n\n // Now that we have a node definition we can carry out any validation that may require the node to be fully populated.\n if (poppedNode) {\n validatePoppedNode(poppedNode);\n }\n\n break;\n }\n\n default: {\n throw new Error(`unexpected token: ${token}`);\n }\n }\n }\n\n return rootNodes as RootNodeDefinition[];\n}\n\n/**\n * Creates a root node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The root node JSON definition.\n */\nfunction createRootNode(tokens: string[], stringLiteralPlaceholders: StringLiteralPlaceholders): RootNodeDefinition {\n // Create the root node definition.\n let node = {\n type: \"root\",\n id: undefined\n } as RootNodeDefinition;\n\n // Parse any node arguments, we should only have one if any which will be an identifier argument for the root identifier.\n const nodeArguments = parseArgumentTokens(tokens, stringLiteralPlaceholders);\n\n // Check whether any node arguments were defined.\n if (nodeArguments.length) {\n // We should only have one argument, if any, which will be an identifier argument for the root identifier.\n if (nodeArguments.length === 1 && nodeArguments[0].type === \"identifier\") {\n // The root node identifier will be the first and only node argument value.\n node.id = nodeArguments[0].value as string;\n } else {\n throw new Error(\"expected single root name argument\");\n }\n }\n\n // Grab any node attribute definitions and spread them into the node definition.\n node = { ...node, ...parseAttributeTokens(tokens, stringLiteralPlaceholders) };\n\n // This is a decorator node, so we expect an opening '{'.\n popAndCheck(tokens, \"{\");\n\n // Return the root node definition.\n return node;\n}\n\n/**\n * Creates a succeed node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The succeed node JSON definition.\n */\nfunction createSucceedNode(\n tokens: string[],\n stringLiteralPlaceholders: StringLiteralPlaceholders\n): SucceedNodeDefinition {\n const node = {\n type: \"succeed\",\n ...parseAttributeTokens(tokens, stringLiteralPlaceholders)\n } as SucceedNodeDefinition;\n\n // This is a decorator node, so we expect an opening '{'.\n popAndCheck(tokens, \"{\");\n\n // Return the succeed node definition.\n return node;\n}\n\n/**\n * Creates a fail node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The fail node JSON definition.\n */\nfunction createFailNode(tokens: string[], stringLiteralPlaceholders: StringLiteralPlaceholders): FailNodeDefinition {\n const node = {\n type: \"fail\",\n ...parseAttributeTokens(tokens, stringLiteralPlaceholders)\n } as FailNodeDefinition;\n\n // This is a decorator node, so we expect an opening '{'.\n popAndCheck(tokens, \"{\");\n\n // Return the fail node definition.\n return node;\n}\n\n/**\n * Creates a flip node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The flip node JSON definition.\n */\nfunction createFlipNode(tokens: string[], stringLiteralPlaceholders: StringLiteralPlaceholders): FlipNodeDefinition {\n const node = {\n type: \"flip\",\n ...parseAttributeTokens(tokens, stringLiteralPlaceholders)\n } as FlipNodeDefinition;\n\n // This is a decorator node, so we expect an opening '{'.\n popAndCheck(tokens, \"{\");\n\n // Return the flip node definition.\n return node;\n}\n\n/**\n * Creates a repeat node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The repeat node JSON definition.\n */\nfunction createRepeatNode(\n tokens: string[],\n stringLiteralPlaceholders: StringLiteralPlaceholders\n): RepeatNodeDefinition {\n let node = { type: \"repeat\" } as RepeatNodeDefinition;\n\n // Get the node arguments.\n const nodeArguments = parseArgumentTokens(tokens, stringLiteralPlaceholders);\n\n // The arguments of a repeat node are optional. We may have:\n // - No node arguments, in which case the repeat note will iterate indefinitely.\n // - One node argument which will be the explicit number of iterations to make.\n // - Two node arguments which define the min and max iteration bounds from which a random iteration count will be picked.\n if (nodeArguments.length) {\n // All repeat node arguments MUST be of type number and must be integer.\n nodeArguments\n .filter((arg) => arg.type !== \"number\" || !arg.isInteger)\n .forEach(() => {\n throw new Error(`repeat node iteration counts must be integer values`);\n });\n\n // We should have got one or two iteration counts.\n if (nodeArguments.length === 1) {\n // A static iteration count was defined.\n node.iterations = nodeArguments[0].value as number;\n\n // A repeat node must have a positive number of iterations if defined.\n if (node.iterations < 0) {\n throw new Error(\"a repeat node must have a positive number of iterations if defined\");\n }\n } else if (nodeArguments.length === 2) {\n // A minimum and maximum iteration count was defined.\n node.iterations = [nodeArguments[0].value as number, nodeArguments[1].value as number];\n\n // A repeat node must have a positive min and max iteration count if they are defined.\n if (node.iterations[0] < 0 || node.iterations[1] < 0) {\n throw new Error(\"a repeat node must have a positive minimum and maximum iteration count if defined\");\n }\n\n // A repeat node must not have an minimum iteration count that exceeds the maximum iteration count.\n if (node.iterations[0] > node.iterations[1]) {\n throw new Error(\n \"a repeat node must not have a minimum iteration count that exceeds the maximum iteration count\"\n );\n }\n } else {\n // An incorrect number of iteration counts was defined.\n throw new Error(\"invalid number of repeat node iteration count arguments defined\");\n }\n }\n\n // Grab any node attribute definitions and spread them into the node definition.\n node = { ...node, ...parseAttributeTokens(tokens, stringLiteralPlaceholders) };\n\n // This is a decorator node, so we expect an opening '{'.\n popAndCheck(tokens, \"{\");\n\n // Return the repeat node definition.\n return node;\n}\n\n/**\n * Creates a retry node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The retry node JSON definition.\n */\nfunction createRetryNode(tokens: string[], stringLiteralPlaceholders: StringLiteralPlaceholders): RetryNodeDefinition {\n let node = { type: \"retry\" } as RetryNodeDefinition;\n\n // Get the node arguments.\n const nodeArguments = parseArgumentTokens(tokens, stringLiteralPlaceholders);\n\n // The arguments of a retry node are optional. We may have:\n // - No node arguments, in which case the retry note will attempt indefinitely.\n // - One node argument which will be the explicit number of attempts to make.\n // - Two node arguments which define the min and max attempt bounds from which a random attempt count will be picked.\n if (nodeArguments.length) {\n // All retry node arguments MUST be of type number and must be integer.\n nodeArguments\n .filter((arg) => arg.type !== \"number\" || !arg.isInteger)\n .forEach(() => {\n throw new Error(`retry node attempt counts must be integer values`);\n });\n\n // We should have got one or two attempt counts.\n if (nodeArguments.length === 1) {\n // A static attempt count was defined.\n node.attempts = nodeArguments[0].value as number;\n\n // A retry node must have a positive number of attempts if defined.\n if (node.attempts < 0) {\n throw new Error(\"a retry node must have a positive number of attempts if defined\");\n }\n } else if (nodeArguments.length === 2) {\n // A minimum and maximum attempt count was defined.\n node.attempts = [nodeArguments[0].value as number, nodeArguments[1].value as number];\n\n // A retry node must have a positive min and max attempts count if they are defined.\n if (node.attempts[0] < 0 || node.attempts[1] < 0) {\n throw new Error(\"a retry node must have a positive minimum and maximum attempt count if defined\");\n }\n\n // A retry node must not have a minimum attempt count that exceeds the maximum attempt count.\n if (node.attempts[0] > node.attempts[1]) {\n throw new Error(\n \"a retry node must not have a minimum attempt count that exceeds the maximum attempt count\"\n );\n }\n } else {\n // An incorrect number of attempt counts was defined.\n throw new Error(\"invalid number of retry node attempt count arguments defined\");\n }\n }\n\n // Grab any node attribute definitions and spread them into the node definition.\n node = { ...node, ...parseAttributeTokens(tokens, stringLiteralPlaceholders) };\n\n // This is a decorator node, so we expect an opening '{'.\n popAndCheck(tokens, \"{\");\n\n // Return the retry node definition.\n return node;\n}\n\n/**\n * Creates a sequence node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The sequence node JSON definition.\n */\nfunction createSequenceNode(\n tokens: string[],\n stringLiteralPlaceholders: StringLiteralPlaceholders\n): SequenceNodeDefinition {\n const node = {\n type: \"sequence\",\n ...parseAttributeTokens(tokens, stringLiteralPlaceholders)\n } as SequenceNodeDefinition;\n\n // This is a composite node, so we expect an opening '{'.\n popAndCheck(tokens, \"{\");\n\n // Return the sequence node definition.\n return node;\n}\n\n/**\n * Creates a selector node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The selector node JSON definition.\n */\nfunction createSelectorNode(\n tokens: string[],\n stringLiteralPlaceholders: StringLiteralPlaceholders\n): SelectorNodeDefinition {\n const node = {\n type: \"selector\",\n ...parseAttributeTokens(tokens, stringLiteralPlaceholders)\n } as SelectorNodeDefinition;\n\n // This is a composite node, so we expect an opening '{'.\n popAndCheck(tokens, \"{\");\n\n // Return the selector node definition.\n return node;\n}\n\n/**\n * Creates a parallel node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The parallel node JSON definition.\n */\nfunction createParallelNode(\n tokens: string[],\n stringLiteralPlaceholders: StringLiteralPlaceholders\n): ParallelNodeDefinition {\n const node = {\n type: \"parallel\",\n ...parseAttributeTokens(tokens, stringLiteralPlaceholders)\n } as ParallelNodeDefinition;\n\n // This is a composite node, so we expect an opening '{'.\n popAndCheck(tokens, \"{\");\n\n // Return the parallel node definition.\n return node;\n}\n\n/**\n * Creates a lotto node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The lotto node JSON definition.\n */\nfunction createLottoNode(tokens: string[], stringLiteralPlaceholders: StringLiteralPlaceholders): LottoNodeDefinition {\n // If any node arguments have been defined then they must be our weights.\n const nodeArguments = parseArgumentTokens(tokens, stringLiteralPlaceholders);\n\n // All lotto node arguments MUST be of type number and must be positive integers.\n nodeArguments\n .filter((arg) => arg.type !== \"number\" || !arg.isInteger || arg.value < 0)\n .forEach(() => {\n throw new Error(`lotto node weight arguments must be positive integer values`);\n });\n\n const node = {\n type: \"lotto\",\n weights: nodeArguments.length ? nodeArguments.map(({ value }) => value) : undefined,\n ...parseAttributeTokens(tokens, stringLiteralPlaceholders)\n } as LottoNodeDefinition;\n\n // This is a composite node, so we expect an opening '{'.\n popAndCheck(tokens, \"{\");\n\n // Return the lotto node definition.\n return node;\n}\n\n/**\n * Creates an action node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The action node JSON definition.\n */\nfunction createActionNode(\n tokens: string[],\n stringLiteralPlaceholders: StringLiteralPlaceholders\n): ActionNodeDefinition {\n // Parse any node arguments, we should have at least one which will be an identifier argument for the action name\n // and agent function to invoke for the action, all other arguments are to be passed as arguments to that function.\n const [actionNameIdentifier, ...agentFunctionArgs] = parseArgumentTokens(tokens, stringLiteralPlaceholders);\n\n // Our first argument MUST be defined and be an identifier as we require an action name argument.\n if (actionNameIdentifier?.type !== \"identifier\") {\n throw new Error(\"expected action name identifier argument\");\n }\n\n // Only the first argument should have been an identifier, all agent function arguments must be string, number, boolean or null.\n agentFunctionArgs\n .filter((arg) => arg.type === \"identifier\")\n .forEach((arg) => {\n throw new Error(\n `invalid action node argument value '${arg.value}', must be string, number, boolean or null`\n );\n });\n\n // Return the action node definition.\n return {\n type: \"action\",\n call: actionNameIdentifier.value,\n args: agentFunctionArgs.map(({ value }) => value),\n ...parseAttributeTokens(tokens, stringLiteralPlaceholders)\n };\n}\n\n/**\n * Creates a condition node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The condition node JSON definition.\n */\nfunction createConditionNode(\n tokens: string[],\n stringLiteralPlaceholders: StringLiteralPlaceholders\n): ConditionNodeDefinition {\n // Parse any node arguments, we should have at least one which will be an identifier argument for the condition name\n // and agent function to invoke for the condition, all other arguments are to be passed as arguments to that function.\n const [conditionNameIdentifier, ...agentFunctionArgs] = parseArgumentTokens(tokens, stringLiteralPlaceholders);\n\n // Our first argument MUST be defined and be an identifier as we require a condition name argument.\n if (conditionNameIdentifier?.type !== \"identifier\") {\n throw new Error(\"expected condition name identifier argument\");\n }\n\n // Only the first argument should have been an identifier, all agent function arguments must be string, number, boolean or null.\n agentFunctionArgs\n .filter((arg) => arg.type === \"identifier\")\n .forEach((arg) => {\n throw new Error(\n `invalid condition node argument value '${arg.value}', must be string, number, boolean or null`\n );\n });\n\n // Return the condition node definition.\n return {\n type: \"condition\",\n call: conditionNameIdentifier.value,\n args: agentFunctionArgs.map(({ value }) => value),\n ...parseAttributeTokens(tokens, stringLiteralPlaceholders)\n };\n}\n\n/**\n * Creates a wait node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The wait node JSON definition.\n */\nfunction createWaitNode(tokens: string[], stringLiteralPlaceholders: StringLiteralPlaceholders): WaitNodeDefinition {\n let node = { type: \"wait\" } as WaitNodeDefinition;\n\n // Get the node arguments.\n const nodeArguments = parseArgumentTokens(tokens, stringLiteralPlaceholders);\n\n // The arguments of a wait node are optional. We may have:\n // - No node arguments, in which case the wait will be indefinite until it is aborted.\n // - One node argument which will be the explicit duration of the wait.\n // - Two node arguments which define the min and max duration bounds from which a random duration will be picked.\n if (nodeArguments.length) {\n // All wait node arguments MUST be of type number and must be integer.\n nodeArguments\n .filter((arg) => arg.type !== \"number\" || !arg.isInteger)\n .forEach(() => {\n throw new Error(`wait node durations must be integer values`);\n });\n\n // We may have:\n // - One node argument which will be the explicit duration of the wait.\n // - Two node arguments which define the min and max duration bounds from which a random duration will be picked.\n // - Too many arguments, which is not valid.\n if (nodeArguments.length === 1) {\n // An explicit duration was defined.\n node.duration = nodeArguments[0].value as number;\n\n // If an explict duration was defined then it must be a positive number.\n if (node.duration < 0) {\n throw new Error(\"a wait node must have a positive duration\");\n }\n } else if (nodeArguments.length === 2) {\n // Min and max duration bounds were defined from which a random duration will be picked.\n node.duration = [nodeArguments[0].value as number, nodeArguments[1].value as number];\n\n // A wait node must have a positive min and max duration.\n if (node.duration[0] < 0 || node.duration[1] < 0) {\n throw new Error(\"a wait node must have a positive minimum and maximum duration\");\n }\n\n // A wait node must not have a minimum duration that exceeds the maximum duration.\n if (node.duration[0] > node.duration[1]) {\n throw new Error(\"a wait node must not have a minimum duration that exceeds the maximum duration\");\n }\n } else if (nodeArguments.length > 2) {\n // An incorrect number of duration arguments were defined.\n throw new Error(\"invalid number of wait node duration arguments defined\");\n }\n }\n\n // Return the wait node definition.\n return { ...node, ...parseAttributeTokens(tokens, stringLiteralPlaceholders) };\n}\n\n/**\n * Creates a branch node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The branch node JSON definition.\n */\nfunction createBranchNode(\n tokens: string[],\n stringLiteralPlaceholders: StringLiteralPlaceholders\n): BranchNodeDefinition {\n // Parse any node arguments, we should have one which will be an identifier argument for the root ref.\n const nodeArguments = parseArgumentTokens(tokens, stringLiteralPlaceholders);\n\n // We should have only a single identifer argument for a branch node, which is the root ref.\n if (nodeArguments.length !== 1 || nodeArguments[0].type !== \"identifier\") {\n throw new Error(\"expected single branch name argument\");\n }\n\n // Return the branch node definition.\n return { type: \"branch\", ref: nodeArguments[0].value };\n}\n\n/**\n * Validate a fully-populated node definition that was popped off of the tree stack.\n * @param definition The popped node to validate.\n */\nfunction validatePoppedNode(definition: AnyNodeDefinition): void {\n // Decorators MUST have a child defined.\n if (isDecoratorNode(definition) && isNullOrUndefined(definition.child)) {\n throw new Error(`a ${definition.type} node must have a single child node defined`);\n }\n\n // Composites MUST have at least one child defined.\n if (isCompositeNode(definition) && !definition.children?.length) {\n throw new Error(`a ${definition.type} node must have at least a single child node defined`);\n }\n\n // We need to make sure that lotto nodes that have weights defined have a number of weights matching the number of child nodes.\n if (definition.type === \"lotto\") {\n // Check whether a 'weights' property has been defined, if it has we expect it to be an array of weights.\n if (typeof definition.weights !== \"undefined\") {\n // Check that the weights property is an array of positive integers with an element for each child node element.\n if (definition.weights.length !== definition.children.length) {\n throw new Error(\n \"expected a number of weight arguments matching the number of child nodes for lotto node\"\n );\n }\n }\n }\n}\n", "import { RootNodeDefinition } from \"./BehaviourTreeDefinition\";\nimport { flattenDefinition, isBranchNode, isInteger } from \"./BehaviourTreeDefinitionUtilities\";\nimport { convertMDSLToJSON } from \"./mdsl/MDSLDefinitionParser\";\n\n/**\n * An object representing the result of validating a tree definition.\n */\nexport type DefinitionValidationResult = {\n /**\n * A flag defining whether validation succeeded.\n */\n succeeded: boolean;\n /**\n * A string containing the error message if validation did not succeed.\n */\n errorMessage?: string;\n /**\n * The definition as json if the validation was successful, or undefined if validation did not succeed.\n */\n json?: RootNodeDefinition[];\n};\n\n/**\n * Validates the specified behaviour tree definition in the form of JSON or MDSL, not taking any globally registered subtrees into consideration.\n * @param definition The behaviour tree definition in the form of JSON or MDSL.\n * @returns An object representing the result of validating the given tree definition.\n */\nexport function validateDefinition(definition: any): DefinitionValidationResult {\n // The definition must be defined.\n if (definition === null || typeof definition === \"undefined\") {\n return createValidationFailureResult(\"definition is null or undefined\");\n }\n\n // We are expecting a definition in one of three different forms:\n // - A string which we will assume is MDSL and we will parse this to JSON before validation.\n // - An array which we will assume is an array of root node definitions with at least one being the primary root node (no 'id' property)\n // - An object which we will assume is the primary root node and should not have an 'id' property.\n if (typeof definition === \"string\") {\n // The definition is a string which we can assume is MDSL, so attempt to validate it.\n return validateMDSLDefinition(definition);\n } else if (typeof definition === \"object\") {\n // The definition will either be an array (of root node definitions) or an object (the single primary root node definition).\n return validateJSONDefinition(definition);\n } else {\n return createValidationFailureResult(`unexpected definition type of '${typeof definition}'`);\n }\n}\n\n/**\n * Validates the specified behaviour tree definition in the form of MDSL.\n * @param definition The behaviour tree definition in the form of MDSL.\n * @returns An object representing the result of validating the given tree definition.\n */\nfunction validateMDSLDefinition(definition: string): DefinitionValidationResult {\n let rootNodeDefinitions;\n\n // The first thing the we need to do is to attempt to convert our MDSL into JSON.\n try {\n // The definition is a string which we can assume is MDSL, so attempt to parse it to a JSON definition in the form of an array of root node definitions.\n rootNodeDefinitions = convertMDSLToJSON(definition);\n } catch (exception) {\n // We failed to parse the JSON from the MDSL, this is likely to be the result of it not being a valid MDSL string.\n return createValidationFailureResult((exception as Error).message);\n }\n\n // Unpack all of the root node definitions into arrays of main ('id' defined) and sub ('id' not defined) root node definitions.\n const mainRootNodeDefinitions = rootNodeDefinitions.filter(({ id }) => typeof id === \"undefined\");\n const subRootNodeDefinitions = rootNodeDefinitions.filter(({ id }) => typeof id === \"string\" && id.length > 0);\n\n // We should ALWAYS have exactly one root node definition without an 'id' property defined, which is out main root node definition.\n if (mainRootNodeDefinitions.length !== 1) {\n return createValidationFailureResult(\n \"expected single unnamed root node at base of definition to act as main root\"\n );\n }\n\n // We should never have duplicate 'id' properties across our sub root node definitions.\n const subRootNodeIdenitifers: string[] = [];\n for (const { id } of subRootNodeDefinitions) {\n // Have we already come across this 'id' property value?\n if (subRootNodeIdenitifers.includes(id!)) {\n return createValidationFailureResult(`multiple root nodes found with duplicate name '${id}'`);\n }\n\n subRootNodeIdenitifers.push(id!);\n }\n\n try {\n // Validate our branch -> subtree links and check for any circular dependencies, we don't care about checking for broken subtree links here.\n validateBranchSubtreeLinks(rootNodeDefinitions, false);\n } catch (exception) {\n return createValidationFailureResult((exception as Error).message);\n }\n\n // Our definition was valid!\n return {\n succeeded: true,\n json: rootNodeDefinitions\n };\n}\n\n/**\n * Validates the specified behaviour tree definition in the form of JSON.\n * @param definition The behaviour tree definition in the form of JSON.\n * @returns An object representing the result of validating the given tree definition.\n */\nexport function validateJSONDefinition(\n definition: RootNodeDefinition | RootNodeDefinition[]\n): DefinitionValidationResult {\n // The definition will either be an array (of root node definitions) or an object (the single primary root node definition).\n const rootNodeDefinitions = Array.isArray(definition) ? definition : [definition];\n\n // Iterate over our array of root nodes and call validateNode for each, passing an initial depth of 0, wrapped in a try catch to handle validation failures.\n try {\n rootNodeDefinitions.forEach((rootNodeDefinition) => validateNode(rootNodeDefinition, 0));\n } catch (error) {\n // Handle cases where we have caught a thrown Error and return a failure result with the error message.\n if (error instanceof Error) {\n return createValidationFailureResult(error.message);\n }\n\n // No idea what happened here!\n return createValidationFailureResult(`unexpected error: ${error}`);\n }\n\n // Unpack all of the root node definitions into arrays of main ('id' defined) and sub ('id' not defined) root node definitions.\n const mainRootNodeDefinitions = rootNodeDefinitions.filter(({ id }) => typeof id === \"undefined\");\n const subRootNodeDefinitions = rootNodeDefinitions.filter(({ id }) => typeof id === \"string\" && id.length > 0);\n\n // We should ALWAYS have exactly one root node definition without an 'id' property defined, which is out main root node definition.\n if (mainRootNodeDefinitions.length !== 1) {\n return createValidationFailureResult(\n \"expected single root node without 'id' property defined to act as main root\"\n );\n }\n\n // We should never have duplicate 'id' properties across our sub root node definitions.\n const subRootNodeIdenitifers: string[] = [];\n for (const { id } of subRootNodeDefinitions) {\n // Have we already come across this 'id' property value?\n if (subRootNodeIdenitifers.includes(id!)) {\n return createValidationFailureResult(\n `multiple root nodes found with duplicate 'id' property value of '${id}'`\n );\n }\n\n subRootNodeIdenitifers.push(id!);\n }\n\n try {\n // Validate our branch -> subtree links and check for any circular dependencies, we don't care about checking for broken subtree links here.\n validateBranchSubtreeLinks(rootNodeDefinitions, false);\n } catch (exception) {\n return createValidationFailureResult((exception as Error).message);\n }\n\n // Our definition was valid!\n return {\n succeeded: true,\n json: rootNodeDefinitions\n };\n}\n\n/**\n * Validates the branch -> subtree links across all provided root node definitions.\n * This will not consider branch nodes that reference any globally registered subtrees unless includesGlobalSubtrees\n * is set to true, in which case we will also verify that there are no broken branch -> subtree links.\n * @param rootNodeDefinitions The array of root node definitions.\n * @param includesGlobalSubtrees A flag defining whether the array includes all global subtree root node definitions.\n */\nexport function validateBranchSubtreeLinks(rootNodeDefinitions: RootNodeDefinition[], includesGlobalSubtrees: boolean) {\n // Create a mapping of root node identifiers to other root nodes that they reference via branch nodes.\n // Below is an example of a mapping that includes a circular dependency (root => a => b => c => a)\n // [{ refs: [\"a\", \"b\"] }, { id: \"a\", refs: [\"b\"] }, { id: \"b\", refs: [\"c\"] }, { id: \"c\", refs: [\"a\"] }]\n const rootNodeMappings: { id: string | undefined; refs: string[] }[] = rootNodeDefinitions.map(\n (rootNodeDefinition) => ({\n id: rootNodeDefinition.id,\n refs: flattenDefinition(rootNodeDefinition)\n .filter(isBranchNode)\n .map(({ ref }) => ref)\n })\n );\n\n // A recursive function to walk through the mappings, keeping track of which root nodes we have visited in the form of a path of root node identifiers.\n const followRefs = (mapping: { id: string | undefined; refs: string[] }, path: (string | undefined)[] = []) => {\n // Have we found a circular dependency?\n if (path.includes(mapping.id)) {\n // We found a circular dependency! Get the bad path of root node identifiers.\n const badPath = [...path, mapping.id];\n\n // Create the formatted path value. [undefined, \"a\", \"b\", \"c\", \"a\"] would be formatted as \"a -> b -> c -> a\".\n const badPathFormatted = badPath.filter((element) => !!element).join(\" => \");\n\n // No need to continue, we found a circular dependency.\n throw new Error(`circular dependency found in branch node references: ${badPathFormatted}`);\n }\n\n for (const ref of mapping.refs) {\n // Find the mapping for the root node with an identifer matching the current ref.\n const subMapping = rootNodeMappings.find(({ id }) => id === ref);\n\n // We may not have a mapping for this ref, which is normal when we aren't considering all globally registered subtrees.\n if (subMapping) {\n followRefs(subMapping, [...path, mapping.id]);\n } else if (includesGlobalSubtrees) {\n // We found a reference to a root node that doesn't exist, which is a problem seeing as the root node definitons includes all globally registered subtrees.\n throw new Error(\n mapping.id\n ? `subtree '${mapping.id}' has branch node that references root node '${ref}' which has not been defined`\n : `primary tree has branch node that references root node '${ref}' which has not been defined`\n );\n }\n }\n };\n\n // Start looking for circular dependencies and broken references from the primary root node definition.\n followRefs(rootNodeMappings.find((mapping) => typeof mapping.id === \"undefined\")!);\n}\n\n/**\n * Validate an object that we expect to be a node definition.\n * @param definition An object that we expect to be a node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateNode(definition: any, depth: number): void {\n // Every node must be valid object and have a non-empty 'type' string property.\n if (typeof definition !== \"object\" || typeof definition.type !== \"string\" || definition.type.length === 0) {\n throw new Error(\n `node definition is not an object or 'type' property is not a non-empty string at depth '${depth}'`\n );\n }\n\n // How we validate this node definition will depend on its type.\n switch (definition.type) {\n case \"action\":\n validateActionNode(definition, depth);\n break;\n\n case \"condition\":\n validateConditionNode(definition, depth);\n break;\n\n case \"wait\":\n validateWaitNode(definition, depth);\n break;\n\n case \"branch\":\n validateBranchNode(definition, depth);\n break;\n\n case \"root\":\n validateRootNode(definition, depth);\n break;\n\n case \"succeed\":\n validateSucceedNode(definition, depth);\n break;\n\n case \"fail\":\n validateFailNode(definition, depth);\n break;\n\n case \"flip\":\n validateFlipNode(definition, depth);\n break;\n\n case \"repeat\":\n validateRepeatNode(definition, depth);\n break;\n\n case \"retry\":\n validateRetryNode(definition, depth);\n break;\n\n case \"sequence\":\n validateSequenceNode(definition, depth);\n break;\n\n case \"selector\":\n validateSelectorNode(definition, depth);\n break;\n\n case \"parallel\":\n validateParallelNode(definition, depth);\n break;\n\n case \"lotto\":\n validateLottoNode(definition, depth);\n break;\n\n default:\n throw new Error(`unexpected node type of '${definition.type}' at depth '${depth}'`);\n }\n}\n\n/**\n * Validate any attributes for a given node definition.\n * @param definition The node definition.\n * @param depth The depth of the node in the behaviour tree definition.\n */\nfunction validateNodeAttributes(definition: any, depth: number): void {\n // Validate each of the attribute types for this node.\n [\"while\", \"until\", \"entry\", \"exit\", \"step\"].forEach((attributeName) => {\n // Attempt to grab the definition for the current attribute from the node definition.\n const attributeDefinition = definition[attributeName];\n\n // All node attributes are optional, so there is nothing to do if the current attribute is not defined.\n if (typeof attributeDefinition === \"undefined\") {\n return;\n }\n\n // The attribute definition must be an object.\n if (typeof attributeDefinition !== \"object\") {\n throw new Error(\n `expected attribute '${attributeName}' to be an object for '${definition.type}' node at depth '${depth}'`\n );\n }\n\n // The 'call' property must be defined for any attribute definition.\n if (typeof attributeDefinition.call !== \"string\" || attributeDefinition.call.length === 0) {\n throw new Error(\n `expected 'call' property for attribute '${attributeName}' to be a non-empty string for '${definition.type}' node at depth '${depth}'`\n );\n }\n\n // If any node attribute arguments have been defined then they must have been defined in an array.\n if (typeof attributeDefinition.args !== \"undefined\" && !Array.isArray(attributeDefinition.args)) {\n throw new Error(\n `expected 'args' property for attribute '${attributeName}' to be an array for '${definition.type}' node at depth '${depth}'`\n );\n }\n });\n}\n\n/**\n * Validate an object that we expect to be a root node definition.\n * @param definition An object that we expect to be a root node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateRootNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"root\") {\n throw new Error(\"expected node type of 'root' for root node\");\n }\n\n // A root node cannot be the child of another node.\n if (depth > 0) {\n throw new Error(\"a root node cannot be the child of another node\");\n }\n\n // Check that, if the root node 'id' property is defined, it is a non-empty string.\n if (typeof definition.id !== \"undefined\" && (typeof definition.id !== \"string\" || definition.id.length === 0)) {\n throw new Error(\"expected non-empty string for 'id' property if defined for root node\");\n }\n\n // A root node is a decorator node, so must have a child node defined.\n if (typeof definition.child === \"undefined\") {\n throw new Error(\"expected property 'child' to be defined for root node\");\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n\n // Validate the child node of this decorator node.\n validateNode(definition.child, depth + 1);\n}\n\n/**\n * Validate an object that we expect to be a succeed node definition.\n * @param definition An object that we expect to be a succeed node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateSucceedNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"succeed\") {\n throw new Error(`expected node type of 'succeed' for succeed node at depth '${depth}'`);\n }\n\n // A succeed node is a decorator node, so must have a child node defined.\n if (typeof definition.child === \"undefined\") {\n throw new Error(`expected property 'child' to be defined for succeed node at depth '${depth}'`);\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n\n // Validate the child node of this decorator node.\n validateNode(definition.child, depth + 1);\n}\n\n/**\n * Validate an object that we expect to be a fail node definition.\n * @param definition An object that we expect to be a fail node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateFailNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"fail\") {\n throw new Error(`expected node type of 'fail' for fail node at depth '${depth}'`);\n }\n\n // A fail node is a decorator node, so must have a child node defined.\n if (typeof definition.child === \"undefined\") {\n throw new Error(`expected property 'child' to be defined for fail node at depth '${depth}'`);\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n\n // Validate the child node of this decorator node.\n validateNode(definition.child, depth + 1);\n}\n\n/**\n * Validate an object that we expect to be a flip node definition.\n * @param definition An object that we expect to be a flip node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateFlipNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"flip\") {\n throw new Error(`expected node type of 'flip' for flip node at depth '${depth}'`);\n }\n\n // A flip node is a decorator node, so must have a child node defined.\n if (typeof definition.child === \"undefined\") {\n throw new Error(`expected property 'child' to be defined for flip node at depth '${depth}'`);\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n\n // Validate the child node of this decorator node.\n validateNode(definition.child, depth + 1);\n}\n\n/**\n * Validate an object that we expect to be a repeat node definition.\n * @param definition An object that we expect to be a repeat node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateRepeatNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"repeat\") {\n throw new Error(`expected node type of 'repeat' for repeat node at depth '${depth}'`);\n }\n\n // A repeat node is a decorator node, so must have a child node defined.\n if (typeof definition.child === \"undefined\") {\n throw new Error(`expected property 'child' to be defined for repeat node at depth '${depth}'`);\n }\n\n // Check whether an 'iterations' property has been defined, it may not have been if this node is to repeat indefinitely.\n if (typeof definition.iterations !== \"undefined\") {\n if (Array.isArray(definition.iterations)) {\n // Check whether any elements of the array are not integer values.\n const containsNonInteger = !!definition.iterations.filter((value: unknown) => !isInteger(value)).length;\n\n // If the 'iterations' property is an array then it MUST contain two integer values.\n if (definition.iterations.length !== 2 || containsNonInteger) {\n throw new Error(\n `expected array containing two integer values for 'iterations' property if defined for repeat node at depth '${depth}'`\n );\n }\n\n // A repeat node must have a positive min and max iterations count if they are defined.\n if (definition.iterations[0] < 0 || definition.iterations[1] < 0) {\n throw new Error(\n `expected positive minimum and maximum iterations count for 'iterations' property if defined for repeat node at depth '${depth}'`\n );\n }\n\n // A repeat node must not have a minimum iterations count that exceeds the maximum iterations count.\n if (definition.iterations[0] > definition.iterations[1]) {\n throw new Error(\n `expected minimum iterations count that does not exceed the maximum iterations count for 'iterations' property if defined for repeat node at depth '${depth}'`\n );\n }\n } else if (isInteger(definition.iterations)) {\n // A repeat node must have a positive number of iterations if defined.\n if (definition.iterations < 0) {\n throw new Error(\n `expected positive iterations count for 'iterations' property if defined for repeat node at depth '${depth}'`\n );\n }\n } else {\n throw new Error(\n `expected integer value or array containing two integer values for 'iterations' property if defined for repeat node at depth '${depth}'`\n );\n }\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n\n // Validate the child node of this decorator node.\n validateNode(definition.child, depth + 1);\n}\n\n/**\n * Validate an object that we expect to be a retry node definition.\n * @param definition An object that we expect to be a retry node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateRetryNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"retry\") {\n throw new Error(`expected node type of 'retry' for retry node at depth '${depth}'`);\n }\n\n // A retry node is a decorator node, so must have a child node defined.\n if (typeof definition.child === \"undefined\") {\n throw new Error(`expected property 'child' to be defined for retry node at depth '${depth}'`);\n }\n\n // Check whether an 'attempts' property has been defined, it may not have been if this node is to retry indefinitely.\n if (typeof definition.attempts !== \"undefined\") {\n if (Array.isArray(definition.attempts)) {\n // Check whether any elements of the array are not integer values.\n const containsNonInteger = !!definition.attempts.filter((value: unknown) => !isInteger(value)).length;\n\n // If the 'attempts' property is an array then it MUST contain two integer values.\n if (definition.attempts.length !== 2 || containsNonInteger) {\n throw new Error(\n `expected array containing two integer values for 'attempts' property if defined for retry node at depth '${depth}'`\n );\n }\n\n // A retry node must have a positive min and max attempts count if they are defined.\n if (definition.attempts[0] < 0 || definition.attempts[1] < 0) {\n throw new Error(\n `expected positive minimum and maximum attempts count for 'attempts' property if defined for retry node at depth '${depth}'`\n );\n }\n\n // A retry node must not have a minimum attempts count that exceeds the maximum attempts count.\n if (definition.attempts[0] > definition.attempts[1]) {\n throw new Error(\n `expected minimum attempts count that does not exceed the maximum attempts count for 'attempts' property if defined for retry node at depth '${depth}'`\n );\n }\n } else if (isInteger(definition.attempts)) {\n // A retry node must have a positive number of attempts if defined.\n if (definition.attempts < 0) {\n throw new Error(\n `expected positive attempts count for 'attempts' property if defined for retry node at depth '${depth}'`\n );\n }\n } else {\n throw new Error(\n `expected integer value or array containing two integer values for 'attempts' property if defined for retry node at depth '${depth}'`\n );\n }\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n\n // Validate the child node of this decorator node.\n validateNode(definition.child, depth + 1);\n}\n\n/**\n * Validate an object that we expect to be a branch node definition.\n * @param definition An object that we expect to be a branch node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateBranchNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"branch\") {\n throw new Error(`expected node type of 'branch' for branch node at depth '${depth}'`);\n }\n\n // Check that the branch node 'ref' property is defined and is a non-empty string.\n if (typeof definition.ref !== \"string\" || definition.ref.length === 0) {\n throw new Error(`expected non-empty string for 'ref' property for branch node at depth '${depth}'`);\n }\n\n // It is invalid to define guard attributes for a branch node as they should be defined on the referenced root node.\n [\"while\", \"until\"].forEach((attributeName) => {\n if (typeof definition[attributeName] !== \"undefined\") {\n throw new Error(\n `guards should not be defined for branch nodes but guard '${attributeName}' was defined for branch node at depth '${depth}'`\n );\n }\n });\n\n // It is invalid to define callback attributes for a branch node as they should be defined on the referenced root node.\n [\"entry\", \"exit\", \"step\"].forEach((attributeName) => {\n if (typeof definition[attributeName] !== \"undefined\") {\n throw new Error(\n `callbacks should not be defined for branch nodes but callback '${attributeName}' was defined for branch node at depth '${depth}'`\n );\n }\n });\n}\n\n/**\n * Validate an object that we expect to be a action node definition.\n * @param definition An object that we expect to be a action node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateActionNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"action\") {\n throw new Error(`expected node type of 'action' for action node at depth '${depth}'`);\n }\n\n // The 'call' property must be defined for a action node definition.\n if (typeof definition.call !== \"string\" || definition.call.length === 0) {\n throw new Error(`expected non-empty string for 'call' property of action node at depth '${depth}'`);\n }\n\n // If any action function arguments have been defined then they must have been defined in an array.\n if (typeof definition.args !== \"undefined\" && !Array.isArray(definition.args)) {\n throw new Error(`expected array for 'args' property if defined for action node at depth '${depth}'`);\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n}\n\n/**\n * Validate an object that we expect to be a condition node definition.\n * @param definition An object that we expect to be a condition node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateConditionNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"condition\") {\n throw new Error(`expected node type of 'condition' for condition node at depth '${depth}'`);\n }\n\n // The 'call' property must be defined for a condition node definition.\n if (typeof definition.call !== \"string\" || definition.call.length === 0) {\n throw new Error(`expected non-empty string for 'call' property of condition node at depth '${depth}'`);\n }\n\n // If any condition function arguments have been defined then they must have been defined in an array.\n if (typeof definition.args !== \"undefined\" && !Array.isArray(definition.args)) {\n throw new Error(`expected array for 'args' property if defined for condition node at depth '${depth}'`);\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n}\n\n/**\n * Validate an object that we expect to be a wait node definition.\n * @param definition An object that we expect to be a wait node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateWaitNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"wait\") {\n throw new Error(`expected node type of 'wait' for wait node at depth '${depth}'`);\n }\n\n // Check whether a 'duration' property has been defined, it may not have been if this node is to wait indefinitely.\n if (typeof definition.duration !== \"undefined\") {\n if (Array.isArray(definition.duration)) {\n // Check whether any elements of the array are not integer values.\n const containsNonInteger = !!definition.duration.filter((value: unknown) => !isInteger(value)).length;\n\n // If the 'duration' property is an array then it MUST contain two integer values.\n if (definition.duration.length !== 2 || containsNonInteger) {\n throw new Error(\n `expected array containing two integer values for 'duration' property if defined for wait node at depth '${depth}'`\n );\n }\n\n // A wait node must have a positive min and max duration value if they are defined.\n if (definition.duration[0] < 0 || definition.duration[1] < 0) {\n throw new Error(\n `expected positive minimum and maximum duration for 'duration' property if defined for wait node at depth '${depth}'`\n );\n }\n\n // A wait node must not have a minimum duration value that exceeds the maximum duration value.\n if (definition.duration[0] > definition.duration[1]) {\n throw new Error(\n `expected minimum duration value that does not exceed the maximum duration value for 'duration' property if defined for wait node at depth '${depth}'`\n );\n }\n } else if (isInteger(definition.duration)) {\n // A wait node must have a positive duration value if defined.\n if (definition.duration < 0) {\n throw new Error(\n `expected positive duration value for 'duration' property if defined for wait node at depth '${depth}'`\n );\n }\n } else {\n throw new Error(\n `expected integer value or array containing two integer values for 'duration' property if defined for wait node at depth '${depth}'`\n );\n }\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n}\n\n/**\n * Validate an object that we expect to be a sequence node definition.\n * @param definition An object that we expect to be a sequence node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateSequenceNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"sequence\") {\n throw new Error(`expected node type of 'sequence' for sequence node at depth '${depth}'`);\n }\n\n // A sequence node is a composite node, so must have a children nodes array defined.\n if (!Array.isArray(definition.children) || definition.children.length === 0) {\n throw new Error(`expected non-empty 'children' array to be defined for sequence node at depth '${depth}'`);\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n\n // Validate the child nodes of this composite node.\n definition.children.forEach((child: any) => validateNode(child, depth + 1));\n}\n\n/**\n * Validate an object that we expect to be a selector node definition.\n * @param definition An object that we expect to be a selector node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateSelectorNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"selector\") {\n throw new Error(`expected node type of 'selector' for selector node at depth '${depth}'`);\n }\n\n // A selector node is a composite node, so must have a children nodes array defined.\n if (!Array.isArray(definition.children) || definition.children.length === 0) {\n throw new Error(`expected non-empty 'children' array to be defined for selector node at depth '${depth}'`);\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n\n // Validate the child nodes of this composite node.\n definition.children.forEach((child: any) => validateNode(child, depth + 1));\n}\n\n/**\n * Validate an object that we expect to be a parallel node definition.\n * @param definition An object that we expect to be a parallel node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateParallelNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"parallel\") {\n throw new Error(`expected node type of 'parallel' for parallel node at depth '${depth}'`);\n }\n\n // A parallel node is a composite node, so must have a children nodes array defined.\n if (!Array.isArray(definition.children) || definition.children.length === 0) {\n throw new Error(`expected non-empty 'children' array to be defined for parallel node at depth '${depth}'`);\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n\n // Validate the child nodes of this composite node.\n definition.children.forEach((child: any) => validateNode(child, depth + 1));\n}\n\n/**\n * Validate an object that we expect to be a lotto node definition.\n * @param definition An object that we expect to be a lotto node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateLottoNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"lotto\") {\n throw new Error(`expected node type of 'lotto' for lotto node at depth '${depth}'`);\n }\n\n // A lotto node is a composite node, so must have a children nodes array defined.\n if (!Array.isArray(definition.children) || definition.children.length === 0) {\n throw new Error(`expected non-empty 'children' array to be defined for lotto node at depth '${depth}'`);\n }\n\n // Check whether a 'weights' property has been defined, if it has we expect it to be an array of weights.\n if (typeof definition.weights !== \"undefined\") {\n // Check that the weights property is an array of positive integers with an element for each child node element.\n if (\n !Array.isArray(definition.weights) ||\n definition.weights.length !== definition.children.length ||\n definition.weights.filter((value: unknown) => !isInteger(value)).length ||\n definition.weights.filter((value: number) => value < 0).length\n ) {\n throw new Error(\n `expected an array of positive integer weight values with a length matching the number of child nodes for 'weights' property if defined for lotto node at depth '${depth}'`\n );\n }\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n\n // Validate the child nodes of this composite node.\n definition.children.forEach((child: any) => validateNode(child, depth + 1));\n}\n\n/**\n * A helper function to create a failure validation result with the given error message.\n * @param errorMessage The validation failure error message.\n * @returns A failure validation result with the given error message.\n */\nfunction createValidationFailureResult(errorMessage: string): DefinitionValidationResult {\n return { succeeded: false, errorMessage };\n}\n", "import { ActionResult, Agent, GlobalFunction } from \"./Agent\";\nimport { RootNodeDefinition } from \"./BehaviourTreeDefinition\";\n\nexport type InvokerFunction = (args: any[]) => ActionResult;\n\n/**\n * A singleton used to store and lookup registered functions and subtrees.\n */\nexport default class Lookup {\n /**\n * The object holding any registered functions keyed on function name.\n */\n private static functionTable: { [key: string]: GlobalFunction } = {};\n /**\n * The object holding any registered subtree root node definitions keyed on tree name.\n */\n private static subtreeTable: { [key: string]: RootNodeDefinition } = {};\n\n /**\n * Gets the function with the specified name.\n * @param name The name of the function.\n * @returns The function with the specified name.\n */\n public static getFunc(name: string): GlobalFunction {\n return this.functionTable[name];\n }\n\n /**\n * Sets the function with the specified name for later lookup.\n * @param name The name of the function.\n * @param func The function.\n */\n public static setFunc(name: string, func: GlobalFunction): void {\n this.functionTable[name] = func;\n }\n\n /**\n * Gets the function invoker for the specified agent and function name.\n * If a function with the specified name exists on the agent object then it will\n * be returned, otherwise we will then check the registered functions for a match.\n * @param agent The agent instance that this behaviour tree is modelling behaviour for.\n * @param name The function name.\n * @returns The function invoker for the specified agent and function name.\n */\n static getFuncInvoker(agent: Agent, name: string): InvokerFunction | null {\n // Check whether the agent contains the specified function.\n const foundOnAgent = agent[name];\n if (foundOnAgent && typeof foundOnAgent === \"function\") {\n return (args: any[]): boolean | ActionResult => foundOnAgent.apply(agent, args);\n }\n\n // The agent does not contain the specified function but it may have been registered at some point.\n if (this.functionTable[name] && typeof this.functionTable[name] === \"function\") {\n return (args: any[]) => this.functionTable[name](agent, ...args.map((arg) => arg.value));\n }\n\n // We have no function to invoke.\n return null;\n }\n\n /**\n * Gets all registered subtree root node definitions.\n */\n static getSubtrees(): { [key: string]: RootNodeDefinition } {\n return this.subtreeTable;\n }\n\n /**\n * Sets the subtree with the specified name for later lookup.\n * @param name The name of the subtree.\n * @param subtree The subtree.\n */\n static setSubtree(name: string, subtree: RootNodeDefinition) {\n this.subtreeTable[name] = subtree;\n }\n\n /**\n * Removes the registered function or subtree with the specified name.\n * @param name The name of the registered function or subtree.\n */\n static remove(name: string) {\n delete this.functionTable[name];\n delete this.subtreeTable[name];\n }\n\n /**\n * Remove all registered functions and subtrees.\n */\n static empty() {\n this.functionTable = {};\n this.subtreeTable = {};\n }\n}\n", "import Node from \"../../nodes/Node\";\n\n/**\n * An exception thrown when evaluating node guard path conditions and a conditions fails.\n */\nexport default class GuardUnsatisifedException extends Error {\n /**\n * @param source The node at which a guard condition failed.\n */\n constructor(private source: Node) {\n super(\"A guard path condition has failed\");\n }\n\n /**\n * Gets whether the specified node is the node at which a guard condition failed.\n * @param node The node to check against the source node.\n * @returns Whether the specified node is the node at which a guard condition failed.\n */\n isSourceNode = (node: Node) => node === this.source;\n}\n", "import { Agent } from \"../../Agent\";\nimport Guard from \"./Guard\";\nimport Node from \"../../nodes/Node\";\nimport GuardUnsatisifedException from \"./GuardUnsatisifedException\";\n\nexport type GuardPathPart = {\n node: Node;\n guards: Guard[];\n};\n\n/**\n * Represents a path of node guards along a root-to-leaf tree path.\n */\nexport default class GuardPath {\n /**\n * @param nodes An array of objects defining a node instance -> guard link, ordered by node depth.\n */\n constructor(private nodes: GuardPathPart[]) {}\n\n /**\n * Evaluate guard conditions for all guards in the tree path, moving outwards from the root.\n * @param agent The agent, required for guard evaluation.\n * @returns An evaluation results object.\n */\n evaluate = (agent: Agent) => {\n // We need to evaluate guard conditions for nodes up the tree, moving outwards from the root.\n for (const details of this.nodes) {\n // There can be multiple guards per node.\n for (const guard of details.guards) {\n // Check whether the guard condition passes, and throw an exception if not.\n if (!guard.isSatisfied(agent)) {\n throw new GuardUnsatisifedException(details.node);\n }\n }\n }\n };\n}\n", "import { BehaviourTreeOptions } from \"../BehaviourTreeOptions\";\nimport State, { AnyState } from \"../State\";\nimport { Agent } from \"../Agent\";\nimport Leaf from \"./leaf/Leaf\";\nimport Attribute from \"../attributes/Attribute\";\nimport Entry from \"../attributes/callbacks/Entry\";\nimport Exit from \"../attributes/callbacks/Exit\";\nimport Step from \"../attributes/callbacks/Step\";\nimport Guard from \"../attributes/guards/Guard\";\nimport GuardPath from \"../attributes/guards/GuardPath\";\nimport GuardUnsatisifedException from \"../attributes/guards/GuardUnsatisifedException\";\n\n/**\n * A base node.\n */\nexport default abstract class Node {\n /**\n * The node uid.\n */\n private readonly uid: string = createNodeUid();\n /**\n * The node state.\n */\n private state: AnyState = State.READY;\n /**\n * The guard path to evaluate as part of a node update.\n */\n private guardPath: GuardPath | undefined;\n\n /**\n * @param type The node type.\n * @param attributes The node attributes.\n * @param args The node argument definitions.\n */\n constructor(private type: string, private attributes: Attribute[], private args: any[]) {}\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected abstract onUpdate(agent: Agent, options: BehaviourTreeOptions): void;\n\n /**\n * Gets the name of the node.\n */\n public abstract getName(): string;\n\n /**\n * Gets whether this node is a leaf node.\n */\n public abstract isLeafNode: () => this is Leaf;\n\n /**\n * Gets/Sets the state of the node.\n */\n getState = (): AnyState => this.state;\n setState = (value: AnyState): void => {\n this.state = value;\n };\n\n /**\n * Gets the unique id of the node.\n */\n getUid = () => this.uid;\n\n /**\n * Gets the type of the node.\n */\n getType = () => this.type;\n\n /**\n * Gets the node attributes.\n */\n getAttributes = () => this.attributes;\n\n /**\n * Gets the node arguments.\n */\n getArguments = () => this.args;\n\n /**\n * Gets the node attribute with the specified type, or null if it does not exist.\n */\n getAttribute(type: \"entry\" | \"ENTRY\"): Entry;\n getAttribute(type: \"exit\" | \"EXIT\"): Exit;\n getAttribute(type: \"step\" | \"STEP\"): Step;\n getAttribute(type: string): Attribute {\n return (\n this.getAttributes().filter((decorator) => decorator.type.toUpperCase() === type.toUpperCase())[0] || null\n );\n }\n\n /**\n * Gets the node attributes.\n */\n getGuardAttributes = (): Guard[] => this.getAttributes().filter((decorator) => decorator.isGuard()) as Guard[];\n\n /**\n * Sets the guard path to evaluate as part of a node update.\n */\n setGuardPath = (value: GuardPath) => (this.guardPath = value);\n\n /**\n * Gets whether a guard path is assigned to this node.\n */\n hasGuardPath = () => !!this.guardPath;\n\n /**\n * Gets whether this node is in the specified state.\n * @param value The value to compare to the node state.\n */\n public is(value: AnyState): boolean {\n return this.state === value;\n }\n\n /**\n * Reset the state of the node.\n */\n public reset(): void {\n this.setState(State.READY);\n }\n\n /**\n * Abort the running of this node.\n * @param agent The agent.\n */\n public abort(agent: Agent): void {\n // There is nothing to do if this node is not in the running state.\n if (!this.is(State.RUNNING)) {\n return;\n }\n\n // Reset the state of this node.\n this.reset();\n\n this.getAttribute(\"exit\")?.callAgentFunction(agent, false, true);\n }\n\n /**\n * Update the node.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n * @returns The result of the update.\n */\n public update(agent: Agent, options: BehaviourTreeOptions): void {\n // If this node is already in a 'SUCCEEDED' or 'FAILED' state then there is nothing to do.\n if (this.is(State.SUCCEEDED) || this.is(State.FAILED)) {\n return;\n }\n\n try {\n // Evaluate all of the guard path conditions for the current tree path.\n this.guardPath!.evaluate(agent);\n\n // If this node is in the READY state then call the ENTRY for this node if it exists.\n if (this.is(State.READY)) {\n this.getAttribute(\"entry\")?.callAgentFunction(agent);\n }\n\n this.getAttribute(\"step\")?.callAgentFunction(agent);\n\n // Do the actual update.\n this.onUpdate(agent, options);\n\n // If this node is now in a 'SUCCEEDED' or 'FAILED' state then call the EXIT for this node if it exists.\n if (this.is(State.SUCCEEDED) || this.is(State.FAILED)) {\n this.getAttribute(\"exit\")?.callAgentFunction(agent, this.is(State.SUCCEEDED), false);\n }\n } catch (error) {\n // If the error is a GuardUnsatisfiedException then we need to determine if this node is the source.\n if (error instanceof GuardUnsatisifedException && error.isSourceNode(this)) {\n // Abort the current node.\n this.abort(agent);\n\n // Any node that is the source of an abort will be a failed node.\n this.setState(State.FAILED);\n } else {\n throw error;\n }\n }\n }\n}\n\n/**\n * Create a randomly generated node uid.\n * @returns A randomly generated node uid.\n */\nfunction createNodeUid(): string {\n var S4 = function () {\n return (((1 + Math.random()) * 0x10000) | 0).toString(16).substring(1);\n };\n return S4() + S4() + \"-\" + S4() + \"-\" + S4() + \"-\" + S4() + \"-\" + S4() + S4() + S4();\n}\n", "import Node from \"../Node\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\n\n/**\n * A composite node that wraps child nodes.\n */\nexport default abstract class Composite extends Node {\n /**\n * @param type The node type.\n * @param attributes The node attributes.\n * @param children The child nodes.\n */\n constructor(type: string, attributes: Attribute[], protected children: Node[]) {\n super(type, attributes, []);\n }\n\n /**\n * Gets whether this node is a leaf node.\n */\n isLeafNode = () => false;\n\n /**\n * Gets the children of this node.\n */\n getChildren = () => this.children;\n\n /**\n * Reset the state of the node.\n */\n reset = () => {\n // Reset the state of this node.\n this.setState(State.READY);\n\n // Reset the state of any child nodes.\n this.getChildren().forEach((child) => child.reset());\n };\n\n /**\n * Abort the running of this node.\n * @param agent The agent.\n */\n abort = (agent: Agent) => {\n // There is nothing to do if this node is not in the running state.\n if (!this.is(State.RUNNING)) {\n return;\n }\n\n // Abort any child nodes.\n this.getChildren().forEach((child) => child.abort(agent));\n\n // Reset the state of this node.\n this.reset();\n\n this.getAttribute(\"exit\")?.callAgentFunction(agent, false, true);\n };\n}\n", "import Composite from \"./Composite\";\nimport State from \"../../State\";\nimport Node from \"../Node\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A PARALLEL node.\n * The child nodes are executed concurrently until one fails or all succeed.\n */\nexport default class Parallel extends Composite {\n /**\n * @param attributes The node attributes.\n * @param children The child nodes.\n */\n constructor(attributes: Attribute[], children: Node[]) {\n super(\"parallel\", attributes, children);\n }\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // Keep a count of the number of succeeded child nodes.\n let succeededCount = 0;\n\n let hasChildFailed = false;\n\n // Iterate over all of the children of this node.\n for (const child of this.children) {\n // If the child has never been updated or is running then we will need to update it now.\n if (child.getState() === State.READY || child.getState() === State.RUNNING) {\n // Update the child of this node.\n child.update(agent, options);\n }\n\n // If the current child has a state of 'SUCCEEDED' then we should move on to the next child.\n if (child.getState() === State.SUCCEEDED) {\n // The child node has succeeded, keep track of this to determine if all children have.\n succeededCount++;\n\n // The child node succeeded, but we have not finished checking every child node yet.\n continue;\n }\n\n // If the current child has a state of 'FAILED' then this node is also a 'FAILED' node.\n if (child.getState() === State.FAILED) {\n hasChildFailed = true;\n\n // There is no need to check the rest of the children.\n break;\n }\n\n // The node should be in the 'RUNNING' state.\n if (child.getState() !== State.RUNNING) {\n // The child node was not in an expected state.\n throw new Error(\"child node was not in an expected state.\");\n }\n }\n\n if (hasChildFailed) {\n // This node is a 'FAILED' node.\n this.setState(State.FAILED);\n\n // Abort every running child.\n for (const child of this.children) {\n if (child.getState() === State.RUNNING) {\n child.abort(agent);\n }\n }\n } else {\n // If all children have succeeded then this node has also succeeded, otherwise it is still running.\n this.setState(succeededCount === this.children.length ? State.SUCCEEDED : State.RUNNING);\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => \"PARALLEL\";\n}\n", "import Composite from \"./Composite\";\nimport Node from \"../Node\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A SELECTOR node.\n * The child nodes are executed in sequence until one succeeds or all fail.\n */\nexport default class Selector extends Composite {\n /**\n * @param attributes The node attributes.\n * @param children The child nodes.\n */\n constructor(attributes: Attribute[], protected children: Node[]) {\n super(\"selector\", attributes, children);\n }\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // Iterate over all of the children of this node.\n for (const child of this.children) {\n // If the child has never been updated or is running then we will need to update it now.\n if (child.getState() === State.READY || child.getState() === State.RUNNING) {\n // Update the child of this node.\n child.update(agent, options);\n }\n\n // If the current child has a state of 'SUCCEEDED' then this node is also a 'SUCCEEDED' node.\n if (child.getState() === State.SUCCEEDED) {\n // This node is a 'SUCCEEDED' node.\n this.setState(State.SUCCEEDED);\n\n // There is no need to check the rest of the selector nodes.\n return;\n }\n\n // If the current child has a state of 'FAILED' then we should move on to the next child.\n if (child.getState() === State.FAILED) {\n // Find out if the current child is the last one in the selector.\n // If it is then this sequence node has also failed.\n if (this.children.indexOf(child) === this.children.length - 1) {\n // This node is a 'FAILED' node.\n this.setState(State.FAILED);\n\n // There is no need to check the rest of the selector as we have completed it.\n return;\n } else {\n // The child node failed, try the next one.\n continue;\n }\n }\n\n // The node should be in the 'RUNNING' state.\n if (child.getState() === State.RUNNING) {\n // This node is a 'RUNNING' node.\n this.setState(State.RUNNING);\n\n // There is no need to check the rest of the selector as the current child is still running.\n return;\n }\n\n // The child node was not in an expected state.\n throw new Error(\"child node was not in an expected state.\");\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => \"SELECTOR\";\n}\n", "import Composite from \"./Composite\";\nimport Node from \"../Node\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A SEQUENCE node.\n * The child nodes are executed in sequence until one fails or all succeed.\n */\nexport default class Sequence extends Composite {\n /**\n * @param attributes The node attributes.\n * @param children The child nodes.\n */\n constructor(attributes: Attribute[], protected children: Node[]) {\n super(\"sequence\", attributes, children);\n }\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // Iterate over all of the children of this node.\n for (const child of this.children) {\n // If the child has never been updated or is running then we will need to update it now.\n if (child.getState() === State.READY || child.getState() === State.RUNNING) {\n // Update the child of this node.\n child.update(agent, options);\n }\n\n // If the current child has a state of 'SUCCEEDED' then we should move on to the next child.\n if (child.getState() === State.SUCCEEDED) {\n // Find out if the current child is the last one in the sequence.\n // If it is then this sequence node has also succeeded.\n if (this.children.indexOf(child) === this.children.length - 1) {\n // This node is a 'SUCCEEDED' node.\n this.setState(State.SUCCEEDED);\n\n // There is no need to check the rest of the sequence as we have completed it.\n return;\n } else {\n // The child node succeeded, but we have not finished the sequence yet.\n continue;\n }\n }\n\n // If the current child has a state of 'FAILED' then this node is also a 'FAILED' node.\n if (child.getState() === State.FAILED) {\n // This node is a 'FAILED' node.\n this.setState(State.FAILED);\n\n // There is no need to check the rest of the sequence.\n return;\n }\n\n // The node should be in the 'RUNNING' state.\n if (child.getState() === State.RUNNING) {\n // This node is a 'RUNNING' node.\n this.setState(State.RUNNING);\n\n // There is no need to check the rest of the sequence as the current child is still running.\n return;\n }\n\n // The child node was not in an expected state.\n throw new Error(\"child node was not in an expected state.\");\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => \"SEQUENCE\";\n}\n", "import createLotto from \"lotto-draw\";\n\nimport Node from \"../Node\";\nimport Composite from \"./Composite\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A LOTTO node.\n * A winning child is picked on the initial update of this node, based on ticket weighting.\n * The state of this node will match the state of the winning child.\n */\nexport default class Lotto extends Composite {\n /**\n * @param attributes The node attributes.\n * @param weights The child node weights.\n * @param children The child nodes.\n */\n constructor(attributes: Attribute[], private weights: number[] | undefined, children: Node[]) {\n super(\"lotto\", attributes, children);\n }\n\n /**\n * The child node selected to be the active one.\n */\n private selectedChild: Node | undefined;\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // If this node is in the READY state then we need to pick a winning child node.\n if (this.is(State.READY)) {\n // Create a lotto draw with which to randomly pick a child node to become the active one.\n const lottoDraw = createLotto({\n // Hook up the optional 'random' behaviour tree function option to the one used by 'lotto-draw'.\n random: options.random,\n // Pass in each child node as a participant in the lotto draw with their respective ticket count.\n participants: this.children.map((child, index) => [child, this.weights?.[index] || 1])\n });\n\n // Randomly pick a child based on ticket weighting, this will become the active child for this composite node.\n this.selectedChild = lottoDraw.draw() || undefined;\n }\n\n // If something went wrong and we don't have an active child then we should throw an error.\n if (!this.selectedChild) {\n throw new Error(\"failed to update lotto node as it has no active child\");\n }\n\n // If the selected child has never been updated or is running then we will need to update it now.\n if (this.selectedChild.getState() === State.READY || this.selectedChild.getState() === State.RUNNING) {\n this.selectedChild.update(agent, options);\n }\n\n // The state of the lotto node is the state of its selected child.\n this.setState(this.selectedChild.getState());\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => (this.weights ? `LOTTO [${this.weights.join(\",\")}]` : \"LOTTO\");\n}\n", "import Node from \"../Node\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\n\n/**\n * A decorator node that wraps a single child node.\n */\nexport default abstract class Decorator extends Node {\n /**\n * @param type The node type.\n * @param attributes The node attributes.\n * @param child The child node.\n */\n constructor(type: string, attributes: Attribute[], protected child: Node) {\n super(type, attributes, []);\n }\n\n /**\n * Gets whether this node is a leaf node.\n */\n isLeafNode = () => false;\n\n /**\n * Gets the children of this node.\n */\n getChildren = () => [this.child];\n\n /**\n * Reset the state of the node.\n */\n reset = () => {\n // Reset the state of this node.\n this.setState(State.READY);\n\n // Reset the state of the child node.\n this.child.reset();\n };\n\n /**\n * Abort the running of this node.\n * @param agent The agent.\n */\n abort = (agent: Agent) => {\n // There is nothing to do if this node is not in the running state.\n if (!this.is(State.RUNNING)) {\n return;\n }\n\n // Abort the child node.\n this.child.abort(agent);\n\n // Reset the state of this node.\n this.reset();\n\n this.getAttribute(\"exit\")?.callAgentFunction(agent, false, true);\n };\n}\n", "import Node from \"../Node\";\nimport Decorator from \"./Decorator\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A Fail node.\n * This node wraps a single child and will always move to the 'FAILED' state when the child moves to a 'SUCCEEDED' or 'FAILED' state.\n */\nexport default class Fail extends Decorator {\n /**\n * @param attributes The node attributes.\n * @param child The child node.\n */\n constructor(attributes: Attribute[], child: Node) {\n super(\"fail\", attributes, child);\n }\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // If the child has never been updated or is running then we will need to update it now.\n if (this.child.getState() === State.READY || this.child.getState() === State.RUNNING) {\n this.child.update(agent, options);\n }\n\n // The state of this node will depend in the state of its child.\n switch (this.child.getState()) {\n case State.RUNNING:\n this.setState(State.RUNNING);\n break;\n\n case State.SUCCEEDED:\n case State.FAILED:\n this.setState(State.FAILED);\n break;\n\n default:\n this.setState(State.READY);\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => \"FAIL\";\n}\n", "import Decorator from \"./Decorator\";\nimport State from \"../../State\";\nimport Node from \"../Node\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A Flip node.\n * This node wraps a single child and will flip the state of the child state.\n */\nexport default class Flip extends Decorator {\n /**\n * @param attributes The node attributes.\n * @param child The child node.\n */\n constructor(attributes: Attribute[], child: Node) {\n super(\"flip\", attributes, child);\n }\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // If the child has never been updated or is running then we will need to update it now.\n if (this.child.getState() === State.READY || this.child.getState() === State.RUNNING) {\n this.child.update(agent, options);\n }\n\n // The state of this node will depend in the state of its child.\n switch (this.child.getState()) {\n case State.RUNNING:\n this.setState(State.RUNNING);\n break;\n\n case State.SUCCEEDED:\n this.setState(State.FAILED);\n break;\n\n case State.FAILED:\n this.setState(State.SUCCEEDED);\n break;\n\n default:\n this.setState(State.READY);\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => \"FLIP\";\n}\n", "import Node from \"../Node\";\nimport Decorator from \"./Decorator\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A REPEAT node.\n * The node has a single child which can have:\n * -- A number of iterations for which to repeat the child node.\n * -- An infinite repeat loop if neither an iteration count or a condition function is defined.\n * The REPEAT node will stop and have a 'FAILED' state if its child is ever in a 'FAILED' state after an update.\n * The REPEAT node will attempt to move on to the next iteration if its child is ever in a 'SUCCEEDED' state.\n */\nexport default class Repeat extends Decorator {\n /**\n * @param attributes The node attributes.\n * @param iterations The number of iterations to repeat the child node.\n * @param iterationsMin The minimum possible number of iterations to repeat the child node.\n * @param iterationsMax The maximum possible number of iterations to repeat the child node.\n * @param child The child node.\n */\n constructor(\n attributes: Attribute[],\n private iterations: number | null,\n private iterationsMin: number | null,\n private iterationsMax: number | null,\n child: Node\n ) {\n super(\"repeat\", attributes, child);\n }\n\n /**\n * The number of target iterations to make.\n */\n private targetIterationCount: number | null = null;\n\n /**\n * The current iteration count.\n */\n private currentIterationCount: number = 0;\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // If this node is in the READY state then we need to reset the child and the target iteration count.\n if (this.is(State.READY)) {\n // Reset the child node.\n this.child.reset();\n\n // Reset the current iteration count.\n this.currentIterationCount = 0;\n\n // Set the target iteration count.\n this.setTargetIterationCount(options);\n }\n\n // Do a check to see if we can iterate. If we can then this node will move into the 'RUNNING' state.\n // If we cannot iterate then we have hit our target iteration count, which means that the node has succeeded.\n if (this.canIterate()) {\n // This node is in the running state and can do its initial iteration.\n this.setState(State.RUNNING);\n\n // We may have already completed an iteration, meaning that the child node will be in the SUCCEEDED state.\n // If this is the case then we will have to reset the child node now.\n if (this.child.getState() === State.SUCCEEDED) {\n this.child.reset();\n }\n\n // Update the child of this node.\n this.child.update(agent, options);\n\n // If the child moved into the FAILED state when we updated it then there is nothing left to do and this node has also failed.\n // If it has moved into the SUCCEEDED state then we have completed the current iteration.\n if (this.child.getState() === State.FAILED) {\n // The child has failed, meaning that this node has failed.\n this.setState(State.FAILED);\n\n return;\n } else if (this.child.getState() === State.SUCCEEDED) {\n // We have completed an iteration.\n this.currentIterationCount += 1;\n }\n } else {\n // This node is in the 'SUCCEEDED' state as we cannot iterate any more.\n this.setState(State.SUCCEEDED);\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => {\n if (this.iterations !== null) {\n return `REPEAT ${this.iterations}x`;\n } else if (this.iterationsMin !== null && this.iterationsMax !== null) {\n return `REPEAT ${this.iterationsMin}x-${this.iterationsMax}x`;\n } else {\n return \"REPEAT\";\n }\n };\n\n /**\n * Reset the state of the node.\n */\n reset = () => {\n // Reset the state of this node.\n this.setState(State.READY);\n\n // Reset the current iteration count.\n this.currentIterationCount = 0;\n\n // Reset the child node.\n this.child.reset();\n };\n\n /**\n * Gets whether an iteration can be made.\n * @returns Whether an iteration can be made.\n */\n private canIterate = () => {\n if (this.targetIterationCount !== null) {\n // We can iterate as long as we have not reached our target iteration count.\n return this.currentIterationCount < this.targetIterationCount;\n }\n\n // If neither an iteration count or a condition function were defined then we can iterate indefinitely.\n return true;\n };\n\n /**\n * Sets the target iteration count.\n * @param options The behaviour tree options object.\n */\n private setTargetIterationCount = (options: BehaviourTreeOptions) => {\n // Are we dealing with an explicit iteration count or will we be randomly picking a iteration count between the min and max iteration count.\n if (this.iterations !== null) {\n this.targetIterationCount = this.iterations;\n } else if (this.iterationsMin !== null && this.iterationsMax !== null) {\n // We will be picking a random iteration count between a min and max iteration count, if the optional 'random'\n // behaviour tree function option is defined then we will be using that, otherwise we will fall back to using Math.random.\n const random = typeof options.random === \"function\" ? options.random : Math.random;\n\n // Pick a random iteration count between a min and max iteration count.\n this.targetIterationCount = Math.floor(\n random() * (this.iterationsMax - this.iterationsMin + 1) + this.iterationsMin\n );\n } else {\n this.targetIterationCount = null;\n }\n };\n}\n", "import Node from \"../Node\";\nimport Decorator from \"./Decorator\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A RETRY node.\n * The node has a single child which can have:\n * -- A number of iterations for which to repeat the child node.\n * -- An infinite repeat loop if neither an iteration count or a condition function is defined.\n * The RETRY node will stop and have a 'SUCCEEDED' state if its child is ever in a 'SUCCEEDED' state after an update.\n * The RETRY node will attempt to move on to the next iteration if its child is ever in a 'FAILED' state.\n */\nexport default class Retry extends Decorator {\n /**\n * @param attributes The node attributes.\n * @param attempts The number of attempts to retry the child node.\n * @param attemptsMin The minimum possible number of attempts to retry the child node.\n * @param attemptsMax The maximum possible number of attempts to retry the child node.\n * @param child The child node.\n */\n constructor(\n attributes: Attribute[],\n private attempts: number | null,\n private attemptsMin: number | null,\n private attemptsMax: number | null,\n child: Node\n ) {\n super(\"retry\", attributes, child);\n }\n\n /**\n * The number of target attempts to make.\n */\n private targetAttemptCount: number | null = null;\n\n /**\n * The current attempt count.\n */\n private currentAttemptCount: number = 0;\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // If this node is in the READY state then we need to reset the child and the target attempt count.\n if (this.is(State.READY)) {\n // Reset the child node.\n this.child.reset();\n\n // Reset the current attempt count.\n this.currentAttemptCount = 0;\n\n // Set the target attempt count.\n this.setTargetAttemptCount(options);\n }\n\n // Do a check to see if we can attempt. If we can then this node will move into the 'RUNNING' state.\n // If we cannot attempt then we have hit our target attempt count, which means that the node has succeeded.\n if (this.canAttempt()) {\n // This node is in the running state and can do its initial attempt.\n this.setState(State.RUNNING);\n\n // We may have already completed an attempt, meaning that the child node will be in the FAILED state.\n // If this is the case then we will have to reset the child node now.\n if (this.child.getState() === State.FAILED) {\n this.child.reset();\n }\n\n // Update the child of this node.\n this.child.update(agent, options);\n\n // If the child moved into the SUCCEEDED state when we updated it then there is nothing left to do and this node has also succeeded.\n // If it has moved into the FAILED state then we have completed the current attempt.\n if (this.child.getState() === State.SUCCEEDED) {\n // The child has succeeded, meaning that this node has succeeded.\n this.setState(State.SUCCEEDED);\n\n return;\n } else if (this.child.getState() === State.FAILED) {\n // We have completed an attempt.\n this.currentAttemptCount += 1;\n }\n } else {\n // This node is in the 'FAILED' state as we cannot iterate any more.\n this.setState(State.FAILED);\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => {\n if (this.attempts !== null) {\n return `RETRY ${this.attempts}x`;\n } else if (this.attemptsMin !== null && this.attemptsMax !== null) {\n return `RETRY ${this.attemptsMin}x-${this.attemptsMax}x`;\n } else {\n return \"RETRY\";\n }\n };\n\n /**\n * Reset the state of the node.\n */\n reset = () => {\n // Reset the state of this node.\n this.setState(State.READY);\n\n // Reset the current attempt count.\n this.currentAttemptCount = 0;\n\n // Reset the child node.\n this.child.reset();\n };\n\n /**\n * Gets whether an attempt can be made.\n * @returns Whether an attempt can be made.\n */\n canAttempt = () => {\n if (this.targetAttemptCount !== null) {\n // We can attempt as long as we have not reached our target attempt count.\n return this.currentAttemptCount < this.targetAttemptCount;\n }\n\n // If neither an attempt count or a condition function were defined then we can attempt indefinitely.\n return true;\n };\n\n /**\n * Sets the target attempt count.\n * @param options The behaviour tree options object.\n */\n setTargetAttemptCount = (options: BehaviourTreeOptions) => {\n // Are we dealing with an explicit attempt count or will we be randomly picking an attempt count between the min and max attempt count.\n if (this.attempts !== null) {\n this.targetAttemptCount = this.attempts;\n } else if (this.attemptsMin !== null && this.attemptsMax !== null) {\n // We will be picking a random attempt count between a min and max attempt count, if the optional 'random'\n // behaviour tree function option is defined then we will be using that, otherwise we will fall back to using Math.random.\n const random = typeof options.random === \"function\" ? options.random : Math.random;\n\n // Pick a random attempt count between a min and max attempt count.\n this.targetAttemptCount = Math.floor(\n random() * (this.attemptsMax - this.attemptsMin + 1) + this.attemptsMin\n );\n } else {\n this.targetAttemptCount = null;\n }\n };\n}\n", "import Node from \"../Node\";\nimport Decorator from \"./Decorator\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A Root node.\n * The root node will have a single child.\n */\nexport default class Root extends Decorator {\n /**\n * @param attributes The node attributes.\n * @param child The child node.\n */\n constructor(attributes: Attribute[], child: Node) {\n super(\"root\", attributes, child);\n }\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // If the child has never been updated or is running then we will need to update it now.\n if (this.child.getState() === State.READY || this.child.getState() === State.RUNNING) {\n // Update the child of this node.\n this.child.update(agent, options);\n }\n\n // The state of the root node is the state of its child.\n this.setState(this.child.getState());\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => \"ROOT\";\n}\n", "import Node from \"../Node\";\nimport Decorator from \"./Decorator\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A Succeed node.\n * This node wraps a single child and will always move to the 'SUCCEEDED' state when the child moves to a 'SUCCEEDED' or 'FAILED' state.\n */\nexport default class Succeed extends Decorator {\n /**\n * @param attributes The node attributes.\n * @param child The child node.\n */\n constructor(attributes: Attribute[], child: Node) {\n super(\"succeed\", attributes, child);\n }\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // If the child has never been updated or is running then we will need to update it now.\n if (this.child.getState() === State.READY || this.child.getState() === State.RUNNING) {\n this.child.update(agent, options);\n }\n\n // The state of this node will depend in the state of its child.\n switch (this.child.getState()) {\n case State.RUNNING:\n this.setState(State.RUNNING);\n break;\n\n case State.SUCCEEDED:\n case State.FAILED:\n this.setState(State.SUCCEEDED);\n break;\n\n default:\n this.setState(State.READY);\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => \"SUCCEED\";\n}\n", "import Node from \"../Node\";\n\n/**\n * A leaf node.\n */\nexport default abstract class Leaf extends Node {\n /**\n * Gets whether this node is a leaf node.\n */\n isLeafNode = () => true;\n}\n", "import { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\nimport State, { CompleteState } from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Leaf from \"./Leaf\";\nimport Lookup from \"../../Lookup\";\nimport Attribute from \"../../attributes/Attribute\";\n\n/**\n * An Action leaf node.\n * This represents an immediate or ongoing state of behaviour.\n */\nexport default class Action extends Leaf {\n /**\n * @param attributes The node attributes.\n * @param actionName The action name.\n * @param actionArguments The array of action argument definitions.\n */\n constructor(attributes: Attribute[], private actionName: string, private actionArguments: any[]) {\n super(\"action\", attributes, actionArguments);\n }\n\n /**\n * Whether there is a pending update promise.\n */\n private isUsingUpdatePromise = false;\n\n /**\n * The finished state result of an update promise.\n */\n private updatePromiseStateResult: CompleteState | null = null;\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // If the result of this action depends on an update promise then there is nothing to do until\n // it resolves, unless there has been a value set as a result of the update promise resolving.\n if (this.isUsingUpdatePromise) {\n // Check whether the update promise has resolved with a state value.\n if (this.updatePromiseStateResult) {\n // Set the state of this node to match the state returned by the promise.\n this.setState(this.updatePromiseStateResult);\n }\n\n return;\n }\n\n // Attempt to get the invoker for the action function.\n const actionFuncInvoker = Lookup.getFuncInvoker(agent, this.actionName);\n\n // The action function should be defined.\n if (actionFuncInvoker === null) {\n throw new Error(\n `cannot update action node as the action '${this.actionName}' function is not defined on the agent and has not been registered`\n );\n }\n\n // Call the action function, the result of which may be:\n // - The finished state of this action node.\n // - A promise to return a finished node state.\n // - Undefined if the node should remain in the running state.\n const updateResult = actionFuncInvoker(this.actionArguments) as CompleteState | Promise;\n\n if (updateResult instanceof Promise) {\n updateResult.then(\n (result) => {\n // If 'isUpdatePromisePending' is null then the promise was cleared as it was resolving, probably via an abort of reset.\n if (!this.isUsingUpdatePromise) {\n return;\n }\n\n // Check to make sure the result is a valid finished state.\n if (result !== State.SUCCEEDED && result !== State.FAILED) {\n throw new Error(\n \"action node promise resolved with an invalid value, expected a State.SUCCEEDED or State.FAILED value to be returned\"\n );\n }\n\n // Set pending update promise state result to be processed on next update.\n this.updatePromiseStateResult = result;\n },\n (reason) => {\n // If 'isUpdatePromisePending' is null then the promise was cleared as it was resolving, probably via an abort of reset.\n if (!this.isUsingUpdatePromise) {\n return;\n }\n\n // Just throw whatever was returned as the rejection argument.\n throw new Error(reason);\n }\n );\n\n // This node will be in the 'RUNNING' state until the update promise resolves.\n this.setState(State.RUNNING);\n\n // We are now waiting for the promise returned by the use to resolve before we know what state this node is in.\n this.isUsingUpdatePromise = true;\n } else {\n // Validate the returned value.\n this.validateUpdateResult(updateResult);\n\n // Set the state of this node, this may be undefined, which just means that the node is still in the 'RUNNING' state.\n this.setState(updateResult || State.RUNNING);\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => this.actionName;\n\n /**\n * Reset the state of the node.\n */\n reset = () => {\n // Reset the state of this node.\n this.setState(State.READY);\n\n // There is no longer an update promise that we care about.\n this.isUsingUpdatePromise = false;\n this.updatePromiseStateResult = null;\n };\n\n /**\n * Validate the result of an update function call.\n * @param result The result of an update function call.\n */\n private validateUpdateResult = (result: CompleteState | boolean) => {\n switch (result) {\n case State.SUCCEEDED:\n case State.FAILED:\n case undefined:\n return;\n default:\n throw new Error(\n `action '${this.actionName}' 'onUpdate' returned an invalid response, expected an optional State.SUCCEEDED or State.FAILED value to be returned`\n );\n }\n };\n}\n", "import { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Leaf from \"./Leaf\";\nimport Lookup from \"../../Lookup\";\nimport Attribute from \"../../attributes/Attribute\";\n\n/**\n * A Condition leaf node.\n * This will succeed or fail immediately based on an agent predicate, without moving to the 'RUNNING' state.\n */\nexport default class Condition extends Leaf {\n /**\n * @param attributes The node attributes.\n * @param conditionName The name of the condition function.\n * @param conditionArguments The array of condition argument definitions.\n */\n constructor(attributes: Attribute[], private conditionName: string, private conditionArguments: any[]) {\n super(\"condition\", attributes, conditionArguments);\n }\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // Attempt to get the invoker for the condition function.\n const conditionFuncInvoker = Lookup.getFuncInvoker(agent, this.conditionName);\n\n // The condition function should be defined.\n if (conditionFuncInvoker === null) {\n throw new Error(\n `cannot update condition node as the condition '${this.conditionName}' function is not defined on the agent and has not been registered`\n );\n }\n\n // Call the condition function to determine the state of this node.\n this.setState(!!conditionFuncInvoker(this.conditionArguments) ? State.SUCCEEDED : State.FAILED);\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => this.conditionName;\n}\n", "import Leaf from \"./Leaf\";\nimport State from \"../../State\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { Agent } from \"../../Agent\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A WAIT node.\n * The state of this node will change to SUCCEEDED after a duration of time\n */\nexport default class Wait extends Leaf {\n /**\n * @param attributes The node attributes.\n * @param duration The duration that this node will wait to succeed in milliseconds.\n * @param durationMin The minimum possible duration in milliseconds that this node will wait to succeed.\n * @param durationMax The maximum possible duration in milliseconds that this node will wait to succeed.\n */\n constructor(\n attributes: Attribute[],\n private duration: number | null,\n private durationMin: number | null,\n private durationMax: number | null\n ) {\n super(\"wait\", attributes, []);\n }\n\n /**\n * The time in milliseconds at which this node was first updated.\n */\n private initialUpdateTime: number = 0;\n\n /**\n * The total duration in milliseconds that this node will be waiting for.\n */\n private totalDuration: number | null = null;\n\n /**\n * The duration in milliseconds that this node has been waiting for.\n */\n private waitedDuration: number = 0;\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // If this node is in the READY state then we need to set the initial update time.\n if (this.is(State.READY)) {\n // Set the initial update time.\n this.initialUpdateTime = new Date().getTime();\n\n // Set the initial waited duration.\n this.waitedDuration = 0;\n\n // Are we dealing with an explicit duration or will we be randomly picking a duration between the min and max duration.\n if (this.duration !== null) {\n this.totalDuration = this.duration;\n } else if (this.durationMin !== null && this.durationMax !== null) {\n // We will be picking a random duration between a min and max duration, if the optional 'random' behaviour tree\n // function option is defined then we will be using that, otherwise we will fall back to using Math.random.\n const random = typeof options.random === \"function\" ? options.random : Math.random;\n\n // Pick a random duration between a min and max duration.\n this.totalDuration = Math.floor(\n random() * (this.durationMax - this.durationMin + 1) + this.durationMin\n );\n } else {\n this.totalDuration = null;\n }\n\n // The node is now running until we finish waiting.\n this.setState(State.RUNNING);\n }\n\n // If we have no total duration then this wait node will wait indefinitely until it is aborted.\n if (this.totalDuration === null) {\n return;\n }\n\n // If we have a 'getDeltaTime' function defined as part of our options then we will use it to figure out how long we have waited for.\n if (typeof options.getDeltaTime === \"function\") {\n // Get the delta time.\n const deltaTime = options.getDeltaTime();\n\n // Our delta time must be a valid number and cannot be NaN.\n if (typeof deltaTime !== \"number\" || isNaN(deltaTime)) {\n throw new Error(\"The delta time must be a valid number and not NaN.\");\n }\n\n // Update the amount of time that this node has been waiting for based on the delta time.\n this.waitedDuration += deltaTime * 1000;\n } else {\n // We are not using a delta time, so we will just work out hom much time has passed since the first update.\n this.waitedDuration = new Date().getTime() - this.initialUpdateTime;\n }\n\n // Have we waited long enough?\n if (this.waitedDuration >= this.totalDuration) {\n // We have finished waiting!\n this.setState(State.SUCCEEDED);\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => {\n if (this.duration !== null) {\n return `WAIT ${this.duration}ms`;\n } else if (this.durationMin !== null && this.durationMax !== null) {\n return `WAIT ${this.durationMin}ms-${this.durationMax}ms`;\n } else {\n return \"WAIT\";\n }\n };\n}\n", "import Guard from \"./guards/Guard\";\n\nexport type AttributeDetails = {\n /** The attribute type. */\n type: string;\n\n /** The attribute arguments. */\n args: any[];\n};\n\n/**\n * A base node attribute.\n */\nexport default abstract class Attribute {\n /**\n * @param type The node attribute type.\n * @param args The array of attribute arguments.\n */\n constructor(public type: string, public args: any[]) {}\n\n /**\n * Gets the attribute details.\n */\n abstract getDetails(): TAttributeDetails;\n\n /**\n * Gets whether this attribute is a guard.\n */\n abstract isGuard: () => this is Guard;\n}\n", "import { Agent } from \"../../Agent\";\nimport Attribute, { AttributeDetails } from \"../Attribute\";\n\nexport type GuardAttributeDetails = {\n /** The name of the condition function that determines whether the guard is satisfied. */\n condition: string;\n} & AttributeDetails;\n\n/**\n * A base node guard attribute.\n */\nexport default abstract class Guard extends Attribute {\n /**\n * @param type The node attribute type.\n * @param args The array of decorator argument definitions.\n * @param condition The name of the condition function that determines whether the guard is satisfied.\n */\n constructor(type: string, args: any[], private condition: string) {\n super(type, args);\n }\n\n /**\n * Gets the name of the condition function that determines whether the guard is satisfied.\n */\n getCondition = () => this.condition;\n\n /**\n * Gets whether this attribute is a guard.\n */\n isGuard = () => true;\n\n /**\n * Gets the attribute details.\n */\n getDetails(): GuardAttributeDetails {\n return {\n type: this.type,\n args: this.args,\n condition: this.getCondition()\n };\n }\n\n /**\n * Gets whether the guard is satisfied.\n * @param agent The agent.\n * @returns Whether the guard is satisfied.\n */\n abstract isSatisfied(agent: Agent): boolean;\n}\n", "import Guard from \"./Guard\";\nimport Lookup from \"../../Lookup\";\nimport { Agent } from \"../../Agent\";\n\n/**\n * A WHILE guard which is satisfied as long as the given condition remains true.\n */\nexport default class While extends Guard {\n /**\n * @param condition The name of the condition function that determines whether the guard is satisfied.\n * @param args The array of decorator argument definitions.\n */\n constructor(condition: string, args: any[]) {\n super(\"while\", args, condition);\n }\n\n /**\n * Gets whether the guard is satisfied.\n * @param agent The agent.\n * @returns Whether the guard is satisfied.\n */\n isSatisfied = (agent: Agent) => {\n // Attempt to get the invoker for the condition function.\n const conditionFuncInvoker = Lookup.getFuncInvoker(agent, this.getCondition());\n\n // The condition function should be defined.\n if (conditionFuncInvoker === null) {\n throw new Error(\n `cannot evaluate node guard as the condition '${this.getCondition()}' function is not defined on the agent and has not been registered`\n );\n }\n\n // Call the condition function to determine whether this guard is satisfied.\n return !!conditionFuncInvoker(this.args);\n };\n}\n", "import Guard from \"./Guard\";\nimport Lookup from \"../../Lookup\";\nimport { Agent } from \"../../Agent\";\n\n/**\n * An UNTIL guard which is satisfied as long as the given condition remains false.\n */\nexport default class Until extends Guard {\n /**\n * @param condition The name of the condition function that determines whether the guard is satisfied.\n * @param args The array of decorator argument definitions.\n */\n constructor(condition: string, args: any[]) {\n super(\"until\", args, condition);\n }\n\n /**\n * Gets whether the guard is satisfied.\n * @param agent The agent.\n * @returns Whether the guard is satisfied.\n */\n isSatisfied = (agent: Agent) => {\n // Attempt to get the invoker for the condition function.\n const conditionFuncInvoker = Lookup.getFuncInvoker(agent, this.getCondition());\n\n // The condition function should be defined.\n if (conditionFuncInvoker === null) {\n throw new Error(\n `cannot evaluate node guard as the condition '${this.getCondition()}' function is not defined on the agent and has not been registered`\n );\n }\n\n // Call the condition function to determine whether this guard is satisfied.\n return !!!conditionFuncInvoker(this.args);\n };\n}\n", "import { Agent } from \"../../Agent\";\nimport Attribute, { AttributeDetails } from \"../Attribute\";\n\nexport type CallbackAttributeDetails = {\n /** The name of the agent function that is called. */\n functionName: string;\n} & AttributeDetails;\n\n/**\n * A base node callback attribute.\n */\nexport default abstract class Callback extends Attribute {\n /**\n * @param type The node attribute type.\n * @param args The array of decorator argument definitions.\n * @param functionName The name of the agent function to call.\n */\n constructor(type: string, args: any[], private functionName: string) {\n super(type, args);\n }\n\n /**\n * Gets the name of the agent function to call.\n */\n getFunctionName = () => this.functionName;\n\n /**\n * Gets whether this attribute is a guard.\n */\n isGuard = () => false;\n\n /**\n * Gets the attribute details.\n */\n getDetails(): CallbackAttributeDetails {\n return {\n type: this.type,\n args: this.args,\n functionName: this.getFunctionName()\n };\n }\n\n /**\n * Attempt to call the agent function that this callback refers to.\n * @param agent The agent.\n */\n abstract callAgentFunction: (agent: Agent, isSuccess: boolean, isAborted: boolean) => void;\n}\n", "import Callback from \"./Callback\";\nimport Lookup from \"../../Lookup\";\nimport { Agent } from \"../../Agent\";\n\n/**\n * An ENTRY callback which defines an agent function to call when the associated node is updated and moves out of running state.\n */\nexport default class Entry extends Callback {\n /**\n * @param functionName The name of the agent function to call.\n * @param args The array of callback argument definitions.\n */\n constructor(functionName: string, args: any[]) {\n super(\"entry\", args, functionName);\n }\n\n /**\n * Attempt to call the agent function that this callback refers to.\n * @param agent The agent.\n */\n callAgentFunction = (agent: Agent) => {\n // Attempt to get the invoker for the callback function.\n const callbackFuncInvoker = Lookup.getFuncInvoker(agent, this.getFunctionName());\n\n // The callback function should be defined.\n if (callbackFuncInvoker === null) {\n throw new Error(\n `cannot call entry function '${this.getFunctionName()}' as is not defined on the agent and has not been registered`\n );\n }\n\n // Call the callback function.\n callbackFuncInvoker(this.args);\n };\n}\n", "import Callback from \"./Callback\";\nimport Lookup from \"../../Lookup\";\nimport { Agent } from \"../../Agent\";\n\n/**\n * A STEP callback which defines an agent function to call when the associated node is updated.\n */\nexport default class Step extends Callback {\n /**\n * @param functionName The name of the agent function to call.\n * @param args The array of callback argument definitions.\n */\n constructor(functionName: string, args: any[]) {\n super(\"step\", args, functionName);\n }\n\n /**\n * Attempt to call the agent function that this callback refers to.\n * @param agent The agent.\n */\n callAgentFunction = (agent: Agent) => {\n // Attempt to get the invoker for the callback function.\n const callbackFuncInvoker = Lookup.getFuncInvoker(agent, this.getFunctionName());\n\n // The callback function should be defined.\n if (callbackFuncInvoker === null) {\n throw new Error(\n `cannot call step function '${this.getFunctionName()}' as is not defined on the agent and has not been registered`\n );\n }\n\n // Call the callback function.\n callbackFuncInvoker(this.args);\n };\n}\n", "import Callback from \"./Callback\";\nimport Lookup from \"../../Lookup\";\nimport { Agent } from \"../../Agent\";\n\n/**\n * An EXIT callback which defines an agent function to call when the associated node is updated and moves to a finished state or is aborted.\n */\nexport default class Exit extends Callback {\n /**\n * @param functionName The name of the agent function to call.\n * @param args The array of callback argument definitions.\n */\n constructor(functionName: string, args: any[]) {\n super(\"exit\", args, functionName);\n }\n\n /**\n * Attempt to call the agent function that this callback refers to.\n * @param agent The agent.\n * @param isSuccess Whether the decorated node was left with a success state.\n * @param isAborted Whether the decorated node was aborted.\n */\n callAgentFunction = (agent: Agent, isSuccess: boolean, isAborted: boolean) => {\n // Attempt to get the invoker for the callback function.\n const callbackFuncInvoker = Lookup.getFuncInvoker(agent, this.getFunctionName());\n\n // The callback function should be defined.\n if (callbackFuncInvoker === null) {\n throw new Error(\n `cannot call exit function '${this.getFunctionName()}' as is not defined on the agent and has not been registered`\n );\n }\n\n // Call the callback function\n callbackFuncInvoker([{ value: { succeeded: isSuccess, aborted: isAborted } }, ...this.args]);\n };\n}\n", "import { AnyNodeDefinition, RootNodeDefinition } from \"./BehaviourTreeDefinition\";\nimport GuardPath, { GuardPathPart } from \"./attributes/guards/GuardPath\";\nimport { validateBranchSubtreeLinks } from \"./BehaviourTreeDefinitionValidator\";\nimport { isInteger } from \"./BehaviourTreeDefinitionUtilities\";\nimport Node from \"./nodes/Node\";\nimport Composite from \"./nodes/composite/Composite\";\nimport Decorator from \"./nodes/decorator/Decorator\";\nimport Parallel from \"./nodes/composite/Parallel\";\nimport Selector from \"./nodes/composite/Selector\";\nimport Sequence from \"./nodes/composite/Sequence\";\nimport Lotto from \"./nodes/composite/Lotto\";\nimport Fail from \"./nodes/decorator/Fail\";\nimport Flip from \"./nodes/decorator/Flip\";\nimport Repeat from \"./nodes/decorator/Repeat\";\nimport Retry from \"./nodes/decorator/Retry\";\nimport Root from \"./nodes/decorator/Root\";\nimport Succeed from \"./nodes/decorator/Succeed\";\nimport Action from \"./nodes/leaf/Action\";\nimport Condition from \"./nodes/leaf/Condition\";\nimport Wait from \"./nodes/leaf/Wait\";\nimport Lookup from \"./Lookup\";\nimport Attribute from \"./attributes/Attribute\";\nimport While from \"./attributes/guards/While\";\nimport Until from \"./attributes/guards/Until\";\nimport Entry from \"./attributes/callbacks/Entry\";\nimport Step from \"./attributes/callbacks/Step\";\nimport Exit from \"./attributes/callbacks/Exit\";\n\n/**\n * A type representing any node instance in a behaviour tree.\n */\ntype AnyNode =\n | Root\n | Action\n | Condition\n | Wait\n | Sequence\n | Selector\n | Lotto\n | Parallel\n | Repeat\n | Retry\n | Flip\n | Succeed\n | Fail;\n\n/**\n * A type defining a mapping of root node identifiers to root node definitions.\n */\ntype RootNodeDefinitionMap = { [key: string | symbol]: RootNodeDefinition };\n\n/**\n * A symbol to use as the main root key in any root node mappings.\n */\nconst MAIN_ROOT_NODE_KEY = Symbol(\"__root__\");\n\n/**\n * Build and populate the root nodes based on the provided definition, assuming that the definition has been validated.\n * @param definition The root node definitions.\n * @returns The built and populated root node definitions.\n */\nexport default function buildRootNode(definition: RootNodeDefinition[]): Root {\n // Create a mapping of root node identifers to root node definitions, including globally registered subtree root node definitions.\n const rootNodeDefinitionMap = createRootNodeDefinitionMap(definition);\n\n // Now that we have all of our root node definitons (those part of the tree definition and those globally\n // registered) we should validate the definition. This will also double-check that we dont have any circular\n // dependencies in our branch -> subtree references and that we have no broken branch -> subtree links.\n validateBranchSubtreeLinks(definition, true);\n\n // Create our populated tree of node instances, starting with our main root node.\n const rootNode = nodeFactory(rootNodeDefinitionMap[MAIN_ROOT_NODE_KEY], rootNodeDefinitionMap) as Root;\n\n // Set a guard path on every leaf of the tree to evaluate as part of each update.\n applyLeafNodeGuardPaths(rootNode);\n\n // We only need to return the main root node.\n return rootNode;\n}\n\n/**\n * A factory function which creates a node instance based on the specified definition.\n * @param definition The node definition.\n * @param rootNodeDefinitionMap The mapping of root node identifers to root node definitions, including globally registered subtree root node definitions.\n * @returns A node instance based on the specified definition.\n */\nfunction nodeFactory(definition: AnyNodeDefinition, rootNodeDefinitionMap: RootNodeDefinitionMap): AnyNode {\n // Get the attributes for the node.\n const attributes = nodeAttributesFactory(definition);\n\n // Create the node instance based on the definition type.\n switch (definition.type) {\n case \"root\":\n return new Root(attributes, nodeFactory(definition.child, rootNodeDefinitionMap));\n\n case \"repeat\":\n let iterations: number | null = null;\n let iterationsMin: number | null = null;\n let iterationsMax: number | null = null;\n\n if (Array.isArray(definition.iterations)) {\n iterationsMin = definition.iterations[0];\n iterationsMax = definition.iterations[1];\n } else if (isInteger(definition.iterations)) {\n iterations = definition.iterations!;\n }\n\n return new Repeat(\n attributes,\n iterations,\n iterationsMin,\n iterationsMax,\n nodeFactory(definition.child, rootNodeDefinitionMap)\n );\n\n case \"retry\":\n let attempts: number | null = null;\n let attemptsMin: number | null = null;\n let attemptsMax: number | null = null;\n\n if (Array.isArray(definition.attempts)) {\n attemptsMin = definition.attempts[0];\n attemptsMax = definition.attempts[1];\n } else if (isInteger(definition.attempts)) {\n attempts = definition.attempts!;\n }\n\n return new Retry(\n attributes,\n attempts,\n attemptsMin,\n attemptsMax,\n nodeFactory(definition.child, rootNodeDefinitionMap)\n );\n\n case \"flip\":\n return new Flip(attributes, nodeFactory(definition.child, rootNodeDefinitionMap));\n\n case \"succeed\":\n return new Succeed(attributes, nodeFactory(definition.child, rootNodeDefinitionMap));\n\n case \"fail\":\n return new Fail(attributes, nodeFactory(definition.child, rootNodeDefinitionMap));\n\n case \"sequence\":\n return new Sequence(\n attributes,\n definition.children.map((child) => nodeFactory(child, rootNodeDefinitionMap))\n );\n\n case \"selector\":\n return new Selector(\n attributes,\n definition.children.map((child) => nodeFactory(child, rootNodeDefinitionMap))\n );\n\n case \"parallel\":\n return new Parallel(\n attributes,\n definition.children.map((child) => nodeFactory(child, rootNodeDefinitionMap))\n );\n\n case \"lotto\":\n return new Lotto(\n attributes,\n definition.weights,\n definition.children.map((child) => nodeFactory(child, rootNodeDefinitionMap))\n );\n\n case \"branch\":\n return nodeFactory(rootNodeDefinitionMap[definition.ref].child, rootNodeDefinitionMap);\n\n case \"action\":\n return new Action(attributes, definition.call, definition.args || []);\n\n case \"condition\":\n return new Condition(attributes, definition.call, definition.args || []);\n\n case \"wait\":\n let duration: number | null = null;\n let durationMin: number | null = null;\n let durationMax: number | null = null;\n\n if (Array.isArray(definition.duration)) {\n durationMin = definition.duration[0];\n durationMax = definition.duration[1];\n } else if (isInteger(definition.duration)) {\n duration = definition.duration!;\n }\n\n return new Wait(attributes, duration, durationMin, durationMax);\n }\n}\n\n/**\n * Creates an array of node attribute instances based on the specified node definition.\n * @param definition The node definition.\n * @returns An array of node attribute instances based on the specified node definition.\n */\nfunction nodeAttributesFactory(definition: AnyNodeDefinition): Attribute[] {\n const attributes: Attribute[] = [];\n\n if (definition.while) {\n attributes.push(new While(definition.while.call, definition.while.args ?? []));\n }\n\n if (definition.until) {\n attributes.push(new Until(definition.until.call, definition.until.args ?? []));\n }\n\n if (definition.entry) {\n attributes.push(new Entry(definition.entry.call, definition.entry.args ?? []));\n }\n\n if (definition.step) {\n attributes.push(new Step(definition.step.call, definition.step.args ?? []));\n }\n\n if (definition.exit) {\n attributes.push(new Exit(definition.exit.call, definition.exit.args ?? []));\n }\n\n return attributes;\n}\n\n/**\n * Creates a mapping of root node identifers to root node definitions, mixing in globally registered subtree root node definitions.\n * @param definition The root node definitions.\n * @returns A mapping of root node identifers to root node definitions, including globally registered subtree root node definitions.\n */\nfunction createRootNodeDefinitionMap(definition: RootNodeDefinition[]): RootNodeDefinitionMap {\n // Create a mapping of root node identifers to root node definitions.\n const rootNodeMap: RootNodeDefinitionMap = {};\n\n // Add in any registered subtree root node definitions.\n for (const [name, rootNodeDefinition] of Object.entries(Lookup.getSubtrees())) {\n // The name used when registering the subtree will be used as the root node identifier.\n rootNodeMap[name] = { ...rootNodeDefinition, id: name };\n }\n\n // Populate the map with the root node definitions that were included with the tree definition.\n // We do this after adding any registered subtrees as we want these to take presedence.\n for (const rootNodeDefinition of definition) {\n rootNodeMap[rootNodeDefinition.id ?? MAIN_ROOT_NODE_KEY] = rootNodeDefinition;\n }\n\n return rootNodeMap;\n}\n\n/**\n * Applies a guard path to every leaf of the tree to evaluate as part of each update.\n * @param root The main root tree node.\n */\nfunction applyLeafNodeGuardPaths(root: Root) {\n const nodePaths: Node[][] = [];\n\n const findLeafNodes = (path: Node[], node: Node) => {\n // Add the current node to the path.\n path = path.concat(node);\n\n // Check whether the current node is a leaf node.\n if (node.isLeafNode()) {\n nodePaths.push(path);\n } else {\n (node as Composite | Decorator).getChildren().forEach((child) => findLeafNodes(path, child));\n }\n };\n\n // Find all leaf node paths, starting from the root.\n findLeafNodes([], root);\n\n nodePaths.forEach((path) => {\n // Each node in the current path will have to be assigned a guard path, working from the root outwards.\n for (let depth = 0; depth < path.length; depth++) {\n // Get the node in the path at the current depth.\n const currentNode = path[depth];\n\n // The node may already have been assigned a guard path, if so just skip it.\n if (currentNode.hasGuardPath()) {\n continue;\n }\n\n // Create the guard path for the current node.\n const guardPath = new GuardPath(\n path\n .slice(0, depth + 1)\n .map((node) => ({ node, guards: node.getGuardAttributes() }))\n .filter((details) => details.guards.length > 0)\n );\n\n // Assign the guard path to the current node.\n currentNode.setGuardPath(guardPath);\n }\n });\n}\n", "import State, { AnyState } from \"./State\";\nimport Lookup from \"./Lookup\";\nimport Node from \"./nodes/Node\";\nimport Root from \"./nodes/decorator/Root\";\nimport Composite from \"./nodes/composite/Composite\";\nimport Decorator from \"./nodes/decorator/Decorator\";\nimport { Agent, GlobalFunction } from \"./Agent\";\nimport { CallbackAttributeDetails } from \"./attributes/callbacks/Callback\";\nimport { GuardAttributeDetails } from \"./attributes/guards/Guard\";\nimport { BehaviourTreeOptions } from \"./BehaviourTreeOptions\";\nimport { convertMDSLToJSON } from \"./mdsl/MDSLDefinitionParser\";\nimport { RootNodeDefinition } from \"./BehaviourTreeDefinition\";\nimport { validateDefinition, validateJSONDefinition } from \"./BehaviourTreeDefinitionValidator\";\nimport buildRootNode from \"./BehaviourTreeBuilder\";\nimport { isNullOrUndefined } from \"./BehaviourTreeDefinitionUtilities\";\n\n// Purely for outside inspection of the tree.\nexport type FlattenedTreeNode = {\n id: string;\n type: string;\n caption: string;\n state: AnyState;\n guards: GuardAttributeDetails[];\n callbacks: CallbackAttributeDetails[];\n args: any[];\n parentId: string | null;\n};\n\n/**\n * A representation of a behaviour tree.\n */\nexport class BehaviourTree {\n /**\n * The main root tree node.\n */\n public readonly rootNode: Root;\n\n /**\n * Creates a new instance of the BehaviourTree class.\n * @param definition The behaviour tree definition.\n * @param agent The agent instance that this behaviour tree is modelling behaviour for.\n * @param options The behaviour tree options object.\n */\n constructor(\n definition: string | RootNodeDefinition | RootNodeDefinition[],\n private agent: Agent,\n private options: BehaviourTreeOptions = {}\n ) {\n // The tree definition must be defined.\n if (isNullOrUndefined(definition)) {\n throw new Error(\"tree definition not defined\");\n }\n\n // The agent must be defined and not null.\n if (typeof agent !== \"object\" || agent === null) {\n throw new Error(\"the agent must be an object and not null\");\n }\n\n // We should validate the definition before we try to build the tree nodes.\n const { succeeded, errorMessage, json } = validateDefinition(definition);\n\n // Did our validation fail without error?\n if (!succeeded) {\n throw new Error(`invalid definition: ${errorMessage}`);\n }\n\n // Double check that we did actually get our json definition as part of our definition validtion.\n if (!json) {\n throw new Error(\n \"expected json definition to be returned as part of successful definition validation response\"\n );\n }\n\n try {\n // Create the populated tree of behaviour tree nodes and get the root node.\n this.rootNode = buildRootNode(json!);\n } catch (exception) {\n // There was an issue in trying build and populate the behaviour tree.\n throw new Error(`error building tree: ${(exception as Error).message}`);\n }\n }\n\n /**\n * Gets whether the tree is in the RUNNING state.\n * @returns true if the tree is in the RUNNING state, otherwise false.\n */\n isRunning() {\n return this.rootNode.getState() === State.RUNNING;\n }\n\n /**\n * Gets the current tree state of SUCCEEDED, FAILED, READY or RUNNING.\n * @returns The current tree state.\n */\n getState() {\n return this.rootNode.getState();\n }\n\n /**\n * Step the tree.\n * 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.\n * 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\n * 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.\n *\n * 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.\n */\n step() {\n // If the root node has already been stepped to completion then we need to reset it.\n if (this.rootNode.getState() === State.SUCCEEDED || this.rootNode.getState() === State.FAILED) {\n this.rootNode.reset();\n }\n\n try {\n this.rootNode.update(this.agent, this.options);\n } catch (exception) {\n throw new Error(`error stepping tree: ${(exception as Error).message}`);\n }\n }\n\n /**\n * Resets the tree from the root node outwards to each nested node, giving each a state of READY.\n */\n reset() {\n this.rootNode.reset();\n }\n\n /**\n * Gets the flattened details of every node in the tree.\n * @returns The flattened details of every node in the tree.\n */\n getFlattenedNodeDetails(): FlattenedTreeNode[] {\n // Create an empty flattened array of tree nodes.\n const flattenedTreeNodes: FlattenedTreeNode[] = [];\n\n /**\n * Helper function to process a node instance and push details into the flattened tree nodes array.\n * @param node The current node.\n * @param parentUid The UID of the node parent, or null if the node is the main root node.\n */\n const processNode = (node: Node, parentUid: string | null) => {\n // Get the guard and callback attribute details for this node.\n const guards = node\n .getAttributes()\n .filter((attribute) => attribute.isGuard())\n .map((attribute) => attribute.getDetails()) as GuardAttributeDetails[];\n const callbacks = node\n .getAttributes()\n .filter((attribute) => !attribute.isGuard())\n .map((attribute) => attribute.getDetails()) as CallbackAttributeDetails[];\n\n // Push the current node into the flattened nodes array.\n flattenedTreeNodes.push({\n id: node.getUid(),\n type: node.getType(),\n caption: node.getName(),\n state: node.getState(),\n guards,\n callbacks,\n args: node.getArguments(),\n parentId: parentUid\n });\n\n // Process each of the nodes children if it is not a leaf node.\n if (!node.isLeafNode()) {\n (node as Composite | Decorator)\n .getChildren()\n .forEach((child) => processNode(child, (node as Composite | Decorator).getUid()));\n }\n };\n\n // Convert the nested node structure into a flattened array of node details.\n processNode(this.rootNode, null);\n\n return flattenedTreeNodes;\n }\n\n /**\n * Registers the action/condition/guard/callback function or subtree with the given name.\n * @param name The name of the function or subtree to register.\n * @param value The function or subtree definition to register.\n */\n static register(name: string, value: GlobalFunction | string | RootNodeDefinition) {\n // Are we going to register a action/condition/guard/callback function?\n if (typeof value === \"function\") {\n Lookup.setFunc(name, value);\n return;\n }\n\n // We are not registering an action/condition/guard/callback function, so we must be registering a subtree.\n if (typeof value === \"string\") {\n let rootNodeDefinitions: RootNodeDefinition[];\n\n // We will assume that any string passed in will be a mdsl definition.\n try {\n rootNodeDefinitions = convertMDSLToJSON(value);\n } catch (exception) {\n throw new Error(`error registering definition, invalid MDSL: ${(exception as Error).message}`);\n }\n\n // This function should only ever be called with a definition containing a single unnamed root node.\n if (rootNodeDefinitions.length != 1 || rootNodeDefinitions[0].id !== null) {\n throw new Error(\"error registering definition: expected a single unnamed root node\");\n }\n\n try {\n // We should validate the subtree as we don't want invalid subtrees available via the lookup.\n const { succeeded, errorMessage } = validateJSONDefinition(rootNodeDefinitions[0]);\n\n // Did our validation fail without error?\n if (!succeeded) {\n throw new Error(errorMessage);\n }\n } catch (exception) {\n throw new Error(`error registering definition: ${(exception as Error).message}`);\n }\n\n // Everything seems hunky-dory, register the subtree.\n Lookup.setSubtree(name, rootNodeDefinitions[0]);\n } else if (typeof value === \"object\" && !Array.isArray(value)) {\n // We will assume that any object passed in is a root node definition.\n\n try {\n // We should validate the subtree as we don't want invalid subtrees available via the lookup.\n const { succeeded, errorMessage } = validateJSONDefinition(value);\n\n // Did our validation fail without error?\n if (!succeeded) {\n throw new Error(errorMessage);\n }\n } catch (exception) {\n throw new Error(`error registering definition: ${(exception as Error).message}`);\n }\n\n // Everything seems hunky-dory, register the subtree.\n Lookup.setSubtree(name, value);\n } else {\n throw new Error(\"unexpected value, expected string mdsl definition, root node json definition or function\");\n }\n }\n\n /**\n * Unregisters the registered action/condition/guard/callback function or subtree with the given name.\n * @param name The name of the registered action/condition/guard/callback function or subtree to unregister.\n */\n static unregister(name: string): void {\n Lookup.remove(name);\n }\n\n /**\n * Unregister all registered action/condition/guard/callback functions and subtrees.\n */\n static unregisterAll(): void {\n Lookup.empty();\n }\n}\n"], + "mappings": "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", "names": ["Participant", "isNullOrUndefined", "Lotto", "createLotto", "State", "createLotto"] } diff --git a/src/BehaviourTree.ts b/src/BehaviourTree.ts index b6174f4..4e9dbfd 100644 --- a/src/BehaviourTree.ts +++ b/src/BehaviourTree.ts @@ -57,16 +57,23 @@ export class BehaviourTree { } // We should validate the definition before we try to build the tree nodes. - const { succeeded, errorMessage } = validateDefinition(definition); + const { succeeded, errorMessage, json } = validateDefinition(definition); // Did our validation fail without error? if (!succeeded) { throw new Error(`invalid definition: ${errorMessage}`); } + // Double check that we did actually get our json definition as part of our definition validtion. + if (!json) { + throw new Error( + "expected json definition to be returned as part of successful definition validation response" + ); + } + try { - // Parse the behaviour tree definition, create the populated tree of behaviour tree nodes, and get the root. - this.rootNode = this._createRootNode(definition); + // Create the populated tree of behaviour tree nodes and get the root node. + this.rootNode = buildRootNode(json!); } catch (exception) { // There was an issue in trying build and populate the behaviour tree. throw new Error(`error building tree: ${(exception as Error).message}`); @@ -245,18 +252,4 @@ export class BehaviourTree { static unregisterAll(): void { Lookup.empty(); } - - /** - * Parses a behaviour tree definition and creates a tree of behaviour tree nodes populated at a root. - * @param {string | RootNodeDefinition | RootNodeDefinition[]} definition The behaviour tree definition. - * @returns The root behaviour tree node. - */ - private _createRootNode(definition: string | RootNodeDefinition | RootNodeDefinition[]): Root { - // Our definition will have to be converted to JSON if it is a MDSL string. - // TODO convertMDSLToJSON is called TWICE, once for validation and once here. Maybe return the JSON as part of the validation result? - const resolvedDefinition = typeof definition === "string" ? convertMDSLToJSON(definition) : definition; - - // Build and populate the root node. - return buildRootNode(Array.isArray(resolvedDefinition) ? resolvedDefinition : [resolvedDefinition]); - } } diff --git a/src/BehaviourTreeDefinitionValidator.ts b/src/BehaviourTreeDefinitionValidator.ts index 52a75b9..f2ffca2 100644 --- a/src/BehaviourTreeDefinitionValidator.ts +++ b/src/BehaviourTreeDefinitionValidator.ts @@ -14,6 +14,10 @@ export type DefinitionValidationResult = { * A string containing the error message if validation did not succeed. */ errorMessage?: string; + /** + * The definition as json if the validation was successful, or undefined if validation did not succeed. + */ + json?: RootNodeDefinition[]; }; /** @@ -47,7 +51,7 @@ export function validateDefinition(definition: any): DefinitionValidationResult * @param definition The behaviour tree definition in the form of MDSL. * @returns An object representing the result of validating the given tree definition. */ -export function validateMDSLDefinition(definition: string): DefinitionValidationResult { +function validateMDSLDefinition(definition: string): DefinitionValidationResult { let rootNodeDefinitions; // The first thing the we need to do is to attempt to convert our MDSL into JSON. @@ -89,7 +93,10 @@ export function validateMDSLDefinition(definition: string): DefinitionValidation } // Our definition was valid! - return { succeeded: true }; + return { + succeeded: true, + json: rootNodeDefinitions + }; } /** @@ -148,7 +155,10 @@ export function validateJSONDefinition( } // Our definition was valid! - return { succeeded: true }; + return { + succeeded: true, + json: rootNodeDefinitions + }; } /** From 1ad9ec10682f6e6f6471592de1d4d26a2e46cc50 Mon Sep 17 00:00:00 2001 From: Nikolas Howard Date: Sat, 17 Feb 2024 19:06:19 +0000 Subject: [PATCH 27/48] tidying --- dist/BehaviourTree.d.ts | 2 +- dist/bundle.js.map | 4 ++-- dist/index.js.map | 4 ++-- src/BehaviourTree.ts | 4 ++-- 4 files changed, 7 insertions(+), 7 deletions(-) diff --git a/dist/BehaviourTree.d.ts b/dist/BehaviourTree.d.ts index 8289ddf..daae1a4 100644 --- a/dist/BehaviourTree.d.ts +++ b/dist/BehaviourTree.d.ts @@ -27,7 +27,7 @@ export declare class BehaviourTree { readonly rootNode: Root; /** * Creates a new instance of the BehaviourTree class. - * @param definition The behaviour tree definition. + * @param definition The behaviour tree definition as either an MDSL string, root node definition object or array of root node definition objects. * @param agent The agent instance that this behaviour tree is modelling behaviour for. * @param options The behaviour tree options object. */ diff --git a/dist/bundle.js.map b/dist/bundle.js.map index 5ea67a0..49b5ee3 100644 --- a/dist/bundle.js.map +++ b/dist/bundle.js.map @@ -1,7 +1,7 @@ { "version": 3, "sources": ["../node_modules/lotto-draw/dist/Participant.js", "../node_modules/lotto-draw/dist/Utilities.js", "../node_modules/lotto-draw/dist/Lotto.js", "../node_modules/lotto-draw/dist/createLotto.js", "../node_modules/lotto-draw/dist/index.js", "../src/index.ts", "../src/State.ts", "../src/BehaviourTreeDefinitionUtilities.ts", "../src/mdsl/MDSLUtilities.ts", "../src/mdsl/MDSLNodeArgumentParser.ts", "../src/mdsl/MDSLNodeAttributeParser.ts", "../src/mdsl/MDSLDefinitionParser.ts", "../src/BehaviourTreeDefinitionValidator.ts", "../src/Lookup.ts", "../src/attributes/guards/GuardUnsatisifedException.ts", "../src/attributes/guards/GuardPath.ts", "../src/nodes/Node.ts", "../src/nodes/composite/Composite.ts", "../src/nodes/composite/Parallel.ts", "../src/nodes/composite/Selector.ts", "../src/nodes/composite/Sequence.ts", "../src/nodes/composite/Lotto.ts", "../src/nodes/decorator/Decorator.ts", "../src/nodes/decorator/Fail.ts", "../src/nodes/decorator/Flip.ts", "../src/nodes/decorator/Repeat.ts", "../src/nodes/decorator/Retry.ts", "../src/nodes/decorator/Root.ts", "../src/nodes/decorator/Succeed.ts", "../src/nodes/leaf/Leaf.ts", "../src/nodes/leaf/Action.ts", "../src/nodes/leaf/Condition.ts", "../src/nodes/leaf/Wait.ts", "../src/attributes/Attribute.ts", "../src/attributes/guards/Guard.ts", "../src/attributes/guards/While.ts", "../src/attributes/guards/Until.ts", "../src/attributes/callbacks/Callback.ts", "../src/attributes/callbacks/Entry.ts", "../src/attributes/callbacks/Step.ts", "../src/attributes/callbacks/Exit.ts", "../src/BehaviourTreeBuilder.ts", "../src/BehaviourTree.ts"], - "sourcesContent": ["\"use strict\";\r\nObject.defineProperty(exports, \"__esModule\", { value: true });\r\nexports.Participant = void 0;\r\n/**\r\n * A participant that holds a number of tickets.\r\n */\r\nvar Participant = /** @class */ (function () {\r\n /**\r\n * Creates an instance of the Participant class.\r\n * @param participant The actual participant.\r\n * @param tickets The number of tickets held by the participant.\r\n */\r\n function Participant(participant, tickets) {\r\n if (tickets === void 0) { tickets = 1; }\r\n this._participant = participant;\r\n this._tickets = tickets;\r\n }\r\n Object.defineProperty(Participant.prototype, \"participant\", {\r\n /** Gets the actual participant. */\r\n get: function () {\r\n return this._participant;\r\n },\r\n enumerable: false,\r\n configurable: true\r\n });\r\n Object.defineProperty(Participant.prototype, \"tickets\", {\r\n /** Gets or sets the number of tickets held by the participant. */\r\n get: function () {\r\n return this._tickets;\r\n },\r\n set: function (value) {\r\n this._tickets = value;\r\n },\r\n enumerable: false,\r\n configurable: true\r\n });\r\n return Participant;\r\n}());\r\nexports.Participant = Participant;\r\n", "\"use strict\";\r\nObject.defineProperty(exports, \"__esModule\", { value: true });\r\nexports.isNaturalNumber = exports.isNullOrUndefined = void 0;\r\n/**\r\n * Gets whether the value provided is null or undefined.\r\n * @param value The value to check.\r\n * @returns Whether the value provided is null or undefined.\r\n */\r\nfunction isNullOrUndefined(value) {\r\n return value === null || value === undefined;\r\n}\r\nexports.isNullOrUndefined = isNullOrUndefined;\r\n/**\r\n * Gets whether the value provided is a natural number.\r\n * @param value The value to check.\r\n * @returns Whether the value provided is a natural number.\r\n */\r\nfunction isNaturalNumber(value) {\r\n return typeof value === \"number\" && value >= 1 && Math.floor(value) === value;\r\n}\r\nexports.isNaturalNumber = isNaturalNumber;\r\n", "\"use strict\";\r\nObject.defineProperty(exports, \"__esModule\", { value: true });\r\nexports.Lotto = void 0;\r\nvar Participant_1 = require(\"./Participant\");\r\nvar Utilities_1 = require(\"./Utilities\");\r\n/**\r\n * Represents a lotto consisting of a number of pickable ticket-holding participants.\r\n */\r\nvar Lotto = /** @class */ (function () {\r\n /**\r\n * Creates a new instance of Lotto.\r\n * @param customRandom The custom RNG to use in place of Math.random().\r\n */\r\n function Lotto(customRandom) {\r\n /** The array of participants that are holding tickets in the lotto. */\r\n this._participants = [];\r\n this._customRandom = customRandom;\r\n }\r\n /**\r\n * Adds a participant with the specified number of tickets, or adds to the participant ticket count if the participant already holds tickets.\r\n * @param participant The participant to add or to increase the ticket count for if they already hold tickets.\r\n * @param tickets The number of tickets, defaults to 1.\r\n * @returns The Lotto instance.\r\n */\r\n Lotto.prototype.add = function (participant, tickets) {\r\n if (tickets === void 0) { tickets = 1; }\r\n // Check that we have a valid ticket count.\r\n if (!(0, Utilities_1.isNaturalNumber)(tickets)) {\r\n throw new Error(\"tickets value must be a natural number\");\r\n }\r\n // Check whether this participant has already been added.\r\n var existingParticipant = this._participants.find(function (part) { return part.participant === participant; });\r\n if (existingParticipant) {\r\n // The participant has already been added to the lotto so just add to their ticket count.\r\n existingParticipant.tickets += tickets;\r\n }\r\n else {\r\n // The participant is not part of the lotto so we should add them.\r\n this._participants.push(new Participant_1.Participant(participant, tickets));\r\n }\r\n return this;\r\n };\r\n /**\r\n * Removes the specified number of tickets for the given participant from the draw, or all tickets if a ticket number is not defined.\r\n * @param participant The participant to remove tickets for.\r\n * @param tickets The number of tickets to remove, or undefined if all tickets are to be removed.\r\n * @returns The Lotto instance.\r\n */\r\n Lotto.prototype.remove = function (participant, tickets) {\r\n // Attempt to get the existing participant.\r\n var existingParticipant = this._participants.find(function (part) { return part.participant === participant; });\r\n // There is nothing to do if the specified participant isn't even part of the lotto.\r\n if (!existingParticipant) {\r\n return this;\r\n }\r\n // Check whether a tickets value was given.\r\n if (tickets !== undefined) {\r\n // Check that we have a valid ticket count.\r\n if (!(0, Utilities_1.isNaturalNumber)(tickets)) {\r\n throw new Error(\"tickets value must be a natural number\");\r\n }\r\n existingParticipant.tickets -= tickets;\r\n // If the participant no longer holds any tickets then they should be removed.\r\n if (existingParticipant.tickets < 1) {\r\n this._participants = this._participants.filter(function (part) { return part !== existingParticipant; });\r\n }\r\n }\r\n else {\r\n // We are removing all tickets for the participant so just remove them from the lotto.\r\n this._participants = this._participants.filter(function (part) { return part !== existingParticipant; });\r\n }\r\n return this;\r\n };\r\n /**\r\n * Draw a winning ticket and return the participant that holds the ticket.\r\n * @param options The draw options.\r\n * @returns The participant that holds the winning ticket.\r\n */\r\n Lotto.prototype.draw = function (options) {\r\n if (options === void 0) { options = {}; }\r\n // If we have no participants then just return null.\r\n if (this._participants.length === 0) {\r\n return null;\r\n }\r\n var redrawable = (0, Utilities_1.isNullOrUndefined)(options.redrawable) ? true : options.redrawable;\r\n var pickable = [];\r\n this._participants.forEach(function (_a) {\r\n var participant = _a.participant, tickets = _a.tickets;\r\n for (var ticketCount = 0; ticketCount < tickets; ticketCount++) {\r\n pickable.push(participant);\r\n }\r\n });\r\n var random;\r\n // We need a random floating-point number between 0 (inclusive) and 1 to scale up to pick our winner.\r\n // If a custom random function exists then we should use that or fall back to Math.random().\r\n if (this._customRandom) {\r\n // Call our custom random function to get a random floating-point number.\r\n random = this._customRandom();\r\n // Verify that the result of calling our custom random function is a number between 0 (inclusive) and 1.\r\n if (typeof random !== \"number\" || random < 0 || random >= 1) {\r\n throw new Error(\"the 'random' function provided did not return a number between 0 (inclusive) and 1\");\r\n }\r\n }\r\n else {\r\n // No custom random function was defined so just use good ol' Math.random().\r\n random = Math.random();\r\n }\r\n // Pick a winning participant.\r\n var winner = pickable[Math.floor(random * pickable.length)];\r\n // If the ticket isn't redrawable then we should remove a ticket from the winning participants ticket count.\r\n if (!redrawable) {\r\n this.remove(winner, 1);\r\n }\r\n // Return the winning participant.\r\n return winner;\r\n };\r\n /**\r\n * Draws multiple winning tickets and return an array of the participants that hold the winning tickets.\r\n * @param tickets The number of winning tickets to draw.\r\n * @param options The draw multiple options.\r\n * @returns An array of the participants that hold the winning tickets.\r\n */\r\n Lotto.prototype.drawMultiple = function (tickets, options) {\r\n if (options === void 0) { options = {}; }\r\n var uniqueResults = (0, Utilities_1.isNullOrUndefined)(options.unique) ? false : options.unique;\r\n // Handle cases where the user has asked for zero tickets (no idea why they would do this be we should trust them).\r\n if (tickets === 0) {\r\n return [];\r\n }\r\n // Now that we know out tickets value is not zero we should check that it is a valid natural number.\r\n if (!(0, Utilities_1.isNaturalNumber)(tickets)) {\r\n throw new Error(\"tickets value must be a natural number\");\r\n }\r\n var result = [];\r\n // Keep drawing tickets until we either reach the number of required tickets or we simply run out of tickets to draw.\r\n // We can run out of tickets to draw if 'options.redrawable' is explicity 'false' or we just had no participants when 'drawMultiple' was called.\r\n while (result.length < tickets && this._participants.length > 0) {\r\n result.push(this.draw(options));\r\n }\r\n // If the 'unique' draw option is set then we need to remove duplicates from the result list.\r\n if (uniqueResults) {\r\n // Create an array to store our unique results.\r\n var unique = [];\r\n // Iterate over all of our participants (with potential duplicates) and populate our array of unique values.\r\n for (var _i = 0, result_1 = result; _i < result_1.length; _i++) {\r\n var participant = result_1[_i];\r\n if (unique.indexOf(participant) === -1) {\r\n unique.push(participant);\r\n }\r\n }\r\n result = unique;\r\n }\r\n return result;\r\n };\r\n return Lotto;\r\n}());\r\nexports.Lotto = Lotto;\r\n", "\"use strict\";\r\nObject.defineProperty(exports, \"__esModule\", { value: true });\r\nexports.createLotto = void 0;\r\nvar Lotto_1 = require(\"./Lotto\");\r\n/**\r\n * A function that creates and returns a Lotto instance.\r\n * @param participantsOrOptions An array of initial participants or options relating to the creation of a Lotto instance.\r\n * @returns A new Lotto instance.\r\n */\r\nfunction createLotto(participantsOrOptions) {\r\n // If no initial participants or lotto options were provided as an argument then we can just return a new lotto instance now.\r\n if (!participantsOrOptions) {\r\n return new Lotto_1.Lotto();\r\n }\r\n // Check whether we were provided with an array of initial participants or a lotto options object.\r\n if (Array.isArray(participantsOrOptions)) {\r\n // We are dealing with a pre-defined array of participants.\r\n var participants = participantsOrOptions;\r\n var lotto_1 = new Lotto_1.Lotto();\r\n // If the lotto participants have been defined upfront then we will need to add them all to our lotto instance now.\r\n participants.forEach(function (_a) {\r\n var participant = _a[0], tokens = _a[1];\r\n return lotto_1.add(participant, tokens);\r\n });\r\n // Return the Lotto instance.\r\n return lotto_1;\r\n }\r\n else {\r\n // We are dealing with some lotto options.\r\n var random = participantsOrOptions.random, participants = participantsOrOptions.participants;\r\n // Create a Lotto instance passing the custom RNG function to use in place of Math.random() (which could be undefined).\r\n var lotto_2 = new Lotto_1.Lotto(random);\r\n // If the lotto participants have been defined upfront as part of the options then we will need to add them all to our lotto instance now.\r\n if (participants) {\r\n participants.forEach(function (_a) {\r\n var participant = _a[0], tokens = _a[1];\r\n return lotto_2.add(participant, tokens);\r\n });\r\n }\r\n // Return the Lotto instance.\r\n return lotto_2;\r\n }\r\n}\r\nexports.createLotto = createLotto;\r\n", "\"use strict\";\r\nObject.defineProperty(exports, \"__esModule\", { value: true });\r\nvar createLotto_1 = require(\"./createLotto\");\r\nexports.default = createLotto_1.createLotto;\r\n", "import State from \"./State\";\nimport { validateDefinition } from \"./BehaviourTreeDefinitionValidator\";\nimport { convertMDSLToJSON } from \"./mdsl/MDSLDefinitionParser\";\nimport { BehaviourTree, FlattenedTreeNode } from \"./BehaviourTree\";\nimport { BehaviourTreeOptions } from \"./BehaviourTreeOptions\";\n\nexport { BehaviourTree, State, convertMDSLToJSON, validateDefinition };\nexport type { FlattenedTreeNode, BehaviourTreeOptions };\n", "/**\n * Enumeration of node state types.\n */\nexport enum State {\n READY = \"mistreevous.ready\",\n RUNNING = \"mistreevous.running\",\n SUCCEEDED = \"mistreevous.succeeded\",\n FAILED = \"mistreevous.failed\"\n}\n\nexport { State as default };\n\nexport type CompleteState = State.SUCCEEDED | State.FAILED;\nexport type AnyState = State.READY | State.RUNNING | CompleteState;\n", "import {\n NodeDefinition,\n RootNodeDefinition,\n DecoratorNodeDefinition,\n CompositeNodeDefinition,\n AnyNodeDefinition,\n BranchNodeDefinition\n} from \"./BehaviourTreeDefinition\";\n\n/**\n * A type guard function that returns true if the specified node satisfies the RootNodeDefinition type.\n * @param node The node.\n * @returns A value of true if the specified node satisfies the RootNodeDefinition type.\n */\nexport function isRootNode(node: NodeDefinition): node is RootNodeDefinition {\n return node.type === \"root\";\n}\n\n/**\n * A type guard function that returns true if the specified node satisfies the BranchNodeDefinition type.\n * @param node The node.\n * @returns A value of true if the specified node satisfies the BranchNodeDefinition type.\n */\nexport function isBranchNode(node: NodeDefinition): node is BranchNodeDefinition {\n return node.type === \"branch\";\n}\n\n/**\n * A type guard function that returns true if the specified node satisfies the NodeDefinition type.\n * @param node The node.\n * @returns A value of true if the specified node satisfies the NodeDefinition type.\n */\nexport function isLeafNode(node: NodeDefinition): node is NodeDefinition {\n return [\"branch\", \"action\", \"condition\", \"wait\"].includes(node.type);\n}\n\n/**\n * A type guard function that returns true if the specified node satisfies the DecoratorNodeDefinition type.\n * @param node The node.\n * @returns A value of true if the specified node satisfies the DecoratorNodeDefinition type.\n */\nexport function isDecoratorNode(node: NodeDefinition): node is DecoratorNodeDefinition {\n return [\"root\", \"repeat\", \"retry\", \"flip\", \"succeed\", \"fail\"].includes(node.type);\n}\n\n/**\n * A type guard function that returns true if the specified node satisfies the CompositeNodeDefinition type.\n * @param node The node.\n * @returns A value of true if the specified node satisfies the CompositeNodeDefinition type.\n */\nexport function isCompositeNode(node: NodeDefinition): node is CompositeNodeDefinition {\n return [\"sequence\", \"selector\", \"lotto\", \"parallel\"].includes(node.type);\n}\n\n/**\n * Flatten a node definition into an array of all of its nested node definitions.\n * @param nodeDefinition The node definition to flatten.\n * @returns An array of all of nested node definitions.\n */\nexport function flattenDefinition(nodeDefinition: AnyNodeDefinition): AnyNodeDefinition[] {\n const nodes: AnyNodeDefinition[] = [];\n\n const processNode = (currentNodeDefinition: AnyNodeDefinition) => {\n nodes.push(currentNodeDefinition);\n\n if (isCompositeNode(currentNodeDefinition)) {\n currentNodeDefinition.children.forEach(processNode);\n } else if (isDecoratorNode(currentNodeDefinition)) {\n processNode(currentNodeDefinition.child);\n }\n };\n\n processNode(nodeDefinition);\n\n return nodes;\n}\n\n/**\n * Determines whether the passed value is an integer.\n * @param value The value to check.\n * @returns Whether the passed value is an integer.\n */\nexport function isInteger(value: unknown): boolean {\n return typeof value === \"number\" && Math.floor(value) === value;\n}\n\n/**\n * Determines whether the passed value is null or undefined.\n * @param value The value to check.\n * @returns Whether the passed value is null or undefined.\n */\nexport function isNullOrUndefined(value: unknown): boolean {\n return typeof value === \"undefined\" || value === null;\n}\n", "/**\n * A type defining an object that holds a reference to substitued string literals parsed from the definition.\n */\nexport type StringLiteralPlaceholders = { [key: string]: string };\n\n/**\n * Pop the next raw token from the specified array of tokens and throw an error if it wasn't the expected one.\n * @param tokens The array of tokens.\n * @param expected An optional string or array or items, one of which must match the next popped token.\n * @returns The popped token.\n */\nexport function popAndCheck(tokens: string[], expected?: string | string[]): string {\n // Get and remove the next token.\n const popped = tokens.shift();\n\n // We were expecting another token but there aren't any.\n if (popped === undefined) {\n throw new Error(\"unexpected end of definition\");\n }\n\n // Do we have an expected token/tokens array?\n if (expected != undefined) {\n // Get an array of expected values, if the popped token matches any then we are all good.\n const expectedValues = typeof expected === \"string\" ? [expected] : expected;\n\n // Check whether the popped token matches at least one of our expected items.\n var tokenMatchesExpectation = expectedValues.some((item) => popped.toUpperCase() === item.toUpperCase());\n\n // Throw an error if the popped token didn't match any of our expected items.\n if (!tokenMatchesExpectation) {\n const expectationString = expectedValues.map((item) => \"'\" + item + \"'\").join(\" or \");\n throw new Error(\"unexpected token found. Expected \" + expectationString + \" but got '\" + popped + \"'\");\n }\n }\n\n // Return the popped token.\n return popped;\n}\n\n/**\n * Swaps out any node/attribute argument string literals with placeholders.\n * @param definition The definition.\n * @returns An object containing a mapping of placeholders to original string values as well as the processed definition string.\n */\nexport function substituteStringLiterals(definition: string): {\n placeholders: StringLiteralPlaceholders;\n processedDefinition: string;\n} {\n // Create an object to hold the mapping of placeholders to original string values.\n const placeholders: StringLiteralPlaceholders = {};\n\n // Replace any string literals wrapped with double quotes in our definition with placeholders to be processed later.\n const processedDefinition = definition.replace(/\\\"(\\\\.|[^\"\\\\])*\\\"/g, (match) => {\n var strippedMatch = match.substring(1, match.length - 1);\n var placeholder = Object.keys(placeholders).find((key) => placeholders[key] === strippedMatch);\n\n // If we have no existing string literal match then create a new placeholder.\n if (!placeholder) {\n placeholder = `@@${Object.keys(placeholders).length}@@`;\n placeholders[placeholder] = strippedMatch;\n }\n\n return placeholder;\n });\n\n return { placeholders, processedDefinition };\n}\n\n/**\n * Parse the tree definition into an array of raw tokens.\n * @param definition The definition.\n * @returns An array of tokens parsed from the definition.\n */\nexport function parseTokensFromDefinition(definition: string): string[] {\n // Add some space around various important characters so that they can be plucked out easier as individual tokens.\n definition = definition.replace(/\\(/g, \" ( \");\n definition = definition.replace(/\\)/g, \" ) \");\n definition = definition.replace(/\\{/g, \" { \");\n definition = definition.replace(/\\}/g, \" } \");\n definition = definition.replace(/\\]/g, \" ] \");\n definition = definition.replace(/\\[/g, \" [ \");\n definition = definition.replace(/\\,/g, \" , \");\n\n // Split the definition into raw token form and return it.\n return definition.replace(/\\s+/g, \" \").trim().split(\" \");\n}\n", "import { StringLiteralPlaceholders, popAndCheck } from \"./MDSLUtilities\";\n\n/**\n * A type representing any node function argument.\n */\ntype Argument = {\n /**\n * The argument value.\n */\n value: T;\n /**\n * The argument type, used for validation.\n */\n type: string;\n};\n\ntype NullArgument = Argument & {\n type: \"null\";\n};\n\ntype BooleanArgument = Argument & {\n type: \"boolean\";\n};\n\ntype NumberArgument = Argument & {\n type: \"number\";\n /**\n * A flag defining whether the number argument value is a valid integer. (used for validation)\n */\n isInteger: boolean;\n};\n\ntype StringPlaceholderArgument = Argument & {\n type: \"string\";\n};\n\ntype IdentifierArgument = Argument & {\n type: \"identifier\";\n};\n\n/**\n * A type representing a reference to any node function argument.\n */\ntype AnyArgument = NullArgument | BooleanArgument | NumberArgument | StringPlaceholderArgument | IdentifierArgument;\n\n/**\n * Parse an array of argument definitions from the specified tokens array.\n * @param tokens The array tokens to parse the argument definitions from.\n * @param stringArgumentPlaceholders The mapping of string literal node argument placeholders to original values.\n * @param argumentValidator The argument validator function.\n * @param validationFailedMessage The exception message to throw if argument validation fails.\n * @returns An array of argument definitions parsed from the specified tokens array.\n */\nexport function parseArgumentTokens(\n tokens: string[],\n stringArgumentPlaceholders: StringLiteralPlaceholders\n): AnyArgument[] {\n const argumentList: AnyArgument[] = [];\n\n // If the next token is not a '[' or '(' then we have no arguments to parse.\n if (![\"[\", \"(\"].includes(tokens[0])) {\n return argumentList;\n }\n\n // Any lists of arguments will always be wrapped in '[]' for node arguments or '()' for attribute arguments.\n // We are looking for a '[' or '(' opener that wraps the argument tokens and the relevant closer.\n const closingToken = popAndCheck(tokens, [\"[\", \"(\"]) === \"[\" ? \"]\" : \")\";\n\n const argumentListTokens: string[] = [];\n\n // Grab all tokens between the '[' and ']' or '(' and ')'.\n while (tokens.length && tokens[0] !== closingToken) {\n // The next token is part of our arguments list.\n argumentListTokens.push(tokens.shift()!);\n }\n\n // Validate the order of the argument tokens. Each token must either be a ',' or a single argument that satisfies the validator.\n argumentListTokens.forEach((token, index) => {\n // Get whether this token should be an actual argument.\n const shouldBeArgumentToken = !(index & 1);\n\n // If the current token should be an actual argument then validate it, otherwise it should be a ',' token.\n if (shouldBeArgumentToken) {\n // Get the argument definition.\n const argumentDefinition = getArgumentDefinition(token, stringArgumentPlaceholders);\n\n // This is a valid argument!\n argumentList.push(argumentDefinition);\n } else {\n // The current token should be a ',' token.\n if (token !== \",\") {\n throw new Error(`invalid argument list, expected ',' or ']' but got '${token}'`);\n }\n }\n });\n\n // The arguments list should terminate with a ']' or ')' token, depending on the opener.\n popAndCheck(tokens, closingToken);\n\n // Return the arguments.\n return argumentList;\n}\n\n/**\n * Gets an argument value definition.\n * @param token The argument token.\n * @param stringArgumentPlaceholders The mapping of string literal node argument placeholders to original values.\n * @returns An argument value definition.\n */\nfunction getArgumentDefinition(token: string, stringArgumentPlaceholders: StringLiteralPlaceholders): AnyArgument {\n // Check whether the token represents a null value.\n if (token === \"null\") {\n return {\n value: null,\n type: \"null\"\n } as NullArgument;\n }\n\n // Check whether the token represents a boolean value.\n if (token === \"true\" || token === \"false\") {\n return {\n value: token === \"true\",\n type: \"boolean\"\n } as BooleanArgument;\n }\n\n // Check whether the token represents a number value.\n // TODO: Relies on broken isNaN - see MDN.\n // if (!Number.isNaN(token)) {\n if (!isNaN(token as any)) {\n return {\n value: parseFloat(token),\n isInteger: parseFloat(token) === parseInt(token, 10),\n type: \"number\"\n } as NumberArgument;\n }\n\n // Check whether the token is a placeholder (e.g. @@0@@) representing a string literal.\n if (token.match(/^@@\\d+@@$/g)) {\n return {\n value: stringArgumentPlaceholders[token].replace('\\\\\"', '\"'),\n type: \"string\"\n } as StringPlaceholderArgument;\n }\n\n // The only remaining option is that the argument value is an identifier.\n return {\n value: token,\n type: \"identifier\"\n } as IdentifierArgument;\n}\n", "import { NodeAttributeDefinition } from \"../BehaviourTreeDefinition\";\nimport { parseArgumentTokens } from \"./MDSLNodeArgumentParser\";\nimport { StringLiteralPlaceholders } from \"./MDSLUtilities\";\n\n/**\n * A type defining the attribute definitions of a node.\n */\ntype NodeAttributes = {\n while?: NodeAttributeDefinition;\n until?: NodeAttributeDefinition;\n entry?: NodeAttributeDefinition;\n exit?: NodeAttributeDefinition;\n step?: NodeAttributeDefinition;\n};\n\n/**\n * Parse any node attribute definitions from the specified tokens array.\n * @param tokens The array of remaining tokens.\n * @param stringArgumentPlaceholders The mapping of string literal node argument placeholders to original values.\n * @returns An object of attribute definitions defined by any directly following tokens.\n */\nexport function parseAttributeTokens(\n tokens: string[],\n stringArgumentPlaceholders: StringLiteralPlaceholders\n): NodeAttributes {\n const nodeAttributeNames: (keyof NodeAttributes)[] = [\"while\", \"until\", \"entry\", \"exit\", \"step\"];\n\n // Create an object to hold any attributes found.\n const attributes: NodeAttributes = {};\n\n // Try to get the name of the attribute for the next token.\n let nextAttributeName = tokens[0]?.toLowerCase() as keyof NodeAttributes;\n\n // Pull attribute tokens as well as their arguments off of the tokens stack until we have no more.\n while (nodeAttributeNames.includes(nextAttributeName)) {\n // Check to make sure that we have not already created an attribute definition of this type.\n if (attributes[nextAttributeName]) {\n throw new Error(`duplicate attribute '${tokens[0].toUpperCase()}' found for node`);\n }\n\n // Remove the attribute name token from the array of tokens.\n tokens.shift();\n\n // Grab the attribute arguments, assuming the first to be an identifier.\n const [attributeCallIdentifier, ...attributeArguments] = parseArgumentTokens(\n tokens,\n stringArgumentPlaceholders\n );\n\n // The first attribute argument has to be an identifer, this will reference an agent function.\n if (attributeCallIdentifier?.type !== \"identifier\") {\n throw new Error(\"expected agent function name identifier argument for attribute\");\n }\n\n // Any attribute arguments (other than the expected call identifier) must have a type of string, number, boolean or null.\n attributeArguments\n .filter((arg) => arg.type === \"identifier\")\n .forEach((arg) => {\n throw new Error(\n `invalid attribute argument value '${arg.value}', must be string, number, boolean or null`\n );\n });\n\n // Create the attribute definition and add it to the object of attribute definitions found.\n attributes[nextAttributeName] = {\n call: attributeCallIdentifier.value,\n args: attributeArguments.map(({ value }) => value)\n };\n\n // Try to get the next attribute name token, as there could be multiple.\n nextAttributeName = tokens[0]?.toLowerCase() as keyof NodeAttributes;\n }\n\n return attributes;\n}\n", "import {\n ActionNodeDefinition,\n AnyChildNodeDefinition,\n AnyNodeDefinition,\n BranchNodeDefinition,\n ConditionNodeDefinition,\n FailNodeDefinition,\n FlipNodeDefinition,\n LottoNodeDefinition,\n ParallelNodeDefinition,\n RepeatNodeDefinition,\n RetryNodeDefinition,\n RootNodeDefinition,\n SelectorNodeDefinition,\n SequenceNodeDefinition,\n SucceedNodeDefinition,\n WaitNodeDefinition\n} from \"../BehaviourTreeDefinition\";\nimport {\n isCompositeNode,\n isDecoratorNode,\n isLeafNode,\n isNullOrUndefined,\n isRootNode\n} from \"../BehaviourTreeDefinitionUtilities\";\nimport { parseArgumentTokens } from \"./MDSLNodeArgumentParser\";\nimport { parseAttributeTokens } from \"./MDSLNodeAttributeParser\";\nimport {\n StringLiteralPlaceholders,\n parseTokensFromDefinition,\n popAndCheck,\n substituteStringLiterals\n} from \"./MDSLUtilities\";\n\n/**\n * Convert the MDSL tree definition string into an equivalent JSON definition.\n * @param definition The tree definition string as MDSL.\n * @returns The root node JSON definitions.\n */\nexport function convertMDSLToJSON(definition: string): RootNodeDefinition[] {\n // Swap out any node/attribute argument string literals with a placeholder and get a mapping of placeholders to original values as well as the processed definition.\n const { placeholders, processedDefinition } = substituteStringLiterals(definition);\n\n // Parse our definition definition string into an array of raw tokens.\n const tokens = parseTokensFromDefinition(processedDefinition);\n\n return convertTokensToJSONDefinition(tokens, placeholders);\n}\n\n/**\n * Converts the specified tree definition tokens into a JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The root node JSON definitions.\n */\nfunction convertTokensToJSONDefinition(\n tokens: string[],\n stringLiteralPlaceholders: StringLiteralPlaceholders\n): RootNodeDefinition[] {\n // There must be at least 3 tokens for the tree definition to be valid. 'ROOT', '{' and '}'.\n if (tokens.length < 3) {\n throw new Error(\"invalid token count\");\n }\n\n // We should have a matching number of '{' and '}' tokens. If not, then there are scopes that have not been properly closed.\n if (tokens.filter((token) => token === \"{\").length !== tokens.filter((token) => token === \"}\").length) {\n throw new Error(\"scope character mismatch\");\n }\n\n // Create an array of tree stack arrays where root nodes will always be at the botton and the current composite/decorator node at the top.\n // There should be an element in this array for every root node defined and every element should be an array with a root note as the first element.\n // E.g. A definition with two root nodes defined:\n // [\n // [root, lotto, sequence],\n // [root, selector]\n // ]\n const treeStacks: [Partial, ...Partial[]][] = [];\n\n // Create an array of all root node definitions that we create.\n const rootNodes: Partial[] = [];\n\n // A helper function used to push node definitions onto the tree stack.\n const pushNode = (node: AnyNodeDefinition) => {\n // If the node is a root node then we need to create a new tree stack array with the root node at the root.\n if (isRootNode(node)) {\n // We need to double-check that this root node is not the child of another node.\n // We can do this by checking whether the top tree stack is not empty (contains an existing node)\n if (treeStacks[treeStacks.length - 1]?.length) {\n throw new Error(\"a root node cannot be the child of another node\");\n }\n\n // Add the root node definition to our array of all parsed root node definitions.\n rootNodes.push(node);\n\n // Add the root node definition to the root of a new tree stack.\n treeStacks.push([node]);\n\n return;\n }\n\n // All non-root nodes should be pushed after their root nodes so handle cases\n // where we may not have any tree stacks or our top-most tree stack is empty.\n if (!treeStacks.length || !treeStacks[treeStacks.length - 1].length) {\n throw new Error(\"expected root node at base of definition\");\n }\n\n // Get the current tree stack that we are populating.\n const topTreeStack = treeStacks[treeStacks.length - 1];\n\n // Get the top-most node in the current tree stack, this will be a composite/decorator node\n // for which we will populate its children array if composite or setting its child if a decorator.\n const topTreeStackTopNode = topTreeStack[topTreeStack.length - 1] as AnyNodeDefinition;\n\n // If the top-most node in the current root stack is a composite or decorator\n // node then the current node should be added as a child of the top-most node.\n if (isCompositeNode(topTreeStackTopNode)) {\n topTreeStackTopNode.children = topTreeStackTopNode.children || [];\n topTreeStackTopNode.children.push(node);\n } else if (isDecoratorNode(topTreeStackTopNode)) {\n // If the top node already has a child node set then throw an error as a decorator should only have a single child.\n if (topTreeStackTopNode.child) {\n throw new Error(\"a decorator node must only have a single child node\");\n }\n\n topTreeStackTopNode.child = node;\n }\n\n // If the node we are adding is also a composite or decorator node, then we should push it\n // onto the current tree stack, as subsequent nodes will be added as its child/children.\n if (!isLeafNode(node)) {\n topTreeStack.push(node);\n }\n };\n\n // A helper function used to pop the top-most node definition off of the tree stack and return it.\n const popNode = (): AnyNodeDefinition | null => {\n let poppedNode: AnyNodeDefinition | null = null;\n\n // Get the current tree stack that we are populating.\n const topTreeStack = treeStacks[treeStacks.length - 1];\n\n // Pop the top-most node in the current tree stack if there is one.\n if (topTreeStack.length) {\n poppedNode = topTreeStack.pop() as AnyNodeDefinition;\n }\n\n // We don't want any empty tree stacks in our stack of tree stacks.\n if (!topTreeStack.length) {\n treeStacks.pop();\n }\n\n return poppedNode;\n };\n\n // We should keep processing the raw tokens until we run out of them.\n while (tokens.length) {\n // Grab the next token.\n const token = tokens.shift()!;\n\n // How we create the next node depends on the current raw token value.\n switch (token.toUpperCase()) {\n case \"ROOT\": {\n pushNode(createRootNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"SUCCEED\": {\n pushNode(createSucceedNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"FAIL\": {\n pushNode(createFailNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"FLIP\": {\n pushNode(createFlipNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"REPEAT\": {\n pushNode(createRepeatNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"RETRY\": {\n pushNode(createRetryNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"SEQUENCE\": {\n pushNode(createSequenceNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"SELECTOR\": {\n pushNode(createSelectorNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"PARALLEL\": {\n pushNode(createParallelNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"LOTTO\": {\n pushNode(createLottoNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"ACTION\": {\n pushNode(createActionNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"CONDITION\": {\n pushNode(createConditionNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"WAIT\": {\n pushNode(createWaitNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"BRANCH\": {\n pushNode(createBranchNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"}\": {\n // The '}' character closes the current scope and means that we have to pop a node off of the current stack.\n const poppedNode = popNode();\n\n // Now that we have a node definition we can carry out any validation that may require the node to be fully populated.\n if (poppedNode) {\n validatePoppedNode(poppedNode);\n }\n\n break;\n }\n\n default: {\n throw new Error(`unexpected token: ${token}`);\n }\n }\n }\n\n return rootNodes as RootNodeDefinition[];\n}\n\n/**\n * Creates a root node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The root node JSON definition.\n */\nfunction createRootNode(tokens: string[], stringLiteralPlaceholders: StringLiteralPlaceholders): RootNodeDefinition {\n // Create the root node definition.\n let node = {\n type: \"root\",\n id: undefined\n } as RootNodeDefinition;\n\n // Parse any node arguments, we should only have one if any which will be an identifier argument for the root identifier.\n const nodeArguments = parseArgumentTokens(tokens, stringLiteralPlaceholders);\n\n // Check whether any node arguments were defined.\n if (nodeArguments.length) {\n // We should only have one argument, if any, which will be an identifier argument for the root identifier.\n if (nodeArguments.length === 1 && nodeArguments[0].type === \"identifier\") {\n // The root node identifier will be the first and only node argument value.\n node.id = nodeArguments[0].value as string;\n } else {\n throw new Error(\"expected single root name argument\");\n }\n }\n\n // Grab any node attribute definitions and spread them into the node definition.\n node = { ...node, ...parseAttributeTokens(tokens, stringLiteralPlaceholders) };\n\n // This is a decorator node, so we expect an opening '{'.\n popAndCheck(tokens, \"{\");\n\n // Return the root node definition.\n return node;\n}\n\n/**\n * Creates a succeed node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The succeed node JSON definition.\n */\nfunction createSucceedNode(\n tokens: string[],\n stringLiteralPlaceholders: StringLiteralPlaceholders\n): SucceedNodeDefinition {\n const node = {\n type: \"succeed\",\n ...parseAttributeTokens(tokens, stringLiteralPlaceholders)\n } as SucceedNodeDefinition;\n\n // This is a decorator node, so we expect an opening '{'.\n popAndCheck(tokens, \"{\");\n\n // Return the succeed node definition.\n return node;\n}\n\n/**\n * Creates a fail node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The fail node JSON definition.\n */\nfunction createFailNode(tokens: string[], stringLiteralPlaceholders: StringLiteralPlaceholders): FailNodeDefinition {\n const node = {\n type: \"fail\",\n ...parseAttributeTokens(tokens, stringLiteralPlaceholders)\n } as FailNodeDefinition;\n\n // This is a decorator node, so we expect an opening '{'.\n popAndCheck(tokens, \"{\");\n\n // Return the fail node definition.\n return node;\n}\n\n/**\n * Creates a flip node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The flip node JSON definition.\n */\nfunction createFlipNode(tokens: string[], stringLiteralPlaceholders: StringLiteralPlaceholders): FlipNodeDefinition {\n const node = {\n type: \"flip\",\n ...parseAttributeTokens(tokens, stringLiteralPlaceholders)\n } as FlipNodeDefinition;\n\n // This is a decorator node, so we expect an opening '{'.\n popAndCheck(tokens, \"{\");\n\n // Return the flip node definition.\n return node;\n}\n\n/**\n * Creates a repeat node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The repeat node JSON definition.\n */\nfunction createRepeatNode(\n tokens: string[],\n stringLiteralPlaceholders: StringLiteralPlaceholders\n): RepeatNodeDefinition {\n let node = { type: \"repeat\" } as RepeatNodeDefinition;\n\n // Get the node arguments.\n const nodeArguments = parseArgumentTokens(tokens, stringLiteralPlaceholders);\n\n // The arguments of a repeat node are optional. We may have:\n // - No node arguments, in which case the repeat note will iterate indefinitely.\n // - One node argument which will be the explicit number of iterations to make.\n // - Two node arguments which define the min and max iteration bounds from which a random iteration count will be picked.\n if (nodeArguments.length) {\n // All repeat node arguments MUST be of type number and must be integer.\n nodeArguments\n .filter((arg) => arg.type !== \"number\" || !arg.isInteger)\n .forEach(() => {\n throw new Error(`repeat node iteration counts must be integer values`);\n });\n\n // We should have got one or two iteration counts.\n if (nodeArguments.length === 1) {\n // A static iteration count was defined.\n node.iterations = nodeArguments[0].value as number;\n\n // A repeat node must have a positive number of iterations if defined.\n if (node.iterations < 0) {\n throw new Error(\"a repeat node must have a positive number of iterations if defined\");\n }\n } else if (nodeArguments.length === 2) {\n // A minimum and maximum iteration count was defined.\n node.iterations = [nodeArguments[0].value as number, nodeArguments[1].value as number];\n\n // A repeat node must have a positive min and max iteration count if they are defined.\n if (node.iterations[0] < 0 || node.iterations[1] < 0) {\n throw new Error(\"a repeat node must have a positive minimum and maximum iteration count if defined\");\n }\n\n // A repeat node must not have an minimum iteration count that exceeds the maximum iteration count.\n if (node.iterations[0] > node.iterations[1]) {\n throw new Error(\n \"a repeat node must not have a minimum iteration count that exceeds the maximum iteration count\"\n );\n }\n } else {\n // An incorrect number of iteration counts was defined.\n throw new Error(\"invalid number of repeat node iteration count arguments defined\");\n }\n }\n\n // Grab any node attribute definitions and spread them into the node definition.\n node = { ...node, ...parseAttributeTokens(tokens, stringLiteralPlaceholders) };\n\n // This is a decorator node, so we expect an opening '{'.\n popAndCheck(tokens, \"{\");\n\n // Return the repeat node definition.\n return node;\n}\n\n/**\n * Creates a retry node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The retry node JSON definition.\n */\nfunction createRetryNode(tokens: string[], stringLiteralPlaceholders: StringLiteralPlaceholders): RetryNodeDefinition {\n let node = { type: \"retry\" } as RetryNodeDefinition;\n\n // Get the node arguments.\n const nodeArguments = parseArgumentTokens(tokens, stringLiteralPlaceholders);\n\n // The arguments of a retry node are optional. We may have:\n // - No node arguments, in which case the retry note will attempt indefinitely.\n // - One node argument which will be the explicit number of attempts to make.\n // - Two node arguments which define the min and max attempt bounds from which a random attempt count will be picked.\n if (nodeArguments.length) {\n // All retry node arguments MUST be of type number and must be integer.\n nodeArguments\n .filter((arg) => arg.type !== \"number\" || !arg.isInteger)\n .forEach(() => {\n throw new Error(`retry node attempt counts must be integer values`);\n });\n\n // We should have got one or two attempt counts.\n if (nodeArguments.length === 1) {\n // A static attempt count was defined.\n node.attempts = nodeArguments[0].value as number;\n\n // A retry node must have a positive number of attempts if defined.\n if (node.attempts < 0) {\n throw new Error(\"a retry node must have a positive number of attempts if defined\");\n }\n } else if (nodeArguments.length === 2) {\n // A minimum and maximum attempt count was defined.\n node.attempts = [nodeArguments[0].value as number, nodeArguments[1].value as number];\n\n // A retry node must have a positive min and max attempts count if they are defined.\n if (node.attempts[0] < 0 || node.attempts[1] < 0) {\n throw new Error(\"a retry node must have a positive minimum and maximum attempt count if defined\");\n }\n\n // A retry node must not have a minimum attempt count that exceeds the maximum attempt count.\n if (node.attempts[0] > node.attempts[1]) {\n throw new Error(\n \"a retry node must not have a minimum attempt count that exceeds the maximum attempt count\"\n );\n }\n } else {\n // An incorrect number of attempt counts was defined.\n throw new Error(\"invalid number of retry node attempt count arguments defined\");\n }\n }\n\n // Grab any node attribute definitions and spread them into the node definition.\n node = { ...node, ...parseAttributeTokens(tokens, stringLiteralPlaceholders) };\n\n // This is a decorator node, so we expect an opening '{'.\n popAndCheck(tokens, \"{\");\n\n // Return the retry node definition.\n return node;\n}\n\n/**\n * Creates a sequence node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The sequence node JSON definition.\n */\nfunction createSequenceNode(\n tokens: string[],\n stringLiteralPlaceholders: StringLiteralPlaceholders\n): SequenceNodeDefinition {\n const node = {\n type: \"sequence\",\n ...parseAttributeTokens(tokens, stringLiteralPlaceholders)\n } as SequenceNodeDefinition;\n\n // This is a composite node, so we expect an opening '{'.\n popAndCheck(tokens, \"{\");\n\n // Return the sequence node definition.\n return node;\n}\n\n/**\n * Creates a selector node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The selector node JSON definition.\n */\nfunction createSelectorNode(\n tokens: string[],\n stringLiteralPlaceholders: StringLiteralPlaceholders\n): SelectorNodeDefinition {\n const node = {\n type: \"selector\",\n ...parseAttributeTokens(tokens, stringLiteralPlaceholders)\n } as SelectorNodeDefinition;\n\n // This is a composite node, so we expect an opening '{'.\n popAndCheck(tokens, \"{\");\n\n // Return the selector node definition.\n return node;\n}\n\n/**\n * Creates a parallel node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The parallel node JSON definition.\n */\nfunction createParallelNode(\n tokens: string[],\n stringLiteralPlaceholders: StringLiteralPlaceholders\n): ParallelNodeDefinition {\n const node = {\n type: \"parallel\",\n ...parseAttributeTokens(tokens, stringLiteralPlaceholders)\n } as ParallelNodeDefinition;\n\n // This is a composite node, so we expect an opening '{'.\n popAndCheck(tokens, \"{\");\n\n // Return the parallel node definition.\n return node;\n}\n\n/**\n * Creates a lotto node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The lotto node JSON definition.\n */\nfunction createLottoNode(tokens: string[], stringLiteralPlaceholders: StringLiteralPlaceholders): LottoNodeDefinition {\n // If any node arguments have been defined then they must be our weights.\n const nodeArguments = parseArgumentTokens(tokens, stringLiteralPlaceholders);\n\n // All lotto node arguments MUST be of type number and must be positive integers.\n nodeArguments\n .filter((arg) => arg.type !== \"number\" || !arg.isInteger || arg.value < 0)\n .forEach(() => {\n throw new Error(`lotto node weight arguments must be positive integer values`);\n });\n\n const node = {\n type: \"lotto\",\n weights: nodeArguments.length ? nodeArguments.map(({ value }) => value) : undefined,\n ...parseAttributeTokens(tokens, stringLiteralPlaceholders)\n } as LottoNodeDefinition;\n\n // This is a composite node, so we expect an opening '{'.\n popAndCheck(tokens, \"{\");\n\n // Return the lotto node definition.\n return node;\n}\n\n/**\n * Creates an action node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The action node JSON definition.\n */\nfunction createActionNode(\n tokens: string[],\n stringLiteralPlaceholders: StringLiteralPlaceholders\n): ActionNodeDefinition {\n // Parse any node arguments, we should have at least one which will be an identifier argument for the action name\n // and agent function to invoke for the action, all other arguments are to be passed as arguments to that function.\n const [actionNameIdentifier, ...agentFunctionArgs] = parseArgumentTokens(tokens, stringLiteralPlaceholders);\n\n // Our first argument MUST be defined and be an identifier as we require an action name argument.\n if (actionNameIdentifier?.type !== \"identifier\") {\n throw new Error(\"expected action name identifier argument\");\n }\n\n // Only the first argument should have been an identifier, all agent function arguments must be string, number, boolean or null.\n agentFunctionArgs\n .filter((arg) => arg.type === \"identifier\")\n .forEach((arg) => {\n throw new Error(\n `invalid action node argument value '${arg.value}', must be string, number, boolean or null`\n );\n });\n\n // Return the action node definition.\n return {\n type: \"action\",\n call: actionNameIdentifier.value,\n args: agentFunctionArgs.map(({ value }) => value),\n ...parseAttributeTokens(tokens, stringLiteralPlaceholders)\n };\n}\n\n/**\n * Creates a condition node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The condition node JSON definition.\n */\nfunction createConditionNode(\n tokens: string[],\n stringLiteralPlaceholders: StringLiteralPlaceholders\n): ConditionNodeDefinition {\n // Parse any node arguments, we should have at least one which will be an identifier argument for the condition name\n // and agent function to invoke for the condition, all other arguments are to be passed as arguments to that function.\n const [conditionNameIdentifier, ...agentFunctionArgs] = parseArgumentTokens(tokens, stringLiteralPlaceholders);\n\n // Our first argument MUST be defined and be an identifier as we require a condition name argument.\n if (conditionNameIdentifier?.type !== \"identifier\") {\n throw new Error(\"expected condition name identifier argument\");\n }\n\n // Only the first argument should have been an identifier, all agent function arguments must be string, number, boolean or null.\n agentFunctionArgs\n .filter((arg) => arg.type === \"identifier\")\n .forEach((arg) => {\n throw new Error(\n `invalid condition node argument value '${arg.value}', must be string, number, boolean or null`\n );\n });\n\n // Return the condition node definition.\n return {\n type: \"condition\",\n call: conditionNameIdentifier.value,\n args: agentFunctionArgs.map(({ value }) => value),\n ...parseAttributeTokens(tokens, stringLiteralPlaceholders)\n };\n}\n\n/**\n * Creates a wait node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The wait node JSON definition.\n */\nfunction createWaitNode(tokens: string[], stringLiteralPlaceholders: StringLiteralPlaceholders): WaitNodeDefinition {\n let node = { type: \"wait\" } as WaitNodeDefinition;\n\n // Get the node arguments.\n const nodeArguments = parseArgumentTokens(tokens, stringLiteralPlaceholders);\n\n // The arguments of a wait node are optional. We may have:\n // - No node arguments, in which case the wait will be indefinite until it is aborted.\n // - One node argument which will be the explicit duration of the wait.\n // - Two node arguments which define the min and max duration bounds from which a random duration will be picked.\n if (nodeArguments.length) {\n // All wait node arguments MUST be of type number and must be integer.\n nodeArguments\n .filter((arg) => arg.type !== \"number\" || !arg.isInteger)\n .forEach(() => {\n throw new Error(`wait node durations must be integer values`);\n });\n\n // We may have:\n // - One node argument which will be the explicit duration of the wait.\n // - Two node arguments which define the min and max duration bounds from which a random duration will be picked.\n // - Too many arguments, which is not valid.\n if (nodeArguments.length === 1) {\n // An explicit duration was defined.\n node.duration = nodeArguments[0].value as number;\n\n // If an explict duration was defined then it must be a positive number.\n if (node.duration < 0) {\n throw new Error(\"a wait node must have a positive duration\");\n }\n } else if (nodeArguments.length === 2) {\n // Min and max duration bounds were defined from which a random duration will be picked.\n node.duration = [nodeArguments[0].value as number, nodeArguments[1].value as number];\n\n // A wait node must have a positive min and max duration.\n if (node.duration[0] < 0 || node.duration[1] < 0) {\n throw new Error(\"a wait node must have a positive minimum and maximum duration\");\n }\n\n // A wait node must not have a minimum duration that exceeds the maximum duration.\n if (node.duration[0] > node.duration[1]) {\n throw new Error(\"a wait node must not have a minimum duration that exceeds the maximum duration\");\n }\n } else if (nodeArguments.length > 2) {\n // An incorrect number of duration arguments were defined.\n throw new Error(\"invalid number of wait node duration arguments defined\");\n }\n }\n\n // Return the wait node definition.\n return { ...node, ...parseAttributeTokens(tokens, stringLiteralPlaceholders) };\n}\n\n/**\n * Creates a branch node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The branch node JSON definition.\n */\nfunction createBranchNode(\n tokens: string[],\n stringLiteralPlaceholders: StringLiteralPlaceholders\n): BranchNodeDefinition {\n // Parse any node arguments, we should have one which will be an identifier argument for the root ref.\n const nodeArguments = parseArgumentTokens(tokens, stringLiteralPlaceholders);\n\n // We should have only a single identifer argument for a branch node, which is the root ref.\n if (nodeArguments.length !== 1 || nodeArguments[0].type !== \"identifier\") {\n throw new Error(\"expected single branch name argument\");\n }\n\n // Return the branch node definition.\n return { type: \"branch\", ref: nodeArguments[0].value };\n}\n\n/**\n * Validate a fully-populated node definition that was popped off of the tree stack.\n * @param definition The popped node to validate.\n */\nfunction validatePoppedNode(definition: AnyNodeDefinition): void {\n // Decorators MUST have a child defined.\n if (isDecoratorNode(definition) && isNullOrUndefined(definition.child)) {\n throw new Error(`a ${definition.type} node must have a single child node defined`);\n }\n\n // Composites MUST have at least one child defined.\n if (isCompositeNode(definition) && !definition.children?.length) {\n throw new Error(`a ${definition.type} node must have at least a single child node defined`);\n }\n\n // We need to make sure that lotto nodes that have weights defined have a number of weights matching the number of child nodes.\n if (definition.type === \"lotto\") {\n // Check whether a 'weights' property has been defined, if it has we expect it to be an array of weights.\n if (typeof definition.weights !== \"undefined\") {\n // Check that the weights property is an array of positive integers with an element for each child node element.\n if (definition.weights.length !== definition.children.length) {\n throw new Error(\n \"expected a number of weight arguments matching the number of child nodes for lotto node\"\n );\n }\n }\n }\n}\n", "import { RootNodeDefinition } from \"./BehaviourTreeDefinition\";\nimport { flattenDefinition, isBranchNode, isInteger } from \"./BehaviourTreeDefinitionUtilities\";\nimport { convertMDSLToJSON } from \"./mdsl/MDSLDefinitionParser\";\n\n/**\n * An object representing the result of validating a tree definition.\n */\nexport type DefinitionValidationResult = {\n /**\n * A flag defining whether validation succeeded.\n */\n succeeded: boolean;\n /**\n * A string containing the error message if validation did not succeed.\n */\n errorMessage?: string;\n /**\n * The definition as json if the validation was successful, or undefined if validation did not succeed.\n */\n json?: RootNodeDefinition[];\n};\n\n/**\n * Validates the specified behaviour tree definition in the form of JSON or MDSL, not taking any globally registered subtrees into consideration.\n * @param definition The behaviour tree definition in the form of JSON or MDSL.\n * @returns An object representing the result of validating the given tree definition.\n */\nexport function validateDefinition(definition: any): DefinitionValidationResult {\n // The definition must be defined.\n if (definition === null || typeof definition === \"undefined\") {\n return createValidationFailureResult(\"definition is null or undefined\");\n }\n\n // We are expecting a definition in one of three different forms:\n // - A string which we will assume is MDSL and we will parse this to JSON before validation.\n // - An array which we will assume is an array of root node definitions with at least one being the primary root node (no 'id' property)\n // - An object which we will assume is the primary root node and should not have an 'id' property.\n if (typeof definition === \"string\") {\n // The definition is a string which we can assume is MDSL, so attempt to validate it.\n return validateMDSLDefinition(definition);\n } else if (typeof definition === \"object\") {\n // The definition will either be an array (of root node definitions) or an object (the single primary root node definition).\n return validateJSONDefinition(definition);\n } else {\n return createValidationFailureResult(`unexpected definition type of '${typeof definition}'`);\n }\n}\n\n/**\n * Validates the specified behaviour tree definition in the form of MDSL.\n * @param definition The behaviour tree definition in the form of MDSL.\n * @returns An object representing the result of validating the given tree definition.\n */\nfunction validateMDSLDefinition(definition: string): DefinitionValidationResult {\n let rootNodeDefinitions;\n\n // The first thing the we need to do is to attempt to convert our MDSL into JSON.\n try {\n // The definition is a string which we can assume is MDSL, so attempt to parse it to a JSON definition in the form of an array of root node definitions.\n rootNodeDefinitions = convertMDSLToJSON(definition);\n } catch (exception) {\n // We failed to parse the JSON from the MDSL, this is likely to be the result of it not being a valid MDSL string.\n return createValidationFailureResult((exception as Error).message);\n }\n\n // Unpack all of the root node definitions into arrays of main ('id' defined) and sub ('id' not defined) root node definitions.\n const mainRootNodeDefinitions = rootNodeDefinitions.filter(({ id }) => typeof id === \"undefined\");\n const subRootNodeDefinitions = rootNodeDefinitions.filter(({ id }) => typeof id === \"string\" && id.length > 0);\n\n // We should ALWAYS have exactly one root node definition without an 'id' property defined, which is out main root node definition.\n if (mainRootNodeDefinitions.length !== 1) {\n return createValidationFailureResult(\n \"expected single unnamed root node at base of definition to act as main root\"\n );\n }\n\n // We should never have duplicate 'id' properties across our sub root node definitions.\n const subRootNodeIdenitifers: string[] = [];\n for (const { id } of subRootNodeDefinitions) {\n // Have we already come across this 'id' property value?\n if (subRootNodeIdenitifers.includes(id!)) {\n return createValidationFailureResult(`multiple root nodes found with duplicate name '${id}'`);\n }\n\n subRootNodeIdenitifers.push(id!);\n }\n\n try {\n // Validate our branch -> subtree links and check for any circular dependencies, we don't care about checking for broken subtree links here.\n validateBranchSubtreeLinks(rootNodeDefinitions, false);\n } catch (exception) {\n return createValidationFailureResult((exception as Error).message);\n }\n\n // Our definition was valid!\n return {\n succeeded: true,\n json: rootNodeDefinitions\n };\n}\n\n/**\n * Validates the specified behaviour tree definition in the form of JSON.\n * @param definition The behaviour tree definition in the form of JSON.\n * @returns An object representing the result of validating the given tree definition.\n */\nexport function validateJSONDefinition(\n definition: RootNodeDefinition | RootNodeDefinition[]\n): DefinitionValidationResult {\n // The definition will either be an array (of root node definitions) or an object (the single primary root node definition).\n const rootNodeDefinitions = Array.isArray(definition) ? definition : [definition];\n\n // Iterate over our array of root nodes and call validateNode for each, passing an initial depth of 0, wrapped in a try catch to handle validation failures.\n try {\n rootNodeDefinitions.forEach((rootNodeDefinition) => validateNode(rootNodeDefinition, 0));\n } catch (error) {\n // Handle cases where we have caught a thrown Error and return a failure result with the error message.\n if (error instanceof Error) {\n return createValidationFailureResult(error.message);\n }\n\n // No idea what happened here!\n return createValidationFailureResult(`unexpected error: ${error}`);\n }\n\n // Unpack all of the root node definitions into arrays of main ('id' defined) and sub ('id' not defined) root node definitions.\n const mainRootNodeDefinitions = rootNodeDefinitions.filter(({ id }) => typeof id === \"undefined\");\n const subRootNodeDefinitions = rootNodeDefinitions.filter(({ id }) => typeof id === \"string\" && id.length > 0);\n\n // We should ALWAYS have exactly one root node definition without an 'id' property defined, which is out main root node definition.\n if (mainRootNodeDefinitions.length !== 1) {\n return createValidationFailureResult(\n \"expected single root node without 'id' property defined to act as main root\"\n );\n }\n\n // We should never have duplicate 'id' properties across our sub root node definitions.\n const subRootNodeIdenitifers: string[] = [];\n for (const { id } of subRootNodeDefinitions) {\n // Have we already come across this 'id' property value?\n if (subRootNodeIdenitifers.includes(id!)) {\n return createValidationFailureResult(\n `multiple root nodes found with duplicate 'id' property value of '${id}'`\n );\n }\n\n subRootNodeIdenitifers.push(id!);\n }\n\n try {\n // Validate our branch -> subtree links and check for any circular dependencies, we don't care about checking for broken subtree links here.\n validateBranchSubtreeLinks(rootNodeDefinitions, false);\n } catch (exception) {\n return createValidationFailureResult((exception as Error).message);\n }\n\n // Our definition was valid!\n return {\n succeeded: true,\n json: rootNodeDefinitions\n };\n}\n\n/**\n * Validates the branch -> subtree links across all provided root node definitions.\n * This will not consider branch nodes that reference any globally registered subtrees unless includesGlobalSubtrees\n * is set to true, in which case we will also verify that there are no broken branch -> subtree links.\n * @param rootNodeDefinitions The array of root node definitions.\n * @param includesGlobalSubtrees A flag defining whether the array includes all global subtree root node definitions.\n */\nexport function validateBranchSubtreeLinks(rootNodeDefinitions: RootNodeDefinition[], includesGlobalSubtrees: boolean) {\n // Create a mapping of root node identifiers to other root nodes that they reference via branch nodes.\n // Below is an example of a mapping that includes a circular dependency (root => a => b => c => a)\n // [{ refs: [\"a\", \"b\"] }, { id: \"a\", refs: [\"b\"] }, { id: \"b\", refs: [\"c\"] }, { id: \"c\", refs: [\"a\"] }]\n const rootNodeMappings: { id: string | undefined; refs: string[] }[] = rootNodeDefinitions.map(\n (rootNodeDefinition) => ({\n id: rootNodeDefinition.id,\n refs: flattenDefinition(rootNodeDefinition)\n .filter(isBranchNode)\n .map(({ ref }) => ref)\n })\n );\n\n // A recursive function to walk through the mappings, keeping track of which root nodes we have visited in the form of a path of root node identifiers.\n const followRefs = (mapping: { id: string | undefined; refs: string[] }, path: (string | undefined)[] = []) => {\n // Have we found a circular dependency?\n if (path.includes(mapping.id)) {\n // We found a circular dependency! Get the bad path of root node identifiers.\n const badPath = [...path, mapping.id];\n\n // Create the formatted path value. [undefined, \"a\", \"b\", \"c\", \"a\"] would be formatted as \"a -> b -> c -> a\".\n const badPathFormatted = badPath.filter((element) => !!element).join(\" => \");\n\n // No need to continue, we found a circular dependency.\n throw new Error(`circular dependency found in branch node references: ${badPathFormatted}`);\n }\n\n for (const ref of mapping.refs) {\n // Find the mapping for the root node with an identifer matching the current ref.\n const subMapping = rootNodeMappings.find(({ id }) => id === ref);\n\n // We may not have a mapping for this ref, which is normal when we aren't considering all globally registered subtrees.\n if (subMapping) {\n followRefs(subMapping, [...path, mapping.id]);\n } else if (includesGlobalSubtrees) {\n // We found a reference to a root node that doesn't exist, which is a problem seeing as the root node definitons includes all globally registered subtrees.\n throw new Error(\n mapping.id\n ? `subtree '${mapping.id}' has branch node that references root node '${ref}' which has not been defined`\n : `primary tree has branch node that references root node '${ref}' which has not been defined`\n );\n }\n }\n };\n\n // Start looking for circular dependencies and broken references from the primary root node definition.\n followRefs(rootNodeMappings.find((mapping) => typeof mapping.id === \"undefined\")!);\n}\n\n/**\n * Validate an object that we expect to be a node definition.\n * @param definition An object that we expect to be a node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateNode(definition: any, depth: number): void {\n // Every node must be valid object and have a non-empty 'type' string property.\n if (typeof definition !== \"object\" || typeof definition.type !== \"string\" || definition.type.length === 0) {\n throw new Error(\n `node definition is not an object or 'type' property is not a non-empty string at depth '${depth}'`\n );\n }\n\n // How we validate this node definition will depend on its type.\n switch (definition.type) {\n case \"action\":\n validateActionNode(definition, depth);\n break;\n\n case \"condition\":\n validateConditionNode(definition, depth);\n break;\n\n case \"wait\":\n validateWaitNode(definition, depth);\n break;\n\n case \"branch\":\n validateBranchNode(definition, depth);\n break;\n\n case \"root\":\n validateRootNode(definition, depth);\n break;\n\n case \"succeed\":\n validateSucceedNode(definition, depth);\n break;\n\n case \"fail\":\n validateFailNode(definition, depth);\n break;\n\n case \"flip\":\n validateFlipNode(definition, depth);\n break;\n\n case \"repeat\":\n validateRepeatNode(definition, depth);\n break;\n\n case \"retry\":\n validateRetryNode(definition, depth);\n break;\n\n case \"sequence\":\n validateSequenceNode(definition, depth);\n break;\n\n case \"selector\":\n validateSelectorNode(definition, depth);\n break;\n\n case \"parallel\":\n validateParallelNode(definition, depth);\n break;\n\n case \"lotto\":\n validateLottoNode(definition, depth);\n break;\n\n default:\n throw new Error(`unexpected node type of '${definition.type}' at depth '${depth}'`);\n }\n}\n\n/**\n * Validate any attributes for a given node definition.\n * @param definition The node definition.\n * @param depth The depth of the node in the behaviour tree definition.\n */\nfunction validateNodeAttributes(definition: any, depth: number): void {\n // Validate each of the attribute types for this node.\n [\"while\", \"until\", \"entry\", \"exit\", \"step\"].forEach((attributeName) => {\n // Attempt to grab the definition for the current attribute from the node definition.\n const attributeDefinition = definition[attributeName];\n\n // All node attributes are optional, so there is nothing to do if the current attribute is not defined.\n if (typeof attributeDefinition === \"undefined\") {\n return;\n }\n\n // The attribute definition must be an object.\n if (typeof attributeDefinition !== \"object\") {\n throw new Error(\n `expected attribute '${attributeName}' to be an object for '${definition.type}' node at depth '${depth}'`\n );\n }\n\n // The 'call' property must be defined for any attribute definition.\n if (typeof attributeDefinition.call !== \"string\" || attributeDefinition.call.length === 0) {\n throw new Error(\n `expected 'call' property for attribute '${attributeName}' to be a non-empty string for '${definition.type}' node at depth '${depth}'`\n );\n }\n\n // If any node attribute arguments have been defined then they must have been defined in an array.\n if (typeof attributeDefinition.args !== \"undefined\" && !Array.isArray(attributeDefinition.args)) {\n throw new Error(\n `expected 'args' property for attribute '${attributeName}' to be an array for '${definition.type}' node at depth '${depth}'`\n );\n }\n });\n}\n\n/**\n * Validate an object that we expect to be a root node definition.\n * @param definition An object that we expect to be a root node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateRootNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"root\") {\n throw new Error(\"expected node type of 'root' for root node\");\n }\n\n // A root node cannot be the child of another node.\n if (depth > 0) {\n throw new Error(\"a root node cannot be the child of another node\");\n }\n\n // Check that, if the root node 'id' property is defined, it is a non-empty string.\n if (typeof definition.id !== \"undefined\" && (typeof definition.id !== \"string\" || definition.id.length === 0)) {\n throw new Error(\"expected non-empty string for 'id' property if defined for root node\");\n }\n\n // A root node is a decorator node, so must have a child node defined.\n if (typeof definition.child === \"undefined\") {\n throw new Error(\"expected property 'child' to be defined for root node\");\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n\n // Validate the child node of this decorator node.\n validateNode(definition.child, depth + 1);\n}\n\n/**\n * Validate an object that we expect to be a succeed node definition.\n * @param definition An object that we expect to be a succeed node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateSucceedNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"succeed\") {\n throw new Error(`expected node type of 'succeed' for succeed node at depth '${depth}'`);\n }\n\n // A succeed node is a decorator node, so must have a child node defined.\n if (typeof definition.child === \"undefined\") {\n throw new Error(`expected property 'child' to be defined for succeed node at depth '${depth}'`);\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n\n // Validate the child node of this decorator node.\n validateNode(definition.child, depth + 1);\n}\n\n/**\n * Validate an object that we expect to be a fail node definition.\n * @param definition An object that we expect to be a fail node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateFailNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"fail\") {\n throw new Error(`expected node type of 'fail' for fail node at depth '${depth}'`);\n }\n\n // A fail node is a decorator node, so must have a child node defined.\n if (typeof definition.child === \"undefined\") {\n throw new Error(`expected property 'child' to be defined for fail node at depth '${depth}'`);\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n\n // Validate the child node of this decorator node.\n validateNode(definition.child, depth + 1);\n}\n\n/**\n * Validate an object that we expect to be a flip node definition.\n * @param definition An object that we expect to be a flip node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateFlipNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"flip\") {\n throw new Error(`expected node type of 'flip' for flip node at depth '${depth}'`);\n }\n\n // A flip node is a decorator node, so must have a child node defined.\n if (typeof definition.child === \"undefined\") {\n throw new Error(`expected property 'child' to be defined for flip node at depth '${depth}'`);\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n\n // Validate the child node of this decorator node.\n validateNode(definition.child, depth + 1);\n}\n\n/**\n * Validate an object that we expect to be a repeat node definition.\n * @param definition An object that we expect to be a repeat node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateRepeatNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"repeat\") {\n throw new Error(`expected node type of 'repeat' for repeat node at depth '${depth}'`);\n }\n\n // A repeat node is a decorator node, so must have a child node defined.\n if (typeof definition.child === \"undefined\") {\n throw new Error(`expected property 'child' to be defined for repeat node at depth '${depth}'`);\n }\n\n // Check whether an 'iterations' property has been defined, it may not have been if this node is to repeat indefinitely.\n if (typeof definition.iterations !== \"undefined\") {\n if (Array.isArray(definition.iterations)) {\n // Check whether any elements of the array are not integer values.\n const containsNonInteger = !!definition.iterations.filter((value: unknown) => !isInteger(value)).length;\n\n // If the 'iterations' property is an array then it MUST contain two integer values.\n if (definition.iterations.length !== 2 || containsNonInteger) {\n throw new Error(\n `expected array containing two integer values for 'iterations' property if defined for repeat node at depth '${depth}'`\n );\n }\n\n // A repeat node must have a positive min and max iterations count if they are defined.\n if (definition.iterations[0] < 0 || definition.iterations[1] < 0) {\n throw new Error(\n `expected positive minimum and maximum iterations count for 'iterations' property if defined for repeat node at depth '${depth}'`\n );\n }\n\n // A repeat node must not have a minimum iterations count that exceeds the maximum iterations count.\n if (definition.iterations[0] > definition.iterations[1]) {\n throw new Error(\n `expected minimum iterations count that does not exceed the maximum iterations count for 'iterations' property if defined for repeat node at depth '${depth}'`\n );\n }\n } else if (isInteger(definition.iterations)) {\n // A repeat node must have a positive number of iterations if defined.\n if (definition.iterations < 0) {\n throw new Error(\n `expected positive iterations count for 'iterations' property if defined for repeat node at depth '${depth}'`\n );\n }\n } else {\n throw new Error(\n `expected integer value or array containing two integer values for 'iterations' property if defined for repeat node at depth '${depth}'`\n );\n }\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n\n // Validate the child node of this decorator node.\n validateNode(definition.child, depth + 1);\n}\n\n/**\n * Validate an object that we expect to be a retry node definition.\n * @param definition An object that we expect to be a retry node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateRetryNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"retry\") {\n throw new Error(`expected node type of 'retry' for retry node at depth '${depth}'`);\n }\n\n // A retry node is a decorator node, so must have a child node defined.\n if (typeof definition.child === \"undefined\") {\n throw new Error(`expected property 'child' to be defined for retry node at depth '${depth}'`);\n }\n\n // Check whether an 'attempts' property has been defined, it may not have been if this node is to retry indefinitely.\n if (typeof definition.attempts !== \"undefined\") {\n if (Array.isArray(definition.attempts)) {\n // Check whether any elements of the array are not integer values.\n const containsNonInteger = !!definition.attempts.filter((value: unknown) => !isInteger(value)).length;\n\n // If the 'attempts' property is an array then it MUST contain two integer values.\n if (definition.attempts.length !== 2 || containsNonInteger) {\n throw new Error(\n `expected array containing two integer values for 'attempts' property if defined for retry node at depth '${depth}'`\n );\n }\n\n // A retry node must have a positive min and max attempts count if they are defined.\n if (definition.attempts[0] < 0 || definition.attempts[1] < 0) {\n throw new Error(\n `expected positive minimum and maximum attempts count for 'attempts' property if defined for retry node at depth '${depth}'`\n );\n }\n\n // A retry node must not have a minimum attempts count that exceeds the maximum attempts count.\n if (definition.attempts[0] > definition.attempts[1]) {\n throw new Error(\n `expected minimum attempts count that does not exceed the maximum attempts count for 'attempts' property if defined for retry node at depth '${depth}'`\n );\n }\n } else if (isInteger(definition.attempts)) {\n // A retry node must have a positive number of attempts if defined.\n if (definition.attempts < 0) {\n throw new Error(\n `expected positive attempts count for 'attempts' property if defined for retry node at depth '${depth}'`\n );\n }\n } else {\n throw new Error(\n `expected integer value or array containing two integer values for 'attempts' property if defined for retry node at depth '${depth}'`\n );\n }\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n\n // Validate the child node of this decorator node.\n validateNode(definition.child, depth + 1);\n}\n\n/**\n * Validate an object that we expect to be a branch node definition.\n * @param definition An object that we expect to be a branch node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateBranchNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"branch\") {\n throw new Error(`expected node type of 'branch' for branch node at depth '${depth}'`);\n }\n\n // Check that the branch node 'ref' property is defined and is a non-empty string.\n if (typeof definition.ref !== \"string\" || definition.ref.length === 0) {\n throw new Error(`expected non-empty string for 'ref' property for branch node at depth '${depth}'`);\n }\n\n // It is invalid to define guard attributes for a branch node as they should be defined on the referenced root node.\n [\"while\", \"until\"].forEach((attributeName) => {\n if (typeof definition[attributeName] !== \"undefined\") {\n throw new Error(\n `guards should not be defined for branch nodes but guard '${attributeName}' was defined for branch node at depth '${depth}'`\n );\n }\n });\n\n // It is invalid to define callback attributes for a branch node as they should be defined on the referenced root node.\n [\"entry\", \"exit\", \"step\"].forEach((attributeName) => {\n if (typeof definition[attributeName] !== \"undefined\") {\n throw new Error(\n `callbacks should not be defined for branch nodes but callback '${attributeName}' was defined for branch node at depth '${depth}'`\n );\n }\n });\n}\n\n/**\n * Validate an object that we expect to be a action node definition.\n * @param definition An object that we expect to be a action node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateActionNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"action\") {\n throw new Error(`expected node type of 'action' for action node at depth '${depth}'`);\n }\n\n // The 'call' property must be defined for a action node definition.\n if (typeof definition.call !== \"string\" || definition.call.length === 0) {\n throw new Error(`expected non-empty string for 'call' property of action node at depth '${depth}'`);\n }\n\n // If any action function arguments have been defined then they must have been defined in an array.\n if (typeof definition.args !== \"undefined\" && !Array.isArray(definition.args)) {\n throw new Error(`expected array for 'args' property if defined for action node at depth '${depth}'`);\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n}\n\n/**\n * Validate an object that we expect to be a condition node definition.\n * @param definition An object that we expect to be a condition node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateConditionNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"condition\") {\n throw new Error(`expected node type of 'condition' for condition node at depth '${depth}'`);\n }\n\n // The 'call' property must be defined for a condition node definition.\n if (typeof definition.call !== \"string\" || definition.call.length === 0) {\n throw new Error(`expected non-empty string for 'call' property of condition node at depth '${depth}'`);\n }\n\n // If any condition function arguments have been defined then they must have been defined in an array.\n if (typeof definition.args !== \"undefined\" && !Array.isArray(definition.args)) {\n throw new Error(`expected array for 'args' property if defined for condition node at depth '${depth}'`);\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n}\n\n/**\n * Validate an object that we expect to be a wait node definition.\n * @param definition An object that we expect to be a wait node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateWaitNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"wait\") {\n throw new Error(`expected node type of 'wait' for wait node at depth '${depth}'`);\n }\n\n // Check whether a 'duration' property has been defined, it may not have been if this node is to wait indefinitely.\n if (typeof definition.duration !== \"undefined\") {\n if (Array.isArray(definition.duration)) {\n // Check whether any elements of the array are not integer values.\n const containsNonInteger = !!definition.duration.filter((value: unknown) => !isInteger(value)).length;\n\n // If the 'duration' property is an array then it MUST contain two integer values.\n if (definition.duration.length !== 2 || containsNonInteger) {\n throw new Error(\n `expected array containing two integer values for 'duration' property if defined for wait node at depth '${depth}'`\n );\n }\n\n // A wait node must have a positive min and max duration value if they are defined.\n if (definition.duration[0] < 0 || definition.duration[1] < 0) {\n throw new Error(\n `expected positive minimum and maximum duration for 'duration' property if defined for wait node at depth '${depth}'`\n );\n }\n\n // A wait node must not have a minimum duration value that exceeds the maximum duration value.\n if (definition.duration[0] > definition.duration[1]) {\n throw new Error(\n `expected minimum duration value that does not exceed the maximum duration value for 'duration' property if defined for wait node at depth '${depth}'`\n );\n }\n } else if (isInteger(definition.duration)) {\n // A wait node must have a positive duration value if defined.\n if (definition.duration < 0) {\n throw new Error(\n `expected positive duration value for 'duration' property if defined for wait node at depth '${depth}'`\n );\n }\n } else {\n throw new Error(\n `expected integer value or array containing two integer values for 'duration' property if defined for wait node at depth '${depth}'`\n );\n }\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n}\n\n/**\n * Validate an object that we expect to be a sequence node definition.\n * @param definition An object that we expect to be a sequence node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateSequenceNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"sequence\") {\n throw new Error(`expected node type of 'sequence' for sequence node at depth '${depth}'`);\n }\n\n // A sequence node is a composite node, so must have a children nodes array defined.\n if (!Array.isArray(definition.children) || definition.children.length === 0) {\n throw new Error(`expected non-empty 'children' array to be defined for sequence node at depth '${depth}'`);\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n\n // Validate the child nodes of this composite node.\n definition.children.forEach((child: any) => validateNode(child, depth + 1));\n}\n\n/**\n * Validate an object that we expect to be a selector node definition.\n * @param definition An object that we expect to be a selector node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateSelectorNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"selector\") {\n throw new Error(`expected node type of 'selector' for selector node at depth '${depth}'`);\n }\n\n // A selector node is a composite node, so must have a children nodes array defined.\n if (!Array.isArray(definition.children) || definition.children.length === 0) {\n throw new Error(`expected non-empty 'children' array to be defined for selector node at depth '${depth}'`);\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n\n // Validate the child nodes of this composite node.\n definition.children.forEach((child: any) => validateNode(child, depth + 1));\n}\n\n/**\n * Validate an object that we expect to be a parallel node definition.\n * @param definition An object that we expect to be a parallel node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateParallelNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"parallel\") {\n throw new Error(`expected node type of 'parallel' for parallel node at depth '${depth}'`);\n }\n\n // A parallel node is a composite node, so must have a children nodes array defined.\n if (!Array.isArray(definition.children) || definition.children.length === 0) {\n throw new Error(`expected non-empty 'children' array to be defined for parallel node at depth '${depth}'`);\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n\n // Validate the child nodes of this composite node.\n definition.children.forEach((child: any) => validateNode(child, depth + 1));\n}\n\n/**\n * Validate an object that we expect to be a lotto node definition.\n * @param definition An object that we expect to be a lotto node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateLottoNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"lotto\") {\n throw new Error(`expected node type of 'lotto' for lotto node at depth '${depth}'`);\n }\n\n // A lotto node is a composite node, so must have a children nodes array defined.\n if (!Array.isArray(definition.children) || definition.children.length === 0) {\n throw new Error(`expected non-empty 'children' array to be defined for lotto node at depth '${depth}'`);\n }\n\n // Check whether a 'weights' property has been defined, if it has we expect it to be an array of weights.\n if (typeof definition.weights !== \"undefined\") {\n // Check that the weights property is an array of positive integers with an element for each child node element.\n if (\n !Array.isArray(definition.weights) ||\n definition.weights.length !== definition.children.length ||\n definition.weights.filter((value: unknown) => !isInteger(value)).length ||\n definition.weights.filter((value: number) => value < 0).length\n ) {\n throw new Error(\n `expected an array of positive integer weight values with a length matching the number of child nodes for 'weights' property if defined for lotto node at depth '${depth}'`\n );\n }\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n\n // Validate the child nodes of this composite node.\n definition.children.forEach((child: any) => validateNode(child, depth + 1));\n}\n\n/**\n * A helper function to create a failure validation result with the given error message.\n * @param errorMessage The validation failure error message.\n * @returns A failure validation result with the given error message.\n */\nfunction createValidationFailureResult(errorMessage: string): DefinitionValidationResult {\n return { succeeded: false, errorMessage };\n}\n", "import { ActionResult, Agent, GlobalFunction } from \"./Agent\";\nimport { RootNodeDefinition } from \"./BehaviourTreeDefinition\";\n\nexport type InvokerFunction = (args: any[]) => ActionResult;\n\n/**\n * A singleton used to store and lookup registered functions and subtrees.\n */\nexport default class Lookup {\n /**\n * The object holding any registered functions keyed on function name.\n */\n private static functionTable: { [key: string]: GlobalFunction } = {};\n /**\n * The object holding any registered subtree root node definitions keyed on tree name.\n */\n private static subtreeTable: { [key: string]: RootNodeDefinition } = {};\n\n /**\n * Gets the function with the specified name.\n * @param name The name of the function.\n * @returns The function with the specified name.\n */\n public static getFunc(name: string): GlobalFunction {\n return this.functionTable[name];\n }\n\n /**\n * Sets the function with the specified name for later lookup.\n * @param name The name of the function.\n * @param func The function.\n */\n public static setFunc(name: string, func: GlobalFunction): void {\n this.functionTable[name] = func;\n }\n\n /**\n * Gets the function invoker for the specified agent and function name.\n * If a function with the specified name exists on the agent object then it will\n * be returned, otherwise we will then check the registered functions for a match.\n * @param agent The agent instance that this behaviour tree is modelling behaviour for.\n * @param name The function name.\n * @returns The function invoker for the specified agent and function name.\n */\n static getFuncInvoker(agent: Agent, name: string): InvokerFunction | null {\n // Check whether the agent contains the specified function.\n const foundOnAgent = agent[name];\n if (foundOnAgent && typeof foundOnAgent === \"function\") {\n return (args: any[]): boolean | ActionResult => foundOnAgent.apply(agent, args);\n }\n\n // The agent does not contain the specified function but it may have been registered at some point.\n if (this.functionTable[name] && typeof this.functionTable[name] === \"function\") {\n return (args: any[]) => this.functionTable[name](agent, ...args.map((arg) => arg.value));\n }\n\n // We have no function to invoke.\n return null;\n }\n\n /**\n * Gets all registered subtree root node definitions.\n */\n static getSubtrees(): { [key: string]: RootNodeDefinition } {\n return this.subtreeTable;\n }\n\n /**\n * Sets the subtree with the specified name for later lookup.\n * @param name The name of the subtree.\n * @param subtree The subtree.\n */\n static setSubtree(name: string, subtree: RootNodeDefinition) {\n this.subtreeTable[name] = subtree;\n }\n\n /**\n * Removes the registered function or subtree with the specified name.\n * @param name The name of the registered function or subtree.\n */\n static remove(name: string) {\n delete this.functionTable[name];\n delete this.subtreeTable[name];\n }\n\n /**\n * Remove all registered functions and subtrees.\n */\n static empty() {\n this.functionTable = {};\n this.subtreeTable = {};\n }\n}\n", "import Node from \"../../nodes/Node\";\n\n/**\n * An exception thrown when evaluating node guard path conditions and a conditions fails.\n */\nexport default class GuardUnsatisifedException extends Error {\n /**\n * @param source The node at which a guard condition failed.\n */\n constructor(private source: Node) {\n super(\"A guard path condition has failed\");\n }\n\n /**\n * Gets whether the specified node is the node at which a guard condition failed.\n * @param node The node to check against the source node.\n * @returns Whether the specified node is the node at which a guard condition failed.\n */\n isSourceNode = (node: Node) => node === this.source;\n}\n", "import { Agent } from \"../../Agent\";\nimport Guard from \"./Guard\";\nimport Node from \"../../nodes/Node\";\nimport GuardUnsatisifedException from \"./GuardUnsatisifedException\";\n\nexport type GuardPathPart = {\n node: Node;\n guards: Guard[];\n};\n\n/**\n * Represents a path of node guards along a root-to-leaf tree path.\n */\nexport default class GuardPath {\n /**\n * @param nodes An array of objects defining a node instance -> guard link, ordered by node depth.\n */\n constructor(private nodes: GuardPathPart[]) {}\n\n /**\n * Evaluate guard conditions for all guards in the tree path, moving outwards from the root.\n * @param agent The agent, required for guard evaluation.\n * @returns An evaluation results object.\n */\n evaluate = (agent: Agent) => {\n // We need to evaluate guard conditions for nodes up the tree, moving outwards from the root.\n for (const details of this.nodes) {\n // There can be multiple guards per node.\n for (const guard of details.guards) {\n // Check whether the guard condition passes, and throw an exception if not.\n if (!guard.isSatisfied(agent)) {\n throw new GuardUnsatisifedException(details.node);\n }\n }\n }\n };\n}\n", "import { BehaviourTreeOptions } from \"../BehaviourTreeOptions\";\nimport State, { AnyState } from \"../State\";\nimport { Agent } from \"../Agent\";\nimport Leaf from \"./leaf/Leaf\";\nimport Attribute from \"../attributes/Attribute\";\nimport Entry from \"../attributes/callbacks/Entry\";\nimport Exit from \"../attributes/callbacks/Exit\";\nimport Step from \"../attributes/callbacks/Step\";\nimport Guard from \"../attributes/guards/Guard\";\nimport GuardPath from \"../attributes/guards/GuardPath\";\nimport GuardUnsatisifedException from \"../attributes/guards/GuardUnsatisifedException\";\n\n/**\n * A base node.\n */\nexport default abstract class Node {\n /**\n * The node uid.\n */\n private readonly uid: string = createNodeUid();\n /**\n * The node state.\n */\n private state: AnyState = State.READY;\n /**\n * The guard path to evaluate as part of a node update.\n */\n private guardPath: GuardPath | undefined;\n\n /**\n * @param type The node type.\n * @param attributes The node attributes.\n * @param args The node argument definitions.\n */\n constructor(private type: string, private attributes: Attribute[], private args: any[]) {}\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected abstract onUpdate(agent: Agent, options: BehaviourTreeOptions): void;\n\n /**\n * Gets the name of the node.\n */\n public abstract getName(): string;\n\n /**\n * Gets whether this node is a leaf node.\n */\n public abstract isLeafNode: () => this is Leaf;\n\n /**\n * Gets/Sets the state of the node.\n */\n getState = (): AnyState => this.state;\n setState = (value: AnyState): void => {\n this.state = value;\n };\n\n /**\n * Gets the unique id of the node.\n */\n getUid = () => this.uid;\n\n /**\n * Gets the type of the node.\n */\n getType = () => this.type;\n\n /**\n * Gets the node attributes.\n */\n getAttributes = () => this.attributes;\n\n /**\n * Gets the node arguments.\n */\n getArguments = () => this.args;\n\n /**\n * Gets the node attribute with the specified type, or null if it does not exist.\n */\n getAttribute(type: \"entry\" | \"ENTRY\"): Entry;\n getAttribute(type: \"exit\" | \"EXIT\"): Exit;\n getAttribute(type: \"step\" | \"STEP\"): Step;\n getAttribute(type: string): Attribute {\n return (\n this.getAttributes().filter((decorator) => decorator.type.toUpperCase() === type.toUpperCase())[0] || null\n );\n }\n\n /**\n * Gets the node attributes.\n */\n getGuardAttributes = (): Guard[] => this.getAttributes().filter((decorator) => decorator.isGuard()) as Guard[];\n\n /**\n * Sets the guard path to evaluate as part of a node update.\n */\n setGuardPath = (value: GuardPath) => (this.guardPath = value);\n\n /**\n * Gets whether a guard path is assigned to this node.\n */\n hasGuardPath = () => !!this.guardPath;\n\n /**\n * Gets whether this node is in the specified state.\n * @param value The value to compare to the node state.\n */\n public is(value: AnyState): boolean {\n return this.state === value;\n }\n\n /**\n * Reset the state of the node.\n */\n public reset(): void {\n this.setState(State.READY);\n }\n\n /**\n * Abort the running of this node.\n * @param agent The agent.\n */\n public abort(agent: Agent): void {\n // There is nothing to do if this node is not in the running state.\n if (!this.is(State.RUNNING)) {\n return;\n }\n\n // Reset the state of this node.\n this.reset();\n\n this.getAttribute(\"exit\")?.callAgentFunction(agent, false, true);\n }\n\n /**\n * Update the node.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n * @returns The result of the update.\n */\n public update(agent: Agent, options: BehaviourTreeOptions): void {\n // If this node is already in a 'SUCCEEDED' or 'FAILED' state then there is nothing to do.\n if (this.is(State.SUCCEEDED) || this.is(State.FAILED)) {\n return;\n }\n\n try {\n // Evaluate all of the guard path conditions for the current tree path.\n this.guardPath!.evaluate(agent);\n\n // If this node is in the READY state then call the ENTRY for this node if it exists.\n if (this.is(State.READY)) {\n this.getAttribute(\"entry\")?.callAgentFunction(agent);\n }\n\n this.getAttribute(\"step\")?.callAgentFunction(agent);\n\n // Do the actual update.\n this.onUpdate(agent, options);\n\n // If this node is now in a 'SUCCEEDED' or 'FAILED' state then call the EXIT for this node if it exists.\n if (this.is(State.SUCCEEDED) || this.is(State.FAILED)) {\n this.getAttribute(\"exit\")?.callAgentFunction(agent, this.is(State.SUCCEEDED), false);\n }\n } catch (error) {\n // If the error is a GuardUnsatisfiedException then we need to determine if this node is the source.\n if (error instanceof GuardUnsatisifedException && error.isSourceNode(this)) {\n // Abort the current node.\n this.abort(agent);\n\n // Any node that is the source of an abort will be a failed node.\n this.setState(State.FAILED);\n } else {\n throw error;\n }\n }\n }\n}\n\n/**\n * Create a randomly generated node uid.\n * @returns A randomly generated node uid.\n */\nfunction createNodeUid(): string {\n var S4 = function () {\n return (((1 + Math.random()) * 0x10000) | 0).toString(16).substring(1);\n };\n return S4() + S4() + \"-\" + S4() + \"-\" + S4() + \"-\" + S4() + \"-\" + S4() + S4() + S4();\n}\n", "import Node from \"../Node\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\n\n/**\n * A composite node that wraps child nodes.\n */\nexport default abstract class Composite extends Node {\n /**\n * @param type The node type.\n * @param attributes The node attributes.\n * @param children The child nodes.\n */\n constructor(type: string, attributes: Attribute[], protected children: Node[]) {\n super(type, attributes, []);\n }\n\n /**\n * Gets whether this node is a leaf node.\n */\n isLeafNode = () => false;\n\n /**\n * Gets the children of this node.\n */\n getChildren = () => this.children;\n\n /**\n * Reset the state of the node.\n */\n reset = () => {\n // Reset the state of this node.\n this.setState(State.READY);\n\n // Reset the state of any child nodes.\n this.getChildren().forEach((child) => child.reset());\n };\n\n /**\n * Abort the running of this node.\n * @param agent The agent.\n */\n abort = (agent: Agent) => {\n // There is nothing to do if this node is not in the running state.\n if (!this.is(State.RUNNING)) {\n return;\n }\n\n // Abort any child nodes.\n this.getChildren().forEach((child) => child.abort(agent));\n\n // Reset the state of this node.\n this.reset();\n\n this.getAttribute(\"exit\")?.callAgentFunction(agent, false, true);\n };\n}\n", "import Composite from \"./Composite\";\nimport State from \"../../State\";\nimport Node from \"../Node\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A PARALLEL node.\n * The child nodes are executed concurrently until one fails or all succeed.\n */\nexport default class Parallel extends Composite {\n /**\n * @param attributes The node attributes.\n * @param children The child nodes.\n */\n constructor(attributes: Attribute[], children: Node[]) {\n super(\"parallel\", attributes, children);\n }\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // Keep a count of the number of succeeded child nodes.\n let succeededCount = 0;\n\n let hasChildFailed = false;\n\n // Iterate over all of the children of this node.\n for (const child of this.children) {\n // If the child has never been updated or is running then we will need to update it now.\n if (child.getState() === State.READY || child.getState() === State.RUNNING) {\n // Update the child of this node.\n child.update(agent, options);\n }\n\n // If the current child has a state of 'SUCCEEDED' then we should move on to the next child.\n if (child.getState() === State.SUCCEEDED) {\n // The child node has succeeded, keep track of this to determine if all children have.\n succeededCount++;\n\n // The child node succeeded, but we have not finished checking every child node yet.\n continue;\n }\n\n // If the current child has a state of 'FAILED' then this node is also a 'FAILED' node.\n if (child.getState() === State.FAILED) {\n hasChildFailed = true;\n\n // There is no need to check the rest of the children.\n break;\n }\n\n // The node should be in the 'RUNNING' state.\n if (child.getState() !== State.RUNNING) {\n // The child node was not in an expected state.\n throw new Error(\"child node was not in an expected state.\");\n }\n }\n\n if (hasChildFailed) {\n // This node is a 'FAILED' node.\n this.setState(State.FAILED);\n\n // Abort every running child.\n for (const child of this.children) {\n if (child.getState() === State.RUNNING) {\n child.abort(agent);\n }\n }\n } else {\n // If all children have succeeded then this node has also succeeded, otherwise it is still running.\n this.setState(succeededCount === this.children.length ? State.SUCCEEDED : State.RUNNING);\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => \"PARALLEL\";\n}\n", "import Composite from \"./Composite\";\nimport Node from \"../Node\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A SELECTOR node.\n * The child nodes are executed in sequence until one succeeds or all fail.\n */\nexport default class Selector extends Composite {\n /**\n * @param attributes The node attributes.\n * @param children The child nodes.\n */\n constructor(attributes: Attribute[], protected children: Node[]) {\n super(\"selector\", attributes, children);\n }\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // Iterate over all of the children of this node.\n for (const child of this.children) {\n // If the child has never been updated or is running then we will need to update it now.\n if (child.getState() === State.READY || child.getState() === State.RUNNING) {\n // Update the child of this node.\n child.update(agent, options);\n }\n\n // If the current child has a state of 'SUCCEEDED' then this node is also a 'SUCCEEDED' node.\n if (child.getState() === State.SUCCEEDED) {\n // This node is a 'SUCCEEDED' node.\n this.setState(State.SUCCEEDED);\n\n // There is no need to check the rest of the selector nodes.\n return;\n }\n\n // If the current child has a state of 'FAILED' then we should move on to the next child.\n if (child.getState() === State.FAILED) {\n // Find out if the current child is the last one in the selector.\n // If it is then this sequence node has also failed.\n if (this.children.indexOf(child) === this.children.length - 1) {\n // This node is a 'FAILED' node.\n this.setState(State.FAILED);\n\n // There is no need to check the rest of the selector as we have completed it.\n return;\n } else {\n // The child node failed, try the next one.\n continue;\n }\n }\n\n // The node should be in the 'RUNNING' state.\n if (child.getState() === State.RUNNING) {\n // This node is a 'RUNNING' node.\n this.setState(State.RUNNING);\n\n // There is no need to check the rest of the selector as the current child is still running.\n return;\n }\n\n // The child node was not in an expected state.\n throw new Error(\"child node was not in an expected state.\");\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => \"SELECTOR\";\n}\n", "import Composite from \"./Composite\";\nimport Node from \"../Node\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A SEQUENCE node.\n * The child nodes are executed in sequence until one fails or all succeed.\n */\nexport default class Sequence extends Composite {\n /**\n * @param attributes The node attributes.\n * @param children The child nodes.\n */\n constructor(attributes: Attribute[], protected children: Node[]) {\n super(\"sequence\", attributes, children);\n }\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // Iterate over all of the children of this node.\n for (const child of this.children) {\n // If the child has never been updated or is running then we will need to update it now.\n if (child.getState() === State.READY || child.getState() === State.RUNNING) {\n // Update the child of this node.\n child.update(agent, options);\n }\n\n // If the current child has a state of 'SUCCEEDED' then we should move on to the next child.\n if (child.getState() === State.SUCCEEDED) {\n // Find out if the current child is the last one in the sequence.\n // If it is then this sequence node has also succeeded.\n if (this.children.indexOf(child) === this.children.length - 1) {\n // This node is a 'SUCCEEDED' node.\n this.setState(State.SUCCEEDED);\n\n // There is no need to check the rest of the sequence as we have completed it.\n return;\n } else {\n // The child node succeeded, but we have not finished the sequence yet.\n continue;\n }\n }\n\n // If the current child has a state of 'FAILED' then this node is also a 'FAILED' node.\n if (child.getState() === State.FAILED) {\n // This node is a 'FAILED' node.\n this.setState(State.FAILED);\n\n // There is no need to check the rest of the sequence.\n return;\n }\n\n // The node should be in the 'RUNNING' state.\n if (child.getState() === State.RUNNING) {\n // This node is a 'RUNNING' node.\n this.setState(State.RUNNING);\n\n // There is no need to check the rest of the sequence as the current child is still running.\n return;\n }\n\n // The child node was not in an expected state.\n throw new Error(\"child node was not in an expected state.\");\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => \"SEQUENCE\";\n}\n", "import createLotto from \"lotto-draw\";\n\nimport Node from \"../Node\";\nimport Composite from \"./Composite\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A LOTTO node.\n * A winning child is picked on the initial update of this node, based on ticket weighting.\n * The state of this node will match the state of the winning child.\n */\nexport default class Lotto extends Composite {\n /**\n * @param attributes The node attributes.\n * @param weights The child node weights.\n * @param children The child nodes.\n */\n constructor(attributes: Attribute[], private weights: number[] | undefined, children: Node[]) {\n super(\"lotto\", attributes, children);\n }\n\n /**\n * The child node selected to be the active one.\n */\n private selectedChild: Node | undefined;\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // If this node is in the READY state then we need to pick a winning child node.\n if (this.is(State.READY)) {\n // Create a lotto draw with which to randomly pick a child node to become the active one.\n const lottoDraw = createLotto({\n // Hook up the optional 'random' behaviour tree function option to the one used by 'lotto-draw'.\n random: options.random,\n // Pass in each child node as a participant in the lotto draw with their respective ticket count.\n participants: this.children.map((child, index) => [child, this.weights?.[index] || 1])\n });\n\n // Randomly pick a child based on ticket weighting, this will become the active child for this composite node.\n this.selectedChild = lottoDraw.draw() || undefined;\n }\n\n // If something went wrong and we don't have an active child then we should throw an error.\n if (!this.selectedChild) {\n throw new Error(\"failed to update lotto node as it has no active child\");\n }\n\n // If the selected child has never been updated or is running then we will need to update it now.\n if (this.selectedChild.getState() === State.READY || this.selectedChild.getState() === State.RUNNING) {\n this.selectedChild.update(agent, options);\n }\n\n // The state of the lotto node is the state of its selected child.\n this.setState(this.selectedChild.getState());\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => (this.weights ? `LOTTO [${this.weights.join(\",\")}]` : \"LOTTO\");\n}\n", "import Node from \"../Node\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\n\n/**\n * A decorator node that wraps a single child node.\n */\nexport default abstract class Decorator extends Node {\n /**\n * @param type The node type.\n * @param attributes The node attributes.\n * @param child The child node.\n */\n constructor(type: string, attributes: Attribute[], protected child: Node) {\n super(type, attributes, []);\n }\n\n /**\n * Gets whether this node is a leaf node.\n */\n isLeafNode = () => false;\n\n /**\n * Gets the children of this node.\n */\n getChildren = () => [this.child];\n\n /**\n * Reset the state of the node.\n */\n reset = () => {\n // Reset the state of this node.\n this.setState(State.READY);\n\n // Reset the state of the child node.\n this.child.reset();\n };\n\n /**\n * Abort the running of this node.\n * @param agent The agent.\n */\n abort = (agent: Agent) => {\n // There is nothing to do if this node is not in the running state.\n if (!this.is(State.RUNNING)) {\n return;\n }\n\n // Abort the child node.\n this.child.abort(agent);\n\n // Reset the state of this node.\n this.reset();\n\n this.getAttribute(\"exit\")?.callAgentFunction(agent, false, true);\n };\n}\n", "import Node from \"../Node\";\nimport Decorator from \"./Decorator\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A Fail node.\n * This node wraps a single child and will always move to the 'FAILED' state when the child moves to a 'SUCCEEDED' or 'FAILED' state.\n */\nexport default class Fail extends Decorator {\n /**\n * @param attributes The node attributes.\n * @param child The child node.\n */\n constructor(attributes: Attribute[], child: Node) {\n super(\"fail\", attributes, child);\n }\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // If the child has never been updated or is running then we will need to update it now.\n if (this.child.getState() === State.READY || this.child.getState() === State.RUNNING) {\n this.child.update(agent, options);\n }\n\n // The state of this node will depend in the state of its child.\n switch (this.child.getState()) {\n case State.RUNNING:\n this.setState(State.RUNNING);\n break;\n\n case State.SUCCEEDED:\n case State.FAILED:\n this.setState(State.FAILED);\n break;\n\n default:\n this.setState(State.READY);\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => \"FAIL\";\n}\n", "import Decorator from \"./Decorator\";\nimport State from \"../../State\";\nimport Node from \"../Node\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A Flip node.\n * This node wraps a single child and will flip the state of the child state.\n */\nexport default class Flip extends Decorator {\n /**\n * @param attributes The node attributes.\n * @param child The child node.\n */\n constructor(attributes: Attribute[], child: Node) {\n super(\"flip\", attributes, child);\n }\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // If the child has never been updated or is running then we will need to update it now.\n if (this.child.getState() === State.READY || this.child.getState() === State.RUNNING) {\n this.child.update(agent, options);\n }\n\n // The state of this node will depend in the state of its child.\n switch (this.child.getState()) {\n case State.RUNNING:\n this.setState(State.RUNNING);\n break;\n\n case State.SUCCEEDED:\n this.setState(State.FAILED);\n break;\n\n case State.FAILED:\n this.setState(State.SUCCEEDED);\n break;\n\n default:\n this.setState(State.READY);\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => \"FLIP\";\n}\n", "import Node from \"../Node\";\nimport Decorator from \"./Decorator\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A REPEAT node.\n * The node has a single child which can have:\n * -- A number of iterations for which to repeat the child node.\n * -- An infinite repeat loop if neither an iteration count or a condition function is defined.\n * The REPEAT node will stop and have a 'FAILED' state if its child is ever in a 'FAILED' state after an update.\n * The REPEAT node will attempt to move on to the next iteration if its child is ever in a 'SUCCEEDED' state.\n */\nexport default class Repeat extends Decorator {\n /**\n * @param attributes The node attributes.\n * @param iterations The number of iterations to repeat the child node.\n * @param iterationsMin The minimum possible number of iterations to repeat the child node.\n * @param iterationsMax The maximum possible number of iterations to repeat the child node.\n * @param child The child node.\n */\n constructor(\n attributes: Attribute[],\n private iterations: number | null,\n private iterationsMin: number | null,\n private iterationsMax: number | null,\n child: Node\n ) {\n super(\"repeat\", attributes, child);\n }\n\n /**\n * The number of target iterations to make.\n */\n private targetIterationCount: number | null = null;\n\n /**\n * The current iteration count.\n */\n private currentIterationCount: number = 0;\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // If this node is in the READY state then we need to reset the child and the target iteration count.\n if (this.is(State.READY)) {\n // Reset the child node.\n this.child.reset();\n\n // Reset the current iteration count.\n this.currentIterationCount = 0;\n\n // Set the target iteration count.\n this.setTargetIterationCount(options);\n }\n\n // Do a check to see if we can iterate. If we can then this node will move into the 'RUNNING' state.\n // If we cannot iterate then we have hit our target iteration count, which means that the node has succeeded.\n if (this.canIterate()) {\n // This node is in the running state and can do its initial iteration.\n this.setState(State.RUNNING);\n\n // We may have already completed an iteration, meaning that the child node will be in the SUCCEEDED state.\n // If this is the case then we will have to reset the child node now.\n if (this.child.getState() === State.SUCCEEDED) {\n this.child.reset();\n }\n\n // Update the child of this node.\n this.child.update(agent, options);\n\n // If the child moved into the FAILED state when we updated it then there is nothing left to do and this node has also failed.\n // If it has moved into the SUCCEEDED state then we have completed the current iteration.\n if (this.child.getState() === State.FAILED) {\n // The child has failed, meaning that this node has failed.\n this.setState(State.FAILED);\n\n return;\n } else if (this.child.getState() === State.SUCCEEDED) {\n // We have completed an iteration.\n this.currentIterationCount += 1;\n }\n } else {\n // This node is in the 'SUCCEEDED' state as we cannot iterate any more.\n this.setState(State.SUCCEEDED);\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => {\n if (this.iterations !== null) {\n return `REPEAT ${this.iterations}x`;\n } else if (this.iterationsMin !== null && this.iterationsMax !== null) {\n return `REPEAT ${this.iterationsMin}x-${this.iterationsMax}x`;\n } else {\n return \"REPEAT\";\n }\n };\n\n /**\n * Reset the state of the node.\n */\n reset = () => {\n // Reset the state of this node.\n this.setState(State.READY);\n\n // Reset the current iteration count.\n this.currentIterationCount = 0;\n\n // Reset the child node.\n this.child.reset();\n };\n\n /**\n * Gets whether an iteration can be made.\n * @returns Whether an iteration can be made.\n */\n private canIterate = () => {\n if (this.targetIterationCount !== null) {\n // We can iterate as long as we have not reached our target iteration count.\n return this.currentIterationCount < this.targetIterationCount;\n }\n\n // If neither an iteration count or a condition function were defined then we can iterate indefinitely.\n return true;\n };\n\n /**\n * Sets the target iteration count.\n * @param options The behaviour tree options object.\n */\n private setTargetIterationCount = (options: BehaviourTreeOptions) => {\n // Are we dealing with an explicit iteration count or will we be randomly picking a iteration count between the min and max iteration count.\n if (this.iterations !== null) {\n this.targetIterationCount = this.iterations;\n } else if (this.iterationsMin !== null && this.iterationsMax !== null) {\n // We will be picking a random iteration count between a min and max iteration count, if the optional 'random'\n // behaviour tree function option is defined then we will be using that, otherwise we will fall back to using Math.random.\n const random = typeof options.random === \"function\" ? options.random : Math.random;\n\n // Pick a random iteration count between a min and max iteration count.\n this.targetIterationCount = Math.floor(\n random() * (this.iterationsMax - this.iterationsMin + 1) + this.iterationsMin\n );\n } else {\n this.targetIterationCount = null;\n }\n };\n}\n", "import Node from \"../Node\";\nimport Decorator from \"./Decorator\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A RETRY node.\n * The node has a single child which can have:\n * -- A number of iterations for which to repeat the child node.\n * -- An infinite repeat loop if neither an iteration count or a condition function is defined.\n * The RETRY node will stop and have a 'SUCCEEDED' state if its child is ever in a 'SUCCEEDED' state after an update.\n * The RETRY node will attempt to move on to the next iteration if its child is ever in a 'FAILED' state.\n */\nexport default class Retry extends Decorator {\n /**\n * @param attributes The node attributes.\n * @param attempts The number of attempts to retry the child node.\n * @param attemptsMin The minimum possible number of attempts to retry the child node.\n * @param attemptsMax The maximum possible number of attempts to retry the child node.\n * @param child The child node.\n */\n constructor(\n attributes: Attribute[],\n private attempts: number | null,\n private attemptsMin: number | null,\n private attemptsMax: number | null,\n child: Node\n ) {\n super(\"retry\", attributes, child);\n }\n\n /**\n * The number of target attempts to make.\n */\n private targetAttemptCount: number | null = null;\n\n /**\n * The current attempt count.\n */\n private currentAttemptCount: number = 0;\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // If this node is in the READY state then we need to reset the child and the target attempt count.\n if (this.is(State.READY)) {\n // Reset the child node.\n this.child.reset();\n\n // Reset the current attempt count.\n this.currentAttemptCount = 0;\n\n // Set the target attempt count.\n this.setTargetAttemptCount(options);\n }\n\n // Do a check to see if we can attempt. If we can then this node will move into the 'RUNNING' state.\n // If we cannot attempt then we have hit our target attempt count, which means that the node has succeeded.\n if (this.canAttempt()) {\n // This node is in the running state and can do its initial attempt.\n this.setState(State.RUNNING);\n\n // We may have already completed an attempt, meaning that the child node will be in the FAILED state.\n // If this is the case then we will have to reset the child node now.\n if (this.child.getState() === State.FAILED) {\n this.child.reset();\n }\n\n // Update the child of this node.\n this.child.update(agent, options);\n\n // If the child moved into the SUCCEEDED state when we updated it then there is nothing left to do and this node has also succeeded.\n // If it has moved into the FAILED state then we have completed the current attempt.\n if (this.child.getState() === State.SUCCEEDED) {\n // The child has succeeded, meaning that this node has succeeded.\n this.setState(State.SUCCEEDED);\n\n return;\n } else if (this.child.getState() === State.FAILED) {\n // We have completed an attempt.\n this.currentAttemptCount += 1;\n }\n } else {\n // This node is in the 'FAILED' state as we cannot iterate any more.\n this.setState(State.FAILED);\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => {\n if (this.attempts !== null) {\n return `RETRY ${this.attempts}x`;\n } else if (this.attemptsMin !== null && this.attemptsMax !== null) {\n return `RETRY ${this.attemptsMin}x-${this.attemptsMax}x`;\n } else {\n return \"RETRY\";\n }\n };\n\n /**\n * Reset the state of the node.\n */\n reset = () => {\n // Reset the state of this node.\n this.setState(State.READY);\n\n // Reset the current attempt count.\n this.currentAttemptCount = 0;\n\n // Reset the child node.\n this.child.reset();\n };\n\n /**\n * Gets whether an attempt can be made.\n * @returns Whether an attempt can be made.\n */\n canAttempt = () => {\n if (this.targetAttemptCount !== null) {\n // We can attempt as long as we have not reached our target attempt count.\n return this.currentAttemptCount < this.targetAttemptCount;\n }\n\n // If neither an attempt count or a condition function were defined then we can attempt indefinitely.\n return true;\n };\n\n /**\n * Sets the target attempt count.\n * @param options The behaviour tree options object.\n */\n setTargetAttemptCount = (options: BehaviourTreeOptions) => {\n // Are we dealing with an explicit attempt count or will we be randomly picking an attempt count between the min and max attempt count.\n if (this.attempts !== null) {\n this.targetAttemptCount = this.attempts;\n } else if (this.attemptsMin !== null && this.attemptsMax !== null) {\n // We will be picking a random attempt count between a min and max attempt count, if the optional 'random'\n // behaviour tree function option is defined then we will be using that, otherwise we will fall back to using Math.random.\n const random = typeof options.random === \"function\" ? options.random : Math.random;\n\n // Pick a random attempt count between a min and max attempt count.\n this.targetAttemptCount = Math.floor(\n random() * (this.attemptsMax - this.attemptsMin + 1) + this.attemptsMin\n );\n } else {\n this.targetAttemptCount = null;\n }\n };\n}\n", "import Node from \"../Node\";\nimport Decorator from \"./Decorator\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A Root node.\n * The root node will have a single child.\n */\nexport default class Root extends Decorator {\n /**\n * @param attributes The node attributes.\n * @param child The child node.\n */\n constructor(attributes: Attribute[], child: Node) {\n super(\"root\", attributes, child);\n }\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // If the child has never been updated or is running then we will need to update it now.\n if (this.child.getState() === State.READY || this.child.getState() === State.RUNNING) {\n // Update the child of this node.\n this.child.update(agent, options);\n }\n\n // The state of the root node is the state of its child.\n this.setState(this.child.getState());\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => \"ROOT\";\n}\n", "import Node from \"../Node\";\nimport Decorator from \"./Decorator\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A Succeed node.\n * This node wraps a single child and will always move to the 'SUCCEEDED' state when the child moves to a 'SUCCEEDED' or 'FAILED' state.\n */\nexport default class Succeed extends Decorator {\n /**\n * @param attributes The node attributes.\n * @param child The child node.\n */\n constructor(attributes: Attribute[], child: Node) {\n super(\"succeed\", attributes, child);\n }\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // If the child has never been updated or is running then we will need to update it now.\n if (this.child.getState() === State.READY || this.child.getState() === State.RUNNING) {\n this.child.update(agent, options);\n }\n\n // The state of this node will depend in the state of its child.\n switch (this.child.getState()) {\n case State.RUNNING:\n this.setState(State.RUNNING);\n break;\n\n case State.SUCCEEDED:\n case State.FAILED:\n this.setState(State.SUCCEEDED);\n break;\n\n default:\n this.setState(State.READY);\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => \"SUCCEED\";\n}\n", "import Node from \"../Node\";\n\n/**\n * A leaf node.\n */\nexport default abstract class Leaf extends Node {\n /**\n * Gets whether this node is a leaf node.\n */\n isLeafNode = () => true;\n}\n", "import { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\nimport State, { CompleteState } from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Leaf from \"./Leaf\";\nimport Lookup from \"../../Lookup\";\nimport Attribute from \"../../attributes/Attribute\";\n\n/**\n * An Action leaf node.\n * This represents an immediate or ongoing state of behaviour.\n */\nexport default class Action extends Leaf {\n /**\n * @param attributes The node attributes.\n * @param actionName The action name.\n * @param actionArguments The array of action argument definitions.\n */\n constructor(attributes: Attribute[], private actionName: string, private actionArguments: any[]) {\n super(\"action\", attributes, actionArguments);\n }\n\n /**\n * Whether there is a pending update promise.\n */\n private isUsingUpdatePromise = false;\n\n /**\n * The finished state result of an update promise.\n */\n private updatePromiseStateResult: CompleteState | null = null;\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // If the result of this action depends on an update promise then there is nothing to do until\n // it resolves, unless there has been a value set as a result of the update promise resolving.\n if (this.isUsingUpdatePromise) {\n // Check whether the update promise has resolved with a state value.\n if (this.updatePromiseStateResult) {\n // Set the state of this node to match the state returned by the promise.\n this.setState(this.updatePromiseStateResult);\n }\n\n return;\n }\n\n // Attempt to get the invoker for the action function.\n const actionFuncInvoker = Lookup.getFuncInvoker(agent, this.actionName);\n\n // The action function should be defined.\n if (actionFuncInvoker === null) {\n throw new Error(\n `cannot update action node as the action '${this.actionName}' function is not defined on the agent and has not been registered`\n );\n }\n\n // Call the action function, the result of which may be:\n // - The finished state of this action node.\n // - A promise to return a finished node state.\n // - Undefined if the node should remain in the running state.\n const updateResult = actionFuncInvoker(this.actionArguments) as CompleteState | Promise;\n\n if (updateResult instanceof Promise) {\n updateResult.then(\n (result) => {\n // If 'isUpdatePromisePending' is null then the promise was cleared as it was resolving, probably via an abort of reset.\n if (!this.isUsingUpdatePromise) {\n return;\n }\n\n // Check to make sure the result is a valid finished state.\n if (result !== State.SUCCEEDED && result !== State.FAILED) {\n throw new Error(\n \"action node promise resolved with an invalid value, expected a State.SUCCEEDED or State.FAILED value to be returned\"\n );\n }\n\n // Set pending update promise state result to be processed on next update.\n this.updatePromiseStateResult = result;\n },\n (reason) => {\n // If 'isUpdatePromisePending' is null then the promise was cleared as it was resolving, probably via an abort of reset.\n if (!this.isUsingUpdatePromise) {\n return;\n }\n\n // Just throw whatever was returned as the rejection argument.\n throw new Error(reason);\n }\n );\n\n // This node will be in the 'RUNNING' state until the update promise resolves.\n this.setState(State.RUNNING);\n\n // We are now waiting for the promise returned by the use to resolve before we know what state this node is in.\n this.isUsingUpdatePromise = true;\n } else {\n // Validate the returned value.\n this.validateUpdateResult(updateResult);\n\n // Set the state of this node, this may be undefined, which just means that the node is still in the 'RUNNING' state.\n this.setState(updateResult || State.RUNNING);\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => this.actionName;\n\n /**\n * Reset the state of the node.\n */\n reset = () => {\n // Reset the state of this node.\n this.setState(State.READY);\n\n // There is no longer an update promise that we care about.\n this.isUsingUpdatePromise = false;\n this.updatePromiseStateResult = null;\n };\n\n /**\n * Validate the result of an update function call.\n * @param result The result of an update function call.\n */\n private validateUpdateResult = (result: CompleteState | boolean) => {\n switch (result) {\n case State.SUCCEEDED:\n case State.FAILED:\n case undefined:\n return;\n default:\n throw new Error(\n `action '${this.actionName}' 'onUpdate' returned an invalid response, expected an optional State.SUCCEEDED or State.FAILED value to be returned`\n );\n }\n };\n}\n", "import { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Leaf from \"./Leaf\";\nimport Lookup from \"../../Lookup\";\nimport Attribute from \"../../attributes/Attribute\";\n\n/**\n * A Condition leaf node.\n * This will succeed or fail immediately based on an agent predicate, without moving to the 'RUNNING' state.\n */\nexport default class Condition extends Leaf {\n /**\n * @param attributes The node attributes.\n * @param conditionName The name of the condition function.\n * @param conditionArguments The array of condition argument definitions.\n */\n constructor(attributes: Attribute[], private conditionName: string, private conditionArguments: any[]) {\n super(\"condition\", attributes, conditionArguments);\n }\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // Attempt to get the invoker for the condition function.\n const conditionFuncInvoker = Lookup.getFuncInvoker(agent, this.conditionName);\n\n // The condition function should be defined.\n if (conditionFuncInvoker === null) {\n throw new Error(\n `cannot update condition node as the condition '${this.conditionName}' function is not defined on the agent and has not been registered`\n );\n }\n\n // Call the condition function to determine the state of this node.\n this.setState(!!conditionFuncInvoker(this.conditionArguments) ? State.SUCCEEDED : State.FAILED);\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => this.conditionName;\n}\n", "import Leaf from \"./Leaf\";\nimport State from \"../../State\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { Agent } from \"../../Agent\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A WAIT node.\n * The state of this node will change to SUCCEEDED after a duration of time\n */\nexport default class Wait extends Leaf {\n /**\n * @param attributes The node attributes.\n * @param duration The duration that this node will wait to succeed in milliseconds.\n * @param durationMin The minimum possible duration in milliseconds that this node will wait to succeed.\n * @param durationMax The maximum possible duration in milliseconds that this node will wait to succeed.\n */\n constructor(\n attributes: Attribute[],\n private duration: number | null,\n private durationMin: number | null,\n private durationMax: number | null\n ) {\n super(\"wait\", attributes, []);\n }\n\n /**\n * The time in milliseconds at which this node was first updated.\n */\n private initialUpdateTime: number = 0;\n\n /**\n * The total duration in milliseconds that this node will be waiting for.\n */\n private totalDuration: number | null = null;\n\n /**\n * The duration in milliseconds that this node has been waiting for.\n */\n private waitedDuration: number = 0;\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // If this node is in the READY state then we need to set the initial update time.\n if (this.is(State.READY)) {\n // Set the initial update time.\n this.initialUpdateTime = new Date().getTime();\n\n // Set the initial waited duration.\n this.waitedDuration = 0;\n\n // Are we dealing with an explicit duration or will we be randomly picking a duration between the min and max duration.\n if (this.duration !== null) {\n this.totalDuration = this.duration;\n } else if (this.durationMin !== null && this.durationMax !== null) {\n // We will be picking a random duration between a min and max duration, if the optional 'random' behaviour tree\n // function option is defined then we will be using that, otherwise we will fall back to using Math.random.\n const random = typeof options.random === \"function\" ? options.random : Math.random;\n\n // Pick a random duration between a min and max duration.\n this.totalDuration = Math.floor(\n random() * (this.durationMax - this.durationMin + 1) + this.durationMin\n );\n } else {\n this.totalDuration = null;\n }\n\n // The node is now running until we finish waiting.\n this.setState(State.RUNNING);\n }\n\n // If we have no total duration then this wait node will wait indefinitely until it is aborted.\n if (this.totalDuration === null) {\n return;\n }\n\n // If we have a 'getDeltaTime' function defined as part of our options then we will use it to figure out how long we have waited for.\n if (typeof options.getDeltaTime === \"function\") {\n // Get the delta time.\n const deltaTime = options.getDeltaTime();\n\n // Our delta time must be a valid number and cannot be NaN.\n if (typeof deltaTime !== \"number\" || isNaN(deltaTime)) {\n throw new Error(\"The delta time must be a valid number and not NaN.\");\n }\n\n // Update the amount of time that this node has been waiting for based on the delta time.\n this.waitedDuration += deltaTime * 1000;\n } else {\n // We are not using a delta time, so we will just work out hom much time has passed since the first update.\n this.waitedDuration = new Date().getTime() - this.initialUpdateTime;\n }\n\n // Have we waited long enough?\n if (this.waitedDuration >= this.totalDuration) {\n // We have finished waiting!\n this.setState(State.SUCCEEDED);\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => {\n if (this.duration !== null) {\n return `WAIT ${this.duration}ms`;\n } else if (this.durationMin !== null && this.durationMax !== null) {\n return `WAIT ${this.durationMin}ms-${this.durationMax}ms`;\n } else {\n return \"WAIT\";\n }\n };\n}\n", "import Guard from \"./guards/Guard\";\n\nexport type AttributeDetails = {\n /** The attribute type. */\n type: string;\n\n /** The attribute arguments. */\n args: any[];\n};\n\n/**\n * A base node attribute.\n */\nexport default abstract class Attribute {\n /**\n * @param type The node attribute type.\n * @param args The array of attribute arguments.\n */\n constructor(public type: string, public args: any[]) {}\n\n /**\n * Gets the attribute details.\n */\n abstract getDetails(): TAttributeDetails;\n\n /**\n * Gets whether this attribute is a guard.\n */\n abstract isGuard: () => this is Guard;\n}\n", "import { Agent } from \"../../Agent\";\nimport Attribute, { AttributeDetails } from \"../Attribute\";\n\nexport type GuardAttributeDetails = {\n /** The name of the condition function that determines whether the guard is satisfied. */\n condition: string;\n} & AttributeDetails;\n\n/**\n * A base node guard attribute.\n */\nexport default abstract class Guard extends Attribute {\n /**\n * @param type The node attribute type.\n * @param args The array of decorator argument definitions.\n * @param condition The name of the condition function that determines whether the guard is satisfied.\n */\n constructor(type: string, args: any[], private condition: string) {\n super(type, args);\n }\n\n /**\n * Gets the name of the condition function that determines whether the guard is satisfied.\n */\n getCondition = () => this.condition;\n\n /**\n * Gets whether this attribute is a guard.\n */\n isGuard = () => true;\n\n /**\n * Gets the attribute details.\n */\n getDetails(): GuardAttributeDetails {\n return {\n type: this.type,\n args: this.args,\n condition: this.getCondition()\n };\n }\n\n /**\n * Gets whether the guard is satisfied.\n * @param agent The agent.\n * @returns Whether the guard is satisfied.\n */\n abstract isSatisfied(agent: Agent): boolean;\n}\n", "import Guard from \"./Guard\";\nimport Lookup from \"../../Lookup\";\nimport { Agent } from \"../../Agent\";\n\n/**\n * A WHILE guard which is satisfied as long as the given condition remains true.\n */\nexport default class While extends Guard {\n /**\n * @param condition The name of the condition function that determines whether the guard is satisfied.\n * @param args The array of decorator argument definitions.\n */\n constructor(condition: string, args: any[]) {\n super(\"while\", args, condition);\n }\n\n /**\n * Gets whether the guard is satisfied.\n * @param agent The agent.\n * @returns Whether the guard is satisfied.\n */\n isSatisfied = (agent: Agent) => {\n // Attempt to get the invoker for the condition function.\n const conditionFuncInvoker = Lookup.getFuncInvoker(agent, this.getCondition());\n\n // The condition function should be defined.\n if (conditionFuncInvoker === null) {\n throw new Error(\n `cannot evaluate node guard as the condition '${this.getCondition()}' function is not defined on the agent and has not been registered`\n );\n }\n\n // Call the condition function to determine whether this guard is satisfied.\n return !!conditionFuncInvoker(this.args);\n };\n}\n", "import Guard from \"./Guard\";\nimport Lookup from \"../../Lookup\";\nimport { Agent } from \"../../Agent\";\n\n/**\n * An UNTIL guard which is satisfied as long as the given condition remains false.\n */\nexport default class Until extends Guard {\n /**\n * @param condition The name of the condition function that determines whether the guard is satisfied.\n * @param args The array of decorator argument definitions.\n */\n constructor(condition: string, args: any[]) {\n super(\"until\", args, condition);\n }\n\n /**\n * Gets whether the guard is satisfied.\n * @param agent The agent.\n * @returns Whether the guard is satisfied.\n */\n isSatisfied = (agent: Agent) => {\n // Attempt to get the invoker for the condition function.\n const conditionFuncInvoker = Lookup.getFuncInvoker(agent, this.getCondition());\n\n // The condition function should be defined.\n if (conditionFuncInvoker === null) {\n throw new Error(\n `cannot evaluate node guard as the condition '${this.getCondition()}' function is not defined on the agent and has not been registered`\n );\n }\n\n // Call the condition function to determine whether this guard is satisfied.\n return !!!conditionFuncInvoker(this.args);\n };\n}\n", "import { Agent } from \"../../Agent\";\nimport Attribute, { AttributeDetails } from \"../Attribute\";\n\nexport type CallbackAttributeDetails = {\n /** The name of the agent function that is called. */\n functionName: string;\n} & AttributeDetails;\n\n/**\n * A base node callback attribute.\n */\nexport default abstract class Callback extends Attribute {\n /**\n * @param type The node attribute type.\n * @param args The array of decorator argument definitions.\n * @param functionName The name of the agent function to call.\n */\n constructor(type: string, args: any[], private functionName: string) {\n super(type, args);\n }\n\n /**\n * Gets the name of the agent function to call.\n */\n getFunctionName = () => this.functionName;\n\n /**\n * Gets whether this attribute is a guard.\n */\n isGuard = () => false;\n\n /**\n * Gets the attribute details.\n */\n getDetails(): CallbackAttributeDetails {\n return {\n type: this.type,\n args: this.args,\n functionName: this.getFunctionName()\n };\n }\n\n /**\n * Attempt to call the agent function that this callback refers to.\n * @param agent The agent.\n */\n abstract callAgentFunction: (agent: Agent, isSuccess: boolean, isAborted: boolean) => void;\n}\n", "import Callback from \"./Callback\";\nimport Lookup from \"../../Lookup\";\nimport { Agent } from \"../../Agent\";\n\n/**\n * An ENTRY callback which defines an agent function to call when the associated node is updated and moves out of running state.\n */\nexport default class Entry extends Callback {\n /**\n * @param functionName The name of the agent function to call.\n * @param args The array of callback argument definitions.\n */\n constructor(functionName: string, args: any[]) {\n super(\"entry\", args, functionName);\n }\n\n /**\n * Attempt to call the agent function that this callback refers to.\n * @param agent The agent.\n */\n callAgentFunction = (agent: Agent) => {\n // Attempt to get the invoker for the callback function.\n const callbackFuncInvoker = Lookup.getFuncInvoker(agent, this.getFunctionName());\n\n // The callback function should be defined.\n if (callbackFuncInvoker === null) {\n throw new Error(\n `cannot call entry function '${this.getFunctionName()}' as is not defined on the agent and has not been registered`\n );\n }\n\n // Call the callback function.\n callbackFuncInvoker(this.args);\n };\n}\n", "import Callback from \"./Callback\";\nimport Lookup from \"../../Lookup\";\nimport { Agent } from \"../../Agent\";\n\n/**\n * A STEP callback which defines an agent function to call when the associated node is updated.\n */\nexport default class Step extends Callback {\n /**\n * @param functionName The name of the agent function to call.\n * @param args The array of callback argument definitions.\n */\n constructor(functionName: string, args: any[]) {\n super(\"step\", args, functionName);\n }\n\n /**\n * Attempt to call the agent function that this callback refers to.\n * @param agent The agent.\n */\n callAgentFunction = (agent: Agent) => {\n // Attempt to get the invoker for the callback function.\n const callbackFuncInvoker = Lookup.getFuncInvoker(agent, this.getFunctionName());\n\n // The callback function should be defined.\n if (callbackFuncInvoker === null) {\n throw new Error(\n `cannot call step function '${this.getFunctionName()}' as is not defined on the agent and has not been registered`\n );\n }\n\n // Call the callback function.\n callbackFuncInvoker(this.args);\n };\n}\n", "import Callback from \"./Callback\";\nimport Lookup from \"../../Lookup\";\nimport { Agent } from \"../../Agent\";\n\n/**\n * An EXIT callback which defines an agent function to call when the associated node is updated and moves to a finished state or is aborted.\n */\nexport default class Exit extends Callback {\n /**\n * @param functionName The name of the agent function to call.\n * @param args The array of callback argument definitions.\n */\n constructor(functionName: string, args: any[]) {\n super(\"exit\", args, functionName);\n }\n\n /**\n * Attempt to call the agent function that this callback refers to.\n * @param agent The agent.\n * @param isSuccess Whether the decorated node was left with a success state.\n * @param isAborted Whether the decorated node was aborted.\n */\n callAgentFunction = (agent: Agent, isSuccess: boolean, isAborted: boolean) => {\n // Attempt to get the invoker for the callback function.\n const callbackFuncInvoker = Lookup.getFuncInvoker(agent, this.getFunctionName());\n\n // The callback function should be defined.\n if (callbackFuncInvoker === null) {\n throw new Error(\n `cannot call exit function '${this.getFunctionName()}' as is not defined on the agent and has not been registered`\n );\n }\n\n // Call the callback function\n callbackFuncInvoker([{ value: { succeeded: isSuccess, aborted: isAborted } }, ...this.args]);\n };\n}\n", "import { AnyNodeDefinition, RootNodeDefinition } from \"./BehaviourTreeDefinition\";\nimport GuardPath, { GuardPathPart } from \"./attributes/guards/GuardPath\";\nimport { validateBranchSubtreeLinks } from \"./BehaviourTreeDefinitionValidator\";\nimport { isInteger } from \"./BehaviourTreeDefinitionUtilities\";\nimport Node from \"./nodes/Node\";\nimport Composite from \"./nodes/composite/Composite\";\nimport Decorator from \"./nodes/decorator/Decorator\";\nimport Parallel from \"./nodes/composite/Parallel\";\nimport Selector from \"./nodes/composite/Selector\";\nimport Sequence from \"./nodes/composite/Sequence\";\nimport Lotto from \"./nodes/composite/Lotto\";\nimport Fail from \"./nodes/decorator/Fail\";\nimport Flip from \"./nodes/decorator/Flip\";\nimport Repeat from \"./nodes/decorator/Repeat\";\nimport Retry from \"./nodes/decorator/Retry\";\nimport Root from \"./nodes/decorator/Root\";\nimport Succeed from \"./nodes/decorator/Succeed\";\nimport Action from \"./nodes/leaf/Action\";\nimport Condition from \"./nodes/leaf/Condition\";\nimport Wait from \"./nodes/leaf/Wait\";\nimport Lookup from \"./Lookup\";\nimport Attribute from \"./attributes/Attribute\";\nimport While from \"./attributes/guards/While\";\nimport Until from \"./attributes/guards/Until\";\nimport Entry from \"./attributes/callbacks/Entry\";\nimport Step from \"./attributes/callbacks/Step\";\nimport Exit from \"./attributes/callbacks/Exit\";\n\n/**\n * A type representing any node instance in a behaviour tree.\n */\ntype AnyNode =\n | Root\n | Action\n | Condition\n | Wait\n | Sequence\n | Selector\n | Lotto\n | Parallel\n | Repeat\n | Retry\n | Flip\n | Succeed\n | Fail;\n\n/**\n * A type defining a mapping of root node identifiers to root node definitions.\n */\ntype RootNodeDefinitionMap = { [key: string | symbol]: RootNodeDefinition };\n\n/**\n * A symbol to use as the main root key in any root node mappings.\n */\nconst MAIN_ROOT_NODE_KEY = Symbol(\"__root__\");\n\n/**\n * Build and populate the root nodes based on the provided definition, assuming that the definition has been validated.\n * @param definition The root node definitions.\n * @returns The built and populated root node definitions.\n */\nexport default function buildRootNode(definition: RootNodeDefinition[]): Root {\n // Create a mapping of root node identifers to root node definitions, including globally registered subtree root node definitions.\n const rootNodeDefinitionMap = createRootNodeDefinitionMap(definition);\n\n // Now that we have all of our root node definitons (those part of the tree definition and those globally\n // registered) we should validate the definition. This will also double-check that we dont have any circular\n // dependencies in our branch -> subtree references and that we have no broken branch -> subtree links.\n validateBranchSubtreeLinks(definition, true);\n\n // Create our populated tree of node instances, starting with our main root node.\n const rootNode = nodeFactory(rootNodeDefinitionMap[MAIN_ROOT_NODE_KEY], rootNodeDefinitionMap) as Root;\n\n // Set a guard path on every leaf of the tree to evaluate as part of each update.\n applyLeafNodeGuardPaths(rootNode);\n\n // We only need to return the main root node.\n return rootNode;\n}\n\n/**\n * A factory function which creates a node instance based on the specified definition.\n * @param definition The node definition.\n * @param rootNodeDefinitionMap The mapping of root node identifers to root node definitions, including globally registered subtree root node definitions.\n * @returns A node instance based on the specified definition.\n */\nfunction nodeFactory(definition: AnyNodeDefinition, rootNodeDefinitionMap: RootNodeDefinitionMap): AnyNode {\n // Get the attributes for the node.\n const attributes = nodeAttributesFactory(definition);\n\n // Create the node instance based on the definition type.\n switch (definition.type) {\n case \"root\":\n return new Root(attributes, nodeFactory(definition.child, rootNodeDefinitionMap));\n\n case \"repeat\":\n let iterations: number | null = null;\n let iterationsMin: number | null = null;\n let iterationsMax: number | null = null;\n\n if (Array.isArray(definition.iterations)) {\n iterationsMin = definition.iterations[0];\n iterationsMax = definition.iterations[1];\n } else if (isInteger(definition.iterations)) {\n iterations = definition.iterations!;\n }\n\n return new Repeat(\n attributes,\n iterations,\n iterationsMin,\n iterationsMax,\n nodeFactory(definition.child, rootNodeDefinitionMap)\n );\n\n case \"retry\":\n let attempts: number | null = null;\n let attemptsMin: number | null = null;\n let attemptsMax: number | null = null;\n\n if (Array.isArray(definition.attempts)) {\n attemptsMin = definition.attempts[0];\n attemptsMax = definition.attempts[1];\n } else if (isInteger(definition.attempts)) {\n attempts = definition.attempts!;\n }\n\n return new Retry(\n attributes,\n attempts,\n attemptsMin,\n attemptsMax,\n nodeFactory(definition.child, rootNodeDefinitionMap)\n );\n\n case \"flip\":\n return new Flip(attributes, nodeFactory(definition.child, rootNodeDefinitionMap));\n\n case \"succeed\":\n return new Succeed(attributes, nodeFactory(definition.child, rootNodeDefinitionMap));\n\n case \"fail\":\n return new Fail(attributes, nodeFactory(definition.child, rootNodeDefinitionMap));\n\n case \"sequence\":\n return new Sequence(\n attributes,\n definition.children.map((child) => nodeFactory(child, rootNodeDefinitionMap))\n );\n\n case \"selector\":\n return new Selector(\n attributes,\n definition.children.map((child) => nodeFactory(child, rootNodeDefinitionMap))\n );\n\n case \"parallel\":\n return new Parallel(\n attributes,\n definition.children.map((child) => nodeFactory(child, rootNodeDefinitionMap))\n );\n\n case \"lotto\":\n return new Lotto(\n attributes,\n definition.weights,\n definition.children.map((child) => nodeFactory(child, rootNodeDefinitionMap))\n );\n\n case \"branch\":\n return nodeFactory(rootNodeDefinitionMap[definition.ref].child, rootNodeDefinitionMap);\n\n case \"action\":\n return new Action(attributes, definition.call, definition.args || []);\n\n case \"condition\":\n return new Condition(attributes, definition.call, definition.args || []);\n\n case \"wait\":\n let duration: number | null = null;\n let durationMin: number | null = null;\n let durationMax: number | null = null;\n\n if (Array.isArray(definition.duration)) {\n durationMin = definition.duration[0];\n durationMax = definition.duration[1];\n } else if (isInteger(definition.duration)) {\n duration = definition.duration!;\n }\n\n return new Wait(attributes, duration, durationMin, durationMax);\n }\n}\n\n/**\n * Creates an array of node attribute instances based on the specified node definition.\n * @param definition The node definition.\n * @returns An array of node attribute instances based on the specified node definition.\n */\nfunction nodeAttributesFactory(definition: AnyNodeDefinition): Attribute[] {\n const attributes: Attribute[] = [];\n\n if (definition.while) {\n attributes.push(new While(definition.while.call, definition.while.args ?? []));\n }\n\n if (definition.until) {\n attributes.push(new Until(definition.until.call, definition.until.args ?? []));\n }\n\n if (definition.entry) {\n attributes.push(new Entry(definition.entry.call, definition.entry.args ?? []));\n }\n\n if (definition.step) {\n attributes.push(new Step(definition.step.call, definition.step.args ?? []));\n }\n\n if (definition.exit) {\n attributes.push(new Exit(definition.exit.call, definition.exit.args ?? []));\n }\n\n return attributes;\n}\n\n/**\n * Creates a mapping of root node identifers to root node definitions, mixing in globally registered subtree root node definitions.\n * @param definition The root node definitions.\n * @returns A mapping of root node identifers to root node definitions, including globally registered subtree root node definitions.\n */\nfunction createRootNodeDefinitionMap(definition: RootNodeDefinition[]): RootNodeDefinitionMap {\n // Create a mapping of root node identifers to root node definitions.\n const rootNodeMap: RootNodeDefinitionMap = {};\n\n // Add in any registered subtree root node definitions.\n for (const [name, rootNodeDefinition] of Object.entries(Lookup.getSubtrees())) {\n // The name used when registering the subtree will be used as the root node identifier.\n rootNodeMap[name] = { ...rootNodeDefinition, id: name };\n }\n\n // Populate the map with the root node definitions that were included with the tree definition.\n // We do this after adding any registered subtrees as we want these to take presedence.\n for (const rootNodeDefinition of definition) {\n rootNodeMap[rootNodeDefinition.id ?? MAIN_ROOT_NODE_KEY] = rootNodeDefinition;\n }\n\n return rootNodeMap;\n}\n\n/**\n * Applies a guard path to every leaf of the tree to evaluate as part of each update.\n * @param root The main root tree node.\n */\nfunction applyLeafNodeGuardPaths(root: Root) {\n const nodePaths: Node[][] = [];\n\n const findLeafNodes = (path: Node[], node: Node) => {\n // Add the current node to the path.\n path = path.concat(node);\n\n // Check whether the current node is a leaf node.\n if (node.isLeafNode()) {\n nodePaths.push(path);\n } else {\n (node as Composite | Decorator).getChildren().forEach((child) => findLeafNodes(path, child));\n }\n };\n\n // Find all leaf node paths, starting from the root.\n findLeafNodes([], root);\n\n nodePaths.forEach((path) => {\n // Each node in the current path will have to be assigned a guard path, working from the root outwards.\n for (let depth = 0; depth < path.length; depth++) {\n // Get the node in the path at the current depth.\n const currentNode = path[depth];\n\n // The node may already have been assigned a guard path, if so just skip it.\n if (currentNode.hasGuardPath()) {\n continue;\n }\n\n // Create the guard path for the current node.\n const guardPath = new GuardPath(\n path\n .slice(0, depth + 1)\n .map((node) => ({ node, guards: node.getGuardAttributes() }))\n .filter((details) => details.guards.length > 0)\n );\n\n // Assign the guard path to the current node.\n currentNode.setGuardPath(guardPath);\n }\n });\n}\n", "import State, { AnyState } from \"./State\";\nimport Lookup from \"./Lookup\";\nimport Node from \"./nodes/Node\";\nimport Root from \"./nodes/decorator/Root\";\nimport Composite from \"./nodes/composite/Composite\";\nimport Decorator from \"./nodes/decorator/Decorator\";\nimport { Agent, GlobalFunction } from \"./Agent\";\nimport { CallbackAttributeDetails } from \"./attributes/callbacks/Callback\";\nimport { GuardAttributeDetails } from \"./attributes/guards/Guard\";\nimport { BehaviourTreeOptions } from \"./BehaviourTreeOptions\";\nimport { convertMDSLToJSON } from \"./mdsl/MDSLDefinitionParser\";\nimport { RootNodeDefinition } from \"./BehaviourTreeDefinition\";\nimport { validateDefinition, validateJSONDefinition } from \"./BehaviourTreeDefinitionValidator\";\nimport buildRootNode from \"./BehaviourTreeBuilder\";\nimport { isNullOrUndefined } from \"./BehaviourTreeDefinitionUtilities\";\n\n// Purely for outside inspection of the tree.\nexport type FlattenedTreeNode = {\n id: string;\n type: string;\n caption: string;\n state: AnyState;\n guards: GuardAttributeDetails[];\n callbacks: CallbackAttributeDetails[];\n args: any[];\n parentId: string | null;\n};\n\n/**\n * A representation of a behaviour tree.\n */\nexport class BehaviourTree {\n /**\n * The main root tree node.\n */\n public readonly rootNode: Root;\n\n /**\n * Creates a new instance of the BehaviourTree class.\n * @param definition The behaviour tree definition.\n * @param agent The agent instance that this behaviour tree is modelling behaviour for.\n * @param options The behaviour tree options object.\n */\n constructor(\n definition: string | RootNodeDefinition | RootNodeDefinition[],\n private agent: Agent,\n private options: BehaviourTreeOptions = {}\n ) {\n // The tree definition must be defined.\n if (isNullOrUndefined(definition)) {\n throw new Error(\"tree definition not defined\");\n }\n\n // The agent must be defined and not null.\n if (typeof agent !== \"object\" || agent === null) {\n throw new Error(\"the agent must be an object and not null\");\n }\n\n // We should validate the definition before we try to build the tree nodes.\n const { succeeded, errorMessage, json } = validateDefinition(definition);\n\n // Did our validation fail without error?\n if (!succeeded) {\n throw new Error(`invalid definition: ${errorMessage}`);\n }\n\n // Double check that we did actually get our json definition as part of our definition validtion.\n if (!json) {\n throw new Error(\n \"expected json definition to be returned as part of successful definition validation response\"\n );\n }\n\n try {\n // Create the populated tree of behaviour tree nodes and get the root node.\n this.rootNode = buildRootNode(json!);\n } catch (exception) {\n // There was an issue in trying build and populate the behaviour tree.\n throw new Error(`error building tree: ${(exception as Error).message}`);\n }\n }\n\n /**\n * Gets whether the tree is in the RUNNING state.\n * @returns true if the tree is in the RUNNING state, otherwise false.\n */\n isRunning() {\n return this.rootNode.getState() === State.RUNNING;\n }\n\n /**\n * Gets the current tree state of SUCCEEDED, FAILED, READY or RUNNING.\n * @returns The current tree state.\n */\n getState() {\n return this.rootNode.getState();\n }\n\n /**\n * Step the tree.\n * 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.\n * 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\n * 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.\n *\n * 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.\n */\n step() {\n // If the root node has already been stepped to completion then we need to reset it.\n if (this.rootNode.getState() === State.SUCCEEDED || this.rootNode.getState() === State.FAILED) {\n this.rootNode.reset();\n }\n\n try {\n this.rootNode.update(this.agent, this.options);\n } catch (exception) {\n throw new Error(`error stepping tree: ${(exception as Error).message}`);\n }\n }\n\n /**\n * Resets the tree from the root node outwards to each nested node, giving each a state of READY.\n */\n reset() {\n this.rootNode.reset();\n }\n\n /**\n * Gets the flattened details of every node in the tree.\n * @returns The flattened details of every node in the tree.\n */\n getFlattenedNodeDetails(): FlattenedTreeNode[] {\n // Create an empty flattened array of tree nodes.\n const flattenedTreeNodes: FlattenedTreeNode[] = [];\n\n /**\n * Helper function to process a node instance and push details into the flattened tree nodes array.\n * @param node The current node.\n * @param parentUid The UID of the node parent, or null if the node is the main root node.\n */\n const processNode = (node: Node, parentUid: string | null) => {\n // Get the guard and callback attribute details for this node.\n const guards = node\n .getAttributes()\n .filter((attribute) => attribute.isGuard())\n .map((attribute) => attribute.getDetails()) as GuardAttributeDetails[];\n const callbacks = node\n .getAttributes()\n .filter((attribute) => !attribute.isGuard())\n .map((attribute) => attribute.getDetails()) as CallbackAttributeDetails[];\n\n // Push the current node into the flattened nodes array.\n flattenedTreeNodes.push({\n id: node.getUid(),\n type: node.getType(),\n caption: node.getName(),\n state: node.getState(),\n guards,\n callbacks,\n args: node.getArguments(),\n parentId: parentUid\n });\n\n // Process each of the nodes children if it is not a leaf node.\n if (!node.isLeafNode()) {\n (node as Composite | Decorator)\n .getChildren()\n .forEach((child) => processNode(child, (node as Composite | Decorator).getUid()));\n }\n };\n\n // Convert the nested node structure into a flattened array of node details.\n processNode(this.rootNode, null);\n\n return flattenedTreeNodes;\n }\n\n /**\n * Registers the action/condition/guard/callback function or subtree with the given name.\n * @param name The name of the function or subtree to register.\n * @param value The function or subtree definition to register.\n */\n static register(name: string, value: GlobalFunction | string | RootNodeDefinition) {\n // Are we going to register a action/condition/guard/callback function?\n if (typeof value === \"function\") {\n Lookup.setFunc(name, value);\n return;\n }\n\n // We are not registering an action/condition/guard/callback function, so we must be registering a subtree.\n if (typeof value === \"string\") {\n let rootNodeDefinitions: RootNodeDefinition[];\n\n // We will assume that any string passed in will be a mdsl definition.\n try {\n rootNodeDefinitions = convertMDSLToJSON(value);\n } catch (exception) {\n throw new Error(`error registering definition, invalid MDSL: ${(exception as Error).message}`);\n }\n\n // This function should only ever be called with a definition containing a single unnamed root node.\n if (rootNodeDefinitions.length != 1 || rootNodeDefinitions[0].id !== null) {\n throw new Error(\"error registering definition: expected a single unnamed root node\");\n }\n\n try {\n // We should validate the subtree as we don't want invalid subtrees available via the lookup.\n const { succeeded, errorMessage } = validateJSONDefinition(rootNodeDefinitions[0]);\n\n // Did our validation fail without error?\n if (!succeeded) {\n throw new Error(errorMessage);\n }\n } catch (exception) {\n throw new Error(`error registering definition: ${(exception as Error).message}`);\n }\n\n // Everything seems hunky-dory, register the subtree.\n Lookup.setSubtree(name, rootNodeDefinitions[0]);\n } else if (typeof value === \"object\" && !Array.isArray(value)) {\n // We will assume that any object passed in is a root node definition.\n\n try {\n // We should validate the subtree as we don't want invalid subtrees available via the lookup.\n const { succeeded, errorMessage } = validateJSONDefinition(value);\n\n // Did our validation fail without error?\n if (!succeeded) {\n throw new Error(errorMessage);\n }\n } catch (exception) {\n throw new Error(`error registering definition: ${(exception as Error).message}`);\n }\n\n // Everything seems hunky-dory, register the subtree.\n Lookup.setSubtree(name, value);\n } else {\n throw new Error(\"unexpected value, expected string mdsl definition, root node json definition or function\");\n }\n }\n\n /**\n * Unregisters the registered action/condition/guard/callback function or subtree with the given name.\n * @param name The name of the registered action/condition/guard/callback function or subtree to unregister.\n */\n static unregister(name: string): void {\n Lookup.remove(name);\n }\n\n /**\n * Unregister all registered action/condition/guard/callback functions and subtrees.\n */\n static unregisterAll(): void {\n Lookup.empty();\n }\n}\n"], - "mappings": "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", + "sourcesContent": ["\"use strict\";\r\nObject.defineProperty(exports, \"__esModule\", { value: true });\r\nexports.Participant = void 0;\r\n/**\r\n * A participant that holds a number of tickets.\r\n */\r\nvar Participant = /** @class */ (function () {\r\n /**\r\n * Creates an instance of the Participant class.\r\n * @param participant The actual participant.\r\n * @param tickets The number of tickets held by the participant.\r\n */\r\n function Participant(participant, tickets) {\r\n if (tickets === void 0) { tickets = 1; }\r\n this._participant = participant;\r\n this._tickets = tickets;\r\n }\r\n Object.defineProperty(Participant.prototype, \"participant\", {\r\n /** Gets the actual participant. */\r\n get: function () {\r\n return this._participant;\r\n },\r\n enumerable: false,\r\n configurable: true\r\n });\r\n Object.defineProperty(Participant.prototype, \"tickets\", {\r\n /** Gets or sets the number of tickets held by the participant. */\r\n get: function () {\r\n return this._tickets;\r\n },\r\n set: function (value) {\r\n this._tickets = value;\r\n },\r\n enumerable: false,\r\n configurable: true\r\n });\r\n return Participant;\r\n}());\r\nexports.Participant = Participant;\r\n", "\"use strict\";\r\nObject.defineProperty(exports, \"__esModule\", { value: true });\r\nexports.isNaturalNumber = exports.isNullOrUndefined = void 0;\r\n/**\r\n * Gets whether the value provided is null or undefined.\r\n * @param value The value to check.\r\n * @returns Whether the value provided is null or undefined.\r\n */\r\nfunction isNullOrUndefined(value) {\r\n return value === null || value === undefined;\r\n}\r\nexports.isNullOrUndefined = isNullOrUndefined;\r\n/**\r\n * Gets whether the value provided is a natural number.\r\n * @param value The value to check.\r\n * @returns Whether the value provided is a natural number.\r\n */\r\nfunction isNaturalNumber(value) {\r\n return typeof value === \"number\" && value >= 1 && Math.floor(value) === value;\r\n}\r\nexports.isNaturalNumber = isNaturalNumber;\r\n", "\"use strict\";\r\nObject.defineProperty(exports, \"__esModule\", { value: true });\r\nexports.Lotto = void 0;\r\nvar Participant_1 = require(\"./Participant\");\r\nvar Utilities_1 = require(\"./Utilities\");\r\n/**\r\n * Represents a lotto consisting of a number of pickable ticket-holding participants.\r\n */\r\nvar Lotto = /** @class */ (function () {\r\n /**\r\n * Creates a new instance of Lotto.\r\n * @param customRandom The custom RNG to use in place of Math.random().\r\n */\r\n function Lotto(customRandom) {\r\n /** The array of participants that are holding tickets in the lotto. */\r\n this._participants = [];\r\n this._customRandom = customRandom;\r\n }\r\n /**\r\n * Adds a participant with the specified number of tickets, or adds to the participant ticket count if the participant already holds tickets.\r\n * @param participant The participant to add or to increase the ticket count for if they already hold tickets.\r\n * @param tickets The number of tickets, defaults to 1.\r\n * @returns The Lotto instance.\r\n */\r\n Lotto.prototype.add = function (participant, tickets) {\r\n if (tickets === void 0) { tickets = 1; }\r\n // Check that we have a valid ticket count.\r\n if (!(0, Utilities_1.isNaturalNumber)(tickets)) {\r\n throw new Error(\"tickets value must be a natural number\");\r\n }\r\n // Check whether this participant has already been added.\r\n var existingParticipant = this._participants.find(function (part) { return part.participant === participant; });\r\n if (existingParticipant) {\r\n // The participant has already been added to the lotto so just add to their ticket count.\r\n existingParticipant.tickets += tickets;\r\n }\r\n else {\r\n // The participant is not part of the lotto so we should add them.\r\n this._participants.push(new Participant_1.Participant(participant, tickets));\r\n }\r\n return this;\r\n };\r\n /**\r\n * Removes the specified number of tickets for the given participant from the draw, or all tickets if a ticket number is not defined.\r\n * @param participant The participant to remove tickets for.\r\n * @param tickets The number of tickets to remove, or undefined if all tickets are to be removed.\r\n * @returns The Lotto instance.\r\n */\r\n Lotto.prototype.remove = function (participant, tickets) {\r\n // Attempt to get the existing participant.\r\n var existingParticipant = this._participants.find(function (part) { return part.participant === participant; });\r\n // There is nothing to do if the specified participant isn't even part of the lotto.\r\n if (!existingParticipant) {\r\n return this;\r\n }\r\n // Check whether a tickets value was given.\r\n if (tickets !== undefined) {\r\n // Check that we have a valid ticket count.\r\n if (!(0, Utilities_1.isNaturalNumber)(tickets)) {\r\n throw new Error(\"tickets value must be a natural number\");\r\n }\r\n existingParticipant.tickets -= tickets;\r\n // If the participant no longer holds any tickets then they should be removed.\r\n if (existingParticipant.tickets < 1) {\r\n this._participants = this._participants.filter(function (part) { return part !== existingParticipant; });\r\n }\r\n }\r\n else {\r\n // We are removing all tickets for the participant so just remove them from the lotto.\r\n this._participants = this._participants.filter(function (part) { return part !== existingParticipant; });\r\n }\r\n return this;\r\n };\r\n /**\r\n * Draw a winning ticket and return the participant that holds the ticket.\r\n * @param options The draw options.\r\n * @returns The participant that holds the winning ticket.\r\n */\r\n Lotto.prototype.draw = function (options) {\r\n if (options === void 0) { options = {}; }\r\n // If we have no participants then just return null.\r\n if (this._participants.length === 0) {\r\n return null;\r\n }\r\n var redrawable = (0, Utilities_1.isNullOrUndefined)(options.redrawable) ? true : options.redrawable;\r\n var pickable = [];\r\n this._participants.forEach(function (_a) {\r\n var participant = _a.participant, tickets = _a.tickets;\r\n for (var ticketCount = 0; ticketCount < tickets; ticketCount++) {\r\n pickable.push(participant);\r\n }\r\n });\r\n var random;\r\n // We need a random floating-point number between 0 (inclusive) and 1 to scale up to pick our winner.\r\n // If a custom random function exists then we should use that or fall back to Math.random().\r\n if (this._customRandom) {\r\n // Call our custom random function to get a random floating-point number.\r\n random = this._customRandom();\r\n // Verify that the result of calling our custom random function is a number between 0 (inclusive) and 1.\r\n if (typeof random !== \"number\" || random < 0 || random >= 1) {\r\n throw new Error(\"the 'random' function provided did not return a number between 0 (inclusive) and 1\");\r\n }\r\n }\r\n else {\r\n // No custom random function was defined so just use good ol' Math.random().\r\n random = Math.random();\r\n }\r\n // Pick a winning participant.\r\n var winner = pickable[Math.floor(random * pickable.length)];\r\n // If the ticket isn't redrawable then we should remove a ticket from the winning participants ticket count.\r\n if (!redrawable) {\r\n this.remove(winner, 1);\r\n }\r\n // Return the winning participant.\r\n return winner;\r\n };\r\n /**\r\n * Draws multiple winning tickets and return an array of the participants that hold the winning tickets.\r\n * @param tickets The number of winning tickets to draw.\r\n * @param options The draw multiple options.\r\n * @returns An array of the participants that hold the winning tickets.\r\n */\r\n Lotto.prototype.drawMultiple = function (tickets, options) {\r\n if (options === void 0) { options = {}; }\r\n var uniqueResults = (0, Utilities_1.isNullOrUndefined)(options.unique) ? false : options.unique;\r\n // Handle cases where the user has asked for zero tickets (no idea why they would do this be we should trust them).\r\n if (tickets === 0) {\r\n return [];\r\n }\r\n // Now that we know out tickets value is not zero we should check that it is a valid natural number.\r\n if (!(0, Utilities_1.isNaturalNumber)(tickets)) {\r\n throw new Error(\"tickets value must be a natural number\");\r\n }\r\n var result = [];\r\n // Keep drawing tickets until we either reach the number of required tickets or we simply run out of tickets to draw.\r\n // We can run out of tickets to draw if 'options.redrawable' is explicity 'false' or we just had no participants when 'drawMultiple' was called.\r\n while (result.length < tickets && this._participants.length > 0) {\r\n result.push(this.draw(options));\r\n }\r\n // If the 'unique' draw option is set then we need to remove duplicates from the result list.\r\n if (uniqueResults) {\r\n // Create an array to store our unique results.\r\n var unique = [];\r\n // Iterate over all of our participants (with potential duplicates) and populate our array of unique values.\r\n for (var _i = 0, result_1 = result; _i < result_1.length; _i++) {\r\n var participant = result_1[_i];\r\n if (unique.indexOf(participant) === -1) {\r\n unique.push(participant);\r\n }\r\n }\r\n result = unique;\r\n }\r\n return result;\r\n };\r\n return Lotto;\r\n}());\r\nexports.Lotto = Lotto;\r\n", "\"use strict\";\r\nObject.defineProperty(exports, \"__esModule\", { value: true });\r\nexports.createLotto = void 0;\r\nvar Lotto_1 = require(\"./Lotto\");\r\n/**\r\n * A function that creates and returns a Lotto instance.\r\n * @param participantsOrOptions An array of initial participants or options relating to the creation of a Lotto instance.\r\n * @returns A new Lotto instance.\r\n */\r\nfunction createLotto(participantsOrOptions) {\r\n // If no initial participants or lotto options were provided as an argument then we can just return a new lotto instance now.\r\n if (!participantsOrOptions) {\r\n return new Lotto_1.Lotto();\r\n }\r\n // Check whether we were provided with an array of initial participants or a lotto options object.\r\n if (Array.isArray(participantsOrOptions)) {\r\n // We are dealing with a pre-defined array of participants.\r\n var participants = participantsOrOptions;\r\n var lotto_1 = new Lotto_1.Lotto();\r\n // If the lotto participants have been defined upfront then we will need to add them all to our lotto instance now.\r\n participants.forEach(function (_a) {\r\n var participant = _a[0], tokens = _a[1];\r\n return lotto_1.add(participant, tokens);\r\n });\r\n // Return the Lotto instance.\r\n return lotto_1;\r\n }\r\n else {\r\n // We are dealing with some lotto options.\r\n var random = participantsOrOptions.random, participants = participantsOrOptions.participants;\r\n // Create a Lotto instance passing the custom RNG function to use in place of Math.random() (which could be undefined).\r\n var lotto_2 = new Lotto_1.Lotto(random);\r\n // If the lotto participants have been defined upfront as part of the options then we will need to add them all to our lotto instance now.\r\n if (participants) {\r\n participants.forEach(function (_a) {\r\n var participant = _a[0], tokens = _a[1];\r\n return lotto_2.add(participant, tokens);\r\n });\r\n }\r\n // Return the Lotto instance.\r\n return lotto_2;\r\n }\r\n}\r\nexports.createLotto = createLotto;\r\n", "\"use strict\";\r\nObject.defineProperty(exports, \"__esModule\", { value: true });\r\nvar createLotto_1 = require(\"./createLotto\");\r\nexports.default = createLotto_1.createLotto;\r\n", "import State from \"./State\";\nimport { validateDefinition } from \"./BehaviourTreeDefinitionValidator\";\nimport { convertMDSLToJSON } from \"./mdsl/MDSLDefinitionParser\";\nimport { BehaviourTree, FlattenedTreeNode } from \"./BehaviourTree\";\nimport { BehaviourTreeOptions } from \"./BehaviourTreeOptions\";\n\nexport { BehaviourTree, State, convertMDSLToJSON, validateDefinition };\nexport type { FlattenedTreeNode, BehaviourTreeOptions };\n", "/**\n * Enumeration of node state types.\n */\nexport enum State {\n READY = \"mistreevous.ready\",\n RUNNING = \"mistreevous.running\",\n SUCCEEDED = \"mistreevous.succeeded\",\n FAILED = \"mistreevous.failed\"\n}\n\nexport { State as default };\n\nexport type CompleteState = State.SUCCEEDED | State.FAILED;\nexport type AnyState = State.READY | State.RUNNING | CompleteState;\n", "import {\n NodeDefinition,\n RootNodeDefinition,\n DecoratorNodeDefinition,\n CompositeNodeDefinition,\n AnyNodeDefinition,\n BranchNodeDefinition\n} from \"./BehaviourTreeDefinition\";\n\n/**\n * A type guard function that returns true if the specified node satisfies the RootNodeDefinition type.\n * @param node The node.\n * @returns A value of true if the specified node satisfies the RootNodeDefinition type.\n */\nexport function isRootNode(node: NodeDefinition): node is RootNodeDefinition {\n return node.type === \"root\";\n}\n\n/**\n * A type guard function that returns true if the specified node satisfies the BranchNodeDefinition type.\n * @param node The node.\n * @returns A value of true if the specified node satisfies the BranchNodeDefinition type.\n */\nexport function isBranchNode(node: NodeDefinition): node is BranchNodeDefinition {\n return node.type === \"branch\";\n}\n\n/**\n * A type guard function that returns true if the specified node satisfies the NodeDefinition type.\n * @param node The node.\n * @returns A value of true if the specified node satisfies the NodeDefinition type.\n */\nexport function isLeafNode(node: NodeDefinition): node is NodeDefinition {\n return [\"branch\", \"action\", \"condition\", \"wait\"].includes(node.type);\n}\n\n/**\n * A type guard function that returns true if the specified node satisfies the DecoratorNodeDefinition type.\n * @param node The node.\n * @returns A value of true if the specified node satisfies the DecoratorNodeDefinition type.\n */\nexport function isDecoratorNode(node: NodeDefinition): node is DecoratorNodeDefinition {\n return [\"root\", \"repeat\", \"retry\", \"flip\", \"succeed\", \"fail\"].includes(node.type);\n}\n\n/**\n * A type guard function that returns true if the specified node satisfies the CompositeNodeDefinition type.\n * @param node The node.\n * @returns A value of true if the specified node satisfies the CompositeNodeDefinition type.\n */\nexport function isCompositeNode(node: NodeDefinition): node is CompositeNodeDefinition {\n return [\"sequence\", \"selector\", \"lotto\", \"parallel\"].includes(node.type);\n}\n\n/**\n * Flatten a node definition into an array of all of its nested node definitions.\n * @param nodeDefinition The node definition to flatten.\n * @returns An array of all of nested node definitions.\n */\nexport function flattenDefinition(nodeDefinition: AnyNodeDefinition): AnyNodeDefinition[] {\n const nodes: AnyNodeDefinition[] = [];\n\n const processNode = (currentNodeDefinition: AnyNodeDefinition) => {\n nodes.push(currentNodeDefinition);\n\n if (isCompositeNode(currentNodeDefinition)) {\n currentNodeDefinition.children.forEach(processNode);\n } else if (isDecoratorNode(currentNodeDefinition)) {\n processNode(currentNodeDefinition.child);\n }\n };\n\n processNode(nodeDefinition);\n\n return nodes;\n}\n\n/**\n * Determines whether the passed value is an integer.\n * @param value The value to check.\n * @returns Whether the passed value is an integer.\n */\nexport function isInteger(value: unknown): boolean {\n return typeof value === \"number\" && Math.floor(value) === value;\n}\n\n/**\n * Determines whether the passed value is null or undefined.\n * @param value The value to check.\n * @returns Whether the passed value is null or undefined.\n */\nexport function isNullOrUndefined(value: unknown): boolean {\n return typeof value === \"undefined\" || value === null;\n}\n", "/**\n * A type defining an object that holds a reference to substitued string literals parsed from the definition.\n */\nexport type StringLiteralPlaceholders = { [key: string]: string };\n\n/**\n * Pop the next raw token from the specified array of tokens and throw an error if it wasn't the expected one.\n * @param tokens The array of tokens.\n * @param expected An optional string or array or items, one of which must match the next popped token.\n * @returns The popped token.\n */\nexport function popAndCheck(tokens: string[], expected?: string | string[]): string {\n // Get and remove the next token.\n const popped = tokens.shift();\n\n // We were expecting another token but there aren't any.\n if (popped === undefined) {\n throw new Error(\"unexpected end of definition\");\n }\n\n // Do we have an expected token/tokens array?\n if (expected != undefined) {\n // Get an array of expected values, if the popped token matches any then we are all good.\n const expectedValues = typeof expected === \"string\" ? [expected] : expected;\n\n // Check whether the popped token matches at least one of our expected items.\n var tokenMatchesExpectation = expectedValues.some((item) => popped.toUpperCase() === item.toUpperCase());\n\n // Throw an error if the popped token didn't match any of our expected items.\n if (!tokenMatchesExpectation) {\n const expectationString = expectedValues.map((item) => \"'\" + item + \"'\").join(\" or \");\n throw new Error(\"unexpected token found. Expected \" + expectationString + \" but got '\" + popped + \"'\");\n }\n }\n\n // Return the popped token.\n return popped;\n}\n\n/**\n * Swaps out any node/attribute argument string literals with placeholders.\n * @param definition The definition.\n * @returns An object containing a mapping of placeholders to original string values as well as the processed definition string.\n */\nexport function substituteStringLiterals(definition: string): {\n placeholders: StringLiteralPlaceholders;\n processedDefinition: string;\n} {\n // Create an object to hold the mapping of placeholders to original string values.\n const placeholders: StringLiteralPlaceholders = {};\n\n // Replace any string literals wrapped with double quotes in our definition with placeholders to be processed later.\n const processedDefinition = definition.replace(/\\\"(\\\\.|[^\"\\\\])*\\\"/g, (match) => {\n var strippedMatch = match.substring(1, match.length - 1);\n var placeholder = Object.keys(placeholders).find((key) => placeholders[key] === strippedMatch);\n\n // If we have no existing string literal match then create a new placeholder.\n if (!placeholder) {\n placeholder = `@@${Object.keys(placeholders).length}@@`;\n placeholders[placeholder] = strippedMatch;\n }\n\n return placeholder;\n });\n\n return { placeholders, processedDefinition };\n}\n\n/**\n * Parse the tree definition into an array of raw tokens.\n * @param definition The definition.\n * @returns An array of tokens parsed from the definition.\n */\nexport function parseTokensFromDefinition(definition: string): string[] {\n // Add some space around various important characters so that they can be plucked out easier as individual tokens.\n definition = definition.replace(/\\(/g, \" ( \");\n definition = definition.replace(/\\)/g, \" ) \");\n definition = definition.replace(/\\{/g, \" { \");\n definition = definition.replace(/\\}/g, \" } \");\n definition = definition.replace(/\\]/g, \" ] \");\n definition = definition.replace(/\\[/g, \" [ \");\n definition = definition.replace(/\\,/g, \" , \");\n\n // Split the definition into raw token form and return it.\n return definition.replace(/\\s+/g, \" \").trim().split(\" \");\n}\n", "import { StringLiteralPlaceholders, popAndCheck } from \"./MDSLUtilities\";\n\n/**\n * A type representing any node function argument.\n */\ntype Argument = {\n /**\n * The argument value.\n */\n value: T;\n /**\n * The argument type, used for validation.\n */\n type: string;\n};\n\ntype NullArgument = Argument & {\n type: \"null\";\n};\n\ntype BooleanArgument = Argument & {\n type: \"boolean\";\n};\n\ntype NumberArgument = Argument & {\n type: \"number\";\n /**\n * A flag defining whether the number argument value is a valid integer. (used for validation)\n */\n isInteger: boolean;\n};\n\ntype StringPlaceholderArgument = Argument & {\n type: \"string\";\n};\n\ntype IdentifierArgument = Argument & {\n type: \"identifier\";\n};\n\n/**\n * A type representing a reference to any node function argument.\n */\ntype AnyArgument = NullArgument | BooleanArgument | NumberArgument | StringPlaceholderArgument | IdentifierArgument;\n\n/**\n * Parse an array of argument definitions from the specified tokens array.\n * @param tokens The array tokens to parse the argument definitions from.\n * @param stringArgumentPlaceholders The mapping of string literal node argument placeholders to original values.\n * @param argumentValidator The argument validator function.\n * @param validationFailedMessage The exception message to throw if argument validation fails.\n * @returns An array of argument definitions parsed from the specified tokens array.\n */\nexport function parseArgumentTokens(\n tokens: string[],\n stringArgumentPlaceholders: StringLiteralPlaceholders\n): AnyArgument[] {\n const argumentList: AnyArgument[] = [];\n\n // If the next token is not a '[' or '(' then we have no arguments to parse.\n if (![\"[\", \"(\"].includes(tokens[0])) {\n return argumentList;\n }\n\n // Any lists of arguments will always be wrapped in '[]' for node arguments or '()' for attribute arguments.\n // We are looking for a '[' or '(' opener that wraps the argument tokens and the relevant closer.\n const closingToken = popAndCheck(tokens, [\"[\", \"(\"]) === \"[\" ? \"]\" : \")\";\n\n const argumentListTokens: string[] = [];\n\n // Grab all tokens between the '[' and ']' or '(' and ')'.\n while (tokens.length && tokens[0] !== closingToken) {\n // The next token is part of our arguments list.\n argumentListTokens.push(tokens.shift()!);\n }\n\n // Validate the order of the argument tokens. Each token must either be a ',' or a single argument that satisfies the validator.\n argumentListTokens.forEach((token, index) => {\n // Get whether this token should be an actual argument.\n const shouldBeArgumentToken = !(index & 1);\n\n // If the current token should be an actual argument then validate it, otherwise it should be a ',' token.\n if (shouldBeArgumentToken) {\n // Get the argument definition.\n const argumentDefinition = getArgumentDefinition(token, stringArgumentPlaceholders);\n\n // This is a valid argument!\n argumentList.push(argumentDefinition);\n } else {\n // The current token should be a ',' token.\n if (token !== \",\") {\n throw new Error(`invalid argument list, expected ',' or ']' but got '${token}'`);\n }\n }\n });\n\n // The arguments list should terminate with a ']' or ')' token, depending on the opener.\n popAndCheck(tokens, closingToken);\n\n // Return the arguments.\n return argumentList;\n}\n\n/**\n * Gets an argument value definition.\n * @param token The argument token.\n * @param stringArgumentPlaceholders The mapping of string literal node argument placeholders to original values.\n * @returns An argument value definition.\n */\nfunction getArgumentDefinition(token: string, stringArgumentPlaceholders: StringLiteralPlaceholders): AnyArgument {\n // Check whether the token represents a null value.\n if (token === \"null\") {\n return {\n value: null,\n type: \"null\"\n } as NullArgument;\n }\n\n // Check whether the token represents a boolean value.\n if (token === \"true\" || token === \"false\") {\n return {\n value: token === \"true\",\n type: \"boolean\"\n } as BooleanArgument;\n }\n\n // Check whether the token represents a number value.\n // TODO: Relies on broken isNaN - see MDN.\n // if (!Number.isNaN(token)) {\n if (!isNaN(token as any)) {\n return {\n value: parseFloat(token),\n isInteger: parseFloat(token) === parseInt(token, 10),\n type: \"number\"\n } as NumberArgument;\n }\n\n // Check whether the token is a placeholder (e.g. @@0@@) representing a string literal.\n if (token.match(/^@@\\d+@@$/g)) {\n return {\n value: stringArgumentPlaceholders[token].replace('\\\\\"', '\"'),\n type: \"string\"\n } as StringPlaceholderArgument;\n }\n\n // The only remaining option is that the argument value is an identifier.\n return {\n value: token,\n type: \"identifier\"\n } as IdentifierArgument;\n}\n", "import { NodeAttributeDefinition } from \"../BehaviourTreeDefinition\";\nimport { parseArgumentTokens } from \"./MDSLNodeArgumentParser\";\nimport { StringLiteralPlaceholders } from \"./MDSLUtilities\";\n\n/**\n * A type defining the attribute definitions of a node.\n */\ntype NodeAttributes = {\n while?: NodeAttributeDefinition;\n until?: NodeAttributeDefinition;\n entry?: NodeAttributeDefinition;\n exit?: NodeAttributeDefinition;\n step?: NodeAttributeDefinition;\n};\n\n/**\n * Parse any node attribute definitions from the specified tokens array.\n * @param tokens The array of remaining tokens.\n * @param stringArgumentPlaceholders The mapping of string literal node argument placeholders to original values.\n * @returns An object of attribute definitions defined by any directly following tokens.\n */\nexport function parseAttributeTokens(\n tokens: string[],\n stringArgumentPlaceholders: StringLiteralPlaceholders\n): NodeAttributes {\n const nodeAttributeNames: (keyof NodeAttributes)[] = [\"while\", \"until\", \"entry\", \"exit\", \"step\"];\n\n // Create an object to hold any attributes found.\n const attributes: NodeAttributes = {};\n\n // Try to get the name of the attribute for the next token.\n let nextAttributeName = tokens[0]?.toLowerCase() as keyof NodeAttributes;\n\n // Pull attribute tokens as well as their arguments off of the tokens stack until we have no more.\n while (nodeAttributeNames.includes(nextAttributeName)) {\n // Check to make sure that we have not already created an attribute definition of this type.\n if (attributes[nextAttributeName]) {\n throw new Error(`duplicate attribute '${tokens[0].toUpperCase()}' found for node`);\n }\n\n // Remove the attribute name token from the array of tokens.\n tokens.shift();\n\n // Grab the attribute arguments, assuming the first to be an identifier.\n const [attributeCallIdentifier, ...attributeArguments] = parseArgumentTokens(\n tokens,\n stringArgumentPlaceholders\n );\n\n // The first attribute argument has to be an identifer, this will reference an agent function.\n if (attributeCallIdentifier?.type !== \"identifier\") {\n throw new Error(\"expected agent function name identifier argument for attribute\");\n }\n\n // Any attribute arguments (other than the expected call identifier) must have a type of string, number, boolean or null.\n attributeArguments\n .filter((arg) => arg.type === \"identifier\")\n .forEach((arg) => {\n throw new Error(\n `invalid attribute argument value '${arg.value}', must be string, number, boolean or null`\n );\n });\n\n // Create the attribute definition and add it to the object of attribute definitions found.\n attributes[nextAttributeName] = {\n call: attributeCallIdentifier.value,\n args: attributeArguments.map(({ value }) => value)\n };\n\n // Try to get the next attribute name token, as there could be multiple.\n nextAttributeName = tokens[0]?.toLowerCase() as keyof NodeAttributes;\n }\n\n return attributes;\n}\n", "import {\n ActionNodeDefinition,\n AnyChildNodeDefinition,\n AnyNodeDefinition,\n BranchNodeDefinition,\n ConditionNodeDefinition,\n FailNodeDefinition,\n FlipNodeDefinition,\n LottoNodeDefinition,\n ParallelNodeDefinition,\n RepeatNodeDefinition,\n RetryNodeDefinition,\n RootNodeDefinition,\n SelectorNodeDefinition,\n SequenceNodeDefinition,\n SucceedNodeDefinition,\n WaitNodeDefinition\n} from \"../BehaviourTreeDefinition\";\nimport {\n isCompositeNode,\n isDecoratorNode,\n isLeafNode,\n isNullOrUndefined,\n isRootNode\n} from \"../BehaviourTreeDefinitionUtilities\";\nimport { parseArgumentTokens } from \"./MDSLNodeArgumentParser\";\nimport { parseAttributeTokens } from \"./MDSLNodeAttributeParser\";\nimport {\n StringLiteralPlaceholders,\n parseTokensFromDefinition,\n popAndCheck,\n substituteStringLiterals\n} from \"./MDSLUtilities\";\n\n/**\n * Convert the MDSL tree definition string into an equivalent JSON definition.\n * @param definition The tree definition string as MDSL.\n * @returns The root node JSON definitions.\n */\nexport function convertMDSLToJSON(definition: string): RootNodeDefinition[] {\n // Swap out any node/attribute argument string literals with a placeholder and get a mapping of placeholders to original values as well as the processed definition.\n const { placeholders, processedDefinition } = substituteStringLiterals(definition);\n\n // Parse our definition definition string into an array of raw tokens.\n const tokens = parseTokensFromDefinition(processedDefinition);\n\n return convertTokensToJSONDefinition(tokens, placeholders);\n}\n\n/**\n * Converts the specified tree definition tokens into a JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The root node JSON definitions.\n */\nfunction convertTokensToJSONDefinition(\n tokens: string[],\n stringLiteralPlaceholders: StringLiteralPlaceholders\n): RootNodeDefinition[] {\n // There must be at least 3 tokens for the tree definition to be valid. 'ROOT', '{' and '}'.\n if (tokens.length < 3) {\n throw new Error(\"invalid token count\");\n }\n\n // We should have a matching number of '{' and '}' tokens. If not, then there are scopes that have not been properly closed.\n if (tokens.filter((token) => token === \"{\").length !== tokens.filter((token) => token === \"}\").length) {\n throw new Error(\"scope character mismatch\");\n }\n\n // Create an array of tree stack arrays where root nodes will always be at the botton and the current composite/decorator node at the top.\n // There should be an element in this array for every root node defined and every element should be an array with a root note as the first element.\n // E.g. A definition with two root nodes defined:\n // [\n // [root, lotto, sequence],\n // [root, selector]\n // ]\n const treeStacks: [Partial, ...Partial[]][] = [];\n\n // Create an array of all root node definitions that we create.\n const rootNodes: Partial[] = [];\n\n // A helper function used to push node definitions onto the tree stack.\n const pushNode = (node: AnyNodeDefinition) => {\n // If the node is a root node then we need to create a new tree stack array with the root node at the root.\n if (isRootNode(node)) {\n // We need to double-check that this root node is not the child of another node.\n // We can do this by checking whether the top tree stack is not empty (contains an existing node)\n if (treeStacks[treeStacks.length - 1]?.length) {\n throw new Error(\"a root node cannot be the child of another node\");\n }\n\n // Add the root node definition to our array of all parsed root node definitions.\n rootNodes.push(node);\n\n // Add the root node definition to the root of a new tree stack.\n treeStacks.push([node]);\n\n return;\n }\n\n // All non-root nodes should be pushed after their root nodes so handle cases\n // where we may not have any tree stacks or our top-most tree stack is empty.\n if (!treeStacks.length || !treeStacks[treeStacks.length - 1].length) {\n throw new Error(\"expected root node at base of definition\");\n }\n\n // Get the current tree stack that we are populating.\n const topTreeStack = treeStacks[treeStacks.length - 1];\n\n // Get the top-most node in the current tree stack, this will be a composite/decorator node\n // for which we will populate its children array if composite or setting its child if a decorator.\n const topTreeStackTopNode = topTreeStack[topTreeStack.length - 1] as AnyNodeDefinition;\n\n // If the top-most node in the current root stack is a composite or decorator\n // node then the current node should be added as a child of the top-most node.\n if (isCompositeNode(topTreeStackTopNode)) {\n topTreeStackTopNode.children = topTreeStackTopNode.children || [];\n topTreeStackTopNode.children.push(node);\n } else if (isDecoratorNode(topTreeStackTopNode)) {\n // If the top node already has a child node set then throw an error as a decorator should only have a single child.\n if (topTreeStackTopNode.child) {\n throw new Error(\"a decorator node must only have a single child node\");\n }\n\n topTreeStackTopNode.child = node;\n }\n\n // If the node we are adding is also a composite or decorator node, then we should push it\n // onto the current tree stack, as subsequent nodes will be added as its child/children.\n if (!isLeafNode(node)) {\n topTreeStack.push(node);\n }\n };\n\n // A helper function used to pop the top-most node definition off of the tree stack and return it.\n const popNode = (): AnyNodeDefinition | null => {\n let poppedNode: AnyNodeDefinition | null = null;\n\n // Get the current tree stack that we are populating.\n const topTreeStack = treeStacks[treeStacks.length - 1];\n\n // Pop the top-most node in the current tree stack if there is one.\n if (topTreeStack.length) {\n poppedNode = topTreeStack.pop() as AnyNodeDefinition;\n }\n\n // We don't want any empty tree stacks in our stack of tree stacks.\n if (!topTreeStack.length) {\n treeStacks.pop();\n }\n\n return poppedNode;\n };\n\n // We should keep processing the raw tokens until we run out of them.\n while (tokens.length) {\n // Grab the next token.\n const token = tokens.shift()!;\n\n // How we create the next node depends on the current raw token value.\n switch (token.toUpperCase()) {\n case \"ROOT\": {\n pushNode(createRootNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"SUCCEED\": {\n pushNode(createSucceedNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"FAIL\": {\n pushNode(createFailNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"FLIP\": {\n pushNode(createFlipNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"REPEAT\": {\n pushNode(createRepeatNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"RETRY\": {\n pushNode(createRetryNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"SEQUENCE\": {\n pushNode(createSequenceNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"SELECTOR\": {\n pushNode(createSelectorNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"PARALLEL\": {\n pushNode(createParallelNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"LOTTO\": {\n pushNode(createLottoNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"ACTION\": {\n pushNode(createActionNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"CONDITION\": {\n pushNode(createConditionNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"WAIT\": {\n pushNode(createWaitNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"BRANCH\": {\n pushNode(createBranchNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"}\": {\n // The '}' character closes the current scope and means that we have to pop a node off of the current stack.\n const poppedNode = popNode();\n\n // Now that we have a node definition we can carry out any validation that may require the node to be fully populated.\n if (poppedNode) {\n validatePoppedNode(poppedNode);\n }\n\n break;\n }\n\n default: {\n throw new Error(`unexpected token: ${token}`);\n }\n }\n }\n\n return rootNodes as RootNodeDefinition[];\n}\n\n/**\n * Creates a root node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The root node JSON definition.\n */\nfunction createRootNode(tokens: string[], stringLiteralPlaceholders: StringLiteralPlaceholders): RootNodeDefinition {\n // Create the root node definition.\n let node = {\n type: \"root\",\n id: undefined\n } as RootNodeDefinition;\n\n // Parse any node arguments, we should only have one if any which will be an identifier argument for the root identifier.\n const nodeArguments = parseArgumentTokens(tokens, stringLiteralPlaceholders);\n\n // Check whether any node arguments were defined.\n if (nodeArguments.length) {\n // We should only have one argument, if any, which will be an identifier argument for the root identifier.\n if (nodeArguments.length === 1 && nodeArguments[0].type === \"identifier\") {\n // The root node identifier will be the first and only node argument value.\n node.id = nodeArguments[0].value as string;\n } else {\n throw new Error(\"expected single root name argument\");\n }\n }\n\n // Grab any node attribute definitions and spread them into the node definition.\n node = { ...node, ...parseAttributeTokens(tokens, stringLiteralPlaceholders) };\n\n // This is a decorator node, so we expect an opening '{'.\n popAndCheck(tokens, \"{\");\n\n // Return the root node definition.\n return node;\n}\n\n/**\n * Creates a succeed node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The succeed node JSON definition.\n */\nfunction createSucceedNode(\n tokens: string[],\n stringLiteralPlaceholders: StringLiteralPlaceholders\n): SucceedNodeDefinition {\n const node = {\n type: \"succeed\",\n ...parseAttributeTokens(tokens, stringLiteralPlaceholders)\n } as SucceedNodeDefinition;\n\n // This is a decorator node, so we expect an opening '{'.\n popAndCheck(tokens, \"{\");\n\n // Return the succeed node definition.\n return node;\n}\n\n/**\n * Creates a fail node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The fail node JSON definition.\n */\nfunction createFailNode(tokens: string[], stringLiteralPlaceholders: StringLiteralPlaceholders): FailNodeDefinition {\n const node = {\n type: \"fail\",\n ...parseAttributeTokens(tokens, stringLiteralPlaceholders)\n } as FailNodeDefinition;\n\n // This is a decorator node, so we expect an opening '{'.\n popAndCheck(tokens, \"{\");\n\n // Return the fail node definition.\n return node;\n}\n\n/**\n * Creates a flip node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The flip node JSON definition.\n */\nfunction createFlipNode(tokens: string[], stringLiteralPlaceholders: StringLiteralPlaceholders): FlipNodeDefinition {\n const node = {\n type: \"flip\",\n ...parseAttributeTokens(tokens, stringLiteralPlaceholders)\n } as FlipNodeDefinition;\n\n // This is a decorator node, so we expect an opening '{'.\n popAndCheck(tokens, \"{\");\n\n // Return the flip node definition.\n return node;\n}\n\n/**\n * Creates a repeat node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The repeat node JSON definition.\n */\nfunction createRepeatNode(\n tokens: string[],\n stringLiteralPlaceholders: StringLiteralPlaceholders\n): RepeatNodeDefinition {\n let node = { type: \"repeat\" } as RepeatNodeDefinition;\n\n // Get the node arguments.\n const nodeArguments = parseArgumentTokens(tokens, stringLiteralPlaceholders);\n\n // The arguments of a repeat node are optional. We may have:\n // - No node arguments, in which case the repeat note will iterate indefinitely.\n // - One node argument which will be the explicit number of iterations to make.\n // - Two node arguments which define the min and max iteration bounds from which a random iteration count will be picked.\n if (nodeArguments.length) {\n // All repeat node arguments MUST be of type number and must be integer.\n nodeArguments\n .filter((arg) => arg.type !== \"number\" || !arg.isInteger)\n .forEach(() => {\n throw new Error(`repeat node iteration counts must be integer values`);\n });\n\n // We should have got one or two iteration counts.\n if (nodeArguments.length === 1) {\n // A static iteration count was defined.\n node.iterations = nodeArguments[0].value as number;\n\n // A repeat node must have a positive number of iterations if defined.\n if (node.iterations < 0) {\n throw new Error(\"a repeat node must have a positive number of iterations if defined\");\n }\n } else if (nodeArguments.length === 2) {\n // A minimum and maximum iteration count was defined.\n node.iterations = [nodeArguments[0].value as number, nodeArguments[1].value as number];\n\n // A repeat node must have a positive min and max iteration count if they are defined.\n if (node.iterations[0] < 0 || node.iterations[1] < 0) {\n throw new Error(\"a repeat node must have a positive minimum and maximum iteration count if defined\");\n }\n\n // A repeat node must not have an minimum iteration count that exceeds the maximum iteration count.\n if (node.iterations[0] > node.iterations[1]) {\n throw new Error(\n \"a repeat node must not have a minimum iteration count that exceeds the maximum iteration count\"\n );\n }\n } else {\n // An incorrect number of iteration counts was defined.\n throw new Error(\"invalid number of repeat node iteration count arguments defined\");\n }\n }\n\n // Grab any node attribute definitions and spread them into the node definition.\n node = { ...node, ...parseAttributeTokens(tokens, stringLiteralPlaceholders) };\n\n // This is a decorator node, so we expect an opening '{'.\n popAndCheck(tokens, \"{\");\n\n // Return the repeat node definition.\n return node;\n}\n\n/**\n * Creates a retry node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The retry node JSON definition.\n */\nfunction createRetryNode(tokens: string[], stringLiteralPlaceholders: StringLiteralPlaceholders): RetryNodeDefinition {\n let node = { type: \"retry\" } as RetryNodeDefinition;\n\n // Get the node arguments.\n const nodeArguments = parseArgumentTokens(tokens, stringLiteralPlaceholders);\n\n // The arguments of a retry node are optional. We may have:\n // - No node arguments, in which case the retry note will attempt indefinitely.\n // - One node argument which will be the explicit number of attempts to make.\n // - Two node arguments which define the min and max attempt bounds from which a random attempt count will be picked.\n if (nodeArguments.length) {\n // All retry node arguments MUST be of type number and must be integer.\n nodeArguments\n .filter((arg) => arg.type !== \"number\" || !arg.isInteger)\n .forEach(() => {\n throw new Error(`retry node attempt counts must be integer values`);\n });\n\n // We should have got one or two attempt counts.\n if (nodeArguments.length === 1) {\n // A static attempt count was defined.\n node.attempts = nodeArguments[0].value as number;\n\n // A retry node must have a positive number of attempts if defined.\n if (node.attempts < 0) {\n throw new Error(\"a retry node must have a positive number of attempts if defined\");\n }\n } else if (nodeArguments.length === 2) {\n // A minimum and maximum attempt count was defined.\n node.attempts = [nodeArguments[0].value as number, nodeArguments[1].value as number];\n\n // A retry node must have a positive min and max attempts count if they are defined.\n if (node.attempts[0] < 0 || node.attempts[1] < 0) {\n throw new Error(\"a retry node must have a positive minimum and maximum attempt count if defined\");\n }\n\n // A retry node must not have a minimum attempt count that exceeds the maximum attempt count.\n if (node.attempts[0] > node.attempts[1]) {\n throw new Error(\n \"a retry node must not have a minimum attempt count that exceeds the maximum attempt count\"\n );\n }\n } else {\n // An incorrect number of attempt counts was defined.\n throw new Error(\"invalid number of retry node attempt count arguments defined\");\n }\n }\n\n // Grab any node attribute definitions and spread them into the node definition.\n node = { ...node, ...parseAttributeTokens(tokens, stringLiteralPlaceholders) };\n\n // This is a decorator node, so we expect an opening '{'.\n popAndCheck(tokens, \"{\");\n\n // Return the retry node definition.\n return node;\n}\n\n/**\n * Creates a sequence node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The sequence node JSON definition.\n */\nfunction createSequenceNode(\n tokens: string[],\n stringLiteralPlaceholders: StringLiteralPlaceholders\n): SequenceNodeDefinition {\n const node = {\n type: \"sequence\",\n ...parseAttributeTokens(tokens, stringLiteralPlaceholders)\n } as SequenceNodeDefinition;\n\n // This is a composite node, so we expect an opening '{'.\n popAndCheck(tokens, \"{\");\n\n // Return the sequence node definition.\n return node;\n}\n\n/**\n * Creates a selector node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The selector node JSON definition.\n */\nfunction createSelectorNode(\n tokens: string[],\n stringLiteralPlaceholders: StringLiteralPlaceholders\n): SelectorNodeDefinition {\n const node = {\n type: \"selector\",\n ...parseAttributeTokens(tokens, stringLiteralPlaceholders)\n } as SelectorNodeDefinition;\n\n // This is a composite node, so we expect an opening '{'.\n popAndCheck(tokens, \"{\");\n\n // Return the selector node definition.\n return node;\n}\n\n/**\n * Creates a parallel node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The parallel node JSON definition.\n */\nfunction createParallelNode(\n tokens: string[],\n stringLiteralPlaceholders: StringLiteralPlaceholders\n): ParallelNodeDefinition {\n const node = {\n type: \"parallel\",\n ...parseAttributeTokens(tokens, stringLiteralPlaceholders)\n } as ParallelNodeDefinition;\n\n // This is a composite node, so we expect an opening '{'.\n popAndCheck(tokens, \"{\");\n\n // Return the parallel node definition.\n return node;\n}\n\n/**\n * Creates a lotto node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The lotto node JSON definition.\n */\nfunction createLottoNode(tokens: string[], stringLiteralPlaceholders: StringLiteralPlaceholders): LottoNodeDefinition {\n // If any node arguments have been defined then they must be our weights.\n const nodeArguments = parseArgumentTokens(tokens, stringLiteralPlaceholders);\n\n // All lotto node arguments MUST be of type number and must be positive integers.\n nodeArguments\n .filter((arg) => arg.type !== \"number\" || !arg.isInteger || arg.value < 0)\n .forEach(() => {\n throw new Error(`lotto node weight arguments must be positive integer values`);\n });\n\n const node = {\n type: \"lotto\",\n weights: nodeArguments.length ? nodeArguments.map(({ value }) => value) : undefined,\n ...parseAttributeTokens(tokens, stringLiteralPlaceholders)\n } as LottoNodeDefinition;\n\n // This is a composite node, so we expect an opening '{'.\n popAndCheck(tokens, \"{\");\n\n // Return the lotto node definition.\n return node;\n}\n\n/**\n * Creates an action node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The action node JSON definition.\n */\nfunction createActionNode(\n tokens: string[],\n stringLiteralPlaceholders: StringLiteralPlaceholders\n): ActionNodeDefinition {\n // Parse any node arguments, we should have at least one which will be an identifier argument for the action name\n // and agent function to invoke for the action, all other arguments are to be passed as arguments to that function.\n const [actionNameIdentifier, ...agentFunctionArgs] = parseArgumentTokens(tokens, stringLiteralPlaceholders);\n\n // Our first argument MUST be defined and be an identifier as we require an action name argument.\n if (actionNameIdentifier?.type !== \"identifier\") {\n throw new Error(\"expected action name identifier argument\");\n }\n\n // Only the first argument should have been an identifier, all agent function arguments must be string, number, boolean or null.\n agentFunctionArgs\n .filter((arg) => arg.type === \"identifier\")\n .forEach((arg) => {\n throw new Error(\n `invalid action node argument value '${arg.value}', must be string, number, boolean or null`\n );\n });\n\n // Return the action node definition.\n return {\n type: \"action\",\n call: actionNameIdentifier.value,\n args: agentFunctionArgs.map(({ value }) => value),\n ...parseAttributeTokens(tokens, stringLiteralPlaceholders)\n };\n}\n\n/**\n * Creates a condition node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The condition node JSON definition.\n */\nfunction createConditionNode(\n tokens: string[],\n stringLiteralPlaceholders: StringLiteralPlaceholders\n): ConditionNodeDefinition {\n // Parse any node arguments, we should have at least one which will be an identifier argument for the condition name\n // and agent function to invoke for the condition, all other arguments are to be passed as arguments to that function.\n const [conditionNameIdentifier, ...agentFunctionArgs] = parseArgumentTokens(tokens, stringLiteralPlaceholders);\n\n // Our first argument MUST be defined and be an identifier as we require a condition name argument.\n if (conditionNameIdentifier?.type !== \"identifier\") {\n throw new Error(\"expected condition name identifier argument\");\n }\n\n // Only the first argument should have been an identifier, all agent function arguments must be string, number, boolean or null.\n agentFunctionArgs\n .filter((arg) => arg.type === \"identifier\")\n .forEach((arg) => {\n throw new Error(\n `invalid condition node argument value '${arg.value}', must be string, number, boolean or null`\n );\n });\n\n // Return the condition node definition.\n return {\n type: \"condition\",\n call: conditionNameIdentifier.value,\n args: agentFunctionArgs.map(({ value }) => value),\n ...parseAttributeTokens(tokens, stringLiteralPlaceholders)\n };\n}\n\n/**\n * Creates a wait node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The wait node JSON definition.\n */\nfunction createWaitNode(tokens: string[], stringLiteralPlaceholders: StringLiteralPlaceholders): WaitNodeDefinition {\n let node = { type: \"wait\" } as WaitNodeDefinition;\n\n // Get the node arguments.\n const nodeArguments = parseArgumentTokens(tokens, stringLiteralPlaceholders);\n\n // The arguments of a wait node are optional. We may have:\n // - No node arguments, in which case the wait will be indefinite until it is aborted.\n // - One node argument which will be the explicit duration of the wait.\n // - Two node arguments which define the min and max duration bounds from which a random duration will be picked.\n if (nodeArguments.length) {\n // All wait node arguments MUST be of type number and must be integer.\n nodeArguments\n .filter((arg) => arg.type !== \"number\" || !arg.isInteger)\n .forEach(() => {\n throw new Error(`wait node durations must be integer values`);\n });\n\n // We may have:\n // - One node argument which will be the explicit duration of the wait.\n // - Two node arguments which define the min and max duration bounds from which a random duration will be picked.\n // - Too many arguments, which is not valid.\n if (nodeArguments.length === 1) {\n // An explicit duration was defined.\n node.duration = nodeArguments[0].value as number;\n\n // If an explict duration was defined then it must be a positive number.\n if (node.duration < 0) {\n throw new Error(\"a wait node must have a positive duration\");\n }\n } else if (nodeArguments.length === 2) {\n // Min and max duration bounds were defined from which a random duration will be picked.\n node.duration = [nodeArguments[0].value as number, nodeArguments[1].value as number];\n\n // A wait node must have a positive min and max duration.\n if (node.duration[0] < 0 || node.duration[1] < 0) {\n throw new Error(\"a wait node must have a positive minimum and maximum duration\");\n }\n\n // A wait node must not have a minimum duration that exceeds the maximum duration.\n if (node.duration[0] > node.duration[1]) {\n throw new Error(\"a wait node must not have a minimum duration that exceeds the maximum duration\");\n }\n } else if (nodeArguments.length > 2) {\n // An incorrect number of duration arguments were defined.\n throw new Error(\"invalid number of wait node duration arguments defined\");\n }\n }\n\n // Return the wait node definition.\n return { ...node, ...parseAttributeTokens(tokens, stringLiteralPlaceholders) };\n}\n\n/**\n * Creates a branch node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The branch node JSON definition.\n */\nfunction createBranchNode(\n tokens: string[],\n stringLiteralPlaceholders: StringLiteralPlaceholders\n): BranchNodeDefinition {\n // Parse any node arguments, we should have one which will be an identifier argument for the root ref.\n const nodeArguments = parseArgumentTokens(tokens, stringLiteralPlaceholders);\n\n // We should have only a single identifer argument for a branch node, which is the root ref.\n if (nodeArguments.length !== 1 || nodeArguments[0].type !== \"identifier\") {\n throw new Error(\"expected single branch name argument\");\n }\n\n // Return the branch node definition.\n return { type: \"branch\", ref: nodeArguments[0].value };\n}\n\n/**\n * Validate a fully-populated node definition that was popped off of the tree stack.\n * @param definition The popped node to validate.\n */\nfunction validatePoppedNode(definition: AnyNodeDefinition): void {\n // Decorators MUST have a child defined.\n if (isDecoratorNode(definition) && isNullOrUndefined(definition.child)) {\n throw new Error(`a ${definition.type} node must have a single child node defined`);\n }\n\n // Composites MUST have at least one child defined.\n if (isCompositeNode(definition) && !definition.children?.length) {\n throw new Error(`a ${definition.type} node must have at least a single child node defined`);\n }\n\n // We need to make sure that lotto nodes that have weights defined have a number of weights matching the number of child nodes.\n if (definition.type === \"lotto\") {\n // Check whether a 'weights' property has been defined, if it has we expect it to be an array of weights.\n if (typeof definition.weights !== \"undefined\") {\n // Check that the weights property is an array of positive integers with an element for each child node element.\n if (definition.weights.length !== definition.children.length) {\n throw new Error(\n \"expected a number of weight arguments matching the number of child nodes for lotto node\"\n );\n }\n }\n }\n}\n", "import { RootNodeDefinition } from \"./BehaviourTreeDefinition\";\nimport { flattenDefinition, isBranchNode, isInteger } from \"./BehaviourTreeDefinitionUtilities\";\nimport { convertMDSLToJSON } from \"./mdsl/MDSLDefinitionParser\";\n\n/**\n * An object representing the result of validating a tree definition.\n */\nexport type DefinitionValidationResult = {\n /**\n * A flag defining whether validation succeeded.\n */\n succeeded: boolean;\n /**\n * A string containing the error message if validation did not succeed.\n */\n errorMessage?: string;\n /**\n * The definition as json if the validation was successful, or undefined if validation did not succeed.\n */\n json?: RootNodeDefinition[];\n};\n\n/**\n * Validates the specified behaviour tree definition in the form of JSON or MDSL, not taking any globally registered subtrees into consideration.\n * @param definition The behaviour tree definition in the form of JSON or MDSL.\n * @returns An object representing the result of validating the given tree definition.\n */\nexport function validateDefinition(definition: any): DefinitionValidationResult {\n // The definition must be defined.\n if (definition === null || typeof definition === \"undefined\") {\n return createValidationFailureResult(\"definition is null or undefined\");\n }\n\n // We are expecting a definition in one of three different forms:\n // - A string which we will assume is MDSL and we will parse this to JSON before validation.\n // - An array which we will assume is an array of root node definitions with at least one being the primary root node (no 'id' property)\n // - An object which we will assume is the primary root node and should not have an 'id' property.\n if (typeof definition === \"string\") {\n // The definition is a string which we can assume is MDSL, so attempt to validate it.\n return validateMDSLDefinition(definition);\n } else if (typeof definition === \"object\") {\n // The definition will either be an array (of root node definitions) or an object (the single primary root node definition).\n return validateJSONDefinition(definition);\n } else {\n return createValidationFailureResult(`unexpected definition type of '${typeof definition}'`);\n }\n}\n\n/**\n * Validates the specified behaviour tree definition in the form of MDSL.\n * @param definition The behaviour tree definition in the form of MDSL.\n * @returns An object representing the result of validating the given tree definition.\n */\nfunction validateMDSLDefinition(definition: string): DefinitionValidationResult {\n let rootNodeDefinitions;\n\n // The first thing the we need to do is to attempt to convert our MDSL into JSON.\n try {\n // The definition is a string which we can assume is MDSL, so attempt to parse it to a JSON definition in the form of an array of root node definitions.\n rootNodeDefinitions = convertMDSLToJSON(definition);\n } catch (exception) {\n // We failed to parse the JSON from the MDSL, this is likely to be the result of it not being a valid MDSL string.\n return createValidationFailureResult((exception as Error).message);\n }\n\n // Unpack all of the root node definitions into arrays of main ('id' defined) and sub ('id' not defined) root node definitions.\n const mainRootNodeDefinitions = rootNodeDefinitions.filter(({ id }) => typeof id === \"undefined\");\n const subRootNodeDefinitions = rootNodeDefinitions.filter(({ id }) => typeof id === \"string\" && id.length > 0);\n\n // We should ALWAYS have exactly one root node definition without an 'id' property defined, which is out main root node definition.\n if (mainRootNodeDefinitions.length !== 1) {\n return createValidationFailureResult(\n \"expected single unnamed root node at base of definition to act as main root\"\n );\n }\n\n // We should never have duplicate 'id' properties across our sub root node definitions.\n const subRootNodeIdenitifers: string[] = [];\n for (const { id } of subRootNodeDefinitions) {\n // Have we already come across this 'id' property value?\n if (subRootNodeIdenitifers.includes(id!)) {\n return createValidationFailureResult(`multiple root nodes found with duplicate name '${id}'`);\n }\n\n subRootNodeIdenitifers.push(id!);\n }\n\n try {\n // Validate our branch -> subtree links and check for any circular dependencies, we don't care about checking for broken subtree links here.\n validateBranchSubtreeLinks(rootNodeDefinitions, false);\n } catch (exception) {\n return createValidationFailureResult((exception as Error).message);\n }\n\n // Our definition was valid!\n return {\n succeeded: true,\n json: rootNodeDefinitions\n };\n}\n\n/**\n * Validates the specified behaviour tree definition in the form of JSON.\n * @param definition The behaviour tree definition in the form of JSON.\n * @returns An object representing the result of validating the given tree definition.\n */\nexport function validateJSONDefinition(\n definition: RootNodeDefinition | RootNodeDefinition[]\n): DefinitionValidationResult {\n // The definition will either be an array (of root node definitions) or an object (the single primary root node definition).\n const rootNodeDefinitions = Array.isArray(definition) ? definition : [definition];\n\n // Iterate over our array of root nodes and call validateNode for each, passing an initial depth of 0, wrapped in a try catch to handle validation failures.\n try {\n rootNodeDefinitions.forEach((rootNodeDefinition) => validateNode(rootNodeDefinition, 0));\n } catch (error) {\n // Handle cases where we have caught a thrown Error and return a failure result with the error message.\n if (error instanceof Error) {\n return createValidationFailureResult(error.message);\n }\n\n // No idea what happened here!\n return createValidationFailureResult(`unexpected error: ${error}`);\n }\n\n // Unpack all of the root node definitions into arrays of main ('id' defined) and sub ('id' not defined) root node definitions.\n const mainRootNodeDefinitions = rootNodeDefinitions.filter(({ id }) => typeof id === \"undefined\");\n const subRootNodeDefinitions = rootNodeDefinitions.filter(({ id }) => typeof id === \"string\" && id.length > 0);\n\n // We should ALWAYS have exactly one root node definition without an 'id' property defined, which is out main root node definition.\n if (mainRootNodeDefinitions.length !== 1) {\n return createValidationFailureResult(\n \"expected single root node without 'id' property defined to act as main root\"\n );\n }\n\n // We should never have duplicate 'id' properties across our sub root node definitions.\n const subRootNodeIdenitifers: string[] = [];\n for (const { id } of subRootNodeDefinitions) {\n // Have we already come across this 'id' property value?\n if (subRootNodeIdenitifers.includes(id!)) {\n return createValidationFailureResult(\n `multiple root nodes found with duplicate 'id' property value of '${id}'`\n );\n }\n\n subRootNodeIdenitifers.push(id!);\n }\n\n try {\n // Validate our branch -> subtree links and check for any circular dependencies, we don't care about checking for broken subtree links here.\n validateBranchSubtreeLinks(rootNodeDefinitions, false);\n } catch (exception) {\n return createValidationFailureResult((exception as Error).message);\n }\n\n // Our definition was valid!\n return {\n succeeded: true,\n json: rootNodeDefinitions\n };\n}\n\n/**\n * Validates the branch -> subtree links across all provided root node definitions.\n * This will not consider branch nodes that reference any globally registered subtrees unless includesGlobalSubtrees\n * is set to true, in which case we will also verify that there are no broken branch -> subtree links.\n * @param rootNodeDefinitions The array of root node definitions.\n * @param includesGlobalSubtrees A flag defining whether the array includes all global subtree root node definitions.\n */\nexport function validateBranchSubtreeLinks(rootNodeDefinitions: RootNodeDefinition[], includesGlobalSubtrees: boolean) {\n // Create a mapping of root node identifiers to other root nodes that they reference via branch nodes.\n // Below is an example of a mapping that includes a circular dependency (root => a => b => c => a)\n // [{ refs: [\"a\", \"b\"] }, { id: \"a\", refs: [\"b\"] }, { id: \"b\", refs: [\"c\"] }, { id: \"c\", refs: [\"a\"] }]\n const rootNodeMappings: { id: string | undefined; refs: string[] }[] = rootNodeDefinitions.map(\n (rootNodeDefinition) => ({\n id: rootNodeDefinition.id,\n refs: flattenDefinition(rootNodeDefinition)\n .filter(isBranchNode)\n .map(({ ref }) => ref)\n })\n );\n\n // A recursive function to walk through the mappings, keeping track of which root nodes we have visited in the form of a path of root node identifiers.\n const followRefs = (mapping: { id: string | undefined; refs: string[] }, path: (string | undefined)[] = []) => {\n // Have we found a circular dependency?\n if (path.includes(mapping.id)) {\n // We found a circular dependency! Get the bad path of root node identifiers.\n const badPath = [...path, mapping.id];\n\n // Create the formatted path value. [undefined, \"a\", \"b\", \"c\", \"a\"] would be formatted as \"a -> b -> c -> a\".\n const badPathFormatted = badPath.filter((element) => !!element).join(\" => \");\n\n // No need to continue, we found a circular dependency.\n throw new Error(`circular dependency found in branch node references: ${badPathFormatted}`);\n }\n\n for (const ref of mapping.refs) {\n // Find the mapping for the root node with an identifer matching the current ref.\n const subMapping = rootNodeMappings.find(({ id }) => id === ref);\n\n // We may not have a mapping for this ref, which is normal when we aren't considering all globally registered subtrees.\n if (subMapping) {\n followRefs(subMapping, [...path, mapping.id]);\n } else if (includesGlobalSubtrees) {\n // We found a reference to a root node that doesn't exist, which is a problem seeing as the root node definitons includes all globally registered subtrees.\n throw new Error(\n mapping.id\n ? `subtree '${mapping.id}' has branch node that references root node '${ref}' which has not been defined`\n : `primary tree has branch node that references root node '${ref}' which has not been defined`\n );\n }\n }\n };\n\n // Start looking for circular dependencies and broken references from the primary root node definition.\n followRefs(rootNodeMappings.find((mapping) => typeof mapping.id === \"undefined\")!);\n}\n\n/**\n * Validate an object that we expect to be a node definition.\n * @param definition An object that we expect to be a node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateNode(definition: any, depth: number): void {\n // Every node must be valid object and have a non-empty 'type' string property.\n if (typeof definition !== \"object\" || typeof definition.type !== \"string\" || definition.type.length === 0) {\n throw new Error(\n `node definition is not an object or 'type' property is not a non-empty string at depth '${depth}'`\n );\n }\n\n // How we validate this node definition will depend on its type.\n switch (definition.type) {\n case \"action\":\n validateActionNode(definition, depth);\n break;\n\n case \"condition\":\n validateConditionNode(definition, depth);\n break;\n\n case \"wait\":\n validateWaitNode(definition, depth);\n break;\n\n case \"branch\":\n validateBranchNode(definition, depth);\n break;\n\n case \"root\":\n validateRootNode(definition, depth);\n break;\n\n case \"succeed\":\n validateSucceedNode(definition, depth);\n break;\n\n case \"fail\":\n validateFailNode(definition, depth);\n break;\n\n case \"flip\":\n validateFlipNode(definition, depth);\n break;\n\n case \"repeat\":\n validateRepeatNode(definition, depth);\n break;\n\n case \"retry\":\n validateRetryNode(definition, depth);\n break;\n\n case \"sequence\":\n validateSequenceNode(definition, depth);\n break;\n\n case \"selector\":\n validateSelectorNode(definition, depth);\n break;\n\n case \"parallel\":\n validateParallelNode(definition, depth);\n break;\n\n case \"lotto\":\n validateLottoNode(definition, depth);\n break;\n\n default:\n throw new Error(`unexpected node type of '${definition.type}' at depth '${depth}'`);\n }\n}\n\n/**\n * Validate any attributes for a given node definition.\n * @param definition The node definition.\n * @param depth The depth of the node in the behaviour tree definition.\n */\nfunction validateNodeAttributes(definition: any, depth: number): void {\n // Validate each of the attribute types for this node.\n [\"while\", \"until\", \"entry\", \"exit\", \"step\"].forEach((attributeName) => {\n // Attempt to grab the definition for the current attribute from the node definition.\n const attributeDefinition = definition[attributeName];\n\n // All node attributes are optional, so there is nothing to do if the current attribute is not defined.\n if (typeof attributeDefinition === \"undefined\") {\n return;\n }\n\n // The attribute definition must be an object.\n if (typeof attributeDefinition !== \"object\") {\n throw new Error(\n `expected attribute '${attributeName}' to be an object for '${definition.type}' node at depth '${depth}'`\n );\n }\n\n // The 'call' property must be defined for any attribute definition.\n if (typeof attributeDefinition.call !== \"string\" || attributeDefinition.call.length === 0) {\n throw new Error(\n `expected 'call' property for attribute '${attributeName}' to be a non-empty string for '${definition.type}' node at depth '${depth}'`\n );\n }\n\n // If any node attribute arguments have been defined then they must have been defined in an array.\n if (typeof attributeDefinition.args !== \"undefined\" && !Array.isArray(attributeDefinition.args)) {\n throw new Error(\n `expected 'args' property for attribute '${attributeName}' to be an array for '${definition.type}' node at depth '${depth}'`\n );\n }\n });\n}\n\n/**\n * Validate an object that we expect to be a root node definition.\n * @param definition An object that we expect to be a root node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateRootNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"root\") {\n throw new Error(\"expected node type of 'root' for root node\");\n }\n\n // A root node cannot be the child of another node.\n if (depth > 0) {\n throw new Error(\"a root node cannot be the child of another node\");\n }\n\n // Check that, if the root node 'id' property is defined, it is a non-empty string.\n if (typeof definition.id !== \"undefined\" && (typeof definition.id !== \"string\" || definition.id.length === 0)) {\n throw new Error(\"expected non-empty string for 'id' property if defined for root node\");\n }\n\n // A root node is a decorator node, so must have a child node defined.\n if (typeof definition.child === \"undefined\") {\n throw new Error(\"expected property 'child' to be defined for root node\");\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n\n // Validate the child node of this decorator node.\n validateNode(definition.child, depth + 1);\n}\n\n/**\n * Validate an object that we expect to be a succeed node definition.\n * @param definition An object that we expect to be a succeed node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateSucceedNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"succeed\") {\n throw new Error(`expected node type of 'succeed' for succeed node at depth '${depth}'`);\n }\n\n // A succeed node is a decorator node, so must have a child node defined.\n if (typeof definition.child === \"undefined\") {\n throw new Error(`expected property 'child' to be defined for succeed node at depth '${depth}'`);\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n\n // Validate the child node of this decorator node.\n validateNode(definition.child, depth + 1);\n}\n\n/**\n * Validate an object that we expect to be a fail node definition.\n * @param definition An object that we expect to be a fail node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateFailNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"fail\") {\n throw new Error(`expected node type of 'fail' for fail node at depth '${depth}'`);\n }\n\n // A fail node is a decorator node, so must have a child node defined.\n if (typeof definition.child === \"undefined\") {\n throw new Error(`expected property 'child' to be defined for fail node at depth '${depth}'`);\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n\n // Validate the child node of this decorator node.\n validateNode(definition.child, depth + 1);\n}\n\n/**\n * Validate an object that we expect to be a flip node definition.\n * @param definition An object that we expect to be a flip node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateFlipNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"flip\") {\n throw new Error(`expected node type of 'flip' for flip node at depth '${depth}'`);\n }\n\n // A flip node is a decorator node, so must have a child node defined.\n if (typeof definition.child === \"undefined\") {\n throw new Error(`expected property 'child' to be defined for flip node at depth '${depth}'`);\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n\n // Validate the child node of this decorator node.\n validateNode(definition.child, depth + 1);\n}\n\n/**\n * Validate an object that we expect to be a repeat node definition.\n * @param definition An object that we expect to be a repeat node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateRepeatNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"repeat\") {\n throw new Error(`expected node type of 'repeat' for repeat node at depth '${depth}'`);\n }\n\n // A repeat node is a decorator node, so must have a child node defined.\n if (typeof definition.child === \"undefined\") {\n throw new Error(`expected property 'child' to be defined for repeat node at depth '${depth}'`);\n }\n\n // Check whether an 'iterations' property has been defined, it may not have been if this node is to repeat indefinitely.\n if (typeof definition.iterations !== \"undefined\") {\n if (Array.isArray(definition.iterations)) {\n // Check whether any elements of the array are not integer values.\n const containsNonInteger = !!definition.iterations.filter((value: unknown) => !isInteger(value)).length;\n\n // If the 'iterations' property is an array then it MUST contain two integer values.\n if (definition.iterations.length !== 2 || containsNonInteger) {\n throw new Error(\n `expected array containing two integer values for 'iterations' property if defined for repeat node at depth '${depth}'`\n );\n }\n\n // A repeat node must have a positive min and max iterations count if they are defined.\n if (definition.iterations[0] < 0 || definition.iterations[1] < 0) {\n throw new Error(\n `expected positive minimum and maximum iterations count for 'iterations' property if defined for repeat node at depth '${depth}'`\n );\n }\n\n // A repeat node must not have a minimum iterations count that exceeds the maximum iterations count.\n if (definition.iterations[0] > definition.iterations[1]) {\n throw new Error(\n `expected minimum iterations count that does not exceed the maximum iterations count for 'iterations' property if defined for repeat node at depth '${depth}'`\n );\n }\n } else if (isInteger(definition.iterations)) {\n // A repeat node must have a positive number of iterations if defined.\n if (definition.iterations < 0) {\n throw new Error(\n `expected positive iterations count for 'iterations' property if defined for repeat node at depth '${depth}'`\n );\n }\n } else {\n throw new Error(\n `expected integer value or array containing two integer values for 'iterations' property if defined for repeat node at depth '${depth}'`\n );\n }\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n\n // Validate the child node of this decorator node.\n validateNode(definition.child, depth + 1);\n}\n\n/**\n * Validate an object that we expect to be a retry node definition.\n * @param definition An object that we expect to be a retry node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateRetryNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"retry\") {\n throw new Error(`expected node type of 'retry' for retry node at depth '${depth}'`);\n }\n\n // A retry node is a decorator node, so must have a child node defined.\n if (typeof definition.child === \"undefined\") {\n throw new Error(`expected property 'child' to be defined for retry node at depth '${depth}'`);\n }\n\n // Check whether an 'attempts' property has been defined, it may not have been if this node is to retry indefinitely.\n if (typeof definition.attempts !== \"undefined\") {\n if (Array.isArray(definition.attempts)) {\n // Check whether any elements of the array are not integer values.\n const containsNonInteger = !!definition.attempts.filter((value: unknown) => !isInteger(value)).length;\n\n // If the 'attempts' property is an array then it MUST contain two integer values.\n if (definition.attempts.length !== 2 || containsNonInteger) {\n throw new Error(\n `expected array containing two integer values for 'attempts' property if defined for retry node at depth '${depth}'`\n );\n }\n\n // A retry node must have a positive min and max attempts count if they are defined.\n if (definition.attempts[0] < 0 || definition.attempts[1] < 0) {\n throw new Error(\n `expected positive minimum and maximum attempts count for 'attempts' property if defined for retry node at depth '${depth}'`\n );\n }\n\n // A retry node must not have a minimum attempts count that exceeds the maximum attempts count.\n if (definition.attempts[0] > definition.attempts[1]) {\n throw new Error(\n `expected minimum attempts count that does not exceed the maximum attempts count for 'attempts' property if defined for retry node at depth '${depth}'`\n );\n }\n } else if (isInteger(definition.attempts)) {\n // A retry node must have a positive number of attempts if defined.\n if (definition.attempts < 0) {\n throw new Error(\n `expected positive attempts count for 'attempts' property if defined for retry node at depth '${depth}'`\n );\n }\n } else {\n throw new Error(\n `expected integer value or array containing two integer values for 'attempts' property if defined for retry node at depth '${depth}'`\n );\n }\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n\n // Validate the child node of this decorator node.\n validateNode(definition.child, depth + 1);\n}\n\n/**\n * Validate an object that we expect to be a branch node definition.\n * @param definition An object that we expect to be a branch node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateBranchNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"branch\") {\n throw new Error(`expected node type of 'branch' for branch node at depth '${depth}'`);\n }\n\n // Check that the branch node 'ref' property is defined and is a non-empty string.\n if (typeof definition.ref !== \"string\" || definition.ref.length === 0) {\n throw new Error(`expected non-empty string for 'ref' property for branch node at depth '${depth}'`);\n }\n\n // It is invalid to define guard attributes for a branch node as they should be defined on the referenced root node.\n [\"while\", \"until\"].forEach((attributeName) => {\n if (typeof definition[attributeName] !== \"undefined\") {\n throw new Error(\n `guards should not be defined for branch nodes but guard '${attributeName}' was defined for branch node at depth '${depth}'`\n );\n }\n });\n\n // It is invalid to define callback attributes for a branch node as they should be defined on the referenced root node.\n [\"entry\", \"exit\", \"step\"].forEach((attributeName) => {\n if (typeof definition[attributeName] !== \"undefined\") {\n throw new Error(\n `callbacks should not be defined for branch nodes but callback '${attributeName}' was defined for branch node at depth '${depth}'`\n );\n }\n });\n}\n\n/**\n * Validate an object that we expect to be a action node definition.\n * @param definition An object that we expect to be a action node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateActionNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"action\") {\n throw new Error(`expected node type of 'action' for action node at depth '${depth}'`);\n }\n\n // The 'call' property must be defined for a action node definition.\n if (typeof definition.call !== \"string\" || definition.call.length === 0) {\n throw new Error(`expected non-empty string for 'call' property of action node at depth '${depth}'`);\n }\n\n // If any action function arguments have been defined then they must have been defined in an array.\n if (typeof definition.args !== \"undefined\" && !Array.isArray(definition.args)) {\n throw new Error(`expected array for 'args' property if defined for action node at depth '${depth}'`);\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n}\n\n/**\n * Validate an object that we expect to be a condition node definition.\n * @param definition An object that we expect to be a condition node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateConditionNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"condition\") {\n throw new Error(`expected node type of 'condition' for condition node at depth '${depth}'`);\n }\n\n // The 'call' property must be defined for a condition node definition.\n if (typeof definition.call !== \"string\" || definition.call.length === 0) {\n throw new Error(`expected non-empty string for 'call' property of condition node at depth '${depth}'`);\n }\n\n // If any condition function arguments have been defined then they must have been defined in an array.\n if (typeof definition.args !== \"undefined\" && !Array.isArray(definition.args)) {\n throw new Error(`expected array for 'args' property if defined for condition node at depth '${depth}'`);\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n}\n\n/**\n * Validate an object that we expect to be a wait node definition.\n * @param definition An object that we expect to be a wait node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateWaitNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"wait\") {\n throw new Error(`expected node type of 'wait' for wait node at depth '${depth}'`);\n }\n\n // Check whether a 'duration' property has been defined, it may not have been if this node is to wait indefinitely.\n if (typeof definition.duration !== \"undefined\") {\n if (Array.isArray(definition.duration)) {\n // Check whether any elements of the array are not integer values.\n const containsNonInteger = !!definition.duration.filter((value: unknown) => !isInteger(value)).length;\n\n // If the 'duration' property is an array then it MUST contain two integer values.\n if (definition.duration.length !== 2 || containsNonInteger) {\n throw new Error(\n `expected array containing two integer values for 'duration' property if defined for wait node at depth '${depth}'`\n );\n }\n\n // A wait node must have a positive min and max duration value if they are defined.\n if (definition.duration[0] < 0 || definition.duration[1] < 0) {\n throw new Error(\n `expected positive minimum and maximum duration for 'duration' property if defined for wait node at depth '${depth}'`\n );\n }\n\n // A wait node must not have a minimum duration value that exceeds the maximum duration value.\n if (definition.duration[0] > definition.duration[1]) {\n throw new Error(\n `expected minimum duration value that does not exceed the maximum duration value for 'duration' property if defined for wait node at depth '${depth}'`\n );\n }\n } else if (isInteger(definition.duration)) {\n // A wait node must have a positive duration value if defined.\n if (definition.duration < 0) {\n throw new Error(\n `expected positive duration value for 'duration' property if defined for wait node at depth '${depth}'`\n );\n }\n } else {\n throw new Error(\n `expected integer value or array containing two integer values for 'duration' property if defined for wait node at depth '${depth}'`\n );\n }\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n}\n\n/**\n * Validate an object that we expect to be a sequence node definition.\n * @param definition An object that we expect to be a sequence node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateSequenceNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"sequence\") {\n throw new Error(`expected node type of 'sequence' for sequence node at depth '${depth}'`);\n }\n\n // A sequence node is a composite node, so must have a children nodes array defined.\n if (!Array.isArray(definition.children) || definition.children.length === 0) {\n throw new Error(`expected non-empty 'children' array to be defined for sequence node at depth '${depth}'`);\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n\n // Validate the child nodes of this composite node.\n definition.children.forEach((child: any) => validateNode(child, depth + 1));\n}\n\n/**\n * Validate an object that we expect to be a selector node definition.\n * @param definition An object that we expect to be a selector node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateSelectorNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"selector\") {\n throw new Error(`expected node type of 'selector' for selector node at depth '${depth}'`);\n }\n\n // A selector node is a composite node, so must have a children nodes array defined.\n if (!Array.isArray(definition.children) || definition.children.length === 0) {\n throw new Error(`expected non-empty 'children' array to be defined for selector node at depth '${depth}'`);\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n\n // Validate the child nodes of this composite node.\n definition.children.forEach((child: any) => validateNode(child, depth + 1));\n}\n\n/**\n * Validate an object that we expect to be a parallel node definition.\n * @param definition An object that we expect to be a parallel node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateParallelNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"parallel\") {\n throw new Error(`expected node type of 'parallel' for parallel node at depth '${depth}'`);\n }\n\n // A parallel node is a composite node, so must have a children nodes array defined.\n if (!Array.isArray(definition.children) || definition.children.length === 0) {\n throw new Error(`expected non-empty 'children' array to be defined for parallel node at depth '${depth}'`);\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n\n // Validate the child nodes of this composite node.\n definition.children.forEach((child: any) => validateNode(child, depth + 1));\n}\n\n/**\n * Validate an object that we expect to be a lotto node definition.\n * @param definition An object that we expect to be a lotto node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateLottoNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"lotto\") {\n throw new Error(`expected node type of 'lotto' for lotto node at depth '${depth}'`);\n }\n\n // A lotto node is a composite node, so must have a children nodes array defined.\n if (!Array.isArray(definition.children) || definition.children.length === 0) {\n throw new Error(`expected non-empty 'children' array to be defined for lotto node at depth '${depth}'`);\n }\n\n // Check whether a 'weights' property has been defined, if it has we expect it to be an array of weights.\n if (typeof definition.weights !== \"undefined\") {\n // Check that the weights property is an array of positive integers with an element for each child node element.\n if (\n !Array.isArray(definition.weights) ||\n definition.weights.length !== definition.children.length ||\n definition.weights.filter((value: unknown) => !isInteger(value)).length ||\n definition.weights.filter((value: number) => value < 0).length\n ) {\n throw new Error(\n `expected an array of positive integer weight values with a length matching the number of child nodes for 'weights' property if defined for lotto node at depth '${depth}'`\n );\n }\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n\n // Validate the child nodes of this composite node.\n definition.children.forEach((child: any) => validateNode(child, depth + 1));\n}\n\n/**\n * A helper function to create a failure validation result with the given error message.\n * @param errorMessage The validation failure error message.\n * @returns A failure validation result with the given error message.\n */\nfunction createValidationFailureResult(errorMessage: string): DefinitionValidationResult {\n return { succeeded: false, errorMessage };\n}\n", "import { ActionResult, Agent, GlobalFunction } from \"./Agent\";\nimport { RootNodeDefinition } from \"./BehaviourTreeDefinition\";\n\nexport type InvokerFunction = (args: any[]) => ActionResult;\n\n/**\n * A singleton used to store and lookup registered functions and subtrees.\n */\nexport default class Lookup {\n /**\n * The object holding any registered functions keyed on function name.\n */\n private static functionTable: { [key: string]: GlobalFunction } = {};\n /**\n * The object holding any registered subtree root node definitions keyed on tree name.\n */\n private static subtreeTable: { [key: string]: RootNodeDefinition } = {};\n\n /**\n * Gets the function with the specified name.\n * @param name The name of the function.\n * @returns The function with the specified name.\n */\n public static getFunc(name: string): GlobalFunction {\n return this.functionTable[name];\n }\n\n /**\n * Sets the function with the specified name for later lookup.\n * @param name The name of the function.\n * @param func The function.\n */\n public static setFunc(name: string, func: GlobalFunction): void {\n this.functionTable[name] = func;\n }\n\n /**\n * Gets the function invoker for the specified agent and function name.\n * If a function with the specified name exists on the agent object then it will\n * be returned, otherwise we will then check the registered functions for a match.\n * @param agent The agent instance that this behaviour tree is modelling behaviour for.\n * @param name The function name.\n * @returns The function invoker for the specified agent and function name.\n */\n static getFuncInvoker(agent: Agent, name: string): InvokerFunction | null {\n // Check whether the agent contains the specified function.\n const foundOnAgent = agent[name];\n if (foundOnAgent && typeof foundOnAgent === \"function\") {\n return (args: any[]): boolean | ActionResult => foundOnAgent.apply(agent, args);\n }\n\n // The agent does not contain the specified function but it may have been registered at some point.\n if (this.functionTable[name] && typeof this.functionTable[name] === \"function\") {\n return (args: any[]) => this.functionTable[name](agent, ...args.map((arg) => arg.value));\n }\n\n // We have no function to invoke.\n return null;\n }\n\n /**\n * Gets all registered subtree root node definitions.\n */\n static getSubtrees(): { [key: string]: RootNodeDefinition } {\n return this.subtreeTable;\n }\n\n /**\n * Sets the subtree with the specified name for later lookup.\n * @param name The name of the subtree.\n * @param subtree The subtree.\n */\n static setSubtree(name: string, subtree: RootNodeDefinition) {\n this.subtreeTable[name] = subtree;\n }\n\n /**\n * Removes the registered function or subtree with the specified name.\n * @param name The name of the registered function or subtree.\n */\n static remove(name: string) {\n delete this.functionTable[name];\n delete this.subtreeTable[name];\n }\n\n /**\n * Remove all registered functions and subtrees.\n */\n static empty() {\n this.functionTable = {};\n this.subtreeTable = {};\n }\n}\n", "import Node from \"../../nodes/Node\";\n\n/**\n * An exception thrown when evaluating node guard path conditions and a conditions fails.\n */\nexport default class GuardUnsatisifedException extends Error {\n /**\n * @param source The node at which a guard condition failed.\n */\n constructor(private source: Node) {\n super(\"A guard path condition has failed\");\n }\n\n /**\n * Gets whether the specified node is the node at which a guard condition failed.\n * @param node The node to check against the source node.\n * @returns Whether the specified node is the node at which a guard condition failed.\n */\n isSourceNode = (node: Node) => node === this.source;\n}\n", "import { Agent } from \"../../Agent\";\nimport Guard from \"./Guard\";\nimport Node from \"../../nodes/Node\";\nimport GuardUnsatisifedException from \"./GuardUnsatisifedException\";\n\nexport type GuardPathPart = {\n node: Node;\n guards: Guard[];\n};\n\n/**\n * Represents a path of node guards along a root-to-leaf tree path.\n */\nexport default class GuardPath {\n /**\n * @param nodes An array of objects defining a node instance -> guard link, ordered by node depth.\n */\n constructor(private nodes: GuardPathPart[]) {}\n\n /**\n * Evaluate guard conditions for all guards in the tree path, moving outwards from the root.\n * @param agent The agent, required for guard evaluation.\n * @returns An evaluation results object.\n */\n evaluate = (agent: Agent) => {\n // We need to evaluate guard conditions for nodes up the tree, moving outwards from the root.\n for (const details of this.nodes) {\n // There can be multiple guards per node.\n for (const guard of details.guards) {\n // Check whether the guard condition passes, and throw an exception if not.\n if (!guard.isSatisfied(agent)) {\n throw new GuardUnsatisifedException(details.node);\n }\n }\n }\n };\n}\n", "import { BehaviourTreeOptions } from \"../BehaviourTreeOptions\";\nimport State, { AnyState } from \"../State\";\nimport { Agent } from \"../Agent\";\nimport Leaf from \"./leaf/Leaf\";\nimport Attribute from \"../attributes/Attribute\";\nimport Entry from \"../attributes/callbacks/Entry\";\nimport Exit from \"../attributes/callbacks/Exit\";\nimport Step from \"../attributes/callbacks/Step\";\nimport Guard from \"../attributes/guards/Guard\";\nimport GuardPath from \"../attributes/guards/GuardPath\";\nimport GuardUnsatisifedException from \"../attributes/guards/GuardUnsatisifedException\";\n\n/**\n * A base node.\n */\nexport default abstract class Node {\n /**\n * The node uid.\n */\n private readonly uid: string = createNodeUid();\n /**\n * The node state.\n */\n private state: AnyState = State.READY;\n /**\n * The guard path to evaluate as part of a node update.\n */\n private guardPath: GuardPath | undefined;\n\n /**\n * @param type The node type.\n * @param attributes The node attributes.\n * @param args The node argument definitions.\n */\n constructor(private type: string, private attributes: Attribute[], private args: any[]) {}\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected abstract onUpdate(agent: Agent, options: BehaviourTreeOptions): void;\n\n /**\n * Gets the name of the node.\n */\n public abstract getName(): string;\n\n /**\n * Gets whether this node is a leaf node.\n */\n public abstract isLeafNode: () => this is Leaf;\n\n /**\n * Gets/Sets the state of the node.\n */\n getState = (): AnyState => this.state;\n setState = (value: AnyState): void => {\n this.state = value;\n };\n\n /**\n * Gets the unique id of the node.\n */\n getUid = () => this.uid;\n\n /**\n * Gets the type of the node.\n */\n getType = () => this.type;\n\n /**\n * Gets the node attributes.\n */\n getAttributes = () => this.attributes;\n\n /**\n * Gets the node arguments.\n */\n getArguments = () => this.args;\n\n /**\n * Gets the node attribute with the specified type, or null if it does not exist.\n */\n getAttribute(type: \"entry\" | \"ENTRY\"): Entry;\n getAttribute(type: \"exit\" | \"EXIT\"): Exit;\n getAttribute(type: \"step\" | \"STEP\"): Step;\n getAttribute(type: string): Attribute {\n return (\n this.getAttributes().filter((decorator) => decorator.type.toUpperCase() === type.toUpperCase())[0] || null\n );\n }\n\n /**\n * Gets the node attributes.\n */\n getGuardAttributes = (): Guard[] => this.getAttributes().filter((decorator) => decorator.isGuard()) as Guard[];\n\n /**\n * Sets the guard path to evaluate as part of a node update.\n */\n setGuardPath = (value: GuardPath) => (this.guardPath = value);\n\n /**\n * Gets whether a guard path is assigned to this node.\n */\n hasGuardPath = () => !!this.guardPath;\n\n /**\n * Gets whether this node is in the specified state.\n * @param value The value to compare to the node state.\n */\n public is(value: AnyState): boolean {\n return this.state === value;\n }\n\n /**\n * Reset the state of the node.\n */\n public reset(): void {\n this.setState(State.READY);\n }\n\n /**\n * Abort the running of this node.\n * @param agent The agent.\n */\n public abort(agent: Agent): void {\n // There is nothing to do if this node is not in the running state.\n if (!this.is(State.RUNNING)) {\n return;\n }\n\n // Reset the state of this node.\n this.reset();\n\n this.getAttribute(\"exit\")?.callAgentFunction(agent, false, true);\n }\n\n /**\n * Update the node.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n * @returns The result of the update.\n */\n public update(agent: Agent, options: BehaviourTreeOptions): void {\n // If this node is already in a 'SUCCEEDED' or 'FAILED' state then there is nothing to do.\n if (this.is(State.SUCCEEDED) || this.is(State.FAILED)) {\n return;\n }\n\n try {\n // Evaluate all of the guard path conditions for the current tree path.\n this.guardPath!.evaluate(agent);\n\n // If this node is in the READY state then call the ENTRY for this node if it exists.\n if (this.is(State.READY)) {\n this.getAttribute(\"entry\")?.callAgentFunction(agent);\n }\n\n this.getAttribute(\"step\")?.callAgentFunction(agent);\n\n // Do the actual update.\n this.onUpdate(agent, options);\n\n // If this node is now in a 'SUCCEEDED' or 'FAILED' state then call the EXIT for this node if it exists.\n if (this.is(State.SUCCEEDED) || this.is(State.FAILED)) {\n this.getAttribute(\"exit\")?.callAgentFunction(agent, this.is(State.SUCCEEDED), false);\n }\n } catch (error) {\n // If the error is a GuardUnsatisfiedException then we need to determine if this node is the source.\n if (error instanceof GuardUnsatisifedException && error.isSourceNode(this)) {\n // Abort the current node.\n this.abort(agent);\n\n // Any node that is the source of an abort will be a failed node.\n this.setState(State.FAILED);\n } else {\n throw error;\n }\n }\n }\n}\n\n/**\n * Create a randomly generated node uid.\n * @returns A randomly generated node uid.\n */\nfunction createNodeUid(): string {\n var S4 = function () {\n return (((1 + Math.random()) * 0x10000) | 0).toString(16).substring(1);\n };\n return S4() + S4() + \"-\" + S4() + \"-\" + S4() + \"-\" + S4() + \"-\" + S4() + S4() + S4();\n}\n", "import Node from \"../Node\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\n\n/**\n * A composite node that wraps child nodes.\n */\nexport default abstract class Composite extends Node {\n /**\n * @param type The node type.\n * @param attributes The node attributes.\n * @param children The child nodes.\n */\n constructor(type: string, attributes: Attribute[], protected children: Node[]) {\n super(type, attributes, []);\n }\n\n /**\n * Gets whether this node is a leaf node.\n */\n isLeafNode = () => false;\n\n /**\n * Gets the children of this node.\n */\n getChildren = () => this.children;\n\n /**\n * Reset the state of the node.\n */\n reset = () => {\n // Reset the state of this node.\n this.setState(State.READY);\n\n // Reset the state of any child nodes.\n this.getChildren().forEach((child) => child.reset());\n };\n\n /**\n * Abort the running of this node.\n * @param agent The agent.\n */\n abort = (agent: Agent) => {\n // There is nothing to do if this node is not in the running state.\n if (!this.is(State.RUNNING)) {\n return;\n }\n\n // Abort any child nodes.\n this.getChildren().forEach((child) => child.abort(agent));\n\n // Reset the state of this node.\n this.reset();\n\n this.getAttribute(\"exit\")?.callAgentFunction(agent, false, true);\n };\n}\n", "import Composite from \"./Composite\";\nimport State from \"../../State\";\nimport Node from \"../Node\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A PARALLEL node.\n * The child nodes are executed concurrently until one fails or all succeed.\n */\nexport default class Parallel extends Composite {\n /**\n * @param attributes The node attributes.\n * @param children The child nodes.\n */\n constructor(attributes: Attribute[], children: Node[]) {\n super(\"parallel\", attributes, children);\n }\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // Keep a count of the number of succeeded child nodes.\n let succeededCount = 0;\n\n let hasChildFailed = false;\n\n // Iterate over all of the children of this node.\n for (const child of this.children) {\n // If the child has never been updated or is running then we will need to update it now.\n if (child.getState() === State.READY || child.getState() === State.RUNNING) {\n // Update the child of this node.\n child.update(agent, options);\n }\n\n // If the current child has a state of 'SUCCEEDED' then we should move on to the next child.\n if (child.getState() === State.SUCCEEDED) {\n // The child node has succeeded, keep track of this to determine if all children have.\n succeededCount++;\n\n // The child node succeeded, but we have not finished checking every child node yet.\n continue;\n }\n\n // If the current child has a state of 'FAILED' then this node is also a 'FAILED' node.\n if (child.getState() === State.FAILED) {\n hasChildFailed = true;\n\n // There is no need to check the rest of the children.\n break;\n }\n\n // The node should be in the 'RUNNING' state.\n if (child.getState() !== State.RUNNING) {\n // The child node was not in an expected state.\n throw new Error(\"child node was not in an expected state.\");\n }\n }\n\n if (hasChildFailed) {\n // This node is a 'FAILED' node.\n this.setState(State.FAILED);\n\n // Abort every running child.\n for (const child of this.children) {\n if (child.getState() === State.RUNNING) {\n child.abort(agent);\n }\n }\n } else {\n // If all children have succeeded then this node has also succeeded, otherwise it is still running.\n this.setState(succeededCount === this.children.length ? State.SUCCEEDED : State.RUNNING);\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => \"PARALLEL\";\n}\n", "import Composite from \"./Composite\";\nimport Node from \"../Node\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A SELECTOR node.\n * The child nodes are executed in sequence until one succeeds or all fail.\n */\nexport default class Selector extends Composite {\n /**\n * @param attributes The node attributes.\n * @param children The child nodes.\n */\n constructor(attributes: Attribute[], protected children: Node[]) {\n super(\"selector\", attributes, children);\n }\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // Iterate over all of the children of this node.\n for (const child of this.children) {\n // If the child has never been updated or is running then we will need to update it now.\n if (child.getState() === State.READY || child.getState() === State.RUNNING) {\n // Update the child of this node.\n child.update(agent, options);\n }\n\n // If the current child has a state of 'SUCCEEDED' then this node is also a 'SUCCEEDED' node.\n if (child.getState() === State.SUCCEEDED) {\n // This node is a 'SUCCEEDED' node.\n this.setState(State.SUCCEEDED);\n\n // There is no need to check the rest of the selector nodes.\n return;\n }\n\n // If the current child has a state of 'FAILED' then we should move on to the next child.\n if (child.getState() === State.FAILED) {\n // Find out if the current child is the last one in the selector.\n // If it is then this sequence node has also failed.\n if (this.children.indexOf(child) === this.children.length - 1) {\n // This node is a 'FAILED' node.\n this.setState(State.FAILED);\n\n // There is no need to check the rest of the selector as we have completed it.\n return;\n } else {\n // The child node failed, try the next one.\n continue;\n }\n }\n\n // The node should be in the 'RUNNING' state.\n if (child.getState() === State.RUNNING) {\n // This node is a 'RUNNING' node.\n this.setState(State.RUNNING);\n\n // There is no need to check the rest of the selector as the current child is still running.\n return;\n }\n\n // The child node was not in an expected state.\n throw new Error(\"child node was not in an expected state.\");\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => \"SELECTOR\";\n}\n", "import Composite from \"./Composite\";\nimport Node from \"../Node\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A SEQUENCE node.\n * The child nodes are executed in sequence until one fails or all succeed.\n */\nexport default class Sequence extends Composite {\n /**\n * @param attributes The node attributes.\n * @param children The child nodes.\n */\n constructor(attributes: Attribute[], protected children: Node[]) {\n super(\"sequence\", attributes, children);\n }\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // Iterate over all of the children of this node.\n for (const child of this.children) {\n // If the child has never been updated or is running then we will need to update it now.\n if (child.getState() === State.READY || child.getState() === State.RUNNING) {\n // Update the child of this node.\n child.update(agent, options);\n }\n\n // If the current child has a state of 'SUCCEEDED' then we should move on to the next child.\n if (child.getState() === State.SUCCEEDED) {\n // Find out if the current child is the last one in the sequence.\n // If it is then this sequence node has also succeeded.\n if (this.children.indexOf(child) === this.children.length - 1) {\n // This node is a 'SUCCEEDED' node.\n this.setState(State.SUCCEEDED);\n\n // There is no need to check the rest of the sequence as we have completed it.\n return;\n } else {\n // The child node succeeded, but we have not finished the sequence yet.\n continue;\n }\n }\n\n // If the current child has a state of 'FAILED' then this node is also a 'FAILED' node.\n if (child.getState() === State.FAILED) {\n // This node is a 'FAILED' node.\n this.setState(State.FAILED);\n\n // There is no need to check the rest of the sequence.\n return;\n }\n\n // The node should be in the 'RUNNING' state.\n if (child.getState() === State.RUNNING) {\n // This node is a 'RUNNING' node.\n this.setState(State.RUNNING);\n\n // There is no need to check the rest of the sequence as the current child is still running.\n return;\n }\n\n // The child node was not in an expected state.\n throw new Error(\"child node was not in an expected state.\");\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => \"SEQUENCE\";\n}\n", "import createLotto from \"lotto-draw\";\n\nimport Node from \"../Node\";\nimport Composite from \"./Composite\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A LOTTO node.\n * A winning child is picked on the initial update of this node, based on ticket weighting.\n * The state of this node will match the state of the winning child.\n */\nexport default class Lotto extends Composite {\n /**\n * @param attributes The node attributes.\n * @param weights The child node weights.\n * @param children The child nodes.\n */\n constructor(attributes: Attribute[], private weights: number[] | undefined, children: Node[]) {\n super(\"lotto\", attributes, children);\n }\n\n /**\n * The child node selected to be the active one.\n */\n private selectedChild: Node | undefined;\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // If this node is in the READY state then we need to pick a winning child node.\n if (this.is(State.READY)) {\n // Create a lotto draw with which to randomly pick a child node to become the active one.\n const lottoDraw = createLotto({\n // Hook up the optional 'random' behaviour tree function option to the one used by 'lotto-draw'.\n random: options.random,\n // Pass in each child node as a participant in the lotto draw with their respective ticket count.\n participants: this.children.map((child, index) => [child, this.weights?.[index] || 1])\n });\n\n // Randomly pick a child based on ticket weighting, this will become the active child for this composite node.\n this.selectedChild = lottoDraw.draw() || undefined;\n }\n\n // If something went wrong and we don't have an active child then we should throw an error.\n if (!this.selectedChild) {\n throw new Error(\"failed to update lotto node as it has no active child\");\n }\n\n // If the selected child has never been updated or is running then we will need to update it now.\n if (this.selectedChild.getState() === State.READY || this.selectedChild.getState() === State.RUNNING) {\n this.selectedChild.update(agent, options);\n }\n\n // The state of the lotto node is the state of its selected child.\n this.setState(this.selectedChild.getState());\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => (this.weights ? `LOTTO [${this.weights.join(\",\")}]` : \"LOTTO\");\n}\n", "import Node from \"../Node\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\n\n/**\n * A decorator node that wraps a single child node.\n */\nexport default abstract class Decorator extends Node {\n /**\n * @param type The node type.\n * @param attributes The node attributes.\n * @param child The child node.\n */\n constructor(type: string, attributes: Attribute[], protected child: Node) {\n super(type, attributes, []);\n }\n\n /**\n * Gets whether this node is a leaf node.\n */\n isLeafNode = () => false;\n\n /**\n * Gets the children of this node.\n */\n getChildren = () => [this.child];\n\n /**\n * Reset the state of the node.\n */\n reset = () => {\n // Reset the state of this node.\n this.setState(State.READY);\n\n // Reset the state of the child node.\n this.child.reset();\n };\n\n /**\n * Abort the running of this node.\n * @param agent The agent.\n */\n abort = (agent: Agent) => {\n // There is nothing to do if this node is not in the running state.\n if (!this.is(State.RUNNING)) {\n return;\n }\n\n // Abort the child node.\n this.child.abort(agent);\n\n // Reset the state of this node.\n this.reset();\n\n this.getAttribute(\"exit\")?.callAgentFunction(agent, false, true);\n };\n}\n", "import Node from \"../Node\";\nimport Decorator from \"./Decorator\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A Fail node.\n * This node wraps a single child and will always move to the 'FAILED' state when the child moves to a 'SUCCEEDED' or 'FAILED' state.\n */\nexport default class Fail extends Decorator {\n /**\n * @param attributes The node attributes.\n * @param child The child node.\n */\n constructor(attributes: Attribute[], child: Node) {\n super(\"fail\", attributes, child);\n }\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // If the child has never been updated or is running then we will need to update it now.\n if (this.child.getState() === State.READY || this.child.getState() === State.RUNNING) {\n this.child.update(agent, options);\n }\n\n // The state of this node will depend in the state of its child.\n switch (this.child.getState()) {\n case State.RUNNING:\n this.setState(State.RUNNING);\n break;\n\n case State.SUCCEEDED:\n case State.FAILED:\n this.setState(State.FAILED);\n break;\n\n default:\n this.setState(State.READY);\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => \"FAIL\";\n}\n", "import Decorator from \"./Decorator\";\nimport State from \"../../State\";\nimport Node from \"../Node\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A Flip node.\n * This node wraps a single child and will flip the state of the child state.\n */\nexport default class Flip extends Decorator {\n /**\n * @param attributes The node attributes.\n * @param child The child node.\n */\n constructor(attributes: Attribute[], child: Node) {\n super(\"flip\", attributes, child);\n }\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // If the child has never been updated or is running then we will need to update it now.\n if (this.child.getState() === State.READY || this.child.getState() === State.RUNNING) {\n this.child.update(agent, options);\n }\n\n // The state of this node will depend in the state of its child.\n switch (this.child.getState()) {\n case State.RUNNING:\n this.setState(State.RUNNING);\n break;\n\n case State.SUCCEEDED:\n this.setState(State.FAILED);\n break;\n\n case State.FAILED:\n this.setState(State.SUCCEEDED);\n break;\n\n default:\n this.setState(State.READY);\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => \"FLIP\";\n}\n", "import Node from \"../Node\";\nimport Decorator from \"./Decorator\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A REPEAT node.\n * The node has a single child which can have:\n * -- A number of iterations for which to repeat the child node.\n * -- An infinite repeat loop if neither an iteration count or a condition function is defined.\n * The REPEAT node will stop and have a 'FAILED' state if its child is ever in a 'FAILED' state after an update.\n * The REPEAT node will attempt to move on to the next iteration if its child is ever in a 'SUCCEEDED' state.\n */\nexport default class Repeat extends Decorator {\n /**\n * @param attributes The node attributes.\n * @param iterations The number of iterations to repeat the child node.\n * @param iterationsMin The minimum possible number of iterations to repeat the child node.\n * @param iterationsMax The maximum possible number of iterations to repeat the child node.\n * @param child The child node.\n */\n constructor(\n attributes: Attribute[],\n private iterations: number | null,\n private iterationsMin: number | null,\n private iterationsMax: number | null,\n child: Node\n ) {\n super(\"repeat\", attributes, child);\n }\n\n /**\n * The number of target iterations to make.\n */\n private targetIterationCount: number | null = null;\n\n /**\n * The current iteration count.\n */\n private currentIterationCount: number = 0;\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // If this node is in the READY state then we need to reset the child and the target iteration count.\n if (this.is(State.READY)) {\n // Reset the child node.\n this.child.reset();\n\n // Reset the current iteration count.\n this.currentIterationCount = 0;\n\n // Set the target iteration count.\n this.setTargetIterationCount(options);\n }\n\n // Do a check to see if we can iterate. If we can then this node will move into the 'RUNNING' state.\n // If we cannot iterate then we have hit our target iteration count, which means that the node has succeeded.\n if (this.canIterate()) {\n // This node is in the running state and can do its initial iteration.\n this.setState(State.RUNNING);\n\n // We may have already completed an iteration, meaning that the child node will be in the SUCCEEDED state.\n // If this is the case then we will have to reset the child node now.\n if (this.child.getState() === State.SUCCEEDED) {\n this.child.reset();\n }\n\n // Update the child of this node.\n this.child.update(agent, options);\n\n // If the child moved into the FAILED state when we updated it then there is nothing left to do and this node has also failed.\n // If it has moved into the SUCCEEDED state then we have completed the current iteration.\n if (this.child.getState() === State.FAILED) {\n // The child has failed, meaning that this node has failed.\n this.setState(State.FAILED);\n\n return;\n } else if (this.child.getState() === State.SUCCEEDED) {\n // We have completed an iteration.\n this.currentIterationCount += 1;\n }\n } else {\n // This node is in the 'SUCCEEDED' state as we cannot iterate any more.\n this.setState(State.SUCCEEDED);\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => {\n if (this.iterations !== null) {\n return `REPEAT ${this.iterations}x`;\n } else if (this.iterationsMin !== null && this.iterationsMax !== null) {\n return `REPEAT ${this.iterationsMin}x-${this.iterationsMax}x`;\n } else {\n return \"REPEAT\";\n }\n };\n\n /**\n * Reset the state of the node.\n */\n reset = () => {\n // Reset the state of this node.\n this.setState(State.READY);\n\n // Reset the current iteration count.\n this.currentIterationCount = 0;\n\n // Reset the child node.\n this.child.reset();\n };\n\n /**\n * Gets whether an iteration can be made.\n * @returns Whether an iteration can be made.\n */\n private canIterate = () => {\n if (this.targetIterationCount !== null) {\n // We can iterate as long as we have not reached our target iteration count.\n return this.currentIterationCount < this.targetIterationCount;\n }\n\n // If neither an iteration count or a condition function were defined then we can iterate indefinitely.\n return true;\n };\n\n /**\n * Sets the target iteration count.\n * @param options The behaviour tree options object.\n */\n private setTargetIterationCount = (options: BehaviourTreeOptions) => {\n // Are we dealing with an explicit iteration count or will we be randomly picking a iteration count between the min and max iteration count.\n if (this.iterations !== null) {\n this.targetIterationCount = this.iterations;\n } else if (this.iterationsMin !== null && this.iterationsMax !== null) {\n // We will be picking a random iteration count between a min and max iteration count, if the optional 'random'\n // behaviour tree function option is defined then we will be using that, otherwise we will fall back to using Math.random.\n const random = typeof options.random === \"function\" ? options.random : Math.random;\n\n // Pick a random iteration count between a min and max iteration count.\n this.targetIterationCount = Math.floor(\n random() * (this.iterationsMax - this.iterationsMin + 1) + this.iterationsMin\n );\n } else {\n this.targetIterationCount = null;\n }\n };\n}\n", "import Node from \"../Node\";\nimport Decorator from \"./Decorator\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A RETRY node.\n * The node has a single child which can have:\n * -- A number of iterations for which to repeat the child node.\n * -- An infinite repeat loop if neither an iteration count or a condition function is defined.\n * The RETRY node will stop and have a 'SUCCEEDED' state if its child is ever in a 'SUCCEEDED' state after an update.\n * The RETRY node will attempt to move on to the next iteration if its child is ever in a 'FAILED' state.\n */\nexport default class Retry extends Decorator {\n /**\n * @param attributes The node attributes.\n * @param attempts The number of attempts to retry the child node.\n * @param attemptsMin The minimum possible number of attempts to retry the child node.\n * @param attemptsMax The maximum possible number of attempts to retry the child node.\n * @param child The child node.\n */\n constructor(\n attributes: Attribute[],\n private attempts: number | null,\n private attemptsMin: number | null,\n private attemptsMax: number | null,\n child: Node\n ) {\n super(\"retry\", attributes, child);\n }\n\n /**\n * The number of target attempts to make.\n */\n private targetAttemptCount: number | null = null;\n\n /**\n * The current attempt count.\n */\n private currentAttemptCount: number = 0;\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // If this node is in the READY state then we need to reset the child and the target attempt count.\n if (this.is(State.READY)) {\n // Reset the child node.\n this.child.reset();\n\n // Reset the current attempt count.\n this.currentAttemptCount = 0;\n\n // Set the target attempt count.\n this.setTargetAttemptCount(options);\n }\n\n // Do a check to see if we can attempt. If we can then this node will move into the 'RUNNING' state.\n // If we cannot attempt then we have hit our target attempt count, which means that the node has succeeded.\n if (this.canAttempt()) {\n // This node is in the running state and can do its initial attempt.\n this.setState(State.RUNNING);\n\n // We may have already completed an attempt, meaning that the child node will be in the FAILED state.\n // If this is the case then we will have to reset the child node now.\n if (this.child.getState() === State.FAILED) {\n this.child.reset();\n }\n\n // Update the child of this node.\n this.child.update(agent, options);\n\n // If the child moved into the SUCCEEDED state when we updated it then there is nothing left to do and this node has also succeeded.\n // If it has moved into the FAILED state then we have completed the current attempt.\n if (this.child.getState() === State.SUCCEEDED) {\n // The child has succeeded, meaning that this node has succeeded.\n this.setState(State.SUCCEEDED);\n\n return;\n } else if (this.child.getState() === State.FAILED) {\n // We have completed an attempt.\n this.currentAttemptCount += 1;\n }\n } else {\n // This node is in the 'FAILED' state as we cannot iterate any more.\n this.setState(State.FAILED);\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => {\n if (this.attempts !== null) {\n return `RETRY ${this.attempts}x`;\n } else if (this.attemptsMin !== null && this.attemptsMax !== null) {\n return `RETRY ${this.attemptsMin}x-${this.attemptsMax}x`;\n } else {\n return \"RETRY\";\n }\n };\n\n /**\n * Reset the state of the node.\n */\n reset = () => {\n // Reset the state of this node.\n this.setState(State.READY);\n\n // Reset the current attempt count.\n this.currentAttemptCount = 0;\n\n // Reset the child node.\n this.child.reset();\n };\n\n /**\n * Gets whether an attempt can be made.\n * @returns Whether an attempt can be made.\n */\n canAttempt = () => {\n if (this.targetAttemptCount !== null) {\n // We can attempt as long as we have not reached our target attempt count.\n return this.currentAttemptCount < this.targetAttemptCount;\n }\n\n // If neither an attempt count or a condition function were defined then we can attempt indefinitely.\n return true;\n };\n\n /**\n * Sets the target attempt count.\n * @param options The behaviour tree options object.\n */\n setTargetAttemptCount = (options: BehaviourTreeOptions) => {\n // Are we dealing with an explicit attempt count or will we be randomly picking an attempt count between the min and max attempt count.\n if (this.attempts !== null) {\n this.targetAttemptCount = this.attempts;\n } else if (this.attemptsMin !== null && this.attemptsMax !== null) {\n // We will be picking a random attempt count between a min and max attempt count, if the optional 'random'\n // behaviour tree function option is defined then we will be using that, otherwise we will fall back to using Math.random.\n const random = typeof options.random === \"function\" ? options.random : Math.random;\n\n // Pick a random attempt count between a min and max attempt count.\n this.targetAttemptCount = Math.floor(\n random() * (this.attemptsMax - this.attemptsMin + 1) + this.attemptsMin\n );\n } else {\n this.targetAttemptCount = null;\n }\n };\n}\n", "import Node from \"../Node\";\nimport Decorator from \"./Decorator\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A Root node.\n * The root node will have a single child.\n */\nexport default class Root extends Decorator {\n /**\n * @param attributes The node attributes.\n * @param child The child node.\n */\n constructor(attributes: Attribute[], child: Node) {\n super(\"root\", attributes, child);\n }\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // If the child has never been updated or is running then we will need to update it now.\n if (this.child.getState() === State.READY || this.child.getState() === State.RUNNING) {\n // Update the child of this node.\n this.child.update(agent, options);\n }\n\n // The state of the root node is the state of its child.\n this.setState(this.child.getState());\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => \"ROOT\";\n}\n", "import Node from \"../Node\";\nimport Decorator from \"./Decorator\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A Succeed node.\n * This node wraps a single child and will always move to the 'SUCCEEDED' state when the child moves to a 'SUCCEEDED' or 'FAILED' state.\n */\nexport default class Succeed extends Decorator {\n /**\n * @param attributes The node attributes.\n * @param child The child node.\n */\n constructor(attributes: Attribute[], child: Node) {\n super(\"succeed\", attributes, child);\n }\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // If the child has never been updated or is running then we will need to update it now.\n if (this.child.getState() === State.READY || this.child.getState() === State.RUNNING) {\n this.child.update(agent, options);\n }\n\n // The state of this node will depend in the state of its child.\n switch (this.child.getState()) {\n case State.RUNNING:\n this.setState(State.RUNNING);\n break;\n\n case State.SUCCEEDED:\n case State.FAILED:\n this.setState(State.SUCCEEDED);\n break;\n\n default:\n this.setState(State.READY);\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => \"SUCCEED\";\n}\n", "import Node from \"../Node\";\n\n/**\n * A leaf node.\n */\nexport default abstract class Leaf extends Node {\n /**\n * Gets whether this node is a leaf node.\n */\n isLeafNode = () => true;\n}\n", "import { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\nimport State, { CompleteState } from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Leaf from \"./Leaf\";\nimport Lookup from \"../../Lookup\";\nimport Attribute from \"../../attributes/Attribute\";\n\n/**\n * An Action leaf node.\n * This represents an immediate or ongoing state of behaviour.\n */\nexport default class Action extends Leaf {\n /**\n * @param attributes The node attributes.\n * @param actionName The action name.\n * @param actionArguments The array of action argument definitions.\n */\n constructor(attributes: Attribute[], private actionName: string, private actionArguments: any[]) {\n super(\"action\", attributes, actionArguments);\n }\n\n /**\n * Whether there is a pending update promise.\n */\n private isUsingUpdatePromise = false;\n\n /**\n * The finished state result of an update promise.\n */\n private updatePromiseStateResult: CompleteState | null = null;\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // If the result of this action depends on an update promise then there is nothing to do until\n // it resolves, unless there has been a value set as a result of the update promise resolving.\n if (this.isUsingUpdatePromise) {\n // Check whether the update promise has resolved with a state value.\n if (this.updatePromiseStateResult) {\n // Set the state of this node to match the state returned by the promise.\n this.setState(this.updatePromiseStateResult);\n }\n\n return;\n }\n\n // Attempt to get the invoker for the action function.\n const actionFuncInvoker = Lookup.getFuncInvoker(agent, this.actionName);\n\n // The action function should be defined.\n if (actionFuncInvoker === null) {\n throw new Error(\n `cannot update action node as the action '${this.actionName}' function is not defined on the agent and has not been registered`\n );\n }\n\n // Call the action function, the result of which may be:\n // - The finished state of this action node.\n // - A promise to return a finished node state.\n // - Undefined if the node should remain in the running state.\n const updateResult = actionFuncInvoker(this.actionArguments) as CompleteState | Promise;\n\n if (updateResult instanceof Promise) {\n updateResult.then(\n (result) => {\n // If 'isUpdatePromisePending' is null then the promise was cleared as it was resolving, probably via an abort of reset.\n if (!this.isUsingUpdatePromise) {\n return;\n }\n\n // Check to make sure the result is a valid finished state.\n if (result !== State.SUCCEEDED && result !== State.FAILED) {\n throw new Error(\n \"action node promise resolved with an invalid value, expected a State.SUCCEEDED or State.FAILED value to be returned\"\n );\n }\n\n // Set pending update promise state result to be processed on next update.\n this.updatePromiseStateResult = result;\n },\n (reason) => {\n // If 'isUpdatePromisePending' is null then the promise was cleared as it was resolving, probably via an abort of reset.\n if (!this.isUsingUpdatePromise) {\n return;\n }\n\n // Just throw whatever was returned as the rejection argument.\n throw new Error(reason);\n }\n );\n\n // This node will be in the 'RUNNING' state until the update promise resolves.\n this.setState(State.RUNNING);\n\n // We are now waiting for the promise returned by the use to resolve before we know what state this node is in.\n this.isUsingUpdatePromise = true;\n } else {\n // Validate the returned value.\n this.validateUpdateResult(updateResult);\n\n // Set the state of this node, this may be undefined, which just means that the node is still in the 'RUNNING' state.\n this.setState(updateResult || State.RUNNING);\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => this.actionName;\n\n /**\n * Reset the state of the node.\n */\n reset = () => {\n // Reset the state of this node.\n this.setState(State.READY);\n\n // There is no longer an update promise that we care about.\n this.isUsingUpdatePromise = false;\n this.updatePromiseStateResult = null;\n };\n\n /**\n * Validate the result of an update function call.\n * @param result The result of an update function call.\n */\n private validateUpdateResult = (result: CompleteState | boolean) => {\n switch (result) {\n case State.SUCCEEDED:\n case State.FAILED:\n case undefined:\n return;\n default:\n throw new Error(\n `action '${this.actionName}' 'onUpdate' returned an invalid response, expected an optional State.SUCCEEDED or State.FAILED value to be returned`\n );\n }\n };\n}\n", "import { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Leaf from \"./Leaf\";\nimport Lookup from \"../../Lookup\";\nimport Attribute from \"../../attributes/Attribute\";\n\n/**\n * A Condition leaf node.\n * This will succeed or fail immediately based on an agent predicate, without moving to the 'RUNNING' state.\n */\nexport default class Condition extends Leaf {\n /**\n * @param attributes The node attributes.\n * @param conditionName The name of the condition function.\n * @param conditionArguments The array of condition argument definitions.\n */\n constructor(attributes: Attribute[], private conditionName: string, private conditionArguments: any[]) {\n super(\"condition\", attributes, conditionArguments);\n }\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // Attempt to get the invoker for the condition function.\n const conditionFuncInvoker = Lookup.getFuncInvoker(agent, this.conditionName);\n\n // The condition function should be defined.\n if (conditionFuncInvoker === null) {\n throw new Error(\n `cannot update condition node as the condition '${this.conditionName}' function is not defined on the agent and has not been registered`\n );\n }\n\n // Call the condition function to determine the state of this node.\n this.setState(!!conditionFuncInvoker(this.conditionArguments) ? State.SUCCEEDED : State.FAILED);\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => this.conditionName;\n}\n", "import Leaf from \"./Leaf\";\nimport State from \"../../State\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { Agent } from \"../../Agent\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A WAIT node.\n * The state of this node will change to SUCCEEDED after a duration of time\n */\nexport default class Wait extends Leaf {\n /**\n * @param attributes The node attributes.\n * @param duration The duration that this node will wait to succeed in milliseconds.\n * @param durationMin The minimum possible duration in milliseconds that this node will wait to succeed.\n * @param durationMax The maximum possible duration in milliseconds that this node will wait to succeed.\n */\n constructor(\n attributes: Attribute[],\n private duration: number | null,\n private durationMin: number | null,\n private durationMax: number | null\n ) {\n super(\"wait\", attributes, []);\n }\n\n /**\n * The time in milliseconds at which this node was first updated.\n */\n private initialUpdateTime: number = 0;\n\n /**\n * The total duration in milliseconds that this node will be waiting for.\n */\n private totalDuration: number | null = null;\n\n /**\n * The duration in milliseconds that this node has been waiting for.\n */\n private waitedDuration: number = 0;\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // If this node is in the READY state then we need to set the initial update time.\n if (this.is(State.READY)) {\n // Set the initial update time.\n this.initialUpdateTime = new Date().getTime();\n\n // Set the initial waited duration.\n this.waitedDuration = 0;\n\n // Are we dealing with an explicit duration or will we be randomly picking a duration between the min and max duration.\n if (this.duration !== null) {\n this.totalDuration = this.duration;\n } else if (this.durationMin !== null && this.durationMax !== null) {\n // We will be picking a random duration between a min and max duration, if the optional 'random' behaviour tree\n // function option is defined then we will be using that, otherwise we will fall back to using Math.random.\n const random = typeof options.random === \"function\" ? options.random : Math.random;\n\n // Pick a random duration between a min and max duration.\n this.totalDuration = Math.floor(\n random() * (this.durationMax - this.durationMin + 1) + this.durationMin\n );\n } else {\n this.totalDuration = null;\n }\n\n // The node is now running until we finish waiting.\n this.setState(State.RUNNING);\n }\n\n // If we have no total duration then this wait node will wait indefinitely until it is aborted.\n if (this.totalDuration === null) {\n return;\n }\n\n // If we have a 'getDeltaTime' function defined as part of our options then we will use it to figure out how long we have waited for.\n if (typeof options.getDeltaTime === \"function\") {\n // Get the delta time.\n const deltaTime = options.getDeltaTime();\n\n // Our delta time must be a valid number and cannot be NaN.\n if (typeof deltaTime !== \"number\" || isNaN(deltaTime)) {\n throw new Error(\"The delta time must be a valid number and not NaN.\");\n }\n\n // Update the amount of time that this node has been waiting for based on the delta time.\n this.waitedDuration += deltaTime * 1000;\n } else {\n // We are not using a delta time, so we will just work out hom much time has passed since the first update.\n this.waitedDuration = new Date().getTime() - this.initialUpdateTime;\n }\n\n // Have we waited long enough?\n if (this.waitedDuration >= this.totalDuration) {\n // We have finished waiting!\n this.setState(State.SUCCEEDED);\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => {\n if (this.duration !== null) {\n return `WAIT ${this.duration}ms`;\n } else if (this.durationMin !== null && this.durationMax !== null) {\n return `WAIT ${this.durationMin}ms-${this.durationMax}ms`;\n } else {\n return \"WAIT\";\n }\n };\n}\n", "import Guard from \"./guards/Guard\";\n\nexport type AttributeDetails = {\n /** The attribute type. */\n type: string;\n\n /** The attribute arguments. */\n args: any[];\n};\n\n/**\n * A base node attribute.\n */\nexport default abstract class Attribute {\n /**\n * @param type The node attribute type.\n * @param args The array of attribute arguments.\n */\n constructor(public type: string, public args: any[]) {}\n\n /**\n * Gets the attribute details.\n */\n abstract getDetails(): TAttributeDetails;\n\n /**\n * Gets whether this attribute is a guard.\n */\n abstract isGuard: () => this is Guard;\n}\n", "import { Agent } from \"../../Agent\";\nimport Attribute, { AttributeDetails } from \"../Attribute\";\n\nexport type GuardAttributeDetails = {\n /** The name of the condition function that determines whether the guard is satisfied. */\n condition: string;\n} & AttributeDetails;\n\n/**\n * A base node guard attribute.\n */\nexport default abstract class Guard extends Attribute {\n /**\n * @param type The node attribute type.\n * @param args The array of decorator argument definitions.\n * @param condition The name of the condition function that determines whether the guard is satisfied.\n */\n constructor(type: string, args: any[], private condition: string) {\n super(type, args);\n }\n\n /**\n * Gets the name of the condition function that determines whether the guard is satisfied.\n */\n getCondition = () => this.condition;\n\n /**\n * Gets whether this attribute is a guard.\n */\n isGuard = () => true;\n\n /**\n * Gets the attribute details.\n */\n getDetails(): GuardAttributeDetails {\n return {\n type: this.type,\n args: this.args,\n condition: this.getCondition()\n };\n }\n\n /**\n * Gets whether the guard is satisfied.\n * @param agent The agent.\n * @returns Whether the guard is satisfied.\n */\n abstract isSatisfied(agent: Agent): boolean;\n}\n", "import Guard from \"./Guard\";\nimport Lookup from \"../../Lookup\";\nimport { Agent } from \"../../Agent\";\n\n/**\n * A WHILE guard which is satisfied as long as the given condition remains true.\n */\nexport default class While extends Guard {\n /**\n * @param condition The name of the condition function that determines whether the guard is satisfied.\n * @param args The array of decorator argument definitions.\n */\n constructor(condition: string, args: any[]) {\n super(\"while\", args, condition);\n }\n\n /**\n * Gets whether the guard is satisfied.\n * @param agent The agent.\n * @returns Whether the guard is satisfied.\n */\n isSatisfied = (agent: Agent) => {\n // Attempt to get the invoker for the condition function.\n const conditionFuncInvoker = Lookup.getFuncInvoker(agent, this.getCondition());\n\n // The condition function should be defined.\n if (conditionFuncInvoker === null) {\n throw new Error(\n `cannot evaluate node guard as the condition '${this.getCondition()}' function is not defined on the agent and has not been registered`\n );\n }\n\n // Call the condition function to determine whether this guard is satisfied.\n return !!conditionFuncInvoker(this.args);\n };\n}\n", "import Guard from \"./Guard\";\nimport Lookup from \"../../Lookup\";\nimport { Agent } from \"../../Agent\";\n\n/**\n * An UNTIL guard which is satisfied as long as the given condition remains false.\n */\nexport default class Until extends Guard {\n /**\n * @param condition The name of the condition function that determines whether the guard is satisfied.\n * @param args The array of decorator argument definitions.\n */\n constructor(condition: string, args: any[]) {\n super(\"until\", args, condition);\n }\n\n /**\n * Gets whether the guard is satisfied.\n * @param agent The agent.\n * @returns Whether the guard is satisfied.\n */\n isSatisfied = (agent: Agent) => {\n // Attempt to get the invoker for the condition function.\n const conditionFuncInvoker = Lookup.getFuncInvoker(agent, this.getCondition());\n\n // The condition function should be defined.\n if (conditionFuncInvoker === null) {\n throw new Error(\n `cannot evaluate node guard as the condition '${this.getCondition()}' function is not defined on the agent and has not been registered`\n );\n }\n\n // Call the condition function to determine whether this guard is satisfied.\n return !!!conditionFuncInvoker(this.args);\n };\n}\n", "import { Agent } from \"../../Agent\";\nimport Attribute, { AttributeDetails } from \"../Attribute\";\n\nexport type CallbackAttributeDetails = {\n /** The name of the agent function that is called. */\n functionName: string;\n} & AttributeDetails;\n\n/**\n * A base node callback attribute.\n */\nexport default abstract class Callback extends Attribute {\n /**\n * @param type The node attribute type.\n * @param args The array of decorator argument definitions.\n * @param functionName The name of the agent function to call.\n */\n constructor(type: string, args: any[], private functionName: string) {\n super(type, args);\n }\n\n /**\n * Gets the name of the agent function to call.\n */\n getFunctionName = () => this.functionName;\n\n /**\n * Gets whether this attribute is a guard.\n */\n isGuard = () => false;\n\n /**\n * Gets the attribute details.\n */\n getDetails(): CallbackAttributeDetails {\n return {\n type: this.type,\n args: this.args,\n functionName: this.getFunctionName()\n };\n }\n\n /**\n * Attempt to call the agent function that this callback refers to.\n * @param agent The agent.\n */\n abstract callAgentFunction: (agent: Agent, isSuccess: boolean, isAborted: boolean) => void;\n}\n", "import Callback from \"./Callback\";\nimport Lookup from \"../../Lookup\";\nimport { Agent } from \"../../Agent\";\n\n/**\n * An ENTRY callback which defines an agent function to call when the associated node is updated and moves out of running state.\n */\nexport default class Entry extends Callback {\n /**\n * @param functionName The name of the agent function to call.\n * @param args The array of callback argument definitions.\n */\n constructor(functionName: string, args: any[]) {\n super(\"entry\", args, functionName);\n }\n\n /**\n * Attempt to call the agent function that this callback refers to.\n * @param agent The agent.\n */\n callAgentFunction = (agent: Agent) => {\n // Attempt to get the invoker for the callback function.\n const callbackFuncInvoker = Lookup.getFuncInvoker(agent, this.getFunctionName());\n\n // The callback function should be defined.\n if (callbackFuncInvoker === null) {\n throw new Error(\n `cannot call entry function '${this.getFunctionName()}' as is not defined on the agent and has not been registered`\n );\n }\n\n // Call the callback function.\n callbackFuncInvoker(this.args);\n };\n}\n", "import Callback from \"./Callback\";\nimport Lookup from \"../../Lookup\";\nimport { Agent } from \"../../Agent\";\n\n/**\n * A STEP callback which defines an agent function to call when the associated node is updated.\n */\nexport default class Step extends Callback {\n /**\n * @param functionName The name of the agent function to call.\n * @param args The array of callback argument definitions.\n */\n constructor(functionName: string, args: any[]) {\n super(\"step\", args, functionName);\n }\n\n /**\n * Attempt to call the agent function that this callback refers to.\n * @param agent The agent.\n */\n callAgentFunction = (agent: Agent) => {\n // Attempt to get the invoker for the callback function.\n const callbackFuncInvoker = Lookup.getFuncInvoker(agent, this.getFunctionName());\n\n // The callback function should be defined.\n if (callbackFuncInvoker === null) {\n throw new Error(\n `cannot call step function '${this.getFunctionName()}' as is not defined on the agent and has not been registered`\n );\n }\n\n // Call the callback function.\n callbackFuncInvoker(this.args);\n };\n}\n", "import Callback from \"./Callback\";\nimport Lookup from \"../../Lookup\";\nimport { Agent } from \"../../Agent\";\n\n/**\n * An EXIT callback which defines an agent function to call when the associated node is updated and moves to a finished state or is aborted.\n */\nexport default class Exit extends Callback {\n /**\n * @param functionName The name of the agent function to call.\n * @param args The array of callback argument definitions.\n */\n constructor(functionName: string, args: any[]) {\n super(\"exit\", args, functionName);\n }\n\n /**\n * Attempt to call the agent function that this callback refers to.\n * @param agent The agent.\n * @param isSuccess Whether the decorated node was left with a success state.\n * @param isAborted Whether the decorated node was aborted.\n */\n callAgentFunction = (agent: Agent, isSuccess: boolean, isAborted: boolean) => {\n // Attempt to get the invoker for the callback function.\n const callbackFuncInvoker = Lookup.getFuncInvoker(agent, this.getFunctionName());\n\n // The callback function should be defined.\n if (callbackFuncInvoker === null) {\n throw new Error(\n `cannot call exit function '${this.getFunctionName()}' as is not defined on the agent and has not been registered`\n );\n }\n\n // Call the callback function\n callbackFuncInvoker([{ value: { succeeded: isSuccess, aborted: isAborted } }, ...this.args]);\n };\n}\n", "import { AnyNodeDefinition, RootNodeDefinition } from \"./BehaviourTreeDefinition\";\nimport GuardPath, { GuardPathPart } from \"./attributes/guards/GuardPath\";\nimport { validateBranchSubtreeLinks } from \"./BehaviourTreeDefinitionValidator\";\nimport { isInteger } from \"./BehaviourTreeDefinitionUtilities\";\nimport Node from \"./nodes/Node\";\nimport Composite from \"./nodes/composite/Composite\";\nimport Decorator from \"./nodes/decorator/Decorator\";\nimport Parallel from \"./nodes/composite/Parallel\";\nimport Selector from \"./nodes/composite/Selector\";\nimport Sequence from \"./nodes/composite/Sequence\";\nimport Lotto from \"./nodes/composite/Lotto\";\nimport Fail from \"./nodes/decorator/Fail\";\nimport Flip from \"./nodes/decorator/Flip\";\nimport Repeat from \"./nodes/decorator/Repeat\";\nimport Retry from \"./nodes/decorator/Retry\";\nimport Root from \"./nodes/decorator/Root\";\nimport Succeed from \"./nodes/decorator/Succeed\";\nimport Action from \"./nodes/leaf/Action\";\nimport Condition from \"./nodes/leaf/Condition\";\nimport Wait from \"./nodes/leaf/Wait\";\nimport Lookup from \"./Lookup\";\nimport Attribute from \"./attributes/Attribute\";\nimport While from \"./attributes/guards/While\";\nimport Until from \"./attributes/guards/Until\";\nimport Entry from \"./attributes/callbacks/Entry\";\nimport Step from \"./attributes/callbacks/Step\";\nimport Exit from \"./attributes/callbacks/Exit\";\n\n/**\n * A type representing any node instance in a behaviour tree.\n */\ntype AnyNode =\n | Root\n | Action\n | Condition\n | Wait\n | Sequence\n | Selector\n | Lotto\n | Parallel\n | Repeat\n | Retry\n | Flip\n | Succeed\n | Fail;\n\n/**\n * A type defining a mapping of root node identifiers to root node definitions.\n */\ntype RootNodeDefinitionMap = { [key: string | symbol]: RootNodeDefinition };\n\n/**\n * A symbol to use as the main root key in any root node mappings.\n */\nconst MAIN_ROOT_NODE_KEY = Symbol(\"__root__\");\n\n/**\n * Build and populate the root nodes based on the provided definition, assuming that the definition has been validated.\n * @param definition The root node definitions.\n * @returns The built and populated root node definitions.\n */\nexport default function buildRootNode(definition: RootNodeDefinition[]): Root {\n // Create a mapping of root node identifers to root node definitions, including globally registered subtree root node definitions.\n const rootNodeDefinitionMap = createRootNodeDefinitionMap(definition);\n\n // Now that we have all of our root node definitons (those part of the tree definition and those globally\n // registered) we should validate the definition. This will also double-check that we dont have any circular\n // dependencies in our branch -> subtree references and that we have no broken branch -> subtree links.\n validateBranchSubtreeLinks(definition, true);\n\n // Create our populated tree of node instances, starting with our main root node.\n const rootNode = nodeFactory(rootNodeDefinitionMap[MAIN_ROOT_NODE_KEY], rootNodeDefinitionMap) as Root;\n\n // Set a guard path on every leaf of the tree to evaluate as part of each update.\n applyLeafNodeGuardPaths(rootNode);\n\n // We only need to return the main root node.\n return rootNode;\n}\n\n/**\n * A factory function which creates a node instance based on the specified definition.\n * @param definition The node definition.\n * @param rootNodeDefinitionMap The mapping of root node identifers to root node definitions, including globally registered subtree root node definitions.\n * @returns A node instance based on the specified definition.\n */\nfunction nodeFactory(definition: AnyNodeDefinition, rootNodeDefinitionMap: RootNodeDefinitionMap): AnyNode {\n // Get the attributes for the node.\n const attributes = nodeAttributesFactory(definition);\n\n // Create the node instance based on the definition type.\n switch (definition.type) {\n case \"root\":\n return new Root(attributes, nodeFactory(definition.child, rootNodeDefinitionMap));\n\n case \"repeat\":\n let iterations: number | null = null;\n let iterationsMin: number | null = null;\n let iterationsMax: number | null = null;\n\n if (Array.isArray(definition.iterations)) {\n iterationsMin = definition.iterations[0];\n iterationsMax = definition.iterations[1];\n } else if (isInteger(definition.iterations)) {\n iterations = definition.iterations!;\n }\n\n return new Repeat(\n attributes,\n iterations,\n iterationsMin,\n iterationsMax,\n nodeFactory(definition.child, rootNodeDefinitionMap)\n );\n\n case \"retry\":\n let attempts: number | null = null;\n let attemptsMin: number | null = null;\n let attemptsMax: number | null = null;\n\n if (Array.isArray(definition.attempts)) {\n attemptsMin = definition.attempts[0];\n attemptsMax = definition.attempts[1];\n } else if (isInteger(definition.attempts)) {\n attempts = definition.attempts!;\n }\n\n return new Retry(\n attributes,\n attempts,\n attemptsMin,\n attemptsMax,\n nodeFactory(definition.child, rootNodeDefinitionMap)\n );\n\n case \"flip\":\n return new Flip(attributes, nodeFactory(definition.child, rootNodeDefinitionMap));\n\n case \"succeed\":\n return new Succeed(attributes, nodeFactory(definition.child, rootNodeDefinitionMap));\n\n case \"fail\":\n return new Fail(attributes, nodeFactory(definition.child, rootNodeDefinitionMap));\n\n case \"sequence\":\n return new Sequence(\n attributes,\n definition.children.map((child) => nodeFactory(child, rootNodeDefinitionMap))\n );\n\n case \"selector\":\n return new Selector(\n attributes,\n definition.children.map((child) => nodeFactory(child, rootNodeDefinitionMap))\n );\n\n case \"parallel\":\n return new Parallel(\n attributes,\n definition.children.map((child) => nodeFactory(child, rootNodeDefinitionMap))\n );\n\n case \"lotto\":\n return new Lotto(\n attributes,\n definition.weights,\n definition.children.map((child) => nodeFactory(child, rootNodeDefinitionMap))\n );\n\n case \"branch\":\n return nodeFactory(rootNodeDefinitionMap[definition.ref].child, rootNodeDefinitionMap);\n\n case \"action\":\n return new Action(attributes, definition.call, definition.args || []);\n\n case \"condition\":\n return new Condition(attributes, definition.call, definition.args || []);\n\n case \"wait\":\n let duration: number | null = null;\n let durationMin: number | null = null;\n let durationMax: number | null = null;\n\n if (Array.isArray(definition.duration)) {\n durationMin = definition.duration[0];\n durationMax = definition.duration[1];\n } else if (isInteger(definition.duration)) {\n duration = definition.duration!;\n }\n\n return new Wait(attributes, duration, durationMin, durationMax);\n }\n}\n\n/**\n * Creates an array of node attribute instances based on the specified node definition.\n * @param definition The node definition.\n * @returns An array of node attribute instances based on the specified node definition.\n */\nfunction nodeAttributesFactory(definition: AnyNodeDefinition): Attribute[] {\n const attributes: Attribute[] = [];\n\n if (definition.while) {\n attributes.push(new While(definition.while.call, definition.while.args ?? []));\n }\n\n if (definition.until) {\n attributes.push(new Until(definition.until.call, definition.until.args ?? []));\n }\n\n if (definition.entry) {\n attributes.push(new Entry(definition.entry.call, definition.entry.args ?? []));\n }\n\n if (definition.step) {\n attributes.push(new Step(definition.step.call, definition.step.args ?? []));\n }\n\n if (definition.exit) {\n attributes.push(new Exit(definition.exit.call, definition.exit.args ?? []));\n }\n\n return attributes;\n}\n\n/**\n * Creates a mapping of root node identifers to root node definitions, mixing in globally registered subtree root node definitions.\n * @param definition The root node definitions.\n * @returns A mapping of root node identifers to root node definitions, including globally registered subtree root node definitions.\n */\nfunction createRootNodeDefinitionMap(definition: RootNodeDefinition[]): RootNodeDefinitionMap {\n // Create a mapping of root node identifers to root node definitions.\n const rootNodeMap: RootNodeDefinitionMap = {};\n\n // Add in any registered subtree root node definitions.\n for (const [name, rootNodeDefinition] of Object.entries(Lookup.getSubtrees())) {\n // The name used when registering the subtree will be used as the root node identifier.\n rootNodeMap[name] = { ...rootNodeDefinition, id: name };\n }\n\n // Populate the map with the root node definitions that were included with the tree definition.\n // We do this after adding any registered subtrees as we want these to take presedence.\n for (const rootNodeDefinition of definition) {\n rootNodeMap[rootNodeDefinition.id ?? MAIN_ROOT_NODE_KEY] = rootNodeDefinition;\n }\n\n return rootNodeMap;\n}\n\n/**\n * Applies a guard path to every leaf of the tree to evaluate as part of each update.\n * @param root The main root tree node.\n */\nfunction applyLeafNodeGuardPaths(root: Root) {\n const nodePaths: Node[][] = [];\n\n const findLeafNodes = (path: Node[], node: Node) => {\n // Add the current node to the path.\n path = path.concat(node);\n\n // Check whether the current node is a leaf node.\n if (node.isLeafNode()) {\n nodePaths.push(path);\n } else {\n (node as Composite | Decorator).getChildren().forEach((child) => findLeafNodes(path, child));\n }\n };\n\n // Find all leaf node paths, starting from the root.\n findLeafNodes([], root);\n\n nodePaths.forEach((path) => {\n // Each node in the current path will have to be assigned a guard path, working from the root outwards.\n for (let depth = 0; depth < path.length; depth++) {\n // Get the node in the path at the current depth.\n const currentNode = path[depth];\n\n // The node may already have been assigned a guard path, if so just skip it.\n if (currentNode.hasGuardPath()) {\n continue;\n }\n\n // Create the guard path for the current node.\n const guardPath = new GuardPath(\n path\n .slice(0, depth + 1)\n .map((node) => ({ node, guards: node.getGuardAttributes() }))\n .filter((details) => details.guards.length > 0)\n );\n\n // Assign the guard path to the current node.\n currentNode.setGuardPath(guardPath);\n }\n });\n}\n", "import State, { AnyState } from \"./State\";\nimport Lookup from \"./Lookup\";\nimport Node from \"./nodes/Node\";\nimport Root from \"./nodes/decorator/Root\";\nimport Composite from \"./nodes/composite/Composite\";\nimport Decorator from \"./nodes/decorator/Decorator\";\nimport { Agent, GlobalFunction } from \"./Agent\";\nimport { CallbackAttributeDetails } from \"./attributes/callbacks/Callback\";\nimport { GuardAttributeDetails } from \"./attributes/guards/Guard\";\nimport { BehaviourTreeOptions } from \"./BehaviourTreeOptions\";\nimport { convertMDSLToJSON } from \"./mdsl/MDSLDefinitionParser\";\nimport { RootNodeDefinition } from \"./BehaviourTreeDefinition\";\nimport { validateDefinition, validateJSONDefinition } from \"./BehaviourTreeDefinitionValidator\";\nimport buildRootNode from \"./BehaviourTreeBuilder\";\nimport { isNullOrUndefined } from \"./BehaviourTreeDefinitionUtilities\";\n\n// Purely for outside inspection of the tree.\nexport type FlattenedTreeNode = {\n id: string;\n type: string;\n caption: string;\n state: AnyState;\n guards: GuardAttributeDetails[];\n callbacks: CallbackAttributeDetails[];\n args: any[];\n parentId: string | null;\n};\n\n/**\n * A representation of a behaviour tree.\n */\nexport class BehaviourTree {\n /**\n * The main root tree node.\n */\n public readonly rootNode: Root;\n\n /**\n * Creates a new instance of the BehaviourTree class.\n * @param definition The behaviour tree definition as either an MDSL string, root node definition object or array of root node definition objects.\n * @param agent The agent instance that this behaviour tree is modelling behaviour for.\n * @param options The behaviour tree options object.\n */\n constructor(\n definition: string | RootNodeDefinition | RootNodeDefinition[],\n private agent: Agent,\n private options: BehaviourTreeOptions = {}\n ) {\n // The tree definition must be defined.\n if (isNullOrUndefined(definition)) {\n throw new Error(\"tree definition not defined\");\n }\n\n // The agent must be defined and not null.\n if (typeof agent !== \"object\" || agent === null) {\n throw new Error(\"the agent must be an object and not null\");\n }\n\n // We should validate the definition before we try to build the tree nodes.\n const { succeeded, errorMessage, json } = validateDefinition(definition);\n\n // Did our validation fail without error?\n if (!succeeded) {\n throw new Error(`invalid definition: ${errorMessage}`);\n }\n\n // Double check that we did actually get our json definition as part of our definition validtion.\n if (!json) {\n throw new Error(\n \"expected json definition to be returned as part of successful definition validation response\"\n );\n }\n\n try {\n // Create the populated tree of behaviour tree nodes and get the root node.\n this.rootNode = buildRootNode(json);\n } catch (exception) {\n // There was an issue in trying build and populate the behaviour tree.\n throw new Error(`error building tree: ${(exception as Error).message}`);\n }\n }\n\n /**\n * Gets whether the tree is in the RUNNING state.\n * @returns true if the tree is in the RUNNING state, otherwise false.\n */\n isRunning() {\n return this.rootNode.getState() === State.RUNNING;\n }\n\n /**\n * Gets the current tree state of SUCCEEDED, FAILED, READY or RUNNING.\n * @returns The current tree state.\n */\n getState() {\n return this.rootNode.getState();\n }\n\n /**\n * Step the tree.\n * 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.\n * 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\n * 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.\n *\n * 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.\n */\n step() {\n // If the root node has already been stepped to completion then we need to reset it.\n if (this.rootNode.getState() === State.SUCCEEDED || this.rootNode.getState() === State.FAILED) {\n this.rootNode.reset();\n }\n\n try {\n this.rootNode.update(this.agent, this.options);\n } catch (exception) {\n throw new Error(`error stepping tree: ${(exception as Error).message}`);\n }\n }\n\n /**\n * Resets the tree from the root node outwards to each nested node, giving each a state of READY.\n */\n reset() {\n this.rootNode.reset();\n }\n\n /**\n * Gets the flattened details of every node in the tree.\n * @returns The flattened details of every node in the tree.\n */\n getFlattenedNodeDetails(): FlattenedTreeNode[] {\n // Create an empty flattened array of tree nodes.\n const flattenedTreeNodes: FlattenedTreeNode[] = [];\n\n /**\n * Helper function to process a node instance and push details into the flattened tree nodes array.\n * @param node The current node.\n * @param parentUid The UID of the node parent, or null if the node is the main root node.\n */\n const processNode = (node: Node, parentUid: string | null) => {\n // Get the guard and callback attribute details for this node.\n const guards = node\n .getAttributes()\n .filter((attribute) => attribute.isGuard())\n .map((attribute) => attribute.getDetails()) as GuardAttributeDetails[];\n const callbacks = node\n .getAttributes()\n .filter((attribute) => !attribute.isGuard())\n .map((attribute) => attribute.getDetails()) as CallbackAttributeDetails[];\n\n // Push the current node into the flattened nodes array.\n flattenedTreeNodes.push({\n id: node.getUid(),\n type: node.getType(),\n caption: node.getName(),\n state: node.getState(),\n guards,\n callbacks,\n args: node.getArguments(),\n parentId: parentUid\n });\n\n // Process each of the nodes children if it is not a leaf node.\n if (!node.isLeafNode()) {\n (node as Composite | Decorator)\n .getChildren()\n .forEach((child) => processNode(child, (node as Composite | Decorator).getUid()));\n }\n };\n\n // Convert the nested node structure into a flattened array of node details.\n processNode(this.rootNode, null);\n\n return flattenedTreeNodes;\n }\n\n /**\n * Registers the action/condition/guard/callback function or subtree with the given name.\n * @param name The name of the function or subtree to register.\n * @param value The function or subtree definition to register.\n */\n static register(name: string, value: GlobalFunction | string | RootNodeDefinition) {\n // Are we going to register a action/condition/guard/callback function?\n if (typeof value === \"function\") {\n Lookup.setFunc(name, value);\n return;\n }\n\n // We are not registering an action/condition/guard/callback function, so we must be registering a subtree.\n if (typeof value === \"string\") {\n let rootNodeDefinitions: RootNodeDefinition[];\n\n // We will assume that any string passed in will be a mdsl definition.\n try {\n rootNodeDefinitions = convertMDSLToJSON(value);\n } catch (exception) {\n throw new Error(`error registering definition, invalid MDSL: ${(exception as Error).message}`);\n }\n\n // This function should only ever be called with a definition containing a single unnamed root node.\n if (rootNodeDefinitions.length != 1 || rootNodeDefinitions[0].id !== null) {\n throw new Error(\"error registering definition: expected a single unnamed root node\");\n }\n\n try {\n // We should validate the subtree as we don't want invalid subtrees available via the lookup.\n const { succeeded, errorMessage } = validateJSONDefinition(rootNodeDefinitions[0]);\n\n // Did our validation fail without error?\n if (!succeeded) {\n throw new Error(errorMessage);\n }\n } catch (exception) {\n throw new Error(`error registering definition: ${(exception as Error).message}`);\n }\n\n // Everything seems hunky-dory, register the subtree.\n Lookup.setSubtree(name, rootNodeDefinitions[0]);\n } else if (typeof value === \"object\" && !Array.isArray(value)) {\n // We will assume that any object passed in is a root node definition.\n\n try {\n // We should validate the subtree as we don't want invalid subtrees available via the lookup.\n const { succeeded, errorMessage } = validateJSONDefinition(value);\n\n // Did our validation fail without error?\n if (!succeeded) {\n throw new Error(errorMessage);\n }\n } catch (exception) {\n throw new Error(`error registering definition: ${(exception as Error).message}`);\n }\n\n // Everything seems hunky-dory, register the subtree.\n Lookup.setSubtree(name, value);\n } else {\n throw new Error(\"unexpected value, expected string mdsl definition, root node json definition or function\");\n }\n }\n\n /**\n * Unregisters the registered action/condition/guard/callback function or subtree with the given name.\n * @param name The name of the registered action/condition/guard/callback function or subtree to unregister.\n */\n static unregister(name: string): void {\n Lookup.remove(name);\n }\n\n /**\n * Unregister all registered action/condition/guard/callback functions and subtrees.\n */\n static unregisterAll(): void {\n Lookup.empty();\n }\n}\n"], + "mappings": ";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AACA,aAAO,eAAe,SAAS,cAAc,EAAE,OAAO,KAAK,CAAC;AAC5D,cAAQ,cAAc;AAItB,UAAI,cAA6B,WAAY;AAMzC,iBAASA,aAAY,aAAa,SAAS;AACvC,cAAI,YAAY,QAAQ;AAAE,sBAAU;AAAA,UAAG;AACvC,eAAK,eAAe;AACpB,eAAK,WAAW;AAAA,QACpB;AACA,eAAO,eAAeA,aAAY,WAAW,eAAe;AAAA,UAExD,KAAK,WAAY;AACb,mBAAO,KAAK;AAAA,UAChB;AAAA,UACA,YAAY;AAAA,UACZ,cAAc;AAAA,QAClB,CAAC;AACD,eAAO,eAAeA,aAAY,WAAW,WAAW;AAAA,UAEpD,KAAK,WAAY;AACb,mBAAO,KAAK;AAAA,UAChB;AAAA,UACA,KAAK,SAAU,OAAO;AAClB,iBAAK,WAAW;AAAA,UACpB;AAAA,UACA,YAAY;AAAA,UACZ,cAAc;AAAA,QAClB,CAAC;AACD,eAAOA;AAAA,MACX,EAAE;AACF,cAAQ,cAAc;AAAA;AAAA;;;ACtCtB;AAAA;AAAA;AACA,aAAO,eAAe,SAAS,cAAc,EAAE,OAAO,KAAK,CAAC;AAC5D,cAAQ,kBAAkB,QAAQ,oBAAoB;AAMtD,eAASC,mBAAkB,OAAO;AAC9B,eAAO,UAAU,QAAQ,UAAU;AAAA,MACvC;AACA,cAAQ,oBAAoBA;AAM5B,eAAS,gBAAgB,OAAO;AAC5B,eAAO,OAAO,UAAU,YAAY,SAAS,KAAK,KAAK,MAAM,KAAK,MAAM;AAAA,MAC5E;AACA,cAAQ,kBAAkB;AAAA;AAAA;;;ACpB1B;AAAA;AAAA;AACA,aAAO,eAAe,SAAS,cAAc,EAAE,OAAO,KAAK,CAAC;AAC5D,cAAQ,QAAQ;AAChB,UAAI,gBAAgB;AACpB,UAAI,cAAc;AAIlB,UAAIC,SAAuB,WAAY;AAKnC,iBAASA,OAAM,cAAc;AAEzB,eAAK,gBAAgB,CAAC;AACtB,eAAK,gBAAgB;AAAA,QACzB;AAOA,QAAAA,OAAM,UAAU,MAAM,SAAU,aAAa,SAAS;AAClD,cAAI,YAAY,QAAQ;AAAE,sBAAU;AAAA,UAAG;AAEvC,cAAI,EAAE,GAAG,YAAY,iBAAiB,OAAO,GAAG;AAC5C,kBAAM,IAAI,MAAM,wCAAwC;AAAA,UAC5D;AAEA,cAAI,sBAAsB,KAAK,cAAc,KAAK,SAAU,MAAM;AAAE,mBAAO,KAAK,gBAAgB;AAAA,UAAa,CAAC;AAC9G,cAAI,qBAAqB;AAErB,gCAAoB,WAAW;AAAA,UACnC,OACK;AAED,iBAAK,cAAc,KAAK,IAAI,cAAc,YAAY,aAAa,OAAO,CAAC;AAAA,UAC/E;AACA,iBAAO;AAAA,QACX;AAOA,QAAAA,OAAM,UAAU,SAAS,SAAU,aAAa,SAAS;AAErD,cAAI,sBAAsB,KAAK,cAAc,KAAK,SAAU,MAAM;AAAE,mBAAO,KAAK,gBAAgB;AAAA,UAAa,CAAC;AAE9G,cAAI,CAAC,qBAAqB;AACtB,mBAAO;AAAA,UACX;AAEA,cAAI,YAAY,QAAW;AAEvB,gBAAI,EAAE,GAAG,YAAY,iBAAiB,OAAO,GAAG;AAC5C,oBAAM,IAAI,MAAM,wCAAwC;AAAA,YAC5D;AACA,gCAAoB,WAAW;AAE/B,gBAAI,oBAAoB,UAAU,GAAG;AACjC,mBAAK,gBAAgB,KAAK,cAAc,OAAO,SAAU,MAAM;AAAE,uBAAO,SAAS;AAAA,cAAqB,CAAC;AAAA,YAC3G;AAAA,UACJ,OACK;AAED,iBAAK,gBAAgB,KAAK,cAAc,OAAO,SAAU,MAAM;AAAE,qBAAO,SAAS;AAAA,YAAqB,CAAC;AAAA,UAC3G;AACA,iBAAO;AAAA,QACX;AAMA,QAAAA,OAAM,UAAU,OAAO,SAAU,SAAS;AACtC,cAAI,YAAY,QAAQ;AAAE,sBAAU,CAAC;AAAA,UAAG;AAExC,cAAI,KAAK,cAAc,WAAW,GAAG;AACjC,mBAAO;AAAA,UACX;AACA,cAAI,cAAc,GAAG,YAAY,mBAAmB,QAAQ,UAAU,IAAI,OAAO,QAAQ;AACzF,cAAI,WAAW,CAAC;AAChB,eAAK,cAAc,QAAQ,SAAU,IAAI;AACrC,gBAAI,cAAc,GAAG,aAAa,UAAU,GAAG;AAC/C,qBAAS,cAAc,GAAG,cAAc,SAAS,eAAe;AAC5D,uBAAS,KAAK,WAAW;AAAA,YAC7B;AAAA,UACJ,CAAC;AACD,cAAI;AAGJ,cAAI,KAAK,eAAe;AAEpB,qBAAS,KAAK,cAAc;AAE5B,gBAAI,OAAO,WAAW,YAAY,SAAS,KAAK,UAAU,GAAG;AACzD,oBAAM,IAAI,MAAM,oFAAoF;AAAA,YACxG;AAAA,UACJ,OACK;AAED,qBAAS,KAAK,OAAO;AAAA,UACzB;AAEA,cAAI,SAAS,SAAS,KAAK,MAAM,SAAS,SAAS,MAAM;AAEzD,cAAI,CAAC,YAAY;AACb,iBAAK,OAAO,QAAQ,CAAC;AAAA,UACzB;AAEA,iBAAO;AAAA,QACX;AAOA,QAAAA,OAAM,UAAU,eAAe,SAAU,SAAS,SAAS;AACvD,cAAI,YAAY,QAAQ;AAAE,sBAAU,CAAC;AAAA,UAAG;AACxC,cAAI,iBAAiB,GAAG,YAAY,mBAAmB,QAAQ,MAAM,IAAI,QAAQ,QAAQ;AAEzF,cAAI,YAAY,GAAG;AACf,mBAAO,CAAC;AAAA,UACZ;AAEA,cAAI,EAAE,GAAG,YAAY,iBAAiB,OAAO,GAAG;AAC5C,kBAAM,IAAI,MAAM,wCAAwC;AAAA,UAC5D;AACA,cAAI,SAAS,CAAC;AAGd,iBAAO,OAAO,SAAS,WAAW,KAAK,cAAc,SAAS,GAAG;AAC7D,mBAAO,KAAK,KAAK,KAAK,OAAO,CAAC;AAAA,UAClC;AAEA,cAAI,eAAe;AAEf,gBAAI,SAAS,CAAC;AAEd,qBAAS,KAAK,GAAG,WAAW,QAAQ,KAAK,SAAS,QAAQ,MAAM;AAC5D,kBAAI,cAAc,SAAS;AAC3B,kBAAI,OAAO,QAAQ,WAAW,MAAM,IAAI;AACpC,uBAAO,KAAK,WAAW;AAAA,cAC3B;AAAA,YACJ;AACA,qBAAS;AAAA,UACb;AACA,iBAAO;AAAA,QACX;AACA,eAAOA;AAAA,MACX,EAAE;AACF,cAAQ,QAAQA;AAAA;AAAA;;;AC5JhB;AAAA;AAAA;AACA,aAAO,eAAe,SAAS,cAAc,EAAE,OAAO,KAAK,CAAC;AAC5D,cAAQ,cAAc;AACtB,UAAI,UAAU;AAMd,eAASC,aAAY,uBAAuB;AAExC,YAAI,CAAC,uBAAuB;AACxB,iBAAO,IAAI,QAAQ,MAAM;AAAA,QAC7B;AAEA,YAAI,MAAM,QAAQ,qBAAqB,GAAG;AAEtC,cAAI,eAAe;AACnB,cAAI,UAAU,IAAI,QAAQ,MAAM;AAEhC,uBAAa,QAAQ,SAAU,IAAI;AAC/B,gBAAI,cAAc,GAAG,IAAI,SAAS,GAAG;AACrC,mBAAO,QAAQ,IAAI,aAAa,MAAM;AAAA,UAC1C,CAAC;AAED,iBAAO;AAAA,QACX,OACK;AAED,cAAI,SAAS,sBAAsB,QAAQ,eAAe,sBAAsB;AAEhF,cAAI,UAAU,IAAI,QAAQ,MAAM,MAAM;AAEtC,cAAI,cAAc;AACd,yBAAa,QAAQ,SAAU,IAAI;AAC/B,kBAAI,cAAc,GAAG,IAAI,SAAS,GAAG;AACrC,qBAAO,QAAQ,IAAI,aAAa,MAAM;AAAA,YAC1C,CAAC;AAAA,UACL;AAEA,iBAAO;AAAA,QACX;AAAA,MACJ;AACA,cAAQ,cAAcA;AAAA;AAAA;;;AC3CtB;AAAA;AAAA;AACA,aAAO,eAAe,SAAS,cAAc,EAAE,OAAO,KAAK,CAAC;AAC5D,UAAI,gBAAgB;AACpB,cAAQ,UAAU,cAAc;AAAA;AAAA;;;ACHhC;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;;ACGO,MAAK,QAAL,kBAAKC,WAAL;AACH,IAAAA,OAAA,WAAQ;AACR,IAAAA,OAAA,aAAU;AACV,IAAAA,OAAA,eAAY;AACZ,IAAAA,OAAA,YAAS;AAJD,WAAAA;AAAA,KAAA;;;ACWL,WAAS,WAAW,MAAkD;AACzE,WAAO,KAAK,SAAS;AAAA,EACzB;AAOO,WAAS,aAAa,MAAoD;AAC7E,WAAO,KAAK,SAAS;AAAA,EACzB;AAOO,WAAS,WAAW,MAA8C;AACrE,WAAO,CAAC,UAAU,UAAU,aAAa,MAAM,EAAE,SAAS,KAAK,IAAI;AAAA,EACvE;AAOO,WAAS,gBAAgB,MAAuD;AACnF,WAAO,CAAC,QAAQ,UAAU,SAAS,QAAQ,WAAW,MAAM,EAAE,SAAS,KAAK,IAAI;AAAA,EACpF;AAOO,WAAS,gBAAgB,MAAuD;AACnF,WAAO,CAAC,YAAY,YAAY,SAAS,UAAU,EAAE,SAAS,KAAK,IAAI;AAAA,EAC3E;AAOO,WAAS,kBAAkB,gBAAwD;AACtF,UAAM,QAA6B,CAAC;AAEpC,UAAM,cAAc,CAAC,0BAA6C;AAC9D,YAAM,KAAK,qBAAqB;AAEhC,UAAI,gBAAgB,qBAAqB,GAAG;AACxC,8BAAsB,SAAS,QAAQ,WAAW;AAAA,MACtD,WAAW,gBAAgB,qBAAqB,GAAG;AAC/C,oBAAY,sBAAsB,KAAK;AAAA,MAC3C;AAAA,IACJ;AAEA,gBAAY,cAAc;AAE1B,WAAO;AAAA,EACX;AAOO,WAAS,UAAU,OAAyB;AAC/C,WAAO,OAAO,UAAU,YAAY,KAAK,MAAM,KAAK,MAAM;AAAA,EAC9D;AAOO,WAAS,kBAAkB,OAAyB;AACvD,WAAO,OAAO,UAAU,eAAe,UAAU;AAAA,EACrD;;;AClFO,WAAS,YAAY,QAAkB,UAAsC;AAEhF,UAAM,SAAS,OAAO,MAAM;AAG5B,QAAI,WAAW,QAAW;AACtB,YAAM,IAAI,MAAM,8BAA8B;AAAA,IAClD;AAGA,QAAI,YAAY,QAAW;AAEvB,YAAM,iBAAiB,OAAO,aAAa,WAAW,CAAC,QAAQ,IAAI;AAGnE,UAAI,0BAA0B,eAAe,KAAK,CAAC,SAAS,OAAO,YAAY,MAAM,KAAK,YAAY,CAAC;AAGvG,UAAI,CAAC,yBAAyB;AAC1B,cAAM,oBAAoB,eAAe,IAAI,CAAC,SAAS,MAAM,OAAO,GAAG,EAAE,KAAK,MAAM;AACpF,cAAM,IAAI,MAAM,sCAAsC,oBAAoB,eAAe,SAAS,GAAG;AAAA,MACzG;AAAA,IACJ;AAGA,WAAO;AAAA,EACX;AAOO,WAAS,yBAAyB,YAGvC;AAEE,UAAM,eAA0C,CAAC;AAGjD,UAAM,sBAAsB,WAAW,QAAQ,sBAAsB,CAAC,UAAU;AAC5E,UAAI,gBAAgB,MAAM,UAAU,GAAG,MAAM,SAAS,CAAC;AACvD,UAAI,cAAc,OAAO,KAAK,YAAY,EAAE,KAAK,CAAC,QAAQ,aAAa,SAAS,aAAa;AAG7F,UAAI,CAAC,aAAa;AACd,sBAAc,KAAK,OAAO,KAAK,YAAY,EAAE;AAC7C,qBAAa,eAAe;AAAA,MAChC;AAEA,aAAO;AAAA,IACX,CAAC;AAED,WAAO,EAAE,cAAc,oBAAoB;AAAA,EAC/C;AAOO,WAAS,0BAA0B,YAA8B;AAEpE,iBAAa,WAAW,QAAQ,OAAO,KAAK;AAC5C,iBAAa,WAAW,QAAQ,OAAO,KAAK;AAC5C,iBAAa,WAAW,QAAQ,OAAO,KAAK;AAC5C,iBAAa,WAAW,QAAQ,OAAO,KAAK;AAC5C,iBAAa,WAAW,QAAQ,OAAO,KAAK;AAC5C,iBAAa,WAAW,QAAQ,OAAO,KAAK;AAC5C,iBAAa,WAAW,QAAQ,OAAO,KAAK;AAG5C,WAAO,WAAW,QAAQ,QAAQ,GAAG,EAAE,KAAK,EAAE,MAAM,GAAG;AAAA,EAC3D;;;AChCO,WAAS,oBACZ,QACA,4BACa;AACb,UAAM,eAA8B,CAAC;AAGrC,QAAI,CAAC,CAAC,KAAK,GAAG,EAAE,SAAS,OAAO,EAAE,GAAG;AACjC,aAAO;AAAA,IACX;AAIA,UAAM,eAAe,YAAY,QAAQ,CAAC,KAAK,GAAG,CAAC,MAAM,MAAM,MAAM;AAErE,UAAM,qBAA+B,CAAC;AAGtC,WAAO,OAAO,UAAU,OAAO,OAAO,cAAc;AAEhD,yBAAmB,KAAK,OAAO,MAAM,CAAE;AAAA,IAC3C;AAGA,uBAAmB,QAAQ,CAAC,OAAO,UAAU;AAEzC,YAAM,wBAAwB,EAAE,QAAQ;AAGxC,UAAI,uBAAuB;AAEvB,cAAM,qBAAqB,sBAAsB,OAAO,0BAA0B;AAGlF,qBAAa,KAAK,kBAAkB;AAAA,MACxC,OAAO;AAEH,YAAI,UAAU,KAAK;AACf,gBAAM,IAAI,MAAM,uDAAuD,QAAQ;AAAA,QACnF;AAAA,MACJ;AAAA,IACJ,CAAC;AAGD,gBAAY,QAAQ,YAAY;AAGhC,WAAO;AAAA,EACX;AAQA,WAAS,sBAAsB,OAAe,4BAAoE;AAE9G,QAAI,UAAU,QAAQ;AAClB,aAAO;AAAA,QACH,OAAO;AAAA,QACP,MAAM;AAAA,MACV;AAAA,IACJ;AAGA,QAAI,UAAU,UAAU,UAAU,SAAS;AACvC,aAAO;AAAA,QACH,OAAO,UAAU;AAAA,QACjB,MAAM;AAAA,MACV;AAAA,IACJ;AAKA,QAAI,CAAC,MAAM,KAAY,GAAG;AACtB,aAAO;AAAA,QACH,OAAO,WAAW,KAAK;AAAA,QACvB,WAAW,WAAW,KAAK,MAAM,SAAS,OAAO,EAAE;AAAA,QACnD,MAAM;AAAA,MACV;AAAA,IACJ;AAGA,QAAI,MAAM,MAAM,YAAY,GAAG;AAC3B,aAAO;AAAA,QACH,OAAO,2BAA2B,OAAO,QAAQ,OAAO,GAAG;AAAA,QAC3D,MAAM;AAAA,MACV;AAAA,IACJ;AAGA,WAAO;AAAA,MACH,OAAO;AAAA,MACP,MAAM;AAAA,IACV;AAAA,EACJ;;;ACjIO,WAAS,qBACZ,QACA,4BACc;AACd,UAAM,qBAA+C,CAAC,SAAS,SAAS,SAAS,QAAQ,MAAM;AAG/F,UAAM,aAA6B,CAAC;AAGpC,QAAI,oBAAoB,OAAO,IAAI,YAAY;AAG/C,WAAO,mBAAmB,SAAS,iBAAiB,GAAG;AAEnD,UAAI,WAAW,oBAAoB;AAC/B,cAAM,IAAI,MAAM,wBAAwB,OAAO,GAAG,YAAY,mBAAmB;AAAA,MACrF;AAGA,aAAO,MAAM;AAGb,YAAM,CAAC,4BAA4B,kBAAkB,IAAI;AAAA,QACrD;AAAA,QACA;AAAA,MACJ;AAGA,UAAI,yBAAyB,SAAS,cAAc;AAChD,cAAM,IAAI,MAAM,gEAAgE;AAAA,MACpF;AAGA,yBACK,OAAO,CAAC,QAAQ,IAAI,SAAS,YAAY,EACzC,QAAQ,CAAC,QAAQ;AACd,cAAM,IAAI;AAAA,UACN,qCAAqC,IAAI;AAAA,QAC7C;AAAA,MACJ,CAAC;AAGL,iBAAW,qBAAqB;AAAA,QAC5B,MAAM,wBAAwB;AAAA,QAC9B,MAAM,mBAAmB,IAAI,CAAC,EAAE,MAAM,MAAM,KAAK;AAAA,MACrD;AAGA,0BAAoB,OAAO,IAAI,YAAY;AAAA,IAC/C;AAEA,WAAO;AAAA,EACX;;;ACnCO,WAAS,kBAAkB,YAA0C;AAExE,UAAM,EAAE,cAAc,oBAAoB,IAAI,yBAAyB,UAAU;AAGjF,UAAM,SAAS,0BAA0B,mBAAmB;AAE5D,WAAO,8BAA8B,QAAQ,YAAY;AAAA,EAC7D;AAQA,WAAS,8BACL,QACA,2BACoB;AAEpB,QAAI,OAAO,SAAS,GAAG;AACnB,YAAM,IAAI,MAAM,qBAAqB;AAAA,IACzC;AAGA,QAAI,OAAO,OAAO,CAAC,UAAU,UAAU,GAAG,EAAE,WAAW,OAAO,OAAO,CAAC,UAAU,UAAU,GAAG,EAAE,QAAQ;AACnG,YAAM,IAAI,MAAM,0BAA0B;AAAA,IAC9C;AASA,UAAM,aAAoF,CAAC;AAG3F,UAAM,YAA2C,CAAC;AAGlD,UAAM,WAAW,CAAC,SAA4B;AAE1C,UAAI,WAAW,IAAI,GAAG;AAGlB,YAAI,WAAW,WAAW,SAAS,IAAI,QAAQ;AAC3C,gBAAM,IAAI,MAAM,iDAAiD;AAAA,QACrE;AAGA,kBAAU,KAAK,IAAI;AAGnB,mBAAW,KAAK,CAAC,IAAI,CAAC;AAEtB;AAAA,MACJ;AAIA,UAAI,CAAC,WAAW,UAAU,CAAC,WAAW,WAAW,SAAS,GAAG,QAAQ;AACjE,cAAM,IAAI,MAAM,0CAA0C;AAAA,MAC9D;AAGA,YAAM,eAAe,WAAW,WAAW,SAAS;AAIpD,YAAM,sBAAsB,aAAa,aAAa,SAAS;AAI/D,UAAI,gBAAgB,mBAAmB,GAAG;AACtC,4BAAoB,WAAW,oBAAoB,YAAY,CAAC;AAChE,4BAAoB,SAAS,KAAK,IAAI;AAAA,MAC1C,WAAW,gBAAgB,mBAAmB,GAAG;AAE7C,YAAI,oBAAoB,OAAO;AAC3B,gBAAM,IAAI,MAAM,qDAAqD;AAAA,QACzE;AAEA,4BAAoB,QAAQ;AAAA,MAChC;AAIA,UAAI,CAAC,WAAW,IAAI,GAAG;AACnB,qBAAa,KAAK,IAAI;AAAA,MAC1B;AAAA,IACJ;AAGA,UAAM,UAAU,MAAgC;AAC5C,UAAI,aAAuC;AAG3C,YAAM,eAAe,WAAW,WAAW,SAAS;AAGpD,UAAI,aAAa,QAAQ;AACrB,qBAAa,aAAa,IAAI;AAAA,MAClC;AAGA,UAAI,CAAC,aAAa,QAAQ;AACtB,mBAAW,IAAI;AAAA,MACnB;AAEA,aAAO;AAAA,IACX;AAGA,WAAO,OAAO,QAAQ;AAElB,YAAM,QAAQ,OAAO,MAAM;AAG3B,cAAQ,MAAM,YAAY,GAAG;AAAA,QACzB,KAAK,QAAQ;AACT,mBAAS,eAAe,QAAQ,yBAAyB,CAAC;AAC1D;AAAA,QACJ;AAAA,QAEA,KAAK,WAAW;AACZ,mBAAS,kBAAkB,QAAQ,yBAAyB,CAAC;AAC7D;AAAA,QACJ;AAAA,QAEA,KAAK,QAAQ;AACT,mBAAS,eAAe,QAAQ,yBAAyB,CAAC;AAC1D;AAAA,QACJ;AAAA,QAEA,KAAK,QAAQ;AACT,mBAAS,eAAe,QAAQ,yBAAyB,CAAC;AAC1D;AAAA,QACJ;AAAA,QAEA,KAAK,UAAU;AACX,mBAAS,iBAAiB,QAAQ,yBAAyB,CAAC;AAC5D;AAAA,QACJ;AAAA,QAEA,KAAK,SAAS;AACV,mBAAS,gBAAgB,QAAQ,yBAAyB,CAAC;AAC3D;AAAA,QACJ;AAAA,QAEA,KAAK,YAAY;AACb,mBAAS,mBAAmB,QAAQ,yBAAyB,CAAC;AAC9D;AAAA,QACJ;AAAA,QAEA,KAAK,YAAY;AACb,mBAAS,mBAAmB,QAAQ,yBAAyB,CAAC;AAC9D;AAAA,QACJ;AAAA,QAEA,KAAK,YAAY;AACb,mBAAS,mBAAmB,QAAQ,yBAAyB,CAAC;AAC9D;AAAA,QACJ;AAAA,QAEA,KAAK,SAAS;AACV,mBAAS,gBAAgB,QAAQ,yBAAyB,CAAC;AAC3D;AAAA,QACJ;AAAA,QAEA,KAAK,UAAU;AACX,mBAAS,iBAAiB,QAAQ,yBAAyB,CAAC;AAC5D;AAAA,QACJ;AAAA,QAEA,KAAK,aAAa;AACd,mBAAS,oBAAoB,QAAQ,yBAAyB,CAAC;AAC/D;AAAA,QACJ;AAAA,QAEA,KAAK,QAAQ;AACT,mBAAS,eAAe,QAAQ,yBAAyB,CAAC;AAC1D;AAAA,QACJ;AAAA,QAEA,KAAK,UAAU;AACX,mBAAS,iBAAiB,QAAQ,yBAAyB,CAAC;AAC5D;AAAA,QACJ;AAAA,QAEA,KAAK,KAAK;AAEN,gBAAM,aAAa,QAAQ;AAG3B,cAAI,YAAY;AACZ,+BAAmB,UAAU;AAAA,UACjC;AAEA;AAAA,QACJ;AAAA,QAEA,SAAS;AACL,gBAAM,IAAI,MAAM,qBAAqB,OAAO;AAAA,QAChD;AAAA,MACJ;AAAA,IACJ;AAEA,WAAO;AAAA,EACX;AAQA,WAAS,eAAe,QAAkB,2BAA0E;AAEhH,QAAI,OAAO;AAAA,MACP,MAAM;AAAA,MACN,IAAI;AAAA,IACR;AAGA,UAAM,gBAAgB,oBAAoB,QAAQ,yBAAyB;AAG3E,QAAI,cAAc,QAAQ;AAEtB,UAAI,cAAc,WAAW,KAAK,cAAc,GAAG,SAAS,cAAc;AAEtE,aAAK,KAAK,cAAc,GAAG;AAAA,MAC/B,OAAO;AACH,cAAM,IAAI,MAAM,oCAAoC;AAAA,MACxD;AAAA,IACJ;AAGA,WAAO,EAAE,GAAG,MAAM,GAAG,qBAAqB,QAAQ,yBAAyB,EAAE;AAG7E,gBAAY,QAAQ,GAAG;AAGvB,WAAO;AAAA,EACX;AAQA,WAAS,kBACL,QACA,2BACqB;AACrB,UAAM,OAAO;AAAA,MACT,MAAM;AAAA,MACN,GAAG,qBAAqB,QAAQ,yBAAyB;AAAA,IAC7D;AAGA,gBAAY,QAAQ,GAAG;AAGvB,WAAO;AAAA,EACX;AAQA,WAAS,eAAe,QAAkB,2BAA0E;AAChH,UAAM,OAAO;AAAA,MACT,MAAM;AAAA,MACN,GAAG,qBAAqB,QAAQ,yBAAyB;AAAA,IAC7D;AAGA,gBAAY,QAAQ,GAAG;AAGvB,WAAO;AAAA,EACX;AAQA,WAAS,eAAe,QAAkB,2BAA0E;AAChH,UAAM,OAAO;AAAA,MACT,MAAM;AAAA,MACN,GAAG,qBAAqB,QAAQ,yBAAyB;AAAA,IAC7D;AAGA,gBAAY,QAAQ,GAAG;AAGvB,WAAO;AAAA,EACX;AAQA,WAAS,iBACL,QACA,2BACoB;AACpB,QAAI,OAAO,EAAE,MAAM,SAAS;AAG5B,UAAM,gBAAgB,oBAAoB,QAAQ,yBAAyB;AAM3E,QAAI,cAAc,QAAQ;AAEtB,oBACK,OAAO,CAAC,QAAQ,IAAI,SAAS,YAAY,CAAC,IAAI,SAAS,EACvD,QAAQ,MAAM;AACX,cAAM,IAAI,MAAM,qDAAqD;AAAA,MACzE,CAAC;AAGL,UAAI,cAAc,WAAW,GAAG;AAE5B,aAAK,aAAa,cAAc,GAAG;AAGnC,YAAI,KAAK,aAAa,GAAG;AACrB,gBAAM,IAAI,MAAM,oEAAoE;AAAA,QACxF;AAAA,MACJ,WAAW,cAAc,WAAW,GAAG;AAEnC,aAAK,aAAa,CAAC,cAAc,GAAG,OAAiB,cAAc,GAAG,KAAe;AAGrF,YAAI,KAAK,WAAW,KAAK,KAAK,KAAK,WAAW,KAAK,GAAG;AAClD,gBAAM,IAAI,MAAM,mFAAmF;AAAA,QACvG;AAGA,YAAI,KAAK,WAAW,KAAK,KAAK,WAAW,IAAI;AACzC,gBAAM,IAAI;AAAA,YACN;AAAA,UACJ;AAAA,QACJ;AAAA,MACJ,OAAO;AAEH,cAAM,IAAI,MAAM,iEAAiE;AAAA,MACrF;AAAA,IACJ;AAGA,WAAO,EAAE,GAAG,MAAM,GAAG,qBAAqB,QAAQ,yBAAyB,EAAE;AAG7E,gBAAY,QAAQ,GAAG;AAGvB,WAAO;AAAA,EACX;AAQA,WAAS,gBAAgB,QAAkB,2BAA2E;AAClH,QAAI,OAAO,EAAE,MAAM,QAAQ;AAG3B,UAAM,gBAAgB,oBAAoB,QAAQ,yBAAyB;AAM3E,QAAI,cAAc,QAAQ;AAEtB,oBACK,OAAO,CAAC,QAAQ,IAAI,SAAS,YAAY,CAAC,IAAI,SAAS,EACvD,QAAQ,MAAM;AACX,cAAM,IAAI,MAAM,kDAAkD;AAAA,MACtE,CAAC;AAGL,UAAI,cAAc,WAAW,GAAG;AAE5B,aAAK,WAAW,cAAc,GAAG;AAGjC,YAAI,KAAK,WAAW,GAAG;AACnB,gBAAM,IAAI,MAAM,iEAAiE;AAAA,QACrF;AAAA,MACJ,WAAW,cAAc,WAAW,GAAG;AAEnC,aAAK,WAAW,CAAC,cAAc,GAAG,OAAiB,cAAc,GAAG,KAAe;AAGnF,YAAI,KAAK,SAAS,KAAK,KAAK,KAAK,SAAS,KAAK,GAAG;AAC9C,gBAAM,IAAI,MAAM,gFAAgF;AAAA,QACpG;AAGA,YAAI,KAAK,SAAS,KAAK,KAAK,SAAS,IAAI;AACrC,gBAAM,IAAI;AAAA,YACN;AAAA,UACJ;AAAA,QACJ;AAAA,MACJ,OAAO;AAEH,cAAM,IAAI,MAAM,8DAA8D;AAAA,MAClF;AAAA,IACJ;AAGA,WAAO,EAAE,GAAG,MAAM,GAAG,qBAAqB,QAAQ,yBAAyB,EAAE;AAG7E,gBAAY,QAAQ,GAAG;AAGvB,WAAO;AAAA,EACX;AAQA,WAAS,mBACL,QACA,2BACsB;AACtB,UAAM,OAAO;AAAA,MACT,MAAM;AAAA,MACN,GAAG,qBAAqB,QAAQ,yBAAyB;AAAA,IAC7D;AAGA,gBAAY,QAAQ,GAAG;AAGvB,WAAO;AAAA,EACX;AAQA,WAAS,mBACL,QACA,2BACsB;AACtB,UAAM,OAAO;AAAA,MACT,MAAM;AAAA,MACN,GAAG,qBAAqB,QAAQ,yBAAyB;AAAA,IAC7D;AAGA,gBAAY,QAAQ,GAAG;AAGvB,WAAO;AAAA,EACX;AAQA,WAAS,mBACL,QACA,2BACsB;AACtB,UAAM,OAAO;AAAA,MACT,MAAM;AAAA,MACN,GAAG,qBAAqB,QAAQ,yBAAyB;AAAA,IAC7D;AAGA,gBAAY,QAAQ,GAAG;AAGvB,WAAO;AAAA,EACX;AAQA,WAAS,gBAAgB,QAAkB,2BAA2E;AAElH,UAAM,gBAAgB,oBAAoB,QAAQ,yBAAyB;AAG3E,kBACK,OAAO,CAAC,QAAQ,IAAI,SAAS,YAAY,CAAC,IAAI,aAAa,IAAI,QAAQ,CAAC,EACxE,QAAQ,MAAM;AACX,YAAM,IAAI,MAAM,6DAA6D;AAAA,IACjF,CAAC;AAEL,UAAM,OAAO;AAAA,MACT,MAAM;AAAA,MACN,SAAS,cAAc,SAAS,cAAc,IAAI,CAAC,EAAE,MAAM,MAAM,KAAK,IAAI;AAAA,MAC1E,GAAG,qBAAqB,QAAQ,yBAAyB;AAAA,IAC7D;AAGA,gBAAY,QAAQ,GAAG;AAGvB,WAAO;AAAA,EACX;AAQA,WAAS,iBACL,QACA,2BACoB;AAGpB,UAAM,CAAC,yBAAyB,iBAAiB,IAAI,oBAAoB,QAAQ,yBAAyB;AAG1G,QAAI,sBAAsB,SAAS,cAAc;AAC7C,YAAM,IAAI,MAAM,0CAA0C;AAAA,IAC9D;AAGA,sBACK,OAAO,CAAC,QAAQ,IAAI,SAAS,YAAY,EACzC,QAAQ,CAAC,QAAQ;AACd,YAAM,IAAI;AAAA,QACN,uCAAuC,IAAI;AAAA,MAC/C;AAAA,IACJ,CAAC;AAGL,WAAO;AAAA,MACH,MAAM;AAAA,MACN,MAAM,qBAAqB;AAAA,MAC3B,MAAM,kBAAkB,IAAI,CAAC,EAAE,MAAM,MAAM,KAAK;AAAA,MAChD,GAAG,qBAAqB,QAAQ,yBAAyB;AAAA,IAC7D;AAAA,EACJ;AAQA,WAAS,oBACL,QACA,2BACuB;AAGvB,UAAM,CAAC,4BAA4B,iBAAiB,IAAI,oBAAoB,QAAQ,yBAAyB;AAG7G,QAAI,yBAAyB,SAAS,cAAc;AAChD,YAAM,IAAI,MAAM,6CAA6C;AAAA,IACjE;AAGA,sBACK,OAAO,CAAC,QAAQ,IAAI,SAAS,YAAY,EACzC,QAAQ,CAAC,QAAQ;AACd,YAAM,IAAI;AAAA,QACN,0CAA0C,IAAI;AAAA,MAClD;AAAA,IACJ,CAAC;AAGL,WAAO;AAAA,MACH,MAAM;AAAA,MACN,MAAM,wBAAwB;AAAA,MAC9B,MAAM,kBAAkB,IAAI,CAAC,EAAE,MAAM,MAAM,KAAK;AAAA,MAChD,GAAG,qBAAqB,QAAQ,yBAAyB;AAAA,IAC7D;AAAA,EACJ;AAQA,WAAS,eAAe,QAAkB,2BAA0E;AAChH,QAAI,OAAO,EAAE,MAAM,OAAO;AAG1B,UAAM,gBAAgB,oBAAoB,QAAQ,yBAAyB;AAM3E,QAAI,cAAc,QAAQ;AAEtB,oBACK,OAAO,CAAC,QAAQ,IAAI,SAAS,YAAY,CAAC,IAAI,SAAS,EACvD,QAAQ,MAAM;AACX,cAAM,IAAI,MAAM,4CAA4C;AAAA,MAChE,CAAC;AAML,UAAI,cAAc,WAAW,GAAG;AAE5B,aAAK,WAAW,cAAc,GAAG;AAGjC,YAAI,KAAK,WAAW,GAAG;AACnB,gBAAM,IAAI,MAAM,2CAA2C;AAAA,QAC/D;AAAA,MACJ,WAAW,cAAc,WAAW,GAAG;AAEnC,aAAK,WAAW,CAAC,cAAc,GAAG,OAAiB,cAAc,GAAG,KAAe;AAGnF,YAAI,KAAK,SAAS,KAAK,KAAK,KAAK,SAAS,KAAK,GAAG;AAC9C,gBAAM,IAAI,MAAM,+DAA+D;AAAA,QACnF;AAGA,YAAI,KAAK,SAAS,KAAK,KAAK,SAAS,IAAI;AACrC,gBAAM,IAAI,MAAM,gFAAgF;AAAA,QACpG;AAAA,MACJ,WAAW,cAAc,SAAS,GAAG;AAEjC,cAAM,IAAI,MAAM,wDAAwD;AAAA,MAC5E;AAAA,IACJ;AAGA,WAAO,EAAE,GAAG,MAAM,GAAG,qBAAqB,QAAQ,yBAAyB,EAAE;AAAA,EACjF;AAQA,WAAS,iBACL,QACA,2BACoB;AAEpB,UAAM,gBAAgB,oBAAoB,QAAQ,yBAAyB;AAG3E,QAAI,cAAc,WAAW,KAAK,cAAc,GAAG,SAAS,cAAc;AACtE,YAAM,IAAI,MAAM,sCAAsC;AAAA,IAC1D;AAGA,WAAO,EAAE,MAAM,UAAU,KAAK,cAAc,GAAG,MAAM;AAAA,EACzD;AAMA,WAAS,mBAAmB,YAAqC;AAE7D,QAAI,gBAAgB,UAAU,KAAK,kBAAkB,WAAW,KAAK,GAAG;AACpE,YAAM,IAAI,MAAM,KAAK,WAAW,iDAAiD;AAAA,IACrF;AAGA,QAAI,gBAAgB,UAAU,KAAK,CAAC,WAAW,UAAU,QAAQ;AAC7D,YAAM,IAAI,MAAM,KAAK,WAAW,0DAA0D;AAAA,IAC9F;AAGA,QAAI,WAAW,SAAS,SAAS;AAE7B,UAAI,OAAO,WAAW,YAAY,aAAa;AAE3C,YAAI,WAAW,QAAQ,WAAW,WAAW,SAAS,QAAQ;AAC1D,gBAAM,IAAI;AAAA,YACN;AAAA,UACJ;AAAA,QACJ;AAAA,MACJ;AAAA,IACJ;AAAA,EACJ;;;AC3tBO,WAAS,mBAAmB,YAA6C;AAE5E,QAAI,eAAe,QAAQ,OAAO,eAAe,aAAa;AAC1D,aAAO,8BAA8B,iCAAiC;AAAA,IAC1E;AAMA,QAAI,OAAO,eAAe,UAAU;AAEhC,aAAO,uBAAuB,UAAU;AAAA,IAC5C,WAAW,OAAO,eAAe,UAAU;AAEvC,aAAO,uBAAuB,UAAU;AAAA,IAC5C,OAAO;AACH,aAAO,8BAA8B,kCAAkC,OAAO,aAAa;AAAA,IAC/F;AAAA,EACJ;AAOA,WAAS,uBAAuB,YAAgD;AAC5E,QAAI;AAGJ,QAAI;AAEA,4BAAsB,kBAAkB,UAAU;AAAA,IACtD,SAAS,WAAP;AAEE,aAAO,8BAA+B,UAAoB,OAAO;AAAA,IACrE;AAGA,UAAM,0BAA0B,oBAAoB,OAAO,CAAC,EAAE,GAAG,MAAM,OAAO,OAAO,WAAW;AAChG,UAAM,yBAAyB,oBAAoB,OAAO,CAAC,EAAE,GAAG,MAAM,OAAO,OAAO,YAAY,GAAG,SAAS,CAAC;AAG7G,QAAI,wBAAwB,WAAW,GAAG;AACtC,aAAO;AAAA,QACH;AAAA,MACJ;AAAA,IACJ;AAGA,UAAM,yBAAmC,CAAC;AAC1C,eAAW,EAAE,GAAG,KAAK,wBAAwB;AAEzC,UAAI,uBAAuB,SAAS,EAAG,GAAG;AACtC,eAAO,8BAA8B,kDAAkD,KAAK;AAAA,MAChG;AAEA,6BAAuB,KAAK,EAAG;AAAA,IACnC;AAEA,QAAI;AAEA,iCAA2B,qBAAqB,KAAK;AAAA,IACzD,SAAS,WAAP;AACE,aAAO,8BAA+B,UAAoB,OAAO;AAAA,IACrE;AAGA,WAAO;AAAA,MACH,WAAW;AAAA,MACX,MAAM;AAAA,IACV;AAAA,EACJ;AAOO,WAAS,uBACZ,YAC0B;AAE1B,UAAM,sBAAsB,MAAM,QAAQ,UAAU,IAAI,aAAa,CAAC,UAAU;AAGhF,QAAI;AACA,0BAAoB,QAAQ,CAAC,uBAAuB,aAAa,oBAAoB,CAAC,CAAC;AAAA,IAC3F,SAAS,OAAP;AAEE,UAAI,iBAAiB,OAAO;AACxB,eAAO,8BAA8B,MAAM,OAAO;AAAA,MACtD;AAGA,aAAO,8BAA8B,qBAAqB,OAAO;AAAA,IACrE;AAGA,UAAM,0BAA0B,oBAAoB,OAAO,CAAC,EAAE,GAAG,MAAM,OAAO,OAAO,WAAW;AAChG,UAAM,yBAAyB,oBAAoB,OAAO,CAAC,EAAE,GAAG,MAAM,OAAO,OAAO,YAAY,GAAG,SAAS,CAAC;AAG7G,QAAI,wBAAwB,WAAW,GAAG;AACtC,aAAO;AAAA,QACH;AAAA,MACJ;AAAA,IACJ;AAGA,UAAM,yBAAmC,CAAC;AAC1C,eAAW,EAAE,GAAG,KAAK,wBAAwB;AAEzC,UAAI,uBAAuB,SAAS,EAAG,GAAG;AACtC,eAAO;AAAA,UACH,oEAAoE;AAAA,QACxE;AAAA,MACJ;AAEA,6BAAuB,KAAK,EAAG;AAAA,IACnC;AAEA,QAAI;AAEA,iCAA2B,qBAAqB,KAAK;AAAA,IACzD,SAAS,WAAP;AACE,aAAO,8BAA+B,UAAoB,OAAO;AAAA,IACrE;AAGA,WAAO;AAAA,MACH,WAAW;AAAA,MACX,MAAM;AAAA,IACV;AAAA,EACJ;AASO,WAAS,2BAA2B,qBAA2C,wBAAiC;AAInH,UAAM,mBAAiE,oBAAoB;AAAA,MACvF,CAAC,wBAAwB;AAAA,QACrB,IAAI,mBAAmB;AAAA,QACvB,MAAM,kBAAkB,kBAAkB,EACrC,OAAO,YAAY,EACnB,IAAI,CAAC,EAAE,IAAI,MAAM,GAAG;AAAA,MAC7B;AAAA,IACJ;AAGA,UAAM,aAAa,CAAC,SAAqD,OAA+B,CAAC,MAAM;AAE3G,UAAI,KAAK,SAAS,QAAQ,EAAE,GAAG;AAE3B,cAAM,UAAU,CAAC,GAAG,MAAM,QAAQ,EAAE;AAGpC,cAAM,mBAAmB,QAAQ,OAAO,CAAC,YAAY,CAAC,CAAC,OAAO,EAAE,KAAK,MAAM;AAG3E,cAAM,IAAI,MAAM,wDAAwD,kBAAkB;AAAA,MAC9F;AAEA,iBAAW,OAAO,QAAQ,MAAM;AAE5B,cAAM,aAAa,iBAAiB,KAAK,CAAC,EAAE,GAAG,MAAM,OAAO,GAAG;AAG/D,YAAI,YAAY;AACZ,qBAAW,YAAY,CAAC,GAAG,MAAM,QAAQ,EAAE,CAAC;AAAA,QAChD,WAAW,wBAAwB;AAE/B,gBAAM,IAAI;AAAA,YACN,QAAQ,KACF,YAAY,QAAQ,kDAAkD,oCACtE,2DAA2D;AAAA,UACrE;AAAA,QACJ;AAAA,MACJ;AAAA,IACJ;AAGA,eAAW,iBAAiB,KAAK,CAAC,YAAY,OAAO,QAAQ,OAAO,WAAW,CAAE;AAAA,EACrF;AAOA,WAAS,aAAa,YAAiB,OAAqB;AAExD,QAAI,OAAO,eAAe,YAAY,OAAO,WAAW,SAAS,YAAY,WAAW,KAAK,WAAW,GAAG;AACvG,YAAM,IAAI;AAAA,QACN,2FAA2F;AAAA,MAC/F;AAAA,IACJ;AAGA,YAAQ,WAAW,MAAM;AAAA,MACrB,KAAK;AACD,2BAAmB,YAAY,KAAK;AACpC;AAAA,MAEJ,KAAK;AACD,8BAAsB,YAAY,KAAK;AACvC;AAAA,MAEJ,KAAK;AACD,yBAAiB,YAAY,KAAK;AAClC;AAAA,MAEJ,KAAK;AACD,2BAAmB,YAAY,KAAK;AACpC;AAAA,MAEJ,KAAK;AACD,yBAAiB,YAAY,KAAK;AAClC;AAAA,MAEJ,KAAK;AACD,4BAAoB,YAAY,KAAK;AACrC;AAAA,MAEJ,KAAK;AACD,yBAAiB,YAAY,KAAK;AAClC;AAAA,MAEJ,KAAK;AACD,yBAAiB,YAAY,KAAK;AAClC;AAAA,MAEJ,KAAK;AACD,2BAAmB,YAAY,KAAK;AACpC;AAAA,MAEJ,KAAK;AACD,0BAAkB,YAAY,KAAK;AACnC;AAAA,MAEJ,KAAK;AACD,6BAAqB,YAAY,KAAK;AACtC;AAAA,MAEJ,KAAK;AACD,6BAAqB,YAAY,KAAK;AACtC;AAAA,MAEJ,KAAK;AACD,6BAAqB,YAAY,KAAK;AACtC;AAAA,MAEJ,KAAK;AACD,0BAAkB,YAAY,KAAK;AACnC;AAAA,MAEJ;AACI,cAAM,IAAI,MAAM,4BAA4B,WAAW,mBAAmB,QAAQ;AAAA,IAC1F;AAAA,EACJ;AAOA,WAAS,uBAAuB,YAAiB,OAAqB;AAElE,KAAC,SAAS,SAAS,SAAS,QAAQ,MAAM,EAAE,QAAQ,CAAC,kBAAkB;AAEnE,YAAM,sBAAsB,WAAW;AAGvC,UAAI,OAAO,wBAAwB,aAAa;AAC5C;AAAA,MACJ;AAGA,UAAI,OAAO,wBAAwB,UAAU;AACzC,cAAM,IAAI;AAAA,UACN,uBAAuB,uCAAuC,WAAW,wBAAwB;AAAA,QACrG;AAAA,MACJ;AAGA,UAAI,OAAO,oBAAoB,SAAS,YAAY,oBAAoB,KAAK,WAAW,GAAG;AACvF,cAAM,IAAI;AAAA,UACN,2CAA2C,gDAAgD,WAAW,wBAAwB;AAAA,QAClI;AAAA,MACJ;AAGA,UAAI,OAAO,oBAAoB,SAAS,eAAe,CAAC,MAAM,QAAQ,oBAAoB,IAAI,GAAG;AAC7F,cAAM,IAAI;AAAA,UACN,2CAA2C,sCAAsC,WAAW,wBAAwB;AAAA,QACxH;AAAA,MACJ;AAAA,IACJ,CAAC;AAAA,EACL;AAOA,WAAS,iBAAiB,YAAiB,OAAqB;AAE5D,QAAI,WAAW,SAAS,QAAQ;AAC5B,YAAM,IAAI,MAAM,4CAA4C;AAAA,IAChE;AAGA,QAAI,QAAQ,GAAG;AACX,YAAM,IAAI,MAAM,iDAAiD;AAAA,IACrE;AAGA,QAAI,OAAO,WAAW,OAAO,gBAAgB,OAAO,WAAW,OAAO,YAAY,WAAW,GAAG,WAAW,IAAI;AAC3G,YAAM,IAAI,MAAM,sEAAsE;AAAA,IAC1F;AAGA,QAAI,OAAO,WAAW,UAAU,aAAa;AACzC,YAAM,IAAI,MAAM,uDAAuD;AAAA,IAC3E;AAGA,2BAAuB,YAAY,KAAK;AAGxC,iBAAa,WAAW,OAAO,QAAQ,CAAC;AAAA,EAC5C;AAOA,WAAS,oBAAoB,YAAiB,OAAqB;AAE/D,QAAI,WAAW,SAAS,WAAW;AAC/B,YAAM,IAAI,MAAM,8DAA8D,QAAQ;AAAA,IAC1F;AAGA,QAAI,OAAO,WAAW,UAAU,aAAa;AACzC,YAAM,IAAI,MAAM,sEAAsE,QAAQ;AAAA,IAClG;AAGA,2BAAuB,YAAY,KAAK;AAGxC,iBAAa,WAAW,OAAO,QAAQ,CAAC;AAAA,EAC5C;AAOA,WAAS,iBAAiB,YAAiB,OAAqB;AAE5D,QAAI,WAAW,SAAS,QAAQ;AAC5B,YAAM,IAAI,MAAM,wDAAwD,QAAQ;AAAA,IACpF;AAGA,QAAI,OAAO,WAAW,UAAU,aAAa;AACzC,YAAM,IAAI,MAAM,mEAAmE,QAAQ;AAAA,IAC/F;AAGA,2BAAuB,YAAY,KAAK;AAGxC,iBAAa,WAAW,OAAO,QAAQ,CAAC;AAAA,EAC5C;AAOA,WAAS,iBAAiB,YAAiB,OAAqB;AAE5D,QAAI,WAAW,SAAS,QAAQ;AAC5B,YAAM,IAAI,MAAM,wDAAwD,QAAQ;AAAA,IACpF;AAGA,QAAI,OAAO,WAAW,UAAU,aAAa;AACzC,YAAM,IAAI,MAAM,mEAAmE,QAAQ;AAAA,IAC/F;AAGA,2BAAuB,YAAY,KAAK;AAGxC,iBAAa,WAAW,OAAO,QAAQ,CAAC;AAAA,EAC5C;AAOA,WAAS,mBAAmB,YAAiB,OAAqB;AAE9D,QAAI,WAAW,SAAS,UAAU;AAC9B,YAAM,IAAI,MAAM,4DAA4D,QAAQ;AAAA,IACxF;AAGA,QAAI,OAAO,WAAW,UAAU,aAAa;AACzC,YAAM,IAAI,MAAM,qEAAqE,QAAQ;AAAA,IACjG;AAGA,QAAI,OAAO,WAAW,eAAe,aAAa;AAC9C,UAAI,MAAM,QAAQ,WAAW,UAAU,GAAG;AAEtC,cAAM,qBAAqB,CAAC,CAAC,WAAW,WAAW,OAAO,CAAC,UAAmB,CAAC,UAAU,KAAK,CAAC,EAAE;AAGjG,YAAI,WAAW,WAAW,WAAW,KAAK,oBAAoB;AAC1D,gBAAM,IAAI;AAAA,YACN,+GAA+G;AAAA,UACnH;AAAA,QACJ;AAGA,YAAI,WAAW,WAAW,KAAK,KAAK,WAAW,WAAW,KAAK,GAAG;AAC9D,gBAAM,IAAI;AAAA,YACN,yHAAyH;AAAA,UAC7H;AAAA,QACJ;AAGA,YAAI,WAAW,WAAW,KAAK,WAAW,WAAW,IAAI;AACrD,gBAAM,IAAI;AAAA,YACN,sJAAsJ;AAAA,UAC1J;AAAA,QACJ;AAAA,MACJ,WAAW,UAAU,WAAW,UAAU,GAAG;AAEzC,YAAI,WAAW,aAAa,GAAG;AAC3B,gBAAM,IAAI;AAAA,YACN,qGAAqG;AAAA,UACzG;AAAA,QACJ;AAAA,MACJ,OAAO;AACH,cAAM,IAAI;AAAA,UACN,gIAAgI;AAAA,QACpI;AAAA,MACJ;AAAA,IACJ;AAGA,2BAAuB,YAAY,KAAK;AAGxC,iBAAa,WAAW,OAAO,QAAQ,CAAC;AAAA,EAC5C;AAOA,WAAS,kBAAkB,YAAiB,OAAqB;AAE7D,QAAI,WAAW,SAAS,SAAS;AAC7B,YAAM,IAAI,MAAM,0DAA0D,QAAQ;AAAA,IACtF;AAGA,QAAI,OAAO,WAAW,UAAU,aAAa;AACzC,YAAM,IAAI,MAAM,oEAAoE,QAAQ;AAAA,IAChG;AAGA,QAAI,OAAO,WAAW,aAAa,aAAa;AAC5C,UAAI,MAAM,QAAQ,WAAW,QAAQ,GAAG;AAEpC,cAAM,qBAAqB,CAAC,CAAC,WAAW,SAAS,OAAO,CAAC,UAAmB,CAAC,UAAU,KAAK,CAAC,EAAE;AAG/F,YAAI,WAAW,SAAS,WAAW,KAAK,oBAAoB;AACxD,gBAAM,IAAI;AAAA,YACN,4GAA4G;AAAA,UAChH;AAAA,QACJ;AAGA,YAAI,WAAW,SAAS,KAAK,KAAK,WAAW,SAAS,KAAK,GAAG;AAC1D,gBAAM,IAAI;AAAA,YACN,oHAAoH;AAAA,UACxH;AAAA,QACJ;AAGA,YAAI,WAAW,SAAS,KAAK,WAAW,SAAS,IAAI;AACjD,gBAAM,IAAI;AAAA,YACN,+IAA+I;AAAA,UACnJ;AAAA,QACJ;AAAA,MACJ,WAAW,UAAU,WAAW,QAAQ,GAAG;AAEvC,YAAI,WAAW,WAAW,GAAG;AACzB,gBAAM,IAAI;AAAA,YACN,gGAAgG;AAAA,UACpG;AAAA,QACJ;AAAA,MACJ,OAAO;AACH,cAAM,IAAI;AAAA,UACN,6HAA6H;AAAA,QACjI;AAAA,MACJ;AAAA,IACJ;AAGA,2BAAuB,YAAY,KAAK;AAGxC,iBAAa,WAAW,OAAO,QAAQ,CAAC;AAAA,EAC5C;AAOA,WAAS,mBAAmB,YAAiB,OAAqB;AAE9D,QAAI,WAAW,SAAS,UAAU;AAC9B,YAAM,IAAI,MAAM,4DAA4D,QAAQ;AAAA,IACxF;AAGA,QAAI,OAAO,WAAW,QAAQ,YAAY,WAAW,IAAI,WAAW,GAAG;AACnE,YAAM,IAAI,MAAM,0EAA0E,QAAQ;AAAA,IACtG;AAGA,KAAC,SAAS,OAAO,EAAE,QAAQ,CAAC,kBAAkB;AAC1C,UAAI,OAAO,WAAW,mBAAmB,aAAa;AAClD,cAAM,IAAI;AAAA,UACN,4DAA4D,wDAAwD;AAAA,QACxH;AAAA,MACJ;AAAA,IACJ,CAAC;AAGD,KAAC,SAAS,QAAQ,MAAM,EAAE,QAAQ,CAAC,kBAAkB;AACjD,UAAI,OAAO,WAAW,mBAAmB,aAAa;AAClD,cAAM,IAAI;AAAA,UACN,kEAAkE,wDAAwD;AAAA,QAC9H;AAAA,MACJ;AAAA,IACJ,CAAC;AAAA,EACL;AAOA,WAAS,mBAAmB,YAAiB,OAAqB;AAE9D,QAAI,WAAW,SAAS,UAAU;AAC9B,YAAM,IAAI,MAAM,4DAA4D,QAAQ;AAAA,IACxF;AAGA,QAAI,OAAO,WAAW,SAAS,YAAY,WAAW,KAAK,WAAW,GAAG;AACrE,YAAM,IAAI,MAAM,0EAA0E,QAAQ;AAAA,IACtG;AAGA,QAAI,OAAO,WAAW,SAAS,eAAe,CAAC,MAAM,QAAQ,WAAW,IAAI,GAAG;AAC3E,YAAM,IAAI,MAAM,2EAA2E,QAAQ;AAAA,IACvG;AAGA,2BAAuB,YAAY,KAAK;AAAA,EAC5C;AAOA,WAAS,sBAAsB,YAAiB,OAAqB;AAEjE,QAAI,WAAW,SAAS,aAAa;AACjC,YAAM,IAAI,MAAM,kEAAkE,QAAQ;AAAA,IAC9F;AAGA,QAAI,OAAO,WAAW,SAAS,YAAY,WAAW,KAAK,WAAW,GAAG;AACrE,YAAM,IAAI,MAAM,6EAA6E,QAAQ;AAAA,IACzG;AAGA,QAAI,OAAO,WAAW,SAAS,eAAe,CAAC,MAAM,QAAQ,WAAW,IAAI,GAAG;AAC3E,YAAM,IAAI,MAAM,8EAA8E,QAAQ;AAAA,IAC1G;AAGA,2BAAuB,YAAY,KAAK;AAAA,EAC5C;AAOA,WAAS,iBAAiB,YAAiB,OAAqB;AAE5D,QAAI,WAAW,SAAS,QAAQ;AAC5B,YAAM,IAAI,MAAM,wDAAwD,QAAQ;AAAA,IACpF;AAGA,QAAI,OAAO,WAAW,aAAa,aAAa;AAC5C,UAAI,MAAM,QAAQ,WAAW,QAAQ,GAAG;AAEpC,cAAM,qBAAqB,CAAC,CAAC,WAAW,SAAS,OAAO,CAAC,UAAmB,CAAC,UAAU,KAAK,CAAC,EAAE;AAG/F,YAAI,WAAW,SAAS,WAAW,KAAK,oBAAoB;AACxD,gBAAM,IAAI;AAAA,YACN,2GAA2G;AAAA,UAC/G;AAAA,QACJ;AAGA,YAAI,WAAW,SAAS,KAAK,KAAK,WAAW,SAAS,KAAK,GAAG;AAC1D,gBAAM,IAAI;AAAA,YACN,6GAA6G;AAAA,UACjH;AAAA,QACJ;AAGA,YAAI,WAAW,SAAS,KAAK,WAAW,SAAS,IAAI;AACjD,gBAAM,IAAI;AAAA,YACN,8IAA8I;AAAA,UAClJ;AAAA,QACJ;AAAA,MACJ,WAAW,UAAU,WAAW,QAAQ,GAAG;AAEvC,YAAI,WAAW,WAAW,GAAG;AACzB,gBAAM,IAAI;AAAA,YACN,+FAA+F;AAAA,UACnG;AAAA,QACJ;AAAA,MACJ,OAAO;AACH,cAAM,IAAI;AAAA,UACN,4HAA4H;AAAA,QAChI;AAAA,MACJ;AAAA,IACJ;AAGA,2BAAuB,YAAY,KAAK;AAAA,EAC5C;AAOA,WAAS,qBAAqB,YAAiB,OAAqB;AAEhE,QAAI,WAAW,SAAS,YAAY;AAChC,YAAM,IAAI,MAAM,gEAAgE,QAAQ;AAAA,IAC5F;AAGA,QAAI,CAAC,MAAM,QAAQ,WAAW,QAAQ,KAAK,WAAW,SAAS,WAAW,GAAG;AACzE,YAAM,IAAI,MAAM,iFAAiF,QAAQ;AAAA,IAC7G;AAGA,2BAAuB,YAAY,KAAK;AAGxC,eAAW,SAAS,QAAQ,CAAC,UAAe,aAAa,OAAO,QAAQ,CAAC,CAAC;AAAA,EAC9E;AAOA,WAAS,qBAAqB,YAAiB,OAAqB;AAEhE,QAAI,WAAW,SAAS,YAAY;AAChC,YAAM,IAAI,MAAM,gEAAgE,QAAQ;AAAA,IAC5F;AAGA,QAAI,CAAC,MAAM,QAAQ,WAAW,QAAQ,KAAK,WAAW,SAAS,WAAW,GAAG;AACzE,YAAM,IAAI,MAAM,iFAAiF,QAAQ;AAAA,IAC7G;AAGA,2BAAuB,YAAY,KAAK;AAGxC,eAAW,SAAS,QAAQ,CAAC,UAAe,aAAa,OAAO,QAAQ,CAAC,CAAC;AAAA,EAC9E;AAOA,WAAS,qBAAqB,YAAiB,OAAqB;AAEhE,QAAI,WAAW,SAAS,YAAY;AAChC,YAAM,IAAI,MAAM,gEAAgE,QAAQ;AAAA,IAC5F;AAGA,QAAI,CAAC,MAAM,QAAQ,WAAW,QAAQ,KAAK,WAAW,SAAS,WAAW,GAAG;AACzE,YAAM,IAAI,MAAM,iFAAiF,QAAQ;AAAA,IAC7G;AAGA,2BAAuB,YAAY,KAAK;AAGxC,eAAW,SAAS,QAAQ,CAAC,UAAe,aAAa,OAAO,QAAQ,CAAC,CAAC;AAAA,EAC9E;AAOA,WAAS,kBAAkB,YAAiB,OAAqB;AAE7D,QAAI,WAAW,SAAS,SAAS;AAC7B,YAAM,IAAI,MAAM,0DAA0D,QAAQ;AAAA,IACtF;AAGA,QAAI,CAAC,MAAM,QAAQ,WAAW,QAAQ,KAAK,WAAW,SAAS,WAAW,GAAG;AACzE,YAAM,IAAI,MAAM,8EAA8E,QAAQ;AAAA,IAC1G;AAGA,QAAI,OAAO,WAAW,YAAY,aAAa;AAE3C,UACI,CAAC,MAAM,QAAQ,WAAW,OAAO,KACjC,WAAW,QAAQ,WAAW,WAAW,SAAS,UAClD,WAAW,QAAQ,OAAO,CAAC,UAAmB,CAAC,UAAU,KAAK,CAAC,EAAE,UACjE,WAAW,QAAQ,OAAO,CAAC,UAAkB,QAAQ,CAAC,EAAE,QAC1D;AACE,cAAM,IAAI;AAAA,UACN,mKAAmK;AAAA,QACvK;AAAA,MACJ;AAAA,IACJ;AAGA,2BAAuB,YAAY,KAAK;AAGxC,eAAW,SAAS,QAAQ,CAAC,UAAe,aAAa,OAAO,QAAQ,CAAC,CAAC;AAAA,EAC9E;AAOA,WAAS,8BAA8B,cAAkD;AACrF,WAAO,EAAE,WAAW,OAAO,aAAa;AAAA,EAC5C;;;ACxyBA,MAAqB,SAArB,MAA4B;AAAA,IAexB,OAAc,QAAQ,MAA8B;AAChD,aAAO,KAAK,cAAc;AAAA,IAC9B;AAAA,IAOA,OAAc,QAAQ,MAAc,MAA4B;AAC5D,WAAK,cAAc,QAAQ;AAAA,IAC/B;AAAA,IAUA,OAAO,eAAe,OAAc,MAAsC;AAEtE,YAAM,eAAe,MAAM;AAC3B,UAAI,gBAAgB,OAAO,iBAAiB,YAAY;AACpD,eAAO,CAAC,SAAwC,aAAa,MAAM,OAAO,IAAI;AAAA,MAClF;AAGA,UAAI,KAAK,cAAc,SAAS,OAAO,KAAK,cAAc,UAAU,YAAY;AAC5E,eAAO,CAAC,SAAgB,KAAK,cAAc,MAAM,OAAO,GAAG,KAAK,IAAI,CAAC,QAAQ,IAAI,KAAK,CAAC;AAAA,MAC3F;AAGA,aAAO;AAAA,IACX;AAAA,IAKA,OAAO,cAAqD;AACxD,aAAO,KAAK;AAAA,IAChB;AAAA,IAOA,OAAO,WAAW,MAAc,SAA6B;AACzD,WAAK,aAAa,QAAQ;AAAA,IAC9B;AAAA,IAMA,OAAO,OAAO,MAAc;AACxB,aAAO,KAAK,cAAc;AAC1B,aAAO,KAAK,aAAa;AAAA,IAC7B;AAAA,IAKA,OAAO,QAAQ;AACX,WAAK,gBAAgB,CAAC;AACtB,WAAK,eAAe,CAAC;AAAA,IACzB;AAAA,EACJ;AAhFI,gBAJiB,QAIF,iBAAmD,CAAC;AAInE,gBARiB,QAQF,gBAAsD,CAAC;;;ACX1E,MAAqB,4BAArB,cAAuD,MAAM;AAAA,IAIzD,YAAoB,QAAc;AAC9B,YAAM,mCAAmC;AADzB;AAAA,IAEpB;AAAA,IAOA,eAAe,CAAC,SAAe,SAAS,KAAK;AAAA,EACjD;;;ACNA,MAAqB,YAArB,MAA+B;AAAA,IAI3B,YAAoB,OAAwB;AAAxB;AAAA,IAAyB;AAAA,IAO7C,WAAW,CAAC,UAAiB;AAEzB,iBAAW,WAAW,KAAK,OAAO;AAE9B,mBAAW,SAAS,QAAQ,QAAQ;AAEhC,cAAI,CAAC,MAAM,YAAY,KAAK,GAAG;AAC3B,kBAAM,IAAI,0BAA0B,QAAQ,IAAI;AAAA,UACpD;AAAA,QACJ;AAAA,MACJ;AAAA,IACJ;AAAA,EACJ;;;ACrBA,MAA8B,OAA9B,MAAmC;AAAA,IAmB/B,YAAoB,MAAsB,YAAiC,MAAa;AAApE;AAAsB;AAAiC;AAAA,IAAc;AAAA,IAfxE,MAAc,cAAc;AAAA,IAIrC;AAAA,IAIA;AAAA,IA6BR,WAAW,MAAgB,KAAK;AAAA,IAChC,WAAW,CAAC,UAA0B;AAClC,WAAK,QAAQ;AAAA,IACjB;AAAA,IAKA,SAAS,MAAM,KAAK;AAAA,IAKpB,UAAU,MAAM,KAAK;AAAA,IAKrB,gBAAgB,MAAM,KAAK;AAAA,IAK3B,eAAe,MAAM,KAAK;AAAA,IAQ1B,aAAa,MAAyB;AAClC,aACI,KAAK,cAAc,EAAE,OAAO,CAAC,cAAc,UAAU,KAAK,YAAY,MAAM,KAAK,YAAY,CAAC,EAAE,MAAM;AAAA,IAE9G;AAAA,IAKA,qBAAqB,MAAe,KAAK,cAAc,EAAE,OAAO,CAAC,cAAc,UAAU,QAAQ,CAAC;AAAA,IAKlG,eAAe,CAAC,UAAsB,KAAK,YAAY;AAAA,IAKvD,eAAe,MAAM,CAAC,CAAC,KAAK;AAAA,IAMrB,GAAG,OAA0B;AAChC,aAAO,KAAK,UAAU;AAAA,IAC1B;AAAA,IAKO,QAAc;AACjB,WAAK,wCAAoB;AAAA,IAC7B;AAAA,IAMO,MAAM,OAAoB;AAE7B,UAAI,CAAC,KAAK,sCAAgB,GAAG;AACzB;AAAA,MACJ;AAGA,WAAK,MAAM;AAEX,WAAK,aAAa,MAAM,GAAG,kBAAkB,OAAO,OAAO,IAAI;AAAA,IACnE;AAAA,IAQO,OAAO,OAAc,SAAqC;AAE7D,UAAI,KAAK,0CAAkB,KAAK,KAAK,oCAAe,GAAG;AACnD;AAAA,MACJ;AAEA,UAAI;AAEA,aAAK,UAAW,SAAS,KAAK;AAG9B,YAAI,KAAK,kCAAc,GAAG;AACtB,eAAK,aAAa,OAAO,GAAG,kBAAkB,KAAK;AAAA,QACvD;AAEA,aAAK,aAAa,MAAM,GAAG,kBAAkB,KAAK;AAGlD,aAAK,SAAS,OAAO,OAAO;AAG5B,YAAI,KAAK,0CAAkB,KAAK,KAAK,oCAAe,GAAG;AACnD,eAAK,aAAa,MAAM,GAAG,kBAAkB,OAAO,KAAK,0CAAkB,GAAG,KAAK;AAAA,QACvF;AAAA,MACJ,SAAS,OAAP;AAEE,YAAI,iBAAiB,6BAA6B,MAAM,aAAa,IAAI,GAAG;AAExE,eAAK,MAAM,KAAK;AAGhB,eAAK,0CAAqB;AAAA,QAC9B,OAAO;AACH,gBAAM;AAAA,QACV;AAAA,MACJ;AAAA,IACJ;AAAA,EACJ;AAMA,WAAS,gBAAwB;AAC7B,QAAI,KAAK,WAAY;AACjB,eAAU,IAAI,KAAK,OAAO,KAAK,QAAW,GAAG,SAAS,EAAE,EAAE,UAAU,CAAC;AAAA,IACzE;AACA,WAAO,GAAG,IAAI,GAAG,IAAI,MAAM,GAAG,IAAI,MAAM,GAAG,IAAI,MAAM,GAAG,IAAI,MAAM,GAAG,IAAI,GAAG,IAAI,GAAG;AAAA,EACvF;;;ACzLA,MAA8B,YAA9B,cAAgD,KAAK;AAAA,IAMjD,YAAY,MAAc,YAAmC,UAAkB;AAC3E,YAAM,MAAM,YAAY,CAAC,CAAC;AAD+B;AAAA,IAE7D;AAAA,IAKA,aAAa,MAAM;AAAA,IAKnB,cAAc,MAAM,KAAK;AAAA,IAKzB,QAAQ,MAAM;AAEV,WAAK,wCAAoB;AAGzB,WAAK,YAAY,EAAE,QAAQ,CAAC,UAAU,MAAM,MAAM,CAAC;AAAA,IACvD;AAAA,IAMA,QAAQ,CAAC,UAAiB;AAEtB,UAAI,CAAC,KAAK,sCAAgB,GAAG;AACzB;AAAA,MACJ;AAGA,WAAK,YAAY,EAAE,QAAQ,CAAC,UAAU,MAAM,MAAM,KAAK,CAAC;AAGxD,WAAK,MAAM;AAEX,WAAK,aAAa,MAAM,GAAG,kBAAkB,OAAO,OAAO,IAAI;AAAA,IACnE;AAAA,EACJ;;;AC9CA,MAAqB,WAArB,cAAsC,UAAU;AAAA,IAK5C,YAAY,YAAyB,UAAkB;AACnD,YAAM,YAAY,YAAY,QAAQ;AAAA,IAC1C;AAAA,IAOU,SAAS,OAAc,SAAqC;AAElE,UAAI,iBAAiB;AAErB,UAAI,iBAAiB;AAGrB,iBAAW,SAAS,KAAK,UAAU;AAE/B,YAAI,MAAM,SAAS,yCAAqB,MAAM,SAAS,2CAAqB;AAExE,gBAAM,OAAO,OAAO,OAAO;AAAA,QAC/B;AAGA,YAAI,MAAM,SAAS,+CAAuB;AAEtC;AAGA;AAAA,QACJ;AAGA,YAAI,MAAM,SAAS,yCAAoB;AACnC,2BAAiB;AAGjB;AAAA,QACJ;AAGA,YAAI,MAAM,SAAS,2CAAqB;AAEpC,gBAAM,IAAI,MAAM,0CAA0C;AAAA,QAC9D;AAAA,MACJ;AAEA,UAAI,gBAAgB;AAEhB,aAAK,0CAAqB;AAG1B,mBAAW,SAAS,KAAK,UAAU;AAC/B,cAAI,MAAM,SAAS,2CAAqB;AACpC,kBAAM,MAAM,KAAK;AAAA,UACrB;AAAA,QACJ;AAAA,MACJ,OAAO;AAEH,aAAK,SAAS,mBAAmB,KAAK,SAAS,sFAAwC;AAAA,MAC3F;AAAA,IACJ;AAAA,IAKA,UAAU,MAAM;AAAA,EACpB;;;ACxEA,MAAqB,WAArB,cAAsC,UAAU;AAAA,IAK5C,YAAY,YAAmC,UAAkB;AAC7D,YAAM,YAAY,YAAY,QAAQ;AADK;AAAA,IAE/C;AAAA,IAOU,SAAS,OAAc,SAAqC;AAElE,iBAAW,SAAS,KAAK,UAAU;AAE/B,YAAI,MAAM,SAAS,yCAAqB,MAAM,SAAS,2CAAqB;AAExE,gBAAM,OAAO,OAAO,OAAO;AAAA,QAC/B;AAGA,YAAI,MAAM,SAAS,+CAAuB;AAEtC,eAAK,gDAAwB;AAG7B;AAAA,QACJ;AAGA,YAAI,MAAM,SAAS,yCAAoB;AAGnC,cAAI,KAAK,SAAS,QAAQ,KAAK,MAAM,KAAK,SAAS,SAAS,GAAG;AAE3D,iBAAK,0CAAqB;AAG1B;AAAA,UACJ,OAAO;AAEH;AAAA,UACJ;AAAA,QACJ;AAGA,YAAI,MAAM,SAAS,2CAAqB;AAEpC,eAAK,4CAAsB;AAG3B;AAAA,QACJ;AAGA,cAAM,IAAI,MAAM,0CAA0C;AAAA,MAC9D;AAAA,IACJ;AAAA,IAKA,UAAU,MAAM;AAAA,EACpB;;;AClEA,MAAqB,WAArB,cAAsC,UAAU;AAAA,IAK5C,YAAY,YAAmC,UAAkB;AAC7D,YAAM,YAAY,YAAY,QAAQ;AADK;AAAA,IAE/C;AAAA,IAOU,SAAS,OAAc,SAAqC;AAElE,iBAAW,SAAS,KAAK,UAAU;AAE/B,YAAI,MAAM,SAAS,yCAAqB,MAAM,SAAS,2CAAqB;AAExE,gBAAM,OAAO,OAAO,OAAO;AAAA,QAC/B;AAGA,YAAI,MAAM,SAAS,+CAAuB;AAGtC,cAAI,KAAK,SAAS,QAAQ,KAAK,MAAM,KAAK,SAAS,SAAS,GAAG;AAE3D,iBAAK,gDAAwB;AAG7B;AAAA,UACJ,OAAO;AAEH;AAAA,UACJ;AAAA,QACJ;AAGA,YAAI,MAAM,SAAS,yCAAoB;AAEnC,eAAK,0CAAqB;AAG1B;AAAA,QACJ;AAGA,YAAI,MAAM,SAAS,2CAAqB;AAEpC,eAAK,4CAAsB;AAG3B;AAAA,QACJ;AAGA,cAAM,IAAI,MAAM,0CAA0C;AAAA,MAC9D;AAAA,IACJ;AAAA,IAKA,UAAU,MAAM;AAAA,EACpB;;;AC7EA,0BAAwB;AAcxB,MAAqB,QAArB,cAAmC,UAAU;AAAA,IAMzC,YAAY,YAAiC,SAA+B,UAAkB;AAC1F,YAAM,SAAS,YAAY,QAAQ;AADM;AAAA,IAE7C;AAAA,IAKQ;AAAA,IAOE,SAAS,OAAc,SAAqC;AAElE,UAAI,KAAK,kCAAc,GAAG;AAEtB,cAAM,gBAAY,kBAAAC,SAAkB;AAAA,UAEhC,QAAQ,QAAQ;AAAA,UAEhB,cAAc,KAAK,SAAS,IAAI,CAAC,OAAO,UAAU,CAAC,OAAO,KAAK,UAAU,UAAU,CAAC,CAAC;AAAA,QACzF,CAAC;AAGD,aAAK,gBAAgB,UAAU,KAAK,KAAK;AAAA,MAC7C;AAGA,UAAI,CAAC,KAAK,eAAe;AACrB,cAAM,IAAI,MAAM,uDAAuD;AAAA,MAC3E;AAGA,UAAI,KAAK,cAAc,SAAS,yCAAqB,KAAK,cAAc,SAAS,2CAAqB;AAClG,aAAK,cAAc,OAAO,OAAO,OAAO;AAAA,MAC5C;AAGA,WAAK,SAAS,KAAK,cAAc,SAAS,CAAC;AAAA,IAC/C;AAAA,IAKA,UAAU,MAAO,KAAK,UAAU,UAAU,KAAK,QAAQ,KAAK,GAAG,OAAO;AAAA,EAC1E;;;AC3DA,MAA8B,YAA9B,cAAgD,KAAK;AAAA,IAMjD,YAAY,MAAc,YAAmC,OAAa;AACtE,YAAM,MAAM,YAAY,CAAC,CAAC;AAD+B;AAAA,IAE7D;AAAA,IAKA,aAAa,MAAM;AAAA,IAKnB,cAAc,MAAM,CAAC,KAAK,KAAK;AAAA,IAK/B,QAAQ,MAAM;AAEV,WAAK,wCAAoB;AAGzB,WAAK,MAAM,MAAM;AAAA,IACrB;AAAA,IAMA,QAAQ,CAAC,UAAiB;AAEtB,UAAI,CAAC,KAAK,sCAAgB,GAAG;AACzB;AAAA,MACJ;AAGA,WAAK,MAAM,MAAM,KAAK;AAGtB,WAAK,MAAM;AAEX,WAAK,aAAa,MAAM,GAAG,kBAAkB,OAAO,OAAO,IAAI;AAAA,IACnE;AAAA,EACJ;;;AC9CA,MAAqB,OAArB,cAAkC,UAAU;AAAA,IAKxC,YAAY,YAAyB,OAAa;AAC9C,YAAM,QAAQ,YAAY,KAAK;AAAA,IACnC;AAAA,IAOU,SAAS,OAAc,SAAqC;AAElE,UAAI,KAAK,MAAM,SAAS,yCAAqB,KAAK,MAAM,SAAS,2CAAqB;AAClF,aAAK,MAAM,OAAO,OAAO,OAAO;AAAA,MACpC;AAGA,cAAQ,KAAK,MAAM,SAAS,GAAG;AAAA,QAC3B;AACI,eAAK,4CAAsB;AAC3B;AAAA,QAEJ;AAAA,QACA;AACI,eAAK,0CAAqB;AAC1B;AAAA,QAEJ;AACI,eAAK,wCAAoB;AAAA,MACjC;AAAA,IACJ;AAAA,IAKA,UAAU,MAAM;AAAA,EACpB;;;ACxCA,MAAqB,OAArB,cAAkC,UAAU;AAAA,IAKxC,YAAY,YAAyB,OAAa;AAC9C,YAAM,QAAQ,YAAY,KAAK;AAAA,IACnC;AAAA,IAOU,SAAS,OAAc,SAAqC;AAElE,UAAI,KAAK,MAAM,SAAS,yCAAqB,KAAK,MAAM,SAAS,2CAAqB;AAClF,aAAK,MAAM,OAAO,OAAO,OAAO;AAAA,MACpC;AAGA,cAAQ,KAAK,MAAM,SAAS,GAAG;AAAA,QAC3B;AACI,eAAK,4CAAsB;AAC3B;AAAA,QAEJ;AACI,eAAK,0CAAqB;AAC1B;AAAA,QAEJ;AACI,eAAK,gDAAwB;AAC7B;AAAA,QAEJ;AACI,eAAK,wCAAoB;AAAA,MACjC;AAAA,IACJ;AAAA,IAKA,UAAU,MAAM;AAAA,EACpB;;;ACvCA,MAAqB,SAArB,cAAoC,UAAU;AAAA,IAQ1C,YACI,YACQ,YACA,eACA,eACR,OACF;AACE,YAAM,UAAU,YAAY,KAAK;AALzB;AACA;AACA;AAAA,IAIZ;AAAA,IAKQ,uBAAsC;AAAA,IAKtC,wBAAgC;AAAA,IAO9B,SAAS,OAAc,SAAqC;AAElE,UAAI,KAAK,kCAAc,GAAG;AAEtB,aAAK,MAAM,MAAM;AAGjB,aAAK,wBAAwB;AAG7B,aAAK,wBAAwB,OAAO;AAAA,MACxC;AAIA,UAAI,KAAK,WAAW,GAAG;AAEnB,aAAK,4CAAsB;AAI3B,YAAI,KAAK,MAAM,SAAS,+CAAuB;AAC3C,eAAK,MAAM,MAAM;AAAA,QACrB;AAGA,aAAK,MAAM,OAAO,OAAO,OAAO;AAIhC,YAAI,KAAK,MAAM,SAAS,yCAAoB;AAExC,eAAK,0CAAqB;AAE1B;AAAA,QACJ,WAAW,KAAK,MAAM,SAAS,+CAAuB;AAElD,eAAK,yBAAyB;AAAA,QAClC;AAAA,MACJ,OAAO;AAEH,aAAK,gDAAwB;AAAA,MACjC;AAAA,IACJ;AAAA,IAKA,UAAU,MAAM;AACZ,UAAI,KAAK,eAAe,MAAM;AAC1B,eAAO,UAAU,KAAK;AAAA,MAC1B,WAAW,KAAK,kBAAkB,QAAQ,KAAK,kBAAkB,MAAM;AACnE,eAAO,UAAU,KAAK,kBAAkB,KAAK;AAAA,MACjD,OAAO;AACH,eAAO;AAAA,MACX;AAAA,IACJ;AAAA,IAKA,QAAQ,MAAM;AAEV,WAAK,wCAAoB;AAGzB,WAAK,wBAAwB;AAG7B,WAAK,MAAM,MAAM;AAAA,IACrB;AAAA,IAMQ,aAAa,MAAM;AACvB,UAAI,KAAK,yBAAyB,MAAM;AAEpC,eAAO,KAAK,wBAAwB,KAAK;AAAA,MAC7C;AAGA,aAAO;AAAA,IACX;AAAA,IAMQ,0BAA0B,CAAC,YAAkC;AAEjE,UAAI,KAAK,eAAe,MAAM;AAC1B,aAAK,uBAAuB,KAAK;AAAA,MACrC,WAAW,KAAK,kBAAkB,QAAQ,KAAK,kBAAkB,MAAM;AAGnE,cAAM,SAAS,OAAO,QAAQ,WAAW,aAAa,QAAQ,SAAS,KAAK;AAG5E,aAAK,uBAAuB,KAAK;AAAA,UAC7B,OAAO,KAAK,KAAK,gBAAgB,KAAK,gBAAgB,KAAK,KAAK;AAAA,QACpE;AAAA,MACJ,OAAO;AACH,aAAK,uBAAuB;AAAA,MAChC;AAAA,IACJ;AAAA,EACJ;;;AC5IA,MAAqB,QAArB,cAAmC,UAAU;AAAA,IAQzC,YACI,YACQ,UACA,aACA,aACR,OACF;AACE,YAAM,SAAS,YAAY,KAAK;AALxB;AACA;AACA;AAAA,IAIZ;AAAA,IAKQ,qBAAoC;AAAA,IAKpC,sBAA8B;AAAA,IAO5B,SAAS,OAAc,SAAqC;AAElE,UAAI,KAAK,kCAAc,GAAG;AAEtB,aAAK,MAAM,MAAM;AAGjB,aAAK,sBAAsB;AAG3B,aAAK,sBAAsB,OAAO;AAAA,MACtC;AAIA,UAAI,KAAK,WAAW,GAAG;AAEnB,aAAK,4CAAsB;AAI3B,YAAI,KAAK,MAAM,SAAS,yCAAoB;AACxC,eAAK,MAAM,MAAM;AAAA,QACrB;AAGA,aAAK,MAAM,OAAO,OAAO,OAAO;AAIhC,YAAI,KAAK,MAAM,SAAS,+CAAuB;AAE3C,eAAK,gDAAwB;AAE7B;AAAA,QACJ,WAAW,KAAK,MAAM,SAAS,yCAAoB;AAE/C,eAAK,uBAAuB;AAAA,QAChC;AAAA,MACJ,OAAO;AAEH,aAAK,0CAAqB;AAAA,MAC9B;AAAA,IACJ;AAAA,IAKA,UAAU,MAAM;AACZ,UAAI,KAAK,aAAa,MAAM;AACxB,eAAO,SAAS,KAAK;AAAA,MACzB,WAAW,KAAK,gBAAgB,QAAQ,KAAK,gBAAgB,MAAM;AAC/D,eAAO,SAAS,KAAK,gBAAgB,KAAK;AAAA,MAC9C,OAAO;AACH,eAAO;AAAA,MACX;AAAA,IACJ;AAAA,IAKA,QAAQ,MAAM;AAEV,WAAK,wCAAoB;AAGzB,WAAK,sBAAsB;AAG3B,WAAK,MAAM,MAAM;AAAA,IACrB;AAAA,IAMA,aAAa,MAAM;AACf,UAAI,KAAK,uBAAuB,MAAM;AAElC,eAAO,KAAK,sBAAsB,KAAK;AAAA,MAC3C;AAGA,aAAO;AAAA,IACX;AAAA,IAMA,wBAAwB,CAAC,YAAkC;AAEvD,UAAI,KAAK,aAAa,MAAM;AACxB,aAAK,qBAAqB,KAAK;AAAA,MACnC,WAAW,KAAK,gBAAgB,QAAQ,KAAK,gBAAgB,MAAM;AAG/D,cAAM,SAAS,OAAO,QAAQ,WAAW,aAAa,QAAQ,SAAS,KAAK;AAG5E,aAAK,qBAAqB,KAAK;AAAA,UAC3B,OAAO,KAAK,KAAK,cAAc,KAAK,cAAc,KAAK,KAAK;AAAA,QAChE;AAAA,MACJ,OAAO;AACH,aAAK,qBAAqB;AAAA,MAC9B;AAAA,IACJ;AAAA,EACJ;;;AChJA,MAAqB,OAArB,cAAkC,UAAU;AAAA,IAKxC,YAAY,YAAyB,OAAa;AAC9C,YAAM,QAAQ,YAAY,KAAK;AAAA,IACnC;AAAA,IAOU,SAAS,OAAc,SAAqC;AAElE,UAAI,KAAK,MAAM,SAAS,yCAAqB,KAAK,MAAM,SAAS,2CAAqB;AAElF,aAAK,MAAM,OAAO,OAAO,OAAO;AAAA,MACpC;AAGA,WAAK,SAAS,KAAK,MAAM,SAAS,CAAC;AAAA,IACvC;AAAA,IAKA,UAAU,MAAM;AAAA,EACpB;;;AC7BA,MAAqB,UAArB,cAAqC,UAAU;AAAA,IAK3C,YAAY,YAAyB,OAAa;AAC9C,YAAM,WAAW,YAAY,KAAK;AAAA,IACtC;AAAA,IAOU,SAAS,OAAc,SAAqC;AAElE,UAAI,KAAK,MAAM,SAAS,yCAAqB,KAAK,MAAM,SAAS,2CAAqB;AAClF,aAAK,MAAM,OAAO,OAAO,OAAO;AAAA,MACpC;AAGA,cAAQ,KAAK,MAAM,SAAS,GAAG;AAAA,QAC3B;AACI,eAAK,4CAAsB;AAC3B;AAAA,QAEJ;AAAA,QACA;AACI,eAAK,gDAAwB;AAC7B;AAAA,QAEJ;AACI,eAAK,wCAAoB;AAAA,MACjC;AAAA,IACJ;AAAA,IAKA,UAAU,MAAM;AAAA,EACpB;;;AC9CA,MAA8B,OAA9B,cAA2C,KAAK;AAAA,IAI5C,aAAa,MAAM;AAAA,EACvB;;;ACCA,MAAqB,SAArB,cAAoC,KAAK;AAAA,IAMrC,YAAY,YAAiC,YAA4B,iBAAwB;AAC7F,YAAM,UAAU,YAAY,eAAe;AADF;AAA4B;AAAA,IAEzE;AAAA,IAKQ,uBAAuB;AAAA,IAKvB,2BAAiD;AAAA,IAO/C,SAAS,OAAc,SAAqC;AAGlE,UAAI,KAAK,sBAAsB;AAE3B,YAAI,KAAK,0BAA0B;AAE/B,eAAK,SAAS,KAAK,wBAAwB;AAAA,QAC/C;AAEA;AAAA,MACJ;AAGA,YAAM,oBAAoB,OAAO,eAAe,OAAO,KAAK,UAAU;AAGtE,UAAI,sBAAsB,MAAM;AAC5B,cAAM,IAAI;AAAA,UACN,4CAA4C,KAAK;AAAA,QACrD;AAAA,MACJ;AAMA,YAAM,eAAe,kBAAkB,KAAK,eAAe;AAE3D,UAAI,wBAAwB,SAAS;AACjC,qBAAa;AAAA,UACT,CAAC,WAAW;AAER,gBAAI,CAAC,KAAK,sBAAsB;AAC5B;AAAA,YACJ;AAGA,gBAAI,sDAA8B,8CAAyB;AACvD,oBAAM,IAAI;AAAA,gBACN;AAAA,cACJ;AAAA,YACJ;AAGA,iBAAK,2BAA2B;AAAA,UACpC;AAAA,UACA,CAAC,WAAW;AAER,gBAAI,CAAC,KAAK,sBAAsB;AAC5B;AAAA,YACJ;AAGA,kBAAM,IAAI,MAAM,MAAM;AAAA,UAC1B;AAAA,QACJ;AAGA,aAAK,4CAAsB;AAG3B,aAAK,uBAAuB;AAAA,MAChC,OAAO;AAEH,aAAK,qBAAqB,YAAY;AAGtC,aAAK,SAAS,mDAA6B;AAAA,MAC/C;AAAA,IACJ;AAAA,IAKA,UAAU,MAAM,KAAK;AAAA,IAKrB,QAAQ,MAAM;AAEV,WAAK,wCAAoB;AAGzB,WAAK,uBAAuB;AAC5B,WAAK,2BAA2B;AAAA,IACpC;AAAA,IAMQ,uBAAuB,CAAC,WAAoC;AAChE,cAAQ,QAAQ;AAAA,QACZ;AAAA,QACA;AAAA,QACA,KAAK;AACD;AAAA,QACJ;AACI,gBAAM,IAAI;AAAA,YACN,WAAW,KAAK;AAAA,UACpB;AAAA,MACR;AAAA,IACJ;AAAA,EACJ;;;AClIA,MAAqB,YAArB,cAAuC,KAAK;AAAA,IAMxC,YAAY,YAAiC,eAA+B,oBAA2B;AACnG,YAAM,aAAa,YAAY,kBAAkB;AADR;AAA+B;AAAA,IAE5E;AAAA,IAOU,SAAS,OAAc,SAAqC;AAElE,YAAM,uBAAuB,OAAO,eAAe,OAAO,KAAK,aAAa;AAG5E,UAAI,yBAAyB,MAAM;AAC/B,cAAM,IAAI;AAAA,UACN,kDAAkD,KAAK;AAAA,QAC3D;AAAA,MACJ;AAGA,WAAK,SAAS,CAAC,CAAC,qBAAqB,KAAK,kBAAkB,+EAAkC;AAAA,IAClG;AAAA,IAKA,UAAU,MAAM,KAAK;AAAA,EACzB;;;ACnCA,MAAqB,OAArB,cAAkC,KAAK;AAAA,IAOnC,YACI,YACQ,UACA,aACA,aACV;AACE,YAAM,QAAQ,YAAY,CAAC,CAAC;AAJpB;AACA;AACA;AAAA,IAGZ;AAAA,IAKQ,oBAA4B;AAAA,IAK5B,gBAA+B;AAAA,IAK/B,iBAAyB;AAAA,IAOvB,SAAS,OAAc,SAAqC;AAElE,UAAI,KAAK,kCAAc,GAAG;AAEtB,aAAK,oBAAoB,IAAI,KAAK,EAAE,QAAQ;AAG5C,aAAK,iBAAiB;AAGtB,YAAI,KAAK,aAAa,MAAM;AACxB,eAAK,gBAAgB,KAAK;AAAA,QAC9B,WAAW,KAAK,gBAAgB,QAAQ,KAAK,gBAAgB,MAAM;AAG/D,gBAAM,SAAS,OAAO,QAAQ,WAAW,aAAa,QAAQ,SAAS,KAAK;AAG5E,eAAK,gBAAgB,KAAK;AAAA,YACtB,OAAO,KAAK,KAAK,cAAc,KAAK,cAAc,KAAK,KAAK;AAAA,UAChE;AAAA,QACJ,OAAO;AACH,eAAK,gBAAgB;AAAA,QACzB;AAGA,aAAK,4CAAsB;AAAA,MAC/B;AAGA,UAAI,KAAK,kBAAkB,MAAM;AAC7B;AAAA,MACJ;AAGA,UAAI,OAAO,QAAQ,iBAAiB,YAAY;AAE5C,cAAM,YAAY,QAAQ,aAAa;AAGvC,YAAI,OAAO,cAAc,YAAY,MAAM,SAAS,GAAG;AACnD,gBAAM,IAAI,MAAM,oDAAoD;AAAA,QACxE;AAGA,aAAK,kBAAkB,YAAY;AAAA,MACvC,OAAO;AAEH,aAAK,iBAAiB,IAAI,KAAK,EAAE,QAAQ,IAAI,KAAK;AAAA,MACtD;AAGA,UAAI,KAAK,kBAAkB,KAAK,eAAe;AAE3C,aAAK,gDAAwB;AAAA,MACjC;AAAA,IACJ;AAAA,IAKA,UAAU,MAAM;AACZ,UAAI,KAAK,aAAa,MAAM;AACxB,eAAO,QAAQ,KAAK;AAAA,MACxB,WAAW,KAAK,gBAAgB,QAAQ,KAAK,gBAAgB,MAAM;AAC/D,eAAO,QAAQ,KAAK,iBAAiB,KAAK;AAAA,MAC9C,OAAO;AACH,eAAO;AAAA,MACX;AAAA,IACJ;AAAA,EACJ;;;ACvGA,MAA8B,YAA9B,MAAuG;AAAA,IAKnG,YAAmB,MAAqB,MAAa;AAAlC;AAAqB;AAAA,IAAc;AAAA,EAW1D;;;AClBA,MAA8B,QAA9B,cAA4C,UAAiC;AAAA,IAMzE,YAAY,MAAc,MAAqB,WAAmB;AAC9D,YAAM,MAAM,IAAI;AAD2B;AAAA,IAE/C;AAAA,IAKA,eAAe,MAAM,KAAK;AAAA,IAK1B,UAAU,MAAM;AAAA,IAKhB,aAAoC;AAChC,aAAO;AAAA,QACH,MAAM,KAAK;AAAA,QACX,MAAM,KAAK;AAAA,QACX,WAAW,KAAK,aAAa;AAAA,MACjC;AAAA,IACJ;AAAA,EAQJ;;;ACzCA,MAAqB,QAArB,cAAmC,MAAM;AAAA,IAKrC,YAAY,WAAmB,MAAa;AACxC,YAAM,SAAS,MAAM,SAAS;AAAA,IAClC;AAAA,IAOA,cAAc,CAAC,UAAiB;AAE5B,YAAM,uBAAuB,OAAO,eAAe,OAAO,KAAK,aAAa,CAAC;AAG7E,UAAI,yBAAyB,MAAM;AAC/B,cAAM,IAAI;AAAA,UACN,gDAAgD,KAAK,aAAa;AAAA,QACtE;AAAA,MACJ;AAGA,aAAO,CAAC,CAAC,qBAAqB,KAAK,IAAI;AAAA,IAC3C;AAAA,EACJ;;;AC5BA,MAAqB,QAArB,cAAmC,MAAM;AAAA,IAKrC,YAAY,WAAmB,MAAa;AACxC,YAAM,SAAS,MAAM,SAAS;AAAA,IAClC;AAAA,IAOA,cAAc,CAAC,UAAiB;AAE5B,YAAM,uBAAuB,OAAO,eAAe,OAAO,KAAK,aAAa,CAAC;AAG7E,UAAI,yBAAyB,MAAM;AAC/B,cAAM,IAAI;AAAA,UACN,gDAAgD,KAAK,aAAa;AAAA,QACtE;AAAA,MACJ;AAGA,aAAO,CAAC,CAAC,CAAC,qBAAqB,KAAK,IAAI;AAAA,IAC5C;AAAA,EACJ;;;ACxBA,MAA8B,WAA9B,cAA+C,UAAoC;AAAA,IAM/E,YAAY,MAAc,MAAqB,cAAsB;AACjE,YAAM,MAAM,IAAI;AAD2B;AAAA,IAE/C;AAAA,IAKA,kBAAkB,MAAM,KAAK;AAAA,IAK7B,UAAU,MAAM;AAAA,IAKhB,aAAuC;AACnC,aAAO;AAAA,QACH,MAAM,KAAK;AAAA,QACX,MAAM,KAAK;AAAA,QACX,cAAc,KAAK,gBAAgB;AAAA,MACvC;AAAA,IACJ;AAAA,EAOJ;;;ACxCA,MAAqB,QAArB,cAAmC,SAAS;AAAA,IAKxC,YAAY,cAAsB,MAAa;AAC3C,YAAM,SAAS,MAAM,YAAY;AAAA,IACrC;AAAA,IAMA,oBAAoB,CAAC,UAAiB;AAElC,YAAM,sBAAsB,OAAO,eAAe,OAAO,KAAK,gBAAgB,CAAC;AAG/E,UAAI,wBAAwB,MAAM;AAC9B,cAAM,IAAI;AAAA,UACN,+BAA+B,KAAK,gBAAgB;AAAA,QACxD;AAAA,MACJ;AAGA,0BAAoB,KAAK,IAAI;AAAA,IACjC;AAAA,EACJ;;;AC3BA,MAAqB,OAArB,cAAkC,SAAS;AAAA,IAKvC,YAAY,cAAsB,MAAa;AAC3C,YAAM,QAAQ,MAAM,YAAY;AAAA,IACpC;AAAA,IAMA,oBAAoB,CAAC,UAAiB;AAElC,YAAM,sBAAsB,OAAO,eAAe,OAAO,KAAK,gBAAgB,CAAC;AAG/E,UAAI,wBAAwB,MAAM;AAC9B,cAAM,IAAI;AAAA,UACN,8BAA8B,KAAK,gBAAgB;AAAA,QACvD;AAAA,MACJ;AAGA,0BAAoB,KAAK,IAAI;AAAA,IACjC;AAAA,EACJ;;;AC3BA,MAAqB,OAArB,cAAkC,SAAS;AAAA,IAKvC,YAAY,cAAsB,MAAa;AAC3C,YAAM,QAAQ,MAAM,YAAY;AAAA,IACpC;AAAA,IAQA,oBAAoB,CAAC,OAAc,WAAoB,cAAuB;AAE1E,YAAM,sBAAsB,OAAO,eAAe,OAAO,KAAK,gBAAgB,CAAC;AAG/E,UAAI,wBAAwB,MAAM;AAC9B,cAAM,IAAI;AAAA,UACN,8BAA8B,KAAK,gBAAgB;AAAA,QACvD;AAAA,MACJ;AAGA,0BAAoB,CAAC,EAAE,OAAO,EAAE,WAAW,WAAW,SAAS,UAAU,EAAE,GAAG,GAAG,KAAK,IAAI,CAAC;AAAA,IAC/F;AAAA,EACJ;;;ACkBA,MAAM,qBAAqB,OAAO,UAAU;AAO7B,WAAR,cAA+B,YAAwC;AAE1E,UAAM,wBAAwB,4BAA4B,UAAU;AAKpE,+BAA2B,YAAY,IAAI;AAG3C,UAAM,WAAW,YAAY,sBAAsB,qBAAqB,qBAAqB;AAG7F,4BAAwB,QAAQ;AAGhC,WAAO;AAAA,EACX;AAQA,WAAS,YAAY,YAA+B,uBAAuD;AAEvG,UAAM,aAAa,sBAAsB,UAAU;AAGnD,YAAQ,WAAW,MAAM;AAAA,MACrB,KAAK;AACD,eAAO,IAAI,KAAK,YAAY,YAAY,WAAW,OAAO,qBAAqB,CAAC;AAAA,MAEpF,KAAK;AACD,YAAI,aAA4B;AAChC,YAAI,gBAA+B;AACnC,YAAI,gBAA+B;AAEnC,YAAI,MAAM,QAAQ,WAAW,UAAU,GAAG;AACtC,0BAAgB,WAAW,WAAW;AACtC,0BAAgB,WAAW,WAAW;AAAA,QAC1C,WAAW,UAAU,WAAW,UAAU,GAAG;AACzC,uBAAa,WAAW;AAAA,QAC5B;AAEA,eAAO,IAAI;AAAA,UACP;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA,YAAY,WAAW,OAAO,qBAAqB;AAAA,QACvD;AAAA,MAEJ,KAAK;AACD,YAAI,WAA0B;AAC9B,YAAI,cAA6B;AACjC,YAAI,cAA6B;AAEjC,YAAI,MAAM,QAAQ,WAAW,QAAQ,GAAG;AACpC,wBAAc,WAAW,SAAS;AAClC,wBAAc,WAAW,SAAS;AAAA,QACtC,WAAW,UAAU,WAAW,QAAQ,GAAG;AACvC,qBAAW,WAAW;AAAA,QAC1B;AAEA,eAAO,IAAI;AAAA,UACP;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA,YAAY,WAAW,OAAO,qBAAqB;AAAA,QACvD;AAAA,MAEJ,KAAK;AACD,eAAO,IAAI,KAAK,YAAY,YAAY,WAAW,OAAO,qBAAqB,CAAC;AAAA,MAEpF,KAAK;AACD,eAAO,IAAI,QAAQ,YAAY,YAAY,WAAW,OAAO,qBAAqB,CAAC;AAAA,MAEvF,KAAK;AACD,eAAO,IAAI,KAAK,YAAY,YAAY,WAAW,OAAO,qBAAqB,CAAC;AAAA,MAEpF,KAAK;AACD,eAAO,IAAI;AAAA,UACP;AAAA,UACA,WAAW,SAAS,IAAI,CAAC,UAAU,YAAY,OAAO,qBAAqB,CAAC;AAAA,QAChF;AAAA,MAEJ,KAAK;AACD,eAAO,IAAI;AAAA,UACP;AAAA,UACA,WAAW,SAAS,IAAI,CAAC,UAAU,YAAY,OAAO,qBAAqB,CAAC;AAAA,QAChF;AAAA,MAEJ,KAAK;AACD,eAAO,IAAI;AAAA,UACP;AAAA,UACA,WAAW,SAAS,IAAI,CAAC,UAAU,YAAY,OAAO,qBAAqB,CAAC;AAAA,QAChF;AAAA,MAEJ,KAAK;AACD,eAAO,IAAI;AAAA,UACP;AAAA,UACA,WAAW;AAAA,UACX,WAAW,SAAS,IAAI,CAAC,UAAU,YAAY,OAAO,qBAAqB,CAAC;AAAA,QAChF;AAAA,MAEJ,KAAK;AACD,eAAO,YAAY,sBAAsB,WAAW,KAAK,OAAO,qBAAqB;AAAA,MAEzF,KAAK;AACD,eAAO,IAAI,OAAO,YAAY,WAAW,MAAM,WAAW,QAAQ,CAAC,CAAC;AAAA,MAExE,KAAK;AACD,eAAO,IAAI,UAAU,YAAY,WAAW,MAAM,WAAW,QAAQ,CAAC,CAAC;AAAA,MAE3E,KAAK;AACD,YAAI,WAA0B;AAC9B,YAAI,cAA6B;AACjC,YAAI,cAA6B;AAEjC,YAAI,MAAM,QAAQ,WAAW,QAAQ,GAAG;AACpC,wBAAc,WAAW,SAAS;AAClC,wBAAc,WAAW,SAAS;AAAA,QACtC,WAAW,UAAU,WAAW,QAAQ,GAAG;AACvC,qBAAW,WAAW;AAAA,QAC1B;AAEA,eAAO,IAAI,KAAK,YAAY,UAAU,aAAa,WAAW;AAAA,IACtE;AAAA,EACJ;AAOA,WAAS,sBAAsB,YAA4C;AACvE,UAAM,aAA0B,CAAC;AAEjC,QAAI,WAAW,OAAO;AAClB,iBAAW,KAAK,IAAI,MAAM,WAAW,MAAM,MAAM,WAAW,MAAM,QAAQ,CAAC,CAAC,CAAC;AAAA,IACjF;AAEA,QAAI,WAAW,OAAO;AAClB,iBAAW,KAAK,IAAI,MAAM,WAAW,MAAM,MAAM,WAAW,MAAM,QAAQ,CAAC,CAAC,CAAC;AAAA,IACjF;AAEA,QAAI,WAAW,OAAO;AAClB,iBAAW,KAAK,IAAI,MAAM,WAAW,MAAM,MAAM,WAAW,MAAM,QAAQ,CAAC,CAAC,CAAC;AAAA,IACjF;AAEA,QAAI,WAAW,MAAM;AACjB,iBAAW,KAAK,IAAI,KAAK,WAAW,KAAK,MAAM,WAAW,KAAK,QAAQ,CAAC,CAAC,CAAC;AAAA,IAC9E;AAEA,QAAI,WAAW,MAAM;AACjB,iBAAW,KAAK,IAAI,KAAK,WAAW,KAAK,MAAM,WAAW,KAAK,QAAQ,CAAC,CAAC,CAAC;AAAA,IAC9E;AAEA,WAAO;AAAA,EACX;AAOA,WAAS,4BAA4B,YAAyD;AAE1F,UAAM,cAAqC,CAAC;AAG5C,eAAW,CAAC,MAAM,kBAAkB,KAAK,OAAO,QAAQ,OAAO,YAAY,CAAC,GAAG;AAE3E,kBAAY,QAAQ,EAAE,GAAG,oBAAoB,IAAI,KAAK;AAAA,IAC1D;AAIA,eAAW,sBAAsB,YAAY;AACzC,kBAAY,mBAAmB,MAAM,sBAAsB;AAAA,IAC/D;AAEA,WAAO;AAAA,EACX;AAMA,WAAS,wBAAwB,MAAY;AACzC,UAAM,YAAsB,CAAC;AAE7B,UAAM,gBAAgB,CAAC,MAAc,SAAe;AAEhD,aAAO,KAAK,OAAO,IAAI;AAGvB,UAAI,KAAK,WAAW,GAAG;AACnB,kBAAU,KAAK,IAAI;AAAA,MACvB,OAAO;AACH,QAAC,KAA+B,YAAY,EAAE,QAAQ,CAAC,UAAU,cAAc,MAAM,KAAK,CAAC;AAAA,MAC/F;AAAA,IACJ;AAGA,kBAAc,CAAC,GAAG,IAAI;AAEtB,cAAU,QAAQ,CAAC,SAAS;AAExB,eAAS,QAAQ,GAAG,QAAQ,KAAK,QAAQ,SAAS;AAE9C,cAAM,cAAc,KAAK;AAGzB,YAAI,YAAY,aAAa,GAAG;AAC5B;AAAA,QACJ;AAGA,cAAM,YAAY,IAAI;AAAA,UAClB,KACK,MAAM,GAAG,QAAQ,CAAC,EAClB,IAAmB,CAAC,UAAU,EAAE,MAAM,QAAQ,KAAK,mBAAmB,EAAE,EAAE,EAC1E,OAAO,CAAC,YAAY,QAAQ,OAAO,SAAS,CAAC;AAAA,QACtD;AAGA,oBAAY,aAAa,SAAS;AAAA,MACtC;AAAA,IACJ,CAAC;AAAA,EACL;;;ACvQO,MAAM,gBAAN,MAAoB;AAAA,IAYvB,YACI,YACQ,OACA,UAAgC,CAAC,GAC3C;AAFU;AACA;AAGR,UAAI,kBAAkB,UAAU,GAAG;AAC/B,cAAM,IAAI,MAAM,6BAA6B;AAAA,MACjD;AAGA,UAAI,OAAO,UAAU,YAAY,UAAU,MAAM;AAC7C,cAAM,IAAI,MAAM,0CAA0C;AAAA,MAC9D;AAGA,YAAM,EAAE,WAAW,cAAc,KAAK,IAAI,mBAAmB,UAAU;AAGvE,UAAI,CAAC,WAAW;AACZ,cAAM,IAAI,MAAM,uBAAuB,cAAc;AAAA,MACzD;AAGA,UAAI,CAAC,MAAM;AACP,cAAM,IAAI;AAAA,UACN;AAAA,QACJ;AAAA,MACJ;AAEA,UAAI;AAEA,aAAK,WAAW,cAAc,IAAI;AAAA,MACtC,SAAS,WAAP;AAEE,cAAM,IAAI,MAAM,wBAAyB,UAAoB,SAAS;AAAA,MAC1E;AAAA,IACJ;AAAA,IA7CgB;AAAA,IAmDhB,YAAY;AACR,aAAO,KAAK,SAAS,SAAS;AAAA,IAClC;AAAA,IAMA,WAAW;AACP,aAAO,KAAK,SAAS,SAAS;AAAA,IAClC;AAAA,IAUA,OAAO;AAEH,UAAI,KAAK,SAAS,SAAS,iDAAyB,KAAK,SAAS,SAAS,yCAAoB;AAC3F,aAAK,SAAS,MAAM;AAAA,MACxB;AAEA,UAAI;AACA,aAAK,SAAS,OAAO,KAAK,OAAO,KAAK,OAAO;AAAA,MACjD,SAAS,WAAP;AACE,cAAM,IAAI,MAAM,wBAAyB,UAAoB,SAAS;AAAA,MAC1E;AAAA,IACJ;AAAA,IAKA,QAAQ;AACJ,WAAK,SAAS,MAAM;AAAA,IACxB;AAAA,IAMA,0BAA+C;AAE3C,YAAM,qBAA0C,CAAC;AAOjD,YAAM,cAAc,CAAC,MAAY,cAA6B;AAE1D,cAAM,SAAS,KACV,cAAc,EACd,OAAO,CAAC,cAAc,UAAU,QAAQ,CAAC,EACzC,IAAI,CAAC,cAAc,UAAU,WAAW,CAAC;AAC9C,cAAM,YAAY,KACb,cAAc,EACd,OAAO,CAAC,cAAc,CAAC,UAAU,QAAQ,CAAC,EAC1C,IAAI,CAAC,cAAc,UAAU,WAAW,CAAC;AAG9C,2BAAmB,KAAK;AAAA,UACpB,IAAI,KAAK,OAAO;AAAA,UAChB,MAAM,KAAK,QAAQ;AAAA,UACnB,SAAS,KAAK,QAAQ;AAAA,UACtB,OAAO,KAAK,SAAS;AAAA,UACrB;AAAA,UACA;AAAA,UACA,MAAM,KAAK,aAAa;AAAA,UACxB,UAAU;AAAA,QACd,CAAC;AAGD,YAAI,CAAC,KAAK,WAAW,GAAG;AACpB,UAAC,KACI,YAAY,EACZ,QAAQ,CAAC,UAAU,YAAY,OAAQ,KAA+B,OAAO,CAAC,CAAC;AAAA,QACxF;AAAA,MACJ;AAGA,kBAAY,KAAK,UAAU,IAAI;AAE/B,aAAO;AAAA,IACX;AAAA,IAOA,OAAO,SAAS,MAAc,OAAqD;AAE/E,UAAI,OAAO,UAAU,YAAY;AAC7B,eAAO,QAAQ,MAAM,KAAK;AAC1B;AAAA,MACJ;AAGA,UAAI,OAAO,UAAU,UAAU;AAC3B,YAAI;AAGJ,YAAI;AACA,gCAAsB,kBAAkB,KAAK;AAAA,QACjD,SAAS,WAAP;AACE,gBAAM,IAAI,MAAM,+CAAgD,UAAoB,SAAS;AAAA,QACjG;AAGA,YAAI,oBAAoB,UAAU,KAAK,oBAAoB,GAAG,OAAO,MAAM;AACvE,gBAAM,IAAI,MAAM,mEAAmE;AAAA,QACvF;AAEA,YAAI;AAEA,gBAAM,EAAE,WAAW,aAAa,IAAI,uBAAuB,oBAAoB,EAAE;AAGjF,cAAI,CAAC,WAAW;AACZ,kBAAM,IAAI,MAAM,YAAY;AAAA,UAChC;AAAA,QACJ,SAAS,WAAP;AACE,gBAAM,IAAI,MAAM,iCAAkC,UAAoB,SAAS;AAAA,QACnF;AAGA,eAAO,WAAW,MAAM,oBAAoB,EAAE;AAAA,MAClD,WAAW,OAAO,UAAU,YAAY,CAAC,MAAM,QAAQ,KAAK,GAAG;AAG3D,YAAI;AAEA,gBAAM,EAAE,WAAW,aAAa,IAAI,uBAAuB,KAAK;AAGhE,cAAI,CAAC,WAAW;AACZ,kBAAM,IAAI,MAAM,YAAY;AAAA,UAChC;AAAA,QACJ,SAAS,WAAP;AACE,gBAAM,IAAI,MAAM,iCAAkC,UAAoB,SAAS;AAAA,QACnF;AAGA,eAAO,WAAW,MAAM,KAAK;AAAA,MACjC,OAAO;AACH,cAAM,IAAI,MAAM,0FAA0F;AAAA,MAC9G;AAAA,IACJ;AAAA,IAMA,OAAO,WAAW,MAAoB;AAClC,aAAO,OAAO,IAAI;AAAA,IACtB;AAAA,IAKA,OAAO,gBAAsB;AACzB,aAAO,MAAM;AAAA,IACjB;AAAA,EACJ;", "names": ["Participant", "isNullOrUndefined", "Lotto", "createLotto", "State", "createLotto"] } diff --git a/dist/index.js.map b/dist/index.js.map index 6f0e041..4fadc01 100644 --- a/dist/index.js.map +++ b/dist/index.js.map @@ -1,7 +1,7 @@ { "version": 3, "sources": ["../node_modules/lotto-draw/dist/Participant.js", "../node_modules/lotto-draw/dist/Utilities.js", "../node_modules/lotto-draw/dist/Lotto.js", "../node_modules/lotto-draw/dist/createLotto.js", "../node_modules/lotto-draw/dist/index.js", "../src/index.ts", "../src/State.ts", "../src/BehaviourTreeDefinitionUtilities.ts", "../src/mdsl/MDSLUtilities.ts", "../src/mdsl/MDSLNodeArgumentParser.ts", "../src/mdsl/MDSLNodeAttributeParser.ts", "../src/mdsl/MDSLDefinitionParser.ts", "../src/BehaviourTreeDefinitionValidator.ts", "../src/Lookup.ts", "../src/attributes/guards/GuardUnsatisifedException.ts", "../src/attributes/guards/GuardPath.ts", "../src/nodes/Node.ts", "../src/nodes/composite/Composite.ts", "../src/nodes/composite/Parallel.ts", "../src/nodes/composite/Selector.ts", "../src/nodes/composite/Sequence.ts", "../src/nodes/composite/Lotto.ts", "../src/nodes/decorator/Decorator.ts", "../src/nodes/decorator/Fail.ts", "../src/nodes/decorator/Flip.ts", "../src/nodes/decorator/Repeat.ts", "../src/nodes/decorator/Retry.ts", "../src/nodes/decorator/Root.ts", "../src/nodes/decorator/Succeed.ts", "../src/nodes/leaf/Leaf.ts", "../src/nodes/leaf/Action.ts", "../src/nodes/leaf/Condition.ts", "../src/nodes/leaf/Wait.ts", "../src/attributes/Attribute.ts", "../src/attributes/guards/Guard.ts", "../src/attributes/guards/While.ts", "../src/attributes/guards/Until.ts", "../src/attributes/callbacks/Callback.ts", "../src/attributes/callbacks/Entry.ts", "../src/attributes/callbacks/Step.ts", "../src/attributes/callbacks/Exit.ts", "../src/BehaviourTreeBuilder.ts", "../src/BehaviourTree.ts"], - "sourcesContent": ["\"use strict\";\r\nObject.defineProperty(exports, \"__esModule\", { value: true });\r\nexports.Participant = void 0;\r\n/**\r\n * A participant that holds a number of tickets.\r\n */\r\nvar Participant = /** @class */ (function () {\r\n /**\r\n * Creates an instance of the Participant class.\r\n * @param participant The actual participant.\r\n * @param tickets The number of tickets held by the participant.\r\n */\r\n function Participant(participant, tickets) {\r\n if (tickets === void 0) { tickets = 1; }\r\n this._participant = participant;\r\n this._tickets = tickets;\r\n }\r\n Object.defineProperty(Participant.prototype, \"participant\", {\r\n /** Gets the actual participant. */\r\n get: function () {\r\n return this._participant;\r\n },\r\n enumerable: false,\r\n configurable: true\r\n });\r\n Object.defineProperty(Participant.prototype, \"tickets\", {\r\n /** Gets or sets the number of tickets held by the participant. */\r\n get: function () {\r\n return this._tickets;\r\n },\r\n set: function (value) {\r\n this._tickets = value;\r\n },\r\n enumerable: false,\r\n configurable: true\r\n });\r\n return Participant;\r\n}());\r\nexports.Participant = Participant;\r\n", "\"use strict\";\r\nObject.defineProperty(exports, \"__esModule\", { value: true });\r\nexports.isNaturalNumber = exports.isNullOrUndefined = void 0;\r\n/**\r\n * Gets whether the value provided is null or undefined.\r\n * @param value The value to check.\r\n * @returns Whether the value provided is null or undefined.\r\n */\r\nfunction isNullOrUndefined(value) {\r\n return value === null || value === undefined;\r\n}\r\nexports.isNullOrUndefined = isNullOrUndefined;\r\n/**\r\n * Gets whether the value provided is a natural number.\r\n * @param value The value to check.\r\n * @returns Whether the value provided is a natural number.\r\n */\r\nfunction isNaturalNumber(value) {\r\n return typeof value === \"number\" && value >= 1 && Math.floor(value) === value;\r\n}\r\nexports.isNaturalNumber = isNaturalNumber;\r\n", "\"use strict\";\r\nObject.defineProperty(exports, \"__esModule\", { value: true });\r\nexports.Lotto = void 0;\r\nvar Participant_1 = require(\"./Participant\");\r\nvar Utilities_1 = require(\"./Utilities\");\r\n/**\r\n * Represents a lotto consisting of a number of pickable ticket-holding participants.\r\n */\r\nvar Lotto = /** @class */ (function () {\r\n /**\r\n * Creates a new instance of Lotto.\r\n * @param customRandom The custom RNG to use in place of Math.random().\r\n */\r\n function Lotto(customRandom) {\r\n /** The array of participants that are holding tickets in the lotto. */\r\n this._participants = [];\r\n this._customRandom = customRandom;\r\n }\r\n /**\r\n * Adds a participant with the specified number of tickets, or adds to the participant ticket count if the participant already holds tickets.\r\n * @param participant The participant to add or to increase the ticket count for if they already hold tickets.\r\n * @param tickets The number of tickets, defaults to 1.\r\n * @returns The Lotto instance.\r\n */\r\n Lotto.prototype.add = function (participant, tickets) {\r\n if (tickets === void 0) { tickets = 1; }\r\n // Check that we have a valid ticket count.\r\n if (!(0, Utilities_1.isNaturalNumber)(tickets)) {\r\n throw new Error(\"tickets value must be a natural number\");\r\n }\r\n // Check whether this participant has already been added.\r\n var existingParticipant = this._participants.find(function (part) { return part.participant === participant; });\r\n if (existingParticipant) {\r\n // The participant has already been added to the lotto so just add to their ticket count.\r\n existingParticipant.tickets += tickets;\r\n }\r\n else {\r\n // The participant is not part of the lotto so we should add them.\r\n this._participants.push(new Participant_1.Participant(participant, tickets));\r\n }\r\n return this;\r\n };\r\n /**\r\n * Removes the specified number of tickets for the given participant from the draw, or all tickets if a ticket number is not defined.\r\n * @param participant The participant to remove tickets for.\r\n * @param tickets The number of tickets to remove, or undefined if all tickets are to be removed.\r\n * @returns The Lotto instance.\r\n */\r\n Lotto.prototype.remove = function (participant, tickets) {\r\n // Attempt to get the existing participant.\r\n var existingParticipant = this._participants.find(function (part) { return part.participant === participant; });\r\n // There is nothing to do if the specified participant isn't even part of the lotto.\r\n if (!existingParticipant) {\r\n return this;\r\n }\r\n // Check whether a tickets value was given.\r\n if (tickets !== undefined) {\r\n // Check that we have a valid ticket count.\r\n if (!(0, Utilities_1.isNaturalNumber)(tickets)) {\r\n throw new Error(\"tickets value must be a natural number\");\r\n }\r\n existingParticipant.tickets -= tickets;\r\n // If the participant no longer holds any tickets then they should be removed.\r\n if (existingParticipant.tickets < 1) {\r\n this._participants = this._participants.filter(function (part) { return part !== existingParticipant; });\r\n }\r\n }\r\n else {\r\n // We are removing all tickets for the participant so just remove them from the lotto.\r\n this._participants = this._participants.filter(function (part) { return part !== existingParticipant; });\r\n }\r\n return this;\r\n };\r\n /**\r\n * Draw a winning ticket and return the participant that holds the ticket.\r\n * @param options The draw options.\r\n * @returns The participant that holds the winning ticket.\r\n */\r\n Lotto.prototype.draw = function (options) {\r\n if (options === void 0) { options = {}; }\r\n // If we have no participants then just return null.\r\n if (this._participants.length === 0) {\r\n return null;\r\n }\r\n var redrawable = (0, Utilities_1.isNullOrUndefined)(options.redrawable) ? true : options.redrawable;\r\n var pickable = [];\r\n this._participants.forEach(function (_a) {\r\n var participant = _a.participant, tickets = _a.tickets;\r\n for (var ticketCount = 0; ticketCount < tickets; ticketCount++) {\r\n pickable.push(participant);\r\n }\r\n });\r\n var random;\r\n // We need a random floating-point number between 0 (inclusive) and 1 to scale up to pick our winner.\r\n // If a custom random function exists then we should use that or fall back to Math.random().\r\n if (this._customRandom) {\r\n // Call our custom random function to get a random floating-point number.\r\n random = this._customRandom();\r\n // Verify that the result of calling our custom random function is a number between 0 (inclusive) and 1.\r\n if (typeof random !== \"number\" || random < 0 || random >= 1) {\r\n throw new Error(\"the 'random' function provided did not return a number between 0 (inclusive) and 1\");\r\n }\r\n }\r\n else {\r\n // No custom random function was defined so just use good ol' Math.random().\r\n random = Math.random();\r\n }\r\n // Pick a winning participant.\r\n var winner = pickable[Math.floor(random * pickable.length)];\r\n // If the ticket isn't redrawable then we should remove a ticket from the winning participants ticket count.\r\n if (!redrawable) {\r\n this.remove(winner, 1);\r\n }\r\n // Return the winning participant.\r\n return winner;\r\n };\r\n /**\r\n * Draws multiple winning tickets and return an array of the participants that hold the winning tickets.\r\n * @param tickets The number of winning tickets to draw.\r\n * @param options The draw multiple options.\r\n * @returns An array of the participants that hold the winning tickets.\r\n */\r\n Lotto.prototype.drawMultiple = function (tickets, options) {\r\n if (options === void 0) { options = {}; }\r\n var uniqueResults = (0, Utilities_1.isNullOrUndefined)(options.unique) ? false : options.unique;\r\n // Handle cases where the user has asked for zero tickets (no idea why they would do this be we should trust them).\r\n if (tickets === 0) {\r\n return [];\r\n }\r\n // Now that we know out tickets value is not zero we should check that it is a valid natural number.\r\n if (!(0, Utilities_1.isNaturalNumber)(tickets)) {\r\n throw new Error(\"tickets value must be a natural number\");\r\n }\r\n var result = [];\r\n // Keep drawing tickets until we either reach the number of required tickets or we simply run out of tickets to draw.\r\n // We can run out of tickets to draw if 'options.redrawable' is explicity 'false' or we just had no participants when 'drawMultiple' was called.\r\n while (result.length < tickets && this._participants.length > 0) {\r\n result.push(this.draw(options));\r\n }\r\n // If the 'unique' draw option is set then we need to remove duplicates from the result list.\r\n if (uniqueResults) {\r\n // Create an array to store our unique results.\r\n var unique = [];\r\n // Iterate over all of our participants (with potential duplicates) and populate our array of unique values.\r\n for (var _i = 0, result_1 = result; _i < result_1.length; _i++) {\r\n var participant = result_1[_i];\r\n if (unique.indexOf(participant) === -1) {\r\n unique.push(participant);\r\n }\r\n }\r\n result = unique;\r\n }\r\n return result;\r\n };\r\n return Lotto;\r\n}());\r\nexports.Lotto = Lotto;\r\n", "\"use strict\";\r\nObject.defineProperty(exports, \"__esModule\", { value: true });\r\nexports.createLotto = void 0;\r\nvar Lotto_1 = require(\"./Lotto\");\r\n/**\r\n * A function that creates and returns a Lotto instance.\r\n * @param participantsOrOptions An array of initial participants or options relating to the creation of a Lotto instance.\r\n * @returns A new Lotto instance.\r\n */\r\nfunction createLotto(participantsOrOptions) {\r\n // If no initial participants or lotto options were provided as an argument then we can just return a new lotto instance now.\r\n if (!participantsOrOptions) {\r\n return new Lotto_1.Lotto();\r\n }\r\n // Check whether we were provided with an array of initial participants or a lotto options object.\r\n if (Array.isArray(participantsOrOptions)) {\r\n // We are dealing with a pre-defined array of participants.\r\n var participants = participantsOrOptions;\r\n var lotto_1 = new Lotto_1.Lotto();\r\n // If the lotto participants have been defined upfront then we will need to add them all to our lotto instance now.\r\n participants.forEach(function (_a) {\r\n var participant = _a[0], tokens = _a[1];\r\n return lotto_1.add(participant, tokens);\r\n });\r\n // Return the Lotto instance.\r\n return lotto_1;\r\n }\r\n else {\r\n // We are dealing with some lotto options.\r\n var random = participantsOrOptions.random, participants = participantsOrOptions.participants;\r\n // Create a Lotto instance passing the custom RNG function to use in place of Math.random() (which could be undefined).\r\n var lotto_2 = new Lotto_1.Lotto(random);\r\n // If the lotto participants have been defined upfront as part of the options then we will need to add them all to our lotto instance now.\r\n if (participants) {\r\n participants.forEach(function (_a) {\r\n var participant = _a[0], tokens = _a[1];\r\n return lotto_2.add(participant, tokens);\r\n });\r\n }\r\n // Return the Lotto instance.\r\n return lotto_2;\r\n }\r\n}\r\nexports.createLotto = createLotto;\r\n", "\"use strict\";\r\nObject.defineProperty(exports, \"__esModule\", { value: true });\r\nvar createLotto_1 = require(\"./createLotto\");\r\nexports.default = createLotto_1.createLotto;\r\n", "import State from \"./State\";\nimport { validateDefinition } from \"./BehaviourTreeDefinitionValidator\";\nimport { convertMDSLToJSON } from \"./mdsl/MDSLDefinitionParser\";\nimport { BehaviourTree, FlattenedTreeNode } from \"./BehaviourTree\";\nimport { BehaviourTreeOptions } from \"./BehaviourTreeOptions\";\n\nexport { BehaviourTree, State, convertMDSLToJSON, validateDefinition };\nexport type { FlattenedTreeNode, BehaviourTreeOptions };\n", "/**\n * Enumeration of node state types.\n */\nexport enum State {\n READY = \"mistreevous.ready\",\n RUNNING = \"mistreevous.running\",\n SUCCEEDED = \"mistreevous.succeeded\",\n FAILED = \"mistreevous.failed\"\n}\n\nexport { State as default };\n\nexport type CompleteState = State.SUCCEEDED | State.FAILED;\nexport type AnyState = State.READY | State.RUNNING | CompleteState;\n", "import {\n NodeDefinition,\n RootNodeDefinition,\n DecoratorNodeDefinition,\n CompositeNodeDefinition,\n AnyNodeDefinition,\n BranchNodeDefinition\n} from \"./BehaviourTreeDefinition\";\n\n/**\n * A type guard function that returns true if the specified node satisfies the RootNodeDefinition type.\n * @param node The node.\n * @returns A value of true if the specified node satisfies the RootNodeDefinition type.\n */\nexport function isRootNode(node: NodeDefinition): node is RootNodeDefinition {\n return node.type === \"root\";\n}\n\n/**\n * A type guard function that returns true if the specified node satisfies the BranchNodeDefinition type.\n * @param node The node.\n * @returns A value of true if the specified node satisfies the BranchNodeDefinition type.\n */\nexport function isBranchNode(node: NodeDefinition): node is BranchNodeDefinition {\n return node.type === \"branch\";\n}\n\n/**\n * A type guard function that returns true if the specified node satisfies the NodeDefinition type.\n * @param node The node.\n * @returns A value of true if the specified node satisfies the NodeDefinition type.\n */\nexport function isLeafNode(node: NodeDefinition): node is NodeDefinition {\n return [\"branch\", \"action\", \"condition\", \"wait\"].includes(node.type);\n}\n\n/**\n * A type guard function that returns true if the specified node satisfies the DecoratorNodeDefinition type.\n * @param node The node.\n * @returns A value of true if the specified node satisfies the DecoratorNodeDefinition type.\n */\nexport function isDecoratorNode(node: NodeDefinition): node is DecoratorNodeDefinition {\n return [\"root\", \"repeat\", \"retry\", \"flip\", \"succeed\", \"fail\"].includes(node.type);\n}\n\n/**\n * A type guard function that returns true if the specified node satisfies the CompositeNodeDefinition type.\n * @param node The node.\n * @returns A value of true if the specified node satisfies the CompositeNodeDefinition type.\n */\nexport function isCompositeNode(node: NodeDefinition): node is CompositeNodeDefinition {\n return [\"sequence\", \"selector\", \"lotto\", \"parallel\"].includes(node.type);\n}\n\n/**\n * Flatten a node definition into an array of all of its nested node definitions.\n * @param nodeDefinition The node definition to flatten.\n * @returns An array of all of nested node definitions.\n */\nexport function flattenDefinition(nodeDefinition: AnyNodeDefinition): AnyNodeDefinition[] {\n const nodes: AnyNodeDefinition[] = [];\n\n const processNode = (currentNodeDefinition: AnyNodeDefinition) => {\n nodes.push(currentNodeDefinition);\n\n if (isCompositeNode(currentNodeDefinition)) {\n currentNodeDefinition.children.forEach(processNode);\n } else if (isDecoratorNode(currentNodeDefinition)) {\n processNode(currentNodeDefinition.child);\n }\n };\n\n processNode(nodeDefinition);\n\n return nodes;\n}\n\n/**\n * Determines whether the passed value is an integer.\n * @param value The value to check.\n * @returns Whether the passed value is an integer.\n */\nexport function isInteger(value: unknown): boolean {\n return typeof value === \"number\" && Math.floor(value) === value;\n}\n\n/**\n * Determines whether the passed value is null or undefined.\n * @param value The value to check.\n * @returns Whether the passed value is null or undefined.\n */\nexport function isNullOrUndefined(value: unknown): boolean {\n return typeof value === \"undefined\" || value === null;\n}\n", "/**\n * A type defining an object that holds a reference to substitued string literals parsed from the definition.\n */\nexport type StringLiteralPlaceholders = { [key: string]: string };\n\n/**\n * Pop the next raw token from the specified array of tokens and throw an error if it wasn't the expected one.\n * @param tokens The array of tokens.\n * @param expected An optional string or array or items, one of which must match the next popped token.\n * @returns The popped token.\n */\nexport function popAndCheck(tokens: string[], expected?: string | string[]): string {\n // Get and remove the next token.\n const popped = tokens.shift();\n\n // We were expecting another token but there aren't any.\n if (popped === undefined) {\n throw new Error(\"unexpected end of definition\");\n }\n\n // Do we have an expected token/tokens array?\n if (expected != undefined) {\n // Get an array of expected values, if the popped token matches any then we are all good.\n const expectedValues = typeof expected === \"string\" ? [expected] : expected;\n\n // Check whether the popped token matches at least one of our expected items.\n var tokenMatchesExpectation = expectedValues.some((item) => popped.toUpperCase() === item.toUpperCase());\n\n // Throw an error if the popped token didn't match any of our expected items.\n if (!tokenMatchesExpectation) {\n const expectationString = expectedValues.map((item) => \"'\" + item + \"'\").join(\" or \");\n throw new Error(\"unexpected token found. Expected \" + expectationString + \" but got '\" + popped + \"'\");\n }\n }\n\n // Return the popped token.\n return popped;\n}\n\n/**\n * Swaps out any node/attribute argument string literals with placeholders.\n * @param definition The definition.\n * @returns An object containing a mapping of placeholders to original string values as well as the processed definition string.\n */\nexport function substituteStringLiterals(definition: string): {\n placeholders: StringLiteralPlaceholders;\n processedDefinition: string;\n} {\n // Create an object to hold the mapping of placeholders to original string values.\n const placeholders: StringLiteralPlaceholders = {};\n\n // Replace any string literals wrapped with double quotes in our definition with placeholders to be processed later.\n const processedDefinition = definition.replace(/\\\"(\\\\.|[^\"\\\\])*\\\"/g, (match) => {\n var strippedMatch = match.substring(1, match.length - 1);\n var placeholder = Object.keys(placeholders).find((key) => placeholders[key] === strippedMatch);\n\n // If we have no existing string literal match then create a new placeholder.\n if (!placeholder) {\n placeholder = `@@${Object.keys(placeholders).length}@@`;\n placeholders[placeholder] = strippedMatch;\n }\n\n return placeholder;\n });\n\n return { placeholders, processedDefinition };\n}\n\n/**\n * Parse the tree definition into an array of raw tokens.\n * @param definition The definition.\n * @returns An array of tokens parsed from the definition.\n */\nexport function parseTokensFromDefinition(definition: string): string[] {\n // Add some space around various important characters so that they can be plucked out easier as individual tokens.\n definition = definition.replace(/\\(/g, \" ( \");\n definition = definition.replace(/\\)/g, \" ) \");\n definition = definition.replace(/\\{/g, \" { \");\n definition = definition.replace(/\\}/g, \" } \");\n definition = definition.replace(/\\]/g, \" ] \");\n definition = definition.replace(/\\[/g, \" [ \");\n definition = definition.replace(/\\,/g, \" , \");\n\n // Split the definition into raw token form and return it.\n return definition.replace(/\\s+/g, \" \").trim().split(\" \");\n}\n", "import { StringLiteralPlaceholders, popAndCheck } from \"./MDSLUtilities\";\n\n/**\n * A type representing any node function argument.\n */\ntype Argument = {\n /**\n * The argument value.\n */\n value: T;\n /**\n * The argument type, used for validation.\n */\n type: string;\n};\n\ntype NullArgument = Argument & {\n type: \"null\";\n};\n\ntype BooleanArgument = Argument & {\n type: \"boolean\";\n};\n\ntype NumberArgument = Argument & {\n type: \"number\";\n /**\n * A flag defining whether the number argument value is a valid integer. (used for validation)\n */\n isInteger: boolean;\n};\n\ntype StringPlaceholderArgument = Argument & {\n type: \"string\";\n};\n\ntype IdentifierArgument = Argument & {\n type: \"identifier\";\n};\n\n/**\n * A type representing a reference to any node function argument.\n */\ntype AnyArgument = NullArgument | BooleanArgument | NumberArgument | StringPlaceholderArgument | IdentifierArgument;\n\n/**\n * Parse an array of argument definitions from the specified tokens array.\n * @param tokens The array tokens to parse the argument definitions from.\n * @param stringArgumentPlaceholders The mapping of string literal node argument placeholders to original values.\n * @param argumentValidator The argument validator function.\n * @param validationFailedMessage The exception message to throw if argument validation fails.\n * @returns An array of argument definitions parsed from the specified tokens array.\n */\nexport function parseArgumentTokens(\n tokens: string[],\n stringArgumentPlaceholders: StringLiteralPlaceholders\n): AnyArgument[] {\n const argumentList: AnyArgument[] = [];\n\n // If the next token is not a '[' or '(' then we have no arguments to parse.\n if (![\"[\", \"(\"].includes(tokens[0])) {\n return argumentList;\n }\n\n // Any lists of arguments will always be wrapped in '[]' for node arguments or '()' for attribute arguments.\n // We are looking for a '[' or '(' opener that wraps the argument tokens and the relevant closer.\n const closingToken = popAndCheck(tokens, [\"[\", \"(\"]) === \"[\" ? \"]\" : \")\";\n\n const argumentListTokens: string[] = [];\n\n // Grab all tokens between the '[' and ']' or '(' and ')'.\n while (tokens.length && tokens[0] !== closingToken) {\n // The next token is part of our arguments list.\n argumentListTokens.push(tokens.shift()!);\n }\n\n // Validate the order of the argument tokens. Each token must either be a ',' or a single argument that satisfies the validator.\n argumentListTokens.forEach((token, index) => {\n // Get whether this token should be an actual argument.\n const shouldBeArgumentToken = !(index & 1);\n\n // If the current token should be an actual argument then validate it, otherwise it should be a ',' token.\n if (shouldBeArgumentToken) {\n // Get the argument definition.\n const argumentDefinition = getArgumentDefinition(token, stringArgumentPlaceholders);\n\n // This is a valid argument!\n argumentList.push(argumentDefinition);\n } else {\n // The current token should be a ',' token.\n if (token !== \",\") {\n throw new Error(`invalid argument list, expected ',' or ']' but got '${token}'`);\n }\n }\n });\n\n // The arguments list should terminate with a ']' or ')' token, depending on the opener.\n popAndCheck(tokens, closingToken);\n\n // Return the arguments.\n return argumentList;\n}\n\n/**\n * Gets an argument value definition.\n * @param token The argument token.\n * @param stringArgumentPlaceholders The mapping of string literal node argument placeholders to original values.\n * @returns An argument value definition.\n */\nfunction getArgumentDefinition(token: string, stringArgumentPlaceholders: StringLiteralPlaceholders): AnyArgument {\n // Check whether the token represents a null value.\n if (token === \"null\") {\n return {\n value: null,\n type: \"null\"\n } as NullArgument;\n }\n\n // Check whether the token represents a boolean value.\n if (token === \"true\" || token === \"false\") {\n return {\n value: token === \"true\",\n type: \"boolean\"\n } as BooleanArgument;\n }\n\n // Check whether the token represents a number value.\n // TODO: Relies on broken isNaN - see MDN.\n // if (!Number.isNaN(token)) {\n if (!isNaN(token as any)) {\n return {\n value: parseFloat(token),\n isInteger: parseFloat(token) === parseInt(token, 10),\n type: \"number\"\n } as NumberArgument;\n }\n\n // Check whether the token is a placeholder (e.g. @@0@@) representing a string literal.\n if (token.match(/^@@\\d+@@$/g)) {\n return {\n value: stringArgumentPlaceholders[token].replace('\\\\\"', '\"'),\n type: \"string\"\n } as StringPlaceholderArgument;\n }\n\n // The only remaining option is that the argument value is an identifier.\n return {\n value: token,\n type: \"identifier\"\n } as IdentifierArgument;\n}\n", "import { NodeAttributeDefinition } from \"../BehaviourTreeDefinition\";\nimport { parseArgumentTokens } from \"./MDSLNodeArgumentParser\";\nimport { StringLiteralPlaceholders } from \"./MDSLUtilities\";\n\n/**\n * A type defining the attribute definitions of a node.\n */\ntype NodeAttributes = {\n while?: NodeAttributeDefinition;\n until?: NodeAttributeDefinition;\n entry?: NodeAttributeDefinition;\n exit?: NodeAttributeDefinition;\n step?: NodeAttributeDefinition;\n};\n\n/**\n * Parse any node attribute definitions from the specified tokens array.\n * @param tokens The array of remaining tokens.\n * @param stringArgumentPlaceholders The mapping of string literal node argument placeholders to original values.\n * @returns An object of attribute definitions defined by any directly following tokens.\n */\nexport function parseAttributeTokens(\n tokens: string[],\n stringArgumentPlaceholders: StringLiteralPlaceholders\n): NodeAttributes {\n const nodeAttributeNames: (keyof NodeAttributes)[] = [\"while\", \"until\", \"entry\", \"exit\", \"step\"];\n\n // Create an object to hold any attributes found.\n const attributes: NodeAttributes = {};\n\n // Try to get the name of the attribute for the next token.\n let nextAttributeName = tokens[0]?.toLowerCase() as keyof NodeAttributes;\n\n // Pull attribute tokens as well as their arguments off of the tokens stack until we have no more.\n while (nodeAttributeNames.includes(nextAttributeName)) {\n // Check to make sure that we have not already created an attribute definition of this type.\n if (attributes[nextAttributeName]) {\n throw new Error(`duplicate attribute '${tokens[0].toUpperCase()}' found for node`);\n }\n\n // Remove the attribute name token from the array of tokens.\n tokens.shift();\n\n // Grab the attribute arguments, assuming the first to be an identifier.\n const [attributeCallIdentifier, ...attributeArguments] = parseArgumentTokens(\n tokens,\n stringArgumentPlaceholders\n );\n\n // The first attribute argument has to be an identifer, this will reference an agent function.\n if (attributeCallIdentifier?.type !== \"identifier\") {\n throw new Error(\"expected agent function name identifier argument for attribute\");\n }\n\n // Any attribute arguments (other than the expected call identifier) must have a type of string, number, boolean or null.\n attributeArguments\n .filter((arg) => arg.type === \"identifier\")\n .forEach((arg) => {\n throw new Error(\n `invalid attribute argument value '${arg.value}', must be string, number, boolean or null`\n );\n });\n\n // Create the attribute definition and add it to the object of attribute definitions found.\n attributes[nextAttributeName] = {\n call: attributeCallIdentifier.value,\n args: attributeArguments.map(({ value }) => value)\n };\n\n // Try to get the next attribute name token, as there could be multiple.\n nextAttributeName = tokens[0]?.toLowerCase() as keyof NodeAttributes;\n }\n\n return attributes;\n}\n", "import {\n ActionNodeDefinition,\n AnyChildNodeDefinition,\n AnyNodeDefinition,\n BranchNodeDefinition,\n ConditionNodeDefinition,\n FailNodeDefinition,\n FlipNodeDefinition,\n LottoNodeDefinition,\n ParallelNodeDefinition,\n RepeatNodeDefinition,\n RetryNodeDefinition,\n RootNodeDefinition,\n SelectorNodeDefinition,\n SequenceNodeDefinition,\n SucceedNodeDefinition,\n WaitNodeDefinition\n} from \"../BehaviourTreeDefinition\";\nimport {\n isCompositeNode,\n isDecoratorNode,\n isLeafNode,\n isNullOrUndefined,\n isRootNode\n} from \"../BehaviourTreeDefinitionUtilities\";\nimport { parseArgumentTokens } from \"./MDSLNodeArgumentParser\";\nimport { parseAttributeTokens } from \"./MDSLNodeAttributeParser\";\nimport {\n StringLiteralPlaceholders,\n parseTokensFromDefinition,\n popAndCheck,\n substituteStringLiterals\n} from \"./MDSLUtilities\";\n\n/**\n * Convert the MDSL tree definition string into an equivalent JSON definition.\n * @param definition The tree definition string as MDSL.\n * @returns The root node JSON definitions.\n */\nexport function convertMDSLToJSON(definition: string): RootNodeDefinition[] {\n // Swap out any node/attribute argument string literals with a placeholder and get a mapping of placeholders to original values as well as the processed definition.\n const { placeholders, processedDefinition } = substituteStringLiterals(definition);\n\n // Parse our definition definition string into an array of raw tokens.\n const tokens = parseTokensFromDefinition(processedDefinition);\n\n return convertTokensToJSONDefinition(tokens, placeholders);\n}\n\n/**\n * Converts the specified tree definition tokens into a JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The root node JSON definitions.\n */\nfunction convertTokensToJSONDefinition(\n tokens: string[],\n stringLiteralPlaceholders: StringLiteralPlaceholders\n): RootNodeDefinition[] {\n // There must be at least 3 tokens for the tree definition to be valid. 'ROOT', '{' and '}'.\n if (tokens.length < 3) {\n throw new Error(\"invalid token count\");\n }\n\n // We should have a matching number of '{' and '}' tokens. If not, then there are scopes that have not been properly closed.\n if (tokens.filter((token) => token === \"{\").length !== tokens.filter((token) => token === \"}\").length) {\n throw new Error(\"scope character mismatch\");\n }\n\n // Create an array of tree stack arrays where root nodes will always be at the botton and the current composite/decorator node at the top.\n // There should be an element in this array for every root node defined and every element should be an array with a root note as the first element.\n // E.g. A definition with two root nodes defined:\n // [\n // [root, lotto, sequence],\n // [root, selector]\n // ]\n const treeStacks: [Partial, ...Partial[]][] = [];\n\n // Create an array of all root node definitions that we create.\n const rootNodes: Partial[] = [];\n\n // A helper function used to push node definitions onto the tree stack.\n const pushNode = (node: AnyNodeDefinition) => {\n // If the node is a root node then we need to create a new tree stack array with the root node at the root.\n if (isRootNode(node)) {\n // We need to double-check that this root node is not the child of another node.\n // We can do this by checking whether the top tree stack is not empty (contains an existing node)\n if (treeStacks[treeStacks.length - 1]?.length) {\n throw new Error(\"a root node cannot be the child of another node\");\n }\n\n // Add the root node definition to our array of all parsed root node definitions.\n rootNodes.push(node);\n\n // Add the root node definition to the root of a new tree stack.\n treeStacks.push([node]);\n\n return;\n }\n\n // All non-root nodes should be pushed after their root nodes so handle cases\n // where we may not have any tree stacks or our top-most tree stack is empty.\n if (!treeStacks.length || !treeStacks[treeStacks.length - 1].length) {\n throw new Error(\"expected root node at base of definition\");\n }\n\n // Get the current tree stack that we are populating.\n const topTreeStack = treeStacks[treeStacks.length - 1];\n\n // Get the top-most node in the current tree stack, this will be a composite/decorator node\n // for which we will populate its children array if composite or setting its child if a decorator.\n const topTreeStackTopNode = topTreeStack[topTreeStack.length - 1] as AnyNodeDefinition;\n\n // If the top-most node in the current root stack is a composite or decorator\n // node then the current node should be added as a child of the top-most node.\n if (isCompositeNode(topTreeStackTopNode)) {\n topTreeStackTopNode.children = topTreeStackTopNode.children || [];\n topTreeStackTopNode.children.push(node);\n } else if (isDecoratorNode(topTreeStackTopNode)) {\n // If the top node already has a child node set then throw an error as a decorator should only have a single child.\n if (topTreeStackTopNode.child) {\n throw new Error(\"a decorator node must only have a single child node\");\n }\n\n topTreeStackTopNode.child = node;\n }\n\n // If the node we are adding is also a composite or decorator node, then we should push it\n // onto the current tree stack, as subsequent nodes will be added as its child/children.\n if (!isLeafNode(node)) {\n topTreeStack.push(node);\n }\n };\n\n // A helper function used to pop the top-most node definition off of the tree stack and return it.\n const popNode = (): AnyNodeDefinition | null => {\n let poppedNode: AnyNodeDefinition | null = null;\n\n // Get the current tree stack that we are populating.\n const topTreeStack = treeStacks[treeStacks.length - 1];\n\n // Pop the top-most node in the current tree stack if there is one.\n if (topTreeStack.length) {\n poppedNode = topTreeStack.pop() as AnyNodeDefinition;\n }\n\n // We don't want any empty tree stacks in our stack of tree stacks.\n if (!topTreeStack.length) {\n treeStacks.pop();\n }\n\n return poppedNode;\n };\n\n // We should keep processing the raw tokens until we run out of them.\n while (tokens.length) {\n // Grab the next token.\n const token = tokens.shift()!;\n\n // How we create the next node depends on the current raw token value.\n switch (token.toUpperCase()) {\n case \"ROOT\": {\n pushNode(createRootNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"SUCCEED\": {\n pushNode(createSucceedNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"FAIL\": {\n pushNode(createFailNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"FLIP\": {\n pushNode(createFlipNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"REPEAT\": {\n pushNode(createRepeatNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"RETRY\": {\n pushNode(createRetryNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"SEQUENCE\": {\n pushNode(createSequenceNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"SELECTOR\": {\n pushNode(createSelectorNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"PARALLEL\": {\n pushNode(createParallelNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"LOTTO\": {\n pushNode(createLottoNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"ACTION\": {\n pushNode(createActionNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"CONDITION\": {\n pushNode(createConditionNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"WAIT\": {\n pushNode(createWaitNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"BRANCH\": {\n pushNode(createBranchNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"}\": {\n // The '}' character closes the current scope and means that we have to pop a node off of the current stack.\n const poppedNode = popNode();\n\n // Now that we have a node definition we can carry out any validation that may require the node to be fully populated.\n if (poppedNode) {\n validatePoppedNode(poppedNode);\n }\n\n break;\n }\n\n default: {\n throw new Error(`unexpected token: ${token}`);\n }\n }\n }\n\n return rootNodes as RootNodeDefinition[];\n}\n\n/**\n * Creates a root node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The root node JSON definition.\n */\nfunction createRootNode(tokens: string[], stringLiteralPlaceholders: StringLiteralPlaceholders): RootNodeDefinition {\n // Create the root node definition.\n let node = {\n type: \"root\",\n id: undefined\n } as RootNodeDefinition;\n\n // Parse any node arguments, we should only have one if any which will be an identifier argument for the root identifier.\n const nodeArguments = parseArgumentTokens(tokens, stringLiteralPlaceholders);\n\n // Check whether any node arguments were defined.\n if (nodeArguments.length) {\n // We should only have one argument, if any, which will be an identifier argument for the root identifier.\n if (nodeArguments.length === 1 && nodeArguments[0].type === \"identifier\") {\n // The root node identifier will be the first and only node argument value.\n node.id = nodeArguments[0].value as string;\n } else {\n throw new Error(\"expected single root name argument\");\n }\n }\n\n // Grab any node attribute definitions and spread them into the node definition.\n node = { ...node, ...parseAttributeTokens(tokens, stringLiteralPlaceholders) };\n\n // This is a decorator node, so we expect an opening '{'.\n popAndCheck(tokens, \"{\");\n\n // Return the root node definition.\n return node;\n}\n\n/**\n * Creates a succeed node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The succeed node JSON definition.\n */\nfunction createSucceedNode(\n tokens: string[],\n stringLiteralPlaceholders: StringLiteralPlaceholders\n): SucceedNodeDefinition {\n const node = {\n type: \"succeed\",\n ...parseAttributeTokens(tokens, stringLiteralPlaceholders)\n } as SucceedNodeDefinition;\n\n // This is a decorator node, so we expect an opening '{'.\n popAndCheck(tokens, \"{\");\n\n // Return the succeed node definition.\n return node;\n}\n\n/**\n * Creates a fail node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The fail node JSON definition.\n */\nfunction createFailNode(tokens: string[], stringLiteralPlaceholders: StringLiteralPlaceholders): FailNodeDefinition {\n const node = {\n type: \"fail\",\n ...parseAttributeTokens(tokens, stringLiteralPlaceholders)\n } as FailNodeDefinition;\n\n // This is a decorator node, so we expect an opening '{'.\n popAndCheck(tokens, \"{\");\n\n // Return the fail node definition.\n return node;\n}\n\n/**\n * Creates a flip node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The flip node JSON definition.\n */\nfunction createFlipNode(tokens: string[], stringLiteralPlaceholders: StringLiteralPlaceholders): FlipNodeDefinition {\n const node = {\n type: \"flip\",\n ...parseAttributeTokens(tokens, stringLiteralPlaceholders)\n } as FlipNodeDefinition;\n\n // This is a decorator node, so we expect an opening '{'.\n popAndCheck(tokens, \"{\");\n\n // Return the flip node definition.\n return node;\n}\n\n/**\n * Creates a repeat node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The repeat node JSON definition.\n */\nfunction createRepeatNode(\n tokens: string[],\n stringLiteralPlaceholders: StringLiteralPlaceholders\n): RepeatNodeDefinition {\n let node = { type: \"repeat\" } as RepeatNodeDefinition;\n\n // Get the node arguments.\n const nodeArguments = parseArgumentTokens(tokens, stringLiteralPlaceholders);\n\n // The arguments of a repeat node are optional. We may have:\n // - No node arguments, in which case the repeat note will iterate indefinitely.\n // - One node argument which will be the explicit number of iterations to make.\n // - Two node arguments which define the min and max iteration bounds from which a random iteration count will be picked.\n if (nodeArguments.length) {\n // All repeat node arguments MUST be of type number and must be integer.\n nodeArguments\n .filter((arg) => arg.type !== \"number\" || !arg.isInteger)\n .forEach(() => {\n throw new Error(`repeat node iteration counts must be integer values`);\n });\n\n // We should have got one or two iteration counts.\n if (nodeArguments.length === 1) {\n // A static iteration count was defined.\n node.iterations = nodeArguments[0].value as number;\n\n // A repeat node must have a positive number of iterations if defined.\n if (node.iterations < 0) {\n throw new Error(\"a repeat node must have a positive number of iterations if defined\");\n }\n } else if (nodeArguments.length === 2) {\n // A minimum and maximum iteration count was defined.\n node.iterations = [nodeArguments[0].value as number, nodeArguments[1].value as number];\n\n // A repeat node must have a positive min and max iteration count if they are defined.\n if (node.iterations[0] < 0 || node.iterations[1] < 0) {\n throw new Error(\"a repeat node must have a positive minimum and maximum iteration count if defined\");\n }\n\n // A repeat node must not have an minimum iteration count that exceeds the maximum iteration count.\n if (node.iterations[0] > node.iterations[1]) {\n throw new Error(\n \"a repeat node must not have a minimum iteration count that exceeds the maximum iteration count\"\n );\n }\n } else {\n // An incorrect number of iteration counts was defined.\n throw new Error(\"invalid number of repeat node iteration count arguments defined\");\n }\n }\n\n // Grab any node attribute definitions and spread them into the node definition.\n node = { ...node, ...parseAttributeTokens(tokens, stringLiteralPlaceholders) };\n\n // This is a decorator node, so we expect an opening '{'.\n popAndCheck(tokens, \"{\");\n\n // Return the repeat node definition.\n return node;\n}\n\n/**\n * Creates a retry node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The retry node JSON definition.\n */\nfunction createRetryNode(tokens: string[], stringLiteralPlaceholders: StringLiteralPlaceholders): RetryNodeDefinition {\n let node = { type: \"retry\" } as RetryNodeDefinition;\n\n // Get the node arguments.\n const nodeArguments = parseArgumentTokens(tokens, stringLiteralPlaceholders);\n\n // The arguments of a retry node are optional. We may have:\n // - No node arguments, in which case the retry note will attempt indefinitely.\n // - One node argument which will be the explicit number of attempts to make.\n // - Two node arguments which define the min and max attempt bounds from which a random attempt count will be picked.\n if (nodeArguments.length) {\n // All retry node arguments MUST be of type number and must be integer.\n nodeArguments\n .filter((arg) => arg.type !== \"number\" || !arg.isInteger)\n .forEach(() => {\n throw new Error(`retry node attempt counts must be integer values`);\n });\n\n // We should have got one or two attempt counts.\n if (nodeArguments.length === 1) {\n // A static attempt count was defined.\n node.attempts = nodeArguments[0].value as number;\n\n // A retry node must have a positive number of attempts if defined.\n if (node.attempts < 0) {\n throw new Error(\"a retry node must have a positive number of attempts if defined\");\n }\n } else if (nodeArguments.length === 2) {\n // A minimum and maximum attempt count was defined.\n node.attempts = [nodeArguments[0].value as number, nodeArguments[1].value as number];\n\n // A retry node must have a positive min and max attempts count if they are defined.\n if (node.attempts[0] < 0 || node.attempts[1] < 0) {\n throw new Error(\"a retry node must have a positive minimum and maximum attempt count if defined\");\n }\n\n // A retry node must not have a minimum attempt count that exceeds the maximum attempt count.\n if (node.attempts[0] > node.attempts[1]) {\n throw new Error(\n \"a retry node must not have a minimum attempt count that exceeds the maximum attempt count\"\n );\n }\n } else {\n // An incorrect number of attempt counts was defined.\n throw new Error(\"invalid number of retry node attempt count arguments defined\");\n }\n }\n\n // Grab any node attribute definitions and spread them into the node definition.\n node = { ...node, ...parseAttributeTokens(tokens, stringLiteralPlaceholders) };\n\n // This is a decorator node, so we expect an opening '{'.\n popAndCheck(tokens, \"{\");\n\n // Return the retry node definition.\n return node;\n}\n\n/**\n * Creates a sequence node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The sequence node JSON definition.\n */\nfunction createSequenceNode(\n tokens: string[],\n stringLiteralPlaceholders: StringLiteralPlaceholders\n): SequenceNodeDefinition {\n const node = {\n type: \"sequence\",\n ...parseAttributeTokens(tokens, stringLiteralPlaceholders)\n } as SequenceNodeDefinition;\n\n // This is a composite node, so we expect an opening '{'.\n popAndCheck(tokens, \"{\");\n\n // Return the sequence node definition.\n return node;\n}\n\n/**\n * Creates a selector node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The selector node JSON definition.\n */\nfunction createSelectorNode(\n tokens: string[],\n stringLiteralPlaceholders: StringLiteralPlaceholders\n): SelectorNodeDefinition {\n const node = {\n type: \"selector\",\n ...parseAttributeTokens(tokens, stringLiteralPlaceholders)\n } as SelectorNodeDefinition;\n\n // This is a composite node, so we expect an opening '{'.\n popAndCheck(tokens, \"{\");\n\n // Return the selector node definition.\n return node;\n}\n\n/**\n * Creates a parallel node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The parallel node JSON definition.\n */\nfunction createParallelNode(\n tokens: string[],\n stringLiteralPlaceholders: StringLiteralPlaceholders\n): ParallelNodeDefinition {\n const node = {\n type: \"parallel\",\n ...parseAttributeTokens(tokens, stringLiteralPlaceholders)\n } as ParallelNodeDefinition;\n\n // This is a composite node, so we expect an opening '{'.\n popAndCheck(tokens, \"{\");\n\n // Return the parallel node definition.\n return node;\n}\n\n/**\n * Creates a lotto node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The lotto node JSON definition.\n */\nfunction createLottoNode(tokens: string[], stringLiteralPlaceholders: StringLiteralPlaceholders): LottoNodeDefinition {\n // If any node arguments have been defined then they must be our weights.\n const nodeArguments = parseArgumentTokens(tokens, stringLiteralPlaceholders);\n\n // All lotto node arguments MUST be of type number and must be positive integers.\n nodeArguments\n .filter((arg) => arg.type !== \"number\" || !arg.isInteger || arg.value < 0)\n .forEach(() => {\n throw new Error(`lotto node weight arguments must be positive integer values`);\n });\n\n const node = {\n type: \"lotto\",\n weights: nodeArguments.length ? nodeArguments.map(({ value }) => value) : undefined,\n ...parseAttributeTokens(tokens, stringLiteralPlaceholders)\n } as LottoNodeDefinition;\n\n // This is a composite node, so we expect an opening '{'.\n popAndCheck(tokens, \"{\");\n\n // Return the lotto node definition.\n return node;\n}\n\n/**\n * Creates an action node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The action node JSON definition.\n */\nfunction createActionNode(\n tokens: string[],\n stringLiteralPlaceholders: StringLiteralPlaceholders\n): ActionNodeDefinition {\n // Parse any node arguments, we should have at least one which will be an identifier argument for the action name\n // and agent function to invoke for the action, all other arguments are to be passed as arguments to that function.\n const [actionNameIdentifier, ...agentFunctionArgs] = parseArgumentTokens(tokens, stringLiteralPlaceholders);\n\n // Our first argument MUST be defined and be an identifier as we require an action name argument.\n if (actionNameIdentifier?.type !== \"identifier\") {\n throw new Error(\"expected action name identifier argument\");\n }\n\n // Only the first argument should have been an identifier, all agent function arguments must be string, number, boolean or null.\n agentFunctionArgs\n .filter((arg) => arg.type === \"identifier\")\n .forEach((arg) => {\n throw new Error(\n `invalid action node argument value '${arg.value}', must be string, number, boolean or null`\n );\n });\n\n // Return the action node definition.\n return {\n type: \"action\",\n call: actionNameIdentifier.value,\n args: agentFunctionArgs.map(({ value }) => value),\n ...parseAttributeTokens(tokens, stringLiteralPlaceholders)\n };\n}\n\n/**\n * Creates a condition node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The condition node JSON definition.\n */\nfunction createConditionNode(\n tokens: string[],\n stringLiteralPlaceholders: StringLiteralPlaceholders\n): ConditionNodeDefinition {\n // Parse any node arguments, we should have at least one which will be an identifier argument for the condition name\n // and agent function to invoke for the condition, all other arguments are to be passed as arguments to that function.\n const [conditionNameIdentifier, ...agentFunctionArgs] = parseArgumentTokens(tokens, stringLiteralPlaceholders);\n\n // Our first argument MUST be defined and be an identifier as we require a condition name argument.\n if (conditionNameIdentifier?.type !== \"identifier\") {\n throw new Error(\"expected condition name identifier argument\");\n }\n\n // Only the first argument should have been an identifier, all agent function arguments must be string, number, boolean or null.\n agentFunctionArgs\n .filter((arg) => arg.type === \"identifier\")\n .forEach((arg) => {\n throw new Error(\n `invalid condition node argument value '${arg.value}', must be string, number, boolean or null`\n );\n });\n\n // Return the condition node definition.\n return {\n type: \"condition\",\n call: conditionNameIdentifier.value,\n args: agentFunctionArgs.map(({ value }) => value),\n ...parseAttributeTokens(tokens, stringLiteralPlaceholders)\n };\n}\n\n/**\n * Creates a wait node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The wait node JSON definition.\n */\nfunction createWaitNode(tokens: string[], stringLiteralPlaceholders: StringLiteralPlaceholders): WaitNodeDefinition {\n let node = { type: \"wait\" } as WaitNodeDefinition;\n\n // Get the node arguments.\n const nodeArguments = parseArgumentTokens(tokens, stringLiteralPlaceholders);\n\n // The arguments of a wait node are optional. We may have:\n // - No node arguments, in which case the wait will be indefinite until it is aborted.\n // - One node argument which will be the explicit duration of the wait.\n // - Two node arguments which define the min and max duration bounds from which a random duration will be picked.\n if (nodeArguments.length) {\n // All wait node arguments MUST be of type number and must be integer.\n nodeArguments\n .filter((arg) => arg.type !== \"number\" || !arg.isInteger)\n .forEach(() => {\n throw new Error(`wait node durations must be integer values`);\n });\n\n // We may have:\n // - One node argument which will be the explicit duration of the wait.\n // - Two node arguments which define the min and max duration bounds from which a random duration will be picked.\n // - Too many arguments, which is not valid.\n if (nodeArguments.length === 1) {\n // An explicit duration was defined.\n node.duration = nodeArguments[0].value as number;\n\n // If an explict duration was defined then it must be a positive number.\n if (node.duration < 0) {\n throw new Error(\"a wait node must have a positive duration\");\n }\n } else if (nodeArguments.length === 2) {\n // Min and max duration bounds were defined from which a random duration will be picked.\n node.duration = [nodeArguments[0].value as number, nodeArguments[1].value as number];\n\n // A wait node must have a positive min and max duration.\n if (node.duration[0] < 0 || node.duration[1] < 0) {\n throw new Error(\"a wait node must have a positive minimum and maximum duration\");\n }\n\n // A wait node must not have a minimum duration that exceeds the maximum duration.\n if (node.duration[0] > node.duration[1]) {\n throw new Error(\"a wait node must not have a minimum duration that exceeds the maximum duration\");\n }\n } else if (nodeArguments.length > 2) {\n // An incorrect number of duration arguments were defined.\n throw new Error(\"invalid number of wait node duration arguments defined\");\n }\n }\n\n // Return the wait node definition.\n return { ...node, ...parseAttributeTokens(tokens, stringLiteralPlaceholders) };\n}\n\n/**\n * Creates a branch node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The branch node JSON definition.\n */\nfunction createBranchNode(\n tokens: string[],\n stringLiteralPlaceholders: StringLiteralPlaceholders\n): BranchNodeDefinition {\n // Parse any node arguments, we should have one which will be an identifier argument for the root ref.\n const nodeArguments = parseArgumentTokens(tokens, stringLiteralPlaceholders);\n\n // We should have only a single identifer argument for a branch node, which is the root ref.\n if (nodeArguments.length !== 1 || nodeArguments[0].type !== \"identifier\") {\n throw new Error(\"expected single branch name argument\");\n }\n\n // Return the branch node definition.\n return { type: \"branch\", ref: nodeArguments[0].value };\n}\n\n/**\n * Validate a fully-populated node definition that was popped off of the tree stack.\n * @param definition The popped node to validate.\n */\nfunction validatePoppedNode(definition: AnyNodeDefinition): void {\n // Decorators MUST have a child defined.\n if (isDecoratorNode(definition) && isNullOrUndefined(definition.child)) {\n throw new Error(`a ${definition.type} node must have a single child node defined`);\n }\n\n // Composites MUST have at least one child defined.\n if (isCompositeNode(definition) && !definition.children?.length) {\n throw new Error(`a ${definition.type} node must have at least a single child node defined`);\n }\n\n // We need to make sure that lotto nodes that have weights defined have a number of weights matching the number of child nodes.\n if (definition.type === \"lotto\") {\n // Check whether a 'weights' property has been defined, if it has we expect it to be an array of weights.\n if (typeof definition.weights !== \"undefined\") {\n // Check that the weights property is an array of positive integers with an element for each child node element.\n if (definition.weights.length !== definition.children.length) {\n throw new Error(\n \"expected a number of weight arguments matching the number of child nodes for lotto node\"\n );\n }\n }\n }\n}\n", "import { RootNodeDefinition } from \"./BehaviourTreeDefinition\";\nimport { flattenDefinition, isBranchNode, isInteger } from \"./BehaviourTreeDefinitionUtilities\";\nimport { convertMDSLToJSON } from \"./mdsl/MDSLDefinitionParser\";\n\n/**\n * An object representing the result of validating a tree definition.\n */\nexport type DefinitionValidationResult = {\n /**\n * A flag defining whether validation succeeded.\n */\n succeeded: boolean;\n /**\n * A string containing the error message if validation did not succeed.\n */\n errorMessage?: string;\n /**\n * The definition as json if the validation was successful, or undefined if validation did not succeed.\n */\n json?: RootNodeDefinition[];\n};\n\n/**\n * Validates the specified behaviour tree definition in the form of JSON or MDSL, not taking any globally registered subtrees into consideration.\n * @param definition The behaviour tree definition in the form of JSON or MDSL.\n * @returns An object representing the result of validating the given tree definition.\n */\nexport function validateDefinition(definition: any): DefinitionValidationResult {\n // The definition must be defined.\n if (definition === null || typeof definition === \"undefined\") {\n return createValidationFailureResult(\"definition is null or undefined\");\n }\n\n // We are expecting a definition in one of three different forms:\n // - A string which we will assume is MDSL and we will parse this to JSON before validation.\n // - An array which we will assume is an array of root node definitions with at least one being the primary root node (no 'id' property)\n // - An object which we will assume is the primary root node and should not have an 'id' property.\n if (typeof definition === \"string\") {\n // The definition is a string which we can assume is MDSL, so attempt to validate it.\n return validateMDSLDefinition(definition);\n } else if (typeof definition === \"object\") {\n // The definition will either be an array (of root node definitions) or an object (the single primary root node definition).\n return validateJSONDefinition(definition);\n } else {\n return createValidationFailureResult(`unexpected definition type of '${typeof definition}'`);\n }\n}\n\n/**\n * Validates the specified behaviour tree definition in the form of MDSL.\n * @param definition The behaviour tree definition in the form of MDSL.\n * @returns An object representing the result of validating the given tree definition.\n */\nfunction validateMDSLDefinition(definition: string): DefinitionValidationResult {\n let rootNodeDefinitions;\n\n // The first thing the we need to do is to attempt to convert our MDSL into JSON.\n try {\n // The definition is a string which we can assume is MDSL, so attempt to parse it to a JSON definition in the form of an array of root node definitions.\n rootNodeDefinitions = convertMDSLToJSON(definition);\n } catch (exception) {\n // We failed to parse the JSON from the MDSL, this is likely to be the result of it not being a valid MDSL string.\n return createValidationFailureResult((exception as Error).message);\n }\n\n // Unpack all of the root node definitions into arrays of main ('id' defined) and sub ('id' not defined) root node definitions.\n const mainRootNodeDefinitions = rootNodeDefinitions.filter(({ id }) => typeof id === \"undefined\");\n const subRootNodeDefinitions = rootNodeDefinitions.filter(({ id }) => typeof id === \"string\" && id.length > 0);\n\n // We should ALWAYS have exactly one root node definition without an 'id' property defined, which is out main root node definition.\n if (mainRootNodeDefinitions.length !== 1) {\n return createValidationFailureResult(\n \"expected single unnamed root node at base of definition to act as main root\"\n );\n }\n\n // We should never have duplicate 'id' properties across our sub root node definitions.\n const subRootNodeIdenitifers: string[] = [];\n for (const { id } of subRootNodeDefinitions) {\n // Have we already come across this 'id' property value?\n if (subRootNodeIdenitifers.includes(id!)) {\n return createValidationFailureResult(`multiple root nodes found with duplicate name '${id}'`);\n }\n\n subRootNodeIdenitifers.push(id!);\n }\n\n try {\n // Validate our branch -> subtree links and check for any circular dependencies, we don't care about checking for broken subtree links here.\n validateBranchSubtreeLinks(rootNodeDefinitions, false);\n } catch (exception) {\n return createValidationFailureResult((exception as Error).message);\n }\n\n // Our definition was valid!\n return {\n succeeded: true,\n json: rootNodeDefinitions\n };\n}\n\n/**\n * Validates the specified behaviour tree definition in the form of JSON.\n * @param definition The behaviour tree definition in the form of JSON.\n * @returns An object representing the result of validating the given tree definition.\n */\nexport function validateJSONDefinition(\n definition: RootNodeDefinition | RootNodeDefinition[]\n): DefinitionValidationResult {\n // The definition will either be an array (of root node definitions) or an object (the single primary root node definition).\n const rootNodeDefinitions = Array.isArray(definition) ? definition : [definition];\n\n // Iterate over our array of root nodes and call validateNode for each, passing an initial depth of 0, wrapped in a try catch to handle validation failures.\n try {\n rootNodeDefinitions.forEach((rootNodeDefinition) => validateNode(rootNodeDefinition, 0));\n } catch (error) {\n // Handle cases where we have caught a thrown Error and return a failure result with the error message.\n if (error instanceof Error) {\n return createValidationFailureResult(error.message);\n }\n\n // No idea what happened here!\n return createValidationFailureResult(`unexpected error: ${error}`);\n }\n\n // Unpack all of the root node definitions into arrays of main ('id' defined) and sub ('id' not defined) root node definitions.\n const mainRootNodeDefinitions = rootNodeDefinitions.filter(({ id }) => typeof id === \"undefined\");\n const subRootNodeDefinitions = rootNodeDefinitions.filter(({ id }) => typeof id === \"string\" && id.length > 0);\n\n // We should ALWAYS have exactly one root node definition without an 'id' property defined, which is out main root node definition.\n if (mainRootNodeDefinitions.length !== 1) {\n return createValidationFailureResult(\n \"expected single root node without 'id' property defined to act as main root\"\n );\n }\n\n // We should never have duplicate 'id' properties across our sub root node definitions.\n const subRootNodeIdenitifers: string[] = [];\n for (const { id } of subRootNodeDefinitions) {\n // Have we already come across this 'id' property value?\n if (subRootNodeIdenitifers.includes(id!)) {\n return createValidationFailureResult(\n `multiple root nodes found with duplicate 'id' property value of '${id}'`\n );\n }\n\n subRootNodeIdenitifers.push(id!);\n }\n\n try {\n // Validate our branch -> subtree links and check for any circular dependencies, we don't care about checking for broken subtree links here.\n validateBranchSubtreeLinks(rootNodeDefinitions, false);\n } catch (exception) {\n return createValidationFailureResult((exception as Error).message);\n }\n\n // Our definition was valid!\n return {\n succeeded: true,\n json: rootNodeDefinitions\n };\n}\n\n/**\n * Validates the branch -> subtree links across all provided root node definitions.\n * This will not consider branch nodes that reference any globally registered subtrees unless includesGlobalSubtrees\n * is set to true, in which case we will also verify that there are no broken branch -> subtree links.\n * @param rootNodeDefinitions The array of root node definitions.\n * @param includesGlobalSubtrees A flag defining whether the array includes all global subtree root node definitions.\n */\nexport function validateBranchSubtreeLinks(rootNodeDefinitions: RootNodeDefinition[], includesGlobalSubtrees: boolean) {\n // Create a mapping of root node identifiers to other root nodes that they reference via branch nodes.\n // Below is an example of a mapping that includes a circular dependency (root => a => b => c => a)\n // [{ refs: [\"a\", \"b\"] }, { id: \"a\", refs: [\"b\"] }, { id: \"b\", refs: [\"c\"] }, { id: \"c\", refs: [\"a\"] }]\n const rootNodeMappings: { id: string | undefined; refs: string[] }[] = rootNodeDefinitions.map(\n (rootNodeDefinition) => ({\n id: rootNodeDefinition.id,\n refs: flattenDefinition(rootNodeDefinition)\n .filter(isBranchNode)\n .map(({ ref }) => ref)\n })\n );\n\n // A recursive function to walk through the mappings, keeping track of which root nodes we have visited in the form of a path of root node identifiers.\n const followRefs = (mapping: { id: string | undefined; refs: string[] }, path: (string | undefined)[] = []) => {\n // Have we found a circular dependency?\n if (path.includes(mapping.id)) {\n // We found a circular dependency! Get the bad path of root node identifiers.\n const badPath = [...path, mapping.id];\n\n // Create the formatted path value. [undefined, \"a\", \"b\", \"c\", \"a\"] would be formatted as \"a -> b -> c -> a\".\n const badPathFormatted = badPath.filter((element) => !!element).join(\" => \");\n\n // No need to continue, we found a circular dependency.\n throw new Error(`circular dependency found in branch node references: ${badPathFormatted}`);\n }\n\n for (const ref of mapping.refs) {\n // Find the mapping for the root node with an identifer matching the current ref.\n const subMapping = rootNodeMappings.find(({ id }) => id === ref);\n\n // We may not have a mapping for this ref, which is normal when we aren't considering all globally registered subtrees.\n if (subMapping) {\n followRefs(subMapping, [...path, mapping.id]);\n } else if (includesGlobalSubtrees) {\n // We found a reference to a root node that doesn't exist, which is a problem seeing as the root node definitons includes all globally registered subtrees.\n throw new Error(\n mapping.id\n ? `subtree '${mapping.id}' has branch node that references root node '${ref}' which has not been defined`\n : `primary tree has branch node that references root node '${ref}' which has not been defined`\n );\n }\n }\n };\n\n // Start looking for circular dependencies and broken references from the primary root node definition.\n followRefs(rootNodeMappings.find((mapping) => typeof mapping.id === \"undefined\")!);\n}\n\n/**\n * Validate an object that we expect to be a node definition.\n * @param definition An object that we expect to be a node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateNode(definition: any, depth: number): void {\n // Every node must be valid object and have a non-empty 'type' string property.\n if (typeof definition !== \"object\" || typeof definition.type !== \"string\" || definition.type.length === 0) {\n throw new Error(\n `node definition is not an object or 'type' property is not a non-empty string at depth '${depth}'`\n );\n }\n\n // How we validate this node definition will depend on its type.\n switch (definition.type) {\n case \"action\":\n validateActionNode(definition, depth);\n break;\n\n case \"condition\":\n validateConditionNode(definition, depth);\n break;\n\n case \"wait\":\n validateWaitNode(definition, depth);\n break;\n\n case \"branch\":\n validateBranchNode(definition, depth);\n break;\n\n case \"root\":\n validateRootNode(definition, depth);\n break;\n\n case \"succeed\":\n validateSucceedNode(definition, depth);\n break;\n\n case \"fail\":\n validateFailNode(definition, depth);\n break;\n\n case \"flip\":\n validateFlipNode(definition, depth);\n break;\n\n case \"repeat\":\n validateRepeatNode(definition, depth);\n break;\n\n case \"retry\":\n validateRetryNode(definition, depth);\n break;\n\n case \"sequence\":\n validateSequenceNode(definition, depth);\n break;\n\n case \"selector\":\n validateSelectorNode(definition, depth);\n break;\n\n case \"parallel\":\n validateParallelNode(definition, depth);\n break;\n\n case \"lotto\":\n validateLottoNode(definition, depth);\n break;\n\n default:\n throw new Error(`unexpected node type of '${definition.type}' at depth '${depth}'`);\n }\n}\n\n/**\n * Validate any attributes for a given node definition.\n * @param definition The node definition.\n * @param depth The depth of the node in the behaviour tree definition.\n */\nfunction validateNodeAttributes(definition: any, depth: number): void {\n // Validate each of the attribute types for this node.\n [\"while\", \"until\", \"entry\", \"exit\", \"step\"].forEach((attributeName) => {\n // Attempt to grab the definition for the current attribute from the node definition.\n const attributeDefinition = definition[attributeName];\n\n // All node attributes are optional, so there is nothing to do if the current attribute is not defined.\n if (typeof attributeDefinition === \"undefined\") {\n return;\n }\n\n // The attribute definition must be an object.\n if (typeof attributeDefinition !== \"object\") {\n throw new Error(\n `expected attribute '${attributeName}' to be an object for '${definition.type}' node at depth '${depth}'`\n );\n }\n\n // The 'call' property must be defined for any attribute definition.\n if (typeof attributeDefinition.call !== \"string\" || attributeDefinition.call.length === 0) {\n throw new Error(\n `expected 'call' property for attribute '${attributeName}' to be a non-empty string for '${definition.type}' node at depth '${depth}'`\n );\n }\n\n // If any node attribute arguments have been defined then they must have been defined in an array.\n if (typeof attributeDefinition.args !== \"undefined\" && !Array.isArray(attributeDefinition.args)) {\n throw new Error(\n `expected 'args' property for attribute '${attributeName}' to be an array for '${definition.type}' node at depth '${depth}'`\n );\n }\n });\n}\n\n/**\n * Validate an object that we expect to be a root node definition.\n * @param definition An object that we expect to be a root node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateRootNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"root\") {\n throw new Error(\"expected node type of 'root' for root node\");\n }\n\n // A root node cannot be the child of another node.\n if (depth > 0) {\n throw new Error(\"a root node cannot be the child of another node\");\n }\n\n // Check that, if the root node 'id' property is defined, it is a non-empty string.\n if (typeof definition.id !== \"undefined\" && (typeof definition.id !== \"string\" || definition.id.length === 0)) {\n throw new Error(\"expected non-empty string for 'id' property if defined for root node\");\n }\n\n // A root node is a decorator node, so must have a child node defined.\n if (typeof definition.child === \"undefined\") {\n throw new Error(\"expected property 'child' to be defined for root node\");\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n\n // Validate the child node of this decorator node.\n validateNode(definition.child, depth + 1);\n}\n\n/**\n * Validate an object that we expect to be a succeed node definition.\n * @param definition An object that we expect to be a succeed node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateSucceedNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"succeed\") {\n throw new Error(`expected node type of 'succeed' for succeed node at depth '${depth}'`);\n }\n\n // A succeed node is a decorator node, so must have a child node defined.\n if (typeof definition.child === \"undefined\") {\n throw new Error(`expected property 'child' to be defined for succeed node at depth '${depth}'`);\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n\n // Validate the child node of this decorator node.\n validateNode(definition.child, depth + 1);\n}\n\n/**\n * Validate an object that we expect to be a fail node definition.\n * @param definition An object that we expect to be a fail node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateFailNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"fail\") {\n throw new Error(`expected node type of 'fail' for fail node at depth '${depth}'`);\n }\n\n // A fail node is a decorator node, so must have a child node defined.\n if (typeof definition.child === \"undefined\") {\n throw new Error(`expected property 'child' to be defined for fail node at depth '${depth}'`);\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n\n // Validate the child node of this decorator node.\n validateNode(definition.child, depth + 1);\n}\n\n/**\n * Validate an object that we expect to be a flip node definition.\n * @param definition An object that we expect to be a flip node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateFlipNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"flip\") {\n throw new Error(`expected node type of 'flip' for flip node at depth '${depth}'`);\n }\n\n // A flip node is a decorator node, so must have a child node defined.\n if (typeof definition.child === \"undefined\") {\n throw new Error(`expected property 'child' to be defined for flip node at depth '${depth}'`);\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n\n // Validate the child node of this decorator node.\n validateNode(definition.child, depth + 1);\n}\n\n/**\n * Validate an object that we expect to be a repeat node definition.\n * @param definition An object that we expect to be a repeat node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateRepeatNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"repeat\") {\n throw new Error(`expected node type of 'repeat' for repeat node at depth '${depth}'`);\n }\n\n // A repeat node is a decorator node, so must have a child node defined.\n if (typeof definition.child === \"undefined\") {\n throw new Error(`expected property 'child' to be defined for repeat node at depth '${depth}'`);\n }\n\n // Check whether an 'iterations' property has been defined, it may not have been if this node is to repeat indefinitely.\n if (typeof definition.iterations !== \"undefined\") {\n if (Array.isArray(definition.iterations)) {\n // Check whether any elements of the array are not integer values.\n const containsNonInteger = !!definition.iterations.filter((value: unknown) => !isInteger(value)).length;\n\n // If the 'iterations' property is an array then it MUST contain two integer values.\n if (definition.iterations.length !== 2 || containsNonInteger) {\n throw new Error(\n `expected array containing two integer values for 'iterations' property if defined for repeat node at depth '${depth}'`\n );\n }\n\n // A repeat node must have a positive min and max iterations count if they are defined.\n if (definition.iterations[0] < 0 || definition.iterations[1] < 0) {\n throw new Error(\n `expected positive minimum and maximum iterations count for 'iterations' property if defined for repeat node at depth '${depth}'`\n );\n }\n\n // A repeat node must not have a minimum iterations count that exceeds the maximum iterations count.\n if (definition.iterations[0] > definition.iterations[1]) {\n throw new Error(\n `expected minimum iterations count that does not exceed the maximum iterations count for 'iterations' property if defined for repeat node at depth '${depth}'`\n );\n }\n } else if (isInteger(definition.iterations)) {\n // A repeat node must have a positive number of iterations if defined.\n if (definition.iterations < 0) {\n throw new Error(\n `expected positive iterations count for 'iterations' property if defined for repeat node at depth '${depth}'`\n );\n }\n } else {\n throw new Error(\n `expected integer value or array containing two integer values for 'iterations' property if defined for repeat node at depth '${depth}'`\n );\n }\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n\n // Validate the child node of this decorator node.\n validateNode(definition.child, depth + 1);\n}\n\n/**\n * Validate an object that we expect to be a retry node definition.\n * @param definition An object that we expect to be a retry node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateRetryNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"retry\") {\n throw new Error(`expected node type of 'retry' for retry node at depth '${depth}'`);\n }\n\n // A retry node is a decorator node, so must have a child node defined.\n if (typeof definition.child === \"undefined\") {\n throw new Error(`expected property 'child' to be defined for retry node at depth '${depth}'`);\n }\n\n // Check whether an 'attempts' property has been defined, it may not have been if this node is to retry indefinitely.\n if (typeof definition.attempts !== \"undefined\") {\n if (Array.isArray(definition.attempts)) {\n // Check whether any elements of the array are not integer values.\n const containsNonInteger = !!definition.attempts.filter((value: unknown) => !isInteger(value)).length;\n\n // If the 'attempts' property is an array then it MUST contain two integer values.\n if (definition.attempts.length !== 2 || containsNonInteger) {\n throw new Error(\n `expected array containing two integer values for 'attempts' property if defined for retry node at depth '${depth}'`\n );\n }\n\n // A retry node must have a positive min and max attempts count if they are defined.\n if (definition.attempts[0] < 0 || definition.attempts[1] < 0) {\n throw new Error(\n `expected positive minimum and maximum attempts count for 'attempts' property if defined for retry node at depth '${depth}'`\n );\n }\n\n // A retry node must not have a minimum attempts count that exceeds the maximum attempts count.\n if (definition.attempts[0] > definition.attempts[1]) {\n throw new Error(\n `expected minimum attempts count that does not exceed the maximum attempts count for 'attempts' property if defined for retry node at depth '${depth}'`\n );\n }\n } else if (isInteger(definition.attempts)) {\n // A retry node must have a positive number of attempts if defined.\n if (definition.attempts < 0) {\n throw new Error(\n `expected positive attempts count for 'attempts' property if defined for retry node at depth '${depth}'`\n );\n }\n } else {\n throw new Error(\n `expected integer value or array containing two integer values for 'attempts' property if defined for retry node at depth '${depth}'`\n );\n }\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n\n // Validate the child node of this decorator node.\n validateNode(definition.child, depth + 1);\n}\n\n/**\n * Validate an object that we expect to be a branch node definition.\n * @param definition An object that we expect to be a branch node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateBranchNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"branch\") {\n throw new Error(`expected node type of 'branch' for branch node at depth '${depth}'`);\n }\n\n // Check that the branch node 'ref' property is defined and is a non-empty string.\n if (typeof definition.ref !== \"string\" || definition.ref.length === 0) {\n throw new Error(`expected non-empty string for 'ref' property for branch node at depth '${depth}'`);\n }\n\n // It is invalid to define guard attributes for a branch node as they should be defined on the referenced root node.\n [\"while\", \"until\"].forEach((attributeName) => {\n if (typeof definition[attributeName] !== \"undefined\") {\n throw new Error(\n `guards should not be defined for branch nodes but guard '${attributeName}' was defined for branch node at depth '${depth}'`\n );\n }\n });\n\n // It is invalid to define callback attributes for a branch node as they should be defined on the referenced root node.\n [\"entry\", \"exit\", \"step\"].forEach((attributeName) => {\n if (typeof definition[attributeName] !== \"undefined\") {\n throw new Error(\n `callbacks should not be defined for branch nodes but callback '${attributeName}' was defined for branch node at depth '${depth}'`\n );\n }\n });\n}\n\n/**\n * Validate an object that we expect to be a action node definition.\n * @param definition An object that we expect to be a action node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateActionNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"action\") {\n throw new Error(`expected node type of 'action' for action node at depth '${depth}'`);\n }\n\n // The 'call' property must be defined for a action node definition.\n if (typeof definition.call !== \"string\" || definition.call.length === 0) {\n throw new Error(`expected non-empty string for 'call' property of action node at depth '${depth}'`);\n }\n\n // If any action function arguments have been defined then they must have been defined in an array.\n if (typeof definition.args !== \"undefined\" && !Array.isArray(definition.args)) {\n throw new Error(`expected array for 'args' property if defined for action node at depth '${depth}'`);\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n}\n\n/**\n * Validate an object that we expect to be a condition node definition.\n * @param definition An object that we expect to be a condition node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateConditionNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"condition\") {\n throw new Error(`expected node type of 'condition' for condition node at depth '${depth}'`);\n }\n\n // The 'call' property must be defined for a condition node definition.\n if (typeof definition.call !== \"string\" || definition.call.length === 0) {\n throw new Error(`expected non-empty string for 'call' property of condition node at depth '${depth}'`);\n }\n\n // If any condition function arguments have been defined then they must have been defined in an array.\n if (typeof definition.args !== \"undefined\" && !Array.isArray(definition.args)) {\n throw new Error(`expected array for 'args' property if defined for condition node at depth '${depth}'`);\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n}\n\n/**\n * Validate an object that we expect to be a wait node definition.\n * @param definition An object that we expect to be a wait node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateWaitNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"wait\") {\n throw new Error(`expected node type of 'wait' for wait node at depth '${depth}'`);\n }\n\n // Check whether a 'duration' property has been defined, it may not have been if this node is to wait indefinitely.\n if (typeof definition.duration !== \"undefined\") {\n if (Array.isArray(definition.duration)) {\n // Check whether any elements of the array are not integer values.\n const containsNonInteger = !!definition.duration.filter((value: unknown) => !isInteger(value)).length;\n\n // If the 'duration' property is an array then it MUST contain two integer values.\n if (definition.duration.length !== 2 || containsNonInteger) {\n throw new Error(\n `expected array containing two integer values for 'duration' property if defined for wait node at depth '${depth}'`\n );\n }\n\n // A wait node must have a positive min and max duration value if they are defined.\n if (definition.duration[0] < 0 || definition.duration[1] < 0) {\n throw new Error(\n `expected positive minimum and maximum duration for 'duration' property if defined for wait node at depth '${depth}'`\n );\n }\n\n // A wait node must not have a minimum duration value that exceeds the maximum duration value.\n if (definition.duration[0] > definition.duration[1]) {\n throw new Error(\n `expected minimum duration value that does not exceed the maximum duration value for 'duration' property if defined for wait node at depth '${depth}'`\n );\n }\n } else if (isInteger(definition.duration)) {\n // A wait node must have a positive duration value if defined.\n if (definition.duration < 0) {\n throw new Error(\n `expected positive duration value for 'duration' property if defined for wait node at depth '${depth}'`\n );\n }\n } else {\n throw new Error(\n `expected integer value or array containing two integer values for 'duration' property if defined for wait node at depth '${depth}'`\n );\n }\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n}\n\n/**\n * Validate an object that we expect to be a sequence node definition.\n * @param definition An object that we expect to be a sequence node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateSequenceNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"sequence\") {\n throw new Error(`expected node type of 'sequence' for sequence node at depth '${depth}'`);\n }\n\n // A sequence node is a composite node, so must have a children nodes array defined.\n if (!Array.isArray(definition.children) || definition.children.length === 0) {\n throw new Error(`expected non-empty 'children' array to be defined for sequence node at depth '${depth}'`);\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n\n // Validate the child nodes of this composite node.\n definition.children.forEach((child: any) => validateNode(child, depth + 1));\n}\n\n/**\n * Validate an object that we expect to be a selector node definition.\n * @param definition An object that we expect to be a selector node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateSelectorNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"selector\") {\n throw new Error(`expected node type of 'selector' for selector node at depth '${depth}'`);\n }\n\n // A selector node is a composite node, so must have a children nodes array defined.\n if (!Array.isArray(definition.children) || definition.children.length === 0) {\n throw new Error(`expected non-empty 'children' array to be defined for selector node at depth '${depth}'`);\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n\n // Validate the child nodes of this composite node.\n definition.children.forEach((child: any) => validateNode(child, depth + 1));\n}\n\n/**\n * Validate an object that we expect to be a parallel node definition.\n * @param definition An object that we expect to be a parallel node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateParallelNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"parallel\") {\n throw new Error(`expected node type of 'parallel' for parallel node at depth '${depth}'`);\n }\n\n // A parallel node is a composite node, so must have a children nodes array defined.\n if (!Array.isArray(definition.children) || definition.children.length === 0) {\n throw new Error(`expected non-empty 'children' array to be defined for parallel node at depth '${depth}'`);\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n\n // Validate the child nodes of this composite node.\n definition.children.forEach((child: any) => validateNode(child, depth + 1));\n}\n\n/**\n * Validate an object that we expect to be a lotto node definition.\n * @param definition An object that we expect to be a lotto node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateLottoNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"lotto\") {\n throw new Error(`expected node type of 'lotto' for lotto node at depth '${depth}'`);\n }\n\n // A lotto node is a composite node, so must have a children nodes array defined.\n if (!Array.isArray(definition.children) || definition.children.length === 0) {\n throw new Error(`expected non-empty 'children' array to be defined for lotto node at depth '${depth}'`);\n }\n\n // Check whether a 'weights' property has been defined, if it has we expect it to be an array of weights.\n if (typeof definition.weights !== \"undefined\") {\n // Check that the weights property is an array of positive integers with an element for each child node element.\n if (\n !Array.isArray(definition.weights) ||\n definition.weights.length !== definition.children.length ||\n definition.weights.filter((value: unknown) => !isInteger(value)).length ||\n definition.weights.filter((value: number) => value < 0).length\n ) {\n throw new Error(\n `expected an array of positive integer weight values with a length matching the number of child nodes for 'weights' property if defined for lotto node at depth '${depth}'`\n );\n }\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n\n // Validate the child nodes of this composite node.\n definition.children.forEach((child: any) => validateNode(child, depth + 1));\n}\n\n/**\n * A helper function to create a failure validation result with the given error message.\n * @param errorMessage The validation failure error message.\n * @returns A failure validation result with the given error message.\n */\nfunction createValidationFailureResult(errorMessage: string): DefinitionValidationResult {\n return { succeeded: false, errorMessage };\n}\n", "import { ActionResult, Agent, GlobalFunction } from \"./Agent\";\nimport { RootNodeDefinition } from \"./BehaviourTreeDefinition\";\n\nexport type InvokerFunction = (args: any[]) => ActionResult;\n\n/**\n * A singleton used to store and lookup registered functions and subtrees.\n */\nexport default class Lookup {\n /**\n * The object holding any registered functions keyed on function name.\n */\n private static functionTable: { [key: string]: GlobalFunction } = {};\n /**\n * The object holding any registered subtree root node definitions keyed on tree name.\n */\n private static subtreeTable: { [key: string]: RootNodeDefinition } = {};\n\n /**\n * Gets the function with the specified name.\n * @param name The name of the function.\n * @returns The function with the specified name.\n */\n public static getFunc(name: string): GlobalFunction {\n return this.functionTable[name];\n }\n\n /**\n * Sets the function with the specified name for later lookup.\n * @param name The name of the function.\n * @param func The function.\n */\n public static setFunc(name: string, func: GlobalFunction): void {\n this.functionTable[name] = func;\n }\n\n /**\n * Gets the function invoker for the specified agent and function name.\n * If a function with the specified name exists on the agent object then it will\n * be returned, otherwise we will then check the registered functions for a match.\n * @param agent The agent instance that this behaviour tree is modelling behaviour for.\n * @param name The function name.\n * @returns The function invoker for the specified agent and function name.\n */\n static getFuncInvoker(agent: Agent, name: string): InvokerFunction | null {\n // Check whether the agent contains the specified function.\n const foundOnAgent = agent[name];\n if (foundOnAgent && typeof foundOnAgent === \"function\") {\n return (args: any[]): boolean | ActionResult => foundOnAgent.apply(agent, args);\n }\n\n // The agent does not contain the specified function but it may have been registered at some point.\n if (this.functionTable[name] && typeof this.functionTable[name] === \"function\") {\n return (args: any[]) => this.functionTable[name](agent, ...args.map((arg) => arg.value));\n }\n\n // We have no function to invoke.\n return null;\n }\n\n /**\n * Gets all registered subtree root node definitions.\n */\n static getSubtrees(): { [key: string]: RootNodeDefinition } {\n return this.subtreeTable;\n }\n\n /**\n * Sets the subtree with the specified name for later lookup.\n * @param name The name of the subtree.\n * @param subtree The subtree.\n */\n static setSubtree(name: string, subtree: RootNodeDefinition) {\n this.subtreeTable[name] = subtree;\n }\n\n /**\n * Removes the registered function or subtree with the specified name.\n * @param name The name of the registered function or subtree.\n */\n static remove(name: string) {\n delete this.functionTable[name];\n delete this.subtreeTable[name];\n }\n\n /**\n * Remove all registered functions and subtrees.\n */\n static empty() {\n this.functionTable = {};\n this.subtreeTable = {};\n }\n}\n", "import Node from \"../../nodes/Node\";\n\n/**\n * An exception thrown when evaluating node guard path conditions and a conditions fails.\n */\nexport default class GuardUnsatisifedException extends Error {\n /**\n * @param source The node at which a guard condition failed.\n */\n constructor(private source: Node) {\n super(\"A guard path condition has failed\");\n }\n\n /**\n * Gets whether the specified node is the node at which a guard condition failed.\n * @param node The node to check against the source node.\n * @returns Whether the specified node is the node at which a guard condition failed.\n */\n isSourceNode = (node: Node) => node === this.source;\n}\n", "import { Agent } from \"../../Agent\";\nimport Guard from \"./Guard\";\nimport Node from \"../../nodes/Node\";\nimport GuardUnsatisifedException from \"./GuardUnsatisifedException\";\n\nexport type GuardPathPart = {\n node: Node;\n guards: Guard[];\n};\n\n/**\n * Represents a path of node guards along a root-to-leaf tree path.\n */\nexport default class GuardPath {\n /**\n * @param nodes An array of objects defining a node instance -> guard link, ordered by node depth.\n */\n constructor(private nodes: GuardPathPart[]) {}\n\n /**\n * Evaluate guard conditions for all guards in the tree path, moving outwards from the root.\n * @param agent The agent, required for guard evaluation.\n * @returns An evaluation results object.\n */\n evaluate = (agent: Agent) => {\n // We need to evaluate guard conditions for nodes up the tree, moving outwards from the root.\n for (const details of this.nodes) {\n // There can be multiple guards per node.\n for (const guard of details.guards) {\n // Check whether the guard condition passes, and throw an exception if not.\n if (!guard.isSatisfied(agent)) {\n throw new GuardUnsatisifedException(details.node);\n }\n }\n }\n };\n}\n", "import { BehaviourTreeOptions } from \"../BehaviourTreeOptions\";\nimport State, { AnyState } from \"../State\";\nimport { Agent } from \"../Agent\";\nimport Leaf from \"./leaf/Leaf\";\nimport Attribute from \"../attributes/Attribute\";\nimport Entry from \"../attributes/callbacks/Entry\";\nimport Exit from \"../attributes/callbacks/Exit\";\nimport Step from \"../attributes/callbacks/Step\";\nimport Guard from \"../attributes/guards/Guard\";\nimport GuardPath from \"../attributes/guards/GuardPath\";\nimport GuardUnsatisifedException from \"../attributes/guards/GuardUnsatisifedException\";\n\n/**\n * A base node.\n */\nexport default abstract class Node {\n /**\n * The node uid.\n */\n private readonly uid: string = createNodeUid();\n /**\n * The node state.\n */\n private state: AnyState = State.READY;\n /**\n * The guard path to evaluate as part of a node update.\n */\n private guardPath: GuardPath | undefined;\n\n /**\n * @param type The node type.\n * @param attributes The node attributes.\n * @param args The node argument definitions.\n */\n constructor(private type: string, private attributes: Attribute[], private args: any[]) {}\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected abstract onUpdate(agent: Agent, options: BehaviourTreeOptions): void;\n\n /**\n * Gets the name of the node.\n */\n public abstract getName(): string;\n\n /**\n * Gets whether this node is a leaf node.\n */\n public abstract isLeafNode: () => this is Leaf;\n\n /**\n * Gets/Sets the state of the node.\n */\n getState = (): AnyState => this.state;\n setState = (value: AnyState): void => {\n this.state = value;\n };\n\n /**\n * Gets the unique id of the node.\n */\n getUid = () => this.uid;\n\n /**\n * Gets the type of the node.\n */\n getType = () => this.type;\n\n /**\n * Gets the node attributes.\n */\n getAttributes = () => this.attributes;\n\n /**\n * Gets the node arguments.\n */\n getArguments = () => this.args;\n\n /**\n * Gets the node attribute with the specified type, or null if it does not exist.\n */\n getAttribute(type: \"entry\" | \"ENTRY\"): Entry;\n getAttribute(type: \"exit\" | \"EXIT\"): Exit;\n getAttribute(type: \"step\" | \"STEP\"): Step;\n getAttribute(type: string): Attribute {\n return (\n this.getAttributes().filter((decorator) => decorator.type.toUpperCase() === type.toUpperCase())[0] || null\n );\n }\n\n /**\n * Gets the node attributes.\n */\n getGuardAttributes = (): Guard[] => this.getAttributes().filter((decorator) => decorator.isGuard()) as Guard[];\n\n /**\n * Sets the guard path to evaluate as part of a node update.\n */\n setGuardPath = (value: GuardPath) => (this.guardPath = value);\n\n /**\n * Gets whether a guard path is assigned to this node.\n */\n hasGuardPath = () => !!this.guardPath;\n\n /**\n * Gets whether this node is in the specified state.\n * @param value The value to compare to the node state.\n */\n public is(value: AnyState): boolean {\n return this.state === value;\n }\n\n /**\n * Reset the state of the node.\n */\n public reset(): void {\n this.setState(State.READY);\n }\n\n /**\n * Abort the running of this node.\n * @param agent The agent.\n */\n public abort(agent: Agent): void {\n // There is nothing to do if this node is not in the running state.\n if (!this.is(State.RUNNING)) {\n return;\n }\n\n // Reset the state of this node.\n this.reset();\n\n this.getAttribute(\"exit\")?.callAgentFunction(agent, false, true);\n }\n\n /**\n * Update the node.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n * @returns The result of the update.\n */\n public update(agent: Agent, options: BehaviourTreeOptions): void {\n // If this node is already in a 'SUCCEEDED' or 'FAILED' state then there is nothing to do.\n if (this.is(State.SUCCEEDED) || this.is(State.FAILED)) {\n return;\n }\n\n try {\n // Evaluate all of the guard path conditions for the current tree path.\n this.guardPath!.evaluate(agent);\n\n // If this node is in the READY state then call the ENTRY for this node if it exists.\n if (this.is(State.READY)) {\n this.getAttribute(\"entry\")?.callAgentFunction(agent);\n }\n\n this.getAttribute(\"step\")?.callAgentFunction(agent);\n\n // Do the actual update.\n this.onUpdate(agent, options);\n\n // If this node is now in a 'SUCCEEDED' or 'FAILED' state then call the EXIT for this node if it exists.\n if (this.is(State.SUCCEEDED) || this.is(State.FAILED)) {\n this.getAttribute(\"exit\")?.callAgentFunction(agent, this.is(State.SUCCEEDED), false);\n }\n } catch (error) {\n // If the error is a GuardUnsatisfiedException then we need to determine if this node is the source.\n if (error instanceof GuardUnsatisifedException && error.isSourceNode(this)) {\n // Abort the current node.\n this.abort(agent);\n\n // Any node that is the source of an abort will be a failed node.\n this.setState(State.FAILED);\n } else {\n throw error;\n }\n }\n }\n}\n\n/**\n * Create a randomly generated node uid.\n * @returns A randomly generated node uid.\n */\nfunction createNodeUid(): string {\n var S4 = function () {\n return (((1 + Math.random()) * 0x10000) | 0).toString(16).substring(1);\n };\n return S4() + S4() + \"-\" + S4() + \"-\" + S4() + \"-\" + S4() + \"-\" + S4() + S4() + S4();\n}\n", "import Node from \"../Node\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\n\n/**\n * A composite node that wraps child nodes.\n */\nexport default abstract class Composite extends Node {\n /**\n * @param type The node type.\n * @param attributes The node attributes.\n * @param children The child nodes.\n */\n constructor(type: string, attributes: Attribute[], protected children: Node[]) {\n super(type, attributes, []);\n }\n\n /**\n * Gets whether this node is a leaf node.\n */\n isLeafNode = () => false;\n\n /**\n * Gets the children of this node.\n */\n getChildren = () => this.children;\n\n /**\n * Reset the state of the node.\n */\n reset = () => {\n // Reset the state of this node.\n this.setState(State.READY);\n\n // Reset the state of any child nodes.\n this.getChildren().forEach((child) => child.reset());\n };\n\n /**\n * Abort the running of this node.\n * @param agent The agent.\n */\n abort = (agent: Agent) => {\n // There is nothing to do if this node is not in the running state.\n if (!this.is(State.RUNNING)) {\n return;\n }\n\n // Abort any child nodes.\n this.getChildren().forEach((child) => child.abort(agent));\n\n // Reset the state of this node.\n this.reset();\n\n this.getAttribute(\"exit\")?.callAgentFunction(agent, false, true);\n };\n}\n", "import Composite from \"./Composite\";\nimport State from \"../../State\";\nimport Node from \"../Node\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A PARALLEL node.\n * The child nodes are executed concurrently until one fails or all succeed.\n */\nexport default class Parallel extends Composite {\n /**\n * @param attributes The node attributes.\n * @param children The child nodes.\n */\n constructor(attributes: Attribute[], children: Node[]) {\n super(\"parallel\", attributes, children);\n }\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // Keep a count of the number of succeeded child nodes.\n let succeededCount = 0;\n\n let hasChildFailed = false;\n\n // Iterate over all of the children of this node.\n for (const child of this.children) {\n // If the child has never been updated or is running then we will need to update it now.\n if (child.getState() === State.READY || child.getState() === State.RUNNING) {\n // Update the child of this node.\n child.update(agent, options);\n }\n\n // If the current child has a state of 'SUCCEEDED' then we should move on to the next child.\n if (child.getState() === State.SUCCEEDED) {\n // The child node has succeeded, keep track of this to determine if all children have.\n succeededCount++;\n\n // The child node succeeded, but we have not finished checking every child node yet.\n continue;\n }\n\n // If the current child has a state of 'FAILED' then this node is also a 'FAILED' node.\n if (child.getState() === State.FAILED) {\n hasChildFailed = true;\n\n // There is no need to check the rest of the children.\n break;\n }\n\n // The node should be in the 'RUNNING' state.\n if (child.getState() !== State.RUNNING) {\n // The child node was not in an expected state.\n throw new Error(\"child node was not in an expected state.\");\n }\n }\n\n if (hasChildFailed) {\n // This node is a 'FAILED' node.\n this.setState(State.FAILED);\n\n // Abort every running child.\n for (const child of this.children) {\n if (child.getState() === State.RUNNING) {\n child.abort(agent);\n }\n }\n } else {\n // If all children have succeeded then this node has also succeeded, otherwise it is still running.\n this.setState(succeededCount === this.children.length ? State.SUCCEEDED : State.RUNNING);\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => \"PARALLEL\";\n}\n", "import Composite from \"./Composite\";\nimport Node from \"../Node\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A SELECTOR node.\n * The child nodes are executed in sequence until one succeeds or all fail.\n */\nexport default class Selector extends Composite {\n /**\n * @param attributes The node attributes.\n * @param children The child nodes.\n */\n constructor(attributes: Attribute[], protected children: Node[]) {\n super(\"selector\", attributes, children);\n }\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // Iterate over all of the children of this node.\n for (const child of this.children) {\n // If the child has never been updated or is running then we will need to update it now.\n if (child.getState() === State.READY || child.getState() === State.RUNNING) {\n // Update the child of this node.\n child.update(agent, options);\n }\n\n // If the current child has a state of 'SUCCEEDED' then this node is also a 'SUCCEEDED' node.\n if (child.getState() === State.SUCCEEDED) {\n // This node is a 'SUCCEEDED' node.\n this.setState(State.SUCCEEDED);\n\n // There is no need to check the rest of the selector nodes.\n return;\n }\n\n // If the current child has a state of 'FAILED' then we should move on to the next child.\n if (child.getState() === State.FAILED) {\n // Find out if the current child is the last one in the selector.\n // If it is then this sequence node has also failed.\n if (this.children.indexOf(child) === this.children.length - 1) {\n // This node is a 'FAILED' node.\n this.setState(State.FAILED);\n\n // There is no need to check the rest of the selector as we have completed it.\n return;\n } else {\n // The child node failed, try the next one.\n continue;\n }\n }\n\n // The node should be in the 'RUNNING' state.\n if (child.getState() === State.RUNNING) {\n // This node is a 'RUNNING' node.\n this.setState(State.RUNNING);\n\n // There is no need to check the rest of the selector as the current child is still running.\n return;\n }\n\n // The child node was not in an expected state.\n throw new Error(\"child node was not in an expected state.\");\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => \"SELECTOR\";\n}\n", "import Composite from \"./Composite\";\nimport Node from \"../Node\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A SEQUENCE node.\n * The child nodes are executed in sequence until one fails or all succeed.\n */\nexport default class Sequence extends Composite {\n /**\n * @param attributes The node attributes.\n * @param children The child nodes.\n */\n constructor(attributes: Attribute[], protected children: Node[]) {\n super(\"sequence\", attributes, children);\n }\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // Iterate over all of the children of this node.\n for (const child of this.children) {\n // If the child has never been updated or is running then we will need to update it now.\n if (child.getState() === State.READY || child.getState() === State.RUNNING) {\n // Update the child of this node.\n child.update(agent, options);\n }\n\n // If the current child has a state of 'SUCCEEDED' then we should move on to the next child.\n if (child.getState() === State.SUCCEEDED) {\n // Find out if the current child is the last one in the sequence.\n // If it is then this sequence node has also succeeded.\n if (this.children.indexOf(child) === this.children.length - 1) {\n // This node is a 'SUCCEEDED' node.\n this.setState(State.SUCCEEDED);\n\n // There is no need to check the rest of the sequence as we have completed it.\n return;\n } else {\n // The child node succeeded, but we have not finished the sequence yet.\n continue;\n }\n }\n\n // If the current child has a state of 'FAILED' then this node is also a 'FAILED' node.\n if (child.getState() === State.FAILED) {\n // This node is a 'FAILED' node.\n this.setState(State.FAILED);\n\n // There is no need to check the rest of the sequence.\n return;\n }\n\n // The node should be in the 'RUNNING' state.\n if (child.getState() === State.RUNNING) {\n // This node is a 'RUNNING' node.\n this.setState(State.RUNNING);\n\n // There is no need to check the rest of the sequence as the current child is still running.\n return;\n }\n\n // The child node was not in an expected state.\n throw new Error(\"child node was not in an expected state.\");\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => \"SEQUENCE\";\n}\n", "import createLotto from \"lotto-draw\";\n\nimport Node from \"../Node\";\nimport Composite from \"./Composite\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A LOTTO node.\n * A winning child is picked on the initial update of this node, based on ticket weighting.\n * The state of this node will match the state of the winning child.\n */\nexport default class Lotto extends Composite {\n /**\n * @param attributes The node attributes.\n * @param weights The child node weights.\n * @param children The child nodes.\n */\n constructor(attributes: Attribute[], private weights: number[] | undefined, children: Node[]) {\n super(\"lotto\", attributes, children);\n }\n\n /**\n * The child node selected to be the active one.\n */\n private selectedChild: Node | undefined;\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // If this node is in the READY state then we need to pick a winning child node.\n if (this.is(State.READY)) {\n // Create a lotto draw with which to randomly pick a child node to become the active one.\n const lottoDraw = createLotto({\n // Hook up the optional 'random' behaviour tree function option to the one used by 'lotto-draw'.\n random: options.random,\n // Pass in each child node as a participant in the lotto draw with their respective ticket count.\n participants: this.children.map((child, index) => [child, this.weights?.[index] || 1])\n });\n\n // Randomly pick a child based on ticket weighting, this will become the active child for this composite node.\n this.selectedChild = lottoDraw.draw() || undefined;\n }\n\n // If something went wrong and we don't have an active child then we should throw an error.\n if (!this.selectedChild) {\n throw new Error(\"failed to update lotto node as it has no active child\");\n }\n\n // If the selected child has never been updated or is running then we will need to update it now.\n if (this.selectedChild.getState() === State.READY || this.selectedChild.getState() === State.RUNNING) {\n this.selectedChild.update(agent, options);\n }\n\n // The state of the lotto node is the state of its selected child.\n this.setState(this.selectedChild.getState());\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => (this.weights ? `LOTTO [${this.weights.join(\",\")}]` : \"LOTTO\");\n}\n", "import Node from \"../Node\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\n\n/**\n * A decorator node that wraps a single child node.\n */\nexport default abstract class Decorator extends Node {\n /**\n * @param type The node type.\n * @param attributes The node attributes.\n * @param child The child node.\n */\n constructor(type: string, attributes: Attribute[], protected child: Node) {\n super(type, attributes, []);\n }\n\n /**\n * Gets whether this node is a leaf node.\n */\n isLeafNode = () => false;\n\n /**\n * Gets the children of this node.\n */\n getChildren = () => [this.child];\n\n /**\n * Reset the state of the node.\n */\n reset = () => {\n // Reset the state of this node.\n this.setState(State.READY);\n\n // Reset the state of the child node.\n this.child.reset();\n };\n\n /**\n * Abort the running of this node.\n * @param agent The agent.\n */\n abort = (agent: Agent) => {\n // There is nothing to do if this node is not in the running state.\n if (!this.is(State.RUNNING)) {\n return;\n }\n\n // Abort the child node.\n this.child.abort(agent);\n\n // Reset the state of this node.\n this.reset();\n\n this.getAttribute(\"exit\")?.callAgentFunction(agent, false, true);\n };\n}\n", "import Node from \"../Node\";\nimport Decorator from \"./Decorator\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A Fail node.\n * This node wraps a single child and will always move to the 'FAILED' state when the child moves to a 'SUCCEEDED' or 'FAILED' state.\n */\nexport default class Fail extends Decorator {\n /**\n * @param attributes The node attributes.\n * @param child The child node.\n */\n constructor(attributes: Attribute[], child: Node) {\n super(\"fail\", attributes, child);\n }\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // If the child has never been updated or is running then we will need to update it now.\n if (this.child.getState() === State.READY || this.child.getState() === State.RUNNING) {\n this.child.update(agent, options);\n }\n\n // The state of this node will depend in the state of its child.\n switch (this.child.getState()) {\n case State.RUNNING:\n this.setState(State.RUNNING);\n break;\n\n case State.SUCCEEDED:\n case State.FAILED:\n this.setState(State.FAILED);\n break;\n\n default:\n this.setState(State.READY);\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => \"FAIL\";\n}\n", "import Decorator from \"./Decorator\";\nimport State from \"../../State\";\nimport Node from \"../Node\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A Flip node.\n * This node wraps a single child and will flip the state of the child state.\n */\nexport default class Flip extends Decorator {\n /**\n * @param attributes The node attributes.\n * @param child The child node.\n */\n constructor(attributes: Attribute[], child: Node) {\n super(\"flip\", attributes, child);\n }\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // If the child has never been updated or is running then we will need to update it now.\n if (this.child.getState() === State.READY || this.child.getState() === State.RUNNING) {\n this.child.update(agent, options);\n }\n\n // The state of this node will depend in the state of its child.\n switch (this.child.getState()) {\n case State.RUNNING:\n this.setState(State.RUNNING);\n break;\n\n case State.SUCCEEDED:\n this.setState(State.FAILED);\n break;\n\n case State.FAILED:\n this.setState(State.SUCCEEDED);\n break;\n\n default:\n this.setState(State.READY);\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => \"FLIP\";\n}\n", "import Node from \"../Node\";\nimport Decorator from \"./Decorator\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A REPEAT node.\n * The node has a single child which can have:\n * -- A number of iterations for which to repeat the child node.\n * -- An infinite repeat loop if neither an iteration count or a condition function is defined.\n * The REPEAT node will stop and have a 'FAILED' state if its child is ever in a 'FAILED' state after an update.\n * The REPEAT node will attempt to move on to the next iteration if its child is ever in a 'SUCCEEDED' state.\n */\nexport default class Repeat extends Decorator {\n /**\n * @param attributes The node attributes.\n * @param iterations The number of iterations to repeat the child node.\n * @param iterationsMin The minimum possible number of iterations to repeat the child node.\n * @param iterationsMax The maximum possible number of iterations to repeat the child node.\n * @param child The child node.\n */\n constructor(\n attributes: Attribute[],\n private iterations: number | null,\n private iterationsMin: number | null,\n private iterationsMax: number | null,\n child: Node\n ) {\n super(\"repeat\", attributes, child);\n }\n\n /**\n * The number of target iterations to make.\n */\n private targetIterationCount: number | null = null;\n\n /**\n * The current iteration count.\n */\n private currentIterationCount: number = 0;\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // If this node is in the READY state then we need to reset the child and the target iteration count.\n if (this.is(State.READY)) {\n // Reset the child node.\n this.child.reset();\n\n // Reset the current iteration count.\n this.currentIterationCount = 0;\n\n // Set the target iteration count.\n this.setTargetIterationCount(options);\n }\n\n // Do a check to see if we can iterate. If we can then this node will move into the 'RUNNING' state.\n // If we cannot iterate then we have hit our target iteration count, which means that the node has succeeded.\n if (this.canIterate()) {\n // This node is in the running state and can do its initial iteration.\n this.setState(State.RUNNING);\n\n // We may have already completed an iteration, meaning that the child node will be in the SUCCEEDED state.\n // If this is the case then we will have to reset the child node now.\n if (this.child.getState() === State.SUCCEEDED) {\n this.child.reset();\n }\n\n // Update the child of this node.\n this.child.update(agent, options);\n\n // If the child moved into the FAILED state when we updated it then there is nothing left to do and this node has also failed.\n // If it has moved into the SUCCEEDED state then we have completed the current iteration.\n if (this.child.getState() === State.FAILED) {\n // The child has failed, meaning that this node has failed.\n this.setState(State.FAILED);\n\n return;\n } else if (this.child.getState() === State.SUCCEEDED) {\n // We have completed an iteration.\n this.currentIterationCount += 1;\n }\n } else {\n // This node is in the 'SUCCEEDED' state as we cannot iterate any more.\n this.setState(State.SUCCEEDED);\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => {\n if (this.iterations !== null) {\n return `REPEAT ${this.iterations}x`;\n } else if (this.iterationsMin !== null && this.iterationsMax !== null) {\n return `REPEAT ${this.iterationsMin}x-${this.iterationsMax}x`;\n } else {\n return \"REPEAT\";\n }\n };\n\n /**\n * Reset the state of the node.\n */\n reset = () => {\n // Reset the state of this node.\n this.setState(State.READY);\n\n // Reset the current iteration count.\n this.currentIterationCount = 0;\n\n // Reset the child node.\n this.child.reset();\n };\n\n /**\n * Gets whether an iteration can be made.\n * @returns Whether an iteration can be made.\n */\n private canIterate = () => {\n if (this.targetIterationCount !== null) {\n // We can iterate as long as we have not reached our target iteration count.\n return this.currentIterationCount < this.targetIterationCount;\n }\n\n // If neither an iteration count or a condition function were defined then we can iterate indefinitely.\n return true;\n };\n\n /**\n * Sets the target iteration count.\n * @param options The behaviour tree options object.\n */\n private setTargetIterationCount = (options: BehaviourTreeOptions) => {\n // Are we dealing with an explicit iteration count or will we be randomly picking a iteration count between the min and max iteration count.\n if (this.iterations !== null) {\n this.targetIterationCount = this.iterations;\n } else if (this.iterationsMin !== null && this.iterationsMax !== null) {\n // We will be picking a random iteration count between a min and max iteration count, if the optional 'random'\n // behaviour tree function option is defined then we will be using that, otherwise we will fall back to using Math.random.\n const random = typeof options.random === \"function\" ? options.random : Math.random;\n\n // Pick a random iteration count between a min and max iteration count.\n this.targetIterationCount = Math.floor(\n random() * (this.iterationsMax - this.iterationsMin + 1) + this.iterationsMin\n );\n } else {\n this.targetIterationCount = null;\n }\n };\n}\n", "import Node from \"../Node\";\nimport Decorator from \"./Decorator\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A RETRY node.\n * The node has a single child which can have:\n * -- A number of iterations for which to repeat the child node.\n * -- An infinite repeat loop if neither an iteration count or a condition function is defined.\n * The RETRY node will stop and have a 'SUCCEEDED' state if its child is ever in a 'SUCCEEDED' state after an update.\n * The RETRY node will attempt to move on to the next iteration if its child is ever in a 'FAILED' state.\n */\nexport default class Retry extends Decorator {\n /**\n * @param attributes The node attributes.\n * @param attempts The number of attempts to retry the child node.\n * @param attemptsMin The minimum possible number of attempts to retry the child node.\n * @param attemptsMax The maximum possible number of attempts to retry the child node.\n * @param child The child node.\n */\n constructor(\n attributes: Attribute[],\n private attempts: number | null,\n private attemptsMin: number | null,\n private attemptsMax: number | null,\n child: Node\n ) {\n super(\"retry\", attributes, child);\n }\n\n /**\n * The number of target attempts to make.\n */\n private targetAttemptCount: number | null = null;\n\n /**\n * The current attempt count.\n */\n private currentAttemptCount: number = 0;\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // If this node is in the READY state then we need to reset the child and the target attempt count.\n if (this.is(State.READY)) {\n // Reset the child node.\n this.child.reset();\n\n // Reset the current attempt count.\n this.currentAttemptCount = 0;\n\n // Set the target attempt count.\n this.setTargetAttemptCount(options);\n }\n\n // Do a check to see if we can attempt. If we can then this node will move into the 'RUNNING' state.\n // If we cannot attempt then we have hit our target attempt count, which means that the node has succeeded.\n if (this.canAttempt()) {\n // This node is in the running state and can do its initial attempt.\n this.setState(State.RUNNING);\n\n // We may have already completed an attempt, meaning that the child node will be in the FAILED state.\n // If this is the case then we will have to reset the child node now.\n if (this.child.getState() === State.FAILED) {\n this.child.reset();\n }\n\n // Update the child of this node.\n this.child.update(agent, options);\n\n // If the child moved into the SUCCEEDED state when we updated it then there is nothing left to do and this node has also succeeded.\n // If it has moved into the FAILED state then we have completed the current attempt.\n if (this.child.getState() === State.SUCCEEDED) {\n // The child has succeeded, meaning that this node has succeeded.\n this.setState(State.SUCCEEDED);\n\n return;\n } else if (this.child.getState() === State.FAILED) {\n // We have completed an attempt.\n this.currentAttemptCount += 1;\n }\n } else {\n // This node is in the 'FAILED' state as we cannot iterate any more.\n this.setState(State.FAILED);\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => {\n if (this.attempts !== null) {\n return `RETRY ${this.attempts}x`;\n } else if (this.attemptsMin !== null && this.attemptsMax !== null) {\n return `RETRY ${this.attemptsMin}x-${this.attemptsMax}x`;\n } else {\n return \"RETRY\";\n }\n };\n\n /**\n * Reset the state of the node.\n */\n reset = () => {\n // Reset the state of this node.\n this.setState(State.READY);\n\n // Reset the current attempt count.\n this.currentAttemptCount = 0;\n\n // Reset the child node.\n this.child.reset();\n };\n\n /**\n * Gets whether an attempt can be made.\n * @returns Whether an attempt can be made.\n */\n canAttempt = () => {\n if (this.targetAttemptCount !== null) {\n // We can attempt as long as we have not reached our target attempt count.\n return this.currentAttemptCount < this.targetAttemptCount;\n }\n\n // If neither an attempt count or a condition function were defined then we can attempt indefinitely.\n return true;\n };\n\n /**\n * Sets the target attempt count.\n * @param options The behaviour tree options object.\n */\n setTargetAttemptCount = (options: BehaviourTreeOptions) => {\n // Are we dealing with an explicit attempt count or will we be randomly picking an attempt count between the min and max attempt count.\n if (this.attempts !== null) {\n this.targetAttemptCount = this.attempts;\n } else if (this.attemptsMin !== null && this.attemptsMax !== null) {\n // We will be picking a random attempt count between a min and max attempt count, if the optional 'random'\n // behaviour tree function option is defined then we will be using that, otherwise we will fall back to using Math.random.\n const random = typeof options.random === \"function\" ? options.random : Math.random;\n\n // Pick a random attempt count between a min and max attempt count.\n this.targetAttemptCount = Math.floor(\n random() * (this.attemptsMax - this.attemptsMin + 1) + this.attemptsMin\n );\n } else {\n this.targetAttemptCount = null;\n }\n };\n}\n", "import Node from \"../Node\";\nimport Decorator from \"./Decorator\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A Root node.\n * The root node will have a single child.\n */\nexport default class Root extends Decorator {\n /**\n * @param attributes The node attributes.\n * @param child The child node.\n */\n constructor(attributes: Attribute[], child: Node) {\n super(\"root\", attributes, child);\n }\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // If the child has never been updated or is running then we will need to update it now.\n if (this.child.getState() === State.READY || this.child.getState() === State.RUNNING) {\n // Update the child of this node.\n this.child.update(agent, options);\n }\n\n // The state of the root node is the state of its child.\n this.setState(this.child.getState());\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => \"ROOT\";\n}\n", "import Node from \"../Node\";\nimport Decorator from \"./Decorator\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A Succeed node.\n * This node wraps a single child and will always move to the 'SUCCEEDED' state when the child moves to a 'SUCCEEDED' or 'FAILED' state.\n */\nexport default class Succeed extends Decorator {\n /**\n * @param attributes The node attributes.\n * @param child The child node.\n */\n constructor(attributes: Attribute[], child: Node) {\n super(\"succeed\", attributes, child);\n }\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // If the child has never been updated or is running then we will need to update it now.\n if (this.child.getState() === State.READY || this.child.getState() === State.RUNNING) {\n this.child.update(agent, options);\n }\n\n // The state of this node will depend in the state of its child.\n switch (this.child.getState()) {\n case State.RUNNING:\n this.setState(State.RUNNING);\n break;\n\n case State.SUCCEEDED:\n case State.FAILED:\n this.setState(State.SUCCEEDED);\n break;\n\n default:\n this.setState(State.READY);\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => \"SUCCEED\";\n}\n", "import Node from \"../Node\";\n\n/**\n * A leaf node.\n */\nexport default abstract class Leaf extends Node {\n /**\n * Gets whether this node is a leaf node.\n */\n isLeafNode = () => true;\n}\n", "import { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\nimport State, { CompleteState } from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Leaf from \"./Leaf\";\nimport Lookup from \"../../Lookup\";\nimport Attribute from \"../../attributes/Attribute\";\n\n/**\n * An Action leaf node.\n * This represents an immediate or ongoing state of behaviour.\n */\nexport default class Action extends Leaf {\n /**\n * @param attributes The node attributes.\n * @param actionName The action name.\n * @param actionArguments The array of action argument definitions.\n */\n constructor(attributes: Attribute[], private actionName: string, private actionArguments: any[]) {\n super(\"action\", attributes, actionArguments);\n }\n\n /**\n * Whether there is a pending update promise.\n */\n private isUsingUpdatePromise = false;\n\n /**\n * The finished state result of an update promise.\n */\n private updatePromiseStateResult: CompleteState | null = null;\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // If the result of this action depends on an update promise then there is nothing to do until\n // it resolves, unless there has been a value set as a result of the update promise resolving.\n if (this.isUsingUpdatePromise) {\n // Check whether the update promise has resolved with a state value.\n if (this.updatePromiseStateResult) {\n // Set the state of this node to match the state returned by the promise.\n this.setState(this.updatePromiseStateResult);\n }\n\n return;\n }\n\n // Attempt to get the invoker for the action function.\n const actionFuncInvoker = Lookup.getFuncInvoker(agent, this.actionName);\n\n // The action function should be defined.\n if (actionFuncInvoker === null) {\n throw new Error(\n `cannot update action node as the action '${this.actionName}' function is not defined on the agent and has not been registered`\n );\n }\n\n // Call the action function, the result of which may be:\n // - The finished state of this action node.\n // - A promise to return a finished node state.\n // - Undefined if the node should remain in the running state.\n const updateResult = actionFuncInvoker(this.actionArguments) as CompleteState | Promise;\n\n if (updateResult instanceof Promise) {\n updateResult.then(\n (result) => {\n // If 'isUpdatePromisePending' is null then the promise was cleared as it was resolving, probably via an abort of reset.\n if (!this.isUsingUpdatePromise) {\n return;\n }\n\n // Check to make sure the result is a valid finished state.\n if (result !== State.SUCCEEDED && result !== State.FAILED) {\n throw new Error(\n \"action node promise resolved with an invalid value, expected a State.SUCCEEDED or State.FAILED value to be returned\"\n );\n }\n\n // Set pending update promise state result to be processed on next update.\n this.updatePromiseStateResult = result;\n },\n (reason) => {\n // If 'isUpdatePromisePending' is null then the promise was cleared as it was resolving, probably via an abort of reset.\n if (!this.isUsingUpdatePromise) {\n return;\n }\n\n // Just throw whatever was returned as the rejection argument.\n throw new Error(reason);\n }\n );\n\n // This node will be in the 'RUNNING' state until the update promise resolves.\n this.setState(State.RUNNING);\n\n // We are now waiting for the promise returned by the use to resolve before we know what state this node is in.\n this.isUsingUpdatePromise = true;\n } else {\n // Validate the returned value.\n this.validateUpdateResult(updateResult);\n\n // Set the state of this node, this may be undefined, which just means that the node is still in the 'RUNNING' state.\n this.setState(updateResult || State.RUNNING);\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => this.actionName;\n\n /**\n * Reset the state of the node.\n */\n reset = () => {\n // Reset the state of this node.\n this.setState(State.READY);\n\n // There is no longer an update promise that we care about.\n this.isUsingUpdatePromise = false;\n this.updatePromiseStateResult = null;\n };\n\n /**\n * Validate the result of an update function call.\n * @param result The result of an update function call.\n */\n private validateUpdateResult = (result: CompleteState | boolean) => {\n switch (result) {\n case State.SUCCEEDED:\n case State.FAILED:\n case undefined:\n return;\n default:\n throw new Error(\n `action '${this.actionName}' 'onUpdate' returned an invalid response, expected an optional State.SUCCEEDED or State.FAILED value to be returned`\n );\n }\n };\n}\n", "import { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Leaf from \"./Leaf\";\nimport Lookup from \"../../Lookup\";\nimport Attribute from \"../../attributes/Attribute\";\n\n/**\n * A Condition leaf node.\n * This will succeed or fail immediately based on an agent predicate, without moving to the 'RUNNING' state.\n */\nexport default class Condition extends Leaf {\n /**\n * @param attributes The node attributes.\n * @param conditionName The name of the condition function.\n * @param conditionArguments The array of condition argument definitions.\n */\n constructor(attributes: Attribute[], private conditionName: string, private conditionArguments: any[]) {\n super(\"condition\", attributes, conditionArguments);\n }\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // Attempt to get the invoker for the condition function.\n const conditionFuncInvoker = Lookup.getFuncInvoker(agent, this.conditionName);\n\n // The condition function should be defined.\n if (conditionFuncInvoker === null) {\n throw new Error(\n `cannot update condition node as the condition '${this.conditionName}' function is not defined on the agent and has not been registered`\n );\n }\n\n // Call the condition function to determine the state of this node.\n this.setState(!!conditionFuncInvoker(this.conditionArguments) ? State.SUCCEEDED : State.FAILED);\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => this.conditionName;\n}\n", "import Leaf from \"./Leaf\";\nimport State from \"../../State\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { Agent } from \"../../Agent\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A WAIT node.\n * The state of this node will change to SUCCEEDED after a duration of time\n */\nexport default class Wait extends Leaf {\n /**\n * @param attributes The node attributes.\n * @param duration The duration that this node will wait to succeed in milliseconds.\n * @param durationMin The minimum possible duration in milliseconds that this node will wait to succeed.\n * @param durationMax The maximum possible duration in milliseconds that this node will wait to succeed.\n */\n constructor(\n attributes: Attribute[],\n private duration: number | null,\n private durationMin: number | null,\n private durationMax: number | null\n ) {\n super(\"wait\", attributes, []);\n }\n\n /**\n * The time in milliseconds at which this node was first updated.\n */\n private initialUpdateTime: number = 0;\n\n /**\n * The total duration in milliseconds that this node will be waiting for.\n */\n private totalDuration: number | null = null;\n\n /**\n * The duration in milliseconds that this node has been waiting for.\n */\n private waitedDuration: number = 0;\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // If this node is in the READY state then we need to set the initial update time.\n if (this.is(State.READY)) {\n // Set the initial update time.\n this.initialUpdateTime = new Date().getTime();\n\n // Set the initial waited duration.\n this.waitedDuration = 0;\n\n // Are we dealing with an explicit duration or will we be randomly picking a duration between the min and max duration.\n if (this.duration !== null) {\n this.totalDuration = this.duration;\n } else if (this.durationMin !== null && this.durationMax !== null) {\n // We will be picking a random duration between a min and max duration, if the optional 'random' behaviour tree\n // function option is defined then we will be using that, otherwise we will fall back to using Math.random.\n const random = typeof options.random === \"function\" ? options.random : Math.random;\n\n // Pick a random duration between a min and max duration.\n this.totalDuration = Math.floor(\n random() * (this.durationMax - this.durationMin + 1) + this.durationMin\n );\n } else {\n this.totalDuration = null;\n }\n\n // The node is now running until we finish waiting.\n this.setState(State.RUNNING);\n }\n\n // If we have no total duration then this wait node will wait indefinitely until it is aborted.\n if (this.totalDuration === null) {\n return;\n }\n\n // If we have a 'getDeltaTime' function defined as part of our options then we will use it to figure out how long we have waited for.\n if (typeof options.getDeltaTime === \"function\") {\n // Get the delta time.\n const deltaTime = options.getDeltaTime();\n\n // Our delta time must be a valid number and cannot be NaN.\n if (typeof deltaTime !== \"number\" || isNaN(deltaTime)) {\n throw new Error(\"The delta time must be a valid number and not NaN.\");\n }\n\n // Update the amount of time that this node has been waiting for based on the delta time.\n this.waitedDuration += deltaTime * 1000;\n } else {\n // We are not using a delta time, so we will just work out hom much time has passed since the first update.\n this.waitedDuration = new Date().getTime() - this.initialUpdateTime;\n }\n\n // Have we waited long enough?\n if (this.waitedDuration >= this.totalDuration) {\n // We have finished waiting!\n this.setState(State.SUCCEEDED);\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => {\n if (this.duration !== null) {\n return `WAIT ${this.duration}ms`;\n } else if (this.durationMin !== null && this.durationMax !== null) {\n return `WAIT ${this.durationMin}ms-${this.durationMax}ms`;\n } else {\n return \"WAIT\";\n }\n };\n}\n", "import Guard from \"./guards/Guard\";\n\nexport type AttributeDetails = {\n /** The attribute type. */\n type: string;\n\n /** The attribute arguments. */\n args: any[];\n};\n\n/**\n * A base node attribute.\n */\nexport default abstract class Attribute {\n /**\n * @param type The node attribute type.\n * @param args The array of attribute arguments.\n */\n constructor(public type: string, public args: any[]) {}\n\n /**\n * Gets the attribute details.\n */\n abstract getDetails(): TAttributeDetails;\n\n /**\n * Gets whether this attribute is a guard.\n */\n abstract isGuard: () => this is Guard;\n}\n", "import { Agent } from \"../../Agent\";\nimport Attribute, { AttributeDetails } from \"../Attribute\";\n\nexport type GuardAttributeDetails = {\n /** The name of the condition function that determines whether the guard is satisfied. */\n condition: string;\n} & AttributeDetails;\n\n/**\n * A base node guard attribute.\n */\nexport default abstract class Guard extends Attribute {\n /**\n * @param type The node attribute type.\n * @param args The array of decorator argument definitions.\n * @param condition The name of the condition function that determines whether the guard is satisfied.\n */\n constructor(type: string, args: any[], private condition: string) {\n super(type, args);\n }\n\n /**\n * Gets the name of the condition function that determines whether the guard is satisfied.\n */\n getCondition = () => this.condition;\n\n /**\n * Gets whether this attribute is a guard.\n */\n isGuard = () => true;\n\n /**\n * Gets the attribute details.\n */\n getDetails(): GuardAttributeDetails {\n return {\n type: this.type,\n args: this.args,\n condition: this.getCondition()\n };\n }\n\n /**\n * Gets whether the guard is satisfied.\n * @param agent The agent.\n * @returns Whether the guard is satisfied.\n */\n abstract isSatisfied(agent: Agent): boolean;\n}\n", "import Guard from \"./Guard\";\nimport Lookup from \"../../Lookup\";\nimport { Agent } from \"../../Agent\";\n\n/**\n * A WHILE guard which is satisfied as long as the given condition remains true.\n */\nexport default class While extends Guard {\n /**\n * @param condition The name of the condition function that determines whether the guard is satisfied.\n * @param args The array of decorator argument definitions.\n */\n constructor(condition: string, args: any[]) {\n super(\"while\", args, condition);\n }\n\n /**\n * Gets whether the guard is satisfied.\n * @param agent The agent.\n * @returns Whether the guard is satisfied.\n */\n isSatisfied = (agent: Agent) => {\n // Attempt to get the invoker for the condition function.\n const conditionFuncInvoker = Lookup.getFuncInvoker(agent, this.getCondition());\n\n // The condition function should be defined.\n if (conditionFuncInvoker === null) {\n throw new Error(\n `cannot evaluate node guard as the condition '${this.getCondition()}' function is not defined on the agent and has not been registered`\n );\n }\n\n // Call the condition function to determine whether this guard is satisfied.\n return !!conditionFuncInvoker(this.args);\n };\n}\n", "import Guard from \"./Guard\";\nimport Lookup from \"../../Lookup\";\nimport { Agent } from \"../../Agent\";\n\n/**\n * An UNTIL guard which is satisfied as long as the given condition remains false.\n */\nexport default class Until extends Guard {\n /**\n * @param condition The name of the condition function that determines whether the guard is satisfied.\n * @param args The array of decorator argument definitions.\n */\n constructor(condition: string, args: any[]) {\n super(\"until\", args, condition);\n }\n\n /**\n * Gets whether the guard is satisfied.\n * @param agent The agent.\n * @returns Whether the guard is satisfied.\n */\n isSatisfied = (agent: Agent) => {\n // Attempt to get the invoker for the condition function.\n const conditionFuncInvoker = Lookup.getFuncInvoker(agent, this.getCondition());\n\n // The condition function should be defined.\n if (conditionFuncInvoker === null) {\n throw new Error(\n `cannot evaluate node guard as the condition '${this.getCondition()}' function is not defined on the agent and has not been registered`\n );\n }\n\n // Call the condition function to determine whether this guard is satisfied.\n return !!!conditionFuncInvoker(this.args);\n };\n}\n", "import { Agent } from \"../../Agent\";\nimport Attribute, { AttributeDetails } from \"../Attribute\";\n\nexport type CallbackAttributeDetails = {\n /** The name of the agent function that is called. */\n functionName: string;\n} & AttributeDetails;\n\n/**\n * A base node callback attribute.\n */\nexport default abstract class Callback extends Attribute {\n /**\n * @param type The node attribute type.\n * @param args The array of decorator argument definitions.\n * @param functionName The name of the agent function to call.\n */\n constructor(type: string, args: any[], private functionName: string) {\n super(type, args);\n }\n\n /**\n * Gets the name of the agent function to call.\n */\n getFunctionName = () => this.functionName;\n\n /**\n * Gets whether this attribute is a guard.\n */\n isGuard = () => false;\n\n /**\n * Gets the attribute details.\n */\n getDetails(): CallbackAttributeDetails {\n return {\n type: this.type,\n args: this.args,\n functionName: this.getFunctionName()\n };\n }\n\n /**\n * Attempt to call the agent function that this callback refers to.\n * @param agent The agent.\n */\n abstract callAgentFunction: (agent: Agent, isSuccess: boolean, isAborted: boolean) => void;\n}\n", "import Callback from \"./Callback\";\nimport Lookup from \"../../Lookup\";\nimport { Agent } from \"../../Agent\";\n\n/**\n * An ENTRY callback which defines an agent function to call when the associated node is updated and moves out of running state.\n */\nexport default class Entry extends Callback {\n /**\n * @param functionName The name of the agent function to call.\n * @param args The array of callback argument definitions.\n */\n constructor(functionName: string, args: any[]) {\n super(\"entry\", args, functionName);\n }\n\n /**\n * Attempt to call the agent function that this callback refers to.\n * @param agent The agent.\n */\n callAgentFunction = (agent: Agent) => {\n // Attempt to get the invoker for the callback function.\n const callbackFuncInvoker = Lookup.getFuncInvoker(agent, this.getFunctionName());\n\n // The callback function should be defined.\n if (callbackFuncInvoker === null) {\n throw new Error(\n `cannot call entry function '${this.getFunctionName()}' as is not defined on the agent and has not been registered`\n );\n }\n\n // Call the callback function.\n callbackFuncInvoker(this.args);\n };\n}\n", "import Callback from \"./Callback\";\nimport Lookup from \"../../Lookup\";\nimport { Agent } from \"../../Agent\";\n\n/**\n * A STEP callback which defines an agent function to call when the associated node is updated.\n */\nexport default class Step extends Callback {\n /**\n * @param functionName The name of the agent function to call.\n * @param args The array of callback argument definitions.\n */\n constructor(functionName: string, args: any[]) {\n super(\"step\", args, functionName);\n }\n\n /**\n * Attempt to call the agent function that this callback refers to.\n * @param agent The agent.\n */\n callAgentFunction = (agent: Agent) => {\n // Attempt to get the invoker for the callback function.\n const callbackFuncInvoker = Lookup.getFuncInvoker(agent, this.getFunctionName());\n\n // The callback function should be defined.\n if (callbackFuncInvoker === null) {\n throw new Error(\n `cannot call step function '${this.getFunctionName()}' as is not defined on the agent and has not been registered`\n );\n }\n\n // Call the callback function.\n callbackFuncInvoker(this.args);\n };\n}\n", "import Callback from \"./Callback\";\nimport Lookup from \"../../Lookup\";\nimport { Agent } from \"../../Agent\";\n\n/**\n * An EXIT callback which defines an agent function to call when the associated node is updated and moves to a finished state or is aborted.\n */\nexport default class Exit extends Callback {\n /**\n * @param functionName The name of the agent function to call.\n * @param args The array of callback argument definitions.\n */\n constructor(functionName: string, args: any[]) {\n super(\"exit\", args, functionName);\n }\n\n /**\n * Attempt to call the agent function that this callback refers to.\n * @param agent The agent.\n * @param isSuccess Whether the decorated node was left with a success state.\n * @param isAborted Whether the decorated node was aborted.\n */\n callAgentFunction = (agent: Agent, isSuccess: boolean, isAborted: boolean) => {\n // Attempt to get the invoker for the callback function.\n const callbackFuncInvoker = Lookup.getFuncInvoker(agent, this.getFunctionName());\n\n // The callback function should be defined.\n if (callbackFuncInvoker === null) {\n throw new Error(\n `cannot call exit function '${this.getFunctionName()}' as is not defined on the agent and has not been registered`\n );\n }\n\n // Call the callback function\n callbackFuncInvoker([{ value: { succeeded: isSuccess, aborted: isAborted } }, ...this.args]);\n };\n}\n", "import { AnyNodeDefinition, RootNodeDefinition } from \"./BehaviourTreeDefinition\";\nimport GuardPath, { GuardPathPart } from \"./attributes/guards/GuardPath\";\nimport { validateBranchSubtreeLinks } from \"./BehaviourTreeDefinitionValidator\";\nimport { isInteger } from \"./BehaviourTreeDefinitionUtilities\";\nimport Node from \"./nodes/Node\";\nimport Composite from \"./nodes/composite/Composite\";\nimport Decorator from \"./nodes/decorator/Decorator\";\nimport Parallel from \"./nodes/composite/Parallel\";\nimport Selector from \"./nodes/composite/Selector\";\nimport Sequence from \"./nodes/composite/Sequence\";\nimport Lotto from \"./nodes/composite/Lotto\";\nimport Fail from \"./nodes/decorator/Fail\";\nimport Flip from \"./nodes/decorator/Flip\";\nimport Repeat from \"./nodes/decorator/Repeat\";\nimport Retry from \"./nodes/decorator/Retry\";\nimport Root from \"./nodes/decorator/Root\";\nimport Succeed from \"./nodes/decorator/Succeed\";\nimport Action from \"./nodes/leaf/Action\";\nimport Condition from \"./nodes/leaf/Condition\";\nimport Wait from \"./nodes/leaf/Wait\";\nimport Lookup from \"./Lookup\";\nimport Attribute from \"./attributes/Attribute\";\nimport While from \"./attributes/guards/While\";\nimport Until from \"./attributes/guards/Until\";\nimport Entry from \"./attributes/callbacks/Entry\";\nimport Step from \"./attributes/callbacks/Step\";\nimport Exit from \"./attributes/callbacks/Exit\";\n\n/**\n * A type representing any node instance in a behaviour tree.\n */\ntype AnyNode =\n | Root\n | Action\n | Condition\n | Wait\n | Sequence\n | Selector\n | Lotto\n | Parallel\n | Repeat\n | Retry\n | Flip\n | Succeed\n | Fail;\n\n/**\n * A type defining a mapping of root node identifiers to root node definitions.\n */\ntype RootNodeDefinitionMap = { [key: string | symbol]: RootNodeDefinition };\n\n/**\n * A symbol to use as the main root key in any root node mappings.\n */\nconst MAIN_ROOT_NODE_KEY = Symbol(\"__root__\");\n\n/**\n * Build and populate the root nodes based on the provided definition, assuming that the definition has been validated.\n * @param definition The root node definitions.\n * @returns The built and populated root node definitions.\n */\nexport default function buildRootNode(definition: RootNodeDefinition[]): Root {\n // Create a mapping of root node identifers to root node definitions, including globally registered subtree root node definitions.\n const rootNodeDefinitionMap = createRootNodeDefinitionMap(definition);\n\n // Now that we have all of our root node definitons (those part of the tree definition and those globally\n // registered) we should validate the definition. This will also double-check that we dont have any circular\n // dependencies in our branch -> subtree references and that we have no broken branch -> subtree links.\n validateBranchSubtreeLinks(definition, true);\n\n // Create our populated tree of node instances, starting with our main root node.\n const rootNode = nodeFactory(rootNodeDefinitionMap[MAIN_ROOT_NODE_KEY], rootNodeDefinitionMap) as Root;\n\n // Set a guard path on every leaf of the tree to evaluate as part of each update.\n applyLeafNodeGuardPaths(rootNode);\n\n // We only need to return the main root node.\n return rootNode;\n}\n\n/**\n * A factory function which creates a node instance based on the specified definition.\n * @param definition The node definition.\n * @param rootNodeDefinitionMap The mapping of root node identifers to root node definitions, including globally registered subtree root node definitions.\n * @returns A node instance based on the specified definition.\n */\nfunction nodeFactory(definition: AnyNodeDefinition, rootNodeDefinitionMap: RootNodeDefinitionMap): AnyNode {\n // Get the attributes for the node.\n const attributes = nodeAttributesFactory(definition);\n\n // Create the node instance based on the definition type.\n switch (definition.type) {\n case \"root\":\n return new Root(attributes, nodeFactory(definition.child, rootNodeDefinitionMap));\n\n case \"repeat\":\n let iterations: number | null = null;\n let iterationsMin: number | null = null;\n let iterationsMax: number | null = null;\n\n if (Array.isArray(definition.iterations)) {\n iterationsMin = definition.iterations[0];\n iterationsMax = definition.iterations[1];\n } else if (isInteger(definition.iterations)) {\n iterations = definition.iterations!;\n }\n\n return new Repeat(\n attributes,\n iterations,\n iterationsMin,\n iterationsMax,\n nodeFactory(definition.child, rootNodeDefinitionMap)\n );\n\n case \"retry\":\n let attempts: number | null = null;\n let attemptsMin: number | null = null;\n let attemptsMax: number | null = null;\n\n if (Array.isArray(definition.attempts)) {\n attemptsMin = definition.attempts[0];\n attemptsMax = definition.attempts[1];\n } else if (isInteger(definition.attempts)) {\n attempts = definition.attempts!;\n }\n\n return new Retry(\n attributes,\n attempts,\n attemptsMin,\n attemptsMax,\n nodeFactory(definition.child, rootNodeDefinitionMap)\n );\n\n case \"flip\":\n return new Flip(attributes, nodeFactory(definition.child, rootNodeDefinitionMap));\n\n case \"succeed\":\n return new Succeed(attributes, nodeFactory(definition.child, rootNodeDefinitionMap));\n\n case \"fail\":\n return new Fail(attributes, nodeFactory(definition.child, rootNodeDefinitionMap));\n\n case \"sequence\":\n return new Sequence(\n attributes,\n definition.children.map((child) => nodeFactory(child, rootNodeDefinitionMap))\n );\n\n case \"selector\":\n return new Selector(\n attributes,\n definition.children.map((child) => nodeFactory(child, rootNodeDefinitionMap))\n );\n\n case \"parallel\":\n return new Parallel(\n attributes,\n definition.children.map((child) => nodeFactory(child, rootNodeDefinitionMap))\n );\n\n case \"lotto\":\n return new Lotto(\n attributes,\n definition.weights,\n definition.children.map((child) => nodeFactory(child, rootNodeDefinitionMap))\n );\n\n case \"branch\":\n return nodeFactory(rootNodeDefinitionMap[definition.ref].child, rootNodeDefinitionMap);\n\n case \"action\":\n return new Action(attributes, definition.call, definition.args || []);\n\n case \"condition\":\n return new Condition(attributes, definition.call, definition.args || []);\n\n case \"wait\":\n let duration: number | null = null;\n let durationMin: number | null = null;\n let durationMax: number | null = null;\n\n if (Array.isArray(definition.duration)) {\n durationMin = definition.duration[0];\n durationMax = definition.duration[1];\n } else if (isInteger(definition.duration)) {\n duration = definition.duration!;\n }\n\n return new Wait(attributes, duration, durationMin, durationMax);\n }\n}\n\n/**\n * Creates an array of node attribute instances based on the specified node definition.\n * @param definition The node definition.\n * @returns An array of node attribute instances based on the specified node definition.\n */\nfunction nodeAttributesFactory(definition: AnyNodeDefinition): Attribute[] {\n const attributes: Attribute[] = [];\n\n if (definition.while) {\n attributes.push(new While(definition.while.call, definition.while.args ?? []));\n }\n\n if (definition.until) {\n attributes.push(new Until(definition.until.call, definition.until.args ?? []));\n }\n\n if (definition.entry) {\n attributes.push(new Entry(definition.entry.call, definition.entry.args ?? []));\n }\n\n if (definition.step) {\n attributes.push(new Step(definition.step.call, definition.step.args ?? []));\n }\n\n if (definition.exit) {\n attributes.push(new Exit(definition.exit.call, definition.exit.args ?? []));\n }\n\n return attributes;\n}\n\n/**\n * Creates a mapping of root node identifers to root node definitions, mixing in globally registered subtree root node definitions.\n * @param definition The root node definitions.\n * @returns A mapping of root node identifers to root node definitions, including globally registered subtree root node definitions.\n */\nfunction createRootNodeDefinitionMap(definition: RootNodeDefinition[]): RootNodeDefinitionMap {\n // Create a mapping of root node identifers to root node definitions.\n const rootNodeMap: RootNodeDefinitionMap = {};\n\n // Add in any registered subtree root node definitions.\n for (const [name, rootNodeDefinition] of Object.entries(Lookup.getSubtrees())) {\n // The name used when registering the subtree will be used as the root node identifier.\n rootNodeMap[name] = { ...rootNodeDefinition, id: name };\n }\n\n // Populate the map with the root node definitions that were included with the tree definition.\n // We do this after adding any registered subtrees as we want these to take presedence.\n for (const rootNodeDefinition of definition) {\n rootNodeMap[rootNodeDefinition.id ?? MAIN_ROOT_NODE_KEY] = rootNodeDefinition;\n }\n\n return rootNodeMap;\n}\n\n/**\n * Applies a guard path to every leaf of the tree to evaluate as part of each update.\n * @param root The main root tree node.\n */\nfunction applyLeafNodeGuardPaths(root: Root) {\n const nodePaths: Node[][] = [];\n\n const findLeafNodes = (path: Node[], node: Node) => {\n // Add the current node to the path.\n path = path.concat(node);\n\n // Check whether the current node is a leaf node.\n if (node.isLeafNode()) {\n nodePaths.push(path);\n } else {\n (node as Composite | Decorator).getChildren().forEach((child) => findLeafNodes(path, child));\n }\n };\n\n // Find all leaf node paths, starting from the root.\n findLeafNodes([], root);\n\n nodePaths.forEach((path) => {\n // Each node in the current path will have to be assigned a guard path, working from the root outwards.\n for (let depth = 0; depth < path.length; depth++) {\n // Get the node in the path at the current depth.\n const currentNode = path[depth];\n\n // The node may already have been assigned a guard path, if so just skip it.\n if (currentNode.hasGuardPath()) {\n continue;\n }\n\n // Create the guard path for the current node.\n const guardPath = new GuardPath(\n path\n .slice(0, depth + 1)\n .map((node) => ({ node, guards: node.getGuardAttributes() }))\n .filter((details) => details.guards.length > 0)\n );\n\n // Assign the guard path to the current node.\n currentNode.setGuardPath(guardPath);\n }\n });\n}\n", "import State, { AnyState } from \"./State\";\nimport Lookup from \"./Lookup\";\nimport Node from \"./nodes/Node\";\nimport Root from \"./nodes/decorator/Root\";\nimport Composite from \"./nodes/composite/Composite\";\nimport Decorator from \"./nodes/decorator/Decorator\";\nimport { Agent, GlobalFunction } from \"./Agent\";\nimport { CallbackAttributeDetails } from \"./attributes/callbacks/Callback\";\nimport { GuardAttributeDetails } from \"./attributes/guards/Guard\";\nimport { BehaviourTreeOptions } from \"./BehaviourTreeOptions\";\nimport { convertMDSLToJSON } from \"./mdsl/MDSLDefinitionParser\";\nimport { RootNodeDefinition } from \"./BehaviourTreeDefinition\";\nimport { validateDefinition, validateJSONDefinition } from \"./BehaviourTreeDefinitionValidator\";\nimport buildRootNode from \"./BehaviourTreeBuilder\";\nimport { isNullOrUndefined } from \"./BehaviourTreeDefinitionUtilities\";\n\n// Purely for outside inspection of the tree.\nexport type FlattenedTreeNode = {\n id: string;\n type: string;\n caption: string;\n state: AnyState;\n guards: GuardAttributeDetails[];\n callbacks: CallbackAttributeDetails[];\n args: any[];\n parentId: string | null;\n};\n\n/**\n * A representation of a behaviour tree.\n */\nexport class BehaviourTree {\n /**\n * The main root tree node.\n */\n public readonly rootNode: Root;\n\n /**\n * Creates a new instance of the BehaviourTree class.\n * @param definition The behaviour tree definition.\n * @param agent The agent instance that this behaviour tree is modelling behaviour for.\n * @param options The behaviour tree options object.\n */\n constructor(\n definition: string | RootNodeDefinition | RootNodeDefinition[],\n private agent: Agent,\n private options: BehaviourTreeOptions = {}\n ) {\n // The tree definition must be defined.\n if (isNullOrUndefined(definition)) {\n throw new Error(\"tree definition not defined\");\n }\n\n // The agent must be defined and not null.\n if (typeof agent !== \"object\" || agent === null) {\n throw new Error(\"the agent must be an object and not null\");\n }\n\n // We should validate the definition before we try to build the tree nodes.\n const { succeeded, errorMessage, json } = validateDefinition(definition);\n\n // Did our validation fail without error?\n if (!succeeded) {\n throw new Error(`invalid definition: ${errorMessage}`);\n }\n\n // Double check that we did actually get our json definition as part of our definition validtion.\n if (!json) {\n throw new Error(\n \"expected json definition to be returned as part of successful definition validation response\"\n );\n }\n\n try {\n // Create the populated tree of behaviour tree nodes and get the root node.\n this.rootNode = buildRootNode(json!);\n } catch (exception) {\n // There was an issue in trying build and populate the behaviour tree.\n throw new Error(`error building tree: ${(exception as Error).message}`);\n }\n }\n\n /**\n * Gets whether the tree is in the RUNNING state.\n * @returns true if the tree is in the RUNNING state, otherwise false.\n */\n isRunning() {\n return this.rootNode.getState() === State.RUNNING;\n }\n\n /**\n * Gets the current tree state of SUCCEEDED, FAILED, READY or RUNNING.\n * @returns The current tree state.\n */\n getState() {\n return this.rootNode.getState();\n }\n\n /**\n * Step the tree.\n * 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.\n * 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\n * 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.\n *\n * 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.\n */\n step() {\n // If the root node has already been stepped to completion then we need to reset it.\n if (this.rootNode.getState() === State.SUCCEEDED || this.rootNode.getState() === State.FAILED) {\n this.rootNode.reset();\n }\n\n try {\n this.rootNode.update(this.agent, this.options);\n } catch (exception) {\n throw new Error(`error stepping tree: ${(exception as Error).message}`);\n }\n }\n\n /**\n * Resets the tree from the root node outwards to each nested node, giving each a state of READY.\n */\n reset() {\n this.rootNode.reset();\n }\n\n /**\n * Gets the flattened details of every node in the tree.\n * @returns The flattened details of every node in the tree.\n */\n getFlattenedNodeDetails(): FlattenedTreeNode[] {\n // Create an empty flattened array of tree nodes.\n const flattenedTreeNodes: FlattenedTreeNode[] = [];\n\n /**\n * Helper function to process a node instance and push details into the flattened tree nodes array.\n * @param node The current node.\n * @param parentUid The UID of the node parent, or null if the node is the main root node.\n */\n const processNode = (node: Node, parentUid: string | null) => {\n // Get the guard and callback attribute details for this node.\n const guards = node\n .getAttributes()\n .filter((attribute) => attribute.isGuard())\n .map((attribute) => attribute.getDetails()) as GuardAttributeDetails[];\n const callbacks = node\n .getAttributes()\n .filter((attribute) => !attribute.isGuard())\n .map((attribute) => attribute.getDetails()) as CallbackAttributeDetails[];\n\n // Push the current node into the flattened nodes array.\n flattenedTreeNodes.push({\n id: node.getUid(),\n type: node.getType(),\n caption: node.getName(),\n state: node.getState(),\n guards,\n callbacks,\n args: node.getArguments(),\n parentId: parentUid\n });\n\n // Process each of the nodes children if it is not a leaf node.\n if (!node.isLeafNode()) {\n (node as Composite | Decorator)\n .getChildren()\n .forEach((child) => processNode(child, (node as Composite | Decorator).getUid()));\n }\n };\n\n // Convert the nested node structure into a flattened array of node details.\n processNode(this.rootNode, null);\n\n return flattenedTreeNodes;\n }\n\n /**\n * Registers the action/condition/guard/callback function or subtree with the given name.\n * @param name The name of the function or subtree to register.\n * @param value The function or subtree definition to register.\n */\n static register(name: string, value: GlobalFunction | string | RootNodeDefinition) {\n // Are we going to register a action/condition/guard/callback function?\n if (typeof value === \"function\") {\n Lookup.setFunc(name, value);\n return;\n }\n\n // We are not registering an action/condition/guard/callback function, so we must be registering a subtree.\n if (typeof value === \"string\") {\n let rootNodeDefinitions: RootNodeDefinition[];\n\n // We will assume that any string passed in will be a mdsl definition.\n try {\n rootNodeDefinitions = convertMDSLToJSON(value);\n } catch (exception) {\n throw new Error(`error registering definition, invalid MDSL: ${(exception as Error).message}`);\n }\n\n // This function should only ever be called with a definition containing a single unnamed root node.\n if (rootNodeDefinitions.length != 1 || rootNodeDefinitions[0].id !== null) {\n throw new Error(\"error registering definition: expected a single unnamed root node\");\n }\n\n try {\n // We should validate the subtree as we don't want invalid subtrees available via the lookup.\n const { succeeded, errorMessage } = validateJSONDefinition(rootNodeDefinitions[0]);\n\n // Did our validation fail without error?\n if (!succeeded) {\n throw new Error(errorMessage);\n }\n } catch (exception) {\n throw new Error(`error registering definition: ${(exception as Error).message}`);\n }\n\n // Everything seems hunky-dory, register the subtree.\n Lookup.setSubtree(name, rootNodeDefinitions[0]);\n } else if (typeof value === \"object\" && !Array.isArray(value)) {\n // We will assume that any object passed in is a root node definition.\n\n try {\n // We should validate the subtree as we don't want invalid subtrees available via the lookup.\n const { succeeded, errorMessage } = validateJSONDefinition(value);\n\n // Did our validation fail without error?\n if (!succeeded) {\n throw new Error(errorMessage);\n }\n } catch (exception) {\n throw new Error(`error registering definition: ${(exception as Error).message}`);\n }\n\n // Everything seems hunky-dory, register the subtree.\n Lookup.setSubtree(name, value);\n } else {\n throw new Error(\"unexpected value, expected string mdsl definition, root node json definition or function\");\n }\n }\n\n /**\n * Unregisters the registered action/condition/guard/callback function or subtree with the given name.\n * @param name The name of the registered action/condition/guard/callback function or subtree to unregister.\n */\n static unregister(name: string): void {\n Lookup.remove(name);\n }\n\n /**\n * Unregister all registered action/condition/guard/callback functions and subtrees.\n */\n static unregisterAll(): void {\n Lookup.empty();\n }\n}\n"], - "mappings": "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", + "sourcesContent": ["\"use strict\";\r\nObject.defineProperty(exports, \"__esModule\", { value: true });\r\nexports.Participant = void 0;\r\n/**\r\n * A participant that holds a number of tickets.\r\n */\r\nvar Participant = /** @class */ (function () {\r\n /**\r\n * Creates an instance of the Participant class.\r\n * @param participant The actual participant.\r\n * @param tickets The number of tickets held by the participant.\r\n */\r\n function Participant(participant, tickets) {\r\n if (tickets === void 0) { tickets = 1; }\r\n this._participant = participant;\r\n this._tickets = tickets;\r\n }\r\n Object.defineProperty(Participant.prototype, \"participant\", {\r\n /** Gets the actual participant. */\r\n get: function () {\r\n return this._participant;\r\n },\r\n enumerable: false,\r\n configurable: true\r\n });\r\n Object.defineProperty(Participant.prototype, \"tickets\", {\r\n /** Gets or sets the number of tickets held by the participant. */\r\n get: function () {\r\n return this._tickets;\r\n },\r\n set: function (value) {\r\n this._tickets = value;\r\n },\r\n enumerable: false,\r\n configurable: true\r\n });\r\n return Participant;\r\n}());\r\nexports.Participant = Participant;\r\n", "\"use strict\";\r\nObject.defineProperty(exports, \"__esModule\", { value: true });\r\nexports.isNaturalNumber = exports.isNullOrUndefined = void 0;\r\n/**\r\n * Gets whether the value provided is null or undefined.\r\n * @param value The value to check.\r\n * @returns Whether the value provided is null or undefined.\r\n */\r\nfunction isNullOrUndefined(value) {\r\n return value === null || value === undefined;\r\n}\r\nexports.isNullOrUndefined = isNullOrUndefined;\r\n/**\r\n * Gets whether the value provided is a natural number.\r\n * @param value The value to check.\r\n * @returns Whether the value provided is a natural number.\r\n */\r\nfunction isNaturalNumber(value) {\r\n return typeof value === \"number\" && value >= 1 && Math.floor(value) === value;\r\n}\r\nexports.isNaturalNumber = isNaturalNumber;\r\n", "\"use strict\";\r\nObject.defineProperty(exports, \"__esModule\", { value: true });\r\nexports.Lotto = void 0;\r\nvar Participant_1 = require(\"./Participant\");\r\nvar Utilities_1 = require(\"./Utilities\");\r\n/**\r\n * Represents a lotto consisting of a number of pickable ticket-holding participants.\r\n */\r\nvar Lotto = /** @class */ (function () {\r\n /**\r\n * Creates a new instance of Lotto.\r\n * @param customRandom The custom RNG to use in place of Math.random().\r\n */\r\n function Lotto(customRandom) {\r\n /** The array of participants that are holding tickets in the lotto. */\r\n this._participants = [];\r\n this._customRandom = customRandom;\r\n }\r\n /**\r\n * Adds a participant with the specified number of tickets, or adds to the participant ticket count if the participant already holds tickets.\r\n * @param participant The participant to add or to increase the ticket count for if they already hold tickets.\r\n * @param tickets The number of tickets, defaults to 1.\r\n * @returns The Lotto instance.\r\n */\r\n Lotto.prototype.add = function (participant, tickets) {\r\n if (tickets === void 0) { tickets = 1; }\r\n // Check that we have a valid ticket count.\r\n if (!(0, Utilities_1.isNaturalNumber)(tickets)) {\r\n throw new Error(\"tickets value must be a natural number\");\r\n }\r\n // Check whether this participant has already been added.\r\n var existingParticipant = this._participants.find(function (part) { return part.participant === participant; });\r\n if (existingParticipant) {\r\n // The participant has already been added to the lotto so just add to their ticket count.\r\n existingParticipant.tickets += tickets;\r\n }\r\n else {\r\n // The participant is not part of the lotto so we should add them.\r\n this._participants.push(new Participant_1.Participant(participant, tickets));\r\n }\r\n return this;\r\n };\r\n /**\r\n * Removes the specified number of tickets for the given participant from the draw, or all tickets if a ticket number is not defined.\r\n * @param participant The participant to remove tickets for.\r\n * @param tickets The number of tickets to remove, or undefined if all tickets are to be removed.\r\n * @returns The Lotto instance.\r\n */\r\n Lotto.prototype.remove = function (participant, tickets) {\r\n // Attempt to get the existing participant.\r\n var existingParticipant = this._participants.find(function (part) { return part.participant === participant; });\r\n // There is nothing to do if the specified participant isn't even part of the lotto.\r\n if (!existingParticipant) {\r\n return this;\r\n }\r\n // Check whether a tickets value was given.\r\n if (tickets !== undefined) {\r\n // Check that we have a valid ticket count.\r\n if (!(0, Utilities_1.isNaturalNumber)(tickets)) {\r\n throw new Error(\"tickets value must be a natural number\");\r\n }\r\n existingParticipant.tickets -= tickets;\r\n // If the participant no longer holds any tickets then they should be removed.\r\n if (existingParticipant.tickets < 1) {\r\n this._participants = this._participants.filter(function (part) { return part !== existingParticipant; });\r\n }\r\n }\r\n else {\r\n // We are removing all tickets for the participant so just remove them from the lotto.\r\n this._participants = this._participants.filter(function (part) { return part !== existingParticipant; });\r\n }\r\n return this;\r\n };\r\n /**\r\n * Draw a winning ticket and return the participant that holds the ticket.\r\n * @param options The draw options.\r\n * @returns The participant that holds the winning ticket.\r\n */\r\n Lotto.prototype.draw = function (options) {\r\n if (options === void 0) { options = {}; }\r\n // If we have no participants then just return null.\r\n if (this._participants.length === 0) {\r\n return null;\r\n }\r\n var redrawable = (0, Utilities_1.isNullOrUndefined)(options.redrawable) ? true : options.redrawable;\r\n var pickable = [];\r\n this._participants.forEach(function (_a) {\r\n var participant = _a.participant, tickets = _a.tickets;\r\n for (var ticketCount = 0; ticketCount < tickets; ticketCount++) {\r\n pickable.push(participant);\r\n }\r\n });\r\n var random;\r\n // We need a random floating-point number between 0 (inclusive) and 1 to scale up to pick our winner.\r\n // If a custom random function exists then we should use that or fall back to Math.random().\r\n if (this._customRandom) {\r\n // Call our custom random function to get a random floating-point number.\r\n random = this._customRandom();\r\n // Verify that the result of calling our custom random function is a number between 0 (inclusive) and 1.\r\n if (typeof random !== \"number\" || random < 0 || random >= 1) {\r\n throw new Error(\"the 'random' function provided did not return a number between 0 (inclusive) and 1\");\r\n }\r\n }\r\n else {\r\n // No custom random function was defined so just use good ol' Math.random().\r\n random = Math.random();\r\n }\r\n // Pick a winning participant.\r\n var winner = pickable[Math.floor(random * pickable.length)];\r\n // If the ticket isn't redrawable then we should remove a ticket from the winning participants ticket count.\r\n if (!redrawable) {\r\n this.remove(winner, 1);\r\n }\r\n // Return the winning participant.\r\n return winner;\r\n };\r\n /**\r\n * Draws multiple winning tickets and return an array of the participants that hold the winning tickets.\r\n * @param tickets The number of winning tickets to draw.\r\n * @param options The draw multiple options.\r\n * @returns An array of the participants that hold the winning tickets.\r\n */\r\n Lotto.prototype.drawMultiple = function (tickets, options) {\r\n if (options === void 0) { options = {}; }\r\n var uniqueResults = (0, Utilities_1.isNullOrUndefined)(options.unique) ? false : options.unique;\r\n // Handle cases where the user has asked for zero tickets (no idea why they would do this be we should trust them).\r\n if (tickets === 0) {\r\n return [];\r\n }\r\n // Now that we know out tickets value is not zero we should check that it is a valid natural number.\r\n if (!(0, Utilities_1.isNaturalNumber)(tickets)) {\r\n throw new Error(\"tickets value must be a natural number\");\r\n }\r\n var result = [];\r\n // Keep drawing tickets until we either reach the number of required tickets or we simply run out of tickets to draw.\r\n // We can run out of tickets to draw if 'options.redrawable' is explicity 'false' or we just had no participants when 'drawMultiple' was called.\r\n while (result.length < tickets && this._participants.length > 0) {\r\n result.push(this.draw(options));\r\n }\r\n // If the 'unique' draw option is set then we need to remove duplicates from the result list.\r\n if (uniqueResults) {\r\n // Create an array to store our unique results.\r\n var unique = [];\r\n // Iterate over all of our participants (with potential duplicates) and populate our array of unique values.\r\n for (var _i = 0, result_1 = result; _i < result_1.length; _i++) {\r\n var participant = result_1[_i];\r\n if (unique.indexOf(participant) === -1) {\r\n unique.push(participant);\r\n }\r\n }\r\n result = unique;\r\n }\r\n return result;\r\n };\r\n return Lotto;\r\n}());\r\nexports.Lotto = Lotto;\r\n", "\"use strict\";\r\nObject.defineProperty(exports, \"__esModule\", { value: true });\r\nexports.createLotto = void 0;\r\nvar Lotto_1 = require(\"./Lotto\");\r\n/**\r\n * A function that creates and returns a Lotto instance.\r\n * @param participantsOrOptions An array of initial participants or options relating to the creation of a Lotto instance.\r\n * @returns A new Lotto instance.\r\n */\r\nfunction createLotto(participantsOrOptions) {\r\n // If no initial participants or lotto options were provided as an argument then we can just return a new lotto instance now.\r\n if (!participantsOrOptions) {\r\n return new Lotto_1.Lotto();\r\n }\r\n // Check whether we were provided with an array of initial participants or a lotto options object.\r\n if (Array.isArray(participantsOrOptions)) {\r\n // We are dealing with a pre-defined array of participants.\r\n var participants = participantsOrOptions;\r\n var lotto_1 = new Lotto_1.Lotto();\r\n // If the lotto participants have been defined upfront then we will need to add them all to our lotto instance now.\r\n participants.forEach(function (_a) {\r\n var participant = _a[0], tokens = _a[1];\r\n return lotto_1.add(participant, tokens);\r\n });\r\n // Return the Lotto instance.\r\n return lotto_1;\r\n }\r\n else {\r\n // We are dealing with some lotto options.\r\n var random = participantsOrOptions.random, participants = participantsOrOptions.participants;\r\n // Create a Lotto instance passing the custom RNG function to use in place of Math.random() (which could be undefined).\r\n var lotto_2 = new Lotto_1.Lotto(random);\r\n // If the lotto participants have been defined upfront as part of the options then we will need to add them all to our lotto instance now.\r\n if (participants) {\r\n participants.forEach(function (_a) {\r\n var participant = _a[0], tokens = _a[1];\r\n return lotto_2.add(participant, tokens);\r\n });\r\n }\r\n // Return the Lotto instance.\r\n return lotto_2;\r\n }\r\n}\r\nexports.createLotto = createLotto;\r\n", "\"use strict\";\r\nObject.defineProperty(exports, \"__esModule\", { value: true });\r\nvar createLotto_1 = require(\"./createLotto\");\r\nexports.default = createLotto_1.createLotto;\r\n", "import State from \"./State\";\nimport { validateDefinition } from \"./BehaviourTreeDefinitionValidator\";\nimport { convertMDSLToJSON } from \"./mdsl/MDSLDefinitionParser\";\nimport { BehaviourTree, FlattenedTreeNode } from \"./BehaviourTree\";\nimport { BehaviourTreeOptions } from \"./BehaviourTreeOptions\";\n\nexport { BehaviourTree, State, convertMDSLToJSON, validateDefinition };\nexport type { FlattenedTreeNode, BehaviourTreeOptions };\n", "/**\n * Enumeration of node state types.\n */\nexport enum State {\n READY = \"mistreevous.ready\",\n RUNNING = \"mistreevous.running\",\n SUCCEEDED = \"mistreevous.succeeded\",\n FAILED = \"mistreevous.failed\"\n}\n\nexport { State as default };\n\nexport type CompleteState = State.SUCCEEDED | State.FAILED;\nexport type AnyState = State.READY | State.RUNNING | CompleteState;\n", "import {\n NodeDefinition,\n RootNodeDefinition,\n DecoratorNodeDefinition,\n CompositeNodeDefinition,\n AnyNodeDefinition,\n BranchNodeDefinition\n} from \"./BehaviourTreeDefinition\";\n\n/**\n * A type guard function that returns true if the specified node satisfies the RootNodeDefinition type.\n * @param node The node.\n * @returns A value of true if the specified node satisfies the RootNodeDefinition type.\n */\nexport function isRootNode(node: NodeDefinition): node is RootNodeDefinition {\n return node.type === \"root\";\n}\n\n/**\n * A type guard function that returns true if the specified node satisfies the BranchNodeDefinition type.\n * @param node The node.\n * @returns A value of true if the specified node satisfies the BranchNodeDefinition type.\n */\nexport function isBranchNode(node: NodeDefinition): node is BranchNodeDefinition {\n return node.type === \"branch\";\n}\n\n/**\n * A type guard function that returns true if the specified node satisfies the NodeDefinition type.\n * @param node The node.\n * @returns A value of true if the specified node satisfies the NodeDefinition type.\n */\nexport function isLeafNode(node: NodeDefinition): node is NodeDefinition {\n return [\"branch\", \"action\", \"condition\", \"wait\"].includes(node.type);\n}\n\n/**\n * A type guard function that returns true if the specified node satisfies the DecoratorNodeDefinition type.\n * @param node The node.\n * @returns A value of true if the specified node satisfies the DecoratorNodeDefinition type.\n */\nexport function isDecoratorNode(node: NodeDefinition): node is DecoratorNodeDefinition {\n return [\"root\", \"repeat\", \"retry\", \"flip\", \"succeed\", \"fail\"].includes(node.type);\n}\n\n/**\n * A type guard function that returns true if the specified node satisfies the CompositeNodeDefinition type.\n * @param node The node.\n * @returns A value of true if the specified node satisfies the CompositeNodeDefinition type.\n */\nexport function isCompositeNode(node: NodeDefinition): node is CompositeNodeDefinition {\n return [\"sequence\", \"selector\", \"lotto\", \"parallel\"].includes(node.type);\n}\n\n/**\n * Flatten a node definition into an array of all of its nested node definitions.\n * @param nodeDefinition The node definition to flatten.\n * @returns An array of all of nested node definitions.\n */\nexport function flattenDefinition(nodeDefinition: AnyNodeDefinition): AnyNodeDefinition[] {\n const nodes: AnyNodeDefinition[] = [];\n\n const processNode = (currentNodeDefinition: AnyNodeDefinition) => {\n nodes.push(currentNodeDefinition);\n\n if (isCompositeNode(currentNodeDefinition)) {\n currentNodeDefinition.children.forEach(processNode);\n } else if (isDecoratorNode(currentNodeDefinition)) {\n processNode(currentNodeDefinition.child);\n }\n };\n\n processNode(nodeDefinition);\n\n return nodes;\n}\n\n/**\n * Determines whether the passed value is an integer.\n * @param value The value to check.\n * @returns Whether the passed value is an integer.\n */\nexport function isInteger(value: unknown): boolean {\n return typeof value === \"number\" && Math.floor(value) === value;\n}\n\n/**\n * Determines whether the passed value is null or undefined.\n * @param value The value to check.\n * @returns Whether the passed value is null or undefined.\n */\nexport function isNullOrUndefined(value: unknown): boolean {\n return typeof value === \"undefined\" || value === null;\n}\n", "/**\n * A type defining an object that holds a reference to substitued string literals parsed from the definition.\n */\nexport type StringLiteralPlaceholders = { [key: string]: string };\n\n/**\n * Pop the next raw token from the specified array of tokens and throw an error if it wasn't the expected one.\n * @param tokens The array of tokens.\n * @param expected An optional string or array or items, one of which must match the next popped token.\n * @returns The popped token.\n */\nexport function popAndCheck(tokens: string[], expected?: string | string[]): string {\n // Get and remove the next token.\n const popped = tokens.shift();\n\n // We were expecting another token but there aren't any.\n if (popped === undefined) {\n throw new Error(\"unexpected end of definition\");\n }\n\n // Do we have an expected token/tokens array?\n if (expected != undefined) {\n // Get an array of expected values, if the popped token matches any then we are all good.\n const expectedValues = typeof expected === \"string\" ? [expected] : expected;\n\n // Check whether the popped token matches at least one of our expected items.\n var tokenMatchesExpectation = expectedValues.some((item) => popped.toUpperCase() === item.toUpperCase());\n\n // Throw an error if the popped token didn't match any of our expected items.\n if (!tokenMatchesExpectation) {\n const expectationString = expectedValues.map((item) => \"'\" + item + \"'\").join(\" or \");\n throw new Error(\"unexpected token found. Expected \" + expectationString + \" but got '\" + popped + \"'\");\n }\n }\n\n // Return the popped token.\n return popped;\n}\n\n/**\n * Swaps out any node/attribute argument string literals with placeholders.\n * @param definition The definition.\n * @returns An object containing a mapping of placeholders to original string values as well as the processed definition string.\n */\nexport function substituteStringLiterals(definition: string): {\n placeholders: StringLiteralPlaceholders;\n processedDefinition: string;\n} {\n // Create an object to hold the mapping of placeholders to original string values.\n const placeholders: StringLiteralPlaceholders = {};\n\n // Replace any string literals wrapped with double quotes in our definition with placeholders to be processed later.\n const processedDefinition = definition.replace(/\\\"(\\\\.|[^\"\\\\])*\\\"/g, (match) => {\n var strippedMatch = match.substring(1, match.length - 1);\n var placeholder = Object.keys(placeholders).find((key) => placeholders[key] === strippedMatch);\n\n // If we have no existing string literal match then create a new placeholder.\n if (!placeholder) {\n placeholder = `@@${Object.keys(placeholders).length}@@`;\n placeholders[placeholder] = strippedMatch;\n }\n\n return placeholder;\n });\n\n return { placeholders, processedDefinition };\n}\n\n/**\n * Parse the tree definition into an array of raw tokens.\n * @param definition The definition.\n * @returns An array of tokens parsed from the definition.\n */\nexport function parseTokensFromDefinition(definition: string): string[] {\n // Add some space around various important characters so that they can be plucked out easier as individual tokens.\n definition = definition.replace(/\\(/g, \" ( \");\n definition = definition.replace(/\\)/g, \" ) \");\n definition = definition.replace(/\\{/g, \" { \");\n definition = definition.replace(/\\}/g, \" } \");\n definition = definition.replace(/\\]/g, \" ] \");\n definition = definition.replace(/\\[/g, \" [ \");\n definition = definition.replace(/\\,/g, \" , \");\n\n // Split the definition into raw token form and return it.\n return definition.replace(/\\s+/g, \" \").trim().split(\" \");\n}\n", "import { StringLiteralPlaceholders, popAndCheck } from \"./MDSLUtilities\";\n\n/**\n * A type representing any node function argument.\n */\ntype Argument = {\n /**\n * The argument value.\n */\n value: T;\n /**\n * The argument type, used for validation.\n */\n type: string;\n};\n\ntype NullArgument = Argument & {\n type: \"null\";\n};\n\ntype BooleanArgument = Argument & {\n type: \"boolean\";\n};\n\ntype NumberArgument = Argument & {\n type: \"number\";\n /**\n * A flag defining whether the number argument value is a valid integer. (used for validation)\n */\n isInteger: boolean;\n};\n\ntype StringPlaceholderArgument = Argument & {\n type: \"string\";\n};\n\ntype IdentifierArgument = Argument & {\n type: \"identifier\";\n};\n\n/**\n * A type representing a reference to any node function argument.\n */\ntype AnyArgument = NullArgument | BooleanArgument | NumberArgument | StringPlaceholderArgument | IdentifierArgument;\n\n/**\n * Parse an array of argument definitions from the specified tokens array.\n * @param tokens The array tokens to parse the argument definitions from.\n * @param stringArgumentPlaceholders The mapping of string literal node argument placeholders to original values.\n * @param argumentValidator The argument validator function.\n * @param validationFailedMessage The exception message to throw if argument validation fails.\n * @returns An array of argument definitions parsed from the specified tokens array.\n */\nexport function parseArgumentTokens(\n tokens: string[],\n stringArgumentPlaceholders: StringLiteralPlaceholders\n): AnyArgument[] {\n const argumentList: AnyArgument[] = [];\n\n // If the next token is not a '[' or '(' then we have no arguments to parse.\n if (![\"[\", \"(\"].includes(tokens[0])) {\n return argumentList;\n }\n\n // Any lists of arguments will always be wrapped in '[]' for node arguments or '()' for attribute arguments.\n // We are looking for a '[' or '(' opener that wraps the argument tokens and the relevant closer.\n const closingToken = popAndCheck(tokens, [\"[\", \"(\"]) === \"[\" ? \"]\" : \")\";\n\n const argumentListTokens: string[] = [];\n\n // Grab all tokens between the '[' and ']' or '(' and ')'.\n while (tokens.length && tokens[0] !== closingToken) {\n // The next token is part of our arguments list.\n argumentListTokens.push(tokens.shift()!);\n }\n\n // Validate the order of the argument tokens. Each token must either be a ',' or a single argument that satisfies the validator.\n argumentListTokens.forEach((token, index) => {\n // Get whether this token should be an actual argument.\n const shouldBeArgumentToken = !(index & 1);\n\n // If the current token should be an actual argument then validate it, otherwise it should be a ',' token.\n if (shouldBeArgumentToken) {\n // Get the argument definition.\n const argumentDefinition = getArgumentDefinition(token, stringArgumentPlaceholders);\n\n // This is a valid argument!\n argumentList.push(argumentDefinition);\n } else {\n // The current token should be a ',' token.\n if (token !== \",\") {\n throw new Error(`invalid argument list, expected ',' or ']' but got '${token}'`);\n }\n }\n });\n\n // The arguments list should terminate with a ']' or ')' token, depending on the opener.\n popAndCheck(tokens, closingToken);\n\n // Return the arguments.\n return argumentList;\n}\n\n/**\n * Gets an argument value definition.\n * @param token The argument token.\n * @param stringArgumentPlaceholders The mapping of string literal node argument placeholders to original values.\n * @returns An argument value definition.\n */\nfunction getArgumentDefinition(token: string, stringArgumentPlaceholders: StringLiteralPlaceholders): AnyArgument {\n // Check whether the token represents a null value.\n if (token === \"null\") {\n return {\n value: null,\n type: \"null\"\n } as NullArgument;\n }\n\n // Check whether the token represents a boolean value.\n if (token === \"true\" || token === \"false\") {\n return {\n value: token === \"true\",\n type: \"boolean\"\n } as BooleanArgument;\n }\n\n // Check whether the token represents a number value.\n // TODO: Relies on broken isNaN - see MDN.\n // if (!Number.isNaN(token)) {\n if (!isNaN(token as any)) {\n return {\n value: parseFloat(token),\n isInteger: parseFloat(token) === parseInt(token, 10),\n type: \"number\"\n } as NumberArgument;\n }\n\n // Check whether the token is a placeholder (e.g. @@0@@) representing a string literal.\n if (token.match(/^@@\\d+@@$/g)) {\n return {\n value: stringArgumentPlaceholders[token].replace('\\\\\"', '\"'),\n type: \"string\"\n } as StringPlaceholderArgument;\n }\n\n // The only remaining option is that the argument value is an identifier.\n return {\n value: token,\n type: \"identifier\"\n } as IdentifierArgument;\n}\n", "import { NodeAttributeDefinition } from \"../BehaviourTreeDefinition\";\nimport { parseArgumentTokens } from \"./MDSLNodeArgumentParser\";\nimport { StringLiteralPlaceholders } from \"./MDSLUtilities\";\n\n/**\n * A type defining the attribute definitions of a node.\n */\ntype NodeAttributes = {\n while?: NodeAttributeDefinition;\n until?: NodeAttributeDefinition;\n entry?: NodeAttributeDefinition;\n exit?: NodeAttributeDefinition;\n step?: NodeAttributeDefinition;\n};\n\n/**\n * Parse any node attribute definitions from the specified tokens array.\n * @param tokens The array of remaining tokens.\n * @param stringArgumentPlaceholders The mapping of string literal node argument placeholders to original values.\n * @returns An object of attribute definitions defined by any directly following tokens.\n */\nexport function parseAttributeTokens(\n tokens: string[],\n stringArgumentPlaceholders: StringLiteralPlaceholders\n): NodeAttributes {\n const nodeAttributeNames: (keyof NodeAttributes)[] = [\"while\", \"until\", \"entry\", \"exit\", \"step\"];\n\n // Create an object to hold any attributes found.\n const attributes: NodeAttributes = {};\n\n // Try to get the name of the attribute for the next token.\n let nextAttributeName = tokens[0]?.toLowerCase() as keyof NodeAttributes;\n\n // Pull attribute tokens as well as their arguments off of the tokens stack until we have no more.\n while (nodeAttributeNames.includes(nextAttributeName)) {\n // Check to make sure that we have not already created an attribute definition of this type.\n if (attributes[nextAttributeName]) {\n throw new Error(`duplicate attribute '${tokens[0].toUpperCase()}' found for node`);\n }\n\n // Remove the attribute name token from the array of tokens.\n tokens.shift();\n\n // Grab the attribute arguments, assuming the first to be an identifier.\n const [attributeCallIdentifier, ...attributeArguments] = parseArgumentTokens(\n tokens,\n stringArgumentPlaceholders\n );\n\n // The first attribute argument has to be an identifer, this will reference an agent function.\n if (attributeCallIdentifier?.type !== \"identifier\") {\n throw new Error(\"expected agent function name identifier argument for attribute\");\n }\n\n // Any attribute arguments (other than the expected call identifier) must have a type of string, number, boolean or null.\n attributeArguments\n .filter((arg) => arg.type === \"identifier\")\n .forEach((arg) => {\n throw new Error(\n `invalid attribute argument value '${arg.value}', must be string, number, boolean or null`\n );\n });\n\n // Create the attribute definition and add it to the object of attribute definitions found.\n attributes[nextAttributeName] = {\n call: attributeCallIdentifier.value,\n args: attributeArguments.map(({ value }) => value)\n };\n\n // Try to get the next attribute name token, as there could be multiple.\n nextAttributeName = tokens[0]?.toLowerCase() as keyof NodeAttributes;\n }\n\n return attributes;\n}\n", "import {\n ActionNodeDefinition,\n AnyChildNodeDefinition,\n AnyNodeDefinition,\n BranchNodeDefinition,\n ConditionNodeDefinition,\n FailNodeDefinition,\n FlipNodeDefinition,\n LottoNodeDefinition,\n ParallelNodeDefinition,\n RepeatNodeDefinition,\n RetryNodeDefinition,\n RootNodeDefinition,\n SelectorNodeDefinition,\n SequenceNodeDefinition,\n SucceedNodeDefinition,\n WaitNodeDefinition\n} from \"../BehaviourTreeDefinition\";\nimport {\n isCompositeNode,\n isDecoratorNode,\n isLeafNode,\n isNullOrUndefined,\n isRootNode\n} from \"../BehaviourTreeDefinitionUtilities\";\nimport { parseArgumentTokens } from \"./MDSLNodeArgumentParser\";\nimport { parseAttributeTokens } from \"./MDSLNodeAttributeParser\";\nimport {\n StringLiteralPlaceholders,\n parseTokensFromDefinition,\n popAndCheck,\n substituteStringLiterals\n} from \"./MDSLUtilities\";\n\n/**\n * Convert the MDSL tree definition string into an equivalent JSON definition.\n * @param definition The tree definition string as MDSL.\n * @returns The root node JSON definitions.\n */\nexport function convertMDSLToJSON(definition: string): RootNodeDefinition[] {\n // Swap out any node/attribute argument string literals with a placeholder and get a mapping of placeholders to original values as well as the processed definition.\n const { placeholders, processedDefinition } = substituteStringLiterals(definition);\n\n // Parse our definition definition string into an array of raw tokens.\n const tokens = parseTokensFromDefinition(processedDefinition);\n\n return convertTokensToJSONDefinition(tokens, placeholders);\n}\n\n/**\n * Converts the specified tree definition tokens into a JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The root node JSON definitions.\n */\nfunction convertTokensToJSONDefinition(\n tokens: string[],\n stringLiteralPlaceholders: StringLiteralPlaceholders\n): RootNodeDefinition[] {\n // There must be at least 3 tokens for the tree definition to be valid. 'ROOT', '{' and '}'.\n if (tokens.length < 3) {\n throw new Error(\"invalid token count\");\n }\n\n // We should have a matching number of '{' and '}' tokens. If not, then there are scopes that have not been properly closed.\n if (tokens.filter((token) => token === \"{\").length !== tokens.filter((token) => token === \"}\").length) {\n throw new Error(\"scope character mismatch\");\n }\n\n // Create an array of tree stack arrays where root nodes will always be at the botton and the current composite/decorator node at the top.\n // There should be an element in this array for every root node defined and every element should be an array with a root note as the first element.\n // E.g. A definition with two root nodes defined:\n // [\n // [root, lotto, sequence],\n // [root, selector]\n // ]\n const treeStacks: [Partial, ...Partial[]][] = [];\n\n // Create an array of all root node definitions that we create.\n const rootNodes: Partial[] = [];\n\n // A helper function used to push node definitions onto the tree stack.\n const pushNode = (node: AnyNodeDefinition) => {\n // If the node is a root node then we need to create a new tree stack array with the root node at the root.\n if (isRootNode(node)) {\n // We need to double-check that this root node is not the child of another node.\n // We can do this by checking whether the top tree stack is not empty (contains an existing node)\n if (treeStacks[treeStacks.length - 1]?.length) {\n throw new Error(\"a root node cannot be the child of another node\");\n }\n\n // Add the root node definition to our array of all parsed root node definitions.\n rootNodes.push(node);\n\n // Add the root node definition to the root of a new tree stack.\n treeStacks.push([node]);\n\n return;\n }\n\n // All non-root nodes should be pushed after their root nodes so handle cases\n // where we may not have any tree stacks or our top-most tree stack is empty.\n if (!treeStacks.length || !treeStacks[treeStacks.length - 1].length) {\n throw new Error(\"expected root node at base of definition\");\n }\n\n // Get the current tree stack that we are populating.\n const topTreeStack = treeStacks[treeStacks.length - 1];\n\n // Get the top-most node in the current tree stack, this will be a composite/decorator node\n // for which we will populate its children array if composite or setting its child if a decorator.\n const topTreeStackTopNode = topTreeStack[topTreeStack.length - 1] as AnyNodeDefinition;\n\n // If the top-most node in the current root stack is a composite or decorator\n // node then the current node should be added as a child of the top-most node.\n if (isCompositeNode(topTreeStackTopNode)) {\n topTreeStackTopNode.children = topTreeStackTopNode.children || [];\n topTreeStackTopNode.children.push(node);\n } else if (isDecoratorNode(topTreeStackTopNode)) {\n // If the top node already has a child node set then throw an error as a decorator should only have a single child.\n if (topTreeStackTopNode.child) {\n throw new Error(\"a decorator node must only have a single child node\");\n }\n\n topTreeStackTopNode.child = node;\n }\n\n // If the node we are adding is also a composite or decorator node, then we should push it\n // onto the current tree stack, as subsequent nodes will be added as its child/children.\n if (!isLeafNode(node)) {\n topTreeStack.push(node);\n }\n };\n\n // A helper function used to pop the top-most node definition off of the tree stack and return it.\n const popNode = (): AnyNodeDefinition | null => {\n let poppedNode: AnyNodeDefinition | null = null;\n\n // Get the current tree stack that we are populating.\n const topTreeStack = treeStacks[treeStacks.length - 1];\n\n // Pop the top-most node in the current tree stack if there is one.\n if (topTreeStack.length) {\n poppedNode = topTreeStack.pop() as AnyNodeDefinition;\n }\n\n // We don't want any empty tree stacks in our stack of tree stacks.\n if (!topTreeStack.length) {\n treeStacks.pop();\n }\n\n return poppedNode;\n };\n\n // We should keep processing the raw tokens until we run out of them.\n while (tokens.length) {\n // Grab the next token.\n const token = tokens.shift()!;\n\n // How we create the next node depends on the current raw token value.\n switch (token.toUpperCase()) {\n case \"ROOT\": {\n pushNode(createRootNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"SUCCEED\": {\n pushNode(createSucceedNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"FAIL\": {\n pushNode(createFailNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"FLIP\": {\n pushNode(createFlipNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"REPEAT\": {\n pushNode(createRepeatNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"RETRY\": {\n pushNode(createRetryNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"SEQUENCE\": {\n pushNode(createSequenceNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"SELECTOR\": {\n pushNode(createSelectorNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"PARALLEL\": {\n pushNode(createParallelNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"LOTTO\": {\n pushNode(createLottoNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"ACTION\": {\n pushNode(createActionNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"CONDITION\": {\n pushNode(createConditionNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"WAIT\": {\n pushNode(createWaitNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"BRANCH\": {\n pushNode(createBranchNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"}\": {\n // The '}' character closes the current scope and means that we have to pop a node off of the current stack.\n const poppedNode = popNode();\n\n // Now that we have a node definition we can carry out any validation that may require the node to be fully populated.\n if (poppedNode) {\n validatePoppedNode(poppedNode);\n }\n\n break;\n }\n\n default: {\n throw new Error(`unexpected token: ${token}`);\n }\n }\n }\n\n return rootNodes as RootNodeDefinition[];\n}\n\n/**\n * Creates a root node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The root node JSON definition.\n */\nfunction createRootNode(tokens: string[], stringLiteralPlaceholders: StringLiteralPlaceholders): RootNodeDefinition {\n // Create the root node definition.\n let node = {\n type: \"root\",\n id: undefined\n } as RootNodeDefinition;\n\n // Parse any node arguments, we should only have one if any which will be an identifier argument for the root identifier.\n const nodeArguments = parseArgumentTokens(tokens, stringLiteralPlaceholders);\n\n // Check whether any node arguments were defined.\n if (nodeArguments.length) {\n // We should only have one argument, if any, which will be an identifier argument for the root identifier.\n if (nodeArguments.length === 1 && nodeArguments[0].type === \"identifier\") {\n // The root node identifier will be the first and only node argument value.\n node.id = nodeArguments[0].value as string;\n } else {\n throw new Error(\"expected single root name argument\");\n }\n }\n\n // Grab any node attribute definitions and spread them into the node definition.\n node = { ...node, ...parseAttributeTokens(tokens, stringLiteralPlaceholders) };\n\n // This is a decorator node, so we expect an opening '{'.\n popAndCheck(tokens, \"{\");\n\n // Return the root node definition.\n return node;\n}\n\n/**\n * Creates a succeed node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The succeed node JSON definition.\n */\nfunction createSucceedNode(\n tokens: string[],\n stringLiteralPlaceholders: StringLiteralPlaceholders\n): SucceedNodeDefinition {\n const node = {\n type: \"succeed\",\n ...parseAttributeTokens(tokens, stringLiteralPlaceholders)\n } as SucceedNodeDefinition;\n\n // This is a decorator node, so we expect an opening '{'.\n popAndCheck(tokens, \"{\");\n\n // Return the succeed node definition.\n return node;\n}\n\n/**\n * Creates a fail node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The fail node JSON definition.\n */\nfunction createFailNode(tokens: string[], stringLiteralPlaceholders: StringLiteralPlaceholders): FailNodeDefinition {\n const node = {\n type: \"fail\",\n ...parseAttributeTokens(tokens, stringLiteralPlaceholders)\n } as FailNodeDefinition;\n\n // This is a decorator node, so we expect an opening '{'.\n popAndCheck(tokens, \"{\");\n\n // Return the fail node definition.\n return node;\n}\n\n/**\n * Creates a flip node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The flip node JSON definition.\n */\nfunction createFlipNode(tokens: string[], stringLiteralPlaceholders: StringLiteralPlaceholders): FlipNodeDefinition {\n const node = {\n type: \"flip\",\n ...parseAttributeTokens(tokens, stringLiteralPlaceholders)\n } as FlipNodeDefinition;\n\n // This is a decorator node, so we expect an opening '{'.\n popAndCheck(tokens, \"{\");\n\n // Return the flip node definition.\n return node;\n}\n\n/**\n * Creates a repeat node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The repeat node JSON definition.\n */\nfunction createRepeatNode(\n tokens: string[],\n stringLiteralPlaceholders: StringLiteralPlaceholders\n): RepeatNodeDefinition {\n let node = { type: \"repeat\" } as RepeatNodeDefinition;\n\n // Get the node arguments.\n const nodeArguments = parseArgumentTokens(tokens, stringLiteralPlaceholders);\n\n // The arguments of a repeat node are optional. We may have:\n // - No node arguments, in which case the repeat note will iterate indefinitely.\n // - One node argument which will be the explicit number of iterations to make.\n // - Two node arguments which define the min and max iteration bounds from which a random iteration count will be picked.\n if (nodeArguments.length) {\n // All repeat node arguments MUST be of type number and must be integer.\n nodeArguments\n .filter((arg) => arg.type !== \"number\" || !arg.isInteger)\n .forEach(() => {\n throw new Error(`repeat node iteration counts must be integer values`);\n });\n\n // We should have got one or two iteration counts.\n if (nodeArguments.length === 1) {\n // A static iteration count was defined.\n node.iterations = nodeArguments[0].value as number;\n\n // A repeat node must have a positive number of iterations if defined.\n if (node.iterations < 0) {\n throw new Error(\"a repeat node must have a positive number of iterations if defined\");\n }\n } else if (nodeArguments.length === 2) {\n // A minimum and maximum iteration count was defined.\n node.iterations = [nodeArguments[0].value as number, nodeArguments[1].value as number];\n\n // A repeat node must have a positive min and max iteration count if they are defined.\n if (node.iterations[0] < 0 || node.iterations[1] < 0) {\n throw new Error(\"a repeat node must have a positive minimum and maximum iteration count if defined\");\n }\n\n // A repeat node must not have an minimum iteration count that exceeds the maximum iteration count.\n if (node.iterations[0] > node.iterations[1]) {\n throw new Error(\n \"a repeat node must not have a minimum iteration count that exceeds the maximum iteration count\"\n );\n }\n } else {\n // An incorrect number of iteration counts was defined.\n throw new Error(\"invalid number of repeat node iteration count arguments defined\");\n }\n }\n\n // Grab any node attribute definitions and spread them into the node definition.\n node = { ...node, ...parseAttributeTokens(tokens, stringLiteralPlaceholders) };\n\n // This is a decorator node, so we expect an opening '{'.\n popAndCheck(tokens, \"{\");\n\n // Return the repeat node definition.\n return node;\n}\n\n/**\n * Creates a retry node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The retry node JSON definition.\n */\nfunction createRetryNode(tokens: string[], stringLiteralPlaceholders: StringLiteralPlaceholders): RetryNodeDefinition {\n let node = { type: \"retry\" } as RetryNodeDefinition;\n\n // Get the node arguments.\n const nodeArguments = parseArgumentTokens(tokens, stringLiteralPlaceholders);\n\n // The arguments of a retry node are optional. We may have:\n // - No node arguments, in which case the retry note will attempt indefinitely.\n // - One node argument which will be the explicit number of attempts to make.\n // - Two node arguments which define the min and max attempt bounds from which a random attempt count will be picked.\n if (nodeArguments.length) {\n // All retry node arguments MUST be of type number and must be integer.\n nodeArguments\n .filter((arg) => arg.type !== \"number\" || !arg.isInteger)\n .forEach(() => {\n throw new Error(`retry node attempt counts must be integer values`);\n });\n\n // We should have got one or two attempt counts.\n if (nodeArguments.length === 1) {\n // A static attempt count was defined.\n node.attempts = nodeArguments[0].value as number;\n\n // A retry node must have a positive number of attempts if defined.\n if (node.attempts < 0) {\n throw new Error(\"a retry node must have a positive number of attempts if defined\");\n }\n } else if (nodeArguments.length === 2) {\n // A minimum and maximum attempt count was defined.\n node.attempts = [nodeArguments[0].value as number, nodeArguments[1].value as number];\n\n // A retry node must have a positive min and max attempts count if they are defined.\n if (node.attempts[0] < 0 || node.attempts[1] < 0) {\n throw new Error(\"a retry node must have a positive minimum and maximum attempt count if defined\");\n }\n\n // A retry node must not have a minimum attempt count that exceeds the maximum attempt count.\n if (node.attempts[0] > node.attempts[1]) {\n throw new Error(\n \"a retry node must not have a minimum attempt count that exceeds the maximum attempt count\"\n );\n }\n } else {\n // An incorrect number of attempt counts was defined.\n throw new Error(\"invalid number of retry node attempt count arguments defined\");\n }\n }\n\n // Grab any node attribute definitions and spread them into the node definition.\n node = { ...node, ...parseAttributeTokens(tokens, stringLiteralPlaceholders) };\n\n // This is a decorator node, so we expect an opening '{'.\n popAndCheck(tokens, \"{\");\n\n // Return the retry node definition.\n return node;\n}\n\n/**\n * Creates a sequence node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The sequence node JSON definition.\n */\nfunction createSequenceNode(\n tokens: string[],\n stringLiteralPlaceholders: StringLiteralPlaceholders\n): SequenceNodeDefinition {\n const node = {\n type: \"sequence\",\n ...parseAttributeTokens(tokens, stringLiteralPlaceholders)\n } as SequenceNodeDefinition;\n\n // This is a composite node, so we expect an opening '{'.\n popAndCheck(tokens, \"{\");\n\n // Return the sequence node definition.\n return node;\n}\n\n/**\n * Creates a selector node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The selector node JSON definition.\n */\nfunction createSelectorNode(\n tokens: string[],\n stringLiteralPlaceholders: StringLiteralPlaceholders\n): SelectorNodeDefinition {\n const node = {\n type: \"selector\",\n ...parseAttributeTokens(tokens, stringLiteralPlaceholders)\n } as SelectorNodeDefinition;\n\n // This is a composite node, so we expect an opening '{'.\n popAndCheck(tokens, \"{\");\n\n // Return the selector node definition.\n return node;\n}\n\n/**\n * Creates a parallel node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The parallel node JSON definition.\n */\nfunction createParallelNode(\n tokens: string[],\n stringLiteralPlaceholders: StringLiteralPlaceholders\n): ParallelNodeDefinition {\n const node = {\n type: \"parallel\",\n ...parseAttributeTokens(tokens, stringLiteralPlaceholders)\n } as ParallelNodeDefinition;\n\n // This is a composite node, so we expect an opening '{'.\n popAndCheck(tokens, \"{\");\n\n // Return the parallel node definition.\n return node;\n}\n\n/**\n * Creates a lotto node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The lotto node JSON definition.\n */\nfunction createLottoNode(tokens: string[], stringLiteralPlaceholders: StringLiteralPlaceholders): LottoNodeDefinition {\n // If any node arguments have been defined then they must be our weights.\n const nodeArguments = parseArgumentTokens(tokens, stringLiteralPlaceholders);\n\n // All lotto node arguments MUST be of type number and must be positive integers.\n nodeArguments\n .filter((arg) => arg.type !== \"number\" || !arg.isInteger || arg.value < 0)\n .forEach(() => {\n throw new Error(`lotto node weight arguments must be positive integer values`);\n });\n\n const node = {\n type: \"lotto\",\n weights: nodeArguments.length ? nodeArguments.map(({ value }) => value) : undefined,\n ...parseAttributeTokens(tokens, stringLiteralPlaceholders)\n } as LottoNodeDefinition;\n\n // This is a composite node, so we expect an opening '{'.\n popAndCheck(tokens, \"{\");\n\n // Return the lotto node definition.\n return node;\n}\n\n/**\n * Creates an action node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The action node JSON definition.\n */\nfunction createActionNode(\n tokens: string[],\n stringLiteralPlaceholders: StringLiteralPlaceholders\n): ActionNodeDefinition {\n // Parse any node arguments, we should have at least one which will be an identifier argument for the action name\n // and agent function to invoke for the action, all other arguments are to be passed as arguments to that function.\n const [actionNameIdentifier, ...agentFunctionArgs] = parseArgumentTokens(tokens, stringLiteralPlaceholders);\n\n // Our first argument MUST be defined and be an identifier as we require an action name argument.\n if (actionNameIdentifier?.type !== \"identifier\") {\n throw new Error(\"expected action name identifier argument\");\n }\n\n // Only the first argument should have been an identifier, all agent function arguments must be string, number, boolean or null.\n agentFunctionArgs\n .filter((arg) => arg.type === \"identifier\")\n .forEach((arg) => {\n throw new Error(\n `invalid action node argument value '${arg.value}', must be string, number, boolean or null`\n );\n });\n\n // Return the action node definition.\n return {\n type: \"action\",\n call: actionNameIdentifier.value,\n args: agentFunctionArgs.map(({ value }) => value),\n ...parseAttributeTokens(tokens, stringLiteralPlaceholders)\n };\n}\n\n/**\n * Creates a condition node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The condition node JSON definition.\n */\nfunction createConditionNode(\n tokens: string[],\n stringLiteralPlaceholders: StringLiteralPlaceholders\n): ConditionNodeDefinition {\n // Parse any node arguments, we should have at least one which will be an identifier argument for the condition name\n // and agent function to invoke for the condition, all other arguments are to be passed as arguments to that function.\n const [conditionNameIdentifier, ...agentFunctionArgs] = parseArgumentTokens(tokens, stringLiteralPlaceholders);\n\n // Our first argument MUST be defined and be an identifier as we require a condition name argument.\n if (conditionNameIdentifier?.type !== \"identifier\") {\n throw new Error(\"expected condition name identifier argument\");\n }\n\n // Only the first argument should have been an identifier, all agent function arguments must be string, number, boolean or null.\n agentFunctionArgs\n .filter((arg) => arg.type === \"identifier\")\n .forEach((arg) => {\n throw new Error(\n `invalid condition node argument value '${arg.value}', must be string, number, boolean or null`\n );\n });\n\n // Return the condition node definition.\n return {\n type: \"condition\",\n call: conditionNameIdentifier.value,\n args: agentFunctionArgs.map(({ value }) => value),\n ...parseAttributeTokens(tokens, stringLiteralPlaceholders)\n };\n}\n\n/**\n * Creates a wait node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The wait node JSON definition.\n */\nfunction createWaitNode(tokens: string[], stringLiteralPlaceholders: StringLiteralPlaceholders): WaitNodeDefinition {\n let node = { type: \"wait\" } as WaitNodeDefinition;\n\n // Get the node arguments.\n const nodeArguments = parseArgumentTokens(tokens, stringLiteralPlaceholders);\n\n // The arguments of a wait node are optional. We may have:\n // - No node arguments, in which case the wait will be indefinite until it is aborted.\n // - One node argument which will be the explicit duration of the wait.\n // - Two node arguments which define the min and max duration bounds from which a random duration will be picked.\n if (nodeArguments.length) {\n // All wait node arguments MUST be of type number and must be integer.\n nodeArguments\n .filter((arg) => arg.type !== \"number\" || !arg.isInteger)\n .forEach(() => {\n throw new Error(`wait node durations must be integer values`);\n });\n\n // We may have:\n // - One node argument which will be the explicit duration of the wait.\n // - Two node arguments which define the min and max duration bounds from which a random duration will be picked.\n // - Too many arguments, which is not valid.\n if (nodeArguments.length === 1) {\n // An explicit duration was defined.\n node.duration = nodeArguments[0].value as number;\n\n // If an explict duration was defined then it must be a positive number.\n if (node.duration < 0) {\n throw new Error(\"a wait node must have a positive duration\");\n }\n } else if (nodeArguments.length === 2) {\n // Min and max duration bounds were defined from which a random duration will be picked.\n node.duration = [nodeArguments[0].value as number, nodeArguments[1].value as number];\n\n // A wait node must have a positive min and max duration.\n if (node.duration[0] < 0 || node.duration[1] < 0) {\n throw new Error(\"a wait node must have a positive minimum and maximum duration\");\n }\n\n // A wait node must not have a minimum duration that exceeds the maximum duration.\n if (node.duration[0] > node.duration[1]) {\n throw new Error(\"a wait node must not have a minimum duration that exceeds the maximum duration\");\n }\n } else if (nodeArguments.length > 2) {\n // An incorrect number of duration arguments were defined.\n throw new Error(\"invalid number of wait node duration arguments defined\");\n }\n }\n\n // Return the wait node definition.\n return { ...node, ...parseAttributeTokens(tokens, stringLiteralPlaceholders) };\n}\n\n/**\n * Creates a branch node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The branch node JSON definition.\n */\nfunction createBranchNode(\n tokens: string[],\n stringLiteralPlaceholders: StringLiteralPlaceholders\n): BranchNodeDefinition {\n // Parse any node arguments, we should have one which will be an identifier argument for the root ref.\n const nodeArguments = parseArgumentTokens(tokens, stringLiteralPlaceholders);\n\n // We should have only a single identifer argument for a branch node, which is the root ref.\n if (nodeArguments.length !== 1 || nodeArguments[0].type !== \"identifier\") {\n throw new Error(\"expected single branch name argument\");\n }\n\n // Return the branch node definition.\n return { type: \"branch\", ref: nodeArguments[0].value };\n}\n\n/**\n * Validate a fully-populated node definition that was popped off of the tree stack.\n * @param definition The popped node to validate.\n */\nfunction validatePoppedNode(definition: AnyNodeDefinition): void {\n // Decorators MUST have a child defined.\n if (isDecoratorNode(definition) && isNullOrUndefined(definition.child)) {\n throw new Error(`a ${definition.type} node must have a single child node defined`);\n }\n\n // Composites MUST have at least one child defined.\n if (isCompositeNode(definition) && !definition.children?.length) {\n throw new Error(`a ${definition.type} node must have at least a single child node defined`);\n }\n\n // We need to make sure that lotto nodes that have weights defined have a number of weights matching the number of child nodes.\n if (definition.type === \"lotto\") {\n // Check whether a 'weights' property has been defined, if it has we expect it to be an array of weights.\n if (typeof definition.weights !== \"undefined\") {\n // Check that the weights property is an array of positive integers with an element for each child node element.\n if (definition.weights.length !== definition.children.length) {\n throw new Error(\n \"expected a number of weight arguments matching the number of child nodes for lotto node\"\n );\n }\n }\n }\n}\n", "import { RootNodeDefinition } from \"./BehaviourTreeDefinition\";\nimport { flattenDefinition, isBranchNode, isInteger } from \"./BehaviourTreeDefinitionUtilities\";\nimport { convertMDSLToJSON } from \"./mdsl/MDSLDefinitionParser\";\n\n/**\n * An object representing the result of validating a tree definition.\n */\nexport type DefinitionValidationResult = {\n /**\n * A flag defining whether validation succeeded.\n */\n succeeded: boolean;\n /**\n * A string containing the error message if validation did not succeed.\n */\n errorMessage?: string;\n /**\n * The definition as json if the validation was successful, or undefined if validation did not succeed.\n */\n json?: RootNodeDefinition[];\n};\n\n/**\n * Validates the specified behaviour tree definition in the form of JSON or MDSL, not taking any globally registered subtrees into consideration.\n * @param definition The behaviour tree definition in the form of JSON or MDSL.\n * @returns An object representing the result of validating the given tree definition.\n */\nexport function validateDefinition(definition: any): DefinitionValidationResult {\n // The definition must be defined.\n if (definition === null || typeof definition === \"undefined\") {\n return createValidationFailureResult(\"definition is null or undefined\");\n }\n\n // We are expecting a definition in one of three different forms:\n // - A string which we will assume is MDSL and we will parse this to JSON before validation.\n // - An array which we will assume is an array of root node definitions with at least one being the primary root node (no 'id' property)\n // - An object which we will assume is the primary root node and should not have an 'id' property.\n if (typeof definition === \"string\") {\n // The definition is a string which we can assume is MDSL, so attempt to validate it.\n return validateMDSLDefinition(definition);\n } else if (typeof definition === \"object\") {\n // The definition will either be an array (of root node definitions) or an object (the single primary root node definition).\n return validateJSONDefinition(definition);\n } else {\n return createValidationFailureResult(`unexpected definition type of '${typeof definition}'`);\n }\n}\n\n/**\n * Validates the specified behaviour tree definition in the form of MDSL.\n * @param definition The behaviour tree definition in the form of MDSL.\n * @returns An object representing the result of validating the given tree definition.\n */\nfunction validateMDSLDefinition(definition: string): DefinitionValidationResult {\n let rootNodeDefinitions;\n\n // The first thing the we need to do is to attempt to convert our MDSL into JSON.\n try {\n // The definition is a string which we can assume is MDSL, so attempt to parse it to a JSON definition in the form of an array of root node definitions.\n rootNodeDefinitions = convertMDSLToJSON(definition);\n } catch (exception) {\n // We failed to parse the JSON from the MDSL, this is likely to be the result of it not being a valid MDSL string.\n return createValidationFailureResult((exception as Error).message);\n }\n\n // Unpack all of the root node definitions into arrays of main ('id' defined) and sub ('id' not defined) root node definitions.\n const mainRootNodeDefinitions = rootNodeDefinitions.filter(({ id }) => typeof id === \"undefined\");\n const subRootNodeDefinitions = rootNodeDefinitions.filter(({ id }) => typeof id === \"string\" && id.length > 0);\n\n // We should ALWAYS have exactly one root node definition without an 'id' property defined, which is out main root node definition.\n if (mainRootNodeDefinitions.length !== 1) {\n return createValidationFailureResult(\n \"expected single unnamed root node at base of definition to act as main root\"\n );\n }\n\n // We should never have duplicate 'id' properties across our sub root node definitions.\n const subRootNodeIdenitifers: string[] = [];\n for (const { id } of subRootNodeDefinitions) {\n // Have we already come across this 'id' property value?\n if (subRootNodeIdenitifers.includes(id!)) {\n return createValidationFailureResult(`multiple root nodes found with duplicate name '${id}'`);\n }\n\n subRootNodeIdenitifers.push(id!);\n }\n\n try {\n // Validate our branch -> subtree links and check for any circular dependencies, we don't care about checking for broken subtree links here.\n validateBranchSubtreeLinks(rootNodeDefinitions, false);\n } catch (exception) {\n return createValidationFailureResult((exception as Error).message);\n }\n\n // Our definition was valid!\n return {\n succeeded: true,\n json: rootNodeDefinitions\n };\n}\n\n/**\n * Validates the specified behaviour tree definition in the form of JSON.\n * @param definition The behaviour tree definition in the form of JSON.\n * @returns An object representing the result of validating the given tree definition.\n */\nexport function validateJSONDefinition(\n definition: RootNodeDefinition | RootNodeDefinition[]\n): DefinitionValidationResult {\n // The definition will either be an array (of root node definitions) or an object (the single primary root node definition).\n const rootNodeDefinitions = Array.isArray(definition) ? definition : [definition];\n\n // Iterate over our array of root nodes and call validateNode for each, passing an initial depth of 0, wrapped in a try catch to handle validation failures.\n try {\n rootNodeDefinitions.forEach((rootNodeDefinition) => validateNode(rootNodeDefinition, 0));\n } catch (error) {\n // Handle cases where we have caught a thrown Error and return a failure result with the error message.\n if (error instanceof Error) {\n return createValidationFailureResult(error.message);\n }\n\n // No idea what happened here!\n return createValidationFailureResult(`unexpected error: ${error}`);\n }\n\n // Unpack all of the root node definitions into arrays of main ('id' defined) and sub ('id' not defined) root node definitions.\n const mainRootNodeDefinitions = rootNodeDefinitions.filter(({ id }) => typeof id === \"undefined\");\n const subRootNodeDefinitions = rootNodeDefinitions.filter(({ id }) => typeof id === \"string\" && id.length > 0);\n\n // We should ALWAYS have exactly one root node definition without an 'id' property defined, which is out main root node definition.\n if (mainRootNodeDefinitions.length !== 1) {\n return createValidationFailureResult(\n \"expected single root node without 'id' property defined to act as main root\"\n );\n }\n\n // We should never have duplicate 'id' properties across our sub root node definitions.\n const subRootNodeIdenitifers: string[] = [];\n for (const { id } of subRootNodeDefinitions) {\n // Have we already come across this 'id' property value?\n if (subRootNodeIdenitifers.includes(id!)) {\n return createValidationFailureResult(\n `multiple root nodes found with duplicate 'id' property value of '${id}'`\n );\n }\n\n subRootNodeIdenitifers.push(id!);\n }\n\n try {\n // Validate our branch -> subtree links and check for any circular dependencies, we don't care about checking for broken subtree links here.\n validateBranchSubtreeLinks(rootNodeDefinitions, false);\n } catch (exception) {\n return createValidationFailureResult((exception as Error).message);\n }\n\n // Our definition was valid!\n return {\n succeeded: true,\n json: rootNodeDefinitions\n };\n}\n\n/**\n * Validates the branch -> subtree links across all provided root node definitions.\n * This will not consider branch nodes that reference any globally registered subtrees unless includesGlobalSubtrees\n * is set to true, in which case we will also verify that there are no broken branch -> subtree links.\n * @param rootNodeDefinitions The array of root node definitions.\n * @param includesGlobalSubtrees A flag defining whether the array includes all global subtree root node definitions.\n */\nexport function validateBranchSubtreeLinks(rootNodeDefinitions: RootNodeDefinition[], includesGlobalSubtrees: boolean) {\n // Create a mapping of root node identifiers to other root nodes that they reference via branch nodes.\n // Below is an example of a mapping that includes a circular dependency (root => a => b => c => a)\n // [{ refs: [\"a\", \"b\"] }, { id: \"a\", refs: [\"b\"] }, { id: \"b\", refs: [\"c\"] }, { id: \"c\", refs: [\"a\"] }]\n const rootNodeMappings: { id: string | undefined; refs: string[] }[] = rootNodeDefinitions.map(\n (rootNodeDefinition) => ({\n id: rootNodeDefinition.id,\n refs: flattenDefinition(rootNodeDefinition)\n .filter(isBranchNode)\n .map(({ ref }) => ref)\n })\n );\n\n // A recursive function to walk through the mappings, keeping track of which root nodes we have visited in the form of a path of root node identifiers.\n const followRefs = (mapping: { id: string | undefined; refs: string[] }, path: (string | undefined)[] = []) => {\n // Have we found a circular dependency?\n if (path.includes(mapping.id)) {\n // We found a circular dependency! Get the bad path of root node identifiers.\n const badPath = [...path, mapping.id];\n\n // Create the formatted path value. [undefined, \"a\", \"b\", \"c\", \"a\"] would be formatted as \"a -> b -> c -> a\".\n const badPathFormatted = badPath.filter((element) => !!element).join(\" => \");\n\n // No need to continue, we found a circular dependency.\n throw new Error(`circular dependency found in branch node references: ${badPathFormatted}`);\n }\n\n for (const ref of mapping.refs) {\n // Find the mapping for the root node with an identifer matching the current ref.\n const subMapping = rootNodeMappings.find(({ id }) => id === ref);\n\n // We may not have a mapping for this ref, which is normal when we aren't considering all globally registered subtrees.\n if (subMapping) {\n followRefs(subMapping, [...path, mapping.id]);\n } else if (includesGlobalSubtrees) {\n // We found a reference to a root node that doesn't exist, which is a problem seeing as the root node definitons includes all globally registered subtrees.\n throw new Error(\n mapping.id\n ? `subtree '${mapping.id}' has branch node that references root node '${ref}' which has not been defined`\n : `primary tree has branch node that references root node '${ref}' which has not been defined`\n );\n }\n }\n };\n\n // Start looking for circular dependencies and broken references from the primary root node definition.\n followRefs(rootNodeMappings.find((mapping) => typeof mapping.id === \"undefined\")!);\n}\n\n/**\n * Validate an object that we expect to be a node definition.\n * @param definition An object that we expect to be a node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateNode(definition: any, depth: number): void {\n // Every node must be valid object and have a non-empty 'type' string property.\n if (typeof definition !== \"object\" || typeof definition.type !== \"string\" || definition.type.length === 0) {\n throw new Error(\n `node definition is not an object or 'type' property is not a non-empty string at depth '${depth}'`\n );\n }\n\n // How we validate this node definition will depend on its type.\n switch (definition.type) {\n case \"action\":\n validateActionNode(definition, depth);\n break;\n\n case \"condition\":\n validateConditionNode(definition, depth);\n break;\n\n case \"wait\":\n validateWaitNode(definition, depth);\n break;\n\n case \"branch\":\n validateBranchNode(definition, depth);\n break;\n\n case \"root\":\n validateRootNode(definition, depth);\n break;\n\n case \"succeed\":\n validateSucceedNode(definition, depth);\n break;\n\n case \"fail\":\n validateFailNode(definition, depth);\n break;\n\n case \"flip\":\n validateFlipNode(definition, depth);\n break;\n\n case \"repeat\":\n validateRepeatNode(definition, depth);\n break;\n\n case \"retry\":\n validateRetryNode(definition, depth);\n break;\n\n case \"sequence\":\n validateSequenceNode(definition, depth);\n break;\n\n case \"selector\":\n validateSelectorNode(definition, depth);\n break;\n\n case \"parallel\":\n validateParallelNode(definition, depth);\n break;\n\n case \"lotto\":\n validateLottoNode(definition, depth);\n break;\n\n default:\n throw new Error(`unexpected node type of '${definition.type}' at depth '${depth}'`);\n }\n}\n\n/**\n * Validate any attributes for a given node definition.\n * @param definition The node definition.\n * @param depth The depth of the node in the behaviour tree definition.\n */\nfunction validateNodeAttributes(definition: any, depth: number): void {\n // Validate each of the attribute types for this node.\n [\"while\", \"until\", \"entry\", \"exit\", \"step\"].forEach((attributeName) => {\n // Attempt to grab the definition for the current attribute from the node definition.\n const attributeDefinition = definition[attributeName];\n\n // All node attributes are optional, so there is nothing to do if the current attribute is not defined.\n if (typeof attributeDefinition === \"undefined\") {\n return;\n }\n\n // The attribute definition must be an object.\n if (typeof attributeDefinition !== \"object\") {\n throw new Error(\n `expected attribute '${attributeName}' to be an object for '${definition.type}' node at depth '${depth}'`\n );\n }\n\n // The 'call' property must be defined for any attribute definition.\n if (typeof attributeDefinition.call !== \"string\" || attributeDefinition.call.length === 0) {\n throw new Error(\n `expected 'call' property for attribute '${attributeName}' to be a non-empty string for '${definition.type}' node at depth '${depth}'`\n );\n }\n\n // If any node attribute arguments have been defined then they must have been defined in an array.\n if (typeof attributeDefinition.args !== \"undefined\" && !Array.isArray(attributeDefinition.args)) {\n throw new Error(\n `expected 'args' property for attribute '${attributeName}' to be an array for '${definition.type}' node at depth '${depth}'`\n );\n }\n });\n}\n\n/**\n * Validate an object that we expect to be a root node definition.\n * @param definition An object that we expect to be a root node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateRootNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"root\") {\n throw new Error(\"expected node type of 'root' for root node\");\n }\n\n // A root node cannot be the child of another node.\n if (depth > 0) {\n throw new Error(\"a root node cannot be the child of another node\");\n }\n\n // Check that, if the root node 'id' property is defined, it is a non-empty string.\n if (typeof definition.id !== \"undefined\" && (typeof definition.id !== \"string\" || definition.id.length === 0)) {\n throw new Error(\"expected non-empty string for 'id' property if defined for root node\");\n }\n\n // A root node is a decorator node, so must have a child node defined.\n if (typeof definition.child === \"undefined\") {\n throw new Error(\"expected property 'child' to be defined for root node\");\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n\n // Validate the child node of this decorator node.\n validateNode(definition.child, depth + 1);\n}\n\n/**\n * Validate an object that we expect to be a succeed node definition.\n * @param definition An object that we expect to be a succeed node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateSucceedNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"succeed\") {\n throw new Error(`expected node type of 'succeed' for succeed node at depth '${depth}'`);\n }\n\n // A succeed node is a decorator node, so must have a child node defined.\n if (typeof definition.child === \"undefined\") {\n throw new Error(`expected property 'child' to be defined for succeed node at depth '${depth}'`);\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n\n // Validate the child node of this decorator node.\n validateNode(definition.child, depth + 1);\n}\n\n/**\n * Validate an object that we expect to be a fail node definition.\n * @param definition An object that we expect to be a fail node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateFailNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"fail\") {\n throw new Error(`expected node type of 'fail' for fail node at depth '${depth}'`);\n }\n\n // A fail node is a decorator node, so must have a child node defined.\n if (typeof definition.child === \"undefined\") {\n throw new Error(`expected property 'child' to be defined for fail node at depth '${depth}'`);\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n\n // Validate the child node of this decorator node.\n validateNode(definition.child, depth + 1);\n}\n\n/**\n * Validate an object that we expect to be a flip node definition.\n * @param definition An object that we expect to be a flip node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateFlipNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"flip\") {\n throw new Error(`expected node type of 'flip' for flip node at depth '${depth}'`);\n }\n\n // A flip node is a decorator node, so must have a child node defined.\n if (typeof definition.child === \"undefined\") {\n throw new Error(`expected property 'child' to be defined for flip node at depth '${depth}'`);\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n\n // Validate the child node of this decorator node.\n validateNode(definition.child, depth + 1);\n}\n\n/**\n * Validate an object that we expect to be a repeat node definition.\n * @param definition An object that we expect to be a repeat node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateRepeatNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"repeat\") {\n throw new Error(`expected node type of 'repeat' for repeat node at depth '${depth}'`);\n }\n\n // A repeat node is a decorator node, so must have a child node defined.\n if (typeof definition.child === \"undefined\") {\n throw new Error(`expected property 'child' to be defined for repeat node at depth '${depth}'`);\n }\n\n // Check whether an 'iterations' property has been defined, it may not have been if this node is to repeat indefinitely.\n if (typeof definition.iterations !== \"undefined\") {\n if (Array.isArray(definition.iterations)) {\n // Check whether any elements of the array are not integer values.\n const containsNonInteger = !!definition.iterations.filter((value: unknown) => !isInteger(value)).length;\n\n // If the 'iterations' property is an array then it MUST contain two integer values.\n if (definition.iterations.length !== 2 || containsNonInteger) {\n throw new Error(\n `expected array containing two integer values for 'iterations' property if defined for repeat node at depth '${depth}'`\n );\n }\n\n // A repeat node must have a positive min and max iterations count if they are defined.\n if (definition.iterations[0] < 0 || definition.iterations[1] < 0) {\n throw new Error(\n `expected positive minimum and maximum iterations count for 'iterations' property if defined for repeat node at depth '${depth}'`\n );\n }\n\n // A repeat node must not have a minimum iterations count that exceeds the maximum iterations count.\n if (definition.iterations[0] > definition.iterations[1]) {\n throw new Error(\n `expected minimum iterations count that does not exceed the maximum iterations count for 'iterations' property if defined for repeat node at depth '${depth}'`\n );\n }\n } else if (isInteger(definition.iterations)) {\n // A repeat node must have a positive number of iterations if defined.\n if (definition.iterations < 0) {\n throw new Error(\n `expected positive iterations count for 'iterations' property if defined for repeat node at depth '${depth}'`\n );\n }\n } else {\n throw new Error(\n `expected integer value or array containing two integer values for 'iterations' property if defined for repeat node at depth '${depth}'`\n );\n }\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n\n // Validate the child node of this decorator node.\n validateNode(definition.child, depth + 1);\n}\n\n/**\n * Validate an object that we expect to be a retry node definition.\n * @param definition An object that we expect to be a retry node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateRetryNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"retry\") {\n throw new Error(`expected node type of 'retry' for retry node at depth '${depth}'`);\n }\n\n // A retry node is a decorator node, so must have a child node defined.\n if (typeof definition.child === \"undefined\") {\n throw new Error(`expected property 'child' to be defined for retry node at depth '${depth}'`);\n }\n\n // Check whether an 'attempts' property has been defined, it may not have been if this node is to retry indefinitely.\n if (typeof definition.attempts !== \"undefined\") {\n if (Array.isArray(definition.attempts)) {\n // Check whether any elements of the array are not integer values.\n const containsNonInteger = !!definition.attempts.filter((value: unknown) => !isInteger(value)).length;\n\n // If the 'attempts' property is an array then it MUST contain two integer values.\n if (definition.attempts.length !== 2 || containsNonInteger) {\n throw new Error(\n `expected array containing two integer values for 'attempts' property if defined for retry node at depth '${depth}'`\n );\n }\n\n // A retry node must have a positive min and max attempts count if they are defined.\n if (definition.attempts[0] < 0 || definition.attempts[1] < 0) {\n throw new Error(\n `expected positive minimum and maximum attempts count for 'attempts' property if defined for retry node at depth '${depth}'`\n );\n }\n\n // A retry node must not have a minimum attempts count that exceeds the maximum attempts count.\n if (definition.attempts[0] > definition.attempts[1]) {\n throw new Error(\n `expected minimum attempts count that does not exceed the maximum attempts count for 'attempts' property if defined for retry node at depth '${depth}'`\n );\n }\n } else if (isInteger(definition.attempts)) {\n // A retry node must have a positive number of attempts if defined.\n if (definition.attempts < 0) {\n throw new Error(\n `expected positive attempts count for 'attempts' property if defined for retry node at depth '${depth}'`\n );\n }\n } else {\n throw new Error(\n `expected integer value or array containing two integer values for 'attempts' property if defined for retry node at depth '${depth}'`\n );\n }\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n\n // Validate the child node of this decorator node.\n validateNode(definition.child, depth + 1);\n}\n\n/**\n * Validate an object that we expect to be a branch node definition.\n * @param definition An object that we expect to be a branch node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateBranchNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"branch\") {\n throw new Error(`expected node type of 'branch' for branch node at depth '${depth}'`);\n }\n\n // Check that the branch node 'ref' property is defined and is a non-empty string.\n if (typeof definition.ref !== \"string\" || definition.ref.length === 0) {\n throw new Error(`expected non-empty string for 'ref' property for branch node at depth '${depth}'`);\n }\n\n // It is invalid to define guard attributes for a branch node as they should be defined on the referenced root node.\n [\"while\", \"until\"].forEach((attributeName) => {\n if (typeof definition[attributeName] !== \"undefined\") {\n throw new Error(\n `guards should not be defined for branch nodes but guard '${attributeName}' was defined for branch node at depth '${depth}'`\n );\n }\n });\n\n // It is invalid to define callback attributes for a branch node as they should be defined on the referenced root node.\n [\"entry\", \"exit\", \"step\"].forEach((attributeName) => {\n if (typeof definition[attributeName] !== \"undefined\") {\n throw new Error(\n `callbacks should not be defined for branch nodes but callback '${attributeName}' was defined for branch node at depth '${depth}'`\n );\n }\n });\n}\n\n/**\n * Validate an object that we expect to be a action node definition.\n * @param definition An object that we expect to be a action node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateActionNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"action\") {\n throw new Error(`expected node type of 'action' for action node at depth '${depth}'`);\n }\n\n // The 'call' property must be defined for a action node definition.\n if (typeof definition.call !== \"string\" || definition.call.length === 0) {\n throw new Error(`expected non-empty string for 'call' property of action node at depth '${depth}'`);\n }\n\n // If any action function arguments have been defined then they must have been defined in an array.\n if (typeof definition.args !== \"undefined\" && !Array.isArray(definition.args)) {\n throw new Error(`expected array for 'args' property if defined for action node at depth '${depth}'`);\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n}\n\n/**\n * Validate an object that we expect to be a condition node definition.\n * @param definition An object that we expect to be a condition node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateConditionNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"condition\") {\n throw new Error(`expected node type of 'condition' for condition node at depth '${depth}'`);\n }\n\n // The 'call' property must be defined for a condition node definition.\n if (typeof definition.call !== \"string\" || definition.call.length === 0) {\n throw new Error(`expected non-empty string for 'call' property of condition node at depth '${depth}'`);\n }\n\n // If any condition function arguments have been defined then they must have been defined in an array.\n if (typeof definition.args !== \"undefined\" && !Array.isArray(definition.args)) {\n throw new Error(`expected array for 'args' property if defined for condition node at depth '${depth}'`);\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n}\n\n/**\n * Validate an object that we expect to be a wait node definition.\n * @param definition An object that we expect to be a wait node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateWaitNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"wait\") {\n throw new Error(`expected node type of 'wait' for wait node at depth '${depth}'`);\n }\n\n // Check whether a 'duration' property has been defined, it may not have been if this node is to wait indefinitely.\n if (typeof definition.duration !== \"undefined\") {\n if (Array.isArray(definition.duration)) {\n // Check whether any elements of the array are not integer values.\n const containsNonInteger = !!definition.duration.filter((value: unknown) => !isInteger(value)).length;\n\n // If the 'duration' property is an array then it MUST contain two integer values.\n if (definition.duration.length !== 2 || containsNonInteger) {\n throw new Error(\n `expected array containing two integer values for 'duration' property if defined for wait node at depth '${depth}'`\n );\n }\n\n // A wait node must have a positive min and max duration value if they are defined.\n if (definition.duration[0] < 0 || definition.duration[1] < 0) {\n throw new Error(\n `expected positive minimum and maximum duration for 'duration' property if defined for wait node at depth '${depth}'`\n );\n }\n\n // A wait node must not have a minimum duration value that exceeds the maximum duration value.\n if (definition.duration[0] > definition.duration[1]) {\n throw new Error(\n `expected minimum duration value that does not exceed the maximum duration value for 'duration' property if defined for wait node at depth '${depth}'`\n );\n }\n } else if (isInteger(definition.duration)) {\n // A wait node must have a positive duration value if defined.\n if (definition.duration < 0) {\n throw new Error(\n `expected positive duration value for 'duration' property if defined for wait node at depth '${depth}'`\n );\n }\n } else {\n throw new Error(\n `expected integer value or array containing two integer values for 'duration' property if defined for wait node at depth '${depth}'`\n );\n }\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n}\n\n/**\n * Validate an object that we expect to be a sequence node definition.\n * @param definition An object that we expect to be a sequence node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateSequenceNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"sequence\") {\n throw new Error(`expected node type of 'sequence' for sequence node at depth '${depth}'`);\n }\n\n // A sequence node is a composite node, so must have a children nodes array defined.\n if (!Array.isArray(definition.children) || definition.children.length === 0) {\n throw new Error(`expected non-empty 'children' array to be defined for sequence node at depth '${depth}'`);\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n\n // Validate the child nodes of this composite node.\n definition.children.forEach((child: any) => validateNode(child, depth + 1));\n}\n\n/**\n * Validate an object that we expect to be a selector node definition.\n * @param definition An object that we expect to be a selector node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateSelectorNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"selector\") {\n throw new Error(`expected node type of 'selector' for selector node at depth '${depth}'`);\n }\n\n // A selector node is a composite node, so must have a children nodes array defined.\n if (!Array.isArray(definition.children) || definition.children.length === 0) {\n throw new Error(`expected non-empty 'children' array to be defined for selector node at depth '${depth}'`);\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n\n // Validate the child nodes of this composite node.\n definition.children.forEach((child: any) => validateNode(child, depth + 1));\n}\n\n/**\n * Validate an object that we expect to be a parallel node definition.\n * @param definition An object that we expect to be a parallel node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateParallelNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"parallel\") {\n throw new Error(`expected node type of 'parallel' for parallel node at depth '${depth}'`);\n }\n\n // A parallel node is a composite node, so must have a children nodes array defined.\n if (!Array.isArray(definition.children) || definition.children.length === 0) {\n throw new Error(`expected non-empty 'children' array to be defined for parallel node at depth '${depth}'`);\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n\n // Validate the child nodes of this composite node.\n definition.children.forEach((child: any) => validateNode(child, depth + 1));\n}\n\n/**\n * Validate an object that we expect to be a lotto node definition.\n * @param definition An object that we expect to be a lotto node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateLottoNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"lotto\") {\n throw new Error(`expected node type of 'lotto' for lotto node at depth '${depth}'`);\n }\n\n // A lotto node is a composite node, so must have a children nodes array defined.\n if (!Array.isArray(definition.children) || definition.children.length === 0) {\n throw new Error(`expected non-empty 'children' array to be defined for lotto node at depth '${depth}'`);\n }\n\n // Check whether a 'weights' property has been defined, if it has we expect it to be an array of weights.\n if (typeof definition.weights !== \"undefined\") {\n // Check that the weights property is an array of positive integers with an element for each child node element.\n if (\n !Array.isArray(definition.weights) ||\n definition.weights.length !== definition.children.length ||\n definition.weights.filter((value: unknown) => !isInteger(value)).length ||\n definition.weights.filter((value: number) => value < 0).length\n ) {\n throw new Error(\n `expected an array of positive integer weight values with a length matching the number of child nodes for 'weights' property if defined for lotto node at depth '${depth}'`\n );\n }\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n\n // Validate the child nodes of this composite node.\n definition.children.forEach((child: any) => validateNode(child, depth + 1));\n}\n\n/**\n * A helper function to create a failure validation result with the given error message.\n * @param errorMessage The validation failure error message.\n * @returns A failure validation result with the given error message.\n */\nfunction createValidationFailureResult(errorMessage: string): DefinitionValidationResult {\n return { succeeded: false, errorMessage };\n}\n", "import { ActionResult, Agent, GlobalFunction } from \"./Agent\";\nimport { RootNodeDefinition } from \"./BehaviourTreeDefinition\";\n\nexport type InvokerFunction = (args: any[]) => ActionResult;\n\n/**\n * A singleton used to store and lookup registered functions and subtrees.\n */\nexport default class Lookup {\n /**\n * The object holding any registered functions keyed on function name.\n */\n private static functionTable: { [key: string]: GlobalFunction } = {};\n /**\n * The object holding any registered subtree root node definitions keyed on tree name.\n */\n private static subtreeTable: { [key: string]: RootNodeDefinition } = {};\n\n /**\n * Gets the function with the specified name.\n * @param name The name of the function.\n * @returns The function with the specified name.\n */\n public static getFunc(name: string): GlobalFunction {\n return this.functionTable[name];\n }\n\n /**\n * Sets the function with the specified name for later lookup.\n * @param name The name of the function.\n * @param func The function.\n */\n public static setFunc(name: string, func: GlobalFunction): void {\n this.functionTable[name] = func;\n }\n\n /**\n * Gets the function invoker for the specified agent and function name.\n * If a function with the specified name exists on the agent object then it will\n * be returned, otherwise we will then check the registered functions for a match.\n * @param agent The agent instance that this behaviour tree is modelling behaviour for.\n * @param name The function name.\n * @returns The function invoker for the specified agent and function name.\n */\n static getFuncInvoker(agent: Agent, name: string): InvokerFunction | null {\n // Check whether the agent contains the specified function.\n const foundOnAgent = agent[name];\n if (foundOnAgent && typeof foundOnAgent === \"function\") {\n return (args: any[]): boolean | ActionResult => foundOnAgent.apply(agent, args);\n }\n\n // The agent does not contain the specified function but it may have been registered at some point.\n if (this.functionTable[name] && typeof this.functionTable[name] === \"function\") {\n return (args: any[]) => this.functionTable[name](agent, ...args.map((arg) => arg.value));\n }\n\n // We have no function to invoke.\n return null;\n }\n\n /**\n * Gets all registered subtree root node definitions.\n */\n static getSubtrees(): { [key: string]: RootNodeDefinition } {\n return this.subtreeTable;\n }\n\n /**\n * Sets the subtree with the specified name for later lookup.\n * @param name The name of the subtree.\n * @param subtree The subtree.\n */\n static setSubtree(name: string, subtree: RootNodeDefinition) {\n this.subtreeTable[name] = subtree;\n }\n\n /**\n * Removes the registered function or subtree with the specified name.\n * @param name The name of the registered function or subtree.\n */\n static remove(name: string) {\n delete this.functionTable[name];\n delete this.subtreeTable[name];\n }\n\n /**\n * Remove all registered functions and subtrees.\n */\n static empty() {\n this.functionTable = {};\n this.subtreeTable = {};\n }\n}\n", "import Node from \"../../nodes/Node\";\n\n/**\n * An exception thrown when evaluating node guard path conditions and a conditions fails.\n */\nexport default class GuardUnsatisifedException extends Error {\n /**\n * @param source The node at which a guard condition failed.\n */\n constructor(private source: Node) {\n super(\"A guard path condition has failed\");\n }\n\n /**\n * Gets whether the specified node is the node at which a guard condition failed.\n * @param node The node to check against the source node.\n * @returns Whether the specified node is the node at which a guard condition failed.\n */\n isSourceNode = (node: Node) => node === this.source;\n}\n", "import { Agent } from \"../../Agent\";\nimport Guard from \"./Guard\";\nimport Node from \"../../nodes/Node\";\nimport GuardUnsatisifedException from \"./GuardUnsatisifedException\";\n\nexport type GuardPathPart = {\n node: Node;\n guards: Guard[];\n};\n\n/**\n * Represents a path of node guards along a root-to-leaf tree path.\n */\nexport default class GuardPath {\n /**\n * @param nodes An array of objects defining a node instance -> guard link, ordered by node depth.\n */\n constructor(private nodes: GuardPathPart[]) {}\n\n /**\n * Evaluate guard conditions for all guards in the tree path, moving outwards from the root.\n * @param agent The agent, required for guard evaluation.\n * @returns An evaluation results object.\n */\n evaluate = (agent: Agent) => {\n // We need to evaluate guard conditions for nodes up the tree, moving outwards from the root.\n for (const details of this.nodes) {\n // There can be multiple guards per node.\n for (const guard of details.guards) {\n // Check whether the guard condition passes, and throw an exception if not.\n if (!guard.isSatisfied(agent)) {\n throw new GuardUnsatisifedException(details.node);\n }\n }\n }\n };\n}\n", "import { BehaviourTreeOptions } from \"../BehaviourTreeOptions\";\nimport State, { AnyState } from \"../State\";\nimport { Agent } from \"../Agent\";\nimport Leaf from \"./leaf/Leaf\";\nimport Attribute from \"../attributes/Attribute\";\nimport Entry from \"../attributes/callbacks/Entry\";\nimport Exit from \"../attributes/callbacks/Exit\";\nimport Step from \"../attributes/callbacks/Step\";\nimport Guard from \"../attributes/guards/Guard\";\nimport GuardPath from \"../attributes/guards/GuardPath\";\nimport GuardUnsatisifedException from \"../attributes/guards/GuardUnsatisifedException\";\n\n/**\n * A base node.\n */\nexport default abstract class Node {\n /**\n * The node uid.\n */\n private readonly uid: string = createNodeUid();\n /**\n * The node state.\n */\n private state: AnyState = State.READY;\n /**\n * The guard path to evaluate as part of a node update.\n */\n private guardPath: GuardPath | undefined;\n\n /**\n * @param type The node type.\n * @param attributes The node attributes.\n * @param args The node argument definitions.\n */\n constructor(private type: string, private attributes: Attribute[], private args: any[]) {}\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected abstract onUpdate(agent: Agent, options: BehaviourTreeOptions): void;\n\n /**\n * Gets the name of the node.\n */\n public abstract getName(): string;\n\n /**\n * Gets whether this node is a leaf node.\n */\n public abstract isLeafNode: () => this is Leaf;\n\n /**\n * Gets/Sets the state of the node.\n */\n getState = (): AnyState => this.state;\n setState = (value: AnyState): void => {\n this.state = value;\n };\n\n /**\n * Gets the unique id of the node.\n */\n getUid = () => this.uid;\n\n /**\n * Gets the type of the node.\n */\n getType = () => this.type;\n\n /**\n * Gets the node attributes.\n */\n getAttributes = () => this.attributes;\n\n /**\n * Gets the node arguments.\n */\n getArguments = () => this.args;\n\n /**\n * Gets the node attribute with the specified type, or null if it does not exist.\n */\n getAttribute(type: \"entry\" | \"ENTRY\"): Entry;\n getAttribute(type: \"exit\" | \"EXIT\"): Exit;\n getAttribute(type: \"step\" | \"STEP\"): Step;\n getAttribute(type: string): Attribute {\n return (\n this.getAttributes().filter((decorator) => decorator.type.toUpperCase() === type.toUpperCase())[0] || null\n );\n }\n\n /**\n * Gets the node attributes.\n */\n getGuardAttributes = (): Guard[] => this.getAttributes().filter((decorator) => decorator.isGuard()) as Guard[];\n\n /**\n * Sets the guard path to evaluate as part of a node update.\n */\n setGuardPath = (value: GuardPath) => (this.guardPath = value);\n\n /**\n * Gets whether a guard path is assigned to this node.\n */\n hasGuardPath = () => !!this.guardPath;\n\n /**\n * Gets whether this node is in the specified state.\n * @param value The value to compare to the node state.\n */\n public is(value: AnyState): boolean {\n return this.state === value;\n }\n\n /**\n * Reset the state of the node.\n */\n public reset(): void {\n this.setState(State.READY);\n }\n\n /**\n * Abort the running of this node.\n * @param agent The agent.\n */\n public abort(agent: Agent): void {\n // There is nothing to do if this node is not in the running state.\n if (!this.is(State.RUNNING)) {\n return;\n }\n\n // Reset the state of this node.\n this.reset();\n\n this.getAttribute(\"exit\")?.callAgentFunction(agent, false, true);\n }\n\n /**\n * Update the node.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n * @returns The result of the update.\n */\n public update(agent: Agent, options: BehaviourTreeOptions): void {\n // If this node is already in a 'SUCCEEDED' or 'FAILED' state then there is nothing to do.\n if (this.is(State.SUCCEEDED) || this.is(State.FAILED)) {\n return;\n }\n\n try {\n // Evaluate all of the guard path conditions for the current tree path.\n this.guardPath!.evaluate(agent);\n\n // If this node is in the READY state then call the ENTRY for this node if it exists.\n if (this.is(State.READY)) {\n this.getAttribute(\"entry\")?.callAgentFunction(agent);\n }\n\n this.getAttribute(\"step\")?.callAgentFunction(agent);\n\n // Do the actual update.\n this.onUpdate(agent, options);\n\n // If this node is now in a 'SUCCEEDED' or 'FAILED' state then call the EXIT for this node if it exists.\n if (this.is(State.SUCCEEDED) || this.is(State.FAILED)) {\n this.getAttribute(\"exit\")?.callAgentFunction(agent, this.is(State.SUCCEEDED), false);\n }\n } catch (error) {\n // If the error is a GuardUnsatisfiedException then we need to determine if this node is the source.\n if (error instanceof GuardUnsatisifedException && error.isSourceNode(this)) {\n // Abort the current node.\n this.abort(agent);\n\n // Any node that is the source of an abort will be a failed node.\n this.setState(State.FAILED);\n } else {\n throw error;\n }\n }\n }\n}\n\n/**\n * Create a randomly generated node uid.\n * @returns A randomly generated node uid.\n */\nfunction createNodeUid(): string {\n var S4 = function () {\n return (((1 + Math.random()) * 0x10000) | 0).toString(16).substring(1);\n };\n return S4() + S4() + \"-\" + S4() + \"-\" + S4() + \"-\" + S4() + \"-\" + S4() + S4() + S4();\n}\n", "import Node from \"../Node\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\n\n/**\n * A composite node that wraps child nodes.\n */\nexport default abstract class Composite extends Node {\n /**\n * @param type The node type.\n * @param attributes The node attributes.\n * @param children The child nodes.\n */\n constructor(type: string, attributes: Attribute[], protected children: Node[]) {\n super(type, attributes, []);\n }\n\n /**\n * Gets whether this node is a leaf node.\n */\n isLeafNode = () => false;\n\n /**\n * Gets the children of this node.\n */\n getChildren = () => this.children;\n\n /**\n * Reset the state of the node.\n */\n reset = () => {\n // Reset the state of this node.\n this.setState(State.READY);\n\n // Reset the state of any child nodes.\n this.getChildren().forEach((child) => child.reset());\n };\n\n /**\n * Abort the running of this node.\n * @param agent The agent.\n */\n abort = (agent: Agent) => {\n // There is nothing to do if this node is not in the running state.\n if (!this.is(State.RUNNING)) {\n return;\n }\n\n // Abort any child nodes.\n this.getChildren().forEach((child) => child.abort(agent));\n\n // Reset the state of this node.\n this.reset();\n\n this.getAttribute(\"exit\")?.callAgentFunction(agent, false, true);\n };\n}\n", "import Composite from \"./Composite\";\nimport State from \"../../State\";\nimport Node from \"../Node\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A PARALLEL node.\n * The child nodes are executed concurrently until one fails or all succeed.\n */\nexport default class Parallel extends Composite {\n /**\n * @param attributes The node attributes.\n * @param children The child nodes.\n */\n constructor(attributes: Attribute[], children: Node[]) {\n super(\"parallel\", attributes, children);\n }\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // Keep a count of the number of succeeded child nodes.\n let succeededCount = 0;\n\n let hasChildFailed = false;\n\n // Iterate over all of the children of this node.\n for (const child of this.children) {\n // If the child has never been updated or is running then we will need to update it now.\n if (child.getState() === State.READY || child.getState() === State.RUNNING) {\n // Update the child of this node.\n child.update(agent, options);\n }\n\n // If the current child has a state of 'SUCCEEDED' then we should move on to the next child.\n if (child.getState() === State.SUCCEEDED) {\n // The child node has succeeded, keep track of this to determine if all children have.\n succeededCount++;\n\n // The child node succeeded, but we have not finished checking every child node yet.\n continue;\n }\n\n // If the current child has a state of 'FAILED' then this node is also a 'FAILED' node.\n if (child.getState() === State.FAILED) {\n hasChildFailed = true;\n\n // There is no need to check the rest of the children.\n break;\n }\n\n // The node should be in the 'RUNNING' state.\n if (child.getState() !== State.RUNNING) {\n // The child node was not in an expected state.\n throw new Error(\"child node was not in an expected state.\");\n }\n }\n\n if (hasChildFailed) {\n // This node is a 'FAILED' node.\n this.setState(State.FAILED);\n\n // Abort every running child.\n for (const child of this.children) {\n if (child.getState() === State.RUNNING) {\n child.abort(agent);\n }\n }\n } else {\n // If all children have succeeded then this node has also succeeded, otherwise it is still running.\n this.setState(succeededCount === this.children.length ? State.SUCCEEDED : State.RUNNING);\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => \"PARALLEL\";\n}\n", "import Composite from \"./Composite\";\nimport Node from \"../Node\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A SELECTOR node.\n * The child nodes are executed in sequence until one succeeds or all fail.\n */\nexport default class Selector extends Composite {\n /**\n * @param attributes The node attributes.\n * @param children The child nodes.\n */\n constructor(attributes: Attribute[], protected children: Node[]) {\n super(\"selector\", attributes, children);\n }\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // Iterate over all of the children of this node.\n for (const child of this.children) {\n // If the child has never been updated or is running then we will need to update it now.\n if (child.getState() === State.READY || child.getState() === State.RUNNING) {\n // Update the child of this node.\n child.update(agent, options);\n }\n\n // If the current child has a state of 'SUCCEEDED' then this node is also a 'SUCCEEDED' node.\n if (child.getState() === State.SUCCEEDED) {\n // This node is a 'SUCCEEDED' node.\n this.setState(State.SUCCEEDED);\n\n // There is no need to check the rest of the selector nodes.\n return;\n }\n\n // If the current child has a state of 'FAILED' then we should move on to the next child.\n if (child.getState() === State.FAILED) {\n // Find out if the current child is the last one in the selector.\n // If it is then this sequence node has also failed.\n if (this.children.indexOf(child) === this.children.length - 1) {\n // This node is a 'FAILED' node.\n this.setState(State.FAILED);\n\n // There is no need to check the rest of the selector as we have completed it.\n return;\n } else {\n // The child node failed, try the next one.\n continue;\n }\n }\n\n // The node should be in the 'RUNNING' state.\n if (child.getState() === State.RUNNING) {\n // This node is a 'RUNNING' node.\n this.setState(State.RUNNING);\n\n // There is no need to check the rest of the selector as the current child is still running.\n return;\n }\n\n // The child node was not in an expected state.\n throw new Error(\"child node was not in an expected state.\");\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => \"SELECTOR\";\n}\n", "import Composite from \"./Composite\";\nimport Node from \"../Node\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A SEQUENCE node.\n * The child nodes are executed in sequence until one fails or all succeed.\n */\nexport default class Sequence extends Composite {\n /**\n * @param attributes The node attributes.\n * @param children The child nodes.\n */\n constructor(attributes: Attribute[], protected children: Node[]) {\n super(\"sequence\", attributes, children);\n }\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // Iterate over all of the children of this node.\n for (const child of this.children) {\n // If the child has never been updated or is running then we will need to update it now.\n if (child.getState() === State.READY || child.getState() === State.RUNNING) {\n // Update the child of this node.\n child.update(agent, options);\n }\n\n // If the current child has a state of 'SUCCEEDED' then we should move on to the next child.\n if (child.getState() === State.SUCCEEDED) {\n // Find out if the current child is the last one in the sequence.\n // If it is then this sequence node has also succeeded.\n if (this.children.indexOf(child) === this.children.length - 1) {\n // This node is a 'SUCCEEDED' node.\n this.setState(State.SUCCEEDED);\n\n // There is no need to check the rest of the sequence as we have completed it.\n return;\n } else {\n // The child node succeeded, but we have not finished the sequence yet.\n continue;\n }\n }\n\n // If the current child has a state of 'FAILED' then this node is also a 'FAILED' node.\n if (child.getState() === State.FAILED) {\n // This node is a 'FAILED' node.\n this.setState(State.FAILED);\n\n // There is no need to check the rest of the sequence.\n return;\n }\n\n // The node should be in the 'RUNNING' state.\n if (child.getState() === State.RUNNING) {\n // This node is a 'RUNNING' node.\n this.setState(State.RUNNING);\n\n // There is no need to check the rest of the sequence as the current child is still running.\n return;\n }\n\n // The child node was not in an expected state.\n throw new Error(\"child node was not in an expected state.\");\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => \"SEQUENCE\";\n}\n", "import createLotto from \"lotto-draw\";\n\nimport Node from \"../Node\";\nimport Composite from \"./Composite\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A LOTTO node.\n * A winning child is picked on the initial update of this node, based on ticket weighting.\n * The state of this node will match the state of the winning child.\n */\nexport default class Lotto extends Composite {\n /**\n * @param attributes The node attributes.\n * @param weights The child node weights.\n * @param children The child nodes.\n */\n constructor(attributes: Attribute[], private weights: number[] | undefined, children: Node[]) {\n super(\"lotto\", attributes, children);\n }\n\n /**\n * The child node selected to be the active one.\n */\n private selectedChild: Node | undefined;\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // If this node is in the READY state then we need to pick a winning child node.\n if (this.is(State.READY)) {\n // Create a lotto draw with which to randomly pick a child node to become the active one.\n const lottoDraw = createLotto({\n // Hook up the optional 'random' behaviour tree function option to the one used by 'lotto-draw'.\n random: options.random,\n // Pass in each child node as a participant in the lotto draw with their respective ticket count.\n participants: this.children.map((child, index) => [child, this.weights?.[index] || 1])\n });\n\n // Randomly pick a child based on ticket weighting, this will become the active child for this composite node.\n this.selectedChild = lottoDraw.draw() || undefined;\n }\n\n // If something went wrong and we don't have an active child then we should throw an error.\n if (!this.selectedChild) {\n throw new Error(\"failed to update lotto node as it has no active child\");\n }\n\n // If the selected child has never been updated or is running then we will need to update it now.\n if (this.selectedChild.getState() === State.READY || this.selectedChild.getState() === State.RUNNING) {\n this.selectedChild.update(agent, options);\n }\n\n // The state of the lotto node is the state of its selected child.\n this.setState(this.selectedChild.getState());\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => (this.weights ? `LOTTO [${this.weights.join(\",\")}]` : \"LOTTO\");\n}\n", "import Node from \"../Node\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\n\n/**\n * A decorator node that wraps a single child node.\n */\nexport default abstract class Decorator extends Node {\n /**\n * @param type The node type.\n * @param attributes The node attributes.\n * @param child The child node.\n */\n constructor(type: string, attributes: Attribute[], protected child: Node) {\n super(type, attributes, []);\n }\n\n /**\n * Gets whether this node is a leaf node.\n */\n isLeafNode = () => false;\n\n /**\n * Gets the children of this node.\n */\n getChildren = () => [this.child];\n\n /**\n * Reset the state of the node.\n */\n reset = () => {\n // Reset the state of this node.\n this.setState(State.READY);\n\n // Reset the state of the child node.\n this.child.reset();\n };\n\n /**\n * Abort the running of this node.\n * @param agent The agent.\n */\n abort = (agent: Agent) => {\n // There is nothing to do if this node is not in the running state.\n if (!this.is(State.RUNNING)) {\n return;\n }\n\n // Abort the child node.\n this.child.abort(agent);\n\n // Reset the state of this node.\n this.reset();\n\n this.getAttribute(\"exit\")?.callAgentFunction(agent, false, true);\n };\n}\n", "import Node from \"../Node\";\nimport Decorator from \"./Decorator\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A Fail node.\n * This node wraps a single child and will always move to the 'FAILED' state when the child moves to a 'SUCCEEDED' or 'FAILED' state.\n */\nexport default class Fail extends Decorator {\n /**\n * @param attributes The node attributes.\n * @param child The child node.\n */\n constructor(attributes: Attribute[], child: Node) {\n super(\"fail\", attributes, child);\n }\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // If the child has never been updated or is running then we will need to update it now.\n if (this.child.getState() === State.READY || this.child.getState() === State.RUNNING) {\n this.child.update(agent, options);\n }\n\n // The state of this node will depend in the state of its child.\n switch (this.child.getState()) {\n case State.RUNNING:\n this.setState(State.RUNNING);\n break;\n\n case State.SUCCEEDED:\n case State.FAILED:\n this.setState(State.FAILED);\n break;\n\n default:\n this.setState(State.READY);\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => \"FAIL\";\n}\n", "import Decorator from \"./Decorator\";\nimport State from \"../../State\";\nimport Node from \"../Node\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A Flip node.\n * This node wraps a single child and will flip the state of the child state.\n */\nexport default class Flip extends Decorator {\n /**\n * @param attributes The node attributes.\n * @param child The child node.\n */\n constructor(attributes: Attribute[], child: Node) {\n super(\"flip\", attributes, child);\n }\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // If the child has never been updated or is running then we will need to update it now.\n if (this.child.getState() === State.READY || this.child.getState() === State.RUNNING) {\n this.child.update(agent, options);\n }\n\n // The state of this node will depend in the state of its child.\n switch (this.child.getState()) {\n case State.RUNNING:\n this.setState(State.RUNNING);\n break;\n\n case State.SUCCEEDED:\n this.setState(State.FAILED);\n break;\n\n case State.FAILED:\n this.setState(State.SUCCEEDED);\n break;\n\n default:\n this.setState(State.READY);\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => \"FLIP\";\n}\n", "import Node from \"../Node\";\nimport Decorator from \"./Decorator\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A REPEAT node.\n * The node has a single child which can have:\n * -- A number of iterations for which to repeat the child node.\n * -- An infinite repeat loop if neither an iteration count or a condition function is defined.\n * The REPEAT node will stop and have a 'FAILED' state if its child is ever in a 'FAILED' state after an update.\n * The REPEAT node will attempt to move on to the next iteration if its child is ever in a 'SUCCEEDED' state.\n */\nexport default class Repeat extends Decorator {\n /**\n * @param attributes The node attributes.\n * @param iterations The number of iterations to repeat the child node.\n * @param iterationsMin The minimum possible number of iterations to repeat the child node.\n * @param iterationsMax The maximum possible number of iterations to repeat the child node.\n * @param child The child node.\n */\n constructor(\n attributes: Attribute[],\n private iterations: number | null,\n private iterationsMin: number | null,\n private iterationsMax: number | null,\n child: Node\n ) {\n super(\"repeat\", attributes, child);\n }\n\n /**\n * The number of target iterations to make.\n */\n private targetIterationCount: number | null = null;\n\n /**\n * The current iteration count.\n */\n private currentIterationCount: number = 0;\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // If this node is in the READY state then we need to reset the child and the target iteration count.\n if (this.is(State.READY)) {\n // Reset the child node.\n this.child.reset();\n\n // Reset the current iteration count.\n this.currentIterationCount = 0;\n\n // Set the target iteration count.\n this.setTargetIterationCount(options);\n }\n\n // Do a check to see if we can iterate. If we can then this node will move into the 'RUNNING' state.\n // If we cannot iterate then we have hit our target iteration count, which means that the node has succeeded.\n if (this.canIterate()) {\n // This node is in the running state and can do its initial iteration.\n this.setState(State.RUNNING);\n\n // We may have already completed an iteration, meaning that the child node will be in the SUCCEEDED state.\n // If this is the case then we will have to reset the child node now.\n if (this.child.getState() === State.SUCCEEDED) {\n this.child.reset();\n }\n\n // Update the child of this node.\n this.child.update(agent, options);\n\n // If the child moved into the FAILED state when we updated it then there is nothing left to do and this node has also failed.\n // If it has moved into the SUCCEEDED state then we have completed the current iteration.\n if (this.child.getState() === State.FAILED) {\n // The child has failed, meaning that this node has failed.\n this.setState(State.FAILED);\n\n return;\n } else if (this.child.getState() === State.SUCCEEDED) {\n // We have completed an iteration.\n this.currentIterationCount += 1;\n }\n } else {\n // This node is in the 'SUCCEEDED' state as we cannot iterate any more.\n this.setState(State.SUCCEEDED);\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => {\n if (this.iterations !== null) {\n return `REPEAT ${this.iterations}x`;\n } else if (this.iterationsMin !== null && this.iterationsMax !== null) {\n return `REPEAT ${this.iterationsMin}x-${this.iterationsMax}x`;\n } else {\n return \"REPEAT\";\n }\n };\n\n /**\n * Reset the state of the node.\n */\n reset = () => {\n // Reset the state of this node.\n this.setState(State.READY);\n\n // Reset the current iteration count.\n this.currentIterationCount = 0;\n\n // Reset the child node.\n this.child.reset();\n };\n\n /**\n * Gets whether an iteration can be made.\n * @returns Whether an iteration can be made.\n */\n private canIterate = () => {\n if (this.targetIterationCount !== null) {\n // We can iterate as long as we have not reached our target iteration count.\n return this.currentIterationCount < this.targetIterationCount;\n }\n\n // If neither an iteration count or a condition function were defined then we can iterate indefinitely.\n return true;\n };\n\n /**\n * Sets the target iteration count.\n * @param options The behaviour tree options object.\n */\n private setTargetIterationCount = (options: BehaviourTreeOptions) => {\n // Are we dealing with an explicit iteration count or will we be randomly picking a iteration count between the min and max iteration count.\n if (this.iterations !== null) {\n this.targetIterationCount = this.iterations;\n } else if (this.iterationsMin !== null && this.iterationsMax !== null) {\n // We will be picking a random iteration count between a min and max iteration count, if the optional 'random'\n // behaviour tree function option is defined then we will be using that, otherwise we will fall back to using Math.random.\n const random = typeof options.random === \"function\" ? options.random : Math.random;\n\n // Pick a random iteration count between a min and max iteration count.\n this.targetIterationCount = Math.floor(\n random() * (this.iterationsMax - this.iterationsMin + 1) + this.iterationsMin\n );\n } else {\n this.targetIterationCount = null;\n }\n };\n}\n", "import Node from \"../Node\";\nimport Decorator from \"./Decorator\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A RETRY node.\n * The node has a single child which can have:\n * -- A number of iterations for which to repeat the child node.\n * -- An infinite repeat loop if neither an iteration count or a condition function is defined.\n * The RETRY node will stop and have a 'SUCCEEDED' state if its child is ever in a 'SUCCEEDED' state after an update.\n * The RETRY node will attempt to move on to the next iteration if its child is ever in a 'FAILED' state.\n */\nexport default class Retry extends Decorator {\n /**\n * @param attributes The node attributes.\n * @param attempts The number of attempts to retry the child node.\n * @param attemptsMin The minimum possible number of attempts to retry the child node.\n * @param attemptsMax The maximum possible number of attempts to retry the child node.\n * @param child The child node.\n */\n constructor(\n attributes: Attribute[],\n private attempts: number | null,\n private attemptsMin: number | null,\n private attemptsMax: number | null,\n child: Node\n ) {\n super(\"retry\", attributes, child);\n }\n\n /**\n * The number of target attempts to make.\n */\n private targetAttemptCount: number | null = null;\n\n /**\n * The current attempt count.\n */\n private currentAttemptCount: number = 0;\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // If this node is in the READY state then we need to reset the child and the target attempt count.\n if (this.is(State.READY)) {\n // Reset the child node.\n this.child.reset();\n\n // Reset the current attempt count.\n this.currentAttemptCount = 0;\n\n // Set the target attempt count.\n this.setTargetAttemptCount(options);\n }\n\n // Do a check to see if we can attempt. If we can then this node will move into the 'RUNNING' state.\n // If we cannot attempt then we have hit our target attempt count, which means that the node has succeeded.\n if (this.canAttempt()) {\n // This node is in the running state and can do its initial attempt.\n this.setState(State.RUNNING);\n\n // We may have already completed an attempt, meaning that the child node will be in the FAILED state.\n // If this is the case then we will have to reset the child node now.\n if (this.child.getState() === State.FAILED) {\n this.child.reset();\n }\n\n // Update the child of this node.\n this.child.update(agent, options);\n\n // If the child moved into the SUCCEEDED state when we updated it then there is nothing left to do and this node has also succeeded.\n // If it has moved into the FAILED state then we have completed the current attempt.\n if (this.child.getState() === State.SUCCEEDED) {\n // The child has succeeded, meaning that this node has succeeded.\n this.setState(State.SUCCEEDED);\n\n return;\n } else if (this.child.getState() === State.FAILED) {\n // We have completed an attempt.\n this.currentAttemptCount += 1;\n }\n } else {\n // This node is in the 'FAILED' state as we cannot iterate any more.\n this.setState(State.FAILED);\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => {\n if (this.attempts !== null) {\n return `RETRY ${this.attempts}x`;\n } else if (this.attemptsMin !== null && this.attemptsMax !== null) {\n return `RETRY ${this.attemptsMin}x-${this.attemptsMax}x`;\n } else {\n return \"RETRY\";\n }\n };\n\n /**\n * Reset the state of the node.\n */\n reset = () => {\n // Reset the state of this node.\n this.setState(State.READY);\n\n // Reset the current attempt count.\n this.currentAttemptCount = 0;\n\n // Reset the child node.\n this.child.reset();\n };\n\n /**\n * Gets whether an attempt can be made.\n * @returns Whether an attempt can be made.\n */\n canAttempt = () => {\n if (this.targetAttemptCount !== null) {\n // We can attempt as long as we have not reached our target attempt count.\n return this.currentAttemptCount < this.targetAttemptCount;\n }\n\n // If neither an attempt count or a condition function were defined then we can attempt indefinitely.\n return true;\n };\n\n /**\n * Sets the target attempt count.\n * @param options The behaviour tree options object.\n */\n setTargetAttemptCount = (options: BehaviourTreeOptions) => {\n // Are we dealing with an explicit attempt count or will we be randomly picking an attempt count between the min and max attempt count.\n if (this.attempts !== null) {\n this.targetAttemptCount = this.attempts;\n } else if (this.attemptsMin !== null && this.attemptsMax !== null) {\n // We will be picking a random attempt count between a min and max attempt count, if the optional 'random'\n // behaviour tree function option is defined then we will be using that, otherwise we will fall back to using Math.random.\n const random = typeof options.random === \"function\" ? options.random : Math.random;\n\n // Pick a random attempt count between a min and max attempt count.\n this.targetAttemptCount = Math.floor(\n random() * (this.attemptsMax - this.attemptsMin + 1) + this.attemptsMin\n );\n } else {\n this.targetAttemptCount = null;\n }\n };\n}\n", "import Node from \"../Node\";\nimport Decorator from \"./Decorator\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A Root node.\n * The root node will have a single child.\n */\nexport default class Root extends Decorator {\n /**\n * @param attributes The node attributes.\n * @param child The child node.\n */\n constructor(attributes: Attribute[], child: Node) {\n super(\"root\", attributes, child);\n }\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // If the child has never been updated or is running then we will need to update it now.\n if (this.child.getState() === State.READY || this.child.getState() === State.RUNNING) {\n // Update the child of this node.\n this.child.update(agent, options);\n }\n\n // The state of the root node is the state of its child.\n this.setState(this.child.getState());\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => \"ROOT\";\n}\n", "import Node from \"../Node\";\nimport Decorator from \"./Decorator\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A Succeed node.\n * This node wraps a single child and will always move to the 'SUCCEEDED' state when the child moves to a 'SUCCEEDED' or 'FAILED' state.\n */\nexport default class Succeed extends Decorator {\n /**\n * @param attributes The node attributes.\n * @param child The child node.\n */\n constructor(attributes: Attribute[], child: Node) {\n super(\"succeed\", attributes, child);\n }\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // If the child has never been updated or is running then we will need to update it now.\n if (this.child.getState() === State.READY || this.child.getState() === State.RUNNING) {\n this.child.update(agent, options);\n }\n\n // The state of this node will depend in the state of its child.\n switch (this.child.getState()) {\n case State.RUNNING:\n this.setState(State.RUNNING);\n break;\n\n case State.SUCCEEDED:\n case State.FAILED:\n this.setState(State.SUCCEEDED);\n break;\n\n default:\n this.setState(State.READY);\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => \"SUCCEED\";\n}\n", "import Node from \"../Node\";\n\n/**\n * A leaf node.\n */\nexport default abstract class Leaf extends Node {\n /**\n * Gets whether this node is a leaf node.\n */\n isLeafNode = () => true;\n}\n", "import { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\nimport State, { CompleteState } from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Leaf from \"./Leaf\";\nimport Lookup from \"../../Lookup\";\nimport Attribute from \"../../attributes/Attribute\";\n\n/**\n * An Action leaf node.\n * This represents an immediate or ongoing state of behaviour.\n */\nexport default class Action extends Leaf {\n /**\n * @param attributes The node attributes.\n * @param actionName The action name.\n * @param actionArguments The array of action argument definitions.\n */\n constructor(attributes: Attribute[], private actionName: string, private actionArguments: any[]) {\n super(\"action\", attributes, actionArguments);\n }\n\n /**\n * Whether there is a pending update promise.\n */\n private isUsingUpdatePromise = false;\n\n /**\n * The finished state result of an update promise.\n */\n private updatePromiseStateResult: CompleteState | null = null;\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // If the result of this action depends on an update promise then there is nothing to do until\n // it resolves, unless there has been a value set as a result of the update promise resolving.\n if (this.isUsingUpdatePromise) {\n // Check whether the update promise has resolved with a state value.\n if (this.updatePromiseStateResult) {\n // Set the state of this node to match the state returned by the promise.\n this.setState(this.updatePromiseStateResult);\n }\n\n return;\n }\n\n // Attempt to get the invoker for the action function.\n const actionFuncInvoker = Lookup.getFuncInvoker(agent, this.actionName);\n\n // The action function should be defined.\n if (actionFuncInvoker === null) {\n throw new Error(\n `cannot update action node as the action '${this.actionName}' function is not defined on the agent and has not been registered`\n );\n }\n\n // Call the action function, the result of which may be:\n // - The finished state of this action node.\n // - A promise to return a finished node state.\n // - Undefined if the node should remain in the running state.\n const updateResult = actionFuncInvoker(this.actionArguments) as CompleteState | Promise;\n\n if (updateResult instanceof Promise) {\n updateResult.then(\n (result) => {\n // If 'isUpdatePromisePending' is null then the promise was cleared as it was resolving, probably via an abort of reset.\n if (!this.isUsingUpdatePromise) {\n return;\n }\n\n // Check to make sure the result is a valid finished state.\n if (result !== State.SUCCEEDED && result !== State.FAILED) {\n throw new Error(\n \"action node promise resolved with an invalid value, expected a State.SUCCEEDED or State.FAILED value to be returned\"\n );\n }\n\n // Set pending update promise state result to be processed on next update.\n this.updatePromiseStateResult = result;\n },\n (reason) => {\n // If 'isUpdatePromisePending' is null then the promise was cleared as it was resolving, probably via an abort of reset.\n if (!this.isUsingUpdatePromise) {\n return;\n }\n\n // Just throw whatever was returned as the rejection argument.\n throw new Error(reason);\n }\n );\n\n // This node will be in the 'RUNNING' state until the update promise resolves.\n this.setState(State.RUNNING);\n\n // We are now waiting for the promise returned by the use to resolve before we know what state this node is in.\n this.isUsingUpdatePromise = true;\n } else {\n // Validate the returned value.\n this.validateUpdateResult(updateResult);\n\n // Set the state of this node, this may be undefined, which just means that the node is still in the 'RUNNING' state.\n this.setState(updateResult || State.RUNNING);\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => this.actionName;\n\n /**\n * Reset the state of the node.\n */\n reset = () => {\n // Reset the state of this node.\n this.setState(State.READY);\n\n // There is no longer an update promise that we care about.\n this.isUsingUpdatePromise = false;\n this.updatePromiseStateResult = null;\n };\n\n /**\n * Validate the result of an update function call.\n * @param result The result of an update function call.\n */\n private validateUpdateResult = (result: CompleteState | boolean) => {\n switch (result) {\n case State.SUCCEEDED:\n case State.FAILED:\n case undefined:\n return;\n default:\n throw new Error(\n `action '${this.actionName}' 'onUpdate' returned an invalid response, expected an optional State.SUCCEEDED or State.FAILED value to be returned`\n );\n }\n };\n}\n", "import { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Leaf from \"./Leaf\";\nimport Lookup from \"../../Lookup\";\nimport Attribute from \"../../attributes/Attribute\";\n\n/**\n * A Condition leaf node.\n * This will succeed or fail immediately based on an agent predicate, without moving to the 'RUNNING' state.\n */\nexport default class Condition extends Leaf {\n /**\n * @param attributes The node attributes.\n * @param conditionName The name of the condition function.\n * @param conditionArguments The array of condition argument definitions.\n */\n constructor(attributes: Attribute[], private conditionName: string, private conditionArguments: any[]) {\n super(\"condition\", attributes, conditionArguments);\n }\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // Attempt to get the invoker for the condition function.\n const conditionFuncInvoker = Lookup.getFuncInvoker(agent, this.conditionName);\n\n // The condition function should be defined.\n if (conditionFuncInvoker === null) {\n throw new Error(\n `cannot update condition node as the condition '${this.conditionName}' function is not defined on the agent and has not been registered`\n );\n }\n\n // Call the condition function to determine the state of this node.\n this.setState(!!conditionFuncInvoker(this.conditionArguments) ? State.SUCCEEDED : State.FAILED);\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => this.conditionName;\n}\n", "import Leaf from \"./Leaf\";\nimport State from \"../../State\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { Agent } from \"../../Agent\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A WAIT node.\n * The state of this node will change to SUCCEEDED after a duration of time\n */\nexport default class Wait extends Leaf {\n /**\n * @param attributes The node attributes.\n * @param duration The duration that this node will wait to succeed in milliseconds.\n * @param durationMin The minimum possible duration in milliseconds that this node will wait to succeed.\n * @param durationMax The maximum possible duration in milliseconds that this node will wait to succeed.\n */\n constructor(\n attributes: Attribute[],\n private duration: number | null,\n private durationMin: number | null,\n private durationMax: number | null\n ) {\n super(\"wait\", attributes, []);\n }\n\n /**\n * The time in milliseconds at which this node was first updated.\n */\n private initialUpdateTime: number = 0;\n\n /**\n * The total duration in milliseconds that this node will be waiting for.\n */\n private totalDuration: number | null = null;\n\n /**\n * The duration in milliseconds that this node has been waiting for.\n */\n private waitedDuration: number = 0;\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // If this node is in the READY state then we need to set the initial update time.\n if (this.is(State.READY)) {\n // Set the initial update time.\n this.initialUpdateTime = new Date().getTime();\n\n // Set the initial waited duration.\n this.waitedDuration = 0;\n\n // Are we dealing with an explicit duration or will we be randomly picking a duration between the min and max duration.\n if (this.duration !== null) {\n this.totalDuration = this.duration;\n } else if (this.durationMin !== null && this.durationMax !== null) {\n // We will be picking a random duration between a min and max duration, if the optional 'random' behaviour tree\n // function option is defined then we will be using that, otherwise we will fall back to using Math.random.\n const random = typeof options.random === \"function\" ? options.random : Math.random;\n\n // Pick a random duration between a min and max duration.\n this.totalDuration = Math.floor(\n random() * (this.durationMax - this.durationMin + 1) + this.durationMin\n );\n } else {\n this.totalDuration = null;\n }\n\n // The node is now running until we finish waiting.\n this.setState(State.RUNNING);\n }\n\n // If we have no total duration then this wait node will wait indefinitely until it is aborted.\n if (this.totalDuration === null) {\n return;\n }\n\n // If we have a 'getDeltaTime' function defined as part of our options then we will use it to figure out how long we have waited for.\n if (typeof options.getDeltaTime === \"function\") {\n // Get the delta time.\n const deltaTime = options.getDeltaTime();\n\n // Our delta time must be a valid number and cannot be NaN.\n if (typeof deltaTime !== \"number\" || isNaN(deltaTime)) {\n throw new Error(\"The delta time must be a valid number and not NaN.\");\n }\n\n // Update the amount of time that this node has been waiting for based on the delta time.\n this.waitedDuration += deltaTime * 1000;\n } else {\n // We are not using a delta time, so we will just work out hom much time has passed since the first update.\n this.waitedDuration = new Date().getTime() - this.initialUpdateTime;\n }\n\n // Have we waited long enough?\n if (this.waitedDuration >= this.totalDuration) {\n // We have finished waiting!\n this.setState(State.SUCCEEDED);\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => {\n if (this.duration !== null) {\n return `WAIT ${this.duration}ms`;\n } else if (this.durationMin !== null && this.durationMax !== null) {\n return `WAIT ${this.durationMin}ms-${this.durationMax}ms`;\n } else {\n return \"WAIT\";\n }\n };\n}\n", "import Guard from \"./guards/Guard\";\n\nexport type AttributeDetails = {\n /** The attribute type. */\n type: string;\n\n /** The attribute arguments. */\n args: any[];\n};\n\n/**\n * A base node attribute.\n */\nexport default abstract class Attribute {\n /**\n * @param type The node attribute type.\n * @param args The array of attribute arguments.\n */\n constructor(public type: string, public args: any[]) {}\n\n /**\n * Gets the attribute details.\n */\n abstract getDetails(): TAttributeDetails;\n\n /**\n * Gets whether this attribute is a guard.\n */\n abstract isGuard: () => this is Guard;\n}\n", "import { Agent } from \"../../Agent\";\nimport Attribute, { AttributeDetails } from \"../Attribute\";\n\nexport type GuardAttributeDetails = {\n /** The name of the condition function that determines whether the guard is satisfied. */\n condition: string;\n} & AttributeDetails;\n\n/**\n * A base node guard attribute.\n */\nexport default abstract class Guard extends Attribute {\n /**\n * @param type The node attribute type.\n * @param args The array of decorator argument definitions.\n * @param condition The name of the condition function that determines whether the guard is satisfied.\n */\n constructor(type: string, args: any[], private condition: string) {\n super(type, args);\n }\n\n /**\n * Gets the name of the condition function that determines whether the guard is satisfied.\n */\n getCondition = () => this.condition;\n\n /**\n * Gets whether this attribute is a guard.\n */\n isGuard = () => true;\n\n /**\n * Gets the attribute details.\n */\n getDetails(): GuardAttributeDetails {\n return {\n type: this.type,\n args: this.args,\n condition: this.getCondition()\n };\n }\n\n /**\n * Gets whether the guard is satisfied.\n * @param agent The agent.\n * @returns Whether the guard is satisfied.\n */\n abstract isSatisfied(agent: Agent): boolean;\n}\n", "import Guard from \"./Guard\";\nimport Lookup from \"../../Lookup\";\nimport { Agent } from \"../../Agent\";\n\n/**\n * A WHILE guard which is satisfied as long as the given condition remains true.\n */\nexport default class While extends Guard {\n /**\n * @param condition The name of the condition function that determines whether the guard is satisfied.\n * @param args The array of decorator argument definitions.\n */\n constructor(condition: string, args: any[]) {\n super(\"while\", args, condition);\n }\n\n /**\n * Gets whether the guard is satisfied.\n * @param agent The agent.\n * @returns Whether the guard is satisfied.\n */\n isSatisfied = (agent: Agent) => {\n // Attempt to get the invoker for the condition function.\n const conditionFuncInvoker = Lookup.getFuncInvoker(agent, this.getCondition());\n\n // The condition function should be defined.\n if (conditionFuncInvoker === null) {\n throw new Error(\n `cannot evaluate node guard as the condition '${this.getCondition()}' function is not defined on the agent and has not been registered`\n );\n }\n\n // Call the condition function to determine whether this guard is satisfied.\n return !!conditionFuncInvoker(this.args);\n };\n}\n", "import Guard from \"./Guard\";\nimport Lookup from \"../../Lookup\";\nimport { Agent } from \"../../Agent\";\n\n/**\n * An UNTIL guard which is satisfied as long as the given condition remains false.\n */\nexport default class Until extends Guard {\n /**\n * @param condition The name of the condition function that determines whether the guard is satisfied.\n * @param args The array of decorator argument definitions.\n */\n constructor(condition: string, args: any[]) {\n super(\"until\", args, condition);\n }\n\n /**\n * Gets whether the guard is satisfied.\n * @param agent The agent.\n * @returns Whether the guard is satisfied.\n */\n isSatisfied = (agent: Agent) => {\n // Attempt to get the invoker for the condition function.\n const conditionFuncInvoker = Lookup.getFuncInvoker(agent, this.getCondition());\n\n // The condition function should be defined.\n if (conditionFuncInvoker === null) {\n throw new Error(\n `cannot evaluate node guard as the condition '${this.getCondition()}' function is not defined on the agent and has not been registered`\n );\n }\n\n // Call the condition function to determine whether this guard is satisfied.\n return !!!conditionFuncInvoker(this.args);\n };\n}\n", "import { Agent } from \"../../Agent\";\nimport Attribute, { AttributeDetails } from \"../Attribute\";\n\nexport type CallbackAttributeDetails = {\n /** The name of the agent function that is called. */\n functionName: string;\n} & AttributeDetails;\n\n/**\n * A base node callback attribute.\n */\nexport default abstract class Callback extends Attribute {\n /**\n * @param type The node attribute type.\n * @param args The array of decorator argument definitions.\n * @param functionName The name of the agent function to call.\n */\n constructor(type: string, args: any[], private functionName: string) {\n super(type, args);\n }\n\n /**\n * Gets the name of the agent function to call.\n */\n getFunctionName = () => this.functionName;\n\n /**\n * Gets whether this attribute is a guard.\n */\n isGuard = () => false;\n\n /**\n * Gets the attribute details.\n */\n getDetails(): CallbackAttributeDetails {\n return {\n type: this.type,\n args: this.args,\n functionName: this.getFunctionName()\n };\n }\n\n /**\n * Attempt to call the agent function that this callback refers to.\n * @param agent The agent.\n */\n abstract callAgentFunction: (agent: Agent, isSuccess: boolean, isAborted: boolean) => void;\n}\n", "import Callback from \"./Callback\";\nimport Lookup from \"../../Lookup\";\nimport { Agent } from \"../../Agent\";\n\n/**\n * An ENTRY callback which defines an agent function to call when the associated node is updated and moves out of running state.\n */\nexport default class Entry extends Callback {\n /**\n * @param functionName The name of the agent function to call.\n * @param args The array of callback argument definitions.\n */\n constructor(functionName: string, args: any[]) {\n super(\"entry\", args, functionName);\n }\n\n /**\n * Attempt to call the agent function that this callback refers to.\n * @param agent The agent.\n */\n callAgentFunction = (agent: Agent) => {\n // Attempt to get the invoker for the callback function.\n const callbackFuncInvoker = Lookup.getFuncInvoker(agent, this.getFunctionName());\n\n // The callback function should be defined.\n if (callbackFuncInvoker === null) {\n throw new Error(\n `cannot call entry function '${this.getFunctionName()}' as is not defined on the agent and has not been registered`\n );\n }\n\n // Call the callback function.\n callbackFuncInvoker(this.args);\n };\n}\n", "import Callback from \"./Callback\";\nimport Lookup from \"../../Lookup\";\nimport { Agent } from \"../../Agent\";\n\n/**\n * A STEP callback which defines an agent function to call when the associated node is updated.\n */\nexport default class Step extends Callback {\n /**\n * @param functionName The name of the agent function to call.\n * @param args The array of callback argument definitions.\n */\n constructor(functionName: string, args: any[]) {\n super(\"step\", args, functionName);\n }\n\n /**\n * Attempt to call the agent function that this callback refers to.\n * @param agent The agent.\n */\n callAgentFunction = (agent: Agent) => {\n // Attempt to get the invoker for the callback function.\n const callbackFuncInvoker = Lookup.getFuncInvoker(agent, this.getFunctionName());\n\n // The callback function should be defined.\n if (callbackFuncInvoker === null) {\n throw new Error(\n `cannot call step function '${this.getFunctionName()}' as is not defined on the agent and has not been registered`\n );\n }\n\n // Call the callback function.\n callbackFuncInvoker(this.args);\n };\n}\n", "import Callback from \"./Callback\";\nimport Lookup from \"../../Lookup\";\nimport { Agent } from \"../../Agent\";\n\n/**\n * An EXIT callback which defines an agent function to call when the associated node is updated and moves to a finished state or is aborted.\n */\nexport default class Exit extends Callback {\n /**\n * @param functionName The name of the agent function to call.\n * @param args The array of callback argument definitions.\n */\n constructor(functionName: string, args: any[]) {\n super(\"exit\", args, functionName);\n }\n\n /**\n * Attempt to call the agent function that this callback refers to.\n * @param agent The agent.\n * @param isSuccess Whether the decorated node was left with a success state.\n * @param isAborted Whether the decorated node was aborted.\n */\n callAgentFunction = (agent: Agent, isSuccess: boolean, isAborted: boolean) => {\n // Attempt to get the invoker for the callback function.\n const callbackFuncInvoker = Lookup.getFuncInvoker(agent, this.getFunctionName());\n\n // The callback function should be defined.\n if (callbackFuncInvoker === null) {\n throw new Error(\n `cannot call exit function '${this.getFunctionName()}' as is not defined on the agent and has not been registered`\n );\n }\n\n // Call the callback function\n callbackFuncInvoker([{ value: { succeeded: isSuccess, aborted: isAborted } }, ...this.args]);\n };\n}\n", "import { AnyNodeDefinition, RootNodeDefinition } from \"./BehaviourTreeDefinition\";\nimport GuardPath, { GuardPathPart } from \"./attributes/guards/GuardPath\";\nimport { validateBranchSubtreeLinks } from \"./BehaviourTreeDefinitionValidator\";\nimport { isInteger } from \"./BehaviourTreeDefinitionUtilities\";\nimport Node from \"./nodes/Node\";\nimport Composite from \"./nodes/composite/Composite\";\nimport Decorator from \"./nodes/decorator/Decorator\";\nimport Parallel from \"./nodes/composite/Parallel\";\nimport Selector from \"./nodes/composite/Selector\";\nimport Sequence from \"./nodes/composite/Sequence\";\nimport Lotto from \"./nodes/composite/Lotto\";\nimport Fail from \"./nodes/decorator/Fail\";\nimport Flip from \"./nodes/decorator/Flip\";\nimport Repeat from \"./nodes/decorator/Repeat\";\nimport Retry from \"./nodes/decorator/Retry\";\nimport Root from \"./nodes/decorator/Root\";\nimport Succeed from \"./nodes/decorator/Succeed\";\nimport Action from \"./nodes/leaf/Action\";\nimport Condition from \"./nodes/leaf/Condition\";\nimport Wait from \"./nodes/leaf/Wait\";\nimport Lookup from \"./Lookup\";\nimport Attribute from \"./attributes/Attribute\";\nimport While from \"./attributes/guards/While\";\nimport Until from \"./attributes/guards/Until\";\nimport Entry from \"./attributes/callbacks/Entry\";\nimport Step from \"./attributes/callbacks/Step\";\nimport Exit from \"./attributes/callbacks/Exit\";\n\n/**\n * A type representing any node instance in a behaviour tree.\n */\ntype AnyNode =\n | Root\n | Action\n | Condition\n | Wait\n | Sequence\n | Selector\n | Lotto\n | Parallel\n | Repeat\n | Retry\n | Flip\n | Succeed\n | Fail;\n\n/**\n * A type defining a mapping of root node identifiers to root node definitions.\n */\ntype RootNodeDefinitionMap = { [key: string | symbol]: RootNodeDefinition };\n\n/**\n * A symbol to use as the main root key in any root node mappings.\n */\nconst MAIN_ROOT_NODE_KEY = Symbol(\"__root__\");\n\n/**\n * Build and populate the root nodes based on the provided definition, assuming that the definition has been validated.\n * @param definition The root node definitions.\n * @returns The built and populated root node definitions.\n */\nexport default function buildRootNode(definition: RootNodeDefinition[]): Root {\n // Create a mapping of root node identifers to root node definitions, including globally registered subtree root node definitions.\n const rootNodeDefinitionMap = createRootNodeDefinitionMap(definition);\n\n // Now that we have all of our root node definitons (those part of the tree definition and those globally\n // registered) we should validate the definition. This will also double-check that we dont have any circular\n // dependencies in our branch -> subtree references and that we have no broken branch -> subtree links.\n validateBranchSubtreeLinks(definition, true);\n\n // Create our populated tree of node instances, starting with our main root node.\n const rootNode = nodeFactory(rootNodeDefinitionMap[MAIN_ROOT_NODE_KEY], rootNodeDefinitionMap) as Root;\n\n // Set a guard path on every leaf of the tree to evaluate as part of each update.\n applyLeafNodeGuardPaths(rootNode);\n\n // We only need to return the main root node.\n return rootNode;\n}\n\n/**\n * A factory function which creates a node instance based on the specified definition.\n * @param definition The node definition.\n * @param rootNodeDefinitionMap The mapping of root node identifers to root node definitions, including globally registered subtree root node definitions.\n * @returns A node instance based on the specified definition.\n */\nfunction nodeFactory(definition: AnyNodeDefinition, rootNodeDefinitionMap: RootNodeDefinitionMap): AnyNode {\n // Get the attributes for the node.\n const attributes = nodeAttributesFactory(definition);\n\n // Create the node instance based on the definition type.\n switch (definition.type) {\n case \"root\":\n return new Root(attributes, nodeFactory(definition.child, rootNodeDefinitionMap));\n\n case \"repeat\":\n let iterations: number | null = null;\n let iterationsMin: number | null = null;\n let iterationsMax: number | null = null;\n\n if (Array.isArray(definition.iterations)) {\n iterationsMin = definition.iterations[0];\n iterationsMax = definition.iterations[1];\n } else if (isInteger(definition.iterations)) {\n iterations = definition.iterations!;\n }\n\n return new Repeat(\n attributes,\n iterations,\n iterationsMin,\n iterationsMax,\n nodeFactory(definition.child, rootNodeDefinitionMap)\n );\n\n case \"retry\":\n let attempts: number | null = null;\n let attemptsMin: number | null = null;\n let attemptsMax: number | null = null;\n\n if (Array.isArray(definition.attempts)) {\n attemptsMin = definition.attempts[0];\n attemptsMax = definition.attempts[1];\n } else if (isInteger(definition.attempts)) {\n attempts = definition.attempts!;\n }\n\n return new Retry(\n attributes,\n attempts,\n attemptsMin,\n attemptsMax,\n nodeFactory(definition.child, rootNodeDefinitionMap)\n );\n\n case \"flip\":\n return new Flip(attributes, nodeFactory(definition.child, rootNodeDefinitionMap));\n\n case \"succeed\":\n return new Succeed(attributes, nodeFactory(definition.child, rootNodeDefinitionMap));\n\n case \"fail\":\n return new Fail(attributes, nodeFactory(definition.child, rootNodeDefinitionMap));\n\n case \"sequence\":\n return new Sequence(\n attributes,\n definition.children.map((child) => nodeFactory(child, rootNodeDefinitionMap))\n );\n\n case \"selector\":\n return new Selector(\n attributes,\n definition.children.map((child) => nodeFactory(child, rootNodeDefinitionMap))\n );\n\n case \"parallel\":\n return new Parallel(\n attributes,\n definition.children.map((child) => nodeFactory(child, rootNodeDefinitionMap))\n );\n\n case \"lotto\":\n return new Lotto(\n attributes,\n definition.weights,\n definition.children.map((child) => nodeFactory(child, rootNodeDefinitionMap))\n );\n\n case \"branch\":\n return nodeFactory(rootNodeDefinitionMap[definition.ref].child, rootNodeDefinitionMap);\n\n case \"action\":\n return new Action(attributes, definition.call, definition.args || []);\n\n case \"condition\":\n return new Condition(attributes, definition.call, definition.args || []);\n\n case \"wait\":\n let duration: number | null = null;\n let durationMin: number | null = null;\n let durationMax: number | null = null;\n\n if (Array.isArray(definition.duration)) {\n durationMin = definition.duration[0];\n durationMax = definition.duration[1];\n } else if (isInteger(definition.duration)) {\n duration = definition.duration!;\n }\n\n return new Wait(attributes, duration, durationMin, durationMax);\n }\n}\n\n/**\n * Creates an array of node attribute instances based on the specified node definition.\n * @param definition The node definition.\n * @returns An array of node attribute instances based on the specified node definition.\n */\nfunction nodeAttributesFactory(definition: AnyNodeDefinition): Attribute[] {\n const attributes: Attribute[] = [];\n\n if (definition.while) {\n attributes.push(new While(definition.while.call, definition.while.args ?? []));\n }\n\n if (definition.until) {\n attributes.push(new Until(definition.until.call, definition.until.args ?? []));\n }\n\n if (definition.entry) {\n attributes.push(new Entry(definition.entry.call, definition.entry.args ?? []));\n }\n\n if (definition.step) {\n attributes.push(new Step(definition.step.call, definition.step.args ?? []));\n }\n\n if (definition.exit) {\n attributes.push(new Exit(definition.exit.call, definition.exit.args ?? []));\n }\n\n return attributes;\n}\n\n/**\n * Creates a mapping of root node identifers to root node definitions, mixing in globally registered subtree root node definitions.\n * @param definition The root node definitions.\n * @returns A mapping of root node identifers to root node definitions, including globally registered subtree root node definitions.\n */\nfunction createRootNodeDefinitionMap(definition: RootNodeDefinition[]): RootNodeDefinitionMap {\n // Create a mapping of root node identifers to root node definitions.\n const rootNodeMap: RootNodeDefinitionMap = {};\n\n // Add in any registered subtree root node definitions.\n for (const [name, rootNodeDefinition] of Object.entries(Lookup.getSubtrees())) {\n // The name used when registering the subtree will be used as the root node identifier.\n rootNodeMap[name] = { ...rootNodeDefinition, id: name };\n }\n\n // Populate the map with the root node definitions that were included with the tree definition.\n // We do this after adding any registered subtrees as we want these to take presedence.\n for (const rootNodeDefinition of definition) {\n rootNodeMap[rootNodeDefinition.id ?? MAIN_ROOT_NODE_KEY] = rootNodeDefinition;\n }\n\n return rootNodeMap;\n}\n\n/**\n * Applies a guard path to every leaf of the tree to evaluate as part of each update.\n * @param root The main root tree node.\n */\nfunction applyLeafNodeGuardPaths(root: Root) {\n const nodePaths: Node[][] = [];\n\n const findLeafNodes = (path: Node[], node: Node) => {\n // Add the current node to the path.\n path = path.concat(node);\n\n // Check whether the current node is a leaf node.\n if (node.isLeafNode()) {\n nodePaths.push(path);\n } else {\n (node as Composite | Decorator).getChildren().forEach((child) => findLeafNodes(path, child));\n }\n };\n\n // Find all leaf node paths, starting from the root.\n findLeafNodes([], root);\n\n nodePaths.forEach((path) => {\n // Each node in the current path will have to be assigned a guard path, working from the root outwards.\n for (let depth = 0; depth < path.length; depth++) {\n // Get the node in the path at the current depth.\n const currentNode = path[depth];\n\n // The node may already have been assigned a guard path, if so just skip it.\n if (currentNode.hasGuardPath()) {\n continue;\n }\n\n // Create the guard path for the current node.\n const guardPath = new GuardPath(\n path\n .slice(0, depth + 1)\n .map((node) => ({ node, guards: node.getGuardAttributes() }))\n .filter((details) => details.guards.length > 0)\n );\n\n // Assign the guard path to the current node.\n currentNode.setGuardPath(guardPath);\n }\n });\n}\n", "import State, { AnyState } from \"./State\";\nimport Lookup from \"./Lookup\";\nimport Node from \"./nodes/Node\";\nimport Root from \"./nodes/decorator/Root\";\nimport Composite from \"./nodes/composite/Composite\";\nimport Decorator from \"./nodes/decorator/Decorator\";\nimport { Agent, GlobalFunction } from \"./Agent\";\nimport { CallbackAttributeDetails } from \"./attributes/callbacks/Callback\";\nimport { GuardAttributeDetails } from \"./attributes/guards/Guard\";\nimport { BehaviourTreeOptions } from \"./BehaviourTreeOptions\";\nimport { convertMDSLToJSON } from \"./mdsl/MDSLDefinitionParser\";\nimport { RootNodeDefinition } from \"./BehaviourTreeDefinition\";\nimport { validateDefinition, validateJSONDefinition } from \"./BehaviourTreeDefinitionValidator\";\nimport buildRootNode from \"./BehaviourTreeBuilder\";\nimport { isNullOrUndefined } from \"./BehaviourTreeDefinitionUtilities\";\n\n// Purely for outside inspection of the tree.\nexport type FlattenedTreeNode = {\n id: string;\n type: string;\n caption: string;\n state: AnyState;\n guards: GuardAttributeDetails[];\n callbacks: CallbackAttributeDetails[];\n args: any[];\n parentId: string | null;\n};\n\n/**\n * A representation of a behaviour tree.\n */\nexport class BehaviourTree {\n /**\n * The main root tree node.\n */\n public readonly rootNode: Root;\n\n /**\n * Creates a new instance of the BehaviourTree class.\n * @param definition The behaviour tree definition as either an MDSL string, root node definition object or array of root node definition objects.\n * @param agent The agent instance that this behaviour tree is modelling behaviour for.\n * @param options The behaviour tree options object.\n */\n constructor(\n definition: string | RootNodeDefinition | RootNodeDefinition[],\n private agent: Agent,\n private options: BehaviourTreeOptions = {}\n ) {\n // The tree definition must be defined.\n if (isNullOrUndefined(definition)) {\n throw new Error(\"tree definition not defined\");\n }\n\n // The agent must be defined and not null.\n if (typeof agent !== \"object\" || agent === null) {\n throw new Error(\"the agent must be an object and not null\");\n }\n\n // We should validate the definition before we try to build the tree nodes.\n const { succeeded, errorMessage, json } = validateDefinition(definition);\n\n // Did our validation fail without error?\n if (!succeeded) {\n throw new Error(`invalid definition: ${errorMessage}`);\n }\n\n // Double check that we did actually get our json definition as part of our definition validtion.\n if (!json) {\n throw new Error(\n \"expected json definition to be returned as part of successful definition validation response\"\n );\n }\n\n try {\n // Create the populated tree of behaviour tree nodes and get the root node.\n this.rootNode = buildRootNode(json);\n } catch (exception) {\n // There was an issue in trying build and populate the behaviour tree.\n throw new Error(`error building tree: ${(exception as Error).message}`);\n }\n }\n\n /**\n * Gets whether the tree is in the RUNNING state.\n * @returns true if the tree is in the RUNNING state, otherwise false.\n */\n isRunning() {\n return this.rootNode.getState() === State.RUNNING;\n }\n\n /**\n * Gets the current tree state of SUCCEEDED, FAILED, READY or RUNNING.\n * @returns The current tree state.\n */\n getState() {\n return this.rootNode.getState();\n }\n\n /**\n * Step the tree.\n * 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.\n * 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\n * 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.\n *\n * 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.\n */\n step() {\n // If the root node has already been stepped to completion then we need to reset it.\n if (this.rootNode.getState() === State.SUCCEEDED || this.rootNode.getState() === State.FAILED) {\n this.rootNode.reset();\n }\n\n try {\n this.rootNode.update(this.agent, this.options);\n } catch (exception) {\n throw new Error(`error stepping tree: ${(exception as Error).message}`);\n }\n }\n\n /**\n * Resets the tree from the root node outwards to each nested node, giving each a state of READY.\n */\n reset() {\n this.rootNode.reset();\n }\n\n /**\n * Gets the flattened details of every node in the tree.\n * @returns The flattened details of every node in the tree.\n */\n getFlattenedNodeDetails(): FlattenedTreeNode[] {\n // Create an empty flattened array of tree nodes.\n const flattenedTreeNodes: FlattenedTreeNode[] = [];\n\n /**\n * Helper function to process a node instance and push details into the flattened tree nodes array.\n * @param node The current node.\n * @param parentUid The UID of the node parent, or null if the node is the main root node.\n */\n const processNode = (node: Node, parentUid: string | null) => {\n // Get the guard and callback attribute details for this node.\n const guards = node\n .getAttributes()\n .filter((attribute) => attribute.isGuard())\n .map((attribute) => attribute.getDetails()) as GuardAttributeDetails[];\n const callbacks = node\n .getAttributes()\n .filter((attribute) => !attribute.isGuard())\n .map((attribute) => attribute.getDetails()) as CallbackAttributeDetails[];\n\n // Push the current node into the flattened nodes array.\n flattenedTreeNodes.push({\n id: node.getUid(),\n type: node.getType(),\n caption: node.getName(),\n state: node.getState(),\n guards,\n callbacks,\n args: node.getArguments(),\n parentId: parentUid\n });\n\n // Process each of the nodes children if it is not a leaf node.\n if (!node.isLeafNode()) {\n (node as Composite | Decorator)\n .getChildren()\n .forEach((child) => processNode(child, (node as Composite | Decorator).getUid()));\n }\n };\n\n // Convert the nested node structure into a flattened array of node details.\n processNode(this.rootNode, null);\n\n return flattenedTreeNodes;\n }\n\n /**\n * Registers the action/condition/guard/callback function or subtree with the given name.\n * @param name The name of the function or subtree to register.\n * @param value The function or subtree definition to register.\n */\n static register(name: string, value: GlobalFunction | string | RootNodeDefinition) {\n // Are we going to register a action/condition/guard/callback function?\n if (typeof value === \"function\") {\n Lookup.setFunc(name, value);\n return;\n }\n\n // We are not registering an action/condition/guard/callback function, so we must be registering a subtree.\n if (typeof value === \"string\") {\n let rootNodeDefinitions: RootNodeDefinition[];\n\n // We will assume that any string passed in will be a mdsl definition.\n try {\n rootNodeDefinitions = convertMDSLToJSON(value);\n } catch (exception) {\n throw new Error(`error registering definition, invalid MDSL: ${(exception as Error).message}`);\n }\n\n // This function should only ever be called with a definition containing a single unnamed root node.\n if (rootNodeDefinitions.length != 1 || rootNodeDefinitions[0].id !== null) {\n throw new Error(\"error registering definition: expected a single unnamed root node\");\n }\n\n try {\n // We should validate the subtree as we don't want invalid subtrees available via the lookup.\n const { succeeded, errorMessage } = validateJSONDefinition(rootNodeDefinitions[0]);\n\n // Did our validation fail without error?\n if (!succeeded) {\n throw new Error(errorMessage);\n }\n } catch (exception) {\n throw new Error(`error registering definition: ${(exception as Error).message}`);\n }\n\n // Everything seems hunky-dory, register the subtree.\n Lookup.setSubtree(name, rootNodeDefinitions[0]);\n } else if (typeof value === \"object\" && !Array.isArray(value)) {\n // We will assume that any object passed in is a root node definition.\n\n try {\n // We should validate the subtree as we don't want invalid subtrees available via the lookup.\n const { succeeded, errorMessage } = validateJSONDefinition(value);\n\n // Did our validation fail without error?\n if (!succeeded) {\n throw new Error(errorMessage);\n }\n } catch (exception) {\n throw new Error(`error registering definition: ${(exception as Error).message}`);\n }\n\n // Everything seems hunky-dory, register the subtree.\n Lookup.setSubtree(name, value);\n } else {\n throw new Error(\"unexpected value, expected string mdsl definition, root node json definition or function\");\n }\n }\n\n /**\n * Unregisters the registered action/condition/guard/callback function or subtree with the given name.\n * @param name The name of the registered action/condition/guard/callback function or subtree to unregister.\n */\n static unregister(name: string): void {\n Lookup.remove(name);\n }\n\n /**\n * Unregister all registered action/condition/guard/callback functions and subtrees.\n */\n static unregisterAll(): void {\n Lookup.empty();\n }\n}\n"], + "mappings": "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", "names": ["Participant", "isNullOrUndefined", "Lotto", "createLotto", "State", "createLotto"] } diff --git a/src/BehaviourTree.ts b/src/BehaviourTree.ts index 4e9dbfd..7569a21 100644 --- a/src/BehaviourTree.ts +++ b/src/BehaviourTree.ts @@ -37,7 +37,7 @@ export class BehaviourTree { /** * Creates a new instance of the BehaviourTree class. - * @param definition The behaviour tree definition. + * @param definition The behaviour tree definition as either an MDSL string, root node definition object or array of root node definition objects. * @param agent The agent instance that this behaviour tree is modelling behaviour for. * @param options The behaviour tree options object. */ @@ -73,7 +73,7 @@ export class BehaviourTree { try { // Create the populated tree of behaviour tree nodes and get the root node. - this.rootNode = buildRootNode(json!); + this.rootNode = buildRootNode(json); } catch (exception) { // There was an issue in trying build and populate the behaviour tree. throw new Error(`error building tree: ${(exception as Error).message}`); From 70699ad1b28969577cb3dc285565da744eebccf0 Mon Sep 17 00:00:00 2001 From: Nikolas Howard Date: Sat, 17 Feb 2024 21:32:03 +0000 Subject: [PATCH 28/48] Updated all test.js files to spec.ts files --- .vscode/launch.json | 20 +- dist/Agent.d.ts | 2 +- dist/BehaviourTree.d.ts | 3 +- dist/bundle.js | 18 +- dist/bundle.js.map | 4 +- dist/index.js | 18 +- dist/index.js.map | 4 +- package-lock.json | 265 ++++++++++++++++-- package.json | 13 +- src/Agent.ts | 2 +- src/BehaviourTree.ts | 18 +- ...iourTree.test.js => BehaviourTree.spec.ts} | 215 +++++++------- ... BehaviourTreeDefinitionValidator.spec.ts} | 12 +- test/TestUtilities.ts | 25 ++ ...r.test.js => MDSLDefinitionParser.spec.ts} | 5 +- .../{Lotto.test.js => Lotto.spec.ts} | 144 +++++----- .../{Parallel.test.js => Parallel.spec.ts} | 14 +- .../{Selector.test.js => Selector.spec.ts} | 74 ++--- .../{Sequence.test.js => Sequence.spec.ts} | 14 +- .../decorator/{Fail.test.js => Fail.spec.ts} | 66 ++--- .../decorator/{Flip.test.js => Flip.spec.ts} | 58 ++-- .../{Repeat.test.js => Repeat.spec.ts} | 66 ++--- .../{Retry.test.js => Retry.spec.ts} | 66 ++--- .../{Succeed.test.js => Succeed.spec.ts} | 58 ++-- .../leaf/{Action.test.js => Action.spec.ts} | 94 +++---- .../{Condition.test.js => Condition.spec.ts} | 70 ++--- .../nodes/leaf/{Wait.test.js => Wait.spec.ts} | 72 ++--- 27 files changed, 840 insertions(+), 580 deletions(-) rename test/{BehaviourTree.test.js => BehaviourTree.spec.ts} (57%) rename test/{BehaviourTreeDefinitionValidator.test.js => BehaviourTreeDefinitionValidator.spec.ts} (93%) create mode 100644 test/TestUtilities.ts rename test/mdsl/{MDSLDefinitionParser.test.js => MDSLDefinitionParser.spec.ts} (65%) rename test/nodes/composite/{Lotto.test.js => Lotto.spec.ts} (75%) rename test/nodes/composite/{Parallel.test.js => Parallel.spec.ts} (71%) rename test/nodes/composite/{Selector.test.js => Selector.spec.ts} (67%) rename test/nodes/composite/{Sequence.test.js => Sequence.spec.ts} (71%) rename test/nodes/decorator/{Fail.test.js => Fail.spec.ts} (63%) rename test/nodes/decorator/{Flip.test.js => Flip.spec.ts} (67%) rename test/nodes/decorator/{Repeat.test.js => Repeat.spec.ts} (67%) rename test/nodes/decorator/{Retry.test.js => Retry.spec.ts} (67%) rename test/nodes/decorator/{Succeed.test.js => Succeed.spec.ts} (68%) rename test/nodes/leaf/{Action.test.js => Action.spec.ts} (61%) rename test/nodes/leaf/{Condition.test.js => Condition.spec.ts} (65%) rename test/nodes/leaf/{Wait.test.js => Wait.spec.ts} (68%) diff --git a/.vscode/launch.json b/.vscode/launch.json index 220954a..420caba 100644 --- a/.vscode/launch.json +++ b/.vscode/launch.json @@ -13,20 +13,20 @@ ], "program": "${workspaceFolder}\\dist\\index.js" }, { + "type": "node", + "request": "launch", + "name": "Mocha Tests", + "program": "${workspaceFolder}/node_modules/mocha/bin/_mocha", "args": [ + "-r", + "ts-node/register", "--timeout", "999999", "--colors", - "${workspaceFolder}/test/**/*.js" - ], - "internalConsoleOptions": "openOnSessionStart", - "name": "Mocha Tests", - "program": "${workspaceFolder}/node_modules/mocha/bin/_mocha", - "request": "launch", - "skipFiles": [ - "/**" + "${workspaceFolder}/test/**/*spec.ts", ], - "type": "node" - } + "console": "integratedTerminal", + "internalConsoleOptions": "neverOpen" + }, ] } \ No newline at end of file diff --git a/dist/Agent.d.ts b/dist/Agent.d.ts index bd0a3ac..aaa4112 100644 --- a/dist/Agent.d.ts +++ b/dist/Agent.d.ts @@ -10,6 +10,6 @@ export type ExitFunctionArg = { aborted: boolean; }; export type FunctionArg = number | string | boolean | null | ExitFunctionArg; -export type ActionResult = CompleteState | Promise | boolean; +export type ActionResult = CompleteState | Promise | boolean | void; export type AgentFunction = (this: Agent, ...args: FunctionArg[]) => ActionResult; export type GlobalFunction = (agent: Agent, ...args: FunctionArg[]) => ActionResult; diff --git a/dist/BehaviourTree.d.ts b/dist/BehaviourTree.d.ts index daae1a4..b54ab39 100644 --- a/dist/BehaviourTree.d.ts +++ b/dist/BehaviourTree.d.ts @@ -1,5 +1,4 @@ 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"; @@ -24,7 +23,7 @@ export declare class BehaviourTree { /** * The main root tree node. */ - readonly rootNode: Root; + private readonly _rootNode; /** * Creates a new instance of the BehaviourTree class. * @param definition The behaviour tree definition as either an MDSL string, root node definition object or array of root node definition objects. diff --git a/dist/bundle.js b/dist/bundle.js index 5faad33..3c7cb0c 100644 --- a/dist/bundle.js +++ b/dist/bundle.js @@ -2183,30 +2183,30 @@ var mistreevous = (() => { ); } try { - this.rootNode = buildRootNode(json); + this._rootNode = buildRootNode(json); } catch (exception) { throw new Error(`error building tree: ${exception.message}`); } } - rootNode; + _rootNode; isRunning() { - return this.rootNode.getState() === "mistreevous.running" /* RUNNING */; + return this._rootNode.getState() === "mistreevous.running" /* RUNNING */; } getState() { - return this.rootNode.getState(); + return this._rootNode.getState(); } step() { - if (this.rootNode.getState() === "mistreevous.succeeded" /* SUCCEEDED */ || this.rootNode.getState() === "mistreevous.failed" /* FAILED */) { - this.rootNode.reset(); + if (this._rootNode.getState() === "mistreevous.succeeded" /* SUCCEEDED */ || this._rootNode.getState() === "mistreevous.failed" /* FAILED */) { + this._rootNode.reset(); } try { - this.rootNode.update(this.agent, this.options); + this._rootNode.update(this.agent, this.options); } catch (exception) { throw new Error(`error stepping tree: ${exception.message}`); } } reset() { - this.rootNode.reset(); + this._rootNode.reset(); } getFlattenedNodeDetails() { const flattenedTreeNodes = []; @@ -2227,7 +2227,7 @@ var mistreevous = (() => { node.getChildren().forEach((child) => processNode(child, node.getUid())); } }; - processNode(this.rootNode, null); + processNode(this._rootNode, null); return flattenedTreeNodes; } static register(name, value) { diff --git a/dist/bundle.js.map b/dist/bundle.js.map index 49b5ee3..9fef22c 100644 --- a/dist/bundle.js.map +++ b/dist/bundle.js.map @@ -1,7 +1,7 @@ { "version": 3, "sources": ["../node_modules/lotto-draw/dist/Participant.js", "../node_modules/lotto-draw/dist/Utilities.js", "../node_modules/lotto-draw/dist/Lotto.js", "../node_modules/lotto-draw/dist/createLotto.js", "../node_modules/lotto-draw/dist/index.js", "../src/index.ts", "../src/State.ts", "../src/BehaviourTreeDefinitionUtilities.ts", "../src/mdsl/MDSLUtilities.ts", "../src/mdsl/MDSLNodeArgumentParser.ts", "../src/mdsl/MDSLNodeAttributeParser.ts", "../src/mdsl/MDSLDefinitionParser.ts", "../src/BehaviourTreeDefinitionValidator.ts", "../src/Lookup.ts", "../src/attributes/guards/GuardUnsatisifedException.ts", "../src/attributes/guards/GuardPath.ts", "../src/nodes/Node.ts", "../src/nodes/composite/Composite.ts", "../src/nodes/composite/Parallel.ts", "../src/nodes/composite/Selector.ts", "../src/nodes/composite/Sequence.ts", "../src/nodes/composite/Lotto.ts", "../src/nodes/decorator/Decorator.ts", "../src/nodes/decorator/Fail.ts", "../src/nodes/decorator/Flip.ts", "../src/nodes/decorator/Repeat.ts", "../src/nodes/decorator/Retry.ts", "../src/nodes/decorator/Root.ts", "../src/nodes/decorator/Succeed.ts", "../src/nodes/leaf/Leaf.ts", "../src/nodes/leaf/Action.ts", "../src/nodes/leaf/Condition.ts", "../src/nodes/leaf/Wait.ts", "../src/attributes/Attribute.ts", "../src/attributes/guards/Guard.ts", "../src/attributes/guards/While.ts", "../src/attributes/guards/Until.ts", "../src/attributes/callbacks/Callback.ts", "../src/attributes/callbacks/Entry.ts", "../src/attributes/callbacks/Step.ts", "../src/attributes/callbacks/Exit.ts", "../src/BehaviourTreeBuilder.ts", "../src/BehaviourTree.ts"], - "sourcesContent": ["\"use strict\";\r\nObject.defineProperty(exports, \"__esModule\", { value: true });\r\nexports.Participant = void 0;\r\n/**\r\n * A participant that holds a number of tickets.\r\n */\r\nvar Participant = /** @class */ (function () {\r\n /**\r\n * Creates an instance of the Participant class.\r\n * @param participant The actual participant.\r\n * @param tickets The number of tickets held by the participant.\r\n */\r\n function Participant(participant, tickets) {\r\n if (tickets === void 0) { tickets = 1; }\r\n this._participant = participant;\r\n this._tickets = tickets;\r\n }\r\n Object.defineProperty(Participant.prototype, \"participant\", {\r\n /** Gets the actual participant. */\r\n get: function () {\r\n return this._participant;\r\n },\r\n enumerable: false,\r\n configurable: true\r\n });\r\n Object.defineProperty(Participant.prototype, \"tickets\", {\r\n /** Gets or sets the number of tickets held by the participant. */\r\n get: function () {\r\n return this._tickets;\r\n },\r\n set: function (value) {\r\n this._tickets = value;\r\n },\r\n enumerable: false,\r\n configurable: true\r\n });\r\n return Participant;\r\n}());\r\nexports.Participant = Participant;\r\n", "\"use strict\";\r\nObject.defineProperty(exports, \"__esModule\", { value: true });\r\nexports.isNaturalNumber = exports.isNullOrUndefined = void 0;\r\n/**\r\n * Gets whether the value provided is null or undefined.\r\n * @param value The value to check.\r\n * @returns Whether the value provided is null or undefined.\r\n */\r\nfunction isNullOrUndefined(value) {\r\n return value === null || value === undefined;\r\n}\r\nexports.isNullOrUndefined = isNullOrUndefined;\r\n/**\r\n * Gets whether the value provided is a natural number.\r\n * @param value The value to check.\r\n * @returns Whether the value provided is a natural number.\r\n */\r\nfunction isNaturalNumber(value) {\r\n return typeof value === \"number\" && value >= 1 && Math.floor(value) === value;\r\n}\r\nexports.isNaturalNumber = isNaturalNumber;\r\n", "\"use strict\";\r\nObject.defineProperty(exports, \"__esModule\", { value: true });\r\nexports.Lotto = void 0;\r\nvar Participant_1 = require(\"./Participant\");\r\nvar Utilities_1 = require(\"./Utilities\");\r\n/**\r\n * Represents a lotto consisting of a number of pickable ticket-holding participants.\r\n */\r\nvar Lotto = /** @class */ (function () {\r\n /**\r\n * Creates a new instance of Lotto.\r\n * @param customRandom The custom RNG to use in place of Math.random().\r\n */\r\n function Lotto(customRandom) {\r\n /** The array of participants that are holding tickets in the lotto. */\r\n this._participants = [];\r\n this._customRandom = customRandom;\r\n }\r\n /**\r\n * Adds a participant with the specified number of tickets, or adds to the participant ticket count if the participant already holds tickets.\r\n * @param participant The participant to add or to increase the ticket count for if they already hold tickets.\r\n * @param tickets The number of tickets, defaults to 1.\r\n * @returns The Lotto instance.\r\n */\r\n Lotto.prototype.add = function (participant, tickets) {\r\n if (tickets === void 0) { tickets = 1; }\r\n // Check that we have a valid ticket count.\r\n if (!(0, Utilities_1.isNaturalNumber)(tickets)) {\r\n throw new Error(\"tickets value must be a natural number\");\r\n }\r\n // Check whether this participant has already been added.\r\n var existingParticipant = this._participants.find(function (part) { return part.participant === participant; });\r\n if (existingParticipant) {\r\n // The participant has already been added to the lotto so just add to their ticket count.\r\n existingParticipant.tickets += tickets;\r\n }\r\n else {\r\n // The participant is not part of the lotto so we should add them.\r\n this._participants.push(new Participant_1.Participant(participant, tickets));\r\n }\r\n return this;\r\n };\r\n /**\r\n * Removes the specified number of tickets for the given participant from the draw, or all tickets if a ticket number is not defined.\r\n * @param participant The participant to remove tickets for.\r\n * @param tickets The number of tickets to remove, or undefined if all tickets are to be removed.\r\n * @returns The Lotto instance.\r\n */\r\n Lotto.prototype.remove = function (participant, tickets) {\r\n // Attempt to get the existing participant.\r\n var existingParticipant = this._participants.find(function (part) { return part.participant === participant; });\r\n // There is nothing to do if the specified participant isn't even part of the lotto.\r\n if (!existingParticipant) {\r\n return this;\r\n }\r\n // Check whether a tickets value was given.\r\n if (tickets !== undefined) {\r\n // Check that we have a valid ticket count.\r\n if (!(0, Utilities_1.isNaturalNumber)(tickets)) {\r\n throw new Error(\"tickets value must be a natural number\");\r\n }\r\n existingParticipant.tickets -= tickets;\r\n // If the participant no longer holds any tickets then they should be removed.\r\n if (existingParticipant.tickets < 1) {\r\n this._participants = this._participants.filter(function (part) { return part !== existingParticipant; });\r\n }\r\n }\r\n else {\r\n // We are removing all tickets for the participant so just remove them from the lotto.\r\n this._participants = this._participants.filter(function (part) { return part !== existingParticipant; });\r\n }\r\n return this;\r\n };\r\n /**\r\n * Draw a winning ticket and return the participant that holds the ticket.\r\n * @param options The draw options.\r\n * @returns The participant that holds the winning ticket.\r\n */\r\n Lotto.prototype.draw = function (options) {\r\n if (options === void 0) { options = {}; }\r\n // If we have no participants then just return null.\r\n if (this._participants.length === 0) {\r\n return null;\r\n }\r\n var redrawable = (0, Utilities_1.isNullOrUndefined)(options.redrawable) ? true : options.redrawable;\r\n var pickable = [];\r\n this._participants.forEach(function (_a) {\r\n var participant = _a.participant, tickets = _a.tickets;\r\n for (var ticketCount = 0; ticketCount < tickets; ticketCount++) {\r\n pickable.push(participant);\r\n }\r\n });\r\n var random;\r\n // We need a random floating-point number between 0 (inclusive) and 1 to scale up to pick our winner.\r\n // If a custom random function exists then we should use that or fall back to Math.random().\r\n if (this._customRandom) {\r\n // Call our custom random function to get a random floating-point number.\r\n random = this._customRandom();\r\n // Verify that the result of calling our custom random function is a number between 0 (inclusive) and 1.\r\n if (typeof random !== \"number\" || random < 0 || random >= 1) {\r\n throw new Error(\"the 'random' function provided did not return a number between 0 (inclusive) and 1\");\r\n }\r\n }\r\n else {\r\n // No custom random function was defined so just use good ol' Math.random().\r\n random = Math.random();\r\n }\r\n // Pick a winning participant.\r\n var winner = pickable[Math.floor(random * pickable.length)];\r\n // If the ticket isn't redrawable then we should remove a ticket from the winning participants ticket count.\r\n if (!redrawable) {\r\n this.remove(winner, 1);\r\n }\r\n // Return the winning participant.\r\n return winner;\r\n };\r\n /**\r\n * Draws multiple winning tickets and return an array of the participants that hold the winning tickets.\r\n * @param tickets The number of winning tickets to draw.\r\n * @param options The draw multiple options.\r\n * @returns An array of the participants that hold the winning tickets.\r\n */\r\n Lotto.prototype.drawMultiple = function (tickets, options) {\r\n if (options === void 0) { options = {}; }\r\n var uniqueResults = (0, Utilities_1.isNullOrUndefined)(options.unique) ? false : options.unique;\r\n // Handle cases where the user has asked for zero tickets (no idea why they would do this be we should trust them).\r\n if (tickets === 0) {\r\n return [];\r\n }\r\n // Now that we know out tickets value is not zero we should check that it is a valid natural number.\r\n if (!(0, Utilities_1.isNaturalNumber)(tickets)) {\r\n throw new Error(\"tickets value must be a natural number\");\r\n }\r\n var result = [];\r\n // Keep drawing tickets until we either reach the number of required tickets or we simply run out of tickets to draw.\r\n // We can run out of tickets to draw if 'options.redrawable' is explicity 'false' or we just had no participants when 'drawMultiple' was called.\r\n while (result.length < tickets && this._participants.length > 0) {\r\n result.push(this.draw(options));\r\n }\r\n // If the 'unique' draw option is set then we need to remove duplicates from the result list.\r\n if (uniqueResults) {\r\n // Create an array to store our unique results.\r\n var unique = [];\r\n // Iterate over all of our participants (with potential duplicates) and populate our array of unique values.\r\n for (var _i = 0, result_1 = result; _i < result_1.length; _i++) {\r\n var participant = result_1[_i];\r\n if (unique.indexOf(participant) === -1) {\r\n unique.push(participant);\r\n }\r\n }\r\n result = unique;\r\n }\r\n return result;\r\n };\r\n return Lotto;\r\n}());\r\nexports.Lotto = Lotto;\r\n", "\"use strict\";\r\nObject.defineProperty(exports, \"__esModule\", { value: true });\r\nexports.createLotto = void 0;\r\nvar Lotto_1 = require(\"./Lotto\");\r\n/**\r\n * A function that creates and returns a Lotto instance.\r\n * @param participantsOrOptions An array of initial participants or options relating to the creation of a Lotto instance.\r\n * @returns A new Lotto instance.\r\n */\r\nfunction createLotto(participantsOrOptions) {\r\n // If no initial participants or lotto options were provided as an argument then we can just return a new lotto instance now.\r\n if (!participantsOrOptions) {\r\n return new Lotto_1.Lotto();\r\n }\r\n // Check whether we were provided with an array of initial participants or a lotto options object.\r\n if (Array.isArray(participantsOrOptions)) {\r\n // We are dealing with a pre-defined array of participants.\r\n var participants = participantsOrOptions;\r\n var lotto_1 = new Lotto_1.Lotto();\r\n // If the lotto participants have been defined upfront then we will need to add them all to our lotto instance now.\r\n participants.forEach(function (_a) {\r\n var participant = _a[0], tokens = _a[1];\r\n return lotto_1.add(participant, tokens);\r\n });\r\n // Return the Lotto instance.\r\n return lotto_1;\r\n }\r\n else {\r\n // We are dealing with some lotto options.\r\n var random = participantsOrOptions.random, participants = participantsOrOptions.participants;\r\n // Create a Lotto instance passing the custom RNG function to use in place of Math.random() (which could be undefined).\r\n var lotto_2 = new Lotto_1.Lotto(random);\r\n // If the lotto participants have been defined upfront as part of the options then we will need to add them all to our lotto instance now.\r\n if (participants) {\r\n participants.forEach(function (_a) {\r\n var participant = _a[0], tokens = _a[1];\r\n return lotto_2.add(participant, tokens);\r\n });\r\n }\r\n // Return the Lotto instance.\r\n return lotto_2;\r\n }\r\n}\r\nexports.createLotto = createLotto;\r\n", "\"use strict\";\r\nObject.defineProperty(exports, \"__esModule\", { value: true });\r\nvar createLotto_1 = require(\"./createLotto\");\r\nexports.default = createLotto_1.createLotto;\r\n", "import State from \"./State\";\nimport { validateDefinition } from \"./BehaviourTreeDefinitionValidator\";\nimport { convertMDSLToJSON } from \"./mdsl/MDSLDefinitionParser\";\nimport { BehaviourTree, FlattenedTreeNode } from \"./BehaviourTree\";\nimport { BehaviourTreeOptions } from \"./BehaviourTreeOptions\";\n\nexport { BehaviourTree, State, convertMDSLToJSON, validateDefinition };\nexport type { FlattenedTreeNode, BehaviourTreeOptions };\n", "/**\n * Enumeration of node state types.\n */\nexport enum State {\n READY = \"mistreevous.ready\",\n RUNNING = \"mistreevous.running\",\n SUCCEEDED = \"mistreevous.succeeded\",\n FAILED = \"mistreevous.failed\"\n}\n\nexport { State as default };\n\nexport type CompleteState = State.SUCCEEDED | State.FAILED;\nexport type AnyState = State.READY | State.RUNNING | CompleteState;\n", "import {\n NodeDefinition,\n RootNodeDefinition,\n DecoratorNodeDefinition,\n CompositeNodeDefinition,\n AnyNodeDefinition,\n BranchNodeDefinition\n} from \"./BehaviourTreeDefinition\";\n\n/**\n * A type guard function that returns true if the specified node satisfies the RootNodeDefinition type.\n * @param node The node.\n * @returns A value of true if the specified node satisfies the RootNodeDefinition type.\n */\nexport function isRootNode(node: NodeDefinition): node is RootNodeDefinition {\n return node.type === \"root\";\n}\n\n/**\n * A type guard function that returns true if the specified node satisfies the BranchNodeDefinition type.\n * @param node The node.\n * @returns A value of true if the specified node satisfies the BranchNodeDefinition type.\n */\nexport function isBranchNode(node: NodeDefinition): node is BranchNodeDefinition {\n return node.type === \"branch\";\n}\n\n/**\n * A type guard function that returns true if the specified node satisfies the NodeDefinition type.\n * @param node The node.\n * @returns A value of true if the specified node satisfies the NodeDefinition type.\n */\nexport function isLeafNode(node: NodeDefinition): node is NodeDefinition {\n return [\"branch\", \"action\", \"condition\", \"wait\"].includes(node.type);\n}\n\n/**\n * A type guard function that returns true if the specified node satisfies the DecoratorNodeDefinition type.\n * @param node The node.\n * @returns A value of true if the specified node satisfies the DecoratorNodeDefinition type.\n */\nexport function isDecoratorNode(node: NodeDefinition): node is DecoratorNodeDefinition {\n return [\"root\", \"repeat\", \"retry\", \"flip\", \"succeed\", \"fail\"].includes(node.type);\n}\n\n/**\n * A type guard function that returns true if the specified node satisfies the CompositeNodeDefinition type.\n * @param node The node.\n * @returns A value of true if the specified node satisfies the CompositeNodeDefinition type.\n */\nexport function isCompositeNode(node: NodeDefinition): node is CompositeNodeDefinition {\n return [\"sequence\", \"selector\", \"lotto\", \"parallel\"].includes(node.type);\n}\n\n/**\n * Flatten a node definition into an array of all of its nested node definitions.\n * @param nodeDefinition The node definition to flatten.\n * @returns An array of all of nested node definitions.\n */\nexport function flattenDefinition(nodeDefinition: AnyNodeDefinition): AnyNodeDefinition[] {\n const nodes: AnyNodeDefinition[] = [];\n\n const processNode = (currentNodeDefinition: AnyNodeDefinition) => {\n nodes.push(currentNodeDefinition);\n\n if (isCompositeNode(currentNodeDefinition)) {\n currentNodeDefinition.children.forEach(processNode);\n } else if (isDecoratorNode(currentNodeDefinition)) {\n processNode(currentNodeDefinition.child);\n }\n };\n\n processNode(nodeDefinition);\n\n return nodes;\n}\n\n/**\n * Determines whether the passed value is an integer.\n * @param value The value to check.\n * @returns Whether the passed value is an integer.\n */\nexport function isInteger(value: unknown): boolean {\n return typeof value === \"number\" && Math.floor(value) === value;\n}\n\n/**\n * Determines whether the passed value is null or undefined.\n * @param value The value to check.\n * @returns Whether the passed value is null or undefined.\n */\nexport function isNullOrUndefined(value: unknown): boolean {\n return typeof value === \"undefined\" || value === null;\n}\n", "/**\n * A type defining an object that holds a reference to substitued string literals parsed from the definition.\n */\nexport type StringLiteralPlaceholders = { [key: string]: string };\n\n/**\n * Pop the next raw token from the specified array of tokens and throw an error if it wasn't the expected one.\n * @param tokens The array of tokens.\n * @param expected An optional string or array or items, one of which must match the next popped token.\n * @returns The popped token.\n */\nexport function popAndCheck(tokens: string[], expected?: string | string[]): string {\n // Get and remove the next token.\n const popped = tokens.shift();\n\n // We were expecting another token but there aren't any.\n if (popped === undefined) {\n throw new Error(\"unexpected end of definition\");\n }\n\n // Do we have an expected token/tokens array?\n if (expected != undefined) {\n // Get an array of expected values, if the popped token matches any then we are all good.\n const expectedValues = typeof expected === \"string\" ? [expected] : expected;\n\n // Check whether the popped token matches at least one of our expected items.\n var tokenMatchesExpectation = expectedValues.some((item) => popped.toUpperCase() === item.toUpperCase());\n\n // Throw an error if the popped token didn't match any of our expected items.\n if (!tokenMatchesExpectation) {\n const expectationString = expectedValues.map((item) => \"'\" + item + \"'\").join(\" or \");\n throw new Error(\"unexpected token found. Expected \" + expectationString + \" but got '\" + popped + \"'\");\n }\n }\n\n // Return the popped token.\n return popped;\n}\n\n/**\n * Swaps out any node/attribute argument string literals with placeholders.\n * @param definition The definition.\n * @returns An object containing a mapping of placeholders to original string values as well as the processed definition string.\n */\nexport function substituteStringLiterals(definition: string): {\n placeholders: StringLiteralPlaceholders;\n processedDefinition: string;\n} {\n // Create an object to hold the mapping of placeholders to original string values.\n const placeholders: StringLiteralPlaceholders = {};\n\n // Replace any string literals wrapped with double quotes in our definition with placeholders to be processed later.\n const processedDefinition = definition.replace(/\\\"(\\\\.|[^\"\\\\])*\\\"/g, (match) => {\n var strippedMatch = match.substring(1, match.length - 1);\n var placeholder = Object.keys(placeholders).find((key) => placeholders[key] === strippedMatch);\n\n // If we have no existing string literal match then create a new placeholder.\n if (!placeholder) {\n placeholder = `@@${Object.keys(placeholders).length}@@`;\n placeholders[placeholder] = strippedMatch;\n }\n\n return placeholder;\n });\n\n return { placeholders, processedDefinition };\n}\n\n/**\n * Parse the tree definition into an array of raw tokens.\n * @param definition The definition.\n * @returns An array of tokens parsed from the definition.\n */\nexport function parseTokensFromDefinition(definition: string): string[] {\n // Add some space around various important characters so that they can be plucked out easier as individual tokens.\n definition = definition.replace(/\\(/g, \" ( \");\n definition = definition.replace(/\\)/g, \" ) \");\n definition = definition.replace(/\\{/g, \" { \");\n definition = definition.replace(/\\}/g, \" } \");\n definition = definition.replace(/\\]/g, \" ] \");\n definition = definition.replace(/\\[/g, \" [ \");\n definition = definition.replace(/\\,/g, \" , \");\n\n // Split the definition into raw token form and return it.\n return definition.replace(/\\s+/g, \" \").trim().split(\" \");\n}\n", "import { StringLiteralPlaceholders, popAndCheck } from \"./MDSLUtilities\";\n\n/**\n * A type representing any node function argument.\n */\ntype Argument = {\n /**\n * The argument value.\n */\n value: T;\n /**\n * The argument type, used for validation.\n */\n type: string;\n};\n\ntype NullArgument = Argument & {\n type: \"null\";\n};\n\ntype BooleanArgument = Argument & {\n type: \"boolean\";\n};\n\ntype NumberArgument = Argument & {\n type: \"number\";\n /**\n * A flag defining whether the number argument value is a valid integer. (used for validation)\n */\n isInteger: boolean;\n};\n\ntype StringPlaceholderArgument = Argument & {\n type: \"string\";\n};\n\ntype IdentifierArgument = Argument & {\n type: \"identifier\";\n};\n\n/**\n * A type representing a reference to any node function argument.\n */\ntype AnyArgument = NullArgument | BooleanArgument | NumberArgument | StringPlaceholderArgument | IdentifierArgument;\n\n/**\n * Parse an array of argument definitions from the specified tokens array.\n * @param tokens The array tokens to parse the argument definitions from.\n * @param stringArgumentPlaceholders The mapping of string literal node argument placeholders to original values.\n * @param argumentValidator The argument validator function.\n * @param validationFailedMessage The exception message to throw if argument validation fails.\n * @returns An array of argument definitions parsed from the specified tokens array.\n */\nexport function parseArgumentTokens(\n tokens: string[],\n stringArgumentPlaceholders: StringLiteralPlaceholders\n): AnyArgument[] {\n const argumentList: AnyArgument[] = [];\n\n // If the next token is not a '[' or '(' then we have no arguments to parse.\n if (![\"[\", \"(\"].includes(tokens[0])) {\n return argumentList;\n }\n\n // Any lists of arguments will always be wrapped in '[]' for node arguments or '()' for attribute arguments.\n // We are looking for a '[' or '(' opener that wraps the argument tokens and the relevant closer.\n const closingToken = popAndCheck(tokens, [\"[\", \"(\"]) === \"[\" ? \"]\" : \")\";\n\n const argumentListTokens: string[] = [];\n\n // Grab all tokens between the '[' and ']' or '(' and ')'.\n while (tokens.length && tokens[0] !== closingToken) {\n // The next token is part of our arguments list.\n argumentListTokens.push(tokens.shift()!);\n }\n\n // Validate the order of the argument tokens. Each token must either be a ',' or a single argument that satisfies the validator.\n argumentListTokens.forEach((token, index) => {\n // Get whether this token should be an actual argument.\n const shouldBeArgumentToken = !(index & 1);\n\n // If the current token should be an actual argument then validate it, otherwise it should be a ',' token.\n if (shouldBeArgumentToken) {\n // Get the argument definition.\n const argumentDefinition = getArgumentDefinition(token, stringArgumentPlaceholders);\n\n // This is a valid argument!\n argumentList.push(argumentDefinition);\n } else {\n // The current token should be a ',' token.\n if (token !== \",\") {\n throw new Error(`invalid argument list, expected ',' or ']' but got '${token}'`);\n }\n }\n });\n\n // The arguments list should terminate with a ']' or ')' token, depending on the opener.\n popAndCheck(tokens, closingToken);\n\n // Return the arguments.\n return argumentList;\n}\n\n/**\n * Gets an argument value definition.\n * @param token The argument token.\n * @param stringArgumentPlaceholders The mapping of string literal node argument placeholders to original values.\n * @returns An argument value definition.\n */\nfunction getArgumentDefinition(token: string, stringArgumentPlaceholders: StringLiteralPlaceholders): AnyArgument {\n // Check whether the token represents a null value.\n if (token === \"null\") {\n return {\n value: null,\n type: \"null\"\n } as NullArgument;\n }\n\n // Check whether the token represents a boolean value.\n if (token === \"true\" || token === \"false\") {\n return {\n value: token === \"true\",\n type: \"boolean\"\n } as BooleanArgument;\n }\n\n // Check whether the token represents a number value.\n // TODO: Relies on broken isNaN - see MDN.\n // if (!Number.isNaN(token)) {\n if (!isNaN(token as any)) {\n return {\n value: parseFloat(token),\n isInteger: parseFloat(token) === parseInt(token, 10),\n type: \"number\"\n } as NumberArgument;\n }\n\n // Check whether the token is a placeholder (e.g. @@0@@) representing a string literal.\n if (token.match(/^@@\\d+@@$/g)) {\n return {\n value: stringArgumentPlaceholders[token].replace('\\\\\"', '\"'),\n type: \"string\"\n } as StringPlaceholderArgument;\n }\n\n // The only remaining option is that the argument value is an identifier.\n return {\n value: token,\n type: \"identifier\"\n } as IdentifierArgument;\n}\n", "import { NodeAttributeDefinition } from \"../BehaviourTreeDefinition\";\nimport { parseArgumentTokens } from \"./MDSLNodeArgumentParser\";\nimport { StringLiteralPlaceholders } from \"./MDSLUtilities\";\n\n/**\n * A type defining the attribute definitions of a node.\n */\ntype NodeAttributes = {\n while?: NodeAttributeDefinition;\n until?: NodeAttributeDefinition;\n entry?: NodeAttributeDefinition;\n exit?: NodeAttributeDefinition;\n step?: NodeAttributeDefinition;\n};\n\n/**\n * Parse any node attribute definitions from the specified tokens array.\n * @param tokens The array of remaining tokens.\n * @param stringArgumentPlaceholders The mapping of string literal node argument placeholders to original values.\n * @returns An object of attribute definitions defined by any directly following tokens.\n */\nexport function parseAttributeTokens(\n tokens: string[],\n stringArgumentPlaceholders: StringLiteralPlaceholders\n): NodeAttributes {\n const nodeAttributeNames: (keyof NodeAttributes)[] = [\"while\", \"until\", \"entry\", \"exit\", \"step\"];\n\n // Create an object to hold any attributes found.\n const attributes: NodeAttributes = {};\n\n // Try to get the name of the attribute for the next token.\n let nextAttributeName = tokens[0]?.toLowerCase() as keyof NodeAttributes;\n\n // Pull attribute tokens as well as their arguments off of the tokens stack until we have no more.\n while (nodeAttributeNames.includes(nextAttributeName)) {\n // Check to make sure that we have not already created an attribute definition of this type.\n if (attributes[nextAttributeName]) {\n throw new Error(`duplicate attribute '${tokens[0].toUpperCase()}' found for node`);\n }\n\n // Remove the attribute name token from the array of tokens.\n tokens.shift();\n\n // Grab the attribute arguments, assuming the first to be an identifier.\n const [attributeCallIdentifier, ...attributeArguments] = parseArgumentTokens(\n tokens,\n stringArgumentPlaceholders\n );\n\n // The first attribute argument has to be an identifer, this will reference an agent function.\n if (attributeCallIdentifier?.type !== \"identifier\") {\n throw new Error(\"expected agent function name identifier argument for attribute\");\n }\n\n // Any attribute arguments (other than the expected call identifier) must have a type of string, number, boolean or null.\n attributeArguments\n .filter((arg) => arg.type === \"identifier\")\n .forEach((arg) => {\n throw new Error(\n `invalid attribute argument value '${arg.value}', must be string, number, boolean or null`\n );\n });\n\n // Create the attribute definition and add it to the object of attribute definitions found.\n attributes[nextAttributeName] = {\n call: attributeCallIdentifier.value,\n args: attributeArguments.map(({ value }) => value)\n };\n\n // Try to get the next attribute name token, as there could be multiple.\n nextAttributeName = tokens[0]?.toLowerCase() as keyof NodeAttributes;\n }\n\n return attributes;\n}\n", "import {\n ActionNodeDefinition,\n AnyChildNodeDefinition,\n AnyNodeDefinition,\n BranchNodeDefinition,\n ConditionNodeDefinition,\n FailNodeDefinition,\n FlipNodeDefinition,\n LottoNodeDefinition,\n ParallelNodeDefinition,\n RepeatNodeDefinition,\n RetryNodeDefinition,\n RootNodeDefinition,\n SelectorNodeDefinition,\n SequenceNodeDefinition,\n SucceedNodeDefinition,\n WaitNodeDefinition\n} from \"../BehaviourTreeDefinition\";\nimport {\n isCompositeNode,\n isDecoratorNode,\n isLeafNode,\n isNullOrUndefined,\n isRootNode\n} from \"../BehaviourTreeDefinitionUtilities\";\nimport { parseArgumentTokens } from \"./MDSLNodeArgumentParser\";\nimport { parseAttributeTokens } from \"./MDSLNodeAttributeParser\";\nimport {\n StringLiteralPlaceholders,\n parseTokensFromDefinition,\n popAndCheck,\n substituteStringLiterals\n} from \"./MDSLUtilities\";\n\n/**\n * Convert the MDSL tree definition string into an equivalent JSON definition.\n * @param definition The tree definition string as MDSL.\n * @returns The root node JSON definitions.\n */\nexport function convertMDSLToJSON(definition: string): RootNodeDefinition[] {\n // Swap out any node/attribute argument string literals with a placeholder and get a mapping of placeholders to original values as well as the processed definition.\n const { placeholders, processedDefinition } = substituteStringLiterals(definition);\n\n // Parse our definition definition string into an array of raw tokens.\n const tokens = parseTokensFromDefinition(processedDefinition);\n\n return convertTokensToJSONDefinition(tokens, placeholders);\n}\n\n/**\n * Converts the specified tree definition tokens into a JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The root node JSON definitions.\n */\nfunction convertTokensToJSONDefinition(\n tokens: string[],\n stringLiteralPlaceholders: StringLiteralPlaceholders\n): RootNodeDefinition[] {\n // There must be at least 3 tokens for the tree definition to be valid. 'ROOT', '{' and '}'.\n if (tokens.length < 3) {\n throw new Error(\"invalid token count\");\n }\n\n // We should have a matching number of '{' and '}' tokens. If not, then there are scopes that have not been properly closed.\n if (tokens.filter((token) => token === \"{\").length !== tokens.filter((token) => token === \"}\").length) {\n throw new Error(\"scope character mismatch\");\n }\n\n // Create an array of tree stack arrays where root nodes will always be at the botton and the current composite/decorator node at the top.\n // There should be an element in this array for every root node defined and every element should be an array with a root note as the first element.\n // E.g. A definition with two root nodes defined:\n // [\n // [root, lotto, sequence],\n // [root, selector]\n // ]\n const treeStacks: [Partial, ...Partial[]][] = [];\n\n // Create an array of all root node definitions that we create.\n const rootNodes: Partial[] = [];\n\n // A helper function used to push node definitions onto the tree stack.\n const pushNode = (node: AnyNodeDefinition) => {\n // If the node is a root node then we need to create a new tree stack array with the root node at the root.\n if (isRootNode(node)) {\n // We need to double-check that this root node is not the child of another node.\n // We can do this by checking whether the top tree stack is not empty (contains an existing node)\n if (treeStacks[treeStacks.length - 1]?.length) {\n throw new Error(\"a root node cannot be the child of another node\");\n }\n\n // Add the root node definition to our array of all parsed root node definitions.\n rootNodes.push(node);\n\n // Add the root node definition to the root of a new tree stack.\n treeStacks.push([node]);\n\n return;\n }\n\n // All non-root nodes should be pushed after their root nodes so handle cases\n // where we may not have any tree stacks or our top-most tree stack is empty.\n if (!treeStacks.length || !treeStacks[treeStacks.length - 1].length) {\n throw new Error(\"expected root node at base of definition\");\n }\n\n // Get the current tree stack that we are populating.\n const topTreeStack = treeStacks[treeStacks.length - 1];\n\n // Get the top-most node in the current tree stack, this will be a composite/decorator node\n // for which we will populate its children array if composite or setting its child if a decorator.\n const topTreeStackTopNode = topTreeStack[topTreeStack.length - 1] as AnyNodeDefinition;\n\n // If the top-most node in the current root stack is a composite or decorator\n // node then the current node should be added as a child of the top-most node.\n if (isCompositeNode(topTreeStackTopNode)) {\n topTreeStackTopNode.children = topTreeStackTopNode.children || [];\n topTreeStackTopNode.children.push(node);\n } else if (isDecoratorNode(topTreeStackTopNode)) {\n // If the top node already has a child node set then throw an error as a decorator should only have a single child.\n if (topTreeStackTopNode.child) {\n throw new Error(\"a decorator node must only have a single child node\");\n }\n\n topTreeStackTopNode.child = node;\n }\n\n // If the node we are adding is also a composite or decorator node, then we should push it\n // onto the current tree stack, as subsequent nodes will be added as its child/children.\n if (!isLeafNode(node)) {\n topTreeStack.push(node);\n }\n };\n\n // A helper function used to pop the top-most node definition off of the tree stack and return it.\n const popNode = (): AnyNodeDefinition | null => {\n let poppedNode: AnyNodeDefinition | null = null;\n\n // Get the current tree stack that we are populating.\n const topTreeStack = treeStacks[treeStacks.length - 1];\n\n // Pop the top-most node in the current tree stack if there is one.\n if (topTreeStack.length) {\n poppedNode = topTreeStack.pop() as AnyNodeDefinition;\n }\n\n // We don't want any empty tree stacks in our stack of tree stacks.\n if (!topTreeStack.length) {\n treeStacks.pop();\n }\n\n return poppedNode;\n };\n\n // We should keep processing the raw tokens until we run out of them.\n while (tokens.length) {\n // Grab the next token.\n const token = tokens.shift()!;\n\n // How we create the next node depends on the current raw token value.\n switch (token.toUpperCase()) {\n case \"ROOT\": {\n pushNode(createRootNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"SUCCEED\": {\n pushNode(createSucceedNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"FAIL\": {\n pushNode(createFailNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"FLIP\": {\n pushNode(createFlipNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"REPEAT\": {\n pushNode(createRepeatNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"RETRY\": {\n pushNode(createRetryNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"SEQUENCE\": {\n pushNode(createSequenceNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"SELECTOR\": {\n pushNode(createSelectorNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"PARALLEL\": {\n pushNode(createParallelNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"LOTTO\": {\n pushNode(createLottoNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"ACTION\": {\n pushNode(createActionNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"CONDITION\": {\n pushNode(createConditionNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"WAIT\": {\n pushNode(createWaitNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"BRANCH\": {\n pushNode(createBranchNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"}\": {\n // The '}' character closes the current scope and means that we have to pop a node off of the current stack.\n const poppedNode = popNode();\n\n // Now that we have a node definition we can carry out any validation that may require the node to be fully populated.\n if (poppedNode) {\n validatePoppedNode(poppedNode);\n }\n\n break;\n }\n\n default: {\n throw new Error(`unexpected token: ${token}`);\n }\n }\n }\n\n return rootNodes as RootNodeDefinition[];\n}\n\n/**\n * Creates a root node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The root node JSON definition.\n */\nfunction createRootNode(tokens: string[], stringLiteralPlaceholders: StringLiteralPlaceholders): RootNodeDefinition {\n // Create the root node definition.\n let node = {\n type: \"root\",\n id: undefined\n } as RootNodeDefinition;\n\n // Parse any node arguments, we should only have one if any which will be an identifier argument for the root identifier.\n const nodeArguments = parseArgumentTokens(tokens, stringLiteralPlaceholders);\n\n // Check whether any node arguments were defined.\n if (nodeArguments.length) {\n // We should only have one argument, if any, which will be an identifier argument for the root identifier.\n if (nodeArguments.length === 1 && nodeArguments[0].type === \"identifier\") {\n // The root node identifier will be the first and only node argument value.\n node.id = nodeArguments[0].value as string;\n } else {\n throw new Error(\"expected single root name argument\");\n }\n }\n\n // Grab any node attribute definitions and spread them into the node definition.\n node = { ...node, ...parseAttributeTokens(tokens, stringLiteralPlaceholders) };\n\n // This is a decorator node, so we expect an opening '{'.\n popAndCheck(tokens, \"{\");\n\n // Return the root node definition.\n return node;\n}\n\n/**\n * Creates a succeed node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The succeed node JSON definition.\n */\nfunction createSucceedNode(\n tokens: string[],\n stringLiteralPlaceholders: StringLiteralPlaceholders\n): SucceedNodeDefinition {\n const node = {\n type: \"succeed\",\n ...parseAttributeTokens(tokens, stringLiteralPlaceholders)\n } as SucceedNodeDefinition;\n\n // This is a decorator node, so we expect an opening '{'.\n popAndCheck(tokens, \"{\");\n\n // Return the succeed node definition.\n return node;\n}\n\n/**\n * Creates a fail node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The fail node JSON definition.\n */\nfunction createFailNode(tokens: string[], stringLiteralPlaceholders: StringLiteralPlaceholders): FailNodeDefinition {\n const node = {\n type: \"fail\",\n ...parseAttributeTokens(tokens, stringLiteralPlaceholders)\n } as FailNodeDefinition;\n\n // This is a decorator node, so we expect an opening '{'.\n popAndCheck(tokens, \"{\");\n\n // Return the fail node definition.\n return node;\n}\n\n/**\n * Creates a flip node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The flip node JSON definition.\n */\nfunction createFlipNode(tokens: string[], stringLiteralPlaceholders: StringLiteralPlaceholders): FlipNodeDefinition {\n const node = {\n type: \"flip\",\n ...parseAttributeTokens(tokens, stringLiteralPlaceholders)\n } as FlipNodeDefinition;\n\n // This is a decorator node, so we expect an opening '{'.\n popAndCheck(tokens, \"{\");\n\n // Return the flip node definition.\n return node;\n}\n\n/**\n * Creates a repeat node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The repeat node JSON definition.\n */\nfunction createRepeatNode(\n tokens: string[],\n stringLiteralPlaceholders: StringLiteralPlaceholders\n): RepeatNodeDefinition {\n let node = { type: \"repeat\" } as RepeatNodeDefinition;\n\n // Get the node arguments.\n const nodeArguments = parseArgumentTokens(tokens, stringLiteralPlaceholders);\n\n // The arguments of a repeat node are optional. We may have:\n // - No node arguments, in which case the repeat note will iterate indefinitely.\n // - One node argument which will be the explicit number of iterations to make.\n // - Two node arguments which define the min and max iteration bounds from which a random iteration count will be picked.\n if (nodeArguments.length) {\n // All repeat node arguments MUST be of type number and must be integer.\n nodeArguments\n .filter((arg) => arg.type !== \"number\" || !arg.isInteger)\n .forEach(() => {\n throw new Error(`repeat node iteration counts must be integer values`);\n });\n\n // We should have got one or two iteration counts.\n if (nodeArguments.length === 1) {\n // A static iteration count was defined.\n node.iterations = nodeArguments[0].value as number;\n\n // A repeat node must have a positive number of iterations if defined.\n if (node.iterations < 0) {\n throw new Error(\"a repeat node must have a positive number of iterations if defined\");\n }\n } else if (nodeArguments.length === 2) {\n // A minimum and maximum iteration count was defined.\n node.iterations = [nodeArguments[0].value as number, nodeArguments[1].value as number];\n\n // A repeat node must have a positive min and max iteration count if they are defined.\n if (node.iterations[0] < 0 || node.iterations[1] < 0) {\n throw new Error(\"a repeat node must have a positive minimum and maximum iteration count if defined\");\n }\n\n // A repeat node must not have an minimum iteration count that exceeds the maximum iteration count.\n if (node.iterations[0] > node.iterations[1]) {\n throw new Error(\n \"a repeat node must not have a minimum iteration count that exceeds the maximum iteration count\"\n );\n }\n } else {\n // An incorrect number of iteration counts was defined.\n throw new Error(\"invalid number of repeat node iteration count arguments defined\");\n }\n }\n\n // Grab any node attribute definitions and spread them into the node definition.\n node = { ...node, ...parseAttributeTokens(tokens, stringLiteralPlaceholders) };\n\n // This is a decorator node, so we expect an opening '{'.\n popAndCheck(tokens, \"{\");\n\n // Return the repeat node definition.\n return node;\n}\n\n/**\n * Creates a retry node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The retry node JSON definition.\n */\nfunction createRetryNode(tokens: string[], stringLiteralPlaceholders: StringLiteralPlaceholders): RetryNodeDefinition {\n let node = { type: \"retry\" } as RetryNodeDefinition;\n\n // Get the node arguments.\n const nodeArguments = parseArgumentTokens(tokens, stringLiteralPlaceholders);\n\n // The arguments of a retry node are optional. We may have:\n // - No node arguments, in which case the retry note will attempt indefinitely.\n // - One node argument which will be the explicit number of attempts to make.\n // - Two node arguments which define the min and max attempt bounds from which a random attempt count will be picked.\n if (nodeArguments.length) {\n // All retry node arguments MUST be of type number and must be integer.\n nodeArguments\n .filter((arg) => arg.type !== \"number\" || !arg.isInteger)\n .forEach(() => {\n throw new Error(`retry node attempt counts must be integer values`);\n });\n\n // We should have got one or two attempt counts.\n if (nodeArguments.length === 1) {\n // A static attempt count was defined.\n node.attempts = nodeArguments[0].value as number;\n\n // A retry node must have a positive number of attempts if defined.\n if (node.attempts < 0) {\n throw new Error(\"a retry node must have a positive number of attempts if defined\");\n }\n } else if (nodeArguments.length === 2) {\n // A minimum and maximum attempt count was defined.\n node.attempts = [nodeArguments[0].value as number, nodeArguments[1].value as number];\n\n // A retry node must have a positive min and max attempts count if they are defined.\n if (node.attempts[0] < 0 || node.attempts[1] < 0) {\n throw new Error(\"a retry node must have a positive minimum and maximum attempt count if defined\");\n }\n\n // A retry node must not have a minimum attempt count that exceeds the maximum attempt count.\n if (node.attempts[0] > node.attempts[1]) {\n throw new Error(\n \"a retry node must not have a minimum attempt count that exceeds the maximum attempt count\"\n );\n }\n } else {\n // An incorrect number of attempt counts was defined.\n throw new Error(\"invalid number of retry node attempt count arguments defined\");\n }\n }\n\n // Grab any node attribute definitions and spread them into the node definition.\n node = { ...node, ...parseAttributeTokens(tokens, stringLiteralPlaceholders) };\n\n // This is a decorator node, so we expect an opening '{'.\n popAndCheck(tokens, \"{\");\n\n // Return the retry node definition.\n return node;\n}\n\n/**\n * Creates a sequence node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The sequence node JSON definition.\n */\nfunction createSequenceNode(\n tokens: string[],\n stringLiteralPlaceholders: StringLiteralPlaceholders\n): SequenceNodeDefinition {\n const node = {\n type: \"sequence\",\n ...parseAttributeTokens(tokens, stringLiteralPlaceholders)\n } as SequenceNodeDefinition;\n\n // This is a composite node, so we expect an opening '{'.\n popAndCheck(tokens, \"{\");\n\n // Return the sequence node definition.\n return node;\n}\n\n/**\n * Creates a selector node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The selector node JSON definition.\n */\nfunction createSelectorNode(\n tokens: string[],\n stringLiteralPlaceholders: StringLiteralPlaceholders\n): SelectorNodeDefinition {\n const node = {\n type: \"selector\",\n ...parseAttributeTokens(tokens, stringLiteralPlaceholders)\n } as SelectorNodeDefinition;\n\n // This is a composite node, so we expect an opening '{'.\n popAndCheck(tokens, \"{\");\n\n // Return the selector node definition.\n return node;\n}\n\n/**\n * Creates a parallel node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The parallel node JSON definition.\n */\nfunction createParallelNode(\n tokens: string[],\n stringLiteralPlaceholders: StringLiteralPlaceholders\n): ParallelNodeDefinition {\n const node = {\n type: \"parallel\",\n ...parseAttributeTokens(tokens, stringLiteralPlaceholders)\n } as ParallelNodeDefinition;\n\n // This is a composite node, so we expect an opening '{'.\n popAndCheck(tokens, \"{\");\n\n // Return the parallel node definition.\n return node;\n}\n\n/**\n * Creates a lotto node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The lotto node JSON definition.\n */\nfunction createLottoNode(tokens: string[], stringLiteralPlaceholders: StringLiteralPlaceholders): LottoNodeDefinition {\n // If any node arguments have been defined then they must be our weights.\n const nodeArguments = parseArgumentTokens(tokens, stringLiteralPlaceholders);\n\n // All lotto node arguments MUST be of type number and must be positive integers.\n nodeArguments\n .filter((arg) => arg.type !== \"number\" || !arg.isInteger || arg.value < 0)\n .forEach(() => {\n throw new Error(`lotto node weight arguments must be positive integer values`);\n });\n\n const node = {\n type: \"lotto\",\n weights: nodeArguments.length ? nodeArguments.map(({ value }) => value) : undefined,\n ...parseAttributeTokens(tokens, stringLiteralPlaceholders)\n } as LottoNodeDefinition;\n\n // This is a composite node, so we expect an opening '{'.\n popAndCheck(tokens, \"{\");\n\n // Return the lotto node definition.\n return node;\n}\n\n/**\n * Creates an action node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The action node JSON definition.\n */\nfunction createActionNode(\n tokens: string[],\n stringLiteralPlaceholders: StringLiteralPlaceholders\n): ActionNodeDefinition {\n // Parse any node arguments, we should have at least one which will be an identifier argument for the action name\n // and agent function to invoke for the action, all other arguments are to be passed as arguments to that function.\n const [actionNameIdentifier, ...agentFunctionArgs] = parseArgumentTokens(tokens, stringLiteralPlaceholders);\n\n // Our first argument MUST be defined and be an identifier as we require an action name argument.\n if (actionNameIdentifier?.type !== \"identifier\") {\n throw new Error(\"expected action name identifier argument\");\n }\n\n // Only the first argument should have been an identifier, all agent function arguments must be string, number, boolean or null.\n agentFunctionArgs\n .filter((arg) => arg.type === \"identifier\")\n .forEach((arg) => {\n throw new Error(\n `invalid action node argument value '${arg.value}', must be string, number, boolean or null`\n );\n });\n\n // Return the action node definition.\n return {\n type: \"action\",\n call: actionNameIdentifier.value,\n args: agentFunctionArgs.map(({ value }) => value),\n ...parseAttributeTokens(tokens, stringLiteralPlaceholders)\n };\n}\n\n/**\n * Creates a condition node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The condition node JSON definition.\n */\nfunction createConditionNode(\n tokens: string[],\n stringLiteralPlaceholders: StringLiteralPlaceholders\n): ConditionNodeDefinition {\n // Parse any node arguments, we should have at least one which will be an identifier argument for the condition name\n // and agent function to invoke for the condition, all other arguments are to be passed as arguments to that function.\n const [conditionNameIdentifier, ...agentFunctionArgs] = parseArgumentTokens(tokens, stringLiteralPlaceholders);\n\n // Our first argument MUST be defined and be an identifier as we require a condition name argument.\n if (conditionNameIdentifier?.type !== \"identifier\") {\n throw new Error(\"expected condition name identifier argument\");\n }\n\n // Only the first argument should have been an identifier, all agent function arguments must be string, number, boolean or null.\n agentFunctionArgs\n .filter((arg) => arg.type === \"identifier\")\n .forEach((arg) => {\n throw new Error(\n `invalid condition node argument value '${arg.value}', must be string, number, boolean or null`\n );\n });\n\n // Return the condition node definition.\n return {\n type: \"condition\",\n call: conditionNameIdentifier.value,\n args: agentFunctionArgs.map(({ value }) => value),\n ...parseAttributeTokens(tokens, stringLiteralPlaceholders)\n };\n}\n\n/**\n * Creates a wait node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The wait node JSON definition.\n */\nfunction createWaitNode(tokens: string[], stringLiteralPlaceholders: StringLiteralPlaceholders): WaitNodeDefinition {\n let node = { type: \"wait\" } as WaitNodeDefinition;\n\n // Get the node arguments.\n const nodeArguments = parseArgumentTokens(tokens, stringLiteralPlaceholders);\n\n // The arguments of a wait node are optional. We may have:\n // - No node arguments, in which case the wait will be indefinite until it is aborted.\n // - One node argument which will be the explicit duration of the wait.\n // - Two node arguments which define the min and max duration bounds from which a random duration will be picked.\n if (nodeArguments.length) {\n // All wait node arguments MUST be of type number and must be integer.\n nodeArguments\n .filter((arg) => arg.type !== \"number\" || !arg.isInteger)\n .forEach(() => {\n throw new Error(`wait node durations must be integer values`);\n });\n\n // We may have:\n // - One node argument which will be the explicit duration of the wait.\n // - Two node arguments which define the min and max duration bounds from which a random duration will be picked.\n // - Too many arguments, which is not valid.\n if (nodeArguments.length === 1) {\n // An explicit duration was defined.\n node.duration = nodeArguments[0].value as number;\n\n // If an explict duration was defined then it must be a positive number.\n if (node.duration < 0) {\n throw new Error(\"a wait node must have a positive duration\");\n }\n } else if (nodeArguments.length === 2) {\n // Min and max duration bounds were defined from which a random duration will be picked.\n node.duration = [nodeArguments[0].value as number, nodeArguments[1].value as number];\n\n // A wait node must have a positive min and max duration.\n if (node.duration[0] < 0 || node.duration[1] < 0) {\n throw new Error(\"a wait node must have a positive minimum and maximum duration\");\n }\n\n // A wait node must not have a minimum duration that exceeds the maximum duration.\n if (node.duration[0] > node.duration[1]) {\n throw new Error(\"a wait node must not have a minimum duration that exceeds the maximum duration\");\n }\n } else if (nodeArguments.length > 2) {\n // An incorrect number of duration arguments were defined.\n throw new Error(\"invalid number of wait node duration arguments defined\");\n }\n }\n\n // Return the wait node definition.\n return { ...node, ...parseAttributeTokens(tokens, stringLiteralPlaceholders) };\n}\n\n/**\n * Creates a branch node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The branch node JSON definition.\n */\nfunction createBranchNode(\n tokens: string[],\n stringLiteralPlaceholders: StringLiteralPlaceholders\n): BranchNodeDefinition {\n // Parse any node arguments, we should have one which will be an identifier argument for the root ref.\n const nodeArguments = parseArgumentTokens(tokens, stringLiteralPlaceholders);\n\n // We should have only a single identifer argument for a branch node, which is the root ref.\n if (nodeArguments.length !== 1 || nodeArguments[0].type !== \"identifier\") {\n throw new Error(\"expected single branch name argument\");\n }\n\n // Return the branch node definition.\n return { type: \"branch\", ref: nodeArguments[0].value };\n}\n\n/**\n * Validate a fully-populated node definition that was popped off of the tree stack.\n * @param definition The popped node to validate.\n */\nfunction validatePoppedNode(definition: AnyNodeDefinition): void {\n // Decorators MUST have a child defined.\n if (isDecoratorNode(definition) && isNullOrUndefined(definition.child)) {\n throw new Error(`a ${definition.type} node must have a single child node defined`);\n }\n\n // Composites MUST have at least one child defined.\n if (isCompositeNode(definition) && !definition.children?.length) {\n throw new Error(`a ${definition.type} node must have at least a single child node defined`);\n }\n\n // We need to make sure that lotto nodes that have weights defined have a number of weights matching the number of child nodes.\n if (definition.type === \"lotto\") {\n // Check whether a 'weights' property has been defined, if it has we expect it to be an array of weights.\n if (typeof definition.weights !== \"undefined\") {\n // Check that the weights property is an array of positive integers with an element for each child node element.\n if (definition.weights.length !== definition.children.length) {\n throw new Error(\n \"expected a number of weight arguments matching the number of child nodes for lotto node\"\n );\n }\n }\n }\n}\n", "import { RootNodeDefinition } from \"./BehaviourTreeDefinition\";\nimport { flattenDefinition, isBranchNode, isInteger } from \"./BehaviourTreeDefinitionUtilities\";\nimport { convertMDSLToJSON } from \"./mdsl/MDSLDefinitionParser\";\n\n/**\n * An object representing the result of validating a tree definition.\n */\nexport type DefinitionValidationResult = {\n /**\n * A flag defining whether validation succeeded.\n */\n succeeded: boolean;\n /**\n * A string containing the error message if validation did not succeed.\n */\n errorMessage?: string;\n /**\n * The definition as json if the validation was successful, or undefined if validation did not succeed.\n */\n json?: RootNodeDefinition[];\n};\n\n/**\n * Validates the specified behaviour tree definition in the form of JSON or MDSL, not taking any globally registered subtrees into consideration.\n * @param definition The behaviour tree definition in the form of JSON or MDSL.\n * @returns An object representing the result of validating the given tree definition.\n */\nexport function validateDefinition(definition: any): DefinitionValidationResult {\n // The definition must be defined.\n if (definition === null || typeof definition === \"undefined\") {\n return createValidationFailureResult(\"definition is null or undefined\");\n }\n\n // We are expecting a definition in one of three different forms:\n // - A string which we will assume is MDSL and we will parse this to JSON before validation.\n // - An array which we will assume is an array of root node definitions with at least one being the primary root node (no 'id' property)\n // - An object which we will assume is the primary root node and should not have an 'id' property.\n if (typeof definition === \"string\") {\n // The definition is a string which we can assume is MDSL, so attempt to validate it.\n return validateMDSLDefinition(definition);\n } else if (typeof definition === \"object\") {\n // The definition will either be an array (of root node definitions) or an object (the single primary root node definition).\n return validateJSONDefinition(definition);\n } else {\n return createValidationFailureResult(`unexpected definition type of '${typeof definition}'`);\n }\n}\n\n/**\n * Validates the specified behaviour tree definition in the form of MDSL.\n * @param definition The behaviour tree definition in the form of MDSL.\n * @returns An object representing the result of validating the given tree definition.\n */\nfunction validateMDSLDefinition(definition: string): DefinitionValidationResult {\n let rootNodeDefinitions;\n\n // The first thing the we need to do is to attempt to convert our MDSL into JSON.\n try {\n // The definition is a string which we can assume is MDSL, so attempt to parse it to a JSON definition in the form of an array of root node definitions.\n rootNodeDefinitions = convertMDSLToJSON(definition);\n } catch (exception) {\n // We failed to parse the JSON from the MDSL, this is likely to be the result of it not being a valid MDSL string.\n return createValidationFailureResult((exception as Error).message);\n }\n\n // Unpack all of the root node definitions into arrays of main ('id' defined) and sub ('id' not defined) root node definitions.\n const mainRootNodeDefinitions = rootNodeDefinitions.filter(({ id }) => typeof id === \"undefined\");\n const subRootNodeDefinitions = rootNodeDefinitions.filter(({ id }) => typeof id === \"string\" && id.length > 0);\n\n // We should ALWAYS have exactly one root node definition without an 'id' property defined, which is out main root node definition.\n if (mainRootNodeDefinitions.length !== 1) {\n return createValidationFailureResult(\n \"expected single unnamed root node at base of definition to act as main root\"\n );\n }\n\n // We should never have duplicate 'id' properties across our sub root node definitions.\n const subRootNodeIdenitifers: string[] = [];\n for (const { id } of subRootNodeDefinitions) {\n // Have we already come across this 'id' property value?\n if (subRootNodeIdenitifers.includes(id!)) {\n return createValidationFailureResult(`multiple root nodes found with duplicate name '${id}'`);\n }\n\n subRootNodeIdenitifers.push(id!);\n }\n\n try {\n // Validate our branch -> subtree links and check for any circular dependencies, we don't care about checking for broken subtree links here.\n validateBranchSubtreeLinks(rootNodeDefinitions, false);\n } catch (exception) {\n return createValidationFailureResult((exception as Error).message);\n }\n\n // Our definition was valid!\n return {\n succeeded: true,\n json: rootNodeDefinitions\n };\n}\n\n/**\n * Validates the specified behaviour tree definition in the form of JSON.\n * @param definition The behaviour tree definition in the form of JSON.\n * @returns An object representing the result of validating the given tree definition.\n */\nexport function validateJSONDefinition(\n definition: RootNodeDefinition | RootNodeDefinition[]\n): DefinitionValidationResult {\n // The definition will either be an array (of root node definitions) or an object (the single primary root node definition).\n const rootNodeDefinitions = Array.isArray(definition) ? definition : [definition];\n\n // Iterate over our array of root nodes and call validateNode for each, passing an initial depth of 0, wrapped in a try catch to handle validation failures.\n try {\n rootNodeDefinitions.forEach((rootNodeDefinition) => validateNode(rootNodeDefinition, 0));\n } catch (error) {\n // Handle cases where we have caught a thrown Error and return a failure result with the error message.\n if (error instanceof Error) {\n return createValidationFailureResult(error.message);\n }\n\n // No idea what happened here!\n return createValidationFailureResult(`unexpected error: ${error}`);\n }\n\n // Unpack all of the root node definitions into arrays of main ('id' defined) and sub ('id' not defined) root node definitions.\n const mainRootNodeDefinitions = rootNodeDefinitions.filter(({ id }) => typeof id === \"undefined\");\n const subRootNodeDefinitions = rootNodeDefinitions.filter(({ id }) => typeof id === \"string\" && id.length > 0);\n\n // We should ALWAYS have exactly one root node definition without an 'id' property defined, which is out main root node definition.\n if (mainRootNodeDefinitions.length !== 1) {\n return createValidationFailureResult(\n \"expected single root node without 'id' property defined to act as main root\"\n );\n }\n\n // We should never have duplicate 'id' properties across our sub root node definitions.\n const subRootNodeIdenitifers: string[] = [];\n for (const { id } of subRootNodeDefinitions) {\n // Have we already come across this 'id' property value?\n if (subRootNodeIdenitifers.includes(id!)) {\n return createValidationFailureResult(\n `multiple root nodes found with duplicate 'id' property value of '${id}'`\n );\n }\n\n subRootNodeIdenitifers.push(id!);\n }\n\n try {\n // Validate our branch -> subtree links and check for any circular dependencies, we don't care about checking for broken subtree links here.\n validateBranchSubtreeLinks(rootNodeDefinitions, false);\n } catch (exception) {\n return createValidationFailureResult((exception as Error).message);\n }\n\n // Our definition was valid!\n return {\n succeeded: true,\n json: rootNodeDefinitions\n };\n}\n\n/**\n * Validates the branch -> subtree links across all provided root node definitions.\n * This will not consider branch nodes that reference any globally registered subtrees unless includesGlobalSubtrees\n * is set to true, in which case we will also verify that there are no broken branch -> subtree links.\n * @param rootNodeDefinitions The array of root node definitions.\n * @param includesGlobalSubtrees A flag defining whether the array includes all global subtree root node definitions.\n */\nexport function validateBranchSubtreeLinks(rootNodeDefinitions: RootNodeDefinition[], includesGlobalSubtrees: boolean) {\n // Create a mapping of root node identifiers to other root nodes that they reference via branch nodes.\n // Below is an example of a mapping that includes a circular dependency (root => a => b => c => a)\n // [{ refs: [\"a\", \"b\"] }, { id: \"a\", refs: [\"b\"] }, { id: \"b\", refs: [\"c\"] }, { id: \"c\", refs: [\"a\"] }]\n const rootNodeMappings: { id: string | undefined; refs: string[] }[] = rootNodeDefinitions.map(\n (rootNodeDefinition) => ({\n id: rootNodeDefinition.id,\n refs: flattenDefinition(rootNodeDefinition)\n .filter(isBranchNode)\n .map(({ ref }) => ref)\n })\n );\n\n // A recursive function to walk through the mappings, keeping track of which root nodes we have visited in the form of a path of root node identifiers.\n const followRefs = (mapping: { id: string | undefined; refs: string[] }, path: (string | undefined)[] = []) => {\n // Have we found a circular dependency?\n if (path.includes(mapping.id)) {\n // We found a circular dependency! Get the bad path of root node identifiers.\n const badPath = [...path, mapping.id];\n\n // Create the formatted path value. [undefined, \"a\", \"b\", \"c\", \"a\"] would be formatted as \"a -> b -> c -> a\".\n const badPathFormatted = badPath.filter((element) => !!element).join(\" => \");\n\n // No need to continue, we found a circular dependency.\n throw new Error(`circular dependency found in branch node references: ${badPathFormatted}`);\n }\n\n for (const ref of mapping.refs) {\n // Find the mapping for the root node with an identifer matching the current ref.\n const subMapping = rootNodeMappings.find(({ id }) => id === ref);\n\n // We may not have a mapping for this ref, which is normal when we aren't considering all globally registered subtrees.\n if (subMapping) {\n followRefs(subMapping, [...path, mapping.id]);\n } else if (includesGlobalSubtrees) {\n // We found a reference to a root node that doesn't exist, which is a problem seeing as the root node definitons includes all globally registered subtrees.\n throw new Error(\n mapping.id\n ? `subtree '${mapping.id}' has branch node that references root node '${ref}' which has not been defined`\n : `primary tree has branch node that references root node '${ref}' which has not been defined`\n );\n }\n }\n };\n\n // Start looking for circular dependencies and broken references from the primary root node definition.\n followRefs(rootNodeMappings.find((mapping) => typeof mapping.id === \"undefined\")!);\n}\n\n/**\n * Validate an object that we expect to be a node definition.\n * @param definition An object that we expect to be a node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateNode(definition: any, depth: number): void {\n // Every node must be valid object and have a non-empty 'type' string property.\n if (typeof definition !== \"object\" || typeof definition.type !== \"string\" || definition.type.length === 0) {\n throw new Error(\n `node definition is not an object or 'type' property is not a non-empty string at depth '${depth}'`\n );\n }\n\n // How we validate this node definition will depend on its type.\n switch (definition.type) {\n case \"action\":\n validateActionNode(definition, depth);\n break;\n\n case \"condition\":\n validateConditionNode(definition, depth);\n break;\n\n case \"wait\":\n validateWaitNode(definition, depth);\n break;\n\n case \"branch\":\n validateBranchNode(definition, depth);\n break;\n\n case \"root\":\n validateRootNode(definition, depth);\n break;\n\n case \"succeed\":\n validateSucceedNode(definition, depth);\n break;\n\n case \"fail\":\n validateFailNode(definition, depth);\n break;\n\n case \"flip\":\n validateFlipNode(definition, depth);\n break;\n\n case \"repeat\":\n validateRepeatNode(definition, depth);\n break;\n\n case \"retry\":\n validateRetryNode(definition, depth);\n break;\n\n case \"sequence\":\n validateSequenceNode(definition, depth);\n break;\n\n case \"selector\":\n validateSelectorNode(definition, depth);\n break;\n\n case \"parallel\":\n validateParallelNode(definition, depth);\n break;\n\n case \"lotto\":\n validateLottoNode(definition, depth);\n break;\n\n default:\n throw new Error(`unexpected node type of '${definition.type}' at depth '${depth}'`);\n }\n}\n\n/**\n * Validate any attributes for a given node definition.\n * @param definition The node definition.\n * @param depth The depth of the node in the behaviour tree definition.\n */\nfunction validateNodeAttributes(definition: any, depth: number): void {\n // Validate each of the attribute types for this node.\n [\"while\", \"until\", \"entry\", \"exit\", \"step\"].forEach((attributeName) => {\n // Attempt to grab the definition for the current attribute from the node definition.\n const attributeDefinition = definition[attributeName];\n\n // All node attributes are optional, so there is nothing to do if the current attribute is not defined.\n if (typeof attributeDefinition === \"undefined\") {\n return;\n }\n\n // The attribute definition must be an object.\n if (typeof attributeDefinition !== \"object\") {\n throw new Error(\n `expected attribute '${attributeName}' to be an object for '${definition.type}' node at depth '${depth}'`\n );\n }\n\n // The 'call' property must be defined for any attribute definition.\n if (typeof attributeDefinition.call !== \"string\" || attributeDefinition.call.length === 0) {\n throw new Error(\n `expected 'call' property for attribute '${attributeName}' to be a non-empty string for '${definition.type}' node at depth '${depth}'`\n );\n }\n\n // If any node attribute arguments have been defined then they must have been defined in an array.\n if (typeof attributeDefinition.args !== \"undefined\" && !Array.isArray(attributeDefinition.args)) {\n throw new Error(\n `expected 'args' property for attribute '${attributeName}' to be an array for '${definition.type}' node at depth '${depth}'`\n );\n }\n });\n}\n\n/**\n * Validate an object that we expect to be a root node definition.\n * @param definition An object that we expect to be a root node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateRootNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"root\") {\n throw new Error(\"expected node type of 'root' for root node\");\n }\n\n // A root node cannot be the child of another node.\n if (depth > 0) {\n throw new Error(\"a root node cannot be the child of another node\");\n }\n\n // Check that, if the root node 'id' property is defined, it is a non-empty string.\n if (typeof definition.id !== \"undefined\" && (typeof definition.id !== \"string\" || definition.id.length === 0)) {\n throw new Error(\"expected non-empty string for 'id' property if defined for root node\");\n }\n\n // A root node is a decorator node, so must have a child node defined.\n if (typeof definition.child === \"undefined\") {\n throw new Error(\"expected property 'child' to be defined for root node\");\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n\n // Validate the child node of this decorator node.\n validateNode(definition.child, depth + 1);\n}\n\n/**\n * Validate an object that we expect to be a succeed node definition.\n * @param definition An object that we expect to be a succeed node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateSucceedNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"succeed\") {\n throw new Error(`expected node type of 'succeed' for succeed node at depth '${depth}'`);\n }\n\n // A succeed node is a decorator node, so must have a child node defined.\n if (typeof definition.child === \"undefined\") {\n throw new Error(`expected property 'child' to be defined for succeed node at depth '${depth}'`);\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n\n // Validate the child node of this decorator node.\n validateNode(definition.child, depth + 1);\n}\n\n/**\n * Validate an object that we expect to be a fail node definition.\n * @param definition An object that we expect to be a fail node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateFailNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"fail\") {\n throw new Error(`expected node type of 'fail' for fail node at depth '${depth}'`);\n }\n\n // A fail node is a decorator node, so must have a child node defined.\n if (typeof definition.child === \"undefined\") {\n throw new Error(`expected property 'child' to be defined for fail node at depth '${depth}'`);\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n\n // Validate the child node of this decorator node.\n validateNode(definition.child, depth + 1);\n}\n\n/**\n * Validate an object that we expect to be a flip node definition.\n * @param definition An object that we expect to be a flip node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateFlipNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"flip\") {\n throw new Error(`expected node type of 'flip' for flip node at depth '${depth}'`);\n }\n\n // A flip node is a decorator node, so must have a child node defined.\n if (typeof definition.child === \"undefined\") {\n throw new Error(`expected property 'child' to be defined for flip node at depth '${depth}'`);\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n\n // Validate the child node of this decorator node.\n validateNode(definition.child, depth + 1);\n}\n\n/**\n * Validate an object that we expect to be a repeat node definition.\n * @param definition An object that we expect to be a repeat node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateRepeatNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"repeat\") {\n throw new Error(`expected node type of 'repeat' for repeat node at depth '${depth}'`);\n }\n\n // A repeat node is a decorator node, so must have a child node defined.\n if (typeof definition.child === \"undefined\") {\n throw new Error(`expected property 'child' to be defined for repeat node at depth '${depth}'`);\n }\n\n // Check whether an 'iterations' property has been defined, it may not have been if this node is to repeat indefinitely.\n if (typeof definition.iterations !== \"undefined\") {\n if (Array.isArray(definition.iterations)) {\n // Check whether any elements of the array are not integer values.\n const containsNonInteger = !!definition.iterations.filter((value: unknown) => !isInteger(value)).length;\n\n // If the 'iterations' property is an array then it MUST contain two integer values.\n if (definition.iterations.length !== 2 || containsNonInteger) {\n throw new Error(\n `expected array containing two integer values for 'iterations' property if defined for repeat node at depth '${depth}'`\n );\n }\n\n // A repeat node must have a positive min and max iterations count if they are defined.\n if (definition.iterations[0] < 0 || definition.iterations[1] < 0) {\n throw new Error(\n `expected positive minimum and maximum iterations count for 'iterations' property if defined for repeat node at depth '${depth}'`\n );\n }\n\n // A repeat node must not have a minimum iterations count that exceeds the maximum iterations count.\n if (definition.iterations[0] > definition.iterations[1]) {\n throw new Error(\n `expected minimum iterations count that does not exceed the maximum iterations count for 'iterations' property if defined for repeat node at depth '${depth}'`\n );\n }\n } else if (isInteger(definition.iterations)) {\n // A repeat node must have a positive number of iterations if defined.\n if (definition.iterations < 0) {\n throw new Error(\n `expected positive iterations count for 'iterations' property if defined for repeat node at depth '${depth}'`\n );\n }\n } else {\n throw new Error(\n `expected integer value or array containing two integer values for 'iterations' property if defined for repeat node at depth '${depth}'`\n );\n }\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n\n // Validate the child node of this decorator node.\n validateNode(definition.child, depth + 1);\n}\n\n/**\n * Validate an object that we expect to be a retry node definition.\n * @param definition An object that we expect to be a retry node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateRetryNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"retry\") {\n throw new Error(`expected node type of 'retry' for retry node at depth '${depth}'`);\n }\n\n // A retry node is a decorator node, so must have a child node defined.\n if (typeof definition.child === \"undefined\") {\n throw new Error(`expected property 'child' to be defined for retry node at depth '${depth}'`);\n }\n\n // Check whether an 'attempts' property has been defined, it may not have been if this node is to retry indefinitely.\n if (typeof definition.attempts !== \"undefined\") {\n if (Array.isArray(definition.attempts)) {\n // Check whether any elements of the array are not integer values.\n const containsNonInteger = !!definition.attempts.filter((value: unknown) => !isInteger(value)).length;\n\n // If the 'attempts' property is an array then it MUST contain two integer values.\n if (definition.attempts.length !== 2 || containsNonInteger) {\n throw new Error(\n `expected array containing two integer values for 'attempts' property if defined for retry node at depth '${depth}'`\n );\n }\n\n // A retry node must have a positive min and max attempts count if they are defined.\n if (definition.attempts[0] < 0 || definition.attempts[1] < 0) {\n throw new Error(\n `expected positive minimum and maximum attempts count for 'attempts' property if defined for retry node at depth '${depth}'`\n );\n }\n\n // A retry node must not have a minimum attempts count that exceeds the maximum attempts count.\n if (definition.attempts[0] > definition.attempts[1]) {\n throw new Error(\n `expected minimum attempts count that does not exceed the maximum attempts count for 'attempts' property if defined for retry node at depth '${depth}'`\n );\n }\n } else if (isInteger(definition.attempts)) {\n // A retry node must have a positive number of attempts if defined.\n if (definition.attempts < 0) {\n throw new Error(\n `expected positive attempts count for 'attempts' property if defined for retry node at depth '${depth}'`\n );\n }\n } else {\n throw new Error(\n `expected integer value or array containing two integer values for 'attempts' property if defined for retry node at depth '${depth}'`\n );\n }\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n\n // Validate the child node of this decorator node.\n validateNode(definition.child, depth + 1);\n}\n\n/**\n * Validate an object that we expect to be a branch node definition.\n * @param definition An object that we expect to be a branch node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateBranchNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"branch\") {\n throw new Error(`expected node type of 'branch' for branch node at depth '${depth}'`);\n }\n\n // Check that the branch node 'ref' property is defined and is a non-empty string.\n if (typeof definition.ref !== \"string\" || definition.ref.length === 0) {\n throw new Error(`expected non-empty string for 'ref' property for branch node at depth '${depth}'`);\n }\n\n // It is invalid to define guard attributes for a branch node as they should be defined on the referenced root node.\n [\"while\", \"until\"].forEach((attributeName) => {\n if (typeof definition[attributeName] !== \"undefined\") {\n throw new Error(\n `guards should not be defined for branch nodes but guard '${attributeName}' was defined for branch node at depth '${depth}'`\n );\n }\n });\n\n // It is invalid to define callback attributes for a branch node as they should be defined on the referenced root node.\n [\"entry\", \"exit\", \"step\"].forEach((attributeName) => {\n if (typeof definition[attributeName] !== \"undefined\") {\n throw new Error(\n `callbacks should not be defined for branch nodes but callback '${attributeName}' was defined for branch node at depth '${depth}'`\n );\n }\n });\n}\n\n/**\n * Validate an object that we expect to be a action node definition.\n * @param definition An object that we expect to be a action node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateActionNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"action\") {\n throw new Error(`expected node type of 'action' for action node at depth '${depth}'`);\n }\n\n // The 'call' property must be defined for a action node definition.\n if (typeof definition.call !== \"string\" || definition.call.length === 0) {\n throw new Error(`expected non-empty string for 'call' property of action node at depth '${depth}'`);\n }\n\n // If any action function arguments have been defined then they must have been defined in an array.\n if (typeof definition.args !== \"undefined\" && !Array.isArray(definition.args)) {\n throw new Error(`expected array for 'args' property if defined for action node at depth '${depth}'`);\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n}\n\n/**\n * Validate an object that we expect to be a condition node definition.\n * @param definition An object that we expect to be a condition node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateConditionNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"condition\") {\n throw new Error(`expected node type of 'condition' for condition node at depth '${depth}'`);\n }\n\n // The 'call' property must be defined for a condition node definition.\n if (typeof definition.call !== \"string\" || definition.call.length === 0) {\n throw new Error(`expected non-empty string for 'call' property of condition node at depth '${depth}'`);\n }\n\n // If any condition function arguments have been defined then they must have been defined in an array.\n if (typeof definition.args !== \"undefined\" && !Array.isArray(definition.args)) {\n throw new Error(`expected array for 'args' property if defined for condition node at depth '${depth}'`);\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n}\n\n/**\n * Validate an object that we expect to be a wait node definition.\n * @param definition An object that we expect to be a wait node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateWaitNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"wait\") {\n throw new Error(`expected node type of 'wait' for wait node at depth '${depth}'`);\n }\n\n // Check whether a 'duration' property has been defined, it may not have been if this node is to wait indefinitely.\n if (typeof definition.duration !== \"undefined\") {\n if (Array.isArray(definition.duration)) {\n // Check whether any elements of the array are not integer values.\n const containsNonInteger = !!definition.duration.filter((value: unknown) => !isInteger(value)).length;\n\n // If the 'duration' property is an array then it MUST contain two integer values.\n if (definition.duration.length !== 2 || containsNonInteger) {\n throw new Error(\n `expected array containing two integer values for 'duration' property if defined for wait node at depth '${depth}'`\n );\n }\n\n // A wait node must have a positive min and max duration value if they are defined.\n if (definition.duration[0] < 0 || definition.duration[1] < 0) {\n throw new Error(\n `expected positive minimum and maximum duration for 'duration' property if defined for wait node at depth '${depth}'`\n );\n }\n\n // A wait node must not have a minimum duration value that exceeds the maximum duration value.\n if (definition.duration[0] > definition.duration[1]) {\n throw new Error(\n `expected minimum duration value that does not exceed the maximum duration value for 'duration' property if defined for wait node at depth '${depth}'`\n );\n }\n } else if (isInteger(definition.duration)) {\n // A wait node must have a positive duration value if defined.\n if (definition.duration < 0) {\n throw new Error(\n `expected positive duration value for 'duration' property if defined for wait node at depth '${depth}'`\n );\n }\n } else {\n throw new Error(\n `expected integer value or array containing two integer values for 'duration' property if defined for wait node at depth '${depth}'`\n );\n }\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n}\n\n/**\n * Validate an object that we expect to be a sequence node definition.\n * @param definition An object that we expect to be a sequence node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateSequenceNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"sequence\") {\n throw new Error(`expected node type of 'sequence' for sequence node at depth '${depth}'`);\n }\n\n // A sequence node is a composite node, so must have a children nodes array defined.\n if (!Array.isArray(definition.children) || definition.children.length === 0) {\n throw new Error(`expected non-empty 'children' array to be defined for sequence node at depth '${depth}'`);\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n\n // Validate the child nodes of this composite node.\n definition.children.forEach((child: any) => validateNode(child, depth + 1));\n}\n\n/**\n * Validate an object that we expect to be a selector node definition.\n * @param definition An object that we expect to be a selector node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateSelectorNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"selector\") {\n throw new Error(`expected node type of 'selector' for selector node at depth '${depth}'`);\n }\n\n // A selector node is a composite node, so must have a children nodes array defined.\n if (!Array.isArray(definition.children) || definition.children.length === 0) {\n throw new Error(`expected non-empty 'children' array to be defined for selector node at depth '${depth}'`);\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n\n // Validate the child nodes of this composite node.\n definition.children.forEach((child: any) => validateNode(child, depth + 1));\n}\n\n/**\n * Validate an object that we expect to be a parallel node definition.\n * @param definition An object that we expect to be a parallel node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateParallelNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"parallel\") {\n throw new Error(`expected node type of 'parallel' for parallel node at depth '${depth}'`);\n }\n\n // A parallel node is a composite node, so must have a children nodes array defined.\n if (!Array.isArray(definition.children) || definition.children.length === 0) {\n throw new Error(`expected non-empty 'children' array to be defined for parallel node at depth '${depth}'`);\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n\n // Validate the child nodes of this composite node.\n definition.children.forEach((child: any) => validateNode(child, depth + 1));\n}\n\n/**\n * Validate an object that we expect to be a lotto node definition.\n * @param definition An object that we expect to be a lotto node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateLottoNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"lotto\") {\n throw new Error(`expected node type of 'lotto' for lotto node at depth '${depth}'`);\n }\n\n // A lotto node is a composite node, so must have a children nodes array defined.\n if (!Array.isArray(definition.children) || definition.children.length === 0) {\n throw new Error(`expected non-empty 'children' array to be defined for lotto node at depth '${depth}'`);\n }\n\n // Check whether a 'weights' property has been defined, if it has we expect it to be an array of weights.\n if (typeof definition.weights !== \"undefined\") {\n // Check that the weights property is an array of positive integers with an element for each child node element.\n if (\n !Array.isArray(definition.weights) ||\n definition.weights.length !== definition.children.length ||\n definition.weights.filter((value: unknown) => !isInteger(value)).length ||\n definition.weights.filter((value: number) => value < 0).length\n ) {\n throw new Error(\n `expected an array of positive integer weight values with a length matching the number of child nodes for 'weights' property if defined for lotto node at depth '${depth}'`\n );\n }\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n\n // Validate the child nodes of this composite node.\n definition.children.forEach((child: any) => validateNode(child, depth + 1));\n}\n\n/**\n * A helper function to create a failure validation result with the given error message.\n * @param errorMessage The validation failure error message.\n * @returns A failure validation result with the given error message.\n */\nfunction createValidationFailureResult(errorMessage: string): DefinitionValidationResult {\n return { succeeded: false, errorMessage };\n}\n", "import { ActionResult, Agent, GlobalFunction } from \"./Agent\";\nimport { RootNodeDefinition } from \"./BehaviourTreeDefinition\";\n\nexport type InvokerFunction = (args: any[]) => ActionResult;\n\n/**\n * A singleton used to store and lookup registered functions and subtrees.\n */\nexport default class Lookup {\n /**\n * The object holding any registered functions keyed on function name.\n */\n private static functionTable: { [key: string]: GlobalFunction } = {};\n /**\n * The object holding any registered subtree root node definitions keyed on tree name.\n */\n private static subtreeTable: { [key: string]: RootNodeDefinition } = {};\n\n /**\n * Gets the function with the specified name.\n * @param name The name of the function.\n * @returns The function with the specified name.\n */\n public static getFunc(name: string): GlobalFunction {\n return this.functionTable[name];\n }\n\n /**\n * Sets the function with the specified name for later lookup.\n * @param name The name of the function.\n * @param func The function.\n */\n public static setFunc(name: string, func: GlobalFunction): void {\n this.functionTable[name] = func;\n }\n\n /**\n * Gets the function invoker for the specified agent and function name.\n * If a function with the specified name exists on the agent object then it will\n * be returned, otherwise we will then check the registered functions for a match.\n * @param agent The agent instance that this behaviour tree is modelling behaviour for.\n * @param name The function name.\n * @returns The function invoker for the specified agent and function name.\n */\n static getFuncInvoker(agent: Agent, name: string): InvokerFunction | null {\n // Check whether the agent contains the specified function.\n const foundOnAgent = agent[name];\n if (foundOnAgent && typeof foundOnAgent === \"function\") {\n return (args: any[]): boolean | ActionResult => foundOnAgent.apply(agent, args);\n }\n\n // The agent does not contain the specified function but it may have been registered at some point.\n if (this.functionTable[name] && typeof this.functionTable[name] === \"function\") {\n return (args: any[]) => this.functionTable[name](agent, ...args.map((arg) => arg.value));\n }\n\n // We have no function to invoke.\n return null;\n }\n\n /**\n * Gets all registered subtree root node definitions.\n */\n static getSubtrees(): { [key: string]: RootNodeDefinition } {\n return this.subtreeTable;\n }\n\n /**\n * Sets the subtree with the specified name for later lookup.\n * @param name The name of the subtree.\n * @param subtree The subtree.\n */\n static setSubtree(name: string, subtree: RootNodeDefinition) {\n this.subtreeTable[name] = subtree;\n }\n\n /**\n * Removes the registered function or subtree with the specified name.\n * @param name The name of the registered function or subtree.\n */\n static remove(name: string) {\n delete this.functionTable[name];\n delete this.subtreeTable[name];\n }\n\n /**\n * Remove all registered functions and subtrees.\n */\n static empty() {\n this.functionTable = {};\n this.subtreeTable = {};\n }\n}\n", "import Node from \"../../nodes/Node\";\n\n/**\n * An exception thrown when evaluating node guard path conditions and a conditions fails.\n */\nexport default class GuardUnsatisifedException extends Error {\n /**\n * @param source The node at which a guard condition failed.\n */\n constructor(private source: Node) {\n super(\"A guard path condition has failed\");\n }\n\n /**\n * Gets whether the specified node is the node at which a guard condition failed.\n * @param node The node to check against the source node.\n * @returns Whether the specified node is the node at which a guard condition failed.\n */\n isSourceNode = (node: Node) => node === this.source;\n}\n", "import { Agent } from \"../../Agent\";\nimport Guard from \"./Guard\";\nimport Node from \"../../nodes/Node\";\nimport GuardUnsatisifedException from \"./GuardUnsatisifedException\";\n\nexport type GuardPathPart = {\n node: Node;\n guards: Guard[];\n};\n\n/**\n * Represents a path of node guards along a root-to-leaf tree path.\n */\nexport default class GuardPath {\n /**\n * @param nodes An array of objects defining a node instance -> guard link, ordered by node depth.\n */\n constructor(private nodes: GuardPathPart[]) {}\n\n /**\n * Evaluate guard conditions for all guards in the tree path, moving outwards from the root.\n * @param agent The agent, required for guard evaluation.\n * @returns An evaluation results object.\n */\n evaluate = (agent: Agent) => {\n // We need to evaluate guard conditions for nodes up the tree, moving outwards from the root.\n for (const details of this.nodes) {\n // There can be multiple guards per node.\n for (const guard of details.guards) {\n // Check whether the guard condition passes, and throw an exception if not.\n if (!guard.isSatisfied(agent)) {\n throw new GuardUnsatisifedException(details.node);\n }\n }\n }\n };\n}\n", "import { BehaviourTreeOptions } from \"../BehaviourTreeOptions\";\nimport State, { AnyState } from \"../State\";\nimport { Agent } from \"../Agent\";\nimport Leaf from \"./leaf/Leaf\";\nimport Attribute from \"../attributes/Attribute\";\nimport Entry from \"../attributes/callbacks/Entry\";\nimport Exit from \"../attributes/callbacks/Exit\";\nimport Step from \"../attributes/callbacks/Step\";\nimport Guard from \"../attributes/guards/Guard\";\nimport GuardPath from \"../attributes/guards/GuardPath\";\nimport GuardUnsatisifedException from \"../attributes/guards/GuardUnsatisifedException\";\n\n/**\n * A base node.\n */\nexport default abstract class Node {\n /**\n * The node uid.\n */\n private readonly uid: string = createNodeUid();\n /**\n * The node state.\n */\n private state: AnyState = State.READY;\n /**\n * The guard path to evaluate as part of a node update.\n */\n private guardPath: GuardPath | undefined;\n\n /**\n * @param type The node type.\n * @param attributes The node attributes.\n * @param args The node argument definitions.\n */\n constructor(private type: string, private attributes: Attribute[], private args: any[]) {}\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected abstract onUpdate(agent: Agent, options: BehaviourTreeOptions): void;\n\n /**\n * Gets the name of the node.\n */\n public abstract getName(): string;\n\n /**\n * Gets whether this node is a leaf node.\n */\n public abstract isLeafNode: () => this is Leaf;\n\n /**\n * Gets/Sets the state of the node.\n */\n getState = (): AnyState => this.state;\n setState = (value: AnyState): void => {\n this.state = value;\n };\n\n /**\n * Gets the unique id of the node.\n */\n getUid = () => this.uid;\n\n /**\n * Gets the type of the node.\n */\n getType = () => this.type;\n\n /**\n * Gets the node attributes.\n */\n getAttributes = () => this.attributes;\n\n /**\n * Gets the node arguments.\n */\n getArguments = () => this.args;\n\n /**\n * Gets the node attribute with the specified type, or null if it does not exist.\n */\n getAttribute(type: \"entry\" | \"ENTRY\"): Entry;\n getAttribute(type: \"exit\" | \"EXIT\"): Exit;\n getAttribute(type: \"step\" | \"STEP\"): Step;\n getAttribute(type: string): Attribute {\n return (\n this.getAttributes().filter((decorator) => decorator.type.toUpperCase() === type.toUpperCase())[0] || null\n );\n }\n\n /**\n * Gets the node attributes.\n */\n getGuardAttributes = (): Guard[] => this.getAttributes().filter((decorator) => decorator.isGuard()) as Guard[];\n\n /**\n * Sets the guard path to evaluate as part of a node update.\n */\n setGuardPath = (value: GuardPath) => (this.guardPath = value);\n\n /**\n * Gets whether a guard path is assigned to this node.\n */\n hasGuardPath = () => !!this.guardPath;\n\n /**\n * Gets whether this node is in the specified state.\n * @param value The value to compare to the node state.\n */\n public is(value: AnyState): boolean {\n return this.state === value;\n }\n\n /**\n * Reset the state of the node.\n */\n public reset(): void {\n this.setState(State.READY);\n }\n\n /**\n * Abort the running of this node.\n * @param agent The agent.\n */\n public abort(agent: Agent): void {\n // There is nothing to do if this node is not in the running state.\n if (!this.is(State.RUNNING)) {\n return;\n }\n\n // Reset the state of this node.\n this.reset();\n\n this.getAttribute(\"exit\")?.callAgentFunction(agent, false, true);\n }\n\n /**\n * Update the node.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n * @returns The result of the update.\n */\n public update(agent: Agent, options: BehaviourTreeOptions): void {\n // If this node is already in a 'SUCCEEDED' or 'FAILED' state then there is nothing to do.\n if (this.is(State.SUCCEEDED) || this.is(State.FAILED)) {\n return;\n }\n\n try {\n // Evaluate all of the guard path conditions for the current tree path.\n this.guardPath!.evaluate(agent);\n\n // If this node is in the READY state then call the ENTRY for this node if it exists.\n if (this.is(State.READY)) {\n this.getAttribute(\"entry\")?.callAgentFunction(agent);\n }\n\n this.getAttribute(\"step\")?.callAgentFunction(agent);\n\n // Do the actual update.\n this.onUpdate(agent, options);\n\n // If this node is now in a 'SUCCEEDED' or 'FAILED' state then call the EXIT for this node if it exists.\n if (this.is(State.SUCCEEDED) || this.is(State.FAILED)) {\n this.getAttribute(\"exit\")?.callAgentFunction(agent, this.is(State.SUCCEEDED), false);\n }\n } catch (error) {\n // If the error is a GuardUnsatisfiedException then we need to determine if this node is the source.\n if (error instanceof GuardUnsatisifedException && error.isSourceNode(this)) {\n // Abort the current node.\n this.abort(agent);\n\n // Any node that is the source of an abort will be a failed node.\n this.setState(State.FAILED);\n } else {\n throw error;\n }\n }\n }\n}\n\n/**\n * Create a randomly generated node uid.\n * @returns A randomly generated node uid.\n */\nfunction createNodeUid(): string {\n var S4 = function () {\n return (((1 + Math.random()) * 0x10000) | 0).toString(16).substring(1);\n };\n return S4() + S4() + \"-\" + S4() + \"-\" + S4() + \"-\" + S4() + \"-\" + S4() + S4() + S4();\n}\n", "import Node from \"../Node\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\n\n/**\n * A composite node that wraps child nodes.\n */\nexport default abstract class Composite extends Node {\n /**\n * @param type The node type.\n * @param attributes The node attributes.\n * @param children The child nodes.\n */\n constructor(type: string, attributes: Attribute[], protected children: Node[]) {\n super(type, attributes, []);\n }\n\n /**\n * Gets whether this node is a leaf node.\n */\n isLeafNode = () => false;\n\n /**\n * Gets the children of this node.\n */\n getChildren = () => this.children;\n\n /**\n * Reset the state of the node.\n */\n reset = () => {\n // Reset the state of this node.\n this.setState(State.READY);\n\n // Reset the state of any child nodes.\n this.getChildren().forEach((child) => child.reset());\n };\n\n /**\n * Abort the running of this node.\n * @param agent The agent.\n */\n abort = (agent: Agent) => {\n // There is nothing to do if this node is not in the running state.\n if (!this.is(State.RUNNING)) {\n return;\n }\n\n // Abort any child nodes.\n this.getChildren().forEach((child) => child.abort(agent));\n\n // Reset the state of this node.\n this.reset();\n\n this.getAttribute(\"exit\")?.callAgentFunction(agent, false, true);\n };\n}\n", "import Composite from \"./Composite\";\nimport State from \"../../State\";\nimport Node from \"../Node\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A PARALLEL node.\n * The child nodes are executed concurrently until one fails or all succeed.\n */\nexport default class Parallel extends Composite {\n /**\n * @param attributes The node attributes.\n * @param children The child nodes.\n */\n constructor(attributes: Attribute[], children: Node[]) {\n super(\"parallel\", attributes, children);\n }\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // Keep a count of the number of succeeded child nodes.\n let succeededCount = 0;\n\n let hasChildFailed = false;\n\n // Iterate over all of the children of this node.\n for (const child of this.children) {\n // If the child has never been updated or is running then we will need to update it now.\n if (child.getState() === State.READY || child.getState() === State.RUNNING) {\n // Update the child of this node.\n child.update(agent, options);\n }\n\n // If the current child has a state of 'SUCCEEDED' then we should move on to the next child.\n if (child.getState() === State.SUCCEEDED) {\n // The child node has succeeded, keep track of this to determine if all children have.\n succeededCount++;\n\n // The child node succeeded, but we have not finished checking every child node yet.\n continue;\n }\n\n // If the current child has a state of 'FAILED' then this node is also a 'FAILED' node.\n if (child.getState() === State.FAILED) {\n hasChildFailed = true;\n\n // There is no need to check the rest of the children.\n break;\n }\n\n // The node should be in the 'RUNNING' state.\n if (child.getState() !== State.RUNNING) {\n // The child node was not in an expected state.\n throw new Error(\"child node was not in an expected state.\");\n }\n }\n\n if (hasChildFailed) {\n // This node is a 'FAILED' node.\n this.setState(State.FAILED);\n\n // Abort every running child.\n for (const child of this.children) {\n if (child.getState() === State.RUNNING) {\n child.abort(agent);\n }\n }\n } else {\n // If all children have succeeded then this node has also succeeded, otherwise it is still running.\n this.setState(succeededCount === this.children.length ? State.SUCCEEDED : State.RUNNING);\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => \"PARALLEL\";\n}\n", "import Composite from \"./Composite\";\nimport Node from \"../Node\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A SELECTOR node.\n * The child nodes are executed in sequence until one succeeds or all fail.\n */\nexport default class Selector extends Composite {\n /**\n * @param attributes The node attributes.\n * @param children The child nodes.\n */\n constructor(attributes: Attribute[], protected children: Node[]) {\n super(\"selector\", attributes, children);\n }\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // Iterate over all of the children of this node.\n for (const child of this.children) {\n // If the child has never been updated or is running then we will need to update it now.\n if (child.getState() === State.READY || child.getState() === State.RUNNING) {\n // Update the child of this node.\n child.update(agent, options);\n }\n\n // If the current child has a state of 'SUCCEEDED' then this node is also a 'SUCCEEDED' node.\n if (child.getState() === State.SUCCEEDED) {\n // This node is a 'SUCCEEDED' node.\n this.setState(State.SUCCEEDED);\n\n // There is no need to check the rest of the selector nodes.\n return;\n }\n\n // If the current child has a state of 'FAILED' then we should move on to the next child.\n if (child.getState() === State.FAILED) {\n // Find out if the current child is the last one in the selector.\n // If it is then this sequence node has also failed.\n if (this.children.indexOf(child) === this.children.length - 1) {\n // This node is a 'FAILED' node.\n this.setState(State.FAILED);\n\n // There is no need to check the rest of the selector as we have completed it.\n return;\n } else {\n // The child node failed, try the next one.\n continue;\n }\n }\n\n // The node should be in the 'RUNNING' state.\n if (child.getState() === State.RUNNING) {\n // This node is a 'RUNNING' node.\n this.setState(State.RUNNING);\n\n // There is no need to check the rest of the selector as the current child is still running.\n return;\n }\n\n // The child node was not in an expected state.\n throw new Error(\"child node was not in an expected state.\");\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => \"SELECTOR\";\n}\n", "import Composite from \"./Composite\";\nimport Node from \"../Node\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A SEQUENCE node.\n * The child nodes are executed in sequence until one fails or all succeed.\n */\nexport default class Sequence extends Composite {\n /**\n * @param attributes The node attributes.\n * @param children The child nodes.\n */\n constructor(attributes: Attribute[], protected children: Node[]) {\n super(\"sequence\", attributes, children);\n }\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // Iterate over all of the children of this node.\n for (const child of this.children) {\n // If the child has never been updated or is running then we will need to update it now.\n if (child.getState() === State.READY || child.getState() === State.RUNNING) {\n // Update the child of this node.\n child.update(agent, options);\n }\n\n // If the current child has a state of 'SUCCEEDED' then we should move on to the next child.\n if (child.getState() === State.SUCCEEDED) {\n // Find out if the current child is the last one in the sequence.\n // If it is then this sequence node has also succeeded.\n if (this.children.indexOf(child) === this.children.length - 1) {\n // This node is a 'SUCCEEDED' node.\n this.setState(State.SUCCEEDED);\n\n // There is no need to check the rest of the sequence as we have completed it.\n return;\n } else {\n // The child node succeeded, but we have not finished the sequence yet.\n continue;\n }\n }\n\n // If the current child has a state of 'FAILED' then this node is also a 'FAILED' node.\n if (child.getState() === State.FAILED) {\n // This node is a 'FAILED' node.\n this.setState(State.FAILED);\n\n // There is no need to check the rest of the sequence.\n return;\n }\n\n // The node should be in the 'RUNNING' state.\n if (child.getState() === State.RUNNING) {\n // This node is a 'RUNNING' node.\n this.setState(State.RUNNING);\n\n // There is no need to check the rest of the sequence as the current child is still running.\n return;\n }\n\n // The child node was not in an expected state.\n throw new Error(\"child node was not in an expected state.\");\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => \"SEQUENCE\";\n}\n", "import createLotto from \"lotto-draw\";\n\nimport Node from \"../Node\";\nimport Composite from \"./Composite\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A LOTTO node.\n * A winning child is picked on the initial update of this node, based on ticket weighting.\n * The state of this node will match the state of the winning child.\n */\nexport default class Lotto extends Composite {\n /**\n * @param attributes The node attributes.\n * @param weights The child node weights.\n * @param children The child nodes.\n */\n constructor(attributes: Attribute[], private weights: number[] | undefined, children: Node[]) {\n super(\"lotto\", attributes, children);\n }\n\n /**\n * The child node selected to be the active one.\n */\n private selectedChild: Node | undefined;\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // If this node is in the READY state then we need to pick a winning child node.\n if (this.is(State.READY)) {\n // Create a lotto draw with which to randomly pick a child node to become the active one.\n const lottoDraw = createLotto({\n // Hook up the optional 'random' behaviour tree function option to the one used by 'lotto-draw'.\n random: options.random,\n // Pass in each child node as a participant in the lotto draw with their respective ticket count.\n participants: this.children.map((child, index) => [child, this.weights?.[index] || 1])\n });\n\n // Randomly pick a child based on ticket weighting, this will become the active child for this composite node.\n this.selectedChild = lottoDraw.draw() || undefined;\n }\n\n // If something went wrong and we don't have an active child then we should throw an error.\n if (!this.selectedChild) {\n throw new Error(\"failed to update lotto node as it has no active child\");\n }\n\n // If the selected child has never been updated or is running then we will need to update it now.\n if (this.selectedChild.getState() === State.READY || this.selectedChild.getState() === State.RUNNING) {\n this.selectedChild.update(agent, options);\n }\n\n // The state of the lotto node is the state of its selected child.\n this.setState(this.selectedChild.getState());\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => (this.weights ? `LOTTO [${this.weights.join(\",\")}]` : \"LOTTO\");\n}\n", "import Node from \"../Node\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\n\n/**\n * A decorator node that wraps a single child node.\n */\nexport default abstract class Decorator extends Node {\n /**\n * @param type The node type.\n * @param attributes The node attributes.\n * @param child The child node.\n */\n constructor(type: string, attributes: Attribute[], protected child: Node) {\n super(type, attributes, []);\n }\n\n /**\n * Gets whether this node is a leaf node.\n */\n isLeafNode = () => false;\n\n /**\n * Gets the children of this node.\n */\n getChildren = () => [this.child];\n\n /**\n * Reset the state of the node.\n */\n reset = () => {\n // Reset the state of this node.\n this.setState(State.READY);\n\n // Reset the state of the child node.\n this.child.reset();\n };\n\n /**\n * Abort the running of this node.\n * @param agent The agent.\n */\n abort = (agent: Agent) => {\n // There is nothing to do if this node is not in the running state.\n if (!this.is(State.RUNNING)) {\n return;\n }\n\n // Abort the child node.\n this.child.abort(agent);\n\n // Reset the state of this node.\n this.reset();\n\n this.getAttribute(\"exit\")?.callAgentFunction(agent, false, true);\n };\n}\n", "import Node from \"../Node\";\nimport Decorator from \"./Decorator\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A Fail node.\n * This node wraps a single child and will always move to the 'FAILED' state when the child moves to a 'SUCCEEDED' or 'FAILED' state.\n */\nexport default class Fail extends Decorator {\n /**\n * @param attributes The node attributes.\n * @param child The child node.\n */\n constructor(attributes: Attribute[], child: Node) {\n super(\"fail\", attributes, child);\n }\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // If the child has never been updated or is running then we will need to update it now.\n if (this.child.getState() === State.READY || this.child.getState() === State.RUNNING) {\n this.child.update(agent, options);\n }\n\n // The state of this node will depend in the state of its child.\n switch (this.child.getState()) {\n case State.RUNNING:\n this.setState(State.RUNNING);\n break;\n\n case State.SUCCEEDED:\n case State.FAILED:\n this.setState(State.FAILED);\n break;\n\n default:\n this.setState(State.READY);\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => \"FAIL\";\n}\n", "import Decorator from \"./Decorator\";\nimport State from \"../../State\";\nimport Node from \"../Node\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A Flip node.\n * This node wraps a single child and will flip the state of the child state.\n */\nexport default class Flip extends Decorator {\n /**\n * @param attributes The node attributes.\n * @param child The child node.\n */\n constructor(attributes: Attribute[], child: Node) {\n super(\"flip\", attributes, child);\n }\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // If the child has never been updated or is running then we will need to update it now.\n if (this.child.getState() === State.READY || this.child.getState() === State.RUNNING) {\n this.child.update(agent, options);\n }\n\n // The state of this node will depend in the state of its child.\n switch (this.child.getState()) {\n case State.RUNNING:\n this.setState(State.RUNNING);\n break;\n\n case State.SUCCEEDED:\n this.setState(State.FAILED);\n break;\n\n case State.FAILED:\n this.setState(State.SUCCEEDED);\n break;\n\n default:\n this.setState(State.READY);\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => \"FLIP\";\n}\n", "import Node from \"../Node\";\nimport Decorator from \"./Decorator\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A REPEAT node.\n * The node has a single child which can have:\n * -- A number of iterations for which to repeat the child node.\n * -- An infinite repeat loop if neither an iteration count or a condition function is defined.\n * The REPEAT node will stop and have a 'FAILED' state if its child is ever in a 'FAILED' state after an update.\n * The REPEAT node will attempt to move on to the next iteration if its child is ever in a 'SUCCEEDED' state.\n */\nexport default class Repeat extends Decorator {\n /**\n * @param attributes The node attributes.\n * @param iterations The number of iterations to repeat the child node.\n * @param iterationsMin The minimum possible number of iterations to repeat the child node.\n * @param iterationsMax The maximum possible number of iterations to repeat the child node.\n * @param child The child node.\n */\n constructor(\n attributes: Attribute[],\n private iterations: number | null,\n private iterationsMin: number | null,\n private iterationsMax: number | null,\n child: Node\n ) {\n super(\"repeat\", attributes, child);\n }\n\n /**\n * The number of target iterations to make.\n */\n private targetIterationCount: number | null = null;\n\n /**\n * The current iteration count.\n */\n private currentIterationCount: number = 0;\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // If this node is in the READY state then we need to reset the child and the target iteration count.\n if (this.is(State.READY)) {\n // Reset the child node.\n this.child.reset();\n\n // Reset the current iteration count.\n this.currentIterationCount = 0;\n\n // Set the target iteration count.\n this.setTargetIterationCount(options);\n }\n\n // Do a check to see if we can iterate. If we can then this node will move into the 'RUNNING' state.\n // If we cannot iterate then we have hit our target iteration count, which means that the node has succeeded.\n if (this.canIterate()) {\n // This node is in the running state and can do its initial iteration.\n this.setState(State.RUNNING);\n\n // We may have already completed an iteration, meaning that the child node will be in the SUCCEEDED state.\n // If this is the case then we will have to reset the child node now.\n if (this.child.getState() === State.SUCCEEDED) {\n this.child.reset();\n }\n\n // Update the child of this node.\n this.child.update(agent, options);\n\n // If the child moved into the FAILED state when we updated it then there is nothing left to do and this node has also failed.\n // If it has moved into the SUCCEEDED state then we have completed the current iteration.\n if (this.child.getState() === State.FAILED) {\n // The child has failed, meaning that this node has failed.\n this.setState(State.FAILED);\n\n return;\n } else if (this.child.getState() === State.SUCCEEDED) {\n // We have completed an iteration.\n this.currentIterationCount += 1;\n }\n } else {\n // This node is in the 'SUCCEEDED' state as we cannot iterate any more.\n this.setState(State.SUCCEEDED);\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => {\n if (this.iterations !== null) {\n return `REPEAT ${this.iterations}x`;\n } else if (this.iterationsMin !== null && this.iterationsMax !== null) {\n return `REPEAT ${this.iterationsMin}x-${this.iterationsMax}x`;\n } else {\n return \"REPEAT\";\n }\n };\n\n /**\n * Reset the state of the node.\n */\n reset = () => {\n // Reset the state of this node.\n this.setState(State.READY);\n\n // Reset the current iteration count.\n this.currentIterationCount = 0;\n\n // Reset the child node.\n this.child.reset();\n };\n\n /**\n * Gets whether an iteration can be made.\n * @returns Whether an iteration can be made.\n */\n private canIterate = () => {\n if (this.targetIterationCount !== null) {\n // We can iterate as long as we have not reached our target iteration count.\n return this.currentIterationCount < this.targetIterationCount;\n }\n\n // If neither an iteration count or a condition function were defined then we can iterate indefinitely.\n return true;\n };\n\n /**\n * Sets the target iteration count.\n * @param options The behaviour tree options object.\n */\n private setTargetIterationCount = (options: BehaviourTreeOptions) => {\n // Are we dealing with an explicit iteration count or will we be randomly picking a iteration count between the min and max iteration count.\n if (this.iterations !== null) {\n this.targetIterationCount = this.iterations;\n } else if (this.iterationsMin !== null && this.iterationsMax !== null) {\n // We will be picking a random iteration count between a min and max iteration count, if the optional 'random'\n // behaviour tree function option is defined then we will be using that, otherwise we will fall back to using Math.random.\n const random = typeof options.random === \"function\" ? options.random : Math.random;\n\n // Pick a random iteration count between a min and max iteration count.\n this.targetIterationCount = Math.floor(\n random() * (this.iterationsMax - this.iterationsMin + 1) + this.iterationsMin\n );\n } else {\n this.targetIterationCount = null;\n }\n };\n}\n", "import Node from \"../Node\";\nimport Decorator from \"./Decorator\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A RETRY node.\n * The node has a single child which can have:\n * -- A number of iterations for which to repeat the child node.\n * -- An infinite repeat loop if neither an iteration count or a condition function is defined.\n * The RETRY node will stop and have a 'SUCCEEDED' state if its child is ever in a 'SUCCEEDED' state after an update.\n * The RETRY node will attempt to move on to the next iteration if its child is ever in a 'FAILED' state.\n */\nexport default class Retry extends Decorator {\n /**\n * @param attributes The node attributes.\n * @param attempts The number of attempts to retry the child node.\n * @param attemptsMin The minimum possible number of attempts to retry the child node.\n * @param attemptsMax The maximum possible number of attempts to retry the child node.\n * @param child The child node.\n */\n constructor(\n attributes: Attribute[],\n private attempts: number | null,\n private attemptsMin: number | null,\n private attemptsMax: number | null,\n child: Node\n ) {\n super(\"retry\", attributes, child);\n }\n\n /**\n * The number of target attempts to make.\n */\n private targetAttemptCount: number | null = null;\n\n /**\n * The current attempt count.\n */\n private currentAttemptCount: number = 0;\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // If this node is in the READY state then we need to reset the child and the target attempt count.\n if (this.is(State.READY)) {\n // Reset the child node.\n this.child.reset();\n\n // Reset the current attempt count.\n this.currentAttemptCount = 0;\n\n // Set the target attempt count.\n this.setTargetAttemptCount(options);\n }\n\n // Do a check to see if we can attempt. If we can then this node will move into the 'RUNNING' state.\n // If we cannot attempt then we have hit our target attempt count, which means that the node has succeeded.\n if (this.canAttempt()) {\n // This node is in the running state and can do its initial attempt.\n this.setState(State.RUNNING);\n\n // We may have already completed an attempt, meaning that the child node will be in the FAILED state.\n // If this is the case then we will have to reset the child node now.\n if (this.child.getState() === State.FAILED) {\n this.child.reset();\n }\n\n // Update the child of this node.\n this.child.update(agent, options);\n\n // If the child moved into the SUCCEEDED state when we updated it then there is nothing left to do and this node has also succeeded.\n // If it has moved into the FAILED state then we have completed the current attempt.\n if (this.child.getState() === State.SUCCEEDED) {\n // The child has succeeded, meaning that this node has succeeded.\n this.setState(State.SUCCEEDED);\n\n return;\n } else if (this.child.getState() === State.FAILED) {\n // We have completed an attempt.\n this.currentAttemptCount += 1;\n }\n } else {\n // This node is in the 'FAILED' state as we cannot iterate any more.\n this.setState(State.FAILED);\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => {\n if (this.attempts !== null) {\n return `RETRY ${this.attempts}x`;\n } else if (this.attemptsMin !== null && this.attemptsMax !== null) {\n return `RETRY ${this.attemptsMin}x-${this.attemptsMax}x`;\n } else {\n return \"RETRY\";\n }\n };\n\n /**\n * Reset the state of the node.\n */\n reset = () => {\n // Reset the state of this node.\n this.setState(State.READY);\n\n // Reset the current attempt count.\n this.currentAttemptCount = 0;\n\n // Reset the child node.\n this.child.reset();\n };\n\n /**\n * Gets whether an attempt can be made.\n * @returns Whether an attempt can be made.\n */\n canAttempt = () => {\n if (this.targetAttemptCount !== null) {\n // We can attempt as long as we have not reached our target attempt count.\n return this.currentAttemptCount < this.targetAttemptCount;\n }\n\n // If neither an attempt count or a condition function were defined then we can attempt indefinitely.\n return true;\n };\n\n /**\n * Sets the target attempt count.\n * @param options The behaviour tree options object.\n */\n setTargetAttemptCount = (options: BehaviourTreeOptions) => {\n // Are we dealing with an explicit attempt count or will we be randomly picking an attempt count between the min and max attempt count.\n if (this.attempts !== null) {\n this.targetAttemptCount = this.attempts;\n } else if (this.attemptsMin !== null && this.attemptsMax !== null) {\n // We will be picking a random attempt count between a min and max attempt count, if the optional 'random'\n // behaviour tree function option is defined then we will be using that, otherwise we will fall back to using Math.random.\n const random = typeof options.random === \"function\" ? options.random : Math.random;\n\n // Pick a random attempt count between a min and max attempt count.\n this.targetAttemptCount = Math.floor(\n random() * (this.attemptsMax - this.attemptsMin + 1) + this.attemptsMin\n );\n } else {\n this.targetAttemptCount = null;\n }\n };\n}\n", "import Node from \"../Node\";\nimport Decorator from \"./Decorator\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A Root node.\n * The root node will have a single child.\n */\nexport default class Root extends Decorator {\n /**\n * @param attributes The node attributes.\n * @param child The child node.\n */\n constructor(attributes: Attribute[], child: Node) {\n super(\"root\", attributes, child);\n }\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // If the child has never been updated or is running then we will need to update it now.\n if (this.child.getState() === State.READY || this.child.getState() === State.RUNNING) {\n // Update the child of this node.\n this.child.update(agent, options);\n }\n\n // The state of the root node is the state of its child.\n this.setState(this.child.getState());\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => \"ROOT\";\n}\n", "import Node from \"../Node\";\nimport Decorator from \"./Decorator\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A Succeed node.\n * This node wraps a single child and will always move to the 'SUCCEEDED' state when the child moves to a 'SUCCEEDED' or 'FAILED' state.\n */\nexport default class Succeed extends Decorator {\n /**\n * @param attributes The node attributes.\n * @param child The child node.\n */\n constructor(attributes: Attribute[], child: Node) {\n super(\"succeed\", attributes, child);\n }\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // If the child has never been updated or is running then we will need to update it now.\n if (this.child.getState() === State.READY || this.child.getState() === State.RUNNING) {\n this.child.update(agent, options);\n }\n\n // The state of this node will depend in the state of its child.\n switch (this.child.getState()) {\n case State.RUNNING:\n this.setState(State.RUNNING);\n break;\n\n case State.SUCCEEDED:\n case State.FAILED:\n this.setState(State.SUCCEEDED);\n break;\n\n default:\n this.setState(State.READY);\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => \"SUCCEED\";\n}\n", "import Node from \"../Node\";\n\n/**\n * A leaf node.\n */\nexport default abstract class Leaf extends Node {\n /**\n * Gets whether this node is a leaf node.\n */\n isLeafNode = () => true;\n}\n", "import { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\nimport State, { CompleteState } from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Leaf from \"./Leaf\";\nimport Lookup from \"../../Lookup\";\nimport Attribute from \"../../attributes/Attribute\";\n\n/**\n * An Action leaf node.\n * This represents an immediate or ongoing state of behaviour.\n */\nexport default class Action extends Leaf {\n /**\n * @param attributes The node attributes.\n * @param actionName The action name.\n * @param actionArguments The array of action argument definitions.\n */\n constructor(attributes: Attribute[], private actionName: string, private actionArguments: any[]) {\n super(\"action\", attributes, actionArguments);\n }\n\n /**\n * Whether there is a pending update promise.\n */\n private isUsingUpdatePromise = false;\n\n /**\n * The finished state result of an update promise.\n */\n private updatePromiseStateResult: CompleteState | null = null;\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // If the result of this action depends on an update promise then there is nothing to do until\n // it resolves, unless there has been a value set as a result of the update promise resolving.\n if (this.isUsingUpdatePromise) {\n // Check whether the update promise has resolved with a state value.\n if (this.updatePromiseStateResult) {\n // Set the state of this node to match the state returned by the promise.\n this.setState(this.updatePromiseStateResult);\n }\n\n return;\n }\n\n // Attempt to get the invoker for the action function.\n const actionFuncInvoker = Lookup.getFuncInvoker(agent, this.actionName);\n\n // The action function should be defined.\n if (actionFuncInvoker === null) {\n throw new Error(\n `cannot update action node as the action '${this.actionName}' function is not defined on the agent and has not been registered`\n );\n }\n\n // Call the action function, the result of which may be:\n // - The finished state of this action node.\n // - A promise to return a finished node state.\n // - Undefined if the node should remain in the running state.\n const updateResult = actionFuncInvoker(this.actionArguments) as CompleteState | Promise;\n\n if (updateResult instanceof Promise) {\n updateResult.then(\n (result) => {\n // If 'isUpdatePromisePending' is null then the promise was cleared as it was resolving, probably via an abort of reset.\n if (!this.isUsingUpdatePromise) {\n return;\n }\n\n // Check to make sure the result is a valid finished state.\n if (result !== State.SUCCEEDED && result !== State.FAILED) {\n throw new Error(\n \"action node promise resolved with an invalid value, expected a State.SUCCEEDED or State.FAILED value to be returned\"\n );\n }\n\n // Set pending update promise state result to be processed on next update.\n this.updatePromiseStateResult = result;\n },\n (reason) => {\n // If 'isUpdatePromisePending' is null then the promise was cleared as it was resolving, probably via an abort of reset.\n if (!this.isUsingUpdatePromise) {\n return;\n }\n\n // Just throw whatever was returned as the rejection argument.\n throw new Error(reason);\n }\n );\n\n // This node will be in the 'RUNNING' state until the update promise resolves.\n this.setState(State.RUNNING);\n\n // We are now waiting for the promise returned by the use to resolve before we know what state this node is in.\n this.isUsingUpdatePromise = true;\n } else {\n // Validate the returned value.\n this.validateUpdateResult(updateResult);\n\n // Set the state of this node, this may be undefined, which just means that the node is still in the 'RUNNING' state.\n this.setState(updateResult || State.RUNNING);\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => this.actionName;\n\n /**\n * Reset the state of the node.\n */\n reset = () => {\n // Reset the state of this node.\n this.setState(State.READY);\n\n // There is no longer an update promise that we care about.\n this.isUsingUpdatePromise = false;\n this.updatePromiseStateResult = null;\n };\n\n /**\n * Validate the result of an update function call.\n * @param result The result of an update function call.\n */\n private validateUpdateResult = (result: CompleteState | boolean) => {\n switch (result) {\n case State.SUCCEEDED:\n case State.FAILED:\n case undefined:\n return;\n default:\n throw new Error(\n `action '${this.actionName}' 'onUpdate' returned an invalid response, expected an optional State.SUCCEEDED or State.FAILED value to be returned`\n );\n }\n };\n}\n", "import { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Leaf from \"./Leaf\";\nimport Lookup from \"../../Lookup\";\nimport Attribute from \"../../attributes/Attribute\";\n\n/**\n * A Condition leaf node.\n * This will succeed or fail immediately based on an agent predicate, without moving to the 'RUNNING' state.\n */\nexport default class Condition extends Leaf {\n /**\n * @param attributes The node attributes.\n * @param conditionName The name of the condition function.\n * @param conditionArguments The array of condition argument definitions.\n */\n constructor(attributes: Attribute[], private conditionName: string, private conditionArguments: any[]) {\n super(\"condition\", attributes, conditionArguments);\n }\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // Attempt to get the invoker for the condition function.\n const conditionFuncInvoker = Lookup.getFuncInvoker(agent, this.conditionName);\n\n // The condition function should be defined.\n if (conditionFuncInvoker === null) {\n throw new Error(\n `cannot update condition node as the condition '${this.conditionName}' function is not defined on the agent and has not been registered`\n );\n }\n\n // Call the condition function to determine the state of this node.\n this.setState(!!conditionFuncInvoker(this.conditionArguments) ? State.SUCCEEDED : State.FAILED);\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => this.conditionName;\n}\n", "import Leaf from \"./Leaf\";\nimport State from \"../../State\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { Agent } from \"../../Agent\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A WAIT node.\n * The state of this node will change to SUCCEEDED after a duration of time\n */\nexport default class Wait extends Leaf {\n /**\n * @param attributes The node attributes.\n * @param duration The duration that this node will wait to succeed in milliseconds.\n * @param durationMin The minimum possible duration in milliseconds that this node will wait to succeed.\n * @param durationMax The maximum possible duration in milliseconds that this node will wait to succeed.\n */\n constructor(\n attributes: Attribute[],\n private duration: number | null,\n private durationMin: number | null,\n private durationMax: number | null\n ) {\n super(\"wait\", attributes, []);\n }\n\n /**\n * The time in milliseconds at which this node was first updated.\n */\n private initialUpdateTime: number = 0;\n\n /**\n * The total duration in milliseconds that this node will be waiting for.\n */\n private totalDuration: number | null = null;\n\n /**\n * The duration in milliseconds that this node has been waiting for.\n */\n private waitedDuration: number = 0;\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // If this node is in the READY state then we need to set the initial update time.\n if (this.is(State.READY)) {\n // Set the initial update time.\n this.initialUpdateTime = new Date().getTime();\n\n // Set the initial waited duration.\n this.waitedDuration = 0;\n\n // Are we dealing with an explicit duration or will we be randomly picking a duration between the min and max duration.\n if (this.duration !== null) {\n this.totalDuration = this.duration;\n } else if (this.durationMin !== null && this.durationMax !== null) {\n // We will be picking a random duration between a min and max duration, if the optional 'random' behaviour tree\n // function option is defined then we will be using that, otherwise we will fall back to using Math.random.\n const random = typeof options.random === \"function\" ? options.random : Math.random;\n\n // Pick a random duration between a min and max duration.\n this.totalDuration = Math.floor(\n random() * (this.durationMax - this.durationMin + 1) + this.durationMin\n );\n } else {\n this.totalDuration = null;\n }\n\n // The node is now running until we finish waiting.\n this.setState(State.RUNNING);\n }\n\n // If we have no total duration then this wait node will wait indefinitely until it is aborted.\n if (this.totalDuration === null) {\n return;\n }\n\n // If we have a 'getDeltaTime' function defined as part of our options then we will use it to figure out how long we have waited for.\n if (typeof options.getDeltaTime === \"function\") {\n // Get the delta time.\n const deltaTime = options.getDeltaTime();\n\n // Our delta time must be a valid number and cannot be NaN.\n if (typeof deltaTime !== \"number\" || isNaN(deltaTime)) {\n throw new Error(\"The delta time must be a valid number and not NaN.\");\n }\n\n // Update the amount of time that this node has been waiting for based on the delta time.\n this.waitedDuration += deltaTime * 1000;\n } else {\n // We are not using a delta time, so we will just work out hom much time has passed since the first update.\n this.waitedDuration = new Date().getTime() - this.initialUpdateTime;\n }\n\n // Have we waited long enough?\n if (this.waitedDuration >= this.totalDuration) {\n // We have finished waiting!\n this.setState(State.SUCCEEDED);\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => {\n if (this.duration !== null) {\n return `WAIT ${this.duration}ms`;\n } else if (this.durationMin !== null && this.durationMax !== null) {\n return `WAIT ${this.durationMin}ms-${this.durationMax}ms`;\n } else {\n return \"WAIT\";\n }\n };\n}\n", "import Guard from \"./guards/Guard\";\n\nexport type AttributeDetails = {\n /** The attribute type. */\n type: string;\n\n /** The attribute arguments. */\n args: any[];\n};\n\n/**\n * A base node attribute.\n */\nexport default abstract class Attribute {\n /**\n * @param type The node attribute type.\n * @param args The array of attribute arguments.\n */\n constructor(public type: string, public args: any[]) {}\n\n /**\n * Gets the attribute details.\n */\n abstract getDetails(): TAttributeDetails;\n\n /**\n * Gets whether this attribute is a guard.\n */\n abstract isGuard: () => this is Guard;\n}\n", "import { Agent } from \"../../Agent\";\nimport Attribute, { AttributeDetails } from \"../Attribute\";\n\nexport type GuardAttributeDetails = {\n /** The name of the condition function that determines whether the guard is satisfied. */\n condition: string;\n} & AttributeDetails;\n\n/**\n * A base node guard attribute.\n */\nexport default abstract class Guard extends Attribute {\n /**\n * @param type The node attribute type.\n * @param args The array of decorator argument definitions.\n * @param condition The name of the condition function that determines whether the guard is satisfied.\n */\n constructor(type: string, args: any[], private condition: string) {\n super(type, args);\n }\n\n /**\n * Gets the name of the condition function that determines whether the guard is satisfied.\n */\n getCondition = () => this.condition;\n\n /**\n * Gets whether this attribute is a guard.\n */\n isGuard = () => true;\n\n /**\n * Gets the attribute details.\n */\n getDetails(): GuardAttributeDetails {\n return {\n type: this.type,\n args: this.args,\n condition: this.getCondition()\n };\n }\n\n /**\n * Gets whether the guard is satisfied.\n * @param agent The agent.\n * @returns Whether the guard is satisfied.\n */\n abstract isSatisfied(agent: Agent): boolean;\n}\n", "import Guard from \"./Guard\";\nimport Lookup from \"../../Lookup\";\nimport { Agent } from \"../../Agent\";\n\n/**\n * A WHILE guard which is satisfied as long as the given condition remains true.\n */\nexport default class While extends Guard {\n /**\n * @param condition The name of the condition function that determines whether the guard is satisfied.\n * @param args The array of decorator argument definitions.\n */\n constructor(condition: string, args: any[]) {\n super(\"while\", args, condition);\n }\n\n /**\n * Gets whether the guard is satisfied.\n * @param agent The agent.\n * @returns Whether the guard is satisfied.\n */\n isSatisfied = (agent: Agent) => {\n // Attempt to get the invoker for the condition function.\n const conditionFuncInvoker = Lookup.getFuncInvoker(agent, this.getCondition());\n\n // The condition function should be defined.\n if (conditionFuncInvoker === null) {\n throw new Error(\n `cannot evaluate node guard as the condition '${this.getCondition()}' function is not defined on the agent and has not been registered`\n );\n }\n\n // Call the condition function to determine whether this guard is satisfied.\n return !!conditionFuncInvoker(this.args);\n };\n}\n", "import Guard from \"./Guard\";\nimport Lookup from \"../../Lookup\";\nimport { Agent } from \"../../Agent\";\n\n/**\n * An UNTIL guard which is satisfied as long as the given condition remains false.\n */\nexport default class Until extends Guard {\n /**\n * @param condition The name of the condition function that determines whether the guard is satisfied.\n * @param args The array of decorator argument definitions.\n */\n constructor(condition: string, args: any[]) {\n super(\"until\", args, condition);\n }\n\n /**\n * Gets whether the guard is satisfied.\n * @param agent The agent.\n * @returns Whether the guard is satisfied.\n */\n isSatisfied = (agent: Agent) => {\n // Attempt to get the invoker for the condition function.\n const conditionFuncInvoker = Lookup.getFuncInvoker(agent, this.getCondition());\n\n // The condition function should be defined.\n if (conditionFuncInvoker === null) {\n throw new Error(\n `cannot evaluate node guard as the condition '${this.getCondition()}' function is not defined on the agent and has not been registered`\n );\n }\n\n // Call the condition function to determine whether this guard is satisfied.\n return !!!conditionFuncInvoker(this.args);\n };\n}\n", "import { Agent } from \"../../Agent\";\nimport Attribute, { AttributeDetails } from \"../Attribute\";\n\nexport type CallbackAttributeDetails = {\n /** The name of the agent function that is called. */\n functionName: string;\n} & AttributeDetails;\n\n/**\n * A base node callback attribute.\n */\nexport default abstract class Callback extends Attribute {\n /**\n * @param type The node attribute type.\n * @param args The array of decorator argument definitions.\n * @param functionName The name of the agent function to call.\n */\n constructor(type: string, args: any[], private functionName: string) {\n super(type, args);\n }\n\n /**\n * Gets the name of the agent function to call.\n */\n getFunctionName = () => this.functionName;\n\n /**\n * Gets whether this attribute is a guard.\n */\n isGuard = () => false;\n\n /**\n * Gets the attribute details.\n */\n getDetails(): CallbackAttributeDetails {\n return {\n type: this.type,\n args: this.args,\n functionName: this.getFunctionName()\n };\n }\n\n /**\n * Attempt to call the agent function that this callback refers to.\n * @param agent The agent.\n */\n abstract callAgentFunction: (agent: Agent, isSuccess: boolean, isAborted: boolean) => void;\n}\n", "import Callback from \"./Callback\";\nimport Lookup from \"../../Lookup\";\nimport { Agent } from \"../../Agent\";\n\n/**\n * An ENTRY callback which defines an agent function to call when the associated node is updated and moves out of running state.\n */\nexport default class Entry extends Callback {\n /**\n * @param functionName The name of the agent function to call.\n * @param args The array of callback argument definitions.\n */\n constructor(functionName: string, args: any[]) {\n super(\"entry\", args, functionName);\n }\n\n /**\n * Attempt to call the agent function that this callback refers to.\n * @param agent The agent.\n */\n callAgentFunction = (agent: Agent) => {\n // Attempt to get the invoker for the callback function.\n const callbackFuncInvoker = Lookup.getFuncInvoker(agent, this.getFunctionName());\n\n // The callback function should be defined.\n if (callbackFuncInvoker === null) {\n throw new Error(\n `cannot call entry function '${this.getFunctionName()}' as is not defined on the agent and has not been registered`\n );\n }\n\n // Call the callback function.\n callbackFuncInvoker(this.args);\n };\n}\n", "import Callback from \"./Callback\";\nimport Lookup from \"../../Lookup\";\nimport { Agent } from \"../../Agent\";\n\n/**\n * A STEP callback which defines an agent function to call when the associated node is updated.\n */\nexport default class Step extends Callback {\n /**\n * @param functionName The name of the agent function to call.\n * @param args The array of callback argument definitions.\n */\n constructor(functionName: string, args: any[]) {\n super(\"step\", args, functionName);\n }\n\n /**\n * Attempt to call the agent function that this callback refers to.\n * @param agent The agent.\n */\n callAgentFunction = (agent: Agent) => {\n // Attempt to get the invoker for the callback function.\n const callbackFuncInvoker = Lookup.getFuncInvoker(agent, this.getFunctionName());\n\n // The callback function should be defined.\n if (callbackFuncInvoker === null) {\n throw new Error(\n `cannot call step function '${this.getFunctionName()}' as is not defined on the agent and has not been registered`\n );\n }\n\n // Call the callback function.\n callbackFuncInvoker(this.args);\n };\n}\n", "import Callback from \"./Callback\";\nimport Lookup from \"../../Lookup\";\nimport { Agent } from \"../../Agent\";\n\n/**\n * An EXIT callback which defines an agent function to call when the associated node is updated and moves to a finished state or is aborted.\n */\nexport default class Exit extends Callback {\n /**\n * @param functionName The name of the agent function to call.\n * @param args The array of callback argument definitions.\n */\n constructor(functionName: string, args: any[]) {\n super(\"exit\", args, functionName);\n }\n\n /**\n * Attempt to call the agent function that this callback refers to.\n * @param agent The agent.\n * @param isSuccess Whether the decorated node was left with a success state.\n * @param isAborted Whether the decorated node was aborted.\n */\n callAgentFunction = (agent: Agent, isSuccess: boolean, isAborted: boolean) => {\n // Attempt to get the invoker for the callback function.\n const callbackFuncInvoker = Lookup.getFuncInvoker(agent, this.getFunctionName());\n\n // The callback function should be defined.\n if (callbackFuncInvoker === null) {\n throw new Error(\n `cannot call exit function '${this.getFunctionName()}' as is not defined on the agent and has not been registered`\n );\n }\n\n // Call the callback function\n callbackFuncInvoker([{ value: { succeeded: isSuccess, aborted: isAborted } }, ...this.args]);\n };\n}\n", "import { AnyNodeDefinition, RootNodeDefinition } from \"./BehaviourTreeDefinition\";\nimport GuardPath, { GuardPathPart } from \"./attributes/guards/GuardPath\";\nimport { validateBranchSubtreeLinks } from \"./BehaviourTreeDefinitionValidator\";\nimport { isInteger } from \"./BehaviourTreeDefinitionUtilities\";\nimport Node from \"./nodes/Node\";\nimport Composite from \"./nodes/composite/Composite\";\nimport Decorator from \"./nodes/decorator/Decorator\";\nimport Parallel from \"./nodes/composite/Parallel\";\nimport Selector from \"./nodes/composite/Selector\";\nimport Sequence from \"./nodes/composite/Sequence\";\nimport Lotto from \"./nodes/composite/Lotto\";\nimport Fail from \"./nodes/decorator/Fail\";\nimport Flip from \"./nodes/decorator/Flip\";\nimport Repeat from \"./nodes/decorator/Repeat\";\nimport Retry from \"./nodes/decorator/Retry\";\nimport Root from \"./nodes/decorator/Root\";\nimport Succeed from \"./nodes/decorator/Succeed\";\nimport Action from \"./nodes/leaf/Action\";\nimport Condition from \"./nodes/leaf/Condition\";\nimport Wait from \"./nodes/leaf/Wait\";\nimport Lookup from \"./Lookup\";\nimport Attribute from \"./attributes/Attribute\";\nimport While from \"./attributes/guards/While\";\nimport Until from \"./attributes/guards/Until\";\nimport Entry from \"./attributes/callbacks/Entry\";\nimport Step from \"./attributes/callbacks/Step\";\nimport Exit from \"./attributes/callbacks/Exit\";\n\n/**\n * A type representing any node instance in a behaviour tree.\n */\ntype AnyNode =\n | Root\n | Action\n | Condition\n | Wait\n | Sequence\n | Selector\n | Lotto\n | Parallel\n | Repeat\n | Retry\n | Flip\n | Succeed\n | Fail;\n\n/**\n * A type defining a mapping of root node identifiers to root node definitions.\n */\ntype RootNodeDefinitionMap = { [key: string | symbol]: RootNodeDefinition };\n\n/**\n * A symbol to use as the main root key in any root node mappings.\n */\nconst MAIN_ROOT_NODE_KEY = Symbol(\"__root__\");\n\n/**\n * Build and populate the root nodes based on the provided definition, assuming that the definition has been validated.\n * @param definition The root node definitions.\n * @returns The built and populated root node definitions.\n */\nexport default function buildRootNode(definition: RootNodeDefinition[]): Root {\n // Create a mapping of root node identifers to root node definitions, including globally registered subtree root node definitions.\n const rootNodeDefinitionMap = createRootNodeDefinitionMap(definition);\n\n // Now that we have all of our root node definitons (those part of the tree definition and those globally\n // registered) we should validate the definition. This will also double-check that we dont have any circular\n // dependencies in our branch -> subtree references and that we have no broken branch -> subtree links.\n validateBranchSubtreeLinks(definition, true);\n\n // Create our populated tree of node instances, starting with our main root node.\n const rootNode = nodeFactory(rootNodeDefinitionMap[MAIN_ROOT_NODE_KEY], rootNodeDefinitionMap) as Root;\n\n // Set a guard path on every leaf of the tree to evaluate as part of each update.\n applyLeafNodeGuardPaths(rootNode);\n\n // We only need to return the main root node.\n return rootNode;\n}\n\n/**\n * A factory function which creates a node instance based on the specified definition.\n * @param definition The node definition.\n * @param rootNodeDefinitionMap The mapping of root node identifers to root node definitions, including globally registered subtree root node definitions.\n * @returns A node instance based on the specified definition.\n */\nfunction nodeFactory(definition: AnyNodeDefinition, rootNodeDefinitionMap: RootNodeDefinitionMap): AnyNode {\n // Get the attributes for the node.\n const attributes = nodeAttributesFactory(definition);\n\n // Create the node instance based on the definition type.\n switch (definition.type) {\n case \"root\":\n return new Root(attributes, nodeFactory(definition.child, rootNodeDefinitionMap));\n\n case \"repeat\":\n let iterations: number | null = null;\n let iterationsMin: number | null = null;\n let iterationsMax: number | null = null;\n\n if (Array.isArray(definition.iterations)) {\n iterationsMin = definition.iterations[0];\n iterationsMax = definition.iterations[1];\n } else if (isInteger(definition.iterations)) {\n iterations = definition.iterations!;\n }\n\n return new Repeat(\n attributes,\n iterations,\n iterationsMin,\n iterationsMax,\n nodeFactory(definition.child, rootNodeDefinitionMap)\n );\n\n case \"retry\":\n let attempts: number | null = null;\n let attemptsMin: number | null = null;\n let attemptsMax: number | null = null;\n\n if (Array.isArray(definition.attempts)) {\n attemptsMin = definition.attempts[0];\n attemptsMax = definition.attempts[1];\n } else if (isInteger(definition.attempts)) {\n attempts = definition.attempts!;\n }\n\n return new Retry(\n attributes,\n attempts,\n attemptsMin,\n attemptsMax,\n nodeFactory(definition.child, rootNodeDefinitionMap)\n );\n\n case \"flip\":\n return new Flip(attributes, nodeFactory(definition.child, rootNodeDefinitionMap));\n\n case \"succeed\":\n return new Succeed(attributes, nodeFactory(definition.child, rootNodeDefinitionMap));\n\n case \"fail\":\n return new Fail(attributes, nodeFactory(definition.child, rootNodeDefinitionMap));\n\n case \"sequence\":\n return new Sequence(\n attributes,\n definition.children.map((child) => nodeFactory(child, rootNodeDefinitionMap))\n );\n\n case \"selector\":\n return new Selector(\n attributes,\n definition.children.map((child) => nodeFactory(child, rootNodeDefinitionMap))\n );\n\n case \"parallel\":\n return new Parallel(\n attributes,\n definition.children.map((child) => nodeFactory(child, rootNodeDefinitionMap))\n );\n\n case \"lotto\":\n return new Lotto(\n attributes,\n definition.weights,\n definition.children.map((child) => nodeFactory(child, rootNodeDefinitionMap))\n );\n\n case \"branch\":\n return nodeFactory(rootNodeDefinitionMap[definition.ref].child, rootNodeDefinitionMap);\n\n case \"action\":\n return new Action(attributes, definition.call, definition.args || []);\n\n case \"condition\":\n return new Condition(attributes, definition.call, definition.args || []);\n\n case \"wait\":\n let duration: number | null = null;\n let durationMin: number | null = null;\n let durationMax: number | null = null;\n\n if (Array.isArray(definition.duration)) {\n durationMin = definition.duration[0];\n durationMax = definition.duration[1];\n } else if (isInteger(definition.duration)) {\n duration = definition.duration!;\n }\n\n return new Wait(attributes, duration, durationMin, durationMax);\n }\n}\n\n/**\n * Creates an array of node attribute instances based on the specified node definition.\n * @param definition The node definition.\n * @returns An array of node attribute instances based on the specified node definition.\n */\nfunction nodeAttributesFactory(definition: AnyNodeDefinition): Attribute[] {\n const attributes: Attribute[] = [];\n\n if (definition.while) {\n attributes.push(new While(definition.while.call, definition.while.args ?? []));\n }\n\n if (definition.until) {\n attributes.push(new Until(definition.until.call, definition.until.args ?? []));\n }\n\n if (definition.entry) {\n attributes.push(new Entry(definition.entry.call, definition.entry.args ?? []));\n }\n\n if (definition.step) {\n attributes.push(new Step(definition.step.call, definition.step.args ?? []));\n }\n\n if (definition.exit) {\n attributes.push(new Exit(definition.exit.call, definition.exit.args ?? []));\n }\n\n return attributes;\n}\n\n/**\n * Creates a mapping of root node identifers to root node definitions, mixing in globally registered subtree root node definitions.\n * @param definition The root node definitions.\n * @returns A mapping of root node identifers to root node definitions, including globally registered subtree root node definitions.\n */\nfunction createRootNodeDefinitionMap(definition: RootNodeDefinition[]): RootNodeDefinitionMap {\n // Create a mapping of root node identifers to root node definitions.\n const rootNodeMap: RootNodeDefinitionMap = {};\n\n // Add in any registered subtree root node definitions.\n for (const [name, rootNodeDefinition] of Object.entries(Lookup.getSubtrees())) {\n // The name used when registering the subtree will be used as the root node identifier.\n rootNodeMap[name] = { ...rootNodeDefinition, id: name };\n }\n\n // Populate the map with the root node definitions that were included with the tree definition.\n // We do this after adding any registered subtrees as we want these to take presedence.\n for (const rootNodeDefinition of definition) {\n rootNodeMap[rootNodeDefinition.id ?? MAIN_ROOT_NODE_KEY] = rootNodeDefinition;\n }\n\n return rootNodeMap;\n}\n\n/**\n * Applies a guard path to every leaf of the tree to evaluate as part of each update.\n * @param root The main root tree node.\n */\nfunction applyLeafNodeGuardPaths(root: Root) {\n const nodePaths: Node[][] = [];\n\n const findLeafNodes = (path: Node[], node: Node) => {\n // Add the current node to the path.\n path = path.concat(node);\n\n // Check whether the current node is a leaf node.\n if (node.isLeafNode()) {\n nodePaths.push(path);\n } else {\n (node as Composite | Decorator).getChildren().forEach((child) => findLeafNodes(path, child));\n }\n };\n\n // Find all leaf node paths, starting from the root.\n findLeafNodes([], root);\n\n nodePaths.forEach((path) => {\n // Each node in the current path will have to be assigned a guard path, working from the root outwards.\n for (let depth = 0; depth < path.length; depth++) {\n // Get the node in the path at the current depth.\n const currentNode = path[depth];\n\n // The node may already have been assigned a guard path, if so just skip it.\n if (currentNode.hasGuardPath()) {\n continue;\n }\n\n // Create the guard path for the current node.\n const guardPath = new GuardPath(\n path\n .slice(0, depth + 1)\n .map((node) => ({ node, guards: node.getGuardAttributes() }))\n .filter((details) => details.guards.length > 0)\n );\n\n // Assign the guard path to the current node.\n currentNode.setGuardPath(guardPath);\n }\n });\n}\n", "import State, { AnyState } from \"./State\";\nimport Lookup from \"./Lookup\";\nimport Node from \"./nodes/Node\";\nimport Root from \"./nodes/decorator/Root\";\nimport Composite from \"./nodes/composite/Composite\";\nimport Decorator from \"./nodes/decorator/Decorator\";\nimport { Agent, GlobalFunction } from \"./Agent\";\nimport { CallbackAttributeDetails } from \"./attributes/callbacks/Callback\";\nimport { GuardAttributeDetails } from \"./attributes/guards/Guard\";\nimport { BehaviourTreeOptions } from \"./BehaviourTreeOptions\";\nimport { convertMDSLToJSON } from \"./mdsl/MDSLDefinitionParser\";\nimport { RootNodeDefinition } from \"./BehaviourTreeDefinition\";\nimport { validateDefinition, validateJSONDefinition } from \"./BehaviourTreeDefinitionValidator\";\nimport buildRootNode from \"./BehaviourTreeBuilder\";\nimport { isNullOrUndefined } from \"./BehaviourTreeDefinitionUtilities\";\n\n// Purely for outside inspection of the tree.\nexport type FlattenedTreeNode = {\n id: string;\n type: string;\n caption: string;\n state: AnyState;\n guards: GuardAttributeDetails[];\n callbacks: CallbackAttributeDetails[];\n args: any[];\n parentId: string | null;\n};\n\n/**\n * A representation of a behaviour tree.\n */\nexport class BehaviourTree {\n /**\n * The main root tree node.\n */\n public readonly rootNode: Root;\n\n /**\n * Creates a new instance of the BehaviourTree class.\n * @param definition The behaviour tree definition as either an MDSL string, root node definition object or array of root node definition objects.\n * @param agent The agent instance that this behaviour tree is modelling behaviour for.\n * @param options The behaviour tree options object.\n */\n constructor(\n definition: string | RootNodeDefinition | RootNodeDefinition[],\n private agent: Agent,\n private options: BehaviourTreeOptions = {}\n ) {\n // The tree definition must be defined.\n if (isNullOrUndefined(definition)) {\n throw new Error(\"tree definition not defined\");\n }\n\n // The agent must be defined and not null.\n if (typeof agent !== \"object\" || agent === null) {\n throw new Error(\"the agent must be an object and not null\");\n }\n\n // We should validate the definition before we try to build the tree nodes.\n const { succeeded, errorMessage, json } = validateDefinition(definition);\n\n // Did our validation fail without error?\n if (!succeeded) {\n throw new Error(`invalid definition: ${errorMessage}`);\n }\n\n // Double check that we did actually get our json definition as part of our definition validtion.\n if (!json) {\n throw new Error(\n \"expected json definition to be returned as part of successful definition validation response\"\n );\n }\n\n try {\n // Create the populated tree of behaviour tree nodes and get the root node.\n this.rootNode = buildRootNode(json);\n } catch (exception) {\n // There was an issue in trying build and populate the behaviour tree.\n throw new Error(`error building tree: ${(exception as Error).message}`);\n }\n }\n\n /**\n * Gets whether the tree is in the RUNNING state.\n * @returns true if the tree is in the RUNNING state, otherwise false.\n */\n isRunning() {\n return this.rootNode.getState() === State.RUNNING;\n }\n\n /**\n * Gets the current tree state of SUCCEEDED, FAILED, READY or RUNNING.\n * @returns The current tree state.\n */\n getState() {\n return this.rootNode.getState();\n }\n\n /**\n * Step the tree.\n * 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.\n * 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\n * 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.\n *\n * 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.\n */\n step() {\n // If the root node has already been stepped to completion then we need to reset it.\n if (this.rootNode.getState() === State.SUCCEEDED || this.rootNode.getState() === State.FAILED) {\n this.rootNode.reset();\n }\n\n try {\n this.rootNode.update(this.agent, this.options);\n } catch (exception) {\n throw new Error(`error stepping tree: ${(exception as Error).message}`);\n }\n }\n\n /**\n * Resets the tree from the root node outwards to each nested node, giving each a state of READY.\n */\n reset() {\n this.rootNode.reset();\n }\n\n /**\n * Gets the flattened details of every node in the tree.\n * @returns The flattened details of every node in the tree.\n */\n getFlattenedNodeDetails(): FlattenedTreeNode[] {\n // Create an empty flattened array of tree nodes.\n const flattenedTreeNodes: FlattenedTreeNode[] = [];\n\n /**\n * Helper function to process a node instance and push details into the flattened tree nodes array.\n * @param node The current node.\n * @param parentUid The UID of the node parent, or null if the node is the main root node.\n */\n const processNode = (node: Node, parentUid: string | null) => {\n // Get the guard and callback attribute details for this node.\n const guards = node\n .getAttributes()\n .filter((attribute) => attribute.isGuard())\n .map((attribute) => attribute.getDetails()) as GuardAttributeDetails[];\n const callbacks = node\n .getAttributes()\n .filter((attribute) => !attribute.isGuard())\n .map((attribute) => attribute.getDetails()) as CallbackAttributeDetails[];\n\n // Push the current node into the flattened nodes array.\n flattenedTreeNodes.push({\n id: node.getUid(),\n type: node.getType(),\n caption: node.getName(),\n state: node.getState(),\n guards,\n callbacks,\n args: node.getArguments(),\n parentId: parentUid\n });\n\n // Process each of the nodes children if it is not a leaf node.\n if (!node.isLeafNode()) {\n (node as Composite | Decorator)\n .getChildren()\n .forEach((child) => processNode(child, (node as Composite | Decorator).getUid()));\n }\n };\n\n // Convert the nested node structure into a flattened array of node details.\n processNode(this.rootNode, null);\n\n return flattenedTreeNodes;\n }\n\n /**\n * Registers the action/condition/guard/callback function or subtree with the given name.\n * @param name The name of the function or subtree to register.\n * @param value The function or subtree definition to register.\n */\n static register(name: string, value: GlobalFunction | string | RootNodeDefinition) {\n // Are we going to register a action/condition/guard/callback function?\n if (typeof value === \"function\") {\n Lookup.setFunc(name, value);\n return;\n }\n\n // We are not registering an action/condition/guard/callback function, so we must be registering a subtree.\n if (typeof value === \"string\") {\n let rootNodeDefinitions: RootNodeDefinition[];\n\n // We will assume that any string passed in will be a mdsl definition.\n try {\n rootNodeDefinitions = convertMDSLToJSON(value);\n } catch (exception) {\n throw new Error(`error registering definition, invalid MDSL: ${(exception as Error).message}`);\n }\n\n // This function should only ever be called with a definition containing a single unnamed root node.\n if (rootNodeDefinitions.length != 1 || rootNodeDefinitions[0].id !== null) {\n throw new Error(\"error registering definition: expected a single unnamed root node\");\n }\n\n try {\n // We should validate the subtree as we don't want invalid subtrees available via the lookup.\n const { succeeded, errorMessage } = validateJSONDefinition(rootNodeDefinitions[0]);\n\n // Did our validation fail without error?\n if (!succeeded) {\n throw new Error(errorMessage);\n }\n } catch (exception) {\n throw new Error(`error registering definition: ${(exception as Error).message}`);\n }\n\n // Everything seems hunky-dory, register the subtree.\n Lookup.setSubtree(name, rootNodeDefinitions[0]);\n } else if (typeof value === \"object\" && !Array.isArray(value)) {\n // We will assume that any object passed in is a root node definition.\n\n try {\n // We should validate the subtree as we don't want invalid subtrees available via the lookup.\n const { succeeded, errorMessage } = validateJSONDefinition(value);\n\n // Did our validation fail without error?\n if (!succeeded) {\n throw new Error(errorMessage);\n }\n } catch (exception) {\n throw new Error(`error registering definition: ${(exception as Error).message}`);\n }\n\n // Everything seems hunky-dory, register the subtree.\n Lookup.setSubtree(name, value);\n } else {\n throw new Error(\"unexpected value, expected string mdsl definition, root node json definition or function\");\n }\n }\n\n /**\n * Unregisters the registered action/condition/guard/callback function or subtree with the given name.\n * @param name The name of the registered action/condition/guard/callback function or subtree to unregister.\n */\n static unregister(name: string): void {\n Lookup.remove(name);\n }\n\n /**\n * Unregister all registered action/condition/guard/callback functions and subtrees.\n */\n static unregisterAll(): void {\n Lookup.empty();\n }\n}\n"], - "mappings": "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", + "sourcesContent": ["\"use strict\";\r\nObject.defineProperty(exports, \"__esModule\", { value: true });\r\nexports.Participant = void 0;\r\n/**\r\n * A participant that holds a number of tickets.\r\n */\r\nvar Participant = /** @class */ (function () {\r\n /**\r\n * Creates an instance of the Participant class.\r\n * @param participant The actual participant.\r\n * @param tickets The number of tickets held by the participant.\r\n */\r\n function Participant(participant, tickets) {\r\n if (tickets === void 0) { tickets = 1; }\r\n this._participant = participant;\r\n this._tickets = tickets;\r\n }\r\n Object.defineProperty(Participant.prototype, \"participant\", {\r\n /** Gets the actual participant. */\r\n get: function () {\r\n return this._participant;\r\n },\r\n enumerable: false,\r\n configurable: true\r\n });\r\n Object.defineProperty(Participant.prototype, \"tickets\", {\r\n /** Gets or sets the number of tickets held by the participant. */\r\n get: function () {\r\n return this._tickets;\r\n },\r\n set: function (value) {\r\n this._tickets = value;\r\n },\r\n enumerable: false,\r\n configurable: true\r\n });\r\n return Participant;\r\n}());\r\nexports.Participant = Participant;\r\n", "\"use strict\";\r\nObject.defineProperty(exports, \"__esModule\", { value: true });\r\nexports.isNaturalNumber = exports.isNullOrUndefined = void 0;\r\n/**\r\n * Gets whether the value provided is null or undefined.\r\n * @param value The value to check.\r\n * @returns Whether the value provided is null or undefined.\r\n */\r\nfunction isNullOrUndefined(value) {\r\n return value === null || value === undefined;\r\n}\r\nexports.isNullOrUndefined = isNullOrUndefined;\r\n/**\r\n * Gets whether the value provided is a natural number.\r\n * @param value The value to check.\r\n * @returns Whether the value provided is a natural number.\r\n */\r\nfunction isNaturalNumber(value) {\r\n return typeof value === \"number\" && value >= 1 && Math.floor(value) === value;\r\n}\r\nexports.isNaturalNumber = isNaturalNumber;\r\n", "\"use strict\";\r\nObject.defineProperty(exports, \"__esModule\", { value: true });\r\nexports.Lotto = void 0;\r\nvar Participant_1 = require(\"./Participant\");\r\nvar Utilities_1 = require(\"./Utilities\");\r\n/**\r\n * Represents a lotto consisting of a number of pickable ticket-holding participants.\r\n */\r\nvar Lotto = /** @class */ (function () {\r\n /**\r\n * Creates a new instance of Lotto.\r\n * @param customRandom The custom RNG to use in place of Math.random().\r\n */\r\n function Lotto(customRandom) {\r\n /** The array of participants that are holding tickets in the lotto. */\r\n this._participants = [];\r\n this._customRandom = customRandom;\r\n }\r\n /**\r\n * Adds a participant with the specified number of tickets, or adds to the participant ticket count if the participant already holds tickets.\r\n * @param participant The participant to add or to increase the ticket count for if they already hold tickets.\r\n * @param tickets The number of tickets, defaults to 1.\r\n * @returns The Lotto instance.\r\n */\r\n Lotto.prototype.add = function (participant, tickets) {\r\n if (tickets === void 0) { tickets = 1; }\r\n // Check that we have a valid ticket count.\r\n if (!(0, Utilities_1.isNaturalNumber)(tickets)) {\r\n throw new Error(\"tickets value must be a natural number\");\r\n }\r\n // Check whether this participant has already been added.\r\n var existingParticipant = this._participants.find(function (part) { return part.participant === participant; });\r\n if (existingParticipant) {\r\n // The participant has already been added to the lotto so just add to their ticket count.\r\n existingParticipant.tickets += tickets;\r\n }\r\n else {\r\n // The participant is not part of the lotto so we should add them.\r\n this._participants.push(new Participant_1.Participant(participant, tickets));\r\n }\r\n return this;\r\n };\r\n /**\r\n * Removes the specified number of tickets for the given participant from the draw, or all tickets if a ticket number is not defined.\r\n * @param participant The participant to remove tickets for.\r\n * @param tickets The number of tickets to remove, or undefined if all tickets are to be removed.\r\n * @returns The Lotto instance.\r\n */\r\n Lotto.prototype.remove = function (participant, tickets) {\r\n // Attempt to get the existing participant.\r\n var existingParticipant = this._participants.find(function (part) { return part.participant === participant; });\r\n // There is nothing to do if the specified participant isn't even part of the lotto.\r\n if (!existingParticipant) {\r\n return this;\r\n }\r\n // Check whether a tickets value was given.\r\n if (tickets !== undefined) {\r\n // Check that we have a valid ticket count.\r\n if (!(0, Utilities_1.isNaturalNumber)(tickets)) {\r\n throw new Error(\"tickets value must be a natural number\");\r\n }\r\n existingParticipant.tickets -= tickets;\r\n // If the participant no longer holds any tickets then they should be removed.\r\n if (existingParticipant.tickets < 1) {\r\n this._participants = this._participants.filter(function (part) { return part !== existingParticipant; });\r\n }\r\n }\r\n else {\r\n // We are removing all tickets for the participant so just remove them from the lotto.\r\n this._participants = this._participants.filter(function (part) { return part !== existingParticipant; });\r\n }\r\n return this;\r\n };\r\n /**\r\n * Draw a winning ticket and return the participant that holds the ticket.\r\n * @param options The draw options.\r\n * @returns The participant that holds the winning ticket.\r\n */\r\n Lotto.prototype.draw = function (options) {\r\n if (options === void 0) { options = {}; }\r\n // If we have no participants then just return null.\r\n if (this._participants.length === 0) {\r\n return null;\r\n }\r\n var redrawable = (0, Utilities_1.isNullOrUndefined)(options.redrawable) ? true : options.redrawable;\r\n var pickable = [];\r\n this._participants.forEach(function (_a) {\r\n var participant = _a.participant, tickets = _a.tickets;\r\n for (var ticketCount = 0; ticketCount < tickets; ticketCount++) {\r\n pickable.push(participant);\r\n }\r\n });\r\n var random;\r\n // We need a random floating-point number between 0 (inclusive) and 1 to scale up to pick our winner.\r\n // If a custom random function exists then we should use that or fall back to Math.random().\r\n if (this._customRandom) {\r\n // Call our custom random function to get a random floating-point number.\r\n random = this._customRandom();\r\n // Verify that the result of calling our custom random function is a number between 0 (inclusive) and 1.\r\n if (typeof random !== \"number\" || random < 0 || random >= 1) {\r\n throw new Error(\"the 'random' function provided did not return a number between 0 (inclusive) and 1\");\r\n }\r\n }\r\n else {\r\n // No custom random function was defined so just use good ol' Math.random().\r\n random = Math.random();\r\n }\r\n // Pick a winning participant.\r\n var winner = pickable[Math.floor(random * pickable.length)];\r\n // If the ticket isn't redrawable then we should remove a ticket from the winning participants ticket count.\r\n if (!redrawable) {\r\n this.remove(winner, 1);\r\n }\r\n // Return the winning participant.\r\n return winner;\r\n };\r\n /**\r\n * Draws multiple winning tickets and return an array of the participants that hold the winning tickets.\r\n * @param tickets The number of winning tickets to draw.\r\n * @param options The draw multiple options.\r\n * @returns An array of the participants that hold the winning tickets.\r\n */\r\n Lotto.prototype.drawMultiple = function (tickets, options) {\r\n if (options === void 0) { options = {}; }\r\n var uniqueResults = (0, Utilities_1.isNullOrUndefined)(options.unique) ? false : options.unique;\r\n // Handle cases where the user has asked for zero tickets (no idea why they would do this be we should trust them).\r\n if (tickets === 0) {\r\n return [];\r\n }\r\n // Now that we know out tickets value is not zero we should check that it is a valid natural number.\r\n if (!(0, Utilities_1.isNaturalNumber)(tickets)) {\r\n throw new Error(\"tickets value must be a natural number\");\r\n }\r\n var result = [];\r\n // Keep drawing tickets until we either reach the number of required tickets or we simply run out of tickets to draw.\r\n // We can run out of tickets to draw if 'options.redrawable' is explicity 'false' or we just had no participants when 'drawMultiple' was called.\r\n while (result.length < tickets && this._participants.length > 0) {\r\n result.push(this.draw(options));\r\n }\r\n // If the 'unique' draw option is set then we need to remove duplicates from the result list.\r\n if (uniqueResults) {\r\n // Create an array to store our unique results.\r\n var unique = [];\r\n // Iterate over all of our participants (with potential duplicates) and populate our array of unique values.\r\n for (var _i = 0, result_1 = result; _i < result_1.length; _i++) {\r\n var participant = result_1[_i];\r\n if (unique.indexOf(participant) === -1) {\r\n unique.push(participant);\r\n }\r\n }\r\n result = unique;\r\n }\r\n return result;\r\n };\r\n return Lotto;\r\n}());\r\nexports.Lotto = Lotto;\r\n", "\"use strict\";\r\nObject.defineProperty(exports, \"__esModule\", { value: true });\r\nexports.createLotto = void 0;\r\nvar Lotto_1 = require(\"./Lotto\");\r\n/**\r\n * A function that creates and returns a Lotto instance.\r\n * @param participantsOrOptions An array of initial participants or options relating to the creation of a Lotto instance.\r\n * @returns A new Lotto instance.\r\n */\r\nfunction createLotto(participantsOrOptions) {\r\n // If no initial participants or lotto options were provided as an argument then we can just return a new lotto instance now.\r\n if (!participantsOrOptions) {\r\n return new Lotto_1.Lotto();\r\n }\r\n // Check whether we were provided with an array of initial participants or a lotto options object.\r\n if (Array.isArray(participantsOrOptions)) {\r\n // We are dealing with a pre-defined array of participants.\r\n var participants = participantsOrOptions;\r\n var lotto_1 = new Lotto_1.Lotto();\r\n // If the lotto participants have been defined upfront then we will need to add them all to our lotto instance now.\r\n participants.forEach(function (_a) {\r\n var participant = _a[0], tokens = _a[1];\r\n return lotto_1.add(participant, tokens);\r\n });\r\n // Return the Lotto instance.\r\n return lotto_1;\r\n }\r\n else {\r\n // We are dealing with some lotto options.\r\n var random = participantsOrOptions.random, participants = participantsOrOptions.participants;\r\n // Create a Lotto instance passing the custom RNG function to use in place of Math.random() (which could be undefined).\r\n var lotto_2 = new Lotto_1.Lotto(random);\r\n // If the lotto participants have been defined upfront as part of the options then we will need to add them all to our lotto instance now.\r\n if (participants) {\r\n participants.forEach(function (_a) {\r\n var participant = _a[0], tokens = _a[1];\r\n return lotto_2.add(participant, tokens);\r\n });\r\n }\r\n // Return the Lotto instance.\r\n return lotto_2;\r\n }\r\n}\r\nexports.createLotto = createLotto;\r\n", "\"use strict\";\r\nObject.defineProperty(exports, \"__esModule\", { value: true });\r\nvar createLotto_1 = require(\"./createLotto\");\r\nexports.default = createLotto_1.createLotto;\r\n", "import State from \"./State\";\nimport { validateDefinition } from \"./BehaviourTreeDefinitionValidator\";\nimport { convertMDSLToJSON } from \"./mdsl/MDSLDefinitionParser\";\nimport { BehaviourTree, FlattenedTreeNode } from \"./BehaviourTree\";\nimport { BehaviourTreeOptions } from \"./BehaviourTreeOptions\";\n\nexport { BehaviourTree, State, convertMDSLToJSON, validateDefinition };\nexport type { FlattenedTreeNode, BehaviourTreeOptions };\n", "/**\n * Enumeration of node state types.\n */\nexport enum State {\n READY = \"mistreevous.ready\",\n RUNNING = \"mistreevous.running\",\n SUCCEEDED = \"mistreevous.succeeded\",\n FAILED = \"mistreevous.failed\"\n}\n\nexport { State as default };\n\nexport type CompleteState = State.SUCCEEDED | State.FAILED;\nexport type AnyState = State.READY | State.RUNNING | CompleteState;\n", "import {\n NodeDefinition,\n RootNodeDefinition,\n DecoratorNodeDefinition,\n CompositeNodeDefinition,\n AnyNodeDefinition,\n BranchNodeDefinition\n} from \"./BehaviourTreeDefinition\";\n\n/**\n * A type guard function that returns true if the specified node satisfies the RootNodeDefinition type.\n * @param node The node.\n * @returns A value of true if the specified node satisfies the RootNodeDefinition type.\n */\nexport function isRootNode(node: NodeDefinition): node is RootNodeDefinition {\n return node.type === \"root\";\n}\n\n/**\n * A type guard function that returns true if the specified node satisfies the BranchNodeDefinition type.\n * @param node The node.\n * @returns A value of true if the specified node satisfies the BranchNodeDefinition type.\n */\nexport function isBranchNode(node: NodeDefinition): node is BranchNodeDefinition {\n return node.type === \"branch\";\n}\n\n/**\n * A type guard function that returns true if the specified node satisfies the NodeDefinition type.\n * @param node The node.\n * @returns A value of true if the specified node satisfies the NodeDefinition type.\n */\nexport function isLeafNode(node: NodeDefinition): node is NodeDefinition {\n return [\"branch\", \"action\", \"condition\", \"wait\"].includes(node.type);\n}\n\n/**\n * A type guard function that returns true if the specified node satisfies the DecoratorNodeDefinition type.\n * @param node The node.\n * @returns A value of true if the specified node satisfies the DecoratorNodeDefinition type.\n */\nexport function isDecoratorNode(node: NodeDefinition): node is DecoratorNodeDefinition {\n return [\"root\", \"repeat\", \"retry\", \"flip\", \"succeed\", \"fail\"].includes(node.type);\n}\n\n/**\n * A type guard function that returns true if the specified node satisfies the CompositeNodeDefinition type.\n * @param node The node.\n * @returns A value of true if the specified node satisfies the CompositeNodeDefinition type.\n */\nexport function isCompositeNode(node: NodeDefinition): node is CompositeNodeDefinition {\n return [\"sequence\", \"selector\", \"lotto\", \"parallel\"].includes(node.type);\n}\n\n/**\n * Flatten a node definition into an array of all of its nested node definitions.\n * @param nodeDefinition The node definition to flatten.\n * @returns An array of all of nested node definitions.\n */\nexport function flattenDefinition(nodeDefinition: AnyNodeDefinition): AnyNodeDefinition[] {\n const nodes: AnyNodeDefinition[] = [];\n\n const processNode = (currentNodeDefinition: AnyNodeDefinition) => {\n nodes.push(currentNodeDefinition);\n\n if (isCompositeNode(currentNodeDefinition)) {\n currentNodeDefinition.children.forEach(processNode);\n } else if (isDecoratorNode(currentNodeDefinition)) {\n processNode(currentNodeDefinition.child);\n }\n };\n\n processNode(nodeDefinition);\n\n return nodes;\n}\n\n/**\n * Determines whether the passed value is an integer.\n * @param value The value to check.\n * @returns Whether the passed value is an integer.\n */\nexport function isInteger(value: unknown): boolean {\n return typeof value === \"number\" && Math.floor(value) === value;\n}\n\n/**\n * Determines whether the passed value is null or undefined.\n * @param value The value to check.\n * @returns Whether the passed value is null or undefined.\n */\nexport function isNullOrUndefined(value: unknown): boolean {\n return typeof value === \"undefined\" || value === null;\n}\n", "/**\n * A type defining an object that holds a reference to substitued string literals parsed from the definition.\n */\nexport type StringLiteralPlaceholders = { [key: string]: string };\n\n/**\n * Pop the next raw token from the specified array of tokens and throw an error if it wasn't the expected one.\n * @param tokens The array of tokens.\n * @param expected An optional string or array or items, one of which must match the next popped token.\n * @returns The popped token.\n */\nexport function popAndCheck(tokens: string[], expected?: string | string[]): string {\n // Get and remove the next token.\n const popped = tokens.shift();\n\n // We were expecting another token but there aren't any.\n if (popped === undefined) {\n throw new Error(\"unexpected end of definition\");\n }\n\n // Do we have an expected token/tokens array?\n if (expected != undefined) {\n // Get an array of expected values, if the popped token matches any then we are all good.\n const expectedValues = typeof expected === \"string\" ? [expected] : expected;\n\n // Check whether the popped token matches at least one of our expected items.\n var tokenMatchesExpectation = expectedValues.some((item) => popped.toUpperCase() === item.toUpperCase());\n\n // Throw an error if the popped token didn't match any of our expected items.\n if (!tokenMatchesExpectation) {\n const expectationString = expectedValues.map((item) => \"'\" + item + \"'\").join(\" or \");\n throw new Error(\"unexpected token found. Expected \" + expectationString + \" but got '\" + popped + \"'\");\n }\n }\n\n // Return the popped token.\n return popped;\n}\n\n/**\n * Swaps out any node/attribute argument string literals with placeholders.\n * @param definition The definition.\n * @returns An object containing a mapping of placeholders to original string values as well as the processed definition string.\n */\nexport function substituteStringLiterals(definition: string): {\n placeholders: StringLiteralPlaceholders;\n processedDefinition: string;\n} {\n // Create an object to hold the mapping of placeholders to original string values.\n const placeholders: StringLiteralPlaceholders = {};\n\n // Replace any string literals wrapped with double quotes in our definition with placeholders to be processed later.\n const processedDefinition = definition.replace(/\\\"(\\\\.|[^\"\\\\])*\\\"/g, (match) => {\n var strippedMatch = match.substring(1, match.length - 1);\n var placeholder = Object.keys(placeholders).find((key) => placeholders[key] === strippedMatch);\n\n // If we have no existing string literal match then create a new placeholder.\n if (!placeholder) {\n placeholder = `@@${Object.keys(placeholders).length}@@`;\n placeholders[placeholder] = strippedMatch;\n }\n\n return placeholder;\n });\n\n return { placeholders, processedDefinition };\n}\n\n/**\n * Parse the tree definition into an array of raw tokens.\n * @param definition The definition.\n * @returns An array of tokens parsed from the definition.\n */\nexport function parseTokensFromDefinition(definition: string): string[] {\n // Add some space around various important characters so that they can be plucked out easier as individual tokens.\n definition = definition.replace(/\\(/g, \" ( \");\n definition = definition.replace(/\\)/g, \" ) \");\n definition = definition.replace(/\\{/g, \" { \");\n definition = definition.replace(/\\}/g, \" } \");\n definition = definition.replace(/\\]/g, \" ] \");\n definition = definition.replace(/\\[/g, \" [ \");\n definition = definition.replace(/\\,/g, \" , \");\n\n // Split the definition into raw token form and return it.\n return definition.replace(/\\s+/g, \" \").trim().split(\" \");\n}\n", "import { StringLiteralPlaceholders, popAndCheck } from \"./MDSLUtilities\";\n\n/**\n * A type representing any node function argument.\n */\ntype Argument = {\n /**\n * The argument value.\n */\n value: T;\n /**\n * The argument type, used for validation.\n */\n type: string;\n};\n\ntype NullArgument = Argument & {\n type: \"null\";\n};\n\ntype BooleanArgument = Argument & {\n type: \"boolean\";\n};\n\ntype NumberArgument = Argument & {\n type: \"number\";\n /**\n * A flag defining whether the number argument value is a valid integer. (used for validation)\n */\n isInteger: boolean;\n};\n\ntype StringPlaceholderArgument = Argument & {\n type: \"string\";\n};\n\ntype IdentifierArgument = Argument & {\n type: \"identifier\";\n};\n\n/**\n * A type representing a reference to any node function argument.\n */\ntype AnyArgument = NullArgument | BooleanArgument | NumberArgument | StringPlaceholderArgument | IdentifierArgument;\n\n/**\n * Parse an array of argument definitions from the specified tokens array.\n * @param tokens The array tokens to parse the argument definitions from.\n * @param stringArgumentPlaceholders The mapping of string literal node argument placeholders to original values.\n * @param argumentValidator The argument validator function.\n * @param validationFailedMessage The exception message to throw if argument validation fails.\n * @returns An array of argument definitions parsed from the specified tokens array.\n */\nexport function parseArgumentTokens(\n tokens: string[],\n stringArgumentPlaceholders: StringLiteralPlaceholders\n): AnyArgument[] {\n const argumentList: AnyArgument[] = [];\n\n // If the next token is not a '[' or '(' then we have no arguments to parse.\n if (![\"[\", \"(\"].includes(tokens[0])) {\n return argumentList;\n }\n\n // Any lists of arguments will always be wrapped in '[]' for node arguments or '()' for attribute arguments.\n // We are looking for a '[' or '(' opener that wraps the argument tokens and the relevant closer.\n const closingToken = popAndCheck(tokens, [\"[\", \"(\"]) === \"[\" ? \"]\" : \")\";\n\n const argumentListTokens: string[] = [];\n\n // Grab all tokens between the '[' and ']' or '(' and ')'.\n while (tokens.length && tokens[0] !== closingToken) {\n // The next token is part of our arguments list.\n argumentListTokens.push(tokens.shift()!);\n }\n\n // Validate the order of the argument tokens. Each token must either be a ',' or a single argument that satisfies the validator.\n argumentListTokens.forEach((token, index) => {\n // Get whether this token should be an actual argument.\n const shouldBeArgumentToken = !(index & 1);\n\n // If the current token should be an actual argument then validate it, otherwise it should be a ',' token.\n if (shouldBeArgumentToken) {\n // Get the argument definition.\n const argumentDefinition = getArgumentDefinition(token, stringArgumentPlaceholders);\n\n // This is a valid argument!\n argumentList.push(argumentDefinition);\n } else {\n // The current token should be a ',' token.\n if (token !== \",\") {\n throw new Error(`invalid argument list, expected ',' or ']' but got '${token}'`);\n }\n }\n });\n\n // The arguments list should terminate with a ']' or ')' token, depending on the opener.\n popAndCheck(tokens, closingToken);\n\n // Return the arguments.\n return argumentList;\n}\n\n/**\n * Gets an argument value definition.\n * @param token The argument token.\n * @param stringArgumentPlaceholders The mapping of string literal node argument placeholders to original values.\n * @returns An argument value definition.\n */\nfunction getArgumentDefinition(token: string, stringArgumentPlaceholders: StringLiteralPlaceholders): AnyArgument {\n // Check whether the token represents a null value.\n if (token === \"null\") {\n return {\n value: null,\n type: \"null\"\n } as NullArgument;\n }\n\n // Check whether the token represents a boolean value.\n if (token === \"true\" || token === \"false\") {\n return {\n value: token === \"true\",\n type: \"boolean\"\n } as BooleanArgument;\n }\n\n // Check whether the token represents a number value.\n // TODO: Relies on broken isNaN - see MDN.\n // if (!Number.isNaN(token)) {\n if (!isNaN(token as any)) {\n return {\n value: parseFloat(token),\n isInteger: parseFloat(token) === parseInt(token, 10),\n type: \"number\"\n } as NumberArgument;\n }\n\n // Check whether the token is a placeholder (e.g. @@0@@) representing a string literal.\n if (token.match(/^@@\\d+@@$/g)) {\n return {\n value: stringArgumentPlaceholders[token].replace('\\\\\"', '\"'),\n type: \"string\"\n } as StringPlaceholderArgument;\n }\n\n // The only remaining option is that the argument value is an identifier.\n return {\n value: token,\n type: \"identifier\"\n } as IdentifierArgument;\n}\n", "import { NodeAttributeDefinition } from \"../BehaviourTreeDefinition\";\nimport { parseArgumentTokens } from \"./MDSLNodeArgumentParser\";\nimport { StringLiteralPlaceholders } from \"./MDSLUtilities\";\n\n/**\n * A type defining the attribute definitions of a node.\n */\ntype NodeAttributes = {\n while?: NodeAttributeDefinition;\n until?: NodeAttributeDefinition;\n entry?: NodeAttributeDefinition;\n exit?: NodeAttributeDefinition;\n step?: NodeAttributeDefinition;\n};\n\n/**\n * Parse any node attribute definitions from the specified tokens array.\n * @param tokens The array of remaining tokens.\n * @param stringArgumentPlaceholders The mapping of string literal node argument placeholders to original values.\n * @returns An object of attribute definitions defined by any directly following tokens.\n */\nexport function parseAttributeTokens(\n tokens: string[],\n stringArgumentPlaceholders: StringLiteralPlaceholders\n): NodeAttributes {\n const nodeAttributeNames: (keyof NodeAttributes)[] = [\"while\", \"until\", \"entry\", \"exit\", \"step\"];\n\n // Create an object to hold any attributes found.\n const attributes: NodeAttributes = {};\n\n // Try to get the name of the attribute for the next token.\n let nextAttributeName = tokens[0]?.toLowerCase() as keyof NodeAttributes;\n\n // Pull attribute tokens as well as their arguments off of the tokens stack until we have no more.\n while (nodeAttributeNames.includes(nextAttributeName)) {\n // Check to make sure that we have not already created an attribute definition of this type.\n if (attributes[nextAttributeName]) {\n throw new Error(`duplicate attribute '${tokens[0].toUpperCase()}' found for node`);\n }\n\n // Remove the attribute name token from the array of tokens.\n tokens.shift();\n\n // Grab the attribute arguments, assuming the first to be an identifier.\n const [attributeCallIdentifier, ...attributeArguments] = parseArgumentTokens(\n tokens,\n stringArgumentPlaceholders\n );\n\n // The first attribute argument has to be an identifer, this will reference an agent function.\n if (attributeCallIdentifier?.type !== \"identifier\") {\n throw new Error(\"expected agent function name identifier argument for attribute\");\n }\n\n // Any attribute arguments (other than the expected call identifier) must have a type of string, number, boolean or null.\n attributeArguments\n .filter((arg) => arg.type === \"identifier\")\n .forEach((arg) => {\n throw new Error(\n `invalid attribute argument value '${arg.value}', must be string, number, boolean or null`\n );\n });\n\n // Create the attribute definition and add it to the object of attribute definitions found.\n attributes[nextAttributeName] = {\n call: attributeCallIdentifier.value,\n args: attributeArguments.map(({ value }) => value)\n };\n\n // Try to get the next attribute name token, as there could be multiple.\n nextAttributeName = tokens[0]?.toLowerCase() as keyof NodeAttributes;\n }\n\n return attributes;\n}\n", "import {\n ActionNodeDefinition,\n AnyChildNodeDefinition,\n AnyNodeDefinition,\n BranchNodeDefinition,\n ConditionNodeDefinition,\n FailNodeDefinition,\n FlipNodeDefinition,\n LottoNodeDefinition,\n ParallelNodeDefinition,\n RepeatNodeDefinition,\n RetryNodeDefinition,\n RootNodeDefinition,\n SelectorNodeDefinition,\n SequenceNodeDefinition,\n SucceedNodeDefinition,\n WaitNodeDefinition\n} from \"../BehaviourTreeDefinition\";\nimport {\n isCompositeNode,\n isDecoratorNode,\n isLeafNode,\n isNullOrUndefined,\n isRootNode\n} from \"../BehaviourTreeDefinitionUtilities\";\nimport { parseArgumentTokens } from \"./MDSLNodeArgumentParser\";\nimport { parseAttributeTokens } from \"./MDSLNodeAttributeParser\";\nimport {\n StringLiteralPlaceholders,\n parseTokensFromDefinition,\n popAndCheck,\n substituteStringLiterals\n} from \"./MDSLUtilities\";\n\n/**\n * Convert the MDSL tree definition string into an equivalent JSON definition.\n * @param definition The tree definition string as MDSL.\n * @returns The root node JSON definitions.\n */\nexport function convertMDSLToJSON(definition: string): RootNodeDefinition[] {\n // Swap out any node/attribute argument string literals with a placeholder and get a mapping of placeholders to original values as well as the processed definition.\n const { placeholders, processedDefinition } = substituteStringLiterals(definition);\n\n // Parse our definition definition string into an array of raw tokens.\n const tokens = parseTokensFromDefinition(processedDefinition);\n\n return convertTokensToJSONDefinition(tokens, placeholders);\n}\n\n/**\n * Converts the specified tree definition tokens into a JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The root node JSON definitions.\n */\nfunction convertTokensToJSONDefinition(\n tokens: string[],\n stringLiteralPlaceholders: StringLiteralPlaceholders\n): RootNodeDefinition[] {\n // There must be at least 3 tokens for the tree definition to be valid. 'ROOT', '{' and '}'.\n if (tokens.length < 3) {\n throw new Error(\"invalid token count\");\n }\n\n // We should have a matching number of '{' and '}' tokens. If not, then there are scopes that have not been properly closed.\n if (tokens.filter((token) => token === \"{\").length !== tokens.filter((token) => token === \"}\").length) {\n throw new Error(\"scope character mismatch\");\n }\n\n // Create an array of tree stack arrays where root nodes will always be at the botton and the current composite/decorator node at the top.\n // There should be an element in this array for every root node defined and every element should be an array with a root note as the first element.\n // E.g. A definition with two root nodes defined:\n // [\n // [root, lotto, sequence],\n // [root, selector]\n // ]\n const treeStacks: [Partial, ...Partial[]][] = [];\n\n // Create an array of all root node definitions that we create.\n const rootNodes: Partial[] = [];\n\n // A helper function used to push node definitions onto the tree stack.\n const pushNode = (node: AnyNodeDefinition) => {\n // If the node is a root node then we need to create a new tree stack array with the root node at the root.\n if (isRootNode(node)) {\n // We need to double-check that this root node is not the child of another node.\n // We can do this by checking whether the top tree stack is not empty (contains an existing node)\n if (treeStacks[treeStacks.length - 1]?.length) {\n throw new Error(\"a root node cannot be the child of another node\");\n }\n\n // Add the root node definition to our array of all parsed root node definitions.\n rootNodes.push(node);\n\n // Add the root node definition to the root of a new tree stack.\n treeStacks.push([node]);\n\n return;\n }\n\n // All non-root nodes should be pushed after their root nodes so handle cases\n // where we may not have any tree stacks or our top-most tree stack is empty.\n if (!treeStacks.length || !treeStacks[treeStacks.length - 1].length) {\n throw new Error(\"expected root node at base of definition\");\n }\n\n // Get the current tree stack that we are populating.\n const topTreeStack = treeStacks[treeStacks.length - 1];\n\n // Get the top-most node in the current tree stack, this will be a composite/decorator node\n // for which we will populate its children array if composite or setting its child if a decorator.\n const topTreeStackTopNode = topTreeStack[topTreeStack.length - 1] as AnyNodeDefinition;\n\n // If the top-most node in the current root stack is a composite or decorator\n // node then the current node should be added as a child of the top-most node.\n if (isCompositeNode(topTreeStackTopNode)) {\n topTreeStackTopNode.children = topTreeStackTopNode.children || [];\n topTreeStackTopNode.children.push(node);\n } else if (isDecoratorNode(topTreeStackTopNode)) {\n // If the top node already has a child node set then throw an error as a decorator should only have a single child.\n if (topTreeStackTopNode.child) {\n throw new Error(\"a decorator node must only have a single child node\");\n }\n\n topTreeStackTopNode.child = node;\n }\n\n // If the node we are adding is also a composite or decorator node, then we should push it\n // onto the current tree stack, as subsequent nodes will be added as its child/children.\n if (!isLeafNode(node)) {\n topTreeStack.push(node);\n }\n };\n\n // A helper function used to pop the top-most node definition off of the tree stack and return it.\n const popNode = (): AnyNodeDefinition | null => {\n let poppedNode: AnyNodeDefinition | null = null;\n\n // Get the current tree stack that we are populating.\n const topTreeStack = treeStacks[treeStacks.length - 1];\n\n // Pop the top-most node in the current tree stack if there is one.\n if (topTreeStack.length) {\n poppedNode = topTreeStack.pop() as AnyNodeDefinition;\n }\n\n // We don't want any empty tree stacks in our stack of tree stacks.\n if (!topTreeStack.length) {\n treeStacks.pop();\n }\n\n return poppedNode;\n };\n\n // We should keep processing the raw tokens until we run out of them.\n while (tokens.length) {\n // Grab the next token.\n const token = tokens.shift()!;\n\n // How we create the next node depends on the current raw token value.\n switch (token.toUpperCase()) {\n case \"ROOT\": {\n pushNode(createRootNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"SUCCEED\": {\n pushNode(createSucceedNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"FAIL\": {\n pushNode(createFailNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"FLIP\": {\n pushNode(createFlipNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"REPEAT\": {\n pushNode(createRepeatNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"RETRY\": {\n pushNode(createRetryNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"SEQUENCE\": {\n pushNode(createSequenceNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"SELECTOR\": {\n pushNode(createSelectorNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"PARALLEL\": {\n pushNode(createParallelNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"LOTTO\": {\n pushNode(createLottoNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"ACTION\": {\n pushNode(createActionNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"CONDITION\": {\n pushNode(createConditionNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"WAIT\": {\n pushNode(createWaitNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"BRANCH\": {\n pushNode(createBranchNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"}\": {\n // The '}' character closes the current scope and means that we have to pop a node off of the current stack.\n const poppedNode = popNode();\n\n // Now that we have a node definition we can carry out any validation that may require the node to be fully populated.\n if (poppedNode) {\n validatePoppedNode(poppedNode);\n }\n\n break;\n }\n\n default: {\n throw new Error(`unexpected token: ${token}`);\n }\n }\n }\n\n return rootNodes as RootNodeDefinition[];\n}\n\n/**\n * Creates a root node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The root node JSON definition.\n */\nfunction createRootNode(tokens: string[], stringLiteralPlaceholders: StringLiteralPlaceholders): RootNodeDefinition {\n // Create the root node definition.\n let node = {\n type: \"root\",\n id: undefined\n } as RootNodeDefinition;\n\n // Parse any node arguments, we should only have one if any which will be an identifier argument for the root identifier.\n const nodeArguments = parseArgumentTokens(tokens, stringLiteralPlaceholders);\n\n // Check whether any node arguments were defined.\n if (nodeArguments.length) {\n // We should only have one argument, if any, which will be an identifier argument for the root identifier.\n if (nodeArguments.length === 1 && nodeArguments[0].type === \"identifier\") {\n // The root node identifier will be the first and only node argument value.\n node.id = nodeArguments[0].value as string;\n } else {\n throw new Error(\"expected single root name argument\");\n }\n }\n\n // Grab any node attribute definitions and spread them into the node definition.\n node = { ...node, ...parseAttributeTokens(tokens, stringLiteralPlaceholders) };\n\n // This is a decorator node, so we expect an opening '{'.\n popAndCheck(tokens, \"{\");\n\n // Return the root node definition.\n return node;\n}\n\n/**\n * Creates a succeed node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The succeed node JSON definition.\n */\nfunction createSucceedNode(\n tokens: string[],\n stringLiteralPlaceholders: StringLiteralPlaceholders\n): SucceedNodeDefinition {\n const node = {\n type: \"succeed\",\n ...parseAttributeTokens(tokens, stringLiteralPlaceholders)\n } as SucceedNodeDefinition;\n\n // This is a decorator node, so we expect an opening '{'.\n popAndCheck(tokens, \"{\");\n\n // Return the succeed node definition.\n return node;\n}\n\n/**\n * Creates a fail node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The fail node JSON definition.\n */\nfunction createFailNode(tokens: string[], stringLiteralPlaceholders: StringLiteralPlaceholders): FailNodeDefinition {\n const node = {\n type: \"fail\",\n ...parseAttributeTokens(tokens, stringLiteralPlaceholders)\n } as FailNodeDefinition;\n\n // This is a decorator node, so we expect an opening '{'.\n popAndCheck(tokens, \"{\");\n\n // Return the fail node definition.\n return node;\n}\n\n/**\n * Creates a flip node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The flip node JSON definition.\n */\nfunction createFlipNode(tokens: string[], stringLiteralPlaceholders: StringLiteralPlaceholders): FlipNodeDefinition {\n const node = {\n type: \"flip\",\n ...parseAttributeTokens(tokens, stringLiteralPlaceholders)\n } as FlipNodeDefinition;\n\n // This is a decorator node, so we expect an opening '{'.\n popAndCheck(tokens, \"{\");\n\n // Return the flip node definition.\n return node;\n}\n\n/**\n * Creates a repeat node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The repeat node JSON definition.\n */\nfunction createRepeatNode(\n tokens: string[],\n stringLiteralPlaceholders: StringLiteralPlaceholders\n): RepeatNodeDefinition {\n let node = { type: \"repeat\" } as RepeatNodeDefinition;\n\n // Get the node arguments.\n const nodeArguments = parseArgumentTokens(tokens, stringLiteralPlaceholders);\n\n // The arguments of a repeat node are optional. We may have:\n // - No node arguments, in which case the repeat note will iterate indefinitely.\n // - One node argument which will be the explicit number of iterations to make.\n // - Two node arguments which define the min and max iteration bounds from which a random iteration count will be picked.\n if (nodeArguments.length) {\n // All repeat node arguments MUST be of type number and must be integer.\n nodeArguments\n .filter((arg) => arg.type !== \"number\" || !arg.isInteger)\n .forEach(() => {\n throw new Error(`repeat node iteration counts must be integer values`);\n });\n\n // We should have got one or two iteration counts.\n if (nodeArguments.length === 1) {\n // A static iteration count was defined.\n node.iterations = nodeArguments[0].value as number;\n\n // A repeat node must have a positive number of iterations if defined.\n if (node.iterations < 0) {\n throw new Error(\"a repeat node must have a positive number of iterations if defined\");\n }\n } else if (nodeArguments.length === 2) {\n // A minimum and maximum iteration count was defined.\n node.iterations = [nodeArguments[0].value as number, nodeArguments[1].value as number];\n\n // A repeat node must have a positive min and max iteration count if they are defined.\n if (node.iterations[0] < 0 || node.iterations[1] < 0) {\n throw new Error(\"a repeat node must have a positive minimum and maximum iteration count if defined\");\n }\n\n // A repeat node must not have an minimum iteration count that exceeds the maximum iteration count.\n if (node.iterations[0] > node.iterations[1]) {\n throw new Error(\n \"a repeat node must not have a minimum iteration count that exceeds the maximum iteration count\"\n );\n }\n } else {\n // An incorrect number of iteration counts was defined.\n throw new Error(\"invalid number of repeat node iteration count arguments defined\");\n }\n }\n\n // Grab any node attribute definitions and spread them into the node definition.\n node = { ...node, ...parseAttributeTokens(tokens, stringLiteralPlaceholders) };\n\n // This is a decorator node, so we expect an opening '{'.\n popAndCheck(tokens, \"{\");\n\n // Return the repeat node definition.\n return node;\n}\n\n/**\n * Creates a retry node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The retry node JSON definition.\n */\nfunction createRetryNode(tokens: string[], stringLiteralPlaceholders: StringLiteralPlaceholders): RetryNodeDefinition {\n let node = { type: \"retry\" } as RetryNodeDefinition;\n\n // Get the node arguments.\n const nodeArguments = parseArgumentTokens(tokens, stringLiteralPlaceholders);\n\n // The arguments of a retry node are optional. We may have:\n // - No node arguments, in which case the retry note will attempt indefinitely.\n // - One node argument which will be the explicit number of attempts to make.\n // - Two node arguments which define the min and max attempt bounds from which a random attempt count will be picked.\n if (nodeArguments.length) {\n // All retry node arguments MUST be of type number and must be integer.\n nodeArguments\n .filter((arg) => arg.type !== \"number\" || !arg.isInteger)\n .forEach(() => {\n throw new Error(`retry node attempt counts must be integer values`);\n });\n\n // We should have got one or two attempt counts.\n if (nodeArguments.length === 1) {\n // A static attempt count was defined.\n node.attempts = nodeArguments[0].value as number;\n\n // A retry node must have a positive number of attempts if defined.\n if (node.attempts < 0) {\n throw new Error(\"a retry node must have a positive number of attempts if defined\");\n }\n } else if (nodeArguments.length === 2) {\n // A minimum and maximum attempt count was defined.\n node.attempts = [nodeArguments[0].value as number, nodeArguments[1].value as number];\n\n // A retry node must have a positive min and max attempts count if they are defined.\n if (node.attempts[0] < 0 || node.attempts[1] < 0) {\n throw new Error(\"a retry node must have a positive minimum and maximum attempt count if defined\");\n }\n\n // A retry node must not have a minimum attempt count that exceeds the maximum attempt count.\n if (node.attempts[0] > node.attempts[1]) {\n throw new Error(\n \"a retry node must not have a minimum attempt count that exceeds the maximum attempt count\"\n );\n }\n } else {\n // An incorrect number of attempt counts was defined.\n throw new Error(\"invalid number of retry node attempt count arguments defined\");\n }\n }\n\n // Grab any node attribute definitions and spread them into the node definition.\n node = { ...node, ...parseAttributeTokens(tokens, stringLiteralPlaceholders) };\n\n // This is a decorator node, so we expect an opening '{'.\n popAndCheck(tokens, \"{\");\n\n // Return the retry node definition.\n return node;\n}\n\n/**\n * Creates a sequence node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The sequence node JSON definition.\n */\nfunction createSequenceNode(\n tokens: string[],\n stringLiteralPlaceholders: StringLiteralPlaceholders\n): SequenceNodeDefinition {\n const node = {\n type: \"sequence\",\n ...parseAttributeTokens(tokens, stringLiteralPlaceholders)\n } as SequenceNodeDefinition;\n\n // This is a composite node, so we expect an opening '{'.\n popAndCheck(tokens, \"{\");\n\n // Return the sequence node definition.\n return node;\n}\n\n/**\n * Creates a selector node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The selector node JSON definition.\n */\nfunction createSelectorNode(\n tokens: string[],\n stringLiteralPlaceholders: StringLiteralPlaceholders\n): SelectorNodeDefinition {\n const node = {\n type: \"selector\",\n ...parseAttributeTokens(tokens, stringLiteralPlaceholders)\n } as SelectorNodeDefinition;\n\n // This is a composite node, so we expect an opening '{'.\n popAndCheck(tokens, \"{\");\n\n // Return the selector node definition.\n return node;\n}\n\n/**\n * Creates a parallel node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The parallel node JSON definition.\n */\nfunction createParallelNode(\n tokens: string[],\n stringLiteralPlaceholders: StringLiteralPlaceholders\n): ParallelNodeDefinition {\n const node = {\n type: \"parallel\",\n ...parseAttributeTokens(tokens, stringLiteralPlaceholders)\n } as ParallelNodeDefinition;\n\n // This is a composite node, so we expect an opening '{'.\n popAndCheck(tokens, \"{\");\n\n // Return the parallel node definition.\n return node;\n}\n\n/**\n * Creates a lotto node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The lotto node JSON definition.\n */\nfunction createLottoNode(tokens: string[], stringLiteralPlaceholders: StringLiteralPlaceholders): LottoNodeDefinition {\n // If any node arguments have been defined then they must be our weights.\n const nodeArguments = parseArgumentTokens(tokens, stringLiteralPlaceholders);\n\n // All lotto node arguments MUST be of type number and must be positive integers.\n nodeArguments\n .filter((arg) => arg.type !== \"number\" || !arg.isInteger || arg.value < 0)\n .forEach(() => {\n throw new Error(`lotto node weight arguments must be positive integer values`);\n });\n\n const node = {\n type: \"lotto\",\n weights: nodeArguments.length ? nodeArguments.map(({ value }) => value) : undefined,\n ...parseAttributeTokens(tokens, stringLiteralPlaceholders)\n } as LottoNodeDefinition;\n\n // This is a composite node, so we expect an opening '{'.\n popAndCheck(tokens, \"{\");\n\n // Return the lotto node definition.\n return node;\n}\n\n/**\n * Creates an action node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The action node JSON definition.\n */\nfunction createActionNode(\n tokens: string[],\n stringLiteralPlaceholders: StringLiteralPlaceholders\n): ActionNodeDefinition {\n // Parse any node arguments, we should have at least one which will be an identifier argument for the action name\n // and agent function to invoke for the action, all other arguments are to be passed as arguments to that function.\n const [actionNameIdentifier, ...agentFunctionArgs] = parseArgumentTokens(tokens, stringLiteralPlaceholders);\n\n // Our first argument MUST be defined and be an identifier as we require an action name argument.\n if (actionNameIdentifier?.type !== \"identifier\") {\n throw new Error(\"expected action name identifier argument\");\n }\n\n // Only the first argument should have been an identifier, all agent function arguments must be string, number, boolean or null.\n agentFunctionArgs\n .filter((arg) => arg.type === \"identifier\")\n .forEach((arg) => {\n throw new Error(\n `invalid action node argument value '${arg.value}', must be string, number, boolean or null`\n );\n });\n\n // Return the action node definition.\n return {\n type: \"action\",\n call: actionNameIdentifier.value,\n args: agentFunctionArgs.map(({ value }) => value),\n ...parseAttributeTokens(tokens, stringLiteralPlaceholders)\n };\n}\n\n/**\n * Creates a condition node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The condition node JSON definition.\n */\nfunction createConditionNode(\n tokens: string[],\n stringLiteralPlaceholders: StringLiteralPlaceholders\n): ConditionNodeDefinition {\n // Parse any node arguments, we should have at least one which will be an identifier argument for the condition name\n // and agent function to invoke for the condition, all other arguments are to be passed as arguments to that function.\n const [conditionNameIdentifier, ...agentFunctionArgs] = parseArgumentTokens(tokens, stringLiteralPlaceholders);\n\n // Our first argument MUST be defined and be an identifier as we require a condition name argument.\n if (conditionNameIdentifier?.type !== \"identifier\") {\n throw new Error(\"expected condition name identifier argument\");\n }\n\n // Only the first argument should have been an identifier, all agent function arguments must be string, number, boolean or null.\n agentFunctionArgs\n .filter((arg) => arg.type === \"identifier\")\n .forEach((arg) => {\n throw new Error(\n `invalid condition node argument value '${arg.value}', must be string, number, boolean or null`\n );\n });\n\n // Return the condition node definition.\n return {\n type: \"condition\",\n call: conditionNameIdentifier.value,\n args: agentFunctionArgs.map(({ value }) => value),\n ...parseAttributeTokens(tokens, stringLiteralPlaceholders)\n };\n}\n\n/**\n * Creates a wait node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The wait node JSON definition.\n */\nfunction createWaitNode(tokens: string[], stringLiteralPlaceholders: StringLiteralPlaceholders): WaitNodeDefinition {\n let node = { type: \"wait\" } as WaitNodeDefinition;\n\n // Get the node arguments.\n const nodeArguments = parseArgumentTokens(tokens, stringLiteralPlaceholders);\n\n // The arguments of a wait node are optional. We may have:\n // - No node arguments, in which case the wait will be indefinite until it is aborted.\n // - One node argument which will be the explicit duration of the wait.\n // - Two node arguments which define the min and max duration bounds from which a random duration will be picked.\n if (nodeArguments.length) {\n // All wait node arguments MUST be of type number and must be integer.\n nodeArguments\n .filter((arg) => arg.type !== \"number\" || !arg.isInteger)\n .forEach(() => {\n throw new Error(`wait node durations must be integer values`);\n });\n\n // We may have:\n // - One node argument which will be the explicit duration of the wait.\n // - Two node arguments which define the min and max duration bounds from which a random duration will be picked.\n // - Too many arguments, which is not valid.\n if (nodeArguments.length === 1) {\n // An explicit duration was defined.\n node.duration = nodeArguments[0].value as number;\n\n // If an explict duration was defined then it must be a positive number.\n if (node.duration < 0) {\n throw new Error(\"a wait node must have a positive duration\");\n }\n } else if (nodeArguments.length === 2) {\n // Min and max duration bounds were defined from which a random duration will be picked.\n node.duration = [nodeArguments[0].value as number, nodeArguments[1].value as number];\n\n // A wait node must have a positive min and max duration.\n if (node.duration[0] < 0 || node.duration[1] < 0) {\n throw new Error(\"a wait node must have a positive minimum and maximum duration\");\n }\n\n // A wait node must not have a minimum duration that exceeds the maximum duration.\n if (node.duration[0] > node.duration[1]) {\n throw new Error(\"a wait node must not have a minimum duration that exceeds the maximum duration\");\n }\n } else if (nodeArguments.length > 2) {\n // An incorrect number of duration arguments were defined.\n throw new Error(\"invalid number of wait node duration arguments defined\");\n }\n }\n\n // Return the wait node definition.\n return { ...node, ...parseAttributeTokens(tokens, stringLiteralPlaceholders) };\n}\n\n/**\n * Creates a branch node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The branch node JSON definition.\n */\nfunction createBranchNode(\n tokens: string[],\n stringLiteralPlaceholders: StringLiteralPlaceholders\n): BranchNodeDefinition {\n // Parse any node arguments, we should have one which will be an identifier argument for the root ref.\n const nodeArguments = parseArgumentTokens(tokens, stringLiteralPlaceholders);\n\n // We should have only a single identifer argument for a branch node, which is the root ref.\n if (nodeArguments.length !== 1 || nodeArguments[0].type !== \"identifier\") {\n throw new Error(\"expected single branch name argument\");\n }\n\n // Return the branch node definition.\n return { type: \"branch\", ref: nodeArguments[0].value };\n}\n\n/**\n * Validate a fully-populated node definition that was popped off of the tree stack.\n * @param definition The popped node to validate.\n */\nfunction validatePoppedNode(definition: AnyNodeDefinition): void {\n // Decorators MUST have a child defined.\n if (isDecoratorNode(definition) && isNullOrUndefined(definition.child)) {\n throw new Error(`a ${definition.type} node must have a single child node defined`);\n }\n\n // Composites MUST have at least one child defined.\n if (isCompositeNode(definition) && !definition.children?.length) {\n throw new Error(`a ${definition.type} node must have at least a single child node defined`);\n }\n\n // We need to make sure that lotto nodes that have weights defined have a number of weights matching the number of child nodes.\n if (definition.type === \"lotto\") {\n // Check whether a 'weights' property has been defined, if it has we expect it to be an array of weights.\n if (typeof definition.weights !== \"undefined\") {\n // Check that the weights property is an array of positive integers with an element for each child node element.\n if (definition.weights.length !== definition.children.length) {\n throw new Error(\n \"expected a number of weight arguments matching the number of child nodes for lotto node\"\n );\n }\n }\n }\n}\n", "import { RootNodeDefinition } from \"./BehaviourTreeDefinition\";\nimport { flattenDefinition, isBranchNode, isInteger } from \"./BehaviourTreeDefinitionUtilities\";\nimport { convertMDSLToJSON } from \"./mdsl/MDSLDefinitionParser\";\n\n/**\n * An object representing the result of validating a tree definition.\n */\nexport type DefinitionValidationResult = {\n /**\n * A flag defining whether validation succeeded.\n */\n succeeded: boolean;\n /**\n * A string containing the error message if validation did not succeed.\n */\n errorMessage?: string;\n /**\n * The definition as json if the validation was successful, or undefined if validation did not succeed.\n */\n json?: RootNodeDefinition[];\n};\n\n/**\n * Validates the specified behaviour tree definition in the form of JSON or MDSL, not taking any globally registered subtrees into consideration.\n * @param definition The behaviour tree definition in the form of JSON or MDSL.\n * @returns An object representing the result of validating the given tree definition.\n */\nexport function validateDefinition(definition: any): DefinitionValidationResult {\n // The definition must be defined.\n if (definition === null || typeof definition === \"undefined\") {\n return createValidationFailureResult(\"definition is null or undefined\");\n }\n\n // We are expecting a definition in one of three different forms:\n // - A string which we will assume is MDSL and we will parse this to JSON before validation.\n // - An array which we will assume is an array of root node definitions with at least one being the primary root node (no 'id' property)\n // - An object which we will assume is the primary root node and should not have an 'id' property.\n if (typeof definition === \"string\") {\n // The definition is a string which we can assume is MDSL, so attempt to validate it.\n return validateMDSLDefinition(definition);\n } else if (typeof definition === \"object\") {\n // The definition will either be an array (of root node definitions) or an object (the single primary root node definition).\n return validateJSONDefinition(definition);\n } else {\n return createValidationFailureResult(`unexpected definition type of '${typeof definition}'`);\n }\n}\n\n/**\n * Validates the specified behaviour tree definition in the form of MDSL.\n * @param definition The behaviour tree definition in the form of MDSL.\n * @returns An object representing the result of validating the given tree definition.\n */\nfunction validateMDSLDefinition(definition: string): DefinitionValidationResult {\n let rootNodeDefinitions;\n\n // The first thing the we need to do is to attempt to convert our MDSL into JSON.\n try {\n // The definition is a string which we can assume is MDSL, so attempt to parse it to a JSON definition in the form of an array of root node definitions.\n rootNodeDefinitions = convertMDSLToJSON(definition);\n } catch (exception) {\n // We failed to parse the JSON from the MDSL, this is likely to be the result of it not being a valid MDSL string.\n return createValidationFailureResult((exception as Error).message);\n }\n\n // Unpack all of the root node definitions into arrays of main ('id' defined) and sub ('id' not defined) root node definitions.\n const mainRootNodeDefinitions = rootNodeDefinitions.filter(({ id }) => typeof id === \"undefined\");\n const subRootNodeDefinitions = rootNodeDefinitions.filter(({ id }) => typeof id === \"string\" && id.length > 0);\n\n // We should ALWAYS have exactly one root node definition without an 'id' property defined, which is out main root node definition.\n if (mainRootNodeDefinitions.length !== 1) {\n return createValidationFailureResult(\n \"expected single unnamed root node at base of definition to act as main root\"\n );\n }\n\n // We should never have duplicate 'id' properties across our sub root node definitions.\n const subRootNodeIdenitifers: string[] = [];\n for (const { id } of subRootNodeDefinitions) {\n // Have we already come across this 'id' property value?\n if (subRootNodeIdenitifers.includes(id!)) {\n return createValidationFailureResult(`multiple root nodes found with duplicate name '${id}'`);\n }\n\n subRootNodeIdenitifers.push(id!);\n }\n\n try {\n // Validate our branch -> subtree links and check for any circular dependencies, we don't care about checking for broken subtree links here.\n validateBranchSubtreeLinks(rootNodeDefinitions, false);\n } catch (exception) {\n return createValidationFailureResult((exception as Error).message);\n }\n\n // Our definition was valid!\n return {\n succeeded: true,\n json: rootNodeDefinitions\n };\n}\n\n/**\n * Validates the specified behaviour tree definition in the form of JSON.\n * @param definition The behaviour tree definition in the form of JSON.\n * @returns An object representing the result of validating the given tree definition.\n */\nexport function validateJSONDefinition(\n definition: RootNodeDefinition | RootNodeDefinition[]\n): DefinitionValidationResult {\n // The definition will either be an array (of root node definitions) or an object (the single primary root node definition).\n const rootNodeDefinitions = Array.isArray(definition) ? definition : [definition];\n\n // Iterate over our array of root nodes and call validateNode for each, passing an initial depth of 0, wrapped in a try catch to handle validation failures.\n try {\n rootNodeDefinitions.forEach((rootNodeDefinition) => validateNode(rootNodeDefinition, 0));\n } catch (error) {\n // Handle cases where we have caught a thrown Error and return a failure result with the error message.\n if (error instanceof Error) {\n return createValidationFailureResult(error.message);\n }\n\n // No idea what happened here!\n return createValidationFailureResult(`unexpected error: ${error}`);\n }\n\n // Unpack all of the root node definitions into arrays of main ('id' defined) and sub ('id' not defined) root node definitions.\n const mainRootNodeDefinitions = rootNodeDefinitions.filter(({ id }) => typeof id === \"undefined\");\n const subRootNodeDefinitions = rootNodeDefinitions.filter(({ id }) => typeof id === \"string\" && id.length > 0);\n\n // We should ALWAYS have exactly one root node definition without an 'id' property defined, which is out main root node definition.\n if (mainRootNodeDefinitions.length !== 1) {\n return createValidationFailureResult(\n \"expected single root node without 'id' property defined to act as main root\"\n );\n }\n\n // We should never have duplicate 'id' properties across our sub root node definitions.\n const subRootNodeIdenitifers: string[] = [];\n for (const { id } of subRootNodeDefinitions) {\n // Have we already come across this 'id' property value?\n if (subRootNodeIdenitifers.includes(id!)) {\n return createValidationFailureResult(\n `multiple root nodes found with duplicate 'id' property value of '${id}'`\n );\n }\n\n subRootNodeIdenitifers.push(id!);\n }\n\n try {\n // Validate our branch -> subtree links and check for any circular dependencies, we don't care about checking for broken subtree links here.\n validateBranchSubtreeLinks(rootNodeDefinitions, false);\n } catch (exception) {\n return createValidationFailureResult((exception as Error).message);\n }\n\n // Our definition was valid!\n return {\n succeeded: true,\n json: rootNodeDefinitions\n };\n}\n\n/**\n * Validates the branch -> subtree links across all provided root node definitions.\n * This will not consider branch nodes that reference any globally registered subtrees unless includesGlobalSubtrees\n * is set to true, in which case we will also verify that there are no broken branch -> subtree links.\n * @param rootNodeDefinitions The array of root node definitions.\n * @param includesGlobalSubtrees A flag defining whether the array includes all global subtree root node definitions.\n */\nexport function validateBranchSubtreeLinks(rootNodeDefinitions: RootNodeDefinition[], includesGlobalSubtrees: boolean) {\n // Create a mapping of root node identifiers to other root nodes that they reference via branch nodes.\n // Below is an example of a mapping that includes a circular dependency (root => a => b => c => a)\n // [{ refs: [\"a\", \"b\"] }, { id: \"a\", refs: [\"b\"] }, { id: \"b\", refs: [\"c\"] }, { id: \"c\", refs: [\"a\"] }]\n const rootNodeMappings: { id: string | undefined; refs: string[] }[] = rootNodeDefinitions.map(\n (rootNodeDefinition) => ({\n id: rootNodeDefinition.id,\n refs: flattenDefinition(rootNodeDefinition)\n .filter(isBranchNode)\n .map(({ ref }) => ref)\n })\n );\n\n // A recursive function to walk through the mappings, keeping track of which root nodes we have visited in the form of a path of root node identifiers.\n const followRefs = (mapping: { id: string | undefined; refs: string[] }, path: (string | undefined)[] = []) => {\n // Have we found a circular dependency?\n if (path.includes(mapping.id)) {\n // We found a circular dependency! Get the bad path of root node identifiers.\n const badPath = [...path, mapping.id];\n\n // Create the formatted path value. [undefined, \"a\", \"b\", \"c\", \"a\"] would be formatted as \"a -> b -> c -> a\".\n const badPathFormatted = badPath.filter((element) => !!element).join(\" => \");\n\n // No need to continue, we found a circular dependency.\n throw new Error(`circular dependency found in branch node references: ${badPathFormatted}`);\n }\n\n for (const ref of mapping.refs) {\n // Find the mapping for the root node with an identifer matching the current ref.\n const subMapping = rootNodeMappings.find(({ id }) => id === ref);\n\n // We may not have a mapping for this ref, which is normal when we aren't considering all globally registered subtrees.\n if (subMapping) {\n followRefs(subMapping, [...path, mapping.id]);\n } else if (includesGlobalSubtrees) {\n // We found a reference to a root node that doesn't exist, which is a problem seeing as the root node definitons includes all globally registered subtrees.\n throw new Error(\n mapping.id\n ? `subtree '${mapping.id}' has branch node that references root node '${ref}' which has not been defined`\n : `primary tree has branch node that references root node '${ref}' which has not been defined`\n );\n }\n }\n };\n\n // Start looking for circular dependencies and broken references from the primary root node definition.\n followRefs(rootNodeMappings.find((mapping) => typeof mapping.id === \"undefined\")!);\n}\n\n/**\n * Validate an object that we expect to be a node definition.\n * @param definition An object that we expect to be a node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateNode(definition: any, depth: number): void {\n // Every node must be valid object and have a non-empty 'type' string property.\n if (typeof definition !== \"object\" || typeof definition.type !== \"string\" || definition.type.length === 0) {\n throw new Error(\n `node definition is not an object or 'type' property is not a non-empty string at depth '${depth}'`\n );\n }\n\n // How we validate this node definition will depend on its type.\n switch (definition.type) {\n case \"action\":\n validateActionNode(definition, depth);\n break;\n\n case \"condition\":\n validateConditionNode(definition, depth);\n break;\n\n case \"wait\":\n validateWaitNode(definition, depth);\n break;\n\n case \"branch\":\n validateBranchNode(definition, depth);\n break;\n\n case \"root\":\n validateRootNode(definition, depth);\n break;\n\n case \"succeed\":\n validateSucceedNode(definition, depth);\n break;\n\n case \"fail\":\n validateFailNode(definition, depth);\n break;\n\n case \"flip\":\n validateFlipNode(definition, depth);\n break;\n\n case \"repeat\":\n validateRepeatNode(definition, depth);\n break;\n\n case \"retry\":\n validateRetryNode(definition, depth);\n break;\n\n case \"sequence\":\n validateSequenceNode(definition, depth);\n break;\n\n case \"selector\":\n validateSelectorNode(definition, depth);\n break;\n\n case \"parallel\":\n validateParallelNode(definition, depth);\n break;\n\n case \"lotto\":\n validateLottoNode(definition, depth);\n break;\n\n default:\n throw new Error(`unexpected node type of '${definition.type}' at depth '${depth}'`);\n }\n}\n\n/**\n * Validate any attributes for a given node definition.\n * @param definition The node definition.\n * @param depth The depth of the node in the behaviour tree definition.\n */\nfunction validateNodeAttributes(definition: any, depth: number): void {\n // Validate each of the attribute types for this node.\n [\"while\", \"until\", \"entry\", \"exit\", \"step\"].forEach((attributeName) => {\n // Attempt to grab the definition for the current attribute from the node definition.\n const attributeDefinition = definition[attributeName];\n\n // All node attributes are optional, so there is nothing to do if the current attribute is not defined.\n if (typeof attributeDefinition === \"undefined\") {\n return;\n }\n\n // The attribute definition must be an object.\n if (typeof attributeDefinition !== \"object\") {\n throw new Error(\n `expected attribute '${attributeName}' to be an object for '${definition.type}' node at depth '${depth}'`\n );\n }\n\n // The 'call' property must be defined for any attribute definition.\n if (typeof attributeDefinition.call !== \"string\" || attributeDefinition.call.length === 0) {\n throw new Error(\n `expected 'call' property for attribute '${attributeName}' to be a non-empty string for '${definition.type}' node at depth '${depth}'`\n );\n }\n\n // If any node attribute arguments have been defined then they must have been defined in an array.\n if (typeof attributeDefinition.args !== \"undefined\" && !Array.isArray(attributeDefinition.args)) {\n throw new Error(\n `expected 'args' property for attribute '${attributeName}' to be an array for '${definition.type}' node at depth '${depth}'`\n );\n }\n });\n}\n\n/**\n * Validate an object that we expect to be a root node definition.\n * @param definition An object that we expect to be a root node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateRootNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"root\") {\n throw new Error(\"expected node type of 'root' for root node\");\n }\n\n // A root node cannot be the child of another node.\n if (depth > 0) {\n throw new Error(\"a root node cannot be the child of another node\");\n }\n\n // Check that, if the root node 'id' property is defined, it is a non-empty string.\n if (typeof definition.id !== \"undefined\" && (typeof definition.id !== \"string\" || definition.id.length === 0)) {\n throw new Error(\"expected non-empty string for 'id' property if defined for root node\");\n }\n\n // A root node is a decorator node, so must have a child node defined.\n if (typeof definition.child === \"undefined\") {\n throw new Error(\"expected property 'child' to be defined for root node\");\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n\n // Validate the child node of this decorator node.\n validateNode(definition.child, depth + 1);\n}\n\n/**\n * Validate an object that we expect to be a succeed node definition.\n * @param definition An object that we expect to be a succeed node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateSucceedNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"succeed\") {\n throw new Error(`expected node type of 'succeed' for succeed node at depth '${depth}'`);\n }\n\n // A succeed node is a decorator node, so must have a child node defined.\n if (typeof definition.child === \"undefined\") {\n throw new Error(`expected property 'child' to be defined for succeed node at depth '${depth}'`);\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n\n // Validate the child node of this decorator node.\n validateNode(definition.child, depth + 1);\n}\n\n/**\n * Validate an object that we expect to be a fail node definition.\n * @param definition An object that we expect to be a fail node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateFailNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"fail\") {\n throw new Error(`expected node type of 'fail' for fail node at depth '${depth}'`);\n }\n\n // A fail node is a decorator node, so must have a child node defined.\n if (typeof definition.child === \"undefined\") {\n throw new Error(`expected property 'child' to be defined for fail node at depth '${depth}'`);\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n\n // Validate the child node of this decorator node.\n validateNode(definition.child, depth + 1);\n}\n\n/**\n * Validate an object that we expect to be a flip node definition.\n * @param definition An object that we expect to be a flip node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateFlipNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"flip\") {\n throw new Error(`expected node type of 'flip' for flip node at depth '${depth}'`);\n }\n\n // A flip node is a decorator node, so must have a child node defined.\n if (typeof definition.child === \"undefined\") {\n throw new Error(`expected property 'child' to be defined for flip node at depth '${depth}'`);\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n\n // Validate the child node of this decorator node.\n validateNode(definition.child, depth + 1);\n}\n\n/**\n * Validate an object that we expect to be a repeat node definition.\n * @param definition An object that we expect to be a repeat node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateRepeatNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"repeat\") {\n throw new Error(`expected node type of 'repeat' for repeat node at depth '${depth}'`);\n }\n\n // A repeat node is a decorator node, so must have a child node defined.\n if (typeof definition.child === \"undefined\") {\n throw new Error(`expected property 'child' to be defined for repeat node at depth '${depth}'`);\n }\n\n // Check whether an 'iterations' property has been defined, it may not have been if this node is to repeat indefinitely.\n if (typeof definition.iterations !== \"undefined\") {\n if (Array.isArray(definition.iterations)) {\n // Check whether any elements of the array are not integer values.\n const containsNonInteger = !!definition.iterations.filter((value: unknown) => !isInteger(value)).length;\n\n // If the 'iterations' property is an array then it MUST contain two integer values.\n if (definition.iterations.length !== 2 || containsNonInteger) {\n throw new Error(\n `expected array containing two integer values for 'iterations' property if defined for repeat node at depth '${depth}'`\n );\n }\n\n // A repeat node must have a positive min and max iterations count if they are defined.\n if (definition.iterations[0] < 0 || definition.iterations[1] < 0) {\n throw new Error(\n `expected positive minimum and maximum iterations count for 'iterations' property if defined for repeat node at depth '${depth}'`\n );\n }\n\n // A repeat node must not have a minimum iterations count that exceeds the maximum iterations count.\n if (definition.iterations[0] > definition.iterations[1]) {\n throw new Error(\n `expected minimum iterations count that does not exceed the maximum iterations count for 'iterations' property if defined for repeat node at depth '${depth}'`\n );\n }\n } else if (isInteger(definition.iterations)) {\n // A repeat node must have a positive number of iterations if defined.\n if (definition.iterations < 0) {\n throw new Error(\n `expected positive iterations count for 'iterations' property if defined for repeat node at depth '${depth}'`\n );\n }\n } else {\n throw new Error(\n `expected integer value or array containing two integer values for 'iterations' property if defined for repeat node at depth '${depth}'`\n );\n }\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n\n // Validate the child node of this decorator node.\n validateNode(definition.child, depth + 1);\n}\n\n/**\n * Validate an object that we expect to be a retry node definition.\n * @param definition An object that we expect to be a retry node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateRetryNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"retry\") {\n throw new Error(`expected node type of 'retry' for retry node at depth '${depth}'`);\n }\n\n // A retry node is a decorator node, so must have a child node defined.\n if (typeof definition.child === \"undefined\") {\n throw new Error(`expected property 'child' to be defined for retry node at depth '${depth}'`);\n }\n\n // Check whether an 'attempts' property has been defined, it may not have been if this node is to retry indefinitely.\n if (typeof definition.attempts !== \"undefined\") {\n if (Array.isArray(definition.attempts)) {\n // Check whether any elements of the array are not integer values.\n const containsNonInteger = !!definition.attempts.filter((value: unknown) => !isInteger(value)).length;\n\n // If the 'attempts' property is an array then it MUST contain two integer values.\n if (definition.attempts.length !== 2 || containsNonInteger) {\n throw new Error(\n `expected array containing two integer values for 'attempts' property if defined for retry node at depth '${depth}'`\n );\n }\n\n // A retry node must have a positive min and max attempts count if they are defined.\n if (definition.attempts[0] < 0 || definition.attempts[1] < 0) {\n throw new Error(\n `expected positive minimum and maximum attempts count for 'attempts' property if defined for retry node at depth '${depth}'`\n );\n }\n\n // A retry node must not have a minimum attempts count that exceeds the maximum attempts count.\n if (definition.attempts[0] > definition.attempts[1]) {\n throw new Error(\n `expected minimum attempts count that does not exceed the maximum attempts count for 'attempts' property if defined for retry node at depth '${depth}'`\n );\n }\n } else if (isInteger(definition.attempts)) {\n // A retry node must have a positive number of attempts if defined.\n if (definition.attempts < 0) {\n throw new Error(\n `expected positive attempts count for 'attempts' property if defined for retry node at depth '${depth}'`\n );\n }\n } else {\n throw new Error(\n `expected integer value or array containing two integer values for 'attempts' property if defined for retry node at depth '${depth}'`\n );\n }\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n\n // Validate the child node of this decorator node.\n validateNode(definition.child, depth + 1);\n}\n\n/**\n * Validate an object that we expect to be a branch node definition.\n * @param definition An object that we expect to be a branch node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateBranchNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"branch\") {\n throw new Error(`expected node type of 'branch' for branch node at depth '${depth}'`);\n }\n\n // Check that the branch node 'ref' property is defined and is a non-empty string.\n if (typeof definition.ref !== \"string\" || definition.ref.length === 0) {\n throw new Error(`expected non-empty string for 'ref' property for branch node at depth '${depth}'`);\n }\n\n // It is invalid to define guard attributes for a branch node as they should be defined on the referenced root node.\n [\"while\", \"until\"].forEach((attributeName) => {\n if (typeof definition[attributeName] !== \"undefined\") {\n throw new Error(\n `guards should not be defined for branch nodes but guard '${attributeName}' was defined for branch node at depth '${depth}'`\n );\n }\n });\n\n // It is invalid to define callback attributes for a branch node as they should be defined on the referenced root node.\n [\"entry\", \"exit\", \"step\"].forEach((attributeName) => {\n if (typeof definition[attributeName] !== \"undefined\") {\n throw new Error(\n `callbacks should not be defined for branch nodes but callback '${attributeName}' was defined for branch node at depth '${depth}'`\n );\n }\n });\n}\n\n/**\n * Validate an object that we expect to be a action node definition.\n * @param definition An object that we expect to be a action node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateActionNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"action\") {\n throw new Error(`expected node type of 'action' for action node at depth '${depth}'`);\n }\n\n // The 'call' property must be defined for a action node definition.\n if (typeof definition.call !== \"string\" || definition.call.length === 0) {\n throw new Error(`expected non-empty string for 'call' property of action node at depth '${depth}'`);\n }\n\n // If any action function arguments have been defined then they must have been defined in an array.\n if (typeof definition.args !== \"undefined\" && !Array.isArray(definition.args)) {\n throw new Error(`expected array for 'args' property if defined for action node at depth '${depth}'`);\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n}\n\n/**\n * Validate an object that we expect to be a condition node definition.\n * @param definition An object that we expect to be a condition node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateConditionNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"condition\") {\n throw new Error(`expected node type of 'condition' for condition node at depth '${depth}'`);\n }\n\n // The 'call' property must be defined for a condition node definition.\n if (typeof definition.call !== \"string\" || definition.call.length === 0) {\n throw new Error(`expected non-empty string for 'call' property of condition node at depth '${depth}'`);\n }\n\n // If any condition function arguments have been defined then they must have been defined in an array.\n if (typeof definition.args !== \"undefined\" && !Array.isArray(definition.args)) {\n throw new Error(`expected array for 'args' property if defined for condition node at depth '${depth}'`);\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n}\n\n/**\n * Validate an object that we expect to be a wait node definition.\n * @param definition An object that we expect to be a wait node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateWaitNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"wait\") {\n throw new Error(`expected node type of 'wait' for wait node at depth '${depth}'`);\n }\n\n // Check whether a 'duration' property has been defined, it may not have been if this node is to wait indefinitely.\n if (typeof definition.duration !== \"undefined\") {\n if (Array.isArray(definition.duration)) {\n // Check whether any elements of the array are not integer values.\n const containsNonInteger = !!definition.duration.filter((value: unknown) => !isInteger(value)).length;\n\n // If the 'duration' property is an array then it MUST contain two integer values.\n if (definition.duration.length !== 2 || containsNonInteger) {\n throw new Error(\n `expected array containing two integer values for 'duration' property if defined for wait node at depth '${depth}'`\n );\n }\n\n // A wait node must have a positive min and max duration value if they are defined.\n if (definition.duration[0] < 0 || definition.duration[1] < 0) {\n throw new Error(\n `expected positive minimum and maximum duration for 'duration' property if defined for wait node at depth '${depth}'`\n );\n }\n\n // A wait node must not have a minimum duration value that exceeds the maximum duration value.\n if (definition.duration[0] > definition.duration[1]) {\n throw new Error(\n `expected minimum duration value that does not exceed the maximum duration value for 'duration' property if defined for wait node at depth '${depth}'`\n );\n }\n } else if (isInteger(definition.duration)) {\n // A wait node must have a positive duration value if defined.\n if (definition.duration < 0) {\n throw new Error(\n `expected positive duration value for 'duration' property if defined for wait node at depth '${depth}'`\n );\n }\n } else {\n throw new Error(\n `expected integer value or array containing two integer values for 'duration' property if defined for wait node at depth '${depth}'`\n );\n }\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n}\n\n/**\n * Validate an object that we expect to be a sequence node definition.\n * @param definition An object that we expect to be a sequence node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateSequenceNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"sequence\") {\n throw new Error(`expected node type of 'sequence' for sequence node at depth '${depth}'`);\n }\n\n // A sequence node is a composite node, so must have a children nodes array defined.\n if (!Array.isArray(definition.children) || definition.children.length === 0) {\n throw new Error(`expected non-empty 'children' array to be defined for sequence node at depth '${depth}'`);\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n\n // Validate the child nodes of this composite node.\n definition.children.forEach((child: any) => validateNode(child, depth + 1));\n}\n\n/**\n * Validate an object that we expect to be a selector node definition.\n * @param definition An object that we expect to be a selector node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateSelectorNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"selector\") {\n throw new Error(`expected node type of 'selector' for selector node at depth '${depth}'`);\n }\n\n // A selector node is a composite node, so must have a children nodes array defined.\n if (!Array.isArray(definition.children) || definition.children.length === 0) {\n throw new Error(`expected non-empty 'children' array to be defined for selector node at depth '${depth}'`);\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n\n // Validate the child nodes of this composite node.\n definition.children.forEach((child: any) => validateNode(child, depth + 1));\n}\n\n/**\n * Validate an object that we expect to be a parallel node definition.\n * @param definition An object that we expect to be a parallel node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateParallelNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"parallel\") {\n throw new Error(`expected node type of 'parallel' for parallel node at depth '${depth}'`);\n }\n\n // A parallel node is a composite node, so must have a children nodes array defined.\n if (!Array.isArray(definition.children) || definition.children.length === 0) {\n throw new Error(`expected non-empty 'children' array to be defined for parallel node at depth '${depth}'`);\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n\n // Validate the child nodes of this composite node.\n definition.children.forEach((child: any) => validateNode(child, depth + 1));\n}\n\n/**\n * Validate an object that we expect to be a lotto node definition.\n * @param definition An object that we expect to be a lotto node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateLottoNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"lotto\") {\n throw new Error(`expected node type of 'lotto' for lotto node at depth '${depth}'`);\n }\n\n // A lotto node is a composite node, so must have a children nodes array defined.\n if (!Array.isArray(definition.children) || definition.children.length === 0) {\n throw new Error(`expected non-empty 'children' array to be defined for lotto node at depth '${depth}'`);\n }\n\n // Check whether a 'weights' property has been defined, if it has we expect it to be an array of weights.\n if (typeof definition.weights !== \"undefined\") {\n // Check that the weights property is an array of positive integers with an element for each child node element.\n if (\n !Array.isArray(definition.weights) ||\n definition.weights.length !== definition.children.length ||\n definition.weights.filter((value: unknown) => !isInteger(value)).length ||\n definition.weights.filter((value: number) => value < 0).length\n ) {\n throw new Error(\n `expected an array of positive integer weight values with a length matching the number of child nodes for 'weights' property if defined for lotto node at depth '${depth}'`\n );\n }\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n\n // Validate the child nodes of this composite node.\n definition.children.forEach((child: any) => validateNode(child, depth + 1));\n}\n\n/**\n * A helper function to create a failure validation result with the given error message.\n * @param errorMessage The validation failure error message.\n * @returns A failure validation result with the given error message.\n */\nfunction createValidationFailureResult(errorMessage: string): DefinitionValidationResult {\n return { succeeded: false, errorMessage };\n}\n", "import { ActionResult, Agent, GlobalFunction } from \"./Agent\";\nimport { RootNodeDefinition } from \"./BehaviourTreeDefinition\";\n\nexport type InvokerFunction = (args: any[]) => ActionResult;\n\n/**\n * A singleton used to store and lookup registered functions and subtrees.\n */\nexport default class Lookup {\n /**\n * The object holding any registered functions keyed on function name.\n */\n private static functionTable: { [key: string]: GlobalFunction } = {};\n /**\n * The object holding any registered subtree root node definitions keyed on tree name.\n */\n private static subtreeTable: { [key: string]: RootNodeDefinition } = {};\n\n /**\n * Gets the function with the specified name.\n * @param name The name of the function.\n * @returns The function with the specified name.\n */\n public static getFunc(name: string): GlobalFunction {\n return this.functionTable[name];\n }\n\n /**\n * Sets the function with the specified name for later lookup.\n * @param name The name of the function.\n * @param func The function.\n */\n public static setFunc(name: string, func: GlobalFunction): void {\n this.functionTable[name] = func;\n }\n\n /**\n * Gets the function invoker for the specified agent and function name.\n * If a function with the specified name exists on the agent object then it will\n * be returned, otherwise we will then check the registered functions for a match.\n * @param agent The agent instance that this behaviour tree is modelling behaviour for.\n * @param name The function name.\n * @returns The function invoker for the specified agent and function name.\n */\n static getFuncInvoker(agent: Agent, name: string): InvokerFunction | null {\n // Check whether the agent contains the specified function.\n const foundOnAgent = agent[name];\n if (foundOnAgent && typeof foundOnAgent === \"function\") {\n return (args: any[]): boolean | ActionResult => foundOnAgent.apply(agent, args);\n }\n\n // The agent does not contain the specified function but it may have been registered at some point.\n if (this.functionTable[name] && typeof this.functionTable[name] === \"function\") {\n return (args: any[]) => this.functionTable[name](agent, ...args.map((arg) => arg.value));\n }\n\n // We have no function to invoke.\n return null;\n }\n\n /**\n * Gets all registered subtree root node definitions.\n */\n static getSubtrees(): { [key: string]: RootNodeDefinition } {\n return this.subtreeTable;\n }\n\n /**\n * Sets the subtree with the specified name for later lookup.\n * @param name The name of the subtree.\n * @param subtree The subtree.\n */\n static setSubtree(name: string, subtree: RootNodeDefinition) {\n this.subtreeTable[name] = subtree;\n }\n\n /**\n * Removes the registered function or subtree with the specified name.\n * @param name The name of the registered function or subtree.\n */\n static remove(name: string) {\n delete this.functionTable[name];\n delete this.subtreeTable[name];\n }\n\n /**\n * Remove all registered functions and subtrees.\n */\n static empty() {\n this.functionTable = {};\n this.subtreeTable = {};\n }\n}\n", "import Node from \"../../nodes/Node\";\n\n/**\n * An exception thrown when evaluating node guard path conditions and a conditions fails.\n */\nexport default class GuardUnsatisifedException extends Error {\n /**\n * @param source The node at which a guard condition failed.\n */\n constructor(private source: Node) {\n super(\"A guard path condition has failed\");\n }\n\n /**\n * Gets whether the specified node is the node at which a guard condition failed.\n * @param node The node to check against the source node.\n * @returns Whether the specified node is the node at which a guard condition failed.\n */\n isSourceNode = (node: Node) => node === this.source;\n}\n", "import { Agent } from \"../../Agent\";\nimport Guard from \"./Guard\";\nimport Node from \"../../nodes/Node\";\nimport GuardUnsatisifedException from \"./GuardUnsatisifedException\";\n\nexport type GuardPathPart = {\n node: Node;\n guards: Guard[];\n};\n\n/**\n * Represents a path of node guards along a root-to-leaf tree path.\n */\nexport default class GuardPath {\n /**\n * @param nodes An array of objects defining a node instance -> guard link, ordered by node depth.\n */\n constructor(private nodes: GuardPathPart[]) {}\n\n /**\n * Evaluate guard conditions for all guards in the tree path, moving outwards from the root.\n * @param agent The agent, required for guard evaluation.\n * @returns An evaluation results object.\n */\n evaluate = (agent: Agent) => {\n // We need to evaluate guard conditions for nodes up the tree, moving outwards from the root.\n for (const details of this.nodes) {\n // There can be multiple guards per node.\n for (const guard of details.guards) {\n // Check whether the guard condition passes, and throw an exception if not.\n if (!guard.isSatisfied(agent)) {\n throw new GuardUnsatisifedException(details.node);\n }\n }\n }\n };\n}\n", "import { BehaviourTreeOptions } from \"../BehaviourTreeOptions\";\nimport State, { AnyState } from \"../State\";\nimport { Agent } from \"../Agent\";\nimport Leaf from \"./leaf/Leaf\";\nimport Attribute from \"../attributes/Attribute\";\nimport Entry from \"../attributes/callbacks/Entry\";\nimport Exit from \"../attributes/callbacks/Exit\";\nimport Step from \"../attributes/callbacks/Step\";\nimport Guard from \"../attributes/guards/Guard\";\nimport GuardPath from \"../attributes/guards/GuardPath\";\nimport GuardUnsatisifedException from \"../attributes/guards/GuardUnsatisifedException\";\n\n/**\n * A base node.\n */\nexport default abstract class Node {\n /**\n * The node uid.\n */\n private readonly uid: string = createNodeUid();\n /**\n * The node state.\n */\n private state: AnyState = State.READY;\n /**\n * The guard path to evaluate as part of a node update.\n */\n private guardPath: GuardPath | undefined;\n\n /**\n * @param type The node type.\n * @param attributes The node attributes.\n * @param args The node argument definitions.\n */\n constructor(private type: string, private attributes: Attribute[], private args: any[]) {}\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected abstract onUpdate(agent: Agent, options: BehaviourTreeOptions): void;\n\n /**\n * Gets the name of the node.\n */\n public abstract getName(): string;\n\n /**\n * Gets whether this node is a leaf node.\n */\n public abstract isLeafNode: () => this is Leaf;\n\n /**\n * Gets/Sets the state of the node.\n */\n getState = (): AnyState => this.state;\n setState = (value: AnyState): void => {\n this.state = value;\n };\n\n /**\n * Gets the unique id of the node.\n */\n getUid = () => this.uid;\n\n /**\n * Gets the type of the node.\n */\n getType = () => this.type;\n\n /**\n * Gets the node attributes.\n */\n getAttributes = () => this.attributes;\n\n /**\n * Gets the node arguments.\n */\n getArguments = () => this.args;\n\n /**\n * Gets the node attribute with the specified type, or null if it does not exist.\n */\n getAttribute(type: \"entry\" | \"ENTRY\"): Entry;\n getAttribute(type: \"exit\" | \"EXIT\"): Exit;\n getAttribute(type: \"step\" | \"STEP\"): Step;\n getAttribute(type: string): Attribute {\n return (\n this.getAttributes().filter((decorator) => decorator.type.toUpperCase() === type.toUpperCase())[0] || null\n );\n }\n\n /**\n * Gets the node attributes.\n */\n getGuardAttributes = (): Guard[] => this.getAttributes().filter((decorator) => decorator.isGuard()) as Guard[];\n\n /**\n * Sets the guard path to evaluate as part of a node update.\n */\n setGuardPath = (value: GuardPath) => (this.guardPath = value);\n\n /**\n * Gets whether a guard path is assigned to this node.\n */\n hasGuardPath = () => !!this.guardPath;\n\n /**\n * Gets whether this node is in the specified state.\n * @param value The value to compare to the node state.\n */\n public is(value: AnyState): boolean {\n return this.state === value;\n }\n\n /**\n * Reset the state of the node.\n */\n public reset(): void {\n this.setState(State.READY);\n }\n\n /**\n * Abort the running of this node.\n * @param agent The agent.\n */\n public abort(agent: Agent): void {\n // There is nothing to do if this node is not in the running state.\n if (!this.is(State.RUNNING)) {\n return;\n }\n\n // Reset the state of this node.\n this.reset();\n\n this.getAttribute(\"exit\")?.callAgentFunction(agent, false, true);\n }\n\n /**\n * Update the node.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n * @returns The result of the update.\n */\n public update(agent: Agent, options: BehaviourTreeOptions): void {\n // If this node is already in a 'SUCCEEDED' or 'FAILED' state then there is nothing to do.\n if (this.is(State.SUCCEEDED) || this.is(State.FAILED)) {\n return;\n }\n\n try {\n // Evaluate all of the guard path conditions for the current tree path.\n this.guardPath!.evaluate(agent);\n\n // If this node is in the READY state then call the ENTRY for this node if it exists.\n if (this.is(State.READY)) {\n this.getAttribute(\"entry\")?.callAgentFunction(agent);\n }\n\n this.getAttribute(\"step\")?.callAgentFunction(agent);\n\n // Do the actual update.\n this.onUpdate(agent, options);\n\n // If this node is now in a 'SUCCEEDED' or 'FAILED' state then call the EXIT for this node if it exists.\n if (this.is(State.SUCCEEDED) || this.is(State.FAILED)) {\n this.getAttribute(\"exit\")?.callAgentFunction(agent, this.is(State.SUCCEEDED), false);\n }\n } catch (error) {\n // If the error is a GuardUnsatisfiedException then we need to determine if this node is the source.\n if (error instanceof GuardUnsatisifedException && error.isSourceNode(this)) {\n // Abort the current node.\n this.abort(agent);\n\n // Any node that is the source of an abort will be a failed node.\n this.setState(State.FAILED);\n } else {\n throw error;\n }\n }\n }\n}\n\n/**\n * Create a randomly generated node uid.\n * @returns A randomly generated node uid.\n */\nfunction createNodeUid(): string {\n var S4 = function () {\n return (((1 + Math.random()) * 0x10000) | 0).toString(16).substring(1);\n };\n return S4() + S4() + \"-\" + S4() + \"-\" + S4() + \"-\" + S4() + \"-\" + S4() + S4() + S4();\n}\n", "import Node from \"../Node\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\n\n/**\n * A composite node that wraps child nodes.\n */\nexport default abstract class Composite extends Node {\n /**\n * @param type The node type.\n * @param attributes The node attributes.\n * @param children The child nodes.\n */\n constructor(type: string, attributes: Attribute[], protected children: Node[]) {\n super(type, attributes, []);\n }\n\n /**\n * Gets whether this node is a leaf node.\n */\n isLeafNode = () => false;\n\n /**\n * Gets the children of this node.\n */\n getChildren = () => this.children;\n\n /**\n * Reset the state of the node.\n */\n reset = () => {\n // Reset the state of this node.\n this.setState(State.READY);\n\n // Reset the state of any child nodes.\n this.getChildren().forEach((child) => child.reset());\n };\n\n /**\n * Abort the running of this node.\n * @param agent The agent.\n */\n abort = (agent: Agent) => {\n // There is nothing to do if this node is not in the running state.\n if (!this.is(State.RUNNING)) {\n return;\n }\n\n // Abort any child nodes.\n this.getChildren().forEach((child) => child.abort(agent));\n\n // Reset the state of this node.\n this.reset();\n\n this.getAttribute(\"exit\")?.callAgentFunction(agent, false, true);\n };\n}\n", "import Composite from \"./Composite\";\nimport State from \"../../State\";\nimport Node from \"../Node\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A PARALLEL node.\n * The child nodes are executed concurrently until one fails or all succeed.\n */\nexport default class Parallel extends Composite {\n /**\n * @param attributes The node attributes.\n * @param children The child nodes.\n */\n constructor(attributes: Attribute[], children: Node[]) {\n super(\"parallel\", attributes, children);\n }\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // Keep a count of the number of succeeded child nodes.\n let succeededCount = 0;\n\n let hasChildFailed = false;\n\n // Iterate over all of the children of this node.\n for (const child of this.children) {\n // If the child has never been updated or is running then we will need to update it now.\n if (child.getState() === State.READY || child.getState() === State.RUNNING) {\n // Update the child of this node.\n child.update(agent, options);\n }\n\n // If the current child has a state of 'SUCCEEDED' then we should move on to the next child.\n if (child.getState() === State.SUCCEEDED) {\n // The child node has succeeded, keep track of this to determine if all children have.\n succeededCount++;\n\n // The child node succeeded, but we have not finished checking every child node yet.\n continue;\n }\n\n // If the current child has a state of 'FAILED' then this node is also a 'FAILED' node.\n if (child.getState() === State.FAILED) {\n hasChildFailed = true;\n\n // There is no need to check the rest of the children.\n break;\n }\n\n // The node should be in the 'RUNNING' state.\n if (child.getState() !== State.RUNNING) {\n // The child node was not in an expected state.\n throw new Error(\"child node was not in an expected state.\");\n }\n }\n\n if (hasChildFailed) {\n // This node is a 'FAILED' node.\n this.setState(State.FAILED);\n\n // Abort every running child.\n for (const child of this.children) {\n if (child.getState() === State.RUNNING) {\n child.abort(agent);\n }\n }\n } else {\n // If all children have succeeded then this node has also succeeded, otherwise it is still running.\n this.setState(succeededCount === this.children.length ? State.SUCCEEDED : State.RUNNING);\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => \"PARALLEL\";\n}\n", "import Composite from \"./Composite\";\nimport Node from \"../Node\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A SELECTOR node.\n * The child nodes are executed in sequence until one succeeds or all fail.\n */\nexport default class Selector extends Composite {\n /**\n * @param attributes The node attributes.\n * @param children The child nodes.\n */\n constructor(attributes: Attribute[], protected children: Node[]) {\n super(\"selector\", attributes, children);\n }\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // Iterate over all of the children of this node.\n for (const child of this.children) {\n // If the child has never been updated or is running then we will need to update it now.\n if (child.getState() === State.READY || child.getState() === State.RUNNING) {\n // Update the child of this node.\n child.update(agent, options);\n }\n\n // If the current child has a state of 'SUCCEEDED' then this node is also a 'SUCCEEDED' node.\n if (child.getState() === State.SUCCEEDED) {\n // This node is a 'SUCCEEDED' node.\n this.setState(State.SUCCEEDED);\n\n // There is no need to check the rest of the selector nodes.\n return;\n }\n\n // If the current child has a state of 'FAILED' then we should move on to the next child.\n if (child.getState() === State.FAILED) {\n // Find out if the current child is the last one in the selector.\n // If it is then this sequence node has also failed.\n if (this.children.indexOf(child) === this.children.length - 1) {\n // This node is a 'FAILED' node.\n this.setState(State.FAILED);\n\n // There is no need to check the rest of the selector as we have completed it.\n return;\n } else {\n // The child node failed, try the next one.\n continue;\n }\n }\n\n // The node should be in the 'RUNNING' state.\n if (child.getState() === State.RUNNING) {\n // This node is a 'RUNNING' node.\n this.setState(State.RUNNING);\n\n // There is no need to check the rest of the selector as the current child is still running.\n return;\n }\n\n // The child node was not in an expected state.\n throw new Error(\"child node was not in an expected state.\");\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => \"SELECTOR\";\n}\n", "import Composite from \"./Composite\";\nimport Node from \"../Node\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A SEQUENCE node.\n * The child nodes are executed in sequence until one fails or all succeed.\n */\nexport default class Sequence extends Composite {\n /**\n * @param attributes The node attributes.\n * @param children The child nodes.\n */\n constructor(attributes: Attribute[], protected children: Node[]) {\n super(\"sequence\", attributes, children);\n }\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // Iterate over all of the children of this node.\n for (const child of this.children) {\n // If the child has never been updated or is running then we will need to update it now.\n if (child.getState() === State.READY || child.getState() === State.RUNNING) {\n // Update the child of this node.\n child.update(agent, options);\n }\n\n // If the current child has a state of 'SUCCEEDED' then we should move on to the next child.\n if (child.getState() === State.SUCCEEDED) {\n // Find out if the current child is the last one in the sequence.\n // If it is then this sequence node has also succeeded.\n if (this.children.indexOf(child) === this.children.length - 1) {\n // This node is a 'SUCCEEDED' node.\n this.setState(State.SUCCEEDED);\n\n // There is no need to check the rest of the sequence as we have completed it.\n return;\n } else {\n // The child node succeeded, but we have not finished the sequence yet.\n continue;\n }\n }\n\n // If the current child has a state of 'FAILED' then this node is also a 'FAILED' node.\n if (child.getState() === State.FAILED) {\n // This node is a 'FAILED' node.\n this.setState(State.FAILED);\n\n // There is no need to check the rest of the sequence.\n return;\n }\n\n // The node should be in the 'RUNNING' state.\n if (child.getState() === State.RUNNING) {\n // This node is a 'RUNNING' node.\n this.setState(State.RUNNING);\n\n // There is no need to check the rest of the sequence as the current child is still running.\n return;\n }\n\n // The child node was not in an expected state.\n throw new Error(\"child node was not in an expected state.\");\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => \"SEQUENCE\";\n}\n", "import createLotto from \"lotto-draw\";\n\nimport Node from \"../Node\";\nimport Composite from \"./Composite\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A LOTTO node.\n * A winning child is picked on the initial update of this node, based on ticket weighting.\n * The state of this node will match the state of the winning child.\n */\nexport default class Lotto extends Composite {\n /**\n * @param attributes The node attributes.\n * @param weights The child node weights.\n * @param children The child nodes.\n */\n constructor(attributes: Attribute[], private weights: number[] | undefined, children: Node[]) {\n super(\"lotto\", attributes, children);\n }\n\n /**\n * The child node selected to be the active one.\n */\n private selectedChild: Node | undefined;\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // If this node is in the READY state then we need to pick a winning child node.\n if (this.is(State.READY)) {\n // Create a lotto draw with which to randomly pick a child node to become the active one.\n const lottoDraw = createLotto({\n // Hook up the optional 'random' behaviour tree function option to the one used by 'lotto-draw'.\n random: options.random,\n // Pass in each child node as a participant in the lotto draw with their respective ticket count.\n participants: this.children.map((child, index) => [child, this.weights?.[index] || 1])\n });\n\n // Randomly pick a child based on ticket weighting, this will become the active child for this composite node.\n this.selectedChild = lottoDraw.draw() || undefined;\n }\n\n // If something went wrong and we don't have an active child then we should throw an error.\n if (!this.selectedChild) {\n throw new Error(\"failed to update lotto node as it has no active child\");\n }\n\n // If the selected child has never been updated or is running then we will need to update it now.\n if (this.selectedChild.getState() === State.READY || this.selectedChild.getState() === State.RUNNING) {\n this.selectedChild.update(agent, options);\n }\n\n // The state of the lotto node is the state of its selected child.\n this.setState(this.selectedChild.getState());\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => (this.weights ? `LOTTO [${this.weights.join(\",\")}]` : \"LOTTO\");\n}\n", "import Node from \"../Node\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\n\n/**\n * A decorator node that wraps a single child node.\n */\nexport default abstract class Decorator extends Node {\n /**\n * @param type The node type.\n * @param attributes The node attributes.\n * @param child The child node.\n */\n constructor(type: string, attributes: Attribute[], protected child: Node) {\n super(type, attributes, []);\n }\n\n /**\n * Gets whether this node is a leaf node.\n */\n isLeafNode = () => false;\n\n /**\n * Gets the children of this node.\n */\n getChildren = () => [this.child];\n\n /**\n * Reset the state of the node.\n */\n reset = () => {\n // Reset the state of this node.\n this.setState(State.READY);\n\n // Reset the state of the child node.\n this.child.reset();\n };\n\n /**\n * Abort the running of this node.\n * @param agent The agent.\n */\n abort = (agent: Agent) => {\n // There is nothing to do if this node is not in the running state.\n if (!this.is(State.RUNNING)) {\n return;\n }\n\n // Abort the child node.\n this.child.abort(agent);\n\n // Reset the state of this node.\n this.reset();\n\n this.getAttribute(\"exit\")?.callAgentFunction(agent, false, true);\n };\n}\n", "import Node from \"../Node\";\nimport Decorator from \"./Decorator\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A Fail node.\n * This node wraps a single child and will always move to the 'FAILED' state when the child moves to a 'SUCCEEDED' or 'FAILED' state.\n */\nexport default class Fail extends Decorator {\n /**\n * @param attributes The node attributes.\n * @param child The child node.\n */\n constructor(attributes: Attribute[], child: Node) {\n super(\"fail\", attributes, child);\n }\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // If the child has never been updated or is running then we will need to update it now.\n if (this.child.getState() === State.READY || this.child.getState() === State.RUNNING) {\n this.child.update(agent, options);\n }\n\n // The state of this node will depend in the state of its child.\n switch (this.child.getState()) {\n case State.RUNNING:\n this.setState(State.RUNNING);\n break;\n\n case State.SUCCEEDED:\n case State.FAILED:\n this.setState(State.FAILED);\n break;\n\n default:\n this.setState(State.READY);\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => \"FAIL\";\n}\n", "import Decorator from \"./Decorator\";\nimport State from \"../../State\";\nimport Node from \"../Node\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A Flip node.\n * This node wraps a single child and will flip the state of the child state.\n */\nexport default class Flip extends Decorator {\n /**\n * @param attributes The node attributes.\n * @param child The child node.\n */\n constructor(attributes: Attribute[], child: Node) {\n super(\"flip\", attributes, child);\n }\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // If the child has never been updated or is running then we will need to update it now.\n if (this.child.getState() === State.READY || this.child.getState() === State.RUNNING) {\n this.child.update(agent, options);\n }\n\n // The state of this node will depend in the state of its child.\n switch (this.child.getState()) {\n case State.RUNNING:\n this.setState(State.RUNNING);\n break;\n\n case State.SUCCEEDED:\n this.setState(State.FAILED);\n break;\n\n case State.FAILED:\n this.setState(State.SUCCEEDED);\n break;\n\n default:\n this.setState(State.READY);\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => \"FLIP\";\n}\n", "import Node from \"../Node\";\nimport Decorator from \"./Decorator\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A REPEAT node.\n * The node has a single child which can have:\n * -- A number of iterations for which to repeat the child node.\n * -- An infinite repeat loop if neither an iteration count or a condition function is defined.\n * The REPEAT node will stop and have a 'FAILED' state if its child is ever in a 'FAILED' state after an update.\n * The REPEAT node will attempt to move on to the next iteration if its child is ever in a 'SUCCEEDED' state.\n */\nexport default class Repeat extends Decorator {\n /**\n * @param attributes The node attributes.\n * @param iterations The number of iterations to repeat the child node.\n * @param iterationsMin The minimum possible number of iterations to repeat the child node.\n * @param iterationsMax The maximum possible number of iterations to repeat the child node.\n * @param child The child node.\n */\n constructor(\n attributes: Attribute[],\n private iterations: number | null,\n private iterationsMin: number | null,\n private iterationsMax: number | null,\n child: Node\n ) {\n super(\"repeat\", attributes, child);\n }\n\n /**\n * The number of target iterations to make.\n */\n private targetIterationCount: number | null = null;\n\n /**\n * The current iteration count.\n */\n private currentIterationCount: number = 0;\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // If this node is in the READY state then we need to reset the child and the target iteration count.\n if (this.is(State.READY)) {\n // Reset the child node.\n this.child.reset();\n\n // Reset the current iteration count.\n this.currentIterationCount = 0;\n\n // Set the target iteration count.\n this.setTargetIterationCount(options);\n }\n\n // Do a check to see if we can iterate. If we can then this node will move into the 'RUNNING' state.\n // If we cannot iterate then we have hit our target iteration count, which means that the node has succeeded.\n if (this.canIterate()) {\n // This node is in the running state and can do its initial iteration.\n this.setState(State.RUNNING);\n\n // We may have already completed an iteration, meaning that the child node will be in the SUCCEEDED state.\n // If this is the case then we will have to reset the child node now.\n if (this.child.getState() === State.SUCCEEDED) {\n this.child.reset();\n }\n\n // Update the child of this node.\n this.child.update(agent, options);\n\n // If the child moved into the FAILED state when we updated it then there is nothing left to do and this node has also failed.\n // If it has moved into the SUCCEEDED state then we have completed the current iteration.\n if (this.child.getState() === State.FAILED) {\n // The child has failed, meaning that this node has failed.\n this.setState(State.FAILED);\n\n return;\n } else if (this.child.getState() === State.SUCCEEDED) {\n // We have completed an iteration.\n this.currentIterationCount += 1;\n }\n } else {\n // This node is in the 'SUCCEEDED' state as we cannot iterate any more.\n this.setState(State.SUCCEEDED);\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => {\n if (this.iterations !== null) {\n return `REPEAT ${this.iterations}x`;\n } else if (this.iterationsMin !== null && this.iterationsMax !== null) {\n return `REPEAT ${this.iterationsMin}x-${this.iterationsMax}x`;\n } else {\n return \"REPEAT\";\n }\n };\n\n /**\n * Reset the state of the node.\n */\n reset = () => {\n // Reset the state of this node.\n this.setState(State.READY);\n\n // Reset the current iteration count.\n this.currentIterationCount = 0;\n\n // Reset the child node.\n this.child.reset();\n };\n\n /**\n * Gets whether an iteration can be made.\n * @returns Whether an iteration can be made.\n */\n private canIterate = () => {\n if (this.targetIterationCount !== null) {\n // We can iterate as long as we have not reached our target iteration count.\n return this.currentIterationCount < this.targetIterationCount;\n }\n\n // If neither an iteration count or a condition function were defined then we can iterate indefinitely.\n return true;\n };\n\n /**\n * Sets the target iteration count.\n * @param options The behaviour tree options object.\n */\n private setTargetIterationCount = (options: BehaviourTreeOptions) => {\n // Are we dealing with an explicit iteration count or will we be randomly picking a iteration count between the min and max iteration count.\n if (this.iterations !== null) {\n this.targetIterationCount = this.iterations;\n } else if (this.iterationsMin !== null && this.iterationsMax !== null) {\n // We will be picking a random iteration count between a min and max iteration count, if the optional 'random'\n // behaviour tree function option is defined then we will be using that, otherwise we will fall back to using Math.random.\n const random = typeof options.random === \"function\" ? options.random : Math.random;\n\n // Pick a random iteration count between a min and max iteration count.\n this.targetIterationCount = Math.floor(\n random() * (this.iterationsMax - this.iterationsMin + 1) + this.iterationsMin\n );\n } else {\n this.targetIterationCount = null;\n }\n };\n}\n", "import Node from \"../Node\";\nimport Decorator from \"./Decorator\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A RETRY node.\n * The node has a single child which can have:\n * -- A number of iterations for which to repeat the child node.\n * -- An infinite repeat loop if neither an iteration count or a condition function is defined.\n * The RETRY node will stop and have a 'SUCCEEDED' state if its child is ever in a 'SUCCEEDED' state after an update.\n * The RETRY node will attempt to move on to the next iteration if its child is ever in a 'FAILED' state.\n */\nexport default class Retry extends Decorator {\n /**\n * @param attributes The node attributes.\n * @param attempts The number of attempts to retry the child node.\n * @param attemptsMin The minimum possible number of attempts to retry the child node.\n * @param attemptsMax The maximum possible number of attempts to retry the child node.\n * @param child The child node.\n */\n constructor(\n attributes: Attribute[],\n private attempts: number | null,\n private attemptsMin: number | null,\n private attemptsMax: number | null,\n child: Node\n ) {\n super(\"retry\", attributes, child);\n }\n\n /**\n * The number of target attempts to make.\n */\n private targetAttemptCount: number | null = null;\n\n /**\n * The current attempt count.\n */\n private currentAttemptCount: number = 0;\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // If this node is in the READY state then we need to reset the child and the target attempt count.\n if (this.is(State.READY)) {\n // Reset the child node.\n this.child.reset();\n\n // Reset the current attempt count.\n this.currentAttemptCount = 0;\n\n // Set the target attempt count.\n this.setTargetAttemptCount(options);\n }\n\n // Do a check to see if we can attempt. If we can then this node will move into the 'RUNNING' state.\n // If we cannot attempt then we have hit our target attempt count, which means that the node has succeeded.\n if (this.canAttempt()) {\n // This node is in the running state and can do its initial attempt.\n this.setState(State.RUNNING);\n\n // We may have already completed an attempt, meaning that the child node will be in the FAILED state.\n // If this is the case then we will have to reset the child node now.\n if (this.child.getState() === State.FAILED) {\n this.child.reset();\n }\n\n // Update the child of this node.\n this.child.update(agent, options);\n\n // If the child moved into the SUCCEEDED state when we updated it then there is nothing left to do and this node has also succeeded.\n // If it has moved into the FAILED state then we have completed the current attempt.\n if (this.child.getState() === State.SUCCEEDED) {\n // The child has succeeded, meaning that this node has succeeded.\n this.setState(State.SUCCEEDED);\n\n return;\n } else if (this.child.getState() === State.FAILED) {\n // We have completed an attempt.\n this.currentAttemptCount += 1;\n }\n } else {\n // This node is in the 'FAILED' state as we cannot iterate any more.\n this.setState(State.FAILED);\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => {\n if (this.attempts !== null) {\n return `RETRY ${this.attempts}x`;\n } else if (this.attemptsMin !== null && this.attemptsMax !== null) {\n return `RETRY ${this.attemptsMin}x-${this.attemptsMax}x`;\n } else {\n return \"RETRY\";\n }\n };\n\n /**\n * Reset the state of the node.\n */\n reset = () => {\n // Reset the state of this node.\n this.setState(State.READY);\n\n // Reset the current attempt count.\n this.currentAttemptCount = 0;\n\n // Reset the child node.\n this.child.reset();\n };\n\n /**\n * Gets whether an attempt can be made.\n * @returns Whether an attempt can be made.\n */\n canAttempt = () => {\n if (this.targetAttemptCount !== null) {\n // We can attempt as long as we have not reached our target attempt count.\n return this.currentAttemptCount < this.targetAttemptCount;\n }\n\n // If neither an attempt count or a condition function were defined then we can attempt indefinitely.\n return true;\n };\n\n /**\n * Sets the target attempt count.\n * @param options The behaviour tree options object.\n */\n setTargetAttemptCount = (options: BehaviourTreeOptions) => {\n // Are we dealing with an explicit attempt count or will we be randomly picking an attempt count between the min and max attempt count.\n if (this.attempts !== null) {\n this.targetAttemptCount = this.attempts;\n } else if (this.attemptsMin !== null && this.attemptsMax !== null) {\n // We will be picking a random attempt count between a min and max attempt count, if the optional 'random'\n // behaviour tree function option is defined then we will be using that, otherwise we will fall back to using Math.random.\n const random = typeof options.random === \"function\" ? options.random : Math.random;\n\n // Pick a random attempt count between a min and max attempt count.\n this.targetAttemptCount = Math.floor(\n random() * (this.attemptsMax - this.attemptsMin + 1) + this.attemptsMin\n );\n } else {\n this.targetAttemptCount = null;\n }\n };\n}\n", "import Node from \"../Node\";\nimport Decorator from \"./Decorator\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A Root node.\n * The root node will have a single child.\n */\nexport default class Root extends Decorator {\n /**\n * @param attributes The node attributes.\n * @param child The child node.\n */\n constructor(attributes: Attribute[], child: Node) {\n super(\"root\", attributes, child);\n }\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // If the child has never been updated or is running then we will need to update it now.\n if (this.child.getState() === State.READY || this.child.getState() === State.RUNNING) {\n // Update the child of this node.\n this.child.update(agent, options);\n }\n\n // The state of the root node is the state of its child.\n this.setState(this.child.getState());\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => \"ROOT\";\n}\n", "import Node from \"../Node\";\nimport Decorator from \"./Decorator\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A Succeed node.\n * This node wraps a single child and will always move to the 'SUCCEEDED' state when the child moves to a 'SUCCEEDED' or 'FAILED' state.\n */\nexport default class Succeed extends Decorator {\n /**\n * @param attributes The node attributes.\n * @param child The child node.\n */\n constructor(attributes: Attribute[], child: Node) {\n super(\"succeed\", attributes, child);\n }\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // If the child has never been updated or is running then we will need to update it now.\n if (this.child.getState() === State.READY || this.child.getState() === State.RUNNING) {\n this.child.update(agent, options);\n }\n\n // The state of this node will depend in the state of its child.\n switch (this.child.getState()) {\n case State.RUNNING:\n this.setState(State.RUNNING);\n break;\n\n case State.SUCCEEDED:\n case State.FAILED:\n this.setState(State.SUCCEEDED);\n break;\n\n default:\n this.setState(State.READY);\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => \"SUCCEED\";\n}\n", "import Node from \"../Node\";\n\n/**\n * A leaf node.\n */\nexport default abstract class Leaf extends Node {\n /**\n * Gets whether this node is a leaf node.\n */\n isLeafNode = () => true;\n}\n", "import { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\nimport State, { CompleteState } from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Leaf from \"./Leaf\";\nimport Lookup from \"../../Lookup\";\nimport Attribute from \"../../attributes/Attribute\";\n\n/**\n * An Action leaf node.\n * This represents an immediate or ongoing state of behaviour.\n */\nexport default class Action extends Leaf {\n /**\n * @param attributes The node attributes.\n * @param actionName The action name.\n * @param actionArguments The array of action argument definitions.\n */\n constructor(attributes: Attribute[], private actionName: string, private actionArguments: any[]) {\n super(\"action\", attributes, actionArguments);\n }\n\n /**\n * Whether there is a pending update promise.\n */\n private isUsingUpdatePromise = false;\n\n /**\n * The finished state result of an update promise.\n */\n private updatePromiseStateResult: CompleteState | null = null;\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // If the result of this action depends on an update promise then there is nothing to do until\n // it resolves, unless there has been a value set as a result of the update promise resolving.\n if (this.isUsingUpdatePromise) {\n // Check whether the update promise has resolved with a state value.\n if (this.updatePromiseStateResult) {\n // Set the state of this node to match the state returned by the promise.\n this.setState(this.updatePromiseStateResult);\n }\n\n return;\n }\n\n // Attempt to get the invoker for the action function.\n const actionFuncInvoker = Lookup.getFuncInvoker(agent, this.actionName);\n\n // The action function should be defined.\n if (actionFuncInvoker === null) {\n throw new Error(\n `cannot update action node as the action '${this.actionName}' function is not defined on the agent and has not been registered`\n );\n }\n\n // Call the action function, the result of which may be:\n // - The finished state of this action node.\n // - A promise to return a finished node state.\n // - Undefined if the node should remain in the running state.\n const updateResult = actionFuncInvoker(this.actionArguments) as CompleteState | Promise;\n\n if (updateResult instanceof Promise) {\n updateResult.then(\n (result) => {\n // If 'isUpdatePromisePending' is null then the promise was cleared as it was resolving, probably via an abort of reset.\n if (!this.isUsingUpdatePromise) {\n return;\n }\n\n // Check to make sure the result is a valid finished state.\n if (result !== State.SUCCEEDED && result !== State.FAILED) {\n throw new Error(\n \"action node promise resolved with an invalid value, expected a State.SUCCEEDED or State.FAILED value to be returned\"\n );\n }\n\n // Set pending update promise state result to be processed on next update.\n this.updatePromiseStateResult = result;\n },\n (reason) => {\n // If 'isUpdatePromisePending' is null then the promise was cleared as it was resolving, probably via an abort of reset.\n if (!this.isUsingUpdatePromise) {\n return;\n }\n\n // Just throw whatever was returned as the rejection argument.\n throw new Error(reason);\n }\n );\n\n // This node will be in the 'RUNNING' state until the update promise resolves.\n this.setState(State.RUNNING);\n\n // We are now waiting for the promise returned by the use to resolve before we know what state this node is in.\n this.isUsingUpdatePromise = true;\n } else {\n // Validate the returned value.\n this.validateUpdateResult(updateResult);\n\n // Set the state of this node, this may be undefined, which just means that the node is still in the 'RUNNING' state.\n this.setState(updateResult || State.RUNNING);\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => this.actionName;\n\n /**\n * Reset the state of the node.\n */\n reset = () => {\n // Reset the state of this node.\n this.setState(State.READY);\n\n // There is no longer an update promise that we care about.\n this.isUsingUpdatePromise = false;\n this.updatePromiseStateResult = null;\n };\n\n /**\n * Validate the result of an update function call.\n * @param result The result of an update function call.\n */\n private validateUpdateResult = (result: CompleteState | boolean) => {\n switch (result) {\n case State.SUCCEEDED:\n case State.FAILED:\n case undefined:\n return;\n default:\n throw new Error(\n `action '${this.actionName}' 'onUpdate' returned an invalid response, expected an optional State.SUCCEEDED or State.FAILED value to be returned`\n );\n }\n };\n}\n", "import { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Leaf from \"./Leaf\";\nimport Lookup from \"../../Lookup\";\nimport Attribute from \"../../attributes/Attribute\";\n\n/**\n * A Condition leaf node.\n * This will succeed or fail immediately based on an agent predicate, without moving to the 'RUNNING' state.\n */\nexport default class Condition extends Leaf {\n /**\n * @param attributes The node attributes.\n * @param conditionName The name of the condition function.\n * @param conditionArguments The array of condition argument definitions.\n */\n constructor(attributes: Attribute[], private conditionName: string, private conditionArguments: any[]) {\n super(\"condition\", attributes, conditionArguments);\n }\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // Attempt to get the invoker for the condition function.\n const conditionFuncInvoker = Lookup.getFuncInvoker(agent, this.conditionName);\n\n // The condition function should be defined.\n if (conditionFuncInvoker === null) {\n throw new Error(\n `cannot update condition node as the condition '${this.conditionName}' function is not defined on the agent and has not been registered`\n );\n }\n\n // Call the condition function to determine the state of this node.\n this.setState(!!conditionFuncInvoker(this.conditionArguments) ? State.SUCCEEDED : State.FAILED);\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => this.conditionName;\n}\n", "import Leaf from \"./Leaf\";\nimport State from \"../../State\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { Agent } from \"../../Agent\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A WAIT node.\n * The state of this node will change to SUCCEEDED after a duration of time\n */\nexport default class Wait extends Leaf {\n /**\n * @param attributes The node attributes.\n * @param duration The duration that this node will wait to succeed in milliseconds.\n * @param durationMin The minimum possible duration in milliseconds that this node will wait to succeed.\n * @param durationMax The maximum possible duration in milliseconds that this node will wait to succeed.\n */\n constructor(\n attributes: Attribute[],\n private duration: number | null,\n private durationMin: number | null,\n private durationMax: number | null\n ) {\n super(\"wait\", attributes, []);\n }\n\n /**\n * The time in milliseconds at which this node was first updated.\n */\n private initialUpdateTime: number = 0;\n\n /**\n * The total duration in milliseconds that this node will be waiting for.\n */\n private totalDuration: number | null = null;\n\n /**\n * The duration in milliseconds that this node has been waiting for.\n */\n private waitedDuration: number = 0;\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // If this node is in the READY state then we need to set the initial update time.\n if (this.is(State.READY)) {\n // Set the initial update time.\n this.initialUpdateTime = new Date().getTime();\n\n // Set the initial waited duration.\n this.waitedDuration = 0;\n\n // Are we dealing with an explicit duration or will we be randomly picking a duration between the min and max duration.\n if (this.duration !== null) {\n this.totalDuration = this.duration;\n } else if (this.durationMin !== null && this.durationMax !== null) {\n // We will be picking a random duration between a min and max duration, if the optional 'random' behaviour tree\n // function option is defined then we will be using that, otherwise we will fall back to using Math.random.\n const random = typeof options.random === \"function\" ? options.random : Math.random;\n\n // Pick a random duration between a min and max duration.\n this.totalDuration = Math.floor(\n random() * (this.durationMax - this.durationMin + 1) + this.durationMin\n );\n } else {\n this.totalDuration = null;\n }\n\n // The node is now running until we finish waiting.\n this.setState(State.RUNNING);\n }\n\n // If we have no total duration then this wait node will wait indefinitely until it is aborted.\n if (this.totalDuration === null) {\n return;\n }\n\n // If we have a 'getDeltaTime' function defined as part of our options then we will use it to figure out how long we have waited for.\n if (typeof options.getDeltaTime === \"function\") {\n // Get the delta time.\n const deltaTime = options.getDeltaTime();\n\n // Our delta time must be a valid number and cannot be NaN.\n if (typeof deltaTime !== \"number\" || isNaN(deltaTime)) {\n throw new Error(\"The delta time must be a valid number and not NaN.\");\n }\n\n // Update the amount of time that this node has been waiting for based on the delta time.\n this.waitedDuration += deltaTime * 1000;\n } else {\n // We are not using a delta time, so we will just work out hom much time has passed since the first update.\n this.waitedDuration = new Date().getTime() - this.initialUpdateTime;\n }\n\n // Have we waited long enough?\n if (this.waitedDuration >= this.totalDuration) {\n // We have finished waiting!\n this.setState(State.SUCCEEDED);\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => {\n if (this.duration !== null) {\n return `WAIT ${this.duration}ms`;\n } else if (this.durationMin !== null && this.durationMax !== null) {\n return `WAIT ${this.durationMin}ms-${this.durationMax}ms`;\n } else {\n return \"WAIT\";\n }\n };\n}\n", "import Guard from \"./guards/Guard\";\n\nexport type AttributeDetails = {\n /** The attribute type. */\n type: string;\n\n /** The attribute arguments. */\n args: any[];\n};\n\n/**\n * A base node attribute.\n */\nexport default abstract class Attribute {\n /**\n * @param type The node attribute type.\n * @param args The array of attribute arguments.\n */\n constructor(public type: string, public args: any[]) {}\n\n /**\n * Gets the attribute details.\n */\n abstract getDetails(): TAttributeDetails;\n\n /**\n * Gets whether this attribute is a guard.\n */\n abstract isGuard: () => this is Guard;\n}\n", "import { Agent } from \"../../Agent\";\nimport Attribute, { AttributeDetails } from \"../Attribute\";\n\nexport type GuardAttributeDetails = {\n /** The name of the condition function that determines whether the guard is satisfied. */\n condition: string;\n} & AttributeDetails;\n\n/**\n * A base node guard attribute.\n */\nexport default abstract class Guard extends Attribute {\n /**\n * @param type The node attribute type.\n * @param args The array of decorator argument definitions.\n * @param condition The name of the condition function that determines whether the guard is satisfied.\n */\n constructor(type: string, args: any[], private condition: string) {\n super(type, args);\n }\n\n /**\n * Gets the name of the condition function that determines whether the guard is satisfied.\n */\n getCondition = () => this.condition;\n\n /**\n * Gets whether this attribute is a guard.\n */\n isGuard = () => true;\n\n /**\n * Gets the attribute details.\n */\n getDetails(): GuardAttributeDetails {\n return {\n type: this.type,\n args: this.args,\n condition: this.getCondition()\n };\n }\n\n /**\n * Gets whether the guard is satisfied.\n * @param agent The agent.\n * @returns Whether the guard is satisfied.\n */\n abstract isSatisfied(agent: Agent): boolean;\n}\n", "import Guard from \"./Guard\";\nimport Lookup from \"../../Lookup\";\nimport { Agent } from \"../../Agent\";\n\n/**\n * A WHILE guard which is satisfied as long as the given condition remains true.\n */\nexport default class While extends Guard {\n /**\n * @param condition The name of the condition function that determines whether the guard is satisfied.\n * @param args The array of decorator argument definitions.\n */\n constructor(condition: string, args: any[]) {\n super(\"while\", args, condition);\n }\n\n /**\n * Gets whether the guard is satisfied.\n * @param agent The agent.\n * @returns Whether the guard is satisfied.\n */\n isSatisfied = (agent: Agent) => {\n // Attempt to get the invoker for the condition function.\n const conditionFuncInvoker = Lookup.getFuncInvoker(agent, this.getCondition());\n\n // The condition function should be defined.\n if (conditionFuncInvoker === null) {\n throw new Error(\n `cannot evaluate node guard as the condition '${this.getCondition()}' function is not defined on the agent and has not been registered`\n );\n }\n\n // Call the condition function to determine whether this guard is satisfied.\n return !!conditionFuncInvoker(this.args);\n };\n}\n", "import Guard from \"./Guard\";\nimport Lookup from \"../../Lookup\";\nimport { Agent } from \"../../Agent\";\n\n/**\n * An UNTIL guard which is satisfied as long as the given condition remains false.\n */\nexport default class Until extends Guard {\n /**\n * @param condition The name of the condition function that determines whether the guard is satisfied.\n * @param args The array of decorator argument definitions.\n */\n constructor(condition: string, args: any[]) {\n super(\"until\", args, condition);\n }\n\n /**\n * Gets whether the guard is satisfied.\n * @param agent The agent.\n * @returns Whether the guard is satisfied.\n */\n isSatisfied = (agent: Agent) => {\n // Attempt to get the invoker for the condition function.\n const conditionFuncInvoker = Lookup.getFuncInvoker(agent, this.getCondition());\n\n // The condition function should be defined.\n if (conditionFuncInvoker === null) {\n throw new Error(\n `cannot evaluate node guard as the condition '${this.getCondition()}' function is not defined on the agent and has not been registered`\n );\n }\n\n // Call the condition function to determine whether this guard is satisfied.\n return !!!conditionFuncInvoker(this.args);\n };\n}\n", "import { Agent } from \"../../Agent\";\nimport Attribute, { AttributeDetails } from \"../Attribute\";\n\nexport type CallbackAttributeDetails = {\n /** The name of the agent function that is called. */\n functionName: string;\n} & AttributeDetails;\n\n/**\n * A base node callback attribute.\n */\nexport default abstract class Callback extends Attribute {\n /**\n * @param type The node attribute type.\n * @param args The array of decorator argument definitions.\n * @param functionName The name of the agent function to call.\n */\n constructor(type: string, args: any[], private functionName: string) {\n super(type, args);\n }\n\n /**\n * Gets the name of the agent function to call.\n */\n getFunctionName = () => this.functionName;\n\n /**\n * Gets whether this attribute is a guard.\n */\n isGuard = () => false;\n\n /**\n * Gets the attribute details.\n */\n getDetails(): CallbackAttributeDetails {\n return {\n type: this.type,\n args: this.args,\n functionName: this.getFunctionName()\n };\n }\n\n /**\n * Attempt to call the agent function that this callback refers to.\n * @param agent The agent.\n */\n abstract callAgentFunction: (agent: Agent, isSuccess: boolean, isAborted: boolean) => void;\n}\n", "import Callback from \"./Callback\";\nimport Lookup from \"../../Lookup\";\nimport { Agent } from \"../../Agent\";\n\n/**\n * An ENTRY callback which defines an agent function to call when the associated node is updated and moves out of running state.\n */\nexport default class Entry extends Callback {\n /**\n * @param functionName The name of the agent function to call.\n * @param args The array of callback argument definitions.\n */\n constructor(functionName: string, args: any[]) {\n super(\"entry\", args, functionName);\n }\n\n /**\n * Attempt to call the agent function that this callback refers to.\n * @param agent The agent.\n */\n callAgentFunction = (agent: Agent) => {\n // Attempt to get the invoker for the callback function.\n const callbackFuncInvoker = Lookup.getFuncInvoker(agent, this.getFunctionName());\n\n // The callback function should be defined.\n if (callbackFuncInvoker === null) {\n throw new Error(\n `cannot call entry function '${this.getFunctionName()}' as is not defined on the agent and has not been registered`\n );\n }\n\n // Call the callback function.\n callbackFuncInvoker(this.args);\n };\n}\n", "import Callback from \"./Callback\";\nimport Lookup from \"../../Lookup\";\nimport { Agent } from \"../../Agent\";\n\n/**\n * A STEP callback which defines an agent function to call when the associated node is updated.\n */\nexport default class Step extends Callback {\n /**\n * @param functionName The name of the agent function to call.\n * @param args The array of callback argument definitions.\n */\n constructor(functionName: string, args: any[]) {\n super(\"step\", args, functionName);\n }\n\n /**\n * Attempt to call the agent function that this callback refers to.\n * @param agent The agent.\n */\n callAgentFunction = (agent: Agent) => {\n // Attempt to get the invoker for the callback function.\n const callbackFuncInvoker = Lookup.getFuncInvoker(agent, this.getFunctionName());\n\n // The callback function should be defined.\n if (callbackFuncInvoker === null) {\n throw new Error(\n `cannot call step function '${this.getFunctionName()}' as is not defined on the agent and has not been registered`\n );\n }\n\n // Call the callback function.\n callbackFuncInvoker(this.args);\n };\n}\n", "import Callback from \"./Callback\";\nimport Lookup from \"../../Lookup\";\nimport { Agent } from \"../../Agent\";\n\n/**\n * An EXIT callback which defines an agent function to call when the associated node is updated and moves to a finished state or is aborted.\n */\nexport default class Exit extends Callback {\n /**\n * @param functionName The name of the agent function to call.\n * @param args The array of callback argument definitions.\n */\n constructor(functionName: string, args: any[]) {\n super(\"exit\", args, functionName);\n }\n\n /**\n * Attempt to call the agent function that this callback refers to.\n * @param agent The agent.\n * @param isSuccess Whether the decorated node was left with a success state.\n * @param isAborted Whether the decorated node was aborted.\n */\n callAgentFunction = (agent: Agent, isSuccess: boolean, isAborted: boolean) => {\n // Attempt to get the invoker for the callback function.\n const callbackFuncInvoker = Lookup.getFuncInvoker(agent, this.getFunctionName());\n\n // The callback function should be defined.\n if (callbackFuncInvoker === null) {\n throw new Error(\n `cannot call exit function '${this.getFunctionName()}' as is not defined on the agent and has not been registered`\n );\n }\n\n // Call the callback function\n callbackFuncInvoker([{ value: { succeeded: isSuccess, aborted: isAborted } }, ...this.args]);\n };\n}\n", "import { AnyNodeDefinition, RootNodeDefinition } from \"./BehaviourTreeDefinition\";\nimport GuardPath, { GuardPathPart } from \"./attributes/guards/GuardPath\";\nimport { validateBranchSubtreeLinks } from \"./BehaviourTreeDefinitionValidator\";\nimport { isInteger } from \"./BehaviourTreeDefinitionUtilities\";\nimport Node from \"./nodes/Node\";\nimport Composite from \"./nodes/composite/Composite\";\nimport Decorator from \"./nodes/decorator/Decorator\";\nimport Parallel from \"./nodes/composite/Parallel\";\nimport Selector from \"./nodes/composite/Selector\";\nimport Sequence from \"./nodes/composite/Sequence\";\nimport Lotto from \"./nodes/composite/Lotto\";\nimport Fail from \"./nodes/decorator/Fail\";\nimport Flip from \"./nodes/decorator/Flip\";\nimport Repeat from \"./nodes/decorator/Repeat\";\nimport Retry from \"./nodes/decorator/Retry\";\nimport Root from \"./nodes/decorator/Root\";\nimport Succeed from \"./nodes/decorator/Succeed\";\nimport Action from \"./nodes/leaf/Action\";\nimport Condition from \"./nodes/leaf/Condition\";\nimport Wait from \"./nodes/leaf/Wait\";\nimport Lookup from \"./Lookup\";\nimport Attribute from \"./attributes/Attribute\";\nimport While from \"./attributes/guards/While\";\nimport Until from \"./attributes/guards/Until\";\nimport Entry from \"./attributes/callbacks/Entry\";\nimport Step from \"./attributes/callbacks/Step\";\nimport Exit from \"./attributes/callbacks/Exit\";\n\n/**\n * A type representing any node instance in a behaviour tree.\n */\ntype AnyNode =\n | Root\n | Action\n | Condition\n | Wait\n | Sequence\n | Selector\n | Lotto\n | Parallel\n | Repeat\n | Retry\n | Flip\n | Succeed\n | Fail;\n\n/**\n * A type defining a mapping of root node identifiers to root node definitions.\n */\ntype RootNodeDefinitionMap = { [key: string | symbol]: RootNodeDefinition };\n\n/**\n * A symbol to use as the main root key in any root node mappings.\n */\nconst MAIN_ROOT_NODE_KEY = Symbol(\"__root__\");\n\n/**\n * Build and populate the root nodes based on the provided definition, assuming that the definition has been validated.\n * @param definition The root node definitions.\n * @returns The built and populated root node definitions.\n */\nexport default function buildRootNode(definition: RootNodeDefinition[]): Root {\n // Create a mapping of root node identifers to root node definitions, including globally registered subtree root node definitions.\n const rootNodeDefinitionMap = createRootNodeDefinitionMap(definition);\n\n // Now that we have all of our root node definitons (those part of the tree definition and those globally\n // registered) we should validate the definition. This will also double-check that we dont have any circular\n // dependencies in our branch -> subtree references and that we have no broken branch -> subtree links.\n validateBranchSubtreeLinks(definition, true);\n\n // Create our populated tree of node instances, starting with our main root node.\n const rootNode = nodeFactory(rootNodeDefinitionMap[MAIN_ROOT_NODE_KEY], rootNodeDefinitionMap) as Root;\n\n // Set a guard path on every leaf of the tree to evaluate as part of each update.\n applyLeafNodeGuardPaths(rootNode);\n\n // We only need to return the main root node.\n return rootNode;\n}\n\n/**\n * A factory function which creates a node instance based on the specified definition.\n * @param definition The node definition.\n * @param rootNodeDefinitionMap The mapping of root node identifers to root node definitions, including globally registered subtree root node definitions.\n * @returns A node instance based on the specified definition.\n */\nfunction nodeFactory(definition: AnyNodeDefinition, rootNodeDefinitionMap: RootNodeDefinitionMap): AnyNode {\n // Get the attributes for the node.\n const attributes = nodeAttributesFactory(definition);\n\n // Create the node instance based on the definition type.\n switch (definition.type) {\n case \"root\":\n return new Root(attributes, nodeFactory(definition.child, rootNodeDefinitionMap));\n\n case \"repeat\":\n let iterations: number | null = null;\n let iterationsMin: number | null = null;\n let iterationsMax: number | null = null;\n\n if (Array.isArray(definition.iterations)) {\n iterationsMin = definition.iterations[0];\n iterationsMax = definition.iterations[1];\n } else if (isInteger(definition.iterations)) {\n iterations = definition.iterations!;\n }\n\n return new Repeat(\n attributes,\n iterations,\n iterationsMin,\n iterationsMax,\n nodeFactory(definition.child, rootNodeDefinitionMap)\n );\n\n case \"retry\":\n let attempts: number | null = null;\n let attemptsMin: number | null = null;\n let attemptsMax: number | null = null;\n\n if (Array.isArray(definition.attempts)) {\n attemptsMin = definition.attempts[0];\n attemptsMax = definition.attempts[1];\n } else if (isInteger(definition.attempts)) {\n attempts = definition.attempts!;\n }\n\n return new Retry(\n attributes,\n attempts,\n attemptsMin,\n attemptsMax,\n nodeFactory(definition.child, rootNodeDefinitionMap)\n );\n\n case \"flip\":\n return new Flip(attributes, nodeFactory(definition.child, rootNodeDefinitionMap));\n\n case \"succeed\":\n return new Succeed(attributes, nodeFactory(definition.child, rootNodeDefinitionMap));\n\n case \"fail\":\n return new Fail(attributes, nodeFactory(definition.child, rootNodeDefinitionMap));\n\n case \"sequence\":\n return new Sequence(\n attributes,\n definition.children.map((child) => nodeFactory(child, rootNodeDefinitionMap))\n );\n\n case \"selector\":\n return new Selector(\n attributes,\n definition.children.map((child) => nodeFactory(child, rootNodeDefinitionMap))\n );\n\n case \"parallel\":\n return new Parallel(\n attributes,\n definition.children.map((child) => nodeFactory(child, rootNodeDefinitionMap))\n );\n\n case \"lotto\":\n return new Lotto(\n attributes,\n definition.weights,\n definition.children.map((child) => nodeFactory(child, rootNodeDefinitionMap))\n );\n\n case \"branch\":\n return nodeFactory(rootNodeDefinitionMap[definition.ref].child, rootNodeDefinitionMap);\n\n case \"action\":\n return new Action(attributes, definition.call, definition.args || []);\n\n case \"condition\":\n return new Condition(attributes, definition.call, definition.args || []);\n\n case \"wait\":\n let duration: number | null = null;\n let durationMin: number | null = null;\n let durationMax: number | null = null;\n\n if (Array.isArray(definition.duration)) {\n durationMin = definition.duration[0];\n durationMax = definition.duration[1];\n } else if (isInteger(definition.duration)) {\n duration = definition.duration!;\n }\n\n return new Wait(attributes, duration, durationMin, durationMax);\n }\n}\n\n/**\n * Creates an array of node attribute instances based on the specified node definition.\n * @param definition The node definition.\n * @returns An array of node attribute instances based on the specified node definition.\n */\nfunction nodeAttributesFactory(definition: AnyNodeDefinition): Attribute[] {\n const attributes: Attribute[] = [];\n\n if (definition.while) {\n attributes.push(new While(definition.while.call, definition.while.args ?? []));\n }\n\n if (definition.until) {\n attributes.push(new Until(definition.until.call, definition.until.args ?? []));\n }\n\n if (definition.entry) {\n attributes.push(new Entry(definition.entry.call, definition.entry.args ?? []));\n }\n\n if (definition.step) {\n attributes.push(new Step(definition.step.call, definition.step.args ?? []));\n }\n\n if (definition.exit) {\n attributes.push(new Exit(definition.exit.call, definition.exit.args ?? []));\n }\n\n return attributes;\n}\n\n/**\n * Creates a mapping of root node identifers to root node definitions, mixing in globally registered subtree root node definitions.\n * @param definition The root node definitions.\n * @returns A mapping of root node identifers to root node definitions, including globally registered subtree root node definitions.\n */\nfunction createRootNodeDefinitionMap(definition: RootNodeDefinition[]): RootNodeDefinitionMap {\n // Create a mapping of root node identifers to root node definitions.\n const rootNodeMap: RootNodeDefinitionMap = {};\n\n // Add in any registered subtree root node definitions.\n for (const [name, rootNodeDefinition] of Object.entries(Lookup.getSubtrees())) {\n // The name used when registering the subtree will be used as the root node identifier.\n rootNodeMap[name] = { ...rootNodeDefinition, id: name };\n }\n\n // Populate the map with the root node definitions that were included with the tree definition.\n // We do this after adding any registered subtrees as we want these to take presedence.\n for (const rootNodeDefinition of definition) {\n rootNodeMap[rootNodeDefinition.id ?? MAIN_ROOT_NODE_KEY] = rootNodeDefinition;\n }\n\n return rootNodeMap;\n}\n\n/**\n * Applies a guard path to every leaf of the tree to evaluate as part of each update.\n * @param root The main root tree node.\n */\nfunction applyLeafNodeGuardPaths(root: Root) {\n const nodePaths: Node[][] = [];\n\n const findLeafNodes = (path: Node[], node: Node) => {\n // Add the current node to the path.\n path = path.concat(node);\n\n // Check whether the current node is a leaf node.\n if (node.isLeafNode()) {\n nodePaths.push(path);\n } else {\n (node as Composite | Decorator).getChildren().forEach((child) => findLeafNodes(path, child));\n }\n };\n\n // Find all leaf node paths, starting from the root.\n findLeafNodes([], root);\n\n nodePaths.forEach((path) => {\n // Each node in the current path will have to be assigned a guard path, working from the root outwards.\n for (let depth = 0; depth < path.length; depth++) {\n // Get the node in the path at the current depth.\n const currentNode = path[depth];\n\n // The node may already have been assigned a guard path, if so just skip it.\n if (currentNode.hasGuardPath()) {\n continue;\n }\n\n // Create the guard path for the current node.\n const guardPath = new GuardPath(\n path\n .slice(0, depth + 1)\n .map((node) => ({ node, guards: node.getGuardAttributes() }))\n .filter((details) => details.guards.length > 0)\n );\n\n // Assign the guard path to the current node.\n currentNode.setGuardPath(guardPath);\n }\n });\n}\n", "import State, { AnyState } from \"./State\";\nimport Lookup from \"./Lookup\";\nimport Node from \"./nodes/Node\";\nimport Root from \"./nodes/decorator/Root\";\nimport Composite from \"./nodes/composite/Composite\";\nimport Decorator from \"./nodes/decorator/Decorator\";\nimport { Agent, GlobalFunction } from \"./Agent\";\nimport { CallbackAttributeDetails } from \"./attributes/callbacks/Callback\";\nimport { GuardAttributeDetails } from \"./attributes/guards/Guard\";\nimport { BehaviourTreeOptions } from \"./BehaviourTreeOptions\";\nimport { convertMDSLToJSON } from \"./mdsl/MDSLDefinitionParser\";\nimport { RootNodeDefinition } from \"./BehaviourTreeDefinition\";\nimport { validateDefinition, validateJSONDefinition } from \"./BehaviourTreeDefinitionValidator\";\nimport buildRootNode from \"./BehaviourTreeBuilder\";\nimport { isNullOrUndefined } from \"./BehaviourTreeDefinitionUtilities\";\n\n// Purely for outside inspection of the tree.\nexport type FlattenedTreeNode = {\n id: string;\n type: string;\n caption: string;\n state: AnyState;\n guards: GuardAttributeDetails[];\n callbacks: CallbackAttributeDetails[];\n args: any[];\n parentId: string | null;\n};\n\n/**\n * A representation of a behaviour tree.\n */\nexport class BehaviourTree {\n /**\n * The main root tree node.\n */\n private readonly _rootNode: Root;\n\n /**\n * Creates a new instance of the BehaviourTree class.\n * @param definition The behaviour tree definition as either an MDSL string, root node definition object or array of root node definition objects.\n * @param agent The agent instance that this behaviour tree is modelling behaviour for.\n * @param options The behaviour tree options object.\n */\n constructor(\n definition: string | RootNodeDefinition | RootNodeDefinition[],\n private agent: Agent,\n private options: BehaviourTreeOptions = {}\n ) {\n // The tree definition must be defined.\n if (isNullOrUndefined(definition)) {\n throw new Error(\"tree definition not defined\");\n }\n\n // The agent must be defined and not null.\n if (typeof agent !== \"object\" || agent === null) {\n throw new Error(\"the agent must be an object and not null\");\n }\n\n // We should validate the definition before we try to build the tree nodes.\n const { succeeded, errorMessage, json } = validateDefinition(definition);\n\n // Did our validation fail without error?\n if (!succeeded) {\n throw new Error(`invalid definition: ${errorMessage}`);\n }\n\n // Double check that we did actually get our json definition as part of our definition validtion.\n if (!json) {\n throw new Error(\n \"expected json definition to be returned as part of successful definition validation response\"\n );\n }\n\n try {\n // Create the populated tree of behaviour tree nodes and get the root node.\n this._rootNode = buildRootNode(json);\n } catch (exception) {\n // There was an issue in trying build and populate the behaviour tree.\n throw new Error(`error building tree: ${(exception as Error).message}`);\n }\n }\n\n /**\n * Gets whether the tree is in the RUNNING state.\n * @returns true if the tree is in the RUNNING state, otherwise false.\n */\n isRunning() {\n return this._rootNode.getState() === State.RUNNING;\n }\n\n /**\n * Gets the current tree state of SUCCEEDED, FAILED, READY or RUNNING.\n * @returns The current tree state.\n */\n getState() {\n return this._rootNode.getState();\n }\n\n /**\n * Step the tree.\n * 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.\n * 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\n * 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.\n *\n * 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.\n */\n step() {\n // If the root node has already been stepped to completion then we need to reset it.\n if (this._rootNode.getState() === State.SUCCEEDED || this._rootNode.getState() === State.FAILED) {\n this._rootNode.reset();\n }\n\n try {\n this._rootNode.update(this.agent, this.options);\n } catch (exception) {\n throw new Error(`error stepping tree: ${(exception as Error).message}`);\n }\n }\n\n /**\n * Resets the tree from the root node outwards to each nested node, giving each a state of READY.\n */\n reset() {\n this._rootNode.reset();\n }\n\n /**\n * Gets the flattened details of every node in the tree.\n * @returns The flattened details of every node in the tree.\n */\n getFlattenedNodeDetails(): FlattenedTreeNode[] {\n // Create an empty flattened array of tree nodes.\n const flattenedTreeNodes: FlattenedTreeNode[] = [];\n\n /**\n * Helper function to process a node instance and push details into the flattened tree nodes array.\n * @param node The current node.\n * @param parentUid The UID of the node parent, or null if the node is the main root node.\n */\n const processNode = (node: Node, parentUid: string | null) => {\n // Get the guard and callback attribute details for this node.\n const guards = node\n .getAttributes()\n .filter((attribute) => attribute.isGuard())\n .map((attribute) => attribute.getDetails()) as GuardAttributeDetails[];\n const callbacks = node\n .getAttributes()\n .filter((attribute) => !attribute.isGuard())\n .map((attribute) => attribute.getDetails()) as CallbackAttributeDetails[];\n\n // Push the current node into the flattened nodes array.\n flattenedTreeNodes.push({\n id: node.getUid(),\n type: node.getType(),\n caption: node.getName(),\n state: node.getState(),\n guards,\n callbacks,\n args: node.getArguments(),\n parentId: parentUid\n });\n\n // Process each of the nodes children if it is not a leaf node.\n if (!node.isLeafNode()) {\n (node as Composite | Decorator)\n .getChildren()\n .forEach((child) => processNode(child, (node as Composite | Decorator).getUid()));\n }\n };\n\n // Convert the nested node structure into a flattened array of node details.\n processNode(this._rootNode, null);\n\n return flattenedTreeNodes;\n }\n\n /**\n * Registers the action/condition/guard/callback function or subtree with the given name.\n * @param name The name of the function or subtree to register.\n * @param value The function or subtree definition to register.\n */\n static register(name: string, value: GlobalFunction | string | RootNodeDefinition) {\n // Are we going to register a action/condition/guard/callback function?\n if (typeof value === \"function\") {\n Lookup.setFunc(name, value);\n return;\n }\n\n // We are not registering an action/condition/guard/callback function, so we must be registering a subtree.\n if (typeof value === \"string\") {\n let rootNodeDefinitions: RootNodeDefinition[];\n\n // We will assume that any string passed in will be a mdsl definition.\n try {\n rootNodeDefinitions = convertMDSLToJSON(value);\n } catch (exception) {\n throw new Error(`error registering definition, invalid MDSL: ${(exception as Error).message}`);\n }\n\n // This function should only ever be called with a definition containing a single unnamed root node.\n if (rootNodeDefinitions.length != 1 || rootNodeDefinitions[0].id !== null) {\n throw new Error(\"error registering definition: expected a single unnamed root node\");\n }\n\n try {\n // We should validate the subtree as we don't want invalid subtrees available via the lookup.\n const { succeeded, errorMessage } = validateJSONDefinition(rootNodeDefinitions[0]);\n\n // Did our validation fail without error?\n if (!succeeded) {\n throw new Error(errorMessage);\n }\n } catch (exception) {\n throw new Error(`error registering definition: ${(exception as Error).message}`);\n }\n\n // Everything seems hunky-dory, register the subtree.\n Lookup.setSubtree(name, rootNodeDefinitions[0]);\n } else if (typeof value === \"object\" && !Array.isArray(value)) {\n // We will assume that any object passed in is a root node definition.\n\n try {\n // We should validate the subtree as we don't want invalid subtrees available via the lookup.\n const { succeeded, errorMessage } = validateJSONDefinition(value);\n\n // Did our validation fail without error?\n if (!succeeded) {\n throw new Error(errorMessage);\n }\n } catch (exception) {\n throw new Error(`error registering definition: ${(exception as Error).message}`);\n }\n\n // Everything seems hunky-dory, register the subtree.\n Lookup.setSubtree(name, value);\n } else {\n throw new Error(\"unexpected value, expected string mdsl definition, root node json definition or function\");\n }\n }\n\n /**\n * Unregisters the registered action/condition/guard/callback function or subtree with the given name.\n * @param name The name of the registered action/condition/guard/callback function or subtree to unregister.\n */\n static unregister(name: string): void {\n Lookup.remove(name);\n }\n\n /**\n * Unregister all registered action/condition/guard/callback functions and subtrees.\n */\n static unregisterAll(): void {\n Lookup.empty();\n }\n}\n"], + "mappings": "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", "names": ["Participant", "isNullOrUndefined", "Lotto", "createLotto", "State", "createLotto"] } diff --git a/dist/index.js b/dist/index.js index f7cd245..492a782 100644 --- a/dist/index.js +++ b/dist/index.js @@ -2183,30 +2183,30 @@ var BehaviourTree = class { ); } try { - this.rootNode = buildRootNode(json); + this._rootNode = buildRootNode(json); } catch (exception) { throw new Error(`error building tree: ${exception.message}`); } } - rootNode; + _rootNode; isRunning() { - return this.rootNode.getState() === "mistreevous.running" /* RUNNING */; + return this._rootNode.getState() === "mistreevous.running" /* RUNNING */; } getState() { - return this.rootNode.getState(); + return this._rootNode.getState(); } step() { - if (this.rootNode.getState() === "mistreevous.succeeded" /* SUCCEEDED */ || this.rootNode.getState() === "mistreevous.failed" /* FAILED */) { - this.rootNode.reset(); + if (this._rootNode.getState() === "mistreevous.succeeded" /* SUCCEEDED */ || this._rootNode.getState() === "mistreevous.failed" /* FAILED */) { + this._rootNode.reset(); } try { - this.rootNode.update(this.agent, this.options); + this._rootNode.update(this.agent, this.options); } catch (exception) { throw new Error(`error stepping tree: ${exception.message}`); } } reset() { - this.rootNode.reset(); + this._rootNode.reset(); } getFlattenedNodeDetails() { const flattenedTreeNodes = []; @@ -2227,7 +2227,7 @@ var BehaviourTree = class { node.getChildren().forEach((child) => processNode(child, node.getUid())); } }; - processNode(this.rootNode, null); + processNode(this._rootNode, null); return flattenedTreeNodes; } static register(name, value) { diff --git a/dist/index.js.map b/dist/index.js.map index 4fadc01..8798d49 100644 --- a/dist/index.js.map +++ b/dist/index.js.map @@ -1,7 +1,7 @@ { "version": 3, "sources": ["../node_modules/lotto-draw/dist/Participant.js", "../node_modules/lotto-draw/dist/Utilities.js", "../node_modules/lotto-draw/dist/Lotto.js", "../node_modules/lotto-draw/dist/createLotto.js", "../node_modules/lotto-draw/dist/index.js", "../src/index.ts", "../src/State.ts", "../src/BehaviourTreeDefinitionUtilities.ts", "../src/mdsl/MDSLUtilities.ts", "../src/mdsl/MDSLNodeArgumentParser.ts", "../src/mdsl/MDSLNodeAttributeParser.ts", "../src/mdsl/MDSLDefinitionParser.ts", "../src/BehaviourTreeDefinitionValidator.ts", "../src/Lookup.ts", "../src/attributes/guards/GuardUnsatisifedException.ts", "../src/attributes/guards/GuardPath.ts", "../src/nodes/Node.ts", "../src/nodes/composite/Composite.ts", "../src/nodes/composite/Parallel.ts", "../src/nodes/composite/Selector.ts", "../src/nodes/composite/Sequence.ts", "../src/nodes/composite/Lotto.ts", "../src/nodes/decorator/Decorator.ts", "../src/nodes/decorator/Fail.ts", "../src/nodes/decorator/Flip.ts", "../src/nodes/decorator/Repeat.ts", "../src/nodes/decorator/Retry.ts", "../src/nodes/decorator/Root.ts", "../src/nodes/decorator/Succeed.ts", "../src/nodes/leaf/Leaf.ts", "../src/nodes/leaf/Action.ts", "../src/nodes/leaf/Condition.ts", "../src/nodes/leaf/Wait.ts", "../src/attributes/Attribute.ts", "../src/attributes/guards/Guard.ts", "../src/attributes/guards/While.ts", "../src/attributes/guards/Until.ts", "../src/attributes/callbacks/Callback.ts", "../src/attributes/callbacks/Entry.ts", "../src/attributes/callbacks/Step.ts", "../src/attributes/callbacks/Exit.ts", "../src/BehaviourTreeBuilder.ts", "../src/BehaviourTree.ts"], - "sourcesContent": ["\"use strict\";\r\nObject.defineProperty(exports, \"__esModule\", { value: true });\r\nexports.Participant = void 0;\r\n/**\r\n * A participant that holds a number of tickets.\r\n */\r\nvar Participant = /** @class */ (function () {\r\n /**\r\n * Creates an instance of the Participant class.\r\n * @param participant The actual participant.\r\n * @param tickets The number of tickets held by the participant.\r\n */\r\n function Participant(participant, tickets) {\r\n if (tickets === void 0) { tickets = 1; }\r\n this._participant = participant;\r\n this._tickets = tickets;\r\n }\r\n Object.defineProperty(Participant.prototype, \"participant\", {\r\n /** Gets the actual participant. */\r\n get: function () {\r\n return this._participant;\r\n },\r\n enumerable: false,\r\n configurable: true\r\n });\r\n Object.defineProperty(Participant.prototype, \"tickets\", {\r\n /** Gets or sets the number of tickets held by the participant. */\r\n get: function () {\r\n return this._tickets;\r\n },\r\n set: function (value) {\r\n this._tickets = value;\r\n },\r\n enumerable: false,\r\n configurable: true\r\n });\r\n return Participant;\r\n}());\r\nexports.Participant = Participant;\r\n", "\"use strict\";\r\nObject.defineProperty(exports, \"__esModule\", { value: true });\r\nexports.isNaturalNumber = exports.isNullOrUndefined = void 0;\r\n/**\r\n * Gets whether the value provided is null or undefined.\r\n * @param value The value to check.\r\n * @returns Whether the value provided is null or undefined.\r\n */\r\nfunction isNullOrUndefined(value) {\r\n return value === null || value === undefined;\r\n}\r\nexports.isNullOrUndefined = isNullOrUndefined;\r\n/**\r\n * Gets whether the value provided is a natural number.\r\n * @param value The value to check.\r\n * @returns Whether the value provided is a natural number.\r\n */\r\nfunction isNaturalNumber(value) {\r\n return typeof value === \"number\" && value >= 1 && Math.floor(value) === value;\r\n}\r\nexports.isNaturalNumber = isNaturalNumber;\r\n", "\"use strict\";\r\nObject.defineProperty(exports, \"__esModule\", { value: true });\r\nexports.Lotto = void 0;\r\nvar Participant_1 = require(\"./Participant\");\r\nvar Utilities_1 = require(\"./Utilities\");\r\n/**\r\n * Represents a lotto consisting of a number of pickable ticket-holding participants.\r\n */\r\nvar Lotto = /** @class */ (function () {\r\n /**\r\n * Creates a new instance of Lotto.\r\n * @param customRandom The custom RNG to use in place of Math.random().\r\n */\r\n function Lotto(customRandom) {\r\n /** The array of participants that are holding tickets in the lotto. */\r\n this._participants = [];\r\n this._customRandom = customRandom;\r\n }\r\n /**\r\n * Adds a participant with the specified number of tickets, or adds to the participant ticket count if the participant already holds tickets.\r\n * @param participant The participant to add or to increase the ticket count for if they already hold tickets.\r\n * @param tickets The number of tickets, defaults to 1.\r\n * @returns The Lotto instance.\r\n */\r\n Lotto.prototype.add = function (participant, tickets) {\r\n if (tickets === void 0) { tickets = 1; }\r\n // Check that we have a valid ticket count.\r\n if (!(0, Utilities_1.isNaturalNumber)(tickets)) {\r\n throw new Error(\"tickets value must be a natural number\");\r\n }\r\n // Check whether this participant has already been added.\r\n var existingParticipant = this._participants.find(function (part) { return part.participant === participant; });\r\n if (existingParticipant) {\r\n // The participant has already been added to the lotto so just add to their ticket count.\r\n existingParticipant.tickets += tickets;\r\n }\r\n else {\r\n // The participant is not part of the lotto so we should add them.\r\n this._participants.push(new Participant_1.Participant(participant, tickets));\r\n }\r\n return this;\r\n };\r\n /**\r\n * Removes the specified number of tickets for the given participant from the draw, or all tickets if a ticket number is not defined.\r\n * @param participant The participant to remove tickets for.\r\n * @param tickets The number of tickets to remove, or undefined if all tickets are to be removed.\r\n * @returns The Lotto instance.\r\n */\r\n Lotto.prototype.remove = function (participant, tickets) {\r\n // Attempt to get the existing participant.\r\n var existingParticipant = this._participants.find(function (part) { return part.participant === participant; });\r\n // There is nothing to do if the specified participant isn't even part of the lotto.\r\n if (!existingParticipant) {\r\n return this;\r\n }\r\n // Check whether a tickets value was given.\r\n if (tickets !== undefined) {\r\n // Check that we have a valid ticket count.\r\n if (!(0, Utilities_1.isNaturalNumber)(tickets)) {\r\n throw new Error(\"tickets value must be a natural number\");\r\n }\r\n existingParticipant.tickets -= tickets;\r\n // If the participant no longer holds any tickets then they should be removed.\r\n if (existingParticipant.tickets < 1) {\r\n this._participants = this._participants.filter(function (part) { return part !== existingParticipant; });\r\n }\r\n }\r\n else {\r\n // We are removing all tickets for the participant so just remove them from the lotto.\r\n this._participants = this._participants.filter(function (part) { return part !== existingParticipant; });\r\n }\r\n return this;\r\n };\r\n /**\r\n * Draw a winning ticket and return the participant that holds the ticket.\r\n * @param options The draw options.\r\n * @returns The participant that holds the winning ticket.\r\n */\r\n Lotto.prototype.draw = function (options) {\r\n if (options === void 0) { options = {}; }\r\n // If we have no participants then just return null.\r\n if (this._participants.length === 0) {\r\n return null;\r\n }\r\n var redrawable = (0, Utilities_1.isNullOrUndefined)(options.redrawable) ? true : options.redrawable;\r\n var pickable = [];\r\n this._participants.forEach(function (_a) {\r\n var participant = _a.participant, tickets = _a.tickets;\r\n for (var ticketCount = 0; ticketCount < tickets; ticketCount++) {\r\n pickable.push(participant);\r\n }\r\n });\r\n var random;\r\n // We need a random floating-point number between 0 (inclusive) and 1 to scale up to pick our winner.\r\n // If a custom random function exists then we should use that or fall back to Math.random().\r\n if (this._customRandom) {\r\n // Call our custom random function to get a random floating-point number.\r\n random = this._customRandom();\r\n // Verify that the result of calling our custom random function is a number between 0 (inclusive) and 1.\r\n if (typeof random !== \"number\" || random < 0 || random >= 1) {\r\n throw new Error(\"the 'random' function provided did not return a number between 0 (inclusive) and 1\");\r\n }\r\n }\r\n else {\r\n // No custom random function was defined so just use good ol' Math.random().\r\n random = Math.random();\r\n }\r\n // Pick a winning participant.\r\n var winner = pickable[Math.floor(random * pickable.length)];\r\n // If the ticket isn't redrawable then we should remove a ticket from the winning participants ticket count.\r\n if (!redrawable) {\r\n this.remove(winner, 1);\r\n }\r\n // Return the winning participant.\r\n return winner;\r\n };\r\n /**\r\n * Draws multiple winning tickets and return an array of the participants that hold the winning tickets.\r\n * @param tickets The number of winning tickets to draw.\r\n * @param options The draw multiple options.\r\n * @returns An array of the participants that hold the winning tickets.\r\n */\r\n Lotto.prototype.drawMultiple = function (tickets, options) {\r\n if (options === void 0) { options = {}; }\r\n var uniqueResults = (0, Utilities_1.isNullOrUndefined)(options.unique) ? false : options.unique;\r\n // Handle cases where the user has asked for zero tickets (no idea why they would do this be we should trust them).\r\n if (tickets === 0) {\r\n return [];\r\n }\r\n // Now that we know out tickets value is not zero we should check that it is a valid natural number.\r\n if (!(0, Utilities_1.isNaturalNumber)(tickets)) {\r\n throw new Error(\"tickets value must be a natural number\");\r\n }\r\n var result = [];\r\n // Keep drawing tickets until we either reach the number of required tickets or we simply run out of tickets to draw.\r\n // We can run out of tickets to draw if 'options.redrawable' is explicity 'false' or we just had no participants when 'drawMultiple' was called.\r\n while (result.length < tickets && this._participants.length > 0) {\r\n result.push(this.draw(options));\r\n }\r\n // If the 'unique' draw option is set then we need to remove duplicates from the result list.\r\n if (uniqueResults) {\r\n // Create an array to store our unique results.\r\n var unique = [];\r\n // Iterate over all of our participants (with potential duplicates) and populate our array of unique values.\r\n for (var _i = 0, result_1 = result; _i < result_1.length; _i++) {\r\n var participant = result_1[_i];\r\n if (unique.indexOf(participant) === -1) {\r\n unique.push(participant);\r\n }\r\n }\r\n result = unique;\r\n }\r\n return result;\r\n };\r\n return Lotto;\r\n}());\r\nexports.Lotto = Lotto;\r\n", "\"use strict\";\r\nObject.defineProperty(exports, \"__esModule\", { value: true });\r\nexports.createLotto = void 0;\r\nvar Lotto_1 = require(\"./Lotto\");\r\n/**\r\n * A function that creates and returns a Lotto instance.\r\n * @param participantsOrOptions An array of initial participants or options relating to the creation of a Lotto instance.\r\n * @returns A new Lotto instance.\r\n */\r\nfunction createLotto(participantsOrOptions) {\r\n // If no initial participants or lotto options were provided as an argument then we can just return a new lotto instance now.\r\n if (!participantsOrOptions) {\r\n return new Lotto_1.Lotto();\r\n }\r\n // Check whether we were provided with an array of initial participants or a lotto options object.\r\n if (Array.isArray(participantsOrOptions)) {\r\n // We are dealing with a pre-defined array of participants.\r\n var participants = participantsOrOptions;\r\n var lotto_1 = new Lotto_1.Lotto();\r\n // If the lotto participants have been defined upfront then we will need to add them all to our lotto instance now.\r\n participants.forEach(function (_a) {\r\n var participant = _a[0], tokens = _a[1];\r\n return lotto_1.add(participant, tokens);\r\n });\r\n // Return the Lotto instance.\r\n return lotto_1;\r\n }\r\n else {\r\n // We are dealing with some lotto options.\r\n var random = participantsOrOptions.random, participants = participantsOrOptions.participants;\r\n // Create a Lotto instance passing the custom RNG function to use in place of Math.random() (which could be undefined).\r\n var lotto_2 = new Lotto_1.Lotto(random);\r\n // If the lotto participants have been defined upfront as part of the options then we will need to add them all to our lotto instance now.\r\n if (participants) {\r\n participants.forEach(function (_a) {\r\n var participant = _a[0], tokens = _a[1];\r\n return lotto_2.add(participant, tokens);\r\n });\r\n }\r\n // Return the Lotto instance.\r\n return lotto_2;\r\n }\r\n}\r\nexports.createLotto = createLotto;\r\n", "\"use strict\";\r\nObject.defineProperty(exports, \"__esModule\", { value: true });\r\nvar createLotto_1 = require(\"./createLotto\");\r\nexports.default = createLotto_1.createLotto;\r\n", "import State from \"./State\";\nimport { validateDefinition } from \"./BehaviourTreeDefinitionValidator\";\nimport { convertMDSLToJSON } from \"./mdsl/MDSLDefinitionParser\";\nimport { BehaviourTree, FlattenedTreeNode } from \"./BehaviourTree\";\nimport { BehaviourTreeOptions } from \"./BehaviourTreeOptions\";\n\nexport { BehaviourTree, State, convertMDSLToJSON, validateDefinition };\nexport type { FlattenedTreeNode, BehaviourTreeOptions };\n", "/**\n * Enumeration of node state types.\n */\nexport enum State {\n READY = \"mistreevous.ready\",\n RUNNING = \"mistreevous.running\",\n SUCCEEDED = \"mistreevous.succeeded\",\n FAILED = \"mistreevous.failed\"\n}\n\nexport { State as default };\n\nexport type CompleteState = State.SUCCEEDED | State.FAILED;\nexport type AnyState = State.READY | State.RUNNING | CompleteState;\n", "import {\n NodeDefinition,\n RootNodeDefinition,\n DecoratorNodeDefinition,\n CompositeNodeDefinition,\n AnyNodeDefinition,\n BranchNodeDefinition\n} from \"./BehaviourTreeDefinition\";\n\n/**\n * A type guard function that returns true if the specified node satisfies the RootNodeDefinition type.\n * @param node The node.\n * @returns A value of true if the specified node satisfies the RootNodeDefinition type.\n */\nexport function isRootNode(node: NodeDefinition): node is RootNodeDefinition {\n return node.type === \"root\";\n}\n\n/**\n * A type guard function that returns true if the specified node satisfies the BranchNodeDefinition type.\n * @param node The node.\n * @returns A value of true if the specified node satisfies the BranchNodeDefinition type.\n */\nexport function isBranchNode(node: NodeDefinition): node is BranchNodeDefinition {\n return node.type === \"branch\";\n}\n\n/**\n * A type guard function that returns true if the specified node satisfies the NodeDefinition type.\n * @param node The node.\n * @returns A value of true if the specified node satisfies the NodeDefinition type.\n */\nexport function isLeafNode(node: NodeDefinition): node is NodeDefinition {\n return [\"branch\", \"action\", \"condition\", \"wait\"].includes(node.type);\n}\n\n/**\n * A type guard function that returns true if the specified node satisfies the DecoratorNodeDefinition type.\n * @param node The node.\n * @returns A value of true if the specified node satisfies the DecoratorNodeDefinition type.\n */\nexport function isDecoratorNode(node: NodeDefinition): node is DecoratorNodeDefinition {\n return [\"root\", \"repeat\", \"retry\", \"flip\", \"succeed\", \"fail\"].includes(node.type);\n}\n\n/**\n * A type guard function that returns true if the specified node satisfies the CompositeNodeDefinition type.\n * @param node The node.\n * @returns A value of true if the specified node satisfies the CompositeNodeDefinition type.\n */\nexport function isCompositeNode(node: NodeDefinition): node is CompositeNodeDefinition {\n return [\"sequence\", \"selector\", \"lotto\", \"parallel\"].includes(node.type);\n}\n\n/**\n * Flatten a node definition into an array of all of its nested node definitions.\n * @param nodeDefinition The node definition to flatten.\n * @returns An array of all of nested node definitions.\n */\nexport function flattenDefinition(nodeDefinition: AnyNodeDefinition): AnyNodeDefinition[] {\n const nodes: AnyNodeDefinition[] = [];\n\n const processNode = (currentNodeDefinition: AnyNodeDefinition) => {\n nodes.push(currentNodeDefinition);\n\n if (isCompositeNode(currentNodeDefinition)) {\n currentNodeDefinition.children.forEach(processNode);\n } else if (isDecoratorNode(currentNodeDefinition)) {\n processNode(currentNodeDefinition.child);\n }\n };\n\n processNode(nodeDefinition);\n\n return nodes;\n}\n\n/**\n * Determines whether the passed value is an integer.\n * @param value The value to check.\n * @returns Whether the passed value is an integer.\n */\nexport function isInteger(value: unknown): boolean {\n return typeof value === \"number\" && Math.floor(value) === value;\n}\n\n/**\n * Determines whether the passed value is null or undefined.\n * @param value The value to check.\n * @returns Whether the passed value is null or undefined.\n */\nexport function isNullOrUndefined(value: unknown): boolean {\n return typeof value === \"undefined\" || value === null;\n}\n", "/**\n * A type defining an object that holds a reference to substitued string literals parsed from the definition.\n */\nexport type StringLiteralPlaceholders = { [key: string]: string };\n\n/**\n * Pop the next raw token from the specified array of tokens and throw an error if it wasn't the expected one.\n * @param tokens The array of tokens.\n * @param expected An optional string or array or items, one of which must match the next popped token.\n * @returns The popped token.\n */\nexport function popAndCheck(tokens: string[], expected?: string | string[]): string {\n // Get and remove the next token.\n const popped = tokens.shift();\n\n // We were expecting another token but there aren't any.\n if (popped === undefined) {\n throw new Error(\"unexpected end of definition\");\n }\n\n // Do we have an expected token/tokens array?\n if (expected != undefined) {\n // Get an array of expected values, if the popped token matches any then we are all good.\n const expectedValues = typeof expected === \"string\" ? [expected] : expected;\n\n // Check whether the popped token matches at least one of our expected items.\n var tokenMatchesExpectation = expectedValues.some((item) => popped.toUpperCase() === item.toUpperCase());\n\n // Throw an error if the popped token didn't match any of our expected items.\n if (!tokenMatchesExpectation) {\n const expectationString = expectedValues.map((item) => \"'\" + item + \"'\").join(\" or \");\n throw new Error(\"unexpected token found. Expected \" + expectationString + \" but got '\" + popped + \"'\");\n }\n }\n\n // Return the popped token.\n return popped;\n}\n\n/**\n * Swaps out any node/attribute argument string literals with placeholders.\n * @param definition The definition.\n * @returns An object containing a mapping of placeholders to original string values as well as the processed definition string.\n */\nexport function substituteStringLiterals(definition: string): {\n placeholders: StringLiteralPlaceholders;\n processedDefinition: string;\n} {\n // Create an object to hold the mapping of placeholders to original string values.\n const placeholders: StringLiteralPlaceholders = {};\n\n // Replace any string literals wrapped with double quotes in our definition with placeholders to be processed later.\n const processedDefinition = definition.replace(/\\\"(\\\\.|[^\"\\\\])*\\\"/g, (match) => {\n var strippedMatch = match.substring(1, match.length - 1);\n var placeholder = Object.keys(placeholders).find((key) => placeholders[key] === strippedMatch);\n\n // If we have no existing string literal match then create a new placeholder.\n if (!placeholder) {\n placeholder = `@@${Object.keys(placeholders).length}@@`;\n placeholders[placeholder] = strippedMatch;\n }\n\n return placeholder;\n });\n\n return { placeholders, processedDefinition };\n}\n\n/**\n * Parse the tree definition into an array of raw tokens.\n * @param definition The definition.\n * @returns An array of tokens parsed from the definition.\n */\nexport function parseTokensFromDefinition(definition: string): string[] {\n // Add some space around various important characters so that they can be plucked out easier as individual tokens.\n definition = definition.replace(/\\(/g, \" ( \");\n definition = definition.replace(/\\)/g, \" ) \");\n definition = definition.replace(/\\{/g, \" { \");\n definition = definition.replace(/\\}/g, \" } \");\n definition = definition.replace(/\\]/g, \" ] \");\n definition = definition.replace(/\\[/g, \" [ \");\n definition = definition.replace(/\\,/g, \" , \");\n\n // Split the definition into raw token form and return it.\n return definition.replace(/\\s+/g, \" \").trim().split(\" \");\n}\n", "import { StringLiteralPlaceholders, popAndCheck } from \"./MDSLUtilities\";\n\n/**\n * A type representing any node function argument.\n */\ntype Argument = {\n /**\n * The argument value.\n */\n value: T;\n /**\n * The argument type, used for validation.\n */\n type: string;\n};\n\ntype NullArgument = Argument & {\n type: \"null\";\n};\n\ntype BooleanArgument = Argument & {\n type: \"boolean\";\n};\n\ntype NumberArgument = Argument & {\n type: \"number\";\n /**\n * A flag defining whether the number argument value is a valid integer. (used for validation)\n */\n isInteger: boolean;\n};\n\ntype StringPlaceholderArgument = Argument & {\n type: \"string\";\n};\n\ntype IdentifierArgument = Argument & {\n type: \"identifier\";\n};\n\n/**\n * A type representing a reference to any node function argument.\n */\ntype AnyArgument = NullArgument | BooleanArgument | NumberArgument | StringPlaceholderArgument | IdentifierArgument;\n\n/**\n * Parse an array of argument definitions from the specified tokens array.\n * @param tokens The array tokens to parse the argument definitions from.\n * @param stringArgumentPlaceholders The mapping of string literal node argument placeholders to original values.\n * @param argumentValidator The argument validator function.\n * @param validationFailedMessage The exception message to throw if argument validation fails.\n * @returns An array of argument definitions parsed from the specified tokens array.\n */\nexport function parseArgumentTokens(\n tokens: string[],\n stringArgumentPlaceholders: StringLiteralPlaceholders\n): AnyArgument[] {\n const argumentList: AnyArgument[] = [];\n\n // If the next token is not a '[' or '(' then we have no arguments to parse.\n if (![\"[\", \"(\"].includes(tokens[0])) {\n return argumentList;\n }\n\n // Any lists of arguments will always be wrapped in '[]' for node arguments or '()' for attribute arguments.\n // We are looking for a '[' or '(' opener that wraps the argument tokens and the relevant closer.\n const closingToken = popAndCheck(tokens, [\"[\", \"(\"]) === \"[\" ? \"]\" : \")\";\n\n const argumentListTokens: string[] = [];\n\n // Grab all tokens between the '[' and ']' or '(' and ')'.\n while (tokens.length && tokens[0] !== closingToken) {\n // The next token is part of our arguments list.\n argumentListTokens.push(tokens.shift()!);\n }\n\n // Validate the order of the argument tokens. Each token must either be a ',' or a single argument that satisfies the validator.\n argumentListTokens.forEach((token, index) => {\n // Get whether this token should be an actual argument.\n const shouldBeArgumentToken = !(index & 1);\n\n // If the current token should be an actual argument then validate it, otherwise it should be a ',' token.\n if (shouldBeArgumentToken) {\n // Get the argument definition.\n const argumentDefinition = getArgumentDefinition(token, stringArgumentPlaceholders);\n\n // This is a valid argument!\n argumentList.push(argumentDefinition);\n } else {\n // The current token should be a ',' token.\n if (token !== \",\") {\n throw new Error(`invalid argument list, expected ',' or ']' but got '${token}'`);\n }\n }\n });\n\n // The arguments list should terminate with a ']' or ')' token, depending on the opener.\n popAndCheck(tokens, closingToken);\n\n // Return the arguments.\n return argumentList;\n}\n\n/**\n * Gets an argument value definition.\n * @param token The argument token.\n * @param stringArgumentPlaceholders The mapping of string literal node argument placeholders to original values.\n * @returns An argument value definition.\n */\nfunction getArgumentDefinition(token: string, stringArgumentPlaceholders: StringLiteralPlaceholders): AnyArgument {\n // Check whether the token represents a null value.\n if (token === \"null\") {\n return {\n value: null,\n type: \"null\"\n } as NullArgument;\n }\n\n // Check whether the token represents a boolean value.\n if (token === \"true\" || token === \"false\") {\n return {\n value: token === \"true\",\n type: \"boolean\"\n } as BooleanArgument;\n }\n\n // Check whether the token represents a number value.\n // TODO: Relies on broken isNaN - see MDN.\n // if (!Number.isNaN(token)) {\n if (!isNaN(token as any)) {\n return {\n value: parseFloat(token),\n isInteger: parseFloat(token) === parseInt(token, 10),\n type: \"number\"\n } as NumberArgument;\n }\n\n // Check whether the token is a placeholder (e.g. @@0@@) representing a string literal.\n if (token.match(/^@@\\d+@@$/g)) {\n return {\n value: stringArgumentPlaceholders[token].replace('\\\\\"', '\"'),\n type: \"string\"\n } as StringPlaceholderArgument;\n }\n\n // The only remaining option is that the argument value is an identifier.\n return {\n value: token,\n type: \"identifier\"\n } as IdentifierArgument;\n}\n", "import { NodeAttributeDefinition } from \"../BehaviourTreeDefinition\";\nimport { parseArgumentTokens } from \"./MDSLNodeArgumentParser\";\nimport { StringLiteralPlaceholders } from \"./MDSLUtilities\";\n\n/**\n * A type defining the attribute definitions of a node.\n */\ntype NodeAttributes = {\n while?: NodeAttributeDefinition;\n until?: NodeAttributeDefinition;\n entry?: NodeAttributeDefinition;\n exit?: NodeAttributeDefinition;\n step?: NodeAttributeDefinition;\n};\n\n/**\n * Parse any node attribute definitions from the specified tokens array.\n * @param tokens The array of remaining tokens.\n * @param stringArgumentPlaceholders The mapping of string literal node argument placeholders to original values.\n * @returns An object of attribute definitions defined by any directly following tokens.\n */\nexport function parseAttributeTokens(\n tokens: string[],\n stringArgumentPlaceholders: StringLiteralPlaceholders\n): NodeAttributes {\n const nodeAttributeNames: (keyof NodeAttributes)[] = [\"while\", \"until\", \"entry\", \"exit\", \"step\"];\n\n // Create an object to hold any attributes found.\n const attributes: NodeAttributes = {};\n\n // Try to get the name of the attribute for the next token.\n let nextAttributeName = tokens[0]?.toLowerCase() as keyof NodeAttributes;\n\n // Pull attribute tokens as well as their arguments off of the tokens stack until we have no more.\n while (nodeAttributeNames.includes(nextAttributeName)) {\n // Check to make sure that we have not already created an attribute definition of this type.\n if (attributes[nextAttributeName]) {\n throw new Error(`duplicate attribute '${tokens[0].toUpperCase()}' found for node`);\n }\n\n // Remove the attribute name token from the array of tokens.\n tokens.shift();\n\n // Grab the attribute arguments, assuming the first to be an identifier.\n const [attributeCallIdentifier, ...attributeArguments] = parseArgumentTokens(\n tokens,\n stringArgumentPlaceholders\n );\n\n // The first attribute argument has to be an identifer, this will reference an agent function.\n if (attributeCallIdentifier?.type !== \"identifier\") {\n throw new Error(\"expected agent function name identifier argument for attribute\");\n }\n\n // Any attribute arguments (other than the expected call identifier) must have a type of string, number, boolean or null.\n attributeArguments\n .filter((arg) => arg.type === \"identifier\")\n .forEach((arg) => {\n throw new Error(\n `invalid attribute argument value '${arg.value}', must be string, number, boolean or null`\n );\n });\n\n // Create the attribute definition and add it to the object of attribute definitions found.\n attributes[nextAttributeName] = {\n call: attributeCallIdentifier.value,\n args: attributeArguments.map(({ value }) => value)\n };\n\n // Try to get the next attribute name token, as there could be multiple.\n nextAttributeName = tokens[0]?.toLowerCase() as keyof NodeAttributes;\n }\n\n return attributes;\n}\n", "import {\n ActionNodeDefinition,\n AnyChildNodeDefinition,\n AnyNodeDefinition,\n BranchNodeDefinition,\n ConditionNodeDefinition,\n FailNodeDefinition,\n FlipNodeDefinition,\n LottoNodeDefinition,\n ParallelNodeDefinition,\n RepeatNodeDefinition,\n RetryNodeDefinition,\n RootNodeDefinition,\n SelectorNodeDefinition,\n SequenceNodeDefinition,\n SucceedNodeDefinition,\n WaitNodeDefinition\n} from \"../BehaviourTreeDefinition\";\nimport {\n isCompositeNode,\n isDecoratorNode,\n isLeafNode,\n isNullOrUndefined,\n isRootNode\n} from \"../BehaviourTreeDefinitionUtilities\";\nimport { parseArgumentTokens } from \"./MDSLNodeArgumentParser\";\nimport { parseAttributeTokens } from \"./MDSLNodeAttributeParser\";\nimport {\n StringLiteralPlaceholders,\n parseTokensFromDefinition,\n popAndCheck,\n substituteStringLiterals\n} from \"./MDSLUtilities\";\n\n/**\n * Convert the MDSL tree definition string into an equivalent JSON definition.\n * @param definition The tree definition string as MDSL.\n * @returns The root node JSON definitions.\n */\nexport function convertMDSLToJSON(definition: string): RootNodeDefinition[] {\n // Swap out any node/attribute argument string literals with a placeholder and get a mapping of placeholders to original values as well as the processed definition.\n const { placeholders, processedDefinition } = substituteStringLiterals(definition);\n\n // Parse our definition definition string into an array of raw tokens.\n const tokens = parseTokensFromDefinition(processedDefinition);\n\n return convertTokensToJSONDefinition(tokens, placeholders);\n}\n\n/**\n * Converts the specified tree definition tokens into a JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The root node JSON definitions.\n */\nfunction convertTokensToJSONDefinition(\n tokens: string[],\n stringLiteralPlaceholders: StringLiteralPlaceholders\n): RootNodeDefinition[] {\n // There must be at least 3 tokens for the tree definition to be valid. 'ROOT', '{' and '}'.\n if (tokens.length < 3) {\n throw new Error(\"invalid token count\");\n }\n\n // We should have a matching number of '{' and '}' tokens. If not, then there are scopes that have not been properly closed.\n if (tokens.filter((token) => token === \"{\").length !== tokens.filter((token) => token === \"}\").length) {\n throw new Error(\"scope character mismatch\");\n }\n\n // Create an array of tree stack arrays where root nodes will always be at the botton and the current composite/decorator node at the top.\n // There should be an element in this array for every root node defined and every element should be an array with a root note as the first element.\n // E.g. A definition with two root nodes defined:\n // [\n // [root, lotto, sequence],\n // [root, selector]\n // ]\n const treeStacks: [Partial, ...Partial[]][] = [];\n\n // Create an array of all root node definitions that we create.\n const rootNodes: Partial[] = [];\n\n // A helper function used to push node definitions onto the tree stack.\n const pushNode = (node: AnyNodeDefinition) => {\n // If the node is a root node then we need to create a new tree stack array with the root node at the root.\n if (isRootNode(node)) {\n // We need to double-check that this root node is not the child of another node.\n // We can do this by checking whether the top tree stack is not empty (contains an existing node)\n if (treeStacks[treeStacks.length - 1]?.length) {\n throw new Error(\"a root node cannot be the child of another node\");\n }\n\n // Add the root node definition to our array of all parsed root node definitions.\n rootNodes.push(node);\n\n // Add the root node definition to the root of a new tree stack.\n treeStacks.push([node]);\n\n return;\n }\n\n // All non-root nodes should be pushed after their root nodes so handle cases\n // where we may not have any tree stacks or our top-most tree stack is empty.\n if (!treeStacks.length || !treeStacks[treeStacks.length - 1].length) {\n throw new Error(\"expected root node at base of definition\");\n }\n\n // Get the current tree stack that we are populating.\n const topTreeStack = treeStacks[treeStacks.length - 1];\n\n // Get the top-most node in the current tree stack, this will be a composite/decorator node\n // for which we will populate its children array if composite or setting its child if a decorator.\n const topTreeStackTopNode = topTreeStack[topTreeStack.length - 1] as AnyNodeDefinition;\n\n // If the top-most node in the current root stack is a composite or decorator\n // node then the current node should be added as a child of the top-most node.\n if (isCompositeNode(topTreeStackTopNode)) {\n topTreeStackTopNode.children = topTreeStackTopNode.children || [];\n topTreeStackTopNode.children.push(node);\n } else if (isDecoratorNode(topTreeStackTopNode)) {\n // If the top node already has a child node set then throw an error as a decorator should only have a single child.\n if (topTreeStackTopNode.child) {\n throw new Error(\"a decorator node must only have a single child node\");\n }\n\n topTreeStackTopNode.child = node;\n }\n\n // If the node we are adding is also a composite or decorator node, then we should push it\n // onto the current tree stack, as subsequent nodes will be added as its child/children.\n if (!isLeafNode(node)) {\n topTreeStack.push(node);\n }\n };\n\n // A helper function used to pop the top-most node definition off of the tree stack and return it.\n const popNode = (): AnyNodeDefinition | null => {\n let poppedNode: AnyNodeDefinition | null = null;\n\n // Get the current tree stack that we are populating.\n const topTreeStack = treeStacks[treeStacks.length - 1];\n\n // Pop the top-most node in the current tree stack if there is one.\n if (topTreeStack.length) {\n poppedNode = topTreeStack.pop() as AnyNodeDefinition;\n }\n\n // We don't want any empty tree stacks in our stack of tree stacks.\n if (!topTreeStack.length) {\n treeStacks.pop();\n }\n\n return poppedNode;\n };\n\n // We should keep processing the raw tokens until we run out of them.\n while (tokens.length) {\n // Grab the next token.\n const token = tokens.shift()!;\n\n // How we create the next node depends on the current raw token value.\n switch (token.toUpperCase()) {\n case \"ROOT\": {\n pushNode(createRootNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"SUCCEED\": {\n pushNode(createSucceedNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"FAIL\": {\n pushNode(createFailNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"FLIP\": {\n pushNode(createFlipNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"REPEAT\": {\n pushNode(createRepeatNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"RETRY\": {\n pushNode(createRetryNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"SEQUENCE\": {\n pushNode(createSequenceNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"SELECTOR\": {\n pushNode(createSelectorNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"PARALLEL\": {\n pushNode(createParallelNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"LOTTO\": {\n pushNode(createLottoNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"ACTION\": {\n pushNode(createActionNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"CONDITION\": {\n pushNode(createConditionNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"WAIT\": {\n pushNode(createWaitNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"BRANCH\": {\n pushNode(createBranchNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"}\": {\n // The '}' character closes the current scope and means that we have to pop a node off of the current stack.\n const poppedNode = popNode();\n\n // Now that we have a node definition we can carry out any validation that may require the node to be fully populated.\n if (poppedNode) {\n validatePoppedNode(poppedNode);\n }\n\n break;\n }\n\n default: {\n throw new Error(`unexpected token: ${token}`);\n }\n }\n }\n\n return rootNodes as RootNodeDefinition[];\n}\n\n/**\n * Creates a root node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The root node JSON definition.\n */\nfunction createRootNode(tokens: string[], stringLiteralPlaceholders: StringLiteralPlaceholders): RootNodeDefinition {\n // Create the root node definition.\n let node = {\n type: \"root\",\n id: undefined\n } as RootNodeDefinition;\n\n // Parse any node arguments, we should only have one if any which will be an identifier argument for the root identifier.\n const nodeArguments = parseArgumentTokens(tokens, stringLiteralPlaceholders);\n\n // Check whether any node arguments were defined.\n if (nodeArguments.length) {\n // We should only have one argument, if any, which will be an identifier argument for the root identifier.\n if (nodeArguments.length === 1 && nodeArguments[0].type === \"identifier\") {\n // The root node identifier will be the first and only node argument value.\n node.id = nodeArguments[0].value as string;\n } else {\n throw new Error(\"expected single root name argument\");\n }\n }\n\n // Grab any node attribute definitions and spread them into the node definition.\n node = { ...node, ...parseAttributeTokens(tokens, stringLiteralPlaceholders) };\n\n // This is a decorator node, so we expect an opening '{'.\n popAndCheck(tokens, \"{\");\n\n // Return the root node definition.\n return node;\n}\n\n/**\n * Creates a succeed node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The succeed node JSON definition.\n */\nfunction createSucceedNode(\n tokens: string[],\n stringLiteralPlaceholders: StringLiteralPlaceholders\n): SucceedNodeDefinition {\n const node = {\n type: \"succeed\",\n ...parseAttributeTokens(tokens, stringLiteralPlaceholders)\n } as SucceedNodeDefinition;\n\n // This is a decorator node, so we expect an opening '{'.\n popAndCheck(tokens, \"{\");\n\n // Return the succeed node definition.\n return node;\n}\n\n/**\n * Creates a fail node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The fail node JSON definition.\n */\nfunction createFailNode(tokens: string[], stringLiteralPlaceholders: StringLiteralPlaceholders): FailNodeDefinition {\n const node = {\n type: \"fail\",\n ...parseAttributeTokens(tokens, stringLiteralPlaceholders)\n } as FailNodeDefinition;\n\n // This is a decorator node, so we expect an opening '{'.\n popAndCheck(tokens, \"{\");\n\n // Return the fail node definition.\n return node;\n}\n\n/**\n * Creates a flip node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The flip node JSON definition.\n */\nfunction createFlipNode(tokens: string[], stringLiteralPlaceholders: StringLiteralPlaceholders): FlipNodeDefinition {\n const node = {\n type: \"flip\",\n ...parseAttributeTokens(tokens, stringLiteralPlaceholders)\n } as FlipNodeDefinition;\n\n // This is a decorator node, so we expect an opening '{'.\n popAndCheck(tokens, \"{\");\n\n // Return the flip node definition.\n return node;\n}\n\n/**\n * Creates a repeat node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The repeat node JSON definition.\n */\nfunction createRepeatNode(\n tokens: string[],\n stringLiteralPlaceholders: StringLiteralPlaceholders\n): RepeatNodeDefinition {\n let node = { type: \"repeat\" } as RepeatNodeDefinition;\n\n // Get the node arguments.\n const nodeArguments = parseArgumentTokens(tokens, stringLiteralPlaceholders);\n\n // The arguments of a repeat node are optional. We may have:\n // - No node arguments, in which case the repeat note will iterate indefinitely.\n // - One node argument which will be the explicit number of iterations to make.\n // - Two node arguments which define the min and max iteration bounds from which a random iteration count will be picked.\n if (nodeArguments.length) {\n // All repeat node arguments MUST be of type number and must be integer.\n nodeArguments\n .filter((arg) => arg.type !== \"number\" || !arg.isInteger)\n .forEach(() => {\n throw new Error(`repeat node iteration counts must be integer values`);\n });\n\n // We should have got one or two iteration counts.\n if (nodeArguments.length === 1) {\n // A static iteration count was defined.\n node.iterations = nodeArguments[0].value as number;\n\n // A repeat node must have a positive number of iterations if defined.\n if (node.iterations < 0) {\n throw new Error(\"a repeat node must have a positive number of iterations if defined\");\n }\n } else if (nodeArguments.length === 2) {\n // A minimum and maximum iteration count was defined.\n node.iterations = [nodeArguments[0].value as number, nodeArguments[1].value as number];\n\n // A repeat node must have a positive min and max iteration count if they are defined.\n if (node.iterations[0] < 0 || node.iterations[1] < 0) {\n throw new Error(\"a repeat node must have a positive minimum and maximum iteration count if defined\");\n }\n\n // A repeat node must not have an minimum iteration count that exceeds the maximum iteration count.\n if (node.iterations[0] > node.iterations[1]) {\n throw new Error(\n \"a repeat node must not have a minimum iteration count that exceeds the maximum iteration count\"\n );\n }\n } else {\n // An incorrect number of iteration counts was defined.\n throw new Error(\"invalid number of repeat node iteration count arguments defined\");\n }\n }\n\n // Grab any node attribute definitions and spread them into the node definition.\n node = { ...node, ...parseAttributeTokens(tokens, stringLiteralPlaceholders) };\n\n // This is a decorator node, so we expect an opening '{'.\n popAndCheck(tokens, \"{\");\n\n // Return the repeat node definition.\n return node;\n}\n\n/**\n * Creates a retry node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The retry node JSON definition.\n */\nfunction createRetryNode(tokens: string[], stringLiteralPlaceholders: StringLiteralPlaceholders): RetryNodeDefinition {\n let node = { type: \"retry\" } as RetryNodeDefinition;\n\n // Get the node arguments.\n const nodeArguments = parseArgumentTokens(tokens, stringLiteralPlaceholders);\n\n // The arguments of a retry node are optional. We may have:\n // - No node arguments, in which case the retry note will attempt indefinitely.\n // - One node argument which will be the explicit number of attempts to make.\n // - Two node arguments which define the min and max attempt bounds from which a random attempt count will be picked.\n if (nodeArguments.length) {\n // All retry node arguments MUST be of type number and must be integer.\n nodeArguments\n .filter((arg) => arg.type !== \"number\" || !arg.isInteger)\n .forEach(() => {\n throw new Error(`retry node attempt counts must be integer values`);\n });\n\n // We should have got one or two attempt counts.\n if (nodeArguments.length === 1) {\n // A static attempt count was defined.\n node.attempts = nodeArguments[0].value as number;\n\n // A retry node must have a positive number of attempts if defined.\n if (node.attempts < 0) {\n throw new Error(\"a retry node must have a positive number of attempts if defined\");\n }\n } else if (nodeArguments.length === 2) {\n // A minimum and maximum attempt count was defined.\n node.attempts = [nodeArguments[0].value as number, nodeArguments[1].value as number];\n\n // A retry node must have a positive min and max attempts count if they are defined.\n if (node.attempts[0] < 0 || node.attempts[1] < 0) {\n throw new Error(\"a retry node must have a positive minimum and maximum attempt count if defined\");\n }\n\n // A retry node must not have a minimum attempt count that exceeds the maximum attempt count.\n if (node.attempts[0] > node.attempts[1]) {\n throw new Error(\n \"a retry node must not have a minimum attempt count that exceeds the maximum attempt count\"\n );\n }\n } else {\n // An incorrect number of attempt counts was defined.\n throw new Error(\"invalid number of retry node attempt count arguments defined\");\n }\n }\n\n // Grab any node attribute definitions and spread them into the node definition.\n node = { ...node, ...parseAttributeTokens(tokens, stringLiteralPlaceholders) };\n\n // This is a decorator node, so we expect an opening '{'.\n popAndCheck(tokens, \"{\");\n\n // Return the retry node definition.\n return node;\n}\n\n/**\n * Creates a sequence node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The sequence node JSON definition.\n */\nfunction createSequenceNode(\n tokens: string[],\n stringLiteralPlaceholders: StringLiteralPlaceholders\n): SequenceNodeDefinition {\n const node = {\n type: \"sequence\",\n ...parseAttributeTokens(tokens, stringLiteralPlaceholders)\n } as SequenceNodeDefinition;\n\n // This is a composite node, so we expect an opening '{'.\n popAndCheck(tokens, \"{\");\n\n // Return the sequence node definition.\n return node;\n}\n\n/**\n * Creates a selector node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The selector node JSON definition.\n */\nfunction createSelectorNode(\n tokens: string[],\n stringLiteralPlaceholders: StringLiteralPlaceholders\n): SelectorNodeDefinition {\n const node = {\n type: \"selector\",\n ...parseAttributeTokens(tokens, stringLiteralPlaceholders)\n } as SelectorNodeDefinition;\n\n // This is a composite node, so we expect an opening '{'.\n popAndCheck(tokens, \"{\");\n\n // Return the selector node definition.\n return node;\n}\n\n/**\n * Creates a parallel node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The parallel node JSON definition.\n */\nfunction createParallelNode(\n tokens: string[],\n stringLiteralPlaceholders: StringLiteralPlaceholders\n): ParallelNodeDefinition {\n const node = {\n type: \"parallel\",\n ...parseAttributeTokens(tokens, stringLiteralPlaceholders)\n } as ParallelNodeDefinition;\n\n // This is a composite node, so we expect an opening '{'.\n popAndCheck(tokens, \"{\");\n\n // Return the parallel node definition.\n return node;\n}\n\n/**\n * Creates a lotto node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The lotto node JSON definition.\n */\nfunction createLottoNode(tokens: string[], stringLiteralPlaceholders: StringLiteralPlaceholders): LottoNodeDefinition {\n // If any node arguments have been defined then they must be our weights.\n const nodeArguments = parseArgumentTokens(tokens, stringLiteralPlaceholders);\n\n // All lotto node arguments MUST be of type number and must be positive integers.\n nodeArguments\n .filter((arg) => arg.type !== \"number\" || !arg.isInteger || arg.value < 0)\n .forEach(() => {\n throw new Error(`lotto node weight arguments must be positive integer values`);\n });\n\n const node = {\n type: \"lotto\",\n weights: nodeArguments.length ? nodeArguments.map(({ value }) => value) : undefined,\n ...parseAttributeTokens(tokens, stringLiteralPlaceholders)\n } as LottoNodeDefinition;\n\n // This is a composite node, so we expect an opening '{'.\n popAndCheck(tokens, \"{\");\n\n // Return the lotto node definition.\n return node;\n}\n\n/**\n * Creates an action node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The action node JSON definition.\n */\nfunction createActionNode(\n tokens: string[],\n stringLiteralPlaceholders: StringLiteralPlaceholders\n): ActionNodeDefinition {\n // Parse any node arguments, we should have at least one which will be an identifier argument for the action name\n // and agent function to invoke for the action, all other arguments are to be passed as arguments to that function.\n const [actionNameIdentifier, ...agentFunctionArgs] = parseArgumentTokens(tokens, stringLiteralPlaceholders);\n\n // Our first argument MUST be defined and be an identifier as we require an action name argument.\n if (actionNameIdentifier?.type !== \"identifier\") {\n throw new Error(\"expected action name identifier argument\");\n }\n\n // Only the first argument should have been an identifier, all agent function arguments must be string, number, boolean or null.\n agentFunctionArgs\n .filter((arg) => arg.type === \"identifier\")\n .forEach((arg) => {\n throw new Error(\n `invalid action node argument value '${arg.value}', must be string, number, boolean or null`\n );\n });\n\n // Return the action node definition.\n return {\n type: \"action\",\n call: actionNameIdentifier.value,\n args: agentFunctionArgs.map(({ value }) => value),\n ...parseAttributeTokens(tokens, stringLiteralPlaceholders)\n };\n}\n\n/**\n * Creates a condition node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The condition node JSON definition.\n */\nfunction createConditionNode(\n tokens: string[],\n stringLiteralPlaceholders: StringLiteralPlaceholders\n): ConditionNodeDefinition {\n // Parse any node arguments, we should have at least one which will be an identifier argument for the condition name\n // and agent function to invoke for the condition, all other arguments are to be passed as arguments to that function.\n const [conditionNameIdentifier, ...agentFunctionArgs] = parseArgumentTokens(tokens, stringLiteralPlaceholders);\n\n // Our first argument MUST be defined and be an identifier as we require a condition name argument.\n if (conditionNameIdentifier?.type !== \"identifier\") {\n throw new Error(\"expected condition name identifier argument\");\n }\n\n // Only the first argument should have been an identifier, all agent function arguments must be string, number, boolean or null.\n agentFunctionArgs\n .filter((arg) => arg.type === \"identifier\")\n .forEach((arg) => {\n throw new Error(\n `invalid condition node argument value '${arg.value}', must be string, number, boolean or null`\n );\n });\n\n // Return the condition node definition.\n return {\n type: \"condition\",\n call: conditionNameIdentifier.value,\n args: agentFunctionArgs.map(({ value }) => value),\n ...parseAttributeTokens(tokens, stringLiteralPlaceholders)\n };\n}\n\n/**\n * Creates a wait node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The wait node JSON definition.\n */\nfunction createWaitNode(tokens: string[], stringLiteralPlaceholders: StringLiteralPlaceholders): WaitNodeDefinition {\n let node = { type: \"wait\" } as WaitNodeDefinition;\n\n // Get the node arguments.\n const nodeArguments = parseArgumentTokens(tokens, stringLiteralPlaceholders);\n\n // The arguments of a wait node are optional. We may have:\n // - No node arguments, in which case the wait will be indefinite until it is aborted.\n // - One node argument which will be the explicit duration of the wait.\n // - Two node arguments which define the min and max duration bounds from which a random duration will be picked.\n if (nodeArguments.length) {\n // All wait node arguments MUST be of type number and must be integer.\n nodeArguments\n .filter((arg) => arg.type !== \"number\" || !arg.isInteger)\n .forEach(() => {\n throw new Error(`wait node durations must be integer values`);\n });\n\n // We may have:\n // - One node argument which will be the explicit duration of the wait.\n // - Two node arguments which define the min and max duration bounds from which a random duration will be picked.\n // - Too many arguments, which is not valid.\n if (nodeArguments.length === 1) {\n // An explicit duration was defined.\n node.duration = nodeArguments[0].value as number;\n\n // If an explict duration was defined then it must be a positive number.\n if (node.duration < 0) {\n throw new Error(\"a wait node must have a positive duration\");\n }\n } else if (nodeArguments.length === 2) {\n // Min and max duration bounds were defined from which a random duration will be picked.\n node.duration = [nodeArguments[0].value as number, nodeArguments[1].value as number];\n\n // A wait node must have a positive min and max duration.\n if (node.duration[0] < 0 || node.duration[1] < 0) {\n throw new Error(\"a wait node must have a positive minimum and maximum duration\");\n }\n\n // A wait node must not have a minimum duration that exceeds the maximum duration.\n if (node.duration[0] > node.duration[1]) {\n throw new Error(\"a wait node must not have a minimum duration that exceeds the maximum duration\");\n }\n } else if (nodeArguments.length > 2) {\n // An incorrect number of duration arguments were defined.\n throw new Error(\"invalid number of wait node duration arguments defined\");\n }\n }\n\n // Return the wait node definition.\n return { ...node, ...parseAttributeTokens(tokens, stringLiteralPlaceholders) };\n}\n\n/**\n * Creates a branch node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The branch node JSON definition.\n */\nfunction createBranchNode(\n tokens: string[],\n stringLiteralPlaceholders: StringLiteralPlaceholders\n): BranchNodeDefinition {\n // Parse any node arguments, we should have one which will be an identifier argument for the root ref.\n const nodeArguments = parseArgumentTokens(tokens, stringLiteralPlaceholders);\n\n // We should have only a single identifer argument for a branch node, which is the root ref.\n if (nodeArguments.length !== 1 || nodeArguments[0].type !== \"identifier\") {\n throw new Error(\"expected single branch name argument\");\n }\n\n // Return the branch node definition.\n return { type: \"branch\", ref: nodeArguments[0].value };\n}\n\n/**\n * Validate a fully-populated node definition that was popped off of the tree stack.\n * @param definition The popped node to validate.\n */\nfunction validatePoppedNode(definition: AnyNodeDefinition): void {\n // Decorators MUST have a child defined.\n if (isDecoratorNode(definition) && isNullOrUndefined(definition.child)) {\n throw new Error(`a ${definition.type} node must have a single child node defined`);\n }\n\n // Composites MUST have at least one child defined.\n if (isCompositeNode(definition) && !definition.children?.length) {\n throw new Error(`a ${definition.type} node must have at least a single child node defined`);\n }\n\n // We need to make sure that lotto nodes that have weights defined have a number of weights matching the number of child nodes.\n if (definition.type === \"lotto\") {\n // Check whether a 'weights' property has been defined, if it has we expect it to be an array of weights.\n if (typeof definition.weights !== \"undefined\") {\n // Check that the weights property is an array of positive integers with an element for each child node element.\n if (definition.weights.length !== definition.children.length) {\n throw new Error(\n \"expected a number of weight arguments matching the number of child nodes for lotto node\"\n );\n }\n }\n }\n}\n", "import { RootNodeDefinition } from \"./BehaviourTreeDefinition\";\nimport { flattenDefinition, isBranchNode, isInteger } from \"./BehaviourTreeDefinitionUtilities\";\nimport { convertMDSLToJSON } from \"./mdsl/MDSLDefinitionParser\";\n\n/**\n * An object representing the result of validating a tree definition.\n */\nexport type DefinitionValidationResult = {\n /**\n * A flag defining whether validation succeeded.\n */\n succeeded: boolean;\n /**\n * A string containing the error message if validation did not succeed.\n */\n errorMessage?: string;\n /**\n * The definition as json if the validation was successful, or undefined if validation did not succeed.\n */\n json?: RootNodeDefinition[];\n};\n\n/**\n * Validates the specified behaviour tree definition in the form of JSON or MDSL, not taking any globally registered subtrees into consideration.\n * @param definition The behaviour tree definition in the form of JSON or MDSL.\n * @returns An object representing the result of validating the given tree definition.\n */\nexport function validateDefinition(definition: any): DefinitionValidationResult {\n // The definition must be defined.\n if (definition === null || typeof definition === \"undefined\") {\n return createValidationFailureResult(\"definition is null or undefined\");\n }\n\n // We are expecting a definition in one of three different forms:\n // - A string which we will assume is MDSL and we will parse this to JSON before validation.\n // - An array which we will assume is an array of root node definitions with at least one being the primary root node (no 'id' property)\n // - An object which we will assume is the primary root node and should not have an 'id' property.\n if (typeof definition === \"string\") {\n // The definition is a string which we can assume is MDSL, so attempt to validate it.\n return validateMDSLDefinition(definition);\n } else if (typeof definition === \"object\") {\n // The definition will either be an array (of root node definitions) or an object (the single primary root node definition).\n return validateJSONDefinition(definition);\n } else {\n return createValidationFailureResult(`unexpected definition type of '${typeof definition}'`);\n }\n}\n\n/**\n * Validates the specified behaviour tree definition in the form of MDSL.\n * @param definition The behaviour tree definition in the form of MDSL.\n * @returns An object representing the result of validating the given tree definition.\n */\nfunction validateMDSLDefinition(definition: string): DefinitionValidationResult {\n let rootNodeDefinitions;\n\n // The first thing the we need to do is to attempt to convert our MDSL into JSON.\n try {\n // The definition is a string which we can assume is MDSL, so attempt to parse it to a JSON definition in the form of an array of root node definitions.\n rootNodeDefinitions = convertMDSLToJSON(definition);\n } catch (exception) {\n // We failed to parse the JSON from the MDSL, this is likely to be the result of it not being a valid MDSL string.\n return createValidationFailureResult((exception as Error).message);\n }\n\n // Unpack all of the root node definitions into arrays of main ('id' defined) and sub ('id' not defined) root node definitions.\n const mainRootNodeDefinitions = rootNodeDefinitions.filter(({ id }) => typeof id === \"undefined\");\n const subRootNodeDefinitions = rootNodeDefinitions.filter(({ id }) => typeof id === \"string\" && id.length > 0);\n\n // We should ALWAYS have exactly one root node definition without an 'id' property defined, which is out main root node definition.\n if (mainRootNodeDefinitions.length !== 1) {\n return createValidationFailureResult(\n \"expected single unnamed root node at base of definition to act as main root\"\n );\n }\n\n // We should never have duplicate 'id' properties across our sub root node definitions.\n const subRootNodeIdenitifers: string[] = [];\n for (const { id } of subRootNodeDefinitions) {\n // Have we already come across this 'id' property value?\n if (subRootNodeIdenitifers.includes(id!)) {\n return createValidationFailureResult(`multiple root nodes found with duplicate name '${id}'`);\n }\n\n subRootNodeIdenitifers.push(id!);\n }\n\n try {\n // Validate our branch -> subtree links and check for any circular dependencies, we don't care about checking for broken subtree links here.\n validateBranchSubtreeLinks(rootNodeDefinitions, false);\n } catch (exception) {\n return createValidationFailureResult((exception as Error).message);\n }\n\n // Our definition was valid!\n return {\n succeeded: true,\n json: rootNodeDefinitions\n };\n}\n\n/**\n * Validates the specified behaviour tree definition in the form of JSON.\n * @param definition The behaviour tree definition in the form of JSON.\n * @returns An object representing the result of validating the given tree definition.\n */\nexport function validateJSONDefinition(\n definition: RootNodeDefinition | RootNodeDefinition[]\n): DefinitionValidationResult {\n // The definition will either be an array (of root node definitions) or an object (the single primary root node definition).\n const rootNodeDefinitions = Array.isArray(definition) ? definition : [definition];\n\n // Iterate over our array of root nodes and call validateNode for each, passing an initial depth of 0, wrapped in a try catch to handle validation failures.\n try {\n rootNodeDefinitions.forEach((rootNodeDefinition) => validateNode(rootNodeDefinition, 0));\n } catch (error) {\n // Handle cases where we have caught a thrown Error and return a failure result with the error message.\n if (error instanceof Error) {\n return createValidationFailureResult(error.message);\n }\n\n // No idea what happened here!\n return createValidationFailureResult(`unexpected error: ${error}`);\n }\n\n // Unpack all of the root node definitions into arrays of main ('id' defined) and sub ('id' not defined) root node definitions.\n const mainRootNodeDefinitions = rootNodeDefinitions.filter(({ id }) => typeof id === \"undefined\");\n const subRootNodeDefinitions = rootNodeDefinitions.filter(({ id }) => typeof id === \"string\" && id.length > 0);\n\n // We should ALWAYS have exactly one root node definition without an 'id' property defined, which is out main root node definition.\n if (mainRootNodeDefinitions.length !== 1) {\n return createValidationFailureResult(\n \"expected single root node without 'id' property defined to act as main root\"\n );\n }\n\n // We should never have duplicate 'id' properties across our sub root node definitions.\n const subRootNodeIdenitifers: string[] = [];\n for (const { id } of subRootNodeDefinitions) {\n // Have we already come across this 'id' property value?\n if (subRootNodeIdenitifers.includes(id!)) {\n return createValidationFailureResult(\n `multiple root nodes found with duplicate 'id' property value of '${id}'`\n );\n }\n\n subRootNodeIdenitifers.push(id!);\n }\n\n try {\n // Validate our branch -> subtree links and check for any circular dependencies, we don't care about checking for broken subtree links here.\n validateBranchSubtreeLinks(rootNodeDefinitions, false);\n } catch (exception) {\n return createValidationFailureResult((exception as Error).message);\n }\n\n // Our definition was valid!\n return {\n succeeded: true,\n json: rootNodeDefinitions\n };\n}\n\n/**\n * Validates the branch -> subtree links across all provided root node definitions.\n * This will not consider branch nodes that reference any globally registered subtrees unless includesGlobalSubtrees\n * is set to true, in which case we will also verify that there are no broken branch -> subtree links.\n * @param rootNodeDefinitions The array of root node definitions.\n * @param includesGlobalSubtrees A flag defining whether the array includes all global subtree root node definitions.\n */\nexport function validateBranchSubtreeLinks(rootNodeDefinitions: RootNodeDefinition[], includesGlobalSubtrees: boolean) {\n // Create a mapping of root node identifiers to other root nodes that they reference via branch nodes.\n // Below is an example of a mapping that includes a circular dependency (root => a => b => c => a)\n // [{ refs: [\"a\", \"b\"] }, { id: \"a\", refs: [\"b\"] }, { id: \"b\", refs: [\"c\"] }, { id: \"c\", refs: [\"a\"] }]\n const rootNodeMappings: { id: string | undefined; refs: string[] }[] = rootNodeDefinitions.map(\n (rootNodeDefinition) => ({\n id: rootNodeDefinition.id,\n refs: flattenDefinition(rootNodeDefinition)\n .filter(isBranchNode)\n .map(({ ref }) => ref)\n })\n );\n\n // A recursive function to walk through the mappings, keeping track of which root nodes we have visited in the form of a path of root node identifiers.\n const followRefs = (mapping: { id: string | undefined; refs: string[] }, path: (string | undefined)[] = []) => {\n // Have we found a circular dependency?\n if (path.includes(mapping.id)) {\n // We found a circular dependency! Get the bad path of root node identifiers.\n const badPath = [...path, mapping.id];\n\n // Create the formatted path value. [undefined, \"a\", \"b\", \"c\", \"a\"] would be formatted as \"a -> b -> c -> a\".\n const badPathFormatted = badPath.filter((element) => !!element).join(\" => \");\n\n // No need to continue, we found a circular dependency.\n throw new Error(`circular dependency found in branch node references: ${badPathFormatted}`);\n }\n\n for (const ref of mapping.refs) {\n // Find the mapping for the root node with an identifer matching the current ref.\n const subMapping = rootNodeMappings.find(({ id }) => id === ref);\n\n // We may not have a mapping for this ref, which is normal when we aren't considering all globally registered subtrees.\n if (subMapping) {\n followRefs(subMapping, [...path, mapping.id]);\n } else if (includesGlobalSubtrees) {\n // We found a reference to a root node that doesn't exist, which is a problem seeing as the root node definitons includes all globally registered subtrees.\n throw new Error(\n mapping.id\n ? `subtree '${mapping.id}' has branch node that references root node '${ref}' which has not been defined`\n : `primary tree has branch node that references root node '${ref}' which has not been defined`\n );\n }\n }\n };\n\n // Start looking for circular dependencies and broken references from the primary root node definition.\n followRefs(rootNodeMappings.find((mapping) => typeof mapping.id === \"undefined\")!);\n}\n\n/**\n * Validate an object that we expect to be a node definition.\n * @param definition An object that we expect to be a node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateNode(definition: any, depth: number): void {\n // Every node must be valid object and have a non-empty 'type' string property.\n if (typeof definition !== \"object\" || typeof definition.type !== \"string\" || definition.type.length === 0) {\n throw new Error(\n `node definition is not an object or 'type' property is not a non-empty string at depth '${depth}'`\n );\n }\n\n // How we validate this node definition will depend on its type.\n switch (definition.type) {\n case \"action\":\n validateActionNode(definition, depth);\n break;\n\n case \"condition\":\n validateConditionNode(definition, depth);\n break;\n\n case \"wait\":\n validateWaitNode(definition, depth);\n break;\n\n case \"branch\":\n validateBranchNode(definition, depth);\n break;\n\n case \"root\":\n validateRootNode(definition, depth);\n break;\n\n case \"succeed\":\n validateSucceedNode(definition, depth);\n break;\n\n case \"fail\":\n validateFailNode(definition, depth);\n break;\n\n case \"flip\":\n validateFlipNode(definition, depth);\n break;\n\n case \"repeat\":\n validateRepeatNode(definition, depth);\n break;\n\n case \"retry\":\n validateRetryNode(definition, depth);\n break;\n\n case \"sequence\":\n validateSequenceNode(definition, depth);\n break;\n\n case \"selector\":\n validateSelectorNode(definition, depth);\n break;\n\n case \"parallel\":\n validateParallelNode(definition, depth);\n break;\n\n case \"lotto\":\n validateLottoNode(definition, depth);\n break;\n\n default:\n throw new Error(`unexpected node type of '${definition.type}' at depth '${depth}'`);\n }\n}\n\n/**\n * Validate any attributes for a given node definition.\n * @param definition The node definition.\n * @param depth The depth of the node in the behaviour tree definition.\n */\nfunction validateNodeAttributes(definition: any, depth: number): void {\n // Validate each of the attribute types for this node.\n [\"while\", \"until\", \"entry\", \"exit\", \"step\"].forEach((attributeName) => {\n // Attempt to grab the definition for the current attribute from the node definition.\n const attributeDefinition = definition[attributeName];\n\n // All node attributes are optional, so there is nothing to do if the current attribute is not defined.\n if (typeof attributeDefinition === \"undefined\") {\n return;\n }\n\n // The attribute definition must be an object.\n if (typeof attributeDefinition !== \"object\") {\n throw new Error(\n `expected attribute '${attributeName}' to be an object for '${definition.type}' node at depth '${depth}'`\n );\n }\n\n // The 'call' property must be defined for any attribute definition.\n if (typeof attributeDefinition.call !== \"string\" || attributeDefinition.call.length === 0) {\n throw new Error(\n `expected 'call' property for attribute '${attributeName}' to be a non-empty string for '${definition.type}' node at depth '${depth}'`\n );\n }\n\n // If any node attribute arguments have been defined then they must have been defined in an array.\n if (typeof attributeDefinition.args !== \"undefined\" && !Array.isArray(attributeDefinition.args)) {\n throw new Error(\n `expected 'args' property for attribute '${attributeName}' to be an array for '${definition.type}' node at depth '${depth}'`\n );\n }\n });\n}\n\n/**\n * Validate an object that we expect to be a root node definition.\n * @param definition An object that we expect to be a root node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateRootNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"root\") {\n throw new Error(\"expected node type of 'root' for root node\");\n }\n\n // A root node cannot be the child of another node.\n if (depth > 0) {\n throw new Error(\"a root node cannot be the child of another node\");\n }\n\n // Check that, if the root node 'id' property is defined, it is a non-empty string.\n if (typeof definition.id !== \"undefined\" && (typeof definition.id !== \"string\" || definition.id.length === 0)) {\n throw new Error(\"expected non-empty string for 'id' property if defined for root node\");\n }\n\n // A root node is a decorator node, so must have a child node defined.\n if (typeof definition.child === \"undefined\") {\n throw new Error(\"expected property 'child' to be defined for root node\");\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n\n // Validate the child node of this decorator node.\n validateNode(definition.child, depth + 1);\n}\n\n/**\n * Validate an object that we expect to be a succeed node definition.\n * @param definition An object that we expect to be a succeed node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateSucceedNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"succeed\") {\n throw new Error(`expected node type of 'succeed' for succeed node at depth '${depth}'`);\n }\n\n // A succeed node is a decorator node, so must have a child node defined.\n if (typeof definition.child === \"undefined\") {\n throw new Error(`expected property 'child' to be defined for succeed node at depth '${depth}'`);\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n\n // Validate the child node of this decorator node.\n validateNode(definition.child, depth + 1);\n}\n\n/**\n * Validate an object that we expect to be a fail node definition.\n * @param definition An object that we expect to be a fail node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateFailNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"fail\") {\n throw new Error(`expected node type of 'fail' for fail node at depth '${depth}'`);\n }\n\n // A fail node is a decorator node, so must have a child node defined.\n if (typeof definition.child === \"undefined\") {\n throw new Error(`expected property 'child' to be defined for fail node at depth '${depth}'`);\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n\n // Validate the child node of this decorator node.\n validateNode(definition.child, depth + 1);\n}\n\n/**\n * Validate an object that we expect to be a flip node definition.\n * @param definition An object that we expect to be a flip node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateFlipNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"flip\") {\n throw new Error(`expected node type of 'flip' for flip node at depth '${depth}'`);\n }\n\n // A flip node is a decorator node, so must have a child node defined.\n if (typeof definition.child === \"undefined\") {\n throw new Error(`expected property 'child' to be defined for flip node at depth '${depth}'`);\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n\n // Validate the child node of this decorator node.\n validateNode(definition.child, depth + 1);\n}\n\n/**\n * Validate an object that we expect to be a repeat node definition.\n * @param definition An object that we expect to be a repeat node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateRepeatNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"repeat\") {\n throw new Error(`expected node type of 'repeat' for repeat node at depth '${depth}'`);\n }\n\n // A repeat node is a decorator node, so must have a child node defined.\n if (typeof definition.child === \"undefined\") {\n throw new Error(`expected property 'child' to be defined for repeat node at depth '${depth}'`);\n }\n\n // Check whether an 'iterations' property has been defined, it may not have been if this node is to repeat indefinitely.\n if (typeof definition.iterations !== \"undefined\") {\n if (Array.isArray(definition.iterations)) {\n // Check whether any elements of the array are not integer values.\n const containsNonInteger = !!definition.iterations.filter((value: unknown) => !isInteger(value)).length;\n\n // If the 'iterations' property is an array then it MUST contain two integer values.\n if (definition.iterations.length !== 2 || containsNonInteger) {\n throw new Error(\n `expected array containing two integer values for 'iterations' property if defined for repeat node at depth '${depth}'`\n );\n }\n\n // A repeat node must have a positive min and max iterations count if they are defined.\n if (definition.iterations[0] < 0 || definition.iterations[1] < 0) {\n throw new Error(\n `expected positive minimum and maximum iterations count for 'iterations' property if defined for repeat node at depth '${depth}'`\n );\n }\n\n // A repeat node must not have a minimum iterations count that exceeds the maximum iterations count.\n if (definition.iterations[0] > definition.iterations[1]) {\n throw new Error(\n `expected minimum iterations count that does not exceed the maximum iterations count for 'iterations' property if defined for repeat node at depth '${depth}'`\n );\n }\n } else if (isInteger(definition.iterations)) {\n // A repeat node must have a positive number of iterations if defined.\n if (definition.iterations < 0) {\n throw new Error(\n `expected positive iterations count for 'iterations' property if defined for repeat node at depth '${depth}'`\n );\n }\n } else {\n throw new Error(\n `expected integer value or array containing two integer values for 'iterations' property if defined for repeat node at depth '${depth}'`\n );\n }\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n\n // Validate the child node of this decorator node.\n validateNode(definition.child, depth + 1);\n}\n\n/**\n * Validate an object that we expect to be a retry node definition.\n * @param definition An object that we expect to be a retry node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateRetryNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"retry\") {\n throw new Error(`expected node type of 'retry' for retry node at depth '${depth}'`);\n }\n\n // A retry node is a decorator node, so must have a child node defined.\n if (typeof definition.child === \"undefined\") {\n throw new Error(`expected property 'child' to be defined for retry node at depth '${depth}'`);\n }\n\n // Check whether an 'attempts' property has been defined, it may not have been if this node is to retry indefinitely.\n if (typeof definition.attempts !== \"undefined\") {\n if (Array.isArray(definition.attempts)) {\n // Check whether any elements of the array are not integer values.\n const containsNonInteger = !!definition.attempts.filter((value: unknown) => !isInteger(value)).length;\n\n // If the 'attempts' property is an array then it MUST contain two integer values.\n if (definition.attempts.length !== 2 || containsNonInteger) {\n throw new Error(\n `expected array containing two integer values for 'attempts' property if defined for retry node at depth '${depth}'`\n );\n }\n\n // A retry node must have a positive min and max attempts count if they are defined.\n if (definition.attempts[0] < 0 || definition.attempts[1] < 0) {\n throw new Error(\n `expected positive minimum and maximum attempts count for 'attempts' property if defined for retry node at depth '${depth}'`\n );\n }\n\n // A retry node must not have a minimum attempts count that exceeds the maximum attempts count.\n if (definition.attempts[0] > definition.attempts[1]) {\n throw new Error(\n `expected minimum attempts count that does not exceed the maximum attempts count for 'attempts' property if defined for retry node at depth '${depth}'`\n );\n }\n } else if (isInteger(definition.attempts)) {\n // A retry node must have a positive number of attempts if defined.\n if (definition.attempts < 0) {\n throw new Error(\n `expected positive attempts count for 'attempts' property if defined for retry node at depth '${depth}'`\n );\n }\n } else {\n throw new Error(\n `expected integer value or array containing two integer values for 'attempts' property if defined for retry node at depth '${depth}'`\n );\n }\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n\n // Validate the child node of this decorator node.\n validateNode(definition.child, depth + 1);\n}\n\n/**\n * Validate an object that we expect to be a branch node definition.\n * @param definition An object that we expect to be a branch node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateBranchNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"branch\") {\n throw new Error(`expected node type of 'branch' for branch node at depth '${depth}'`);\n }\n\n // Check that the branch node 'ref' property is defined and is a non-empty string.\n if (typeof definition.ref !== \"string\" || definition.ref.length === 0) {\n throw new Error(`expected non-empty string for 'ref' property for branch node at depth '${depth}'`);\n }\n\n // It is invalid to define guard attributes for a branch node as they should be defined on the referenced root node.\n [\"while\", \"until\"].forEach((attributeName) => {\n if (typeof definition[attributeName] !== \"undefined\") {\n throw new Error(\n `guards should not be defined for branch nodes but guard '${attributeName}' was defined for branch node at depth '${depth}'`\n );\n }\n });\n\n // It is invalid to define callback attributes for a branch node as they should be defined on the referenced root node.\n [\"entry\", \"exit\", \"step\"].forEach((attributeName) => {\n if (typeof definition[attributeName] !== \"undefined\") {\n throw new Error(\n `callbacks should not be defined for branch nodes but callback '${attributeName}' was defined for branch node at depth '${depth}'`\n );\n }\n });\n}\n\n/**\n * Validate an object that we expect to be a action node definition.\n * @param definition An object that we expect to be a action node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateActionNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"action\") {\n throw new Error(`expected node type of 'action' for action node at depth '${depth}'`);\n }\n\n // The 'call' property must be defined for a action node definition.\n if (typeof definition.call !== \"string\" || definition.call.length === 0) {\n throw new Error(`expected non-empty string for 'call' property of action node at depth '${depth}'`);\n }\n\n // If any action function arguments have been defined then they must have been defined in an array.\n if (typeof definition.args !== \"undefined\" && !Array.isArray(definition.args)) {\n throw new Error(`expected array for 'args' property if defined for action node at depth '${depth}'`);\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n}\n\n/**\n * Validate an object that we expect to be a condition node definition.\n * @param definition An object that we expect to be a condition node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateConditionNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"condition\") {\n throw new Error(`expected node type of 'condition' for condition node at depth '${depth}'`);\n }\n\n // The 'call' property must be defined for a condition node definition.\n if (typeof definition.call !== \"string\" || definition.call.length === 0) {\n throw new Error(`expected non-empty string for 'call' property of condition node at depth '${depth}'`);\n }\n\n // If any condition function arguments have been defined then they must have been defined in an array.\n if (typeof definition.args !== \"undefined\" && !Array.isArray(definition.args)) {\n throw new Error(`expected array for 'args' property if defined for condition node at depth '${depth}'`);\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n}\n\n/**\n * Validate an object that we expect to be a wait node definition.\n * @param definition An object that we expect to be a wait node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateWaitNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"wait\") {\n throw new Error(`expected node type of 'wait' for wait node at depth '${depth}'`);\n }\n\n // Check whether a 'duration' property has been defined, it may not have been if this node is to wait indefinitely.\n if (typeof definition.duration !== \"undefined\") {\n if (Array.isArray(definition.duration)) {\n // Check whether any elements of the array are not integer values.\n const containsNonInteger = !!definition.duration.filter((value: unknown) => !isInteger(value)).length;\n\n // If the 'duration' property is an array then it MUST contain two integer values.\n if (definition.duration.length !== 2 || containsNonInteger) {\n throw new Error(\n `expected array containing two integer values for 'duration' property if defined for wait node at depth '${depth}'`\n );\n }\n\n // A wait node must have a positive min and max duration value if they are defined.\n if (definition.duration[0] < 0 || definition.duration[1] < 0) {\n throw new Error(\n `expected positive minimum and maximum duration for 'duration' property if defined for wait node at depth '${depth}'`\n );\n }\n\n // A wait node must not have a minimum duration value that exceeds the maximum duration value.\n if (definition.duration[0] > definition.duration[1]) {\n throw new Error(\n `expected minimum duration value that does not exceed the maximum duration value for 'duration' property if defined for wait node at depth '${depth}'`\n );\n }\n } else if (isInteger(definition.duration)) {\n // A wait node must have a positive duration value if defined.\n if (definition.duration < 0) {\n throw new Error(\n `expected positive duration value for 'duration' property if defined for wait node at depth '${depth}'`\n );\n }\n } else {\n throw new Error(\n `expected integer value or array containing two integer values for 'duration' property if defined for wait node at depth '${depth}'`\n );\n }\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n}\n\n/**\n * Validate an object that we expect to be a sequence node definition.\n * @param definition An object that we expect to be a sequence node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateSequenceNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"sequence\") {\n throw new Error(`expected node type of 'sequence' for sequence node at depth '${depth}'`);\n }\n\n // A sequence node is a composite node, so must have a children nodes array defined.\n if (!Array.isArray(definition.children) || definition.children.length === 0) {\n throw new Error(`expected non-empty 'children' array to be defined for sequence node at depth '${depth}'`);\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n\n // Validate the child nodes of this composite node.\n definition.children.forEach((child: any) => validateNode(child, depth + 1));\n}\n\n/**\n * Validate an object that we expect to be a selector node definition.\n * @param definition An object that we expect to be a selector node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateSelectorNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"selector\") {\n throw new Error(`expected node type of 'selector' for selector node at depth '${depth}'`);\n }\n\n // A selector node is a composite node, so must have a children nodes array defined.\n if (!Array.isArray(definition.children) || definition.children.length === 0) {\n throw new Error(`expected non-empty 'children' array to be defined for selector node at depth '${depth}'`);\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n\n // Validate the child nodes of this composite node.\n definition.children.forEach((child: any) => validateNode(child, depth + 1));\n}\n\n/**\n * Validate an object that we expect to be a parallel node definition.\n * @param definition An object that we expect to be a parallel node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateParallelNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"parallel\") {\n throw new Error(`expected node type of 'parallel' for parallel node at depth '${depth}'`);\n }\n\n // A parallel node is a composite node, so must have a children nodes array defined.\n if (!Array.isArray(definition.children) || definition.children.length === 0) {\n throw new Error(`expected non-empty 'children' array to be defined for parallel node at depth '${depth}'`);\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n\n // Validate the child nodes of this composite node.\n definition.children.forEach((child: any) => validateNode(child, depth + 1));\n}\n\n/**\n * Validate an object that we expect to be a lotto node definition.\n * @param definition An object that we expect to be a lotto node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateLottoNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"lotto\") {\n throw new Error(`expected node type of 'lotto' for lotto node at depth '${depth}'`);\n }\n\n // A lotto node is a composite node, so must have a children nodes array defined.\n if (!Array.isArray(definition.children) || definition.children.length === 0) {\n throw new Error(`expected non-empty 'children' array to be defined for lotto node at depth '${depth}'`);\n }\n\n // Check whether a 'weights' property has been defined, if it has we expect it to be an array of weights.\n if (typeof definition.weights !== \"undefined\") {\n // Check that the weights property is an array of positive integers with an element for each child node element.\n if (\n !Array.isArray(definition.weights) ||\n definition.weights.length !== definition.children.length ||\n definition.weights.filter((value: unknown) => !isInteger(value)).length ||\n definition.weights.filter((value: number) => value < 0).length\n ) {\n throw new Error(\n `expected an array of positive integer weight values with a length matching the number of child nodes for 'weights' property if defined for lotto node at depth '${depth}'`\n );\n }\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n\n // Validate the child nodes of this composite node.\n definition.children.forEach((child: any) => validateNode(child, depth + 1));\n}\n\n/**\n * A helper function to create a failure validation result with the given error message.\n * @param errorMessage The validation failure error message.\n * @returns A failure validation result with the given error message.\n */\nfunction createValidationFailureResult(errorMessage: string): DefinitionValidationResult {\n return { succeeded: false, errorMessage };\n}\n", "import { ActionResult, Agent, GlobalFunction } from \"./Agent\";\nimport { RootNodeDefinition } from \"./BehaviourTreeDefinition\";\n\nexport type InvokerFunction = (args: any[]) => ActionResult;\n\n/**\n * A singleton used to store and lookup registered functions and subtrees.\n */\nexport default class Lookup {\n /**\n * The object holding any registered functions keyed on function name.\n */\n private static functionTable: { [key: string]: GlobalFunction } = {};\n /**\n * The object holding any registered subtree root node definitions keyed on tree name.\n */\n private static subtreeTable: { [key: string]: RootNodeDefinition } = {};\n\n /**\n * Gets the function with the specified name.\n * @param name The name of the function.\n * @returns The function with the specified name.\n */\n public static getFunc(name: string): GlobalFunction {\n return this.functionTable[name];\n }\n\n /**\n * Sets the function with the specified name for later lookup.\n * @param name The name of the function.\n * @param func The function.\n */\n public static setFunc(name: string, func: GlobalFunction): void {\n this.functionTable[name] = func;\n }\n\n /**\n * Gets the function invoker for the specified agent and function name.\n * If a function with the specified name exists on the agent object then it will\n * be returned, otherwise we will then check the registered functions for a match.\n * @param agent The agent instance that this behaviour tree is modelling behaviour for.\n * @param name The function name.\n * @returns The function invoker for the specified agent and function name.\n */\n static getFuncInvoker(agent: Agent, name: string): InvokerFunction | null {\n // Check whether the agent contains the specified function.\n const foundOnAgent = agent[name];\n if (foundOnAgent && typeof foundOnAgent === \"function\") {\n return (args: any[]): boolean | ActionResult => foundOnAgent.apply(agent, args);\n }\n\n // The agent does not contain the specified function but it may have been registered at some point.\n if (this.functionTable[name] && typeof this.functionTable[name] === \"function\") {\n return (args: any[]) => this.functionTable[name](agent, ...args.map((arg) => arg.value));\n }\n\n // We have no function to invoke.\n return null;\n }\n\n /**\n * Gets all registered subtree root node definitions.\n */\n static getSubtrees(): { [key: string]: RootNodeDefinition } {\n return this.subtreeTable;\n }\n\n /**\n * Sets the subtree with the specified name for later lookup.\n * @param name The name of the subtree.\n * @param subtree The subtree.\n */\n static setSubtree(name: string, subtree: RootNodeDefinition) {\n this.subtreeTable[name] = subtree;\n }\n\n /**\n * Removes the registered function or subtree with the specified name.\n * @param name The name of the registered function or subtree.\n */\n static remove(name: string) {\n delete this.functionTable[name];\n delete this.subtreeTable[name];\n }\n\n /**\n * Remove all registered functions and subtrees.\n */\n static empty() {\n this.functionTable = {};\n this.subtreeTable = {};\n }\n}\n", "import Node from \"../../nodes/Node\";\n\n/**\n * An exception thrown when evaluating node guard path conditions and a conditions fails.\n */\nexport default class GuardUnsatisifedException extends Error {\n /**\n * @param source The node at which a guard condition failed.\n */\n constructor(private source: Node) {\n super(\"A guard path condition has failed\");\n }\n\n /**\n * Gets whether the specified node is the node at which a guard condition failed.\n * @param node The node to check against the source node.\n * @returns Whether the specified node is the node at which a guard condition failed.\n */\n isSourceNode = (node: Node) => node === this.source;\n}\n", "import { Agent } from \"../../Agent\";\nimport Guard from \"./Guard\";\nimport Node from \"../../nodes/Node\";\nimport GuardUnsatisifedException from \"./GuardUnsatisifedException\";\n\nexport type GuardPathPart = {\n node: Node;\n guards: Guard[];\n};\n\n/**\n * Represents a path of node guards along a root-to-leaf tree path.\n */\nexport default class GuardPath {\n /**\n * @param nodes An array of objects defining a node instance -> guard link, ordered by node depth.\n */\n constructor(private nodes: GuardPathPart[]) {}\n\n /**\n * Evaluate guard conditions for all guards in the tree path, moving outwards from the root.\n * @param agent The agent, required for guard evaluation.\n * @returns An evaluation results object.\n */\n evaluate = (agent: Agent) => {\n // We need to evaluate guard conditions for nodes up the tree, moving outwards from the root.\n for (const details of this.nodes) {\n // There can be multiple guards per node.\n for (const guard of details.guards) {\n // Check whether the guard condition passes, and throw an exception if not.\n if (!guard.isSatisfied(agent)) {\n throw new GuardUnsatisifedException(details.node);\n }\n }\n }\n };\n}\n", "import { BehaviourTreeOptions } from \"../BehaviourTreeOptions\";\nimport State, { AnyState } from \"../State\";\nimport { Agent } from \"../Agent\";\nimport Leaf from \"./leaf/Leaf\";\nimport Attribute from \"../attributes/Attribute\";\nimport Entry from \"../attributes/callbacks/Entry\";\nimport Exit from \"../attributes/callbacks/Exit\";\nimport Step from \"../attributes/callbacks/Step\";\nimport Guard from \"../attributes/guards/Guard\";\nimport GuardPath from \"../attributes/guards/GuardPath\";\nimport GuardUnsatisifedException from \"../attributes/guards/GuardUnsatisifedException\";\n\n/**\n * A base node.\n */\nexport default abstract class Node {\n /**\n * The node uid.\n */\n private readonly uid: string = createNodeUid();\n /**\n * The node state.\n */\n private state: AnyState = State.READY;\n /**\n * The guard path to evaluate as part of a node update.\n */\n private guardPath: GuardPath | undefined;\n\n /**\n * @param type The node type.\n * @param attributes The node attributes.\n * @param args The node argument definitions.\n */\n constructor(private type: string, private attributes: Attribute[], private args: any[]) {}\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected abstract onUpdate(agent: Agent, options: BehaviourTreeOptions): void;\n\n /**\n * Gets the name of the node.\n */\n public abstract getName(): string;\n\n /**\n * Gets whether this node is a leaf node.\n */\n public abstract isLeafNode: () => this is Leaf;\n\n /**\n * Gets/Sets the state of the node.\n */\n getState = (): AnyState => this.state;\n setState = (value: AnyState): void => {\n this.state = value;\n };\n\n /**\n * Gets the unique id of the node.\n */\n getUid = () => this.uid;\n\n /**\n * Gets the type of the node.\n */\n getType = () => this.type;\n\n /**\n * Gets the node attributes.\n */\n getAttributes = () => this.attributes;\n\n /**\n * Gets the node arguments.\n */\n getArguments = () => this.args;\n\n /**\n * Gets the node attribute with the specified type, or null if it does not exist.\n */\n getAttribute(type: \"entry\" | \"ENTRY\"): Entry;\n getAttribute(type: \"exit\" | \"EXIT\"): Exit;\n getAttribute(type: \"step\" | \"STEP\"): Step;\n getAttribute(type: string): Attribute {\n return (\n this.getAttributes().filter((decorator) => decorator.type.toUpperCase() === type.toUpperCase())[0] || null\n );\n }\n\n /**\n * Gets the node attributes.\n */\n getGuardAttributes = (): Guard[] => this.getAttributes().filter((decorator) => decorator.isGuard()) as Guard[];\n\n /**\n * Sets the guard path to evaluate as part of a node update.\n */\n setGuardPath = (value: GuardPath) => (this.guardPath = value);\n\n /**\n * Gets whether a guard path is assigned to this node.\n */\n hasGuardPath = () => !!this.guardPath;\n\n /**\n * Gets whether this node is in the specified state.\n * @param value The value to compare to the node state.\n */\n public is(value: AnyState): boolean {\n return this.state === value;\n }\n\n /**\n * Reset the state of the node.\n */\n public reset(): void {\n this.setState(State.READY);\n }\n\n /**\n * Abort the running of this node.\n * @param agent The agent.\n */\n public abort(agent: Agent): void {\n // There is nothing to do if this node is not in the running state.\n if (!this.is(State.RUNNING)) {\n return;\n }\n\n // Reset the state of this node.\n this.reset();\n\n this.getAttribute(\"exit\")?.callAgentFunction(agent, false, true);\n }\n\n /**\n * Update the node.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n * @returns The result of the update.\n */\n public update(agent: Agent, options: BehaviourTreeOptions): void {\n // If this node is already in a 'SUCCEEDED' or 'FAILED' state then there is nothing to do.\n if (this.is(State.SUCCEEDED) || this.is(State.FAILED)) {\n return;\n }\n\n try {\n // Evaluate all of the guard path conditions for the current tree path.\n this.guardPath!.evaluate(agent);\n\n // If this node is in the READY state then call the ENTRY for this node if it exists.\n if (this.is(State.READY)) {\n this.getAttribute(\"entry\")?.callAgentFunction(agent);\n }\n\n this.getAttribute(\"step\")?.callAgentFunction(agent);\n\n // Do the actual update.\n this.onUpdate(agent, options);\n\n // If this node is now in a 'SUCCEEDED' or 'FAILED' state then call the EXIT for this node if it exists.\n if (this.is(State.SUCCEEDED) || this.is(State.FAILED)) {\n this.getAttribute(\"exit\")?.callAgentFunction(agent, this.is(State.SUCCEEDED), false);\n }\n } catch (error) {\n // If the error is a GuardUnsatisfiedException then we need to determine if this node is the source.\n if (error instanceof GuardUnsatisifedException && error.isSourceNode(this)) {\n // Abort the current node.\n this.abort(agent);\n\n // Any node that is the source of an abort will be a failed node.\n this.setState(State.FAILED);\n } else {\n throw error;\n }\n }\n }\n}\n\n/**\n * Create a randomly generated node uid.\n * @returns A randomly generated node uid.\n */\nfunction createNodeUid(): string {\n var S4 = function () {\n return (((1 + Math.random()) * 0x10000) | 0).toString(16).substring(1);\n };\n return S4() + S4() + \"-\" + S4() + \"-\" + S4() + \"-\" + S4() + \"-\" + S4() + S4() + S4();\n}\n", "import Node from \"../Node\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\n\n/**\n * A composite node that wraps child nodes.\n */\nexport default abstract class Composite extends Node {\n /**\n * @param type The node type.\n * @param attributes The node attributes.\n * @param children The child nodes.\n */\n constructor(type: string, attributes: Attribute[], protected children: Node[]) {\n super(type, attributes, []);\n }\n\n /**\n * Gets whether this node is a leaf node.\n */\n isLeafNode = () => false;\n\n /**\n * Gets the children of this node.\n */\n getChildren = () => this.children;\n\n /**\n * Reset the state of the node.\n */\n reset = () => {\n // Reset the state of this node.\n this.setState(State.READY);\n\n // Reset the state of any child nodes.\n this.getChildren().forEach((child) => child.reset());\n };\n\n /**\n * Abort the running of this node.\n * @param agent The agent.\n */\n abort = (agent: Agent) => {\n // There is nothing to do if this node is not in the running state.\n if (!this.is(State.RUNNING)) {\n return;\n }\n\n // Abort any child nodes.\n this.getChildren().forEach((child) => child.abort(agent));\n\n // Reset the state of this node.\n this.reset();\n\n this.getAttribute(\"exit\")?.callAgentFunction(agent, false, true);\n };\n}\n", "import Composite from \"./Composite\";\nimport State from \"../../State\";\nimport Node from \"../Node\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A PARALLEL node.\n * The child nodes are executed concurrently until one fails or all succeed.\n */\nexport default class Parallel extends Composite {\n /**\n * @param attributes The node attributes.\n * @param children The child nodes.\n */\n constructor(attributes: Attribute[], children: Node[]) {\n super(\"parallel\", attributes, children);\n }\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // Keep a count of the number of succeeded child nodes.\n let succeededCount = 0;\n\n let hasChildFailed = false;\n\n // Iterate over all of the children of this node.\n for (const child of this.children) {\n // If the child has never been updated or is running then we will need to update it now.\n if (child.getState() === State.READY || child.getState() === State.RUNNING) {\n // Update the child of this node.\n child.update(agent, options);\n }\n\n // If the current child has a state of 'SUCCEEDED' then we should move on to the next child.\n if (child.getState() === State.SUCCEEDED) {\n // The child node has succeeded, keep track of this to determine if all children have.\n succeededCount++;\n\n // The child node succeeded, but we have not finished checking every child node yet.\n continue;\n }\n\n // If the current child has a state of 'FAILED' then this node is also a 'FAILED' node.\n if (child.getState() === State.FAILED) {\n hasChildFailed = true;\n\n // There is no need to check the rest of the children.\n break;\n }\n\n // The node should be in the 'RUNNING' state.\n if (child.getState() !== State.RUNNING) {\n // The child node was not in an expected state.\n throw new Error(\"child node was not in an expected state.\");\n }\n }\n\n if (hasChildFailed) {\n // This node is a 'FAILED' node.\n this.setState(State.FAILED);\n\n // Abort every running child.\n for (const child of this.children) {\n if (child.getState() === State.RUNNING) {\n child.abort(agent);\n }\n }\n } else {\n // If all children have succeeded then this node has also succeeded, otherwise it is still running.\n this.setState(succeededCount === this.children.length ? State.SUCCEEDED : State.RUNNING);\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => \"PARALLEL\";\n}\n", "import Composite from \"./Composite\";\nimport Node from \"../Node\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A SELECTOR node.\n * The child nodes are executed in sequence until one succeeds or all fail.\n */\nexport default class Selector extends Composite {\n /**\n * @param attributes The node attributes.\n * @param children The child nodes.\n */\n constructor(attributes: Attribute[], protected children: Node[]) {\n super(\"selector\", attributes, children);\n }\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // Iterate over all of the children of this node.\n for (const child of this.children) {\n // If the child has never been updated or is running then we will need to update it now.\n if (child.getState() === State.READY || child.getState() === State.RUNNING) {\n // Update the child of this node.\n child.update(agent, options);\n }\n\n // If the current child has a state of 'SUCCEEDED' then this node is also a 'SUCCEEDED' node.\n if (child.getState() === State.SUCCEEDED) {\n // This node is a 'SUCCEEDED' node.\n this.setState(State.SUCCEEDED);\n\n // There is no need to check the rest of the selector nodes.\n return;\n }\n\n // If the current child has a state of 'FAILED' then we should move on to the next child.\n if (child.getState() === State.FAILED) {\n // Find out if the current child is the last one in the selector.\n // If it is then this sequence node has also failed.\n if (this.children.indexOf(child) === this.children.length - 1) {\n // This node is a 'FAILED' node.\n this.setState(State.FAILED);\n\n // There is no need to check the rest of the selector as we have completed it.\n return;\n } else {\n // The child node failed, try the next one.\n continue;\n }\n }\n\n // The node should be in the 'RUNNING' state.\n if (child.getState() === State.RUNNING) {\n // This node is a 'RUNNING' node.\n this.setState(State.RUNNING);\n\n // There is no need to check the rest of the selector as the current child is still running.\n return;\n }\n\n // The child node was not in an expected state.\n throw new Error(\"child node was not in an expected state.\");\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => \"SELECTOR\";\n}\n", "import Composite from \"./Composite\";\nimport Node from \"../Node\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A SEQUENCE node.\n * The child nodes are executed in sequence until one fails or all succeed.\n */\nexport default class Sequence extends Composite {\n /**\n * @param attributes The node attributes.\n * @param children The child nodes.\n */\n constructor(attributes: Attribute[], protected children: Node[]) {\n super(\"sequence\", attributes, children);\n }\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // Iterate over all of the children of this node.\n for (const child of this.children) {\n // If the child has never been updated or is running then we will need to update it now.\n if (child.getState() === State.READY || child.getState() === State.RUNNING) {\n // Update the child of this node.\n child.update(agent, options);\n }\n\n // If the current child has a state of 'SUCCEEDED' then we should move on to the next child.\n if (child.getState() === State.SUCCEEDED) {\n // Find out if the current child is the last one in the sequence.\n // If it is then this sequence node has also succeeded.\n if (this.children.indexOf(child) === this.children.length - 1) {\n // This node is a 'SUCCEEDED' node.\n this.setState(State.SUCCEEDED);\n\n // There is no need to check the rest of the sequence as we have completed it.\n return;\n } else {\n // The child node succeeded, but we have not finished the sequence yet.\n continue;\n }\n }\n\n // If the current child has a state of 'FAILED' then this node is also a 'FAILED' node.\n if (child.getState() === State.FAILED) {\n // This node is a 'FAILED' node.\n this.setState(State.FAILED);\n\n // There is no need to check the rest of the sequence.\n return;\n }\n\n // The node should be in the 'RUNNING' state.\n if (child.getState() === State.RUNNING) {\n // This node is a 'RUNNING' node.\n this.setState(State.RUNNING);\n\n // There is no need to check the rest of the sequence as the current child is still running.\n return;\n }\n\n // The child node was not in an expected state.\n throw new Error(\"child node was not in an expected state.\");\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => \"SEQUENCE\";\n}\n", "import createLotto from \"lotto-draw\";\n\nimport Node from \"../Node\";\nimport Composite from \"./Composite\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A LOTTO node.\n * A winning child is picked on the initial update of this node, based on ticket weighting.\n * The state of this node will match the state of the winning child.\n */\nexport default class Lotto extends Composite {\n /**\n * @param attributes The node attributes.\n * @param weights The child node weights.\n * @param children The child nodes.\n */\n constructor(attributes: Attribute[], private weights: number[] | undefined, children: Node[]) {\n super(\"lotto\", attributes, children);\n }\n\n /**\n * The child node selected to be the active one.\n */\n private selectedChild: Node | undefined;\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // If this node is in the READY state then we need to pick a winning child node.\n if (this.is(State.READY)) {\n // Create a lotto draw with which to randomly pick a child node to become the active one.\n const lottoDraw = createLotto({\n // Hook up the optional 'random' behaviour tree function option to the one used by 'lotto-draw'.\n random: options.random,\n // Pass in each child node as a participant in the lotto draw with their respective ticket count.\n participants: this.children.map((child, index) => [child, this.weights?.[index] || 1])\n });\n\n // Randomly pick a child based on ticket weighting, this will become the active child for this composite node.\n this.selectedChild = lottoDraw.draw() || undefined;\n }\n\n // If something went wrong and we don't have an active child then we should throw an error.\n if (!this.selectedChild) {\n throw new Error(\"failed to update lotto node as it has no active child\");\n }\n\n // If the selected child has never been updated or is running then we will need to update it now.\n if (this.selectedChild.getState() === State.READY || this.selectedChild.getState() === State.RUNNING) {\n this.selectedChild.update(agent, options);\n }\n\n // The state of the lotto node is the state of its selected child.\n this.setState(this.selectedChild.getState());\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => (this.weights ? `LOTTO [${this.weights.join(\",\")}]` : \"LOTTO\");\n}\n", "import Node from \"../Node\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\n\n/**\n * A decorator node that wraps a single child node.\n */\nexport default abstract class Decorator extends Node {\n /**\n * @param type The node type.\n * @param attributes The node attributes.\n * @param child The child node.\n */\n constructor(type: string, attributes: Attribute[], protected child: Node) {\n super(type, attributes, []);\n }\n\n /**\n * Gets whether this node is a leaf node.\n */\n isLeafNode = () => false;\n\n /**\n * Gets the children of this node.\n */\n getChildren = () => [this.child];\n\n /**\n * Reset the state of the node.\n */\n reset = () => {\n // Reset the state of this node.\n this.setState(State.READY);\n\n // Reset the state of the child node.\n this.child.reset();\n };\n\n /**\n * Abort the running of this node.\n * @param agent The agent.\n */\n abort = (agent: Agent) => {\n // There is nothing to do if this node is not in the running state.\n if (!this.is(State.RUNNING)) {\n return;\n }\n\n // Abort the child node.\n this.child.abort(agent);\n\n // Reset the state of this node.\n this.reset();\n\n this.getAttribute(\"exit\")?.callAgentFunction(agent, false, true);\n };\n}\n", "import Node from \"../Node\";\nimport Decorator from \"./Decorator\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A Fail node.\n * This node wraps a single child and will always move to the 'FAILED' state when the child moves to a 'SUCCEEDED' or 'FAILED' state.\n */\nexport default class Fail extends Decorator {\n /**\n * @param attributes The node attributes.\n * @param child The child node.\n */\n constructor(attributes: Attribute[], child: Node) {\n super(\"fail\", attributes, child);\n }\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // If the child has never been updated or is running then we will need to update it now.\n if (this.child.getState() === State.READY || this.child.getState() === State.RUNNING) {\n this.child.update(agent, options);\n }\n\n // The state of this node will depend in the state of its child.\n switch (this.child.getState()) {\n case State.RUNNING:\n this.setState(State.RUNNING);\n break;\n\n case State.SUCCEEDED:\n case State.FAILED:\n this.setState(State.FAILED);\n break;\n\n default:\n this.setState(State.READY);\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => \"FAIL\";\n}\n", "import Decorator from \"./Decorator\";\nimport State from \"../../State\";\nimport Node from \"../Node\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A Flip node.\n * This node wraps a single child and will flip the state of the child state.\n */\nexport default class Flip extends Decorator {\n /**\n * @param attributes The node attributes.\n * @param child The child node.\n */\n constructor(attributes: Attribute[], child: Node) {\n super(\"flip\", attributes, child);\n }\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // If the child has never been updated or is running then we will need to update it now.\n if (this.child.getState() === State.READY || this.child.getState() === State.RUNNING) {\n this.child.update(agent, options);\n }\n\n // The state of this node will depend in the state of its child.\n switch (this.child.getState()) {\n case State.RUNNING:\n this.setState(State.RUNNING);\n break;\n\n case State.SUCCEEDED:\n this.setState(State.FAILED);\n break;\n\n case State.FAILED:\n this.setState(State.SUCCEEDED);\n break;\n\n default:\n this.setState(State.READY);\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => \"FLIP\";\n}\n", "import Node from \"../Node\";\nimport Decorator from \"./Decorator\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A REPEAT node.\n * The node has a single child which can have:\n * -- A number of iterations for which to repeat the child node.\n * -- An infinite repeat loop if neither an iteration count or a condition function is defined.\n * The REPEAT node will stop and have a 'FAILED' state if its child is ever in a 'FAILED' state after an update.\n * The REPEAT node will attempt to move on to the next iteration if its child is ever in a 'SUCCEEDED' state.\n */\nexport default class Repeat extends Decorator {\n /**\n * @param attributes The node attributes.\n * @param iterations The number of iterations to repeat the child node.\n * @param iterationsMin The minimum possible number of iterations to repeat the child node.\n * @param iterationsMax The maximum possible number of iterations to repeat the child node.\n * @param child The child node.\n */\n constructor(\n attributes: Attribute[],\n private iterations: number | null,\n private iterationsMin: number | null,\n private iterationsMax: number | null,\n child: Node\n ) {\n super(\"repeat\", attributes, child);\n }\n\n /**\n * The number of target iterations to make.\n */\n private targetIterationCount: number | null = null;\n\n /**\n * The current iteration count.\n */\n private currentIterationCount: number = 0;\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // If this node is in the READY state then we need to reset the child and the target iteration count.\n if (this.is(State.READY)) {\n // Reset the child node.\n this.child.reset();\n\n // Reset the current iteration count.\n this.currentIterationCount = 0;\n\n // Set the target iteration count.\n this.setTargetIterationCount(options);\n }\n\n // Do a check to see if we can iterate. If we can then this node will move into the 'RUNNING' state.\n // If we cannot iterate then we have hit our target iteration count, which means that the node has succeeded.\n if (this.canIterate()) {\n // This node is in the running state and can do its initial iteration.\n this.setState(State.RUNNING);\n\n // We may have already completed an iteration, meaning that the child node will be in the SUCCEEDED state.\n // If this is the case then we will have to reset the child node now.\n if (this.child.getState() === State.SUCCEEDED) {\n this.child.reset();\n }\n\n // Update the child of this node.\n this.child.update(agent, options);\n\n // If the child moved into the FAILED state when we updated it then there is nothing left to do and this node has also failed.\n // If it has moved into the SUCCEEDED state then we have completed the current iteration.\n if (this.child.getState() === State.FAILED) {\n // The child has failed, meaning that this node has failed.\n this.setState(State.FAILED);\n\n return;\n } else if (this.child.getState() === State.SUCCEEDED) {\n // We have completed an iteration.\n this.currentIterationCount += 1;\n }\n } else {\n // This node is in the 'SUCCEEDED' state as we cannot iterate any more.\n this.setState(State.SUCCEEDED);\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => {\n if (this.iterations !== null) {\n return `REPEAT ${this.iterations}x`;\n } else if (this.iterationsMin !== null && this.iterationsMax !== null) {\n return `REPEAT ${this.iterationsMin}x-${this.iterationsMax}x`;\n } else {\n return \"REPEAT\";\n }\n };\n\n /**\n * Reset the state of the node.\n */\n reset = () => {\n // Reset the state of this node.\n this.setState(State.READY);\n\n // Reset the current iteration count.\n this.currentIterationCount = 0;\n\n // Reset the child node.\n this.child.reset();\n };\n\n /**\n * Gets whether an iteration can be made.\n * @returns Whether an iteration can be made.\n */\n private canIterate = () => {\n if (this.targetIterationCount !== null) {\n // We can iterate as long as we have not reached our target iteration count.\n return this.currentIterationCount < this.targetIterationCount;\n }\n\n // If neither an iteration count or a condition function were defined then we can iterate indefinitely.\n return true;\n };\n\n /**\n * Sets the target iteration count.\n * @param options The behaviour tree options object.\n */\n private setTargetIterationCount = (options: BehaviourTreeOptions) => {\n // Are we dealing with an explicit iteration count or will we be randomly picking a iteration count between the min and max iteration count.\n if (this.iterations !== null) {\n this.targetIterationCount = this.iterations;\n } else if (this.iterationsMin !== null && this.iterationsMax !== null) {\n // We will be picking a random iteration count between a min and max iteration count, if the optional 'random'\n // behaviour tree function option is defined then we will be using that, otherwise we will fall back to using Math.random.\n const random = typeof options.random === \"function\" ? options.random : Math.random;\n\n // Pick a random iteration count between a min and max iteration count.\n this.targetIterationCount = Math.floor(\n random() * (this.iterationsMax - this.iterationsMin + 1) + this.iterationsMin\n );\n } else {\n this.targetIterationCount = null;\n }\n };\n}\n", "import Node from \"../Node\";\nimport Decorator from \"./Decorator\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A RETRY node.\n * The node has a single child which can have:\n * -- A number of iterations for which to repeat the child node.\n * -- An infinite repeat loop if neither an iteration count or a condition function is defined.\n * The RETRY node will stop and have a 'SUCCEEDED' state if its child is ever in a 'SUCCEEDED' state after an update.\n * The RETRY node will attempt to move on to the next iteration if its child is ever in a 'FAILED' state.\n */\nexport default class Retry extends Decorator {\n /**\n * @param attributes The node attributes.\n * @param attempts The number of attempts to retry the child node.\n * @param attemptsMin The minimum possible number of attempts to retry the child node.\n * @param attemptsMax The maximum possible number of attempts to retry the child node.\n * @param child The child node.\n */\n constructor(\n attributes: Attribute[],\n private attempts: number | null,\n private attemptsMin: number | null,\n private attemptsMax: number | null,\n child: Node\n ) {\n super(\"retry\", attributes, child);\n }\n\n /**\n * The number of target attempts to make.\n */\n private targetAttemptCount: number | null = null;\n\n /**\n * The current attempt count.\n */\n private currentAttemptCount: number = 0;\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // If this node is in the READY state then we need to reset the child and the target attempt count.\n if (this.is(State.READY)) {\n // Reset the child node.\n this.child.reset();\n\n // Reset the current attempt count.\n this.currentAttemptCount = 0;\n\n // Set the target attempt count.\n this.setTargetAttemptCount(options);\n }\n\n // Do a check to see if we can attempt. If we can then this node will move into the 'RUNNING' state.\n // If we cannot attempt then we have hit our target attempt count, which means that the node has succeeded.\n if (this.canAttempt()) {\n // This node is in the running state and can do its initial attempt.\n this.setState(State.RUNNING);\n\n // We may have already completed an attempt, meaning that the child node will be in the FAILED state.\n // If this is the case then we will have to reset the child node now.\n if (this.child.getState() === State.FAILED) {\n this.child.reset();\n }\n\n // Update the child of this node.\n this.child.update(agent, options);\n\n // If the child moved into the SUCCEEDED state when we updated it then there is nothing left to do and this node has also succeeded.\n // If it has moved into the FAILED state then we have completed the current attempt.\n if (this.child.getState() === State.SUCCEEDED) {\n // The child has succeeded, meaning that this node has succeeded.\n this.setState(State.SUCCEEDED);\n\n return;\n } else if (this.child.getState() === State.FAILED) {\n // We have completed an attempt.\n this.currentAttemptCount += 1;\n }\n } else {\n // This node is in the 'FAILED' state as we cannot iterate any more.\n this.setState(State.FAILED);\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => {\n if (this.attempts !== null) {\n return `RETRY ${this.attempts}x`;\n } else if (this.attemptsMin !== null && this.attemptsMax !== null) {\n return `RETRY ${this.attemptsMin}x-${this.attemptsMax}x`;\n } else {\n return \"RETRY\";\n }\n };\n\n /**\n * Reset the state of the node.\n */\n reset = () => {\n // Reset the state of this node.\n this.setState(State.READY);\n\n // Reset the current attempt count.\n this.currentAttemptCount = 0;\n\n // Reset the child node.\n this.child.reset();\n };\n\n /**\n * Gets whether an attempt can be made.\n * @returns Whether an attempt can be made.\n */\n canAttempt = () => {\n if (this.targetAttemptCount !== null) {\n // We can attempt as long as we have not reached our target attempt count.\n return this.currentAttemptCount < this.targetAttemptCount;\n }\n\n // If neither an attempt count or a condition function were defined then we can attempt indefinitely.\n return true;\n };\n\n /**\n * Sets the target attempt count.\n * @param options The behaviour tree options object.\n */\n setTargetAttemptCount = (options: BehaviourTreeOptions) => {\n // Are we dealing with an explicit attempt count or will we be randomly picking an attempt count between the min and max attempt count.\n if (this.attempts !== null) {\n this.targetAttemptCount = this.attempts;\n } else if (this.attemptsMin !== null && this.attemptsMax !== null) {\n // We will be picking a random attempt count between a min and max attempt count, if the optional 'random'\n // behaviour tree function option is defined then we will be using that, otherwise we will fall back to using Math.random.\n const random = typeof options.random === \"function\" ? options.random : Math.random;\n\n // Pick a random attempt count between a min and max attempt count.\n this.targetAttemptCount = Math.floor(\n random() * (this.attemptsMax - this.attemptsMin + 1) + this.attemptsMin\n );\n } else {\n this.targetAttemptCount = null;\n }\n };\n}\n", "import Node from \"../Node\";\nimport Decorator from \"./Decorator\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A Root node.\n * The root node will have a single child.\n */\nexport default class Root extends Decorator {\n /**\n * @param attributes The node attributes.\n * @param child The child node.\n */\n constructor(attributes: Attribute[], child: Node) {\n super(\"root\", attributes, child);\n }\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // If the child has never been updated or is running then we will need to update it now.\n if (this.child.getState() === State.READY || this.child.getState() === State.RUNNING) {\n // Update the child of this node.\n this.child.update(agent, options);\n }\n\n // The state of the root node is the state of its child.\n this.setState(this.child.getState());\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => \"ROOT\";\n}\n", "import Node from \"../Node\";\nimport Decorator from \"./Decorator\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A Succeed node.\n * This node wraps a single child and will always move to the 'SUCCEEDED' state when the child moves to a 'SUCCEEDED' or 'FAILED' state.\n */\nexport default class Succeed extends Decorator {\n /**\n * @param attributes The node attributes.\n * @param child The child node.\n */\n constructor(attributes: Attribute[], child: Node) {\n super(\"succeed\", attributes, child);\n }\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // If the child has never been updated or is running then we will need to update it now.\n if (this.child.getState() === State.READY || this.child.getState() === State.RUNNING) {\n this.child.update(agent, options);\n }\n\n // The state of this node will depend in the state of its child.\n switch (this.child.getState()) {\n case State.RUNNING:\n this.setState(State.RUNNING);\n break;\n\n case State.SUCCEEDED:\n case State.FAILED:\n this.setState(State.SUCCEEDED);\n break;\n\n default:\n this.setState(State.READY);\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => \"SUCCEED\";\n}\n", "import Node from \"../Node\";\n\n/**\n * A leaf node.\n */\nexport default abstract class Leaf extends Node {\n /**\n * Gets whether this node is a leaf node.\n */\n isLeafNode = () => true;\n}\n", "import { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\nimport State, { CompleteState } from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Leaf from \"./Leaf\";\nimport Lookup from \"../../Lookup\";\nimport Attribute from \"../../attributes/Attribute\";\n\n/**\n * An Action leaf node.\n * This represents an immediate or ongoing state of behaviour.\n */\nexport default class Action extends Leaf {\n /**\n * @param attributes The node attributes.\n * @param actionName The action name.\n * @param actionArguments The array of action argument definitions.\n */\n constructor(attributes: Attribute[], private actionName: string, private actionArguments: any[]) {\n super(\"action\", attributes, actionArguments);\n }\n\n /**\n * Whether there is a pending update promise.\n */\n private isUsingUpdatePromise = false;\n\n /**\n * The finished state result of an update promise.\n */\n private updatePromiseStateResult: CompleteState | null = null;\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // If the result of this action depends on an update promise then there is nothing to do until\n // it resolves, unless there has been a value set as a result of the update promise resolving.\n if (this.isUsingUpdatePromise) {\n // Check whether the update promise has resolved with a state value.\n if (this.updatePromiseStateResult) {\n // Set the state of this node to match the state returned by the promise.\n this.setState(this.updatePromiseStateResult);\n }\n\n return;\n }\n\n // Attempt to get the invoker for the action function.\n const actionFuncInvoker = Lookup.getFuncInvoker(agent, this.actionName);\n\n // The action function should be defined.\n if (actionFuncInvoker === null) {\n throw new Error(\n `cannot update action node as the action '${this.actionName}' function is not defined on the agent and has not been registered`\n );\n }\n\n // Call the action function, the result of which may be:\n // - The finished state of this action node.\n // - A promise to return a finished node state.\n // - Undefined if the node should remain in the running state.\n const updateResult = actionFuncInvoker(this.actionArguments) as CompleteState | Promise;\n\n if (updateResult instanceof Promise) {\n updateResult.then(\n (result) => {\n // If 'isUpdatePromisePending' is null then the promise was cleared as it was resolving, probably via an abort of reset.\n if (!this.isUsingUpdatePromise) {\n return;\n }\n\n // Check to make sure the result is a valid finished state.\n if (result !== State.SUCCEEDED && result !== State.FAILED) {\n throw new Error(\n \"action node promise resolved with an invalid value, expected a State.SUCCEEDED or State.FAILED value to be returned\"\n );\n }\n\n // Set pending update promise state result to be processed on next update.\n this.updatePromiseStateResult = result;\n },\n (reason) => {\n // If 'isUpdatePromisePending' is null then the promise was cleared as it was resolving, probably via an abort of reset.\n if (!this.isUsingUpdatePromise) {\n return;\n }\n\n // Just throw whatever was returned as the rejection argument.\n throw new Error(reason);\n }\n );\n\n // This node will be in the 'RUNNING' state until the update promise resolves.\n this.setState(State.RUNNING);\n\n // We are now waiting for the promise returned by the use to resolve before we know what state this node is in.\n this.isUsingUpdatePromise = true;\n } else {\n // Validate the returned value.\n this.validateUpdateResult(updateResult);\n\n // Set the state of this node, this may be undefined, which just means that the node is still in the 'RUNNING' state.\n this.setState(updateResult || State.RUNNING);\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => this.actionName;\n\n /**\n * Reset the state of the node.\n */\n reset = () => {\n // Reset the state of this node.\n this.setState(State.READY);\n\n // There is no longer an update promise that we care about.\n this.isUsingUpdatePromise = false;\n this.updatePromiseStateResult = null;\n };\n\n /**\n * Validate the result of an update function call.\n * @param result The result of an update function call.\n */\n private validateUpdateResult = (result: CompleteState | boolean) => {\n switch (result) {\n case State.SUCCEEDED:\n case State.FAILED:\n case undefined:\n return;\n default:\n throw new Error(\n `action '${this.actionName}' 'onUpdate' returned an invalid response, expected an optional State.SUCCEEDED or State.FAILED value to be returned`\n );\n }\n };\n}\n", "import { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Leaf from \"./Leaf\";\nimport Lookup from \"../../Lookup\";\nimport Attribute from \"../../attributes/Attribute\";\n\n/**\n * A Condition leaf node.\n * This will succeed or fail immediately based on an agent predicate, without moving to the 'RUNNING' state.\n */\nexport default class Condition extends Leaf {\n /**\n * @param attributes The node attributes.\n * @param conditionName The name of the condition function.\n * @param conditionArguments The array of condition argument definitions.\n */\n constructor(attributes: Attribute[], private conditionName: string, private conditionArguments: any[]) {\n super(\"condition\", attributes, conditionArguments);\n }\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // Attempt to get the invoker for the condition function.\n const conditionFuncInvoker = Lookup.getFuncInvoker(agent, this.conditionName);\n\n // The condition function should be defined.\n if (conditionFuncInvoker === null) {\n throw new Error(\n `cannot update condition node as the condition '${this.conditionName}' function is not defined on the agent and has not been registered`\n );\n }\n\n // Call the condition function to determine the state of this node.\n this.setState(!!conditionFuncInvoker(this.conditionArguments) ? State.SUCCEEDED : State.FAILED);\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => this.conditionName;\n}\n", "import Leaf from \"./Leaf\";\nimport State from \"../../State\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { Agent } from \"../../Agent\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A WAIT node.\n * The state of this node will change to SUCCEEDED after a duration of time\n */\nexport default class Wait extends Leaf {\n /**\n * @param attributes The node attributes.\n * @param duration The duration that this node will wait to succeed in milliseconds.\n * @param durationMin The minimum possible duration in milliseconds that this node will wait to succeed.\n * @param durationMax The maximum possible duration in milliseconds that this node will wait to succeed.\n */\n constructor(\n attributes: Attribute[],\n private duration: number | null,\n private durationMin: number | null,\n private durationMax: number | null\n ) {\n super(\"wait\", attributes, []);\n }\n\n /**\n * The time in milliseconds at which this node was first updated.\n */\n private initialUpdateTime: number = 0;\n\n /**\n * The total duration in milliseconds that this node will be waiting for.\n */\n private totalDuration: number | null = null;\n\n /**\n * The duration in milliseconds that this node has been waiting for.\n */\n private waitedDuration: number = 0;\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // If this node is in the READY state then we need to set the initial update time.\n if (this.is(State.READY)) {\n // Set the initial update time.\n this.initialUpdateTime = new Date().getTime();\n\n // Set the initial waited duration.\n this.waitedDuration = 0;\n\n // Are we dealing with an explicit duration or will we be randomly picking a duration between the min and max duration.\n if (this.duration !== null) {\n this.totalDuration = this.duration;\n } else if (this.durationMin !== null && this.durationMax !== null) {\n // We will be picking a random duration between a min and max duration, if the optional 'random' behaviour tree\n // function option is defined then we will be using that, otherwise we will fall back to using Math.random.\n const random = typeof options.random === \"function\" ? options.random : Math.random;\n\n // Pick a random duration between a min and max duration.\n this.totalDuration = Math.floor(\n random() * (this.durationMax - this.durationMin + 1) + this.durationMin\n );\n } else {\n this.totalDuration = null;\n }\n\n // The node is now running until we finish waiting.\n this.setState(State.RUNNING);\n }\n\n // If we have no total duration then this wait node will wait indefinitely until it is aborted.\n if (this.totalDuration === null) {\n return;\n }\n\n // If we have a 'getDeltaTime' function defined as part of our options then we will use it to figure out how long we have waited for.\n if (typeof options.getDeltaTime === \"function\") {\n // Get the delta time.\n const deltaTime = options.getDeltaTime();\n\n // Our delta time must be a valid number and cannot be NaN.\n if (typeof deltaTime !== \"number\" || isNaN(deltaTime)) {\n throw new Error(\"The delta time must be a valid number and not NaN.\");\n }\n\n // Update the amount of time that this node has been waiting for based on the delta time.\n this.waitedDuration += deltaTime * 1000;\n } else {\n // We are not using a delta time, so we will just work out hom much time has passed since the first update.\n this.waitedDuration = new Date().getTime() - this.initialUpdateTime;\n }\n\n // Have we waited long enough?\n if (this.waitedDuration >= this.totalDuration) {\n // We have finished waiting!\n this.setState(State.SUCCEEDED);\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => {\n if (this.duration !== null) {\n return `WAIT ${this.duration}ms`;\n } else if (this.durationMin !== null && this.durationMax !== null) {\n return `WAIT ${this.durationMin}ms-${this.durationMax}ms`;\n } else {\n return \"WAIT\";\n }\n };\n}\n", "import Guard from \"./guards/Guard\";\n\nexport type AttributeDetails = {\n /** The attribute type. */\n type: string;\n\n /** The attribute arguments. */\n args: any[];\n};\n\n/**\n * A base node attribute.\n */\nexport default abstract class Attribute {\n /**\n * @param type The node attribute type.\n * @param args The array of attribute arguments.\n */\n constructor(public type: string, public args: any[]) {}\n\n /**\n * Gets the attribute details.\n */\n abstract getDetails(): TAttributeDetails;\n\n /**\n * Gets whether this attribute is a guard.\n */\n abstract isGuard: () => this is Guard;\n}\n", "import { Agent } from \"../../Agent\";\nimport Attribute, { AttributeDetails } from \"../Attribute\";\n\nexport type GuardAttributeDetails = {\n /** The name of the condition function that determines whether the guard is satisfied. */\n condition: string;\n} & AttributeDetails;\n\n/**\n * A base node guard attribute.\n */\nexport default abstract class Guard extends Attribute {\n /**\n * @param type The node attribute type.\n * @param args The array of decorator argument definitions.\n * @param condition The name of the condition function that determines whether the guard is satisfied.\n */\n constructor(type: string, args: any[], private condition: string) {\n super(type, args);\n }\n\n /**\n * Gets the name of the condition function that determines whether the guard is satisfied.\n */\n getCondition = () => this.condition;\n\n /**\n * Gets whether this attribute is a guard.\n */\n isGuard = () => true;\n\n /**\n * Gets the attribute details.\n */\n getDetails(): GuardAttributeDetails {\n return {\n type: this.type,\n args: this.args,\n condition: this.getCondition()\n };\n }\n\n /**\n * Gets whether the guard is satisfied.\n * @param agent The agent.\n * @returns Whether the guard is satisfied.\n */\n abstract isSatisfied(agent: Agent): boolean;\n}\n", "import Guard from \"./Guard\";\nimport Lookup from \"../../Lookup\";\nimport { Agent } from \"../../Agent\";\n\n/**\n * A WHILE guard which is satisfied as long as the given condition remains true.\n */\nexport default class While extends Guard {\n /**\n * @param condition The name of the condition function that determines whether the guard is satisfied.\n * @param args The array of decorator argument definitions.\n */\n constructor(condition: string, args: any[]) {\n super(\"while\", args, condition);\n }\n\n /**\n * Gets whether the guard is satisfied.\n * @param agent The agent.\n * @returns Whether the guard is satisfied.\n */\n isSatisfied = (agent: Agent) => {\n // Attempt to get the invoker for the condition function.\n const conditionFuncInvoker = Lookup.getFuncInvoker(agent, this.getCondition());\n\n // The condition function should be defined.\n if (conditionFuncInvoker === null) {\n throw new Error(\n `cannot evaluate node guard as the condition '${this.getCondition()}' function is not defined on the agent and has not been registered`\n );\n }\n\n // Call the condition function to determine whether this guard is satisfied.\n return !!conditionFuncInvoker(this.args);\n };\n}\n", "import Guard from \"./Guard\";\nimport Lookup from \"../../Lookup\";\nimport { Agent } from \"../../Agent\";\n\n/**\n * An UNTIL guard which is satisfied as long as the given condition remains false.\n */\nexport default class Until extends Guard {\n /**\n * @param condition The name of the condition function that determines whether the guard is satisfied.\n * @param args The array of decorator argument definitions.\n */\n constructor(condition: string, args: any[]) {\n super(\"until\", args, condition);\n }\n\n /**\n * Gets whether the guard is satisfied.\n * @param agent The agent.\n * @returns Whether the guard is satisfied.\n */\n isSatisfied = (agent: Agent) => {\n // Attempt to get the invoker for the condition function.\n const conditionFuncInvoker = Lookup.getFuncInvoker(agent, this.getCondition());\n\n // The condition function should be defined.\n if (conditionFuncInvoker === null) {\n throw new Error(\n `cannot evaluate node guard as the condition '${this.getCondition()}' function is not defined on the agent and has not been registered`\n );\n }\n\n // Call the condition function to determine whether this guard is satisfied.\n return !!!conditionFuncInvoker(this.args);\n };\n}\n", "import { Agent } from \"../../Agent\";\nimport Attribute, { AttributeDetails } from \"../Attribute\";\n\nexport type CallbackAttributeDetails = {\n /** The name of the agent function that is called. */\n functionName: string;\n} & AttributeDetails;\n\n/**\n * A base node callback attribute.\n */\nexport default abstract class Callback extends Attribute {\n /**\n * @param type The node attribute type.\n * @param args The array of decorator argument definitions.\n * @param functionName The name of the agent function to call.\n */\n constructor(type: string, args: any[], private functionName: string) {\n super(type, args);\n }\n\n /**\n * Gets the name of the agent function to call.\n */\n getFunctionName = () => this.functionName;\n\n /**\n * Gets whether this attribute is a guard.\n */\n isGuard = () => false;\n\n /**\n * Gets the attribute details.\n */\n getDetails(): CallbackAttributeDetails {\n return {\n type: this.type,\n args: this.args,\n functionName: this.getFunctionName()\n };\n }\n\n /**\n * Attempt to call the agent function that this callback refers to.\n * @param agent The agent.\n */\n abstract callAgentFunction: (agent: Agent, isSuccess: boolean, isAborted: boolean) => void;\n}\n", "import Callback from \"./Callback\";\nimport Lookup from \"../../Lookup\";\nimport { Agent } from \"../../Agent\";\n\n/**\n * An ENTRY callback which defines an agent function to call when the associated node is updated and moves out of running state.\n */\nexport default class Entry extends Callback {\n /**\n * @param functionName The name of the agent function to call.\n * @param args The array of callback argument definitions.\n */\n constructor(functionName: string, args: any[]) {\n super(\"entry\", args, functionName);\n }\n\n /**\n * Attempt to call the agent function that this callback refers to.\n * @param agent The agent.\n */\n callAgentFunction = (agent: Agent) => {\n // Attempt to get the invoker for the callback function.\n const callbackFuncInvoker = Lookup.getFuncInvoker(agent, this.getFunctionName());\n\n // The callback function should be defined.\n if (callbackFuncInvoker === null) {\n throw new Error(\n `cannot call entry function '${this.getFunctionName()}' as is not defined on the agent and has not been registered`\n );\n }\n\n // Call the callback function.\n callbackFuncInvoker(this.args);\n };\n}\n", "import Callback from \"./Callback\";\nimport Lookup from \"../../Lookup\";\nimport { Agent } from \"../../Agent\";\n\n/**\n * A STEP callback which defines an agent function to call when the associated node is updated.\n */\nexport default class Step extends Callback {\n /**\n * @param functionName The name of the agent function to call.\n * @param args The array of callback argument definitions.\n */\n constructor(functionName: string, args: any[]) {\n super(\"step\", args, functionName);\n }\n\n /**\n * Attempt to call the agent function that this callback refers to.\n * @param agent The agent.\n */\n callAgentFunction = (agent: Agent) => {\n // Attempt to get the invoker for the callback function.\n const callbackFuncInvoker = Lookup.getFuncInvoker(agent, this.getFunctionName());\n\n // The callback function should be defined.\n if (callbackFuncInvoker === null) {\n throw new Error(\n `cannot call step function '${this.getFunctionName()}' as is not defined on the agent and has not been registered`\n );\n }\n\n // Call the callback function.\n callbackFuncInvoker(this.args);\n };\n}\n", "import Callback from \"./Callback\";\nimport Lookup from \"../../Lookup\";\nimport { Agent } from \"../../Agent\";\n\n/**\n * An EXIT callback which defines an agent function to call when the associated node is updated and moves to a finished state or is aborted.\n */\nexport default class Exit extends Callback {\n /**\n * @param functionName The name of the agent function to call.\n * @param args The array of callback argument definitions.\n */\n constructor(functionName: string, args: any[]) {\n super(\"exit\", args, functionName);\n }\n\n /**\n * Attempt to call the agent function that this callback refers to.\n * @param agent The agent.\n * @param isSuccess Whether the decorated node was left with a success state.\n * @param isAborted Whether the decorated node was aborted.\n */\n callAgentFunction = (agent: Agent, isSuccess: boolean, isAborted: boolean) => {\n // Attempt to get the invoker for the callback function.\n const callbackFuncInvoker = Lookup.getFuncInvoker(agent, this.getFunctionName());\n\n // The callback function should be defined.\n if (callbackFuncInvoker === null) {\n throw new Error(\n `cannot call exit function '${this.getFunctionName()}' as is not defined on the agent and has not been registered`\n );\n }\n\n // Call the callback function\n callbackFuncInvoker([{ value: { succeeded: isSuccess, aborted: isAborted } }, ...this.args]);\n };\n}\n", "import { AnyNodeDefinition, RootNodeDefinition } from \"./BehaviourTreeDefinition\";\nimport GuardPath, { GuardPathPart } from \"./attributes/guards/GuardPath\";\nimport { validateBranchSubtreeLinks } from \"./BehaviourTreeDefinitionValidator\";\nimport { isInteger } from \"./BehaviourTreeDefinitionUtilities\";\nimport Node from \"./nodes/Node\";\nimport Composite from \"./nodes/composite/Composite\";\nimport Decorator from \"./nodes/decorator/Decorator\";\nimport Parallel from \"./nodes/composite/Parallel\";\nimport Selector from \"./nodes/composite/Selector\";\nimport Sequence from \"./nodes/composite/Sequence\";\nimport Lotto from \"./nodes/composite/Lotto\";\nimport Fail from \"./nodes/decorator/Fail\";\nimport Flip from \"./nodes/decorator/Flip\";\nimport Repeat from \"./nodes/decorator/Repeat\";\nimport Retry from \"./nodes/decorator/Retry\";\nimport Root from \"./nodes/decorator/Root\";\nimport Succeed from \"./nodes/decorator/Succeed\";\nimport Action from \"./nodes/leaf/Action\";\nimport Condition from \"./nodes/leaf/Condition\";\nimport Wait from \"./nodes/leaf/Wait\";\nimport Lookup from \"./Lookup\";\nimport Attribute from \"./attributes/Attribute\";\nimport While from \"./attributes/guards/While\";\nimport Until from \"./attributes/guards/Until\";\nimport Entry from \"./attributes/callbacks/Entry\";\nimport Step from \"./attributes/callbacks/Step\";\nimport Exit from \"./attributes/callbacks/Exit\";\n\n/**\n * A type representing any node instance in a behaviour tree.\n */\ntype AnyNode =\n | Root\n | Action\n | Condition\n | Wait\n | Sequence\n | Selector\n | Lotto\n | Parallel\n | Repeat\n | Retry\n | Flip\n | Succeed\n | Fail;\n\n/**\n * A type defining a mapping of root node identifiers to root node definitions.\n */\ntype RootNodeDefinitionMap = { [key: string | symbol]: RootNodeDefinition };\n\n/**\n * A symbol to use as the main root key in any root node mappings.\n */\nconst MAIN_ROOT_NODE_KEY = Symbol(\"__root__\");\n\n/**\n * Build and populate the root nodes based on the provided definition, assuming that the definition has been validated.\n * @param definition The root node definitions.\n * @returns The built and populated root node definitions.\n */\nexport default function buildRootNode(definition: RootNodeDefinition[]): Root {\n // Create a mapping of root node identifers to root node definitions, including globally registered subtree root node definitions.\n const rootNodeDefinitionMap = createRootNodeDefinitionMap(definition);\n\n // Now that we have all of our root node definitons (those part of the tree definition and those globally\n // registered) we should validate the definition. This will also double-check that we dont have any circular\n // dependencies in our branch -> subtree references and that we have no broken branch -> subtree links.\n validateBranchSubtreeLinks(definition, true);\n\n // Create our populated tree of node instances, starting with our main root node.\n const rootNode = nodeFactory(rootNodeDefinitionMap[MAIN_ROOT_NODE_KEY], rootNodeDefinitionMap) as Root;\n\n // Set a guard path on every leaf of the tree to evaluate as part of each update.\n applyLeafNodeGuardPaths(rootNode);\n\n // We only need to return the main root node.\n return rootNode;\n}\n\n/**\n * A factory function which creates a node instance based on the specified definition.\n * @param definition The node definition.\n * @param rootNodeDefinitionMap The mapping of root node identifers to root node definitions, including globally registered subtree root node definitions.\n * @returns A node instance based on the specified definition.\n */\nfunction nodeFactory(definition: AnyNodeDefinition, rootNodeDefinitionMap: RootNodeDefinitionMap): AnyNode {\n // Get the attributes for the node.\n const attributes = nodeAttributesFactory(definition);\n\n // Create the node instance based on the definition type.\n switch (definition.type) {\n case \"root\":\n return new Root(attributes, nodeFactory(definition.child, rootNodeDefinitionMap));\n\n case \"repeat\":\n let iterations: number | null = null;\n let iterationsMin: number | null = null;\n let iterationsMax: number | null = null;\n\n if (Array.isArray(definition.iterations)) {\n iterationsMin = definition.iterations[0];\n iterationsMax = definition.iterations[1];\n } else if (isInteger(definition.iterations)) {\n iterations = definition.iterations!;\n }\n\n return new Repeat(\n attributes,\n iterations,\n iterationsMin,\n iterationsMax,\n nodeFactory(definition.child, rootNodeDefinitionMap)\n );\n\n case \"retry\":\n let attempts: number | null = null;\n let attemptsMin: number | null = null;\n let attemptsMax: number | null = null;\n\n if (Array.isArray(definition.attempts)) {\n attemptsMin = definition.attempts[0];\n attemptsMax = definition.attempts[1];\n } else if (isInteger(definition.attempts)) {\n attempts = definition.attempts!;\n }\n\n return new Retry(\n attributes,\n attempts,\n attemptsMin,\n attemptsMax,\n nodeFactory(definition.child, rootNodeDefinitionMap)\n );\n\n case \"flip\":\n return new Flip(attributes, nodeFactory(definition.child, rootNodeDefinitionMap));\n\n case \"succeed\":\n return new Succeed(attributes, nodeFactory(definition.child, rootNodeDefinitionMap));\n\n case \"fail\":\n return new Fail(attributes, nodeFactory(definition.child, rootNodeDefinitionMap));\n\n case \"sequence\":\n return new Sequence(\n attributes,\n definition.children.map((child) => nodeFactory(child, rootNodeDefinitionMap))\n );\n\n case \"selector\":\n return new Selector(\n attributes,\n definition.children.map((child) => nodeFactory(child, rootNodeDefinitionMap))\n );\n\n case \"parallel\":\n return new Parallel(\n attributes,\n definition.children.map((child) => nodeFactory(child, rootNodeDefinitionMap))\n );\n\n case \"lotto\":\n return new Lotto(\n attributes,\n definition.weights,\n definition.children.map((child) => nodeFactory(child, rootNodeDefinitionMap))\n );\n\n case \"branch\":\n return nodeFactory(rootNodeDefinitionMap[definition.ref].child, rootNodeDefinitionMap);\n\n case \"action\":\n return new Action(attributes, definition.call, definition.args || []);\n\n case \"condition\":\n return new Condition(attributes, definition.call, definition.args || []);\n\n case \"wait\":\n let duration: number | null = null;\n let durationMin: number | null = null;\n let durationMax: number | null = null;\n\n if (Array.isArray(definition.duration)) {\n durationMin = definition.duration[0];\n durationMax = definition.duration[1];\n } else if (isInteger(definition.duration)) {\n duration = definition.duration!;\n }\n\n return new Wait(attributes, duration, durationMin, durationMax);\n }\n}\n\n/**\n * Creates an array of node attribute instances based on the specified node definition.\n * @param definition The node definition.\n * @returns An array of node attribute instances based on the specified node definition.\n */\nfunction nodeAttributesFactory(definition: AnyNodeDefinition): Attribute[] {\n const attributes: Attribute[] = [];\n\n if (definition.while) {\n attributes.push(new While(definition.while.call, definition.while.args ?? []));\n }\n\n if (definition.until) {\n attributes.push(new Until(definition.until.call, definition.until.args ?? []));\n }\n\n if (definition.entry) {\n attributes.push(new Entry(definition.entry.call, definition.entry.args ?? []));\n }\n\n if (definition.step) {\n attributes.push(new Step(definition.step.call, definition.step.args ?? []));\n }\n\n if (definition.exit) {\n attributes.push(new Exit(definition.exit.call, definition.exit.args ?? []));\n }\n\n return attributes;\n}\n\n/**\n * Creates a mapping of root node identifers to root node definitions, mixing in globally registered subtree root node definitions.\n * @param definition The root node definitions.\n * @returns A mapping of root node identifers to root node definitions, including globally registered subtree root node definitions.\n */\nfunction createRootNodeDefinitionMap(definition: RootNodeDefinition[]): RootNodeDefinitionMap {\n // Create a mapping of root node identifers to root node definitions.\n const rootNodeMap: RootNodeDefinitionMap = {};\n\n // Add in any registered subtree root node definitions.\n for (const [name, rootNodeDefinition] of Object.entries(Lookup.getSubtrees())) {\n // The name used when registering the subtree will be used as the root node identifier.\n rootNodeMap[name] = { ...rootNodeDefinition, id: name };\n }\n\n // Populate the map with the root node definitions that were included with the tree definition.\n // We do this after adding any registered subtrees as we want these to take presedence.\n for (const rootNodeDefinition of definition) {\n rootNodeMap[rootNodeDefinition.id ?? MAIN_ROOT_NODE_KEY] = rootNodeDefinition;\n }\n\n return rootNodeMap;\n}\n\n/**\n * Applies a guard path to every leaf of the tree to evaluate as part of each update.\n * @param root The main root tree node.\n */\nfunction applyLeafNodeGuardPaths(root: Root) {\n const nodePaths: Node[][] = [];\n\n const findLeafNodes = (path: Node[], node: Node) => {\n // Add the current node to the path.\n path = path.concat(node);\n\n // Check whether the current node is a leaf node.\n if (node.isLeafNode()) {\n nodePaths.push(path);\n } else {\n (node as Composite | Decorator).getChildren().forEach((child) => findLeafNodes(path, child));\n }\n };\n\n // Find all leaf node paths, starting from the root.\n findLeafNodes([], root);\n\n nodePaths.forEach((path) => {\n // Each node in the current path will have to be assigned a guard path, working from the root outwards.\n for (let depth = 0; depth < path.length; depth++) {\n // Get the node in the path at the current depth.\n const currentNode = path[depth];\n\n // The node may already have been assigned a guard path, if so just skip it.\n if (currentNode.hasGuardPath()) {\n continue;\n }\n\n // Create the guard path for the current node.\n const guardPath = new GuardPath(\n path\n .slice(0, depth + 1)\n .map((node) => ({ node, guards: node.getGuardAttributes() }))\n .filter((details) => details.guards.length > 0)\n );\n\n // Assign the guard path to the current node.\n currentNode.setGuardPath(guardPath);\n }\n });\n}\n", "import State, { AnyState } from \"./State\";\nimport Lookup from \"./Lookup\";\nimport Node from \"./nodes/Node\";\nimport Root from \"./nodes/decorator/Root\";\nimport Composite from \"./nodes/composite/Composite\";\nimport Decorator from \"./nodes/decorator/Decorator\";\nimport { Agent, GlobalFunction } from \"./Agent\";\nimport { CallbackAttributeDetails } from \"./attributes/callbacks/Callback\";\nimport { GuardAttributeDetails } from \"./attributes/guards/Guard\";\nimport { BehaviourTreeOptions } from \"./BehaviourTreeOptions\";\nimport { convertMDSLToJSON } from \"./mdsl/MDSLDefinitionParser\";\nimport { RootNodeDefinition } from \"./BehaviourTreeDefinition\";\nimport { validateDefinition, validateJSONDefinition } from \"./BehaviourTreeDefinitionValidator\";\nimport buildRootNode from \"./BehaviourTreeBuilder\";\nimport { isNullOrUndefined } from \"./BehaviourTreeDefinitionUtilities\";\n\n// Purely for outside inspection of the tree.\nexport type FlattenedTreeNode = {\n id: string;\n type: string;\n caption: string;\n state: AnyState;\n guards: GuardAttributeDetails[];\n callbacks: CallbackAttributeDetails[];\n args: any[];\n parentId: string | null;\n};\n\n/**\n * A representation of a behaviour tree.\n */\nexport class BehaviourTree {\n /**\n * The main root tree node.\n */\n public readonly rootNode: Root;\n\n /**\n * Creates a new instance of the BehaviourTree class.\n * @param definition The behaviour tree definition as either an MDSL string, root node definition object or array of root node definition objects.\n * @param agent The agent instance that this behaviour tree is modelling behaviour for.\n * @param options The behaviour tree options object.\n */\n constructor(\n definition: string | RootNodeDefinition | RootNodeDefinition[],\n private agent: Agent,\n private options: BehaviourTreeOptions = {}\n ) {\n // The tree definition must be defined.\n if (isNullOrUndefined(definition)) {\n throw new Error(\"tree definition not defined\");\n }\n\n // The agent must be defined and not null.\n if (typeof agent !== \"object\" || agent === null) {\n throw new Error(\"the agent must be an object and not null\");\n }\n\n // We should validate the definition before we try to build the tree nodes.\n const { succeeded, errorMessage, json } = validateDefinition(definition);\n\n // Did our validation fail without error?\n if (!succeeded) {\n throw new Error(`invalid definition: ${errorMessage}`);\n }\n\n // Double check that we did actually get our json definition as part of our definition validtion.\n if (!json) {\n throw new Error(\n \"expected json definition to be returned as part of successful definition validation response\"\n );\n }\n\n try {\n // Create the populated tree of behaviour tree nodes and get the root node.\n this.rootNode = buildRootNode(json);\n } catch (exception) {\n // There was an issue in trying build and populate the behaviour tree.\n throw new Error(`error building tree: ${(exception as Error).message}`);\n }\n }\n\n /**\n * Gets whether the tree is in the RUNNING state.\n * @returns true if the tree is in the RUNNING state, otherwise false.\n */\n isRunning() {\n return this.rootNode.getState() === State.RUNNING;\n }\n\n /**\n * Gets the current tree state of SUCCEEDED, FAILED, READY or RUNNING.\n * @returns The current tree state.\n */\n getState() {\n return this.rootNode.getState();\n }\n\n /**\n * Step the tree.\n * 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.\n * 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\n * 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.\n *\n * 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.\n */\n step() {\n // If the root node has already been stepped to completion then we need to reset it.\n if (this.rootNode.getState() === State.SUCCEEDED || this.rootNode.getState() === State.FAILED) {\n this.rootNode.reset();\n }\n\n try {\n this.rootNode.update(this.agent, this.options);\n } catch (exception) {\n throw new Error(`error stepping tree: ${(exception as Error).message}`);\n }\n }\n\n /**\n * Resets the tree from the root node outwards to each nested node, giving each a state of READY.\n */\n reset() {\n this.rootNode.reset();\n }\n\n /**\n * Gets the flattened details of every node in the tree.\n * @returns The flattened details of every node in the tree.\n */\n getFlattenedNodeDetails(): FlattenedTreeNode[] {\n // Create an empty flattened array of tree nodes.\n const flattenedTreeNodes: FlattenedTreeNode[] = [];\n\n /**\n * Helper function to process a node instance and push details into the flattened tree nodes array.\n * @param node The current node.\n * @param parentUid The UID of the node parent, or null if the node is the main root node.\n */\n const processNode = (node: Node, parentUid: string | null) => {\n // Get the guard and callback attribute details for this node.\n const guards = node\n .getAttributes()\n .filter((attribute) => attribute.isGuard())\n .map((attribute) => attribute.getDetails()) as GuardAttributeDetails[];\n const callbacks = node\n .getAttributes()\n .filter((attribute) => !attribute.isGuard())\n .map((attribute) => attribute.getDetails()) as CallbackAttributeDetails[];\n\n // Push the current node into the flattened nodes array.\n flattenedTreeNodes.push({\n id: node.getUid(),\n type: node.getType(),\n caption: node.getName(),\n state: node.getState(),\n guards,\n callbacks,\n args: node.getArguments(),\n parentId: parentUid\n });\n\n // Process each of the nodes children if it is not a leaf node.\n if (!node.isLeafNode()) {\n (node as Composite | Decorator)\n .getChildren()\n .forEach((child) => processNode(child, (node as Composite | Decorator).getUid()));\n }\n };\n\n // Convert the nested node structure into a flattened array of node details.\n processNode(this.rootNode, null);\n\n return flattenedTreeNodes;\n }\n\n /**\n * Registers the action/condition/guard/callback function or subtree with the given name.\n * @param name The name of the function or subtree to register.\n * @param value The function or subtree definition to register.\n */\n static register(name: string, value: GlobalFunction | string | RootNodeDefinition) {\n // Are we going to register a action/condition/guard/callback function?\n if (typeof value === \"function\") {\n Lookup.setFunc(name, value);\n return;\n }\n\n // We are not registering an action/condition/guard/callback function, so we must be registering a subtree.\n if (typeof value === \"string\") {\n let rootNodeDefinitions: RootNodeDefinition[];\n\n // We will assume that any string passed in will be a mdsl definition.\n try {\n rootNodeDefinitions = convertMDSLToJSON(value);\n } catch (exception) {\n throw new Error(`error registering definition, invalid MDSL: ${(exception as Error).message}`);\n }\n\n // This function should only ever be called with a definition containing a single unnamed root node.\n if (rootNodeDefinitions.length != 1 || rootNodeDefinitions[0].id !== null) {\n throw new Error(\"error registering definition: expected a single unnamed root node\");\n }\n\n try {\n // We should validate the subtree as we don't want invalid subtrees available via the lookup.\n const { succeeded, errorMessage } = validateJSONDefinition(rootNodeDefinitions[0]);\n\n // Did our validation fail without error?\n if (!succeeded) {\n throw new Error(errorMessage);\n }\n } catch (exception) {\n throw new Error(`error registering definition: ${(exception as Error).message}`);\n }\n\n // Everything seems hunky-dory, register the subtree.\n Lookup.setSubtree(name, rootNodeDefinitions[0]);\n } else if (typeof value === \"object\" && !Array.isArray(value)) {\n // We will assume that any object passed in is a root node definition.\n\n try {\n // We should validate the subtree as we don't want invalid subtrees available via the lookup.\n const { succeeded, errorMessage } = validateJSONDefinition(value);\n\n // Did our validation fail without error?\n if (!succeeded) {\n throw new Error(errorMessage);\n }\n } catch (exception) {\n throw new Error(`error registering definition: ${(exception as Error).message}`);\n }\n\n // Everything seems hunky-dory, register the subtree.\n Lookup.setSubtree(name, value);\n } else {\n throw new Error(\"unexpected value, expected string mdsl definition, root node json definition or function\");\n }\n }\n\n /**\n * Unregisters the registered action/condition/guard/callback function or subtree with the given name.\n * @param name The name of the registered action/condition/guard/callback function or subtree to unregister.\n */\n static unregister(name: string): void {\n Lookup.remove(name);\n }\n\n /**\n * Unregister all registered action/condition/guard/callback functions and subtrees.\n */\n static unregisterAll(): void {\n Lookup.empty();\n }\n}\n"], - "mappings": "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", + "sourcesContent": ["\"use strict\";\r\nObject.defineProperty(exports, \"__esModule\", { value: true });\r\nexports.Participant = void 0;\r\n/**\r\n * A participant that holds a number of tickets.\r\n */\r\nvar Participant = /** @class */ (function () {\r\n /**\r\n * Creates an instance of the Participant class.\r\n * @param participant The actual participant.\r\n * @param tickets The number of tickets held by the participant.\r\n */\r\n function Participant(participant, tickets) {\r\n if (tickets === void 0) { tickets = 1; }\r\n this._participant = participant;\r\n this._tickets = tickets;\r\n }\r\n Object.defineProperty(Participant.prototype, \"participant\", {\r\n /** Gets the actual participant. */\r\n get: function () {\r\n return this._participant;\r\n },\r\n enumerable: false,\r\n configurable: true\r\n });\r\n Object.defineProperty(Participant.prototype, \"tickets\", {\r\n /** Gets or sets the number of tickets held by the participant. */\r\n get: function () {\r\n return this._tickets;\r\n },\r\n set: function (value) {\r\n this._tickets = value;\r\n },\r\n enumerable: false,\r\n configurable: true\r\n });\r\n return Participant;\r\n}());\r\nexports.Participant = Participant;\r\n", "\"use strict\";\r\nObject.defineProperty(exports, \"__esModule\", { value: true });\r\nexports.isNaturalNumber = exports.isNullOrUndefined = void 0;\r\n/**\r\n * Gets whether the value provided is null or undefined.\r\n * @param value The value to check.\r\n * @returns Whether the value provided is null or undefined.\r\n */\r\nfunction isNullOrUndefined(value) {\r\n return value === null || value === undefined;\r\n}\r\nexports.isNullOrUndefined = isNullOrUndefined;\r\n/**\r\n * Gets whether the value provided is a natural number.\r\n * @param value The value to check.\r\n * @returns Whether the value provided is a natural number.\r\n */\r\nfunction isNaturalNumber(value) {\r\n return typeof value === \"number\" && value >= 1 && Math.floor(value) === value;\r\n}\r\nexports.isNaturalNumber = isNaturalNumber;\r\n", "\"use strict\";\r\nObject.defineProperty(exports, \"__esModule\", { value: true });\r\nexports.Lotto = void 0;\r\nvar Participant_1 = require(\"./Participant\");\r\nvar Utilities_1 = require(\"./Utilities\");\r\n/**\r\n * Represents a lotto consisting of a number of pickable ticket-holding participants.\r\n */\r\nvar Lotto = /** @class */ (function () {\r\n /**\r\n * Creates a new instance of Lotto.\r\n * @param customRandom The custom RNG to use in place of Math.random().\r\n */\r\n function Lotto(customRandom) {\r\n /** The array of participants that are holding tickets in the lotto. */\r\n this._participants = [];\r\n this._customRandom = customRandom;\r\n }\r\n /**\r\n * Adds a participant with the specified number of tickets, or adds to the participant ticket count if the participant already holds tickets.\r\n * @param participant The participant to add or to increase the ticket count for if they already hold tickets.\r\n * @param tickets The number of tickets, defaults to 1.\r\n * @returns The Lotto instance.\r\n */\r\n Lotto.prototype.add = function (participant, tickets) {\r\n if (tickets === void 0) { tickets = 1; }\r\n // Check that we have a valid ticket count.\r\n if (!(0, Utilities_1.isNaturalNumber)(tickets)) {\r\n throw new Error(\"tickets value must be a natural number\");\r\n }\r\n // Check whether this participant has already been added.\r\n var existingParticipant = this._participants.find(function (part) { return part.participant === participant; });\r\n if (existingParticipant) {\r\n // The participant has already been added to the lotto so just add to their ticket count.\r\n existingParticipant.tickets += tickets;\r\n }\r\n else {\r\n // The participant is not part of the lotto so we should add them.\r\n this._participants.push(new Participant_1.Participant(participant, tickets));\r\n }\r\n return this;\r\n };\r\n /**\r\n * Removes the specified number of tickets for the given participant from the draw, or all tickets if a ticket number is not defined.\r\n * @param participant The participant to remove tickets for.\r\n * @param tickets The number of tickets to remove, or undefined if all tickets are to be removed.\r\n * @returns The Lotto instance.\r\n */\r\n Lotto.prototype.remove = function (participant, tickets) {\r\n // Attempt to get the existing participant.\r\n var existingParticipant = this._participants.find(function (part) { return part.participant === participant; });\r\n // There is nothing to do if the specified participant isn't even part of the lotto.\r\n if (!existingParticipant) {\r\n return this;\r\n }\r\n // Check whether a tickets value was given.\r\n if (tickets !== undefined) {\r\n // Check that we have a valid ticket count.\r\n if (!(0, Utilities_1.isNaturalNumber)(tickets)) {\r\n throw new Error(\"tickets value must be a natural number\");\r\n }\r\n existingParticipant.tickets -= tickets;\r\n // If the participant no longer holds any tickets then they should be removed.\r\n if (existingParticipant.tickets < 1) {\r\n this._participants = this._participants.filter(function (part) { return part !== existingParticipant; });\r\n }\r\n }\r\n else {\r\n // We are removing all tickets for the participant so just remove them from the lotto.\r\n this._participants = this._participants.filter(function (part) { return part !== existingParticipant; });\r\n }\r\n return this;\r\n };\r\n /**\r\n * Draw a winning ticket and return the participant that holds the ticket.\r\n * @param options The draw options.\r\n * @returns The participant that holds the winning ticket.\r\n */\r\n Lotto.prototype.draw = function (options) {\r\n if (options === void 0) { options = {}; }\r\n // If we have no participants then just return null.\r\n if (this._participants.length === 0) {\r\n return null;\r\n }\r\n var redrawable = (0, Utilities_1.isNullOrUndefined)(options.redrawable) ? true : options.redrawable;\r\n var pickable = [];\r\n this._participants.forEach(function (_a) {\r\n var participant = _a.participant, tickets = _a.tickets;\r\n for (var ticketCount = 0; ticketCount < tickets; ticketCount++) {\r\n pickable.push(participant);\r\n }\r\n });\r\n var random;\r\n // We need a random floating-point number between 0 (inclusive) and 1 to scale up to pick our winner.\r\n // If a custom random function exists then we should use that or fall back to Math.random().\r\n if (this._customRandom) {\r\n // Call our custom random function to get a random floating-point number.\r\n random = this._customRandom();\r\n // Verify that the result of calling our custom random function is a number between 0 (inclusive) and 1.\r\n if (typeof random !== \"number\" || random < 0 || random >= 1) {\r\n throw new Error(\"the 'random' function provided did not return a number between 0 (inclusive) and 1\");\r\n }\r\n }\r\n else {\r\n // No custom random function was defined so just use good ol' Math.random().\r\n random = Math.random();\r\n }\r\n // Pick a winning participant.\r\n var winner = pickable[Math.floor(random * pickable.length)];\r\n // If the ticket isn't redrawable then we should remove a ticket from the winning participants ticket count.\r\n if (!redrawable) {\r\n this.remove(winner, 1);\r\n }\r\n // Return the winning participant.\r\n return winner;\r\n };\r\n /**\r\n * Draws multiple winning tickets and return an array of the participants that hold the winning tickets.\r\n * @param tickets The number of winning tickets to draw.\r\n * @param options The draw multiple options.\r\n * @returns An array of the participants that hold the winning tickets.\r\n */\r\n Lotto.prototype.drawMultiple = function (tickets, options) {\r\n if (options === void 0) { options = {}; }\r\n var uniqueResults = (0, Utilities_1.isNullOrUndefined)(options.unique) ? false : options.unique;\r\n // Handle cases where the user has asked for zero tickets (no idea why they would do this be we should trust them).\r\n if (tickets === 0) {\r\n return [];\r\n }\r\n // Now that we know out tickets value is not zero we should check that it is a valid natural number.\r\n if (!(0, Utilities_1.isNaturalNumber)(tickets)) {\r\n throw new Error(\"tickets value must be a natural number\");\r\n }\r\n var result = [];\r\n // Keep drawing tickets until we either reach the number of required tickets or we simply run out of tickets to draw.\r\n // We can run out of tickets to draw if 'options.redrawable' is explicity 'false' or we just had no participants when 'drawMultiple' was called.\r\n while (result.length < tickets && this._participants.length > 0) {\r\n result.push(this.draw(options));\r\n }\r\n // If the 'unique' draw option is set then we need to remove duplicates from the result list.\r\n if (uniqueResults) {\r\n // Create an array to store our unique results.\r\n var unique = [];\r\n // Iterate over all of our participants (with potential duplicates) and populate our array of unique values.\r\n for (var _i = 0, result_1 = result; _i < result_1.length; _i++) {\r\n var participant = result_1[_i];\r\n if (unique.indexOf(participant) === -1) {\r\n unique.push(participant);\r\n }\r\n }\r\n result = unique;\r\n }\r\n return result;\r\n };\r\n return Lotto;\r\n}());\r\nexports.Lotto = Lotto;\r\n", "\"use strict\";\r\nObject.defineProperty(exports, \"__esModule\", { value: true });\r\nexports.createLotto = void 0;\r\nvar Lotto_1 = require(\"./Lotto\");\r\n/**\r\n * A function that creates and returns a Lotto instance.\r\n * @param participantsOrOptions An array of initial participants or options relating to the creation of a Lotto instance.\r\n * @returns A new Lotto instance.\r\n */\r\nfunction createLotto(participantsOrOptions) {\r\n // If no initial participants or lotto options were provided as an argument then we can just return a new lotto instance now.\r\n if (!participantsOrOptions) {\r\n return new Lotto_1.Lotto();\r\n }\r\n // Check whether we were provided with an array of initial participants or a lotto options object.\r\n if (Array.isArray(participantsOrOptions)) {\r\n // We are dealing with a pre-defined array of participants.\r\n var participants = participantsOrOptions;\r\n var lotto_1 = new Lotto_1.Lotto();\r\n // If the lotto participants have been defined upfront then we will need to add them all to our lotto instance now.\r\n participants.forEach(function (_a) {\r\n var participant = _a[0], tokens = _a[1];\r\n return lotto_1.add(participant, tokens);\r\n });\r\n // Return the Lotto instance.\r\n return lotto_1;\r\n }\r\n else {\r\n // We are dealing with some lotto options.\r\n var random = participantsOrOptions.random, participants = participantsOrOptions.participants;\r\n // Create a Lotto instance passing the custom RNG function to use in place of Math.random() (which could be undefined).\r\n var lotto_2 = new Lotto_1.Lotto(random);\r\n // If the lotto participants have been defined upfront as part of the options then we will need to add them all to our lotto instance now.\r\n if (participants) {\r\n participants.forEach(function (_a) {\r\n var participant = _a[0], tokens = _a[1];\r\n return lotto_2.add(participant, tokens);\r\n });\r\n }\r\n // Return the Lotto instance.\r\n return lotto_2;\r\n }\r\n}\r\nexports.createLotto = createLotto;\r\n", "\"use strict\";\r\nObject.defineProperty(exports, \"__esModule\", { value: true });\r\nvar createLotto_1 = require(\"./createLotto\");\r\nexports.default = createLotto_1.createLotto;\r\n", "import State from \"./State\";\nimport { validateDefinition } from \"./BehaviourTreeDefinitionValidator\";\nimport { convertMDSLToJSON } from \"./mdsl/MDSLDefinitionParser\";\nimport { BehaviourTree, FlattenedTreeNode } from \"./BehaviourTree\";\nimport { BehaviourTreeOptions } from \"./BehaviourTreeOptions\";\n\nexport { BehaviourTree, State, convertMDSLToJSON, validateDefinition };\nexport type { FlattenedTreeNode, BehaviourTreeOptions };\n", "/**\n * Enumeration of node state types.\n */\nexport enum State {\n READY = \"mistreevous.ready\",\n RUNNING = \"mistreevous.running\",\n SUCCEEDED = \"mistreevous.succeeded\",\n FAILED = \"mistreevous.failed\"\n}\n\nexport { State as default };\n\nexport type CompleteState = State.SUCCEEDED | State.FAILED;\nexport type AnyState = State.READY | State.RUNNING | CompleteState;\n", "import {\n NodeDefinition,\n RootNodeDefinition,\n DecoratorNodeDefinition,\n CompositeNodeDefinition,\n AnyNodeDefinition,\n BranchNodeDefinition\n} from \"./BehaviourTreeDefinition\";\n\n/**\n * A type guard function that returns true if the specified node satisfies the RootNodeDefinition type.\n * @param node The node.\n * @returns A value of true if the specified node satisfies the RootNodeDefinition type.\n */\nexport function isRootNode(node: NodeDefinition): node is RootNodeDefinition {\n return node.type === \"root\";\n}\n\n/**\n * A type guard function that returns true if the specified node satisfies the BranchNodeDefinition type.\n * @param node The node.\n * @returns A value of true if the specified node satisfies the BranchNodeDefinition type.\n */\nexport function isBranchNode(node: NodeDefinition): node is BranchNodeDefinition {\n return node.type === \"branch\";\n}\n\n/**\n * A type guard function that returns true if the specified node satisfies the NodeDefinition type.\n * @param node The node.\n * @returns A value of true if the specified node satisfies the NodeDefinition type.\n */\nexport function isLeafNode(node: NodeDefinition): node is NodeDefinition {\n return [\"branch\", \"action\", \"condition\", \"wait\"].includes(node.type);\n}\n\n/**\n * A type guard function that returns true if the specified node satisfies the DecoratorNodeDefinition type.\n * @param node The node.\n * @returns A value of true if the specified node satisfies the DecoratorNodeDefinition type.\n */\nexport function isDecoratorNode(node: NodeDefinition): node is DecoratorNodeDefinition {\n return [\"root\", \"repeat\", \"retry\", \"flip\", \"succeed\", \"fail\"].includes(node.type);\n}\n\n/**\n * A type guard function that returns true if the specified node satisfies the CompositeNodeDefinition type.\n * @param node The node.\n * @returns A value of true if the specified node satisfies the CompositeNodeDefinition type.\n */\nexport function isCompositeNode(node: NodeDefinition): node is CompositeNodeDefinition {\n return [\"sequence\", \"selector\", \"lotto\", \"parallel\"].includes(node.type);\n}\n\n/**\n * Flatten a node definition into an array of all of its nested node definitions.\n * @param nodeDefinition The node definition to flatten.\n * @returns An array of all of nested node definitions.\n */\nexport function flattenDefinition(nodeDefinition: AnyNodeDefinition): AnyNodeDefinition[] {\n const nodes: AnyNodeDefinition[] = [];\n\n const processNode = (currentNodeDefinition: AnyNodeDefinition) => {\n nodes.push(currentNodeDefinition);\n\n if (isCompositeNode(currentNodeDefinition)) {\n currentNodeDefinition.children.forEach(processNode);\n } else if (isDecoratorNode(currentNodeDefinition)) {\n processNode(currentNodeDefinition.child);\n }\n };\n\n processNode(nodeDefinition);\n\n return nodes;\n}\n\n/**\n * Determines whether the passed value is an integer.\n * @param value The value to check.\n * @returns Whether the passed value is an integer.\n */\nexport function isInteger(value: unknown): boolean {\n return typeof value === \"number\" && Math.floor(value) === value;\n}\n\n/**\n * Determines whether the passed value is null or undefined.\n * @param value The value to check.\n * @returns Whether the passed value is null or undefined.\n */\nexport function isNullOrUndefined(value: unknown): boolean {\n return typeof value === \"undefined\" || value === null;\n}\n", "/**\n * A type defining an object that holds a reference to substitued string literals parsed from the definition.\n */\nexport type StringLiteralPlaceholders = { [key: string]: string };\n\n/**\n * Pop the next raw token from the specified array of tokens and throw an error if it wasn't the expected one.\n * @param tokens The array of tokens.\n * @param expected An optional string or array or items, one of which must match the next popped token.\n * @returns The popped token.\n */\nexport function popAndCheck(tokens: string[], expected?: string | string[]): string {\n // Get and remove the next token.\n const popped = tokens.shift();\n\n // We were expecting another token but there aren't any.\n if (popped === undefined) {\n throw new Error(\"unexpected end of definition\");\n }\n\n // Do we have an expected token/tokens array?\n if (expected != undefined) {\n // Get an array of expected values, if the popped token matches any then we are all good.\n const expectedValues = typeof expected === \"string\" ? [expected] : expected;\n\n // Check whether the popped token matches at least one of our expected items.\n var tokenMatchesExpectation = expectedValues.some((item) => popped.toUpperCase() === item.toUpperCase());\n\n // Throw an error if the popped token didn't match any of our expected items.\n if (!tokenMatchesExpectation) {\n const expectationString = expectedValues.map((item) => \"'\" + item + \"'\").join(\" or \");\n throw new Error(\"unexpected token found. Expected \" + expectationString + \" but got '\" + popped + \"'\");\n }\n }\n\n // Return the popped token.\n return popped;\n}\n\n/**\n * Swaps out any node/attribute argument string literals with placeholders.\n * @param definition The definition.\n * @returns An object containing a mapping of placeholders to original string values as well as the processed definition string.\n */\nexport function substituteStringLiterals(definition: string): {\n placeholders: StringLiteralPlaceholders;\n processedDefinition: string;\n} {\n // Create an object to hold the mapping of placeholders to original string values.\n const placeholders: StringLiteralPlaceholders = {};\n\n // Replace any string literals wrapped with double quotes in our definition with placeholders to be processed later.\n const processedDefinition = definition.replace(/\\\"(\\\\.|[^\"\\\\])*\\\"/g, (match) => {\n var strippedMatch = match.substring(1, match.length - 1);\n var placeholder = Object.keys(placeholders).find((key) => placeholders[key] === strippedMatch);\n\n // If we have no existing string literal match then create a new placeholder.\n if (!placeholder) {\n placeholder = `@@${Object.keys(placeholders).length}@@`;\n placeholders[placeholder] = strippedMatch;\n }\n\n return placeholder;\n });\n\n return { placeholders, processedDefinition };\n}\n\n/**\n * Parse the tree definition into an array of raw tokens.\n * @param definition The definition.\n * @returns An array of tokens parsed from the definition.\n */\nexport function parseTokensFromDefinition(definition: string): string[] {\n // Add some space around various important characters so that they can be plucked out easier as individual tokens.\n definition = definition.replace(/\\(/g, \" ( \");\n definition = definition.replace(/\\)/g, \" ) \");\n definition = definition.replace(/\\{/g, \" { \");\n definition = definition.replace(/\\}/g, \" } \");\n definition = definition.replace(/\\]/g, \" ] \");\n definition = definition.replace(/\\[/g, \" [ \");\n definition = definition.replace(/\\,/g, \" , \");\n\n // Split the definition into raw token form and return it.\n return definition.replace(/\\s+/g, \" \").trim().split(\" \");\n}\n", "import { StringLiteralPlaceholders, popAndCheck } from \"./MDSLUtilities\";\n\n/**\n * A type representing any node function argument.\n */\ntype Argument = {\n /**\n * The argument value.\n */\n value: T;\n /**\n * The argument type, used for validation.\n */\n type: string;\n};\n\ntype NullArgument = Argument & {\n type: \"null\";\n};\n\ntype BooleanArgument = Argument & {\n type: \"boolean\";\n};\n\ntype NumberArgument = Argument & {\n type: \"number\";\n /**\n * A flag defining whether the number argument value is a valid integer. (used for validation)\n */\n isInteger: boolean;\n};\n\ntype StringPlaceholderArgument = Argument & {\n type: \"string\";\n};\n\ntype IdentifierArgument = Argument & {\n type: \"identifier\";\n};\n\n/**\n * A type representing a reference to any node function argument.\n */\ntype AnyArgument = NullArgument | BooleanArgument | NumberArgument | StringPlaceholderArgument | IdentifierArgument;\n\n/**\n * Parse an array of argument definitions from the specified tokens array.\n * @param tokens The array tokens to parse the argument definitions from.\n * @param stringArgumentPlaceholders The mapping of string literal node argument placeholders to original values.\n * @param argumentValidator The argument validator function.\n * @param validationFailedMessage The exception message to throw if argument validation fails.\n * @returns An array of argument definitions parsed from the specified tokens array.\n */\nexport function parseArgumentTokens(\n tokens: string[],\n stringArgumentPlaceholders: StringLiteralPlaceholders\n): AnyArgument[] {\n const argumentList: AnyArgument[] = [];\n\n // If the next token is not a '[' or '(' then we have no arguments to parse.\n if (![\"[\", \"(\"].includes(tokens[0])) {\n return argumentList;\n }\n\n // Any lists of arguments will always be wrapped in '[]' for node arguments or '()' for attribute arguments.\n // We are looking for a '[' or '(' opener that wraps the argument tokens and the relevant closer.\n const closingToken = popAndCheck(tokens, [\"[\", \"(\"]) === \"[\" ? \"]\" : \")\";\n\n const argumentListTokens: string[] = [];\n\n // Grab all tokens between the '[' and ']' or '(' and ')'.\n while (tokens.length && tokens[0] !== closingToken) {\n // The next token is part of our arguments list.\n argumentListTokens.push(tokens.shift()!);\n }\n\n // Validate the order of the argument tokens. Each token must either be a ',' or a single argument that satisfies the validator.\n argumentListTokens.forEach((token, index) => {\n // Get whether this token should be an actual argument.\n const shouldBeArgumentToken = !(index & 1);\n\n // If the current token should be an actual argument then validate it, otherwise it should be a ',' token.\n if (shouldBeArgumentToken) {\n // Get the argument definition.\n const argumentDefinition = getArgumentDefinition(token, stringArgumentPlaceholders);\n\n // This is a valid argument!\n argumentList.push(argumentDefinition);\n } else {\n // The current token should be a ',' token.\n if (token !== \",\") {\n throw new Error(`invalid argument list, expected ',' or ']' but got '${token}'`);\n }\n }\n });\n\n // The arguments list should terminate with a ']' or ')' token, depending on the opener.\n popAndCheck(tokens, closingToken);\n\n // Return the arguments.\n return argumentList;\n}\n\n/**\n * Gets an argument value definition.\n * @param token The argument token.\n * @param stringArgumentPlaceholders The mapping of string literal node argument placeholders to original values.\n * @returns An argument value definition.\n */\nfunction getArgumentDefinition(token: string, stringArgumentPlaceholders: StringLiteralPlaceholders): AnyArgument {\n // Check whether the token represents a null value.\n if (token === \"null\") {\n return {\n value: null,\n type: \"null\"\n } as NullArgument;\n }\n\n // Check whether the token represents a boolean value.\n if (token === \"true\" || token === \"false\") {\n return {\n value: token === \"true\",\n type: \"boolean\"\n } as BooleanArgument;\n }\n\n // Check whether the token represents a number value.\n // TODO: Relies on broken isNaN - see MDN.\n // if (!Number.isNaN(token)) {\n if (!isNaN(token as any)) {\n return {\n value: parseFloat(token),\n isInteger: parseFloat(token) === parseInt(token, 10),\n type: \"number\"\n } as NumberArgument;\n }\n\n // Check whether the token is a placeholder (e.g. @@0@@) representing a string literal.\n if (token.match(/^@@\\d+@@$/g)) {\n return {\n value: stringArgumentPlaceholders[token].replace('\\\\\"', '\"'),\n type: \"string\"\n } as StringPlaceholderArgument;\n }\n\n // The only remaining option is that the argument value is an identifier.\n return {\n value: token,\n type: \"identifier\"\n } as IdentifierArgument;\n}\n", "import { NodeAttributeDefinition } from \"../BehaviourTreeDefinition\";\nimport { parseArgumentTokens } from \"./MDSLNodeArgumentParser\";\nimport { StringLiteralPlaceholders } from \"./MDSLUtilities\";\n\n/**\n * A type defining the attribute definitions of a node.\n */\ntype NodeAttributes = {\n while?: NodeAttributeDefinition;\n until?: NodeAttributeDefinition;\n entry?: NodeAttributeDefinition;\n exit?: NodeAttributeDefinition;\n step?: NodeAttributeDefinition;\n};\n\n/**\n * Parse any node attribute definitions from the specified tokens array.\n * @param tokens The array of remaining tokens.\n * @param stringArgumentPlaceholders The mapping of string literal node argument placeholders to original values.\n * @returns An object of attribute definitions defined by any directly following tokens.\n */\nexport function parseAttributeTokens(\n tokens: string[],\n stringArgumentPlaceholders: StringLiteralPlaceholders\n): NodeAttributes {\n const nodeAttributeNames: (keyof NodeAttributes)[] = [\"while\", \"until\", \"entry\", \"exit\", \"step\"];\n\n // Create an object to hold any attributes found.\n const attributes: NodeAttributes = {};\n\n // Try to get the name of the attribute for the next token.\n let nextAttributeName = tokens[0]?.toLowerCase() as keyof NodeAttributes;\n\n // Pull attribute tokens as well as their arguments off of the tokens stack until we have no more.\n while (nodeAttributeNames.includes(nextAttributeName)) {\n // Check to make sure that we have not already created an attribute definition of this type.\n if (attributes[nextAttributeName]) {\n throw new Error(`duplicate attribute '${tokens[0].toUpperCase()}' found for node`);\n }\n\n // Remove the attribute name token from the array of tokens.\n tokens.shift();\n\n // Grab the attribute arguments, assuming the first to be an identifier.\n const [attributeCallIdentifier, ...attributeArguments] = parseArgumentTokens(\n tokens,\n stringArgumentPlaceholders\n );\n\n // The first attribute argument has to be an identifer, this will reference an agent function.\n if (attributeCallIdentifier?.type !== \"identifier\") {\n throw new Error(\"expected agent function name identifier argument for attribute\");\n }\n\n // Any attribute arguments (other than the expected call identifier) must have a type of string, number, boolean or null.\n attributeArguments\n .filter((arg) => arg.type === \"identifier\")\n .forEach((arg) => {\n throw new Error(\n `invalid attribute argument value '${arg.value}', must be string, number, boolean or null`\n );\n });\n\n // Create the attribute definition and add it to the object of attribute definitions found.\n attributes[nextAttributeName] = {\n call: attributeCallIdentifier.value,\n args: attributeArguments.map(({ value }) => value)\n };\n\n // Try to get the next attribute name token, as there could be multiple.\n nextAttributeName = tokens[0]?.toLowerCase() as keyof NodeAttributes;\n }\n\n return attributes;\n}\n", "import {\n ActionNodeDefinition,\n AnyChildNodeDefinition,\n AnyNodeDefinition,\n BranchNodeDefinition,\n ConditionNodeDefinition,\n FailNodeDefinition,\n FlipNodeDefinition,\n LottoNodeDefinition,\n ParallelNodeDefinition,\n RepeatNodeDefinition,\n RetryNodeDefinition,\n RootNodeDefinition,\n SelectorNodeDefinition,\n SequenceNodeDefinition,\n SucceedNodeDefinition,\n WaitNodeDefinition\n} from \"../BehaviourTreeDefinition\";\nimport {\n isCompositeNode,\n isDecoratorNode,\n isLeafNode,\n isNullOrUndefined,\n isRootNode\n} from \"../BehaviourTreeDefinitionUtilities\";\nimport { parseArgumentTokens } from \"./MDSLNodeArgumentParser\";\nimport { parseAttributeTokens } from \"./MDSLNodeAttributeParser\";\nimport {\n StringLiteralPlaceholders,\n parseTokensFromDefinition,\n popAndCheck,\n substituteStringLiterals\n} from \"./MDSLUtilities\";\n\n/**\n * Convert the MDSL tree definition string into an equivalent JSON definition.\n * @param definition The tree definition string as MDSL.\n * @returns The root node JSON definitions.\n */\nexport function convertMDSLToJSON(definition: string): RootNodeDefinition[] {\n // Swap out any node/attribute argument string literals with a placeholder and get a mapping of placeholders to original values as well as the processed definition.\n const { placeholders, processedDefinition } = substituteStringLiterals(definition);\n\n // Parse our definition definition string into an array of raw tokens.\n const tokens = parseTokensFromDefinition(processedDefinition);\n\n return convertTokensToJSONDefinition(tokens, placeholders);\n}\n\n/**\n * Converts the specified tree definition tokens into a JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The root node JSON definitions.\n */\nfunction convertTokensToJSONDefinition(\n tokens: string[],\n stringLiteralPlaceholders: StringLiteralPlaceholders\n): RootNodeDefinition[] {\n // There must be at least 3 tokens for the tree definition to be valid. 'ROOT', '{' and '}'.\n if (tokens.length < 3) {\n throw new Error(\"invalid token count\");\n }\n\n // We should have a matching number of '{' and '}' tokens. If not, then there are scopes that have not been properly closed.\n if (tokens.filter((token) => token === \"{\").length !== tokens.filter((token) => token === \"}\").length) {\n throw new Error(\"scope character mismatch\");\n }\n\n // Create an array of tree stack arrays where root nodes will always be at the botton and the current composite/decorator node at the top.\n // There should be an element in this array for every root node defined and every element should be an array with a root note as the first element.\n // E.g. A definition with two root nodes defined:\n // [\n // [root, lotto, sequence],\n // [root, selector]\n // ]\n const treeStacks: [Partial, ...Partial[]][] = [];\n\n // Create an array of all root node definitions that we create.\n const rootNodes: Partial[] = [];\n\n // A helper function used to push node definitions onto the tree stack.\n const pushNode = (node: AnyNodeDefinition) => {\n // If the node is a root node then we need to create a new tree stack array with the root node at the root.\n if (isRootNode(node)) {\n // We need to double-check that this root node is not the child of another node.\n // We can do this by checking whether the top tree stack is not empty (contains an existing node)\n if (treeStacks[treeStacks.length - 1]?.length) {\n throw new Error(\"a root node cannot be the child of another node\");\n }\n\n // Add the root node definition to our array of all parsed root node definitions.\n rootNodes.push(node);\n\n // Add the root node definition to the root of a new tree stack.\n treeStacks.push([node]);\n\n return;\n }\n\n // All non-root nodes should be pushed after their root nodes so handle cases\n // where we may not have any tree stacks or our top-most tree stack is empty.\n if (!treeStacks.length || !treeStacks[treeStacks.length - 1].length) {\n throw new Error(\"expected root node at base of definition\");\n }\n\n // Get the current tree stack that we are populating.\n const topTreeStack = treeStacks[treeStacks.length - 1];\n\n // Get the top-most node in the current tree stack, this will be a composite/decorator node\n // for which we will populate its children array if composite or setting its child if a decorator.\n const topTreeStackTopNode = topTreeStack[topTreeStack.length - 1] as AnyNodeDefinition;\n\n // If the top-most node in the current root stack is a composite or decorator\n // node then the current node should be added as a child of the top-most node.\n if (isCompositeNode(topTreeStackTopNode)) {\n topTreeStackTopNode.children = topTreeStackTopNode.children || [];\n topTreeStackTopNode.children.push(node);\n } else if (isDecoratorNode(topTreeStackTopNode)) {\n // If the top node already has a child node set then throw an error as a decorator should only have a single child.\n if (topTreeStackTopNode.child) {\n throw new Error(\"a decorator node must only have a single child node\");\n }\n\n topTreeStackTopNode.child = node;\n }\n\n // If the node we are adding is also a composite or decorator node, then we should push it\n // onto the current tree stack, as subsequent nodes will be added as its child/children.\n if (!isLeafNode(node)) {\n topTreeStack.push(node);\n }\n };\n\n // A helper function used to pop the top-most node definition off of the tree stack and return it.\n const popNode = (): AnyNodeDefinition | null => {\n let poppedNode: AnyNodeDefinition | null = null;\n\n // Get the current tree stack that we are populating.\n const topTreeStack = treeStacks[treeStacks.length - 1];\n\n // Pop the top-most node in the current tree stack if there is one.\n if (topTreeStack.length) {\n poppedNode = topTreeStack.pop() as AnyNodeDefinition;\n }\n\n // We don't want any empty tree stacks in our stack of tree stacks.\n if (!topTreeStack.length) {\n treeStacks.pop();\n }\n\n return poppedNode;\n };\n\n // We should keep processing the raw tokens until we run out of them.\n while (tokens.length) {\n // Grab the next token.\n const token = tokens.shift()!;\n\n // How we create the next node depends on the current raw token value.\n switch (token.toUpperCase()) {\n case \"ROOT\": {\n pushNode(createRootNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"SUCCEED\": {\n pushNode(createSucceedNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"FAIL\": {\n pushNode(createFailNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"FLIP\": {\n pushNode(createFlipNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"REPEAT\": {\n pushNode(createRepeatNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"RETRY\": {\n pushNode(createRetryNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"SEQUENCE\": {\n pushNode(createSequenceNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"SELECTOR\": {\n pushNode(createSelectorNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"PARALLEL\": {\n pushNode(createParallelNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"LOTTO\": {\n pushNode(createLottoNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"ACTION\": {\n pushNode(createActionNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"CONDITION\": {\n pushNode(createConditionNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"WAIT\": {\n pushNode(createWaitNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"BRANCH\": {\n pushNode(createBranchNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"}\": {\n // The '}' character closes the current scope and means that we have to pop a node off of the current stack.\n const poppedNode = popNode();\n\n // Now that we have a node definition we can carry out any validation that may require the node to be fully populated.\n if (poppedNode) {\n validatePoppedNode(poppedNode);\n }\n\n break;\n }\n\n default: {\n throw new Error(`unexpected token: ${token}`);\n }\n }\n }\n\n return rootNodes as RootNodeDefinition[];\n}\n\n/**\n * Creates a root node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The root node JSON definition.\n */\nfunction createRootNode(tokens: string[], stringLiteralPlaceholders: StringLiteralPlaceholders): RootNodeDefinition {\n // Create the root node definition.\n let node = {\n type: \"root\",\n id: undefined\n } as RootNodeDefinition;\n\n // Parse any node arguments, we should only have one if any which will be an identifier argument for the root identifier.\n const nodeArguments = parseArgumentTokens(tokens, stringLiteralPlaceholders);\n\n // Check whether any node arguments were defined.\n if (nodeArguments.length) {\n // We should only have one argument, if any, which will be an identifier argument for the root identifier.\n if (nodeArguments.length === 1 && nodeArguments[0].type === \"identifier\") {\n // The root node identifier will be the first and only node argument value.\n node.id = nodeArguments[0].value as string;\n } else {\n throw new Error(\"expected single root name argument\");\n }\n }\n\n // Grab any node attribute definitions and spread them into the node definition.\n node = { ...node, ...parseAttributeTokens(tokens, stringLiteralPlaceholders) };\n\n // This is a decorator node, so we expect an opening '{'.\n popAndCheck(tokens, \"{\");\n\n // Return the root node definition.\n return node;\n}\n\n/**\n * Creates a succeed node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The succeed node JSON definition.\n */\nfunction createSucceedNode(\n tokens: string[],\n stringLiteralPlaceholders: StringLiteralPlaceholders\n): SucceedNodeDefinition {\n const node = {\n type: \"succeed\",\n ...parseAttributeTokens(tokens, stringLiteralPlaceholders)\n } as SucceedNodeDefinition;\n\n // This is a decorator node, so we expect an opening '{'.\n popAndCheck(tokens, \"{\");\n\n // Return the succeed node definition.\n return node;\n}\n\n/**\n * Creates a fail node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The fail node JSON definition.\n */\nfunction createFailNode(tokens: string[], stringLiteralPlaceholders: StringLiteralPlaceholders): FailNodeDefinition {\n const node = {\n type: \"fail\",\n ...parseAttributeTokens(tokens, stringLiteralPlaceholders)\n } as FailNodeDefinition;\n\n // This is a decorator node, so we expect an opening '{'.\n popAndCheck(tokens, \"{\");\n\n // Return the fail node definition.\n return node;\n}\n\n/**\n * Creates a flip node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The flip node JSON definition.\n */\nfunction createFlipNode(tokens: string[], stringLiteralPlaceholders: StringLiteralPlaceholders): FlipNodeDefinition {\n const node = {\n type: \"flip\",\n ...parseAttributeTokens(tokens, stringLiteralPlaceholders)\n } as FlipNodeDefinition;\n\n // This is a decorator node, so we expect an opening '{'.\n popAndCheck(tokens, \"{\");\n\n // Return the flip node definition.\n return node;\n}\n\n/**\n * Creates a repeat node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The repeat node JSON definition.\n */\nfunction createRepeatNode(\n tokens: string[],\n stringLiteralPlaceholders: StringLiteralPlaceholders\n): RepeatNodeDefinition {\n let node = { type: \"repeat\" } as RepeatNodeDefinition;\n\n // Get the node arguments.\n const nodeArguments = parseArgumentTokens(tokens, stringLiteralPlaceholders);\n\n // The arguments of a repeat node are optional. We may have:\n // - No node arguments, in which case the repeat note will iterate indefinitely.\n // - One node argument which will be the explicit number of iterations to make.\n // - Two node arguments which define the min and max iteration bounds from which a random iteration count will be picked.\n if (nodeArguments.length) {\n // All repeat node arguments MUST be of type number and must be integer.\n nodeArguments\n .filter((arg) => arg.type !== \"number\" || !arg.isInteger)\n .forEach(() => {\n throw new Error(`repeat node iteration counts must be integer values`);\n });\n\n // We should have got one or two iteration counts.\n if (nodeArguments.length === 1) {\n // A static iteration count was defined.\n node.iterations = nodeArguments[0].value as number;\n\n // A repeat node must have a positive number of iterations if defined.\n if (node.iterations < 0) {\n throw new Error(\"a repeat node must have a positive number of iterations if defined\");\n }\n } else if (nodeArguments.length === 2) {\n // A minimum and maximum iteration count was defined.\n node.iterations = [nodeArguments[0].value as number, nodeArguments[1].value as number];\n\n // A repeat node must have a positive min and max iteration count if they are defined.\n if (node.iterations[0] < 0 || node.iterations[1] < 0) {\n throw new Error(\"a repeat node must have a positive minimum and maximum iteration count if defined\");\n }\n\n // A repeat node must not have an minimum iteration count that exceeds the maximum iteration count.\n if (node.iterations[0] > node.iterations[1]) {\n throw new Error(\n \"a repeat node must not have a minimum iteration count that exceeds the maximum iteration count\"\n );\n }\n } else {\n // An incorrect number of iteration counts was defined.\n throw new Error(\"invalid number of repeat node iteration count arguments defined\");\n }\n }\n\n // Grab any node attribute definitions and spread them into the node definition.\n node = { ...node, ...parseAttributeTokens(tokens, stringLiteralPlaceholders) };\n\n // This is a decorator node, so we expect an opening '{'.\n popAndCheck(tokens, \"{\");\n\n // Return the repeat node definition.\n return node;\n}\n\n/**\n * Creates a retry node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The retry node JSON definition.\n */\nfunction createRetryNode(tokens: string[], stringLiteralPlaceholders: StringLiteralPlaceholders): RetryNodeDefinition {\n let node = { type: \"retry\" } as RetryNodeDefinition;\n\n // Get the node arguments.\n const nodeArguments = parseArgumentTokens(tokens, stringLiteralPlaceholders);\n\n // The arguments of a retry node are optional. We may have:\n // - No node arguments, in which case the retry note will attempt indefinitely.\n // - One node argument which will be the explicit number of attempts to make.\n // - Two node arguments which define the min and max attempt bounds from which a random attempt count will be picked.\n if (nodeArguments.length) {\n // All retry node arguments MUST be of type number and must be integer.\n nodeArguments\n .filter((arg) => arg.type !== \"number\" || !arg.isInteger)\n .forEach(() => {\n throw new Error(`retry node attempt counts must be integer values`);\n });\n\n // We should have got one or two attempt counts.\n if (nodeArguments.length === 1) {\n // A static attempt count was defined.\n node.attempts = nodeArguments[0].value as number;\n\n // A retry node must have a positive number of attempts if defined.\n if (node.attempts < 0) {\n throw new Error(\"a retry node must have a positive number of attempts if defined\");\n }\n } else if (nodeArguments.length === 2) {\n // A minimum and maximum attempt count was defined.\n node.attempts = [nodeArguments[0].value as number, nodeArguments[1].value as number];\n\n // A retry node must have a positive min and max attempts count if they are defined.\n if (node.attempts[0] < 0 || node.attempts[1] < 0) {\n throw new Error(\"a retry node must have a positive minimum and maximum attempt count if defined\");\n }\n\n // A retry node must not have a minimum attempt count that exceeds the maximum attempt count.\n if (node.attempts[0] > node.attempts[1]) {\n throw new Error(\n \"a retry node must not have a minimum attempt count that exceeds the maximum attempt count\"\n );\n }\n } else {\n // An incorrect number of attempt counts was defined.\n throw new Error(\"invalid number of retry node attempt count arguments defined\");\n }\n }\n\n // Grab any node attribute definitions and spread them into the node definition.\n node = { ...node, ...parseAttributeTokens(tokens, stringLiteralPlaceholders) };\n\n // This is a decorator node, so we expect an opening '{'.\n popAndCheck(tokens, \"{\");\n\n // Return the retry node definition.\n return node;\n}\n\n/**\n * Creates a sequence node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The sequence node JSON definition.\n */\nfunction createSequenceNode(\n tokens: string[],\n stringLiteralPlaceholders: StringLiteralPlaceholders\n): SequenceNodeDefinition {\n const node = {\n type: \"sequence\",\n ...parseAttributeTokens(tokens, stringLiteralPlaceholders)\n } as SequenceNodeDefinition;\n\n // This is a composite node, so we expect an opening '{'.\n popAndCheck(tokens, \"{\");\n\n // Return the sequence node definition.\n return node;\n}\n\n/**\n * Creates a selector node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The selector node JSON definition.\n */\nfunction createSelectorNode(\n tokens: string[],\n stringLiteralPlaceholders: StringLiteralPlaceholders\n): SelectorNodeDefinition {\n const node = {\n type: \"selector\",\n ...parseAttributeTokens(tokens, stringLiteralPlaceholders)\n } as SelectorNodeDefinition;\n\n // This is a composite node, so we expect an opening '{'.\n popAndCheck(tokens, \"{\");\n\n // Return the selector node definition.\n return node;\n}\n\n/**\n * Creates a parallel node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The parallel node JSON definition.\n */\nfunction createParallelNode(\n tokens: string[],\n stringLiteralPlaceholders: StringLiteralPlaceholders\n): ParallelNodeDefinition {\n const node = {\n type: \"parallel\",\n ...parseAttributeTokens(tokens, stringLiteralPlaceholders)\n } as ParallelNodeDefinition;\n\n // This is a composite node, so we expect an opening '{'.\n popAndCheck(tokens, \"{\");\n\n // Return the parallel node definition.\n return node;\n}\n\n/**\n * Creates a lotto node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The lotto node JSON definition.\n */\nfunction createLottoNode(tokens: string[], stringLiteralPlaceholders: StringLiteralPlaceholders): LottoNodeDefinition {\n // If any node arguments have been defined then they must be our weights.\n const nodeArguments = parseArgumentTokens(tokens, stringLiteralPlaceholders);\n\n // All lotto node arguments MUST be of type number and must be positive integers.\n nodeArguments\n .filter((arg) => arg.type !== \"number\" || !arg.isInteger || arg.value < 0)\n .forEach(() => {\n throw new Error(`lotto node weight arguments must be positive integer values`);\n });\n\n const node = {\n type: \"lotto\",\n weights: nodeArguments.length ? nodeArguments.map(({ value }) => value) : undefined,\n ...parseAttributeTokens(tokens, stringLiteralPlaceholders)\n } as LottoNodeDefinition;\n\n // This is a composite node, so we expect an opening '{'.\n popAndCheck(tokens, \"{\");\n\n // Return the lotto node definition.\n return node;\n}\n\n/**\n * Creates an action node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The action node JSON definition.\n */\nfunction createActionNode(\n tokens: string[],\n stringLiteralPlaceholders: StringLiteralPlaceholders\n): ActionNodeDefinition {\n // Parse any node arguments, we should have at least one which will be an identifier argument for the action name\n // and agent function to invoke for the action, all other arguments are to be passed as arguments to that function.\n const [actionNameIdentifier, ...agentFunctionArgs] = parseArgumentTokens(tokens, stringLiteralPlaceholders);\n\n // Our first argument MUST be defined and be an identifier as we require an action name argument.\n if (actionNameIdentifier?.type !== \"identifier\") {\n throw new Error(\"expected action name identifier argument\");\n }\n\n // Only the first argument should have been an identifier, all agent function arguments must be string, number, boolean or null.\n agentFunctionArgs\n .filter((arg) => arg.type === \"identifier\")\n .forEach((arg) => {\n throw new Error(\n `invalid action node argument value '${arg.value}', must be string, number, boolean or null`\n );\n });\n\n // Return the action node definition.\n return {\n type: \"action\",\n call: actionNameIdentifier.value,\n args: agentFunctionArgs.map(({ value }) => value),\n ...parseAttributeTokens(tokens, stringLiteralPlaceholders)\n };\n}\n\n/**\n * Creates a condition node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The condition node JSON definition.\n */\nfunction createConditionNode(\n tokens: string[],\n stringLiteralPlaceholders: StringLiteralPlaceholders\n): ConditionNodeDefinition {\n // Parse any node arguments, we should have at least one which will be an identifier argument for the condition name\n // and agent function to invoke for the condition, all other arguments are to be passed as arguments to that function.\n const [conditionNameIdentifier, ...agentFunctionArgs] = parseArgumentTokens(tokens, stringLiteralPlaceholders);\n\n // Our first argument MUST be defined and be an identifier as we require a condition name argument.\n if (conditionNameIdentifier?.type !== \"identifier\") {\n throw new Error(\"expected condition name identifier argument\");\n }\n\n // Only the first argument should have been an identifier, all agent function arguments must be string, number, boolean or null.\n agentFunctionArgs\n .filter((arg) => arg.type === \"identifier\")\n .forEach((arg) => {\n throw new Error(\n `invalid condition node argument value '${arg.value}', must be string, number, boolean or null`\n );\n });\n\n // Return the condition node definition.\n return {\n type: \"condition\",\n call: conditionNameIdentifier.value,\n args: agentFunctionArgs.map(({ value }) => value),\n ...parseAttributeTokens(tokens, stringLiteralPlaceholders)\n };\n}\n\n/**\n * Creates a wait node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The wait node JSON definition.\n */\nfunction createWaitNode(tokens: string[], stringLiteralPlaceholders: StringLiteralPlaceholders): WaitNodeDefinition {\n let node = { type: \"wait\" } as WaitNodeDefinition;\n\n // Get the node arguments.\n const nodeArguments = parseArgumentTokens(tokens, stringLiteralPlaceholders);\n\n // The arguments of a wait node are optional. We may have:\n // - No node arguments, in which case the wait will be indefinite until it is aborted.\n // - One node argument which will be the explicit duration of the wait.\n // - Two node arguments which define the min and max duration bounds from which a random duration will be picked.\n if (nodeArguments.length) {\n // All wait node arguments MUST be of type number and must be integer.\n nodeArguments\n .filter((arg) => arg.type !== \"number\" || !arg.isInteger)\n .forEach(() => {\n throw new Error(`wait node durations must be integer values`);\n });\n\n // We may have:\n // - One node argument which will be the explicit duration of the wait.\n // - Two node arguments which define the min and max duration bounds from which a random duration will be picked.\n // - Too many arguments, which is not valid.\n if (nodeArguments.length === 1) {\n // An explicit duration was defined.\n node.duration = nodeArguments[0].value as number;\n\n // If an explict duration was defined then it must be a positive number.\n if (node.duration < 0) {\n throw new Error(\"a wait node must have a positive duration\");\n }\n } else if (nodeArguments.length === 2) {\n // Min and max duration bounds were defined from which a random duration will be picked.\n node.duration = [nodeArguments[0].value as number, nodeArguments[1].value as number];\n\n // A wait node must have a positive min and max duration.\n if (node.duration[0] < 0 || node.duration[1] < 0) {\n throw new Error(\"a wait node must have a positive minimum and maximum duration\");\n }\n\n // A wait node must not have a minimum duration that exceeds the maximum duration.\n if (node.duration[0] > node.duration[1]) {\n throw new Error(\"a wait node must not have a minimum duration that exceeds the maximum duration\");\n }\n } else if (nodeArguments.length > 2) {\n // An incorrect number of duration arguments were defined.\n throw new Error(\"invalid number of wait node duration arguments defined\");\n }\n }\n\n // Return the wait node definition.\n return { ...node, ...parseAttributeTokens(tokens, stringLiteralPlaceholders) };\n}\n\n/**\n * Creates a branch node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The branch node JSON definition.\n */\nfunction createBranchNode(\n tokens: string[],\n stringLiteralPlaceholders: StringLiteralPlaceholders\n): BranchNodeDefinition {\n // Parse any node arguments, we should have one which will be an identifier argument for the root ref.\n const nodeArguments = parseArgumentTokens(tokens, stringLiteralPlaceholders);\n\n // We should have only a single identifer argument for a branch node, which is the root ref.\n if (nodeArguments.length !== 1 || nodeArguments[0].type !== \"identifier\") {\n throw new Error(\"expected single branch name argument\");\n }\n\n // Return the branch node definition.\n return { type: \"branch\", ref: nodeArguments[0].value };\n}\n\n/**\n * Validate a fully-populated node definition that was popped off of the tree stack.\n * @param definition The popped node to validate.\n */\nfunction validatePoppedNode(definition: AnyNodeDefinition): void {\n // Decorators MUST have a child defined.\n if (isDecoratorNode(definition) && isNullOrUndefined(definition.child)) {\n throw new Error(`a ${definition.type} node must have a single child node defined`);\n }\n\n // Composites MUST have at least one child defined.\n if (isCompositeNode(definition) && !definition.children?.length) {\n throw new Error(`a ${definition.type} node must have at least a single child node defined`);\n }\n\n // We need to make sure that lotto nodes that have weights defined have a number of weights matching the number of child nodes.\n if (definition.type === \"lotto\") {\n // Check whether a 'weights' property has been defined, if it has we expect it to be an array of weights.\n if (typeof definition.weights !== \"undefined\") {\n // Check that the weights property is an array of positive integers with an element for each child node element.\n if (definition.weights.length !== definition.children.length) {\n throw new Error(\n \"expected a number of weight arguments matching the number of child nodes for lotto node\"\n );\n }\n }\n }\n}\n", "import { RootNodeDefinition } from \"./BehaviourTreeDefinition\";\nimport { flattenDefinition, isBranchNode, isInteger } from \"./BehaviourTreeDefinitionUtilities\";\nimport { convertMDSLToJSON } from \"./mdsl/MDSLDefinitionParser\";\n\n/**\n * An object representing the result of validating a tree definition.\n */\nexport type DefinitionValidationResult = {\n /**\n * A flag defining whether validation succeeded.\n */\n succeeded: boolean;\n /**\n * A string containing the error message if validation did not succeed.\n */\n errorMessage?: string;\n /**\n * The definition as json if the validation was successful, or undefined if validation did not succeed.\n */\n json?: RootNodeDefinition[];\n};\n\n/**\n * Validates the specified behaviour tree definition in the form of JSON or MDSL, not taking any globally registered subtrees into consideration.\n * @param definition The behaviour tree definition in the form of JSON or MDSL.\n * @returns An object representing the result of validating the given tree definition.\n */\nexport function validateDefinition(definition: any): DefinitionValidationResult {\n // The definition must be defined.\n if (definition === null || typeof definition === \"undefined\") {\n return createValidationFailureResult(\"definition is null or undefined\");\n }\n\n // We are expecting a definition in one of three different forms:\n // - A string which we will assume is MDSL and we will parse this to JSON before validation.\n // - An array which we will assume is an array of root node definitions with at least one being the primary root node (no 'id' property)\n // - An object which we will assume is the primary root node and should not have an 'id' property.\n if (typeof definition === \"string\") {\n // The definition is a string which we can assume is MDSL, so attempt to validate it.\n return validateMDSLDefinition(definition);\n } else if (typeof definition === \"object\") {\n // The definition will either be an array (of root node definitions) or an object (the single primary root node definition).\n return validateJSONDefinition(definition);\n } else {\n return createValidationFailureResult(`unexpected definition type of '${typeof definition}'`);\n }\n}\n\n/**\n * Validates the specified behaviour tree definition in the form of MDSL.\n * @param definition The behaviour tree definition in the form of MDSL.\n * @returns An object representing the result of validating the given tree definition.\n */\nfunction validateMDSLDefinition(definition: string): DefinitionValidationResult {\n let rootNodeDefinitions;\n\n // The first thing the we need to do is to attempt to convert our MDSL into JSON.\n try {\n // The definition is a string which we can assume is MDSL, so attempt to parse it to a JSON definition in the form of an array of root node definitions.\n rootNodeDefinitions = convertMDSLToJSON(definition);\n } catch (exception) {\n // We failed to parse the JSON from the MDSL, this is likely to be the result of it not being a valid MDSL string.\n return createValidationFailureResult((exception as Error).message);\n }\n\n // Unpack all of the root node definitions into arrays of main ('id' defined) and sub ('id' not defined) root node definitions.\n const mainRootNodeDefinitions = rootNodeDefinitions.filter(({ id }) => typeof id === \"undefined\");\n const subRootNodeDefinitions = rootNodeDefinitions.filter(({ id }) => typeof id === \"string\" && id.length > 0);\n\n // We should ALWAYS have exactly one root node definition without an 'id' property defined, which is out main root node definition.\n if (mainRootNodeDefinitions.length !== 1) {\n return createValidationFailureResult(\n \"expected single unnamed root node at base of definition to act as main root\"\n );\n }\n\n // We should never have duplicate 'id' properties across our sub root node definitions.\n const subRootNodeIdenitifers: string[] = [];\n for (const { id } of subRootNodeDefinitions) {\n // Have we already come across this 'id' property value?\n if (subRootNodeIdenitifers.includes(id!)) {\n return createValidationFailureResult(`multiple root nodes found with duplicate name '${id}'`);\n }\n\n subRootNodeIdenitifers.push(id!);\n }\n\n try {\n // Validate our branch -> subtree links and check for any circular dependencies, we don't care about checking for broken subtree links here.\n validateBranchSubtreeLinks(rootNodeDefinitions, false);\n } catch (exception) {\n return createValidationFailureResult((exception as Error).message);\n }\n\n // Our definition was valid!\n return {\n succeeded: true,\n json: rootNodeDefinitions\n };\n}\n\n/**\n * Validates the specified behaviour tree definition in the form of JSON.\n * @param definition The behaviour tree definition in the form of JSON.\n * @returns An object representing the result of validating the given tree definition.\n */\nexport function validateJSONDefinition(\n definition: RootNodeDefinition | RootNodeDefinition[]\n): DefinitionValidationResult {\n // The definition will either be an array (of root node definitions) or an object (the single primary root node definition).\n const rootNodeDefinitions = Array.isArray(definition) ? definition : [definition];\n\n // Iterate over our array of root nodes and call validateNode for each, passing an initial depth of 0, wrapped in a try catch to handle validation failures.\n try {\n rootNodeDefinitions.forEach((rootNodeDefinition) => validateNode(rootNodeDefinition, 0));\n } catch (error) {\n // Handle cases where we have caught a thrown Error and return a failure result with the error message.\n if (error instanceof Error) {\n return createValidationFailureResult(error.message);\n }\n\n // No idea what happened here!\n return createValidationFailureResult(`unexpected error: ${error}`);\n }\n\n // Unpack all of the root node definitions into arrays of main ('id' defined) and sub ('id' not defined) root node definitions.\n const mainRootNodeDefinitions = rootNodeDefinitions.filter(({ id }) => typeof id === \"undefined\");\n const subRootNodeDefinitions = rootNodeDefinitions.filter(({ id }) => typeof id === \"string\" && id.length > 0);\n\n // We should ALWAYS have exactly one root node definition without an 'id' property defined, which is out main root node definition.\n if (mainRootNodeDefinitions.length !== 1) {\n return createValidationFailureResult(\n \"expected single root node without 'id' property defined to act as main root\"\n );\n }\n\n // We should never have duplicate 'id' properties across our sub root node definitions.\n const subRootNodeIdenitifers: string[] = [];\n for (const { id } of subRootNodeDefinitions) {\n // Have we already come across this 'id' property value?\n if (subRootNodeIdenitifers.includes(id!)) {\n return createValidationFailureResult(\n `multiple root nodes found with duplicate 'id' property value of '${id}'`\n );\n }\n\n subRootNodeIdenitifers.push(id!);\n }\n\n try {\n // Validate our branch -> subtree links and check for any circular dependencies, we don't care about checking for broken subtree links here.\n validateBranchSubtreeLinks(rootNodeDefinitions, false);\n } catch (exception) {\n return createValidationFailureResult((exception as Error).message);\n }\n\n // Our definition was valid!\n return {\n succeeded: true,\n json: rootNodeDefinitions\n };\n}\n\n/**\n * Validates the branch -> subtree links across all provided root node definitions.\n * This will not consider branch nodes that reference any globally registered subtrees unless includesGlobalSubtrees\n * is set to true, in which case we will also verify that there are no broken branch -> subtree links.\n * @param rootNodeDefinitions The array of root node definitions.\n * @param includesGlobalSubtrees A flag defining whether the array includes all global subtree root node definitions.\n */\nexport function validateBranchSubtreeLinks(rootNodeDefinitions: RootNodeDefinition[], includesGlobalSubtrees: boolean) {\n // Create a mapping of root node identifiers to other root nodes that they reference via branch nodes.\n // Below is an example of a mapping that includes a circular dependency (root => a => b => c => a)\n // [{ refs: [\"a\", \"b\"] }, { id: \"a\", refs: [\"b\"] }, { id: \"b\", refs: [\"c\"] }, { id: \"c\", refs: [\"a\"] }]\n const rootNodeMappings: { id: string | undefined; refs: string[] }[] = rootNodeDefinitions.map(\n (rootNodeDefinition) => ({\n id: rootNodeDefinition.id,\n refs: flattenDefinition(rootNodeDefinition)\n .filter(isBranchNode)\n .map(({ ref }) => ref)\n })\n );\n\n // A recursive function to walk through the mappings, keeping track of which root nodes we have visited in the form of a path of root node identifiers.\n const followRefs = (mapping: { id: string | undefined; refs: string[] }, path: (string | undefined)[] = []) => {\n // Have we found a circular dependency?\n if (path.includes(mapping.id)) {\n // We found a circular dependency! Get the bad path of root node identifiers.\n const badPath = [...path, mapping.id];\n\n // Create the formatted path value. [undefined, \"a\", \"b\", \"c\", \"a\"] would be formatted as \"a -> b -> c -> a\".\n const badPathFormatted = badPath.filter((element) => !!element).join(\" => \");\n\n // No need to continue, we found a circular dependency.\n throw new Error(`circular dependency found in branch node references: ${badPathFormatted}`);\n }\n\n for (const ref of mapping.refs) {\n // Find the mapping for the root node with an identifer matching the current ref.\n const subMapping = rootNodeMappings.find(({ id }) => id === ref);\n\n // We may not have a mapping for this ref, which is normal when we aren't considering all globally registered subtrees.\n if (subMapping) {\n followRefs(subMapping, [...path, mapping.id]);\n } else if (includesGlobalSubtrees) {\n // We found a reference to a root node that doesn't exist, which is a problem seeing as the root node definitons includes all globally registered subtrees.\n throw new Error(\n mapping.id\n ? `subtree '${mapping.id}' has branch node that references root node '${ref}' which has not been defined`\n : `primary tree has branch node that references root node '${ref}' which has not been defined`\n );\n }\n }\n };\n\n // Start looking for circular dependencies and broken references from the primary root node definition.\n followRefs(rootNodeMappings.find((mapping) => typeof mapping.id === \"undefined\")!);\n}\n\n/**\n * Validate an object that we expect to be a node definition.\n * @param definition An object that we expect to be a node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateNode(definition: any, depth: number): void {\n // Every node must be valid object and have a non-empty 'type' string property.\n if (typeof definition !== \"object\" || typeof definition.type !== \"string\" || definition.type.length === 0) {\n throw new Error(\n `node definition is not an object or 'type' property is not a non-empty string at depth '${depth}'`\n );\n }\n\n // How we validate this node definition will depend on its type.\n switch (definition.type) {\n case \"action\":\n validateActionNode(definition, depth);\n break;\n\n case \"condition\":\n validateConditionNode(definition, depth);\n break;\n\n case \"wait\":\n validateWaitNode(definition, depth);\n break;\n\n case \"branch\":\n validateBranchNode(definition, depth);\n break;\n\n case \"root\":\n validateRootNode(definition, depth);\n break;\n\n case \"succeed\":\n validateSucceedNode(definition, depth);\n break;\n\n case \"fail\":\n validateFailNode(definition, depth);\n break;\n\n case \"flip\":\n validateFlipNode(definition, depth);\n break;\n\n case \"repeat\":\n validateRepeatNode(definition, depth);\n break;\n\n case \"retry\":\n validateRetryNode(definition, depth);\n break;\n\n case \"sequence\":\n validateSequenceNode(definition, depth);\n break;\n\n case \"selector\":\n validateSelectorNode(definition, depth);\n break;\n\n case \"parallel\":\n validateParallelNode(definition, depth);\n break;\n\n case \"lotto\":\n validateLottoNode(definition, depth);\n break;\n\n default:\n throw new Error(`unexpected node type of '${definition.type}' at depth '${depth}'`);\n }\n}\n\n/**\n * Validate any attributes for a given node definition.\n * @param definition The node definition.\n * @param depth The depth of the node in the behaviour tree definition.\n */\nfunction validateNodeAttributes(definition: any, depth: number): void {\n // Validate each of the attribute types for this node.\n [\"while\", \"until\", \"entry\", \"exit\", \"step\"].forEach((attributeName) => {\n // Attempt to grab the definition for the current attribute from the node definition.\n const attributeDefinition = definition[attributeName];\n\n // All node attributes are optional, so there is nothing to do if the current attribute is not defined.\n if (typeof attributeDefinition === \"undefined\") {\n return;\n }\n\n // The attribute definition must be an object.\n if (typeof attributeDefinition !== \"object\") {\n throw new Error(\n `expected attribute '${attributeName}' to be an object for '${definition.type}' node at depth '${depth}'`\n );\n }\n\n // The 'call' property must be defined for any attribute definition.\n if (typeof attributeDefinition.call !== \"string\" || attributeDefinition.call.length === 0) {\n throw new Error(\n `expected 'call' property for attribute '${attributeName}' to be a non-empty string for '${definition.type}' node at depth '${depth}'`\n );\n }\n\n // If any node attribute arguments have been defined then they must have been defined in an array.\n if (typeof attributeDefinition.args !== \"undefined\" && !Array.isArray(attributeDefinition.args)) {\n throw new Error(\n `expected 'args' property for attribute '${attributeName}' to be an array for '${definition.type}' node at depth '${depth}'`\n );\n }\n });\n}\n\n/**\n * Validate an object that we expect to be a root node definition.\n * @param definition An object that we expect to be a root node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateRootNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"root\") {\n throw new Error(\"expected node type of 'root' for root node\");\n }\n\n // A root node cannot be the child of another node.\n if (depth > 0) {\n throw new Error(\"a root node cannot be the child of another node\");\n }\n\n // Check that, if the root node 'id' property is defined, it is a non-empty string.\n if (typeof definition.id !== \"undefined\" && (typeof definition.id !== \"string\" || definition.id.length === 0)) {\n throw new Error(\"expected non-empty string for 'id' property if defined for root node\");\n }\n\n // A root node is a decorator node, so must have a child node defined.\n if (typeof definition.child === \"undefined\") {\n throw new Error(\"expected property 'child' to be defined for root node\");\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n\n // Validate the child node of this decorator node.\n validateNode(definition.child, depth + 1);\n}\n\n/**\n * Validate an object that we expect to be a succeed node definition.\n * @param definition An object that we expect to be a succeed node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateSucceedNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"succeed\") {\n throw new Error(`expected node type of 'succeed' for succeed node at depth '${depth}'`);\n }\n\n // A succeed node is a decorator node, so must have a child node defined.\n if (typeof definition.child === \"undefined\") {\n throw new Error(`expected property 'child' to be defined for succeed node at depth '${depth}'`);\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n\n // Validate the child node of this decorator node.\n validateNode(definition.child, depth + 1);\n}\n\n/**\n * Validate an object that we expect to be a fail node definition.\n * @param definition An object that we expect to be a fail node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateFailNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"fail\") {\n throw new Error(`expected node type of 'fail' for fail node at depth '${depth}'`);\n }\n\n // A fail node is a decorator node, so must have a child node defined.\n if (typeof definition.child === \"undefined\") {\n throw new Error(`expected property 'child' to be defined for fail node at depth '${depth}'`);\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n\n // Validate the child node of this decorator node.\n validateNode(definition.child, depth + 1);\n}\n\n/**\n * Validate an object that we expect to be a flip node definition.\n * @param definition An object that we expect to be a flip node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateFlipNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"flip\") {\n throw new Error(`expected node type of 'flip' for flip node at depth '${depth}'`);\n }\n\n // A flip node is a decorator node, so must have a child node defined.\n if (typeof definition.child === \"undefined\") {\n throw new Error(`expected property 'child' to be defined for flip node at depth '${depth}'`);\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n\n // Validate the child node of this decorator node.\n validateNode(definition.child, depth + 1);\n}\n\n/**\n * Validate an object that we expect to be a repeat node definition.\n * @param definition An object that we expect to be a repeat node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateRepeatNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"repeat\") {\n throw new Error(`expected node type of 'repeat' for repeat node at depth '${depth}'`);\n }\n\n // A repeat node is a decorator node, so must have a child node defined.\n if (typeof definition.child === \"undefined\") {\n throw new Error(`expected property 'child' to be defined for repeat node at depth '${depth}'`);\n }\n\n // Check whether an 'iterations' property has been defined, it may not have been if this node is to repeat indefinitely.\n if (typeof definition.iterations !== \"undefined\") {\n if (Array.isArray(definition.iterations)) {\n // Check whether any elements of the array are not integer values.\n const containsNonInteger = !!definition.iterations.filter((value: unknown) => !isInteger(value)).length;\n\n // If the 'iterations' property is an array then it MUST contain two integer values.\n if (definition.iterations.length !== 2 || containsNonInteger) {\n throw new Error(\n `expected array containing two integer values for 'iterations' property if defined for repeat node at depth '${depth}'`\n );\n }\n\n // A repeat node must have a positive min and max iterations count if they are defined.\n if (definition.iterations[0] < 0 || definition.iterations[1] < 0) {\n throw new Error(\n `expected positive minimum and maximum iterations count for 'iterations' property if defined for repeat node at depth '${depth}'`\n );\n }\n\n // A repeat node must not have a minimum iterations count that exceeds the maximum iterations count.\n if (definition.iterations[0] > definition.iterations[1]) {\n throw new Error(\n `expected minimum iterations count that does not exceed the maximum iterations count for 'iterations' property if defined for repeat node at depth '${depth}'`\n );\n }\n } else if (isInteger(definition.iterations)) {\n // A repeat node must have a positive number of iterations if defined.\n if (definition.iterations < 0) {\n throw new Error(\n `expected positive iterations count for 'iterations' property if defined for repeat node at depth '${depth}'`\n );\n }\n } else {\n throw new Error(\n `expected integer value or array containing two integer values for 'iterations' property if defined for repeat node at depth '${depth}'`\n );\n }\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n\n // Validate the child node of this decorator node.\n validateNode(definition.child, depth + 1);\n}\n\n/**\n * Validate an object that we expect to be a retry node definition.\n * @param definition An object that we expect to be a retry node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateRetryNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"retry\") {\n throw new Error(`expected node type of 'retry' for retry node at depth '${depth}'`);\n }\n\n // A retry node is a decorator node, so must have a child node defined.\n if (typeof definition.child === \"undefined\") {\n throw new Error(`expected property 'child' to be defined for retry node at depth '${depth}'`);\n }\n\n // Check whether an 'attempts' property has been defined, it may not have been if this node is to retry indefinitely.\n if (typeof definition.attempts !== \"undefined\") {\n if (Array.isArray(definition.attempts)) {\n // Check whether any elements of the array are not integer values.\n const containsNonInteger = !!definition.attempts.filter((value: unknown) => !isInteger(value)).length;\n\n // If the 'attempts' property is an array then it MUST contain two integer values.\n if (definition.attempts.length !== 2 || containsNonInteger) {\n throw new Error(\n `expected array containing two integer values for 'attempts' property if defined for retry node at depth '${depth}'`\n );\n }\n\n // A retry node must have a positive min and max attempts count if they are defined.\n if (definition.attempts[0] < 0 || definition.attempts[1] < 0) {\n throw new Error(\n `expected positive minimum and maximum attempts count for 'attempts' property if defined for retry node at depth '${depth}'`\n );\n }\n\n // A retry node must not have a minimum attempts count that exceeds the maximum attempts count.\n if (definition.attempts[0] > definition.attempts[1]) {\n throw new Error(\n `expected minimum attempts count that does not exceed the maximum attempts count for 'attempts' property if defined for retry node at depth '${depth}'`\n );\n }\n } else if (isInteger(definition.attempts)) {\n // A retry node must have a positive number of attempts if defined.\n if (definition.attempts < 0) {\n throw new Error(\n `expected positive attempts count for 'attempts' property if defined for retry node at depth '${depth}'`\n );\n }\n } else {\n throw new Error(\n `expected integer value or array containing two integer values for 'attempts' property if defined for retry node at depth '${depth}'`\n );\n }\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n\n // Validate the child node of this decorator node.\n validateNode(definition.child, depth + 1);\n}\n\n/**\n * Validate an object that we expect to be a branch node definition.\n * @param definition An object that we expect to be a branch node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateBranchNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"branch\") {\n throw new Error(`expected node type of 'branch' for branch node at depth '${depth}'`);\n }\n\n // Check that the branch node 'ref' property is defined and is a non-empty string.\n if (typeof definition.ref !== \"string\" || definition.ref.length === 0) {\n throw new Error(`expected non-empty string for 'ref' property for branch node at depth '${depth}'`);\n }\n\n // It is invalid to define guard attributes for a branch node as they should be defined on the referenced root node.\n [\"while\", \"until\"].forEach((attributeName) => {\n if (typeof definition[attributeName] !== \"undefined\") {\n throw new Error(\n `guards should not be defined for branch nodes but guard '${attributeName}' was defined for branch node at depth '${depth}'`\n );\n }\n });\n\n // It is invalid to define callback attributes for a branch node as they should be defined on the referenced root node.\n [\"entry\", \"exit\", \"step\"].forEach((attributeName) => {\n if (typeof definition[attributeName] !== \"undefined\") {\n throw new Error(\n `callbacks should not be defined for branch nodes but callback '${attributeName}' was defined for branch node at depth '${depth}'`\n );\n }\n });\n}\n\n/**\n * Validate an object that we expect to be a action node definition.\n * @param definition An object that we expect to be a action node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateActionNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"action\") {\n throw new Error(`expected node type of 'action' for action node at depth '${depth}'`);\n }\n\n // The 'call' property must be defined for a action node definition.\n if (typeof definition.call !== \"string\" || definition.call.length === 0) {\n throw new Error(`expected non-empty string for 'call' property of action node at depth '${depth}'`);\n }\n\n // If any action function arguments have been defined then they must have been defined in an array.\n if (typeof definition.args !== \"undefined\" && !Array.isArray(definition.args)) {\n throw new Error(`expected array for 'args' property if defined for action node at depth '${depth}'`);\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n}\n\n/**\n * Validate an object that we expect to be a condition node definition.\n * @param definition An object that we expect to be a condition node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateConditionNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"condition\") {\n throw new Error(`expected node type of 'condition' for condition node at depth '${depth}'`);\n }\n\n // The 'call' property must be defined for a condition node definition.\n if (typeof definition.call !== \"string\" || definition.call.length === 0) {\n throw new Error(`expected non-empty string for 'call' property of condition node at depth '${depth}'`);\n }\n\n // If any condition function arguments have been defined then they must have been defined in an array.\n if (typeof definition.args !== \"undefined\" && !Array.isArray(definition.args)) {\n throw new Error(`expected array for 'args' property if defined for condition node at depth '${depth}'`);\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n}\n\n/**\n * Validate an object that we expect to be a wait node definition.\n * @param definition An object that we expect to be a wait node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateWaitNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"wait\") {\n throw new Error(`expected node type of 'wait' for wait node at depth '${depth}'`);\n }\n\n // Check whether a 'duration' property has been defined, it may not have been if this node is to wait indefinitely.\n if (typeof definition.duration !== \"undefined\") {\n if (Array.isArray(definition.duration)) {\n // Check whether any elements of the array are not integer values.\n const containsNonInteger = !!definition.duration.filter((value: unknown) => !isInteger(value)).length;\n\n // If the 'duration' property is an array then it MUST contain two integer values.\n if (definition.duration.length !== 2 || containsNonInteger) {\n throw new Error(\n `expected array containing two integer values for 'duration' property if defined for wait node at depth '${depth}'`\n );\n }\n\n // A wait node must have a positive min and max duration value if they are defined.\n if (definition.duration[0] < 0 || definition.duration[1] < 0) {\n throw new Error(\n `expected positive minimum and maximum duration for 'duration' property if defined for wait node at depth '${depth}'`\n );\n }\n\n // A wait node must not have a minimum duration value that exceeds the maximum duration value.\n if (definition.duration[0] > definition.duration[1]) {\n throw new Error(\n `expected minimum duration value that does not exceed the maximum duration value for 'duration' property if defined for wait node at depth '${depth}'`\n );\n }\n } else if (isInteger(definition.duration)) {\n // A wait node must have a positive duration value if defined.\n if (definition.duration < 0) {\n throw new Error(\n `expected positive duration value for 'duration' property if defined for wait node at depth '${depth}'`\n );\n }\n } else {\n throw new Error(\n `expected integer value or array containing two integer values for 'duration' property if defined for wait node at depth '${depth}'`\n );\n }\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n}\n\n/**\n * Validate an object that we expect to be a sequence node definition.\n * @param definition An object that we expect to be a sequence node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateSequenceNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"sequence\") {\n throw new Error(`expected node type of 'sequence' for sequence node at depth '${depth}'`);\n }\n\n // A sequence node is a composite node, so must have a children nodes array defined.\n if (!Array.isArray(definition.children) || definition.children.length === 0) {\n throw new Error(`expected non-empty 'children' array to be defined for sequence node at depth '${depth}'`);\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n\n // Validate the child nodes of this composite node.\n definition.children.forEach((child: any) => validateNode(child, depth + 1));\n}\n\n/**\n * Validate an object that we expect to be a selector node definition.\n * @param definition An object that we expect to be a selector node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateSelectorNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"selector\") {\n throw new Error(`expected node type of 'selector' for selector node at depth '${depth}'`);\n }\n\n // A selector node is a composite node, so must have a children nodes array defined.\n if (!Array.isArray(definition.children) || definition.children.length === 0) {\n throw new Error(`expected non-empty 'children' array to be defined for selector node at depth '${depth}'`);\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n\n // Validate the child nodes of this composite node.\n definition.children.forEach((child: any) => validateNode(child, depth + 1));\n}\n\n/**\n * Validate an object that we expect to be a parallel node definition.\n * @param definition An object that we expect to be a parallel node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateParallelNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"parallel\") {\n throw new Error(`expected node type of 'parallel' for parallel node at depth '${depth}'`);\n }\n\n // A parallel node is a composite node, so must have a children nodes array defined.\n if (!Array.isArray(definition.children) || definition.children.length === 0) {\n throw new Error(`expected non-empty 'children' array to be defined for parallel node at depth '${depth}'`);\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n\n // Validate the child nodes of this composite node.\n definition.children.forEach((child: any) => validateNode(child, depth + 1));\n}\n\n/**\n * Validate an object that we expect to be a lotto node definition.\n * @param definition An object that we expect to be a lotto node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateLottoNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"lotto\") {\n throw new Error(`expected node type of 'lotto' for lotto node at depth '${depth}'`);\n }\n\n // A lotto node is a composite node, so must have a children nodes array defined.\n if (!Array.isArray(definition.children) || definition.children.length === 0) {\n throw new Error(`expected non-empty 'children' array to be defined for lotto node at depth '${depth}'`);\n }\n\n // Check whether a 'weights' property has been defined, if it has we expect it to be an array of weights.\n if (typeof definition.weights !== \"undefined\") {\n // Check that the weights property is an array of positive integers with an element for each child node element.\n if (\n !Array.isArray(definition.weights) ||\n definition.weights.length !== definition.children.length ||\n definition.weights.filter((value: unknown) => !isInteger(value)).length ||\n definition.weights.filter((value: number) => value < 0).length\n ) {\n throw new Error(\n `expected an array of positive integer weight values with a length matching the number of child nodes for 'weights' property if defined for lotto node at depth '${depth}'`\n );\n }\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n\n // Validate the child nodes of this composite node.\n definition.children.forEach((child: any) => validateNode(child, depth + 1));\n}\n\n/**\n * A helper function to create a failure validation result with the given error message.\n * @param errorMessage The validation failure error message.\n * @returns A failure validation result with the given error message.\n */\nfunction createValidationFailureResult(errorMessage: string): DefinitionValidationResult {\n return { succeeded: false, errorMessage };\n}\n", "import { ActionResult, Agent, GlobalFunction } from \"./Agent\";\nimport { RootNodeDefinition } from \"./BehaviourTreeDefinition\";\n\nexport type InvokerFunction = (args: any[]) => ActionResult;\n\n/**\n * A singleton used to store and lookup registered functions and subtrees.\n */\nexport default class Lookup {\n /**\n * The object holding any registered functions keyed on function name.\n */\n private static functionTable: { [key: string]: GlobalFunction } = {};\n /**\n * The object holding any registered subtree root node definitions keyed on tree name.\n */\n private static subtreeTable: { [key: string]: RootNodeDefinition } = {};\n\n /**\n * Gets the function with the specified name.\n * @param name The name of the function.\n * @returns The function with the specified name.\n */\n public static getFunc(name: string): GlobalFunction {\n return this.functionTable[name];\n }\n\n /**\n * Sets the function with the specified name for later lookup.\n * @param name The name of the function.\n * @param func The function.\n */\n public static setFunc(name: string, func: GlobalFunction): void {\n this.functionTable[name] = func;\n }\n\n /**\n * Gets the function invoker for the specified agent and function name.\n * If a function with the specified name exists on the agent object then it will\n * be returned, otherwise we will then check the registered functions for a match.\n * @param agent The agent instance that this behaviour tree is modelling behaviour for.\n * @param name The function name.\n * @returns The function invoker for the specified agent and function name.\n */\n static getFuncInvoker(agent: Agent, name: string): InvokerFunction | null {\n // Check whether the agent contains the specified function.\n const foundOnAgent = agent[name];\n if (foundOnAgent && typeof foundOnAgent === \"function\") {\n return (args: any[]): boolean | ActionResult => foundOnAgent.apply(agent, args);\n }\n\n // The agent does not contain the specified function but it may have been registered at some point.\n if (this.functionTable[name] && typeof this.functionTable[name] === \"function\") {\n return (args: any[]) => this.functionTable[name](agent, ...args.map((arg) => arg.value));\n }\n\n // We have no function to invoke.\n return null;\n }\n\n /**\n * Gets all registered subtree root node definitions.\n */\n static getSubtrees(): { [key: string]: RootNodeDefinition } {\n return this.subtreeTable;\n }\n\n /**\n * Sets the subtree with the specified name for later lookup.\n * @param name The name of the subtree.\n * @param subtree The subtree.\n */\n static setSubtree(name: string, subtree: RootNodeDefinition) {\n this.subtreeTable[name] = subtree;\n }\n\n /**\n * Removes the registered function or subtree with the specified name.\n * @param name The name of the registered function or subtree.\n */\n static remove(name: string) {\n delete this.functionTable[name];\n delete this.subtreeTable[name];\n }\n\n /**\n * Remove all registered functions and subtrees.\n */\n static empty() {\n this.functionTable = {};\n this.subtreeTable = {};\n }\n}\n", "import Node from \"../../nodes/Node\";\n\n/**\n * An exception thrown when evaluating node guard path conditions and a conditions fails.\n */\nexport default class GuardUnsatisifedException extends Error {\n /**\n * @param source The node at which a guard condition failed.\n */\n constructor(private source: Node) {\n super(\"A guard path condition has failed\");\n }\n\n /**\n * Gets whether the specified node is the node at which a guard condition failed.\n * @param node The node to check against the source node.\n * @returns Whether the specified node is the node at which a guard condition failed.\n */\n isSourceNode = (node: Node) => node === this.source;\n}\n", "import { Agent } from \"../../Agent\";\nimport Guard from \"./Guard\";\nimport Node from \"../../nodes/Node\";\nimport GuardUnsatisifedException from \"./GuardUnsatisifedException\";\n\nexport type GuardPathPart = {\n node: Node;\n guards: Guard[];\n};\n\n/**\n * Represents a path of node guards along a root-to-leaf tree path.\n */\nexport default class GuardPath {\n /**\n * @param nodes An array of objects defining a node instance -> guard link, ordered by node depth.\n */\n constructor(private nodes: GuardPathPart[]) {}\n\n /**\n * Evaluate guard conditions for all guards in the tree path, moving outwards from the root.\n * @param agent The agent, required for guard evaluation.\n * @returns An evaluation results object.\n */\n evaluate = (agent: Agent) => {\n // We need to evaluate guard conditions for nodes up the tree, moving outwards from the root.\n for (const details of this.nodes) {\n // There can be multiple guards per node.\n for (const guard of details.guards) {\n // Check whether the guard condition passes, and throw an exception if not.\n if (!guard.isSatisfied(agent)) {\n throw new GuardUnsatisifedException(details.node);\n }\n }\n }\n };\n}\n", "import { BehaviourTreeOptions } from \"../BehaviourTreeOptions\";\nimport State, { AnyState } from \"../State\";\nimport { Agent } from \"../Agent\";\nimport Leaf from \"./leaf/Leaf\";\nimport Attribute from \"../attributes/Attribute\";\nimport Entry from \"../attributes/callbacks/Entry\";\nimport Exit from \"../attributes/callbacks/Exit\";\nimport Step from \"../attributes/callbacks/Step\";\nimport Guard from \"../attributes/guards/Guard\";\nimport GuardPath from \"../attributes/guards/GuardPath\";\nimport GuardUnsatisifedException from \"../attributes/guards/GuardUnsatisifedException\";\n\n/**\n * A base node.\n */\nexport default abstract class Node {\n /**\n * The node uid.\n */\n private readonly uid: string = createNodeUid();\n /**\n * The node state.\n */\n private state: AnyState = State.READY;\n /**\n * The guard path to evaluate as part of a node update.\n */\n private guardPath: GuardPath | undefined;\n\n /**\n * @param type The node type.\n * @param attributes The node attributes.\n * @param args The node argument definitions.\n */\n constructor(private type: string, private attributes: Attribute[], private args: any[]) {}\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected abstract onUpdate(agent: Agent, options: BehaviourTreeOptions): void;\n\n /**\n * Gets the name of the node.\n */\n public abstract getName(): string;\n\n /**\n * Gets whether this node is a leaf node.\n */\n public abstract isLeafNode: () => this is Leaf;\n\n /**\n * Gets/Sets the state of the node.\n */\n getState = (): AnyState => this.state;\n setState = (value: AnyState): void => {\n this.state = value;\n };\n\n /**\n * Gets the unique id of the node.\n */\n getUid = () => this.uid;\n\n /**\n * Gets the type of the node.\n */\n getType = () => this.type;\n\n /**\n * Gets the node attributes.\n */\n getAttributes = () => this.attributes;\n\n /**\n * Gets the node arguments.\n */\n getArguments = () => this.args;\n\n /**\n * Gets the node attribute with the specified type, or null if it does not exist.\n */\n getAttribute(type: \"entry\" | \"ENTRY\"): Entry;\n getAttribute(type: \"exit\" | \"EXIT\"): Exit;\n getAttribute(type: \"step\" | \"STEP\"): Step;\n getAttribute(type: string): Attribute {\n return (\n this.getAttributes().filter((decorator) => decorator.type.toUpperCase() === type.toUpperCase())[0] || null\n );\n }\n\n /**\n * Gets the node attributes.\n */\n getGuardAttributes = (): Guard[] => this.getAttributes().filter((decorator) => decorator.isGuard()) as Guard[];\n\n /**\n * Sets the guard path to evaluate as part of a node update.\n */\n setGuardPath = (value: GuardPath) => (this.guardPath = value);\n\n /**\n * Gets whether a guard path is assigned to this node.\n */\n hasGuardPath = () => !!this.guardPath;\n\n /**\n * Gets whether this node is in the specified state.\n * @param value The value to compare to the node state.\n */\n public is(value: AnyState): boolean {\n return this.state === value;\n }\n\n /**\n * Reset the state of the node.\n */\n public reset(): void {\n this.setState(State.READY);\n }\n\n /**\n * Abort the running of this node.\n * @param agent The agent.\n */\n public abort(agent: Agent): void {\n // There is nothing to do if this node is not in the running state.\n if (!this.is(State.RUNNING)) {\n return;\n }\n\n // Reset the state of this node.\n this.reset();\n\n this.getAttribute(\"exit\")?.callAgentFunction(agent, false, true);\n }\n\n /**\n * Update the node.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n * @returns The result of the update.\n */\n public update(agent: Agent, options: BehaviourTreeOptions): void {\n // If this node is already in a 'SUCCEEDED' or 'FAILED' state then there is nothing to do.\n if (this.is(State.SUCCEEDED) || this.is(State.FAILED)) {\n return;\n }\n\n try {\n // Evaluate all of the guard path conditions for the current tree path.\n this.guardPath!.evaluate(agent);\n\n // If this node is in the READY state then call the ENTRY for this node if it exists.\n if (this.is(State.READY)) {\n this.getAttribute(\"entry\")?.callAgentFunction(agent);\n }\n\n this.getAttribute(\"step\")?.callAgentFunction(agent);\n\n // Do the actual update.\n this.onUpdate(agent, options);\n\n // If this node is now in a 'SUCCEEDED' or 'FAILED' state then call the EXIT for this node if it exists.\n if (this.is(State.SUCCEEDED) || this.is(State.FAILED)) {\n this.getAttribute(\"exit\")?.callAgentFunction(agent, this.is(State.SUCCEEDED), false);\n }\n } catch (error) {\n // If the error is a GuardUnsatisfiedException then we need to determine if this node is the source.\n if (error instanceof GuardUnsatisifedException && error.isSourceNode(this)) {\n // Abort the current node.\n this.abort(agent);\n\n // Any node that is the source of an abort will be a failed node.\n this.setState(State.FAILED);\n } else {\n throw error;\n }\n }\n }\n}\n\n/**\n * Create a randomly generated node uid.\n * @returns A randomly generated node uid.\n */\nfunction createNodeUid(): string {\n var S4 = function () {\n return (((1 + Math.random()) * 0x10000) | 0).toString(16).substring(1);\n };\n return S4() + S4() + \"-\" + S4() + \"-\" + S4() + \"-\" + S4() + \"-\" + S4() + S4() + S4();\n}\n", "import Node from \"../Node\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\n\n/**\n * A composite node that wraps child nodes.\n */\nexport default abstract class Composite extends Node {\n /**\n * @param type The node type.\n * @param attributes The node attributes.\n * @param children The child nodes.\n */\n constructor(type: string, attributes: Attribute[], protected children: Node[]) {\n super(type, attributes, []);\n }\n\n /**\n * Gets whether this node is a leaf node.\n */\n isLeafNode = () => false;\n\n /**\n * Gets the children of this node.\n */\n getChildren = () => this.children;\n\n /**\n * Reset the state of the node.\n */\n reset = () => {\n // Reset the state of this node.\n this.setState(State.READY);\n\n // Reset the state of any child nodes.\n this.getChildren().forEach((child) => child.reset());\n };\n\n /**\n * Abort the running of this node.\n * @param agent The agent.\n */\n abort = (agent: Agent) => {\n // There is nothing to do if this node is not in the running state.\n if (!this.is(State.RUNNING)) {\n return;\n }\n\n // Abort any child nodes.\n this.getChildren().forEach((child) => child.abort(agent));\n\n // Reset the state of this node.\n this.reset();\n\n this.getAttribute(\"exit\")?.callAgentFunction(agent, false, true);\n };\n}\n", "import Composite from \"./Composite\";\nimport State from \"../../State\";\nimport Node from \"../Node\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A PARALLEL node.\n * The child nodes are executed concurrently until one fails or all succeed.\n */\nexport default class Parallel extends Composite {\n /**\n * @param attributes The node attributes.\n * @param children The child nodes.\n */\n constructor(attributes: Attribute[], children: Node[]) {\n super(\"parallel\", attributes, children);\n }\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // Keep a count of the number of succeeded child nodes.\n let succeededCount = 0;\n\n let hasChildFailed = false;\n\n // Iterate over all of the children of this node.\n for (const child of this.children) {\n // If the child has never been updated or is running then we will need to update it now.\n if (child.getState() === State.READY || child.getState() === State.RUNNING) {\n // Update the child of this node.\n child.update(agent, options);\n }\n\n // If the current child has a state of 'SUCCEEDED' then we should move on to the next child.\n if (child.getState() === State.SUCCEEDED) {\n // The child node has succeeded, keep track of this to determine if all children have.\n succeededCount++;\n\n // The child node succeeded, but we have not finished checking every child node yet.\n continue;\n }\n\n // If the current child has a state of 'FAILED' then this node is also a 'FAILED' node.\n if (child.getState() === State.FAILED) {\n hasChildFailed = true;\n\n // There is no need to check the rest of the children.\n break;\n }\n\n // The node should be in the 'RUNNING' state.\n if (child.getState() !== State.RUNNING) {\n // The child node was not in an expected state.\n throw new Error(\"child node was not in an expected state.\");\n }\n }\n\n if (hasChildFailed) {\n // This node is a 'FAILED' node.\n this.setState(State.FAILED);\n\n // Abort every running child.\n for (const child of this.children) {\n if (child.getState() === State.RUNNING) {\n child.abort(agent);\n }\n }\n } else {\n // If all children have succeeded then this node has also succeeded, otherwise it is still running.\n this.setState(succeededCount === this.children.length ? State.SUCCEEDED : State.RUNNING);\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => \"PARALLEL\";\n}\n", "import Composite from \"./Composite\";\nimport Node from \"../Node\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A SELECTOR node.\n * The child nodes are executed in sequence until one succeeds or all fail.\n */\nexport default class Selector extends Composite {\n /**\n * @param attributes The node attributes.\n * @param children The child nodes.\n */\n constructor(attributes: Attribute[], protected children: Node[]) {\n super(\"selector\", attributes, children);\n }\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // Iterate over all of the children of this node.\n for (const child of this.children) {\n // If the child has never been updated or is running then we will need to update it now.\n if (child.getState() === State.READY || child.getState() === State.RUNNING) {\n // Update the child of this node.\n child.update(agent, options);\n }\n\n // If the current child has a state of 'SUCCEEDED' then this node is also a 'SUCCEEDED' node.\n if (child.getState() === State.SUCCEEDED) {\n // This node is a 'SUCCEEDED' node.\n this.setState(State.SUCCEEDED);\n\n // There is no need to check the rest of the selector nodes.\n return;\n }\n\n // If the current child has a state of 'FAILED' then we should move on to the next child.\n if (child.getState() === State.FAILED) {\n // Find out if the current child is the last one in the selector.\n // If it is then this sequence node has also failed.\n if (this.children.indexOf(child) === this.children.length - 1) {\n // This node is a 'FAILED' node.\n this.setState(State.FAILED);\n\n // There is no need to check the rest of the selector as we have completed it.\n return;\n } else {\n // The child node failed, try the next one.\n continue;\n }\n }\n\n // The node should be in the 'RUNNING' state.\n if (child.getState() === State.RUNNING) {\n // This node is a 'RUNNING' node.\n this.setState(State.RUNNING);\n\n // There is no need to check the rest of the selector as the current child is still running.\n return;\n }\n\n // The child node was not in an expected state.\n throw new Error(\"child node was not in an expected state.\");\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => \"SELECTOR\";\n}\n", "import Composite from \"./Composite\";\nimport Node from \"../Node\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A SEQUENCE node.\n * The child nodes are executed in sequence until one fails or all succeed.\n */\nexport default class Sequence extends Composite {\n /**\n * @param attributes The node attributes.\n * @param children The child nodes.\n */\n constructor(attributes: Attribute[], protected children: Node[]) {\n super(\"sequence\", attributes, children);\n }\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // Iterate over all of the children of this node.\n for (const child of this.children) {\n // If the child has never been updated or is running then we will need to update it now.\n if (child.getState() === State.READY || child.getState() === State.RUNNING) {\n // Update the child of this node.\n child.update(agent, options);\n }\n\n // If the current child has a state of 'SUCCEEDED' then we should move on to the next child.\n if (child.getState() === State.SUCCEEDED) {\n // Find out if the current child is the last one in the sequence.\n // If it is then this sequence node has also succeeded.\n if (this.children.indexOf(child) === this.children.length - 1) {\n // This node is a 'SUCCEEDED' node.\n this.setState(State.SUCCEEDED);\n\n // There is no need to check the rest of the sequence as we have completed it.\n return;\n } else {\n // The child node succeeded, but we have not finished the sequence yet.\n continue;\n }\n }\n\n // If the current child has a state of 'FAILED' then this node is also a 'FAILED' node.\n if (child.getState() === State.FAILED) {\n // This node is a 'FAILED' node.\n this.setState(State.FAILED);\n\n // There is no need to check the rest of the sequence.\n return;\n }\n\n // The node should be in the 'RUNNING' state.\n if (child.getState() === State.RUNNING) {\n // This node is a 'RUNNING' node.\n this.setState(State.RUNNING);\n\n // There is no need to check the rest of the sequence as the current child is still running.\n return;\n }\n\n // The child node was not in an expected state.\n throw new Error(\"child node was not in an expected state.\");\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => \"SEQUENCE\";\n}\n", "import createLotto from \"lotto-draw\";\n\nimport Node from \"../Node\";\nimport Composite from \"./Composite\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A LOTTO node.\n * A winning child is picked on the initial update of this node, based on ticket weighting.\n * The state of this node will match the state of the winning child.\n */\nexport default class Lotto extends Composite {\n /**\n * @param attributes The node attributes.\n * @param weights The child node weights.\n * @param children The child nodes.\n */\n constructor(attributes: Attribute[], private weights: number[] | undefined, children: Node[]) {\n super(\"lotto\", attributes, children);\n }\n\n /**\n * The child node selected to be the active one.\n */\n private selectedChild: Node | undefined;\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // If this node is in the READY state then we need to pick a winning child node.\n if (this.is(State.READY)) {\n // Create a lotto draw with which to randomly pick a child node to become the active one.\n const lottoDraw = createLotto({\n // Hook up the optional 'random' behaviour tree function option to the one used by 'lotto-draw'.\n random: options.random,\n // Pass in each child node as a participant in the lotto draw with their respective ticket count.\n participants: this.children.map((child, index) => [child, this.weights?.[index] || 1])\n });\n\n // Randomly pick a child based on ticket weighting, this will become the active child for this composite node.\n this.selectedChild = lottoDraw.draw() || undefined;\n }\n\n // If something went wrong and we don't have an active child then we should throw an error.\n if (!this.selectedChild) {\n throw new Error(\"failed to update lotto node as it has no active child\");\n }\n\n // If the selected child has never been updated or is running then we will need to update it now.\n if (this.selectedChild.getState() === State.READY || this.selectedChild.getState() === State.RUNNING) {\n this.selectedChild.update(agent, options);\n }\n\n // The state of the lotto node is the state of its selected child.\n this.setState(this.selectedChild.getState());\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => (this.weights ? `LOTTO [${this.weights.join(\",\")}]` : \"LOTTO\");\n}\n", "import Node from \"../Node\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\n\n/**\n * A decorator node that wraps a single child node.\n */\nexport default abstract class Decorator extends Node {\n /**\n * @param type The node type.\n * @param attributes The node attributes.\n * @param child The child node.\n */\n constructor(type: string, attributes: Attribute[], protected child: Node) {\n super(type, attributes, []);\n }\n\n /**\n * Gets whether this node is a leaf node.\n */\n isLeafNode = () => false;\n\n /**\n * Gets the children of this node.\n */\n getChildren = () => [this.child];\n\n /**\n * Reset the state of the node.\n */\n reset = () => {\n // Reset the state of this node.\n this.setState(State.READY);\n\n // Reset the state of the child node.\n this.child.reset();\n };\n\n /**\n * Abort the running of this node.\n * @param agent The agent.\n */\n abort = (agent: Agent) => {\n // There is nothing to do if this node is not in the running state.\n if (!this.is(State.RUNNING)) {\n return;\n }\n\n // Abort the child node.\n this.child.abort(agent);\n\n // Reset the state of this node.\n this.reset();\n\n this.getAttribute(\"exit\")?.callAgentFunction(agent, false, true);\n };\n}\n", "import Node from \"../Node\";\nimport Decorator from \"./Decorator\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A Fail node.\n * This node wraps a single child and will always move to the 'FAILED' state when the child moves to a 'SUCCEEDED' or 'FAILED' state.\n */\nexport default class Fail extends Decorator {\n /**\n * @param attributes The node attributes.\n * @param child The child node.\n */\n constructor(attributes: Attribute[], child: Node) {\n super(\"fail\", attributes, child);\n }\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // If the child has never been updated or is running then we will need to update it now.\n if (this.child.getState() === State.READY || this.child.getState() === State.RUNNING) {\n this.child.update(agent, options);\n }\n\n // The state of this node will depend in the state of its child.\n switch (this.child.getState()) {\n case State.RUNNING:\n this.setState(State.RUNNING);\n break;\n\n case State.SUCCEEDED:\n case State.FAILED:\n this.setState(State.FAILED);\n break;\n\n default:\n this.setState(State.READY);\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => \"FAIL\";\n}\n", "import Decorator from \"./Decorator\";\nimport State from \"../../State\";\nimport Node from \"../Node\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A Flip node.\n * This node wraps a single child and will flip the state of the child state.\n */\nexport default class Flip extends Decorator {\n /**\n * @param attributes The node attributes.\n * @param child The child node.\n */\n constructor(attributes: Attribute[], child: Node) {\n super(\"flip\", attributes, child);\n }\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // If the child has never been updated or is running then we will need to update it now.\n if (this.child.getState() === State.READY || this.child.getState() === State.RUNNING) {\n this.child.update(agent, options);\n }\n\n // The state of this node will depend in the state of its child.\n switch (this.child.getState()) {\n case State.RUNNING:\n this.setState(State.RUNNING);\n break;\n\n case State.SUCCEEDED:\n this.setState(State.FAILED);\n break;\n\n case State.FAILED:\n this.setState(State.SUCCEEDED);\n break;\n\n default:\n this.setState(State.READY);\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => \"FLIP\";\n}\n", "import Node from \"../Node\";\nimport Decorator from \"./Decorator\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A REPEAT node.\n * The node has a single child which can have:\n * -- A number of iterations for which to repeat the child node.\n * -- An infinite repeat loop if neither an iteration count or a condition function is defined.\n * The REPEAT node will stop and have a 'FAILED' state if its child is ever in a 'FAILED' state after an update.\n * The REPEAT node will attempt to move on to the next iteration if its child is ever in a 'SUCCEEDED' state.\n */\nexport default class Repeat extends Decorator {\n /**\n * @param attributes The node attributes.\n * @param iterations The number of iterations to repeat the child node.\n * @param iterationsMin The minimum possible number of iterations to repeat the child node.\n * @param iterationsMax The maximum possible number of iterations to repeat the child node.\n * @param child The child node.\n */\n constructor(\n attributes: Attribute[],\n private iterations: number | null,\n private iterationsMin: number | null,\n private iterationsMax: number | null,\n child: Node\n ) {\n super(\"repeat\", attributes, child);\n }\n\n /**\n * The number of target iterations to make.\n */\n private targetIterationCount: number | null = null;\n\n /**\n * The current iteration count.\n */\n private currentIterationCount: number = 0;\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // If this node is in the READY state then we need to reset the child and the target iteration count.\n if (this.is(State.READY)) {\n // Reset the child node.\n this.child.reset();\n\n // Reset the current iteration count.\n this.currentIterationCount = 0;\n\n // Set the target iteration count.\n this.setTargetIterationCount(options);\n }\n\n // Do a check to see if we can iterate. If we can then this node will move into the 'RUNNING' state.\n // If we cannot iterate then we have hit our target iteration count, which means that the node has succeeded.\n if (this.canIterate()) {\n // This node is in the running state and can do its initial iteration.\n this.setState(State.RUNNING);\n\n // We may have already completed an iteration, meaning that the child node will be in the SUCCEEDED state.\n // If this is the case then we will have to reset the child node now.\n if (this.child.getState() === State.SUCCEEDED) {\n this.child.reset();\n }\n\n // Update the child of this node.\n this.child.update(agent, options);\n\n // If the child moved into the FAILED state when we updated it then there is nothing left to do and this node has also failed.\n // If it has moved into the SUCCEEDED state then we have completed the current iteration.\n if (this.child.getState() === State.FAILED) {\n // The child has failed, meaning that this node has failed.\n this.setState(State.FAILED);\n\n return;\n } else if (this.child.getState() === State.SUCCEEDED) {\n // We have completed an iteration.\n this.currentIterationCount += 1;\n }\n } else {\n // This node is in the 'SUCCEEDED' state as we cannot iterate any more.\n this.setState(State.SUCCEEDED);\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => {\n if (this.iterations !== null) {\n return `REPEAT ${this.iterations}x`;\n } else if (this.iterationsMin !== null && this.iterationsMax !== null) {\n return `REPEAT ${this.iterationsMin}x-${this.iterationsMax}x`;\n } else {\n return \"REPEAT\";\n }\n };\n\n /**\n * Reset the state of the node.\n */\n reset = () => {\n // Reset the state of this node.\n this.setState(State.READY);\n\n // Reset the current iteration count.\n this.currentIterationCount = 0;\n\n // Reset the child node.\n this.child.reset();\n };\n\n /**\n * Gets whether an iteration can be made.\n * @returns Whether an iteration can be made.\n */\n private canIterate = () => {\n if (this.targetIterationCount !== null) {\n // We can iterate as long as we have not reached our target iteration count.\n return this.currentIterationCount < this.targetIterationCount;\n }\n\n // If neither an iteration count or a condition function were defined then we can iterate indefinitely.\n return true;\n };\n\n /**\n * Sets the target iteration count.\n * @param options The behaviour tree options object.\n */\n private setTargetIterationCount = (options: BehaviourTreeOptions) => {\n // Are we dealing with an explicit iteration count or will we be randomly picking a iteration count between the min and max iteration count.\n if (this.iterations !== null) {\n this.targetIterationCount = this.iterations;\n } else if (this.iterationsMin !== null && this.iterationsMax !== null) {\n // We will be picking a random iteration count between a min and max iteration count, if the optional 'random'\n // behaviour tree function option is defined then we will be using that, otherwise we will fall back to using Math.random.\n const random = typeof options.random === \"function\" ? options.random : Math.random;\n\n // Pick a random iteration count between a min and max iteration count.\n this.targetIterationCount = Math.floor(\n random() * (this.iterationsMax - this.iterationsMin + 1) + this.iterationsMin\n );\n } else {\n this.targetIterationCount = null;\n }\n };\n}\n", "import Node from \"../Node\";\nimport Decorator from \"./Decorator\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A RETRY node.\n * The node has a single child which can have:\n * -- A number of iterations for which to repeat the child node.\n * -- An infinite repeat loop if neither an iteration count or a condition function is defined.\n * The RETRY node will stop and have a 'SUCCEEDED' state if its child is ever in a 'SUCCEEDED' state after an update.\n * The RETRY node will attempt to move on to the next iteration if its child is ever in a 'FAILED' state.\n */\nexport default class Retry extends Decorator {\n /**\n * @param attributes The node attributes.\n * @param attempts The number of attempts to retry the child node.\n * @param attemptsMin The minimum possible number of attempts to retry the child node.\n * @param attemptsMax The maximum possible number of attempts to retry the child node.\n * @param child The child node.\n */\n constructor(\n attributes: Attribute[],\n private attempts: number | null,\n private attemptsMin: number | null,\n private attemptsMax: number | null,\n child: Node\n ) {\n super(\"retry\", attributes, child);\n }\n\n /**\n * The number of target attempts to make.\n */\n private targetAttemptCount: number | null = null;\n\n /**\n * The current attempt count.\n */\n private currentAttemptCount: number = 0;\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // If this node is in the READY state then we need to reset the child and the target attempt count.\n if (this.is(State.READY)) {\n // Reset the child node.\n this.child.reset();\n\n // Reset the current attempt count.\n this.currentAttemptCount = 0;\n\n // Set the target attempt count.\n this.setTargetAttemptCount(options);\n }\n\n // Do a check to see if we can attempt. If we can then this node will move into the 'RUNNING' state.\n // If we cannot attempt then we have hit our target attempt count, which means that the node has succeeded.\n if (this.canAttempt()) {\n // This node is in the running state and can do its initial attempt.\n this.setState(State.RUNNING);\n\n // We may have already completed an attempt, meaning that the child node will be in the FAILED state.\n // If this is the case then we will have to reset the child node now.\n if (this.child.getState() === State.FAILED) {\n this.child.reset();\n }\n\n // Update the child of this node.\n this.child.update(agent, options);\n\n // If the child moved into the SUCCEEDED state when we updated it then there is nothing left to do and this node has also succeeded.\n // If it has moved into the FAILED state then we have completed the current attempt.\n if (this.child.getState() === State.SUCCEEDED) {\n // The child has succeeded, meaning that this node has succeeded.\n this.setState(State.SUCCEEDED);\n\n return;\n } else if (this.child.getState() === State.FAILED) {\n // We have completed an attempt.\n this.currentAttemptCount += 1;\n }\n } else {\n // This node is in the 'FAILED' state as we cannot iterate any more.\n this.setState(State.FAILED);\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => {\n if (this.attempts !== null) {\n return `RETRY ${this.attempts}x`;\n } else if (this.attemptsMin !== null && this.attemptsMax !== null) {\n return `RETRY ${this.attemptsMin}x-${this.attemptsMax}x`;\n } else {\n return \"RETRY\";\n }\n };\n\n /**\n * Reset the state of the node.\n */\n reset = () => {\n // Reset the state of this node.\n this.setState(State.READY);\n\n // Reset the current attempt count.\n this.currentAttemptCount = 0;\n\n // Reset the child node.\n this.child.reset();\n };\n\n /**\n * Gets whether an attempt can be made.\n * @returns Whether an attempt can be made.\n */\n canAttempt = () => {\n if (this.targetAttemptCount !== null) {\n // We can attempt as long as we have not reached our target attempt count.\n return this.currentAttemptCount < this.targetAttemptCount;\n }\n\n // If neither an attempt count or a condition function were defined then we can attempt indefinitely.\n return true;\n };\n\n /**\n * Sets the target attempt count.\n * @param options The behaviour tree options object.\n */\n setTargetAttemptCount = (options: BehaviourTreeOptions) => {\n // Are we dealing with an explicit attempt count or will we be randomly picking an attempt count between the min and max attempt count.\n if (this.attempts !== null) {\n this.targetAttemptCount = this.attempts;\n } else if (this.attemptsMin !== null && this.attemptsMax !== null) {\n // We will be picking a random attempt count between a min and max attempt count, if the optional 'random'\n // behaviour tree function option is defined then we will be using that, otherwise we will fall back to using Math.random.\n const random = typeof options.random === \"function\" ? options.random : Math.random;\n\n // Pick a random attempt count between a min and max attempt count.\n this.targetAttemptCount = Math.floor(\n random() * (this.attemptsMax - this.attemptsMin + 1) + this.attemptsMin\n );\n } else {\n this.targetAttemptCount = null;\n }\n };\n}\n", "import Node from \"../Node\";\nimport Decorator from \"./Decorator\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A Root node.\n * The root node will have a single child.\n */\nexport default class Root extends Decorator {\n /**\n * @param attributes The node attributes.\n * @param child The child node.\n */\n constructor(attributes: Attribute[], child: Node) {\n super(\"root\", attributes, child);\n }\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // If the child has never been updated or is running then we will need to update it now.\n if (this.child.getState() === State.READY || this.child.getState() === State.RUNNING) {\n // Update the child of this node.\n this.child.update(agent, options);\n }\n\n // The state of the root node is the state of its child.\n this.setState(this.child.getState());\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => \"ROOT\";\n}\n", "import Node from \"../Node\";\nimport Decorator from \"./Decorator\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A Succeed node.\n * This node wraps a single child and will always move to the 'SUCCEEDED' state when the child moves to a 'SUCCEEDED' or 'FAILED' state.\n */\nexport default class Succeed extends Decorator {\n /**\n * @param attributes The node attributes.\n * @param child The child node.\n */\n constructor(attributes: Attribute[], child: Node) {\n super(\"succeed\", attributes, child);\n }\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // If the child has never been updated or is running then we will need to update it now.\n if (this.child.getState() === State.READY || this.child.getState() === State.RUNNING) {\n this.child.update(agent, options);\n }\n\n // The state of this node will depend in the state of its child.\n switch (this.child.getState()) {\n case State.RUNNING:\n this.setState(State.RUNNING);\n break;\n\n case State.SUCCEEDED:\n case State.FAILED:\n this.setState(State.SUCCEEDED);\n break;\n\n default:\n this.setState(State.READY);\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => \"SUCCEED\";\n}\n", "import Node from \"../Node\";\n\n/**\n * A leaf node.\n */\nexport default abstract class Leaf extends Node {\n /**\n * Gets whether this node is a leaf node.\n */\n isLeafNode = () => true;\n}\n", "import { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\nimport State, { CompleteState } from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Leaf from \"./Leaf\";\nimport Lookup from \"../../Lookup\";\nimport Attribute from \"../../attributes/Attribute\";\n\n/**\n * An Action leaf node.\n * This represents an immediate or ongoing state of behaviour.\n */\nexport default class Action extends Leaf {\n /**\n * @param attributes The node attributes.\n * @param actionName The action name.\n * @param actionArguments The array of action argument definitions.\n */\n constructor(attributes: Attribute[], private actionName: string, private actionArguments: any[]) {\n super(\"action\", attributes, actionArguments);\n }\n\n /**\n * Whether there is a pending update promise.\n */\n private isUsingUpdatePromise = false;\n\n /**\n * The finished state result of an update promise.\n */\n private updatePromiseStateResult: CompleteState | null = null;\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // If the result of this action depends on an update promise then there is nothing to do until\n // it resolves, unless there has been a value set as a result of the update promise resolving.\n if (this.isUsingUpdatePromise) {\n // Check whether the update promise has resolved with a state value.\n if (this.updatePromiseStateResult) {\n // Set the state of this node to match the state returned by the promise.\n this.setState(this.updatePromiseStateResult);\n }\n\n return;\n }\n\n // Attempt to get the invoker for the action function.\n const actionFuncInvoker = Lookup.getFuncInvoker(agent, this.actionName);\n\n // The action function should be defined.\n if (actionFuncInvoker === null) {\n throw new Error(\n `cannot update action node as the action '${this.actionName}' function is not defined on the agent and has not been registered`\n );\n }\n\n // Call the action function, the result of which may be:\n // - The finished state of this action node.\n // - A promise to return a finished node state.\n // - Undefined if the node should remain in the running state.\n const updateResult = actionFuncInvoker(this.actionArguments) as CompleteState | Promise;\n\n if (updateResult instanceof Promise) {\n updateResult.then(\n (result) => {\n // If 'isUpdatePromisePending' is null then the promise was cleared as it was resolving, probably via an abort of reset.\n if (!this.isUsingUpdatePromise) {\n return;\n }\n\n // Check to make sure the result is a valid finished state.\n if (result !== State.SUCCEEDED && result !== State.FAILED) {\n throw new Error(\n \"action node promise resolved with an invalid value, expected a State.SUCCEEDED or State.FAILED value to be returned\"\n );\n }\n\n // Set pending update promise state result to be processed on next update.\n this.updatePromiseStateResult = result;\n },\n (reason) => {\n // If 'isUpdatePromisePending' is null then the promise was cleared as it was resolving, probably via an abort of reset.\n if (!this.isUsingUpdatePromise) {\n return;\n }\n\n // Just throw whatever was returned as the rejection argument.\n throw new Error(reason);\n }\n );\n\n // This node will be in the 'RUNNING' state until the update promise resolves.\n this.setState(State.RUNNING);\n\n // We are now waiting for the promise returned by the use to resolve before we know what state this node is in.\n this.isUsingUpdatePromise = true;\n } else {\n // Validate the returned value.\n this.validateUpdateResult(updateResult);\n\n // Set the state of this node, this may be undefined, which just means that the node is still in the 'RUNNING' state.\n this.setState(updateResult || State.RUNNING);\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => this.actionName;\n\n /**\n * Reset the state of the node.\n */\n reset = () => {\n // Reset the state of this node.\n this.setState(State.READY);\n\n // There is no longer an update promise that we care about.\n this.isUsingUpdatePromise = false;\n this.updatePromiseStateResult = null;\n };\n\n /**\n * Validate the result of an update function call.\n * @param result The result of an update function call.\n */\n private validateUpdateResult = (result: CompleteState | boolean) => {\n switch (result) {\n case State.SUCCEEDED:\n case State.FAILED:\n case undefined:\n return;\n default:\n throw new Error(\n `action '${this.actionName}' 'onUpdate' returned an invalid response, expected an optional State.SUCCEEDED or State.FAILED value to be returned`\n );\n }\n };\n}\n", "import { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Leaf from \"./Leaf\";\nimport Lookup from \"../../Lookup\";\nimport Attribute from \"../../attributes/Attribute\";\n\n/**\n * A Condition leaf node.\n * This will succeed or fail immediately based on an agent predicate, without moving to the 'RUNNING' state.\n */\nexport default class Condition extends Leaf {\n /**\n * @param attributes The node attributes.\n * @param conditionName The name of the condition function.\n * @param conditionArguments The array of condition argument definitions.\n */\n constructor(attributes: Attribute[], private conditionName: string, private conditionArguments: any[]) {\n super(\"condition\", attributes, conditionArguments);\n }\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // Attempt to get the invoker for the condition function.\n const conditionFuncInvoker = Lookup.getFuncInvoker(agent, this.conditionName);\n\n // The condition function should be defined.\n if (conditionFuncInvoker === null) {\n throw new Error(\n `cannot update condition node as the condition '${this.conditionName}' function is not defined on the agent and has not been registered`\n );\n }\n\n // Call the condition function to determine the state of this node.\n this.setState(!!conditionFuncInvoker(this.conditionArguments) ? State.SUCCEEDED : State.FAILED);\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => this.conditionName;\n}\n", "import Leaf from \"./Leaf\";\nimport State from \"../../State\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { Agent } from \"../../Agent\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A WAIT node.\n * The state of this node will change to SUCCEEDED after a duration of time\n */\nexport default class Wait extends Leaf {\n /**\n * @param attributes The node attributes.\n * @param duration The duration that this node will wait to succeed in milliseconds.\n * @param durationMin The minimum possible duration in milliseconds that this node will wait to succeed.\n * @param durationMax The maximum possible duration in milliseconds that this node will wait to succeed.\n */\n constructor(\n attributes: Attribute[],\n private duration: number | null,\n private durationMin: number | null,\n private durationMax: number | null\n ) {\n super(\"wait\", attributes, []);\n }\n\n /**\n * The time in milliseconds at which this node was first updated.\n */\n private initialUpdateTime: number = 0;\n\n /**\n * The total duration in milliseconds that this node will be waiting for.\n */\n private totalDuration: number | null = null;\n\n /**\n * The duration in milliseconds that this node has been waiting for.\n */\n private waitedDuration: number = 0;\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // If this node is in the READY state then we need to set the initial update time.\n if (this.is(State.READY)) {\n // Set the initial update time.\n this.initialUpdateTime = new Date().getTime();\n\n // Set the initial waited duration.\n this.waitedDuration = 0;\n\n // Are we dealing with an explicit duration or will we be randomly picking a duration between the min and max duration.\n if (this.duration !== null) {\n this.totalDuration = this.duration;\n } else if (this.durationMin !== null && this.durationMax !== null) {\n // We will be picking a random duration between a min and max duration, if the optional 'random' behaviour tree\n // function option is defined then we will be using that, otherwise we will fall back to using Math.random.\n const random = typeof options.random === \"function\" ? options.random : Math.random;\n\n // Pick a random duration between a min and max duration.\n this.totalDuration = Math.floor(\n random() * (this.durationMax - this.durationMin + 1) + this.durationMin\n );\n } else {\n this.totalDuration = null;\n }\n\n // The node is now running until we finish waiting.\n this.setState(State.RUNNING);\n }\n\n // If we have no total duration then this wait node will wait indefinitely until it is aborted.\n if (this.totalDuration === null) {\n return;\n }\n\n // If we have a 'getDeltaTime' function defined as part of our options then we will use it to figure out how long we have waited for.\n if (typeof options.getDeltaTime === \"function\") {\n // Get the delta time.\n const deltaTime = options.getDeltaTime();\n\n // Our delta time must be a valid number and cannot be NaN.\n if (typeof deltaTime !== \"number\" || isNaN(deltaTime)) {\n throw new Error(\"The delta time must be a valid number and not NaN.\");\n }\n\n // Update the amount of time that this node has been waiting for based on the delta time.\n this.waitedDuration += deltaTime * 1000;\n } else {\n // We are not using a delta time, so we will just work out hom much time has passed since the first update.\n this.waitedDuration = new Date().getTime() - this.initialUpdateTime;\n }\n\n // Have we waited long enough?\n if (this.waitedDuration >= this.totalDuration) {\n // We have finished waiting!\n this.setState(State.SUCCEEDED);\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => {\n if (this.duration !== null) {\n return `WAIT ${this.duration}ms`;\n } else if (this.durationMin !== null && this.durationMax !== null) {\n return `WAIT ${this.durationMin}ms-${this.durationMax}ms`;\n } else {\n return \"WAIT\";\n }\n };\n}\n", "import Guard from \"./guards/Guard\";\n\nexport type AttributeDetails = {\n /** The attribute type. */\n type: string;\n\n /** The attribute arguments. */\n args: any[];\n};\n\n/**\n * A base node attribute.\n */\nexport default abstract class Attribute {\n /**\n * @param type The node attribute type.\n * @param args The array of attribute arguments.\n */\n constructor(public type: string, public args: any[]) {}\n\n /**\n * Gets the attribute details.\n */\n abstract getDetails(): TAttributeDetails;\n\n /**\n * Gets whether this attribute is a guard.\n */\n abstract isGuard: () => this is Guard;\n}\n", "import { Agent } from \"../../Agent\";\nimport Attribute, { AttributeDetails } from \"../Attribute\";\n\nexport type GuardAttributeDetails = {\n /** The name of the condition function that determines whether the guard is satisfied. */\n condition: string;\n} & AttributeDetails;\n\n/**\n * A base node guard attribute.\n */\nexport default abstract class Guard extends Attribute {\n /**\n * @param type The node attribute type.\n * @param args The array of decorator argument definitions.\n * @param condition The name of the condition function that determines whether the guard is satisfied.\n */\n constructor(type: string, args: any[], private condition: string) {\n super(type, args);\n }\n\n /**\n * Gets the name of the condition function that determines whether the guard is satisfied.\n */\n getCondition = () => this.condition;\n\n /**\n * Gets whether this attribute is a guard.\n */\n isGuard = () => true;\n\n /**\n * Gets the attribute details.\n */\n getDetails(): GuardAttributeDetails {\n return {\n type: this.type,\n args: this.args,\n condition: this.getCondition()\n };\n }\n\n /**\n * Gets whether the guard is satisfied.\n * @param agent The agent.\n * @returns Whether the guard is satisfied.\n */\n abstract isSatisfied(agent: Agent): boolean;\n}\n", "import Guard from \"./Guard\";\nimport Lookup from \"../../Lookup\";\nimport { Agent } from \"../../Agent\";\n\n/**\n * A WHILE guard which is satisfied as long as the given condition remains true.\n */\nexport default class While extends Guard {\n /**\n * @param condition The name of the condition function that determines whether the guard is satisfied.\n * @param args The array of decorator argument definitions.\n */\n constructor(condition: string, args: any[]) {\n super(\"while\", args, condition);\n }\n\n /**\n * Gets whether the guard is satisfied.\n * @param agent The agent.\n * @returns Whether the guard is satisfied.\n */\n isSatisfied = (agent: Agent) => {\n // Attempt to get the invoker for the condition function.\n const conditionFuncInvoker = Lookup.getFuncInvoker(agent, this.getCondition());\n\n // The condition function should be defined.\n if (conditionFuncInvoker === null) {\n throw new Error(\n `cannot evaluate node guard as the condition '${this.getCondition()}' function is not defined on the agent and has not been registered`\n );\n }\n\n // Call the condition function to determine whether this guard is satisfied.\n return !!conditionFuncInvoker(this.args);\n };\n}\n", "import Guard from \"./Guard\";\nimport Lookup from \"../../Lookup\";\nimport { Agent } from \"../../Agent\";\n\n/**\n * An UNTIL guard which is satisfied as long as the given condition remains false.\n */\nexport default class Until extends Guard {\n /**\n * @param condition The name of the condition function that determines whether the guard is satisfied.\n * @param args The array of decorator argument definitions.\n */\n constructor(condition: string, args: any[]) {\n super(\"until\", args, condition);\n }\n\n /**\n * Gets whether the guard is satisfied.\n * @param agent The agent.\n * @returns Whether the guard is satisfied.\n */\n isSatisfied = (agent: Agent) => {\n // Attempt to get the invoker for the condition function.\n const conditionFuncInvoker = Lookup.getFuncInvoker(agent, this.getCondition());\n\n // The condition function should be defined.\n if (conditionFuncInvoker === null) {\n throw new Error(\n `cannot evaluate node guard as the condition '${this.getCondition()}' function is not defined on the agent and has not been registered`\n );\n }\n\n // Call the condition function to determine whether this guard is satisfied.\n return !!!conditionFuncInvoker(this.args);\n };\n}\n", "import { Agent } from \"../../Agent\";\nimport Attribute, { AttributeDetails } from \"../Attribute\";\n\nexport type CallbackAttributeDetails = {\n /** The name of the agent function that is called. */\n functionName: string;\n} & AttributeDetails;\n\n/**\n * A base node callback attribute.\n */\nexport default abstract class Callback extends Attribute {\n /**\n * @param type The node attribute type.\n * @param args The array of decorator argument definitions.\n * @param functionName The name of the agent function to call.\n */\n constructor(type: string, args: any[], private functionName: string) {\n super(type, args);\n }\n\n /**\n * Gets the name of the agent function to call.\n */\n getFunctionName = () => this.functionName;\n\n /**\n * Gets whether this attribute is a guard.\n */\n isGuard = () => false;\n\n /**\n * Gets the attribute details.\n */\n getDetails(): CallbackAttributeDetails {\n return {\n type: this.type,\n args: this.args,\n functionName: this.getFunctionName()\n };\n }\n\n /**\n * Attempt to call the agent function that this callback refers to.\n * @param agent The agent.\n */\n abstract callAgentFunction: (agent: Agent, isSuccess: boolean, isAborted: boolean) => void;\n}\n", "import Callback from \"./Callback\";\nimport Lookup from \"../../Lookup\";\nimport { Agent } from \"../../Agent\";\n\n/**\n * An ENTRY callback which defines an agent function to call when the associated node is updated and moves out of running state.\n */\nexport default class Entry extends Callback {\n /**\n * @param functionName The name of the agent function to call.\n * @param args The array of callback argument definitions.\n */\n constructor(functionName: string, args: any[]) {\n super(\"entry\", args, functionName);\n }\n\n /**\n * Attempt to call the agent function that this callback refers to.\n * @param agent The agent.\n */\n callAgentFunction = (agent: Agent) => {\n // Attempt to get the invoker for the callback function.\n const callbackFuncInvoker = Lookup.getFuncInvoker(agent, this.getFunctionName());\n\n // The callback function should be defined.\n if (callbackFuncInvoker === null) {\n throw new Error(\n `cannot call entry function '${this.getFunctionName()}' as is not defined on the agent and has not been registered`\n );\n }\n\n // Call the callback function.\n callbackFuncInvoker(this.args);\n };\n}\n", "import Callback from \"./Callback\";\nimport Lookup from \"../../Lookup\";\nimport { Agent } from \"../../Agent\";\n\n/**\n * A STEP callback which defines an agent function to call when the associated node is updated.\n */\nexport default class Step extends Callback {\n /**\n * @param functionName The name of the agent function to call.\n * @param args The array of callback argument definitions.\n */\n constructor(functionName: string, args: any[]) {\n super(\"step\", args, functionName);\n }\n\n /**\n * Attempt to call the agent function that this callback refers to.\n * @param agent The agent.\n */\n callAgentFunction = (agent: Agent) => {\n // Attempt to get the invoker for the callback function.\n const callbackFuncInvoker = Lookup.getFuncInvoker(agent, this.getFunctionName());\n\n // The callback function should be defined.\n if (callbackFuncInvoker === null) {\n throw new Error(\n `cannot call step function '${this.getFunctionName()}' as is not defined on the agent and has not been registered`\n );\n }\n\n // Call the callback function.\n callbackFuncInvoker(this.args);\n };\n}\n", "import Callback from \"./Callback\";\nimport Lookup from \"../../Lookup\";\nimport { Agent } from \"../../Agent\";\n\n/**\n * An EXIT callback which defines an agent function to call when the associated node is updated and moves to a finished state or is aborted.\n */\nexport default class Exit extends Callback {\n /**\n * @param functionName The name of the agent function to call.\n * @param args The array of callback argument definitions.\n */\n constructor(functionName: string, args: any[]) {\n super(\"exit\", args, functionName);\n }\n\n /**\n * Attempt to call the agent function that this callback refers to.\n * @param agent The agent.\n * @param isSuccess Whether the decorated node was left with a success state.\n * @param isAborted Whether the decorated node was aborted.\n */\n callAgentFunction = (agent: Agent, isSuccess: boolean, isAborted: boolean) => {\n // Attempt to get the invoker for the callback function.\n const callbackFuncInvoker = Lookup.getFuncInvoker(agent, this.getFunctionName());\n\n // The callback function should be defined.\n if (callbackFuncInvoker === null) {\n throw new Error(\n `cannot call exit function '${this.getFunctionName()}' as is not defined on the agent and has not been registered`\n );\n }\n\n // Call the callback function\n callbackFuncInvoker([{ value: { succeeded: isSuccess, aborted: isAborted } }, ...this.args]);\n };\n}\n", "import { AnyNodeDefinition, RootNodeDefinition } from \"./BehaviourTreeDefinition\";\nimport GuardPath, { GuardPathPart } from \"./attributes/guards/GuardPath\";\nimport { validateBranchSubtreeLinks } from \"./BehaviourTreeDefinitionValidator\";\nimport { isInteger } from \"./BehaviourTreeDefinitionUtilities\";\nimport Node from \"./nodes/Node\";\nimport Composite from \"./nodes/composite/Composite\";\nimport Decorator from \"./nodes/decorator/Decorator\";\nimport Parallel from \"./nodes/composite/Parallel\";\nimport Selector from \"./nodes/composite/Selector\";\nimport Sequence from \"./nodes/composite/Sequence\";\nimport Lotto from \"./nodes/composite/Lotto\";\nimport Fail from \"./nodes/decorator/Fail\";\nimport Flip from \"./nodes/decorator/Flip\";\nimport Repeat from \"./nodes/decorator/Repeat\";\nimport Retry from \"./nodes/decorator/Retry\";\nimport Root from \"./nodes/decorator/Root\";\nimport Succeed from \"./nodes/decorator/Succeed\";\nimport Action from \"./nodes/leaf/Action\";\nimport Condition from \"./nodes/leaf/Condition\";\nimport Wait from \"./nodes/leaf/Wait\";\nimport Lookup from \"./Lookup\";\nimport Attribute from \"./attributes/Attribute\";\nimport While from \"./attributes/guards/While\";\nimport Until from \"./attributes/guards/Until\";\nimport Entry from \"./attributes/callbacks/Entry\";\nimport Step from \"./attributes/callbacks/Step\";\nimport Exit from \"./attributes/callbacks/Exit\";\n\n/**\n * A type representing any node instance in a behaviour tree.\n */\ntype AnyNode =\n | Root\n | Action\n | Condition\n | Wait\n | Sequence\n | Selector\n | Lotto\n | Parallel\n | Repeat\n | Retry\n | Flip\n | Succeed\n | Fail;\n\n/**\n * A type defining a mapping of root node identifiers to root node definitions.\n */\ntype RootNodeDefinitionMap = { [key: string | symbol]: RootNodeDefinition };\n\n/**\n * A symbol to use as the main root key in any root node mappings.\n */\nconst MAIN_ROOT_NODE_KEY = Symbol(\"__root__\");\n\n/**\n * Build and populate the root nodes based on the provided definition, assuming that the definition has been validated.\n * @param definition The root node definitions.\n * @returns The built and populated root node definitions.\n */\nexport default function buildRootNode(definition: RootNodeDefinition[]): Root {\n // Create a mapping of root node identifers to root node definitions, including globally registered subtree root node definitions.\n const rootNodeDefinitionMap = createRootNodeDefinitionMap(definition);\n\n // Now that we have all of our root node definitons (those part of the tree definition and those globally\n // registered) we should validate the definition. This will also double-check that we dont have any circular\n // dependencies in our branch -> subtree references and that we have no broken branch -> subtree links.\n validateBranchSubtreeLinks(definition, true);\n\n // Create our populated tree of node instances, starting with our main root node.\n const rootNode = nodeFactory(rootNodeDefinitionMap[MAIN_ROOT_NODE_KEY], rootNodeDefinitionMap) as Root;\n\n // Set a guard path on every leaf of the tree to evaluate as part of each update.\n applyLeafNodeGuardPaths(rootNode);\n\n // We only need to return the main root node.\n return rootNode;\n}\n\n/**\n * A factory function which creates a node instance based on the specified definition.\n * @param definition The node definition.\n * @param rootNodeDefinitionMap The mapping of root node identifers to root node definitions, including globally registered subtree root node definitions.\n * @returns A node instance based on the specified definition.\n */\nfunction nodeFactory(definition: AnyNodeDefinition, rootNodeDefinitionMap: RootNodeDefinitionMap): AnyNode {\n // Get the attributes for the node.\n const attributes = nodeAttributesFactory(definition);\n\n // Create the node instance based on the definition type.\n switch (definition.type) {\n case \"root\":\n return new Root(attributes, nodeFactory(definition.child, rootNodeDefinitionMap));\n\n case \"repeat\":\n let iterations: number | null = null;\n let iterationsMin: number | null = null;\n let iterationsMax: number | null = null;\n\n if (Array.isArray(definition.iterations)) {\n iterationsMin = definition.iterations[0];\n iterationsMax = definition.iterations[1];\n } else if (isInteger(definition.iterations)) {\n iterations = definition.iterations!;\n }\n\n return new Repeat(\n attributes,\n iterations,\n iterationsMin,\n iterationsMax,\n nodeFactory(definition.child, rootNodeDefinitionMap)\n );\n\n case \"retry\":\n let attempts: number | null = null;\n let attemptsMin: number | null = null;\n let attemptsMax: number | null = null;\n\n if (Array.isArray(definition.attempts)) {\n attemptsMin = definition.attempts[0];\n attemptsMax = definition.attempts[1];\n } else if (isInteger(definition.attempts)) {\n attempts = definition.attempts!;\n }\n\n return new Retry(\n attributes,\n attempts,\n attemptsMin,\n attemptsMax,\n nodeFactory(definition.child, rootNodeDefinitionMap)\n );\n\n case \"flip\":\n return new Flip(attributes, nodeFactory(definition.child, rootNodeDefinitionMap));\n\n case \"succeed\":\n return new Succeed(attributes, nodeFactory(definition.child, rootNodeDefinitionMap));\n\n case \"fail\":\n return new Fail(attributes, nodeFactory(definition.child, rootNodeDefinitionMap));\n\n case \"sequence\":\n return new Sequence(\n attributes,\n definition.children.map((child) => nodeFactory(child, rootNodeDefinitionMap))\n );\n\n case \"selector\":\n return new Selector(\n attributes,\n definition.children.map((child) => nodeFactory(child, rootNodeDefinitionMap))\n );\n\n case \"parallel\":\n return new Parallel(\n attributes,\n definition.children.map((child) => nodeFactory(child, rootNodeDefinitionMap))\n );\n\n case \"lotto\":\n return new Lotto(\n attributes,\n definition.weights,\n definition.children.map((child) => nodeFactory(child, rootNodeDefinitionMap))\n );\n\n case \"branch\":\n return nodeFactory(rootNodeDefinitionMap[definition.ref].child, rootNodeDefinitionMap);\n\n case \"action\":\n return new Action(attributes, definition.call, definition.args || []);\n\n case \"condition\":\n return new Condition(attributes, definition.call, definition.args || []);\n\n case \"wait\":\n let duration: number | null = null;\n let durationMin: number | null = null;\n let durationMax: number | null = null;\n\n if (Array.isArray(definition.duration)) {\n durationMin = definition.duration[0];\n durationMax = definition.duration[1];\n } else if (isInteger(definition.duration)) {\n duration = definition.duration!;\n }\n\n return new Wait(attributes, duration, durationMin, durationMax);\n }\n}\n\n/**\n * Creates an array of node attribute instances based on the specified node definition.\n * @param definition The node definition.\n * @returns An array of node attribute instances based on the specified node definition.\n */\nfunction nodeAttributesFactory(definition: AnyNodeDefinition): Attribute[] {\n const attributes: Attribute[] = [];\n\n if (definition.while) {\n attributes.push(new While(definition.while.call, definition.while.args ?? []));\n }\n\n if (definition.until) {\n attributes.push(new Until(definition.until.call, definition.until.args ?? []));\n }\n\n if (definition.entry) {\n attributes.push(new Entry(definition.entry.call, definition.entry.args ?? []));\n }\n\n if (definition.step) {\n attributes.push(new Step(definition.step.call, definition.step.args ?? []));\n }\n\n if (definition.exit) {\n attributes.push(new Exit(definition.exit.call, definition.exit.args ?? []));\n }\n\n return attributes;\n}\n\n/**\n * Creates a mapping of root node identifers to root node definitions, mixing in globally registered subtree root node definitions.\n * @param definition The root node definitions.\n * @returns A mapping of root node identifers to root node definitions, including globally registered subtree root node definitions.\n */\nfunction createRootNodeDefinitionMap(definition: RootNodeDefinition[]): RootNodeDefinitionMap {\n // Create a mapping of root node identifers to root node definitions.\n const rootNodeMap: RootNodeDefinitionMap = {};\n\n // Add in any registered subtree root node definitions.\n for (const [name, rootNodeDefinition] of Object.entries(Lookup.getSubtrees())) {\n // The name used when registering the subtree will be used as the root node identifier.\n rootNodeMap[name] = { ...rootNodeDefinition, id: name };\n }\n\n // Populate the map with the root node definitions that were included with the tree definition.\n // We do this after adding any registered subtrees as we want these to take presedence.\n for (const rootNodeDefinition of definition) {\n rootNodeMap[rootNodeDefinition.id ?? MAIN_ROOT_NODE_KEY] = rootNodeDefinition;\n }\n\n return rootNodeMap;\n}\n\n/**\n * Applies a guard path to every leaf of the tree to evaluate as part of each update.\n * @param root The main root tree node.\n */\nfunction applyLeafNodeGuardPaths(root: Root) {\n const nodePaths: Node[][] = [];\n\n const findLeafNodes = (path: Node[], node: Node) => {\n // Add the current node to the path.\n path = path.concat(node);\n\n // Check whether the current node is a leaf node.\n if (node.isLeafNode()) {\n nodePaths.push(path);\n } else {\n (node as Composite | Decorator).getChildren().forEach((child) => findLeafNodes(path, child));\n }\n };\n\n // Find all leaf node paths, starting from the root.\n findLeafNodes([], root);\n\n nodePaths.forEach((path) => {\n // Each node in the current path will have to be assigned a guard path, working from the root outwards.\n for (let depth = 0; depth < path.length; depth++) {\n // Get the node in the path at the current depth.\n const currentNode = path[depth];\n\n // The node may already have been assigned a guard path, if so just skip it.\n if (currentNode.hasGuardPath()) {\n continue;\n }\n\n // Create the guard path for the current node.\n const guardPath = new GuardPath(\n path\n .slice(0, depth + 1)\n .map((node) => ({ node, guards: node.getGuardAttributes() }))\n .filter((details) => details.guards.length > 0)\n );\n\n // Assign the guard path to the current node.\n currentNode.setGuardPath(guardPath);\n }\n });\n}\n", "import State, { AnyState } from \"./State\";\nimport Lookup from \"./Lookup\";\nimport Node from \"./nodes/Node\";\nimport Root from \"./nodes/decorator/Root\";\nimport Composite from \"./nodes/composite/Composite\";\nimport Decorator from \"./nodes/decorator/Decorator\";\nimport { Agent, GlobalFunction } from \"./Agent\";\nimport { CallbackAttributeDetails } from \"./attributes/callbacks/Callback\";\nimport { GuardAttributeDetails } from \"./attributes/guards/Guard\";\nimport { BehaviourTreeOptions } from \"./BehaviourTreeOptions\";\nimport { convertMDSLToJSON } from \"./mdsl/MDSLDefinitionParser\";\nimport { RootNodeDefinition } from \"./BehaviourTreeDefinition\";\nimport { validateDefinition, validateJSONDefinition } from \"./BehaviourTreeDefinitionValidator\";\nimport buildRootNode from \"./BehaviourTreeBuilder\";\nimport { isNullOrUndefined } from \"./BehaviourTreeDefinitionUtilities\";\n\n// Purely for outside inspection of the tree.\nexport type FlattenedTreeNode = {\n id: string;\n type: string;\n caption: string;\n state: AnyState;\n guards: GuardAttributeDetails[];\n callbacks: CallbackAttributeDetails[];\n args: any[];\n parentId: string | null;\n};\n\n/**\n * A representation of a behaviour tree.\n */\nexport class BehaviourTree {\n /**\n * The main root tree node.\n */\n private readonly _rootNode: Root;\n\n /**\n * Creates a new instance of the BehaviourTree class.\n * @param definition The behaviour tree definition as either an MDSL string, root node definition object or array of root node definition objects.\n * @param agent The agent instance that this behaviour tree is modelling behaviour for.\n * @param options The behaviour tree options object.\n */\n constructor(\n definition: string | RootNodeDefinition | RootNodeDefinition[],\n private agent: Agent,\n private options: BehaviourTreeOptions = {}\n ) {\n // The tree definition must be defined.\n if (isNullOrUndefined(definition)) {\n throw new Error(\"tree definition not defined\");\n }\n\n // The agent must be defined and not null.\n if (typeof agent !== \"object\" || agent === null) {\n throw new Error(\"the agent must be an object and not null\");\n }\n\n // We should validate the definition before we try to build the tree nodes.\n const { succeeded, errorMessage, json } = validateDefinition(definition);\n\n // Did our validation fail without error?\n if (!succeeded) {\n throw new Error(`invalid definition: ${errorMessage}`);\n }\n\n // Double check that we did actually get our json definition as part of our definition validtion.\n if (!json) {\n throw new Error(\n \"expected json definition to be returned as part of successful definition validation response\"\n );\n }\n\n try {\n // Create the populated tree of behaviour tree nodes and get the root node.\n this._rootNode = buildRootNode(json);\n } catch (exception) {\n // There was an issue in trying build and populate the behaviour tree.\n throw new Error(`error building tree: ${(exception as Error).message}`);\n }\n }\n\n /**\n * Gets whether the tree is in the RUNNING state.\n * @returns true if the tree is in the RUNNING state, otherwise false.\n */\n isRunning() {\n return this._rootNode.getState() === State.RUNNING;\n }\n\n /**\n * Gets the current tree state of SUCCEEDED, FAILED, READY or RUNNING.\n * @returns The current tree state.\n */\n getState() {\n return this._rootNode.getState();\n }\n\n /**\n * Step the tree.\n * 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.\n * 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\n * 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.\n *\n * 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.\n */\n step() {\n // If the root node has already been stepped to completion then we need to reset it.\n if (this._rootNode.getState() === State.SUCCEEDED || this._rootNode.getState() === State.FAILED) {\n this._rootNode.reset();\n }\n\n try {\n this._rootNode.update(this.agent, this.options);\n } catch (exception) {\n throw new Error(`error stepping tree: ${(exception as Error).message}`);\n }\n }\n\n /**\n * Resets the tree from the root node outwards to each nested node, giving each a state of READY.\n */\n reset() {\n this._rootNode.reset();\n }\n\n /**\n * Gets the flattened details of every node in the tree.\n * @returns The flattened details of every node in the tree.\n */\n getFlattenedNodeDetails(): FlattenedTreeNode[] {\n // Create an empty flattened array of tree nodes.\n const flattenedTreeNodes: FlattenedTreeNode[] = [];\n\n /**\n * Helper function to process a node instance and push details into the flattened tree nodes array.\n * @param node The current node.\n * @param parentUid The UID of the node parent, or null if the node is the main root node.\n */\n const processNode = (node: Node, parentUid: string | null) => {\n // Get the guard and callback attribute details for this node.\n const guards = node\n .getAttributes()\n .filter((attribute) => attribute.isGuard())\n .map((attribute) => attribute.getDetails()) as GuardAttributeDetails[];\n const callbacks = node\n .getAttributes()\n .filter((attribute) => !attribute.isGuard())\n .map((attribute) => attribute.getDetails()) as CallbackAttributeDetails[];\n\n // Push the current node into the flattened nodes array.\n flattenedTreeNodes.push({\n id: node.getUid(),\n type: node.getType(),\n caption: node.getName(),\n state: node.getState(),\n guards,\n callbacks,\n args: node.getArguments(),\n parentId: parentUid\n });\n\n // Process each of the nodes children if it is not a leaf node.\n if (!node.isLeafNode()) {\n (node as Composite | Decorator)\n .getChildren()\n .forEach((child) => processNode(child, (node as Composite | Decorator).getUid()));\n }\n };\n\n // Convert the nested node structure into a flattened array of node details.\n processNode(this._rootNode, null);\n\n return flattenedTreeNodes;\n }\n\n /**\n * Registers the action/condition/guard/callback function or subtree with the given name.\n * @param name The name of the function or subtree to register.\n * @param value The function or subtree definition to register.\n */\n static register(name: string, value: GlobalFunction | string | RootNodeDefinition) {\n // Are we going to register a action/condition/guard/callback function?\n if (typeof value === \"function\") {\n Lookup.setFunc(name, value);\n return;\n }\n\n // We are not registering an action/condition/guard/callback function, so we must be registering a subtree.\n if (typeof value === \"string\") {\n let rootNodeDefinitions: RootNodeDefinition[];\n\n // We will assume that any string passed in will be a mdsl definition.\n try {\n rootNodeDefinitions = convertMDSLToJSON(value);\n } catch (exception) {\n throw new Error(`error registering definition, invalid MDSL: ${(exception as Error).message}`);\n }\n\n // This function should only ever be called with a definition containing a single unnamed root node.\n if (rootNodeDefinitions.length != 1 || rootNodeDefinitions[0].id !== null) {\n throw new Error(\"error registering definition: expected a single unnamed root node\");\n }\n\n try {\n // We should validate the subtree as we don't want invalid subtrees available via the lookup.\n const { succeeded, errorMessage } = validateJSONDefinition(rootNodeDefinitions[0]);\n\n // Did our validation fail without error?\n if (!succeeded) {\n throw new Error(errorMessage);\n }\n } catch (exception) {\n throw new Error(`error registering definition: ${(exception as Error).message}`);\n }\n\n // Everything seems hunky-dory, register the subtree.\n Lookup.setSubtree(name, rootNodeDefinitions[0]);\n } else if (typeof value === \"object\" && !Array.isArray(value)) {\n // We will assume that any object passed in is a root node definition.\n\n try {\n // We should validate the subtree as we don't want invalid subtrees available via the lookup.\n const { succeeded, errorMessage } = validateJSONDefinition(value);\n\n // Did our validation fail without error?\n if (!succeeded) {\n throw new Error(errorMessage);\n }\n } catch (exception) {\n throw new Error(`error registering definition: ${(exception as Error).message}`);\n }\n\n // Everything seems hunky-dory, register the subtree.\n Lookup.setSubtree(name, value);\n } else {\n throw new Error(\"unexpected value, expected string mdsl definition, root node json definition or function\");\n }\n }\n\n /**\n * Unregisters the registered action/condition/guard/callback function or subtree with the given name.\n * @param name The name of the registered action/condition/guard/callback function or subtree to unregister.\n */\n static unregister(name: string): void {\n Lookup.remove(name);\n }\n\n /**\n * Unregister all registered action/condition/guard/callback functions and subtrees.\n */\n static unregisterAll(): void {\n Lookup.empty();\n }\n}\n"], + "mappings": "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", "names": ["Participant", "isNullOrUndefined", "Lotto", "createLotto", "State", "createLotto"] } diff --git a/package-lock.json b/package-lock.json index ba18dd8..738f3e1 100644 --- a/package-lock.json +++ b/package-lock.json @@ -12,14 +12,19 @@ "lotto-draw": "^1.0.2" }, "devDependencies": { - "chai": "^4.3.7", + "@types/chai": "^4.3.11", + "@types/mocha": "^10.0.6", + "@types/sinon": "^17.0.3", + "chai": "^4.4.1", "esbuild": "^0.15.18", "expect": "^25.5.0", "mocha": "^10.2.0", "npm-run-all": "^4.1.5", "prettier": "2.7.1", "should": "^1.3.0", - "sinon": "^14.0.1" + "sinon": "^14.0.2", + "ts-node": "^10.9.2", + "typescript": "^5.3.3" } }, "node_modules/@babel/code-frame": { @@ -63,6 +68,18 @@ "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==", "dev": true }, + "node_modules/@cspotcode/source-map-support": { + "version": "0.8.1", + "resolved": "https://registry.npmjs.org/@cspotcode/source-map-support/-/source-map-support-0.8.1.tgz", + "integrity": "sha512-IchNf6dN4tHoMFIn/7OE8LWZ19Y6q/67Bmf6vnGREv8RSbBVb9LPJxEcnwrcwX6ixSvaiGoomAUvu4YSxXrVgw==", + "dev": true, + "dependencies": { + "@jridgewell/trace-mapping": "0.3.9" + }, + "engines": { + "node": ">=12" + } + }, "node_modules/@esbuild/android-arm": { "version": "0.15.18", "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.15.18.tgz", @@ -159,6 +176,31 @@ "node": ">=8" } }, + "node_modules/@jridgewell/resolve-uri": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz", + "integrity": "sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==", + "dev": true, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@jridgewell/sourcemap-codec": { + "version": "1.4.15", + "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.15.tgz", + "integrity": "sha512-eF2rxCRulEKXHTRiDrDy6erMYWqNw4LPdQ8UQA4huuxaQsVeRPFl2oM8oDGxMFhJUWZf9McpLtJasDDZb/Bpeg==", + "dev": true + }, + "node_modules/@jridgewell/trace-mapping": { + "version": "0.3.9", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.9.tgz", + "integrity": "sha512-3Belt6tdc8bPgAtbcmdtNJlirVoTmEb5e2gC94PnkwEW9jI6CAHUeoG85tjWP5WquqfavoMtMwiG4P926ZKKuQ==", + "dev": true, + "dependencies": { + "@jridgewell/resolve-uri": "^3.0.3", + "@jridgewell/sourcemap-codec": "^1.4.10" + } + }, "node_modules/@sinonjs/commons": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/@sinonjs/commons/-/commons-2.0.0.tgz", @@ -203,6 +245,36 @@ "integrity": "sha512-sXXKG+uL9IrKqViTtao2Ws6dy0znu9sOaP1di/jKGW1M6VssO8vlpXCQcpZ+jisQ1tTFAC5Jo/EOzFbggBagFQ==", "dev": true }, + "node_modules/@tsconfig/node10": { + "version": "1.0.9", + "resolved": "https://registry.npmjs.org/@tsconfig/node10/-/node10-1.0.9.tgz", + "integrity": "sha512-jNsYVVxU8v5g43Erja32laIDHXeoNvFEpX33OK4d6hljo3jDhCBDhx5dhCCTMWUojscpAagGiRkBKxpdl9fxqA==", + "dev": true + }, + "node_modules/@tsconfig/node12": { + "version": "1.0.11", + "resolved": "https://registry.npmjs.org/@tsconfig/node12/-/node12-1.0.11.tgz", + "integrity": "sha512-cqefuRsh12pWyGsIoBKJA9luFu3mRxCA+ORZvA4ktLSzIuCUtWVxGIuXigEwO5/ywWFMZ2QEGKWvkZG1zDMTag==", + "dev": true + }, + "node_modules/@tsconfig/node14": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/@tsconfig/node14/-/node14-1.0.3.tgz", + "integrity": "sha512-ysT8mhdixWK6Hw3i1V2AeRqZ5WfXg1G43mqoYlM2nc6388Fq5jcXyr5mRsqViLx/GJYdoL0bfXD8nmF+Zn/Iow==", + "dev": true + }, + "node_modules/@tsconfig/node16": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/@tsconfig/node16/-/node16-1.0.4.tgz", + "integrity": "sha512-vxhUy4J8lyeyinH7Azl1pdd43GJhZH/tP2weN8TntQblOY+A0XbT8DJk1/oCPuOOyg/Ja757rG0CgHcWC8OfMA==", + "dev": true + }, + "node_modules/@types/chai": { + "version": "4.3.11", + "resolved": "https://registry.npmjs.org/@types/chai/-/chai-4.3.11.tgz", + "integrity": "sha512-qQR1dr2rGIHYlJulmr8Ioq3De0Le9E4MJ5AiaeAETJJpndT1uUNHsGFK3L/UIu+rbkQSdj8J/w2bCsBZc/Y5fQ==", + "dev": true + }, "node_modules/@types/istanbul-lib-coverage": { "version": "2.0.3", "resolved": "https://registry.npmjs.org/@types/istanbul-lib-coverage/-/istanbul-lib-coverage-2.0.3.tgz", @@ -228,6 +300,37 @@ "@types/istanbul-lib-report": "*" } }, + "node_modules/@types/mocha": { + "version": "10.0.6", + "resolved": "https://registry.npmjs.org/@types/mocha/-/mocha-10.0.6.tgz", + "integrity": "sha512-dJvrYWxP/UcXm36Qn36fxhUKu8A/xMRXVT2cliFF1Z7UA9liG5Psj3ezNSZw+5puH2czDXRLcXQxf8JbJt0ejg==", + "dev": true + }, + "node_modules/@types/node": { + "version": "20.11.19", + "resolved": "https://registry.npmjs.org/@types/node/-/node-20.11.19.tgz", + "integrity": "sha512-7xMnVEcZFu0DikYjWOlRq7NTPETrm7teqUT2WkQjrTIkEgUyyGdWsj/Zg8bEJt5TNklzbPD1X3fqfsHw3SpapQ==", + "dev": true, + "peer": true, + "dependencies": { + "undici-types": "~5.26.4" + } + }, + "node_modules/@types/sinon": { + "version": "17.0.3", + "resolved": "https://registry.npmjs.org/@types/sinon/-/sinon-17.0.3.tgz", + "integrity": "sha512-j3uovdn8ewky9kRBG19bOwaZbexJu/XjtkHyjvUgt4xfPFz18dcORIMqnYh66Fx3Powhcr85NT5+er3+oViapw==", + "dev": true, + "dependencies": { + "@types/sinonjs__fake-timers": "*" + } + }, + "node_modules/@types/sinonjs__fake-timers": { + "version": "8.1.5", + "resolved": "https://registry.npmjs.org/@types/sinonjs__fake-timers/-/sinonjs__fake-timers-8.1.5.tgz", + "integrity": "sha512-mQkU2jY8jJEF7YHjHvsQO8+3ughTL1mcnn96igfhONmR+fUPSKIkefQYpSe8bsly2Ep7oQbn/6VG5/9/0qcArQ==", + "dev": true + }, "node_modules/@types/stack-utils": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/@types/stack-utils/-/stack-utils-1.0.1.tgz", @@ -249,6 +352,27 @@ "integrity": "sha512-7tFImggNeNBVMsn0vLrpn1H1uPrUBdnARPTpZoitY37ZrdJREzf7I16tMrlK3hen349gr1NYh8CmZQa7CTG6Aw==", "dev": true }, + "node_modules/acorn": { + "version": "8.11.3", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.11.3.tgz", + "integrity": "sha512-Y9rRfJG5jcKOE0CLisYbojUjIrIEE7AGMzA/Sm4BslANhbS+cDMpgBdcPT91oJ7OuJ9hYJBx59RjbhxVnrF8Xg==", + "dev": true, + "bin": { + "acorn": "bin/acorn" + }, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/acorn-walk": { + "version": "8.3.2", + "resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-8.3.2.tgz", + "integrity": "sha512-cjkyv4OtNCIeqhHrfS81QWXoCBPExR/J62oyEqepVw8WaQeSqpW2uhuLPh1m9eWhDuOo/jUXVTlifvesOWp/4A==", + "dev": true, + "engines": { + "node": ">=0.4.0" + } + }, "node_modules/ansi-colors": { "version": "4.1.1", "resolved": "https://registry.npmjs.org/ansi-colors/-/ansi-colors-4.1.1.tgz", @@ -307,6 +431,12 @@ "node": ">= 8" } }, + "node_modules/arg": { + "version": "4.1.3", + "resolved": "https://registry.npmjs.org/arg/-/arg-4.1.3.tgz", + "integrity": "sha512-58S9QDqG0Xx27YwPSt9fJxivjYl432YCwfDMfZ+71RAqUrZef7LrKQZ3LHLOwCS4FLNBplP533Zx895SeOCHvA==", + "dev": true + }, "node_modules/argparse": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", @@ -391,18 +521,18 @@ } }, "node_modules/chai": { - "version": "4.3.7", - "resolved": "https://registry.npmjs.org/chai/-/chai-4.3.7.tgz", - "integrity": "sha512-HLnAzZ2iupm25PlN0xFreAlBA5zaBSv3og0DdeGA4Ar6h6rJ3A0rolRUKJhSF2V10GZKDgWF/VmAEsNWjCRB+A==", + "version": "4.4.1", + "resolved": "https://registry.npmjs.org/chai/-/chai-4.4.1.tgz", + "integrity": "sha512-13sOfMv2+DWduEU+/xbun3LScLoqN17nBeTLUsmDfKdoiC1fr0n9PU4guu4AhRcOVFk/sW8LyZWHuhWtQZiF+g==", "dev": true, "dependencies": { "assertion-error": "^1.1.0", - "check-error": "^1.0.2", - "deep-eql": "^4.1.2", - "get-func-name": "^2.0.0", - "loupe": "^2.3.1", + "check-error": "^1.0.3", + "deep-eql": "^4.1.3", + "get-func-name": "^2.0.2", + "loupe": "^2.3.6", "pathval": "^1.1.1", - "type-detect": "^4.0.5" + "type-detect": "^4.0.8" }, "engines": { "node": ">=4" @@ -423,10 +553,13 @@ } }, "node_modules/check-error": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/check-error/-/check-error-1.0.2.tgz", - "integrity": "sha512-BrgHpW9NURQgzoNyjfq0Wu6VFO6D7IZEmJNdtgNqpzGG8RuNFHt2jQxWlAs4HMe119chBnv+34syEZtc6IhLtA==", + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/check-error/-/check-error-1.0.3.tgz", + "integrity": "sha512-iKEoDYaRmd1mxM90a2OEfWhjsjPpYPuQ+lMYsoxB126+t8fw7ySEO48nmDg5COTjxDI65/Y2OWpeEHk3ZOe8zg==", "dev": true, + "dependencies": { + "get-func-name": "^2.0.2" + }, "engines": { "node": "*" } @@ -493,6 +626,12 @@ "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=", "dev": true }, + "node_modules/create-require": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/create-require/-/create-require-1.1.1.tgz", + "integrity": "sha512-dcKFX3jn0MpIaXjisoRvexIJVEKzaq7z2rZKxf+MSr9TkdmHmsU4m2lcLojrj/FHl8mk5VxMmYA+ftRkP/3oKQ==", + "dev": true + }, "node_modules/cross-spawn": { "version": "6.0.5", "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-6.0.5.tgz", @@ -1184,9 +1323,9 @@ } }, "node_modules/get-func-name": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/get-func-name/-/get-func-name-2.0.0.tgz", - "integrity": "sha512-Hm0ixYtaSZ/V7C8FJrtZIuBBI+iSgL+1Aq82zSu8VQNB4S3Gk8e7Qs3VwBDJAhmRZcFqkl3tQu36g/Foh5I5ig==", + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/get-func-name/-/get-func-name-2.0.2.tgz", + "integrity": "sha512-8vXOvuE167CtIc3OyItco7N/dpRtBbYOsPsXCz7X/PMnlGjYjSGuZJgM1Y7mmew7BKf9BqvLX2tnOVy1BBUsxQ==", "dev": true, "engines": { "node": "*" @@ -2000,6 +2139,12 @@ "get-func-name": "^2.0.0" } }, + "node_modules/make-error": { + "version": "1.3.6", + "resolved": "https://registry.npmjs.org/make-error/-/make-error-1.3.6.tgz", + "integrity": "sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw==", + "dev": true + }, "node_modules/memorystream": { "version": "0.3.1", "resolved": "https://registry.npmjs.org/memorystream/-/memorystream-0.3.1.tgz", @@ -2618,6 +2763,7 @@ "version": "14.0.2", "resolved": "https://registry.npmjs.org/sinon/-/sinon-14.0.2.tgz", "integrity": "sha512-PDpV0ZI3ZCS3pEqx0vpNp6kzPhHrLx72wA0G+ZLaaJjLIYeE0n8INlgaohKuGy7hP0as5tbUd23QWu5U233t+w==", + "deprecated": "16.1.1", "dev": true, "dependencies": { "@sinonjs/commons": "^2.0.0", @@ -2834,6 +2980,58 @@ "node": ">=8.0" } }, + "node_modules/ts-node": { + "version": "10.9.2", + "resolved": "https://registry.npmjs.org/ts-node/-/ts-node-10.9.2.tgz", + "integrity": "sha512-f0FFpIdcHgn8zcPSbf1dRevwt047YMnaiJM3u2w2RewrB+fob/zePZcrOyQoLMMO7aBIddLcQIEK5dYjkLnGrQ==", + "dev": true, + "dependencies": { + "@cspotcode/source-map-support": "^0.8.0", + "@tsconfig/node10": "^1.0.7", + "@tsconfig/node12": "^1.0.7", + "@tsconfig/node14": "^1.0.0", + "@tsconfig/node16": "^1.0.2", + "acorn": "^8.4.1", + "acorn-walk": "^8.1.1", + "arg": "^4.1.0", + "create-require": "^1.1.0", + "diff": "^4.0.1", + "make-error": "^1.1.1", + "v8-compile-cache-lib": "^3.0.1", + "yn": "3.1.1" + }, + "bin": { + "ts-node": "dist/bin.js", + "ts-node-cwd": "dist/bin-cwd.js", + "ts-node-esm": "dist/bin-esm.js", + "ts-node-script": "dist/bin-script.js", + "ts-node-transpile-only": "dist/bin-transpile.js", + "ts-script": "dist/bin-script-deprecated.js" + }, + "peerDependencies": { + "@swc/core": ">=1.2.50", + "@swc/wasm": ">=1.2.50", + "@types/node": "*", + "typescript": ">=2.7" + }, + "peerDependenciesMeta": { + "@swc/core": { + "optional": true + }, + "@swc/wasm": { + "optional": true + } + } + }, + "node_modules/ts-node/node_modules/diff": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/diff/-/diff-4.0.2.tgz", + "integrity": "sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A==", + "dev": true, + "engines": { + "node": ">=0.3.1" + } + }, "node_modules/type-detect": { "version": "4.0.8", "resolved": "https://registry.npmjs.org/type-detect/-/type-detect-4.0.8.tgz", @@ -2843,6 +3041,19 @@ "node": ">=4" } }, + "node_modules/typescript": { + "version": "5.3.3", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.3.3.tgz", + "integrity": "sha512-pXWcraxM0uxAS+tN0AG/BF2TyqmHO014Z070UsJ+pFvYuRSq8KH8DmWpnbXe0pEPDHXZV3FcAbJkijJ5oNEnWw==", + "dev": true, + "bin": { + "tsc": "bin/tsc", + "tsserver": "bin/tsserver" + }, + "engines": { + "node": ">=14.17" + } + }, "node_modules/unbox-primitive": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/unbox-primitive/-/unbox-primitive-1.0.2.tgz", @@ -2858,6 +3069,19 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/undici-types": { + "version": "5.26.5", + "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-5.26.5.tgz", + "integrity": "sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA==", + "dev": true, + "peer": true + }, + "node_modules/v8-compile-cache-lib": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/v8-compile-cache-lib/-/v8-compile-cache-lib-3.0.1.tgz", + "integrity": "sha512-wa7YjyUGfNZngI/vtK0UHAN+lgDCxBPCylVXGp0zu59Fz5aiGtNXaq3DhIov063MorB+VfufLh3JlF2KdTK3xg==", + "dev": true + }, "node_modules/validate-npm-package-license": { "version": "3.0.4", "resolved": "https://registry.npmjs.org/validate-npm-package-license/-/validate-npm-package-license-3.0.4.tgz", @@ -2991,6 +3215,15 @@ "node": ">=10" } }, + "node_modules/yn": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/yn/-/yn-3.1.1.tgz", + "integrity": "sha512-Ux4ygGWsu2c7isFWe8Yu1YluJmqVhxqK2cLXNQA5AcC3QfbGNpM7fu0Y8b/z16pXLnFxZYvWhd3fhBY9DLmC6Q==", + "dev": true, + "engines": { + "node": ">=6" + } + }, "node_modules/yocto-queue": { "version": "0.1.0", "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz", diff --git a/package.json b/package.json index 585bb12..0f21be1 100644 --- a/package.json +++ b/package.json @@ -8,24 +8,29 @@ "dist/*" ], "devDependencies": { - "chai": "^4.3.7", + "@types/chai": "^4.3.11", + "@types/mocha": "^10.0.6", + "@types/sinon": "^17.0.3", + "chai": "^4.4.1", "esbuild": "^0.15.18", "expect": "^25.5.0", "mocha": "^10.2.0", "npm-run-all": "^4.1.5", "prettier": "2.7.1", "should": "^1.3.0", - "sinon": "^14.0.1" + "sinon": "^14.0.2", + "ts-node": "^10.9.2", + "typescript": "^5.3.3" }, "scripts": { "build": "npm-run-all build:format build:node build:web build:typecheck", "watch": "npm run build:node -- --watch", "test": "npm-run-all build test:unit-test", - "build:format": "prettier --write \"src/**/*.ts\" \"test/**/*.js\"", + "build:format": "prettier --write \"src/**/*.ts\" \"test/**/*.ts\"", "build:node": "esbuild ./src/index.ts --bundle --sourcemap --outdir=dist --platform=node", "build:web": "esbuild ./src/index.ts --bundle --sourcemap --platform=browser --global-name=mistreevous --outfile=dist/bundle.js", "build:typecheck": "tsc --emitDeclarationOnly", - "test:unit-test": "mocha \"test/**/*.js\"" + "test:unit-test": "mocha --require ts-node/register test/**/*.spec.ts" }, "repository": { "type": "git", diff --git a/src/Agent.ts b/src/Agent.ts index 60d0767..525720c 100644 --- a/src/Agent.ts +++ b/src/Agent.ts @@ -35,6 +35,6 @@ export type Agent = { export type ExitFunctionArg = { succeeded: boolean; aborted: boolean }; export type FunctionArg = number | string | boolean | null | ExitFunctionArg; -export type ActionResult = CompleteState | Promise | boolean; +export type ActionResult = CompleteState | Promise | boolean | void; export type AgentFunction = (this: Agent, ...args: FunctionArg[]) => ActionResult; export type GlobalFunction = (agent: Agent, ...args: FunctionArg[]) => ActionResult; diff --git a/src/BehaviourTree.ts b/src/BehaviourTree.ts index 7569a21..bb43497 100644 --- a/src/BehaviourTree.ts +++ b/src/BehaviourTree.ts @@ -33,7 +33,7 @@ export class BehaviourTree { /** * The main root tree node. */ - public readonly rootNode: Root; + private readonly _rootNode: Root; /** * Creates a new instance of the BehaviourTree class. @@ -73,7 +73,7 @@ export class BehaviourTree { try { // Create the populated tree of behaviour tree nodes and get the root node. - this.rootNode = buildRootNode(json); + this._rootNode = buildRootNode(json); } catch (exception) { // There was an issue in trying build and populate the behaviour tree. throw new Error(`error building tree: ${(exception as Error).message}`); @@ -85,7 +85,7 @@ export class BehaviourTree { * @returns true if the tree is in the RUNNING state, otherwise false. */ isRunning() { - return this.rootNode.getState() === State.RUNNING; + return this._rootNode.getState() === State.RUNNING; } /** @@ -93,7 +93,7 @@ export class BehaviourTree { * @returns The current tree state. */ getState() { - return this.rootNode.getState(); + return this._rootNode.getState(); } /** @@ -106,12 +106,12 @@ export class BehaviourTree { */ step() { // If the root node has already been stepped to completion then we need to reset it. - if (this.rootNode.getState() === State.SUCCEEDED || this.rootNode.getState() === State.FAILED) { - this.rootNode.reset(); + if (this._rootNode.getState() === State.SUCCEEDED || this._rootNode.getState() === State.FAILED) { + this._rootNode.reset(); } try { - this.rootNode.update(this.agent, this.options); + this._rootNode.update(this.agent, this.options); } catch (exception) { throw new Error(`error stepping tree: ${(exception as Error).message}`); } @@ -121,7 +121,7 @@ export class BehaviourTree { * Resets the tree from the root node outwards to each nested node, giving each a state of READY. */ reset() { - this.rootNode.reset(); + this._rootNode.reset(); } /** @@ -169,7 +169,7 @@ export class BehaviourTree { }; // Convert the nested node structure into a flattened array of node details. - processNode(this.rootNode, null); + processNode(this._rootNode, null); return flattenedTreeNodes; } diff --git a/test/BehaviourTree.test.js b/test/BehaviourTree.spec.ts similarity index 57% rename from test/BehaviourTree.test.js rename to test/BehaviourTree.spec.ts index ac78600..8434d08 100644 --- a/test/BehaviourTree.test.js +++ b/test/BehaviourTree.spec.ts @@ -1,32 +1,33 @@ -const mistreevous = require("../dist/index"); -const chai = require("chai"); +import { assert } from "chai"; +import sinon from "sinon"; -var assert = chai.assert; +import { BehaviourTree, State } from "../src/index"; +import { RootNodeDefinition } from "../src/BehaviourTreeDefinition"; +import { Agent } from "../src/Agent"; -const findNode = (tree, type, caption) => - tree.getFlattenedNodeDetails().find((node) => node.type === type && node.caption === caption); +import { findNode } from "./TestUtilities"; describe("A BehaviourTree instance", () => { describe("has initialisation logic that", () => { describe("should error when", () => { it("the tree definition argument is not defined", () => { - assert.throws(() => new mistreevous.BehaviourTree(null, {}), Error, "tree definition not defined"); - assert.throws(() => new mistreevous.BehaviourTree(undefined, {}), Error, "tree definition not defined"); + assert.throws(() => new BehaviourTree(null as any, {}), Error, "tree definition not defined"); + assert.throws(() => new BehaviourTree(undefined as any, {}), Error, "tree definition not defined"); }); it("the agent object is not defined", () => { assert.throws( - () => new mistreevous.BehaviourTree("", undefined), + () => new BehaviourTree("", undefined as any), Error, "the agent must be an object and not null" ); assert.throws( - () => new mistreevous.BehaviourTree("", null), + () => new BehaviourTree("", null as any), Error, "the agent must be an object and not null" ); assert.throws( - () => new mistreevous.BehaviourTree("", 42), + () => new BehaviourTree("", 42 as any), Error, "the agent must be an object and not null" ); @@ -36,77 +37,71 @@ describe("A BehaviourTree instance", () => { describe("should not error when the tree definition argument is a valid definition", () => { it("(MDSL)", () => { const definition = "root { action [test] }"; - assert.doesNotThrow(() => new mistreevous.BehaviourTree(definition, {}), Error); + assert.doesNotThrow(() => new BehaviourTree(definition, {}), Error); }); it("(JSON)", () => { - const definition = { + const definition: RootNodeDefinition = { type: "root", child: { type: "action", call: "test" } }; - assert.doesNotThrow(() => new mistreevous.BehaviourTree(definition, {}), Error); + assert.doesNotThrow(() => new BehaviourTree(definition, {}), Error); }); }); }); describe("has a 'getState' function that returns the state of the root node", () => { it("(MDSL)", () => { - let actionResult = undefined; - const definition = "root { action [getActionResult] }"; - const agent = { getActionResult: () => actionResult }; - const tree = new mistreevous.BehaviourTree(definition, agent); + const agent: Agent = { getActionResult: () => {} }; + const tree = new BehaviourTree(definition, agent); - assert.strictEqual(tree.getState(), mistreevous.State.READY); + assert.strictEqual(tree.getState(), State.READY); tree.step(); - assert.strictEqual(tree.getState(), mistreevous.State.RUNNING); + assert.strictEqual(tree.getState(), State.RUNNING); - actionResult = mistreevous.State.SUCCEEDED; + agent.getActionResult = () => State.SUCCEEDED; tree.step(); - assert.strictEqual(tree.getState(), mistreevous.State.SUCCEEDED); + assert.strictEqual(tree.getState(), State.SUCCEEDED); }); it("(JSON)", () => { - let actionResult = undefined; - - const definition = { + const definition: RootNodeDefinition = { type: "root", child: { type: "action", call: "getActionResult" } }; - const agent = { getActionResult: () => actionResult }; - const tree = new mistreevous.BehaviourTree(definition, agent); + const agent = { getActionResult: () => {} }; + const tree = new BehaviourTree(definition, agent); - assert.strictEqual(tree.getState(), mistreevous.State.READY); + assert.strictEqual(tree.getState(), State.READY); tree.step(); - assert.strictEqual(tree.getState(), mistreevous.State.RUNNING); + assert.strictEqual(tree.getState(), State.RUNNING); - actionResult = mistreevous.State.SUCCEEDED; + agent.getActionResult = () => State.SUCCEEDED; tree.step(); - assert.strictEqual(tree.getState(), mistreevous.State.SUCCEEDED); + assert.strictEqual(tree.getState(), State.SUCCEEDED); }); }); describe("has an 'isRunning' function that returns a flag defining whether the tree is in a running state", () => { it("(MDSL)", () => { - let actionResult = undefined; - const definition = "root { action [getActionResult] }"; - const agent = { getActionResult: () => actionResult }; - const tree = new mistreevous.BehaviourTree(definition, agent); + const agent = { getActionResult: () => {} }; + const tree = new BehaviourTree(definition, agent); assert.strictEqual(tree.isRunning(), false); @@ -114,7 +109,7 @@ describe("A BehaviourTree instance", () => { assert.strictEqual(tree.isRunning(), true); - actionResult = mistreevous.State.SUCCEEDED; + agent.getActionResult = () => State.SUCCEEDED; tree.step(); @@ -122,17 +117,15 @@ describe("A BehaviourTree instance", () => { }); it("(JSON)", () => { - let actionResult = undefined; - - const definition = { + const definition: RootNodeDefinition = { type: "root", child: { type: "action", call: "getActionResult" } }; - const agent = { getActionResult: () => actionResult }; - const tree = new mistreevous.BehaviourTree(definition, agent); + const agent = { getActionResult: () => {} }; + const tree = new BehaviourTree(definition, agent); assert.strictEqual(tree.isRunning(), false); @@ -140,7 +133,7 @@ describe("A BehaviourTree instance", () => { assert.strictEqual(tree.isRunning(), true); - actionResult = mistreevous.State.SUCCEEDED; + agent.getActionResult = () => State.SUCCEEDED; tree.step(); @@ -151,28 +144,28 @@ describe("A BehaviourTree instance", () => { describe("has a 'reset' function that resets the tree from the root node outwards to each nested node, giving each a state of READY", () => { it("(MDSL)", () => { const definition = "root { sequence { action [getActionResult] } }"; - const agent = { getActionResult: () => mistreevous.State.SUCCEEDED }; - const tree = new mistreevous.BehaviourTree(definition, agent); + const agent: Agent = { getActionResult: () => State.SUCCEEDED }; + const tree = new BehaviourTree(definition, agent); - assert.strictEqual(findNode(tree, "root", "ROOT").state, mistreevous.State.READY); - assert.strictEqual(findNode(tree, "sequence", "SEQUENCE").state, mistreevous.State.READY); - assert.strictEqual(findNode(tree, "action", "getActionResult").state, mistreevous.State.READY); + assert.strictEqual(findNode(tree, "root", "ROOT").state, State.READY); + assert.strictEqual(findNode(tree, "sequence", "SEQUENCE").state, State.READY); + assert.strictEqual(findNode(tree, "action", "getActionResult").state, State.READY); tree.step(); - assert.strictEqual(findNode(tree, "root", "ROOT").state, mistreevous.State.SUCCEEDED); - assert.strictEqual(findNode(tree, "sequence", "SEQUENCE").state, mistreevous.State.SUCCEEDED); - assert.strictEqual(findNode(tree, "action", "getActionResult").state, mistreevous.State.SUCCEEDED); + assert.strictEqual(findNode(tree, "root", "ROOT").state, State.SUCCEEDED); + assert.strictEqual(findNode(tree, "sequence", "SEQUENCE").state, State.SUCCEEDED); + assert.strictEqual(findNode(tree, "action", "getActionResult").state, State.SUCCEEDED); tree.reset(); - assert.strictEqual(findNode(tree, "root", "ROOT").state, mistreevous.State.READY); - assert.strictEqual(findNode(tree, "sequence", "SEQUENCE").state, mistreevous.State.READY); - assert.strictEqual(findNode(tree, "action", "getActionResult").state, mistreevous.State.READY); + assert.strictEqual(findNode(tree, "root", "ROOT").state, State.READY); + assert.strictEqual(findNode(tree, "sequence", "SEQUENCE").state, State.READY); + assert.strictEqual(findNode(tree, "action", "getActionResult").state, State.READY); }); it("(JSON)", () => { - const definition = { + const definition: RootNodeDefinition = { type: "root", child: { type: "sequence", @@ -184,24 +177,24 @@ describe("A BehaviourTree instance", () => { ] } }; - const agent = { getActionResult: () => mistreevous.State.SUCCEEDED }; - const tree = new mistreevous.BehaviourTree(definition, agent); + const agent: Agent = { getActionResult: () => State.SUCCEEDED }; + const tree = new BehaviourTree(definition, agent); - assert.strictEqual(findNode(tree, "root", "ROOT").state, mistreevous.State.READY); - assert.strictEqual(findNode(tree, "sequence", "SEQUENCE").state, mistreevous.State.READY); - assert.strictEqual(findNode(tree, "action", "getActionResult").state, mistreevous.State.READY); + assert.strictEqual(findNode(tree, "root", "ROOT").state, State.READY); + assert.strictEqual(findNode(tree, "sequence", "SEQUENCE").state, State.READY); + assert.strictEqual(findNode(tree, "action", "getActionResult").state, State.READY); tree.step(); - assert.strictEqual(findNode(tree, "root", "ROOT").state, mistreevous.State.SUCCEEDED); - assert.strictEqual(findNode(tree, "sequence", "SEQUENCE").state, mistreevous.State.SUCCEEDED); - assert.strictEqual(findNode(tree, "action", "getActionResult").state, mistreevous.State.SUCCEEDED); + assert.strictEqual(findNode(tree, "root", "ROOT").state, State.SUCCEEDED); + assert.strictEqual(findNode(tree, "sequence", "SEQUENCE").state, State.SUCCEEDED); + assert.strictEqual(findNode(tree, "action", "getActionResult").state, State.SUCCEEDED); tree.reset(); - assert.strictEqual(findNode(tree, "root", "ROOT").state, mistreevous.State.READY); - assert.strictEqual(findNode(tree, "sequence", "SEQUENCE").state, mistreevous.State.READY); - assert.strictEqual(findNode(tree, "action", "getActionResult").state, mistreevous.State.READY); + assert.strictEqual(findNode(tree, "root", "ROOT").state, State.READY); + assert.strictEqual(findNode(tree, "sequence", "SEQUENCE").state, State.READY); + assert.strictEqual(findNode(tree, "action", "getActionResult").state, State.READY); }); }); @@ -209,47 +202,47 @@ describe("A BehaviourTree instance", () => { it("(MDSL)", () => { const definition = "root { sequence { action [getActionResult0] action [getActionResult1] action [getActionResult2] action [getActionResult3] } }"; - const agent = { - getActionResult0: () => mistreevous.State.SUCCEEDED, - getActionResult1: () => mistreevous.State.SUCCEEDED, - getActionResult2: () => undefined, - getActionResult3: () => mistreevous.State.SUCCEEDED + const agent: Agent = { + getActionResult0: () => State.SUCCEEDED, + getActionResult1: () => State.SUCCEEDED, + getActionResult2: () => {}, + getActionResult3: () => State.SUCCEEDED }; - const tree = new mistreevous.BehaviourTree(definition, agent); + const tree = new BehaviourTree(definition, agent); - assert.strictEqual(findNode(tree, "action", "getActionResult0").state, mistreevous.State.READY); - assert.strictEqual(findNode(tree, "action", "getActionResult1").state, mistreevous.State.READY); - assert.strictEqual(findNode(tree, "action", "getActionResult2").state, mistreevous.State.READY); - assert.strictEqual(findNode(tree, "action", "getActionResult3").state, mistreevous.State.READY); + assert.strictEqual(findNode(tree, "action", "getActionResult0").state, State.READY); + assert.strictEqual(findNode(tree, "action", "getActionResult1").state, State.READY); + assert.strictEqual(findNode(tree, "action", "getActionResult2").state, State.READY); + assert.strictEqual(findNode(tree, "action", "getActionResult3").state, State.READY); tree.step(); - assert.strictEqual(findNode(tree, "action", "getActionResult0").state, mistreevous.State.SUCCEEDED); - assert.strictEqual(findNode(tree, "action", "getActionResult1").state, mistreevous.State.SUCCEEDED); - assert.strictEqual(findNode(tree, "action", "getActionResult2").state, mistreevous.State.RUNNING); - assert.strictEqual(findNode(tree, "action", "getActionResult3").state, mistreevous.State.READY); + assert.strictEqual(findNode(tree, "action", "getActionResult0").state, State.SUCCEEDED); + assert.strictEqual(findNode(tree, "action", "getActionResult1").state, State.SUCCEEDED); + assert.strictEqual(findNode(tree, "action", "getActionResult2").state, State.RUNNING); + assert.strictEqual(findNode(tree, "action", "getActionResult3").state, State.READY); - agent.getActionResult2 = () => mistreevous.State.SUCCEEDED; + agent.getActionResult2 = () => State.SUCCEEDED; tree.step(); - assert.strictEqual(findNode(tree, "action", "getActionResult0").state, mistreevous.State.SUCCEEDED); - assert.strictEqual(findNode(tree, "action", "getActionResult1").state, mistreevous.State.SUCCEEDED); - assert.strictEqual(findNode(tree, "action", "getActionResult2").state, mistreevous.State.SUCCEEDED); - assert.strictEqual(findNode(tree, "action", "getActionResult3").state, mistreevous.State.SUCCEEDED); + assert.strictEqual(findNode(tree, "action", "getActionResult0").state, State.SUCCEEDED); + assert.strictEqual(findNode(tree, "action", "getActionResult1").state, State.SUCCEEDED); + assert.strictEqual(findNode(tree, "action", "getActionResult2").state, State.SUCCEEDED); + assert.strictEqual(findNode(tree, "action", "getActionResult3").state, State.SUCCEEDED); agent.getActionResult2 = () => undefined; tree.step(); - assert.strictEqual(findNode(tree, "action", "getActionResult0").state, mistreevous.State.SUCCEEDED); - assert.strictEqual(findNode(tree, "action", "getActionResult1").state, mistreevous.State.SUCCEEDED); - assert.strictEqual(findNode(tree, "action", "getActionResult2").state, mistreevous.State.RUNNING); - assert.strictEqual(findNode(tree, "action", "getActionResult3").state, mistreevous.State.READY); + assert.strictEqual(findNode(tree, "action", "getActionResult0").state, State.SUCCEEDED); + assert.strictEqual(findNode(tree, "action", "getActionResult1").state, State.SUCCEEDED); + assert.strictEqual(findNode(tree, "action", "getActionResult2").state, State.RUNNING); + assert.strictEqual(findNode(tree, "action", "getActionResult3").state, State.READY); }); it("(JSON)", () => { - const definition = { + const definition: RootNodeDefinition = { type: "root", child: { type: "sequence", @@ -273,43 +266,43 @@ describe("A BehaviourTree instance", () => { ] } }; - const agent = { - getActionResult0: () => mistreevous.State.SUCCEEDED, - getActionResult1: () => mistreevous.State.SUCCEEDED, - getActionResult2: () => undefined, - getActionResult3: () => mistreevous.State.SUCCEEDED + const agent: Agent = { + getActionResult0: () => State.SUCCEEDED, + getActionResult1: () => State.SUCCEEDED, + getActionResult2: () => {}, + getActionResult3: () => State.SUCCEEDED }; - const tree = new mistreevous.BehaviourTree(definition, agent); + const tree = new BehaviourTree(definition, agent); - assert.strictEqual(findNode(tree, "action", "getActionResult0").state, mistreevous.State.READY); - assert.strictEqual(findNode(tree, "action", "getActionResult1").state, mistreevous.State.READY); - assert.strictEqual(findNode(tree, "action", "getActionResult2").state, mistreevous.State.READY); - assert.strictEqual(findNode(tree, "action", "getActionResult3").state, mistreevous.State.READY); + assert.strictEqual(findNode(tree, "action", "getActionResult0").state, State.READY); + assert.strictEqual(findNode(tree, "action", "getActionResult1").state, State.READY); + assert.strictEqual(findNode(tree, "action", "getActionResult2").state, State.READY); + assert.strictEqual(findNode(tree, "action", "getActionResult3").state, State.READY); tree.step(); - assert.strictEqual(findNode(tree, "action", "getActionResult0").state, mistreevous.State.SUCCEEDED); - assert.strictEqual(findNode(tree, "action", "getActionResult1").state, mistreevous.State.SUCCEEDED); - assert.strictEqual(findNode(tree, "action", "getActionResult2").state, mistreevous.State.RUNNING); - assert.strictEqual(findNode(tree, "action", "getActionResult3").state, mistreevous.State.READY); + assert.strictEqual(findNode(tree, "action", "getActionResult0").state, State.SUCCEEDED); + assert.strictEqual(findNode(tree, "action", "getActionResult1").state, State.SUCCEEDED); + assert.strictEqual(findNode(tree, "action", "getActionResult2").state, State.RUNNING); + assert.strictEqual(findNode(tree, "action", "getActionResult3").state, State.READY); - agent.getActionResult2 = () => mistreevous.State.SUCCEEDED; + agent.getActionResult2 = () => State.SUCCEEDED; tree.step(); - assert.strictEqual(findNode(tree, "action", "getActionResult0").state, mistreevous.State.SUCCEEDED); - assert.strictEqual(findNode(tree, "action", "getActionResult1").state, mistreevous.State.SUCCEEDED); - assert.strictEqual(findNode(tree, "action", "getActionResult2").state, mistreevous.State.SUCCEEDED); - assert.strictEqual(findNode(tree, "action", "getActionResult3").state, mistreevous.State.SUCCEEDED); + assert.strictEqual(findNode(tree, "action", "getActionResult0").state, State.SUCCEEDED); + assert.strictEqual(findNode(tree, "action", "getActionResult1").state, State.SUCCEEDED); + assert.strictEqual(findNode(tree, "action", "getActionResult2").state, State.SUCCEEDED); + assert.strictEqual(findNode(tree, "action", "getActionResult3").state, State.SUCCEEDED); agent.getActionResult2 = () => undefined; tree.step(); - assert.strictEqual(findNode(tree, "action", "getActionResult0").state, mistreevous.State.SUCCEEDED); - assert.strictEqual(findNode(tree, "action", "getActionResult1").state, mistreevous.State.SUCCEEDED); - assert.strictEqual(findNode(tree, "action", "getActionResult2").state, mistreevous.State.RUNNING); - assert.strictEqual(findNode(tree, "action", "getActionResult3").state, mistreevous.State.READY); + assert.strictEqual(findNode(tree, "action", "getActionResult0").state, State.SUCCEEDED); + assert.strictEqual(findNode(tree, "action", "getActionResult1").state, State.SUCCEEDED); + assert.strictEqual(findNode(tree, "action", "getActionResult2").state, State.RUNNING); + assert.strictEqual(findNode(tree, "action", "getActionResult3").state, State.READY); }); }); }); diff --git a/test/BehaviourTreeDefinitionValidator.test.js b/test/BehaviourTreeDefinitionValidator.spec.ts similarity index 93% rename from test/BehaviourTreeDefinitionValidator.test.js rename to test/BehaviourTreeDefinitionValidator.spec.ts index b1ee0b6..640e523 100644 --- a/test/BehaviourTreeDefinitionValidator.test.js +++ b/test/BehaviourTreeDefinitionValidator.spec.ts @@ -1,13 +1,15 @@ -const mistreevous = require("../dist/index"); -const chai = require("chai"); +import { assert } from "chai"; +import sinon from "sinon"; -var assert = chai.assert; +import { BehaviourTree, State, validateDefinition } from "../src/index"; +import { RootNodeDefinition } from "../src/BehaviourTreeDefinition"; +import { Agent } from "../src/Agent"; describe("The validateDefinition function takes a tree definition as an argument and", () => { // Helper function to carry out the validation and verify the expected result. - const verifyResult = (definition, success, errorMessage) => { + const verifyResult = (definition: any, success: boolean, errorMessage: string) => { // Do the actual validation. - const result = mistreevous.validateDefinition(definition); + const result = validateDefinition(definition); // Verify the result matches the expected succeeded state and error message. assert.deepEqual(result, success ? { succeeded: true } : { succeeded: false, errorMessage }); diff --git a/test/TestUtilities.ts b/test/TestUtilities.ts new file mode 100644 index 0000000..fc05e01 --- /dev/null +++ b/test/TestUtilities.ts @@ -0,0 +1,25 @@ +import { BehaviourTree, FlattenedTreeNode } from "../src/index"; +import { AnyNodeDefinition } from "../src/BehaviourTreeDefinition"; + +/** + * Get the flattened tree node for the specified node type and caption from the given behaviour tree instance, or error if it doesn't exist. + * @param tree The behaviour tree instance. + * @param type The type of the node to get. + * @param caption The caption of the node to get. + * @returns The flattened tree node for the specified node type and caption from the given behaviour tree instance. + */ +export function findNode(tree: BehaviourTree, type: AnyNodeDefinition["type"], caption?: string): FlattenedTreeNode { + const node = tree + .getFlattenedNodeDetails() + .find((node) => node.type === type && (!caption || node.caption === caption)); + + if (!node) { + throw new Error( + caption + ? `cannot find flattened tree node with type: '${type}' caption: '${caption}'` + : `cannot find flattened tree node with type: '${type}'` + ); + } + + return node; +} diff --git a/test/mdsl/MDSLDefinitionParser.test.js b/test/mdsl/MDSLDefinitionParser.spec.ts similarity index 65% rename from test/mdsl/MDSLDefinitionParser.test.js rename to test/mdsl/MDSLDefinitionParser.spec.ts index ca4a6f9..85176e7 100644 --- a/test/mdsl/MDSLDefinitionParser.test.js +++ b/test/mdsl/MDSLDefinitionParser.spec.ts @@ -1,7 +1,6 @@ -const mistreevous = require("../../dist/index"); -const chai = require("chai"); +import { assert } from "chai"; -var assert = chai.assert; +import { findNode } from "../TestUtilities"; describe("The convertMDSLToJSON function", () => { it("does stuff", () => { diff --git a/test/nodes/composite/Lotto.test.js b/test/nodes/composite/Lotto.spec.ts similarity index 75% rename from test/nodes/composite/Lotto.test.js rename to test/nodes/composite/Lotto.spec.ts index 83af99b..455e01e 100644 --- a/test/nodes/composite/Lotto.test.js +++ b/test/nodes/composite/Lotto.spec.ts @@ -1,9 +1,9 @@ -const mistreevous = require("../../../dist/index"); -const chai = require("chai"); +import { assert } from "chai"; -var assert = chai.assert; +import { BehaviourTree, State } from "../../../src/index"; +import { RootNodeDefinition } from "../../../src/BehaviourTreeDefinition"; -const findNode = (tree, type, caption) => tree.getFlattenedNodeDetails().find((node) => node.type === type); +import { findNode } from "../../TestUtilities"; describe("A Lotto node", () => { describe("on tree initialisation", () => { @@ -11,14 +11,14 @@ describe("A Lotto node", () => { it("(MDSL)", () => { const definition = "root { lotto {} }"; assert.throws( - () => new mistreevous.BehaviourTree(definition, {}), + () => new BehaviourTree(definition, {}), Error, "invalid definition: a lotto node must have at least a single child" ); }); it("(JSON)", () => { - const definition = { + const definition: RootNodeDefinition = { type: "root", child: { type: "lotto", @@ -26,7 +26,7 @@ describe("A Lotto node", () => { } }; assert.throws( - () => new mistreevous.BehaviourTree(definition, {}), + () => new BehaviourTree(definition, {}), Error, "invalid definition: expected non-empty 'children' array to be defined for lotto node at depth '1'" ); @@ -38,35 +38,35 @@ describe("A Lotto node", () => { it("(MDSL)", () => { let definition = "root { lotto [-1] { action [SomeAction] } }"; assert.throws( - () => new mistreevous.BehaviourTree(definition, {}), + () => new BehaviourTree(definition, {}), Error, "invalid definition: lotto node weight arguments must be positive integer values" ); definition = "root { lotto [1.234] { action [SomeAction] } }"; assert.throws( - () => new mistreevous.BehaviourTree(definition, {}), + () => new BehaviourTree(definition, {}), Error, "invalid definition: lotto node weight arguments must be positive integer values" ); definition = 'root { lotto ["some-string"] { action [SomeAction] } }'; assert.throws( - () => new mistreevous.BehaviourTree(definition, {}), + () => new BehaviourTree(definition, {}), Error, "invalid definition: lotto node weight arguments must be positive integer values" ); definition = "root { lotto [false] { action [SomeAction] } }"; assert.throws( - () => new mistreevous.BehaviourTree(definition, {}), + () => new BehaviourTree(definition, {}), Error, "invalid definition: lotto node weight arguments must be positive integer values" ); }); it("(JSON)", () => { - let definition = { + let definition: RootNodeDefinition = { type: "root", child: { type: "lotto", @@ -80,7 +80,7 @@ describe("A Lotto node", () => { } }; assert.throws( - () => new mistreevous.BehaviourTree(definition, {}), + () => new BehaviourTree(definition, {}), Error, "invalid definition: expected an array of positive integer weight values with a length matching the number of child nodes for 'weights' property if defined for lotto node at depth '1'" ); @@ -99,7 +99,7 @@ describe("A Lotto node", () => { } }; assert.throws( - () => new mistreevous.BehaviourTree(definition, {}), + () => new BehaviourTree(definition, {}), Error, "invalid definition: expected an array of positive integer weight values with a length matching the number of child nodes for 'weights' property if defined for lotto node at depth '1'" ); @@ -116,9 +116,9 @@ describe("A Lotto node", () => { } ] } - }; + } as any; assert.throws( - () => new mistreevous.BehaviourTree(definition, {}), + () => new BehaviourTree(definition, {}), Error, "invalid definition: expected an array of positive integer weight values with a length matching the number of child nodes for 'weights' property if defined for lotto node at depth '1'" ); @@ -135,9 +135,9 @@ describe("A Lotto node", () => { } ] } - }; + } as any; assert.throws( - () => new mistreevous.BehaviourTree(definition, {}), + () => new BehaviourTree(definition, {}), Error, "invalid definition: expected an array of positive integer weight values with a length matching the number of child nodes for 'weights' property if defined for lotto node at depth '1'" ); @@ -148,14 +148,14 @@ describe("A Lotto node", () => { it("(MDSL)", () => { const definition = "root { lotto [1] { action [SomeAction] action [SomeOtherAction] } }"; assert.throws( - () => new mistreevous.BehaviourTree(definition, {}), + () => new BehaviourTree(definition, {}), Error, "invalid definition: expected a number of weight arguments matching the number of child nodes for lotto node" ); }); it("(JSON)", () => { - const definition = { + const definition: RootNodeDefinition = { type: "root", child: { type: "lotto", @@ -173,7 +173,7 @@ describe("A Lotto node", () => { } }; assert.throws( - () => new mistreevous.BehaviourTree(definition, {}), + () => new BehaviourTree(definition, {}), Error, "invalid definition: expected an array of positive integer weight values with a length matching the number of child nodes for 'weights' property if defined for lotto node at depth '1'" ); @@ -187,23 +187,23 @@ describe("A Lotto node", () => { it("(MDSL)", () => { const definition = "root { lotto { condition [IsTrue] } }"; const agent = { IsTrue: () => true }; - const tree = new mistreevous.BehaviourTree(definition, agent); + const tree = new BehaviourTree(definition, agent); let lottoNode = findNode(tree, "lotto"); let childNode = findNode(tree, "condition"); - assert.strictEqual(lottoNode.state, mistreevous.State.READY); - assert.strictEqual(childNode.state, mistreevous.State.READY); + assert.strictEqual(lottoNode.state, State.READY); + assert.strictEqual(childNode.state, State.READY); tree.step(); lottoNode = findNode(tree, "lotto"); childNode = findNode(tree, "condition"); - assert.strictEqual(lottoNode.state, mistreevous.State.SUCCEEDED); - assert.strictEqual(childNode.state, mistreevous.State.SUCCEEDED); + assert.strictEqual(lottoNode.state, State.SUCCEEDED); + assert.strictEqual(childNode.state, State.SUCCEEDED); }); it("(JSON)", () => { - const definition = { + const definition: RootNodeDefinition = { type: "root", child: { type: "lotto", @@ -216,19 +216,19 @@ describe("A Lotto node", () => { } }; const agent = { IsTrue: () => true }; - const tree = new mistreevous.BehaviourTree(definition, agent); + const tree = new BehaviourTree(definition, agent); let lottoNode = findNode(tree, "lotto"); let childNode = findNode(tree, "condition"); - assert.strictEqual(lottoNode.state, mistreevous.State.READY); - assert.strictEqual(childNode.state, mistreevous.State.READY); + assert.strictEqual(lottoNode.state, State.READY); + assert.strictEqual(childNode.state, State.READY); tree.step(); lottoNode = findNode(tree, "lotto"); childNode = findNode(tree, "condition"); - assert.strictEqual(lottoNode.state, mistreevous.State.SUCCEEDED); - assert.strictEqual(childNode.state, mistreevous.State.SUCCEEDED); + assert.strictEqual(lottoNode.state, State.SUCCEEDED); + assert.strictEqual(childNode.state, State.SUCCEEDED); }); }); @@ -246,21 +246,21 @@ describe("A Lotto node", () => { // lotto node is selected. A value of 0.6 should always result in the fourth child out of six being picked. random: () => 0.6 }; - const tree = new mistreevous.BehaviourTree(definition, agent, options); + const tree = new BehaviourTree(definition, agent, options); let lottoNode = findNode(tree, "lotto"); - assert.strictEqual(lottoNode.state, mistreevous.State.READY); + assert.strictEqual(lottoNode.state, State.READY); tree.step(); // Check that the lotto node has moved into the SUCCEEDED state. This would only // have happened if the fourth condition node was selected by the lotto node. lottoNode = findNode(tree, "lotto"); - assert.strictEqual(lottoNode.state, mistreevous.State.SUCCEEDED); + assert.strictEqual(lottoNode.state, State.SUCCEEDED); }); it("(JSON)", () => { - const definition = { + const definition: RootNodeDefinition = { type: "root", child: { type: "lotto", @@ -302,17 +302,17 @@ describe("A Lotto node", () => { // lotto node is selected. A value of 0.6 should always result in the fourth child out of six being picked. random: () => 0.6 }; - const tree = new mistreevous.BehaviourTree(definition, agent, options); + const tree = new BehaviourTree(definition, agent, options); let lottoNode = findNode(tree, "lotto"); - assert.strictEqual(lottoNode.state, mistreevous.State.READY); + assert.strictEqual(lottoNode.state, State.READY); tree.step(); // Check that the lotto node has moved into the SUCCEEDED state. This would only // have happened if the fourth condition node was selected by the lotto node. lottoNode = findNode(tree, "lotto"); - assert.strictEqual(lottoNode.state, mistreevous.State.SUCCEEDED); + assert.strictEqual(lottoNode.state, State.SUCCEEDED); }); }); @@ -324,23 +324,23 @@ describe("A Lotto node", () => { it("(MDSL)", () => { const definition = "root { lotto { condition [IsTrue] } }"; const agent = { IsTrue: () => true }; - const tree = new mistreevous.BehaviourTree(definition, agent); + const tree = new BehaviourTree(definition, agent); let lottoNode = findNode(tree, "lotto"); let childNode = findNode(tree, "condition"); - assert.strictEqual(lottoNode.state, mistreevous.State.READY); - assert.strictEqual(childNode.state, mistreevous.State.READY); + assert.strictEqual(lottoNode.state, State.READY); + assert.strictEqual(childNode.state, State.READY); tree.step(); lottoNode = findNode(tree, "lotto"); childNode = findNode(tree, "condition"); - assert.strictEqual(lottoNode.state, mistreevous.State.SUCCEEDED); - assert.strictEqual(childNode.state, mistreevous.State.SUCCEEDED); + assert.strictEqual(lottoNode.state, State.SUCCEEDED); + assert.strictEqual(childNode.state, State.SUCCEEDED); }); it("(JSON)", () => { - const definition = { + const definition: RootNodeDefinition = { type: "root", child: { type: "lotto", @@ -353,19 +353,19 @@ describe("A Lotto node", () => { } }; const agent = { IsTrue: () => true }; - const tree = new mistreevous.BehaviourTree(definition, agent); + const tree = new BehaviourTree(definition, agent); let lottoNode = findNode(tree, "lotto"); let childNode = findNode(tree, "condition"); - assert.strictEqual(lottoNode.state, mistreevous.State.READY); - assert.strictEqual(childNode.state, mistreevous.State.READY); + assert.strictEqual(lottoNode.state, State.READY); + assert.strictEqual(childNode.state, State.READY); tree.step(); lottoNode = findNode(tree, "lotto"); childNode = findNode(tree, "condition"); - assert.strictEqual(lottoNode.state, mistreevous.State.SUCCEEDED); - assert.strictEqual(childNode.state, mistreevous.State.SUCCEEDED); + assert.strictEqual(lottoNode.state, State.SUCCEEDED); + assert.strictEqual(childNode.state, State.SUCCEEDED); }); }); @@ -373,23 +373,23 @@ describe("A Lotto node", () => { it("(MDSL)", () => { const definition = "root { lotto { condition [IsFalse] } }"; const agent = { IsFalse: () => false }; - const tree = new mistreevous.BehaviourTree(definition, agent); + const tree = new BehaviourTree(definition, agent); let lottoNode = findNode(tree, "lotto"); let childNode = findNode(tree, "condition"); - assert.strictEqual(lottoNode.state, mistreevous.State.READY); - assert.strictEqual(childNode.state, mistreevous.State.READY); + assert.strictEqual(lottoNode.state, State.READY); + assert.strictEqual(childNode.state, State.READY); tree.step(); lottoNode = findNode(tree, "lotto"); childNode = findNode(tree, "condition"); - assert.strictEqual(lottoNode.state, mistreevous.State.FAILED); - assert.strictEqual(childNode.state, mistreevous.State.FAILED); + assert.strictEqual(lottoNode.state, State.FAILED); + assert.strictEqual(childNode.state, State.FAILED); }); it("(JSON)", () => { - const definition = { + const definition: RootNodeDefinition = { type: "root", child: { type: "lotto", @@ -402,19 +402,19 @@ describe("A Lotto node", () => { } }; const agent = { IsFalse: () => false }; - const tree = new mistreevous.BehaviourTree(definition, agent); + const tree = new BehaviourTree(definition, agent); let lottoNode = findNode(tree, "lotto"); let childNode = findNode(tree, "condition"); - assert.strictEqual(lottoNode.state, mistreevous.State.READY); - assert.strictEqual(childNode.state, mistreevous.State.READY); + assert.strictEqual(lottoNode.state, State.READY); + assert.strictEqual(childNode.state, State.READY); tree.step(); lottoNode = findNode(tree, "lotto"); childNode = findNode(tree, "condition"); - assert.strictEqual(lottoNode.state, mistreevous.State.FAILED); - assert.strictEqual(childNode.state, mistreevous.State.FAILED); + assert.strictEqual(lottoNode.state, State.FAILED); + assert.strictEqual(childNode.state, State.FAILED); }); }); @@ -422,23 +422,23 @@ describe("A Lotto node", () => { it("(MDSL)", () => { const definition = "root { lotto { action [someAction] } }"; const agent = { someAction: () => {} }; - const tree = new mistreevous.BehaviourTree(definition, agent); + const tree = new BehaviourTree(definition, agent); let lottoNode = findNode(tree, "lotto"); let actionNode = findNode(tree, "action"); - assert.strictEqual(lottoNode.state, mistreevous.State.READY); - assert.strictEqual(actionNode.state, mistreevous.State.READY); + assert.strictEqual(lottoNode.state, State.READY); + assert.strictEqual(actionNode.state, State.READY); tree.step(); lottoNode = findNode(tree, "lotto"); actionNode = findNode(tree, "action"); - assert.strictEqual(lottoNode.state, mistreevous.State.RUNNING); - assert.strictEqual(actionNode.state, mistreevous.State.RUNNING); + assert.strictEqual(lottoNode.state, State.RUNNING); + assert.strictEqual(actionNode.state, State.RUNNING); }); it("(JSON)", () => { - const definition = { + const definition: RootNodeDefinition = { type: "root", child: { type: "lotto", @@ -451,19 +451,19 @@ describe("A Lotto node", () => { } }; const agent = { someAction: () => {} }; - const tree = new mistreevous.BehaviourTree(definition, agent); + const tree = new BehaviourTree(definition, agent); let lottoNode = findNode(tree, "lotto"); let actionNode = findNode(tree, "action"); - assert.strictEqual(lottoNode.state, mistreevous.State.READY); - assert.strictEqual(actionNode.state, mistreevous.State.READY); + assert.strictEqual(lottoNode.state, State.READY); + assert.strictEqual(actionNode.state, State.READY); tree.step(); lottoNode = findNode(tree, "lotto"); actionNode = findNode(tree, "action"); - assert.strictEqual(lottoNode.state, mistreevous.State.RUNNING); - assert.strictEqual(actionNode.state, mistreevous.State.RUNNING); + assert.strictEqual(lottoNode.state, State.RUNNING); + assert.strictEqual(actionNode.state, State.RUNNING); }); }); }); diff --git a/test/nodes/composite/Parallel.test.js b/test/nodes/composite/Parallel.spec.ts similarity index 71% rename from test/nodes/composite/Parallel.test.js rename to test/nodes/composite/Parallel.spec.ts index 4899487..68c6af4 100644 --- a/test/nodes/composite/Parallel.test.js +++ b/test/nodes/composite/Parallel.spec.ts @@ -1,7 +1,9 @@ -const mistreevous = require("../../../dist/index"); -const chai = require("chai"); +import { assert } from "chai"; -var assert = chai.assert; +import { BehaviourTree, State } from "../../../src/index"; +import { RootNodeDefinition } from "../../../src/BehaviourTreeDefinition"; + +import { findNode } from "../../TestUtilities"; describe("A Parallel node", () => { describe("on tree initialisation", () => { @@ -9,14 +11,14 @@ describe("A Parallel node", () => { it("(MDSL)", () => { const definition = "root { parallel {} }"; assert.throws( - () => new mistreevous.BehaviourTree(definition, {}), + () => new BehaviourTree(definition, {}), Error, "invalid definition: a parallel node must have at least a single child" ); }); it("(JSON)", () => { - const definition = { + const definition: RootNodeDefinition = { type: "root", child: { type: "parallel", @@ -24,7 +26,7 @@ describe("A Parallel node", () => { } }; assert.throws( - () => new mistreevous.BehaviourTree(definition, {}), + () => new BehaviourTree(definition, {}), Error, "invalid definition: expected non-empty 'children' array to be defined for parallel node at depth '1'" ); diff --git a/test/nodes/composite/Selector.test.js b/test/nodes/composite/Selector.spec.ts similarity index 67% rename from test/nodes/composite/Selector.test.js rename to test/nodes/composite/Selector.spec.ts index 99cf463..e662c1c 100644 --- a/test/nodes/composite/Selector.test.js +++ b/test/nodes/composite/Selector.spec.ts @@ -1,10 +1,10 @@ -const mistreevous = require("../../../dist/index"); -const chai = require("chai"); +import { assert } from "chai"; -var assert = chai.assert; +import { BehaviourTree, State } from "../../../src/index"; +import { RootNodeDefinition } from "../../../src/BehaviourTreeDefinition"; +import { Agent } from "../../../src/Agent"; -const findNode = (tree, type, caption) => - tree.getFlattenedNodeDetails().find((node) => node.type === type && node.caption === caption); +import { findNode } from "../../TestUtilities"; describe("A Selector node", () => { describe("on tree initialisation", () => { @@ -12,14 +12,14 @@ describe("A Selector node", () => { it("(MDSL)", () => { const definition = "root { selector {} }"; assert.throws( - () => new mistreevous.BehaviourTree(definition, {}), + () => new BehaviourTree(definition, {}), Error, "invalid definition: a selector node must have at least a single child" ); }); it("(JSON)", () => { - const definition = { + const definition: RootNodeDefinition = { type: "root", child: { type: "selector", @@ -27,7 +27,7 @@ describe("A Selector node", () => { } }; assert.throws( - () => new mistreevous.BehaviourTree(definition, {}), + () => new BehaviourTree(definition, {}), Error, "invalid definition: expected non-empty 'children' array to be defined for selector node at depth '1'" ); @@ -44,30 +44,30 @@ describe("A Selector node", () => { it("(MDSL)", () => { const definition = "root { selector { action [actionFail] action [actionRunning] action [actionSucceed] } }"; - const agent = { - actionSucceed: () => mistreevous.State.SUCCEEDED, + const agent: Agent = { + actionSucceed: () => State.SUCCEEDED, actionRunning: () => {}, - actionFail: () => mistreevous.State.FAILED + actionFail: () => State.FAILED }; - const tree = new mistreevous.BehaviourTree(definition, agent); + const tree = new BehaviourTree(definition, agent); - assert.strictEqual(findNode(tree, "root", "ROOT").state, mistreevous.State.READY); - assert.strictEqual(findNode(tree, "selector", "SELECTOR").state, mistreevous.State.READY); - assert.strictEqual(findNode(tree, "action", "actionFail").state, mistreevous.State.READY); - assert.strictEqual(findNode(tree, "action", "actionRunning").state, mistreevous.State.READY); - assert.strictEqual(findNode(tree, "action", "actionSucceed").state, mistreevous.State.READY); + assert.strictEqual(findNode(tree, "root", "ROOT").state, State.READY); + assert.strictEqual(findNode(tree, "selector", "SELECTOR").state, State.READY); + assert.strictEqual(findNode(tree, "action", "actionFail").state, State.READY); + assert.strictEqual(findNode(tree, "action", "actionRunning").state, State.READY); + assert.strictEqual(findNode(tree, "action", "actionSucceed").state, State.READY); tree.step(); - assert.strictEqual(findNode(tree, "root", "ROOT").state, mistreevous.State.RUNNING); - assert.strictEqual(findNode(tree, "selector", "SELECTOR").state, mistreevous.State.RUNNING); - assert.strictEqual(findNode(tree, "action", "actionFail").state, mistreevous.State.FAILED); - assert.strictEqual(findNode(tree, "action", "actionRunning").state, mistreevous.State.RUNNING); - assert.strictEqual(findNode(tree, "action", "actionSucceed").state, mistreevous.State.READY); + assert.strictEqual(findNode(tree, "root", "ROOT").state, State.RUNNING); + assert.strictEqual(findNode(tree, "selector", "SELECTOR").state, State.RUNNING); + assert.strictEqual(findNode(tree, "action", "actionFail").state, State.FAILED); + assert.strictEqual(findNode(tree, "action", "actionRunning").state, State.RUNNING); + assert.strictEqual(findNode(tree, "action", "actionSucceed").state, State.READY); }); it("(JSON)", () => { - const definition = { + const definition: RootNodeDefinition = { type: "root", child: { type: "selector", @@ -87,26 +87,26 @@ describe("A Selector node", () => { ] } }; - const agent = { - actionSucceed: () => mistreevous.State.SUCCEEDED, + const agent: Agent = { + actionSucceed: () => State.SUCCEEDED, actionRunning: () => {}, - actionFail: () => mistreevous.State.FAILED + actionFail: () => State.FAILED }; - const tree = new mistreevous.BehaviourTree(definition, agent); + const tree = new BehaviourTree(definition, agent); - assert.strictEqual(findNode(tree, "root", "ROOT").state, mistreevous.State.READY); - assert.strictEqual(findNode(tree, "selector", "SELECTOR").state, mistreevous.State.READY); - assert.strictEqual(findNode(tree, "action", "actionFail").state, mistreevous.State.READY); - assert.strictEqual(findNode(tree, "action", "actionRunning").state, mistreevous.State.READY); - assert.strictEqual(findNode(tree, "action", "actionSucceed").state, mistreevous.State.READY); + assert.strictEqual(findNode(tree, "root", "ROOT").state, State.READY); + assert.strictEqual(findNode(tree, "selector", "SELECTOR").state, State.READY); + assert.strictEqual(findNode(tree, "action", "actionFail").state, State.READY); + assert.strictEqual(findNode(tree, "action", "actionRunning").state, State.READY); + assert.strictEqual(findNode(tree, "action", "actionSucceed").state, State.READY); tree.step(); - assert.strictEqual(findNode(tree, "root", "ROOT").state, mistreevous.State.RUNNING); - assert.strictEqual(findNode(tree, "selector", "SELECTOR").state, mistreevous.State.RUNNING); - assert.strictEqual(findNode(tree, "action", "actionFail").state, mistreevous.State.FAILED); - assert.strictEqual(findNode(tree, "action", "actionRunning").state, mistreevous.State.RUNNING); - assert.strictEqual(findNode(tree, "action", "actionSucceed").state, mistreevous.State.READY); + assert.strictEqual(findNode(tree, "root", "ROOT").state, State.RUNNING); + assert.strictEqual(findNode(tree, "selector", "SELECTOR").state, State.RUNNING); + assert.strictEqual(findNode(tree, "action", "actionFail").state, State.FAILED); + assert.strictEqual(findNode(tree, "action", "actionRunning").state, State.RUNNING); + assert.strictEqual(findNode(tree, "action", "actionSucceed").state, State.READY); }); }); }); diff --git a/test/nodes/composite/Sequence.test.js b/test/nodes/composite/Sequence.spec.ts similarity index 71% rename from test/nodes/composite/Sequence.test.js rename to test/nodes/composite/Sequence.spec.ts index 4be3a2f..5bfde86 100644 --- a/test/nodes/composite/Sequence.test.js +++ b/test/nodes/composite/Sequence.spec.ts @@ -1,7 +1,9 @@ -const mistreevous = require("../../../dist/index"); -const chai = require("chai"); +import { assert } from "chai"; -var assert = chai.assert; +import { BehaviourTree, State } from "../../../src/index"; +import { RootNodeDefinition } from "../../../src/BehaviourTreeDefinition"; + +import { findNode } from "../../TestUtilities"; describe("A Sequence node", () => { describe("on tree initialisation", () => { @@ -9,14 +11,14 @@ describe("A Sequence node", () => { it("(MDSL)", () => { const definition = "root { sequence {} }"; assert.throws( - () => new mistreevous.BehaviourTree(definition, {}), + () => new BehaviourTree(definition, {}), Error, "invalid definition: a sequence node must have at least a single child" ); }); it("(JSON)", () => { - const definition = { + const definition: RootNodeDefinition = { type: "root", child: { type: "sequence", @@ -24,7 +26,7 @@ describe("A Sequence node", () => { } }; assert.throws( - () => new mistreevous.BehaviourTree(definition, {}), + () => new BehaviourTree(definition, {}), Error, "invalid definition: expected non-empty 'children' array to be defined for sequence node at depth '1'" ); diff --git a/test/nodes/decorator/Fail.test.js b/test/nodes/decorator/Fail.spec.ts similarity index 63% rename from test/nodes/decorator/Fail.test.js rename to test/nodes/decorator/Fail.spec.ts index 1f0bc00..bc644a3 100644 --- a/test/nodes/decorator/Fail.test.js +++ b/test/nodes/decorator/Fail.spec.ts @@ -1,10 +1,10 @@ -const mistreevous = require("../../../dist/index"); -const chai = require("chai"); +import { assert } from "chai"; -var assert = chai.assert; +import { BehaviourTree, State } from "../../../src/index"; +import { RootNodeDefinition } from "../../../src/BehaviourTreeDefinition"; +import { Agent } from "../../../src/Agent"; -const findNode = (tree, type, caption) => - tree.getFlattenedNodeDetails().find((node) => node.type === type && node.caption === caption); +import { findNode } from "../../TestUtilities"; describe("A Fail node", () => { describe("on tree initialisation", () => { @@ -12,7 +12,7 @@ describe("A Fail node", () => { it("(MDSL)", () => { const definition = "root { fail {} }"; assert.throws( - () => new mistreevous.BehaviourTree(definition, {}), + () => new BehaviourTree(definition, {}), Error, "invalid definition: a fail node must have a single child" ); @@ -24,9 +24,9 @@ describe("A Fail node", () => { child: { type: "fail" } - }; + } as any; assert.throws( - () => new mistreevous.BehaviourTree(definition, {}), + () => new BehaviourTree(definition, {}), Error, "invalid definition: expected property 'child' to be defined for fail node at depth '1'" ); @@ -40,19 +40,19 @@ describe("A Fail node", () => { it("(MDSL)", () => { const definition = "root { fail { condition [someCondition] } }"; const agent = { someCondition: () => false }; - const tree = new mistreevous.BehaviourTree(definition, agent); + const tree = new BehaviourTree(definition, agent); - let node = findNode(tree, "fail", "FAIL"); - assert.strictEqual(node.state, mistreevous.State.READY); + let node = findNode(tree, "fail"); + assert.strictEqual(node.state, State.READY); tree.step(); - node = findNode(tree, "fail", "FAIL"); - assert.strictEqual(node.state, mistreevous.State.FAILED); + node = findNode(tree, "fail"); + assert.strictEqual(node.state, State.FAILED); }); it("(JSON)", () => { - const definition = { + const definition: RootNodeDefinition = { type: "root", child: { type: "fail", @@ -63,15 +63,15 @@ describe("A Fail node", () => { } }; const agent = { someCondition: () => false }; - const tree = new mistreevous.BehaviourTree(definition, agent); + const tree = new BehaviourTree(definition, agent); - let node = findNode(tree, "fail", "FAIL"); - assert.strictEqual(node.state, mistreevous.State.READY); + let node = findNode(tree, "fail"); + assert.strictEqual(node.state, State.READY); tree.step(); - node = findNode(tree, "fail", "FAIL"); - assert.strictEqual(node.state, mistreevous.State.FAILED); + node = findNode(tree, "fail"); + assert.strictEqual(node.state, State.FAILED); }); }); @@ -79,19 +79,19 @@ describe("A Fail node", () => { it("(MDSL)", () => { const definition = "root { fail { condition [someCondition] } }"; const agent = { someCondition: () => true }; - const tree = new mistreevous.BehaviourTree(definition, agent); + const tree = new BehaviourTree(definition, agent); let node = findNode(tree, "fail", "FAIL"); - assert.strictEqual(node.state, mistreevous.State.READY); + assert.strictEqual(node.state, State.READY); tree.step(); node = findNode(tree, "fail", "FAIL"); - assert.strictEqual(node.state, mistreevous.State.FAILED); + assert.strictEqual(node.state, State.FAILED); }); it("(JSON)", () => { - const definition = { + const definition: RootNodeDefinition = { type: "root", child: { type: "fail", @@ -102,15 +102,15 @@ describe("A Fail node", () => { } }; const agent = { someCondition: () => true }; - const tree = new mistreevous.BehaviourTree(definition, agent); + const tree = new BehaviourTree(definition, agent); let node = findNode(tree, "fail", "FAIL"); - assert.strictEqual(node.state, mistreevous.State.READY); + assert.strictEqual(node.state, State.READY); tree.step(); node = findNode(tree, "fail", "FAIL"); - assert.strictEqual(node.state, mistreevous.State.FAILED); + assert.strictEqual(node.state, State.FAILED); }); }); }); @@ -119,19 +119,19 @@ describe("A Fail node", () => { it("(MDSL)", () => { const definition = "root { fail { action [someAction] } }"; const agent = { someAction: () => {} }; - const tree = new mistreevous.BehaviourTree(definition, agent); + const tree = new BehaviourTree(definition, agent); let node = findNode(tree, "fail", "FAIL"); - assert.strictEqual(node.state, mistreevous.State.READY); + assert.strictEqual(node.state, State.READY); tree.step(); node = findNode(tree, "fail", "FAIL"); - assert.strictEqual(node.state, mistreevous.State.RUNNING); + assert.strictEqual(node.state, State.RUNNING); }); it("(JSON)", () => { - const definition = { + const definition: RootNodeDefinition = { type: "root", child: { type: "fail", @@ -142,15 +142,15 @@ describe("A Fail node", () => { } }; const agent = { someAction: () => {} }; - const tree = new mistreevous.BehaviourTree(definition, agent); + const tree = new BehaviourTree(definition, agent); let node = findNode(tree, "fail", "FAIL"); - assert.strictEqual(node.state, mistreevous.State.READY); + assert.strictEqual(node.state, State.READY); tree.step(); node = findNode(tree, "fail", "FAIL"); - assert.strictEqual(node.state, mistreevous.State.RUNNING); + assert.strictEqual(node.state, State.RUNNING); }); }); }); diff --git a/test/nodes/decorator/Flip.test.js b/test/nodes/decorator/Flip.spec.ts similarity index 67% rename from test/nodes/decorator/Flip.test.js rename to test/nodes/decorator/Flip.spec.ts index 8cc05a5..3bb737d 100644 --- a/test/nodes/decorator/Flip.test.js +++ b/test/nodes/decorator/Flip.spec.ts @@ -1,10 +1,10 @@ -const mistreevous = require("../../../dist/index"); -const chai = require("chai"); +import { assert } from "chai"; -var assert = chai.assert; +import { BehaviourTree, State } from "../../../src/index"; +import { RootNodeDefinition } from "../../../src/BehaviourTreeDefinition"; +import { Agent } from "../../../src/Agent"; -const findNode = (tree, type, caption) => - tree.getFlattenedNodeDetails().find((node) => node.type === type && node.caption === caption); +import { findNode } from "../../TestUtilities"; describe("A Flip node", () => { describe("on tree initialisation", () => { @@ -12,7 +12,7 @@ describe("A Flip node", () => { it("(MDSL)", () => { const definition = "root { flip {} }"; assert.throws( - () => new mistreevous.BehaviourTree(definition, {}), + () => new BehaviourTree(definition, {}), Error, "invalid definition: a flip node must have a single child" ); @@ -24,9 +24,9 @@ describe("A Flip node", () => { child: { type: "flip" } - }; + } as any; assert.throws( - () => new mistreevous.BehaviourTree(definition, {}), + () => new BehaviourTree(definition, {}), Error, "invalid definition: expected property 'child' to be defined for flip node at depth '1'" ); @@ -39,19 +39,19 @@ describe("A Flip node", () => { it("(MDSL)", () => { const definition = "root { flip { condition [someCondition] } }"; const agent = { someCondition: () => false }; - const tree = new mistreevous.BehaviourTree(definition, agent); + const tree = new BehaviourTree(definition, agent); let node = findNode(tree, "flip", "FLIP"); - assert.strictEqual(node.state, mistreevous.State.READY); + assert.strictEqual(node.state, State.READY); tree.step(); node = findNode(tree, "flip", "FLIP"); - assert.strictEqual(node.state, mistreevous.State.SUCCEEDED); + assert.strictEqual(node.state, State.SUCCEEDED); }); it("(JSON)", () => { - const definition = { + const definition: RootNodeDefinition = { type: "root", child: { type: "flip", @@ -62,15 +62,15 @@ describe("A Flip node", () => { } }; const agent = { someCondition: () => false }; - const tree = new mistreevous.BehaviourTree(definition, agent); + const tree = new BehaviourTree(definition, agent); let node = findNode(tree, "flip", "FLIP"); - assert.strictEqual(node.state, mistreevous.State.READY); + assert.strictEqual(node.state, State.READY); tree.step(); node = findNode(tree, "flip", "FLIP"); - assert.strictEqual(node.state, mistreevous.State.SUCCEEDED); + assert.strictEqual(node.state, State.SUCCEEDED); }); }); @@ -78,19 +78,19 @@ describe("A Flip node", () => { it("(MDSL)", () => { const definition = "root { flip { condition [someCondition] } }"; const agent = { someCondition: () => true }; - const tree = new mistreevous.BehaviourTree(definition, agent); + const tree = new BehaviourTree(definition, agent); let node = findNode(tree, "flip", "FLIP"); - assert.strictEqual(node.state, mistreevous.State.READY); + assert.strictEqual(node.state, State.READY); tree.step(); node = findNode(tree, "flip", "FLIP"); - assert.strictEqual(node.state, mistreevous.State.FAILED); + assert.strictEqual(node.state, State.FAILED); }); it("(JSON)", () => { - const definition = { + const definition: RootNodeDefinition = { type: "root", child: { type: "flip", @@ -101,15 +101,15 @@ describe("A Flip node", () => { } }; const agent = { someCondition: () => true }; - const tree = new mistreevous.BehaviourTree(definition, agent); + const tree = new BehaviourTree(definition, agent); let node = findNode(tree, "flip", "FLIP"); - assert.strictEqual(node.state, mistreevous.State.READY); + assert.strictEqual(node.state, State.READY); tree.step(); node = findNode(tree, "flip", "FLIP"); - assert.strictEqual(node.state, mistreevous.State.FAILED); + assert.strictEqual(node.state, State.FAILED); }); }); @@ -117,19 +117,19 @@ describe("A Flip node", () => { it("(MDSL)", () => { const definition = "root { flip { action [someAction] } }"; const agent = { someAction: () => {} }; - const tree = new mistreevous.BehaviourTree(definition, agent); + const tree = new BehaviourTree(definition, agent); let node = findNode(tree, "flip", "FLIP"); - assert.strictEqual(node.state, mistreevous.State.READY); + assert.strictEqual(node.state, State.READY); tree.step(); node = findNode(tree, "flip", "FLIP"); - assert.strictEqual(node.state, mistreevous.State.RUNNING); + assert.strictEqual(node.state, State.RUNNING); }); it("(JSON)", () => { - const definition = { + const definition: RootNodeDefinition = { type: "root", child: { type: "flip", @@ -140,15 +140,15 @@ describe("A Flip node", () => { } }; const agent = { someAction: () => {} }; - const tree = new mistreevous.BehaviourTree(definition, agent); + const tree = new BehaviourTree(definition, agent); let node = findNode(tree, "flip", "FLIP"); - assert.strictEqual(node.state, mistreevous.State.READY); + assert.strictEqual(node.state, State.READY); tree.step(); node = findNode(tree, "flip", "FLIP"); - assert.strictEqual(node.state, mistreevous.State.RUNNING); + assert.strictEqual(node.state, State.RUNNING); }); }); }); diff --git a/test/nodes/decorator/Repeat.test.js b/test/nodes/decorator/Repeat.spec.ts similarity index 67% rename from test/nodes/decorator/Repeat.test.js rename to test/nodes/decorator/Repeat.spec.ts index 764cc33..594a455 100644 --- a/test/nodes/decorator/Repeat.test.js +++ b/test/nodes/decorator/Repeat.spec.ts @@ -1,18 +1,18 @@ -const mistreevous = require("../../../dist/index"); -const chai = require("chai"); -const sinon = require("sinon"); +import { assert } from "chai"; +import sinon, { SinonSandbox } from "sinon"; -var assert = chai.assert; +import { BehaviourTree, State } from "../../../src/index"; +import { RootNodeDefinition } from "../../../src/BehaviourTreeDefinition"; +import { Agent } from "../../../src/Agent"; -const findNode = (tree, type, caption) => - tree.getFlattenedNodeDetails().find((node) => node.type === type && node.caption === caption); +import { findNode } from "../../TestUtilities"; describe("A Repeat node", () => { describe("on tree initialisation", () => { it("will error if the node does not have a single child", () => { const definition = "root { repeat {} }"; assert.throws( - () => new mistreevous.BehaviourTree(definition, {}), + () => new BehaviourTree(definition, {}), Error, "invalid definition: a repeat node must have a single child" ); @@ -20,7 +20,7 @@ describe("A Repeat node", () => { }); describe("when updated as part of a tree step", () => { - var sandbox; + var sandbox: SinonSandbox; beforeEach(() => { sandbox = sinon.createSandbox(); @@ -32,61 +32,61 @@ describe("A Repeat node", () => { it("will move to the FAILED state if the child node moves to the FAILED state", () => { const definition = "root { repeat { condition [someCondition] } }"; const agent = { someCondition: () => false }; - const tree = new mistreevous.BehaviourTree(definition, agent); + const tree = new BehaviourTree(definition, agent); let node = findNode(tree, "repeat", "REPEAT"); assert.exists(node); - assert.strictEqual(node.state, mistreevous.State.READY); + assert.strictEqual(node.state, State.READY); tree.step(); node = findNode(tree, "repeat", "REPEAT"); - assert.strictEqual(node.state, mistreevous.State.FAILED); + assert.strictEqual(node.state, State.FAILED); }); it("will move to the RUNNING state if the child node moves to the SUCCEEDED state", () => { const definition = "root { repeat { condition [someCondition] } }"; const agent = { someCondition: () => true }; - const tree = new mistreevous.BehaviourTree(definition, agent); + const tree = new BehaviourTree(definition, agent); let node = findNode(tree, "repeat", "REPEAT"); assert.exists(node); - assert.strictEqual(node.state, mistreevous.State.READY); + assert.strictEqual(node.state, State.READY); tree.step(); node = findNode(tree, "repeat", "REPEAT"); - assert.strictEqual(node.state, mistreevous.State.RUNNING); + assert.strictEqual(node.state, State.RUNNING); }); it("and an iteration count node argument is defined will attempt to re-run the child node until the iteration count is reached", () => { const definition = "root { repeat [3] { condition [someCondition] } }"; const agent = { someCondition: () => true }; - const tree = new mistreevous.BehaviourTree(definition, agent); + const tree = new BehaviourTree(definition, agent); let node = findNode(tree, "repeat", "REPEAT 3x"); assert.exists(node); - assert.strictEqual(node.state, mistreevous.State.READY); + assert.strictEqual(node.state, State.READY); tree.step(); node = findNode(tree, "repeat", "REPEAT 3x"); - assert.strictEqual(node.state, mistreevous.State.RUNNING); + assert.strictEqual(node.state, State.RUNNING); tree.step(); node = findNode(tree, "repeat", "REPEAT 3x"); - assert.strictEqual(node.state, mistreevous.State.RUNNING); + assert.strictEqual(node.state, State.RUNNING); tree.step(); node = findNode(tree, "repeat", "REPEAT 3x"); - assert.strictEqual(node.state, mistreevous.State.RUNNING); + assert.strictEqual(node.state, State.RUNNING); tree.step(); node = findNode(tree, "repeat", "REPEAT 3x"); - assert.strictEqual(node.state, mistreevous.State.SUCCEEDED); + assert.strictEqual(node.state, State.SUCCEEDED); }); describe("and minumum and maximum iteration count node arguments are defined", () => { @@ -94,36 +94,36 @@ describe("A Repeat node", () => { // We have spied on Math.random to always return 0.5 for the sake of this test, so our iteration count should always be 4. const definition = "root { repeat [2, 6] { condition [someCondition] } }"; const agent = { someCondition: () => true }; - const tree = new mistreevous.BehaviourTree(definition, agent); + const tree = new BehaviourTree(definition, agent); let node = findNode(tree, "repeat", "REPEAT 2x-6x"); assert.exists(node); - assert.strictEqual(node.state, mistreevous.State.READY); + assert.strictEqual(node.state, State.READY); tree.step(); node = findNode(tree, "repeat", "REPEAT 2x-6x"); - assert.strictEqual(node.state, mistreevous.State.RUNNING); + assert.strictEqual(node.state, State.RUNNING); tree.step(); node = findNode(tree, "repeat", "REPEAT 2x-6x"); - assert.strictEqual(node.state, mistreevous.State.RUNNING); + assert.strictEqual(node.state, State.RUNNING); tree.step(); node = findNode(tree, "repeat", "REPEAT 2x-6x"); - assert.strictEqual(node.state, mistreevous.State.RUNNING); + assert.strictEqual(node.state, State.RUNNING); tree.step(); node = findNode(tree, "repeat", "REPEAT 2x-6x"); - assert.strictEqual(node.state, mistreevous.State.RUNNING); + assert.strictEqual(node.state, State.RUNNING); tree.step(); node = findNode(tree, "repeat", "REPEAT 2x-6x"); - assert.strictEqual(node.state, mistreevous.State.SUCCEEDED); + assert.strictEqual(node.state, State.SUCCEEDED); }); it("and if the 'random' behaviour tree option is defined will use it to pick an iteration count from between the minimum and maximum bounds", () => { @@ -135,31 +135,31 @@ describe("A Repeat node", () => { // A value of 0.2 should always result in an iteration count of 3. random: () => 0.2 }; - const tree = new mistreevous.BehaviourTree(definition, agent, options); + const tree = new BehaviourTree(definition, agent, options); let node = findNode(tree, "repeat", "REPEAT 2x-10x"); assert.exists(node); - assert.strictEqual(node.state, mistreevous.State.READY); + assert.strictEqual(node.state, State.READY); tree.step(); node = findNode(tree, "repeat", "REPEAT 2x-10x"); - assert.strictEqual(node.state, mistreevous.State.RUNNING); + assert.strictEqual(node.state, State.RUNNING); tree.step(); node = findNode(tree, "repeat", "REPEAT 2x-10x"); - assert.strictEqual(node.state, mistreevous.State.RUNNING); + assert.strictEqual(node.state, State.RUNNING); tree.step(); node = findNode(tree, "repeat", "REPEAT 2x-10x"); - assert.strictEqual(node.state, mistreevous.State.RUNNING); + assert.strictEqual(node.state, State.RUNNING); tree.step(); node = findNode(tree, "repeat", "REPEAT 2x-10x"); - assert.strictEqual(node.state, mistreevous.State.SUCCEEDED); + assert.strictEqual(node.state, State.SUCCEEDED); }); }); }); diff --git a/test/nodes/decorator/Retry.test.js b/test/nodes/decorator/Retry.spec.ts similarity index 67% rename from test/nodes/decorator/Retry.test.js rename to test/nodes/decorator/Retry.spec.ts index 791b517..e207d6b 100644 --- a/test/nodes/decorator/Retry.test.js +++ b/test/nodes/decorator/Retry.spec.ts @@ -1,18 +1,18 @@ -const mistreevous = require("../../../dist/index"); -const chai = require("chai"); -const sinon = require("sinon"); +import { assert } from "chai"; +import sinon, { SinonSandbox } from "sinon"; -var assert = chai.assert; +import { BehaviourTree, State } from "../../../src/index"; +import { RootNodeDefinition } from "../../../src/BehaviourTreeDefinition"; +import { Agent } from "../../../src/Agent"; -const findNode = (tree, type, caption) => - tree.getFlattenedNodeDetails().find((node) => node.type === type && node.caption === caption); +import { findNode } from "../../TestUtilities"; describe("A Retry node", () => { describe("on tree initialisation", () => { it("will error if the node does not have a single child", () => { const definition = "root { retry {} }"; assert.throws( - () => new mistreevous.BehaviourTree(definition, {}), + () => new BehaviourTree(definition, {}), Error, "invalid definition: a retry node must have a single child" ); @@ -20,7 +20,7 @@ describe("A Retry node", () => { }); describe("when updated as part of a tree step", () => { - var sandbox; + var sandbox: SinonSandbox; beforeEach(() => { sandbox = sinon.createSandbox(); @@ -32,61 +32,61 @@ describe("A Retry node", () => { it("will move to the SUCCEEDED state if the child node moves to the SUCCEEDED state", () => { const definition = "root { retry { condition [someCondition] } }"; const agent = { someCondition: () => true }; - const tree = new mistreevous.BehaviourTree(definition, agent); + const tree = new BehaviourTree(definition, agent); let node = findNode(tree, "retry", "RETRY"); assert.exists(node); - assert.strictEqual(node.state, mistreevous.State.READY); + assert.strictEqual(node.state, State.READY); tree.step(); node = findNode(tree, "retry", "RETRY"); - assert.strictEqual(node.state, mistreevous.State.SUCCEEDED); + assert.strictEqual(node.state, State.SUCCEEDED); }); it("will move to the RUNNING state if the child node moves to the FAILED state", () => { const definition = "root { retry { condition [someCondition] } }"; const agent = { someCondition: () => false }; - const tree = new mistreevous.BehaviourTree(definition, agent); + const tree = new BehaviourTree(definition, agent); let node = findNode(tree, "retry", "RETRY"); assert.exists(node); - assert.strictEqual(node.state, mistreevous.State.READY); + assert.strictEqual(node.state, State.READY); tree.step(); node = findNode(tree, "retry", "RETRY"); - assert.strictEqual(node.state, mistreevous.State.RUNNING); + assert.strictEqual(node.state, State.RUNNING); }); it("and an attempt count node argument is defined will attempt to re-run the child node until the attempt count is reached", () => { const definition = "root { retry [3] { condition [someCondition] } }"; const agent = { someCondition: () => false }; - const tree = new mistreevous.BehaviourTree(definition, agent); + const tree = new BehaviourTree(definition, agent); let node = findNode(tree, "retry", "RETRY 3x"); assert.exists(node); - assert.strictEqual(node.state, mistreevous.State.READY); + assert.strictEqual(node.state, State.READY); tree.step(); node = findNode(tree, "retry", "RETRY 3x"); - assert.strictEqual(node.state, mistreevous.State.RUNNING); + assert.strictEqual(node.state, State.RUNNING); tree.step(); node = findNode(tree, "retry", "RETRY 3x"); - assert.strictEqual(node.state, mistreevous.State.RUNNING); + assert.strictEqual(node.state, State.RUNNING); tree.step(); node = findNode(tree, "retry", "RETRY 3x"); - assert.strictEqual(node.state, mistreevous.State.RUNNING); + assert.strictEqual(node.state, State.RUNNING); tree.step(); node = findNode(tree, "retry", "RETRY 3x"); - assert.strictEqual(node.state, mistreevous.State.FAILED); + assert.strictEqual(node.state, State.FAILED); }); describe("and minumum and maximum attempt count node arguments are defined", () => { @@ -94,36 +94,36 @@ describe("A Retry node", () => { // We have spied on Math.random to always return 0.5 for the sake of this test, so our attempt count should always be 4. const definition = "root { retry [2, 6] { condition [someCondition] } }"; const agent = { someCondition: () => false }; - const tree = new mistreevous.BehaviourTree(definition, agent); + const tree = new BehaviourTree(definition, agent); let node = findNode(tree, "retry", "RETRY 2x-6x"); assert.exists(node); - assert.strictEqual(node.state, mistreevous.State.READY); + assert.strictEqual(node.state, State.READY); tree.step(); node = findNode(tree, "retry", "RETRY 2x-6x"); - assert.strictEqual(node.state, mistreevous.State.RUNNING); + assert.strictEqual(node.state, State.RUNNING); tree.step(); node = findNode(tree, "retry", "RETRY 2x-6x"); - assert.strictEqual(node.state, mistreevous.State.RUNNING); + assert.strictEqual(node.state, State.RUNNING); tree.step(); node = findNode(tree, "retry", "RETRY 2x-6x"); - assert.strictEqual(node.state, mistreevous.State.RUNNING); + assert.strictEqual(node.state, State.RUNNING); tree.step(); node = findNode(tree, "retry", "RETRY 2x-6x"); - assert.strictEqual(node.state, mistreevous.State.RUNNING); + assert.strictEqual(node.state, State.RUNNING); tree.step(); node = findNode(tree, "retry", "RETRY 2x-6x"); - assert.strictEqual(node.state, mistreevous.State.FAILED); + assert.strictEqual(node.state, State.FAILED); }); it("and if the 'random' behaviour tree option is defined will use it to pick an attempt count from between the minimum and maximum bounds", () => { @@ -135,31 +135,31 @@ describe("A Retry node", () => { // A value of 0.2 should always result in an attempt count of 3. random: () => 0.2 }; - const tree = new mistreevous.BehaviourTree(definition, agent, options); + const tree = new BehaviourTree(definition, agent, options); let node = findNode(tree, "retry", "RETRY 2x-10x"); assert.exists(node); - assert.strictEqual(node.state, mistreevous.State.READY); + assert.strictEqual(node.state, State.READY); tree.step(); node = findNode(tree, "retry", "RETRY 2x-10x"); - assert.strictEqual(node.state, mistreevous.State.RUNNING); + assert.strictEqual(node.state, State.RUNNING); tree.step(); node = findNode(tree, "retry", "RETRY 2x-10x"); - assert.strictEqual(node.state, mistreevous.State.RUNNING); + assert.strictEqual(node.state, State.RUNNING); tree.step(); node = findNode(tree, "retry", "RETRY 2x-10x"); - assert.strictEqual(node.state, mistreevous.State.RUNNING); + assert.strictEqual(node.state, State.RUNNING); tree.step(); node = findNode(tree, "retry", "RETRY 2x-10x"); - assert.strictEqual(node.state, mistreevous.State.FAILED); + assert.strictEqual(node.state, State.FAILED); }); }); }); diff --git a/test/nodes/decorator/Succeed.test.js b/test/nodes/decorator/Succeed.spec.ts similarity index 68% rename from test/nodes/decorator/Succeed.test.js rename to test/nodes/decorator/Succeed.spec.ts index 1205a85..475791a 100644 --- a/test/nodes/decorator/Succeed.test.js +++ b/test/nodes/decorator/Succeed.spec.ts @@ -1,10 +1,10 @@ -const mistreevous = require("../../../dist/index"); -const chai = require("chai"); +import { assert } from "chai"; -var assert = chai.assert; +import { BehaviourTree, State } from "../../../src/index"; +import { RootNodeDefinition } from "../../../src/BehaviourTreeDefinition"; +import { Agent } from "../../../src/Agent"; -const findNode = (tree, type, caption) => - tree.getFlattenedNodeDetails().find((node) => node.type === type && node.caption === caption); +import { findNode } from "../../TestUtilities"; describe("A Succeed node", () => { describe("on tree initialisation", () => { @@ -12,7 +12,7 @@ describe("A Succeed node", () => { it("(MDSL)", () => { const definition = "root { succeed {} }"; assert.throws( - () => new mistreevous.BehaviourTree(definition, {}), + () => new BehaviourTree(definition, {}), Error, "invalid definition: a succeed node must have a single child" ); @@ -24,9 +24,9 @@ describe("A Succeed node", () => { child: { type: "succeed" } - }; + } as any; assert.throws( - () => new mistreevous.BehaviourTree(definition, {}), + () => new BehaviourTree(definition, {}), Error, "invalid definition: expected property 'child' to be defined for succeed node at depth '1'" ); @@ -40,19 +40,19 @@ describe("A Succeed node", () => { it("(MDSL)", () => { const definition = "root { succeed { condition [someCondition] } }"; const agent = { someCondition: () => false }; - const tree = new mistreevous.BehaviourTree(definition, agent); + const tree = new BehaviourTree(definition, agent); let node = findNode(tree, "succeed", "SUCCEED"); - assert.strictEqual(node.state, mistreevous.State.READY); + assert.strictEqual(node.state, State.READY); tree.step(); node = findNode(tree, "succeed", "SUCCEED"); - assert.strictEqual(node.state, mistreevous.State.SUCCEEDED); + assert.strictEqual(node.state, State.SUCCEEDED); }); it("(JSON)", () => { - const definition = { + const definition: RootNodeDefinition = { type: "root", child: { type: "succeed", @@ -63,15 +63,15 @@ describe("A Succeed node", () => { } }; const agent = { someCondition: () => false }; - const tree = new mistreevous.BehaviourTree(definition, agent); + const tree = new BehaviourTree(definition, agent); let node = findNode(tree, "succeed", "SUCCEED"); - assert.strictEqual(node.state, mistreevous.State.READY); + assert.strictEqual(node.state, State.READY); tree.step(); node = findNode(tree, "succeed", "SUCCEED"); - assert.strictEqual(node.state, mistreevous.State.SUCCEEDED); + assert.strictEqual(node.state, State.SUCCEEDED); }); }); @@ -79,19 +79,19 @@ describe("A Succeed node", () => { it("(MDSL)", () => { const definition = "root { succeed { condition [someCondition] } }"; const agent = { someCondition: () => true }; - const tree = new mistreevous.BehaviourTree(definition, agent); + const tree = new BehaviourTree(definition, agent); let node = findNode(tree, "succeed", "SUCCEED"); - assert.strictEqual(node.state, mistreevous.State.READY); + assert.strictEqual(node.state, State.READY); tree.step(); node = findNode(tree, "succeed", "SUCCEED"); - assert.strictEqual(node.state, mistreevous.State.SUCCEEDED); + assert.strictEqual(node.state, State.SUCCEEDED); }); it("(JSON)", () => { - const definition = { + const definition: RootNodeDefinition = { type: "root", child: { type: "succeed", @@ -102,15 +102,15 @@ describe("A Succeed node", () => { } }; const agent = { someCondition: () => true }; - const tree = new mistreevous.BehaviourTree(definition, agent); + const tree = new BehaviourTree(definition, agent); let node = findNode(tree, "succeed", "SUCCEED"); - assert.strictEqual(node.state, mistreevous.State.READY); + assert.strictEqual(node.state, State.READY); tree.step(); node = findNode(tree, "succeed", "SUCCEED"); - assert.strictEqual(node.state, mistreevous.State.SUCCEEDED); + assert.strictEqual(node.state, State.SUCCEEDED); }); }); }); @@ -119,19 +119,19 @@ describe("A Succeed node", () => { it("(MDSL)", () => { const definition = "root { succeed { action [someAction] } }"; const agent = { someAction: () => {} }; - const tree = new mistreevous.BehaviourTree(definition, agent); + const tree = new BehaviourTree(definition, agent); let node = findNode(tree, "succeed", "SUCCEED"); - assert.strictEqual(node.state, mistreevous.State.READY); + assert.strictEqual(node.state, State.READY); tree.step(); node = findNode(tree, "succeed", "SUCCEED"); - assert.strictEqual(node.state, mistreevous.State.RUNNING); + assert.strictEqual(node.state, State.RUNNING); }); it("(JSON)", () => { - const definition = { + const definition: RootNodeDefinition = { type: "root", child: { type: "succeed", @@ -142,15 +142,15 @@ describe("A Succeed node", () => { } }; const agent = { someAction: () => {} }; - const tree = new mistreevous.BehaviourTree(definition, agent); + const tree = new BehaviourTree(definition, agent); let node = findNode(tree, "succeed", "SUCCEED"); - assert.strictEqual(node.state, mistreevous.State.READY); + assert.strictEqual(node.state, State.READY); tree.step(); node = findNode(tree, "succeed", "SUCCEED"); - assert.strictEqual(node.state, mistreevous.State.RUNNING); + assert.strictEqual(node.state, State.RUNNING); }); }); }); diff --git a/test/nodes/leaf/Action.test.js b/test/nodes/leaf/Action.spec.ts similarity index 61% rename from test/nodes/leaf/Action.test.js rename to test/nodes/leaf/Action.spec.ts index 68354c9..6b5e744 100644 --- a/test/nodes/leaf/Action.test.js +++ b/test/nodes/leaf/Action.spec.ts @@ -1,17 +1,17 @@ -const mistreevous = require("../../../dist/index"); -const chai = require("chai"); +import { assert } from "chai"; -var assert = chai.assert; +import { BehaviourTree, State } from "../../../src/index"; +import { RootNodeDefinition } from "../../../src/BehaviourTreeDefinition"; +import { Agent } from "../../../src/Agent"; -const findNode = (tree, type, caption) => - tree.getFlattenedNodeDetails().find((node) => node.type === type && node.caption === caption); +import { findNode } from "../../TestUtilities"; describe("An Action node", () => { describe("on tree initialisation", () => { it("will error if an action name identifier is not the first node argument", () => { const definition = "root { action [] }"; assert.throws( - () => new mistreevous.BehaviourTree(definition, {}), + () => new BehaviourTree(definition, {}), Error, "invalid definition: expected action name identifier argument" ); @@ -22,35 +22,35 @@ describe("An Action node", () => { describe("will call the function defined by the first node argument", () => { describe("when the referenced function is", () => { it("a registered function", () => { - mistreevous.BehaviourTree.register("doAction", () => { - return mistreevous.State.SUCCEEDED; + BehaviourTree.register("doAction", () => { + return State.SUCCEEDED; }); const definition = "root { action [doAction] }"; - const tree = new mistreevous.BehaviourTree(definition, {}); + const tree = new BehaviourTree(definition, {}); tree.step(); - node = findNode(tree, "action", "doAction"); - assert.strictEqual(node.state, mistreevous.State.SUCCEEDED); + const node = findNode(tree, "action", "doAction"); + assert.strictEqual(node.state, State.SUCCEEDED); }); it("an agent function", () => { const definition = "root { action [doAction] }"; - const agent = { doAction: () => mistreevous.State.SUCCEEDED }; - const tree = new mistreevous.BehaviourTree(definition, agent); + const agent: Agent = { doAction: () => State.SUCCEEDED }; + const tree = new BehaviourTree(definition, agent); tree.step(); - node = findNode(tree, "action", "doAction"); - assert.strictEqual(node.state, mistreevous.State.SUCCEEDED); + const node = findNode(tree, "action", "doAction"); + assert.strictEqual(node.state, State.SUCCEEDED); }); }); it("and will error if there is no agent function or registered function that matches the action name", () => { const definition = "root { action [DoTheThing] }"; - let tree; - assert.doesNotThrow(() => (tree = new mistreevous.BehaviourTree(definition, {})), Error); + let tree: BehaviourTree; + assert.doesNotThrow(() => (tree = new BehaviourTree(definition, {})), Error); assert.throws( () => tree.step(), Error, @@ -61,56 +61,56 @@ describe("An Action node", () => { describe("and move to", () => { it("the SUCCESS state if the function returns a value of State.SUCCEEDED", () => { const definition = "root { action [doAction] }"; - const agent = { doAction: () => mistreevous.State.SUCCEEDED }; - const tree = new mistreevous.BehaviourTree(definition, agent); + const agent: Agent = { doAction: () => State.SUCCEEDED }; + const tree = new BehaviourTree(definition, agent); let node = findNode(tree, "action", "doAction"); - assert.strictEqual(node.state, mistreevous.State.READY); + assert.strictEqual(node.state, State.READY); tree.step(); node = findNode(tree, "action", "doAction"); - assert.strictEqual(node.state, mistreevous.State.SUCCEEDED); + assert.strictEqual(node.state, State.SUCCEEDED); }); it("the FAILED state if the function returns a value of State.FAILED", () => { const definition = "root { action [doAction] }"; - const agent = { doAction: () => mistreevous.State.FAILED }; - const tree = new mistreevous.BehaviourTree(definition, agent); + const agent: Agent = { doAction: () => State.FAILED }; + const tree = new BehaviourTree(definition, agent); let node = findNode(tree, "action", "doAction"); - assert.strictEqual(node.state, mistreevous.State.READY); + assert.strictEqual(node.state, State.READY); tree.step(); node = findNode(tree, "action", "doAction"); - assert.strictEqual(node.state, mistreevous.State.FAILED); + assert.strictEqual(node.state, State.FAILED); }); describe("the RUNNING state if", () => { it("the function returns undefined", () => { const definition = "root { action [doAction] }"; const agent = { doAction: () => {} }; - const tree = new mistreevous.BehaviourTree(definition, agent); + const tree = new BehaviourTree(definition, agent); let node = findNode(tree, "action", "doAction"); - assert.strictEqual(node.state, mistreevous.State.READY); + assert.strictEqual(node.state, State.READY); tree.step(); node = findNode(tree, "action", "doAction"); - assert.strictEqual(node.state, mistreevous.State.RUNNING); + assert.strictEqual(node.state, State.RUNNING); }); it("the function returns a promise to return a value of State.SUCCEEDED or State.FAILED", (done) => { - const result = new Promise((resolve) => resolve(mistreevous.State.SUCCEEDED)); + const result: Promise = new Promise((resolve) => resolve(State.SUCCEEDED)); const definition = "root { action [doAction] }"; - const agent = { doAction: () => result }; - const tree = new mistreevous.BehaviourTree(definition, agent); + const agent: Agent = { doAction: () => result }; + const tree = new BehaviourTree(definition, agent); let node = findNode(tree, "action", "doAction"); - assert.strictEqual(node.state, mistreevous.State.READY); + assert.strictEqual(node.state, State.READY); tree.step(); @@ -118,7 +118,7 @@ describe("An Action node", () => { .then(() => tree.step()) .then(() => { node = findNode(tree, "action", "doAction"); - assert.strictEqual(node.state, mistreevous.State.SUCCEEDED); + assert.strictEqual(node.state, State.SUCCEEDED); }) .then(done); }); @@ -130,9 +130,9 @@ describe("An Action node", () => { it("string", () => { const definition = 'root { action [doAction, "hello world!"] }'; const agent = { - doAction: (arg) => assert.strictEqual(arg, "hello world!") + doAction: (arg: any) => assert.strictEqual(arg, "hello world!") }; - const tree = new mistreevous.BehaviourTree(definition, agent); + const tree = new BehaviourTree(definition, agent); tree.step(); }); @@ -140,9 +140,9 @@ describe("An Action node", () => { it("string with escaped quotes", () => { const definition = 'root { action [doAction, "hello \\" world!"] }'; const agent = { - doAction: (arg) => assert.strictEqual(arg, 'hello " world!') + doAction: (arg: any) => assert.strictEqual(arg, 'hello " world!') }; - const tree = new mistreevous.BehaviourTree(definition, agent); + const tree = new BehaviourTree(definition, agent); tree.step(); }); @@ -150,9 +150,9 @@ describe("An Action node", () => { it("number", () => { const definition = "root { action [doAction, 23.4567] }"; const agent = { - doAction: (arg) => assert.strictEqual(arg, 23.4567) + doAction: (arg: any) => assert.strictEqual(arg, 23.4567) }; - const tree = new mistreevous.BehaviourTree(definition, agent); + const tree = new BehaviourTree(definition, agent); tree.step(); }); @@ -160,9 +160,9 @@ describe("An Action node", () => { it("boolean 'true' literal", () => { const definition = "root { action [doAction, true] }"; const agent = { - doAction: (arg) => assert.strictEqual(arg, true) + doAction: (arg: any) => assert.strictEqual(arg, true) }; - const tree = new mistreevous.BehaviourTree(definition, agent); + const tree = new BehaviourTree(definition, agent); tree.step(); }); @@ -170,9 +170,9 @@ describe("An Action node", () => { it("boolean 'false' literal", () => { const definition = "root { action [doAction, false] }"; const agent = { - doAction: (arg) => assert.strictEqual(arg, false) + doAction: (arg: any) => assert.strictEqual(arg, false) }; - const tree = new mistreevous.BehaviourTree(definition, agent); + const tree = new BehaviourTree(definition, agent); tree.step(); }); @@ -180,9 +180,9 @@ describe("An Action node", () => { it("null", () => { const definition = "root { action [doAction, null] }"; const agent = { - doAction: (arg) => assert.isNull(arg) + doAction: (arg: any) => assert.isNull(arg) }; - const tree = new mistreevous.BehaviourTree(definition, agent); + const tree = new BehaviourTree(definition, agent); tree.step(); }); @@ -191,14 +191,14 @@ describe("An Action node", () => { it("there are multiple arguments", () => { const definition = 'root { action [doAction, 1.23, "hello world!", false, null] }'; const agent = { - doAction: (arg0, arg1, arg2, arg3) => { + doAction: (arg0: any, arg1: any, arg2: any, arg3: any) => { assert.strictEqual(arg0, 1.23); assert.strictEqual(arg1, "hello world!"); assert.strictEqual(arg2, false); assert.strictEqual(arg3, null); } }; - const tree = new mistreevous.BehaviourTree(definition, agent); + const tree = new BehaviourTree(definition, agent); tree.step(); }); diff --git a/test/nodes/leaf/Condition.test.js b/test/nodes/leaf/Condition.spec.ts similarity index 65% rename from test/nodes/leaf/Condition.test.js rename to test/nodes/leaf/Condition.spec.ts index 8494805..6a176d7 100644 --- a/test/nodes/leaf/Condition.test.js +++ b/test/nodes/leaf/Condition.spec.ts @@ -1,17 +1,17 @@ -const mistreevous = require("../../../dist/index"); -const chai = require("chai"); +import { assert } from "chai"; -var assert = chai.assert; +import { BehaviourTree, State } from "../../../src/index"; +import { RootNodeDefinition } from "../../../src/BehaviourTreeDefinition"; +import { Agent } from "../../../src/Agent"; -const findNode = (tree, type, caption) => - tree.getFlattenedNodeDetails().find((node) => node.type === type && node.caption === caption); +import { findNode } from "../../TestUtilities"; describe("A Condition node", () => { describe("on tree initialisation", () => { it("will error if a condition name identifier is not the first node argument", () => { const definition = "root { condition [] }"; assert.throws( - () => new mistreevous.BehaviourTree(definition, {}), + () => new BehaviourTree(definition, {}), Error, "invalid definition: expected condition name identifier argument" ); @@ -22,35 +22,35 @@ describe("A Condition node", () => { describe("will call the function defined by the first node argument", () => { describe("when the referenced function is", () => { it("a registered function", () => { - mistreevous.BehaviourTree.register("someCondition", () => { + BehaviourTree.register("someCondition", () => { return true; }); const definition = "root { condition [someCondition] }"; - const tree = new mistreevous.BehaviourTree(definition, {}); + const tree = new BehaviourTree(definition, {}); tree.step(); - node = findNode(tree, "condition", "someCondition"); - assert.strictEqual(node.state, mistreevous.State.SUCCEEDED); + const node = findNode(tree, "condition", "someCondition"); + assert.strictEqual(node.state, State.SUCCEEDED); }); it("an agent function", () => { const definition = "root { condition [someCondition] }"; const agent = { someCondition: () => true }; - const tree = new mistreevous.BehaviourTree(definition, agent); + const tree = new BehaviourTree(definition, agent); tree.step(); - node = findNode(tree, "condition", "someCondition"); - assert.strictEqual(node.state, mistreevous.State.SUCCEEDED); + const node = findNode(tree, "condition", "someCondition"); + assert.strictEqual(node.state, State.SUCCEEDED); }); }); it("and will error if there is no agent function or registered function that matches the condition name", () => { const definition = "root { condition [someCondition] }"; - let tree; - assert.doesNotThrow(() => (tree = new mistreevous.BehaviourTree(definition, {})), Error); + let tree: BehaviourTree; + assert.doesNotThrow(() => (tree = new BehaviourTree(definition, {})), Error); assert.throws( () => tree.step(), Error, @@ -62,29 +62,29 @@ describe("A Condition node", () => { it("the SUCCESS state if the function returns a truthy value", () => { const definition = "root { condition [someCondition] }"; const agent = { someCondition: () => true }; - const tree = new mistreevous.BehaviourTree(definition, agent); + const tree = new BehaviourTree(definition, agent); let node = findNode(tree, "condition", "someCondition"); - assert.strictEqual(node.state, mistreevous.State.READY); + assert.strictEqual(node.state, State.READY); tree.step(); node = findNode(tree, "condition", "someCondition"); - assert.strictEqual(node.state, mistreevous.State.SUCCEEDED); + assert.strictEqual(node.state, State.SUCCEEDED); }); it("the FAILED state if the function returns a falsy value", () => { const definition = "root { condition [someCondition] }"; const agent = { someCondition: () => false }; - const tree = new mistreevous.BehaviourTree(definition, agent); + const tree = new BehaviourTree(definition, agent); let node = findNode(tree, "condition", "someCondition"); - assert.strictEqual(node.state, mistreevous.State.READY); + assert.strictEqual(node.state, State.READY); tree.step(); node = findNode(tree, "condition", "someCondition"); - assert.strictEqual(node.state, mistreevous.State.FAILED); + assert.strictEqual(node.state, State.FAILED); }); }); @@ -93,9 +93,9 @@ describe("A Condition node", () => { it("string", () => { const definition = 'root { condition [someCondition, "hello world!"] }'; const agent = { - someCondition: (arg) => assert.strictEqual(arg, "hello world!") + someCondition: (arg: any) => assert.strictEqual(arg, "hello world!") }; - const tree = new mistreevous.BehaviourTree(definition, agent); + const tree = new BehaviourTree(definition, agent); tree.step(); }); @@ -103,9 +103,9 @@ describe("A Condition node", () => { it("string with escaped quotes", () => { const definition = 'root { condition [someCondition, "hello \\" world!"] }'; const agent = { - someCondition: (arg) => assert.strictEqual(arg, 'hello " world!') + someCondition: (arg: any) => assert.strictEqual(arg, 'hello " world!') }; - const tree = new mistreevous.BehaviourTree(definition, agent); + const tree = new BehaviourTree(definition, agent); tree.step(); }); @@ -113,9 +113,9 @@ describe("A Condition node", () => { it("number", () => { const definition = "root { condition [someCondition, 23.4567] }"; const agent = { - someCondition: (arg) => assert.strictEqual(arg, 23.4567) + someCondition: (arg: any) => assert.strictEqual(arg, 23.4567) }; - const tree = new mistreevous.BehaviourTree(definition, agent); + const tree = new BehaviourTree(definition, agent); tree.step(); }); @@ -123,9 +123,9 @@ describe("A Condition node", () => { it("boolean 'true' literal", () => { const definition = "root { condition [someCondition, true] }"; const agent = { - someCondition: (arg) => assert.strictEqual(arg, true) + someCondition: (arg: any) => assert.strictEqual(arg, true) }; - const tree = new mistreevous.BehaviourTree(definition, agent); + const tree = new BehaviourTree(definition, agent); tree.step(); }); @@ -133,9 +133,9 @@ describe("A Condition node", () => { it("boolean 'false' literal", () => { const definition = "root { condition [someCondition, false] }"; const agent = { - someCondition: (arg) => assert.strictEqual(arg, false) + someCondition: (arg: any) => assert.strictEqual(arg, false) }; - const tree = new mistreevous.BehaviourTree(definition, agent); + const tree = new BehaviourTree(definition, agent); tree.step(); }); @@ -143,9 +143,9 @@ describe("A Condition node", () => { it("null", () => { const definition = "root { condition [someCondition, null] }"; const agent = { - someCondition: (arg) => assert.isNull(arg) + someCondition: (arg: any) => assert.isNull(arg) }; - const tree = new mistreevous.BehaviourTree(definition, agent); + const tree = new BehaviourTree(definition, agent); tree.step(); }); @@ -154,14 +154,14 @@ describe("A Condition node", () => { it("there are multiple arguments", () => { const definition = 'root { condition [someCondition, 1.23, "hello world!", false, null] }'; const agent = { - someCondition: (arg0, arg1, arg2, arg3) => { + someCondition: (arg0: any, arg1: any, arg2: any, arg3: any) => { assert.strictEqual(arg0, 1.23); assert.strictEqual(arg1, "hello world!"); assert.strictEqual(arg2, false); assert.strictEqual(arg3, null); } }; - const tree = new mistreevous.BehaviourTree(definition, agent); + const tree = new BehaviourTree(definition, agent); tree.step(); }); diff --git a/test/nodes/leaf/Wait.test.js b/test/nodes/leaf/Wait.spec.ts similarity index 68% rename from test/nodes/leaf/Wait.test.js rename to test/nodes/leaf/Wait.spec.ts index c960ac7..19597d9 100644 --- a/test/nodes/leaf/Wait.test.js +++ b/test/nodes/leaf/Wait.spec.ts @@ -1,11 +1,11 @@ -const mistreevous = require("../../../dist/index"); -const chai = require("chai"); -const sinon = require("sinon"); +import { assert } from "chai"; +import sinon, { SinonFakeTimers, SinonSandbox } from "sinon"; -var assert = chai.assert; +import { BehaviourTree, State } from "../../../src/index"; +import { RootNodeDefinition } from "../../../src/BehaviourTreeDefinition"; +import { Agent } from "../../../src/Agent"; -const findNode = (tree, type, caption) => - tree.getFlattenedNodeDetails().find((node) => node.type === type && (!caption || node.caption === caption)); +import { findNode } from "../../TestUtilities"; describe("A Wait node", () => { describe("on tree initialisation", () => { @@ -13,7 +13,7 @@ describe("A Wait node", () => { it("the defined node arguments are not integers", () => { const definition = "root { wait ['not', 'integers'] }"; assert.throws( - () => new mistreevous.BehaviourTree(definition, {}), + () => new BehaviourTree(definition, {}), Error, "invalid definition: wait node durations must be integer values" ); @@ -22,7 +22,7 @@ describe("A Wait node", () => { it("a negative duration node argument was defined", () => { const definition = "root { wait [-1] }"; assert.throws( - () => new mistreevous.BehaviourTree(definition, {}), + () => new BehaviourTree(definition, {}), Error, "invalid definition: a wait node must have a positive duration" ); @@ -31,7 +31,7 @@ describe("A Wait node", () => { it("more than two node arguments are defined", () => { const definition = "root { wait [0, 1000, 4000] }"; assert.throws( - () => new mistreevous.BehaviourTree(definition, {}), + () => new BehaviourTree(definition, {}), Error, "invalid definition: invalid number of wait node duration arguments defined" ); @@ -40,7 +40,7 @@ describe("A Wait node", () => { it("a minimum duration bound node argument is defined that is greater than the maximum duration bound node argument", () => { const definition = "root { wait [1000, 500] }"; assert.throws( - () => new mistreevous.BehaviourTree(definition, {}), + () => new BehaviourTree(definition, {}), Error, "invalid definition: a wait node must not have a minimum duration that exceeds the maximum duration" ); @@ -49,8 +49,8 @@ describe("A Wait node", () => { }); describe("when updated as part of a tree step", () => { - var clock; - var sandbox; + var clock: SinonFakeTimers; + var sandbox: SinonSandbox; beforeEach(() => { clock = sinon.useFakeTimers(); @@ -65,43 +65,43 @@ describe("A Wait node", () => { it("and an explicit duration was defined will move to the SUCCEEDED state if the duration has expired", () => { const definition = "root { wait [100] }"; - const tree = new mistreevous.BehaviourTree(definition, {}); + const tree = new BehaviourTree(definition, {}); let node = findNode(tree, "wait"); - assert.strictEqual(node.state, mistreevous.State.READY); + assert.strictEqual(node.state, State.READY); tree.step(); node = findNode(tree, "wait"); - assert.strictEqual(node.state, mistreevous.State.RUNNING); + assert.strictEqual(node.state, State.RUNNING); clock.tick(99); tree.step(); node = findNode(tree, "wait"); - assert.strictEqual(node.state, mistreevous.State.RUNNING); + assert.strictEqual(node.state, State.RUNNING); clock.tick(1); tree.step(); node = findNode(tree, "wait"); - assert.strictEqual(node.state, mistreevous.State.SUCCEEDED); + assert.strictEqual(node.state, State.SUCCEEDED); }); describe("and min and max durations were defined", () => { it("will select a random duration between the min and max durations and move to the SUCCEEDED state if the duration has expired", () => { const definition = "root { wait [5000, 10000] }"; - const tree = new mistreevous.BehaviourTree(definition, {}); + const tree = new BehaviourTree(definition, {}); let node = findNode(tree, "wait"); - assert.strictEqual(node.state, mistreevous.State.READY); + assert.strictEqual(node.state, State.READY); tree.step(); node = findNode(tree, "wait"); - assert.strictEqual(node.state, mistreevous.State.RUNNING); + assert.strictEqual(node.state, State.RUNNING); // We have spied on Math.random to always return 0.5 for the sake of this test, so our actual duration 'should' be 7500ms. clock.tick(7499); @@ -109,14 +109,14 @@ describe("A Wait node", () => { tree.step(); node = findNode(tree, "wait"); - assert.strictEqual(node.state, mistreevous.State.RUNNING); + assert.strictEqual(node.state, State.RUNNING); clock.tick(1); tree.step(); node = findNode(tree, "wait"); - assert.strictEqual(node.state, mistreevous.State.SUCCEEDED); + assert.strictEqual(node.state, State.SUCCEEDED); }); it("will use the 'random' function to select the duration between the min and max durations if it was defined as a behaviour tree option and move to the SUCCEEDED state if the duration has expired", () => { @@ -126,15 +126,15 @@ describe("A Wait node", () => { // just want to make sure that the number we return actually has an impact on which duration is picked. random: () => 0.2 }; - const tree = new mistreevous.BehaviourTree(definition, {}, options); + const tree = new BehaviourTree(definition, {}, options); let node = findNode(tree, "wait"); - assert.strictEqual(node.state, mistreevous.State.READY); + assert.strictEqual(node.state, State.READY); tree.step(); node = findNode(tree, "wait"); - assert.strictEqual(node.state, mistreevous.State.RUNNING); + assert.strictEqual(node.state, State.RUNNING); // Our 'random' function option will always return 0.2 for the sake of this test, so our actual duration 'should' be 6000ms. clock.tick(5999); @@ -142,14 +142,14 @@ describe("A Wait node", () => { tree.step(); node = findNode(tree, "wait"); - assert.strictEqual(node.state, mistreevous.State.RUNNING); + assert.strictEqual(node.state, State.RUNNING); clock.tick(1); tree.step(); node = findNode(tree, "wait"); - assert.strictEqual(node.state, mistreevous.State.SUCCEEDED); + assert.strictEqual(node.state, State.SUCCEEDED); }); }); @@ -157,47 +157,47 @@ describe("A Wait node", () => { const definition = "root { wait while(CanWait) }"; let canWait = true; const agent = { CanWait: () => canWait }; - const tree = new mistreevous.BehaviourTree(definition, agent); + const tree = new BehaviourTree(definition, agent); let node = findNode(tree, "wait"); - assert.strictEqual(node.state, mistreevous.State.READY); + assert.strictEqual(node.state, State.READY); tree.step(); node = findNode(tree, "wait"); - assert.strictEqual(node.state, mistreevous.State.RUNNING); + assert.strictEqual(node.state, State.RUNNING); clock.tick(1000000); tree.step(); node = findNode(tree, "wait"); - assert.strictEqual(node.state, mistreevous.State.RUNNING); + assert.strictEqual(node.state, State.RUNNING); canWait = false; tree.step(); node = findNode(tree, "wait"); - assert.strictEqual(node.state, mistreevous.State.FAILED); + assert.strictEqual(node.state, State.FAILED); }); it("will use the 'getDeltaTime' function to update the elapsed duration if it was defined as a behaviour tree option", () => { const definition = "root { wait [1000] }"; - const tree = new mistreevous.BehaviourTree(definition, {}, { getDeltaTime: () => 0.5 }); + const tree = new BehaviourTree(definition, {}, { getDeltaTime: () => 0.5 }); let node = findNode(tree, "wait"); - assert.strictEqual(node.state, mistreevous.State.READY); + assert.strictEqual(node.state, State.READY); tree.step(); node = findNode(tree, "wait"); - assert.strictEqual(node.state, mistreevous.State.RUNNING); + assert.strictEqual(node.state, State.RUNNING); tree.step(); node = findNode(tree, "wait"); - assert.strictEqual(node.state, mistreevous.State.SUCCEEDED); + assert.strictEqual(node.state, State.SUCCEEDED); }); }); }); From 0b9581c60feaa71d29acd81a136b4cc21a8af625 Mon Sep 17 00:00:00 2001 From: Nikolas Howard Date: Mon, 19 Feb 2024 17:37:36 +0000 Subject: [PATCH 29/48] Updated Agent typings --- dist/Agent.d.ts | 2 +- src/Agent.ts | 2 +- test/BehaviourTree.spec.ts | 10 +++++----- test/nodes/composite/Selector.spec.ts | 4 ++-- test/nodes/leaf/Action.spec.ts | 8 ++++---- 5 files changed, 13 insertions(+), 13 deletions(-) diff --git a/dist/Agent.d.ts b/dist/Agent.d.ts index aaa4112..1287ddc 100644 --- a/dist/Agent.d.ts +++ b/dist/Agent.d.ts @@ -3,7 +3,7 @@ import { CompleteState } from "./State"; * A type representing an agent that a behavior tree instance would operate on. */ export type Agent = { - [actionName: string]: AgentFunction; + [propertyName: string]: AgentFunction | unknown; }; export type ExitFunctionArg = { succeeded: boolean; diff --git a/src/Agent.ts b/src/Agent.ts index 525720c..ee600fc 100644 --- a/src/Agent.ts +++ b/src/Agent.ts @@ -4,7 +4,7 @@ import { CompleteState } from "./State"; * A type representing an agent that a behavior tree instance would operate on. */ export type Agent = { - [actionName: string]: AgentFunction; + [propertyName: string]: AgentFunction | unknown; }; /* diff --git a/test/BehaviourTree.spec.ts b/test/BehaviourTree.spec.ts index 8434d08..67ebbc4 100644 --- a/test/BehaviourTree.spec.ts +++ b/test/BehaviourTree.spec.ts @@ -56,7 +56,7 @@ describe("A BehaviourTree instance", () => { describe("has a 'getState' function that returns the state of the root node", () => { it("(MDSL)", () => { const definition = "root { action [getActionResult] }"; - const agent: Agent = { getActionResult: () => {} }; + const agent = { getActionResult: () => {} }; const tree = new BehaviourTree(definition, agent); assert.strictEqual(tree.getState(), State.READY); @@ -144,7 +144,7 @@ describe("A BehaviourTree instance", () => { describe("has a 'reset' function that resets the tree from the root node outwards to each nested node, giving each a state of READY", () => { it("(MDSL)", () => { const definition = "root { sequence { action [getActionResult] } }"; - const agent: Agent = { getActionResult: () => State.SUCCEEDED }; + const agent = { getActionResult: () => State.SUCCEEDED }; const tree = new BehaviourTree(definition, agent); assert.strictEqual(findNode(tree, "root", "ROOT").state, State.READY); @@ -177,7 +177,7 @@ describe("A BehaviourTree instance", () => { ] } }; - const agent: Agent = { getActionResult: () => State.SUCCEEDED }; + const agent = { getActionResult: () => State.SUCCEEDED }; const tree = new BehaviourTree(definition, agent); assert.strictEqual(findNode(tree, "root", "ROOT").state, State.READY); @@ -202,7 +202,7 @@ describe("A BehaviourTree instance", () => { it("(MDSL)", () => { const definition = "root { sequence { action [getActionResult0] action [getActionResult1] action [getActionResult2] action [getActionResult3] } }"; - const agent: Agent = { + const agent = { getActionResult0: () => State.SUCCEEDED, getActionResult1: () => State.SUCCEEDED, getActionResult2: () => {}, @@ -266,7 +266,7 @@ describe("A BehaviourTree instance", () => { ] } }; - const agent: Agent = { + const agent = { getActionResult0: () => State.SUCCEEDED, getActionResult1: () => State.SUCCEEDED, getActionResult2: () => {}, diff --git a/test/nodes/composite/Selector.spec.ts b/test/nodes/composite/Selector.spec.ts index e662c1c..ba21258 100644 --- a/test/nodes/composite/Selector.spec.ts +++ b/test/nodes/composite/Selector.spec.ts @@ -44,7 +44,7 @@ describe("A Selector node", () => { it("(MDSL)", () => { const definition = "root { selector { action [actionFail] action [actionRunning] action [actionSucceed] } }"; - const agent: Agent = { + const agent = { actionSucceed: () => State.SUCCEEDED, actionRunning: () => {}, actionFail: () => State.FAILED @@ -87,7 +87,7 @@ describe("A Selector node", () => { ] } }; - const agent: Agent = { + const agent = { actionSucceed: () => State.SUCCEEDED, actionRunning: () => {}, actionFail: () => State.FAILED diff --git a/test/nodes/leaf/Action.spec.ts b/test/nodes/leaf/Action.spec.ts index 6b5e744..f9c6c6b 100644 --- a/test/nodes/leaf/Action.spec.ts +++ b/test/nodes/leaf/Action.spec.ts @@ -37,7 +37,7 @@ describe("An Action node", () => { it("an agent function", () => { const definition = "root { action [doAction] }"; - const agent: Agent = { doAction: () => State.SUCCEEDED }; + const agent = { doAction: () => State.SUCCEEDED }; const tree = new BehaviourTree(definition, agent); tree.step(); @@ -61,7 +61,7 @@ describe("An Action node", () => { describe("and move to", () => { it("the SUCCESS state if the function returns a value of State.SUCCEEDED", () => { const definition = "root { action [doAction] }"; - const agent: Agent = { doAction: () => State.SUCCEEDED }; + const agent = { doAction: () => State.SUCCEEDED }; const tree = new BehaviourTree(definition, agent); let node = findNode(tree, "action", "doAction"); @@ -75,7 +75,7 @@ describe("An Action node", () => { it("the FAILED state if the function returns a value of State.FAILED", () => { const definition = "root { action [doAction] }"; - const agent: Agent = { doAction: () => State.FAILED }; + const agent = { doAction: () => State.FAILED }; const tree = new BehaviourTree(definition, agent); let node = findNode(tree, "action", "doAction"); @@ -106,7 +106,7 @@ describe("An Action node", () => { const result: Promise = new Promise((resolve) => resolve(State.SUCCEEDED)); const definition = "root { action [doAction] }"; - const agent: Agent = { doAction: () => result }; + const agent = { doAction: () => result }; const tree = new BehaviourTree(definition, agent); let node = findNode(tree, "action", "doAction"); From cfc26d293af39fb592e0f88715cc65d3cc447297 Mon Sep 17 00:00:00 2001 From: Nikolas Howard Date: Mon, 19 Feb 2024 17:56:48 +0000 Subject: [PATCH 30/48] Updated Retry and Repeat specs --- test/nodes/decorator/Repeat.spec.ts | 360 ++++++++++++++++++++++------ test/nodes/decorator/Retry.spec.ts | 360 ++++++++++++++++++++++------ 2 files changed, 566 insertions(+), 154 deletions(-) diff --git a/test/nodes/decorator/Repeat.spec.ts b/test/nodes/decorator/Repeat.spec.ts index 594a455..16f9c21 100644 --- a/test/nodes/decorator/Repeat.spec.ts +++ b/test/nodes/decorator/Repeat.spec.ts @@ -9,13 +9,29 @@ import { findNode } from "../../TestUtilities"; describe("A Repeat node", () => { describe("on tree initialisation", () => { - it("will error if the node does not have a single child", () => { - const definition = "root { repeat {} }"; - assert.throws( - () => new BehaviourTree(definition, {}), - Error, - "invalid definition: a repeat node must have a single child" - ); + describe("will error if the node does not have a single child", () => { + it("(MDSL)", () => { + const definition = "root { repeat {} }"; + assert.throws( + () => new BehaviourTree(definition, {}), + Error, + "invalid definition: a repeat node must have a single child" + ); + }); + + it("(JSON)", () => { + const definition = { + type: "root", + child: { + type: "repeat" + } + } as any; + assert.throws( + () => new BehaviourTree(definition, {}), + Error, + "invalid definition: expected property 'child' to be defined for repeat node at depth '1'" + ); + }); }); }); @@ -29,138 +45,328 @@ describe("A Repeat node", () => { afterEach(() => sandbox.restore()); - it("will move to the FAILED state if the child node moves to the FAILED state", () => { - const definition = "root { repeat { condition [someCondition] } }"; - const agent = { someCondition: () => false }; - const tree = new BehaviourTree(definition, agent); + describe("will move to the FAILED state if the child node moves to the FAILED state", () => { + it("(MDSL)", () => { + const definition = "root { repeat { condition [someCondition] } }"; + const agent = { someCondition: () => false }; + const tree = new BehaviourTree(definition, agent); - let node = findNode(tree, "repeat", "REPEAT"); - assert.exists(node); - assert.strictEqual(node.state, State.READY); + let node = findNode(tree, "repeat", "REPEAT"); + assert.exists(node); + assert.strictEqual(node.state, State.READY); - tree.step(); + tree.step(); - node = findNode(tree, "repeat", "REPEAT"); - assert.strictEqual(node.state, State.FAILED); - }); + node = findNode(tree, "repeat", "REPEAT"); + assert.strictEqual(node.state, State.FAILED); + }); - it("will move to the RUNNING state if the child node moves to the SUCCEEDED state", () => { - const definition = "root { repeat { condition [someCondition] } }"; - const agent = { someCondition: () => true }; - const tree = new BehaviourTree(definition, agent); + it("(JSON)", () => { + const definition: RootNodeDefinition = { + type: "root", + child: { + type: "repeat", + child: { + type: "condition", + call: "someCondition" + } + } + }; + const agent = { someCondition: () => false }; + const tree = new BehaviourTree(definition, agent); - let node = findNode(tree, "repeat", "REPEAT"); - assert.exists(node); - assert.strictEqual(node.state, State.READY); + let node = findNode(tree, "repeat", "REPEAT"); + assert.exists(node); + assert.strictEqual(node.state, State.READY); - tree.step(); + tree.step(); - node = findNode(tree, "repeat", "REPEAT"); - assert.strictEqual(node.state, State.RUNNING); + node = findNode(tree, "repeat", "REPEAT"); + assert.strictEqual(node.state, State.FAILED); + }); }); - it("and an iteration count node argument is defined will attempt to re-run the child node until the iteration count is reached", () => { - const definition = "root { repeat [3] { condition [someCondition] } }"; - const agent = { someCondition: () => true }; - const tree = new BehaviourTree(definition, agent); - - let node = findNode(tree, "repeat", "REPEAT 3x"); - assert.exists(node); - assert.strictEqual(node.state, State.READY); - - tree.step(); + describe("will move to the RUNNING state if the child node moves to the SUCCEEDED state", () => { + it("(MDSL)", () => { + const definition = "root { repeat { condition [someCondition] } }"; + const agent = { someCondition: () => true }; + const tree = new BehaviourTree(definition, agent); - node = findNode(tree, "repeat", "REPEAT 3x"); - assert.strictEqual(node.state, State.RUNNING); + let node = findNode(tree, "repeat", "REPEAT"); + assert.exists(node); + assert.strictEqual(node.state, State.READY); - tree.step(); + tree.step(); - node = findNode(tree, "repeat", "REPEAT 3x"); - assert.strictEqual(node.state, State.RUNNING); + node = findNode(tree, "repeat", "REPEAT"); + assert.strictEqual(node.state, State.RUNNING); + }); - tree.step(); + it("(JSON)", () => { + const definition: RootNodeDefinition = { + type: "root", + child: { + type: "repeat", + child: { + type: "condition", + call: "someCondition" + } + } + }; + const agent = { someCondition: () => true }; + const tree = new BehaviourTree(definition, agent); - node = findNode(tree, "repeat", "REPEAT 3x"); - assert.strictEqual(node.state, State.RUNNING); + let node = findNode(tree, "repeat", "REPEAT"); + assert.exists(node); + assert.strictEqual(node.state, State.READY); - tree.step(); + tree.step(); - node = findNode(tree, "repeat", "REPEAT 3x"); - assert.strictEqual(node.state, State.SUCCEEDED); + node = findNode(tree, "repeat", "REPEAT"); + assert.strictEqual(node.state, State.RUNNING); + }); }); - describe("and minumum and maximum iteration count node arguments are defined", () => { - it("and if the 'random' behaviour tree option is not defined will pick an iteration count from between the minimum and maximum bounds using Math.random", () => { - // We have spied on Math.random to always return 0.5 for the sake of this test, so our iteration count should always be 4. - const definition = "root { repeat [2, 6] { condition [someCondition] } }"; + describe("and an iteration count node argument is defined will attempt to re-run the child node until the iteration count is reached", () => { + it("(MDSL)", () => { + const definition = "root { repeat [3] { condition [someCondition] } }"; const agent = { someCondition: () => true }; const tree = new BehaviourTree(definition, agent); - let node = findNode(tree, "repeat", "REPEAT 2x-6x"); + let node = findNode(tree, "repeat", "REPEAT 3x"); assert.exists(node); assert.strictEqual(node.state, State.READY); tree.step(); - node = findNode(tree, "repeat", "REPEAT 2x-6x"); + node = findNode(tree, "repeat", "REPEAT 3x"); assert.strictEqual(node.state, State.RUNNING); tree.step(); - node = findNode(tree, "repeat", "REPEAT 2x-6x"); + node = findNode(tree, "repeat", "REPEAT 3x"); assert.strictEqual(node.state, State.RUNNING); tree.step(); - node = findNode(tree, "repeat", "REPEAT 2x-6x"); + node = findNode(tree, "repeat", "REPEAT 3x"); assert.strictEqual(node.state, State.RUNNING); tree.step(); - node = findNode(tree, "repeat", "REPEAT 2x-6x"); - assert.strictEqual(node.state, State.RUNNING); - - tree.step(); - - node = findNode(tree, "repeat", "REPEAT 2x-6x"); + node = findNode(tree, "repeat", "REPEAT 3x"); assert.strictEqual(node.state, State.SUCCEEDED); }); - it("and if the 'random' behaviour tree option is defined will use it to pick an iteration count from between the minimum and maximum bounds", () => { - const definition = "root { repeat [2, 10] { condition [someCondition] } }"; - const agent = { someCondition: () => true }; - const options = { - // Usually this would return a new pseudo-random number each time, but for the sake of this test we - // just want to make sure that the number we return actually has an impact on the iteration count picked. - // A value of 0.2 should always result in an iteration count of 3. - random: () => 0.2 + it("(JSON)", () => { + const definition: RootNodeDefinition = { + type: "root", + child: { + type: "repeat", + iterations: 3, + child: { + type: "condition", + call: "someCondition" + } + } }; - const tree = new BehaviourTree(definition, agent, options); + const agent = { someCondition: () => true }; + const tree = new BehaviourTree(definition, agent); - let node = findNode(tree, "repeat", "REPEAT 2x-10x"); + let node = findNode(tree, "repeat", "REPEAT 3x"); assert.exists(node); assert.strictEqual(node.state, State.READY); tree.step(); - node = findNode(tree, "repeat", "REPEAT 2x-10x"); + node = findNode(tree, "repeat", "REPEAT 3x"); assert.strictEqual(node.state, State.RUNNING); tree.step(); - node = findNode(tree, "repeat", "REPEAT 2x-10x"); + node = findNode(tree, "repeat", "REPEAT 3x"); assert.strictEqual(node.state, State.RUNNING); tree.step(); - node = findNode(tree, "repeat", "REPEAT 2x-10x"); + node = findNode(tree, "repeat", "REPEAT 3x"); assert.strictEqual(node.state, State.RUNNING); tree.step(); - node = findNode(tree, "repeat", "REPEAT 2x-10x"); + node = findNode(tree, "repeat", "REPEAT 3x"); assert.strictEqual(node.state, State.SUCCEEDED); }); }); + + describe("and minumum and maximum iteration count node arguments are defined", () => { + describe("and if the 'random' behaviour tree option is not defined will pick an iteration count from between the minimum and maximum bounds using Math.random", () => { + it("(MDSL)", () => { + // We have spied on Math.random to always return 0.5 for the sake of this test, so our iteration count should always be 4. + const definition = "root { repeat [2, 6] { condition [someCondition] } }"; + const agent = { someCondition: () => true }; + const tree = new BehaviourTree(definition, agent); + + let node = findNode(tree, "repeat", "REPEAT 2x-6x"); + assert.exists(node); + assert.strictEqual(node.state, State.READY); + + tree.step(); + + node = findNode(tree, "repeat", "REPEAT 2x-6x"); + assert.strictEqual(node.state, State.RUNNING); + + tree.step(); + + node = findNode(tree, "repeat", "REPEAT 2x-6x"); + assert.strictEqual(node.state, State.RUNNING); + + tree.step(); + + node = findNode(tree, "repeat", "REPEAT 2x-6x"); + assert.strictEqual(node.state, State.RUNNING); + + tree.step(); + + node = findNode(tree, "repeat", "REPEAT 2x-6x"); + assert.strictEqual(node.state, State.RUNNING); + + tree.step(); + + node = findNode(tree, "repeat", "REPEAT 2x-6x"); + assert.strictEqual(node.state, State.SUCCEEDED); + }); + + it("(JSON)", () => { + // We have spied on Math.random to always return 0.5 for the sake of this test, so our iteration count should always be 4. + const definition: RootNodeDefinition = { + type: "root", + child: { + type: "repeat", + iterations: [2, 6], + child: { + type: "condition", + call: "someCondition" + } + } + }; + const agent = { someCondition: () => true }; + const tree = new BehaviourTree(definition, agent); + + let node = findNode(tree, "repeat", "REPEAT 2x-6x"); + assert.exists(node); + assert.strictEqual(node.state, State.READY); + + tree.step(); + + node = findNode(tree, "repeat", "REPEAT 2x-6x"); + assert.strictEqual(node.state, State.RUNNING); + + tree.step(); + + node = findNode(tree, "repeat", "REPEAT 2x-6x"); + assert.strictEqual(node.state, State.RUNNING); + + tree.step(); + + node = findNode(tree, "repeat", "REPEAT 2x-6x"); + assert.strictEqual(node.state, State.RUNNING); + + tree.step(); + + node = findNode(tree, "repeat", "REPEAT 2x-6x"); + assert.strictEqual(node.state, State.RUNNING); + + tree.step(); + + node = findNode(tree, "repeat", "REPEAT 2x-6x"); + assert.strictEqual(node.state, State.SUCCEEDED); + }); + }); + + describe("and if the 'random' behaviour tree option is defined will use it to pick an iteration count from between the minimum and maximum bounds", () => { + it("(MDSL)", () => { + const definition = "root { repeat [2, 10] { condition [someCondition] } }"; + const agent = { someCondition: () => true }; + const options = { + // Usually this would return a new pseudo-random number each time, but for the sake of this test we + // just want to make sure that the number we return actually has an impact on the iteration count picked. + // A value of 0.2 should always result in an iteration count of 3. + random: () => 0.2 + }; + const tree = new BehaviourTree(definition, agent, options); + + let node = findNode(tree, "repeat", "REPEAT 2x-10x"); + assert.exists(node); + assert.strictEqual(node.state, State.READY); + + tree.step(); + + node = findNode(tree, "repeat", "REPEAT 2x-10x"); + assert.strictEqual(node.state, State.RUNNING); + + tree.step(); + + node = findNode(tree, "repeat", "REPEAT 2x-10x"); + assert.strictEqual(node.state, State.RUNNING); + + tree.step(); + + node = findNode(tree, "repeat", "REPEAT 2x-10x"); + assert.strictEqual(node.state, State.RUNNING); + + tree.step(); + + node = findNode(tree, "repeat", "REPEAT 2x-10x"); + assert.strictEqual(node.state, State.SUCCEEDED); + }); + + it("(JSON)", () => { + const definition: RootNodeDefinition = { + type: "root", + child: { + type: "repeat", + iterations: [2, 10], + child: { + type: "condition", + call: "someCondition" + } + } + }; + const agent = { someCondition: () => true }; + const options = { + // Usually this would return a new pseudo-random number each time, but for the sake of this test we + // just want to make sure that the number we return actually has an impact on the iteration count picked. + // A value of 0.2 should always result in an iteration count of 3. + random: () => 0.2 + }; + const tree = new BehaviourTree(definition, agent, options); + + let node = findNode(tree, "repeat", "REPEAT 2x-10x"); + assert.exists(node); + assert.strictEqual(node.state, State.READY); + + tree.step(); + + node = findNode(tree, "repeat", "REPEAT 2x-10x"); + assert.strictEqual(node.state, State.RUNNING); + + tree.step(); + + node = findNode(tree, "repeat", "REPEAT 2x-10x"); + assert.strictEqual(node.state, State.RUNNING); + + tree.step(); + + node = findNode(tree, "repeat", "REPEAT 2x-10x"); + assert.strictEqual(node.state, State.RUNNING); + + tree.step(); + + node = findNode(tree, "repeat", "REPEAT 2x-10x"); + assert.strictEqual(node.state, State.SUCCEEDED); + }); + }); + }); }); }); diff --git a/test/nodes/decorator/Retry.spec.ts b/test/nodes/decorator/Retry.spec.ts index e207d6b..efe20cd 100644 --- a/test/nodes/decorator/Retry.spec.ts +++ b/test/nodes/decorator/Retry.spec.ts @@ -9,13 +9,29 @@ import { findNode } from "../../TestUtilities"; describe("A Retry node", () => { describe("on tree initialisation", () => { - it("will error if the node does not have a single child", () => { - const definition = "root { retry {} }"; - assert.throws( - () => new BehaviourTree(definition, {}), - Error, - "invalid definition: a retry node must have a single child" - ); + describe("will error if the node does not have a single child", () => { + it("(MDSL)", () => { + const definition = "root { retry {} }"; + assert.throws( + () => new BehaviourTree(definition, {}), + Error, + "invalid definition: a retry node must have a single child" + ); + }); + + it("(JSON)", () => { + const definition = { + type: "root", + child: { + type: "retry" + } + } as any; + assert.throws( + () => new BehaviourTree(definition, {}), + Error, + "invalid definition: expected property 'child' to be defined for retry node at depth '1'" + ); + }); }); }); @@ -29,138 +45,328 @@ describe("A Retry node", () => { afterEach(() => sandbox.restore()); - it("will move to the SUCCEEDED state if the child node moves to the SUCCEEDED state", () => { - const definition = "root { retry { condition [someCondition] } }"; - const agent = { someCondition: () => true }; - const tree = new BehaviourTree(definition, agent); + describe("will move to the SUCCEEDED state if the child node moves to the SUCCEEDED state", () => { + it("(MDSL)", () => { + const definition = "root { retry { condition [someCondition] } }"; + const agent = { someCondition: () => true }; + const tree = new BehaviourTree(definition, agent); - let node = findNode(tree, "retry", "RETRY"); - assert.exists(node); - assert.strictEqual(node.state, State.READY); + let node = findNode(tree, "retry", "RETRY"); + assert.exists(node); + assert.strictEqual(node.state, State.READY); - tree.step(); + tree.step(); - node = findNode(tree, "retry", "RETRY"); - assert.strictEqual(node.state, State.SUCCEEDED); - }); + node = findNode(tree, "retry", "RETRY"); + assert.strictEqual(node.state, State.SUCCEEDED); + }); - it("will move to the RUNNING state if the child node moves to the FAILED state", () => { - const definition = "root { retry { condition [someCondition] } }"; - const agent = { someCondition: () => false }; - const tree = new BehaviourTree(definition, agent); + it("(JSON)", () => { + const definition: RootNodeDefinition = { + type: "root", + child: { + type: "retry", + child: { + type: "condition", + call: "someCondition" + } + } + }; + const agent = { someCondition: () => true }; + const tree = new BehaviourTree(definition, agent); - let node = findNode(tree, "retry", "RETRY"); - assert.exists(node); - assert.strictEqual(node.state, State.READY); + let node = findNode(tree, "retry", "RETRY"); + assert.exists(node); + assert.strictEqual(node.state, State.READY); - tree.step(); + tree.step(); - node = findNode(tree, "retry", "RETRY"); - assert.strictEqual(node.state, State.RUNNING); + node = findNode(tree, "retry", "RETRY"); + assert.strictEqual(node.state, State.SUCCEEDED); + }); }); - it("and an attempt count node argument is defined will attempt to re-run the child node until the attempt count is reached", () => { - const definition = "root { retry [3] { condition [someCondition] } }"; - const agent = { someCondition: () => false }; - const tree = new BehaviourTree(definition, agent); - - let node = findNode(tree, "retry", "RETRY 3x"); - assert.exists(node); - assert.strictEqual(node.state, State.READY); - - tree.step(); + describe("will move to the RUNNING state if the child node moves to the FAILED state", () => { + it("(MDSL)", () => { + const definition = "root { retry { condition [someCondition] } }"; + const agent = { someCondition: () => false }; + const tree = new BehaviourTree(definition, agent); - node = findNode(tree, "retry", "RETRY 3x"); - assert.strictEqual(node.state, State.RUNNING); + let node = findNode(tree, "retry", "RETRY"); + assert.exists(node); + assert.strictEqual(node.state, State.READY); - tree.step(); + tree.step(); - node = findNode(tree, "retry", "RETRY 3x"); - assert.strictEqual(node.state, State.RUNNING); + node = findNode(tree, "retry", "RETRY"); + assert.strictEqual(node.state, State.RUNNING); + }); - tree.step(); + it("(JSON)", () => { + const definition: RootNodeDefinition = { + type: "root", + child: { + type: "retry", + child: { + type: "condition", + call: "someCondition" + } + } + }; + const agent = { someCondition: () => false }; + const tree = new BehaviourTree(definition, agent); - node = findNode(tree, "retry", "RETRY 3x"); - assert.strictEqual(node.state, State.RUNNING); + let node = findNode(tree, "retry", "RETRY"); + assert.exists(node); + assert.strictEqual(node.state, State.READY); - tree.step(); + tree.step(); - node = findNode(tree, "retry", "RETRY 3x"); - assert.strictEqual(node.state, State.FAILED); + node = findNode(tree, "retry", "RETRY"); + assert.strictEqual(node.state, State.RUNNING); + }); }); - describe("and minumum and maximum attempt count node arguments are defined", () => { - it("and if the 'random' behaviour tree option is not defined will pick an attempt count from between the minimum and maximum bounds using Math.random", () => { - // We have spied on Math.random to always return 0.5 for the sake of this test, so our attempt count should always be 4. - const definition = "root { retry [2, 6] { condition [someCondition] } }"; + describe("and an attempt count node argument is defined will attempt to re-run the child node until the attempt count is reached", () => { + it("(MDSL)", () => { + const definition = "root { retry [3] { condition [someCondition] } }"; const agent = { someCondition: () => false }; const tree = new BehaviourTree(definition, agent); - let node = findNode(tree, "retry", "RETRY 2x-6x"); + let node = findNode(tree, "retry", "RETRY 3x"); assert.exists(node); assert.strictEqual(node.state, State.READY); tree.step(); - node = findNode(tree, "retry", "RETRY 2x-6x"); + node = findNode(tree, "retry", "RETRY 3x"); assert.strictEqual(node.state, State.RUNNING); tree.step(); - node = findNode(tree, "retry", "RETRY 2x-6x"); + node = findNode(tree, "retry", "RETRY 3x"); assert.strictEqual(node.state, State.RUNNING); tree.step(); - node = findNode(tree, "retry", "RETRY 2x-6x"); + node = findNode(tree, "retry", "RETRY 3x"); assert.strictEqual(node.state, State.RUNNING); tree.step(); - node = findNode(tree, "retry", "RETRY 2x-6x"); - assert.strictEqual(node.state, State.RUNNING); - - tree.step(); - - node = findNode(tree, "retry", "RETRY 2x-6x"); + node = findNode(tree, "retry", "RETRY 3x"); assert.strictEqual(node.state, State.FAILED); }); - it("and if the 'random' behaviour tree option is defined will use it to pick an attempt count from between the minimum and maximum bounds", () => { - const definition = "root { retry [2, 10] { condition [someCondition] } }"; - const agent = { someCondition: () => false }; - const options = { - // Usually this would return a new pseudo-random number each time, but for the sake of this test we - // just want to make sure that the number we return actually has an impact on the attempt count picked. - // A value of 0.2 should always result in an attempt count of 3. - random: () => 0.2 + it("(JSON)", () => { + const definition: RootNodeDefinition = { + type: "root", + child: { + type: "retry", + attempts: 3, + child: { + type: "condition", + call: "someCondition" + } + } }; - const tree = new BehaviourTree(definition, agent, options); + const agent = { someCondition: () => false }; + const tree = new BehaviourTree(definition, agent); - let node = findNode(tree, "retry", "RETRY 2x-10x"); + let node = findNode(tree, "retry", "RETRY 3x"); assert.exists(node); assert.strictEqual(node.state, State.READY); tree.step(); - node = findNode(tree, "retry", "RETRY 2x-10x"); + node = findNode(tree, "retry", "RETRY 3x"); assert.strictEqual(node.state, State.RUNNING); tree.step(); - node = findNode(tree, "retry", "RETRY 2x-10x"); + node = findNode(tree, "retry", "RETRY 3x"); assert.strictEqual(node.state, State.RUNNING); tree.step(); - node = findNode(tree, "retry", "RETRY 2x-10x"); + node = findNode(tree, "retry", "RETRY 3x"); assert.strictEqual(node.state, State.RUNNING); tree.step(); - node = findNode(tree, "retry", "RETRY 2x-10x"); + node = findNode(tree, "retry", "RETRY 3x"); assert.strictEqual(node.state, State.FAILED); }); }); + + describe("and minumum and maximum attempt count node arguments are defined", () => { + describe("and if the 'random' behaviour tree option is not defined will pick an attempt count from between the minimum and maximum bounds using Math.random", () => { + it("(MDSL)", () => { + // We have spied on Math.random to always return 0.5 for the sake of this test, so our attempt count should always be 4. + const definition = "root { retry [2, 6] { condition [someCondition] } }"; + const agent = { someCondition: () => false }; + const tree = new BehaviourTree(definition, agent); + + let node = findNode(tree, "retry", "RETRY 2x-6x"); + assert.exists(node); + assert.strictEqual(node.state, State.READY); + + tree.step(); + + node = findNode(tree, "retry", "RETRY 2x-6x"); + assert.strictEqual(node.state, State.RUNNING); + + tree.step(); + + node = findNode(tree, "retry", "RETRY 2x-6x"); + assert.strictEqual(node.state, State.RUNNING); + + tree.step(); + + node = findNode(tree, "retry", "RETRY 2x-6x"); + assert.strictEqual(node.state, State.RUNNING); + + tree.step(); + + node = findNode(tree, "retry", "RETRY 2x-6x"); + assert.strictEqual(node.state, State.RUNNING); + + tree.step(); + + node = findNode(tree, "retry", "RETRY 2x-6x"); + assert.strictEqual(node.state, State.FAILED); + }); + + it("(JSON)", () => { + // We have spied on Math.random to always return 0.5 for the sake of this test, so our attempt count should always be 4. + const definition: RootNodeDefinition = { + type: "root", + child: { + type: "retry", + attempts: [2, 6], + child: { + type: "condition", + call: "someCondition" + } + } + }; + const agent = { someCondition: () => false }; + const tree = new BehaviourTree(definition, agent); + + let node = findNode(tree, "retry", "RETRY 2x-6x"); + assert.exists(node); + assert.strictEqual(node.state, State.READY); + + tree.step(); + + node = findNode(tree, "retry", "RETRY 2x-6x"); + assert.strictEqual(node.state, State.RUNNING); + + tree.step(); + + node = findNode(tree, "retry", "RETRY 2x-6x"); + assert.strictEqual(node.state, State.RUNNING); + + tree.step(); + + node = findNode(tree, "retry", "RETRY 2x-6x"); + assert.strictEqual(node.state, State.RUNNING); + + tree.step(); + + node = findNode(tree, "retry", "RETRY 2x-6x"); + assert.strictEqual(node.state, State.RUNNING); + + tree.step(); + + node = findNode(tree, "retry", "RETRY 2x-6x"); + assert.strictEqual(node.state, State.FAILED); + }); + }); + + describe("and if the 'random' behaviour tree option is defined will use it to pick an attempt count from between the minimum and maximum bounds", () => { + it("(MDSL)", () => { + const definition = "root { retry [2, 10] { condition [someCondition] } }"; + const agent = { someCondition: () => false }; + const options = { + // Usually this would return a new pseudo-random number each time, but for the sake of this test we + // just want to make sure that the number we return actually has an impact on the attempt count picked. + // A value of 0.2 should always result in an attempt count of 3. + random: () => 0.2 + }; + const tree = new BehaviourTree(definition, agent, options); + + let node = findNode(tree, "retry", "RETRY 2x-10x"); + assert.exists(node); + assert.strictEqual(node.state, State.READY); + + tree.step(); + + node = findNode(tree, "retry", "RETRY 2x-10x"); + assert.strictEqual(node.state, State.RUNNING); + + tree.step(); + + node = findNode(tree, "retry", "RETRY 2x-10x"); + assert.strictEqual(node.state, State.RUNNING); + + tree.step(); + + node = findNode(tree, "retry", "RETRY 2x-10x"); + assert.strictEqual(node.state, State.RUNNING); + + tree.step(); + + node = findNode(tree, "retry", "RETRY 2x-10x"); + assert.strictEqual(node.state, State.FAILED); + }); + + it("(JSON)", () => { + const definition: RootNodeDefinition = { + type: "root", + child: { + type: "retry", + attempts: [2, 10], + child: { + type: "condition", + call: "someCondition" + } + } + }; + const agent = { someCondition: () => false }; + const options = { + // Usually this would return a new pseudo-random number each time, but for the sake of this test we + // just want to make sure that the number we return actually has an impact on the attempt count picked. + // A value of 0.2 should always result in an attempt count of 3. + random: () => 0.2 + }; + const tree = new BehaviourTree(definition, agent, options); + + let node = findNode(tree, "retry", "RETRY 2x-10x"); + assert.exists(node); + assert.strictEqual(node.state, State.READY); + + tree.step(); + + node = findNode(tree, "retry", "RETRY 2x-10x"); + assert.strictEqual(node.state, State.RUNNING); + + tree.step(); + + node = findNode(tree, "retry", "RETRY 2x-10x"); + assert.strictEqual(node.state, State.RUNNING); + + tree.step(); + + node = findNode(tree, "retry", "RETRY 2x-10x"); + assert.strictEqual(node.state, State.RUNNING); + + tree.step(); + + node = findNode(tree, "retry", "RETRY 2x-10x"); + assert.strictEqual(node.state, State.FAILED); + }); + }); + }); }); }); From 903e634626cb0deaccad446d34f82fa271fbcc9b Mon Sep 17 00:00:00 2001 From: Nikolas Howard Date: Tue, 20 Feb 2024 17:33:01 +0000 Subject: [PATCH 31/48] specs --- test/BehaviourTree.spec.ts | 26 +- test/nodes/composite/Parallel.spec.ts | 233 +++++++++++++- test/nodes/composite/Selector.spec.ts | 146 ++++++++- test/nodes/composite/Sequence.spec.ts | 190 +++++++++++- test/nodes/decorator/Repeat.spec.ts | 162 ++++++++-- test/nodes/decorator/Retry.spec.ts | 162 ++++++++-- test/nodes/leaf/Wait.spec.ts | 429 ++++++++++++++++++++------ 7 files changed, 1189 insertions(+), 159 deletions(-) diff --git a/test/BehaviourTree.spec.ts b/test/BehaviourTree.spec.ts index 67ebbc4..047582c 100644 --- a/test/BehaviourTree.spec.ts +++ b/test/BehaviourTree.spec.ts @@ -1,9 +1,7 @@ import { assert } from "chai"; -import sinon from "sinon"; import { BehaviourTree, State } from "../src/index"; import { RootNodeDefinition } from "../src/BehaviourTreeDefinition"; -import { Agent } from "../src/Agent"; import { findNode } from "./TestUtilities"; @@ -147,20 +145,20 @@ describe("A BehaviourTree instance", () => { const agent = { getActionResult: () => State.SUCCEEDED }; const tree = new BehaviourTree(definition, agent); - assert.strictEqual(findNode(tree, "root", "ROOT").state, State.READY); - assert.strictEqual(findNode(tree, "sequence", "SEQUENCE").state, State.READY); + assert.strictEqual(findNode(tree, "root").state, State.READY); + assert.strictEqual(findNode(tree, "sequence").state, State.READY); assert.strictEqual(findNode(tree, "action", "getActionResult").state, State.READY); tree.step(); - assert.strictEqual(findNode(tree, "root", "ROOT").state, State.SUCCEEDED); - assert.strictEqual(findNode(tree, "sequence", "SEQUENCE").state, State.SUCCEEDED); + assert.strictEqual(findNode(tree, "root").state, State.SUCCEEDED); + assert.strictEqual(findNode(tree, "sequence").state, State.SUCCEEDED); assert.strictEqual(findNode(tree, "action", "getActionResult").state, State.SUCCEEDED); tree.reset(); - assert.strictEqual(findNode(tree, "root", "ROOT").state, State.READY); - assert.strictEqual(findNode(tree, "sequence", "SEQUENCE").state, State.READY); + assert.strictEqual(findNode(tree, "root").state, State.READY); + assert.strictEqual(findNode(tree, "sequence").state, State.READY); assert.strictEqual(findNode(tree, "action", "getActionResult").state, State.READY); }); @@ -180,20 +178,20 @@ describe("A BehaviourTree instance", () => { const agent = { getActionResult: () => State.SUCCEEDED }; const tree = new BehaviourTree(definition, agent); - assert.strictEqual(findNode(tree, "root", "ROOT").state, State.READY); - assert.strictEqual(findNode(tree, "sequence", "SEQUENCE").state, State.READY); + assert.strictEqual(findNode(tree, "root").state, State.READY); + assert.strictEqual(findNode(tree, "sequence").state, State.READY); assert.strictEqual(findNode(tree, "action", "getActionResult").state, State.READY); tree.step(); - assert.strictEqual(findNode(tree, "root", "ROOT").state, State.SUCCEEDED); - assert.strictEqual(findNode(tree, "sequence", "SEQUENCE").state, State.SUCCEEDED); + assert.strictEqual(findNode(tree, "root").state, State.SUCCEEDED); + assert.strictEqual(findNode(tree, "sequence").state, State.SUCCEEDED); assert.strictEqual(findNode(tree, "action", "getActionResult").state, State.SUCCEEDED); tree.reset(); - assert.strictEqual(findNode(tree, "root", "ROOT").state, State.READY); - assert.strictEqual(findNode(tree, "sequence", "SEQUENCE").state, State.READY); + assert.strictEqual(findNode(tree, "root").state, State.READY); + assert.strictEqual(findNode(tree, "sequence").state, State.READY); assert.strictEqual(findNode(tree, "action", "getActionResult").state, State.READY); }); }); diff --git a/test/nodes/composite/Parallel.spec.ts b/test/nodes/composite/Parallel.spec.ts index 68c6af4..83854fc 100644 --- a/test/nodes/composite/Parallel.spec.ts +++ b/test/nodes/composite/Parallel.spec.ts @@ -34,5 +34,236 @@ describe("A Parallel node", () => { }); }); - describe("when updated as part of a tree step will", () => {}); + describe("when updated as part of a tree step will", () => { + describe("update each child node concurrently", () => { + it("(MDSL)", () => { + const definition = "root { parallel { action [actionRunning1] action [actionRunning2] } }"; + const agent = { + actionRunning1: () => {}, + actionRunning2: () => {} + }; + const tree = new BehaviourTree(definition, agent); + + assert.strictEqual(findNode(tree, "root").state, State.READY); + assert.strictEqual(findNode(tree, "parallel").state, State.READY); + assert.strictEqual(findNode(tree, "action", "actionRunning1").state, State.READY); + assert.strictEqual(findNode(tree, "action", "actionRunning2").state, State.READY); + + tree.step(); + + assert.strictEqual(findNode(tree, "root").state, State.RUNNING); + assert.strictEqual(findNode(tree, "parallel").state, State.RUNNING); + assert.strictEqual(findNode(tree, "action", "actionRunning1").state, State.RUNNING); + assert.strictEqual(findNode(tree, "action", "actionRunning2").state, State.RUNNING); + }); + + it("(JSON)", () => { + const definition: RootNodeDefinition = { + type: "root", + child: { + type: "parallel", + children: [ + { + type: "action", + call: "actionRunning1" + }, + { + type: "action", + call: "actionRunning2" + } + ] + } + }; + const agent = { + actionRunning1: () => {}, + actionRunning2: () => {} + }; + const tree = new BehaviourTree(definition, agent); + + assert.strictEqual(findNode(tree, "root").state, State.READY); + assert.strictEqual(findNode(tree, "parallel").state, State.READY); + assert.strictEqual(findNode(tree, "action", "actionRunning1").state, State.READY); + assert.strictEqual(findNode(tree, "action", "actionRunning2").state, State.READY); + + tree.step(); + + assert.strictEqual(findNode(tree, "root").state, State.RUNNING); + assert.strictEqual(findNode(tree, "parallel").state, State.RUNNING); + assert.strictEqual(findNode(tree, "action", "actionRunning1").state, State.RUNNING); + assert.strictEqual(findNode(tree, "action", "actionRunning2").state, State.RUNNING); + }); + }); + + describe("move to the FAILED state if any child node moves to the FAILED state", () => { + it("(MDSL)", () => { + const definition = "root { parallel { action [action1] action [action2] } }"; + const agent = { + action1: () => {}, + action2: () => {} + }; + const tree = new BehaviourTree(definition, agent); + + assert.strictEqual(findNode(tree, "root").state, State.READY); + assert.strictEqual(findNode(tree, "parallel").state, State.READY); + assert.strictEqual(findNode(tree, "action", "action1").state, State.READY); + assert.strictEqual(findNode(tree, "action", "action2").state, State.READY); + + tree.step(); + + assert.strictEqual(findNode(tree, "root").state, State.RUNNING); + assert.strictEqual(findNode(tree, "parallel").state, State.RUNNING); + assert.strictEqual(findNode(tree, "action", "action1").state, State.RUNNING); + assert.strictEqual(findNode(tree, "action", "action2").state, State.RUNNING); + + agent.action2 = () => State.FAILED; + + tree.step(); + + assert.strictEqual(findNode(tree, "root").state, State.FAILED); + assert.strictEqual(findNode(tree, "parallel").state, State.FAILED); + assert.strictEqual(findNode(tree, "action", "action1").state, State.READY); + assert.strictEqual(findNode(tree, "action", "action2").state, State.FAILED); + }); + + it("(JSON)", () => { + const definition: RootNodeDefinition = { + type: "root", + child: { + type: "parallel", + children: [ + { + type: "action", + call: "action1" + }, + { + type: "action", + call: "action2" + } + ] + } + }; + const agent = { + action1: () => {}, + action2: () => {} + }; + const tree = new BehaviourTree(definition, agent); + + assert.strictEqual(findNode(tree, "root").state, State.READY); + assert.strictEqual(findNode(tree, "parallel").state, State.READY); + assert.strictEqual(findNode(tree, "action", "action1").state, State.READY); + assert.strictEqual(findNode(tree, "action", "action2").state, State.READY); + + tree.step(); + + assert.strictEqual(findNode(tree, "root").state, State.RUNNING); + assert.strictEqual(findNode(tree, "parallel").state, State.RUNNING); + assert.strictEqual(findNode(tree, "action", "action1").state, State.RUNNING); + assert.strictEqual(findNode(tree, "action", "action2").state, State.RUNNING); + + agent.action2 = () => State.FAILED; + + tree.step(); + + assert.strictEqual(findNode(tree, "root").state, State.FAILED); + assert.strictEqual(findNode(tree, "parallel").state, State.FAILED); + assert.strictEqual(findNode(tree, "action", "action1").state, State.READY); + assert.strictEqual(findNode(tree, "action", "action2").state, State.FAILED); + }); + }); + + describe("move to the SUCCEEDED state if any child node moves to the SUCCEEDED state", () => { + it("(MDSL)", () => { + const definition = "root { parallel { action [action1] action [action2] } }"; + const agent = { + action1: () => {}, + action2: () => {} + }; + const tree = new BehaviourTree(definition, agent); + + assert.strictEqual(findNode(tree, "root").state, State.READY); + assert.strictEqual(findNode(tree, "parallel").state, State.READY); + assert.strictEqual(findNode(tree, "action", "action1").state, State.READY); + assert.strictEqual(findNode(tree, "action", "action2").state, State.READY); + + tree.step(); + + assert.strictEqual(findNode(tree, "root").state, State.RUNNING); + assert.strictEqual(findNode(tree, "parallel").state, State.RUNNING); + assert.strictEqual(findNode(tree, "action", "action1").state, State.RUNNING); + assert.strictEqual(findNode(tree, "action", "action2").state, State.RUNNING); + + agent.action1 = () => State.SUCCEEDED; + + tree.step(); + + assert.strictEqual(findNode(tree, "root").state, State.RUNNING); + assert.strictEqual(findNode(tree, "parallel").state, State.RUNNING); + assert.strictEqual(findNode(tree, "action", "action1").state, State.SUCCEEDED); + assert.strictEqual(findNode(tree, "action", "action2").state, State.RUNNING); + + agent.action2 = () => State.SUCCEEDED; + + tree.step(); + + assert.strictEqual(findNode(tree, "root").state, State.SUCCEEDED); + assert.strictEqual(findNode(tree, "parallel").state, State.SUCCEEDED); + assert.strictEqual(findNode(tree, "action", "action1").state, State.SUCCEEDED); + assert.strictEqual(findNode(tree, "action", "action2").state, State.SUCCEEDED); + }); + + it("(JSON)", () => { + const definition: RootNodeDefinition = { + type: "root", + child: { + type: "parallel", + children: [ + { + type: "action", + call: "action1" + }, + { + type: "action", + call: "action2" + } + ] + } + }; + const agent = { + action1: () => {}, + action2: () => {} + }; + const tree = new BehaviourTree(definition, agent); + + assert.strictEqual(findNode(tree, "root").state, State.READY); + assert.strictEqual(findNode(tree, "parallel").state, State.READY); + assert.strictEqual(findNode(tree, "action", "action1").state, State.READY); + assert.strictEqual(findNode(tree, "action", "action2").state, State.READY); + + tree.step(); + + assert.strictEqual(findNode(tree, "root").state, State.RUNNING); + assert.strictEqual(findNode(tree, "parallel").state, State.RUNNING); + assert.strictEqual(findNode(tree, "action", "action1").state, State.RUNNING); + assert.strictEqual(findNode(tree, "action", "action2").state, State.RUNNING); + + agent.action1 = () => State.SUCCEEDED; + + tree.step(); + + assert.strictEqual(findNode(tree, "root").state, State.RUNNING); + assert.strictEqual(findNode(tree, "parallel").state, State.RUNNING); + assert.strictEqual(findNode(tree, "action", "action1").state, State.SUCCEEDED); + assert.strictEqual(findNode(tree, "action", "action2").state, State.RUNNING); + + agent.action2 = () => State.SUCCEEDED; + + tree.step(); + + assert.strictEqual(findNode(tree, "root").state, State.SUCCEEDED); + assert.strictEqual(findNode(tree, "parallel").state, State.SUCCEEDED); + assert.strictEqual(findNode(tree, "action", "action1").state, State.SUCCEEDED); + assert.strictEqual(findNode(tree, "action", "action2").state, State.SUCCEEDED); + }); + }); + }); }); diff --git a/test/nodes/composite/Selector.spec.ts b/test/nodes/composite/Selector.spec.ts index ba21258..016ed02 100644 --- a/test/nodes/composite/Selector.spec.ts +++ b/test/nodes/composite/Selector.spec.ts @@ -2,7 +2,6 @@ import { assert } from "chai"; import { BehaviourTree, State } from "../../../src/index"; import { RootNodeDefinition } from "../../../src/BehaviourTreeDefinition"; -import { Agent } from "../../../src/Agent"; import { findNode } from "../../TestUtilities"; @@ -36,9 +35,134 @@ describe("A Selector node", () => { }); describe("when updated as part of a tree step will", () => { - describe("move to the FAILED state if all child nodes move to the FAILED state", () => {}); + describe("move to the FAILED state if all child nodes move to the FAILED state", () => { + it("(MDSL)", () => { + const definition = "root { selector { action [actionFail1] action [actionFail2] } }"; + const agent = { + actionFail1: () => State.FAILED, + actionFail2: () => State.FAILED + }; + const tree = new BehaviourTree(definition, agent); + + assert.strictEqual(findNode(tree, "root").state, State.READY); + assert.strictEqual(findNode(tree, "selector").state, State.READY); + assert.strictEqual(findNode(tree, "action", "actionFail1").state, State.READY); + assert.strictEqual(findNode(tree, "action", "actionFail2").state, State.READY); + + tree.step(); + + assert.strictEqual(findNode(tree, "root").state, State.FAILED); + assert.strictEqual(findNode(tree, "selector").state, State.FAILED); + assert.strictEqual(findNode(tree, "action", "actionFail1").state, State.FAILED); + assert.strictEqual(findNode(tree, "action", "actionFail2").state, State.FAILED); + }); + + it("(JSON)", () => { + const definition: RootNodeDefinition = { + type: "root", + child: { + type: "selector", + children: [ + { + type: "action", + call: "actionFail1" + }, + { + type: "action", + call: "actionFail2" + } + ] + } + }; + const agent = { + actionFail1: () => State.FAILED, + actionFail2: () => State.FAILED + }; + const tree = new BehaviourTree(definition, agent); + + assert.strictEqual(findNode(tree, "root").state, State.READY); + assert.strictEqual(findNode(tree, "selector").state, State.READY); + assert.strictEqual(findNode(tree, "action", "actionFail1").state, State.READY); + assert.strictEqual(findNode(tree, "action", "actionFail2").state, State.READY); + + tree.step(); - describe("move to the SUCCEEDED state if any child node moves to the SUCCEEDED state", () => {}); + assert.strictEqual(findNode(tree, "root").state, State.FAILED); + assert.strictEqual(findNode(tree, "selector").state, State.FAILED); + assert.strictEqual(findNode(tree, "action", "actionFail1").state, State.FAILED); + assert.strictEqual(findNode(tree, "action", "actionFail2").state, State.FAILED); + }); + }); + + describe("move to the SUCCEEDED state if any child node moves to the SUCCEEDED state", () => { + it("(MDSL)", () => { + const definition = + "root { selector { action [actionFail] action [actionSucceed1] action [actionSucceed2] } }"; + const agent = { + actionSucceed1: () => State.SUCCEEDED, + actionSucceed2: () => State.SUCCEEDED, + actionFail: () => State.FAILED + }; + const tree = new BehaviourTree(definition, agent); + + assert.strictEqual(findNode(tree, "root").state, State.READY); + assert.strictEqual(findNode(tree, "selector").state, State.READY); + assert.strictEqual(findNode(tree, "action", "actionFail").state, State.READY); + assert.strictEqual(findNode(tree, "action", "actionSucceed1").state, State.READY); + assert.strictEqual(findNode(tree, "action", "actionSucceed2").state, State.READY); + + tree.step(); + + assert.strictEqual(findNode(tree, "root").state, State.SUCCEEDED); + assert.strictEqual(findNode(tree, "selector").state, State.SUCCEEDED); + assert.strictEqual(findNode(tree, "action", "actionFail").state, State.FAILED); + assert.strictEqual(findNode(tree, "action", "actionSucceed1").state, State.SUCCEEDED); + assert.strictEqual(findNode(tree, "action", "actionSucceed2").state, State.READY); + }); + + it("(JSON)", () => { + const definition: RootNodeDefinition = { + type: "root", + child: { + type: "selector", + children: [ + { + type: "action", + call: "actionFail" + }, + { + type: "action", + call: "actionSucceed1" + }, + { + type: "action", + call: "actionSucceed2" + } + ] + } + }; + const agent = { + actionSucceed1: () => State.SUCCEEDED, + actionSucceed2: () => State.SUCCEEDED, + actionFail: () => State.FAILED + }; + const tree = new BehaviourTree(definition, agent); + + assert.strictEqual(findNode(tree, "root").state, State.READY); + assert.strictEqual(findNode(tree, "selector").state, State.READY); + assert.strictEqual(findNode(tree, "action", "actionFail").state, State.READY); + assert.strictEqual(findNode(tree, "action", "actionSucceed1").state, State.READY); + assert.strictEqual(findNode(tree, "action", "actionSucceed2").state, State.READY); + + tree.step(); + + assert.strictEqual(findNode(tree, "root").state, State.SUCCEEDED); + assert.strictEqual(findNode(tree, "selector").state, State.SUCCEEDED); + assert.strictEqual(findNode(tree, "action", "actionFail").state, State.FAILED); + assert.strictEqual(findNode(tree, "action", "actionSucceed1").state, State.SUCCEEDED); + assert.strictEqual(findNode(tree, "action", "actionSucceed2").state, State.READY); + }); + }); describe("move to the RUNNING state if any child node is in the RUNNING state", () => { it("(MDSL)", () => { @@ -51,16 +175,16 @@ describe("A Selector node", () => { }; const tree = new BehaviourTree(definition, agent); - assert.strictEqual(findNode(tree, "root", "ROOT").state, State.READY); - assert.strictEqual(findNode(tree, "selector", "SELECTOR").state, State.READY); + assert.strictEqual(findNode(tree, "root").state, State.READY); + assert.strictEqual(findNode(tree, "selector").state, State.READY); assert.strictEqual(findNode(tree, "action", "actionFail").state, State.READY); assert.strictEqual(findNode(tree, "action", "actionRunning").state, State.READY); assert.strictEqual(findNode(tree, "action", "actionSucceed").state, State.READY); tree.step(); - assert.strictEqual(findNode(tree, "root", "ROOT").state, State.RUNNING); - assert.strictEqual(findNode(tree, "selector", "SELECTOR").state, State.RUNNING); + assert.strictEqual(findNode(tree, "root").state, State.RUNNING); + assert.strictEqual(findNode(tree, "selector").state, State.RUNNING); assert.strictEqual(findNode(tree, "action", "actionFail").state, State.FAILED); assert.strictEqual(findNode(tree, "action", "actionRunning").state, State.RUNNING); assert.strictEqual(findNode(tree, "action", "actionSucceed").state, State.READY); @@ -94,16 +218,16 @@ describe("A Selector node", () => { }; const tree = new BehaviourTree(definition, agent); - assert.strictEqual(findNode(tree, "root", "ROOT").state, State.READY); - assert.strictEqual(findNode(tree, "selector", "SELECTOR").state, State.READY); + assert.strictEqual(findNode(tree, "root").state, State.READY); + assert.strictEqual(findNode(tree, "selector").state, State.READY); assert.strictEqual(findNode(tree, "action", "actionFail").state, State.READY); assert.strictEqual(findNode(tree, "action", "actionRunning").state, State.READY); assert.strictEqual(findNode(tree, "action", "actionSucceed").state, State.READY); tree.step(); - assert.strictEqual(findNode(tree, "root", "ROOT").state, State.RUNNING); - assert.strictEqual(findNode(tree, "selector", "SELECTOR").state, State.RUNNING); + assert.strictEqual(findNode(tree, "root").state, State.RUNNING); + assert.strictEqual(findNode(tree, "selector").state, State.RUNNING); assert.strictEqual(findNode(tree, "action", "actionFail").state, State.FAILED); assert.strictEqual(findNode(tree, "action", "actionRunning").state, State.RUNNING); assert.strictEqual(findNode(tree, "action", "actionSucceed").state, State.READY); diff --git a/test/nodes/composite/Sequence.spec.ts b/test/nodes/composite/Sequence.spec.ts index 5bfde86..f7672db 100644 --- a/test/nodes/composite/Sequence.spec.ts +++ b/test/nodes/composite/Sequence.spec.ts @@ -34,5 +34,193 @@ describe("A Sequence node", () => { }); }); - describe("when updated as part of a tree step will", () => {}); + describe("when updated as part of a tree step will", () => { + describe("move to the FAILED state if any child node moves to the FAILED state", () => { + it("(MDSL)", () => { + const definition = "root { sequence { action [actionFail] action [actionSucceed] } }"; + const agent = { + actionFail: () => State.FAILED, + actionSucceed: () => State.SUCCEEDED + }; + const tree = new BehaviourTree(definition, agent); + + assert.strictEqual(findNode(tree, "root").state, State.READY); + assert.strictEqual(findNode(tree, "sequence").state, State.READY); + assert.strictEqual(findNode(tree, "action", "actionFail").state, State.READY); + assert.strictEqual(findNode(tree, "action", "actionSucceed").state, State.READY); + + tree.step(); + + assert.strictEqual(findNode(tree, "root").state, State.FAILED); + assert.strictEqual(findNode(tree, "sequence").state, State.FAILED); + assert.strictEqual(findNode(tree, "action", "actionFail").state, State.FAILED); + assert.strictEqual(findNode(tree, "action", "actionSucceed").state, State.READY); + }); + + it("(JSON)", () => { + const definition: RootNodeDefinition = { + type: "root", + child: { + type: "sequence", + children: [ + { + type: "action", + call: "actionFail" + }, + { + type: "action", + call: "actionSucceed" + } + ] + } + }; + const agent = { + actionFail: () => State.FAILED, + actionSucceed: () => State.SUCCEEDED + }; + const tree = new BehaviourTree(definition, agent); + + assert.strictEqual(findNode(tree, "root").state, State.READY); + assert.strictEqual(findNode(tree, "sequence").state, State.READY); + assert.strictEqual(findNode(tree, "action", "actionFail").state, State.READY); + assert.strictEqual(findNode(tree, "action", "actionSucceed").state, State.READY); + + tree.step(); + + assert.strictEqual(findNode(tree, "root").state, State.FAILED); + assert.strictEqual(findNode(tree, "sequence").state, State.FAILED); + assert.strictEqual(findNode(tree, "action", "actionFail").state, State.FAILED); + assert.strictEqual(findNode(tree, "action", "actionSucceed").state, State.READY); + }); + }); + + describe("move to the SUCCEEDED state if all child nodes move to the SUCCEEDED state", () => { + it("(MDSL)", () => { + const definition = "root { sequence { action [actionSucceed1] action [actionSucceed2] } }"; + const agent = { + actionSucceed1: () => State.SUCCEEDED, + actionSucceed2: () => State.SUCCEEDED + }; + const tree = new BehaviourTree(definition, agent); + + assert.strictEqual(findNode(tree, "root").state, State.READY); + assert.strictEqual(findNode(tree, "sequence").state, State.READY); + assert.strictEqual(findNode(tree, "action", "actionSucceed1").state, State.READY); + assert.strictEqual(findNode(tree, "action", "actionSucceed2").state, State.READY); + + tree.step(); + + assert.strictEqual(findNode(tree, "root").state, State.SUCCEEDED); + assert.strictEqual(findNode(tree, "sequence").state, State.SUCCEEDED); + assert.strictEqual(findNode(tree, "action", "actionSucceed1").state, State.SUCCEEDED); + assert.strictEqual(findNode(tree, "action", "actionSucceed2").state, State.SUCCEEDED); + }); + + it("(JSON)", () => { + const definition: RootNodeDefinition = { + type: "root", + child: { + type: "sequence", + children: [ + { + type: "action", + call: "actionSucceed1" + }, + { + type: "action", + call: "actionSucceed2" + } + ] + } + }; + const agent = { + actionSucceed1: () => State.SUCCEEDED, + actionSucceed2: () => State.SUCCEEDED + }; + const tree = new BehaviourTree(definition, agent); + + assert.strictEqual(findNode(tree, "root").state, State.READY); + assert.strictEqual(findNode(tree, "sequence").state, State.READY); + assert.strictEqual(findNode(tree, "action", "actionSucceed1").state, State.READY); + assert.strictEqual(findNode(tree, "action", "actionSucceed2").state, State.READY); + + tree.step(); + + assert.strictEqual(findNode(tree, "root").state, State.SUCCEEDED); + assert.strictEqual(findNode(tree, "sequence").state, State.SUCCEEDED); + assert.strictEqual(findNode(tree, "action", "actionSucceed1").state, State.SUCCEEDED); + assert.strictEqual(findNode(tree, "action", "actionSucceed2").state, State.SUCCEEDED); + }); + }); + + describe("move to the RUNNING state if any child node is in the RUNNING state", () => { + it("(MDSL)", () => { + const definition = + "root { sequence { action [actionSucceed] action [actionRunning] action [actionFail] } }"; + const agent = { + actionSucceed: () => State.SUCCEEDED, + actionRunning: () => {}, + actionFail: () => State.FAILED + }; + const tree = new BehaviourTree(definition, agent); + + assert.strictEqual(findNode(tree, "root").state, State.READY); + assert.strictEqual(findNode(tree, "sequence").state, State.READY); + assert.strictEqual(findNode(tree, "action", "actionSucceed").state, State.READY); + assert.strictEqual(findNode(tree, "action", "actionRunning").state, State.READY); + assert.strictEqual(findNode(tree, "action", "actionFail").state, State.READY); + + tree.step(); + + assert.strictEqual(findNode(tree, "root").state, State.RUNNING); + assert.strictEqual(findNode(tree, "sequence").state, State.RUNNING); + assert.strictEqual(findNode(tree, "action", "actionSucceed").state, State.SUCCEEDED); + assert.strictEqual(findNode(tree, "action", "actionRunning").state, State.RUNNING); + assert.strictEqual(findNode(tree, "action", "actionFail").state, State.READY); + }); + + it("(JSON)", () => { + const definition: RootNodeDefinition = { + type: "root", + child: { + type: "sequence", + children: [ + { + type: "action", + call: "actionSucceed" + }, + { + type: "action", + call: "actionRunning" + }, + { + type: "action", + call: "actionFail" + } + ] + } + }; + const agent = { + actionSucceed: () => State.SUCCEEDED, + actionRunning: () => {}, + actionFail: () => State.FAILED + }; + const tree = new BehaviourTree(definition, agent); + + assert.strictEqual(findNode(tree, "root").state, State.READY); + assert.strictEqual(findNode(tree, "sequence").state, State.READY); + assert.strictEqual(findNode(tree, "action", "actionSucceed").state, State.READY); + assert.strictEqual(findNode(tree, "action", "actionRunning").state, State.READY); + assert.strictEqual(findNode(tree, "action", "actionFail").state, State.READY); + + tree.step(); + + assert.strictEqual(findNode(tree, "root").state, State.RUNNING); + assert.strictEqual(findNode(tree, "sequence").state, State.RUNNING); + assert.strictEqual(findNode(tree, "action", "actionSucceed").state, State.SUCCEEDED); + assert.strictEqual(findNode(tree, "action", "actionRunning").state, State.RUNNING); + assert.strictEqual(findNode(tree, "action", "actionFail").state, State.READY); + }); + }); + }); }); diff --git a/test/nodes/decorator/Repeat.spec.ts b/test/nodes/decorator/Repeat.spec.ts index 16f9c21..a171416 100644 --- a/test/nodes/decorator/Repeat.spec.ts +++ b/test/nodes/decorator/Repeat.spec.ts @@ -9,28 +9,150 @@ import { findNode } from "../../TestUtilities"; describe("A Repeat node", () => { describe("on tree initialisation", () => { - describe("will error if the node does not have a single child", () => { - it("(MDSL)", () => { - const definition = "root { repeat {} }"; - assert.throws( - () => new BehaviourTree(definition, {}), - Error, - "invalid definition: a repeat node must have a single child" - ); + describe("will error if", () => { + describe("the node does not have a single child", () => { + it("(MDSL)", () => { + const definition = "root { repeat {} }"; + assert.throws( + () => new BehaviourTree(definition, {}), + Error, + "invalid definition: a repeat node must have a single child" + ); + }); + + it("(JSON)", () => { + const definition = { + type: "root", + child: { + type: "repeat" + } + } as any; + assert.throws( + () => new BehaviourTree(definition, {}), + Error, + "invalid definition: expected property 'child' to be defined for repeat node at depth '1'" + ); + }); }); - it("(JSON)", () => { - const definition = { - type: "root", - child: { - type: "repeat" - } - } as any; - assert.throws( - () => new BehaviourTree(definition, {}), - Error, - "invalid definition: expected property 'child' to be defined for repeat node at depth '1'" - ); + describe("the defined node arguments are not integers", () => { + it("(MDSL)", () => { + const definition = "root { repeat ['not', 'integers'] { condition [someCondition] } }"; + assert.throws( + () => new BehaviourTree(definition, {}), + Error, + "invalid definition: repeat node iteration counts must be integer values" + ); + }); + + it("(JSON)", () => { + const definition = { + type: "root", + child: { + type: "repeat", + iterations: ["not", "integers"], + child: { + type: "condition", + call: "someCondition" + } + } + } as any; + assert.throws( + () => new BehaviourTree(definition, {}), + Error, + "invalid definition: expected array containing two integer values for 'iterations' property if defined for repeat node at depth '1'" + ); + }); + }); + + describe("a negative iteration count node argument was defined", () => { + it("(MDSL)", () => { + const definition = "root { repeat [-1] { condition [someCondition] } }"; + assert.throws( + () => new BehaviourTree(definition, {}), + Error, + "invalid definition: a repeat node must have a positive number of iterations if defined" + ); + }); + + it("(JSON)", () => { + const definition = { + type: "root", + child: { + type: "repeat", + iterations: -1, + child: { + type: "condition", + call: "someCondition" + } + } + } as any; + assert.throws( + () => new BehaviourTree(definition, {}), + Error, + "invalid definition: expected positive iterations count for 'iterations' property if defined for repeat node at depth '1'" + ); + }); + }); + + describe("more than two node arguments are defined", () => { + it("(MDSL)", () => { + const definition = "root { repeat [0, 10, 20] { condition [someCondition] } }"; + assert.throws( + () => new BehaviourTree(definition, {}), + Error, + "invalid definition: invalid number of repeat node iteration count arguments defined" + ); + }); + + it("(JSON)", () => { + const definition = { + type: "root", + child: { + type: "repeat", + iterations: [0, 10, 20], + child: { + type: "condition", + call: "someCondition" + } + } + } as any; + assert.throws( + () => new BehaviourTree(definition, {}), + Error, + "invalid definition: expected array containing two integer values for 'iterations' property if defined for repeat node at depth '1'" + ); + }); + }); + + describe("a minimum iteration count node argument is defined that is greater than the maximum iteration count node argument", () => { + it("(MDSL)", () => { + const definition = "root { repeat [10, 5] { condition [someCondition] } }"; + assert.throws( + () => new BehaviourTree(definition, {}), + Error, + "invalid definition: a repeat node must not have a minimum iteration count that exceeds the maximum iteration count" + ); + }); + + it("(JSON)", () => { + const definition = { + type: "root", + child: { + type: "repeat", + iterations: [10, 5], + child: { + type: "condition", + call: "someCondition" + } + } + } as any; + assert.throws( + () => new BehaviourTree(definition, {}), + Error, + "invalid definition: expected minimum iterations count that does not exceed the maximum iterations count for 'iterations' property if defined for repeat node at depth '1'" + ); + }); }); }); }); diff --git a/test/nodes/decorator/Retry.spec.ts b/test/nodes/decorator/Retry.spec.ts index efe20cd..78b4925 100644 --- a/test/nodes/decorator/Retry.spec.ts +++ b/test/nodes/decorator/Retry.spec.ts @@ -9,28 +9,150 @@ import { findNode } from "../../TestUtilities"; describe("A Retry node", () => { describe("on tree initialisation", () => { - describe("will error if the node does not have a single child", () => { - it("(MDSL)", () => { - const definition = "root { retry {} }"; - assert.throws( - () => new BehaviourTree(definition, {}), - Error, - "invalid definition: a retry node must have a single child" - ); + describe("will error if", () => { + describe("the node does not have a single child", () => { + it("(MDSL)", () => { + const definition = "root { retry {} }"; + assert.throws( + () => new BehaviourTree(definition, {}), + Error, + "invalid definition: a retry node must have a single child" + ); + }); + + it("(JSON)", () => { + const definition = { + type: "root", + child: { + type: "retry" + } + } as any; + assert.throws( + () => new BehaviourTree(definition, {}), + Error, + "invalid definition: expected property 'child' to be defined for retry node at depth '1'" + ); + }); }); - it("(JSON)", () => { - const definition = { - type: "root", - child: { - type: "retry" - } - } as any; - assert.throws( - () => new BehaviourTree(definition, {}), - Error, - "invalid definition: expected property 'child' to be defined for retry node at depth '1'" - ); + describe("the defined node arguments are not integers", () => { + it("(MDSL)", () => { + const definition = "root { retry ['not', 'integers'] { condition [someCondition] } }"; + assert.throws( + () => new BehaviourTree(definition, {}), + Error, + "invalid definition: retry node attempt counts must be integer values" + ); + }); + + it("(JSON)", () => { + const definition = { + type: "root", + child: { + type: "retry", + attempts: ["not", "integers"], + child: { + type: "condition", + call: "someCondition" + } + } + } as any; + assert.throws( + () => new BehaviourTree(definition, {}), + Error, + "invalid definition: expected array containing two integer values for 'attempts' property if defined for retry node at depth '1'" + ); + }); + }); + + describe("a negative attempts count node argument was defined", () => { + it("(MDSL)", () => { + const definition = "root { retry [-1] { condition [someCondition] } }"; + assert.throws( + () => new BehaviourTree(definition, {}), + Error, + "invalid definition: a retry node must have a positive number of attempts if defined" + ); + }); + + it("(JSON)", () => { + const definition = { + type: "root", + child: { + type: "retry", + attempts: -1, + child: { + type: "condition", + call: "someCondition" + } + } + } as any; + assert.throws( + () => new BehaviourTree(definition, {}), + Error, + "invalid definition: expected positive attempts count for 'attempts' property if defined for retry node at depth '1'" + ); + }); + }); + + describe("more than two node arguments are defined", () => { + it("(MDSL)", () => { + const definition = "root { retry [0, 10, 20] { condition [someCondition] } }"; + assert.throws( + () => new BehaviourTree(definition, {}), + Error, + "invalid definition: invalid number of retry node attempt count arguments defined" + ); + }); + + it("(JSON)", () => { + const definition = { + type: "root", + child: { + type: "retry", + attempts: [0, 10, 20], + child: { + type: "condition", + call: "someCondition" + } + } + } as any; + assert.throws( + () => new BehaviourTree(definition, {}), + Error, + "invalid definition: expected array containing two integer values for 'attempts' property if defined for retry node at depth '1'" + ); + }); + }); + + describe("a minimum iteration count node argument is defined that is greater than the maximum iteration count node argument", () => { + it("(MDSL)", () => { + const definition = "root { retry [10, 5] { condition [someCondition] } }"; + assert.throws( + () => new BehaviourTree(definition, {}), + Error, + "invalid definition: a retry node must not have a minimum attempt count that exceeds the maximum attempt count" + ); + }); + + it("(JSON)", () => { + const definition = { + type: "root", + child: { + type: "retry", + attempts: [10, 5], + child: { + type: "condition", + call: "someCondition" + } + } + } as any; + assert.throws( + () => new BehaviourTree(definition, {}), + Error, + "invalid definition: expected minimum attempts count that does not exceed the maximum attempts count for 'attempts' property if defined for retry node at depth '1'" + ); + }); }); }); }); diff --git a/test/nodes/leaf/Wait.spec.ts b/test/nodes/leaf/Wait.spec.ts index 19597d9..6c923aa 100644 --- a/test/nodes/leaf/Wait.spec.ts +++ b/test/nodes/leaf/Wait.spec.ts @@ -10,40 +10,108 @@ import { findNode } from "../../TestUtilities"; describe("A Wait node", () => { describe("on tree initialisation", () => { describe("will error if", () => { - it("the defined node arguments are not integers", () => { - const definition = "root { wait ['not', 'integers'] }"; - assert.throws( - () => new BehaviourTree(definition, {}), - Error, - "invalid definition: wait node durations must be integer values" - ); + describe("the defined node arguments are not integers", () => { + it("(MDSL)", () => { + const definition = "root { wait ['not', 'integers'] }"; + assert.throws( + () => new BehaviourTree(definition, {}), + Error, + "invalid definition: wait node durations must be integer values" + ); + }); + + it("(JSON)", () => { + const definition = { + type: "root", + child: { + type: "wait", + duration: ["not", "integers"] + } + } as any; + assert.throws( + () => new BehaviourTree(definition, {}), + Error, + "invalid definition: expected array containing two integer values for 'duration' property if defined for wait node at depth '1'" + ); + }); }); - it("a negative duration node argument was defined", () => { - const definition = "root { wait [-1] }"; - assert.throws( - () => new BehaviourTree(definition, {}), - Error, - "invalid definition: a wait node must have a positive duration" - ); + describe("a negative duration node argument was defined", () => { + it("(MDSL)", () => { + const definition = "root { wait [-1] }"; + assert.throws( + () => new BehaviourTree(definition, {}), + Error, + "invalid definition: a wait node must have a positive duration" + ); + }); + + it("(JSON)", () => { + const definition = { + type: "root", + child: { + type: "wait", + duration: -1 + } + } as any; + assert.throws( + () => new BehaviourTree(definition, {}), + Error, + "invalid definition: expected positive duration value for 'duration' property if defined for wait node at depth '1'" + ); + }); }); - it("more than two node arguments are defined", () => { - const definition = "root { wait [0, 1000, 4000] }"; - assert.throws( - () => new BehaviourTree(definition, {}), - Error, - "invalid definition: invalid number of wait node duration arguments defined" - ); + describe("more than two node arguments are defined", () => { + it("(MDSL)", () => { + const definition = "root { wait [0, 1000, 4000] }"; + assert.throws( + () => new BehaviourTree(definition, {}), + Error, + "invalid definition: invalid number of wait node duration arguments defined" + ); + }); + + it("(JSON)", () => { + const definition = { + type: "root", + child: { + type: "wait", + duration: [0, 1000, 4000] + } + } as any; + assert.throws( + () => new BehaviourTree(definition, {}), + Error, + "invalid definition: expected array containing two integer values for 'duration' property if defined for wait node at depth '1'" + ); + }); }); - it("a minimum duration bound node argument is defined that is greater than the maximum duration bound node argument", () => { - const definition = "root { wait [1000, 500] }"; - assert.throws( - () => new BehaviourTree(definition, {}), - Error, - "invalid definition: a wait node must not have a minimum duration that exceeds the maximum duration" - ); + describe("a minimum duration bound node argument is defined that is greater than the maximum duration bound node argument", () => { + it("(MDSL)", () => { + const definition = "root { wait [1000, 500] }"; + assert.throws( + () => new BehaviourTree(definition, {}), + Error, + "invalid definition: a wait node must not have a minimum duration that exceeds the maximum duration" + ); + }); + + it("(JSON)", () => { + const definition = { + type: "root", + child: { + type: "wait", + duration: [1000, 500] + } + } as any; + assert.throws( + () => new BehaviourTree(definition, {}), + Error, + "invalid definition: expected minimum duration value that does not exceed the maximum duration value for 'duration' property if defined for wait node at depth '1'" + ); + }); }); }); }); @@ -63,36 +131,42 @@ describe("A Wait node", () => { sandbox.restore(); }); - it("and an explicit duration was defined will move to the SUCCEEDED state if the duration has expired", () => { - const definition = "root { wait [100] }"; - const tree = new BehaviourTree(definition, {}); + describe("and an explicit duration was defined will move to the SUCCEEDED state if the duration has expired", () => { + it("(MDSL)", () => { + const definition = "root { wait [100] }"; + const tree = new BehaviourTree(definition, {}); - let node = findNode(tree, "wait"); - assert.strictEqual(node.state, State.READY); + let node = findNode(tree, "wait"); + assert.strictEqual(node.state, State.READY); - tree.step(); + tree.step(); - node = findNode(tree, "wait"); - assert.strictEqual(node.state, State.RUNNING); + node = findNode(tree, "wait"); + assert.strictEqual(node.state, State.RUNNING); - clock.tick(99); + clock.tick(99); - tree.step(); + tree.step(); - node = findNode(tree, "wait"); - assert.strictEqual(node.state, State.RUNNING); + node = findNode(tree, "wait"); + assert.strictEqual(node.state, State.RUNNING); - clock.tick(1); + clock.tick(1); - tree.step(); + tree.step(); - node = findNode(tree, "wait"); - assert.strictEqual(node.state, State.SUCCEEDED); - }); + node = findNode(tree, "wait"); + assert.strictEqual(node.state, State.SUCCEEDED); + }); - describe("and min and max durations were defined", () => { - it("will select a random duration between the min and max durations and move to the SUCCEEDED state if the duration has expired", () => { - const definition = "root { wait [5000, 10000] }"; + it("(JSON)", () => { + const definition: RootNodeDefinition = { + type: "root", + child: { + type: "wait", + duration: 100 + } + }; const tree = new BehaviourTree(definition, {}); let node = findNode(tree, "wait"); @@ -103,8 +177,7 @@ describe("A Wait node", () => { node = findNode(tree, "wait"); assert.strictEqual(node.state, State.RUNNING); - // We have spied on Math.random to always return 0.5 for the sake of this test, so our actual duration 'should' be 7500ms. - clock.tick(7499); + clock.tick(99); tree.step(); @@ -118,15 +191,154 @@ describe("A Wait node", () => { node = findNode(tree, "wait"); assert.strictEqual(node.state, State.SUCCEEDED); }); + }); - it("will use the 'random' function to select the duration between the min and max durations if it was defined as a behaviour tree option and move to the SUCCEEDED state if the duration has expired", () => { - const definition = "root { wait [5000, 10000] }"; - const options = { - // Usually this would return a new pseudo-random number each time, but for the sake of this test we - // just want to make sure that the number we return actually has an impact on which duration is picked. - random: () => 0.2 - }; - const tree = new BehaviourTree(definition, {}, options); + describe("and min and max durations were defined", () => { + describe("will select a random duration between the min and max durations and move to the SUCCEEDED state if the duration has expired", () => { + it("(MDSL)", () => { + const definition = "root { wait [5000, 10000] }"; + const tree = new BehaviourTree(definition, {}); + + let node = findNode(tree, "wait"); + assert.strictEqual(node.state, State.READY); + + tree.step(); + + node = findNode(tree, "wait"); + assert.strictEqual(node.state, State.RUNNING); + + // We have spied on Math.random to always return 0.5 for the sake of this test, so our actual duration 'should' be 7500ms. + clock.tick(7499); + + tree.step(); + + node = findNode(tree, "wait"); + assert.strictEqual(node.state, State.RUNNING); + + clock.tick(1); + + tree.step(); + + node = findNode(tree, "wait"); + assert.strictEqual(node.state, State.SUCCEEDED); + }); + + it("(JSON)", () => { + const definition: RootNodeDefinition = { + type: "root", + child: { + type: "wait", + duration: [5000, 10000] + } + }; + const tree = new BehaviourTree(definition, {}); + + let node = findNode(tree, "wait"); + assert.strictEqual(node.state, State.READY); + + tree.step(); + + node = findNode(tree, "wait"); + assert.strictEqual(node.state, State.RUNNING); + + // We have spied on Math.random to always return 0.5 for the sake of this test, so our actual duration 'should' be 7500ms. + clock.tick(7499); + + tree.step(); + + node = findNode(tree, "wait"); + assert.strictEqual(node.state, State.RUNNING); + + clock.tick(1); + + tree.step(); + + node = findNode(tree, "wait"); + assert.strictEqual(node.state, State.SUCCEEDED); + }); + }); + + describe("will use the 'random' function to select the duration between the min and max durations if it was defined as a behaviour tree option and move to the SUCCEEDED state if the duration has expired", () => { + it("(MDSL)", () => { + const definition = "root { wait [5000, 10000] }"; + const options = { + // Usually this would return a new pseudo-random number each time, but for the sake of this test we + // just want to make sure that the number we return actually has an impact on which duration is picked. + random: () => 0.2 + }; + const tree = new BehaviourTree(definition, {}, options); + + let node = findNode(tree, "wait"); + assert.strictEqual(node.state, State.READY); + + tree.step(); + + node = findNode(tree, "wait"); + assert.strictEqual(node.state, State.RUNNING); + + // Our 'random' function option will always return 0.2 for the sake of this test, so our actual duration 'should' be 6000ms. + clock.tick(5999); + + tree.step(); + + node = findNode(tree, "wait"); + assert.strictEqual(node.state, State.RUNNING); + + clock.tick(1); + + tree.step(); + + node = findNode(tree, "wait"); + assert.strictEqual(node.state, State.SUCCEEDED); + }); + + it("(JSON)", () => { + const definition: RootNodeDefinition = { + type: "root", + child: { + type: "wait", + duration: [5000, 10000] + } + }; + const options = { + // Usually this would return a new pseudo-random number each time, but for the sake of this test we + // just want to make sure that the number we return actually has an impact on which duration is picked. + random: () => 0.2 + }; + const tree = new BehaviourTree(definition, {}, options); + + let node = findNode(tree, "wait"); + assert.strictEqual(node.state, State.READY); + + tree.step(); + + node = findNode(tree, "wait"); + assert.strictEqual(node.state, State.RUNNING); + + // Our 'random' function option will always return 0.2 for the sake of this test, so our actual duration 'should' be 6000ms. + clock.tick(5999); + + tree.step(); + + node = findNode(tree, "wait"); + assert.strictEqual(node.state, State.RUNNING); + + clock.tick(1); + + tree.step(); + + node = findNode(tree, "wait"); + assert.strictEqual(node.state, State.SUCCEEDED); + }); + }); + }); + + describe("and an explicit duration or min and max durations were not defined will stay in the RUNNING state until aborted", () => { + it("(MDSL)", () => { + const definition = "root { wait while(CanWait) }"; + let canWait = true; + const agent = { CanWait: () => canWait }; + const tree = new BehaviourTree(definition, agent); let node = findNode(tree, "wait"); assert.strictEqual(node.state, State.READY); @@ -136,68 +348,101 @@ describe("A Wait node", () => { node = findNode(tree, "wait"); assert.strictEqual(node.state, State.RUNNING); - // Our 'random' function option will always return 0.2 for the sake of this test, so our actual duration 'should' be 6000ms. - clock.tick(5999); + clock.tick(1000000); tree.step(); node = findNode(tree, "wait"); assert.strictEqual(node.state, State.RUNNING); - clock.tick(1); + canWait = false; tree.step(); node = findNode(tree, "wait"); - assert.strictEqual(node.state, State.SUCCEEDED); + assert.strictEqual(node.state, State.FAILED); }); - }); - it("and an explicit duration or min and max durations were not defined will stay in the RUNNING state until aborted", () => { - const definition = "root { wait while(CanWait) }"; - let canWait = true; - const agent = { CanWait: () => canWait }; - const tree = new BehaviourTree(definition, agent); + it("(JSON)", () => { + const definition: RootNodeDefinition = { + type: "root", + child: { + type: "wait", + while: { + call: "CanWait" + } + } + }; + let canWait = true; + const agent = { CanWait: () => canWait }; + const tree = new BehaviourTree(definition, agent); - let node = findNode(tree, "wait"); - assert.strictEqual(node.state, State.READY); + let node = findNode(tree, "wait"); + assert.strictEqual(node.state, State.READY); - tree.step(); + tree.step(); - node = findNode(tree, "wait"); - assert.strictEqual(node.state, State.RUNNING); + node = findNode(tree, "wait"); + assert.strictEqual(node.state, State.RUNNING); - clock.tick(1000000); + clock.tick(1000000); - tree.step(); + tree.step(); - node = findNode(tree, "wait"); - assert.strictEqual(node.state, State.RUNNING); + node = findNode(tree, "wait"); + assert.strictEqual(node.state, State.RUNNING); - canWait = false; + canWait = false; - tree.step(); + tree.step(); - node = findNode(tree, "wait"); - assert.strictEqual(node.state, State.FAILED); + node = findNode(tree, "wait"); + assert.strictEqual(node.state, State.FAILED); + }); }); - it("will use the 'getDeltaTime' function to update the elapsed duration if it was defined as a behaviour tree option", () => { - const definition = "root { wait [1000] }"; - const tree = new BehaviourTree(definition, {}, { getDeltaTime: () => 0.5 }); + describe("will use the 'getDeltaTime' function to update the elapsed duration if it was defined as a behaviour tree option", () => { + it("(MDSL)", () => { + const definition = "root { wait [1000] }"; + const tree = new BehaviourTree(definition, {}, { getDeltaTime: () => 0.5 }); - let node = findNode(tree, "wait"); - assert.strictEqual(node.state, State.READY); + let node = findNode(tree, "wait"); + assert.strictEqual(node.state, State.READY); - tree.step(); + tree.step(); - node = findNode(tree, "wait"); - assert.strictEqual(node.state, State.RUNNING); + node = findNode(tree, "wait"); + assert.strictEqual(node.state, State.RUNNING); - tree.step(); + tree.step(); - node = findNode(tree, "wait"); - assert.strictEqual(node.state, State.SUCCEEDED); + node = findNode(tree, "wait"); + assert.strictEqual(node.state, State.SUCCEEDED); + }); + + it("(JSON)", () => { + const definition: RootNodeDefinition = { + type: "root", + child: { + type: "wait", + duration: 1000 + } + }; + const tree = new BehaviourTree(definition, {}, { getDeltaTime: () => 0.5 }); + + let node = findNode(tree, "wait"); + assert.strictEqual(node.state, State.READY); + + tree.step(); + + node = findNode(tree, "wait"); + assert.strictEqual(node.state, State.RUNNING); + + tree.step(); + + node = findNode(tree, "wait"); + assert.strictEqual(node.state, State.SUCCEEDED); + }); }); }); }); From 8115e45d6c14b2aa57e3fa6b7efffdccea1b9ae8 Mon Sep 17 00:00:00 2001 From: Nikolas Howard Date: Wed, 21 Feb 2024 13:29:19 +0000 Subject: [PATCH 32/48] some condition specs --- test/nodes/leaf/Condition.spec.ts | 103 +++++++++++++++++++++++------- 1 file changed, 80 insertions(+), 23 deletions(-) diff --git a/test/nodes/leaf/Condition.spec.ts b/test/nodes/leaf/Condition.spec.ts index 6a176d7..ff29175 100644 --- a/test/nodes/leaf/Condition.spec.ts +++ b/test/nodes/leaf/Condition.spec.ts @@ -8,42 +8,99 @@ import { findNode } from "../../TestUtilities"; describe("A Condition node", () => { describe("on tree initialisation", () => { - it("will error if a condition name identifier is not the first node argument", () => { - const definition = "root { condition [] }"; - assert.throws( - () => new BehaviourTree(definition, {}), - Error, - "invalid definition: expected condition name identifier argument" - ); + describe("will error if no condition function name is defined", () => { + it("(MDSL)", () => { + const definition = "root { condition [] }"; + assert.throws( + () => new BehaviourTree(definition, {}), + Error, + "invalid definition: expected condition name identifier argument" + ); + }); + + it("(JSON)", () => { + const definition = { + type: "root", + child: { + type: "condition" + } + } as any; + assert.throws( + () => new BehaviourTree(definition, {}), + Error, + "invalid definition: expected non-empty string for 'call' property of condition node at depth '1'" + ); + }); }); }); describe("when updated as part of a tree step", () => { - describe("will call the function defined by the first node argument", () => { + describe("will call the condition function", () => { describe("when the referenced function is", () => { - it("a registered function", () => { - BehaviourTree.register("someCondition", () => { - return true; + describe("a registered function", () => { + it("(MDSL)", () => { + BehaviourTree.register("someCondition", () => { + return true; + }); + + const definition = "root { condition [someCondition] }"; + const tree = new BehaviourTree(definition, {}); + + tree.step(); + + const node = findNode(tree, "condition", "someCondition"); + assert.strictEqual(node.state, State.SUCCEEDED); }); - const definition = "root { condition [someCondition] }"; - const tree = new BehaviourTree(definition, {}); + it("(JSON)", () => { + BehaviourTree.register("someCondition", () => { + return true; + }); + + const definition: RootNodeDefinition = { + type: "root", + child: { + type: "condition", + call: "someCondition" + } + }; + const tree = new BehaviourTree(definition, {}); - tree.step(); + tree.step(); - const node = findNode(tree, "condition", "someCondition"); - assert.strictEqual(node.state, State.SUCCEEDED); + const node = findNode(tree, "condition", "someCondition"); + assert.strictEqual(node.state, State.SUCCEEDED); + }); }); - it("an agent function", () => { - const definition = "root { condition [someCondition] }"; - const agent = { someCondition: () => true }; - const tree = new BehaviourTree(definition, agent); + describe("an agent function", () => { + it("(MDSL)", () => { + const definition = "root { condition [someCondition] }"; + const agent = { someCondition: () => true }; + const tree = new BehaviourTree(definition, agent); - tree.step(); + tree.step(); - const node = findNode(tree, "condition", "someCondition"); - assert.strictEqual(node.state, State.SUCCEEDED); + const node = findNode(tree, "condition", "someCondition"); + assert.strictEqual(node.state, State.SUCCEEDED); + }); + + it("(JSON)", () => { + const definition: RootNodeDefinition = { + type: "root", + child: { + type: "condition", + call: "someCondition" + } + }; + const agent = { someCondition: () => true }; + const tree = new BehaviourTree(definition, agent); + + tree.step(); + + const node = findNode(tree, "condition", "someCondition"); + assert.strictEqual(node.state, State.SUCCEEDED); + }); }); }); From e47bf255d3c5fb679bc3ef807dff2864847a6eb1 Mon Sep 17 00:00:00 2001 From: Nikolas Howard Date: Wed, 21 Feb 2024 13:56:59 +0000 Subject: [PATCH 33/48] condition specs --- test/nodes/leaf/Condition.spec.ts | 353 +++++++++++++++++++++++------- 1 file changed, 278 insertions(+), 75 deletions(-) diff --git a/test/nodes/leaf/Condition.spec.ts b/test/nodes/leaf/Condition.spec.ts index ff29175..705152d 100644 --- a/test/nodes/leaf/Condition.spec.ts +++ b/test/nodes/leaf/Condition.spec.ts @@ -7,6 +7,8 @@ import { Agent } from "../../../src/Agent"; import { findNode } from "../../TestUtilities"; describe("A Condition node", () => { + beforeEach(() => BehaviourTree.unregisterAll()); + describe("on tree initialisation", () => { describe("will error if no condition function name is defined", () => { it("(MDSL)", () => { @@ -104,124 +106,325 @@ describe("A Condition node", () => { }); }); - it("and will error if there is no agent function or registered function that matches the condition name", () => { - const definition = "root { condition [someCondition] }"; - let tree: BehaviourTree; - assert.doesNotThrow(() => (tree = new BehaviourTree(definition, {})), Error); - assert.throws( - () => tree.step(), - Error, - "error stepping tree: cannot update condition node as the condition 'someCondition' function is not defined on the agent and has not been registered" - ); + describe("and will error if there is no agent function or registered function that matches the condition name", () => { + it("(MDSL)", () => { + const definition = "root { condition [someCondition] }"; + let tree: BehaviourTree; + assert.doesNotThrow(() => (tree = new BehaviourTree(definition, {})), Error); + assert.throws( + () => tree.step(), + Error, + "error stepping tree: cannot update condition node as the condition 'someCondition' function is not defined on the agent and has not been registered" + ); + }); + + it("(JSON)", () => { + const definition: RootNodeDefinition = { + type: "root", + child: { + type: "condition", + call: "someCondition" + } + }; + let tree: BehaviourTree; + assert.doesNotThrow(() => (tree = new BehaviourTree(definition, {})), Error); + assert.throws( + () => tree.step(), + Error, + "error stepping tree: cannot update condition node as the condition 'someCondition' function is not defined on the agent and has not been registered" + ); + }); }); describe("and move to", () => { - it("the SUCCESS state if the function returns a truthy value", () => { - const definition = "root { condition [someCondition] }"; - const agent = { someCondition: () => true }; - const tree = new BehaviourTree(definition, agent); + describe("the SUCCESS state if the function returns a truthy value", () => { + it("(MDSL)", () => { + const definition = "root { condition [someCondition] }"; + const agent = { someCondition: () => true }; + const tree = new BehaviourTree(definition, agent); - let node = findNode(tree, "condition", "someCondition"); - assert.strictEqual(node.state, State.READY); + let node = findNode(tree, "condition", "someCondition"); + assert.strictEqual(node.state, State.READY); - tree.step(); + tree.step(); - node = findNode(tree, "condition", "someCondition"); - assert.strictEqual(node.state, State.SUCCEEDED); - }); + node = findNode(tree, "condition", "someCondition"); + assert.strictEqual(node.state, State.SUCCEEDED); + }); - it("the FAILED state if the function returns a falsy value", () => { - const definition = "root { condition [someCondition] }"; - const agent = { someCondition: () => false }; - const tree = new BehaviourTree(definition, agent); + it("(JSON)", () => { + const definition: RootNodeDefinition = { + type: "root", + child: { + type: "condition", + call: "someCondition" + } + }; + const agent = { someCondition: () => true }; + const tree = new BehaviourTree(definition, agent); - let node = findNode(tree, "condition", "someCondition"); - assert.strictEqual(node.state, State.READY); + let node = findNode(tree, "condition", "someCondition"); + assert.strictEqual(node.state, State.READY); - tree.step(); + tree.step(); - node = findNode(tree, "condition", "someCondition"); - assert.strictEqual(node.state, State.FAILED); + node = findNode(tree, "condition", "someCondition"); + assert.strictEqual(node.state, State.SUCCEEDED); + }); }); - }); - describe("and pass any node arguments that follow the condition name identifier argument where", () => { - describe("the argument is a", () => { - it("string", () => { - const definition = 'root { condition [someCondition, "hello world!"] }'; - const agent = { - someCondition: (arg: any) => assert.strictEqual(arg, "hello world!") - }; + describe("the FAILED state if the function returns a falsy value", () => { + it("(MDSL)", () => { + const definition = "root { condition [someCondition] }"; + const agent = { someCondition: () => false }; const tree = new BehaviourTree(definition, agent); + let node = findNode(tree, "condition", "someCondition"); + assert.strictEqual(node.state, State.READY); + tree.step(); + + node = findNode(tree, "condition", "someCondition"); + assert.strictEqual(node.state, State.FAILED); }); - it("string with escaped quotes", () => { - const definition = 'root { condition [someCondition, "hello \\" world!"] }'; - const agent = { - someCondition: (arg: any) => assert.strictEqual(arg, 'hello " world!') + it("(JSON)", () => { + const definition: RootNodeDefinition = { + type: "root", + child: { + type: "condition", + call: "someCondition" + } }; + const agent = { someCondition: () => false }; const tree = new BehaviourTree(definition, agent); + let node = findNode(tree, "condition", "someCondition"); + assert.strictEqual(node.state, State.READY); + tree.step(); + + node = findNode(tree, "condition", "someCondition"); + assert.strictEqual(node.state, State.FAILED); }); + }); + }); - it("number", () => { - const definition = "root { condition [someCondition, 23.4567] }"; - const agent = { - someCondition: (arg: any) => assert.strictEqual(arg, 23.4567) - }; - const tree = new BehaviourTree(definition, agent); + describe("and pass any node arguments that follow the condition name identifier argument where", () => { + describe("the argument is a", () => { + describe("string", () => { + it("(MDSL)", () => { + const definition = 'root { condition [someCondition, "hello world!"] }'; + const agent = { + someCondition: (arg: any) => assert.strictEqual(arg, "hello world!") + }; + const tree = new BehaviourTree(definition, agent); + + tree.step(); + }); - tree.step(); + it("(JSON)", () => { + const definition: RootNodeDefinition = { + type: "root", + child: { + type: "condition", + call: "someCondition", + args: ["hello world!"] + } + }; + const agent = { + someCondition: (arg: any) => assert.strictEqual(arg, "hello world!") + }; + const tree = new BehaviourTree(definition, agent); + + tree.step(); + }); }); - it("boolean 'true' literal", () => { - const definition = "root { condition [someCondition, true] }"; - const agent = { - someCondition: (arg: any) => assert.strictEqual(arg, true) - }; - const tree = new BehaviourTree(definition, agent); + describe("string with escaped quotes", () => { + it("(MDSL)", () => { + const definition = 'root { condition [someCondition, "hello \\" world!"] }'; + const agent = { + someCondition: (arg: any) => assert.strictEqual(arg, 'hello " world!') + }; + const tree = new BehaviourTree(definition, agent); - tree.step(); + tree.step(); + }); + + it("(JSON)", () => { + const definition: RootNodeDefinition = { + type: "root", + child: { + type: "condition", + call: "someCondition", + args: ['hello " world!'] + } + }; + const agent = { + someCondition: (arg: any) => assert.strictEqual(arg, 'hello " world!') + }; + const tree = new BehaviourTree(definition, agent); + + tree.step(); + }); + }); + + describe("number", () => { + it("(MDSL)", () => { + const definition = "root { condition [someCondition, 23.4567] }"; + const agent = { + someCondition: (arg: any) => assert.strictEqual(arg, 23.4567) + }; + const tree = new BehaviourTree(definition, agent); + + tree.step(); + }); + + it("(JSON)", () => { + const definition: RootNodeDefinition = { + type: "root", + child: { + type: "condition", + call: "someCondition", + args: [23.4567] + } + }; + const agent = { + someCondition: (arg: any) => assert.strictEqual(arg, 23.4567) + }; + const tree = new BehaviourTree(definition, agent); + + tree.step(); + }); + }); + + describe("boolean 'true' literal", () => { + it("(MDSL)", () => { + const definition = "root { condition [someCondition, true] }"; + const agent = { + someCondition: (arg: any) => assert.strictEqual(arg, true) + }; + const tree = new BehaviourTree(definition, agent); + + tree.step(); + }); + + it("(JSON)", () => { + const definition: RootNodeDefinition = { + type: "root", + child: { + type: "condition", + call: "someCondition", + args: [true] + } + }; + const agent = { + someCondition: (arg: any) => assert.strictEqual(arg, true) + }; + const tree = new BehaviourTree(definition, agent); + + tree.step(); + }); + }); + + describe("boolean 'false' literal", () => { + it("(MDSL)", () => { + const definition = "root { condition [someCondition, false] }"; + const agent = { + someCondition: (arg: any) => assert.strictEqual(arg, false) + }; + const tree = new BehaviourTree(definition, agent); + + tree.step(); + }); + + it("(JSON)", () => { + const definition: RootNodeDefinition = { + type: "root", + child: { + type: "condition", + call: "someCondition", + args: [false] + } + }; + const agent = { + someCondition: (arg: any) => assert.strictEqual(arg, false) + }; + const tree = new BehaviourTree(definition, agent); + + tree.step(); + }); + }); + + describe("null", () => { + it("(MDSL)", () => { + const definition = "root { condition [someCondition, null] }"; + const agent = { + someCondition: (arg: any) => assert.isNull(arg) + }; + const tree = new BehaviourTree(definition, agent); + + tree.step(); + }); + + it("(JSON)", () => { + const definition: RootNodeDefinition = { + type: "root", + child: { + type: "condition", + call: "someCondition", + args: [null] + } + }; + const agent = { + someCondition: (arg: any) => assert.isNull(arg) + }; + const tree = new BehaviourTree(definition, agent); + + tree.step(); + }); }); + }); - it("boolean 'false' literal", () => { - const definition = "root { condition [someCondition, false] }"; + describe("there are multiple arguments", () => { + it("(MDSL)", () => { + const definition = 'root { condition [someCondition, 1.23, "hello world!", false, null] }'; const agent = { - someCondition: (arg: any) => assert.strictEqual(arg, false) + someCondition: (arg0: any, arg1: any, arg2: any, arg3: any) => { + assert.strictEqual(arg0, 1.23); + assert.strictEqual(arg1, "hello world!"); + assert.strictEqual(arg2, false); + assert.strictEqual(arg3, null); + } }; const tree = new BehaviourTree(definition, agent); tree.step(); }); - it("null", () => { - const definition = "root { condition [someCondition, null] }"; + it("(JSON)", () => { + const definition: RootNodeDefinition = { + type: "root", + child: { + type: "condition", + call: "someCondition", + args: [1.23, "hello world!", false, null] + } + }; const agent = { - someCondition: (arg: any) => assert.isNull(arg) + someCondition: (arg0: any, arg1: any, arg2: any, arg3: any) => { + assert.strictEqual(arg0, 1.23); + assert.strictEqual(arg1, "hello world!"); + assert.strictEqual(arg2, false); + assert.strictEqual(arg3, null); + } }; const tree = new BehaviourTree(definition, agent); tree.step(); }); }); - - it("there are multiple arguments", () => { - const definition = 'root { condition [someCondition, 1.23, "hello world!", false, null] }'; - const agent = { - someCondition: (arg0: any, arg1: any, arg2: any, arg3: any) => { - assert.strictEqual(arg0, 1.23); - assert.strictEqual(arg1, "hello world!"); - assert.strictEqual(arg2, false); - assert.strictEqual(arg3, null); - } - }; - const tree = new BehaviourTree(definition, agent); - - tree.step(); - }); }); }); }); From c1dd5d31d979da1199fa5311b2150b8fa6be2b97 Mon Sep 17 00:00:00 2001 From: Nikolas Howard Date: Mon, 26 Feb 2024 08:48:12 +0000 Subject: [PATCH 34/48] actiond and condition specs --- dist/BehaviourTreeDefinition.d.ts | 8 +- dist/bundle.js | 30 +- dist/bundle.js.map | 4 +- dist/index.js | 30 +- dist/index.js.map | 4 +- src/BehaviourTreeDefinition.ts | 8 +- src/nodes/leaf/Action.ts | 35 +- src/nodes/leaf/Condition.ts | 21 +- test/nodes/leaf/Action.spec.ts | 635 ++++++++++++++++++++++++------ test/nodes/leaf/Condition.spec.ts | 146 +++++-- 10 files changed, 726 insertions(+), 195 deletions(-) diff --git a/dist/BehaviourTreeDefinition.d.ts b/dist/BehaviourTreeDefinition.d.ts index 08281af..129b9b3 100644 --- a/dist/BehaviourTreeDefinition.d.ts +++ b/dist/BehaviourTreeDefinition.d.ts @@ -80,11 +80,11 @@ export interface ActionNodeDefinition extends NodeDefinition { */ type: "action"; /** - * The name of the agent function to invoke. + * The name of the agent function or registered function to invoke. */ call: string; /** - * An array of arguments to pass when invoking the agent function. + * An array of arguments to pass when invoking the action function. */ args?: any[]; } @@ -97,11 +97,11 @@ export interface ConditionNodeDefinition extends NodeDefinition { */ type: "condition"; /** - * The name of the agent function to invoke. + * The name of the agent function or registered function to invoke. */ call: string; /** - * An array of arguments to pass when invoking the agent function. + * An array of arguments to pass when invoking the condition function. */ args?: any[]; } diff --git a/dist/bundle.js b/dist/bundle.js index 3c7cb0c..35ca87f 100644 --- a/dist/bundle.js +++ b/dist/bundle.js @@ -1771,9 +1771,14 @@ var mistreevous = (() => { `cannot update action node as the action '${this.actionName}' function is not defined on the agent and has not been registered` ); } - const updateResult = actionFuncInvoker(this.actionArguments); - if (updateResult instanceof Promise) { - updateResult.then( + let actionFunctionResult; + try { + actionFunctionResult = actionFuncInvoker(this.actionArguments); + } catch (error) { + throw new Error(`action function '${this.actionName}' threw '${error}'`); + } + if (actionFunctionResult instanceof Promise) { + actionFunctionResult.then( (result) => { if (!this.isUsingUpdatePromise) { return; @@ -1789,14 +1794,14 @@ var mistreevous = (() => { if (!this.isUsingUpdatePromise) { return; } - throw new Error(reason); + throw new Error(`action function '${this.actionName}' promise rejected with reason '${reason}'`); } ); this.setState("mistreevous.running" /* RUNNING */); this.isUsingUpdatePromise = true; } else { - this.validateUpdateResult(updateResult); - this.setState(updateResult || "mistreevous.running" /* RUNNING */); + this.validateUpdateResult(actionFunctionResult); + this.setState(actionFunctionResult || "mistreevous.running" /* RUNNING */); } } getName = () => this.actionName; @@ -1833,7 +1838,18 @@ var mistreevous = (() => { `cannot update condition node as the condition '${this.conditionName}' function is not defined on the agent and has not been registered` ); } - this.setState(!!conditionFuncInvoker(this.conditionArguments) ? "mistreevous.succeeded" /* SUCCEEDED */ : "mistreevous.failed" /* FAILED */); + let conditionFunctionResult; + try { + conditionFunctionResult = conditionFuncInvoker(this.conditionArguments); + } catch (error) { + throw new Error(`condition function '${this.conditionName}' threw '${error}'`); + } + if (typeof conditionFunctionResult !== "boolean") { + throw new Error( + `expected condition function '${this.conditionName}' to return a boolean but returned '${conditionFunctionResult}'` + ); + } + this.setState(!!conditionFunctionResult ? "mistreevous.succeeded" /* SUCCEEDED */ : "mistreevous.failed" /* FAILED */); } getName = () => this.conditionName; }; diff --git a/dist/bundle.js.map b/dist/bundle.js.map index 9fef22c..ae52249 100644 --- a/dist/bundle.js.map +++ b/dist/bundle.js.map @@ -1,7 +1,7 @@ { "version": 3, "sources": ["../node_modules/lotto-draw/dist/Participant.js", "../node_modules/lotto-draw/dist/Utilities.js", "../node_modules/lotto-draw/dist/Lotto.js", "../node_modules/lotto-draw/dist/createLotto.js", "../node_modules/lotto-draw/dist/index.js", "../src/index.ts", "../src/State.ts", "../src/BehaviourTreeDefinitionUtilities.ts", "../src/mdsl/MDSLUtilities.ts", "../src/mdsl/MDSLNodeArgumentParser.ts", "../src/mdsl/MDSLNodeAttributeParser.ts", "../src/mdsl/MDSLDefinitionParser.ts", "../src/BehaviourTreeDefinitionValidator.ts", "../src/Lookup.ts", "../src/attributes/guards/GuardUnsatisifedException.ts", "../src/attributes/guards/GuardPath.ts", "../src/nodes/Node.ts", "../src/nodes/composite/Composite.ts", "../src/nodes/composite/Parallel.ts", "../src/nodes/composite/Selector.ts", "../src/nodes/composite/Sequence.ts", "../src/nodes/composite/Lotto.ts", "../src/nodes/decorator/Decorator.ts", "../src/nodes/decorator/Fail.ts", "../src/nodes/decorator/Flip.ts", "../src/nodes/decorator/Repeat.ts", "../src/nodes/decorator/Retry.ts", "../src/nodes/decorator/Root.ts", "../src/nodes/decorator/Succeed.ts", "../src/nodes/leaf/Leaf.ts", "../src/nodes/leaf/Action.ts", "../src/nodes/leaf/Condition.ts", "../src/nodes/leaf/Wait.ts", "../src/attributes/Attribute.ts", "../src/attributes/guards/Guard.ts", "../src/attributes/guards/While.ts", "../src/attributes/guards/Until.ts", "../src/attributes/callbacks/Callback.ts", "../src/attributes/callbacks/Entry.ts", "../src/attributes/callbacks/Step.ts", "../src/attributes/callbacks/Exit.ts", "../src/BehaviourTreeBuilder.ts", "../src/BehaviourTree.ts"], - "sourcesContent": ["\"use strict\";\r\nObject.defineProperty(exports, \"__esModule\", { value: true });\r\nexports.Participant = void 0;\r\n/**\r\n * A participant that holds a number of tickets.\r\n */\r\nvar Participant = /** @class */ (function () {\r\n /**\r\n * Creates an instance of the Participant class.\r\n * @param participant The actual participant.\r\n * @param tickets The number of tickets held by the participant.\r\n */\r\n function Participant(participant, tickets) {\r\n if (tickets === void 0) { tickets = 1; }\r\n this._participant = participant;\r\n this._tickets = tickets;\r\n }\r\n Object.defineProperty(Participant.prototype, \"participant\", {\r\n /** Gets the actual participant. */\r\n get: function () {\r\n return this._participant;\r\n },\r\n enumerable: false,\r\n configurable: true\r\n });\r\n Object.defineProperty(Participant.prototype, \"tickets\", {\r\n /** Gets or sets the number of tickets held by the participant. */\r\n get: function () {\r\n return this._tickets;\r\n },\r\n set: function (value) {\r\n this._tickets = value;\r\n },\r\n enumerable: false,\r\n configurable: true\r\n });\r\n return Participant;\r\n}());\r\nexports.Participant = Participant;\r\n", "\"use strict\";\r\nObject.defineProperty(exports, \"__esModule\", { value: true });\r\nexports.isNaturalNumber = exports.isNullOrUndefined = void 0;\r\n/**\r\n * Gets whether the value provided is null or undefined.\r\n * @param value The value to check.\r\n * @returns Whether the value provided is null or undefined.\r\n */\r\nfunction isNullOrUndefined(value) {\r\n return value === null || value === undefined;\r\n}\r\nexports.isNullOrUndefined = isNullOrUndefined;\r\n/**\r\n * Gets whether the value provided is a natural number.\r\n * @param value The value to check.\r\n * @returns Whether the value provided is a natural number.\r\n */\r\nfunction isNaturalNumber(value) {\r\n return typeof value === \"number\" && value >= 1 && Math.floor(value) === value;\r\n}\r\nexports.isNaturalNumber = isNaturalNumber;\r\n", "\"use strict\";\r\nObject.defineProperty(exports, \"__esModule\", { value: true });\r\nexports.Lotto = void 0;\r\nvar Participant_1 = require(\"./Participant\");\r\nvar Utilities_1 = require(\"./Utilities\");\r\n/**\r\n * Represents a lotto consisting of a number of pickable ticket-holding participants.\r\n */\r\nvar Lotto = /** @class */ (function () {\r\n /**\r\n * Creates a new instance of Lotto.\r\n * @param customRandom The custom RNG to use in place of Math.random().\r\n */\r\n function Lotto(customRandom) {\r\n /** The array of participants that are holding tickets in the lotto. */\r\n this._participants = [];\r\n this._customRandom = customRandom;\r\n }\r\n /**\r\n * Adds a participant with the specified number of tickets, or adds to the participant ticket count if the participant already holds tickets.\r\n * @param participant The participant to add or to increase the ticket count for if they already hold tickets.\r\n * @param tickets The number of tickets, defaults to 1.\r\n * @returns The Lotto instance.\r\n */\r\n Lotto.prototype.add = function (participant, tickets) {\r\n if (tickets === void 0) { tickets = 1; }\r\n // Check that we have a valid ticket count.\r\n if (!(0, Utilities_1.isNaturalNumber)(tickets)) {\r\n throw new Error(\"tickets value must be a natural number\");\r\n }\r\n // Check whether this participant has already been added.\r\n var existingParticipant = this._participants.find(function (part) { return part.participant === participant; });\r\n if (existingParticipant) {\r\n // The participant has already been added to the lotto so just add to their ticket count.\r\n existingParticipant.tickets += tickets;\r\n }\r\n else {\r\n // The participant is not part of the lotto so we should add them.\r\n this._participants.push(new Participant_1.Participant(participant, tickets));\r\n }\r\n return this;\r\n };\r\n /**\r\n * Removes the specified number of tickets for the given participant from the draw, or all tickets if a ticket number is not defined.\r\n * @param participant The participant to remove tickets for.\r\n * @param tickets The number of tickets to remove, or undefined if all tickets are to be removed.\r\n * @returns The Lotto instance.\r\n */\r\n Lotto.prototype.remove = function (participant, tickets) {\r\n // Attempt to get the existing participant.\r\n var existingParticipant = this._participants.find(function (part) { return part.participant === participant; });\r\n // There is nothing to do if the specified participant isn't even part of the lotto.\r\n if (!existingParticipant) {\r\n return this;\r\n }\r\n // Check whether a tickets value was given.\r\n if (tickets !== undefined) {\r\n // Check that we have a valid ticket count.\r\n if (!(0, Utilities_1.isNaturalNumber)(tickets)) {\r\n throw new Error(\"tickets value must be a natural number\");\r\n }\r\n existingParticipant.tickets -= tickets;\r\n // If the participant no longer holds any tickets then they should be removed.\r\n if (existingParticipant.tickets < 1) {\r\n this._participants = this._participants.filter(function (part) { return part !== existingParticipant; });\r\n }\r\n }\r\n else {\r\n // We are removing all tickets for the participant so just remove them from the lotto.\r\n this._participants = this._participants.filter(function (part) { return part !== existingParticipant; });\r\n }\r\n return this;\r\n };\r\n /**\r\n * Draw a winning ticket and return the participant that holds the ticket.\r\n * @param options The draw options.\r\n * @returns The participant that holds the winning ticket.\r\n */\r\n Lotto.prototype.draw = function (options) {\r\n if (options === void 0) { options = {}; }\r\n // If we have no participants then just return null.\r\n if (this._participants.length === 0) {\r\n return null;\r\n }\r\n var redrawable = (0, Utilities_1.isNullOrUndefined)(options.redrawable) ? true : options.redrawable;\r\n var pickable = [];\r\n this._participants.forEach(function (_a) {\r\n var participant = _a.participant, tickets = _a.tickets;\r\n for (var ticketCount = 0; ticketCount < tickets; ticketCount++) {\r\n pickable.push(participant);\r\n }\r\n });\r\n var random;\r\n // We need a random floating-point number between 0 (inclusive) and 1 to scale up to pick our winner.\r\n // If a custom random function exists then we should use that or fall back to Math.random().\r\n if (this._customRandom) {\r\n // Call our custom random function to get a random floating-point number.\r\n random = this._customRandom();\r\n // Verify that the result of calling our custom random function is a number between 0 (inclusive) and 1.\r\n if (typeof random !== \"number\" || random < 0 || random >= 1) {\r\n throw new Error(\"the 'random' function provided did not return a number between 0 (inclusive) and 1\");\r\n }\r\n }\r\n else {\r\n // No custom random function was defined so just use good ol' Math.random().\r\n random = Math.random();\r\n }\r\n // Pick a winning participant.\r\n var winner = pickable[Math.floor(random * pickable.length)];\r\n // If the ticket isn't redrawable then we should remove a ticket from the winning participants ticket count.\r\n if (!redrawable) {\r\n this.remove(winner, 1);\r\n }\r\n // Return the winning participant.\r\n return winner;\r\n };\r\n /**\r\n * Draws multiple winning tickets and return an array of the participants that hold the winning tickets.\r\n * @param tickets The number of winning tickets to draw.\r\n * @param options The draw multiple options.\r\n * @returns An array of the participants that hold the winning tickets.\r\n */\r\n Lotto.prototype.drawMultiple = function (tickets, options) {\r\n if (options === void 0) { options = {}; }\r\n var uniqueResults = (0, Utilities_1.isNullOrUndefined)(options.unique) ? false : options.unique;\r\n // Handle cases where the user has asked for zero tickets (no idea why they would do this be we should trust them).\r\n if (tickets === 0) {\r\n return [];\r\n }\r\n // Now that we know out tickets value is not zero we should check that it is a valid natural number.\r\n if (!(0, Utilities_1.isNaturalNumber)(tickets)) {\r\n throw new Error(\"tickets value must be a natural number\");\r\n }\r\n var result = [];\r\n // Keep drawing tickets until we either reach the number of required tickets or we simply run out of tickets to draw.\r\n // We can run out of tickets to draw if 'options.redrawable' is explicity 'false' or we just had no participants when 'drawMultiple' was called.\r\n while (result.length < tickets && this._participants.length > 0) {\r\n result.push(this.draw(options));\r\n }\r\n // If the 'unique' draw option is set then we need to remove duplicates from the result list.\r\n if (uniqueResults) {\r\n // Create an array to store our unique results.\r\n var unique = [];\r\n // Iterate over all of our participants (with potential duplicates) and populate our array of unique values.\r\n for (var _i = 0, result_1 = result; _i < result_1.length; _i++) {\r\n var participant = result_1[_i];\r\n if (unique.indexOf(participant) === -1) {\r\n unique.push(participant);\r\n }\r\n }\r\n result = unique;\r\n }\r\n return result;\r\n };\r\n return Lotto;\r\n}());\r\nexports.Lotto = Lotto;\r\n", "\"use strict\";\r\nObject.defineProperty(exports, \"__esModule\", { value: true });\r\nexports.createLotto = void 0;\r\nvar Lotto_1 = require(\"./Lotto\");\r\n/**\r\n * A function that creates and returns a Lotto instance.\r\n * @param participantsOrOptions An array of initial participants or options relating to the creation of a Lotto instance.\r\n * @returns A new Lotto instance.\r\n */\r\nfunction createLotto(participantsOrOptions) {\r\n // If no initial participants or lotto options were provided as an argument then we can just return a new lotto instance now.\r\n if (!participantsOrOptions) {\r\n return new Lotto_1.Lotto();\r\n }\r\n // Check whether we were provided with an array of initial participants or a lotto options object.\r\n if (Array.isArray(participantsOrOptions)) {\r\n // We are dealing with a pre-defined array of participants.\r\n var participants = participantsOrOptions;\r\n var lotto_1 = new Lotto_1.Lotto();\r\n // If the lotto participants have been defined upfront then we will need to add them all to our lotto instance now.\r\n participants.forEach(function (_a) {\r\n var participant = _a[0], tokens = _a[1];\r\n return lotto_1.add(participant, tokens);\r\n });\r\n // Return the Lotto instance.\r\n return lotto_1;\r\n }\r\n else {\r\n // We are dealing with some lotto options.\r\n var random = participantsOrOptions.random, participants = participantsOrOptions.participants;\r\n // Create a Lotto instance passing the custom RNG function to use in place of Math.random() (which could be undefined).\r\n var lotto_2 = new Lotto_1.Lotto(random);\r\n // If the lotto participants have been defined upfront as part of the options then we will need to add them all to our lotto instance now.\r\n if (participants) {\r\n participants.forEach(function (_a) {\r\n var participant = _a[0], tokens = _a[1];\r\n return lotto_2.add(participant, tokens);\r\n });\r\n }\r\n // Return the Lotto instance.\r\n return lotto_2;\r\n }\r\n}\r\nexports.createLotto = createLotto;\r\n", "\"use strict\";\r\nObject.defineProperty(exports, \"__esModule\", { value: true });\r\nvar createLotto_1 = require(\"./createLotto\");\r\nexports.default = createLotto_1.createLotto;\r\n", "import State from \"./State\";\nimport { validateDefinition } from \"./BehaviourTreeDefinitionValidator\";\nimport { convertMDSLToJSON } from \"./mdsl/MDSLDefinitionParser\";\nimport { BehaviourTree, FlattenedTreeNode } from \"./BehaviourTree\";\nimport { BehaviourTreeOptions } from \"./BehaviourTreeOptions\";\n\nexport { BehaviourTree, State, convertMDSLToJSON, validateDefinition };\nexport type { FlattenedTreeNode, BehaviourTreeOptions };\n", "/**\n * Enumeration of node state types.\n */\nexport enum State {\n READY = \"mistreevous.ready\",\n RUNNING = \"mistreevous.running\",\n SUCCEEDED = \"mistreevous.succeeded\",\n FAILED = \"mistreevous.failed\"\n}\n\nexport { State as default };\n\nexport type CompleteState = State.SUCCEEDED | State.FAILED;\nexport type AnyState = State.READY | State.RUNNING | CompleteState;\n", "import {\n NodeDefinition,\n RootNodeDefinition,\n DecoratorNodeDefinition,\n CompositeNodeDefinition,\n AnyNodeDefinition,\n BranchNodeDefinition\n} from \"./BehaviourTreeDefinition\";\n\n/**\n * A type guard function that returns true if the specified node satisfies the RootNodeDefinition type.\n * @param node The node.\n * @returns A value of true if the specified node satisfies the RootNodeDefinition type.\n */\nexport function isRootNode(node: NodeDefinition): node is RootNodeDefinition {\n return node.type === \"root\";\n}\n\n/**\n * A type guard function that returns true if the specified node satisfies the BranchNodeDefinition type.\n * @param node The node.\n * @returns A value of true if the specified node satisfies the BranchNodeDefinition type.\n */\nexport function isBranchNode(node: NodeDefinition): node is BranchNodeDefinition {\n return node.type === \"branch\";\n}\n\n/**\n * A type guard function that returns true if the specified node satisfies the NodeDefinition type.\n * @param node The node.\n * @returns A value of true if the specified node satisfies the NodeDefinition type.\n */\nexport function isLeafNode(node: NodeDefinition): node is NodeDefinition {\n return [\"branch\", \"action\", \"condition\", \"wait\"].includes(node.type);\n}\n\n/**\n * A type guard function that returns true if the specified node satisfies the DecoratorNodeDefinition type.\n * @param node The node.\n * @returns A value of true if the specified node satisfies the DecoratorNodeDefinition type.\n */\nexport function isDecoratorNode(node: NodeDefinition): node is DecoratorNodeDefinition {\n return [\"root\", \"repeat\", \"retry\", \"flip\", \"succeed\", \"fail\"].includes(node.type);\n}\n\n/**\n * A type guard function that returns true if the specified node satisfies the CompositeNodeDefinition type.\n * @param node The node.\n * @returns A value of true if the specified node satisfies the CompositeNodeDefinition type.\n */\nexport function isCompositeNode(node: NodeDefinition): node is CompositeNodeDefinition {\n return [\"sequence\", \"selector\", \"lotto\", \"parallel\"].includes(node.type);\n}\n\n/**\n * Flatten a node definition into an array of all of its nested node definitions.\n * @param nodeDefinition The node definition to flatten.\n * @returns An array of all of nested node definitions.\n */\nexport function flattenDefinition(nodeDefinition: AnyNodeDefinition): AnyNodeDefinition[] {\n const nodes: AnyNodeDefinition[] = [];\n\n const processNode = (currentNodeDefinition: AnyNodeDefinition) => {\n nodes.push(currentNodeDefinition);\n\n if (isCompositeNode(currentNodeDefinition)) {\n currentNodeDefinition.children.forEach(processNode);\n } else if (isDecoratorNode(currentNodeDefinition)) {\n processNode(currentNodeDefinition.child);\n }\n };\n\n processNode(nodeDefinition);\n\n return nodes;\n}\n\n/**\n * Determines whether the passed value is an integer.\n * @param value The value to check.\n * @returns Whether the passed value is an integer.\n */\nexport function isInteger(value: unknown): boolean {\n return typeof value === \"number\" && Math.floor(value) === value;\n}\n\n/**\n * Determines whether the passed value is null or undefined.\n * @param value The value to check.\n * @returns Whether the passed value is null or undefined.\n */\nexport function isNullOrUndefined(value: unknown): boolean {\n return typeof value === \"undefined\" || value === null;\n}\n", "/**\n * A type defining an object that holds a reference to substitued string literals parsed from the definition.\n */\nexport type StringLiteralPlaceholders = { [key: string]: string };\n\n/**\n * Pop the next raw token from the specified array of tokens and throw an error if it wasn't the expected one.\n * @param tokens The array of tokens.\n * @param expected An optional string or array or items, one of which must match the next popped token.\n * @returns The popped token.\n */\nexport function popAndCheck(tokens: string[], expected?: string | string[]): string {\n // Get and remove the next token.\n const popped = tokens.shift();\n\n // We were expecting another token but there aren't any.\n if (popped === undefined) {\n throw new Error(\"unexpected end of definition\");\n }\n\n // Do we have an expected token/tokens array?\n if (expected != undefined) {\n // Get an array of expected values, if the popped token matches any then we are all good.\n const expectedValues = typeof expected === \"string\" ? [expected] : expected;\n\n // Check whether the popped token matches at least one of our expected items.\n var tokenMatchesExpectation = expectedValues.some((item) => popped.toUpperCase() === item.toUpperCase());\n\n // Throw an error if the popped token didn't match any of our expected items.\n if (!tokenMatchesExpectation) {\n const expectationString = expectedValues.map((item) => \"'\" + item + \"'\").join(\" or \");\n throw new Error(\"unexpected token found. Expected \" + expectationString + \" but got '\" + popped + \"'\");\n }\n }\n\n // Return the popped token.\n return popped;\n}\n\n/**\n * Swaps out any node/attribute argument string literals with placeholders.\n * @param definition The definition.\n * @returns An object containing a mapping of placeholders to original string values as well as the processed definition string.\n */\nexport function substituteStringLiterals(definition: string): {\n placeholders: StringLiteralPlaceholders;\n processedDefinition: string;\n} {\n // Create an object to hold the mapping of placeholders to original string values.\n const placeholders: StringLiteralPlaceholders = {};\n\n // Replace any string literals wrapped with double quotes in our definition with placeholders to be processed later.\n const processedDefinition = definition.replace(/\\\"(\\\\.|[^\"\\\\])*\\\"/g, (match) => {\n var strippedMatch = match.substring(1, match.length - 1);\n var placeholder = Object.keys(placeholders).find((key) => placeholders[key] === strippedMatch);\n\n // If we have no existing string literal match then create a new placeholder.\n if (!placeholder) {\n placeholder = `@@${Object.keys(placeholders).length}@@`;\n placeholders[placeholder] = strippedMatch;\n }\n\n return placeholder;\n });\n\n return { placeholders, processedDefinition };\n}\n\n/**\n * Parse the tree definition into an array of raw tokens.\n * @param definition The definition.\n * @returns An array of tokens parsed from the definition.\n */\nexport function parseTokensFromDefinition(definition: string): string[] {\n // Add some space around various important characters so that they can be plucked out easier as individual tokens.\n definition = definition.replace(/\\(/g, \" ( \");\n definition = definition.replace(/\\)/g, \" ) \");\n definition = definition.replace(/\\{/g, \" { \");\n definition = definition.replace(/\\}/g, \" } \");\n definition = definition.replace(/\\]/g, \" ] \");\n definition = definition.replace(/\\[/g, \" [ \");\n definition = definition.replace(/\\,/g, \" , \");\n\n // Split the definition into raw token form and return it.\n return definition.replace(/\\s+/g, \" \").trim().split(\" \");\n}\n", "import { StringLiteralPlaceholders, popAndCheck } from \"./MDSLUtilities\";\n\n/**\n * A type representing any node function argument.\n */\ntype Argument = {\n /**\n * The argument value.\n */\n value: T;\n /**\n * The argument type, used for validation.\n */\n type: string;\n};\n\ntype NullArgument = Argument & {\n type: \"null\";\n};\n\ntype BooleanArgument = Argument & {\n type: \"boolean\";\n};\n\ntype NumberArgument = Argument & {\n type: \"number\";\n /**\n * A flag defining whether the number argument value is a valid integer. (used for validation)\n */\n isInteger: boolean;\n};\n\ntype StringPlaceholderArgument = Argument & {\n type: \"string\";\n};\n\ntype IdentifierArgument = Argument & {\n type: \"identifier\";\n};\n\n/**\n * A type representing a reference to any node function argument.\n */\ntype AnyArgument = NullArgument | BooleanArgument | NumberArgument | StringPlaceholderArgument | IdentifierArgument;\n\n/**\n * Parse an array of argument definitions from the specified tokens array.\n * @param tokens The array tokens to parse the argument definitions from.\n * @param stringArgumentPlaceholders The mapping of string literal node argument placeholders to original values.\n * @param argumentValidator The argument validator function.\n * @param validationFailedMessage The exception message to throw if argument validation fails.\n * @returns An array of argument definitions parsed from the specified tokens array.\n */\nexport function parseArgumentTokens(\n tokens: string[],\n stringArgumentPlaceholders: StringLiteralPlaceholders\n): AnyArgument[] {\n const argumentList: AnyArgument[] = [];\n\n // If the next token is not a '[' or '(' then we have no arguments to parse.\n if (![\"[\", \"(\"].includes(tokens[0])) {\n return argumentList;\n }\n\n // Any lists of arguments will always be wrapped in '[]' for node arguments or '()' for attribute arguments.\n // We are looking for a '[' or '(' opener that wraps the argument tokens and the relevant closer.\n const closingToken = popAndCheck(tokens, [\"[\", \"(\"]) === \"[\" ? \"]\" : \")\";\n\n const argumentListTokens: string[] = [];\n\n // Grab all tokens between the '[' and ']' or '(' and ')'.\n while (tokens.length && tokens[0] !== closingToken) {\n // The next token is part of our arguments list.\n argumentListTokens.push(tokens.shift()!);\n }\n\n // Validate the order of the argument tokens. Each token must either be a ',' or a single argument that satisfies the validator.\n argumentListTokens.forEach((token, index) => {\n // Get whether this token should be an actual argument.\n const shouldBeArgumentToken = !(index & 1);\n\n // If the current token should be an actual argument then validate it, otherwise it should be a ',' token.\n if (shouldBeArgumentToken) {\n // Get the argument definition.\n const argumentDefinition = getArgumentDefinition(token, stringArgumentPlaceholders);\n\n // This is a valid argument!\n argumentList.push(argumentDefinition);\n } else {\n // The current token should be a ',' token.\n if (token !== \",\") {\n throw new Error(`invalid argument list, expected ',' or ']' but got '${token}'`);\n }\n }\n });\n\n // The arguments list should terminate with a ']' or ')' token, depending on the opener.\n popAndCheck(tokens, closingToken);\n\n // Return the arguments.\n return argumentList;\n}\n\n/**\n * Gets an argument value definition.\n * @param token The argument token.\n * @param stringArgumentPlaceholders The mapping of string literal node argument placeholders to original values.\n * @returns An argument value definition.\n */\nfunction getArgumentDefinition(token: string, stringArgumentPlaceholders: StringLiteralPlaceholders): AnyArgument {\n // Check whether the token represents a null value.\n if (token === \"null\") {\n return {\n value: null,\n type: \"null\"\n } as NullArgument;\n }\n\n // Check whether the token represents a boolean value.\n if (token === \"true\" || token === \"false\") {\n return {\n value: token === \"true\",\n type: \"boolean\"\n } as BooleanArgument;\n }\n\n // Check whether the token represents a number value.\n // TODO: Relies on broken isNaN - see MDN.\n // if (!Number.isNaN(token)) {\n if (!isNaN(token as any)) {\n return {\n value: parseFloat(token),\n isInteger: parseFloat(token) === parseInt(token, 10),\n type: \"number\"\n } as NumberArgument;\n }\n\n // Check whether the token is a placeholder (e.g. @@0@@) representing a string literal.\n if (token.match(/^@@\\d+@@$/g)) {\n return {\n value: stringArgumentPlaceholders[token].replace('\\\\\"', '\"'),\n type: \"string\"\n } as StringPlaceholderArgument;\n }\n\n // The only remaining option is that the argument value is an identifier.\n return {\n value: token,\n type: \"identifier\"\n } as IdentifierArgument;\n}\n", "import { NodeAttributeDefinition } from \"../BehaviourTreeDefinition\";\nimport { parseArgumentTokens } from \"./MDSLNodeArgumentParser\";\nimport { StringLiteralPlaceholders } from \"./MDSLUtilities\";\n\n/**\n * A type defining the attribute definitions of a node.\n */\ntype NodeAttributes = {\n while?: NodeAttributeDefinition;\n until?: NodeAttributeDefinition;\n entry?: NodeAttributeDefinition;\n exit?: NodeAttributeDefinition;\n step?: NodeAttributeDefinition;\n};\n\n/**\n * Parse any node attribute definitions from the specified tokens array.\n * @param tokens The array of remaining tokens.\n * @param stringArgumentPlaceholders The mapping of string literal node argument placeholders to original values.\n * @returns An object of attribute definitions defined by any directly following tokens.\n */\nexport function parseAttributeTokens(\n tokens: string[],\n stringArgumentPlaceholders: StringLiteralPlaceholders\n): NodeAttributes {\n const nodeAttributeNames: (keyof NodeAttributes)[] = [\"while\", \"until\", \"entry\", \"exit\", \"step\"];\n\n // Create an object to hold any attributes found.\n const attributes: NodeAttributes = {};\n\n // Try to get the name of the attribute for the next token.\n let nextAttributeName = tokens[0]?.toLowerCase() as keyof NodeAttributes;\n\n // Pull attribute tokens as well as their arguments off of the tokens stack until we have no more.\n while (nodeAttributeNames.includes(nextAttributeName)) {\n // Check to make sure that we have not already created an attribute definition of this type.\n if (attributes[nextAttributeName]) {\n throw new Error(`duplicate attribute '${tokens[0].toUpperCase()}' found for node`);\n }\n\n // Remove the attribute name token from the array of tokens.\n tokens.shift();\n\n // Grab the attribute arguments, assuming the first to be an identifier.\n const [attributeCallIdentifier, ...attributeArguments] = parseArgumentTokens(\n tokens,\n stringArgumentPlaceholders\n );\n\n // The first attribute argument has to be an identifer, this will reference an agent function.\n if (attributeCallIdentifier?.type !== \"identifier\") {\n throw new Error(\"expected agent function name identifier argument for attribute\");\n }\n\n // Any attribute arguments (other than the expected call identifier) must have a type of string, number, boolean or null.\n attributeArguments\n .filter((arg) => arg.type === \"identifier\")\n .forEach((arg) => {\n throw new Error(\n `invalid attribute argument value '${arg.value}', must be string, number, boolean or null`\n );\n });\n\n // Create the attribute definition and add it to the object of attribute definitions found.\n attributes[nextAttributeName] = {\n call: attributeCallIdentifier.value,\n args: attributeArguments.map(({ value }) => value)\n };\n\n // Try to get the next attribute name token, as there could be multiple.\n nextAttributeName = tokens[0]?.toLowerCase() as keyof NodeAttributes;\n }\n\n return attributes;\n}\n", "import {\n ActionNodeDefinition,\n AnyChildNodeDefinition,\n AnyNodeDefinition,\n BranchNodeDefinition,\n ConditionNodeDefinition,\n FailNodeDefinition,\n FlipNodeDefinition,\n LottoNodeDefinition,\n ParallelNodeDefinition,\n RepeatNodeDefinition,\n RetryNodeDefinition,\n RootNodeDefinition,\n SelectorNodeDefinition,\n SequenceNodeDefinition,\n SucceedNodeDefinition,\n WaitNodeDefinition\n} from \"../BehaviourTreeDefinition\";\nimport {\n isCompositeNode,\n isDecoratorNode,\n isLeafNode,\n isNullOrUndefined,\n isRootNode\n} from \"../BehaviourTreeDefinitionUtilities\";\nimport { parseArgumentTokens } from \"./MDSLNodeArgumentParser\";\nimport { parseAttributeTokens } from \"./MDSLNodeAttributeParser\";\nimport {\n StringLiteralPlaceholders,\n parseTokensFromDefinition,\n popAndCheck,\n substituteStringLiterals\n} from \"./MDSLUtilities\";\n\n/**\n * Convert the MDSL tree definition string into an equivalent JSON definition.\n * @param definition The tree definition string as MDSL.\n * @returns The root node JSON definitions.\n */\nexport function convertMDSLToJSON(definition: string): RootNodeDefinition[] {\n // Swap out any node/attribute argument string literals with a placeholder and get a mapping of placeholders to original values as well as the processed definition.\n const { placeholders, processedDefinition } = substituteStringLiterals(definition);\n\n // Parse our definition definition string into an array of raw tokens.\n const tokens = parseTokensFromDefinition(processedDefinition);\n\n return convertTokensToJSONDefinition(tokens, placeholders);\n}\n\n/**\n * Converts the specified tree definition tokens into a JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The root node JSON definitions.\n */\nfunction convertTokensToJSONDefinition(\n tokens: string[],\n stringLiteralPlaceholders: StringLiteralPlaceholders\n): RootNodeDefinition[] {\n // There must be at least 3 tokens for the tree definition to be valid. 'ROOT', '{' and '}'.\n if (tokens.length < 3) {\n throw new Error(\"invalid token count\");\n }\n\n // We should have a matching number of '{' and '}' tokens. If not, then there are scopes that have not been properly closed.\n if (tokens.filter((token) => token === \"{\").length !== tokens.filter((token) => token === \"}\").length) {\n throw new Error(\"scope character mismatch\");\n }\n\n // Create an array of tree stack arrays where root nodes will always be at the botton and the current composite/decorator node at the top.\n // There should be an element in this array for every root node defined and every element should be an array with a root note as the first element.\n // E.g. A definition with two root nodes defined:\n // [\n // [root, lotto, sequence],\n // [root, selector]\n // ]\n const treeStacks: [Partial, ...Partial[]][] = [];\n\n // Create an array of all root node definitions that we create.\n const rootNodes: Partial[] = [];\n\n // A helper function used to push node definitions onto the tree stack.\n const pushNode = (node: AnyNodeDefinition) => {\n // If the node is a root node then we need to create a new tree stack array with the root node at the root.\n if (isRootNode(node)) {\n // We need to double-check that this root node is not the child of another node.\n // We can do this by checking whether the top tree stack is not empty (contains an existing node)\n if (treeStacks[treeStacks.length - 1]?.length) {\n throw new Error(\"a root node cannot be the child of another node\");\n }\n\n // Add the root node definition to our array of all parsed root node definitions.\n rootNodes.push(node);\n\n // Add the root node definition to the root of a new tree stack.\n treeStacks.push([node]);\n\n return;\n }\n\n // All non-root nodes should be pushed after their root nodes so handle cases\n // where we may not have any tree stacks or our top-most tree stack is empty.\n if (!treeStacks.length || !treeStacks[treeStacks.length - 1].length) {\n throw new Error(\"expected root node at base of definition\");\n }\n\n // Get the current tree stack that we are populating.\n const topTreeStack = treeStacks[treeStacks.length - 1];\n\n // Get the top-most node in the current tree stack, this will be a composite/decorator node\n // for which we will populate its children array if composite or setting its child if a decorator.\n const topTreeStackTopNode = topTreeStack[topTreeStack.length - 1] as AnyNodeDefinition;\n\n // If the top-most node in the current root stack is a composite or decorator\n // node then the current node should be added as a child of the top-most node.\n if (isCompositeNode(topTreeStackTopNode)) {\n topTreeStackTopNode.children = topTreeStackTopNode.children || [];\n topTreeStackTopNode.children.push(node);\n } else if (isDecoratorNode(topTreeStackTopNode)) {\n // If the top node already has a child node set then throw an error as a decorator should only have a single child.\n if (topTreeStackTopNode.child) {\n throw new Error(\"a decorator node must only have a single child node\");\n }\n\n topTreeStackTopNode.child = node;\n }\n\n // If the node we are adding is also a composite or decorator node, then we should push it\n // onto the current tree stack, as subsequent nodes will be added as its child/children.\n if (!isLeafNode(node)) {\n topTreeStack.push(node);\n }\n };\n\n // A helper function used to pop the top-most node definition off of the tree stack and return it.\n const popNode = (): AnyNodeDefinition | null => {\n let poppedNode: AnyNodeDefinition | null = null;\n\n // Get the current tree stack that we are populating.\n const topTreeStack = treeStacks[treeStacks.length - 1];\n\n // Pop the top-most node in the current tree stack if there is one.\n if (topTreeStack.length) {\n poppedNode = topTreeStack.pop() as AnyNodeDefinition;\n }\n\n // We don't want any empty tree stacks in our stack of tree stacks.\n if (!topTreeStack.length) {\n treeStacks.pop();\n }\n\n return poppedNode;\n };\n\n // We should keep processing the raw tokens until we run out of them.\n while (tokens.length) {\n // Grab the next token.\n const token = tokens.shift()!;\n\n // How we create the next node depends on the current raw token value.\n switch (token.toUpperCase()) {\n case \"ROOT\": {\n pushNode(createRootNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"SUCCEED\": {\n pushNode(createSucceedNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"FAIL\": {\n pushNode(createFailNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"FLIP\": {\n pushNode(createFlipNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"REPEAT\": {\n pushNode(createRepeatNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"RETRY\": {\n pushNode(createRetryNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"SEQUENCE\": {\n pushNode(createSequenceNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"SELECTOR\": {\n pushNode(createSelectorNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"PARALLEL\": {\n pushNode(createParallelNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"LOTTO\": {\n pushNode(createLottoNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"ACTION\": {\n pushNode(createActionNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"CONDITION\": {\n pushNode(createConditionNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"WAIT\": {\n pushNode(createWaitNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"BRANCH\": {\n pushNode(createBranchNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"}\": {\n // The '}' character closes the current scope and means that we have to pop a node off of the current stack.\n const poppedNode = popNode();\n\n // Now that we have a node definition we can carry out any validation that may require the node to be fully populated.\n if (poppedNode) {\n validatePoppedNode(poppedNode);\n }\n\n break;\n }\n\n default: {\n throw new Error(`unexpected token: ${token}`);\n }\n }\n }\n\n return rootNodes as RootNodeDefinition[];\n}\n\n/**\n * Creates a root node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The root node JSON definition.\n */\nfunction createRootNode(tokens: string[], stringLiteralPlaceholders: StringLiteralPlaceholders): RootNodeDefinition {\n // Create the root node definition.\n let node = {\n type: \"root\",\n id: undefined\n } as RootNodeDefinition;\n\n // Parse any node arguments, we should only have one if any which will be an identifier argument for the root identifier.\n const nodeArguments = parseArgumentTokens(tokens, stringLiteralPlaceholders);\n\n // Check whether any node arguments were defined.\n if (nodeArguments.length) {\n // We should only have one argument, if any, which will be an identifier argument for the root identifier.\n if (nodeArguments.length === 1 && nodeArguments[0].type === \"identifier\") {\n // The root node identifier will be the first and only node argument value.\n node.id = nodeArguments[0].value as string;\n } else {\n throw new Error(\"expected single root name argument\");\n }\n }\n\n // Grab any node attribute definitions and spread them into the node definition.\n node = { ...node, ...parseAttributeTokens(tokens, stringLiteralPlaceholders) };\n\n // This is a decorator node, so we expect an opening '{'.\n popAndCheck(tokens, \"{\");\n\n // Return the root node definition.\n return node;\n}\n\n/**\n * Creates a succeed node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The succeed node JSON definition.\n */\nfunction createSucceedNode(\n tokens: string[],\n stringLiteralPlaceholders: StringLiteralPlaceholders\n): SucceedNodeDefinition {\n const node = {\n type: \"succeed\",\n ...parseAttributeTokens(tokens, stringLiteralPlaceholders)\n } as SucceedNodeDefinition;\n\n // This is a decorator node, so we expect an opening '{'.\n popAndCheck(tokens, \"{\");\n\n // Return the succeed node definition.\n return node;\n}\n\n/**\n * Creates a fail node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The fail node JSON definition.\n */\nfunction createFailNode(tokens: string[], stringLiteralPlaceholders: StringLiteralPlaceholders): FailNodeDefinition {\n const node = {\n type: \"fail\",\n ...parseAttributeTokens(tokens, stringLiteralPlaceholders)\n } as FailNodeDefinition;\n\n // This is a decorator node, so we expect an opening '{'.\n popAndCheck(tokens, \"{\");\n\n // Return the fail node definition.\n return node;\n}\n\n/**\n * Creates a flip node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The flip node JSON definition.\n */\nfunction createFlipNode(tokens: string[], stringLiteralPlaceholders: StringLiteralPlaceholders): FlipNodeDefinition {\n const node = {\n type: \"flip\",\n ...parseAttributeTokens(tokens, stringLiteralPlaceholders)\n } as FlipNodeDefinition;\n\n // This is a decorator node, so we expect an opening '{'.\n popAndCheck(tokens, \"{\");\n\n // Return the flip node definition.\n return node;\n}\n\n/**\n * Creates a repeat node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The repeat node JSON definition.\n */\nfunction createRepeatNode(\n tokens: string[],\n stringLiteralPlaceholders: StringLiteralPlaceholders\n): RepeatNodeDefinition {\n let node = { type: \"repeat\" } as RepeatNodeDefinition;\n\n // Get the node arguments.\n const nodeArguments = parseArgumentTokens(tokens, stringLiteralPlaceholders);\n\n // The arguments of a repeat node are optional. We may have:\n // - No node arguments, in which case the repeat note will iterate indefinitely.\n // - One node argument which will be the explicit number of iterations to make.\n // - Two node arguments which define the min and max iteration bounds from which a random iteration count will be picked.\n if (nodeArguments.length) {\n // All repeat node arguments MUST be of type number and must be integer.\n nodeArguments\n .filter((arg) => arg.type !== \"number\" || !arg.isInteger)\n .forEach(() => {\n throw new Error(`repeat node iteration counts must be integer values`);\n });\n\n // We should have got one or two iteration counts.\n if (nodeArguments.length === 1) {\n // A static iteration count was defined.\n node.iterations = nodeArguments[0].value as number;\n\n // A repeat node must have a positive number of iterations if defined.\n if (node.iterations < 0) {\n throw new Error(\"a repeat node must have a positive number of iterations if defined\");\n }\n } else if (nodeArguments.length === 2) {\n // A minimum and maximum iteration count was defined.\n node.iterations = [nodeArguments[0].value as number, nodeArguments[1].value as number];\n\n // A repeat node must have a positive min and max iteration count if they are defined.\n if (node.iterations[0] < 0 || node.iterations[1] < 0) {\n throw new Error(\"a repeat node must have a positive minimum and maximum iteration count if defined\");\n }\n\n // A repeat node must not have an minimum iteration count that exceeds the maximum iteration count.\n if (node.iterations[0] > node.iterations[1]) {\n throw new Error(\n \"a repeat node must not have a minimum iteration count that exceeds the maximum iteration count\"\n );\n }\n } else {\n // An incorrect number of iteration counts was defined.\n throw new Error(\"invalid number of repeat node iteration count arguments defined\");\n }\n }\n\n // Grab any node attribute definitions and spread them into the node definition.\n node = { ...node, ...parseAttributeTokens(tokens, stringLiteralPlaceholders) };\n\n // This is a decorator node, so we expect an opening '{'.\n popAndCheck(tokens, \"{\");\n\n // Return the repeat node definition.\n return node;\n}\n\n/**\n * Creates a retry node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The retry node JSON definition.\n */\nfunction createRetryNode(tokens: string[], stringLiteralPlaceholders: StringLiteralPlaceholders): RetryNodeDefinition {\n let node = { type: \"retry\" } as RetryNodeDefinition;\n\n // Get the node arguments.\n const nodeArguments = parseArgumentTokens(tokens, stringLiteralPlaceholders);\n\n // The arguments of a retry node are optional. We may have:\n // - No node arguments, in which case the retry note will attempt indefinitely.\n // - One node argument which will be the explicit number of attempts to make.\n // - Two node arguments which define the min and max attempt bounds from which a random attempt count will be picked.\n if (nodeArguments.length) {\n // All retry node arguments MUST be of type number and must be integer.\n nodeArguments\n .filter((arg) => arg.type !== \"number\" || !arg.isInteger)\n .forEach(() => {\n throw new Error(`retry node attempt counts must be integer values`);\n });\n\n // We should have got one or two attempt counts.\n if (nodeArguments.length === 1) {\n // A static attempt count was defined.\n node.attempts = nodeArguments[0].value as number;\n\n // A retry node must have a positive number of attempts if defined.\n if (node.attempts < 0) {\n throw new Error(\"a retry node must have a positive number of attempts if defined\");\n }\n } else if (nodeArguments.length === 2) {\n // A minimum and maximum attempt count was defined.\n node.attempts = [nodeArguments[0].value as number, nodeArguments[1].value as number];\n\n // A retry node must have a positive min and max attempts count if they are defined.\n if (node.attempts[0] < 0 || node.attempts[1] < 0) {\n throw new Error(\"a retry node must have a positive minimum and maximum attempt count if defined\");\n }\n\n // A retry node must not have a minimum attempt count that exceeds the maximum attempt count.\n if (node.attempts[0] > node.attempts[1]) {\n throw new Error(\n \"a retry node must not have a minimum attempt count that exceeds the maximum attempt count\"\n );\n }\n } else {\n // An incorrect number of attempt counts was defined.\n throw new Error(\"invalid number of retry node attempt count arguments defined\");\n }\n }\n\n // Grab any node attribute definitions and spread them into the node definition.\n node = { ...node, ...parseAttributeTokens(tokens, stringLiteralPlaceholders) };\n\n // This is a decorator node, so we expect an opening '{'.\n popAndCheck(tokens, \"{\");\n\n // Return the retry node definition.\n return node;\n}\n\n/**\n * Creates a sequence node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The sequence node JSON definition.\n */\nfunction createSequenceNode(\n tokens: string[],\n stringLiteralPlaceholders: StringLiteralPlaceholders\n): SequenceNodeDefinition {\n const node = {\n type: \"sequence\",\n ...parseAttributeTokens(tokens, stringLiteralPlaceholders)\n } as SequenceNodeDefinition;\n\n // This is a composite node, so we expect an opening '{'.\n popAndCheck(tokens, \"{\");\n\n // Return the sequence node definition.\n return node;\n}\n\n/**\n * Creates a selector node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The selector node JSON definition.\n */\nfunction createSelectorNode(\n tokens: string[],\n stringLiteralPlaceholders: StringLiteralPlaceholders\n): SelectorNodeDefinition {\n const node = {\n type: \"selector\",\n ...parseAttributeTokens(tokens, stringLiteralPlaceholders)\n } as SelectorNodeDefinition;\n\n // This is a composite node, so we expect an opening '{'.\n popAndCheck(tokens, \"{\");\n\n // Return the selector node definition.\n return node;\n}\n\n/**\n * Creates a parallel node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The parallel node JSON definition.\n */\nfunction createParallelNode(\n tokens: string[],\n stringLiteralPlaceholders: StringLiteralPlaceholders\n): ParallelNodeDefinition {\n const node = {\n type: \"parallel\",\n ...parseAttributeTokens(tokens, stringLiteralPlaceholders)\n } as ParallelNodeDefinition;\n\n // This is a composite node, so we expect an opening '{'.\n popAndCheck(tokens, \"{\");\n\n // Return the parallel node definition.\n return node;\n}\n\n/**\n * Creates a lotto node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The lotto node JSON definition.\n */\nfunction createLottoNode(tokens: string[], stringLiteralPlaceholders: StringLiteralPlaceholders): LottoNodeDefinition {\n // If any node arguments have been defined then they must be our weights.\n const nodeArguments = parseArgumentTokens(tokens, stringLiteralPlaceholders);\n\n // All lotto node arguments MUST be of type number and must be positive integers.\n nodeArguments\n .filter((arg) => arg.type !== \"number\" || !arg.isInteger || arg.value < 0)\n .forEach(() => {\n throw new Error(`lotto node weight arguments must be positive integer values`);\n });\n\n const node = {\n type: \"lotto\",\n weights: nodeArguments.length ? nodeArguments.map(({ value }) => value) : undefined,\n ...parseAttributeTokens(tokens, stringLiteralPlaceholders)\n } as LottoNodeDefinition;\n\n // This is a composite node, so we expect an opening '{'.\n popAndCheck(tokens, \"{\");\n\n // Return the lotto node definition.\n return node;\n}\n\n/**\n * Creates an action node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The action node JSON definition.\n */\nfunction createActionNode(\n tokens: string[],\n stringLiteralPlaceholders: StringLiteralPlaceholders\n): ActionNodeDefinition {\n // Parse any node arguments, we should have at least one which will be an identifier argument for the action name\n // and agent function to invoke for the action, all other arguments are to be passed as arguments to that function.\n const [actionNameIdentifier, ...agentFunctionArgs] = parseArgumentTokens(tokens, stringLiteralPlaceholders);\n\n // Our first argument MUST be defined and be an identifier as we require an action name argument.\n if (actionNameIdentifier?.type !== \"identifier\") {\n throw new Error(\"expected action name identifier argument\");\n }\n\n // Only the first argument should have been an identifier, all agent function arguments must be string, number, boolean or null.\n agentFunctionArgs\n .filter((arg) => arg.type === \"identifier\")\n .forEach((arg) => {\n throw new Error(\n `invalid action node argument value '${arg.value}', must be string, number, boolean or null`\n );\n });\n\n // Return the action node definition.\n return {\n type: \"action\",\n call: actionNameIdentifier.value,\n args: agentFunctionArgs.map(({ value }) => value),\n ...parseAttributeTokens(tokens, stringLiteralPlaceholders)\n };\n}\n\n/**\n * Creates a condition node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The condition node JSON definition.\n */\nfunction createConditionNode(\n tokens: string[],\n stringLiteralPlaceholders: StringLiteralPlaceholders\n): ConditionNodeDefinition {\n // Parse any node arguments, we should have at least one which will be an identifier argument for the condition name\n // and agent function to invoke for the condition, all other arguments are to be passed as arguments to that function.\n const [conditionNameIdentifier, ...agentFunctionArgs] = parseArgumentTokens(tokens, stringLiteralPlaceholders);\n\n // Our first argument MUST be defined and be an identifier as we require a condition name argument.\n if (conditionNameIdentifier?.type !== \"identifier\") {\n throw new Error(\"expected condition name identifier argument\");\n }\n\n // Only the first argument should have been an identifier, all agent function arguments must be string, number, boolean or null.\n agentFunctionArgs\n .filter((arg) => arg.type === \"identifier\")\n .forEach((arg) => {\n throw new Error(\n `invalid condition node argument value '${arg.value}', must be string, number, boolean or null`\n );\n });\n\n // Return the condition node definition.\n return {\n type: \"condition\",\n call: conditionNameIdentifier.value,\n args: agentFunctionArgs.map(({ value }) => value),\n ...parseAttributeTokens(tokens, stringLiteralPlaceholders)\n };\n}\n\n/**\n * Creates a wait node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The wait node JSON definition.\n */\nfunction createWaitNode(tokens: string[], stringLiteralPlaceholders: StringLiteralPlaceholders): WaitNodeDefinition {\n let node = { type: \"wait\" } as WaitNodeDefinition;\n\n // Get the node arguments.\n const nodeArguments = parseArgumentTokens(tokens, stringLiteralPlaceholders);\n\n // The arguments of a wait node are optional. We may have:\n // - No node arguments, in which case the wait will be indefinite until it is aborted.\n // - One node argument which will be the explicit duration of the wait.\n // - Two node arguments which define the min and max duration bounds from which a random duration will be picked.\n if (nodeArguments.length) {\n // All wait node arguments MUST be of type number and must be integer.\n nodeArguments\n .filter((arg) => arg.type !== \"number\" || !arg.isInteger)\n .forEach(() => {\n throw new Error(`wait node durations must be integer values`);\n });\n\n // We may have:\n // - One node argument which will be the explicit duration of the wait.\n // - Two node arguments which define the min and max duration bounds from which a random duration will be picked.\n // - Too many arguments, which is not valid.\n if (nodeArguments.length === 1) {\n // An explicit duration was defined.\n node.duration = nodeArguments[0].value as number;\n\n // If an explict duration was defined then it must be a positive number.\n if (node.duration < 0) {\n throw new Error(\"a wait node must have a positive duration\");\n }\n } else if (nodeArguments.length === 2) {\n // Min and max duration bounds were defined from which a random duration will be picked.\n node.duration = [nodeArguments[0].value as number, nodeArguments[1].value as number];\n\n // A wait node must have a positive min and max duration.\n if (node.duration[0] < 0 || node.duration[1] < 0) {\n throw new Error(\"a wait node must have a positive minimum and maximum duration\");\n }\n\n // A wait node must not have a minimum duration that exceeds the maximum duration.\n if (node.duration[0] > node.duration[1]) {\n throw new Error(\"a wait node must not have a minimum duration that exceeds the maximum duration\");\n }\n } else if (nodeArguments.length > 2) {\n // An incorrect number of duration arguments were defined.\n throw new Error(\"invalid number of wait node duration arguments defined\");\n }\n }\n\n // Return the wait node definition.\n return { ...node, ...parseAttributeTokens(tokens, stringLiteralPlaceholders) };\n}\n\n/**\n * Creates a branch node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The branch node JSON definition.\n */\nfunction createBranchNode(\n tokens: string[],\n stringLiteralPlaceholders: StringLiteralPlaceholders\n): BranchNodeDefinition {\n // Parse any node arguments, we should have one which will be an identifier argument for the root ref.\n const nodeArguments = parseArgumentTokens(tokens, stringLiteralPlaceholders);\n\n // We should have only a single identifer argument for a branch node, which is the root ref.\n if (nodeArguments.length !== 1 || nodeArguments[0].type !== \"identifier\") {\n throw new Error(\"expected single branch name argument\");\n }\n\n // Return the branch node definition.\n return { type: \"branch\", ref: nodeArguments[0].value };\n}\n\n/**\n * Validate a fully-populated node definition that was popped off of the tree stack.\n * @param definition The popped node to validate.\n */\nfunction validatePoppedNode(definition: AnyNodeDefinition): void {\n // Decorators MUST have a child defined.\n if (isDecoratorNode(definition) && isNullOrUndefined(definition.child)) {\n throw new Error(`a ${definition.type} node must have a single child node defined`);\n }\n\n // Composites MUST have at least one child defined.\n if (isCompositeNode(definition) && !definition.children?.length) {\n throw new Error(`a ${definition.type} node must have at least a single child node defined`);\n }\n\n // We need to make sure that lotto nodes that have weights defined have a number of weights matching the number of child nodes.\n if (definition.type === \"lotto\") {\n // Check whether a 'weights' property has been defined, if it has we expect it to be an array of weights.\n if (typeof definition.weights !== \"undefined\") {\n // Check that the weights property is an array of positive integers with an element for each child node element.\n if (definition.weights.length !== definition.children.length) {\n throw new Error(\n \"expected a number of weight arguments matching the number of child nodes for lotto node\"\n );\n }\n }\n }\n}\n", "import { RootNodeDefinition } from \"./BehaviourTreeDefinition\";\nimport { flattenDefinition, isBranchNode, isInteger } from \"./BehaviourTreeDefinitionUtilities\";\nimport { convertMDSLToJSON } from \"./mdsl/MDSLDefinitionParser\";\n\n/**\n * An object representing the result of validating a tree definition.\n */\nexport type DefinitionValidationResult = {\n /**\n * A flag defining whether validation succeeded.\n */\n succeeded: boolean;\n /**\n * A string containing the error message if validation did not succeed.\n */\n errorMessage?: string;\n /**\n * The definition as json if the validation was successful, or undefined if validation did not succeed.\n */\n json?: RootNodeDefinition[];\n};\n\n/**\n * Validates the specified behaviour tree definition in the form of JSON or MDSL, not taking any globally registered subtrees into consideration.\n * @param definition The behaviour tree definition in the form of JSON or MDSL.\n * @returns An object representing the result of validating the given tree definition.\n */\nexport function validateDefinition(definition: any): DefinitionValidationResult {\n // The definition must be defined.\n if (definition === null || typeof definition === \"undefined\") {\n return createValidationFailureResult(\"definition is null or undefined\");\n }\n\n // We are expecting a definition in one of three different forms:\n // - A string which we will assume is MDSL and we will parse this to JSON before validation.\n // - An array which we will assume is an array of root node definitions with at least one being the primary root node (no 'id' property)\n // - An object which we will assume is the primary root node and should not have an 'id' property.\n if (typeof definition === \"string\") {\n // The definition is a string which we can assume is MDSL, so attempt to validate it.\n return validateMDSLDefinition(definition);\n } else if (typeof definition === \"object\") {\n // The definition will either be an array (of root node definitions) or an object (the single primary root node definition).\n return validateJSONDefinition(definition);\n } else {\n return createValidationFailureResult(`unexpected definition type of '${typeof definition}'`);\n }\n}\n\n/**\n * Validates the specified behaviour tree definition in the form of MDSL.\n * @param definition The behaviour tree definition in the form of MDSL.\n * @returns An object representing the result of validating the given tree definition.\n */\nfunction validateMDSLDefinition(definition: string): DefinitionValidationResult {\n let rootNodeDefinitions;\n\n // The first thing the we need to do is to attempt to convert our MDSL into JSON.\n try {\n // The definition is a string which we can assume is MDSL, so attempt to parse it to a JSON definition in the form of an array of root node definitions.\n rootNodeDefinitions = convertMDSLToJSON(definition);\n } catch (exception) {\n // We failed to parse the JSON from the MDSL, this is likely to be the result of it not being a valid MDSL string.\n return createValidationFailureResult((exception as Error).message);\n }\n\n // Unpack all of the root node definitions into arrays of main ('id' defined) and sub ('id' not defined) root node definitions.\n const mainRootNodeDefinitions = rootNodeDefinitions.filter(({ id }) => typeof id === \"undefined\");\n const subRootNodeDefinitions = rootNodeDefinitions.filter(({ id }) => typeof id === \"string\" && id.length > 0);\n\n // We should ALWAYS have exactly one root node definition without an 'id' property defined, which is out main root node definition.\n if (mainRootNodeDefinitions.length !== 1) {\n return createValidationFailureResult(\n \"expected single unnamed root node at base of definition to act as main root\"\n );\n }\n\n // We should never have duplicate 'id' properties across our sub root node definitions.\n const subRootNodeIdenitifers: string[] = [];\n for (const { id } of subRootNodeDefinitions) {\n // Have we already come across this 'id' property value?\n if (subRootNodeIdenitifers.includes(id!)) {\n return createValidationFailureResult(`multiple root nodes found with duplicate name '${id}'`);\n }\n\n subRootNodeIdenitifers.push(id!);\n }\n\n try {\n // Validate our branch -> subtree links and check for any circular dependencies, we don't care about checking for broken subtree links here.\n validateBranchSubtreeLinks(rootNodeDefinitions, false);\n } catch (exception) {\n return createValidationFailureResult((exception as Error).message);\n }\n\n // Our definition was valid!\n return {\n succeeded: true,\n json: rootNodeDefinitions\n };\n}\n\n/**\n * Validates the specified behaviour tree definition in the form of JSON.\n * @param definition The behaviour tree definition in the form of JSON.\n * @returns An object representing the result of validating the given tree definition.\n */\nexport function validateJSONDefinition(\n definition: RootNodeDefinition | RootNodeDefinition[]\n): DefinitionValidationResult {\n // The definition will either be an array (of root node definitions) or an object (the single primary root node definition).\n const rootNodeDefinitions = Array.isArray(definition) ? definition : [definition];\n\n // Iterate over our array of root nodes and call validateNode for each, passing an initial depth of 0, wrapped in a try catch to handle validation failures.\n try {\n rootNodeDefinitions.forEach((rootNodeDefinition) => validateNode(rootNodeDefinition, 0));\n } catch (error) {\n // Handle cases where we have caught a thrown Error and return a failure result with the error message.\n if (error instanceof Error) {\n return createValidationFailureResult(error.message);\n }\n\n // No idea what happened here!\n return createValidationFailureResult(`unexpected error: ${error}`);\n }\n\n // Unpack all of the root node definitions into arrays of main ('id' defined) and sub ('id' not defined) root node definitions.\n const mainRootNodeDefinitions = rootNodeDefinitions.filter(({ id }) => typeof id === \"undefined\");\n const subRootNodeDefinitions = rootNodeDefinitions.filter(({ id }) => typeof id === \"string\" && id.length > 0);\n\n // We should ALWAYS have exactly one root node definition without an 'id' property defined, which is out main root node definition.\n if (mainRootNodeDefinitions.length !== 1) {\n return createValidationFailureResult(\n \"expected single root node without 'id' property defined to act as main root\"\n );\n }\n\n // We should never have duplicate 'id' properties across our sub root node definitions.\n const subRootNodeIdenitifers: string[] = [];\n for (const { id } of subRootNodeDefinitions) {\n // Have we already come across this 'id' property value?\n if (subRootNodeIdenitifers.includes(id!)) {\n return createValidationFailureResult(\n `multiple root nodes found with duplicate 'id' property value of '${id}'`\n );\n }\n\n subRootNodeIdenitifers.push(id!);\n }\n\n try {\n // Validate our branch -> subtree links and check for any circular dependencies, we don't care about checking for broken subtree links here.\n validateBranchSubtreeLinks(rootNodeDefinitions, false);\n } catch (exception) {\n return createValidationFailureResult((exception as Error).message);\n }\n\n // Our definition was valid!\n return {\n succeeded: true,\n json: rootNodeDefinitions\n };\n}\n\n/**\n * Validates the branch -> subtree links across all provided root node definitions.\n * This will not consider branch nodes that reference any globally registered subtrees unless includesGlobalSubtrees\n * is set to true, in which case we will also verify that there are no broken branch -> subtree links.\n * @param rootNodeDefinitions The array of root node definitions.\n * @param includesGlobalSubtrees A flag defining whether the array includes all global subtree root node definitions.\n */\nexport function validateBranchSubtreeLinks(rootNodeDefinitions: RootNodeDefinition[], includesGlobalSubtrees: boolean) {\n // Create a mapping of root node identifiers to other root nodes that they reference via branch nodes.\n // Below is an example of a mapping that includes a circular dependency (root => a => b => c => a)\n // [{ refs: [\"a\", \"b\"] }, { id: \"a\", refs: [\"b\"] }, { id: \"b\", refs: [\"c\"] }, { id: \"c\", refs: [\"a\"] }]\n const rootNodeMappings: { id: string | undefined; refs: string[] }[] = rootNodeDefinitions.map(\n (rootNodeDefinition) => ({\n id: rootNodeDefinition.id,\n refs: flattenDefinition(rootNodeDefinition)\n .filter(isBranchNode)\n .map(({ ref }) => ref)\n })\n );\n\n // A recursive function to walk through the mappings, keeping track of which root nodes we have visited in the form of a path of root node identifiers.\n const followRefs = (mapping: { id: string | undefined; refs: string[] }, path: (string | undefined)[] = []) => {\n // Have we found a circular dependency?\n if (path.includes(mapping.id)) {\n // We found a circular dependency! Get the bad path of root node identifiers.\n const badPath = [...path, mapping.id];\n\n // Create the formatted path value. [undefined, \"a\", \"b\", \"c\", \"a\"] would be formatted as \"a -> b -> c -> a\".\n const badPathFormatted = badPath.filter((element) => !!element).join(\" => \");\n\n // No need to continue, we found a circular dependency.\n throw new Error(`circular dependency found in branch node references: ${badPathFormatted}`);\n }\n\n for (const ref of mapping.refs) {\n // Find the mapping for the root node with an identifer matching the current ref.\n const subMapping = rootNodeMappings.find(({ id }) => id === ref);\n\n // We may not have a mapping for this ref, which is normal when we aren't considering all globally registered subtrees.\n if (subMapping) {\n followRefs(subMapping, [...path, mapping.id]);\n } else if (includesGlobalSubtrees) {\n // We found a reference to a root node that doesn't exist, which is a problem seeing as the root node definitons includes all globally registered subtrees.\n throw new Error(\n mapping.id\n ? `subtree '${mapping.id}' has branch node that references root node '${ref}' which has not been defined`\n : `primary tree has branch node that references root node '${ref}' which has not been defined`\n );\n }\n }\n };\n\n // Start looking for circular dependencies and broken references from the primary root node definition.\n followRefs(rootNodeMappings.find((mapping) => typeof mapping.id === \"undefined\")!);\n}\n\n/**\n * Validate an object that we expect to be a node definition.\n * @param definition An object that we expect to be a node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateNode(definition: any, depth: number): void {\n // Every node must be valid object and have a non-empty 'type' string property.\n if (typeof definition !== \"object\" || typeof definition.type !== \"string\" || definition.type.length === 0) {\n throw new Error(\n `node definition is not an object or 'type' property is not a non-empty string at depth '${depth}'`\n );\n }\n\n // How we validate this node definition will depend on its type.\n switch (definition.type) {\n case \"action\":\n validateActionNode(definition, depth);\n break;\n\n case \"condition\":\n validateConditionNode(definition, depth);\n break;\n\n case \"wait\":\n validateWaitNode(definition, depth);\n break;\n\n case \"branch\":\n validateBranchNode(definition, depth);\n break;\n\n case \"root\":\n validateRootNode(definition, depth);\n break;\n\n case \"succeed\":\n validateSucceedNode(definition, depth);\n break;\n\n case \"fail\":\n validateFailNode(definition, depth);\n break;\n\n case \"flip\":\n validateFlipNode(definition, depth);\n break;\n\n case \"repeat\":\n validateRepeatNode(definition, depth);\n break;\n\n case \"retry\":\n validateRetryNode(definition, depth);\n break;\n\n case \"sequence\":\n validateSequenceNode(definition, depth);\n break;\n\n case \"selector\":\n validateSelectorNode(definition, depth);\n break;\n\n case \"parallel\":\n validateParallelNode(definition, depth);\n break;\n\n case \"lotto\":\n validateLottoNode(definition, depth);\n break;\n\n default:\n throw new Error(`unexpected node type of '${definition.type}' at depth '${depth}'`);\n }\n}\n\n/**\n * Validate any attributes for a given node definition.\n * @param definition The node definition.\n * @param depth The depth of the node in the behaviour tree definition.\n */\nfunction validateNodeAttributes(definition: any, depth: number): void {\n // Validate each of the attribute types for this node.\n [\"while\", \"until\", \"entry\", \"exit\", \"step\"].forEach((attributeName) => {\n // Attempt to grab the definition for the current attribute from the node definition.\n const attributeDefinition = definition[attributeName];\n\n // All node attributes are optional, so there is nothing to do if the current attribute is not defined.\n if (typeof attributeDefinition === \"undefined\") {\n return;\n }\n\n // The attribute definition must be an object.\n if (typeof attributeDefinition !== \"object\") {\n throw new Error(\n `expected attribute '${attributeName}' to be an object for '${definition.type}' node at depth '${depth}'`\n );\n }\n\n // The 'call' property must be defined for any attribute definition.\n if (typeof attributeDefinition.call !== \"string\" || attributeDefinition.call.length === 0) {\n throw new Error(\n `expected 'call' property for attribute '${attributeName}' to be a non-empty string for '${definition.type}' node at depth '${depth}'`\n );\n }\n\n // If any node attribute arguments have been defined then they must have been defined in an array.\n if (typeof attributeDefinition.args !== \"undefined\" && !Array.isArray(attributeDefinition.args)) {\n throw new Error(\n `expected 'args' property for attribute '${attributeName}' to be an array for '${definition.type}' node at depth '${depth}'`\n );\n }\n });\n}\n\n/**\n * Validate an object that we expect to be a root node definition.\n * @param definition An object that we expect to be a root node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateRootNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"root\") {\n throw new Error(\"expected node type of 'root' for root node\");\n }\n\n // A root node cannot be the child of another node.\n if (depth > 0) {\n throw new Error(\"a root node cannot be the child of another node\");\n }\n\n // Check that, if the root node 'id' property is defined, it is a non-empty string.\n if (typeof definition.id !== \"undefined\" && (typeof definition.id !== \"string\" || definition.id.length === 0)) {\n throw new Error(\"expected non-empty string for 'id' property if defined for root node\");\n }\n\n // A root node is a decorator node, so must have a child node defined.\n if (typeof definition.child === \"undefined\") {\n throw new Error(\"expected property 'child' to be defined for root node\");\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n\n // Validate the child node of this decorator node.\n validateNode(definition.child, depth + 1);\n}\n\n/**\n * Validate an object that we expect to be a succeed node definition.\n * @param definition An object that we expect to be a succeed node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateSucceedNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"succeed\") {\n throw new Error(`expected node type of 'succeed' for succeed node at depth '${depth}'`);\n }\n\n // A succeed node is a decorator node, so must have a child node defined.\n if (typeof definition.child === \"undefined\") {\n throw new Error(`expected property 'child' to be defined for succeed node at depth '${depth}'`);\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n\n // Validate the child node of this decorator node.\n validateNode(definition.child, depth + 1);\n}\n\n/**\n * Validate an object that we expect to be a fail node definition.\n * @param definition An object that we expect to be a fail node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateFailNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"fail\") {\n throw new Error(`expected node type of 'fail' for fail node at depth '${depth}'`);\n }\n\n // A fail node is a decorator node, so must have a child node defined.\n if (typeof definition.child === \"undefined\") {\n throw new Error(`expected property 'child' to be defined for fail node at depth '${depth}'`);\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n\n // Validate the child node of this decorator node.\n validateNode(definition.child, depth + 1);\n}\n\n/**\n * Validate an object that we expect to be a flip node definition.\n * @param definition An object that we expect to be a flip node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateFlipNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"flip\") {\n throw new Error(`expected node type of 'flip' for flip node at depth '${depth}'`);\n }\n\n // A flip node is a decorator node, so must have a child node defined.\n if (typeof definition.child === \"undefined\") {\n throw new Error(`expected property 'child' to be defined for flip node at depth '${depth}'`);\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n\n // Validate the child node of this decorator node.\n validateNode(definition.child, depth + 1);\n}\n\n/**\n * Validate an object that we expect to be a repeat node definition.\n * @param definition An object that we expect to be a repeat node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateRepeatNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"repeat\") {\n throw new Error(`expected node type of 'repeat' for repeat node at depth '${depth}'`);\n }\n\n // A repeat node is a decorator node, so must have a child node defined.\n if (typeof definition.child === \"undefined\") {\n throw new Error(`expected property 'child' to be defined for repeat node at depth '${depth}'`);\n }\n\n // Check whether an 'iterations' property has been defined, it may not have been if this node is to repeat indefinitely.\n if (typeof definition.iterations !== \"undefined\") {\n if (Array.isArray(definition.iterations)) {\n // Check whether any elements of the array are not integer values.\n const containsNonInteger = !!definition.iterations.filter((value: unknown) => !isInteger(value)).length;\n\n // If the 'iterations' property is an array then it MUST contain two integer values.\n if (definition.iterations.length !== 2 || containsNonInteger) {\n throw new Error(\n `expected array containing two integer values for 'iterations' property if defined for repeat node at depth '${depth}'`\n );\n }\n\n // A repeat node must have a positive min and max iterations count if they are defined.\n if (definition.iterations[0] < 0 || definition.iterations[1] < 0) {\n throw new Error(\n `expected positive minimum and maximum iterations count for 'iterations' property if defined for repeat node at depth '${depth}'`\n );\n }\n\n // A repeat node must not have a minimum iterations count that exceeds the maximum iterations count.\n if (definition.iterations[0] > definition.iterations[1]) {\n throw new Error(\n `expected minimum iterations count that does not exceed the maximum iterations count for 'iterations' property if defined for repeat node at depth '${depth}'`\n );\n }\n } else if (isInteger(definition.iterations)) {\n // A repeat node must have a positive number of iterations if defined.\n if (definition.iterations < 0) {\n throw new Error(\n `expected positive iterations count for 'iterations' property if defined for repeat node at depth '${depth}'`\n );\n }\n } else {\n throw new Error(\n `expected integer value or array containing two integer values for 'iterations' property if defined for repeat node at depth '${depth}'`\n );\n }\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n\n // Validate the child node of this decorator node.\n validateNode(definition.child, depth + 1);\n}\n\n/**\n * Validate an object that we expect to be a retry node definition.\n * @param definition An object that we expect to be a retry node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateRetryNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"retry\") {\n throw new Error(`expected node type of 'retry' for retry node at depth '${depth}'`);\n }\n\n // A retry node is a decorator node, so must have a child node defined.\n if (typeof definition.child === \"undefined\") {\n throw new Error(`expected property 'child' to be defined for retry node at depth '${depth}'`);\n }\n\n // Check whether an 'attempts' property has been defined, it may not have been if this node is to retry indefinitely.\n if (typeof definition.attempts !== \"undefined\") {\n if (Array.isArray(definition.attempts)) {\n // Check whether any elements of the array are not integer values.\n const containsNonInteger = !!definition.attempts.filter((value: unknown) => !isInteger(value)).length;\n\n // If the 'attempts' property is an array then it MUST contain two integer values.\n if (definition.attempts.length !== 2 || containsNonInteger) {\n throw new Error(\n `expected array containing two integer values for 'attempts' property if defined for retry node at depth '${depth}'`\n );\n }\n\n // A retry node must have a positive min and max attempts count if they are defined.\n if (definition.attempts[0] < 0 || definition.attempts[1] < 0) {\n throw new Error(\n `expected positive minimum and maximum attempts count for 'attempts' property if defined for retry node at depth '${depth}'`\n );\n }\n\n // A retry node must not have a minimum attempts count that exceeds the maximum attempts count.\n if (definition.attempts[0] > definition.attempts[1]) {\n throw new Error(\n `expected minimum attempts count that does not exceed the maximum attempts count for 'attempts' property if defined for retry node at depth '${depth}'`\n );\n }\n } else if (isInteger(definition.attempts)) {\n // A retry node must have a positive number of attempts if defined.\n if (definition.attempts < 0) {\n throw new Error(\n `expected positive attempts count for 'attempts' property if defined for retry node at depth '${depth}'`\n );\n }\n } else {\n throw new Error(\n `expected integer value or array containing two integer values for 'attempts' property if defined for retry node at depth '${depth}'`\n );\n }\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n\n // Validate the child node of this decorator node.\n validateNode(definition.child, depth + 1);\n}\n\n/**\n * Validate an object that we expect to be a branch node definition.\n * @param definition An object that we expect to be a branch node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateBranchNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"branch\") {\n throw new Error(`expected node type of 'branch' for branch node at depth '${depth}'`);\n }\n\n // Check that the branch node 'ref' property is defined and is a non-empty string.\n if (typeof definition.ref !== \"string\" || definition.ref.length === 0) {\n throw new Error(`expected non-empty string for 'ref' property for branch node at depth '${depth}'`);\n }\n\n // It is invalid to define guard attributes for a branch node as they should be defined on the referenced root node.\n [\"while\", \"until\"].forEach((attributeName) => {\n if (typeof definition[attributeName] !== \"undefined\") {\n throw new Error(\n `guards should not be defined for branch nodes but guard '${attributeName}' was defined for branch node at depth '${depth}'`\n );\n }\n });\n\n // It is invalid to define callback attributes for a branch node as they should be defined on the referenced root node.\n [\"entry\", \"exit\", \"step\"].forEach((attributeName) => {\n if (typeof definition[attributeName] !== \"undefined\") {\n throw new Error(\n `callbacks should not be defined for branch nodes but callback '${attributeName}' was defined for branch node at depth '${depth}'`\n );\n }\n });\n}\n\n/**\n * Validate an object that we expect to be a action node definition.\n * @param definition An object that we expect to be a action node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateActionNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"action\") {\n throw new Error(`expected node type of 'action' for action node at depth '${depth}'`);\n }\n\n // The 'call' property must be defined for a action node definition.\n if (typeof definition.call !== \"string\" || definition.call.length === 0) {\n throw new Error(`expected non-empty string for 'call' property of action node at depth '${depth}'`);\n }\n\n // If any action function arguments have been defined then they must have been defined in an array.\n if (typeof definition.args !== \"undefined\" && !Array.isArray(definition.args)) {\n throw new Error(`expected array for 'args' property if defined for action node at depth '${depth}'`);\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n}\n\n/**\n * Validate an object that we expect to be a condition node definition.\n * @param definition An object that we expect to be a condition node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateConditionNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"condition\") {\n throw new Error(`expected node type of 'condition' for condition node at depth '${depth}'`);\n }\n\n // The 'call' property must be defined for a condition node definition.\n if (typeof definition.call !== \"string\" || definition.call.length === 0) {\n throw new Error(`expected non-empty string for 'call' property of condition node at depth '${depth}'`);\n }\n\n // If any condition function arguments have been defined then they must have been defined in an array.\n if (typeof definition.args !== \"undefined\" && !Array.isArray(definition.args)) {\n throw new Error(`expected array for 'args' property if defined for condition node at depth '${depth}'`);\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n}\n\n/**\n * Validate an object that we expect to be a wait node definition.\n * @param definition An object that we expect to be a wait node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateWaitNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"wait\") {\n throw new Error(`expected node type of 'wait' for wait node at depth '${depth}'`);\n }\n\n // Check whether a 'duration' property has been defined, it may not have been if this node is to wait indefinitely.\n if (typeof definition.duration !== \"undefined\") {\n if (Array.isArray(definition.duration)) {\n // Check whether any elements of the array are not integer values.\n const containsNonInteger = !!definition.duration.filter((value: unknown) => !isInteger(value)).length;\n\n // If the 'duration' property is an array then it MUST contain two integer values.\n if (definition.duration.length !== 2 || containsNonInteger) {\n throw new Error(\n `expected array containing two integer values for 'duration' property if defined for wait node at depth '${depth}'`\n );\n }\n\n // A wait node must have a positive min and max duration value if they are defined.\n if (definition.duration[0] < 0 || definition.duration[1] < 0) {\n throw new Error(\n `expected positive minimum and maximum duration for 'duration' property if defined for wait node at depth '${depth}'`\n );\n }\n\n // A wait node must not have a minimum duration value that exceeds the maximum duration value.\n if (definition.duration[0] > definition.duration[1]) {\n throw new Error(\n `expected minimum duration value that does not exceed the maximum duration value for 'duration' property if defined for wait node at depth '${depth}'`\n );\n }\n } else if (isInteger(definition.duration)) {\n // A wait node must have a positive duration value if defined.\n if (definition.duration < 0) {\n throw new Error(\n `expected positive duration value for 'duration' property if defined for wait node at depth '${depth}'`\n );\n }\n } else {\n throw new Error(\n `expected integer value or array containing two integer values for 'duration' property if defined for wait node at depth '${depth}'`\n );\n }\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n}\n\n/**\n * Validate an object that we expect to be a sequence node definition.\n * @param definition An object that we expect to be a sequence node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateSequenceNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"sequence\") {\n throw new Error(`expected node type of 'sequence' for sequence node at depth '${depth}'`);\n }\n\n // A sequence node is a composite node, so must have a children nodes array defined.\n if (!Array.isArray(definition.children) || definition.children.length === 0) {\n throw new Error(`expected non-empty 'children' array to be defined for sequence node at depth '${depth}'`);\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n\n // Validate the child nodes of this composite node.\n definition.children.forEach((child: any) => validateNode(child, depth + 1));\n}\n\n/**\n * Validate an object that we expect to be a selector node definition.\n * @param definition An object that we expect to be a selector node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateSelectorNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"selector\") {\n throw new Error(`expected node type of 'selector' for selector node at depth '${depth}'`);\n }\n\n // A selector node is a composite node, so must have a children nodes array defined.\n if (!Array.isArray(definition.children) || definition.children.length === 0) {\n throw new Error(`expected non-empty 'children' array to be defined for selector node at depth '${depth}'`);\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n\n // Validate the child nodes of this composite node.\n definition.children.forEach((child: any) => validateNode(child, depth + 1));\n}\n\n/**\n * Validate an object that we expect to be a parallel node definition.\n * @param definition An object that we expect to be a parallel node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateParallelNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"parallel\") {\n throw new Error(`expected node type of 'parallel' for parallel node at depth '${depth}'`);\n }\n\n // A parallel node is a composite node, so must have a children nodes array defined.\n if (!Array.isArray(definition.children) || definition.children.length === 0) {\n throw new Error(`expected non-empty 'children' array to be defined for parallel node at depth '${depth}'`);\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n\n // Validate the child nodes of this composite node.\n definition.children.forEach((child: any) => validateNode(child, depth + 1));\n}\n\n/**\n * Validate an object that we expect to be a lotto node definition.\n * @param definition An object that we expect to be a lotto node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateLottoNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"lotto\") {\n throw new Error(`expected node type of 'lotto' for lotto node at depth '${depth}'`);\n }\n\n // A lotto node is a composite node, so must have a children nodes array defined.\n if (!Array.isArray(definition.children) || definition.children.length === 0) {\n throw new Error(`expected non-empty 'children' array to be defined for lotto node at depth '${depth}'`);\n }\n\n // Check whether a 'weights' property has been defined, if it has we expect it to be an array of weights.\n if (typeof definition.weights !== \"undefined\") {\n // Check that the weights property is an array of positive integers with an element for each child node element.\n if (\n !Array.isArray(definition.weights) ||\n definition.weights.length !== definition.children.length ||\n definition.weights.filter((value: unknown) => !isInteger(value)).length ||\n definition.weights.filter((value: number) => value < 0).length\n ) {\n throw new Error(\n `expected an array of positive integer weight values with a length matching the number of child nodes for 'weights' property if defined for lotto node at depth '${depth}'`\n );\n }\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n\n // Validate the child nodes of this composite node.\n definition.children.forEach((child: any) => validateNode(child, depth + 1));\n}\n\n/**\n * A helper function to create a failure validation result with the given error message.\n * @param errorMessage The validation failure error message.\n * @returns A failure validation result with the given error message.\n */\nfunction createValidationFailureResult(errorMessage: string): DefinitionValidationResult {\n return { succeeded: false, errorMessage };\n}\n", "import { ActionResult, Agent, GlobalFunction } from \"./Agent\";\nimport { RootNodeDefinition } from \"./BehaviourTreeDefinition\";\n\nexport type InvokerFunction = (args: any[]) => ActionResult;\n\n/**\n * A singleton used to store and lookup registered functions and subtrees.\n */\nexport default class Lookup {\n /**\n * The object holding any registered functions keyed on function name.\n */\n private static functionTable: { [key: string]: GlobalFunction } = {};\n /**\n * The object holding any registered subtree root node definitions keyed on tree name.\n */\n private static subtreeTable: { [key: string]: RootNodeDefinition } = {};\n\n /**\n * Gets the function with the specified name.\n * @param name The name of the function.\n * @returns The function with the specified name.\n */\n public static getFunc(name: string): GlobalFunction {\n return this.functionTable[name];\n }\n\n /**\n * Sets the function with the specified name for later lookup.\n * @param name The name of the function.\n * @param func The function.\n */\n public static setFunc(name: string, func: GlobalFunction): void {\n this.functionTable[name] = func;\n }\n\n /**\n * Gets the function invoker for the specified agent and function name.\n * If a function with the specified name exists on the agent object then it will\n * be returned, otherwise we will then check the registered functions for a match.\n * @param agent The agent instance that this behaviour tree is modelling behaviour for.\n * @param name The function name.\n * @returns The function invoker for the specified agent and function name.\n */\n static getFuncInvoker(agent: Agent, name: string): InvokerFunction | null {\n // Check whether the agent contains the specified function.\n const foundOnAgent = agent[name];\n if (foundOnAgent && typeof foundOnAgent === \"function\") {\n return (args: any[]): boolean | ActionResult => foundOnAgent.apply(agent, args);\n }\n\n // The agent does not contain the specified function but it may have been registered at some point.\n if (this.functionTable[name] && typeof this.functionTable[name] === \"function\") {\n return (args: any[]) => this.functionTable[name](agent, ...args.map((arg) => arg.value));\n }\n\n // We have no function to invoke.\n return null;\n }\n\n /**\n * Gets all registered subtree root node definitions.\n */\n static getSubtrees(): { [key: string]: RootNodeDefinition } {\n return this.subtreeTable;\n }\n\n /**\n * Sets the subtree with the specified name for later lookup.\n * @param name The name of the subtree.\n * @param subtree The subtree.\n */\n static setSubtree(name: string, subtree: RootNodeDefinition) {\n this.subtreeTable[name] = subtree;\n }\n\n /**\n * Removes the registered function or subtree with the specified name.\n * @param name The name of the registered function or subtree.\n */\n static remove(name: string) {\n delete this.functionTable[name];\n delete this.subtreeTable[name];\n }\n\n /**\n * Remove all registered functions and subtrees.\n */\n static empty() {\n this.functionTable = {};\n this.subtreeTable = {};\n }\n}\n", "import Node from \"../../nodes/Node\";\n\n/**\n * An exception thrown when evaluating node guard path conditions and a conditions fails.\n */\nexport default class GuardUnsatisifedException extends Error {\n /**\n * @param source The node at which a guard condition failed.\n */\n constructor(private source: Node) {\n super(\"A guard path condition has failed\");\n }\n\n /**\n * Gets whether the specified node is the node at which a guard condition failed.\n * @param node The node to check against the source node.\n * @returns Whether the specified node is the node at which a guard condition failed.\n */\n isSourceNode = (node: Node) => node === this.source;\n}\n", "import { Agent } from \"../../Agent\";\nimport Guard from \"./Guard\";\nimport Node from \"../../nodes/Node\";\nimport GuardUnsatisifedException from \"./GuardUnsatisifedException\";\n\nexport type GuardPathPart = {\n node: Node;\n guards: Guard[];\n};\n\n/**\n * Represents a path of node guards along a root-to-leaf tree path.\n */\nexport default class GuardPath {\n /**\n * @param nodes An array of objects defining a node instance -> guard link, ordered by node depth.\n */\n constructor(private nodes: GuardPathPart[]) {}\n\n /**\n * Evaluate guard conditions for all guards in the tree path, moving outwards from the root.\n * @param agent The agent, required for guard evaluation.\n * @returns An evaluation results object.\n */\n evaluate = (agent: Agent) => {\n // We need to evaluate guard conditions for nodes up the tree, moving outwards from the root.\n for (const details of this.nodes) {\n // There can be multiple guards per node.\n for (const guard of details.guards) {\n // Check whether the guard condition passes, and throw an exception if not.\n if (!guard.isSatisfied(agent)) {\n throw new GuardUnsatisifedException(details.node);\n }\n }\n }\n };\n}\n", "import { BehaviourTreeOptions } from \"../BehaviourTreeOptions\";\nimport State, { AnyState } from \"../State\";\nimport { Agent } from \"../Agent\";\nimport Leaf from \"./leaf/Leaf\";\nimport Attribute from \"../attributes/Attribute\";\nimport Entry from \"../attributes/callbacks/Entry\";\nimport Exit from \"../attributes/callbacks/Exit\";\nimport Step from \"../attributes/callbacks/Step\";\nimport Guard from \"../attributes/guards/Guard\";\nimport GuardPath from \"../attributes/guards/GuardPath\";\nimport GuardUnsatisifedException from \"../attributes/guards/GuardUnsatisifedException\";\n\n/**\n * A base node.\n */\nexport default abstract class Node {\n /**\n * The node uid.\n */\n private readonly uid: string = createNodeUid();\n /**\n * The node state.\n */\n private state: AnyState = State.READY;\n /**\n * The guard path to evaluate as part of a node update.\n */\n private guardPath: GuardPath | undefined;\n\n /**\n * @param type The node type.\n * @param attributes The node attributes.\n * @param args The node argument definitions.\n */\n constructor(private type: string, private attributes: Attribute[], private args: any[]) {}\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected abstract onUpdate(agent: Agent, options: BehaviourTreeOptions): void;\n\n /**\n * Gets the name of the node.\n */\n public abstract getName(): string;\n\n /**\n * Gets whether this node is a leaf node.\n */\n public abstract isLeafNode: () => this is Leaf;\n\n /**\n * Gets/Sets the state of the node.\n */\n getState = (): AnyState => this.state;\n setState = (value: AnyState): void => {\n this.state = value;\n };\n\n /**\n * Gets the unique id of the node.\n */\n getUid = () => this.uid;\n\n /**\n * Gets the type of the node.\n */\n getType = () => this.type;\n\n /**\n * Gets the node attributes.\n */\n getAttributes = () => this.attributes;\n\n /**\n * Gets the node arguments.\n */\n getArguments = () => this.args;\n\n /**\n * Gets the node attribute with the specified type, or null if it does not exist.\n */\n getAttribute(type: \"entry\" | \"ENTRY\"): Entry;\n getAttribute(type: \"exit\" | \"EXIT\"): Exit;\n getAttribute(type: \"step\" | \"STEP\"): Step;\n getAttribute(type: string): Attribute {\n return (\n this.getAttributes().filter((decorator) => decorator.type.toUpperCase() === type.toUpperCase())[0] || null\n );\n }\n\n /**\n * Gets the node attributes.\n */\n getGuardAttributes = (): Guard[] => this.getAttributes().filter((decorator) => decorator.isGuard()) as Guard[];\n\n /**\n * Sets the guard path to evaluate as part of a node update.\n */\n setGuardPath = (value: GuardPath) => (this.guardPath = value);\n\n /**\n * Gets whether a guard path is assigned to this node.\n */\n hasGuardPath = () => !!this.guardPath;\n\n /**\n * Gets whether this node is in the specified state.\n * @param value The value to compare to the node state.\n */\n public is(value: AnyState): boolean {\n return this.state === value;\n }\n\n /**\n * Reset the state of the node.\n */\n public reset(): void {\n this.setState(State.READY);\n }\n\n /**\n * Abort the running of this node.\n * @param agent The agent.\n */\n public abort(agent: Agent): void {\n // There is nothing to do if this node is not in the running state.\n if (!this.is(State.RUNNING)) {\n return;\n }\n\n // Reset the state of this node.\n this.reset();\n\n this.getAttribute(\"exit\")?.callAgentFunction(agent, false, true);\n }\n\n /**\n * Update the node.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n * @returns The result of the update.\n */\n public update(agent: Agent, options: BehaviourTreeOptions): void {\n // If this node is already in a 'SUCCEEDED' or 'FAILED' state then there is nothing to do.\n if (this.is(State.SUCCEEDED) || this.is(State.FAILED)) {\n return;\n }\n\n try {\n // Evaluate all of the guard path conditions for the current tree path.\n this.guardPath!.evaluate(agent);\n\n // If this node is in the READY state then call the ENTRY for this node if it exists.\n if (this.is(State.READY)) {\n this.getAttribute(\"entry\")?.callAgentFunction(agent);\n }\n\n this.getAttribute(\"step\")?.callAgentFunction(agent);\n\n // Do the actual update.\n this.onUpdate(agent, options);\n\n // If this node is now in a 'SUCCEEDED' or 'FAILED' state then call the EXIT for this node if it exists.\n if (this.is(State.SUCCEEDED) || this.is(State.FAILED)) {\n this.getAttribute(\"exit\")?.callAgentFunction(agent, this.is(State.SUCCEEDED), false);\n }\n } catch (error) {\n // If the error is a GuardUnsatisfiedException then we need to determine if this node is the source.\n if (error instanceof GuardUnsatisifedException && error.isSourceNode(this)) {\n // Abort the current node.\n this.abort(agent);\n\n // Any node that is the source of an abort will be a failed node.\n this.setState(State.FAILED);\n } else {\n throw error;\n }\n }\n }\n}\n\n/**\n * Create a randomly generated node uid.\n * @returns A randomly generated node uid.\n */\nfunction createNodeUid(): string {\n var S4 = function () {\n return (((1 + Math.random()) * 0x10000) | 0).toString(16).substring(1);\n };\n return S4() + S4() + \"-\" + S4() + \"-\" + S4() + \"-\" + S4() + \"-\" + S4() + S4() + S4();\n}\n", "import Node from \"../Node\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\n\n/**\n * A composite node that wraps child nodes.\n */\nexport default abstract class Composite extends Node {\n /**\n * @param type The node type.\n * @param attributes The node attributes.\n * @param children The child nodes.\n */\n constructor(type: string, attributes: Attribute[], protected children: Node[]) {\n super(type, attributes, []);\n }\n\n /**\n * Gets whether this node is a leaf node.\n */\n isLeafNode = () => false;\n\n /**\n * Gets the children of this node.\n */\n getChildren = () => this.children;\n\n /**\n * Reset the state of the node.\n */\n reset = () => {\n // Reset the state of this node.\n this.setState(State.READY);\n\n // Reset the state of any child nodes.\n this.getChildren().forEach((child) => child.reset());\n };\n\n /**\n * Abort the running of this node.\n * @param agent The agent.\n */\n abort = (agent: Agent) => {\n // There is nothing to do if this node is not in the running state.\n if (!this.is(State.RUNNING)) {\n return;\n }\n\n // Abort any child nodes.\n this.getChildren().forEach((child) => child.abort(agent));\n\n // Reset the state of this node.\n this.reset();\n\n this.getAttribute(\"exit\")?.callAgentFunction(agent, false, true);\n };\n}\n", "import Composite from \"./Composite\";\nimport State from \"../../State\";\nimport Node from \"../Node\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A PARALLEL node.\n * The child nodes are executed concurrently until one fails or all succeed.\n */\nexport default class Parallel extends Composite {\n /**\n * @param attributes The node attributes.\n * @param children The child nodes.\n */\n constructor(attributes: Attribute[], children: Node[]) {\n super(\"parallel\", attributes, children);\n }\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // Keep a count of the number of succeeded child nodes.\n let succeededCount = 0;\n\n let hasChildFailed = false;\n\n // Iterate over all of the children of this node.\n for (const child of this.children) {\n // If the child has never been updated or is running then we will need to update it now.\n if (child.getState() === State.READY || child.getState() === State.RUNNING) {\n // Update the child of this node.\n child.update(agent, options);\n }\n\n // If the current child has a state of 'SUCCEEDED' then we should move on to the next child.\n if (child.getState() === State.SUCCEEDED) {\n // The child node has succeeded, keep track of this to determine if all children have.\n succeededCount++;\n\n // The child node succeeded, but we have not finished checking every child node yet.\n continue;\n }\n\n // If the current child has a state of 'FAILED' then this node is also a 'FAILED' node.\n if (child.getState() === State.FAILED) {\n hasChildFailed = true;\n\n // There is no need to check the rest of the children.\n break;\n }\n\n // The node should be in the 'RUNNING' state.\n if (child.getState() !== State.RUNNING) {\n // The child node was not in an expected state.\n throw new Error(\"child node was not in an expected state.\");\n }\n }\n\n if (hasChildFailed) {\n // This node is a 'FAILED' node.\n this.setState(State.FAILED);\n\n // Abort every running child.\n for (const child of this.children) {\n if (child.getState() === State.RUNNING) {\n child.abort(agent);\n }\n }\n } else {\n // If all children have succeeded then this node has also succeeded, otherwise it is still running.\n this.setState(succeededCount === this.children.length ? State.SUCCEEDED : State.RUNNING);\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => \"PARALLEL\";\n}\n", "import Composite from \"./Composite\";\nimport Node from \"../Node\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A SELECTOR node.\n * The child nodes are executed in sequence until one succeeds or all fail.\n */\nexport default class Selector extends Composite {\n /**\n * @param attributes The node attributes.\n * @param children The child nodes.\n */\n constructor(attributes: Attribute[], protected children: Node[]) {\n super(\"selector\", attributes, children);\n }\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // Iterate over all of the children of this node.\n for (const child of this.children) {\n // If the child has never been updated or is running then we will need to update it now.\n if (child.getState() === State.READY || child.getState() === State.RUNNING) {\n // Update the child of this node.\n child.update(agent, options);\n }\n\n // If the current child has a state of 'SUCCEEDED' then this node is also a 'SUCCEEDED' node.\n if (child.getState() === State.SUCCEEDED) {\n // This node is a 'SUCCEEDED' node.\n this.setState(State.SUCCEEDED);\n\n // There is no need to check the rest of the selector nodes.\n return;\n }\n\n // If the current child has a state of 'FAILED' then we should move on to the next child.\n if (child.getState() === State.FAILED) {\n // Find out if the current child is the last one in the selector.\n // If it is then this sequence node has also failed.\n if (this.children.indexOf(child) === this.children.length - 1) {\n // This node is a 'FAILED' node.\n this.setState(State.FAILED);\n\n // There is no need to check the rest of the selector as we have completed it.\n return;\n } else {\n // The child node failed, try the next one.\n continue;\n }\n }\n\n // The node should be in the 'RUNNING' state.\n if (child.getState() === State.RUNNING) {\n // This node is a 'RUNNING' node.\n this.setState(State.RUNNING);\n\n // There is no need to check the rest of the selector as the current child is still running.\n return;\n }\n\n // The child node was not in an expected state.\n throw new Error(\"child node was not in an expected state.\");\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => \"SELECTOR\";\n}\n", "import Composite from \"./Composite\";\nimport Node from \"../Node\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A SEQUENCE node.\n * The child nodes are executed in sequence until one fails or all succeed.\n */\nexport default class Sequence extends Composite {\n /**\n * @param attributes The node attributes.\n * @param children The child nodes.\n */\n constructor(attributes: Attribute[], protected children: Node[]) {\n super(\"sequence\", attributes, children);\n }\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // Iterate over all of the children of this node.\n for (const child of this.children) {\n // If the child has never been updated or is running then we will need to update it now.\n if (child.getState() === State.READY || child.getState() === State.RUNNING) {\n // Update the child of this node.\n child.update(agent, options);\n }\n\n // If the current child has a state of 'SUCCEEDED' then we should move on to the next child.\n if (child.getState() === State.SUCCEEDED) {\n // Find out if the current child is the last one in the sequence.\n // If it is then this sequence node has also succeeded.\n if (this.children.indexOf(child) === this.children.length - 1) {\n // This node is a 'SUCCEEDED' node.\n this.setState(State.SUCCEEDED);\n\n // There is no need to check the rest of the sequence as we have completed it.\n return;\n } else {\n // The child node succeeded, but we have not finished the sequence yet.\n continue;\n }\n }\n\n // If the current child has a state of 'FAILED' then this node is also a 'FAILED' node.\n if (child.getState() === State.FAILED) {\n // This node is a 'FAILED' node.\n this.setState(State.FAILED);\n\n // There is no need to check the rest of the sequence.\n return;\n }\n\n // The node should be in the 'RUNNING' state.\n if (child.getState() === State.RUNNING) {\n // This node is a 'RUNNING' node.\n this.setState(State.RUNNING);\n\n // There is no need to check the rest of the sequence as the current child is still running.\n return;\n }\n\n // The child node was not in an expected state.\n throw new Error(\"child node was not in an expected state.\");\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => \"SEQUENCE\";\n}\n", "import createLotto from \"lotto-draw\";\n\nimport Node from \"../Node\";\nimport Composite from \"./Composite\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A LOTTO node.\n * A winning child is picked on the initial update of this node, based on ticket weighting.\n * The state of this node will match the state of the winning child.\n */\nexport default class Lotto extends Composite {\n /**\n * @param attributes The node attributes.\n * @param weights The child node weights.\n * @param children The child nodes.\n */\n constructor(attributes: Attribute[], private weights: number[] | undefined, children: Node[]) {\n super(\"lotto\", attributes, children);\n }\n\n /**\n * The child node selected to be the active one.\n */\n private selectedChild: Node | undefined;\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // If this node is in the READY state then we need to pick a winning child node.\n if (this.is(State.READY)) {\n // Create a lotto draw with which to randomly pick a child node to become the active one.\n const lottoDraw = createLotto({\n // Hook up the optional 'random' behaviour tree function option to the one used by 'lotto-draw'.\n random: options.random,\n // Pass in each child node as a participant in the lotto draw with their respective ticket count.\n participants: this.children.map((child, index) => [child, this.weights?.[index] || 1])\n });\n\n // Randomly pick a child based on ticket weighting, this will become the active child for this composite node.\n this.selectedChild = lottoDraw.draw() || undefined;\n }\n\n // If something went wrong and we don't have an active child then we should throw an error.\n if (!this.selectedChild) {\n throw new Error(\"failed to update lotto node as it has no active child\");\n }\n\n // If the selected child has never been updated or is running then we will need to update it now.\n if (this.selectedChild.getState() === State.READY || this.selectedChild.getState() === State.RUNNING) {\n this.selectedChild.update(agent, options);\n }\n\n // The state of the lotto node is the state of its selected child.\n this.setState(this.selectedChild.getState());\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => (this.weights ? `LOTTO [${this.weights.join(\",\")}]` : \"LOTTO\");\n}\n", "import Node from \"../Node\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\n\n/**\n * A decorator node that wraps a single child node.\n */\nexport default abstract class Decorator extends Node {\n /**\n * @param type The node type.\n * @param attributes The node attributes.\n * @param child The child node.\n */\n constructor(type: string, attributes: Attribute[], protected child: Node) {\n super(type, attributes, []);\n }\n\n /**\n * Gets whether this node is a leaf node.\n */\n isLeafNode = () => false;\n\n /**\n * Gets the children of this node.\n */\n getChildren = () => [this.child];\n\n /**\n * Reset the state of the node.\n */\n reset = () => {\n // Reset the state of this node.\n this.setState(State.READY);\n\n // Reset the state of the child node.\n this.child.reset();\n };\n\n /**\n * Abort the running of this node.\n * @param agent The agent.\n */\n abort = (agent: Agent) => {\n // There is nothing to do if this node is not in the running state.\n if (!this.is(State.RUNNING)) {\n return;\n }\n\n // Abort the child node.\n this.child.abort(agent);\n\n // Reset the state of this node.\n this.reset();\n\n this.getAttribute(\"exit\")?.callAgentFunction(agent, false, true);\n };\n}\n", "import Node from \"../Node\";\nimport Decorator from \"./Decorator\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A Fail node.\n * This node wraps a single child and will always move to the 'FAILED' state when the child moves to a 'SUCCEEDED' or 'FAILED' state.\n */\nexport default class Fail extends Decorator {\n /**\n * @param attributes The node attributes.\n * @param child The child node.\n */\n constructor(attributes: Attribute[], child: Node) {\n super(\"fail\", attributes, child);\n }\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // If the child has never been updated or is running then we will need to update it now.\n if (this.child.getState() === State.READY || this.child.getState() === State.RUNNING) {\n this.child.update(agent, options);\n }\n\n // The state of this node will depend in the state of its child.\n switch (this.child.getState()) {\n case State.RUNNING:\n this.setState(State.RUNNING);\n break;\n\n case State.SUCCEEDED:\n case State.FAILED:\n this.setState(State.FAILED);\n break;\n\n default:\n this.setState(State.READY);\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => \"FAIL\";\n}\n", "import Decorator from \"./Decorator\";\nimport State from \"../../State\";\nimport Node from \"../Node\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A Flip node.\n * This node wraps a single child and will flip the state of the child state.\n */\nexport default class Flip extends Decorator {\n /**\n * @param attributes The node attributes.\n * @param child The child node.\n */\n constructor(attributes: Attribute[], child: Node) {\n super(\"flip\", attributes, child);\n }\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // If the child has never been updated or is running then we will need to update it now.\n if (this.child.getState() === State.READY || this.child.getState() === State.RUNNING) {\n this.child.update(agent, options);\n }\n\n // The state of this node will depend in the state of its child.\n switch (this.child.getState()) {\n case State.RUNNING:\n this.setState(State.RUNNING);\n break;\n\n case State.SUCCEEDED:\n this.setState(State.FAILED);\n break;\n\n case State.FAILED:\n this.setState(State.SUCCEEDED);\n break;\n\n default:\n this.setState(State.READY);\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => \"FLIP\";\n}\n", "import Node from \"../Node\";\nimport Decorator from \"./Decorator\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A REPEAT node.\n * The node has a single child which can have:\n * -- A number of iterations for which to repeat the child node.\n * -- An infinite repeat loop if neither an iteration count or a condition function is defined.\n * The REPEAT node will stop and have a 'FAILED' state if its child is ever in a 'FAILED' state after an update.\n * The REPEAT node will attempt to move on to the next iteration if its child is ever in a 'SUCCEEDED' state.\n */\nexport default class Repeat extends Decorator {\n /**\n * @param attributes The node attributes.\n * @param iterations The number of iterations to repeat the child node.\n * @param iterationsMin The minimum possible number of iterations to repeat the child node.\n * @param iterationsMax The maximum possible number of iterations to repeat the child node.\n * @param child The child node.\n */\n constructor(\n attributes: Attribute[],\n private iterations: number | null,\n private iterationsMin: number | null,\n private iterationsMax: number | null,\n child: Node\n ) {\n super(\"repeat\", attributes, child);\n }\n\n /**\n * The number of target iterations to make.\n */\n private targetIterationCount: number | null = null;\n\n /**\n * The current iteration count.\n */\n private currentIterationCount: number = 0;\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // If this node is in the READY state then we need to reset the child and the target iteration count.\n if (this.is(State.READY)) {\n // Reset the child node.\n this.child.reset();\n\n // Reset the current iteration count.\n this.currentIterationCount = 0;\n\n // Set the target iteration count.\n this.setTargetIterationCount(options);\n }\n\n // Do a check to see if we can iterate. If we can then this node will move into the 'RUNNING' state.\n // If we cannot iterate then we have hit our target iteration count, which means that the node has succeeded.\n if (this.canIterate()) {\n // This node is in the running state and can do its initial iteration.\n this.setState(State.RUNNING);\n\n // We may have already completed an iteration, meaning that the child node will be in the SUCCEEDED state.\n // If this is the case then we will have to reset the child node now.\n if (this.child.getState() === State.SUCCEEDED) {\n this.child.reset();\n }\n\n // Update the child of this node.\n this.child.update(agent, options);\n\n // If the child moved into the FAILED state when we updated it then there is nothing left to do and this node has also failed.\n // If it has moved into the SUCCEEDED state then we have completed the current iteration.\n if (this.child.getState() === State.FAILED) {\n // The child has failed, meaning that this node has failed.\n this.setState(State.FAILED);\n\n return;\n } else if (this.child.getState() === State.SUCCEEDED) {\n // We have completed an iteration.\n this.currentIterationCount += 1;\n }\n } else {\n // This node is in the 'SUCCEEDED' state as we cannot iterate any more.\n this.setState(State.SUCCEEDED);\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => {\n if (this.iterations !== null) {\n return `REPEAT ${this.iterations}x`;\n } else if (this.iterationsMin !== null && this.iterationsMax !== null) {\n return `REPEAT ${this.iterationsMin}x-${this.iterationsMax}x`;\n } else {\n return \"REPEAT\";\n }\n };\n\n /**\n * Reset the state of the node.\n */\n reset = () => {\n // Reset the state of this node.\n this.setState(State.READY);\n\n // Reset the current iteration count.\n this.currentIterationCount = 0;\n\n // Reset the child node.\n this.child.reset();\n };\n\n /**\n * Gets whether an iteration can be made.\n * @returns Whether an iteration can be made.\n */\n private canIterate = () => {\n if (this.targetIterationCount !== null) {\n // We can iterate as long as we have not reached our target iteration count.\n return this.currentIterationCount < this.targetIterationCount;\n }\n\n // If neither an iteration count or a condition function were defined then we can iterate indefinitely.\n return true;\n };\n\n /**\n * Sets the target iteration count.\n * @param options The behaviour tree options object.\n */\n private setTargetIterationCount = (options: BehaviourTreeOptions) => {\n // Are we dealing with an explicit iteration count or will we be randomly picking a iteration count between the min and max iteration count.\n if (this.iterations !== null) {\n this.targetIterationCount = this.iterations;\n } else if (this.iterationsMin !== null && this.iterationsMax !== null) {\n // We will be picking a random iteration count between a min and max iteration count, if the optional 'random'\n // behaviour tree function option is defined then we will be using that, otherwise we will fall back to using Math.random.\n const random = typeof options.random === \"function\" ? options.random : Math.random;\n\n // Pick a random iteration count between a min and max iteration count.\n this.targetIterationCount = Math.floor(\n random() * (this.iterationsMax - this.iterationsMin + 1) + this.iterationsMin\n );\n } else {\n this.targetIterationCount = null;\n }\n };\n}\n", "import Node from \"../Node\";\nimport Decorator from \"./Decorator\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A RETRY node.\n * The node has a single child which can have:\n * -- A number of iterations for which to repeat the child node.\n * -- An infinite repeat loop if neither an iteration count or a condition function is defined.\n * The RETRY node will stop and have a 'SUCCEEDED' state if its child is ever in a 'SUCCEEDED' state after an update.\n * The RETRY node will attempt to move on to the next iteration if its child is ever in a 'FAILED' state.\n */\nexport default class Retry extends Decorator {\n /**\n * @param attributes The node attributes.\n * @param attempts The number of attempts to retry the child node.\n * @param attemptsMin The minimum possible number of attempts to retry the child node.\n * @param attemptsMax The maximum possible number of attempts to retry the child node.\n * @param child The child node.\n */\n constructor(\n attributes: Attribute[],\n private attempts: number | null,\n private attemptsMin: number | null,\n private attemptsMax: number | null,\n child: Node\n ) {\n super(\"retry\", attributes, child);\n }\n\n /**\n * The number of target attempts to make.\n */\n private targetAttemptCount: number | null = null;\n\n /**\n * The current attempt count.\n */\n private currentAttemptCount: number = 0;\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // If this node is in the READY state then we need to reset the child and the target attempt count.\n if (this.is(State.READY)) {\n // Reset the child node.\n this.child.reset();\n\n // Reset the current attempt count.\n this.currentAttemptCount = 0;\n\n // Set the target attempt count.\n this.setTargetAttemptCount(options);\n }\n\n // Do a check to see if we can attempt. If we can then this node will move into the 'RUNNING' state.\n // If we cannot attempt then we have hit our target attempt count, which means that the node has succeeded.\n if (this.canAttempt()) {\n // This node is in the running state and can do its initial attempt.\n this.setState(State.RUNNING);\n\n // We may have already completed an attempt, meaning that the child node will be in the FAILED state.\n // If this is the case then we will have to reset the child node now.\n if (this.child.getState() === State.FAILED) {\n this.child.reset();\n }\n\n // Update the child of this node.\n this.child.update(agent, options);\n\n // If the child moved into the SUCCEEDED state when we updated it then there is nothing left to do and this node has also succeeded.\n // If it has moved into the FAILED state then we have completed the current attempt.\n if (this.child.getState() === State.SUCCEEDED) {\n // The child has succeeded, meaning that this node has succeeded.\n this.setState(State.SUCCEEDED);\n\n return;\n } else if (this.child.getState() === State.FAILED) {\n // We have completed an attempt.\n this.currentAttemptCount += 1;\n }\n } else {\n // This node is in the 'FAILED' state as we cannot iterate any more.\n this.setState(State.FAILED);\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => {\n if (this.attempts !== null) {\n return `RETRY ${this.attempts}x`;\n } else if (this.attemptsMin !== null && this.attemptsMax !== null) {\n return `RETRY ${this.attemptsMin}x-${this.attemptsMax}x`;\n } else {\n return \"RETRY\";\n }\n };\n\n /**\n * Reset the state of the node.\n */\n reset = () => {\n // Reset the state of this node.\n this.setState(State.READY);\n\n // Reset the current attempt count.\n this.currentAttemptCount = 0;\n\n // Reset the child node.\n this.child.reset();\n };\n\n /**\n * Gets whether an attempt can be made.\n * @returns Whether an attempt can be made.\n */\n canAttempt = () => {\n if (this.targetAttemptCount !== null) {\n // We can attempt as long as we have not reached our target attempt count.\n return this.currentAttemptCount < this.targetAttemptCount;\n }\n\n // If neither an attempt count or a condition function were defined then we can attempt indefinitely.\n return true;\n };\n\n /**\n * Sets the target attempt count.\n * @param options The behaviour tree options object.\n */\n setTargetAttemptCount = (options: BehaviourTreeOptions) => {\n // Are we dealing with an explicit attempt count or will we be randomly picking an attempt count between the min and max attempt count.\n if (this.attempts !== null) {\n this.targetAttemptCount = this.attempts;\n } else if (this.attemptsMin !== null && this.attemptsMax !== null) {\n // We will be picking a random attempt count between a min and max attempt count, if the optional 'random'\n // behaviour tree function option is defined then we will be using that, otherwise we will fall back to using Math.random.\n const random = typeof options.random === \"function\" ? options.random : Math.random;\n\n // Pick a random attempt count between a min and max attempt count.\n this.targetAttemptCount = Math.floor(\n random() * (this.attemptsMax - this.attemptsMin + 1) + this.attemptsMin\n );\n } else {\n this.targetAttemptCount = null;\n }\n };\n}\n", "import Node from \"../Node\";\nimport Decorator from \"./Decorator\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A Root node.\n * The root node will have a single child.\n */\nexport default class Root extends Decorator {\n /**\n * @param attributes The node attributes.\n * @param child The child node.\n */\n constructor(attributes: Attribute[], child: Node) {\n super(\"root\", attributes, child);\n }\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // If the child has never been updated or is running then we will need to update it now.\n if (this.child.getState() === State.READY || this.child.getState() === State.RUNNING) {\n // Update the child of this node.\n this.child.update(agent, options);\n }\n\n // The state of the root node is the state of its child.\n this.setState(this.child.getState());\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => \"ROOT\";\n}\n", "import Node from \"../Node\";\nimport Decorator from \"./Decorator\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A Succeed node.\n * This node wraps a single child and will always move to the 'SUCCEEDED' state when the child moves to a 'SUCCEEDED' or 'FAILED' state.\n */\nexport default class Succeed extends Decorator {\n /**\n * @param attributes The node attributes.\n * @param child The child node.\n */\n constructor(attributes: Attribute[], child: Node) {\n super(\"succeed\", attributes, child);\n }\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // If the child has never been updated or is running then we will need to update it now.\n if (this.child.getState() === State.READY || this.child.getState() === State.RUNNING) {\n this.child.update(agent, options);\n }\n\n // The state of this node will depend in the state of its child.\n switch (this.child.getState()) {\n case State.RUNNING:\n this.setState(State.RUNNING);\n break;\n\n case State.SUCCEEDED:\n case State.FAILED:\n this.setState(State.SUCCEEDED);\n break;\n\n default:\n this.setState(State.READY);\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => \"SUCCEED\";\n}\n", "import Node from \"../Node\";\n\n/**\n * A leaf node.\n */\nexport default abstract class Leaf extends Node {\n /**\n * Gets whether this node is a leaf node.\n */\n isLeafNode = () => true;\n}\n", "import { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\nimport State, { CompleteState } from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Leaf from \"./Leaf\";\nimport Lookup from \"../../Lookup\";\nimport Attribute from \"../../attributes/Attribute\";\n\n/**\n * An Action leaf node.\n * This represents an immediate or ongoing state of behaviour.\n */\nexport default class Action extends Leaf {\n /**\n * @param attributes The node attributes.\n * @param actionName The action name.\n * @param actionArguments The array of action argument definitions.\n */\n constructor(attributes: Attribute[], private actionName: string, private actionArguments: any[]) {\n super(\"action\", attributes, actionArguments);\n }\n\n /**\n * Whether there is a pending update promise.\n */\n private isUsingUpdatePromise = false;\n\n /**\n * The finished state result of an update promise.\n */\n private updatePromiseStateResult: CompleteState | null = null;\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // If the result of this action depends on an update promise then there is nothing to do until\n // it resolves, unless there has been a value set as a result of the update promise resolving.\n if (this.isUsingUpdatePromise) {\n // Check whether the update promise has resolved with a state value.\n if (this.updatePromiseStateResult) {\n // Set the state of this node to match the state returned by the promise.\n this.setState(this.updatePromiseStateResult);\n }\n\n return;\n }\n\n // Attempt to get the invoker for the action function.\n const actionFuncInvoker = Lookup.getFuncInvoker(agent, this.actionName);\n\n // The action function should be defined.\n if (actionFuncInvoker === null) {\n throw new Error(\n `cannot update action node as the action '${this.actionName}' function is not defined on the agent and has not been registered`\n );\n }\n\n // Call the action function, the result of which may be:\n // - The finished state of this action node.\n // - A promise to return a finished node state.\n // - Undefined if the node should remain in the running state.\n const updateResult = actionFuncInvoker(this.actionArguments) as CompleteState | Promise;\n\n if (updateResult instanceof Promise) {\n updateResult.then(\n (result) => {\n // If 'isUpdatePromisePending' is null then the promise was cleared as it was resolving, probably via an abort of reset.\n if (!this.isUsingUpdatePromise) {\n return;\n }\n\n // Check to make sure the result is a valid finished state.\n if (result !== State.SUCCEEDED && result !== State.FAILED) {\n throw new Error(\n \"action node promise resolved with an invalid value, expected a State.SUCCEEDED or State.FAILED value to be returned\"\n );\n }\n\n // Set pending update promise state result to be processed on next update.\n this.updatePromiseStateResult = result;\n },\n (reason) => {\n // If 'isUpdatePromisePending' is null then the promise was cleared as it was resolving, probably via an abort of reset.\n if (!this.isUsingUpdatePromise) {\n return;\n }\n\n // Just throw whatever was returned as the rejection argument.\n throw new Error(reason);\n }\n );\n\n // This node will be in the 'RUNNING' state until the update promise resolves.\n this.setState(State.RUNNING);\n\n // We are now waiting for the promise returned by the use to resolve before we know what state this node is in.\n this.isUsingUpdatePromise = true;\n } else {\n // Validate the returned value.\n this.validateUpdateResult(updateResult);\n\n // Set the state of this node, this may be undefined, which just means that the node is still in the 'RUNNING' state.\n this.setState(updateResult || State.RUNNING);\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => this.actionName;\n\n /**\n * Reset the state of the node.\n */\n reset = () => {\n // Reset the state of this node.\n this.setState(State.READY);\n\n // There is no longer an update promise that we care about.\n this.isUsingUpdatePromise = false;\n this.updatePromiseStateResult = null;\n };\n\n /**\n * Validate the result of an update function call.\n * @param result The result of an update function call.\n */\n private validateUpdateResult = (result: CompleteState | boolean) => {\n switch (result) {\n case State.SUCCEEDED:\n case State.FAILED:\n case undefined:\n return;\n default:\n throw new Error(\n `action '${this.actionName}' 'onUpdate' returned an invalid response, expected an optional State.SUCCEEDED or State.FAILED value to be returned`\n );\n }\n };\n}\n", "import { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Leaf from \"./Leaf\";\nimport Lookup from \"../../Lookup\";\nimport Attribute from \"../../attributes/Attribute\";\n\n/**\n * A Condition leaf node.\n * This will succeed or fail immediately based on an agent predicate, without moving to the 'RUNNING' state.\n */\nexport default class Condition extends Leaf {\n /**\n * @param attributes The node attributes.\n * @param conditionName The name of the condition function.\n * @param conditionArguments The array of condition argument definitions.\n */\n constructor(attributes: Attribute[], private conditionName: string, private conditionArguments: any[]) {\n super(\"condition\", attributes, conditionArguments);\n }\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // Attempt to get the invoker for the condition function.\n const conditionFuncInvoker = Lookup.getFuncInvoker(agent, this.conditionName);\n\n // The condition function should be defined.\n if (conditionFuncInvoker === null) {\n throw new Error(\n `cannot update condition node as the condition '${this.conditionName}' function is not defined on the agent and has not been registered`\n );\n }\n\n // Call the condition function to determine the state of this node.\n this.setState(!!conditionFuncInvoker(this.conditionArguments) ? State.SUCCEEDED : State.FAILED);\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => this.conditionName;\n}\n", "import Leaf from \"./Leaf\";\nimport State from \"../../State\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { Agent } from \"../../Agent\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A WAIT node.\n * The state of this node will change to SUCCEEDED after a duration of time\n */\nexport default class Wait extends Leaf {\n /**\n * @param attributes The node attributes.\n * @param duration The duration that this node will wait to succeed in milliseconds.\n * @param durationMin The minimum possible duration in milliseconds that this node will wait to succeed.\n * @param durationMax The maximum possible duration in milliseconds that this node will wait to succeed.\n */\n constructor(\n attributes: Attribute[],\n private duration: number | null,\n private durationMin: number | null,\n private durationMax: number | null\n ) {\n super(\"wait\", attributes, []);\n }\n\n /**\n * The time in milliseconds at which this node was first updated.\n */\n private initialUpdateTime: number = 0;\n\n /**\n * The total duration in milliseconds that this node will be waiting for.\n */\n private totalDuration: number | null = null;\n\n /**\n * The duration in milliseconds that this node has been waiting for.\n */\n private waitedDuration: number = 0;\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // If this node is in the READY state then we need to set the initial update time.\n if (this.is(State.READY)) {\n // Set the initial update time.\n this.initialUpdateTime = new Date().getTime();\n\n // Set the initial waited duration.\n this.waitedDuration = 0;\n\n // Are we dealing with an explicit duration or will we be randomly picking a duration between the min and max duration.\n if (this.duration !== null) {\n this.totalDuration = this.duration;\n } else if (this.durationMin !== null && this.durationMax !== null) {\n // We will be picking a random duration between a min and max duration, if the optional 'random' behaviour tree\n // function option is defined then we will be using that, otherwise we will fall back to using Math.random.\n const random = typeof options.random === \"function\" ? options.random : Math.random;\n\n // Pick a random duration between a min and max duration.\n this.totalDuration = Math.floor(\n random() * (this.durationMax - this.durationMin + 1) + this.durationMin\n );\n } else {\n this.totalDuration = null;\n }\n\n // The node is now running until we finish waiting.\n this.setState(State.RUNNING);\n }\n\n // If we have no total duration then this wait node will wait indefinitely until it is aborted.\n if (this.totalDuration === null) {\n return;\n }\n\n // If we have a 'getDeltaTime' function defined as part of our options then we will use it to figure out how long we have waited for.\n if (typeof options.getDeltaTime === \"function\") {\n // Get the delta time.\n const deltaTime = options.getDeltaTime();\n\n // Our delta time must be a valid number and cannot be NaN.\n if (typeof deltaTime !== \"number\" || isNaN(deltaTime)) {\n throw new Error(\"The delta time must be a valid number and not NaN.\");\n }\n\n // Update the amount of time that this node has been waiting for based on the delta time.\n this.waitedDuration += deltaTime * 1000;\n } else {\n // We are not using a delta time, so we will just work out hom much time has passed since the first update.\n this.waitedDuration = new Date().getTime() - this.initialUpdateTime;\n }\n\n // Have we waited long enough?\n if (this.waitedDuration >= this.totalDuration) {\n // We have finished waiting!\n this.setState(State.SUCCEEDED);\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => {\n if (this.duration !== null) {\n return `WAIT ${this.duration}ms`;\n } else if (this.durationMin !== null && this.durationMax !== null) {\n return `WAIT ${this.durationMin}ms-${this.durationMax}ms`;\n } else {\n return \"WAIT\";\n }\n };\n}\n", "import Guard from \"./guards/Guard\";\n\nexport type AttributeDetails = {\n /** The attribute type. */\n type: string;\n\n /** The attribute arguments. */\n args: any[];\n};\n\n/**\n * A base node attribute.\n */\nexport default abstract class Attribute {\n /**\n * @param type The node attribute type.\n * @param args The array of attribute arguments.\n */\n constructor(public type: string, public args: any[]) {}\n\n /**\n * Gets the attribute details.\n */\n abstract getDetails(): TAttributeDetails;\n\n /**\n * Gets whether this attribute is a guard.\n */\n abstract isGuard: () => this is Guard;\n}\n", "import { Agent } from \"../../Agent\";\nimport Attribute, { AttributeDetails } from \"../Attribute\";\n\nexport type GuardAttributeDetails = {\n /** The name of the condition function that determines whether the guard is satisfied. */\n condition: string;\n} & AttributeDetails;\n\n/**\n * A base node guard attribute.\n */\nexport default abstract class Guard extends Attribute {\n /**\n * @param type The node attribute type.\n * @param args The array of decorator argument definitions.\n * @param condition The name of the condition function that determines whether the guard is satisfied.\n */\n constructor(type: string, args: any[], private condition: string) {\n super(type, args);\n }\n\n /**\n * Gets the name of the condition function that determines whether the guard is satisfied.\n */\n getCondition = () => this.condition;\n\n /**\n * Gets whether this attribute is a guard.\n */\n isGuard = () => true;\n\n /**\n * Gets the attribute details.\n */\n getDetails(): GuardAttributeDetails {\n return {\n type: this.type,\n args: this.args,\n condition: this.getCondition()\n };\n }\n\n /**\n * Gets whether the guard is satisfied.\n * @param agent The agent.\n * @returns Whether the guard is satisfied.\n */\n abstract isSatisfied(agent: Agent): boolean;\n}\n", "import Guard from \"./Guard\";\nimport Lookup from \"../../Lookup\";\nimport { Agent } from \"../../Agent\";\n\n/**\n * A WHILE guard which is satisfied as long as the given condition remains true.\n */\nexport default class While extends Guard {\n /**\n * @param condition The name of the condition function that determines whether the guard is satisfied.\n * @param args The array of decorator argument definitions.\n */\n constructor(condition: string, args: any[]) {\n super(\"while\", args, condition);\n }\n\n /**\n * Gets whether the guard is satisfied.\n * @param agent The agent.\n * @returns Whether the guard is satisfied.\n */\n isSatisfied = (agent: Agent) => {\n // Attempt to get the invoker for the condition function.\n const conditionFuncInvoker = Lookup.getFuncInvoker(agent, this.getCondition());\n\n // The condition function should be defined.\n if (conditionFuncInvoker === null) {\n throw new Error(\n `cannot evaluate node guard as the condition '${this.getCondition()}' function is not defined on the agent and has not been registered`\n );\n }\n\n // Call the condition function to determine whether this guard is satisfied.\n return !!conditionFuncInvoker(this.args);\n };\n}\n", "import Guard from \"./Guard\";\nimport Lookup from \"../../Lookup\";\nimport { Agent } from \"../../Agent\";\n\n/**\n * An UNTIL guard which is satisfied as long as the given condition remains false.\n */\nexport default class Until extends Guard {\n /**\n * @param condition The name of the condition function that determines whether the guard is satisfied.\n * @param args The array of decorator argument definitions.\n */\n constructor(condition: string, args: any[]) {\n super(\"until\", args, condition);\n }\n\n /**\n * Gets whether the guard is satisfied.\n * @param agent The agent.\n * @returns Whether the guard is satisfied.\n */\n isSatisfied = (agent: Agent) => {\n // Attempt to get the invoker for the condition function.\n const conditionFuncInvoker = Lookup.getFuncInvoker(agent, this.getCondition());\n\n // The condition function should be defined.\n if (conditionFuncInvoker === null) {\n throw new Error(\n `cannot evaluate node guard as the condition '${this.getCondition()}' function is not defined on the agent and has not been registered`\n );\n }\n\n // Call the condition function to determine whether this guard is satisfied.\n return !!!conditionFuncInvoker(this.args);\n };\n}\n", "import { Agent } from \"../../Agent\";\nimport Attribute, { AttributeDetails } from \"../Attribute\";\n\nexport type CallbackAttributeDetails = {\n /** The name of the agent function that is called. */\n functionName: string;\n} & AttributeDetails;\n\n/**\n * A base node callback attribute.\n */\nexport default abstract class Callback extends Attribute {\n /**\n * @param type The node attribute type.\n * @param args The array of decorator argument definitions.\n * @param functionName The name of the agent function to call.\n */\n constructor(type: string, args: any[], private functionName: string) {\n super(type, args);\n }\n\n /**\n * Gets the name of the agent function to call.\n */\n getFunctionName = () => this.functionName;\n\n /**\n * Gets whether this attribute is a guard.\n */\n isGuard = () => false;\n\n /**\n * Gets the attribute details.\n */\n getDetails(): CallbackAttributeDetails {\n return {\n type: this.type,\n args: this.args,\n functionName: this.getFunctionName()\n };\n }\n\n /**\n * Attempt to call the agent function that this callback refers to.\n * @param agent The agent.\n */\n abstract callAgentFunction: (agent: Agent, isSuccess: boolean, isAborted: boolean) => void;\n}\n", "import Callback from \"./Callback\";\nimport Lookup from \"../../Lookup\";\nimport { Agent } from \"../../Agent\";\n\n/**\n * An ENTRY callback which defines an agent function to call when the associated node is updated and moves out of running state.\n */\nexport default class Entry extends Callback {\n /**\n * @param functionName The name of the agent function to call.\n * @param args The array of callback argument definitions.\n */\n constructor(functionName: string, args: any[]) {\n super(\"entry\", args, functionName);\n }\n\n /**\n * Attempt to call the agent function that this callback refers to.\n * @param agent The agent.\n */\n callAgentFunction = (agent: Agent) => {\n // Attempt to get the invoker for the callback function.\n const callbackFuncInvoker = Lookup.getFuncInvoker(agent, this.getFunctionName());\n\n // The callback function should be defined.\n if (callbackFuncInvoker === null) {\n throw new Error(\n `cannot call entry function '${this.getFunctionName()}' as is not defined on the agent and has not been registered`\n );\n }\n\n // Call the callback function.\n callbackFuncInvoker(this.args);\n };\n}\n", "import Callback from \"./Callback\";\nimport Lookup from \"../../Lookup\";\nimport { Agent } from \"../../Agent\";\n\n/**\n * A STEP callback which defines an agent function to call when the associated node is updated.\n */\nexport default class Step extends Callback {\n /**\n * @param functionName The name of the agent function to call.\n * @param args The array of callback argument definitions.\n */\n constructor(functionName: string, args: any[]) {\n super(\"step\", args, functionName);\n }\n\n /**\n * Attempt to call the agent function that this callback refers to.\n * @param agent The agent.\n */\n callAgentFunction = (agent: Agent) => {\n // Attempt to get the invoker for the callback function.\n const callbackFuncInvoker = Lookup.getFuncInvoker(agent, this.getFunctionName());\n\n // The callback function should be defined.\n if (callbackFuncInvoker === null) {\n throw new Error(\n `cannot call step function '${this.getFunctionName()}' as is not defined on the agent and has not been registered`\n );\n }\n\n // Call the callback function.\n callbackFuncInvoker(this.args);\n };\n}\n", "import Callback from \"./Callback\";\nimport Lookup from \"../../Lookup\";\nimport { Agent } from \"../../Agent\";\n\n/**\n * An EXIT callback which defines an agent function to call when the associated node is updated and moves to a finished state or is aborted.\n */\nexport default class Exit extends Callback {\n /**\n * @param functionName The name of the agent function to call.\n * @param args The array of callback argument definitions.\n */\n constructor(functionName: string, args: any[]) {\n super(\"exit\", args, functionName);\n }\n\n /**\n * Attempt to call the agent function that this callback refers to.\n * @param agent The agent.\n * @param isSuccess Whether the decorated node was left with a success state.\n * @param isAborted Whether the decorated node was aborted.\n */\n callAgentFunction = (agent: Agent, isSuccess: boolean, isAborted: boolean) => {\n // Attempt to get the invoker for the callback function.\n const callbackFuncInvoker = Lookup.getFuncInvoker(agent, this.getFunctionName());\n\n // The callback function should be defined.\n if (callbackFuncInvoker === null) {\n throw new Error(\n `cannot call exit function '${this.getFunctionName()}' as is not defined on the agent and has not been registered`\n );\n }\n\n // Call the callback function\n callbackFuncInvoker([{ value: { succeeded: isSuccess, aborted: isAborted } }, ...this.args]);\n };\n}\n", "import { AnyNodeDefinition, RootNodeDefinition } from \"./BehaviourTreeDefinition\";\nimport GuardPath, { GuardPathPart } from \"./attributes/guards/GuardPath\";\nimport { validateBranchSubtreeLinks } from \"./BehaviourTreeDefinitionValidator\";\nimport { isInteger } from \"./BehaviourTreeDefinitionUtilities\";\nimport Node from \"./nodes/Node\";\nimport Composite from \"./nodes/composite/Composite\";\nimport Decorator from \"./nodes/decorator/Decorator\";\nimport Parallel from \"./nodes/composite/Parallel\";\nimport Selector from \"./nodes/composite/Selector\";\nimport Sequence from \"./nodes/composite/Sequence\";\nimport Lotto from \"./nodes/composite/Lotto\";\nimport Fail from \"./nodes/decorator/Fail\";\nimport Flip from \"./nodes/decorator/Flip\";\nimport Repeat from \"./nodes/decorator/Repeat\";\nimport Retry from \"./nodes/decorator/Retry\";\nimport Root from \"./nodes/decorator/Root\";\nimport Succeed from \"./nodes/decorator/Succeed\";\nimport Action from \"./nodes/leaf/Action\";\nimport Condition from \"./nodes/leaf/Condition\";\nimport Wait from \"./nodes/leaf/Wait\";\nimport Lookup from \"./Lookup\";\nimport Attribute from \"./attributes/Attribute\";\nimport While from \"./attributes/guards/While\";\nimport Until from \"./attributes/guards/Until\";\nimport Entry from \"./attributes/callbacks/Entry\";\nimport Step from \"./attributes/callbacks/Step\";\nimport Exit from \"./attributes/callbacks/Exit\";\n\n/**\n * A type representing any node instance in a behaviour tree.\n */\ntype AnyNode =\n | Root\n | Action\n | Condition\n | Wait\n | Sequence\n | Selector\n | Lotto\n | Parallel\n | Repeat\n | Retry\n | Flip\n | Succeed\n | Fail;\n\n/**\n * A type defining a mapping of root node identifiers to root node definitions.\n */\ntype RootNodeDefinitionMap = { [key: string | symbol]: RootNodeDefinition };\n\n/**\n * A symbol to use as the main root key in any root node mappings.\n */\nconst MAIN_ROOT_NODE_KEY = Symbol(\"__root__\");\n\n/**\n * Build and populate the root nodes based on the provided definition, assuming that the definition has been validated.\n * @param definition The root node definitions.\n * @returns The built and populated root node definitions.\n */\nexport default function buildRootNode(definition: RootNodeDefinition[]): Root {\n // Create a mapping of root node identifers to root node definitions, including globally registered subtree root node definitions.\n const rootNodeDefinitionMap = createRootNodeDefinitionMap(definition);\n\n // Now that we have all of our root node definitons (those part of the tree definition and those globally\n // registered) we should validate the definition. This will also double-check that we dont have any circular\n // dependencies in our branch -> subtree references and that we have no broken branch -> subtree links.\n validateBranchSubtreeLinks(definition, true);\n\n // Create our populated tree of node instances, starting with our main root node.\n const rootNode = nodeFactory(rootNodeDefinitionMap[MAIN_ROOT_NODE_KEY], rootNodeDefinitionMap) as Root;\n\n // Set a guard path on every leaf of the tree to evaluate as part of each update.\n applyLeafNodeGuardPaths(rootNode);\n\n // We only need to return the main root node.\n return rootNode;\n}\n\n/**\n * A factory function which creates a node instance based on the specified definition.\n * @param definition The node definition.\n * @param rootNodeDefinitionMap The mapping of root node identifers to root node definitions, including globally registered subtree root node definitions.\n * @returns A node instance based on the specified definition.\n */\nfunction nodeFactory(definition: AnyNodeDefinition, rootNodeDefinitionMap: RootNodeDefinitionMap): AnyNode {\n // Get the attributes for the node.\n const attributes = nodeAttributesFactory(definition);\n\n // Create the node instance based on the definition type.\n switch (definition.type) {\n case \"root\":\n return new Root(attributes, nodeFactory(definition.child, rootNodeDefinitionMap));\n\n case \"repeat\":\n let iterations: number | null = null;\n let iterationsMin: number | null = null;\n let iterationsMax: number | null = null;\n\n if (Array.isArray(definition.iterations)) {\n iterationsMin = definition.iterations[0];\n iterationsMax = definition.iterations[1];\n } else if (isInteger(definition.iterations)) {\n iterations = definition.iterations!;\n }\n\n return new Repeat(\n attributes,\n iterations,\n iterationsMin,\n iterationsMax,\n nodeFactory(definition.child, rootNodeDefinitionMap)\n );\n\n case \"retry\":\n let attempts: number | null = null;\n let attemptsMin: number | null = null;\n let attemptsMax: number | null = null;\n\n if (Array.isArray(definition.attempts)) {\n attemptsMin = definition.attempts[0];\n attemptsMax = definition.attempts[1];\n } else if (isInteger(definition.attempts)) {\n attempts = definition.attempts!;\n }\n\n return new Retry(\n attributes,\n attempts,\n attemptsMin,\n attemptsMax,\n nodeFactory(definition.child, rootNodeDefinitionMap)\n );\n\n case \"flip\":\n return new Flip(attributes, nodeFactory(definition.child, rootNodeDefinitionMap));\n\n case \"succeed\":\n return new Succeed(attributes, nodeFactory(definition.child, rootNodeDefinitionMap));\n\n case \"fail\":\n return new Fail(attributes, nodeFactory(definition.child, rootNodeDefinitionMap));\n\n case \"sequence\":\n return new Sequence(\n attributes,\n definition.children.map((child) => nodeFactory(child, rootNodeDefinitionMap))\n );\n\n case \"selector\":\n return new Selector(\n attributes,\n definition.children.map((child) => nodeFactory(child, rootNodeDefinitionMap))\n );\n\n case \"parallel\":\n return new Parallel(\n attributes,\n definition.children.map((child) => nodeFactory(child, rootNodeDefinitionMap))\n );\n\n case \"lotto\":\n return new Lotto(\n attributes,\n definition.weights,\n definition.children.map((child) => nodeFactory(child, rootNodeDefinitionMap))\n );\n\n case \"branch\":\n return nodeFactory(rootNodeDefinitionMap[definition.ref].child, rootNodeDefinitionMap);\n\n case \"action\":\n return new Action(attributes, definition.call, definition.args || []);\n\n case \"condition\":\n return new Condition(attributes, definition.call, definition.args || []);\n\n case \"wait\":\n let duration: number | null = null;\n let durationMin: number | null = null;\n let durationMax: number | null = null;\n\n if (Array.isArray(definition.duration)) {\n durationMin = definition.duration[0];\n durationMax = definition.duration[1];\n } else if (isInteger(definition.duration)) {\n duration = definition.duration!;\n }\n\n return new Wait(attributes, duration, durationMin, durationMax);\n }\n}\n\n/**\n * Creates an array of node attribute instances based on the specified node definition.\n * @param definition The node definition.\n * @returns An array of node attribute instances based on the specified node definition.\n */\nfunction nodeAttributesFactory(definition: AnyNodeDefinition): Attribute[] {\n const attributes: Attribute[] = [];\n\n if (definition.while) {\n attributes.push(new While(definition.while.call, definition.while.args ?? []));\n }\n\n if (definition.until) {\n attributes.push(new Until(definition.until.call, definition.until.args ?? []));\n }\n\n if (definition.entry) {\n attributes.push(new Entry(definition.entry.call, definition.entry.args ?? []));\n }\n\n if (definition.step) {\n attributes.push(new Step(definition.step.call, definition.step.args ?? []));\n }\n\n if (definition.exit) {\n attributes.push(new Exit(definition.exit.call, definition.exit.args ?? []));\n }\n\n return attributes;\n}\n\n/**\n * Creates a mapping of root node identifers to root node definitions, mixing in globally registered subtree root node definitions.\n * @param definition The root node definitions.\n * @returns A mapping of root node identifers to root node definitions, including globally registered subtree root node definitions.\n */\nfunction createRootNodeDefinitionMap(definition: RootNodeDefinition[]): RootNodeDefinitionMap {\n // Create a mapping of root node identifers to root node definitions.\n const rootNodeMap: RootNodeDefinitionMap = {};\n\n // Add in any registered subtree root node definitions.\n for (const [name, rootNodeDefinition] of Object.entries(Lookup.getSubtrees())) {\n // The name used when registering the subtree will be used as the root node identifier.\n rootNodeMap[name] = { ...rootNodeDefinition, id: name };\n }\n\n // Populate the map with the root node definitions that were included with the tree definition.\n // We do this after adding any registered subtrees as we want these to take presedence.\n for (const rootNodeDefinition of definition) {\n rootNodeMap[rootNodeDefinition.id ?? MAIN_ROOT_NODE_KEY] = rootNodeDefinition;\n }\n\n return rootNodeMap;\n}\n\n/**\n * Applies a guard path to every leaf of the tree to evaluate as part of each update.\n * @param root The main root tree node.\n */\nfunction applyLeafNodeGuardPaths(root: Root) {\n const nodePaths: Node[][] = [];\n\n const findLeafNodes = (path: Node[], node: Node) => {\n // Add the current node to the path.\n path = path.concat(node);\n\n // Check whether the current node is a leaf node.\n if (node.isLeafNode()) {\n nodePaths.push(path);\n } else {\n (node as Composite | Decorator).getChildren().forEach((child) => findLeafNodes(path, child));\n }\n };\n\n // Find all leaf node paths, starting from the root.\n findLeafNodes([], root);\n\n nodePaths.forEach((path) => {\n // Each node in the current path will have to be assigned a guard path, working from the root outwards.\n for (let depth = 0; depth < path.length; depth++) {\n // Get the node in the path at the current depth.\n const currentNode = path[depth];\n\n // The node may already have been assigned a guard path, if so just skip it.\n if (currentNode.hasGuardPath()) {\n continue;\n }\n\n // Create the guard path for the current node.\n const guardPath = new GuardPath(\n path\n .slice(0, depth + 1)\n .map((node) => ({ node, guards: node.getGuardAttributes() }))\n .filter((details) => details.guards.length > 0)\n );\n\n // Assign the guard path to the current node.\n currentNode.setGuardPath(guardPath);\n }\n });\n}\n", "import State, { AnyState } from \"./State\";\nimport Lookup from \"./Lookup\";\nimport Node from \"./nodes/Node\";\nimport Root from \"./nodes/decorator/Root\";\nimport Composite from \"./nodes/composite/Composite\";\nimport Decorator from \"./nodes/decorator/Decorator\";\nimport { Agent, GlobalFunction } from \"./Agent\";\nimport { CallbackAttributeDetails } from \"./attributes/callbacks/Callback\";\nimport { GuardAttributeDetails } from \"./attributes/guards/Guard\";\nimport { BehaviourTreeOptions } from \"./BehaviourTreeOptions\";\nimport { convertMDSLToJSON } from \"./mdsl/MDSLDefinitionParser\";\nimport { RootNodeDefinition } from \"./BehaviourTreeDefinition\";\nimport { validateDefinition, validateJSONDefinition } from \"./BehaviourTreeDefinitionValidator\";\nimport buildRootNode from \"./BehaviourTreeBuilder\";\nimport { isNullOrUndefined } from \"./BehaviourTreeDefinitionUtilities\";\n\n// Purely for outside inspection of the tree.\nexport type FlattenedTreeNode = {\n id: string;\n type: string;\n caption: string;\n state: AnyState;\n guards: GuardAttributeDetails[];\n callbacks: CallbackAttributeDetails[];\n args: any[];\n parentId: string | null;\n};\n\n/**\n * A representation of a behaviour tree.\n */\nexport class BehaviourTree {\n /**\n * The main root tree node.\n */\n private readonly _rootNode: Root;\n\n /**\n * Creates a new instance of the BehaviourTree class.\n * @param definition The behaviour tree definition as either an MDSL string, root node definition object or array of root node definition objects.\n * @param agent The agent instance that this behaviour tree is modelling behaviour for.\n * @param options The behaviour tree options object.\n */\n constructor(\n definition: string | RootNodeDefinition | RootNodeDefinition[],\n private agent: Agent,\n private options: BehaviourTreeOptions = {}\n ) {\n // The tree definition must be defined.\n if (isNullOrUndefined(definition)) {\n throw new Error(\"tree definition not defined\");\n }\n\n // The agent must be defined and not null.\n if (typeof agent !== \"object\" || agent === null) {\n throw new Error(\"the agent must be an object and not null\");\n }\n\n // We should validate the definition before we try to build the tree nodes.\n const { succeeded, errorMessage, json } = validateDefinition(definition);\n\n // Did our validation fail without error?\n if (!succeeded) {\n throw new Error(`invalid definition: ${errorMessage}`);\n }\n\n // Double check that we did actually get our json definition as part of our definition validtion.\n if (!json) {\n throw new Error(\n \"expected json definition to be returned as part of successful definition validation response\"\n );\n }\n\n try {\n // Create the populated tree of behaviour tree nodes and get the root node.\n this._rootNode = buildRootNode(json);\n } catch (exception) {\n // There was an issue in trying build and populate the behaviour tree.\n throw new Error(`error building tree: ${(exception as Error).message}`);\n }\n }\n\n /**\n * Gets whether the tree is in the RUNNING state.\n * @returns true if the tree is in the RUNNING state, otherwise false.\n */\n isRunning() {\n return this._rootNode.getState() === State.RUNNING;\n }\n\n /**\n * Gets the current tree state of SUCCEEDED, FAILED, READY or RUNNING.\n * @returns The current tree state.\n */\n getState() {\n return this._rootNode.getState();\n }\n\n /**\n * Step the tree.\n * 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.\n * 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\n * 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.\n *\n * 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.\n */\n step() {\n // If the root node has already been stepped to completion then we need to reset it.\n if (this._rootNode.getState() === State.SUCCEEDED || this._rootNode.getState() === State.FAILED) {\n this._rootNode.reset();\n }\n\n try {\n this._rootNode.update(this.agent, this.options);\n } catch (exception) {\n throw new Error(`error stepping tree: ${(exception as Error).message}`);\n }\n }\n\n /**\n * Resets the tree from the root node outwards to each nested node, giving each a state of READY.\n */\n reset() {\n this._rootNode.reset();\n }\n\n /**\n * Gets the flattened details of every node in the tree.\n * @returns The flattened details of every node in the tree.\n */\n getFlattenedNodeDetails(): FlattenedTreeNode[] {\n // Create an empty flattened array of tree nodes.\n const flattenedTreeNodes: FlattenedTreeNode[] = [];\n\n /**\n * Helper function to process a node instance and push details into the flattened tree nodes array.\n * @param node The current node.\n * @param parentUid The UID of the node parent, or null if the node is the main root node.\n */\n const processNode = (node: Node, parentUid: string | null) => {\n // Get the guard and callback attribute details for this node.\n const guards = node\n .getAttributes()\n .filter((attribute) => attribute.isGuard())\n .map((attribute) => attribute.getDetails()) as GuardAttributeDetails[];\n const callbacks = node\n .getAttributes()\n .filter((attribute) => !attribute.isGuard())\n .map((attribute) => attribute.getDetails()) as CallbackAttributeDetails[];\n\n // Push the current node into the flattened nodes array.\n flattenedTreeNodes.push({\n id: node.getUid(),\n type: node.getType(),\n caption: node.getName(),\n state: node.getState(),\n guards,\n callbacks,\n args: node.getArguments(),\n parentId: parentUid\n });\n\n // Process each of the nodes children if it is not a leaf node.\n if (!node.isLeafNode()) {\n (node as Composite | Decorator)\n .getChildren()\n .forEach((child) => processNode(child, (node as Composite | Decorator).getUid()));\n }\n };\n\n // Convert the nested node structure into a flattened array of node details.\n processNode(this._rootNode, null);\n\n return flattenedTreeNodes;\n }\n\n /**\n * Registers the action/condition/guard/callback function or subtree with the given name.\n * @param name The name of the function or subtree to register.\n * @param value The function or subtree definition to register.\n */\n static register(name: string, value: GlobalFunction | string | RootNodeDefinition) {\n // Are we going to register a action/condition/guard/callback function?\n if (typeof value === \"function\") {\n Lookup.setFunc(name, value);\n return;\n }\n\n // We are not registering an action/condition/guard/callback function, so we must be registering a subtree.\n if (typeof value === \"string\") {\n let rootNodeDefinitions: RootNodeDefinition[];\n\n // We will assume that any string passed in will be a mdsl definition.\n try {\n rootNodeDefinitions = convertMDSLToJSON(value);\n } catch (exception) {\n throw new Error(`error registering definition, invalid MDSL: ${(exception as Error).message}`);\n }\n\n // This function should only ever be called with a definition containing a single unnamed root node.\n if (rootNodeDefinitions.length != 1 || rootNodeDefinitions[0].id !== null) {\n throw new Error(\"error registering definition: expected a single unnamed root node\");\n }\n\n try {\n // We should validate the subtree as we don't want invalid subtrees available via the lookup.\n const { succeeded, errorMessage } = validateJSONDefinition(rootNodeDefinitions[0]);\n\n // Did our validation fail without error?\n if (!succeeded) {\n throw new Error(errorMessage);\n }\n } catch (exception) {\n throw new Error(`error registering definition: ${(exception as Error).message}`);\n }\n\n // Everything seems hunky-dory, register the subtree.\n Lookup.setSubtree(name, rootNodeDefinitions[0]);\n } else if (typeof value === \"object\" && !Array.isArray(value)) {\n // We will assume that any object passed in is a root node definition.\n\n try {\n // We should validate the subtree as we don't want invalid subtrees available via the lookup.\n const { succeeded, errorMessage } = validateJSONDefinition(value);\n\n // Did our validation fail without error?\n if (!succeeded) {\n throw new Error(errorMessage);\n }\n } catch (exception) {\n throw new Error(`error registering definition: ${(exception as Error).message}`);\n }\n\n // Everything seems hunky-dory, register the subtree.\n Lookup.setSubtree(name, value);\n } else {\n throw new Error(\"unexpected value, expected string mdsl definition, root node json definition or function\");\n }\n }\n\n /**\n * Unregisters the registered action/condition/guard/callback function or subtree with the given name.\n * @param name The name of the registered action/condition/guard/callback function or subtree to unregister.\n */\n static unregister(name: string): void {\n Lookup.remove(name);\n }\n\n /**\n * Unregister all registered action/condition/guard/callback functions and subtrees.\n */\n static unregisterAll(): void {\n Lookup.empty();\n }\n}\n"], - "mappings": "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", + "sourcesContent": ["\"use strict\";\r\nObject.defineProperty(exports, \"__esModule\", { value: true });\r\nexports.Participant = void 0;\r\n/**\r\n * A participant that holds a number of tickets.\r\n */\r\nvar Participant = /** @class */ (function () {\r\n /**\r\n * Creates an instance of the Participant class.\r\n * @param participant The actual participant.\r\n * @param tickets The number of tickets held by the participant.\r\n */\r\n function Participant(participant, tickets) {\r\n if (tickets === void 0) { tickets = 1; }\r\n this._participant = participant;\r\n this._tickets = tickets;\r\n }\r\n Object.defineProperty(Participant.prototype, \"participant\", {\r\n /** Gets the actual participant. */\r\n get: function () {\r\n return this._participant;\r\n },\r\n enumerable: false,\r\n configurable: true\r\n });\r\n Object.defineProperty(Participant.prototype, \"tickets\", {\r\n /** Gets or sets the number of tickets held by the participant. */\r\n get: function () {\r\n return this._tickets;\r\n },\r\n set: function (value) {\r\n this._tickets = value;\r\n },\r\n enumerable: false,\r\n configurable: true\r\n });\r\n return Participant;\r\n}());\r\nexports.Participant = Participant;\r\n", "\"use strict\";\r\nObject.defineProperty(exports, \"__esModule\", { value: true });\r\nexports.isNaturalNumber = exports.isNullOrUndefined = void 0;\r\n/**\r\n * Gets whether the value provided is null or undefined.\r\n * @param value The value to check.\r\n * @returns Whether the value provided is null or undefined.\r\n */\r\nfunction isNullOrUndefined(value) {\r\n return value === null || value === undefined;\r\n}\r\nexports.isNullOrUndefined = isNullOrUndefined;\r\n/**\r\n * Gets whether the value provided is a natural number.\r\n * @param value The value to check.\r\n * @returns Whether the value provided is a natural number.\r\n */\r\nfunction isNaturalNumber(value) {\r\n return typeof value === \"number\" && value >= 1 && Math.floor(value) === value;\r\n}\r\nexports.isNaturalNumber = isNaturalNumber;\r\n", "\"use strict\";\r\nObject.defineProperty(exports, \"__esModule\", { value: true });\r\nexports.Lotto = void 0;\r\nvar Participant_1 = require(\"./Participant\");\r\nvar Utilities_1 = require(\"./Utilities\");\r\n/**\r\n * Represents a lotto consisting of a number of pickable ticket-holding participants.\r\n */\r\nvar Lotto = /** @class */ (function () {\r\n /**\r\n * Creates a new instance of Lotto.\r\n * @param customRandom The custom RNG to use in place of Math.random().\r\n */\r\n function Lotto(customRandom) {\r\n /** The array of participants that are holding tickets in the lotto. */\r\n this._participants = [];\r\n this._customRandom = customRandom;\r\n }\r\n /**\r\n * Adds a participant with the specified number of tickets, or adds to the participant ticket count if the participant already holds tickets.\r\n * @param participant The participant to add or to increase the ticket count for if they already hold tickets.\r\n * @param tickets The number of tickets, defaults to 1.\r\n * @returns The Lotto instance.\r\n */\r\n Lotto.prototype.add = function (participant, tickets) {\r\n if (tickets === void 0) { tickets = 1; }\r\n // Check that we have a valid ticket count.\r\n if (!(0, Utilities_1.isNaturalNumber)(tickets)) {\r\n throw new Error(\"tickets value must be a natural number\");\r\n }\r\n // Check whether this participant has already been added.\r\n var existingParticipant = this._participants.find(function (part) { return part.participant === participant; });\r\n if (existingParticipant) {\r\n // The participant has already been added to the lotto so just add to their ticket count.\r\n existingParticipant.tickets += tickets;\r\n }\r\n else {\r\n // The participant is not part of the lotto so we should add them.\r\n this._participants.push(new Participant_1.Participant(participant, tickets));\r\n }\r\n return this;\r\n };\r\n /**\r\n * Removes the specified number of tickets for the given participant from the draw, or all tickets if a ticket number is not defined.\r\n * @param participant The participant to remove tickets for.\r\n * @param tickets The number of tickets to remove, or undefined if all tickets are to be removed.\r\n * @returns The Lotto instance.\r\n */\r\n Lotto.prototype.remove = function (participant, tickets) {\r\n // Attempt to get the existing participant.\r\n var existingParticipant = this._participants.find(function (part) { return part.participant === participant; });\r\n // There is nothing to do if the specified participant isn't even part of the lotto.\r\n if (!existingParticipant) {\r\n return this;\r\n }\r\n // Check whether a tickets value was given.\r\n if (tickets !== undefined) {\r\n // Check that we have a valid ticket count.\r\n if (!(0, Utilities_1.isNaturalNumber)(tickets)) {\r\n throw new Error(\"tickets value must be a natural number\");\r\n }\r\n existingParticipant.tickets -= tickets;\r\n // If the participant no longer holds any tickets then they should be removed.\r\n if (existingParticipant.tickets < 1) {\r\n this._participants = this._participants.filter(function (part) { return part !== existingParticipant; });\r\n }\r\n }\r\n else {\r\n // We are removing all tickets for the participant so just remove them from the lotto.\r\n this._participants = this._participants.filter(function (part) { return part !== existingParticipant; });\r\n }\r\n return this;\r\n };\r\n /**\r\n * Draw a winning ticket and return the participant that holds the ticket.\r\n * @param options The draw options.\r\n * @returns The participant that holds the winning ticket.\r\n */\r\n Lotto.prototype.draw = function (options) {\r\n if (options === void 0) { options = {}; }\r\n // If we have no participants then just return null.\r\n if (this._participants.length === 0) {\r\n return null;\r\n }\r\n var redrawable = (0, Utilities_1.isNullOrUndefined)(options.redrawable) ? true : options.redrawable;\r\n var pickable = [];\r\n this._participants.forEach(function (_a) {\r\n var participant = _a.participant, tickets = _a.tickets;\r\n for (var ticketCount = 0; ticketCount < tickets; ticketCount++) {\r\n pickable.push(participant);\r\n }\r\n });\r\n var random;\r\n // We need a random floating-point number between 0 (inclusive) and 1 to scale up to pick our winner.\r\n // If a custom random function exists then we should use that or fall back to Math.random().\r\n if (this._customRandom) {\r\n // Call our custom random function to get a random floating-point number.\r\n random = this._customRandom();\r\n // Verify that the result of calling our custom random function is a number between 0 (inclusive) and 1.\r\n if (typeof random !== \"number\" || random < 0 || random >= 1) {\r\n throw new Error(\"the 'random' function provided did not return a number between 0 (inclusive) and 1\");\r\n }\r\n }\r\n else {\r\n // No custom random function was defined so just use good ol' Math.random().\r\n random = Math.random();\r\n }\r\n // Pick a winning participant.\r\n var winner = pickable[Math.floor(random * pickable.length)];\r\n // If the ticket isn't redrawable then we should remove a ticket from the winning participants ticket count.\r\n if (!redrawable) {\r\n this.remove(winner, 1);\r\n }\r\n // Return the winning participant.\r\n return winner;\r\n };\r\n /**\r\n * Draws multiple winning tickets and return an array of the participants that hold the winning tickets.\r\n * @param tickets The number of winning tickets to draw.\r\n * @param options The draw multiple options.\r\n * @returns An array of the participants that hold the winning tickets.\r\n */\r\n Lotto.prototype.drawMultiple = function (tickets, options) {\r\n if (options === void 0) { options = {}; }\r\n var uniqueResults = (0, Utilities_1.isNullOrUndefined)(options.unique) ? false : options.unique;\r\n // Handle cases where the user has asked for zero tickets (no idea why they would do this be we should trust them).\r\n if (tickets === 0) {\r\n return [];\r\n }\r\n // Now that we know out tickets value is not zero we should check that it is a valid natural number.\r\n if (!(0, Utilities_1.isNaturalNumber)(tickets)) {\r\n throw new Error(\"tickets value must be a natural number\");\r\n }\r\n var result = [];\r\n // Keep drawing tickets until we either reach the number of required tickets or we simply run out of tickets to draw.\r\n // We can run out of tickets to draw if 'options.redrawable' is explicity 'false' or we just had no participants when 'drawMultiple' was called.\r\n while (result.length < tickets && this._participants.length > 0) {\r\n result.push(this.draw(options));\r\n }\r\n // If the 'unique' draw option is set then we need to remove duplicates from the result list.\r\n if (uniqueResults) {\r\n // Create an array to store our unique results.\r\n var unique = [];\r\n // Iterate over all of our participants (with potential duplicates) and populate our array of unique values.\r\n for (var _i = 0, result_1 = result; _i < result_1.length; _i++) {\r\n var participant = result_1[_i];\r\n if (unique.indexOf(participant) === -1) {\r\n unique.push(participant);\r\n }\r\n }\r\n result = unique;\r\n }\r\n return result;\r\n };\r\n return Lotto;\r\n}());\r\nexports.Lotto = Lotto;\r\n", "\"use strict\";\r\nObject.defineProperty(exports, \"__esModule\", { value: true });\r\nexports.createLotto = void 0;\r\nvar Lotto_1 = require(\"./Lotto\");\r\n/**\r\n * A function that creates and returns a Lotto instance.\r\n * @param participantsOrOptions An array of initial participants or options relating to the creation of a Lotto instance.\r\n * @returns A new Lotto instance.\r\n */\r\nfunction createLotto(participantsOrOptions) {\r\n // If no initial participants or lotto options were provided as an argument then we can just return a new lotto instance now.\r\n if (!participantsOrOptions) {\r\n return new Lotto_1.Lotto();\r\n }\r\n // Check whether we were provided with an array of initial participants or a lotto options object.\r\n if (Array.isArray(participantsOrOptions)) {\r\n // We are dealing with a pre-defined array of participants.\r\n var participants = participantsOrOptions;\r\n var lotto_1 = new Lotto_1.Lotto();\r\n // If the lotto participants have been defined upfront then we will need to add them all to our lotto instance now.\r\n participants.forEach(function (_a) {\r\n var participant = _a[0], tokens = _a[1];\r\n return lotto_1.add(participant, tokens);\r\n });\r\n // Return the Lotto instance.\r\n return lotto_1;\r\n }\r\n else {\r\n // We are dealing with some lotto options.\r\n var random = participantsOrOptions.random, participants = participantsOrOptions.participants;\r\n // Create a Lotto instance passing the custom RNG function to use in place of Math.random() (which could be undefined).\r\n var lotto_2 = new Lotto_1.Lotto(random);\r\n // If the lotto participants have been defined upfront as part of the options then we will need to add them all to our lotto instance now.\r\n if (participants) {\r\n participants.forEach(function (_a) {\r\n var participant = _a[0], tokens = _a[1];\r\n return lotto_2.add(participant, tokens);\r\n });\r\n }\r\n // Return the Lotto instance.\r\n return lotto_2;\r\n }\r\n}\r\nexports.createLotto = createLotto;\r\n", "\"use strict\";\r\nObject.defineProperty(exports, \"__esModule\", { value: true });\r\nvar createLotto_1 = require(\"./createLotto\");\r\nexports.default = createLotto_1.createLotto;\r\n", "import State from \"./State\";\nimport { validateDefinition } from \"./BehaviourTreeDefinitionValidator\";\nimport { convertMDSLToJSON } from \"./mdsl/MDSLDefinitionParser\";\nimport { BehaviourTree, FlattenedTreeNode } from \"./BehaviourTree\";\nimport { BehaviourTreeOptions } from \"./BehaviourTreeOptions\";\n\nexport { BehaviourTree, State, convertMDSLToJSON, validateDefinition };\nexport type { FlattenedTreeNode, BehaviourTreeOptions };\n", "/**\n * Enumeration of node state types.\n */\nexport enum State {\n READY = \"mistreevous.ready\",\n RUNNING = \"mistreevous.running\",\n SUCCEEDED = \"mistreevous.succeeded\",\n FAILED = \"mistreevous.failed\"\n}\n\nexport { State as default };\n\nexport type CompleteState = State.SUCCEEDED | State.FAILED;\nexport type AnyState = State.READY | State.RUNNING | CompleteState;\n", "import {\n NodeDefinition,\n RootNodeDefinition,\n DecoratorNodeDefinition,\n CompositeNodeDefinition,\n AnyNodeDefinition,\n BranchNodeDefinition\n} from \"./BehaviourTreeDefinition\";\n\n/**\n * A type guard function that returns true if the specified node satisfies the RootNodeDefinition type.\n * @param node The node.\n * @returns A value of true if the specified node satisfies the RootNodeDefinition type.\n */\nexport function isRootNode(node: NodeDefinition): node is RootNodeDefinition {\n return node.type === \"root\";\n}\n\n/**\n * A type guard function that returns true if the specified node satisfies the BranchNodeDefinition type.\n * @param node The node.\n * @returns A value of true if the specified node satisfies the BranchNodeDefinition type.\n */\nexport function isBranchNode(node: NodeDefinition): node is BranchNodeDefinition {\n return node.type === \"branch\";\n}\n\n/**\n * A type guard function that returns true if the specified node satisfies the NodeDefinition type.\n * @param node The node.\n * @returns A value of true if the specified node satisfies the NodeDefinition type.\n */\nexport function isLeafNode(node: NodeDefinition): node is NodeDefinition {\n return [\"branch\", \"action\", \"condition\", \"wait\"].includes(node.type);\n}\n\n/**\n * A type guard function that returns true if the specified node satisfies the DecoratorNodeDefinition type.\n * @param node The node.\n * @returns A value of true if the specified node satisfies the DecoratorNodeDefinition type.\n */\nexport function isDecoratorNode(node: NodeDefinition): node is DecoratorNodeDefinition {\n return [\"root\", \"repeat\", \"retry\", \"flip\", \"succeed\", \"fail\"].includes(node.type);\n}\n\n/**\n * A type guard function that returns true if the specified node satisfies the CompositeNodeDefinition type.\n * @param node The node.\n * @returns A value of true if the specified node satisfies the CompositeNodeDefinition type.\n */\nexport function isCompositeNode(node: NodeDefinition): node is CompositeNodeDefinition {\n return [\"sequence\", \"selector\", \"lotto\", \"parallel\"].includes(node.type);\n}\n\n/**\n * Flatten a node definition into an array of all of its nested node definitions.\n * @param nodeDefinition The node definition to flatten.\n * @returns An array of all of nested node definitions.\n */\nexport function flattenDefinition(nodeDefinition: AnyNodeDefinition): AnyNodeDefinition[] {\n const nodes: AnyNodeDefinition[] = [];\n\n const processNode = (currentNodeDefinition: AnyNodeDefinition) => {\n nodes.push(currentNodeDefinition);\n\n if (isCompositeNode(currentNodeDefinition)) {\n currentNodeDefinition.children.forEach(processNode);\n } else if (isDecoratorNode(currentNodeDefinition)) {\n processNode(currentNodeDefinition.child);\n }\n };\n\n processNode(nodeDefinition);\n\n return nodes;\n}\n\n/**\n * Determines whether the passed value is an integer.\n * @param value The value to check.\n * @returns Whether the passed value is an integer.\n */\nexport function isInteger(value: unknown): boolean {\n return typeof value === \"number\" && Math.floor(value) === value;\n}\n\n/**\n * Determines whether the passed value is null or undefined.\n * @param value The value to check.\n * @returns Whether the passed value is null or undefined.\n */\nexport function isNullOrUndefined(value: unknown): boolean {\n return typeof value === \"undefined\" || value === null;\n}\n", "/**\n * A type defining an object that holds a reference to substitued string literals parsed from the definition.\n */\nexport type StringLiteralPlaceholders = { [key: string]: string };\n\n/**\n * Pop the next raw token from the specified array of tokens and throw an error if it wasn't the expected one.\n * @param tokens The array of tokens.\n * @param expected An optional string or array or items, one of which must match the next popped token.\n * @returns The popped token.\n */\nexport function popAndCheck(tokens: string[], expected?: string | string[]): string {\n // Get and remove the next token.\n const popped = tokens.shift();\n\n // We were expecting another token but there aren't any.\n if (popped === undefined) {\n throw new Error(\"unexpected end of definition\");\n }\n\n // Do we have an expected token/tokens array?\n if (expected != undefined) {\n // Get an array of expected values, if the popped token matches any then we are all good.\n const expectedValues = typeof expected === \"string\" ? [expected] : expected;\n\n // Check whether the popped token matches at least one of our expected items.\n var tokenMatchesExpectation = expectedValues.some((item) => popped.toUpperCase() === item.toUpperCase());\n\n // Throw an error if the popped token didn't match any of our expected items.\n if (!tokenMatchesExpectation) {\n const expectationString = expectedValues.map((item) => \"'\" + item + \"'\").join(\" or \");\n throw new Error(\"unexpected token found. Expected \" + expectationString + \" but got '\" + popped + \"'\");\n }\n }\n\n // Return the popped token.\n return popped;\n}\n\n/**\n * Swaps out any node/attribute argument string literals with placeholders.\n * @param definition The definition.\n * @returns An object containing a mapping of placeholders to original string values as well as the processed definition string.\n */\nexport function substituteStringLiterals(definition: string): {\n placeholders: StringLiteralPlaceholders;\n processedDefinition: string;\n} {\n // Create an object to hold the mapping of placeholders to original string values.\n const placeholders: StringLiteralPlaceholders = {};\n\n // Replace any string literals wrapped with double quotes in our definition with placeholders to be processed later.\n const processedDefinition = definition.replace(/\\\"(\\\\.|[^\"\\\\])*\\\"/g, (match) => {\n var strippedMatch = match.substring(1, match.length - 1);\n var placeholder = Object.keys(placeholders).find((key) => placeholders[key] === strippedMatch);\n\n // If we have no existing string literal match then create a new placeholder.\n if (!placeholder) {\n placeholder = `@@${Object.keys(placeholders).length}@@`;\n placeholders[placeholder] = strippedMatch;\n }\n\n return placeholder;\n });\n\n return { placeholders, processedDefinition };\n}\n\n/**\n * Parse the tree definition into an array of raw tokens.\n * @param definition The definition.\n * @returns An array of tokens parsed from the definition.\n */\nexport function parseTokensFromDefinition(definition: string): string[] {\n // Add some space around various important characters so that they can be plucked out easier as individual tokens.\n definition = definition.replace(/\\(/g, \" ( \");\n definition = definition.replace(/\\)/g, \" ) \");\n definition = definition.replace(/\\{/g, \" { \");\n definition = definition.replace(/\\}/g, \" } \");\n definition = definition.replace(/\\]/g, \" ] \");\n definition = definition.replace(/\\[/g, \" [ \");\n definition = definition.replace(/\\,/g, \" , \");\n\n // Split the definition into raw token form and return it.\n return definition.replace(/\\s+/g, \" \").trim().split(\" \");\n}\n", "import { StringLiteralPlaceholders, popAndCheck } from \"./MDSLUtilities\";\n\n/**\n * A type representing any node function argument.\n */\ntype Argument = {\n /**\n * The argument value.\n */\n value: T;\n /**\n * The argument type, used for validation.\n */\n type: string;\n};\n\ntype NullArgument = Argument & {\n type: \"null\";\n};\n\ntype BooleanArgument = Argument & {\n type: \"boolean\";\n};\n\ntype NumberArgument = Argument & {\n type: \"number\";\n /**\n * A flag defining whether the number argument value is a valid integer. (used for validation)\n */\n isInteger: boolean;\n};\n\ntype StringPlaceholderArgument = Argument & {\n type: \"string\";\n};\n\ntype IdentifierArgument = Argument & {\n type: \"identifier\";\n};\n\n/**\n * A type representing a reference to any node function argument.\n */\ntype AnyArgument = NullArgument | BooleanArgument | NumberArgument | StringPlaceholderArgument | IdentifierArgument;\n\n/**\n * Parse an array of argument definitions from the specified tokens array.\n * @param tokens The array tokens to parse the argument definitions from.\n * @param stringArgumentPlaceholders The mapping of string literal node argument placeholders to original values.\n * @param argumentValidator The argument validator function.\n * @param validationFailedMessage The exception message to throw if argument validation fails.\n * @returns An array of argument definitions parsed from the specified tokens array.\n */\nexport function parseArgumentTokens(\n tokens: string[],\n stringArgumentPlaceholders: StringLiteralPlaceholders\n): AnyArgument[] {\n const argumentList: AnyArgument[] = [];\n\n // If the next token is not a '[' or '(' then we have no arguments to parse.\n if (![\"[\", \"(\"].includes(tokens[0])) {\n return argumentList;\n }\n\n // Any lists of arguments will always be wrapped in '[]' for node arguments or '()' for attribute arguments.\n // We are looking for a '[' or '(' opener that wraps the argument tokens and the relevant closer.\n const closingToken = popAndCheck(tokens, [\"[\", \"(\"]) === \"[\" ? \"]\" : \")\";\n\n const argumentListTokens: string[] = [];\n\n // Grab all tokens between the '[' and ']' or '(' and ')'.\n while (tokens.length && tokens[0] !== closingToken) {\n // The next token is part of our arguments list.\n argumentListTokens.push(tokens.shift()!);\n }\n\n // Validate the order of the argument tokens. Each token must either be a ',' or a single argument that satisfies the validator.\n argumentListTokens.forEach((token, index) => {\n // Get whether this token should be an actual argument.\n const shouldBeArgumentToken = !(index & 1);\n\n // If the current token should be an actual argument then validate it, otherwise it should be a ',' token.\n if (shouldBeArgumentToken) {\n // Get the argument definition.\n const argumentDefinition = getArgumentDefinition(token, stringArgumentPlaceholders);\n\n // This is a valid argument!\n argumentList.push(argumentDefinition);\n } else {\n // The current token should be a ',' token.\n if (token !== \",\") {\n throw new Error(`invalid argument list, expected ',' or ']' but got '${token}'`);\n }\n }\n });\n\n // The arguments list should terminate with a ']' or ')' token, depending on the opener.\n popAndCheck(tokens, closingToken);\n\n // Return the arguments.\n return argumentList;\n}\n\n/**\n * Gets an argument value definition.\n * @param token The argument token.\n * @param stringArgumentPlaceholders The mapping of string literal node argument placeholders to original values.\n * @returns An argument value definition.\n */\nfunction getArgumentDefinition(token: string, stringArgumentPlaceholders: StringLiteralPlaceholders): AnyArgument {\n // Check whether the token represents a null value.\n if (token === \"null\") {\n return {\n value: null,\n type: \"null\"\n } as NullArgument;\n }\n\n // Check whether the token represents a boolean value.\n if (token === \"true\" || token === \"false\") {\n return {\n value: token === \"true\",\n type: \"boolean\"\n } as BooleanArgument;\n }\n\n // Check whether the token represents a number value.\n // TODO: Relies on broken isNaN - see MDN.\n // if (!Number.isNaN(token)) {\n if (!isNaN(token as any)) {\n return {\n value: parseFloat(token),\n isInteger: parseFloat(token) === parseInt(token, 10),\n type: \"number\"\n } as NumberArgument;\n }\n\n // Check whether the token is a placeholder (e.g. @@0@@) representing a string literal.\n if (token.match(/^@@\\d+@@$/g)) {\n return {\n value: stringArgumentPlaceholders[token].replace('\\\\\"', '\"'),\n type: \"string\"\n } as StringPlaceholderArgument;\n }\n\n // The only remaining option is that the argument value is an identifier.\n return {\n value: token,\n type: \"identifier\"\n } as IdentifierArgument;\n}\n", "import { NodeAttributeDefinition } from \"../BehaviourTreeDefinition\";\nimport { parseArgumentTokens } from \"./MDSLNodeArgumentParser\";\nimport { StringLiteralPlaceholders } from \"./MDSLUtilities\";\n\n/**\n * A type defining the attribute definitions of a node.\n */\ntype NodeAttributes = {\n while?: NodeAttributeDefinition;\n until?: NodeAttributeDefinition;\n entry?: NodeAttributeDefinition;\n exit?: NodeAttributeDefinition;\n step?: NodeAttributeDefinition;\n};\n\n/**\n * Parse any node attribute definitions from the specified tokens array.\n * @param tokens The array of remaining tokens.\n * @param stringArgumentPlaceholders The mapping of string literal node argument placeholders to original values.\n * @returns An object of attribute definitions defined by any directly following tokens.\n */\nexport function parseAttributeTokens(\n tokens: string[],\n stringArgumentPlaceholders: StringLiteralPlaceholders\n): NodeAttributes {\n const nodeAttributeNames: (keyof NodeAttributes)[] = [\"while\", \"until\", \"entry\", \"exit\", \"step\"];\n\n // Create an object to hold any attributes found.\n const attributes: NodeAttributes = {};\n\n // Try to get the name of the attribute for the next token.\n let nextAttributeName = tokens[0]?.toLowerCase() as keyof NodeAttributes;\n\n // Pull attribute tokens as well as their arguments off of the tokens stack until we have no more.\n while (nodeAttributeNames.includes(nextAttributeName)) {\n // Check to make sure that we have not already created an attribute definition of this type.\n if (attributes[nextAttributeName]) {\n throw new Error(`duplicate attribute '${tokens[0].toUpperCase()}' found for node`);\n }\n\n // Remove the attribute name token from the array of tokens.\n tokens.shift();\n\n // Grab the attribute arguments, assuming the first to be an identifier.\n const [attributeCallIdentifier, ...attributeArguments] = parseArgumentTokens(\n tokens,\n stringArgumentPlaceholders\n );\n\n // The first attribute argument has to be an identifer, this will reference an agent function.\n if (attributeCallIdentifier?.type !== \"identifier\") {\n throw new Error(\"expected agent function name identifier argument for attribute\");\n }\n\n // Any attribute arguments (other than the expected call identifier) must have a type of string, number, boolean or null.\n attributeArguments\n .filter((arg) => arg.type === \"identifier\")\n .forEach((arg) => {\n throw new Error(\n `invalid attribute argument value '${arg.value}', must be string, number, boolean or null`\n );\n });\n\n // Create the attribute definition and add it to the object of attribute definitions found.\n attributes[nextAttributeName] = {\n call: attributeCallIdentifier.value,\n args: attributeArguments.map(({ value }) => value)\n };\n\n // Try to get the next attribute name token, as there could be multiple.\n nextAttributeName = tokens[0]?.toLowerCase() as keyof NodeAttributes;\n }\n\n return attributes;\n}\n", "import {\n ActionNodeDefinition,\n AnyChildNodeDefinition,\n AnyNodeDefinition,\n BranchNodeDefinition,\n ConditionNodeDefinition,\n FailNodeDefinition,\n FlipNodeDefinition,\n LottoNodeDefinition,\n ParallelNodeDefinition,\n RepeatNodeDefinition,\n RetryNodeDefinition,\n RootNodeDefinition,\n SelectorNodeDefinition,\n SequenceNodeDefinition,\n SucceedNodeDefinition,\n WaitNodeDefinition\n} from \"../BehaviourTreeDefinition\";\nimport {\n isCompositeNode,\n isDecoratorNode,\n isLeafNode,\n isNullOrUndefined,\n isRootNode\n} from \"../BehaviourTreeDefinitionUtilities\";\nimport { parseArgumentTokens } from \"./MDSLNodeArgumentParser\";\nimport { parseAttributeTokens } from \"./MDSLNodeAttributeParser\";\nimport {\n StringLiteralPlaceholders,\n parseTokensFromDefinition,\n popAndCheck,\n substituteStringLiterals\n} from \"./MDSLUtilities\";\n\n/**\n * Convert the MDSL tree definition string into an equivalent JSON definition.\n * @param definition The tree definition string as MDSL.\n * @returns The root node JSON definitions.\n */\nexport function convertMDSLToJSON(definition: string): RootNodeDefinition[] {\n // Swap out any node/attribute argument string literals with a placeholder and get a mapping of placeholders to original values as well as the processed definition.\n const { placeholders, processedDefinition } = substituteStringLiterals(definition);\n\n // Parse our definition definition string into an array of raw tokens.\n const tokens = parseTokensFromDefinition(processedDefinition);\n\n return convertTokensToJSONDefinition(tokens, placeholders);\n}\n\n/**\n * Converts the specified tree definition tokens into a JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The root node JSON definitions.\n */\nfunction convertTokensToJSONDefinition(\n tokens: string[],\n stringLiteralPlaceholders: StringLiteralPlaceholders\n): RootNodeDefinition[] {\n // There must be at least 3 tokens for the tree definition to be valid. 'ROOT', '{' and '}'.\n if (tokens.length < 3) {\n throw new Error(\"invalid token count\");\n }\n\n // We should have a matching number of '{' and '}' tokens. If not, then there are scopes that have not been properly closed.\n if (tokens.filter((token) => token === \"{\").length !== tokens.filter((token) => token === \"}\").length) {\n throw new Error(\"scope character mismatch\");\n }\n\n // Create an array of tree stack arrays where root nodes will always be at the botton and the current composite/decorator node at the top.\n // There should be an element in this array for every root node defined and every element should be an array with a root note as the first element.\n // E.g. A definition with two root nodes defined:\n // [\n // [root, lotto, sequence],\n // [root, selector]\n // ]\n const treeStacks: [Partial, ...Partial[]][] = [];\n\n // Create an array of all root node definitions that we create.\n const rootNodes: Partial[] = [];\n\n // A helper function used to push node definitions onto the tree stack.\n const pushNode = (node: AnyNodeDefinition) => {\n // If the node is a root node then we need to create a new tree stack array with the root node at the root.\n if (isRootNode(node)) {\n // We need to double-check that this root node is not the child of another node.\n // We can do this by checking whether the top tree stack is not empty (contains an existing node)\n if (treeStacks[treeStacks.length - 1]?.length) {\n throw new Error(\"a root node cannot be the child of another node\");\n }\n\n // Add the root node definition to our array of all parsed root node definitions.\n rootNodes.push(node);\n\n // Add the root node definition to the root of a new tree stack.\n treeStacks.push([node]);\n\n return;\n }\n\n // All non-root nodes should be pushed after their root nodes so handle cases\n // where we may not have any tree stacks or our top-most tree stack is empty.\n if (!treeStacks.length || !treeStacks[treeStacks.length - 1].length) {\n throw new Error(\"expected root node at base of definition\");\n }\n\n // Get the current tree stack that we are populating.\n const topTreeStack = treeStacks[treeStacks.length - 1];\n\n // Get the top-most node in the current tree stack, this will be a composite/decorator node\n // for which we will populate its children array if composite or setting its child if a decorator.\n const topTreeStackTopNode = topTreeStack[topTreeStack.length - 1] as AnyNodeDefinition;\n\n // If the top-most node in the current root stack is a composite or decorator\n // node then the current node should be added as a child of the top-most node.\n if (isCompositeNode(topTreeStackTopNode)) {\n topTreeStackTopNode.children = topTreeStackTopNode.children || [];\n topTreeStackTopNode.children.push(node);\n } else if (isDecoratorNode(topTreeStackTopNode)) {\n // If the top node already has a child node set then throw an error as a decorator should only have a single child.\n if (topTreeStackTopNode.child) {\n throw new Error(\"a decorator node must only have a single child node\");\n }\n\n topTreeStackTopNode.child = node;\n }\n\n // If the node we are adding is also a composite or decorator node, then we should push it\n // onto the current tree stack, as subsequent nodes will be added as its child/children.\n if (!isLeafNode(node)) {\n topTreeStack.push(node);\n }\n };\n\n // A helper function used to pop the top-most node definition off of the tree stack and return it.\n const popNode = (): AnyNodeDefinition | null => {\n let poppedNode: AnyNodeDefinition | null = null;\n\n // Get the current tree stack that we are populating.\n const topTreeStack = treeStacks[treeStacks.length - 1];\n\n // Pop the top-most node in the current tree stack if there is one.\n if (topTreeStack.length) {\n poppedNode = topTreeStack.pop() as AnyNodeDefinition;\n }\n\n // We don't want any empty tree stacks in our stack of tree stacks.\n if (!topTreeStack.length) {\n treeStacks.pop();\n }\n\n return poppedNode;\n };\n\n // We should keep processing the raw tokens until we run out of them.\n while (tokens.length) {\n // Grab the next token.\n const token = tokens.shift()!;\n\n // How we create the next node depends on the current raw token value.\n switch (token.toUpperCase()) {\n case \"ROOT\": {\n pushNode(createRootNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"SUCCEED\": {\n pushNode(createSucceedNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"FAIL\": {\n pushNode(createFailNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"FLIP\": {\n pushNode(createFlipNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"REPEAT\": {\n pushNode(createRepeatNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"RETRY\": {\n pushNode(createRetryNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"SEQUENCE\": {\n pushNode(createSequenceNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"SELECTOR\": {\n pushNode(createSelectorNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"PARALLEL\": {\n pushNode(createParallelNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"LOTTO\": {\n pushNode(createLottoNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"ACTION\": {\n pushNode(createActionNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"CONDITION\": {\n pushNode(createConditionNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"WAIT\": {\n pushNode(createWaitNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"BRANCH\": {\n pushNode(createBranchNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"}\": {\n // The '}' character closes the current scope and means that we have to pop a node off of the current stack.\n const poppedNode = popNode();\n\n // Now that we have a node definition we can carry out any validation that may require the node to be fully populated.\n if (poppedNode) {\n validatePoppedNode(poppedNode);\n }\n\n break;\n }\n\n default: {\n throw new Error(`unexpected token: ${token}`);\n }\n }\n }\n\n return rootNodes as RootNodeDefinition[];\n}\n\n/**\n * Creates a root node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The root node JSON definition.\n */\nfunction createRootNode(tokens: string[], stringLiteralPlaceholders: StringLiteralPlaceholders): RootNodeDefinition {\n // Create the root node definition.\n let node = {\n type: \"root\",\n id: undefined\n } as RootNodeDefinition;\n\n // Parse any node arguments, we should only have one if any which will be an identifier argument for the root identifier.\n const nodeArguments = parseArgumentTokens(tokens, stringLiteralPlaceholders);\n\n // Check whether any node arguments were defined.\n if (nodeArguments.length) {\n // We should only have one argument, if any, which will be an identifier argument for the root identifier.\n if (nodeArguments.length === 1 && nodeArguments[0].type === \"identifier\") {\n // The root node identifier will be the first and only node argument value.\n node.id = nodeArguments[0].value as string;\n } else {\n throw new Error(\"expected single root name argument\");\n }\n }\n\n // Grab any node attribute definitions and spread them into the node definition.\n node = { ...node, ...parseAttributeTokens(tokens, stringLiteralPlaceholders) };\n\n // This is a decorator node, so we expect an opening '{'.\n popAndCheck(tokens, \"{\");\n\n // Return the root node definition.\n return node;\n}\n\n/**\n * Creates a succeed node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The succeed node JSON definition.\n */\nfunction createSucceedNode(\n tokens: string[],\n stringLiteralPlaceholders: StringLiteralPlaceholders\n): SucceedNodeDefinition {\n const node = {\n type: \"succeed\",\n ...parseAttributeTokens(tokens, stringLiteralPlaceholders)\n } as SucceedNodeDefinition;\n\n // This is a decorator node, so we expect an opening '{'.\n popAndCheck(tokens, \"{\");\n\n // Return the succeed node definition.\n return node;\n}\n\n/**\n * Creates a fail node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The fail node JSON definition.\n */\nfunction createFailNode(tokens: string[], stringLiteralPlaceholders: StringLiteralPlaceholders): FailNodeDefinition {\n const node = {\n type: \"fail\",\n ...parseAttributeTokens(tokens, stringLiteralPlaceholders)\n } as FailNodeDefinition;\n\n // This is a decorator node, so we expect an opening '{'.\n popAndCheck(tokens, \"{\");\n\n // Return the fail node definition.\n return node;\n}\n\n/**\n * Creates a flip node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The flip node JSON definition.\n */\nfunction createFlipNode(tokens: string[], stringLiteralPlaceholders: StringLiteralPlaceholders): FlipNodeDefinition {\n const node = {\n type: \"flip\",\n ...parseAttributeTokens(tokens, stringLiteralPlaceholders)\n } as FlipNodeDefinition;\n\n // This is a decorator node, so we expect an opening '{'.\n popAndCheck(tokens, \"{\");\n\n // Return the flip node definition.\n return node;\n}\n\n/**\n * Creates a repeat node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The repeat node JSON definition.\n */\nfunction createRepeatNode(\n tokens: string[],\n stringLiteralPlaceholders: StringLiteralPlaceholders\n): RepeatNodeDefinition {\n let node = { type: \"repeat\" } as RepeatNodeDefinition;\n\n // Get the node arguments.\n const nodeArguments = parseArgumentTokens(tokens, stringLiteralPlaceholders);\n\n // The arguments of a repeat node are optional. We may have:\n // - No node arguments, in which case the repeat note will iterate indefinitely.\n // - One node argument which will be the explicit number of iterations to make.\n // - Two node arguments which define the min and max iteration bounds from which a random iteration count will be picked.\n if (nodeArguments.length) {\n // All repeat node arguments MUST be of type number and must be integer.\n nodeArguments\n .filter((arg) => arg.type !== \"number\" || !arg.isInteger)\n .forEach(() => {\n throw new Error(`repeat node iteration counts must be integer values`);\n });\n\n // We should have got one or two iteration counts.\n if (nodeArguments.length === 1) {\n // A static iteration count was defined.\n node.iterations = nodeArguments[0].value as number;\n\n // A repeat node must have a positive number of iterations if defined.\n if (node.iterations < 0) {\n throw new Error(\"a repeat node must have a positive number of iterations if defined\");\n }\n } else if (nodeArguments.length === 2) {\n // A minimum and maximum iteration count was defined.\n node.iterations = [nodeArguments[0].value as number, nodeArguments[1].value as number];\n\n // A repeat node must have a positive min and max iteration count if they are defined.\n if (node.iterations[0] < 0 || node.iterations[1] < 0) {\n throw new Error(\"a repeat node must have a positive minimum and maximum iteration count if defined\");\n }\n\n // A repeat node must not have an minimum iteration count that exceeds the maximum iteration count.\n if (node.iterations[0] > node.iterations[1]) {\n throw new Error(\n \"a repeat node must not have a minimum iteration count that exceeds the maximum iteration count\"\n );\n }\n } else {\n // An incorrect number of iteration counts was defined.\n throw new Error(\"invalid number of repeat node iteration count arguments defined\");\n }\n }\n\n // Grab any node attribute definitions and spread them into the node definition.\n node = { ...node, ...parseAttributeTokens(tokens, stringLiteralPlaceholders) };\n\n // This is a decorator node, so we expect an opening '{'.\n popAndCheck(tokens, \"{\");\n\n // Return the repeat node definition.\n return node;\n}\n\n/**\n * Creates a retry node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The retry node JSON definition.\n */\nfunction createRetryNode(tokens: string[], stringLiteralPlaceholders: StringLiteralPlaceholders): RetryNodeDefinition {\n let node = { type: \"retry\" } as RetryNodeDefinition;\n\n // Get the node arguments.\n const nodeArguments = parseArgumentTokens(tokens, stringLiteralPlaceholders);\n\n // The arguments of a retry node are optional. We may have:\n // - No node arguments, in which case the retry note will attempt indefinitely.\n // - One node argument which will be the explicit number of attempts to make.\n // - Two node arguments which define the min and max attempt bounds from which a random attempt count will be picked.\n if (nodeArguments.length) {\n // All retry node arguments MUST be of type number and must be integer.\n nodeArguments\n .filter((arg) => arg.type !== \"number\" || !arg.isInteger)\n .forEach(() => {\n throw new Error(`retry node attempt counts must be integer values`);\n });\n\n // We should have got one or two attempt counts.\n if (nodeArguments.length === 1) {\n // A static attempt count was defined.\n node.attempts = nodeArguments[0].value as number;\n\n // A retry node must have a positive number of attempts if defined.\n if (node.attempts < 0) {\n throw new Error(\"a retry node must have a positive number of attempts if defined\");\n }\n } else if (nodeArguments.length === 2) {\n // A minimum and maximum attempt count was defined.\n node.attempts = [nodeArguments[0].value as number, nodeArguments[1].value as number];\n\n // A retry node must have a positive min and max attempts count if they are defined.\n if (node.attempts[0] < 0 || node.attempts[1] < 0) {\n throw new Error(\"a retry node must have a positive minimum and maximum attempt count if defined\");\n }\n\n // A retry node must not have a minimum attempt count that exceeds the maximum attempt count.\n if (node.attempts[0] > node.attempts[1]) {\n throw new Error(\n \"a retry node must not have a minimum attempt count that exceeds the maximum attempt count\"\n );\n }\n } else {\n // An incorrect number of attempt counts was defined.\n throw new Error(\"invalid number of retry node attempt count arguments defined\");\n }\n }\n\n // Grab any node attribute definitions and spread them into the node definition.\n node = { ...node, ...parseAttributeTokens(tokens, stringLiteralPlaceholders) };\n\n // This is a decorator node, so we expect an opening '{'.\n popAndCheck(tokens, \"{\");\n\n // Return the retry node definition.\n return node;\n}\n\n/**\n * Creates a sequence node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The sequence node JSON definition.\n */\nfunction createSequenceNode(\n tokens: string[],\n stringLiteralPlaceholders: StringLiteralPlaceholders\n): SequenceNodeDefinition {\n const node = {\n type: \"sequence\",\n ...parseAttributeTokens(tokens, stringLiteralPlaceholders)\n } as SequenceNodeDefinition;\n\n // This is a composite node, so we expect an opening '{'.\n popAndCheck(tokens, \"{\");\n\n // Return the sequence node definition.\n return node;\n}\n\n/**\n * Creates a selector node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The selector node JSON definition.\n */\nfunction createSelectorNode(\n tokens: string[],\n stringLiteralPlaceholders: StringLiteralPlaceholders\n): SelectorNodeDefinition {\n const node = {\n type: \"selector\",\n ...parseAttributeTokens(tokens, stringLiteralPlaceholders)\n } as SelectorNodeDefinition;\n\n // This is a composite node, so we expect an opening '{'.\n popAndCheck(tokens, \"{\");\n\n // Return the selector node definition.\n return node;\n}\n\n/**\n * Creates a parallel node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The parallel node JSON definition.\n */\nfunction createParallelNode(\n tokens: string[],\n stringLiteralPlaceholders: StringLiteralPlaceholders\n): ParallelNodeDefinition {\n const node = {\n type: \"parallel\",\n ...parseAttributeTokens(tokens, stringLiteralPlaceholders)\n } as ParallelNodeDefinition;\n\n // This is a composite node, so we expect an opening '{'.\n popAndCheck(tokens, \"{\");\n\n // Return the parallel node definition.\n return node;\n}\n\n/**\n * Creates a lotto node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The lotto node JSON definition.\n */\nfunction createLottoNode(tokens: string[], stringLiteralPlaceholders: StringLiteralPlaceholders): LottoNodeDefinition {\n // If any node arguments have been defined then they must be our weights.\n const nodeArguments = parseArgumentTokens(tokens, stringLiteralPlaceholders);\n\n // All lotto node arguments MUST be of type number and must be positive integers.\n nodeArguments\n .filter((arg) => arg.type !== \"number\" || !arg.isInteger || arg.value < 0)\n .forEach(() => {\n throw new Error(`lotto node weight arguments must be positive integer values`);\n });\n\n const node = {\n type: \"lotto\",\n weights: nodeArguments.length ? nodeArguments.map(({ value }) => value) : undefined,\n ...parseAttributeTokens(tokens, stringLiteralPlaceholders)\n } as LottoNodeDefinition;\n\n // This is a composite node, so we expect an opening '{'.\n popAndCheck(tokens, \"{\");\n\n // Return the lotto node definition.\n return node;\n}\n\n/**\n * Creates an action node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The action node JSON definition.\n */\nfunction createActionNode(\n tokens: string[],\n stringLiteralPlaceholders: StringLiteralPlaceholders\n): ActionNodeDefinition {\n // Parse any node arguments, we should have at least one which will be an identifier argument for the action name\n // and agent function to invoke for the action, all other arguments are to be passed as arguments to that function.\n const [actionNameIdentifier, ...agentFunctionArgs] = parseArgumentTokens(tokens, stringLiteralPlaceholders);\n\n // Our first argument MUST be defined and be an identifier as we require an action name argument.\n if (actionNameIdentifier?.type !== \"identifier\") {\n throw new Error(\"expected action name identifier argument\");\n }\n\n // Only the first argument should have been an identifier, all agent function arguments must be string, number, boolean or null.\n agentFunctionArgs\n .filter((arg) => arg.type === \"identifier\")\n .forEach((arg) => {\n throw new Error(\n `invalid action node argument value '${arg.value}', must be string, number, boolean or null`\n );\n });\n\n // Return the action node definition.\n return {\n type: \"action\",\n call: actionNameIdentifier.value,\n args: agentFunctionArgs.map(({ value }) => value),\n ...parseAttributeTokens(tokens, stringLiteralPlaceholders)\n };\n}\n\n/**\n * Creates a condition node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The condition node JSON definition.\n */\nfunction createConditionNode(\n tokens: string[],\n stringLiteralPlaceholders: StringLiteralPlaceholders\n): ConditionNodeDefinition {\n // Parse any node arguments, we should have at least one which will be an identifier argument for the condition name\n // and agent function to invoke for the condition, all other arguments are to be passed as arguments to that function.\n const [conditionNameIdentifier, ...agentFunctionArgs] = parseArgumentTokens(tokens, stringLiteralPlaceholders);\n\n // Our first argument MUST be defined and be an identifier as we require a condition name argument.\n if (conditionNameIdentifier?.type !== \"identifier\") {\n throw new Error(\"expected condition name identifier argument\");\n }\n\n // Only the first argument should have been an identifier, all agent function arguments must be string, number, boolean or null.\n agentFunctionArgs\n .filter((arg) => arg.type === \"identifier\")\n .forEach((arg) => {\n throw new Error(\n `invalid condition node argument value '${arg.value}', must be string, number, boolean or null`\n );\n });\n\n // Return the condition node definition.\n return {\n type: \"condition\",\n call: conditionNameIdentifier.value,\n args: agentFunctionArgs.map(({ value }) => value),\n ...parseAttributeTokens(tokens, stringLiteralPlaceholders)\n };\n}\n\n/**\n * Creates a wait node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The wait node JSON definition.\n */\nfunction createWaitNode(tokens: string[], stringLiteralPlaceholders: StringLiteralPlaceholders): WaitNodeDefinition {\n let node = { type: \"wait\" } as WaitNodeDefinition;\n\n // Get the node arguments.\n const nodeArguments = parseArgumentTokens(tokens, stringLiteralPlaceholders);\n\n // The arguments of a wait node are optional. We may have:\n // - No node arguments, in which case the wait will be indefinite until it is aborted.\n // - One node argument which will be the explicit duration of the wait.\n // - Two node arguments which define the min and max duration bounds from which a random duration will be picked.\n if (nodeArguments.length) {\n // All wait node arguments MUST be of type number and must be integer.\n nodeArguments\n .filter((arg) => arg.type !== \"number\" || !arg.isInteger)\n .forEach(() => {\n throw new Error(`wait node durations must be integer values`);\n });\n\n // We may have:\n // - One node argument which will be the explicit duration of the wait.\n // - Two node arguments which define the min and max duration bounds from which a random duration will be picked.\n // - Too many arguments, which is not valid.\n if (nodeArguments.length === 1) {\n // An explicit duration was defined.\n node.duration = nodeArguments[0].value as number;\n\n // If an explict duration was defined then it must be a positive number.\n if (node.duration < 0) {\n throw new Error(\"a wait node must have a positive duration\");\n }\n } else if (nodeArguments.length === 2) {\n // Min and max duration bounds were defined from which a random duration will be picked.\n node.duration = [nodeArguments[0].value as number, nodeArguments[1].value as number];\n\n // A wait node must have a positive min and max duration.\n if (node.duration[0] < 0 || node.duration[1] < 0) {\n throw new Error(\"a wait node must have a positive minimum and maximum duration\");\n }\n\n // A wait node must not have a minimum duration that exceeds the maximum duration.\n if (node.duration[0] > node.duration[1]) {\n throw new Error(\"a wait node must not have a minimum duration that exceeds the maximum duration\");\n }\n } else if (nodeArguments.length > 2) {\n // An incorrect number of duration arguments were defined.\n throw new Error(\"invalid number of wait node duration arguments defined\");\n }\n }\n\n // Return the wait node definition.\n return { ...node, ...parseAttributeTokens(tokens, stringLiteralPlaceholders) };\n}\n\n/**\n * Creates a branch node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The branch node JSON definition.\n */\nfunction createBranchNode(\n tokens: string[],\n stringLiteralPlaceholders: StringLiteralPlaceholders\n): BranchNodeDefinition {\n // Parse any node arguments, we should have one which will be an identifier argument for the root ref.\n const nodeArguments = parseArgumentTokens(tokens, stringLiteralPlaceholders);\n\n // We should have only a single identifer argument for a branch node, which is the root ref.\n if (nodeArguments.length !== 1 || nodeArguments[0].type !== \"identifier\") {\n throw new Error(\"expected single branch name argument\");\n }\n\n // Return the branch node definition.\n return { type: \"branch\", ref: nodeArguments[0].value };\n}\n\n/**\n * Validate a fully-populated node definition that was popped off of the tree stack.\n * @param definition The popped node to validate.\n */\nfunction validatePoppedNode(definition: AnyNodeDefinition): void {\n // Decorators MUST have a child defined.\n if (isDecoratorNode(definition) && isNullOrUndefined(definition.child)) {\n throw new Error(`a ${definition.type} node must have a single child node defined`);\n }\n\n // Composites MUST have at least one child defined.\n if (isCompositeNode(definition) && !definition.children?.length) {\n throw new Error(`a ${definition.type} node must have at least a single child node defined`);\n }\n\n // We need to make sure that lotto nodes that have weights defined have a number of weights matching the number of child nodes.\n if (definition.type === \"lotto\") {\n // Check whether a 'weights' property has been defined, if it has we expect it to be an array of weights.\n if (typeof definition.weights !== \"undefined\") {\n // Check that the weights property is an array of positive integers with an element for each child node element.\n if (definition.weights.length !== definition.children.length) {\n throw new Error(\n \"expected a number of weight arguments matching the number of child nodes for lotto node\"\n );\n }\n }\n }\n}\n", "import { RootNodeDefinition } from \"./BehaviourTreeDefinition\";\nimport { flattenDefinition, isBranchNode, isInteger } from \"./BehaviourTreeDefinitionUtilities\";\nimport { convertMDSLToJSON } from \"./mdsl/MDSLDefinitionParser\";\n\n/**\n * An object representing the result of validating a tree definition.\n */\nexport type DefinitionValidationResult = {\n /**\n * A flag defining whether validation succeeded.\n */\n succeeded: boolean;\n /**\n * A string containing the error message if validation did not succeed.\n */\n errorMessage?: string;\n /**\n * The definition as json if the validation was successful, or undefined if validation did not succeed.\n */\n json?: RootNodeDefinition[];\n};\n\n/**\n * Validates the specified behaviour tree definition in the form of JSON or MDSL, not taking any globally registered subtrees into consideration.\n * @param definition The behaviour tree definition in the form of JSON or MDSL.\n * @returns An object representing the result of validating the given tree definition.\n */\nexport function validateDefinition(definition: any): DefinitionValidationResult {\n // The definition must be defined.\n if (definition === null || typeof definition === \"undefined\") {\n return createValidationFailureResult(\"definition is null or undefined\");\n }\n\n // We are expecting a definition in one of three different forms:\n // - A string which we will assume is MDSL and we will parse this to JSON before validation.\n // - An array which we will assume is an array of root node definitions with at least one being the primary root node (no 'id' property)\n // - An object which we will assume is the primary root node and should not have an 'id' property.\n if (typeof definition === \"string\") {\n // The definition is a string which we can assume is MDSL, so attempt to validate it.\n return validateMDSLDefinition(definition);\n } else if (typeof definition === \"object\") {\n // The definition will either be an array (of root node definitions) or an object (the single primary root node definition).\n return validateJSONDefinition(definition);\n } else {\n return createValidationFailureResult(`unexpected definition type of '${typeof definition}'`);\n }\n}\n\n/**\n * Validates the specified behaviour tree definition in the form of MDSL.\n * @param definition The behaviour tree definition in the form of MDSL.\n * @returns An object representing the result of validating the given tree definition.\n */\nfunction validateMDSLDefinition(definition: string): DefinitionValidationResult {\n let rootNodeDefinitions;\n\n // The first thing the we need to do is to attempt to convert our MDSL into JSON.\n try {\n // The definition is a string which we can assume is MDSL, so attempt to parse it to a JSON definition in the form of an array of root node definitions.\n rootNodeDefinitions = convertMDSLToJSON(definition);\n } catch (exception) {\n // We failed to parse the JSON from the MDSL, this is likely to be the result of it not being a valid MDSL string.\n return createValidationFailureResult((exception as Error).message);\n }\n\n // Unpack all of the root node definitions into arrays of main ('id' defined) and sub ('id' not defined) root node definitions.\n const mainRootNodeDefinitions = rootNodeDefinitions.filter(({ id }) => typeof id === \"undefined\");\n const subRootNodeDefinitions = rootNodeDefinitions.filter(({ id }) => typeof id === \"string\" && id.length > 0);\n\n // We should ALWAYS have exactly one root node definition without an 'id' property defined, which is out main root node definition.\n if (mainRootNodeDefinitions.length !== 1) {\n return createValidationFailureResult(\n \"expected single unnamed root node at base of definition to act as main root\"\n );\n }\n\n // We should never have duplicate 'id' properties across our sub root node definitions.\n const subRootNodeIdenitifers: string[] = [];\n for (const { id } of subRootNodeDefinitions) {\n // Have we already come across this 'id' property value?\n if (subRootNodeIdenitifers.includes(id!)) {\n return createValidationFailureResult(`multiple root nodes found with duplicate name '${id}'`);\n }\n\n subRootNodeIdenitifers.push(id!);\n }\n\n try {\n // Validate our branch -> subtree links and check for any circular dependencies, we don't care about checking for broken subtree links here.\n validateBranchSubtreeLinks(rootNodeDefinitions, false);\n } catch (exception) {\n return createValidationFailureResult((exception as Error).message);\n }\n\n // Our definition was valid!\n return {\n succeeded: true,\n json: rootNodeDefinitions\n };\n}\n\n/**\n * Validates the specified behaviour tree definition in the form of JSON.\n * @param definition The behaviour tree definition in the form of JSON.\n * @returns An object representing the result of validating the given tree definition.\n */\nexport function validateJSONDefinition(\n definition: RootNodeDefinition | RootNodeDefinition[]\n): DefinitionValidationResult {\n // The definition will either be an array (of root node definitions) or an object (the single primary root node definition).\n const rootNodeDefinitions = Array.isArray(definition) ? definition : [definition];\n\n // Iterate over our array of root nodes and call validateNode for each, passing an initial depth of 0, wrapped in a try catch to handle validation failures.\n try {\n rootNodeDefinitions.forEach((rootNodeDefinition) => validateNode(rootNodeDefinition, 0));\n } catch (error) {\n // Handle cases where we have caught a thrown Error and return a failure result with the error message.\n if (error instanceof Error) {\n return createValidationFailureResult(error.message);\n }\n\n // No idea what happened here!\n return createValidationFailureResult(`unexpected error: ${error}`);\n }\n\n // Unpack all of the root node definitions into arrays of main ('id' defined) and sub ('id' not defined) root node definitions.\n const mainRootNodeDefinitions = rootNodeDefinitions.filter(({ id }) => typeof id === \"undefined\");\n const subRootNodeDefinitions = rootNodeDefinitions.filter(({ id }) => typeof id === \"string\" && id.length > 0);\n\n // We should ALWAYS have exactly one root node definition without an 'id' property defined, which is out main root node definition.\n if (mainRootNodeDefinitions.length !== 1) {\n return createValidationFailureResult(\n \"expected single root node without 'id' property defined to act as main root\"\n );\n }\n\n // We should never have duplicate 'id' properties across our sub root node definitions.\n const subRootNodeIdenitifers: string[] = [];\n for (const { id } of subRootNodeDefinitions) {\n // Have we already come across this 'id' property value?\n if (subRootNodeIdenitifers.includes(id!)) {\n return createValidationFailureResult(\n `multiple root nodes found with duplicate 'id' property value of '${id}'`\n );\n }\n\n subRootNodeIdenitifers.push(id!);\n }\n\n try {\n // Validate our branch -> subtree links and check for any circular dependencies, we don't care about checking for broken subtree links here.\n validateBranchSubtreeLinks(rootNodeDefinitions, false);\n } catch (exception) {\n return createValidationFailureResult((exception as Error).message);\n }\n\n // Our definition was valid!\n return {\n succeeded: true,\n json: rootNodeDefinitions\n };\n}\n\n/**\n * Validates the branch -> subtree links across all provided root node definitions.\n * This will not consider branch nodes that reference any globally registered subtrees unless includesGlobalSubtrees\n * is set to true, in which case we will also verify that there are no broken branch -> subtree links.\n * @param rootNodeDefinitions The array of root node definitions.\n * @param includesGlobalSubtrees A flag defining whether the array includes all global subtree root node definitions.\n */\nexport function validateBranchSubtreeLinks(rootNodeDefinitions: RootNodeDefinition[], includesGlobalSubtrees: boolean) {\n // Create a mapping of root node identifiers to other root nodes that they reference via branch nodes.\n // Below is an example of a mapping that includes a circular dependency (root => a => b => c => a)\n // [{ refs: [\"a\", \"b\"] }, { id: \"a\", refs: [\"b\"] }, { id: \"b\", refs: [\"c\"] }, { id: \"c\", refs: [\"a\"] }]\n const rootNodeMappings: { id: string | undefined; refs: string[] }[] = rootNodeDefinitions.map(\n (rootNodeDefinition) => ({\n id: rootNodeDefinition.id,\n refs: flattenDefinition(rootNodeDefinition)\n .filter(isBranchNode)\n .map(({ ref }) => ref)\n })\n );\n\n // A recursive function to walk through the mappings, keeping track of which root nodes we have visited in the form of a path of root node identifiers.\n const followRefs = (mapping: { id: string | undefined; refs: string[] }, path: (string | undefined)[] = []) => {\n // Have we found a circular dependency?\n if (path.includes(mapping.id)) {\n // We found a circular dependency! Get the bad path of root node identifiers.\n const badPath = [...path, mapping.id];\n\n // Create the formatted path value. [undefined, \"a\", \"b\", \"c\", \"a\"] would be formatted as \"a -> b -> c -> a\".\n const badPathFormatted = badPath.filter((element) => !!element).join(\" => \");\n\n // No need to continue, we found a circular dependency.\n throw new Error(`circular dependency found in branch node references: ${badPathFormatted}`);\n }\n\n for (const ref of mapping.refs) {\n // Find the mapping for the root node with an identifer matching the current ref.\n const subMapping = rootNodeMappings.find(({ id }) => id === ref);\n\n // We may not have a mapping for this ref, which is normal when we aren't considering all globally registered subtrees.\n if (subMapping) {\n followRefs(subMapping, [...path, mapping.id]);\n } else if (includesGlobalSubtrees) {\n // We found a reference to a root node that doesn't exist, which is a problem seeing as the root node definitons includes all globally registered subtrees.\n throw new Error(\n mapping.id\n ? `subtree '${mapping.id}' has branch node that references root node '${ref}' which has not been defined`\n : `primary tree has branch node that references root node '${ref}' which has not been defined`\n );\n }\n }\n };\n\n // Start looking for circular dependencies and broken references from the primary root node definition.\n followRefs(rootNodeMappings.find((mapping) => typeof mapping.id === \"undefined\")!);\n}\n\n/**\n * Validate an object that we expect to be a node definition.\n * @param definition An object that we expect to be a node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateNode(definition: any, depth: number): void {\n // Every node must be valid object and have a non-empty 'type' string property.\n if (typeof definition !== \"object\" || typeof definition.type !== \"string\" || definition.type.length === 0) {\n throw new Error(\n `node definition is not an object or 'type' property is not a non-empty string at depth '${depth}'`\n );\n }\n\n // How we validate this node definition will depend on its type.\n switch (definition.type) {\n case \"action\":\n validateActionNode(definition, depth);\n break;\n\n case \"condition\":\n validateConditionNode(definition, depth);\n break;\n\n case \"wait\":\n validateWaitNode(definition, depth);\n break;\n\n case \"branch\":\n validateBranchNode(definition, depth);\n break;\n\n case \"root\":\n validateRootNode(definition, depth);\n break;\n\n case \"succeed\":\n validateSucceedNode(definition, depth);\n break;\n\n case \"fail\":\n validateFailNode(definition, depth);\n break;\n\n case \"flip\":\n validateFlipNode(definition, depth);\n break;\n\n case \"repeat\":\n validateRepeatNode(definition, depth);\n break;\n\n case \"retry\":\n validateRetryNode(definition, depth);\n break;\n\n case \"sequence\":\n validateSequenceNode(definition, depth);\n break;\n\n case \"selector\":\n validateSelectorNode(definition, depth);\n break;\n\n case \"parallel\":\n validateParallelNode(definition, depth);\n break;\n\n case \"lotto\":\n validateLottoNode(definition, depth);\n break;\n\n default:\n throw new Error(`unexpected node type of '${definition.type}' at depth '${depth}'`);\n }\n}\n\n/**\n * Validate any attributes for a given node definition.\n * @param definition The node definition.\n * @param depth The depth of the node in the behaviour tree definition.\n */\nfunction validateNodeAttributes(definition: any, depth: number): void {\n // Validate each of the attribute types for this node.\n [\"while\", \"until\", \"entry\", \"exit\", \"step\"].forEach((attributeName) => {\n // Attempt to grab the definition for the current attribute from the node definition.\n const attributeDefinition = definition[attributeName];\n\n // All node attributes are optional, so there is nothing to do if the current attribute is not defined.\n if (typeof attributeDefinition === \"undefined\") {\n return;\n }\n\n // The attribute definition must be an object.\n if (typeof attributeDefinition !== \"object\") {\n throw new Error(\n `expected attribute '${attributeName}' to be an object for '${definition.type}' node at depth '${depth}'`\n );\n }\n\n // The 'call' property must be defined for any attribute definition.\n if (typeof attributeDefinition.call !== \"string\" || attributeDefinition.call.length === 0) {\n throw new Error(\n `expected 'call' property for attribute '${attributeName}' to be a non-empty string for '${definition.type}' node at depth '${depth}'`\n );\n }\n\n // If any node attribute arguments have been defined then they must have been defined in an array.\n if (typeof attributeDefinition.args !== \"undefined\" && !Array.isArray(attributeDefinition.args)) {\n throw new Error(\n `expected 'args' property for attribute '${attributeName}' to be an array for '${definition.type}' node at depth '${depth}'`\n );\n }\n });\n}\n\n/**\n * Validate an object that we expect to be a root node definition.\n * @param definition An object that we expect to be a root node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateRootNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"root\") {\n throw new Error(\"expected node type of 'root' for root node\");\n }\n\n // A root node cannot be the child of another node.\n if (depth > 0) {\n throw new Error(\"a root node cannot be the child of another node\");\n }\n\n // Check that, if the root node 'id' property is defined, it is a non-empty string.\n if (typeof definition.id !== \"undefined\" && (typeof definition.id !== \"string\" || definition.id.length === 0)) {\n throw new Error(\"expected non-empty string for 'id' property if defined for root node\");\n }\n\n // A root node is a decorator node, so must have a child node defined.\n if (typeof definition.child === \"undefined\") {\n throw new Error(\"expected property 'child' to be defined for root node\");\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n\n // Validate the child node of this decorator node.\n validateNode(definition.child, depth + 1);\n}\n\n/**\n * Validate an object that we expect to be a succeed node definition.\n * @param definition An object that we expect to be a succeed node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateSucceedNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"succeed\") {\n throw new Error(`expected node type of 'succeed' for succeed node at depth '${depth}'`);\n }\n\n // A succeed node is a decorator node, so must have a child node defined.\n if (typeof definition.child === \"undefined\") {\n throw new Error(`expected property 'child' to be defined for succeed node at depth '${depth}'`);\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n\n // Validate the child node of this decorator node.\n validateNode(definition.child, depth + 1);\n}\n\n/**\n * Validate an object that we expect to be a fail node definition.\n * @param definition An object that we expect to be a fail node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateFailNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"fail\") {\n throw new Error(`expected node type of 'fail' for fail node at depth '${depth}'`);\n }\n\n // A fail node is a decorator node, so must have a child node defined.\n if (typeof definition.child === \"undefined\") {\n throw new Error(`expected property 'child' to be defined for fail node at depth '${depth}'`);\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n\n // Validate the child node of this decorator node.\n validateNode(definition.child, depth + 1);\n}\n\n/**\n * Validate an object that we expect to be a flip node definition.\n * @param definition An object that we expect to be a flip node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateFlipNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"flip\") {\n throw new Error(`expected node type of 'flip' for flip node at depth '${depth}'`);\n }\n\n // A flip node is a decorator node, so must have a child node defined.\n if (typeof definition.child === \"undefined\") {\n throw new Error(`expected property 'child' to be defined for flip node at depth '${depth}'`);\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n\n // Validate the child node of this decorator node.\n validateNode(definition.child, depth + 1);\n}\n\n/**\n * Validate an object that we expect to be a repeat node definition.\n * @param definition An object that we expect to be a repeat node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateRepeatNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"repeat\") {\n throw new Error(`expected node type of 'repeat' for repeat node at depth '${depth}'`);\n }\n\n // A repeat node is a decorator node, so must have a child node defined.\n if (typeof definition.child === \"undefined\") {\n throw new Error(`expected property 'child' to be defined for repeat node at depth '${depth}'`);\n }\n\n // Check whether an 'iterations' property has been defined, it may not have been if this node is to repeat indefinitely.\n if (typeof definition.iterations !== \"undefined\") {\n if (Array.isArray(definition.iterations)) {\n // Check whether any elements of the array are not integer values.\n const containsNonInteger = !!definition.iterations.filter((value: unknown) => !isInteger(value)).length;\n\n // If the 'iterations' property is an array then it MUST contain two integer values.\n if (definition.iterations.length !== 2 || containsNonInteger) {\n throw new Error(\n `expected array containing two integer values for 'iterations' property if defined for repeat node at depth '${depth}'`\n );\n }\n\n // A repeat node must have a positive min and max iterations count if they are defined.\n if (definition.iterations[0] < 0 || definition.iterations[1] < 0) {\n throw new Error(\n `expected positive minimum and maximum iterations count for 'iterations' property if defined for repeat node at depth '${depth}'`\n );\n }\n\n // A repeat node must not have a minimum iterations count that exceeds the maximum iterations count.\n if (definition.iterations[0] > definition.iterations[1]) {\n throw new Error(\n `expected minimum iterations count that does not exceed the maximum iterations count for 'iterations' property if defined for repeat node at depth '${depth}'`\n );\n }\n } else if (isInteger(definition.iterations)) {\n // A repeat node must have a positive number of iterations if defined.\n if (definition.iterations < 0) {\n throw new Error(\n `expected positive iterations count for 'iterations' property if defined for repeat node at depth '${depth}'`\n );\n }\n } else {\n throw new Error(\n `expected integer value or array containing two integer values for 'iterations' property if defined for repeat node at depth '${depth}'`\n );\n }\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n\n // Validate the child node of this decorator node.\n validateNode(definition.child, depth + 1);\n}\n\n/**\n * Validate an object that we expect to be a retry node definition.\n * @param definition An object that we expect to be a retry node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateRetryNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"retry\") {\n throw new Error(`expected node type of 'retry' for retry node at depth '${depth}'`);\n }\n\n // A retry node is a decorator node, so must have a child node defined.\n if (typeof definition.child === \"undefined\") {\n throw new Error(`expected property 'child' to be defined for retry node at depth '${depth}'`);\n }\n\n // Check whether an 'attempts' property has been defined, it may not have been if this node is to retry indefinitely.\n if (typeof definition.attempts !== \"undefined\") {\n if (Array.isArray(definition.attempts)) {\n // Check whether any elements of the array are not integer values.\n const containsNonInteger = !!definition.attempts.filter((value: unknown) => !isInteger(value)).length;\n\n // If the 'attempts' property is an array then it MUST contain two integer values.\n if (definition.attempts.length !== 2 || containsNonInteger) {\n throw new Error(\n `expected array containing two integer values for 'attempts' property if defined for retry node at depth '${depth}'`\n );\n }\n\n // A retry node must have a positive min and max attempts count if they are defined.\n if (definition.attempts[0] < 0 || definition.attempts[1] < 0) {\n throw new Error(\n `expected positive minimum and maximum attempts count for 'attempts' property if defined for retry node at depth '${depth}'`\n );\n }\n\n // A retry node must not have a minimum attempts count that exceeds the maximum attempts count.\n if (definition.attempts[0] > definition.attempts[1]) {\n throw new Error(\n `expected minimum attempts count that does not exceed the maximum attempts count for 'attempts' property if defined for retry node at depth '${depth}'`\n );\n }\n } else if (isInteger(definition.attempts)) {\n // A retry node must have a positive number of attempts if defined.\n if (definition.attempts < 0) {\n throw new Error(\n `expected positive attempts count for 'attempts' property if defined for retry node at depth '${depth}'`\n );\n }\n } else {\n throw new Error(\n `expected integer value or array containing two integer values for 'attempts' property if defined for retry node at depth '${depth}'`\n );\n }\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n\n // Validate the child node of this decorator node.\n validateNode(definition.child, depth + 1);\n}\n\n/**\n * Validate an object that we expect to be a branch node definition.\n * @param definition An object that we expect to be a branch node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateBranchNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"branch\") {\n throw new Error(`expected node type of 'branch' for branch node at depth '${depth}'`);\n }\n\n // Check that the branch node 'ref' property is defined and is a non-empty string.\n if (typeof definition.ref !== \"string\" || definition.ref.length === 0) {\n throw new Error(`expected non-empty string for 'ref' property for branch node at depth '${depth}'`);\n }\n\n // It is invalid to define guard attributes for a branch node as they should be defined on the referenced root node.\n [\"while\", \"until\"].forEach((attributeName) => {\n if (typeof definition[attributeName] !== \"undefined\") {\n throw new Error(\n `guards should not be defined for branch nodes but guard '${attributeName}' was defined for branch node at depth '${depth}'`\n );\n }\n });\n\n // It is invalid to define callback attributes for a branch node as they should be defined on the referenced root node.\n [\"entry\", \"exit\", \"step\"].forEach((attributeName) => {\n if (typeof definition[attributeName] !== \"undefined\") {\n throw new Error(\n `callbacks should not be defined for branch nodes but callback '${attributeName}' was defined for branch node at depth '${depth}'`\n );\n }\n });\n}\n\n/**\n * Validate an object that we expect to be a action node definition.\n * @param definition An object that we expect to be a action node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateActionNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"action\") {\n throw new Error(`expected node type of 'action' for action node at depth '${depth}'`);\n }\n\n // The 'call' property must be defined for a action node definition.\n if (typeof definition.call !== \"string\" || definition.call.length === 0) {\n throw new Error(`expected non-empty string for 'call' property of action node at depth '${depth}'`);\n }\n\n // If any action function arguments have been defined then they must have been defined in an array.\n if (typeof definition.args !== \"undefined\" && !Array.isArray(definition.args)) {\n throw new Error(`expected array for 'args' property if defined for action node at depth '${depth}'`);\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n}\n\n/**\n * Validate an object that we expect to be a condition node definition.\n * @param definition An object that we expect to be a condition node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateConditionNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"condition\") {\n throw new Error(`expected node type of 'condition' for condition node at depth '${depth}'`);\n }\n\n // The 'call' property must be defined for a condition node definition.\n if (typeof definition.call !== \"string\" || definition.call.length === 0) {\n throw new Error(`expected non-empty string for 'call' property of condition node at depth '${depth}'`);\n }\n\n // If any condition function arguments have been defined then they must have been defined in an array.\n if (typeof definition.args !== \"undefined\" && !Array.isArray(definition.args)) {\n throw new Error(`expected array for 'args' property if defined for condition node at depth '${depth}'`);\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n}\n\n/**\n * Validate an object that we expect to be a wait node definition.\n * @param definition An object that we expect to be a wait node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateWaitNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"wait\") {\n throw new Error(`expected node type of 'wait' for wait node at depth '${depth}'`);\n }\n\n // Check whether a 'duration' property has been defined, it may not have been if this node is to wait indefinitely.\n if (typeof definition.duration !== \"undefined\") {\n if (Array.isArray(definition.duration)) {\n // Check whether any elements of the array are not integer values.\n const containsNonInteger = !!definition.duration.filter((value: unknown) => !isInteger(value)).length;\n\n // If the 'duration' property is an array then it MUST contain two integer values.\n if (definition.duration.length !== 2 || containsNonInteger) {\n throw new Error(\n `expected array containing two integer values for 'duration' property if defined for wait node at depth '${depth}'`\n );\n }\n\n // A wait node must have a positive min and max duration value if they are defined.\n if (definition.duration[0] < 0 || definition.duration[1] < 0) {\n throw new Error(\n `expected positive minimum and maximum duration for 'duration' property if defined for wait node at depth '${depth}'`\n );\n }\n\n // A wait node must not have a minimum duration value that exceeds the maximum duration value.\n if (definition.duration[0] > definition.duration[1]) {\n throw new Error(\n `expected minimum duration value that does not exceed the maximum duration value for 'duration' property if defined for wait node at depth '${depth}'`\n );\n }\n } else if (isInteger(definition.duration)) {\n // A wait node must have a positive duration value if defined.\n if (definition.duration < 0) {\n throw new Error(\n `expected positive duration value for 'duration' property if defined for wait node at depth '${depth}'`\n );\n }\n } else {\n throw new Error(\n `expected integer value or array containing two integer values for 'duration' property if defined for wait node at depth '${depth}'`\n );\n }\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n}\n\n/**\n * Validate an object that we expect to be a sequence node definition.\n * @param definition An object that we expect to be a sequence node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateSequenceNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"sequence\") {\n throw new Error(`expected node type of 'sequence' for sequence node at depth '${depth}'`);\n }\n\n // A sequence node is a composite node, so must have a children nodes array defined.\n if (!Array.isArray(definition.children) || definition.children.length === 0) {\n throw new Error(`expected non-empty 'children' array to be defined for sequence node at depth '${depth}'`);\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n\n // Validate the child nodes of this composite node.\n definition.children.forEach((child: any) => validateNode(child, depth + 1));\n}\n\n/**\n * Validate an object that we expect to be a selector node definition.\n * @param definition An object that we expect to be a selector node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateSelectorNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"selector\") {\n throw new Error(`expected node type of 'selector' for selector node at depth '${depth}'`);\n }\n\n // A selector node is a composite node, so must have a children nodes array defined.\n if (!Array.isArray(definition.children) || definition.children.length === 0) {\n throw new Error(`expected non-empty 'children' array to be defined for selector node at depth '${depth}'`);\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n\n // Validate the child nodes of this composite node.\n definition.children.forEach((child: any) => validateNode(child, depth + 1));\n}\n\n/**\n * Validate an object that we expect to be a parallel node definition.\n * @param definition An object that we expect to be a parallel node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateParallelNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"parallel\") {\n throw new Error(`expected node type of 'parallel' for parallel node at depth '${depth}'`);\n }\n\n // A parallel node is a composite node, so must have a children nodes array defined.\n if (!Array.isArray(definition.children) || definition.children.length === 0) {\n throw new Error(`expected non-empty 'children' array to be defined for parallel node at depth '${depth}'`);\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n\n // Validate the child nodes of this composite node.\n definition.children.forEach((child: any) => validateNode(child, depth + 1));\n}\n\n/**\n * Validate an object that we expect to be a lotto node definition.\n * @param definition An object that we expect to be a lotto node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateLottoNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"lotto\") {\n throw new Error(`expected node type of 'lotto' for lotto node at depth '${depth}'`);\n }\n\n // A lotto node is a composite node, so must have a children nodes array defined.\n if (!Array.isArray(definition.children) || definition.children.length === 0) {\n throw new Error(`expected non-empty 'children' array to be defined for lotto node at depth '${depth}'`);\n }\n\n // Check whether a 'weights' property has been defined, if it has we expect it to be an array of weights.\n if (typeof definition.weights !== \"undefined\") {\n // Check that the weights property is an array of positive integers with an element for each child node element.\n if (\n !Array.isArray(definition.weights) ||\n definition.weights.length !== definition.children.length ||\n definition.weights.filter((value: unknown) => !isInteger(value)).length ||\n definition.weights.filter((value: number) => value < 0).length\n ) {\n throw new Error(\n `expected an array of positive integer weight values with a length matching the number of child nodes for 'weights' property if defined for lotto node at depth '${depth}'`\n );\n }\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n\n // Validate the child nodes of this composite node.\n definition.children.forEach((child: any) => validateNode(child, depth + 1));\n}\n\n/**\n * A helper function to create a failure validation result with the given error message.\n * @param errorMessage The validation failure error message.\n * @returns A failure validation result with the given error message.\n */\nfunction createValidationFailureResult(errorMessage: string): DefinitionValidationResult {\n return { succeeded: false, errorMessage };\n}\n", "import { ActionResult, Agent, GlobalFunction } from \"./Agent\";\nimport { RootNodeDefinition } from \"./BehaviourTreeDefinition\";\n\nexport type InvokerFunction = (args: any[]) => ActionResult;\n\n/**\n * A singleton used to store and lookup registered functions and subtrees.\n */\nexport default class Lookup {\n /**\n * The object holding any registered functions keyed on function name.\n */\n private static functionTable: { [key: string]: GlobalFunction } = {};\n /**\n * The object holding any registered subtree root node definitions keyed on tree name.\n */\n private static subtreeTable: { [key: string]: RootNodeDefinition } = {};\n\n /**\n * Gets the function with the specified name.\n * @param name The name of the function.\n * @returns The function with the specified name.\n */\n public static getFunc(name: string): GlobalFunction {\n return this.functionTable[name];\n }\n\n /**\n * Sets the function with the specified name for later lookup.\n * @param name The name of the function.\n * @param func The function.\n */\n public static setFunc(name: string, func: GlobalFunction): void {\n this.functionTable[name] = func;\n }\n\n /**\n * Gets the function invoker for the specified agent and function name.\n * If a function with the specified name exists on the agent object then it will\n * be returned, otherwise we will then check the registered functions for a match.\n * @param agent The agent instance that this behaviour tree is modelling behaviour for.\n * @param name The function name.\n * @returns The function invoker for the specified agent and function name.\n */\n static getFuncInvoker(agent: Agent, name: string): InvokerFunction | null {\n // Check whether the agent contains the specified function.\n const foundOnAgent = agent[name];\n if (foundOnAgent && typeof foundOnAgent === \"function\") {\n return (args: any[]): boolean | ActionResult => foundOnAgent.apply(agent, args);\n }\n\n // The agent does not contain the specified function but it may have been registered at some point.\n if (this.functionTable[name] && typeof this.functionTable[name] === \"function\") {\n return (args: any[]) => this.functionTable[name](agent, ...args.map((arg) => arg.value));\n }\n\n // We have no function to invoke.\n return null;\n }\n\n /**\n * Gets all registered subtree root node definitions.\n */\n static getSubtrees(): { [key: string]: RootNodeDefinition } {\n return this.subtreeTable;\n }\n\n /**\n * Sets the subtree with the specified name for later lookup.\n * @param name The name of the subtree.\n * @param subtree The subtree.\n */\n static setSubtree(name: string, subtree: RootNodeDefinition) {\n this.subtreeTable[name] = subtree;\n }\n\n /**\n * Removes the registered function or subtree with the specified name.\n * @param name The name of the registered function or subtree.\n */\n static remove(name: string) {\n delete this.functionTable[name];\n delete this.subtreeTable[name];\n }\n\n /**\n * Remove all registered functions and subtrees.\n */\n static empty() {\n this.functionTable = {};\n this.subtreeTable = {};\n }\n}\n", "import Node from \"../../nodes/Node\";\n\n/**\n * An exception thrown when evaluating node guard path conditions and a conditions fails.\n */\nexport default class GuardUnsatisifedException extends Error {\n /**\n * @param source The node at which a guard condition failed.\n */\n constructor(private source: Node) {\n super(\"A guard path condition has failed\");\n }\n\n /**\n * Gets whether the specified node is the node at which a guard condition failed.\n * @param node The node to check against the source node.\n * @returns Whether the specified node is the node at which a guard condition failed.\n */\n isSourceNode = (node: Node) => node === this.source;\n}\n", "import { Agent } from \"../../Agent\";\nimport Guard from \"./Guard\";\nimport Node from \"../../nodes/Node\";\nimport GuardUnsatisifedException from \"./GuardUnsatisifedException\";\n\nexport type GuardPathPart = {\n node: Node;\n guards: Guard[];\n};\n\n/**\n * Represents a path of node guards along a root-to-leaf tree path.\n */\nexport default class GuardPath {\n /**\n * @param nodes An array of objects defining a node instance -> guard link, ordered by node depth.\n */\n constructor(private nodes: GuardPathPart[]) {}\n\n /**\n * Evaluate guard conditions for all guards in the tree path, moving outwards from the root.\n * @param agent The agent, required for guard evaluation.\n * @returns An evaluation results object.\n */\n evaluate = (agent: Agent) => {\n // We need to evaluate guard conditions for nodes up the tree, moving outwards from the root.\n for (const details of this.nodes) {\n // There can be multiple guards per node.\n for (const guard of details.guards) {\n // Check whether the guard condition passes, and throw an exception if not.\n if (!guard.isSatisfied(agent)) {\n throw new GuardUnsatisifedException(details.node);\n }\n }\n }\n };\n}\n", "import { BehaviourTreeOptions } from \"../BehaviourTreeOptions\";\nimport State, { AnyState } from \"../State\";\nimport { Agent } from \"../Agent\";\nimport Leaf from \"./leaf/Leaf\";\nimport Attribute from \"../attributes/Attribute\";\nimport Entry from \"../attributes/callbacks/Entry\";\nimport Exit from \"../attributes/callbacks/Exit\";\nimport Step from \"../attributes/callbacks/Step\";\nimport Guard from \"../attributes/guards/Guard\";\nimport GuardPath from \"../attributes/guards/GuardPath\";\nimport GuardUnsatisifedException from \"../attributes/guards/GuardUnsatisifedException\";\n\n/**\n * A base node.\n */\nexport default abstract class Node {\n /**\n * The node uid.\n */\n private readonly uid: string = createNodeUid();\n /**\n * The node state.\n */\n private state: AnyState = State.READY;\n /**\n * The guard path to evaluate as part of a node update.\n */\n private guardPath: GuardPath | undefined;\n\n /**\n * @param type The node type.\n * @param attributes The node attributes.\n * @param args The node argument definitions.\n */\n constructor(private type: string, private attributes: Attribute[], private args: any[]) {}\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected abstract onUpdate(agent: Agent, options: BehaviourTreeOptions): void;\n\n /**\n * Gets the name of the node.\n */\n public abstract getName(): string;\n\n /**\n * Gets whether this node is a leaf node.\n */\n public abstract isLeafNode: () => this is Leaf;\n\n /**\n * Gets/Sets the state of the node.\n */\n getState = (): AnyState => this.state;\n setState = (value: AnyState): void => {\n this.state = value;\n };\n\n /**\n * Gets the unique id of the node.\n */\n getUid = () => this.uid;\n\n /**\n * Gets the type of the node.\n */\n getType = () => this.type;\n\n /**\n * Gets the node attributes.\n */\n getAttributes = () => this.attributes;\n\n /**\n * Gets the node arguments.\n */\n getArguments = () => this.args;\n\n /**\n * Gets the node attribute with the specified type, or null if it does not exist.\n */\n getAttribute(type: \"entry\" | \"ENTRY\"): Entry;\n getAttribute(type: \"exit\" | \"EXIT\"): Exit;\n getAttribute(type: \"step\" | \"STEP\"): Step;\n getAttribute(type: string): Attribute {\n return (\n this.getAttributes().filter((decorator) => decorator.type.toUpperCase() === type.toUpperCase())[0] || null\n );\n }\n\n /**\n * Gets the node attributes.\n */\n getGuardAttributes = (): Guard[] => this.getAttributes().filter((decorator) => decorator.isGuard()) as Guard[];\n\n /**\n * Sets the guard path to evaluate as part of a node update.\n */\n setGuardPath = (value: GuardPath) => (this.guardPath = value);\n\n /**\n * Gets whether a guard path is assigned to this node.\n */\n hasGuardPath = () => !!this.guardPath;\n\n /**\n * Gets whether this node is in the specified state.\n * @param value The value to compare to the node state.\n */\n public is(value: AnyState): boolean {\n return this.state === value;\n }\n\n /**\n * Reset the state of the node.\n */\n public reset(): void {\n this.setState(State.READY);\n }\n\n /**\n * Abort the running of this node.\n * @param agent The agent.\n */\n public abort(agent: Agent): void {\n // There is nothing to do if this node is not in the running state.\n if (!this.is(State.RUNNING)) {\n return;\n }\n\n // Reset the state of this node.\n this.reset();\n\n this.getAttribute(\"exit\")?.callAgentFunction(agent, false, true);\n }\n\n /**\n * Update the node.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n * @returns The result of the update.\n */\n public update(agent: Agent, options: BehaviourTreeOptions): void {\n // If this node is already in a 'SUCCEEDED' or 'FAILED' state then there is nothing to do.\n if (this.is(State.SUCCEEDED) || this.is(State.FAILED)) {\n return;\n }\n\n try {\n // Evaluate all of the guard path conditions for the current tree path.\n this.guardPath!.evaluate(agent);\n\n // If this node is in the READY state then call the ENTRY for this node if it exists.\n if (this.is(State.READY)) {\n this.getAttribute(\"entry\")?.callAgentFunction(agent);\n }\n\n this.getAttribute(\"step\")?.callAgentFunction(agent);\n\n // Do the actual update.\n this.onUpdate(agent, options);\n\n // If this node is now in a 'SUCCEEDED' or 'FAILED' state then call the EXIT for this node if it exists.\n if (this.is(State.SUCCEEDED) || this.is(State.FAILED)) {\n this.getAttribute(\"exit\")?.callAgentFunction(agent, this.is(State.SUCCEEDED), false);\n }\n } catch (error) {\n // If the error is a GuardUnsatisfiedException then we need to determine if this node is the source.\n if (error instanceof GuardUnsatisifedException && error.isSourceNode(this)) {\n // Abort the current node.\n this.abort(agent);\n\n // Any node that is the source of an abort will be a failed node.\n this.setState(State.FAILED);\n } else {\n throw error;\n }\n }\n }\n}\n\n/**\n * Create a randomly generated node uid.\n * @returns A randomly generated node uid.\n */\nfunction createNodeUid(): string {\n var S4 = function () {\n return (((1 + Math.random()) * 0x10000) | 0).toString(16).substring(1);\n };\n return S4() + S4() + \"-\" + S4() + \"-\" + S4() + \"-\" + S4() + \"-\" + S4() + S4() + S4();\n}\n", "import Node from \"../Node\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\n\n/**\n * A composite node that wraps child nodes.\n */\nexport default abstract class Composite extends Node {\n /**\n * @param type The node type.\n * @param attributes The node attributes.\n * @param children The child nodes.\n */\n constructor(type: string, attributes: Attribute[], protected children: Node[]) {\n super(type, attributes, []);\n }\n\n /**\n * Gets whether this node is a leaf node.\n */\n isLeafNode = () => false;\n\n /**\n * Gets the children of this node.\n */\n getChildren = () => this.children;\n\n /**\n * Reset the state of the node.\n */\n reset = () => {\n // Reset the state of this node.\n this.setState(State.READY);\n\n // Reset the state of any child nodes.\n this.getChildren().forEach((child) => child.reset());\n };\n\n /**\n * Abort the running of this node.\n * @param agent The agent.\n */\n abort = (agent: Agent) => {\n // There is nothing to do if this node is not in the running state.\n if (!this.is(State.RUNNING)) {\n return;\n }\n\n // Abort any child nodes.\n this.getChildren().forEach((child) => child.abort(agent));\n\n // Reset the state of this node.\n this.reset();\n\n this.getAttribute(\"exit\")?.callAgentFunction(agent, false, true);\n };\n}\n", "import Composite from \"./Composite\";\nimport State from \"../../State\";\nimport Node from \"../Node\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A PARALLEL node.\n * The child nodes are executed concurrently until one fails or all succeed.\n */\nexport default class Parallel extends Composite {\n /**\n * @param attributes The node attributes.\n * @param children The child nodes.\n */\n constructor(attributes: Attribute[], children: Node[]) {\n super(\"parallel\", attributes, children);\n }\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // Keep a count of the number of succeeded child nodes.\n let succeededCount = 0;\n\n let hasChildFailed = false;\n\n // Iterate over all of the children of this node.\n for (const child of this.children) {\n // If the child has never been updated or is running then we will need to update it now.\n if (child.getState() === State.READY || child.getState() === State.RUNNING) {\n // Update the child of this node.\n child.update(agent, options);\n }\n\n // If the current child has a state of 'SUCCEEDED' then we should move on to the next child.\n if (child.getState() === State.SUCCEEDED) {\n // The child node has succeeded, keep track of this to determine if all children have.\n succeededCount++;\n\n // The child node succeeded, but we have not finished checking every child node yet.\n continue;\n }\n\n // If the current child has a state of 'FAILED' then this node is also a 'FAILED' node.\n if (child.getState() === State.FAILED) {\n hasChildFailed = true;\n\n // There is no need to check the rest of the children.\n break;\n }\n\n // The node should be in the 'RUNNING' state.\n if (child.getState() !== State.RUNNING) {\n // The child node was not in an expected state.\n throw new Error(\"child node was not in an expected state.\");\n }\n }\n\n if (hasChildFailed) {\n // This node is a 'FAILED' node.\n this.setState(State.FAILED);\n\n // Abort every running child.\n for (const child of this.children) {\n if (child.getState() === State.RUNNING) {\n child.abort(agent);\n }\n }\n } else {\n // If all children have succeeded then this node has also succeeded, otherwise it is still running.\n this.setState(succeededCount === this.children.length ? State.SUCCEEDED : State.RUNNING);\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => \"PARALLEL\";\n}\n", "import Composite from \"./Composite\";\nimport Node from \"../Node\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A SELECTOR node.\n * The child nodes are executed in sequence until one succeeds or all fail.\n */\nexport default class Selector extends Composite {\n /**\n * @param attributes The node attributes.\n * @param children The child nodes.\n */\n constructor(attributes: Attribute[], protected children: Node[]) {\n super(\"selector\", attributes, children);\n }\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // Iterate over all of the children of this node.\n for (const child of this.children) {\n // If the child has never been updated or is running then we will need to update it now.\n if (child.getState() === State.READY || child.getState() === State.RUNNING) {\n // Update the child of this node.\n child.update(agent, options);\n }\n\n // If the current child has a state of 'SUCCEEDED' then this node is also a 'SUCCEEDED' node.\n if (child.getState() === State.SUCCEEDED) {\n // This node is a 'SUCCEEDED' node.\n this.setState(State.SUCCEEDED);\n\n // There is no need to check the rest of the selector nodes.\n return;\n }\n\n // If the current child has a state of 'FAILED' then we should move on to the next child.\n if (child.getState() === State.FAILED) {\n // Find out if the current child is the last one in the selector.\n // If it is then this sequence node has also failed.\n if (this.children.indexOf(child) === this.children.length - 1) {\n // This node is a 'FAILED' node.\n this.setState(State.FAILED);\n\n // There is no need to check the rest of the selector as we have completed it.\n return;\n } else {\n // The child node failed, try the next one.\n continue;\n }\n }\n\n // The node should be in the 'RUNNING' state.\n if (child.getState() === State.RUNNING) {\n // This node is a 'RUNNING' node.\n this.setState(State.RUNNING);\n\n // There is no need to check the rest of the selector as the current child is still running.\n return;\n }\n\n // The child node was not in an expected state.\n throw new Error(\"child node was not in an expected state.\");\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => \"SELECTOR\";\n}\n", "import Composite from \"./Composite\";\nimport Node from \"../Node\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A SEQUENCE node.\n * The child nodes are executed in sequence until one fails or all succeed.\n */\nexport default class Sequence extends Composite {\n /**\n * @param attributes The node attributes.\n * @param children The child nodes.\n */\n constructor(attributes: Attribute[], protected children: Node[]) {\n super(\"sequence\", attributes, children);\n }\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // Iterate over all of the children of this node.\n for (const child of this.children) {\n // If the child has never been updated or is running then we will need to update it now.\n if (child.getState() === State.READY || child.getState() === State.RUNNING) {\n // Update the child of this node.\n child.update(agent, options);\n }\n\n // If the current child has a state of 'SUCCEEDED' then we should move on to the next child.\n if (child.getState() === State.SUCCEEDED) {\n // Find out if the current child is the last one in the sequence.\n // If it is then this sequence node has also succeeded.\n if (this.children.indexOf(child) === this.children.length - 1) {\n // This node is a 'SUCCEEDED' node.\n this.setState(State.SUCCEEDED);\n\n // There is no need to check the rest of the sequence as we have completed it.\n return;\n } else {\n // The child node succeeded, but we have not finished the sequence yet.\n continue;\n }\n }\n\n // If the current child has a state of 'FAILED' then this node is also a 'FAILED' node.\n if (child.getState() === State.FAILED) {\n // This node is a 'FAILED' node.\n this.setState(State.FAILED);\n\n // There is no need to check the rest of the sequence.\n return;\n }\n\n // The node should be in the 'RUNNING' state.\n if (child.getState() === State.RUNNING) {\n // This node is a 'RUNNING' node.\n this.setState(State.RUNNING);\n\n // There is no need to check the rest of the sequence as the current child is still running.\n return;\n }\n\n // The child node was not in an expected state.\n throw new Error(\"child node was not in an expected state.\");\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => \"SEQUENCE\";\n}\n", "import createLotto from \"lotto-draw\";\n\nimport Node from \"../Node\";\nimport Composite from \"./Composite\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A LOTTO node.\n * A winning child is picked on the initial update of this node, based on ticket weighting.\n * The state of this node will match the state of the winning child.\n */\nexport default class Lotto extends Composite {\n /**\n * @param attributes The node attributes.\n * @param weights The child node weights.\n * @param children The child nodes.\n */\n constructor(attributes: Attribute[], private weights: number[] | undefined, children: Node[]) {\n super(\"lotto\", attributes, children);\n }\n\n /**\n * The child node selected to be the active one.\n */\n private selectedChild: Node | undefined;\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // If this node is in the READY state then we need to pick a winning child node.\n if (this.is(State.READY)) {\n // Create a lotto draw with which to randomly pick a child node to become the active one.\n const lottoDraw = createLotto({\n // Hook up the optional 'random' behaviour tree function option to the one used by 'lotto-draw'.\n random: options.random,\n // Pass in each child node as a participant in the lotto draw with their respective ticket count.\n participants: this.children.map((child, index) => [child, this.weights?.[index] || 1])\n });\n\n // Randomly pick a child based on ticket weighting, this will become the active child for this composite node.\n this.selectedChild = lottoDraw.draw() || undefined;\n }\n\n // If something went wrong and we don't have an active child then we should throw an error.\n if (!this.selectedChild) {\n throw new Error(\"failed to update lotto node as it has no active child\");\n }\n\n // If the selected child has never been updated or is running then we will need to update it now.\n if (this.selectedChild.getState() === State.READY || this.selectedChild.getState() === State.RUNNING) {\n this.selectedChild.update(agent, options);\n }\n\n // The state of the lotto node is the state of its selected child.\n this.setState(this.selectedChild.getState());\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => (this.weights ? `LOTTO [${this.weights.join(\",\")}]` : \"LOTTO\");\n}\n", "import Node from \"../Node\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\n\n/**\n * A decorator node that wraps a single child node.\n */\nexport default abstract class Decorator extends Node {\n /**\n * @param type The node type.\n * @param attributes The node attributes.\n * @param child The child node.\n */\n constructor(type: string, attributes: Attribute[], protected child: Node) {\n super(type, attributes, []);\n }\n\n /**\n * Gets whether this node is a leaf node.\n */\n isLeafNode = () => false;\n\n /**\n * Gets the children of this node.\n */\n getChildren = () => [this.child];\n\n /**\n * Reset the state of the node.\n */\n reset = () => {\n // Reset the state of this node.\n this.setState(State.READY);\n\n // Reset the state of the child node.\n this.child.reset();\n };\n\n /**\n * Abort the running of this node.\n * @param agent The agent.\n */\n abort = (agent: Agent) => {\n // There is nothing to do if this node is not in the running state.\n if (!this.is(State.RUNNING)) {\n return;\n }\n\n // Abort the child node.\n this.child.abort(agent);\n\n // Reset the state of this node.\n this.reset();\n\n this.getAttribute(\"exit\")?.callAgentFunction(agent, false, true);\n };\n}\n", "import Node from \"../Node\";\nimport Decorator from \"./Decorator\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A Fail node.\n * This node wraps a single child and will always move to the 'FAILED' state when the child moves to a 'SUCCEEDED' or 'FAILED' state.\n */\nexport default class Fail extends Decorator {\n /**\n * @param attributes The node attributes.\n * @param child The child node.\n */\n constructor(attributes: Attribute[], child: Node) {\n super(\"fail\", attributes, child);\n }\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // If the child has never been updated or is running then we will need to update it now.\n if (this.child.getState() === State.READY || this.child.getState() === State.RUNNING) {\n this.child.update(agent, options);\n }\n\n // The state of this node will depend in the state of its child.\n switch (this.child.getState()) {\n case State.RUNNING:\n this.setState(State.RUNNING);\n break;\n\n case State.SUCCEEDED:\n case State.FAILED:\n this.setState(State.FAILED);\n break;\n\n default:\n this.setState(State.READY);\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => \"FAIL\";\n}\n", "import Decorator from \"./Decorator\";\nimport State from \"../../State\";\nimport Node from \"../Node\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A Flip node.\n * This node wraps a single child and will flip the state of the child state.\n */\nexport default class Flip extends Decorator {\n /**\n * @param attributes The node attributes.\n * @param child The child node.\n */\n constructor(attributes: Attribute[], child: Node) {\n super(\"flip\", attributes, child);\n }\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // If the child has never been updated or is running then we will need to update it now.\n if (this.child.getState() === State.READY || this.child.getState() === State.RUNNING) {\n this.child.update(agent, options);\n }\n\n // The state of this node will depend in the state of its child.\n switch (this.child.getState()) {\n case State.RUNNING:\n this.setState(State.RUNNING);\n break;\n\n case State.SUCCEEDED:\n this.setState(State.FAILED);\n break;\n\n case State.FAILED:\n this.setState(State.SUCCEEDED);\n break;\n\n default:\n this.setState(State.READY);\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => \"FLIP\";\n}\n", "import Node from \"../Node\";\nimport Decorator from \"./Decorator\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A REPEAT node.\n * The node has a single child which can have:\n * -- A number of iterations for which to repeat the child node.\n * -- An infinite repeat loop if neither an iteration count or a condition function is defined.\n * The REPEAT node will stop and have a 'FAILED' state if its child is ever in a 'FAILED' state after an update.\n * The REPEAT node will attempt to move on to the next iteration if its child is ever in a 'SUCCEEDED' state.\n */\nexport default class Repeat extends Decorator {\n /**\n * @param attributes The node attributes.\n * @param iterations The number of iterations to repeat the child node.\n * @param iterationsMin The minimum possible number of iterations to repeat the child node.\n * @param iterationsMax The maximum possible number of iterations to repeat the child node.\n * @param child The child node.\n */\n constructor(\n attributes: Attribute[],\n private iterations: number | null,\n private iterationsMin: number | null,\n private iterationsMax: number | null,\n child: Node\n ) {\n super(\"repeat\", attributes, child);\n }\n\n /**\n * The number of target iterations to make.\n */\n private targetIterationCount: number | null = null;\n\n /**\n * The current iteration count.\n */\n private currentIterationCount: number = 0;\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // If this node is in the READY state then we need to reset the child and the target iteration count.\n if (this.is(State.READY)) {\n // Reset the child node.\n this.child.reset();\n\n // Reset the current iteration count.\n this.currentIterationCount = 0;\n\n // Set the target iteration count.\n this.setTargetIterationCount(options);\n }\n\n // Do a check to see if we can iterate. If we can then this node will move into the 'RUNNING' state.\n // If we cannot iterate then we have hit our target iteration count, which means that the node has succeeded.\n if (this.canIterate()) {\n // This node is in the running state and can do its initial iteration.\n this.setState(State.RUNNING);\n\n // We may have already completed an iteration, meaning that the child node will be in the SUCCEEDED state.\n // If this is the case then we will have to reset the child node now.\n if (this.child.getState() === State.SUCCEEDED) {\n this.child.reset();\n }\n\n // Update the child of this node.\n this.child.update(agent, options);\n\n // If the child moved into the FAILED state when we updated it then there is nothing left to do and this node has also failed.\n // If it has moved into the SUCCEEDED state then we have completed the current iteration.\n if (this.child.getState() === State.FAILED) {\n // The child has failed, meaning that this node has failed.\n this.setState(State.FAILED);\n\n return;\n } else if (this.child.getState() === State.SUCCEEDED) {\n // We have completed an iteration.\n this.currentIterationCount += 1;\n }\n } else {\n // This node is in the 'SUCCEEDED' state as we cannot iterate any more.\n this.setState(State.SUCCEEDED);\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => {\n if (this.iterations !== null) {\n return `REPEAT ${this.iterations}x`;\n } else if (this.iterationsMin !== null && this.iterationsMax !== null) {\n return `REPEAT ${this.iterationsMin}x-${this.iterationsMax}x`;\n } else {\n return \"REPEAT\";\n }\n };\n\n /**\n * Reset the state of the node.\n */\n reset = () => {\n // Reset the state of this node.\n this.setState(State.READY);\n\n // Reset the current iteration count.\n this.currentIterationCount = 0;\n\n // Reset the child node.\n this.child.reset();\n };\n\n /**\n * Gets whether an iteration can be made.\n * @returns Whether an iteration can be made.\n */\n private canIterate = () => {\n if (this.targetIterationCount !== null) {\n // We can iterate as long as we have not reached our target iteration count.\n return this.currentIterationCount < this.targetIterationCount;\n }\n\n // If neither an iteration count or a condition function were defined then we can iterate indefinitely.\n return true;\n };\n\n /**\n * Sets the target iteration count.\n * @param options The behaviour tree options object.\n */\n private setTargetIterationCount = (options: BehaviourTreeOptions) => {\n // Are we dealing with an explicit iteration count or will we be randomly picking a iteration count between the min and max iteration count.\n if (this.iterations !== null) {\n this.targetIterationCount = this.iterations;\n } else if (this.iterationsMin !== null && this.iterationsMax !== null) {\n // We will be picking a random iteration count between a min and max iteration count, if the optional 'random'\n // behaviour tree function option is defined then we will be using that, otherwise we will fall back to using Math.random.\n const random = typeof options.random === \"function\" ? options.random : Math.random;\n\n // Pick a random iteration count between a min and max iteration count.\n this.targetIterationCount = Math.floor(\n random() * (this.iterationsMax - this.iterationsMin + 1) + this.iterationsMin\n );\n } else {\n this.targetIterationCount = null;\n }\n };\n}\n", "import Node from \"../Node\";\nimport Decorator from \"./Decorator\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A RETRY node.\n * The node has a single child which can have:\n * -- A number of iterations for which to repeat the child node.\n * -- An infinite repeat loop if neither an iteration count or a condition function is defined.\n * The RETRY node will stop and have a 'SUCCEEDED' state if its child is ever in a 'SUCCEEDED' state after an update.\n * The RETRY node will attempt to move on to the next iteration if its child is ever in a 'FAILED' state.\n */\nexport default class Retry extends Decorator {\n /**\n * @param attributes The node attributes.\n * @param attempts The number of attempts to retry the child node.\n * @param attemptsMin The minimum possible number of attempts to retry the child node.\n * @param attemptsMax The maximum possible number of attempts to retry the child node.\n * @param child The child node.\n */\n constructor(\n attributes: Attribute[],\n private attempts: number | null,\n private attemptsMin: number | null,\n private attemptsMax: number | null,\n child: Node\n ) {\n super(\"retry\", attributes, child);\n }\n\n /**\n * The number of target attempts to make.\n */\n private targetAttemptCount: number | null = null;\n\n /**\n * The current attempt count.\n */\n private currentAttemptCount: number = 0;\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // If this node is in the READY state then we need to reset the child and the target attempt count.\n if (this.is(State.READY)) {\n // Reset the child node.\n this.child.reset();\n\n // Reset the current attempt count.\n this.currentAttemptCount = 0;\n\n // Set the target attempt count.\n this.setTargetAttemptCount(options);\n }\n\n // Do a check to see if we can attempt. If we can then this node will move into the 'RUNNING' state.\n // If we cannot attempt then we have hit our target attempt count, which means that the node has succeeded.\n if (this.canAttempt()) {\n // This node is in the running state and can do its initial attempt.\n this.setState(State.RUNNING);\n\n // We may have already completed an attempt, meaning that the child node will be in the FAILED state.\n // If this is the case then we will have to reset the child node now.\n if (this.child.getState() === State.FAILED) {\n this.child.reset();\n }\n\n // Update the child of this node.\n this.child.update(agent, options);\n\n // If the child moved into the SUCCEEDED state when we updated it then there is nothing left to do and this node has also succeeded.\n // If it has moved into the FAILED state then we have completed the current attempt.\n if (this.child.getState() === State.SUCCEEDED) {\n // The child has succeeded, meaning that this node has succeeded.\n this.setState(State.SUCCEEDED);\n\n return;\n } else if (this.child.getState() === State.FAILED) {\n // We have completed an attempt.\n this.currentAttemptCount += 1;\n }\n } else {\n // This node is in the 'FAILED' state as we cannot iterate any more.\n this.setState(State.FAILED);\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => {\n if (this.attempts !== null) {\n return `RETRY ${this.attempts}x`;\n } else if (this.attemptsMin !== null && this.attemptsMax !== null) {\n return `RETRY ${this.attemptsMin}x-${this.attemptsMax}x`;\n } else {\n return \"RETRY\";\n }\n };\n\n /**\n * Reset the state of the node.\n */\n reset = () => {\n // Reset the state of this node.\n this.setState(State.READY);\n\n // Reset the current attempt count.\n this.currentAttemptCount = 0;\n\n // Reset the child node.\n this.child.reset();\n };\n\n /**\n * Gets whether an attempt can be made.\n * @returns Whether an attempt can be made.\n */\n canAttempt = () => {\n if (this.targetAttemptCount !== null) {\n // We can attempt as long as we have not reached our target attempt count.\n return this.currentAttemptCount < this.targetAttemptCount;\n }\n\n // If neither an attempt count or a condition function were defined then we can attempt indefinitely.\n return true;\n };\n\n /**\n * Sets the target attempt count.\n * @param options The behaviour tree options object.\n */\n setTargetAttemptCount = (options: BehaviourTreeOptions) => {\n // Are we dealing with an explicit attempt count or will we be randomly picking an attempt count between the min and max attempt count.\n if (this.attempts !== null) {\n this.targetAttemptCount = this.attempts;\n } else if (this.attemptsMin !== null && this.attemptsMax !== null) {\n // We will be picking a random attempt count between a min and max attempt count, if the optional 'random'\n // behaviour tree function option is defined then we will be using that, otherwise we will fall back to using Math.random.\n const random = typeof options.random === \"function\" ? options.random : Math.random;\n\n // Pick a random attempt count between a min and max attempt count.\n this.targetAttemptCount = Math.floor(\n random() * (this.attemptsMax - this.attemptsMin + 1) + this.attemptsMin\n );\n } else {\n this.targetAttemptCount = null;\n }\n };\n}\n", "import Node from \"../Node\";\nimport Decorator from \"./Decorator\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A Root node.\n * The root node will have a single child.\n */\nexport default class Root extends Decorator {\n /**\n * @param attributes The node attributes.\n * @param child The child node.\n */\n constructor(attributes: Attribute[], child: Node) {\n super(\"root\", attributes, child);\n }\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // If the child has never been updated or is running then we will need to update it now.\n if (this.child.getState() === State.READY || this.child.getState() === State.RUNNING) {\n // Update the child of this node.\n this.child.update(agent, options);\n }\n\n // The state of the root node is the state of its child.\n this.setState(this.child.getState());\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => \"ROOT\";\n}\n", "import Node from \"../Node\";\nimport Decorator from \"./Decorator\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A Succeed node.\n * This node wraps a single child and will always move to the 'SUCCEEDED' state when the child moves to a 'SUCCEEDED' or 'FAILED' state.\n */\nexport default class Succeed extends Decorator {\n /**\n * @param attributes The node attributes.\n * @param child The child node.\n */\n constructor(attributes: Attribute[], child: Node) {\n super(\"succeed\", attributes, child);\n }\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // If the child has never been updated or is running then we will need to update it now.\n if (this.child.getState() === State.READY || this.child.getState() === State.RUNNING) {\n this.child.update(agent, options);\n }\n\n // The state of this node will depend in the state of its child.\n switch (this.child.getState()) {\n case State.RUNNING:\n this.setState(State.RUNNING);\n break;\n\n case State.SUCCEEDED:\n case State.FAILED:\n this.setState(State.SUCCEEDED);\n break;\n\n default:\n this.setState(State.READY);\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => \"SUCCEED\";\n}\n", "import Node from \"../Node\";\n\n/**\n * A leaf node.\n */\nexport default abstract class Leaf extends Node {\n /**\n * Gets whether this node is a leaf node.\n */\n isLeafNode = () => true;\n}\n", "import { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\nimport State, { CompleteState } from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Leaf from \"./Leaf\";\nimport Lookup from \"../../Lookup\";\nimport Attribute from \"../../attributes/Attribute\";\n\n/**\n * An Action leaf node.\n * This represents an immediate or ongoing state of behaviour.\n */\nexport default class Action extends Leaf {\n /**\n * @param attributes The node attributes.\n * @param actionName The action name.\n * @param actionArguments The array of action argument definitions.\n */\n constructor(attributes: Attribute[], private actionName: string, private actionArguments: any[]) {\n super(\"action\", attributes, actionArguments);\n }\n\n /**\n * Whether there is a pending update promise.\n */\n private isUsingUpdatePromise = false;\n\n /**\n * The finished state result of an update promise.\n */\n private updatePromiseStateResult: CompleteState | null = null;\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // If the result of this action depends on an update promise then there is nothing to do until\n // it resolves, unless there has been a value set as a result of the update promise resolving.\n if (this.isUsingUpdatePromise) {\n // Check whether the update promise has resolved with a state value.\n if (this.updatePromiseStateResult) {\n // Set the state of this node to match the state returned by the promise.\n this.setState(this.updatePromiseStateResult);\n }\n\n return;\n }\n\n // Attempt to get the invoker for the action function.\n const actionFuncInvoker = Lookup.getFuncInvoker(agent, this.actionName);\n\n // The action function should be defined.\n if (actionFuncInvoker === null) {\n throw new Error(\n `cannot update action node as the action '${this.actionName}' function is not defined on the agent and has not been registered`\n );\n }\n\n let actionFunctionResult;\n\n try {\n // Call the action function, the result of which may be:\n // - The finished state of this action node.\n // - A promise to return a finished node state.\n // - Undefined if the node should remain in the running state.\n actionFunctionResult = actionFuncInvoker(this.actionArguments) as CompleteState | Promise;\n } catch (error) {\n // The user was naughty and threw something.\n throw new Error(`action function '${this.actionName}' threw '${error}'`);\n }\n\n if (actionFunctionResult instanceof Promise) {\n actionFunctionResult.then(\n (result) => {\n // If 'isUpdatePromisePending' is null then the promise was cleared as it was resolving, probably via an abort of reset.\n if (!this.isUsingUpdatePromise) {\n return;\n }\n\n // Check to make sure the result is a valid finished state.\n if (result !== State.SUCCEEDED && result !== State.FAILED) {\n throw new Error(\n \"action node promise resolved with an invalid value, expected a State.SUCCEEDED or State.FAILED value to be returned\"\n );\n }\n\n // Set pending update promise state result to be processed on next update.\n this.updatePromiseStateResult = result;\n },\n (reason) => {\n // If 'isUpdatePromisePending' is null then the promise was cleared as it was resolving, probably via an abort or reset.\n if (!this.isUsingUpdatePromise) {\n return;\n }\n\n // TODO We shouldn't throw an error here, we actually need to set this.updatePromiseRejectionReason so that it can be thrown on the next tree.step() call.\n\n // The promise was rejected, which isn't great.\n throw new Error(`action function '${this.actionName}' promise rejected with reason '${reason}'`);\n }\n );\n\n // This node will be in the 'RUNNING' state until the update promise resolves.\n this.setState(State.RUNNING);\n\n // We are now waiting for the promise returned by the use to resolve before we know what state this node is in.\n this.isUsingUpdatePromise = true;\n } else {\n // Validate the returned value.\n this.validateUpdateResult(actionFunctionResult);\n\n // Set the state of this node, this may be undefined, which just means that the node is still in the 'RUNNING' state.\n this.setState(actionFunctionResult || State.RUNNING);\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => this.actionName;\n\n /**\n * Reset the state of the node.\n */\n reset = () => {\n // Reset the state of this node.\n this.setState(State.READY);\n\n // There is no longer an update promise that we care about.\n this.isUsingUpdatePromise = false;\n this.updatePromiseStateResult = null;\n };\n\n /**\n * Validate the result of an update function call.\n * @param result The result of an update function call.\n */\n private validateUpdateResult = (result: CompleteState | boolean) => {\n switch (result) {\n case State.SUCCEEDED:\n case State.FAILED:\n case undefined:\n return;\n default:\n throw new Error(\n `action '${this.actionName}' 'onUpdate' returned an invalid response, expected an optional State.SUCCEEDED or State.FAILED value to be returned`\n );\n }\n };\n}\n", "import { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Leaf from \"./Leaf\";\nimport Lookup from \"../../Lookup\";\nimport Attribute from \"../../attributes/Attribute\";\n\n/**\n * A Condition leaf node.\n * This will succeed or fail immediately based on an agent predicate, without moving to the 'RUNNING' state.\n */\nexport default class Condition extends Leaf {\n /**\n * @param attributes The node attributes.\n * @param conditionName The name of the condition function.\n * @param conditionArguments The array of condition argument definitions.\n */\n constructor(attributes: Attribute[], private conditionName: string, private conditionArguments: any[]) {\n super(\"condition\", attributes, conditionArguments);\n }\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // Attempt to get the invoker for the condition function.\n const conditionFuncInvoker = Lookup.getFuncInvoker(agent, this.conditionName);\n\n // The condition function should be defined.\n if (conditionFuncInvoker === null) {\n throw new Error(\n `cannot update condition node as the condition '${this.conditionName}' function is not defined on the agent and has not been registered`\n );\n }\n\n let conditionFunctionResult;\n\n try {\n // Call the condition function to determine the state of this node, the result of which should be a boolean.\n conditionFunctionResult = conditionFuncInvoker(this.conditionArguments);\n } catch (error) {\n // The user was naughty and threw something.\n throw new Error(`condition function '${this.conditionName}' threw '${error}'`);\n }\n\n // The result of calling the condition function must be a boolean value.\n if (typeof conditionFunctionResult !== \"boolean\") {\n throw new Error(\n `expected condition function '${this.conditionName}' to return a boolean but returned '${conditionFunctionResult}'`\n );\n }\n\n // Set the state of this node based on the result of calling the condition function.\n this.setState(!!conditionFunctionResult ? State.SUCCEEDED : State.FAILED);\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => this.conditionName;\n}\n", "import Leaf from \"./Leaf\";\nimport State from \"../../State\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { Agent } from \"../../Agent\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A WAIT node.\n * The state of this node will change to SUCCEEDED after a duration of time\n */\nexport default class Wait extends Leaf {\n /**\n * @param attributes The node attributes.\n * @param duration The duration that this node will wait to succeed in milliseconds.\n * @param durationMin The minimum possible duration in milliseconds that this node will wait to succeed.\n * @param durationMax The maximum possible duration in milliseconds that this node will wait to succeed.\n */\n constructor(\n attributes: Attribute[],\n private duration: number | null,\n private durationMin: number | null,\n private durationMax: number | null\n ) {\n super(\"wait\", attributes, []);\n }\n\n /**\n * The time in milliseconds at which this node was first updated.\n */\n private initialUpdateTime: number = 0;\n\n /**\n * The total duration in milliseconds that this node will be waiting for.\n */\n private totalDuration: number | null = null;\n\n /**\n * The duration in milliseconds that this node has been waiting for.\n */\n private waitedDuration: number = 0;\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // If this node is in the READY state then we need to set the initial update time.\n if (this.is(State.READY)) {\n // Set the initial update time.\n this.initialUpdateTime = new Date().getTime();\n\n // Set the initial waited duration.\n this.waitedDuration = 0;\n\n // Are we dealing with an explicit duration or will we be randomly picking a duration between the min and max duration.\n if (this.duration !== null) {\n this.totalDuration = this.duration;\n } else if (this.durationMin !== null && this.durationMax !== null) {\n // We will be picking a random duration between a min and max duration, if the optional 'random' behaviour tree\n // function option is defined then we will be using that, otherwise we will fall back to using Math.random.\n const random = typeof options.random === \"function\" ? options.random : Math.random;\n\n // Pick a random duration between a min and max duration.\n this.totalDuration = Math.floor(\n random() * (this.durationMax - this.durationMin + 1) + this.durationMin\n );\n } else {\n this.totalDuration = null;\n }\n\n // The node is now running until we finish waiting.\n this.setState(State.RUNNING);\n }\n\n // If we have no total duration then this wait node will wait indefinitely until it is aborted.\n if (this.totalDuration === null) {\n return;\n }\n\n // If we have a 'getDeltaTime' function defined as part of our options then we will use it to figure out how long we have waited for.\n if (typeof options.getDeltaTime === \"function\") {\n // Get the delta time.\n const deltaTime = options.getDeltaTime();\n\n // Our delta time must be a valid number and cannot be NaN.\n if (typeof deltaTime !== \"number\" || isNaN(deltaTime)) {\n throw new Error(\"The delta time must be a valid number and not NaN.\");\n }\n\n // Update the amount of time that this node has been waiting for based on the delta time.\n this.waitedDuration += deltaTime * 1000;\n } else {\n // We are not using a delta time, so we will just work out hom much time has passed since the first update.\n this.waitedDuration = new Date().getTime() - this.initialUpdateTime;\n }\n\n // Have we waited long enough?\n if (this.waitedDuration >= this.totalDuration) {\n // We have finished waiting!\n this.setState(State.SUCCEEDED);\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => {\n if (this.duration !== null) {\n return `WAIT ${this.duration}ms`;\n } else if (this.durationMin !== null && this.durationMax !== null) {\n return `WAIT ${this.durationMin}ms-${this.durationMax}ms`;\n } else {\n return \"WAIT\";\n }\n };\n}\n", "import Guard from \"./guards/Guard\";\n\nexport type AttributeDetails = {\n /** The attribute type. */\n type: string;\n\n /** The attribute arguments. */\n args: any[];\n};\n\n/**\n * A base node attribute.\n */\nexport default abstract class Attribute {\n /**\n * @param type The node attribute type.\n * @param args The array of attribute arguments.\n */\n constructor(public type: string, public args: any[]) {}\n\n /**\n * Gets the attribute details.\n */\n abstract getDetails(): TAttributeDetails;\n\n /**\n * Gets whether this attribute is a guard.\n */\n abstract isGuard: () => this is Guard;\n}\n", "import { Agent } from \"../../Agent\";\nimport Attribute, { AttributeDetails } from \"../Attribute\";\n\nexport type GuardAttributeDetails = {\n /** The name of the condition function that determines whether the guard is satisfied. */\n condition: string;\n} & AttributeDetails;\n\n/**\n * A base node guard attribute.\n */\nexport default abstract class Guard extends Attribute {\n /**\n * @param type The node attribute type.\n * @param args The array of decorator argument definitions.\n * @param condition The name of the condition function that determines whether the guard is satisfied.\n */\n constructor(type: string, args: any[], private condition: string) {\n super(type, args);\n }\n\n /**\n * Gets the name of the condition function that determines whether the guard is satisfied.\n */\n getCondition = () => this.condition;\n\n /**\n * Gets whether this attribute is a guard.\n */\n isGuard = () => true;\n\n /**\n * Gets the attribute details.\n */\n getDetails(): GuardAttributeDetails {\n return {\n type: this.type,\n args: this.args,\n condition: this.getCondition()\n };\n }\n\n /**\n * Gets whether the guard is satisfied.\n * @param agent The agent.\n * @returns Whether the guard is satisfied.\n */\n abstract isSatisfied(agent: Agent): boolean;\n}\n", "import Guard from \"./Guard\";\nimport Lookup from \"../../Lookup\";\nimport { Agent } from \"../../Agent\";\n\n/**\n * A WHILE guard which is satisfied as long as the given condition remains true.\n */\nexport default class While extends Guard {\n /**\n * @param condition The name of the condition function that determines whether the guard is satisfied.\n * @param args The array of decorator argument definitions.\n */\n constructor(condition: string, args: any[]) {\n super(\"while\", args, condition);\n }\n\n /**\n * Gets whether the guard is satisfied.\n * @param agent The agent.\n * @returns Whether the guard is satisfied.\n */\n isSatisfied = (agent: Agent) => {\n // Attempt to get the invoker for the condition function.\n const conditionFuncInvoker = Lookup.getFuncInvoker(agent, this.getCondition());\n\n // The condition function should be defined.\n if (conditionFuncInvoker === null) {\n throw new Error(\n `cannot evaluate node guard as the condition '${this.getCondition()}' function is not defined on the agent and has not been registered`\n );\n }\n\n // Call the condition function to determine whether this guard is satisfied.\n return !!conditionFuncInvoker(this.args);\n };\n}\n", "import Guard from \"./Guard\";\nimport Lookup from \"../../Lookup\";\nimport { Agent } from \"../../Agent\";\n\n/**\n * An UNTIL guard which is satisfied as long as the given condition remains false.\n */\nexport default class Until extends Guard {\n /**\n * @param condition The name of the condition function that determines whether the guard is satisfied.\n * @param args The array of decorator argument definitions.\n */\n constructor(condition: string, args: any[]) {\n super(\"until\", args, condition);\n }\n\n /**\n * Gets whether the guard is satisfied.\n * @param agent The agent.\n * @returns Whether the guard is satisfied.\n */\n isSatisfied = (agent: Agent) => {\n // Attempt to get the invoker for the condition function.\n const conditionFuncInvoker = Lookup.getFuncInvoker(agent, this.getCondition());\n\n // The condition function should be defined.\n if (conditionFuncInvoker === null) {\n throw new Error(\n `cannot evaluate node guard as the condition '${this.getCondition()}' function is not defined on the agent and has not been registered`\n );\n }\n\n // Call the condition function to determine whether this guard is satisfied.\n return !!!conditionFuncInvoker(this.args);\n };\n}\n", "import { Agent } from \"../../Agent\";\nimport Attribute, { AttributeDetails } from \"../Attribute\";\n\nexport type CallbackAttributeDetails = {\n /** The name of the agent function that is called. */\n functionName: string;\n} & AttributeDetails;\n\n/**\n * A base node callback attribute.\n */\nexport default abstract class Callback extends Attribute {\n /**\n * @param type The node attribute type.\n * @param args The array of decorator argument definitions.\n * @param functionName The name of the agent function to call.\n */\n constructor(type: string, args: any[], private functionName: string) {\n super(type, args);\n }\n\n /**\n * Gets the name of the agent function to call.\n */\n getFunctionName = () => this.functionName;\n\n /**\n * Gets whether this attribute is a guard.\n */\n isGuard = () => false;\n\n /**\n * Gets the attribute details.\n */\n getDetails(): CallbackAttributeDetails {\n return {\n type: this.type,\n args: this.args,\n functionName: this.getFunctionName()\n };\n }\n\n /**\n * Attempt to call the agent function that this callback refers to.\n * @param agent The agent.\n */\n abstract callAgentFunction: (agent: Agent, isSuccess: boolean, isAborted: boolean) => void;\n}\n", "import Callback from \"./Callback\";\nimport Lookup from \"../../Lookup\";\nimport { Agent } from \"../../Agent\";\n\n/**\n * An ENTRY callback which defines an agent function to call when the associated node is updated and moves out of running state.\n */\nexport default class Entry extends Callback {\n /**\n * @param functionName The name of the agent function to call.\n * @param args The array of callback argument definitions.\n */\n constructor(functionName: string, args: any[]) {\n super(\"entry\", args, functionName);\n }\n\n /**\n * Attempt to call the agent function that this callback refers to.\n * @param agent The agent.\n */\n callAgentFunction = (agent: Agent) => {\n // Attempt to get the invoker for the callback function.\n const callbackFuncInvoker = Lookup.getFuncInvoker(agent, this.getFunctionName());\n\n // The callback function should be defined.\n if (callbackFuncInvoker === null) {\n throw new Error(\n `cannot call entry function '${this.getFunctionName()}' as is not defined on the agent and has not been registered`\n );\n }\n\n // Call the callback function.\n callbackFuncInvoker(this.args);\n };\n}\n", "import Callback from \"./Callback\";\nimport Lookup from \"../../Lookup\";\nimport { Agent } from \"../../Agent\";\n\n/**\n * A STEP callback which defines an agent function to call when the associated node is updated.\n */\nexport default class Step extends Callback {\n /**\n * @param functionName The name of the agent function to call.\n * @param args The array of callback argument definitions.\n */\n constructor(functionName: string, args: any[]) {\n super(\"step\", args, functionName);\n }\n\n /**\n * Attempt to call the agent function that this callback refers to.\n * @param agent The agent.\n */\n callAgentFunction = (agent: Agent) => {\n // Attempt to get the invoker for the callback function.\n const callbackFuncInvoker = Lookup.getFuncInvoker(agent, this.getFunctionName());\n\n // The callback function should be defined.\n if (callbackFuncInvoker === null) {\n throw new Error(\n `cannot call step function '${this.getFunctionName()}' as is not defined on the agent and has not been registered`\n );\n }\n\n // Call the callback function.\n callbackFuncInvoker(this.args);\n };\n}\n", "import Callback from \"./Callback\";\nimport Lookup from \"../../Lookup\";\nimport { Agent } from \"../../Agent\";\n\n/**\n * An EXIT callback which defines an agent function to call when the associated node is updated and moves to a finished state or is aborted.\n */\nexport default class Exit extends Callback {\n /**\n * @param functionName The name of the agent function to call.\n * @param args The array of callback argument definitions.\n */\n constructor(functionName: string, args: any[]) {\n super(\"exit\", args, functionName);\n }\n\n /**\n * Attempt to call the agent function that this callback refers to.\n * @param agent The agent.\n * @param isSuccess Whether the decorated node was left with a success state.\n * @param isAborted Whether the decorated node was aborted.\n */\n callAgentFunction = (agent: Agent, isSuccess: boolean, isAborted: boolean) => {\n // Attempt to get the invoker for the callback function.\n const callbackFuncInvoker = Lookup.getFuncInvoker(agent, this.getFunctionName());\n\n // The callback function should be defined.\n if (callbackFuncInvoker === null) {\n throw new Error(\n `cannot call exit function '${this.getFunctionName()}' as is not defined on the agent and has not been registered`\n );\n }\n\n // Call the callback function\n callbackFuncInvoker([{ value: { succeeded: isSuccess, aborted: isAborted } }, ...this.args]);\n };\n}\n", "import { AnyNodeDefinition, RootNodeDefinition } from \"./BehaviourTreeDefinition\";\nimport GuardPath, { GuardPathPart } from \"./attributes/guards/GuardPath\";\nimport { validateBranchSubtreeLinks } from \"./BehaviourTreeDefinitionValidator\";\nimport { isInteger } from \"./BehaviourTreeDefinitionUtilities\";\nimport Node from \"./nodes/Node\";\nimport Composite from \"./nodes/composite/Composite\";\nimport Decorator from \"./nodes/decorator/Decorator\";\nimport Parallel from \"./nodes/composite/Parallel\";\nimport Selector from \"./nodes/composite/Selector\";\nimport Sequence from \"./nodes/composite/Sequence\";\nimport Lotto from \"./nodes/composite/Lotto\";\nimport Fail from \"./nodes/decorator/Fail\";\nimport Flip from \"./nodes/decorator/Flip\";\nimport Repeat from \"./nodes/decorator/Repeat\";\nimport Retry from \"./nodes/decorator/Retry\";\nimport Root from \"./nodes/decorator/Root\";\nimport Succeed from \"./nodes/decorator/Succeed\";\nimport Action from \"./nodes/leaf/Action\";\nimport Condition from \"./nodes/leaf/Condition\";\nimport Wait from \"./nodes/leaf/Wait\";\nimport Lookup from \"./Lookup\";\nimport Attribute from \"./attributes/Attribute\";\nimport While from \"./attributes/guards/While\";\nimport Until from \"./attributes/guards/Until\";\nimport Entry from \"./attributes/callbacks/Entry\";\nimport Step from \"./attributes/callbacks/Step\";\nimport Exit from \"./attributes/callbacks/Exit\";\n\n/**\n * A type representing any node instance in a behaviour tree.\n */\ntype AnyNode =\n | Root\n | Action\n | Condition\n | Wait\n | Sequence\n | Selector\n | Lotto\n | Parallel\n | Repeat\n | Retry\n | Flip\n | Succeed\n | Fail;\n\n/**\n * A type defining a mapping of root node identifiers to root node definitions.\n */\ntype RootNodeDefinitionMap = { [key: string | symbol]: RootNodeDefinition };\n\n/**\n * A symbol to use as the main root key in any root node mappings.\n */\nconst MAIN_ROOT_NODE_KEY = Symbol(\"__root__\");\n\n/**\n * Build and populate the root nodes based on the provided definition, assuming that the definition has been validated.\n * @param definition The root node definitions.\n * @returns The built and populated root node definitions.\n */\nexport default function buildRootNode(definition: RootNodeDefinition[]): Root {\n // Create a mapping of root node identifers to root node definitions, including globally registered subtree root node definitions.\n const rootNodeDefinitionMap = createRootNodeDefinitionMap(definition);\n\n // Now that we have all of our root node definitons (those part of the tree definition and those globally\n // registered) we should validate the definition. This will also double-check that we dont have any circular\n // dependencies in our branch -> subtree references and that we have no broken branch -> subtree links.\n validateBranchSubtreeLinks(definition, true);\n\n // Create our populated tree of node instances, starting with our main root node.\n const rootNode = nodeFactory(rootNodeDefinitionMap[MAIN_ROOT_NODE_KEY], rootNodeDefinitionMap) as Root;\n\n // Set a guard path on every leaf of the tree to evaluate as part of each update.\n applyLeafNodeGuardPaths(rootNode);\n\n // We only need to return the main root node.\n return rootNode;\n}\n\n/**\n * A factory function which creates a node instance based on the specified definition.\n * @param definition The node definition.\n * @param rootNodeDefinitionMap The mapping of root node identifers to root node definitions, including globally registered subtree root node definitions.\n * @returns A node instance based on the specified definition.\n */\nfunction nodeFactory(definition: AnyNodeDefinition, rootNodeDefinitionMap: RootNodeDefinitionMap): AnyNode {\n // Get the attributes for the node.\n const attributes = nodeAttributesFactory(definition);\n\n // Create the node instance based on the definition type.\n switch (definition.type) {\n case \"root\":\n return new Root(attributes, nodeFactory(definition.child, rootNodeDefinitionMap));\n\n case \"repeat\":\n let iterations: number | null = null;\n let iterationsMin: number | null = null;\n let iterationsMax: number | null = null;\n\n if (Array.isArray(definition.iterations)) {\n iterationsMin = definition.iterations[0];\n iterationsMax = definition.iterations[1];\n } else if (isInteger(definition.iterations)) {\n iterations = definition.iterations!;\n }\n\n return new Repeat(\n attributes,\n iterations,\n iterationsMin,\n iterationsMax,\n nodeFactory(definition.child, rootNodeDefinitionMap)\n );\n\n case \"retry\":\n let attempts: number | null = null;\n let attemptsMin: number | null = null;\n let attemptsMax: number | null = null;\n\n if (Array.isArray(definition.attempts)) {\n attemptsMin = definition.attempts[0];\n attemptsMax = definition.attempts[1];\n } else if (isInteger(definition.attempts)) {\n attempts = definition.attempts!;\n }\n\n return new Retry(\n attributes,\n attempts,\n attemptsMin,\n attemptsMax,\n nodeFactory(definition.child, rootNodeDefinitionMap)\n );\n\n case \"flip\":\n return new Flip(attributes, nodeFactory(definition.child, rootNodeDefinitionMap));\n\n case \"succeed\":\n return new Succeed(attributes, nodeFactory(definition.child, rootNodeDefinitionMap));\n\n case \"fail\":\n return new Fail(attributes, nodeFactory(definition.child, rootNodeDefinitionMap));\n\n case \"sequence\":\n return new Sequence(\n attributes,\n definition.children.map((child) => nodeFactory(child, rootNodeDefinitionMap))\n );\n\n case \"selector\":\n return new Selector(\n attributes,\n definition.children.map((child) => nodeFactory(child, rootNodeDefinitionMap))\n );\n\n case \"parallel\":\n return new Parallel(\n attributes,\n definition.children.map((child) => nodeFactory(child, rootNodeDefinitionMap))\n );\n\n case \"lotto\":\n return new Lotto(\n attributes,\n definition.weights,\n definition.children.map((child) => nodeFactory(child, rootNodeDefinitionMap))\n );\n\n case \"branch\":\n return nodeFactory(rootNodeDefinitionMap[definition.ref].child, rootNodeDefinitionMap);\n\n case \"action\":\n return new Action(attributes, definition.call, definition.args || []);\n\n case \"condition\":\n return new Condition(attributes, definition.call, definition.args || []);\n\n case \"wait\":\n let duration: number | null = null;\n let durationMin: number | null = null;\n let durationMax: number | null = null;\n\n if (Array.isArray(definition.duration)) {\n durationMin = definition.duration[0];\n durationMax = definition.duration[1];\n } else if (isInteger(definition.duration)) {\n duration = definition.duration!;\n }\n\n return new Wait(attributes, duration, durationMin, durationMax);\n }\n}\n\n/**\n * Creates an array of node attribute instances based on the specified node definition.\n * @param definition The node definition.\n * @returns An array of node attribute instances based on the specified node definition.\n */\nfunction nodeAttributesFactory(definition: AnyNodeDefinition): Attribute[] {\n const attributes: Attribute[] = [];\n\n if (definition.while) {\n attributes.push(new While(definition.while.call, definition.while.args ?? []));\n }\n\n if (definition.until) {\n attributes.push(new Until(definition.until.call, definition.until.args ?? []));\n }\n\n if (definition.entry) {\n attributes.push(new Entry(definition.entry.call, definition.entry.args ?? []));\n }\n\n if (definition.step) {\n attributes.push(new Step(definition.step.call, definition.step.args ?? []));\n }\n\n if (definition.exit) {\n attributes.push(new Exit(definition.exit.call, definition.exit.args ?? []));\n }\n\n return attributes;\n}\n\n/**\n * Creates a mapping of root node identifers to root node definitions, mixing in globally registered subtree root node definitions.\n * @param definition The root node definitions.\n * @returns A mapping of root node identifers to root node definitions, including globally registered subtree root node definitions.\n */\nfunction createRootNodeDefinitionMap(definition: RootNodeDefinition[]): RootNodeDefinitionMap {\n // Create a mapping of root node identifers to root node definitions.\n const rootNodeMap: RootNodeDefinitionMap = {};\n\n // Add in any registered subtree root node definitions.\n for (const [name, rootNodeDefinition] of Object.entries(Lookup.getSubtrees())) {\n // The name used when registering the subtree will be used as the root node identifier.\n rootNodeMap[name] = { ...rootNodeDefinition, id: name };\n }\n\n // Populate the map with the root node definitions that were included with the tree definition.\n // We do this after adding any registered subtrees as we want these to take presedence.\n for (const rootNodeDefinition of definition) {\n rootNodeMap[rootNodeDefinition.id ?? MAIN_ROOT_NODE_KEY] = rootNodeDefinition;\n }\n\n return rootNodeMap;\n}\n\n/**\n * Applies a guard path to every leaf of the tree to evaluate as part of each update.\n * @param root The main root tree node.\n */\nfunction applyLeafNodeGuardPaths(root: Root) {\n const nodePaths: Node[][] = [];\n\n const findLeafNodes = (path: Node[], node: Node) => {\n // Add the current node to the path.\n path = path.concat(node);\n\n // Check whether the current node is a leaf node.\n if (node.isLeafNode()) {\n nodePaths.push(path);\n } else {\n (node as Composite | Decorator).getChildren().forEach((child) => findLeafNodes(path, child));\n }\n };\n\n // Find all leaf node paths, starting from the root.\n findLeafNodes([], root);\n\n nodePaths.forEach((path) => {\n // Each node in the current path will have to be assigned a guard path, working from the root outwards.\n for (let depth = 0; depth < path.length; depth++) {\n // Get the node in the path at the current depth.\n const currentNode = path[depth];\n\n // The node may already have been assigned a guard path, if so just skip it.\n if (currentNode.hasGuardPath()) {\n continue;\n }\n\n // Create the guard path for the current node.\n const guardPath = new GuardPath(\n path\n .slice(0, depth + 1)\n .map((node) => ({ node, guards: node.getGuardAttributes() }))\n .filter((details) => details.guards.length > 0)\n );\n\n // Assign the guard path to the current node.\n currentNode.setGuardPath(guardPath);\n }\n });\n}\n", "import State, { AnyState } from \"./State\";\nimport Lookup from \"./Lookup\";\nimport Node from \"./nodes/Node\";\nimport Root from \"./nodes/decorator/Root\";\nimport Composite from \"./nodes/composite/Composite\";\nimport Decorator from \"./nodes/decorator/Decorator\";\nimport { Agent, GlobalFunction } from \"./Agent\";\nimport { CallbackAttributeDetails } from \"./attributes/callbacks/Callback\";\nimport { GuardAttributeDetails } from \"./attributes/guards/Guard\";\nimport { BehaviourTreeOptions } from \"./BehaviourTreeOptions\";\nimport { convertMDSLToJSON } from \"./mdsl/MDSLDefinitionParser\";\nimport { RootNodeDefinition } from \"./BehaviourTreeDefinition\";\nimport { validateDefinition, validateJSONDefinition } from \"./BehaviourTreeDefinitionValidator\";\nimport buildRootNode from \"./BehaviourTreeBuilder\";\nimport { isNullOrUndefined } from \"./BehaviourTreeDefinitionUtilities\";\n\n// Purely for outside inspection of the tree.\nexport type FlattenedTreeNode = {\n id: string;\n type: string;\n caption: string;\n state: AnyState;\n guards: GuardAttributeDetails[];\n callbacks: CallbackAttributeDetails[];\n args: any[];\n parentId: string | null;\n};\n\n/**\n * A representation of a behaviour tree.\n */\nexport class BehaviourTree {\n /**\n * The main root tree node.\n */\n private readonly _rootNode: Root;\n\n /**\n * Creates a new instance of the BehaviourTree class.\n * @param definition The behaviour tree definition as either an MDSL string, root node definition object or array of root node definition objects.\n * @param agent The agent instance that this behaviour tree is modelling behaviour for.\n * @param options The behaviour tree options object.\n */\n constructor(\n definition: string | RootNodeDefinition | RootNodeDefinition[],\n private agent: Agent,\n private options: BehaviourTreeOptions = {}\n ) {\n // The tree definition must be defined.\n if (isNullOrUndefined(definition)) {\n throw new Error(\"tree definition not defined\");\n }\n\n // The agent must be defined and not null.\n if (typeof agent !== \"object\" || agent === null) {\n throw new Error(\"the agent must be an object and not null\");\n }\n\n // We should validate the definition before we try to build the tree nodes.\n const { succeeded, errorMessage, json } = validateDefinition(definition);\n\n // Did our validation fail without error?\n if (!succeeded) {\n throw new Error(`invalid definition: ${errorMessage}`);\n }\n\n // Double check that we did actually get our json definition as part of our definition validtion.\n if (!json) {\n throw new Error(\n \"expected json definition to be returned as part of successful definition validation response\"\n );\n }\n\n try {\n // Create the populated tree of behaviour tree nodes and get the root node.\n this._rootNode = buildRootNode(json);\n } catch (exception) {\n // There was an issue in trying build and populate the behaviour tree.\n throw new Error(`error building tree: ${(exception as Error).message}`);\n }\n }\n\n /**\n * Gets whether the tree is in the RUNNING state.\n * @returns true if the tree is in the RUNNING state, otherwise false.\n */\n isRunning() {\n return this._rootNode.getState() === State.RUNNING;\n }\n\n /**\n * Gets the current tree state of SUCCEEDED, FAILED, READY or RUNNING.\n * @returns The current tree state.\n */\n getState() {\n return this._rootNode.getState();\n }\n\n /**\n * Step the tree.\n * 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.\n * 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\n * 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.\n *\n * 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.\n */\n step() {\n // If the root node has already been stepped to completion then we need to reset it.\n if (this._rootNode.getState() === State.SUCCEEDED || this._rootNode.getState() === State.FAILED) {\n this._rootNode.reset();\n }\n\n try {\n this._rootNode.update(this.agent, this.options);\n } catch (exception) {\n throw new Error(`error stepping tree: ${(exception as Error).message}`);\n }\n }\n\n /**\n * Resets the tree from the root node outwards to each nested node, giving each a state of READY.\n */\n reset() {\n this._rootNode.reset();\n }\n\n /**\n * Gets the flattened details of every node in the tree.\n * @returns The flattened details of every node in the tree.\n */\n getFlattenedNodeDetails(): FlattenedTreeNode[] {\n // Create an empty flattened array of tree nodes.\n const flattenedTreeNodes: FlattenedTreeNode[] = [];\n\n /**\n * Helper function to process a node instance and push details into the flattened tree nodes array.\n * @param node The current node.\n * @param parentUid The UID of the node parent, or null if the node is the main root node.\n */\n const processNode = (node: Node, parentUid: string | null) => {\n // Get the guard and callback attribute details for this node.\n const guards = node\n .getAttributes()\n .filter((attribute) => attribute.isGuard())\n .map((attribute) => attribute.getDetails()) as GuardAttributeDetails[];\n const callbacks = node\n .getAttributes()\n .filter((attribute) => !attribute.isGuard())\n .map((attribute) => attribute.getDetails()) as CallbackAttributeDetails[];\n\n // Push the current node into the flattened nodes array.\n flattenedTreeNodes.push({\n id: node.getUid(),\n type: node.getType(),\n caption: node.getName(),\n state: node.getState(),\n guards,\n callbacks,\n args: node.getArguments(),\n parentId: parentUid\n });\n\n // Process each of the nodes children if it is not a leaf node.\n if (!node.isLeafNode()) {\n (node as Composite | Decorator)\n .getChildren()\n .forEach((child) => processNode(child, (node as Composite | Decorator).getUid()));\n }\n };\n\n // Convert the nested node structure into a flattened array of node details.\n processNode(this._rootNode, null);\n\n return flattenedTreeNodes;\n }\n\n /**\n * Registers the action/condition/guard/callback function or subtree with the given name.\n * @param name The name of the function or subtree to register.\n * @param value The function or subtree definition to register.\n */\n static register(name: string, value: GlobalFunction | string | RootNodeDefinition) {\n // Are we going to register a action/condition/guard/callback function?\n if (typeof value === \"function\") {\n Lookup.setFunc(name, value);\n return;\n }\n\n // We are not registering an action/condition/guard/callback function, so we must be registering a subtree.\n if (typeof value === \"string\") {\n let rootNodeDefinitions: RootNodeDefinition[];\n\n // We will assume that any string passed in will be a mdsl definition.\n try {\n rootNodeDefinitions = convertMDSLToJSON(value);\n } catch (exception) {\n throw new Error(`error registering definition, invalid MDSL: ${(exception as Error).message}`);\n }\n\n // This function should only ever be called with a definition containing a single unnamed root node.\n if (rootNodeDefinitions.length != 1 || rootNodeDefinitions[0].id !== null) {\n throw new Error(\"error registering definition: expected a single unnamed root node\");\n }\n\n try {\n // We should validate the subtree as we don't want invalid subtrees available via the lookup.\n const { succeeded, errorMessage } = validateJSONDefinition(rootNodeDefinitions[0]);\n\n // Did our validation fail without error?\n if (!succeeded) {\n throw new Error(errorMessage);\n }\n } catch (exception) {\n throw new Error(`error registering definition: ${(exception as Error).message}`);\n }\n\n // Everything seems hunky-dory, register the subtree.\n Lookup.setSubtree(name, rootNodeDefinitions[0]);\n } else if (typeof value === \"object\" && !Array.isArray(value)) {\n // We will assume that any object passed in is a root node definition.\n\n try {\n // We should validate the subtree as we don't want invalid subtrees available via the lookup.\n const { succeeded, errorMessage } = validateJSONDefinition(value);\n\n // Did our validation fail without error?\n if (!succeeded) {\n throw new Error(errorMessage);\n }\n } catch (exception) {\n throw new Error(`error registering definition: ${(exception as Error).message}`);\n }\n\n // Everything seems hunky-dory, register the subtree.\n Lookup.setSubtree(name, value);\n } else {\n throw new Error(\"unexpected value, expected string mdsl definition, root node json definition or function\");\n }\n }\n\n /**\n * Unregisters the registered action/condition/guard/callback function or subtree with the given name.\n * @param name The name of the registered action/condition/guard/callback function or subtree to unregister.\n */\n static unregister(name: string): void {\n Lookup.remove(name);\n }\n\n /**\n * Unregister all registered action/condition/guard/callback functions and subtrees.\n */\n static unregisterAll(): void {\n Lookup.empty();\n }\n}\n"], + "mappings": "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", "names": ["Participant", "isNullOrUndefined", "Lotto", "createLotto", "State", "createLotto"] } diff --git a/dist/index.js b/dist/index.js index 492a782..2ef07ff 100644 --- a/dist/index.js +++ b/dist/index.js @@ -1771,9 +1771,14 @@ var Action = class extends Leaf { `cannot update action node as the action '${this.actionName}' function is not defined on the agent and has not been registered` ); } - const updateResult = actionFuncInvoker(this.actionArguments); - if (updateResult instanceof Promise) { - updateResult.then( + let actionFunctionResult; + try { + actionFunctionResult = actionFuncInvoker(this.actionArguments); + } catch (error) { + throw new Error(`action function '${this.actionName}' threw '${error}'`); + } + if (actionFunctionResult instanceof Promise) { + actionFunctionResult.then( (result) => { if (!this.isUsingUpdatePromise) { return; @@ -1789,14 +1794,14 @@ var Action = class extends Leaf { if (!this.isUsingUpdatePromise) { return; } - throw new Error(reason); + throw new Error(`action function '${this.actionName}' promise rejected with reason '${reason}'`); } ); this.setState("mistreevous.running" /* RUNNING */); this.isUsingUpdatePromise = true; } else { - this.validateUpdateResult(updateResult); - this.setState(updateResult || "mistreevous.running" /* RUNNING */); + this.validateUpdateResult(actionFunctionResult); + this.setState(actionFunctionResult || "mistreevous.running" /* RUNNING */); } } getName = () => this.actionName; @@ -1833,7 +1838,18 @@ var Condition = class extends Leaf { `cannot update condition node as the condition '${this.conditionName}' function is not defined on the agent and has not been registered` ); } - this.setState(!!conditionFuncInvoker(this.conditionArguments) ? "mistreevous.succeeded" /* SUCCEEDED */ : "mistreevous.failed" /* FAILED */); + let conditionFunctionResult; + try { + conditionFunctionResult = conditionFuncInvoker(this.conditionArguments); + } catch (error) { + throw new Error(`condition function '${this.conditionName}' threw '${error}'`); + } + if (typeof conditionFunctionResult !== "boolean") { + throw new Error( + `expected condition function '${this.conditionName}' to return a boolean but returned '${conditionFunctionResult}'` + ); + } + this.setState(!!conditionFunctionResult ? "mistreevous.succeeded" /* SUCCEEDED */ : "mistreevous.failed" /* FAILED */); } getName = () => this.conditionName; }; diff --git a/dist/index.js.map b/dist/index.js.map index 8798d49..832a469 100644 --- a/dist/index.js.map +++ b/dist/index.js.map @@ -1,7 +1,7 @@ { "version": 3, "sources": ["../node_modules/lotto-draw/dist/Participant.js", "../node_modules/lotto-draw/dist/Utilities.js", "../node_modules/lotto-draw/dist/Lotto.js", "../node_modules/lotto-draw/dist/createLotto.js", "../node_modules/lotto-draw/dist/index.js", "../src/index.ts", "../src/State.ts", "../src/BehaviourTreeDefinitionUtilities.ts", "../src/mdsl/MDSLUtilities.ts", "../src/mdsl/MDSLNodeArgumentParser.ts", "../src/mdsl/MDSLNodeAttributeParser.ts", "../src/mdsl/MDSLDefinitionParser.ts", "../src/BehaviourTreeDefinitionValidator.ts", "../src/Lookup.ts", "../src/attributes/guards/GuardUnsatisifedException.ts", "../src/attributes/guards/GuardPath.ts", "../src/nodes/Node.ts", "../src/nodes/composite/Composite.ts", "../src/nodes/composite/Parallel.ts", "../src/nodes/composite/Selector.ts", "../src/nodes/composite/Sequence.ts", "../src/nodes/composite/Lotto.ts", "../src/nodes/decorator/Decorator.ts", "../src/nodes/decorator/Fail.ts", "../src/nodes/decorator/Flip.ts", "../src/nodes/decorator/Repeat.ts", "../src/nodes/decorator/Retry.ts", "../src/nodes/decorator/Root.ts", "../src/nodes/decorator/Succeed.ts", "../src/nodes/leaf/Leaf.ts", "../src/nodes/leaf/Action.ts", "../src/nodes/leaf/Condition.ts", "../src/nodes/leaf/Wait.ts", "../src/attributes/Attribute.ts", "../src/attributes/guards/Guard.ts", "../src/attributes/guards/While.ts", "../src/attributes/guards/Until.ts", "../src/attributes/callbacks/Callback.ts", "../src/attributes/callbacks/Entry.ts", "../src/attributes/callbacks/Step.ts", "../src/attributes/callbacks/Exit.ts", "../src/BehaviourTreeBuilder.ts", "../src/BehaviourTree.ts"], - "sourcesContent": ["\"use strict\";\r\nObject.defineProperty(exports, \"__esModule\", { value: true });\r\nexports.Participant = void 0;\r\n/**\r\n * A participant that holds a number of tickets.\r\n */\r\nvar Participant = /** @class */ (function () {\r\n /**\r\n * Creates an instance of the Participant class.\r\n * @param participant The actual participant.\r\n * @param tickets The number of tickets held by the participant.\r\n */\r\n function Participant(participant, tickets) {\r\n if (tickets === void 0) { tickets = 1; }\r\n this._participant = participant;\r\n this._tickets = tickets;\r\n }\r\n Object.defineProperty(Participant.prototype, \"participant\", {\r\n /** Gets the actual participant. */\r\n get: function () {\r\n return this._participant;\r\n },\r\n enumerable: false,\r\n configurable: true\r\n });\r\n Object.defineProperty(Participant.prototype, \"tickets\", {\r\n /** Gets or sets the number of tickets held by the participant. */\r\n get: function () {\r\n return this._tickets;\r\n },\r\n set: function (value) {\r\n this._tickets = value;\r\n },\r\n enumerable: false,\r\n configurable: true\r\n });\r\n return Participant;\r\n}());\r\nexports.Participant = Participant;\r\n", "\"use strict\";\r\nObject.defineProperty(exports, \"__esModule\", { value: true });\r\nexports.isNaturalNumber = exports.isNullOrUndefined = void 0;\r\n/**\r\n * Gets whether the value provided is null or undefined.\r\n * @param value The value to check.\r\n * @returns Whether the value provided is null or undefined.\r\n */\r\nfunction isNullOrUndefined(value) {\r\n return value === null || value === undefined;\r\n}\r\nexports.isNullOrUndefined = isNullOrUndefined;\r\n/**\r\n * Gets whether the value provided is a natural number.\r\n * @param value The value to check.\r\n * @returns Whether the value provided is a natural number.\r\n */\r\nfunction isNaturalNumber(value) {\r\n return typeof value === \"number\" && value >= 1 && Math.floor(value) === value;\r\n}\r\nexports.isNaturalNumber = isNaturalNumber;\r\n", "\"use strict\";\r\nObject.defineProperty(exports, \"__esModule\", { value: true });\r\nexports.Lotto = void 0;\r\nvar Participant_1 = require(\"./Participant\");\r\nvar Utilities_1 = require(\"./Utilities\");\r\n/**\r\n * Represents a lotto consisting of a number of pickable ticket-holding participants.\r\n */\r\nvar Lotto = /** @class */ (function () {\r\n /**\r\n * Creates a new instance of Lotto.\r\n * @param customRandom The custom RNG to use in place of Math.random().\r\n */\r\n function Lotto(customRandom) {\r\n /** The array of participants that are holding tickets in the lotto. */\r\n this._participants = [];\r\n this._customRandom = customRandom;\r\n }\r\n /**\r\n * Adds a participant with the specified number of tickets, or adds to the participant ticket count if the participant already holds tickets.\r\n * @param participant The participant to add or to increase the ticket count for if they already hold tickets.\r\n * @param tickets The number of tickets, defaults to 1.\r\n * @returns The Lotto instance.\r\n */\r\n Lotto.prototype.add = function (participant, tickets) {\r\n if (tickets === void 0) { tickets = 1; }\r\n // Check that we have a valid ticket count.\r\n if (!(0, Utilities_1.isNaturalNumber)(tickets)) {\r\n throw new Error(\"tickets value must be a natural number\");\r\n }\r\n // Check whether this participant has already been added.\r\n var existingParticipant = this._participants.find(function (part) { return part.participant === participant; });\r\n if (existingParticipant) {\r\n // The participant has already been added to the lotto so just add to their ticket count.\r\n existingParticipant.tickets += tickets;\r\n }\r\n else {\r\n // The participant is not part of the lotto so we should add them.\r\n this._participants.push(new Participant_1.Participant(participant, tickets));\r\n }\r\n return this;\r\n };\r\n /**\r\n * Removes the specified number of tickets for the given participant from the draw, or all tickets if a ticket number is not defined.\r\n * @param participant The participant to remove tickets for.\r\n * @param tickets The number of tickets to remove, or undefined if all tickets are to be removed.\r\n * @returns The Lotto instance.\r\n */\r\n Lotto.prototype.remove = function (participant, tickets) {\r\n // Attempt to get the existing participant.\r\n var existingParticipant = this._participants.find(function (part) { return part.participant === participant; });\r\n // There is nothing to do if the specified participant isn't even part of the lotto.\r\n if (!existingParticipant) {\r\n return this;\r\n }\r\n // Check whether a tickets value was given.\r\n if (tickets !== undefined) {\r\n // Check that we have a valid ticket count.\r\n if (!(0, Utilities_1.isNaturalNumber)(tickets)) {\r\n throw new Error(\"tickets value must be a natural number\");\r\n }\r\n existingParticipant.tickets -= tickets;\r\n // If the participant no longer holds any tickets then they should be removed.\r\n if (existingParticipant.tickets < 1) {\r\n this._participants = this._participants.filter(function (part) { return part !== existingParticipant; });\r\n }\r\n }\r\n else {\r\n // We are removing all tickets for the participant so just remove them from the lotto.\r\n this._participants = this._participants.filter(function (part) { return part !== existingParticipant; });\r\n }\r\n return this;\r\n };\r\n /**\r\n * Draw a winning ticket and return the participant that holds the ticket.\r\n * @param options The draw options.\r\n * @returns The participant that holds the winning ticket.\r\n */\r\n Lotto.prototype.draw = function (options) {\r\n if (options === void 0) { options = {}; }\r\n // If we have no participants then just return null.\r\n if (this._participants.length === 0) {\r\n return null;\r\n }\r\n var redrawable = (0, Utilities_1.isNullOrUndefined)(options.redrawable) ? true : options.redrawable;\r\n var pickable = [];\r\n this._participants.forEach(function (_a) {\r\n var participant = _a.participant, tickets = _a.tickets;\r\n for (var ticketCount = 0; ticketCount < tickets; ticketCount++) {\r\n pickable.push(participant);\r\n }\r\n });\r\n var random;\r\n // We need a random floating-point number between 0 (inclusive) and 1 to scale up to pick our winner.\r\n // If a custom random function exists then we should use that or fall back to Math.random().\r\n if (this._customRandom) {\r\n // Call our custom random function to get a random floating-point number.\r\n random = this._customRandom();\r\n // Verify that the result of calling our custom random function is a number between 0 (inclusive) and 1.\r\n if (typeof random !== \"number\" || random < 0 || random >= 1) {\r\n throw new Error(\"the 'random' function provided did not return a number between 0 (inclusive) and 1\");\r\n }\r\n }\r\n else {\r\n // No custom random function was defined so just use good ol' Math.random().\r\n random = Math.random();\r\n }\r\n // Pick a winning participant.\r\n var winner = pickable[Math.floor(random * pickable.length)];\r\n // If the ticket isn't redrawable then we should remove a ticket from the winning participants ticket count.\r\n if (!redrawable) {\r\n this.remove(winner, 1);\r\n }\r\n // Return the winning participant.\r\n return winner;\r\n };\r\n /**\r\n * Draws multiple winning tickets and return an array of the participants that hold the winning tickets.\r\n * @param tickets The number of winning tickets to draw.\r\n * @param options The draw multiple options.\r\n * @returns An array of the participants that hold the winning tickets.\r\n */\r\n Lotto.prototype.drawMultiple = function (tickets, options) {\r\n if (options === void 0) { options = {}; }\r\n var uniqueResults = (0, Utilities_1.isNullOrUndefined)(options.unique) ? false : options.unique;\r\n // Handle cases where the user has asked for zero tickets (no idea why they would do this be we should trust them).\r\n if (tickets === 0) {\r\n return [];\r\n }\r\n // Now that we know out tickets value is not zero we should check that it is a valid natural number.\r\n if (!(0, Utilities_1.isNaturalNumber)(tickets)) {\r\n throw new Error(\"tickets value must be a natural number\");\r\n }\r\n var result = [];\r\n // Keep drawing tickets until we either reach the number of required tickets or we simply run out of tickets to draw.\r\n // We can run out of tickets to draw if 'options.redrawable' is explicity 'false' or we just had no participants when 'drawMultiple' was called.\r\n while (result.length < tickets && this._participants.length > 0) {\r\n result.push(this.draw(options));\r\n }\r\n // If the 'unique' draw option is set then we need to remove duplicates from the result list.\r\n if (uniqueResults) {\r\n // Create an array to store our unique results.\r\n var unique = [];\r\n // Iterate over all of our participants (with potential duplicates) and populate our array of unique values.\r\n for (var _i = 0, result_1 = result; _i < result_1.length; _i++) {\r\n var participant = result_1[_i];\r\n if (unique.indexOf(participant) === -1) {\r\n unique.push(participant);\r\n }\r\n }\r\n result = unique;\r\n }\r\n return result;\r\n };\r\n return Lotto;\r\n}());\r\nexports.Lotto = Lotto;\r\n", "\"use strict\";\r\nObject.defineProperty(exports, \"__esModule\", { value: true });\r\nexports.createLotto = void 0;\r\nvar Lotto_1 = require(\"./Lotto\");\r\n/**\r\n * A function that creates and returns a Lotto instance.\r\n * @param participantsOrOptions An array of initial participants or options relating to the creation of a Lotto instance.\r\n * @returns A new Lotto instance.\r\n */\r\nfunction createLotto(participantsOrOptions) {\r\n // If no initial participants or lotto options were provided as an argument then we can just return a new lotto instance now.\r\n if (!participantsOrOptions) {\r\n return new Lotto_1.Lotto();\r\n }\r\n // Check whether we were provided with an array of initial participants or a lotto options object.\r\n if (Array.isArray(participantsOrOptions)) {\r\n // We are dealing with a pre-defined array of participants.\r\n var participants = participantsOrOptions;\r\n var lotto_1 = new Lotto_1.Lotto();\r\n // If the lotto participants have been defined upfront then we will need to add them all to our lotto instance now.\r\n participants.forEach(function (_a) {\r\n var participant = _a[0], tokens = _a[1];\r\n return lotto_1.add(participant, tokens);\r\n });\r\n // Return the Lotto instance.\r\n return lotto_1;\r\n }\r\n else {\r\n // We are dealing with some lotto options.\r\n var random = participantsOrOptions.random, participants = participantsOrOptions.participants;\r\n // Create a Lotto instance passing the custom RNG function to use in place of Math.random() (which could be undefined).\r\n var lotto_2 = new Lotto_1.Lotto(random);\r\n // If the lotto participants have been defined upfront as part of the options then we will need to add them all to our lotto instance now.\r\n if (participants) {\r\n participants.forEach(function (_a) {\r\n var participant = _a[0], tokens = _a[1];\r\n return lotto_2.add(participant, tokens);\r\n });\r\n }\r\n // Return the Lotto instance.\r\n return lotto_2;\r\n }\r\n}\r\nexports.createLotto = createLotto;\r\n", "\"use strict\";\r\nObject.defineProperty(exports, \"__esModule\", { value: true });\r\nvar createLotto_1 = require(\"./createLotto\");\r\nexports.default = createLotto_1.createLotto;\r\n", "import State from \"./State\";\nimport { validateDefinition } from \"./BehaviourTreeDefinitionValidator\";\nimport { convertMDSLToJSON } from \"./mdsl/MDSLDefinitionParser\";\nimport { BehaviourTree, FlattenedTreeNode } from \"./BehaviourTree\";\nimport { BehaviourTreeOptions } from \"./BehaviourTreeOptions\";\n\nexport { BehaviourTree, State, convertMDSLToJSON, validateDefinition };\nexport type { FlattenedTreeNode, BehaviourTreeOptions };\n", "/**\n * Enumeration of node state types.\n */\nexport enum State {\n READY = \"mistreevous.ready\",\n RUNNING = \"mistreevous.running\",\n SUCCEEDED = \"mistreevous.succeeded\",\n FAILED = \"mistreevous.failed\"\n}\n\nexport { State as default };\n\nexport type CompleteState = State.SUCCEEDED | State.FAILED;\nexport type AnyState = State.READY | State.RUNNING | CompleteState;\n", "import {\n NodeDefinition,\n RootNodeDefinition,\n DecoratorNodeDefinition,\n CompositeNodeDefinition,\n AnyNodeDefinition,\n BranchNodeDefinition\n} from \"./BehaviourTreeDefinition\";\n\n/**\n * A type guard function that returns true if the specified node satisfies the RootNodeDefinition type.\n * @param node The node.\n * @returns A value of true if the specified node satisfies the RootNodeDefinition type.\n */\nexport function isRootNode(node: NodeDefinition): node is RootNodeDefinition {\n return node.type === \"root\";\n}\n\n/**\n * A type guard function that returns true if the specified node satisfies the BranchNodeDefinition type.\n * @param node The node.\n * @returns A value of true if the specified node satisfies the BranchNodeDefinition type.\n */\nexport function isBranchNode(node: NodeDefinition): node is BranchNodeDefinition {\n return node.type === \"branch\";\n}\n\n/**\n * A type guard function that returns true if the specified node satisfies the NodeDefinition type.\n * @param node The node.\n * @returns A value of true if the specified node satisfies the NodeDefinition type.\n */\nexport function isLeafNode(node: NodeDefinition): node is NodeDefinition {\n return [\"branch\", \"action\", \"condition\", \"wait\"].includes(node.type);\n}\n\n/**\n * A type guard function that returns true if the specified node satisfies the DecoratorNodeDefinition type.\n * @param node The node.\n * @returns A value of true if the specified node satisfies the DecoratorNodeDefinition type.\n */\nexport function isDecoratorNode(node: NodeDefinition): node is DecoratorNodeDefinition {\n return [\"root\", \"repeat\", \"retry\", \"flip\", \"succeed\", \"fail\"].includes(node.type);\n}\n\n/**\n * A type guard function that returns true if the specified node satisfies the CompositeNodeDefinition type.\n * @param node The node.\n * @returns A value of true if the specified node satisfies the CompositeNodeDefinition type.\n */\nexport function isCompositeNode(node: NodeDefinition): node is CompositeNodeDefinition {\n return [\"sequence\", \"selector\", \"lotto\", \"parallel\"].includes(node.type);\n}\n\n/**\n * Flatten a node definition into an array of all of its nested node definitions.\n * @param nodeDefinition The node definition to flatten.\n * @returns An array of all of nested node definitions.\n */\nexport function flattenDefinition(nodeDefinition: AnyNodeDefinition): AnyNodeDefinition[] {\n const nodes: AnyNodeDefinition[] = [];\n\n const processNode = (currentNodeDefinition: AnyNodeDefinition) => {\n nodes.push(currentNodeDefinition);\n\n if (isCompositeNode(currentNodeDefinition)) {\n currentNodeDefinition.children.forEach(processNode);\n } else if (isDecoratorNode(currentNodeDefinition)) {\n processNode(currentNodeDefinition.child);\n }\n };\n\n processNode(nodeDefinition);\n\n return nodes;\n}\n\n/**\n * Determines whether the passed value is an integer.\n * @param value The value to check.\n * @returns Whether the passed value is an integer.\n */\nexport function isInteger(value: unknown): boolean {\n return typeof value === \"number\" && Math.floor(value) === value;\n}\n\n/**\n * Determines whether the passed value is null or undefined.\n * @param value The value to check.\n * @returns Whether the passed value is null or undefined.\n */\nexport function isNullOrUndefined(value: unknown): boolean {\n return typeof value === \"undefined\" || value === null;\n}\n", "/**\n * A type defining an object that holds a reference to substitued string literals parsed from the definition.\n */\nexport type StringLiteralPlaceholders = { [key: string]: string };\n\n/**\n * Pop the next raw token from the specified array of tokens and throw an error if it wasn't the expected one.\n * @param tokens The array of tokens.\n * @param expected An optional string or array or items, one of which must match the next popped token.\n * @returns The popped token.\n */\nexport function popAndCheck(tokens: string[], expected?: string | string[]): string {\n // Get and remove the next token.\n const popped = tokens.shift();\n\n // We were expecting another token but there aren't any.\n if (popped === undefined) {\n throw new Error(\"unexpected end of definition\");\n }\n\n // Do we have an expected token/tokens array?\n if (expected != undefined) {\n // Get an array of expected values, if the popped token matches any then we are all good.\n const expectedValues = typeof expected === \"string\" ? [expected] : expected;\n\n // Check whether the popped token matches at least one of our expected items.\n var tokenMatchesExpectation = expectedValues.some((item) => popped.toUpperCase() === item.toUpperCase());\n\n // Throw an error if the popped token didn't match any of our expected items.\n if (!tokenMatchesExpectation) {\n const expectationString = expectedValues.map((item) => \"'\" + item + \"'\").join(\" or \");\n throw new Error(\"unexpected token found. Expected \" + expectationString + \" but got '\" + popped + \"'\");\n }\n }\n\n // Return the popped token.\n return popped;\n}\n\n/**\n * Swaps out any node/attribute argument string literals with placeholders.\n * @param definition The definition.\n * @returns An object containing a mapping of placeholders to original string values as well as the processed definition string.\n */\nexport function substituteStringLiterals(definition: string): {\n placeholders: StringLiteralPlaceholders;\n processedDefinition: string;\n} {\n // Create an object to hold the mapping of placeholders to original string values.\n const placeholders: StringLiteralPlaceholders = {};\n\n // Replace any string literals wrapped with double quotes in our definition with placeholders to be processed later.\n const processedDefinition = definition.replace(/\\\"(\\\\.|[^\"\\\\])*\\\"/g, (match) => {\n var strippedMatch = match.substring(1, match.length - 1);\n var placeholder = Object.keys(placeholders).find((key) => placeholders[key] === strippedMatch);\n\n // If we have no existing string literal match then create a new placeholder.\n if (!placeholder) {\n placeholder = `@@${Object.keys(placeholders).length}@@`;\n placeholders[placeholder] = strippedMatch;\n }\n\n return placeholder;\n });\n\n return { placeholders, processedDefinition };\n}\n\n/**\n * Parse the tree definition into an array of raw tokens.\n * @param definition The definition.\n * @returns An array of tokens parsed from the definition.\n */\nexport function parseTokensFromDefinition(definition: string): string[] {\n // Add some space around various important characters so that they can be plucked out easier as individual tokens.\n definition = definition.replace(/\\(/g, \" ( \");\n definition = definition.replace(/\\)/g, \" ) \");\n definition = definition.replace(/\\{/g, \" { \");\n definition = definition.replace(/\\}/g, \" } \");\n definition = definition.replace(/\\]/g, \" ] \");\n definition = definition.replace(/\\[/g, \" [ \");\n definition = definition.replace(/\\,/g, \" , \");\n\n // Split the definition into raw token form and return it.\n return definition.replace(/\\s+/g, \" \").trim().split(\" \");\n}\n", "import { StringLiteralPlaceholders, popAndCheck } from \"./MDSLUtilities\";\n\n/**\n * A type representing any node function argument.\n */\ntype Argument = {\n /**\n * The argument value.\n */\n value: T;\n /**\n * The argument type, used for validation.\n */\n type: string;\n};\n\ntype NullArgument = Argument & {\n type: \"null\";\n};\n\ntype BooleanArgument = Argument & {\n type: \"boolean\";\n};\n\ntype NumberArgument = Argument & {\n type: \"number\";\n /**\n * A flag defining whether the number argument value is a valid integer. (used for validation)\n */\n isInteger: boolean;\n};\n\ntype StringPlaceholderArgument = Argument & {\n type: \"string\";\n};\n\ntype IdentifierArgument = Argument & {\n type: \"identifier\";\n};\n\n/**\n * A type representing a reference to any node function argument.\n */\ntype AnyArgument = NullArgument | BooleanArgument | NumberArgument | StringPlaceholderArgument | IdentifierArgument;\n\n/**\n * Parse an array of argument definitions from the specified tokens array.\n * @param tokens The array tokens to parse the argument definitions from.\n * @param stringArgumentPlaceholders The mapping of string literal node argument placeholders to original values.\n * @param argumentValidator The argument validator function.\n * @param validationFailedMessage The exception message to throw if argument validation fails.\n * @returns An array of argument definitions parsed from the specified tokens array.\n */\nexport function parseArgumentTokens(\n tokens: string[],\n stringArgumentPlaceholders: StringLiteralPlaceholders\n): AnyArgument[] {\n const argumentList: AnyArgument[] = [];\n\n // If the next token is not a '[' or '(' then we have no arguments to parse.\n if (![\"[\", \"(\"].includes(tokens[0])) {\n return argumentList;\n }\n\n // Any lists of arguments will always be wrapped in '[]' for node arguments or '()' for attribute arguments.\n // We are looking for a '[' or '(' opener that wraps the argument tokens and the relevant closer.\n const closingToken = popAndCheck(tokens, [\"[\", \"(\"]) === \"[\" ? \"]\" : \")\";\n\n const argumentListTokens: string[] = [];\n\n // Grab all tokens between the '[' and ']' or '(' and ')'.\n while (tokens.length && tokens[0] !== closingToken) {\n // The next token is part of our arguments list.\n argumentListTokens.push(tokens.shift()!);\n }\n\n // Validate the order of the argument tokens. Each token must either be a ',' or a single argument that satisfies the validator.\n argumentListTokens.forEach((token, index) => {\n // Get whether this token should be an actual argument.\n const shouldBeArgumentToken = !(index & 1);\n\n // If the current token should be an actual argument then validate it, otherwise it should be a ',' token.\n if (shouldBeArgumentToken) {\n // Get the argument definition.\n const argumentDefinition = getArgumentDefinition(token, stringArgumentPlaceholders);\n\n // This is a valid argument!\n argumentList.push(argumentDefinition);\n } else {\n // The current token should be a ',' token.\n if (token !== \",\") {\n throw new Error(`invalid argument list, expected ',' or ']' but got '${token}'`);\n }\n }\n });\n\n // The arguments list should terminate with a ']' or ')' token, depending on the opener.\n popAndCheck(tokens, closingToken);\n\n // Return the arguments.\n return argumentList;\n}\n\n/**\n * Gets an argument value definition.\n * @param token The argument token.\n * @param stringArgumentPlaceholders The mapping of string literal node argument placeholders to original values.\n * @returns An argument value definition.\n */\nfunction getArgumentDefinition(token: string, stringArgumentPlaceholders: StringLiteralPlaceholders): AnyArgument {\n // Check whether the token represents a null value.\n if (token === \"null\") {\n return {\n value: null,\n type: \"null\"\n } as NullArgument;\n }\n\n // Check whether the token represents a boolean value.\n if (token === \"true\" || token === \"false\") {\n return {\n value: token === \"true\",\n type: \"boolean\"\n } as BooleanArgument;\n }\n\n // Check whether the token represents a number value.\n // TODO: Relies on broken isNaN - see MDN.\n // if (!Number.isNaN(token)) {\n if (!isNaN(token as any)) {\n return {\n value: parseFloat(token),\n isInteger: parseFloat(token) === parseInt(token, 10),\n type: \"number\"\n } as NumberArgument;\n }\n\n // Check whether the token is a placeholder (e.g. @@0@@) representing a string literal.\n if (token.match(/^@@\\d+@@$/g)) {\n return {\n value: stringArgumentPlaceholders[token].replace('\\\\\"', '\"'),\n type: \"string\"\n } as StringPlaceholderArgument;\n }\n\n // The only remaining option is that the argument value is an identifier.\n return {\n value: token,\n type: \"identifier\"\n } as IdentifierArgument;\n}\n", "import { NodeAttributeDefinition } from \"../BehaviourTreeDefinition\";\nimport { parseArgumentTokens } from \"./MDSLNodeArgumentParser\";\nimport { StringLiteralPlaceholders } from \"./MDSLUtilities\";\n\n/**\n * A type defining the attribute definitions of a node.\n */\ntype NodeAttributes = {\n while?: NodeAttributeDefinition;\n until?: NodeAttributeDefinition;\n entry?: NodeAttributeDefinition;\n exit?: NodeAttributeDefinition;\n step?: NodeAttributeDefinition;\n};\n\n/**\n * Parse any node attribute definitions from the specified tokens array.\n * @param tokens The array of remaining tokens.\n * @param stringArgumentPlaceholders The mapping of string literal node argument placeholders to original values.\n * @returns An object of attribute definitions defined by any directly following tokens.\n */\nexport function parseAttributeTokens(\n tokens: string[],\n stringArgumentPlaceholders: StringLiteralPlaceholders\n): NodeAttributes {\n const nodeAttributeNames: (keyof NodeAttributes)[] = [\"while\", \"until\", \"entry\", \"exit\", \"step\"];\n\n // Create an object to hold any attributes found.\n const attributes: NodeAttributes = {};\n\n // Try to get the name of the attribute for the next token.\n let nextAttributeName = tokens[0]?.toLowerCase() as keyof NodeAttributes;\n\n // Pull attribute tokens as well as their arguments off of the tokens stack until we have no more.\n while (nodeAttributeNames.includes(nextAttributeName)) {\n // Check to make sure that we have not already created an attribute definition of this type.\n if (attributes[nextAttributeName]) {\n throw new Error(`duplicate attribute '${tokens[0].toUpperCase()}' found for node`);\n }\n\n // Remove the attribute name token from the array of tokens.\n tokens.shift();\n\n // Grab the attribute arguments, assuming the first to be an identifier.\n const [attributeCallIdentifier, ...attributeArguments] = parseArgumentTokens(\n tokens,\n stringArgumentPlaceholders\n );\n\n // The first attribute argument has to be an identifer, this will reference an agent function.\n if (attributeCallIdentifier?.type !== \"identifier\") {\n throw new Error(\"expected agent function name identifier argument for attribute\");\n }\n\n // Any attribute arguments (other than the expected call identifier) must have a type of string, number, boolean or null.\n attributeArguments\n .filter((arg) => arg.type === \"identifier\")\n .forEach((arg) => {\n throw new Error(\n `invalid attribute argument value '${arg.value}', must be string, number, boolean or null`\n );\n });\n\n // Create the attribute definition and add it to the object of attribute definitions found.\n attributes[nextAttributeName] = {\n call: attributeCallIdentifier.value,\n args: attributeArguments.map(({ value }) => value)\n };\n\n // Try to get the next attribute name token, as there could be multiple.\n nextAttributeName = tokens[0]?.toLowerCase() as keyof NodeAttributes;\n }\n\n return attributes;\n}\n", "import {\n ActionNodeDefinition,\n AnyChildNodeDefinition,\n AnyNodeDefinition,\n BranchNodeDefinition,\n ConditionNodeDefinition,\n FailNodeDefinition,\n FlipNodeDefinition,\n LottoNodeDefinition,\n ParallelNodeDefinition,\n RepeatNodeDefinition,\n RetryNodeDefinition,\n RootNodeDefinition,\n SelectorNodeDefinition,\n SequenceNodeDefinition,\n SucceedNodeDefinition,\n WaitNodeDefinition\n} from \"../BehaviourTreeDefinition\";\nimport {\n isCompositeNode,\n isDecoratorNode,\n isLeafNode,\n isNullOrUndefined,\n isRootNode\n} from \"../BehaviourTreeDefinitionUtilities\";\nimport { parseArgumentTokens } from \"./MDSLNodeArgumentParser\";\nimport { parseAttributeTokens } from \"./MDSLNodeAttributeParser\";\nimport {\n StringLiteralPlaceholders,\n parseTokensFromDefinition,\n popAndCheck,\n substituteStringLiterals\n} from \"./MDSLUtilities\";\n\n/**\n * Convert the MDSL tree definition string into an equivalent JSON definition.\n * @param definition The tree definition string as MDSL.\n * @returns The root node JSON definitions.\n */\nexport function convertMDSLToJSON(definition: string): RootNodeDefinition[] {\n // Swap out any node/attribute argument string literals with a placeholder and get a mapping of placeholders to original values as well as the processed definition.\n const { placeholders, processedDefinition } = substituteStringLiterals(definition);\n\n // Parse our definition definition string into an array of raw tokens.\n const tokens = parseTokensFromDefinition(processedDefinition);\n\n return convertTokensToJSONDefinition(tokens, placeholders);\n}\n\n/**\n * Converts the specified tree definition tokens into a JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The root node JSON definitions.\n */\nfunction convertTokensToJSONDefinition(\n tokens: string[],\n stringLiteralPlaceholders: StringLiteralPlaceholders\n): RootNodeDefinition[] {\n // There must be at least 3 tokens for the tree definition to be valid. 'ROOT', '{' and '}'.\n if (tokens.length < 3) {\n throw new Error(\"invalid token count\");\n }\n\n // We should have a matching number of '{' and '}' tokens. If not, then there are scopes that have not been properly closed.\n if (tokens.filter((token) => token === \"{\").length !== tokens.filter((token) => token === \"}\").length) {\n throw new Error(\"scope character mismatch\");\n }\n\n // Create an array of tree stack arrays where root nodes will always be at the botton and the current composite/decorator node at the top.\n // There should be an element in this array for every root node defined and every element should be an array with a root note as the first element.\n // E.g. A definition with two root nodes defined:\n // [\n // [root, lotto, sequence],\n // [root, selector]\n // ]\n const treeStacks: [Partial, ...Partial[]][] = [];\n\n // Create an array of all root node definitions that we create.\n const rootNodes: Partial[] = [];\n\n // A helper function used to push node definitions onto the tree stack.\n const pushNode = (node: AnyNodeDefinition) => {\n // If the node is a root node then we need to create a new tree stack array with the root node at the root.\n if (isRootNode(node)) {\n // We need to double-check that this root node is not the child of another node.\n // We can do this by checking whether the top tree stack is not empty (contains an existing node)\n if (treeStacks[treeStacks.length - 1]?.length) {\n throw new Error(\"a root node cannot be the child of another node\");\n }\n\n // Add the root node definition to our array of all parsed root node definitions.\n rootNodes.push(node);\n\n // Add the root node definition to the root of a new tree stack.\n treeStacks.push([node]);\n\n return;\n }\n\n // All non-root nodes should be pushed after their root nodes so handle cases\n // where we may not have any tree stacks or our top-most tree stack is empty.\n if (!treeStacks.length || !treeStacks[treeStacks.length - 1].length) {\n throw new Error(\"expected root node at base of definition\");\n }\n\n // Get the current tree stack that we are populating.\n const topTreeStack = treeStacks[treeStacks.length - 1];\n\n // Get the top-most node in the current tree stack, this will be a composite/decorator node\n // for which we will populate its children array if composite or setting its child if a decorator.\n const topTreeStackTopNode = topTreeStack[topTreeStack.length - 1] as AnyNodeDefinition;\n\n // If the top-most node in the current root stack is a composite or decorator\n // node then the current node should be added as a child of the top-most node.\n if (isCompositeNode(topTreeStackTopNode)) {\n topTreeStackTopNode.children = topTreeStackTopNode.children || [];\n topTreeStackTopNode.children.push(node);\n } else if (isDecoratorNode(topTreeStackTopNode)) {\n // If the top node already has a child node set then throw an error as a decorator should only have a single child.\n if (topTreeStackTopNode.child) {\n throw new Error(\"a decorator node must only have a single child node\");\n }\n\n topTreeStackTopNode.child = node;\n }\n\n // If the node we are adding is also a composite or decorator node, then we should push it\n // onto the current tree stack, as subsequent nodes will be added as its child/children.\n if (!isLeafNode(node)) {\n topTreeStack.push(node);\n }\n };\n\n // A helper function used to pop the top-most node definition off of the tree stack and return it.\n const popNode = (): AnyNodeDefinition | null => {\n let poppedNode: AnyNodeDefinition | null = null;\n\n // Get the current tree stack that we are populating.\n const topTreeStack = treeStacks[treeStacks.length - 1];\n\n // Pop the top-most node in the current tree stack if there is one.\n if (topTreeStack.length) {\n poppedNode = topTreeStack.pop() as AnyNodeDefinition;\n }\n\n // We don't want any empty tree stacks in our stack of tree stacks.\n if (!topTreeStack.length) {\n treeStacks.pop();\n }\n\n return poppedNode;\n };\n\n // We should keep processing the raw tokens until we run out of them.\n while (tokens.length) {\n // Grab the next token.\n const token = tokens.shift()!;\n\n // How we create the next node depends on the current raw token value.\n switch (token.toUpperCase()) {\n case \"ROOT\": {\n pushNode(createRootNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"SUCCEED\": {\n pushNode(createSucceedNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"FAIL\": {\n pushNode(createFailNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"FLIP\": {\n pushNode(createFlipNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"REPEAT\": {\n pushNode(createRepeatNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"RETRY\": {\n pushNode(createRetryNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"SEQUENCE\": {\n pushNode(createSequenceNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"SELECTOR\": {\n pushNode(createSelectorNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"PARALLEL\": {\n pushNode(createParallelNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"LOTTO\": {\n pushNode(createLottoNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"ACTION\": {\n pushNode(createActionNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"CONDITION\": {\n pushNode(createConditionNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"WAIT\": {\n pushNode(createWaitNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"BRANCH\": {\n pushNode(createBranchNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"}\": {\n // The '}' character closes the current scope and means that we have to pop a node off of the current stack.\n const poppedNode = popNode();\n\n // Now that we have a node definition we can carry out any validation that may require the node to be fully populated.\n if (poppedNode) {\n validatePoppedNode(poppedNode);\n }\n\n break;\n }\n\n default: {\n throw new Error(`unexpected token: ${token}`);\n }\n }\n }\n\n return rootNodes as RootNodeDefinition[];\n}\n\n/**\n * Creates a root node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The root node JSON definition.\n */\nfunction createRootNode(tokens: string[], stringLiteralPlaceholders: StringLiteralPlaceholders): RootNodeDefinition {\n // Create the root node definition.\n let node = {\n type: \"root\",\n id: undefined\n } as RootNodeDefinition;\n\n // Parse any node arguments, we should only have one if any which will be an identifier argument for the root identifier.\n const nodeArguments = parseArgumentTokens(tokens, stringLiteralPlaceholders);\n\n // Check whether any node arguments were defined.\n if (nodeArguments.length) {\n // We should only have one argument, if any, which will be an identifier argument for the root identifier.\n if (nodeArguments.length === 1 && nodeArguments[0].type === \"identifier\") {\n // The root node identifier will be the first and only node argument value.\n node.id = nodeArguments[0].value as string;\n } else {\n throw new Error(\"expected single root name argument\");\n }\n }\n\n // Grab any node attribute definitions and spread them into the node definition.\n node = { ...node, ...parseAttributeTokens(tokens, stringLiteralPlaceholders) };\n\n // This is a decorator node, so we expect an opening '{'.\n popAndCheck(tokens, \"{\");\n\n // Return the root node definition.\n return node;\n}\n\n/**\n * Creates a succeed node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The succeed node JSON definition.\n */\nfunction createSucceedNode(\n tokens: string[],\n stringLiteralPlaceholders: StringLiteralPlaceholders\n): SucceedNodeDefinition {\n const node = {\n type: \"succeed\",\n ...parseAttributeTokens(tokens, stringLiteralPlaceholders)\n } as SucceedNodeDefinition;\n\n // This is a decorator node, so we expect an opening '{'.\n popAndCheck(tokens, \"{\");\n\n // Return the succeed node definition.\n return node;\n}\n\n/**\n * Creates a fail node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The fail node JSON definition.\n */\nfunction createFailNode(tokens: string[], stringLiteralPlaceholders: StringLiteralPlaceholders): FailNodeDefinition {\n const node = {\n type: \"fail\",\n ...parseAttributeTokens(tokens, stringLiteralPlaceholders)\n } as FailNodeDefinition;\n\n // This is a decorator node, so we expect an opening '{'.\n popAndCheck(tokens, \"{\");\n\n // Return the fail node definition.\n return node;\n}\n\n/**\n * Creates a flip node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The flip node JSON definition.\n */\nfunction createFlipNode(tokens: string[], stringLiteralPlaceholders: StringLiteralPlaceholders): FlipNodeDefinition {\n const node = {\n type: \"flip\",\n ...parseAttributeTokens(tokens, stringLiteralPlaceholders)\n } as FlipNodeDefinition;\n\n // This is a decorator node, so we expect an opening '{'.\n popAndCheck(tokens, \"{\");\n\n // Return the flip node definition.\n return node;\n}\n\n/**\n * Creates a repeat node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The repeat node JSON definition.\n */\nfunction createRepeatNode(\n tokens: string[],\n stringLiteralPlaceholders: StringLiteralPlaceholders\n): RepeatNodeDefinition {\n let node = { type: \"repeat\" } as RepeatNodeDefinition;\n\n // Get the node arguments.\n const nodeArguments = parseArgumentTokens(tokens, stringLiteralPlaceholders);\n\n // The arguments of a repeat node are optional. We may have:\n // - No node arguments, in which case the repeat note will iterate indefinitely.\n // - One node argument which will be the explicit number of iterations to make.\n // - Two node arguments which define the min and max iteration bounds from which a random iteration count will be picked.\n if (nodeArguments.length) {\n // All repeat node arguments MUST be of type number and must be integer.\n nodeArguments\n .filter((arg) => arg.type !== \"number\" || !arg.isInteger)\n .forEach(() => {\n throw new Error(`repeat node iteration counts must be integer values`);\n });\n\n // We should have got one or two iteration counts.\n if (nodeArguments.length === 1) {\n // A static iteration count was defined.\n node.iterations = nodeArguments[0].value as number;\n\n // A repeat node must have a positive number of iterations if defined.\n if (node.iterations < 0) {\n throw new Error(\"a repeat node must have a positive number of iterations if defined\");\n }\n } else if (nodeArguments.length === 2) {\n // A minimum and maximum iteration count was defined.\n node.iterations = [nodeArguments[0].value as number, nodeArguments[1].value as number];\n\n // A repeat node must have a positive min and max iteration count if they are defined.\n if (node.iterations[0] < 0 || node.iterations[1] < 0) {\n throw new Error(\"a repeat node must have a positive minimum and maximum iteration count if defined\");\n }\n\n // A repeat node must not have an minimum iteration count that exceeds the maximum iteration count.\n if (node.iterations[0] > node.iterations[1]) {\n throw new Error(\n \"a repeat node must not have a minimum iteration count that exceeds the maximum iteration count\"\n );\n }\n } else {\n // An incorrect number of iteration counts was defined.\n throw new Error(\"invalid number of repeat node iteration count arguments defined\");\n }\n }\n\n // Grab any node attribute definitions and spread them into the node definition.\n node = { ...node, ...parseAttributeTokens(tokens, stringLiteralPlaceholders) };\n\n // This is a decorator node, so we expect an opening '{'.\n popAndCheck(tokens, \"{\");\n\n // Return the repeat node definition.\n return node;\n}\n\n/**\n * Creates a retry node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The retry node JSON definition.\n */\nfunction createRetryNode(tokens: string[], stringLiteralPlaceholders: StringLiteralPlaceholders): RetryNodeDefinition {\n let node = { type: \"retry\" } as RetryNodeDefinition;\n\n // Get the node arguments.\n const nodeArguments = parseArgumentTokens(tokens, stringLiteralPlaceholders);\n\n // The arguments of a retry node are optional. We may have:\n // - No node arguments, in which case the retry note will attempt indefinitely.\n // - One node argument which will be the explicit number of attempts to make.\n // - Two node arguments which define the min and max attempt bounds from which a random attempt count will be picked.\n if (nodeArguments.length) {\n // All retry node arguments MUST be of type number and must be integer.\n nodeArguments\n .filter((arg) => arg.type !== \"number\" || !arg.isInteger)\n .forEach(() => {\n throw new Error(`retry node attempt counts must be integer values`);\n });\n\n // We should have got one or two attempt counts.\n if (nodeArguments.length === 1) {\n // A static attempt count was defined.\n node.attempts = nodeArguments[0].value as number;\n\n // A retry node must have a positive number of attempts if defined.\n if (node.attempts < 0) {\n throw new Error(\"a retry node must have a positive number of attempts if defined\");\n }\n } else if (nodeArguments.length === 2) {\n // A minimum and maximum attempt count was defined.\n node.attempts = [nodeArguments[0].value as number, nodeArguments[1].value as number];\n\n // A retry node must have a positive min and max attempts count if they are defined.\n if (node.attempts[0] < 0 || node.attempts[1] < 0) {\n throw new Error(\"a retry node must have a positive minimum and maximum attempt count if defined\");\n }\n\n // A retry node must not have a minimum attempt count that exceeds the maximum attempt count.\n if (node.attempts[0] > node.attempts[1]) {\n throw new Error(\n \"a retry node must not have a minimum attempt count that exceeds the maximum attempt count\"\n );\n }\n } else {\n // An incorrect number of attempt counts was defined.\n throw new Error(\"invalid number of retry node attempt count arguments defined\");\n }\n }\n\n // Grab any node attribute definitions and spread them into the node definition.\n node = { ...node, ...parseAttributeTokens(tokens, stringLiteralPlaceholders) };\n\n // This is a decorator node, so we expect an opening '{'.\n popAndCheck(tokens, \"{\");\n\n // Return the retry node definition.\n return node;\n}\n\n/**\n * Creates a sequence node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The sequence node JSON definition.\n */\nfunction createSequenceNode(\n tokens: string[],\n stringLiteralPlaceholders: StringLiteralPlaceholders\n): SequenceNodeDefinition {\n const node = {\n type: \"sequence\",\n ...parseAttributeTokens(tokens, stringLiteralPlaceholders)\n } as SequenceNodeDefinition;\n\n // This is a composite node, so we expect an opening '{'.\n popAndCheck(tokens, \"{\");\n\n // Return the sequence node definition.\n return node;\n}\n\n/**\n * Creates a selector node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The selector node JSON definition.\n */\nfunction createSelectorNode(\n tokens: string[],\n stringLiteralPlaceholders: StringLiteralPlaceholders\n): SelectorNodeDefinition {\n const node = {\n type: \"selector\",\n ...parseAttributeTokens(tokens, stringLiteralPlaceholders)\n } as SelectorNodeDefinition;\n\n // This is a composite node, so we expect an opening '{'.\n popAndCheck(tokens, \"{\");\n\n // Return the selector node definition.\n return node;\n}\n\n/**\n * Creates a parallel node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The parallel node JSON definition.\n */\nfunction createParallelNode(\n tokens: string[],\n stringLiteralPlaceholders: StringLiteralPlaceholders\n): ParallelNodeDefinition {\n const node = {\n type: \"parallel\",\n ...parseAttributeTokens(tokens, stringLiteralPlaceholders)\n } as ParallelNodeDefinition;\n\n // This is a composite node, so we expect an opening '{'.\n popAndCheck(tokens, \"{\");\n\n // Return the parallel node definition.\n return node;\n}\n\n/**\n * Creates a lotto node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The lotto node JSON definition.\n */\nfunction createLottoNode(tokens: string[], stringLiteralPlaceholders: StringLiteralPlaceholders): LottoNodeDefinition {\n // If any node arguments have been defined then they must be our weights.\n const nodeArguments = parseArgumentTokens(tokens, stringLiteralPlaceholders);\n\n // All lotto node arguments MUST be of type number and must be positive integers.\n nodeArguments\n .filter((arg) => arg.type !== \"number\" || !arg.isInteger || arg.value < 0)\n .forEach(() => {\n throw new Error(`lotto node weight arguments must be positive integer values`);\n });\n\n const node = {\n type: \"lotto\",\n weights: nodeArguments.length ? nodeArguments.map(({ value }) => value) : undefined,\n ...parseAttributeTokens(tokens, stringLiteralPlaceholders)\n } as LottoNodeDefinition;\n\n // This is a composite node, so we expect an opening '{'.\n popAndCheck(tokens, \"{\");\n\n // Return the lotto node definition.\n return node;\n}\n\n/**\n * Creates an action node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The action node JSON definition.\n */\nfunction createActionNode(\n tokens: string[],\n stringLiteralPlaceholders: StringLiteralPlaceholders\n): ActionNodeDefinition {\n // Parse any node arguments, we should have at least one which will be an identifier argument for the action name\n // and agent function to invoke for the action, all other arguments are to be passed as arguments to that function.\n const [actionNameIdentifier, ...agentFunctionArgs] = parseArgumentTokens(tokens, stringLiteralPlaceholders);\n\n // Our first argument MUST be defined and be an identifier as we require an action name argument.\n if (actionNameIdentifier?.type !== \"identifier\") {\n throw new Error(\"expected action name identifier argument\");\n }\n\n // Only the first argument should have been an identifier, all agent function arguments must be string, number, boolean or null.\n agentFunctionArgs\n .filter((arg) => arg.type === \"identifier\")\n .forEach((arg) => {\n throw new Error(\n `invalid action node argument value '${arg.value}', must be string, number, boolean or null`\n );\n });\n\n // Return the action node definition.\n return {\n type: \"action\",\n call: actionNameIdentifier.value,\n args: agentFunctionArgs.map(({ value }) => value),\n ...parseAttributeTokens(tokens, stringLiteralPlaceholders)\n };\n}\n\n/**\n * Creates a condition node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The condition node JSON definition.\n */\nfunction createConditionNode(\n tokens: string[],\n stringLiteralPlaceholders: StringLiteralPlaceholders\n): ConditionNodeDefinition {\n // Parse any node arguments, we should have at least one which will be an identifier argument for the condition name\n // and agent function to invoke for the condition, all other arguments are to be passed as arguments to that function.\n const [conditionNameIdentifier, ...agentFunctionArgs] = parseArgumentTokens(tokens, stringLiteralPlaceholders);\n\n // Our first argument MUST be defined and be an identifier as we require a condition name argument.\n if (conditionNameIdentifier?.type !== \"identifier\") {\n throw new Error(\"expected condition name identifier argument\");\n }\n\n // Only the first argument should have been an identifier, all agent function arguments must be string, number, boolean or null.\n agentFunctionArgs\n .filter((arg) => arg.type === \"identifier\")\n .forEach((arg) => {\n throw new Error(\n `invalid condition node argument value '${arg.value}', must be string, number, boolean or null`\n );\n });\n\n // Return the condition node definition.\n return {\n type: \"condition\",\n call: conditionNameIdentifier.value,\n args: agentFunctionArgs.map(({ value }) => value),\n ...parseAttributeTokens(tokens, stringLiteralPlaceholders)\n };\n}\n\n/**\n * Creates a wait node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The wait node JSON definition.\n */\nfunction createWaitNode(tokens: string[], stringLiteralPlaceholders: StringLiteralPlaceholders): WaitNodeDefinition {\n let node = { type: \"wait\" } as WaitNodeDefinition;\n\n // Get the node arguments.\n const nodeArguments = parseArgumentTokens(tokens, stringLiteralPlaceholders);\n\n // The arguments of a wait node are optional. We may have:\n // - No node arguments, in which case the wait will be indefinite until it is aborted.\n // - One node argument which will be the explicit duration of the wait.\n // - Two node arguments which define the min and max duration bounds from which a random duration will be picked.\n if (nodeArguments.length) {\n // All wait node arguments MUST be of type number and must be integer.\n nodeArguments\n .filter((arg) => arg.type !== \"number\" || !arg.isInteger)\n .forEach(() => {\n throw new Error(`wait node durations must be integer values`);\n });\n\n // We may have:\n // - One node argument which will be the explicit duration of the wait.\n // - Two node arguments which define the min and max duration bounds from which a random duration will be picked.\n // - Too many arguments, which is not valid.\n if (nodeArguments.length === 1) {\n // An explicit duration was defined.\n node.duration = nodeArguments[0].value as number;\n\n // If an explict duration was defined then it must be a positive number.\n if (node.duration < 0) {\n throw new Error(\"a wait node must have a positive duration\");\n }\n } else if (nodeArguments.length === 2) {\n // Min and max duration bounds were defined from which a random duration will be picked.\n node.duration = [nodeArguments[0].value as number, nodeArguments[1].value as number];\n\n // A wait node must have a positive min and max duration.\n if (node.duration[0] < 0 || node.duration[1] < 0) {\n throw new Error(\"a wait node must have a positive minimum and maximum duration\");\n }\n\n // A wait node must not have a minimum duration that exceeds the maximum duration.\n if (node.duration[0] > node.duration[1]) {\n throw new Error(\"a wait node must not have a minimum duration that exceeds the maximum duration\");\n }\n } else if (nodeArguments.length > 2) {\n // An incorrect number of duration arguments were defined.\n throw new Error(\"invalid number of wait node duration arguments defined\");\n }\n }\n\n // Return the wait node definition.\n return { ...node, ...parseAttributeTokens(tokens, stringLiteralPlaceholders) };\n}\n\n/**\n * Creates a branch node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The branch node JSON definition.\n */\nfunction createBranchNode(\n tokens: string[],\n stringLiteralPlaceholders: StringLiteralPlaceholders\n): BranchNodeDefinition {\n // Parse any node arguments, we should have one which will be an identifier argument for the root ref.\n const nodeArguments = parseArgumentTokens(tokens, stringLiteralPlaceholders);\n\n // We should have only a single identifer argument for a branch node, which is the root ref.\n if (nodeArguments.length !== 1 || nodeArguments[0].type !== \"identifier\") {\n throw new Error(\"expected single branch name argument\");\n }\n\n // Return the branch node definition.\n return { type: \"branch\", ref: nodeArguments[0].value };\n}\n\n/**\n * Validate a fully-populated node definition that was popped off of the tree stack.\n * @param definition The popped node to validate.\n */\nfunction validatePoppedNode(definition: AnyNodeDefinition): void {\n // Decorators MUST have a child defined.\n if (isDecoratorNode(definition) && isNullOrUndefined(definition.child)) {\n throw new Error(`a ${definition.type} node must have a single child node defined`);\n }\n\n // Composites MUST have at least one child defined.\n if (isCompositeNode(definition) && !definition.children?.length) {\n throw new Error(`a ${definition.type} node must have at least a single child node defined`);\n }\n\n // We need to make sure that lotto nodes that have weights defined have a number of weights matching the number of child nodes.\n if (definition.type === \"lotto\") {\n // Check whether a 'weights' property has been defined, if it has we expect it to be an array of weights.\n if (typeof definition.weights !== \"undefined\") {\n // Check that the weights property is an array of positive integers with an element for each child node element.\n if (definition.weights.length !== definition.children.length) {\n throw new Error(\n \"expected a number of weight arguments matching the number of child nodes for lotto node\"\n );\n }\n }\n }\n}\n", "import { RootNodeDefinition } from \"./BehaviourTreeDefinition\";\nimport { flattenDefinition, isBranchNode, isInteger } from \"./BehaviourTreeDefinitionUtilities\";\nimport { convertMDSLToJSON } from \"./mdsl/MDSLDefinitionParser\";\n\n/**\n * An object representing the result of validating a tree definition.\n */\nexport type DefinitionValidationResult = {\n /**\n * A flag defining whether validation succeeded.\n */\n succeeded: boolean;\n /**\n * A string containing the error message if validation did not succeed.\n */\n errorMessage?: string;\n /**\n * The definition as json if the validation was successful, or undefined if validation did not succeed.\n */\n json?: RootNodeDefinition[];\n};\n\n/**\n * Validates the specified behaviour tree definition in the form of JSON or MDSL, not taking any globally registered subtrees into consideration.\n * @param definition The behaviour tree definition in the form of JSON or MDSL.\n * @returns An object representing the result of validating the given tree definition.\n */\nexport function validateDefinition(definition: any): DefinitionValidationResult {\n // The definition must be defined.\n if (definition === null || typeof definition === \"undefined\") {\n return createValidationFailureResult(\"definition is null or undefined\");\n }\n\n // We are expecting a definition in one of three different forms:\n // - A string which we will assume is MDSL and we will parse this to JSON before validation.\n // - An array which we will assume is an array of root node definitions with at least one being the primary root node (no 'id' property)\n // - An object which we will assume is the primary root node and should not have an 'id' property.\n if (typeof definition === \"string\") {\n // The definition is a string which we can assume is MDSL, so attempt to validate it.\n return validateMDSLDefinition(definition);\n } else if (typeof definition === \"object\") {\n // The definition will either be an array (of root node definitions) or an object (the single primary root node definition).\n return validateJSONDefinition(definition);\n } else {\n return createValidationFailureResult(`unexpected definition type of '${typeof definition}'`);\n }\n}\n\n/**\n * Validates the specified behaviour tree definition in the form of MDSL.\n * @param definition The behaviour tree definition in the form of MDSL.\n * @returns An object representing the result of validating the given tree definition.\n */\nfunction validateMDSLDefinition(definition: string): DefinitionValidationResult {\n let rootNodeDefinitions;\n\n // The first thing the we need to do is to attempt to convert our MDSL into JSON.\n try {\n // The definition is a string which we can assume is MDSL, so attempt to parse it to a JSON definition in the form of an array of root node definitions.\n rootNodeDefinitions = convertMDSLToJSON(definition);\n } catch (exception) {\n // We failed to parse the JSON from the MDSL, this is likely to be the result of it not being a valid MDSL string.\n return createValidationFailureResult((exception as Error).message);\n }\n\n // Unpack all of the root node definitions into arrays of main ('id' defined) and sub ('id' not defined) root node definitions.\n const mainRootNodeDefinitions = rootNodeDefinitions.filter(({ id }) => typeof id === \"undefined\");\n const subRootNodeDefinitions = rootNodeDefinitions.filter(({ id }) => typeof id === \"string\" && id.length > 0);\n\n // We should ALWAYS have exactly one root node definition without an 'id' property defined, which is out main root node definition.\n if (mainRootNodeDefinitions.length !== 1) {\n return createValidationFailureResult(\n \"expected single unnamed root node at base of definition to act as main root\"\n );\n }\n\n // We should never have duplicate 'id' properties across our sub root node definitions.\n const subRootNodeIdenitifers: string[] = [];\n for (const { id } of subRootNodeDefinitions) {\n // Have we already come across this 'id' property value?\n if (subRootNodeIdenitifers.includes(id!)) {\n return createValidationFailureResult(`multiple root nodes found with duplicate name '${id}'`);\n }\n\n subRootNodeIdenitifers.push(id!);\n }\n\n try {\n // Validate our branch -> subtree links and check for any circular dependencies, we don't care about checking for broken subtree links here.\n validateBranchSubtreeLinks(rootNodeDefinitions, false);\n } catch (exception) {\n return createValidationFailureResult((exception as Error).message);\n }\n\n // Our definition was valid!\n return {\n succeeded: true,\n json: rootNodeDefinitions\n };\n}\n\n/**\n * Validates the specified behaviour tree definition in the form of JSON.\n * @param definition The behaviour tree definition in the form of JSON.\n * @returns An object representing the result of validating the given tree definition.\n */\nexport function validateJSONDefinition(\n definition: RootNodeDefinition | RootNodeDefinition[]\n): DefinitionValidationResult {\n // The definition will either be an array (of root node definitions) or an object (the single primary root node definition).\n const rootNodeDefinitions = Array.isArray(definition) ? definition : [definition];\n\n // Iterate over our array of root nodes and call validateNode for each, passing an initial depth of 0, wrapped in a try catch to handle validation failures.\n try {\n rootNodeDefinitions.forEach((rootNodeDefinition) => validateNode(rootNodeDefinition, 0));\n } catch (error) {\n // Handle cases where we have caught a thrown Error and return a failure result with the error message.\n if (error instanceof Error) {\n return createValidationFailureResult(error.message);\n }\n\n // No idea what happened here!\n return createValidationFailureResult(`unexpected error: ${error}`);\n }\n\n // Unpack all of the root node definitions into arrays of main ('id' defined) and sub ('id' not defined) root node definitions.\n const mainRootNodeDefinitions = rootNodeDefinitions.filter(({ id }) => typeof id === \"undefined\");\n const subRootNodeDefinitions = rootNodeDefinitions.filter(({ id }) => typeof id === \"string\" && id.length > 0);\n\n // We should ALWAYS have exactly one root node definition without an 'id' property defined, which is out main root node definition.\n if (mainRootNodeDefinitions.length !== 1) {\n return createValidationFailureResult(\n \"expected single root node without 'id' property defined to act as main root\"\n );\n }\n\n // We should never have duplicate 'id' properties across our sub root node definitions.\n const subRootNodeIdenitifers: string[] = [];\n for (const { id } of subRootNodeDefinitions) {\n // Have we already come across this 'id' property value?\n if (subRootNodeIdenitifers.includes(id!)) {\n return createValidationFailureResult(\n `multiple root nodes found with duplicate 'id' property value of '${id}'`\n );\n }\n\n subRootNodeIdenitifers.push(id!);\n }\n\n try {\n // Validate our branch -> subtree links and check for any circular dependencies, we don't care about checking for broken subtree links here.\n validateBranchSubtreeLinks(rootNodeDefinitions, false);\n } catch (exception) {\n return createValidationFailureResult((exception as Error).message);\n }\n\n // Our definition was valid!\n return {\n succeeded: true,\n json: rootNodeDefinitions\n };\n}\n\n/**\n * Validates the branch -> subtree links across all provided root node definitions.\n * This will not consider branch nodes that reference any globally registered subtrees unless includesGlobalSubtrees\n * is set to true, in which case we will also verify that there are no broken branch -> subtree links.\n * @param rootNodeDefinitions The array of root node definitions.\n * @param includesGlobalSubtrees A flag defining whether the array includes all global subtree root node definitions.\n */\nexport function validateBranchSubtreeLinks(rootNodeDefinitions: RootNodeDefinition[], includesGlobalSubtrees: boolean) {\n // Create a mapping of root node identifiers to other root nodes that they reference via branch nodes.\n // Below is an example of a mapping that includes a circular dependency (root => a => b => c => a)\n // [{ refs: [\"a\", \"b\"] }, { id: \"a\", refs: [\"b\"] }, { id: \"b\", refs: [\"c\"] }, { id: \"c\", refs: [\"a\"] }]\n const rootNodeMappings: { id: string | undefined; refs: string[] }[] = rootNodeDefinitions.map(\n (rootNodeDefinition) => ({\n id: rootNodeDefinition.id,\n refs: flattenDefinition(rootNodeDefinition)\n .filter(isBranchNode)\n .map(({ ref }) => ref)\n })\n );\n\n // A recursive function to walk through the mappings, keeping track of which root nodes we have visited in the form of a path of root node identifiers.\n const followRefs = (mapping: { id: string | undefined; refs: string[] }, path: (string | undefined)[] = []) => {\n // Have we found a circular dependency?\n if (path.includes(mapping.id)) {\n // We found a circular dependency! Get the bad path of root node identifiers.\n const badPath = [...path, mapping.id];\n\n // Create the formatted path value. [undefined, \"a\", \"b\", \"c\", \"a\"] would be formatted as \"a -> b -> c -> a\".\n const badPathFormatted = badPath.filter((element) => !!element).join(\" => \");\n\n // No need to continue, we found a circular dependency.\n throw new Error(`circular dependency found in branch node references: ${badPathFormatted}`);\n }\n\n for (const ref of mapping.refs) {\n // Find the mapping for the root node with an identifer matching the current ref.\n const subMapping = rootNodeMappings.find(({ id }) => id === ref);\n\n // We may not have a mapping for this ref, which is normal when we aren't considering all globally registered subtrees.\n if (subMapping) {\n followRefs(subMapping, [...path, mapping.id]);\n } else if (includesGlobalSubtrees) {\n // We found a reference to a root node that doesn't exist, which is a problem seeing as the root node definitons includes all globally registered subtrees.\n throw new Error(\n mapping.id\n ? `subtree '${mapping.id}' has branch node that references root node '${ref}' which has not been defined`\n : `primary tree has branch node that references root node '${ref}' which has not been defined`\n );\n }\n }\n };\n\n // Start looking for circular dependencies and broken references from the primary root node definition.\n followRefs(rootNodeMappings.find((mapping) => typeof mapping.id === \"undefined\")!);\n}\n\n/**\n * Validate an object that we expect to be a node definition.\n * @param definition An object that we expect to be a node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateNode(definition: any, depth: number): void {\n // Every node must be valid object and have a non-empty 'type' string property.\n if (typeof definition !== \"object\" || typeof definition.type !== \"string\" || definition.type.length === 0) {\n throw new Error(\n `node definition is not an object or 'type' property is not a non-empty string at depth '${depth}'`\n );\n }\n\n // How we validate this node definition will depend on its type.\n switch (definition.type) {\n case \"action\":\n validateActionNode(definition, depth);\n break;\n\n case \"condition\":\n validateConditionNode(definition, depth);\n break;\n\n case \"wait\":\n validateWaitNode(definition, depth);\n break;\n\n case \"branch\":\n validateBranchNode(definition, depth);\n break;\n\n case \"root\":\n validateRootNode(definition, depth);\n break;\n\n case \"succeed\":\n validateSucceedNode(definition, depth);\n break;\n\n case \"fail\":\n validateFailNode(definition, depth);\n break;\n\n case \"flip\":\n validateFlipNode(definition, depth);\n break;\n\n case \"repeat\":\n validateRepeatNode(definition, depth);\n break;\n\n case \"retry\":\n validateRetryNode(definition, depth);\n break;\n\n case \"sequence\":\n validateSequenceNode(definition, depth);\n break;\n\n case \"selector\":\n validateSelectorNode(definition, depth);\n break;\n\n case \"parallel\":\n validateParallelNode(definition, depth);\n break;\n\n case \"lotto\":\n validateLottoNode(definition, depth);\n break;\n\n default:\n throw new Error(`unexpected node type of '${definition.type}' at depth '${depth}'`);\n }\n}\n\n/**\n * Validate any attributes for a given node definition.\n * @param definition The node definition.\n * @param depth The depth of the node in the behaviour tree definition.\n */\nfunction validateNodeAttributes(definition: any, depth: number): void {\n // Validate each of the attribute types for this node.\n [\"while\", \"until\", \"entry\", \"exit\", \"step\"].forEach((attributeName) => {\n // Attempt to grab the definition for the current attribute from the node definition.\n const attributeDefinition = definition[attributeName];\n\n // All node attributes are optional, so there is nothing to do if the current attribute is not defined.\n if (typeof attributeDefinition === \"undefined\") {\n return;\n }\n\n // The attribute definition must be an object.\n if (typeof attributeDefinition !== \"object\") {\n throw new Error(\n `expected attribute '${attributeName}' to be an object for '${definition.type}' node at depth '${depth}'`\n );\n }\n\n // The 'call' property must be defined for any attribute definition.\n if (typeof attributeDefinition.call !== \"string\" || attributeDefinition.call.length === 0) {\n throw new Error(\n `expected 'call' property for attribute '${attributeName}' to be a non-empty string for '${definition.type}' node at depth '${depth}'`\n );\n }\n\n // If any node attribute arguments have been defined then they must have been defined in an array.\n if (typeof attributeDefinition.args !== \"undefined\" && !Array.isArray(attributeDefinition.args)) {\n throw new Error(\n `expected 'args' property for attribute '${attributeName}' to be an array for '${definition.type}' node at depth '${depth}'`\n );\n }\n });\n}\n\n/**\n * Validate an object that we expect to be a root node definition.\n * @param definition An object that we expect to be a root node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateRootNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"root\") {\n throw new Error(\"expected node type of 'root' for root node\");\n }\n\n // A root node cannot be the child of another node.\n if (depth > 0) {\n throw new Error(\"a root node cannot be the child of another node\");\n }\n\n // Check that, if the root node 'id' property is defined, it is a non-empty string.\n if (typeof definition.id !== \"undefined\" && (typeof definition.id !== \"string\" || definition.id.length === 0)) {\n throw new Error(\"expected non-empty string for 'id' property if defined for root node\");\n }\n\n // A root node is a decorator node, so must have a child node defined.\n if (typeof definition.child === \"undefined\") {\n throw new Error(\"expected property 'child' to be defined for root node\");\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n\n // Validate the child node of this decorator node.\n validateNode(definition.child, depth + 1);\n}\n\n/**\n * Validate an object that we expect to be a succeed node definition.\n * @param definition An object that we expect to be a succeed node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateSucceedNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"succeed\") {\n throw new Error(`expected node type of 'succeed' for succeed node at depth '${depth}'`);\n }\n\n // A succeed node is a decorator node, so must have a child node defined.\n if (typeof definition.child === \"undefined\") {\n throw new Error(`expected property 'child' to be defined for succeed node at depth '${depth}'`);\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n\n // Validate the child node of this decorator node.\n validateNode(definition.child, depth + 1);\n}\n\n/**\n * Validate an object that we expect to be a fail node definition.\n * @param definition An object that we expect to be a fail node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateFailNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"fail\") {\n throw new Error(`expected node type of 'fail' for fail node at depth '${depth}'`);\n }\n\n // A fail node is a decorator node, so must have a child node defined.\n if (typeof definition.child === \"undefined\") {\n throw new Error(`expected property 'child' to be defined for fail node at depth '${depth}'`);\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n\n // Validate the child node of this decorator node.\n validateNode(definition.child, depth + 1);\n}\n\n/**\n * Validate an object that we expect to be a flip node definition.\n * @param definition An object that we expect to be a flip node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateFlipNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"flip\") {\n throw new Error(`expected node type of 'flip' for flip node at depth '${depth}'`);\n }\n\n // A flip node is a decorator node, so must have a child node defined.\n if (typeof definition.child === \"undefined\") {\n throw new Error(`expected property 'child' to be defined for flip node at depth '${depth}'`);\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n\n // Validate the child node of this decorator node.\n validateNode(definition.child, depth + 1);\n}\n\n/**\n * Validate an object that we expect to be a repeat node definition.\n * @param definition An object that we expect to be a repeat node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateRepeatNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"repeat\") {\n throw new Error(`expected node type of 'repeat' for repeat node at depth '${depth}'`);\n }\n\n // A repeat node is a decorator node, so must have a child node defined.\n if (typeof definition.child === \"undefined\") {\n throw new Error(`expected property 'child' to be defined for repeat node at depth '${depth}'`);\n }\n\n // Check whether an 'iterations' property has been defined, it may not have been if this node is to repeat indefinitely.\n if (typeof definition.iterations !== \"undefined\") {\n if (Array.isArray(definition.iterations)) {\n // Check whether any elements of the array are not integer values.\n const containsNonInteger = !!definition.iterations.filter((value: unknown) => !isInteger(value)).length;\n\n // If the 'iterations' property is an array then it MUST contain two integer values.\n if (definition.iterations.length !== 2 || containsNonInteger) {\n throw new Error(\n `expected array containing two integer values for 'iterations' property if defined for repeat node at depth '${depth}'`\n );\n }\n\n // A repeat node must have a positive min and max iterations count if they are defined.\n if (definition.iterations[0] < 0 || definition.iterations[1] < 0) {\n throw new Error(\n `expected positive minimum and maximum iterations count for 'iterations' property if defined for repeat node at depth '${depth}'`\n );\n }\n\n // A repeat node must not have a minimum iterations count that exceeds the maximum iterations count.\n if (definition.iterations[0] > definition.iterations[1]) {\n throw new Error(\n `expected minimum iterations count that does not exceed the maximum iterations count for 'iterations' property if defined for repeat node at depth '${depth}'`\n );\n }\n } else if (isInteger(definition.iterations)) {\n // A repeat node must have a positive number of iterations if defined.\n if (definition.iterations < 0) {\n throw new Error(\n `expected positive iterations count for 'iterations' property if defined for repeat node at depth '${depth}'`\n );\n }\n } else {\n throw new Error(\n `expected integer value or array containing two integer values for 'iterations' property if defined for repeat node at depth '${depth}'`\n );\n }\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n\n // Validate the child node of this decorator node.\n validateNode(definition.child, depth + 1);\n}\n\n/**\n * Validate an object that we expect to be a retry node definition.\n * @param definition An object that we expect to be a retry node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateRetryNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"retry\") {\n throw new Error(`expected node type of 'retry' for retry node at depth '${depth}'`);\n }\n\n // A retry node is a decorator node, so must have a child node defined.\n if (typeof definition.child === \"undefined\") {\n throw new Error(`expected property 'child' to be defined for retry node at depth '${depth}'`);\n }\n\n // Check whether an 'attempts' property has been defined, it may not have been if this node is to retry indefinitely.\n if (typeof definition.attempts !== \"undefined\") {\n if (Array.isArray(definition.attempts)) {\n // Check whether any elements of the array are not integer values.\n const containsNonInteger = !!definition.attempts.filter((value: unknown) => !isInteger(value)).length;\n\n // If the 'attempts' property is an array then it MUST contain two integer values.\n if (definition.attempts.length !== 2 || containsNonInteger) {\n throw new Error(\n `expected array containing two integer values for 'attempts' property if defined for retry node at depth '${depth}'`\n );\n }\n\n // A retry node must have a positive min and max attempts count if they are defined.\n if (definition.attempts[0] < 0 || definition.attempts[1] < 0) {\n throw new Error(\n `expected positive minimum and maximum attempts count for 'attempts' property if defined for retry node at depth '${depth}'`\n );\n }\n\n // A retry node must not have a minimum attempts count that exceeds the maximum attempts count.\n if (definition.attempts[0] > definition.attempts[1]) {\n throw new Error(\n `expected minimum attempts count that does not exceed the maximum attempts count for 'attempts' property if defined for retry node at depth '${depth}'`\n );\n }\n } else if (isInteger(definition.attempts)) {\n // A retry node must have a positive number of attempts if defined.\n if (definition.attempts < 0) {\n throw new Error(\n `expected positive attempts count for 'attempts' property if defined for retry node at depth '${depth}'`\n );\n }\n } else {\n throw new Error(\n `expected integer value or array containing two integer values for 'attempts' property if defined for retry node at depth '${depth}'`\n );\n }\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n\n // Validate the child node of this decorator node.\n validateNode(definition.child, depth + 1);\n}\n\n/**\n * Validate an object that we expect to be a branch node definition.\n * @param definition An object that we expect to be a branch node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateBranchNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"branch\") {\n throw new Error(`expected node type of 'branch' for branch node at depth '${depth}'`);\n }\n\n // Check that the branch node 'ref' property is defined and is a non-empty string.\n if (typeof definition.ref !== \"string\" || definition.ref.length === 0) {\n throw new Error(`expected non-empty string for 'ref' property for branch node at depth '${depth}'`);\n }\n\n // It is invalid to define guard attributes for a branch node as they should be defined on the referenced root node.\n [\"while\", \"until\"].forEach((attributeName) => {\n if (typeof definition[attributeName] !== \"undefined\") {\n throw new Error(\n `guards should not be defined for branch nodes but guard '${attributeName}' was defined for branch node at depth '${depth}'`\n );\n }\n });\n\n // It is invalid to define callback attributes for a branch node as they should be defined on the referenced root node.\n [\"entry\", \"exit\", \"step\"].forEach((attributeName) => {\n if (typeof definition[attributeName] !== \"undefined\") {\n throw new Error(\n `callbacks should not be defined for branch nodes but callback '${attributeName}' was defined for branch node at depth '${depth}'`\n );\n }\n });\n}\n\n/**\n * Validate an object that we expect to be a action node definition.\n * @param definition An object that we expect to be a action node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateActionNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"action\") {\n throw new Error(`expected node type of 'action' for action node at depth '${depth}'`);\n }\n\n // The 'call' property must be defined for a action node definition.\n if (typeof definition.call !== \"string\" || definition.call.length === 0) {\n throw new Error(`expected non-empty string for 'call' property of action node at depth '${depth}'`);\n }\n\n // If any action function arguments have been defined then they must have been defined in an array.\n if (typeof definition.args !== \"undefined\" && !Array.isArray(definition.args)) {\n throw new Error(`expected array for 'args' property if defined for action node at depth '${depth}'`);\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n}\n\n/**\n * Validate an object that we expect to be a condition node definition.\n * @param definition An object that we expect to be a condition node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateConditionNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"condition\") {\n throw new Error(`expected node type of 'condition' for condition node at depth '${depth}'`);\n }\n\n // The 'call' property must be defined for a condition node definition.\n if (typeof definition.call !== \"string\" || definition.call.length === 0) {\n throw new Error(`expected non-empty string for 'call' property of condition node at depth '${depth}'`);\n }\n\n // If any condition function arguments have been defined then they must have been defined in an array.\n if (typeof definition.args !== \"undefined\" && !Array.isArray(definition.args)) {\n throw new Error(`expected array for 'args' property if defined for condition node at depth '${depth}'`);\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n}\n\n/**\n * Validate an object that we expect to be a wait node definition.\n * @param definition An object that we expect to be a wait node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateWaitNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"wait\") {\n throw new Error(`expected node type of 'wait' for wait node at depth '${depth}'`);\n }\n\n // Check whether a 'duration' property has been defined, it may not have been if this node is to wait indefinitely.\n if (typeof definition.duration !== \"undefined\") {\n if (Array.isArray(definition.duration)) {\n // Check whether any elements of the array are not integer values.\n const containsNonInteger = !!definition.duration.filter((value: unknown) => !isInteger(value)).length;\n\n // If the 'duration' property is an array then it MUST contain two integer values.\n if (definition.duration.length !== 2 || containsNonInteger) {\n throw new Error(\n `expected array containing two integer values for 'duration' property if defined for wait node at depth '${depth}'`\n );\n }\n\n // A wait node must have a positive min and max duration value if they are defined.\n if (definition.duration[0] < 0 || definition.duration[1] < 0) {\n throw new Error(\n `expected positive minimum and maximum duration for 'duration' property if defined for wait node at depth '${depth}'`\n );\n }\n\n // A wait node must not have a minimum duration value that exceeds the maximum duration value.\n if (definition.duration[0] > definition.duration[1]) {\n throw new Error(\n `expected minimum duration value that does not exceed the maximum duration value for 'duration' property if defined for wait node at depth '${depth}'`\n );\n }\n } else if (isInteger(definition.duration)) {\n // A wait node must have a positive duration value if defined.\n if (definition.duration < 0) {\n throw new Error(\n `expected positive duration value for 'duration' property if defined for wait node at depth '${depth}'`\n );\n }\n } else {\n throw new Error(\n `expected integer value or array containing two integer values for 'duration' property if defined for wait node at depth '${depth}'`\n );\n }\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n}\n\n/**\n * Validate an object that we expect to be a sequence node definition.\n * @param definition An object that we expect to be a sequence node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateSequenceNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"sequence\") {\n throw new Error(`expected node type of 'sequence' for sequence node at depth '${depth}'`);\n }\n\n // A sequence node is a composite node, so must have a children nodes array defined.\n if (!Array.isArray(definition.children) || definition.children.length === 0) {\n throw new Error(`expected non-empty 'children' array to be defined for sequence node at depth '${depth}'`);\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n\n // Validate the child nodes of this composite node.\n definition.children.forEach((child: any) => validateNode(child, depth + 1));\n}\n\n/**\n * Validate an object that we expect to be a selector node definition.\n * @param definition An object that we expect to be a selector node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateSelectorNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"selector\") {\n throw new Error(`expected node type of 'selector' for selector node at depth '${depth}'`);\n }\n\n // A selector node is a composite node, so must have a children nodes array defined.\n if (!Array.isArray(definition.children) || definition.children.length === 0) {\n throw new Error(`expected non-empty 'children' array to be defined for selector node at depth '${depth}'`);\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n\n // Validate the child nodes of this composite node.\n definition.children.forEach((child: any) => validateNode(child, depth + 1));\n}\n\n/**\n * Validate an object that we expect to be a parallel node definition.\n * @param definition An object that we expect to be a parallel node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateParallelNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"parallel\") {\n throw new Error(`expected node type of 'parallel' for parallel node at depth '${depth}'`);\n }\n\n // A parallel node is a composite node, so must have a children nodes array defined.\n if (!Array.isArray(definition.children) || definition.children.length === 0) {\n throw new Error(`expected non-empty 'children' array to be defined for parallel node at depth '${depth}'`);\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n\n // Validate the child nodes of this composite node.\n definition.children.forEach((child: any) => validateNode(child, depth + 1));\n}\n\n/**\n * Validate an object that we expect to be a lotto node definition.\n * @param definition An object that we expect to be a lotto node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateLottoNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"lotto\") {\n throw new Error(`expected node type of 'lotto' for lotto node at depth '${depth}'`);\n }\n\n // A lotto node is a composite node, so must have a children nodes array defined.\n if (!Array.isArray(definition.children) || definition.children.length === 0) {\n throw new Error(`expected non-empty 'children' array to be defined for lotto node at depth '${depth}'`);\n }\n\n // Check whether a 'weights' property has been defined, if it has we expect it to be an array of weights.\n if (typeof definition.weights !== \"undefined\") {\n // Check that the weights property is an array of positive integers with an element for each child node element.\n if (\n !Array.isArray(definition.weights) ||\n definition.weights.length !== definition.children.length ||\n definition.weights.filter((value: unknown) => !isInteger(value)).length ||\n definition.weights.filter((value: number) => value < 0).length\n ) {\n throw new Error(\n `expected an array of positive integer weight values with a length matching the number of child nodes for 'weights' property if defined for lotto node at depth '${depth}'`\n );\n }\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n\n // Validate the child nodes of this composite node.\n definition.children.forEach((child: any) => validateNode(child, depth + 1));\n}\n\n/**\n * A helper function to create a failure validation result with the given error message.\n * @param errorMessage The validation failure error message.\n * @returns A failure validation result with the given error message.\n */\nfunction createValidationFailureResult(errorMessage: string): DefinitionValidationResult {\n return { succeeded: false, errorMessage };\n}\n", "import { ActionResult, Agent, GlobalFunction } from \"./Agent\";\nimport { RootNodeDefinition } from \"./BehaviourTreeDefinition\";\n\nexport type InvokerFunction = (args: any[]) => ActionResult;\n\n/**\n * A singleton used to store and lookup registered functions and subtrees.\n */\nexport default class Lookup {\n /**\n * The object holding any registered functions keyed on function name.\n */\n private static functionTable: { [key: string]: GlobalFunction } = {};\n /**\n * The object holding any registered subtree root node definitions keyed on tree name.\n */\n private static subtreeTable: { [key: string]: RootNodeDefinition } = {};\n\n /**\n * Gets the function with the specified name.\n * @param name The name of the function.\n * @returns The function with the specified name.\n */\n public static getFunc(name: string): GlobalFunction {\n return this.functionTable[name];\n }\n\n /**\n * Sets the function with the specified name for later lookup.\n * @param name The name of the function.\n * @param func The function.\n */\n public static setFunc(name: string, func: GlobalFunction): void {\n this.functionTable[name] = func;\n }\n\n /**\n * Gets the function invoker for the specified agent and function name.\n * If a function with the specified name exists on the agent object then it will\n * be returned, otherwise we will then check the registered functions for a match.\n * @param agent The agent instance that this behaviour tree is modelling behaviour for.\n * @param name The function name.\n * @returns The function invoker for the specified agent and function name.\n */\n static getFuncInvoker(agent: Agent, name: string): InvokerFunction | null {\n // Check whether the agent contains the specified function.\n const foundOnAgent = agent[name];\n if (foundOnAgent && typeof foundOnAgent === \"function\") {\n return (args: any[]): boolean | ActionResult => foundOnAgent.apply(agent, args);\n }\n\n // The agent does not contain the specified function but it may have been registered at some point.\n if (this.functionTable[name] && typeof this.functionTable[name] === \"function\") {\n return (args: any[]) => this.functionTable[name](agent, ...args.map((arg) => arg.value));\n }\n\n // We have no function to invoke.\n return null;\n }\n\n /**\n * Gets all registered subtree root node definitions.\n */\n static getSubtrees(): { [key: string]: RootNodeDefinition } {\n return this.subtreeTable;\n }\n\n /**\n * Sets the subtree with the specified name for later lookup.\n * @param name The name of the subtree.\n * @param subtree The subtree.\n */\n static setSubtree(name: string, subtree: RootNodeDefinition) {\n this.subtreeTable[name] = subtree;\n }\n\n /**\n * Removes the registered function or subtree with the specified name.\n * @param name The name of the registered function or subtree.\n */\n static remove(name: string) {\n delete this.functionTable[name];\n delete this.subtreeTable[name];\n }\n\n /**\n * Remove all registered functions and subtrees.\n */\n static empty() {\n this.functionTable = {};\n this.subtreeTable = {};\n }\n}\n", "import Node from \"../../nodes/Node\";\n\n/**\n * An exception thrown when evaluating node guard path conditions and a conditions fails.\n */\nexport default class GuardUnsatisifedException extends Error {\n /**\n * @param source The node at which a guard condition failed.\n */\n constructor(private source: Node) {\n super(\"A guard path condition has failed\");\n }\n\n /**\n * Gets whether the specified node is the node at which a guard condition failed.\n * @param node The node to check against the source node.\n * @returns Whether the specified node is the node at which a guard condition failed.\n */\n isSourceNode = (node: Node) => node === this.source;\n}\n", "import { Agent } from \"../../Agent\";\nimport Guard from \"./Guard\";\nimport Node from \"../../nodes/Node\";\nimport GuardUnsatisifedException from \"./GuardUnsatisifedException\";\n\nexport type GuardPathPart = {\n node: Node;\n guards: Guard[];\n};\n\n/**\n * Represents a path of node guards along a root-to-leaf tree path.\n */\nexport default class GuardPath {\n /**\n * @param nodes An array of objects defining a node instance -> guard link, ordered by node depth.\n */\n constructor(private nodes: GuardPathPart[]) {}\n\n /**\n * Evaluate guard conditions for all guards in the tree path, moving outwards from the root.\n * @param agent The agent, required for guard evaluation.\n * @returns An evaluation results object.\n */\n evaluate = (agent: Agent) => {\n // We need to evaluate guard conditions for nodes up the tree, moving outwards from the root.\n for (const details of this.nodes) {\n // There can be multiple guards per node.\n for (const guard of details.guards) {\n // Check whether the guard condition passes, and throw an exception if not.\n if (!guard.isSatisfied(agent)) {\n throw new GuardUnsatisifedException(details.node);\n }\n }\n }\n };\n}\n", "import { BehaviourTreeOptions } from \"../BehaviourTreeOptions\";\nimport State, { AnyState } from \"../State\";\nimport { Agent } from \"../Agent\";\nimport Leaf from \"./leaf/Leaf\";\nimport Attribute from \"../attributes/Attribute\";\nimport Entry from \"../attributes/callbacks/Entry\";\nimport Exit from \"../attributes/callbacks/Exit\";\nimport Step from \"../attributes/callbacks/Step\";\nimport Guard from \"../attributes/guards/Guard\";\nimport GuardPath from \"../attributes/guards/GuardPath\";\nimport GuardUnsatisifedException from \"../attributes/guards/GuardUnsatisifedException\";\n\n/**\n * A base node.\n */\nexport default abstract class Node {\n /**\n * The node uid.\n */\n private readonly uid: string = createNodeUid();\n /**\n * The node state.\n */\n private state: AnyState = State.READY;\n /**\n * The guard path to evaluate as part of a node update.\n */\n private guardPath: GuardPath | undefined;\n\n /**\n * @param type The node type.\n * @param attributes The node attributes.\n * @param args The node argument definitions.\n */\n constructor(private type: string, private attributes: Attribute[], private args: any[]) {}\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected abstract onUpdate(agent: Agent, options: BehaviourTreeOptions): void;\n\n /**\n * Gets the name of the node.\n */\n public abstract getName(): string;\n\n /**\n * Gets whether this node is a leaf node.\n */\n public abstract isLeafNode: () => this is Leaf;\n\n /**\n * Gets/Sets the state of the node.\n */\n getState = (): AnyState => this.state;\n setState = (value: AnyState): void => {\n this.state = value;\n };\n\n /**\n * Gets the unique id of the node.\n */\n getUid = () => this.uid;\n\n /**\n * Gets the type of the node.\n */\n getType = () => this.type;\n\n /**\n * Gets the node attributes.\n */\n getAttributes = () => this.attributes;\n\n /**\n * Gets the node arguments.\n */\n getArguments = () => this.args;\n\n /**\n * Gets the node attribute with the specified type, or null if it does not exist.\n */\n getAttribute(type: \"entry\" | \"ENTRY\"): Entry;\n getAttribute(type: \"exit\" | \"EXIT\"): Exit;\n getAttribute(type: \"step\" | \"STEP\"): Step;\n getAttribute(type: string): Attribute {\n return (\n this.getAttributes().filter((decorator) => decorator.type.toUpperCase() === type.toUpperCase())[0] || null\n );\n }\n\n /**\n * Gets the node attributes.\n */\n getGuardAttributes = (): Guard[] => this.getAttributes().filter((decorator) => decorator.isGuard()) as Guard[];\n\n /**\n * Sets the guard path to evaluate as part of a node update.\n */\n setGuardPath = (value: GuardPath) => (this.guardPath = value);\n\n /**\n * Gets whether a guard path is assigned to this node.\n */\n hasGuardPath = () => !!this.guardPath;\n\n /**\n * Gets whether this node is in the specified state.\n * @param value The value to compare to the node state.\n */\n public is(value: AnyState): boolean {\n return this.state === value;\n }\n\n /**\n * Reset the state of the node.\n */\n public reset(): void {\n this.setState(State.READY);\n }\n\n /**\n * Abort the running of this node.\n * @param agent The agent.\n */\n public abort(agent: Agent): void {\n // There is nothing to do if this node is not in the running state.\n if (!this.is(State.RUNNING)) {\n return;\n }\n\n // Reset the state of this node.\n this.reset();\n\n this.getAttribute(\"exit\")?.callAgentFunction(agent, false, true);\n }\n\n /**\n * Update the node.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n * @returns The result of the update.\n */\n public update(agent: Agent, options: BehaviourTreeOptions): void {\n // If this node is already in a 'SUCCEEDED' or 'FAILED' state then there is nothing to do.\n if (this.is(State.SUCCEEDED) || this.is(State.FAILED)) {\n return;\n }\n\n try {\n // Evaluate all of the guard path conditions for the current tree path.\n this.guardPath!.evaluate(agent);\n\n // If this node is in the READY state then call the ENTRY for this node if it exists.\n if (this.is(State.READY)) {\n this.getAttribute(\"entry\")?.callAgentFunction(agent);\n }\n\n this.getAttribute(\"step\")?.callAgentFunction(agent);\n\n // Do the actual update.\n this.onUpdate(agent, options);\n\n // If this node is now in a 'SUCCEEDED' or 'FAILED' state then call the EXIT for this node if it exists.\n if (this.is(State.SUCCEEDED) || this.is(State.FAILED)) {\n this.getAttribute(\"exit\")?.callAgentFunction(agent, this.is(State.SUCCEEDED), false);\n }\n } catch (error) {\n // If the error is a GuardUnsatisfiedException then we need to determine if this node is the source.\n if (error instanceof GuardUnsatisifedException && error.isSourceNode(this)) {\n // Abort the current node.\n this.abort(agent);\n\n // Any node that is the source of an abort will be a failed node.\n this.setState(State.FAILED);\n } else {\n throw error;\n }\n }\n }\n}\n\n/**\n * Create a randomly generated node uid.\n * @returns A randomly generated node uid.\n */\nfunction createNodeUid(): string {\n var S4 = function () {\n return (((1 + Math.random()) * 0x10000) | 0).toString(16).substring(1);\n };\n return S4() + S4() + \"-\" + S4() + \"-\" + S4() + \"-\" + S4() + \"-\" + S4() + S4() + S4();\n}\n", "import Node from \"../Node\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\n\n/**\n * A composite node that wraps child nodes.\n */\nexport default abstract class Composite extends Node {\n /**\n * @param type The node type.\n * @param attributes The node attributes.\n * @param children The child nodes.\n */\n constructor(type: string, attributes: Attribute[], protected children: Node[]) {\n super(type, attributes, []);\n }\n\n /**\n * Gets whether this node is a leaf node.\n */\n isLeafNode = () => false;\n\n /**\n * Gets the children of this node.\n */\n getChildren = () => this.children;\n\n /**\n * Reset the state of the node.\n */\n reset = () => {\n // Reset the state of this node.\n this.setState(State.READY);\n\n // Reset the state of any child nodes.\n this.getChildren().forEach((child) => child.reset());\n };\n\n /**\n * Abort the running of this node.\n * @param agent The agent.\n */\n abort = (agent: Agent) => {\n // There is nothing to do if this node is not in the running state.\n if (!this.is(State.RUNNING)) {\n return;\n }\n\n // Abort any child nodes.\n this.getChildren().forEach((child) => child.abort(agent));\n\n // Reset the state of this node.\n this.reset();\n\n this.getAttribute(\"exit\")?.callAgentFunction(agent, false, true);\n };\n}\n", "import Composite from \"./Composite\";\nimport State from \"../../State\";\nimport Node from \"../Node\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A PARALLEL node.\n * The child nodes are executed concurrently until one fails or all succeed.\n */\nexport default class Parallel extends Composite {\n /**\n * @param attributes The node attributes.\n * @param children The child nodes.\n */\n constructor(attributes: Attribute[], children: Node[]) {\n super(\"parallel\", attributes, children);\n }\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // Keep a count of the number of succeeded child nodes.\n let succeededCount = 0;\n\n let hasChildFailed = false;\n\n // Iterate over all of the children of this node.\n for (const child of this.children) {\n // If the child has never been updated or is running then we will need to update it now.\n if (child.getState() === State.READY || child.getState() === State.RUNNING) {\n // Update the child of this node.\n child.update(agent, options);\n }\n\n // If the current child has a state of 'SUCCEEDED' then we should move on to the next child.\n if (child.getState() === State.SUCCEEDED) {\n // The child node has succeeded, keep track of this to determine if all children have.\n succeededCount++;\n\n // The child node succeeded, but we have not finished checking every child node yet.\n continue;\n }\n\n // If the current child has a state of 'FAILED' then this node is also a 'FAILED' node.\n if (child.getState() === State.FAILED) {\n hasChildFailed = true;\n\n // There is no need to check the rest of the children.\n break;\n }\n\n // The node should be in the 'RUNNING' state.\n if (child.getState() !== State.RUNNING) {\n // The child node was not in an expected state.\n throw new Error(\"child node was not in an expected state.\");\n }\n }\n\n if (hasChildFailed) {\n // This node is a 'FAILED' node.\n this.setState(State.FAILED);\n\n // Abort every running child.\n for (const child of this.children) {\n if (child.getState() === State.RUNNING) {\n child.abort(agent);\n }\n }\n } else {\n // If all children have succeeded then this node has also succeeded, otherwise it is still running.\n this.setState(succeededCount === this.children.length ? State.SUCCEEDED : State.RUNNING);\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => \"PARALLEL\";\n}\n", "import Composite from \"./Composite\";\nimport Node from \"../Node\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A SELECTOR node.\n * The child nodes are executed in sequence until one succeeds or all fail.\n */\nexport default class Selector extends Composite {\n /**\n * @param attributes The node attributes.\n * @param children The child nodes.\n */\n constructor(attributes: Attribute[], protected children: Node[]) {\n super(\"selector\", attributes, children);\n }\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // Iterate over all of the children of this node.\n for (const child of this.children) {\n // If the child has never been updated or is running then we will need to update it now.\n if (child.getState() === State.READY || child.getState() === State.RUNNING) {\n // Update the child of this node.\n child.update(agent, options);\n }\n\n // If the current child has a state of 'SUCCEEDED' then this node is also a 'SUCCEEDED' node.\n if (child.getState() === State.SUCCEEDED) {\n // This node is a 'SUCCEEDED' node.\n this.setState(State.SUCCEEDED);\n\n // There is no need to check the rest of the selector nodes.\n return;\n }\n\n // If the current child has a state of 'FAILED' then we should move on to the next child.\n if (child.getState() === State.FAILED) {\n // Find out if the current child is the last one in the selector.\n // If it is then this sequence node has also failed.\n if (this.children.indexOf(child) === this.children.length - 1) {\n // This node is a 'FAILED' node.\n this.setState(State.FAILED);\n\n // There is no need to check the rest of the selector as we have completed it.\n return;\n } else {\n // The child node failed, try the next one.\n continue;\n }\n }\n\n // The node should be in the 'RUNNING' state.\n if (child.getState() === State.RUNNING) {\n // This node is a 'RUNNING' node.\n this.setState(State.RUNNING);\n\n // There is no need to check the rest of the selector as the current child is still running.\n return;\n }\n\n // The child node was not in an expected state.\n throw new Error(\"child node was not in an expected state.\");\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => \"SELECTOR\";\n}\n", "import Composite from \"./Composite\";\nimport Node from \"../Node\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A SEQUENCE node.\n * The child nodes are executed in sequence until one fails or all succeed.\n */\nexport default class Sequence extends Composite {\n /**\n * @param attributes The node attributes.\n * @param children The child nodes.\n */\n constructor(attributes: Attribute[], protected children: Node[]) {\n super(\"sequence\", attributes, children);\n }\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // Iterate over all of the children of this node.\n for (const child of this.children) {\n // If the child has never been updated or is running then we will need to update it now.\n if (child.getState() === State.READY || child.getState() === State.RUNNING) {\n // Update the child of this node.\n child.update(agent, options);\n }\n\n // If the current child has a state of 'SUCCEEDED' then we should move on to the next child.\n if (child.getState() === State.SUCCEEDED) {\n // Find out if the current child is the last one in the sequence.\n // If it is then this sequence node has also succeeded.\n if (this.children.indexOf(child) === this.children.length - 1) {\n // This node is a 'SUCCEEDED' node.\n this.setState(State.SUCCEEDED);\n\n // There is no need to check the rest of the sequence as we have completed it.\n return;\n } else {\n // The child node succeeded, but we have not finished the sequence yet.\n continue;\n }\n }\n\n // If the current child has a state of 'FAILED' then this node is also a 'FAILED' node.\n if (child.getState() === State.FAILED) {\n // This node is a 'FAILED' node.\n this.setState(State.FAILED);\n\n // There is no need to check the rest of the sequence.\n return;\n }\n\n // The node should be in the 'RUNNING' state.\n if (child.getState() === State.RUNNING) {\n // This node is a 'RUNNING' node.\n this.setState(State.RUNNING);\n\n // There is no need to check the rest of the sequence as the current child is still running.\n return;\n }\n\n // The child node was not in an expected state.\n throw new Error(\"child node was not in an expected state.\");\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => \"SEQUENCE\";\n}\n", "import createLotto from \"lotto-draw\";\n\nimport Node from \"../Node\";\nimport Composite from \"./Composite\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A LOTTO node.\n * A winning child is picked on the initial update of this node, based on ticket weighting.\n * The state of this node will match the state of the winning child.\n */\nexport default class Lotto extends Composite {\n /**\n * @param attributes The node attributes.\n * @param weights The child node weights.\n * @param children The child nodes.\n */\n constructor(attributes: Attribute[], private weights: number[] | undefined, children: Node[]) {\n super(\"lotto\", attributes, children);\n }\n\n /**\n * The child node selected to be the active one.\n */\n private selectedChild: Node | undefined;\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // If this node is in the READY state then we need to pick a winning child node.\n if (this.is(State.READY)) {\n // Create a lotto draw with which to randomly pick a child node to become the active one.\n const lottoDraw = createLotto({\n // Hook up the optional 'random' behaviour tree function option to the one used by 'lotto-draw'.\n random: options.random,\n // Pass in each child node as a participant in the lotto draw with their respective ticket count.\n participants: this.children.map((child, index) => [child, this.weights?.[index] || 1])\n });\n\n // Randomly pick a child based on ticket weighting, this will become the active child for this composite node.\n this.selectedChild = lottoDraw.draw() || undefined;\n }\n\n // If something went wrong and we don't have an active child then we should throw an error.\n if (!this.selectedChild) {\n throw new Error(\"failed to update lotto node as it has no active child\");\n }\n\n // If the selected child has never been updated or is running then we will need to update it now.\n if (this.selectedChild.getState() === State.READY || this.selectedChild.getState() === State.RUNNING) {\n this.selectedChild.update(agent, options);\n }\n\n // The state of the lotto node is the state of its selected child.\n this.setState(this.selectedChild.getState());\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => (this.weights ? `LOTTO [${this.weights.join(\",\")}]` : \"LOTTO\");\n}\n", "import Node from \"../Node\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\n\n/**\n * A decorator node that wraps a single child node.\n */\nexport default abstract class Decorator extends Node {\n /**\n * @param type The node type.\n * @param attributes The node attributes.\n * @param child The child node.\n */\n constructor(type: string, attributes: Attribute[], protected child: Node) {\n super(type, attributes, []);\n }\n\n /**\n * Gets whether this node is a leaf node.\n */\n isLeafNode = () => false;\n\n /**\n * Gets the children of this node.\n */\n getChildren = () => [this.child];\n\n /**\n * Reset the state of the node.\n */\n reset = () => {\n // Reset the state of this node.\n this.setState(State.READY);\n\n // Reset the state of the child node.\n this.child.reset();\n };\n\n /**\n * Abort the running of this node.\n * @param agent The agent.\n */\n abort = (agent: Agent) => {\n // There is nothing to do if this node is not in the running state.\n if (!this.is(State.RUNNING)) {\n return;\n }\n\n // Abort the child node.\n this.child.abort(agent);\n\n // Reset the state of this node.\n this.reset();\n\n this.getAttribute(\"exit\")?.callAgentFunction(agent, false, true);\n };\n}\n", "import Node from \"../Node\";\nimport Decorator from \"./Decorator\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A Fail node.\n * This node wraps a single child and will always move to the 'FAILED' state when the child moves to a 'SUCCEEDED' or 'FAILED' state.\n */\nexport default class Fail extends Decorator {\n /**\n * @param attributes The node attributes.\n * @param child The child node.\n */\n constructor(attributes: Attribute[], child: Node) {\n super(\"fail\", attributes, child);\n }\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // If the child has never been updated or is running then we will need to update it now.\n if (this.child.getState() === State.READY || this.child.getState() === State.RUNNING) {\n this.child.update(agent, options);\n }\n\n // The state of this node will depend in the state of its child.\n switch (this.child.getState()) {\n case State.RUNNING:\n this.setState(State.RUNNING);\n break;\n\n case State.SUCCEEDED:\n case State.FAILED:\n this.setState(State.FAILED);\n break;\n\n default:\n this.setState(State.READY);\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => \"FAIL\";\n}\n", "import Decorator from \"./Decorator\";\nimport State from \"../../State\";\nimport Node from \"../Node\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A Flip node.\n * This node wraps a single child and will flip the state of the child state.\n */\nexport default class Flip extends Decorator {\n /**\n * @param attributes The node attributes.\n * @param child The child node.\n */\n constructor(attributes: Attribute[], child: Node) {\n super(\"flip\", attributes, child);\n }\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // If the child has never been updated or is running then we will need to update it now.\n if (this.child.getState() === State.READY || this.child.getState() === State.RUNNING) {\n this.child.update(agent, options);\n }\n\n // The state of this node will depend in the state of its child.\n switch (this.child.getState()) {\n case State.RUNNING:\n this.setState(State.RUNNING);\n break;\n\n case State.SUCCEEDED:\n this.setState(State.FAILED);\n break;\n\n case State.FAILED:\n this.setState(State.SUCCEEDED);\n break;\n\n default:\n this.setState(State.READY);\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => \"FLIP\";\n}\n", "import Node from \"../Node\";\nimport Decorator from \"./Decorator\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A REPEAT node.\n * The node has a single child which can have:\n * -- A number of iterations for which to repeat the child node.\n * -- An infinite repeat loop if neither an iteration count or a condition function is defined.\n * The REPEAT node will stop and have a 'FAILED' state if its child is ever in a 'FAILED' state after an update.\n * The REPEAT node will attempt to move on to the next iteration if its child is ever in a 'SUCCEEDED' state.\n */\nexport default class Repeat extends Decorator {\n /**\n * @param attributes The node attributes.\n * @param iterations The number of iterations to repeat the child node.\n * @param iterationsMin The minimum possible number of iterations to repeat the child node.\n * @param iterationsMax The maximum possible number of iterations to repeat the child node.\n * @param child The child node.\n */\n constructor(\n attributes: Attribute[],\n private iterations: number | null,\n private iterationsMin: number | null,\n private iterationsMax: number | null,\n child: Node\n ) {\n super(\"repeat\", attributes, child);\n }\n\n /**\n * The number of target iterations to make.\n */\n private targetIterationCount: number | null = null;\n\n /**\n * The current iteration count.\n */\n private currentIterationCount: number = 0;\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // If this node is in the READY state then we need to reset the child and the target iteration count.\n if (this.is(State.READY)) {\n // Reset the child node.\n this.child.reset();\n\n // Reset the current iteration count.\n this.currentIterationCount = 0;\n\n // Set the target iteration count.\n this.setTargetIterationCount(options);\n }\n\n // Do a check to see if we can iterate. If we can then this node will move into the 'RUNNING' state.\n // If we cannot iterate then we have hit our target iteration count, which means that the node has succeeded.\n if (this.canIterate()) {\n // This node is in the running state and can do its initial iteration.\n this.setState(State.RUNNING);\n\n // We may have already completed an iteration, meaning that the child node will be in the SUCCEEDED state.\n // If this is the case then we will have to reset the child node now.\n if (this.child.getState() === State.SUCCEEDED) {\n this.child.reset();\n }\n\n // Update the child of this node.\n this.child.update(agent, options);\n\n // If the child moved into the FAILED state when we updated it then there is nothing left to do and this node has also failed.\n // If it has moved into the SUCCEEDED state then we have completed the current iteration.\n if (this.child.getState() === State.FAILED) {\n // The child has failed, meaning that this node has failed.\n this.setState(State.FAILED);\n\n return;\n } else if (this.child.getState() === State.SUCCEEDED) {\n // We have completed an iteration.\n this.currentIterationCount += 1;\n }\n } else {\n // This node is in the 'SUCCEEDED' state as we cannot iterate any more.\n this.setState(State.SUCCEEDED);\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => {\n if (this.iterations !== null) {\n return `REPEAT ${this.iterations}x`;\n } else if (this.iterationsMin !== null && this.iterationsMax !== null) {\n return `REPEAT ${this.iterationsMin}x-${this.iterationsMax}x`;\n } else {\n return \"REPEAT\";\n }\n };\n\n /**\n * Reset the state of the node.\n */\n reset = () => {\n // Reset the state of this node.\n this.setState(State.READY);\n\n // Reset the current iteration count.\n this.currentIterationCount = 0;\n\n // Reset the child node.\n this.child.reset();\n };\n\n /**\n * Gets whether an iteration can be made.\n * @returns Whether an iteration can be made.\n */\n private canIterate = () => {\n if (this.targetIterationCount !== null) {\n // We can iterate as long as we have not reached our target iteration count.\n return this.currentIterationCount < this.targetIterationCount;\n }\n\n // If neither an iteration count or a condition function were defined then we can iterate indefinitely.\n return true;\n };\n\n /**\n * Sets the target iteration count.\n * @param options The behaviour tree options object.\n */\n private setTargetIterationCount = (options: BehaviourTreeOptions) => {\n // Are we dealing with an explicit iteration count or will we be randomly picking a iteration count between the min and max iteration count.\n if (this.iterations !== null) {\n this.targetIterationCount = this.iterations;\n } else if (this.iterationsMin !== null && this.iterationsMax !== null) {\n // We will be picking a random iteration count between a min and max iteration count, if the optional 'random'\n // behaviour tree function option is defined then we will be using that, otherwise we will fall back to using Math.random.\n const random = typeof options.random === \"function\" ? options.random : Math.random;\n\n // Pick a random iteration count between a min and max iteration count.\n this.targetIterationCount = Math.floor(\n random() * (this.iterationsMax - this.iterationsMin + 1) + this.iterationsMin\n );\n } else {\n this.targetIterationCount = null;\n }\n };\n}\n", "import Node from \"../Node\";\nimport Decorator from \"./Decorator\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A RETRY node.\n * The node has a single child which can have:\n * -- A number of iterations for which to repeat the child node.\n * -- An infinite repeat loop if neither an iteration count or a condition function is defined.\n * The RETRY node will stop and have a 'SUCCEEDED' state if its child is ever in a 'SUCCEEDED' state after an update.\n * The RETRY node will attempt to move on to the next iteration if its child is ever in a 'FAILED' state.\n */\nexport default class Retry extends Decorator {\n /**\n * @param attributes The node attributes.\n * @param attempts The number of attempts to retry the child node.\n * @param attemptsMin The minimum possible number of attempts to retry the child node.\n * @param attemptsMax The maximum possible number of attempts to retry the child node.\n * @param child The child node.\n */\n constructor(\n attributes: Attribute[],\n private attempts: number | null,\n private attemptsMin: number | null,\n private attemptsMax: number | null,\n child: Node\n ) {\n super(\"retry\", attributes, child);\n }\n\n /**\n * The number of target attempts to make.\n */\n private targetAttemptCount: number | null = null;\n\n /**\n * The current attempt count.\n */\n private currentAttemptCount: number = 0;\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // If this node is in the READY state then we need to reset the child and the target attempt count.\n if (this.is(State.READY)) {\n // Reset the child node.\n this.child.reset();\n\n // Reset the current attempt count.\n this.currentAttemptCount = 0;\n\n // Set the target attempt count.\n this.setTargetAttemptCount(options);\n }\n\n // Do a check to see if we can attempt. If we can then this node will move into the 'RUNNING' state.\n // If we cannot attempt then we have hit our target attempt count, which means that the node has succeeded.\n if (this.canAttempt()) {\n // This node is in the running state and can do its initial attempt.\n this.setState(State.RUNNING);\n\n // We may have already completed an attempt, meaning that the child node will be in the FAILED state.\n // If this is the case then we will have to reset the child node now.\n if (this.child.getState() === State.FAILED) {\n this.child.reset();\n }\n\n // Update the child of this node.\n this.child.update(agent, options);\n\n // If the child moved into the SUCCEEDED state when we updated it then there is nothing left to do and this node has also succeeded.\n // If it has moved into the FAILED state then we have completed the current attempt.\n if (this.child.getState() === State.SUCCEEDED) {\n // The child has succeeded, meaning that this node has succeeded.\n this.setState(State.SUCCEEDED);\n\n return;\n } else if (this.child.getState() === State.FAILED) {\n // We have completed an attempt.\n this.currentAttemptCount += 1;\n }\n } else {\n // This node is in the 'FAILED' state as we cannot iterate any more.\n this.setState(State.FAILED);\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => {\n if (this.attempts !== null) {\n return `RETRY ${this.attempts}x`;\n } else if (this.attemptsMin !== null && this.attemptsMax !== null) {\n return `RETRY ${this.attemptsMin}x-${this.attemptsMax}x`;\n } else {\n return \"RETRY\";\n }\n };\n\n /**\n * Reset the state of the node.\n */\n reset = () => {\n // Reset the state of this node.\n this.setState(State.READY);\n\n // Reset the current attempt count.\n this.currentAttemptCount = 0;\n\n // Reset the child node.\n this.child.reset();\n };\n\n /**\n * Gets whether an attempt can be made.\n * @returns Whether an attempt can be made.\n */\n canAttempt = () => {\n if (this.targetAttemptCount !== null) {\n // We can attempt as long as we have not reached our target attempt count.\n return this.currentAttemptCount < this.targetAttemptCount;\n }\n\n // If neither an attempt count or a condition function were defined then we can attempt indefinitely.\n return true;\n };\n\n /**\n * Sets the target attempt count.\n * @param options The behaviour tree options object.\n */\n setTargetAttemptCount = (options: BehaviourTreeOptions) => {\n // Are we dealing with an explicit attempt count or will we be randomly picking an attempt count between the min and max attempt count.\n if (this.attempts !== null) {\n this.targetAttemptCount = this.attempts;\n } else if (this.attemptsMin !== null && this.attemptsMax !== null) {\n // We will be picking a random attempt count between a min and max attempt count, if the optional 'random'\n // behaviour tree function option is defined then we will be using that, otherwise we will fall back to using Math.random.\n const random = typeof options.random === \"function\" ? options.random : Math.random;\n\n // Pick a random attempt count between a min and max attempt count.\n this.targetAttemptCount = Math.floor(\n random() * (this.attemptsMax - this.attemptsMin + 1) + this.attemptsMin\n );\n } else {\n this.targetAttemptCount = null;\n }\n };\n}\n", "import Node from \"../Node\";\nimport Decorator from \"./Decorator\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A Root node.\n * The root node will have a single child.\n */\nexport default class Root extends Decorator {\n /**\n * @param attributes The node attributes.\n * @param child The child node.\n */\n constructor(attributes: Attribute[], child: Node) {\n super(\"root\", attributes, child);\n }\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // If the child has never been updated or is running then we will need to update it now.\n if (this.child.getState() === State.READY || this.child.getState() === State.RUNNING) {\n // Update the child of this node.\n this.child.update(agent, options);\n }\n\n // The state of the root node is the state of its child.\n this.setState(this.child.getState());\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => \"ROOT\";\n}\n", "import Node from \"../Node\";\nimport Decorator from \"./Decorator\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A Succeed node.\n * This node wraps a single child and will always move to the 'SUCCEEDED' state when the child moves to a 'SUCCEEDED' or 'FAILED' state.\n */\nexport default class Succeed extends Decorator {\n /**\n * @param attributes The node attributes.\n * @param child The child node.\n */\n constructor(attributes: Attribute[], child: Node) {\n super(\"succeed\", attributes, child);\n }\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // If the child has never been updated or is running then we will need to update it now.\n if (this.child.getState() === State.READY || this.child.getState() === State.RUNNING) {\n this.child.update(agent, options);\n }\n\n // The state of this node will depend in the state of its child.\n switch (this.child.getState()) {\n case State.RUNNING:\n this.setState(State.RUNNING);\n break;\n\n case State.SUCCEEDED:\n case State.FAILED:\n this.setState(State.SUCCEEDED);\n break;\n\n default:\n this.setState(State.READY);\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => \"SUCCEED\";\n}\n", "import Node from \"../Node\";\n\n/**\n * A leaf node.\n */\nexport default abstract class Leaf extends Node {\n /**\n * Gets whether this node is a leaf node.\n */\n isLeafNode = () => true;\n}\n", "import { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\nimport State, { CompleteState } from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Leaf from \"./Leaf\";\nimport Lookup from \"../../Lookup\";\nimport Attribute from \"../../attributes/Attribute\";\n\n/**\n * An Action leaf node.\n * This represents an immediate or ongoing state of behaviour.\n */\nexport default class Action extends Leaf {\n /**\n * @param attributes The node attributes.\n * @param actionName The action name.\n * @param actionArguments The array of action argument definitions.\n */\n constructor(attributes: Attribute[], private actionName: string, private actionArguments: any[]) {\n super(\"action\", attributes, actionArguments);\n }\n\n /**\n * Whether there is a pending update promise.\n */\n private isUsingUpdatePromise = false;\n\n /**\n * The finished state result of an update promise.\n */\n private updatePromiseStateResult: CompleteState | null = null;\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // If the result of this action depends on an update promise then there is nothing to do until\n // it resolves, unless there has been a value set as a result of the update promise resolving.\n if (this.isUsingUpdatePromise) {\n // Check whether the update promise has resolved with a state value.\n if (this.updatePromiseStateResult) {\n // Set the state of this node to match the state returned by the promise.\n this.setState(this.updatePromiseStateResult);\n }\n\n return;\n }\n\n // Attempt to get the invoker for the action function.\n const actionFuncInvoker = Lookup.getFuncInvoker(agent, this.actionName);\n\n // The action function should be defined.\n if (actionFuncInvoker === null) {\n throw new Error(\n `cannot update action node as the action '${this.actionName}' function is not defined on the agent and has not been registered`\n );\n }\n\n // Call the action function, the result of which may be:\n // - The finished state of this action node.\n // - A promise to return a finished node state.\n // - Undefined if the node should remain in the running state.\n const updateResult = actionFuncInvoker(this.actionArguments) as CompleteState | Promise;\n\n if (updateResult instanceof Promise) {\n updateResult.then(\n (result) => {\n // If 'isUpdatePromisePending' is null then the promise was cleared as it was resolving, probably via an abort of reset.\n if (!this.isUsingUpdatePromise) {\n return;\n }\n\n // Check to make sure the result is a valid finished state.\n if (result !== State.SUCCEEDED && result !== State.FAILED) {\n throw new Error(\n \"action node promise resolved with an invalid value, expected a State.SUCCEEDED or State.FAILED value to be returned\"\n );\n }\n\n // Set pending update promise state result to be processed on next update.\n this.updatePromiseStateResult = result;\n },\n (reason) => {\n // If 'isUpdatePromisePending' is null then the promise was cleared as it was resolving, probably via an abort of reset.\n if (!this.isUsingUpdatePromise) {\n return;\n }\n\n // Just throw whatever was returned as the rejection argument.\n throw new Error(reason);\n }\n );\n\n // This node will be in the 'RUNNING' state until the update promise resolves.\n this.setState(State.RUNNING);\n\n // We are now waiting for the promise returned by the use to resolve before we know what state this node is in.\n this.isUsingUpdatePromise = true;\n } else {\n // Validate the returned value.\n this.validateUpdateResult(updateResult);\n\n // Set the state of this node, this may be undefined, which just means that the node is still in the 'RUNNING' state.\n this.setState(updateResult || State.RUNNING);\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => this.actionName;\n\n /**\n * Reset the state of the node.\n */\n reset = () => {\n // Reset the state of this node.\n this.setState(State.READY);\n\n // There is no longer an update promise that we care about.\n this.isUsingUpdatePromise = false;\n this.updatePromiseStateResult = null;\n };\n\n /**\n * Validate the result of an update function call.\n * @param result The result of an update function call.\n */\n private validateUpdateResult = (result: CompleteState | boolean) => {\n switch (result) {\n case State.SUCCEEDED:\n case State.FAILED:\n case undefined:\n return;\n default:\n throw new Error(\n `action '${this.actionName}' 'onUpdate' returned an invalid response, expected an optional State.SUCCEEDED or State.FAILED value to be returned`\n );\n }\n };\n}\n", "import { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Leaf from \"./Leaf\";\nimport Lookup from \"../../Lookup\";\nimport Attribute from \"../../attributes/Attribute\";\n\n/**\n * A Condition leaf node.\n * This will succeed or fail immediately based on an agent predicate, without moving to the 'RUNNING' state.\n */\nexport default class Condition extends Leaf {\n /**\n * @param attributes The node attributes.\n * @param conditionName The name of the condition function.\n * @param conditionArguments The array of condition argument definitions.\n */\n constructor(attributes: Attribute[], private conditionName: string, private conditionArguments: any[]) {\n super(\"condition\", attributes, conditionArguments);\n }\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // Attempt to get the invoker for the condition function.\n const conditionFuncInvoker = Lookup.getFuncInvoker(agent, this.conditionName);\n\n // The condition function should be defined.\n if (conditionFuncInvoker === null) {\n throw new Error(\n `cannot update condition node as the condition '${this.conditionName}' function is not defined on the agent and has not been registered`\n );\n }\n\n // Call the condition function to determine the state of this node.\n this.setState(!!conditionFuncInvoker(this.conditionArguments) ? State.SUCCEEDED : State.FAILED);\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => this.conditionName;\n}\n", "import Leaf from \"./Leaf\";\nimport State from \"../../State\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { Agent } from \"../../Agent\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A WAIT node.\n * The state of this node will change to SUCCEEDED after a duration of time\n */\nexport default class Wait extends Leaf {\n /**\n * @param attributes The node attributes.\n * @param duration The duration that this node will wait to succeed in milliseconds.\n * @param durationMin The minimum possible duration in milliseconds that this node will wait to succeed.\n * @param durationMax The maximum possible duration in milliseconds that this node will wait to succeed.\n */\n constructor(\n attributes: Attribute[],\n private duration: number | null,\n private durationMin: number | null,\n private durationMax: number | null\n ) {\n super(\"wait\", attributes, []);\n }\n\n /**\n * The time in milliseconds at which this node was first updated.\n */\n private initialUpdateTime: number = 0;\n\n /**\n * The total duration in milliseconds that this node will be waiting for.\n */\n private totalDuration: number | null = null;\n\n /**\n * The duration in milliseconds that this node has been waiting for.\n */\n private waitedDuration: number = 0;\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // If this node is in the READY state then we need to set the initial update time.\n if (this.is(State.READY)) {\n // Set the initial update time.\n this.initialUpdateTime = new Date().getTime();\n\n // Set the initial waited duration.\n this.waitedDuration = 0;\n\n // Are we dealing with an explicit duration or will we be randomly picking a duration between the min and max duration.\n if (this.duration !== null) {\n this.totalDuration = this.duration;\n } else if (this.durationMin !== null && this.durationMax !== null) {\n // We will be picking a random duration between a min and max duration, if the optional 'random' behaviour tree\n // function option is defined then we will be using that, otherwise we will fall back to using Math.random.\n const random = typeof options.random === \"function\" ? options.random : Math.random;\n\n // Pick a random duration between a min and max duration.\n this.totalDuration = Math.floor(\n random() * (this.durationMax - this.durationMin + 1) + this.durationMin\n );\n } else {\n this.totalDuration = null;\n }\n\n // The node is now running until we finish waiting.\n this.setState(State.RUNNING);\n }\n\n // If we have no total duration then this wait node will wait indefinitely until it is aborted.\n if (this.totalDuration === null) {\n return;\n }\n\n // If we have a 'getDeltaTime' function defined as part of our options then we will use it to figure out how long we have waited for.\n if (typeof options.getDeltaTime === \"function\") {\n // Get the delta time.\n const deltaTime = options.getDeltaTime();\n\n // Our delta time must be a valid number and cannot be NaN.\n if (typeof deltaTime !== \"number\" || isNaN(deltaTime)) {\n throw new Error(\"The delta time must be a valid number and not NaN.\");\n }\n\n // Update the amount of time that this node has been waiting for based on the delta time.\n this.waitedDuration += deltaTime * 1000;\n } else {\n // We are not using a delta time, so we will just work out hom much time has passed since the first update.\n this.waitedDuration = new Date().getTime() - this.initialUpdateTime;\n }\n\n // Have we waited long enough?\n if (this.waitedDuration >= this.totalDuration) {\n // We have finished waiting!\n this.setState(State.SUCCEEDED);\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => {\n if (this.duration !== null) {\n return `WAIT ${this.duration}ms`;\n } else if (this.durationMin !== null && this.durationMax !== null) {\n return `WAIT ${this.durationMin}ms-${this.durationMax}ms`;\n } else {\n return \"WAIT\";\n }\n };\n}\n", "import Guard from \"./guards/Guard\";\n\nexport type AttributeDetails = {\n /** The attribute type. */\n type: string;\n\n /** The attribute arguments. */\n args: any[];\n};\n\n/**\n * A base node attribute.\n */\nexport default abstract class Attribute {\n /**\n * @param type The node attribute type.\n * @param args The array of attribute arguments.\n */\n constructor(public type: string, public args: any[]) {}\n\n /**\n * Gets the attribute details.\n */\n abstract getDetails(): TAttributeDetails;\n\n /**\n * Gets whether this attribute is a guard.\n */\n abstract isGuard: () => this is Guard;\n}\n", "import { Agent } from \"../../Agent\";\nimport Attribute, { AttributeDetails } from \"../Attribute\";\n\nexport type GuardAttributeDetails = {\n /** The name of the condition function that determines whether the guard is satisfied. */\n condition: string;\n} & AttributeDetails;\n\n/**\n * A base node guard attribute.\n */\nexport default abstract class Guard extends Attribute {\n /**\n * @param type The node attribute type.\n * @param args The array of decorator argument definitions.\n * @param condition The name of the condition function that determines whether the guard is satisfied.\n */\n constructor(type: string, args: any[], private condition: string) {\n super(type, args);\n }\n\n /**\n * Gets the name of the condition function that determines whether the guard is satisfied.\n */\n getCondition = () => this.condition;\n\n /**\n * Gets whether this attribute is a guard.\n */\n isGuard = () => true;\n\n /**\n * Gets the attribute details.\n */\n getDetails(): GuardAttributeDetails {\n return {\n type: this.type,\n args: this.args,\n condition: this.getCondition()\n };\n }\n\n /**\n * Gets whether the guard is satisfied.\n * @param agent The agent.\n * @returns Whether the guard is satisfied.\n */\n abstract isSatisfied(agent: Agent): boolean;\n}\n", "import Guard from \"./Guard\";\nimport Lookup from \"../../Lookup\";\nimport { Agent } from \"../../Agent\";\n\n/**\n * A WHILE guard which is satisfied as long as the given condition remains true.\n */\nexport default class While extends Guard {\n /**\n * @param condition The name of the condition function that determines whether the guard is satisfied.\n * @param args The array of decorator argument definitions.\n */\n constructor(condition: string, args: any[]) {\n super(\"while\", args, condition);\n }\n\n /**\n * Gets whether the guard is satisfied.\n * @param agent The agent.\n * @returns Whether the guard is satisfied.\n */\n isSatisfied = (agent: Agent) => {\n // Attempt to get the invoker for the condition function.\n const conditionFuncInvoker = Lookup.getFuncInvoker(agent, this.getCondition());\n\n // The condition function should be defined.\n if (conditionFuncInvoker === null) {\n throw new Error(\n `cannot evaluate node guard as the condition '${this.getCondition()}' function is not defined on the agent and has not been registered`\n );\n }\n\n // Call the condition function to determine whether this guard is satisfied.\n return !!conditionFuncInvoker(this.args);\n };\n}\n", "import Guard from \"./Guard\";\nimport Lookup from \"../../Lookup\";\nimport { Agent } from \"../../Agent\";\n\n/**\n * An UNTIL guard which is satisfied as long as the given condition remains false.\n */\nexport default class Until extends Guard {\n /**\n * @param condition The name of the condition function that determines whether the guard is satisfied.\n * @param args The array of decorator argument definitions.\n */\n constructor(condition: string, args: any[]) {\n super(\"until\", args, condition);\n }\n\n /**\n * Gets whether the guard is satisfied.\n * @param agent The agent.\n * @returns Whether the guard is satisfied.\n */\n isSatisfied = (agent: Agent) => {\n // Attempt to get the invoker for the condition function.\n const conditionFuncInvoker = Lookup.getFuncInvoker(agent, this.getCondition());\n\n // The condition function should be defined.\n if (conditionFuncInvoker === null) {\n throw new Error(\n `cannot evaluate node guard as the condition '${this.getCondition()}' function is not defined on the agent and has not been registered`\n );\n }\n\n // Call the condition function to determine whether this guard is satisfied.\n return !!!conditionFuncInvoker(this.args);\n };\n}\n", "import { Agent } from \"../../Agent\";\nimport Attribute, { AttributeDetails } from \"../Attribute\";\n\nexport type CallbackAttributeDetails = {\n /** The name of the agent function that is called. */\n functionName: string;\n} & AttributeDetails;\n\n/**\n * A base node callback attribute.\n */\nexport default abstract class Callback extends Attribute {\n /**\n * @param type The node attribute type.\n * @param args The array of decorator argument definitions.\n * @param functionName The name of the agent function to call.\n */\n constructor(type: string, args: any[], private functionName: string) {\n super(type, args);\n }\n\n /**\n * Gets the name of the agent function to call.\n */\n getFunctionName = () => this.functionName;\n\n /**\n * Gets whether this attribute is a guard.\n */\n isGuard = () => false;\n\n /**\n * Gets the attribute details.\n */\n getDetails(): CallbackAttributeDetails {\n return {\n type: this.type,\n args: this.args,\n functionName: this.getFunctionName()\n };\n }\n\n /**\n * Attempt to call the agent function that this callback refers to.\n * @param agent The agent.\n */\n abstract callAgentFunction: (agent: Agent, isSuccess: boolean, isAborted: boolean) => void;\n}\n", "import Callback from \"./Callback\";\nimport Lookup from \"../../Lookup\";\nimport { Agent } from \"../../Agent\";\n\n/**\n * An ENTRY callback which defines an agent function to call when the associated node is updated and moves out of running state.\n */\nexport default class Entry extends Callback {\n /**\n * @param functionName The name of the agent function to call.\n * @param args The array of callback argument definitions.\n */\n constructor(functionName: string, args: any[]) {\n super(\"entry\", args, functionName);\n }\n\n /**\n * Attempt to call the agent function that this callback refers to.\n * @param agent The agent.\n */\n callAgentFunction = (agent: Agent) => {\n // Attempt to get the invoker for the callback function.\n const callbackFuncInvoker = Lookup.getFuncInvoker(agent, this.getFunctionName());\n\n // The callback function should be defined.\n if (callbackFuncInvoker === null) {\n throw new Error(\n `cannot call entry function '${this.getFunctionName()}' as is not defined on the agent and has not been registered`\n );\n }\n\n // Call the callback function.\n callbackFuncInvoker(this.args);\n };\n}\n", "import Callback from \"./Callback\";\nimport Lookup from \"../../Lookup\";\nimport { Agent } from \"../../Agent\";\n\n/**\n * A STEP callback which defines an agent function to call when the associated node is updated.\n */\nexport default class Step extends Callback {\n /**\n * @param functionName The name of the agent function to call.\n * @param args The array of callback argument definitions.\n */\n constructor(functionName: string, args: any[]) {\n super(\"step\", args, functionName);\n }\n\n /**\n * Attempt to call the agent function that this callback refers to.\n * @param agent The agent.\n */\n callAgentFunction = (agent: Agent) => {\n // Attempt to get the invoker for the callback function.\n const callbackFuncInvoker = Lookup.getFuncInvoker(agent, this.getFunctionName());\n\n // The callback function should be defined.\n if (callbackFuncInvoker === null) {\n throw new Error(\n `cannot call step function '${this.getFunctionName()}' as is not defined on the agent and has not been registered`\n );\n }\n\n // Call the callback function.\n callbackFuncInvoker(this.args);\n };\n}\n", "import Callback from \"./Callback\";\nimport Lookup from \"../../Lookup\";\nimport { Agent } from \"../../Agent\";\n\n/**\n * An EXIT callback which defines an agent function to call when the associated node is updated and moves to a finished state or is aborted.\n */\nexport default class Exit extends Callback {\n /**\n * @param functionName The name of the agent function to call.\n * @param args The array of callback argument definitions.\n */\n constructor(functionName: string, args: any[]) {\n super(\"exit\", args, functionName);\n }\n\n /**\n * Attempt to call the agent function that this callback refers to.\n * @param agent The agent.\n * @param isSuccess Whether the decorated node was left with a success state.\n * @param isAborted Whether the decorated node was aborted.\n */\n callAgentFunction = (agent: Agent, isSuccess: boolean, isAborted: boolean) => {\n // Attempt to get the invoker for the callback function.\n const callbackFuncInvoker = Lookup.getFuncInvoker(agent, this.getFunctionName());\n\n // The callback function should be defined.\n if (callbackFuncInvoker === null) {\n throw new Error(\n `cannot call exit function '${this.getFunctionName()}' as is not defined on the agent and has not been registered`\n );\n }\n\n // Call the callback function\n callbackFuncInvoker([{ value: { succeeded: isSuccess, aborted: isAborted } }, ...this.args]);\n };\n}\n", "import { AnyNodeDefinition, RootNodeDefinition } from \"./BehaviourTreeDefinition\";\nimport GuardPath, { GuardPathPart } from \"./attributes/guards/GuardPath\";\nimport { validateBranchSubtreeLinks } from \"./BehaviourTreeDefinitionValidator\";\nimport { isInteger } from \"./BehaviourTreeDefinitionUtilities\";\nimport Node from \"./nodes/Node\";\nimport Composite from \"./nodes/composite/Composite\";\nimport Decorator from \"./nodes/decorator/Decorator\";\nimport Parallel from \"./nodes/composite/Parallel\";\nimport Selector from \"./nodes/composite/Selector\";\nimport Sequence from \"./nodes/composite/Sequence\";\nimport Lotto from \"./nodes/composite/Lotto\";\nimport Fail from \"./nodes/decorator/Fail\";\nimport Flip from \"./nodes/decorator/Flip\";\nimport Repeat from \"./nodes/decorator/Repeat\";\nimport Retry from \"./nodes/decorator/Retry\";\nimport Root from \"./nodes/decorator/Root\";\nimport Succeed from \"./nodes/decorator/Succeed\";\nimport Action from \"./nodes/leaf/Action\";\nimport Condition from \"./nodes/leaf/Condition\";\nimport Wait from \"./nodes/leaf/Wait\";\nimport Lookup from \"./Lookup\";\nimport Attribute from \"./attributes/Attribute\";\nimport While from \"./attributes/guards/While\";\nimport Until from \"./attributes/guards/Until\";\nimport Entry from \"./attributes/callbacks/Entry\";\nimport Step from \"./attributes/callbacks/Step\";\nimport Exit from \"./attributes/callbacks/Exit\";\n\n/**\n * A type representing any node instance in a behaviour tree.\n */\ntype AnyNode =\n | Root\n | Action\n | Condition\n | Wait\n | Sequence\n | Selector\n | Lotto\n | Parallel\n | Repeat\n | Retry\n | Flip\n | Succeed\n | Fail;\n\n/**\n * A type defining a mapping of root node identifiers to root node definitions.\n */\ntype RootNodeDefinitionMap = { [key: string | symbol]: RootNodeDefinition };\n\n/**\n * A symbol to use as the main root key in any root node mappings.\n */\nconst MAIN_ROOT_NODE_KEY = Symbol(\"__root__\");\n\n/**\n * Build and populate the root nodes based on the provided definition, assuming that the definition has been validated.\n * @param definition The root node definitions.\n * @returns The built and populated root node definitions.\n */\nexport default function buildRootNode(definition: RootNodeDefinition[]): Root {\n // Create a mapping of root node identifers to root node definitions, including globally registered subtree root node definitions.\n const rootNodeDefinitionMap = createRootNodeDefinitionMap(definition);\n\n // Now that we have all of our root node definitons (those part of the tree definition and those globally\n // registered) we should validate the definition. This will also double-check that we dont have any circular\n // dependencies in our branch -> subtree references and that we have no broken branch -> subtree links.\n validateBranchSubtreeLinks(definition, true);\n\n // Create our populated tree of node instances, starting with our main root node.\n const rootNode = nodeFactory(rootNodeDefinitionMap[MAIN_ROOT_NODE_KEY], rootNodeDefinitionMap) as Root;\n\n // Set a guard path on every leaf of the tree to evaluate as part of each update.\n applyLeafNodeGuardPaths(rootNode);\n\n // We only need to return the main root node.\n return rootNode;\n}\n\n/**\n * A factory function which creates a node instance based on the specified definition.\n * @param definition The node definition.\n * @param rootNodeDefinitionMap The mapping of root node identifers to root node definitions, including globally registered subtree root node definitions.\n * @returns A node instance based on the specified definition.\n */\nfunction nodeFactory(definition: AnyNodeDefinition, rootNodeDefinitionMap: RootNodeDefinitionMap): AnyNode {\n // Get the attributes for the node.\n const attributes = nodeAttributesFactory(definition);\n\n // Create the node instance based on the definition type.\n switch (definition.type) {\n case \"root\":\n return new Root(attributes, nodeFactory(definition.child, rootNodeDefinitionMap));\n\n case \"repeat\":\n let iterations: number | null = null;\n let iterationsMin: number | null = null;\n let iterationsMax: number | null = null;\n\n if (Array.isArray(definition.iterations)) {\n iterationsMin = definition.iterations[0];\n iterationsMax = definition.iterations[1];\n } else if (isInteger(definition.iterations)) {\n iterations = definition.iterations!;\n }\n\n return new Repeat(\n attributes,\n iterations,\n iterationsMin,\n iterationsMax,\n nodeFactory(definition.child, rootNodeDefinitionMap)\n );\n\n case \"retry\":\n let attempts: number | null = null;\n let attemptsMin: number | null = null;\n let attemptsMax: number | null = null;\n\n if (Array.isArray(definition.attempts)) {\n attemptsMin = definition.attempts[0];\n attemptsMax = definition.attempts[1];\n } else if (isInteger(definition.attempts)) {\n attempts = definition.attempts!;\n }\n\n return new Retry(\n attributes,\n attempts,\n attemptsMin,\n attemptsMax,\n nodeFactory(definition.child, rootNodeDefinitionMap)\n );\n\n case \"flip\":\n return new Flip(attributes, nodeFactory(definition.child, rootNodeDefinitionMap));\n\n case \"succeed\":\n return new Succeed(attributes, nodeFactory(definition.child, rootNodeDefinitionMap));\n\n case \"fail\":\n return new Fail(attributes, nodeFactory(definition.child, rootNodeDefinitionMap));\n\n case \"sequence\":\n return new Sequence(\n attributes,\n definition.children.map((child) => nodeFactory(child, rootNodeDefinitionMap))\n );\n\n case \"selector\":\n return new Selector(\n attributes,\n definition.children.map((child) => nodeFactory(child, rootNodeDefinitionMap))\n );\n\n case \"parallel\":\n return new Parallel(\n attributes,\n definition.children.map((child) => nodeFactory(child, rootNodeDefinitionMap))\n );\n\n case \"lotto\":\n return new Lotto(\n attributes,\n definition.weights,\n definition.children.map((child) => nodeFactory(child, rootNodeDefinitionMap))\n );\n\n case \"branch\":\n return nodeFactory(rootNodeDefinitionMap[definition.ref].child, rootNodeDefinitionMap);\n\n case \"action\":\n return new Action(attributes, definition.call, definition.args || []);\n\n case \"condition\":\n return new Condition(attributes, definition.call, definition.args || []);\n\n case \"wait\":\n let duration: number | null = null;\n let durationMin: number | null = null;\n let durationMax: number | null = null;\n\n if (Array.isArray(definition.duration)) {\n durationMin = definition.duration[0];\n durationMax = definition.duration[1];\n } else if (isInteger(definition.duration)) {\n duration = definition.duration!;\n }\n\n return new Wait(attributes, duration, durationMin, durationMax);\n }\n}\n\n/**\n * Creates an array of node attribute instances based on the specified node definition.\n * @param definition The node definition.\n * @returns An array of node attribute instances based on the specified node definition.\n */\nfunction nodeAttributesFactory(definition: AnyNodeDefinition): Attribute[] {\n const attributes: Attribute[] = [];\n\n if (definition.while) {\n attributes.push(new While(definition.while.call, definition.while.args ?? []));\n }\n\n if (definition.until) {\n attributes.push(new Until(definition.until.call, definition.until.args ?? []));\n }\n\n if (definition.entry) {\n attributes.push(new Entry(definition.entry.call, definition.entry.args ?? []));\n }\n\n if (definition.step) {\n attributes.push(new Step(definition.step.call, definition.step.args ?? []));\n }\n\n if (definition.exit) {\n attributes.push(new Exit(definition.exit.call, definition.exit.args ?? []));\n }\n\n return attributes;\n}\n\n/**\n * Creates a mapping of root node identifers to root node definitions, mixing in globally registered subtree root node definitions.\n * @param definition The root node definitions.\n * @returns A mapping of root node identifers to root node definitions, including globally registered subtree root node definitions.\n */\nfunction createRootNodeDefinitionMap(definition: RootNodeDefinition[]): RootNodeDefinitionMap {\n // Create a mapping of root node identifers to root node definitions.\n const rootNodeMap: RootNodeDefinitionMap = {};\n\n // Add in any registered subtree root node definitions.\n for (const [name, rootNodeDefinition] of Object.entries(Lookup.getSubtrees())) {\n // The name used when registering the subtree will be used as the root node identifier.\n rootNodeMap[name] = { ...rootNodeDefinition, id: name };\n }\n\n // Populate the map with the root node definitions that were included with the tree definition.\n // We do this after adding any registered subtrees as we want these to take presedence.\n for (const rootNodeDefinition of definition) {\n rootNodeMap[rootNodeDefinition.id ?? MAIN_ROOT_NODE_KEY] = rootNodeDefinition;\n }\n\n return rootNodeMap;\n}\n\n/**\n * Applies a guard path to every leaf of the tree to evaluate as part of each update.\n * @param root The main root tree node.\n */\nfunction applyLeafNodeGuardPaths(root: Root) {\n const nodePaths: Node[][] = [];\n\n const findLeafNodes = (path: Node[], node: Node) => {\n // Add the current node to the path.\n path = path.concat(node);\n\n // Check whether the current node is a leaf node.\n if (node.isLeafNode()) {\n nodePaths.push(path);\n } else {\n (node as Composite | Decorator).getChildren().forEach((child) => findLeafNodes(path, child));\n }\n };\n\n // Find all leaf node paths, starting from the root.\n findLeafNodes([], root);\n\n nodePaths.forEach((path) => {\n // Each node in the current path will have to be assigned a guard path, working from the root outwards.\n for (let depth = 0; depth < path.length; depth++) {\n // Get the node in the path at the current depth.\n const currentNode = path[depth];\n\n // The node may already have been assigned a guard path, if so just skip it.\n if (currentNode.hasGuardPath()) {\n continue;\n }\n\n // Create the guard path for the current node.\n const guardPath = new GuardPath(\n path\n .slice(0, depth + 1)\n .map((node) => ({ node, guards: node.getGuardAttributes() }))\n .filter((details) => details.guards.length > 0)\n );\n\n // Assign the guard path to the current node.\n currentNode.setGuardPath(guardPath);\n }\n });\n}\n", "import State, { AnyState } from \"./State\";\nimport Lookup from \"./Lookup\";\nimport Node from \"./nodes/Node\";\nimport Root from \"./nodes/decorator/Root\";\nimport Composite from \"./nodes/composite/Composite\";\nimport Decorator from \"./nodes/decorator/Decorator\";\nimport { Agent, GlobalFunction } from \"./Agent\";\nimport { CallbackAttributeDetails } from \"./attributes/callbacks/Callback\";\nimport { GuardAttributeDetails } from \"./attributes/guards/Guard\";\nimport { BehaviourTreeOptions } from \"./BehaviourTreeOptions\";\nimport { convertMDSLToJSON } from \"./mdsl/MDSLDefinitionParser\";\nimport { RootNodeDefinition } from \"./BehaviourTreeDefinition\";\nimport { validateDefinition, validateJSONDefinition } from \"./BehaviourTreeDefinitionValidator\";\nimport buildRootNode from \"./BehaviourTreeBuilder\";\nimport { isNullOrUndefined } from \"./BehaviourTreeDefinitionUtilities\";\n\n// Purely for outside inspection of the tree.\nexport type FlattenedTreeNode = {\n id: string;\n type: string;\n caption: string;\n state: AnyState;\n guards: GuardAttributeDetails[];\n callbacks: CallbackAttributeDetails[];\n args: any[];\n parentId: string | null;\n};\n\n/**\n * A representation of a behaviour tree.\n */\nexport class BehaviourTree {\n /**\n * The main root tree node.\n */\n private readonly _rootNode: Root;\n\n /**\n * Creates a new instance of the BehaviourTree class.\n * @param definition The behaviour tree definition as either an MDSL string, root node definition object or array of root node definition objects.\n * @param agent The agent instance that this behaviour tree is modelling behaviour for.\n * @param options The behaviour tree options object.\n */\n constructor(\n definition: string | RootNodeDefinition | RootNodeDefinition[],\n private agent: Agent,\n private options: BehaviourTreeOptions = {}\n ) {\n // The tree definition must be defined.\n if (isNullOrUndefined(definition)) {\n throw new Error(\"tree definition not defined\");\n }\n\n // The agent must be defined and not null.\n if (typeof agent !== \"object\" || agent === null) {\n throw new Error(\"the agent must be an object and not null\");\n }\n\n // We should validate the definition before we try to build the tree nodes.\n const { succeeded, errorMessage, json } = validateDefinition(definition);\n\n // Did our validation fail without error?\n if (!succeeded) {\n throw new Error(`invalid definition: ${errorMessage}`);\n }\n\n // Double check that we did actually get our json definition as part of our definition validtion.\n if (!json) {\n throw new Error(\n \"expected json definition to be returned as part of successful definition validation response\"\n );\n }\n\n try {\n // Create the populated tree of behaviour tree nodes and get the root node.\n this._rootNode = buildRootNode(json);\n } catch (exception) {\n // There was an issue in trying build and populate the behaviour tree.\n throw new Error(`error building tree: ${(exception as Error).message}`);\n }\n }\n\n /**\n * Gets whether the tree is in the RUNNING state.\n * @returns true if the tree is in the RUNNING state, otherwise false.\n */\n isRunning() {\n return this._rootNode.getState() === State.RUNNING;\n }\n\n /**\n * Gets the current tree state of SUCCEEDED, FAILED, READY or RUNNING.\n * @returns The current tree state.\n */\n getState() {\n return this._rootNode.getState();\n }\n\n /**\n * Step the tree.\n * 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.\n * 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\n * 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.\n *\n * 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.\n */\n step() {\n // If the root node has already been stepped to completion then we need to reset it.\n if (this._rootNode.getState() === State.SUCCEEDED || this._rootNode.getState() === State.FAILED) {\n this._rootNode.reset();\n }\n\n try {\n this._rootNode.update(this.agent, this.options);\n } catch (exception) {\n throw new Error(`error stepping tree: ${(exception as Error).message}`);\n }\n }\n\n /**\n * Resets the tree from the root node outwards to each nested node, giving each a state of READY.\n */\n reset() {\n this._rootNode.reset();\n }\n\n /**\n * Gets the flattened details of every node in the tree.\n * @returns The flattened details of every node in the tree.\n */\n getFlattenedNodeDetails(): FlattenedTreeNode[] {\n // Create an empty flattened array of tree nodes.\n const flattenedTreeNodes: FlattenedTreeNode[] = [];\n\n /**\n * Helper function to process a node instance and push details into the flattened tree nodes array.\n * @param node The current node.\n * @param parentUid The UID of the node parent, or null if the node is the main root node.\n */\n const processNode = (node: Node, parentUid: string | null) => {\n // Get the guard and callback attribute details for this node.\n const guards = node\n .getAttributes()\n .filter((attribute) => attribute.isGuard())\n .map((attribute) => attribute.getDetails()) as GuardAttributeDetails[];\n const callbacks = node\n .getAttributes()\n .filter((attribute) => !attribute.isGuard())\n .map((attribute) => attribute.getDetails()) as CallbackAttributeDetails[];\n\n // Push the current node into the flattened nodes array.\n flattenedTreeNodes.push({\n id: node.getUid(),\n type: node.getType(),\n caption: node.getName(),\n state: node.getState(),\n guards,\n callbacks,\n args: node.getArguments(),\n parentId: parentUid\n });\n\n // Process each of the nodes children if it is not a leaf node.\n if (!node.isLeafNode()) {\n (node as Composite | Decorator)\n .getChildren()\n .forEach((child) => processNode(child, (node as Composite | Decorator).getUid()));\n }\n };\n\n // Convert the nested node structure into a flattened array of node details.\n processNode(this._rootNode, null);\n\n return flattenedTreeNodes;\n }\n\n /**\n * Registers the action/condition/guard/callback function or subtree with the given name.\n * @param name The name of the function or subtree to register.\n * @param value The function or subtree definition to register.\n */\n static register(name: string, value: GlobalFunction | string | RootNodeDefinition) {\n // Are we going to register a action/condition/guard/callback function?\n if (typeof value === \"function\") {\n Lookup.setFunc(name, value);\n return;\n }\n\n // We are not registering an action/condition/guard/callback function, so we must be registering a subtree.\n if (typeof value === \"string\") {\n let rootNodeDefinitions: RootNodeDefinition[];\n\n // We will assume that any string passed in will be a mdsl definition.\n try {\n rootNodeDefinitions = convertMDSLToJSON(value);\n } catch (exception) {\n throw new Error(`error registering definition, invalid MDSL: ${(exception as Error).message}`);\n }\n\n // This function should only ever be called with a definition containing a single unnamed root node.\n if (rootNodeDefinitions.length != 1 || rootNodeDefinitions[0].id !== null) {\n throw new Error(\"error registering definition: expected a single unnamed root node\");\n }\n\n try {\n // We should validate the subtree as we don't want invalid subtrees available via the lookup.\n const { succeeded, errorMessage } = validateJSONDefinition(rootNodeDefinitions[0]);\n\n // Did our validation fail without error?\n if (!succeeded) {\n throw new Error(errorMessage);\n }\n } catch (exception) {\n throw new Error(`error registering definition: ${(exception as Error).message}`);\n }\n\n // Everything seems hunky-dory, register the subtree.\n Lookup.setSubtree(name, rootNodeDefinitions[0]);\n } else if (typeof value === \"object\" && !Array.isArray(value)) {\n // We will assume that any object passed in is a root node definition.\n\n try {\n // We should validate the subtree as we don't want invalid subtrees available via the lookup.\n const { succeeded, errorMessage } = validateJSONDefinition(value);\n\n // Did our validation fail without error?\n if (!succeeded) {\n throw new Error(errorMessage);\n }\n } catch (exception) {\n throw new Error(`error registering definition: ${(exception as Error).message}`);\n }\n\n // Everything seems hunky-dory, register the subtree.\n Lookup.setSubtree(name, value);\n } else {\n throw new Error(\"unexpected value, expected string mdsl definition, root node json definition or function\");\n }\n }\n\n /**\n * Unregisters the registered action/condition/guard/callback function or subtree with the given name.\n * @param name The name of the registered action/condition/guard/callback function or subtree to unregister.\n */\n static unregister(name: string): void {\n Lookup.remove(name);\n }\n\n /**\n * Unregister all registered action/condition/guard/callback functions and subtrees.\n */\n static unregisterAll(): void {\n Lookup.empty();\n }\n}\n"], - "mappings": "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", + "sourcesContent": ["\"use strict\";\r\nObject.defineProperty(exports, \"__esModule\", { value: true });\r\nexports.Participant = void 0;\r\n/**\r\n * A participant that holds a number of tickets.\r\n */\r\nvar Participant = /** @class */ (function () {\r\n /**\r\n * Creates an instance of the Participant class.\r\n * @param participant The actual participant.\r\n * @param tickets The number of tickets held by the participant.\r\n */\r\n function Participant(participant, tickets) {\r\n if (tickets === void 0) { tickets = 1; }\r\n this._participant = participant;\r\n this._tickets = tickets;\r\n }\r\n Object.defineProperty(Participant.prototype, \"participant\", {\r\n /** Gets the actual participant. */\r\n get: function () {\r\n return this._participant;\r\n },\r\n enumerable: false,\r\n configurable: true\r\n });\r\n Object.defineProperty(Participant.prototype, \"tickets\", {\r\n /** Gets or sets the number of tickets held by the participant. */\r\n get: function () {\r\n return this._tickets;\r\n },\r\n set: function (value) {\r\n this._tickets = value;\r\n },\r\n enumerable: false,\r\n configurable: true\r\n });\r\n return Participant;\r\n}());\r\nexports.Participant = Participant;\r\n", "\"use strict\";\r\nObject.defineProperty(exports, \"__esModule\", { value: true });\r\nexports.isNaturalNumber = exports.isNullOrUndefined = void 0;\r\n/**\r\n * Gets whether the value provided is null or undefined.\r\n * @param value The value to check.\r\n * @returns Whether the value provided is null or undefined.\r\n */\r\nfunction isNullOrUndefined(value) {\r\n return value === null || value === undefined;\r\n}\r\nexports.isNullOrUndefined = isNullOrUndefined;\r\n/**\r\n * Gets whether the value provided is a natural number.\r\n * @param value The value to check.\r\n * @returns Whether the value provided is a natural number.\r\n */\r\nfunction isNaturalNumber(value) {\r\n return typeof value === \"number\" && value >= 1 && Math.floor(value) === value;\r\n}\r\nexports.isNaturalNumber = isNaturalNumber;\r\n", "\"use strict\";\r\nObject.defineProperty(exports, \"__esModule\", { value: true });\r\nexports.Lotto = void 0;\r\nvar Participant_1 = require(\"./Participant\");\r\nvar Utilities_1 = require(\"./Utilities\");\r\n/**\r\n * Represents a lotto consisting of a number of pickable ticket-holding participants.\r\n */\r\nvar Lotto = /** @class */ (function () {\r\n /**\r\n * Creates a new instance of Lotto.\r\n * @param customRandom The custom RNG to use in place of Math.random().\r\n */\r\n function Lotto(customRandom) {\r\n /** The array of participants that are holding tickets in the lotto. */\r\n this._participants = [];\r\n this._customRandom = customRandom;\r\n }\r\n /**\r\n * Adds a participant with the specified number of tickets, or adds to the participant ticket count if the participant already holds tickets.\r\n * @param participant The participant to add or to increase the ticket count for if they already hold tickets.\r\n * @param tickets The number of tickets, defaults to 1.\r\n * @returns The Lotto instance.\r\n */\r\n Lotto.prototype.add = function (participant, tickets) {\r\n if (tickets === void 0) { tickets = 1; }\r\n // Check that we have a valid ticket count.\r\n if (!(0, Utilities_1.isNaturalNumber)(tickets)) {\r\n throw new Error(\"tickets value must be a natural number\");\r\n }\r\n // Check whether this participant has already been added.\r\n var existingParticipant = this._participants.find(function (part) { return part.participant === participant; });\r\n if (existingParticipant) {\r\n // The participant has already been added to the lotto so just add to their ticket count.\r\n existingParticipant.tickets += tickets;\r\n }\r\n else {\r\n // The participant is not part of the lotto so we should add them.\r\n this._participants.push(new Participant_1.Participant(participant, tickets));\r\n }\r\n return this;\r\n };\r\n /**\r\n * Removes the specified number of tickets for the given participant from the draw, or all tickets if a ticket number is not defined.\r\n * @param participant The participant to remove tickets for.\r\n * @param tickets The number of tickets to remove, or undefined if all tickets are to be removed.\r\n * @returns The Lotto instance.\r\n */\r\n Lotto.prototype.remove = function (participant, tickets) {\r\n // Attempt to get the existing participant.\r\n var existingParticipant = this._participants.find(function (part) { return part.participant === participant; });\r\n // There is nothing to do if the specified participant isn't even part of the lotto.\r\n if (!existingParticipant) {\r\n return this;\r\n }\r\n // Check whether a tickets value was given.\r\n if (tickets !== undefined) {\r\n // Check that we have a valid ticket count.\r\n if (!(0, Utilities_1.isNaturalNumber)(tickets)) {\r\n throw new Error(\"tickets value must be a natural number\");\r\n }\r\n existingParticipant.tickets -= tickets;\r\n // If the participant no longer holds any tickets then they should be removed.\r\n if (existingParticipant.tickets < 1) {\r\n this._participants = this._participants.filter(function (part) { return part !== existingParticipant; });\r\n }\r\n }\r\n else {\r\n // We are removing all tickets for the participant so just remove them from the lotto.\r\n this._participants = this._participants.filter(function (part) { return part !== existingParticipant; });\r\n }\r\n return this;\r\n };\r\n /**\r\n * Draw a winning ticket and return the participant that holds the ticket.\r\n * @param options The draw options.\r\n * @returns The participant that holds the winning ticket.\r\n */\r\n Lotto.prototype.draw = function (options) {\r\n if (options === void 0) { options = {}; }\r\n // If we have no participants then just return null.\r\n if (this._participants.length === 0) {\r\n return null;\r\n }\r\n var redrawable = (0, Utilities_1.isNullOrUndefined)(options.redrawable) ? true : options.redrawable;\r\n var pickable = [];\r\n this._participants.forEach(function (_a) {\r\n var participant = _a.participant, tickets = _a.tickets;\r\n for (var ticketCount = 0; ticketCount < tickets; ticketCount++) {\r\n pickable.push(participant);\r\n }\r\n });\r\n var random;\r\n // We need a random floating-point number between 0 (inclusive) and 1 to scale up to pick our winner.\r\n // If a custom random function exists then we should use that or fall back to Math.random().\r\n if (this._customRandom) {\r\n // Call our custom random function to get a random floating-point number.\r\n random = this._customRandom();\r\n // Verify that the result of calling our custom random function is a number between 0 (inclusive) and 1.\r\n if (typeof random !== \"number\" || random < 0 || random >= 1) {\r\n throw new Error(\"the 'random' function provided did not return a number between 0 (inclusive) and 1\");\r\n }\r\n }\r\n else {\r\n // No custom random function was defined so just use good ol' Math.random().\r\n random = Math.random();\r\n }\r\n // Pick a winning participant.\r\n var winner = pickable[Math.floor(random * pickable.length)];\r\n // If the ticket isn't redrawable then we should remove a ticket from the winning participants ticket count.\r\n if (!redrawable) {\r\n this.remove(winner, 1);\r\n }\r\n // Return the winning participant.\r\n return winner;\r\n };\r\n /**\r\n * Draws multiple winning tickets and return an array of the participants that hold the winning tickets.\r\n * @param tickets The number of winning tickets to draw.\r\n * @param options The draw multiple options.\r\n * @returns An array of the participants that hold the winning tickets.\r\n */\r\n Lotto.prototype.drawMultiple = function (tickets, options) {\r\n if (options === void 0) { options = {}; }\r\n var uniqueResults = (0, Utilities_1.isNullOrUndefined)(options.unique) ? false : options.unique;\r\n // Handle cases where the user has asked for zero tickets (no idea why they would do this be we should trust them).\r\n if (tickets === 0) {\r\n return [];\r\n }\r\n // Now that we know out tickets value is not zero we should check that it is a valid natural number.\r\n if (!(0, Utilities_1.isNaturalNumber)(tickets)) {\r\n throw new Error(\"tickets value must be a natural number\");\r\n }\r\n var result = [];\r\n // Keep drawing tickets until we either reach the number of required tickets or we simply run out of tickets to draw.\r\n // We can run out of tickets to draw if 'options.redrawable' is explicity 'false' or we just had no participants when 'drawMultiple' was called.\r\n while (result.length < tickets && this._participants.length > 0) {\r\n result.push(this.draw(options));\r\n }\r\n // If the 'unique' draw option is set then we need to remove duplicates from the result list.\r\n if (uniqueResults) {\r\n // Create an array to store our unique results.\r\n var unique = [];\r\n // Iterate over all of our participants (with potential duplicates) and populate our array of unique values.\r\n for (var _i = 0, result_1 = result; _i < result_1.length; _i++) {\r\n var participant = result_1[_i];\r\n if (unique.indexOf(participant) === -1) {\r\n unique.push(participant);\r\n }\r\n }\r\n result = unique;\r\n }\r\n return result;\r\n };\r\n return Lotto;\r\n}());\r\nexports.Lotto = Lotto;\r\n", "\"use strict\";\r\nObject.defineProperty(exports, \"__esModule\", { value: true });\r\nexports.createLotto = void 0;\r\nvar Lotto_1 = require(\"./Lotto\");\r\n/**\r\n * A function that creates and returns a Lotto instance.\r\n * @param participantsOrOptions An array of initial participants or options relating to the creation of a Lotto instance.\r\n * @returns A new Lotto instance.\r\n */\r\nfunction createLotto(participantsOrOptions) {\r\n // If no initial participants or lotto options were provided as an argument then we can just return a new lotto instance now.\r\n if (!participantsOrOptions) {\r\n return new Lotto_1.Lotto();\r\n }\r\n // Check whether we were provided with an array of initial participants or a lotto options object.\r\n if (Array.isArray(participantsOrOptions)) {\r\n // We are dealing with a pre-defined array of participants.\r\n var participants = participantsOrOptions;\r\n var lotto_1 = new Lotto_1.Lotto();\r\n // If the lotto participants have been defined upfront then we will need to add them all to our lotto instance now.\r\n participants.forEach(function (_a) {\r\n var participant = _a[0], tokens = _a[1];\r\n return lotto_1.add(participant, tokens);\r\n });\r\n // Return the Lotto instance.\r\n return lotto_1;\r\n }\r\n else {\r\n // We are dealing with some lotto options.\r\n var random = participantsOrOptions.random, participants = participantsOrOptions.participants;\r\n // Create a Lotto instance passing the custom RNG function to use in place of Math.random() (which could be undefined).\r\n var lotto_2 = new Lotto_1.Lotto(random);\r\n // If the lotto participants have been defined upfront as part of the options then we will need to add them all to our lotto instance now.\r\n if (participants) {\r\n participants.forEach(function (_a) {\r\n var participant = _a[0], tokens = _a[1];\r\n return lotto_2.add(participant, tokens);\r\n });\r\n }\r\n // Return the Lotto instance.\r\n return lotto_2;\r\n }\r\n}\r\nexports.createLotto = createLotto;\r\n", "\"use strict\";\r\nObject.defineProperty(exports, \"__esModule\", { value: true });\r\nvar createLotto_1 = require(\"./createLotto\");\r\nexports.default = createLotto_1.createLotto;\r\n", "import State from \"./State\";\nimport { validateDefinition } from \"./BehaviourTreeDefinitionValidator\";\nimport { convertMDSLToJSON } from \"./mdsl/MDSLDefinitionParser\";\nimport { BehaviourTree, FlattenedTreeNode } from \"./BehaviourTree\";\nimport { BehaviourTreeOptions } from \"./BehaviourTreeOptions\";\n\nexport { BehaviourTree, State, convertMDSLToJSON, validateDefinition };\nexport type { FlattenedTreeNode, BehaviourTreeOptions };\n", "/**\n * Enumeration of node state types.\n */\nexport enum State {\n READY = \"mistreevous.ready\",\n RUNNING = \"mistreevous.running\",\n SUCCEEDED = \"mistreevous.succeeded\",\n FAILED = \"mistreevous.failed\"\n}\n\nexport { State as default };\n\nexport type CompleteState = State.SUCCEEDED | State.FAILED;\nexport type AnyState = State.READY | State.RUNNING | CompleteState;\n", "import {\n NodeDefinition,\n RootNodeDefinition,\n DecoratorNodeDefinition,\n CompositeNodeDefinition,\n AnyNodeDefinition,\n BranchNodeDefinition\n} from \"./BehaviourTreeDefinition\";\n\n/**\n * A type guard function that returns true if the specified node satisfies the RootNodeDefinition type.\n * @param node The node.\n * @returns A value of true if the specified node satisfies the RootNodeDefinition type.\n */\nexport function isRootNode(node: NodeDefinition): node is RootNodeDefinition {\n return node.type === \"root\";\n}\n\n/**\n * A type guard function that returns true if the specified node satisfies the BranchNodeDefinition type.\n * @param node The node.\n * @returns A value of true if the specified node satisfies the BranchNodeDefinition type.\n */\nexport function isBranchNode(node: NodeDefinition): node is BranchNodeDefinition {\n return node.type === \"branch\";\n}\n\n/**\n * A type guard function that returns true if the specified node satisfies the NodeDefinition type.\n * @param node The node.\n * @returns A value of true if the specified node satisfies the NodeDefinition type.\n */\nexport function isLeafNode(node: NodeDefinition): node is NodeDefinition {\n return [\"branch\", \"action\", \"condition\", \"wait\"].includes(node.type);\n}\n\n/**\n * A type guard function that returns true if the specified node satisfies the DecoratorNodeDefinition type.\n * @param node The node.\n * @returns A value of true if the specified node satisfies the DecoratorNodeDefinition type.\n */\nexport function isDecoratorNode(node: NodeDefinition): node is DecoratorNodeDefinition {\n return [\"root\", \"repeat\", \"retry\", \"flip\", \"succeed\", \"fail\"].includes(node.type);\n}\n\n/**\n * A type guard function that returns true if the specified node satisfies the CompositeNodeDefinition type.\n * @param node The node.\n * @returns A value of true if the specified node satisfies the CompositeNodeDefinition type.\n */\nexport function isCompositeNode(node: NodeDefinition): node is CompositeNodeDefinition {\n return [\"sequence\", \"selector\", \"lotto\", \"parallel\"].includes(node.type);\n}\n\n/**\n * Flatten a node definition into an array of all of its nested node definitions.\n * @param nodeDefinition The node definition to flatten.\n * @returns An array of all of nested node definitions.\n */\nexport function flattenDefinition(nodeDefinition: AnyNodeDefinition): AnyNodeDefinition[] {\n const nodes: AnyNodeDefinition[] = [];\n\n const processNode = (currentNodeDefinition: AnyNodeDefinition) => {\n nodes.push(currentNodeDefinition);\n\n if (isCompositeNode(currentNodeDefinition)) {\n currentNodeDefinition.children.forEach(processNode);\n } else if (isDecoratorNode(currentNodeDefinition)) {\n processNode(currentNodeDefinition.child);\n }\n };\n\n processNode(nodeDefinition);\n\n return nodes;\n}\n\n/**\n * Determines whether the passed value is an integer.\n * @param value The value to check.\n * @returns Whether the passed value is an integer.\n */\nexport function isInteger(value: unknown): boolean {\n return typeof value === \"number\" && Math.floor(value) === value;\n}\n\n/**\n * Determines whether the passed value is null or undefined.\n * @param value The value to check.\n * @returns Whether the passed value is null or undefined.\n */\nexport function isNullOrUndefined(value: unknown): boolean {\n return typeof value === \"undefined\" || value === null;\n}\n", "/**\n * A type defining an object that holds a reference to substitued string literals parsed from the definition.\n */\nexport type StringLiteralPlaceholders = { [key: string]: string };\n\n/**\n * Pop the next raw token from the specified array of tokens and throw an error if it wasn't the expected one.\n * @param tokens The array of tokens.\n * @param expected An optional string or array or items, one of which must match the next popped token.\n * @returns The popped token.\n */\nexport function popAndCheck(tokens: string[], expected?: string | string[]): string {\n // Get and remove the next token.\n const popped = tokens.shift();\n\n // We were expecting another token but there aren't any.\n if (popped === undefined) {\n throw new Error(\"unexpected end of definition\");\n }\n\n // Do we have an expected token/tokens array?\n if (expected != undefined) {\n // Get an array of expected values, if the popped token matches any then we are all good.\n const expectedValues = typeof expected === \"string\" ? [expected] : expected;\n\n // Check whether the popped token matches at least one of our expected items.\n var tokenMatchesExpectation = expectedValues.some((item) => popped.toUpperCase() === item.toUpperCase());\n\n // Throw an error if the popped token didn't match any of our expected items.\n if (!tokenMatchesExpectation) {\n const expectationString = expectedValues.map((item) => \"'\" + item + \"'\").join(\" or \");\n throw new Error(\"unexpected token found. Expected \" + expectationString + \" but got '\" + popped + \"'\");\n }\n }\n\n // Return the popped token.\n return popped;\n}\n\n/**\n * Swaps out any node/attribute argument string literals with placeholders.\n * @param definition The definition.\n * @returns An object containing a mapping of placeholders to original string values as well as the processed definition string.\n */\nexport function substituteStringLiterals(definition: string): {\n placeholders: StringLiteralPlaceholders;\n processedDefinition: string;\n} {\n // Create an object to hold the mapping of placeholders to original string values.\n const placeholders: StringLiteralPlaceholders = {};\n\n // Replace any string literals wrapped with double quotes in our definition with placeholders to be processed later.\n const processedDefinition = definition.replace(/\\\"(\\\\.|[^\"\\\\])*\\\"/g, (match) => {\n var strippedMatch = match.substring(1, match.length - 1);\n var placeholder = Object.keys(placeholders).find((key) => placeholders[key] === strippedMatch);\n\n // If we have no existing string literal match then create a new placeholder.\n if (!placeholder) {\n placeholder = `@@${Object.keys(placeholders).length}@@`;\n placeholders[placeholder] = strippedMatch;\n }\n\n return placeholder;\n });\n\n return { placeholders, processedDefinition };\n}\n\n/**\n * Parse the tree definition into an array of raw tokens.\n * @param definition The definition.\n * @returns An array of tokens parsed from the definition.\n */\nexport function parseTokensFromDefinition(definition: string): string[] {\n // Add some space around various important characters so that they can be plucked out easier as individual tokens.\n definition = definition.replace(/\\(/g, \" ( \");\n definition = definition.replace(/\\)/g, \" ) \");\n definition = definition.replace(/\\{/g, \" { \");\n definition = definition.replace(/\\}/g, \" } \");\n definition = definition.replace(/\\]/g, \" ] \");\n definition = definition.replace(/\\[/g, \" [ \");\n definition = definition.replace(/\\,/g, \" , \");\n\n // Split the definition into raw token form and return it.\n return definition.replace(/\\s+/g, \" \").trim().split(\" \");\n}\n", "import { StringLiteralPlaceholders, popAndCheck } from \"./MDSLUtilities\";\n\n/**\n * A type representing any node function argument.\n */\ntype Argument = {\n /**\n * The argument value.\n */\n value: T;\n /**\n * The argument type, used for validation.\n */\n type: string;\n};\n\ntype NullArgument = Argument & {\n type: \"null\";\n};\n\ntype BooleanArgument = Argument & {\n type: \"boolean\";\n};\n\ntype NumberArgument = Argument & {\n type: \"number\";\n /**\n * A flag defining whether the number argument value is a valid integer. (used for validation)\n */\n isInteger: boolean;\n};\n\ntype StringPlaceholderArgument = Argument & {\n type: \"string\";\n};\n\ntype IdentifierArgument = Argument & {\n type: \"identifier\";\n};\n\n/**\n * A type representing a reference to any node function argument.\n */\ntype AnyArgument = NullArgument | BooleanArgument | NumberArgument | StringPlaceholderArgument | IdentifierArgument;\n\n/**\n * Parse an array of argument definitions from the specified tokens array.\n * @param tokens The array tokens to parse the argument definitions from.\n * @param stringArgumentPlaceholders The mapping of string literal node argument placeholders to original values.\n * @param argumentValidator The argument validator function.\n * @param validationFailedMessage The exception message to throw if argument validation fails.\n * @returns An array of argument definitions parsed from the specified tokens array.\n */\nexport function parseArgumentTokens(\n tokens: string[],\n stringArgumentPlaceholders: StringLiteralPlaceholders\n): AnyArgument[] {\n const argumentList: AnyArgument[] = [];\n\n // If the next token is not a '[' or '(' then we have no arguments to parse.\n if (![\"[\", \"(\"].includes(tokens[0])) {\n return argumentList;\n }\n\n // Any lists of arguments will always be wrapped in '[]' for node arguments or '()' for attribute arguments.\n // We are looking for a '[' or '(' opener that wraps the argument tokens and the relevant closer.\n const closingToken = popAndCheck(tokens, [\"[\", \"(\"]) === \"[\" ? \"]\" : \")\";\n\n const argumentListTokens: string[] = [];\n\n // Grab all tokens between the '[' and ']' or '(' and ')'.\n while (tokens.length && tokens[0] !== closingToken) {\n // The next token is part of our arguments list.\n argumentListTokens.push(tokens.shift()!);\n }\n\n // Validate the order of the argument tokens. Each token must either be a ',' or a single argument that satisfies the validator.\n argumentListTokens.forEach((token, index) => {\n // Get whether this token should be an actual argument.\n const shouldBeArgumentToken = !(index & 1);\n\n // If the current token should be an actual argument then validate it, otherwise it should be a ',' token.\n if (shouldBeArgumentToken) {\n // Get the argument definition.\n const argumentDefinition = getArgumentDefinition(token, stringArgumentPlaceholders);\n\n // This is a valid argument!\n argumentList.push(argumentDefinition);\n } else {\n // The current token should be a ',' token.\n if (token !== \",\") {\n throw new Error(`invalid argument list, expected ',' or ']' but got '${token}'`);\n }\n }\n });\n\n // The arguments list should terminate with a ']' or ')' token, depending on the opener.\n popAndCheck(tokens, closingToken);\n\n // Return the arguments.\n return argumentList;\n}\n\n/**\n * Gets an argument value definition.\n * @param token The argument token.\n * @param stringArgumentPlaceholders The mapping of string literal node argument placeholders to original values.\n * @returns An argument value definition.\n */\nfunction getArgumentDefinition(token: string, stringArgumentPlaceholders: StringLiteralPlaceholders): AnyArgument {\n // Check whether the token represents a null value.\n if (token === \"null\") {\n return {\n value: null,\n type: \"null\"\n } as NullArgument;\n }\n\n // Check whether the token represents a boolean value.\n if (token === \"true\" || token === \"false\") {\n return {\n value: token === \"true\",\n type: \"boolean\"\n } as BooleanArgument;\n }\n\n // Check whether the token represents a number value.\n // TODO: Relies on broken isNaN - see MDN.\n // if (!Number.isNaN(token)) {\n if (!isNaN(token as any)) {\n return {\n value: parseFloat(token),\n isInteger: parseFloat(token) === parseInt(token, 10),\n type: \"number\"\n } as NumberArgument;\n }\n\n // Check whether the token is a placeholder (e.g. @@0@@) representing a string literal.\n if (token.match(/^@@\\d+@@$/g)) {\n return {\n value: stringArgumentPlaceholders[token].replace('\\\\\"', '\"'),\n type: \"string\"\n } as StringPlaceholderArgument;\n }\n\n // The only remaining option is that the argument value is an identifier.\n return {\n value: token,\n type: \"identifier\"\n } as IdentifierArgument;\n}\n", "import { NodeAttributeDefinition } from \"../BehaviourTreeDefinition\";\nimport { parseArgumentTokens } from \"./MDSLNodeArgumentParser\";\nimport { StringLiteralPlaceholders } from \"./MDSLUtilities\";\n\n/**\n * A type defining the attribute definitions of a node.\n */\ntype NodeAttributes = {\n while?: NodeAttributeDefinition;\n until?: NodeAttributeDefinition;\n entry?: NodeAttributeDefinition;\n exit?: NodeAttributeDefinition;\n step?: NodeAttributeDefinition;\n};\n\n/**\n * Parse any node attribute definitions from the specified tokens array.\n * @param tokens The array of remaining tokens.\n * @param stringArgumentPlaceholders The mapping of string literal node argument placeholders to original values.\n * @returns An object of attribute definitions defined by any directly following tokens.\n */\nexport function parseAttributeTokens(\n tokens: string[],\n stringArgumentPlaceholders: StringLiteralPlaceholders\n): NodeAttributes {\n const nodeAttributeNames: (keyof NodeAttributes)[] = [\"while\", \"until\", \"entry\", \"exit\", \"step\"];\n\n // Create an object to hold any attributes found.\n const attributes: NodeAttributes = {};\n\n // Try to get the name of the attribute for the next token.\n let nextAttributeName = tokens[0]?.toLowerCase() as keyof NodeAttributes;\n\n // Pull attribute tokens as well as their arguments off of the tokens stack until we have no more.\n while (nodeAttributeNames.includes(nextAttributeName)) {\n // Check to make sure that we have not already created an attribute definition of this type.\n if (attributes[nextAttributeName]) {\n throw new Error(`duplicate attribute '${tokens[0].toUpperCase()}' found for node`);\n }\n\n // Remove the attribute name token from the array of tokens.\n tokens.shift();\n\n // Grab the attribute arguments, assuming the first to be an identifier.\n const [attributeCallIdentifier, ...attributeArguments] = parseArgumentTokens(\n tokens,\n stringArgumentPlaceholders\n );\n\n // The first attribute argument has to be an identifer, this will reference an agent function.\n if (attributeCallIdentifier?.type !== \"identifier\") {\n throw new Error(\"expected agent function name identifier argument for attribute\");\n }\n\n // Any attribute arguments (other than the expected call identifier) must have a type of string, number, boolean or null.\n attributeArguments\n .filter((arg) => arg.type === \"identifier\")\n .forEach((arg) => {\n throw new Error(\n `invalid attribute argument value '${arg.value}', must be string, number, boolean or null`\n );\n });\n\n // Create the attribute definition and add it to the object of attribute definitions found.\n attributes[nextAttributeName] = {\n call: attributeCallIdentifier.value,\n args: attributeArguments.map(({ value }) => value)\n };\n\n // Try to get the next attribute name token, as there could be multiple.\n nextAttributeName = tokens[0]?.toLowerCase() as keyof NodeAttributes;\n }\n\n return attributes;\n}\n", "import {\n ActionNodeDefinition,\n AnyChildNodeDefinition,\n AnyNodeDefinition,\n BranchNodeDefinition,\n ConditionNodeDefinition,\n FailNodeDefinition,\n FlipNodeDefinition,\n LottoNodeDefinition,\n ParallelNodeDefinition,\n RepeatNodeDefinition,\n RetryNodeDefinition,\n RootNodeDefinition,\n SelectorNodeDefinition,\n SequenceNodeDefinition,\n SucceedNodeDefinition,\n WaitNodeDefinition\n} from \"../BehaviourTreeDefinition\";\nimport {\n isCompositeNode,\n isDecoratorNode,\n isLeafNode,\n isNullOrUndefined,\n isRootNode\n} from \"../BehaviourTreeDefinitionUtilities\";\nimport { parseArgumentTokens } from \"./MDSLNodeArgumentParser\";\nimport { parseAttributeTokens } from \"./MDSLNodeAttributeParser\";\nimport {\n StringLiteralPlaceholders,\n parseTokensFromDefinition,\n popAndCheck,\n substituteStringLiterals\n} from \"./MDSLUtilities\";\n\n/**\n * Convert the MDSL tree definition string into an equivalent JSON definition.\n * @param definition The tree definition string as MDSL.\n * @returns The root node JSON definitions.\n */\nexport function convertMDSLToJSON(definition: string): RootNodeDefinition[] {\n // Swap out any node/attribute argument string literals with a placeholder and get a mapping of placeholders to original values as well as the processed definition.\n const { placeholders, processedDefinition } = substituteStringLiterals(definition);\n\n // Parse our definition definition string into an array of raw tokens.\n const tokens = parseTokensFromDefinition(processedDefinition);\n\n return convertTokensToJSONDefinition(tokens, placeholders);\n}\n\n/**\n * Converts the specified tree definition tokens into a JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The root node JSON definitions.\n */\nfunction convertTokensToJSONDefinition(\n tokens: string[],\n stringLiteralPlaceholders: StringLiteralPlaceholders\n): RootNodeDefinition[] {\n // There must be at least 3 tokens for the tree definition to be valid. 'ROOT', '{' and '}'.\n if (tokens.length < 3) {\n throw new Error(\"invalid token count\");\n }\n\n // We should have a matching number of '{' and '}' tokens. If not, then there are scopes that have not been properly closed.\n if (tokens.filter((token) => token === \"{\").length !== tokens.filter((token) => token === \"}\").length) {\n throw new Error(\"scope character mismatch\");\n }\n\n // Create an array of tree stack arrays where root nodes will always be at the botton and the current composite/decorator node at the top.\n // There should be an element in this array for every root node defined and every element should be an array with a root note as the first element.\n // E.g. A definition with two root nodes defined:\n // [\n // [root, lotto, sequence],\n // [root, selector]\n // ]\n const treeStacks: [Partial, ...Partial[]][] = [];\n\n // Create an array of all root node definitions that we create.\n const rootNodes: Partial[] = [];\n\n // A helper function used to push node definitions onto the tree stack.\n const pushNode = (node: AnyNodeDefinition) => {\n // If the node is a root node then we need to create a new tree stack array with the root node at the root.\n if (isRootNode(node)) {\n // We need to double-check that this root node is not the child of another node.\n // We can do this by checking whether the top tree stack is not empty (contains an existing node)\n if (treeStacks[treeStacks.length - 1]?.length) {\n throw new Error(\"a root node cannot be the child of another node\");\n }\n\n // Add the root node definition to our array of all parsed root node definitions.\n rootNodes.push(node);\n\n // Add the root node definition to the root of a new tree stack.\n treeStacks.push([node]);\n\n return;\n }\n\n // All non-root nodes should be pushed after their root nodes so handle cases\n // where we may not have any tree stacks or our top-most tree stack is empty.\n if (!treeStacks.length || !treeStacks[treeStacks.length - 1].length) {\n throw new Error(\"expected root node at base of definition\");\n }\n\n // Get the current tree stack that we are populating.\n const topTreeStack = treeStacks[treeStacks.length - 1];\n\n // Get the top-most node in the current tree stack, this will be a composite/decorator node\n // for which we will populate its children array if composite or setting its child if a decorator.\n const topTreeStackTopNode = topTreeStack[topTreeStack.length - 1] as AnyNodeDefinition;\n\n // If the top-most node in the current root stack is a composite or decorator\n // node then the current node should be added as a child of the top-most node.\n if (isCompositeNode(topTreeStackTopNode)) {\n topTreeStackTopNode.children = topTreeStackTopNode.children || [];\n topTreeStackTopNode.children.push(node);\n } else if (isDecoratorNode(topTreeStackTopNode)) {\n // If the top node already has a child node set then throw an error as a decorator should only have a single child.\n if (topTreeStackTopNode.child) {\n throw new Error(\"a decorator node must only have a single child node\");\n }\n\n topTreeStackTopNode.child = node;\n }\n\n // If the node we are adding is also a composite or decorator node, then we should push it\n // onto the current tree stack, as subsequent nodes will be added as its child/children.\n if (!isLeafNode(node)) {\n topTreeStack.push(node);\n }\n };\n\n // A helper function used to pop the top-most node definition off of the tree stack and return it.\n const popNode = (): AnyNodeDefinition | null => {\n let poppedNode: AnyNodeDefinition | null = null;\n\n // Get the current tree stack that we are populating.\n const topTreeStack = treeStacks[treeStacks.length - 1];\n\n // Pop the top-most node in the current tree stack if there is one.\n if (topTreeStack.length) {\n poppedNode = topTreeStack.pop() as AnyNodeDefinition;\n }\n\n // We don't want any empty tree stacks in our stack of tree stacks.\n if (!topTreeStack.length) {\n treeStacks.pop();\n }\n\n return poppedNode;\n };\n\n // We should keep processing the raw tokens until we run out of them.\n while (tokens.length) {\n // Grab the next token.\n const token = tokens.shift()!;\n\n // How we create the next node depends on the current raw token value.\n switch (token.toUpperCase()) {\n case \"ROOT\": {\n pushNode(createRootNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"SUCCEED\": {\n pushNode(createSucceedNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"FAIL\": {\n pushNode(createFailNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"FLIP\": {\n pushNode(createFlipNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"REPEAT\": {\n pushNode(createRepeatNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"RETRY\": {\n pushNode(createRetryNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"SEQUENCE\": {\n pushNode(createSequenceNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"SELECTOR\": {\n pushNode(createSelectorNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"PARALLEL\": {\n pushNode(createParallelNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"LOTTO\": {\n pushNode(createLottoNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"ACTION\": {\n pushNode(createActionNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"CONDITION\": {\n pushNode(createConditionNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"WAIT\": {\n pushNode(createWaitNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"BRANCH\": {\n pushNode(createBranchNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"}\": {\n // The '}' character closes the current scope and means that we have to pop a node off of the current stack.\n const poppedNode = popNode();\n\n // Now that we have a node definition we can carry out any validation that may require the node to be fully populated.\n if (poppedNode) {\n validatePoppedNode(poppedNode);\n }\n\n break;\n }\n\n default: {\n throw new Error(`unexpected token: ${token}`);\n }\n }\n }\n\n return rootNodes as RootNodeDefinition[];\n}\n\n/**\n * Creates a root node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The root node JSON definition.\n */\nfunction createRootNode(tokens: string[], stringLiteralPlaceholders: StringLiteralPlaceholders): RootNodeDefinition {\n // Create the root node definition.\n let node = {\n type: \"root\",\n id: undefined\n } as RootNodeDefinition;\n\n // Parse any node arguments, we should only have one if any which will be an identifier argument for the root identifier.\n const nodeArguments = parseArgumentTokens(tokens, stringLiteralPlaceholders);\n\n // Check whether any node arguments were defined.\n if (nodeArguments.length) {\n // We should only have one argument, if any, which will be an identifier argument for the root identifier.\n if (nodeArguments.length === 1 && nodeArguments[0].type === \"identifier\") {\n // The root node identifier will be the first and only node argument value.\n node.id = nodeArguments[0].value as string;\n } else {\n throw new Error(\"expected single root name argument\");\n }\n }\n\n // Grab any node attribute definitions and spread them into the node definition.\n node = { ...node, ...parseAttributeTokens(tokens, stringLiteralPlaceholders) };\n\n // This is a decorator node, so we expect an opening '{'.\n popAndCheck(tokens, \"{\");\n\n // Return the root node definition.\n return node;\n}\n\n/**\n * Creates a succeed node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The succeed node JSON definition.\n */\nfunction createSucceedNode(\n tokens: string[],\n stringLiteralPlaceholders: StringLiteralPlaceholders\n): SucceedNodeDefinition {\n const node = {\n type: \"succeed\",\n ...parseAttributeTokens(tokens, stringLiteralPlaceholders)\n } as SucceedNodeDefinition;\n\n // This is a decorator node, so we expect an opening '{'.\n popAndCheck(tokens, \"{\");\n\n // Return the succeed node definition.\n return node;\n}\n\n/**\n * Creates a fail node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The fail node JSON definition.\n */\nfunction createFailNode(tokens: string[], stringLiteralPlaceholders: StringLiteralPlaceholders): FailNodeDefinition {\n const node = {\n type: \"fail\",\n ...parseAttributeTokens(tokens, stringLiteralPlaceholders)\n } as FailNodeDefinition;\n\n // This is a decorator node, so we expect an opening '{'.\n popAndCheck(tokens, \"{\");\n\n // Return the fail node definition.\n return node;\n}\n\n/**\n * Creates a flip node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The flip node JSON definition.\n */\nfunction createFlipNode(tokens: string[], stringLiteralPlaceholders: StringLiteralPlaceholders): FlipNodeDefinition {\n const node = {\n type: \"flip\",\n ...parseAttributeTokens(tokens, stringLiteralPlaceholders)\n } as FlipNodeDefinition;\n\n // This is a decorator node, so we expect an opening '{'.\n popAndCheck(tokens, \"{\");\n\n // Return the flip node definition.\n return node;\n}\n\n/**\n * Creates a repeat node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The repeat node JSON definition.\n */\nfunction createRepeatNode(\n tokens: string[],\n stringLiteralPlaceholders: StringLiteralPlaceholders\n): RepeatNodeDefinition {\n let node = { type: \"repeat\" } as RepeatNodeDefinition;\n\n // Get the node arguments.\n const nodeArguments = parseArgumentTokens(tokens, stringLiteralPlaceholders);\n\n // The arguments of a repeat node are optional. We may have:\n // - No node arguments, in which case the repeat note will iterate indefinitely.\n // - One node argument which will be the explicit number of iterations to make.\n // - Two node arguments which define the min and max iteration bounds from which a random iteration count will be picked.\n if (nodeArguments.length) {\n // All repeat node arguments MUST be of type number and must be integer.\n nodeArguments\n .filter((arg) => arg.type !== \"number\" || !arg.isInteger)\n .forEach(() => {\n throw new Error(`repeat node iteration counts must be integer values`);\n });\n\n // We should have got one or two iteration counts.\n if (nodeArguments.length === 1) {\n // A static iteration count was defined.\n node.iterations = nodeArguments[0].value as number;\n\n // A repeat node must have a positive number of iterations if defined.\n if (node.iterations < 0) {\n throw new Error(\"a repeat node must have a positive number of iterations if defined\");\n }\n } else if (nodeArguments.length === 2) {\n // A minimum and maximum iteration count was defined.\n node.iterations = [nodeArguments[0].value as number, nodeArguments[1].value as number];\n\n // A repeat node must have a positive min and max iteration count if they are defined.\n if (node.iterations[0] < 0 || node.iterations[1] < 0) {\n throw new Error(\"a repeat node must have a positive minimum and maximum iteration count if defined\");\n }\n\n // A repeat node must not have an minimum iteration count that exceeds the maximum iteration count.\n if (node.iterations[0] > node.iterations[1]) {\n throw new Error(\n \"a repeat node must not have a minimum iteration count that exceeds the maximum iteration count\"\n );\n }\n } else {\n // An incorrect number of iteration counts was defined.\n throw new Error(\"invalid number of repeat node iteration count arguments defined\");\n }\n }\n\n // Grab any node attribute definitions and spread them into the node definition.\n node = { ...node, ...parseAttributeTokens(tokens, stringLiteralPlaceholders) };\n\n // This is a decorator node, so we expect an opening '{'.\n popAndCheck(tokens, \"{\");\n\n // Return the repeat node definition.\n return node;\n}\n\n/**\n * Creates a retry node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The retry node JSON definition.\n */\nfunction createRetryNode(tokens: string[], stringLiteralPlaceholders: StringLiteralPlaceholders): RetryNodeDefinition {\n let node = { type: \"retry\" } as RetryNodeDefinition;\n\n // Get the node arguments.\n const nodeArguments = parseArgumentTokens(tokens, stringLiteralPlaceholders);\n\n // The arguments of a retry node are optional. We may have:\n // - No node arguments, in which case the retry note will attempt indefinitely.\n // - One node argument which will be the explicit number of attempts to make.\n // - Two node arguments which define the min and max attempt bounds from which a random attempt count will be picked.\n if (nodeArguments.length) {\n // All retry node arguments MUST be of type number and must be integer.\n nodeArguments\n .filter((arg) => arg.type !== \"number\" || !arg.isInteger)\n .forEach(() => {\n throw new Error(`retry node attempt counts must be integer values`);\n });\n\n // We should have got one or two attempt counts.\n if (nodeArguments.length === 1) {\n // A static attempt count was defined.\n node.attempts = nodeArguments[0].value as number;\n\n // A retry node must have a positive number of attempts if defined.\n if (node.attempts < 0) {\n throw new Error(\"a retry node must have a positive number of attempts if defined\");\n }\n } else if (nodeArguments.length === 2) {\n // A minimum and maximum attempt count was defined.\n node.attempts = [nodeArguments[0].value as number, nodeArguments[1].value as number];\n\n // A retry node must have a positive min and max attempts count if they are defined.\n if (node.attempts[0] < 0 || node.attempts[1] < 0) {\n throw new Error(\"a retry node must have a positive minimum and maximum attempt count if defined\");\n }\n\n // A retry node must not have a minimum attempt count that exceeds the maximum attempt count.\n if (node.attempts[0] > node.attempts[1]) {\n throw new Error(\n \"a retry node must not have a minimum attempt count that exceeds the maximum attempt count\"\n );\n }\n } else {\n // An incorrect number of attempt counts was defined.\n throw new Error(\"invalid number of retry node attempt count arguments defined\");\n }\n }\n\n // Grab any node attribute definitions and spread them into the node definition.\n node = { ...node, ...parseAttributeTokens(tokens, stringLiteralPlaceholders) };\n\n // This is a decorator node, so we expect an opening '{'.\n popAndCheck(tokens, \"{\");\n\n // Return the retry node definition.\n return node;\n}\n\n/**\n * Creates a sequence node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The sequence node JSON definition.\n */\nfunction createSequenceNode(\n tokens: string[],\n stringLiteralPlaceholders: StringLiteralPlaceholders\n): SequenceNodeDefinition {\n const node = {\n type: \"sequence\",\n ...parseAttributeTokens(tokens, stringLiteralPlaceholders)\n } as SequenceNodeDefinition;\n\n // This is a composite node, so we expect an opening '{'.\n popAndCheck(tokens, \"{\");\n\n // Return the sequence node definition.\n return node;\n}\n\n/**\n * Creates a selector node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The selector node JSON definition.\n */\nfunction createSelectorNode(\n tokens: string[],\n stringLiteralPlaceholders: StringLiteralPlaceholders\n): SelectorNodeDefinition {\n const node = {\n type: \"selector\",\n ...parseAttributeTokens(tokens, stringLiteralPlaceholders)\n } as SelectorNodeDefinition;\n\n // This is a composite node, so we expect an opening '{'.\n popAndCheck(tokens, \"{\");\n\n // Return the selector node definition.\n return node;\n}\n\n/**\n * Creates a parallel node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The parallel node JSON definition.\n */\nfunction createParallelNode(\n tokens: string[],\n stringLiteralPlaceholders: StringLiteralPlaceholders\n): ParallelNodeDefinition {\n const node = {\n type: \"parallel\",\n ...parseAttributeTokens(tokens, stringLiteralPlaceholders)\n } as ParallelNodeDefinition;\n\n // This is a composite node, so we expect an opening '{'.\n popAndCheck(tokens, \"{\");\n\n // Return the parallel node definition.\n return node;\n}\n\n/**\n * Creates a lotto node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The lotto node JSON definition.\n */\nfunction createLottoNode(tokens: string[], stringLiteralPlaceholders: StringLiteralPlaceholders): LottoNodeDefinition {\n // If any node arguments have been defined then they must be our weights.\n const nodeArguments = parseArgumentTokens(tokens, stringLiteralPlaceholders);\n\n // All lotto node arguments MUST be of type number and must be positive integers.\n nodeArguments\n .filter((arg) => arg.type !== \"number\" || !arg.isInteger || arg.value < 0)\n .forEach(() => {\n throw new Error(`lotto node weight arguments must be positive integer values`);\n });\n\n const node = {\n type: \"lotto\",\n weights: nodeArguments.length ? nodeArguments.map(({ value }) => value) : undefined,\n ...parseAttributeTokens(tokens, stringLiteralPlaceholders)\n } as LottoNodeDefinition;\n\n // This is a composite node, so we expect an opening '{'.\n popAndCheck(tokens, \"{\");\n\n // Return the lotto node definition.\n return node;\n}\n\n/**\n * Creates an action node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The action node JSON definition.\n */\nfunction createActionNode(\n tokens: string[],\n stringLiteralPlaceholders: StringLiteralPlaceholders\n): ActionNodeDefinition {\n // Parse any node arguments, we should have at least one which will be an identifier argument for the action name\n // and agent function to invoke for the action, all other arguments are to be passed as arguments to that function.\n const [actionNameIdentifier, ...agentFunctionArgs] = parseArgumentTokens(tokens, stringLiteralPlaceholders);\n\n // Our first argument MUST be defined and be an identifier as we require an action name argument.\n if (actionNameIdentifier?.type !== \"identifier\") {\n throw new Error(\"expected action name identifier argument\");\n }\n\n // Only the first argument should have been an identifier, all agent function arguments must be string, number, boolean or null.\n agentFunctionArgs\n .filter((arg) => arg.type === \"identifier\")\n .forEach((arg) => {\n throw new Error(\n `invalid action node argument value '${arg.value}', must be string, number, boolean or null`\n );\n });\n\n // Return the action node definition.\n return {\n type: \"action\",\n call: actionNameIdentifier.value,\n args: agentFunctionArgs.map(({ value }) => value),\n ...parseAttributeTokens(tokens, stringLiteralPlaceholders)\n };\n}\n\n/**\n * Creates a condition node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The condition node JSON definition.\n */\nfunction createConditionNode(\n tokens: string[],\n stringLiteralPlaceholders: StringLiteralPlaceholders\n): ConditionNodeDefinition {\n // Parse any node arguments, we should have at least one which will be an identifier argument for the condition name\n // and agent function to invoke for the condition, all other arguments are to be passed as arguments to that function.\n const [conditionNameIdentifier, ...agentFunctionArgs] = parseArgumentTokens(tokens, stringLiteralPlaceholders);\n\n // Our first argument MUST be defined and be an identifier as we require a condition name argument.\n if (conditionNameIdentifier?.type !== \"identifier\") {\n throw new Error(\"expected condition name identifier argument\");\n }\n\n // Only the first argument should have been an identifier, all agent function arguments must be string, number, boolean or null.\n agentFunctionArgs\n .filter((arg) => arg.type === \"identifier\")\n .forEach((arg) => {\n throw new Error(\n `invalid condition node argument value '${arg.value}', must be string, number, boolean or null`\n );\n });\n\n // Return the condition node definition.\n return {\n type: \"condition\",\n call: conditionNameIdentifier.value,\n args: agentFunctionArgs.map(({ value }) => value),\n ...parseAttributeTokens(tokens, stringLiteralPlaceholders)\n };\n}\n\n/**\n * Creates a wait node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The wait node JSON definition.\n */\nfunction createWaitNode(tokens: string[], stringLiteralPlaceholders: StringLiteralPlaceholders): WaitNodeDefinition {\n let node = { type: \"wait\" } as WaitNodeDefinition;\n\n // Get the node arguments.\n const nodeArguments = parseArgumentTokens(tokens, stringLiteralPlaceholders);\n\n // The arguments of a wait node are optional. We may have:\n // - No node arguments, in which case the wait will be indefinite until it is aborted.\n // - One node argument which will be the explicit duration of the wait.\n // - Two node arguments which define the min and max duration bounds from which a random duration will be picked.\n if (nodeArguments.length) {\n // All wait node arguments MUST be of type number and must be integer.\n nodeArguments\n .filter((arg) => arg.type !== \"number\" || !arg.isInteger)\n .forEach(() => {\n throw new Error(`wait node durations must be integer values`);\n });\n\n // We may have:\n // - One node argument which will be the explicit duration of the wait.\n // - Two node arguments which define the min and max duration bounds from which a random duration will be picked.\n // - Too many arguments, which is not valid.\n if (nodeArguments.length === 1) {\n // An explicit duration was defined.\n node.duration = nodeArguments[0].value as number;\n\n // If an explict duration was defined then it must be a positive number.\n if (node.duration < 0) {\n throw new Error(\"a wait node must have a positive duration\");\n }\n } else if (nodeArguments.length === 2) {\n // Min and max duration bounds were defined from which a random duration will be picked.\n node.duration = [nodeArguments[0].value as number, nodeArguments[1].value as number];\n\n // A wait node must have a positive min and max duration.\n if (node.duration[0] < 0 || node.duration[1] < 0) {\n throw new Error(\"a wait node must have a positive minimum and maximum duration\");\n }\n\n // A wait node must not have a minimum duration that exceeds the maximum duration.\n if (node.duration[0] > node.duration[1]) {\n throw new Error(\"a wait node must not have a minimum duration that exceeds the maximum duration\");\n }\n } else if (nodeArguments.length > 2) {\n // An incorrect number of duration arguments were defined.\n throw new Error(\"invalid number of wait node duration arguments defined\");\n }\n }\n\n // Return the wait node definition.\n return { ...node, ...parseAttributeTokens(tokens, stringLiteralPlaceholders) };\n}\n\n/**\n * Creates a branch node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The branch node JSON definition.\n */\nfunction createBranchNode(\n tokens: string[],\n stringLiteralPlaceholders: StringLiteralPlaceholders\n): BranchNodeDefinition {\n // Parse any node arguments, we should have one which will be an identifier argument for the root ref.\n const nodeArguments = parseArgumentTokens(tokens, stringLiteralPlaceholders);\n\n // We should have only a single identifer argument for a branch node, which is the root ref.\n if (nodeArguments.length !== 1 || nodeArguments[0].type !== \"identifier\") {\n throw new Error(\"expected single branch name argument\");\n }\n\n // Return the branch node definition.\n return { type: \"branch\", ref: nodeArguments[0].value };\n}\n\n/**\n * Validate a fully-populated node definition that was popped off of the tree stack.\n * @param definition The popped node to validate.\n */\nfunction validatePoppedNode(definition: AnyNodeDefinition): void {\n // Decorators MUST have a child defined.\n if (isDecoratorNode(definition) && isNullOrUndefined(definition.child)) {\n throw new Error(`a ${definition.type} node must have a single child node defined`);\n }\n\n // Composites MUST have at least one child defined.\n if (isCompositeNode(definition) && !definition.children?.length) {\n throw new Error(`a ${definition.type} node must have at least a single child node defined`);\n }\n\n // We need to make sure that lotto nodes that have weights defined have a number of weights matching the number of child nodes.\n if (definition.type === \"lotto\") {\n // Check whether a 'weights' property has been defined, if it has we expect it to be an array of weights.\n if (typeof definition.weights !== \"undefined\") {\n // Check that the weights property is an array of positive integers with an element for each child node element.\n if (definition.weights.length !== definition.children.length) {\n throw new Error(\n \"expected a number of weight arguments matching the number of child nodes for lotto node\"\n );\n }\n }\n }\n}\n", "import { RootNodeDefinition } from \"./BehaviourTreeDefinition\";\nimport { flattenDefinition, isBranchNode, isInteger } from \"./BehaviourTreeDefinitionUtilities\";\nimport { convertMDSLToJSON } from \"./mdsl/MDSLDefinitionParser\";\n\n/**\n * An object representing the result of validating a tree definition.\n */\nexport type DefinitionValidationResult = {\n /**\n * A flag defining whether validation succeeded.\n */\n succeeded: boolean;\n /**\n * A string containing the error message if validation did not succeed.\n */\n errorMessage?: string;\n /**\n * The definition as json if the validation was successful, or undefined if validation did not succeed.\n */\n json?: RootNodeDefinition[];\n};\n\n/**\n * Validates the specified behaviour tree definition in the form of JSON or MDSL, not taking any globally registered subtrees into consideration.\n * @param definition The behaviour tree definition in the form of JSON or MDSL.\n * @returns An object representing the result of validating the given tree definition.\n */\nexport function validateDefinition(definition: any): DefinitionValidationResult {\n // The definition must be defined.\n if (definition === null || typeof definition === \"undefined\") {\n return createValidationFailureResult(\"definition is null or undefined\");\n }\n\n // We are expecting a definition in one of three different forms:\n // - A string which we will assume is MDSL and we will parse this to JSON before validation.\n // - An array which we will assume is an array of root node definitions with at least one being the primary root node (no 'id' property)\n // - An object which we will assume is the primary root node and should not have an 'id' property.\n if (typeof definition === \"string\") {\n // The definition is a string which we can assume is MDSL, so attempt to validate it.\n return validateMDSLDefinition(definition);\n } else if (typeof definition === \"object\") {\n // The definition will either be an array (of root node definitions) or an object (the single primary root node definition).\n return validateJSONDefinition(definition);\n } else {\n return createValidationFailureResult(`unexpected definition type of '${typeof definition}'`);\n }\n}\n\n/**\n * Validates the specified behaviour tree definition in the form of MDSL.\n * @param definition The behaviour tree definition in the form of MDSL.\n * @returns An object representing the result of validating the given tree definition.\n */\nfunction validateMDSLDefinition(definition: string): DefinitionValidationResult {\n let rootNodeDefinitions;\n\n // The first thing the we need to do is to attempt to convert our MDSL into JSON.\n try {\n // The definition is a string which we can assume is MDSL, so attempt to parse it to a JSON definition in the form of an array of root node definitions.\n rootNodeDefinitions = convertMDSLToJSON(definition);\n } catch (exception) {\n // We failed to parse the JSON from the MDSL, this is likely to be the result of it not being a valid MDSL string.\n return createValidationFailureResult((exception as Error).message);\n }\n\n // Unpack all of the root node definitions into arrays of main ('id' defined) and sub ('id' not defined) root node definitions.\n const mainRootNodeDefinitions = rootNodeDefinitions.filter(({ id }) => typeof id === \"undefined\");\n const subRootNodeDefinitions = rootNodeDefinitions.filter(({ id }) => typeof id === \"string\" && id.length > 0);\n\n // We should ALWAYS have exactly one root node definition without an 'id' property defined, which is out main root node definition.\n if (mainRootNodeDefinitions.length !== 1) {\n return createValidationFailureResult(\n \"expected single unnamed root node at base of definition to act as main root\"\n );\n }\n\n // We should never have duplicate 'id' properties across our sub root node definitions.\n const subRootNodeIdenitifers: string[] = [];\n for (const { id } of subRootNodeDefinitions) {\n // Have we already come across this 'id' property value?\n if (subRootNodeIdenitifers.includes(id!)) {\n return createValidationFailureResult(`multiple root nodes found with duplicate name '${id}'`);\n }\n\n subRootNodeIdenitifers.push(id!);\n }\n\n try {\n // Validate our branch -> subtree links and check for any circular dependencies, we don't care about checking for broken subtree links here.\n validateBranchSubtreeLinks(rootNodeDefinitions, false);\n } catch (exception) {\n return createValidationFailureResult((exception as Error).message);\n }\n\n // Our definition was valid!\n return {\n succeeded: true,\n json: rootNodeDefinitions\n };\n}\n\n/**\n * Validates the specified behaviour tree definition in the form of JSON.\n * @param definition The behaviour tree definition in the form of JSON.\n * @returns An object representing the result of validating the given tree definition.\n */\nexport function validateJSONDefinition(\n definition: RootNodeDefinition | RootNodeDefinition[]\n): DefinitionValidationResult {\n // The definition will either be an array (of root node definitions) or an object (the single primary root node definition).\n const rootNodeDefinitions = Array.isArray(definition) ? definition : [definition];\n\n // Iterate over our array of root nodes and call validateNode for each, passing an initial depth of 0, wrapped in a try catch to handle validation failures.\n try {\n rootNodeDefinitions.forEach((rootNodeDefinition) => validateNode(rootNodeDefinition, 0));\n } catch (error) {\n // Handle cases where we have caught a thrown Error and return a failure result with the error message.\n if (error instanceof Error) {\n return createValidationFailureResult(error.message);\n }\n\n // No idea what happened here!\n return createValidationFailureResult(`unexpected error: ${error}`);\n }\n\n // Unpack all of the root node definitions into arrays of main ('id' defined) and sub ('id' not defined) root node definitions.\n const mainRootNodeDefinitions = rootNodeDefinitions.filter(({ id }) => typeof id === \"undefined\");\n const subRootNodeDefinitions = rootNodeDefinitions.filter(({ id }) => typeof id === \"string\" && id.length > 0);\n\n // We should ALWAYS have exactly one root node definition without an 'id' property defined, which is out main root node definition.\n if (mainRootNodeDefinitions.length !== 1) {\n return createValidationFailureResult(\n \"expected single root node without 'id' property defined to act as main root\"\n );\n }\n\n // We should never have duplicate 'id' properties across our sub root node definitions.\n const subRootNodeIdenitifers: string[] = [];\n for (const { id } of subRootNodeDefinitions) {\n // Have we already come across this 'id' property value?\n if (subRootNodeIdenitifers.includes(id!)) {\n return createValidationFailureResult(\n `multiple root nodes found with duplicate 'id' property value of '${id}'`\n );\n }\n\n subRootNodeIdenitifers.push(id!);\n }\n\n try {\n // Validate our branch -> subtree links and check for any circular dependencies, we don't care about checking for broken subtree links here.\n validateBranchSubtreeLinks(rootNodeDefinitions, false);\n } catch (exception) {\n return createValidationFailureResult((exception as Error).message);\n }\n\n // Our definition was valid!\n return {\n succeeded: true,\n json: rootNodeDefinitions\n };\n}\n\n/**\n * Validates the branch -> subtree links across all provided root node definitions.\n * This will not consider branch nodes that reference any globally registered subtrees unless includesGlobalSubtrees\n * is set to true, in which case we will also verify that there are no broken branch -> subtree links.\n * @param rootNodeDefinitions The array of root node definitions.\n * @param includesGlobalSubtrees A flag defining whether the array includes all global subtree root node definitions.\n */\nexport function validateBranchSubtreeLinks(rootNodeDefinitions: RootNodeDefinition[], includesGlobalSubtrees: boolean) {\n // Create a mapping of root node identifiers to other root nodes that they reference via branch nodes.\n // Below is an example of a mapping that includes a circular dependency (root => a => b => c => a)\n // [{ refs: [\"a\", \"b\"] }, { id: \"a\", refs: [\"b\"] }, { id: \"b\", refs: [\"c\"] }, { id: \"c\", refs: [\"a\"] }]\n const rootNodeMappings: { id: string | undefined; refs: string[] }[] = rootNodeDefinitions.map(\n (rootNodeDefinition) => ({\n id: rootNodeDefinition.id,\n refs: flattenDefinition(rootNodeDefinition)\n .filter(isBranchNode)\n .map(({ ref }) => ref)\n })\n );\n\n // A recursive function to walk through the mappings, keeping track of which root nodes we have visited in the form of a path of root node identifiers.\n const followRefs = (mapping: { id: string | undefined; refs: string[] }, path: (string | undefined)[] = []) => {\n // Have we found a circular dependency?\n if (path.includes(mapping.id)) {\n // We found a circular dependency! Get the bad path of root node identifiers.\n const badPath = [...path, mapping.id];\n\n // Create the formatted path value. [undefined, \"a\", \"b\", \"c\", \"a\"] would be formatted as \"a -> b -> c -> a\".\n const badPathFormatted = badPath.filter((element) => !!element).join(\" => \");\n\n // No need to continue, we found a circular dependency.\n throw new Error(`circular dependency found in branch node references: ${badPathFormatted}`);\n }\n\n for (const ref of mapping.refs) {\n // Find the mapping for the root node with an identifer matching the current ref.\n const subMapping = rootNodeMappings.find(({ id }) => id === ref);\n\n // We may not have a mapping for this ref, which is normal when we aren't considering all globally registered subtrees.\n if (subMapping) {\n followRefs(subMapping, [...path, mapping.id]);\n } else if (includesGlobalSubtrees) {\n // We found a reference to a root node that doesn't exist, which is a problem seeing as the root node definitons includes all globally registered subtrees.\n throw new Error(\n mapping.id\n ? `subtree '${mapping.id}' has branch node that references root node '${ref}' which has not been defined`\n : `primary tree has branch node that references root node '${ref}' which has not been defined`\n );\n }\n }\n };\n\n // Start looking for circular dependencies and broken references from the primary root node definition.\n followRefs(rootNodeMappings.find((mapping) => typeof mapping.id === \"undefined\")!);\n}\n\n/**\n * Validate an object that we expect to be a node definition.\n * @param definition An object that we expect to be a node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateNode(definition: any, depth: number): void {\n // Every node must be valid object and have a non-empty 'type' string property.\n if (typeof definition !== \"object\" || typeof definition.type !== \"string\" || definition.type.length === 0) {\n throw new Error(\n `node definition is not an object or 'type' property is not a non-empty string at depth '${depth}'`\n );\n }\n\n // How we validate this node definition will depend on its type.\n switch (definition.type) {\n case \"action\":\n validateActionNode(definition, depth);\n break;\n\n case \"condition\":\n validateConditionNode(definition, depth);\n break;\n\n case \"wait\":\n validateWaitNode(definition, depth);\n break;\n\n case \"branch\":\n validateBranchNode(definition, depth);\n break;\n\n case \"root\":\n validateRootNode(definition, depth);\n break;\n\n case \"succeed\":\n validateSucceedNode(definition, depth);\n break;\n\n case \"fail\":\n validateFailNode(definition, depth);\n break;\n\n case \"flip\":\n validateFlipNode(definition, depth);\n break;\n\n case \"repeat\":\n validateRepeatNode(definition, depth);\n break;\n\n case \"retry\":\n validateRetryNode(definition, depth);\n break;\n\n case \"sequence\":\n validateSequenceNode(definition, depth);\n break;\n\n case \"selector\":\n validateSelectorNode(definition, depth);\n break;\n\n case \"parallel\":\n validateParallelNode(definition, depth);\n break;\n\n case \"lotto\":\n validateLottoNode(definition, depth);\n break;\n\n default:\n throw new Error(`unexpected node type of '${definition.type}' at depth '${depth}'`);\n }\n}\n\n/**\n * Validate any attributes for a given node definition.\n * @param definition The node definition.\n * @param depth The depth of the node in the behaviour tree definition.\n */\nfunction validateNodeAttributes(definition: any, depth: number): void {\n // Validate each of the attribute types for this node.\n [\"while\", \"until\", \"entry\", \"exit\", \"step\"].forEach((attributeName) => {\n // Attempt to grab the definition for the current attribute from the node definition.\n const attributeDefinition = definition[attributeName];\n\n // All node attributes are optional, so there is nothing to do if the current attribute is not defined.\n if (typeof attributeDefinition === \"undefined\") {\n return;\n }\n\n // The attribute definition must be an object.\n if (typeof attributeDefinition !== \"object\") {\n throw new Error(\n `expected attribute '${attributeName}' to be an object for '${definition.type}' node at depth '${depth}'`\n );\n }\n\n // The 'call' property must be defined for any attribute definition.\n if (typeof attributeDefinition.call !== \"string\" || attributeDefinition.call.length === 0) {\n throw new Error(\n `expected 'call' property for attribute '${attributeName}' to be a non-empty string for '${definition.type}' node at depth '${depth}'`\n );\n }\n\n // If any node attribute arguments have been defined then they must have been defined in an array.\n if (typeof attributeDefinition.args !== \"undefined\" && !Array.isArray(attributeDefinition.args)) {\n throw new Error(\n `expected 'args' property for attribute '${attributeName}' to be an array for '${definition.type}' node at depth '${depth}'`\n );\n }\n });\n}\n\n/**\n * Validate an object that we expect to be a root node definition.\n * @param definition An object that we expect to be a root node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateRootNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"root\") {\n throw new Error(\"expected node type of 'root' for root node\");\n }\n\n // A root node cannot be the child of another node.\n if (depth > 0) {\n throw new Error(\"a root node cannot be the child of another node\");\n }\n\n // Check that, if the root node 'id' property is defined, it is a non-empty string.\n if (typeof definition.id !== \"undefined\" && (typeof definition.id !== \"string\" || definition.id.length === 0)) {\n throw new Error(\"expected non-empty string for 'id' property if defined for root node\");\n }\n\n // A root node is a decorator node, so must have a child node defined.\n if (typeof definition.child === \"undefined\") {\n throw new Error(\"expected property 'child' to be defined for root node\");\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n\n // Validate the child node of this decorator node.\n validateNode(definition.child, depth + 1);\n}\n\n/**\n * Validate an object that we expect to be a succeed node definition.\n * @param definition An object that we expect to be a succeed node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateSucceedNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"succeed\") {\n throw new Error(`expected node type of 'succeed' for succeed node at depth '${depth}'`);\n }\n\n // A succeed node is a decorator node, so must have a child node defined.\n if (typeof definition.child === \"undefined\") {\n throw new Error(`expected property 'child' to be defined for succeed node at depth '${depth}'`);\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n\n // Validate the child node of this decorator node.\n validateNode(definition.child, depth + 1);\n}\n\n/**\n * Validate an object that we expect to be a fail node definition.\n * @param definition An object that we expect to be a fail node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateFailNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"fail\") {\n throw new Error(`expected node type of 'fail' for fail node at depth '${depth}'`);\n }\n\n // A fail node is a decorator node, so must have a child node defined.\n if (typeof definition.child === \"undefined\") {\n throw new Error(`expected property 'child' to be defined for fail node at depth '${depth}'`);\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n\n // Validate the child node of this decorator node.\n validateNode(definition.child, depth + 1);\n}\n\n/**\n * Validate an object that we expect to be a flip node definition.\n * @param definition An object that we expect to be a flip node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateFlipNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"flip\") {\n throw new Error(`expected node type of 'flip' for flip node at depth '${depth}'`);\n }\n\n // A flip node is a decorator node, so must have a child node defined.\n if (typeof definition.child === \"undefined\") {\n throw new Error(`expected property 'child' to be defined for flip node at depth '${depth}'`);\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n\n // Validate the child node of this decorator node.\n validateNode(definition.child, depth + 1);\n}\n\n/**\n * Validate an object that we expect to be a repeat node definition.\n * @param definition An object that we expect to be a repeat node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateRepeatNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"repeat\") {\n throw new Error(`expected node type of 'repeat' for repeat node at depth '${depth}'`);\n }\n\n // A repeat node is a decorator node, so must have a child node defined.\n if (typeof definition.child === \"undefined\") {\n throw new Error(`expected property 'child' to be defined for repeat node at depth '${depth}'`);\n }\n\n // Check whether an 'iterations' property has been defined, it may not have been if this node is to repeat indefinitely.\n if (typeof definition.iterations !== \"undefined\") {\n if (Array.isArray(definition.iterations)) {\n // Check whether any elements of the array are not integer values.\n const containsNonInteger = !!definition.iterations.filter((value: unknown) => !isInteger(value)).length;\n\n // If the 'iterations' property is an array then it MUST contain two integer values.\n if (definition.iterations.length !== 2 || containsNonInteger) {\n throw new Error(\n `expected array containing two integer values for 'iterations' property if defined for repeat node at depth '${depth}'`\n );\n }\n\n // A repeat node must have a positive min and max iterations count if they are defined.\n if (definition.iterations[0] < 0 || definition.iterations[1] < 0) {\n throw new Error(\n `expected positive minimum and maximum iterations count for 'iterations' property if defined for repeat node at depth '${depth}'`\n );\n }\n\n // A repeat node must not have a minimum iterations count that exceeds the maximum iterations count.\n if (definition.iterations[0] > definition.iterations[1]) {\n throw new Error(\n `expected minimum iterations count that does not exceed the maximum iterations count for 'iterations' property if defined for repeat node at depth '${depth}'`\n );\n }\n } else if (isInteger(definition.iterations)) {\n // A repeat node must have a positive number of iterations if defined.\n if (definition.iterations < 0) {\n throw new Error(\n `expected positive iterations count for 'iterations' property if defined for repeat node at depth '${depth}'`\n );\n }\n } else {\n throw new Error(\n `expected integer value or array containing two integer values for 'iterations' property if defined for repeat node at depth '${depth}'`\n );\n }\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n\n // Validate the child node of this decorator node.\n validateNode(definition.child, depth + 1);\n}\n\n/**\n * Validate an object that we expect to be a retry node definition.\n * @param definition An object that we expect to be a retry node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateRetryNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"retry\") {\n throw new Error(`expected node type of 'retry' for retry node at depth '${depth}'`);\n }\n\n // A retry node is a decorator node, so must have a child node defined.\n if (typeof definition.child === \"undefined\") {\n throw new Error(`expected property 'child' to be defined for retry node at depth '${depth}'`);\n }\n\n // Check whether an 'attempts' property has been defined, it may not have been if this node is to retry indefinitely.\n if (typeof definition.attempts !== \"undefined\") {\n if (Array.isArray(definition.attempts)) {\n // Check whether any elements of the array are not integer values.\n const containsNonInteger = !!definition.attempts.filter((value: unknown) => !isInteger(value)).length;\n\n // If the 'attempts' property is an array then it MUST contain two integer values.\n if (definition.attempts.length !== 2 || containsNonInteger) {\n throw new Error(\n `expected array containing two integer values for 'attempts' property if defined for retry node at depth '${depth}'`\n );\n }\n\n // A retry node must have a positive min and max attempts count if they are defined.\n if (definition.attempts[0] < 0 || definition.attempts[1] < 0) {\n throw new Error(\n `expected positive minimum and maximum attempts count for 'attempts' property if defined for retry node at depth '${depth}'`\n );\n }\n\n // A retry node must not have a minimum attempts count that exceeds the maximum attempts count.\n if (definition.attempts[0] > definition.attempts[1]) {\n throw new Error(\n `expected minimum attempts count that does not exceed the maximum attempts count for 'attempts' property if defined for retry node at depth '${depth}'`\n );\n }\n } else if (isInteger(definition.attempts)) {\n // A retry node must have a positive number of attempts if defined.\n if (definition.attempts < 0) {\n throw new Error(\n `expected positive attempts count for 'attempts' property if defined for retry node at depth '${depth}'`\n );\n }\n } else {\n throw new Error(\n `expected integer value or array containing two integer values for 'attempts' property if defined for retry node at depth '${depth}'`\n );\n }\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n\n // Validate the child node of this decorator node.\n validateNode(definition.child, depth + 1);\n}\n\n/**\n * Validate an object that we expect to be a branch node definition.\n * @param definition An object that we expect to be a branch node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateBranchNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"branch\") {\n throw new Error(`expected node type of 'branch' for branch node at depth '${depth}'`);\n }\n\n // Check that the branch node 'ref' property is defined and is a non-empty string.\n if (typeof definition.ref !== \"string\" || definition.ref.length === 0) {\n throw new Error(`expected non-empty string for 'ref' property for branch node at depth '${depth}'`);\n }\n\n // It is invalid to define guard attributes for a branch node as they should be defined on the referenced root node.\n [\"while\", \"until\"].forEach((attributeName) => {\n if (typeof definition[attributeName] !== \"undefined\") {\n throw new Error(\n `guards should not be defined for branch nodes but guard '${attributeName}' was defined for branch node at depth '${depth}'`\n );\n }\n });\n\n // It is invalid to define callback attributes for a branch node as they should be defined on the referenced root node.\n [\"entry\", \"exit\", \"step\"].forEach((attributeName) => {\n if (typeof definition[attributeName] !== \"undefined\") {\n throw new Error(\n `callbacks should not be defined for branch nodes but callback '${attributeName}' was defined for branch node at depth '${depth}'`\n );\n }\n });\n}\n\n/**\n * Validate an object that we expect to be a action node definition.\n * @param definition An object that we expect to be a action node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateActionNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"action\") {\n throw new Error(`expected node type of 'action' for action node at depth '${depth}'`);\n }\n\n // The 'call' property must be defined for a action node definition.\n if (typeof definition.call !== \"string\" || definition.call.length === 0) {\n throw new Error(`expected non-empty string for 'call' property of action node at depth '${depth}'`);\n }\n\n // If any action function arguments have been defined then they must have been defined in an array.\n if (typeof definition.args !== \"undefined\" && !Array.isArray(definition.args)) {\n throw new Error(`expected array for 'args' property if defined for action node at depth '${depth}'`);\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n}\n\n/**\n * Validate an object that we expect to be a condition node definition.\n * @param definition An object that we expect to be a condition node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateConditionNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"condition\") {\n throw new Error(`expected node type of 'condition' for condition node at depth '${depth}'`);\n }\n\n // The 'call' property must be defined for a condition node definition.\n if (typeof definition.call !== \"string\" || definition.call.length === 0) {\n throw new Error(`expected non-empty string for 'call' property of condition node at depth '${depth}'`);\n }\n\n // If any condition function arguments have been defined then they must have been defined in an array.\n if (typeof definition.args !== \"undefined\" && !Array.isArray(definition.args)) {\n throw new Error(`expected array for 'args' property if defined for condition node at depth '${depth}'`);\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n}\n\n/**\n * Validate an object that we expect to be a wait node definition.\n * @param definition An object that we expect to be a wait node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateWaitNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"wait\") {\n throw new Error(`expected node type of 'wait' for wait node at depth '${depth}'`);\n }\n\n // Check whether a 'duration' property has been defined, it may not have been if this node is to wait indefinitely.\n if (typeof definition.duration !== \"undefined\") {\n if (Array.isArray(definition.duration)) {\n // Check whether any elements of the array are not integer values.\n const containsNonInteger = !!definition.duration.filter((value: unknown) => !isInteger(value)).length;\n\n // If the 'duration' property is an array then it MUST contain two integer values.\n if (definition.duration.length !== 2 || containsNonInteger) {\n throw new Error(\n `expected array containing two integer values for 'duration' property if defined for wait node at depth '${depth}'`\n );\n }\n\n // A wait node must have a positive min and max duration value if they are defined.\n if (definition.duration[0] < 0 || definition.duration[1] < 0) {\n throw new Error(\n `expected positive minimum and maximum duration for 'duration' property if defined for wait node at depth '${depth}'`\n );\n }\n\n // A wait node must not have a minimum duration value that exceeds the maximum duration value.\n if (definition.duration[0] > definition.duration[1]) {\n throw new Error(\n `expected minimum duration value that does not exceed the maximum duration value for 'duration' property if defined for wait node at depth '${depth}'`\n );\n }\n } else if (isInteger(definition.duration)) {\n // A wait node must have a positive duration value if defined.\n if (definition.duration < 0) {\n throw new Error(\n `expected positive duration value for 'duration' property if defined for wait node at depth '${depth}'`\n );\n }\n } else {\n throw new Error(\n `expected integer value or array containing two integer values for 'duration' property if defined for wait node at depth '${depth}'`\n );\n }\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n}\n\n/**\n * Validate an object that we expect to be a sequence node definition.\n * @param definition An object that we expect to be a sequence node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateSequenceNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"sequence\") {\n throw new Error(`expected node type of 'sequence' for sequence node at depth '${depth}'`);\n }\n\n // A sequence node is a composite node, so must have a children nodes array defined.\n if (!Array.isArray(definition.children) || definition.children.length === 0) {\n throw new Error(`expected non-empty 'children' array to be defined for sequence node at depth '${depth}'`);\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n\n // Validate the child nodes of this composite node.\n definition.children.forEach((child: any) => validateNode(child, depth + 1));\n}\n\n/**\n * Validate an object that we expect to be a selector node definition.\n * @param definition An object that we expect to be a selector node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateSelectorNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"selector\") {\n throw new Error(`expected node type of 'selector' for selector node at depth '${depth}'`);\n }\n\n // A selector node is a composite node, so must have a children nodes array defined.\n if (!Array.isArray(definition.children) || definition.children.length === 0) {\n throw new Error(`expected non-empty 'children' array to be defined for selector node at depth '${depth}'`);\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n\n // Validate the child nodes of this composite node.\n definition.children.forEach((child: any) => validateNode(child, depth + 1));\n}\n\n/**\n * Validate an object that we expect to be a parallel node definition.\n * @param definition An object that we expect to be a parallel node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateParallelNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"parallel\") {\n throw new Error(`expected node type of 'parallel' for parallel node at depth '${depth}'`);\n }\n\n // A parallel node is a composite node, so must have a children nodes array defined.\n if (!Array.isArray(definition.children) || definition.children.length === 0) {\n throw new Error(`expected non-empty 'children' array to be defined for parallel node at depth '${depth}'`);\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n\n // Validate the child nodes of this composite node.\n definition.children.forEach((child: any) => validateNode(child, depth + 1));\n}\n\n/**\n * Validate an object that we expect to be a lotto node definition.\n * @param definition An object that we expect to be a lotto node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateLottoNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"lotto\") {\n throw new Error(`expected node type of 'lotto' for lotto node at depth '${depth}'`);\n }\n\n // A lotto node is a composite node, so must have a children nodes array defined.\n if (!Array.isArray(definition.children) || definition.children.length === 0) {\n throw new Error(`expected non-empty 'children' array to be defined for lotto node at depth '${depth}'`);\n }\n\n // Check whether a 'weights' property has been defined, if it has we expect it to be an array of weights.\n if (typeof definition.weights !== \"undefined\") {\n // Check that the weights property is an array of positive integers with an element for each child node element.\n if (\n !Array.isArray(definition.weights) ||\n definition.weights.length !== definition.children.length ||\n definition.weights.filter((value: unknown) => !isInteger(value)).length ||\n definition.weights.filter((value: number) => value < 0).length\n ) {\n throw new Error(\n `expected an array of positive integer weight values with a length matching the number of child nodes for 'weights' property if defined for lotto node at depth '${depth}'`\n );\n }\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n\n // Validate the child nodes of this composite node.\n definition.children.forEach((child: any) => validateNode(child, depth + 1));\n}\n\n/**\n * A helper function to create a failure validation result with the given error message.\n * @param errorMessage The validation failure error message.\n * @returns A failure validation result with the given error message.\n */\nfunction createValidationFailureResult(errorMessage: string): DefinitionValidationResult {\n return { succeeded: false, errorMessage };\n}\n", "import { ActionResult, Agent, GlobalFunction } from \"./Agent\";\nimport { RootNodeDefinition } from \"./BehaviourTreeDefinition\";\n\nexport type InvokerFunction = (args: any[]) => ActionResult;\n\n/**\n * A singleton used to store and lookup registered functions and subtrees.\n */\nexport default class Lookup {\n /**\n * The object holding any registered functions keyed on function name.\n */\n private static functionTable: { [key: string]: GlobalFunction } = {};\n /**\n * The object holding any registered subtree root node definitions keyed on tree name.\n */\n private static subtreeTable: { [key: string]: RootNodeDefinition } = {};\n\n /**\n * Gets the function with the specified name.\n * @param name The name of the function.\n * @returns The function with the specified name.\n */\n public static getFunc(name: string): GlobalFunction {\n return this.functionTable[name];\n }\n\n /**\n * Sets the function with the specified name for later lookup.\n * @param name The name of the function.\n * @param func The function.\n */\n public static setFunc(name: string, func: GlobalFunction): void {\n this.functionTable[name] = func;\n }\n\n /**\n * Gets the function invoker for the specified agent and function name.\n * If a function with the specified name exists on the agent object then it will\n * be returned, otherwise we will then check the registered functions for a match.\n * @param agent The agent instance that this behaviour tree is modelling behaviour for.\n * @param name The function name.\n * @returns The function invoker for the specified agent and function name.\n */\n static getFuncInvoker(agent: Agent, name: string): InvokerFunction | null {\n // Check whether the agent contains the specified function.\n const foundOnAgent = agent[name];\n if (foundOnAgent && typeof foundOnAgent === \"function\") {\n return (args: any[]): boolean | ActionResult => foundOnAgent.apply(agent, args);\n }\n\n // The agent does not contain the specified function but it may have been registered at some point.\n if (this.functionTable[name] && typeof this.functionTable[name] === \"function\") {\n return (args: any[]) => this.functionTable[name](agent, ...args.map((arg) => arg.value));\n }\n\n // We have no function to invoke.\n return null;\n }\n\n /**\n * Gets all registered subtree root node definitions.\n */\n static getSubtrees(): { [key: string]: RootNodeDefinition } {\n return this.subtreeTable;\n }\n\n /**\n * Sets the subtree with the specified name for later lookup.\n * @param name The name of the subtree.\n * @param subtree The subtree.\n */\n static setSubtree(name: string, subtree: RootNodeDefinition) {\n this.subtreeTable[name] = subtree;\n }\n\n /**\n * Removes the registered function or subtree with the specified name.\n * @param name The name of the registered function or subtree.\n */\n static remove(name: string) {\n delete this.functionTable[name];\n delete this.subtreeTable[name];\n }\n\n /**\n * Remove all registered functions and subtrees.\n */\n static empty() {\n this.functionTable = {};\n this.subtreeTable = {};\n }\n}\n", "import Node from \"../../nodes/Node\";\n\n/**\n * An exception thrown when evaluating node guard path conditions and a conditions fails.\n */\nexport default class GuardUnsatisifedException extends Error {\n /**\n * @param source The node at which a guard condition failed.\n */\n constructor(private source: Node) {\n super(\"A guard path condition has failed\");\n }\n\n /**\n * Gets whether the specified node is the node at which a guard condition failed.\n * @param node The node to check against the source node.\n * @returns Whether the specified node is the node at which a guard condition failed.\n */\n isSourceNode = (node: Node) => node === this.source;\n}\n", "import { Agent } from \"../../Agent\";\nimport Guard from \"./Guard\";\nimport Node from \"../../nodes/Node\";\nimport GuardUnsatisifedException from \"./GuardUnsatisifedException\";\n\nexport type GuardPathPart = {\n node: Node;\n guards: Guard[];\n};\n\n/**\n * Represents a path of node guards along a root-to-leaf tree path.\n */\nexport default class GuardPath {\n /**\n * @param nodes An array of objects defining a node instance -> guard link, ordered by node depth.\n */\n constructor(private nodes: GuardPathPart[]) {}\n\n /**\n * Evaluate guard conditions for all guards in the tree path, moving outwards from the root.\n * @param agent The agent, required for guard evaluation.\n * @returns An evaluation results object.\n */\n evaluate = (agent: Agent) => {\n // We need to evaluate guard conditions for nodes up the tree, moving outwards from the root.\n for (const details of this.nodes) {\n // There can be multiple guards per node.\n for (const guard of details.guards) {\n // Check whether the guard condition passes, and throw an exception if not.\n if (!guard.isSatisfied(agent)) {\n throw new GuardUnsatisifedException(details.node);\n }\n }\n }\n };\n}\n", "import { BehaviourTreeOptions } from \"../BehaviourTreeOptions\";\nimport State, { AnyState } from \"../State\";\nimport { Agent } from \"../Agent\";\nimport Leaf from \"./leaf/Leaf\";\nimport Attribute from \"../attributes/Attribute\";\nimport Entry from \"../attributes/callbacks/Entry\";\nimport Exit from \"../attributes/callbacks/Exit\";\nimport Step from \"../attributes/callbacks/Step\";\nimport Guard from \"../attributes/guards/Guard\";\nimport GuardPath from \"../attributes/guards/GuardPath\";\nimport GuardUnsatisifedException from \"../attributes/guards/GuardUnsatisifedException\";\n\n/**\n * A base node.\n */\nexport default abstract class Node {\n /**\n * The node uid.\n */\n private readonly uid: string = createNodeUid();\n /**\n * The node state.\n */\n private state: AnyState = State.READY;\n /**\n * The guard path to evaluate as part of a node update.\n */\n private guardPath: GuardPath | undefined;\n\n /**\n * @param type The node type.\n * @param attributes The node attributes.\n * @param args The node argument definitions.\n */\n constructor(private type: string, private attributes: Attribute[], private args: any[]) {}\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected abstract onUpdate(agent: Agent, options: BehaviourTreeOptions): void;\n\n /**\n * Gets the name of the node.\n */\n public abstract getName(): string;\n\n /**\n * Gets whether this node is a leaf node.\n */\n public abstract isLeafNode: () => this is Leaf;\n\n /**\n * Gets/Sets the state of the node.\n */\n getState = (): AnyState => this.state;\n setState = (value: AnyState): void => {\n this.state = value;\n };\n\n /**\n * Gets the unique id of the node.\n */\n getUid = () => this.uid;\n\n /**\n * Gets the type of the node.\n */\n getType = () => this.type;\n\n /**\n * Gets the node attributes.\n */\n getAttributes = () => this.attributes;\n\n /**\n * Gets the node arguments.\n */\n getArguments = () => this.args;\n\n /**\n * Gets the node attribute with the specified type, or null if it does not exist.\n */\n getAttribute(type: \"entry\" | \"ENTRY\"): Entry;\n getAttribute(type: \"exit\" | \"EXIT\"): Exit;\n getAttribute(type: \"step\" | \"STEP\"): Step;\n getAttribute(type: string): Attribute {\n return (\n this.getAttributes().filter((decorator) => decorator.type.toUpperCase() === type.toUpperCase())[0] || null\n );\n }\n\n /**\n * Gets the node attributes.\n */\n getGuardAttributes = (): Guard[] => this.getAttributes().filter((decorator) => decorator.isGuard()) as Guard[];\n\n /**\n * Sets the guard path to evaluate as part of a node update.\n */\n setGuardPath = (value: GuardPath) => (this.guardPath = value);\n\n /**\n * Gets whether a guard path is assigned to this node.\n */\n hasGuardPath = () => !!this.guardPath;\n\n /**\n * Gets whether this node is in the specified state.\n * @param value The value to compare to the node state.\n */\n public is(value: AnyState): boolean {\n return this.state === value;\n }\n\n /**\n * Reset the state of the node.\n */\n public reset(): void {\n this.setState(State.READY);\n }\n\n /**\n * Abort the running of this node.\n * @param agent The agent.\n */\n public abort(agent: Agent): void {\n // There is nothing to do if this node is not in the running state.\n if (!this.is(State.RUNNING)) {\n return;\n }\n\n // Reset the state of this node.\n this.reset();\n\n this.getAttribute(\"exit\")?.callAgentFunction(agent, false, true);\n }\n\n /**\n * Update the node.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n * @returns The result of the update.\n */\n public update(agent: Agent, options: BehaviourTreeOptions): void {\n // If this node is already in a 'SUCCEEDED' or 'FAILED' state then there is nothing to do.\n if (this.is(State.SUCCEEDED) || this.is(State.FAILED)) {\n return;\n }\n\n try {\n // Evaluate all of the guard path conditions for the current tree path.\n this.guardPath!.evaluate(agent);\n\n // If this node is in the READY state then call the ENTRY for this node if it exists.\n if (this.is(State.READY)) {\n this.getAttribute(\"entry\")?.callAgentFunction(agent);\n }\n\n this.getAttribute(\"step\")?.callAgentFunction(agent);\n\n // Do the actual update.\n this.onUpdate(agent, options);\n\n // If this node is now in a 'SUCCEEDED' or 'FAILED' state then call the EXIT for this node if it exists.\n if (this.is(State.SUCCEEDED) || this.is(State.FAILED)) {\n this.getAttribute(\"exit\")?.callAgentFunction(agent, this.is(State.SUCCEEDED), false);\n }\n } catch (error) {\n // If the error is a GuardUnsatisfiedException then we need to determine if this node is the source.\n if (error instanceof GuardUnsatisifedException && error.isSourceNode(this)) {\n // Abort the current node.\n this.abort(agent);\n\n // Any node that is the source of an abort will be a failed node.\n this.setState(State.FAILED);\n } else {\n throw error;\n }\n }\n }\n}\n\n/**\n * Create a randomly generated node uid.\n * @returns A randomly generated node uid.\n */\nfunction createNodeUid(): string {\n var S4 = function () {\n return (((1 + Math.random()) * 0x10000) | 0).toString(16).substring(1);\n };\n return S4() + S4() + \"-\" + S4() + \"-\" + S4() + \"-\" + S4() + \"-\" + S4() + S4() + S4();\n}\n", "import Node from \"../Node\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\n\n/**\n * A composite node that wraps child nodes.\n */\nexport default abstract class Composite extends Node {\n /**\n * @param type The node type.\n * @param attributes The node attributes.\n * @param children The child nodes.\n */\n constructor(type: string, attributes: Attribute[], protected children: Node[]) {\n super(type, attributes, []);\n }\n\n /**\n * Gets whether this node is a leaf node.\n */\n isLeafNode = () => false;\n\n /**\n * Gets the children of this node.\n */\n getChildren = () => this.children;\n\n /**\n * Reset the state of the node.\n */\n reset = () => {\n // Reset the state of this node.\n this.setState(State.READY);\n\n // Reset the state of any child nodes.\n this.getChildren().forEach((child) => child.reset());\n };\n\n /**\n * Abort the running of this node.\n * @param agent The agent.\n */\n abort = (agent: Agent) => {\n // There is nothing to do if this node is not in the running state.\n if (!this.is(State.RUNNING)) {\n return;\n }\n\n // Abort any child nodes.\n this.getChildren().forEach((child) => child.abort(agent));\n\n // Reset the state of this node.\n this.reset();\n\n this.getAttribute(\"exit\")?.callAgentFunction(agent, false, true);\n };\n}\n", "import Composite from \"./Composite\";\nimport State from \"../../State\";\nimport Node from \"../Node\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A PARALLEL node.\n * The child nodes are executed concurrently until one fails or all succeed.\n */\nexport default class Parallel extends Composite {\n /**\n * @param attributes The node attributes.\n * @param children The child nodes.\n */\n constructor(attributes: Attribute[], children: Node[]) {\n super(\"parallel\", attributes, children);\n }\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // Keep a count of the number of succeeded child nodes.\n let succeededCount = 0;\n\n let hasChildFailed = false;\n\n // Iterate over all of the children of this node.\n for (const child of this.children) {\n // If the child has never been updated or is running then we will need to update it now.\n if (child.getState() === State.READY || child.getState() === State.RUNNING) {\n // Update the child of this node.\n child.update(agent, options);\n }\n\n // If the current child has a state of 'SUCCEEDED' then we should move on to the next child.\n if (child.getState() === State.SUCCEEDED) {\n // The child node has succeeded, keep track of this to determine if all children have.\n succeededCount++;\n\n // The child node succeeded, but we have not finished checking every child node yet.\n continue;\n }\n\n // If the current child has a state of 'FAILED' then this node is also a 'FAILED' node.\n if (child.getState() === State.FAILED) {\n hasChildFailed = true;\n\n // There is no need to check the rest of the children.\n break;\n }\n\n // The node should be in the 'RUNNING' state.\n if (child.getState() !== State.RUNNING) {\n // The child node was not in an expected state.\n throw new Error(\"child node was not in an expected state.\");\n }\n }\n\n if (hasChildFailed) {\n // This node is a 'FAILED' node.\n this.setState(State.FAILED);\n\n // Abort every running child.\n for (const child of this.children) {\n if (child.getState() === State.RUNNING) {\n child.abort(agent);\n }\n }\n } else {\n // If all children have succeeded then this node has also succeeded, otherwise it is still running.\n this.setState(succeededCount === this.children.length ? State.SUCCEEDED : State.RUNNING);\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => \"PARALLEL\";\n}\n", "import Composite from \"./Composite\";\nimport Node from \"../Node\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A SELECTOR node.\n * The child nodes are executed in sequence until one succeeds or all fail.\n */\nexport default class Selector extends Composite {\n /**\n * @param attributes The node attributes.\n * @param children The child nodes.\n */\n constructor(attributes: Attribute[], protected children: Node[]) {\n super(\"selector\", attributes, children);\n }\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // Iterate over all of the children of this node.\n for (const child of this.children) {\n // If the child has never been updated or is running then we will need to update it now.\n if (child.getState() === State.READY || child.getState() === State.RUNNING) {\n // Update the child of this node.\n child.update(agent, options);\n }\n\n // If the current child has a state of 'SUCCEEDED' then this node is also a 'SUCCEEDED' node.\n if (child.getState() === State.SUCCEEDED) {\n // This node is a 'SUCCEEDED' node.\n this.setState(State.SUCCEEDED);\n\n // There is no need to check the rest of the selector nodes.\n return;\n }\n\n // If the current child has a state of 'FAILED' then we should move on to the next child.\n if (child.getState() === State.FAILED) {\n // Find out if the current child is the last one in the selector.\n // If it is then this sequence node has also failed.\n if (this.children.indexOf(child) === this.children.length - 1) {\n // This node is a 'FAILED' node.\n this.setState(State.FAILED);\n\n // There is no need to check the rest of the selector as we have completed it.\n return;\n } else {\n // The child node failed, try the next one.\n continue;\n }\n }\n\n // The node should be in the 'RUNNING' state.\n if (child.getState() === State.RUNNING) {\n // This node is a 'RUNNING' node.\n this.setState(State.RUNNING);\n\n // There is no need to check the rest of the selector as the current child is still running.\n return;\n }\n\n // The child node was not in an expected state.\n throw new Error(\"child node was not in an expected state.\");\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => \"SELECTOR\";\n}\n", "import Composite from \"./Composite\";\nimport Node from \"../Node\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A SEQUENCE node.\n * The child nodes are executed in sequence until one fails or all succeed.\n */\nexport default class Sequence extends Composite {\n /**\n * @param attributes The node attributes.\n * @param children The child nodes.\n */\n constructor(attributes: Attribute[], protected children: Node[]) {\n super(\"sequence\", attributes, children);\n }\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // Iterate over all of the children of this node.\n for (const child of this.children) {\n // If the child has never been updated or is running then we will need to update it now.\n if (child.getState() === State.READY || child.getState() === State.RUNNING) {\n // Update the child of this node.\n child.update(agent, options);\n }\n\n // If the current child has a state of 'SUCCEEDED' then we should move on to the next child.\n if (child.getState() === State.SUCCEEDED) {\n // Find out if the current child is the last one in the sequence.\n // If it is then this sequence node has also succeeded.\n if (this.children.indexOf(child) === this.children.length - 1) {\n // This node is a 'SUCCEEDED' node.\n this.setState(State.SUCCEEDED);\n\n // There is no need to check the rest of the sequence as we have completed it.\n return;\n } else {\n // The child node succeeded, but we have not finished the sequence yet.\n continue;\n }\n }\n\n // If the current child has a state of 'FAILED' then this node is also a 'FAILED' node.\n if (child.getState() === State.FAILED) {\n // This node is a 'FAILED' node.\n this.setState(State.FAILED);\n\n // There is no need to check the rest of the sequence.\n return;\n }\n\n // The node should be in the 'RUNNING' state.\n if (child.getState() === State.RUNNING) {\n // This node is a 'RUNNING' node.\n this.setState(State.RUNNING);\n\n // There is no need to check the rest of the sequence as the current child is still running.\n return;\n }\n\n // The child node was not in an expected state.\n throw new Error(\"child node was not in an expected state.\");\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => \"SEQUENCE\";\n}\n", "import createLotto from \"lotto-draw\";\n\nimport Node from \"../Node\";\nimport Composite from \"./Composite\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A LOTTO node.\n * A winning child is picked on the initial update of this node, based on ticket weighting.\n * The state of this node will match the state of the winning child.\n */\nexport default class Lotto extends Composite {\n /**\n * @param attributes The node attributes.\n * @param weights The child node weights.\n * @param children The child nodes.\n */\n constructor(attributes: Attribute[], private weights: number[] | undefined, children: Node[]) {\n super(\"lotto\", attributes, children);\n }\n\n /**\n * The child node selected to be the active one.\n */\n private selectedChild: Node | undefined;\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // If this node is in the READY state then we need to pick a winning child node.\n if (this.is(State.READY)) {\n // Create a lotto draw with which to randomly pick a child node to become the active one.\n const lottoDraw = createLotto({\n // Hook up the optional 'random' behaviour tree function option to the one used by 'lotto-draw'.\n random: options.random,\n // Pass in each child node as a participant in the lotto draw with their respective ticket count.\n participants: this.children.map((child, index) => [child, this.weights?.[index] || 1])\n });\n\n // Randomly pick a child based on ticket weighting, this will become the active child for this composite node.\n this.selectedChild = lottoDraw.draw() || undefined;\n }\n\n // If something went wrong and we don't have an active child then we should throw an error.\n if (!this.selectedChild) {\n throw new Error(\"failed to update lotto node as it has no active child\");\n }\n\n // If the selected child has never been updated or is running then we will need to update it now.\n if (this.selectedChild.getState() === State.READY || this.selectedChild.getState() === State.RUNNING) {\n this.selectedChild.update(agent, options);\n }\n\n // The state of the lotto node is the state of its selected child.\n this.setState(this.selectedChild.getState());\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => (this.weights ? `LOTTO [${this.weights.join(\",\")}]` : \"LOTTO\");\n}\n", "import Node from \"../Node\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\n\n/**\n * A decorator node that wraps a single child node.\n */\nexport default abstract class Decorator extends Node {\n /**\n * @param type The node type.\n * @param attributes The node attributes.\n * @param child The child node.\n */\n constructor(type: string, attributes: Attribute[], protected child: Node) {\n super(type, attributes, []);\n }\n\n /**\n * Gets whether this node is a leaf node.\n */\n isLeafNode = () => false;\n\n /**\n * Gets the children of this node.\n */\n getChildren = () => [this.child];\n\n /**\n * Reset the state of the node.\n */\n reset = () => {\n // Reset the state of this node.\n this.setState(State.READY);\n\n // Reset the state of the child node.\n this.child.reset();\n };\n\n /**\n * Abort the running of this node.\n * @param agent The agent.\n */\n abort = (agent: Agent) => {\n // There is nothing to do if this node is not in the running state.\n if (!this.is(State.RUNNING)) {\n return;\n }\n\n // Abort the child node.\n this.child.abort(agent);\n\n // Reset the state of this node.\n this.reset();\n\n this.getAttribute(\"exit\")?.callAgentFunction(agent, false, true);\n };\n}\n", "import Node from \"../Node\";\nimport Decorator from \"./Decorator\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A Fail node.\n * This node wraps a single child and will always move to the 'FAILED' state when the child moves to a 'SUCCEEDED' or 'FAILED' state.\n */\nexport default class Fail extends Decorator {\n /**\n * @param attributes The node attributes.\n * @param child The child node.\n */\n constructor(attributes: Attribute[], child: Node) {\n super(\"fail\", attributes, child);\n }\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // If the child has never been updated or is running then we will need to update it now.\n if (this.child.getState() === State.READY || this.child.getState() === State.RUNNING) {\n this.child.update(agent, options);\n }\n\n // The state of this node will depend in the state of its child.\n switch (this.child.getState()) {\n case State.RUNNING:\n this.setState(State.RUNNING);\n break;\n\n case State.SUCCEEDED:\n case State.FAILED:\n this.setState(State.FAILED);\n break;\n\n default:\n this.setState(State.READY);\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => \"FAIL\";\n}\n", "import Decorator from \"./Decorator\";\nimport State from \"../../State\";\nimport Node from \"../Node\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A Flip node.\n * This node wraps a single child and will flip the state of the child state.\n */\nexport default class Flip extends Decorator {\n /**\n * @param attributes The node attributes.\n * @param child The child node.\n */\n constructor(attributes: Attribute[], child: Node) {\n super(\"flip\", attributes, child);\n }\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // If the child has never been updated or is running then we will need to update it now.\n if (this.child.getState() === State.READY || this.child.getState() === State.RUNNING) {\n this.child.update(agent, options);\n }\n\n // The state of this node will depend in the state of its child.\n switch (this.child.getState()) {\n case State.RUNNING:\n this.setState(State.RUNNING);\n break;\n\n case State.SUCCEEDED:\n this.setState(State.FAILED);\n break;\n\n case State.FAILED:\n this.setState(State.SUCCEEDED);\n break;\n\n default:\n this.setState(State.READY);\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => \"FLIP\";\n}\n", "import Node from \"../Node\";\nimport Decorator from \"./Decorator\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A REPEAT node.\n * The node has a single child which can have:\n * -- A number of iterations for which to repeat the child node.\n * -- An infinite repeat loop if neither an iteration count or a condition function is defined.\n * The REPEAT node will stop and have a 'FAILED' state if its child is ever in a 'FAILED' state after an update.\n * The REPEAT node will attempt to move on to the next iteration if its child is ever in a 'SUCCEEDED' state.\n */\nexport default class Repeat extends Decorator {\n /**\n * @param attributes The node attributes.\n * @param iterations The number of iterations to repeat the child node.\n * @param iterationsMin The minimum possible number of iterations to repeat the child node.\n * @param iterationsMax The maximum possible number of iterations to repeat the child node.\n * @param child The child node.\n */\n constructor(\n attributes: Attribute[],\n private iterations: number | null,\n private iterationsMin: number | null,\n private iterationsMax: number | null,\n child: Node\n ) {\n super(\"repeat\", attributes, child);\n }\n\n /**\n * The number of target iterations to make.\n */\n private targetIterationCount: number | null = null;\n\n /**\n * The current iteration count.\n */\n private currentIterationCount: number = 0;\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // If this node is in the READY state then we need to reset the child and the target iteration count.\n if (this.is(State.READY)) {\n // Reset the child node.\n this.child.reset();\n\n // Reset the current iteration count.\n this.currentIterationCount = 0;\n\n // Set the target iteration count.\n this.setTargetIterationCount(options);\n }\n\n // Do a check to see if we can iterate. If we can then this node will move into the 'RUNNING' state.\n // If we cannot iterate then we have hit our target iteration count, which means that the node has succeeded.\n if (this.canIterate()) {\n // This node is in the running state and can do its initial iteration.\n this.setState(State.RUNNING);\n\n // We may have already completed an iteration, meaning that the child node will be in the SUCCEEDED state.\n // If this is the case then we will have to reset the child node now.\n if (this.child.getState() === State.SUCCEEDED) {\n this.child.reset();\n }\n\n // Update the child of this node.\n this.child.update(agent, options);\n\n // If the child moved into the FAILED state when we updated it then there is nothing left to do and this node has also failed.\n // If it has moved into the SUCCEEDED state then we have completed the current iteration.\n if (this.child.getState() === State.FAILED) {\n // The child has failed, meaning that this node has failed.\n this.setState(State.FAILED);\n\n return;\n } else if (this.child.getState() === State.SUCCEEDED) {\n // We have completed an iteration.\n this.currentIterationCount += 1;\n }\n } else {\n // This node is in the 'SUCCEEDED' state as we cannot iterate any more.\n this.setState(State.SUCCEEDED);\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => {\n if (this.iterations !== null) {\n return `REPEAT ${this.iterations}x`;\n } else if (this.iterationsMin !== null && this.iterationsMax !== null) {\n return `REPEAT ${this.iterationsMin}x-${this.iterationsMax}x`;\n } else {\n return \"REPEAT\";\n }\n };\n\n /**\n * Reset the state of the node.\n */\n reset = () => {\n // Reset the state of this node.\n this.setState(State.READY);\n\n // Reset the current iteration count.\n this.currentIterationCount = 0;\n\n // Reset the child node.\n this.child.reset();\n };\n\n /**\n * Gets whether an iteration can be made.\n * @returns Whether an iteration can be made.\n */\n private canIterate = () => {\n if (this.targetIterationCount !== null) {\n // We can iterate as long as we have not reached our target iteration count.\n return this.currentIterationCount < this.targetIterationCount;\n }\n\n // If neither an iteration count or a condition function were defined then we can iterate indefinitely.\n return true;\n };\n\n /**\n * Sets the target iteration count.\n * @param options The behaviour tree options object.\n */\n private setTargetIterationCount = (options: BehaviourTreeOptions) => {\n // Are we dealing with an explicit iteration count or will we be randomly picking a iteration count between the min and max iteration count.\n if (this.iterations !== null) {\n this.targetIterationCount = this.iterations;\n } else if (this.iterationsMin !== null && this.iterationsMax !== null) {\n // We will be picking a random iteration count between a min and max iteration count, if the optional 'random'\n // behaviour tree function option is defined then we will be using that, otherwise we will fall back to using Math.random.\n const random = typeof options.random === \"function\" ? options.random : Math.random;\n\n // Pick a random iteration count between a min and max iteration count.\n this.targetIterationCount = Math.floor(\n random() * (this.iterationsMax - this.iterationsMin + 1) + this.iterationsMin\n );\n } else {\n this.targetIterationCount = null;\n }\n };\n}\n", "import Node from \"../Node\";\nimport Decorator from \"./Decorator\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A RETRY node.\n * The node has a single child which can have:\n * -- A number of iterations for which to repeat the child node.\n * -- An infinite repeat loop if neither an iteration count or a condition function is defined.\n * The RETRY node will stop and have a 'SUCCEEDED' state if its child is ever in a 'SUCCEEDED' state after an update.\n * The RETRY node will attempt to move on to the next iteration if its child is ever in a 'FAILED' state.\n */\nexport default class Retry extends Decorator {\n /**\n * @param attributes The node attributes.\n * @param attempts The number of attempts to retry the child node.\n * @param attemptsMin The minimum possible number of attempts to retry the child node.\n * @param attemptsMax The maximum possible number of attempts to retry the child node.\n * @param child The child node.\n */\n constructor(\n attributes: Attribute[],\n private attempts: number | null,\n private attemptsMin: number | null,\n private attemptsMax: number | null,\n child: Node\n ) {\n super(\"retry\", attributes, child);\n }\n\n /**\n * The number of target attempts to make.\n */\n private targetAttemptCount: number | null = null;\n\n /**\n * The current attempt count.\n */\n private currentAttemptCount: number = 0;\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // If this node is in the READY state then we need to reset the child and the target attempt count.\n if (this.is(State.READY)) {\n // Reset the child node.\n this.child.reset();\n\n // Reset the current attempt count.\n this.currentAttemptCount = 0;\n\n // Set the target attempt count.\n this.setTargetAttemptCount(options);\n }\n\n // Do a check to see if we can attempt. If we can then this node will move into the 'RUNNING' state.\n // If we cannot attempt then we have hit our target attempt count, which means that the node has succeeded.\n if (this.canAttempt()) {\n // This node is in the running state and can do its initial attempt.\n this.setState(State.RUNNING);\n\n // We may have already completed an attempt, meaning that the child node will be in the FAILED state.\n // If this is the case then we will have to reset the child node now.\n if (this.child.getState() === State.FAILED) {\n this.child.reset();\n }\n\n // Update the child of this node.\n this.child.update(agent, options);\n\n // If the child moved into the SUCCEEDED state when we updated it then there is nothing left to do and this node has also succeeded.\n // If it has moved into the FAILED state then we have completed the current attempt.\n if (this.child.getState() === State.SUCCEEDED) {\n // The child has succeeded, meaning that this node has succeeded.\n this.setState(State.SUCCEEDED);\n\n return;\n } else if (this.child.getState() === State.FAILED) {\n // We have completed an attempt.\n this.currentAttemptCount += 1;\n }\n } else {\n // This node is in the 'FAILED' state as we cannot iterate any more.\n this.setState(State.FAILED);\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => {\n if (this.attempts !== null) {\n return `RETRY ${this.attempts}x`;\n } else if (this.attemptsMin !== null && this.attemptsMax !== null) {\n return `RETRY ${this.attemptsMin}x-${this.attemptsMax}x`;\n } else {\n return \"RETRY\";\n }\n };\n\n /**\n * Reset the state of the node.\n */\n reset = () => {\n // Reset the state of this node.\n this.setState(State.READY);\n\n // Reset the current attempt count.\n this.currentAttemptCount = 0;\n\n // Reset the child node.\n this.child.reset();\n };\n\n /**\n * Gets whether an attempt can be made.\n * @returns Whether an attempt can be made.\n */\n canAttempt = () => {\n if (this.targetAttemptCount !== null) {\n // We can attempt as long as we have not reached our target attempt count.\n return this.currentAttemptCount < this.targetAttemptCount;\n }\n\n // If neither an attempt count or a condition function were defined then we can attempt indefinitely.\n return true;\n };\n\n /**\n * Sets the target attempt count.\n * @param options The behaviour tree options object.\n */\n setTargetAttemptCount = (options: BehaviourTreeOptions) => {\n // Are we dealing with an explicit attempt count or will we be randomly picking an attempt count between the min and max attempt count.\n if (this.attempts !== null) {\n this.targetAttemptCount = this.attempts;\n } else if (this.attemptsMin !== null && this.attemptsMax !== null) {\n // We will be picking a random attempt count between a min and max attempt count, if the optional 'random'\n // behaviour tree function option is defined then we will be using that, otherwise we will fall back to using Math.random.\n const random = typeof options.random === \"function\" ? options.random : Math.random;\n\n // Pick a random attempt count between a min and max attempt count.\n this.targetAttemptCount = Math.floor(\n random() * (this.attemptsMax - this.attemptsMin + 1) + this.attemptsMin\n );\n } else {\n this.targetAttemptCount = null;\n }\n };\n}\n", "import Node from \"../Node\";\nimport Decorator from \"./Decorator\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A Root node.\n * The root node will have a single child.\n */\nexport default class Root extends Decorator {\n /**\n * @param attributes The node attributes.\n * @param child The child node.\n */\n constructor(attributes: Attribute[], child: Node) {\n super(\"root\", attributes, child);\n }\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // If the child has never been updated or is running then we will need to update it now.\n if (this.child.getState() === State.READY || this.child.getState() === State.RUNNING) {\n // Update the child of this node.\n this.child.update(agent, options);\n }\n\n // The state of the root node is the state of its child.\n this.setState(this.child.getState());\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => \"ROOT\";\n}\n", "import Node from \"../Node\";\nimport Decorator from \"./Decorator\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A Succeed node.\n * This node wraps a single child and will always move to the 'SUCCEEDED' state when the child moves to a 'SUCCEEDED' or 'FAILED' state.\n */\nexport default class Succeed extends Decorator {\n /**\n * @param attributes The node attributes.\n * @param child The child node.\n */\n constructor(attributes: Attribute[], child: Node) {\n super(\"succeed\", attributes, child);\n }\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // If the child has never been updated or is running then we will need to update it now.\n if (this.child.getState() === State.READY || this.child.getState() === State.RUNNING) {\n this.child.update(agent, options);\n }\n\n // The state of this node will depend in the state of its child.\n switch (this.child.getState()) {\n case State.RUNNING:\n this.setState(State.RUNNING);\n break;\n\n case State.SUCCEEDED:\n case State.FAILED:\n this.setState(State.SUCCEEDED);\n break;\n\n default:\n this.setState(State.READY);\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => \"SUCCEED\";\n}\n", "import Node from \"../Node\";\n\n/**\n * A leaf node.\n */\nexport default abstract class Leaf extends Node {\n /**\n * Gets whether this node is a leaf node.\n */\n isLeafNode = () => true;\n}\n", "import { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\nimport State, { CompleteState } from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Leaf from \"./Leaf\";\nimport Lookup from \"../../Lookup\";\nimport Attribute from \"../../attributes/Attribute\";\n\n/**\n * An Action leaf node.\n * This represents an immediate or ongoing state of behaviour.\n */\nexport default class Action extends Leaf {\n /**\n * @param attributes The node attributes.\n * @param actionName The action name.\n * @param actionArguments The array of action argument definitions.\n */\n constructor(attributes: Attribute[], private actionName: string, private actionArguments: any[]) {\n super(\"action\", attributes, actionArguments);\n }\n\n /**\n * Whether there is a pending update promise.\n */\n private isUsingUpdatePromise = false;\n\n /**\n * The finished state result of an update promise.\n */\n private updatePromiseStateResult: CompleteState | null = null;\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // If the result of this action depends on an update promise then there is nothing to do until\n // it resolves, unless there has been a value set as a result of the update promise resolving.\n if (this.isUsingUpdatePromise) {\n // Check whether the update promise has resolved with a state value.\n if (this.updatePromiseStateResult) {\n // Set the state of this node to match the state returned by the promise.\n this.setState(this.updatePromiseStateResult);\n }\n\n return;\n }\n\n // Attempt to get the invoker for the action function.\n const actionFuncInvoker = Lookup.getFuncInvoker(agent, this.actionName);\n\n // The action function should be defined.\n if (actionFuncInvoker === null) {\n throw new Error(\n `cannot update action node as the action '${this.actionName}' function is not defined on the agent and has not been registered`\n );\n }\n\n let actionFunctionResult;\n\n try {\n // Call the action function, the result of which may be:\n // - The finished state of this action node.\n // - A promise to return a finished node state.\n // - Undefined if the node should remain in the running state.\n actionFunctionResult = actionFuncInvoker(this.actionArguments) as CompleteState | Promise;\n } catch (error) {\n // The user was naughty and threw something.\n throw new Error(`action function '${this.actionName}' threw '${error}'`);\n }\n\n if (actionFunctionResult instanceof Promise) {\n actionFunctionResult.then(\n (result) => {\n // If 'isUpdatePromisePending' is null then the promise was cleared as it was resolving, probably via an abort of reset.\n if (!this.isUsingUpdatePromise) {\n return;\n }\n\n // Check to make sure the result is a valid finished state.\n if (result !== State.SUCCEEDED && result !== State.FAILED) {\n throw new Error(\n \"action node promise resolved with an invalid value, expected a State.SUCCEEDED or State.FAILED value to be returned\"\n );\n }\n\n // Set pending update promise state result to be processed on next update.\n this.updatePromiseStateResult = result;\n },\n (reason) => {\n // If 'isUpdatePromisePending' is null then the promise was cleared as it was resolving, probably via an abort or reset.\n if (!this.isUsingUpdatePromise) {\n return;\n }\n\n // TODO We shouldn't throw an error here, we actually need to set this.updatePromiseRejectionReason so that it can be thrown on the next tree.step() call.\n\n // The promise was rejected, which isn't great.\n throw new Error(`action function '${this.actionName}' promise rejected with reason '${reason}'`);\n }\n );\n\n // This node will be in the 'RUNNING' state until the update promise resolves.\n this.setState(State.RUNNING);\n\n // We are now waiting for the promise returned by the use to resolve before we know what state this node is in.\n this.isUsingUpdatePromise = true;\n } else {\n // Validate the returned value.\n this.validateUpdateResult(actionFunctionResult);\n\n // Set the state of this node, this may be undefined, which just means that the node is still in the 'RUNNING' state.\n this.setState(actionFunctionResult || State.RUNNING);\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => this.actionName;\n\n /**\n * Reset the state of the node.\n */\n reset = () => {\n // Reset the state of this node.\n this.setState(State.READY);\n\n // There is no longer an update promise that we care about.\n this.isUsingUpdatePromise = false;\n this.updatePromiseStateResult = null;\n };\n\n /**\n * Validate the result of an update function call.\n * @param result The result of an update function call.\n */\n private validateUpdateResult = (result: CompleteState | boolean) => {\n switch (result) {\n case State.SUCCEEDED:\n case State.FAILED:\n case undefined:\n return;\n default:\n throw new Error(\n `action '${this.actionName}' 'onUpdate' returned an invalid response, expected an optional State.SUCCEEDED or State.FAILED value to be returned`\n );\n }\n };\n}\n", "import { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Leaf from \"./Leaf\";\nimport Lookup from \"../../Lookup\";\nimport Attribute from \"../../attributes/Attribute\";\n\n/**\n * A Condition leaf node.\n * This will succeed or fail immediately based on an agent predicate, without moving to the 'RUNNING' state.\n */\nexport default class Condition extends Leaf {\n /**\n * @param attributes The node attributes.\n * @param conditionName The name of the condition function.\n * @param conditionArguments The array of condition argument definitions.\n */\n constructor(attributes: Attribute[], private conditionName: string, private conditionArguments: any[]) {\n super(\"condition\", attributes, conditionArguments);\n }\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // Attempt to get the invoker for the condition function.\n const conditionFuncInvoker = Lookup.getFuncInvoker(agent, this.conditionName);\n\n // The condition function should be defined.\n if (conditionFuncInvoker === null) {\n throw new Error(\n `cannot update condition node as the condition '${this.conditionName}' function is not defined on the agent and has not been registered`\n );\n }\n\n let conditionFunctionResult;\n\n try {\n // Call the condition function to determine the state of this node, the result of which should be a boolean.\n conditionFunctionResult = conditionFuncInvoker(this.conditionArguments);\n } catch (error) {\n // The user was naughty and threw something.\n throw new Error(`condition function '${this.conditionName}' threw '${error}'`);\n }\n\n // The result of calling the condition function must be a boolean value.\n if (typeof conditionFunctionResult !== \"boolean\") {\n throw new Error(\n `expected condition function '${this.conditionName}' to return a boolean but returned '${conditionFunctionResult}'`\n );\n }\n\n // Set the state of this node based on the result of calling the condition function.\n this.setState(!!conditionFunctionResult ? State.SUCCEEDED : State.FAILED);\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => this.conditionName;\n}\n", "import Leaf from \"./Leaf\";\nimport State from \"../../State\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { Agent } from \"../../Agent\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A WAIT node.\n * The state of this node will change to SUCCEEDED after a duration of time\n */\nexport default class Wait extends Leaf {\n /**\n * @param attributes The node attributes.\n * @param duration The duration that this node will wait to succeed in milliseconds.\n * @param durationMin The minimum possible duration in milliseconds that this node will wait to succeed.\n * @param durationMax The maximum possible duration in milliseconds that this node will wait to succeed.\n */\n constructor(\n attributes: Attribute[],\n private duration: number | null,\n private durationMin: number | null,\n private durationMax: number | null\n ) {\n super(\"wait\", attributes, []);\n }\n\n /**\n * The time in milliseconds at which this node was first updated.\n */\n private initialUpdateTime: number = 0;\n\n /**\n * The total duration in milliseconds that this node will be waiting for.\n */\n private totalDuration: number | null = null;\n\n /**\n * The duration in milliseconds that this node has been waiting for.\n */\n private waitedDuration: number = 0;\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // If this node is in the READY state then we need to set the initial update time.\n if (this.is(State.READY)) {\n // Set the initial update time.\n this.initialUpdateTime = new Date().getTime();\n\n // Set the initial waited duration.\n this.waitedDuration = 0;\n\n // Are we dealing with an explicit duration or will we be randomly picking a duration between the min and max duration.\n if (this.duration !== null) {\n this.totalDuration = this.duration;\n } else if (this.durationMin !== null && this.durationMax !== null) {\n // We will be picking a random duration between a min and max duration, if the optional 'random' behaviour tree\n // function option is defined then we will be using that, otherwise we will fall back to using Math.random.\n const random = typeof options.random === \"function\" ? options.random : Math.random;\n\n // Pick a random duration between a min and max duration.\n this.totalDuration = Math.floor(\n random() * (this.durationMax - this.durationMin + 1) + this.durationMin\n );\n } else {\n this.totalDuration = null;\n }\n\n // The node is now running until we finish waiting.\n this.setState(State.RUNNING);\n }\n\n // If we have no total duration then this wait node will wait indefinitely until it is aborted.\n if (this.totalDuration === null) {\n return;\n }\n\n // If we have a 'getDeltaTime' function defined as part of our options then we will use it to figure out how long we have waited for.\n if (typeof options.getDeltaTime === \"function\") {\n // Get the delta time.\n const deltaTime = options.getDeltaTime();\n\n // Our delta time must be a valid number and cannot be NaN.\n if (typeof deltaTime !== \"number\" || isNaN(deltaTime)) {\n throw new Error(\"The delta time must be a valid number and not NaN.\");\n }\n\n // Update the amount of time that this node has been waiting for based on the delta time.\n this.waitedDuration += deltaTime * 1000;\n } else {\n // We are not using a delta time, so we will just work out hom much time has passed since the first update.\n this.waitedDuration = new Date().getTime() - this.initialUpdateTime;\n }\n\n // Have we waited long enough?\n if (this.waitedDuration >= this.totalDuration) {\n // We have finished waiting!\n this.setState(State.SUCCEEDED);\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => {\n if (this.duration !== null) {\n return `WAIT ${this.duration}ms`;\n } else if (this.durationMin !== null && this.durationMax !== null) {\n return `WAIT ${this.durationMin}ms-${this.durationMax}ms`;\n } else {\n return \"WAIT\";\n }\n };\n}\n", "import Guard from \"./guards/Guard\";\n\nexport type AttributeDetails = {\n /** The attribute type. */\n type: string;\n\n /** The attribute arguments. */\n args: any[];\n};\n\n/**\n * A base node attribute.\n */\nexport default abstract class Attribute {\n /**\n * @param type The node attribute type.\n * @param args The array of attribute arguments.\n */\n constructor(public type: string, public args: any[]) {}\n\n /**\n * Gets the attribute details.\n */\n abstract getDetails(): TAttributeDetails;\n\n /**\n * Gets whether this attribute is a guard.\n */\n abstract isGuard: () => this is Guard;\n}\n", "import { Agent } from \"../../Agent\";\nimport Attribute, { AttributeDetails } from \"../Attribute\";\n\nexport type GuardAttributeDetails = {\n /** The name of the condition function that determines whether the guard is satisfied. */\n condition: string;\n} & AttributeDetails;\n\n/**\n * A base node guard attribute.\n */\nexport default abstract class Guard extends Attribute {\n /**\n * @param type The node attribute type.\n * @param args The array of decorator argument definitions.\n * @param condition The name of the condition function that determines whether the guard is satisfied.\n */\n constructor(type: string, args: any[], private condition: string) {\n super(type, args);\n }\n\n /**\n * Gets the name of the condition function that determines whether the guard is satisfied.\n */\n getCondition = () => this.condition;\n\n /**\n * Gets whether this attribute is a guard.\n */\n isGuard = () => true;\n\n /**\n * Gets the attribute details.\n */\n getDetails(): GuardAttributeDetails {\n return {\n type: this.type,\n args: this.args,\n condition: this.getCondition()\n };\n }\n\n /**\n * Gets whether the guard is satisfied.\n * @param agent The agent.\n * @returns Whether the guard is satisfied.\n */\n abstract isSatisfied(agent: Agent): boolean;\n}\n", "import Guard from \"./Guard\";\nimport Lookup from \"../../Lookup\";\nimport { Agent } from \"../../Agent\";\n\n/**\n * A WHILE guard which is satisfied as long as the given condition remains true.\n */\nexport default class While extends Guard {\n /**\n * @param condition The name of the condition function that determines whether the guard is satisfied.\n * @param args The array of decorator argument definitions.\n */\n constructor(condition: string, args: any[]) {\n super(\"while\", args, condition);\n }\n\n /**\n * Gets whether the guard is satisfied.\n * @param agent The agent.\n * @returns Whether the guard is satisfied.\n */\n isSatisfied = (agent: Agent) => {\n // Attempt to get the invoker for the condition function.\n const conditionFuncInvoker = Lookup.getFuncInvoker(agent, this.getCondition());\n\n // The condition function should be defined.\n if (conditionFuncInvoker === null) {\n throw new Error(\n `cannot evaluate node guard as the condition '${this.getCondition()}' function is not defined on the agent and has not been registered`\n );\n }\n\n // Call the condition function to determine whether this guard is satisfied.\n return !!conditionFuncInvoker(this.args);\n };\n}\n", "import Guard from \"./Guard\";\nimport Lookup from \"../../Lookup\";\nimport { Agent } from \"../../Agent\";\n\n/**\n * An UNTIL guard which is satisfied as long as the given condition remains false.\n */\nexport default class Until extends Guard {\n /**\n * @param condition The name of the condition function that determines whether the guard is satisfied.\n * @param args The array of decorator argument definitions.\n */\n constructor(condition: string, args: any[]) {\n super(\"until\", args, condition);\n }\n\n /**\n * Gets whether the guard is satisfied.\n * @param agent The agent.\n * @returns Whether the guard is satisfied.\n */\n isSatisfied = (agent: Agent) => {\n // Attempt to get the invoker for the condition function.\n const conditionFuncInvoker = Lookup.getFuncInvoker(agent, this.getCondition());\n\n // The condition function should be defined.\n if (conditionFuncInvoker === null) {\n throw new Error(\n `cannot evaluate node guard as the condition '${this.getCondition()}' function is not defined on the agent and has not been registered`\n );\n }\n\n // Call the condition function to determine whether this guard is satisfied.\n return !!!conditionFuncInvoker(this.args);\n };\n}\n", "import { Agent } from \"../../Agent\";\nimport Attribute, { AttributeDetails } from \"../Attribute\";\n\nexport type CallbackAttributeDetails = {\n /** The name of the agent function that is called. */\n functionName: string;\n} & AttributeDetails;\n\n/**\n * A base node callback attribute.\n */\nexport default abstract class Callback extends Attribute {\n /**\n * @param type The node attribute type.\n * @param args The array of decorator argument definitions.\n * @param functionName The name of the agent function to call.\n */\n constructor(type: string, args: any[], private functionName: string) {\n super(type, args);\n }\n\n /**\n * Gets the name of the agent function to call.\n */\n getFunctionName = () => this.functionName;\n\n /**\n * Gets whether this attribute is a guard.\n */\n isGuard = () => false;\n\n /**\n * Gets the attribute details.\n */\n getDetails(): CallbackAttributeDetails {\n return {\n type: this.type,\n args: this.args,\n functionName: this.getFunctionName()\n };\n }\n\n /**\n * Attempt to call the agent function that this callback refers to.\n * @param agent The agent.\n */\n abstract callAgentFunction: (agent: Agent, isSuccess: boolean, isAborted: boolean) => void;\n}\n", "import Callback from \"./Callback\";\nimport Lookup from \"../../Lookup\";\nimport { Agent } from \"../../Agent\";\n\n/**\n * An ENTRY callback which defines an agent function to call when the associated node is updated and moves out of running state.\n */\nexport default class Entry extends Callback {\n /**\n * @param functionName The name of the agent function to call.\n * @param args The array of callback argument definitions.\n */\n constructor(functionName: string, args: any[]) {\n super(\"entry\", args, functionName);\n }\n\n /**\n * Attempt to call the agent function that this callback refers to.\n * @param agent The agent.\n */\n callAgentFunction = (agent: Agent) => {\n // Attempt to get the invoker for the callback function.\n const callbackFuncInvoker = Lookup.getFuncInvoker(agent, this.getFunctionName());\n\n // The callback function should be defined.\n if (callbackFuncInvoker === null) {\n throw new Error(\n `cannot call entry function '${this.getFunctionName()}' as is not defined on the agent and has not been registered`\n );\n }\n\n // Call the callback function.\n callbackFuncInvoker(this.args);\n };\n}\n", "import Callback from \"./Callback\";\nimport Lookup from \"../../Lookup\";\nimport { Agent } from \"../../Agent\";\n\n/**\n * A STEP callback which defines an agent function to call when the associated node is updated.\n */\nexport default class Step extends Callback {\n /**\n * @param functionName The name of the agent function to call.\n * @param args The array of callback argument definitions.\n */\n constructor(functionName: string, args: any[]) {\n super(\"step\", args, functionName);\n }\n\n /**\n * Attempt to call the agent function that this callback refers to.\n * @param agent The agent.\n */\n callAgentFunction = (agent: Agent) => {\n // Attempt to get the invoker for the callback function.\n const callbackFuncInvoker = Lookup.getFuncInvoker(agent, this.getFunctionName());\n\n // The callback function should be defined.\n if (callbackFuncInvoker === null) {\n throw new Error(\n `cannot call step function '${this.getFunctionName()}' as is not defined on the agent and has not been registered`\n );\n }\n\n // Call the callback function.\n callbackFuncInvoker(this.args);\n };\n}\n", "import Callback from \"./Callback\";\nimport Lookup from \"../../Lookup\";\nimport { Agent } from \"../../Agent\";\n\n/**\n * An EXIT callback which defines an agent function to call when the associated node is updated and moves to a finished state or is aborted.\n */\nexport default class Exit extends Callback {\n /**\n * @param functionName The name of the agent function to call.\n * @param args The array of callback argument definitions.\n */\n constructor(functionName: string, args: any[]) {\n super(\"exit\", args, functionName);\n }\n\n /**\n * Attempt to call the agent function that this callback refers to.\n * @param agent The agent.\n * @param isSuccess Whether the decorated node was left with a success state.\n * @param isAborted Whether the decorated node was aborted.\n */\n callAgentFunction = (agent: Agent, isSuccess: boolean, isAborted: boolean) => {\n // Attempt to get the invoker for the callback function.\n const callbackFuncInvoker = Lookup.getFuncInvoker(agent, this.getFunctionName());\n\n // The callback function should be defined.\n if (callbackFuncInvoker === null) {\n throw new Error(\n `cannot call exit function '${this.getFunctionName()}' as is not defined on the agent and has not been registered`\n );\n }\n\n // Call the callback function\n callbackFuncInvoker([{ value: { succeeded: isSuccess, aborted: isAborted } }, ...this.args]);\n };\n}\n", "import { AnyNodeDefinition, RootNodeDefinition } from \"./BehaviourTreeDefinition\";\nimport GuardPath, { GuardPathPart } from \"./attributes/guards/GuardPath\";\nimport { validateBranchSubtreeLinks } from \"./BehaviourTreeDefinitionValidator\";\nimport { isInteger } from \"./BehaviourTreeDefinitionUtilities\";\nimport Node from \"./nodes/Node\";\nimport Composite from \"./nodes/composite/Composite\";\nimport Decorator from \"./nodes/decorator/Decorator\";\nimport Parallel from \"./nodes/composite/Parallel\";\nimport Selector from \"./nodes/composite/Selector\";\nimport Sequence from \"./nodes/composite/Sequence\";\nimport Lotto from \"./nodes/composite/Lotto\";\nimport Fail from \"./nodes/decorator/Fail\";\nimport Flip from \"./nodes/decorator/Flip\";\nimport Repeat from \"./nodes/decorator/Repeat\";\nimport Retry from \"./nodes/decorator/Retry\";\nimport Root from \"./nodes/decorator/Root\";\nimport Succeed from \"./nodes/decorator/Succeed\";\nimport Action from \"./nodes/leaf/Action\";\nimport Condition from \"./nodes/leaf/Condition\";\nimport Wait from \"./nodes/leaf/Wait\";\nimport Lookup from \"./Lookup\";\nimport Attribute from \"./attributes/Attribute\";\nimport While from \"./attributes/guards/While\";\nimport Until from \"./attributes/guards/Until\";\nimport Entry from \"./attributes/callbacks/Entry\";\nimport Step from \"./attributes/callbacks/Step\";\nimport Exit from \"./attributes/callbacks/Exit\";\n\n/**\n * A type representing any node instance in a behaviour tree.\n */\ntype AnyNode =\n | Root\n | Action\n | Condition\n | Wait\n | Sequence\n | Selector\n | Lotto\n | Parallel\n | Repeat\n | Retry\n | Flip\n | Succeed\n | Fail;\n\n/**\n * A type defining a mapping of root node identifiers to root node definitions.\n */\ntype RootNodeDefinitionMap = { [key: string | symbol]: RootNodeDefinition };\n\n/**\n * A symbol to use as the main root key in any root node mappings.\n */\nconst MAIN_ROOT_NODE_KEY = Symbol(\"__root__\");\n\n/**\n * Build and populate the root nodes based on the provided definition, assuming that the definition has been validated.\n * @param definition The root node definitions.\n * @returns The built and populated root node definitions.\n */\nexport default function buildRootNode(definition: RootNodeDefinition[]): Root {\n // Create a mapping of root node identifers to root node definitions, including globally registered subtree root node definitions.\n const rootNodeDefinitionMap = createRootNodeDefinitionMap(definition);\n\n // Now that we have all of our root node definitons (those part of the tree definition and those globally\n // registered) we should validate the definition. This will also double-check that we dont have any circular\n // dependencies in our branch -> subtree references and that we have no broken branch -> subtree links.\n validateBranchSubtreeLinks(definition, true);\n\n // Create our populated tree of node instances, starting with our main root node.\n const rootNode = nodeFactory(rootNodeDefinitionMap[MAIN_ROOT_NODE_KEY], rootNodeDefinitionMap) as Root;\n\n // Set a guard path on every leaf of the tree to evaluate as part of each update.\n applyLeafNodeGuardPaths(rootNode);\n\n // We only need to return the main root node.\n return rootNode;\n}\n\n/**\n * A factory function which creates a node instance based on the specified definition.\n * @param definition The node definition.\n * @param rootNodeDefinitionMap The mapping of root node identifers to root node definitions, including globally registered subtree root node definitions.\n * @returns A node instance based on the specified definition.\n */\nfunction nodeFactory(definition: AnyNodeDefinition, rootNodeDefinitionMap: RootNodeDefinitionMap): AnyNode {\n // Get the attributes for the node.\n const attributes = nodeAttributesFactory(definition);\n\n // Create the node instance based on the definition type.\n switch (definition.type) {\n case \"root\":\n return new Root(attributes, nodeFactory(definition.child, rootNodeDefinitionMap));\n\n case \"repeat\":\n let iterations: number | null = null;\n let iterationsMin: number | null = null;\n let iterationsMax: number | null = null;\n\n if (Array.isArray(definition.iterations)) {\n iterationsMin = definition.iterations[0];\n iterationsMax = definition.iterations[1];\n } else if (isInteger(definition.iterations)) {\n iterations = definition.iterations!;\n }\n\n return new Repeat(\n attributes,\n iterations,\n iterationsMin,\n iterationsMax,\n nodeFactory(definition.child, rootNodeDefinitionMap)\n );\n\n case \"retry\":\n let attempts: number | null = null;\n let attemptsMin: number | null = null;\n let attemptsMax: number | null = null;\n\n if (Array.isArray(definition.attempts)) {\n attemptsMin = definition.attempts[0];\n attemptsMax = definition.attempts[1];\n } else if (isInteger(definition.attempts)) {\n attempts = definition.attempts!;\n }\n\n return new Retry(\n attributes,\n attempts,\n attemptsMin,\n attemptsMax,\n nodeFactory(definition.child, rootNodeDefinitionMap)\n );\n\n case \"flip\":\n return new Flip(attributes, nodeFactory(definition.child, rootNodeDefinitionMap));\n\n case \"succeed\":\n return new Succeed(attributes, nodeFactory(definition.child, rootNodeDefinitionMap));\n\n case \"fail\":\n return new Fail(attributes, nodeFactory(definition.child, rootNodeDefinitionMap));\n\n case \"sequence\":\n return new Sequence(\n attributes,\n definition.children.map((child) => nodeFactory(child, rootNodeDefinitionMap))\n );\n\n case \"selector\":\n return new Selector(\n attributes,\n definition.children.map((child) => nodeFactory(child, rootNodeDefinitionMap))\n );\n\n case \"parallel\":\n return new Parallel(\n attributes,\n definition.children.map((child) => nodeFactory(child, rootNodeDefinitionMap))\n );\n\n case \"lotto\":\n return new Lotto(\n attributes,\n definition.weights,\n definition.children.map((child) => nodeFactory(child, rootNodeDefinitionMap))\n );\n\n case \"branch\":\n return nodeFactory(rootNodeDefinitionMap[definition.ref].child, rootNodeDefinitionMap);\n\n case \"action\":\n return new Action(attributes, definition.call, definition.args || []);\n\n case \"condition\":\n return new Condition(attributes, definition.call, definition.args || []);\n\n case \"wait\":\n let duration: number | null = null;\n let durationMin: number | null = null;\n let durationMax: number | null = null;\n\n if (Array.isArray(definition.duration)) {\n durationMin = definition.duration[0];\n durationMax = definition.duration[1];\n } else if (isInteger(definition.duration)) {\n duration = definition.duration!;\n }\n\n return new Wait(attributes, duration, durationMin, durationMax);\n }\n}\n\n/**\n * Creates an array of node attribute instances based on the specified node definition.\n * @param definition The node definition.\n * @returns An array of node attribute instances based on the specified node definition.\n */\nfunction nodeAttributesFactory(definition: AnyNodeDefinition): Attribute[] {\n const attributes: Attribute[] = [];\n\n if (definition.while) {\n attributes.push(new While(definition.while.call, definition.while.args ?? []));\n }\n\n if (definition.until) {\n attributes.push(new Until(definition.until.call, definition.until.args ?? []));\n }\n\n if (definition.entry) {\n attributes.push(new Entry(definition.entry.call, definition.entry.args ?? []));\n }\n\n if (definition.step) {\n attributes.push(new Step(definition.step.call, definition.step.args ?? []));\n }\n\n if (definition.exit) {\n attributes.push(new Exit(definition.exit.call, definition.exit.args ?? []));\n }\n\n return attributes;\n}\n\n/**\n * Creates a mapping of root node identifers to root node definitions, mixing in globally registered subtree root node definitions.\n * @param definition The root node definitions.\n * @returns A mapping of root node identifers to root node definitions, including globally registered subtree root node definitions.\n */\nfunction createRootNodeDefinitionMap(definition: RootNodeDefinition[]): RootNodeDefinitionMap {\n // Create a mapping of root node identifers to root node definitions.\n const rootNodeMap: RootNodeDefinitionMap = {};\n\n // Add in any registered subtree root node definitions.\n for (const [name, rootNodeDefinition] of Object.entries(Lookup.getSubtrees())) {\n // The name used when registering the subtree will be used as the root node identifier.\n rootNodeMap[name] = { ...rootNodeDefinition, id: name };\n }\n\n // Populate the map with the root node definitions that were included with the tree definition.\n // We do this after adding any registered subtrees as we want these to take presedence.\n for (const rootNodeDefinition of definition) {\n rootNodeMap[rootNodeDefinition.id ?? MAIN_ROOT_NODE_KEY] = rootNodeDefinition;\n }\n\n return rootNodeMap;\n}\n\n/**\n * Applies a guard path to every leaf of the tree to evaluate as part of each update.\n * @param root The main root tree node.\n */\nfunction applyLeafNodeGuardPaths(root: Root) {\n const nodePaths: Node[][] = [];\n\n const findLeafNodes = (path: Node[], node: Node) => {\n // Add the current node to the path.\n path = path.concat(node);\n\n // Check whether the current node is a leaf node.\n if (node.isLeafNode()) {\n nodePaths.push(path);\n } else {\n (node as Composite | Decorator).getChildren().forEach((child) => findLeafNodes(path, child));\n }\n };\n\n // Find all leaf node paths, starting from the root.\n findLeafNodes([], root);\n\n nodePaths.forEach((path) => {\n // Each node in the current path will have to be assigned a guard path, working from the root outwards.\n for (let depth = 0; depth < path.length; depth++) {\n // Get the node in the path at the current depth.\n const currentNode = path[depth];\n\n // The node may already have been assigned a guard path, if so just skip it.\n if (currentNode.hasGuardPath()) {\n continue;\n }\n\n // Create the guard path for the current node.\n const guardPath = new GuardPath(\n path\n .slice(0, depth + 1)\n .map((node) => ({ node, guards: node.getGuardAttributes() }))\n .filter((details) => details.guards.length > 0)\n );\n\n // Assign the guard path to the current node.\n currentNode.setGuardPath(guardPath);\n }\n });\n}\n", "import State, { AnyState } from \"./State\";\nimport Lookup from \"./Lookup\";\nimport Node from \"./nodes/Node\";\nimport Root from \"./nodes/decorator/Root\";\nimport Composite from \"./nodes/composite/Composite\";\nimport Decorator from \"./nodes/decorator/Decorator\";\nimport { Agent, GlobalFunction } from \"./Agent\";\nimport { CallbackAttributeDetails } from \"./attributes/callbacks/Callback\";\nimport { GuardAttributeDetails } from \"./attributes/guards/Guard\";\nimport { BehaviourTreeOptions } from \"./BehaviourTreeOptions\";\nimport { convertMDSLToJSON } from \"./mdsl/MDSLDefinitionParser\";\nimport { RootNodeDefinition } from \"./BehaviourTreeDefinition\";\nimport { validateDefinition, validateJSONDefinition } from \"./BehaviourTreeDefinitionValidator\";\nimport buildRootNode from \"./BehaviourTreeBuilder\";\nimport { isNullOrUndefined } from \"./BehaviourTreeDefinitionUtilities\";\n\n// Purely for outside inspection of the tree.\nexport type FlattenedTreeNode = {\n id: string;\n type: string;\n caption: string;\n state: AnyState;\n guards: GuardAttributeDetails[];\n callbacks: CallbackAttributeDetails[];\n args: any[];\n parentId: string | null;\n};\n\n/**\n * A representation of a behaviour tree.\n */\nexport class BehaviourTree {\n /**\n * The main root tree node.\n */\n private readonly _rootNode: Root;\n\n /**\n * Creates a new instance of the BehaviourTree class.\n * @param definition The behaviour tree definition as either an MDSL string, root node definition object or array of root node definition objects.\n * @param agent The agent instance that this behaviour tree is modelling behaviour for.\n * @param options The behaviour tree options object.\n */\n constructor(\n definition: string | RootNodeDefinition | RootNodeDefinition[],\n private agent: Agent,\n private options: BehaviourTreeOptions = {}\n ) {\n // The tree definition must be defined.\n if (isNullOrUndefined(definition)) {\n throw new Error(\"tree definition not defined\");\n }\n\n // The agent must be defined and not null.\n if (typeof agent !== \"object\" || agent === null) {\n throw new Error(\"the agent must be an object and not null\");\n }\n\n // We should validate the definition before we try to build the tree nodes.\n const { succeeded, errorMessage, json } = validateDefinition(definition);\n\n // Did our validation fail without error?\n if (!succeeded) {\n throw new Error(`invalid definition: ${errorMessage}`);\n }\n\n // Double check that we did actually get our json definition as part of our definition validtion.\n if (!json) {\n throw new Error(\n \"expected json definition to be returned as part of successful definition validation response\"\n );\n }\n\n try {\n // Create the populated tree of behaviour tree nodes and get the root node.\n this._rootNode = buildRootNode(json);\n } catch (exception) {\n // There was an issue in trying build and populate the behaviour tree.\n throw new Error(`error building tree: ${(exception as Error).message}`);\n }\n }\n\n /**\n * Gets whether the tree is in the RUNNING state.\n * @returns true if the tree is in the RUNNING state, otherwise false.\n */\n isRunning() {\n return this._rootNode.getState() === State.RUNNING;\n }\n\n /**\n * Gets the current tree state of SUCCEEDED, FAILED, READY or RUNNING.\n * @returns The current tree state.\n */\n getState() {\n return this._rootNode.getState();\n }\n\n /**\n * Step the tree.\n * 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.\n * 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\n * 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.\n *\n * 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.\n */\n step() {\n // If the root node has already been stepped to completion then we need to reset it.\n if (this._rootNode.getState() === State.SUCCEEDED || this._rootNode.getState() === State.FAILED) {\n this._rootNode.reset();\n }\n\n try {\n this._rootNode.update(this.agent, this.options);\n } catch (exception) {\n throw new Error(`error stepping tree: ${(exception as Error).message}`);\n }\n }\n\n /**\n * Resets the tree from the root node outwards to each nested node, giving each a state of READY.\n */\n reset() {\n this._rootNode.reset();\n }\n\n /**\n * Gets the flattened details of every node in the tree.\n * @returns The flattened details of every node in the tree.\n */\n getFlattenedNodeDetails(): FlattenedTreeNode[] {\n // Create an empty flattened array of tree nodes.\n const flattenedTreeNodes: FlattenedTreeNode[] = [];\n\n /**\n * Helper function to process a node instance and push details into the flattened tree nodes array.\n * @param node The current node.\n * @param parentUid The UID of the node parent, or null if the node is the main root node.\n */\n const processNode = (node: Node, parentUid: string | null) => {\n // Get the guard and callback attribute details for this node.\n const guards = node\n .getAttributes()\n .filter((attribute) => attribute.isGuard())\n .map((attribute) => attribute.getDetails()) as GuardAttributeDetails[];\n const callbacks = node\n .getAttributes()\n .filter((attribute) => !attribute.isGuard())\n .map((attribute) => attribute.getDetails()) as CallbackAttributeDetails[];\n\n // Push the current node into the flattened nodes array.\n flattenedTreeNodes.push({\n id: node.getUid(),\n type: node.getType(),\n caption: node.getName(),\n state: node.getState(),\n guards,\n callbacks,\n args: node.getArguments(),\n parentId: parentUid\n });\n\n // Process each of the nodes children if it is not a leaf node.\n if (!node.isLeafNode()) {\n (node as Composite | Decorator)\n .getChildren()\n .forEach((child) => processNode(child, (node as Composite | Decorator).getUid()));\n }\n };\n\n // Convert the nested node structure into a flattened array of node details.\n processNode(this._rootNode, null);\n\n return flattenedTreeNodes;\n }\n\n /**\n * Registers the action/condition/guard/callback function or subtree with the given name.\n * @param name The name of the function or subtree to register.\n * @param value The function or subtree definition to register.\n */\n static register(name: string, value: GlobalFunction | string | RootNodeDefinition) {\n // Are we going to register a action/condition/guard/callback function?\n if (typeof value === \"function\") {\n Lookup.setFunc(name, value);\n return;\n }\n\n // We are not registering an action/condition/guard/callback function, so we must be registering a subtree.\n if (typeof value === \"string\") {\n let rootNodeDefinitions: RootNodeDefinition[];\n\n // We will assume that any string passed in will be a mdsl definition.\n try {\n rootNodeDefinitions = convertMDSLToJSON(value);\n } catch (exception) {\n throw new Error(`error registering definition, invalid MDSL: ${(exception as Error).message}`);\n }\n\n // This function should only ever be called with a definition containing a single unnamed root node.\n if (rootNodeDefinitions.length != 1 || rootNodeDefinitions[0].id !== null) {\n throw new Error(\"error registering definition: expected a single unnamed root node\");\n }\n\n try {\n // We should validate the subtree as we don't want invalid subtrees available via the lookup.\n const { succeeded, errorMessage } = validateJSONDefinition(rootNodeDefinitions[0]);\n\n // Did our validation fail without error?\n if (!succeeded) {\n throw new Error(errorMessage);\n }\n } catch (exception) {\n throw new Error(`error registering definition: ${(exception as Error).message}`);\n }\n\n // Everything seems hunky-dory, register the subtree.\n Lookup.setSubtree(name, rootNodeDefinitions[0]);\n } else if (typeof value === \"object\" && !Array.isArray(value)) {\n // We will assume that any object passed in is a root node definition.\n\n try {\n // We should validate the subtree as we don't want invalid subtrees available via the lookup.\n const { succeeded, errorMessage } = validateJSONDefinition(value);\n\n // Did our validation fail without error?\n if (!succeeded) {\n throw new Error(errorMessage);\n }\n } catch (exception) {\n throw new Error(`error registering definition: ${(exception as Error).message}`);\n }\n\n // Everything seems hunky-dory, register the subtree.\n Lookup.setSubtree(name, value);\n } else {\n throw new Error(\"unexpected value, expected string mdsl definition, root node json definition or function\");\n }\n }\n\n /**\n * Unregisters the registered action/condition/guard/callback function or subtree with the given name.\n * @param name The name of the registered action/condition/guard/callback function or subtree to unregister.\n */\n static unregister(name: string): void {\n Lookup.remove(name);\n }\n\n /**\n * Unregister all registered action/condition/guard/callback functions and subtrees.\n */\n static unregisterAll(): void {\n Lookup.empty();\n }\n}\n"], + "mappings": "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", "names": ["Participant", "isNullOrUndefined", "Lotto", "createLotto", "State", "createLotto"] } diff --git a/src/BehaviourTreeDefinition.ts b/src/BehaviourTreeDefinition.ts index edb42bc..70776ff 100644 --- a/src/BehaviourTreeDefinition.ts +++ b/src/BehaviourTreeDefinition.ts @@ -85,11 +85,11 @@ export interface ActionNodeDefinition extends NodeDefinition { */ type: "action"; /** - * The name of the agent function to invoke. + * The name of the agent function or registered function to invoke. */ call: string; /** - * An array of arguments to pass when invoking the agent function. + * An array of arguments to pass when invoking the action function. */ args?: any[]; } @@ -103,11 +103,11 @@ export interface ConditionNodeDefinition extends NodeDefinition { */ type: "condition"; /** - * The name of the agent function to invoke. + * The name of the agent function or registered function to invoke. */ call: string; /** - * An array of arguments to pass when invoking the agent function. + * An array of arguments to pass when invoking the condition function. */ args?: any[]; } diff --git a/src/nodes/leaf/Action.ts b/src/nodes/leaf/Action.ts index a35387a..8ae386f 100644 --- a/src/nodes/leaf/Action.ts +++ b/src/nodes/leaf/Action.ts @@ -57,14 +57,21 @@ export default class Action extends Leaf { ); } - // Call the action function, the result of which may be: - // - The finished state of this action node. - // - A promise to return a finished node state. - // - Undefined if the node should remain in the running state. - const updateResult = actionFuncInvoker(this.actionArguments) as CompleteState | Promise; - - if (updateResult instanceof Promise) { - updateResult.then( + let actionFunctionResult; + + try { + // Call the action function, the result of which may be: + // - The finished state of this action node. + // - A promise to return a finished node state. + // - Undefined if the node should remain in the running state. + actionFunctionResult = actionFuncInvoker(this.actionArguments) as CompleteState | Promise; + } catch (error) { + // The user was naughty and threw something. + throw new Error(`action function '${this.actionName}' threw '${error}'`); + } + + if (actionFunctionResult instanceof Promise) { + actionFunctionResult.then( (result) => { // If 'isUpdatePromisePending' is null then the promise was cleared as it was resolving, probably via an abort of reset. if (!this.isUsingUpdatePromise) { @@ -82,13 +89,15 @@ export default class Action extends Leaf { this.updatePromiseStateResult = result; }, (reason) => { - // If 'isUpdatePromisePending' is null then the promise was cleared as it was resolving, probably via an abort of reset. + // If 'isUpdatePromisePending' is null then the promise was cleared as it was resolving, probably via an abort or reset. if (!this.isUsingUpdatePromise) { return; } - // Just throw whatever was returned as the rejection argument. - throw new Error(reason); + // TODO We shouldn't throw an error here, we actually need to set this.updatePromiseRejectionReason so that it can be thrown on the next tree.step() call. + + // The promise was rejected, which isn't great. + throw new Error(`action function '${this.actionName}' promise rejected with reason '${reason}'`); } ); @@ -99,10 +108,10 @@ export default class Action extends Leaf { this.isUsingUpdatePromise = true; } else { // Validate the returned value. - this.validateUpdateResult(updateResult); + this.validateUpdateResult(actionFunctionResult); // Set the state of this node, this may be undefined, which just means that the node is still in the 'RUNNING' state. - this.setState(updateResult || State.RUNNING); + this.setState(actionFunctionResult || State.RUNNING); } } diff --git a/src/nodes/leaf/Condition.ts b/src/nodes/leaf/Condition.ts index bb00971..f389d43 100644 --- a/src/nodes/leaf/Condition.ts +++ b/src/nodes/leaf/Condition.ts @@ -35,8 +35,25 @@ export default class Condition extends Leaf { ); } - // Call the condition function to determine the state of this node. - this.setState(!!conditionFuncInvoker(this.conditionArguments) ? State.SUCCEEDED : State.FAILED); + let conditionFunctionResult; + + try { + // Call the condition function to determine the state of this node, the result of which should be a boolean. + conditionFunctionResult = conditionFuncInvoker(this.conditionArguments); + } catch (error) { + // The user was naughty and threw something. + throw new Error(`condition function '${this.conditionName}' threw '${error}'`); + } + + // The result of calling the condition function must be a boolean value. + if (typeof conditionFunctionResult !== "boolean") { + throw new Error( + `expected condition function '${this.conditionName}' to return a boolean but returned '${conditionFunctionResult}'` + ); + } + + // Set the state of this node based on the result of calling the condition function. + this.setState(!!conditionFunctionResult ? State.SUCCEEDED : State.FAILED); } /** diff --git a/test/nodes/leaf/Action.spec.ts b/test/nodes/leaf/Action.spec.ts index f9c6c6b..5c6dbfb 100644 --- a/test/nodes/leaf/Action.spec.ts +++ b/test/nodes/leaf/Action.spec.ts @@ -7,90 +7,230 @@ import { Agent } from "../../../src/Agent"; import { findNode } from "../../TestUtilities"; describe("An Action node", () => { + beforeEach(() => BehaviourTree.unregisterAll()); + describe("on tree initialisation", () => { - it("will error if an action name identifier is not the first node argument", () => { - const definition = "root { action [] }"; - assert.throws( - () => new BehaviourTree(definition, {}), - Error, - "invalid definition: expected action name identifier argument" - ); + describe("will error if no action function name is defined", () => { + it("(MDSL)", () => { + const definition = "root { action [] }"; + assert.throws( + () => new BehaviourTree(definition, {}), + Error, + "invalid definition: expected action name identifier argument" + ); + }); + + it("(JSON)", () => { + const definition = { + type: "root", + child: { + type: "action" + } + } as any; + assert.throws( + () => new BehaviourTree(definition, {}), + Error, + "invalid definition: expected non-empty string for 'call' property of action node at depth '1'" + ); + }); }); }); describe("when updated as part of a tree step", () => { describe("will call the function defined by the first node argument", () => { describe("when the referenced function is", () => { - it("a registered function", () => { - BehaviourTree.register("doAction", () => { - return State.SUCCEEDED; - }); + describe("a registered function", () => { + it("(MDSL)", () => { + const definition = "root { action [doAction] }"; - const definition = "root { action [doAction] }"; - const tree = new BehaviourTree(definition, {}); + BehaviourTree.register("doAction", () => { + return State.SUCCEEDED; + }); - tree.step(); + const tree = new BehaviourTree(definition, {}); - const node = findNode(tree, "action", "doAction"); - assert.strictEqual(node.state, State.SUCCEEDED); - }); + tree.step(); + + const node = findNode(tree, "action", "doAction"); + assert.strictEqual(node.state, State.SUCCEEDED); + }); + + it("(JSON)", () => { + const definition: RootNodeDefinition = { + type: "root", + child: { + type: "action", + call: "doAction" + } + }; + + BehaviourTree.register("doAction", () => { + return State.SUCCEEDED; + }); - it("an agent function", () => { - const definition = "root { action [doAction] }"; - const agent = { doAction: () => State.SUCCEEDED }; - const tree = new BehaviourTree(definition, agent); + const tree = new BehaviourTree(definition, {}); - tree.step(); + tree.step(); - const node = findNode(tree, "action", "doAction"); - assert.strictEqual(node.state, State.SUCCEEDED); + const node = findNode(tree, "action", "doAction"); + assert.strictEqual(node.state, State.SUCCEEDED); + }); }); - }); - it("and will error if there is no agent function or registered function that matches the action name", () => { - const definition = "root { action [DoTheThing] }"; - let tree: BehaviourTree; - assert.doesNotThrow(() => (tree = new BehaviourTree(definition, {})), Error); - assert.throws( - () => tree.step(), - Error, - "error stepping tree: cannot update action node as the action 'DoTheThing' function is not defined on the agent and has not been registered" - ); - }); + describe("an agent function", () => { + it("(MDSL)", () => { + const definition = "root { action [doAction] }"; + const agent = { doAction: () => State.SUCCEEDED }; + const tree = new BehaviourTree(definition, agent); - describe("and move to", () => { - it("the SUCCESS state if the function returns a value of State.SUCCEEDED", () => { - const definition = "root { action [doAction] }"; - const agent = { doAction: () => State.SUCCEEDED }; - const tree = new BehaviourTree(definition, agent); + tree.step(); + + const node = findNode(tree, "action", "doAction"); + assert.strictEqual(node.state, State.SUCCEEDED); + }); - let node = findNode(tree, "action", "doAction"); - assert.strictEqual(node.state, State.READY); + it("(JSON)", () => { + const definition: RootNodeDefinition = { + type: "root", + child: { + type: "action", + call: "doAction" + } + }; + const agent = { doAction: () => State.SUCCEEDED }; + const tree = new BehaviourTree(definition, agent); - tree.step(); + tree.step(); - node = findNode(tree, "action", "doAction"); - assert.strictEqual(node.state, State.SUCCEEDED); + const node = findNode(tree, "action", "doAction"); + assert.strictEqual(node.state, State.SUCCEEDED); + }); }); + }); - it("the FAILED state if the function returns a value of State.FAILED", () => { - const definition = "root { action [doAction] }"; - const agent = { doAction: () => State.FAILED }; - const tree = new BehaviourTree(definition, agent); + describe("and will error if", () => { + describe("there is no agent function or registered function that matches the action name", () => { + it("(MDSL)", () => { + const definition = "root { action [DoTheThing] }"; + let tree: BehaviourTree; + assert.doesNotThrow(() => (tree = new BehaviourTree(definition, {})), Error); + assert.throws( + () => tree.step(), + Error, + "error stepping tree: cannot update action node as the action 'DoTheThing' function is not defined on the agent and has not been registered" + ); + }); + + it("(JSON)", () => { + const definition: RootNodeDefinition = { + type: "root", + child: { + type: "action", + call: "DoTheThing" + } + }; + let tree: BehaviourTree; + assert.doesNotThrow(() => (tree = new BehaviourTree(definition, {})), Error); + assert.throws( + () => tree.step(), + Error, + "error stepping tree: cannot update action node as the action 'DoTheThing' function is not defined on the agent and has not been registered" + ); + }); + }); - let node = findNode(tree, "action", "doAction"); - assert.strictEqual(node.state, State.READY); + describe("the action function", () => { + describe("throws an error object", () => { + it("(MDSL)", () => { + const definition = "root { action [doAction] }"; + const agent = { + doAction: () => { + throw new Error("Disaster!"); + } + }; + const tree = new BehaviourTree(definition, agent); + + assert.throws( + () => tree.step(), + Error, + "error stepping tree: action function 'doAction' threw 'Error: Disaster!'" + ); + }); + + it("(JSON)", () => { + const definition: RootNodeDefinition = { + type: "root", + child: { + type: "action", + call: "doAction" + } + }; + const agent = { + doAction: () => { + throw new Error("Disaster!"); + } + }; + const tree = new BehaviourTree(definition, agent); + + assert.throws( + () => tree.step(), + Error, + "error stepping tree: action function 'doAction' threw 'Error: Disaster!'" + ); + }); + }); - tree.step(); + describe("throws something that isn't an error object", () => { + it("(MDSL)", () => { + const definition = "root { action [doAction] }"; + const agent = { + doAction: () => { + throw "Disaster!"; + } + }; + const tree = new BehaviourTree(definition, agent); + + assert.throws( + () => tree.step(), + Error, + "error stepping tree: action function 'doAction' threw 'Disaster!'" + ); + }); + + it("(JSON)", () => { + const definition: RootNodeDefinition = { + type: "root", + child: { + type: "action", + call: "doAction" + } + }; + const agent = { + doAction: () => { + throw "Disaster!"; + } + }; + const tree = new BehaviourTree(definition, agent); + + assert.throws( + () => tree.step(), + Error, + "error stepping tree: action function 'doAction' threw 'Disaster!'" + ); + }); + }); - node = findNode(tree, "action", "doAction"); - assert.strictEqual(node.state, State.FAILED); + describe("returns a rejected promise", () => { + it("(MDSL)", () => {}); + }); }); + }); - describe("the RUNNING state if", () => { - it("the function returns undefined", () => { + describe("and move to", () => { + describe("the SUCCESS state if the function returns a value of State.SUCCEEDED", () => { + it("(MDSL)", () => { const definition = "root { action [doAction] }"; - const agent = { doAction: () => {} }; + const agent = { doAction: () => State.SUCCEEDED }; const tree = new BehaviourTree(definition, agent); let node = findNode(tree, "action", "doAction"); @@ -99,14 +239,18 @@ describe("An Action node", () => { tree.step(); node = findNode(tree, "action", "doAction"); - assert.strictEqual(node.state, State.RUNNING); + assert.strictEqual(node.state, State.SUCCEEDED); }); - it("the function returns a promise to return a value of State.SUCCEEDED or State.FAILED", (done) => { - const result: Promise = new Promise((resolve) => resolve(State.SUCCEEDED)); - - const definition = "root { action [doAction] }"; - const agent = { doAction: () => result }; + it("(JSON)", () => { + const definition: RootNodeDefinition = { + type: "root", + child: { + type: "action", + call: "doAction" + } + }; + const agent = { doAction: () => State.SUCCEEDED }; const tree = new BehaviourTree(definition, agent); let node = findNode(tree, "action", "doAction"); @@ -114,94 +258,351 @@ describe("An Action node", () => { tree.step(); - result - .then(() => tree.step()) - .then(() => { - node = findNode(tree, "action", "doAction"); - assert.strictEqual(node.state, State.SUCCEEDED); - }) - .then(done); + node = findNode(tree, "action", "doAction"); + assert.strictEqual(node.state, State.SUCCEEDED); }); }); - }); - describe("and pass any node arguments that follow the action name identifier argument where", () => { - describe("the argument is a", () => { - it("string", () => { - const definition = 'root { action [doAction, "hello world!"] }'; - const agent = { - doAction: (arg: any) => assert.strictEqual(arg, "hello world!") - }; + describe("the FAILED state if the function returns a value of State.FAILED", () => { + it("(MDSL)", () => { + const definition = "root { action [doAction] }"; + const agent = { doAction: () => State.FAILED }; const tree = new BehaviourTree(definition, agent); + let node = findNode(tree, "action", "doAction"); + assert.strictEqual(node.state, State.READY); + tree.step(); + + node = findNode(tree, "action", "doAction"); + assert.strictEqual(node.state, State.FAILED); }); - it("string with escaped quotes", () => { - const definition = 'root { action [doAction, "hello \\" world!"] }'; - const agent = { - doAction: (arg: any) => assert.strictEqual(arg, 'hello " world!') + it("(JSON)", () => { + const definition: RootNodeDefinition = { + type: "root", + child: { + type: "action", + call: "doAction" + } }; + const agent = { doAction: () => State.FAILED }; const tree = new BehaviourTree(definition, agent); + let node = findNode(tree, "action", "doAction"); + assert.strictEqual(node.state, State.READY); + tree.step(); + + node = findNode(tree, "action", "doAction"); + assert.strictEqual(node.state, State.FAILED); }); + }); - it("number", () => { - const definition = "root { action [doAction, 23.4567] }"; - const agent = { - doAction: (arg: any) => assert.strictEqual(arg, 23.4567) - }; - const tree = new BehaviourTree(definition, agent); + describe("the RUNNING state if", () => { + describe("the function returns undefined", () => { + it("(MDSL)", () => { + const definition = "root { action [doAction] }"; + const agent = { doAction: () => {} }; + const tree = new BehaviourTree(definition, agent); + + let node = findNode(tree, "action", "doAction"); + assert.strictEqual(node.state, State.READY); + + tree.step(); + + node = findNode(tree, "action", "doAction"); + assert.strictEqual(node.state, State.RUNNING); + }); + + it("(JSON)", () => { + const definition: RootNodeDefinition = { + type: "root", + child: { + type: "action", + call: "doAction" + } + }; + const agent = { doAction: () => {} }; + const tree = new BehaviourTree(definition, agent); + + let node = findNode(tree, "action", "doAction"); + assert.strictEqual(node.state, State.READY); + + tree.step(); + + node = findNode(tree, "action", "doAction"); + assert.strictEqual(node.state, State.RUNNING); + }); + }); - tree.step(); + describe("the function returns a promise to return a value of State.SUCCEEDED or State.FAILED", () => { + it("(MDSL)", (done) => { + const definition = "root { action [doAction] }"; + + const result: Promise = new Promise((resolve) => resolve(State.SUCCEEDED)); + const agent = { doAction: () => result }; + const tree = new BehaviourTree(definition, agent); + + let node = findNode(tree, "action", "doAction"); + assert.strictEqual(node.state, State.READY); + + tree.step(); + + result + .then(() => tree.step()) + .then(() => { + node = findNode(tree, "action", "doAction"); + assert.strictEqual(node.state, State.SUCCEEDED); + }) + .then(done); + }); + + it("(JSON)", (done) => { + const definition: RootNodeDefinition = { + type: "root", + child: { + type: "action", + call: "doAction" + } + }; + + const result: Promise = new Promise((resolve) => resolve(State.SUCCEEDED)); + const agent = { doAction: () => result }; + const tree = new BehaviourTree(definition, agent); + + let node = findNode(tree, "action", "doAction"); + assert.strictEqual(node.state, State.READY); + + tree.step(); + + result + .then(() => tree.step()) + .then(() => { + node = findNode(tree, "action", "doAction"); + assert.strictEqual(node.state, State.SUCCEEDED); + }) + .then(done); + }); }); + }); + }); - it("boolean 'true' literal", () => { - const definition = "root { action [doAction, true] }"; - const agent = { - doAction: (arg: any) => assert.strictEqual(arg, true) - }; - const tree = new BehaviourTree(definition, agent); + describe("and pass any node arguments that follow the action name identifier argument where", () => { + describe("the argument is a", () => { + describe("string", () => { + it("(MDSL)", () => { + const definition = 'root { action [doAction, "hello world!"] }'; + const agent = { + doAction: (arg: any) => assert.strictEqual(arg, "hello world!") + }; + const tree = new BehaviourTree(definition, agent); + + tree.step(); + }); + + it("(JSON)", () => { + const definition: RootNodeDefinition = { + type: "root", + child: { + type: "action", + call: "doAction", + args: ["hello world!"] + } + }; + const agent = { + doAction: (arg: any) => assert.strictEqual(arg, "hello world!") + }; + const tree = new BehaviourTree(definition, agent); + + tree.step(); + }); + }); - tree.step(); + describe("string with escaped quotes", () => { + it("(MDSL)", () => { + const definition = 'root { action [doAction, "hello \\" world!"] }'; + const agent = { + doAction: (arg: any) => assert.strictEqual(arg, 'hello " world!') + }; + const tree = new BehaviourTree(definition, agent); + + tree.step(); + }); + + it("(JSON)", () => { + const definition: RootNodeDefinition = { + type: "root", + child: { + type: "action", + call: "doAction", + args: ['hello " world!'] + } + }; + const agent = { + doAction: (arg: any) => assert.strictEqual(arg, 'hello " world!') + }; + const tree = new BehaviourTree(definition, agent); + + tree.step(); + }); }); - it("boolean 'false' literal", () => { - const definition = "root { action [doAction, false] }"; + describe("number", () => { + it("(MDSL)", () => { + const definition = "root { action [doAction, 23.4567] }"; + const agent = { + doAction: (arg: any) => assert.strictEqual(arg, 23.4567) + }; + const tree = new BehaviourTree(definition, agent); + + tree.step(); + }); + + it("(JSON)", () => { + const definition: RootNodeDefinition = { + type: "root", + child: { + type: "action", + call: "doAction", + args: [23.4567] + } + }; + const agent = { + doAction: (arg: any) => assert.strictEqual(arg, 23.4567) + }; + const tree = new BehaviourTree(definition, agent); + + tree.step(); + }); + }); + + describe("boolean 'true' literal", () => { + it("(MDSL)", () => { + const definition = "root { action [doAction, true] }"; + const agent = { + doAction: (arg: any) => assert.strictEqual(arg, true) + }; + const tree = new BehaviourTree(definition, agent); + + tree.step(); + }); + + it("(JSON)", () => { + const definition: RootNodeDefinition = { + type: "root", + child: { + type: "action", + call: "doAction", + args: [true] + } + }; + const agent = { + doAction: (arg: any) => assert.strictEqual(arg, true) + }; + const tree = new BehaviourTree(definition, agent); + + tree.step(); + }); + }); + + describe("boolean 'false' literal", () => { + it("(MDSL)", () => { + const definition = "root { action [doAction, false] }"; + const agent = { + doAction: (arg: any) => assert.strictEqual(arg, false) + }; + const tree = new BehaviourTree(definition, agent); + + tree.step(); + }); + + it("(JSON)", () => { + const definition: RootNodeDefinition = { + type: "root", + child: { + type: "action", + call: "doAction", + args: [false] + } + }; + const agent = { + doAction: (arg: any) => assert.strictEqual(arg, false) + }; + const tree = new BehaviourTree(definition, agent); + + tree.step(); + }); + }); + + describe("null", () => { + it("(MDSL)", () => { + const definition = "root { action [doAction, null] }"; + const agent = { + doAction: (arg: any) => assert.isNull(arg) + }; + const tree = new BehaviourTree(definition, agent); + + tree.step(); + }); + + it("(JSON)", () => { + const definition: RootNodeDefinition = { + type: "root", + child: { + type: "action", + call: "doAction", + args: [null] + } + }; + const agent = { + doAction: (arg: any) => assert.isNull(arg) + }; + const tree = new BehaviourTree(definition, agent); + + tree.step(); + }); + }); + }); + + describe("there are multiple arguments", () => { + it("(MDSL)", () => { + const definition = 'root { action [doAction, 1.23, "hello world!", false, null] }'; const agent = { - doAction: (arg: any) => assert.strictEqual(arg, false) + doAction: (arg0: any, arg1: any, arg2: any, arg3: any) => { + assert.strictEqual(arg0, 1.23); + assert.strictEqual(arg1, "hello world!"); + assert.strictEqual(arg2, false); + assert.strictEqual(arg3, null); + } }; const tree = new BehaviourTree(definition, agent); tree.step(); }); - it("null", () => { - const definition = "root { action [doAction, null] }"; + it("(JSON)", () => { + const definition: RootNodeDefinition = { + type: "root", + child: { + type: "action", + call: "doAction", + args: [1.23, "hello world!", false, null] + } + }; const agent = { - doAction: (arg: any) => assert.isNull(arg) + doAction: (arg0: any, arg1: any, arg2: any, arg3: any) => { + assert.strictEqual(arg0, 1.23); + assert.strictEqual(arg1, "hello world!"); + assert.strictEqual(arg2, false); + assert.strictEqual(arg3, null); + } }; const tree = new BehaviourTree(definition, agent); tree.step(); }); }); - - it("there are multiple arguments", () => { - const definition = 'root { action [doAction, 1.23, "hello world!", false, null] }'; - const agent = { - doAction: (arg0: any, arg1: any, arg2: any, arg3: any) => { - assert.strictEqual(arg0, 1.23); - assert.strictEqual(arg1, "hello world!"); - assert.strictEqual(arg2, false); - assert.strictEqual(arg3, null); - } - }; - const tree = new BehaviourTree(definition, agent); - - tree.step(); - }); }); }); }); diff --git a/test/nodes/leaf/Condition.spec.ts b/test/nodes/leaf/Condition.spec.ts index 705152d..92a18b1 100644 --- a/test/nodes/leaf/Condition.spec.ts +++ b/test/nodes/leaf/Condition.spec.ts @@ -106,33 +106,67 @@ describe("A Condition node", () => { }); }); - describe("and will error if there is no agent function or registered function that matches the condition name", () => { - it("(MDSL)", () => { - const definition = "root { condition [someCondition] }"; - let tree: BehaviourTree; - assert.doesNotThrow(() => (tree = new BehaviourTree(definition, {})), Error); - assert.throws( - () => tree.step(), - Error, - "error stepping tree: cannot update condition node as the condition 'someCondition' function is not defined on the agent and has not been registered" - ); + describe("and will error if", () => { + describe("there is no agent function or registered function that matches the condition name", () => { + it("(MDSL)", () => { + const definition = "root { condition [someCondition] }"; + let tree: BehaviourTree; + assert.doesNotThrow(() => (tree = new BehaviourTree(definition, {})), Error); + assert.throws( + () => tree.step(), + Error, + "error stepping tree: cannot update condition node as the condition 'someCondition' function is not defined on the agent and has not been registered" + ); + }); + + it("(JSON)", () => { + const definition: RootNodeDefinition = { + type: "root", + child: { + type: "condition", + call: "someCondition" + } + }; + let tree: BehaviourTree; + assert.doesNotThrow(() => (tree = new BehaviourTree(definition, {})), Error); + assert.throws( + () => tree.step(), + Error, + "error stepping tree: cannot update condition node as the condition 'someCondition' function is not defined on the agent and has not been registered" + ); + }); }); - it("(JSON)", () => { - const definition: RootNodeDefinition = { - type: "root", - child: { - type: "condition", - call: "someCondition" - } - }; - let tree: BehaviourTree; - assert.doesNotThrow(() => (tree = new BehaviourTree(definition, {})), Error); - assert.throws( - () => tree.step(), - Error, - "error stepping tree: cannot update condition node as the condition 'someCondition' function is not defined on the agent and has not been registered" - ); + describe("the agent function does not return a boolean value", () => { + it("(MDSL)", () => { + const definition = "root { condition [someCondition] }"; + const agent = { someCondition: () => null }; + const tree = new BehaviourTree(definition, agent); + + assert.throws( + () => tree.step(), + Error, + "error stepping tree: expected condition function 'someCondition' to return a boolean but returned 'null'" + ); + }); + + it("(JSON)", () => { + const definition: RootNodeDefinition = { + type: "root", + child: { + type: "condition", + call: "someCondition" + } + }; + const agent = { someCondition: () => null }; + const tree = new BehaviourTree(definition, agent); + + assert.throws( + () => tree.step(), + Error, + "error stepping tree: expected condition function 'someCondition' to return a boolean but returned 'null'" + ); + }); }); }); @@ -216,7 +250,10 @@ describe("A Condition node", () => { it("(MDSL)", () => { const definition = 'root { condition [someCondition, "hello world!"] }'; const agent = { - someCondition: (arg: any) => assert.strictEqual(arg, "hello world!") + someCondition: (arg: any) => { + assert.strictEqual(arg, "hello world!"); + return true; + } }; const tree = new BehaviourTree(definition, agent); @@ -233,7 +270,10 @@ describe("A Condition node", () => { } }; const agent = { - someCondition: (arg: any) => assert.strictEqual(arg, "hello world!") + someCondition: (arg: any) => { + assert.strictEqual(arg, "hello world!"); + return true; + } }; const tree = new BehaviourTree(definition, agent); @@ -245,7 +285,10 @@ describe("A Condition node", () => { it("(MDSL)", () => { const definition = 'root { condition [someCondition, "hello \\" world!"] }'; const agent = { - someCondition: (arg: any) => assert.strictEqual(arg, 'hello " world!') + someCondition: (arg: any) => { + assert.strictEqual(arg, 'hello " world!'); + return true; + } }; const tree = new BehaviourTree(definition, agent); @@ -262,7 +305,10 @@ describe("A Condition node", () => { } }; const agent = { - someCondition: (arg: any) => assert.strictEqual(arg, 'hello " world!') + someCondition: (arg: any) => { + assert.strictEqual(arg, 'hello " world!'); + return true; + } }; const tree = new BehaviourTree(definition, agent); @@ -274,7 +320,10 @@ describe("A Condition node", () => { it("(MDSL)", () => { const definition = "root { condition [someCondition, 23.4567] }"; const agent = { - someCondition: (arg: any) => assert.strictEqual(arg, 23.4567) + someCondition: (arg: any) => { + assert.strictEqual(arg, 23.4567); + return true; + } }; const tree = new BehaviourTree(definition, agent); @@ -291,7 +340,10 @@ describe("A Condition node", () => { } }; const agent = { - someCondition: (arg: any) => assert.strictEqual(arg, 23.4567) + someCondition: (arg: any) => { + assert.strictEqual(arg, 23.4567); + return true; + } }; const tree = new BehaviourTree(definition, agent); @@ -303,7 +355,10 @@ describe("A Condition node", () => { it("(MDSL)", () => { const definition = "root { condition [someCondition, true] }"; const agent = { - someCondition: (arg: any) => assert.strictEqual(arg, true) + someCondition: (arg: any) => { + assert.strictEqual(arg, true); + return true; + } }; const tree = new BehaviourTree(definition, agent); @@ -320,7 +375,10 @@ describe("A Condition node", () => { } }; const agent = { - someCondition: (arg: any) => assert.strictEqual(arg, true) + someCondition: (arg: any) => { + assert.strictEqual(arg, true); + return true; + } }; const tree = new BehaviourTree(definition, agent); @@ -332,7 +390,10 @@ describe("A Condition node", () => { it("(MDSL)", () => { const definition = "root { condition [someCondition, false] }"; const agent = { - someCondition: (arg: any) => assert.strictEqual(arg, false) + someCondition: (arg: any) => { + assert.strictEqual(arg, false); + return true; + } }; const tree = new BehaviourTree(definition, agent); @@ -349,7 +410,10 @@ describe("A Condition node", () => { } }; const agent = { - someCondition: (arg: any) => assert.strictEqual(arg, false) + someCondition: (arg: any) => { + assert.strictEqual(arg, false); + return true; + } }; const tree = new BehaviourTree(definition, agent); @@ -361,7 +425,10 @@ describe("A Condition node", () => { it("(MDSL)", () => { const definition = "root { condition [someCondition, null] }"; const agent = { - someCondition: (arg: any) => assert.isNull(arg) + someCondition: (arg: any) => { + assert.isNull(arg); + return true; + } }; const tree = new BehaviourTree(definition, agent); @@ -378,7 +445,10 @@ describe("A Condition node", () => { } }; const agent = { - someCondition: (arg: any) => assert.isNull(arg) + someCondition: (arg: any) => { + assert.isNull(arg); + return true; + } }; const tree = new BehaviourTree(definition, agent); @@ -396,6 +466,7 @@ describe("A Condition node", () => { assert.strictEqual(arg1, "hello world!"); assert.strictEqual(arg2, false); assert.strictEqual(arg3, null); + return true; } }; const tree = new BehaviourTree(definition, agent); @@ -418,6 +489,7 @@ describe("A Condition node", () => { assert.strictEqual(arg1, "hello world!"); assert.strictEqual(arg2, false); assert.strictEqual(arg3, null); + return true; } }; const tree = new BehaviourTree(definition, agent); From 7c54e03517ec521c14580e89e52120b3b2f63d86 Mon Sep 17 00:00:00 2001 From: Nikolas Howard Date: Mon, 26 Feb 2024 17:48:30 +0000 Subject: [PATCH 35/48] Fixed issues with action nodes not handling update promise rejections properly and added specs --- README.md | 139 ++++++++++++++++++++++++++- dist/bundle.js | 36 ++++--- dist/bundle.js.map | 4 +- dist/index.js | 36 ++++--- dist/index.js.map | 4 +- dist/nodes/leaf/Action.d.ts | 2 +- src/nodes/leaf/Action.ts | 76 ++++++++++----- test/nodes/decorator/Fail.spec.ts | 2 +- test/nodes/decorator/Flip.spec.ts | 2 +- test/nodes/decorator/Repeat.spec.ts | 2 +- test/nodes/decorator/Retry.spec.ts | 2 +- test/nodes/decorator/Root.spec.ts | 66 +++++++++++++ test/nodes/decorator/Succeed.spec.ts | 2 +- test/nodes/leaf/Action.spec.ts | 94 ++++++++++++++---- 14 files changed, 388 insertions(+), 79 deletions(-) create mode 100644 test/nodes/decorator/Root.spec.ts diff --git a/README.md b/README.md index 562b233..baf9786 100644 --- a/README.md +++ b/README.md @@ -2,9 +2,9 @@ [![npm version](https://badge.fury.io/js/mistreevous.svg)](https://badge.fury.io/js/mistreevous) [![Node.js CI](https://github.com/nikkorn/mistreevous/actions/workflows/node.js.yml/badge.svg?branch=master)](https://github.com/nikkorn/mistreevous/actions/workflows/node.js.yml) -A tool to declaratively define and generate behaviour trees, built using Typescript. Behaviour trees are used to create complex AI via the modular heirarchical composition of individual tasks. +A library to declaratively define, build and execute behaviour trees, written in Typescript. Behaviour trees are used to create complex AI via the modular heirarchical composition of individual tasks. -Using this tool, trees can be defined with a simple and minimal built-in DSL, avoiding the need to write verbose definitions in JSON. +Using this tool, trees can be defined with either JSON or a simple and minimal built-in DSL (MDSL), avoiding the need to write verbose definitions in JSON. ![Sorting Lunch](resources/images/sorting-lunch-example.png?raw=true "Sorting Lunch") @@ -97,6 +97,7 @@ Composite nodes wrap one or more child nodes, each of which will be processed in This composite node will update each child node in sequence. It will succeed if all of its children have succeeded and will fail if any of its children fail. This node will remain in the running state if one of its children is running. [Example](https://nikkorn.github.io/mistreevous-visualiser/index.html?example=sequence) +*MDSL* ``` root { sequence { @@ -107,10 +108,35 @@ root { } ``` +*JSON* +```js +{ + "type": "root", + "child": { + "type": "sequence", + "children": [ + { + "type": "action", + "call": "Walk" + }, + { + "type": "action", + "call": "Fall" + }, + { + "type": "action", + "call": "Laugh" + } + ] + } +} +``` + ### Selector This composite node will update each child node in sequence. It will fail if all of its children have failed and will succeed if any of its children succeed. This node will remain in the running state if one of its children is running. [Example](https://nikkorn.github.io/mistreevous-visualiser/index.html?example=selector) +*MDSL* ``` root { selector { @@ -121,10 +147,35 @@ root { } ``` +*JSON* +```js +{ + "type": "root", + "child": { + "type": "selector", + "children": [ + { + "type": "action", + "call": "TryThis" + }, + { + "type": "action", + "call": "ThenTryThis" + }, + { + "type": "action", + "call": "TryThisLast" + } + ] + } +} +``` + ### Parallel This composite node will update each child node concurrently. It will succeed if all of its children have succeeded and will fail if any of its children fail. This node will remain in the running state if any of its children are running. [Example](https://nikkorn.github.io/mistreevous-visualiser/index.html?example=parallel) +*MDSL* ``` root { parallel { @@ -134,10 +185,31 @@ root { } ``` +*JSON* +```js +{ + "type": "root", + "child": { + "type": "parallel", + "children": [ + { + "type": "action", + "call": "RubBelly" + }, + { + "type": "action", + "call": "PatHead" + } + ] + } +} +``` + ### Lotto This composite node will select a single child at random to run as the active running node. The state of this node will reflect the state of the active child. [Example](https://nikkorn.github.io/mistreevous-visualiser/index.html?example=lotto) +*MDSL* ``` root { lotto { @@ -147,9 +219,30 @@ root { } ``` +*JSON* +```js +{ + "type": "root", + "child": { + "type": "lotto", + "children": [ + { + "type": "action", + "call": "MoveLeft" + }, + { + "type": "action", + "call": "MoveRight" + } + ] + } +} +``` + A probability weight can be defined for each child node as an optional integer node argument, influencing the likelihood that a particular child will be picked. [Example](https://nikkorn.github.io/mistreevous-visualiser/index.html?example=weighted-lotto) +*MDSL* ``` root { lotto [10,5,3,1] { @@ -161,6 +254,35 @@ root { } ``` +*JSON* +```js +{ + "type": "root", + "child": { + "type": "lotto", + "children": [ + { + "type": "action", + "call": "CommonAction" + }, + { + "type": "action", + "call": "UncommonAction" + }, + { + "type": "action", + "call": "RareAction" + }, + { + "type": "action", + "call": "VeryRareAction" + } + ], + "weights": [10, 5, 3, 1] + } +} +``` + ## Decorator Nodes A decorator node is similar to a composite node, but it can only have a single child node. The state of a decorator node is usually some transformation of the state of the child node. Decorator nodes are also used to repeat or terminate execution of a particular node. @@ -169,14 +291,27 @@ This decorator node represents the root of a behaviour tree and cannot be the ch The state of a root node will reflect the state of its child node. +*MDSL* ``` root { action [Dance] } ``` +*JSON* +```js +{ + "type": "root", + "child": { + "type": "action", + "call": "Dance" + } +} +``` + Additional named root nodes can be defined and reused throughout a definition. Other root nodes can be referenced via the **branch** node. Exactly one root node must be left unnamed, this root node will be used as the main root node for the entire tree. +*MDSL* ``` root { branch [SomeOtherTree] diff --git a/dist/bundle.js b/dist/bundle.js index 35ca87f..4b6249f 100644 --- a/dist/bundle.js +++ b/dist/bundle.js @@ -1757,13 +1757,24 @@ var mistreevous = (() => { this.actionArguments = actionArguments; } isUsingUpdatePromise = false; - updatePromiseStateResult = null; + updatePromiseResult = null; onUpdate(agent, options) { if (this.isUsingUpdatePromise) { - if (this.updatePromiseStateResult) { - this.setState(this.updatePromiseStateResult); + if (!this.updatePromiseResult) { + return; + } + const { isResolved, value } = this.updatePromiseResult; + if (isResolved) { + if (value !== "mistreevous.succeeded" /* SUCCEEDED */ && value !== "mistreevous.failed" /* FAILED */) { + throw new Error( + "action node promise resolved with an invalid value, expected a State.SUCCEEDED or State.FAILED value to be returned" + ); + } + this.setState(value); + return; + } else { + throw new Error(`action function '${this.actionName}' promise rejected with '${value}'`); } - return; } const actionFuncInvoker = Lookup.getFuncInvoker(agent, this.actionName); if (actionFuncInvoker === null) { @@ -1783,18 +1794,19 @@ var mistreevous = (() => { if (!this.isUsingUpdatePromise) { return; } - if (result !== "mistreevous.succeeded" /* SUCCEEDED */ && result !== "mistreevous.failed" /* FAILED */) { - throw new Error( - "action node promise resolved with an invalid value, expected a State.SUCCEEDED or State.FAILED value to be returned" - ); - } - this.updatePromiseStateResult = result; + this.updatePromiseResult = { + isResolved: true, + value: result + }; }, (reason) => { if (!this.isUsingUpdatePromise) { return; } - throw new Error(`action function '${this.actionName}' promise rejected with reason '${reason}'`); + this.updatePromiseResult = { + isResolved: false, + value: reason + }; } ); this.setState("mistreevous.running" /* RUNNING */); @@ -1808,7 +1820,7 @@ var mistreevous = (() => { reset = () => { this.setState("mistreevous.ready" /* READY */); this.isUsingUpdatePromise = false; - this.updatePromiseStateResult = null; + this.updatePromiseResult = null; }; validateUpdateResult = (result) => { switch (result) { diff --git a/dist/bundle.js.map b/dist/bundle.js.map index ae52249..d3062ce 100644 --- a/dist/bundle.js.map +++ b/dist/bundle.js.map @@ -1,7 +1,7 @@ { "version": 3, "sources": ["../node_modules/lotto-draw/dist/Participant.js", "../node_modules/lotto-draw/dist/Utilities.js", "../node_modules/lotto-draw/dist/Lotto.js", "../node_modules/lotto-draw/dist/createLotto.js", "../node_modules/lotto-draw/dist/index.js", "../src/index.ts", "../src/State.ts", "../src/BehaviourTreeDefinitionUtilities.ts", "../src/mdsl/MDSLUtilities.ts", "../src/mdsl/MDSLNodeArgumentParser.ts", "../src/mdsl/MDSLNodeAttributeParser.ts", "../src/mdsl/MDSLDefinitionParser.ts", "../src/BehaviourTreeDefinitionValidator.ts", "../src/Lookup.ts", "../src/attributes/guards/GuardUnsatisifedException.ts", "../src/attributes/guards/GuardPath.ts", "../src/nodes/Node.ts", "../src/nodes/composite/Composite.ts", "../src/nodes/composite/Parallel.ts", "../src/nodes/composite/Selector.ts", "../src/nodes/composite/Sequence.ts", "../src/nodes/composite/Lotto.ts", "../src/nodes/decorator/Decorator.ts", "../src/nodes/decorator/Fail.ts", "../src/nodes/decorator/Flip.ts", "../src/nodes/decorator/Repeat.ts", "../src/nodes/decorator/Retry.ts", "../src/nodes/decorator/Root.ts", "../src/nodes/decorator/Succeed.ts", "../src/nodes/leaf/Leaf.ts", "../src/nodes/leaf/Action.ts", "../src/nodes/leaf/Condition.ts", "../src/nodes/leaf/Wait.ts", "../src/attributes/Attribute.ts", "../src/attributes/guards/Guard.ts", "../src/attributes/guards/While.ts", "../src/attributes/guards/Until.ts", "../src/attributes/callbacks/Callback.ts", "../src/attributes/callbacks/Entry.ts", "../src/attributes/callbacks/Step.ts", "../src/attributes/callbacks/Exit.ts", "../src/BehaviourTreeBuilder.ts", "../src/BehaviourTree.ts"], - "sourcesContent": ["\"use strict\";\r\nObject.defineProperty(exports, \"__esModule\", { value: true });\r\nexports.Participant = void 0;\r\n/**\r\n * A participant that holds a number of tickets.\r\n */\r\nvar Participant = /** @class */ (function () {\r\n /**\r\n * Creates an instance of the Participant class.\r\n * @param participant The actual participant.\r\n * @param tickets The number of tickets held by the participant.\r\n */\r\n function Participant(participant, tickets) {\r\n if (tickets === void 0) { tickets = 1; }\r\n this._participant = participant;\r\n this._tickets = tickets;\r\n }\r\n Object.defineProperty(Participant.prototype, \"participant\", {\r\n /** Gets the actual participant. */\r\n get: function () {\r\n return this._participant;\r\n },\r\n enumerable: false,\r\n configurable: true\r\n });\r\n Object.defineProperty(Participant.prototype, \"tickets\", {\r\n /** Gets or sets the number of tickets held by the participant. */\r\n get: function () {\r\n return this._tickets;\r\n },\r\n set: function (value) {\r\n this._tickets = value;\r\n },\r\n enumerable: false,\r\n configurable: true\r\n });\r\n return Participant;\r\n}());\r\nexports.Participant = Participant;\r\n", "\"use strict\";\r\nObject.defineProperty(exports, \"__esModule\", { value: true });\r\nexports.isNaturalNumber = exports.isNullOrUndefined = void 0;\r\n/**\r\n * Gets whether the value provided is null or undefined.\r\n * @param value The value to check.\r\n * @returns Whether the value provided is null or undefined.\r\n */\r\nfunction isNullOrUndefined(value) {\r\n return value === null || value === undefined;\r\n}\r\nexports.isNullOrUndefined = isNullOrUndefined;\r\n/**\r\n * Gets whether the value provided is a natural number.\r\n * @param value The value to check.\r\n * @returns Whether the value provided is a natural number.\r\n */\r\nfunction isNaturalNumber(value) {\r\n return typeof value === \"number\" && value >= 1 && Math.floor(value) === value;\r\n}\r\nexports.isNaturalNumber = isNaturalNumber;\r\n", "\"use strict\";\r\nObject.defineProperty(exports, \"__esModule\", { value: true });\r\nexports.Lotto = void 0;\r\nvar Participant_1 = require(\"./Participant\");\r\nvar Utilities_1 = require(\"./Utilities\");\r\n/**\r\n * Represents a lotto consisting of a number of pickable ticket-holding participants.\r\n */\r\nvar Lotto = /** @class */ (function () {\r\n /**\r\n * Creates a new instance of Lotto.\r\n * @param customRandom The custom RNG to use in place of Math.random().\r\n */\r\n function Lotto(customRandom) {\r\n /** The array of participants that are holding tickets in the lotto. */\r\n this._participants = [];\r\n this._customRandom = customRandom;\r\n }\r\n /**\r\n * Adds a participant with the specified number of tickets, or adds to the participant ticket count if the participant already holds tickets.\r\n * @param participant The participant to add or to increase the ticket count for if they already hold tickets.\r\n * @param tickets The number of tickets, defaults to 1.\r\n * @returns The Lotto instance.\r\n */\r\n Lotto.prototype.add = function (participant, tickets) {\r\n if (tickets === void 0) { tickets = 1; }\r\n // Check that we have a valid ticket count.\r\n if (!(0, Utilities_1.isNaturalNumber)(tickets)) {\r\n throw new Error(\"tickets value must be a natural number\");\r\n }\r\n // Check whether this participant has already been added.\r\n var existingParticipant = this._participants.find(function (part) { return part.participant === participant; });\r\n if (existingParticipant) {\r\n // The participant has already been added to the lotto so just add to their ticket count.\r\n existingParticipant.tickets += tickets;\r\n }\r\n else {\r\n // The participant is not part of the lotto so we should add them.\r\n this._participants.push(new Participant_1.Participant(participant, tickets));\r\n }\r\n return this;\r\n };\r\n /**\r\n * Removes the specified number of tickets for the given participant from the draw, or all tickets if a ticket number is not defined.\r\n * @param participant The participant to remove tickets for.\r\n * @param tickets The number of tickets to remove, or undefined if all tickets are to be removed.\r\n * @returns The Lotto instance.\r\n */\r\n Lotto.prototype.remove = function (participant, tickets) {\r\n // Attempt to get the existing participant.\r\n var existingParticipant = this._participants.find(function (part) { return part.participant === participant; });\r\n // There is nothing to do if the specified participant isn't even part of the lotto.\r\n if (!existingParticipant) {\r\n return this;\r\n }\r\n // Check whether a tickets value was given.\r\n if (tickets !== undefined) {\r\n // Check that we have a valid ticket count.\r\n if (!(0, Utilities_1.isNaturalNumber)(tickets)) {\r\n throw new Error(\"tickets value must be a natural number\");\r\n }\r\n existingParticipant.tickets -= tickets;\r\n // If the participant no longer holds any tickets then they should be removed.\r\n if (existingParticipant.tickets < 1) {\r\n this._participants = this._participants.filter(function (part) { return part !== existingParticipant; });\r\n }\r\n }\r\n else {\r\n // We are removing all tickets for the participant so just remove them from the lotto.\r\n this._participants = this._participants.filter(function (part) { return part !== existingParticipant; });\r\n }\r\n return this;\r\n };\r\n /**\r\n * Draw a winning ticket and return the participant that holds the ticket.\r\n * @param options The draw options.\r\n * @returns The participant that holds the winning ticket.\r\n */\r\n Lotto.prototype.draw = function (options) {\r\n if (options === void 0) { options = {}; }\r\n // If we have no participants then just return null.\r\n if (this._participants.length === 0) {\r\n return null;\r\n }\r\n var redrawable = (0, Utilities_1.isNullOrUndefined)(options.redrawable) ? true : options.redrawable;\r\n var pickable = [];\r\n this._participants.forEach(function (_a) {\r\n var participant = _a.participant, tickets = _a.tickets;\r\n for (var ticketCount = 0; ticketCount < tickets; ticketCount++) {\r\n pickable.push(participant);\r\n }\r\n });\r\n var random;\r\n // We need a random floating-point number between 0 (inclusive) and 1 to scale up to pick our winner.\r\n // If a custom random function exists then we should use that or fall back to Math.random().\r\n if (this._customRandom) {\r\n // Call our custom random function to get a random floating-point number.\r\n random = this._customRandom();\r\n // Verify that the result of calling our custom random function is a number between 0 (inclusive) and 1.\r\n if (typeof random !== \"number\" || random < 0 || random >= 1) {\r\n throw new Error(\"the 'random' function provided did not return a number between 0 (inclusive) and 1\");\r\n }\r\n }\r\n else {\r\n // No custom random function was defined so just use good ol' Math.random().\r\n random = Math.random();\r\n }\r\n // Pick a winning participant.\r\n var winner = pickable[Math.floor(random * pickable.length)];\r\n // If the ticket isn't redrawable then we should remove a ticket from the winning participants ticket count.\r\n if (!redrawable) {\r\n this.remove(winner, 1);\r\n }\r\n // Return the winning participant.\r\n return winner;\r\n };\r\n /**\r\n * Draws multiple winning tickets and return an array of the participants that hold the winning tickets.\r\n * @param tickets The number of winning tickets to draw.\r\n * @param options The draw multiple options.\r\n * @returns An array of the participants that hold the winning tickets.\r\n */\r\n Lotto.prototype.drawMultiple = function (tickets, options) {\r\n if (options === void 0) { options = {}; }\r\n var uniqueResults = (0, Utilities_1.isNullOrUndefined)(options.unique) ? false : options.unique;\r\n // Handle cases where the user has asked for zero tickets (no idea why they would do this be we should trust them).\r\n if (tickets === 0) {\r\n return [];\r\n }\r\n // Now that we know out tickets value is not zero we should check that it is a valid natural number.\r\n if (!(0, Utilities_1.isNaturalNumber)(tickets)) {\r\n throw new Error(\"tickets value must be a natural number\");\r\n }\r\n var result = [];\r\n // Keep drawing tickets until we either reach the number of required tickets or we simply run out of tickets to draw.\r\n // We can run out of tickets to draw if 'options.redrawable' is explicity 'false' or we just had no participants when 'drawMultiple' was called.\r\n while (result.length < tickets && this._participants.length > 0) {\r\n result.push(this.draw(options));\r\n }\r\n // If the 'unique' draw option is set then we need to remove duplicates from the result list.\r\n if (uniqueResults) {\r\n // Create an array to store our unique results.\r\n var unique = [];\r\n // Iterate over all of our participants (with potential duplicates) and populate our array of unique values.\r\n for (var _i = 0, result_1 = result; _i < result_1.length; _i++) {\r\n var participant = result_1[_i];\r\n if (unique.indexOf(participant) === -1) {\r\n unique.push(participant);\r\n }\r\n }\r\n result = unique;\r\n }\r\n return result;\r\n };\r\n return Lotto;\r\n}());\r\nexports.Lotto = Lotto;\r\n", "\"use strict\";\r\nObject.defineProperty(exports, \"__esModule\", { value: true });\r\nexports.createLotto = void 0;\r\nvar Lotto_1 = require(\"./Lotto\");\r\n/**\r\n * A function that creates and returns a Lotto instance.\r\n * @param participantsOrOptions An array of initial participants or options relating to the creation of a Lotto instance.\r\n * @returns A new Lotto instance.\r\n */\r\nfunction createLotto(participantsOrOptions) {\r\n // If no initial participants or lotto options were provided as an argument then we can just return a new lotto instance now.\r\n if (!participantsOrOptions) {\r\n return new Lotto_1.Lotto();\r\n }\r\n // Check whether we were provided with an array of initial participants or a lotto options object.\r\n if (Array.isArray(participantsOrOptions)) {\r\n // We are dealing with a pre-defined array of participants.\r\n var participants = participantsOrOptions;\r\n var lotto_1 = new Lotto_1.Lotto();\r\n // If the lotto participants have been defined upfront then we will need to add them all to our lotto instance now.\r\n participants.forEach(function (_a) {\r\n var participant = _a[0], tokens = _a[1];\r\n return lotto_1.add(participant, tokens);\r\n });\r\n // Return the Lotto instance.\r\n return lotto_1;\r\n }\r\n else {\r\n // We are dealing with some lotto options.\r\n var random = participantsOrOptions.random, participants = participantsOrOptions.participants;\r\n // Create a Lotto instance passing the custom RNG function to use in place of Math.random() (which could be undefined).\r\n var lotto_2 = new Lotto_1.Lotto(random);\r\n // If the lotto participants have been defined upfront as part of the options then we will need to add them all to our lotto instance now.\r\n if (participants) {\r\n participants.forEach(function (_a) {\r\n var participant = _a[0], tokens = _a[1];\r\n return lotto_2.add(participant, tokens);\r\n });\r\n }\r\n // Return the Lotto instance.\r\n return lotto_2;\r\n }\r\n}\r\nexports.createLotto = createLotto;\r\n", "\"use strict\";\r\nObject.defineProperty(exports, \"__esModule\", { value: true });\r\nvar createLotto_1 = require(\"./createLotto\");\r\nexports.default = createLotto_1.createLotto;\r\n", "import State from \"./State\";\nimport { validateDefinition } from \"./BehaviourTreeDefinitionValidator\";\nimport { convertMDSLToJSON } from \"./mdsl/MDSLDefinitionParser\";\nimport { BehaviourTree, FlattenedTreeNode } from \"./BehaviourTree\";\nimport { BehaviourTreeOptions } from \"./BehaviourTreeOptions\";\n\nexport { BehaviourTree, State, convertMDSLToJSON, validateDefinition };\nexport type { FlattenedTreeNode, BehaviourTreeOptions };\n", "/**\n * Enumeration of node state types.\n */\nexport enum State {\n READY = \"mistreevous.ready\",\n RUNNING = \"mistreevous.running\",\n SUCCEEDED = \"mistreevous.succeeded\",\n FAILED = \"mistreevous.failed\"\n}\n\nexport { State as default };\n\nexport type CompleteState = State.SUCCEEDED | State.FAILED;\nexport type AnyState = State.READY | State.RUNNING | CompleteState;\n", "import {\n NodeDefinition,\n RootNodeDefinition,\n DecoratorNodeDefinition,\n CompositeNodeDefinition,\n AnyNodeDefinition,\n BranchNodeDefinition\n} from \"./BehaviourTreeDefinition\";\n\n/**\n * A type guard function that returns true if the specified node satisfies the RootNodeDefinition type.\n * @param node The node.\n * @returns A value of true if the specified node satisfies the RootNodeDefinition type.\n */\nexport function isRootNode(node: NodeDefinition): node is RootNodeDefinition {\n return node.type === \"root\";\n}\n\n/**\n * A type guard function that returns true if the specified node satisfies the BranchNodeDefinition type.\n * @param node The node.\n * @returns A value of true if the specified node satisfies the BranchNodeDefinition type.\n */\nexport function isBranchNode(node: NodeDefinition): node is BranchNodeDefinition {\n return node.type === \"branch\";\n}\n\n/**\n * A type guard function that returns true if the specified node satisfies the NodeDefinition type.\n * @param node The node.\n * @returns A value of true if the specified node satisfies the NodeDefinition type.\n */\nexport function isLeafNode(node: NodeDefinition): node is NodeDefinition {\n return [\"branch\", \"action\", \"condition\", \"wait\"].includes(node.type);\n}\n\n/**\n * A type guard function that returns true if the specified node satisfies the DecoratorNodeDefinition type.\n * @param node The node.\n * @returns A value of true if the specified node satisfies the DecoratorNodeDefinition type.\n */\nexport function isDecoratorNode(node: NodeDefinition): node is DecoratorNodeDefinition {\n return [\"root\", \"repeat\", \"retry\", \"flip\", \"succeed\", \"fail\"].includes(node.type);\n}\n\n/**\n * A type guard function that returns true if the specified node satisfies the CompositeNodeDefinition type.\n * @param node The node.\n * @returns A value of true if the specified node satisfies the CompositeNodeDefinition type.\n */\nexport function isCompositeNode(node: NodeDefinition): node is CompositeNodeDefinition {\n return [\"sequence\", \"selector\", \"lotto\", \"parallel\"].includes(node.type);\n}\n\n/**\n * Flatten a node definition into an array of all of its nested node definitions.\n * @param nodeDefinition The node definition to flatten.\n * @returns An array of all of nested node definitions.\n */\nexport function flattenDefinition(nodeDefinition: AnyNodeDefinition): AnyNodeDefinition[] {\n const nodes: AnyNodeDefinition[] = [];\n\n const processNode = (currentNodeDefinition: AnyNodeDefinition) => {\n nodes.push(currentNodeDefinition);\n\n if (isCompositeNode(currentNodeDefinition)) {\n currentNodeDefinition.children.forEach(processNode);\n } else if (isDecoratorNode(currentNodeDefinition)) {\n processNode(currentNodeDefinition.child);\n }\n };\n\n processNode(nodeDefinition);\n\n return nodes;\n}\n\n/**\n * Determines whether the passed value is an integer.\n * @param value The value to check.\n * @returns Whether the passed value is an integer.\n */\nexport function isInteger(value: unknown): boolean {\n return typeof value === \"number\" && Math.floor(value) === value;\n}\n\n/**\n * Determines whether the passed value is null or undefined.\n * @param value The value to check.\n * @returns Whether the passed value is null or undefined.\n */\nexport function isNullOrUndefined(value: unknown): boolean {\n return typeof value === \"undefined\" || value === null;\n}\n", "/**\n * A type defining an object that holds a reference to substitued string literals parsed from the definition.\n */\nexport type StringLiteralPlaceholders = { [key: string]: string };\n\n/**\n * Pop the next raw token from the specified array of tokens and throw an error if it wasn't the expected one.\n * @param tokens The array of tokens.\n * @param expected An optional string or array or items, one of which must match the next popped token.\n * @returns The popped token.\n */\nexport function popAndCheck(tokens: string[], expected?: string | string[]): string {\n // Get and remove the next token.\n const popped = tokens.shift();\n\n // We were expecting another token but there aren't any.\n if (popped === undefined) {\n throw new Error(\"unexpected end of definition\");\n }\n\n // Do we have an expected token/tokens array?\n if (expected != undefined) {\n // Get an array of expected values, if the popped token matches any then we are all good.\n const expectedValues = typeof expected === \"string\" ? [expected] : expected;\n\n // Check whether the popped token matches at least one of our expected items.\n var tokenMatchesExpectation = expectedValues.some((item) => popped.toUpperCase() === item.toUpperCase());\n\n // Throw an error if the popped token didn't match any of our expected items.\n if (!tokenMatchesExpectation) {\n const expectationString = expectedValues.map((item) => \"'\" + item + \"'\").join(\" or \");\n throw new Error(\"unexpected token found. Expected \" + expectationString + \" but got '\" + popped + \"'\");\n }\n }\n\n // Return the popped token.\n return popped;\n}\n\n/**\n * Swaps out any node/attribute argument string literals with placeholders.\n * @param definition The definition.\n * @returns An object containing a mapping of placeholders to original string values as well as the processed definition string.\n */\nexport function substituteStringLiterals(definition: string): {\n placeholders: StringLiteralPlaceholders;\n processedDefinition: string;\n} {\n // Create an object to hold the mapping of placeholders to original string values.\n const placeholders: StringLiteralPlaceholders = {};\n\n // Replace any string literals wrapped with double quotes in our definition with placeholders to be processed later.\n const processedDefinition = definition.replace(/\\\"(\\\\.|[^\"\\\\])*\\\"/g, (match) => {\n var strippedMatch = match.substring(1, match.length - 1);\n var placeholder = Object.keys(placeholders).find((key) => placeholders[key] === strippedMatch);\n\n // If we have no existing string literal match then create a new placeholder.\n if (!placeholder) {\n placeholder = `@@${Object.keys(placeholders).length}@@`;\n placeholders[placeholder] = strippedMatch;\n }\n\n return placeholder;\n });\n\n return { placeholders, processedDefinition };\n}\n\n/**\n * Parse the tree definition into an array of raw tokens.\n * @param definition The definition.\n * @returns An array of tokens parsed from the definition.\n */\nexport function parseTokensFromDefinition(definition: string): string[] {\n // Add some space around various important characters so that they can be plucked out easier as individual tokens.\n definition = definition.replace(/\\(/g, \" ( \");\n definition = definition.replace(/\\)/g, \" ) \");\n definition = definition.replace(/\\{/g, \" { \");\n definition = definition.replace(/\\}/g, \" } \");\n definition = definition.replace(/\\]/g, \" ] \");\n definition = definition.replace(/\\[/g, \" [ \");\n definition = definition.replace(/\\,/g, \" , \");\n\n // Split the definition into raw token form and return it.\n return definition.replace(/\\s+/g, \" \").trim().split(\" \");\n}\n", "import { StringLiteralPlaceholders, popAndCheck } from \"./MDSLUtilities\";\n\n/**\n * A type representing any node function argument.\n */\ntype Argument = {\n /**\n * The argument value.\n */\n value: T;\n /**\n * The argument type, used for validation.\n */\n type: string;\n};\n\ntype NullArgument = Argument & {\n type: \"null\";\n};\n\ntype BooleanArgument = Argument & {\n type: \"boolean\";\n};\n\ntype NumberArgument = Argument & {\n type: \"number\";\n /**\n * A flag defining whether the number argument value is a valid integer. (used for validation)\n */\n isInteger: boolean;\n};\n\ntype StringPlaceholderArgument = Argument & {\n type: \"string\";\n};\n\ntype IdentifierArgument = Argument & {\n type: \"identifier\";\n};\n\n/**\n * A type representing a reference to any node function argument.\n */\ntype AnyArgument = NullArgument | BooleanArgument | NumberArgument | StringPlaceholderArgument | IdentifierArgument;\n\n/**\n * Parse an array of argument definitions from the specified tokens array.\n * @param tokens The array tokens to parse the argument definitions from.\n * @param stringArgumentPlaceholders The mapping of string literal node argument placeholders to original values.\n * @param argumentValidator The argument validator function.\n * @param validationFailedMessage The exception message to throw if argument validation fails.\n * @returns An array of argument definitions parsed from the specified tokens array.\n */\nexport function parseArgumentTokens(\n tokens: string[],\n stringArgumentPlaceholders: StringLiteralPlaceholders\n): AnyArgument[] {\n const argumentList: AnyArgument[] = [];\n\n // If the next token is not a '[' or '(' then we have no arguments to parse.\n if (![\"[\", \"(\"].includes(tokens[0])) {\n return argumentList;\n }\n\n // Any lists of arguments will always be wrapped in '[]' for node arguments or '()' for attribute arguments.\n // We are looking for a '[' or '(' opener that wraps the argument tokens and the relevant closer.\n const closingToken = popAndCheck(tokens, [\"[\", \"(\"]) === \"[\" ? \"]\" : \")\";\n\n const argumentListTokens: string[] = [];\n\n // Grab all tokens between the '[' and ']' or '(' and ')'.\n while (tokens.length && tokens[0] !== closingToken) {\n // The next token is part of our arguments list.\n argumentListTokens.push(tokens.shift()!);\n }\n\n // Validate the order of the argument tokens. Each token must either be a ',' or a single argument that satisfies the validator.\n argumentListTokens.forEach((token, index) => {\n // Get whether this token should be an actual argument.\n const shouldBeArgumentToken = !(index & 1);\n\n // If the current token should be an actual argument then validate it, otherwise it should be a ',' token.\n if (shouldBeArgumentToken) {\n // Get the argument definition.\n const argumentDefinition = getArgumentDefinition(token, stringArgumentPlaceholders);\n\n // This is a valid argument!\n argumentList.push(argumentDefinition);\n } else {\n // The current token should be a ',' token.\n if (token !== \",\") {\n throw new Error(`invalid argument list, expected ',' or ']' but got '${token}'`);\n }\n }\n });\n\n // The arguments list should terminate with a ']' or ')' token, depending on the opener.\n popAndCheck(tokens, closingToken);\n\n // Return the arguments.\n return argumentList;\n}\n\n/**\n * Gets an argument value definition.\n * @param token The argument token.\n * @param stringArgumentPlaceholders The mapping of string literal node argument placeholders to original values.\n * @returns An argument value definition.\n */\nfunction getArgumentDefinition(token: string, stringArgumentPlaceholders: StringLiteralPlaceholders): AnyArgument {\n // Check whether the token represents a null value.\n if (token === \"null\") {\n return {\n value: null,\n type: \"null\"\n } as NullArgument;\n }\n\n // Check whether the token represents a boolean value.\n if (token === \"true\" || token === \"false\") {\n return {\n value: token === \"true\",\n type: \"boolean\"\n } as BooleanArgument;\n }\n\n // Check whether the token represents a number value.\n // TODO: Relies on broken isNaN - see MDN.\n // if (!Number.isNaN(token)) {\n if (!isNaN(token as any)) {\n return {\n value: parseFloat(token),\n isInteger: parseFloat(token) === parseInt(token, 10),\n type: \"number\"\n } as NumberArgument;\n }\n\n // Check whether the token is a placeholder (e.g. @@0@@) representing a string literal.\n if (token.match(/^@@\\d+@@$/g)) {\n return {\n value: stringArgumentPlaceholders[token].replace('\\\\\"', '\"'),\n type: \"string\"\n } as StringPlaceholderArgument;\n }\n\n // The only remaining option is that the argument value is an identifier.\n return {\n value: token,\n type: \"identifier\"\n } as IdentifierArgument;\n}\n", "import { NodeAttributeDefinition } from \"../BehaviourTreeDefinition\";\nimport { parseArgumentTokens } from \"./MDSLNodeArgumentParser\";\nimport { StringLiteralPlaceholders } from \"./MDSLUtilities\";\n\n/**\n * A type defining the attribute definitions of a node.\n */\ntype NodeAttributes = {\n while?: NodeAttributeDefinition;\n until?: NodeAttributeDefinition;\n entry?: NodeAttributeDefinition;\n exit?: NodeAttributeDefinition;\n step?: NodeAttributeDefinition;\n};\n\n/**\n * Parse any node attribute definitions from the specified tokens array.\n * @param tokens The array of remaining tokens.\n * @param stringArgumentPlaceholders The mapping of string literal node argument placeholders to original values.\n * @returns An object of attribute definitions defined by any directly following tokens.\n */\nexport function parseAttributeTokens(\n tokens: string[],\n stringArgumentPlaceholders: StringLiteralPlaceholders\n): NodeAttributes {\n const nodeAttributeNames: (keyof NodeAttributes)[] = [\"while\", \"until\", \"entry\", \"exit\", \"step\"];\n\n // Create an object to hold any attributes found.\n const attributes: NodeAttributes = {};\n\n // Try to get the name of the attribute for the next token.\n let nextAttributeName = tokens[0]?.toLowerCase() as keyof NodeAttributes;\n\n // Pull attribute tokens as well as their arguments off of the tokens stack until we have no more.\n while (nodeAttributeNames.includes(nextAttributeName)) {\n // Check to make sure that we have not already created an attribute definition of this type.\n if (attributes[nextAttributeName]) {\n throw new Error(`duplicate attribute '${tokens[0].toUpperCase()}' found for node`);\n }\n\n // Remove the attribute name token from the array of tokens.\n tokens.shift();\n\n // Grab the attribute arguments, assuming the first to be an identifier.\n const [attributeCallIdentifier, ...attributeArguments] = parseArgumentTokens(\n tokens,\n stringArgumentPlaceholders\n );\n\n // The first attribute argument has to be an identifer, this will reference an agent function.\n if (attributeCallIdentifier?.type !== \"identifier\") {\n throw new Error(\"expected agent function name identifier argument for attribute\");\n }\n\n // Any attribute arguments (other than the expected call identifier) must have a type of string, number, boolean or null.\n attributeArguments\n .filter((arg) => arg.type === \"identifier\")\n .forEach((arg) => {\n throw new Error(\n `invalid attribute argument value '${arg.value}', must be string, number, boolean or null`\n );\n });\n\n // Create the attribute definition and add it to the object of attribute definitions found.\n attributes[nextAttributeName] = {\n call: attributeCallIdentifier.value,\n args: attributeArguments.map(({ value }) => value)\n };\n\n // Try to get the next attribute name token, as there could be multiple.\n nextAttributeName = tokens[0]?.toLowerCase() as keyof NodeAttributes;\n }\n\n return attributes;\n}\n", "import {\n ActionNodeDefinition,\n AnyChildNodeDefinition,\n AnyNodeDefinition,\n BranchNodeDefinition,\n ConditionNodeDefinition,\n FailNodeDefinition,\n FlipNodeDefinition,\n LottoNodeDefinition,\n ParallelNodeDefinition,\n RepeatNodeDefinition,\n RetryNodeDefinition,\n RootNodeDefinition,\n SelectorNodeDefinition,\n SequenceNodeDefinition,\n SucceedNodeDefinition,\n WaitNodeDefinition\n} from \"../BehaviourTreeDefinition\";\nimport {\n isCompositeNode,\n isDecoratorNode,\n isLeafNode,\n isNullOrUndefined,\n isRootNode\n} from \"../BehaviourTreeDefinitionUtilities\";\nimport { parseArgumentTokens } from \"./MDSLNodeArgumentParser\";\nimport { parseAttributeTokens } from \"./MDSLNodeAttributeParser\";\nimport {\n StringLiteralPlaceholders,\n parseTokensFromDefinition,\n popAndCheck,\n substituteStringLiterals\n} from \"./MDSLUtilities\";\n\n/**\n * Convert the MDSL tree definition string into an equivalent JSON definition.\n * @param definition The tree definition string as MDSL.\n * @returns The root node JSON definitions.\n */\nexport function convertMDSLToJSON(definition: string): RootNodeDefinition[] {\n // Swap out any node/attribute argument string literals with a placeholder and get a mapping of placeholders to original values as well as the processed definition.\n const { placeholders, processedDefinition } = substituteStringLiterals(definition);\n\n // Parse our definition definition string into an array of raw tokens.\n const tokens = parseTokensFromDefinition(processedDefinition);\n\n return convertTokensToJSONDefinition(tokens, placeholders);\n}\n\n/**\n * Converts the specified tree definition tokens into a JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The root node JSON definitions.\n */\nfunction convertTokensToJSONDefinition(\n tokens: string[],\n stringLiteralPlaceholders: StringLiteralPlaceholders\n): RootNodeDefinition[] {\n // There must be at least 3 tokens for the tree definition to be valid. 'ROOT', '{' and '}'.\n if (tokens.length < 3) {\n throw new Error(\"invalid token count\");\n }\n\n // We should have a matching number of '{' and '}' tokens. If not, then there are scopes that have not been properly closed.\n if (tokens.filter((token) => token === \"{\").length !== tokens.filter((token) => token === \"}\").length) {\n throw new Error(\"scope character mismatch\");\n }\n\n // Create an array of tree stack arrays where root nodes will always be at the botton and the current composite/decorator node at the top.\n // There should be an element in this array for every root node defined and every element should be an array with a root note as the first element.\n // E.g. A definition with two root nodes defined:\n // [\n // [root, lotto, sequence],\n // [root, selector]\n // ]\n const treeStacks: [Partial, ...Partial[]][] = [];\n\n // Create an array of all root node definitions that we create.\n const rootNodes: Partial[] = [];\n\n // A helper function used to push node definitions onto the tree stack.\n const pushNode = (node: AnyNodeDefinition) => {\n // If the node is a root node then we need to create a new tree stack array with the root node at the root.\n if (isRootNode(node)) {\n // We need to double-check that this root node is not the child of another node.\n // We can do this by checking whether the top tree stack is not empty (contains an existing node)\n if (treeStacks[treeStacks.length - 1]?.length) {\n throw new Error(\"a root node cannot be the child of another node\");\n }\n\n // Add the root node definition to our array of all parsed root node definitions.\n rootNodes.push(node);\n\n // Add the root node definition to the root of a new tree stack.\n treeStacks.push([node]);\n\n return;\n }\n\n // All non-root nodes should be pushed after their root nodes so handle cases\n // where we may not have any tree stacks or our top-most tree stack is empty.\n if (!treeStacks.length || !treeStacks[treeStacks.length - 1].length) {\n throw new Error(\"expected root node at base of definition\");\n }\n\n // Get the current tree stack that we are populating.\n const topTreeStack = treeStacks[treeStacks.length - 1];\n\n // Get the top-most node in the current tree stack, this will be a composite/decorator node\n // for which we will populate its children array if composite or setting its child if a decorator.\n const topTreeStackTopNode = topTreeStack[topTreeStack.length - 1] as AnyNodeDefinition;\n\n // If the top-most node in the current root stack is a composite or decorator\n // node then the current node should be added as a child of the top-most node.\n if (isCompositeNode(topTreeStackTopNode)) {\n topTreeStackTopNode.children = topTreeStackTopNode.children || [];\n topTreeStackTopNode.children.push(node);\n } else if (isDecoratorNode(topTreeStackTopNode)) {\n // If the top node already has a child node set then throw an error as a decorator should only have a single child.\n if (topTreeStackTopNode.child) {\n throw new Error(\"a decorator node must only have a single child node\");\n }\n\n topTreeStackTopNode.child = node;\n }\n\n // If the node we are adding is also a composite or decorator node, then we should push it\n // onto the current tree stack, as subsequent nodes will be added as its child/children.\n if (!isLeafNode(node)) {\n topTreeStack.push(node);\n }\n };\n\n // A helper function used to pop the top-most node definition off of the tree stack and return it.\n const popNode = (): AnyNodeDefinition | null => {\n let poppedNode: AnyNodeDefinition | null = null;\n\n // Get the current tree stack that we are populating.\n const topTreeStack = treeStacks[treeStacks.length - 1];\n\n // Pop the top-most node in the current tree stack if there is one.\n if (topTreeStack.length) {\n poppedNode = topTreeStack.pop() as AnyNodeDefinition;\n }\n\n // We don't want any empty tree stacks in our stack of tree stacks.\n if (!topTreeStack.length) {\n treeStacks.pop();\n }\n\n return poppedNode;\n };\n\n // We should keep processing the raw tokens until we run out of them.\n while (tokens.length) {\n // Grab the next token.\n const token = tokens.shift()!;\n\n // How we create the next node depends on the current raw token value.\n switch (token.toUpperCase()) {\n case \"ROOT\": {\n pushNode(createRootNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"SUCCEED\": {\n pushNode(createSucceedNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"FAIL\": {\n pushNode(createFailNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"FLIP\": {\n pushNode(createFlipNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"REPEAT\": {\n pushNode(createRepeatNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"RETRY\": {\n pushNode(createRetryNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"SEQUENCE\": {\n pushNode(createSequenceNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"SELECTOR\": {\n pushNode(createSelectorNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"PARALLEL\": {\n pushNode(createParallelNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"LOTTO\": {\n pushNode(createLottoNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"ACTION\": {\n pushNode(createActionNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"CONDITION\": {\n pushNode(createConditionNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"WAIT\": {\n pushNode(createWaitNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"BRANCH\": {\n pushNode(createBranchNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"}\": {\n // The '}' character closes the current scope and means that we have to pop a node off of the current stack.\n const poppedNode = popNode();\n\n // Now that we have a node definition we can carry out any validation that may require the node to be fully populated.\n if (poppedNode) {\n validatePoppedNode(poppedNode);\n }\n\n break;\n }\n\n default: {\n throw new Error(`unexpected token: ${token}`);\n }\n }\n }\n\n return rootNodes as RootNodeDefinition[];\n}\n\n/**\n * Creates a root node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The root node JSON definition.\n */\nfunction createRootNode(tokens: string[], stringLiteralPlaceholders: StringLiteralPlaceholders): RootNodeDefinition {\n // Create the root node definition.\n let node = {\n type: \"root\",\n id: undefined\n } as RootNodeDefinition;\n\n // Parse any node arguments, we should only have one if any which will be an identifier argument for the root identifier.\n const nodeArguments = parseArgumentTokens(tokens, stringLiteralPlaceholders);\n\n // Check whether any node arguments were defined.\n if (nodeArguments.length) {\n // We should only have one argument, if any, which will be an identifier argument for the root identifier.\n if (nodeArguments.length === 1 && nodeArguments[0].type === \"identifier\") {\n // The root node identifier will be the first and only node argument value.\n node.id = nodeArguments[0].value as string;\n } else {\n throw new Error(\"expected single root name argument\");\n }\n }\n\n // Grab any node attribute definitions and spread them into the node definition.\n node = { ...node, ...parseAttributeTokens(tokens, stringLiteralPlaceholders) };\n\n // This is a decorator node, so we expect an opening '{'.\n popAndCheck(tokens, \"{\");\n\n // Return the root node definition.\n return node;\n}\n\n/**\n * Creates a succeed node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The succeed node JSON definition.\n */\nfunction createSucceedNode(\n tokens: string[],\n stringLiteralPlaceholders: StringLiteralPlaceholders\n): SucceedNodeDefinition {\n const node = {\n type: \"succeed\",\n ...parseAttributeTokens(tokens, stringLiteralPlaceholders)\n } as SucceedNodeDefinition;\n\n // This is a decorator node, so we expect an opening '{'.\n popAndCheck(tokens, \"{\");\n\n // Return the succeed node definition.\n return node;\n}\n\n/**\n * Creates a fail node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The fail node JSON definition.\n */\nfunction createFailNode(tokens: string[], stringLiteralPlaceholders: StringLiteralPlaceholders): FailNodeDefinition {\n const node = {\n type: \"fail\",\n ...parseAttributeTokens(tokens, stringLiteralPlaceholders)\n } as FailNodeDefinition;\n\n // This is a decorator node, so we expect an opening '{'.\n popAndCheck(tokens, \"{\");\n\n // Return the fail node definition.\n return node;\n}\n\n/**\n * Creates a flip node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The flip node JSON definition.\n */\nfunction createFlipNode(tokens: string[], stringLiteralPlaceholders: StringLiteralPlaceholders): FlipNodeDefinition {\n const node = {\n type: \"flip\",\n ...parseAttributeTokens(tokens, stringLiteralPlaceholders)\n } as FlipNodeDefinition;\n\n // This is a decorator node, so we expect an opening '{'.\n popAndCheck(tokens, \"{\");\n\n // Return the flip node definition.\n return node;\n}\n\n/**\n * Creates a repeat node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The repeat node JSON definition.\n */\nfunction createRepeatNode(\n tokens: string[],\n stringLiteralPlaceholders: StringLiteralPlaceholders\n): RepeatNodeDefinition {\n let node = { type: \"repeat\" } as RepeatNodeDefinition;\n\n // Get the node arguments.\n const nodeArguments = parseArgumentTokens(tokens, stringLiteralPlaceholders);\n\n // The arguments of a repeat node are optional. We may have:\n // - No node arguments, in which case the repeat note will iterate indefinitely.\n // - One node argument which will be the explicit number of iterations to make.\n // - Two node arguments which define the min and max iteration bounds from which a random iteration count will be picked.\n if (nodeArguments.length) {\n // All repeat node arguments MUST be of type number and must be integer.\n nodeArguments\n .filter((arg) => arg.type !== \"number\" || !arg.isInteger)\n .forEach(() => {\n throw new Error(`repeat node iteration counts must be integer values`);\n });\n\n // We should have got one or two iteration counts.\n if (nodeArguments.length === 1) {\n // A static iteration count was defined.\n node.iterations = nodeArguments[0].value as number;\n\n // A repeat node must have a positive number of iterations if defined.\n if (node.iterations < 0) {\n throw new Error(\"a repeat node must have a positive number of iterations if defined\");\n }\n } else if (nodeArguments.length === 2) {\n // A minimum and maximum iteration count was defined.\n node.iterations = [nodeArguments[0].value as number, nodeArguments[1].value as number];\n\n // A repeat node must have a positive min and max iteration count if they are defined.\n if (node.iterations[0] < 0 || node.iterations[1] < 0) {\n throw new Error(\"a repeat node must have a positive minimum and maximum iteration count if defined\");\n }\n\n // A repeat node must not have an minimum iteration count that exceeds the maximum iteration count.\n if (node.iterations[0] > node.iterations[1]) {\n throw new Error(\n \"a repeat node must not have a minimum iteration count that exceeds the maximum iteration count\"\n );\n }\n } else {\n // An incorrect number of iteration counts was defined.\n throw new Error(\"invalid number of repeat node iteration count arguments defined\");\n }\n }\n\n // Grab any node attribute definitions and spread them into the node definition.\n node = { ...node, ...parseAttributeTokens(tokens, stringLiteralPlaceholders) };\n\n // This is a decorator node, so we expect an opening '{'.\n popAndCheck(tokens, \"{\");\n\n // Return the repeat node definition.\n return node;\n}\n\n/**\n * Creates a retry node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The retry node JSON definition.\n */\nfunction createRetryNode(tokens: string[], stringLiteralPlaceholders: StringLiteralPlaceholders): RetryNodeDefinition {\n let node = { type: \"retry\" } as RetryNodeDefinition;\n\n // Get the node arguments.\n const nodeArguments = parseArgumentTokens(tokens, stringLiteralPlaceholders);\n\n // The arguments of a retry node are optional. We may have:\n // - No node arguments, in which case the retry note will attempt indefinitely.\n // - One node argument which will be the explicit number of attempts to make.\n // - Two node arguments which define the min and max attempt bounds from which a random attempt count will be picked.\n if (nodeArguments.length) {\n // All retry node arguments MUST be of type number and must be integer.\n nodeArguments\n .filter((arg) => arg.type !== \"number\" || !arg.isInteger)\n .forEach(() => {\n throw new Error(`retry node attempt counts must be integer values`);\n });\n\n // We should have got one or two attempt counts.\n if (nodeArguments.length === 1) {\n // A static attempt count was defined.\n node.attempts = nodeArguments[0].value as number;\n\n // A retry node must have a positive number of attempts if defined.\n if (node.attempts < 0) {\n throw new Error(\"a retry node must have a positive number of attempts if defined\");\n }\n } else if (nodeArguments.length === 2) {\n // A minimum and maximum attempt count was defined.\n node.attempts = [nodeArguments[0].value as number, nodeArguments[1].value as number];\n\n // A retry node must have a positive min and max attempts count if they are defined.\n if (node.attempts[0] < 0 || node.attempts[1] < 0) {\n throw new Error(\"a retry node must have a positive minimum and maximum attempt count if defined\");\n }\n\n // A retry node must not have a minimum attempt count that exceeds the maximum attempt count.\n if (node.attempts[0] > node.attempts[1]) {\n throw new Error(\n \"a retry node must not have a minimum attempt count that exceeds the maximum attempt count\"\n );\n }\n } else {\n // An incorrect number of attempt counts was defined.\n throw new Error(\"invalid number of retry node attempt count arguments defined\");\n }\n }\n\n // Grab any node attribute definitions and spread them into the node definition.\n node = { ...node, ...parseAttributeTokens(tokens, stringLiteralPlaceholders) };\n\n // This is a decorator node, so we expect an opening '{'.\n popAndCheck(tokens, \"{\");\n\n // Return the retry node definition.\n return node;\n}\n\n/**\n * Creates a sequence node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The sequence node JSON definition.\n */\nfunction createSequenceNode(\n tokens: string[],\n stringLiteralPlaceholders: StringLiteralPlaceholders\n): SequenceNodeDefinition {\n const node = {\n type: \"sequence\",\n ...parseAttributeTokens(tokens, stringLiteralPlaceholders)\n } as SequenceNodeDefinition;\n\n // This is a composite node, so we expect an opening '{'.\n popAndCheck(tokens, \"{\");\n\n // Return the sequence node definition.\n return node;\n}\n\n/**\n * Creates a selector node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The selector node JSON definition.\n */\nfunction createSelectorNode(\n tokens: string[],\n stringLiteralPlaceholders: StringLiteralPlaceholders\n): SelectorNodeDefinition {\n const node = {\n type: \"selector\",\n ...parseAttributeTokens(tokens, stringLiteralPlaceholders)\n } as SelectorNodeDefinition;\n\n // This is a composite node, so we expect an opening '{'.\n popAndCheck(tokens, \"{\");\n\n // Return the selector node definition.\n return node;\n}\n\n/**\n * Creates a parallel node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The parallel node JSON definition.\n */\nfunction createParallelNode(\n tokens: string[],\n stringLiteralPlaceholders: StringLiteralPlaceholders\n): ParallelNodeDefinition {\n const node = {\n type: \"parallel\",\n ...parseAttributeTokens(tokens, stringLiteralPlaceholders)\n } as ParallelNodeDefinition;\n\n // This is a composite node, so we expect an opening '{'.\n popAndCheck(tokens, \"{\");\n\n // Return the parallel node definition.\n return node;\n}\n\n/**\n * Creates a lotto node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The lotto node JSON definition.\n */\nfunction createLottoNode(tokens: string[], stringLiteralPlaceholders: StringLiteralPlaceholders): LottoNodeDefinition {\n // If any node arguments have been defined then they must be our weights.\n const nodeArguments = parseArgumentTokens(tokens, stringLiteralPlaceholders);\n\n // All lotto node arguments MUST be of type number and must be positive integers.\n nodeArguments\n .filter((arg) => arg.type !== \"number\" || !arg.isInteger || arg.value < 0)\n .forEach(() => {\n throw new Error(`lotto node weight arguments must be positive integer values`);\n });\n\n const node = {\n type: \"lotto\",\n weights: nodeArguments.length ? nodeArguments.map(({ value }) => value) : undefined,\n ...parseAttributeTokens(tokens, stringLiteralPlaceholders)\n } as LottoNodeDefinition;\n\n // This is a composite node, so we expect an opening '{'.\n popAndCheck(tokens, \"{\");\n\n // Return the lotto node definition.\n return node;\n}\n\n/**\n * Creates an action node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The action node JSON definition.\n */\nfunction createActionNode(\n tokens: string[],\n stringLiteralPlaceholders: StringLiteralPlaceholders\n): ActionNodeDefinition {\n // Parse any node arguments, we should have at least one which will be an identifier argument for the action name\n // and agent function to invoke for the action, all other arguments are to be passed as arguments to that function.\n const [actionNameIdentifier, ...agentFunctionArgs] = parseArgumentTokens(tokens, stringLiteralPlaceholders);\n\n // Our first argument MUST be defined and be an identifier as we require an action name argument.\n if (actionNameIdentifier?.type !== \"identifier\") {\n throw new Error(\"expected action name identifier argument\");\n }\n\n // Only the first argument should have been an identifier, all agent function arguments must be string, number, boolean or null.\n agentFunctionArgs\n .filter((arg) => arg.type === \"identifier\")\n .forEach((arg) => {\n throw new Error(\n `invalid action node argument value '${arg.value}', must be string, number, boolean or null`\n );\n });\n\n // Return the action node definition.\n return {\n type: \"action\",\n call: actionNameIdentifier.value,\n args: agentFunctionArgs.map(({ value }) => value),\n ...parseAttributeTokens(tokens, stringLiteralPlaceholders)\n };\n}\n\n/**\n * Creates a condition node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The condition node JSON definition.\n */\nfunction createConditionNode(\n tokens: string[],\n stringLiteralPlaceholders: StringLiteralPlaceholders\n): ConditionNodeDefinition {\n // Parse any node arguments, we should have at least one which will be an identifier argument for the condition name\n // and agent function to invoke for the condition, all other arguments are to be passed as arguments to that function.\n const [conditionNameIdentifier, ...agentFunctionArgs] = parseArgumentTokens(tokens, stringLiteralPlaceholders);\n\n // Our first argument MUST be defined and be an identifier as we require a condition name argument.\n if (conditionNameIdentifier?.type !== \"identifier\") {\n throw new Error(\"expected condition name identifier argument\");\n }\n\n // Only the first argument should have been an identifier, all agent function arguments must be string, number, boolean or null.\n agentFunctionArgs\n .filter((arg) => arg.type === \"identifier\")\n .forEach((arg) => {\n throw new Error(\n `invalid condition node argument value '${arg.value}', must be string, number, boolean or null`\n );\n });\n\n // Return the condition node definition.\n return {\n type: \"condition\",\n call: conditionNameIdentifier.value,\n args: agentFunctionArgs.map(({ value }) => value),\n ...parseAttributeTokens(tokens, stringLiteralPlaceholders)\n };\n}\n\n/**\n * Creates a wait node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The wait node JSON definition.\n */\nfunction createWaitNode(tokens: string[], stringLiteralPlaceholders: StringLiteralPlaceholders): WaitNodeDefinition {\n let node = { type: \"wait\" } as WaitNodeDefinition;\n\n // Get the node arguments.\n const nodeArguments = parseArgumentTokens(tokens, stringLiteralPlaceholders);\n\n // The arguments of a wait node are optional. We may have:\n // - No node arguments, in which case the wait will be indefinite until it is aborted.\n // - One node argument which will be the explicit duration of the wait.\n // - Two node arguments which define the min and max duration bounds from which a random duration will be picked.\n if (nodeArguments.length) {\n // All wait node arguments MUST be of type number and must be integer.\n nodeArguments\n .filter((arg) => arg.type !== \"number\" || !arg.isInteger)\n .forEach(() => {\n throw new Error(`wait node durations must be integer values`);\n });\n\n // We may have:\n // - One node argument which will be the explicit duration of the wait.\n // - Two node arguments which define the min and max duration bounds from which a random duration will be picked.\n // - Too many arguments, which is not valid.\n if (nodeArguments.length === 1) {\n // An explicit duration was defined.\n node.duration = nodeArguments[0].value as number;\n\n // If an explict duration was defined then it must be a positive number.\n if (node.duration < 0) {\n throw new Error(\"a wait node must have a positive duration\");\n }\n } else if (nodeArguments.length === 2) {\n // Min and max duration bounds were defined from which a random duration will be picked.\n node.duration = [nodeArguments[0].value as number, nodeArguments[1].value as number];\n\n // A wait node must have a positive min and max duration.\n if (node.duration[0] < 0 || node.duration[1] < 0) {\n throw new Error(\"a wait node must have a positive minimum and maximum duration\");\n }\n\n // A wait node must not have a minimum duration that exceeds the maximum duration.\n if (node.duration[0] > node.duration[1]) {\n throw new Error(\"a wait node must not have a minimum duration that exceeds the maximum duration\");\n }\n } else if (nodeArguments.length > 2) {\n // An incorrect number of duration arguments were defined.\n throw new Error(\"invalid number of wait node duration arguments defined\");\n }\n }\n\n // Return the wait node definition.\n return { ...node, ...parseAttributeTokens(tokens, stringLiteralPlaceholders) };\n}\n\n/**\n * Creates a branch node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The branch node JSON definition.\n */\nfunction createBranchNode(\n tokens: string[],\n stringLiteralPlaceholders: StringLiteralPlaceholders\n): BranchNodeDefinition {\n // Parse any node arguments, we should have one which will be an identifier argument for the root ref.\n const nodeArguments = parseArgumentTokens(tokens, stringLiteralPlaceholders);\n\n // We should have only a single identifer argument for a branch node, which is the root ref.\n if (nodeArguments.length !== 1 || nodeArguments[0].type !== \"identifier\") {\n throw new Error(\"expected single branch name argument\");\n }\n\n // Return the branch node definition.\n return { type: \"branch\", ref: nodeArguments[0].value };\n}\n\n/**\n * Validate a fully-populated node definition that was popped off of the tree stack.\n * @param definition The popped node to validate.\n */\nfunction validatePoppedNode(definition: AnyNodeDefinition): void {\n // Decorators MUST have a child defined.\n if (isDecoratorNode(definition) && isNullOrUndefined(definition.child)) {\n throw new Error(`a ${definition.type} node must have a single child node defined`);\n }\n\n // Composites MUST have at least one child defined.\n if (isCompositeNode(definition) && !definition.children?.length) {\n throw new Error(`a ${definition.type} node must have at least a single child node defined`);\n }\n\n // We need to make sure that lotto nodes that have weights defined have a number of weights matching the number of child nodes.\n if (definition.type === \"lotto\") {\n // Check whether a 'weights' property has been defined, if it has we expect it to be an array of weights.\n if (typeof definition.weights !== \"undefined\") {\n // Check that the weights property is an array of positive integers with an element for each child node element.\n if (definition.weights.length !== definition.children.length) {\n throw new Error(\n \"expected a number of weight arguments matching the number of child nodes for lotto node\"\n );\n }\n }\n }\n}\n", "import { RootNodeDefinition } from \"./BehaviourTreeDefinition\";\nimport { flattenDefinition, isBranchNode, isInteger } from \"./BehaviourTreeDefinitionUtilities\";\nimport { convertMDSLToJSON } from \"./mdsl/MDSLDefinitionParser\";\n\n/**\n * An object representing the result of validating a tree definition.\n */\nexport type DefinitionValidationResult = {\n /**\n * A flag defining whether validation succeeded.\n */\n succeeded: boolean;\n /**\n * A string containing the error message if validation did not succeed.\n */\n errorMessage?: string;\n /**\n * The definition as json if the validation was successful, or undefined if validation did not succeed.\n */\n json?: RootNodeDefinition[];\n};\n\n/**\n * Validates the specified behaviour tree definition in the form of JSON or MDSL, not taking any globally registered subtrees into consideration.\n * @param definition The behaviour tree definition in the form of JSON or MDSL.\n * @returns An object representing the result of validating the given tree definition.\n */\nexport function validateDefinition(definition: any): DefinitionValidationResult {\n // The definition must be defined.\n if (definition === null || typeof definition === \"undefined\") {\n return createValidationFailureResult(\"definition is null or undefined\");\n }\n\n // We are expecting a definition in one of three different forms:\n // - A string which we will assume is MDSL and we will parse this to JSON before validation.\n // - An array which we will assume is an array of root node definitions with at least one being the primary root node (no 'id' property)\n // - An object which we will assume is the primary root node and should not have an 'id' property.\n if (typeof definition === \"string\") {\n // The definition is a string which we can assume is MDSL, so attempt to validate it.\n return validateMDSLDefinition(definition);\n } else if (typeof definition === \"object\") {\n // The definition will either be an array (of root node definitions) or an object (the single primary root node definition).\n return validateJSONDefinition(definition);\n } else {\n return createValidationFailureResult(`unexpected definition type of '${typeof definition}'`);\n }\n}\n\n/**\n * Validates the specified behaviour tree definition in the form of MDSL.\n * @param definition The behaviour tree definition in the form of MDSL.\n * @returns An object representing the result of validating the given tree definition.\n */\nfunction validateMDSLDefinition(definition: string): DefinitionValidationResult {\n let rootNodeDefinitions;\n\n // The first thing the we need to do is to attempt to convert our MDSL into JSON.\n try {\n // The definition is a string which we can assume is MDSL, so attempt to parse it to a JSON definition in the form of an array of root node definitions.\n rootNodeDefinitions = convertMDSLToJSON(definition);\n } catch (exception) {\n // We failed to parse the JSON from the MDSL, this is likely to be the result of it not being a valid MDSL string.\n return createValidationFailureResult((exception as Error).message);\n }\n\n // Unpack all of the root node definitions into arrays of main ('id' defined) and sub ('id' not defined) root node definitions.\n const mainRootNodeDefinitions = rootNodeDefinitions.filter(({ id }) => typeof id === \"undefined\");\n const subRootNodeDefinitions = rootNodeDefinitions.filter(({ id }) => typeof id === \"string\" && id.length > 0);\n\n // We should ALWAYS have exactly one root node definition without an 'id' property defined, which is out main root node definition.\n if (mainRootNodeDefinitions.length !== 1) {\n return createValidationFailureResult(\n \"expected single unnamed root node at base of definition to act as main root\"\n );\n }\n\n // We should never have duplicate 'id' properties across our sub root node definitions.\n const subRootNodeIdenitifers: string[] = [];\n for (const { id } of subRootNodeDefinitions) {\n // Have we already come across this 'id' property value?\n if (subRootNodeIdenitifers.includes(id!)) {\n return createValidationFailureResult(`multiple root nodes found with duplicate name '${id}'`);\n }\n\n subRootNodeIdenitifers.push(id!);\n }\n\n try {\n // Validate our branch -> subtree links and check for any circular dependencies, we don't care about checking for broken subtree links here.\n validateBranchSubtreeLinks(rootNodeDefinitions, false);\n } catch (exception) {\n return createValidationFailureResult((exception as Error).message);\n }\n\n // Our definition was valid!\n return {\n succeeded: true,\n json: rootNodeDefinitions\n };\n}\n\n/**\n * Validates the specified behaviour tree definition in the form of JSON.\n * @param definition The behaviour tree definition in the form of JSON.\n * @returns An object representing the result of validating the given tree definition.\n */\nexport function validateJSONDefinition(\n definition: RootNodeDefinition | RootNodeDefinition[]\n): DefinitionValidationResult {\n // The definition will either be an array (of root node definitions) or an object (the single primary root node definition).\n const rootNodeDefinitions = Array.isArray(definition) ? definition : [definition];\n\n // Iterate over our array of root nodes and call validateNode for each, passing an initial depth of 0, wrapped in a try catch to handle validation failures.\n try {\n rootNodeDefinitions.forEach((rootNodeDefinition) => validateNode(rootNodeDefinition, 0));\n } catch (error) {\n // Handle cases where we have caught a thrown Error and return a failure result with the error message.\n if (error instanceof Error) {\n return createValidationFailureResult(error.message);\n }\n\n // No idea what happened here!\n return createValidationFailureResult(`unexpected error: ${error}`);\n }\n\n // Unpack all of the root node definitions into arrays of main ('id' defined) and sub ('id' not defined) root node definitions.\n const mainRootNodeDefinitions = rootNodeDefinitions.filter(({ id }) => typeof id === \"undefined\");\n const subRootNodeDefinitions = rootNodeDefinitions.filter(({ id }) => typeof id === \"string\" && id.length > 0);\n\n // We should ALWAYS have exactly one root node definition without an 'id' property defined, which is out main root node definition.\n if (mainRootNodeDefinitions.length !== 1) {\n return createValidationFailureResult(\n \"expected single root node without 'id' property defined to act as main root\"\n );\n }\n\n // We should never have duplicate 'id' properties across our sub root node definitions.\n const subRootNodeIdenitifers: string[] = [];\n for (const { id } of subRootNodeDefinitions) {\n // Have we already come across this 'id' property value?\n if (subRootNodeIdenitifers.includes(id!)) {\n return createValidationFailureResult(\n `multiple root nodes found with duplicate 'id' property value of '${id}'`\n );\n }\n\n subRootNodeIdenitifers.push(id!);\n }\n\n try {\n // Validate our branch -> subtree links and check for any circular dependencies, we don't care about checking for broken subtree links here.\n validateBranchSubtreeLinks(rootNodeDefinitions, false);\n } catch (exception) {\n return createValidationFailureResult((exception as Error).message);\n }\n\n // Our definition was valid!\n return {\n succeeded: true,\n json: rootNodeDefinitions\n };\n}\n\n/**\n * Validates the branch -> subtree links across all provided root node definitions.\n * This will not consider branch nodes that reference any globally registered subtrees unless includesGlobalSubtrees\n * is set to true, in which case we will also verify that there are no broken branch -> subtree links.\n * @param rootNodeDefinitions The array of root node definitions.\n * @param includesGlobalSubtrees A flag defining whether the array includes all global subtree root node definitions.\n */\nexport function validateBranchSubtreeLinks(rootNodeDefinitions: RootNodeDefinition[], includesGlobalSubtrees: boolean) {\n // Create a mapping of root node identifiers to other root nodes that they reference via branch nodes.\n // Below is an example of a mapping that includes a circular dependency (root => a => b => c => a)\n // [{ refs: [\"a\", \"b\"] }, { id: \"a\", refs: [\"b\"] }, { id: \"b\", refs: [\"c\"] }, { id: \"c\", refs: [\"a\"] }]\n const rootNodeMappings: { id: string | undefined; refs: string[] }[] = rootNodeDefinitions.map(\n (rootNodeDefinition) => ({\n id: rootNodeDefinition.id,\n refs: flattenDefinition(rootNodeDefinition)\n .filter(isBranchNode)\n .map(({ ref }) => ref)\n })\n );\n\n // A recursive function to walk through the mappings, keeping track of which root nodes we have visited in the form of a path of root node identifiers.\n const followRefs = (mapping: { id: string | undefined; refs: string[] }, path: (string | undefined)[] = []) => {\n // Have we found a circular dependency?\n if (path.includes(mapping.id)) {\n // We found a circular dependency! Get the bad path of root node identifiers.\n const badPath = [...path, mapping.id];\n\n // Create the formatted path value. [undefined, \"a\", \"b\", \"c\", \"a\"] would be formatted as \"a -> b -> c -> a\".\n const badPathFormatted = badPath.filter((element) => !!element).join(\" => \");\n\n // No need to continue, we found a circular dependency.\n throw new Error(`circular dependency found in branch node references: ${badPathFormatted}`);\n }\n\n for (const ref of mapping.refs) {\n // Find the mapping for the root node with an identifer matching the current ref.\n const subMapping = rootNodeMappings.find(({ id }) => id === ref);\n\n // We may not have a mapping for this ref, which is normal when we aren't considering all globally registered subtrees.\n if (subMapping) {\n followRefs(subMapping, [...path, mapping.id]);\n } else if (includesGlobalSubtrees) {\n // We found a reference to a root node that doesn't exist, which is a problem seeing as the root node definitons includes all globally registered subtrees.\n throw new Error(\n mapping.id\n ? `subtree '${mapping.id}' has branch node that references root node '${ref}' which has not been defined`\n : `primary tree has branch node that references root node '${ref}' which has not been defined`\n );\n }\n }\n };\n\n // Start looking for circular dependencies and broken references from the primary root node definition.\n followRefs(rootNodeMappings.find((mapping) => typeof mapping.id === \"undefined\")!);\n}\n\n/**\n * Validate an object that we expect to be a node definition.\n * @param definition An object that we expect to be a node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateNode(definition: any, depth: number): void {\n // Every node must be valid object and have a non-empty 'type' string property.\n if (typeof definition !== \"object\" || typeof definition.type !== \"string\" || definition.type.length === 0) {\n throw new Error(\n `node definition is not an object or 'type' property is not a non-empty string at depth '${depth}'`\n );\n }\n\n // How we validate this node definition will depend on its type.\n switch (definition.type) {\n case \"action\":\n validateActionNode(definition, depth);\n break;\n\n case \"condition\":\n validateConditionNode(definition, depth);\n break;\n\n case \"wait\":\n validateWaitNode(definition, depth);\n break;\n\n case \"branch\":\n validateBranchNode(definition, depth);\n break;\n\n case \"root\":\n validateRootNode(definition, depth);\n break;\n\n case \"succeed\":\n validateSucceedNode(definition, depth);\n break;\n\n case \"fail\":\n validateFailNode(definition, depth);\n break;\n\n case \"flip\":\n validateFlipNode(definition, depth);\n break;\n\n case \"repeat\":\n validateRepeatNode(definition, depth);\n break;\n\n case \"retry\":\n validateRetryNode(definition, depth);\n break;\n\n case \"sequence\":\n validateSequenceNode(definition, depth);\n break;\n\n case \"selector\":\n validateSelectorNode(definition, depth);\n break;\n\n case \"parallel\":\n validateParallelNode(definition, depth);\n break;\n\n case \"lotto\":\n validateLottoNode(definition, depth);\n break;\n\n default:\n throw new Error(`unexpected node type of '${definition.type}' at depth '${depth}'`);\n }\n}\n\n/**\n * Validate any attributes for a given node definition.\n * @param definition The node definition.\n * @param depth The depth of the node in the behaviour tree definition.\n */\nfunction validateNodeAttributes(definition: any, depth: number): void {\n // Validate each of the attribute types for this node.\n [\"while\", \"until\", \"entry\", \"exit\", \"step\"].forEach((attributeName) => {\n // Attempt to grab the definition for the current attribute from the node definition.\n const attributeDefinition = definition[attributeName];\n\n // All node attributes are optional, so there is nothing to do if the current attribute is not defined.\n if (typeof attributeDefinition === \"undefined\") {\n return;\n }\n\n // The attribute definition must be an object.\n if (typeof attributeDefinition !== \"object\") {\n throw new Error(\n `expected attribute '${attributeName}' to be an object for '${definition.type}' node at depth '${depth}'`\n );\n }\n\n // The 'call' property must be defined for any attribute definition.\n if (typeof attributeDefinition.call !== \"string\" || attributeDefinition.call.length === 0) {\n throw new Error(\n `expected 'call' property for attribute '${attributeName}' to be a non-empty string for '${definition.type}' node at depth '${depth}'`\n );\n }\n\n // If any node attribute arguments have been defined then they must have been defined in an array.\n if (typeof attributeDefinition.args !== \"undefined\" && !Array.isArray(attributeDefinition.args)) {\n throw new Error(\n `expected 'args' property for attribute '${attributeName}' to be an array for '${definition.type}' node at depth '${depth}'`\n );\n }\n });\n}\n\n/**\n * Validate an object that we expect to be a root node definition.\n * @param definition An object that we expect to be a root node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateRootNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"root\") {\n throw new Error(\"expected node type of 'root' for root node\");\n }\n\n // A root node cannot be the child of another node.\n if (depth > 0) {\n throw new Error(\"a root node cannot be the child of another node\");\n }\n\n // Check that, if the root node 'id' property is defined, it is a non-empty string.\n if (typeof definition.id !== \"undefined\" && (typeof definition.id !== \"string\" || definition.id.length === 0)) {\n throw new Error(\"expected non-empty string for 'id' property if defined for root node\");\n }\n\n // A root node is a decorator node, so must have a child node defined.\n if (typeof definition.child === \"undefined\") {\n throw new Error(\"expected property 'child' to be defined for root node\");\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n\n // Validate the child node of this decorator node.\n validateNode(definition.child, depth + 1);\n}\n\n/**\n * Validate an object that we expect to be a succeed node definition.\n * @param definition An object that we expect to be a succeed node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateSucceedNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"succeed\") {\n throw new Error(`expected node type of 'succeed' for succeed node at depth '${depth}'`);\n }\n\n // A succeed node is a decorator node, so must have a child node defined.\n if (typeof definition.child === \"undefined\") {\n throw new Error(`expected property 'child' to be defined for succeed node at depth '${depth}'`);\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n\n // Validate the child node of this decorator node.\n validateNode(definition.child, depth + 1);\n}\n\n/**\n * Validate an object that we expect to be a fail node definition.\n * @param definition An object that we expect to be a fail node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateFailNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"fail\") {\n throw new Error(`expected node type of 'fail' for fail node at depth '${depth}'`);\n }\n\n // A fail node is a decorator node, so must have a child node defined.\n if (typeof definition.child === \"undefined\") {\n throw new Error(`expected property 'child' to be defined for fail node at depth '${depth}'`);\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n\n // Validate the child node of this decorator node.\n validateNode(definition.child, depth + 1);\n}\n\n/**\n * Validate an object that we expect to be a flip node definition.\n * @param definition An object that we expect to be a flip node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateFlipNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"flip\") {\n throw new Error(`expected node type of 'flip' for flip node at depth '${depth}'`);\n }\n\n // A flip node is a decorator node, so must have a child node defined.\n if (typeof definition.child === \"undefined\") {\n throw new Error(`expected property 'child' to be defined for flip node at depth '${depth}'`);\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n\n // Validate the child node of this decorator node.\n validateNode(definition.child, depth + 1);\n}\n\n/**\n * Validate an object that we expect to be a repeat node definition.\n * @param definition An object that we expect to be a repeat node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateRepeatNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"repeat\") {\n throw new Error(`expected node type of 'repeat' for repeat node at depth '${depth}'`);\n }\n\n // A repeat node is a decorator node, so must have a child node defined.\n if (typeof definition.child === \"undefined\") {\n throw new Error(`expected property 'child' to be defined for repeat node at depth '${depth}'`);\n }\n\n // Check whether an 'iterations' property has been defined, it may not have been if this node is to repeat indefinitely.\n if (typeof definition.iterations !== \"undefined\") {\n if (Array.isArray(definition.iterations)) {\n // Check whether any elements of the array are not integer values.\n const containsNonInteger = !!definition.iterations.filter((value: unknown) => !isInteger(value)).length;\n\n // If the 'iterations' property is an array then it MUST contain two integer values.\n if (definition.iterations.length !== 2 || containsNonInteger) {\n throw new Error(\n `expected array containing two integer values for 'iterations' property if defined for repeat node at depth '${depth}'`\n );\n }\n\n // A repeat node must have a positive min and max iterations count if they are defined.\n if (definition.iterations[0] < 0 || definition.iterations[1] < 0) {\n throw new Error(\n `expected positive minimum and maximum iterations count for 'iterations' property if defined for repeat node at depth '${depth}'`\n );\n }\n\n // A repeat node must not have a minimum iterations count that exceeds the maximum iterations count.\n if (definition.iterations[0] > definition.iterations[1]) {\n throw new Error(\n `expected minimum iterations count that does not exceed the maximum iterations count for 'iterations' property if defined for repeat node at depth '${depth}'`\n );\n }\n } else if (isInteger(definition.iterations)) {\n // A repeat node must have a positive number of iterations if defined.\n if (definition.iterations < 0) {\n throw new Error(\n `expected positive iterations count for 'iterations' property if defined for repeat node at depth '${depth}'`\n );\n }\n } else {\n throw new Error(\n `expected integer value or array containing two integer values for 'iterations' property if defined for repeat node at depth '${depth}'`\n );\n }\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n\n // Validate the child node of this decorator node.\n validateNode(definition.child, depth + 1);\n}\n\n/**\n * Validate an object that we expect to be a retry node definition.\n * @param definition An object that we expect to be a retry node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateRetryNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"retry\") {\n throw new Error(`expected node type of 'retry' for retry node at depth '${depth}'`);\n }\n\n // A retry node is a decorator node, so must have a child node defined.\n if (typeof definition.child === \"undefined\") {\n throw new Error(`expected property 'child' to be defined for retry node at depth '${depth}'`);\n }\n\n // Check whether an 'attempts' property has been defined, it may not have been if this node is to retry indefinitely.\n if (typeof definition.attempts !== \"undefined\") {\n if (Array.isArray(definition.attempts)) {\n // Check whether any elements of the array are not integer values.\n const containsNonInteger = !!definition.attempts.filter((value: unknown) => !isInteger(value)).length;\n\n // If the 'attempts' property is an array then it MUST contain two integer values.\n if (definition.attempts.length !== 2 || containsNonInteger) {\n throw new Error(\n `expected array containing two integer values for 'attempts' property if defined for retry node at depth '${depth}'`\n );\n }\n\n // A retry node must have a positive min and max attempts count if they are defined.\n if (definition.attempts[0] < 0 || definition.attempts[1] < 0) {\n throw new Error(\n `expected positive minimum and maximum attempts count for 'attempts' property if defined for retry node at depth '${depth}'`\n );\n }\n\n // A retry node must not have a minimum attempts count that exceeds the maximum attempts count.\n if (definition.attempts[0] > definition.attempts[1]) {\n throw new Error(\n `expected minimum attempts count that does not exceed the maximum attempts count for 'attempts' property if defined for retry node at depth '${depth}'`\n );\n }\n } else if (isInteger(definition.attempts)) {\n // A retry node must have a positive number of attempts if defined.\n if (definition.attempts < 0) {\n throw new Error(\n `expected positive attempts count for 'attempts' property if defined for retry node at depth '${depth}'`\n );\n }\n } else {\n throw new Error(\n `expected integer value or array containing two integer values for 'attempts' property if defined for retry node at depth '${depth}'`\n );\n }\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n\n // Validate the child node of this decorator node.\n validateNode(definition.child, depth + 1);\n}\n\n/**\n * Validate an object that we expect to be a branch node definition.\n * @param definition An object that we expect to be a branch node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateBranchNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"branch\") {\n throw new Error(`expected node type of 'branch' for branch node at depth '${depth}'`);\n }\n\n // Check that the branch node 'ref' property is defined and is a non-empty string.\n if (typeof definition.ref !== \"string\" || definition.ref.length === 0) {\n throw new Error(`expected non-empty string for 'ref' property for branch node at depth '${depth}'`);\n }\n\n // It is invalid to define guard attributes for a branch node as they should be defined on the referenced root node.\n [\"while\", \"until\"].forEach((attributeName) => {\n if (typeof definition[attributeName] !== \"undefined\") {\n throw new Error(\n `guards should not be defined for branch nodes but guard '${attributeName}' was defined for branch node at depth '${depth}'`\n );\n }\n });\n\n // It is invalid to define callback attributes for a branch node as they should be defined on the referenced root node.\n [\"entry\", \"exit\", \"step\"].forEach((attributeName) => {\n if (typeof definition[attributeName] !== \"undefined\") {\n throw new Error(\n `callbacks should not be defined for branch nodes but callback '${attributeName}' was defined for branch node at depth '${depth}'`\n );\n }\n });\n}\n\n/**\n * Validate an object that we expect to be a action node definition.\n * @param definition An object that we expect to be a action node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateActionNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"action\") {\n throw new Error(`expected node type of 'action' for action node at depth '${depth}'`);\n }\n\n // The 'call' property must be defined for a action node definition.\n if (typeof definition.call !== \"string\" || definition.call.length === 0) {\n throw new Error(`expected non-empty string for 'call' property of action node at depth '${depth}'`);\n }\n\n // If any action function arguments have been defined then they must have been defined in an array.\n if (typeof definition.args !== \"undefined\" && !Array.isArray(definition.args)) {\n throw new Error(`expected array for 'args' property if defined for action node at depth '${depth}'`);\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n}\n\n/**\n * Validate an object that we expect to be a condition node definition.\n * @param definition An object that we expect to be a condition node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateConditionNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"condition\") {\n throw new Error(`expected node type of 'condition' for condition node at depth '${depth}'`);\n }\n\n // The 'call' property must be defined for a condition node definition.\n if (typeof definition.call !== \"string\" || definition.call.length === 0) {\n throw new Error(`expected non-empty string for 'call' property of condition node at depth '${depth}'`);\n }\n\n // If any condition function arguments have been defined then they must have been defined in an array.\n if (typeof definition.args !== \"undefined\" && !Array.isArray(definition.args)) {\n throw new Error(`expected array for 'args' property if defined for condition node at depth '${depth}'`);\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n}\n\n/**\n * Validate an object that we expect to be a wait node definition.\n * @param definition An object that we expect to be a wait node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateWaitNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"wait\") {\n throw new Error(`expected node type of 'wait' for wait node at depth '${depth}'`);\n }\n\n // Check whether a 'duration' property has been defined, it may not have been if this node is to wait indefinitely.\n if (typeof definition.duration !== \"undefined\") {\n if (Array.isArray(definition.duration)) {\n // Check whether any elements of the array are not integer values.\n const containsNonInteger = !!definition.duration.filter((value: unknown) => !isInteger(value)).length;\n\n // If the 'duration' property is an array then it MUST contain two integer values.\n if (definition.duration.length !== 2 || containsNonInteger) {\n throw new Error(\n `expected array containing two integer values for 'duration' property if defined for wait node at depth '${depth}'`\n );\n }\n\n // A wait node must have a positive min and max duration value if they are defined.\n if (definition.duration[0] < 0 || definition.duration[1] < 0) {\n throw new Error(\n `expected positive minimum and maximum duration for 'duration' property if defined for wait node at depth '${depth}'`\n );\n }\n\n // A wait node must not have a minimum duration value that exceeds the maximum duration value.\n if (definition.duration[0] > definition.duration[1]) {\n throw new Error(\n `expected minimum duration value that does not exceed the maximum duration value for 'duration' property if defined for wait node at depth '${depth}'`\n );\n }\n } else if (isInteger(definition.duration)) {\n // A wait node must have a positive duration value if defined.\n if (definition.duration < 0) {\n throw new Error(\n `expected positive duration value for 'duration' property if defined for wait node at depth '${depth}'`\n );\n }\n } else {\n throw new Error(\n `expected integer value or array containing two integer values for 'duration' property if defined for wait node at depth '${depth}'`\n );\n }\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n}\n\n/**\n * Validate an object that we expect to be a sequence node definition.\n * @param definition An object that we expect to be a sequence node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateSequenceNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"sequence\") {\n throw new Error(`expected node type of 'sequence' for sequence node at depth '${depth}'`);\n }\n\n // A sequence node is a composite node, so must have a children nodes array defined.\n if (!Array.isArray(definition.children) || definition.children.length === 0) {\n throw new Error(`expected non-empty 'children' array to be defined for sequence node at depth '${depth}'`);\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n\n // Validate the child nodes of this composite node.\n definition.children.forEach((child: any) => validateNode(child, depth + 1));\n}\n\n/**\n * Validate an object that we expect to be a selector node definition.\n * @param definition An object that we expect to be a selector node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateSelectorNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"selector\") {\n throw new Error(`expected node type of 'selector' for selector node at depth '${depth}'`);\n }\n\n // A selector node is a composite node, so must have a children nodes array defined.\n if (!Array.isArray(definition.children) || definition.children.length === 0) {\n throw new Error(`expected non-empty 'children' array to be defined for selector node at depth '${depth}'`);\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n\n // Validate the child nodes of this composite node.\n definition.children.forEach((child: any) => validateNode(child, depth + 1));\n}\n\n/**\n * Validate an object that we expect to be a parallel node definition.\n * @param definition An object that we expect to be a parallel node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateParallelNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"parallel\") {\n throw new Error(`expected node type of 'parallel' for parallel node at depth '${depth}'`);\n }\n\n // A parallel node is a composite node, so must have a children nodes array defined.\n if (!Array.isArray(definition.children) || definition.children.length === 0) {\n throw new Error(`expected non-empty 'children' array to be defined for parallel node at depth '${depth}'`);\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n\n // Validate the child nodes of this composite node.\n definition.children.forEach((child: any) => validateNode(child, depth + 1));\n}\n\n/**\n * Validate an object that we expect to be a lotto node definition.\n * @param definition An object that we expect to be a lotto node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateLottoNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"lotto\") {\n throw new Error(`expected node type of 'lotto' for lotto node at depth '${depth}'`);\n }\n\n // A lotto node is a composite node, so must have a children nodes array defined.\n if (!Array.isArray(definition.children) || definition.children.length === 0) {\n throw new Error(`expected non-empty 'children' array to be defined for lotto node at depth '${depth}'`);\n }\n\n // Check whether a 'weights' property has been defined, if it has we expect it to be an array of weights.\n if (typeof definition.weights !== \"undefined\") {\n // Check that the weights property is an array of positive integers with an element for each child node element.\n if (\n !Array.isArray(definition.weights) ||\n definition.weights.length !== definition.children.length ||\n definition.weights.filter((value: unknown) => !isInteger(value)).length ||\n definition.weights.filter((value: number) => value < 0).length\n ) {\n throw new Error(\n `expected an array of positive integer weight values with a length matching the number of child nodes for 'weights' property if defined for lotto node at depth '${depth}'`\n );\n }\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n\n // Validate the child nodes of this composite node.\n definition.children.forEach((child: any) => validateNode(child, depth + 1));\n}\n\n/**\n * A helper function to create a failure validation result with the given error message.\n * @param errorMessage The validation failure error message.\n * @returns A failure validation result with the given error message.\n */\nfunction createValidationFailureResult(errorMessage: string): DefinitionValidationResult {\n return { succeeded: false, errorMessage };\n}\n", "import { ActionResult, Agent, GlobalFunction } from \"./Agent\";\nimport { RootNodeDefinition } from \"./BehaviourTreeDefinition\";\n\nexport type InvokerFunction = (args: any[]) => ActionResult;\n\n/**\n * A singleton used to store and lookup registered functions and subtrees.\n */\nexport default class Lookup {\n /**\n * The object holding any registered functions keyed on function name.\n */\n private static functionTable: { [key: string]: GlobalFunction } = {};\n /**\n * The object holding any registered subtree root node definitions keyed on tree name.\n */\n private static subtreeTable: { [key: string]: RootNodeDefinition } = {};\n\n /**\n * Gets the function with the specified name.\n * @param name The name of the function.\n * @returns The function with the specified name.\n */\n public static getFunc(name: string): GlobalFunction {\n return this.functionTable[name];\n }\n\n /**\n * Sets the function with the specified name for later lookup.\n * @param name The name of the function.\n * @param func The function.\n */\n public static setFunc(name: string, func: GlobalFunction): void {\n this.functionTable[name] = func;\n }\n\n /**\n * Gets the function invoker for the specified agent and function name.\n * If a function with the specified name exists on the agent object then it will\n * be returned, otherwise we will then check the registered functions for a match.\n * @param agent The agent instance that this behaviour tree is modelling behaviour for.\n * @param name The function name.\n * @returns The function invoker for the specified agent and function name.\n */\n static getFuncInvoker(agent: Agent, name: string): InvokerFunction | null {\n // Check whether the agent contains the specified function.\n const foundOnAgent = agent[name];\n if (foundOnAgent && typeof foundOnAgent === \"function\") {\n return (args: any[]): boolean | ActionResult => foundOnAgent.apply(agent, args);\n }\n\n // The agent does not contain the specified function but it may have been registered at some point.\n if (this.functionTable[name] && typeof this.functionTable[name] === \"function\") {\n return (args: any[]) => this.functionTable[name](agent, ...args.map((arg) => arg.value));\n }\n\n // We have no function to invoke.\n return null;\n }\n\n /**\n * Gets all registered subtree root node definitions.\n */\n static getSubtrees(): { [key: string]: RootNodeDefinition } {\n return this.subtreeTable;\n }\n\n /**\n * Sets the subtree with the specified name for later lookup.\n * @param name The name of the subtree.\n * @param subtree The subtree.\n */\n static setSubtree(name: string, subtree: RootNodeDefinition) {\n this.subtreeTable[name] = subtree;\n }\n\n /**\n * Removes the registered function or subtree with the specified name.\n * @param name The name of the registered function or subtree.\n */\n static remove(name: string) {\n delete this.functionTable[name];\n delete this.subtreeTable[name];\n }\n\n /**\n * Remove all registered functions and subtrees.\n */\n static empty() {\n this.functionTable = {};\n this.subtreeTable = {};\n }\n}\n", "import Node from \"../../nodes/Node\";\n\n/**\n * An exception thrown when evaluating node guard path conditions and a conditions fails.\n */\nexport default class GuardUnsatisifedException extends Error {\n /**\n * @param source The node at which a guard condition failed.\n */\n constructor(private source: Node) {\n super(\"A guard path condition has failed\");\n }\n\n /**\n * Gets whether the specified node is the node at which a guard condition failed.\n * @param node The node to check against the source node.\n * @returns Whether the specified node is the node at which a guard condition failed.\n */\n isSourceNode = (node: Node) => node === this.source;\n}\n", "import { Agent } from \"../../Agent\";\nimport Guard from \"./Guard\";\nimport Node from \"../../nodes/Node\";\nimport GuardUnsatisifedException from \"./GuardUnsatisifedException\";\n\nexport type GuardPathPart = {\n node: Node;\n guards: Guard[];\n};\n\n/**\n * Represents a path of node guards along a root-to-leaf tree path.\n */\nexport default class GuardPath {\n /**\n * @param nodes An array of objects defining a node instance -> guard link, ordered by node depth.\n */\n constructor(private nodes: GuardPathPart[]) {}\n\n /**\n * Evaluate guard conditions for all guards in the tree path, moving outwards from the root.\n * @param agent The agent, required for guard evaluation.\n * @returns An evaluation results object.\n */\n evaluate = (agent: Agent) => {\n // We need to evaluate guard conditions for nodes up the tree, moving outwards from the root.\n for (const details of this.nodes) {\n // There can be multiple guards per node.\n for (const guard of details.guards) {\n // Check whether the guard condition passes, and throw an exception if not.\n if (!guard.isSatisfied(agent)) {\n throw new GuardUnsatisifedException(details.node);\n }\n }\n }\n };\n}\n", "import { BehaviourTreeOptions } from \"../BehaviourTreeOptions\";\nimport State, { AnyState } from \"../State\";\nimport { Agent } from \"../Agent\";\nimport Leaf from \"./leaf/Leaf\";\nimport Attribute from \"../attributes/Attribute\";\nimport Entry from \"../attributes/callbacks/Entry\";\nimport Exit from \"../attributes/callbacks/Exit\";\nimport Step from \"../attributes/callbacks/Step\";\nimport Guard from \"../attributes/guards/Guard\";\nimport GuardPath from \"../attributes/guards/GuardPath\";\nimport GuardUnsatisifedException from \"../attributes/guards/GuardUnsatisifedException\";\n\n/**\n * A base node.\n */\nexport default abstract class Node {\n /**\n * The node uid.\n */\n private readonly uid: string = createNodeUid();\n /**\n * The node state.\n */\n private state: AnyState = State.READY;\n /**\n * The guard path to evaluate as part of a node update.\n */\n private guardPath: GuardPath | undefined;\n\n /**\n * @param type The node type.\n * @param attributes The node attributes.\n * @param args The node argument definitions.\n */\n constructor(private type: string, private attributes: Attribute[], private args: any[]) {}\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected abstract onUpdate(agent: Agent, options: BehaviourTreeOptions): void;\n\n /**\n * Gets the name of the node.\n */\n public abstract getName(): string;\n\n /**\n * Gets whether this node is a leaf node.\n */\n public abstract isLeafNode: () => this is Leaf;\n\n /**\n * Gets/Sets the state of the node.\n */\n getState = (): AnyState => this.state;\n setState = (value: AnyState): void => {\n this.state = value;\n };\n\n /**\n * Gets the unique id of the node.\n */\n getUid = () => this.uid;\n\n /**\n * Gets the type of the node.\n */\n getType = () => this.type;\n\n /**\n * Gets the node attributes.\n */\n getAttributes = () => this.attributes;\n\n /**\n * Gets the node arguments.\n */\n getArguments = () => this.args;\n\n /**\n * Gets the node attribute with the specified type, or null if it does not exist.\n */\n getAttribute(type: \"entry\" | \"ENTRY\"): Entry;\n getAttribute(type: \"exit\" | \"EXIT\"): Exit;\n getAttribute(type: \"step\" | \"STEP\"): Step;\n getAttribute(type: string): Attribute {\n return (\n this.getAttributes().filter((decorator) => decorator.type.toUpperCase() === type.toUpperCase())[0] || null\n );\n }\n\n /**\n * Gets the node attributes.\n */\n getGuardAttributes = (): Guard[] => this.getAttributes().filter((decorator) => decorator.isGuard()) as Guard[];\n\n /**\n * Sets the guard path to evaluate as part of a node update.\n */\n setGuardPath = (value: GuardPath) => (this.guardPath = value);\n\n /**\n * Gets whether a guard path is assigned to this node.\n */\n hasGuardPath = () => !!this.guardPath;\n\n /**\n * Gets whether this node is in the specified state.\n * @param value The value to compare to the node state.\n */\n public is(value: AnyState): boolean {\n return this.state === value;\n }\n\n /**\n * Reset the state of the node.\n */\n public reset(): void {\n this.setState(State.READY);\n }\n\n /**\n * Abort the running of this node.\n * @param agent The agent.\n */\n public abort(agent: Agent): void {\n // There is nothing to do if this node is not in the running state.\n if (!this.is(State.RUNNING)) {\n return;\n }\n\n // Reset the state of this node.\n this.reset();\n\n this.getAttribute(\"exit\")?.callAgentFunction(agent, false, true);\n }\n\n /**\n * Update the node.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n * @returns The result of the update.\n */\n public update(agent: Agent, options: BehaviourTreeOptions): void {\n // If this node is already in a 'SUCCEEDED' or 'FAILED' state then there is nothing to do.\n if (this.is(State.SUCCEEDED) || this.is(State.FAILED)) {\n return;\n }\n\n try {\n // Evaluate all of the guard path conditions for the current tree path.\n this.guardPath!.evaluate(agent);\n\n // If this node is in the READY state then call the ENTRY for this node if it exists.\n if (this.is(State.READY)) {\n this.getAttribute(\"entry\")?.callAgentFunction(agent);\n }\n\n this.getAttribute(\"step\")?.callAgentFunction(agent);\n\n // Do the actual update.\n this.onUpdate(agent, options);\n\n // If this node is now in a 'SUCCEEDED' or 'FAILED' state then call the EXIT for this node if it exists.\n if (this.is(State.SUCCEEDED) || this.is(State.FAILED)) {\n this.getAttribute(\"exit\")?.callAgentFunction(agent, this.is(State.SUCCEEDED), false);\n }\n } catch (error) {\n // If the error is a GuardUnsatisfiedException then we need to determine if this node is the source.\n if (error instanceof GuardUnsatisifedException && error.isSourceNode(this)) {\n // Abort the current node.\n this.abort(agent);\n\n // Any node that is the source of an abort will be a failed node.\n this.setState(State.FAILED);\n } else {\n throw error;\n }\n }\n }\n}\n\n/**\n * Create a randomly generated node uid.\n * @returns A randomly generated node uid.\n */\nfunction createNodeUid(): string {\n var S4 = function () {\n return (((1 + Math.random()) * 0x10000) | 0).toString(16).substring(1);\n };\n return S4() + S4() + \"-\" + S4() + \"-\" + S4() + \"-\" + S4() + \"-\" + S4() + S4() + S4();\n}\n", "import Node from \"../Node\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\n\n/**\n * A composite node that wraps child nodes.\n */\nexport default abstract class Composite extends Node {\n /**\n * @param type The node type.\n * @param attributes The node attributes.\n * @param children The child nodes.\n */\n constructor(type: string, attributes: Attribute[], protected children: Node[]) {\n super(type, attributes, []);\n }\n\n /**\n * Gets whether this node is a leaf node.\n */\n isLeafNode = () => false;\n\n /**\n * Gets the children of this node.\n */\n getChildren = () => this.children;\n\n /**\n * Reset the state of the node.\n */\n reset = () => {\n // Reset the state of this node.\n this.setState(State.READY);\n\n // Reset the state of any child nodes.\n this.getChildren().forEach((child) => child.reset());\n };\n\n /**\n * Abort the running of this node.\n * @param agent The agent.\n */\n abort = (agent: Agent) => {\n // There is nothing to do if this node is not in the running state.\n if (!this.is(State.RUNNING)) {\n return;\n }\n\n // Abort any child nodes.\n this.getChildren().forEach((child) => child.abort(agent));\n\n // Reset the state of this node.\n this.reset();\n\n this.getAttribute(\"exit\")?.callAgentFunction(agent, false, true);\n };\n}\n", "import Composite from \"./Composite\";\nimport State from \"../../State\";\nimport Node from \"../Node\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A PARALLEL node.\n * The child nodes are executed concurrently until one fails or all succeed.\n */\nexport default class Parallel extends Composite {\n /**\n * @param attributes The node attributes.\n * @param children The child nodes.\n */\n constructor(attributes: Attribute[], children: Node[]) {\n super(\"parallel\", attributes, children);\n }\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // Keep a count of the number of succeeded child nodes.\n let succeededCount = 0;\n\n let hasChildFailed = false;\n\n // Iterate over all of the children of this node.\n for (const child of this.children) {\n // If the child has never been updated or is running then we will need to update it now.\n if (child.getState() === State.READY || child.getState() === State.RUNNING) {\n // Update the child of this node.\n child.update(agent, options);\n }\n\n // If the current child has a state of 'SUCCEEDED' then we should move on to the next child.\n if (child.getState() === State.SUCCEEDED) {\n // The child node has succeeded, keep track of this to determine if all children have.\n succeededCount++;\n\n // The child node succeeded, but we have not finished checking every child node yet.\n continue;\n }\n\n // If the current child has a state of 'FAILED' then this node is also a 'FAILED' node.\n if (child.getState() === State.FAILED) {\n hasChildFailed = true;\n\n // There is no need to check the rest of the children.\n break;\n }\n\n // The node should be in the 'RUNNING' state.\n if (child.getState() !== State.RUNNING) {\n // The child node was not in an expected state.\n throw new Error(\"child node was not in an expected state.\");\n }\n }\n\n if (hasChildFailed) {\n // This node is a 'FAILED' node.\n this.setState(State.FAILED);\n\n // Abort every running child.\n for (const child of this.children) {\n if (child.getState() === State.RUNNING) {\n child.abort(agent);\n }\n }\n } else {\n // If all children have succeeded then this node has also succeeded, otherwise it is still running.\n this.setState(succeededCount === this.children.length ? State.SUCCEEDED : State.RUNNING);\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => \"PARALLEL\";\n}\n", "import Composite from \"./Composite\";\nimport Node from \"../Node\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A SELECTOR node.\n * The child nodes are executed in sequence until one succeeds or all fail.\n */\nexport default class Selector extends Composite {\n /**\n * @param attributes The node attributes.\n * @param children The child nodes.\n */\n constructor(attributes: Attribute[], protected children: Node[]) {\n super(\"selector\", attributes, children);\n }\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // Iterate over all of the children of this node.\n for (const child of this.children) {\n // If the child has never been updated or is running then we will need to update it now.\n if (child.getState() === State.READY || child.getState() === State.RUNNING) {\n // Update the child of this node.\n child.update(agent, options);\n }\n\n // If the current child has a state of 'SUCCEEDED' then this node is also a 'SUCCEEDED' node.\n if (child.getState() === State.SUCCEEDED) {\n // This node is a 'SUCCEEDED' node.\n this.setState(State.SUCCEEDED);\n\n // There is no need to check the rest of the selector nodes.\n return;\n }\n\n // If the current child has a state of 'FAILED' then we should move on to the next child.\n if (child.getState() === State.FAILED) {\n // Find out if the current child is the last one in the selector.\n // If it is then this sequence node has also failed.\n if (this.children.indexOf(child) === this.children.length - 1) {\n // This node is a 'FAILED' node.\n this.setState(State.FAILED);\n\n // There is no need to check the rest of the selector as we have completed it.\n return;\n } else {\n // The child node failed, try the next one.\n continue;\n }\n }\n\n // The node should be in the 'RUNNING' state.\n if (child.getState() === State.RUNNING) {\n // This node is a 'RUNNING' node.\n this.setState(State.RUNNING);\n\n // There is no need to check the rest of the selector as the current child is still running.\n return;\n }\n\n // The child node was not in an expected state.\n throw new Error(\"child node was not in an expected state.\");\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => \"SELECTOR\";\n}\n", "import Composite from \"./Composite\";\nimport Node from \"../Node\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A SEQUENCE node.\n * The child nodes are executed in sequence until one fails or all succeed.\n */\nexport default class Sequence extends Composite {\n /**\n * @param attributes The node attributes.\n * @param children The child nodes.\n */\n constructor(attributes: Attribute[], protected children: Node[]) {\n super(\"sequence\", attributes, children);\n }\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // Iterate over all of the children of this node.\n for (const child of this.children) {\n // If the child has never been updated or is running then we will need to update it now.\n if (child.getState() === State.READY || child.getState() === State.RUNNING) {\n // Update the child of this node.\n child.update(agent, options);\n }\n\n // If the current child has a state of 'SUCCEEDED' then we should move on to the next child.\n if (child.getState() === State.SUCCEEDED) {\n // Find out if the current child is the last one in the sequence.\n // If it is then this sequence node has also succeeded.\n if (this.children.indexOf(child) === this.children.length - 1) {\n // This node is a 'SUCCEEDED' node.\n this.setState(State.SUCCEEDED);\n\n // There is no need to check the rest of the sequence as we have completed it.\n return;\n } else {\n // The child node succeeded, but we have not finished the sequence yet.\n continue;\n }\n }\n\n // If the current child has a state of 'FAILED' then this node is also a 'FAILED' node.\n if (child.getState() === State.FAILED) {\n // This node is a 'FAILED' node.\n this.setState(State.FAILED);\n\n // There is no need to check the rest of the sequence.\n return;\n }\n\n // The node should be in the 'RUNNING' state.\n if (child.getState() === State.RUNNING) {\n // This node is a 'RUNNING' node.\n this.setState(State.RUNNING);\n\n // There is no need to check the rest of the sequence as the current child is still running.\n return;\n }\n\n // The child node was not in an expected state.\n throw new Error(\"child node was not in an expected state.\");\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => \"SEQUENCE\";\n}\n", "import createLotto from \"lotto-draw\";\n\nimport Node from \"../Node\";\nimport Composite from \"./Composite\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A LOTTO node.\n * A winning child is picked on the initial update of this node, based on ticket weighting.\n * The state of this node will match the state of the winning child.\n */\nexport default class Lotto extends Composite {\n /**\n * @param attributes The node attributes.\n * @param weights The child node weights.\n * @param children The child nodes.\n */\n constructor(attributes: Attribute[], private weights: number[] | undefined, children: Node[]) {\n super(\"lotto\", attributes, children);\n }\n\n /**\n * The child node selected to be the active one.\n */\n private selectedChild: Node | undefined;\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // If this node is in the READY state then we need to pick a winning child node.\n if (this.is(State.READY)) {\n // Create a lotto draw with which to randomly pick a child node to become the active one.\n const lottoDraw = createLotto({\n // Hook up the optional 'random' behaviour tree function option to the one used by 'lotto-draw'.\n random: options.random,\n // Pass in each child node as a participant in the lotto draw with their respective ticket count.\n participants: this.children.map((child, index) => [child, this.weights?.[index] || 1])\n });\n\n // Randomly pick a child based on ticket weighting, this will become the active child for this composite node.\n this.selectedChild = lottoDraw.draw() || undefined;\n }\n\n // If something went wrong and we don't have an active child then we should throw an error.\n if (!this.selectedChild) {\n throw new Error(\"failed to update lotto node as it has no active child\");\n }\n\n // If the selected child has never been updated or is running then we will need to update it now.\n if (this.selectedChild.getState() === State.READY || this.selectedChild.getState() === State.RUNNING) {\n this.selectedChild.update(agent, options);\n }\n\n // The state of the lotto node is the state of its selected child.\n this.setState(this.selectedChild.getState());\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => (this.weights ? `LOTTO [${this.weights.join(\",\")}]` : \"LOTTO\");\n}\n", "import Node from \"../Node\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\n\n/**\n * A decorator node that wraps a single child node.\n */\nexport default abstract class Decorator extends Node {\n /**\n * @param type The node type.\n * @param attributes The node attributes.\n * @param child The child node.\n */\n constructor(type: string, attributes: Attribute[], protected child: Node) {\n super(type, attributes, []);\n }\n\n /**\n * Gets whether this node is a leaf node.\n */\n isLeafNode = () => false;\n\n /**\n * Gets the children of this node.\n */\n getChildren = () => [this.child];\n\n /**\n * Reset the state of the node.\n */\n reset = () => {\n // Reset the state of this node.\n this.setState(State.READY);\n\n // Reset the state of the child node.\n this.child.reset();\n };\n\n /**\n * Abort the running of this node.\n * @param agent The agent.\n */\n abort = (agent: Agent) => {\n // There is nothing to do if this node is not in the running state.\n if (!this.is(State.RUNNING)) {\n return;\n }\n\n // Abort the child node.\n this.child.abort(agent);\n\n // Reset the state of this node.\n this.reset();\n\n this.getAttribute(\"exit\")?.callAgentFunction(agent, false, true);\n };\n}\n", "import Node from \"../Node\";\nimport Decorator from \"./Decorator\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A Fail node.\n * This node wraps a single child and will always move to the 'FAILED' state when the child moves to a 'SUCCEEDED' or 'FAILED' state.\n */\nexport default class Fail extends Decorator {\n /**\n * @param attributes The node attributes.\n * @param child The child node.\n */\n constructor(attributes: Attribute[], child: Node) {\n super(\"fail\", attributes, child);\n }\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // If the child has never been updated or is running then we will need to update it now.\n if (this.child.getState() === State.READY || this.child.getState() === State.RUNNING) {\n this.child.update(agent, options);\n }\n\n // The state of this node will depend in the state of its child.\n switch (this.child.getState()) {\n case State.RUNNING:\n this.setState(State.RUNNING);\n break;\n\n case State.SUCCEEDED:\n case State.FAILED:\n this.setState(State.FAILED);\n break;\n\n default:\n this.setState(State.READY);\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => \"FAIL\";\n}\n", "import Decorator from \"./Decorator\";\nimport State from \"../../State\";\nimport Node from \"../Node\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A Flip node.\n * This node wraps a single child and will flip the state of the child state.\n */\nexport default class Flip extends Decorator {\n /**\n * @param attributes The node attributes.\n * @param child The child node.\n */\n constructor(attributes: Attribute[], child: Node) {\n super(\"flip\", attributes, child);\n }\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // If the child has never been updated or is running then we will need to update it now.\n if (this.child.getState() === State.READY || this.child.getState() === State.RUNNING) {\n this.child.update(agent, options);\n }\n\n // The state of this node will depend in the state of its child.\n switch (this.child.getState()) {\n case State.RUNNING:\n this.setState(State.RUNNING);\n break;\n\n case State.SUCCEEDED:\n this.setState(State.FAILED);\n break;\n\n case State.FAILED:\n this.setState(State.SUCCEEDED);\n break;\n\n default:\n this.setState(State.READY);\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => \"FLIP\";\n}\n", "import Node from \"../Node\";\nimport Decorator from \"./Decorator\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A REPEAT node.\n * The node has a single child which can have:\n * -- A number of iterations for which to repeat the child node.\n * -- An infinite repeat loop if neither an iteration count or a condition function is defined.\n * The REPEAT node will stop and have a 'FAILED' state if its child is ever in a 'FAILED' state after an update.\n * The REPEAT node will attempt to move on to the next iteration if its child is ever in a 'SUCCEEDED' state.\n */\nexport default class Repeat extends Decorator {\n /**\n * @param attributes The node attributes.\n * @param iterations The number of iterations to repeat the child node.\n * @param iterationsMin The minimum possible number of iterations to repeat the child node.\n * @param iterationsMax The maximum possible number of iterations to repeat the child node.\n * @param child The child node.\n */\n constructor(\n attributes: Attribute[],\n private iterations: number | null,\n private iterationsMin: number | null,\n private iterationsMax: number | null,\n child: Node\n ) {\n super(\"repeat\", attributes, child);\n }\n\n /**\n * The number of target iterations to make.\n */\n private targetIterationCount: number | null = null;\n\n /**\n * The current iteration count.\n */\n private currentIterationCount: number = 0;\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // If this node is in the READY state then we need to reset the child and the target iteration count.\n if (this.is(State.READY)) {\n // Reset the child node.\n this.child.reset();\n\n // Reset the current iteration count.\n this.currentIterationCount = 0;\n\n // Set the target iteration count.\n this.setTargetIterationCount(options);\n }\n\n // Do a check to see if we can iterate. If we can then this node will move into the 'RUNNING' state.\n // If we cannot iterate then we have hit our target iteration count, which means that the node has succeeded.\n if (this.canIterate()) {\n // This node is in the running state and can do its initial iteration.\n this.setState(State.RUNNING);\n\n // We may have already completed an iteration, meaning that the child node will be in the SUCCEEDED state.\n // If this is the case then we will have to reset the child node now.\n if (this.child.getState() === State.SUCCEEDED) {\n this.child.reset();\n }\n\n // Update the child of this node.\n this.child.update(agent, options);\n\n // If the child moved into the FAILED state when we updated it then there is nothing left to do and this node has also failed.\n // If it has moved into the SUCCEEDED state then we have completed the current iteration.\n if (this.child.getState() === State.FAILED) {\n // The child has failed, meaning that this node has failed.\n this.setState(State.FAILED);\n\n return;\n } else if (this.child.getState() === State.SUCCEEDED) {\n // We have completed an iteration.\n this.currentIterationCount += 1;\n }\n } else {\n // This node is in the 'SUCCEEDED' state as we cannot iterate any more.\n this.setState(State.SUCCEEDED);\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => {\n if (this.iterations !== null) {\n return `REPEAT ${this.iterations}x`;\n } else if (this.iterationsMin !== null && this.iterationsMax !== null) {\n return `REPEAT ${this.iterationsMin}x-${this.iterationsMax}x`;\n } else {\n return \"REPEAT\";\n }\n };\n\n /**\n * Reset the state of the node.\n */\n reset = () => {\n // Reset the state of this node.\n this.setState(State.READY);\n\n // Reset the current iteration count.\n this.currentIterationCount = 0;\n\n // Reset the child node.\n this.child.reset();\n };\n\n /**\n * Gets whether an iteration can be made.\n * @returns Whether an iteration can be made.\n */\n private canIterate = () => {\n if (this.targetIterationCount !== null) {\n // We can iterate as long as we have not reached our target iteration count.\n return this.currentIterationCount < this.targetIterationCount;\n }\n\n // If neither an iteration count or a condition function were defined then we can iterate indefinitely.\n return true;\n };\n\n /**\n * Sets the target iteration count.\n * @param options The behaviour tree options object.\n */\n private setTargetIterationCount = (options: BehaviourTreeOptions) => {\n // Are we dealing with an explicit iteration count or will we be randomly picking a iteration count between the min and max iteration count.\n if (this.iterations !== null) {\n this.targetIterationCount = this.iterations;\n } else if (this.iterationsMin !== null && this.iterationsMax !== null) {\n // We will be picking a random iteration count between a min and max iteration count, if the optional 'random'\n // behaviour tree function option is defined then we will be using that, otherwise we will fall back to using Math.random.\n const random = typeof options.random === \"function\" ? options.random : Math.random;\n\n // Pick a random iteration count between a min and max iteration count.\n this.targetIterationCount = Math.floor(\n random() * (this.iterationsMax - this.iterationsMin + 1) + this.iterationsMin\n );\n } else {\n this.targetIterationCount = null;\n }\n };\n}\n", "import Node from \"../Node\";\nimport Decorator from \"./Decorator\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A RETRY node.\n * The node has a single child which can have:\n * -- A number of iterations for which to repeat the child node.\n * -- An infinite repeat loop if neither an iteration count or a condition function is defined.\n * The RETRY node will stop and have a 'SUCCEEDED' state if its child is ever in a 'SUCCEEDED' state after an update.\n * The RETRY node will attempt to move on to the next iteration if its child is ever in a 'FAILED' state.\n */\nexport default class Retry extends Decorator {\n /**\n * @param attributes The node attributes.\n * @param attempts The number of attempts to retry the child node.\n * @param attemptsMin The minimum possible number of attempts to retry the child node.\n * @param attemptsMax The maximum possible number of attempts to retry the child node.\n * @param child The child node.\n */\n constructor(\n attributes: Attribute[],\n private attempts: number | null,\n private attemptsMin: number | null,\n private attemptsMax: number | null,\n child: Node\n ) {\n super(\"retry\", attributes, child);\n }\n\n /**\n * The number of target attempts to make.\n */\n private targetAttemptCount: number | null = null;\n\n /**\n * The current attempt count.\n */\n private currentAttemptCount: number = 0;\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // If this node is in the READY state then we need to reset the child and the target attempt count.\n if (this.is(State.READY)) {\n // Reset the child node.\n this.child.reset();\n\n // Reset the current attempt count.\n this.currentAttemptCount = 0;\n\n // Set the target attempt count.\n this.setTargetAttemptCount(options);\n }\n\n // Do a check to see if we can attempt. If we can then this node will move into the 'RUNNING' state.\n // If we cannot attempt then we have hit our target attempt count, which means that the node has succeeded.\n if (this.canAttempt()) {\n // This node is in the running state and can do its initial attempt.\n this.setState(State.RUNNING);\n\n // We may have already completed an attempt, meaning that the child node will be in the FAILED state.\n // If this is the case then we will have to reset the child node now.\n if (this.child.getState() === State.FAILED) {\n this.child.reset();\n }\n\n // Update the child of this node.\n this.child.update(agent, options);\n\n // If the child moved into the SUCCEEDED state when we updated it then there is nothing left to do and this node has also succeeded.\n // If it has moved into the FAILED state then we have completed the current attempt.\n if (this.child.getState() === State.SUCCEEDED) {\n // The child has succeeded, meaning that this node has succeeded.\n this.setState(State.SUCCEEDED);\n\n return;\n } else if (this.child.getState() === State.FAILED) {\n // We have completed an attempt.\n this.currentAttemptCount += 1;\n }\n } else {\n // This node is in the 'FAILED' state as we cannot iterate any more.\n this.setState(State.FAILED);\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => {\n if (this.attempts !== null) {\n return `RETRY ${this.attempts}x`;\n } else if (this.attemptsMin !== null && this.attemptsMax !== null) {\n return `RETRY ${this.attemptsMin}x-${this.attemptsMax}x`;\n } else {\n return \"RETRY\";\n }\n };\n\n /**\n * Reset the state of the node.\n */\n reset = () => {\n // Reset the state of this node.\n this.setState(State.READY);\n\n // Reset the current attempt count.\n this.currentAttemptCount = 0;\n\n // Reset the child node.\n this.child.reset();\n };\n\n /**\n * Gets whether an attempt can be made.\n * @returns Whether an attempt can be made.\n */\n canAttempt = () => {\n if (this.targetAttemptCount !== null) {\n // We can attempt as long as we have not reached our target attempt count.\n return this.currentAttemptCount < this.targetAttemptCount;\n }\n\n // If neither an attempt count or a condition function were defined then we can attempt indefinitely.\n return true;\n };\n\n /**\n * Sets the target attempt count.\n * @param options The behaviour tree options object.\n */\n setTargetAttemptCount = (options: BehaviourTreeOptions) => {\n // Are we dealing with an explicit attempt count or will we be randomly picking an attempt count between the min and max attempt count.\n if (this.attempts !== null) {\n this.targetAttemptCount = this.attempts;\n } else if (this.attemptsMin !== null && this.attemptsMax !== null) {\n // We will be picking a random attempt count between a min and max attempt count, if the optional 'random'\n // behaviour tree function option is defined then we will be using that, otherwise we will fall back to using Math.random.\n const random = typeof options.random === \"function\" ? options.random : Math.random;\n\n // Pick a random attempt count between a min and max attempt count.\n this.targetAttemptCount = Math.floor(\n random() * (this.attemptsMax - this.attemptsMin + 1) + this.attemptsMin\n );\n } else {\n this.targetAttemptCount = null;\n }\n };\n}\n", "import Node from \"../Node\";\nimport Decorator from \"./Decorator\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A Root node.\n * The root node will have a single child.\n */\nexport default class Root extends Decorator {\n /**\n * @param attributes The node attributes.\n * @param child The child node.\n */\n constructor(attributes: Attribute[], child: Node) {\n super(\"root\", attributes, child);\n }\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // If the child has never been updated or is running then we will need to update it now.\n if (this.child.getState() === State.READY || this.child.getState() === State.RUNNING) {\n // Update the child of this node.\n this.child.update(agent, options);\n }\n\n // The state of the root node is the state of its child.\n this.setState(this.child.getState());\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => \"ROOT\";\n}\n", "import Node from \"../Node\";\nimport Decorator from \"./Decorator\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A Succeed node.\n * This node wraps a single child and will always move to the 'SUCCEEDED' state when the child moves to a 'SUCCEEDED' or 'FAILED' state.\n */\nexport default class Succeed extends Decorator {\n /**\n * @param attributes The node attributes.\n * @param child The child node.\n */\n constructor(attributes: Attribute[], child: Node) {\n super(\"succeed\", attributes, child);\n }\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // If the child has never been updated or is running then we will need to update it now.\n if (this.child.getState() === State.READY || this.child.getState() === State.RUNNING) {\n this.child.update(agent, options);\n }\n\n // The state of this node will depend in the state of its child.\n switch (this.child.getState()) {\n case State.RUNNING:\n this.setState(State.RUNNING);\n break;\n\n case State.SUCCEEDED:\n case State.FAILED:\n this.setState(State.SUCCEEDED);\n break;\n\n default:\n this.setState(State.READY);\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => \"SUCCEED\";\n}\n", "import Node from \"../Node\";\n\n/**\n * A leaf node.\n */\nexport default abstract class Leaf extends Node {\n /**\n * Gets whether this node is a leaf node.\n */\n isLeafNode = () => true;\n}\n", "import { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\nimport State, { CompleteState } from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Leaf from \"./Leaf\";\nimport Lookup from \"../../Lookup\";\nimport Attribute from \"../../attributes/Attribute\";\n\n/**\n * An Action leaf node.\n * This represents an immediate or ongoing state of behaviour.\n */\nexport default class Action extends Leaf {\n /**\n * @param attributes The node attributes.\n * @param actionName The action name.\n * @param actionArguments The array of action argument definitions.\n */\n constructor(attributes: Attribute[], private actionName: string, private actionArguments: any[]) {\n super(\"action\", attributes, actionArguments);\n }\n\n /**\n * Whether there is a pending update promise.\n */\n private isUsingUpdatePromise = false;\n\n /**\n * The finished state result of an update promise.\n */\n private updatePromiseStateResult: CompleteState | null = null;\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // If the result of this action depends on an update promise then there is nothing to do until\n // it resolves, unless there has been a value set as a result of the update promise resolving.\n if (this.isUsingUpdatePromise) {\n // Check whether the update promise has resolved with a state value.\n if (this.updatePromiseStateResult) {\n // Set the state of this node to match the state returned by the promise.\n this.setState(this.updatePromiseStateResult);\n }\n\n return;\n }\n\n // Attempt to get the invoker for the action function.\n const actionFuncInvoker = Lookup.getFuncInvoker(agent, this.actionName);\n\n // The action function should be defined.\n if (actionFuncInvoker === null) {\n throw new Error(\n `cannot update action node as the action '${this.actionName}' function is not defined on the agent and has not been registered`\n );\n }\n\n let actionFunctionResult;\n\n try {\n // Call the action function, the result of which may be:\n // - The finished state of this action node.\n // - A promise to return a finished node state.\n // - Undefined if the node should remain in the running state.\n actionFunctionResult = actionFuncInvoker(this.actionArguments) as CompleteState | Promise;\n } catch (error) {\n // The user was naughty and threw something.\n throw new Error(`action function '${this.actionName}' threw '${error}'`);\n }\n\n if (actionFunctionResult instanceof Promise) {\n actionFunctionResult.then(\n (result) => {\n // If 'isUpdatePromisePending' is null then the promise was cleared as it was resolving, probably via an abort of reset.\n if (!this.isUsingUpdatePromise) {\n return;\n }\n\n // Check to make sure the result is a valid finished state.\n if (result !== State.SUCCEEDED && result !== State.FAILED) {\n throw new Error(\n \"action node promise resolved with an invalid value, expected a State.SUCCEEDED or State.FAILED value to be returned\"\n );\n }\n\n // Set pending update promise state result to be processed on next update.\n this.updatePromiseStateResult = result;\n },\n (reason) => {\n // If 'isUpdatePromisePending' is null then the promise was cleared as it was resolving, probably via an abort or reset.\n if (!this.isUsingUpdatePromise) {\n return;\n }\n\n // TODO We shouldn't throw an error here, we actually need to set this.updatePromiseRejectionReason so that it can be thrown on the next tree.step() call.\n\n // The promise was rejected, which isn't great.\n throw new Error(`action function '${this.actionName}' promise rejected with reason '${reason}'`);\n }\n );\n\n // This node will be in the 'RUNNING' state until the update promise resolves.\n this.setState(State.RUNNING);\n\n // We are now waiting for the promise returned by the use to resolve before we know what state this node is in.\n this.isUsingUpdatePromise = true;\n } else {\n // Validate the returned value.\n this.validateUpdateResult(actionFunctionResult);\n\n // Set the state of this node, this may be undefined, which just means that the node is still in the 'RUNNING' state.\n this.setState(actionFunctionResult || State.RUNNING);\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => this.actionName;\n\n /**\n * Reset the state of the node.\n */\n reset = () => {\n // Reset the state of this node.\n this.setState(State.READY);\n\n // There is no longer an update promise that we care about.\n this.isUsingUpdatePromise = false;\n this.updatePromiseStateResult = null;\n };\n\n /**\n * Validate the result of an update function call.\n * @param result The result of an update function call.\n */\n private validateUpdateResult = (result: CompleteState | boolean) => {\n switch (result) {\n case State.SUCCEEDED:\n case State.FAILED:\n case undefined:\n return;\n default:\n throw new Error(\n `action '${this.actionName}' 'onUpdate' returned an invalid response, expected an optional State.SUCCEEDED or State.FAILED value to be returned`\n );\n }\n };\n}\n", "import { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Leaf from \"./Leaf\";\nimport Lookup from \"../../Lookup\";\nimport Attribute from \"../../attributes/Attribute\";\n\n/**\n * A Condition leaf node.\n * This will succeed or fail immediately based on an agent predicate, without moving to the 'RUNNING' state.\n */\nexport default class Condition extends Leaf {\n /**\n * @param attributes The node attributes.\n * @param conditionName The name of the condition function.\n * @param conditionArguments The array of condition argument definitions.\n */\n constructor(attributes: Attribute[], private conditionName: string, private conditionArguments: any[]) {\n super(\"condition\", attributes, conditionArguments);\n }\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // Attempt to get the invoker for the condition function.\n const conditionFuncInvoker = Lookup.getFuncInvoker(agent, this.conditionName);\n\n // The condition function should be defined.\n if (conditionFuncInvoker === null) {\n throw new Error(\n `cannot update condition node as the condition '${this.conditionName}' function is not defined on the agent and has not been registered`\n );\n }\n\n let conditionFunctionResult;\n\n try {\n // Call the condition function to determine the state of this node, the result of which should be a boolean.\n conditionFunctionResult = conditionFuncInvoker(this.conditionArguments);\n } catch (error) {\n // The user was naughty and threw something.\n throw new Error(`condition function '${this.conditionName}' threw '${error}'`);\n }\n\n // The result of calling the condition function must be a boolean value.\n if (typeof conditionFunctionResult !== \"boolean\") {\n throw new Error(\n `expected condition function '${this.conditionName}' to return a boolean but returned '${conditionFunctionResult}'`\n );\n }\n\n // Set the state of this node based on the result of calling the condition function.\n this.setState(!!conditionFunctionResult ? State.SUCCEEDED : State.FAILED);\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => this.conditionName;\n}\n", "import Leaf from \"./Leaf\";\nimport State from \"../../State\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { Agent } from \"../../Agent\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A WAIT node.\n * The state of this node will change to SUCCEEDED after a duration of time\n */\nexport default class Wait extends Leaf {\n /**\n * @param attributes The node attributes.\n * @param duration The duration that this node will wait to succeed in milliseconds.\n * @param durationMin The minimum possible duration in milliseconds that this node will wait to succeed.\n * @param durationMax The maximum possible duration in milliseconds that this node will wait to succeed.\n */\n constructor(\n attributes: Attribute[],\n private duration: number | null,\n private durationMin: number | null,\n private durationMax: number | null\n ) {\n super(\"wait\", attributes, []);\n }\n\n /**\n * The time in milliseconds at which this node was first updated.\n */\n private initialUpdateTime: number = 0;\n\n /**\n * The total duration in milliseconds that this node will be waiting for.\n */\n private totalDuration: number | null = null;\n\n /**\n * The duration in milliseconds that this node has been waiting for.\n */\n private waitedDuration: number = 0;\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // If this node is in the READY state then we need to set the initial update time.\n if (this.is(State.READY)) {\n // Set the initial update time.\n this.initialUpdateTime = new Date().getTime();\n\n // Set the initial waited duration.\n this.waitedDuration = 0;\n\n // Are we dealing with an explicit duration or will we be randomly picking a duration between the min and max duration.\n if (this.duration !== null) {\n this.totalDuration = this.duration;\n } else if (this.durationMin !== null && this.durationMax !== null) {\n // We will be picking a random duration between a min and max duration, if the optional 'random' behaviour tree\n // function option is defined then we will be using that, otherwise we will fall back to using Math.random.\n const random = typeof options.random === \"function\" ? options.random : Math.random;\n\n // Pick a random duration between a min and max duration.\n this.totalDuration = Math.floor(\n random() * (this.durationMax - this.durationMin + 1) + this.durationMin\n );\n } else {\n this.totalDuration = null;\n }\n\n // The node is now running until we finish waiting.\n this.setState(State.RUNNING);\n }\n\n // If we have no total duration then this wait node will wait indefinitely until it is aborted.\n if (this.totalDuration === null) {\n return;\n }\n\n // If we have a 'getDeltaTime' function defined as part of our options then we will use it to figure out how long we have waited for.\n if (typeof options.getDeltaTime === \"function\") {\n // Get the delta time.\n const deltaTime = options.getDeltaTime();\n\n // Our delta time must be a valid number and cannot be NaN.\n if (typeof deltaTime !== \"number\" || isNaN(deltaTime)) {\n throw new Error(\"The delta time must be a valid number and not NaN.\");\n }\n\n // Update the amount of time that this node has been waiting for based on the delta time.\n this.waitedDuration += deltaTime * 1000;\n } else {\n // We are not using a delta time, so we will just work out hom much time has passed since the first update.\n this.waitedDuration = new Date().getTime() - this.initialUpdateTime;\n }\n\n // Have we waited long enough?\n if (this.waitedDuration >= this.totalDuration) {\n // We have finished waiting!\n this.setState(State.SUCCEEDED);\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => {\n if (this.duration !== null) {\n return `WAIT ${this.duration}ms`;\n } else if (this.durationMin !== null && this.durationMax !== null) {\n return `WAIT ${this.durationMin}ms-${this.durationMax}ms`;\n } else {\n return \"WAIT\";\n }\n };\n}\n", "import Guard from \"./guards/Guard\";\n\nexport type AttributeDetails = {\n /** The attribute type. */\n type: string;\n\n /** The attribute arguments. */\n args: any[];\n};\n\n/**\n * A base node attribute.\n */\nexport default abstract class Attribute {\n /**\n * @param type The node attribute type.\n * @param args The array of attribute arguments.\n */\n constructor(public type: string, public args: any[]) {}\n\n /**\n * Gets the attribute details.\n */\n abstract getDetails(): TAttributeDetails;\n\n /**\n * Gets whether this attribute is a guard.\n */\n abstract isGuard: () => this is Guard;\n}\n", "import { Agent } from \"../../Agent\";\nimport Attribute, { AttributeDetails } from \"../Attribute\";\n\nexport type GuardAttributeDetails = {\n /** The name of the condition function that determines whether the guard is satisfied. */\n condition: string;\n} & AttributeDetails;\n\n/**\n * A base node guard attribute.\n */\nexport default abstract class Guard extends Attribute {\n /**\n * @param type The node attribute type.\n * @param args The array of decorator argument definitions.\n * @param condition The name of the condition function that determines whether the guard is satisfied.\n */\n constructor(type: string, args: any[], private condition: string) {\n super(type, args);\n }\n\n /**\n * Gets the name of the condition function that determines whether the guard is satisfied.\n */\n getCondition = () => this.condition;\n\n /**\n * Gets whether this attribute is a guard.\n */\n isGuard = () => true;\n\n /**\n * Gets the attribute details.\n */\n getDetails(): GuardAttributeDetails {\n return {\n type: this.type,\n args: this.args,\n condition: this.getCondition()\n };\n }\n\n /**\n * Gets whether the guard is satisfied.\n * @param agent The agent.\n * @returns Whether the guard is satisfied.\n */\n abstract isSatisfied(agent: Agent): boolean;\n}\n", "import Guard from \"./Guard\";\nimport Lookup from \"../../Lookup\";\nimport { Agent } from \"../../Agent\";\n\n/**\n * A WHILE guard which is satisfied as long as the given condition remains true.\n */\nexport default class While extends Guard {\n /**\n * @param condition The name of the condition function that determines whether the guard is satisfied.\n * @param args The array of decorator argument definitions.\n */\n constructor(condition: string, args: any[]) {\n super(\"while\", args, condition);\n }\n\n /**\n * Gets whether the guard is satisfied.\n * @param agent The agent.\n * @returns Whether the guard is satisfied.\n */\n isSatisfied = (agent: Agent) => {\n // Attempt to get the invoker for the condition function.\n const conditionFuncInvoker = Lookup.getFuncInvoker(agent, this.getCondition());\n\n // The condition function should be defined.\n if (conditionFuncInvoker === null) {\n throw new Error(\n `cannot evaluate node guard as the condition '${this.getCondition()}' function is not defined on the agent and has not been registered`\n );\n }\n\n // Call the condition function to determine whether this guard is satisfied.\n return !!conditionFuncInvoker(this.args);\n };\n}\n", "import Guard from \"./Guard\";\nimport Lookup from \"../../Lookup\";\nimport { Agent } from \"../../Agent\";\n\n/**\n * An UNTIL guard which is satisfied as long as the given condition remains false.\n */\nexport default class Until extends Guard {\n /**\n * @param condition The name of the condition function that determines whether the guard is satisfied.\n * @param args The array of decorator argument definitions.\n */\n constructor(condition: string, args: any[]) {\n super(\"until\", args, condition);\n }\n\n /**\n * Gets whether the guard is satisfied.\n * @param agent The agent.\n * @returns Whether the guard is satisfied.\n */\n isSatisfied = (agent: Agent) => {\n // Attempt to get the invoker for the condition function.\n const conditionFuncInvoker = Lookup.getFuncInvoker(agent, this.getCondition());\n\n // The condition function should be defined.\n if (conditionFuncInvoker === null) {\n throw new Error(\n `cannot evaluate node guard as the condition '${this.getCondition()}' function is not defined on the agent and has not been registered`\n );\n }\n\n // Call the condition function to determine whether this guard is satisfied.\n return !!!conditionFuncInvoker(this.args);\n };\n}\n", "import { Agent } from \"../../Agent\";\nimport Attribute, { AttributeDetails } from \"../Attribute\";\n\nexport type CallbackAttributeDetails = {\n /** The name of the agent function that is called. */\n functionName: string;\n} & AttributeDetails;\n\n/**\n * A base node callback attribute.\n */\nexport default abstract class Callback extends Attribute {\n /**\n * @param type The node attribute type.\n * @param args The array of decorator argument definitions.\n * @param functionName The name of the agent function to call.\n */\n constructor(type: string, args: any[], private functionName: string) {\n super(type, args);\n }\n\n /**\n * Gets the name of the agent function to call.\n */\n getFunctionName = () => this.functionName;\n\n /**\n * Gets whether this attribute is a guard.\n */\n isGuard = () => false;\n\n /**\n * Gets the attribute details.\n */\n getDetails(): CallbackAttributeDetails {\n return {\n type: this.type,\n args: this.args,\n functionName: this.getFunctionName()\n };\n }\n\n /**\n * Attempt to call the agent function that this callback refers to.\n * @param agent The agent.\n */\n abstract callAgentFunction: (agent: Agent, isSuccess: boolean, isAborted: boolean) => void;\n}\n", "import Callback from \"./Callback\";\nimport Lookup from \"../../Lookup\";\nimport { Agent } from \"../../Agent\";\n\n/**\n * An ENTRY callback which defines an agent function to call when the associated node is updated and moves out of running state.\n */\nexport default class Entry extends Callback {\n /**\n * @param functionName The name of the agent function to call.\n * @param args The array of callback argument definitions.\n */\n constructor(functionName: string, args: any[]) {\n super(\"entry\", args, functionName);\n }\n\n /**\n * Attempt to call the agent function that this callback refers to.\n * @param agent The agent.\n */\n callAgentFunction = (agent: Agent) => {\n // Attempt to get the invoker for the callback function.\n const callbackFuncInvoker = Lookup.getFuncInvoker(agent, this.getFunctionName());\n\n // The callback function should be defined.\n if (callbackFuncInvoker === null) {\n throw new Error(\n `cannot call entry function '${this.getFunctionName()}' as is not defined on the agent and has not been registered`\n );\n }\n\n // Call the callback function.\n callbackFuncInvoker(this.args);\n };\n}\n", "import Callback from \"./Callback\";\nimport Lookup from \"../../Lookup\";\nimport { Agent } from \"../../Agent\";\n\n/**\n * A STEP callback which defines an agent function to call when the associated node is updated.\n */\nexport default class Step extends Callback {\n /**\n * @param functionName The name of the agent function to call.\n * @param args The array of callback argument definitions.\n */\n constructor(functionName: string, args: any[]) {\n super(\"step\", args, functionName);\n }\n\n /**\n * Attempt to call the agent function that this callback refers to.\n * @param agent The agent.\n */\n callAgentFunction = (agent: Agent) => {\n // Attempt to get the invoker for the callback function.\n const callbackFuncInvoker = Lookup.getFuncInvoker(agent, this.getFunctionName());\n\n // The callback function should be defined.\n if (callbackFuncInvoker === null) {\n throw new Error(\n `cannot call step function '${this.getFunctionName()}' as is not defined on the agent and has not been registered`\n );\n }\n\n // Call the callback function.\n callbackFuncInvoker(this.args);\n };\n}\n", "import Callback from \"./Callback\";\nimport Lookup from \"../../Lookup\";\nimport { Agent } from \"../../Agent\";\n\n/**\n * An EXIT callback which defines an agent function to call when the associated node is updated and moves to a finished state or is aborted.\n */\nexport default class Exit extends Callback {\n /**\n * @param functionName The name of the agent function to call.\n * @param args The array of callback argument definitions.\n */\n constructor(functionName: string, args: any[]) {\n super(\"exit\", args, functionName);\n }\n\n /**\n * Attempt to call the agent function that this callback refers to.\n * @param agent The agent.\n * @param isSuccess Whether the decorated node was left with a success state.\n * @param isAborted Whether the decorated node was aborted.\n */\n callAgentFunction = (agent: Agent, isSuccess: boolean, isAborted: boolean) => {\n // Attempt to get the invoker for the callback function.\n const callbackFuncInvoker = Lookup.getFuncInvoker(agent, this.getFunctionName());\n\n // The callback function should be defined.\n if (callbackFuncInvoker === null) {\n throw new Error(\n `cannot call exit function '${this.getFunctionName()}' as is not defined on the agent and has not been registered`\n );\n }\n\n // Call the callback function\n callbackFuncInvoker([{ value: { succeeded: isSuccess, aborted: isAborted } }, ...this.args]);\n };\n}\n", "import { AnyNodeDefinition, RootNodeDefinition } from \"./BehaviourTreeDefinition\";\nimport GuardPath, { GuardPathPart } from \"./attributes/guards/GuardPath\";\nimport { validateBranchSubtreeLinks } from \"./BehaviourTreeDefinitionValidator\";\nimport { isInteger } from \"./BehaviourTreeDefinitionUtilities\";\nimport Node from \"./nodes/Node\";\nimport Composite from \"./nodes/composite/Composite\";\nimport Decorator from \"./nodes/decorator/Decorator\";\nimport Parallel from \"./nodes/composite/Parallel\";\nimport Selector from \"./nodes/composite/Selector\";\nimport Sequence from \"./nodes/composite/Sequence\";\nimport Lotto from \"./nodes/composite/Lotto\";\nimport Fail from \"./nodes/decorator/Fail\";\nimport Flip from \"./nodes/decorator/Flip\";\nimport Repeat from \"./nodes/decorator/Repeat\";\nimport Retry from \"./nodes/decorator/Retry\";\nimport Root from \"./nodes/decorator/Root\";\nimport Succeed from \"./nodes/decorator/Succeed\";\nimport Action from \"./nodes/leaf/Action\";\nimport Condition from \"./nodes/leaf/Condition\";\nimport Wait from \"./nodes/leaf/Wait\";\nimport Lookup from \"./Lookup\";\nimport Attribute from \"./attributes/Attribute\";\nimport While from \"./attributes/guards/While\";\nimport Until from \"./attributes/guards/Until\";\nimport Entry from \"./attributes/callbacks/Entry\";\nimport Step from \"./attributes/callbacks/Step\";\nimport Exit from \"./attributes/callbacks/Exit\";\n\n/**\n * A type representing any node instance in a behaviour tree.\n */\ntype AnyNode =\n | Root\n | Action\n | Condition\n | Wait\n | Sequence\n | Selector\n | Lotto\n | Parallel\n | Repeat\n | Retry\n | Flip\n | Succeed\n | Fail;\n\n/**\n * A type defining a mapping of root node identifiers to root node definitions.\n */\ntype RootNodeDefinitionMap = { [key: string | symbol]: RootNodeDefinition };\n\n/**\n * A symbol to use as the main root key in any root node mappings.\n */\nconst MAIN_ROOT_NODE_KEY = Symbol(\"__root__\");\n\n/**\n * Build and populate the root nodes based on the provided definition, assuming that the definition has been validated.\n * @param definition The root node definitions.\n * @returns The built and populated root node definitions.\n */\nexport default function buildRootNode(definition: RootNodeDefinition[]): Root {\n // Create a mapping of root node identifers to root node definitions, including globally registered subtree root node definitions.\n const rootNodeDefinitionMap = createRootNodeDefinitionMap(definition);\n\n // Now that we have all of our root node definitons (those part of the tree definition and those globally\n // registered) we should validate the definition. This will also double-check that we dont have any circular\n // dependencies in our branch -> subtree references and that we have no broken branch -> subtree links.\n validateBranchSubtreeLinks(definition, true);\n\n // Create our populated tree of node instances, starting with our main root node.\n const rootNode = nodeFactory(rootNodeDefinitionMap[MAIN_ROOT_NODE_KEY], rootNodeDefinitionMap) as Root;\n\n // Set a guard path on every leaf of the tree to evaluate as part of each update.\n applyLeafNodeGuardPaths(rootNode);\n\n // We only need to return the main root node.\n return rootNode;\n}\n\n/**\n * A factory function which creates a node instance based on the specified definition.\n * @param definition The node definition.\n * @param rootNodeDefinitionMap The mapping of root node identifers to root node definitions, including globally registered subtree root node definitions.\n * @returns A node instance based on the specified definition.\n */\nfunction nodeFactory(definition: AnyNodeDefinition, rootNodeDefinitionMap: RootNodeDefinitionMap): AnyNode {\n // Get the attributes for the node.\n const attributes = nodeAttributesFactory(definition);\n\n // Create the node instance based on the definition type.\n switch (definition.type) {\n case \"root\":\n return new Root(attributes, nodeFactory(definition.child, rootNodeDefinitionMap));\n\n case \"repeat\":\n let iterations: number | null = null;\n let iterationsMin: number | null = null;\n let iterationsMax: number | null = null;\n\n if (Array.isArray(definition.iterations)) {\n iterationsMin = definition.iterations[0];\n iterationsMax = definition.iterations[1];\n } else if (isInteger(definition.iterations)) {\n iterations = definition.iterations!;\n }\n\n return new Repeat(\n attributes,\n iterations,\n iterationsMin,\n iterationsMax,\n nodeFactory(definition.child, rootNodeDefinitionMap)\n );\n\n case \"retry\":\n let attempts: number | null = null;\n let attemptsMin: number | null = null;\n let attemptsMax: number | null = null;\n\n if (Array.isArray(definition.attempts)) {\n attemptsMin = definition.attempts[0];\n attemptsMax = definition.attempts[1];\n } else if (isInteger(definition.attempts)) {\n attempts = definition.attempts!;\n }\n\n return new Retry(\n attributes,\n attempts,\n attemptsMin,\n attemptsMax,\n nodeFactory(definition.child, rootNodeDefinitionMap)\n );\n\n case \"flip\":\n return new Flip(attributes, nodeFactory(definition.child, rootNodeDefinitionMap));\n\n case \"succeed\":\n return new Succeed(attributes, nodeFactory(definition.child, rootNodeDefinitionMap));\n\n case \"fail\":\n return new Fail(attributes, nodeFactory(definition.child, rootNodeDefinitionMap));\n\n case \"sequence\":\n return new Sequence(\n attributes,\n definition.children.map((child) => nodeFactory(child, rootNodeDefinitionMap))\n );\n\n case \"selector\":\n return new Selector(\n attributes,\n definition.children.map((child) => nodeFactory(child, rootNodeDefinitionMap))\n );\n\n case \"parallel\":\n return new Parallel(\n attributes,\n definition.children.map((child) => nodeFactory(child, rootNodeDefinitionMap))\n );\n\n case \"lotto\":\n return new Lotto(\n attributes,\n definition.weights,\n definition.children.map((child) => nodeFactory(child, rootNodeDefinitionMap))\n );\n\n case \"branch\":\n return nodeFactory(rootNodeDefinitionMap[definition.ref].child, rootNodeDefinitionMap);\n\n case \"action\":\n return new Action(attributes, definition.call, definition.args || []);\n\n case \"condition\":\n return new Condition(attributes, definition.call, definition.args || []);\n\n case \"wait\":\n let duration: number | null = null;\n let durationMin: number | null = null;\n let durationMax: number | null = null;\n\n if (Array.isArray(definition.duration)) {\n durationMin = definition.duration[0];\n durationMax = definition.duration[1];\n } else if (isInteger(definition.duration)) {\n duration = definition.duration!;\n }\n\n return new Wait(attributes, duration, durationMin, durationMax);\n }\n}\n\n/**\n * Creates an array of node attribute instances based on the specified node definition.\n * @param definition The node definition.\n * @returns An array of node attribute instances based on the specified node definition.\n */\nfunction nodeAttributesFactory(definition: AnyNodeDefinition): Attribute[] {\n const attributes: Attribute[] = [];\n\n if (definition.while) {\n attributes.push(new While(definition.while.call, definition.while.args ?? []));\n }\n\n if (definition.until) {\n attributes.push(new Until(definition.until.call, definition.until.args ?? []));\n }\n\n if (definition.entry) {\n attributes.push(new Entry(definition.entry.call, definition.entry.args ?? []));\n }\n\n if (definition.step) {\n attributes.push(new Step(definition.step.call, definition.step.args ?? []));\n }\n\n if (definition.exit) {\n attributes.push(new Exit(definition.exit.call, definition.exit.args ?? []));\n }\n\n return attributes;\n}\n\n/**\n * Creates a mapping of root node identifers to root node definitions, mixing in globally registered subtree root node definitions.\n * @param definition The root node definitions.\n * @returns A mapping of root node identifers to root node definitions, including globally registered subtree root node definitions.\n */\nfunction createRootNodeDefinitionMap(definition: RootNodeDefinition[]): RootNodeDefinitionMap {\n // Create a mapping of root node identifers to root node definitions.\n const rootNodeMap: RootNodeDefinitionMap = {};\n\n // Add in any registered subtree root node definitions.\n for (const [name, rootNodeDefinition] of Object.entries(Lookup.getSubtrees())) {\n // The name used when registering the subtree will be used as the root node identifier.\n rootNodeMap[name] = { ...rootNodeDefinition, id: name };\n }\n\n // Populate the map with the root node definitions that were included with the tree definition.\n // We do this after adding any registered subtrees as we want these to take presedence.\n for (const rootNodeDefinition of definition) {\n rootNodeMap[rootNodeDefinition.id ?? MAIN_ROOT_NODE_KEY] = rootNodeDefinition;\n }\n\n return rootNodeMap;\n}\n\n/**\n * Applies a guard path to every leaf of the tree to evaluate as part of each update.\n * @param root The main root tree node.\n */\nfunction applyLeafNodeGuardPaths(root: Root) {\n const nodePaths: Node[][] = [];\n\n const findLeafNodes = (path: Node[], node: Node) => {\n // Add the current node to the path.\n path = path.concat(node);\n\n // Check whether the current node is a leaf node.\n if (node.isLeafNode()) {\n nodePaths.push(path);\n } else {\n (node as Composite | Decorator).getChildren().forEach((child) => findLeafNodes(path, child));\n }\n };\n\n // Find all leaf node paths, starting from the root.\n findLeafNodes([], root);\n\n nodePaths.forEach((path) => {\n // Each node in the current path will have to be assigned a guard path, working from the root outwards.\n for (let depth = 0; depth < path.length; depth++) {\n // Get the node in the path at the current depth.\n const currentNode = path[depth];\n\n // The node may already have been assigned a guard path, if so just skip it.\n if (currentNode.hasGuardPath()) {\n continue;\n }\n\n // Create the guard path for the current node.\n const guardPath = new GuardPath(\n path\n .slice(0, depth + 1)\n .map((node) => ({ node, guards: node.getGuardAttributes() }))\n .filter((details) => details.guards.length > 0)\n );\n\n // Assign the guard path to the current node.\n currentNode.setGuardPath(guardPath);\n }\n });\n}\n", "import State, { AnyState } from \"./State\";\nimport Lookup from \"./Lookup\";\nimport Node from \"./nodes/Node\";\nimport Root from \"./nodes/decorator/Root\";\nimport Composite from \"./nodes/composite/Composite\";\nimport Decorator from \"./nodes/decorator/Decorator\";\nimport { Agent, GlobalFunction } from \"./Agent\";\nimport { CallbackAttributeDetails } from \"./attributes/callbacks/Callback\";\nimport { GuardAttributeDetails } from \"./attributes/guards/Guard\";\nimport { BehaviourTreeOptions } from \"./BehaviourTreeOptions\";\nimport { convertMDSLToJSON } from \"./mdsl/MDSLDefinitionParser\";\nimport { RootNodeDefinition } from \"./BehaviourTreeDefinition\";\nimport { validateDefinition, validateJSONDefinition } from \"./BehaviourTreeDefinitionValidator\";\nimport buildRootNode from \"./BehaviourTreeBuilder\";\nimport { isNullOrUndefined } from \"./BehaviourTreeDefinitionUtilities\";\n\n// Purely for outside inspection of the tree.\nexport type FlattenedTreeNode = {\n id: string;\n type: string;\n caption: string;\n state: AnyState;\n guards: GuardAttributeDetails[];\n callbacks: CallbackAttributeDetails[];\n args: any[];\n parentId: string | null;\n};\n\n/**\n * A representation of a behaviour tree.\n */\nexport class BehaviourTree {\n /**\n * The main root tree node.\n */\n private readonly _rootNode: Root;\n\n /**\n * Creates a new instance of the BehaviourTree class.\n * @param definition The behaviour tree definition as either an MDSL string, root node definition object or array of root node definition objects.\n * @param agent The agent instance that this behaviour tree is modelling behaviour for.\n * @param options The behaviour tree options object.\n */\n constructor(\n definition: string | RootNodeDefinition | RootNodeDefinition[],\n private agent: Agent,\n private options: BehaviourTreeOptions = {}\n ) {\n // The tree definition must be defined.\n if (isNullOrUndefined(definition)) {\n throw new Error(\"tree definition not defined\");\n }\n\n // The agent must be defined and not null.\n if (typeof agent !== \"object\" || agent === null) {\n throw new Error(\"the agent must be an object and not null\");\n }\n\n // We should validate the definition before we try to build the tree nodes.\n const { succeeded, errorMessage, json } = validateDefinition(definition);\n\n // Did our validation fail without error?\n if (!succeeded) {\n throw new Error(`invalid definition: ${errorMessage}`);\n }\n\n // Double check that we did actually get our json definition as part of our definition validtion.\n if (!json) {\n throw new Error(\n \"expected json definition to be returned as part of successful definition validation response\"\n );\n }\n\n try {\n // Create the populated tree of behaviour tree nodes and get the root node.\n this._rootNode = buildRootNode(json);\n } catch (exception) {\n // There was an issue in trying build and populate the behaviour tree.\n throw new Error(`error building tree: ${(exception as Error).message}`);\n }\n }\n\n /**\n * Gets whether the tree is in the RUNNING state.\n * @returns true if the tree is in the RUNNING state, otherwise false.\n */\n isRunning() {\n return this._rootNode.getState() === State.RUNNING;\n }\n\n /**\n * Gets the current tree state of SUCCEEDED, FAILED, READY or RUNNING.\n * @returns The current tree state.\n */\n getState() {\n return this._rootNode.getState();\n }\n\n /**\n * Step the tree.\n * 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.\n * 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\n * 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.\n *\n * 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.\n */\n step() {\n // If the root node has already been stepped to completion then we need to reset it.\n if (this._rootNode.getState() === State.SUCCEEDED || this._rootNode.getState() === State.FAILED) {\n this._rootNode.reset();\n }\n\n try {\n this._rootNode.update(this.agent, this.options);\n } catch (exception) {\n throw new Error(`error stepping tree: ${(exception as Error).message}`);\n }\n }\n\n /**\n * Resets the tree from the root node outwards to each nested node, giving each a state of READY.\n */\n reset() {\n this._rootNode.reset();\n }\n\n /**\n * Gets the flattened details of every node in the tree.\n * @returns The flattened details of every node in the tree.\n */\n getFlattenedNodeDetails(): FlattenedTreeNode[] {\n // Create an empty flattened array of tree nodes.\n const flattenedTreeNodes: FlattenedTreeNode[] = [];\n\n /**\n * Helper function to process a node instance and push details into the flattened tree nodes array.\n * @param node The current node.\n * @param parentUid The UID of the node parent, or null if the node is the main root node.\n */\n const processNode = (node: Node, parentUid: string | null) => {\n // Get the guard and callback attribute details for this node.\n const guards = node\n .getAttributes()\n .filter((attribute) => attribute.isGuard())\n .map((attribute) => attribute.getDetails()) as GuardAttributeDetails[];\n const callbacks = node\n .getAttributes()\n .filter((attribute) => !attribute.isGuard())\n .map((attribute) => attribute.getDetails()) as CallbackAttributeDetails[];\n\n // Push the current node into the flattened nodes array.\n flattenedTreeNodes.push({\n id: node.getUid(),\n type: node.getType(),\n caption: node.getName(),\n state: node.getState(),\n guards,\n callbacks,\n args: node.getArguments(),\n parentId: parentUid\n });\n\n // Process each of the nodes children if it is not a leaf node.\n if (!node.isLeafNode()) {\n (node as Composite | Decorator)\n .getChildren()\n .forEach((child) => processNode(child, (node as Composite | Decorator).getUid()));\n }\n };\n\n // Convert the nested node structure into a flattened array of node details.\n processNode(this._rootNode, null);\n\n return flattenedTreeNodes;\n }\n\n /**\n * Registers the action/condition/guard/callback function or subtree with the given name.\n * @param name The name of the function or subtree to register.\n * @param value The function or subtree definition to register.\n */\n static register(name: string, value: GlobalFunction | string | RootNodeDefinition) {\n // Are we going to register a action/condition/guard/callback function?\n if (typeof value === \"function\") {\n Lookup.setFunc(name, value);\n return;\n }\n\n // We are not registering an action/condition/guard/callback function, so we must be registering a subtree.\n if (typeof value === \"string\") {\n let rootNodeDefinitions: RootNodeDefinition[];\n\n // We will assume that any string passed in will be a mdsl definition.\n try {\n rootNodeDefinitions = convertMDSLToJSON(value);\n } catch (exception) {\n throw new Error(`error registering definition, invalid MDSL: ${(exception as Error).message}`);\n }\n\n // This function should only ever be called with a definition containing a single unnamed root node.\n if (rootNodeDefinitions.length != 1 || rootNodeDefinitions[0].id !== null) {\n throw new Error(\"error registering definition: expected a single unnamed root node\");\n }\n\n try {\n // We should validate the subtree as we don't want invalid subtrees available via the lookup.\n const { succeeded, errorMessage } = validateJSONDefinition(rootNodeDefinitions[0]);\n\n // Did our validation fail without error?\n if (!succeeded) {\n throw new Error(errorMessage);\n }\n } catch (exception) {\n throw new Error(`error registering definition: ${(exception as Error).message}`);\n }\n\n // Everything seems hunky-dory, register the subtree.\n Lookup.setSubtree(name, rootNodeDefinitions[0]);\n } else if (typeof value === \"object\" && !Array.isArray(value)) {\n // We will assume that any object passed in is a root node definition.\n\n try {\n // We should validate the subtree as we don't want invalid subtrees available via the lookup.\n const { succeeded, errorMessage } = validateJSONDefinition(value);\n\n // Did our validation fail without error?\n if (!succeeded) {\n throw new Error(errorMessage);\n }\n } catch (exception) {\n throw new Error(`error registering definition: ${(exception as Error).message}`);\n }\n\n // Everything seems hunky-dory, register the subtree.\n Lookup.setSubtree(name, value);\n } else {\n throw new Error(\"unexpected value, expected string mdsl definition, root node json definition or function\");\n }\n }\n\n /**\n * Unregisters the registered action/condition/guard/callback function or subtree with the given name.\n * @param name The name of the registered action/condition/guard/callback function or subtree to unregister.\n */\n static unregister(name: string): void {\n Lookup.remove(name);\n }\n\n /**\n * Unregister all registered action/condition/guard/callback functions and subtrees.\n */\n static unregisterAll(): void {\n Lookup.empty();\n }\n}\n"], - "mappings": "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", + "sourcesContent": ["\"use strict\";\r\nObject.defineProperty(exports, \"__esModule\", { value: true });\r\nexports.Participant = void 0;\r\n/**\r\n * A participant that holds a number of tickets.\r\n */\r\nvar Participant = /** @class */ (function () {\r\n /**\r\n * Creates an instance of the Participant class.\r\n * @param participant The actual participant.\r\n * @param tickets The number of tickets held by the participant.\r\n */\r\n function Participant(participant, tickets) {\r\n if (tickets === void 0) { tickets = 1; }\r\n this._participant = participant;\r\n this._tickets = tickets;\r\n }\r\n Object.defineProperty(Participant.prototype, \"participant\", {\r\n /** Gets the actual participant. */\r\n get: function () {\r\n return this._participant;\r\n },\r\n enumerable: false,\r\n configurable: true\r\n });\r\n Object.defineProperty(Participant.prototype, \"tickets\", {\r\n /** Gets or sets the number of tickets held by the participant. */\r\n get: function () {\r\n return this._tickets;\r\n },\r\n set: function (value) {\r\n this._tickets = value;\r\n },\r\n enumerable: false,\r\n configurable: true\r\n });\r\n return Participant;\r\n}());\r\nexports.Participant = Participant;\r\n", "\"use strict\";\r\nObject.defineProperty(exports, \"__esModule\", { value: true });\r\nexports.isNaturalNumber = exports.isNullOrUndefined = void 0;\r\n/**\r\n * Gets whether the value provided is null or undefined.\r\n * @param value The value to check.\r\n * @returns Whether the value provided is null or undefined.\r\n */\r\nfunction isNullOrUndefined(value) {\r\n return value === null || value === undefined;\r\n}\r\nexports.isNullOrUndefined = isNullOrUndefined;\r\n/**\r\n * Gets whether the value provided is a natural number.\r\n * @param value The value to check.\r\n * @returns Whether the value provided is a natural number.\r\n */\r\nfunction isNaturalNumber(value) {\r\n return typeof value === \"number\" && value >= 1 && Math.floor(value) === value;\r\n}\r\nexports.isNaturalNumber = isNaturalNumber;\r\n", "\"use strict\";\r\nObject.defineProperty(exports, \"__esModule\", { value: true });\r\nexports.Lotto = void 0;\r\nvar Participant_1 = require(\"./Participant\");\r\nvar Utilities_1 = require(\"./Utilities\");\r\n/**\r\n * Represents a lotto consisting of a number of pickable ticket-holding participants.\r\n */\r\nvar Lotto = /** @class */ (function () {\r\n /**\r\n * Creates a new instance of Lotto.\r\n * @param customRandom The custom RNG to use in place of Math.random().\r\n */\r\n function Lotto(customRandom) {\r\n /** The array of participants that are holding tickets in the lotto. */\r\n this._participants = [];\r\n this._customRandom = customRandom;\r\n }\r\n /**\r\n * Adds a participant with the specified number of tickets, or adds to the participant ticket count if the participant already holds tickets.\r\n * @param participant The participant to add or to increase the ticket count for if they already hold tickets.\r\n * @param tickets The number of tickets, defaults to 1.\r\n * @returns The Lotto instance.\r\n */\r\n Lotto.prototype.add = function (participant, tickets) {\r\n if (tickets === void 0) { tickets = 1; }\r\n // Check that we have a valid ticket count.\r\n if (!(0, Utilities_1.isNaturalNumber)(tickets)) {\r\n throw new Error(\"tickets value must be a natural number\");\r\n }\r\n // Check whether this participant has already been added.\r\n var existingParticipant = this._participants.find(function (part) { return part.participant === participant; });\r\n if (existingParticipant) {\r\n // The participant has already been added to the lotto so just add to their ticket count.\r\n existingParticipant.tickets += tickets;\r\n }\r\n else {\r\n // The participant is not part of the lotto so we should add them.\r\n this._participants.push(new Participant_1.Participant(participant, tickets));\r\n }\r\n return this;\r\n };\r\n /**\r\n * Removes the specified number of tickets for the given participant from the draw, or all tickets if a ticket number is not defined.\r\n * @param participant The participant to remove tickets for.\r\n * @param tickets The number of tickets to remove, or undefined if all tickets are to be removed.\r\n * @returns The Lotto instance.\r\n */\r\n Lotto.prototype.remove = function (participant, tickets) {\r\n // Attempt to get the existing participant.\r\n var existingParticipant = this._participants.find(function (part) { return part.participant === participant; });\r\n // There is nothing to do if the specified participant isn't even part of the lotto.\r\n if (!existingParticipant) {\r\n return this;\r\n }\r\n // Check whether a tickets value was given.\r\n if (tickets !== undefined) {\r\n // Check that we have a valid ticket count.\r\n if (!(0, Utilities_1.isNaturalNumber)(tickets)) {\r\n throw new Error(\"tickets value must be a natural number\");\r\n }\r\n existingParticipant.tickets -= tickets;\r\n // If the participant no longer holds any tickets then they should be removed.\r\n if (existingParticipant.tickets < 1) {\r\n this._participants = this._participants.filter(function (part) { return part !== existingParticipant; });\r\n }\r\n }\r\n else {\r\n // We are removing all tickets for the participant so just remove them from the lotto.\r\n this._participants = this._participants.filter(function (part) { return part !== existingParticipant; });\r\n }\r\n return this;\r\n };\r\n /**\r\n * Draw a winning ticket and return the participant that holds the ticket.\r\n * @param options The draw options.\r\n * @returns The participant that holds the winning ticket.\r\n */\r\n Lotto.prototype.draw = function (options) {\r\n if (options === void 0) { options = {}; }\r\n // If we have no participants then just return null.\r\n if (this._participants.length === 0) {\r\n return null;\r\n }\r\n var redrawable = (0, Utilities_1.isNullOrUndefined)(options.redrawable) ? true : options.redrawable;\r\n var pickable = [];\r\n this._participants.forEach(function (_a) {\r\n var participant = _a.participant, tickets = _a.tickets;\r\n for (var ticketCount = 0; ticketCount < tickets; ticketCount++) {\r\n pickable.push(participant);\r\n }\r\n });\r\n var random;\r\n // We need a random floating-point number between 0 (inclusive) and 1 to scale up to pick our winner.\r\n // If a custom random function exists then we should use that or fall back to Math.random().\r\n if (this._customRandom) {\r\n // Call our custom random function to get a random floating-point number.\r\n random = this._customRandom();\r\n // Verify that the result of calling our custom random function is a number between 0 (inclusive) and 1.\r\n if (typeof random !== \"number\" || random < 0 || random >= 1) {\r\n throw new Error(\"the 'random' function provided did not return a number between 0 (inclusive) and 1\");\r\n }\r\n }\r\n else {\r\n // No custom random function was defined so just use good ol' Math.random().\r\n random = Math.random();\r\n }\r\n // Pick a winning participant.\r\n var winner = pickable[Math.floor(random * pickable.length)];\r\n // If the ticket isn't redrawable then we should remove a ticket from the winning participants ticket count.\r\n if (!redrawable) {\r\n this.remove(winner, 1);\r\n }\r\n // Return the winning participant.\r\n return winner;\r\n };\r\n /**\r\n * Draws multiple winning tickets and return an array of the participants that hold the winning tickets.\r\n * @param tickets The number of winning tickets to draw.\r\n * @param options The draw multiple options.\r\n * @returns An array of the participants that hold the winning tickets.\r\n */\r\n Lotto.prototype.drawMultiple = function (tickets, options) {\r\n if (options === void 0) { options = {}; }\r\n var uniqueResults = (0, Utilities_1.isNullOrUndefined)(options.unique) ? false : options.unique;\r\n // Handle cases where the user has asked for zero tickets (no idea why they would do this be we should trust them).\r\n if (tickets === 0) {\r\n return [];\r\n }\r\n // Now that we know out tickets value is not zero we should check that it is a valid natural number.\r\n if (!(0, Utilities_1.isNaturalNumber)(tickets)) {\r\n throw new Error(\"tickets value must be a natural number\");\r\n }\r\n var result = [];\r\n // Keep drawing tickets until we either reach the number of required tickets or we simply run out of tickets to draw.\r\n // We can run out of tickets to draw if 'options.redrawable' is explicity 'false' or we just had no participants when 'drawMultiple' was called.\r\n while (result.length < tickets && this._participants.length > 0) {\r\n result.push(this.draw(options));\r\n }\r\n // If the 'unique' draw option is set then we need to remove duplicates from the result list.\r\n if (uniqueResults) {\r\n // Create an array to store our unique results.\r\n var unique = [];\r\n // Iterate over all of our participants (with potential duplicates) and populate our array of unique values.\r\n for (var _i = 0, result_1 = result; _i < result_1.length; _i++) {\r\n var participant = result_1[_i];\r\n if (unique.indexOf(participant) === -1) {\r\n unique.push(participant);\r\n }\r\n }\r\n result = unique;\r\n }\r\n return result;\r\n };\r\n return Lotto;\r\n}());\r\nexports.Lotto = Lotto;\r\n", "\"use strict\";\r\nObject.defineProperty(exports, \"__esModule\", { value: true });\r\nexports.createLotto = void 0;\r\nvar Lotto_1 = require(\"./Lotto\");\r\n/**\r\n * A function that creates and returns a Lotto instance.\r\n * @param participantsOrOptions An array of initial participants or options relating to the creation of a Lotto instance.\r\n * @returns A new Lotto instance.\r\n */\r\nfunction createLotto(participantsOrOptions) {\r\n // If no initial participants or lotto options were provided as an argument then we can just return a new lotto instance now.\r\n if (!participantsOrOptions) {\r\n return new Lotto_1.Lotto();\r\n }\r\n // Check whether we were provided with an array of initial participants or a lotto options object.\r\n if (Array.isArray(participantsOrOptions)) {\r\n // We are dealing with a pre-defined array of participants.\r\n var participants = participantsOrOptions;\r\n var lotto_1 = new Lotto_1.Lotto();\r\n // If the lotto participants have been defined upfront then we will need to add them all to our lotto instance now.\r\n participants.forEach(function (_a) {\r\n var participant = _a[0], tokens = _a[1];\r\n return lotto_1.add(participant, tokens);\r\n });\r\n // Return the Lotto instance.\r\n return lotto_1;\r\n }\r\n else {\r\n // We are dealing with some lotto options.\r\n var random = participantsOrOptions.random, participants = participantsOrOptions.participants;\r\n // Create a Lotto instance passing the custom RNG function to use in place of Math.random() (which could be undefined).\r\n var lotto_2 = new Lotto_1.Lotto(random);\r\n // If the lotto participants have been defined upfront as part of the options then we will need to add them all to our lotto instance now.\r\n if (participants) {\r\n participants.forEach(function (_a) {\r\n var participant = _a[0], tokens = _a[1];\r\n return lotto_2.add(participant, tokens);\r\n });\r\n }\r\n // Return the Lotto instance.\r\n return lotto_2;\r\n }\r\n}\r\nexports.createLotto = createLotto;\r\n", "\"use strict\";\r\nObject.defineProperty(exports, \"__esModule\", { value: true });\r\nvar createLotto_1 = require(\"./createLotto\");\r\nexports.default = createLotto_1.createLotto;\r\n", "import State from \"./State\";\nimport { validateDefinition } from \"./BehaviourTreeDefinitionValidator\";\nimport { convertMDSLToJSON } from \"./mdsl/MDSLDefinitionParser\";\nimport { BehaviourTree, FlattenedTreeNode } from \"./BehaviourTree\";\nimport { BehaviourTreeOptions } from \"./BehaviourTreeOptions\";\n\nexport { BehaviourTree, State, convertMDSLToJSON, validateDefinition };\nexport type { FlattenedTreeNode, BehaviourTreeOptions };\n", "/**\n * Enumeration of node state types.\n */\nexport enum State {\n READY = \"mistreevous.ready\",\n RUNNING = \"mistreevous.running\",\n SUCCEEDED = \"mistreevous.succeeded\",\n FAILED = \"mistreevous.failed\"\n}\n\nexport { State as default };\n\nexport type CompleteState = State.SUCCEEDED | State.FAILED;\nexport type AnyState = State.READY | State.RUNNING | CompleteState;\n", "import {\n NodeDefinition,\n RootNodeDefinition,\n DecoratorNodeDefinition,\n CompositeNodeDefinition,\n AnyNodeDefinition,\n BranchNodeDefinition\n} from \"./BehaviourTreeDefinition\";\n\n/**\n * A type guard function that returns true if the specified node satisfies the RootNodeDefinition type.\n * @param node The node.\n * @returns A value of true if the specified node satisfies the RootNodeDefinition type.\n */\nexport function isRootNode(node: NodeDefinition): node is RootNodeDefinition {\n return node.type === \"root\";\n}\n\n/**\n * A type guard function that returns true if the specified node satisfies the BranchNodeDefinition type.\n * @param node The node.\n * @returns A value of true if the specified node satisfies the BranchNodeDefinition type.\n */\nexport function isBranchNode(node: NodeDefinition): node is BranchNodeDefinition {\n return node.type === \"branch\";\n}\n\n/**\n * A type guard function that returns true if the specified node satisfies the NodeDefinition type.\n * @param node The node.\n * @returns A value of true if the specified node satisfies the NodeDefinition type.\n */\nexport function isLeafNode(node: NodeDefinition): node is NodeDefinition {\n return [\"branch\", \"action\", \"condition\", \"wait\"].includes(node.type);\n}\n\n/**\n * A type guard function that returns true if the specified node satisfies the DecoratorNodeDefinition type.\n * @param node The node.\n * @returns A value of true if the specified node satisfies the DecoratorNodeDefinition type.\n */\nexport function isDecoratorNode(node: NodeDefinition): node is DecoratorNodeDefinition {\n return [\"root\", \"repeat\", \"retry\", \"flip\", \"succeed\", \"fail\"].includes(node.type);\n}\n\n/**\n * A type guard function that returns true if the specified node satisfies the CompositeNodeDefinition type.\n * @param node The node.\n * @returns A value of true if the specified node satisfies the CompositeNodeDefinition type.\n */\nexport function isCompositeNode(node: NodeDefinition): node is CompositeNodeDefinition {\n return [\"sequence\", \"selector\", \"lotto\", \"parallel\"].includes(node.type);\n}\n\n/**\n * Flatten a node definition into an array of all of its nested node definitions.\n * @param nodeDefinition The node definition to flatten.\n * @returns An array of all of nested node definitions.\n */\nexport function flattenDefinition(nodeDefinition: AnyNodeDefinition): AnyNodeDefinition[] {\n const nodes: AnyNodeDefinition[] = [];\n\n const processNode = (currentNodeDefinition: AnyNodeDefinition) => {\n nodes.push(currentNodeDefinition);\n\n if (isCompositeNode(currentNodeDefinition)) {\n currentNodeDefinition.children.forEach(processNode);\n } else if (isDecoratorNode(currentNodeDefinition)) {\n processNode(currentNodeDefinition.child);\n }\n };\n\n processNode(nodeDefinition);\n\n return nodes;\n}\n\n/**\n * Determines whether the passed value is an integer.\n * @param value The value to check.\n * @returns Whether the passed value is an integer.\n */\nexport function isInteger(value: unknown): boolean {\n return typeof value === \"number\" && Math.floor(value) === value;\n}\n\n/**\n * Determines whether the passed value is null or undefined.\n * @param value The value to check.\n * @returns Whether the passed value is null or undefined.\n */\nexport function isNullOrUndefined(value: unknown): boolean {\n return typeof value === \"undefined\" || value === null;\n}\n", "/**\n * A type defining an object that holds a reference to substitued string literals parsed from the definition.\n */\nexport type StringLiteralPlaceholders = { [key: string]: string };\n\n/**\n * Pop the next raw token from the specified array of tokens and throw an error if it wasn't the expected one.\n * @param tokens The array of tokens.\n * @param expected An optional string or array or items, one of which must match the next popped token.\n * @returns The popped token.\n */\nexport function popAndCheck(tokens: string[], expected?: string | string[]): string {\n // Get and remove the next token.\n const popped = tokens.shift();\n\n // We were expecting another token but there aren't any.\n if (popped === undefined) {\n throw new Error(\"unexpected end of definition\");\n }\n\n // Do we have an expected token/tokens array?\n if (expected != undefined) {\n // Get an array of expected values, if the popped token matches any then we are all good.\n const expectedValues = typeof expected === \"string\" ? [expected] : expected;\n\n // Check whether the popped token matches at least one of our expected items.\n var tokenMatchesExpectation = expectedValues.some((item) => popped.toUpperCase() === item.toUpperCase());\n\n // Throw an error if the popped token didn't match any of our expected items.\n if (!tokenMatchesExpectation) {\n const expectationString = expectedValues.map((item) => \"'\" + item + \"'\").join(\" or \");\n throw new Error(\"unexpected token found. Expected \" + expectationString + \" but got '\" + popped + \"'\");\n }\n }\n\n // Return the popped token.\n return popped;\n}\n\n/**\n * Swaps out any node/attribute argument string literals with placeholders.\n * @param definition The definition.\n * @returns An object containing a mapping of placeholders to original string values as well as the processed definition string.\n */\nexport function substituteStringLiterals(definition: string): {\n placeholders: StringLiteralPlaceholders;\n processedDefinition: string;\n} {\n // Create an object to hold the mapping of placeholders to original string values.\n const placeholders: StringLiteralPlaceholders = {};\n\n // Replace any string literals wrapped with double quotes in our definition with placeholders to be processed later.\n const processedDefinition = definition.replace(/\\\"(\\\\.|[^\"\\\\])*\\\"/g, (match) => {\n var strippedMatch = match.substring(1, match.length - 1);\n var placeholder = Object.keys(placeholders).find((key) => placeholders[key] === strippedMatch);\n\n // If we have no existing string literal match then create a new placeholder.\n if (!placeholder) {\n placeholder = `@@${Object.keys(placeholders).length}@@`;\n placeholders[placeholder] = strippedMatch;\n }\n\n return placeholder;\n });\n\n return { placeholders, processedDefinition };\n}\n\n/**\n * Parse the tree definition into an array of raw tokens.\n * @param definition The definition.\n * @returns An array of tokens parsed from the definition.\n */\nexport function parseTokensFromDefinition(definition: string): string[] {\n // Add some space around various important characters so that they can be plucked out easier as individual tokens.\n definition = definition.replace(/\\(/g, \" ( \");\n definition = definition.replace(/\\)/g, \" ) \");\n definition = definition.replace(/\\{/g, \" { \");\n definition = definition.replace(/\\}/g, \" } \");\n definition = definition.replace(/\\]/g, \" ] \");\n definition = definition.replace(/\\[/g, \" [ \");\n definition = definition.replace(/\\,/g, \" , \");\n\n // Split the definition into raw token form and return it.\n return definition.replace(/\\s+/g, \" \").trim().split(\" \");\n}\n", "import { StringLiteralPlaceholders, popAndCheck } from \"./MDSLUtilities\";\n\n/**\n * A type representing any node function argument.\n */\ntype Argument = {\n /**\n * The argument value.\n */\n value: T;\n /**\n * The argument type, used for validation.\n */\n type: string;\n};\n\ntype NullArgument = Argument & {\n type: \"null\";\n};\n\ntype BooleanArgument = Argument & {\n type: \"boolean\";\n};\n\ntype NumberArgument = Argument & {\n type: \"number\";\n /**\n * A flag defining whether the number argument value is a valid integer. (used for validation)\n */\n isInteger: boolean;\n};\n\ntype StringPlaceholderArgument = Argument & {\n type: \"string\";\n};\n\ntype IdentifierArgument = Argument & {\n type: \"identifier\";\n};\n\n/**\n * A type representing a reference to any node function argument.\n */\ntype AnyArgument = NullArgument | BooleanArgument | NumberArgument | StringPlaceholderArgument | IdentifierArgument;\n\n/**\n * Parse an array of argument definitions from the specified tokens array.\n * @param tokens The array tokens to parse the argument definitions from.\n * @param stringArgumentPlaceholders The mapping of string literal node argument placeholders to original values.\n * @param argumentValidator The argument validator function.\n * @param validationFailedMessage The exception message to throw if argument validation fails.\n * @returns An array of argument definitions parsed from the specified tokens array.\n */\nexport function parseArgumentTokens(\n tokens: string[],\n stringArgumentPlaceholders: StringLiteralPlaceholders\n): AnyArgument[] {\n const argumentList: AnyArgument[] = [];\n\n // If the next token is not a '[' or '(' then we have no arguments to parse.\n if (![\"[\", \"(\"].includes(tokens[0])) {\n return argumentList;\n }\n\n // Any lists of arguments will always be wrapped in '[]' for node arguments or '()' for attribute arguments.\n // We are looking for a '[' or '(' opener that wraps the argument tokens and the relevant closer.\n const closingToken = popAndCheck(tokens, [\"[\", \"(\"]) === \"[\" ? \"]\" : \")\";\n\n const argumentListTokens: string[] = [];\n\n // Grab all tokens between the '[' and ']' or '(' and ')'.\n while (tokens.length && tokens[0] !== closingToken) {\n // The next token is part of our arguments list.\n argumentListTokens.push(tokens.shift()!);\n }\n\n // Validate the order of the argument tokens. Each token must either be a ',' or a single argument that satisfies the validator.\n argumentListTokens.forEach((token, index) => {\n // Get whether this token should be an actual argument.\n const shouldBeArgumentToken = !(index & 1);\n\n // If the current token should be an actual argument then validate it, otherwise it should be a ',' token.\n if (shouldBeArgumentToken) {\n // Get the argument definition.\n const argumentDefinition = getArgumentDefinition(token, stringArgumentPlaceholders);\n\n // This is a valid argument!\n argumentList.push(argumentDefinition);\n } else {\n // The current token should be a ',' token.\n if (token !== \",\") {\n throw new Error(`invalid argument list, expected ',' or ']' but got '${token}'`);\n }\n }\n });\n\n // The arguments list should terminate with a ']' or ')' token, depending on the opener.\n popAndCheck(tokens, closingToken);\n\n // Return the arguments.\n return argumentList;\n}\n\n/**\n * Gets an argument value definition.\n * @param token The argument token.\n * @param stringArgumentPlaceholders The mapping of string literal node argument placeholders to original values.\n * @returns An argument value definition.\n */\nfunction getArgumentDefinition(token: string, stringArgumentPlaceholders: StringLiteralPlaceholders): AnyArgument {\n // Check whether the token represents a null value.\n if (token === \"null\") {\n return {\n value: null,\n type: \"null\"\n } as NullArgument;\n }\n\n // Check whether the token represents a boolean value.\n if (token === \"true\" || token === \"false\") {\n return {\n value: token === \"true\",\n type: \"boolean\"\n } as BooleanArgument;\n }\n\n // Check whether the token represents a number value.\n // TODO: Relies on broken isNaN - see MDN.\n // if (!Number.isNaN(token)) {\n if (!isNaN(token as any)) {\n return {\n value: parseFloat(token),\n isInteger: parseFloat(token) === parseInt(token, 10),\n type: \"number\"\n } as NumberArgument;\n }\n\n // Check whether the token is a placeholder (e.g. @@0@@) representing a string literal.\n if (token.match(/^@@\\d+@@$/g)) {\n return {\n value: stringArgumentPlaceholders[token].replace('\\\\\"', '\"'),\n type: \"string\"\n } as StringPlaceholderArgument;\n }\n\n // The only remaining option is that the argument value is an identifier.\n return {\n value: token,\n type: \"identifier\"\n } as IdentifierArgument;\n}\n", "import { NodeAttributeDefinition } from \"../BehaviourTreeDefinition\";\nimport { parseArgumentTokens } from \"./MDSLNodeArgumentParser\";\nimport { StringLiteralPlaceholders } from \"./MDSLUtilities\";\n\n/**\n * A type defining the attribute definitions of a node.\n */\ntype NodeAttributes = {\n while?: NodeAttributeDefinition;\n until?: NodeAttributeDefinition;\n entry?: NodeAttributeDefinition;\n exit?: NodeAttributeDefinition;\n step?: NodeAttributeDefinition;\n};\n\n/**\n * Parse any node attribute definitions from the specified tokens array.\n * @param tokens The array of remaining tokens.\n * @param stringArgumentPlaceholders The mapping of string literal node argument placeholders to original values.\n * @returns An object of attribute definitions defined by any directly following tokens.\n */\nexport function parseAttributeTokens(\n tokens: string[],\n stringArgumentPlaceholders: StringLiteralPlaceholders\n): NodeAttributes {\n const nodeAttributeNames: (keyof NodeAttributes)[] = [\"while\", \"until\", \"entry\", \"exit\", \"step\"];\n\n // Create an object to hold any attributes found.\n const attributes: NodeAttributes = {};\n\n // Try to get the name of the attribute for the next token.\n let nextAttributeName = tokens[0]?.toLowerCase() as keyof NodeAttributes;\n\n // Pull attribute tokens as well as their arguments off of the tokens stack until we have no more.\n while (nodeAttributeNames.includes(nextAttributeName)) {\n // Check to make sure that we have not already created an attribute definition of this type.\n if (attributes[nextAttributeName]) {\n throw new Error(`duplicate attribute '${tokens[0].toUpperCase()}' found for node`);\n }\n\n // Remove the attribute name token from the array of tokens.\n tokens.shift();\n\n // Grab the attribute arguments, assuming the first to be an identifier.\n const [attributeCallIdentifier, ...attributeArguments] = parseArgumentTokens(\n tokens,\n stringArgumentPlaceholders\n );\n\n // The first attribute argument has to be an identifer, this will reference an agent function.\n if (attributeCallIdentifier?.type !== \"identifier\") {\n throw new Error(\"expected agent function name identifier argument for attribute\");\n }\n\n // Any attribute arguments (other than the expected call identifier) must have a type of string, number, boolean or null.\n attributeArguments\n .filter((arg) => arg.type === \"identifier\")\n .forEach((arg) => {\n throw new Error(\n `invalid attribute argument value '${arg.value}', must be string, number, boolean or null`\n );\n });\n\n // Create the attribute definition and add it to the object of attribute definitions found.\n attributes[nextAttributeName] = {\n call: attributeCallIdentifier.value,\n args: attributeArguments.map(({ value }) => value)\n };\n\n // Try to get the next attribute name token, as there could be multiple.\n nextAttributeName = tokens[0]?.toLowerCase() as keyof NodeAttributes;\n }\n\n return attributes;\n}\n", "import {\n ActionNodeDefinition,\n AnyChildNodeDefinition,\n AnyNodeDefinition,\n BranchNodeDefinition,\n ConditionNodeDefinition,\n FailNodeDefinition,\n FlipNodeDefinition,\n LottoNodeDefinition,\n ParallelNodeDefinition,\n RepeatNodeDefinition,\n RetryNodeDefinition,\n RootNodeDefinition,\n SelectorNodeDefinition,\n SequenceNodeDefinition,\n SucceedNodeDefinition,\n WaitNodeDefinition\n} from \"../BehaviourTreeDefinition\";\nimport {\n isCompositeNode,\n isDecoratorNode,\n isLeafNode,\n isNullOrUndefined,\n isRootNode\n} from \"../BehaviourTreeDefinitionUtilities\";\nimport { parseArgumentTokens } from \"./MDSLNodeArgumentParser\";\nimport { parseAttributeTokens } from \"./MDSLNodeAttributeParser\";\nimport {\n StringLiteralPlaceholders,\n parseTokensFromDefinition,\n popAndCheck,\n substituteStringLiterals\n} from \"./MDSLUtilities\";\n\n/**\n * Convert the MDSL tree definition string into an equivalent JSON definition.\n * @param definition The tree definition string as MDSL.\n * @returns The root node JSON definitions.\n */\nexport function convertMDSLToJSON(definition: string): RootNodeDefinition[] {\n // Swap out any node/attribute argument string literals with a placeholder and get a mapping of placeholders to original values as well as the processed definition.\n const { placeholders, processedDefinition } = substituteStringLiterals(definition);\n\n // Parse our definition definition string into an array of raw tokens.\n const tokens = parseTokensFromDefinition(processedDefinition);\n\n return convertTokensToJSONDefinition(tokens, placeholders);\n}\n\n/**\n * Converts the specified tree definition tokens into a JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The root node JSON definitions.\n */\nfunction convertTokensToJSONDefinition(\n tokens: string[],\n stringLiteralPlaceholders: StringLiteralPlaceholders\n): RootNodeDefinition[] {\n // There must be at least 3 tokens for the tree definition to be valid. 'ROOT', '{' and '}'.\n if (tokens.length < 3) {\n throw new Error(\"invalid token count\");\n }\n\n // We should have a matching number of '{' and '}' tokens. If not, then there are scopes that have not been properly closed.\n if (tokens.filter((token) => token === \"{\").length !== tokens.filter((token) => token === \"}\").length) {\n throw new Error(\"scope character mismatch\");\n }\n\n // Create an array of tree stack arrays where root nodes will always be at the botton and the current composite/decorator node at the top.\n // There should be an element in this array for every root node defined and every element should be an array with a root note as the first element.\n // E.g. A definition with two root nodes defined:\n // [\n // [root, lotto, sequence],\n // [root, selector]\n // ]\n const treeStacks: [Partial, ...Partial[]][] = [];\n\n // Create an array of all root node definitions that we create.\n const rootNodes: Partial[] = [];\n\n // A helper function used to push node definitions onto the tree stack.\n const pushNode = (node: AnyNodeDefinition) => {\n // If the node is a root node then we need to create a new tree stack array with the root node at the root.\n if (isRootNode(node)) {\n // We need to double-check that this root node is not the child of another node.\n // We can do this by checking whether the top tree stack is not empty (contains an existing node)\n if (treeStacks[treeStacks.length - 1]?.length) {\n throw new Error(\"a root node cannot be the child of another node\");\n }\n\n // Add the root node definition to our array of all parsed root node definitions.\n rootNodes.push(node);\n\n // Add the root node definition to the root of a new tree stack.\n treeStacks.push([node]);\n\n return;\n }\n\n // All non-root nodes should be pushed after their root nodes so handle cases\n // where we may not have any tree stacks or our top-most tree stack is empty.\n if (!treeStacks.length || !treeStacks[treeStacks.length - 1].length) {\n throw new Error(\"expected root node at base of definition\");\n }\n\n // Get the current tree stack that we are populating.\n const topTreeStack = treeStacks[treeStacks.length - 1];\n\n // Get the top-most node in the current tree stack, this will be a composite/decorator node\n // for which we will populate its children array if composite or setting its child if a decorator.\n const topTreeStackTopNode = topTreeStack[topTreeStack.length - 1] as AnyNodeDefinition;\n\n // If the top-most node in the current root stack is a composite or decorator\n // node then the current node should be added as a child of the top-most node.\n if (isCompositeNode(topTreeStackTopNode)) {\n topTreeStackTopNode.children = topTreeStackTopNode.children || [];\n topTreeStackTopNode.children.push(node);\n } else if (isDecoratorNode(topTreeStackTopNode)) {\n // If the top node already has a child node set then throw an error as a decorator should only have a single child.\n if (topTreeStackTopNode.child) {\n throw new Error(\"a decorator node must only have a single child node\");\n }\n\n topTreeStackTopNode.child = node;\n }\n\n // If the node we are adding is also a composite or decorator node, then we should push it\n // onto the current tree stack, as subsequent nodes will be added as its child/children.\n if (!isLeafNode(node)) {\n topTreeStack.push(node);\n }\n };\n\n // A helper function used to pop the top-most node definition off of the tree stack and return it.\n const popNode = (): AnyNodeDefinition | null => {\n let poppedNode: AnyNodeDefinition | null = null;\n\n // Get the current tree stack that we are populating.\n const topTreeStack = treeStacks[treeStacks.length - 1];\n\n // Pop the top-most node in the current tree stack if there is one.\n if (topTreeStack.length) {\n poppedNode = topTreeStack.pop() as AnyNodeDefinition;\n }\n\n // We don't want any empty tree stacks in our stack of tree stacks.\n if (!topTreeStack.length) {\n treeStacks.pop();\n }\n\n return poppedNode;\n };\n\n // We should keep processing the raw tokens until we run out of them.\n while (tokens.length) {\n // Grab the next token.\n const token = tokens.shift()!;\n\n // How we create the next node depends on the current raw token value.\n switch (token.toUpperCase()) {\n case \"ROOT\": {\n pushNode(createRootNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"SUCCEED\": {\n pushNode(createSucceedNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"FAIL\": {\n pushNode(createFailNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"FLIP\": {\n pushNode(createFlipNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"REPEAT\": {\n pushNode(createRepeatNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"RETRY\": {\n pushNode(createRetryNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"SEQUENCE\": {\n pushNode(createSequenceNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"SELECTOR\": {\n pushNode(createSelectorNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"PARALLEL\": {\n pushNode(createParallelNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"LOTTO\": {\n pushNode(createLottoNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"ACTION\": {\n pushNode(createActionNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"CONDITION\": {\n pushNode(createConditionNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"WAIT\": {\n pushNode(createWaitNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"BRANCH\": {\n pushNode(createBranchNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"}\": {\n // The '}' character closes the current scope and means that we have to pop a node off of the current stack.\n const poppedNode = popNode();\n\n // Now that we have a node definition we can carry out any validation that may require the node to be fully populated.\n if (poppedNode) {\n validatePoppedNode(poppedNode);\n }\n\n break;\n }\n\n default: {\n throw new Error(`unexpected token: ${token}`);\n }\n }\n }\n\n return rootNodes as RootNodeDefinition[];\n}\n\n/**\n * Creates a root node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The root node JSON definition.\n */\nfunction createRootNode(tokens: string[], stringLiteralPlaceholders: StringLiteralPlaceholders): RootNodeDefinition {\n // Create the root node definition.\n let node = {\n type: \"root\",\n id: undefined\n } as RootNodeDefinition;\n\n // Parse any node arguments, we should only have one if any which will be an identifier argument for the root identifier.\n const nodeArguments = parseArgumentTokens(tokens, stringLiteralPlaceholders);\n\n // Check whether any node arguments were defined.\n if (nodeArguments.length) {\n // We should only have one argument, if any, which will be an identifier argument for the root identifier.\n if (nodeArguments.length === 1 && nodeArguments[0].type === \"identifier\") {\n // The root node identifier will be the first and only node argument value.\n node.id = nodeArguments[0].value as string;\n } else {\n throw new Error(\"expected single root name argument\");\n }\n }\n\n // Grab any node attribute definitions and spread them into the node definition.\n node = { ...node, ...parseAttributeTokens(tokens, stringLiteralPlaceholders) };\n\n // This is a decorator node, so we expect an opening '{'.\n popAndCheck(tokens, \"{\");\n\n // Return the root node definition.\n return node;\n}\n\n/**\n * Creates a succeed node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The succeed node JSON definition.\n */\nfunction createSucceedNode(\n tokens: string[],\n stringLiteralPlaceholders: StringLiteralPlaceholders\n): SucceedNodeDefinition {\n const node = {\n type: \"succeed\",\n ...parseAttributeTokens(tokens, stringLiteralPlaceholders)\n } as SucceedNodeDefinition;\n\n // This is a decorator node, so we expect an opening '{'.\n popAndCheck(tokens, \"{\");\n\n // Return the succeed node definition.\n return node;\n}\n\n/**\n * Creates a fail node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The fail node JSON definition.\n */\nfunction createFailNode(tokens: string[], stringLiteralPlaceholders: StringLiteralPlaceholders): FailNodeDefinition {\n const node = {\n type: \"fail\",\n ...parseAttributeTokens(tokens, stringLiteralPlaceholders)\n } as FailNodeDefinition;\n\n // This is a decorator node, so we expect an opening '{'.\n popAndCheck(tokens, \"{\");\n\n // Return the fail node definition.\n return node;\n}\n\n/**\n * Creates a flip node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The flip node JSON definition.\n */\nfunction createFlipNode(tokens: string[], stringLiteralPlaceholders: StringLiteralPlaceholders): FlipNodeDefinition {\n const node = {\n type: \"flip\",\n ...parseAttributeTokens(tokens, stringLiteralPlaceholders)\n } as FlipNodeDefinition;\n\n // This is a decorator node, so we expect an opening '{'.\n popAndCheck(tokens, \"{\");\n\n // Return the flip node definition.\n return node;\n}\n\n/**\n * Creates a repeat node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The repeat node JSON definition.\n */\nfunction createRepeatNode(\n tokens: string[],\n stringLiteralPlaceholders: StringLiteralPlaceholders\n): RepeatNodeDefinition {\n let node = { type: \"repeat\" } as RepeatNodeDefinition;\n\n // Get the node arguments.\n const nodeArguments = parseArgumentTokens(tokens, stringLiteralPlaceholders);\n\n // The arguments of a repeat node are optional. We may have:\n // - No node arguments, in which case the repeat note will iterate indefinitely.\n // - One node argument which will be the explicit number of iterations to make.\n // - Two node arguments which define the min and max iteration bounds from which a random iteration count will be picked.\n if (nodeArguments.length) {\n // All repeat node arguments MUST be of type number and must be integer.\n nodeArguments\n .filter((arg) => arg.type !== \"number\" || !arg.isInteger)\n .forEach(() => {\n throw new Error(`repeat node iteration counts must be integer values`);\n });\n\n // We should have got one or two iteration counts.\n if (nodeArguments.length === 1) {\n // A static iteration count was defined.\n node.iterations = nodeArguments[0].value as number;\n\n // A repeat node must have a positive number of iterations if defined.\n if (node.iterations < 0) {\n throw new Error(\"a repeat node must have a positive number of iterations if defined\");\n }\n } else if (nodeArguments.length === 2) {\n // A minimum and maximum iteration count was defined.\n node.iterations = [nodeArguments[0].value as number, nodeArguments[1].value as number];\n\n // A repeat node must have a positive min and max iteration count if they are defined.\n if (node.iterations[0] < 0 || node.iterations[1] < 0) {\n throw new Error(\"a repeat node must have a positive minimum and maximum iteration count if defined\");\n }\n\n // A repeat node must not have an minimum iteration count that exceeds the maximum iteration count.\n if (node.iterations[0] > node.iterations[1]) {\n throw new Error(\n \"a repeat node must not have a minimum iteration count that exceeds the maximum iteration count\"\n );\n }\n } else {\n // An incorrect number of iteration counts was defined.\n throw new Error(\"invalid number of repeat node iteration count arguments defined\");\n }\n }\n\n // Grab any node attribute definitions and spread them into the node definition.\n node = { ...node, ...parseAttributeTokens(tokens, stringLiteralPlaceholders) };\n\n // This is a decorator node, so we expect an opening '{'.\n popAndCheck(tokens, \"{\");\n\n // Return the repeat node definition.\n return node;\n}\n\n/**\n * Creates a retry node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The retry node JSON definition.\n */\nfunction createRetryNode(tokens: string[], stringLiteralPlaceholders: StringLiteralPlaceholders): RetryNodeDefinition {\n let node = { type: \"retry\" } as RetryNodeDefinition;\n\n // Get the node arguments.\n const nodeArguments = parseArgumentTokens(tokens, stringLiteralPlaceholders);\n\n // The arguments of a retry node are optional. We may have:\n // - No node arguments, in which case the retry note will attempt indefinitely.\n // - One node argument which will be the explicit number of attempts to make.\n // - Two node arguments which define the min and max attempt bounds from which a random attempt count will be picked.\n if (nodeArguments.length) {\n // All retry node arguments MUST be of type number and must be integer.\n nodeArguments\n .filter((arg) => arg.type !== \"number\" || !arg.isInteger)\n .forEach(() => {\n throw new Error(`retry node attempt counts must be integer values`);\n });\n\n // We should have got one or two attempt counts.\n if (nodeArguments.length === 1) {\n // A static attempt count was defined.\n node.attempts = nodeArguments[0].value as number;\n\n // A retry node must have a positive number of attempts if defined.\n if (node.attempts < 0) {\n throw new Error(\"a retry node must have a positive number of attempts if defined\");\n }\n } else if (nodeArguments.length === 2) {\n // A minimum and maximum attempt count was defined.\n node.attempts = [nodeArguments[0].value as number, nodeArguments[1].value as number];\n\n // A retry node must have a positive min and max attempts count if they are defined.\n if (node.attempts[0] < 0 || node.attempts[1] < 0) {\n throw new Error(\"a retry node must have a positive minimum and maximum attempt count if defined\");\n }\n\n // A retry node must not have a minimum attempt count that exceeds the maximum attempt count.\n if (node.attempts[0] > node.attempts[1]) {\n throw new Error(\n \"a retry node must not have a minimum attempt count that exceeds the maximum attempt count\"\n );\n }\n } else {\n // An incorrect number of attempt counts was defined.\n throw new Error(\"invalid number of retry node attempt count arguments defined\");\n }\n }\n\n // Grab any node attribute definitions and spread them into the node definition.\n node = { ...node, ...parseAttributeTokens(tokens, stringLiteralPlaceholders) };\n\n // This is a decorator node, so we expect an opening '{'.\n popAndCheck(tokens, \"{\");\n\n // Return the retry node definition.\n return node;\n}\n\n/**\n * Creates a sequence node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The sequence node JSON definition.\n */\nfunction createSequenceNode(\n tokens: string[],\n stringLiteralPlaceholders: StringLiteralPlaceholders\n): SequenceNodeDefinition {\n const node = {\n type: \"sequence\",\n ...parseAttributeTokens(tokens, stringLiteralPlaceholders)\n } as SequenceNodeDefinition;\n\n // This is a composite node, so we expect an opening '{'.\n popAndCheck(tokens, \"{\");\n\n // Return the sequence node definition.\n return node;\n}\n\n/**\n * Creates a selector node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The selector node JSON definition.\n */\nfunction createSelectorNode(\n tokens: string[],\n stringLiteralPlaceholders: StringLiteralPlaceholders\n): SelectorNodeDefinition {\n const node = {\n type: \"selector\",\n ...parseAttributeTokens(tokens, stringLiteralPlaceholders)\n } as SelectorNodeDefinition;\n\n // This is a composite node, so we expect an opening '{'.\n popAndCheck(tokens, \"{\");\n\n // Return the selector node definition.\n return node;\n}\n\n/**\n * Creates a parallel node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The parallel node JSON definition.\n */\nfunction createParallelNode(\n tokens: string[],\n stringLiteralPlaceholders: StringLiteralPlaceholders\n): ParallelNodeDefinition {\n const node = {\n type: \"parallel\",\n ...parseAttributeTokens(tokens, stringLiteralPlaceholders)\n } as ParallelNodeDefinition;\n\n // This is a composite node, so we expect an opening '{'.\n popAndCheck(tokens, \"{\");\n\n // Return the parallel node definition.\n return node;\n}\n\n/**\n * Creates a lotto node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The lotto node JSON definition.\n */\nfunction createLottoNode(tokens: string[], stringLiteralPlaceholders: StringLiteralPlaceholders): LottoNodeDefinition {\n // If any node arguments have been defined then they must be our weights.\n const nodeArguments = parseArgumentTokens(tokens, stringLiteralPlaceholders);\n\n // All lotto node arguments MUST be of type number and must be positive integers.\n nodeArguments\n .filter((arg) => arg.type !== \"number\" || !arg.isInteger || arg.value < 0)\n .forEach(() => {\n throw new Error(`lotto node weight arguments must be positive integer values`);\n });\n\n const node = {\n type: \"lotto\",\n weights: nodeArguments.length ? nodeArguments.map(({ value }) => value) : undefined,\n ...parseAttributeTokens(tokens, stringLiteralPlaceholders)\n } as LottoNodeDefinition;\n\n // This is a composite node, so we expect an opening '{'.\n popAndCheck(tokens, \"{\");\n\n // Return the lotto node definition.\n return node;\n}\n\n/**\n * Creates an action node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The action node JSON definition.\n */\nfunction createActionNode(\n tokens: string[],\n stringLiteralPlaceholders: StringLiteralPlaceholders\n): ActionNodeDefinition {\n // Parse any node arguments, we should have at least one which will be an identifier argument for the action name\n // and agent function to invoke for the action, all other arguments are to be passed as arguments to that function.\n const [actionNameIdentifier, ...agentFunctionArgs] = parseArgumentTokens(tokens, stringLiteralPlaceholders);\n\n // Our first argument MUST be defined and be an identifier as we require an action name argument.\n if (actionNameIdentifier?.type !== \"identifier\") {\n throw new Error(\"expected action name identifier argument\");\n }\n\n // Only the first argument should have been an identifier, all agent function arguments must be string, number, boolean or null.\n agentFunctionArgs\n .filter((arg) => arg.type === \"identifier\")\n .forEach((arg) => {\n throw new Error(\n `invalid action node argument value '${arg.value}', must be string, number, boolean or null`\n );\n });\n\n // Return the action node definition.\n return {\n type: \"action\",\n call: actionNameIdentifier.value,\n args: agentFunctionArgs.map(({ value }) => value),\n ...parseAttributeTokens(tokens, stringLiteralPlaceholders)\n };\n}\n\n/**\n * Creates a condition node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The condition node JSON definition.\n */\nfunction createConditionNode(\n tokens: string[],\n stringLiteralPlaceholders: StringLiteralPlaceholders\n): ConditionNodeDefinition {\n // Parse any node arguments, we should have at least one which will be an identifier argument for the condition name\n // and agent function to invoke for the condition, all other arguments are to be passed as arguments to that function.\n const [conditionNameIdentifier, ...agentFunctionArgs] = parseArgumentTokens(tokens, stringLiteralPlaceholders);\n\n // Our first argument MUST be defined and be an identifier as we require a condition name argument.\n if (conditionNameIdentifier?.type !== \"identifier\") {\n throw new Error(\"expected condition name identifier argument\");\n }\n\n // Only the first argument should have been an identifier, all agent function arguments must be string, number, boolean or null.\n agentFunctionArgs\n .filter((arg) => arg.type === \"identifier\")\n .forEach((arg) => {\n throw new Error(\n `invalid condition node argument value '${arg.value}', must be string, number, boolean or null`\n );\n });\n\n // Return the condition node definition.\n return {\n type: \"condition\",\n call: conditionNameIdentifier.value,\n args: agentFunctionArgs.map(({ value }) => value),\n ...parseAttributeTokens(tokens, stringLiteralPlaceholders)\n };\n}\n\n/**\n * Creates a wait node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The wait node JSON definition.\n */\nfunction createWaitNode(tokens: string[], stringLiteralPlaceholders: StringLiteralPlaceholders): WaitNodeDefinition {\n let node = { type: \"wait\" } as WaitNodeDefinition;\n\n // Get the node arguments.\n const nodeArguments = parseArgumentTokens(tokens, stringLiteralPlaceholders);\n\n // The arguments of a wait node are optional. We may have:\n // - No node arguments, in which case the wait will be indefinite until it is aborted.\n // - One node argument which will be the explicit duration of the wait.\n // - Two node arguments which define the min and max duration bounds from which a random duration will be picked.\n if (nodeArguments.length) {\n // All wait node arguments MUST be of type number and must be integer.\n nodeArguments\n .filter((arg) => arg.type !== \"number\" || !arg.isInteger)\n .forEach(() => {\n throw new Error(`wait node durations must be integer values`);\n });\n\n // We may have:\n // - One node argument which will be the explicit duration of the wait.\n // - Two node arguments which define the min and max duration bounds from which a random duration will be picked.\n // - Too many arguments, which is not valid.\n if (nodeArguments.length === 1) {\n // An explicit duration was defined.\n node.duration = nodeArguments[0].value as number;\n\n // If an explict duration was defined then it must be a positive number.\n if (node.duration < 0) {\n throw new Error(\"a wait node must have a positive duration\");\n }\n } else if (nodeArguments.length === 2) {\n // Min and max duration bounds were defined from which a random duration will be picked.\n node.duration = [nodeArguments[0].value as number, nodeArguments[1].value as number];\n\n // A wait node must have a positive min and max duration.\n if (node.duration[0] < 0 || node.duration[1] < 0) {\n throw new Error(\"a wait node must have a positive minimum and maximum duration\");\n }\n\n // A wait node must not have a minimum duration that exceeds the maximum duration.\n if (node.duration[0] > node.duration[1]) {\n throw new Error(\"a wait node must not have a minimum duration that exceeds the maximum duration\");\n }\n } else if (nodeArguments.length > 2) {\n // An incorrect number of duration arguments were defined.\n throw new Error(\"invalid number of wait node duration arguments defined\");\n }\n }\n\n // Return the wait node definition.\n return { ...node, ...parseAttributeTokens(tokens, stringLiteralPlaceholders) };\n}\n\n/**\n * Creates a branch node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The branch node JSON definition.\n */\nfunction createBranchNode(\n tokens: string[],\n stringLiteralPlaceholders: StringLiteralPlaceholders\n): BranchNodeDefinition {\n // Parse any node arguments, we should have one which will be an identifier argument for the root ref.\n const nodeArguments = parseArgumentTokens(tokens, stringLiteralPlaceholders);\n\n // We should have only a single identifer argument for a branch node, which is the root ref.\n if (nodeArguments.length !== 1 || nodeArguments[0].type !== \"identifier\") {\n throw new Error(\"expected single branch name argument\");\n }\n\n // Return the branch node definition.\n return { type: \"branch\", ref: nodeArguments[0].value };\n}\n\n/**\n * Validate a fully-populated node definition that was popped off of the tree stack.\n * @param definition The popped node to validate.\n */\nfunction validatePoppedNode(definition: AnyNodeDefinition): void {\n // Decorators MUST have a child defined.\n if (isDecoratorNode(definition) && isNullOrUndefined(definition.child)) {\n throw new Error(`a ${definition.type} node must have a single child node defined`);\n }\n\n // Composites MUST have at least one child defined.\n if (isCompositeNode(definition) && !definition.children?.length) {\n throw new Error(`a ${definition.type} node must have at least a single child node defined`);\n }\n\n // We need to make sure that lotto nodes that have weights defined have a number of weights matching the number of child nodes.\n if (definition.type === \"lotto\") {\n // Check whether a 'weights' property has been defined, if it has we expect it to be an array of weights.\n if (typeof definition.weights !== \"undefined\") {\n // Check that the weights property is an array of positive integers with an element for each child node element.\n if (definition.weights.length !== definition.children.length) {\n throw new Error(\n \"expected a number of weight arguments matching the number of child nodes for lotto node\"\n );\n }\n }\n }\n}\n", "import { RootNodeDefinition } from \"./BehaviourTreeDefinition\";\nimport { flattenDefinition, isBranchNode, isInteger } from \"./BehaviourTreeDefinitionUtilities\";\nimport { convertMDSLToJSON } from \"./mdsl/MDSLDefinitionParser\";\n\n/**\n * An object representing the result of validating a tree definition.\n */\nexport type DefinitionValidationResult = {\n /**\n * A flag defining whether validation succeeded.\n */\n succeeded: boolean;\n /**\n * A string containing the error message if validation did not succeed.\n */\n errorMessage?: string;\n /**\n * The definition as json if the validation was successful, or undefined if validation did not succeed.\n */\n json?: RootNodeDefinition[];\n};\n\n/**\n * Validates the specified behaviour tree definition in the form of JSON or MDSL, not taking any globally registered subtrees into consideration.\n * @param definition The behaviour tree definition in the form of JSON or MDSL.\n * @returns An object representing the result of validating the given tree definition.\n */\nexport function validateDefinition(definition: any): DefinitionValidationResult {\n // The definition must be defined.\n if (definition === null || typeof definition === \"undefined\") {\n return createValidationFailureResult(\"definition is null or undefined\");\n }\n\n // We are expecting a definition in one of three different forms:\n // - A string which we will assume is MDSL and we will parse this to JSON before validation.\n // - An array which we will assume is an array of root node definitions with at least one being the primary root node (no 'id' property)\n // - An object which we will assume is the primary root node and should not have an 'id' property.\n if (typeof definition === \"string\") {\n // The definition is a string which we can assume is MDSL, so attempt to validate it.\n return validateMDSLDefinition(definition);\n } else if (typeof definition === \"object\") {\n // The definition will either be an array (of root node definitions) or an object (the single primary root node definition).\n return validateJSONDefinition(definition);\n } else {\n return createValidationFailureResult(`unexpected definition type of '${typeof definition}'`);\n }\n}\n\n/**\n * Validates the specified behaviour tree definition in the form of MDSL.\n * @param definition The behaviour tree definition in the form of MDSL.\n * @returns An object representing the result of validating the given tree definition.\n */\nfunction validateMDSLDefinition(definition: string): DefinitionValidationResult {\n let rootNodeDefinitions;\n\n // The first thing the we need to do is to attempt to convert our MDSL into JSON.\n try {\n // The definition is a string which we can assume is MDSL, so attempt to parse it to a JSON definition in the form of an array of root node definitions.\n rootNodeDefinitions = convertMDSLToJSON(definition);\n } catch (exception) {\n // We failed to parse the JSON from the MDSL, this is likely to be the result of it not being a valid MDSL string.\n return createValidationFailureResult((exception as Error).message);\n }\n\n // Unpack all of the root node definitions into arrays of main ('id' defined) and sub ('id' not defined) root node definitions.\n const mainRootNodeDefinitions = rootNodeDefinitions.filter(({ id }) => typeof id === \"undefined\");\n const subRootNodeDefinitions = rootNodeDefinitions.filter(({ id }) => typeof id === \"string\" && id.length > 0);\n\n // We should ALWAYS have exactly one root node definition without an 'id' property defined, which is out main root node definition.\n if (mainRootNodeDefinitions.length !== 1) {\n return createValidationFailureResult(\n \"expected single unnamed root node at base of definition to act as main root\"\n );\n }\n\n // We should never have duplicate 'id' properties across our sub root node definitions.\n const subRootNodeIdenitifers: string[] = [];\n for (const { id } of subRootNodeDefinitions) {\n // Have we already come across this 'id' property value?\n if (subRootNodeIdenitifers.includes(id!)) {\n return createValidationFailureResult(`multiple root nodes found with duplicate name '${id}'`);\n }\n\n subRootNodeIdenitifers.push(id!);\n }\n\n try {\n // Validate our branch -> subtree links and check for any circular dependencies, we don't care about checking for broken subtree links here.\n validateBranchSubtreeLinks(rootNodeDefinitions, false);\n } catch (exception) {\n return createValidationFailureResult((exception as Error).message);\n }\n\n // Our definition was valid!\n return {\n succeeded: true,\n json: rootNodeDefinitions\n };\n}\n\n/**\n * Validates the specified behaviour tree definition in the form of JSON.\n * @param definition The behaviour tree definition in the form of JSON.\n * @returns An object representing the result of validating the given tree definition.\n */\nexport function validateJSONDefinition(\n definition: RootNodeDefinition | RootNodeDefinition[]\n): DefinitionValidationResult {\n // The definition will either be an array (of root node definitions) or an object (the single primary root node definition).\n const rootNodeDefinitions = Array.isArray(definition) ? definition : [definition];\n\n // Iterate over our array of root nodes and call validateNode for each, passing an initial depth of 0, wrapped in a try catch to handle validation failures.\n try {\n rootNodeDefinitions.forEach((rootNodeDefinition) => validateNode(rootNodeDefinition, 0));\n } catch (error) {\n // Handle cases where we have caught a thrown Error and return a failure result with the error message.\n if (error instanceof Error) {\n return createValidationFailureResult(error.message);\n }\n\n // No idea what happened here!\n return createValidationFailureResult(`unexpected error: ${error}`);\n }\n\n // Unpack all of the root node definitions into arrays of main ('id' defined) and sub ('id' not defined) root node definitions.\n const mainRootNodeDefinitions = rootNodeDefinitions.filter(({ id }) => typeof id === \"undefined\");\n const subRootNodeDefinitions = rootNodeDefinitions.filter(({ id }) => typeof id === \"string\" && id.length > 0);\n\n // We should ALWAYS have exactly one root node definition without an 'id' property defined, which is out main root node definition.\n if (mainRootNodeDefinitions.length !== 1) {\n return createValidationFailureResult(\n \"expected single root node without 'id' property defined to act as main root\"\n );\n }\n\n // We should never have duplicate 'id' properties across our sub root node definitions.\n const subRootNodeIdenitifers: string[] = [];\n for (const { id } of subRootNodeDefinitions) {\n // Have we already come across this 'id' property value?\n if (subRootNodeIdenitifers.includes(id!)) {\n return createValidationFailureResult(\n `multiple root nodes found with duplicate 'id' property value of '${id}'`\n );\n }\n\n subRootNodeIdenitifers.push(id!);\n }\n\n try {\n // Validate our branch -> subtree links and check for any circular dependencies, we don't care about checking for broken subtree links here.\n validateBranchSubtreeLinks(rootNodeDefinitions, false);\n } catch (exception) {\n return createValidationFailureResult((exception as Error).message);\n }\n\n // Our definition was valid!\n return {\n succeeded: true,\n json: rootNodeDefinitions\n };\n}\n\n/**\n * Validates the branch -> subtree links across all provided root node definitions.\n * This will not consider branch nodes that reference any globally registered subtrees unless includesGlobalSubtrees\n * is set to true, in which case we will also verify that there are no broken branch -> subtree links.\n * @param rootNodeDefinitions The array of root node definitions.\n * @param includesGlobalSubtrees A flag defining whether the array includes all global subtree root node definitions.\n */\nexport function validateBranchSubtreeLinks(rootNodeDefinitions: RootNodeDefinition[], includesGlobalSubtrees: boolean) {\n // Create a mapping of root node identifiers to other root nodes that they reference via branch nodes.\n // Below is an example of a mapping that includes a circular dependency (root => a => b => c => a)\n // [{ refs: [\"a\", \"b\"] }, { id: \"a\", refs: [\"b\"] }, { id: \"b\", refs: [\"c\"] }, { id: \"c\", refs: [\"a\"] }]\n const rootNodeMappings: { id: string | undefined; refs: string[] }[] = rootNodeDefinitions.map(\n (rootNodeDefinition) => ({\n id: rootNodeDefinition.id,\n refs: flattenDefinition(rootNodeDefinition)\n .filter(isBranchNode)\n .map(({ ref }) => ref)\n })\n );\n\n // A recursive function to walk through the mappings, keeping track of which root nodes we have visited in the form of a path of root node identifiers.\n const followRefs = (mapping: { id: string | undefined; refs: string[] }, path: (string | undefined)[] = []) => {\n // Have we found a circular dependency?\n if (path.includes(mapping.id)) {\n // We found a circular dependency! Get the bad path of root node identifiers.\n const badPath = [...path, mapping.id];\n\n // Create the formatted path value. [undefined, \"a\", \"b\", \"c\", \"a\"] would be formatted as \"a -> b -> c -> a\".\n const badPathFormatted = badPath.filter((element) => !!element).join(\" => \");\n\n // No need to continue, we found a circular dependency.\n throw new Error(`circular dependency found in branch node references: ${badPathFormatted}`);\n }\n\n for (const ref of mapping.refs) {\n // Find the mapping for the root node with an identifer matching the current ref.\n const subMapping = rootNodeMappings.find(({ id }) => id === ref);\n\n // We may not have a mapping for this ref, which is normal when we aren't considering all globally registered subtrees.\n if (subMapping) {\n followRefs(subMapping, [...path, mapping.id]);\n } else if (includesGlobalSubtrees) {\n // We found a reference to a root node that doesn't exist, which is a problem seeing as the root node definitons includes all globally registered subtrees.\n throw new Error(\n mapping.id\n ? `subtree '${mapping.id}' has branch node that references root node '${ref}' which has not been defined`\n : `primary tree has branch node that references root node '${ref}' which has not been defined`\n );\n }\n }\n };\n\n // Start looking for circular dependencies and broken references from the primary root node definition.\n followRefs(rootNodeMappings.find((mapping) => typeof mapping.id === \"undefined\")!);\n}\n\n/**\n * Validate an object that we expect to be a node definition.\n * @param definition An object that we expect to be a node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateNode(definition: any, depth: number): void {\n // Every node must be valid object and have a non-empty 'type' string property.\n if (typeof definition !== \"object\" || typeof definition.type !== \"string\" || definition.type.length === 0) {\n throw new Error(\n `node definition is not an object or 'type' property is not a non-empty string at depth '${depth}'`\n );\n }\n\n // How we validate this node definition will depend on its type.\n switch (definition.type) {\n case \"action\":\n validateActionNode(definition, depth);\n break;\n\n case \"condition\":\n validateConditionNode(definition, depth);\n break;\n\n case \"wait\":\n validateWaitNode(definition, depth);\n break;\n\n case \"branch\":\n validateBranchNode(definition, depth);\n break;\n\n case \"root\":\n validateRootNode(definition, depth);\n break;\n\n case \"succeed\":\n validateSucceedNode(definition, depth);\n break;\n\n case \"fail\":\n validateFailNode(definition, depth);\n break;\n\n case \"flip\":\n validateFlipNode(definition, depth);\n break;\n\n case \"repeat\":\n validateRepeatNode(definition, depth);\n break;\n\n case \"retry\":\n validateRetryNode(definition, depth);\n break;\n\n case \"sequence\":\n validateSequenceNode(definition, depth);\n break;\n\n case \"selector\":\n validateSelectorNode(definition, depth);\n break;\n\n case \"parallel\":\n validateParallelNode(definition, depth);\n break;\n\n case \"lotto\":\n validateLottoNode(definition, depth);\n break;\n\n default:\n throw new Error(`unexpected node type of '${definition.type}' at depth '${depth}'`);\n }\n}\n\n/**\n * Validate any attributes for a given node definition.\n * @param definition The node definition.\n * @param depth The depth of the node in the behaviour tree definition.\n */\nfunction validateNodeAttributes(definition: any, depth: number): void {\n // Validate each of the attribute types for this node.\n [\"while\", \"until\", \"entry\", \"exit\", \"step\"].forEach((attributeName) => {\n // Attempt to grab the definition for the current attribute from the node definition.\n const attributeDefinition = definition[attributeName];\n\n // All node attributes are optional, so there is nothing to do if the current attribute is not defined.\n if (typeof attributeDefinition === \"undefined\") {\n return;\n }\n\n // The attribute definition must be an object.\n if (typeof attributeDefinition !== \"object\") {\n throw new Error(\n `expected attribute '${attributeName}' to be an object for '${definition.type}' node at depth '${depth}'`\n );\n }\n\n // The 'call' property must be defined for any attribute definition.\n if (typeof attributeDefinition.call !== \"string\" || attributeDefinition.call.length === 0) {\n throw new Error(\n `expected 'call' property for attribute '${attributeName}' to be a non-empty string for '${definition.type}' node at depth '${depth}'`\n );\n }\n\n // If any node attribute arguments have been defined then they must have been defined in an array.\n if (typeof attributeDefinition.args !== \"undefined\" && !Array.isArray(attributeDefinition.args)) {\n throw new Error(\n `expected 'args' property for attribute '${attributeName}' to be an array for '${definition.type}' node at depth '${depth}'`\n );\n }\n });\n}\n\n/**\n * Validate an object that we expect to be a root node definition.\n * @param definition An object that we expect to be a root node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateRootNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"root\") {\n throw new Error(\"expected node type of 'root' for root node\");\n }\n\n // A root node cannot be the child of another node.\n if (depth > 0) {\n throw new Error(\"a root node cannot be the child of another node\");\n }\n\n // Check that, if the root node 'id' property is defined, it is a non-empty string.\n if (typeof definition.id !== \"undefined\" && (typeof definition.id !== \"string\" || definition.id.length === 0)) {\n throw new Error(\"expected non-empty string for 'id' property if defined for root node\");\n }\n\n // A root node is a decorator node, so must have a child node defined.\n if (typeof definition.child === \"undefined\") {\n throw new Error(\"expected property 'child' to be defined for root node\");\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n\n // Validate the child node of this decorator node.\n validateNode(definition.child, depth + 1);\n}\n\n/**\n * Validate an object that we expect to be a succeed node definition.\n * @param definition An object that we expect to be a succeed node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateSucceedNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"succeed\") {\n throw new Error(`expected node type of 'succeed' for succeed node at depth '${depth}'`);\n }\n\n // A succeed node is a decorator node, so must have a child node defined.\n if (typeof definition.child === \"undefined\") {\n throw new Error(`expected property 'child' to be defined for succeed node at depth '${depth}'`);\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n\n // Validate the child node of this decorator node.\n validateNode(definition.child, depth + 1);\n}\n\n/**\n * Validate an object that we expect to be a fail node definition.\n * @param definition An object that we expect to be a fail node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateFailNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"fail\") {\n throw new Error(`expected node type of 'fail' for fail node at depth '${depth}'`);\n }\n\n // A fail node is a decorator node, so must have a child node defined.\n if (typeof definition.child === \"undefined\") {\n throw new Error(`expected property 'child' to be defined for fail node at depth '${depth}'`);\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n\n // Validate the child node of this decorator node.\n validateNode(definition.child, depth + 1);\n}\n\n/**\n * Validate an object that we expect to be a flip node definition.\n * @param definition An object that we expect to be a flip node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateFlipNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"flip\") {\n throw new Error(`expected node type of 'flip' for flip node at depth '${depth}'`);\n }\n\n // A flip node is a decorator node, so must have a child node defined.\n if (typeof definition.child === \"undefined\") {\n throw new Error(`expected property 'child' to be defined for flip node at depth '${depth}'`);\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n\n // Validate the child node of this decorator node.\n validateNode(definition.child, depth + 1);\n}\n\n/**\n * Validate an object that we expect to be a repeat node definition.\n * @param definition An object that we expect to be a repeat node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateRepeatNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"repeat\") {\n throw new Error(`expected node type of 'repeat' for repeat node at depth '${depth}'`);\n }\n\n // A repeat node is a decorator node, so must have a child node defined.\n if (typeof definition.child === \"undefined\") {\n throw new Error(`expected property 'child' to be defined for repeat node at depth '${depth}'`);\n }\n\n // Check whether an 'iterations' property has been defined, it may not have been if this node is to repeat indefinitely.\n if (typeof definition.iterations !== \"undefined\") {\n if (Array.isArray(definition.iterations)) {\n // Check whether any elements of the array are not integer values.\n const containsNonInteger = !!definition.iterations.filter((value: unknown) => !isInteger(value)).length;\n\n // If the 'iterations' property is an array then it MUST contain two integer values.\n if (definition.iterations.length !== 2 || containsNonInteger) {\n throw new Error(\n `expected array containing two integer values for 'iterations' property if defined for repeat node at depth '${depth}'`\n );\n }\n\n // A repeat node must have a positive min and max iterations count if they are defined.\n if (definition.iterations[0] < 0 || definition.iterations[1] < 0) {\n throw new Error(\n `expected positive minimum and maximum iterations count for 'iterations' property if defined for repeat node at depth '${depth}'`\n );\n }\n\n // A repeat node must not have a minimum iterations count that exceeds the maximum iterations count.\n if (definition.iterations[0] > definition.iterations[1]) {\n throw new Error(\n `expected minimum iterations count that does not exceed the maximum iterations count for 'iterations' property if defined for repeat node at depth '${depth}'`\n );\n }\n } else if (isInteger(definition.iterations)) {\n // A repeat node must have a positive number of iterations if defined.\n if (definition.iterations < 0) {\n throw new Error(\n `expected positive iterations count for 'iterations' property if defined for repeat node at depth '${depth}'`\n );\n }\n } else {\n throw new Error(\n `expected integer value or array containing two integer values for 'iterations' property if defined for repeat node at depth '${depth}'`\n );\n }\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n\n // Validate the child node of this decorator node.\n validateNode(definition.child, depth + 1);\n}\n\n/**\n * Validate an object that we expect to be a retry node definition.\n * @param definition An object that we expect to be a retry node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateRetryNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"retry\") {\n throw new Error(`expected node type of 'retry' for retry node at depth '${depth}'`);\n }\n\n // A retry node is a decorator node, so must have a child node defined.\n if (typeof definition.child === \"undefined\") {\n throw new Error(`expected property 'child' to be defined for retry node at depth '${depth}'`);\n }\n\n // Check whether an 'attempts' property has been defined, it may not have been if this node is to retry indefinitely.\n if (typeof definition.attempts !== \"undefined\") {\n if (Array.isArray(definition.attempts)) {\n // Check whether any elements of the array are not integer values.\n const containsNonInteger = !!definition.attempts.filter((value: unknown) => !isInteger(value)).length;\n\n // If the 'attempts' property is an array then it MUST contain two integer values.\n if (definition.attempts.length !== 2 || containsNonInteger) {\n throw new Error(\n `expected array containing two integer values for 'attempts' property if defined for retry node at depth '${depth}'`\n );\n }\n\n // A retry node must have a positive min and max attempts count if they are defined.\n if (definition.attempts[0] < 0 || definition.attempts[1] < 0) {\n throw new Error(\n `expected positive minimum and maximum attempts count for 'attempts' property if defined for retry node at depth '${depth}'`\n );\n }\n\n // A retry node must not have a minimum attempts count that exceeds the maximum attempts count.\n if (definition.attempts[0] > definition.attempts[1]) {\n throw new Error(\n `expected minimum attempts count that does not exceed the maximum attempts count for 'attempts' property if defined for retry node at depth '${depth}'`\n );\n }\n } else if (isInteger(definition.attempts)) {\n // A retry node must have a positive number of attempts if defined.\n if (definition.attempts < 0) {\n throw new Error(\n `expected positive attempts count for 'attempts' property if defined for retry node at depth '${depth}'`\n );\n }\n } else {\n throw new Error(\n `expected integer value or array containing two integer values for 'attempts' property if defined for retry node at depth '${depth}'`\n );\n }\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n\n // Validate the child node of this decorator node.\n validateNode(definition.child, depth + 1);\n}\n\n/**\n * Validate an object that we expect to be a branch node definition.\n * @param definition An object that we expect to be a branch node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateBranchNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"branch\") {\n throw new Error(`expected node type of 'branch' for branch node at depth '${depth}'`);\n }\n\n // Check that the branch node 'ref' property is defined and is a non-empty string.\n if (typeof definition.ref !== \"string\" || definition.ref.length === 0) {\n throw new Error(`expected non-empty string for 'ref' property for branch node at depth '${depth}'`);\n }\n\n // It is invalid to define guard attributes for a branch node as they should be defined on the referenced root node.\n [\"while\", \"until\"].forEach((attributeName) => {\n if (typeof definition[attributeName] !== \"undefined\") {\n throw new Error(\n `guards should not be defined for branch nodes but guard '${attributeName}' was defined for branch node at depth '${depth}'`\n );\n }\n });\n\n // It is invalid to define callback attributes for a branch node as they should be defined on the referenced root node.\n [\"entry\", \"exit\", \"step\"].forEach((attributeName) => {\n if (typeof definition[attributeName] !== \"undefined\") {\n throw new Error(\n `callbacks should not be defined for branch nodes but callback '${attributeName}' was defined for branch node at depth '${depth}'`\n );\n }\n });\n}\n\n/**\n * Validate an object that we expect to be a action node definition.\n * @param definition An object that we expect to be a action node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateActionNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"action\") {\n throw new Error(`expected node type of 'action' for action node at depth '${depth}'`);\n }\n\n // The 'call' property must be defined for a action node definition.\n if (typeof definition.call !== \"string\" || definition.call.length === 0) {\n throw new Error(`expected non-empty string for 'call' property of action node at depth '${depth}'`);\n }\n\n // If any action function arguments have been defined then they must have been defined in an array.\n if (typeof definition.args !== \"undefined\" && !Array.isArray(definition.args)) {\n throw new Error(`expected array for 'args' property if defined for action node at depth '${depth}'`);\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n}\n\n/**\n * Validate an object that we expect to be a condition node definition.\n * @param definition An object that we expect to be a condition node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateConditionNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"condition\") {\n throw new Error(`expected node type of 'condition' for condition node at depth '${depth}'`);\n }\n\n // The 'call' property must be defined for a condition node definition.\n if (typeof definition.call !== \"string\" || definition.call.length === 0) {\n throw new Error(`expected non-empty string for 'call' property of condition node at depth '${depth}'`);\n }\n\n // If any condition function arguments have been defined then they must have been defined in an array.\n if (typeof definition.args !== \"undefined\" && !Array.isArray(definition.args)) {\n throw new Error(`expected array for 'args' property if defined for condition node at depth '${depth}'`);\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n}\n\n/**\n * Validate an object that we expect to be a wait node definition.\n * @param definition An object that we expect to be a wait node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateWaitNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"wait\") {\n throw new Error(`expected node type of 'wait' for wait node at depth '${depth}'`);\n }\n\n // Check whether a 'duration' property has been defined, it may not have been if this node is to wait indefinitely.\n if (typeof definition.duration !== \"undefined\") {\n if (Array.isArray(definition.duration)) {\n // Check whether any elements of the array are not integer values.\n const containsNonInteger = !!definition.duration.filter((value: unknown) => !isInteger(value)).length;\n\n // If the 'duration' property is an array then it MUST contain two integer values.\n if (definition.duration.length !== 2 || containsNonInteger) {\n throw new Error(\n `expected array containing two integer values for 'duration' property if defined for wait node at depth '${depth}'`\n );\n }\n\n // A wait node must have a positive min and max duration value if they are defined.\n if (definition.duration[0] < 0 || definition.duration[1] < 0) {\n throw new Error(\n `expected positive minimum and maximum duration for 'duration' property if defined for wait node at depth '${depth}'`\n );\n }\n\n // A wait node must not have a minimum duration value that exceeds the maximum duration value.\n if (definition.duration[0] > definition.duration[1]) {\n throw new Error(\n `expected minimum duration value that does not exceed the maximum duration value for 'duration' property if defined for wait node at depth '${depth}'`\n );\n }\n } else if (isInteger(definition.duration)) {\n // A wait node must have a positive duration value if defined.\n if (definition.duration < 0) {\n throw new Error(\n `expected positive duration value for 'duration' property if defined for wait node at depth '${depth}'`\n );\n }\n } else {\n throw new Error(\n `expected integer value or array containing two integer values for 'duration' property if defined for wait node at depth '${depth}'`\n );\n }\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n}\n\n/**\n * Validate an object that we expect to be a sequence node definition.\n * @param definition An object that we expect to be a sequence node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateSequenceNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"sequence\") {\n throw new Error(`expected node type of 'sequence' for sequence node at depth '${depth}'`);\n }\n\n // A sequence node is a composite node, so must have a children nodes array defined.\n if (!Array.isArray(definition.children) || definition.children.length === 0) {\n throw new Error(`expected non-empty 'children' array to be defined for sequence node at depth '${depth}'`);\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n\n // Validate the child nodes of this composite node.\n definition.children.forEach((child: any) => validateNode(child, depth + 1));\n}\n\n/**\n * Validate an object that we expect to be a selector node definition.\n * @param definition An object that we expect to be a selector node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateSelectorNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"selector\") {\n throw new Error(`expected node type of 'selector' for selector node at depth '${depth}'`);\n }\n\n // A selector node is a composite node, so must have a children nodes array defined.\n if (!Array.isArray(definition.children) || definition.children.length === 0) {\n throw new Error(`expected non-empty 'children' array to be defined for selector node at depth '${depth}'`);\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n\n // Validate the child nodes of this composite node.\n definition.children.forEach((child: any) => validateNode(child, depth + 1));\n}\n\n/**\n * Validate an object that we expect to be a parallel node definition.\n * @param definition An object that we expect to be a parallel node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateParallelNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"parallel\") {\n throw new Error(`expected node type of 'parallel' for parallel node at depth '${depth}'`);\n }\n\n // A parallel node is a composite node, so must have a children nodes array defined.\n if (!Array.isArray(definition.children) || definition.children.length === 0) {\n throw new Error(`expected non-empty 'children' array to be defined for parallel node at depth '${depth}'`);\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n\n // Validate the child nodes of this composite node.\n definition.children.forEach((child: any) => validateNode(child, depth + 1));\n}\n\n/**\n * Validate an object that we expect to be a lotto node definition.\n * @param definition An object that we expect to be a lotto node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateLottoNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"lotto\") {\n throw new Error(`expected node type of 'lotto' for lotto node at depth '${depth}'`);\n }\n\n // A lotto node is a composite node, so must have a children nodes array defined.\n if (!Array.isArray(definition.children) || definition.children.length === 0) {\n throw new Error(`expected non-empty 'children' array to be defined for lotto node at depth '${depth}'`);\n }\n\n // Check whether a 'weights' property has been defined, if it has we expect it to be an array of weights.\n if (typeof definition.weights !== \"undefined\") {\n // Check that the weights property is an array of positive integers with an element for each child node element.\n if (\n !Array.isArray(definition.weights) ||\n definition.weights.length !== definition.children.length ||\n definition.weights.filter((value: unknown) => !isInteger(value)).length ||\n definition.weights.filter((value: number) => value < 0).length\n ) {\n throw new Error(\n `expected an array of positive integer weight values with a length matching the number of child nodes for 'weights' property if defined for lotto node at depth '${depth}'`\n );\n }\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n\n // Validate the child nodes of this composite node.\n definition.children.forEach((child: any) => validateNode(child, depth + 1));\n}\n\n/**\n * A helper function to create a failure validation result with the given error message.\n * @param errorMessage The validation failure error message.\n * @returns A failure validation result with the given error message.\n */\nfunction createValidationFailureResult(errorMessage: string): DefinitionValidationResult {\n return { succeeded: false, errorMessage };\n}\n", "import { ActionResult, Agent, GlobalFunction } from \"./Agent\";\nimport { RootNodeDefinition } from \"./BehaviourTreeDefinition\";\n\nexport type InvokerFunction = (args: any[]) => ActionResult;\n\n/**\n * A singleton used to store and lookup registered functions and subtrees.\n */\nexport default class Lookup {\n /**\n * The object holding any registered functions keyed on function name.\n */\n private static functionTable: { [key: string]: GlobalFunction } = {};\n /**\n * The object holding any registered subtree root node definitions keyed on tree name.\n */\n private static subtreeTable: { [key: string]: RootNodeDefinition } = {};\n\n /**\n * Gets the function with the specified name.\n * @param name The name of the function.\n * @returns The function with the specified name.\n */\n public static getFunc(name: string): GlobalFunction {\n return this.functionTable[name];\n }\n\n /**\n * Sets the function with the specified name for later lookup.\n * @param name The name of the function.\n * @param func The function.\n */\n public static setFunc(name: string, func: GlobalFunction): void {\n this.functionTable[name] = func;\n }\n\n /**\n * Gets the function invoker for the specified agent and function name.\n * If a function with the specified name exists on the agent object then it will\n * be returned, otherwise we will then check the registered functions for a match.\n * @param agent The agent instance that this behaviour tree is modelling behaviour for.\n * @param name The function name.\n * @returns The function invoker for the specified agent and function name.\n */\n static getFuncInvoker(agent: Agent, name: string): InvokerFunction | null {\n // Check whether the agent contains the specified function.\n const foundOnAgent = agent[name];\n if (foundOnAgent && typeof foundOnAgent === \"function\") {\n return (args: any[]): boolean | ActionResult => foundOnAgent.apply(agent, args);\n }\n\n // The agent does not contain the specified function but it may have been registered at some point.\n if (this.functionTable[name] && typeof this.functionTable[name] === \"function\") {\n return (args: any[]) => this.functionTable[name](agent, ...args.map((arg) => arg.value));\n }\n\n // We have no function to invoke.\n return null;\n }\n\n /**\n * Gets all registered subtree root node definitions.\n */\n static getSubtrees(): { [key: string]: RootNodeDefinition } {\n return this.subtreeTable;\n }\n\n /**\n * Sets the subtree with the specified name for later lookup.\n * @param name The name of the subtree.\n * @param subtree The subtree.\n */\n static setSubtree(name: string, subtree: RootNodeDefinition) {\n this.subtreeTable[name] = subtree;\n }\n\n /**\n * Removes the registered function or subtree with the specified name.\n * @param name The name of the registered function or subtree.\n */\n static remove(name: string) {\n delete this.functionTable[name];\n delete this.subtreeTable[name];\n }\n\n /**\n * Remove all registered functions and subtrees.\n */\n static empty() {\n this.functionTable = {};\n this.subtreeTable = {};\n }\n}\n", "import Node from \"../../nodes/Node\";\n\n/**\n * An exception thrown when evaluating node guard path conditions and a conditions fails.\n */\nexport default class GuardUnsatisifedException extends Error {\n /**\n * @param source The node at which a guard condition failed.\n */\n constructor(private source: Node) {\n super(\"A guard path condition has failed\");\n }\n\n /**\n * Gets whether the specified node is the node at which a guard condition failed.\n * @param node The node to check against the source node.\n * @returns Whether the specified node is the node at which a guard condition failed.\n */\n isSourceNode = (node: Node) => node === this.source;\n}\n", "import { Agent } from \"../../Agent\";\nimport Guard from \"./Guard\";\nimport Node from \"../../nodes/Node\";\nimport GuardUnsatisifedException from \"./GuardUnsatisifedException\";\n\nexport type GuardPathPart = {\n node: Node;\n guards: Guard[];\n};\n\n/**\n * Represents a path of node guards along a root-to-leaf tree path.\n */\nexport default class GuardPath {\n /**\n * @param nodes An array of objects defining a node instance -> guard link, ordered by node depth.\n */\n constructor(private nodes: GuardPathPart[]) {}\n\n /**\n * Evaluate guard conditions for all guards in the tree path, moving outwards from the root.\n * @param agent The agent, required for guard evaluation.\n * @returns An evaluation results object.\n */\n evaluate = (agent: Agent) => {\n // We need to evaluate guard conditions for nodes up the tree, moving outwards from the root.\n for (const details of this.nodes) {\n // There can be multiple guards per node.\n for (const guard of details.guards) {\n // Check whether the guard condition passes, and throw an exception if not.\n if (!guard.isSatisfied(agent)) {\n throw new GuardUnsatisifedException(details.node);\n }\n }\n }\n };\n}\n", "import { BehaviourTreeOptions } from \"../BehaviourTreeOptions\";\nimport State, { AnyState } from \"../State\";\nimport { Agent } from \"../Agent\";\nimport Leaf from \"./leaf/Leaf\";\nimport Attribute from \"../attributes/Attribute\";\nimport Entry from \"../attributes/callbacks/Entry\";\nimport Exit from \"../attributes/callbacks/Exit\";\nimport Step from \"../attributes/callbacks/Step\";\nimport Guard from \"../attributes/guards/Guard\";\nimport GuardPath from \"../attributes/guards/GuardPath\";\nimport GuardUnsatisifedException from \"../attributes/guards/GuardUnsatisifedException\";\n\n/**\n * A base node.\n */\nexport default abstract class Node {\n /**\n * The node uid.\n */\n private readonly uid: string = createNodeUid();\n /**\n * The node state.\n */\n private state: AnyState = State.READY;\n /**\n * The guard path to evaluate as part of a node update.\n */\n private guardPath: GuardPath | undefined;\n\n /**\n * @param type The node type.\n * @param attributes The node attributes.\n * @param args The node argument definitions.\n */\n constructor(private type: string, private attributes: Attribute[], private args: any[]) {}\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected abstract onUpdate(agent: Agent, options: BehaviourTreeOptions): void;\n\n /**\n * Gets the name of the node.\n */\n public abstract getName(): string;\n\n /**\n * Gets whether this node is a leaf node.\n */\n public abstract isLeafNode: () => this is Leaf;\n\n /**\n * Gets/Sets the state of the node.\n */\n getState = (): AnyState => this.state;\n setState = (value: AnyState): void => {\n this.state = value;\n };\n\n /**\n * Gets the unique id of the node.\n */\n getUid = () => this.uid;\n\n /**\n * Gets the type of the node.\n */\n getType = () => this.type;\n\n /**\n * Gets the node attributes.\n */\n getAttributes = () => this.attributes;\n\n /**\n * Gets the node arguments.\n */\n getArguments = () => this.args;\n\n /**\n * Gets the node attribute with the specified type, or null if it does not exist.\n */\n getAttribute(type: \"entry\" | \"ENTRY\"): Entry;\n getAttribute(type: \"exit\" | \"EXIT\"): Exit;\n getAttribute(type: \"step\" | \"STEP\"): Step;\n getAttribute(type: string): Attribute {\n return (\n this.getAttributes().filter((decorator) => decorator.type.toUpperCase() === type.toUpperCase())[0] || null\n );\n }\n\n /**\n * Gets the node attributes.\n */\n getGuardAttributes = (): Guard[] => this.getAttributes().filter((decorator) => decorator.isGuard()) as Guard[];\n\n /**\n * Sets the guard path to evaluate as part of a node update.\n */\n setGuardPath = (value: GuardPath) => (this.guardPath = value);\n\n /**\n * Gets whether a guard path is assigned to this node.\n */\n hasGuardPath = () => !!this.guardPath;\n\n /**\n * Gets whether this node is in the specified state.\n * @param value The value to compare to the node state.\n */\n public is(value: AnyState): boolean {\n return this.state === value;\n }\n\n /**\n * Reset the state of the node.\n */\n public reset(): void {\n this.setState(State.READY);\n }\n\n /**\n * Abort the running of this node.\n * @param agent The agent.\n */\n public abort(agent: Agent): void {\n // There is nothing to do if this node is not in the running state.\n if (!this.is(State.RUNNING)) {\n return;\n }\n\n // Reset the state of this node.\n this.reset();\n\n this.getAttribute(\"exit\")?.callAgentFunction(agent, false, true);\n }\n\n /**\n * Update the node.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n * @returns The result of the update.\n */\n public update(agent: Agent, options: BehaviourTreeOptions): void {\n // If this node is already in a 'SUCCEEDED' or 'FAILED' state then there is nothing to do.\n if (this.is(State.SUCCEEDED) || this.is(State.FAILED)) {\n return;\n }\n\n try {\n // Evaluate all of the guard path conditions for the current tree path.\n this.guardPath!.evaluate(agent);\n\n // If this node is in the READY state then call the ENTRY for this node if it exists.\n if (this.is(State.READY)) {\n this.getAttribute(\"entry\")?.callAgentFunction(agent);\n }\n\n this.getAttribute(\"step\")?.callAgentFunction(agent);\n\n // Do the actual update.\n this.onUpdate(agent, options);\n\n // If this node is now in a 'SUCCEEDED' or 'FAILED' state then call the EXIT for this node if it exists.\n if (this.is(State.SUCCEEDED) || this.is(State.FAILED)) {\n this.getAttribute(\"exit\")?.callAgentFunction(agent, this.is(State.SUCCEEDED), false);\n }\n } catch (error) {\n // If the error is a GuardUnsatisfiedException then we need to determine if this node is the source.\n if (error instanceof GuardUnsatisifedException && error.isSourceNode(this)) {\n // Abort the current node.\n this.abort(agent);\n\n // Any node that is the source of an abort will be a failed node.\n this.setState(State.FAILED);\n } else {\n throw error;\n }\n }\n }\n}\n\n/**\n * Create a randomly generated node uid.\n * @returns A randomly generated node uid.\n */\nfunction createNodeUid(): string {\n var S4 = function () {\n return (((1 + Math.random()) * 0x10000) | 0).toString(16).substring(1);\n };\n return S4() + S4() + \"-\" + S4() + \"-\" + S4() + \"-\" + S4() + \"-\" + S4() + S4() + S4();\n}\n", "import Node from \"../Node\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\n\n/**\n * A composite node that wraps child nodes.\n */\nexport default abstract class Composite extends Node {\n /**\n * @param type The node type.\n * @param attributes The node attributes.\n * @param children The child nodes.\n */\n constructor(type: string, attributes: Attribute[], protected children: Node[]) {\n super(type, attributes, []);\n }\n\n /**\n * Gets whether this node is a leaf node.\n */\n isLeafNode = () => false;\n\n /**\n * Gets the children of this node.\n */\n getChildren = () => this.children;\n\n /**\n * Reset the state of the node.\n */\n reset = () => {\n // Reset the state of this node.\n this.setState(State.READY);\n\n // Reset the state of any child nodes.\n this.getChildren().forEach((child) => child.reset());\n };\n\n /**\n * Abort the running of this node.\n * @param agent The agent.\n */\n abort = (agent: Agent) => {\n // There is nothing to do if this node is not in the running state.\n if (!this.is(State.RUNNING)) {\n return;\n }\n\n // Abort any child nodes.\n this.getChildren().forEach((child) => child.abort(agent));\n\n // Reset the state of this node.\n this.reset();\n\n this.getAttribute(\"exit\")?.callAgentFunction(agent, false, true);\n };\n}\n", "import Composite from \"./Composite\";\nimport State from \"../../State\";\nimport Node from \"../Node\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A PARALLEL node.\n * The child nodes are executed concurrently until one fails or all succeed.\n */\nexport default class Parallel extends Composite {\n /**\n * @param attributes The node attributes.\n * @param children The child nodes.\n */\n constructor(attributes: Attribute[], children: Node[]) {\n super(\"parallel\", attributes, children);\n }\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // Keep a count of the number of succeeded child nodes.\n let succeededCount = 0;\n\n let hasChildFailed = false;\n\n // Iterate over all of the children of this node.\n for (const child of this.children) {\n // If the child has never been updated or is running then we will need to update it now.\n if (child.getState() === State.READY || child.getState() === State.RUNNING) {\n // Update the child of this node.\n child.update(agent, options);\n }\n\n // If the current child has a state of 'SUCCEEDED' then we should move on to the next child.\n if (child.getState() === State.SUCCEEDED) {\n // The child node has succeeded, keep track of this to determine if all children have.\n succeededCount++;\n\n // The child node succeeded, but we have not finished checking every child node yet.\n continue;\n }\n\n // If the current child has a state of 'FAILED' then this node is also a 'FAILED' node.\n if (child.getState() === State.FAILED) {\n hasChildFailed = true;\n\n // There is no need to check the rest of the children.\n break;\n }\n\n // The node should be in the 'RUNNING' state.\n if (child.getState() !== State.RUNNING) {\n // The child node was not in an expected state.\n throw new Error(\"child node was not in an expected state.\");\n }\n }\n\n if (hasChildFailed) {\n // This node is a 'FAILED' node.\n this.setState(State.FAILED);\n\n // Abort every running child.\n for (const child of this.children) {\n if (child.getState() === State.RUNNING) {\n child.abort(agent);\n }\n }\n } else {\n // If all children have succeeded then this node has also succeeded, otherwise it is still running.\n this.setState(succeededCount === this.children.length ? State.SUCCEEDED : State.RUNNING);\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => \"PARALLEL\";\n}\n", "import Composite from \"./Composite\";\nimport Node from \"../Node\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A SELECTOR node.\n * The child nodes are executed in sequence until one succeeds or all fail.\n */\nexport default class Selector extends Composite {\n /**\n * @param attributes The node attributes.\n * @param children The child nodes.\n */\n constructor(attributes: Attribute[], protected children: Node[]) {\n super(\"selector\", attributes, children);\n }\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // Iterate over all of the children of this node.\n for (const child of this.children) {\n // If the child has never been updated or is running then we will need to update it now.\n if (child.getState() === State.READY || child.getState() === State.RUNNING) {\n // Update the child of this node.\n child.update(agent, options);\n }\n\n // If the current child has a state of 'SUCCEEDED' then this node is also a 'SUCCEEDED' node.\n if (child.getState() === State.SUCCEEDED) {\n // This node is a 'SUCCEEDED' node.\n this.setState(State.SUCCEEDED);\n\n // There is no need to check the rest of the selector nodes.\n return;\n }\n\n // If the current child has a state of 'FAILED' then we should move on to the next child.\n if (child.getState() === State.FAILED) {\n // Find out if the current child is the last one in the selector.\n // If it is then this sequence node has also failed.\n if (this.children.indexOf(child) === this.children.length - 1) {\n // This node is a 'FAILED' node.\n this.setState(State.FAILED);\n\n // There is no need to check the rest of the selector as we have completed it.\n return;\n } else {\n // The child node failed, try the next one.\n continue;\n }\n }\n\n // The node should be in the 'RUNNING' state.\n if (child.getState() === State.RUNNING) {\n // This node is a 'RUNNING' node.\n this.setState(State.RUNNING);\n\n // There is no need to check the rest of the selector as the current child is still running.\n return;\n }\n\n // The child node was not in an expected state.\n throw new Error(\"child node was not in an expected state.\");\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => \"SELECTOR\";\n}\n", "import Composite from \"./Composite\";\nimport Node from \"../Node\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A SEQUENCE node.\n * The child nodes are executed in sequence until one fails or all succeed.\n */\nexport default class Sequence extends Composite {\n /**\n * @param attributes The node attributes.\n * @param children The child nodes.\n */\n constructor(attributes: Attribute[], protected children: Node[]) {\n super(\"sequence\", attributes, children);\n }\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // Iterate over all of the children of this node.\n for (const child of this.children) {\n // If the child has never been updated or is running then we will need to update it now.\n if (child.getState() === State.READY || child.getState() === State.RUNNING) {\n // Update the child of this node.\n child.update(agent, options);\n }\n\n // If the current child has a state of 'SUCCEEDED' then we should move on to the next child.\n if (child.getState() === State.SUCCEEDED) {\n // Find out if the current child is the last one in the sequence.\n // If it is then this sequence node has also succeeded.\n if (this.children.indexOf(child) === this.children.length - 1) {\n // This node is a 'SUCCEEDED' node.\n this.setState(State.SUCCEEDED);\n\n // There is no need to check the rest of the sequence as we have completed it.\n return;\n } else {\n // The child node succeeded, but we have not finished the sequence yet.\n continue;\n }\n }\n\n // If the current child has a state of 'FAILED' then this node is also a 'FAILED' node.\n if (child.getState() === State.FAILED) {\n // This node is a 'FAILED' node.\n this.setState(State.FAILED);\n\n // There is no need to check the rest of the sequence.\n return;\n }\n\n // The node should be in the 'RUNNING' state.\n if (child.getState() === State.RUNNING) {\n // This node is a 'RUNNING' node.\n this.setState(State.RUNNING);\n\n // There is no need to check the rest of the sequence as the current child is still running.\n return;\n }\n\n // The child node was not in an expected state.\n throw new Error(\"child node was not in an expected state.\");\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => \"SEQUENCE\";\n}\n", "import createLotto from \"lotto-draw\";\n\nimport Node from \"../Node\";\nimport Composite from \"./Composite\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A LOTTO node.\n * A winning child is picked on the initial update of this node, based on ticket weighting.\n * The state of this node will match the state of the winning child.\n */\nexport default class Lotto extends Composite {\n /**\n * @param attributes The node attributes.\n * @param weights The child node weights.\n * @param children The child nodes.\n */\n constructor(attributes: Attribute[], private weights: number[] | undefined, children: Node[]) {\n super(\"lotto\", attributes, children);\n }\n\n /**\n * The child node selected to be the active one.\n */\n private selectedChild: Node | undefined;\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // If this node is in the READY state then we need to pick a winning child node.\n if (this.is(State.READY)) {\n // Create a lotto draw with which to randomly pick a child node to become the active one.\n const lottoDraw = createLotto({\n // Hook up the optional 'random' behaviour tree function option to the one used by 'lotto-draw'.\n random: options.random,\n // Pass in each child node as a participant in the lotto draw with their respective ticket count.\n participants: this.children.map((child, index) => [child, this.weights?.[index] || 1])\n });\n\n // Randomly pick a child based on ticket weighting, this will become the active child for this composite node.\n this.selectedChild = lottoDraw.draw() || undefined;\n }\n\n // If something went wrong and we don't have an active child then we should throw an error.\n if (!this.selectedChild) {\n throw new Error(\"failed to update lotto node as it has no active child\");\n }\n\n // If the selected child has never been updated or is running then we will need to update it now.\n if (this.selectedChild.getState() === State.READY || this.selectedChild.getState() === State.RUNNING) {\n this.selectedChild.update(agent, options);\n }\n\n // The state of the lotto node is the state of its selected child.\n this.setState(this.selectedChild.getState());\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => (this.weights ? `LOTTO [${this.weights.join(\",\")}]` : \"LOTTO\");\n}\n", "import Node from \"../Node\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\n\n/**\n * A decorator node that wraps a single child node.\n */\nexport default abstract class Decorator extends Node {\n /**\n * @param type The node type.\n * @param attributes The node attributes.\n * @param child The child node.\n */\n constructor(type: string, attributes: Attribute[], protected child: Node) {\n super(type, attributes, []);\n }\n\n /**\n * Gets whether this node is a leaf node.\n */\n isLeafNode = () => false;\n\n /**\n * Gets the children of this node.\n */\n getChildren = () => [this.child];\n\n /**\n * Reset the state of the node.\n */\n reset = () => {\n // Reset the state of this node.\n this.setState(State.READY);\n\n // Reset the state of the child node.\n this.child.reset();\n };\n\n /**\n * Abort the running of this node.\n * @param agent The agent.\n */\n abort = (agent: Agent) => {\n // There is nothing to do if this node is not in the running state.\n if (!this.is(State.RUNNING)) {\n return;\n }\n\n // Abort the child node.\n this.child.abort(agent);\n\n // Reset the state of this node.\n this.reset();\n\n this.getAttribute(\"exit\")?.callAgentFunction(agent, false, true);\n };\n}\n", "import Node from \"../Node\";\nimport Decorator from \"./Decorator\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A Fail node.\n * This node wraps a single child and will always move to the 'FAILED' state when the child moves to a 'SUCCEEDED' or 'FAILED' state.\n */\nexport default class Fail extends Decorator {\n /**\n * @param attributes The node attributes.\n * @param child The child node.\n */\n constructor(attributes: Attribute[], child: Node) {\n super(\"fail\", attributes, child);\n }\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // If the child has never been updated or is running then we will need to update it now.\n if (this.child.getState() === State.READY || this.child.getState() === State.RUNNING) {\n this.child.update(agent, options);\n }\n\n // The state of this node will depend in the state of its child.\n switch (this.child.getState()) {\n case State.RUNNING:\n this.setState(State.RUNNING);\n break;\n\n case State.SUCCEEDED:\n case State.FAILED:\n this.setState(State.FAILED);\n break;\n\n default:\n this.setState(State.READY);\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => \"FAIL\";\n}\n", "import Decorator from \"./Decorator\";\nimport State from \"../../State\";\nimport Node from \"../Node\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A Flip node.\n * This node wraps a single child and will flip the state of the child state.\n */\nexport default class Flip extends Decorator {\n /**\n * @param attributes The node attributes.\n * @param child The child node.\n */\n constructor(attributes: Attribute[], child: Node) {\n super(\"flip\", attributes, child);\n }\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // If the child has never been updated or is running then we will need to update it now.\n if (this.child.getState() === State.READY || this.child.getState() === State.RUNNING) {\n this.child.update(agent, options);\n }\n\n // The state of this node will depend in the state of its child.\n switch (this.child.getState()) {\n case State.RUNNING:\n this.setState(State.RUNNING);\n break;\n\n case State.SUCCEEDED:\n this.setState(State.FAILED);\n break;\n\n case State.FAILED:\n this.setState(State.SUCCEEDED);\n break;\n\n default:\n this.setState(State.READY);\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => \"FLIP\";\n}\n", "import Node from \"../Node\";\nimport Decorator from \"./Decorator\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A REPEAT node.\n * The node has a single child which can have:\n * -- A number of iterations for which to repeat the child node.\n * -- An infinite repeat loop if neither an iteration count or a condition function is defined.\n * The REPEAT node will stop and have a 'FAILED' state if its child is ever in a 'FAILED' state after an update.\n * The REPEAT node will attempt to move on to the next iteration if its child is ever in a 'SUCCEEDED' state.\n */\nexport default class Repeat extends Decorator {\n /**\n * @param attributes The node attributes.\n * @param iterations The number of iterations to repeat the child node.\n * @param iterationsMin The minimum possible number of iterations to repeat the child node.\n * @param iterationsMax The maximum possible number of iterations to repeat the child node.\n * @param child The child node.\n */\n constructor(\n attributes: Attribute[],\n private iterations: number | null,\n private iterationsMin: number | null,\n private iterationsMax: number | null,\n child: Node\n ) {\n super(\"repeat\", attributes, child);\n }\n\n /**\n * The number of target iterations to make.\n */\n private targetIterationCount: number | null = null;\n\n /**\n * The current iteration count.\n */\n private currentIterationCount: number = 0;\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // If this node is in the READY state then we need to reset the child and the target iteration count.\n if (this.is(State.READY)) {\n // Reset the child node.\n this.child.reset();\n\n // Reset the current iteration count.\n this.currentIterationCount = 0;\n\n // Set the target iteration count.\n this.setTargetIterationCount(options);\n }\n\n // Do a check to see if we can iterate. If we can then this node will move into the 'RUNNING' state.\n // If we cannot iterate then we have hit our target iteration count, which means that the node has succeeded.\n if (this.canIterate()) {\n // This node is in the running state and can do its initial iteration.\n this.setState(State.RUNNING);\n\n // We may have already completed an iteration, meaning that the child node will be in the SUCCEEDED state.\n // If this is the case then we will have to reset the child node now.\n if (this.child.getState() === State.SUCCEEDED) {\n this.child.reset();\n }\n\n // Update the child of this node.\n this.child.update(agent, options);\n\n // If the child moved into the FAILED state when we updated it then there is nothing left to do and this node has also failed.\n // If it has moved into the SUCCEEDED state then we have completed the current iteration.\n if (this.child.getState() === State.FAILED) {\n // The child has failed, meaning that this node has failed.\n this.setState(State.FAILED);\n\n return;\n } else if (this.child.getState() === State.SUCCEEDED) {\n // We have completed an iteration.\n this.currentIterationCount += 1;\n }\n } else {\n // This node is in the 'SUCCEEDED' state as we cannot iterate any more.\n this.setState(State.SUCCEEDED);\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => {\n if (this.iterations !== null) {\n return `REPEAT ${this.iterations}x`;\n } else if (this.iterationsMin !== null && this.iterationsMax !== null) {\n return `REPEAT ${this.iterationsMin}x-${this.iterationsMax}x`;\n } else {\n return \"REPEAT\";\n }\n };\n\n /**\n * Reset the state of the node.\n */\n reset = () => {\n // Reset the state of this node.\n this.setState(State.READY);\n\n // Reset the current iteration count.\n this.currentIterationCount = 0;\n\n // Reset the child node.\n this.child.reset();\n };\n\n /**\n * Gets whether an iteration can be made.\n * @returns Whether an iteration can be made.\n */\n private canIterate = () => {\n if (this.targetIterationCount !== null) {\n // We can iterate as long as we have not reached our target iteration count.\n return this.currentIterationCount < this.targetIterationCount;\n }\n\n // If neither an iteration count or a condition function were defined then we can iterate indefinitely.\n return true;\n };\n\n /**\n * Sets the target iteration count.\n * @param options The behaviour tree options object.\n */\n private setTargetIterationCount = (options: BehaviourTreeOptions) => {\n // Are we dealing with an explicit iteration count or will we be randomly picking a iteration count between the min and max iteration count.\n if (this.iterations !== null) {\n this.targetIterationCount = this.iterations;\n } else if (this.iterationsMin !== null && this.iterationsMax !== null) {\n // We will be picking a random iteration count between a min and max iteration count, if the optional 'random'\n // behaviour tree function option is defined then we will be using that, otherwise we will fall back to using Math.random.\n const random = typeof options.random === \"function\" ? options.random : Math.random;\n\n // Pick a random iteration count between a min and max iteration count.\n this.targetIterationCount = Math.floor(\n random() * (this.iterationsMax - this.iterationsMin + 1) + this.iterationsMin\n );\n } else {\n this.targetIterationCount = null;\n }\n };\n}\n", "import Node from \"../Node\";\nimport Decorator from \"./Decorator\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A RETRY node.\n * The node has a single child which can have:\n * -- A number of iterations for which to repeat the child node.\n * -- An infinite repeat loop if neither an iteration count or a condition function is defined.\n * The RETRY node will stop and have a 'SUCCEEDED' state if its child is ever in a 'SUCCEEDED' state after an update.\n * The RETRY node will attempt to move on to the next iteration if its child is ever in a 'FAILED' state.\n */\nexport default class Retry extends Decorator {\n /**\n * @param attributes The node attributes.\n * @param attempts The number of attempts to retry the child node.\n * @param attemptsMin The minimum possible number of attempts to retry the child node.\n * @param attemptsMax The maximum possible number of attempts to retry the child node.\n * @param child The child node.\n */\n constructor(\n attributes: Attribute[],\n private attempts: number | null,\n private attemptsMin: number | null,\n private attemptsMax: number | null,\n child: Node\n ) {\n super(\"retry\", attributes, child);\n }\n\n /**\n * The number of target attempts to make.\n */\n private targetAttemptCount: number | null = null;\n\n /**\n * The current attempt count.\n */\n private currentAttemptCount: number = 0;\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // If this node is in the READY state then we need to reset the child and the target attempt count.\n if (this.is(State.READY)) {\n // Reset the child node.\n this.child.reset();\n\n // Reset the current attempt count.\n this.currentAttemptCount = 0;\n\n // Set the target attempt count.\n this.setTargetAttemptCount(options);\n }\n\n // Do a check to see if we can attempt. If we can then this node will move into the 'RUNNING' state.\n // If we cannot attempt then we have hit our target attempt count, which means that the node has succeeded.\n if (this.canAttempt()) {\n // This node is in the running state and can do its initial attempt.\n this.setState(State.RUNNING);\n\n // We may have already completed an attempt, meaning that the child node will be in the FAILED state.\n // If this is the case then we will have to reset the child node now.\n if (this.child.getState() === State.FAILED) {\n this.child.reset();\n }\n\n // Update the child of this node.\n this.child.update(agent, options);\n\n // If the child moved into the SUCCEEDED state when we updated it then there is nothing left to do and this node has also succeeded.\n // If it has moved into the FAILED state then we have completed the current attempt.\n if (this.child.getState() === State.SUCCEEDED) {\n // The child has succeeded, meaning that this node has succeeded.\n this.setState(State.SUCCEEDED);\n\n return;\n } else if (this.child.getState() === State.FAILED) {\n // We have completed an attempt.\n this.currentAttemptCount += 1;\n }\n } else {\n // This node is in the 'FAILED' state as we cannot iterate any more.\n this.setState(State.FAILED);\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => {\n if (this.attempts !== null) {\n return `RETRY ${this.attempts}x`;\n } else if (this.attemptsMin !== null && this.attemptsMax !== null) {\n return `RETRY ${this.attemptsMin}x-${this.attemptsMax}x`;\n } else {\n return \"RETRY\";\n }\n };\n\n /**\n * Reset the state of the node.\n */\n reset = () => {\n // Reset the state of this node.\n this.setState(State.READY);\n\n // Reset the current attempt count.\n this.currentAttemptCount = 0;\n\n // Reset the child node.\n this.child.reset();\n };\n\n /**\n * Gets whether an attempt can be made.\n * @returns Whether an attempt can be made.\n */\n canAttempt = () => {\n if (this.targetAttemptCount !== null) {\n // We can attempt as long as we have not reached our target attempt count.\n return this.currentAttemptCount < this.targetAttemptCount;\n }\n\n // If neither an attempt count or a condition function were defined then we can attempt indefinitely.\n return true;\n };\n\n /**\n * Sets the target attempt count.\n * @param options The behaviour tree options object.\n */\n setTargetAttemptCount = (options: BehaviourTreeOptions) => {\n // Are we dealing with an explicit attempt count or will we be randomly picking an attempt count between the min and max attempt count.\n if (this.attempts !== null) {\n this.targetAttemptCount = this.attempts;\n } else if (this.attemptsMin !== null && this.attemptsMax !== null) {\n // We will be picking a random attempt count between a min and max attempt count, if the optional 'random'\n // behaviour tree function option is defined then we will be using that, otherwise we will fall back to using Math.random.\n const random = typeof options.random === \"function\" ? options.random : Math.random;\n\n // Pick a random attempt count between a min and max attempt count.\n this.targetAttemptCount = Math.floor(\n random() * (this.attemptsMax - this.attemptsMin + 1) + this.attemptsMin\n );\n } else {\n this.targetAttemptCount = null;\n }\n };\n}\n", "import Node from \"../Node\";\nimport Decorator from \"./Decorator\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A Root node.\n * The root node will have a single child.\n */\nexport default class Root extends Decorator {\n /**\n * @param attributes The node attributes.\n * @param child The child node.\n */\n constructor(attributes: Attribute[], child: Node) {\n super(\"root\", attributes, child);\n }\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // If the child has never been updated or is running then we will need to update it now.\n if (this.child.getState() === State.READY || this.child.getState() === State.RUNNING) {\n // Update the child of this node.\n this.child.update(agent, options);\n }\n\n // The state of the root node is the state of its child.\n this.setState(this.child.getState());\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => \"ROOT\";\n}\n", "import Node from \"../Node\";\nimport Decorator from \"./Decorator\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A Succeed node.\n * This node wraps a single child and will always move to the 'SUCCEEDED' state when the child moves to a 'SUCCEEDED' or 'FAILED' state.\n */\nexport default class Succeed extends Decorator {\n /**\n * @param attributes The node attributes.\n * @param child The child node.\n */\n constructor(attributes: Attribute[], child: Node) {\n super(\"succeed\", attributes, child);\n }\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // If the child has never been updated or is running then we will need to update it now.\n if (this.child.getState() === State.READY || this.child.getState() === State.RUNNING) {\n this.child.update(agent, options);\n }\n\n // The state of this node will depend in the state of its child.\n switch (this.child.getState()) {\n case State.RUNNING:\n this.setState(State.RUNNING);\n break;\n\n case State.SUCCEEDED:\n case State.FAILED:\n this.setState(State.SUCCEEDED);\n break;\n\n default:\n this.setState(State.READY);\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => \"SUCCEED\";\n}\n", "import Node from \"../Node\";\n\n/**\n * A leaf node.\n */\nexport default abstract class Leaf extends Node {\n /**\n * Gets whether this node is a leaf node.\n */\n isLeafNode = () => true;\n}\n", "import { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\nimport State, { CompleteState } from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Leaf from \"./Leaf\";\nimport Lookup from \"../../Lookup\";\nimport Attribute from \"../../attributes/Attribute\";\n\n/**\n * The type representing a resolved/rejected update promise.\n */\ntype UpdatePromiseResult = {\n /**\n * Whether the promise was resolved rather than rejected.\n */\n isResolved: boolean;\n\n /**\n * The promise resolved value or rejection reason.\n */\n value: any;\n};\n\n/**\n * An Action leaf node.\n * This represents an immediate or ongoing state of behaviour.\n */\nexport default class Action extends Leaf {\n /**\n * @param attributes The node attributes.\n * @param actionName The action name.\n * @param actionArguments The array of action argument definitions.\n */\n constructor(attributes: Attribute[], private actionName: string, private actionArguments: any[]) {\n super(\"action\", attributes, actionArguments);\n }\n\n /**\n * Whether there is a pending update promise.\n */\n private isUsingUpdatePromise = false;\n\n /**\n * The finished state result of an update promise.\n */\n private updatePromiseResult: UpdatePromiseResult | null = null;\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // If the result of this action depends on an update promise then there is nothing to do until it settles.\n if (this.isUsingUpdatePromise) {\n // Are we still waiting for our update promise to settle?\n if (!this.updatePromiseResult) {\n return;\n }\n\n const { isResolved, value } = this.updatePromiseResult;\n\n // Our update promise settled, was it resolved or rejected?\n if (isResolved) {\n // Our promise resolved so check to make sure the result is a valid finished state.\n if (value !== State.SUCCEEDED && value !== State.FAILED) {\n throw new Error(\n \"action node promise resolved with an invalid value, expected a State.SUCCEEDED or State.FAILED value to be returned\"\n );\n }\n\n // Set the state of this node to match the state returned by the promise.\n this.setState(value);\n\n return;\n } else {\n // The promise was rejected, which isn't great.\n throw new Error(`action function '${this.actionName}' promise rejected with '${value}'`);\n }\n }\n\n // Attempt to get the invoker for the action function.\n const actionFuncInvoker = Lookup.getFuncInvoker(agent, this.actionName);\n\n // The action function should be defined.\n if (actionFuncInvoker === null) {\n throw new Error(\n `cannot update action node as the action '${this.actionName}' function is not defined on the agent and has not been registered`\n );\n }\n\n let actionFunctionResult;\n\n try {\n // Call the action function, the result of which may be:\n // - The finished state of this action node.\n // - A promise to return a finished node state.\n // - Undefined if the node should remain in the running state.\n actionFunctionResult = actionFuncInvoker(this.actionArguments) as CompleteState | Promise;\n } catch (error) {\n // The user was naughty and threw something.\n throw new Error(`action function '${this.actionName}' threw '${error}'`);\n }\n\n if (actionFunctionResult instanceof Promise) {\n actionFunctionResult.then(\n (result) => {\n // If 'isUpdatePromisePending' is not set then the promise was cleared as it was resolving, probably via an abort of reset.\n if (!this.isUsingUpdatePromise) {\n return;\n }\n\n // Set the resolved update promise result so that it can be handled on the next update of this node.\n this.updatePromiseResult = {\n isResolved: true,\n value: result\n };\n },\n (reason) => {\n // If 'isUpdatePromisePending' is not set then the promise was cleared as it was resolving, probably via an abort or reset.\n if (!this.isUsingUpdatePromise) {\n return;\n }\n\n // Set the rejected update promise result so that it can be handled on the next update of this node.\n this.updatePromiseResult = {\n isResolved: false,\n value: reason\n };\n }\n );\n\n // This node will be in the 'RUNNING' state until the update promise resolves.\n this.setState(State.RUNNING);\n\n // We are now waiting for the promise returned by the use to resolve before we know what state this node is in.\n this.isUsingUpdatePromise = true;\n } else {\n // Validate the returned value.\n this.validateUpdateResult(actionFunctionResult);\n\n // Set the state of this node, this may be undefined, which just means that the node is still in the 'RUNNING' state.\n this.setState(actionFunctionResult || State.RUNNING);\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => this.actionName;\n\n /**\n * Reset the state of the node.\n */\n reset = () => {\n // Reset the state of this node.\n this.setState(State.READY);\n\n // There is no longer an update promise that we care about.\n this.isUsingUpdatePromise = false;\n this.updatePromiseResult = null;\n };\n\n /**\n * Validate the result of an update function call.\n * @param result The result of an update function call.\n */\n private validateUpdateResult = (result: CompleteState | boolean) => {\n switch (result) {\n case State.SUCCEEDED:\n case State.FAILED:\n case undefined:\n return;\n default:\n throw new Error(\n `action '${this.actionName}' 'onUpdate' returned an invalid response, expected an optional State.SUCCEEDED or State.FAILED value to be returned`\n );\n }\n };\n}\n", "import { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Leaf from \"./Leaf\";\nimport Lookup from \"../../Lookup\";\nimport Attribute from \"../../attributes/Attribute\";\n\n/**\n * A Condition leaf node.\n * This will succeed or fail immediately based on an agent predicate, without moving to the 'RUNNING' state.\n */\nexport default class Condition extends Leaf {\n /**\n * @param attributes The node attributes.\n * @param conditionName The name of the condition function.\n * @param conditionArguments The array of condition argument definitions.\n */\n constructor(attributes: Attribute[], private conditionName: string, private conditionArguments: any[]) {\n super(\"condition\", attributes, conditionArguments);\n }\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // Attempt to get the invoker for the condition function.\n const conditionFuncInvoker = Lookup.getFuncInvoker(agent, this.conditionName);\n\n // The condition function should be defined.\n if (conditionFuncInvoker === null) {\n throw new Error(\n `cannot update condition node as the condition '${this.conditionName}' function is not defined on the agent and has not been registered`\n );\n }\n\n let conditionFunctionResult;\n\n try {\n // Call the condition function to determine the state of this node, the result of which should be a boolean.\n conditionFunctionResult = conditionFuncInvoker(this.conditionArguments);\n } catch (error) {\n // The user was naughty and threw something.\n throw new Error(`condition function '${this.conditionName}' threw '${error}'`);\n }\n\n // The result of calling the condition function must be a boolean value.\n if (typeof conditionFunctionResult !== \"boolean\") {\n throw new Error(\n `expected condition function '${this.conditionName}' to return a boolean but returned '${conditionFunctionResult}'`\n );\n }\n\n // Set the state of this node based on the result of calling the condition function.\n this.setState(!!conditionFunctionResult ? State.SUCCEEDED : State.FAILED);\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => this.conditionName;\n}\n", "import Leaf from \"./Leaf\";\nimport State from \"../../State\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { Agent } from \"../../Agent\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A WAIT node.\n * The state of this node will change to SUCCEEDED after a duration of time\n */\nexport default class Wait extends Leaf {\n /**\n * @param attributes The node attributes.\n * @param duration The duration that this node will wait to succeed in milliseconds.\n * @param durationMin The minimum possible duration in milliseconds that this node will wait to succeed.\n * @param durationMax The maximum possible duration in milliseconds that this node will wait to succeed.\n */\n constructor(\n attributes: Attribute[],\n private duration: number | null,\n private durationMin: number | null,\n private durationMax: number | null\n ) {\n super(\"wait\", attributes, []);\n }\n\n /**\n * The time in milliseconds at which this node was first updated.\n */\n private initialUpdateTime: number = 0;\n\n /**\n * The total duration in milliseconds that this node will be waiting for.\n */\n private totalDuration: number | null = null;\n\n /**\n * The duration in milliseconds that this node has been waiting for.\n */\n private waitedDuration: number = 0;\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // If this node is in the READY state then we need to set the initial update time.\n if (this.is(State.READY)) {\n // Set the initial update time.\n this.initialUpdateTime = new Date().getTime();\n\n // Set the initial waited duration.\n this.waitedDuration = 0;\n\n // Are we dealing with an explicit duration or will we be randomly picking a duration between the min and max duration.\n if (this.duration !== null) {\n this.totalDuration = this.duration;\n } else if (this.durationMin !== null && this.durationMax !== null) {\n // We will be picking a random duration between a min and max duration, if the optional 'random' behaviour tree\n // function option is defined then we will be using that, otherwise we will fall back to using Math.random.\n const random = typeof options.random === \"function\" ? options.random : Math.random;\n\n // Pick a random duration between a min and max duration.\n this.totalDuration = Math.floor(\n random() * (this.durationMax - this.durationMin + 1) + this.durationMin\n );\n } else {\n this.totalDuration = null;\n }\n\n // The node is now running until we finish waiting.\n this.setState(State.RUNNING);\n }\n\n // If we have no total duration then this wait node will wait indefinitely until it is aborted.\n if (this.totalDuration === null) {\n return;\n }\n\n // If we have a 'getDeltaTime' function defined as part of our options then we will use it to figure out how long we have waited for.\n if (typeof options.getDeltaTime === \"function\") {\n // Get the delta time.\n const deltaTime = options.getDeltaTime();\n\n // Our delta time must be a valid number and cannot be NaN.\n if (typeof deltaTime !== \"number\" || isNaN(deltaTime)) {\n throw new Error(\"The delta time must be a valid number and not NaN.\");\n }\n\n // Update the amount of time that this node has been waiting for based on the delta time.\n this.waitedDuration += deltaTime * 1000;\n } else {\n // We are not using a delta time, so we will just work out hom much time has passed since the first update.\n this.waitedDuration = new Date().getTime() - this.initialUpdateTime;\n }\n\n // Have we waited long enough?\n if (this.waitedDuration >= this.totalDuration) {\n // We have finished waiting!\n this.setState(State.SUCCEEDED);\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => {\n if (this.duration !== null) {\n return `WAIT ${this.duration}ms`;\n } else if (this.durationMin !== null && this.durationMax !== null) {\n return `WAIT ${this.durationMin}ms-${this.durationMax}ms`;\n } else {\n return \"WAIT\";\n }\n };\n}\n", "import Guard from \"./guards/Guard\";\n\nexport type AttributeDetails = {\n /** The attribute type. */\n type: string;\n\n /** The attribute arguments. */\n args: any[];\n};\n\n/**\n * A base node attribute.\n */\nexport default abstract class Attribute {\n /**\n * @param type The node attribute type.\n * @param args The array of attribute arguments.\n */\n constructor(public type: string, public args: any[]) {}\n\n /**\n * Gets the attribute details.\n */\n abstract getDetails(): TAttributeDetails;\n\n /**\n * Gets whether this attribute is a guard.\n */\n abstract isGuard: () => this is Guard;\n}\n", "import { Agent } from \"../../Agent\";\nimport Attribute, { AttributeDetails } from \"../Attribute\";\n\nexport type GuardAttributeDetails = {\n /** The name of the condition function that determines whether the guard is satisfied. */\n condition: string;\n} & AttributeDetails;\n\n/**\n * A base node guard attribute.\n */\nexport default abstract class Guard extends Attribute {\n /**\n * @param type The node attribute type.\n * @param args The array of decorator argument definitions.\n * @param condition The name of the condition function that determines whether the guard is satisfied.\n */\n constructor(type: string, args: any[], private condition: string) {\n super(type, args);\n }\n\n /**\n * Gets the name of the condition function that determines whether the guard is satisfied.\n */\n getCondition = () => this.condition;\n\n /**\n * Gets whether this attribute is a guard.\n */\n isGuard = () => true;\n\n /**\n * Gets the attribute details.\n */\n getDetails(): GuardAttributeDetails {\n return {\n type: this.type,\n args: this.args,\n condition: this.getCondition()\n };\n }\n\n /**\n * Gets whether the guard is satisfied.\n * @param agent The agent.\n * @returns Whether the guard is satisfied.\n */\n abstract isSatisfied(agent: Agent): boolean;\n}\n", "import Guard from \"./Guard\";\nimport Lookup from \"../../Lookup\";\nimport { Agent } from \"../../Agent\";\n\n/**\n * A WHILE guard which is satisfied as long as the given condition remains true.\n */\nexport default class While extends Guard {\n /**\n * @param condition The name of the condition function that determines whether the guard is satisfied.\n * @param args The array of decorator argument definitions.\n */\n constructor(condition: string, args: any[]) {\n super(\"while\", args, condition);\n }\n\n /**\n * Gets whether the guard is satisfied.\n * @param agent The agent.\n * @returns Whether the guard is satisfied.\n */\n isSatisfied = (agent: Agent) => {\n // Attempt to get the invoker for the condition function.\n const conditionFuncInvoker = Lookup.getFuncInvoker(agent, this.getCondition());\n\n // The condition function should be defined.\n if (conditionFuncInvoker === null) {\n throw new Error(\n `cannot evaluate node guard as the condition '${this.getCondition()}' function is not defined on the agent and has not been registered`\n );\n }\n\n // Call the condition function to determine whether this guard is satisfied.\n return !!conditionFuncInvoker(this.args);\n };\n}\n", "import Guard from \"./Guard\";\nimport Lookup from \"../../Lookup\";\nimport { Agent } from \"../../Agent\";\n\n/**\n * An UNTIL guard which is satisfied as long as the given condition remains false.\n */\nexport default class Until extends Guard {\n /**\n * @param condition The name of the condition function that determines whether the guard is satisfied.\n * @param args The array of decorator argument definitions.\n */\n constructor(condition: string, args: any[]) {\n super(\"until\", args, condition);\n }\n\n /**\n * Gets whether the guard is satisfied.\n * @param agent The agent.\n * @returns Whether the guard is satisfied.\n */\n isSatisfied = (agent: Agent) => {\n // Attempt to get the invoker for the condition function.\n const conditionFuncInvoker = Lookup.getFuncInvoker(agent, this.getCondition());\n\n // The condition function should be defined.\n if (conditionFuncInvoker === null) {\n throw new Error(\n `cannot evaluate node guard as the condition '${this.getCondition()}' function is not defined on the agent and has not been registered`\n );\n }\n\n // Call the condition function to determine whether this guard is satisfied.\n return !!!conditionFuncInvoker(this.args);\n };\n}\n", "import { Agent } from \"../../Agent\";\nimport Attribute, { AttributeDetails } from \"../Attribute\";\n\nexport type CallbackAttributeDetails = {\n /** The name of the agent function that is called. */\n functionName: string;\n} & AttributeDetails;\n\n/**\n * A base node callback attribute.\n */\nexport default abstract class Callback extends Attribute {\n /**\n * @param type The node attribute type.\n * @param args The array of decorator argument definitions.\n * @param functionName The name of the agent function to call.\n */\n constructor(type: string, args: any[], private functionName: string) {\n super(type, args);\n }\n\n /**\n * Gets the name of the agent function to call.\n */\n getFunctionName = () => this.functionName;\n\n /**\n * Gets whether this attribute is a guard.\n */\n isGuard = () => false;\n\n /**\n * Gets the attribute details.\n */\n getDetails(): CallbackAttributeDetails {\n return {\n type: this.type,\n args: this.args,\n functionName: this.getFunctionName()\n };\n }\n\n /**\n * Attempt to call the agent function that this callback refers to.\n * @param agent The agent.\n */\n abstract callAgentFunction: (agent: Agent, isSuccess: boolean, isAborted: boolean) => void;\n}\n", "import Callback from \"./Callback\";\nimport Lookup from \"../../Lookup\";\nimport { Agent } from \"../../Agent\";\n\n/**\n * An ENTRY callback which defines an agent function to call when the associated node is updated and moves out of running state.\n */\nexport default class Entry extends Callback {\n /**\n * @param functionName The name of the agent function to call.\n * @param args The array of callback argument definitions.\n */\n constructor(functionName: string, args: any[]) {\n super(\"entry\", args, functionName);\n }\n\n /**\n * Attempt to call the agent function that this callback refers to.\n * @param agent The agent.\n */\n callAgentFunction = (agent: Agent) => {\n // Attempt to get the invoker for the callback function.\n const callbackFuncInvoker = Lookup.getFuncInvoker(agent, this.getFunctionName());\n\n // The callback function should be defined.\n if (callbackFuncInvoker === null) {\n throw new Error(\n `cannot call entry function '${this.getFunctionName()}' as is not defined on the agent and has not been registered`\n );\n }\n\n // Call the callback function.\n callbackFuncInvoker(this.args);\n };\n}\n", "import Callback from \"./Callback\";\nimport Lookup from \"../../Lookup\";\nimport { Agent } from \"../../Agent\";\n\n/**\n * A STEP callback which defines an agent function to call when the associated node is updated.\n */\nexport default class Step extends Callback {\n /**\n * @param functionName The name of the agent function to call.\n * @param args The array of callback argument definitions.\n */\n constructor(functionName: string, args: any[]) {\n super(\"step\", args, functionName);\n }\n\n /**\n * Attempt to call the agent function that this callback refers to.\n * @param agent The agent.\n */\n callAgentFunction = (agent: Agent) => {\n // Attempt to get the invoker for the callback function.\n const callbackFuncInvoker = Lookup.getFuncInvoker(agent, this.getFunctionName());\n\n // The callback function should be defined.\n if (callbackFuncInvoker === null) {\n throw new Error(\n `cannot call step function '${this.getFunctionName()}' as is not defined on the agent and has not been registered`\n );\n }\n\n // Call the callback function.\n callbackFuncInvoker(this.args);\n };\n}\n", "import Callback from \"./Callback\";\nimport Lookup from \"../../Lookup\";\nimport { Agent } from \"../../Agent\";\n\n/**\n * An EXIT callback which defines an agent function to call when the associated node is updated and moves to a finished state or is aborted.\n */\nexport default class Exit extends Callback {\n /**\n * @param functionName The name of the agent function to call.\n * @param args The array of callback argument definitions.\n */\n constructor(functionName: string, args: any[]) {\n super(\"exit\", args, functionName);\n }\n\n /**\n * Attempt to call the agent function that this callback refers to.\n * @param agent The agent.\n * @param isSuccess Whether the decorated node was left with a success state.\n * @param isAborted Whether the decorated node was aborted.\n */\n callAgentFunction = (agent: Agent, isSuccess: boolean, isAborted: boolean) => {\n // Attempt to get the invoker for the callback function.\n const callbackFuncInvoker = Lookup.getFuncInvoker(agent, this.getFunctionName());\n\n // The callback function should be defined.\n if (callbackFuncInvoker === null) {\n throw new Error(\n `cannot call exit function '${this.getFunctionName()}' as is not defined on the agent and has not been registered`\n );\n }\n\n // Call the callback function\n callbackFuncInvoker([{ value: { succeeded: isSuccess, aborted: isAborted } }, ...this.args]);\n };\n}\n", "import { AnyNodeDefinition, RootNodeDefinition } from \"./BehaviourTreeDefinition\";\nimport GuardPath, { GuardPathPart } from \"./attributes/guards/GuardPath\";\nimport { validateBranchSubtreeLinks } from \"./BehaviourTreeDefinitionValidator\";\nimport { isInteger } from \"./BehaviourTreeDefinitionUtilities\";\nimport Node from \"./nodes/Node\";\nimport Composite from \"./nodes/composite/Composite\";\nimport Decorator from \"./nodes/decorator/Decorator\";\nimport Parallel from \"./nodes/composite/Parallel\";\nimport Selector from \"./nodes/composite/Selector\";\nimport Sequence from \"./nodes/composite/Sequence\";\nimport Lotto from \"./nodes/composite/Lotto\";\nimport Fail from \"./nodes/decorator/Fail\";\nimport Flip from \"./nodes/decorator/Flip\";\nimport Repeat from \"./nodes/decorator/Repeat\";\nimport Retry from \"./nodes/decorator/Retry\";\nimport Root from \"./nodes/decorator/Root\";\nimport Succeed from \"./nodes/decorator/Succeed\";\nimport Action from \"./nodes/leaf/Action\";\nimport Condition from \"./nodes/leaf/Condition\";\nimport Wait from \"./nodes/leaf/Wait\";\nimport Lookup from \"./Lookup\";\nimport Attribute from \"./attributes/Attribute\";\nimport While from \"./attributes/guards/While\";\nimport Until from \"./attributes/guards/Until\";\nimport Entry from \"./attributes/callbacks/Entry\";\nimport Step from \"./attributes/callbacks/Step\";\nimport Exit from \"./attributes/callbacks/Exit\";\n\n/**\n * A type representing any node instance in a behaviour tree.\n */\ntype AnyNode =\n | Root\n | Action\n | Condition\n | Wait\n | Sequence\n | Selector\n | Lotto\n | Parallel\n | Repeat\n | Retry\n | Flip\n | Succeed\n | Fail;\n\n/**\n * A type defining a mapping of root node identifiers to root node definitions.\n */\ntype RootNodeDefinitionMap = { [key: string | symbol]: RootNodeDefinition };\n\n/**\n * A symbol to use as the main root key in any root node mappings.\n */\nconst MAIN_ROOT_NODE_KEY = Symbol(\"__root__\");\n\n/**\n * Build and populate the root nodes based on the provided definition, assuming that the definition has been validated.\n * @param definition The root node definitions.\n * @returns The built and populated root node definitions.\n */\nexport default function buildRootNode(definition: RootNodeDefinition[]): Root {\n // Create a mapping of root node identifers to root node definitions, including globally registered subtree root node definitions.\n const rootNodeDefinitionMap = createRootNodeDefinitionMap(definition);\n\n // Now that we have all of our root node definitons (those part of the tree definition and those globally\n // registered) we should validate the definition. This will also double-check that we dont have any circular\n // dependencies in our branch -> subtree references and that we have no broken branch -> subtree links.\n validateBranchSubtreeLinks(definition, true);\n\n // Create our populated tree of node instances, starting with our main root node.\n const rootNode = nodeFactory(rootNodeDefinitionMap[MAIN_ROOT_NODE_KEY], rootNodeDefinitionMap) as Root;\n\n // Set a guard path on every leaf of the tree to evaluate as part of each update.\n applyLeafNodeGuardPaths(rootNode);\n\n // We only need to return the main root node.\n return rootNode;\n}\n\n/**\n * A factory function which creates a node instance based on the specified definition.\n * @param definition The node definition.\n * @param rootNodeDefinitionMap The mapping of root node identifers to root node definitions, including globally registered subtree root node definitions.\n * @returns A node instance based on the specified definition.\n */\nfunction nodeFactory(definition: AnyNodeDefinition, rootNodeDefinitionMap: RootNodeDefinitionMap): AnyNode {\n // Get the attributes for the node.\n const attributes = nodeAttributesFactory(definition);\n\n // Create the node instance based on the definition type.\n switch (definition.type) {\n case \"root\":\n return new Root(attributes, nodeFactory(definition.child, rootNodeDefinitionMap));\n\n case \"repeat\":\n let iterations: number | null = null;\n let iterationsMin: number | null = null;\n let iterationsMax: number | null = null;\n\n if (Array.isArray(definition.iterations)) {\n iterationsMin = definition.iterations[0];\n iterationsMax = definition.iterations[1];\n } else if (isInteger(definition.iterations)) {\n iterations = definition.iterations!;\n }\n\n return new Repeat(\n attributes,\n iterations,\n iterationsMin,\n iterationsMax,\n nodeFactory(definition.child, rootNodeDefinitionMap)\n );\n\n case \"retry\":\n let attempts: number | null = null;\n let attemptsMin: number | null = null;\n let attemptsMax: number | null = null;\n\n if (Array.isArray(definition.attempts)) {\n attemptsMin = definition.attempts[0];\n attemptsMax = definition.attempts[1];\n } else if (isInteger(definition.attempts)) {\n attempts = definition.attempts!;\n }\n\n return new Retry(\n attributes,\n attempts,\n attemptsMin,\n attemptsMax,\n nodeFactory(definition.child, rootNodeDefinitionMap)\n );\n\n case \"flip\":\n return new Flip(attributes, nodeFactory(definition.child, rootNodeDefinitionMap));\n\n case \"succeed\":\n return new Succeed(attributes, nodeFactory(definition.child, rootNodeDefinitionMap));\n\n case \"fail\":\n return new Fail(attributes, nodeFactory(definition.child, rootNodeDefinitionMap));\n\n case \"sequence\":\n return new Sequence(\n attributes,\n definition.children.map((child) => nodeFactory(child, rootNodeDefinitionMap))\n );\n\n case \"selector\":\n return new Selector(\n attributes,\n definition.children.map((child) => nodeFactory(child, rootNodeDefinitionMap))\n );\n\n case \"parallel\":\n return new Parallel(\n attributes,\n definition.children.map((child) => nodeFactory(child, rootNodeDefinitionMap))\n );\n\n case \"lotto\":\n return new Lotto(\n attributes,\n definition.weights,\n definition.children.map((child) => nodeFactory(child, rootNodeDefinitionMap))\n );\n\n case \"branch\":\n return nodeFactory(rootNodeDefinitionMap[definition.ref].child, rootNodeDefinitionMap);\n\n case \"action\":\n return new Action(attributes, definition.call, definition.args || []);\n\n case \"condition\":\n return new Condition(attributes, definition.call, definition.args || []);\n\n case \"wait\":\n let duration: number | null = null;\n let durationMin: number | null = null;\n let durationMax: number | null = null;\n\n if (Array.isArray(definition.duration)) {\n durationMin = definition.duration[0];\n durationMax = definition.duration[1];\n } else if (isInteger(definition.duration)) {\n duration = definition.duration!;\n }\n\n return new Wait(attributes, duration, durationMin, durationMax);\n }\n}\n\n/**\n * Creates an array of node attribute instances based on the specified node definition.\n * @param definition The node definition.\n * @returns An array of node attribute instances based on the specified node definition.\n */\nfunction nodeAttributesFactory(definition: AnyNodeDefinition): Attribute[] {\n const attributes: Attribute[] = [];\n\n if (definition.while) {\n attributes.push(new While(definition.while.call, definition.while.args ?? []));\n }\n\n if (definition.until) {\n attributes.push(new Until(definition.until.call, definition.until.args ?? []));\n }\n\n if (definition.entry) {\n attributes.push(new Entry(definition.entry.call, definition.entry.args ?? []));\n }\n\n if (definition.step) {\n attributes.push(new Step(definition.step.call, definition.step.args ?? []));\n }\n\n if (definition.exit) {\n attributes.push(new Exit(definition.exit.call, definition.exit.args ?? []));\n }\n\n return attributes;\n}\n\n/**\n * Creates a mapping of root node identifers to root node definitions, mixing in globally registered subtree root node definitions.\n * @param definition The root node definitions.\n * @returns A mapping of root node identifers to root node definitions, including globally registered subtree root node definitions.\n */\nfunction createRootNodeDefinitionMap(definition: RootNodeDefinition[]): RootNodeDefinitionMap {\n // Create a mapping of root node identifers to root node definitions.\n const rootNodeMap: RootNodeDefinitionMap = {};\n\n // Add in any registered subtree root node definitions.\n for (const [name, rootNodeDefinition] of Object.entries(Lookup.getSubtrees())) {\n // The name used when registering the subtree will be used as the root node identifier.\n rootNodeMap[name] = { ...rootNodeDefinition, id: name };\n }\n\n // Populate the map with the root node definitions that were included with the tree definition.\n // We do this after adding any registered subtrees as we want these to take presedence.\n for (const rootNodeDefinition of definition) {\n rootNodeMap[rootNodeDefinition.id ?? MAIN_ROOT_NODE_KEY] = rootNodeDefinition;\n }\n\n return rootNodeMap;\n}\n\n/**\n * Applies a guard path to every leaf of the tree to evaluate as part of each update.\n * @param root The main root tree node.\n */\nfunction applyLeafNodeGuardPaths(root: Root) {\n const nodePaths: Node[][] = [];\n\n const findLeafNodes = (path: Node[], node: Node) => {\n // Add the current node to the path.\n path = path.concat(node);\n\n // Check whether the current node is a leaf node.\n if (node.isLeafNode()) {\n nodePaths.push(path);\n } else {\n (node as Composite | Decorator).getChildren().forEach((child) => findLeafNodes(path, child));\n }\n };\n\n // Find all leaf node paths, starting from the root.\n findLeafNodes([], root);\n\n nodePaths.forEach((path) => {\n // Each node in the current path will have to be assigned a guard path, working from the root outwards.\n for (let depth = 0; depth < path.length; depth++) {\n // Get the node in the path at the current depth.\n const currentNode = path[depth];\n\n // The node may already have been assigned a guard path, if so just skip it.\n if (currentNode.hasGuardPath()) {\n continue;\n }\n\n // Create the guard path for the current node.\n const guardPath = new GuardPath(\n path\n .slice(0, depth + 1)\n .map((node) => ({ node, guards: node.getGuardAttributes() }))\n .filter((details) => details.guards.length > 0)\n );\n\n // Assign the guard path to the current node.\n currentNode.setGuardPath(guardPath);\n }\n });\n}\n", "import State, { AnyState } from \"./State\";\nimport Lookup from \"./Lookup\";\nimport Node from \"./nodes/Node\";\nimport Root from \"./nodes/decorator/Root\";\nimport Composite from \"./nodes/composite/Composite\";\nimport Decorator from \"./nodes/decorator/Decorator\";\nimport { Agent, GlobalFunction } from \"./Agent\";\nimport { CallbackAttributeDetails } from \"./attributes/callbacks/Callback\";\nimport { GuardAttributeDetails } from \"./attributes/guards/Guard\";\nimport { BehaviourTreeOptions } from \"./BehaviourTreeOptions\";\nimport { convertMDSLToJSON } from \"./mdsl/MDSLDefinitionParser\";\nimport { RootNodeDefinition } from \"./BehaviourTreeDefinition\";\nimport { validateDefinition, validateJSONDefinition } from \"./BehaviourTreeDefinitionValidator\";\nimport buildRootNode from \"./BehaviourTreeBuilder\";\nimport { isNullOrUndefined } from \"./BehaviourTreeDefinitionUtilities\";\n\n// Purely for outside inspection of the tree.\nexport type FlattenedTreeNode = {\n id: string;\n type: string;\n caption: string;\n state: AnyState;\n guards: GuardAttributeDetails[];\n callbacks: CallbackAttributeDetails[];\n args: any[];\n parentId: string | null;\n};\n\n/**\n * A representation of a behaviour tree.\n */\nexport class BehaviourTree {\n /**\n * The main root tree node.\n */\n private readonly _rootNode: Root;\n\n /**\n * Creates a new instance of the BehaviourTree class.\n * @param definition The behaviour tree definition as either an MDSL string, root node definition object or array of root node definition objects.\n * @param agent The agent instance that this behaviour tree is modelling behaviour for.\n * @param options The behaviour tree options object.\n */\n constructor(\n definition: string | RootNodeDefinition | RootNodeDefinition[],\n private agent: Agent,\n private options: BehaviourTreeOptions = {}\n ) {\n // The tree definition must be defined.\n if (isNullOrUndefined(definition)) {\n throw new Error(\"tree definition not defined\");\n }\n\n // The agent must be defined and not null.\n if (typeof agent !== \"object\" || agent === null) {\n throw new Error(\"the agent must be an object and not null\");\n }\n\n // We should validate the definition before we try to build the tree nodes.\n const { succeeded, errorMessage, json } = validateDefinition(definition);\n\n // Did our validation fail without error?\n if (!succeeded) {\n throw new Error(`invalid definition: ${errorMessage}`);\n }\n\n // Double check that we did actually get our json definition as part of our definition validtion.\n if (!json) {\n throw new Error(\n \"expected json definition to be returned as part of successful definition validation response\"\n );\n }\n\n try {\n // Create the populated tree of behaviour tree nodes and get the root node.\n this._rootNode = buildRootNode(json);\n } catch (exception) {\n // There was an issue in trying build and populate the behaviour tree.\n throw new Error(`error building tree: ${(exception as Error).message}`);\n }\n }\n\n /**\n * Gets whether the tree is in the RUNNING state.\n * @returns true if the tree is in the RUNNING state, otherwise false.\n */\n isRunning() {\n return this._rootNode.getState() === State.RUNNING;\n }\n\n /**\n * Gets the current tree state of SUCCEEDED, FAILED, READY or RUNNING.\n * @returns The current tree state.\n */\n getState() {\n return this._rootNode.getState();\n }\n\n /**\n * Step the tree.\n * 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.\n * 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\n * 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.\n *\n * 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.\n */\n step() {\n // If the root node has already been stepped to completion then we need to reset it.\n if (this._rootNode.getState() === State.SUCCEEDED || this._rootNode.getState() === State.FAILED) {\n this._rootNode.reset();\n }\n\n try {\n this._rootNode.update(this.agent, this.options);\n } catch (exception) {\n throw new Error(`error stepping tree: ${(exception as Error).message}`);\n }\n }\n\n /**\n * Resets the tree from the root node outwards to each nested node, giving each a state of READY.\n */\n reset() {\n this._rootNode.reset();\n }\n\n /**\n * Gets the flattened details of every node in the tree.\n * @returns The flattened details of every node in the tree.\n */\n getFlattenedNodeDetails(): FlattenedTreeNode[] {\n // Create an empty flattened array of tree nodes.\n const flattenedTreeNodes: FlattenedTreeNode[] = [];\n\n /**\n * Helper function to process a node instance and push details into the flattened tree nodes array.\n * @param node The current node.\n * @param parentUid The UID of the node parent, or null if the node is the main root node.\n */\n const processNode = (node: Node, parentUid: string | null) => {\n // Get the guard and callback attribute details for this node.\n const guards = node\n .getAttributes()\n .filter((attribute) => attribute.isGuard())\n .map((attribute) => attribute.getDetails()) as GuardAttributeDetails[];\n const callbacks = node\n .getAttributes()\n .filter((attribute) => !attribute.isGuard())\n .map((attribute) => attribute.getDetails()) as CallbackAttributeDetails[];\n\n // Push the current node into the flattened nodes array.\n flattenedTreeNodes.push({\n id: node.getUid(),\n type: node.getType(),\n caption: node.getName(),\n state: node.getState(),\n guards,\n callbacks,\n args: node.getArguments(),\n parentId: parentUid\n });\n\n // Process each of the nodes children if it is not a leaf node.\n if (!node.isLeafNode()) {\n (node as Composite | Decorator)\n .getChildren()\n .forEach((child) => processNode(child, (node as Composite | Decorator).getUid()));\n }\n };\n\n // Convert the nested node structure into a flattened array of node details.\n processNode(this._rootNode, null);\n\n return flattenedTreeNodes;\n }\n\n /**\n * Registers the action/condition/guard/callback function or subtree with the given name.\n * @param name The name of the function or subtree to register.\n * @param value The function or subtree definition to register.\n */\n static register(name: string, value: GlobalFunction | string | RootNodeDefinition) {\n // Are we going to register a action/condition/guard/callback function?\n if (typeof value === \"function\") {\n Lookup.setFunc(name, value);\n return;\n }\n\n // We are not registering an action/condition/guard/callback function, so we must be registering a subtree.\n if (typeof value === \"string\") {\n let rootNodeDefinitions: RootNodeDefinition[];\n\n // We will assume that any string passed in will be a mdsl definition.\n try {\n rootNodeDefinitions = convertMDSLToJSON(value);\n } catch (exception) {\n throw new Error(`error registering definition, invalid MDSL: ${(exception as Error).message}`);\n }\n\n // This function should only ever be called with a definition containing a single unnamed root node.\n if (rootNodeDefinitions.length != 1 || rootNodeDefinitions[0].id !== null) {\n throw new Error(\"error registering definition: expected a single unnamed root node\");\n }\n\n try {\n // We should validate the subtree as we don't want invalid subtrees available via the lookup.\n const { succeeded, errorMessage } = validateJSONDefinition(rootNodeDefinitions[0]);\n\n // Did our validation fail without error?\n if (!succeeded) {\n throw new Error(errorMessage);\n }\n } catch (exception) {\n throw new Error(`error registering definition: ${(exception as Error).message}`);\n }\n\n // Everything seems hunky-dory, register the subtree.\n Lookup.setSubtree(name, rootNodeDefinitions[0]);\n } else if (typeof value === \"object\" && !Array.isArray(value)) {\n // We will assume that any object passed in is a root node definition.\n\n try {\n // We should validate the subtree as we don't want invalid subtrees available via the lookup.\n const { succeeded, errorMessage } = validateJSONDefinition(value);\n\n // Did our validation fail without error?\n if (!succeeded) {\n throw new Error(errorMessage);\n }\n } catch (exception) {\n throw new Error(`error registering definition: ${(exception as Error).message}`);\n }\n\n // Everything seems hunky-dory, register the subtree.\n Lookup.setSubtree(name, value);\n } else {\n throw new Error(\"unexpected value, expected string mdsl definition, root node json definition or function\");\n }\n }\n\n /**\n * Unregisters the registered action/condition/guard/callback function or subtree with the given name.\n * @param name The name of the registered action/condition/guard/callback function or subtree to unregister.\n */\n static unregister(name: string): void {\n Lookup.remove(name);\n }\n\n /**\n * Unregister all registered action/condition/guard/callback functions and subtrees.\n */\n static unregisterAll(): void {\n Lookup.empty();\n }\n}\n"], + "mappings": "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", "names": ["Participant", "isNullOrUndefined", "Lotto", "createLotto", "State", "createLotto"] } diff --git a/dist/index.js b/dist/index.js index 2ef07ff..9e190ac 100644 --- a/dist/index.js +++ b/dist/index.js @@ -1757,13 +1757,24 @@ var Action = class extends Leaf { this.actionArguments = actionArguments; } isUsingUpdatePromise = false; - updatePromiseStateResult = null; + updatePromiseResult = null; onUpdate(agent, options) { if (this.isUsingUpdatePromise) { - if (this.updatePromiseStateResult) { - this.setState(this.updatePromiseStateResult); + if (!this.updatePromiseResult) { + return; + } + const { isResolved, value } = this.updatePromiseResult; + if (isResolved) { + if (value !== "mistreevous.succeeded" /* SUCCEEDED */ && value !== "mistreevous.failed" /* FAILED */) { + throw new Error( + "action node promise resolved with an invalid value, expected a State.SUCCEEDED or State.FAILED value to be returned" + ); + } + this.setState(value); + return; + } else { + throw new Error(`action function '${this.actionName}' promise rejected with '${value}'`); } - return; } const actionFuncInvoker = Lookup.getFuncInvoker(agent, this.actionName); if (actionFuncInvoker === null) { @@ -1783,18 +1794,19 @@ var Action = class extends Leaf { if (!this.isUsingUpdatePromise) { return; } - if (result !== "mistreevous.succeeded" /* SUCCEEDED */ && result !== "mistreevous.failed" /* FAILED */) { - throw new Error( - "action node promise resolved with an invalid value, expected a State.SUCCEEDED or State.FAILED value to be returned" - ); - } - this.updatePromiseStateResult = result; + this.updatePromiseResult = { + isResolved: true, + value: result + }; }, (reason) => { if (!this.isUsingUpdatePromise) { return; } - throw new Error(`action function '${this.actionName}' promise rejected with reason '${reason}'`); + this.updatePromiseResult = { + isResolved: false, + value: reason + }; } ); this.setState("mistreevous.running" /* RUNNING */); @@ -1808,7 +1820,7 @@ var Action = class extends Leaf { reset = () => { this.setState("mistreevous.ready" /* READY */); this.isUsingUpdatePromise = false; - this.updatePromiseStateResult = null; + this.updatePromiseResult = null; }; validateUpdateResult = (result) => { switch (result) { diff --git a/dist/index.js.map b/dist/index.js.map index 832a469..2298ede 100644 --- a/dist/index.js.map +++ b/dist/index.js.map @@ -1,7 +1,7 @@ { "version": 3, "sources": ["../node_modules/lotto-draw/dist/Participant.js", "../node_modules/lotto-draw/dist/Utilities.js", "../node_modules/lotto-draw/dist/Lotto.js", "../node_modules/lotto-draw/dist/createLotto.js", "../node_modules/lotto-draw/dist/index.js", "../src/index.ts", "../src/State.ts", "../src/BehaviourTreeDefinitionUtilities.ts", "../src/mdsl/MDSLUtilities.ts", "../src/mdsl/MDSLNodeArgumentParser.ts", "../src/mdsl/MDSLNodeAttributeParser.ts", "../src/mdsl/MDSLDefinitionParser.ts", "../src/BehaviourTreeDefinitionValidator.ts", "../src/Lookup.ts", "../src/attributes/guards/GuardUnsatisifedException.ts", "../src/attributes/guards/GuardPath.ts", "../src/nodes/Node.ts", "../src/nodes/composite/Composite.ts", "../src/nodes/composite/Parallel.ts", "../src/nodes/composite/Selector.ts", "../src/nodes/composite/Sequence.ts", "../src/nodes/composite/Lotto.ts", "../src/nodes/decorator/Decorator.ts", "../src/nodes/decorator/Fail.ts", "../src/nodes/decorator/Flip.ts", "../src/nodes/decorator/Repeat.ts", "../src/nodes/decorator/Retry.ts", "../src/nodes/decorator/Root.ts", "../src/nodes/decorator/Succeed.ts", "../src/nodes/leaf/Leaf.ts", "../src/nodes/leaf/Action.ts", "../src/nodes/leaf/Condition.ts", "../src/nodes/leaf/Wait.ts", "../src/attributes/Attribute.ts", "../src/attributes/guards/Guard.ts", "../src/attributes/guards/While.ts", "../src/attributes/guards/Until.ts", "../src/attributes/callbacks/Callback.ts", "../src/attributes/callbacks/Entry.ts", "../src/attributes/callbacks/Step.ts", "../src/attributes/callbacks/Exit.ts", "../src/BehaviourTreeBuilder.ts", "../src/BehaviourTree.ts"], - "sourcesContent": ["\"use strict\";\r\nObject.defineProperty(exports, \"__esModule\", { value: true });\r\nexports.Participant = void 0;\r\n/**\r\n * A participant that holds a number of tickets.\r\n */\r\nvar Participant = /** @class */ (function () {\r\n /**\r\n * Creates an instance of the Participant class.\r\n * @param participant The actual participant.\r\n * @param tickets The number of tickets held by the participant.\r\n */\r\n function Participant(participant, tickets) {\r\n if (tickets === void 0) { tickets = 1; }\r\n this._participant = participant;\r\n this._tickets = tickets;\r\n }\r\n Object.defineProperty(Participant.prototype, \"participant\", {\r\n /** Gets the actual participant. */\r\n get: function () {\r\n return this._participant;\r\n },\r\n enumerable: false,\r\n configurable: true\r\n });\r\n Object.defineProperty(Participant.prototype, \"tickets\", {\r\n /** Gets or sets the number of tickets held by the participant. */\r\n get: function () {\r\n return this._tickets;\r\n },\r\n set: function (value) {\r\n this._tickets = value;\r\n },\r\n enumerable: false,\r\n configurable: true\r\n });\r\n return Participant;\r\n}());\r\nexports.Participant = Participant;\r\n", "\"use strict\";\r\nObject.defineProperty(exports, \"__esModule\", { value: true });\r\nexports.isNaturalNumber = exports.isNullOrUndefined = void 0;\r\n/**\r\n * Gets whether the value provided is null or undefined.\r\n * @param value The value to check.\r\n * @returns Whether the value provided is null or undefined.\r\n */\r\nfunction isNullOrUndefined(value) {\r\n return value === null || value === undefined;\r\n}\r\nexports.isNullOrUndefined = isNullOrUndefined;\r\n/**\r\n * Gets whether the value provided is a natural number.\r\n * @param value The value to check.\r\n * @returns Whether the value provided is a natural number.\r\n */\r\nfunction isNaturalNumber(value) {\r\n return typeof value === \"number\" && value >= 1 && Math.floor(value) === value;\r\n}\r\nexports.isNaturalNumber = isNaturalNumber;\r\n", "\"use strict\";\r\nObject.defineProperty(exports, \"__esModule\", { value: true });\r\nexports.Lotto = void 0;\r\nvar Participant_1 = require(\"./Participant\");\r\nvar Utilities_1 = require(\"./Utilities\");\r\n/**\r\n * Represents a lotto consisting of a number of pickable ticket-holding participants.\r\n */\r\nvar Lotto = /** @class */ (function () {\r\n /**\r\n * Creates a new instance of Lotto.\r\n * @param customRandom The custom RNG to use in place of Math.random().\r\n */\r\n function Lotto(customRandom) {\r\n /** The array of participants that are holding tickets in the lotto. */\r\n this._participants = [];\r\n this._customRandom = customRandom;\r\n }\r\n /**\r\n * Adds a participant with the specified number of tickets, or adds to the participant ticket count if the participant already holds tickets.\r\n * @param participant The participant to add or to increase the ticket count for if they already hold tickets.\r\n * @param tickets The number of tickets, defaults to 1.\r\n * @returns The Lotto instance.\r\n */\r\n Lotto.prototype.add = function (participant, tickets) {\r\n if (tickets === void 0) { tickets = 1; }\r\n // Check that we have a valid ticket count.\r\n if (!(0, Utilities_1.isNaturalNumber)(tickets)) {\r\n throw new Error(\"tickets value must be a natural number\");\r\n }\r\n // Check whether this participant has already been added.\r\n var existingParticipant = this._participants.find(function (part) { return part.participant === participant; });\r\n if (existingParticipant) {\r\n // The participant has already been added to the lotto so just add to their ticket count.\r\n existingParticipant.tickets += tickets;\r\n }\r\n else {\r\n // The participant is not part of the lotto so we should add them.\r\n this._participants.push(new Participant_1.Participant(participant, tickets));\r\n }\r\n return this;\r\n };\r\n /**\r\n * Removes the specified number of tickets for the given participant from the draw, or all tickets if a ticket number is not defined.\r\n * @param participant The participant to remove tickets for.\r\n * @param tickets The number of tickets to remove, or undefined if all tickets are to be removed.\r\n * @returns The Lotto instance.\r\n */\r\n Lotto.prototype.remove = function (participant, tickets) {\r\n // Attempt to get the existing participant.\r\n var existingParticipant = this._participants.find(function (part) { return part.participant === participant; });\r\n // There is nothing to do if the specified participant isn't even part of the lotto.\r\n if (!existingParticipant) {\r\n return this;\r\n }\r\n // Check whether a tickets value was given.\r\n if (tickets !== undefined) {\r\n // Check that we have a valid ticket count.\r\n if (!(0, Utilities_1.isNaturalNumber)(tickets)) {\r\n throw new Error(\"tickets value must be a natural number\");\r\n }\r\n existingParticipant.tickets -= tickets;\r\n // If the participant no longer holds any tickets then they should be removed.\r\n if (existingParticipant.tickets < 1) {\r\n this._participants = this._participants.filter(function (part) { return part !== existingParticipant; });\r\n }\r\n }\r\n else {\r\n // We are removing all tickets for the participant so just remove them from the lotto.\r\n this._participants = this._participants.filter(function (part) { return part !== existingParticipant; });\r\n }\r\n return this;\r\n };\r\n /**\r\n * Draw a winning ticket and return the participant that holds the ticket.\r\n * @param options The draw options.\r\n * @returns The participant that holds the winning ticket.\r\n */\r\n Lotto.prototype.draw = function (options) {\r\n if (options === void 0) { options = {}; }\r\n // If we have no participants then just return null.\r\n if (this._participants.length === 0) {\r\n return null;\r\n }\r\n var redrawable = (0, Utilities_1.isNullOrUndefined)(options.redrawable) ? true : options.redrawable;\r\n var pickable = [];\r\n this._participants.forEach(function (_a) {\r\n var participant = _a.participant, tickets = _a.tickets;\r\n for (var ticketCount = 0; ticketCount < tickets; ticketCount++) {\r\n pickable.push(participant);\r\n }\r\n });\r\n var random;\r\n // We need a random floating-point number between 0 (inclusive) and 1 to scale up to pick our winner.\r\n // If a custom random function exists then we should use that or fall back to Math.random().\r\n if (this._customRandom) {\r\n // Call our custom random function to get a random floating-point number.\r\n random = this._customRandom();\r\n // Verify that the result of calling our custom random function is a number between 0 (inclusive) and 1.\r\n if (typeof random !== \"number\" || random < 0 || random >= 1) {\r\n throw new Error(\"the 'random' function provided did not return a number between 0 (inclusive) and 1\");\r\n }\r\n }\r\n else {\r\n // No custom random function was defined so just use good ol' Math.random().\r\n random = Math.random();\r\n }\r\n // Pick a winning participant.\r\n var winner = pickable[Math.floor(random * pickable.length)];\r\n // If the ticket isn't redrawable then we should remove a ticket from the winning participants ticket count.\r\n if (!redrawable) {\r\n this.remove(winner, 1);\r\n }\r\n // Return the winning participant.\r\n return winner;\r\n };\r\n /**\r\n * Draws multiple winning tickets and return an array of the participants that hold the winning tickets.\r\n * @param tickets The number of winning tickets to draw.\r\n * @param options The draw multiple options.\r\n * @returns An array of the participants that hold the winning tickets.\r\n */\r\n Lotto.prototype.drawMultiple = function (tickets, options) {\r\n if (options === void 0) { options = {}; }\r\n var uniqueResults = (0, Utilities_1.isNullOrUndefined)(options.unique) ? false : options.unique;\r\n // Handle cases where the user has asked for zero tickets (no idea why they would do this be we should trust them).\r\n if (tickets === 0) {\r\n return [];\r\n }\r\n // Now that we know out tickets value is not zero we should check that it is a valid natural number.\r\n if (!(0, Utilities_1.isNaturalNumber)(tickets)) {\r\n throw new Error(\"tickets value must be a natural number\");\r\n }\r\n var result = [];\r\n // Keep drawing tickets until we either reach the number of required tickets or we simply run out of tickets to draw.\r\n // We can run out of tickets to draw if 'options.redrawable' is explicity 'false' or we just had no participants when 'drawMultiple' was called.\r\n while (result.length < tickets && this._participants.length > 0) {\r\n result.push(this.draw(options));\r\n }\r\n // If the 'unique' draw option is set then we need to remove duplicates from the result list.\r\n if (uniqueResults) {\r\n // Create an array to store our unique results.\r\n var unique = [];\r\n // Iterate over all of our participants (with potential duplicates) and populate our array of unique values.\r\n for (var _i = 0, result_1 = result; _i < result_1.length; _i++) {\r\n var participant = result_1[_i];\r\n if (unique.indexOf(participant) === -1) {\r\n unique.push(participant);\r\n }\r\n }\r\n result = unique;\r\n }\r\n return result;\r\n };\r\n return Lotto;\r\n}());\r\nexports.Lotto = Lotto;\r\n", "\"use strict\";\r\nObject.defineProperty(exports, \"__esModule\", { value: true });\r\nexports.createLotto = void 0;\r\nvar Lotto_1 = require(\"./Lotto\");\r\n/**\r\n * A function that creates and returns a Lotto instance.\r\n * @param participantsOrOptions An array of initial participants or options relating to the creation of a Lotto instance.\r\n * @returns A new Lotto instance.\r\n */\r\nfunction createLotto(participantsOrOptions) {\r\n // If no initial participants or lotto options were provided as an argument then we can just return a new lotto instance now.\r\n if (!participantsOrOptions) {\r\n return new Lotto_1.Lotto();\r\n }\r\n // Check whether we were provided with an array of initial participants or a lotto options object.\r\n if (Array.isArray(participantsOrOptions)) {\r\n // We are dealing with a pre-defined array of participants.\r\n var participants = participantsOrOptions;\r\n var lotto_1 = new Lotto_1.Lotto();\r\n // If the lotto participants have been defined upfront then we will need to add them all to our lotto instance now.\r\n participants.forEach(function (_a) {\r\n var participant = _a[0], tokens = _a[1];\r\n return lotto_1.add(participant, tokens);\r\n });\r\n // Return the Lotto instance.\r\n return lotto_1;\r\n }\r\n else {\r\n // We are dealing with some lotto options.\r\n var random = participantsOrOptions.random, participants = participantsOrOptions.participants;\r\n // Create a Lotto instance passing the custom RNG function to use in place of Math.random() (which could be undefined).\r\n var lotto_2 = new Lotto_1.Lotto(random);\r\n // If the lotto participants have been defined upfront as part of the options then we will need to add them all to our lotto instance now.\r\n if (participants) {\r\n participants.forEach(function (_a) {\r\n var participant = _a[0], tokens = _a[1];\r\n return lotto_2.add(participant, tokens);\r\n });\r\n }\r\n // Return the Lotto instance.\r\n return lotto_2;\r\n }\r\n}\r\nexports.createLotto = createLotto;\r\n", "\"use strict\";\r\nObject.defineProperty(exports, \"__esModule\", { value: true });\r\nvar createLotto_1 = require(\"./createLotto\");\r\nexports.default = createLotto_1.createLotto;\r\n", "import State from \"./State\";\nimport { validateDefinition } from \"./BehaviourTreeDefinitionValidator\";\nimport { convertMDSLToJSON } from \"./mdsl/MDSLDefinitionParser\";\nimport { BehaviourTree, FlattenedTreeNode } from \"./BehaviourTree\";\nimport { BehaviourTreeOptions } from \"./BehaviourTreeOptions\";\n\nexport { BehaviourTree, State, convertMDSLToJSON, validateDefinition };\nexport type { FlattenedTreeNode, BehaviourTreeOptions };\n", "/**\n * Enumeration of node state types.\n */\nexport enum State {\n READY = \"mistreevous.ready\",\n RUNNING = \"mistreevous.running\",\n SUCCEEDED = \"mistreevous.succeeded\",\n FAILED = \"mistreevous.failed\"\n}\n\nexport { State as default };\n\nexport type CompleteState = State.SUCCEEDED | State.FAILED;\nexport type AnyState = State.READY | State.RUNNING | CompleteState;\n", "import {\n NodeDefinition,\n RootNodeDefinition,\n DecoratorNodeDefinition,\n CompositeNodeDefinition,\n AnyNodeDefinition,\n BranchNodeDefinition\n} from \"./BehaviourTreeDefinition\";\n\n/**\n * A type guard function that returns true if the specified node satisfies the RootNodeDefinition type.\n * @param node The node.\n * @returns A value of true if the specified node satisfies the RootNodeDefinition type.\n */\nexport function isRootNode(node: NodeDefinition): node is RootNodeDefinition {\n return node.type === \"root\";\n}\n\n/**\n * A type guard function that returns true if the specified node satisfies the BranchNodeDefinition type.\n * @param node The node.\n * @returns A value of true if the specified node satisfies the BranchNodeDefinition type.\n */\nexport function isBranchNode(node: NodeDefinition): node is BranchNodeDefinition {\n return node.type === \"branch\";\n}\n\n/**\n * A type guard function that returns true if the specified node satisfies the NodeDefinition type.\n * @param node The node.\n * @returns A value of true if the specified node satisfies the NodeDefinition type.\n */\nexport function isLeafNode(node: NodeDefinition): node is NodeDefinition {\n return [\"branch\", \"action\", \"condition\", \"wait\"].includes(node.type);\n}\n\n/**\n * A type guard function that returns true if the specified node satisfies the DecoratorNodeDefinition type.\n * @param node The node.\n * @returns A value of true if the specified node satisfies the DecoratorNodeDefinition type.\n */\nexport function isDecoratorNode(node: NodeDefinition): node is DecoratorNodeDefinition {\n return [\"root\", \"repeat\", \"retry\", \"flip\", \"succeed\", \"fail\"].includes(node.type);\n}\n\n/**\n * A type guard function that returns true if the specified node satisfies the CompositeNodeDefinition type.\n * @param node The node.\n * @returns A value of true if the specified node satisfies the CompositeNodeDefinition type.\n */\nexport function isCompositeNode(node: NodeDefinition): node is CompositeNodeDefinition {\n return [\"sequence\", \"selector\", \"lotto\", \"parallel\"].includes(node.type);\n}\n\n/**\n * Flatten a node definition into an array of all of its nested node definitions.\n * @param nodeDefinition The node definition to flatten.\n * @returns An array of all of nested node definitions.\n */\nexport function flattenDefinition(nodeDefinition: AnyNodeDefinition): AnyNodeDefinition[] {\n const nodes: AnyNodeDefinition[] = [];\n\n const processNode = (currentNodeDefinition: AnyNodeDefinition) => {\n nodes.push(currentNodeDefinition);\n\n if (isCompositeNode(currentNodeDefinition)) {\n currentNodeDefinition.children.forEach(processNode);\n } else if (isDecoratorNode(currentNodeDefinition)) {\n processNode(currentNodeDefinition.child);\n }\n };\n\n processNode(nodeDefinition);\n\n return nodes;\n}\n\n/**\n * Determines whether the passed value is an integer.\n * @param value The value to check.\n * @returns Whether the passed value is an integer.\n */\nexport function isInteger(value: unknown): boolean {\n return typeof value === \"number\" && Math.floor(value) === value;\n}\n\n/**\n * Determines whether the passed value is null or undefined.\n * @param value The value to check.\n * @returns Whether the passed value is null or undefined.\n */\nexport function isNullOrUndefined(value: unknown): boolean {\n return typeof value === \"undefined\" || value === null;\n}\n", "/**\n * A type defining an object that holds a reference to substitued string literals parsed from the definition.\n */\nexport type StringLiteralPlaceholders = { [key: string]: string };\n\n/**\n * Pop the next raw token from the specified array of tokens and throw an error if it wasn't the expected one.\n * @param tokens The array of tokens.\n * @param expected An optional string or array or items, one of which must match the next popped token.\n * @returns The popped token.\n */\nexport function popAndCheck(tokens: string[], expected?: string | string[]): string {\n // Get and remove the next token.\n const popped = tokens.shift();\n\n // We were expecting another token but there aren't any.\n if (popped === undefined) {\n throw new Error(\"unexpected end of definition\");\n }\n\n // Do we have an expected token/tokens array?\n if (expected != undefined) {\n // Get an array of expected values, if the popped token matches any then we are all good.\n const expectedValues = typeof expected === \"string\" ? [expected] : expected;\n\n // Check whether the popped token matches at least one of our expected items.\n var tokenMatchesExpectation = expectedValues.some((item) => popped.toUpperCase() === item.toUpperCase());\n\n // Throw an error if the popped token didn't match any of our expected items.\n if (!tokenMatchesExpectation) {\n const expectationString = expectedValues.map((item) => \"'\" + item + \"'\").join(\" or \");\n throw new Error(\"unexpected token found. Expected \" + expectationString + \" but got '\" + popped + \"'\");\n }\n }\n\n // Return the popped token.\n return popped;\n}\n\n/**\n * Swaps out any node/attribute argument string literals with placeholders.\n * @param definition The definition.\n * @returns An object containing a mapping of placeholders to original string values as well as the processed definition string.\n */\nexport function substituteStringLiterals(definition: string): {\n placeholders: StringLiteralPlaceholders;\n processedDefinition: string;\n} {\n // Create an object to hold the mapping of placeholders to original string values.\n const placeholders: StringLiteralPlaceholders = {};\n\n // Replace any string literals wrapped with double quotes in our definition with placeholders to be processed later.\n const processedDefinition = definition.replace(/\\\"(\\\\.|[^\"\\\\])*\\\"/g, (match) => {\n var strippedMatch = match.substring(1, match.length - 1);\n var placeholder = Object.keys(placeholders).find((key) => placeholders[key] === strippedMatch);\n\n // If we have no existing string literal match then create a new placeholder.\n if (!placeholder) {\n placeholder = `@@${Object.keys(placeholders).length}@@`;\n placeholders[placeholder] = strippedMatch;\n }\n\n return placeholder;\n });\n\n return { placeholders, processedDefinition };\n}\n\n/**\n * Parse the tree definition into an array of raw tokens.\n * @param definition The definition.\n * @returns An array of tokens parsed from the definition.\n */\nexport function parseTokensFromDefinition(definition: string): string[] {\n // Add some space around various important characters so that they can be plucked out easier as individual tokens.\n definition = definition.replace(/\\(/g, \" ( \");\n definition = definition.replace(/\\)/g, \" ) \");\n definition = definition.replace(/\\{/g, \" { \");\n definition = definition.replace(/\\}/g, \" } \");\n definition = definition.replace(/\\]/g, \" ] \");\n definition = definition.replace(/\\[/g, \" [ \");\n definition = definition.replace(/\\,/g, \" , \");\n\n // Split the definition into raw token form and return it.\n return definition.replace(/\\s+/g, \" \").trim().split(\" \");\n}\n", "import { StringLiteralPlaceholders, popAndCheck } from \"./MDSLUtilities\";\n\n/**\n * A type representing any node function argument.\n */\ntype Argument = {\n /**\n * The argument value.\n */\n value: T;\n /**\n * The argument type, used for validation.\n */\n type: string;\n};\n\ntype NullArgument = Argument & {\n type: \"null\";\n};\n\ntype BooleanArgument = Argument & {\n type: \"boolean\";\n};\n\ntype NumberArgument = Argument & {\n type: \"number\";\n /**\n * A flag defining whether the number argument value is a valid integer. (used for validation)\n */\n isInteger: boolean;\n};\n\ntype StringPlaceholderArgument = Argument & {\n type: \"string\";\n};\n\ntype IdentifierArgument = Argument & {\n type: \"identifier\";\n};\n\n/**\n * A type representing a reference to any node function argument.\n */\ntype AnyArgument = NullArgument | BooleanArgument | NumberArgument | StringPlaceholderArgument | IdentifierArgument;\n\n/**\n * Parse an array of argument definitions from the specified tokens array.\n * @param tokens The array tokens to parse the argument definitions from.\n * @param stringArgumentPlaceholders The mapping of string literal node argument placeholders to original values.\n * @param argumentValidator The argument validator function.\n * @param validationFailedMessage The exception message to throw if argument validation fails.\n * @returns An array of argument definitions parsed from the specified tokens array.\n */\nexport function parseArgumentTokens(\n tokens: string[],\n stringArgumentPlaceholders: StringLiteralPlaceholders\n): AnyArgument[] {\n const argumentList: AnyArgument[] = [];\n\n // If the next token is not a '[' or '(' then we have no arguments to parse.\n if (![\"[\", \"(\"].includes(tokens[0])) {\n return argumentList;\n }\n\n // Any lists of arguments will always be wrapped in '[]' for node arguments or '()' for attribute arguments.\n // We are looking for a '[' or '(' opener that wraps the argument tokens and the relevant closer.\n const closingToken = popAndCheck(tokens, [\"[\", \"(\"]) === \"[\" ? \"]\" : \")\";\n\n const argumentListTokens: string[] = [];\n\n // Grab all tokens between the '[' and ']' or '(' and ')'.\n while (tokens.length && tokens[0] !== closingToken) {\n // The next token is part of our arguments list.\n argumentListTokens.push(tokens.shift()!);\n }\n\n // Validate the order of the argument tokens. Each token must either be a ',' or a single argument that satisfies the validator.\n argumentListTokens.forEach((token, index) => {\n // Get whether this token should be an actual argument.\n const shouldBeArgumentToken = !(index & 1);\n\n // If the current token should be an actual argument then validate it, otherwise it should be a ',' token.\n if (shouldBeArgumentToken) {\n // Get the argument definition.\n const argumentDefinition = getArgumentDefinition(token, stringArgumentPlaceholders);\n\n // This is a valid argument!\n argumentList.push(argumentDefinition);\n } else {\n // The current token should be a ',' token.\n if (token !== \",\") {\n throw new Error(`invalid argument list, expected ',' or ']' but got '${token}'`);\n }\n }\n });\n\n // The arguments list should terminate with a ']' or ')' token, depending on the opener.\n popAndCheck(tokens, closingToken);\n\n // Return the arguments.\n return argumentList;\n}\n\n/**\n * Gets an argument value definition.\n * @param token The argument token.\n * @param stringArgumentPlaceholders The mapping of string literal node argument placeholders to original values.\n * @returns An argument value definition.\n */\nfunction getArgumentDefinition(token: string, stringArgumentPlaceholders: StringLiteralPlaceholders): AnyArgument {\n // Check whether the token represents a null value.\n if (token === \"null\") {\n return {\n value: null,\n type: \"null\"\n } as NullArgument;\n }\n\n // Check whether the token represents a boolean value.\n if (token === \"true\" || token === \"false\") {\n return {\n value: token === \"true\",\n type: \"boolean\"\n } as BooleanArgument;\n }\n\n // Check whether the token represents a number value.\n // TODO: Relies on broken isNaN - see MDN.\n // if (!Number.isNaN(token)) {\n if (!isNaN(token as any)) {\n return {\n value: parseFloat(token),\n isInteger: parseFloat(token) === parseInt(token, 10),\n type: \"number\"\n } as NumberArgument;\n }\n\n // Check whether the token is a placeholder (e.g. @@0@@) representing a string literal.\n if (token.match(/^@@\\d+@@$/g)) {\n return {\n value: stringArgumentPlaceholders[token].replace('\\\\\"', '\"'),\n type: \"string\"\n } as StringPlaceholderArgument;\n }\n\n // The only remaining option is that the argument value is an identifier.\n return {\n value: token,\n type: \"identifier\"\n } as IdentifierArgument;\n}\n", "import { NodeAttributeDefinition } from \"../BehaviourTreeDefinition\";\nimport { parseArgumentTokens } from \"./MDSLNodeArgumentParser\";\nimport { StringLiteralPlaceholders } from \"./MDSLUtilities\";\n\n/**\n * A type defining the attribute definitions of a node.\n */\ntype NodeAttributes = {\n while?: NodeAttributeDefinition;\n until?: NodeAttributeDefinition;\n entry?: NodeAttributeDefinition;\n exit?: NodeAttributeDefinition;\n step?: NodeAttributeDefinition;\n};\n\n/**\n * Parse any node attribute definitions from the specified tokens array.\n * @param tokens The array of remaining tokens.\n * @param stringArgumentPlaceholders The mapping of string literal node argument placeholders to original values.\n * @returns An object of attribute definitions defined by any directly following tokens.\n */\nexport function parseAttributeTokens(\n tokens: string[],\n stringArgumentPlaceholders: StringLiteralPlaceholders\n): NodeAttributes {\n const nodeAttributeNames: (keyof NodeAttributes)[] = [\"while\", \"until\", \"entry\", \"exit\", \"step\"];\n\n // Create an object to hold any attributes found.\n const attributes: NodeAttributes = {};\n\n // Try to get the name of the attribute for the next token.\n let nextAttributeName = tokens[0]?.toLowerCase() as keyof NodeAttributes;\n\n // Pull attribute tokens as well as their arguments off of the tokens stack until we have no more.\n while (nodeAttributeNames.includes(nextAttributeName)) {\n // Check to make sure that we have not already created an attribute definition of this type.\n if (attributes[nextAttributeName]) {\n throw new Error(`duplicate attribute '${tokens[0].toUpperCase()}' found for node`);\n }\n\n // Remove the attribute name token from the array of tokens.\n tokens.shift();\n\n // Grab the attribute arguments, assuming the first to be an identifier.\n const [attributeCallIdentifier, ...attributeArguments] = parseArgumentTokens(\n tokens,\n stringArgumentPlaceholders\n );\n\n // The first attribute argument has to be an identifer, this will reference an agent function.\n if (attributeCallIdentifier?.type !== \"identifier\") {\n throw new Error(\"expected agent function name identifier argument for attribute\");\n }\n\n // Any attribute arguments (other than the expected call identifier) must have a type of string, number, boolean or null.\n attributeArguments\n .filter((arg) => arg.type === \"identifier\")\n .forEach((arg) => {\n throw new Error(\n `invalid attribute argument value '${arg.value}', must be string, number, boolean or null`\n );\n });\n\n // Create the attribute definition and add it to the object of attribute definitions found.\n attributes[nextAttributeName] = {\n call: attributeCallIdentifier.value,\n args: attributeArguments.map(({ value }) => value)\n };\n\n // Try to get the next attribute name token, as there could be multiple.\n nextAttributeName = tokens[0]?.toLowerCase() as keyof NodeAttributes;\n }\n\n return attributes;\n}\n", "import {\n ActionNodeDefinition,\n AnyChildNodeDefinition,\n AnyNodeDefinition,\n BranchNodeDefinition,\n ConditionNodeDefinition,\n FailNodeDefinition,\n FlipNodeDefinition,\n LottoNodeDefinition,\n ParallelNodeDefinition,\n RepeatNodeDefinition,\n RetryNodeDefinition,\n RootNodeDefinition,\n SelectorNodeDefinition,\n SequenceNodeDefinition,\n SucceedNodeDefinition,\n WaitNodeDefinition\n} from \"../BehaviourTreeDefinition\";\nimport {\n isCompositeNode,\n isDecoratorNode,\n isLeafNode,\n isNullOrUndefined,\n isRootNode\n} from \"../BehaviourTreeDefinitionUtilities\";\nimport { parseArgumentTokens } from \"./MDSLNodeArgumentParser\";\nimport { parseAttributeTokens } from \"./MDSLNodeAttributeParser\";\nimport {\n StringLiteralPlaceholders,\n parseTokensFromDefinition,\n popAndCheck,\n substituteStringLiterals\n} from \"./MDSLUtilities\";\n\n/**\n * Convert the MDSL tree definition string into an equivalent JSON definition.\n * @param definition The tree definition string as MDSL.\n * @returns The root node JSON definitions.\n */\nexport function convertMDSLToJSON(definition: string): RootNodeDefinition[] {\n // Swap out any node/attribute argument string literals with a placeholder and get a mapping of placeholders to original values as well as the processed definition.\n const { placeholders, processedDefinition } = substituteStringLiterals(definition);\n\n // Parse our definition definition string into an array of raw tokens.\n const tokens = parseTokensFromDefinition(processedDefinition);\n\n return convertTokensToJSONDefinition(tokens, placeholders);\n}\n\n/**\n * Converts the specified tree definition tokens into a JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The root node JSON definitions.\n */\nfunction convertTokensToJSONDefinition(\n tokens: string[],\n stringLiteralPlaceholders: StringLiteralPlaceholders\n): RootNodeDefinition[] {\n // There must be at least 3 tokens for the tree definition to be valid. 'ROOT', '{' and '}'.\n if (tokens.length < 3) {\n throw new Error(\"invalid token count\");\n }\n\n // We should have a matching number of '{' and '}' tokens. If not, then there are scopes that have not been properly closed.\n if (tokens.filter((token) => token === \"{\").length !== tokens.filter((token) => token === \"}\").length) {\n throw new Error(\"scope character mismatch\");\n }\n\n // Create an array of tree stack arrays where root nodes will always be at the botton and the current composite/decorator node at the top.\n // There should be an element in this array for every root node defined and every element should be an array with a root note as the first element.\n // E.g. A definition with two root nodes defined:\n // [\n // [root, lotto, sequence],\n // [root, selector]\n // ]\n const treeStacks: [Partial, ...Partial[]][] = [];\n\n // Create an array of all root node definitions that we create.\n const rootNodes: Partial[] = [];\n\n // A helper function used to push node definitions onto the tree stack.\n const pushNode = (node: AnyNodeDefinition) => {\n // If the node is a root node then we need to create a new tree stack array with the root node at the root.\n if (isRootNode(node)) {\n // We need to double-check that this root node is not the child of another node.\n // We can do this by checking whether the top tree stack is not empty (contains an existing node)\n if (treeStacks[treeStacks.length - 1]?.length) {\n throw new Error(\"a root node cannot be the child of another node\");\n }\n\n // Add the root node definition to our array of all parsed root node definitions.\n rootNodes.push(node);\n\n // Add the root node definition to the root of a new tree stack.\n treeStacks.push([node]);\n\n return;\n }\n\n // All non-root nodes should be pushed after their root nodes so handle cases\n // where we may not have any tree stacks or our top-most tree stack is empty.\n if (!treeStacks.length || !treeStacks[treeStacks.length - 1].length) {\n throw new Error(\"expected root node at base of definition\");\n }\n\n // Get the current tree stack that we are populating.\n const topTreeStack = treeStacks[treeStacks.length - 1];\n\n // Get the top-most node in the current tree stack, this will be a composite/decorator node\n // for which we will populate its children array if composite or setting its child if a decorator.\n const topTreeStackTopNode = topTreeStack[topTreeStack.length - 1] as AnyNodeDefinition;\n\n // If the top-most node in the current root stack is a composite or decorator\n // node then the current node should be added as a child of the top-most node.\n if (isCompositeNode(topTreeStackTopNode)) {\n topTreeStackTopNode.children = topTreeStackTopNode.children || [];\n topTreeStackTopNode.children.push(node);\n } else if (isDecoratorNode(topTreeStackTopNode)) {\n // If the top node already has a child node set then throw an error as a decorator should only have a single child.\n if (topTreeStackTopNode.child) {\n throw new Error(\"a decorator node must only have a single child node\");\n }\n\n topTreeStackTopNode.child = node;\n }\n\n // If the node we are adding is also a composite or decorator node, then we should push it\n // onto the current tree stack, as subsequent nodes will be added as its child/children.\n if (!isLeafNode(node)) {\n topTreeStack.push(node);\n }\n };\n\n // A helper function used to pop the top-most node definition off of the tree stack and return it.\n const popNode = (): AnyNodeDefinition | null => {\n let poppedNode: AnyNodeDefinition | null = null;\n\n // Get the current tree stack that we are populating.\n const topTreeStack = treeStacks[treeStacks.length - 1];\n\n // Pop the top-most node in the current tree stack if there is one.\n if (topTreeStack.length) {\n poppedNode = topTreeStack.pop() as AnyNodeDefinition;\n }\n\n // We don't want any empty tree stacks in our stack of tree stacks.\n if (!topTreeStack.length) {\n treeStacks.pop();\n }\n\n return poppedNode;\n };\n\n // We should keep processing the raw tokens until we run out of them.\n while (tokens.length) {\n // Grab the next token.\n const token = tokens.shift()!;\n\n // How we create the next node depends on the current raw token value.\n switch (token.toUpperCase()) {\n case \"ROOT\": {\n pushNode(createRootNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"SUCCEED\": {\n pushNode(createSucceedNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"FAIL\": {\n pushNode(createFailNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"FLIP\": {\n pushNode(createFlipNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"REPEAT\": {\n pushNode(createRepeatNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"RETRY\": {\n pushNode(createRetryNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"SEQUENCE\": {\n pushNode(createSequenceNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"SELECTOR\": {\n pushNode(createSelectorNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"PARALLEL\": {\n pushNode(createParallelNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"LOTTO\": {\n pushNode(createLottoNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"ACTION\": {\n pushNode(createActionNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"CONDITION\": {\n pushNode(createConditionNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"WAIT\": {\n pushNode(createWaitNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"BRANCH\": {\n pushNode(createBranchNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"}\": {\n // The '}' character closes the current scope and means that we have to pop a node off of the current stack.\n const poppedNode = popNode();\n\n // Now that we have a node definition we can carry out any validation that may require the node to be fully populated.\n if (poppedNode) {\n validatePoppedNode(poppedNode);\n }\n\n break;\n }\n\n default: {\n throw new Error(`unexpected token: ${token}`);\n }\n }\n }\n\n return rootNodes as RootNodeDefinition[];\n}\n\n/**\n * Creates a root node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The root node JSON definition.\n */\nfunction createRootNode(tokens: string[], stringLiteralPlaceholders: StringLiteralPlaceholders): RootNodeDefinition {\n // Create the root node definition.\n let node = {\n type: \"root\",\n id: undefined\n } as RootNodeDefinition;\n\n // Parse any node arguments, we should only have one if any which will be an identifier argument for the root identifier.\n const nodeArguments = parseArgumentTokens(tokens, stringLiteralPlaceholders);\n\n // Check whether any node arguments were defined.\n if (nodeArguments.length) {\n // We should only have one argument, if any, which will be an identifier argument for the root identifier.\n if (nodeArguments.length === 1 && nodeArguments[0].type === \"identifier\") {\n // The root node identifier will be the first and only node argument value.\n node.id = nodeArguments[0].value as string;\n } else {\n throw new Error(\"expected single root name argument\");\n }\n }\n\n // Grab any node attribute definitions and spread them into the node definition.\n node = { ...node, ...parseAttributeTokens(tokens, stringLiteralPlaceholders) };\n\n // This is a decorator node, so we expect an opening '{'.\n popAndCheck(tokens, \"{\");\n\n // Return the root node definition.\n return node;\n}\n\n/**\n * Creates a succeed node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The succeed node JSON definition.\n */\nfunction createSucceedNode(\n tokens: string[],\n stringLiteralPlaceholders: StringLiteralPlaceholders\n): SucceedNodeDefinition {\n const node = {\n type: \"succeed\",\n ...parseAttributeTokens(tokens, stringLiteralPlaceholders)\n } as SucceedNodeDefinition;\n\n // This is a decorator node, so we expect an opening '{'.\n popAndCheck(tokens, \"{\");\n\n // Return the succeed node definition.\n return node;\n}\n\n/**\n * Creates a fail node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The fail node JSON definition.\n */\nfunction createFailNode(tokens: string[], stringLiteralPlaceholders: StringLiteralPlaceholders): FailNodeDefinition {\n const node = {\n type: \"fail\",\n ...parseAttributeTokens(tokens, stringLiteralPlaceholders)\n } as FailNodeDefinition;\n\n // This is a decorator node, so we expect an opening '{'.\n popAndCheck(tokens, \"{\");\n\n // Return the fail node definition.\n return node;\n}\n\n/**\n * Creates a flip node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The flip node JSON definition.\n */\nfunction createFlipNode(tokens: string[], stringLiteralPlaceholders: StringLiteralPlaceholders): FlipNodeDefinition {\n const node = {\n type: \"flip\",\n ...parseAttributeTokens(tokens, stringLiteralPlaceholders)\n } as FlipNodeDefinition;\n\n // This is a decorator node, so we expect an opening '{'.\n popAndCheck(tokens, \"{\");\n\n // Return the flip node definition.\n return node;\n}\n\n/**\n * Creates a repeat node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The repeat node JSON definition.\n */\nfunction createRepeatNode(\n tokens: string[],\n stringLiteralPlaceholders: StringLiteralPlaceholders\n): RepeatNodeDefinition {\n let node = { type: \"repeat\" } as RepeatNodeDefinition;\n\n // Get the node arguments.\n const nodeArguments = parseArgumentTokens(tokens, stringLiteralPlaceholders);\n\n // The arguments of a repeat node are optional. We may have:\n // - No node arguments, in which case the repeat note will iterate indefinitely.\n // - One node argument which will be the explicit number of iterations to make.\n // - Two node arguments which define the min and max iteration bounds from which a random iteration count will be picked.\n if (nodeArguments.length) {\n // All repeat node arguments MUST be of type number and must be integer.\n nodeArguments\n .filter((arg) => arg.type !== \"number\" || !arg.isInteger)\n .forEach(() => {\n throw new Error(`repeat node iteration counts must be integer values`);\n });\n\n // We should have got one or two iteration counts.\n if (nodeArguments.length === 1) {\n // A static iteration count was defined.\n node.iterations = nodeArguments[0].value as number;\n\n // A repeat node must have a positive number of iterations if defined.\n if (node.iterations < 0) {\n throw new Error(\"a repeat node must have a positive number of iterations if defined\");\n }\n } else if (nodeArguments.length === 2) {\n // A minimum and maximum iteration count was defined.\n node.iterations = [nodeArguments[0].value as number, nodeArguments[1].value as number];\n\n // A repeat node must have a positive min and max iteration count if they are defined.\n if (node.iterations[0] < 0 || node.iterations[1] < 0) {\n throw new Error(\"a repeat node must have a positive minimum and maximum iteration count if defined\");\n }\n\n // A repeat node must not have an minimum iteration count that exceeds the maximum iteration count.\n if (node.iterations[0] > node.iterations[1]) {\n throw new Error(\n \"a repeat node must not have a minimum iteration count that exceeds the maximum iteration count\"\n );\n }\n } else {\n // An incorrect number of iteration counts was defined.\n throw new Error(\"invalid number of repeat node iteration count arguments defined\");\n }\n }\n\n // Grab any node attribute definitions and spread them into the node definition.\n node = { ...node, ...parseAttributeTokens(tokens, stringLiteralPlaceholders) };\n\n // This is a decorator node, so we expect an opening '{'.\n popAndCheck(tokens, \"{\");\n\n // Return the repeat node definition.\n return node;\n}\n\n/**\n * Creates a retry node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The retry node JSON definition.\n */\nfunction createRetryNode(tokens: string[], stringLiteralPlaceholders: StringLiteralPlaceholders): RetryNodeDefinition {\n let node = { type: \"retry\" } as RetryNodeDefinition;\n\n // Get the node arguments.\n const nodeArguments = parseArgumentTokens(tokens, stringLiteralPlaceholders);\n\n // The arguments of a retry node are optional. We may have:\n // - No node arguments, in which case the retry note will attempt indefinitely.\n // - One node argument which will be the explicit number of attempts to make.\n // - Two node arguments which define the min and max attempt bounds from which a random attempt count will be picked.\n if (nodeArguments.length) {\n // All retry node arguments MUST be of type number and must be integer.\n nodeArguments\n .filter((arg) => arg.type !== \"number\" || !arg.isInteger)\n .forEach(() => {\n throw new Error(`retry node attempt counts must be integer values`);\n });\n\n // We should have got one or two attempt counts.\n if (nodeArguments.length === 1) {\n // A static attempt count was defined.\n node.attempts = nodeArguments[0].value as number;\n\n // A retry node must have a positive number of attempts if defined.\n if (node.attempts < 0) {\n throw new Error(\"a retry node must have a positive number of attempts if defined\");\n }\n } else if (nodeArguments.length === 2) {\n // A minimum and maximum attempt count was defined.\n node.attempts = [nodeArguments[0].value as number, nodeArguments[1].value as number];\n\n // A retry node must have a positive min and max attempts count if they are defined.\n if (node.attempts[0] < 0 || node.attempts[1] < 0) {\n throw new Error(\"a retry node must have a positive minimum and maximum attempt count if defined\");\n }\n\n // A retry node must not have a minimum attempt count that exceeds the maximum attempt count.\n if (node.attempts[0] > node.attempts[1]) {\n throw new Error(\n \"a retry node must not have a minimum attempt count that exceeds the maximum attempt count\"\n );\n }\n } else {\n // An incorrect number of attempt counts was defined.\n throw new Error(\"invalid number of retry node attempt count arguments defined\");\n }\n }\n\n // Grab any node attribute definitions and spread them into the node definition.\n node = { ...node, ...parseAttributeTokens(tokens, stringLiteralPlaceholders) };\n\n // This is a decorator node, so we expect an opening '{'.\n popAndCheck(tokens, \"{\");\n\n // Return the retry node definition.\n return node;\n}\n\n/**\n * Creates a sequence node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The sequence node JSON definition.\n */\nfunction createSequenceNode(\n tokens: string[],\n stringLiteralPlaceholders: StringLiteralPlaceholders\n): SequenceNodeDefinition {\n const node = {\n type: \"sequence\",\n ...parseAttributeTokens(tokens, stringLiteralPlaceholders)\n } as SequenceNodeDefinition;\n\n // This is a composite node, so we expect an opening '{'.\n popAndCheck(tokens, \"{\");\n\n // Return the sequence node definition.\n return node;\n}\n\n/**\n * Creates a selector node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The selector node JSON definition.\n */\nfunction createSelectorNode(\n tokens: string[],\n stringLiteralPlaceholders: StringLiteralPlaceholders\n): SelectorNodeDefinition {\n const node = {\n type: \"selector\",\n ...parseAttributeTokens(tokens, stringLiteralPlaceholders)\n } as SelectorNodeDefinition;\n\n // This is a composite node, so we expect an opening '{'.\n popAndCheck(tokens, \"{\");\n\n // Return the selector node definition.\n return node;\n}\n\n/**\n * Creates a parallel node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The parallel node JSON definition.\n */\nfunction createParallelNode(\n tokens: string[],\n stringLiteralPlaceholders: StringLiteralPlaceholders\n): ParallelNodeDefinition {\n const node = {\n type: \"parallel\",\n ...parseAttributeTokens(tokens, stringLiteralPlaceholders)\n } as ParallelNodeDefinition;\n\n // This is a composite node, so we expect an opening '{'.\n popAndCheck(tokens, \"{\");\n\n // Return the parallel node definition.\n return node;\n}\n\n/**\n * Creates a lotto node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The lotto node JSON definition.\n */\nfunction createLottoNode(tokens: string[], stringLiteralPlaceholders: StringLiteralPlaceholders): LottoNodeDefinition {\n // If any node arguments have been defined then they must be our weights.\n const nodeArguments = parseArgumentTokens(tokens, stringLiteralPlaceholders);\n\n // All lotto node arguments MUST be of type number and must be positive integers.\n nodeArguments\n .filter((arg) => arg.type !== \"number\" || !arg.isInteger || arg.value < 0)\n .forEach(() => {\n throw new Error(`lotto node weight arguments must be positive integer values`);\n });\n\n const node = {\n type: \"lotto\",\n weights: nodeArguments.length ? nodeArguments.map(({ value }) => value) : undefined,\n ...parseAttributeTokens(tokens, stringLiteralPlaceholders)\n } as LottoNodeDefinition;\n\n // This is a composite node, so we expect an opening '{'.\n popAndCheck(tokens, \"{\");\n\n // Return the lotto node definition.\n return node;\n}\n\n/**\n * Creates an action node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The action node JSON definition.\n */\nfunction createActionNode(\n tokens: string[],\n stringLiteralPlaceholders: StringLiteralPlaceholders\n): ActionNodeDefinition {\n // Parse any node arguments, we should have at least one which will be an identifier argument for the action name\n // and agent function to invoke for the action, all other arguments are to be passed as arguments to that function.\n const [actionNameIdentifier, ...agentFunctionArgs] = parseArgumentTokens(tokens, stringLiteralPlaceholders);\n\n // Our first argument MUST be defined and be an identifier as we require an action name argument.\n if (actionNameIdentifier?.type !== \"identifier\") {\n throw new Error(\"expected action name identifier argument\");\n }\n\n // Only the first argument should have been an identifier, all agent function arguments must be string, number, boolean or null.\n agentFunctionArgs\n .filter((arg) => arg.type === \"identifier\")\n .forEach((arg) => {\n throw new Error(\n `invalid action node argument value '${arg.value}', must be string, number, boolean or null`\n );\n });\n\n // Return the action node definition.\n return {\n type: \"action\",\n call: actionNameIdentifier.value,\n args: agentFunctionArgs.map(({ value }) => value),\n ...parseAttributeTokens(tokens, stringLiteralPlaceholders)\n };\n}\n\n/**\n * Creates a condition node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The condition node JSON definition.\n */\nfunction createConditionNode(\n tokens: string[],\n stringLiteralPlaceholders: StringLiteralPlaceholders\n): ConditionNodeDefinition {\n // Parse any node arguments, we should have at least one which will be an identifier argument for the condition name\n // and agent function to invoke for the condition, all other arguments are to be passed as arguments to that function.\n const [conditionNameIdentifier, ...agentFunctionArgs] = parseArgumentTokens(tokens, stringLiteralPlaceholders);\n\n // Our first argument MUST be defined and be an identifier as we require a condition name argument.\n if (conditionNameIdentifier?.type !== \"identifier\") {\n throw new Error(\"expected condition name identifier argument\");\n }\n\n // Only the first argument should have been an identifier, all agent function arguments must be string, number, boolean or null.\n agentFunctionArgs\n .filter((arg) => arg.type === \"identifier\")\n .forEach((arg) => {\n throw new Error(\n `invalid condition node argument value '${arg.value}', must be string, number, boolean or null`\n );\n });\n\n // Return the condition node definition.\n return {\n type: \"condition\",\n call: conditionNameIdentifier.value,\n args: agentFunctionArgs.map(({ value }) => value),\n ...parseAttributeTokens(tokens, stringLiteralPlaceholders)\n };\n}\n\n/**\n * Creates a wait node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The wait node JSON definition.\n */\nfunction createWaitNode(tokens: string[], stringLiteralPlaceholders: StringLiteralPlaceholders): WaitNodeDefinition {\n let node = { type: \"wait\" } as WaitNodeDefinition;\n\n // Get the node arguments.\n const nodeArguments = parseArgumentTokens(tokens, stringLiteralPlaceholders);\n\n // The arguments of a wait node are optional. We may have:\n // - No node arguments, in which case the wait will be indefinite until it is aborted.\n // - One node argument which will be the explicit duration of the wait.\n // - Two node arguments which define the min and max duration bounds from which a random duration will be picked.\n if (nodeArguments.length) {\n // All wait node arguments MUST be of type number and must be integer.\n nodeArguments\n .filter((arg) => arg.type !== \"number\" || !arg.isInteger)\n .forEach(() => {\n throw new Error(`wait node durations must be integer values`);\n });\n\n // We may have:\n // - One node argument which will be the explicit duration of the wait.\n // - Two node arguments which define the min and max duration bounds from which a random duration will be picked.\n // - Too many arguments, which is not valid.\n if (nodeArguments.length === 1) {\n // An explicit duration was defined.\n node.duration = nodeArguments[0].value as number;\n\n // If an explict duration was defined then it must be a positive number.\n if (node.duration < 0) {\n throw new Error(\"a wait node must have a positive duration\");\n }\n } else if (nodeArguments.length === 2) {\n // Min and max duration bounds were defined from which a random duration will be picked.\n node.duration = [nodeArguments[0].value as number, nodeArguments[1].value as number];\n\n // A wait node must have a positive min and max duration.\n if (node.duration[0] < 0 || node.duration[1] < 0) {\n throw new Error(\"a wait node must have a positive minimum and maximum duration\");\n }\n\n // A wait node must not have a minimum duration that exceeds the maximum duration.\n if (node.duration[0] > node.duration[1]) {\n throw new Error(\"a wait node must not have a minimum duration that exceeds the maximum duration\");\n }\n } else if (nodeArguments.length > 2) {\n // An incorrect number of duration arguments were defined.\n throw new Error(\"invalid number of wait node duration arguments defined\");\n }\n }\n\n // Return the wait node definition.\n return { ...node, ...parseAttributeTokens(tokens, stringLiteralPlaceholders) };\n}\n\n/**\n * Creates a branch node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The branch node JSON definition.\n */\nfunction createBranchNode(\n tokens: string[],\n stringLiteralPlaceholders: StringLiteralPlaceholders\n): BranchNodeDefinition {\n // Parse any node arguments, we should have one which will be an identifier argument for the root ref.\n const nodeArguments = parseArgumentTokens(tokens, stringLiteralPlaceholders);\n\n // We should have only a single identifer argument for a branch node, which is the root ref.\n if (nodeArguments.length !== 1 || nodeArguments[0].type !== \"identifier\") {\n throw new Error(\"expected single branch name argument\");\n }\n\n // Return the branch node definition.\n return { type: \"branch\", ref: nodeArguments[0].value };\n}\n\n/**\n * Validate a fully-populated node definition that was popped off of the tree stack.\n * @param definition The popped node to validate.\n */\nfunction validatePoppedNode(definition: AnyNodeDefinition): void {\n // Decorators MUST have a child defined.\n if (isDecoratorNode(definition) && isNullOrUndefined(definition.child)) {\n throw new Error(`a ${definition.type} node must have a single child node defined`);\n }\n\n // Composites MUST have at least one child defined.\n if (isCompositeNode(definition) && !definition.children?.length) {\n throw new Error(`a ${definition.type} node must have at least a single child node defined`);\n }\n\n // We need to make sure that lotto nodes that have weights defined have a number of weights matching the number of child nodes.\n if (definition.type === \"lotto\") {\n // Check whether a 'weights' property has been defined, if it has we expect it to be an array of weights.\n if (typeof definition.weights !== \"undefined\") {\n // Check that the weights property is an array of positive integers with an element for each child node element.\n if (definition.weights.length !== definition.children.length) {\n throw new Error(\n \"expected a number of weight arguments matching the number of child nodes for lotto node\"\n );\n }\n }\n }\n}\n", "import { RootNodeDefinition } from \"./BehaviourTreeDefinition\";\nimport { flattenDefinition, isBranchNode, isInteger } from \"./BehaviourTreeDefinitionUtilities\";\nimport { convertMDSLToJSON } from \"./mdsl/MDSLDefinitionParser\";\n\n/**\n * An object representing the result of validating a tree definition.\n */\nexport type DefinitionValidationResult = {\n /**\n * A flag defining whether validation succeeded.\n */\n succeeded: boolean;\n /**\n * A string containing the error message if validation did not succeed.\n */\n errorMessage?: string;\n /**\n * The definition as json if the validation was successful, or undefined if validation did not succeed.\n */\n json?: RootNodeDefinition[];\n};\n\n/**\n * Validates the specified behaviour tree definition in the form of JSON or MDSL, not taking any globally registered subtrees into consideration.\n * @param definition The behaviour tree definition in the form of JSON or MDSL.\n * @returns An object representing the result of validating the given tree definition.\n */\nexport function validateDefinition(definition: any): DefinitionValidationResult {\n // The definition must be defined.\n if (definition === null || typeof definition === \"undefined\") {\n return createValidationFailureResult(\"definition is null or undefined\");\n }\n\n // We are expecting a definition in one of three different forms:\n // - A string which we will assume is MDSL and we will parse this to JSON before validation.\n // - An array which we will assume is an array of root node definitions with at least one being the primary root node (no 'id' property)\n // - An object which we will assume is the primary root node and should not have an 'id' property.\n if (typeof definition === \"string\") {\n // The definition is a string which we can assume is MDSL, so attempt to validate it.\n return validateMDSLDefinition(definition);\n } else if (typeof definition === \"object\") {\n // The definition will either be an array (of root node definitions) or an object (the single primary root node definition).\n return validateJSONDefinition(definition);\n } else {\n return createValidationFailureResult(`unexpected definition type of '${typeof definition}'`);\n }\n}\n\n/**\n * Validates the specified behaviour tree definition in the form of MDSL.\n * @param definition The behaviour tree definition in the form of MDSL.\n * @returns An object representing the result of validating the given tree definition.\n */\nfunction validateMDSLDefinition(definition: string): DefinitionValidationResult {\n let rootNodeDefinitions;\n\n // The first thing the we need to do is to attempt to convert our MDSL into JSON.\n try {\n // The definition is a string which we can assume is MDSL, so attempt to parse it to a JSON definition in the form of an array of root node definitions.\n rootNodeDefinitions = convertMDSLToJSON(definition);\n } catch (exception) {\n // We failed to parse the JSON from the MDSL, this is likely to be the result of it not being a valid MDSL string.\n return createValidationFailureResult((exception as Error).message);\n }\n\n // Unpack all of the root node definitions into arrays of main ('id' defined) and sub ('id' not defined) root node definitions.\n const mainRootNodeDefinitions = rootNodeDefinitions.filter(({ id }) => typeof id === \"undefined\");\n const subRootNodeDefinitions = rootNodeDefinitions.filter(({ id }) => typeof id === \"string\" && id.length > 0);\n\n // We should ALWAYS have exactly one root node definition without an 'id' property defined, which is out main root node definition.\n if (mainRootNodeDefinitions.length !== 1) {\n return createValidationFailureResult(\n \"expected single unnamed root node at base of definition to act as main root\"\n );\n }\n\n // We should never have duplicate 'id' properties across our sub root node definitions.\n const subRootNodeIdenitifers: string[] = [];\n for (const { id } of subRootNodeDefinitions) {\n // Have we already come across this 'id' property value?\n if (subRootNodeIdenitifers.includes(id!)) {\n return createValidationFailureResult(`multiple root nodes found with duplicate name '${id}'`);\n }\n\n subRootNodeIdenitifers.push(id!);\n }\n\n try {\n // Validate our branch -> subtree links and check for any circular dependencies, we don't care about checking for broken subtree links here.\n validateBranchSubtreeLinks(rootNodeDefinitions, false);\n } catch (exception) {\n return createValidationFailureResult((exception as Error).message);\n }\n\n // Our definition was valid!\n return {\n succeeded: true,\n json: rootNodeDefinitions\n };\n}\n\n/**\n * Validates the specified behaviour tree definition in the form of JSON.\n * @param definition The behaviour tree definition in the form of JSON.\n * @returns An object representing the result of validating the given tree definition.\n */\nexport function validateJSONDefinition(\n definition: RootNodeDefinition | RootNodeDefinition[]\n): DefinitionValidationResult {\n // The definition will either be an array (of root node definitions) or an object (the single primary root node definition).\n const rootNodeDefinitions = Array.isArray(definition) ? definition : [definition];\n\n // Iterate over our array of root nodes and call validateNode for each, passing an initial depth of 0, wrapped in a try catch to handle validation failures.\n try {\n rootNodeDefinitions.forEach((rootNodeDefinition) => validateNode(rootNodeDefinition, 0));\n } catch (error) {\n // Handle cases where we have caught a thrown Error and return a failure result with the error message.\n if (error instanceof Error) {\n return createValidationFailureResult(error.message);\n }\n\n // No idea what happened here!\n return createValidationFailureResult(`unexpected error: ${error}`);\n }\n\n // Unpack all of the root node definitions into arrays of main ('id' defined) and sub ('id' not defined) root node definitions.\n const mainRootNodeDefinitions = rootNodeDefinitions.filter(({ id }) => typeof id === \"undefined\");\n const subRootNodeDefinitions = rootNodeDefinitions.filter(({ id }) => typeof id === \"string\" && id.length > 0);\n\n // We should ALWAYS have exactly one root node definition without an 'id' property defined, which is out main root node definition.\n if (mainRootNodeDefinitions.length !== 1) {\n return createValidationFailureResult(\n \"expected single root node without 'id' property defined to act as main root\"\n );\n }\n\n // We should never have duplicate 'id' properties across our sub root node definitions.\n const subRootNodeIdenitifers: string[] = [];\n for (const { id } of subRootNodeDefinitions) {\n // Have we already come across this 'id' property value?\n if (subRootNodeIdenitifers.includes(id!)) {\n return createValidationFailureResult(\n `multiple root nodes found with duplicate 'id' property value of '${id}'`\n );\n }\n\n subRootNodeIdenitifers.push(id!);\n }\n\n try {\n // Validate our branch -> subtree links and check for any circular dependencies, we don't care about checking for broken subtree links here.\n validateBranchSubtreeLinks(rootNodeDefinitions, false);\n } catch (exception) {\n return createValidationFailureResult((exception as Error).message);\n }\n\n // Our definition was valid!\n return {\n succeeded: true,\n json: rootNodeDefinitions\n };\n}\n\n/**\n * Validates the branch -> subtree links across all provided root node definitions.\n * This will not consider branch nodes that reference any globally registered subtrees unless includesGlobalSubtrees\n * is set to true, in which case we will also verify that there are no broken branch -> subtree links.\n * @param rootNodeDefinitions The array of root node definitions.\n * @param includesGlobalSubtrees A flag defining whether the array includes all global subtree root node definitions.\n */\nexport function validateBranchSubtreeLinks(rootNodeDefinitions: RootNodeDefinition[], includesGlobalSubtrees: boolean) {\n // Create a mapping of root node identifiers to other root nodes that they reference via branch nodes.\n // Below is an example of a mapping that includes a circular dependency (root => a => b => c => a)\n // [{ refs: [\"a\", \"b\"] }, { id: \"a\", refs: [\"b\"] }, { id: \"b\", refs: [\"c\"] }, { id: \"c\", refs: [\"a\"] }]\n const rootNodeMappings: { id: string | undefined; refs: string[] }[] = rootNodeDefinitions.map(\n (rootNodeDefinition) => ({\n id: rootNodeDefinition.id,\n refs: flattenDefinition(rootNodeDefinition)\n .filter(isBranchNode)\n .map(({ ref }) => ref)\n })\n );\n\n // A recursive function to walk through the mappings, keeping track of which root nodes we have visited in the form of a path of root node identifiers.\n const followRefs = (mapping: { id: string | undefined; refs: string[] }, path: (string | undefined)[] = []) => {\n // Have we found a circular dependency?\n if (path.includes(mapping.id)) {\n // We found a circular dependency! Get the bad path of root node identifiers.\n const badPath = [...path, mapping.id];\n\n // Create the formatted path value. [undefined, \"a\", \"b\", \"c\", \"a\"] would be formatted as \"a -> b -> c -> a\".\n const badPathFormatted = badPath.filter((element) => !!element).join(\" => \");\n\n // No need to continue, we found a circular dependency.\n throw new Error(`circular dependency found in branch node references: ${badPathFormatted}`);\n }\n\n for (const ref of mapping.refs) {\n // Find the mapping for the root node with an identifer matching the current ref.\n const subMapping = rootNodeMappings.find(({ id }) => id === ref);\n\n // We may not have a mapping for this ref, which is normal when we aren't considering all globally registered subtrees.\n if (subMapping) {\n followRefs(subMapping, [...path, mapping.id]);\n } else if (includesGlobalSubtrees) {\n // We found a reference to a root node that doesn't exist, which is a problem seeing as the root node definitons includes all globally registered subtrees.\n throw new Error(\n mapping.id\n ? `subtree '${mapping.id}' has branch node that references root node '${ref}' which has not been defined`\n : `primary tree has branch node that references root node '${ref}' which has not been defined`\n );\n }\n }\n };\n\n // Start looking for circular dependencies and broken references from the primary root node definition.\n followRefs(rootNodeMappings.find((mapping) => typeof mapping.id === \"undefined\")!);\n}\n\n/**\n * Validate an object that we expect to be a node definition.\n * @param definition An object that we expect to be a node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateNode(definition: any, depth: number): void {\n // Every node must be valid object and have a non-empty 'type' string property.\n if (typeof definition !== \"object\" || typeof definition.type !== \"string\" || definition.type.length === 0) {\n throw new Error(\n `node definition is not an object or 'type' property is not a non-empty string at depth '${depth}'`\n );\n }\n\n // How we validate this node definition will depend on its type.\n switch (definition.type) {\n case \"action\":\n validateActionNode(definition, depth);\n break;\n\n case \"condition\":\n validateConditionNode(definition, depth);\n break;\n\n case \"wait\":\n validateWaitNode(definition, depth);\n break;\n\n case \"branch\":\n validateBranchNode(definition, depth);\n break;\n\n case \"root\":\n validateRootNode(definition, depth);\n break;\n\n case \"succeed\":\n validateSucceedNode(definition, depth);\n break;\n\n case \"fail\":\n validateFailNode(definition, depth);\n break;\n\n case \"flip\":\n validateFlipNode(definition, depth);\n break;\n\n case \"repeat\":\n validateRepeatNode(definition, depth);\n break;\n\n case \"retry\":\n validateRetryNode(definition, depth);\n break;\n\n case \"sequence\":\n validateSequenceNode(definition, depth);\n break;\n\n case \"selector\":\n validateSelectorNode(definition, depth);\n break;\n\n case \"parallel\":\n validateParallelNode(definition, depth);\n break;\n\n case \"lotto\":\n validateLottoNode(definition, depth);\n break;\n\n default:\n throw new Error(`unexpected node type of '${definition.type}' at depth '${depth}'`);\n }\n}\n\n/**\n * Validate any attributes for a given node definition.\n * @param definition The node definition.\n * @param depth The depth of the node in the behaviour tree definition.\n */\nfunction validateNodeAttributes(definition: any, depth: number): void {\n // Validate each of the attribute types for this node.\n [\"while\", \"until\", \"entry\", \"exit\", \"step\"].forEach((attributeName) => {\n // Attempt to grab the definition for the current attribute from the node definition.\n const attributeDefinition = definition[attributeName];\n\n // All node attributes are optional, so there is nothing to do if the current attribute is not defined.\n if (typeof attributeDefinition === \"undefined\") {\n return;\n }\n\n // The attribute definition must be an object.\n if (typeof attributeDefinition !== \"object\") {\n throw new Error(\n `expected attribute '${attributeName}' to be an object for '${definition.type}' node at depth '${depth}'`\n );\n }\n\n // The 'call' property must be defined for any attribute definition.\n if (typeof attributeDefinition.call !== \"string\" || attributeDefinition.call.length === 0) {\n throw new Error(\n `expected 'call' property for attribute '${attributeName}' to be a non-empty string for '${definition.type}' node at depth '${depth}'`\n );\n }\n\n // If any node attribute arguments have been defined then they must have been defined in an array.\n if (typeof attributeDefinition.args !== \"undefined\" && !Array.isArray(attributeDefinition.args)) {\n throw new Error(\n `expected 'args' property for attribute '${attributeName}' to be an array for '${definition.type}' node at depth '${depth}'`\n );\n }\n });\n}\n\n/**\n * Validate an object that we expect to be a root node definition.\n * @param definition An object that we expect to be a root node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateRootNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"root\") {\n throw new Error(\"expected node type of 'root' for root node\");\n }\n\n // A root node cannot be the child of another node.\n if (depth > 0) {\n throw new Error(\"a root node cannot be the child of another node\");\n }\n\n // Check that, if the root node 'id' property is defined, it is a non-empty string.\n if (typeof definition.id !== \"undefined\" && (typeof definition.id !== \"string\" || definition.id.length === 0)) {\n throw new Error(\"expected non-empty string for 'id' property if defined for root node\");\n }\n\n // A root node is a decorator node, so must have a child node defined.\n if (typeof definition.child === \"undefined\") {\n throw new Error(\"expected property 'child' to be defined for root node\");\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n\n // Validate the child node of this decorator node.\n validateNode(definition.child, depth + 1);\n}\n\n/**\n * Validate an object that we expect to be a succeed node definition.\n * @param definition An object that we expect to be a succeed node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateSucceedNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"succeed\") {\n throw new Error(`expected node type of 'succeed' for succeed node at depth '${depth}'`);\n }\n\n // A succeed node is a decorator node, so must have a child node defined.\n if (typeof definition.child === \"undefined\") {\n throw new Error(`expected property 'child' to be defined for succeed node at depth '${depth}'`);\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n\n // Validate the child node of this decorator node.\n validateNode(definition.child, depth + 1);\n}\n\n/**\n * Validate an object that we expect to be a fail node definition.\n * @param definition An object that we expect to be a fail node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateFailNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"fail\") {\n throw new Error(`expected node type of 'fail' for fail node at depth '${depth}'`);\n }\n\n // A fail node is a decorator node, so must have a child node defined.\n if (typeof definition.child === \"undefined\") {\n throw new Error(`expected property 'child' to be defined for fail node at depth '${depth}'`);\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n\n // Validate the child node of this decorator node.\n validateNode(definition.child, depth + 1);\n}\n\n/**\n * Validate an object that we expect to be a flip node definition.\n * @param definition An object that we expect to be a flip node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateFlipNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"flip\") {\n throw new Error(`expected node type of 'flip' for flip node at depth '${depth}'`);\n }\n\n // A flip node is a decorator node, so must have a child node defined.\n if (typeof definition.child === \"undefined\") {\n throw new Error(`expected property 'child' to be defined for flip node at depth '${depth}'`);\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n\n // Validate the child node of this decorator node.\n validateNode(definition.child, depth + 1);\n}\n\n/**\n * Validate an object that we expect to be a repeat node definition.\n * @param definition An object that we expect to be a repeat node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateRepeatNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"repeat\") {\n throw new Error(`expected node type of 'repeat' for repeat node at depth '${depth}'`);\n }\n\n // A repeat node is a decorator node, so must have a child node defined.\n if (typeof definition.child === \"undefined\") {\n throw new Error(`expected property 'child' to be defined for repeat node at depth '${depth}'`);\n }\n\n // Check whether an 'iterations' property has been defined, it may not have been if this node is to repeat indefinitely.\n if (typeof definition.iterations !== \"undefined\") {\n if (Array.isArray(definition.iterations)) {\n // Check whether any elements of the array are not integer values.\n const containsNonInteger = !!definition.iterations.filter((value: unknown) => !isInteger(value)).length;\n\n // If the 'iterations' property is an array then it MUST contain two integer values.\n if (definition.iterations.length !== 2 || containsNonInteger) {\n throw new Error(\n `expected array containing two integer values for 'iterations' property if defined for repeat node at depth '${depth}'`\n );\n }\n\n // A repeat node must have a positive min and max iterations count if they are defined.\n if (definition.iterations[0] < 0 || definition.iterations[1] < 0) {\n throw new Error(\n `expected positive minimum and maximum iterations count for 'iterations' property if defined for repeat node at depth '${depth}'`\n );\n }\n\n // A repeat node must not have a minimum iterations count that exceeds the maximum iterations count.\n if (definition.iterations[0] > definition.iterations[1]) {\n throw new Error(\n `expected minimum iterations count that does not exceed the maximum iterations count for 'iterations' property if defined for repeat node at depth '${depth}'`\n );\n }\n } else if (isInteger(definition.iterations)) {\n // A repeat node must have a positive number of iterations if defined.\n if (definition.iterations < 0) {\n throw new Error(\n `expected positive iterations count for 'iterations' property if defined for repeat node at depth '${depth}'`\n );\n }\n } else {\n throw new Error(\n `expected integer value or array containing two integer values for 'iterations' property if defined for repeat node at depth '${depth}'`\n );\n }\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n\n // Validate the child node of this decorator node.\n validateNode(definition.child, depth + 1);\n}\n\n/**\n * Validate an object that we expect to be a retry node definition.\n * @param definition An object that we expect to be a retry node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateRetryNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"retry\") {\n throw new Error(`expected node type of 'retry' for retry node at depth '${depth}'`);\n }\n\n // A retry node is a decorator node, so must have a child node defined.\n if (typeof definition.child === \"undefined\") {\n throw new Error(`expected property 'child' to be defined for retry node at depth '${depth}'`);\n }\n\n // Check whether an 'attempts' property has been defined, it may not have been if this node is to retry indefinitely.\n if (typeof definition.attempts !== \"undefined\") {\n if (Array.isArray(definition.attempts)) {\n // Check whether any elements of the array are not integer values.\n const containsNonInteger = !!definition.attempts.filter((value: unknown) => !isInteger(value)).length;\n\n // If the 'attempts' property is an array then it MUST contain two integer values.\n if (definition.attempts.length !== 2 || containsNonInteger) {\n throw new Error(\n `expected array containing two integer values for 'attempts' property if defined for retry node at depth '${depth}'`\n );\n }\n\n // A retry node must have a positive min and max attempts count if they are defined.\n if (definition.attempts[0] < 0 || definition.attempts[1] < 0) {\n throw new Error(\n `expected positive minimum and maximum attempts count for 'attempts' property if defined for retry node at depth '${depth}'`\n );\n }\n\n // A retry node must not have a minimum attempts count that exceeds the maximum attempts count.\n if (definition.attempts[0] > definition.attempts[1]) {\n throw new Error(\n `expected minimum attempts count that does not exceed the maximum attempts count for 'attempts' property if defined for retry node at depth '${depth}'`\n );\n }\n } else if (isInteger(definition.attempts)) {\n // A retry node must have a positive number of attempts if defined.\n if (definition.attempts < 0) {\n throw new Error(\n `expected positive attempts count for 'attempts' property if defined for retry node at depth '${depth}'`\n );\n }\n } else {\n throw new Error(\n `expected integer value or array containing two integer values for 'attempts' property if defined for retry node at depth '${depth}'`\n );\n }\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n\n // Validate the child node of this decorator node.\n validateNode(definition.child, depth + 1);\n}\n\n/**\n * Validate an object that we expect to be a branch node definition.\n * @param definition An object that we expect to be a branch node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateBranchNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"branch\") {\n throw new Error(`expected node type of 'branch' for branch node at depth '${depth}'`);\n }\n\n // Check that the branch node 'ref' property is defined and is a non-empty string.\n if (typeof definition.ref !== \"string\" || definition.ref.length === 0) {\n throw new Error(`expected non-empty string for 'ref' property for branch node at depth '${depth}'`);\n }\n\n // It is invalid to define guard attributes for a branch node as they should be defined on the referenced root node.\n [\"while\", \"until\"].forEach((attributeName) => {\n if (typeof definition[attributeName] !== \"undefined\") {\n throw new Error(\n `guards should not be defined for branch nodes but guard '${attributeName}' was defined for branch node at depth '${depth}'`\n );\n }\n });\n\n // It is invalid to define callback attributes for a branch node as they should be defined on the referenced root node.\n [\"entry\", \"exit\", \"step\"].forEach((attributeName) => {\n if (typeof definition[attributeName] !== \"undefined\") {\n throw new Error(\n `callbacks should not be defined for branch nodes but callback '${attributeName}' was defined for branch node at depth '${depth}'`\n );\n }\n });\n}\n\n/**\n * Validate an object that we expect to be a action node definition.\n * @param definition An object that we expect to be a action node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateActionNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"action\") {\n throw new Error(`expected node type of 'action' for action node at depth '${depth}'`);\n }\n\n // The 'call' property must be defined for a action node definition.\n if (typeof definition.call !== \"string\" || definition.call.length === 0) {\n throw new Error(`expected non-empty string for 'call' property of action node at depth '${depth}'`);\n }\n\n // If any action function arguments have been defined then they must have been defined in an array.\n if (typeof definition.args !== \"undefined\" && !Array.isArray(definition.args)) {\n throw new Error(`expected array for 'args' property if defined for action node at depth '${depth}'`);\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n}\n\n/**\n * Validate an object that we expect to be a condition node definition.\n * @param definition An object that we expect to be a condition node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateConditionNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"condition\") {\n throw new Error(`expected node type of 'condition' for condition node at depth '${depth}'`);\n }\n\n // The 'call' property must be defined for a condition node definition.\n if (typeof definition.call !== \"string\" || definition.call.length === 0) {\n throw new Error(`expected non-empty string for 'call' property of condition node at depth '${depth}'`);\n }\n\n // If any condition function arguments have been defined then they must have been defined in an array.\n if (typeof definition.args !== \"undefined\" && !Array.isArray(definition.args)) {\n throw new Error(`expected array for 'args' property if defined for condition node at depth '${depth}'`);\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n}\n\n/**\n * Validate an object that we expect to be a wait node definition.\n * @param definition An object that we expect to be a wait node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateWaitNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"wait\") {\n throw new Error(`expected node type of 'wait' for wait node at depth '${depth}'`);\n }\n\n // Check whether a 'duration' property has been defined, it may not have been if this node is to wait indefinitely.\n if (typeof definition.duration !== \"undefined\") {\n if (Array.isArray(definition.duration)) {\n // Check whether any elements of the array are not integer values.\n const containsNonInteger = !!definition.duration.filter((value: unknown) => !isInteger(value)).length;\n\n // If the 'duration' property is an array then it MUST contain two integer values.\n if (definition.duration.length !== 2 || containsNonInteger) {\n throw new Error(\n `expected array containing two integer values for 'duration' property if defined for wait node at depth '${depth}'`\n );\n }\n\n // A wait node must have a positive min and max duration value if they are defined.\n if (definition.duration[0] < 0 || definition.duration[1] < 0) {\n throw new Error(\n `expected positive minimum and maximum duration for 'duration' property if defined for wait node at depth '${depth}'`\n );\n }\n\n // A wait node must not have a minimum duration value that exceeds the maximum duration value.\n if (definition.duration[0] > definition.duration[1]) {\n throw new Error(\n `expected minimum duration value that does not exceed the maximum duration value for 'duration' property if defined for wait node at depth '${depth}'`\n );\n }\n } else if (isInteger(definition.duration)) {\n // A wait node must have a positive duration value if defined.\n if (definition.duration < 0) {\n throw new Error(\n `expected positive duration value for 'duration' property if defined for wait node at depth '${depth}'`\n );\n }\n } else {\n throw new Error(\n `expected integer value or array containing two integer values for 'duration' property if defined for wait node at depth '${depth}'`\n );\n }\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n}\n\n/**\n * Validate an object that we expect to be a sequence node definition.\n * @param definition An object that we expect to be a sequence node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateSequenceNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"sequence\") {\n throw new Error(`expected node type of 'sequence' for sequence node at depth '${depth}'`);\n }\n\n // A sequence node is a composite node, so must have a children nodes array defined.\n if (!Array.isArray(definition.children) || definition.children.length === 0) {\n throw new Error(`expected non-empty 'children' array to be defined for sequence node at depth '${depth}'`);\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n\n // Validate the child nodes of this composite node.\n definition.children.forEach((child: any) => validateNode(child, depth + 1));\n}\n\n/**\n * Validate an object that we expect to be a selector node definition.\n * @param definition An object that we expect to be a selector node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateSelectorNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"selector\") {\n throw new Error(`expected node type of 'selector' for selector node at depth '${depth}'`);\n }\n\n // A selector node is a composite node, so must have a children nodes array defined.\n if (!Array.isArray(definition.children) || definition.children.length === 0) {\n throw new Error(`expected non-empty 'children' array to be defined for selector node at depth '${depth}'`);\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n\n // Validate the child nodes of this composite node.\n definition.children.forEach((child: any) => validateNode(child, depth + 1));\n}\n\n/**\n * Validate an object that we expect to be a parallel node definition.\n * @param definition An object that we expect to be a parallel node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateParallelNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"parallel\") {\n throw new Error(`expected node type of 'parallel' for parallel node at depth '${depth}'`);\n }\n\n // A parallel node is a composite node, so must have a children nodes array defined.\n if (!Array.isArray(definition.children) || definition.children.length === 0) {\n throw new Error(`expected non-empty 'children' array to be defined for parallel node at depth '${depth}'`);\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n\n // Validate the child nodes of this composite node.\n definition.children.forEach((child: any) => validateNode(child, depth + 1));\n}\n\n/**\n * Validate an object that we expect to be a lotto node definition.\n * @param definition An object that we expect to be a lotto node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateLottoNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"lotto\") {\n throw new Error(`expected node type of 'lotto' for lotto node at depth '${depth}'`);\n }\n\n // A lotto node is a composite node, so must have a children nodes array defined.\n if (!Array.isArray(definition.children) || definition.children.length === 0) {\n throw new Error(`expected non-empty 'children' array to be defined for lotto node at depth '${depth}'`);\n }\n\n // Check whether a 'weights' property has been defined, if it has we expect it to be an array of weights.\n if (typeof definition.weights !== \"undefined\") {\n // Check that the weights property is an array of positive integers with an element for each child node element.\n if (\n !Array.isArray(definition.weights) ||\n definition.weights.length !== definition.children.length ||\n definition.weights.filter((value: unknown) => !isInteger(value)).length ||\n definition.weights.filter((value: number) => value < 0).length\n ) {\n throw new Error(\n `expected an array of positive integer weight values with a length matching the number of child nodes for 'weights' property if defined for lotto node at depth '${depth}'`\n );\n }\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n\n // Validate the child nodes of this composite node.\n definition.children.forEach((child: any) => validateNode(child, depth + 1));\n}\n\n/**\n * A helper function to create a failure validation result with the given error message.\n * @param errorMessage The validation failure error message.\n * @returns A failure validation result with the given error message.\n */\nfunction createValidationFailureResult(errorMessage: string): DefinitionValidationResult {\n return { succeeded: false, errorMessage };\n}\n", "import { ActionResult, Agent, GlobalFunction } from \"./Agent\";\nimport { RootNodeDefinition } from \"./BehaviourTreeDefinition\";\n\nexport type InvokerFunction = (args: any[]) => ActionResult;\n\n/**\n * A singleton used to store and lookup registered functions and subtrees.\n */\nexport default class Lookup {\n /**\n * The object holding any registered functions keyed on function name.\n */\n private static functionTable: { [key: string]: GlobalFunction } = {};\n /**\n * The object holding any registered subtree root node definitions keyed on tree name.\n */\n private static subtreeTable: { [key: string]: RootNodeDefinition } = {};\n\n /**\n * Gets the function with the specified name.\n * @param name The name of the function.\n * @returns The function with the specified name.\n */\n public static getFunc(name: string): GlobalFunction {\n return this.functionTable[name];\n }\n\n /**\n * Sets the function with the specified name for later lookup.\n * @param name The name of the function.\n * @param func The function.\n */\n public static setFunc(name: string, func: GlobalFunction): void {\n this.functionTable[name] = func;\n }\n\n /**\n * Gets the function invoker for the specified agent and function name.\n * If a function with the specified name exists on the agent object then it will\n * be returned, otherwise we will then check the registered functions for a match.\n * @param agent The agent instance that this behaviour tree is modelling behaviour for.\n * @param name The function name.\n * @returns The function invoker for the specified agent and function name.\n */\n static getFuncInvoker(agent: Agent, name: string): InvokerFunction | null {\n // Check whether the agent contains the specified function.\n const foundOnAgent = agent[name];\n if (foundOnAgent && typeof foundOnAgent === \"function\") {\n return (args: any[]): boolean | ActionResult => foundOnAgent.apply(agent, args);\n }\n\n // The agent does not contain the specified function but it may have been registered at some point.\n if (this.functionTable[name] && typeof this.functionTable[name] === \"function\") {\n return (args: any[]) => this.functionTable[name](agent, ...args.map((arg) => arg.value));\n }\n\n // We have no function to invoke.\n return null;\n }\n\n /**\n * Gets all registered subtree root node definitions.\n */\n static getSubtrees(): { [key: string]: RootNodeDefinition } {\n return this.subtreeTable;\n }\n\n /**\n * Sets the subtree with the specified name for later lookup.\n * @param name The name of the subtree.\n * @param subtree The subtree.\n */\n static setSubtree(name: string, subtree: RootNodeDefinition) {\n this.subtreeTable[name] = subtree;\n }\n\n /**\n * Removes the registered function or subtree with the specified name.\n * @param name The name of the registered function or subtree.\n */\n static remove(name: string) {\n delete this.functionTable[name];\n delete this.subtreeTable[name];\n }\n\n /**\n * Remove all registered functions and subtrees.\n */\n static empty() {\n this.functionTable = {};\n this.subtreeTable = {};\n }\n}\n", "import Node from \"../../nodes/Node\";\n\n/**\n * An exception thrown when evaluating node guard path conditions and a conditions fails.\n */\nexport default class GuardUnsatisifedException extends Error {\n /**\n * @param source The node at which a guard condition failed.\n */\n constructor(private source: Node) {\n super(\"A guard path condition has failed\");\n }\n\n /**\n * Gets whether the specified node is the node at which a guard condition failed.\n * @param node The node to check against the source node.\n * @returns Whether the specified node is the node at which a guard condition failed.\n */\n isSourceNode = (node: Node) => node === this.source;\n}\n", "import { Agent } from \"../../Agent\";\nimport Guard from \"./Guard\";\nimport Node from \"../../nodes/Node\";\nimport GuardUnsatisifedException from \"./GuardUnsatisifedException\";\n\nexport type GuardPathPart = {\n node: Node;\n guards: Guard[];\n};\n\n/**\n * Represents a path of node guards along a root-to-leaf tree path.\n */\nexport default class GuardPath {\n /**\n * @param nodes An array of objects defining a node instance -> guard link, ordered by node depth.\n */\n constructor(private nodes: GuardPathPart[]) {}\n\n /**\n * Evaluate guard conditions for all guards in the tree path, moving outwards from the root.\n * @param agent The agent, required for guard evaluation.\n * @returns An evaluation results object.\n */\n evaluate = (agent: Agent) => {\n // We need to evaluate guard conditions for nodes up the tree, moving outwards from the root.\n for (const details of this.nodes) {\n // There can be multiple guards per node.\n for (const guard of details.guards) {\n // Check whether the guard condition passes, and throw an exception if not.\n if (!guard.isSatisfied(agent)) {\n throw new GuardUnsatisifedException(details.node);\n }\n }\n }\n };\n}\n", "import { BehaviourTreeOptions } from \"../BehaviourTreeOptions\";\nimport State, { AnyState } from \"../State\";\nimport { Agent } from \"../Agent\";\nimport Leaf from \"./leaf/Leaf\";\nimport Attribute from \"../attributes/Attribute\";\nimport Entry from \"../attributes/callbacks/Entry\";\nimport Exit from \"../attributes/callbacks/Exit\";\nimport Step from \"../attributes/callbacks/Step\";\nimport Guard from \"../attributes/guards/Guard\";\nimport GuardPath from \"../attributes/guards/GuardPath\";\nimport GuardUnsatisifedException from \"../attributes/guards/GuardUnsatisifedException\";\n\n/**\n * A base node.\n */\nexport default abstract class Node {\n /**\n * The node uid.\n */\n private readonly uid: string = createNodeUid();\n /**\n * The node state.\n */\n private state: AnyState = State.READY;\n /**\n * The guard path to evaluate as part of a node update.\n */\n private guardPath: GuardPath | undefined;\n\n /**\n * @param type The node type.\n * @param attributes The node attributes.\n * @param args The node argument definitions.\n */\n constructor(private type: string, private attributes: Attribute[], private args: any[]) {}\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected abstract onUpdate(agent: Agent, options: BehaviourTreeOptions): void;\n\n /**\n * Gets the name of the node.\n */\n public abstract getName(): string;\n\n /**\n * Gets whether this node is a leaf node.\n */\n public abstract isLeafNode: () => this is Leaf;\n\n /**\n * Gets/Sets the state of the node.\n */\n getState = (): AnyState => this.state;\n setState = (value: AnyState): void => {\n this.state = value;\n };\n\n /**\n * Gets the unique id of the node.\n */\n getUid = () => this.uid;\n\n /**\n * Gets the type of the node.\n */\n getType = () => this.type;\n\n /**\n * Gets the node attributes.\n */\n getAttributes = () => this.attributes;\n\n /**\n * Gets the node arguments.\n */\n getArguments = () => this.args;\n\n /**\n * Gets the node attribute with the specified type, or null if it does not exist.\n */\n getAttribute(type: \"entry\" | \"ENTRY\"): Entry;\n getAttribute(type: \"exit\" | \"EXIT\"): Exit;\n getAttribute(type: \"step\" | \"STEP\"): Step;\n getAttribute(type: string): Attribute {\n return (\n this.getAttributes().filter((decorator) => decorator.type.toUpperCase() === type.toUpperCase())[0] || null\n );\n }\n\n /**\n * Gets the node attributes.\n */\n getGuardAttributes = (): Guard[] => this.getAttributes().filter((decorator) => decorator.isGuard()) as Guard[];\n\n /**\n * Sets the guard path to evaluate as part of a node update.\n */\n setGuardPath = (value: GuardPath) => (this.guardPath = value);\n\n /**\n * Gets whether a guard path is assigned to this node.\n */\n hasGuardPath = () => !!this.guardPath;\n\n /**\n * Gets whether this node is in the specified state.\n * @param value The value to compare to the node state.\n */\n public is(value: AnyState): boolean {\n return this.state === value;\n }\n\n /**\n * Reset the state of the node.\n */\n public reset(): void {\n this.setState(State.READY);\n }\n\n /**\n * Abort the running of this node.\n * @param agent The agent.\n */\n public abort(agent: Agent): void {\n // There is nothing to do if this node is not in the running state.\n if (!this.is(State.RUNNING)) {\n return;\n }\n\n // Reset the state of this node.\n this.reset();\n\n this.getAttribute(\"exit\")?.callAgentFunction(agent, false, true);\n }\n\n /**\n * Update the node.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n * @returns The result of the update.\n */\n public update(agent: Agent, options: BehaviourTreeOptions): void {\n // If this node is already in a 'SUCCEEDED' or 'FAILED' state then there is nothing to do.\n if (this.is(State.SUCCEEDED) || this.is(State.FAILED)) {\n return;\n }\n\n try {\n // Evaluate all of the guard path conditions for the current tree path.\n this.guardPath!.evaluate(agent);\n\n // If this node is in the READY state then call the ENTRY for this node if it exists.\n if (this.is(State.READY)) {\n this.getAttribute(\"entry\")?.callAgentFunction(agent);\n }\n\n this.getAttribute(\"step\")?.callAgentFunction(agent);\n\n // Do the actual update.\n this.onUpdate(agent, options);\n\n // If this node is now in a 'SUCCEEDED' or 'FAILED' state then call the EXIT for this node if it exists.\n if (this.is(State.SUCCEEDED) || this.is(State.FAILED)) {\n this.getAttribute(\"exit\")?.callAgentFunction(agent, this.is(State.SUCCEEDED), false);\n }\n } catch (error) {\n // If the error is a GuardUnsatisfiedException then we need to determine if this node is the source.\n if (error instanceof GuardUnsatisifedException && error.isSourceNode(this)) {\n // Abort the current node.\n this.abort(agent);\n\n // Any node that is the source of an abort will be a failed node.\n this.setState(State.FAILED);\n } else {\n throw error;\n }\n }\n }\n}\n\n/**\n * Create a randomly generated node uid.\n * @returns A randomly generated node uid.\n */\nfunction createNodeUid(): string {\n var S4 = function () {\n return (((1 + Math.random()) * 0x10000) | 0).toString(16).substring(1);\n };\n return S4() + S4() + \"-\" + S4() + \"-\" + S4() + \"-\" + S4() + \"-\" + S4() + S4() + S4();\n}\n", "import Node from \"../Node\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\n\n/**\n * A composite node that wraps child nodes.\n */\nexport default abstract class Composite extends Node {\n /**\n * @param type The node type.\n * @param attributes The node attributes.\n * @param children The child nodes.\n */\n constructor(type: string, attributes: Attribute[], protected children: Node[]) {\n super(type, attributes, []);\n }\n\n /**\n * Gets whether this node is a leaf node.\n */\n isLeafNode = () => false;\n\n /**\n * Gets the children of this node.\n */\n getChildren = () => this.children;\n\n /**\n * Reset the state of the node.\n */\n reset = () => {\n // Reset the state of this node.\n this.setState(State.READY);\n\n // Reset the state of any child nodes.\n this.getChildren().forEach((child) => child.reset());\n };\n\n /**\n * Abort the running of this node.\n * @param agent The agent.\n */\n abort = (agent: Agent) => {\n // There is nothing to do if this node is not in the running state.\n if (!this.is(State.RUNNING)) {\n return;\n }\n\n // Abort any child nodes.\n this.getChildren().forEach((child) => child.abort(agent));\n\n // Reset the state of this node.\n this.reset();\n\n this.getAttribute(\"exit\")?.callAgentFunction(agent, false, true);\n };\n}\n", "import Composite from \"./Composite\";\nimport State from \"../../State\";\nimport Node from \"../Node\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A PARALLEL node.\n * The child nodes are executed concurrently until one fails or all succeed.\n */\nexport default class Parallel extends Composite {\n /**\n * @param attributes The node attributes.\n * @param children The child nodes.\n */\n constructor(attributes: Attribute[], children: Node[]) {\n super(\"parallel\", attributes, children);\n }\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // Keep a count of the number of succeeded child nodes.\n let succeededCount = 0;\n\n let hasChildFailed = false;\n\n // Iterate over all of the children of this node.\n for (const child of this.children) {\n // If the child has never been updated or is running then we will need to update it now.\n if (child.getState() === State.READY || child.getState() === State.RUNNING) {\n // Update the child of this node.\n child.update(agent, options);\n }\n\n // If the current child has a state of 'SUCCEEDED' then we should move on to the next child.\n if (child.getState() === State.SUCCEEDED) {\n // The child node has succeeded, keep track of this to determine if all children have.\n succeededCount++;\n\n // The child node succeeded, but we have not finished checking every child node yet.\n continue;\n }\n\n // If the current child has a state of 'FAILED' then this node is also a 'FAILED' node.\n if (child.getState() === State.FAILED) {\n hasChildFailed = true;\n\n // There is no need to check the rest of the children.\n break;\n }\n\n // The node should be in the 'RUNNING' state.\n if (child.getState() !== State.RUNNING) {\n // The child node was not in an expected state.\n throw new Error(\"child node was not in an expected state.\");\n }\n }\n\n if (hasChildFailed) {\n // This node is a 'FAILED' node.\n this.setState(State.FAILED);\n\n // Abort every running child.\n for (const child of this.children) {\n if (child.getState() === State.RUNNING) {\n child.abort(agent);\n }\n }\n } else {\n // If all children have succeeded then this node has also succeeded, otherwise it is still running.\n this.setState(succeededCount === this.children.length ? State.SUCCEEDED : State.RUNNING);\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => \"PARALLEL\";\n}\n", "import Composite from \"./Composite\";\nimport Node from \"../Node\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A SELECTOR node.\n * The child nodes are executed in sequence until one succeeds or all fail.\n */\nexport default class Selector extends Composite {\n /**\n * @param attributes The node attributes.\n * @param children The child nodes.\n */\n constructor(attributes: Attribute[], protected children: Node[]) {\n super(\"selector\", attributes, children);\n }\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // Iterate over all of the children of this node.\n for (const child of this.children) {\n // If the child has never been updated or is running then we will need to update it now.\n if (child.getState() === State.READY || child.getState() === State.RUNNING) {\n // Update the child of this node.\n child.update(agent, options);\n }\n\n // If the current child has a state of 'SUCCEEDED' then this node is also a 'SUCCEEDED' node.\n if (child.getState() === State.SUCCEEDED) {\n // This node is a 'SUCCEEDED' node.\n this.setState(State.SUCCEEDED);\n\n // There is no need to check the rest of the selector nodes.\n return;\n }\n\n // If the current child has a state of 'FAILED' then we should move on to the next child.\n if (child.getState() === State.FAILED) {\n // Find out if the current child is the last one in the selector.\n // If it is then this sequence node has also failed.\n if (this.children.indexOf(child) === this.children.length - 1) {\n // This node is a 'FAILED' node.\n this.setState(State.FAILED);\n\n // There is no need to check the rest of the selector as we have completed it.\n return;\n } else {\n // The child node failed, try the next one.\n continue;\n }\n }\n\n // The node should be in the 'RUNNING' state.\n if (child.getState() === State.RUNNING) {\n // This node is a 'RUNNING' node.\n this.setState(State.RUNNING);\n\n // There is no need to check the rest of the selector as the current child is still running.\n return;\n }\n\n // The child node was not in an expected state.\n throw new Error(\"child node was not in an expected state.\");\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => \"SELECTOR\";\n}\n", "import Composite from \"./Composite\";\nimport Node from \"../Node\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A SEQUENCE node.\n * The child nodes are executed in sequence until one fails or all succeed.\n */\nexport default class Sequence extends Composite {\n /**\n * @param attributes The node attributes.\n * @param children The child nodes.\n */\n constructor(attributes: Attribute[], protected children: Node[]) {\n super(\"sequence\", attributes, children);\n }\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // Iterate over all of the children of this node.\n for (const child of this.children) {\n // If the child has never been updated or is running then we will need to update it now.\n if (child.getState() === State.READY || child.getState() === State.RUNNING) {\n // Update the child of this node.\n child.update(agent, options);\n }\n\n // If the current child has a state of 'SUCCEEDED' then we should move on to the next child.\n if (child.getState() === State.SUCCEEDED) {\n // Find out if the current child is the last one in the sequence.\n // If it is then this sequence node has also succeeded.\n if (this.children.indexOf(child) === this.children.length - 1) {\n // This node is a 'SUCCEEDED' node.\n this.setState(State.SUCCEEDED);\n\n // There is no need to check the rest of the sequence as we have completed it.\n return;\n } else {\n // The child node succeeded, but we have not finished the sequence yet.\n continue;\n }\n }\n\n // If the current child has a state of 'FAILED' then this node is also a 'FAILED' node.\n if (child.getState() === State.FAILED) {\n // This node is a 'FAILED' node.\n this.setState(State.FAILED);\n\n // There is no need to check the rest of the sequence.\n return;\n }\n\n // The node should be in the 'RUNNING' state.\n if (child.getState() === State.RUNNING) {\n // This node is a 'RUNNING' node.\n this.setState(State.RUNNING);\n\n // There is no need to check the rest of the sequence as the current child is still running.\n return;\n }\n\n // The child node was not in an expected state.\n throw new Error(\"child node was not in an expected state.\");\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => \"SEQUENCE\";\n}\n", "import createLotto from \"lotto-draw\";\n\nimport Node from \"../Node\";\nimport Composite from \"./Composite\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A LOTTO node.\n * A winning child is picked on the initial update of this node, based on ticket weighting.\n * The state of this node will match the state of the winning child.\n */\nexport default class Lotto extends Composite {\n /**\n * @param attributes The node attributes.\n * @param weights The child node weights.\n * @param children The child nodes.\n */\n constructor(attributes: Attribute[], private weights: number[] | undefined, children: Node[]) {\n super(\"lotto\", attributes, children);\n }\n\n /**\n * The child node selected to be the active one.\n */\n private selectedChild: Node | undefined;\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // If this node is in the READY state then we need to pick a winning child node.\n if (this.is(State.READY)) {\n // Create a lotto draw with which to randomly pick a child node to become the active one.\n const lottoDraw = createLotto({\n // Hook up the optional 'random' behaviour tree function option to the one used by 'lotto-draw'.\n random: options.random,\n // Pass in each child node as a participant in the lotto draw with their respective ticket count.\n participants: this.children.map((child, index) => [child, this.weights?.[index] || 1])\n });\n\n // Randomly pick a child based on ticket weighting, this will become the active child for this composite node.\n this.selectedChild = lottoDraw.draw() || undefined;\n }\n\n // If something went wrong and we don't have an active child then we should throw an error.\n if (!this.selectedChild) {\n throw new Error(\"failed to update lotto node as it has no active child\");\n }\n\n // If the selected child has never been updated or is running then we will need to update it now.\n if (this.selectedChild.getState() === State.READY || this.selectedChild.getState() === State.RUNNING) {\n this.selectedChild.update(agent, options);\n }\n\n // The state of the lotto node is the state of its selected child.\n this.setState(this.selectedChild.getState());\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => (this.weights ? `LOTTO [${this.weights.join(\",\")}]` : \"LOTTO\");\n}\n", "import Node from \"../Node\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\n\n/**\n * A decorator node that wraps a single child node.\n */\nexport default abstract class Decorator extends Node {\n /**\n * @param type The node type.\n * @param attributes The node attributes.\n * @param child The child node.\n */\n constructor(type: string, attributes: Attribute[], protected child: Node) {\n super(type, attributes, []);\n }\n\n /**\n * Gets whether this node is a leaf node.\n */\n isLeafNode = () => false;\n\n /**\n * Gets the children of this node.\n */\n getChildren = () => [this.child];\n\n /**\n * Reset the state of the node.\n */\n reset = () => {\n // Reset the state of this node.\n this.setState(State.READY);\n\n // Reset the state of the child node.\n this.child.reset();\n };\n\n /**\n * Abort the running of this node.\n * @param agent The agent.\n */\n abort = (agent: Agent) => {\n // There is nothing to do if this node is not in the running state.\n if (!this.is(State.RUNNING)) {\n return;\n }\n\n // Abort the child node.\n this.child.abort(agent);\n\n // Reset the state of this node.\n this.reset();\n\n this.getAttribute(\"exit\")?.callAgentFunction(agent, false, true);\n };\n}\n", "import Node from \"../Node\";\nimport Decorator from \"./Decorator\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A Fail node.\n * This node wraps a single child and will always move to the 'FAILED' state when the child moves to a 'SUCCEEDED' or 'FAILED' state.\n */\nexport default class Fail extends Decorator {\n /**\n * @param attributes The node attributes.\n * @param child The child node.\n */\n constructor(attributes: Attribute[], child: Node) {\n super(\"fail\", attributes, child);\n }\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // If the child has never been updated or is running then we will need to update it now.\n if (this.child.getState() === State.READY || this.child.getState() === State.RUNNING) {\n this.child.update(agent, options);\n }\n\n // The state of this node will depend in the state of its child.\n switch (this.child.getState()) {\n case State.RUNNING:\n this.setState(State.RUNNING);\n break;\n\n case State.SUCCEEDED:\n case State.FAILED:\n this.setState(State.FAILED);\n break;\n\n default:\n this.setState(State.READY);\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => \"FAIL\";\n}\n", "import Decorator from \"./Decorator\";\nimport State from \"../../State\";\nimport Node from \"../Node\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A Flip node.\n * This node wraps a single child and will flip the state of the child state.\n */\nexport default class Flip extends Decorator {\n /**\n * @param attributes The node attributes.\n * @param child The child node.\n */\n constructor(attributes: Attribute[], child: Node) {\n super(\"flip\", attributes, child);\n }\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // If the child has never been updated or is running then we will need to update it now.\n if (this.child.getState() === State.READY || this.child.getState() === State.RUNNING) {\n this.child.update(agent, options);\n }\n\n // The state of this node will depend in the state of its child.\n switch (this.child.getState()) {\n case State.RUNNING:\n this.setState(State.RUNNING);\n break;\n\n case State.SUCCEEDED:\n this.setState(State.FAILED);\n break;\n\n case State.FAILED:\n this.setState(State.SUCCEEDED);\n break;\n\n default:\n this.setState(State.READY);\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => \"FLIP\";\n}\n", "import Node from \"../Node\";\nimport Decorator from \"./Decorator\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A REPEAT node.\n * The node has a single child which can have:\n * -- A number of iterations for which to repeat the child node.\n * -- An infinite repeat loop if neither an iteration count or a condition function is defined.\n * The REPEAT node will stop and have a 'FAILED' state if its child is ever in a 'FAILED' state after an update.\n * The REPEAT node will attempt to move on to the next iteration if its child is ever in a 'SUCCEEDED' state.\n */\nexport default class Repeat extends Decorator {\n /**\n * @param attributes The node attributes.\n * @param iterations The number of iterations to repeat the child node.\n * @param iterationsMin The minimum possible number of iterations to repeat the child node.\n * @param iterationsMax The maximum possible number of iterations to repeat the child node.\n * @param child The child node.\n */\n constructor(\n attributes: Attribute[],\n private iterations: number | null,\n private iterationsMin: number | null,\n private iterationsMax: number | null,\n child: Node\n ) {\n super(\"repeat\", attributes, child);\n }\n\n /**\n * The number of target iterations to make.\n */\n private targetIterationCount: number | null = null;\n\n /**\n * The current iteration count.\n */\n private currentIterationCount: number = 0;\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // If this node is in the READY state then we need to reset the child and the target iteration count.\n if (this.is(State.READY)) {\n // Reset the child node.\n this.child.reset();\n\n // Reset the current iteration count.\n this.currentIterationCount = 0;\n\n // Set the target iteration count.\n this.setTargetIterationCount(options);\n }\n\n // Do a check to see if we can iterate. If we can then this node will move into the 'RUNNING' state.\n // If we cannot iterate then we have hit our target iteration count, which means that the node has succeeded.\n if (this.canIterate()) {\n // This node is in the running state and can do its initial iteration.\n this.setState(State.RUNNING);\n\n // We may have already completed an iteration, meaning that the child node will be in the SUCCEEDED state.\n // If this is the case then we will have to reset the child node now.\n if (this.child.getState() === State.SUCCEEDED) {\n this.child.reset();\n }\n\n // Update the child of this node.\n this.child.update(agent, options);\n\n // If the child moved into the FAILED state when we updated it then there is nothing left to do and this node has also failed.\n // If it has moved into the SUCCEEDED state then we have completed the current iteration.\n if (this.child.getState() === State.FAILED) {\n // The child has failed, meaning that this node has failed.\n this.setState(State.FAILED);\n\n return;\n } else if (this.child.getState() === State.SUCCEEDED) {\n // We have completed an iteration.\n this.currentIterationCount += 1;\n }\n } else {\n // This node is in the 'SUCCEEDED' state as we cannot iterate any more.\n this.setState(State.SUCCEEDED);\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => {\n if (this.iterations !== null) {\n return `REPEAT ${this.iterations}x`;\n } else if (this.iterationsMin !== null && this.iterationsMax !== null) {\n return `REPEAT ${this.iterationsMin}x-${this.iterationsMax}x`;\n } else {\n return \"REPEAT\";\n }\n };\n\n /**\n * Reset the state of the node.\n */\n reset = () => {\n // Reset the state of this node.\n this.setState(State.READY);\n\n // Reset the current iteration count.\n this.currentIterationCount = 0;\n\n // Reset the child node.\n this.child.reset();\n };\n\n /**\n * Gets whether an iteration can be made.\n * @returns Whether an iteration can be made.\n */\n private canIterate = () => {\n if (this.targetIterationCount !== null) {\n // We can iterate as long as we have not reached our target iteration count.\n return this.currentIterationCount < this.targetIterationCount;\n }\n\n // If neither an iteration count or a condition function were defined then we can iterate indefinitely.\n return true;\n };\n\n /**\n * Sets the target iteration count.\n * @param options The behaviour tree options object.\n */\n private setTargetIterationCount = (options: BehaviourTreeOptions) => {\n // Are we dealing with an explicit iteration count or will we be randomly picking a iteration count between the min and max iteration count.\n if (this.iterations !== null) {\n this.targetIterationCount = this.iterations;\n } else if (this.iterationsMin !== null && this.iterationsMax !== null) {\n // We will be picking a random iteration count between a min and max iteration count, if the optional 'random'\n // behaviour tree function option is defined then we will be using that, otherwise we will fall back to using Math.random.\n const random = typeof options.random === \"function\" ? options.random : Math.random;\n\n // Pick a random iteration count between a min and max iteration count.\n this.targetIterationCount = Math.floor(\n random() * (this.iterationsMax - this.iterationsMin + 1) + this.iterationsMin\n );\n } else {\n this.targetIterationCount = null;\n }\n };\n}\n", "import Node from \"../Node\";\nimport Decorator from \"./Decorator\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A RETRY node.\n * The node has a single child which can have:\n * -- A number of iterations for which to repeat the child node.\n * -- An infinite repeat loop if neither an iteration count or a condition function is defined.\n * The RETRY node will stop and have a 'SUCCEEDED' state if its child is ever in a 'SUCCEEDED' state after an update.\n * The RETRY node will attempt to move on to the next iteration if its child is ever in a 'FAILED' state.\n */\nexport default class Retry extends Decorator {\n /**\n * @param attributes The node attributes.\n * @param attempts The number of attempts to retry the child node.\n * @param attemptsMin The minimum possible number of attempts to retry the child node.\n * @param attemptsMax The maximum possible number of attempts to retry the child node.\n * @param child The child node.\n */\n constructor(\n attributes: Attribute[],\n private attempts: number | null,\n private attemptsMin: number | null,\n private attemptsMax: number | null,\n child: Node\n ) {\n super(\"retry\", attributes, child);\n }\n\n /**\n * The number of target attempts to make.\n */\n private targetAttemptCount: number | null = null;\n\n /**\n * The current attempt count.\n */\n private currentAttemptCount: number = 0;\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // If this node is in the READY state then we need to reset the child and the target attempt count.\n if (this.is(State.READY)) {\n // Reset the child node.\n this.child.reset();\n\n // Reset the current attempt count.\n this.currentAttemptCount = 0;\n\n // Set the target attempt count.\n this.setTargetAttemptCount(options);\n }\n\n // Do a check to see if we can attempt. If we can then this node will move into the 'RUNNING' state.\n // If we cannot attempt then we have hit our target attempt count, which means that the node has succeeded.\n if (this.canAttempt()) {\n // This node is in the running state and can do its initial attempt.\n this.setState(State.RUNNING);\n\n // We may have already completed an attempt, meaning that the child node will be in the FAILED state.\n // If this is the case then we will have to reset the child node now.\n if (this.child.getState() === State.FAILED) {\n this.child.reset();\n }\n\n // Update the child of this node.\n this.child.update(agent, options);\n\n // If the child moved into the SUCCEEDED state when we updated it then there is nothing left to do and this node has also succeeded.\n // If it has moved into the FAILED state then we have completed the current attempt.\n if (this.child.getState() === State.SUCCEEDED) {\n // The child has succeeded, meaning that this node has succeeded.\n this.setState(State.SUCCEEDED);\n\n return;\n } else if (this.child.getState() === State.FAILED) {\n // We have completed an attempt.\n this.currentAttemptCount += 1;\n }\n } else {\n // This node is in the 'FAILED' state as we cannot iterate any more.\n this.setState(State.FAILED);\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => {\n if (this.attempts !== null) {\n return `RETRY ${this.attempts}x`;\n } else if (this.attemptsMin !== null && this.attemptsMax !== null) {\n return `RETRY ${this.attemptsMin}x-${this.attemptsMax}x`;\n } else {\n return \"RETRY\";\n }\n };\n\n /**\n * Reset the state of the node.\n */\n reset = () => {\n // Reset the state of this node.\n this.setState(State.READY);\n\n // Reset the current attempt count.\n this.currentAttemptCount = 0;\n\n // Reset the child node.\n this.child.reset();\n };\n\n /**\n * Gets whether an attempt can be made.\n * @returns Whether an attempt can be made.\n */\n canAttempt = () => {\n if (this.targetAttemptCount !== null) {\n // We can attempt as long as we have not reached our target attempt count.\n return this.currentAttemptCount < this.targetAttemptCount;\n }\n\n // If neither an attempt count or a condition function were defined then we can attempt indefinitely.\n return true;\n };\n\n /**\n * Sets the target attempt count.\n * @param options The behaviour tree options object.\n */\n setTargetAttemptCount = (options: BehaviourTreeOptions) => {\n // Are we dealing with an explicit attempt count or will we be randomly picking an attempt count between the min and max attempt count.\n if (this.attempts !== null) {\n this.targetAttemptCount = this.attempts;\n } else if (this.attemptsMin !== null && this.attemptsMax !== null) {\n // We will be picking a random attempt count between a min and max attempt count, if the optional 'random'\n // behaviour tree function option is defined then we will be using that, otherwise we will fall back to using Math.random.\n const random = typeof options.random === \"function\" ? options.random : Math.random;\n\n // Pick a random attempt count between a min and max attempt count.\n this.targetAttemptCount = Math.floor(\n random() * (this.attemptsMax - this.attemptsMin + 1) + this.attemptsMin\n );\n } else {\n this.targetAttemptCount = null;\n }\n };\n}\n", "import Node from \"../Node\";\nimport Decorator from \"./Decorator\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A Root node.\n * The root node will have a single child.\n */\nexport default class Root extends Decorator {\n /**\n * @param attributes The node attributes.\n * @param child The child node.\n */\n constructor(attributes: Attribute[], child: Node) {\n super(\"root\", attributes, child);\n }\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // If the child has never been updated or is running then we will need to update it now.\n if (this.child.getState() === State.READY || this.child.getState() === State.RUNNING) {\n // Update the child of this node.\n this.child.update(agent, options);\n }\n\n // The state of the root node is the state of its child.\n this.setState(this.child.getState());\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => \"ROOT\";\n}\n", "import Node from \"../Node\";\nimport Decorator from \"./Decorator\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A Succeed node.\n * This node wraps a single child and will always move to the 'SUCCEEDED' state when the child moves to a 'SUCCEEDED' or 'FAILED' state.\n */\nexport default class Succeed extends Decorator {\n /**\n * @param attributes The node attributes.\n * @param child The child node.\n */\n constructor(attributes: Attribute[], child: Node) {\n super(\"succeed\", attributes, child);\n }\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // If the child has never been updated or is running then we will need to update it now.\n if (this.child.getState() === State.READY || this.child.getState() === State.RUNNING) {\n this.child.update(agent, options);\n }\n\n // The state of this node will depend in the state of its child.\n switch (this.child.getState()) {\n case State.RUNNING:\n this.setState(State.RUNNING);\n break;\n\n case State.SUCCEEDED:\n case State.FAILED:\n this.setState(State.SUCCEEDED);\n break;\n\n default:\n this.setState(State.READY);\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => \"SUCCEED\";\n}\n", "import Node from \"../Node\";\n\n/**\n * A leaf node.\n */\nexport default abstract class Leaf extends Node {\n /**\n * Gets whether this node is a leaf node.\n */\n isLeafNode = () => true;\n}\n", "import { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\nimport State, { CompleteState } from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Leaf from \"./Leaf\";\nimport Lookup from \"../../Lookup\";\nimport Attribute from \"../../attributes/Attribute\";\n\n/**\n * An Action leaf node.\n * This represents an immediate or ongoing state of behaviour.\n */\nexport default class Action extends Leaf {\n /**\n * @param attributes The node attributes.\n * @param actionName The action name.\n * @param actionArguments The array of action argument definitions.\n */\n constructor(attributes: Attribute[], private actionName: string, private actionArguments: any[]) {\n super(\"action\", attributes, actionArguments);\n }\n\n /**\n * Whether there is a pending update promise.\n */\n private isUsingUpdatePromise = false;\n\n /**\n * The finished state result of an update promise.\n */\n private updatePromiseStateResult: CompleteState | null = null;\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // If the result of this action depends on an update promise then there is nothing to do until\n // it resolves, unless there has been a value set as a result of the update promise resolving.\n if (this.isUsingUpdatePromise) {\n // Check whether the update promise has resolved with a state value.\n if (this.updatePromiseStateResult) {\n // Set the state of this node to match the state returned by the promise.\n this.setState(this.updatePromiseStateResult);\n }\n\n return;\n }\n\n // Attempt to get the invoker for the action function.\n const actionFuncInvoker = Lookup.getFuncInvoker(agent, this.actionName);\n\n // The action function should be defined.\n if (actionFuncInvoker === null) {\n throw new Error(\n `cannot update action node as the action '${this.actionName}' function is not defined on the agent and has not been registered`\n );\n }\n\n let actionFunctionResult;\n\n try {\n // Call the action function, the result of which may be:\n // - The finished state of this action node.\n // - A promise to return a finished node state.\n // - Undefined if the node should remain in the running state.\n actionFunctionResult = actionFuncInvoker(this.actionArguments) as CompleteState | Promise;\n } catch (error) {\n // The user was naughty and threw something.\n throw new Error(`action function '${this.actionName}' threw '${error}'`);\n }\n\n if (actionFunctionResult instanceof Promise) {\n actionFunctionResult.then(\n (result) => {\n // If 'isUpdatePromisePending' is null then the promise was cleared as it was resolving, probably via an abort of reset.\n if (!this.isUsingUpdatePromise) {\n return;\n }\n\n // Check to make sure the result is a valid finished state.\n if (result !== State.SUCCEEDED && result !== State.FAILED) {\n throw new Error(\n \"action node promise resolved with an invalid value, expected a State.SUCCEEDED or State.FAILED value to be returned\"\n );\n }\n\n // Set pending update promise state result to be processed on next update.\n this.updatePromiseStateResult = result;\n },\n (reason) => {\n // If 'isUpdatePromisePending' is null then the promise was cleared as it was resolving, probably via an abort or reset.\n if (!this.isUsingUpdatePromise) {\n return;\n }\n\n // TODO We shouldn't throw an error here, we actually need to set this.updatePromiseRejectionReason so that it can be thrown on the next tree.step() call.\n\n // The promise was rejected, which isn't great.\n throw new Error(`action function '${this.actionName}' promise rejected with reason '${reason}'`);\n }\n );\n\n // This node will be in the 'RUNNING' state until the update promise resolves.\n this.setState(State.RUNNING);\n\n // We are now waiting for the promise returned by the use to resolve before we know what state this node is in.\n this.isUsingUpdatePromise = true;\n } else {\n // Validate the returned value.\n this.validateUpdateResult(actionFunctionResult);\n\n // Set the state of this node, this may be undefined, which just means that the node is still in the 'RUNNING' state.\n this.setState(actionFunctionResult || State.RUNNING);\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => this.actionName;\n\n /**\n * Reset the state of the node.\n */\n reset = () => {\n // Reset the state of this node.\n this.setState(State.READY);\n\n // There is no longer an update promise that we care about.\n this.isUsingUpdatePromise = false;\n this.updatePromiseStateResult = null;\n };\n\n /**\n * Validate the result of an update function call.\n * @param result The result of an update function call.\n */\n private validateUpdateResult = (result: CompleteState | boolean) => {\n switch (result) {\n case State.SUCCEEDED:\n case State.FAILED:\n case undefined:\n return;\n default:\n throw new Error(\n `action '${this.actionName}' 'onUpdate' returned an invalid response, expected an optional State.SUCCEEDED or State.FAILED value to be returned`\n );\n }\n };\n}\n", "import { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Leaf from \"./Leaf\";\nimport Lookup from \"../../Lookup\";\nimport Attribute from \"../../attributes/Attribute\";\n\n/**\n * A Condition leaf node.\n * This will succeed or fail immediately based on an agent predicate, without moving to the 'RUNNING' state.\n */\nexport default class Condition extends Leaf {\n /**\n * @param attributes The node attributes.\n * @param conditionName The name of the condition function.\n * @param conditionArguments The array of condition argument definitions.\n */\n constructor(attributes: Attribute[], private conditionName: string, private conditionArguments: any[]) {\n super(\"condition\", attributes, conditionArguments);\n }\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // Attempt to get the invoker for the condition function.\n const conditionFuncInvoker = Lookup.getFuncInvoker(agent, this.conditionName);\n\n // The condition function should be defined.\n if (conditionFuncInvoker === null) {\n throw new Error(\n `cannot update condition node as the condition '${this.conditionName}' function is not defined on the agent and has not been registered`\n );\n }\n\n let conditionFunctionResult;\n\n try {\n // Call the condition function to determine the state of this node, the result of which should be a boolean.\n conditionFunctionResult = conditionFuncInvoker(this.conditionArguments);\n } catch (error) {\n // The user was naughty and threw something.\n throw new Error(`condition function '${this.conditionName}' threw '${error}'`);\n }\n\n // The result of calling the condition function must be a boolean value.\n if (typeof conditionFunctionResult !== \"boolean\") {\n throw new Error(\n `expected condition function '${this.conditionName}' to return a boolean but returned '${conditionFunctionResult}'`\n );\n }\n\n // Set the state of this node based on the result of calling the condition function.\n this.setState(!!conditionFunctionResult ? State.SUCCEEDED : State.FAILED);\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => this.conditionName;\n}\n", "import Leaf from \"./Leaf\";\nimport State from \"../../State\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { Agent } from \"../../Agent\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A WAIT node.\n * The state of this node will change to SUCCEEDED after a duration of time\n */\nexport default class Wait extends Leaf {\n /**\n * @param attributes The node attributes.\n * @param duration The duration that this node will wait to succeed in milliseconds.\n * @param durationMin The minimum possible duration in milliseconds that this node will wait to succeed.\n * @param durationMax The maximum possible duration in milliseconds that this node will wait to succeed.\n */\n constructor(\n attributes: Attribute[],\n private duration: number | null,\n private durationMin: number | null,\n private durationMax: number | null\n ) {\n super(\"wait\", attributes, []);\n }\n\n /**\n * The time in milliseconds at which this node was first updated.\n */\n private initialUpdateTime: number = 0;\n\n /**\n * The total duration in milliseconds that this node will be waiting for.\n */\n private totalDuration: number | null = null;\n\n /**\n * The duration in milliseconds that this node has been waiting for.\n */\n private waitedDuration: number = 0;\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // If this node is in the READY state then we need to set the initial update time.\n if (this.is(State.READY)) {\n // Set the initial update time.\n this.initialUpdateTime = new Date().getTime();\n\n // Set the initial waited duration.\n this.waitedDuration = 0;\n\n // Are we dealing with an explicit duration or will we be randomly picking a duration between the min and max duration.\n if (this.duration !== null) {\n this.totalDuration = this.duration;\n } else if (this.durationMin !== null && this.durationMax !== null) {\n // We will be picking a random duration between a min and max duration, if the optional 'random' behaviour tree\n // function option is defined then we will be using that, otherwise we will fall back to using Math.random.\n const random = typeof options.random === \"function\" ? options.random : Math.random;\n\n // Pick a random duration between a min and max duration.\n this.totalDuration = Math.floor(\n random() * (this.durationMax - this.durationMin + 1) + this.durationMin\n );\n } else {\n this.totalDuration = null;\n }\n\n // The node is now running until we finish waiting.\n this.setState(State.RUNNING);\n }\n\n // If we have no total duration then this wait node will wait indefinitely until it is aborted.\n if (this.totalDuration === null) {\n return;\n }\n\n // If we have a 'getDeltaTime' function defined as part of our options then we will use it to figure out how long we have waited for.\n if (typeof options.getDeltaTime === \"function\") {\n // Get the delta time.\n const deltaTime = options.getDeltaTime();\n\n // Our delta time must be a valid number and cannot be NaN.\n if (typeof deltaTime !== \"number\" || isNaN(deltaTime)) {\n throw new Error(\"The delta time must be a valid number and not NaN.\");\n }\n\n // Update the amount of time that this node has been waiting for based on the delta time.\n this.waitedDuration += deltaTime * 1000;\n } else {\n // We are not using a delta time, so we will just work out hom much time has passed since the first update.\n this.waitedDuration = new Date().getTime() - this.initialUpdateTime;\n }\n\n // Have we waited long enough?\n if (this.waitedDuration >= this.totalDuration) {\n // We have finished waiting!\n this.setState(State.SUCCEEDED);\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => {\n if (this.duration !== null) {\n return `WAIT ${this.duration}ms`;\n } else if (this.durationMin !== null && this.durationMax !== null) {\n return `WAIT ${this.durationMin}ms-${this.durationMax}ms`;\n } else {\n return \"WAIT\";\n }\n };\n}\n", "import Guard from \"./guards/Guard\";\n\nexport type AttributeDetails = {\n /** The attribute type. */\n type: string;\n\n /** The attribute arguments. */\n args: any[];\n};\n\n/**\n * A base node attribute.\n */\nexport default abstract class Attribute {\n /**\n * @param type The node attribute type.\n * @param args The array of attribute arguments.\n */\n constructor(public type: string, public args: any[]) {}\n\n /**\n * Gets the attribute details.\n */\n abstract getDetails(): TAttributeDetails;\n\n /**\n * Gets whether this attribute is a guard.\n */\n abstract isGuard: () => this is Guard;\n}\n", "import { Agent } from \"../../Agent\";\nimport Attribute, { AttributeDetails } from \"../Attribute\";\n\nexport type GuardAttributeDetails = {\n /** The name of the condition function that determines whether the guard is satisfied. */\n condition: string;\n} & AttributeDetails;\n\n/**\n * A base node guard attribute.\n */\nexport default abstract class Guard extends Attribute {\n /**\n * @param type The node attribute type.\n * @param args The array of decorator argument definitions.\n * @param condition The name of the condition function that determines whether the guard is satisfied.\n */\n constructor(type: string, args: any[], private condition: string) {\n super(type, args);\n }\n\n /**\n * Gets the name of the condition function that determines whether the guard is satisfied.\n */\n getCondition = () => this.condition;\n\n /**\n * Gets whether this attribute is a guard.\n */\n isGuard = () => true;\n\n /**\n * Gets the attribute details.\n */\n getDetails(): GuardAttributeDetails {\n return {\n type: this.type,\n args: this.args,\n condition: this.getCondition()\n };\n }\n\n /**\n * Gets whether the guard is satisfied.\n * @param agent The agent.\n * @returns Whether the guard is satisfied.\n */\n abstract isSatisfied(agent: Agent): boolean;\n}\n", "import Guard from \"./Guard\";\nimport Lookup from \"../../Lookup\";\nimport { Agent } from \"../../Agent\";\n\n/**\n * A WHILE guard which is satisfied as long as the given condition remains true.\n */\nexport default class While extends Guard {\n /**\n * @param condition The name of the condition function that determines whether the guard is satisfied.\n * @param args The array of decorator argument definitions.\n */\n constructor(condition: string, args: any[]) {\n super(\"while\", args, condition);\n }\n\n /**\n * Gets whether the guard is satisfied.\n * @param agent The agent.\n * @returns Whether the guard is satisfied.\n */\n isSatisfied = (agent: Agent) => {\n // Attempt to get the invoker for the condition function.\n const conditionFuncInvoker = Lookup.getFuncInvoker(agent, this.getCondition());\n\n // The condition function should be defined.\n if (conditionFuncInvoker === null) {\n throw new Error(\n `cannot evaluate node guard as the condition '${this.getCondition()}' function is not defined on the agent and has not been registered`\n );\n }\n\n // Call the condition function to determine whether this guard is satisfied.\n return !!conditionFuncInvoker(this.args);\n };\n}\n", "import Guard from \"./Guard\";\nimport Lookup from \"../../Lookup\";\nimport { Agent } from \"../../Agent\";\n\n/**\n * An UNTIL guard which is satisfied as long as the given condition remains false.\n */\nexport default class Until extends Guard {\n /**\n * @param condition The name of the condition function that determines whether the guard is satisfied.\n * @param args The array of decorator argument definitions.\n */\n constructor(condition: string, args: any[]) {\n super(\"until\", args, condition);\n }\n\n /**\n * Gets whether the guard is satisfied.\n * @param agent The agent.\n * @returns Whether the guard is satisfied.\n */\n isSatisfied = (agent: Agent) => {\n // Attempt to get the invoker for the condition function.\n const conditionFuncInvoker = Lookup.getFuncInvoker(agent, this.getCondition());\n\n // The condition function should be defined.\n if (conditionFuncInvoker === null) {\n throw new Error(\n `cannot evaluate node guard as the condition '${this.getCondition()}' function is not defined on the agent and has not been registered`\n );\n }\n\n // Call the condition function to determine whether this guard is satisfied.\n return !!!conditionFuncInvoker(this.args);\n };\n}\n", "import { Agent } from \"../../Agent\";\nimport Attribute, { AttributeDetails } from \"../Attribute\";\n\nexport type CallbackAttributeDetails = {\n /** The name of the agent function that is called. */\n functionName: string;\n} & AttributeDetails;\n\n/**\n * A base node callback attribute.\n */\nexport default abstract class Callback extends Attribute {\n /**\n * @param type The node attribute type.\n * @param args The array of decorator argument definitions.\n * @param functionName The name of the agent function to call.\n */\n constructor(type: string, args: any[], private functionName: string) {\n super(type, args);\n }\n\n /**\n * Gets the name of the agent function to call.\n */\n getFunctionName = () => this.functionName;\n\n /**\n * Gets whether this attribute is a guard.\n */\n isGuard = () => false;\n\n /**\n * Gets the attribute details.\n */\n getDetails(): CallbackAttributeDetails {\n return {\n type: this.type,\n args: this.args,\n functionName: this.getFunctionName()\n };\n }\n\n /**\n * Attempt to call the agent function that this callback refers to.\n * @param agent The agent.\n */\n abstract callAgentFunction: (agent: Agent, isSuccess: boolean, isAborted: boolean) => void;\n}\n", "import Callback from \"./Callback\";\nimport Lookup from \"../../Lookup\";\nimport { Agent } from \"../../Agent\";\n\n/**\n * An ENTRY callback which defines an agent function to call when the associated node is updated and moves out of running state.\n */\nexport default class Entry extends Callback {\n /**\n * @param functionName The name of the agent function to call.\n * @param args The array of callback argument definitions.\n */\n constructor(functionName: string, args: any[]) {\n super(\"entry\", args, functionName);\n }\n\n /**\n * Attempt to call the agent function that this callback refers to.\n * @param agent The agent.\n */\n callAgentFunction = (agent: Agent) => {\n // Attempt to get the invoker for the callback function.\n const callbackFuncInvoker = Lookup.getFuncInvoker(agent, this.getFunctionName());\n\n // The callback function should be defined.\n if (callbackFuncInvoker === null) {\n throw new Error(\n `cannot call entry function '${this.getFunctionName()}' as is not defined on the agent and has not been registered`\n );\n }\n\n // Call the callback function.\n callbackFuncInvoker(this.args);\n };\n}\n", "import Callback from \"./Callback\";\nimport Lookup from \"../../Lookup\";\nimport { Agent } from \"../../Agent\";\n\n/**\n * A STEP callback which defines an agent function to call when the associated node is updated.\n */\nexport default class Step extends Callback {\n /**\n * @param functionName The name of the agent function to call.\n * @param args The array of callback argument definitions.\n */\n constructor(functionName: string, args: any[]) {\n super(\"step\", args, functionName);\n }\n\n /**\n * Attempt to call the agent function that this callback refers to.\n * @param agent The agent.\n */\n callAgentFunction = (agent: Agent) => {\n // Attempt to get the invoker for the callback function.\n const callbackFuncInvoker = Lookup.getFuncInvoker(agent, this.getFunctionName());\n\n // The callback function should be defined.\n if (callbackFuncInvoker === null) {\n throw new Error(\n `cannot call step function '${this.getFunctionName()}' as is not defined on the agent and has not been registered`\n );\n }\n\n // Call the callback function.\n callbackFuncInvoker(this.args);\n };\n}\n", "import Callback from \"./Callback\";\nimport Lookup from \"../../Lookup\";\nimport { Agent } from \"../../Agent\";\n\n/**\n * An EXIT callback which defines an agent function to call when the associated node is updated and moves to a finished state or is aborted.\n */\nexport default class Exit extends Callback {\n /**\n * @param functionName The name of the agent function to call.\n * @param args The array of callback argument definitions.\n */\n constructor(functionName: string, args: any[]) {\n super(\"exit\", args, functionName);\n }\n\n /**\n * Attempt to call the agent function that this callback refers to.\n * @param agent The agent.\n * @param isSuccess Whether the decorated node was left with a success state.\n * @param isAborted Whether the decorated node was aborted.\n */\n callAgentFunction = (agent: Agent, isSuccess: boolean, isAborted: boolean) => {\n // Attempt to get the invoker for the callback function.\n const callbackFuncInvoker = Lookup.getFuncInvoker(agent, this.getFunctionName());\n\n // The callback function should be defined.\n if (callbackFuncInvoker === null) {\n throw new Error(\n `cannot call exit function '${this.getFunctionName()}' as is not defined on the agent and has not been registered`\n );\n }\n\n // Call the callback function\n callbackFuncInvoker([{ value: { succeeded: isSuccess, aborted: isAborted } }, ...this.args]);\n };\n}\n", "import { AnyNodeDefinition, RootNodeDefinition } from \"./BehaviourTreeDefinition\";\nimport GuardPath, { GuardPathPart } from \"./attributes/guards/GuardPath\";\nimport { validateBranchSubtreeLinks } from \"./BehaviourTreeDefinitionValidator\";\nimport { isInteger } from \"./BehaviourTreeDefinitionUtilities\";\nimport Node from \"./nodes/Node\";\nimport Composite from \"./nodes/composite/Composite\";\nimport Decorator from \"./nodes/decorator/Decorator\";\nimport Parallel from \"./nodes/composite/Parallel\";\nimport Selector from \"./nodes/composite/Selector\";\nimport Sequence from \"./nodes/composite/Sequence\";\nimport Lotto from \"./nodes/composite/Lotto\";\nimport Fail from \"./nodes/decorator/Fail\";\nimport Flip from \"./nodes/decorator/Flip\";\nimport Repeat from \"./nodes/decorator/Repeat\";\nimport Retry from \"./nodes/decorator/Retry\";\nimport Root from \"./nodes/decorator/Root\";\nimport Succeed from \"./nodes/decorator/Succeed\";\nimport Action from \"./nodes/leaf/Action\";\nimport Condition from \"./nodes/leaf/Condition\";\nimport Wait from \"./nodes/leaf/Wait\";\nimport Lookup from \"./Lookup\";\nimport Attribute from \"./attributes/Attribute\";\nimport While from \"./attributes/guards/While\";\nimport Until from \"./attributes/guards/Until\";\nimport Entry from \"./attributes/callbacks/Entry\";\nimport Step from \"./attributes/callbacks/Step\";\nimport Exit from \"./attributes/callbacks/Exit\";\n\n/**\n * A type representing any node instance in a behaviour tree.\n */\ntype AnyNode =\n | Root\n | Action\n | Condition\n | Wait\n | Sequence\n | Selector\n | Lotto\n | Parallel\n | Repeat\n | Retry\n | Flip\n | Succeed\n | Fail;\n\n/**\n * A type defining a mapping of root node identifiers to root node definitions.\n */\ntype RootNodeDefinitionMap = { [key: string | symbol]: RootNodeDefinition };\n\n/**\n * A symbol to use as the main root key in any root node mappings.\n */\nconst MAIN_ROOT_NODE_KEY = Symbol(\"__root__\");\n\n/**\n * Build and populate the root nodes based on the provided definition, assuming that the definition has been validated.\n * @param definition The root node definitions.\n * @returns The built and populated root node definitions.\n */\nexport default function buildRootNode(definition: RootNodeDefinition[]): Root {\n // Create a mapping of root node identifers to root node definitions, including globally registered subtree root node definitions.\n const rootNodeDefinitionMap = createRootNodeDefinitionMap(definition);\n\n // Now that we have all of our root node definitons (those part of the tree definition and those globally\n // registered) we should validate the definition. This will also double-check that we dont have any circular\n // dependencies in our branch -> subtree references and that we have no broken branch -> subtree links.\n validateBranchSubtreeLinks(definition, true);\n\n // Create our populated tree of node instances, starting with our main root node.\n const rootNode = nodeFactory(rootNodeDefinitionMap[MAIN_ROOT_NODE_KEY], rootNodeDefinitionMap) as Root;\n\n // Set a guard path on every leaf of the tree to evaluate as part of each update.\n applyLeafNodeGuardPaths(rootNode);\n\n // We only need to return the main root node.\n return rootNode;\n}\n\n/**\n * A factory function which creates a node instance based on the specified definition.\n * @param definition The node definition.\n * @param rootNodeDefinitionMap The mapping of root node identifers to root node definitions, including globally registered subtree root node definitions.\n * @returns A node instance based on the specified definition.\n */\nfunction nodeFactory(definition: AnyNodeDefinition, rootNodeDefinitionMap: RootNodeDefinitionMap): AnyNode {\n // Get the attributes for the node.\n const attributes = nodeAttributesFactory(definition);\n\n // Create the node instance based on the definition type.\n switch (definition.type) {\n case \"root\":\n return new Root(attributes, nodeFactory(definition.child, rootNodeDefinitionMap));\n\n case \"repeat\":\n let iterations: number | null = null;\n let iterationsMin: number | null = null;\n let iterationsMax: number | null = null;\n\n if (Array.isArray(definition.iterations)) {\n iterationsMin = definition.iterations[0];\n iterationsMax = definition.iterations[1];\n } else if (isInteger(definition.iterations)) {\n iterations = definition.iterations!;\n }\n\n return new Repeat(\n attributes,\n iterations,\n iterationsMin,\n iterationsMax,\n nodeFactory(definition.child, rootNodeDefinitionMap)\n );\n\n case \"retry\":\n let attempts: number | null = null;\n let attemptsMin: number | null = null;\n let attemptsMax: number | null = null;\n\n if (Array.isArray(definition.attempts)) {\n attemptsMin = definition.attempts[0];\n attemptsMax = definition.attempts[1];\n } else if (isInteger(definition.attempts)) {\n attempts = definition.attempts!;\n }\n\n return new Retry(\n attributes,\n attempts,\n attemptsMin,\n attemptsMax,\n nodeFactory(definition.child, rootNodeDefinitionMap)\n );\n\n case \"flip\":\n return new Flip(attributes, nodeFactory(definition.child, rootNodeDefinitionMap));\n\n case \"succeed\":\n return new Succeed(attributes, nodeFactory(definition.child, rootNodeDefinitionMap));\n\n case \"fail\":\n return new Fail(attributes, nodeFactory(definition.child, rootNodeDefinitionMap));\n\n case \"sequence\":\n return new Sequence(\n attributes,\n definition.children.map((child) => nodeFactory(child, rootNodeDefinitionMap))\n );\n\n case \"selector\":\n return new Selector(\n attributes,\n definition.children.map((child) => nodeFactory(child, rootNodeDefinitionMap))\n );\n\n case \"parallel\":\n return new Parallel(\n attributes,\n definition.children.map((child) => nodeFactory(child, rootNodeDefinitionMap))\n );\n\n case \"lotto\":\n return new Lotto(\n attributes,\n definition.weights,\n definition.children.map((child) => nodeFactory(child, rootNodeDefinitionMap))\n );\n\n case \"branch\":\n return nodeFactory(rootNodeDefinitionMap[definition.ref].child, rootNodeDefinitionMap);\n\n case \"action\":\n return new Action(attributes, definition.call, definition.args || []);\n\n case \"condition\":\n return new Condition(attributes, definition.call, definition.args || []);\n\n case \"wait\":\n let duration: number | null = null;\n let durationMin: number | null = null;\n let durationMax: number | null = null;\n\n if (Array.isArray(definition.duration)) {\n durationMin = definition.duration[0];\n durationMax = definition.duration[1];\n } else if (isInteger(definition.duration)) {\n duration = definition.duration!;\n }\n\n return new Wait(attributes, duration, durationMin, durationMax);\n }\n}\n\n/**\n * Creates an array of node attribute instances based on the specified node definition.\n * @param definition The node definition.\n * @returns An array of node attribute instances based on the specified node definition.\n */\nfunction nodeAttributesFactory(definition: AnyNodeDefinition): Attribute[] {\n const attributes: Attribute[] = [];\n\n if (definition.while) {\n attributes.push(new While(definition.while.call, definition.while.args ?? []));\n }\n\n if (definition.until) {\n attributes.push(new Until(definition.until.call, definition.until.args ?? []));\n }\n\n if (definition.entry) {\n attributes.push(new Entry(definition.entry.call, definition.entry.args ?? []));\n }\n\n if (definition.step) {\n attributes.push(new Step(definition.step.call, definition.step.args ?? []));\n }\n\n if (definition.exit) {\n attributes.push(new Exit(definition.exit.call, definition.exit.args ?? []));\n }\n\n return attributes;\n}\n\n/**\n * Creates a mapping of root node identifers to root node definitions, mixing in globally registered subtree root node definitions.\n * @param definition The root node definitions.\n * @returns A mapping of root node identifers to root node definitions, including globally registered subtree root node definitions.\n */\nfunction createRootNodeDefinitionMap(definition: RootNodeDefinition[]): RootNodeDefinitionMap {\n // Create a mapping of root node identifers to root node definitions.\n const rootNodeMap: RootNodeDefinitionMap = {};\n\n // Add in any registered subtree root node definitions.\n for (const [name, rootNodeDefinition] of Object.entries(Lookup.getSubtrees())) {\n // The name used when registering the subtree will be used as the root node identifier.\n rootNodeMap[name] = { ...rootNodeDefinition, id: name };\n }\n\n // Populate the map with the root node definitions that were included with the tree definition.\n // We do this after adding any registered subtrees as we want these to take presedence.\n for (const rootNodeDefinition of definition) {\n rootNodeMap[rootNodeDefinition.id ?? MAIN_ROOT_NODE_KEY] = rootNodeDefinition;\n }\n\n return rootNodeMap;\n}\n\n/**\n * Applies a guard path to every leaf of the tree to evaluate as part of each update.\n * @param root The main root tree node.\n */\nfunction applyLeafNodeGuardPaths(root: Root) {\n const nodePaths: Node[][] = [];\n\n const findLeafNodes = (path: Node[], node: Node) => {\n // Add the current node to the path.\n path = path.concat(node);\n\n // Check whether the current node is a leaf node.\n if (node.isLeafNode()) {\n nodePaths.push(path);\n } else {\n (node as Composite | Decorator).getChildren().forEach((child) => findLeafNodes(path, child));\n }\n };\n\n // Find all leaf node paths, starting from the root.\n findLeafNodes([], root);\n\n nodePaths.forEach((path) => {\n // Each node in the current path will have to be assigned a guard path, working from the root outwards.\n for (let depth = 0; depth < path.length; depth++) {\n // Get the node in the path at the current depth.\n const currentNode = path[depth];\n\n // The node may already have been assigned a guard path, if so just skip it.\n if (currentNode.hasGuardPath()) {\n continue;\n }\n\n // Create the guard path for the current node.\n const guardPath = new GuardPath(\n path\n .slice(0, depth + 1)\n .map((node) => ({ node, guards: node.getGuardAttributes() }))\n .filter((details) => details.guards.length > 0)\n );\n\n // Assign the guard path to the current node.\n currentNode.setGuardPath(guardPath);\n }\n });\n}\n", "import State, { AnyState } from \"./State\";\nimport Lookup from \"./Lookup\";\nimport Node from \"./nodes/Node\";\nimport Root from \"./nodes/decorator/Root\";\nimport Composite from \"./nodes/composite/Composite\";\nimport Decorator from \"./nodes/decorator/Decorator\";\nimport { Agent, GlobalFunction } from \"./Agent\";\nimport { CallbackAttributeDetails } from \"./attributes/callbacks/Callback\";\nimport { GuardAttributeDetails } from \"./attributes/guards/Guard\";\nimport { BehaviourTreeOptions } from \"./BehaviourTreeOptions\";\nimport { convertMDSLToJSON } from \"./mdsl/MDSLDefinitionParser\";\nimport { RootNodeDefinition } from \"./BehaviourTreeDefinition\";\nimport { validateDefinition, validateJSONDefinition } from \"./BehaviourTreeDefinitionValidator\";\nimport buildRootNode from \"./BehaviourTreeBuilder\";\nimport { isNullOrUndefined } from \"./BehaviourTreeDefinitionUtilities\";\n\n// Purely for outside inspection of the tree.\nexport type FlattenedTreeNode = {\n id: string;\n type: string;\n caption: string;\n state: AnyState;\n guards: GuardAttributeDetails[];\n callbacks: CallbackAttributeDetails[];\n args: any[];\n parentId: string | null;\n};\n\n/**\n * A representation of a behaviour tree.\n */\nexport class BehaviourTree {\n /**\n * The main root tree node.\n */\n private readonly _rootNode: Root;\n\n /**\n * Creates a new instance of the BehaviourTree class.\n * @param definition The behaviour tree definition as either an MDSL string, root node definition object or array of root node definition objects.\n * @param agent The agent instance that this behaviour tree is modelling behaviour for.\n * @param options The behaviour tree options object.\n */\n constructor(\n definition: string | RootNodeDefinition | RootNodeDefinition[],\n private agent: Agent,\n private options: BehaviourTreeOptions = {}\n ) {\n // The tree definition must be defined.\n if (isNullOrUndefined(definition)) {\n throw new Error(\"tree definition not defined\");\n }\n\n // The agent must be defined and not null.\n if (typeof agent !== \"object\" || agent === null) {\n throw new Error(\"the agent must be an object and not null\");\n }\n\n // We should validate the definition before we try to build the tree nodes.\n const { succeeded, errorMessage, json } = validateDefinition(definition);\n\n // Did our validation fail without error?\n if (!succeeded) {\n throw new Error(`invalid definition: ${errorMessage}`);\n }\n\n // Double check that we did actually get our json definition as part of our definition validtion.\n if (!json) {\n throw new Error(\n \"expected json definition to be returned as part of successful definition validation response\"\n );\n }\n\n try {\n // Create the populated tree of behaviour tree nodes and get the root node.\n this._rootNode = buildRootNode(json);\n } catch (exception) {\n // There was an issue in trying build and populate the behaviour tree.\n throw new Error(`error building tree: ${(exception as Error).message}`);\n }\n }\n\n /**\n * Gets whether the tree is in the RUNNING state.\n * @returns true if the tree is in the RUNNING state, otherwise false.\n */\n isRunning() {\n return this._rootNode.getState() === State.RUNNING;\n }\n\n /**\n * Gets the current tree state of SUCCEEDED, FAILED, READY or RUNNING.\n * @returns The current tree state.\n */\n getState() {\n return this._rootNode.getState();\n }\n\n /**\n * Step the tree.\n * 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.\n * 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\n * 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.\n *\n * 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.\n */\n step() {\n // If the root node has already been stepped to completion then we need to reset it.\n if (this._rootNode.getState() === State.SUCCEEDED || this._rootNode.getState() === State.FAILED) {\n this._rootNode.reset();\n }\n\n try {\n this._rootNode.update(this.agent, this.options);\n } catch (exception) {\n throw new Error(`error stepping tree: ${(exception as Error).message}`);\n }\n }\n\n /**\n * Resets the tree from the root node outwards to each nested node, giving each a state of READY.\n */\n reset() {\n this._rootNode.reset();\n }\n\n /**\n * Gets the flattened details of every node in the tree.\n * @returns The flattened details of every node in the tree.\n */\n getFlattenedNodeDetails(): FlattenedTreeNode[] {\n // Create an empty flattened array of tree nodes.\n const flattenedTreeNodes: FlattenedTreeNode[] = [];\n\n /**\n * Helper function to process a node instance and push details into the flattened tree nodes array.\n * @param node The current node.\n * @param parentUid The UID of the node parent, or null if the node is the main root node.\n */\n const processNode = (node: Node, parentUid: string | null) => {\n // Get the guard and callback attribute details for this node.\n const guards = node\n .getAttributes()\n .filter((attribute) => attribute.isGuard())\n .map((attribute) => attribute.getDetails()) as GuardAttributeDetails[];\n const callbacks = node\n .getAttributes()\n .filter((attribute) => !attribute.isGuard())\n .map((attribute) => attribute.getDetails()) as CallbackAttributeDetails[];\n\n // Push the current node into the flattened nodes array.\n flattenedTreeNodes.push({\n id: node.getUid(),\n type: node.getType(),\n caption: node.getName(),\n state: node.getState(),\n guards,\n callbacks,\n args: node.getArguments(),\n parentId: parentUid\n });\n\n // Process each of the nodes children if it is not a leaf node.\n if (!node.isLeafNode()) {\n (node as Composite | Decorator)\n .getChildren()\n .forEach((child) => processNode(child, (node as Composite | Decorator).getUid()));\n }\n };\n\n // Convert the nested node structure into a flattened array of node details.\n processNode(this._rootNode, null);\n\n return flattenedTreeNodes;\n }\n\n /**\n * Registers the action/condition/guard/callback function or subtree with the given name.\n * @param name The name of the function or subtree to register.\n * @param value The function or subtree definition to register.\n */\n static register(name: string, value: GlobalFunction | string | RootNodeDefinition) {\n // Are we going to register a action/condition/guard/callback function?\n if (typeof value === \"function\") {\n Lookup.setFunc(name, value);\n return;\n }\n\n // We are not registering an action/condition/guard/callback function, so we must be registering a subtree.\n if (typeof value === \"string\") {\n let rootNodeDefinitions: RootNodeDefinition[];\n\n // We will assume that any string passed in will be a mdsl definition.\n try {\n rootNodeDefinitions = convertMDSLToJSON(value);\n } catch (exception) {\n throw new Error(`error registering definition, invalid MDSL: ${(exception as Error).message}`);\n }\n\n // This function should only ever be called with a definition containing a single unnamed root node.\n if (rootNodeDefinitions.length != 1 || rootNodeDefinitions[0].id !== null) {\n throw new Error(\"error registering definition: expected a single unnamed root node\");\n }\n\n try {\n // We should validate the subtree as we don't want invalid subtrees available via the lookup.\n const { succeeded, errorMessage } = validateJSONDefinition(rootNodeDefinitions[0]);\n\n // Did our validation fail without error?\n if (!succeeded) {\n throw new Error(errorMessage);\n }\n } catch (exception) {\n throw new Error(`error registering definition: ${(exception as Error).message}`);\n }\n\n // Everything seems hunky-dory, register the subtree.\n Lookup.setSubtree(name, rootNodeDefinitions[0]);\n } else if (typeof value === \"object\" && !Array.isArray(value)) {\n // We will assume that any object passed in is a root node definition.\n\n try {\n // We should validate the subtree as we don't want invalid subtrees available via the lookup.\n const { succeeded, errorMessage } = validateJSONDefinition(value);\n\n // Did our validation fail without error?\n if (!succeeded) {\n throw new Error(errorMessage);\n }\n } catch (exception) {\n throw new Error(`error registering definition: ${(exception as Error).message}`);\n }\n\n // Everything seems hunky-dory, register the subtree.\n Lookup.setSubtree(name, value);\n } else {\n throw new Error(\"unexpected value, expected string mdsl definition, root node json definition or function\");\n }\n }\n\n /**\n * Unregisters the registered action/condition/guard/callback function or subtree with the given name.\n * @param name The name of the registered action/condition/guard/callback function or subtree to unregister.\n */\n static unregister(name: string): void {\n Lookup.remove(name);\n }\n\n /**\n * Unregister all registered action/condition/guard/callback functions and subtrees.\n */\n static unregisterAll(): void {\n Lookup.empty();\n }\n}\n"], - "mappings": "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", + "sourcesContent": ["\"use strict\";\r\nObject.defineProperty(exports, \"__esModule\", { value: true });\r\nexports.Participant = void 0;\r\n/**\r\n * A participant that holds a number of tickets.\r\n */\r\nvar Participant = /** @class */ (function () {\r\n /**\r\n * Creates an instance of the Participant class.\r\n * @param participant The actual participant.\r\n * @param tickets The number of tickets held by the participant.\r\n */\r\n function Participant(participant, tickets) {\r\n if (tickets === void 0) { tickets = 1; }\r\n this._participant = participant;\r\n this._tickets = tickets;\r\n }\r\n Object.defineProperty(Participant.prototype, \"participant\", {\r\n /** Gets the actual participant. */\r\n get: function () {\r\n return this._participant;\r\n },\r\n enumerable: false,\r\n configurable: true\r\n });\r\n Object.defineProperty(Participant.prototype, \"tickets\", {\r\n /** Gets or sets the number of tickets held by the participant. */\r\n get: function () {\r\n return this._tickets;\r\n },\r\n set: function (value) {\r\n this._tickets = value;\r\n },\r\n enumerable: false,\r\n configurable: true\r\n });\r\n return Participant;\r\n}());\r\nexports.Participant = Participant;\r\n", "\"use strict\";\r\nObject.defineProperty(exports, \"__esModule\", { value: true });\r\nexports.isNaturalNumber = exports.isNullOrUndefined = void 0;\r\n/**\r\n * Gets whether the value provided is null or undefined.\r\n * @param value The value to check.\r\n * @returns Whether the value provided is null or undefined.\r\n */\r\nfunction isNullOrUndefined(value) {\r\n return value === null || value === undefined;\r\n}\r\nexports.isNullOrUndefined = isNullOrUndefined;\r\n/**\r\n * Gets whether the value provided is a natural number.\r\n * @param value The value to check.\r\n * @returns Whether the value provided is a natural number.\r\n */\r\nfunction isNaturalNumber(value) {\r\n return typeof value === \"number\" && value >= 1 && Math.floor(value) === value;\r\n}\r\nexports.isNaturalNumber = isNaturalNumber;\r\n", "\"use strict\";\r\nObject.defineProperty(exports, \"__esModule\", { value: true });\r\nexports.Lotto = void 0;\r\nvar Participant_1 = require(\"./Participant\");\r\nvar Utilities_1 = require(\"./Utilities\");\r\n/**\r\n * Represents a lotto consisting of a number of pickable ticket-holding participants.\r\n */\r\nvar Lotto = /** @class */ (function () {\r\n /**\r\n * Creates a new instance of Lotto.\r\n * @param customRandom The custom RNG to use in place of Math.random().\r\n */\r\n function Lotto(customRandom) {\r\n /** The array of participants that are holding tickets in the lotto. */\r\n this._participants = [];\r\n this._customRandom = customRandom;\r\n }\r\n /**\r\n * Adds a participant with the specified number of tickets, or adds to the participant ticket count if the participant already holds tickets.\r\n * @param participant The participant to add or to increase the ticket count for if they already hold tickets.\r\n * @param tickets The number of tickets, defaults to 1.\r\n * @returns The Lotto instance.\r\n */\r\n Lotto.prototype.add = function (participant, tickets) {\r\n if (tickets === void 0) { tickets = 1; }\r\n // Check that we have a valid ticket count.\r\n if (!(0, Utilities_1.isNaturalNumber)(tickets)) {\r\n throw new Error(\"tickets value must be a natural number\");\r\n }\r\n // Check whether this participant has already been added.\r\n var existingParticipant = this._participants.find(function (part) { return part.participant === participant; });\r\n if (existingParticipant) {\r\n // The participant has already been added to the lotto so just add to their ticket count.\r\n existingParticipant.tickets += tickets;\r\n }\r\n else {\r\n // The participant is not part of the lotto so we should add them.\r\n this._participants.push(new Participant_1.Participant(participant, tickets));\r\n }\r\n return this;\r\n };\r\n /**\r\n * Removes the specified number of tickets for the given participant from the draw, or all tickets if a ticket number is not defined.\r\n * @param participant The participant to remove tickets for.\r\n * @param tickets The number of tickets to remove, or undefined if all tickets are to be removed.\r\n * @returns The Lotto instance.\r\n */\r\n Lotto.prototype.remove = function (participant, tickets) {\r\n // Attempt to get the existing participant.\r\n var existingParticipant = this._participants.find(function (part) { return part.participant === participant; });\r\n // There is nothing to do if the specified participant isn't even part of the lotto.\r\n if (!existingParticipant) {\r\n return this;\r\n }\r\n // Check whether a tickets value was given.\r\n if (tickets !== undefined) {\r\n // Check that we have a valid ticket count.\r\n if (!(0, Utilities_1.isNaturalNumber)(tickets)) {\r\n throw new Error(\"tickets value must be a natural number\");\r\n }\r\n existingParticipant.tickets -= tickets;\r\n // If the participant no longer holds any tickets then they should be removed.\r\n if (existingParticipant.tickets < 1) {\r\n this._participants = this._participants.filter(function (part) { return part !== existingParticipant; });\r\n }\r\n }\r\n else {\r\n // We are removing all tickets for the participant so just remove them from the lotto.\r\n this._participants = this._participants.filter(function (part) { return part !== existingParticipant; });\r\n }\r\n return this;\r\n };\r\n /**\r\n * Draw a winning ticket and return the participant that holds the ticket.\r\n * @param options The draw options.\r\n * @returns The participant that holds the winning ticket.\r\n */\r\n Lotto.prototype.draw = function (options) {\r\n if (options === void 0) { options = {}; }\r\n // If we have no participants then just return null.\r\n if (this._participants.length === 0) {\r\n return null;\r\n }\r\n var redrawable = (0, Utilities_1.isNullOrUndefined)(options.redrawable) ? true : options.redrawable;\r\n var pickable = [];\r\n this._participants.forEach(function (_a) {\r\n var participant = _a.participant, tickets = _a.tickets;\r\n for (var ticketCount = 0; ticketCount < tickets; ticketCount++) {\r\n pickable.push(participant);\r\n }\r\n });\r\n var random;\r\n // We need a random floating-point number between 0 (inclusive) and 1 to scale up to pick our winner.\r\n // If a custom random function exists then we should use that or fall back to Math.random().\r\n if (this._customRandom) {\r\n // Call our custom random function to get a random floating-point number.\r\n random = this._customRandom();\r\n // Verify that the result of calling our custom random function is a number between 0 (inclusive) and 1.\r\n if (typeof random !== \"number\" || random < 0 || random >= 1) {\r\n throw new Error(\"the 'random' function provided did not return a number between 0 (inclusive) and 1\");\r\n }\r\n }\r\n else {\r\n // No custom random function was defined so just use good ol' Math.random().\r\n random = Math.random();\r\n }\r\n // Pick a winning participant.\r\n var winner = pickable[Math.floor(random * pickable.length)];\r\n // If the ticket isn't redrawable then we should remove a ticket from the winning participants ticket count.\r\n if (!redrawable) {\r\n this.remove(winner, 1);\r\n }\r\n // Return the winning participant.\r\n return winner;\r\n };\r\n /**\r\n * Draws multiple winning tickets and return an array of the participants that hold the winning tickets.\r\n * @param tickets The number of winning tickets to draw.\r\n * @param options The draw multiple options.\r\n * @returns An array of the participants that hold the winning tickets.\r\n */\r\n Lotto.prototype.drawMultiple = function (tickets, options) {\r\n if (options === void 0) { options = {}; }\r\n var uniqueResults = (0, Utilities_1.isNullOrUndefined)(options.unique) ? false : options.unique;\r\n // Handle cases where the user has asked for zero tickets (no idea why they would do this be we should trust them).\r\n if (tickets === 0) {\r\n return [];\r\n }\r\n // Now that we know out tickets value is not zero we should check that it is a valid natural number.\r\n if (!(0, Utilities_1.isNaturalNumber)(tickets)) {\r\n throw new Error(\"tickets value must be a natural number\");\r\n }\r\n var result = [];\r\n // Keep drawing tickets until we either reach the number of required tickets or we simply run out of tickets to draw.\r\n // We can run out of tickets to draw if 'options.redrawable' is explicity 'false' or we just had no participants when 'drawMultiple' was called.\r\n while (result.length < tickets && this._participants.length > 0) {\r\n result.push(this.draw(options));\r\n }\r\n // If the 'unique' draw option is set then we need to remove duplicates from the result list.\r\n if (uniqueResults) {\r\n // Create an array to store our unique results.\r\n var unique = [];\r\n // Iterate over all of our participants (with potential duplicates) and populate our array of unique values.\r\n for (var _i = 0, result_1 = result; _i < result_1.length; _i++) {\r\n var participant = result_1[_i];\r\n if (unique.indexOf(participant) === -1) {\r\n unique.push(participant);\r\n }\r\n }\r\n result = unique;\r\n }\r\n return result;\r\n };\r\n return Lotto;\r\n}());\r\nexports.Lotto = Lotto;\r\n", "\"use strict\";\r\nObject.defineProperty(exports, \"__esModule\", { value: true });\r\nexports.createLotto = void 0;\r\nvar Lotto_1 = require(\"./Lotto\");\r\n/**\r\n * A function that creates and returns a Lotto instance.\r\n * @param participantsOrOptions An array of initial participants or options relating to the creation of a Lotto instance.\r\n * @returns A new Lotto instance.\r\n */\r\nfunction createLotto(participantsOrOptions) {\r\n // If no initial participants or lotto options were provided as an argument then we can just return a new lotto instance now.\r\n if (!participantsOrOptions) {\r\n return new Lotto_1.Lotto();\r\n }\r\n // Check whether we were provided with an array of initial participants or a lotto options object.\r\n if (Array.isArray(participantsOrOptions)) {\r\n // We are dealing with a pre-defined array of participants.\r\n var participants = participantsOrOptions;\r\n var lotto_1 = new Lotto_1.Lotto();\r\n // If the lotto participants have been defined upfront then we will need to add them all to our lotto instance now.\r\n participants.forEach(function (_a) {\r\n var participant = _a[0], tokens = _a[1];\r\n return lotto_1.add(participant, tokens);\r\n });\r\n // Return the Lotto instance.\r\n return lotto_1;\r\n }\r\n else {\r\n // We are dealing with some lotto options.\r\n var random = participantsOrOptions.random, participants = participantsOrOptions.participants;\r\n // Create a Lotto instance passing the custom RNG function to use in place of Math.random() (which could be undefined).\r\n var lotto_2 = new Lotto_1.Lotto(random);\r\n // If the lotto participants have been defined upfront as part of the options then we will need to add them all to our lotto instance now.\r\n if (participants) {\r\n participants.forEach(function (_a) {\r\n var participant = _a[0], tokens = _a[1];\r\n return lotto_2.add(participant, tokens);\r\n });\r\n }\r\n // Return the Lotto instance.\r\n return lotto_2;\r\n }\r\n}\r\nexports.createLotto = createLotto;\r\n", "\"use strict\";\r\nObject.defineProperty(exports, \"__esModule\", { value: true });\r\nvar createLotto_1 = require(\"./createLotto\");\r\nexports.default = createLotto_1.createLotto;\r\n", "import State from \"./State\";\nimport { validateDefinition } from \"./BehaviourTreeDefinitionValidator\";\nimport { convertMDSLToJSON } from \"./mdsl/MDSLDefinitionParser\";\nimport { BehaviourTree, FlattenedTreeNode } from \"./BehaviourTree\";\nimport { BehaviourTreeOptions } from \"./BehaviourTreeOptions\";\n\nexport { BehaviourTree, State, convertMDSLToJSON, validateDefinition };\nexport type { FlattenedTreeNode, BehaviourTreeOptions };\n", "/**\n * Enumeration of node state types.\n */\nexport enum State {\n READY = \"mistreevous.ready\",\n RUNNING = \"mistreevous.running\",\n SUCCEEDED = \"mistreevous.succeeded\",\n FAILED = \"mistreevous.failed\"\n}\n\nexport { State as default };\n\nexport type CompleteState = State.SUCCEEDED | State.FAILED;\nexport type AnyState = State.READY | State.RUNNING | CompleteState;\n", "import {\n NodeDefinition,\n RootNodeDefinition,\n DecoratorNodeDefinition,\n CompositeNodeDefinition,\n AnyNodeDefinition,\n BranchNodeDefinition\n} from \"./BehaviourTreeDefinition\";\n\n/**\n * A type guard function that returns true if the specified node satisfies the RootNodeDefinition type.\n * @param node The node.\n * @returns A value of true if the specified node satisfies the RootNodeDefinition type.\n */\nexport function isRootNode(node: NodeDefinition): node is RootNodeDefinition {\n return node.type === \"root\";\n}\n\n/**\n * A type guard function that returns true if the specified node satisfies the BranchNodeDefinition type.\n * @param node The node.\n * @returns A value of true if the specified node satisfies the BranchNodeDefinition type.\n */\nexport function isBranchNode(node: NodeDefinition): node is BranchNodeDefinition {\n return node.type === \"branch\";\n}\n\n/**\n * A type guard function that returns true if the specified node satisfies the NodeDefinition type.\n * @param node The node.\n * @returns A value of true if the specified node satisfies the NodeDefinition type.\n */\nexport function isLeafNode(node: NodeDefinition): node is NodeDefinition {\n return [\"branch\", \"action\", \"condition\", \"wait\"].includes(node.type);\n}\n\n/**\n * A type guard function that returns true if the specified node satisfies the DecoratorNodeDefinition type.\n * @param node The node.\n * @returns A value of true if the specified node satisfies the DecoratorNodeDefinition type.\n */\nexport function isDecoratorNode(node: NodeDefinition): node is DecoratorNodeDefinition {\n return [\"root\", \"repeat\", \"retry\", \"flip\", \"succeed\", \"fail\"].includes(node.type);\n}\n\n/**\n * A type guard function that returns true if the specified node satisfies the CompositeNodeDefinition type.\n * @param node The node.\n * @returns A value of true if the specified node satisfies the CompositeNodeDefinition type.\n */\nexport function isCompositeNode(node: NodeDefinition): node is CompositeNodeDefinition {\n return [\"sequence\", \"selector\", \"lotto\", \"parallel\"].includes(node.type);\n}\n\n/**\n * Flatten a node definition into an array of all of its nested node definitions.\n * @param nodeDefinition The node definition to flatten.\n * @returns An array of all of nested node definitions.\n */\nexport function flattenDefinition(nodeDefinition: AnyNodeDefinition): AnyNodeDefinition[] {\n const nodes: AnyNodeDefinition[] = [];\n\n const processNode = (currentNodeDefinition: AnyNodeDefinition) => {\n nodes.push(currentNodeDefinition);\n\n if (isCompositeNode(currentNodeDefinition)) {\n currentNodeDefinition.children.forEach(processNode);\n } else if (isDecoratorNode(currentNodeDefinition)) {\n processNode(currentNodeDefinition.child);\n }\n };\n\n processNode(nodeDefinition);\n\n return nodes;\n}\n\n/**\n * Determines whether the passed value is an integer.\n * @param value The value to check.\n * @returns Whether the passed value is an integer.\n */\nexport function isInteger(value: unknown): boolean {\n return typeof value === \"number\" && Math.floor(value) === value;\n}\n\n/**\n * Determines whether the passed value is null or undefined.\n * @param value The value to check.\n * @returns Whether the passed value is null or undefined.\n */\nexport function isNullOrUndefined(value: unknown): boolean {\n return typeof value === \"undefined\" || value === null;\n}\n", "/**\n * A type defining an object that holds a reference to substitued string literals parsed from the definition.\n */\nexport type StringLiteralPlaceholders = { [key: string]: string };\n\n/**\n * Pop the next raw token from the specified array of tokens and throw an error if it wasn't the expected one.\n * @param tokens The array of tokens.\n * @param expected An optional string or array or items, one of which must match the next popped token.\n * @returns The popped token.\n */\nexport function popAndCheck(tokens: string[], expected?: string | string[]): string {\n // Get and remove the next token.\n const popped = tokens.shift();\n\n // We were expecting another token but there aren't any.\n if (popped === undefined) {\n throw new Error(\"unexpected end of definition\");\n }\n\n // Do we have an expected token/tokens array?\n if (expected != undefined) {\n // Get an array of expected values, if the popped token matches any then we are all good.\n const expectedValues = typeof expected === \"string\" ? [expected] : expected;\n\n // Check whether the popped token matches at least one of our expected items.\n var tokenMatchesExpectation = expectedValues.some((item) => popped.toUpperCase() === item.toUpperCase());\n\n // Throw an error if the popped token didn't match any of our expected items.\n if (!tokenMatchesExpectation) {\n const expectationString = expectedValues.map((item) => \"'\" + item + \"'\").join(\" or \");\n throw new Error(\"unexpected token found. Expected \" + expectationString + \" but got '\" + popped + \"'\");\n }\n }\n\n // Return the popped token.\n return popped;\n}\n\n/**\n * Swaps out any node/attribute argument string literals with placeholders.\n * @param definition The definition.\n * @returns An object containing a mapping of placeholders to original string values as well as the processed definition string.\n */\nexport function substituteStringLiterals(definition: string): {\n placeholders: StringLiteralPlaceholders;\n processedDefinition: string;\n} {\n // Create an object to hold the mapping of placeholders to original string values.\n const placeholders: StringLiteralPlaceholders = {};\n\n // Replace any string literals wrapped with double quotes in our definition with placeholders to be processed later.\n const processedDefinition = definition.replace(/\\\"(\\\\.|[^\"\\\\])*\\\"/g, (match) => {\n var strippedMatch = match.substring(1, match.length - 1);\n var placeholder = Object.keys(placeholders).find((key) => placeholders[key] === strippedMatch);\n\n // If we have no existing string literal match then create a new placeholder.\n if (!placeholder) {\n placeholder = `@@${Object.keys(placeholders).length}@@`;\n placeholders[placeholder] = strippedMatch;\n }\n\n return placeholder;\n });\n\n return { placeholders, processedDefinition };\n}\n\n/**\n * Parse the tree definition into an array of raw tokens.\n * @param definition The definition.\n * @returns An array of tokens parsed from the definition.\n */\nexport function parseTokensFromDefinition(definition: string): string[] {\n // Add some space around various important characters so that they can be plucked out easier as individual tokens.\n definition = definition.replace(/\\(/g, \" ( \");\n definition = definition.replace(/\\)/g, \" ) \");\n definition = definition.replace(/\\{/g, \" { \");\n definition = definition.replace(/\\}/g, \" } \");\n definition = definition.replace(/\\]/g, \" ] \");\n definition = definition.replace(/\\[/g, \" [ \");\n definition = definition.replace(/\\,/g, \" , \");\n\n // Split the definition into raw token form and return it.\n return definition.replace(/\\s+/g, \" \").trim().split(\" \");\n}\n", "import { StringLiteralPlaceholders, popAndCheck } from \"./MDSLUtilities\";\n\n/**\n * A type representing any node function argument.\n */\ntype Argument = {\n /**\n * The argument value.\n */\n value: T;\n /**\n * The argument type, used for validation.\n */\n type: string;\n};\n\ntype NullArgument = Argument & {\n type: \"null\";\n};\n\ntype BooleanArgument = Argument & {\n type: \"boolean\";\n};\n\ntype NumberArgument = Argument & {\n type: \"number\";\n /**\n * A flag defining whether the number argument value is a valid integer. (used for validation)\n */\n isInteger: boolean;\n};\n\ntype StringPlaceholderArgument = Argument & {\n type: \"string\";\n};\n\ntype IdentifierArgument = Argument & {\n type: \"identifier\";\n};\n\n/**\n * A type representing a reference to any node function argument.\n */\ntype AnyArgument = NullArgument | BooleanArgument | NumberArgument | StringPlaceholderArgument | IdentifierArgument;\n\n/**\n * Parse an array of argument definitions from the specified tokens array.\n * @param tokens The array tokens to parse the argument definitions from.\n * @param stringArgumentPlaceholders The mapping of string literal node argument placeholders to original values.\n * @param argumentValidator The argument validator function.\n * @param validationFailedMessage The exception message to throw if argument validation fails.\n * @returns An array of argument definitions parsed from the specified tokens array.\n */\nexport function parseArgumentTokens(\n tokens: string[],\n stringArgumentPlaceholders: StringLiteralPlaceholders\n): AnyArgument[] {\n const argumentList: AnyArgument[] = [];\n\n // If the next token is not a '[' or '(' then we have no arguments to parse.\n if (![\"[\", \"(\"].includes(tokens[0])) {\n return argumentList;\n }\n\n // Any lists of arguments will always be wrapped in '[]' for node arguments or '()' for attribute arguments.\n // We are looking for a '[' or '(' opener that wraps the argument tokens and the relevant closer.\n const closingToken = popAndCheck(tokens, [\"[\", \"(\"]) === \"[\" ? \"]\" : \")\";\n\n const argumentListTokens: string[] = [];\n\n // Grab all tokens between the '[' and ']' or '(' and ')'.\n while (tokens.length && tokens[0] !== closingToken) {\n // The next token is part of our arguments list.\n argumentListTokens.push(tokens.shift()!);\n }\n\n // Validate the order of the argument tokens. Each token must either be a ',' or a single argument that satisfies the validator.\n argumentListTokens.forEach((token, index) => {\n // Get whether this token should be an actual argument.\n const shouldBeArgumentToken = !(index & 1);\n\n // If the current token should be an actual argument then validate it, otherwise it should be a ',' token.\n if (shouldBeArgumentToken) {\n // Get the argument definition.\n const argumentDefinition = getArgumentDefinition(token, stringArgumentPlaceholders);\n\n // This is a valid argument!\n argumentList.push(argumentDefinition);\n } else {\n // The current token should be a ',' token.\n if (token !== \",\") {\n throw new Error(`invalid argument list, expected ',' or ']' but got '${token}'`);\n }\n }\n });\n\n // The arguments list should terminate with a ']' or ')' token, depending on the opener.\n popAndCheck(tokens, closingToken);\n\n // Return the arguments.\n return argumentList;\n}\n\n/**\n * Gets an argument value definition.\n * @param token The argument token.\n * @param stringArgumentPlaceholders The mapping of string literal node argument placeholders to original values.\n * @returns An argument value definition.\n */\nfunction getArgumentDefinition(token: string, stringArgumentPlaceholders: StringLiteralPlaceholders): AnyArgument {\n // Check whether the token represents a null value.\n if (token === \"null\") {\n return {\n value: null,\n type: \"null\"\n } as NullArgument;\n }\n\n // Check whether the token represents a boolean value.\n if (token === \"true\" || token === \"false\") {\n return {\n value: token === \"true\",\n type: \"boolean\"\n } as BooleanArgument;\n }\n\n // Check whether the token represents a number value.\n // TODO: Relies on broken isNaN - see MDN.\n // if (!Number.isNaN(token)) {\n if (!isNaN(token as any)) {\n return {\n value: parseFloat(token),\n isInteger: parseFloat(token) === parseInt(token, 10),\n type: \"number\"\n } as NumberArgument;\n }\n\n // Check whether the token is a placeholder (e.g. @@0@@) representing a string literal.\n if (token.match(/^@@\\d+@@$/g)) {\n return {\n value: stringArgumentPlaceholders[token].replace('\\\\\"', '\"'),\n type: \"string\"\n } as StringPlaceholderArgument;\n }\n\n // The only remaining option is that the argument value is an identifier.\n return {\n value: token,\n type: \"identifier\"\n } as IdentifierArgument;\n}\n", "import { NodeAttributeDefinition } from \"../BehaviourTreeDefinition\";\nimport { parseArgumentTokens } from \"./MDSLNodeArgumentParser\";\nimport { StringLiteralPlaceholders } from \"./MDSLUtilities\";\n\n/**\n * A type defining the attribute definitions of a node.\n */\ntype NodeAttributes = {\n while?: NodeAttributeDefinition;\n until?: NodeAttributeDefinition;\n entry?: NodeAttributeDefinition;\n exit?: NodeAttributeDefinition;\n step?: NodeAttributeDefinition;\n};\n\n/**\n * Parse any node attribute definitions from the specified tokens array.\n * @param tokens The array of remaining tokens.\n * @param stringArgumentPlaceholders The mapping of string literal node argument placeholders to original values.\n * @returns An object of attribute definitions defined by any directly following tokens.\n */\nexport function parseAttributeTokens(\n tokens: string[],\n stringArgumentPlaceholders: StringLiteralPlaceholders\n): NodeAttributes {\n const nodeAttributeNames: (keyof NodeAttributes)[] = [\"while\", \"until\", \"entry\", \"exit\", \"step\"];\n\n // Create an object to hold any attributes found.\n const attributes: NodeAttributes = {};\n\n // Try to get the name of the attribute for the next token.\n let nextAttributeName = tokens[0]?.toLowerCase() as keyof NodeAttributes;\n\n // Pull attribute tokens as well as their arguments off of the tokens stack until we have no more.\n while (nodeAttributeNames.includes(nextAttributeName)) {\n // Check to make sure that we have not already created an attribute definition of this type.\n if (attributes[nextAttributeName]) {\n throw new Error(`duplicate attribute '${tokens[0].toUpperCase()}' found for node`);\n }\n\n // Remove the attribute name token from the array of tokens.\n tokens.shift();\n\n // Grab the attribute arguments, assuming the first to be an identifier.\n const [attributeCallIdentifier, ...attributeArguments] = parseArgumentTokens(\n tokens,\n stringArgumentPlaceholders\n );\n\n // The first attribute argument has to be an identifer, this will reference an agent function.\n if (attributeCallIdentifier?.type !== \"identifier\") {\n throw new Error(\"expected agent function name identifier argument for attribute\");\n }\n\n // Any attribute arguments (other than the expected call identifier) must have a type of string, number, boolean or null.\n attributeArguments\n .filter((arg) => arg.type === \"identifier\")\n .forEach((arg) => {\n throw new Error(\n `invalid attribute argument value '${arg.value}', must be string, number, boolean or null`\n );\n });\n\n // Create the attribute definition and add it to the object of attribute definitions found.\n attributes[nextAttributeName] = {\n call: attributeCallIdentifier.value,\n args: attributeArguments.map(({ value }) => value)\n };\n\n // Try to get the next attribute name token, as there could be multiple.\n nextAttributeName = tokens[0]?.toLowerCase() as keyof NodeAttributes;\n }\n\n return attributes;\n}\n", "import {\n ActionNodeDefinition,\n AnyChildNodeDefinition,\n AnyNodeDefinition,\n BranchNodeDefinition,\n ConditionNodeDefinition,\n FailNodeDefinition,\n FlipNodeDefinition,\n LottoNodeDefinition,\n ParallelNodeDefinition,\n RepeatNodeDefinition,\n RetryNodeDefinition,\n RootNodeDefinition,\n SelectorNodeDefinition,\n SequenceNodeDefinition,\n SucceedNodeDefinition,\n WaitNodeDefinition\n} from \"../BehaviourTreeDefinition\";\nimport {\n isCompositeNode,\n isDecoratorNode,\n isLeafNode,\n isNullOrUndefined,\n isRootNode\n} from \"../BehaviourTreeDefinitionUtilities\";\nimport { parseArgumentTokens } from \"./MDSLNodeArgumentParser\";\nimport { parseAttributeTokens } from \"./MDSLNodeAttributeParser\";\nimport {\n StringLiteralPlaceholders,\n parseTokensFromDefinition,\n popAndCheck,\n substituteStringLiterals\n} from \"./MDSLUtilities\";\n\n/**\n * Convert the MDSL tree definition string into an equivalent JSON definition.\n * @param definition The tree definition string as MDSL.\n * @returns The root node JSON definitions.\n */\nexport function convertMDSLToJSON(definition: string): RootNodeDefinition[] {\n // Swap out any node/attribute argument string literals with a placeholder and get a mapping of placeholders to original values as well as the processed definition.\n const { placeholders, processedDefinition } = substituteStringLiterals(definition);\n\n // Parse our definition definition string into an array of raw tokens.\n const tokens = parseTokensFromDefinition(processedDefinition);\n\n return convertTokensToJSONDefinition(tokens, placeholders);\n}\n\n/**\n * Converts the specified tree definition tokens into a JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The root node JSON definitions.\n */\nfunction convertTokensToJSONDefinition(\n tokens: string[],\n stringLiteralPlaceholders: StringLiteralPlaceholders\n): RootNodeDefinition[] {\n // There must be at least 3 tokens for the tree definition to be valid. 'ROOT', '{' and '}'.\n if (tokens.length < 3) {\n throw new Error(\"invalid token count\");\n }\n\n // We should have a matching number of '{' and '}' tokens. If not, then there are scopes that have not been properly closed.\n if (tokens.filter((token) => token === \"{\").length !== tokens.filter((token) => token === \"}\").length) {\n throw new Error(\"scope character mismatch\");\n }\n\n // Create an array of tree stack arrays where root nodes will always be at the botton and the current composite/decorator node at the top.\n // There should be an element in this array for every root node defined and every element should be an array with a root note as the first element.\n // E.g. A definition with two root nodes defined:\n // [\n // [root, lotto, sequence],\n // [root, selector]\n // ]\n const treeStacks: [Partial, ...Partial[]][] = [];\n\n // Create an array of all root node definitions that we create.\n const rootNodes: Partial[] = [];\n\n // A helper function used to push node definitions onto the tree stack.\n const pushNode = (node: AnyNodeDefinition) => {\n // If the node is a root node then we need to create a new tree stack array with the root node at the root.\n if (isRootNode(node)) {\n // We need to double-check that this root node is not the child of another node.\n // We can do this by checking whether the top tree stack is not empty (contains an existing node)\n if (treeStacks[treeStacks.length - 1]?.length) {\n throw new Error(\"a root node cannot be the child of another node\");\n }\n\n // Add the root node definition to our array of all parsed root node definitions.\n rootNodes.push(node);\n\n // Add the root node definition to the root of a new tree stack.\n treeStacks.push([node]);\n\n return;\n }\n\n // All non-root nodes should be pushed after their root nodes so handle cases\n // where we may not have any tree stacks or our top-most tree stack is empty.\n if (!treeStacks.length || !treeStacks[treeStacks.length - 1].length) {\n throw new Error(\"expected root node at base of definition\");\n }\n\n // Get the current tree stack that we are populating.\n const topTreeStack = treeStacks[treeStacks.length - 1];\n\n // Get the top-most node in the current tree stack, this will be a composite/decorator node\n // for which we will populate its children array if composite or setting its child if a decorator.\n const topTreeStackTopNode = topTreeStack[topTreeStack.length - 1] as AnyNodeDefinition;\n\n // If the top-most node in the current root stack is a composite or decorator\n // node then the current node should be added as a child of the top-most node.\n if (isCompositeNode(topTreeStackTopNode)) {\n topTreeStackTopNode.children = topTreeStackTopNode.children || [];\n topTreeStackTopNode.children.push(node);\n } else if (isDecoratorNode(topTreeStackTopNode)) {\n // If the top node already has a child node set then throw an error as a decorator should only have a single child.\n if (topTreeStackTopNode.child) {\n throw new Error(\"a decorator node must only have a single child node\");\n }\n\n topTreeStackTopNode.child = node;\n }\n\n // If the node we are adding is also a composite or decorator node, then we should push it\n // onto the current tree stack, as subsequent nodes will be added as its child/children.\n if (!isLeafNode(node)) {\n topTreeStack.push(node);\n }\n };\n\n // A helper function used to pop the top-most node definition off of the tree stack and return it.\n const popNode = (): AnyNodeDefinition | null => {\n let poppedNode: AnyNodeDefinition | null = null;\n\n // Get the current tree stack that we are populating.\n const topTreeStack = treeStacks[treeStacks.length - 1];\n\n // Pop the top-most node in the current tree stack if there is one.\n if (topTreeStack.length) {\n poppedNode = topTreeStack.pop() as AnyNodeDefinition;\n }\n\n // We don't want any empty tree stacks in our stack of tree stacks.\n if (!topTreeStack.length) {\n treeStacks.pop();\n }\n\n return poppedNode;\n };\n\n // We should keep processing the raw tokens until we run out of them.\n while (tokens.length) {\n // Grab the next token.\n const token = tokens.shift()!;\n\n // How we create the next node depends on the current raw token value.\n switch (token.toUpperCase()) {\n case \"ROOT\": {\n pushNode(createRootNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"SUCCEED\": {\n pushNode(createSucceedNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"FAIL\": {\n pushNode(createFailNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"FLIP\": {\n pushNode(createFlipNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"REPEAT\": {\n pushNode(createRepeatNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"RETRY\": {\n pushNode(createRetryNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"SEQUENCE\": {\n pushNode(createSequenceNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"SELECTOR\": {\n pushNode(createSelectorNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"PARALLEL\": {\n pushNode(createParallelNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"LOTTO\": {\n pushNode(createLottoNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"ACTION\": {\n pushNode(createActionNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"CONDITION\": {\n pushNode(createConditionNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"WAIT\": {\n pushNode(createWaitNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"BRANCH\": {\n pushNode(createBranchNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"}\": {\n // The '}' character closes the current scope and means that we have to pop a node off of the current stack.\n const poppedNode = popNode();\n\n // Now that we have a node definition we can carry out any validation that may require the node to be fully populated.\n if (poppedNode) {\n validatePoppedNode(poppedNode);\n }\n\n break;\n }\n\n default: {\n throw new Error(`unexpected token: ${token}`);\n }\n }\n }\n\n return rootNodes as RootNodeDefinition[];\n}\n\n/**\n * Creates a root node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The root node JSON definition.\n */\nfunction createRootNode(tokens: string[], stringLiteralPlaceholders: StringLiteralPlaceholders): RootNodeDefinition {\n // Create the root node definition.\n let node = {\n type: \"root\",\n id: undefined\n } as RootNodeDefinition;\n\n // Parse any node arguments, we should only have one if any which will be an identifier argument for the root identifier.\n const nodeArguments = parseArgumentTokens(tokens, stringLiteralPlaceholders);\n\n // Check whether any node arguments were defined.\n if (nodeArguments.length) {\n // We should only have one argument, if any, which will be an identifier argument for the root identifier.\n if (nodeArguments.length === 1 && nodeArguments[0].type === \"identifier\") {\n // The root node identifier will be the first and only node argument value.\n node.id = nodeArguments[0].value as string;\n } else {\n throw new Error(\"expected single root name argument\");\n }\n }\n\n // Grab any node attribute definitions and spread them into the node definition.\n node = { ...node, ...parseAttributeTokens(tokens, stringLiteralPlaceholders) };\n\n // This is a decorator node, so we expect an opening '{'.\n popAndCheck(tokens, \"{\");\n\n // Return the root node definition.\n return node;\n}\n\n/**\n * Creates a succeed node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The succeed node JSON definition.\n */\nfunction createSucceedNode(\n tokens: string[],\n stringLiteralPlaceholders: StringLiteralPlaceholders\n): SucceedNodeDefinition {\n const node = {\n type: \"succeed\",\n ...parseAttributeTokens(tokens, stringLiteralPlaceholders)\n } as SucceedNodeDefinition;\n\n // This is a decorator node, so we expect an opening '{'.\n popAndCheck(tokens, \"{\");\n\n // Return the succeed node definition.\n return node;\n}\n\n/**\n * Creates a fail node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The fail node JSON definition.\n */\nfunction createFailNode(tokens: string[], stringLiteralPlaceholders: StringLiteralPlaceholders): FailNodeDefinition {\n const node = {\n type: \"fail\",\n ...parseAttributeTokens(tokens, stringLiteralPlaceholders)\n } as FailNodeDefinition;\n\n // This is a decorator node, so we expect an opening '{'.\n popAndCheck(tokens, \"{\");\n\n // Return the fail node definition.\n return node;\n}\n\n/**\n * Creates a flip node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The flip node JSON definition.\n */\nfunction createFlipNode(tokens: string[], stringLiteralPlaceholders: StringLiteralPlaceholders): FlipNodeDefinition {\n const node = {\n type: \"flip\",\n ...parseAttributeTokens(tokens, stringLiteralPlaceholders)\n } as FlipNodeDefinition;\n\n // This is a decorator node, so we expect an opening '{'.\n popAndCheck(tokens, \"{\");\n\n // Return the flip node definition.\n return node;\n}\n\n/**\n * Creates a repeat node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The repeat node JSON definition.\n */\nfunction createRepeatNode(\n tokens: string[],\n stringLiteralPlaceholders: StringLiteralPlaceholders\n): RepeatNodeDefinition {\n let node = { type: \"repeat\" } as RepeatNodeDefinition;\n\n // Get the node arguments.\n const nodeArguments = parseArgumentTokens(tokens, stringLiteralPlaceholders);\n\n // The arguments of a repeat node are optional. We may have:\n // - No node arguments, in which case the repeat note will iterate indefinitely.\n // - One node argument which will be the explicit number of iterations to make.\n // - Two node arguments which define the min and max iteration bounds from which a random iteration count will be picked.\n if (nodeArguments.length) {\n // All repeat node arguments MUST be of type number and must be integer.\n nodeArguments\n .filter((arg) => arg.type !== \"number\" || !arg.isInteger)\n .forEach(() => {\n throw new Error(`repeat node iteration counts must be integer values`);\n });\n\n // We should have got one or two iteration counts.\n if (nodeArguments.length === 1) {\n // A static iteration count was defined.\n node.iterations = nodeArguments[0].value as number;\n\n // A repeat node must have a positive number of iterations if defined.\n if (node.iterations < 0) {\n throw new Error(\"a repeat node must have a positive number of iterations if defined\");\n }\n } else if (nodeArguments.length === 2) {\n // A minimum and maximum iteration count was defined.\n node.iterations = [nodeArguments[0].value as number, nodeArguments[1].value as number];\n\n // A repeat node must have a positive min and max iteration count if they are defined.\n if (node.iterations[0] < 0 || node.iterations[1] < 0) {\n throw new Error(\"a repeat node must have a positive minimum and maximum iteration count if defined\");\n }\n\n // A repeat node must not have an minimum iteration count that exceeds the maximum iteration count.\n if (node.iterations[0] > node.iterations[1]) {\n throw new Error(\n \"a repeat node must not have a minimum iteration count that exceeds the maximum iteration count\"\n );\n }\n } else {\n // An incorrect number of iteration counts was defined.\n throw new Error(\"invalid number of repeat node iteration count arguments defined\");\n }\n }\n\n // Grab any node attribute definitions and spread them into the node definition.\n node = { ...node, ...parseAttributeTokens(tokens, stringLiteralPlaceholders) };\n\n // This is a decorator node, so we expect an opening '{'.\n popAndCheck(tokens, \"{\");\n\n // Return the repeat node definition.\n return node;\n}\n\n/**\n * Creates a retry node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The retry node JSON definition.\n */\nfunction createRetryNode(tokens: string[], stringLiteralPlaceholders: StringLiteralPlaceholders): RetryNodeDefinition {\n let node = { type: \"retry\" } as RetryNodeDefinition;\n\n // Get the node arguments.\n const nodeArguments = parseArgumentTokens(tokens, stringLiteralPlaceholders);\n\n // The arguments of a retry node are optional. We may have:\n // - No node arguments, in which case the retry note will attempt indefinitely.\n // - One node argument which will be the explicit number of attempts to make.\n // - Two node arguments which define the min and max attempt bounds from which a random attempt count will be picked.\n if (nodeArguments.length) {\n // All retry node arguments MUST be of type number and must be integer.\n nodeArguments\n .filter((arg) => arg.type !== \"number\" || !arg.isInteger)\n .forEach(() => {\n throw new Error(`retry node attempt counts must be integer values`);\n });\n\n // We should have got one or two attempt counts.\n if (nodeArguments.length === 1) {\n // A static attempt count was defined.\n node.attempts = nodeArguments[0].value as number;\n\n // A retry node must have a positive number of attempts if defined.\n if (node.attempts < 0) {\n throw new Error(\"a retry node must have a positive number of attempts if defined\");\n }\n } else if (nodeArguments.length === 2) {\n // A minimum and maximum attempt count was defined.\n node.attempts = [nodeArguments[0].value as number, nodeArguments[1].value as number];\n\n // A retry node must have a positive min and max attempts count if they are defined.\n if (node.attempts[0] < 0 || node.attempts[1] < 0) {\n throw new Error(\"a retry node must have a positive minimum and maximum attempt count if defined\");\n }\n\n // A retry node must not have a minimum attempt count that exceeds the maximum attempt count.\n if (node.attempts[0] > node.attempts[1]) {\n throw new Error(\n \"a retry node must not have a minimum attempt count that exceeds the maximum attempt count\"\n );\n }\n } else {\n // An incorrect number of attempt counts was defined.\n throw new Error(\"invalid number of retry node attempt count arguments defined\");\n }\n }\n\n // Grab any node attribute definitions and spread them into the node definition.\n node = { ...node, ...parseAttributeTokens(tokens, stringLiteralPlaceholders) };\n\n // This is a decorator node, so we expect an opening '{'.\n popAndCheck(tokens, \"{\");\n\n // Return the retry node definition.\n return node;\n}\n\n/**\n * Creates a sequence node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The sequence node JSON definition.\n */\nfunction createSequenceNode(\n tokens: string[],\n stringLiteralPlaceholders: StringLiteralPlaceholders\n): SequenceNodeDefinition {\n const node = {\n type: \"sequence\",\n ...parseAttributeTokens(tokens, stringLiteralPlaceholders)\n } as SequenceNodeDefinition;\n\n // This is a composite node, so we expect an opening '{'.\n popAndCheck(tokens, \"{\");\n\n // Return the sequence node definition.\n return node;\n}\n\n/**\n * Creates a selector node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The selector node JSON definition.\n */\nfunction createSelectorNode(\n tokens: string[],\n stringLiteralPlaceholders: StringLiteralPlaceholders\n): SelectorNodeDefinition {\n const node = {\n type: \"selector\",\n ...parseAttributeTokens(tokens, stringLiteralPlaceholders)\n } as SelectorNodeDefinition;\n\n // This is a composite node, so we expect an opening '{'.\n popAndCheck(tokens, \"{\");\n\n // Return the selector node definition.\n return node;\n}\n\n/**\n * Creates a parallel node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The parallel node JSON definition.\n */\nfunction createParallelNode(\n tokens: string[],\n stringLiteralPlaceholders: StringLiteralPlaceholders\n): ParallelNodeDefinition {\n const node = {\n type: \"parallel\",\n ...parseAttributeTokens(tokens, stringLiteralPlaceholders)\n } as ParallelNodeDefinition;\n\n // This is a composite node, so we expect an opening '{'.\n popAndCheck(tokens, \"{\");\n\n // Return the parallel node definition.\n return node;\n}\n\n/**\n * Creates a lotto node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The lotto node JSON definition.\n */\nfunction createLottoNode(tokens: string[], stringLiteralPlaceholders: StringLiteralPlaceholders): LottoNodeDefinition {\n // If any node arguments have been defined then they must be our weights.\n const nodeArguments = parseArgumentTokens(tokens, stringLiteralPlaceholders);\n\n // All lotto node arguments MUST be of type number and must be positive integers.\n nodeArguments\n .filter((arg) => arg.type !== \"number\" || !arg.isInteger || arg.value < 0)\n .forEach(() => {\n throw new Error(`lotto node weight arguments must be positive integer values`);\n });\n\n const node = {\n type: \"lotto\",\n weights: nodeArguments.length ? nodeArguments.map(({ value }) => value) : undefined,\n ...parseAttributeTokens(tokens, stringLiteralPlaceholders)\n } as LottoNodeDefinition;\n\n // This is a composite node, so we expect an opening '{'.\n popAndCheck(tokens, \"{\");\n\n // Return the lotto node definition.\n return node;\n}\n\n/**\n * Creates an action node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The action node JSON definition.\n */\nfunction createActionNode(\n tokens: string[],\n stringLiteralPlaceholders: StringLiteralPlaceholders\n): ActionNodeDefinition {\n // Parse any node arguments, we should have at least one which will be an identifier argument for the action name\n // and agent function to invoke for the action, all other arguments are to be passed as arguments to that function.\n const [actionNameIdentifier, ...agentFunctionArgs] = parseArgumentTokens(tokens, stringLiteralPlaceholders);\n\n // Our first argument MUST be defined and be an identifier as we require an action name argument.\n if (actionNameIdentifier?.type !== \"identifier\") {\n throw new Error(\"expected action name identifier argument\");\n }\n\n // Only the first argument should have been an identifier, all agent function arguments must be string, number, boolean or null.\n agentFunctionArgs\n .filter((arg) => arg.type === \"identifier\")\n .forEach((arg) => {\n throw new Error(\n `invalid action node argument value '${arg.value}', must be string, number, boolean or null`\n );\n });\n\n // Return the action node definition.\n return {\n type: \"action\",\n call: actionNameIdentifier.value,\n args: agentFunctionArgs.map(({ value }) => value),\n ...parseAttributeTokens(tokens, stringLiteralPlaceholders)\n };\n}\n\n/**\n * Creates a condition node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The condition node JSON definition.\n */\nfunction createConditionNode(\n tokens: string[],\n stringLiteralPlaceholders: StringLiteralPlaceholders\n): ConditionNodeDefinition {\n // Parse any node arguments, we should have at least one which will be an identifier argument for the condition name\n // and agent function to invoke for the condition, all other arguments are to be passed as arguments to that function.\n const [conditionNameIdentifier, ...agentFunctionArgs] = parseArgumentTokens(tokens, stringLiteralPlaceholders);\n\n // Our first argument MUST be defined and be an identifier as we require a condition name argument.\n if (conditionNameIdentifier?.type !== \"identifier\") {\n throw new Error(\"expected condition name identifier argument\");\n }\n\n // Only the first argument should have been an identifier, all agent function arguments must be string, number, boolean or null.\n agentFunctionArgs\n .filter((arg) => arg.type === \"identifier\")\n .forEach((arg) => {\n throw new Error(\n `invalid condition node argument value '${arg.value}', must be string, number, boolean or null`\n );\n });\n\n // Return the condition node definition.\n return {\n type: \"condition\",\n call: conditionNameIdentifier.value,\n args: agentFunctionArgs.map(({ value }) => value),\n ...parseAttributeTokens(tokens, stringLiteralPlaceholders)\n };\n}\n\n/**\n * Creates a wait node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The wait node JSON definition.\n */\nfunction createWaitNode(tokens: string[], stringLiteralPlaceholders: StringLiteralPlaceholders): WaitNodeDefinition {\n let node = { type: \"wait\" } as WaitNodeDefinition;\n\n // Get the node arguments.\n const nodeArguments = parseArgumentTokens(tokens, stringLiteralPlaceholders);\n\n // The arguments of a wait node are optional. We may have:\n // - No node arguments, in which case the wait will be indefinite until it is aborted.\n // - One node argument which will be the explicit duration of the wait.\n // - Two node arguments which define the min and max duration bounds from which a random duration will be picked.\n if (nodeArguments.length) {\n // All wait node arguments MUST be of type number and must be integer.\n nodeArguments\n .filter((arg) => arg.type !== \"number\" || !arg.isInteger)\n .forEach(() => {\n throw new Error(`wait node durations must be integer values`);\n });\n\n // We may have:\n // - One node argument which will be the explicit duration of the wait.\n // - Two node arguments which define the min and max duration bounds from which a random duration will be picked.\n // - Too many arguments, which is not valid.\n if (nodeArguments.length === 1) {\n // An explicit duration was defined.\n node.duration = nodeArguments[0].value as number;\n\n // If an explict duration was defined then it must be a positive number.\n if (node.duration < 0) {\n throw new Error(\"a wait node must have a positive duration\");\n }\n } else if (nodeArguments.length === 2) {\n // Min and max duration bounds were defined from which a random duration will be picked.\n node.duration = [nodeArguments[0].value as number, nodeArguments[1].value as number];\n\n // A wait node must have a positive min and max duration.\n if (node.duration[0] < 0 || node.duration[1] < 0) {\n throw new Error(\"a wait node must have a positive minimum and maximum duration\");\n }\n\n // A wait node must not have a minimum duration that exceeds the maximum duration.\n if (node.duration[0] > node.duration[1]) {\n throw new Error(\"a wait node must not have a minimum duration that exceeds the maximum duration\");\n }\n } else if (nodeArguments.length > 2) {\n // An incorrect number of duration arguments were defined.\n throw new Error(\"invalid number of wait node duration arguments defined\");\n }\n }\n\n // Return the wait node definition.\n return { ...node, ...parseAttributeTokens(tokens, stringLiteralPlaceholders) };\n}\n\n/**\n * Creates a branch node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The branch node JSON definition.\n */\nfunction createBranchNode(\n tokens: string[],\n stringLiteralPlaceholders: StringLiteralPlaceholders\n): BranchNodeDefinition {\n // Parse any node arguments, we should have one which will be an identifier argument for the root ref.\n const nodeArguments = parseArgumentTokens(tokens, stringLiteralPlaceholders);\n\n // We should have only a single identifer argument for a branch node, which is the root ref.\n if (nodeArguments.length !== 1 || nodeArguments[0].type !== \"identifier\") {\n throw new Error(\"expected single branch name argument\");\n }\n\n // Return the branch node definition.\n return { type: \"branch\", ref: nodeArguments[0].value };\n}\n\n/**\n * Validate a fully-populated node definition that was popped off of the tree stack.\n * @param definition The popped node to validate.\n */\nfunction validatePoppedNode(definition: AnyNodeDefinition): void {\n // Decorators MUST have a child defined.\n if (isDecoratorNode(definition) && isNullOrUndefined(definition.child)) {\n throw new Error(`a ${definition.type} node must have a single child node defined`);\n }\n\n // Composites MUST have at least one child defined.\n if (isCompositeNode(definition) && !definition.children?.length) {\n throw new Error(`a ${definition.type} node must have at least a single child node defined`);\n }\n\n // We need to make sure that lotto nodes that have weights defined have a number of weights matching the number of child nodes.\n if (definition.type === \"lotto\") {\n // Check whether a 'weights' property has been defined, if it has we expect it to be an array of weights.\n if (typeof definition.weights !== \"undefined\") {\n // Check that the weights property is an array of positive integers with an element for each child node element.\n if (definition.weights.length !== definition.children.length) {\n throw new Error(\n \"expected a number of weight arguments matching the number of child nodes for lotto node\"\n );\n }\n }\n }\n}\n", "import { RootNodeDefinition } from \"./BehaviourTreeDefinition\";\nimport { flattenDefinition, isBranchNode, isInteger } from \"./BehaviourTreeDefinitionUtilities\";\nimport { convertMDSLToJSON } from \"./mdsl/MDSLDefinitionParser\";\n\n/**\n * An object representing the result of validating a tree definition.\n */\nexport type DefinitionValidationResult = {\n /**\n * A flag defining whether validation succeeded.\n */\n succeeded: boolean;\n /**\n * A string containing the error message if validation did not succeed.\n */\n errorMessage?: string;\n /**\n * The definition as json if the validation was successful, or undefined if validation did not succeed.\n */\n json?: RootNodeDefinition[];\n};\n\n/**\n * Validates the specified behaviour tree definition in the form of JSON or MDSL, not taking any globally registered subtrees into consideration.\n * @param definition The behaviour tree definition in the form of JSON or MDSL.\n * @returns An object representing the result of validating the given tree definition.\n */\nexport function validateDefinition(definition: any): DefinitionValidationResult {\n // The definition must be defined.\n if (definition === null || typeof definition === \"undefined\") {\n return createValidationFailureResult(\"definition is null or undefined\");\n }\n\n // We are expecting a definition in one of three different forms:\n // - A string which we will assume is MDSL and we will parse this to JSON before validation.\n // - An array which we will assume is an array of root node definitions with at least one being the primary root node (no 'id' property)\n // - An object which we will assume is the primary root node and should not have an 'id' property.\n if (typeof definition === \"string\") {\n // The definition is a string which we can assume is MDSL, so attempt to validate it.\n return validateMDSLDefinition(definition);\n } else if (typeof definition === \"object\") {\n // The definition will either be an array (of root node definitions) or an object (the single primary root node definition).\n return validateJSONDefinition(definition);\n } else {\n return createValidationFailureResult(`unexpected definition type of '${typeof definition}'`);\n }\n}\n\n/**\n * Validates the specified behaviour tree definition in the form of MDSL.\n * @param definition The behaviour tree definition in the form of MDSL.\n * @returns An object representing the result of validating the given tree definition.\n */\nfunction validateMDSLDefinition(definition: string): DefinitionValidationResult {\n let rootNodeDefinitions;\n\n // The first thing the we need to do is to attempt to convert our MDSL into JSON.\n try {\n // The definition is a string which we can assume is MDSL, so attempt to parse it to a JSON definition in the form of an array of root node definitions.\n rootNodeDefinitions = convertMDSLToJSON(definition);\n } catch (exception) {\n // We failed to parse the JSON from the MDSL, this is likely to be the result of it not being a valid MDSL string.\n return createValidationFailureResult((exception as Error).message);\n }\n\n // Unpack all of the root node definitions into arrays of main ('id' defined) and sub ('id' not defined) root node definitions.\n const mainRootNodeDefinitions = rootNodeDefinitions.filter(({ id }) => typeof id === \"undefined\");\n const subRootNodeDefinitions = rootNodeDefinitions.filter(({ id }) => typeof id === \"string\" && id.length > 0);\n\n // We should ALWAYS have exactly one root node definition without an 'id' property defined, which is out main root node definition.\n if (mainRootNodeDefinitions.length !== 1) {\n return createValidationFailureResult(\n \"expected single unnamed root node at base of definition to act as main root\"\n );\n }\n\n // We should never have duplicate 'id' properties across our sub root node definitions.\n const subRootNodeIdenitifers: string[] = [];\n for (const { id } of subRootNodeDefinitions) {\n // Have we already come across this 'id' property value?\n if (subRootNodeIdenitifers.includes(id!)) {\n return createValidationFailureResult(`multiple root nodes found with duplicate name '${id}'`);\n }\n\n subRootNodeIdenitifers.push(id!);\n }\n\n try {\n // Validate our branch -> subtree links and check for any circular dependencies, we don't care about checking for broken subtree links here.\n validateBranchSubtreeLinks(rootNodeDefinitions, false);\n } catch (exception) {\n return createValidationFailureResult((exception as Error).message);\n }\n\n // Our definition was valid!\n return {\n succeeded: true,\n json: rootNodeDefinitions\n };\n}\n\n/**\n * Validates the specified behaviour tree definition in the form of JSON.\n * @param definition The behaviour tree definition in the form of JSON.\n * @returns An object representing the result of validating the given tree definition.\n */\nexport function validateJSONDefinition(\n definition: RootNodeDefinition | RootNodeDefinition[]\n): DefinitionValidationResult {\n // The definition will either be an array (of root node definitions) or an object (the single primary root node definition).\n const rootNodeDefinitions = Array.isArray(definition) ? definition : [definition];\n\n // Iterate over our array of root nodes and call validateNode for each, passing an initial depth of 0, wrapped in a try catch to handle validation failures.\n try {\n rootNodeDefinitions.forEach((rootNodeDefinition) => validateNode(rootNodeDefinition, 0));\n } catch (error) {\n // Handle cases where we have caught a thrown Error and return a failure result with the error message.\n if (error instanceof Error) {\n return createValidationFailureResult(error.message);\n }\n\n // No idea what happened here!\n return createValidationFailureResult(`unexpected error: ${error}`);\n }\n\n // Unpack all of the root node definitions into arrays of main ('id' defined) and sub ('id' not defined) root node definitions.\n const mainRootNodeDefinitions = rootNodeDefinitions.filter(({ id }) => typeof id === \"undefined\");\n const subRootNodeDefinitions = rootNodeDefinitions.filter(({ id }) => typeof id === \"string\" && id.length > 0);\n\n // We should ALWAYS have exactly one root node definition without an 'id' property defined, which is out main root node definition.\n if (mainRootNodeDefinitions.length !== 1) {\n return createValidationFailureResult(\n \"expected single root node without 'id' property defined to act as main root\"\n );\n }\n\n // We should never have duplicate 'id' properties across our sub root node definitions.\n const subRootNodeIdenitifers: string[] = [];\n for (const { id } of subRootNodeDefinitions) {\n // Have we already come across this 'id' property value?\n if (subRootNodeIdenitifers.includes(id!)) {\n return createValidationFailureResult(\n `multiple root nodes found with duplicate 'id' property value of '${id}'`\n );\n }\n\n subRootNodeIdenitifers.push(id!);\n }\n\n try {\n // Validate our branch -> subtree links and check for any circular dependencies, we don't care about checking for broken subtree links here.\n validateBranchSubtreeLinks(rootNodeDefinitions, false);\n } catch (exception) {\n return createValidationFailureResult((exception as Error).message);\n }\n\n // Our definition was valid!\n return {\n succeeded: true,\n json: rootNodeDefinitions\n };\n}\n\n/**\n * Validates the branch -> subtree links across all provided root node definitions.\n * This will not consider branch nodes that reference any globally registered subtrees unless includesGlobalSubtrees\n * is set to true, in which case we will also verify that there are no broken branch -> subtree links.\n * @param rootNodeDefinitions The array of root node definitions.\n * @param includesGlobalSubtrees A flag defining whether the array includes all global subtree root node definitions.\n */\nexport function validateBranchSubtreeLinks(rootNodeDefinitions: RootNodeDefinition[], includesGlobalSubtrees: boolean) {\n // Create a mapping of root node identifiers to other root nodes that they reference via branch nodes.\n // Below is an example of a mapping that includes a circular dependency (root => a => b => c => a)\n // [{ refs: [\"a\", \"b\"] }, { id: \"a\", refs: [\"b\"] }, { id: \"b\", refs: [\"c\"] }, { id: \"c\", refs: [\"a\"] }]\n const rootNodeMappings: { id: string | undefined; refs: string[] }[] = rootNodeDefinitions.map(\n (rootNodeDefinition) => ({\n id: rootNodeDefinition.id,\n refs: flattenDefinition(rootNodeDefinition)\n .filter(isBranchNode)\n .map(({ ref }) => ref)\n })\n );\n\n // A recursive function to walk through the mappings, keeping track of which root nodes we have visited in the form of a path of root node identifiers.\n const followRefs = (mapping: { id: string | undefined; refs: string[] }, path: (string | undefined)[] = []) => {\n // Have we found a circular dependency?\n if (path.includes(mapping.id)) {\n // We found a circular dependency! Get the bad path of root node identifiers.\n const badPath = [...path, mapping.id];\n\n // Create the formatted path value. [undefined, \"a\", \"b\", \"c\", \"a\"] would be formatted as \"a -> b -> c -> a\".\n const badPathFormatted = badPath.filter((element) => !!element).join(\" => \");\n\n // No need to continue, we found a circular dependency.\n throw new Error(`circular dependency found in branch node references: ${badPathFormatted}`);\n }\n\n for (const ref of mapping.refs) {\n // Find the mapping for the root node with an identifer matching the current ref.\n const subMapping = rootNodeMappings.find(({ id }) => id === ref);\n\n // We may not have a mapping for this ref, which is normal when we aren't considering all globally registered subtrees.\n if (subMapping) {\n followRefs(subMapping, [...path, mapping.id]);\n } else if (includesGlobalSubtrees) {\n // We found a reference to a root node that doesn't exist, which is a problem seeing as the root node definitons includes all globally registered subtrees.\n throw new Error(\n mapping.id\n ? `subtree '${mapping.id}' has branch node that references root node '${ref}' which has not been defined`\n : `primary tree has branch node that references root node '${ref}' which has not been defined`\n );\n }\n }\n };\n\n // Start looking for circular dependencies and broken references from the primary root node definition.\n followRefs(rootNodeMappings.find((mapping) => typeof mapping.id === \"undefined\")!);\n}\n\n/**\n * Validate an object that we expect to be a node definition.\n * @param definition An object that we expect to be a node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateNode(definition: any, depth: number): void {\n // Every node must be valid object and have a non-empty 'type' string property.\n if (typeof definition !== \"object\" || typeof definition.type !== \"string\" || definition.type.length === 0) {\n throw new Error(\n `node definition is not an object or 'type' property is not a non-empty string at depth '${depth}'`\n );\n }\n\n // How we validate this node definition will depend on its type.\n switch (definition.type) {\n case \"action\":\n validateActionNode(definition, depth);\n break;\n\n case \"condition\":\n validateConditionNode(definition, depth);\n break;\n\n case \"wait\":\n validateWaitNode(definition, depth);\n break;\n\n case \"branch\":\n validateBranchNode(definition, depth);\n break;\n\n case \"root\":\n validateRootNode(definition, depth);\n break;\n\n case \"succeed\":\n validateSucceedNode(definition, depth);\n break;\n\n case \"fail\":\n validateFailNode(definition, depth);\n break;\n\n case \"flip\":\n validateFlipNode(definition, depth);\n break;\n\n case \"repeat\":\n validateRepeatNode(definition, depth);\n break;\n\n case \"retry\":\n validateRetryNode(definition, depth);\n break;\n\n case \"sequence\":\n validateSequenceNode(definition, depth);\n break;\n\n case \"selector\":\n validateSelectorNode(definition, depth);\n break;\n\n case \"parallel\":\n validateParallelNode(definition, depth);\n break;\n\n case \"lotto\":\n validateLottoNode(definition, depth);\n break;\n\n default:\n throw new Error(`unexpected node type of '${definition.type}' at depth '${depth}'`);\n }\n}\n\n/**\n * Validate any attributes for a given node definition.\n * @param definition The node definition.\n * @param depth The depth of the node in the behaviour tree definition.\n */\nfunction validateNodeAttributes(definition: any, depth: number): void {\n // Validate each of the attribute types for this node.\n [\"while\", \"until\", \"entry\", \"exit\", \"step\"].forEach((attributeName) => {\n // Attempt to grab the definition for the current attribute from the node definition.\n const attributeDefinition = definition[attributeName];\n\n // All node attributes are optional, so there is nothing to do if the current attribute is not defined.\n if (typeof attributeDefinition === \"undefined\") {\n return;\n }\n\n // The attribute definition must be an object.\n if (typeof attributeDefinition !== \"object\") {\n throw new Error(\n `expected attribute '${attributeName}' to be an object for '${definition.type}' node at depth '${depth}'`\n );\n }\n\n // The 'call' property must be defined for any attribute definition.\n if (typeof attributeDefinition.call !== \"string\" || attributeDefinition.call.length === 0) {\n throw new Error(\n `expected 'call' property for attribute '${attributeName}' to be a non-empty string for '${definition.type}' node at depth '${depth}'`\n );\n }\n\n // If any node attribute arguments have been defined then they must have been defined in an array.\n if (typeof attributeDefinition.args !== \"undefined\" && !Array.isArray(attributeDefinition.args)) {\n throw new Error(\n `expected 'args' property for attribute '${attributeName}' to be an array for '${definition.type}' node at depth '${depth}'`\n );\n }\n });\n}\n\n/**\n * Validate an object that we expect to be a root node definition.\n * @param definition An object that we expect to be a root node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateRootNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"root\") {\n throw new Error(\"expected node type of 'root' for root node\");\n }\n\n // A root node cannot be the child of another node.\n if (depth > 0) {\n throw new Error(\"a root node cannot be the child of another node\");\n }\n\n // Check that, if the root node 'id' property is defined, it is a non-empty string.\n if (typeof definition.id !== \"undefined\" && (typeof definition.id !== \"string\" || definition.id.length === 0)) {\n throw new Error(\"expected non-empty string for 'id' property if defined for root node\");\n }\n\n // A root node is a decorator node, so must have a child node defined.\n if (typeof definition.child === \"undefined\") {\n throw new Error(\"expected property 'child' to be defined for root node\");\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n\n // Validate the child node of this decorator node.\n validateNode(definition.child, depth + 1);\n}\n\n/**\n * Validate an object that we expect to be a succeed node definition.\n * @param definition An object that we expect to be a succeed node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateSucceedNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"succeed\") {\n throw new Error(`expected node type of 'succeed' for succeed node at depth '${depth}'`);\n }\n\n // A succeed node is a decorator node, so must have a child node defined.\n if (typeof definition.child === \"undefined\") {\n throw new Error(`expected property 'child' to be defined for succeed node at depth '${depth}'`);\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n\n // Validate the child node of this decorator node.\n validateNode(definition.child, depth + 1);\n}\n\n/**\n * Validate an object that we expect to be a fail node definition.\n * @param definition An object that we expect to be a fail node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateFailNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"fail\") {\n throw new Error(`expected node type of 'fail' for fail node at depth '${depth}'`);\n }\n\n // A fail node is a decorator node, so must have a child node defined.\n if (typeof definition.child === \"undefined\") {\n throw new Error(`expected property 'child' to be defined for fail node at depth '${depth}'`);\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n\n // Validate the child node of this decorator node.\n validateNode(definition.child, depth + 1);\n}\n\n/**\n * Validate an object that we expect to be a flip node definition.\n * @param definition An object that we expect to be a flip node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateFlipNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"flip\") {\n throw new Error(`expected node type of 'flip' for flip node at depth '${depth}'`);\n }\n\n // A flip node is a decorator node, so must have a child node defined.\n if (typeof definition.child === \"undefined\") {\n throw new Error(`expected property 'child' to be defined for flip node at depth '${depth}'`);\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n\n // Validate the child node of this decorator node.\n validateNode(definition.child, depth + 1);\n}\n\n/**\n * Validate an object that we expect to be a repeat node definition.\n * @param definition An object that we expect to be a repeat node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateRepeatNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"repeat\") {\n throw new Error(`expected node type of 'repeat' for repeat node at depth '${depth}'`);\n }\n\n // A repeat node is a decorator node, so must have a child node defined.\n if (typeof definition.child === \"undefined\") {\n throw new Error(`expected property 'child' to be defined for repeat node at depth '${depth}'`);\n }\n\n // Check whether an 'iterations' property has been defined, it may not have been if this node is to repeat indefinitely.\n if (typeof definition.iterations !== \"undefined\") {\n if (Array.isArray(definition.iterations)) {\n // Check whether any elements of the array are not integer values.\n const containsNonInteger = !!definition.iterations.filter((value: unknown) => !isInteger(value)).length;\n\n // If the 'iterations' property is an array then it MUST contain two integer values.\n if (definition.iterations.length !== 2 || containsNonInteger) {\n throw new Error(\n `expected array containing two integer values for 'iterations' property if defined for repeat node at depth '${depth}'`\n );\n }\n\n // A repeat node must have a positive min and max iterations count if they are defined.\n if (definition.iterations[0] < 0 || definition.iterations[1] < 0) {\n throw new Error(\n `expected positive minimum and maximum iterations count for 'iterations' property if defined for repeat node at depth '${depth}'`\n );\n }\n\n // A repeat node must not have a minimum iterations count that exceeds the maximum iterations count.\n if (definition.iterations[0] > definition.iterations[1]) {\n throw new Error(\n `expected minimum iterations count that does not exceed the maximum iterations count for 'iterations' property if defined for repeat node at depth '${depth}'`\n );\n }\n } else if (isInteger(definition.iterations)) {\n // A repeat node must have a positive number of iterations if defined.\n if (definition.iterations < 0) {\n throw new Error(\n `expected positive iterations count for 'iterations' property if defined for repeat node at depth '${depth}'`\n );\n }\n } else {\n throw new Error(\n `expected integer value or array containing two integer values for 'iterations' property if defined for repeat node at depth '${depth}'`\n );\n }\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n\n // Validate the child node of this decorator node.\n validateNode(definition.child, depth + 1);\n}\n\n/**\n * Validate an object that we expect to be a retry node definition.\n * @param definition An object that we expect to be a retry node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateRetryNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"retry\") {\n throw new Error(`expected node type of 'retry' for retry node at depth '${depth}'`);\n }\n\n // A retry node is a decorator node, so must have a child node defined.\n if (typeof definition.child === \"undefined\") {\n throw new Error(`expected property 'child' to be defined for retry node at depth '${depth}'`);\n }\n\n // Check whether an 'attempts' property has been defined, it may not have been if this node is to retry indefinitely.\n if (typeof definition.attempts !== \"undefined\") {\n if (Array.isArray(definition.attempts)) {\n // Check whether any elements of the array are not integer values.\n const containsNonInteger = !!definition.attempts.filter((value: unknown) => !isInteger(value)).length;\n\n // If the 'attempts' property is an array then it MUST contain two integer values.\n if (definition.attempts.length !== 2 || containsNonInteger) {\n throw new Error(\n `expected array containing two integer values for 'attempts' property if defined for retry node at depth '${depth}'`\n );\n }\n\n // A retry node must have a positive min and max attempts count if they are defined.\n if (definition.attempts[0] < 0 || definition.attempts[1] < 0) {\n throw new Error(\n `expected positive minimum and maximum attempts count for 'attempts' property if defined for retry node at depth '${depth}'`\n );\n }\n\n // A retry node must not have a minimum attempts count that exceeds the maximum attempts count.\n if (definition.attempts[0] > definition.attempts[1]) {\n throw new Error(\n `expected minimum attempts count that does not exceed the maximum attempts count for 'attempts' property if defined for retry node at depth '${depth}'`\n );\n }\n } else if (isInteger(definition.attempts)) {\n // A retry node must have a positive number of attempts if defined.\n if (definition.attempts < 0) {\n throw new Error(\n `expected positive attempts count for 'attempts' property if defined for retry node at depth '${depth}'`\n );\n }\n } else {\n throw new Error(\n `expected integer value or array containing two integer values for 'attempts' property if defined for retry node at depth '${depth}'`\n );\n }\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n\n // Validate the child node of this decorator node.\n validateNode(definition.child, depth + 1);\n}\n\n/**\n * Validate an object that we expect to be a branch node definition.\n * @param definition An object that we expect to be a branch node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateBranchNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"branch\") {\n throw new Error(`expected node type of 'branch' for branch node at depth '${depth}'`);\n }\n\n // Check that the branch node 'ref' property is defined and is a non-empty string.\n if (typeof definition.ref !== \"string\" || definition.ref.length === 0) {\n throw new Error(`expected non-empty string for 'ref' property for branch node at depth '${depth}'`);\n }\n\n // It is invalid to define guard attributes for a branch node as they should be defined on the referenced root node.\n [\"while\", \"until\"].forEach((attributeName) => {\n if (typeof definition[attributeName] !== \"undefined\") {\n throw new Error(\n `guards should not be defined for branch nodes but guard '${attributeName}' was defined for branch node at depth '${depth}'`\n );\n }\n });\n\n // It is invalid to define callback attributes for a branch node as they should be defined on the referenced root node.\n [\"entry\", \"exit\", \"step\"].forEach((attributeName) => {\n if (typeof definition[attributeName] !== \"undefined\") {\n throw new Error(\n `callbacks should not be defined for branch nodes but callback '${attributeName}' was defined for branch node at depth '${depth}'`\n );\n }\n });\n}\n\n/**\n * Validate an object that we expect to be a action node definition.\n * @param definition An object that we expect to be a action node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateActionNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"action\") {\n throw new Error(`expected node type of 'action' for action node at depth '${depth}'`);\n }\n\n // The 'call' property must be defined for a action node definition.\n if (typeof definition.call !== \"string\" || definition.call.length === 0) {\n throw new Error(`expected non-empty string for 'call' property of action node at depth '${depth}'`);\n }\n\n // If any action function arguments have been defined then they must have been defined in an array.\n if (typeof definition.args !== \"undefined\" && !Array.isArray(definition.args)) {\n throw new Error(`expected array for 'args' property if defined for action node at depth '${depth}'`);\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n}\n\n/**\n * Validate an object that we expect to be a condition node definition.\n * @param definition An object that we expect to be a condition node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateConditionNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"condition\") {\n throw new Error(`expected node type of 'condition' for condition node at depth '${depth}'`);\n }\n\n // The 'call' property must be defined for a condition node definition.\n if (typeof definition.call !== \"string\" || definition.call.length === 0) {\n throw new Error(`expected non-empty string for 'call' property of condition node at depth '${depth}'`);\n }\n\n // If any condition function arguments have been defined then they must have been defined in an array.\n if (typeof definition.args !== \"undefined\" && !Array.isArray(definition.args)) {\n throw new Error(`expected array for 'args' property if defined for condition node at depth '${depth}'`);\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n}\n\n/**\n * Validate an object that we expect to be a wait node definition.\n * @param definition An object that we expect to be a wait node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateWaitNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"wait\") {\n throw new Error(`expected node type of 'wait' for wait node at depth '${depth}'`);\n }\n\n // Check whether a 'duration' property has been defined, it may not have been if this node is to wait indefinitely.\n if (typeof definition.duration !== \"undefined\") {\n if (Array.isArray(definition.duration)) {\n // Check whether any elements of the array are not integer values.\n const containsNonInteger = !!definition.duration.filter((value: unknown) => !isInteger(value)).length;\n\n // If the 'duration' property is an array then it MUST contain two integer values.\n if (definition.duration.length !== 2 || containsNonInteger) {\n throw new Error(\n `expected array containing two integer values for 'duration' property if defined for wait node at depth '${depth}'`\n );\n }\n\n // A wait node must have a positive min and max duration value if they are defined.\n if (definition.duration[0] < 0 || definition.duration[1] < 0) {\n throw new Error(\n `expected positive minimum and maximum duration for 'duration' property if defined for wait node at depth '${depth}'`\n );\n }\n\n // A wait node must not have a minimum duration value that exceeds the maximum duration value.\n if (definition.duration[0] > definition.duration[1]) {\n throw new Error(\n `expected minimum duration value that does not exceed the maximum duration value for 'duration' property if defined for wait node at depth '${depth}'`\n );\n }\n } else if (isInteger(definition.duration)) {\n // A wait node must have a positive duration value if defined.\n if (definition.duration < 0) {\n throw new Error(\n `expected positive duration value for 'duration' property if defined for wait node at depth '${depth}'`\n );\n }\n } else {\n throw new Error(\n `expected integer value or array containing two integer values for 'duration' property if defined for wait node at depth '${depth}'`\n );\n }\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n}\n\n/**\n * Validate an object that we expect to be a sequence node definition.\n * @param definition An object that we expect to be a sequence node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateSequenceNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"sequence\") {\n throw new Error(`expected node type of 'sequence' for sequence node at depth '${depth}'`);\n }\n\n // A sequence node is a composite node, so must have a children nodes array defined.\n if (!Array.isArray(definition.children) || definition.children.length === 0) {\n throw new Error(`expected non-empty 'children' array to be defined for sequence node at depth '${depth}'`);\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n\n // Validate the child nodes of this composite node.\n definition.children.forEach((child: any) => validateNode(child, depth + 1));\n}\n\n/**\n * Validate an object that we expect to be a selector node definition.\n * @param definition An object that we expect to be a selector node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateSelectorNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"selector\") {\n throw new Error(`expected node type of 'selector' for selector node at depth '${depth}'`);\n }\n\n // A selector node is a composite node, so must have a children nodes array defined.\n if (!Array.isArray(definition.children) || definition.children.length === 0) {\n throw new Error(`expected non-empty 'children' array to be defined for selector node at depth '${depth}'`);\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n\n // Validate the child nodes of this composite node.\n definition.children.forEach((child: any) => validateNode(child, depth + 1));\n}\n\n/**\n * Validate an object that we expect to be a parallel node definition.\n * @param definition An object that we expect to be a parallel node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateParallelNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"parallel\") {\n throw new Error(`expected node type of 'parallel' for parallel node at depth '${depth}'`);\n }\n\n // A parallel node is a composite node, so must have a children nodes array defined.\n if (!Array.isArray(definition.children) || definition.children.length === 0) {\n throw new Error(`expected non-empty 'children' array to be defined for parallel node at depth '${depth}'`);\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n\n // Validate the child nodes of this composite node.\n definition.children.forEach((child: any) => validateNode(child, depth + 1));\n}\n\n/**\n * Validate an object that we expect to be a lotto node definition.\n * @param definition An object that we expect to be a lotto node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateLottoNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"lotto\") {\n throw new Error(`expected node type of 'lotto' for lotto node at depth '${depth}'`);\n }\n\n // A lotto node is a composite node, so must have a children nodes array defined.\n if (!Array.isArray(definition.children) || definition.children.length === 0) {\n throw new Error(`expected non-empty 'children' array to be defined for lotto node at depth '${depth}'`);\n }\n\n // Check whether a 'weights' property has been defined, if it has we expect it to be an array of weights.\n if (typeof definition.weights !== \"undefined\") {\n // Check that the weights property is an array of positive integers with an element for each child node element.\n if (\n !Array.isArray(definition.weights) ||\n definition.weights.length !== definition.children.length ||\n definition.weights.filter((value: unknown) => !isInteger(value)).length ||\n definition.weights.filter((value: number) => value < 0).length\n ) {\n throw new Error(\n `expected an array of positive integer weight values with a length matching the number of child nodes for 'weights' property if defined for lotto node at depth '${depth}'`\n );\n }\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n\n // Validate the child nodes of this composite node.\n definition.children.forEach((child: any) => validateNode(child, depth + 1));\n}\n\n/**\n * A helper function to create a failure validation result with the given error message.\n * @param errorMessage The validation failure error message.\n * @returns A failure validation result with the given error message.\n */\nfunction createValidationFailureResult(errorMessage: string): DefinitionValidationResult {\n return { succeeded: false, errorMessage };\n}\n", "import { ActionResult, Agent, GlobalFunction } from \"./Agent\";\nimport { RootNodeDefinition } from \"./BehaviourTreeDefinition\";\n\nexport type InvokerFunction = (args: any[]) => ActionResult;\n\n/**\n * A singleton used to store and lookup registered functions and subtrees.\n */\nexport default class Lookup {\n /**\n * The object holding any registered functions keyed on function name.\n */\n private static functionTable: { [key: string]: GlobalFunction } = {};\n /**\n * The object holding any registered subtree root node definitions keyed on tree name.\n */\n private static subtreeTable: { [key: string]: RootNodeDefinition } = {};\n\n /**\n * Gets the function with the specified name.\n * @param name The name of the function.\n * @returns The function with the specified name.\n */\n public static getFunc(name: string): GlobalFunction {\n return this.functionTable[name];\n }\n\n /**\n * Sets the function with the specified name for later lookup.\n * @param name The name of the function.\n * @param func The function.\n */\n public static setFunc(name: string, func: GlobalFunction): void {\n this.functionTable[name] = func;\n }\n\n /**\n * Gets the function invoker for the specified agent and function name.\n * If a function with the specified name exists on the agent object then it will\n * be returned, otherwise we will then check the registered functions for a match.\n * @param agent The agent instance that this behaviour tree is modelling behaviour for.\n * @param name The function name.\n * @returns The function invoker for the specified agent and function name.\n */\n static getFuncInvoker(agent: Agent, name: string): InvokerFunction | null {\n // Check whether the agent contains the specified function.\n const foundOnAgent = agent[name];\n if (foundOnAgent && typeof foundOnAgent === \"function\") {\n return (args: any[]): boolean | ActionResult => foundOnAgent.apply(agent, args);\n }\n\n // The agent does not contain the specified function but it may have been registered at some point.\n if (this.functionTable[name] && typeof this.functionTable[name] === \"function\") {\n return (args: any[]) => this.functionTable[name](agent, ...args.map((arg) => arg.value));\n }\n\n // We have no function to invoke.\n return null;\n }\n\n /**\n * Gets all registered subtree root node definitions.\n */\n static getSubtrees(): { [key: string]: RootNodeDefinition } {\n return this.subtreeTable;\n }\n\n /**\n * Sets the subtree with the specified name for later lookup.\n * @param name The name of the subtree.\n * @param subtree The subtree.\n */\n static setSubtree(name: string, subtree: RootNodeDefinition) {\n this.subtreeTable[name] = subtree;\n }\n\n /**\n * Removes the registered function or subtree with the specified name.\n * @param name The name of the registered function or subtree.\n */\n static remove(name: string) {\n delete this.functionTable[name];\n delete this.subtreeTable[name];\n }\n\n /**\n * Remove all registered functions and subtrees.\n */\n static empty() {\n this.functionTable = {};\n this.subtreeTable = {};\n }\n}\n", "import Node from \"../../nodes/Node\";\n\n/**\n * An exception thrown when evaluating node guard path conditions and a conditions fails.\n */\nexport default class GuardUnsatisifedException extends Error {\n /**\n * @param source The node at which a guard condition failed.\n */\n constructor(private source: Node) {\n super(\"A guard path condition has failed\");\n }\n\n /**\n * Gets whether the specified node is the node at which a guard condition failed.\n * @param node The node to check against the source node.\n * @returns Whether the specified node is the node at which a guard condition failed.\n */\n isSourceNode = (node: Node) => node === this.source;\n}\n", "import { Agent } from \"../../Agent\";\nimport Guard from \"./Guard\";\nimport Node from \"../../nodes/Node\";\nimport GuardUnsatisifedException from \"./GuardUnsatisifedException\";\n\nexport type GuardPathPart = {\n node: Node;\n guards: Guard[];\n};\n\n/**\n * Represents a path of node guards along a root-to-leaf tree path.\n */\nexport default class GuardPath {\n /**\n * @param nodes An array of objects defining a node instance -> guard link, ordered by node depth.\n */\n constructor(private nodes: GuardPathPart[]) {}\n\n /**\n * Evaluate guard conditions for all guards in the tree path, moving outwards from the root.\n * @param agent The agent, required for guard evaluation.\n * @returns An evaluation results object.\n */\n evaluate = (agent: Agent) => {\n // We need to evaluate guard conditions for nodes up the tree, moving outwards from the root.\n for (const details of this.nodes) {\n // There can be multiple guards per node.\n for (const guard of details.guards) {\n // Check whether the guard condition passes, and throw an exception if not.\n if (!guard.isSatisfied(agent)) {\n throw new GuardUnsatisifedException(details.node);\n }\n }\n }\n };\n}\n", "import { BehaviourTreeOptions } from \"../BehaviourTreeOptions\";\nimport State, { AnyState } from \"../State\";\nimport { Agent } from \"../Agent\";\nimport Leaf from \"./leaf/Leaf\";\nimport Attribute from \"../attributes/Attribute\";\nimport Entry from \"../attributes/callbacks/Entry\";\nimport Exit from \"../attributes/callbacks/Exit\";\nimport Step from \"../attributes/callbacks/Step\";\nimport Guard from \"../attributes/guards/Guard\";\nimport GuardPath from \"../attributes/guards/GuardPath\";\nimport GuardUnsatisifedException from \"../attributes/guards/GuardUnsatisifedException\";\n\n/**\n * A base node.\n */\nexport default abstract class Node {\n /**\n * The node uid.\n */\n private readonly uid: string = createNodeUid();\n /**\n * The node state.\n */\n private state: AnyState = State.READY;\n /**\n * The guard path to evaluate as part of a node update.\n */\n private guardPath: GuardPath | undefined;\n\n /**\n * @param type The node type.\n * @param attributes The node attributes.\n * @param args The node argument definitions.\n */\n constructor(private type: string, private attributes: Attribute[], private args: any[]) {}\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected abstract onUpdate(agent: Agent, options: BehaviourTreeOptions): void;\n\n /**\n * Gets the name of the node.\n */\n public abstract getName(): string;\n\n /**\n * Gets whether this node is a leaf node.\n */\n public abstract isLeafNode: () => this is Leaf;\n\n /**\n * Gets/Sets the state of the node.\n */\n getState = (): AnyState => this.state;\n setState = (value: AnyState): void => {\n this.state = value;\n };\n\n /**\n * Gets the unique id of the node.\n */\n getUid = () => this.uid;\n\n /**\n * Gets the type of the node.\n */\n getType = () => this.type;\n\n /**\n * Gets the node attributes.\n */\n getAttributes = () => this.attributes;\n\n /**\n * Gets the node arguments.\n */\n getArguments = () => this.args;\n\n /**\n * Gets the node attribute with the specified type, or null if it does not exist.\n */\n getAttribute(type: \"entry\" | \"ENTRY\"): Entry;\n getAttribute(type: \"exit\" | \"EXIT\"): Exit;\n getAttribute(type: \"step\" | \"STEP\"): Step;\n getAttribute(type: string): Attribute {\n return (\n this.getAttributes().filter((decorator) => decorator.type.toUpperCase() === type.toUpperCase())[0] || null\n );\n }\n\n /**\n * Gets the node attributes.\n */\n getGuardAttributes = (): Guard[] => this.getAttributes().filter((decorator) => decorator.isGuard()) as Guard[];\n\n /**\n * Sets the guard path to evaluate as part of a node update.\n */\n setGuardPath = (value: GuardPath) => (this.guardPath = value);\n\n /**\n * Gets whether a guard path is assigned to this node.\n */\n hasGuardPath = () => !!this.guardPath;\n\n /**\n * Gets whether this node is in the specified state.\n * @param value The value to compare to the node state.\n */\n public is(value: AnyState): boolean {\n return this.state === value;\n }\n\n /**\n * Reset the state of the node.\n */\n public reset(): void {\n this.setState(State.READY);\n }\n\n /**\n * Abort the running of this node.\n * @param agent The agent.\n */\n public abort(agent: Agent): void {\n // There is nothing to do if this node is not in the running state.\n if (!this.is(State.RUNNING)) {\n return;\n }\n\n // Reset the state of this node.\n this.reset();\n\n this.getAttribute(\"exit\")?.callAgentFunction(agent, false, true);\n }\n\n /**\n * Update the node.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n * @returns The result of the update.\n */\n public update(agent: Agent, options: BehaviourTreeOptions): void {\n // If this node is already in a 'SUCCEEDED' or 'FAILED' state then there is nothing to do.\n if (this.is(State.SUCCEEDED) || this.is(State.FAILED)) {\n return;\n }\n\n try {\n // Evaluate all of the guard path conditions for the current tree path.\n this.guardPath!.evaluate(agent);\n\n // If this node is in the READY state then call the ENTRY for this node if it exists.\n if (this.is(State.READY)) {\n this.getAttribute(\"entry\")?.callAgentFunction(agent);\n }\n\n this.getAttribute(\"step\")?.callAgentFunction(agent);\n\n // Do the actual update.\n this.onUpdate(agent, options);\n\n // If this node is now in a 'SUCCEEDED' or 'FAILED' state then call the EXIT for this node if it exists.\n if (this.is(State.SUCCEEDED) || this.is(State.FAILED)) {\n this.getAttribute(\"exit\")?.callAgentFunction(agent, this.is(State.SUCCEEDED), false);\n }\n } catch (error) {\n // If the error is a GuardUnsatisfiedException then we need to determine if this node is the source.\n if (error instanceof GuardUnsatisifedException && error.isSourceNode(this)) {\n // Abort the current node.\n this.abort(agent);\n\n // Any node that is the source of an abort will be a failed node.\n this.setState(State.FAILED);\n } else {\n throw error;\n }\n }\n }\n}\n\n/**\n * Create a randomly generated node uid.\n * @returns A randomly generated node uid.\n */\nfunction createNodeUid(): string {\n var S4 = function () {\n return (((1 + Math.random()) * 0x10000) | 0).toString(16).substring(1);\n };\n return S4() + S4() + \"-\" + S4() + \"-\" + S4() + \"-\" + S4() + \"-\" + S4() + S4() + S4();\n}\n", "import Node from \"../Node\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\n\n/**\n * A composite node that wraps child nodes.\n */\nexport default abstract class Composite extends Node {\n /**\n * @param type The node type.\n * @param attributes The node attributes.\n * @param children The child nodes.\n */\n constructor(type: string, attributes: Attribute[], protected children: Node[]) {\n super(type, attributes, []);\n }\n\n /**\n * Gets whether this node is a leaf node.\n */\n isLeafNode = () => false;\n\n /**\n * Gets the children of this node.\n */\n getChildren = () => this.children;\n\n /**\n * Reset the state of the node.\n */\n reset = () => {\n // Reset the state of this node.\n this.setState(State.READY);\n\n // Reset the state of any child nodes.\n this.getChildren().forEach((child) => child.reset());\n };\n\n /**\n * Abort the running of this node.\n * @param agent The agent.\n */\n abort = (agent: Agent) => {\n // There is nothing to do if this node is not in the running state.\n if (!this.is(State.RUNNING)) {\n return;\n }\n\n // Abort any child nodes.\n this.getChildren().forEach((child) => child.abort(agent));\n\n // Reset the state of this node.\n this.reset();\n\n this.getAttribute(\"exit\")?.callAgentFunction(agent, false, true);\n };\n}\n", "import Composite from \"./Composite\";\nimport State from \"../../State\";\nimport Node from \"../Node\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A PARALLEL node.\n * The child nodes are executed concurrently until one fails or all succeed.\n */\nexport default class Parallel extends Composite {\n /**\n * @param attributes The node attributes.\n * @param children The child nodes.\n */\n constructor(attributes: Attribute[], children: Node[]) {\n super(\"parallel\", attributes, children);\n }\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // Keep a count of the number of succeeded child nodes.\n let succeededCount = 0;\n\n let hasChildFailed = false;\n\n // Iterate over all of the children of this node.\n for (const child of this.children) {\n // If the child has never been updated or is running then we will need to update it now.\n if (child.getState() === State.READY || child.getState() === State.RUNNING) {\n // Update the child of this node.\n child.update(agent, options);\n }\n\n // If the current child has a state of 'SUCCEEDED' then we should move on to the next child.\n if (child.getState() === State.SUCCEEDED) {\n // The child node has succeeded, keep track of this to determine if all children have.\n succeededCount++;\n\n // The child node succeeded, but we have not finished checking every child node yet.\n continue;\n }\n\n // If the current child has a state of 'FAILED' then this node is also a 'FAILED' node.\n if (child.getState() === State.FAILED) {\n hasChildFailed = true;\n\n // There is no need to check the rest of the children.\n break;\n }\n\n // The node should be in the 'RUNNING' state.\n if (child.getState() !== State.RUNNING) {\n // The child node was not in an expected state.\n throw new Error(\"child node was not in an expected state.\");\n }\n }\n\n if (hasChildFailed) {\n // This node is a 'FAILED' node.\n this.setState(State.FAILED);\n\n // Abort every running child.\n for (const child of this.children) {\n if (child.getState() === State.RUNNING) {\n child.abort(agent);\n }\n }\n } else {\n // If all children have succeeded then this node has also succeeded, otherwise it is still running.\n this.setState(succeededCount === this.children.length ? State.SUCCEEDED : State.RUNNING);\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => \"PARALLEL\";\n}\n", "import Composite from \"./Composite\";\nimport Node from \"../Node\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A SELECTOR node.\n * The child nodes are executed in sequence until one succeeds or all fail.\n */\nexport default class Selector extends Composite {\n /**\n * @param attributes The node attributes.\n * @param children The child nodes.\n */\n constructor(attributes: Attribute[], protected children: Node[]) {\n super(\"selector\", attributes, children);\n }\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // Iterate over all of the children of this node.\n for (const child of this.children) {\n // If the child has never been updated or is running then we will need to update it now.\n if (child.getState() === State.READY || child.getState() === State.RUNNING) {\n // Update the child of this node.\n child.update(agent, options);\n }\n\n // If the current child has a state of 'SUCCEEDED' then this node is also a 'SUCCEEDED' node.\n if (child.getState() === State.SUCCEEDED) {\n // This node is a 'SUCCEEDED' node.\n this.setState(State.SUCCEEDED);\n\n // There is no need to check the rest of the selector nodes.\n return;\n }\n\n // If the current child has a state of 'FAILED' then we should move on to the next child.\n if (child.getState() === State.FAILED) {\n // Find out if the current child is the last one in the selector.\n // If it is then this sequence node has also failed.\n if (this.children.indexOf(child) === this.children.length - 1) {\n // This node is a 'FAILED' node.\n this.setState(State.FAILED);\n\n // There is no need to check the rest of the selector as we have completed it.\n return;\n } else {\n // The child node failed, try the next one.\n continue;\n }\n }\n\n // The node should be in the 'RUNNING' state.\n if (child.getState() === State.RUNNING) {\n // This node is a 'RUNNING' node.\n this.setState(State.RUNNING);\n\n // There is no need to check the rest of the selector as the current child is still running.\n return;\n }\n\n // The child node was not in an expected state.\n throw new Error(\"child node was not in an expected state.\");\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => \"SELECTOR\";\n}\n", "import Composite from \"./Composite\";\nimport Node from \"../Node\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A SEQUENCE node.\n * The child nodes are executed in sequence until one fails or all succeed.\n */\nexport default class Sequence extends Composite {\n /**\n * @param attributes The node attributes.\n * @param children The child nodes.\n */\n constructor(attributes: Attribute[], protected children: Node[]) {\n super(\"sequence\", attributes, children);\n }\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // Iterate over all of the children of this node.\n for (const child of this.children) {\n // If the child has never been updated or is running then we will need to update it now.\n if (child.getState() === State.READY || child.getState() === State.RUNNING) {\n // Update the child of this node.\n child.update(agent, options);\n }\n\n // If the current child has a state of 'SUCCEEDED' then we should move on to the next child.\n if (child.getState() === State.SUCCEEDED) {\n // Find out if the current child is the last one in the sequence.\n // If it is then this sequence node has also succeeded.\n if (this.children.indexOf(child) === this.children.length - 1) {\n // This node is a 'SUCCEEDED' node.\n this.setState(State.SUCCEEDED);\n\n // There is no need to check the rest of the sequence as we have completed it.\n return;\n } else {\n // The child node succeeded, but we have not finished the sequence yet.\n continue;\n }\n }\n\n // If the current child has a state of 'FAILED' then this node is also a 'FAILED' node.\n if (child.getState() === State.FAILED) {\n // This node is a 'FAILED' node.\n this.setState(State.FAILED);\n\n // There is no need to check the rest of the sequence.\n return;\n }\n\n // The node should be in the 'RUNNING' state.\n if (child.getState() === State.RUNNING) {\n // This node is a 'RUNNING' node.\n this.setState(State.RUNNING);\n\n // There is no need to check the rest of the sequence as the current child is still running.\n return;\n }\n\n // The child node was not in an expected state.\n throw new Error(\"child node was not in an expected state.\");\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => \"SEQUENCE\";\n}\n", "import createLotto from \"lotto-draw\";\n\nimport Node from \"../Node\";\nimport Composite from \"./Composite\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A LOTTO node.\n * A winning child is picked on the initial update of this node, based on ticket weighting.\n * The state of this node will match the state of the winning child.\n */\nexport default class Lotto extends Composite {\n /**\n * @param attributes The node attributes.\n * @param weights The child node weights.\n * @param children The child nodes.\n */\n constructor(attributes: Attribute[], private weights: number[] | undefined, children: Node[]) {\n super(\"lotto\", attributes, children);\n }\n\n /**\n * The child node selected to be the active one.\n */\n private selectedChild: Node | undefined;\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // If this node is in the READY state then we need to pick a winning child node.\n if (this.is(State.READY)) {\n // Create a lotto draw with which to randomly pick a child node to become the active one.\n const lottoDraw = createLotto({\n // Hook up the optional 'random' behaviour tree function option to the one used by 'lotto-draw'.\n random: options.random,\n // Pass in each child node as a participant in the lotto draw with their respective ticket count.\n participants: this.children.map((child, index) => [child, this.weights?.[index] || 1])\n });\n\n // Randomly pick a child based on ticket weighting, this will become the active child for this composite node.\n this.selectedChild = lottoDraw.draw() || undefined;\n }\n\n // If something went wrong and we don't have an active child then we should throw an error.\n if (!this.selectedChild) {\n throw new Error(\"failed to update lotto node as it has no active child\");\n }\n\n // If the selected child has never been updated or is running then we will need to update it now.\n if (this.selectedChild.getState() === State.READY || this.selectedChild.getState() === State.RUNNING) {\n this.selectedChild.update(agent, options);\n }\n\n // The state of the lotto node is the state of its selected child.\n this.setState(this.selectedChild.getState());\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => (this.weights ? `LOTTO [${this.weights.join(\",\")}]` : \"LOTTO\");\n}\n", "import Node from \"../Node\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\n\n/**\n * A decorator node that wraps a single child node.\n */\nexport default abstract class Decorator extends Node {\n /**\n * @param type The node type.\n * @param attributes The node attributes.\n * @param child The child node.\n */\n constructor(type: string, attributes: Attribute[], protected child: Node) {\n super(type, attributes, []);\n }\n\n /**\n * Gets whether this node is a leaf node.\n */\n isLeafNode = () => false;\n\n /**\n * Gets the children of this node.\n */\n getChildren = () => [this.child];\n\n /**\n * Reset the state of the node.\n */\n reset = () => {\n // Reset the state of this node.\n this.setState(State.READY);\n\n // Reset the state of the child node.\n this.child.reset();\n };\n\n /**\n * Abort the running of this node.\n * @param agent The agent.\n */\n abort = (agent: Agent) => {\n // There is nothing to do if this node is not in the running state.\n if (!this.is(State.RUNNING)) {\n return;\n }\n\n // Abort the child node.\n this.child.abort(agent);\n\n // Reset the state of this node.\n this.reset();\n\n this.getAttribute(\"exit\")?.callAgentFunction(agent, false, true);\n };\n}\n", "import Node from \"../Node\";\nimport Decorator from \"./Decorator\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A Fail node.\n * This node wraps a single child and will always move to the 'FAILED' state when the child moves to a 'SUCCEEDED' or 'FAILED' state.\n */\nexport default class Fail extends Decorator {\n /**\n * @param attributes The node attributes.\n * @param child The child node.\n */\n constructor(attributes: Attribute[], child: Node) {\n super(\"fail\", attributes, child);\n }\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // If the child has never been updated or is running then we will need to update it now.\n if (this.child.getState() === State.READY || this.child.getState() === State.RUNNING) {\n this.child.update(agent, options);\n }\n\n // The state of this node will depend in the state of its child.\n switch (this.child.getState()) {\n case State.RUNNING:\n this.setState(State.RUNNING);\n break;\n\n case State.SUCCEEDED:\n case State.FAILED:\n this.setState(State.FAILED);\n break;\n\n default:\n this.setState(State.READY);\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => \"FAIL\";\n}\n", "import Decorator from \"./Decorator\";\nimport State from \"../../State\";\nimport Node from \"../Node\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A Flip node.\n * This node wraps a single child and will flip the state of the child state.\n */\nexport default class Flip extends Decorator {\n /**\n * @param attributes The node attributes.\n * @param child The child node.\n */\n constructor(attributes: Attribute[], child: Node) {\n super(\"flip\", attributes, child);\n }\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // If the child has never been updated or is running then we will need to update it now.\n if (this.child.getState() === State.READY || this.child.getState() === State.RUNNING) {\n this.child.update(agent, options);\n }\n\n // The state of this node will depend in the state of its child.\n switch (this.child.getState()) {\n case State.RUNNING:\n this.setState(State.RUNNING);\n break;\n\n case State.SUCCEEDED:\n this.setState(State.FAILED);\n break;\n\n case State.FAILED:\n this.setState(State.SUCCEEDED);\n break;\n\n default:\n this.setState(State.READY);\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => \"FLIP\";\n}\n", "import Node from \"../Node\";\nimport Decorator from \"./Decorator\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A REPEAT node.\n * The node has a single child which can have:\n * -- A number of iterations for which to repeat the child node.\n * -- An infinite repeat loop if neither an iteration count or a condition function is defined.\n * The REPEAT node will stop and have a 'FAILED' state if its child is ever in a 'FAILED' state after an update.\n * The REPEAT node will attempt to move on to the next iteration if its child is ever in a 'SUCCEEDED' state.\n */\nexport default class Repeat extends Decorator {\n /**\n * @param attributes The node attributes.\n * @param iterations The number of iterations to repeat the child node.\n * @param iterationsMin The minimum possible number of iterations to repeat the child node.\n * @param iterationsMax The maximum possible number of iterations to repeat the child node.\n * @param child The child node.\n */\n constructor(\n attributes: Attribute[],\n private iterations: number | null,\n private iterationsMin: number | null,\n private iterationsMax: number | null,\n child: Node\n ) {\n super(\"repeat\", attributes, child);\n }\n\n /**\n * The number of target iterations to make.\n */\n private targetIterationCount: number | null = null;\n\n /**\n * The current iteration count.\n */\n private currentIterationCount: number = 0;\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // If this node is in the READY state then we need to reset the child and the target iteration count.\n if (this.is(State.READY)) {\n // Reset the child node.\n this.child.reset();\n\n // Reset the current iteration count.\n this.currentIterationCount = 0;\n\n // Set the target iteration count.\n this.setTargetIterationCount(options);\n }\n\n // Do a check to see if we can iterate. If we can then this node will move into the 'RUNNING' state.\n // If we cannot iterate then we have hit our target iteration count, which means that the node has succeeded.\n if (this.canIterate()) {\n // This node is in the running state and can do its initial iteration.\n this.setState(State.RUNNING);\n\n // We may have already completed an iteration, meaning that the child node will be in the SUCCEEDED state.\n // If this is the case then we will have to reset the child node now.\n if (this.child.getState() === State.SUCCEEDED) {\n this.child.reset();\n }\n\n // Update the child of this node.\n this.child.update(agent, options);\n\n // If the child moved into the FAILED state when we updated it then there is nothing left to do and this node has also failed.\n // If it has moved into the SUCCEEDED state then we have completed the current iteration.\n if (this.child.getState() === State.FAILED) {\n // The child has failed, meaning that this node has failed.\n this.setState(State.FAILED);\n\n return;\n } else if (this.child.getState() === State.SUCCEEDED) {\n // We have completed an iteration.\n this.currentIterationCount += 1;\n }\n } else {\n // This node is in the 'SUCCEEDED' state as we cannot iterate any more.\n this.setState(State.SUCCEEDED);\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => {\n if (this.iterations !== null) {\n return `REPEAT ${this.iterations}x`;\n } else if (this.iterationsMin !== null && this.iterationsMax !== null) {\n return `REPEAT ${this.iterationsMin}x-${this.iterationsMax}x`;\n } else {\n return \"REPEAT\";\n }\n };\n\n /**\n * Reset the state of the node.\n */\n reset = () => {\n // Reset the state of this node.\n this.setState(State.READY);\n\n // Reset the current iteration count.\n this.currentIterationCount = 0;\n\n // Reset the child node.\n this.child.reset();\n };\n\n /**\n * Gets whether an iteration can be made.\n * @returns Whether an iteration can be made.\n */\n private canIterate = () => {\n if (this.targetIterationCount !== null) {\n // We can iterate as long as we have not reached our target iteration count.\n return this.currentIterationCount < this.targetIterationCount;\n }\n\n // If neither an iteration count or a condition function were defined then we can iterate indefinitely.\n return true;\n };\n\n /**\n * Sets the target iteration count.\n * @param options The behaviour tree options object.\n */\n private setTargetIterationCount = (options: BehaviourTreeOptions) => {\n // Are we dealing with an explicit iteration count or will we be randomly picking a iteration count between the min and max iteration count.\n if (this.iterations !== null) {\n this.targetIterationCount = this.iterations;\n } else if (this.iterationsMin !== null && this.iterationsMax !== null) {\n // We will be picking a random iteration count between a min and max iteration count, if the optional 'random'\n // behaviour tree function option is defined then we will be using that, otherwise we will fall back to using Math.random.\n const random = typeof options.random === \"function\" ? options.random : Math.random;\n\n // Pick a random iteration count between a min and max iteration count.\n this.targetIterationCount = Math.floor(\n random() * (this.iterationsMax - this.iterationsMin + 1) + this.iterationsMin\n );\n } else {\n this.targetIterationCount = null;\n }\n };\n}\n", "import Node from \"../Node\";\nimport Decorator from \"./Decorator\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A RETRY node.\n * The node has a single child which can have:\n * -- A number of iterations for which to repeat the child node.\n * -- An infinite repeat loop if neither an iteration count or a condition function is defined.\n * The RETRY node will stop and have a 'SUCCEEDED' state if its child is ever in a 'SUCCEEDED' state after an update.\n * The RETRY node will attempt to move on to the next iteration if its child is ever in a 'FAILED' state.\n */\nexport default class Retry extends Decorator {\n /**\n * @param attributes The node attributes.\n * @param attempts The number of attempts to retry the child node.\n * @param attemptsMin The minimum possible number of attempts to retry the child node.\n * @param attemptsMax The maximum possible number of attempts to retry the child node.\n * @param child The child node.\n */\n constructor(\n attributes: Attribute[],\n private attempts: number | null,\n private attemptsMin: number | null,\n private attemptsMax: number | null,\n child: Node\n ) {\n super(\"retry\", attributes, child);\n }\n\n /**\n * The number of target attempts to make.\n */\n private targetAttemptCount: number | null = null;\n\n /**\n * The current attempt count.\n */\n private currentAttemptCount: number = 0;\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // If this node is in the READY state then we need to reset the child and the target attempt count.\n if (this.is(State.READY)) {\n // Reset the child node.\n this.child.reset();\n\n // Reset the current attempt count.\n this.currentAttemptCount = 0;\n\n // Set the target attempt count.\n this.setTargetAttemptCount(options);\n }\n\n // Do a check to see if we can attempt. If we can then this node will move into the 'RUNNING' state.\n // If we cannot attempt then we have hit our target attempt count, which means that the node has succeeded.\n if (this.canAttempt()) {\n // This node is in the running state and can do its initial attempt.\n this.setState(State.RUNNING);\n\n // We may have already completed an attempt, meaning that the child node will be in the FAILED state.\n // If this is the case then we will have to reset the child node now.\n if (this.child.getState() === State.FAILED) {\n this.child.reset();\n }\n\n // Update the child of this node.\n this.child.update(agent, options);\n\n // If the child moved into the SUCCEEDED state when we updated it then there is nothing left to do and this node has also succeeded.\n // If it has moved into the FAILED state then we have completed the current attempt.\n if (this.child.getState() === State.SUCCEEDED) {\n // The child has succeeded, meaning that this node has succeeded.\n this.setState(State.SUCCEEDED);\n\n return;\n } else if (this.child.getState() === State.FAILED) {\n // We have completed an attempt.\n this.currentAttemptCount += 1;\n }\n } else {\n // This node is in the 'FAILED' state as we cannot iterate any more.\n this.setState(State.FAILED);\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => {\n if (this.attempts !== null) {\n return `RETRY ${this.attempts}x`;\n } else if (this.attemptsMin !== null && this.attemptsMax !== null) {\n return `RETRY ${this.attemptsMin}x-${this.attemptsMax}x`;\n } else {\n return \"RETRY\";\n }\n };\n\n /**\n * Reset the state of the node.\n */\n reset = () => {\n // Reset the state of this node.\n this.setState(State.READY);\n\n // Reset the current attempt count.\n this.currentAttemptCount = 0;\n\n // Reset the child node.\n this.child.reset();\n };\n\n /**\n * Gets whether an attempt can be made.\n * @returns Whether an attempt can be made.\n */\n canAttempt = () => {\n if (this.targetAttemptCount !== null) {\n // We can attempt as long as we have not reached our target attempt count.\n return this.currentAttemptCount < this.targetAttemptCount;\n }\n\n // If neither an attempt count or a condition function were defined then we can attempt indefinitely.\n return true;\n };\n\n /**\n * Sets the target attempt count.\n * @param options The behaviour tree options object.\n */\n setTargetAttemptCount = (options: BehaviourTreeOptions) => {\n // Are we dealing with an explicit attempt count or will we be randomly picking an attempt count between the min and max attempt count.\n if (this.attempts !== null) {\n this.targetAttemptCount = this.attempts;\n } else if (this.attemptsMin !== null && this.attemptsMax !== null) {\n // We will be picking a random attempt count between a min and max attempt count, if the optional 'random'\n // behaviour tree function option is defined then we will be using that, otherwise we will fall back to using Math.random.\n const random = typeof options.random === \"function\" ? options.random : Math.random;\n\n // Pick a random attempt count between a min and max attempt count.\n this.targetAttemptCount = Math.floor(\n random() * (this.attemptsMax - this.attemptsMin + 1) + this.attemptsMin\n );\n } else {\n this.targetAttemptCount = null;\n }\n };\n}\n", "import Node from \"../Node\";\nimport Decorator from \"./Decorator\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A Root node.\n * The root node will have a single child.\n */\nexport default class Root extends Decorator {\n /**\n * @param attributes The node attributes.\n * @param child The child node.\n */\n constructor(attributes: Attribute[], child: Node) {\n super(\"root\", attributes, child);\n }\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // If the child has never been updated or is running then we will need to update it now.\n if (this.child.getState() === State.READY || this.child.getState() === State.RUNNING) {\n // Update the child of this node.\n this.child.update(agent, options);\n }\n\n // The state of the root node is the state of its child.\n this.setState(this.child.getState());\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => \"ROOT\";\n}\n", "import Node from \"../Node\";\nimport Decorator from \"./Decorator\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A Succeed node.\n * This node wraps a single child and will always move to the 'SUCCEEDED' state when the child moves to a 'SUCCEEDED' or 'FAILED' state.\n */\nexport default class Succeed extends Decorator {\n /**\n * @param attributes The node attributes.\n * @param child The child node.\n */\n constructor(attributes: Attribute[], child: Node) {\n super(\"succeed\", attributes, child);\n }\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // If the child has never been updated or is running then we will need to update it now.\n if (this.child.getState() === State.READY || this.child.getState() === State.RUNNING) {\n this.child.update(agent, options);\n }\n\n // The state of this node will depend in the state of its child.\n switch (this.child.getState()) {\n case State.RUNNING:\n this.setState(State.RUNNING);\n break;\n\n case State.SUCCEEDED:\n case State.FAILED:\n this.setState(State.SUCCEEDED);\n break;\n\n default:\n this.setState(State.READY);\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => \"SUCCEED\";\n}\n", "import Node from \"../Node\";\n\n/**\n * A leaf node.\n */\nexport default abstract class Leaf extends Node {\n /**\n * Gets whether this node is a leaf node.\n */\n isLeafNode = () => true;\n}\n", "import { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\nimport State, { CompleteState } from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Leaf from \"./Leaf\";\nimport Lookup from \"../../Lookup\";\nimport Attribute from \"../../attributes/Attribute\";\n\n/**\n * The type representing a resolved/rejected update promise.\n */\ntype UpdatePromiseResult = {\n /**\n * Whether the promise was resolved rather than rejected.\n */\n isResolved: boolean;\n\n /**\n * The promise resolved value or rejection reason.\n */\n value: any;\n};\n\n/**\n * An Action leaf node.\n * This represents an immediate or ongoing state of behaviour.\n */\nexport default class Action extends Leaf {\n /**\n * @param attributes The node attributes.\n * @param actionName The action name.\n * @param actionArguments The array of action argument definitions.\n */\n constructor(attributes: Attribute[], private actionName: string, private actionArguments: any[]) {\n super(\"action\", attributes, actionArguments);\n }\n\n /**\n * Whether there is a pending update promise.\n */\n private isUsingUpdatePromise = false;\n\n /**\n * The finished state result of an update promise.\n */\n private updatePromiseResult: UpdatePromiseResult | null = null;\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // If the result of this action depends on an update promise then there is nothing to do until it settles.\n if (this.isUsingUpdatePromise) {\n // Are we still waiting for our update promise to settle?\n if (!this.updatePromiseResult) {\n return;\n }\n\n const { isResolved, value } = this.updatePromiseResult;\n\n // Our update promise settled, was it resolved or rejected?\n if (isResolved) {\n // Our promise resolved so check to make sure the result is a valid finished state.\n if (value !== State.SUCCEEDED && value !== State.FAILED) {\n throw new Error(\n \"action node promise resolved with an invalid value, expected a State.SUCCEEDED or State.FAILED value to be returned\"\n );\n }\n\n // Set the state of this node to match the state returned by the promise.\n this.setState(value);\n\n return;\n } else {\n // The promise was rejected, which isn't great.\n throw new Error(`action function '${this.actionName}' promise rejected with '${value}'`);\n }\n }\n\n // Attempt to get the invoker for the action function.\n const actionFuncInvoker = Lookup.getFuncInvoker(agent, this.actionName);\n\n // The action function should be defined.\n if (actionFuncInvoker === null) {\n throw new Error(\n `cannot update action node as the action '${this.actionName}' function is not defined on the agent and has not been registered`\n );\n }\n\n let actionFunctionResult;\n\n try {\n // Call the action function, the result of which may be:\n // - The finished state of this action node.\n // - A promise to return a finished node state.\n // - Undefined if the node should remain in the running state.\n actionFunctionResult = actionFuncInvoker(this.actionArguments) as CompleteState | Promise;\n } catch (error) {\n // The user was naughty and threw something.\n throw new Error(`action function '${this.actionName}' threw '${error}'`);\n }\n\n if (actionFunctionResult instanceof Promise) {\n actionFunctionResult.then(\n (result) => {\n // If 'isUpdatePromisePending' is not set then the promise was cleared as it was resolving, probably via an abort of reset.\n if (!this.isUsingUpdatePromise) {\n return;\n }\n\n // Set the resolved update promise result so that it can be handled on the next update of this node.\n this.updatePromiseResult = {\n isResolved: true,\n value: result\n };\n },\n (reason) => {\n // If 'isUpdatePromisePending' is not set then the promise was cleared as it was resolving, probably via an abort or reset.\n if (!this.isUsingUpdatePromise) {\n return;\n }\n\n // Set the rejected update promise result so that it can be handled on the next update of this node.\n this.updatePromiseResult = {\n isResolved: false,\n value: reason\n };\n }\n );\n\n // This node will be in the 'RUNNING' state until the update promise resolves.\n this.setState(State.RUNNING);\n\n // We are now waiting for the promise returned by the use to resolve before we know what state this node is in.\n this.isUsingUpdatePromise = true;\n } else {\n // Validate the returned value.\n this.validateUpdateResult(actionFunctionResult);\n\n // Set the state of this node, this may be undefined, which just means that the node is still in the 'RUNNING' state.\n this.setState(actionFunctionResult || State.RUNNING);\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => this.actionName;\n\n /**\n * Reset the state of the node.\n */\n reset = () => {\n // Reset the state of this node.\n this.setState(State.READY);\n\n // There is no longer an update promise that we care about.\n this.isUsingUpdatePromise = false;\n this.updatePromiseResult = null;\n };\n\n /**\n * Validate the result of an update function call.\n * @param result The result of an update function call.\n */\n private validateUpdateResult = (result: CompleteState | boolean) => {\n switch (result) {\n case State.SUCCEEDED:\n case State.FAILED:\n case undefined:\n return;\n default:\n throw new Error(\n `action '${this.actionName}' 'onUpdate' returned an invalid response, expected an optional State.SUCCEEDED or State.FAILED value to be returned`\n );\n }\n };\n}\n", "import { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Leaf from \"./Leaf\";\nimport Lookup from \"../../Lookup\";\nimport Attribute from \"../../attributes/Attribute\";\n\n/**\n * A Condition leaf node.\n * This will succeed or fail immediately based on an agent predicate, without moving to the 'RUNNING' state.\n */\nexport default class Condition extends Leaf {\n /**\n * @param attributes The node attributes.\n * @param conditionName The name of the condition function.\n * @param conditionArguments The array of condition argument definitions.\n */\n constructor(attributes: Attribute[], private conditionName: string, private conditionArguments: any[]) {\n super(\"condition\", attributes, conditionArguments);\n }\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // Attempt to get the invoker for the condition function.\n const conditionFuncInvoker = Lookup.getFuncInvoker(agent, this.conditionName);\n\n // The condition function should be defined.\n if (conditionFuncInvoker === null) {\n throw new Error(\n `cannot update condition node as the condition '${this.conditionName}' function is not defined on the agent and has not been registered`\n );\n }\n\n let conditionFunctionResult;\n\n try {\n // Call the condition function to determine the state of this node, the result of which should be a boolean.\n conditionFunctionResult = conditionFuncInvoker(this.conditionArguments);\n } catch (error) {\n // The user was naughty and threw something.\n throw new Error(`condition function '${this.conditionName}' threw '${error}'`);\n }\n\n // The result of calling the condition function must be a boolean value.\n if (typeof conditionFunctionResult !== \"boolean\") {\n throw new Error(\n `expected condition function '${this.conditionName}' to return a boolean but returned '${conditionFunctionResult}'`\n );\n }\n\n // Set the state of this node based on the result of calling the condition function.\n this.setState(!!conditionFunctionResult ? State.SUCCEEDED : State.FAILED);\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => this.conditionName;\n}\n", "import Leaf from \"./Leaf\";\nimport State from \"../../State\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { Agent } from \"../../Agent\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A WAIT node.\n * The state of this node will change to SUCCEEDED after a duration of time\n */\nexport default class Wait extends Leaf {\n /**\n * @param attributes The node attributes.\n * @param duration The duration that this node will wait to succeed in milliseconds.\n * @param durationMin The minimum possible duration in milliseconds that this node will wait to succeed.\n * @param durationMax The maximum possible duration in milliseconds that this node will wait to succeed.\n */\n constructor(\n attributes: Attribute[],\n private duration: number | null,\n private durationMin: number | null,\n private durationMax: number | null\n ) {\n super(\"wait\", attributes, []);\n }\n\n /**\n * The time in milliseconds at which this node was first updated.\n */\n private initialUpdateTime: number = 0;\n\n /**\n * The total duration in milliseconds that this node will be waiting for.\n */\n private totalDuration: number | null = null;\n\n /**\n * The duration in milliseconds that this node has been waiting for.\n */\n private waitedDuration: number = 0;\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // If this node is in the READY state then we need to set the initial update time.\n if (this.is(State.READY)) {\n // Set the initial update time.\n this.initialUpdateTime = new Date().getTime();\n\n // Set the initial waited duration.\n this.waitedDuration = 0;\n\n // Are we dealing with an explicit duration or will we be randomly picking a duration between the min and max duration.\n if (this.duration !== null) {\n this.totalDuration = this.duration;\n } else if (this.durationMin !== null && this.durationMax !== null) {\n // We will be picking a random duration between a min and max duration, if the optional 'random' behaviour tree\n // function option is defined then we will be using that, otherwise we will fall back to using Math.random.\n const random = typeof options.random === \"function\" ? options.random : Math.random;\n\n // Pick a random duration between a min and max duration.\n this.totalDuration = Math.floor(\n random() * (this.durationMax - this.durationMin + 1) + this.durationMin\n );\n } else {\n this.totalDuration = null;\n }\n\n // The node is now running until we finish waiting.\n this.setState(State.RUNNING);\n }\n\n // If we have no total duration then this wait node will wait indefinitely until it is aborted.\n if (this.totalDuration === null) {\n return;\n }\n\n // If we have a 'getDeltaTime' function defined as part of our options then we will use it to figure out how long we have waited for.\n if (typeof options.getDeltaTime === \"function\") {\n // Get the delta time.\n const deltaTime = options.getDeltaTime();\n\n // Our delta time must be a valid number and cannot be NaN.\n if (typeof deltaTime !== \"number\" || isNaN(deltaTime)) {\n throw new Error(\"The delta time must be a valid number and not NaN.\");\n }\n\n // Update the amount of time that this node has been waiting for based on the delta time.\n this.waitedDuration += deltaTime * 1000;\n } else {\n // We are not using a delta time, so we will just work out hom much time has passed since the first update.\n this.waitedDuration = new Date().getTime() - this.initialUpdateTime;\n }\n\n // Have we waited long enough?\n if (this.waitedDuration >= this.totalDuration) {\n // We have finished waiting!\n this.setState(State.SUCCEEDED);\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => {\n if (this.duration !== null) {\n return `WAIT ${this.duration}ms`;\n } else if (this.durationMin !== null && this.durationMax !== null) {\n return `WAIT ${this.durationMin}ms-${this.durationMax}ms`;\n } else {\n return \"WAIT\";\n }\n };\n}\n", "import Guard from \"./guards/Guard\";\n\nexport type AttributeDetails = {\n /** The attribute type. */\n type: string;\n\n /** The attribute arguments. */\n args: any[];\n};\n\n/**\n * A base node attribute.\n */\nexport default abstract class Attribute {\n /**\n * @param type The node attribute type.\n * @param args The array of attribute arguments.\n */\n constructor(public type: string, public args: any[]) {}\n\n /**\n * Gets the attribute details.\n */\n abstract getDetails(): TAttributeDetails;\n\n /**\n * Gets whether this attribute is a guard.\n */\n abstract isGuard: () => this is Guard;\n}\n", "import { Agent } from \"../../Agent\";\nimport Attribute, { AttributeDetails } from \"../Attribute\";\n\nexport type GuardAttributeDetails = {\n /** The name of the condition function that determines whether the guard is satisfied. */\n condition: string;\n} & AttributeDetails;\n\n/**\n * A base node guard attribute.\n */\nexport default abstract class Guard extends Attribute {\n /**\n * @param type The node attribute type.\n * @param args The array of decorator argument definitions.\n * @param condition The name of the condition function that determines whether the guard is satisfied.\n */\n constructor(type: string, args: any[], private condition: string) {\n super(type, args);\n }\n\n /**\n * Gets the name of the condition function that determines whether the guard is satisfied.\n */\n getCondition = () => this.condition;\n\n /**\n * Gets whether this attribute is a guard.\n */\n isGuard = () => true;\n\n /**\n * Gets the attribute details.\n */\n getDetails(): GuardAttributeDetails {\n return {\n type: this.type,\n args: this.args,\n condition: this.getCondition()\n };\n }\n\n /**\n * Gets whether the guard is satisfied.\n * @param agent The agent.\n * @returns Whether the guard is satisfied.\n */\n abstract isSatisfied(agent: Agent): boolean;\n}\n", "import Guard from \"./Guard\";\nimport Lookup from \"../../Lookup\";\nimport { Agent } from \"../../Agent\";\n\n/**\n * A WHILE guard which is satisfied as long as the given condition remains true.\n */\nexport default class While extends Guard {\n /**\n * @param condition The name of the condition function that determines whether the guard is satisfied.\n * @param args The array of decorator argument definitions.\n */\n constructor(condition: string, args: any[]) {\n super(\"while\", args, condition);\n }\n\n /**\n * Gets whether the guard is satisfied.\n * @param agent The agent.\n * @returns Whether the guard is satisfied.\n */\n isSatisfied = (agent: Agent) => {\n // Attempt to get the invoker for the condition function.\n const conditionFuncInvoker = Lookup.getFuncInvoker(agent, this.getCondition());\n\n // The condition function should be defined.\n if (conditionFuncInvoker === null) {\n throw new Error(\n `cannot evaluate node guard as the condition '${this.getCondition()}' function is not defined on the agent and has not been registered`\n );\n }\n\n // Call the condition function to determine whether this guard is satisfied.\n return !!conditionFuncInvoker(this.args);\n };\n}\n", "import Guard from \"./Guard\";\nimport Lookup from \"../../Lookup\";\nimport { Agent } from \"../../Agent\";\n\n/**\n * An UNTIL guard which is satisfied as long as the given condition remains false.\n */\nexport default class Until extends Guard {\n /**\n * @param condition The name of the condition function that determines whether the guard is satisfied.\n * @param args The array of decorator argument definitions.\n */\n constructor(condition: string, args: any[]) {\n super(\"until\", args, condition);\n }\n\n /**\n * Gets whether the guard is satisfied.\n * @param agent The agent.\n * @returns Whether the guard is satisfied.\n */\n isSatisfied = (agent: Agent) => {\n // Attempt to get the invoker for the condition function.\n const conditionFuncInvoker = Lookup.getFuncInvoker(agent, this.getCondition());\n\n // The condition function should be defined.\n if (conditionFuncInvoker === null) {\n throw new Error(\n `cannot evaluate node guard as the condition '${this.getCondition()}' function is not defined on the agent and has not been registered`\n );\n }\n\n // Call the condition function to determine whether this guard is satisfied.\n return !!!conditionFuncInvoker(this.args);\n };\n}\n", "import { Agent } from \"../../Agent\";\nimport Attribute, { AttributeDetails } from \"../Attribute\";\n\nexport type CallbackAttributeDetails = {\n /** The name of the agent function that is called. */\n functionName: string;\n} & AttributeDetails;\n\n/**\n * A base node callback attribute.\n */\nexport default abstract class Callback extends Attribute {\n /**\n * @param type The node attribute type.\n * @param args The array of decorator argument definitions.\n * @param functionName The name of the agent function to call.\n */\n constructor(type: string, args: any[], private functionName: string) {\n super(type, args);\n }\n\n /**\n * Gets the name of the agent function to call.\n */\n getFunctionName = () => this.functionName;\n\n /**\n * Gets whether this attribute is a guard.\n */\n isGuard = () => false;\n\n /**\n * Gets the attribute details.\n */\n getDetails(): CallbackAttributeDetails {\n return {\n type: this.type,\n args: this.args,\n functionName: this.getFunctionName()\n };\n }\n\n /**\n * Attempt to call the agent function that this callback refers to.\n * @param agent The agent.\n */\n abstract callAgentFunction: (agent: Agent, isSuccess: boolean, isAborted: boolean) => void;\n}\n", "import Callback from \"./Callback\";\nimport Lookup from \"../../Lookup\";\nimport { Agent } from \"../../Agent\";\n\n/**\n * An ENTRY callback which defines an agent function to call when the associated node is updated and moves out of running state.\n */\nexport default class Entry extends Callback {\n /**\n * @param functionName The name of the agent function to call.\n * @param args The array of callback argument definitions.\n */\n constructor(functionName: string, args: any[]) {\n super(\"entry\", args, functionName);\n }\n\n /**\n * Attempt to call the agent function that this callback refers to.\n * @param agent The agent.\n */\n callAgentFunction = (agent: Agent) => {\n // Attempt to get the invoker for the callback function.\n const callbackFuncInvoker = Lookup.getFuncInvoker(agent, this.getFunctionName());\n\n // The callback function should be defined.\n if (callbackFuncInvoker === null) {\n throw new Error(\n `cannot call entry function '${this.getFunctionName()}' as is not defined on the agent and has not been registered`\n );\n }\n\n // Call the callback function.\n callbackFuncInvoker(this.args);\n };\n}\n", "import Callback from \"./Callback\";\nimport Lookup from \"../../Lookup\";\nimport { Agent } from \"../../Agent\";\n\n/**\n * A STEP callback which defines an agent function to call when the associated node is updated.\n */\nexport default class Step extends Callback {\n /**\n * @param functionName The name of the agent function to call.\n * @param args The array of callback argument definitions.\n */\n constructor(functionName: string, args: any[]) {\n super(\"step\", args, functionName);\n }\n\n /**\n * Attempt to call the agent function that this callback refers to.\n * @param agent The agent.\n */\n callAgentFunction = (agent: Agent) => {\n // Attempt to get the invoker for the callback function.\n const callbackFuncInvoker = Lookup.getFuncInvoker(agent, this.getFunctionName());\n\n // The callback function should be defined.\n if (callbackFuncInvoker === null) {\n throw new Error(\n `cannot call step function '${this.getFunctionName()}' as is not defined on the agent and has not been registered`\n );\n }\n\n // Call the callback function.\n callbackFuncInvoker(this.args);\n };\n}\n", "import Callback from \"./Callback\";\nimport Lookup from \"../../Lookup\";\nimport { Agent } from \"../../Agent\";\n\n/**\n * An EXIT callback which defines an agent function to call when the associated node is updated and moves to a finished state or is aborted.\n */\nexport default class Exit extends Callback {\n /**\n * @param functionName The name of the agent function to call.\n * @param args The array of callback argument definitions.\n */\n constructor(functionName: string, args: any[]) {\n super(\"exit\", args, functionName);\n }\n\n /**\n * Attempt to call the agent function that this callback refers to.\n * @param agent The agent.\n * @param isSuccess Whether the decorated node was left with a success state.\n * @param isAborted Whether the decorated node was aborted.\n */\n callAgentFunction = (agent: Agent, isSuccess: boolean, isAborted: boolean) => {\n // Attempt to get the invoker for the callback function.\n const callbackFuncInvoker = Lookup.getFuncInvoker(agent, this.getFunctionName());\n\n // The callback function should be defined.\n if (callbackFuncInvoker === null) {\n throw new Error(\n `cannot call exit function '${this.getFunctionName()}' as is not defined on the agent and has not been registered`\n );\n }\n\n // Call the callback function\n callbackFuncInvoker([{ value: { succeeded: isSuccess, aborted: isAborted } }, ...this.args]);\n };\n}\n", "import { AnyNodeDefinition, RootNodeDefinition } from \"./BehaviourTreeDefinition\";\nimport GuardPath, { GuardPathPart } from \"./attributes/guards/GuardPath\";\nimport { validateBranchSubtreeLinks } from \"./BehaviourTreeDefinitionValidator\";\nimport { isInteger } from \"./BehaviourTreeDefinitionUtilities\";\nimport Node from \"./nodes/Node\";\nimport Composite from \"./nodes/composite/Composite\";\nimport Decorator from \"./nodes/decorator/Decorator\";\nimport Parallel from \"./nodes/composite/Parallel\";\nimport Selector from \"./nodes/composite/Selector\";\nimport Sequence from \"./nodes/composite/Sequence\";\nimport Lotto from \"./nodes/composite/Lotto\";\nimport Fail from \"./nodes/decorator/Fail\";\nimport Flip from \"./nodes/decorator/Flip\";\nimport Repeat from \"./nodes/decorator/Repeat\";\nimport Retry from \"./nodes/decorator/Retry\";\nimport Root from \"./nodes/decorator/Root\";\nimport Succeed from \"./nodes/decorator/Succeed\";\nimport Action from \"./nodes/leaf/Action\";\nimport Condition from \"./nodes/leaf/Condition\";\nimport Wait from \"./nodes/leaf/Wait\";\nimport Lookup from \"./Lookup\";\nimport Attribute from \"./attributes/Attribute\";\nimport While from \"./attributes/guards/While\";\nimport Until from \"./attributes/guards/Until\";\nimport Entry from \"./attributes/callbacks/Entry\";\nimport Step from \"./attributes/callbacks/Step\";\nimport Exit from \"./attributes/callbacks/Exit\";\n\n/**\n * A type representing any node instance in a behaviour tree.\n */\ntype AnyNode =\n | Root\n | Action\n | Condition\n | Wait\n | Sequence\n | Selector\n | Lotto\n | Parallel\n | Repeat\n | Retry\n | Flip\n | Succeed\n | Fail;\n\n/**\n * A type defining a mapping of root node identifiers to root node definitions.\n */\ntype RootNodeDefinitionMap = { [key: string | symbol]: RootNodeDefinition };\n\n/**\n * A symbol to use as the main root key in any root node mappings.\n */\nconst MAIN_ROOT_NODE_KEY = Symbol(\"__root__\");\n\n/**\n * Build and populate the root nodes based on the provided definition, assuming that the definition has been validated.\n * @param definition The root node definitions.\n * @returns The built and populated root node definitions.\n */\nexport default function buildRootNode(definition: RootNodeDefinition[]): Root {\n // Create a mapping of root node identifers to root node definitions, including globally registered subtree root node definitions.\n const rootNodeDefinitionMap = createRootNodeDefinitionMap(definition);\n\n // Now that we have all of our root node definitons (those part of the tree definition and those globally\n // registered) we should validate the definition. This will also double-check that we dont have any circular\n // dependencies in our branch -> subtree references and that we have no broken branch -> subtree links.\n validateBranchSubtreeLinks(definition, true);\n\n // Create our populated tree of node instances, starting with our main root node.\n const rootNode = nodeFactory(rootNodeDefinitionMap[MAIN_ROOT_NODE_KEY], rootNodeDefinitionMap) as Root;\n\n // Set a guard path on every leaf of the tree to evaluate as part of each update.\n applyLeafNodeGuardPaths(rootNode);\n\n // We only need to return the main root node.\n return rootNode;\n}\n\n/**\n * A factory function which creates a node instance based on the specified definition.\n * @param definition The node definition.\n * @param rootNodeDefinitionMap The mapping of root node identifers to root node definitions, including globally registered subtree root node definitions.\n * @returns A node instance based on the specified definition.\n */\nfunction nodeFactory(definition: AnyNodeDefinition, rootNodeDefinitionMap: RootNodeDefinitionMap): AnyNode {\n // Get the attributes for the node.\n const attributes = nodeAttributesFactory(definition);\n\n // Create the node instance based on the definition type.\n switch (definition.type) {\n case \"root\":\n return new Root(attributes, nodeFactory(definition.child, rootNodeDefinitionMap));\n\n case \"repeat\":\n let iterations: number | null = null;\n let iterationsMin: number | null = null;\n let iterationsMax: number | null = null;\n\n if (Array.isArray(definition.iterations)) {\n iterationsMin = definition.iterations[0];\n iterationsMax = definition.iterations[1];\n } else if (isInteger(definition.iterations)) {\n iterations = definition.iterations!;\n }\n\n return new Repeat(\n attributes,\n iterations,\n iterationsMin,\n iterationsMax,\n nodeFactory(definition.child, rootNodeDefinitionMap)\n );\n\n case \"retry\":\n let attempts: number | null = null;\n let attemptsMin: number | null = null;\n let attemptsMax: number | null = null;\n\n if (Array.isArray(definition.attempts)) {\n attemptsMin = definition.attempts[0];\n attemptsMax = definition.attempts[1];\n } else if (isInteger(definition.attempts)) {\n attempts = definition.attempts!;\n }\n\n return new Retry(\n attributes,\n attempts,\n attemptsMin,\n attemptsMax,\n nodeFactory(definition.child, rootNodeDefinitionMap)\n );\n\n case \"flip\":\n return new Flip(attributes, nodeFactory(definition.child, rootNodeDefinitionMap));\n\n case \"succeed\":\n return new Succeed(attributes, nodeFactory(definition.child, rootNodeDefinitionMap));\n\n case \"fail\":\n return new Fail(attributes, nodeFactory(definition.child, rootNodeDefinitionMap));\n\n case \"sequence\":\n return new Sequence(\n attributes,\n definition.children.map((child) => nodeFactory(child, rootNodeDefinitionMap))\n );\n\n case \"selector\":\n return new Selector(\n attributes,\n definition.children.map((child) => nodeFactory(child, rootNodeDefinitionMap))\n );\n\n case \"parallel\":\n return new Parallel(\n attributes,\n definition.children.map((child) => nodeFactory(child, rootNodeDefinitionMap))\n );\n\n case \"lotto\":\n return new Lotto(\n attributes,\n definition.weights,\n definition.children.map((child) => nodeFactory(child, rootNodeDefinitionMap))\n );\n\n case \"branch\":\n return nodeFactory(rootNodeDefinitionMap[definition.ref].child, rootNodeDefinitionMap);\n\n case \"action\":\n return new Action(attributes, definition.call, definition.args || []);\n\n case \"condition\":\n return new Condition(attributes, definition.call, definition.args || []);\n\n case \"wait\":\n let duration: number | null = null;\n let durationMin: number | null = null;\n let durationMax: number | null = null;\n\n if (Array.isArray(definition.duration)) {\n durationMin = definition.duration[0];\n durationMax = definition.duration[1];\n } else if (isInteger(definition.duration)) {\n duration = definition.duration!;\n }\n\n return new Wait(attributes, duration, durationMin, durationMax);\n }\n}\n\n/**\n * Creates an array of node attribute instances based on the specified node definition.\n * @param definition The node definition.\n * @returns An array of node attribute instances based on the specified node definition.\n */\nfunction nodeAttributesFactory(definition: AnyNodeDefinition): Attribute[] {\n const attributes: Attribute[] = [];\n\n if (definition.while) {\n attributes.push(new While(definition.while.call, definition.while.args ?? []));\n }\n\n if (definition.until) {\n attributes.push(new Until(definition.until.call, definition.until.args ?? []));\n }\n\n if (definition.entry) {\n attributes.push(new Entry(definition.entry.call, definition.entry.args ?? []));\n }\n\n if (definition.step) {\n attributes.push(new Step(definition.step.call, definition.step.args ?? []));\n }\n\n if (definition.exit) {\n attributes.push(new Exit(definition.exit.call, definition.exit.args ?? []));\n }\n\n return attributes;\n}\n\n/**\n * Creates a mapping of root node identifers to root node definitions, mixing in globally registered subtree root node definitions.\n * @param definition The root node definitions.\n * @returns A mapping of root node identifers to root node definitions, including globally registered subtree root node definitions.\n */\nfunction createRootNodeDefinitionMap(definition: RootNodeDefinition[]): RootNodeDefinitionMap {\n // Create a mapping of root node identifers to root node definitions.\n const rootNodeMap: RootNodeDefinitionMap = {};\n\n // Add in any registered subtree root node definitions.\n for (const [name, rootNodeDefinition] of Object.entries(Lookup.getSubtrees())) {\n // The name used when registering the subtree will be used as the root node identifier.\n rootNodeMap[name] = { ...rootNodeDefinition, id: name };\n }\n\n // Populate the map with the root node definitions that were included with the tree definition.\n // We do this after adding any registered subtrees as we want these to take presedence.\n for (const rootNodeDefinition of definition) {\n rootNodeMap[rootNodeDefinition.id ?? MAIN_ROOT_NODE_KEY] = rootNodeDefinition;\n }\n\n return rootNodeMap;\n}\n\n/**\n * Applies a guard path to every leaf of the tree to evaluate as part of each update.\n * @param root The main root tree node.\n */\nfunction applyLeafNodeGuardPaths(root: Root) {\n const nodePaths: Node[][] = [];\n\n const findLeafNodes = (path: Node[], node: Node) => {\n // Add the current node to the path.\n path = path.concat(node);\n\n // Check whether the current node is a leaf node.\n if (node.isLeafNode()) {\n nodePaths.push(path);\n } else {\n (node as Composite | Decorator).getChildren().forEach((child) => findLeafNodes(path, child));\n }\n };\n\n // Find all leaf node paths, starting from the root.\n findLeafNodes([], root);\n\n nodePaths.forEach((path) => {\n // Each node in the current path will have to be assigned a guard path, working from the root outwards.\n for (let depth = 0; depth < path.length; depth++) {\n // Get the node in the path at the current depth.\n const currentNode = path[depth];\n\n // The node may already have been assigned a guard path, if so just skip it.\n if (currentNode.hasGuardPath()) {\n continue;\n }\n\n // Create the guard path for the current node.\n const guardPath = new GuardPath(\n path\n .slice(0, depth + 1)\n .map((node) => ({ node, guards: node.getGuardAttributes() }))\n .filter((details) => details.guards.length > 0)\n );\n\n // Assign the guard path to the current node.\n currentNode.setGuardPath(guardPath);\n }\n });\n}\n", "import State, { AnyState } from \"./State\";\nimport Lookup from \"./Lookup\";\nimport Node from \"./nodes/Node\";\nimport Root from \"./nodes/decorator/Root\";\nimport Composite from \"./nodes/composite/Composite\";\nimport Decorator from \"./nodes/decorator/Decorator\";\nimport { Agent, GlobalFunction } from \"./Agent\";\nimport { CallbackAttributeDetails } from \"./attributes/callbacks/Callback\";\nimport { GuardAttributeDetails } from \"./attributes/guards/Guard\";\nimport { BehaviourTreeOptions } from \"./BehaviourTreeOptions\";\nimport { convertMDSLToJSON } from \"./mdsl/MDSLDefinitionParser\";\nimport { RootNodeDefinition } from \"./BehaviourTreeDefinition\";\nimport { validateDefinition, validateJSONDefinition } from \"./BehaviourTreeDefinitionValidator\";\nimport buildRootNode from \"./BehaviourTreeBuilder\";\nimport { isNullOrUndefined } from \"./BehaviourTreeDefinitionUtilities\";\n\n// Purely for outside inspection of the tree.\nexport type FlattenedTreeNode = {\n id: string;\n type: string;\n caption: string;\n state: AnyState;\n guards: GuardAttributeDetails[];\n callbacks: CallbackAttributeDetails[];\n args: any[];\n parentId: string | null;\n};\n\n/**\n * A representation of a behaviour tree.\n */\nexport class BehaviourTree {\n /**\n * The main root tree node.\n */\n private readonly _rootNode: Root;\n\n /**\n * Creates a new instance of the BehaviourTree class.\n * @param definition The behaviour tree definition as either an MDSL string, root node definition object or array of root node definition objects.\n * @param agent The agent instance that this behaviour tree is modelling behaviour for.\n * @param options The behaviour tree options object.\n */\n constructor(\n definition: string | RootNodeDefinition | RootNodeDefinition[],\n private agent: Agent,\n private options: BehaviourTreeOptions = {}\n ) {\n // The tree definition must be defined.\n if (isNullOrUndefined(definition)) {\n throw new Error(\"tree definition not defined\");\n }\n\n // The agent must be defined and not null.\n if (typeof agent !== \"object\" || agent === null) {\n throw new Error(\"the agent must be an object and not null\");\n }\n\n // We should validate the definition before we try to build the tree nodes.\n const { succeeded, errorMessage, json } = validateDefinition(definition);\n\n // Did our validation fail without error?\n if (!succeeded) {\n throw new Error(`invalid definition: ${errorMessage}`);\n }\n\n // Double check that we did actually get our json definition as part of our definition validtion.\n if (!json) {\n throw new Error(\n \"expected json definition to be returned as part of successful definition validation response\"\n );\n }\n\n try {\n // Create the populated tree of behaviour tree nodes and get the root node.\n this._rootNode = buildRootNode(json);\n } catch (exception) {\n // There was an issue in trying build and populate the behaviour tree.\n throw new Error(`error building tree: ${(exception as Error).message}`);\n }\n }\n\n /**\n * Gets whether the tree is in the RUNNING state.\n * @returns true if the tree is in the RUNNING state, otherwise false.\n */\n isRunning() {\n return this._rootNode.getState() === State.RUNNING;\n }\n\n /**\n * Gets the current tree state of SUCCEEDED, FAILED, READY or RUNNING.\n * @returns The current tree state.\n */\n getState() {\n return this._rootNode.getState();\n }\n\n /**\n * Step the tree.\n * 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.\n * 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\n * 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.\n *\n * 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.\n */\n step() {\n // If the root node has already been stepped to completion then we need to reset it.\n if (this._rootNode.getState() === State.SUCCEEDED || this._rootNode.getState() === State.FAILED) {\n this._rootNode.reset();\n }\n\n try {\n this._rootNode.update(this.agent, this.options);\n } catch (exception) {\n throw new Error(`error stepping tree: ${(exception as Error).message}`);\n }\n }\n\n /**\n * Resets the tree from the root node outwards to each nested node, giving each a state of READY.\n */\n reset() {\n this._rootNode.reset();\n }\n\n /**\n * Gets the flattened details of every node in the tree.\n * @returns The flattened details of every node in the tree.\n */\n getFlattenedNodeDetails(): FlattenedTreeNode[] {\n // Create an empty flattened array of tree nodes.\n const flattenedTreeNodes: FlattenedTreeNode[] = [];\n\n /**\n * Helper function to process a node instance and push details into the flattened tree nodes array.\n * @param node The current node.\n * @param parentUid The UID of the node parent, or null if the node is the main root node.\n */\n const processNode = (node: Node, parentUid: string | null) => {\n // Get the guard and callback attribute details for this node.\n const guards = node\n .getAttributes()\n .filter((attribute) => attribute.isGuard())\n .map((attribute) => attribute.getDetails()) as GuardAttributeDetails[];\n const callbacks = node\n .getAttributes()\n .filter((attribute) => !attribute.isGuard())\n .map((attribute) => attribute.getDetails()) as CallbackAttributeDetails[];\n\n // Push the current node into the flattened nodes array.\n flattenedTreeNodes.push({\n id: node.getUid(),\n type: node.getType(),\n caption: node.getName(),\n state: node.getState(),\n guards,\n callbacks,\n args: node.getArguments(),\n parentId: parentUid\n });\n\n // Process each of the nodes children if it is not a leaf node.\n if (!node.isLeafNode()) {\n (node as Composite | Decorator)\n .getChildren()\n .forEach((child) => processNode(child, (node as Composite | Decorator).getUid()));\n }\n };\n\n // Convert the nested node structure into a flattened array of node details.\n processNode(this._rootNode, null);\n\n return flattenedTreeNodes;\n }\n\n /**\n * Registers the action/condition/guard/callback function or subtree with the given name.\n * @param name The name of the function or subtree to register.\n * @param value The function or subtree definition to register.\n */\n static register(name: string, value: GlobalFunction | string | RootNodeDefinition) {\n // Are we going to register a action/condition/guard/callback function?\n if (typeof value === \"function\") {\n Lookup.setFunc(name, value);\n return;\n }\n\n // We are not registering an action/condition/guard/callback function, so we must be registering a subtree.\n if (typeof value === \"string\") {\n let rootNodeDefinitions: RootNodeDefinition[];\n\n // We will assume that any string passed in will be a mdsl definition.\n try {\n rootNodeDefinitions = convertMDSLToJSON(value);\n } catch (exception) {\n throw new Error(`error registering definition, invalid MDSL: ${(exception as Error).message}`);\n }\n\n // This function should only ever be called with a definition containing a single unnamed root node.\n if (rootNodeDefinitions.length != 1 || rootNodeDefinitions[0].id !== null) {\n throw new Error(\"error registering definition: expected a single unnamed root node\");\n }\n\n try {\n // We should validate the subtree as we don't want invalid subtrees available via the lookup.\n const { succeeded, errorMessage } = validateJSONDefinition(rootNodeDefinitions[0]);\n\n // Did our validation fail without error?\n if (!succeeded) {\n throw new Error(errorMessage);\n }\n } catch (exception) {\n throw new Error(`error registering definition: ${(exception as Error).message}`);\n }\n\n // Everything seems hunky-dory, register the subtree.\n Lookup.setSubtree(name, rootNodeDefinitions[0]);\n } else if (typeof value === \"object\" && !Array.isArray(value)) {\n // We will assume that any object passed in is a root node definition.\n\n try {\n // We should validate the subtree as we don't want invalid subtrees available via the lookup.\n const { succeeded, errorMessage } = validateJSONDefinition(value);\n\n // Did our validation fail without error?\n if (!succeeded) {\n throw new Error(errorMessage);\n }\n } catch (exception) {\n throw new Error(`error registering definition: ${(exception as Error).message}`);\n }\n\n // Everything seems hunky-dory, register the subtree.\n Lookup.setSubtree(name, value);\n } else {\n throw new Error(\"unexpected value, expected string mdsl definition, root node json definition or function\");\n }\n }\n\n /**\n * Unregisters the registered action/condition/guard/callback function or subtree with the given name.\n * @param name The name of the registered action/condition/guard/callback function or subtree to unregister.\n */\n static unregister(name: string): void {\n Lookup.remove(name);\n }\n\n /**\n * Unregister all registered action/condition/guard/callback functions and subtrees.\n */\n static unregisterAll(): void {\n Lookup.empty();\n }\n}\n"], + "mappings": "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", "names": ["Participant", "isNullOrUndefined", "Lotto", "createLotto", "State", "createLotto"] } diff --git a/dist/nodes/leaf/Action.d.ts b/dist/nodes/leaf/Action.d.ts index 0ce5e29..37f047c 100644 --- a/dist/nodes/leaf/Action.d.ts +++ b/dist/nodes/leaf/Action.d.ts @@ -22,7 +22,7 @@ export default class Action extends Leaf { /** * The finished state result of an update promise. */ - private updatePromiseStateResult; + private updatePromiseResult; /** * Called when the node is being updated. * @param agent The agent. diff --git a/src/nodes/leaf/Action.ts b/src/nodes/leaf/Action.ts index 8ae386f..357e85e 100644 --- a/src/nodes/leaf/Action.ts +++ b/src/nodes/leaf/Action.ts @@ -5,6 +5,21 @@ import Leaf from "./Leaf"; import Lookup from "../../Lookup"; import Attribute from "../../attributes/Attribute"; +/** + * The type representing a resolved/rejected update promise. + */ +type UpdatePromiseResult = { + /** + * Whether the promise was resolved rather than rejected. + */ + isResolved: boolean; + + /** + * The promise resolved value or rejection reason. + */ + value: any; +}; + /** * An Action leaf node. * This represents an immediate or ongoing state of behaviour. @@ -27,7 +42,7 @@ export default class Action extends Leaf { /** * The finished state result of an update promise. */ - private updatePromiseStateResult: CompleteState | null = null; + private updatePromiseResult: UpdatePromiseResult | null = null; /** * Called when the node is being updated. @@ -35,16 +50,32 @@ export default class Action extends Leaf { * @param options The behaviour tree options object. */ protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void { - // If the result of this action depends on an update promise then there is nothing to do until - // it resolves, unless there has been a value set as a result of the update promise resolving. + // If the result of this action depends on an update promise then there is nothing to do until it settles. if (this.isUsingUpdatePromise) { - // Check whether the update promise has resolved with a state value. - if (this.updatePromiseStateResult) { - // Set the state of this node to match the state returned by the promise. - this.setState(this.updatePromiseStateResult); + // Are we still waiting for our update promise to settle? + if (!this.updatePromiseResult) { + return; } - return; + const { isResolved, value } = this.updatePromiseResult; + + // Our update promise settled, was it resolved or rejected? + if (isResolved) { + // Our promise resolved so check to make sure the result is a valid finished state. + if (value !== State.SUCCEEDED && value !== State.FAILED) { + throw new Error( + "action node promise resolved with an invalid value, expected a State.SUCCEEDED or State.FAILED value to be returned" + ); + } + + // Set the state of this node to match the state returned by the promise. + this.setState(value); + + return; + } else { + // The promise was rejected, which isn't great. + throw new Error(`action function '${this.actionName}' promise rejected with '${value}'`); + } } // Attempt to get the invoker for the action function. @@ -73,31 +104,28 @@ export default class Action extends Leaf { if (actionFunctionResult instanceof Promise) { actionFunctionResult.then( (result) => { - // If 'isUpdatePromisePending' is null then the promise was cleared as it was resolving, probably via an abort of reset. + // If 'isUpdatePromisePending' is not set then the promise was cleared as it was resolving, probably via an abort of reset. if (!this.isUsingUpdatePromise) { return; } - // Check to make sure the result is a valid finished state. - if (result !== State.SUCCEEDED && result !== State.FAILED) { - throw new Error( - "action node promise resolved with an invalid value, expected a State.SUCCEEDED or State.FAILED value to be returned" - ); - } - - // Set pending update promise state result to be processed on next update. - this.updatePromiseStateResult = result; + // Set the resolved update promise result so that it can be handled on the next update of this node. + this.updatePromiseResult = { + isResolved: true, + value: result + }; }, (reason) => { - // If 'isUpdatePromisePending' is null then the promise was cleared as it was resolving, probably via an abort or reset. + // If 'isUpdatePromisePending' is not set then the promise was cleared as it was resolving, probably via an abort or reset. if (!this.isUsingUpdatePromise) { return; } - // TODO We shouldn't throw an error here, we actually need to set this.updatePromiseRejectionReason so that it can be thrown on the next tree.step() call. - - // The promise was rejected, which isn't great. - throw new Error(`action function '${this.actionName}' promise rejected with reason '${reason}'`); + // Set the rejected update promise result so that it can be handled on the next update of this node. + this.updatePromiseResult = { + isResolved: false, + value: reason + }; } ); @@ -129,7 +157,7 @@ export default class Action extends Leaf { // There is no longer an update promise that we care about. this.isUsingUpdatePromise = false; - this.updatePromiseStateResult = null; + this.updatePromiseResult = null; }; /** diff --git a/test/nodes/decorator/Fail.spec.ts b/test/nodes/decorator/Fail.spec.ts index bc644a3..673101e 100644 --- a/test/nodes/decorator/Fail.spec.ts +++ b/test/nodes/decorator/Fail.spec.ts @@ -14,7 +14,7 @@ describe("A Fail node", () => { assert.throws( () => new BehaviourTree(definition, {}), Error, - "invalid definition: a fail node must have a single child" + "invalid definition: a fail node must have a single child node defined" ); }); diff --git a/test/nodes/decorator/Flip.spec.ts b/test/nodes/decorator/Flip.spec.ts index 3bb737d..d59f0e4 100644 --- a/test/nodes/decorator/Flip.spec.ts +++ b/test/nodes/decorator/Flip.spec.ts @@ -14,7 +14,7 @@ describe("A Flip node", () => { assert.throws( () => new BehaviourTree(definition, {}), Error, - "invalid definition: a flip node must have a single child" + "invalid definition: a flip node must have a single child node defined" ); }); diff --git a/test/nodes/decorator/Repeat.spec.ts b/test/nodes/decorator/Repeat.spec.ts index a171416..057213b 100644 --- a/test/nodes/decorator/Repeat.spec.ts +++ b/test/nodes/decorator/Repeat.spec.ts @@ -16,7 +16,7 @@ describe("A Repeat node", () => { assert.throws( () => new BehaviourTree(definition, {}), Error, - "invalid definition: a repeat node must have a single child" + "invalid definition: a repeat node must have a single child node defined" ); }); diff --git a/test/nodes/decorator/Retry.spec.ts b/test/nodes/decorator/Retry.spec.ts index 78b4925..59df623 100644 --- a/test/nodes/decorator/Retry.spec.ts +++ b/test/nodes/decorator/Retry.spec.ts @@ -16,7 +16,7 @@ describe("A Retry node", () => { assert.throws( () => new BehaviourTree(definition, {}), Error, - "invalid definition: a retry node must have a single child" + "invalid definition: a retry node must have a single child node defined" ); }); diff --git a/test/nodes/decorator/Root.spec.ts b/test/nodes/decorator/Root.spec.ts new file mode 100644 index 0000000..5bfb8b2 --- /dev/null +++ b/test/nodes/decorator/Root.spec.ts @@ -0,0 +1,66 @@ +import { assert } from "chai"; + +import { BehaviourTree, State } from "../../../src/index"; +import { RootNodeDefinition } from "../../../src/BehaviourTreeDefinition"; +import { Agent } from "../../../src/Agent"; + +import { findNode } from "../../TestUtilities"; + +describe("A Root node", () => { + describe("on tree initialisation", () => { + describe("will error if the node does not have a single child", () => { + it("(MDSL)", () => { + const definition = "root { }"; + assert.throws( + () => new BehaviourTree(definition, {}), + Error, + "invalid definition: a root node must have a single child node defined" + ); + }); + }); + }); + + describe("when updated as part of a tree step will", () => { + describe("move to the SUCCESS state if the child node moves to the SUCCESS state", () => { + it("(MDSL)", () => { + const definition = "root { condition [someCondition] }"; + const agent = { someCondition: () => false }; + const tree = new BehaviourTree(definition, agent); + + assert.strictEqual(findNode(tree, "root").state, State.READY); + + tree.step(); + + assert.strictEqual(findNode(tree, "root").state, State.FAILED); + }); + }); + + describe("move to the FAILED state if the child node moves to the FAILED state", () => { + it("(MDSL)", () => { + const definition = "root { condition [someCondition] }"; + const agent = { someCondition: () => true }; + const tree = new BehaviourTree(definition, agent); + + assert.strictEqual(findNode(tree, "root").state, State.READY); + + tree.step(); + + assert.strictEqual(findNode(tree, "root").state, State.SUCCEEDED); + }); + }); + + describe("move to the RUNNING state if the child node does not move to the SUCCESS or FAILED state", () => { + it("(MDSL)", () => { + const definition = "root { action [someAction] }"; + const agent = { someAction: () => {} }; + const tree = new BehaviourTree(definition, agent); + + assert.strictEqual(findNode(tree, "root").state, State.READY); + + tree.step(); + + assert.strictEqual(findNode(tree, "root").state, State.RUNNING); + }); + }); + }); +}); diff --git a/test/nodes/decorator/Succeed.spec.ts b/test/nodes/decorator/Succeed.spec.ts index 475791a..65cb922 100644 --- a/test/nodes/decorator/Succeed.spec.ts +++ b/test/nodes/decorator/Succeed.spec.ts @@ -14,7 +14,7 @@ describe("A Succeed node", () => { assert.throws( () => new BehaviourTree(definition, {}), Error, - "invalid definition: a succeed node must have a single child" + "invalid definition: a succeed node must have a single child node defined" ); }); diff --git a/test/nodes/leaf/Action.spec.ts b/test/nodes/leaf/Action.spec.ts index 5c6dbfb..5baaa6e 100644 --- a/test/nodes/leaf/Action.spec.ts +++ b/test/nodes/leaf/Action.spec.ts @@ -221,7 +221,61 @@ describe("An Action node", () => { }); describe("returns a rejected promise", () => { - it("(MDSL)", () => {}); + it("(MDSL)", (done) => { + const definition = "root { action [doAction] }"; + const result: Promise = new Promise(() => { + throw new Error("some-error"); + }); + const agent = { doAction: () => result }; + const tree = new BehaviourTree(definition, agent); + + assert.strictEqual(findNode(tree, "action", "doAction").state, State.READY); + + tree.step(); + + assert.strictEqual(findNode(tree, "action", "doAction").state, State.RUNNING); + + setTimeout(() => { + assert.throws( + () => tree.step(), + Error, + "error stepping tree: action function 'doAction' promise rejected with 'Error: some-error'" + ); + + done(); + }, 0); + }); + + it("(JSON)", (done) => { + const definition: RootNodeDefinition = { + type: "root", + child: { + type: "action", + call: "doAction" + } + }; + const result: Promise = new Promise(() => { + throw new Error("some-error"); + }); + const agent = { doAction: () => result }; + const tree = new BehaviourTree(definition, agent); + + assert.strictEqual(findNode(tree, "action", "doAction").state, State.READY); + + tree.step(); + + assert.strictEqual(findNode(tree, "action", "doAction").state, State.RUNNING); + + setTimeout(() => { + assert.throws( + () => tree.step(), + Error, + "error stepping tree: action function 'doAction' promise rejected with 'Error: some-error'" + ); + + done(); + }, 0); + }); }); }); }); @@ -344,18 +398,19 @@ describe("An Action node", () => { const agent = { doAction: () => result }; const tree = new BehaviourTree(definition, agent); - let node = findNode(tree, "action", "doAction"); - assert.strictEqual(node.state, State.READY); + assert.strictEqual(findNode(tree, "action", "doAction").state, State.READY); tree.step(); - result - .then(() => tree.step()) - .then(() => { - node = findNode(tree, "action", "doAction"); - assert.strictEqual(node.state, State.SUCCEEDED); - }) - .then(done); + assert.strictEqual(findNode(tree, "action", "doAction").state, State.RUNNING); + + setTimeout(() => { + tree.step(); + + assert.strictEqual(findNode(tree, "action", "doAction").state, State.SUCCEEDED); + + done(); + }, 0); }); it("(JSON)", (done) => { @@ -371,18 +426,19 @@ describe("An Action node", () => { const agent = { doAction: () => result }; const tree = new BehaviourTree(definition, agent); - let node = findNode(tree, "action", "doAction"); - assert.strictEqual(node.state, State.READY); + assert.strictEqual(findNode(tree, "action", "doAction").state, State.READY); tree.step(); - result - .then(() => tree.step()) - .then(() => { - node = findNode(tree, "action", "doAction"); - assert.strictEqual(node.state, State.SUCCEEDED); - }) - .then(done); + assert.strictEqual(findNode(tree, "action", "doAction").state, State.RUNNING); + + setTimeout(() => { + tree.step(); + + assert.strictEqual(findNode(tree, "action", "doAction").state, State.SUCCEEDED); + + done(); + }, 0); }); }); }); From 6fd30cc19bdd4ce06dc44f2adf3c167f3bf96210 Mon Sep 17 00:00:00 2001 From: Nikolas Howard Date: Tue, 27 Feb 2024 08:15:13 +0000 Subject: [PATCH 36/48] Root specs --- test/nodes/decorator/Root.spec.ts | 65 +++++++++++++++++++++++++++++++ 1 file changed, 65 insertions(+) diff --git a/test/nodes/decorator/Root.spec.ts b/test/nodes/decorator/Root.spec.ts index 5bfb8b2..4a50959 100644 --- a/test/nodes/decorator/Root.spec.ts +++ b/test/nodes/decorator/Root.spec.ts @@ -17,6 +17,17 @@ describe("A Root node", () => { "invalid definition: a root node must have a single child node defined" ); }); + + it("(JSON)", () => { + const definition = { + type: "root" + } as any; + assert.throws( + () => new BehaviourTree(definition, {}), + Error, + "invalid definition: expected property 'child' to be defined for root node" + ); + }); }); }); @@ -33,6 +44,24 @@ describe("A Root node", () => { assert.strictEqual(findNode(tree, "root").state, State.FAILED); }); + + it("(JSON)", () => { + const definition: RootNodeDefinition = { + type: "root", + child: { + type: "condition", + call: "someCondition" + } + }; + const agent = { someCondition: () => false }; + const tree = new BehaviourTree(definition, agent); + + assert.strictEqual(findNode(tree, "root").state, State.READY); + + tree.step(); + + assert.strictEqual(findNode(tree, "root").state, State.FAILED); + }); }); describe("move to the FAILED state if the child node moves to the FAILED state", () => { @@ -47,6 +76,24 @@ describe("A Root node", () => { assert.strictEqual(findNode(tree, "root").state, State.SUCCEEDED); }); + + it("(JSON)", () => { + const definition: RootNodeDefinition = { + type: "root", + child: { + type: "condition", + call: "someCondition" + } + }; + const agent = { someCondition: () => true }; + const tree = new BehaviourTree(definition, agent); + + assert.strictEqual(findNode(tree, "root").state, State.READY); + + tree.step(); + + assert.strictEqual(findNode(tree, "root").state, State.SUCCEEDED); + }); }); describe("move to the RUNNING state if the child node does not move to the SUCCESS or FAILED state", () => { @@ -61,6 +108,24 @@ describe("A Root node", () => { assert.strictEqual(findNode(tree, "root").state, State.RUNNING); }); + + it("(JSON)", () => { + const definition: RootNodeDefinition = { + type: "root", + child: { + type: "action", + call: "someAction" + } + }; + const agent = { someAction: () => {} }; + const tree = new BehaviourTree(definition, agent); + + assert.strictEqual(findNode(tree, "root").state, State.READY); + + tree.step(); + + assert.strictEqual(findNode(tree, "root").state, State.RUNNING); + }); }); }); }); From b5ec03b6dcfdf040fab6fff5bf5c1eeb2bb7d694 Mon Sep 17 00:00:00 2001 From: Nikolas Howard Date: Tue, 27 Feb 2024 08:34:42 +0000 Subject: [PATCH 37/48] validator specs --- test/BehaviourTreeBuilder.spec.ts | 1 + test/BehaviourTreeDefinitionValidator.spec.ts | 215 ++++++++++-------- 2 files changed, 118 insertions(+), 98 deletions(-) create mode 100644 test/BehaviourTreeBuilder.spec.ts diff --git a/test/BehaviourTreeBuilder.spec.ts b/test/BehaviourTreeBuilder.spec.ts new file mode 100644 index 0000000..fdd4fcd --- /dev/null +++ b/test/BehaviourTreeBuilder.spec.ts @@ -0,0 +1 @@ +describe("The BehaviourTreeBuilder class", () => {}); diff --git a/test/BehaviourTreeDefinitionValidator.spec.ts b/test/BehaviourTreeDefinitionValidator.spec.ts index 640e523..668db7d 100644 --- a/test/BehaviourTreeDefinitionValidator.spec.ts +++ b/test/BehaviourTreeDefinitionValidator.spec.ts @@ -1,9 +1,6 @@ import { assert } from "chai"; -import sinon from "sinon"; -import { BehaviourTree, State, validateDefinition } from "../src/index"; -import { RootNodeDefinition } from "../src/BehaviourTreeDefinition"; -import { Agent } from "../src/Agent"; +import { validateDefinition } from "../src/index"; describe("The validateDefinition function takes a tree definition as an argument and", () => { // Helper function to carry out the validation and verify the expected result. @@ -15,107 +12,129 @@ describe("The validateDefinition function takes a tree definition as an argument assert.deepEqual(result, success ? { succeeded: true } : { succeeded: false, errorMessage }); }; - describe("where the type of that definition is", () => { - describe("MDSL", () => { - // TODO Add better validation to mdsl parsing to better match the json validation. + describe("returns a validation failure when", () => { + describe("the definition doesn't contain a main root node (has no root node identifier defined)", () => { + it("(MDSL)", () => { + verifyResult( + "root [not-main-root] { action [noop] }", + false, + "expected single unnamed root node at base of definition to act as main root" + ); + }); + + it("(JSON)", () => { + const definition = { + id: "not-main-root", + type: "root", + child: { + type: "action", + call: "noop" + } + }; + + // The definition can be either an array (of root node definitions) or an object (the single primary root node definition), verify both. + verifyResult( + definition, + false, + "expected single root node without 'id' property defined to act as main root" + ); + verifyResult( + [definition], + false, + "expected single root node without 'id' property defined to act as main root" + ); + }); }); - describe("JSON", () => { - describe("returns a validation failure when", () => { - it("the definition doesn't contain a main root node (has no root node identifier defined)", () => { - const definition = { - id: "not-main-root", - type: "root", - child: { - type: "action", - call: "noop" + describe("there are duplicate root node identifiers", () => { + it("(MDSL)", () => { + verifyResult( + "root { action [noop] } root [sub-root-node] { action [noop] } root [sub-root-node] { action [noop] }", + false, + "multiple root nodes found with duplicate name 'sub-root-node'" + ); + }); + + it("(JSON)", () => { + verifyResult( + [ + { + type: "root", + child: { + type: "action", + call: "noop" + } + }, + { + id: "sub-root-node", + type: "root", + child: { + type: "action", + call: "noop" + } + }, + { + id: "sub-root-node", + type: "root", + child: { + type: "action", + call: "noop" + } } - }; + ], + false, + "multiple root nodes found with duplicate 'id' property value of 'sub-root-node'" + ); + }); + }); - // The definition can be either an array (of root node definitions) or an object (the single primary root node definition), verify both. - verifyResult( - definition, - false, - "expected single root node without 'id' property defined to act as main root" - ); - verifyResult( - [definition], - false, - "expected single root node without 'id' property defined to act as main root" - ); - }); + describe("there are circular dependencies found in any branch node references", () => { + it("(MDSL)", () => { + verifyResult( + "root { branch [RN_A] } root [RN_A] { branch [RN_B] } root [RN_B] { branch [RN_C] } root [RN_C] { branch [RN_A] }", + false, + "circular dependency found in branch node references: RN_A => RN_B => RN_C => RN_A" + ); + }); - it("there are duplicate root node identifiers", () => { - verifyResult( - [ - { - type: "root", - child: { - type: "action", - call: "noop" - } - }, - { - id: "sub-root-node", - type: "root", - child: { - type: "action", - call: "noop" - } - }, - { - id: "sub-root-node", - type: "root", - child: { - type: "action", - call: "noop" - } + it("(JSON)", () => { + verifyResult( + [ + { + type: "root", + child: { + type: "branch", + ref: "RN_A" } - ], - false, - "multiple root nodes found with duplicate 'id' property value of 'sub-root-node'" - ); - }); - - it("there are circular dependencies found in any branch node references", () => { - verifyResult( - [ - { - type: "root", - child: { - type: "branch", - ref: "RN_A" - } - }, - { - id: "RN_A", - type: "root", - child: { - type: "branch", - ref: "RN_B" - } - }, - { - id: "RN_B", - type: "root", - child: { - type: "branch", - ref: "RN_C" - } - }, - { - id: "RN_C", - type: "root", - child: { - type: "branch", - ref: "RN_A" - } + }, + { + id: "RN_A", + type: "root", + child: { + type: "branch", + ref: "RN_B" + } + }, + { + id: "RN_B", + type: "root", + child: { + type: "branch", + ref: "RN_C" } - ], - false, - "circular dependency found in branch node references: RN_A => RN_B => RN_C => RN_A" - ); - }); + }, + { + id: "RN_C", + type: "root", + child: { + type: "branch", + ref: "RN_A" + } + } + ], + false, + "circular dependency found in branch node references: RN_A => RN_B => RN_C => RN_A" + ); }); }); }); From db1c489c83921f3050795e54be8839590e12fbcd Mon Sep 17 00:00:00 2001 From: Nikolas Howard Date: Tue, 27 Feb 2024 17:46:36 +0000 Subject: [PATCH 38/48] Adding specs and fixing bugs and typings --- dist/Agent.d.ts | 8 +- dist/Lookup.d.ts | 6 +- dist/bundle.js | 48 +++--- dist/bundle.js.map | 4 +- dist/index.js | 48 +++--- dist/index.js.map | 4 +- src/Agent.ts | 8 +- src/BehaviourTreeBuilder.ts | 11 +- src/Lookup.ts | 33 ++-- src/mdsl/MDSLDefinitionParser.ts | 13 +- src/mdsl/MDSLNodeAttributeParser.ts | 2 +- src/nodes/leaf/Action.ts | 5 +- test/BehaviourTreeBuilder.spec.ts | 143 ++++++++++++++++- test/attributes/callbacks/Entry.spec.ts | 102 ++++++++++++ test/attributes/callbacks/Exit.spec.ts | 1 + test/attributes/callbacks/Step.spec.ts | 1 + test/attributes/guards/Until.spec.ts | 1 + test/attributes/guards/While.spec.ts | 1 + test/mdsl/MDSLDefinitionParser.spec.ts | 203 +++++++++++++++++++++++- test/nodes/leaf/Action.spec.ts | 36 +++++ 20 files changed, 588 insertions(+), 90 deletions(-) create mode 100644 test/attributes/callbacks/Entry.spec.ts create mode 100644 test/attributes/callbacks/Exit.spec.ts create mode 100644 test/attributes/callbacks/Step.spec.ts create mode 100644 test/attributes/guards/Until.spec.ts create mode 100644 test/attributes/guards/While.spec.ts diff --git a/dist/Agent.d.ts b/dist/Agent.d.ts index 1287ddc..25d35f4 100644 --- a/dist/Agent.d.ts +++ b/dist/Agent.d.ts @@ -1,4 +1,4 @@ -import { CompleteState } from "./State"; +import State, { CompleteState } from "./State"; /** * A type representing an agent that a behavior tree instance would operate on. */ @@ -10,6 +10,6 @@ export type ExitFunctionArg = { aborted: boolean; }; export type FunctionArg = number | string | boolean | null | ExitFunctionArg; -export type ActionResult = CompleteState | Promise | boolean | void; -export type AgentFunction = (this: Agent, ...args: FunctionArg[]) => ActionResult; -export type GlobalFunction = (agent: Agent, ...args: FunctionArg[]) => ActionResult; +export type ActionResult = CompleteState | Promise | State.RUNNING | void; +export type AgentFunction = (this: Agent, ...args: FunctionArg[]) => ActionResult | boolean; +export type GlobalFunction = (agent: Agent, ...args: FunctionArg[]) => ActionResult | boolean; diff --git a/dist/Lookup.d.ts b/dist/Lookup.d.ts index 134dd92..e9534b4 100644 --- a/dist/Lookup.d.ts +++ b/dist/Lookup.d.ts @@ -1,6 +1,6 @@ import { ActionResult, Agent, GlobalFunction } from "./Agent"; import { RootNodeDefinition } from "./BehaviourTreeDefinition"; -export type InvokerFunction = (args: any[]) => ActionResult; +export type InvokerFunction = (args: any[]) => ActionResult | boolean; /** * A singleton used to store and lookup registered functions and subtrees. */ @@ -8,11 +8,11 @@ export default class Lookup { /** * The object holding any registered functions keyed on function name. */ - private static functionTable; + private static registeredFunctions; /** * The object holding any registered subtree root node definitions keyed on tree name. */ - private static subtreeTable; + private static registeredSubtrees; /** * Gets the function with the specified name. * @param name The name of the function. diff --git a/dist/bundle.js b/dist/bundle.js index 4b6249f..f286b8b 100644 --- a/dist/bundle.js +++ b/dist/bundle.js @@ -414,7 +414,7 @@ var mistreevous = (() => { stringArgumentPlaceholders ); if (attributeCallIdentifier?.type !== "identifier") { - throw new Error("expected agent function name identifier argument for attribute"); + throw new Error("expected agent function or registered function name identifier argument for attribute"); } attributeArguments.filter((arg) => arg.type === "identifier").forEach((arg) => { throw new Error( @@ -558,8 +558,7 @@ var mistreevous = (() => { } function createRootNode(tokens, stringLiteralPlaceholders) { let node = { - type: "root", - id: void 0 + type: "root" }; const nodeArguments = parseArgumentTokens(tokens, stringLiteralPlaceholders); if (nodeArguments.length) { @@ -688,9 +687,11 @@ var mistreevous = (() => { }); const node = { type: "lotto", - weights: nodeArguments.length ? nodeArguments.map(({ value }) => value) : void 0, ...parseAttributeTokens(tokens, stringLiteralPlaceholders) }; + if (nodeArguments.length) { + node.weights = nodeArguments.map(({ value }) => value); + } popAndCheck(tokens, "{"); return node; } @@ -1223,38 +1224,39 @@ var mistreevous = (() => { // src/Lookup.ts var Lookup = class { static getFunc(name) { - return this.functionTable[name]; + return this.registeredFunctions[name]; } static setFunc(name, func) { - this.functionTable[name] = func; + this.registeredFunctions[name] = func; } static getFuncInvoker(agent, name) { - const foundOnAgent = agent[name]; - if (foundOnAgent && typeof foundOnAgent === "function") { - return (args) => foundOnAgent.apply(agent, args); + const agentFunction = agent[name]; + if (agentFunction && typeof agentFunction === "function") { + return (args) => agentFunction.apply(agent, args); } - if (this.functionTable[name] && typeof this.functionTable[name] === "function") { - return (args) => this.functionTable[name](agent, ...args.map((arg) => arg.value)); + if (this.registeredFunctions[name] && typeof this.registeredFunctions[name] === "function") { + const registeredFunction = this.registeredFunctions[name]; + return (args) => registeredFunction(agent, ...args.map((arg) => arg.value)); } return null; } static getSubtrees() { - return this.subtreeTable; + return this.registeredSubtrees; } static setSubtree(name, subtree) { - this.subtreeTable[name] = subtree; + this.registeredSubtrees[name] = subtree; } static remove(name) { - delete this.functionTable[name]; - delete this.subtreeTable[name]; + delete this.registeredFunctions[name]; + delete this.registeredSubtrees[name]; } static empty() { - this.functionTable = {}; - this.subtreeTable = {}; + this.registeredFunctions = {}; + this.registeredSubtrees = {}; } }; - __publicField(Lookup, "functionTable", {}); - __publicField(Lookup, "subtreeTable", {}); + __publicField(Lookup, "registeredFunctions", {}); + __publicField(Lookup, "registeredSubtrees", {}); // src/attributes/guards/GuardUnsatisifedException.ts var GuardUnsatisifedException = class extends Error { @@ -1826,11 +1828,12 @@ var mistreevous = (() => { switch (result) { case "mistreevous.succeeded" /* SUCCEEDED */: case "mistreevous.failed" /* FAILED */: + case "mistreevous.running" /* RUNNING */: case void 0: return; default: throw new Error( - `action '${this.actionName}' 'onUpdate' returned an invalid response, expected an optional State.SUCCEEDED or State.FAILED value to be returned` + `expected action function '${this.actionName}' to return an optional State.SUCCEEDED or State.FAILED value but returned '${result}'` ); } }; @@ -2046,7 +2049,10 @@ var mistreevous = (() => { var MAIN_ROOT_NODE_KEY = Symbol("__root__"); function buildRootNode(definition) { const rootNodeDefinitionMap = createRootNodeDefinitionMap(definition); - validateBranchSubtreeLinks(definition, true); + validateBranchSubtreeLinks( + [rootNodeDefinitionMap[MAIN_ROOT_NODE_KEY], ...Object.values(rootNodeDefinitionMap)], + true + ); const rootNode = nodeFactory(rootNodeDefinitionMap[MAIN_ROOT_NODE_KEY], rootNodeDefinitionMap); applyLeafNodeGuardPaths(rootNode); return rootNode; diff --git a/dist/bundle.js.map b/dist/bundle.js.map index d3062ce..639768a 100644 --- a/dist/bundle.js.map +++ b/dist/bundle.js.map @@ -1,7 +1,7 @@ { "version": 3, "sources": ["../node_modules/lotto-draw/dist/Participant.js", "../node_modules/lotto-draw/dist/Utilities.js", "../node_modules/lotto-draw/dist/Lotto.js", "../node_modules/lotto-draw/dist/createLotto.js", "../node_modules/lotto-draw/dist/index.js", "../src/index.ts", "../src/State.ts", "../src/BehaviourTreeDefinitionUtilities.ts", "../src/mdsl/MDSLUtilities.ts", "../src/mdsl/MDSLNodeArgumentParser.ts", "../src/mdsl/MDSLNodeAttributeParser.ts", "../src/mdsl/MDSLDefinitionParser.ts", "../src/BehaviourTreeDefinitionValidator.ts", "../src/Lookup.ts", "../src/attributes/guards/GuardUnsatisifedException.ts", "../src/attributes/guards/GuardPath.ts", "../src/nodes/Node.ts", "../src/nodes/composite/Composite.ts", "../src/nodes/composite/Parallel.ts", "../src/nodes/composite/Selector.ts", "../src/nodes/composite/Sequence.ts", "../src/nodes/composite/Lotto.ts", "../src/nodes/decorator/Decorator.ts", "../src/nodes/decorator/Fail.ts", "../src/nodes/decorator/Flip.ts", "../src/nodes/decorator/Repeat.ts", "../src/nodes/decorator/Retry.ts", "../src/nodes/decorator/Root.ts", "../src/nodes/decorator/Succeed.ts", "../src/nodes/leaf/Leaf.ts", "../src/nodes/leaf/Action.ts", "../src/nodes/leaf/Condition.ts", "../src/nodes/leaf/Wait.ts", "../src/attributes/Attribute.ts", "../src/attributes/guards/Guard.ts", "../src/attributes/guards/While.ts", "../src/attributes/guards/Until.ts", "../src/attributes/callbacks/Callback.ts", "../src/attributes/callbacks/Entry.ts", "../src/attributes/callbacks/Step.ts", "../src/attributes/callbacks/Exit.ts", "../src/BehaviourTreeBuilder.ts", "../src/BehaviourTree.ts"], - "sourcesContent": ["\"use strict\";\r\nObject.defineProperty(exports, \"__esModule\", { value: true });\r\nexports.Participant = void 0;\r\n/**\r\n * A participant that holds a number of tickets.\r\n */\r\nvar Participant = /** @class */ (function () {\r\n /**\r\n * Creates an instance of the Participant class.\r\n * @param participant The actual participant.\r\n * @param tickets The number of tickets held by the participant.\r\n */\r\n function Participant(participant, tickets) {\r\n if (tickets === void 0) { tickets = 1; }\r\n this._participant = participant;\r\n this._tickets = tickets;\r\n }\r\n Object.defineProperty(Participant.prototype, \"participant\", {\r\n /** Gets the actual participant. */\r\n get: function () {\r\n return this._participant;\r\n },\r\n enumerable: false,\r\n configurable: true\r\n });\r\n Object.defineProperty(Participant.prototype, \"tickets\", {\r\n /** Gets or sets the number of tickets held by the participant. */\r\n get: function () {\r\n return this._tickets;\r\n },\r\n set: function (value) {\r\n this._tickets = value;\r\n },\r\n enumerable: false,\r\n configurable: true\r\n });\r\n return Participant;\r\n}());\r\nexports.Participant = Participant;\r\n", "\"use strict\";\r\nObject.defineProperty(exports, \"__esModule\", { value: true });\r\nexports.isNaturalNumber = exports.isNullOrUndefined = void 0;\r\n/**\r\n * Gets whether the value provided is null or undefined.\r\n * @param value The value to check.\r\n * @returns Whether the value provided is null or undefined.\r\n */\r\nfunction isNullOrUndefined(value) {\r\n return value === null || value === undefined;\r\n}\r\nexports.isNullOrUndefined = isNullOrUndefined;\r\n/**\r\n * Gets whether the value provided is a natural number.\r\n * @param value The value to check.\r\n * @returns Whether the value provided is a natural number.\r\n */\r\nfunction isNaturalNumber(value) {\r\n return typeof value === \"number\" && value >= 1 && Math.floor(value) === value;\r\n}\r\nexports.isNaturalNumber = isNaturalNumber;\r\n", "\"use strict\";\r\nObject.defineProperty(exports, \"__esModule\", { value: true });\r\nexports.Lotto = void 0;\r\nvar Participant_1 = require(\"./Participant\");\r\nvar Utilities_1 = require(\"./Utilities\");\r\n/**\r\n * Represents a lotto consisting of a number of pickable ticket-holding participants.\r\n */\r\nvar Lotto = /** @class */ (function () {\r\n /**\r\n * Creates a new instance of Lotto.\r\n * @param customRandom The custom RNG to use in place of Math.random().\r\n */\r\n function Lotto(customRandom) {\r\n /** The array of participants that are holding tickets in the lotto. */\r\n this._participants = [];\r\n this._customRandom = customRandom;\r\n }\r\n /**\r\n * Adds a participant with the specified number of tickets, or adds to the participant ticket count if the participant already holds tickets.\r\n * @param participant The participant to add or to increase the ticket count for if they already hold tickets.\r\n * @param tickets The number of tickets, defaults to 1.\r\n * @returns The Lotto instance.\r\n */\r\n Lotto.prototype.add = function (participant, tickets) {\r\n if (tickets === void 0) { tickets = 1; }\r\n // Check that we have a valid ticket count.\r\n if (!(0, Utilities_1.isNaturalNumber)(tickets)) {\r\n throw new Error(\"tickets value must be a natural number\");\r\n }\r\n // Check whether this participant has already been added.\r\n var existingParticipant = this._participants.find(function (part) { return part.participant === participant; });\r\n if (existingParticipant) {\r\n // The participant has already been added to the lotto so just add to their ticket count.\r\n existingParticipant.tickets += tickets;\r\n }\r\n else {\r\n // The participant is not part of the lotto so we should add them.\r\n this._participants.push(new Participant_1.Participant(participant, tickets));\r\n }\r\n return this;\r\n };\r\n /**\r\n * Removes the specified number of tickets for the given participant from the draw, or all tickets if a ticket number is not defined.\r\n * @param participant The participant to remove tickets for.\r\n * @param tickets The number of tickets to remove, or undefined if all tickets are to be removed.\r\n * @returns The Lotto instance.\r\n */\r\n Lotto.prototype.remove = function (participant, tickets) {\r\n // Attempt to get the existing participant.\r\n var existingParticipant = this._participants.find(function (part) { return part.participant === participant; });\r\n // There is nothing to do if the specified participant isn't even part of the lotto.\r\n if (!existingParticipant) {\r\n return this;\r\n }\r\n // Check whether a tickets value was given.\r\n if (tickets !== undefined) {\r\n // Check that we have a valid ticket count.\r\n if (!(0, Utilities_1.isNaturalNumber)(tickets)) {\r\n throw new Error(\"tickets value must be a natural number\");\r\n }\r\n existingParticipant.tickets -= tickets;\r\n // If the participant no longer holds any tickets then they should be removed.\r\n if (existingParticipant.tickets < 1) {\r\n this._participants = this._participants.filter(function (part) { return part !== existingParticipant; });\r\n }\r\n }\r\n else {\r\n // We are removing all tickets for the participant so just remove them from the lotto.\r\n this._participants = this._participants.filter(function (part) { return part !== existingParticipant; });\r\n }\r\n return this;\r\n };\r\n /**\r\n * Draw a winning ticket and return the participant that holds the ticket.\r\n * @param options The draw options.\r\n * @returns The participant that holds the winning ticket.\r\n */\r\n Lotto.prototype.draw = function (options) {\r\n if (options === void 0) { options = {}; }\r\n // If we have no participants then just return null.\r\n if (this._participants.length === 0) {\r\n return null;\r\n }\r\n var redrawable = (0, Utilities_1.isNullOrUndefined)(options.redrawable) ? true : options.redrawable;\r\n var pickable = [];\r\n this._participants.forEach(function (_a) {\r\n var participant = _a.participant, tickets = _a.tickets;\r\n for (var ticketCount = 0; ticketCount < tickets; ticketCount++) {\r\n pickable.push(participant);\r\n }\r\n });\r\n var random;\r\n // We need a random floating-point number between 0 (inclusive) and 1 to scale up to pick our winner.\r\n // If a custom random function exists then we should use that or fall back to Math.random().\r\n if (this._customRandom) {\r\n // Call our custom random function to get a random floating-point number.\r\n random = this._customRandom();\r\n // Verify that the result of calling our custom random function is a number between 0 (inclusive) and 1.\r\n if (typeof random !== \"number\" || random < 0 || random >= 1) {\r\n throw new Error(\"the 'random' function provided did not return a number between 0 (inclusive) and 1\");\r\n }\r\n }\r\n else {\r\n // No custom random function was defined so just use good ol' Math.random().\r\n random = Math.random();\r\n }\r\n // Pick a winning participant.\r\n var winner = pickable[Math.floor(random * pickable.length)];\r\n // If the ticket isn't redrawable then we should remove a ticket from the winning participants ticket count.\r\n if (!redrawable) {\r\n this.remove(winner, 1);\r\n }\r\n // Return the winning participant.\r\n return winner;\r\n };\r\n /**\r\n * Draws multiple winning tickets and return an array of the participants that hold the winning tickets.\r\n * @param tickets The number of winning tickets to draw.\r\n * @param options The draw multiple options.\r\n * @returns An array of the participants that hold the winning tickets.\r\n */\r\n Lotto.prototype.drawMultiple = function (tickets, options) {\r\n if (options === void 0) { options = {}; }\r\n var uniqueResults = (0, Utilities_1.isNullOrUndefined)(options.unique) ? false : options.unique;\r\n // Handle cases where the user has asked for zero tickets (no idea why they would do this be we should trust them).\r\n if (tickets === 0) {\r\n return [];\r\n }\r\n // Now that we know out tickets value is not zero we should check that it is a valid natural number.\r\n if (!(0, Utilities_1.isNaturalNumber)(tickets)) {\r\n throw new Error(\"tickets value must be a natural number\");\r\n }\r\n var result = [];\r\n // Keep drawing tickets until we either reach the number of required tickets or we simply run out of tickets to draw.\r\n // We can run out of tickets to draw if 'options.redrawable' is explicity 'false' or we just had no participants when 'drawMultiple' was called.\r\n while (result.length < tickets && this._participants.length > 0) {\r\n result.push(this.draw(options));\r\n }\r\n // If the 'unique' draw option is set then we need to remove duplicates from the result list.\r\n if (uniqueResults) {\r\n // Create an array to store our unique results.\r\n var unique = [];\r\n // Iterate over all of our participants (with potential duplicates) and populate our array of unique values.\r\n for (var _i = 0, result_1 = result; _i < result_1.length; _i++) {\r\n var participant = result_1[_i];\r\n if (unique.indexOf(participant) === -1) {\r\n unique.push(participant);\r\n }\r\n }\r\n result = unique;\r\n }\r\n return result;\r\n };\r\n return Lotto;\r\n}());\r\nexports.Lotto = Lotto;\r\n", "\"use strict\";\r\nObject.defineProperty(exports, \"__esModule\", { value: true });\r\nexports.createLotto = void 0;\r\nvar Lotto_1 = require(\"./Lotto\");\r\n/**\r\n * A function that creates and returns a Lotto instance.\r\n * @param participantsOrOptions An array of initial participants or options relating to the creation of a Lotto instance.\r\n * @returns A new Lotto instance.\r\n */\r\nfunction createLotto(participantsOrOptions) {\r\n // If no initial participants or lotto options were provided as an argument then we can just return a new lotto instance now.\r\n if (!participantsOrOptions) {\r\n return new Lotto_1.Lotto();\r\n }\r\n // Check whether we were provided with an array of initial participants or a lotto options object.\r\n if (Array.isArray(participantsOrOptions)) {\r\n // We are dealing with a pre-defined array of participants.\r\n var participants = participantsOrOptions;\r\n var lotto_1 = new Lotto_1.Lotto();\r\n // If the lotto participants have been defined upfront then we will need to add them all to our lotto instance now.\r\n participants.forEach(function (_a) {\r\n var participant = _a[0], tokens = _a[1];\r\n return lotto_1.add(participant, tokens);\r\n });\r\n // Return the Lotto instance.\r\n return lotto_1;\r\n }\r\n else {\r\n // We are dealing with some lotto options.\r\n var random = participantsOrOptions.random, participants = participantsOrOptions.participants;\r\n // Create a Lotto instance passing the custom RNG function to use in place of Math.random() (which could be undefined).\r\n var lotto_2 = new Lotto_1.Lotto(random);\r\n // If the lotto participants have been defined upfront as part of the options then we will need to add them all to our lotto instance now.\r\n if (participants) {\r\n participants.forEach(function (_a) {\r\n var participant = _a[0], tokens = _a[1];\r\n return lotto_2.add(participant, tokens);\r\n });\r\n }\r\n // Return the Lotto instance.\r\n return lotto_2;\r\n }\r\n}\r\nexports.createLotto = createLotto;\r\n", "\"use strict\";\r\nObject.defineProperty(exports, \"__esModule\", { value: true });\r\nvar createLotto_1 = require(\"./createLotto\");\r\nexports.default = createLotto_1.createLotto;\r\n", "import State from \"./State\";\nimport { validateDefinition } from \"./BehaviourTreeDefinitionValidator\";\nimport { convertMDSLToJSON } from \"./mdsl/MDSLDefinitionParser\";\nimport { BehaviourTree, FlattenedTreeNode } from \"./BehaviourTree\";\nimport { BehaviourTreeOptions } from \"./BehaviourTreeOptions\";\n\nexport { BehaviourTree, State, convertMDSLToJSON, validateDefinition };\nexport type { FlattenedTreeNode, BehaviourTreeOptions };\n", "/**\n * Enumeration of node state types.\n */\nexport enum State {\n READY = \"mistreevous.ready\",\n RUNNING = \"mistreevous.running\",\n SUCCEEDED = \"mistreevous.succeeded\",\n FAILED = \"mistreevous.failed\"\n}\n\nexport { State as default };\n\nexport type CompleteState = State.SUCCEEDED | State.FAILED;\nexport type AnyState = State.READY | State.RUNNING | CompleteState;\n", "import {\n NodeDefinition,\n RootNodeDefinition,\n DecoratorNodeDefinition,\n CompositeNodeDefinition,\n AnyNodeDefinition,\n BranchNodeDefinition\n} from \"./BehaviourTreeDefinition\";\n\n/**\n * A type guard function that returns true if the specified node satisfies the RootNodeDefinition type.\n * @param node The node.\n * @returns A value of true if the specified node satisfies the RootNodeDefinition type.\n */\nexport function isRootNode(node: NodeDefinition): node is RootNodeDefinition {\n return node.type === \"root\";\n}\n\n/**\n * A type guard function that returns true if the specified node satisfies the BranchNodeDefinition type.\n * @param node The node.\n * @returns A value of true if the specified node satisfies the BranchNodeDefinition type.\n */\nexport function isBranchNode(node: NodeDefinition): node is BranchNodeDefinition {\n return node.type === \"branch\";\n}\n\n/**\n * A type guard function that returns true if the specified node satisfies the NodeDefinition type.\n * @param node The node.\n * @returns A value of true if the specified node satisfies the NodeDefinition type.\n */\nexport function isLeafNode(node: NodeDefinition): node is NodeDefinition {\n return [\"branch\", \"action\", \"condition\", \"wait\"].includes(node.type);\n}\n\n/**\n * A type guard function that returns true if the specified node satisfies the DecoratorNodeDefinition type.\n * @param node The node.\n * @returns A value of true if the specified node satisfies the DecoratorNodeDefinition type.\n */\nexport function isDecoratorNode(node: NodeDefinition): node is DecoratorNodeDefinition {\n return [\"root\", \"repeat\", \"retry\", \"flip\", \"succeed\", \"fail\"].includes(node.type);\n}\n\n/**\n * A type guard function that returns true if the specified node satisfies the CompositeNodeDefinition type.\n * @param node The node.\n * @returns A value of true if the specified node satisfies the CompositeNodeDefinition type.\n */\nexport function isCompositeNode(node: NodeDefinition): node is CompositeNodeDefinition {\n return [\"sequence\", \"selector\", \"lotto\", \"parallel\"].includes(node.type);\n}\n\n/**\n * Flatten a node definition into an array of all of its nested node definitions.\n * @param nodeDefinition The node definition to flatten.\n * @returns An array of all of nested node definitions.\n */\nexport function flattenDefinition(nodeDefinition: AnyNodeDefinition): AnyNodeDefinition[] {\n const nodes: AnyNodeDefinition[] = [];\n\n const processNode = (currentNodeDefinition: AnyNodeDefinition) => {\n nodes.push(currentNodeDefinition);\n\n if (isCompositeNode(currentNodeDefinition)) {\n currentNodeDefinition.children.forEach(processNode);\n } else if (isDecoratorNode(currentNodeDefinition)) {\n processNode(currentNodeDefinition.child);\n }\n };\n\n processNode(nodeDefinition);\n\n return nodes;\n}\n\n/**\n * Determines whether the passed value is an integer.\n * @param value The value to check.\n * @returns Whether the passed value is an integer.\n */\nexport function isInteger(value: unknown): boolean {\n return typeof value === \"number\" && Math.floor(value) === value;\n}\n\n/**\n * Determines whether the passed value is null or undefined.\n * @param value The value to check.\n * @returns Whether the passed value is null or undefined.\n */\nexport function isNullOrUndefined(value: unknown): boolean {\n return typeof value === \"undefined\" || value === null;\n}\n", "/**\n * A type defining an object that holds a reference to substitued string literals parsed from the definition.\n */\nexport type StringLiteralPlaceholders = { [key: string]: string };\n\n/**\n * Pop the next raw token from the specified array of tokens and throw an error if it wasn't the expected one.\n * @param tokens The array of tokens.\n * @param expected An optional string or array or items, one of which must match the next popped token.\n * @returns The popped token.\n */\nexport function popAndCheck(tokens: string[], expected?: string | string[]): string {\n // Get and remove the next token.\n const popped = tokens.shift();\n\n // We were expecting another token but there aren't any.\n if (popped === undefined) {\n throw new Error(\"unexpected end of definition\");\n }\n\n // Do we have an expected token/tokens array?\n if (expected != undefined) {\n // Get an array of expected values, if the popped token matches any then we are all good.\n const expectedValues = typeof expected === \"string\" ? [expected] : expected;\n\n // Check whether the popped token matches at least one of our expected items.\n var tokenMatchesExpectation = expectedValues.some((item) => popped.toUpperCase() === item.toUpperCase());\n\n // Throw an error if the popped token didn't match any of our expected items.\n if (!tokenMatchesExpectation) {\n const expectationString = expectedValues.map((item) => \"'\" + item + \"'\").join(\" or \");\n throw new Error(\"unexpected token found. Expected \" + expectationString + \" but got '\" + popped + \"'\");\n }\n }\n\n // Return the popped token.\n return popped;\n}\n\n/**\n * Swaps out any node/attribute argument string literals with placeholders.\n * @param definition The definition.\n * @returns An object containing a mapping of placeholders to original string values as well as the processed definition string.\n */\nexport function substituteStringLiterals(definition: string): {\n placeholders: StringLiteralPlaceholders;\n processedDefinition: string;\n} {\n // Create an object to hold the mapping of placeholders to original string values.\n const placeholders: StringLiteralPlaceholders = {};\n\n // Replace any string literals wrapped with double quotes in our definition with placeholders to be processed later.\n const processedDefinition = definition.replace(/\\\"(\\\\.|[^\"\\\\])*\\\"/g, (match) => {\n var strippedMatch = match.substring(1, match.length - 1);\n var placeholder = Object.keys(placeholders).find((key) => placeholders[key] === strippedMatch);\n\n // If we have no existing string literal match then create a new placeholder.\n if (!placeholder) {\n placeholder = `@@${Object.keys(placeholders).length}@@`;\n placeholders[placeholder] = strippedMatch;\n }\n\n return placeholder;\n });\n\n return { placeholders, processedDefinition };\n}\n\n/**\n * Parse the tree definition into an array of raw tokens.\n * @param definition The definition.\n * @returns An array of tokens parsed from the definition.\n */\nexport function parseTokensFromDefinition(definition: string): string[] {\n // Add some space around various important characters so that they can be plucked out easier as individual tokens.\n definition = definition.replace(/\\(/g, \" ( \");\n definition = definition.replace(/\\)/g, \" ) \");\n definition = definition.replace(/\\{/g, \" { \");\n definition = definition.replace(/\\}/g, \" } \");\n definition = definition.replace(/\\]/g, \" ] \");\n definition = definition.replace(/\\[/g, \" [ \");\n definition = definition.replace(/\\,/g, \" , \");\n\n // Split the definition into raw token form and return it.\n return definition.replace(/\\s+/g, \" \").trim().split(\" \");\n}\n", "import { StringLiteralPlaceholders, popAndCheck } from \"./MDSLUtilities\";\n\n/**\n * A type representing any node function argument.\n */\ntype Argument = {\n /**\n * The argument value.\n */\n value: T;\n /**\n * The argument type, used for validation.\n */\n type: string;\n};\n\ntype NullArgument = Argument & {\n type: \"null\";\n};\n\ntype BooleanArgument = Argument & {\n type: \"boolean\";\n};\n\ntype NumberArgument = Argument & {\n type: \"number\";\n /**\n * A flag defining whether the number argument value is a valid integer. (used for validation)\n */\n isInteger: boolean;\n};\n\ntype StringPlaceholderArgument = Argument & {\n type: \"string\";\n};\n\ntype IdentifierArgument = Argument & {\n type: \"identifier\";\n};\n\n/**\n * A type representing a reference to any node function argument.\n */\ntype AnyArgument = NullArgument | BooleanArgument | NumberArgument | StringPlaceholderArgument | IdentifierArgument;\n\n/**\n * Parse an array of argument definitions from the specified tokens array.\n * @param tokens The array tokens to parse the argument definitions from.\n * @param stringArgumentPlaceholders The mapping of string literal node argument placeholders to original values.\n * @param argumentValidator The argument validator function.\n * @param validationFailedMessage The exception message to throw if argument validation fails.\n * @returns An array of argument definitions parsed from the specified tokens array.\n */\nexport function parseArgumentTokens(\n tokens: string[],\n stringArgumentPlaceholders: StringLiteralPlaceholders\n): AnyArgument[] {\n const argumentList: AnyArgument[] = [];\n\n // If the next token is not a '[' or '(' then we have no arguments to parse.\n if (![\"[\", \"(\"].includes(tokens[0])) {\n return argumentList;\n }\n\n // Any lists of arguments will always be wrapped in '[]' for node arguments or '()' for attribute arguments.\n // We are looking for a '[' or '(' opener that wraps the argument tokens and the relevant closer.\n const closingToken = popAndCheck(tokens, [\"[\", \"(\"]) === \"[\" ? \"]\" : \")\";\n\n const argumentListTokens: string[] = [];\n\n // Grab all tokens between the '[' and ']' or '(' and ')'.\n while (tokens.length && tokens[0] !== closingToken) {\n // The next token is part of our arguments list.\n argumentListTokens.push(tokens.shift()!);\n }\n\n // Validate the order of the argument tokens. Each token must either be a ',' or a single argument that satisfies the validator.\n argumentListTokens.forEach((token, index) => {\n // Get whether this token should be an actual argument.\n const shouldBeArgumentToken = !(index & 1);\n\n // If the current token should be an actual argument then validate it, otherwise it should be a ',' token.\n if (shouldBeArgumentToken) {\n // Get the argument definition.\n const argumentDefinition = getArgumentDefinition(token, stringArgumentPlaceholders);\n\n // This is a valid argument!\n argumentList.push(argumentDefinition);\n } else {\n // The current token should be a ',' token.\n if (token !== \",\") {\n throw new Error(`invalid argument list, expected ',' or ']' but got '${token}'`);\n }\n }\n });\n\n // The arguments list should terminate with a ']' or ')' token, depending on the opener.\n popAndCheck(tokens, closingToken);\n\n // Return the arguments.\n return argumentList;\n}\n\n/**\n * Gets an argument value definition.\n * @param token The argument token.\n * @param stringArgumentPlaceholders The mapping of string literal node argument placeholders to original values.\n * @returns An argument value definition.\n */\nfunction getArgumentDefinition(token: string, stringArgumentPlaceholders: StringLiteralPlaceholders): AnyArgument {\n // Check whether the token represents a null value.\n if (token === \"null\") {\n return {\n value: null,\n type: \"null\"\n } as NullArgument;\n }\n\n // Check whether the token represents a boolean value.\n if (token === \"true\" || token === \"false\") {\n return {\n value: token === \"true\",\n type: \"boolean\"\n } as BooleanArgument;\n }\n\n // Check whether the token represents a number value.\n // TODO: Relies on broken isNaN - see MDN.\n // if (!Number.isNaN(token)) {\n if (!isNaN(token as any)) {\n return {\n value: parseFloat(token),\n isInteger: parseFloat(token) === parseInt(token, 10),\n type: \"number\"\n } as NumberArgument;\n }\n\n // Check whether the token is a placeholder (e.g. @@0@@) representing a string literal.\n if (token.match(/^@@\\d+@@$/g)) {\n return {\n value: stringArgumentPlaceholders[token].replace('\\\\\"', '\"'),\n type: \"string\"\n } as StringPlaceholderArgument;\n }\n\n // The only remaining option is that the argument value is an identifier.\n return {\n value: token,\n type: \"identifier\"\n } as IdentifierArgument;\n}\n", "import { NodeAttributeDefinition } from \"../BehaviourTreeDefinition\";\nimport { parseArgumentTokens } from \"./MDSLNodeArgumentParser\";\nimport { StringLiteralPlaceholders } from \"./MDSLUtilities\";\n\n/**\n * A type defining the attribute definitions of a node.\n */\ntype NodeAttributes = {\n while?: NodeAttributeDefinition;\n until?: NodeAttributeDefinition;\n entry?: NodeAttributeDefinition;\n exit?: NodeAttributeDefinition;\n step?: NodeAttributeDefinition;\n};\n\n/**\n * Parse any node attribute definitions from the specified tokens array.\n * @param tokens The array of remaining tokens.\n * @param stringArgumentPlaceholders The mapping of string literal node argument placeholders to original values.\n * @returns An object of attribute definitions defined by any directly following tokens.\n */\nexport function parseAttributeTokens(\n tokens: string[],\n stringArgumentPlaceholders: StringLiteralPlaceholders\n): NodeAttributes {\n const nodeAttributeNames: (keyof NodeAttributes)[] = [\"while\", \"until\", \"entry\", \"exit\", \"step\"];\n\n // Create an object to hold any attributes found.\n const attributes: NodeAttributes = {};\n\n // Try to get the name of the attribute for the next token.\n let nextAttributeName = tokens[0]?.toLowerCase() as keyof NodeAttributes;\n\n // Pull attribute tokens as well as their arguments off of the tokens stack until we have no more.\n while (nodeAttributeNames.includes(nextAttributeName)) {\n // Check to make sure that we have not already created an attribute definition of this type.\n if (attributes[nextAttributeName]) {\n throw new Error(`duplicate attribute '${tokens[0].toUpperCase()}' found for node`);\n }\n\n // Remove the attribute name token from the array of tokens.\n tokens.shift();\n\n // Grab the attribute arguments, assuming the first to be an identifier.\n const [attributeCallIdentifier, ...attributeArguments] = parseArgumentTokens(\n tokens,\n stringArgumentPlaceholders\n );\n\n // The first attribute argument has to be an identifer, this will reference an agent function.\n if (attributeCallIdentifier?.type !== \"identifier\") {\n throw new Error(\"expected agent function name identifier argument for attribute\");\n }\n\n // Any attribute arguments (other than the expected call identifier) must have a type of string, number, boolean or null.\n attributeArguments\n .filter((arg) => arg.type === \"identifier\")\n .forEach((arg) => {\n throw new Error(\n `invalid attribute argument value '${arg.value}', must be string, number, boolean or null`\n );\n });\n\n // Create the attribute definition and add it to the object of attribute definitions found.\n attributes[nextAttributeName] = {\n call: attributeCallIdentifier.value,\n args: attributeArguments.map(({ value }) => value)\n };\n\n // Try to get the next attribute name token, as there could be multiple.\n nextAttributeName = tokens[0]?.toLowerCase() as keyof NodeAttributes;\n }\n\n return attributes;\n}\n", "import {\n ActionNodeDefinition,\n AnyChildNodeDefinition,\n AnyNodeDefinition,\n BranchNodeDefinition,\n ConditionNodeDefinition,\n FailNodeDefinition,\n FlipNodeDefinition,\n LottoNodeDefinition,\n ParallelNodeDefinition,\n RepeatNodeDefinition,\n RetryNodeDefinition,\n RootNodeDefinition,\n SelectorNodeDefinition,\n SequenceNodeDefinition,\n SucceedNodeDefinition,\n WaitNodeDefinition\n} from \"../BehaviourTreeDefinition\";\nimport {\n isCompositeNode,\n isDecoratorNode,\n isLeafNode,\n isNullOrUndefined,\n isRootNode\n} from \"../BehaviourTreeDefinitionUtilities\";\nimport { parseArgumentTokens } from \"./MDSLNodeArgumentParser\";\nimport { parseAttributeTokens } from \"./MDSLNodeAttributeParser\";\nimport {\n StringLiteralPlaceholders,\n parseTokensFromDefinition,\n popAndCheck,\n substituteStringLiterals\n} from \"./MDSLUtilities\";\n\n/**\n * Convert the MDSL tree definition string into an equivalent JSON definition.\n * @param definition The tree definition string as MDSL.\n * @returns The root node JSON definitions.\n */\nexport function convertMDSLToJSON(definition: string): RootNodeDefinition[] {\n // Swap out any node/attribute argument string literals with a placeholder and get a mapping of placeholders to original values as well as the processed definition.\n const { placeholders, processedDefinition } = substituteStringLiterals(definition);\n\n // Parse our definition definition string into an array of raw tokens.\n const tokens = parseTokensFromDefinition(processedDefinition);\n\n return convertTokensToJSONDefinition(tokens, placeholders);\n}\n\n/**\n * Converts the specified tree definition tokens into a JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The root node JSON definitions.\n */\nfunction convertTokensToJSONDefinition(\n tokens: string[],\n stringLiteralPlaceholders: StringLiteralPlaceholders\n): RootNodeDefinition[] {\n // There must be at least 3 tokens for the tree definition to be valid. 'ROOT', '{' and '}'.\n if (tokens.length < 3) {\n throw new Error(\"invalid token count\");\n }\n\n // We should have a matching number of '{' and '}' tokens. If not, then there are scopes that have not been properly closed.\n if (tokens.filter((token) => token === \"{\").length !== tokens.filter((token) => token === \"}\").length) {\n throw new Error(\"scope character mismatch\");\n }\n\n // Create an array of tree stack arrays where root nodes will always be at the botton and the current composite/decorator node at the top.\n // There should be an element in this array for every root node defined and every element should be an array with a root note as the first element.\n // E.g. A definition with two root nodes defined:\n // [\n // [root, lotto, sequence],\n // [root, selector]\n // ]\n const treeStacks: [Partial, ...Partial[]][] = [];\n\n // Create an array of all root node definitions that we create.\n const rootNodes: Partial[] = [];\n\n // A helper function used to push node definitions onto the tree stack.\n const pushNode = (node: AnyNodeDefinition) => {\n // If the node is a root node then we need to create a new tree stack array with the root node at the root.\n if (isRootNode(node)) {\n // We need to double-check that this root node is not the child of another node.\n // We can do this by checking whether the top tree stack is not empty (contains an existing node)\n if (treeStacks[treeStacks.length - 1]?.length) {\n throw new Error(\"a root node cannot be the child of another node\");\n }\n\n // Add the root node definition to our array of all parsed root node definitions.\n rootNodes.push(node);\n\n // Add the root node definition to the root of a new tree stack.\n treeStacks.push([node]);\n\n return;\n }\n\n // All non-root nodes should be pushed after their root nodes so handle cases\n // where we may not have any tree stacks or our top-most tree stack is empty.\n if (!treeStacks.length || !treeStacks[treeStacks.length - 1].length) {\n throw new Error(\"expected root node at base of definition\");\n }\n\n // Get the current tree stack that we are populating.\n const topTreeStack = treeStacks[treeStacks.length - 1];\n\n // Get the top-most node in the current tree stack, this will be a composite/decorator node\n // for which we will populate its children array if composite or setting its child if a decorator.\n const topTreeStackTopNode = topTreeStack[topTreeStack.length - 1] as AnyNodeDefinition;\n\n // If the top-most node in the current root stack is a composite or decorator\n // node then the current node should be added as a child of the top-most node.\n if (isCompositeNode(topTreeStackTopNode)) {\n topTreeStackTopNode.children = topTreeStackTopNode.children || [];\n topTreeStackTopNode.children.push(node);\n } else if (isDecoratorNode(topTreeStackTopNode)) {\n // If the top node already has a child node set then throw an error as a decorator should only have a single child.\n if (topTreeStackTopNode.child) {\n throw new Error(\"a decorator node must only have a single child node\");\n }\n\n topTreeStackTopNode.child = node;\n }\n\n // If the node we are adding is also a composite or decorator node, then we should push it\n // onto the current tree stack, as subsequent nodes will be added as its child/children.\n if (!isLeafNode(node)) {\n topTreeStack.push(node);\n }\n };\n\n // A helper function used to pop the top-most node definition off of the tree stack and return it.\n const popNode = (): AnyNodeDefinition | null => {\n let poppedNode: AnyNodeDefinition | null = null;\n\n // Get the current tree stack that we are populating.\n const topTreeStack = treeStacks[treeStacks.length - 1];\n\n // Pop the top-most node in the current tree stack if there is one.\n if (topTreeStack.length) {\n poppedNode = topTreeStack.pop() as AnyNodeDefinition;\n }\n\n // We don't want any empty tree stacks in our stack of tree stacks.\n if (!topTreeStack.length) {\n treeStacks.pop();\n }\n\n return poppedNode;\n };\n\n // We should keep processing the raw tokens until we run out of them.\n while (tokens.length) {\n // Grab the next token.\n const token = tokens.shift()!;\n\n // How we create the next node depends on the current raw token value.\n switch (token.toUpperCase()) {\n case \"ROOT\": {\n pushNode(createRootNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"SUCCEED\": {\n pushNode(createSucceedNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"FAIL\": {\n pushNode(createFailNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"FLIP\": {\n pushNode(createFlipNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"REPEAT\": {\n pushNode(createRepeatNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"RETRY\": {\n pushNode(createRetryNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"SEQUENCE\": {\n pushNode(createSequenceNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"SELECTOR\": {\n pushNode(createSelectorNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"PARALLEL\": {\n pushNode(createParallelNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"LOTTO\": {\n pushNode(createLottoNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"ACTION\": {\n pushNode(createActionNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"CONDITION\": {\n pushNode(createConditionNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"WAIT\": {\n pushNode(createWaitNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"BRANCH\": {\n pushNode(createBranchNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"}\": {\n // The '}' character closes the current scope and means that we have to pop a node off of the current stack.\n const poppedNode = popNode();\n\n // Now that we have a node definition we can carry out any validation that may require the node to be fully populated.\n if (poppedNode) {\n validatePoppedNode(poppedNode);\n }\n\n break;\n }\n\n default: {\n throw new Error(`unexpected token: ${token}`);\n }\n }\n }\n\n return rootNodes as RootNodeDefinition[];\n}\n\n/**\n * Creates a root node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The root node JSON definition.\n */\nfunction createRootNode(tokens: string[], stringLiteralPlaceholders: StringLiteralPlaceholders): RootNodeDefinition {\n // Create the root node definition.\n let node = {\n type: \"root\",\n id: undefined\n } as RootNodeDefinition;\n\n // Parse any node arguments, we should only have one if any which will be an identifier argument for the root identifier.\n const nodeArguments = parseArgumentTokens(tokens, stringLiteralPlaceholders);\n\n // Check whether any node arguments were defined.\n if (nodeArguments.length) {\n // We should only have one argument, if any, which will be an identifier argument for the root identifier.\n if (nodeArguments.length === 1 && nodeArguments[0].type === \"identifier\") {\n // The root node identifier will be the first and only node argument value.\n node.id = nodeArguments[0].value as string;\n } else {\n throw new Error(\"expected single root name argument\");\n }\n }\n\n // Grab any node attribute definitions and spread them into the node definition.\n node = { ...node, ...parseAttributeTokens(tokens, stringLiteralPlaceholders) };\n\n // This is a decorator node, so we expect an opening '{'.\n popAndCheck(tokens, \"{\");\n\n // Return the root node definition.\n return node;\n}\n\n/**\n * Creates a succeed node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The succeed node JSON definition.\n */\nfunction createSucceedNode(\n tokens: string[],\n stringLiteralPlaceholders: StringLiteralPlaceholders\n): SucceedNodeDefinition {\n const node = {\n type: \"succeed\",\n ...parseAttributeTokens(tokens, stringLiteralPlaceholders)\n } as SucceedNodeDefinition;\n\n // This is a decorator node, so we expect an opening '{'.\n popAndCheck(tokens, \"{\");\n\n // Return the succeed node definition.\n return node;\n}\n\n/**\n * Creates a fail node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The fail node JSON definition.\n */\nfunction createFailNode(tokens: string[], stringLiteralPlaceholders: StringLiteralPlaceholders): FailNodeDefinition {\n const node = {\n type: \"fail\",\n ...parseAttributeTokens(tokens, stringLiteralPlaceholders)\n } as FailNodeDefinition;\n\n // This is a decorator node, so we expect an opening '{'.\n popAndCheck(tokens, \"{\");\n\n // Return the fail node definition.\n return node;\n}\n\n/**\n * Creates a flip node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The flip node JSON definition.\n */\nfunction createFlipNode(tokens: string[], stringLiteralPlaceholders: StringLiteralPlaceholders): FlipNodeDefinition {\n const node = {\n type: \"flip\",\n ...parseAttributeTokens(tokens, stringLiteralPlaceholders)\n } as FlipNodeDefinition;\n\n // This is a decorator node, so we expect an opening '{'.\n popAndCheck(tokens, \"{\");\n\n // Return the flip node definition.\n return node;\n}\n\n/**\n * Creates a repeat node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The repeat node JSON definition.\n */\nfunction createRepeatNode(\n tokens: string[],\n stringLiteralPlaceholders: StringLiteralPlaceholders\n): RepeatNodeDefinition {\n let node = { type: \"repeat\" } as RepeatNodeDefinition;\n\n // Get the node arguments.\n const nodeArguments = parseArgumentTokens(tokens, stringLiteralPlaceholders);\n\n // The arguments of a repeat node are optional. We may have:\n // - No node arguments, in which case the repeat note will iterate indefinitely.\n // - One node argument which will be the explicit number of iterations to make.\n // - Two node arguments which define the min and max iteration bounds from which a random iteration count will be picked.\n if (nodeArguments.length) {\n // All repeat node arguments MUST be of type number and must be integer.\n nodeArguments\n .filter((arg) => arg.type !== \"number\" || !arg.isInteger)\n .forEach(() => {\n throw new Error(`repeat node iteration counts must be integer values`);\n });\n\n // We should have got one or two iteration counts.\n if (nodeArguments.length === 1) {\n // A static iteration count was defined.\n node.iterations = nodeArguments[0].value as number;\n\n // A repeat node must have a positive number of iterations if defined.\n if (node.iterations < 0) {\n throw new Error(\"a repeat node must have a positive number of iterations if defined\");\n }\n } else if (nodeArguments.length === 2) {\n // A minimum and maximum iteration count was defined.\n node.iterations = [nodeArguments[0].value as number, nodeArguments[1].value as number];\n\n // A repeat node must have a positive min and max iteration count if they are defined.\n if (node.iterations[0] < 0 || node.iterations[1] < 0) {\n throw new Error(\"a repeat node must have a positive minimum and maximum iteration count if defined\");\n }\n\n // A repeat node must not have an minimum iteration count that exceeds the maximum iteration count.\n if (node.iterations[0] > node.iterations[1]) {\n throw new Error(\n \"a repeat node must not have a minimum iteration count that exceeds the maximum iteration count\"\n );\n }\n } else {\n // An incorrect number of iteration counts was defined.\n throw new Error(\"invalid number of repeat node iteration count arguments defined\");\n }\n }\n\n // Grab any node attribute definitions and spread them into the node definition.\n node = { ...node, ...parseAttributeTokens(tokens, stringLiteralPlaceholders) };\n\n // This is a decorator node, so we expect an opening '{'.\n popAndCheck(tokens, \"{\");\n\n // Return the repeat node definition.\n return node;\n}\n\n/**\n * Creates a retry node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The retry node JSON definition.\n */\nfunction createRetryNode(tokens: string[], stringLiteralPlaceholders: StringLiteralPlaceholders): RetryNodeDefinition {\n let node = { type: \"retry\" } as RetryNodeDefinition;\n\n // Get the node arguments.\n const nodeArguments = parseArgumentTokens(tokens, stringLiteralPlaceholders);\n\n // The arguments of a retry node are optional. We may have:\n // - No node arguments, in which case the retry note will attempt indefinitely.\n // - One node argument which will be the explicit number of attempts to make.\n // - Two node arguments which define the min and max attempt bounds from which a random attempt count will be picked.\n if (nodeArguments.length) {\n // All retry node arguments MUST be of type number and must be integer.\n nodeArguments\n .filter((arg) => arg.type !== \"number\" || !arg.isInteger)\n .forEach(() => {\n throw new Error(`retry node attempt counts must be integer values`);\n });\n\n // We should have got one or two attempt counts.\n if (nodeArguments.length === 1) {\n // A static attempt count was defined.\n node.attempts = nodeArguments[0].value as number;\n\n // A retry node must have a positive number of attempts if defined.\n if (node.attempts < 0) {\n throw new Error(\"a retry node must have a positive number of attempts if defined\");\n }\n } else if (nodeArguments.length === 2) {\n // A minimum and maximum attempt count was defined.\n node.attempts = [nodeArguments[0].value as number, nodeArguments[1].value as number];\n\n // A retry node must have a positive min and max attempts count if they are defined.\n if (node.attempts[0] < 0 || node.attempts[1] < 0) {\n throw new Error(\"a retry node must have a positive minimum and maximum attempt count if defined\");\n }\n\n // A retry node must not have a minimum attempt count that exceeds the maximum attempt count.\n if (node.attempts[0] > node.attempts[1]) {\n throw new Error(\n \"a retry node must not have a minimum attempt count that exceeds the maximum attempt count\"\n );\n }\n } else {\n // An incorrect number of attempt counts was defined.\n throw new Error(\"invalid number of retry node attempt count arguments defined\");\n }\n }\n\n // Grab any node attribute definitions and spread them into the node definition.\n node = { ...node, ...parseAttributeTokens(tokens, stringLiteralPlaceholders) };\n\n // This is a decorator node, so we expect an opening '{'.\n popAndCheck(tokens, \"{\");\n\n // Return the retry node definition.\n return node;\n}\n\n/**\n * Creates a sequence node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The sequence node JSON definition.\n */\nfunction createSequenceNode(\n tokens: string[],\n stringLiteralPlaceholders: StringLiteralPlaceholders\n): SequenceNodeDefinition {\n const node = {\n type: \"sequence\",\n ...parseAttributeTokens(tokens, stringLiteralPlaceholders)\n } as SequenceNodeDefinition;\n\n // This is a composite node, so we expect an opening '{'.\n popAndCheck(tokens, \"{\");\n\n // Return the sequence node definition.\n return node;\n}\n\n/**\n * Creates a selector node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The selector node JSON definition.\n */\nfunction createSelectorNode(\n tokens: string[],\n stringLiteralPlaceholders: StringLiteralPlaceholders\n): SelectorNodeDefinition {\n const node = {\n type: \"selector\",\n ...parseAttributeTokens(tokens, stringLiteralPlaceholders)\n } as SelectorNodeDefinition;\n\n // This is a composite node, so we expect an opening '{'.\n popAndCheck(tokens, \"{\");\n\n // Return the selector node definition.\n return node;\n}\n\n/**\n * Creates a parallel node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The parallel node JSON definition.\n */\nfunction createParallelNode(\n tokens: string[],\n stringLiteralPlaceholders: StringLiteralPlaceholders\n): ParallelNodeDefinition {\n const node = {\n type: \"parallel\",\n ...parseAttributeTokens(tokens, stringLiteralPlaceholders)\n } as ParallelNodeDefinition;\n\n // This is a composite node, so we expect an opening '{'.\n popAndCheck(tokens, \"{\");\n\n // Return the parallel node definition.\n return node;\n}\n\n/**\n * Creates a lotto node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The lotto node JSON definition.\n */\nfunction createLottoNode(tokens: string[], stringLiteralPlaceholders: StringLiteralPlaceholders): LottoNodeDefinition {\n // If any node arguments have been defined then they must be our weights.\n const nodeArguments = parseArgumentTokens(tokens, stringLiteralPlaceholders);\n\n // All lotto node arguments MUST be of type number and must be positive integers.\n nodeArguments\n .filter((arg) => arg.type !== \"number\" || !arg.isInteger || arg.value < 0)\n .forEach(() => {\n throw new Error(`lotto node weight arguments must be positive integer values`);\n });\n\n const node = {\n type: \"lotto\",\n weights: nodeArguments.length ? nodeArguments.map(({ value }) => value) : undefined,\n ...parseAttributeTokens(tokens, stringLiteralPlaceholders)\n } as LottoNodeDefinition;\n\n // This is a composite node, so we expect an opening '{'.\n popAndCheck(tokens, \"{\");\n\n // Return the lotto node definition.\n return node;\n}\n\n/**\n * Creates an action node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The action node JSON definition.\n */\nfunction createActionNode(\n tokens: string[],\n stringLiteralPlaceholders: StringLiteralPlaceholders\n): ActionNodeDefinition {\n // Parse any node arguments, we should have at least one which will be an identifier argument for the action name\n // and agent function to invoke for the action, all other arguments are to be passed as arguments to that function.\n const [actionNameIdentifier, ...agentFunctionArgs] = parseArgumentTokens(tokens, stringLiteralPlaceholders);\n\n // Our first argument MUST be defined and be an identifier as we require an action name argument.\n if (actionNameIdentifier?.type !== \"identifier\") {\n throw new Error(\"expected action name identifier argument\");\n }\n\n // Only the first argument should have been an identifier, all agent function arguments must be string, number, boolean or null.\n agentFunctionArgs\n .filter((arg) => arg.type === \"identifier\")\n .forEach((arg) => {\n throw new Error(\n `invalid action node argument value '${arg.value}', must be string, number, boolean or null`\n );\n });\n\n // Return the action node definition.\n return {\n type: \"action\",\n call: actionNameIdentifier.value,\n args: agentFunctionArgs.map(({ value }) => value),\n ...parseAttributeTokens(tokens, stringLiteralPlaceholders)\n };\n}\n\n/**\n * Creates a condition node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The condition node JSON definition.\n */\nfunction createConditionNode(\n tokens: string[],\n stringLiteralPlaceholders: StringLiteralPlaceholders\n): ConditionNodeDefinition {\n // Parse any node arguments, we should have at least one which will be an identifier argument for the condition name\n // and agent function to invoke for the condition, all other arguments are to be passed as arguments to that function.\n const [conditionNameIdentifier, ...agentFunctionArgs] = parseArgumentTokens(tokens, stringLiteralPlaceholders);\n\n // Our first argument MUST be defined and be an identifier as we require a condition name argument.\n if (conditionNameIdentifier?.type !== \"identifier\") {\n throw new Error(\"expected condition name identifier argument\");\n }\n\n // Only the first argument should have been an identifier, all agent function arguments must be string, number, boolean or null.\n agentFunctionArgs\n .filter((arg) => arg.type === \"identifier\")\n .forEach((arg) => {\n throw new Error(\n `invalid condition node argument value '${arg.value}', must be string, number, boolean or null`\n );\n });\n\n // Return the condition node definition.\n return {\n type: \"condition\",\n call: conditionNameIdentifier.value,\n args: agentFunctionArgs.map(({ value }) => value),\n ...parseAttributeTokens(tokens, stringLiteralPlaceholders)\n };\n}\n\n/**\n * Creates a wait node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The wait node JSON definition.\n */\nfunction createWaitNode(tokens: string[], stringLiteralPlaceholders: StringLiteralPlaceholders): WaitNodeDefinition {\n let node = { type: \"wait\" } as WaitNodeDefinition;\n\n // Get the node arguments.\n const nodeArguments = parseArgumentTokens(tokens, stringLiteralPlaceholders);\n\n // The arguments of a wait node are optional. We may have:\n // - No node arguments, in which case the wait will be indefinite until it is aborted.\n // - One node argument which will be the explicit duration of the wait.\n // - Two node arguments which define the min and max duration bounds from which a random duration will be picked.\n if (nodeArguments.length) {\n // All wait node arguments MUST be of type number and must be integer.\n nodeArguments\n .filter((arg) => arg.type !== \"number\" || !arg.isInteger)\n .forEach(() => {\n throw new Error(`wait node durations must be integer values`);\n });\n\n // We may have:\n // - One node argument which will be the explicit duration of the wait.\n // - Two node arguments which define the min and max duration bounds from which a random duration will be picked.\n // - Too many arguments, which is not valid.\n if (nodeArguments.length === 1) {\n // An explicit duration was defined.\n node.duration = nodeArguments[0].value as number;\n\n // If an explict duration was defined then it must be a positive number.\n if (node.duration < 0) {\n throw new Error(\"a wait node must have a positive duration\");\n }\n } else if (nodeArguments.length === 2) {\n // Min and max duration bounds were defined from which a random duration will be picked.\n node.duration = [nodeArguments[0].value as number, nodeArguments[1].value as number];\n\n // A wait node must have a positive min and max duration.\n if (node.duration[0] < 0 || node.duration[1] < 0) {\n throw new Error(\"a wait node must have a positive minimum and maximum duration\");\n }\n\n // A wait node must not have a minimum duration that exceeds the maximum duration.\n if (node.duration[0] > node.duration[1]) {\n throw new Error(\"a wait node must not have a minimum duration that exceeds the maximum duration\");\n }\n } else if (nodeArguments.length > 2) {\n // An incorrect number of duration arguments were defined.\n throw new Error(\"invalid number of wait node duration arguments defined\");\n }\n }\n\n // Return the wait node definition.\n return { ...node, ...parseAttributeTokens(tokens, stringLiteralPlaceholders) };\n}\n\n/**\n * Creates a branch node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The branch node JSON definition.\n */\nfunction createBranchNode(\n tokens: string[],\n stringLiteralPlaceholders: StringLiteralPlaceholders\n): BranchNodeDefinition {\n // Parse any node arguments, we should have one which will be an identifier argument for the root ref.\n const nodeArguments = parseArgumentTokens(tokens, stringLiteralPlaceholders);\n\n // We should have only a single identifer argument for a branch node, which is the root ref.\n if (nodeArguments.length !== 1 || nodeArguments[0].type !== \"identifier\") {\n throw new Error(\"expected single branch name argument\");\n }\n\n // Return the branch node definition.\n return { type: \"branch\", ref: nodeArguments[0].value };\n}\n\n/**\n * Validate a fully-populated node definition that was popped off of the tree stack.\n * @param definition The popped node to validate.\n */\nfunction validatePoppedNode(definition: AnyNodeDefinition): void {\n // Decorators MUST have a child defined.\n if (isDecoratorNode(definition) && isNullOrUndefined(definition.child)) {\n throw new Error(`a ${definition.type} node must have a single child node defined`);\n }\n\n // Composites MUST have at least one child defined.\n if (isCompositeNode(definition) && !definition.children?.length) {\n throw new Error(`a ${definition.type} node must have at least a single child node defined`);\n }\n\n // We need to make sure that lotto nodes that have weights defined have a number of weights matching the number of child nodes.\n if (definition.type === \"lotto\") {\n // Check whether a 'weights' property has been defined, if it has we expect it to be an array of weights.\n if (typeof definition.weights !== \"undefined\") {\n // Check that the weights property is an array of positive integers with an element for each child node element.\n if (definition.weights.length !== definition.children.length) {\n throw new Error(\n \"expected a number of weight arguments matching the number of child nodes for lotto node\"\n );\n }\n }\n }\n}\n", "import { RootNodeDefinition } from \"./BehaviourTreeDefinition\";\nimport { flattenDefinition, isBranchNode, isInteger } from \"./BehaviourTreeDefinitionUtilities\";\nimport { convertMDSLToJSON } from \"./mdsl/MDSLDefinitionParser\";\n\n/**\n * An object representing the result of validating a tree definition.\n */\nexport type DefinitionValidationResult = {\n /**\n * A flag defining whether validation succeeded.\n */\n succeeded: boolean;\n /**\n * A string containing the error message if validation did not succeed.\n */\n errorMessage?: string;\n /**\n * The definition as json if the validation was successful, or undefined if validation did not succeed.\n */\n json?: RootNodeDefinition[];\n};\n\n/**\n * Validates the specified behaviour tree definition in the form of JSON or MDSL, not taking any globally registered subtrees into consideration.\n * @param definition The behaviour tree definition in the form of JSON or MDSL.\n * @returns An object representing the result of validating the given tree definition.\n */\nexport function validateDefinition(definition: any): DefinitionValidationResult {\n // The definition must be defined.\n if (definition === null || typeof definition === \"undefined\") {\n return createValidationFailureResult(\"definition is null or undefined\");\n }\n\n // We are expecting a definition in one of three different forms:\n // - A string which we will assume is MDSL and we will parse this to JSON before validation.\n // - An array which we will assume is an array of root node definitions with at least one being the primary root node (no 'id' property)\n // - An object which we will assume is the primary root node and should not have an 'id' property.\n if (typeof definition === \"string\") {\n // The definition is a string which we can assume is MDSL, so attempt to validate it.\n return validateMDSLDefinition(definition);\n } else if (typeof definition === \"object\") {\n // The definition will either be an array (of root node definitions) or an object (the single primary root node definition).\n return validateJSONDefinition(definition);\n } else {\n return createValidationFailureResult(`unexpected definition type of '${typeof definition}'`);\n }\n}\n\n/**\n * Validates the specified behaviour tree definition in the form of MDSL.\n * @param definition The behaviour tree definition in the form of MDSL.\n * @returns An object representing the result of validating the given tree definition.\n */\nfunction validateMDSLDefinition(definition: string): DefinitionValidationResult {\n let rootNodeDefinitions;\n\n // The first thing the we need to do is to attempt to convert our MDSL into JSON.\n try {\n // The definition is a string which we can assume is MDSL, so attempt to parse it to a JSON definition in the form of an array of root node definitions.\n rootNodeDefinitions = convertMDSLToJSON(definition);\n } catch (exception) {\n // We failed to parse the JSON from the MDSL, this is likely to be the result of it not being a valid MDSL string.\n return createValidationFailureResult((exception as Error).message);\n }\n\n // Unpack all of the root node definitions into arrays of main ('id' defined) and sub ('id' not defined) root node definitions.\n const mainRootNodeDefinitions = rootNodeDefinitions.filter(({ id }) => typeof id === \"undefined\");\n const subRootNodeDefinitions = rootNodeDefinitions.filter(({ id }) => typeof id === \"string\" && id.length > 0);\n\n // We should ALWAYS have exactly one root node definition without an 'id' property defined, which is out main root node definition.\n if (mainRootNodeDefinitions.length !== 1) {\n return createValidationFailureResult(\n \"expected single unnamed root node at base of definition to act as main root\"\n );\n }\n\n // We should never have duplicate 'id' properties across our sub root node definitions.\n const subRootNodeIdenitifers: string[] = [];\n for (const { id } of subRootNodeDefinitions) {\n // Have we already come across this 'id' property value?\n if (subRootNodeIdenitifers.includes(id!)) {\n return createValidationFailureResult(`multiple root nodes found with duplicate name '${id}'`);\n }\n\n subRootNodeIdenitifers.push(id!);\n }\n\n try {\n // Validate our branch -> subtree links and check for any circular dependencies, we don't care about checking for broken subtree links here.\n validateBranchSubtreeLinks(rootNodeDefinitions, false);\n } catch (exception) {\n return createValidationFailureResult((exception as Error).message);\n }\n\n // Our definition was valid!\n return {\n succeeded: true,\n json: rootNodeDefinitions\n };\n}\n\n/**\n * Validates the specified behaviour tree definition in the form of JSON.\n * @param definition The behaviour tree definition in the form of JSON.\n * @returns An object representing the result of validating the given tree definition.\n */\nexport function validateJSONDefinition(\n definition: RootNodeDefinition | RootNodeDefinition[]\n): DefinitionValidationResult {\n // The definition will either be an array (of root node definitions) or an object (the single primary root node definition).\n const rootNodeDefinitions = Array.isArray(definition) ? definition : [definition];\n\n // Iterate over our array of root nodes and call validateNode for each, passing an initial depth of 0, wrapped in a try catch to handle validation failures.\n try {\n rootNodeDefinitions.forEach((rootNodeDefinition) => validateNode(rootNodeDefinition, 0));\n } catch (error) {\n // Handle cases where we have caught a thrown Error and return a failure result with the error message.\n if (error instanceof Error) {\n return createValidationFailureResult(error.message);\n }\n\n // No idea what happened here!\n return createValidationFailureResult(`unexpected error: ${error}`);\n }\n\n // Unpack all of the root node definitions into arrays of main ('id' defined) and sub ('id' not defined) root node definitions.\n const mainRootNodeDefinitions = rootNodeDefinitions.filter(({ id }) => typeof id === \"undefined\");\n const subRootNodeDefinitions = rootNodeDefinitions.filter(({ id }) => typeof id === \"string\" && id.length > 0);\n\n // We should ALWAYS have exactly one root node definition without an 'id' property defined, which is out main root node definition.\n if (mainRootNodeDefinitions.length !== 1) {\n return createValidationFailureResult(\n \"expected single root node without 'id' property defined to act as main root\"\n );\n }\n\n // We should never have duplicate 'id' properties across our sub root node definitions.\n const subRootNodeIdenitifers: string[] = [];\n for (const { id } of subRootNodeDefinitions) {\n // Have we already come across this 'id' property value?\n if (subRootNodeIdenitifers.includes(id!)) {\n return createValidationFailureResult(\n `multiple root nodes found with duplicate 'id' property value of '${id}'`\n );\n }\n\n subRootNodeIdenitifers.push(id!);\n }\n\n try {\n // Validate our branch -> subtree links and check for any circular dependencies, we don't care about checking for broken subtree links here.\n validateBranchSubtreeLinks(rootNodeDefinitions, false);\n } catch (exception) {\n return createValidationFailureResult((exception as Error).message);\n }\n\n // Our definition was valid!\n return {\n succeeded: true,\n json: rootNodeDefinitions\n };\n}\n\n/**\n * Validates the branch -> subtree links across all provided root node definitions.\n * This will not consider branch nodes that reference any globally registered subtrees unless includesGlobalSubtrees\n * is set to true, in which case we will also verify that there are no broken branch -> subtree links.\n * @param rootNodeDefinitions The array of root node definitions.\n * @param includesGlobalSubtrees A flag defining whether the array includes all global subtree root node definitions.\n */\nexport function validateBranchSubtreeLinks(rootNodeDefinitions: RootNodeDefinition[], includesGlobalSubtrees: boolean) {\n // Create a mapping of root node identifiers to other root nodes that they reference via branch nodes.\n // Below is an example of a mapping that includes a circular dependency (root => a => b => c => a)\n // [{ refs: [\"a\", \"b\"] }, { id: \"a\", refs: [\"b\"] }, { id: \"b\", refs: [\"c\"] }, { id: \"c\", refs: [\"a\"] }]\n const rootNodeMappings: { id: string | undefined; refs: string[] }[] = rootNodeDefinitions.map(\n (rootNodeDefinition) => ({\n id: rootNodeDefinition.id,\n refs: flattenDefinition(rootNodeDefinition)\n .filter(isBranchNode)\n .map(({ ref }) => ref)\n })\n );\n\n // A recursive function to walk through the mappings, keeping track of which root nodes we have visited in the form of a path of root node identifiers.\n const followRefs = (mapping: { id: string | undefined; refs: string[] }, path: (string | undefined)[] = []) => {\n // Have we found a circular dependency?\n if (path.includes(mapping.id)) {\n // We found a circular dependency! Get the bad path of root node identifiers.\n const badPath = [...path, mapping.id];\n\n // Create the formatted path value. [undefined, \"a\", \"b\", \"c\", \"a\"] would be formatted as \"a -> b -> c -> a\".\n const badPathFormatted = badPath.filter((element) => !!element).join(\" => \");\n\n // No need to continue, we found a circular dependency.\n throw new Error(`circular dependency found in branch node references: ${badPathFormatted}`);\n }\n\n for (const ref of mapping.refs) {\n // Find the mapping for the root node with an identifer matching the current ref.\n const subMapping = rootNodeMappings.find(({ id }) => id === ref);\n\n // We may not have a mapping for this ref, which is normal when we aren't considering all globally registered subtrees.\n if (subMapping) {\n followRefs(subMapping, [...path, mapping.id]);\n } else if (includesGlobalSubtrees) {\n // We found a reference to a root node that doesn't exist, which is a problem seeing as the root node definitons includes all globally registered subtrees.\n throw new Error(\n mapping.id\n ? `subtree '${mapping.id}' has branch node that references root node '${ref}' which has not been defined`\n : `primary tree has branch node that references root node '${ref}' which has not been defined`\n );\n }\n }\n };\n\n // Start looking for circular dependencies and broken references from the primary root node definition.\n followRefs(rootNodeMappings.find((mapping) => typeof mapping.id === \"undefined\")!);\n}\n\n/**\n * Validate an object that we expect to be a node definition.\n * @param definition An object that we expect to be a node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateNode(definition: any, depth: number): void {\n // Every node must be valid object and have a non-empty 'type' string property.\n if (typeof definition !== \"object\" || typeof definition.type !== \"string\" || definition.type.length === 0) {\n throw new Error(\n `node definition is not an object or 'type' property is not a non-empty string at depth '${depth}'`\n );\n }\n\n // How we validate this node definition will depend on its type.\n switch (definition.type) {\n case \"action\":\n validateActionNode(definition, depth);\n break;\n\n case \"condition\":\n validateConditionNode(definition, depth);\n break;\n\n case \"wait\":\n validateWaitNode(definition, depth);\n break;\n\n case \"branch\":\n validateBranchNode(definition, depth);\n break;\n\n case \"root\":\n validateRootNode(definition, depth);\n break;\n\n case \"succeed\":\n validateSucceedNode(definition, depth);\n break;\n\n case \"fail\":\n validateFailNode(definition, depth);\n break;\n\n case \"flip\":\n validateFlipNode(definition, depth);\n break;\n\n case \"repeat\":\n validateRepeatNode(definition, depth);\n break;\n\n case \"retry\":\n validateRetryNode(definition, depth);\n break;\n\n case \"sequence\":\n validateSequenceNode(definition, depth);\n break;\n\n case \"selector\":\n validateSelectorNode(definition, depth);\n break;\n\n case \"parallel\":\n validateParallelNode(definition, depth);\n break;\n\n case \"lotto\":\n validateLottoNode(definition, depth);\n break;\n\n default:\n throw new Error(`unexpected node type of '${definition.type}' at depth '${depth}'`);\n }\n}\n\n/**\n * Validate any attributes for a given node definition.\n * @param definition The node definition.\n * @param depth The depth of the node in the behaviour tree definition.\n */\nfunction validateNodeAttributes(definition: any, depth: number): void {\n // Validate each of the attribute types for this node.\n [\"while\", \"until\", \"entry\", \"exit\", \"step\"].forEach((attributeName) => {\n // Attempt to grab the definition for the current attribute from the node definition.\n const attributeDefinition = definition[attributeName];\n\n // All node attributes are optional, so there is nothing to do if the current attribute is not defined.\n if (typeof attributeDefinition === \"undefined\") {\n return;\n }\n\n // The attribute definition must be an object.\n if (typeof attributeDefinition !== \"object\") {\n throw new Error(\n `expected attribute '${attributeName}' to be an object for '${definition.type}' node at depth '${depth}'`\n );\n }\n\n // The 'call' property must be defined for any attribute definition.\n if (typeof attributeDefinition.call !== \"string\" || attributeDefinition.call.length === 0) {\n throw new Error(\n `expected 'call' property for attribute '${attributeName}' to be a non-empty string for '${definition.type}' node at depth '${depth}'`\n );\n }\n\n // If any node attribute arguments have been defined then they must have been defined in an array.\n if (typeof attributeDefinition.args !== \"undefined\" && !Array.isArray(attributeDefinition.args)) {\n throw new Error(\n `expected 'args' property for attribute '${attributeName}' to be an array for '${definition.type}' node at depth '${depth}'`\n );\n }\n });\n}\n\n/**\n * Validate an object that we expect to be a root node definition.\n * @param definition An object that we expect to be a root node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateRootNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"root\") {\n throw new Error(\"expected node type of 'root' for root node\");\n }\n\n // A root node cannot be the child of another node.\n if (depth > 0) {\n throw new Error(\"a root node cannot be the child of another node\");\n }\n\n // Check that, if the root node 'id' property is defined, it is a non-empty string.\n if (typeof definition.id !== \"undefined\" && (typeof definition.id !== \"string\" || definition.id.length === 0)) {\n throw new Error(\"expected non-empty string for 'id' property if defined for root node\");\n }\n\n // A root node is a decorator node, so must have a child node defined.\n if (typeof definition.child === \"undefined\") {\n throw new Error(\"expected property 'child' to be defined for root node\");\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n\n // Validate the child node of this decorator node.\n validateNode(definition.child, depth + 1);\n}\n\n/**\n * Validate an object that we expect to be a succeed node definition.\n * @param definition An object that we expect to be a succeed node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateSucceedNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"succeed\") {\n throw new Error(`expected node type of 'succeed' for succeed node at depth '${depth}'`);\n }\n\n // A succeed node is a decorator node, so must have a child node defined.\n if (typeof definition.child === \"undefined\") {\n throw new Error(`expected property 'child' to be defined for succeed node at depth '${depth}'`);\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n\n // Validate the child node of this decorator node.\n validateNode(definition.child, depth + 1);\n}\n\n/**\n * Validate an object that we expect to be a fail node definition.\n * @param definition An object that we expect to be a fail node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateFailNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"fail\") {\n throw new Error(`expected node type of 'fail' for fail node at depth '${depth}'`);\n }\n\n // A fail node is a decorator node, so must have a child node defined.\n if (typeof definition.child === \"undefined\") {\n throw new Error(`expected property 'child' to be defined for fail node at depth '${depth}'`);\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n\n // Validate the child node of this decorator node.\n validateNode(definition.child, depth + 1);\n}\n\n/**\n * Validate an object that we expect to be a flip node definition.\n * @param definition An object that we expect to be a flip node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateFlipNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"flip\") {\n throw new Error(`expected node type of 'flip' for flip node at depth '${depth}'`);\n }\n\n // A flip node is a decorator node, so must have a child node defined.\n if (typeof definition.child === \"undefined\") {\n throw new Error(`expected property 'child' to be defined for flip node at depth '${depth}'`);\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n\n // Validate the child node of this decorator node.\n validateNode(definition.child, depth + 1);\n}\n\n/**\n * Validate an object that we expect to be a repeat node definition.\n * @param definition An object that we expect to be a repeat node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateRepeatNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"repeat\") {\n throw new Error(`expected node type of 'repeat' for repeat node at depth '${depth}'`);\n }\n\n // A repeat node is a decorator node, so must have a child node defined.\n if (typeof definition.child === \"undefined\") {\n throw new Error(`expected property 'child' to be defined for repeat node at depth '${depth}'`);\n }\n\n // Check whether an 'iterations' property has been defined, it may not have been if this node is to repeat indefinitely.\n if (typeof definition.iterations !== \"undefined\") {\n if (Array.isArray(definition.iterations)) {\n // Check whether any elements of the array are not integer values.\n const containsNonInteger = !!definition.iterations.filter((value: unknown) => !isInteger(value)).length;\n\n // If the 'iterations' property is an array then it MUST contain two integer values.\n if (definition.iterations.length !== 2 || containsNonInteger) {\n throw new Error(\n `expected array containing two integer values for 'iterations' property if defined for repeat node at depth '${depth}'`\n );\n }\n\n // A repeat node must have a positive min and max iterations count if they are defined.\n if (definition.iterations[0] < 0 || definition.iterations[1] < 0) {\n throw new Error(\n `expected positive minimum and maximum iterations count for 'iterations' property if defined for repeat node at depth '${depth}'`\n );\n }\n\n // A repeat node must not have a minimum iterations count that exceeds the maximum iterations count.\n if (definition.iterations[0] > definition.iterations[1]) {\n throw new Error(\n `expected minimum iterations count that does not exceed the maximum iterations count for 'iterations' property if defined for repeat node at depth '${depth}'`\n );\n }\n } else if (isInteger(definition.iterations)) {\n // A repeat node must have a positive number of iterations if defined.\n if (definition.iterations < 0) {\n throw new Error(\n `expected positive iterations count for 'iterations' property if defined for repeat node at depth '${depth}'`\n );\n }\n } else {\n throw new Error(\n `expected integer value or array containing two integer values for 'iterations' property if defined for repeat node at depth '${depth}'`\n );\n }\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n\n // Validate the child node of this decorator node.\n validateNode(definition.child, depth + 1);\n}\n\n/**\n * Validate an object that we expect to be a retry node definition.\n * @param definition An object that we expect to be a retry node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateRetryNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"retry\") {\n throw new Error(`expected node type of 'retry' for retry node at depth '${depth}'`);\n }\n\n // A retry node is a decorator node, so must have a child node defined.\n if (typeof definition.child === \"undefined\") {\n throw new Error(`expected property 'child' to be defined for retry node at depth '${depth}'`);\n }\n\n // Check whether an 'attempts' property has been defined, it may not have been if this node is to retry indefinitely.\n if (typeof definition.attempts !== \"undefined\") {\n if (Array.isArray(definition.attempts)) {\n // Check whether any elements of the array are not integer values.\n const containsNonInteger = !!definition.attempts.filter((value: unknown) => !isInteger(value)).length;\n\n // If the 'attempts' property is an array then it MUST contain two integer values.\n if (definition.attempts.length !== 2 || containsNonInteger) {\n throw new Error(\n `expected array containing two integer values for 'attempts' property if defined for retry node at depth '${depth}'`\n );\n }\n\n // A retry node must have a positive min and max attempts count if they are defined.\n if (definition.attempts[0] < 0 || definition.attempts[1] < 0) {\n throw new Error(\n `expected positive minimum and maximum attempts count for 'attempts' property if defined for retry node at depth '${depth}'`\n );\n }\n\n // A retry node must not have a minimum attempts count that exceeds the maximum attempts count.\n if (definition.attempts[0] > definition.attempts[1]) {\n throw new Error(\n `expected minimum attempts count that does not exceed the maximum attempts count for 'attempts' property if defined for retry node at depth '${depth}'`\n );\n }\n } else if (isInteger(definition.attempts)) {\n // A retry node must have a positive number of attempts if defined.\n if (definition.attempts < 0) {\n throw new Error(\n `expected positive attempts count for 'attempts' property if defined for retry node at depth '${depth}'`\n );\n }\n } else {\n throw new Error(\n `expected integer value or array containing two integer values for 'attempts' property if defined for retry node at depth '${depth}'`\n );\n }\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n\n // Validate the child node of this decorator node.\n validateNode(definition.child, depth + 1);\n}\n\n/**\n * Validate an object that we expect to be a branch node definition.\n * @param definition An object that we expect to be a branch node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateBranchNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"branch\") {\n throw new Error(`expected node type of 'branch' for branch node at depth '${depth}'`);\n }\n\n // Check that the branch node 'ref' property is defined and is a non-empty string.\n if (typeof definition.ref !== \"string\" || definition.ref.length === 0) {\n throw new Error(`expected non-empty string for 'ref' property for branch node at depth '${depth}'`);\n }\n\n // It is invalid to define guard attributes for a branch node as they should be defined on the referenced root node.\n [\"while\", \"until\"].forEach((attributeName) => {\n if (typeof definition[attributeName] !== \"undefined\") {\n throw new Error(\n `guards should not be defined for branch nodes but guard '${attributeName}' was defined for branch node at depth '${depth}'`\n );\n }\n });\n\n // It is invalid to define callback attributes for a branch node as they should be defined on the referenced root node.\n [\"entry\", \"exit\", \"step\"].forEach((attributeName) => {\n if (typeof definition[attributeName] !== \"undefined\") {\n throw new Error(\n `callbacks should not be defined for branch nodes but callback '${attributeName}' was defined for branch node at depth '${depth}'`\n );\n }\n });\n}\n\n/**\n * Validate an object that we expect to be a action node definition.\n * @param definition An object that we expect to be a action node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateActionNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"action\") {\n throw new Error(`expected node type of 'action' for action node at depth '${depth}'`);\n }\n\n // The 'call' property must be defined for a action node definition.\n if (typeof definition.call !== \"string\" || definition.call.length === 0) {\n throw new Error(`expected non-empty string for 'call' property of action node at depth '${depth}'`);\n }\n\n // If any action function arguments have been defined then they must have been defined in an array.\n if (typeof definition.args !== \"undefined\" && !Array.isArray(definition.args)) {\n throw new Error(`expected array for 'args' property if defined for action node at depth '${depth}'`);\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n}\n\n/**\n * Validate an object that we expect to be a condition node definition.\n * @param definition An object that we expect to be a condition node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateConditionNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"condition\") {\n throw new Error(`expected node type of 'condition' for condition node at depth '${depth}'`);\n }\n\n // The 'call' property must be defined for a condition node definition.\n if (typeof definition.call !== \"string\" || definition.call.length === 0) {\n throw new Error(`expected non-empty string for 'call' property of condition node at depth '${depth}'`);\n }\n\n // If any condition function arguments have been defined then they must have been defined in an array.\n if (typeof definition.args !== \"undefined\" && !Array.isArray(definition.args)) {\n throw new Error(`expected array for 'args' property if defined for condition node at depth '${depth}'`);\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n}\n\n/**\n * Validate an object that we expect to be a wait node definition.\n * @param definition An object that we expect to be a wait node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateWaitNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"wait\") {\n throw new Error(`expected node type of 'wait' for wait node at depth '${depth}'`);\n }\n\n // Check whether a 'duration' property has been defined, it may not have been if this node is to wait indefinitely.\n if (typeof definition.duration !== \"undefined\") {\n if (Array.isArray(definition.duration)) {\n // Check whether any elements of the array are not integer values.\n const containsNonInteger = !!definition.duration.filter((value: unknown) => !isInteger(value)).length;\n\n // If the 'duration' property is an array then it MUST contain two integer values.\n if (definition.duration.length !== 2 || containsNonInteger) {\n throw new Error(\n `expected array containing two integer values for 'duration' property if defined for wait node at depth '${depth}'`\n );\n }\n\n // A wait node must have a positive min and max duration value if they are defined.\n if (definition.duration[0] < 0 || definition.duration[1] < 0) {\n throw new Error(\n `expected positive minimum and maximum duration for 'duration' property if defined for wait node at depth '${depth}'`\n );\n }\n\n // A wait node must not have a minimum duration value that exceeds the maximum duration value.\n if (definition.duration[0] > definition.duration[1]) {\n throw new Error(\n `expected minimum duration value that does not exceed the maximum duration value for 'duration' property if defined for wait node at depth '${depth}'`\n );\n }\n } else if (isInteger(definition.duration)) {\n // A wait node must have a positive duration value if defined.\n if (definition.duration < 0) {\n throw new Error(\n `expected positive duration value for 'duration' property if defined for wait node at depth '${depth}'`\n );\n }\n } else {\n throw new Error(\n `expected integer value or array containing two integer values for 'duration' property if defined for wait node at depth '${depth}'`\n );\n }\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n}\n\n/**\n * Validate an object that we expect to be a sequence node definition.\n * @param definition An object that we expect to be a sequence node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateSequenceNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"sequence\") {\n throw new Error(`expected node type of 'sequence' for sequence node at depth '${depth}'`);\n }\n\n // A sequence node is a composite node, so must have a children nodes array defined.\n if (!Array.isArray(definition.children) || definition.children.length === 0) {\n throw new Error(`expected non-empty 'children' array to be defined for sequence node at depth '${depth}'`);\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n\n // Validate the child nodes of this composite node.\n definition.children.forEach((child: any) => validateNode(child, depth + 1));\n}\n\n/**\n * Validate an object that we expect to be a selector node definition.\n * @param definition An object that we expect to be a selector node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateSelectorNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"selector\") {\n throw new Error(`expected node type of 'selector' for selector node at depth '${depth}'`);\n }\n\n // A selector node is a composite node, so must have a children nodes array defined.\n if (!Array.isArray(definition.children) || definition.children.length === 0) {\n throw new Error(`expected non-empty 'children' array to be defined for selector node at depth '${depth}'`);\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n\n // Validate the child nodes of this composite node.\n definition.children.forEach((child: any) => validateNode(child, depth + 1));\n}\n\n/**\n * Validate an object that we expect to be a parallel node definition.\n * @param definition An object that we expect to be a parallel node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateParallelNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"parallel\") {\n throw new Error(`expected node type of 'parallel' for parallel node at depth '${depth}'`);\n }\n\n // A parallel node is a composite node, so must have a children nodes array defined.\n if (!Array.isArray(definition.children) || definition.children.length === 0) {\n throw new Error(`expected non-empty 'children' array to be defined for parallel node at depth '${depth}'`);\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n\n // Validate the child nodes of this composite node.\n definition.children.forEach((child: any) => validateNode(child, depth + 1));\n}\n\n/**\n * Validate an object that we expect to be a lotto node definition.\n * @param definition An object that we expect to be a lotto node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateLottoNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"lotto\") {\n throw new Error(`expected node type of 'lotto' for lotto node at depth '${depth}'`);\n }\n\n // A lotto node is a composite node, so must have a children nodes array defined.\n if (!Array.isArray(definition.children) || definition.children.length === 0) {\n throw new Error(`expected non-empty 'children' array to be defined for lotto node at depth '${depth}'`);\n }\n\n // Check whether a 'weights' property has been defined, if it has we expect it to be an array of weights.\n if (typeof definition.weights !== \"undefined\") {\n // Check that the weights property is an array of positive integers with an element for each child node element.\n if (\n !Array.isArray(definition.weights) ||\n definition.weights.length !== definition.children.length ||\n definition.weights.filter((value: unknown) => !isInteger(value)).length ||\n definition.weights.filter((value: number) => value < 0).length\n ) {\n throw new Error(\n `expected an array of positive integer weight values with a length matching the number of child nodes for 'weights' property if defined for lotto node at depth '${depth}'`\n );\n }\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n\n // Validate the child nodes of this composite node.\n definition.children.forEach((child: any) => validateNode(child, depth + 1));\n}\n\n/**\n * A helper function to create a failure validation result with the given error message.\n * @param errorMessage The validation failure error message.\n * @returns A failure validation result with the given error message.\n */\nfunction createValidationFailureResult(errorMessage: string): DefinitionValidationResult {\n return { succeeded: false, errorMessage };\n}\n", "import { ActionResult, Agent, GlobalFunction } from \"./Agent\";\nimport { RootNodeDefinition } from \"./BehaviourTreeDefinition\";\n\nexport type InvokerFunction = (args: any[]) => ActionResult;\n\n/**\n * A singleton used to store and lookup registered functions and subtrees.\n */\nexport default class Lookup {\n /**\n * The object holding any registered functions keyed on function name.\n */\n private static functionTable: { [key: string]: GlobalFunction } = {};\n /**\n * The object holding any registered subtree root node definitions keyed on tree name.\n */\n private static subtreeTable: { [key: string]: RootNodeDefinition } = {};\n\n /**\n * Gets the function with the specified name.\n * @param name The name of the function.\n * @returns The function with the specified name.\n */\n public static getFunc(name: string): GlobalFunction {\n return this.functionTable[name];\n }\n\n /**\n * Sets the function with the specified name for later lookup.\n * @param name The name of the function.\n * @param func The function.\n */\n public static setFunc(name: string, func: GlobalFunction): void {\n this.functionTable[name] = func;\n }\n\n /**\n * Gets the function invoker for the specified agent and function name.\n * If a function with the specified name exists on the agent object then it will\n * be returned, otherwise we will then check the registered functions for a match.\n * @param agent The agent instance that this behaviour tree is modelling behaviour for.\n * @param name The function name.\n * @returns The function invoker for the specified agent and function name.\n */\n static getFuncInvoker(agent: Agent, name: string): InvokerFunction | null {\n // Check whether the agent contains the specified function.\n const foundOnAgent = agent[name];\n if (foundOnAgent && typeof foundOnAgent === \"function\") {\n return (args: any[]): boolean | ActionResult => foundOnAgent.apply(agent, args);\n }\n\n // The agent does not contain the specified function but it may have been registered at some point.\n if (this.functionTable[name] && typeof this.functionTable[name] === \"function\") {\n return (args: any[]) => this.functionTable[name](agent, ...args.map((arg) => arg.value));\n }\n\n // We have no function to invoke.\n return null;\n }\n\n /**\n * Gets all registered subtree root node definitions.\n */\n static getSubtrees(): { [key: string]: RootNodeDefinition } {\n return this.subtreeTable;\n }\n\n /**\n * Sets the subtree with the specified name for later lookup.\n * @param name The name of the subtree.\n * @param subtree The subtree.\n */\n static setSubtree(name: string, subtree: RootNodeDefinition) {\n this.subtreeTable[name] = subtree;\n }\n\n /**\n * Removes the registered function or subtree with the specified name.\n * @param name The name of the registered function or subtree.\n */\n static remove(name: string) {\n delete this.functionTable[name];\n delete this.subtreeTable[name];\n }\n\n /**\n * Remove all registered functions and subtrees.\n */\n static empty() {\n this.functionTable = {};\n this.subtreeTable = {};\n }\n}\n", "import Node from \"../../nodes/Node\";\n\n/**\n * An exception thrown when evaluating node guard path conditions and a conditions fails.\n */\nexport default class GuardUnsatisifedException extends Error {\n /**\n * @param source The node at which a guard condition failed.\n */\n constructor(private source: Node) {\n super(\"A guard path condition has failed\");\n }\n\n /**\n * Gets whether the specified node is the node at which a guard condition failed.\n * @param node The node to check against the source node.\n * @returns Whether the specified node is the node at which a guard condition failed.\n */\n isSourceNode = (node: Node) => node === this.source;\n}\n", "import { Agent } from \"../../Agent\";\nimport Guard from \"./Guard\";\nimport Node from \"../../nodes/Node\";\nimport GuardUnsatisifedException from \"./GuardUnsatisifedException\";\n\nexport type GuardPathPart = {\n node: Node;\n guards: Guard[];\n};\n\n/**\n * Represents a path of node guards along a root-to-leaf tree path.\n */\nexport default class GuardPath {\n /**\n * @param nodes An array of objects defining a node instance -> guard link, ordered by node depth.\n */\n constructor(private nodes: GuardPathPart[]) {}\n\n /**\n * Evaluate guard conditions for all guards in the tree path, moving outwards from the root.\n * @param agent The agent, required for guard evaluation.\n * @returns An evaluation results object.\n */\n evaluate = (agent: Agent) => {\n // We need to evaluate guard conditions for nodes up the tree, moving outwards from the root.\n for (const details of this.nodes) {\n // There can be multiple guards per node.\n for (const guard of details.guards) {\n // Check whether the guard condition passes, and throw an exception if not.\n if (!guard.isSatisfied(agent)) {\n throw new GuardUnsatisifedException(details.node);\n }\n }\n }\n };\n}\n", "import { BehaviourTreeOptions } from \"../BehaviourTreeOptions\";\nimport State, { AnyState } from \"../State\";\nimport { Agent } from \"../Agent\";\nimport Leaf from \"./leaf/Leaf\";\nimport Attribute from \"../attributes/Attribute\";\nimport Entry from \"../attributes/callbacks/Entry\";\nimport Exit from \"../attributes/callbacks/Exit\";\nimport Step from \"../attributes/callbacks/Step\";\nimport Guard from \"../attributes/guards/Guard\";\nimport GuardPath from \"../attributes/guards/GuardPath\";\nimport GuardUnsatisifedException from \"../attributes/guards/GuardUnsatisifedException\";\n\n/**\n * A base node.\n */\nexport default abstract class Node {\n /**\n * The node uid.\n */\n private readonly uid: string = createNodeUid();\n /**\n * The node state.\n */\n private state: AnyState = State.READY;\n /**\n * The guard path to evaluate as part of a node update.\n */\n private guardPath: GuardPath | undefined;\n\n /**\n * @param type The node type.\n * @param attributes The node attributes.\n * @param args The node argument definitions.\n */\n constructor(private type: string, private attributes: Attribute[], private args: any[]) {}\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected abstract onUpdate(agent: Agent, options: BehaviourTreeOptions): void;\n\n /**\n * Gets the name of the node.\n */\n public abstract getName(): string;\n\n /**\n * Gets whether this node is a leaf node.\n */\n public abstract isLeafNode: () => this is Leaf;\n\n /**\n * Gets/Sets the state of the node.\n */\n getState = (): AnyState => this.state;\n setState = (value: AnyState): void => {\n this.state = value;\n };\n\n /**\n * Gets the unique id of the node.\n */\n getUid = () => this.uid;\n\n /**\n * Gets the type of the node.\n */\n getType = () => this.type;\n\n /**\n * Gets the node attributes.\n */\n getAttributes = () => this.attributes;\n\n /**\n * Gets the node arguments.\n */\n getArguments = () => this.args;\n\n /**\n * Gets the node attribute with the specified type, or null if it does not exist.\n */\n getAttribute(type: \"entry\" | \"ENTRY\"): Entry;\n getAttribute(type: \"exit\" | \"EXIT\"): Exit;\n getAttribute(type: \"step\" | \"STEP\"): Step;\n getAttribute(type: string): Attribute {\n return (\n this.getAttributes().filter((decorator) => decorator.type.toUpperCase() === type.toUpperCase())[0] || null\n );\n }\n\n /**\n * Gets the node attributes.\n */\n getGuardAttributes = (): Guard[] => this.getAttributes().filter((decorator) => decorator.isGuard()) as Guard[];\n\n /**\n * Sets the guard path to evaluate as part of a node update.\n */\n setGuardPath = (value: GuardPath) => (this.guardPath = value);\n\n /**\n * Gets whether a guard path is assigned to this node.\n */\n hasGuardPath = () => !!this.guardPath;\n\n /**\n * Gets whether this node is in the specified state.\n * @param value The value to compare to the node state.\n */\n public is(value: AnyState): boolean {\n return this.state === value;\n }\n\n /**\n * Reset the state of the node.\n */\n public reset(): void {\n this.setState(State.READY);\n }\n\n /**\n * Abort the running of this node.\n * @param agent The agent.\n */\n public abort(agent: Agent): void {\n // There is nothing to do if this node is not in the running state.\n if (!this.is(State.RUNNING)) {\n return;\n }\n\n // Reset the state of this node.\n this.reset();\n\n this.getAttribute(\"exit\")?.callAgentFunction(agent, false, true);\n }\n\n /**\n * Update the node.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n * @returns The result of the update.\n */\n public update(agent: Agent, options: BehaviourTreeOptions): void {\n // If this node is already in a 'SUCCEEDED' or 'FAILED' state then there is nothing to do.\n if (this.is(State.SUCCEEDED) || this.is(State.FAILED)) {\n return;\n }\n\n try {\n // Evaluate all of the guard path conditions for the current tree path.\n this.guardPath!.evaluate(agent);\n\n // If this node is in the READY state then call the ENTRY for this node if it exists.\n if (this.is(State.READY)) {\n this.getAttribute(\"entry\")?.callAgentFunction(agent);\n }\n\n this.getAttribute(\"step\")?.callAgentFunction(agent);\n\n // Do the actual update.\n this.onUpdate(agent, options);\n\n // If this node is now in a 'SUCCEEDED' or 'FAILED' state then call the EXIT for this node if it exists.\n if (this.is(State.SUCCEEDED) || this.is(State.FAILED)) {\n this.getAttribute(\"exit\")?.callAgentFunction(agent, this.is(State.SUCCEEDED), false);\n }\n } catch (error) {\n // If the error is a GuardUnsatisfiedException then we need to determine if this node is the source.\n if (error instanceof GuardUnsatisifedException && error.isSourceNode(this)) {\n // Abort the current node.\n this.abort(agent);\n\n // Any node that is the source of an abort will be a failed node.\n this.setState(State.FAILED);\n } else {\n throw error;\n }\n }\n }\n}\n\n/**\n * Create a randomly generated node uid.\n * @returns A randomly generated node uid.\n */\nfunction createNodeUid(): string {\n var S4 = function () {\n return (((1 + Math.random()) * 0x10000) | 0).toString(16).substring(1);\n };\n return S4() + S4() + \"-\" + S4() + \"-\" + S4() + \"-\" + S4() + \"-\" + S4() + S4() + S4();\n}\n", "import Node from \"../Node\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\n\n/**\n * A composite node that wraps child nodes.\n */\nexport default abstract class Composite extends Node {\n /**\n * @param type The node type.\n * @param attributes The node attributes.\n * @param children The child nodes.\n */\n constructor(type: string, attributes: Attribute[], protected children: Node[]) {\n super(type, attributes, []);\n }\n\n /**\n * Gets whether this node is a leaf node.\n */\n isLeafNode = () => false;\n\n /**\n * Gets the children of this node.\n */\n getChildren = () => this.children;\n\n /**\n * Reset the state of the node.\n */\n reset = () => {\n // Reset the state of this node.\n this.setState(State.READY);\n\n // Reset the state of any child nodes.\n this.getChildren().forEach((child) => child.reset());\n };\n\n /**\n * Abort the running of this node.\n * @param agent The agent.\n */\n abort = (agent: Agent) => {\n // There is nothing to do if this node is not in the running state.\n if (!this.is(State.RUNNING)) {\n return;\n }\n\n // Abort any child nodes.\n this.getChildren().forEach((child) => child.abort(agent));\n\n // Reset the state of this node.\n this.reset();\n\n this.getAttribute(\"exit\")?.callAgentFunction(agent, false, true);\n };\n}\n", "import Composite from \"./Composite\";\nimport State from \"../../State\";\nimport Node from \"../Node\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A PARALLEL node.\n * The child nodes are executed concurrently until one fails or all succeed.\n */\nexport default class Parallel extends Composite {\n /**\n * @param attributes The node attributes.\n * @param children The child nodes.\n */\n constructor(attributes: Attribute[], children: Node[]) {\n super(\"parallel\", attributes, children);\n }\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // Keep a count of the number of succeeded child nodes.\n let succeededCount = 0;\n\n let hasChildFailed = false;\n\n // Iterate over all of the children of this node.\n for (const child of this.children) {\n // If the child has never been updated or is running then we will need to update it now.\n if (child.getState() === State.READY || child.getState() === State.RUNNING) {\n // Update the child of this node.\n child.update(agent, options);\n }\n\n // If the current child has a state of 'SUCCEEDED' then we should move on to the next child.\n if (child.getState() === State.SUCCEEDED) {\n // The child node has succeeded, keep track of this to determine if all children have.\n succeededCount++;\n\n // The child node succeeded, but we have not finished checking every child node yet.\n continue;\n }\n\n // If the current child has a state of 'FAILED' then this node is also a 'FAILED' node.\n if (child.getState() === State.FAILED) {\n hasChildFailed = true;\n\n // There is no need to check the rest of the children.\n break;\n }\n\n // The node should be in the 'RUNNING' state.\n if (child.getState() !== State.RUNNING) {\n // The child node was not in an expected state.\n throw new Error(\"child node was not in an expected state.\");\n }\n }\n\n if (hasChildFailed) {\n // This node is a 'FAILED' node.\n this.setState(State.FAILED);\n\n // Abort every running child.\n for (const child of this.children) {\n if (child.getState() === State.RUNNING) {\n child.abort(agent);\n }\n }\n } else {\n // If all children have succeeded then this node has also succeeded, otherwise it is still running.\n this.setState(succeededCount === this.children.length ? State.SUCCEEDED : State.RUNNING);\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => \"PARALLEL\";\n}\n", "import Composite from \"./Composite\";\nimport Node from \"../Node\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A SELECTOR node.\n * The child nodes are executed in sequence until one succeeds or all fail.\n */\nexport default class Selector extends Composite {\n /**\n * @param attributes The node attributes.\n * @param children The child nodes.\n */\n constructor(attributes: Attribute[], protected children: Node[]) {\n super(\"selector\", attributes, children);\n }\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // Iterate over all of the children of this node.\n for (const child of this.children) {\n // If the child has never been updated or is running then we will need to update it now.\n if (child.getState() === State.READY || child.getState() === State.RUNNING) {\n // Update the child of this node.\n child.update(agent, options);\n }\n\n // If the current child has a state of 'SUCCEEDED' then this node is also a 'SUCCEEDED' node.\n if (child.getState() === State.SUCCEEDED) {\n // This node is a 'SUCCEEDED' node.\n this.setState(State.SUCCEEDED);\n\n // There is no need to check the rest of the selector nodes.\n return;\n }\n\n // If the current child has a state of 'FAILED' then we should move on to the next child.\n if (child.getState() === State.FAILED) {\n // Find out if the current child is the last one in the selector.\n // If it is then this sequence node has also failed.\n if (this.children.indexOf(child) === this.children.length - 1) {\n // This node is a 'FAILED' node.\n this.setState(State.FAILED);\n\n // There is no need to check the rest of the selector as we have completed it.\n return;\n } else {\n // The child node failed, try the next one.\n continue;\n }\n }\n\n // The node should be in the 'RUNNING' state.\n if (child.getState() === State.RUNNING) {\n // This node is a 'RUNNING' node.\n this.setState(State.RUNNING);\n\n // There is no need to check the rest of the selector as the current child is still running.\n return;\n }\n\n // The child node was not in an expected state.\n throw new Error(\"child node was not in an expected state.\");\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => \"SELECTOR\";\n}\n", "import Composite from \"./Composite\";\nimport Node from \"../Node\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A SEQUENCE node.\n * The child nodes are executed in sequence until one fails or all succeed.\n */\nexport default class Sequence extends Composite {\n /**\n * @param attributes The node attributes.\n * @param children The child nodes.\n */\n constructor(attributes: Attribute[], protected children: Node[]) {\n super(\"sequence\", attributes, children);\n }\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // Iterate over all of the children of this node.\n for (const child of this.children) {\n // If the child has never been updated or is running then we will need to update it now.\n if (child.getState() === State.READY || child.getState() === State.RUNNING) {\n // Update the child of this node.\n child.update(agent, options);\n }\n\n // If the current child has a state of 'SUCCEEDED' then we should move on to the next child.\n if (child.getState() === State.SUCCEEDED) {\n // Find out if the current child is the last one in the sequence.\n // If it is then this sequence node has also succeeded.\n if (this.children.indexOf(child) === this.children.length - 1) {\n // This node is a 'SUCCEEDED' node.\n this.setState(State.SUCCEEDED);\n\n // There is no need to check the rest of the sequence as we have completed it.\n return;\n } else {\n // The child node succeeded, but we have not finished the sequence yet.\n continue;\n }\n }\n\n // If the current child has a state of 'FAILED' then this node is also a 'FAILED' node.\n if (child.getState() === State.FAILED) {\n // This node is a 'FAILED' node.\n this.setState(State.FAILED);\n\n // There is no need to check the rest of the sequence.\n return;\n }\n\n // The node should be in the 'RUNNING' state.\n if (child.getState() === State.RUNNING) {\n // This node is a 'RUNNING' node.\n this.setState(State.RUNNING);\n\n // There is no need to check the rest of the sequence as the current child is still running.\n return;\n }\n\n // The child node was not in an expected state.\n throw new Error(\"child node was not in an expected state.\");\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => \"SEQUENCE\";\n}\n", "import createLotto from \"lotto-draw\";\n\nimport Node from \"../Node\";\nimport Composite from \"./Composite\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A LOTTO node.\n * A winning child is picked on the initial update of this node, based on ticket weighting.\n * The state of this node will match the state of the winning child.\n */\nexport default class Lotto extends Composite {\n /**\n * @param attributes The node attributes.\n * @param weights The child node weights.\n * @param children The child nodes.\n */\n constructor(attributes: Attribute[], private weights: number[] | undefined, children: Node[]) {\n super(\"lotto\", attributes, children);\n }\n\n /**\n * The child node selected to be the active one.\n */\n private selectedChild: Node | undefined;\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // If this node is in the READY state then we need to pick a winning child node.\n if (this.is(State.READY)) {\n // Create a lotto draw with which to randomly pick a child node to become the active one.\n const lottoDraw = createLotto({\n // Hook up the optional 'random' behaviour tree function option to the one used by 'lotto-draw'.\n random: options.random,\n // Pass in each child node as a participant in the lotto draw with their respective ticket count.\n participants: this.children.map((child, index) => [child, this.weights?.[index] || 1])\n });\n\n // Randomly pick a child based on ticket weighting, this will become the active child for this composite node.\n this.selectedChild = lottoDraw.draw() || undefined;\n }\n\n // If something went wrong and we don't have an active child then we should throw an error.\n if (!this.selectedChild) {\n throw new Error(\"failed to update lotto node as it has no active child\");\n }\n\n // If the selected child has never been updated or is running then we will need to update it now.\n if (this.selectedChild.getState() === State.READY || this.selectedChild.getState() === State.RUNNING) {\n this.selectedChild.update(agent, options);\n }\n\n // The state of the lotto node is the state of its selected child.\n this.setState(this.selectedChild.getState());\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => (this.weights ? `LOTTO [${this.weights.join(\",\")}]` : \"LOTTO\");\n}\n", "import Node from \"../Node\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\n\n/**\n * A decorator node that wraps a single child node.\n */\nexport default abstract class Decorator extends Node {\n /**\n * @param type The node type.\n * @param attributes The node attributes.\n * @param child The child node.\n */\n constructor(type: string, attributes: Attribute[], protected child: Node) {\n super(type, attributes, []);\n }\n\n /**\n * Gets whether this node is a leaf node.\n */\n isLeafNode = () => false;\n\n /**\n * Gets the children of this node.\n */\n getChildren = () => [this.child];\n\n /**\n * Reset the state of the node.\n */\n reset = () => {\n // Reset the state of this node.\n this.setState(State.READY);\n\n // Reset the state of the child node.\n this.child.reset();\n };\n\n /**\n * Abort the running of this node.\n * @param agent The agent.\n */\n abort = (agent: Agent) => {\n // There is nothing to do if this node is not in the running state.\n if (!this.is(State.RUNNING)) {\n return;\n }\n\n // Abort the child node.\n this.child.abort(agent);\n\n // Reset the state of this node.\n this.reset();\n\n this.getAttribute(\"exit\")?.callAgentFunction(agent, false, true);\n };\n}\n", "import Node from \"../Node\";\nimport Decorator from \"./Decorator\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A Fail node.\n * This node wraps a single child and will always move to the 'FAILED' state when the child moves to a 'SUCCEEDED' or 'FAILED' state.\n */\nexport default class Fail extends Decorator {\n /**\n * @param attributes The node attributes.\n * @param child The child node.\n */\n constructor(attributes: Attribute[], child: Node) {\n super(\"fail\", attributes, child);\n }\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // If the child has never been updated or is running then we will need to update it now.\n if (this.child.getState() === State.READY || this.child.getState() === State.RUNNING) {\n this.child.update(agent, options);\n }\n\n // The state of this node will depend in the state of its child.\n switch (this.child.getState()) {\n case State.RUNNING:\n this.setState(State.RUNNING);\n break;\n\n case State.SUCCEEDED:\n case State.FAILED:\n this.setState(State.FAILED);\n break;\n\n default:\n this.setState(State.READY);\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => \"FAIL\";\n}\n", "import Decorator from \"./Decorator\";\nimport State from \"../../State\";\nimport Node from \"../Node\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A Flip node.\n * This node wraps a single child and will flip the state of the child state.\n */\nexport default class Flip extends Decorator {\n /**\n * @param attributes The node attributes.\n * @param child The child node.\n */\n constructor(attributes: Attribute[], child: Node) {\n super(\"flip\", attributes, child);\n }\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // If the child has never been updated or is running then we will need to update it now.\n if (this.child.getState() === State.READY || this.child.getState() === State.RUNNING) {\n this.child.update(agent, options);\n }\n\n // The state of this node will depend in the state of its child.\n switch (this.child.getState()) {\n case State.RUNNING:\n this.setState(State.RUNNING);\n break;\n\n case State.SUCCEEDED:\n this.setState(State.FAILED);\n break;\n\n case State.FAILED:\n this.setState(State.SUCCEEDED);\n break;\n\n default:\n this.setState(State.READY);\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => \"FLIP\";\n}\n", "import Node from \"../Node\";\nimport Decorator from \"./Decorator\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A REPEAT node.\n * The node has a single child which can have:\n * -- A number of iterations for which to repeat the child node.\n * -- An infinite repeat loop if neither an iteration count or a condition function is defined.\n * The REPEAT node will stop and have a 'FAILED' state if its child is ever in a 'FAILED' state after an update.\n * The REPEAT node will attempt to move on to the next iteration if its child is ever in a 'SUCCEEDED' state.\n */\nexport default class Repeat extends Decorator {\n /**\n * @param attributes The node attributes.\n * @param iterations The number of iterations to repeat the child node.\n * @param iterationsMin The minimum possible number of iterations to repeat the child node.\n * @param iterationsMax The maximum possible number of iterations to repeat the child node.\n * @param child The child node.\n */\n constructor(\n attributes: Attribute[],\n private iterations: number | null,\n private iterationsMin: number | null,\n private iterationsMax: number | null,\n child: Node\n ) {\n super(\"repeat\", attributes, child);\n }\n\n /**\n * The number of target iterations to make.\n */\n private targetIterationCount: number | null = null;\n\n /**\n * The current iteration count.\n */\n private currentIterationCount: number = 0;\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // If this node is in the READY state then we need to reset the child and the target iteration count.\n if (this.is(State.READY)) {\n // Reset the child node.\n this.child.reset();\n\n // Reset the current iteration count.\n this.currentIterationCount = 0;\n\n // Set the target iteration count.\n this.setTargetIterationCount(options);\n }\n\n // Do a check to see if we can iterate. If we can then this node will move into the 'RUNNING' state.\n // If we cannot iterate then we have hit our target iteration count, which means that the node has succeeded.\n if (this.canIterate()) {\n // This node is in the running state and can do its initial iteration.\n this.setState(State.RUNNING);\n\n // We may have already completed an iteration, meaning that the child node will be in the SUCCEEDED state.\n // If this is the case then we will have to reset the child node now.\n if (this.child.getState() === State.SUCCEEDED) {\n this.child.reset();\n }\n\n // Update the child of this node.\n this.child.update(agent, options);\n\n // If the child moved into the FAILED state when we updated it then there is nothing left to do and this node has also failed.\n // If it has moved into the SUCCEEDED state then we have completed the current iteration.\n if (this.child.getState() === State.FAILED) {\n // The child has failed, meaning that this node has failed.\n this.setState(State.FAILED);\n\n return;\n } else if (this.child.getState() === State.SUCCEEDED) {\n // We have completed an iteration.\n this.currentIterationCount += 1;\n }\n } else {\n // This node is in the 'SUCCEEDED' state as we cannot iterate any more.\n this.setState(State.SUCCEEDED);\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => {\n if (this.iterations !== null) {\n return `REPEAT ${this.iterations}x`;\n } else if (this.iterationsMin !== null && this.iterationsMax !== null) {\n return `REPEAT ${this.iterationsMin}x-${this.iterationsMax}x`;\n } else {\n return \"REPEAT\";\n }\n };\n\n /**\n * Reset the state of the node.\n */\n reset = () => {\n // Reset the state of this node.\n this.setState(State.READY);\n\n // Reset the current iteration count.\n this.currentIterationCount = 0;\n\n // Reset the child node.\n this.child.reset();\n };\n\n /**\n * Gets whether an iteration can be made.\n * @returns Whether an iteration can be made.\n */\n private canIterate = () => {\n if (this.targetIterationCount !== null) {\n // We can iterate as long as we have not reached our target iteration count.\n return this.currentIterationCount < this.targetIterationCount;\n }\n\n // If neither an iteration count or a condition function were defined then we can iterate indefinitely.\n return true;\n };\n\n /**\n * Sets the target iteration count.\n * @param options The behaviour tree options object.\n */\n private setTargetIterationCount = (options: BehaviourTreeOptions) => {\n // Are we dealing with an explicit iteration count or will we be randomly picking a iteration count between the min and max iteration count.\n if (this.iterations !== null) {\n this.targetIterationCount = this.iterations;\n } else if (this.iterationsMin !== null && this.iterationsMax !== null) {\n // We will be picking a random iteration count between a min and max iteration count, if the optional 'random'\n // behaviour tree function option is defined then we will be using that, otherwise we will fall back to using Math.random.\n const random = typeof options.random === \"function\" ? options.random : Math.random;\n\n // Pick a random iteration count between a min and max iteration count.\n this.targetIterationCount = Math.floor(\n random() * (this.iterationsMax - this.iterationsMin + 1) + this.iterationsMin\n );\n } else {\n this.targetIterationCount = null;\n }\n };\n}\n", "import Node from \"../Node\";\nimport Decorator from \"./Decorator\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A RETRY node.\n * The node has a single child which can have:\n * -- A number of iterations for which to repeat the child node.\n * -- An infinite repeat loop if neither an iteration count or a condition function is defined.\n * The RETRY node will stop and have a 'SUCCEEDED' state if its child is ever in a 'SUCCEEDED' state after an update.\n * The RETRY node will attempt to move on to the next iteration if its child is ever in a 'FAILED' state.\n */\nexport default class Retry extends Decorator {\n /**\n * @param attributes The node attributes.\n * @param attempts The number of attempts to retry the child node.\n * @param attemptsMin The minimum possible number of attempts to retry the child node.\n * @param attemptsMax The maximum possible number of attempts to retry the child node.\n * @param child The child node.\n */\n constructor(\n attributes: Attribute[],\n private attempts: number | null,\n private attemptsMin: number | null,\n private attemptsMax: number | null,\n child: Node\n ) {\n super(\"retry\", attributes, child);\n }\n\n /**\n * The number of target attempts to make.\n */\n private targetAttemptCount: number | null = null;\n\n /**\n * The current attempt count.\n */\n private currentAttemptCount: number = 0;\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // If this node is in the READY state then we need to reset the child and the target attempt count.\n if (this.is(State.READY)) {\n // Reset the child node.\n this.child.reset();\n\n // Reset the current attempt count.\n this.currentAttemptCount = 0;\n\n // Set the target attempt count.\n this.setTargetAttemptCount(options);\n }\n\n // Do a check to see if we can attempt. If we can then this node will move into the 'RUNNING' state.\n // If we cannot attempt then we have hit our target attempt count, which means that the node has succeeded.\n if (this.canAttempt()) {\n // This node is in the running state and can do its initial attempt.\n this.setState(State.RUNNING);\n\n // We may have already completed an attempt, meaning that the child node will be in the FAILED state.\n // If this is the case then we will have to reset the child node now.\n if (this.child.getState() === State.FAILED) {\n this.child.reset();\n }\n\n // Update the child of this node.\n this.child.update(agent, options);\n\n // If the child moved into the SUCCEEDED state when we updated it then there is nothing left to do and this node has also succeeded.\n // If it has moved into the FAILED state then we have completed the current attempt.\n if (this.child.getState() === State.SUCCEEDED) {\n // The child has succeeded, meaning that this node has succeeded.\n this.setState(State.SUCCEEDED);\n\n return;\n } else if (this.child.getState() === State.FAILED) {\n // We have completed an attempt.\n this.currentAttemptCount += 1;\n }\n } else {\n // This node is in the 'FAILED' state as we cannot iterate any more.\n this.setState(State.FAILED);\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => {\n if (this.attempts !== null) {\n return `RETRY ${this.attempts}x`;\n } else if (this.attemptsMin !== null && this.attemptsMax !== null) {\n return `RETRY ${this.attemptsMin}x-${this.attemptsMax}x`;\n } else {\n return \"RETRY\";\n }\n };\n\n /**\n * Reset the state of the node.\n */\n reset = () => {\n // Reset the state of this node.\n this.setState(State.READY);\n\n // Reset the current attempt count.\n this.currentAttemptCount = 0;\n\n // Reset the child node.\n this.child.reset();\n };\n\n /**\n * Gets whether an attempt can be made.\n * @returns Whether an attempt can be made.\n */\n canAttempt = () => {\n if (this.targetAttemptCount !== null) {\n // We can attempt as long as we have not reached our target attempt count.\n return this.currentAttemptCount < this.targetAttemptCount;\n }\n\n // If neither an attempt count or a condition function were defined then we can attempt indefinitely.\n return true;\n };\n\n /**\n * Sets the target attempt count.\n * @param options The behaviour tree options object.\n */\n setTargetAttemptCount = (options: BehaviourTreeOptions) => {\n // Are we dealing with an explicit attempt count or will we be randomly picking an attempt count between the min and max attempt count.\n if (this.attempts !== null) {\n this.targetAttemptCount = this.attempts;\n } else if (this.attemptsMin !== null && this.attemptsMax !== null) {\n // We will be picking a random attempt count between a min and max attempt count, if the optional 'random'\n // behaviour tree function option is defined then we will be using that, otherwise we will fall back to using Math.random.\n const random = typeof options.random === \"function\" ? options.random : Math.random;\n\n // Pick a random attempt count between a min and max attempt count.\n this.targetAttemptCount = Math.floor(\n random() * (this.attemptsMax - this.attemptsMin + 1) + this.attemptsMin\n );\n } else {\n this.targetAttemptCount = null;\n }\n };\n}\n", "import Node from \"../Node\";\nimport Decorator from \"./Decorator\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A Root node.\n * The root node will have a single child.\n */\nexport default class Root extends Decorator {\n /**\n * @param attributes The node attributes.\n * @param child The child node.\n */\n constructor(attributes: Attribute[], child: Node) {\n super(\"root\", attributes, child);\n }\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // If the child has never been updated or is running then we will need to update it now.\n if (this.child.getState() === State.READY || this.child.getState() === State.RUNNING) {\n // Update the child of this node.\n this.child.update(agent, options);\n }\n\n // The state of the root node is the state of its child.\n this.setState(this.child.getState());\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => \"ROOT\";\n}\n", "import Node from \"../Node\";\nimport Decorator from \"./Decorator\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A Succeed node.\n * This node wraps a single child and will always move to the 'SUCCEEDED' state when the child moves to a 'SUCCEEDED' or 'FAILED' state.\n */\nexport default class Succeed extends Decorator {\n /**\n * @param attributes The node attributes.\n * @param child The child node.\n */\n constructor(attributes: Attribute[], child: Node) {\n super(\"succeed\", attributes, child);\n }\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // If the child has never been updated or is running then we will need to update it now.\n if (this.child.getState() === State.READY || this.child.getState() === State.RUNNING) {\n this.child.update(agent, options);\n }\n\n // The state of this node will depend in the state of its child.\n switch (this.child.getState()) {\n case State.RUNNING:\n this.setState(State.RUNNING);\n break;\n\n case State.SUCCEEDED:\n case State.FAILED:\n this.setState(State.SUCCEEDED);\n break;\n\n default:\n this.setState(State.READY);\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => \"SUCCEED\";\n}\n", "import Node from \"../Node\";\n\n/**\n * A leaf node.\n */\nexport default abstract class Leaf extends Node {\n /**\n * Gets whether this node is a leaf node.\n */\n isLeafNode = () => true;\n}\n", "import { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\nimport State, { CompleteState } from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Leaf from \"./Leaf\";\nimport Lookup from \"../../Lookup\";\nimport Attribute from \"../../attributes/Attribute\";\n\n/**\n * The type representing a resolved/rejected update promise.\n */\ntype UpdatePromiseResult = {\n /**\n * Whether the promise was resolved rather than rejected.\n */\n isResolved: boolean;\n\n /**\n * The promise resolved value or rejection reason.\n */\n value: any;\n};\n\n/**\n * An Action leaf node.\n * This represents an immediate or ongoing state of behaviour.\n */\nexport default class Action extends Leaf {\n /**\n * @param attributes The node attributes.\n * @param actionName The action name.\n * @param actionArguments The array of action argument definitions.\n */\n constructor(attributes: Attribute[], private actionName: string, private actionArguments: any[]) {\n super(\"action\", attributes, actionArguments);\n }\n\n /**\n * Whether there is a pending update promise.\n */\n private isUsingUpdatePromise = false;\n\n /**\n * The finished state result of an update promise.\n */\n private updatePromiseResult: UpdatePromiseResult | null = null;\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // If the result of this action depends on an update promise then there is nothing to do until it settles.\n if (this.isUsingUpdatePromise) {\n // Are we still waiting for our update promise to settle?\n if (!this.updatePromiseResult) {\n return;\n }\n\n const { isResolved, value } = this.updatePromiseResult;\n\n // Our update promise settled, was it resolved or rejected?\n if (isResolved) {\n // Our promise resolved so check to make sure the result is a valid finished state.\n if (value !== State.SUCCEEDED && value !== State.FAILED) {\n throw new Error(\n \"action node promise resolved with an invalid value, expected a State.SUCCEEDED or State.FAILED value to be returned\"\n );\n }\n\n // Set the state of this node to match the state returned by the promise.\n this.setState(value);\n\n return;\n } else {\n // The promise was rejected, which isn't great.\n throw new Error(`action function '${this.actionName}' promise rejected with '${value}'`);\n }\n }\n\n // Attempt to get the invoker for the action function.\n const actionFuncInvoker = Lookup.getFuncInvoker(agent, this.actionName);\n\n // The action function should be defined.\n if (actionFuncInvoker === null) {\n throw new Error(\n `cannot update action node as the action '${this.actionName}' function is not defined on the agent and has not been registered`\n );\n }\n\n let actionFunctionResult;\n\n try {\n // Call the action function, the result of which may be:\n // - The finished state of this action node.\n // - A promise to return a finished node state.\n // - Undefined if the node should remain in the running state.\n actionFunctionResult = actionFuncInvoker(this.actionArguments) as CompleteState | Promise;\n } catch (error) {\n // The user was naughty and threw something.\n throw new Error(`action function '${this.actionName}' threw '${error}'`);\n }\n\n if (actionFunctionResult instanceof Promise) {\n actionFunctionResult.then(\n (result) => {\n // If 'isUpdatePromisePending' is not set then the promise was cleared as it was resolving, probably via an abort of reset.\n if (!this.isUsingUpdatePromise) {\n return;\n }\n\n // Set the resolved update promise result so that it can be handled on the next update of this node.\n this.updatePromiseResult = {\n isResolved: true,\n value: result\n };\n },\n (reason) => {\n // If 'isUpdatePromisePending' is not set then the promise was cleared as it was resolving, probably via an abort or reset.\n if (!this.isUsingUpdatePromise) {\n return;\n }\n\n // Set the rejected update promise result so that it can be handled on the next update of this node.\n this.updatePromiseResult = {\n isResolved: false,\n value: reason\n };\n }\n );\n\n // This node will be in the 'RUNNING' state until the update promise resolves.\n this.setState(State.RUNNING);\n\n // We are now waiting for the promise returned by the use to resolve before we know what state this node is in.\n this.isUsingUpdatePromise = true;\n } else {\n // Validate the returned value.\n this.validateUpdateResult(actionFunctionResult);\n\n // Set the state of this node, this may be undefined, which just means that the node is still in the 'RUNNING' state.\n this.setState(actionFunctionResult || State.RUNNING);\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => this.actionName;\n\n /**\n * Reset the state of the node.\n */\n reset = () => {\n // Reset the state of this node.\n this.setState(State.READY);\n\n // There is no longer an update promise that we care about.\n this.isUsingUpdatePromise = false;\n this.updatePromiseResult = null;\n };\n\n /**\n * Validate the result of an update function call.\n * @param result The result of an update function call.\n */\n private validateUpdateResult = (result: CompleteState | boolean) => {\n switch (result) {\n case State.SUCCEEDED:\n case State.FAILED:\n case undefined:\n return;\n default:\n throw new Error(\n `action '${this.actionName}' 'onUpdate' returned an invalid response, expected an optional State.SUCCEEDED or State.FAILED value to be returned`\n );\n }\n };\n}\n", "import { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Leaf from \"./Leaf\";\nimport Lookup from \"../../Lookup\";\nimport Attribute from \"../../attributes/Attribute\";\n\n/**\n * A Condition leaf node.\n * This will succeed or fail immediately based on an agent predicate, without moving to the 'RUNNING' state.\n */\nexport default class Condition extends Leaf {\n /**\n * @param attributes The node attributes.\n * @param conditionName The name of the condition function.\n * @param conditionArguments The array of condition argument definitions.\n */\n constructor(attributes: Attribute[], private conditionName: string, private conditionArguments: any[]) {\n super(\"condition\", attributes, conditionArguments);\n }\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // Attempt to get the invoker for the condition function.\n const conditionFuncInvoker = Lookup.getFuncInvoker(agent, this.conditionName);\n\n // The condition function should be defined.\n if (conditionFuncInvoker === null) {\n throw new Error(\n `cannot update condition node as the condition '${this.conditionName}' function is not defined on the agent and has not been registered`\n );\n }\n\n let conditionFunctionResult;\n\n try {\n // Call the condition function to determine the state of this node, the result of which should be a boolean.\n conditionFunctionResult = conditionFuncInvoker(this.conditionArguments);\n } catch (error) {\n // The user was naughty and threw something.\n throw new Error(`condition function '${this.conditionName}' threw '${error}'`);\n }\n\n // The result of calling the condition function must be a boolean value.\n if (typeof conditionFunctionResult !== \"boolean\") {\n throw new Error(\n `expected condition function '${this.conditionName}' to return a boolean but returned '${conditionFunctionResult}'`\n );\n }\n\n // Set the state of this node based on the result of calling the condition function.\n this.setState(!!conditionFunctionResult ? State.SUCCEEDED : State.FAILED);\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => this.conditionName;\n}\n", "import Leaf from \"./Leaf\";\nimport State from \"../../State\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { Agent } from \"../../Agent\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A WAIT node.\n * The state of this node will change to SUCCEEDED after a duration of time\n */\nexport default class Wait extends Leaf {\n /**\n * @param attributes The node attributes.\n * @param duration The duration that this node will wait to succeed in milliseconds.\n * @param durationMin The minimum possible duration in milliseconds that this node will wait to succeed.\n * @param durationMax The maximum possible duration in milliseconds that this node will wait to succeed.\n */\n constructor(\n attributes: Attribute[],\n private duration: number | null,\n private durationMin: number | null,\n private durationMax: number | null\n ) {\n super(\"wait\", attributes, []);\n }\n\n /**\n * The time in milliseconds at which this node was first updated.\n */\n private initialUpdateTime: number = 0;\n\n /**\n * The total duration in milliseconds that this node will be waiting for.\n */\n private totalDuration: number | null = null;\n\n /**\n * The duration in milliseconds that this node has been waiting for.\n */\n private waitedDuration: number = 0;\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // If this node is in the READY state then we need to set the initial update time.\n if (this.is(State.READY)) {\n // Set the initial update time.\n this.initialUpdateTime = new Date().getTime();\n\n // Set the initial waited duration.\n this.waitedDuration = 0;\n\n // Are we dealing with an explicit duration or will we be randomly picking a duration between the min and max duration.\n if (this.duration !== null) {\n this.totalDuration = this.duration;\n } else if (this.durationMin !== null && this.durationMax !== null) {\n // We will be picking a random duration between a min and max duration, if the optional 'random' behaviour tree\n // function option is defined then we will be using that, otherwise we will fall back to using Math.random.\n const random = typeof options.random === \"function\" ? options.random : Math.random;\n\n // Pick a random duration between a min and max duration.\n this.totalDuration = Math.floor(\n random() * (this.durationMax - this.durationMin + 1) + this.durationMin\n );\n } else {\n this.totalDuration = null;\n }\n\n // The node is now running until we finish waiting.\n this.setState(State.RUNNING);\n }\n\n // If we have no total duration then this wait node will wait indefinitely until it is aborted.\n if (this.totalDuration === null) {\n return;\n }\n\n // If we have a 'getDeltaTime' function defined as part of our options then we will use it to figure out how long we have waited for.\n if (typeof options.getDeltaTime === \"function\") {\n // Get the delta time.\n const deltaTime = options.getDeltaTime();\n\n // Our delta time must be a valid number and cannot be NaN.\n if (typeof deltaTime !== \"number\" || isNaN(deltaTime)) {\n throw new Error(\"The delta time must be a valid number and not NaN.\");\n }\n\n // Update the amount of time that this node has been waiting for based on the delta time.\n this.waitedDuration += deltaTime * 1000;\n } else {\n // We are not using a delta time, so we will just work out hom much time has passed since the first update.\n this.waitedDuration = new Date().getTime() - this.initialUpdateTime;\n }\n\n // Have we waited long enough?\n if (this.waitedDuration >= this.totalDuration) {\n // We have finished waiting!\n this.setState(State.SUCCEEDED);\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => {\n if (this.duration !== null) {\n return `WAIT ${this.duration}ms`;\n } else if (this.durationMin !== null && this.durationMax !== null) {\n return `WAIT ${this.durationMin}ms-${this.durationMax}ms`;\n } else {\n return \"WAIT\";\n }\n };\n}\n", "import Guard from \"./guards/Guard\";\n\nexport type AttributeDetails = {\n /** The attribute type. */\n type: string;\n\n /** The attribute arguments. */\n args: any[];\n};\n\n/**\n * A base node attribute.\n */\nexport default abstract class Attribute {\n /**\n * @param type The node attribute type.\n * @param args The array of attribute arguments.\n */\n constructor(public type: string, public args: any[]) {}\n\n /**\n * Gets the attribute details.\n */\n abstract getDetails(): TAttributeDetails;\n\n /**\n * Gets whether this attribute is a guard.\n */\n abstract isGuard: () => this is Guard;\n}\n", "import { Agent } from \"../../Agent\";\nimport Attribute, { AttributeDetails } from \"../Attribute\";\n\nexport type GuardAttributeDetails = {\n /** The name of the condition function that determines whether the guard is satisfied. */\n condition: string;\n} & AttributeDetails;\n\n/**\n * A base node guard attribute.\n */\nexport default abstract class Guard extends Attribute {\n /**\n * @param type The node attribute type.\n * @param args The array of decorator argument definitions.\n * @param condition The name of the condition function that determines whether the guard is satisfied.\n */\n constructor(type: string, args: any[], private condition: string) {\n super(type, args);\n }\n\n /**\n * Gets the name of the condition function that determines whether the guard is satisfied.\n */\n getCondition = () => this.condition;\n\n /**\n * Gets whether this attribute is a guard.\n */\n isGuard = () => true;\n\n /**\n * Gets the attribute details.\n */\n getDetails(): GuardAttributeDetails {\n return {\n type: this.type,\n args: this.args,\n condition: this.getCondition()\n };\n }\n\n /**\n * Gets whether the guard is satisfied.\n * @param agent The agent.\n * @returns Whether the guard is satisfied.\n */\n abstract isSatisfied(agent: Agent): boolean;\n}\n", "import Guard from \"./Guard\";\nimport Lookup from \"../../Lookup\";\nimport { Agent } from \"../../Agent\";\n\n/**\n * A WHILE guard which is satisfied as long as the given condition remains true.\n */\nexport default class While extends Guard {\n /**\n * @param condition The name of the condition function that determines whether the guard is satisfied.\n * @param args The array of decorator argument definitions.\n */\n constructor(condition: string, args: any[]) {\n super(\"while\", args, condition);\n }\n\n /**\n * Gets whether the guard is satisfied.\n * @param agent The agent.\n * @returns Whether the guard is satisfied.\n */\n isSatisfied = (agent: Agent) => {\n // Attempt to get the invoker for the condition function.\n const conditionFuncInvoker = Lookup.getFuncInvoker(agent, this.getCondition());\n\n // The condition function should be defined.\n if (conditionFuncInvoker === null) {\n throw new Error(\n `cannot evaluate node guard as the condition '${this.getCondition()}' function is not defined on the agent and has not been registered`\n );\n }\n\n // Call the condition function to determine whether this guard is satisfied.\n return !!conditionFuncInvoker(this.args);\n };\n}\n", "import Guard from \"./Guard\";\nimport Lookup from \"../../Lookup\";\nimport { Agent } from \"../../Agent\";\n\n/**\n * An UNTIL guard which is satisfied as long as the given condition remains false.\n */\nexport default class Until extends Guard {\n /**\n * @param condition The name of the condition function that determines whether the guard is satisfied.\n * @param args The array of decorator argument definitions.\n */\n constructor(condition: string, args: any[]) {\n super(\"until\", args, condition);\n }\n\n /**\n * Gets whether the guard is satisfied.\n * @param agent The agent.\n * @returns Whether the guard is satisfied.\n */\n isSatisfied = (agent: Agent) => {\n // Attempt to get the invoker for the condition function.\n const conditionFuncInvoker = Lookup.getFuncInvoker(agent, this.getCondition());\n\n // The condition function should be defined.\n if (conditionFuncInvoker === null) {\n throw new Error(\n `cannot evaluate node guard as the condition '${this.getCondition()}' function is not defined on the agent and has not been registered`\n );\n }\n\n // Call the condition function to determine whether this guard is satisfied.\n return !!!conditionFuncInvoker(this.args);\n };\n}\n", "import { Agent } from \"../../Agent\";\nimport Attribute, { AttributeDetails } from \"../Attribute\";\n\nexport type CallbackAttributeDetails = {\n /** The name of the agent function that is called. */\n functionName: string;\n} & AttributeDetails;\n\n/**\n * A base node callback attribute.\n */\nexport default abstract class Callback extends Attribute {\n /**\n * @param type The node attribute type.\n * @param args The array of decorator argument definitions.\n * @param functionName The name of the agent function to call.\n */\n constructor(type: string, args: any[], private functionName: string) {\n super(type, args);\n }\n\n /**\n * Gets the name of the agent function to call.\n */\n getFunctionName = () => this.functionName;\n\n /**\n * Gets whether this attribute is a guard.\n */\n isGuard = () => false;\n\n /**\n * Gets the attribute details.\n */\n getDetails(): CallbackAttributeDetails {\n return {\n type: this.type,\n args: this.args,\n functionName: this.getFunctionName()\n };\n }\n\n /**\n * Attempt to call the agent function that this callback refers to.\n * @param agent The agent.\n */\n abstract callAgentFunction: (agent: Agent, isSuccess: boolean, isAborted: boolean) => void;\n}\n", "import Callback from \"./Callback\";\nimport Lookup from \"../../Lookup\";\nimport { Agent } from \"../../Agent\";\n\n/**\n * An ENTRY callback which defines an agent function to call when the associated node is updated and moves out of running state.\n */\nexport default class Entry extends Callback {\n /**\n * @param functionName The name of the agent function to call.\n * @param args The array of callback argument definitions.\n */\n constructor(functionName: string, args: any[]) {\n super(\"entry\", args, functionName);\n }\n\n /**\n * Attempt to call the agent function that this callback refers to.\n * @param agent The agent.\n */\n callAgentFunction = (agent: Agent) => {\n // Attempt to get the invoker for the callback function.\n const callbackFuncInvoker = Lookup.getFuncInvoker(agent, this.getFunctionName());\n\n // The callback function should be defined.\n if (callbackFuncInvoker === null) {\n throw new Error(\n `cannot call entry function '${this.getFunctionName()}' as is not defined on the agent and has not been registered`\n );\n }\n\n // Call the callback function.\n callbackFuncInvoker(this.args);\n };\n}\n", "import Callback from \"./Callback\";\nimport Lookup from \"../../Lookup\";\nimport { Agent } from \"../../Agent\";\n\n/**\n * A STEP callback which defines an agent function to call when the associated node is updated.\n */\nexport default class Step extends Callback {\n /**\n * @param functionName The name of the agent function to call.\n * @param args The array of callback argument definitions.\n */\n constructor(functionName: string, args: any[]) {\n super(\"step\", args, functionName);\n }\n\n /**\n * Attempt to call the agent function that this callback refers to.\n * @param agent The agent.\n */\n callAgentFunction = (agent: Agent) => {\n // Attempt to get the invoker for the callback function.\n const callbackFuncInvoker = Lookup.getFuncInvoker(agent, this.getFunctionName());\n\n // The callback function should be defined.\n if (callbackFuncInvoker === null) {\n throw new Error(\n `cannot call step function '${this.getFunctionName()}' as is not defined on the agent and has not been registered`\n );\n }\n\n // Call the callback function.\n callbackFuncInvoker(this.args);\n };\n}\n", "import Callback from \"./Callback\";\nimport Lookup from \"../../Lookup\";\nimport { Agent } from \"../../Agent\";\n\n/**\n * An EXIT callback which defines an agent function to call when the associated node is updated and moves to a finished state or is aborted.\n */\nexport default class Exit extends Callback {\n /**\n * @param functionName The name of the agent function to call.\n * @param args The array of callback argument definitions.\n */\n constructor(functionName: string, args: any[]) {\n super(\"exit\", args, functionName);\n }\n\n /**\n * Attempt to call the agent function that this callback refers to.\n * @param agent The agent.\n * @param isSuccess Whether the decorated node was left with a success state.\n * @param isAborted Whether the decorated node was aborted.\n */\n callAgentFunction = (agent: Agent, isSuccess: boolean, isAborted: boolean) => {\n // Attempt to get the invoker for the callback function.\n const callbackFuncInvoker = Lookup.getFuncInvoker(agent, this.getFunctionName());\n\n // The callback function should be defined.\n if (callbackFuncInvoker === null) {\n throw new Error(\n `cannot call exit function '${this.getFunctionName()}' as is not defined on the agent and has not been registered`\n );\n }\n\n // Call the callback function\n callbackFuncInvoker([{ value: { succeeded: isSuccess, aborted: isAborted } }, ...this.args]);\n };\n}\n", "import { AnyNodeDefinition, RootNodeDefinition } from \"./BehaviourTreeDefinition\";\nimport GuardPath, { GuardPathPart } from \"./attributes/guards/GuardPath\";\nimport { validateBranchSubtreeLinks } from \"./BehaviourTreeDefinitionValidator\";\nimport { isInteger } from \"./BehaviourTreeDefinitionUtilities\";\nimport Node from \"./nodes/Node\";\nimport Composite from \"./nodes/composite/Composite\";\nimport Decorator from \"./nodes/decorator/Decorator\";\nimport Parallel from \"./nodes/composite/Parallel\";\nimport Selector from \"./nodes/composite/Selector\";\nimport Sequence from \"./nodes/composite/Sequence\";\nimport Lotto from \"./nodes/composite/Lotto\";\nimport Fail from \"./nodes/decorator/Fail\";\nimport Flip from \"./nodes/decorator/Flip\";\nimport Repeat from \"./nodes/decorator/Repeat\";\nimport Retry from \"./nodes/decorator/Retry\";\nimport Root from \"./nodes/decorator/Root\";\nimport Succeed from \"./nodes/decorator/Succeed\";\nimport Action from \"./nodes/leaf/Action\";\nimport Condition from \"./nodes/leaf/Condition\";\nimport Wait from \"./nodes/leaf/Wait\";\nimport Lookup from \"./Lookup\";\nimport Attribute from \"./attributes/Attribute\";\nimport While from \"./attributes/guards/While\";\nimport Until from \"./attributes/guards/Until\";\nimport Entry from \"./attributes/callbacks/Entry\";\nimport Step from \"./attributes/callbacks/Step\";\nimport Exit from \"./attributes/callbacks/Exit\";\n\n/**\n * A type representing any node instance in a behaviour tree.\n */\ntype AnyNode =\n | Root\n | Action\n | Condition\n | Wait\n | Sequence\n | Selector\n | Lotto\n | Parallel\n | Repeat\n | Retry\n | Flip\n | Succeed\n | Fail;\n\n/**\n * A type defining a mapping of root node identifiers to root node definitions.\n */\ntype RootNodeDefinitionMap = { [key: string | symbol]: RootNodeDefinition };\n\n/**\n * A symbol to use as the main root key in any root node mappings.\n */\nconst MAIN_ROOT_NODE_KEY = Symbol(\"__root__\");\n\n/**\n * Build and populate the root nodes based on the provided definition, assuming that the definition has been validated.\n * @param definition The root node definitions.\n * @returns The built and populated root node definitions.\n */\nexport default function buildRootNode(definition: RootNodeDefinition[]): Root {\n // Create a mapping of root node identifers to root node definitions, including globally registered subtree root node definitions.\n const rootNodeDefinitionMap = createRootNodeDefinitionMap(definition);\n\n // Now that we have all of our root node definitons (those part of the tree definition and those globally\n // registered) we should validate the definition. This will also double-check that we dont have any circular\n // dependencies in our branch -> subtree references and that we have no broken branch -> subtree links.\n validateBranchSubtreeLinks(definition, true);\n\n // Create our populated tree of node instances, starting with our main root node.\n const rootNode = nodeFactory(rootNodeDefinitionMap[MAIN_ROOT_NODE_KEY], rootNodeDefinitionMap) as Root;\n\n // Set a guard path on every leaf of the tree to evaluate as part of each update.\n applyLeafNodeGuardPaths(rootNode);\n\n // We only need to return the main root node.\n return rootNode;\n}\n\n/**\n * A factory function which creates a node instance based on the specified definition.\n * @param definition The node definition.\n * @param rootNodeDefinitionMap The mapping of root node identifers to root node definitions, including globally registered subtree root node definitions.\n * @returns A node instance based on the specified definition.\n */\nfunction nodeFactory(definition: AnyNodeDefinition, rootNodeDefinitionMap: RootNodeDefinitionMap): AnyNode {\n // Get the attributes for the node.\n const attributes = nodeAttributesFactory(definition);\n\n // Create the node instance based on the definition type.\n switch (definition.type) {\n case \"root\":\n return new Root(attributes, nodeFactory(definition.child, rootNodeDefinitionMap));\n\n case \"repeat\":\n let iterations: number | null = null;\n let iterationsMin: number | null = null;\n let iterationsMax: number | null = null;\n\n if (Array.isArray(definition.iterations)) {\n iterationsMin = definition.iterations[0];\n iterationsMax = definition.iterations[1];\n } else if (isInteger(definition.iterations)) {\n iterations = definition.iterations!;\n }\n\n return new Repeat(\n attributes,\n iterations,\n iterationsMin,\n iterationsMax,\n nodeFactory(definition.child, rootNodeDefinitionMap)\n );\n\n case \"retry\":\n let attempts: number | null = null;\n let attemptsMin: number | null = null;\n let attemptsMax: number | null = null;\n\n if (Array.isArray(definition.attempts)) {\n attemptsMin = definition.attempts[0];\n attemptsMax = definition.attempts[1];\n } else if (isInteger(definition.attempts)) {\n attempts = definition.attempts!;\n }\n\n return new Retry(\n attributes,\n attempts,\n attemptsMin,\n attemptsMax,\n nodeFactory(definition.child, rootNodeDefinitionMap)\n );\n\n case \"flip\":\n return new Flip(attributes, nodeFactory(definition.child, rootNodeDefinitionMap));\n\n case \"succeed\":\n return new Succeed(attributes, nodeFactory(definition.child, rootNodeDefinitionMap));\n\n case \"fail\":\n return new Fail(attributes, nodeFactory(definition.child, rootNodeDefinitionMap));\n\n case \"sequence\":\n return new Sequence(\n attributes,\n definition.children.map((child) => nodeFactory(child, rootNodeDefinitionMap))\n );\n\n case \"selector\":\n return new Selector(\n attributes,\n definition.children.map((child) => nodeFactory(child, rootNodeDefinitionMap))\n );\n\n case \"parallel\":\n return new Parallel(\n attributes,\n definition.children.map((child) => nodeFactory(child, rootNodeDefinitionMap))\n );\n\n case \"lotto\":\n return new Lotto(\n attributes,\n definition.weights,\n definition.children.map((child) => nodeFactory(child, rootNodeDefinitionMap))\n );\n\n case \"branch\":\n return nodeFactory(rootNodeDefinitionMap[definition.ref].child, rootNodeDefinitionMap);\n\n case \"action\":\n return new Action(attributes, definition.call, definition.args || []);\n\n case \"condition\":\n return new Condition(attributes, definition.call, definition.args || []);\n\n case \"wait\":\n let duration: number | null = null;\n let durationMin: number | null = null;\n let durationMax: number | null = null;\n\n if (Array.isArray(definition.duration)) {\n durationMin = definition.duration[0];\n durationMax = definition.duration[1];\n } else if (isInteger(definition.duration)) {\n duration = definition.duration!;\n }\n\n return new Wait(attributes, duration, durationMin, durationMax);\n }\n}\n\n/**\n * Creates an array of node attribute instances based on the specified node definition.\n * @param definition The node definition.\n * @returns An array of node attribute instances based on the specified node definition.\n */\nfunction nodeAttributesFactory(definition: AnyNodeDefinition): Attribute[] {\n const attributes: Attribute[] = [];\n\n if (definition.while) {\n attributes.push(new While(definition.while.call, definition.while.args ?? []));\n }\n\n if (definition.until) {\n attributes.push(new Until(definition.until.call, definition.until.args ?? []));\n }\n\n if (definition.entry) {\n attributes.push(new Entry(definition.entry.call, definition.entry.args ?? []));\n }\n\n if (definition.step) {\n attributes.push(new Step(definition.step.call, definition.step.args ?? []));\n }\n\n if (definition.exit) {\n attributes.push(new Exit(definition.exit.call, definition.exit.args ?? []));\n }\n\n return attributes;\n}\n\n/**\n * Creates a mapping of root node identifers to root node definitions, mixing in globally registered subtree root node definitions.\n * @param definition The root node definitions.\n * @returns A mapping of root node identifers to root node definitions, including globally registered subtree root node definitions.\n */\nfunction createRootNodeDefinitionMap(definition: RootNodeDefinition[]): RootNodeDefinitionMap {\n // Create a mapping of root node identifers to root node definitions.\n const rootNodeMap: RootNodeDefinitionMap = {};\n\n // Add in any registered subtree root node definitions.\n for (const [name, rootNodeDefinition] of Object.entries(Lookup.getSubtrees())) {\n // The name used when registering the subtree will be used as the root node identifier.\n rootNodeMap[name] = { ...rootNodeDefinition, id: name };\n }\n\n // Populate the map with the root node definitions that were included with the tree definition.\n // We do this after adding any registered subtrees as we want these to take presedence.\n for (const rootNodeDefinition of definition) {\n rootNodeMap[rootNodeDefinition.id ?? MAIN_ROOT_NODE_KEY] = rootNodeDefinition;\n }\n\n return rootNodeMap;\n}\n\n/**\n * Applies a guard path to every leaf of the tree to evaluate as part of each update.\n * @param root The main root tree node.\n */\nfunction applyLeafNodeGuardPaths(root: Root) {\n const nodePaths: Node[][] = [];\n\n const findLeafNodes = (path: Node[], node: Node) => {\n // Add the current node to the path.\n path = path.concat(node);\n\n // Check whether the current node is a leaf node.\n if (node.isLeafNode()) {\n nodePaths.push(path);\n } else {\n (node as Composite | Decorator).getChildren().forEach((child) => findLeafNodes(path, child));\n }\n };\n\n // Find all leaf node paths, starting from the root.\n findLeafNodes([], root);\n\n nodePaths.forEach((path) => {\n // Each node in the current path will have to be assigned a guard path, working from the root outwards.\n for (let depth = 0; depth < path.length; depth++) {\n // Get the node in the path at the current depth.\n const currentNode = path[depth];\n\n // The node may already have been assigned a guard path, if so just skip it.\n if (currentNode.hasGuardPath()) {\n continue;\n }\n\n // Create the guard path for the current node.\n const guardPath = new GuardPath(\n path\n .slice(0, depth + 1)\n .map((node) => ({ node, guards: node.getGuardAttributes() }))\n .filter((details) => details.guards.length > 0)\n );\n\n // Assign the guard path to the current node.\n currentNode.setGuardPath(guardPath);\n }\n });\n}\n", "import State, { AnyState } from \"./State\";\nimport Lookup from \"./Lookup\";\nimport Node from \"./nodes/Node\";\nimport Root from \"./nodes/decorator/Root\";\nimport Composite from \"./nodes/composite/Composite\";\nimport Decorator from \"./nodes/decorator/Decorator\";\nimport { Agent, GlobalFunction } from \"./Agent\";\nimport { CallbackAttributeDetails } from \"./attributes/callbacks/Callback\";\nimport { GuardAttributeDetails } from \"./attributes/guards/Guard\";\nimport { BehaviourTreeOptions } from \"./BehaviourTreeOptions\";\nimport { convertMDSLToJSON } from \"./mdsl/MDSLDefinitionParser\";\nimport { RootNodeDefinition } from \"./BehaviourTreeDefinition\";\nimport { validateDefinition, validateJSONDefinition } from \"./BehaviourTreeDefinitionValidator\";\nimport buildRootNode from \"./BehaviourTreeBuilder\";\nimport { isNullOrUndefined } from \"./BehaviourTreeDefinitionUtilities\";\n\n// Purely for outside inspection of the tree.\nexport type FlattenedTreeNode = {\n id: string;\n type: string;\n caption: string;\n state: AnyState;\n guards: GuardAttributeDetails[];\n callbacks: CallbackAttributeDetails[];\n args: any[];\n parentId: string | null;\n};\n\n/**\n * A representation of a behaviour tree.\n */\nexport class BehaviourTree {\n /**\n * The main root tree node.\n */\n private readonly _rootNode: Root;\n\n /**\n * Creates a new instance of the BehaviourTree class.\n * @param definition The behaviour tree definition as either an MDSL string, root node definition object or array of root node definition objects.\n * @param agent The agent instance that this behaviour tree is modelling behaviour for.\n * @param options The behaviour tree options object.\n */\n constructor(\n definition: string | RootNodeDefinition | RootNodeDefinition[],\n private agent: Agent,\n private options: BehaviourTreeOptions = {}\n ) {\n // The tree definition must be defined.\n if (isNullOrUndefined(definition)) {\n throw new Error(\"tree definition not defined\");\n }\n\n // The agent must be defined and not null.\n if (typeof agent !== \"object\" || agent === null) {\n throw new Error(\"the agent must be an object and not null\");\n }\n\n // We should validate the definition before we try to build the tree nodes.\n const { succeeded, errorMessage, json } = validateDefinition(definition);\n\n // Did our validation fail without error?\n if (!succeeded) {\n throw new Error(`invalid definition: ${errorMessage}`);\n }\n\n // Double check that we did actually get our json definition as part of our definition validtion.\n if (!json) {\n throw new Error(\n \"expected json definition to be returned as part of successful definition validation response\"\n );\n }\n\n try {\n // Create the populated tree of behaviour tree nodes and get the root node.\n this._rootNode = buildRootNode(json);\n } catch (exception) {\n // There was an issue in trying build and populate the behaviour tree.\n throw new Error(`error building tree: ${(exception as Error).message}`);\n }\n }\n\n /**\n * Gets whether the tree is in the RUNNING state.\n * @returns true if the tree is in the RUNNING state, otherwise false.\n */\n isRunning() {\n return this._rootNode.getState() === State.RUNNING;\n }\n\n /**\n * Gets the current tree state of SUCCEEDED, FAILED, READY or RUNNING.\n * @returns The current tree state.\n */\n getState() {\n return this._rootNode.getState();\n }\n\n /**\n * Step the tree.\n * 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.\n * 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\n * 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.\n *\n * 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.\n */\n step() {\n // If the root node has already been stepped to completion then we need to reset it.\n if (this._rootNode.getState() === State.SUCCEEDED || this._rootNode.getState() === State.FAILED) {\n this._rootNode.reset();\n }\n\n try {\n this._rootNode.update(this.agent, this.options);\n } catch (exception) {\n throw new Error(`error stepping tree: ${(exception as Error).message}`);\n }\n }\n\n /**\n * Resets the tree from the root node outwards to each nested node, giving each a state of READY.\n */\n reset() {\n this._rootNode.reset();\n }\n\n /**\n * Gets the flattened details of every node in the tree.\n * @returns The flattened details of every node in the tree.\n */\n getFlattenedNodeDetails(): FlattenedTreeNode[] {\n // Create an empty flattened array of tree nodes.\n const flattenedTreeNodes: FlattenedTreeNode[] = [];\n\n /**\n * Helper function to process a node instance and push details into the flattened tree nodes array.\n * @param node The current node.\n * @param parentUid The UID of the node parent, or null if the node is the main root node.\n */\n const processNode = (node: Node, parentUid: string | null) => {\n // Get the guard and callback attribute details for this node.\n const guards = node\n .getAttributes()\n .filter((attribute) => attribute.isGuard())\n .map((attribute) => attribute.getDetails()) as GuardAttributeDetails[];\n const callbacks = node\n .getAttributes()\n .filter((attribute) => !attribute.isGuard())\n .map((attribute) => attribute.getDetails()) as CallbackAttributeDetails[];\n\n // Push the current node into the flattened nodes array.\n flattenedTreeNodes.push({\n id: node.getUid(),\n type: node.getType(),\n caption: node.getName(),\n state: node.getState(),\n guards,\n callbacks,\n args: node.getArguments(),\n parentId: parentUid\n });\n\n // Process each of the nodes children if it is not a leaf node.\n if (!node.isLeafNode()) {\n (node as Composite | Decorator)\n .getChildren()\n .forEach((child) => processNode(child, (node as Composite | Decorator).getUid()));\n }\n };\n\n // Convert the nested node structure into a flattened array of node details.\n processNode(this._rootNode, null);\n\n return flattenedTreeNodes;\n }\n\n /**\n * Registers the action/condition/guard/callback function or subtree with the given name.\n * @param name The name of the function or subtree to register.\n * @param value The function or subtree definition to register.\n */\n static register(name: string, value: GlobalFunction | string | RootNodeDefinition) {\n // Are we going to register a action/condition/guard/callback function?\n if (typeof value === \"function\") {\n Lookup.setFunc(name, value);\n return;\n }\n\n // We are not registering an action/condition/guard/callback function, so we must be registering a subtree.\n if (typeof value === \"string\") {\n let rootNodeDefinitions: RootNodeDefinition[];\n\n // We will assume that any string passed in will be a mdsl definition.\n try {\n rootNodeDefinitions = convertMDSLToJSON(value);\n } catch (exception) {\n throw new Error(`error registering definition, invalid MDSL: ${(exception as Error).message}`);\n }\n\n // This function should only ever be called with a definition containing a single unnamed root node.\n if (rootNodeDefinitions.length != 1 || rootNodeDefinitions[0].id !== null) {\n throw new Error(\"error registering definition: expected a single unnamed root node\");\n }\n\n try {\n // We should validate the subtree as we don't want invalid subtrees available via the lookup.\n const { succeeded, errorMessage } = validateJSONDefinition(rootNodeDefinitions[0]);\n\n // Did our validation fail without error?\n if (!succeeded) {\n throw new Error(errorMessage);\n }\n } catch (exception) {\n throw new Error(`error registering definition: ${(exception as Error).message}`);\n }\n\n // Everything seems hunky-dory, register the subtree.\n Lookup.setSubtree(name, rootNodeDefinitions[0]);\n } else if (typeof value === \"object\" && !Array.isArray(value)) {\n // We will assume that any object passed in is a root node definition.\n\n try {\n // We should validate the subtree as we don't want invalid subtrees available via the lookup.\n const { succeeded, errorMessage } = validateJSONDefinition(value);\n\n // Did our validation fail without error?\n if (!succeeded) {\n throw new Error(errorMessage);\n }\n } catch (exception) {\n throw new Error(`error registering definition: ${(exception as Error).message}`);\n }\n\n // Everything seems hunky-dory, register the subtree.\n Lookup.setSubtree(name, value);\n } else {\n throw new Error(\"unexpected value, expected string mdsl definition, root node json definition or function\");\n }\n }\n\n /**\n * Unregisters the registered action/condition/guard/callback function or subtree with the given name.\n * @param name The name of the registered action/condition/guard/callback function or subtree to unregister.\n */\n static unregister(name: string): void {\n Lookup.remove(name);\n }\n\n /**\n * Unregister all registered action/condition/guard/callback functions and subtrees.\n */\n static unregisterAll(): void {\n Lookup.empty();\n }\n}\n"], - "mappings": "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", + "sourcesContent": ["\"use strict\";\r\nObject.defineProperty(exports, \"__esModule\", { value: true });\r\nexports.Participant = void 0;\r\n/**\r\n * A participant that holds a number of tickets.\r\n */\r\nvar Participant = /** @class */ (function () {\r\n /**\r\n * Creates an instance of the Participant class.\r\n * @param participant The actual participant.\r\n * @param tickets The number of tickets held by the participant.\r\n */\r\n function Participant(participant, tickets) {\r\n if (tickets === void 0) { tickets = 1; }\r\n this._participant = participant;\r\n this._tickets = tickets;\r\n }\r\n Object.defineProperty(Participant.prototype, \"participant\", {\r\n /** Gets the actual participant. */\r\n get: function () {\r\n return this._participant;\r\n },\r\n enumerable: false,\r\n configurable: true\r\n });\r\n Object.defineProperty(Participant.prototype, \"tickets\", {\r\n /** Gets or sets the number of tickets held by the participant. */\r\n get: function () {\r\n return this._tickets;\r\n },\r\n set: function (value) {\r\n this._tickets = value;\r\n },\r\n enumerable: false,\r\n configurable: true\r\n });\r\n return Participant;\r\n}());\r\nexports.Participant = Participant;\r\n", "\"use strict\";\r\nObject.defineProperty(exports, \"__esModule\", { value: true });\r\nexports.isNaturalNumber = exports.isNullOrUndefined = void 0;\r\n/**\r\n * Gets whether the value provided is null or undefined.\r\n * @param value The value to check.\r\n * @returns Whether the value provided is null or undefined.\r\n */\r\nfunction isNullOrUndefined(value) {\r\n return value === null || value === undefined;\r\n}\r\nexports.isNullOrUndefined = isNullOrUndefined;\r\n/**\r\n * Gets whether the value provided is a natural number.\r\n * @param value The value to check.\r\n * @returns Whether the value provided is a natural number.\r\n */\r\nfunction isNaturalNumber(value) {\r\n return typeof value === \"number\" && value >= 1 && Math.floor(value) === value;\r\n}\r\nexports.isNaturalNumber = isNaturalNumber;\r\n", "\"use strict\";\r\nObject.defineProperty(exports, \"__esModule\", { value: true });\r\nexports.Lotto = void 0;\r\nvar Participant_1 = require(\"./Participant\");\r\nvar Utilities_1 = require(\"./Utilities\");\r\n/**\r\n * Represents a lotto consisting of a number of pickable ticket-holding participants.\r\n */\r\nvar Lotto = /** @class */ (function () {\r\n /**\r\n * Creates a new instance of Lotto.\r\n * @param customRandom The custom RNG to use in place of Math.random().\r\n */\r\n function Lotto(customRandom) {\r\n /** The array of participants that are holding tickets in the lotto. */\r\n this._participants = [];\r\n this._customRandom = customRandom;\r\n }\r\n /**\r\n * Adds a participant with the specified number of tickets, or adds to the participant ticket count if the participant already holds tickets.\r\n * @param participant The participant to add or to increase the ticket count for if they already hold tickets.\r\n * @param tickets The number of tickets, defaults to 1.\r\n * @returns The Lotto instance.\r\n */\r\n Lotto.prototype.add = function (participant, tickets) {\r\n if (tickets === void 0) { tickets = 1; }\r\n // Check that we have a valid ticket count.\r\n if (!(0, Utilities_1.isNaturalNumber)(tickets)) {\r\n throw new Error(\"tickets value must be a natural number\");\r\n }\r\n // Check whether this participant has already been added.\r\n var existingParticipant = this._participants.find(function (part) { return part.participant === participant; });\r\n if (existingParticipant) {\r\n // The participant has already been added to the lotto so just add to their ticket count.\r\n existingParticipant.tickets += tickets;\r\n }\r\n else {\r\n // The participant is not part of the lotto so we should add them.\r\n this._participants.push(new Participant_1.Participant(participant, tickets));\r\n }\r\n return this;\r\n };\r\n /**\r\n * Removes the specified number of tickets for the given participant from the draw, or all tickets if a ticket number is not defined.\r\n * @param participant The participant to remove tickets for.\r\n * @param tickets The number of tickets to remove, or undefined if all tickets are to be removed.\r\n * @returns The Lotto instance.\r\n */\r\n Lotto.prototype.remove = function (participant, tickets) {\r\n // Attempt to get the existing participant.\r\n var existingParticipant = this._participants.find(function (part) { return part.participant === participant; });\r\n // There is nothing to do if the specified participant isn't even part of the lotto.\r\n if (!existingParticipant) {\r\n return this;\r\n }\r\n // Check whether a tickets value was given.\r\n if (tickets !== undefined) {\r\n // Check that we have a valid ticket count.\r\n if (!(0, Utilities_1.isNaturalNumber)(tickets)) {\r\n throw new Error(\"tickets value must be a natural number\");\r\n }\r\n existingParticipant.tickets -= tickets;\r\n // If the participant no longer holds any tickets then they should be removed.\r\n if (existingParticipant.tickets < 1) {\r\n this._participants = this._participants.filter(function (part) { return part !== existingParticipant; });\r\n }\r\n }\r\n else {\r\n // We are removing all tickets for the participant so just remove them from the lotto.\r\n this._participants = this._participants.filter(function (part) { return part !== existingParticipant; });\r\n }\r\n return this;\r\n };\r\n /**\r\n * Draw a winning ticket and return the participant that holds the ticket.\r\n * @param options The draw options.\r\n * @returns The participant that holds the winning ticket.\r\n */\r\n Lotto.prototype.draw = function (options) {\r\n if (options === void 0) { options = {}; }\r\n // If we have no participants then just return null.\r\n if (this._participants.length === 0) {\r\n return null;\r\n }\r\n var redrawable = (0, Utilities_1.isNullOrUndefined)(options.redrawable) ? true : options.redrawable;\r\n var pickable = [];\r\n this._participants.forEach(function (_a) {\r\n var participant = _a.participant, tickets = _a.tickets;\r\n for (var ticketCount = 0; ticketCount < tickets; ticketCount++) {\r\n pickable.push(participant);\r\n }\r\n });\r\n var random;\r\n // We need a random floating-point number between 0 (inclusive) and 1 to scale up to pick our winner.\r\n // If a custom random function exists then we should use that or fall back to Math.random().\r\n if (this._customRandom) {\r\n // Call our custom random function to get a random floating-point number.\r\n random = this._customRandom();\r\n // Verify that the result of calling our custom random function is a number between 0 (inclusive) and 1.\r\n if (typeof random !== \"number\" || random < 0 || random >= 1) {\r\n throw new Error(\"the 'random' function provided did not return a number between 0 (inclusive) and 1\");\r\n }\r\n }\r\n else {\r\n // No custom random function was defined so just use good ol' Math.random().\r\n random = Math.random();\r\n }\r\n // Pick a winning participant.\r\n var winner = pickable[Math.floor(random * pickable.length)];\r\n // If the ticket isn't redrawable then we should remove a ticket from the winning participants ticket count.\r\n if (!redrawable) {\r\n this.remove(winner, 1);\r\n }\r\n // Return the winning participant.\r\n return winner;\r\n };\r\n /**\r\n * Draws multiple winning tickets and return an array of the participants that hold the winning tickets.\r\n * @param tickets The number of winning tickets to draw.\r\n * @param options The draw multiple options.\r\n * @returns An array of the participants that hold the winning tickets.\r\n */\r\n Lotto.prototype.drawMultiple = function (tickets, options) {\r\n if (options === void 0) { options = {}; }\r\n var uniqueResults = (0, Utilities_1.isNullOrUndefined)(options.unique) ? false : options.unique;\r\n // Handle cases where the user has asked for zero tickets (no idea why they would do this be we should trust them).\r\n if (tickets === 0) {\r\n return [];\r\n }\r\n // Now that we know out tickets value is not zero we should check that it is a valid natural number.\r\n if (!(0, Utilities_1.isNaturalNumber)(tickets)) {\r\n throw new Error(\"tickets value must be a natural number\");\r\n }\r\n var result = [];\r\n // Keep drawing tickets until we either reach the number of required tickets or we simply run out of tickets to draw.\r\n // We can run out of tickets to draw if 'options.redrawable' is explicity 'false' or we just had no participants when 'drawMultiple' was called.\r\n while (result.length < tickets && this._participants.length > 0) {\r\n result.push(this.draw(options));\r\n }\r\n // If the 'unique' draw option is set then we need to remove duplicates from the result list.\r\n if (uniqueResults) {\r\n // Create an array to store our unique results.\r\n var unique = [];\r\n // Iterate over all of our participants (with potential duplicates) and populate our array of unique values.\r\n for (var _i = 0, result_1 = result; _i < result_1.length; _i++) {\r\n var participant = result_1[_i];\r\n if (unique.indexOf(participant) === -1) {\r\n unique.push(participant);\r\n }\r\n }\r\n result = unique;\r\n }\r\n return result;\r\n };\r\n return Lotto;\r\n}());\r\nexports.Lotto = Lotto;\r\n", "\"use strict\";\r\nObject.defineProperty(exports, \"__esModule\", { value: true });\r\nexports.createLotto = void 0;\r\nvar Lotto_1 = require(\"./Lotto\");\r\n/**\r\n * A function that creates and returns a Lotto instance.\r\n * @param participantsOrOptions An array of initial participants or options relating to the creation of a Lotto instance.\r\n * @returns A new Lotto instance.\r\n */\r\nfunction createLotto(participantsOrOptions) {\r\n // If no initial participants or lotto options were provided as an argument then we can just return a new lotto instance now.\r\n if (!participantsOrOptions) {\r\n return new Lotto_1.Lotto();\r\n }\r\n // Check whether we were provided with an array of initial participants or a lotto options object.\r\n if (Array.isArray(participantsOrOptions)) {\r\n // We are dealing with a pre-defined array of participants.\r\n var participants = participantsOrOptions;\r\n var lotto_1 = new Lotto_1.Lotto();\r\n // If the lotto participants have been defined upfront then we will need to add them all to our lotto instance now.\r\n participants.forEach(function (_a) {\r\n var participant = _a[0], tokens = _a[1];\r\n return lotto_1.add(participant, tokens);\r\n });\r\n // Return the Lotto instance.\r\n return lotto_1;\r\n }\r\n else {\r\n // We are dealing with some lotto options.\r\n var random = participantsOrOptions.random, participants = participantsOrOptions.participants;\r\n // Create a Lotto instance passing the custom RNG function to use in place of Math.random() (which could be undefined).\r\n var lotto_2 = new Lotto_1.Lotto(random);\r\n // If the lotto participants have been defined upfront as part of the options then we will need to add them all to our lotto instance now.\r\n if (participants) {\r\n participants.forEach(function (_a) {\r\n var participant = _a[0], tokens = _a[1];\r\n return lotto_2.add(participant, tokens);\r\n });\r\n }\r\n // Return the Lotto instance.\r\n return lotto_2;\r\n }\r\n}\r\nexports.createLotto = createLotto;\r\n", "\"use strict\";\r\nObject.defineProperty(exports, \"__esModule\", { value: true });\r\nvar createLotto_1 = require(\"./createLotto\");\r\nexports.default = createLotto_1.createLotto;\r\n", "import State from \"./State\";\nimport { validateDefinition } from \"./BehaviourTreeDefinitionValidator\";\nimport { convertMDSLToJSON } from \"./mdsl/MDSLDefinitionParser\";\nimport { BehaviourTree, FlattenedTreeNode } from \"./BehaviourTree\";\nimport { BehaviourTreeOptions } from \"./BehaviourTreeOptions\";\n\nexport { BehaviourTree, State, convertMDSLToJSON, validateDefinition };\nexport type { FlattenedTreeNode, BehaviourTreeOptions };\n", "/**\n * Enumeration of node state types.\n */\nexport enum State {\n READY = \"mistreevous.ready\",\n RUNNING = \"mistreevous.running\",\n SUCCEEDED = \"mistreevous.succeeded\",\n FAILED = \"mistreevous.failed\"\n}\n\nexport { State as default };\n\nexport type CompleteState = State.SUCCEEDED | State.FAILED;\nexport type AnyState = State.READY | State.RUNNING | CompleteState;\n", "import {\n NodeDefinition,\n RootNodeDefinition,\n DecoratorNodeDefinition,\n CompositeNodeDefinition,\n AnyNodeDefinition,\n BranchNodeDefinition\n} from \"./BehaviourTreeDefinition\";\n\n/**\n * A type guard function that returns true if the specified node satisfies the RootNodeDefinition type.\n * @param node The node.\n * @returns A value of true if the specified node satisfies the RootNodeDefinition type.\n */\nexport function isRootNode(node: NodeDefinition): node is RootNodeDefinition {\n return node.type === \"root\";\n}\n\n/**\n * A type guard function that returns true if the specified node satisfies the BranchNodeDefinition type.\n * @param node The node.\n * @returns A value of true if the specified node satisfies the BranchNodeDefinition type.\n */\nexport function isBranchNode(node: NodeDefinition): node is BranchNodeDefinition {\n return node.type === \"branch\";\n}\n\n/**\n * A type guard function that returns true if the specified node satisfies the NodeDefinition type.\n * @param node The node.\n * @returns A value of true if the specified node satisfies the NodeDefinition type.\n */\nexport function isLeafNode(node: NodeDefinition): node is NodeDefinition {\n return [\"branch\", \"action\", \"condition\", \"wait\"].includes(node.type);\n}\n\n/**\n * A type guard function that returns true if the specified node satisfies the DecoratorNodeDefinition type.\n * @param node The node.\n * @returns A value of true if the specified node satisfies the DecoratorNodeDefinition type.\n */\nexport function isDecoratorNode(node: NodeDefinition): node is DecoratorNodeDefinition {\n return [\"root\", \"repeat\", \"retry\", \"flip\", \"succeed\", \"fail\"].includes(node.type);\n}\n\n/**\n * A type guard function that returns true if the specified node satisfies the CompositeNodeDefinition type.\n * @param node The node.\n * @returns A value of true if the specified node satisfies the CompositeNodeDefinition type.\n */\nexport function isCompositeNode(node: NodeDefinition): node is CompositeNodeDefinition {\n return [\"sequence\", \"selector\", \"lotto\", \"parallel\"].includes(node.type);\n}\n\n/**\n * Flatten a node definition into an array of all of its nested node definitions.\n * @param nodeDefinition The node definition to flatten.\n * @returns An array of all of nested node definitions.\n */\nexport function flattenDefinition(nodeDefinition: AnyNodeDefinition): AnyNodeDefinition[] {\n const nodes: AnyNodeDefinition[] = [];\n\n const processNode = (currentNodeDefinition: AnyNodeDefinition) => {\n nodes.push(currentNodeDefinition);\n\n if (isCompositeNode(currentNodeDefinition)) {\n currentNodeDefinition.children.forEach(processNode);\n } else if (isDecoratorNode(currentNodeDefinition)) {\n processNode(currentNodeDefinition.child);\n }\n };\n\n processNode(nodeDefinition);\n\n return nodes;\n}\n\n/**\n * Determines whether the passed value is an integer.\n * @param value The value to check.\n * @returns Whether the passed value is an integer.\n */\nexport function isInteger(value: unknown): boolean {\n return typeof value === \"number\" && Math.floor(value) === value;\n}\n\n/**\n * Determines whether the passed value is null or undefined.\n * @param value The value to check.\n * @returns Whether the passed value is null or undefined.\n */\nexport function isNullOrUndefined(value: unknown): boolean {\n return typeof value === \"undefined\" || value === null;\n}\n", "/**\n * A type defining an object that holds a reference to substitued string literals parsed from the definition.\n */\nexport type StringLiteralPlaceholders = { [key: string]: string };\n\n/**\n * Pop the next raw token from the specified array of tokens and throw an error if it wasn't the expected one.\n * @param tokens The array of tokens.\n * @param expected An optional string or array or items, one of which must match the next popped token.\n * @returns The popped token.\n */\nexport function popAndCheck(tokens: string[], expected?: string | string[]): string {\n // Get and remove the next token.\n const popped = tokens.shift();\n\n // We were expecting another token but there aren't any.\n if (popped === undefined) {\n throw new Error(\"unexpected end of definition\");\n }\n\n // Do we have an expected token/tokens array?\n if (expected != undefined) {\n // Get an array of expected values, if the popped token matches any then we are all good.\n const expectedValues = typeof expected === \"string\" ? [expected] : expected;\n\n // Check whether the popped token matches at least one of our expected items.\n var tokenMatchesExpectation = expectedValues.some((item) => popped.toUpperCase() === item.toUpperCase());\n\n // Throw an error if the popped token didn't match any of our expected items.\n if (!tokenMatchesExpectation) {\n const expectationString = expectedValues.map((item) => \"'\" + item + \"'\").join(\" or \");\n throw new Error(\"unexpected token found. Expected \" + expectationString + \" but got '\" + popped + \"'\");\n }\n }\n\n // Return the popped token.\n return popped;\n}\n\n/**\n * Swaps out any node/attribute argument string literals with placeholders.\n * @param definition The definition.\n * @returns An object containing a mapping of placeholders to original string values as well as the processed definition string.\n */\nexport function substituteStringLiterals(definition: string): {\n placeholders: StringLiteralPlaceholders;\n processedDefinition: string;\n} {\n // Create an object to hold the mapping of placeholders to original string values.\n const placeholders: StringLiteralPlaceholders = {};\n\n // Replace any string literals wrapped with double quotes in our definition with placeholders to be processed later.\n const processedDefinition = definition.replace(/\\\"(\\\\.|[^\"\\\\])*\\\"/g, (match) => {\n var strippedMatch = match.substring(1, match.length - 1);\n var placeholder = Object.keys(placeholders).find((key) => placeholders[key] === strippedMatch);\n\n // If we have no existing string literal match then create a new placeholder.\n if (!placeholder) {\n placeholder = `@@${Object.keys(placeholders).length}@@`;\n placeholders[placeholder] = strippedMatch;\n }\n\n return placeholder;\n });\n\n return { placeholders, processedDefinition };\n}\n\n/**\n * Parse the tree definition into an array of raw tokens.\n * @param definition The definition.\n * @returns An array of tokens parsed from the definition.\n */\nexport function parseTokensFromDefinition(definition: string): string[] {\n // Add some space around various important characters so that they can be plucked out easier as individual tokens.\n definition = definition.replace(/\\(/g, \" ( \");\n definition = definition.replace(/\\)/g, \" ) \");\n definition = definition.replace(/\\{/g, \" { \");\n definition = definition.replace(/\\}/g, \" } \");\n definition = definition.replace(/\\]/g, \" ] \");\n definition = definition.replace(/\\[/g, \" [ \");\n definition = definition.replace(/\\,/g, \" , \");\n\n // Split the definition into raw token form and return it.\n return definition.replace(/\\s+/g, \" \").trim().split(\" \");\n}\n", "import { StringLiteralPlaceholders, popAndCheck } from \"./MDSLUtilities\";\n\n/**\n * A type representing any node function argument.\n */\ntype Argument = {\n /**\n * The argument value.\n */\n value: T;\n /**\n * The argument type, used for validation.\n */\n type: string;\n};\n\ntype NullArgument = Argument & {\n type: \"null\";\n};\n\ntype BooleanArgument = Argument & {\n type: \"boolean\";\n};\n\ntype NumberArgument = Argument & {\n type: \"number\";\n /**\n * A flag defining whether the number argument value is a valid integer. (used for validation)\n */\n isInteger: boolean;\n};\n\ntype StringPlaceholderArgument = Argument & {\n type: \"string\";\n};\n\ntype IdentifierArgument = Argument & {\n type: \"identifier\";\n};\n\n/**\n * A type representing a reference to any node function argument.\n */\ntype AnyArgument = NullArgument | BooleanArgument | NumberArgument | StringPlaceholderArgument | IdentifierArgument;\n\n/**\n * Parse an array of argument definitions from the specified tokens array.\n * @param tokens The array tokens to parse the argument definitions from.\n * @param stringArgumentPlaceholders The mapping of string literal node argument placeholders to original values.\n * @param argumentValidator The argument validator function.\n * @param validationFailedMessage The exception message to throw if argument validation fails.\n * @returns An array of argument definitions parsed from the specified tokens array.\n */\nexport function parseArgumentTokens(\n tokens: string[],\n stringArgumentPlaceholders: StringLiteralPlaceholders\n): AnyArgument[] {\n const argumentList: AnyArgument[] = [];\n\n // If the next token is not a '[' or '(' then we have no arguments to parse.\n if (![\"[\", \"(\"].includes(tokens[0])) {\n return argumentList;\n }\n\n // Any lists of arguments will always be wrapped in '[]' for node arguments or '()' for attribute arguments.\n // We are looking for a '[' or '(' opener that wraps the argument tokens and the relevant closer.\n const closingToken = popAndCheck(tokens, [\"[\", \"(\"]) === \"[\" ? \"]\" : \")\";\n\n const argumentListTokens: string[] = [];\n\n // Grab all tokens between the '[' and ']' or '(' and ')'.\n while (tokens.length && tokens[0] !== closingToken) {\n // The next token is part of our arguments list.\n argumentListTokens.push(tokens.shift()!);\n }\n\n // Validate the order of the argument tokens. Each token must either be a ',' or a single argument that satisfies the validator.\n argumentListTokens.forEach((token, index) => {\n // Get whether this token should be an actual argument.\n const shouldBeArgumentToken = !(index & 1);\n\n // If the current token should be an actual argument then validate it, otherwise it should be a ',' token.\n if (shouldBeArgumentToken) {\n // Get the argument definition.\n const argumentDefinition = getArgumentDefinition(token, stringArgumentPlaceholders);\n\n // This is a valid argument!\n argumentList.push(argumentDefinition);\n } else {\n // The current token should be a ',' token.\n if (token !== \",\") {\n throw new Error(`invalid argument list, expected ',' or ']' but got '${token}'`);\n }\n }\n });\n\n // The arguments list should terminate with a ']' or ')' token, depending on the opener.\n popAndCheck(tokens, closingToken);\n\n // Return the arguments.\n return argumentList;\n}\n\n/**\n * Gets an argument value definition.\n * @param token The argument token.\n * @param stringArgumentPlaceholders The mapping of string literal node argument placeholders to original values.\n * @returns An argument value definition.\n */\nfunction getArgumentDefinition(token: string, stringArgumentPlaceholders: StringLiteralPlaceholders): AnyArgument {\n // Check whether the token represents a null value.\n if (token === \"null\") {\n return {\n value: null,\n type: \"null\"\n } as NullArgument;\n }\n\n // Check whether the token represents a boolean value.\n if (token === \"true\" || token === \"false\") {\n return {\n value: token === \"true\",\n type: \"boolean\"\n } as BooleanArgument;\n }\n\n // Check whether the token represents a number value.\n // TODO: Relies on broken isNaN - see MDN.\n // if (!Number.isNaN(token)) {\n if (!isNaN(token as any)) {\n return {\n value: parseFloat(token),\n isInteger: parseFloat(token) === parseInt(token, 10),\n type: \"number\"\n } as NumberArgument;\n }\n\n // Check whether the token is a placeholder (e.g. @@0@@) representing a string literal.\n if (token.match(/^@@\\d+@@$/g)) {\n return {\n value: stringArgumentPlaceholders[token].replace('\\\\\"', '\"'),\n type: \"string\"\n } as StringPlaceholderArgument;\n }\n\n // The only remaining option is that the argument value is an identifier.\n return {\n value: token,\n type: \"identifier\"\n } as IdentifierArgument;\n}\n", "import { NodeAttributeDefinition } from \"../BehaviourTreeDefinition\";\nimport { parseArgumentTokens } from \"./MDSLNodeArgumentParser\";\nimport { StringLiteralPlaceholders } from \"./MDSLUtilities\";\n\n/**\n * A type defining the attribute definitions of a node.\n */\ntype NodeAttributes = {\n while?: NodeAttributeDefinition;\n until?: NodeAttributeDefinition;\n entry?: NodeAttributeDefinition;\n exit?: NodeAttributeDefinition;\n step?: NodeAttributeDefinition;\n};\n\n/**\n * Parse any node attribute definitions from the specified tokens array.\n * @param tokens The array of remaining tokens.\n * @param stringArgumentPlaceholders The mapping of string literal node argument placeholders to original values.\n * @returns An object of attribute definitions defined by any directly following tokens.\n */\nexport function parseAttributeTokens(\n tokens: string[],\n stringArgumentPlaceholders: StringLiteralPlaceholders\n): NodeAttributes {\n const nodeAttributeNames: (keyof NodeAttributes)[] = [\"while\", \"until\", \"entry\", \"exit\", \"step\"];\n\n // Create an object to hold any attributes found.\n const attributes: NodeAttributes = {};\n\n // Try to get the name of the attribute for the next token.\n let nextAttributeName = tokens[0]?.toLowerCase() as keyof NodeAttributes;\n\n // Pull attribute tokens as well as their arguments off of the tokens stack until we have no more.\n while (nodeAttributeNames.includes(nextAttributeName)) {\n // Check to make sure that we have not already created an attribute definition of this type.\n if (attributes[nextAttributeName]) {\n throw new Error(`duplicate attribute '${tokens[0].toUpperCase()}' found for node`);\n }\n\n // Remove the attribute name token from the array of tokens.\n tokens.shift();\n\n // Grab the attribute arguments, assuming the first to be an identifier.\n const [attributeCallIdentifier, ...attributeArguments] = parseArgumentTokens(\n tokens,\n stringArgumentPlaceholders\n );\n\n // The first attribute argument has to be an identifer, this will reference an agent function.\n if (attributeCallIdentifier?.type !== \"identifier\") {\n throw new Error(\"expected agent function or registered function name identifier argument for attribute\");\n }\n\n // Any attribute arguments (other than the expected call identifier) must have a type of string, number, boolean or null.\n attributeArguments\n .filter((arg) => arg.type === \"identifier\")\n .forEach((arg) => {\n throw new Error(\n `invalid attribute argument value '${arg.value}', must be string, number, boolean or null`\n );\n });\n\n // Create the attribute definition and add it to the object of attribute definitions found.\n attributes[nextAttributeName] = {\n call: attributeCallIdentifier.value,\n args: attributeArguments.map(({ value }) => value)\n };\n\n // Try to get the next attribute name token, as there could be multiple.\n nextAttributeName = tokens[0]?.toLowerCase() as keyof NodeAttributes;\n }\n\n return attributes;\n}\n", "import {\n ActionNodeDefinition,\n AnyChildNodeDefinition,\n AnyNodeDefinition,\n BranchNodeDefinition,\n ConditionNodeDefinition,\n FailNodeDefinition,\n FlipNodeDefinition,\n LottoNodeDefinition,\n ParallelNodeDefinition,\n RepeatNodeDefinition,\n RetryNodeDefinition,\n RootNodeDefinition,\n SelectorNodeDefinition,\n SequenceNodeDefinition,\n SucceedNodeDefinition,\n WaitNodeDefinition\n} from \"../BehaviourTreeDefinition\";\nimport {\n isCompositeNode,\n isDecoratorNode,\n isLeafNode,\n isNullOrUndefined,\n isRootNode\n} from \"../BehaviourTreeDefinitionUtilities\";\nimport { parseArgumentTokens } from \"./MDSLNodeArgumentParser\";\nimport { parseAttributeTokens } from \"./MDSLNodeAttributeParser\";\nimport {\n StringLiteralPlaceholders,\n parseTokensFromDefinition,\n popAndCheck,\n substituteStringLiterals\n} from \"./MDSLUtilities\";\n\n/**\n * Convert the MDSL tree definition string into an equivalent JSON definition.\n * @param definition The tree definition string as MDSL.\n * @returns The root node JSON definitions.\n */\nexport function convertMDSLToJSON(definition: string): RootNodeDefinition[] {\n // Swap out any node/attribute argument string literals with a placeholder and get a mapping of placeholders to original values as well as the processed definition.\n const { placeholders, processedDefinition } = substituteStringLiterals(definition);\n\n // Parse our definition definition string into an array of raw tokens.\n const tokens = parseTokensFromDefinition(processedDefinition);\n\n return convertTokensToJSONDefinition(tokens, placeholders);\n}\n\n/**\n * Converts the specified tree definition tokens into a JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The root node JSON definitions.\n */\nfunction convertTokensToJSONDefinition(\n tokens: string[],\n stringLiteralPlaceholders: StringLiteralPlaceholders\n): RootNodeDefinition[] {\n // There must be at least 3 tokens for the tree definition to be valid. 'ROOT', '{' and '}'.\n if (tokens.length < 3) {\n throw new Error(\"invalid token count\");\n }\n\n // We should have a matching number of '{' and '}' tokens. If not, then there are scopes that have not been properly closed.\n if (tokens.filter((token) => token === \"{\").length !== tokens.filter((token) => token === \"}\").length) {\n throw new Error(\"scope character mismatch\");\n }\n\n // Create an array of tree stack arrays where root nodes will always be at the botton and the current composite/decorator node at the top.\n // There should be an element in this array for every root node defined and every element should be an array with a root note as the first element.\n // E.g. A definition with two root nodes defined:\n // [\n // [root, lotto, sequence],\n // [root, selector]\n // ]\n const treeStacks: [Partial, ...Partial[]][] = [];\n\n // Create an array of all root node definitions that we create.\n const rootNodes: Partial[] = [];\n\n // A helper function used to push node definitions onto the tree stack.\n const pushNode = (node: AnyNodeDefinition) => {\n // If the node is a root node then we need to create a new tree stack array with the root node at the root.\n if (isRootNode(node)) {\n // We need to double-check that this root node is not the child of another node.\n // We can do this by checking whether the top tree stack is not empty (contains an existing node)\n if (treeStacks[treeStacks.length - 1]?.length) {\n throw new Error(\"a root node cannot be the child of another node\");\n }\n\n // Add the root node definition to our array of all parsed root node definitions.\n rootNodes.push(node);\n\n // Add the root node definition to the root of a new tree stack.\n treeStacks.push([node]);\n\n return;\n }\n\n // All non-root nodes should be pushed after their root nodes so handle cases\n // where we may not have any tree stacks or our top-most tree stack is empty.\n if (!treeStacks.length || !treeStacks[treeStacks.length - 1].length) {\n throw new Error(\"expected root node at base of definition\");\n }\n\n // Get the current tree stack that we are populating.\n const topTreeStack = treeStacks[treeStacks.length - 1];\n\n // Get the top-most node in the current tree stack, this will be a composite/decorator node\n // for which we will populate its children array if composite or setting its child if a decorator.\n const topTreeStackTopNode = topTreeStack[topTreeStack.length - 1] as AnyNodeDefinition;\n\n // If the top-most node in the current root stack is a composite or decorator\n // node then the current node should be added as a child of the top-most node.\n if (isCompositeNode(topTreeStackTopNode)) {\n topTreeStackTopNode.children = topTreeStackTopNode.children || [];\n topTreeStackTopNode.children.push(node);\n } else if (isDecoratorNode(topTreeStackTopNode)) {\n // If the top node already has a child node set then throw an error as a decorator should only have a single child.\n if (topTreeStackTopNode.child) {\n throw new Error(\"a decorator node must only have a single child node\");\n }\n\n topTreeStackTopNode.child = node;\n }\n\n // If the node we are adding is also a composite or decorator node, then we should push it\n // onto the current tree stack, as subsequent nodes will be added as its child/children.\n if (!isLeafNode(node)) {\n topTreeStack.push(node);\n }\n };\n\n // A helper function used to pop the top-most node definition off of the tree stack and return it.\n const popNode = (): AnyNodeDefinition | null => {\n let poppedNode: AnyNodeDefinition | null = null;\n\n // Get the current tree stack that we are populating.\n const topTreeStack = treeStacks[treeStacks.length - 1];\n\n // Pop the top-most node in the current tree stack if there is one.\n if (topTreeStack.length) {\n poppedNode = topTreeStack.pop() as AnyNodeDefinition;\n }\n\n // We don't want any empty tree stacks in our stack of tree stacks.\n if (!topTreeStack.length) {\n treeStacks.pop();\n }\n\n return poppedNode;\n };\n\n // We should keep processing the raw tokens until we run out of them.\n while (tokens.length) {\n // Grab the next token.\n const token = tokens.shift()!;\n\n // How we create the next node depends on the current raw token value.\n switch (token.toUpperCase()) {\n case \"ROOT\": {\n pushNode(createRootNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"SUCCEED\": {\n pushNode(createSucceedNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"FAIL\": {\n pushNode(createFailNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"FLIP\": {\n pushNode(createFlipNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"REPEAT\": {\n pushNode(createRepeatNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"RETRY\": {\n pushNode(createRetryNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"SEQUENCE\": {\n pushNode(createSequenceNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"SELECTOR\": {\n pushNode(createSelectorNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"PARALLEL\": {\n pushNode(createParallelNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"LOTTO\": {\n pushNode(createLottoNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"ACTION\": {\n pushNode(createActionNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"CONDITION\": {\n pushNode(createConditionNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"WAIT\": {\n pushNode(createWaitNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"BRANCH\": {\n pushNode(createBranchNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"}\": {\n // The '}' character closes the current scope and means that we have to pop a node off of the current stack.\n const poppedNode = popNode();\n\n // Now that we have a node definition we can carry out any validation that may require the node to be fully populated.\n if (poppedNode) {\n validatePoppedNode(poppedNode);\n }\n\n break;\n }\n\n default: {\n throw new Error(`unexpected token: ${token}`);\n }\n }\n }\n\n return rootNodes as RootNodeDefinition[];\n}\n\n/**\n * Creates a root node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The root node JSON definition.\n */\nfunction createRootNode(tokens: string[], stringLiteralPlaceholders: StringLiteralPlaceholders): RootNodeDefinition {\n // Create the root node definition.\n let node = {\n type: \"root\"\n } as Partial;\n\n // Parse any node arguments, we should only have one if any which will be an identifier argument for the root identifier.\n const nodeArguments = parseArgumentTokens(tokens, stringLiteralPlaceholders);\n\n // Check whether any node arguments were defined.\n if (nodeArguments.length) {\n // We should only have one argument, if any, which will be an identifier argument for the root identifier.\n if (nodeArguments.length === 1 && nodeArguments[0].type === \"identifier\") {\n // The root node identifier will be the first and only node argument value.\n node.id = nodeArguments[0].value as string;\n } else {\n throw new Error(\"expected single root name argument\");\n }\n }\n\n // Grab any node attribute definitions and spread them into the node definition.\n node = { ...node, ...parseAttributeTokens(tokens, stringLiteralPlaceholders) };\n\n // This is a decorator node, so we expect an opening '{'.\n popAndCheck(tokens, \"{\");\n\n // Return the root node definition.\n return node as RootNodeDefinition;\n}\n\n/**\n * Creates a succeed node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The succeed node JSON definition.\n */\nfunction createSucceedNode(\n tokens: string[],\n stringLiteralPlaceholders: StringLiteralPlaceholders\n): SucceedNodeDefinition {\n const node = {\n type: \"succeed\",\n ...parseAttributeTokens(tokens, stringLiteralPlaceholders)\n } as SucceedNodeDefinition;\n\n // This is a decorator node, so we expect an opening '{'.\n popAndCheck(tokens, \"{\");\n\n // Return the succeed node definition.\n return node;\n}\n\n/**\n * Creates a fail node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The fail node JSON definition.\n */\nfunction createFailNode(tokens: string[], stringLiteralPlaceholders: StringLiteralPlaceholders): FailNodeDefinition {\n const node = {\n type: \"fail\",\n ...parseAttributeTokens(tokens, stringLiteralPlaceholders)\n } as FailNodeDefinition;\n\n // This is a decorator node, so we expect an opening '{'.\n popAndCheck(tokens, \"{\");\n\n // Return the fail node definition.\n return node;\n}\n\n/**\n * Creates a flip node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The flip node JSON definition.\n */\nfunction createFlipNode(tokens: string[], stringLiteralPlaceholders: StringLiteralPlaceholders): FlipNodeDefinition {\n const node = {\n type: \"flip\",\n ...parseAttributeTokens(tokens, stringLiteralPlaceholders)\n } as FlipNodeDefinition;\n\n // This is a decorator node, so we expect an opening '{'.\n popAndCheck(tokens, \"{\");\n\n // Return the flip node definition.\n return node;\n}\n\n/**\n * Creates a repeat node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The repeat node JSON definition.\n */\nfunction createRepeatNode(\n tokens: string[],\n stringLiteralPlaceholders: StringLiteralPlaceholders\n): RepeatNodeDefinition {\n let node = { type: \"repeat\" } as RepeatNodeDefinition;\n\n // Get the node arguments.\n const nodeArguments = parseArgumentTokens(tokens, stringLiteralPlaceholders);\n\n // The arguments of a repeat node are optional. We may have:\n // - No node arguments, in which case the repeat note will iterate indefinitely.\n // - One node argument which will be the explicit number of iterations to make.\n // - Two node arguments which define the min and max iteration bounds from which a random iteration count will be picked.\n if (nodeArguments.length) {\n // All repeat node arguments MUST be of type number and must be integer.\n nodeArguments\n .filter((arg) => arg.type !== \"number\" || !arg.isInteger)\n .forEach(() => {\n throw new Error(`repeat node iteration counts must be integer values`);\n });\n\n // We should have got one or two iteration counts.\n if (nodeArguments.length === 1) {\n // A static iteration count was defined.\n node.iterations = nodeArguments[0].value as number;\n\n // A repeat node must have a positive number of iterations if defined.\n if (node.iterations < 0) {\n throw new Error(\"a repeat node must have a positive number of iterations if defined\");\n }\n } else if (nodeArguments.length === 2) {\n // A minimum and maximum iteration count was defined.\n node.iterations = [nodeArguments[0].value as number, nodeArguments[1].value as number];\n\n // A repeat node must have a positive min and max iteration count if they are defined.\n if (node.iterations[0] < 0 || node.iterations[1] < 0) {\n throw new Error(\"a repeat node must have a positive minimum and maximum iteration count if defined\");\n }\n\n // A repeat node must not have an minimum iteration count that exceeds the maximum iteration count.\n if (node.iterations[0] > node.iterations[1]) {\n throw new Error(\n \"a repeat node must not have a minimum iteration count that exceeds the maximum iteration count\"\n );\n }\n } else {\n // An incorrect number of iteration counts was defined.\n throw new Error(\"invalid number of repeat node iteration count arguments defined\");\n }\n }\n\n // Grab any node attribute definitions and spread them into the node definition.\n node = { ...node, ...parseAttributeTokens(tokens, stringLiteralPlaceholders) };\n\n // This is a decorator node, so we expect an opening '{'.\n popAndCheck(tokens, \"{\");\n\n // Return the repeat node definition.\n return node;\n}\n\n/**\n * Creates a retry node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The retry node JSON definition.\n */\nfunction createRetryNode(tokens: string[], stringLiteralPlaceholders: StringLiteralPlaceholders): RetryNodeDefinition {\n let node = { type: \"retry\" } as RetryNodeDefinition;\n\n // Get the node arguments.\n const nodeArguments = parseArgumentTokens(tokens, stringLiteralPlaceholders);\n\n // The arguments of a retry node are optional. We may have:\n // - No node arguments, in which case the retry note will attempt indefinitely.\n // - One node argument which will be the explicit number of attempts to make.\n // - Two node arguments which define the min and max attempt bounds from which a random attempt count will be picked.\n if (nodeArguments.length) {\n // All retry node arguments MUST be of type number and must be integer.\n nodeArguments\n .filter((arg) => arg.type !== \"number\" || !arg.isInteger)\n .forEach(() => {\n throw new Error(`retry node attempt counts must be integer values`);\n });\n\n // We should have got one or two attempt counts.\n if (nodeArguments.length === 1) {\n // A static attempt count was defined.\n node.attempts = nodeArguments[0].value as number;\n\n // A retry node must have a positive number of attempts if defined.\n if (node.attempts < 0) {\n throw new Error(\"a retry node must have a positive number of attempts if defined\");\n }\n } else if (nodeArguments.length === 2) {\n // A minimum and maximum attempt count was defined.\n node.attempts = [nodeArguments[0].value as number, nodeArguments[1].value as number];\n\n // A retry node must have a positive min and max attempts count if they are defined.\n if (node.attempts[0] < 0 || node.attempts[1] < 0) {\n throw new Error(\"a retry node must have a positive minimum and maximum attempt count if defined\");\n }\n\n // A retry node must not have a minimum attempt count that exceeds the maximum attempt count.\n if (node.attempts[0] > node.attempts[1]) {\n throw new Error(\n \"a retry node must not have a minimum attempt count that exceeds the maximum attempt count\"\n );\n }\n } else {\n // An incorrect number of attempt counts was defined.\n throw new Error(\"invalid number of retry node attempt count arguments defined\");\n }\n }\n\n // Grab any node attribute definitions and spread them into the node definition.\n node = { ...node, ...parseAttributeTokens(tokens, stringLiteralPlaceholders) };\n\n // This is a decorator node, so we expect an opening '{'.\n popAndCheck(tokens, \"{\");\n\n // Return the retry node definition.\n return node;\n}\n\n/**\n * Creates a sequence node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The sequence node JSON definition.\n */\nfunction createSequenceNode(\n tokens: string[],\n stringLiteralPlaceholders: StringLiteralPlaceholders\n): SequenceNodeDefinition {\n const node = {\n type: \"sequence\",\n ...parseAttributeTokens(tokens, stringLiteralPlaceholders)\n } as SequenceNodeDefinition;\n\n // This is a composite node, so we expect an opening '{'.\n popAndCheck(tokens, \"{\");\n\n // Return the sequence node definition.\n return node;\n}\n\n/**\n * Creates a selector node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The selector node JSON definition.\n */\nfunction createSelectorNode(\n tokens: string[],\n stringLiteralPlaceholders: StringLiteralPlaceholders\n): SelectorNodeDefinition {\n const node = {\n type: \"selector\",\n ...parseAttributeTokens(tokens, stringLiteralPlaceholders)\n } as SelectorNodeDefinition;\n\n // This is a composite node, so we expect an opening '{'.\n popAndCheck(tokens, \"{\");\n\n // Return the selector node definition.\n return node;\n}\n\n/**\n * Creates a parallel node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The parallel node JSON definition.\n */\nfunction createParallelNode(\n tokens: string[],\n stringLiteralPlaceholders: StringLiteralPlaceholders\n): ParallelNodeDefinition {\n const node = {\n type: \"parallel\",\n ...parseAttributeTokens(tokens, stringLiteralPlaceholders)\n } as ParallelNodeDefinition;\n\n // This is a composite node, so we expect an opening '{'.\n popAndCheck(tokens, \"{\");\n\n // Return the parallel node definition.\n return node;\n}\n\n/**\n * Creates a lotto node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The lotto node JSON definition.\n */\nfunction createLottoNode(tokens: string[], stringLiteralPlaceholders: StringLiteralPlaceholders): LottoNodeDefinition {\n // If any node arguments have been defined then they must be our weights.\n const nodeArguments = parseArgumentTokens(tokens, stringLiteralPlaceholders);\n\n // All lotto node arguments MUST be of type number and must be positive integers.\n nodeArguments\n .filter((arg) => arg.type !== \"number\" || !arg.isInteger || arg.value < 0)\n .forEach(() => {\n throw new Error(`lotto node weight arguments must be positive integer values`);\n });\n\n const node = {\n type: \"lotto\",\n ...parseAttributeTokens(tokens, stringLiteralPlaceholders)\n } as LottoNodeDefinition;\n\n // Apply the weights if any were defined.\n if (nodeArguments.length) {\n node.weights = nodeArguments.map(({ value }) => value) as number[];\n }\n\n // This is a composite node, so we expect an opening '{'.\n popAndCheck(tokens, \"{\");\n\n // Return the lotto node definition.\n return node;\n}\n\n/**\n * Creates an action node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The action node JSON definition.\n */\nfunction createActionNode(\n tokens: string[],\n stringLiteralPlaceholders: StringLiteralPlaceholders\n): ActionNodeDefinition {\n // Parse any node arguments, we should have at least one which will be an identifier argument for the action name\n // and agent function to invoke for the action, all other arguments are to be passed as arguments to that function.\n const [actionNameIdentifier, ...agentFunctionArgs] = parseArgumentTokens(tokens, stringLiteralPlaceholders);\n\n // Our first argument MUST be defined and be an identifier as we require an action name argument.\n if (actionNameIdentifier?.type !== \"identifier\") {\n throw new Error(\"expected action name identifier argument\");\n }\n\n // Only the first argument should have been an identifier, all agent function arguments must be string, number, boolean or null.\n agentFunctionArgs\n .filter((arg) => arg.type === \"identifier\")\n .forEach((arg) => {\n throw new Error(\n `invalid action node argument value '${arg.value}', must be string, number, boolean or null`\n );\n });\n\n // Return the action node definition.\n return {\n type: \"action\",\n call: actionNameIdentifier.value,\n args: agentFunctionArgs.map(({ value }) => value),\n ...parseAttributeTokens(tokens, stringLiteralPlaceholders)\n };\n}\n\n/**\n * Creates a condition node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The condition node JSON definition.\n */\nfunction createConditionNode(\n tokens: string[],\n stringLiteralPlaceholders: StringLiteralPlaceholders\n): ConditionNodeDefinition {\n // Parse any node arguments, we should have at least one which will be an identifier argument for the condition name\n // and agent function to invoke for the condition, all other arguments are to be passed as arguments to that function.\n const [conditionNameIdentifier, ...agentFunctionArgs] = parseArgumentTokens(tokens, stringLiteralPlaceholders);\n\n // Our first argument MUST be defined and be an identifier as we require a condition name argument.\n if (conditionNameIdentifier?.type !== \"identifier\") {\n throw new Error(\"expected condition name identifier argument\");\n }\n\n // Only the first argument should have been an identifier, all agent function arguments must be string, number, boolean or null.\n agentFunctionArgs\n .filter((arg) => arg.type === \"identifier\")\n .forEach((arg) => {\n throw new Error(\n `invalid condition node argument value '${arg.value}', must be string, number, boolean or null`\n );\n });\n\n // Return the condition node definition.\n return {\n type: \"condition\",\n call: conditionNameIdentifier.value,\n args: agentFunctionArgs.map(({ value }) => value),\n ...parseAttributeTokens(tokens, stringLiteralPlaceholders)\n };\n}\n\n/**\n * Creates a wait node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The wait node JSON definition.\n */\nfunction createWaitNode(tokens: string[], stringLiteralPlaceholders: StringLiteralPlaceholders): WaitNodeDefinition {\n let node = { type: \"wait\" } as WaitNodeDefinition;\n\n // Get the node arguments.\n const nodeArguments = parseArgumentTokens(tokens, stringLiteralPlaceholders);\n\n // The arguments of a wait node are optional. We may have:\n // - No node arguments, in which case the wait will be indefinite until it is aborted.\n // - One node argument which will be the explicit duration of the wait.\n // - Two node arguments which define the min and max duration bounds from which a random duration will be picked.\n if (nodeArguments.length) {\n // All wait node arguments MUST be of type number and must be integer.\n nodeArguments\n .filter((arg) => arg.type !== \"number\" || !arg.isInteger)\n .forEach(() => {\n throw new Error(`wait node durations must be integer values`);\n });\n\n // We may have:\n // - One node argument which will be the explicit duration of the wait.\n // - Two node arguments which define the min and max duration bounds from which a random duration will be picked.\n // - Too many arguments, which is not valid.\n if (nodeArguments.length === 1) {\n // An explicit duration was defined.\n node.duration = nodeArguments[0].value as number;\n\n // If an explict duration was defined then it must be a positive number.\n if (node.duration < 0) {\n throw new Error(\"a wait node must have a positive duration\");\n }\n } else if (nodeArguments.length === 2) {\n // Min and max duration bounds were defined from which a random duration will be picked.\n node.duration = [nodeArguments[0].value as number, nodeArguments[1].value as number];\n\n // A wait node must have a positive min and max duration.\n if (node.duration[0] < 0 || node.duration[1] < 0) {\n throw new Error(\"a wait node must have a positive minimum and maximum duration\");\n }\n\n // A wait node must not have a minimum duration that exceeds the maximum duration.\n if (node.duration[0] > node.duration[1]) {\n throw new Error(\"a wait node must not have a minimum duration that exceeds the maximum duration\");\n }\n } else if (nodeArguments.length > 2) {\n // An incorrect number of duration arguments were defined.\n throw new Error(\"invalid number of wait node duration arguments defined\");\n }\n }\n\n // Return the wait node definition.\n return { ...node, ...parseAttributeTokens(tokens, stringLiteralPlaceholders) };\n}\n\n/**\n * Creates a branch node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The branch node JSON definition.\n */\nfunction createBranchNode(\n tokens: string[],\n stringLiteralPlaceholders: StringLiteralPlaceholders\n): BranchNodeDefinition {\n // Parse any node arguments, we should have one which will be an identifier argument for the root ref.\n const nodeArguments = parseArgumentTokens(tokens, stringLiteralPlaceholders);\n\n // We should have only a single identifer argument for a branch node, which is the root ref.\n if (nodeArguments.length !== 1 || nodeArguments[0].type !== \"identifier\") {\n throw new Error(\"expected single branch name argument\");\n }\n\n // Return the branch node definition.\n return { type: \"branch\", ref: nodeArguments[0].value };\n}\n\n/**\n * Validate a fully-populated node definition that was popped off of the tree stack.\n * @param definition The popped node to validate.\n */\nfunction validatePoppedNode(definition: AnyNodeDefinition): void {\n // Decorators MUST have a child defined.\n if (isDecoratorNode(definition) && isNullOrUndefined(definition.child)) {\n throw new Error(`a ${definition.type} node must have a single child node defined`);\n }\n\n // Composites MUST have at least one child defined.\n if (isCompositeNode(definition) && !definition.children?.length) {\n throw new Error(`a ${definition.type} node must have at least a single child node defined`);\n }\n\n // We need to make sure that lotto nodes that have weights defined have a number of weights matching the number of child nodes.\n if (definition.type === \"lotto\") {\n // Check whether a 'weights' property has been defined, if it has we expect it to be an array of weights.\n if (typeof definition.weights !== \"undefined\") {\n // Check that the weights property is an array of positive integers with an element for each child node element.\n if (definition.weights.length !== definition.children.length) {\n throw new Error(\n \"expected a number of weight arguments matching the number of child nodes for lotto node\"\n );\n }\n }\n }\n}\n", "import { RootNodeDefinition } from \"./BehaviourTreeDefinition\";\nimport { flattenDefinition, isBranchNode, isInteger } from \"./BehaviourTreeDefinitionUtilities\";\nimport { convertMDSLToJSON } from \"./mdsl/MDSLDefinitionParser\";\n\n/**\n * An object representing the result of validating a tree definition.\n */\nexport type DefinitionValidationResult = {\n /**\n * A flag defining whether validation succeeded.\n */\n succeeded: boolean;\n /**\n * A string containing the error message if validation did not succeed.\n */\n errorMessage?: string;\n /**\n * The definition as json if the validation was successful, or undefined if validation did not succeed.\n */\n json?: RootNodeDefinition[];\n};\n\n/**\n * Validates the specified behaviour tree definition in the form of JSON or MDSL, not taking any globally registered subtrees into consideration.\n * @param definition The behaviour tree definition in the form of JSON or MDSL.\n * @returns An object representing the result of validating the given tree definition.\n */\nexport function validateDefinition(definition: any): DefinitionValidationResult {\n // The definition must be defined.\n if (definition === null || typeof definition === \"undefined\") {\n return createValidationFailureResult(\"definition is null or undefined\");\n }\n\n // We are expecting a definition in one of three different forms:\n // - A string which we will assume is MDSL and we will parse this to JSON before validation.\n // - An array which we will assume is an array of root node definitions with at least one being the primary root node (no 'id' property)\n // - An object which we will assume is the primary root node and should not have an 'id' property.\n if (typeof definition === \"string\") {\n // The definition is a string which we can assume is MDSL, so attempt to validate it.\n return validateMDSLDefinition(definition);\n } else if (typeof definition === \"object\") {\n // The definition will either be an array (of root node definitions) or an object (the single primary root node definition).\n return validateJSONDefinition(definition);\n } else {\n return createValidationFailureResult(`unexpected definition type of '${typeof definition}'`);\n }\n}\n\n/**\n * Validates the specified behaviour tree definition in the form of MDSL.\n * @param definition The behaviour tree definition in the form of MDSL.\n * @returns An object representing the result of validating the given tree definition.\n */\nfunction validateMDSLDefinition(definition: string): DefinitionValidationResult {\n let rootNodeDefinitions;\n\n // The first thing the we need to do is to attempt to convert our MDSL into JSON.\n try {\n // The definition is a string which we can assume is MDSL, so attempt to parse it to a JSON definition in the form of an array of root node definitions.\n rootNodeDefinitions = convertMDSLToJSON(definition);\n } catch (exception) {\n // We failed to parse the JSON from the MDSL, this is likely to be the result of it not being a valid MDSL string.\n return createValidationFailureResult((exception as Error).message);\n }\n\n // Unpack all of the root node definitions into arrays of main ('id' defined) and sub ('id' not defined) root node definitions.\n const mainRootNodeDefinitions = rootNodeDefinitions.filter(({ id }) => typeof id === \"undefined\");\n const subRootNodeDefinitions = rootNodeDefinitions.filter(({ id }) => typeof id === \"string\" && id.length > 0);\n\n // We should ALWAYS have exactly one root node definition without an 'id' property defined, which is out main root node definition.\n if (mainRootNodeDefinitions.length !== 1) {\n return createValidationFailureResult(\n \"expected single unnamed root node at base of definition to act as main root\"\n );\n }\n\n // We should never have duplicate 'id' properties across our sub root node definitions.\n const subRootNodeIdenitifers: string[] = [];\n for (const { id } of subRootNodeDefinitions) {\n // Have we already come across this 'id' property value?\n if (subRootNodeIdenitifers.includes(id!)) {\n return createValidationFailureResult(`multiple root nodes found with duplicate name '${id}'`);\n }\n\n subRootNodeIdenitifers.push(id!);\n }\n\n try {\n // Validate our branch -> subtree links and check for any circular dependencies, we don't care about checking for broken subtree links here.\n validateBranchSubtreeLinks(rootNodeDefinitions, false);\n } catch (exception) {\n return createValidationFailureResult((exception as Error).message);\n }\n\n // Our definition was valid!\n return {\n succeeded: true,\n json: rootNodeDefinitions\n };\n}\n\n/**\n * Validates the specified behaviour tree definition in the form of JSON.\n * @param definition The behaviour tree definition in the form of JSON.\n * @returns An object representing the result of validating the given tree definition.\n */\nexport function validateJSONDefinition(\n definition: RootNodeDefinition | RootNodeDefinition[]\n): DefinitionValidationResult {\n // The definition will either be an array (of root node definitions) or an object (the single primary root node definition).\n const rootNodeDefinitions = Array.isArray(definition) ? definition : [definition];\n\n // Iterate over our array of root nodes and call validateNode for each, passing an initial depth of 0, wrapped in a try catch to handle validation failures.\n try {\n rootNodeDefinitions.forEach((rootNodeDefinition) => validateNode(rootNodeDefinition, 0));\n } catch (error) {\n // Handle cases where we have caught a thrown Error and return a failure result with the error message.\n if (error instanceof Error) {\n return createValidationFailureResult(error.message);\n }\n\n // No idea what happened here!\n return createValidationFailureResult(`unexpected error: ${error}`);\n }\n\n // Unpack all of the root node definitions into arrays of main ('id' defined) and sub ('id' not defined) root node definitions.\n const mainRootNodeDefinitions = rootNodeDefinitions.filter(({ id }) => typeof id === \"undefined\");\n const subRootNodeDefinitions = rootNodeDefinitions.filter(({ id }) => typeof id === \"string\" && id.length > 0);\n\n // We should ALWAYS have exactly one root node definition without an 'id' property defined, which is out main root node definition.\n if (mainRootNodeDefinitions.length !== 1) {\n return createValidationFailureResult(\n \"expected single root node without 'id' property defined to act as main root\"\n );\n }\n\n // We should never have duplicate 'id' properties across our sub root node definitions.\n const subRootNodeIdenitifers: string[] = [];\n for (const { id } of subRootNodeDefinitions) {\n // Have we already come across this 'id' property value?\n if (subRootNodeIdenitifers.includes(id!)) {\n return createValidationFailureResult(\n `multiple root nodes found with duplicate 'id' property value of '${id}'`\n );\n }\n\n subRootNodeIdenitifers.push(id!);\n }\n\n try {\n // Validate our branch -> subtree links and check for any circular dependencies, we don't care about checking for broken subtree links here.\n validateBranchSubtreeLinks(rootNodeDefinitions, false);\n } catch (exception) {\n return createValidationFailureResult((exception as Error).message);\n }\n\n // Our definition was valid!\n return {\n succeeded: true,\n json: rootNodeDefinitions\n };\n}\n\n/**\n * Validates the branch -> subtree links across all provided root node definitions.\n * This will not consider branch nodes that reference any globally registered subtrees unless includesGlobalSubtrees\n * is set to true, in which case we will also verify that there are no broken branch -> subtree links.\n * @param rootNodeDefinitions The array of root node definitions.\n * @param includesGlobalSubtrees A flag defining whether the array includes all global subtree root node definitions.\n */\nexport function validateBranchSubtreeLinks(rootNodeDefinitions: RootNodeDefinition[], includesGlobalSubtrees: boolean) {\n // Create a mapping of root node identifiers to other root nodes that they reference via branch nodes.\n // Below is an example of a mapping that includes a circular dependency (root => a => b => c => a)\n // [{ refs: [\"a\", \"b\"] }, { id: \"a\", refs: [\"b\"] }, { id: \"b\", refs: [\"c\"] }, { id: \"c\", refs: [\"a\"] }]\n const rootNodeMappings: { id: string | undefined; refs: string[] }[] = rootNodeDefinitions.map(\n (rootNodeDefinition) => ({\n id: rootNodeDefinition.id,\n refs: flattenDefinition(rootNodeDefinition)\n .filter(isBranchNode)\n .map(({ ref }) => ref)\n })\n );\n\n // A recursive function to walk through the mappings, keeping track of which root nodes we have visited in the form of a path of root node identifiers.\n const followRefs = (mapping: { id: string | undefined; refs: string[] }, path: (string | undefined)[] = []) => {\n // Have we found a circular dependency?\n if (path.includes(mapping.id)) {\n // We found a circular dependency! Get the bad path of root node identifiers.\n const badPath = [...path, mapping.id];\n\n // Create the formatted path value. [undefined, \"a\", \"b\", \"c\", \"a\"] would be formatted as \"a -> b -> c -> a\".\n const badPathFormatted = badPath.filter((element) => !!element).join(\" => \");\n\n // No need to continue, we found a circular dependency.\n throw new Error(`circular dependency found in branch node references: ${badPathFormatted}`);\n }\n\n for (const ref of mapping.refs) {\n // Find the mapping for the root node with an identifer matching the current ref.\n const subMapping = rootNodeMappings.find(({ id }) => id === ref);\n\n // We may not have a mapping for this ref, which is normal when we aren't considering all globally registered subtrees.\n if (subMapping) {\n followRefs(subMapping, [...path, mapping.id]);\n } else if (includesGlobalSubtrees) {\n // We found a reference to a root node that doesn't exist, which is a problem seeing as the root node definitons includes all globally registered subtrees.\n throw new Error(\n mapping.id\n ? `subtree '${mapping.id}' has branch node that references root node '${ref}' which has not been defined`\n : `primary tree has branch node that references root node '${ref}' which has not been defined`\n );\n }\n }\n };\n\n // Start looking for circular dependencies and broken references from the primary root node definition.\n followRefs(rootNodeMappings.find((mapping) => typeof mapping.id === \"undefined\")!);\n}\n\n/**\n * Validate an object that we expect to be a node definition.\n * @param definition An object that we expect to be a node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateNode(definition: any, depth: number): void {\n // Every node must be valid object and have a non-empty 'type' string property.\n if (typeof definition !== \"object\" || typeof definition.type !== \"string\" || definition.type.length === 0) {\n throw new Error(\n `node definition is not an object or 'type' property is not a non-empty string at depth '${depth}'`\n );\n }\n\n // How we validate this node definition will depend on its type.\n switch (definition.type) {\n case \"action\":\n validateActionNode(definition, depth);\n break;\n\n case \"condition\":\n validateConditionNode(definition, depth);\n break;\n\n case \"wait\":\n validateWaitNode(definition, depth);\n break;\n\n case \"branch\":\n validateBranchNode(definition, depth);\n break;\n\n case \"root\":\n validateRootNode(definition, depth);\n break;\n\n case \"succeed\":\n validateSucceedNode(definition, depth);\n break;\n\n case \"fail\":\n validateFailNode(definition, depth);\n break;\n\n case \"flip\":\n validateFlipNode(definition, depth);\n break;\n\n case \"repeat\":\n validateRepeatNode(definition, depth);\n break;\n\n case \"retry\":\n validateRetryNode(definition, depth);\n break;\n\n case \"sequence\":\n validateSequenceNode(definition, depth);\n break;\n\n case \"selector\":\n validateSelectorNode(definition, depth);\n break;\n\n case \"parallel\":\n validateParallelNode(definition, depth);\n break;\n\n case \"lotto\":\n validateLottoNode(definition, depth);\n break;\n\n default:\n throw new Error(`unexpected node type of '${definition.type}' at depth '${depth}'`);\n }\n}\n\n/**\n * Validate any attributes for a given node definition.\n * @param definition The node definition.\n * @param depth The depth of the node in the behaviour tree definition.\n */\nfunction validateNodeAttributes(definition: any, depth: number): void {\n // Validate each of the attribute types for this node.\n [\"while\", \"until\", \"entry\", \"exit\", \"step\"].forEach((attributeName) => {\n // Attempt to grab the definition for the current attribute from the node definition.\n const attributeDefinition = definition[attributeName];\n\n // All node attributes are optional, so there is nothing to do if the current attribute is not defined.\n if (typeof attributeDefinition === \"undefined\") {\n return;\n }\n\n // The attribute definition must be an object.\n if (typeof attributeDefinition !== \"object\") {\n throw new Error(\n `expected attribute '${attributeName}' to be an object for '${definition.type}' node at depth '${depth}'`\n );\n }\n\n // The 'call' property must be defined for any attribute definition.\n if (typeof attributeDefinition.call !== \"string\" || attributeDefinition.call.length === 0) {\n throw new Error(\n `expected 'call' property for attribute '${attributeName}' to be a non-empty string for '${definition.type}' node at depth '${depth}'`\n );\n }\n\n // If any node attribute arguments have been defined then they must have been defined in an array.\n if (typeof attributeDefinition.args !== \"undefined\" && !Array.isArray(attributeDefinition.args)) {\n throw new Error(\n `expected 'args' property for attribute '${attributeName}' to be an array for '${definition.type}' node at depth '${depth}'`\n );\n }\n });\n}\n\n/**\n * Validate an object that we expect to be a root node definition.\n * @param definition An object that we expect to be a root node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateRootNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"root\") {\n throw new Error(\"expected node type of 'root' for root node\");\n }\n\n // A root node cannot be the child of another node.\n if (depth > 0) {\n throw new Error(\"a root node cannot be the child of another node\");\n }\n\n // Check that, if the root node 'id' property is defined, it is a non-empty string.\n if (typeof definition.id !== \"undefined\" && (typeof definition.id !== \"string\" || definition.id.length === 0)) {\n throw new Error(\"expected non-empty string for 'id' property if defined for root node\");\n }\n\n // A root node is a decorator node, so must have a child node defined.\n if (typeof definition.child === \"undefined\") {\n throw new Error(\"expected property 'child' to be defined for root node\");\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n\n // Validate the child node of this decorator node.\n validateNode(definition.child, depth + 1);\n}\n\n/**\n * Validate an object that we expect to be a succeed node definition.\n * @param definition An object that we expect to be a succeed node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateSucceedNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"succeed\") {\n throw new Error(`expected node type of 'succeed' for succeed node at depth '${depth}'`);\n }\n\n // A succeed node is a decorator node, so must have a child node defined.\n if (typeof definition.child === \"undefined\") {\n throw new Error(`expected property 'child' to be defined for succeed node at depth '${depth}'`);\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n\n // Validate the child node of this decorator node.\n validateNode(definition.child, depth + 1);\n}\n\n/**\n * Validate an object that we expect to be a fail node definition.\n * @param definition An object that we expect to be a fail node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateFailNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"fail\") {\n throw new Error(`expected node type of 'fail' for fail node at depth '${depth}'`);\n }\n\n // A fail node is a decorator node, so must have a child node defined.\n if (typeof definition.child === \"undefined\") {\n throw new Error(`expected property 'child' to be defined for fail node at depth '${depth}'`);\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n\n // Validate the child node of this decorator node.\n validateNode(definition.child, depth + 1);\n}\n\n/**\n * Validate an object that we expect to be a flip node definition.\n * @param definition An object that we expect to be a flip node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateFlipNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"flip\") {\n throw new Error(`expected node type of 'flip' for flip node at depth '${depth}'`);\n }\n\n // A flip node is a decorator node, so must have a child node defined.\n if (typeof definition.child === \"undefined\") {\n throw new Error(`expected property 'child' to be defined for flip node at depth '${depth}'`);\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n\n // Validate the child node of this decorator node.\n validateNode(definition.child, depth + 1);\n}\n\n/**\n * Validate an object that we expect to be a repeat node definition.\n * @param definition An object that we expect to be a repeat node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateRepeatNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"repeat\") {\n throw new Error(`expected node type of 'repeat' for repeat node at depth '${depth}'`);\n }\n\n // A repeat node is a decorator node, so must have a child node defined.\n if (typeof definition.child === \"undefined\") {\n throw new Error(`expected property 'child' to be defined for repeat node at depth '${depth}'`);\n }\n\n // Check whether an 'iterations' property has been defined, it may not have been if this node is to repeat indefinitely.\n if (typeof definition.iterations !== \"undefined\") {\n if (Array.isArray(definition.iterations)) {\n // Check whether any elements of the array are not integer values.\n const containsNonInteger = !!definition.iterations.filter((value: unknown) => !isInteger(value)).length;\n\n // If the 'iterations' property is an array then it MUST contain two integer values.\n if (definition.iterations.length !== 2 || containsNonInteger) {\n throw new Error(\n `expected array containing two integer values for 'iterations' property if defined for repeat node at depth '${depth}'`\n );\n }\n\n // A repeat node must have a positive min and max iterations count if they are defined.\n if (definition.iterations[0] < 0 || definition.iterations[1] < 0) {\n throw new Error(\n `expected positive minimum and maximum iterations count for 'iterations' property if defined for repeat node at depth '${depth}'`\n );\n }\n\n // A repeat node must not have a minimum iterations count that exceeds the maximum iterations count.\n if (definition.iterations[0] > definition.iterations[1]) {\n throw new Error(\n `expected minimum iterations count that does not exceed the maximum iterations count for 'iterations' property if defined for repeat node at depth '${depth}'`\n );\n }\n } else if (isInteger(definition.iterations)) {\n // A repeat node must have a positive number of iterations if defined.\n if (definition.iterations < 0) {\n throw new Error(\n `expected positive iterations count for 'iterations' property if defined for repeat node at depth '${depth}'`\n );\n }\n } else {\n throw new Error(\n `expected integer value or array containing two integer values for 'iterations' property if defined for repeat node at depth '${depth}'`\n );\n }\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n\n // Validate the child node of this decorator node.\n validateNode(definition.child, depth + 1);\n}\n\n/**\n * Validate an object that we expect to be a retry node definition.\n * @param definition An object that we expect to be a retry node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateRetryNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"retry\") {\n throw new Error(`expected node type of 'retry' for retry node at depth '${depth}'`);\n }\n\n // A retry node is a decorator node, so must have a child node defined.\n if (typeof definition.child === \"undefined\") {\n throw new Error(`expected property 'child' to be defined for retry node at depth '${depth}'`);\n }\n\n // Check whether an 'attempts' property has been defined, it may not have been if this node is to retry indefinitely.\n if (typeof definition.attempts !== \"undefined\") {\n if (Array.isArray(definition.attempts)) {\n // Check whether any elements of the array are not integer values.\n const containsNonInteger = !!definition.attempts.filter((value: unknown) => !isInteger(value)).length;\n\n // If the 'attempts' property is an array then it MUST contain two integer values.\n if (definition.attempts.length !== 2 || containsNonInteger) {\n throw new Error(\n `expected array containing two integer values for 'attempts' property if defined for retry node at depth '${depth}'`\n );\n }\n\n // A retry node must have a positive min and max attempts count if they are defined.\n if (definition.attempts[0] < 0 || definition.attempts[1] < 0) {\n throw new Error(\n `expected positive minimum and maximum attempts count for 'attempts' property if defined for retry node at depth '${depth}'`\n );\n }\n\n // A retry node must not have a minimum attempts count that exceeds the maximum attempts count.\n if (definition.attempts[0] > definition.attempts[1]) {\n throw new Error(\n `expected minimum attempts count that does not exceed the maximum attempts count for 'attempts' property if defined for retry node at depth '${depth}'`\n );\n }\n } else if (isInteger(definition.attempts)) {\n // A retry node must have a positive number of attempts if defined.\n if (definition.attempts < 0) {\n throw new Error(\n `expected positive attempts count for 'attempts' property if defined for retry node at depth '${depth}'`\n );\n }\n } else {\n throw new Error(\n `expected integer value or array containing two integer values for 'attempts' property if defined for retry node at depth '${depth}'`\n );\n }\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n\n // Validate the child node of this decorator node.\n validateNode(definition.child, depth + 1);\n}\n\n/**\n * Validate an object that we expect to be a branch node definition.\n * @param definition An object that we expect to be a branch node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateBranchNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"branch\") {\n throw new Error(`expected node type of 'branch' for branch node at depth '${depth}'`);\n }\n\n // Check that the branch node 'ref' property is defined and is a non-empty string.\n if (typeof definition.ref !== \"string\" || definition.ref.length === 0) {\n throw new Error(`expected non-empty string for 'ref' property for branch node at depth '${depth}'`);\n }\n\n // It is invalid to define guard attributes for a branch node as they should be defined on the referenced root node.\n [\"while\", \"until\"].forEach((attributeName) => {\n if (typeof definition[attributeName] !== \"undefined\") {\n throw new Error(\n `guards should not be defined for branch nodes but guard '${attributeName}' was defined for branch node at depth '${depth}'`\n );\n }\n });\n\n // It is invalid to define callback attributes for a branch node as they should be defined on the referenced root node.\n [\"entry\", \"exit\", \"step\"].forEach((attributeName) => {\n if (typeof definition[attributeName] !== \"undefined\") {\n throw new Error(\n `callbacks should not be defined for branch nodes but callback '${attributeName}' was defined for branch node at depth '${depth}'`\n );\n }\n });\n}\n\n/**\n * Validate an object that we expect to be a action node definition.\n * @param definition An object that we expect to be a action node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateActionNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"action\") {\n throw new Error(`expected node type of 'action' for action node at depth '${depth}'`);\n }\n\n // The 'call' property must be defined for a action node definition.\n if (typeof definition.call !== \"string\" || definition.call.length === 0) {\n throw new Error(`expected non-empty string for 'call' property of action node at depth '${depth}'`);\n }\n\n // If any action function arguments have been defined then they must have been defined in an array.\n if (typeof definition.args !== \"undefined\" && !Array.isArray(definition.args)) {\n throw new Error(`expected array for 'args' property if defined for action node at depth '${depth}'`);\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n}\n\n/**\n * Validate an object that we expect to be a condition node definition.\n * @param definition An object that we expect to be a condition node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateConditionNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"condition\") {\n throw new Error(`expected node type of 'condition' for condition node at depth '${depth}'`);\n }\n\n // The 'call' property must be defined for a condition node definition.\n if (typeof definition.call !== \"string\" || definition.call.length === 0) {\n throw new Error(`expected non-empty string for 'call' property of condition node at depth '${depth}'`);\n }\n\n // If any condition function arguments have been defined then they must have been defined in an array.\n if (typeof definition.args !== \"undefined\" && !Array.isArray(definition.args)) {\n throw new Error(`expected array for 'args' property if defined for condition node at depth '${depth}'`);\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n}\n\n/**\n * Validate an object that we expect to be a wait node definition.\n * @param definition An object that we expect to be a wait node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateWaitNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"wait\") {\n throw new Error(`expected node type of 'wait' for wait node at depth '${depth}'`);\n }\n\n // Check whether a 'duration' property has been defined, it may not have been if this node is to wait indefinitely.\n if (typeof definition.duration !== \"undefined\") {\n if (Array.isArray(definition.duration)) {\n // Check whether any elements of the array are not integer values.\n const containsNonInteger = !!definition.duration.filter((value: unknown) => !isInteger(value)).length;\n\n // If the 'duration' property is an array then it MUST contain two integer values.\n if (definition.duration.length !== 2 || containsNonInteger) {\n throw new Error(\n `expected array containing two integer values for 'duration' property if defined for wait node at depth '${depth}'`\n );\n }\n\n // A wait node must have a positive min and max duration value if they are defined.\n if (definition.duration[0] < 0 || definition.duration[1] < 0) {\n throw new Error(\n `expected positive minimum and maximum duration for 'duration' property if defined for wait node at depth '${depth}'`\n );\n }\n\n // A wait node must not have a minimum duration value that exceeds the maximum duration value.\n if (definition.duration[0] > definition.duration[1]) {\n throw new Error(\n `expected minimum duration value that does not exceed the maximum duration value for 'duration' property if defined for wait node at depth '${depth}'`\n );\n }\n } else if (isInteger(definition.duration)) {\n // A wait node must have a positive duration value if defined.\n if (definition.duration < 0) {\n throw new Error(\n `expected positive duration value for 'duration' property if defined for wait node at depth '${depth}'`\n );\n }\n } else {\n throw new Error(\n `expected integer value or array containing two integer values for 'duration' property if defined for wait node at depth '${depth}'`\n );\n }\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n}\n\n/**\n * Validate an object that we expect to be a sequence node definition.\n * @param definition An object that we expect to be a sequence node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateSequenceNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"sequence\") {\n throw new Error(`expected node type of 'sequence' for sequence node at depth '${depth}'`);\n }\n\n // A sequence node is a composite node, so must have a children nodes array defined.\n if (!Array.isArray(definition.children) || definition.children.length === 0) {\n throw new Error(`expected non-empty 'children' array to be defined for sequence node at depth '${depth}'`);\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n\n // Validate the child nodes of this composite node.\n definition.children.forEach((child: any) => validateNode(child, depth + 1));\n}\n\n/**\n * Validate an object that we expect to be a selector node definition.\n * @param definition An object that we expect to be a selector node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateSelectorNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"selector\") {\n throw new Error(`expected node type of 'selector' for selector node at depth '${depth}'`);\n }\n\n // A selector node is a composite node, so must have a children nodes array defined.\n if (!Array.isArray(definition.children) || definition.children.length === 0) {\n throw new Error(`expected non-empty 'children' array to be defined for selector node at depth '${depth}'`);\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n\n // Validate the child nodes of this composite node.\n definition.children.forEach((child: any) => validateNode(child, depth + 1));\n}\n\n/**\n * Validate an object that we expect to be a parallel node definition.\n * @param definition An object that we expect to be a parallel node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateParallelNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"parallel\") {\n throw new Error(`expected node type of 'parallel' for parallel node at depth '${depth}'`);\n }\n\n // A parallel node is a composite node, so must have a children nodes array defined.\n if (!Array.isArray(definition.children) || definition.children.length === 0) {\n throw new Error(`expected non-empty 'children' array to be defined for parallel node at depth '${depth}'`);\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n\n // Validate the child nodes of this composite node.\n definition.children.forEach((child: any) => validateNode(child, depth + 1));\n}\n\n/**\n * Validate an object that we expect to be a lotto node definition.\n * @param definition An object that we expect to be a lotto node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateLottoNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"lotto\") {\n throw new Error(`expected node type of 'lotto' for lotto node at depth '${depth}'`);\n }\n\n // A lotto node is a composite node, so must have a children nodes array defined.\n if (!Array.isArray(definition.children) || definition.children.length === 0) {\n throw new Error(`expected non-empty 'children' array to be defined for lotto node at depth '${depth}'`);\n }\n\n // Check whether a 'weights' property has been defined, if it has we expect it to be an array of weights.\n if (typeof definition.weights !== \"undefined\") {\n // Check that the weights property is an array of positive integers with an element for each child node element.\n if (\n !Array.isArray(definition.weights) ||\n definition.weights.length !== definition.children.length ||\n definition.weights.filter((value: unknown) => !isInteger(value)).length ||\n definition.weights.filter((value: number) => value < 0).length\n ) {\n throw new Error(\n `expected an array of positive integer weight values with a length matching the number of child nodes for 'weights' property if defined for lotto node at depth '${depth}'`\n );\n }\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n\n // Validate the child nodes of this composite node.\n definition.children.forEach((child: any) => validateNode(child, depth + 1));\n}\n\n/**\n * A helper function to create a failure validation result with the given error message.\n * @param errorMessage The validation failure error message.\n * @returns A failure validation result with the given error message.\n */\nfunction createValidationFailureResult(errorMessage: string): DefinitionValidationResult {\n return { succeeded: false, errorMessage };\n}\n", "import { ActionResult, Agent, GlobalFunction } from \"./Agent\";\nimport { RootNodeDefinition } from \"./BehaviourTreeDefinition\";\n\nexport type InvokerFunction = (args: any[]) => ActionResult | boolean;\n\n/**\n * A singleton used to store and lookup registered functions and subtrees.\n */\nexport default class Lookup {\n /**\n * The object holding any registered functions keyed on function name.\n */\n private static registeredFunctions: { [key: string]: GlobalFunction } = {};\n /**\n * The object holding any registered subtree root node definitions keyed on tree name.\n */\n private static registeredSubtrees: { [key: string]: RootNodeDefinition } = {};\n\n /**\n * Gets the function with the specified name.\n * @param name The name of the function.\n * @returns The function with the specified name.\n */\n public static getFunc(name: string): GlobalFunction {\n return this.registeredFunctions[name];\n }\n\n /**\n * Sets the function with the specified name for later lookup.\n * @param name The name of the function.\n * @param func The function.\n */\n public static setFunc(name: string, func: GlobalFunction): void {\n this.registeredFunctions[name] = func;\n }\n\n /**\n * Gets the function invoker for the specified agent and function name.\n * If a function with the specified name exists on the agent object then it will\n * be returned, otherwise we will then check the registered functions for a match.\n * @param agent The agent instance that this behaviour tree is modelling behaviour for.\n * @param name The function name.\n * @returns The function invoker for the specified agent and function name.\n */\n static getFuncInvoker(agent: Agent, name: string): InvokerFunction | null {\n // Check whether the agent contains the specified function.\n const agentFunction = agent[name];\n if (agentFunction && typeof agentFunction === \"function\") {\n return (args: any[]) => agentFunction.apply(agent, args);\n }\n\n // The agent does not contain the specified function but it may have been registered at some point.\n if (this.registeredFunctions[name] && typeof this.registeredFunctions[name] === \"function\") {\n const registeredFunction = this.registeredFunctions[name];\n return (args: any[]) => registeredFunction(agent, ...args.map((arg) => arg.value));\n }\n\n // We have no function to invoke.\n return null;\n }\n\n /**\n * Gets all registered subtree root node definitions.\n */\n static getSubtrees(): { [key: string]: RootNodeDefinition } {\n return this.registeredSubtrees;\n }\n\n /**\n * Sets the subtree with the specified name for later lookup.\n * @param name The name of the subtree.\n * @param subtree The subtree.\n */\n static setSubtree(name: string, subtree: RootNodeDefinition) {\n this.registeredSubtrees[name] = subtree;\n }\n\n /**\n * Removes the registered function or subtree with the specified name.\n * @param name The name of the registered function or subtree.\n */\n static remove(name: string) {\n delete this.registeredFunctions[name];\n delete this.registeredSubtrees[name];\n }\n\n /**\n * Remove all registered functions and subtrees.\n */\n static empty() {\n this.registeredFunctions = {};\n this.registeredSubtrees = {};\n }\n}\n", "import Node from \"../../nodes/Node\";\n\n/**\n * An exception thrown when evaluating node guard path conditions and a conditions fails.\n */\nexport default class GuardUnsatisifedException extends Error {\n /**\n * @param source The node at which a guard condition failed.\n */\n constructor(private source: Node) {\n super(\"A guard path condition has failed\");\n }\n\n /**\n * Gets whether the specified node is the node at which a guard condition failed.\n * @param node The node to check against the source node.\n * @returns Whether the specified node is the node at which a guard condition failed.\n */\n isSourceNode = (node: Node) => node === this.source;\n}\n", "import { Agent } from \"../../Agent\";\nimport Guard from \"./Guard\";\nimport Node from \"../../nodes/Node\";\nimport GuardUnsatisifedException from \"./GuardUnsatisifedException\";\n\nexport type GuardPathPart = {\n node: Node;\n guards: Guard[];\n};\n\n/**\n * Represents a path of node guards along a root-to-leaf tree path.\n */\nexport default class GuardPath {\n /**\n * @param nodes An array of objects defining a node instance -> guard link, ordered by node depth.\n */\n constructor(private nodes: GuardPathPart[]) {}\n\n /**\n * Evaluate guard conditions for all guards in the tree path, moving outwards from the root.\n * @param agent The agent, required for guard evaluation.\n * @returns An evaluation results object.\n */\n evaluate = (agent: Agent) => {\n // We need to evaluate guard conditions for nodes up the tree, moving outwards from the root.\n for (const details of this.nodes) {\n // There can be multiple guards per node.\n for (const guard of details.guards) {\n // Check whether the guard condition passes, and throw an exception if not.\n if (!guard.isSatisfied(agent)) {\n throw new GuardUnsatisifedException(details.node);\n }\n }\n }\n };\n}\n", "import { BehaviourTreeOptions } from \"../BehaviourTreeOptions\";\nimport State, { AnyState } from \"../State\";\nimport { Agent } from \"../Agent\";\nimport Leaf from \"./leaf/Leaf\";\nimport Attribute from \"../attributes/Attribute\";\nimport Entry from \"../attributes/callbacks/Entry\";\nimport Exit from \"../attributes/callbacks/Exit\";\nimport Step from \"../attributes/callbacks/Step\";\nimport Guard from \"../attributes/guards/Guard\";\nimport GuardPath from \"../attributes/guards/GuardPath\";\nimport GuardUnsatisifedException from \"../attributes/guards/GuardUnsatisifedException\";\n\n/**\n * A base node.\n */\nexport default abstract class Node {\n /**\n * The node uid.\n */\n private readonly uid: string = createNodeUid();\n /**\n * The node state.\n */\n private state: AnyState = State.READY;\n /**\n * The guard path to evaluate as part of a node update.\n */\n private guardPath: GuardPath | undefined;\n\n /**\n * @param type The node type.\n * @param attributes The node attributes.\n * @param args The node argument definitions.\n */\n constructor(private type: string, private attributes: Attribute[], private args: any[]) {}\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected abstract onUpdate(agent: Agent, options: BehaviourTreeOptions): void;\n\n /**\n * Gets the name of the node.\n */\n public abstract getName(): string;\n\n /**\n * Gets whether this node is a leaf node.\n */\n public abstract isLeafNode: () => this is Leaf;\n\n /**\n * Gets/Sets the state of the node.\n */\n getState = (): AnyState => this.state;\n setState = (value: AnyState): void => {\n this.state = value;\n };\n\n /**\n * Gets the unique id of the node.\n */\n getUid = () => this.uid;\n\n /**\n * Gets the type of the node.\n */\n getType = () => this.type;\n\n /**\n * Gets the node attributes.\n */\n getAttributes = () => this.attributes;\n\n /**\n * Gets the node arguments.\n */\n getArguments = () => this.args;\n\n /**\n * Gets the node attribute with the specified type, or null if it does not exist.\n */\n getAttribute(type: \"entry\" | \"ENTRY\"): Entry;\n getAttribute(type: \"exit\" | \"EXIT\"): Exit;\n getAttribute(type: \"step\" | \"STEP\"): Step;\n getAttribute(type: string): Attribute {\n return (\n this.getAttributes().filter((decorator) => decorator.type.toUpperCase() === type.toUpperCase())[0] || null\n );\n }\n\n /**\n * Gets the node attributes.\n */\n getGuardAttributes = (): Guard[] => this.getAttributes().filter((decorator) => decorator.isGuard()) as Guard[];\n\n /**\n * Sets the guard path to evaluate as part of a node update.\n */\n setGuardPath = (value: GuardPath) => (this.guardPath = value);\n\n /**\n * Gets whether a guard path is assigned to this node.\n */\n hasGuardPath = () => !!this.guardPath;\n\n /**\n * Gets whether this node is in the specified state.\n * @param value The value to compare to the node state.\n */\n public is(value: AnyState): boolean {\n return this.state === value;\n }\n\n /**\n * Reset the state of the node.\n */\n public reset(): void {\n this.setState(State.READY);\n }\n\n /**\n * Abort the running of this node.\n * @param agent The agent.\n */\n public abort(agent: Agent): void {\n // There is nothing to do if this node is not in the running state.\n if (!this.is(State.RUNNING)) {\n return;\n }\n\n // Reset the state of this node.\n this.reset();\n\n this.getAttribute(\"exit\")?.callAgentFunction(agent, false, true);\n }\n\n /**\n * Update the node.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n * @returns The result of the update.\n */\n public update(agent: Agent, options: BehaviourTreeOptions): void {\n // If this node is already in a 'SUCCEEDED' or 'FAILED' state then there is nothing to do.\n if (this.is(State.SUCCEEDED) || this.is(State.FAILED)) {\n return;\n }\n\n try {\n // Evaluate all of the guard path conditions for the current tree path.\n this.guardPath!.evaluate(agent);\n\n // If this node is in the READY state then call the ENTRY for this node if it exists.\n if (this.is(State.READY)) {\n this.getAttribute(\"entry\")?.callAgentFunction(agent);\n }\n\n this.getAttribute(\"step\")?.callAgentFunction(agent);\n\n // Do the actual update.\n this.onUpdate(agent, options);\n\n // If this node is now in a 'SUCCEEDED' or 'FAILED' state then call the EXIT for this node if it exists.\n if (this.is(State.SUCCEEDED) || this.is(State.FAILED)) {\n this.getAttribute(\"exit\")?.callAgentFunction(agent, this.is(State.SUCCEEDED), false);\n }\n } catch (error) {\n // If the error is a GuardUnsatisfiedException then we need to determine if this node is the source.\n if (error instanceof GuardUnsatisifedException && error.isSourceNode(this)) {\n // Abort the current node.\n this.abort(agent);\n\n // Any node that is the source of an abort will be a failed node.\n this.setState(State.FAILED);\n } else {\n throw error;\n }\n }\n }\n}\n\n/**\n * Create a randomly generated node uid.\n * @returns A randomly generated node uid.\n */\nfunction createNodeUid(): string {\n var S4 = function () {\n return (((1 + Math.random()) * 0x10000) | 0).toString(16).substring(1);\n };\n return S4() + S4() + \"-\" + S4() + \"-\" + S4() + \"-\" + S4() + \"-\" + S4() + S4() + S4();\n}\n", "import Node from \"../Node\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\n\n/**\n * A composite node that wraps child nodes.\n */\nexport default abstract class Composite extends Node {\n /**\n * @param type The node type.\n * @param attributes The node attributes.\n * @param children The child nodes.\n */\n constructor(type: string, attributes: Attribute[], protected children: Node[]) {\n super(type, attributes, []);\n }\n\n /**\n * Gets whether this node is a leaf node.\n */\n isLeafNode = () => false;\n\n /**\n * Gets the children of this node.\n */\n getChildren = () => this.children;\n\n /**\n * Reset the state of the node.\n */\n reset = () => {\n // Reset the state of this node.\n this.setState(State.READY);\n\n // Reset the state of any child nodes.\n this.getChildren().forEach((child) => child.reset());\n };\n\n /**\n * Abort the running of this node.\n * @param agent The agent.\n */\n abort = (agent: Agent) => {\n // There is nothing to do if this node is not in the running state.\n if (!this.is(State.RUNNING)) {\n return;\n }\n\n // Abort any child nodes.\n this.getChildren().forEach((child) => child.abort(agent));\n\n // Reset the state of this node.\n this.reset();\n\n this.getAttribute(\"exit\")?.callAgentFunction(agent, false, true);\n };\n}\n", "import Composite from \"./Composite\";\nimport State from \"../../State\";\nimport Node from \"../Node\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A PARALLEL node.\n * The child nodes are executed concurrently until one fails or all succeed.\n */\nexport default class Parallel extends Composite {\n /**\n * @param attributes The node attributes.\n * @param children The child nodes.\n */\n constructor(attributes: Attribute[], children: Node[]) {\n super(\"parallel\", attributes, children);\n }\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // Keep a count of the number of succeeded child nodes.\n let succeededCount = 0;\n\n let hasChildFailed = false;\n\n // Iterate over all of the children of this node.\n for (const child of this.children) {\n // If the child has never been updated or is running then we will need to update it now.\n if (child.getState() === State.READY || child.getState() === State.RUNNING) {\n // Update the child of this node.\n child.update(agent, options);\n }\n\n // If the current child has a state of 'SUCCEEDED' then we should move on to the next child.\n if (child.getState() === State.SUCCEEDED) {\n // The child node has succeeded, keep track of this to determine if all children have.\n succeededCount++;\n\n // The child node succeeded, but we have not finished checking every child node yet.\n continue;\n }\n\n // If the current child has a state of 'FAILED' then this node is also a 'FAILED' node.\n if (child.getState() === State.FAILED) {\n hasChildFailed = true;\n\n // There is no need to check the rest of the children.\n break;\n }\n\n // The node should be in the 'RUNNING' state.\n if (child.getState() !== State.RUNNING) {\n // The child node was not in an expected state.\n throw new Error(\"child node was not in an expected state.\");\n }\n }\n\n if (hasChildFailed) {\n // This node is a 'FAILED' node.\n this.setState(State.FAILED);\n\n // Abort every running child.\n for (const child of this.children) {\n if (child.getState() === State.RUNNING) {\n child.abort(agent);\n }\n }\n } else {\n // If all children have succeeded then this node has also succeeded, otherwise it is still running.\n this.setState(succeededCount === this.children.length ? State.SUCCEEDED : State.RUNNING);\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => \"PARALLEL\";\n}\n", "import Composite from \"./Composite\";\nimport Node from \"../Node\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A SELECTOR node.\n * The child nodes are executed in sequence until one succeeds or all fail.\n */\nexport default class Selector extends Composite {\n /**\n * @param attributes The node attributes.\n * @param children The child nodes.\n */\n constructor(attributes: Attribute[], protected children: Node[]) {\n super(\"selector\", attributes, children);\n }\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // Iterate over all of the children of this node.\n for (const child of this.children) {\n // If the child has never been updated or is running then we will need to update it now.\n if (child.getState() === State.READY || child.getState() === State.RUNNING) {\n // Update the child of this node.\n child.update(agent, options);\n }\n\n // If the current child has a state of 'SUCCEEDED' then this node is also a 'SUCCEEDED' node.\n if (child.getState() === State.SUCCEEDED) {\n // This node is a 'SUCCEEDED' node.\n this.setState(State.SUCCEEDED);\n\n // There is no need to check the rest of the selector nodes.\n return;\n }\n\n // If the current child has a state of 'FAILED' then we should move on to the next child.\n if (child.getState() === State.FAILED) {\n // Find out if the current child is the last one in the selector.\n // If it is then this sequence node has also failed.\n if (this.children.indexOf(child) === this.children.length - 1) {\n // This node is a 'FAILED' node.\n this.setState(State.FAILED);\n\n // There is no need to check the rest of the selector as we have completed it.\n return;\n } else {\n // The child node failed, try the next one.\n continue;\n }\n }\n\n // The node should be in the 'RUNNING' state.\n if (child.getState() === State.RUNNING) {\n // This node is a 'RUNNING' node.\n this.setState(State.RUNNING);\n\n // There is no need to check the rest of the selector as the current child is still running.\n return;\n }\n\n // The child node was not in an expected state.\n throw new Error(\"child node was not in an expected state.\");\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => \"SELECTOR\";\n}\n", "import Composite from \"./Composite\";\nimport Node from \"../Node\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A SEQUENCE node.\n * The child nodes are executed in sequence until one fails or all succeed.\n */\nexport default class Sequence extends Composite {\n /**\n * @param attributes The node attributes.\n * @param children The child nodes.\n */\n constructor(attributes: Attribute[], protected children: Node[]) {\n super(\"sequence\", attributes, children);\n }\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // Iterate over all of the children of this node.\n for (const child of this.children) {\n // If the child has never been updated or is running then we will need to update it now.\n if (child.getState() === State.READY || child.getState() === State.RUNNING) {\n // Update the child of this node.\n child.update(agent, options);\n }\n\n // If the current child has a state of 'SUCCEEDED' then we should move on to the next child.\n if (child.getState() === State.SUCCEEDED) {\n // Find out if the current child is the last one in the sequence.\n // If it is then this sequence node has also succeeded.\n if (this.children.indexOf(child) === this.children.length - 1) {\n // This node is a 'SUCCEEDED' node.\n this.setState(State.SUCCEEDED);\n\n // There is no need to check the rest of the sequence as we have completed it.\n return;\n } else {\n // The child node succeeded, but we have not finished the sequence yet.\n continue;\n }\n }\n\n // If the current child has a state of 'FAILED' then this node is also a 'FAILED' node.\n if (child.getState() === State.FAILED) {\n // This node is a 'FAILED' node.\n this.setState(State.FAILED);\n\n // There is no need to check the rest of the sequence.\n return;\n }\n\n // The node should be in the 'RUNNING' state.\n if (child.getState() === State.RUNNING) {\n // This node is a 'RUNNING' node.\n this.setState(State.RUNNING);\n\n // There is no need to check the rest of the sequence as the current child is still running.\n return;\n }\n\n // The child node was not in an expected state.\n throw new Error(\"child node was not in an expected state.\");\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => \"SEQUENCE\";\n}\n", "import createLotto from \"lotto-draw\";\n\nimport Node from \"../Node\";\nimport Composite from \"./Composite\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A LOTTO node.\n * A winning child is picked on the initial update of this node, based on ticket weighting.\n * The state of this node will match the state of the winning child.\n */\nexport default class Lotto extends Composite {\n /**\n * @param attributes The node attributes.\n * @param weights The child node weights.\n * @param children The child nodes.\n */\n constructor(attributes: Attribute[], private weights: number[] | undefined, children: Node[]) {\n super(\"lotto\", attributes, children);\n }\n\n /**\n * The child node selected to be the active one.\n */\n private selectedChild: Node | undefined;\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // If this node is in the READY state then we need to pick a winning child node.\n if (this.is(State.READY)) {\n // Create a lotto draw with which to randomly pick a child node to become the active one.\n const lottoDraw = createLotto({\n // Hook up the optional 'random' behaviour tree function option to the one used by 'lotto-draw'.\n random: options.random,\n // Pass in each child node as a participant in the lotto draw with their respective ticket count.\n participants: this.children.map((child, index) => [child, this.weights?.[index] || 1])\n });\n\n // Randomly pick a child based on ticket weighting, this will become the active child for this composite node.\n this.selectedChild = lottoDraw.draw() || undefined;\n }\n\n // If something went wrong and we don't have an active child then we should throw an error.\n if (!this.selectedChild) {\n throw new Error(\"failed to update lotto node as it has no active child\");\n }\n\n // If the selected child has never been updated or is running then we will need to update it now.\n if (this.selectedChild.getState() === State.READY || this.selectedChild.getState() === State.RUNNING) {\n this.selectedChild.update(agent, options);\n }\n\n // The state of the lotto node is the state of its selected child.\n this.setState(this.selectedChild.getState());\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => (this.weights ? `LOTTO [${this.weights.join(\",\")}]` : \"LOTTO\");\n}\n", "import Node from \"../Node\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\n\n/**\n * A decorator node that wraps a single child node.\n */\nexport default abstract class Decorator extends Node {\n /**\n * @param type The node type.\n * @param attributes The node attributes.\n * @param child The child node.\n */\n constructor(type: string, attributes: Attribute[], protected child: Node) {\n super(type, attributes, []);\n }\n\n /**\n * Gets whether this node is a leaf node.\n */\n isLeafNode = () => false;\n\n /**\n * Gets the children of this node.\n */\n getChildren = () => [this.child];\n\n /**\n * Reset the state of the node.\n */\n reset = () => {\n // Reset the state of this node.\n this.setState(State.READY);\n\n // Reset the state of the child node.\n this.child.reset();\n };\n\n /**\n * Abort the running of this node.\n * @param agent The agent.\n */\n abort = (agent: Agent) => {\n // There is nothing to do if this node is not in the running state.\n if (!this.is(State.RUNNING)) {\n return;\n }\n\n // Abort the child node.\n this.child.abort(agent);\n\n // Reset the state of this node.\n this.reset();\n\n this.getAttribute(\"exit\")?.callAgentFunction(agent, false, true);\n };\n}\n", "import Node from \"../Node\";\nimport Decorator from \"./Decorator\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A Fail node.\n * This node wraps a single child and will always move to the 'FAILED' state when the child moves to a 'SUCCEEDED' or 'FAILED' state.\n */\nexport default class Fail extends Decorator {\n /**\n * @param attributes The node attributes.\n * @param child The child node.\n */\n constructor(attributes: Attribute[], child: Node) {\n super(\"fail\", attributes, child);\n }\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // If the child has never been updated or is running then we will need to update it now.\n if (this.child.getState() === State.READY || this.child.getState() === State.RUNNING) {\n this.child.update(agent, options);\n }\n\n // The state of this node will depend in the state of its child.\n switch (this.child.getState()) {\n case State.RUNNING:\n this.setState(State.RUNNING);\n break;\n\n case State.SUCCEEDED:\n case State.FAILED:\n this.setState(State.FAILED);\n break;\n\n default:\n this.setState(State.READY);\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => \"FAIL\";\n}\n", "import Decorator from \"./Decorator\";\nimport State from \"../../State\";\nimport Node from \"../Node\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A Flip node.\n * This node wraps a single child and will flip the state of the child state.\n */\nexport default class Flip extends Decorator {\n /**\n * @param attributes The node attributes.\n * @param child The child node.\n */\n constructor(attributes: Attribute[], child: Node) {\n super(\"flip\", attributes, child);\n }\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // If the child has never been updated or is running then we will need to update it now.\n if (this.child.getState() === State.READY || this.child.getState() === State.RUNNING) {\n this.child.update(agent, options);\n }\n\n // The state of this node will depend in the state of its child.\n switch (this.child.getState()) {\n case State.RUNNING:\n this.setState(State.RUNNING);\n break;\n\n case State.SUCCEEDED:\n this.setState(State.FAILED);\n break;\n\n case State.FAILED:\n this.setState(State.SUCCEEDED);\n break;\n\n default:\n this.setState(State.READY);\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => \"FLIP\";\n}\n", "import Node from \"../Node\";\nimport Decorator from \"./Decorator\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A REPEAT node.\n * The node has a single child which can have:\n * -- A number of iterations for which to repeat the child node.\n * -- An infinite repeat loop if neither an iteration count or a condition function is defined.\n * The REPEAT node will stop and have a 'FAILED' state if its child is ever in a 'FAILED' state after an update.\n * The REPEAT node will attempt to move on to the next iteration if its child is ever in a 'SUCCEEDED' state.\n */\nexport default class Repeat extends Decorator {\n /**\n * @param attributes The node attributes.\n * @param iterations The number of iterations to repeat the child node.\n * @param iterationsMin The minimum possible number of iterations to repeat the child node.\n * @param iterationsMax The maximum possible number of iterations to repeat the child node.\n * @param child The child node.\n */\n constructor(\n attributes: Attribute[],\n private iterations: number | null,\n private iterationsMin: number | null,\n private iterationsMax: number | null,\n child: Node\n ) {\n super(\"repeat\", attributes, child);\n }\n\n /**\n * The number of target iterations to make.\n */\n private targetIterationCount: number | null = null;\n\n /**\n * The current iteration count.\n */\n private currentIterationCount: number = 0;\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // If this node is in the READY state then we need to reset the child and the target iteration count.\n if (this.is(State.READY)) {\n // Reset the child node.\n this.child.reset();\n\n // Reset the current iteration count.\n this.currentIterationCount = 0;\n\n // Set the target iteration count.\n this.setTargetIterationCount(options);\n }\n\n // Do a check to see if we can iterate. If we can then this node will move into the 'RUNNING' state.\n // If we cannot iterate then we have hit our target iteration count, which means that the node has succeeded.\n if (this.canIterate()) {\n // This node is in the running state and can do its initial iteration.\n this.setState(State.RUNNING);\n\n // We may have already completed an iteration, meaning that the child node will be in the SUCCEEDED state.\n // If this is the case then we will have to reset the child node now.\n if (this.child.getState() === State.SUCCEEDED) {\n this.child.reset();\n }\n\n // Update the child of this node.\n this.child.update(agent, options);\n\n // If the child moved into the FAILED state when we updated it then there is nothing left to do and this node has also failed.\n // If it has moved into the SUCCEEDED state then we have completed the current iteration.\n if (this.child.getState() === State.FAILED) {\n // The child has failed, meaning that this node has failed.\n this.setState(State.FAILED);\n\n return;\n } else if (this.child.getState() === State.SUCCEEDED) {\n // We have completed an iteration.\n this.currentIterationCount += 1;\n }\n } else {\n // This node is in the 'SUCCEEDED' state as we cannot iterate any more.\n this.setState(State.SUCCEEDED);\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => {\n if (this.iterations !== null) {\n return `REPEAT ${this.iterations}x`;\n } else if (this.iterationsMin !== null && this.iterationsMax !== null) {\n return `REPEAT ${this.iterationsMin}x-${this.iterationsMax}x`;\n } else {\n return \"REPEAT\";\n }\n };\n\n /**\n * Reset the state of the node.\n */\n reset = () => {\n // Reset the state of this node.\n this.setState(State.READY);\n\n // Reset the current iteration count.\n this.currentIterationCount = 0;\n\n // Reset the child node.\n this.child.reset();\n };\n\n /**\n * Gets whether an iteration can be made.\n * @returns Whether an iteration can be made.\n */\n private canIterate = () => {\n if (this.targetIterationCount !== null) {\n // We can iterate as long as we have not reached our target iteration count.\n return this.currentIterationCount < this.targetIterationCount;\n }\n\n // If neither an iteration count or a condition function were defined then we can iterate indefinitely.\n return true;\n };\n\n /**\n * Sets the target iteration count.\n * @param options The behaviour tree options object.\n */\n private setTargetIterationCount = (options: BehaviourTreeOptions) => {\n // Are we dealing with an explicit iteration count or will we be randomly picking a iteration count between the min and max iteration count.\n if (this.iterations !== null) {\n this.targetIterationCount = this.iterations;\n } else if (this.iterationsMin !== null && this.iterationsMax !== null) {\n // We will be picking a random iteration count between a min and max iteration count, if the optional 'random'\n // behaviour tree function option is defined then we will be using that, otherwise we will fall back to using Math.random.\n const random = typeof options.random === \"function\" ? options.random : Math.random;\n\n // Pick a random iteration count between a min and max iteration count.\n this.targetIterationCount = Math.floor(\n random() * (this.iterationsMax - this.iterationsMin + 1) + this.iterationsMin\n );\n } else {\n this.targetIterationCount = null;\n }\n };\n}\n", "import Node from \"../Node\";\nimport Decorator from \"./Decorator\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A RETRY node.\n * The node has a single child which can have:\n * -- A number of iterations for which to repeat the child node.\n * -- An infinite repeat loop if neither an iteration count or a condition function is defined.\n * The RETRY node will stop and have a 'SUCCEEDED' state if its child is ever in a 'SUCCEEDED' state after an update.\n * The RETRY node will attempt to move on to the next iteration if its child is ever in a 'FAILED' state.\n */\nexport default class Retry extends Decorator {\n /**\n * @param attributes The node attributes.\n * @param attempts The number of attempts to retry the child node.\n * @param attemptsMin The minimum possible number of attempts to retry the child node.\n * @param attemptsMax The maximum possible number of attempts to retry the child node.\n * @param child The child node.\n */\n constructor(\n attributes: Attribute[],\n private attempts: number | null,\n private attemptsMin: number | null,\n private attemptsMax: number | null,\n child: Node\n ) {\n super(\"retry\", attributes, child);\n }\n\n /**\n * The number of target attempts to make.\n */\n private targetAttemptCount: number | null = null;\n\n /**\n * The current attempt count.\n */\n private currentAttemptCount: number = 0;\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // If this node is in the READY state then we need to reset the child and the target attempt count.\n if (this.is(State.READY)) {\n // Reset the child node.\n this.child.reset();\n\n // Reset the current attempt count.\n this.currentAttemptCount = 0;\n\n // Set the target attempt count.\n this.setTargetAttemptCount(options);\n }\n\n // Do a check to see if we can attempt. If we can then this node will move into the 'RUNNING' state.\n // If we cannot attempt then we have hit our target attempt count, which means that the node has succeeded.\n if (this.canAttempt()) {\n // This node is in the running state and can do its initial attempt.\n this.setState(State.RUNNING);\n\n // We may have already completed an attempt, meaning that the child node will be in the FAILED state.\n // If this is the case then we will have to reset the child node now.\n if (this.child.getState() === State.FAILED) {\n this.child.reset();\n }\n\n // Update the child of this node.\n this.child.update(agent, options);\n\n // If the child moved into the SUCCEEDED state when we updated it then there is nothing left to do and this node has also succeeded.\n // If it has moved into the FAILED state then we have completed the current attempt.\n if (this.child.getState() === State.SUCCEEDED) {\n // The child has succeeded, meaning that this node has succeeded.\n this.setState(State.SUCCEEDED);\n\n return;\n } else if (this.child.getState() === State.FAILED) {\n // We have completed an attempt.\n this.currentAttemptCount += 1;\n }\n } else {\n // This node is in the 'FAILED' state as we cannot iterate any more.\n this.setState(State.FAILED);\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => {\n if (this.attempts !== null) {\n return `RETRY ${this.attempts}x`;\n } else if (this.attemptsMin !== null && this.attemptsMax !== null) {\n return `RETRY ${this.attemptsMin}x-${this.attemptsMax}x`;\n } else {\n return \"RETRY\";\n }\n };\n\n /**\n * Reset the state of the node.\n */\n reset = () => {\n // Reset the state of this node.\n this.setState(State.READY);\n\n // Reset the current attempt count.\n this.currentAttemptCount = 0;\n\n // Reset the child node.\n this.child.reset();\n };\n\n /**\n * Gets whether an attempt can be made.\n * @returns Whether an attempt can be made.\n */\n canAttempt = () => {\n if (this.targetAttemptCount !== null) {\n // We can attempt as long as we have not reached our target attempt count.\n return this.currentAttemptCount < this.targetAttemptCount;\n }\n\n // If neither an attempt count or a condition function were defined then we can attempt indefinitely.\n return true;\n };\n\n /**\n * Sets the target attempt count.\n * @param options The behaviour tree options object.\n */\n setTargetAttemptCount = (options: BehaviourTreeOptions) => {\n // Are we dealing with an explicit attempt count or will we be randomly picking an attempt count between the min and max attempt count.\n if (this.attempts !== null) {\n this.targetAttemptCount = this.attempts;\n } else if (this.attemptsMin !== null && this.attemptsMax !== null) {\n // We will be picking a random attempt count between a min and max attempt count, if the optional 'random'\n // behaviour tree function option is defined then we will be using that, otherwise we will fall back to using Math.random.\n const random = typeof options.random === \"function\" ? options.random : Math.random;\n\n // Pick a random attempt count between a min and max attempt count.\n this.targetAttemptCount = Math.floor(\n random() * (this.attemptsMax - this.attemptsMin + 1) + this.attemptsMin\n );\n } else {\n this.targetAttemptCount = null;\n }\n };\n}\n", "import Node from \"../Node\";\nimport Decorator from \"./Decorator\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A Root node.\n * The root node will have a single child.\n */\nexport default class Root extends Decorator {\n /**\n * @param attributes The node attributes.\n * @param child The child node.\n */\n constructor(attributes: Attribute[], child: Node) {\n super(\"root\", attributes, child);\n }\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // If the child has never been updated or is running then we will need to update it now.\n if (this.child.getState() === State.READY || this.child.getState() === State.RUNNING) {\n // Update the child of this node.\n this.child.update(agent, options);\n }\n\n // The state of the root node is the state of its child.\n this.setState(this.child.getState());\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => \"ROOT\";\n}\n", "import Node from \"../Node\";\nimport Decorator from \"./Decorator\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A Succeed node.\n * This node wraps a single child and will always move to the 'SUCCEEDED' state when the child moves to a 'SUCCEEDED' or 'FAILED' state.\n */\nexport default class Succeed extends Decorator {\n /**\n * @param attributes The node attributes.\n * @param child The child node.\n */\n constructor(attributes: Attribute[], child: Node) {\n super(\"succeed\", attributes, child);\n }\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // If the child has never been updated or is running then we will need to update it now.\n if (this.child.getState() === State.READY || this.child.getState() === State.RUNNING) {\n this.child.update(agent, options);\n }\n\n // The state of this node will depend in the state of its child.\n switch (this.child.getState()) {\n case State.RUNNING:\n this.setState(State.RUNNING);\n break;\n\n case State.SUCCEEDED:\n case State.FAILED:\n this.setState(State.SUCCEEDED);\n break;\n\n default:\n this.setState(State.READY);\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => \"SUCCEED\";\n}\n", "import Node from \"../Node\";\n\n/**\n * A leaf node.\n */\nexport default abstract class Leaf extends Node {\n /**\n * Gets whether this node is a leaf node.\n */\n isLeafNode = () => true;\n}\n", "import { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\nimport State, { CompleteState } from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Leaf from \"./Leaf\";\nimport Lookup from \"../../Lookup\";\nimport Attribute from \"../../attributes/Attribute\";\n\n/**\n * The type representing a resolved/rejected update promise.\n */\ntype UpdatePromiseResult = {\n /**\n * Whether the promise was resolved rather than rejected.\n */\n isResolved: boolean;\n\n /**\n * The promise resolved value or rejection reason.\n */\n value: any;\n};\n\n/**\n * An Action leaf node.\n * This represents an immediate or ongoing state of behaviour.\n */\nexport default class Action extends Leaf {\n /**\n * @param attributes The node attributes.\n * @param actionName The action name.\n * @param actionArguments The array of action argument definitions.\n */\n constructor(attributes: Attribute[], private actionName: string, private actionArguments: any[]) {\n super(\"action\", attributes, actionArguments);\n }\n\n /**\n * Whether there is a pending update promise.\n */\n private isUsingUpdatePromise = false;\n\n /**\n * The finished state result of an update promise.\n */\n private updatePromiseResult: UpdatePromiseResult | null = null;\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // If the result of this action depends on an update promise then there is nothing to do until it settles.\n if (this.isUsingUpdatePromise) {\n // Are we still waiting for our update promise to settle?\n if (!this.updatePromiseResult) {\n return;\n }\n\n const { isResolved, value } = this.updatePromiseResult;\n\n // Our update promise settled, was it resolved or rejected?\n if (isResolved) {\n // Our promise resolved so check to make sure the result is a valid finished state.\n if (value !== State.SUCCEEDED && value !== State.FAILED) {\n throw new Error(\n \"action node promise resolved with an invalid value, expected a State.SUCCEEDED or State.FAILED value to be returned\"\n );\n }\n\n // Set the state of this node to match the state returned by the promise.\n this.setState(value);\n\n return;\n } else {\n // The promise was rejected, which isn't great.\n throw new Error(`action function '${this.actionName}' promise rejected with '${value}'`);\n }\n }\n\n // Attempt to get the invoker for the action function.\n const actionFuncInvoker = Lookup.getFuncInvoker(agent, this.actionName);\n\n // The action function should be defined.\n if (actionFuncInvoker === null) {\n throw new Error(\n `cannot update action node as the action '${this.actionName}' function is not defined on the agent and has not been registered`\n );\n }\n\n let actionFunctionResult;\n\n try {\n // Call the action function, the result of which may be:\n // - The finished state of this action node.\n // - A promise to return a finished node state.\n // - Undefined if the node should remain in the running state.\n actionFunctionResult = actionFuncInvoker(this.actionArguments) as CompleteState | Promise;\n } catch (error) {\n // The user was naughty and threw something.\n throw new Error(`action function '${this.actionName}' threw '${error}'`);\n }\n\n if (actionFunctionResult instanceof Promise) {\n actionFunctionResult.then(\n (result) => {\n // If 'isUpdatePromisePending' is not set then the promise was cleared as it was resolving, probably via an abort of reset.\n if (!this.isUsingUpdatePromise) {\n return;\n }\n\n // Set the resolved update promise result so that it can be handled on the next update of this node.\n this.updatePromiseResult = {\n isResolved: true,\n value: result\n };\n },\n (reason) => {\n // If 'isUpdatePromisePending' is not set then the promise was cleared as it was resolving, probably via an abort or reset.\n if (!this.isUsingUpdatePromise) {\n return;\n }\n\n // Set the rejected update promise result so that it can be handled on the next update of this node.\n this.updatePromiseResult = {\n isResolved: false,\n value: reason\n };\n }\n );\n\n // This node will be in the 'RUNNING' state until the update promise resolves.\n this.setState(State.RUNNING);\n\n // We are now waiting for the promise returned by the use to resolve before we know what state this node is in.\n this.isUsingUpdatePromise = true;\n } else {\n // Validate the returned value.\n this.validateUpdateResult(actionFunctionResult);\n\n // Set the state of this node, this may be undefined, which just means that the node is still in the 'RUNNING' state.\n this.setState(actionFunctionResult || State.RUNNING);\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => this.actionName;\n\n /**\n * Reset the state of the node.\n */\n reset = () => {\n // Reset the state of this node.\n this.setState(State.READY);\n\n // There is no longer an update promise that we care about.\n this.isUsingUpdatePromise = false;\n this.updatePromiseResult = null;\n };\n\n /**\n * Validate the result of an update function call.\n * @param result The result of an update function call.\n */\n private validateUpdateResult = (result: CompleteState | State.RUNNING) => {\n switch (result) {\n case State.SUCCEEDED:\n case State.FAILED:\n case State.RUNNING:\n case undefined:\n return;\n default:\n throw new Error(\n `expected action function '${this.actionName}' to return an optional State.SUCCEEDED or State.FAILED value but returned '${result}'`\n );\n }\n };\n}\n", "import { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Leaf from \"./Leaf\";\nimport Lookup from \"../../Lookup\";\nimport Attribute from \"../../attributes/Attribute\";\n\n/**\n * A Condition leaf node.\n * This will succeed or fail immediately based on an agent predicate, without moving to the 'RUNNING' state.\n */\nexport default class Condition extends Leaf {\n /**\n * @param attributes The node attributes.\n * @param conditionName The name of the condition function.\n * @param conditionArguments The array of condition argument definitions.\n */\n constructor(attributes: Attribute[], private conditionName: string, private conditionArguments: any[]) {\n super(\"condition\", attributes, conditionArguments);\n }\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // Attempt to get the invoker for the condition function.\n const conditionFuncInvoker = Lookup.getFuncInvoker(agent, this.conditionName);\n\n // The condition function should be defined.\n if (conditionFuncInvoker === null) {\n throw new Error(\n `cannot update condition node as the condition '${this.conditionName}' function is not defined on the agent and has not been registered`\n );\n }\n\n let conditionFunctionResult;\n\n try {\n // Call the condition function to determine the state of this node, the result of which should be a boolean.\n conditionFunctionResult = conditionFuncInvoker(this.conditionArguments);\n } catch (error) {\n // The user was naughty and threw something.\n throw new Error(`condition function '${this.conditionName}' threw '${error}'`);\n }\n\n // The result of calling the condition function must be a boolean value.\n if (typeof conditionFunctionResult !== \"boolean\") {\n throw new Error(\n `expected condition function '${this.conditionName}' to return a boolean but returned '${conditionFunctionResult}'`\n );\n }\n\n // Set the state of this node based on the result of calling the condition function.\n this.setState(!!conditionFunctionResult ? State.SUCCEEDED : State.FAILED);\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => this.conditionName;\n}\n", "import Leaf from \"./Leaf\";\nimport State from \"../../State\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { Agent } from \"../../Agent\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A WAIT node.\n * The state of this node will change to SUCCEEDED after a duration of time\n */\nexport default class Wait extends Leaf {\n /**\n * @param attributes The node attributes.\n * @param duration The duration that this node will wait to succeed in milliseconds.\n * @param durationMin The minimum possible duration in milliseconds that this node will wait to succeed.\n * @param durationMax The maximum possible duration in milliseconds that this node will wait to succeed.\n */\n constructor(\n attributes: Attribute[],\n private duration: number | null,\n private durationMin: number | null,\n private durationMax: number | null\n ) {\n super(\"wait\", attributes, []);\n }\n\n /**\n * The time in milliseconds at which this node was first updated.\n */\n private initialUpdateTime: number = 0;\n\n /**\n * The total duration in milliseconds that this node will be waiting for.\n */\n private totalDuration: number | null = null;\n\n /**\n * The duration in milliseconds that this node has been waiting for.\n */\n private waitedDuration: number = 0;\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // If this node is in the READY state then we need to set the initial update time.\n if (this.is(State.READY)) {\n // Set the initial update time.\n this.initialUpdateTime = new Date().getTime();\n\n // Set the initial waited duration.\n this.waitedDuration = 0;\n\n // Are we dealing with an explicit duration or will we be randomly picking a duration between the min and max duration.\n if (this.duration !== null) {\n this.totalDuration = this.duration;\n } else if (this.durationMin !== null && this.durationMax !== null) {\n // We will be picking a random duration between a min and max duration, if the optional 'random' behaviour tree\n // function option is defined then we will be using that, otherwise we will fall back to using Math.random.\n const random = typeof options.random === \"function\" ? options.random : Math.random;\n\n // Pick a random duration between a min and max duration.\n this.totalDuration = Math.floor(\n random() * (this.durationMax - this.durationMin + 1) + this.durationMin\n );\n } else {\n this.totalDuration = null;\n }\n\n // The node is now running until we finish waiting.\n this.setState(State.RUNNING);\n }\n\n // If we have no total duration then this wait node will wait indefinitely until it is aborted.\n if (this.totalDuration === null) {\n return;\n }\n\n // If we have a 'getDeltaTime' function defined as part of our options then we will use it to figure out how long we have waited for.\n if (typeof options.getDeltaTime === \"function\") {\n // Get the delta time.\n const deltaTime = options.getDeltaTime();\n\n // Our delta time must be a valid number and cannot be NaN.\n if (typeof deltaTime !== \"number\" || isNaN(deltaTime)) {\n throw new Error(\"The delta time must be a valid number and not NaN.\");\n }\n\n // Update the amount of time that this node has been waiting for based on the delta time.\n this.waitedDuration += deltaTime * 1000;\n } else {\n // We are not using a delta time, so we will just work out hom much time has passed since the first update.\n this.waitedDuration = new Date().getTime() - this.initialUpdateTime;\n }\n\n // Have we waited long enough?\n if (this.waitedDuration >= this.totalDuration) {\n // We have finished waiting!\n this.setState(State.SUCCEEDED);\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => {\n if (this.duration !== null) {\n return `WAIT ${this.duration}ms`;\n } else if (this.durationMin !== null && this.durationMax !== null) {\n return `WAIT ${this.durationMin}ms-${this.durationMax}ms`;\n } else {\n return \"WAIT\";\n }\n };\n}\n", "import Guard from \"./guards/Guard\";\n\nexport type AttributeDetails = {\n /** The attribute type. */\n type: string;\n\n /** The attribute arguments. */\n args: any[];\n};\n\n/**\n * A base node attribute.\n */\nexport default abstract class Attribute {\n /**\n * @param type The node attribute type.\n * @param args The array of attribute arguments.\n */\n constructor(public type: string, public args: any[]) {}\n\n /**\n * Gets the attribute details.\n */\n abstract getDetails(): TAttributeDetails;\n\n /**\n * Gets whether this attribute is a guard.\n */\n abstract isGuard: () => this is Guard;\n}\n", "import { Agent } from \"../../Agent\";\nimport Attribute, { AttributeDetails } from \"../Attribute\";\n\nexport type GuardAttributeDetails = {\n /** The name of the condition function that determines whether the guard is satisfied. */\n condition: string;\n} & AttributeDetails;\n\n/**\n * A base node guard attribute.\n */\nexport default abstract class Guard extends Attribute {\n /**\n * @param type The node attribute type.\n * @param args The array of decorator argument definitions.\n * @param condition The name of the condition function that determines whether the guard is satisfied.\n */\n constructor(type: string, args: any[], private condition: string) {\n super(type, args);\n }\n\n /**\n * Gets the name of the condition function that determines whether the guard is satisfied.\n */\n getCondition = () => this.condition;\n\n /**\n * Gets whether this attribute is a guard.\n */\n isGuard = () => true;\n\n /**\n * Gets the attribute details.\n */\n getDetails(): GuardAttributeDetails {\n return {\n type: this.type,\n args: this.args,\n condition: this.getCondition()\n };\n }\n\n /**\n * Gets whether the guard is satisfied.\n * @param agent The agent.\n * @returns Whether the guard is satisfied.\n */\n abstract isSatisfied(agent: Agent): boolean;\n}\n", "import Guard from \"./Guard\";\nimport Lookup from \"../../Lookup\";\nimport { Agent } from \"../../Agent\";\n\n/**\n * A WHILE guard which is satisfied as long as the given condition remains true.\n */\nexport default class While extends Guard {\n /**\n * @param condition The name of the condition function that determines whether the guard is satisfied.\n * @param args The array of decorator argument definitions.\n */\n constructor(condition: string, args: any[]) {\n super(\"while\", args, condition);\n }\n\n /**\n * Gets whether the guard is satisfied.\n * @param agent The agent.\n * @returns Whether the guard is satisfied.\n */\n isSatisfied = (agent: Agent) => {\n // Attempt to get the invoker for the condition function.\n const conditionFuncInvoker = Lookup.getFuncInvoker(agent, this.getCondition());\n\n // The condition function should be defined.\n if (conditionFuncInvoker === null) {\n throw new Error(\n `cannot evaluate node guard as the condition '${this.getCondition()}' function is not defined on the agent and has not been registered`\n );\n }\n\n // Call the condition function to determine whether this guard is satisfied.\n return !!conditionFuncInvoker(this.args);\n };\n}\n", "import Guard from \"./Guard\";\nimport Lookup from \"../../Lookup\";\nimport { Agent } from \"../../Agent\";\n\n/**\n * An UNTIL guard which is satisfied as long as the given condition remains false.\n */\nexport default class Until extends Guard {\n /**\n * @param condition The name of the condition function that determines whether the guard is satisfied.\n * @param args The array of decorator argument definitions.\n */\n constructor(condition: string, args: any[]) {\n super(\"until\", args, condition);\n }\n\n /**\n * Gets whether the guard is satisfied.\n * @param agent The agent.\n * @returns Whether the guard is satisfied.\n */\n isSatisfied = (agent: Agent) => {\n // Attempt to get the invoker for the condition function.\n const conditionFuncInvoker = Lookup.getFuncInvoker(agent, this.getCondition());\n\n // The condition function should be defined.\n if (conditionFuncInvoker === null) {\n throw new Error(\n `cannot evaluate node guard as the condition '${this.getCondition()}' function is not defined on the agent and has not been registered`\n );\n }\n\n // Call the condition function to determine whether this guard is satisfied.\n return !!!conditionFuncInvoker(this.args);\n };\n}\n", "import { Agent } from \"../../Agent\";\nimport Attribute, { AttributeDetails } from \"../Attribute\";\n\nexport type CallbackAttributeDetails = {\n /** The name of the agent function that is called. */\n functionName: string;\n} & AttributeDetails;\n\n/**\n * A base node callback attribute.\n */\nexport default abstract class Callback extends Attribute {\n /**\n * @param type The node attribute type.\n * @param args The array of decorator argument definitions.\n * @param functionName The name of the agent function to call.\n */\n constructor(type: string, args: any[], private functionName: string) {\n super(type, args);\n }\n\n /**\n * Gets the name of the agent function to call.\n */\n getFunctionName = () => this.functionName;\n\n /**\n * Gets whether this attribute is a guard.\n */\n isGuard = () => false;\n\n /**\n * Gets the attribute details.\n */\n getDetails(): CallbackAttributeDetails {\n return {\n type: this.type,\n args: this.args,\n functionName: this.getFunctionName()\n };\n }\n\n /**\n * Attempt to call the agent function that this callback refers to.\n * @param agent The agent.\n */\n abstract callAgentFunction: (agent: Agent, isSuccess: boolean, isAborted: boolean) => void;\n}\n", "import Callback from \"./Callback\";\nimport Lookup from \"../../Lookup\";\nimport { Agent } from \"../../Agent\";\n\n/**\n * An ENTRY callback which defines an agent function to call when the associated node is updated and moves out of running state.\n */\nexport default class Entry extends Callback {\n /**\n * @param functionName The name of the agent function to call.\n * @param args The array of callback argument definitions.\n */\n constructor(functionName: string, args: any[]) {\n super(\"entry\", args, functionName);\n }\n\n /**\n * Attempt to call the agent function that this callback refers to.\n * @param agent The agent.\n */\n callAgentFunction = (agent: Agent) => {\n // Attempt to get the invoker for the callback function.\n const callbackFuncInvoker = Lookup.getFuncInvoker(agent, this.getFunctionName());\n\n // The callback function should be defined.\n if (callbackFuncInvoker === null) {\n throw new Error(\n `cannot call entry function '${this.getFunctionName()}' as is not defined on the agent and has not been registered`\n );\n }\n\n // Call the callback function.\n callbackFuncInvoker(this.args);\n };\n}\n", "import Callback from \"./Callback\";\nimport Lookup from \"../../Lookup\";\nimport { Agent } from \"../../Agent\";\n\n/**\n * A STEP callback which defines an agent function to call when the associated node is updated.\n */\nexport default class Step extends Callback {\n /**\n * @param functionName The name of the agent function to call.\n * @param args The array of callback argument definitions.\n */\n constructor(functionName: string, args: any[]) {\n super(\"step\", args, functionName);\n }\n\n /**\n * Attempt to call the agent function that this callback refers to.\n * @param agent The agent.\n */\n callAgentFunction = (agent: Agent) => {\n // Attempt to get the invoker for the callback function.\n const callbackFuncInvoker = Lookup.getFuncInvoker(agent, this.getFunctionName());\n\n // The callback function should be defined.\n if (callbackFuncInvoker === null) {\n throw new Error(\n `cannot call step function '${this.getFunctionName()}' as is not defined on the agent and has not been registered`\n );\n }\n\n // Call the callback function.\n callbackFuncInvoker(this.args);\n };\n}\n", "import Callback from \"./Callback\";\nimport Lookup from \"../../Lookup\";\nimport { Agent } from \"../../Agent\";\n\n/**\n * An EXIT callback which defines an agent function to call when the associated node is updated and moves to a finished state or is aborted.\n */\nexport default class Exit extends Callback {\n /**\n * @param functionName The name of the agent function to call.\n * @param args The array of callback argument definitions.\n */\n constructor(functionName: string, args: any[]) {\n super(\"exit\", args, functionName);\n }\n\n /**\n * Attempt to call the agent function that this callback refers to.\n * @param agent The agent.\n * @param isSuccess Whether the decorated node was left with a success state.\n * @param isAborted Whether the decorated node was aborted.\n */\n callAgentFunction = (agent: Agent, isSuccess: boolean, isAborted: boolean) => {\n // Attempt to get the invoker for the callback function.\n const callbackFuncInvoker = Lookup.getFuncInvoker(agent, this.getFunctionName());\n\n // The callback function should be defined.\n if (callbackFuncInvoker === null) {\n throw new Error(\n `cannot call exit function '${this.getFunctionName()}' as is not defined on the agent and has not been registered`\n );\n }\n\n // Call the callback function\n callbackFuncInvoker([{ value: { succeeded: isSuccess, aborted: isAborted } }, ...this.args]);\n };\n}\n", "import { AnyNodeDefinition, RootNodeDefinition } from \"./BehaviourTreeDefinition\";\nimport GuardPath, { GuardPathPart } from \"./attributes/guards/GuardPath\";\nimport { validateBranchSubtreeLinks } from \"./BehaviourTreeDefinitionValidator\";\nimport { isInteger } from \"./BehaviourTreeDefinitionUtilities\";\nimport Node from \"./nodes/Node\";\nimport Composite from \"./nodes/composite/Composite\";\nimport Decorator from \"./nodes/decorator/Decorator\";\nimport Parallel from \"./nodes/composite/Parallel\";\nimport Selector from \"./nodes/composite/Selector\";\nimport Sequence from \"./nodes/composite/Sequence\";\nimport Lotto from \"./nodes/composite/Lotto\";\nimport Fail from \"./nodes/decorator/Fail\";\nimport Flip from \"./nodes/decorator/Flip\";\nimport Repeat from \"./nodes/decorator/Repeat\";\nimport Retry from \"./nodes/decorator/Retry\";\nimport Root from \"./nodes/decorator/Root\";\nimport Succeed from \"./nodes/decorator/Succeed\";\nimport Action from \"./nodes/leaf/Action\";\nimport Condition from \"./nodes/leaf/Condition\";\nimport Wait from \"./nodes/leaf/Wait\";\nimport Lookup from \"./Lookup\";\nimport Attribute from \"./attributes/Attribute\";\nimport While from \"./attributes/guards/While\";\nimport Until from \"./attributes/guards/Until\";\nimport Entry from \"./attributes/callbacks/Entry\";\nimport Step from \"./attributes/callbacks/Step\";\nimport Exit from \"./attributes/callbacks/Exit\";\n\n/**\n * A type representing any node instance in a behaviour tree.\n */\ntype AnyNode =\n | Root\n | Action\n | Condition\n | Wait\n | Sequence\n | Selector\n | Lotto\n | Parallel\n | Repeat\n | Retry\n | Flip\n | Succeed\n | Fail;\n\n/**\n * A type defining a mapping of root node identifiers to root node definitions.\n */\ntype RootNodeDefinitionMap = { [key: string | symbol]: RootNodeDefinition };\n\n/**\n * A symbol to use as the main root key in any root node mappings.\n */\nconst MAIN_ROOT_NODE_KEY = Symbol(\"__root__\");\n\n/**\n * Build and populate the root nodes based on the provided definition, assuming that the definition has been validated.\n * @param definition The root node definitions.\n * @returns The built and populated root node definitions.\n */\nexport default function buildRootNode(definition: RootNodeDefinition[]): Root {\n // Create a mapping of root node identifers to root node definitions, including globally registered subtree root node definitions.\n const rootNodeDefinitionMap = createRootNodeDefinitionMap(definition);\n\n // Now that we have all of our root node definitions (those part of the tree definition and those globally registered)\n // we should validate the branch-subtree links. This will also double-check that we dont have any circular dependencies\n // in our branch-subtree references and that we have no broken branch-subtree links.\n validateBranchSubtreeLinks(\n [rootNodeDefinitionMap[MAIN_ROOT_NODE_KEY], ...Object.values(rootNodeDefinitionMap)],\n true\n );\n\n // Create our populated tree of node instances, starting with our main root node.\n const rootNode = nodeFactory(rootNodeDefinitionMap[MAIN_ROOT_NODE_KEY], rootNodeDefinitionMap) as Root;\n\n // Set a guard path on every leaf of the tree to evaluate as part of each update.\n applyLeafNodeGuardPaths(rootNode);\n\n // We only need to return the main root node.\n return rootNode;\n}\n\n/**\n * A factory function which creates a node instance based on the specified definition.\n * @param definition The node definition.\n * @param rootNodeDefinitionMap The mapping of root node identifers to root node definitions, including globally registered subtree root node definitions.\n * @returns A node instance based on the specified definition.\n */\nfunction nodeFactory(definition: AnyNodeDefinition, rootNodeDefinitionMap: RootNodeDefinitionMap): AnyNode {\n // Get the attributes for the node.\n const attributes = nodeAttributesFactory(definition);\n\n // Create the node instance based on the definition type.\n switch (definition.type) {\n case \"root\":\n return new Root(attributes, nodeFactory(definition.child, rootNodeDefinitionMap));\n\n case \"repeat\":\n let iterations: number | null = null;\n let iterationsMin: number | null = null;\n let iterationsMax: number | null = null;\n\n if (Array.isArray(definition.iterations)) {\n iterationsMin = definition.iterations[0];\n iterationsMax = definition.iterations[1];\n } else if (isInteger(definition.iterations)) {\n iterations = definition.iterations!;\n }\n\n return new Repeat(\n attributes,\n iterations,\n iterationsMin,\n iterationsMax,\n nodeFactory(definition.child, rootNodeDefinitionMap)\n );\n\n case \"retry\":\n let attempts: number | null = null;\n let attemptsMin: number | null = null;\n let attemptsMax: number | null = null;\n\n if (Array.isArray(definition.attempts)) {\n attemptsMin = definition.attempts[0];\n attemptsMax = definition.attempts[1];\n } else if (isInteger(definition.attempts)) {\n attempts = definition.attempts!;\n }\n\n return new Retry(\n attributes,\n attempts,\n attemptsMin,\n attemptsMax,\n nodeFactory(definition.child, rootNodeDefinitionMap)\n );\n\n case \"flip\":\n return new Flip(attributes, nodeFactory(definition.child, rootNodeDefinitionMap));\n\n case \"succeed\":\n return new Succeed(attributes, nodeFactory(definition.child, rootNodeDefinitionMap));\n\n case \"fail\":\n return new Fail(attributes, nodeFactory(definition.child, rootNodeDefinitionMap));\n\n case \"sequence\":\n return new Sequence(\n attributes,\n definition.children.map((child) => nodeFactory(child, rootNodeDefinitionMap))\n );\n\n case \"selector\":\n return new Selector(\n attributes,\n definition.children.map((child) => nodeFactory(child, rootNodeDefinitionMap))\n );\n\n case \"parallel\":\n return new Parallel(\n attributes,\n definition.children.map((child) => nodeFactory(child, rootNodeDefinitionMap))\n );\n\n case \"lotto\":\n return new Lotto(\n attributes,\n definition.weights,\n definition.children.map((child) => nodeFactory(child, rootNodeDefinitionMap))\n );\n\n case \"branch\":\n return nodeFactory(rootNodeDefinitionMap[definition.ref].child, rootNodeDefinitionMap);\n\n case \"action\":\n return new Action(attributes, definition.call, definition.args || []);\n\n case \"condition\":\n return new Condition(attributes, definition.call, definition.args || []);\n\n case \"wait\":\n let duration: number | null = null;\n let durationMin: number | null = null;\n let durationMax: number | null = null;\n\n if (Array.isArray(definition.duration)) {\n durationMin = definition.duration[0];\n durationMax = definition.duration[1];\n } else if (isInteger(definition.duration)) {\n duration = definition.duration!;\n }\n\n return new Wait(attributes, duration, durationMin, durationMax);\n }\n}\n\n/**\n * Creates an array of node attribute instances based on the specified node definition.\n * @param definition The node definition.\n * @returns An array of node attribute instances based on the specified node definition.\n */\nfunction nodeAttributesFactory(definition: AnyNodeDefinition): Attribute[] {\n const attributes: Attribute[] = [];\n\n if (definition.while) {\n attributes.push(new While(definition.while.call, definition.while.args ?? []));\n }\n\n if (definition.until) {\n attributes.push(new Until(definition.until.call, definition.until.args ?? []));\n }\n\n if (definition.entry) {\n attributes.push(new Entry(definition.entry.call, definition.entry.args ?? []));\n }\n\n if (definition.step) {\n attributes.push(new Step(definition.step.call, definition.step.args ?? []));\n }\n\n if (definition.exit) {\n attributes.push(new Exit(definition.exit.call, definition.exit.args ?? []));\n }\n\n return attributes;\n}\n\n/**\n * Creates a mapping of root node identifers to root node definitions, mixing in globally registered subtree root node definitions.\n * @param definition The root node definitions.\n * @returns A mapping of root node identifers to root node definitions, including globally registered subtree root node definitions.\n */\nfunction createRootNodeDefinitionMap(definition: RootNodeDefinition[]): RootNodeDefinitionMap {\n // Create a mapping of root node identifers to root node definitions.\n const rootNodeMap: RootNodeDefinitionMap = {};\n\n // Add in any registered subtree root node definitions.\n for (const [name, rootNodeDefinition] of Object.entries(Lookup.getSubtrees())) {\n // The name used when registering the subtree will be used as the root node identifier.\n rootNodeMap[name] = { ...rootNodeDefinition, id: name };\n }\n\n // Populate the map with the root node definitions that were included with the tree definition.\n // We do this after adding any registered subtrees as we want these to take presedence.\n for (const rootNodeDefinition of definition) {\n rootNodeMap[rootNodeDefinition.id ?? MAIN_ROOT_NODE_KEY] = rootNodeDefinition;\n }\n\n return rootNodeMap;\n}\n\n/**\n * Applies a guard path to every leaf of the tree to evaluate as part of each update.\n * @param root The main root tree node.\n */\nfunction applyLeafNodeGuardPaths(root: Root) {\n const nodePaths: Node[][] = [];\n\n const findLeafNodes = (path: Node[], node: Node) => {\n // Add the current node to the path.\n path = path.concat(node);\n\n // Check whether the current node is a leaf node.\n if (node.isLeafNode()) {\n nodePaths.push(path);\n } else {\n (node as Composite | Decorator).getChildren().forEach((child) => findLeafNodes(path, child));\n }\n };\n\n // Find all leaf node paths, starting from the root.\n findLeafNodes([], root);\n\n nodePaths.forEach((path) => {\n // Each node in the current path will have to be assigned a guard path, working from the root outwards.\n for (let depth = 0; depth < path.length; depth++) {\n // Get the node in the path at the current depth.\n const currentNode = path[depth];\n\n // The node may already have been assigned a guard path, if so just skip it.\n if (currentNode.hasGuardPath()) {\n continue;\n }\n\n // Create the guard path for the current node.\n const guardPath = new GuardPath(\n path\n .slice(0, depth + 1)\n .map((node) => ({ node, guards: node.getGuardAttributes() }))\n .filter((details) => details.guards.length > 0)\n );\n\n // Assign the guard path to the current node.\n currentNode.setGuardPath(guardPath);\n }\n });\n}\n", "import State, { AnyState } from \"./State\";\nimport Lookup from \"./Lookup\";\nimport Node from \"./nodes/Node\";\nimport Root from \"./nodes/decorator/Root\";\nimport Composite from \"./nodes/composite/Composite\";\nimport Decorator from \"./nodes/decorator/Decorator\";\nimport { Agent, GlobalFunction } from \"./Agent\";\nimport { CallbackAttributeDetails } from \"./attributes/callbacks/Callback\";\nimport { GuardAttributeDetails } from \"./attributes/guards/Guard\";\nimport { BehaviourTreeOptions } from \"./BehaviourTreeOptions\";\nimport { convertMDSLToJSON } from \"./mdsl/MDSLDefinitionParser\";\nimport { RootNodeDefinition } from \"./BehaviourTreeDefinition\";\nimport { validateDefinition, validateJSONDefinition } from \"./BehaviourTreeDefinitionValidator\";\nimport buildRootNode from \"./BehaviourTreeBuilder\";\nimport { isNullOrUndefined } from \"./BehaviourTreeDefinitionUtilities\";\n\n// Purely for outside inspection of the tree.\nexport type FlattenedTreeNode = {\n id: string;\n type: string;\n caption: string;\n state: AnyState;\n guards: GuardAttributeDetails[];\n callbacks: CallbackAttributeDetails[];\n args: any[];\n parentId: string | null;\n};\n\n/**\n * A representation of a behaviour tree.\n */\nexport class BehaviourTree {\n /**\n * The main root tree node.\n */\n private readonly _rootNode: Root;\n\n /**\n * Creates a new instance of the BehaviourTree class.\n * @param definition The behaviour tree definition as either an MDSL string, root node definition object or array of root node definition objects.\n * @param agent The agent instance that this behaviour tree is modelling behaviour for.\n * @param options The behaviour tree options object.\n */\n constructor(\n definition: string | RootNodeDefinition | RootNodeDefinition[],\n private agent: Agent,\n private options: BehaviourTreeOptions = {}\n ) {\n // The tree definition must be defined.\n if (isNullOrUndefined(definition)) {\n throw new Error(\"tree definition not defined\");\n }\n\n // The agent must be defined and not null.\n if (typeof agent !== \"object\" || agent === null) {\n throw new Error(\"the agent must be an object and not null\");\n }\n\n // We should validate the definition before we try to build the tree nodes.\n const { succeeded, errorMessage, json } = validateDefinition(definition);\n\n // Did our validation fail without error?\n if (!succeeded) {\n throw new Error(`invalid definition: ${errorMessage}`);\n }\n\n // Double check that we did actually get our json definition as part of our definition validtion.\n if (!json) {\n throw new Error(\n \"expected json definition to be returned as part of successful definition validation response\"\n );\n }\n\n try {\n // Create the populated tree of behaviour tree nodes and get the root node.\n this._rootNode = buildRootNode(json);\n } catch (exception) {\n // There was an issue in trying build and populate the behaviour tree.\n throw new Error(`error building tree: ${(exception as Error).message}`);\n }\n }\n\n /**\n * Gets whether the tree is in the RUNNING state.\n * @returns true if the tree is in the RUNNING state, otherwise false.\n */\n isRunning() {\n return this._rootNode.getState() === State.RUNNING;\n }\n\n /**\n * Gets the current tree state of SUCCEEDED, FAILED, READY or RUNNING.\n * @returns The current tree state.\n */\n getState() {\n return this._rootNode.getState();\n }\n\n /**\n * Step the tree.\n * 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.\n * 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\n * 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.\n *\n * 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.\n */\n step() {\n // If the root node has already been stepped to completion then we need to reset it.\n if (this._rootNode.getState() === State.SUCCEEDED || this._rootNode.getState() === State.FAILED) {\n this._rootNode.reset();\n }\n\n try {\n this._rootNode.update(this.agent, this.options);\n } catch (exception) {\n throw new Error(`error stepping tree: ${(exception as Error).message}`);\n }\n }\n\n /**\n * Resets the tree from the root node outwards to each nested node, giving each a state of READY.\n */\n reset() {\n this._rootNode.reset();\n }\n\n /**\n * Gets the flattened details of every node in the tree.\n * @returns The flattened details of every node in the tree.\n */\n getFlattenedNodeDetails(): FlattenedTreeNode[] {\n // Create an empty flattened array of tree nodes.\n const flattenedTreeNodes: FlattenedTreeNode[] = [];\n\n /**\n * Helper function to process a node instance and push details into the flattened tree nodes array.\n * @param node The current node.\n * @param parentUid The UID of the node parent, or null if the node is the main root node.\n */\n const processNode = (node: Node, parentUid: string | null) => {\n // Get the guard and callback attribute details for this node.\n const guards = node\n .getAttributes()\n .filter((attribute) => attribute.isGuard())\n .map((attribute) => attribute.getDetails()) as GuardAttributeDetails[];\n const callbacks = node\n .getAttributes()\n .filter((attribute) => !attribute.isGuard())\n .map((attribute) => attribute.getDetails()) as CallbackAttributeDetails[];\n\n // Push the current node into the flattened nodes array.\n flattenedTreeNodes.push({\n id: node.getUid(),\n type: node.getType(),\n caption: node.getName(),\n state: node.getState(),\n guards,\n callbacks,\n args: node.getArguments(),\n parentId: parentUid\n });\n\n // Process each of the nodes children if it is not a leaf node.\n if (!node.isLeafNode()) {\n (node as Composite | Decorator)\n .getChildren()\n .forEach((child) => processNode(child, (node as Composite | Decorator).getUid()));\n }\n };\n\n // Convert the nested node structure into a flattened array of node details.\n processNode(this._rootNode, null);\n\n return flattenedTreeNodes;\n }\n\n /**\n * Registers the action/condition/guard/callback function or subtree with the given name.\n * @param name The name of the function or subtree to register.\n * @param value The function or subtree definition to register.\n */\n static register(name: string, value: GlobalFunction | string | RootNodeDefinition) {\n // Are we going to register a action/condition/guard/callback function?\n if (typeof value === \"function\") {\n Lookup.setFunc(name, value);\n return;\n }\n\n // We are not registering an action/condition/guard/callback function, so we must be registering a subtree.\n if (typeof value === \"string\") {\n let rootNodeDefinitions: RootNodeDefinition[];\n\n // We will assume that any string passed in will be a mdsl definition.\n try {\n rootNodeDefinitions = convertMDSLToJSON(value);\n } catch (exception) {\n throw new Error(`error registering definition, invalid MDSL: ${(exception as Error).message}`);\n }\n\n // This function should only ever be called with a definition containing a single unnamed root node.\n if (rootNodeDefinitions.length != 1 || rootNodeDefinitions[0].id !== null) {\n throw new Error(\"error registering definition: expected a single unnamed root node\");\n }\n\n try {\n // We should validate the subtree as we don't want invalid subtrees available via the lookup.\n const { succeeded, errorMessage } = validateJSONDefinition(rootNodeDefinitions[0]);\n\n // Did our validation fail without error?\n if (!succeeded) {\n throw new Error(errorMessage);\n }\n } catch (exception) {\n throw new Error(`error registering definition: ${(exception as Error).message}`);\n }\n\n // Everything seems hunky-dory, register the subtree.\n Lookup.setSubtree(name, rootNodeDefinitions[0]);\n } else if (typeof value === \"object\" && !Array.isArray(value)) {\n // We will assume that any object passed in is a root node definition.\n\n try {\n // We should validate the subtree as we don't want invalid subtrees available via the lookup.\n const { succeeded, errorMessage } = validateJSONDefinition(value);\n\n // Did our validation fail without error?\n if (!succeeded) {\n throw new Error(errorMessage);\n }\n } catch (exception) {\n throw new Error(`error registering definition: ${(exception as Error).message}`);\n }\n\n // Everything seems hunky-dory, register the subtree.\n Lookup.setSubtree(name, value);\n } else {\n throw new Error(\"unexpected value, expected string mdsl definition, root node json definition or function\");\n }\n }\n\n /**\n * Unregisters the registered action/condition/guard/callback function or subtree with the given name.\n * @param name The name of the registered action/condition/guard/callback function or subtree to unregister.\n */\n static unregister(name: string): void {\n Lookup.remove(name);\n }\n\n /**\n * Unregister all registered action/condition/guard/callback functions and subtrees.\n */\n static unregisterAll(): void {\n Lookup.empty();\n }\n}\n"], + "mappings": "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", "names": ["Participant", "isNullOrUndefined", "Lotto", "createLotto", "State", "createLotto"] } diff --git a/dist/index.js b/dist/index.js index 9e190ac..8d3b7be 100644 --- a/dist/index.js +++ b/dist/index.js @@ -414,7 +414,7 @@ function parseAttributeTokens(tokens, stringArgumentPlaceholders) { stringArgumentPlaceholders ); if (attributeCallIdentifier?.type !== "identifier") { - throw new Error("expected agent function name identifier argument for attribute"); + throw new Error("expected agent function or registered function name identifier argument for attribute"); } attributeArguments.filter((arg) => arg.type === "identifier").forEach((arg) => { throw new Error( @@ -558,8 +558,7 @@ function convertTokensToJSONDefinition(tokens, stringLiteralPlaceholders) { } function createRootNode(tokens, stringLiteralPlaceholders) { let node = { - type: "root", - id: void 0 + type: "root" }; const nodeArguments = parseArgumentTokens(tokens, stringLiteralPlaceholders); if (nodeArguments.length) { @@ -688,9 +687,11 @@ function createLottoNode(tokens, stringLiteralPlaceholders) { }); const node = { type: "lotto", - weights: nodeArguments.length ? nodeArguments.map(({ value }) => value) : void 0, ...parseAttributeTokens(tokens, stringLiteralPlaceholders) }; + if (nodeArguments.length) { + node.weights = nodeArguments.map(({ value }) => value); + } popAndCheck(tokens, "{"); return node; } @@ -1223,38 +1224,39 @@ function createValidationFailureResult(errorMessage) { // src/Lookup.ts var Lookup = class { static getFunc(name) { - return this.functionTable[name]; + return this.registeredFunctions[name]; } static setFunc(name, func) { - this.functionTable[name] = func; + this.registeredFunctions[name] = func; } static getFuncInvoker(agent, name) { - const foundOnAgent = agent[name]; - if (foundOnAgent && typeof foundOnAgent === "function") { - return (args) => foundOnAgent.apply(agent, args); + const agentFunction = agent[name]; + if (agentFunction && typeof agentFunction === "function") { + return (args) => agentFunction.apply(agent, args); } - if (this.functionTable[name] && typeof this.functionTable[name] === "function") { - return (args) => this.functionTable[name](agent, ...args.map((arg) => arg.value)); + if (this.registeredFunctions[name] && typeof this.registeredFunctions[name] === "function") { + const registeredFunction = this.registeredFunctions[name]; + return (args) => registeredFunction(agent, ...args.map((arg) => arg.value)); } return null; } static getSubtrees() { - return this.subtreeTable; + return this.registeredSubtrees; } static setSubtree(name, subtree) { - this.subtreeTable[name] = subtree; + this.registeredSubtrees[name] = subtree; } static remove(name) { - delete this.functionTable[name]; - delete this.subtreeTable[name]; + delete this.registeredFunctions[name]; + delete this.registeredSubtrees[name]; } static empty() { - this.functionTable = {}; - this.subtreeTable = {}; + this.registeredFunctions = {}; + this.registeredSubtrees = {}; } }; -__publicField(Lookup, "functionTable", {}); -__publicField(Lookup, "subtreeTable", {}); +__publicField(Lookup, "registeredFunctions", {}); +__publicField(Lookup, "registeredSubtrees", {}); // src/attributes/guards/GuardUnsatisifedException.ts var GuardUnsatisifedException = class extends Error { @@ -1826,11 +1828,12 @@ var Action = class extends Leaf { switch (result) { case "mistreevous.succeeded" /* SUCCEEDED */: case "mistreevous.failed" /* FAILED */: + case "mistreevous.running" /* RUNNING */: case void 0: return; default: throw new Error( - `action '${this.actionName}' 'onUpdate' returned an invalid response, expected an optional State.SUCCEEDED or State.FAILED value to be returned` + `expected action function '${this.actionName}' to return an optional State.SUCCEEDED or State.FAILED value but returned '${result}'` ); } }; @@ -2046,7 +2049,10 @@ var Exit = class extends Callback { var MAIN_ROOT_NODE_KEY = Symbol("__root__"); function buildRootNode(definition) { const rootNodeDefinitionMap = createRootNodeDefinitionMap(definition); - validateBranchSubtreeLinks(definition, true); + validateBranchSubtreeLinks( + [rootNodeDefinitionMap[MAIN_ROOT_NODE_KEY], ...Object.values(rootNodeDefinitionMap)], + true + ); const rootNode = nodeFactory(rootNodeDefinitionMap[MAIN_ROOT_NODE_KEY], rootNodeDefinitionMap); applyLeafNodeGuardPaths(rootNode); return rootNode; diff --git a/dist/index.js.map b/dist/index.js.map index 2298ede..548a5ac 100644 --- a/dist/index.js.map +++ b/dist/index.js.map @@ -1,7 +1,7 @@ { "version": 3, "sources": ["../node_modules/lotto-draw/dist/Participant.js", "../node_modules/lotto-draw/dist/Utilities.js", "../node_modules/lotto-draw/dist/Lotto.js", "../node_modules/lotto-draw/dist/createLotto.js", "../node_modules/lotto-draw/dist/index.js", "../src/index.ts", "../src/State.ts", "../src/BehaviourTreeDefinitionUtilities.ts", "../src/mdsl/MDSLUtilities.ts", "../src/mdsl/MDSLNodeArgumentParser.ts", "../src/mdsl/MDSLNodeAttributeParser.ts", "../src/mdsl/MDSLDefinitionParser.ts", "../src/BehaviourTreeDefinitionValidator.ts", "../src/Lookup.ts", "../src/attributes/guards/GuardUnsatisifedException.ts", "../src/attributes/guards/GuardPath.ts", "../src/nodes/Node.ts", "../src/nodes/composite/Composite.ts", "../src/nodes/composite/Parallel.ts", "../src/nodes/composite/Selector.ts", "../src/nodes/composite/Sequence.ts", "../src/nodes/composite/Lotto.ts", "../src/nodes/decorator/Decorator.ts", "../src/nodes/decorator/Fail.ts", "../src/nodes/decorator/Flip.ts", "../src/nodes/decorator/Repeat.ts", "../src/nodes/decorator/Retry.ts", "../src/nodes/decorator/Root.ts", "../src/nodes/decorator/Succeed.ts", "../src/nodes/leaf/Leaf.ts", "../src/nodes/leaf/Action.ts", "../src/nodes/leaf/Condition.ts", "../src/nodes/leaf/Wait.ts", "../src/attributes/Attribute.ts", "../src/attributes/guards/Guard.ts", "../src/attributes/guards/While.ts", "../src/attributes/guards/Until.ts", "../src/attributes/callbacks/Callback.ts", "../src/attributes/callbacks/Entry.ts", "../src/attributes/callbacks/Step.ts", "../src/attributes/callbacks/Exit.ts", "../src/BehaviourTreeBuilder.ts", "../src/BehaviourTree.ts"], - "sourcesContent": ["\"use strict\";\r\nObject.defineProperty(exports, \"__esModule\", { value: true });\r\nexports.Participant = void 0;\r\n/**\r\n * A participant that holds a number of tickets.\r\n */\r\nvar Participant = /** @class */ (function () {\r\n /**\r\n * Creates an instance of the Participant class.\r\n * @param participant The actual participant.\r\n * @param tickets The number of tickets held by the participant.\r\n */\r\n function Participant(participant, tickets) {\r\n if (tickets === void 0) { tickets = 1; }\r\n this._participant = participant;\r\n this._tickets = tickets;\r\n }\r\n Object.defineProperty(Participant.prototype, \"participant\", {\r\n /** Gets the actual participant. */\r\n get: function () {\r\n return this._participant;\r\n },\r\n enumerable: false,\r\n configurable: true\r\n });\r\n Object.defineProperty(Participant.prototype, \"tickets\", {\r\n /** Gets or sets the number of tickets held by the participant. */\r\n get: function () {\r\n return this._tickets;\r\n },\r\n set: function (value) {\r\n this._tickets = value;\r\n },\r\n enumerable: false,\r\n configurable: true\r\n });\r\n return Participant;\r\n}());\r\nexports.Participant = Participant;\r\n", "\"use strict\";\r\nObject.defineProperty(exports, \"__esModule\", { value: true });\r\nexports.isNaturalNumber = exports.isNullOrUndefined = void 0;\r\n/**\r\n * Gets whether the value provided is null or undefined.\r\n * @param value The value to check.\r\n * @returns Whether the value provided is null or undefined.\r\n */\r\nfunction isNullOrUndefined(value) {\r\n return value === null || value === undefined;\r\n}\r\nexports.isNullOrUndefined = isNullOrUndefined;\r\n/**\r\n * Gets whether the value provided is a natural number.\r\n * @param value The value to check.\r\n * @returns Whether the value provided is a natural number.\r\n */\r\nfunction isNaturalNumber(value) {\r\n return typeof value === \"number\" && value >= 1 && Math.floor(value) === value;\r\n}\r\nexports.isNaturalNumber = isNaturalNumber;\r\n", "\"use strict\";\r\nObject.defineProperty(exports, \"__esModule\", { value: true });\r\nexports.Lotto = void 0;\r\nvar Participant_1 = require(\"./Participant\");\r\nvar Utilities_1 = require(\"./Utilities\");\r\n/**\r\n * Represents a lotto consisting of a number of pickable ticket-holding participants.\r\n */\r\nvar Lotto = /** @class */ (function () {\r\n /**\r\n * Creates a new instance of Lotto.\r\n * @param customRandom The custom RNG to use in place of Math.random().\r\n */\r\n function Lotto(customRandom) {\r\n /** The array of participants that are holding tickets in the lotto. */\r\n this._participants = [];\r\n this._customRandom = customRandom;\r\n }\r\n /**\r\n * Adds a participant with the specified number of tickets, or adds to the participant ticket count if the participant already holds tickets.\r\n * @param participant The participant to add or to increase the ticket count for if they already hold tickets.\r\n * @param tickets The number of tickets, defaults to 1.\r\n * @returns The Lotto instance.\r\n */\r\n Lotto.prototype.add = function (participant, tickets) {\r\n if (tickets === void 0) { tickets = 1; }\r\n // Check that we have a valid ticket count.\r\n if (!(0, Utilities_1.isNaturalNumber)(tickets)) {\r\n throw new Error(\"tickets value must be a natural number\");\r\n }\r\n // Check whether this participant has already been added.\r\n var existingParticipant = this._participants.find(function (part) { return part.participant === participant; });\r\n if (existingParticipant) {\r\n // The participant has already been added to the lotto so just add to their ticket count.\r\n existingParticipant.tickets += tickets;\r\n }\r\n else {\r\n // The participant is not part of the lotto so we should add them.\r\n this._participants.push(new Participant_1.Participant(participant, tickets));\r\n }\r\n return this;\r\n };\r\n /**\r\n * Removes the specified number of tickets for the given participant from the draw, or all tickets if a ticket number is not defined.\r\n * @param participant The participant to remove tickets for.\r\n * @param tickets The number of tickets to remove, or undefined if all tickets are to be removed.\r\n * @returns The Lotto instance.\r\n */\r\n Lotto.prototype.remove = function (participant, tickets) {\r\n // Attempt to get the existing participant.\r\n var existingParticipant = this._participants.find(function (part) { return part.participant === participant; });\r\n // There is nothing to do if the specified participant isn't even part of the lotto.\r\n if (!existingParticipant) {\r\n return this;\r\n }\r\n // Check whether a tickets value was given.\r\n if (tickets !== undefined) {\r\n // Check that we have a valid ticket count.\r\n if (!(0, Utilities_1.isNaturalNumber)(tickets)) {\r\n throw new Error(\"tickets value must be a natural number\");\r\n }\r\n existingParticipant.tickets -= tickets;\r\n // If the participant no longer holds any tickets then they should be removed.\r\n if (existingParticipant.tickets < 1) {\r\n this._participants = this._participants.filter(function (part) { return part !== existingParticipant; });\r\n }\r\n }\r\n else {\r\n // We are removing all tickets for the participant so just remove them from the lotto.\r\n this._participants = this._participants.filter(function (part) { return part !== existingParticipant; });\r\n }\r\n return this;\r\n };\r\n /**\r\n * Draw a winning ticket and return the participant that holds the ticket.\r\n * @param options The draw options.\r\n * @returns The participant that holds the winning ticket.\r\n */\r\n Lotto.prototype.draw = function (options) {\r\n if (options === void 0) { options = {}; }\r\n // If we have no participants then just return null.\r\n if (this._participants.length === 0) {\r\n return null;\r\n }\r\n var redrawable = (0, Utilities_1.isNullOrUndefined)(options.redrawable) ? true : options.redrawable;\r\n var pickable = [];\r\n this._participants.forEach(function (_a) {\r\n var participant = _a.participant, tickets = _a.tickets;\r\n for (var ticketCount = 0; ticketCount < tickets; ticketCount++) {\r\n pickable.push(participant);\r\n }\r\n });\r\n var random;\r\n // We need a random floating-point number between 0 (inclusive) and 1 to scale up to pick our winner.\r\n // If a custom random function exists then we should use that or fall back to Math.random().\r\n if (this._customRandom) {\r\n // Call our custom random function to get a random floating-point number.\r\n random = this._customRandom();\r\n // Verify that the result of calling our custom random function is a number between 0 (inclusive) and 1.\r\n if (typeof random !== \"number\" || random < 0 || random >= 1) {\r\n throw new Error(\"the 'random' function provided did not return a number between 0 (inclusive) and 1\");\r\n }\r\n }\r\n else {\r\n // No custom random function was defined so just use good ol' Math.random().\r\n random = Math.random();\r\n }\r\n // Pick a winning participant.\r\n var winner = pickable[Math.floor(random * pickable.length)];\r\n // If the ticket isn't redrawable then we should remove a ticket from the winning participants ticket count.\r\n if (!redrawable) {\r\n this.remove(winner, 1);\r\n }\r\n // Return the winning participant.\r\n return winner;\r\n };\r\n /**\r\n * Draws multiple winning tickets and return an array of the participants that hold the winning tickets.\r\n * @param tickets The number of winning tickets to draw.\r\n * @param options The draw multiple options.\r\n * @returns An array of the participants that hold the winning tickets.\r\n */\r\n Lotto.prototype.drawMultiple = function (tickets, options) {\r\n if (options === void 0) { options = {}; }\r\n var uniqueResults = (0, Utilities_1.isNullOrUndefined)(options.unique) ? false : options.unique;\r\n // Handle cases where the user has asked for zero tickets (no idea why they would do this be we should trust them).\r\n if (tickets === 0) {\r\n return [];\r\n }\r\n // Now that we know out tickets value is not zero we should check that it is a valid natural number.\r\n if (!(0, Utilities_1.isNaturalNumber)(tickets)) {\r\n throw new Error(\"tickets value must be a natural number\");\r\n }\r\n var result = [];\r\n // Keep drawing tickets until we either reach the number of required tickets or we simply run out of tickets to draw.\r\n // We can run out of tickets to draw if 'options.redrawable' is explicity 'false' or we just had no participants when 'drawMultiple' was called.\r\n while (result.length < tickets && this._participants.length > 0) {\r\n result.push(this.draw(options));\r\n }\r\n // If the 'unique' draw option is set then we need to remove duplicates from the result list.\r\n if (uniqueResults) {\r\n // Create an array to store our unique results.\r\n var unique = [];\r\n // Iterate over all of our participants (with potential duplicates) and populate our array of unique values.\r\n for (var _i = 0, result_1 = result; _i < result_1.length; _i++) {\r\n var participant = result_1[_i];\r\n if (unique.indexOf(participant) === -1) {\r\n unique.push(participant);\r\n }\r\n }\r\n result = unique;\r\n }\r\n return result;\r\n };\r\n return Lotto;\r\n}());\r\nexports.Lotto = Lotto;\r\n", "\"use strict\";\r\nObject.defineProperty(exports, \"__esModule\", { value: true });\r\nexports.createLotto = void 0;\r\nvar Lotto_1 = require(\"./Lotto\");\r\n/**\r\n * A function that creates and returns a Lotto instance.\r\n * @param participantsOrOptions An array of initial participants or options relating to the creation of a Lotto instance.\r\n * @returns A new Lotto instance.\r\n */\r\nfunction createLotto(participantsOrOptions) {\r\n // If no initial participants or lotto options were provided as an argument then we can just return a new lotto instance now.\r\n if (!participantsOrOptions) {\r\n return new Lotto_1.Lotto();\r\n }\r\n // Check whether we were provided with an array of initial participants or a lotto options object.\r\n if (Array.isArray(participantsOrOptions)) {\r\n // We are dealing with a pre-defined array of participants.\r\n var participants = participantsOrOptions;\r\n var lotto_1 = new Lotto_1.Lotto();\r\n // If the lotto participants have been defined upfront then we will need to add them all to our lotto instance now.\r\n participants.forEach(function (_a) {\r\n var participant = _a[0], tokens = _a[1];\r\n return lotto_1.add(participant, tokens);\r\n });\r\n // Return the Lotto instance.\r\n return lotto_1;\r\n }\r\n else {\r\n // We are dealing with some lotto options.\r\n var random = participantsOrOptions.random, participants = participantsOrOptions.participants;\r\n // Create a Lotto instance passing the custom RNG function to use in place of Math.random() (which could be undefined).\r\n var lotto_2 = new Lotto_1.Lotto(random);\r\n // If the lotto participants have been defined upfront as part of the options then we will need to add them all to our lotto instance now.\r\n if (participants) {\r\n participants.forEach(function (_a) {\r\n var participant = _a[0], tokens = _a[1];\r\n return lotto_2.add(participant, tokens);\r\n });\r\n }\r\n // Return the Lotto instance.\r\n return lotto_2;\r\n }\r\n}\r\nexports.createLotto = createLotto;\r\n", "\"use strict\";\r\nObject.defineProperty(exports, \"__esModule\", { value: true });\r\nvar createLotto_1 = require(\"./createLotto\");\r\nexports.default = createLotto_1.createLotto;\r\n", "import State from \"./State\";\nimport { validateDefinition } from \"./BehaviourTreeDefinitionValidator\";\nimport { convertMDSLToJSON } from \"./mdsl/MDSLDefinitionParser\";\nimport { BehaviourTree, FlattenedTreeNode } from \"./BehaviourTree\";\nimport { BehaviourTreeOptions } from \"./BehaviourTreeOptions\";\n\nexport { BehaviourTree, State, convertMDSLToJSON, validateDefinition };\nexport type { FlattenedTreeNode, BehaviourTreeOptions };\n", "/**\n * Enumeration of node state types.\n */\nexport enum State {\n READY = \"mistreevous.ready\",\n RUNNING = \"mistreevous.running\",\n SUCCEEDED = \"mistreevous.succeeded\",\n FAILED = \"mistreevous.failed\"\n}\n\nexport { State as default };\n\nexport type CompleteState = State.SUCCEEDED | State.FAILED;\nexport type AnyState = State.READY | State.RUNNING | CompleteState;\n", "import {\n NodeDefinition,\n RootNodeDefinition,\n DecoratorNodeDefinition,\n CompositeNodeDefinition,\n AnyNodeDefinition,\n BranchNodeDefinition\n} from \"./BehaviourTreeDefinition\";\n\n/**\n * A type guard function that returns true if the specified node satisfies the RootNodeDefinition type.\n * @param node The node.\n * @returns A value of true if the specified node satisfies the RootNodeDefinition type.\n */\nexport function isRootNode(node: NodeDefinition): node is RootNodeDefinition {\n return node.type === \"root\";\n}\n\n/**\n * A type guard function that returns true if the specified node satisfies the BranchNodeDefinition type.\n * @param node The node.\n * @returns A value of true if the specified node satisfies the BranchNodeDefinition type.\n */\nexport function isBranchNode(node: NodeDefinition): node is BranchNodeDefinition {\n return node.type === \"branch\";\n}\n\n/**\n * A type guard function that returns true if the specified node satisfies the NodeDefinition type.\n * @param node The node.\n * @returns A value of true if the specified node satisfies the NodeDefinition type.\n */\nexport function isLeafNode(node: NodeDefinition): node is NodeDefinition {\n return [\"branch\", \"action\", \"condition\", \"wait\"].includes(node.type);\n}\n\n/**\n * A type guard function that returns true if the specified node satisfies the DecoratorNodeDefinition type.\n * @param node The node.\n * @returns A value of true if the specified node satisfies the DecoratorNodeDefinition type.\n */\nexport function isDecoratorNode(node: NodeDefinition): node is DecoratorNodeDefinition {\n return [\"root\", \"repeat\", \"retry\", \"flip\", \"succeed\", \"fail\"].includes(node.type);\n}\n\n/**\n * A type guard function that returns true if the specified node satisfies the CompositeNodeDefinition type.\n * @param node The node.\n * @returns A value of true if the specified node satisfies the CompositeNodeDefinition type.\n */\nexport function isCompositeNode(node: NodeDefinition): node is CompositeNodeDefinition {\n return [\"sequence\", \"selector\", \"lotto\", \"parallel\"].includes(node.type);\n}\n\n/**\n * Flatten a node definition into an array of all of its nested node definitions.\n * @param nodeDefinition The node definition to flatten.\n * @returns An array of all of nested node definitions.\n */\nexport function flattenDefinition(nodeDefinition: AnyNodeDefinition): AnyNodeDefinition[] {\n const nodes: AnyNodeDefinition[] = [];\n\n const processNode = (currentNodeDefinition: AnyNodeDefinition) => {\n nodes.push(currentNodeDefinition);\n\n if (isCompositeNode(currentNodeDefinition)) {\n currentNodeDefinition.children.forEach(processNode);\n } else if (isDecoratorNode(currentNodeDefinition)) {\n processNode(currentNodeDefinition.child);\n }\n };\n\n processNode(nodeDefinition);\n\n return nodes;\n}\n\n/**\n * Determines whether the passed value is an integer.\n * @param value The value to check.\n * @returns Whether the passed value is an integer.\n */\nexport function isInteger(value: unknown): boolean {\n return typeof value === \"number\" && Math.floor(value) === value;\n}\n\n/**\n * Determines whether the passed value is null or undefined.\n * @param value The value to check.\n * @returns Whether the passed value is null or undefined.\n */\nexport function isNullOrUndefined(value: unknown): boolean {\n return typeof value === \"undefined\" || value === null;\n}\n", "/**\n * A type defining an object that holds a reference to substitued string literals parsed from the definition.\n */\nexport type StringLiteralPlaceholders = { [key: string]: string };\n\n/**\n * Pop the next raw token from the specified array of tokens and throw an error if it wasn't the expected one.\n * @param tokens The array of tokens.\n * @param expected An optional string or array or items, one of which must match the next popped token.\n * @returns The popped token.\n */\nexport function popAndCheck(tokens: string[], expected?: string | string[]): string {\n // Get and remove the next token.\n const popped = tokens.shift();\n\n // We were expecting another token but there aren't any.\n if (popped === undefined) {\n throw new Error(\"unexpected end of definition\");\n }\n\n // Do we have an expected token/tokens array?\n if (expected != undefined) {\n // Get an array of expected values, if the popped token matches any then we are all good.\n const expectedValues = typeof expected === \"string\" ? [expected] : expected;\n\n // Check whether the popped token matches at least one of our expected items.\n var tokenMatchesExpectation = expectedValues.some((item) => popped.toUpperCase() === item.toUpperCase());\n\n // Throw an error if the popped token didn't match any of our expected items.\n if (!tokenMatchesExpectation) {\n const expectationString = expectedValues.map((item) => \"'\" + item + \"'\").join(\" or \");\n throw new Error(\"unexpected token found. Expected \" + expectationString + \" but got '\" + popped + \"'\");\n }\n }\n\n // Return the popped token.\n return popped;\n}\n\n/**\n * Swaps out any node/attribute argument string literals with placeholders.\n * @param definition The definition.\n * @returns An object containing a mapping of placeholders to original string values as well as the processed definition string.\n */\nexport function substituteStringLiterals(definition: string): {\n placeholders: StringLiteralPlaceholders;\n processedDefinition: string;\n} {\n // Create an object to hold the mapping of placeholders to original string values.\n const placeholders: StringLiteralPlaceholders = {};\n\n // Replace any string literals wrapped with double quotes in our definition with placeholders to be processed later.\n const processedDefinition = definition.replace(/\\\"(\\\\.|[^\"\\\\])*\\\"/g, (match) => {\n var strippedMatch = match.substring(1, match.length - 1);\n var placeholder = Object.keys(placeholders).find((key) => placeholders[key] === strippedMatch);\n\n // If we have no existing string literal match then create a new placeholder.\n if (!placeholder) {\n placeholder = `@@${Object.keys(placeholders).length}@@`;\n placeholders[placeholder] = strippedMatch;\n }\n\n return placeholder;\n });\n\n return { placeholders, processedDefinition };\n}\n\n/**\n * Parse the tree definition into an array of raw tokens.\n * @param definition The definition.\n * @returns An array of tokens parsed from the definition.\n */\nexport function parseTokensFromDefinition(definition: string): string[] {\n // Add some space around various important characters so that they can be plucked out easier as individual tokens.\n definition = definition.replace(/\\(/g, \" ( \");\n definition = definition.replace(/\\)/g, \" ) \");\n definition = definition.replace(/\\{/g, \" { \");\n definition = definition.replace(/\\}/g, \" } \");\n definition = definition.replace(/\\]/g, \" ] \");\n definition = definition.replace(/\\[/g, \" [ \");\n definition = definition.replace(/\\,/g, \" , \");\n\n // Split the definition into raw token form and return it.\n return definition.replace(/\\s+/g, \" \").trim().split(\" \");\n}\n", "import { StringLiteralPlaceholders, popAndCheck } from \"./MDSLUtilities\";\n\n/**\n * A type representing any node function argument.\n */\ntype Argument = {\n /**\n * The argument value.\n */\n value: T;\n /**\n * The argument type, used for validation.\n */\n type: string;\n};\n\ntype NullArgument = Argument & {\n type: \"null\";\n};\n\ntype BooleanArgument = Argument & {\n type: \"boolean\";\n};\n\ntype NumberArgument = Argument & {\n type: \"number\";\n /**\n * A flag defining whether the number argument value is a valid integer. (used for validation)\n */\n isInteger: boolean;\n};\n\ntype StringPlaceholderArgument = Argument & {\n type: \"string\";\n};\n\ntype IdentifierArgument = Argument & {\n type: \"identifier\";\n};\n\n/**\n * A type representing a reference to any node function argument.\n */\ntype AnyArgument = NullArgument | BooleanArgument | NumberArgument | StringPlaceholderArgument | IdentifierArgument;\n\n/**\n * Parse an array of argument definitions from the specified tokens array.\n * @param tokens The array tokens to parse the argument definitions from.\n * @param stringArgumentPlaceholders The mapping of string literal node argument placeholders to original values.\n * @param argumentValidator The argument validator function.\n * @param validationFailedMessage The exception message to throw if argument validation fails.\n * @returns An array of argument definitions parsed from the specified tokens array.\n */\nexport function parseArgumentTokens(\n tokens: string[],\n stringArgumentPlaceholders: StringLiteralPlaceholders\n): AnyArgument[] {\n const argumentList: AnyArgument[] = [];\n\n // If the next token is not a '[' or '(' then we have no arguments to parse.\n if (![\"[\", \"(\"].includes(tokens[0])) {\n return argumentList;\n }\n\n // Any lists of arguments will always be wrapped in '[]' for node arguments or '()' for attribute arguments.\n // We are looking for a '[' or '(' opener that wraps the argument tokens and the relevant closer.\n const closingToken = popAndCheck(tokens, [\"[\", \"(\"]) === \"[\" ? \"]\" : \")\";\n\n const argumentListTokens: string[] = [];\n\n // Grab all tokens between the '[' and ']' or '(' and ')'.\n while (tokens.length && tokens[0] !== closingToken) {\n // The next token is part of our arguments list.\n argumentListTokens.push(tokens.shift()!);\n }\n\n // Validate the order of the argument tokens. Each token must either be a ',' or a single argument that satisfies the validator.\n argumentListTokens.forEach((token, index) => {\n // Get whether this token should be an actual argument.\n const shouldBeArgumentToken = !(index & 1);\n\n // If the current token should be an actual argument then validate it, otherwise it should be a ',' token.\n if (shouldBeArgumentToken) {\n // Get the argument definition.\n const argumentDefinition = getArgumentDefinition(token, stringArgumentPlaceholders);\n\n // This is a valid argument!\n argumentList.push(argumentDefinition);\n } else {\n // The current token should be a ',' token.\n if (token !== \",\") {\n throw new Error(`invalid argument list, expected ',' or ']' but got '${token}'`);\n }\n }\n });\n\n // The arguments list should terminate with a ']' or ')' token, depending on the opener.\n popAndCheck(tokens, closingToken);\n\n // Return the arguments.\n return argumentList;\n}\n\n/**\n * Gets an argument value definition.\n * @param token The argument token.\n * @param stringArgumentPlaceholders The mapping of string literal node argument placeholders to original values.\n * @returns An argument value definition.\n */\nfunction getArgumentDefinition(token: string, stringArgumentPlaceholders: StringLiteralPlaceholders): AnyArgument {\n // Check whether the token represents a null value.\n if (token === \"null\") {\n return {\n value: null,\n type: \"null\"\n } as NullArgument;\n }\n\n // Check whether the token represents a boolean value.\n if (token === \"true\" || token === \"false\") {\n return {\n value: token === \"true\",\n type: \"boolean\"\n } as BooleanArgument;\n }\n\n // Check whether the token represents a number value.\n // TODO: Relies on broken isNaN - see MDN.\n // if (!Number.isNaN(token)) {\n if (!isNaN(token as any)) {\n return {\n value: parseFloat(token),\n isInteger: parseFloat(token) === parseInt(token, 10),\n type: \"number\"\n } as NumberArgument;\n }\n\n // Check whether the token is a placeholder (e.g. @@0@@) representing a string literal.\n if (token.match(/^@@\\d+@@$/g)) {\n return {\n value: stringArgumentPlaceholders[token].replace('\\\\\"', '\"'),\n type: \"string\"\n } as StringPlaceholderArgument;\n }\n\n // The only remaining option is that the argument value is an identifier.\n return {\n value: token,\n type: \"identifier\"\n } as IdentifierArgument;\n}\n", "import { NodeAttributeDefinition } from \"../BehaviourTreeDefinition\";\nimport { parseArgumentTokens } from \"./MDSLNodeArgumentParser\";\nimport { StringLiteralPlaceholders } from \"./MDSLUtilities\";\n\n/**\n * A type defining the attribute definitions of a node.\n */\ntype NodeAttributes = {\n while?: NodeAttributeDefinition;\n until?: NodeAttributeDefinition;\n entry?: NodeAttributeDefinition;\n exit?: NodeAttributeDefinition;\n step?: NodeAttributeDefinition;\n};\n\n/**\n * Parse any node attribute definitions from the specified tokens array.\n * @param tokens The array of remaining tokens.\n * @param stringArgumentPlaceholders The mapping of string literal node argument placeholders to original values.\n * @returns An object of attribute definitions defined by any directly following tokens.\n */\nexport function parseAttributeTokens(\n tokens: string[],\n stringArgumentPlaceholders: StringLiteralPlaceholders\n): NodeAttributes {\n const nodeAttributeNames: (keyof NodeAttributes)[] = [\"while\", \"until\", \"entry\", \"exit\", \"step\"];\n\n // Create an object to hold any attributes found.\n const attributes: NodeAttributes = {};\n\n // Try to get the name of the attribute for the next token.\n let nextAttributeName = tokens[0]?.toLowerCase() as keyof NodeAttributes;\n\n // Pull attribute tokens as well as their arguments off of the tokens stack until we have no more.\n while (nodeAttributeNames.includes(nextAttributeName)) {\n // Check to make sure that we have not already created an attribute definition of this type.\n if (attributes[nextAttributeName]) {\n throw new Error(`duplicate attribute '${tokens[0].toUpperCase()}' found for node`);\n }\n\n // Remove the attribute name token from the array of tokens.\n tokens.shift();\n\n // Grab the attribute arguments, assuming the first to be an identifier.\n const [attributeCallIdentifier, ...attributeArguments] = parseArgumentTokens(\n tokens,\n stringArgumentPlaceholders\n );\n\n // The first attribute argument has to be an identifer, this will reference an agent function.\n if (attributeCallIdentifier?.type !== \"identifier\") {\n throw new Error(\"expected agent function name identifier argument for attribute\");\n }\n\n // Any attribute arguments (other than the expected call identifier) must have a type of string, number, boolean or null.\n attributeArguments\n .filter((arg) => arg.type === \"identifier\")\n .forEach((arg) => {\n throw new Error(\n `invalid attribute argument value '${arg.value}', must be string, number, boolean or null`\n );\n });\n\n // Create the attribute definition and add it to the object of attribute definitions found.\n attributes[nextAttributeName] = {\n call: attributeCallIdentifier.value,\n args: attributeArguments.map(({ value }) => value)\n };\n\n // Try to get the next attribute name token, as there could be multiple.\n nextAttributeName = tokens[0]?.toLowerCase() as keyof NodeAttributes;\n }\n\n return attributes;\n}\n", "import {\n ActionNodeDefinition,\n AnyChildNodeDefinition,\n AnyNodeDefinition,\n BranchNodeDefinition,\n ConditionNodeDefinition,\n FailNodeDefinition,\n FlipNodeDefinition,\n LottoNodeDefinition,\n ParallelNodeDefinition,\n RepeatNodeDefinition,\n RetryNodeDefinition,\n RootNodeDefinition,\n SelectorNodeDefinition,\n SequenceNodeDefinition,\n SucceedNodeDefinition,\n WaitNodeDefinition\n} from \"../BehaviourTreeDefinition\";\nimport {\n isCompositeNode,\n isDecoratorNode,\n isLeafNode,\n isNullOrUndefined,\n isRootNode\n} from \"../BehaviourTreeDefinitionUtilities\";\nimport { parseArgumentTokens } from \"./MDSLNodeArgumentParser\";\nimport { parseAttributeTokens } from \"./MDSLNodeAttributeParser\";\nimport {\n StringLiteralPlaceholders,\n parseTokensFromDefinition,\n popAndCheck,\n substituteStringLiterals\n} from \"./MDSLUtilities\";\n\n/**\n * Convert the MDSL tree definition string into an equivalent JSON definition.\n * @param definition The tree definition string as MDSL.\n * @returns The root node JSON definitions.\n */\nexport function convertMDSLToJSON(definition: string): RootNodeDefinition[] {\n // Swap out any node/attribute argument string literals with a placeholder and get a mapping of placeholders to original values as well as the processed definition.\n const { placeholders, processedDefinition } = substituteStringLiterals(definition);\n\n // Parse our definition definition string into an array of raw tokens.\n const tokens = parseTokensFromDefinition(processedDefinition);\n\n return convertTokensToJSONDefinition(tokens, placeholders);\n}\n\n/**\n * Converts the specified tree definition tokens into a JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The root node JSON definitions.\n */\nfunction convertTokensToJSONDefinition(\n tokens: string[],\n stringLiteralPlaceholders: StringLiteralPlaceholders\n): RootNodeDefinition[] {\n // There must be at least 3 tokens for the tree definition to be valid. 'ROOT', '{' and '}'.\n if (tokens.length < 3) {\n throw new Error(\"invalid token count\");\n }\n\n // We should have a matching number of '{' and '}' tokens. If not, then there are scopes that have not been properly closed.\n if (tokens.filter((token) => token === \"{\").length !== tokens.filter((token) => token === \"}\").length) {\n throw new Error(\"scope character mismatch\");\n }\n\n // Create an array of tree stack arrays where root nodes will always be at the botton and the current composite/decorator node at the top.\n // There should be an element in this array for every root node defined and every element should be an array with a root note as the first element.\n // E.g. A definition with two root nodes defined:\n // [\n // [root, lotto, sequence],\n // [root, selector]\n // ]\n const treeStacks: [Partial, ...Partial[]][] = [];\n\n // Create an array of all root node definitions that we create.\n const rootNodes: Partial[] = [];\n\n // A helper function used to push node definitions onto the tree stack.\n const pushNode = (node: AnyNodeDefinition) => {\n // If the node is a root node then we need to create a new tree stack array with the root node at the root.\n if (isRootNode(node)) {\n // We need to double-check that this root node is not the child of another node.\n // We can do this by checking whether the top tree stack is not empty (contains an existing node)\n if (treeStacks[treeStacks.length - 1]?.length) {\n throw new Error(\"a root node cannot be the child of another node\");\n }\n\n // Add the root node definition to our array of all parsed root node definitions.\n rootNodes.push(node);\n\n // Add the root node definition to the root of a new tree stack.\n treeStacks.push([node]);\n\n return;\n }\n\n // All non-root nodes should be pushed after their root nodes so handle cases\n // where we may not have any tree stacks or our top-most tree stack is empty.\n if (!treeStacks.length || !treeStacks[treeStacks.length - 1].length) {\n throw new Error(\"expected root node at base of definition\");\n }\n\n // Get the current tree stack that we are populating.\n const topTreeStack = treeStacks[treeStacks.length - 1];\n\n // Get the top-most node in the current tree stack, this will be a composite/decorator node\n // for which we will populate its children array if composite or setting its child if a decorator.\n const topTreeStackTopNode = topTreeStack[topTreeStack.length - 1] as AnyNodeDefinition;\n\n // If the top-most node in the current root stack is a composite or decorator\n // node then the current node should be added as a child of the top-most node.\n if (isCompositeNode(topTreeStackTopNode)) {\n topTreeStackTopNode.children = topTreeStackTopNode.children || [];\n topTreeStackTopNode.children.push(node);\n } else if (isDecoratorNode(topTreeStackTopNode)) {\n // If the top node already has a child node set then throw an error as a decorator should only have a single child.\n if (topTreeStackTopNode.child) {\n throw new Error(\"a decorator node must only have a single child node\");\n }\n\n topTreeStackTopNode.child = node;\n }\n\n // If the node we are adding is also a composite or decorator node, then we should push it\n // onto the current tree stack, as subsequent nodes will be added as its child/children.\n if (!isLeafNode(node)) {\n topTreeStack.push(node);\n }\n };\n\n // A helper function used to pop the top-most node definition off of the tree stack and return it.\n const popNode = (): AnyNodeDefinition | null => {\n let poppedNode: AnyNodeDefinition | null = null;\n\n // Get the current tree stack that we are populating.\n const topTreeStack = treeStacks[treeStacks.length - 1];\n\n // Pop the top-most node in the current tree stack if there is one.\n if (topTreeStack.length) {\n poppedNode = topTreeStack.pop() as AnyNodeDefinition;\n }\n\n // We don't want any empty tree stacks in our stack of tree stacks.\n if (!topTreeStack.length) {\n treeStacks.pop();\n }\n\n return poppedNode;\n };\n\n // We should keep processing the raw tokens until we run out of them.\n while (tokens.length) {\n // Grab the next token.\n const token = tokens.shift()!;\n\n // How we create the next node depends on the current raw token value.\n switch (token.toUpperCase()) {\n case \"ROOT\": {\n pushNode(createRootNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"SUCCEED\": {\n pushNode(createSucceedNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"FAIL\": {\n pushNode(createFailNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"FLIP\": {\n pushNode(createFlipNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"REPEAT\": {\n pushNode(createRepeatNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"RETRY\": {\n pushNode(createRetryNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"SEQUENCE\": {\n pushNode(createSequenceNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"SELECTOR\": {\n pushNode(createSelectorNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"PARALLEL\": {\n pushNode(createParallelNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"LOTTO\": {\n pushNode(createLottoNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"ACTION\": {\n pushNode(createActionNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"CONDITION\": {\n pushNode(createConditionNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"WAIT\": {\n pushNode(createWaitNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"BRANCH\": {\n pushNode(createBranchNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"}\": {\n // The '}' character closes the current scope and means that we have to pop a node off of the current stack.\n const poppedNode = popNode();\n\n // Now that we have a node definition we can carry out any validation that may require the node to be fully populated.\n if (poppedNode) {\n validatePoppedNode(poppedNode);\n }\n\n break;\n }\n\n default: {\n throw new Error(`unexpected token: ${token}`);\n }\n }\n }\n\n return rootNodes as RootNodeDefinition[];\n}\n\n/**\n * Creates a root node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The root node JSON definition.\n */\nfunction createRootNode(tokens: string[], stringLiteralPlaceholders: StringLiteralPlaceholders): RootNodeDefinition {\n // Create the root node definition.\n let node = {\n type: \"root\",\n id: undefined\n } as RootNodeDefinition;\n\n // Parse any node arguments, we should only have one if any which will be an identifier argument for the root identifier.\n const nodeArguments = parseArgumentTokens(tokens, stringLiteralPlaceholders);\n\n // Check whether any node arguments were defined.\n if (nodeArguments.length) {\n // We should only have one argument, if any, which will be an identifier argument for the root identifier.\n if (nodeArguments.length === 1 && nodeArguments[0].type === \"identifier\") {\n // The root node identifier will be the first and only node argument value.\n node.id = nodeArguments[0].value as string;\n } else {\n throw new Error(\"expected single root name argument\");\n }\n }\n\n // Grab any node attribute definitions and spread them into the node definition.\n node = { ...node, ...parseAttributeTokens(tokens, stringLiteralPlaceholders) };\n\n // This is a decorator node, so we expect an opening '{'.\n popAndCheck(tokens, \"{\");\n\n // Return the root node definition.\n return node;\n}\n\n/**\n * Creates a succeed node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The succeed node JSON definition.\n */\nfunction createSucceedNode(\n tokens: string[],\n stringLiteralPlaceholders: StringLiteralPlaceholders\n): SucceedNodeDefinition {\n const node = {\n type: \"succeed\",\n ...parseAttributeTokens(tokens, stringLiteralPlaceholders)\n } as SucceedNodeDefinition;\n\n // This is a decorator node, so we expect an opening '{'.\n popAndCheck(tokens, \"{\");\n\n // Return the succeed node definition.\n return node;\n}\n\n/**\n * Creates a fail node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The fail node JSON definition.\n */\nfunction createFailNode(tokens: string[], stringLiteralPlaceholders: StringLiteralPlaceholders): FailNodeDefinition {\n const node = {\n type: \"fail\",\n ...parseAttributeTokens(tokens, stringLiteralPlaceholders)\n } as FailNodeDefinition;\n\n // This is a decorator node, so we expect an opening '{'.\n popAndCheck(tokens, \"{\");\n\n // Return the fail node definition.\n return node;\n}\n\n/**\n * Creates a flip node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The flip node JSON definition.\n */\nfunction createFlipNode(tokens: string[], stringLiteralPlaceholders: StringLiteralPlaceholders): FlipNodeDefinition {\n const node = {\n type: \"flip\",\n ...parseAttributeTokens(tokens, stringLiteralPlaceholders)\n } as FlipNodeDefinition;\n\n // This is a decorator node, so we expect an opening '{'.\n popAndCheck(tokens, \"{\");\n\n // Return the flip node definition.\n return node;\n}\n\n/**\n * Creates a repeat node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The repeat node JSON definition.\n */\nfunction createRepeatNode(\n tokens: string[],\n stringLiteralPlaceholders: StringLiteralPlaceholders\n): RepeatNodeDefinition {\n let node = { type: \"repeat\" } as RepeatNodeDefinition;\n\n // Get the node arguments.\n const nodeArguments = parseArgumentTokens(tokens, stringLiteralPlaceholders);\n\n // The arguments of a repeat node are optional. We may have:\n // - No node arguments, in which case the repeat note will iterate indefinitely.\n // - One node argument which will be the explicit number of iterations to make.\n // - Two node arguments which define the min and max iteration bounds from which a random iteration count will be picked.\n if (nodeArguments.length) {\n // All repeat node arguments MUST be of type number and must be integer.\n nodeArguments\n .filter((arg) => arg.type !== \"number\" || !arg.isInteger)\n .forEach(() => {\n throw new Error(`repeat node iteration counts must be integer values`);\n });\n\n // We should have got one or two iteration counts.\n if (nodeArguments.length === 1) {\n // A static iteration count was defined.\n node.iterations = nodeArguments[0].value as number;\n\n // A repeat node must have a positive number of iterations if defined.\n if (node.iterations < 0) {\n throw new Error(\"a repeat node must have a positive number of iterations if defined\");\n }\n } else if (nodeArguments.length === 2) {\n // A minimum and maximum iteration count was defined.\n node.iterations = [nodeArguments[0].value as number, nodeArguments[1].value as number];\n\n // A repeat node must have a positive min and max iteration count if they are defined.\n if (node.iterations[0] < 0 || node.iterations[1] < 0) {\n throw new Error(\"a repeat node must have a positive minimum and maximum iteration count if defined\");\n }\n\n // A repeat node must not have an minimum iteration count that exceeds the maximum iteration count.\n if (node.iterations[0] > node.iterations[1]) {\n throw new Error(\n \"a repeat node must not have a minimum iteration count that exceeds the maximum iteration count\"\n );\n }\n } else {\n // An incorrect number of iteration counts was defined.\n throw new Error(\"invalid number of repeat node iteration count arguments defined\");\n }\n }\n\n // Grab any node attribute definitions and spread them into the node definition.\n node = { ...node, ...parseAttributeTokens(tokens, stringLiteralPlaceholders) };\n\n // This is a decorator node, so we expect an opening '{'.\n popAndCheck(tokens, \"{\");\n\n // Return the repeat node definition.\n return node;\n}\n\n/**\n * Creates a retry node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The retry node JSON definition.\n */\nfunction createRetryNode(tokens: string[], stringLiteralPlaceholders: StringLiteralPlaceholders): RetryNodeDefinition {\n let node = { type: \"retry\" } as RetryNodeDefinition;\n\n // Get the node arguments.\n const nodeArguments = parseArgumentTokens(tokens, stringLiteralPlaceholders);\n\n // The arguments of a retry node are optional. We may have:\n // - No node arguments, in which case the retry note will attempt indefinitely.\n // - One node argument which will be the explicit number of attempts to make.\n // - Two node arguments which define the min and max attempt bounds from which a random attempt count will be picked.\n if (nodeArguments.length) {\n // All retry node arguments MUST be of type number and must be integer.\n nodeArguments\n .filter((arg) => arg.type !== \"number\" || !arg.isInteger)\n .forEach(() => {\n throw new Error(`retry node attempt counts must be integer values`);\n });\n\n // We should have got one or two attempt counts.\n if (nodeArguments.length === 1) {\n // A static attempt count was defined.\n node.attempts = nodeArguments[0].value as number;\n\n // A retry node must have a positive number of attempts if defined.\n if (node.attempts < 0) {\n throw new Error(\"a retry node must have a positive number of attempts if defined\");\n }\n } else if (nodeArguments.length === 2) {\n // A minimum and maximum attempt count was defined.\n node.attempts = [nodeArguments[0].value as number, nodeArguments[1].value as number];\n\n // A retry node must have a positive min and max attempts count if they are defined.\n if (node.attempts[0] < 0 || node.attempts[1] < 0) {\n throw new Error(\"a retry node must have a positive minimum and maximum attempt count if defined\");\n }\n\n // A retry node must not have a minimum attempt count that exceeds the maximum attempt count.\n if (node.attempts[0] > node.attempts[1]) {\n throw new Error(\n \"a retry node must not have a minimum attempt count that exceeds the maximum attempt count\"\n );\n }\n } else {\n // An incorrect number of attempt counts was defined.\n throw new Error(\"invalid number of retry node attempt count arguments defined\");\n }\n }\n\n // Grab any node attribute definitions and spread them into the node definition.\n node = { ...node, ...parseAttributeTokens(tokens, stringLiteralPlaceholders) };\n\n // This is a decorator node, so we expect an opening '{'.\n popAndCheck(tokens, \"{\");\n\n // Return the retry node definition.\n return node;\n}\n\n/**\n * Creates a sequence node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The sequence node JSON definition.\n */\nfunction createSequenceNode(\n tokens: string[],\n stringLiteralPlaceholders: StringLiteralPlaceholders\n): SequenceNodeDefinition {\n const node = {\n type: \"sequence\",\n ...parseAttributeTokens(tokens, stringLiteralPlaceholders)\n } as SequenceNodeDefinition;\n\n // This is a composite node, so we expect an opening '{'.\n popAndCheck(tokens, \"{\");\n\n // Return the sequence node definition.\n return node;\n}\n\n/**\n * Creates a selector node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The selector node JSON definition.\n */\nfunction createSelectorNode(\n tokens: string[],\n stringLiteralPlaceholders: StringLiteralPlaceholders\n): SelectorNodeDefinition {\n const node = {\n type: \"selector\",\n ...parseAttributeTokens(tokens, stringLiteralPlaceholders)\n } as SelectorNodeDefinition;\n\n // This is a composite node, so we expect an opening '{'.\n popAndCheck(tokens, \"{\");\n\n // Return the selector node definition.\n return node;\n}\n\n/**\n * Creates a parallel node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The parallel node JSON definition.\n */\nfunction createParallelNode(\n tokens: string[],\n stringLiteralPlaceholders: StringLiteralPlaceholders\n): ParallelNodeDefinition {\n const node = {\n type: \"parallel\",\n ...parseAttributeTokens(tokens, stringLiteralPlaceholders)\n } as ParallelNodeDefinition;\n\n // This is a composite node, so we expect an opening '{'.\n popAndCheck(tokens, \"{\");\n\n // Return the parallel node definition.\n return node;\n}\n\n/**\n * Creates a lotto node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The lotto node JSON definition.\n */\nfunction createLottoNode(tokens: string[], stringLiteralPlaceholders: StringLiteralPlaceholders): LottoNodeDefinition {\n // If any node arguments have been defined then they must be our weights.\n const nodeArguments = parseArgumentTokens(tokens, stringLiteralPlaceholders);\n\n // All lotto node arguments MUST be of type number and must be positive integers.\n nodeArguments\n .filter((arg) => arg.type !== \"number\" || !arg.isInteger || arg.value < 0)\n .forEach(() => {\n throw new Error(`lotto node weight arguments must be positive integer values`);\n });\n\n const node = {\n type: \"lotto\",\n weights: nodeArguments.length ? nodeArguments.map(({ value }) => value) : undefined,\n ...parseAttributeTokens(tokens, stringLiteralPlaceholders)\n } as LottoNodeDefinition;\n\n // This is a composite node, so we expect an opening '{'.\n popAndCheck(tokens, \"{\");\n\n // Return the lotto node definition.\n return node;\n}\n\n/**\n * Creates an action node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The action node JSON definition.\n */\nfunction createActionNode(\n tokens: string[],\n stringLiteralPlaceholders: StringLiteralPlaceholders\n): ActionNodeDefinition {\n // Parse any node arguments, we should have at least one which will be an identifier argument for the action name\n // and agent function to invoke for the action, all other arguments are to be passed as arguments to that function.\n const [actionNameIdentifier, ...agentFunctionArgs] = parseArgumentTokens(tokens, stringLiteralPlaceholders);\n\n // Our first argument MUST be defined and be an identifier as we require an action name argument.\n if (actionNameIdentifier?.type !== \"identifier\") {\n throw new Error(\"expected action name identifier argument\");\n }\n\n // Only the first argument should have been an identifier, all agent function arguments must be string, number, boolean or null.\n agentFunctionArgs\n .filter((arg) => arg.type === \"identifier\")\n .forEach((arg) => {\n throw new Error(\n `invalid action node argument value '${arg.value}', must be string, number, boolean or null`\n );\n });\n\n // Return the action node definition.\n return {\n type: \"action\",\n call: actionNameIdentifier.value,\n args: agentFunctionArgs.map(({ value }) => value),\n ...parseAttributeTokens(tokens, stringLiteralPlaceholders)\n };\n}\n\n/**\n * Creates a condition node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The condition node JSON definition.\n */\nfunction createConditionNode(\n tokens: string[],\n stringLiteralPlaceholders: StringLiteralPlaceholders\n): ConditionNodeDefinition {\n // Parse any node arguments, we should have at least one which will be an identifier argument for the condition name\n // and agent function to invoke for the condition, all other arguments are to be passed as arguments to that function.\n const [conditionNameIdentifier, ...agentFunctionArgs] = parseArgumentTokens(tokens, stringLiteralPlaceholders);\n\n // Our first argument MUST be defined and be an identifier as we require a condition name argument.\n if (conditionNameIdentifier?.type !== \"identifier\") {\n throw new Error(\"expected condition name identifier argument\");\n }\n\n // Only the first argument should have been an identifier, all agent function arguments must be string, number, boolean or null.\n agentFunctionArgs\n .filter((arg) => arg.type === \"identifier\")\n .forEach((arg) => {\n throw new Error(\n `invalid condition node argument value '${arg.value}', must be string, number, boolean or null`\n );\n });\n\n // Return the condition node definition.\n return {\n type: \"condition\",\n call: conditionNameIdentifier.value,\n args: agentFunctionArgs.map(({ value }) => value),\n ...parseAttributeTokens(tokens, stringLiteralPlaceholders)\n };\n}\n\n/**\n * Creates a wait node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The wait node JSON definition.\n */\nfunction createWaitNode(tokens: string[], stringLiteralPlaceholders: StringLiteralPlaceholders): WaitNodeDefinition {\n let node = { type: \"wait\" } as WaitNodeDefinition;\n\n // Get the node arguments.\n const nodeArguments = parseArgumentTokens(tokens, stringLiteralPlaceholders);\n\n // The arguments of a wait node are optional. We may have:\n // - No node arguments, in which case the wait will be indefinite until it is aborted.\n // - One node argument which will be the explicit duration of the wait.\n // - Two node arguments which define the min and max duration bounds from which a random duration will be picked.\n if (nodeArguments.length) {\n // All wait node arguments MUST be of type number and must be integer.\n nodeArguments\n .filter((arg) => arg.type !== \"number\" || !arg.isInteger)\n .forEach(() => {\n throw new Error(`wait node durations must be integer values`);\n });\n\n // We may have:\n // - One node argument which will be the explicit duration of the wait.\n // - Two node arguments which define the min and max duration bounds from which a random duration will be picked.\n // - Too many arguments, which is not valid.\n if (nodeArguments.length === 1) {\n // An explicit duration was defined.\n node.duration = nodeArguments[0].value as number;\n\n // If an explict duration was defined then it must be a positive number.\n if (node.duration < 0) {\n throw new Error(\"a wait node must have a positive duration\");\n }\n } else if (nodeArguments.length === 2) {\n // Min and max duration bounds were defined from which a random duration will be picked.\n node.duration = [nodeArguments[0].value as number, nodeArguments[1].value as number];\n\n // A wait node must have a positive min and max duration.\n if (node.duration[0] < 0 || node.duration[1] < 0) {\n throw new Error(\"a wait node must have a positive minimum and maximum duration\");\n }\n\n // A wait node must not have a minimum duration that exceeds the maximum duration.\n if (node.duration[0] > node.duration[1]) {\n throw new Error(\"a wait node must not have a minimum duration that exceeds the maximum duration\");\n }\n } else if (nodeArguments.length > 2) {\n // An incorrect number of duration arguments were defined.\n throw new Error(\"invalid number of wait node duration arguments defined\");\n }\n }\n\n // Return the wait node definition.\n return { ...node, ...parseAttributeTokens(tokens, stringLiteralPlaceholders) };\n}\n\n/**\n * Creates a branch node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The branch node JSON definition.\n */\nfunction createBranchNode(\n tokens: string[],\n stringLiteralPlaceholders: StringLiteralPlaceholders\n): BranchNodeDefinition {\n // Parse any node arguments, we should have one which will be an identifier argument for the root ref.\n const nodeArguments = parseArgumentTokens(tokens, stringLiteralPlaceholders);\n\n // We should have only a single identifer argument for a branch node, which is the root ref.\n if (nodeArguments.length !== 1 || nodeArguments[0].type !== \"identifier\") {\n throw new Error(\"expected single branch name argument\");\n }\n\n // Return the branch node definition.\n return { type: \"branch\", ref: nodeArguments[0].value };\n}\n\n/**\n * Validate a fully-populated node definition that was popped off of the tree stack.\n * @param definition The popped node to validate.\n */\nfunction validatePoppedNode(definition: AnyNodeDefinition): void {\n // Decorators MUST have a child defined.\n if (isDecoratorNode(definition) && isNullOrUndefined(definition.child)) {\n throw new Error(`a ${definition.type} node must have a single child node defined`);\n }\n\n // Composites MUST have at least one child defined.\n if (isCompositeNode(definition) && !definition.children?.length) {\n throw new Error(`a ${definition.type} node must have at least a single child node defined`);\n }\n\n // We need to make sure that lotto nodes that have weights defined have a number of weights matching the number of child nodes.\n if (definition.type === \"lotto\") {\n // Check whether a 'weights' property has been defined, if it has we expect it to be an array of weights.\n if (typeof definition.weights !== \"undefined\") {\n // Check that the weights property is an array of positive integers with an element for each child node element.\n if (definition.weights.length !== definition.children.length) {\n throw new Error(\n \"expected a number of weight arguments matching the number of child nodes for lotto node\"\n );\n }\n }\n }\n}\n", "import { RootNodeDefinition } from \"./BehaviourTreeDefinition\";\nimport { flattenDefinition, isBranchNode, isInteger } from \"./BehaviourTreeDefinitionUtilities\";\nimport { convertMDSLToJSON } from \"./mdsl/MDSLDefinitionParser\";\n\n/**\n * An object representing the result of validating a tree definition.\n */\nexport type DefinitionValidationResult = {\n /**\n * A flag defining whether validation succeeded.\n */\n succeeded: boolean;\n /**\n * A string containing the error message if validation did not succeed.\n */\n errorMessage?: string;\n /**\n * The definition as json if the validation was successful, or undefined if validation did not succeed.\n */\n json?: RootNodeDefinition[];\n};\n\n/**\n * Validates the specified behaviour tree definition in the form of JSON or MDSL, not taking any globally registered subtrees into consideration.\n * @param definition The behaviour tree definition in the form of JSON or MDSL.\n * @returns An object representing the result of validating the given tree definition.\n */\nexport function validateDefinition(definition: any): DefinitionValidationResult {\n // The definition must be defined.\n if (definition === null || typeof definition === \"undefined\") {\n return createValidationFailureResult(\"definition is null or undefined\");\n }\n\n // We are expecting a definition in one of three different forms:\n // - A string which we will assume is MDSL and we will parse this to JSON before validation.\n // - An array which we will assume is an array of root node definitions with at least one being the primary root node (no 'id' property)\n // - An object which we will assume is the primary root node and should not have an 'id' property.\n if (typeof definition === \"string\") {\n // The definition is a string which we can assume is MDSL, so attempt to validate it.\n return validateMDSLDefinition(definition);\n } else if (typeof definition === \"object\") {\n // The definition will either be an array (of root node definitions) or an object (the single primary root node definition).\n return validateJSONDefinition(definition);\n } else {\n return createValidationFailureResult(`unexpected definition type of '${typeof definition}'`);\n }\n}\n\n/**\n * Validates the specified behaviour tree definition in the form of MDSL.\n * @param definition The behaviour tree definition in the form of MDSL.\n * @returns An object representing the result of validating the given tree definition.\n */\nfunction validateMDSLDefinition(definition: string): DefinitionValidationResult {\n let rootNodeDefinitions;\n\n // The first thing the we need to do is to attempt to convert our MDSL into JSON.\n try {\n // The definition is a string which we can assume is MDSL, so attempt to parse it to a JSON definition in the form of an array of root node definitions.\n rootNodeDefinitions = convertMDSLToJSON(definition);\n } catch (exception) {\n // We failed to parse the JSON from the MDSL, this is likely to be the result of it not being a valid MDSL string.\n return createValidationFailureResult((exception as Error).message);\n }\n\n // Unpack all of the root node definitions into arrays of main ('id' defined) and sub ('id' not defined) root node definitions.\n const mainRootNodeDefinitions = rootNodeDefinitions.filter(({ id }) => typeof id === \"undefined\");\n const subRootNodeDefinitions = rootNodeDefinitions.filter(({ id }) => typeof id === \"string\" && id.length > 0);\n\n // We should ALWAYS have exactly one root node definition without an 'id' property defined, which is out main root node definition.\n if (mainRootNodeDefinitions.length !== 1) {\n return createValidationFailureResult(\n \"expected single unnamed root node at base of definition to act as main root\"\n );\n }\n\n // We should never have duplicate 'id' properties across our sub root node definitions.\n const subRootNodeIdenitifers: string[] = [];\n for (const { id } of subRootNodeDefinitions) {\n // Have we already come across this 'id' property value?\n if (subRootNodeIdenitifers.includes(id!)) {\n return createValidationFailureResult(`multiple root nodes found with duplicate name '${id}'`);\n }\n\n subRootNodeIdenitifers.push(id!);\n }\n\n try {\n // Validate our branch -> subtree links and check for any circular dependencies, we don't care about checking for broken subtree links here.\n validateBranchSubtreeLinks(rootNodeDefinitions, false);\n } catch (exception) {\n return createValidationFailureResult((exception as Error).message);\n }\n\n // Our definition was valid!\n return {\n succeeded: true,\n json: rootNodeDefinitions\n };\n}\n\n/**\n * Validates the specified behaviour tree definition in the form of JSON.\n * @param definition The behaviour tree definition in the form of JSON.\n * @returns An object representing the result of validating the given tree definition.\n */\nexport function validateJSONDefinition(\n definition: RootNodeDefinition | RootNodeDefinition[]\n): DefinitionValidationResult {\n // The definition will either be an array (of root node definitions) or an object (the single primary root node definition).\n const rootNodeDefinitions = Array.isArray(definition) ? definition : [definition];\n\n // Iterate over our array of root nodes and call validateNode for each, passing an initial depth of 0, wrapped in a try catch to handle validation failures.\n try {\n rootNodeDefinitions.forEach((rootNodeDefinition) => validateNode(rootNodeDefinition, 0));\n } catch (error) {\n // Handle cases where we have caught a thrown Error and return a failure result with the error message.\n if (error instanceof Error) {\n return createValidationFailureResult(error.message);\n }\n\n // No idea what happened here!\n return createValidationFailureResult(`unexpected error: ${error}`);\n }\n\n // Unpack all of the root node definitions into arrays of main ('id' defined) and sub ('id' not defined) root node definitions.\n const mainRootNodeDefinitions = rootNodeDefinitions.filter(({ id }) => typeof id === \"undefined\");\n const subRootNodeDefinitions = rootNodeDefinitions.filter(({ id }) => typeof id === \"string\" && id.length > 0);\n\n // We should ALWAYS have exactly one root node definition without an 'id' property defined, which is out main root node definition.\n if (mainRootNodeDefinitions.length !== 1) {\n return createValidationFailureResult(\n \"expected single root node without 'id' property defined to act as main root\"\n );\n }\n\n // We should never have duplicate 'id' properties across our sub root node definitions.\n const subRootNodeIdenitifers: string[] = [];\n for (const { id } of subRootNodeDefinitions) {\n // Have we already come across this 'id' property value?\n if (subRootNodeIdenitifers.includes(id!)) {\n return createValidationFailureResult(\n `multiple root nodes found with duplicate 'id' property value of '${id}'`\n );\n }\n\n subRootNodeIdenitifers.push(id!);\n }\n\n try {\n // Validate our branch -> subtree links and check for any circular dependencies, we don't care about checking for broken subtree links here.\n validateBranchSubtreeLinks(rootNodeDefinitions, false);\n } catch (exception) {\n return createValidationFailureResult((exception as Error).message);\n }\n\n // Our definition was valid!\n return {\n succeeded: true,\n json: rootNodeDefinitions\n };\n}\n\n/**\n * Validates the branch -> subtree links across all provided root node definitions.\n * This will not consider branch nodes that reference any globally registered subtrees unless includesGlobalSubtrees\n * is set to true, in which case we will also verify that there are no broken branch -> subtree links.\n * @param rootNodeDefinitions The array of root node definitions.\n * @param includesGlobalSubtrees A flag defining whether the array includes all global subtree root node definitions.\n */\nexport function validateBranchSubtreeLinks(rootNodeDefinitions: RootNodeDefinition[], includesGlobalSubtrees: boolean) {\n // Create a mapping of root node identifiers to other root nodes that they reference via branch nodes.\n // Below is an example of a mapping that includes a circular dependency (root => a => b => c => a)\n // [{ refs: [\"a\", \"b\"] }, { id: \"a\", refs: [\"b\"] }, { id: \"b\", refs: [\"c\"] }, { id: \"c\", refs: [\"a\"] }]\n const rootNodeMappings: { id: string | undefined; refs: string[] }[] = rootNodeDefinitions.map(\n (rootNodeDefinition) => ({\n id: rootNodeDefinition.id,\n refs: flattenDefinition(rootNodeDefinition)\n .filter(isBranchNode)\n .map(({ ref }) => ref)\n })\n );\n\n // A recursive function to walk through the mappings, keeping track of which root nodes we have visited in the form of a path of root node identifiers.\n const followRefs = (mapping: { id: string | undefined; refs: string[] }, path: (string | undefined)[] = []) => {\n // Have we found a circular dependency?\n if (path.includes(mapping.id)) {\n // We found a circular dependency! Get the bad path of root node identifiers.\n const badPath = [...path, mapping.id];\n\n // Create the formatted path value. [undefined, \"a\", \"b\", \"c\", \"a\"] would be formatted as \"a -> b -> c -> a\".\n const badPathFormatted = badPath.filter((element) => !!element).join(\" => \");\n\n // No need to continue, we found a circular dependency.\n throw new Error(`circular dependency found in branch node references: ${badPathFormatted}`);\n }\n\n for (const ref of mapping.refs) {\n // Find the mapping for the root node with an identifer matching the current ref.\n const subMapping = rootNodeMappings.find(({ id }) => id === ref);\n\n // We may not have a mapping for this ref, which is normal when we aren't considering all globally registered subtrees.\n if (subMapping) {\n followRefs(subMapping, [...path, mapping.id]);\n } else if (includesGlobalSubtrees) {\n // We found a reference to a root node that doesn't exist, which is a problem seeing as the root node definitons includes all globally registered subtrees.\n throw new Error(\n mapping.id\n ? `subtree '${mapping.id}' has branch node that references root node '${ref}' which has not been defined`\n : `primary tree has branch node that references root node '${ref}' which has not been defined`\n );\n }\n }\n };\n\n // Start looking for circular dependencies and broken references from the primary root node definition.\n followRefs(rootNodeMappings.find((mapping) => typeof mapping.id === \"undefined\")!);\n}\n\n/**\n * Validate an object that we expect to be a node definition.\n * @param definition An object that we expect to be a node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateNode(definition: any, depth: number): void {\n // Every node must be valid object and have a non-empty 'type' string property.\n if (typeof definition !== \"object\" || typeof definition.type !== \"string\" || definition.type.length === 0) {\n throw new Error(\n `node definition is not an object or 'type' property is not a non-empty string at depth '${depth}'`\n );\n }\n\n // How we validate this node definition will depend on its type.\n switch (definition.type) {\n case \"action\":\n validateActionNode(definition, depth);\n break;\n\n case \"condition\":\n validateConditionNode(definition, depth);\n break;\n\n case \"wait\":\n validateWaitNode(definition, depth);\n break;\n\n case \"branch\":\n validateBranchNode(definition, depth);\n break;\n\n case \"root\":\n validateRootNode(definition, depth);\n break;\n\n case \"succeed\":\n validateSucceedNode(definition, depth);\n break;\n\n case \"fail\":\n validateFailNode(definition, depth);\n break;\n\n case \"flip\":\n validateFlipNode(definition, depth);\n break;\n\n case \"repeat\":\n validateRepeatNode(definition, depth);\n break;\n\n case \"retry\":\n validateRetryNode(definition, depth);\n break;\n\n case \"sequence\":\n validateSequenceNode(definition, depth);\n break;\n\n case \"selector\":\n validateSelectorNode(definition, depth);\n break;\n\n case \"parallel\":\n validateParallelNode(definition, depth);\n break;\n\n case \"lotto\":\n validateLottoNode(definition, depth);\n break;\n\n default:\n throw new Error(`unexpected node type of '${definition.type}' at depth '${depth}'`);\n }\n}\n\n/**\n * Validate any attributes for a given node definition.\n * @param definition The node definition.\n * @param depth The depth of the node in the behaviour tree definition.\n */\nfunction validateNodeAttributes(definition: any, depth: number): void {\n // Validate each of the attribute types for this node.\n [\"while\", \"until\", \"entry\", \"exit\", \"step\"].forEach((attributeName) => {\n // Attempt to grab the definition for the current attribute from the node definition.\n const attributeDefinition = definition[attributeName];\n\n // All node attributes are optional, so there is nothing to do if the current attribute is not defined.\n if (typeof attributeDefinition === \"undefined\") {\n return;\n }\n\n // The attribute definition must be an object.\n if (typeof attributeDefinition !== \"object\") {\n throw new Error(\n `expected attribute '${attributeName}' to be an object for '${definition.type}' node at depth '${depth}'`\n );\n }\n\n // The 'call' property must be defined for any attribute definition.\n if (typeof attributeDefinition.call !== \"string\" || attributeDefinition.call.length === 0) {\n throw new Error(\n `expected 'call' property for attribute '${attributeName}' to be a non-empty string for '${definition.type}' node at depth '${depth}'`\n );\n }\n\n // If any node attribute arguments have been defined then they must have been defined in an array.\n if (typeof attributeDefinition.args !== \"undefined\" && !Array.isArray(attributeDefinition.args)) {\n throw new Error(\n `expected 'args' property for attribute '${attributeName}' to be an array for '${definition.type}' node at depth '${depth}'`\n );\n }\n });\n}\n\n/**\n * Validate an object that we expect to be a root node definition.\n * @param definition An object that we expect to be a root node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateRootNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"root\") {\n throw new Error(\"expected node type of 'root' for root node\");\n }\n\n // A root node cannot be the child of another node.\n if (depth > 0) {\n throw new Error(\"a root node cannot be the child of another node\");\n }\n\n // Check that, if the root node 'id' property is defined, it is a non-empty string.\n if (typeof definition.id !== \"undefined\" && (typeof definition.id !== \"string\" || definition.id.length === 0)) {\n throw new Error(\"expected non-empty string for 'id' property if defined for root node\");\n }\n\n // A root node is a decorator node, so must have a child node defined.\n if (typeof definition.child === \"undefined\") {\n throw new Error(\"expected property 'child' to be defined for root node\");\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n\n // Validate the child node of this decorator node.\n validateNode(definition.child, depth + 1);\n}\n\n/**\n * Validate an object that we expect to be a succeed node definition.\n * @param definition An object that we expect to be a succeed node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateSucceedNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"succeed\") {\n throw new Error(`expected node type of 'succeed' for succeed node at depth '${depth}'`);\n }\n\n // A succeed node is a decorator node, so must have a child node defined.\n if (typeof definition.child === \"undefined\") {\n throw new Error(`expected property 'child' to be defined for succeed node at depth '${depth}'`);\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n\n // Validate the child node of this decorator node.\n validateNode(definition.child, depth + 1);\n}\n\n/**\n * Validate an object that we expect to be a fail node definition.\n * @param definition An object that we expect to be a fail node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateFailNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"fail\") {\n throw new Error(`expected node type of 'fail' for fail node at depth '${depth}'`);\n }\n\n // A fail node is a decorator node, so must have a child node defined.\n if (typeof definition.child === \"undefined\") {\n throw new Error(`expected property 'child' to be defined for fail node at depth '${depth}'`);\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n\n // Validate the child node of this decorator node.\n validateNode(definition.child, depth + 1);\n}\n\n/**\n * Validate an object that we expect to be a flip node definition.\n * @param definition An object that we expect to be a flip node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateFlipNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"flip\") {\n throw new Error(`expected node type of 'flip' for flip node at depth '${depth}'`);\n }\n\n // A flip node is a decorator node, so must have a child node defined.\n if (typeof definition.child === \"undefined\") {\n throw new Error(`expected property 'child' to be defined for flip node at depth '${depth}'`);\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n\n // Validate the child node of this decorator node.\n validateNode(definition.child, depth + 1);\n}\n\n/**\n * Validate an object that we expect to be a repeat node definition.\n * @param definition An object that we expect to be a repeat node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateRepeatNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"repeat\") {\n throw new Error(`expected node type of 'repeat' for repeat node at depth '${depth}'`);\n }\n\n // A repeat node is a decorator node, so must have a child node defined.\n if (typeof definition.child === \"undefined\") {\n throw new Error(`expected property 'child' to be defined for repeat node at depth '${depth}'`);\n }\n\n // Check whether an 'iterations' property has been defined, it may not have been if this node is to repeat indefinitely.\n if (typeof definition.iterations !== \"undefined\") {\n if (Array.isArray(definition.iterations)) {\n // Check whether any elements of the array are not integer values.\n const containsNonInteger = !!definition.iterations.filter((value: unknown) => !isInteger(value)).length;\n\n // If the 'iterations' property is an array then it MUST contain two integer values.\n if (definition.iterations.length !== 2 || containsNonInteger) {\n throw new Error(\n `expected array containing two integer values for 'iterations' property if defined for repeat node at depth '${depth}'`\n );\n }\n\n // A repeat node must have a positive min and max iterations count if they are defined.\n if (definition.iterations[0] < 0 || definition.iterations[1] < 0) {\n throw new Error(\n `expected positive minimum and maximum iterations count for 'iterations' property if defined for repeat node at depth '${depth}'`\n );\n }\n\n // A repeat node must not have a minimum iterations count that exceeds the maximum iterations count.\n if (definition.iterations[0] > definition.iterations[1]) {\n throw new Error(\n `expected minimum iterations count that does not exceed the maximum iterations count for 'iterations' property if defined for repeat node at depth '${depth}'`\n );\n }\n } else if (isInteger(definition.iterations)) {\n // A repeat node must have a positive number of iterations if defined.\n if (definition.iterations < 0) {\n throw new Error(\n `expected positive iterations count for 'iterations' property if defined for repeat node at depth '${depth}'`\n );\n }\n } else {\n throw new Error(\n `expected integer value or array containing two integer values for 'iterations' property if defined for repeat node at depth '${depth}'`\n );\n }\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n\n // Validate the child node of this decorator node.\n validateNode(definition.child, depth + 1);\n}\n\n/**\n * Validate an object that we expect to be a retry node definition.\n * @param definition An object that we expect to be a retry node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateRetryNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"retry\") {\n throw new Error(`expected node type of 'retry' for retry node at depth '${depth}'`);\n }\n\n // A retry node is a decorator node, so must have a child node defined.\n if (typeof definition.child === \"undefined\") {\n throw new Error(`expected property 'child' to be defined for retry node at depth '${depth}'`);\n }\n\n // Check whether an 'attempts' property has been defined, it may not have been if this node is to retry indefinitely.\n if (typeof definition.attempts !== \"undefined\") {\n if (Array.isArray(definition.attempts)) {\n // Check whether any elements of the array are not integer values.\n const containsNonInteger = !!definition.attempts.filter((value: unknown) => !isInteger(value)).length;\n\n // If the 'attempts' property is an array then it MUST contain two integer values.\n if (definition.attempts.length !== 2 || containsNonInteger) {\n throw new Error(\n `expected array containing two integer values for 'attempts' property if defined for retry node at depth '${depth}'`\n );\n }\n\n // A retry node must have a positive min and max attempts count if they are defined.\n if (definition.attempts[0] < 0 || definition.attempts[1] < 0) {\n throw new Error(\n `expected positive minimum and maximum attempts count for 'attempts' property if defined for retry node at depth '${depth}'`\n );\n }\n\n // A retry node must not have a minimum attempts count that exceeds the maximum attempts count.\n if (definition.attempts[0] > definition.attempts[1]) {\n throw new Error(\n `expected minimum attempts count that does not exceed the maximum attempts count for 'attempts' property if defined for retry node at depth '${depth}'`\n );\n }\n } else if (isInteger(definition.attempts)) {\n // A retry node must have a positive number of attempts if defined.\n if (definition.attempts < 0) {\n throw new Error(\n `expected positive attempts count for 'attempts' property if defined for retry node at depth '${depth}'`\n );\n }\n } else {\n throw new Error(\n `expected integer value or array containing two integer values for 'attempts' property if defined for retry node at depth '${depth}'`\n );\n }\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n\n // Validate the child node of this decorator node.\n validateNode(definition.child, depth + 1);\n}\n\n/**\n * Validate an object that we expect to be a branch node definition.\n * @param definition An object that we expect to be a branch node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateBranchNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"branch\") {\n throw new Error(`expected node type of 'branch' for branch node at depth '${depth}'`);\n }\n\n // Check that the branch node 'ref' property is defined and is a non-empty string.\n if (typeof definition.ref !== \"string\" || definition.ref.length === 0) {\n throw new Error(`expected non-empty string for 'ref' property for branch node at depth '${depth}'`);\n }\n\n // It is invalid to define guard attributes for a branch node as they should be defined on the referenced root node.\n [\"while\", \"until\"].forEach((attributeName) => {\n if (typeof definition[attributeName] !== \"undefined\") {\n throw new Error(\n `guards should not be defined for branch nodes but guard '${attributeName}' was defined for branch node at depth '${depth}'`\n );\n }\n });\n\n // It is invalid to define callback attributes for a branch node as they should be defined on the referenced root node.\n [\"entry\", \"exit\", \"step\"].forEach((attributeName) => {\n if (typeof definition[attributeName] !== \"undefined\") {\n throw new Error(\n `callbacks should not be defined for branch nodes but callback '${attributeName}' was defined for branch node at depth '${depth}'`\n );\n }\n });\n}\n\n/**\n * Validate an object that we expect to be a action node definition.\n * @param definition An object that we expect to be a action node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateActionNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"action\") {\n throw new Error(`expected node type of 'action' for action node at depth '${depth}'`);\n }\n\n // The 'call' property must be defined for a action node definition.\n if (typeof definition.call !== \"string\" || definition.call.length === 0) {\n throw new Error(`expected non-empty string for 'call' property of action node at depth '${depth}'`);\n }\n\n // If any action function arguments have been defined then they must have been defined in an array.\n if (typeof definition.args !== \"undefined\" && !Array.isArray(definition.args)) {\n throw new Error(`expected array for 'args' property if defined for action node at depth '${depth}'`);\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n}\n\n/**\n * Validate an object that we expect to be a condition node definition.\n * @param definition An object that we expect to be a condition node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateConditionNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"condition\") {\n throw new Error(`expected node type of 'condition' for condition node at depth '${depth}'`);\n }\n\n // The 'call' property must be defined for a condition node definition.\n if (typeof definition.call !== \"string\" || definition.call.length === 0) {\n throw new Error(`expected non-empty string for 'call' property of condition node at depth '${depth}'`);\n }\n\n // If any condition function arguments have been defined then they must have been defined in an array.\n if (typeof definition.args !== \"undefined\" && !Array.isArray(definition.args)) {\n throw new Error(`expected array for 'args' property if defined for condition node at depth '${depth}'`);\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n}\n\n/**\n * Validate an object that we expect to be a wait node definition.\n * @param definition An object that we expect to be a wait node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateWaitNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"wait\") {\n throw new Error(`expected node type of 'wait' for wait node at depth '${depth}'`);\n }\n\n // Check whether a 'duration' property has been defined, it may not have been if this node is to wait indefinitely.\n if (typeof definition.duration !== \"undefined\") {\n if (Array.isArray(definition.duration)) {\n // Check whether any elements of the array are not integer values.\n const containsNonInteger = !!definition.duration.filter((value: unknown) => !isInteger(value)).length;\n\n // If the 'duration' property is an array then it MUST contain two integer values.\n if (definition.duration.length !== 2 || containsNonInteger) {\n throw new Error(\n `expected array containing two integer values for 'duration' property if defined for wait node at depth '${depth}'`\n );\n }\n\n // A wait node must have a positive min and max duration value if they are defined.\n if (definition.duration[0] < 0 || definition.duration[1] < 0) {\n throw new Error(\n `expected positive minimum and maximum duration for 'duration' property if defined for wait node at depth '${depth}'`\n );\n }\n\n // A wait node must not have a minimum duration value that exceeds the maximum duration value.\n if (definition.duration[0] > definition.duration[1]) {\n throw new Error(\n `expected minimum duration value that does not exceed the maximum duration value for 'duration' property if defined for wait node at depth '${depth}'`\n );\n }\n } else if (isInteger(definition.duration)) {\n // A wait node must have a positive duration value if defined.\n if (definition.duration < 0) {\n throw new Error(\n `expected positive duration value for 'duration' property if defined for wait node at depth '${depth}'`\n );\n }\n } else {\n throw new Error(\n `expected integer value or array containing two integer values for 'duration' property if defined for wait node at depth '${depth}'`\n );\n }\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n}\n\n/**\n * Validate an object that we expect to be a sequence node definition.\n * @param definition An object that we expect to be a sequence node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateSequenceNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"sequence\") {\n throw new Error(`expected node type of 'sequence' for sequence node at depth '${depth}'`);\n }\n\n // A sequence node is a composite node, so must have a children nodes array defined.\n if (!Array.isArray(definition.children) || definition.children.length === 0) {\n throw new Error(`expected non-empty 'children' array to be defined for sequence node at depth '${depth}'`);\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n\n // Validate the child nodes of this composite node.\n definition.children.forEach((child: any) => validateNode(child, depth + 1));\n}\n\n/**\n * Validate an object that we expect to be a selector node definition.\n * @param definition An object that we expect to be a selector node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateSelectorNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"selector\") {\n throw new Error(`expected node type of 'selector' for selector node at depth '${depth}'`);\n }\n\n // A selector node is a composite node, so must have a children nodes array defined.\n if (!Array.isArray(definition.children) || definition.children.length === 0) {\n throw new Error(`expected non-empty 'children' array to be defined for selector node at depth '${depth}'`);\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n\n // Validate the child nodes of this composite node.\n definition.children.forEach((child: any) => validateNode(child, depth + 1));\n}\n\n/**\n * Validate an object that we expect to be a parallel node definition.\n * @param definition An object that we expect to be a parallel node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateParallelNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"parallel\") {\n throw new Error(`expected node type of 'parallel' for parallel node at depth '${depth}'`);\n }\n\n // A parallel node is a composite node, so must have a children nodes array defined.\n if (!Array.isArray(definition.children) || definition.children.length === 0) {\n throw new Error(`expected non-empty 'children' array to be defined for parallel node at depth '${depth}'`);\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n\n // Validate the child nodes of this composite node.\n definition.children.forEach((child: any) => validateNode(child, depth + 1));\n}\n\n/**\n * Validate an object that we expect to be a lotto node definition.\n * @param definition An object that we expect to be a lotto node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateLottoNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"lotto\") {\n throw new Error(`expected node type of 'lotto' for lotto node at depth '${depth}'`);\n }\n\n // A lotto node is a composite node, so must have a children nodes array defined.\n if (!Array.isArray(definition.children) || definition.children.length === 0) {\n throw new Error(`expected non-empty 'children' array to be defined for lotto node at depth '${depth}'`);\n }\n\n // Check whether a 'weights' property has been defined, if it has we expect it to be an array of weights.\n if (typeof definition.weights !== \"undefined\") {\n // Check that the weights property is an array of positive integers with an element for each child node element.\n if (\n !Array.isArray(definition.weights) ||\n definition.weights.length !== definition.children.length ||\n definition.weights.filter((value: unknown) => !isInteger(value)).length ||\n definition.weights.filter((value: number) => value < 0).length\n ) {\n throw new Error(\n `expected an array of positive integer weight values with a length matching the number of child nodes for 'weights' property if defined for lotto node at depth '${depth}'`\n );\n }\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n\n // Validate the child nodes of this composite node.\n definition.children.forEach((child: any) => validateNode(child, depth + 1));\n}\n\n/**\n * A helper function to create a failure validation result with the given error message.\n * @param errorMessage The validation failure error message.\n * @returns A failure validation result with the given error message.\n */\nfunction createValidationFailureResult(errorMessage: string): DefinitionValidationResult {\n return { succeeded: false, errorMessage };\n}\n", "import { ActionResult, Agent, GlobalFunction } from \"./Agent\";\nimport { RootNodeDefinition } from \"./BehaviourTreeDefinition\";\n\nexport type InvokerFunction = (args: any[]) => ActionResult;\n\n/**\n * A singleton used to store and lookup registered functions and subtrees.\n */\nexport default class Lookup {\n /**\n * The object holding any registered functions keyed on function name.\n */\n private static functionTable: { [key: string]: GlobalFunction } = {};\n /**\n * The object holding any registered subtree root node definitions keyed on tree name.\n */\n private static subtreeTable: { [key: string]: RootNodeDefinition } = {};\n\n /**\n * Gets the function with the specified name.\n * @param name The name of the function.\n * @returns The function with the specified name.\n */\n public static getFunc(name: string): GlobalFunction {\n return this.functionTable[name];\n }\n\n /**\n * Sets the function with the specified name for later lookup.\n * @param name The name of the function.\n * @param func The function.\n */\n public static setFunc(name: string, func: GlobalFunction): void {\n this.functionTable[name] = func;\n }\n\n /**\n * Gets the function invoker for the specified agent and function name.\n * If a function with the specified name exists on the agent object then it will\n * be returned, otherwise we will then check the registered functions for a match.\n * @param agent The agent instance that this behaviour tree is modelling behaviour for.\n * @param name The function name.\n * @returns The function invoker for the specified agent and function name.\n */\n static getFuncInvoker(agent: Agent, name: string): InvokerFunction | null {\n // Check whether the agent contains the specified function.\n const foundOnAgent = agent[name];\n if (foundOnAgent && typeof foundOnAgent === \"function\") {\n return (args: any[]): boolean | ActionResult => foundOnAgent.apply(agent, args);\n }\n\n // The agent does not contain the specified function but it may have been registered at some point.\n if (this.functionTable[name] && typeof this.functionTable[name] === \"function\") {\n return (args: any[]) => this.functionTable[name](agent, ...args.map((arg) => arg.value));\n }\n\n // We have no function to invoke.\n return null;\n }\n\n /**\n * Gets all registered subtree root node definitions.\n */\n static getSubtrees(): { [key: string]: RootNodeDefinition } {\n return this.subtreeTable;\n }\n\n /**\n * Sets the subtree with the specified name for later lookup.\n * @param name The name of the subtree.\n * @param subtree The subtree.\n */\n static setSubtree(name: string, subtree: RootNodeDefinition) {\n this.subtreeTable[name] = subtree;\n }\n\n /**\n * Removes the registered function or subtree with the specified name.\n * @param name The name of the registered function or subtree.\n */\n static remove(name: string) {\n delete this.functionTable[name];\n delete this.subtreeTable[name];\n }\n\n /**\n * Remove all registered functions and subtrees.\n */\n static empty() {\n this.functionTable = {};\n this.subtreeTable = {};\n }\n}\n", "import Node from \"../../nodes/Node\";\n\n/**\n * An exception thrown when evaluating node guard path conditions and a conditions fails.\n */\nexport default class GuardUnsatisifedException extends Error {\n /**\n * @param source The node at which a guard condition failed.\n */\n constructor(private source: Node) {\n super(\"A guard path condition has failed\");\n }\n\n /**\n * Gets whether the specified node is the node at which a guard condition failed.\n * @param node The node to check against the source node.\n * @returns Whether the specified node is the node at which a guard condition failed.\n */\n isSourceNode = (node: Node) => node === this.source;\n}\n", "import { Agent } from \"../../Agent\";\nimport Guard from \"./Guard\";\nimport Node from \"../../nodes/Node\";\nimport GuardUnsatisifedException from \"./GuardUnsatisifedException\";\n\nexport type GuardPathPart = {\n node: Node;\n guards: Guard[];\n};\n\n/**\n * Represents a path of node guards along a root-to-leaf tree path.\n */\nexport default class GuardPath {\n /**\n * @param nodes An array of objects defining a node instance -> guard link, ordered by node depth.\n */\n constructor(private nodes: GuardPathPart[]) {}\n\n /**\n * Evaluate guard conditions for all guards in the tree path, moving outwards from the root.\n * @param agent The agent, required for guard evaluation.\n * @returns An evaluation results object.\n */\n evaluate = (agent: Agent) => {\n // We need to evaluate guard conditions for nodes up the tree, moving outwards from the root.\n for (const details of this.nodes) {\n // There can be multiple guards per node.\n for (const guard of details.guards) {\n // Check whether the guard condition passes, and throw an exception if not.\n if (!guard.isSatisfied(agent)) {\n throw new GuardUnsatisifedException(details.node);\n }\n }\n }\n };\n}\n", "import { BehaviourTreeOptions } from \"../BehaviourTreeOptions\";\nimport State, { AnyState } from \"../State\";\nimport { Agent } from \"../Agent\";\nimport Leaf from \"./leaf/Leaf\";\nimport Attribute from \"../attributes/Attribute\";\nimport Entry from \"../attributes/callbacks/Entry\";\nimport Exit from \"../attributes/callbacks/Exit\";\nimport Step from \"../attributes/callbacks/Step\";\nimport Guard from \"../attributes/guards/Guard\";\nimport GuardPath from \"../attributes/guards/GuardPath\";\nimport GuardUnsatisifedException from \"../attributes/guards/GuardUnsatisifedException\";\n\n/**\n * A base node.\n */\nexport default abstract class Node {\n /**\n * The node uid.\n */\n private readonly uid: string = createNodeUid();\n /**\n * The node state.\n */\n private state: AnyState = State.READY;\n /**\n * The guard path to evaluate as part of a node update.\n */\n private guardPath: GuardPath | undefined;\n\n /**\n * @param type The node type.\n * @param attributes The node attributes.\n * @param args The node argument definitions.\n */\n constructor(private type: string, private attributes: Attribute[], private args: any[]) {}\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected abstract onUpdate(agent: Agent, options: BehaviourTreeOptions): void;\n\n /**\n * Gets the name of the node.\n */\n public abstract getName(): string;\n\n /**\n * Gets whether this node is a leaf node.\n */\n public abstract isLeafNode: () => this is Leaf;\n\n /**\n * Gets/Sets the state of the node.\n */\n getState = (): AnyState => this.state;\n setState = (value: AnyState): void => {\n this.state = value;\n };\n\n /**\n * Gets the unique id of the node.\n */\n getUid = () => this.uid;\n\n /**\n * Gets the type of the node.\n */\n getType = () => this.type;\n\n /**\n * Gets the node attributes.\n */\n getAttributes = () => this.attributes;\n\n /**\n * Gets the node arguments.\n */\n getArguments = () => this.args;\n\n /**\n * Gets the node attribute with the specified type, or null if it does not exist.\n */\n getAttribute(type: \"entry\" | \"ENTRY\"): Entry;\n getAttribute(type: \"exit\" | \"EXIT\"): Exit;\n getAttribute(type: \"step\" | \"STEP\"): Step;\n getAttribute(type: string): Attribute {\n return (\n this.getAttributes().filter((decorator) => decorator.type.toUpperCase() === type.toUpperCase())[0] || null\n );\n }\n\n /**\n * Gets the node attributes.\n */\n getGuardAttributes = (): Guard[] => this.getAttributes().filter((decorator) => decorator.isGuard()) as Guard[];\n\n /**\n * Sets the guard path to evaluate as part of a node update.\n */\n setGuardPath = (value: GuardPath) => (this.guardPath = value);\n\n /**\n * Gets whether a guard path is assigned to this node.\n */\n hasGuardPath = () => !!this.guardPath;\n\n /**\n * Gets whether this node is in the specified state.\n * @param value The value to compare to the node state.\n */\n public is(value: AnyState): boolean {\n return this.state === value;\n }\n\n /**\n * Reset the state of the node.\n */\n public reset(): void {\n this.setState(State.READY);\n }\n\n /**\n * Abort the running of this node.\n * @param agent The agent.\n */\n public abort(agent: Agent): void {\n // There is nothing to do if this node is not in the running state.\n if (!this.is(State.RUNNING)) {\n return;\n }\n\n // Reset the state of this node.\n this.reset();\n\n this.getAttribute(\"exit\")?.callAgentFunction(agent, false, true);\n }\n\n /**\n * Update the node.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n * @returns The result of the update.\n */\n public update(agent: Agent, options: BehaviourTreeOptions): void {\n // If this node is already in a 'SUCCEEDED' or 'FAILED' state then there is nothing to do.\n if (this.is(State.SUCCEEDED) || this.is(State.FAILED)) {\n return;\n }\n\n try {\n // Evaluate all of the guard path conditions for the current tree path.\n this.guardPath!.evaluate(agent);\n\n // If this node is in the READY state then call the ENTRY for this node if it exists.\n if (this.is(State.READY)) {\n this.getAttribute(\"entry\")?.callAgentFunction(agent);\n }\n\n this.getAttribute(\"step\")?.callAgentFunction(agent);\n\n // Do the actual update.\n this.onUpdate(agent, options);\n\n // If this node is now in a 'SUCCEEDED' or 'FAILED' state then call the EXIT for this node if it exists.\n if (this.is(State.SUCCEEDED) || this.is(State.FAILED)) {\n this.getAttribute(\"exit\")?.callAgentFunction(agent, this.is(State.SUCCEEDED), false);\n }\n } catch (error) {\n // If the error is a GuardUnsatisfiedException then we need to determine if this node is the source.\n if (error instanceof GuardUnsatisifedException && error.isSourceNode(this)) {\n // Abort the current node.\n this.abort(agent);\n\n // Any node that is the source of an abort will be a failed node.\n this.setState(State.FAILED);\n } else {\n throw error;\n }\n }\n }\n}\n\n/**\n * Create a randomly generated node uid.\n * @returns A randomly generated node uid.\n */\nfunction createNodeUid(): string {\n var S4 = function () {\n return (((1 + Math.random()) * 0x10000) | 0).toString(16).substring(1);\n };\n return S4() + S4() + \"-\" + S4() + \"-\" + S4() + \"-\" + S4() + \"-\" + S4() + S4() + S4();\n}\n", "import Node from \"../Node\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\n\n/**\n * A composite node that wraps child nodes.\n */\nexport default abstract class Composite extends Node {\n /**\n * @param type The node type.\n * @param attributes The node attributes.\n * @param children The child nodes.\n */\n constructor(type: string, attributes: Attribute[], protected children: Node[]) {\n super(type, attributes, []);\n }\n\n /**\n * Gets whether this node is a leaf node.\n */\n isLeafNode = () => false;\n\n /**\n * Gets the children of this node.\n */\n getChildren = () => this.children;\n\n /**\n * Reset the state of the node.\n */\n reset = () => {\n // Reset the state of this node.\n this.setState(State.READY);\n\n // Reset the state of any child nodes.\n this.getChildren().forEach((child) => child.reset());\n };\n\n /**\n * Abort the running of this node.\n * @param agent The agent.\n */\n abort = (agent: Agent) => {\n // There is nothing to do if this node is not in the running state.\n if (!this.is(State.RUNNING)) {\n return;\n }\n\n // Abort any child nodes.\n this.getChildren().forEach((child) => child.abort(agent));\n\n // Reset the state of this node.\n this.reset();\n\n this.getAttribute(\"exit\")?.callAgentFunction(agent, false, true);\n };\n}\n", "import Composite from \"./Composite\";\nimport State from \"../../State\";\nimport Node from \"../Node\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A PARALLEL node.\n * The child nodes are executed concurrently until one fails or all succeed.\n */\nexport default class Parallel extends Composite {\n /**\n * @param attributes The node attributes.\n * @param children The child nodes.\n */\n constructor(attributes: Attribute[], children: Node[]) {\n super(\"parallel\", attributes, children);\n }\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // Keep a count of the number of succeeded child nodes.\n let succeededCount = 0;\n\n let hasChildFailed = false;\n\n // Iterate over all of the children of this node.\n for (const child of this.children) {\n // If the child has never been updated or is running then we will need to update it now.\n if (child.getState() === State.READY || child.getState() === State.RUNNING) {\n // Update the child of this node.\n child.update(agent, options);\n }\n\n // If the current child has a state of 'SUCCEEDED' then we should move on to the next child.\n if (child.getState() === State.SUCCEEDED) {\n // The child node has succeeded, keep track of this to determine if all children have.\n succeededCount++;\n\n // The child node succeeded, but we have not finished checking every child node yet.\n continue;\n }\n\n // If the current child has a state of 'FAILED' then this node is also a 'FAILED' node.\n if (child.getState() === State.FAILED) {\n hasChildFailed = true;\n\n // There is no need to check the rest of the children.\n break;\n }\n\n // The node should be in the 'RUNNING' state.\n if (child.getState() !== State.RUNNING) {\n // The child node was not in an expected state.\n throw new Error(\"child node was not in an expected state.\");\n }\n }\n\n if (hasChildFailed) {\n // This node is a 'FAILED' node.\n this.setState(State.FAILED);\n\n // Abort every running child.\n for (const child of this.children) {\n if (child.getState() === State.RUNNING) {\n child.abort(agent);\n }\n }\n } else {\n // If all children have succeeded then this node has also succeeded, otherwise it is still running.\n this.setState(succeededCount === this.children.length ? State.SUCCEEDED : State.RUNNING);\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => \"PARALLEL\";\n}\n", "import Composite from \"./Composite\";\nimport Node from \"../Node\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A SELECTOR node.\n * The child nodes are executed in sequence until one succeeds or all fail.\n */\nexport default class Selector extends Composite {\n /**\n * @param attributes The node attributes.\n * @param children The child nodes.\n */\n constructor(attributes: Attribute[], protected children: Node[]) {\n super(\"selector\", attributes, children);\n }\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // Iterate over all of the children of this node.\n for (const child of this.children) {\n // If the child has never been updated or is running then we will need to update it now.\n if (child.getState() === State.READY || child.getState() === State.RUNNING) {\n // Update the child of this node.\n child.update(agent, options);\n }\n\n // If the current child has a state of 'SUCCEEDED' then this node is also a 'SUCCEEDED' node.\n if (child.getState() === State.SUCCEEDED) {\n // This node is a 'SUCCEEDED' node.\n this.setState(State.SUCCEEDED);\n\n // There is no need to check the rest of the selector nodes.\n return;\n }\n\n // If the current child has a state of 'FAILED' then we should move on to the next child.\n if (child.getState() === State.FAILED) {\n // Find out if the current child is the last one in the selector.\n // If it is then this sequence node has also failed.\n if (this.children.indexOf(child) === this.children.length - 1) {\n // This node is a 'FAILED' node.\n this.setState(State.FAILED);\n\n // There is no need to check the rest of the selector as we have completed it.\n return;\n } else {\n // The child node failed, try the next one.\n continue;\n }\n }\n\n // The node should be in the 'RUNNING' state.\n if (child.getState() === State.RUNNING) {\n // This node is a 'RUNNING' node.\n this.setState(State.RUNNING);\n\n // There is no need to check the rest of the selector as the current child is still running.\n return;\n }\n\n // The child node was not in an expected state.\n throw new Error(\"child node was not in an expected state.\");\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => \"SELECTOR\";\n}\n", "import Composite from \"./Composite\";\nimport Node from \"../Node\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A SEQUENCE node.\n * The child nodes are executed in sequence until one fails or all succeed.\n */\nexport default class Sequence extends Composite {\n /**\n * @param attributes The node attributes.\n * @param children The child nodes.\n */\n constructor(attributes: Attribute[], protected children: Node[]) {\n super(\"sequence\", attributes, children);\n }\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // Iterate over all of the children of this node.\n for (const child of this.children) {\n // If the child has never been updated or is running then we will need to update it now.\n if (child.getState() === State.READY || child.getState() === State.RUNNING) {\n // Update the child of this node.\n child.update(agent, options);\n }\n\n // If the current child has a state of 'SUCCEEDED' then we should move on to the next child.\n if (child.getState() === State.SUCCEEDED) {\n // Find out if the current child is the last one in the sequence.\n // If it is then this sequence node has also succeeded.\n if (this.children.indexOf(child) === this.children.length - 1) {\n // This node is a 'SUCCEEDED' node.\n this.setState(State.SUCCEEDED);\n\n // There is no need to check the rest of the sequence as we have completed it.\n return;\n } else {\n // The child node succeeded, but we have not finished the sequence yet.\n continue;\n }\n }\n\n // If the current child has a state of 'FAILED' then this node is also a 'FAILED' node.\n if (child.getState() === State.FAILED) {\n // This node is a 'FAILED' node.\n this.setState(State.FAILED);\n\n // There is no need to check the rest of the sequence.\n return;\n }\n\n // The node should be in the 'RUNNING' state.\n if (child.getState() === State.RUNNING) {\n // This node is a 'RUNNING' node.\n this.setState(State.RUNNING);\n\n // There is no need to check the rest of the sequence as the current child is still running.\n return;\n }\n\n // The child node was not in an expected state.\n throw new Error(\"child node was not in an expected state.\");\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => \"SEQUENCE\";\n}\n", "import createLotto from \"lotto-draw\";\n\nimport Node from \"../Node\";\nimport Composite from \"./Composite\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A LOTTO node.\n * A winning child is picked on the initial update of this node, based on ticket weighting.\n * The state of this node will match the state of the winning child.\n */\nexport default class Lotto extends Composite {\n /**\n * @param attributes The node attributes.\n * @param weights The child node weights.\n * @param children The child nodes.\n */\n constructor(attributes: Attribute[], private weights: number[] | undefined, children: Node[]) {\n super(\"lotto\", attributes, children);\n }\n\n /**\n * The child node selected to be the active one.\n */\n private selectedChild: Node | undefined;\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // If this node is in the READY state then we need to pick a winning child node.\n if (this.is(State.READY)) {\n // Create a lotto draw with which to randomly pick a child node to become the active one.\n const lottoDraw = createLotto({\n // Hook up the optional 'random' behaviour tree function option to the one used by 'lotto-draw'.\n random: options.random,\n // Pass in each child node as a participant in the lotto draw with their respective ticket count.\n participants: this.children.map((child, index) => [child, this.weights?.[index] || 1])\n });\n\n // Randomly pick a child based on ticket weighting, this will become the active child for this composite node.\n this.selectedChild = lottoDraw.draw() || undefined;\n }\n\n // If something went wrong and we don't have an active child then we should throw an error.\n if (!this.selectedChild) {\n throw new Error(\"failed to update lotto node as it has no active child\");\n }\n\n // If the selected child has never been updated or is running then we will need to update it now.\n if (this.selectedChild.getState() === State.READY || this.selectedChild.getState() === State.RUNNING) {\n this.selectedChild.update(agent, options);\n }\n\n // The state of the lotto node is the state of its selected child.\n this.setState(this.selectedChild.getState());\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => (this.weights ? `LOTTO [${this.weights.join(\",\")}]` : \"LOTTO\");\n}\n", "import Node from \"../Node\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\n\n/**\n * A decorator node that wraps a single child node.\n */\nexport default abstract class Decorator extends Node {\n /**\n * @param type The node type.\n * @param attributes The node attributes.\n * @param child The child node.\n */\n constructor(type: string, attributes: Attribute[], protected child: Node) {\n super(type, attributes, []);\n }\n\n /**\n * Gets whether this node is a leaf node.\n */\n isLeafNode = () => false;\n\n /**\n * Gets the children of this node.\n */\n getChildren = () => [this.child];\n\n /**\n * Reset the state of the node.\n */\n reset = () => {\n // Reset the state of this node.\n this.setState(State.READY);\n\n // Reset the state of the child node.\n this.child.reset();\n };\n\n /**\n * Abort the running of this node.\n * @param agent The agent.\n */\n abort = (agent: Agent) => {\n // There is nothing to do if this node is not in the running state.\n if (!this.is(State.RUNNING)) {\n return;\n }\n\n // Abort the child node.\n this.child.abort(agent);\n\n // Reset the state of this node.\n this.reset();\n\n this.getAttribute(\"exit\")?.callAgentFunction(agent, false, true);\n };\n}\n", "import Node from \"../Node\";\nimport Decorator from \"./Decorator\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A Fail node.\n * This node wraps a single child and will always move to the 'FAILED' state when the child moves to a 'SUCCEEDED' or 'FAILED' state.\n */\nexport default class Fail extends Decorator {\n /**\n * @param attributes The node attributes.\n * @param child The child node.\n */\n constructor(attributes: Attribute[], child: Node) {\n super(\"fail\", attributes, child);\n }\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // If the child has never been updated or is running then we will need to update it now.\n if (this.child.getState() === State.READY || this.child.getState() === State.RUNNING) {\n this.child.update(agent, options);\n }\n\n // The state of this node will depend in the state of its child.\n switch (this.child.getState()) {\n case State.RUNNING:\n this.setState(State.RUNNING);\n break;\n\n case State.SUCCEEDED:\n case State.FAILED:\n this.setState(State.FAILED);\n break;\n\n default:\n this.setState(State.READY);\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => \"FAIL\";\n}\n", "import Decorator from \"./Decorator\";\nimport State from \"../../State\";\nimport Node from \"../Node\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A Flip node.\n * This node wraps a single child and will flip the state of the child state.\n */\nexport default class Flip extends Decorator {\n /**\n * @param attributes The node attributes.\n * @param child The child node.\n */\n constructor(attributes: Attribute[], child: Node) {\n super(\"flip\", attributes, child);\n }\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // If the child has never been updated or is running then we will need to update it now.\n if (this.child.getState() === State.READY || this.child.getState() === State.RUNNING) {\n this.child.update(agent, options);\n }\n\n // The state of this node will depend in the state of its child.\n switch (this.child.getState()) {\n case State.RUNNING:\n this.setState(State.RUNNING);\n break;\n\n case State.SUCCEEDED:\n this.setState(State.FAILED);\n break;\n\n case State.FAILED:\n this.setState(State.SUCCEEDED);\n break;\n\n default:\n this.setState(State.READY);\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => \"FLIP\";\n}\n", "import Node from \"../Node\";\nimport Decorator from \"./Decorator\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A REPEAT node.\n * The node has a single child which can have:\n * -- A number of iterations for which to repeat the child node.\n * -- An infinite repeat loop if neither an iteration count or a condition function is defined.\n * The REPEAT node will stop and have a 'FAILED' state if its child is ever in a 'FAILED' state after an update.\n * The REPEAT node will attempt to move on to the next iteration if its child is ever in a 'SUCCEEDED' state.\n */\nexport default class Repeat extends Decorator {\n /**\n * @param attributes The node attributes.\n * @param iterations The number of iterations to repeat the child node.\n * @param iterationsMin The minimum possible number of iterations to repeat the child node.\n * @param iterationsMax The maximum possible number of iterations to repeat the child node.\n * @param child The child node.\n */\n constructor(\n attributes: Attribute[],\n private iterations: number | null,\n private iterationsMin: number | null,\n private iterationsMax: number | null,\n child: Node\n ) {\n super(\"repeat\", attributes, child);\n }\n\n /**\n * The number of target iterations to make.\n */\n private targetIterationCount: number | null = null;\n\n /**\n * The current iteration count.\n */\n private currentIterationCount: number = 0;\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // If this node is in the READY state then we need to reset the child and the target iteration count.\n if (this.is(State.READY)) {\n // Reset the child node.\n this.child.reset();\n\n // Reset the current iteration count.\n this.currentIterationCount = 0;\n\n // Set the target iteration count.\n this.setTargetIterationCount(options);\n }\n\n // Do a check to see if we can iterate. If we can then this node will move into the 'RUNNING' state.\n // If we cannot iterate then we have hit our target iteration count, which means that the node has succeeded.\n if (this.canIterate()) {\n // This node is in the running state and can do its initial iteration.\n this.setState(State.RUNNING);\n\n // We may have already completed an iteration, meaning that the child node will be in the SUCCEEDED state.\n // If this is the case then we will have to reset the child node now.\n if (this.child.getState() === State.SUCCEEDED) {\n this.child.reset();\n }\n\n // Update the child of this node.\n this.child.update(agent, options);\n\n // If the child moved into the FAILED state when we updated it then there is nothing left to do and this node has also failed.\n // If it has moved into the SUCCEEDED state then we have completed the current iteration.\n if (this.child.getState() === State.FAILED) {\n // The child has failed, meaning that this node has failed.\n this.setState(State.FAILED);\n\n return;\n } else if (this.child.getState() === State.SUCCEEDED) {\n // We have completed an iteration.\n this.currentIterationCount += 1;\n }\n } else {\n // This node is in the 'SUCCEEDED' state as we cannot iterate any more.\n this.setState(State.SUCCEEDED);\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => {\n if (this.iterations !== null) {\n return `REPEAT ${this.iterations}x`;\n } else if (this.iterationsMin !== null && this.iterationsMax !== null) {\n return `REPEAT ${this.iterationsMin}x-${this.iterationsMax}x`;\n } else {\n return \"REPEAT\";\n }\n };\n\n /**\n * Reset the state of the node.\n */\n reset = () => {\n // Reset the state of this node.\n this.setState(State.READY);\n\n // Reset the current iteration count.\n this.currentIterationCount = 0;\n\n // Reset the child node.\n this.child.reset();\n };\n\n /**\n * Gets whether an iteration can be made.\n * @returns Whether an iteration can be made.\n */\n private canIterate = () => {\n if (this.targetIterationCount !== null) {\n // We can iterate as long as we have not reached our target iteration count.\n return this.currentIterationCount < this.targetIterationCount;\n }\n\n // If neither an iteration count or a condition function were defined then we can iterate indefinitely.\n return true;\n };\n\n /**\n * Sets the target iteration count.\n * @param options The behaviour tree options object.\n */\n private setTargetIterationCount = (options: BehaviourTreeOptions) => {\n // Are we dealing with an explicit iteration count or will we be randomly picking a iteration count between the min and max iteration count.\n if (this.iterations !== null) {\n this.targetIterationCount = this.iterations;\n } else if (this.iterationsMin !== null && this.iterationsMax !== null) {\n // We will be picking a random iteration count between a min and max iteration count, if the optional 'random'\n // behaviour tree function option is defined then we will be using that, otherwise we will fall back to using Math.random.\n const random = typeof options.random === \"function\" ? options.random : Math.random;\n\n // Pick a random iteration count between a min and max iteration count.\n this.targetIterationCount = Math.floor(\n random() * (this.iterationsMax - this.iterationsMin + 1) + this.iterationsMin\n );\n } else {\n this.targetIterationCount = null;\n }\n };\n}\n", "import Node from \"../Node\";\nimport Decorator from \"./Decorator\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A RETRY node.\n * The node has a single child which can have:\n * -- A number of iterations for which to repeat the child node.\n * -- An infinite repeat loop if neither an iteration count or a condition function is defined.\n * The RETRY node will stop and have a 'SUCCEEDED' state if its child is ever in a 'SUCCEEDED' state after an update.\n * The RETRY node will attempt to move on to the next iteration if its child is ever in a 'FAILED' state.\n */\nexport default class Retry extends Decorator {\n /**\n * @param attributes The node attributes.\n * @param attempts The number of attempts to retry the child node.\n * @param attemptsMin The minimum possible number of attempts to retry the child node.\n * @param attemptsMax The maximum possible number of attempts to retry the child node.\n * @param child The child node.\n */\n constructor(\n attributes: Attribute[],\n private attempts: number | null,\n private attemptsMin: number | null,\n private attemptsMax: number | null,\n child: Node\n ) {\n super(\"retry\", attributes, child);\n }\n\n /**\n * The number of target attempts to make.\n */\n private targetAttemptCount: number | null = null;\n\n /**\n * The current attempt count.\n */\n private currentAttemptCount: number = 0;\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // If this node is in the READY state then we need to reset the child and the target attempt count.\n if (this.is(State.READY)) {\n // Reset the child node.\n this.child.reset();\n\n // Reset the current attempt count.\n this.currentAttemptCount = 0;\n\n // Set the target attempt count.\n this.setTargetAttemptCount(options);\n }\n\n // Do a check to see if we can attempt. If we can then this node will move into the 'RUNNING' state.\n // If we cannot attempt then we have hit our target attempt count, which means that the node has succeeded.\n if (this.canAttempt()) {\n // This node is in the running state and can do its initial attempt.\n this.setState(State.RUNNING);\n\n // We may have already completed an attempt, meaning that the child node will be in the FAILED state.\n // If this is the case then we will have to reset the child node now.\n if (this.child.getState() === State.FAILED) {\n this.child.reset();\n }\n\n // Update the child of this node.\n this.child.update(agent, options);\n\n // If the child moved into the SUCCEEDED state when we updated it then there is nothing left to do and this node has also succeeded.\n // If it has moved into the FAILED state then we have completed the current attempt.\n if (this.child.getState() === State.SUCCEEDED) {\n // The child has succeeded, meaning that this node has succeeded.\n this.setState(State.SUCCEEDED);\n\n return;\n } else if (this.child.getState() === State.FAILED) {\n // We have completed an attempt.\n this.currentAttemptCount += 1;\n }\n } else {\n // This node is in the 'FAILED' state as we cannot iterate any more.\n this.setState(State.FAILED);\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => {\n if (this.attempts !== null) {\n return `RETRY ${this.attempts}x`;\n } else if (this.attemptsMin !== null && this.attemptsMax !== null) {\n return `RETRY ${this.attemptsMin}x-${this.attemptsMax}x`;\n } else {\n return \"RETRY\";\n }\n };\n\n /**\n * Reset the state of the node.\n */\n reset = () => {\n // Reset the state of this node.\n this.setState(State.READY);\n\n // Reset the current attempt count.\n this.currentAttemptCount = 0;\n\n // Reset the child node.\n this.child.reset();\n };\n\n /**\n * Gets whether an attempt can be made.\n * @returns Whether an attempt can be made.\n */\n canAttempt = () => {\n if (this.targetAttemptCount !== null) {\n // We can attempt as long as we have not reached our target attempt count.\n return this.currentAttemptCount < this.targetAttemptCount;\n }\n\n // If neither an attempt count or a condition function were defined then we can attempt indefinitely.\n return true;\n };\n\n /**\n * Sets the target attempt count.\n * @param options The behaviour tree options object.\n */\n setTargetAttemptCount = (options: BehaviourTreeOptions) => {\n // Are we dealing with an explicit attempt count or will we be randomly picking an attempt count between the min and max attempt count.\n if (this.attempts !== null) {\n this.targetAttemptCount = this.attempts;\n } else if (this.attemptsMin !== null && this.attemptsMax !== null) {\n // We will be picking a random attempt count between a min and max attempt count, if the optional 'random'\n // behaviour tree function option is defined then we will be using that, otherwise we will fall back to using Math.random.\n const random = typeof options.random === \"function\" ? options.random : Math.random;\n\n // Pick a random attempt count between a min and max attempt count.\n this.targetAttemptCount = Math.floor(\n random() * (this.attemptsMax - this.attemptsMin + 1) + this.attemptsMin\n );\n } else {\n this.targetAttemptCount = null;\n }\n };\n}\n", "import Node from \"../Node\";\nimport Decorator from \"./Decorator\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A Root node.\n * The root node will have a single child.\n */\nexport default class Root extends Decorator {\n /**\n * @param attributes The node attributes.\n * @param child The child node.\n */\n constructor(attributes: Attribute[], child: Node) {\n super(\"root\", attributes, child);\n }\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // If the child has never been updated or is running then we will need to update it now.\n if (this.child.getState() === State.READY || this.child.getState() === State.RUNNING) {\n // Update the child of this node.\n this.child.update(agent, options);\n }\n\n // The state of the root node is the state of its child.\n this.setState(this.child.getState());\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => \"ROOT\";\n}\n", "import Node from \"../Node\";\nimport Decorator from \"./Decorator\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A Succeed node.\n * This node wraps a single child and will always move to the 'SUCCEEDED' state when the child moves to a 'SUCCEEDED' or 'FAILED' state.\n */\nexport default class Succeed extends Decorator {\n /**\n * @param attributes The node attributes.\n * @param child The child node.\n */\n constructor(attributes: Attribute[], child: Node) {\n super(\"succeed\", attributes, child);\n }\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // If the child has never been updated or is running then we will need to update it now.\n if (this.child.getState() === State.READY || this.child.getState() === State.RUNNING) {\n this.child.update(agent, options);\n }\n\n // The state of this node will depend in the state of its child.\n switch (this.child.getState()) {\n case State.RUNNING:\n this.setState(State.RUNNING);\n break;\n\n case State.SUCCEEDED:\n case State.FAILED:\n this.setState(State.SUCCEEDED);\n break;\n\n default:\n this.setState(State.READY);\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => \"SUCCEED\";\n}\n", "import Node from \"../Node\";\n\n/**\n * A leaf node.\n */\nexport default abstract class Leaf extends Node {\n /**\n * Gets whether this node is a leaf node.\n */\n isLeafNode = () => true;\n}\n", "import { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\nimport State, { CompleteState } from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Leaf from \"./Leaf\";\nimport Lookup from \"../../Lookup\";\nimport Attribute from \"../../attributes/Attribute\";\n\n/**\n * The type representing a resolved/rejected update promise.\n */\ntype UpdatePromiseResult = {\n /**\n * Whether the promise was resolved rather than rejected.\n */\n isResolved: boolean;\n\n /**\n * The promise resolved value or rejection reason.\n */\n value: any;\n};\n\n/**\n * An Action leaf node.\n * This represents an immediate or ongoing state of behaviour.\n */\nexport default class Action extends Leaf {\n /**\n * @param attributes The node attributes.\n * @param actionName The action name.\n * @param actionArguments The array of action argument definitions.\n */\n constructor(attributes: Attribute[], private actionName: string, private actionArguments: any[]) {\n super(\"action\", attributes, actionArguments);\n }\n\n /**\n * Whether there is a pending update promise.\n */\n private isUsingUpdatePromise = false;\n\n /**\n * The finished state result of an update promise.\n */\n private updatePromiseResult: UpdatePromiseResult | null = null;\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // If the result of this action depends on an update promise then there is nothing to do until it settles.\n if (this.isUsingUpdatePromise) {\n // Are we still waiting for our update promise to settle?\n if (!this.updatePromiseResult) {\n return;\n }\n\n const { isResolved, value } = this.updatePromiseResult;\n\n // Our update promise settled, was it resolved or rejected?\n if (isResolved) {\n // Our promise resolved so check to make sure the result is a valid finished state.\n if (value !== State.SUCCEEDED && value !== State.FAILED) {\n throw new Error(\n \"action node promise resolved with an invalid value, expected a State.SUCCEEDED or State.FAILED value to be returned\"\n );\n }\n\n // Set the state of this node to match the state returned by the promise.\n this.setState(value);\n\n return;\n } else {\n // The promise was rejected, which isn't great.\n throw new Error(`action function '${this.actionName}' promise rejected with '${value}'`);\n }\n }\n\n // Attempt to get the invoker for the action function.\n const actionFuncInvoker = Lookup.getFuncInvoker(agent, this.actionName);\n\n // The action function should be defined.\n if (actionFuncInvoker === null) {\n throw new Error(\n `cannot update action node as the action '${this.actionName}' function is not defined on the agent and has not been registered`\n );\n }\n\n let actionFunctionResult;\n\n try {\n // Call the action function, the result of which may be:\n // - The finished state of this action node.\n // - A promise to return a finished node state.\n // - Undefined if the node should remain in the running state.\n actionFunctionResult = actionFuncInvoker(this.actionArguments) as CompleteState | Promise;\n } catch (error) {\n // The user was naughty and threw something.\n throw new Error(`action function '${this.actionName}' threw '${error}'`);\n }\n\n if (actionFunctionResult instanceof Promise) {\n actionFunctionResult.then(\n (result) => {\n // If 'isUpdatePromisePending' is not set then the promise was cleared as it was resolving, probably via an abort of reset.\n if (!this.isUsingUpdatePromise) {\n return;\n }\n\n // Set the resolved update promise result so that it can be handled on the next update of this node.\n this.updatePromiseResult = {\n isResolved: true,\n value: result\n };\n },\n (reason) => {\n // If 'isUpdatePromisePending' is not set then the promise was cleared as it was resolving, probably via an abort or reset.\n if (!this.isUsingUpdatePromise) {\n return;\n }\n\n // Set the rejected update promise result so that it can be handled on the next update of this node.\n this.updatePromiseResult = {\n isResolved: false,\n value: reason\n };\n }\n );\n\n // This node will be in the 'RUNNING' state until the update promise resolves.\n this.setState(State.RUNNING);\n\n // We are now waiting for the promise returned by the use to resolve before we know what state this node is in.\n this.isUsingUpdatePromise = true;\n } else {\n // Validate the returned value.\n this.validateUpdateResult(actionFunctionResult);\n\n // Set the state of this node, this may be undefined, which just means that the node is still in the 'RUNNING' state.\n this.setState(actionFunctionResult || State.RUNNING);\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => this.actionName;\n\n /**\n * Reset the state of the node.\n */\n reset = () => {\n // Reset the state of this node.\n this.setState(State.READY);\n\n // There is no longer an update promise that we care about.\n this.isUsingUpdatePromise = false;\n this.updatePromiseResult = null;\n };\n\n /**\n * Validate the result of an update function call.\n * @param result The result of an update function call.\n */\n private validateUpdateResult = (result: CompleteState | boolean) => {\n switch (result) {\n case State.SUCCEEDED:\n case State.FAILED:\n case undefined:\n return;\n default:\n throw new Error(\n `action '${this.actionName}' 'onUpdate' returned an invalid response, expected an optional State.SUCCEEDED or State.FAILED value to be returned`\n );\n }\n };\n}\n", "import { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Leaf from \"./Leaf\";\nimport Lookup from \"../../Lookup\";\nimport Attribute from \"../../attributes/Attribute\";\n\n/**\n * A Condition leaf node.\n * This will succeed or fail immediately based on an agent predicate, without moving to the 'RUNNING' state.\n */\nexport default class Condition extends Leaf {\n /**\n * @param attributes The node attributes.\n * @param conditionName The name of the condition function.\n * @param conditionArguments The array of condition argument definitions.\n */\n constructor(attributes: Attribute[], private conditionName: string, private conditionArguments: any[]) {\n super(\"condition\", attributes, conditionArguments);\n }\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // Attempt to get the invoker for the condition function.\n const conditionFuncInvoker = Lookup.getFuncInvoker(agent, this.conditionName);\n\n // The condition function should be defined.\n if (conditionFuncInvoker === null) {\n throw new Error(\n `cannot update condition node as the condition '${this.conditionName}' function is not defined on the agent and has not been registered`\n );\n }\n\n let conditionFunctionResult;\n\n try {\n // Call the condition function to determine the state of this node, the result of which should be a boolean.\n conditionFunctionResult = conditionFuncInvoker(this.conditionArguments);\n } catch (error) {\n // The user was naughty and threw something.\n throw new Error(`condition function '${this.conditionName}' threw '${error}'`);\n }\n\n // The result of calling the condition function must be a boolean value.\n if (typeof conditionFunctionResult !== \"boolean\") {\n throw new Error(\n `expected condition function '${this.conditionName}' to return a boolean but returned '${conditionFunctionResult}'`\n );\n }\n\n // Set the state of this node based on the result of calling the condition function.\n this.setState(!!conditionFunctionResult ? State.SUCCEEDED : State.FAILED);\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => this.conditionName;\n}\n", "import Leaf from \"./Leaf\";\nimport State from \"../../State\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { Agent } from \"../../Agent\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A WAIT node.\n * The state of this node will change to SUCCEEDED after a duration of time\n */\nexport default class Wait extends Leaf {\n /**\n * @param attributes The node attributes.\n * @param duration The duration that this node will wait to succeed in milliseconds.\n * @param durationMin The minimum possible duration in milliseconds that this node will wait to succeed.\n * @param durationMax The maximum possible duration in milliseconds that this node will wait to succeed.\n */\n constructor(\n attributes: Attribute[],\n private duration: number | null,\n private durationMin: number | null,\n private durationMax: number | null\n ) {\n super(\"wait\", attributes, []);\n }\n\n /**\n * The time in milliseconds at which this node was first updated.\n */\n private initialUpdateTime: number = 0;\n\n /**\n * The total duration in milliseconds that this node will be waiting for.\n */\n private totalDuration: number | null = null;\n\n /**\n * The duration in milliseconds that this node has been waiting for.\n */\n private waitedDuration: number = 0;\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // If this node is in the READY state then we need to set the initial update time.\n if (this.is(State.READY)) {\n // Set the initial update time.\n this.initialUpdateTime = new Date().getTime();\n\n // Set the initial waited duration.\n this.waitedDuration = 0;\n\n // Are we dealing with an explicit duration or will we be randomly picking a duration between the min and max duration.\n if (this.duration !== null) {\n this.totalDuration = this.duration;\n } else if (this.durationMin !== null && this.durationMax !== null) {\n // We will be picking a random duration between a min and max duration, if the optional 'random' behaviour tree\n // function option is defined then we will be using that, otherwise we will fall back to using Math.random.\n const random = typeof options.random === \"function\" ? options.random : Math.random;\n\n // Pick a random duration between a min and max duration.\n this.totalDuration = Math.floor(\n random() * (this.durationMax - this.durationMin + 1) + this.durationMin\n );\n } else {\n this.totalDuration = null;\n }\n\n // The node is now running until we finish waiting.\n this.setState(State.RUNNING);\n }\n\n // If we have no total duration then this wait node will wait indefinitely until it is aborted.\n if (this.totalDuration === null) {\n return;\n }\n\n // If we have a 'getDeltaTime' function defined as part of our options then we will use it to figure out how long we have waited for.\n if (typeof options.getDeltaTime === \"function\") {\n // Get the delta time.\n const deltaTime = options.getDeltaTime();\n\n // Our delta time must be a valid number and cannot be NaN.\n if (typeof deltaTime !== \"number\" || isNaN(deltaTime)) {\n throw new Error(\"The delta time must be a valid number and not NaN.\");\n }\n\n // Update the amount of time that this node has been waiting for based on the delta time.\n this.waitedDuration += deltaTime * 1000;\n } else {\n // We are not using a delta time, so we will just work out hom much time has passed since the first update.\n this.waitedDuration = new Date().getTime() - this.initialUpdateTime;\n }\n\n // Have we waited long enough?\n if (this.waitedDuration >= this.totalDuration) {\n // We have finished waiting!\n this.setState(State.SUCCEEDED);\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => {\n if (this.duration !== null) {\n return `WAIT ${this.duration}ms`;\n } else if (this.durationMin !== null && this.durationMax !== null) {\n return `WAIT ${this.durationMin}ms-${this.durationMax}ms`;\n } else {\n return \"WAIT\";\n }\n };\n}\n", "import Guard from \"./guards/Guard\";\n\nexport type AttributeDetails = {\n /** The attribute type. */\n type: string;\n\n /** The attribute arguments. */\n args: any[];\n};\n\n/**\n * A base node attribute.\n */\nexport default abstract class Attribute {\n /**\n * @param type The node attribute type.\n * @param args The array of attribute arguments.\n */\n constructor(public type: string, public args: any[]) {}\n\n /**\n * Gets the attribute details.\n */\n abstract getDetails(): TAttributeDetails;\n\n /**\n * Gets whether this attribute is a guard.\n */\n abstract isGuard: () => this is Guard;\n}\n", "import { Agent } from \"../../Agent\";\nimport Attribute, { AttributeDetails } from \"../Attribute\";\n\nexport type GuardAttributeDetails = {\n /** The name of the condition function that determines whether the guard is satisfied. */\n condition: string;\n} & AttributeDetails;\n\n/**\n * A base node guard attribute.\n */\nexport default abstract class Guard extends Attribute {\n /**\n * @param type The node attribute type.\n * @param args The array of decorator argument definitions.\n * @param condition The name of the condition function that determines whether the guard is satisfied.\n */\n constructor(type: string, args: any[], private condition: string) {\n super(type, args);\n }\n\n /**\n * Gets the name of the condition function that determines whether the guard is satisfied.\n */\n getCondition = () => this.condition;\n\n /**\n * Gets whether this attribute is a guard.\n */\n isGuard = () => true;\n\n /**\n * Gets the attribute details.\n */\n getDetails(): GuardAttributeDetails {\n return {\n type: this.type,\n args: this.args,\n condition: this.getCondition()\n };\n }\n\n /**\n * Gets whether the guard is satisfied.\n * @param agent The agent.\n * @returns Whether the guard is satisfied.\n */\n abstract isSatisfied(agent: Agent): boolean;\n}\n", "import Guard from \"./Guard\";\nimport Lookup from \"../../Lookup\";\nimport { Agent } from \"../../Agent\";\n\n/**\n * A WHILE guard which is satisfied as long as the given condition remains true.\n */\nexport default class While extends Guard {\n /**\n * @param condition The name of the condition function that determines whether the guard is satisfied.\n * @param args The array of decorator argument definitions.\n */\n constructor(condition: string, args: any[]) {\n super(\"while\", args, condition);\n }\n\n /**\n * Gets whether the guard is satisfied.\n * @param agent The agent.\n * @returns Whether the guard is satisfied.\n */\n isSatisfied = (agent: Agent) => {\n // Attempt to get the invoker for the condition function.\n const conditionFuncInvoker = Lookup.getFuncInvoker(agent, this.getCondition());\n\n // The condition function should be defined.\n if (conditionFuncInvoker === null) {\n throw new Error(\n `cannot evaluate node guard as the condition '${this.getCondition()}' function is not defined on the agent and has not been registered`\n );\n }\n\n // Call the condition function to determine whether this guard is satisfied.\n return !!conditionFuncInvoker(this.args);\n };\n}\n", "import Guard from \"./Guard\";\nimport Lookup from \"../../Lookup\";\nimport { Agent } from \"../../Agent\";\n\n/**\n * An UNTIL guard which is satisfied as long as the given condition remains false.\n */\nexport default class Until extends Guard {\n /**\n * @param condition The name of the condition function that determines whether the guard is satisfied.\n * @param args The array of decorator argument definitions.\n */\n constructor(condition: string, args: any[]) {\n super(\"until\", args, condition);\n }\n\n /**\n * Gets whether the guard is satisfied.\n * @param agent The agent.\n * @returns Whether the guard is satisfied.\n */\n isSatisfied = (agent: Agent) => {\n // Attempt to get the invoker for the condition function.\n const conditionFuncInvoker = Lookup.getFuncInvoker(agent, this.getCondition());\n\n // The condition function should be defined.\n if (conditionFuncInvoker === null) {\n throw new Error(\n `cannot evaluate node guard as the condition '${this.getCondition()}' function is not defined on the agent and has not been registered`\n );\n }\n\n // Call the condition function to determine whether this guard is satisfied.\n return !!!conditionFuncInvoker(this.args);\n };\n}\n", "import { Agent } from \"../../Agent\";\nimport Attribute, { AttributeDetails } from \"../Attribute\";\n\nexport type CallbackAttributeDetails = {\n /** The name of the agent function that is called. */\n functionName: string;\n} & AttributeDetails;\n\n/**\n * A base node callback attribute.\n */\nexport default abstract class Callback extends Attribute {\n /**\n * @param type The node attribute type.\n * @param args The array of decorator argument definitions.\n * @param functionName The name of the agent function to call.\n */\n constructor(type: string, args: any[], private functionName: string) {\n super(type, args);\n }\n\n /**\n * Gets the name of the agent function to call.\n */\n getFunctionName = () => this.functionName;\n\n /**\n * Gets whether this attribute is a guard.\n */\n isGuard = () => false;\n\n /**\n * Gets the attribute details.\n */\n getDetails(): CallbackAttributeDetails {\n return {\n type: this.type,\n args: this.args,\n functionName: this.getFunctionName()\n };\n }\n\n /**\n * Attempt to call the agent function that this callback refers to.\n * @param agent The agent.\n */\n abstract callAgentFunction: (agent: Agent, isSuccess: boolean, isAborted: boolean) => void;\n}\n", "import Callback from \"./Callback\";\nimport Lookup from \"../../Lookup\";\nimport { Agent } from \"../../Agent\";\n\n/**\n * An ENTRY callback which defines an agent function to call when the associated node is updated and moves out of running state.\n */\nexport default class Entry extends Callback {\n /**\n * @param functionName The name of the agent function to call.\n * @param args The array of callback argument definitions.\n */\n constructor(functionName: string, args: any[]) {\n super(\"entry\", args, functionName);\n }\n\n /**\n * Attempt to call the agent function that this callback refers to.\n * @param agent The agent.\n */\n callAgentFunction = (agent: Agent) => {\n // Attempt to get the invoker for the callback function.\n const callbackFuncInvoker = Lookup.getFuncInvoker(agent, this.getFunctionName());\n\n // The callback function should be defined.\n if (callbackFuncInvoker === null) {\n throw new Error(\n `cannot call entry function '${this.getFunctionName()}' as is not defined on the agent and has not been registered`\n );\n }\n\n // Call the callback function.\n callbackFuncInvoker(this.args);\n };\n}\n", "import Callback from \"./Callback\";\nimport Lookup from \"../../Lookup\";\nimport { Agent } from \"../../Agent\";\n\n/**\n * A STEP callback which defines an agent function to call when the associated node is updated.\n */\nexport default class Step extends Callback {\n /**\n * @param functionName The name of the agent function to call.\n * @param args The array of callback argument definitions.\n */\n constructor(functionName: string, args: any[]) {\n super(\"step\", args, functionName);\n }\n\n /**\n * Attempt to call the agent function that this callback refers to.\n * @param agent The agent.\n */\n callAgentFunction = (agent: Agent) => {\n // Attempt to get the invoker for the callback function.\n const callbackFuncInvoker = Lookup.getFuncInvoker(agent, this.getFunctionName());\n\n // The callback function should be defined.\n if (callbackFuncInvoker === null) {\n throw new Error(\n `cannot call step function '${this.getFunctionName()}' as is not defined on the agent and has not been registered`\n );\n }\n\n // Call the callback function.\n callbackFuncInvoker(this.args);\n };\n}\n", "import Callback from \"./Callback\";\nimport Lookup from \"../../Lookup\";\nimport { Agent } from \"../../Agent\";\n\n/**\n * An EXIT callback which defines an agent function to call when the associated node is updated and moves to a finished state or is aborted.\n */\nexport default class Exit extends Callback {\n /**\n * @param functionName The name of the agent function to call.\n * @param args The array of callback argument definitions.\n */\n constructor(functionName: string, args: any[]) {\n super(\"exit\", args, functionName);\n }\n\n /**\n * Attempt to call the agent function that this callback refers to.\n * @param agent The agent.\n * @param isSuccess Whether the decorated node was left with a success state.\n * @param isAborted Whether the decorated node was aborted.\n */\n callAgentFunction = (agent: Agent, isSuccess: boolean, isAborted: boolean) => {\n // Attempt to get the invoker for the callback function.\n const callbackFuncInvoker = Lookup.getFuncInvoker(agent, this.getFunctionName());\n\n // The callback function should be defined.\n if (callbackFuncInvoker === null) {\n throw new Error(\n `cannot call exit function '${this.getFunctionName()}' as is not defined on the agent and has not been registered`\n );\n }\n\n // Call the callback function\n callbackFuncInvoker([{ value: { succeeded: isSuccess, aborted: isAborted } }, ...this.args]);\n };\n}\n", "import { AnyNodeDefinition, RootNodeDefinition } from \"./BehaviourTreeDefinition\";\nimport GuardPath, { GuardPathPart } from \"./attributes/guards/GuardPath\";\nimport { validateBranchSubtreeLinks } from \"./BehaviourTreeDefinitionValidator\";\nimport { isInteger } from \"./BehaviourTreeDefinitionUtilities\";\nimport Node from \"./nodes/Node\";\nimport Composite from \"./nodes/composite/Composite\";\nimport Decorator from \"./nodes/decorator/Decorator\";\nimport Parallel from \"./nodes/composite/Parallel\";\nimport Selector from \"./nodes/composite/Selector\";\nimport Sequence from \"./nodes/composite/Sequence\";\nimport Lotto from \"./nodes/composite/Lotto\";\nimport Fail from \"./nodes/decorator/Fail\";\nimport Flip from \"./nodes/decorator/Flip\";\nimport Repeat from \"./nodes/decorator/Repeat\";\nimport Retry from \"./nodes/decorator/Retry\";\nimport Root from \"./nodes/decorator/Root\";\nimport Succeed from \"./nodes/decorator/Succeed\";\nimport Action from \"./nodes/leaf/Action\";\nimport Condition from \"./nodes/leaf/Condition\";\nimport Wait from \"./nodes/leaf/Wait\";\nimport Lookup from \"./Lookup\";\nimport Attribute from \"./attributes/Attribute\";\nimport While from \"./attributes/guards/While\";\nimport Until from \"./attributes/guards/Until\";\nimport Entry from \"./attributes/callbacks/Entry\";\nimport Step from \"./attributes/callbacks/Step\";\nimport Exit from \"./attributes/callbacks/Exit\";\n\n/**\n * A type representing any node instance in a behaviour tree.\n */\ntype AnyNode =\n | Root\n | Action\n | Condition\n | Wait\n | Sequence\n | Selector\n | Lotto\n | Parallel\n | Repeat\n | Retry\n | Flip\n | Succeed\n | Fail;\n\n/**\n * A type defining a mapping of root node identifiers to root node definitions.\n */\ntype RootNodeDefinitionMap = { [key: string | symbol]: RootNodeDefinition };\n\n/**\n * A symbol to use as the main root key in any root node mappings.\n */\nconst MAIN_ROOT_NODE_KEY = Symbol(\"__root__\");\n\n/**\n * Build and populate the root nodes based on the provided definition, assuming that the definition has been validated.\n * @param definition The root node definitions.\n * @returns The built and populated root node definitions.\n */\nexport default function buildRootNode(definition: RootNodeDefinition[]): Root {\n // Create a mapping of root node identifers to root node definitions, including globally registered subtree root node definitions.\n const rootNodeDefinitionMap = createRootNodeDefinitionMap(definition);\n\n // Now that we have all of our root node definitons (those part of the tree definition and those globally\n // registered) we should validate the definition. This will also double-check that we dont have any circular\n // dependencies in our branch -> subtree references and that we have no broken branch -> subtree links.\n validateBranchSubtreeLinks(definition, true);\n\n // Create our populated tree of node instances, starting with our main root node.\n const rootNode = nodeFactory(rootNodeDefinitionMap[MAIN_ROOT_NODE_KEY], rootNodeDefinitionMap) as Root;\n\n // Set a guard path on every leaf of the tree to evaluate as part of each update.\n applyLeafNodeGuardPaths(rootNode);\n\n // We only need to return the main root node.\n return rootNode;\n}\n\n/**\n * A factory function which creates a node instance based on the specified definition.\n * @param definition The node definition.\n * @param rootNodeDefinitionMap The mapping of root node identifers to root node definitions, including globally registered subtree root node definitions.\n * @returns A node instance based on the specified definition.\n */\nfunction nodeFactory(definition: AnyNodeDefinition, rootNodeDefinitionMap: RootNodeDefinitionMap): AnyNode {\n // Get the attributes for the node.\n const attributes = nodeAttributesFactory(definition);\n\n // Create the node instance based on the definition type.\n switch (definition.type) {\n case \"root\":\n return new Root(attributes, nodeFactory(definition.child, rootNodeDefinitionMap));\n\n case \"repeat\":\n let iterations: number | null = null;\n let iterationsMin: number | null = null;\n let iterationsMax: number | null = null;\n\n if (Array.isArray(definition.iterations)) {\n iterationsMin = definition.iterations[0];\n iterationsMax = definition.iterations[1];\n } else if (isInteger(definition.iterations)) {\n iterations = definition.iterations!;\n }\n\n return new Repeat(\n attributes,\n iterations,\n iterationsMin,\n iterationsMax,\n nodeFactory(definition.child, rootNodeDefinitionMap)\n );\n\n case \"retry\":\n let attempts: number | null = null;\n let attemptsMin: number | null = null;\n let attemptsMax: number | null = null;\n\n if (Array.isArray(definition.attempts)) {\n attemptsMin = definition.attempts[0];\n attemptsMax = definition.attempts[1];\n } else if (isInteger(definition.attempts)) {\n attempts = definition.attempts!;\n }\n\n return new Retry(\n attributes,\n attempts,\n attemptsMin,\n attemptsMax,\n nodeFactory(definition.child, rootNodeDefinitionMap)\n );\n\n case \"flip\":\n return new Flip(attributes, nodeFactory(definition.child, rootNodeDefinitionMap));\n\n case \"succeed\":\n return new Succeed(attributes, nodeFactory(definition.child, rootNodeDefinitionMap));\n\n case \"fail\":\n return new Fail(attributes, nodeFactory(definition.child, rootNodeDefinitionMap));\n\n case \"sequence\":\n return new Sequence(\n attributes,\n definition.children.map((child) => nodeFactory(child, rootNodeDefinitionMap))\n );\n\n case \"selector\":\n return new Selector(\n attributes,\n definition.children.map((child) => nodeFactory(child, rootNodeDefinitionMap))\n );\n\n case \"parallel\":\n return new Parallel(\n attributes,\n definition.children.map((child) => nodeFactory(child, rootNodeDefinitionMap))\n );\n\n case \"lotto\":\n return new Lotto(\n attributes,\n definition.weights,\n definition.children.map((child) => nodeFactory(child, rootNodeDefinitionMap))\n );\n\n case \"branch\":\n return nodeFactory(rootNodeDefinitionMap[definition.ref].child, rootNodeDefinitionMap);\n\n case \"action\":\n return new Action(attributes, definition.call, definition.args || []);\n\n case \"condition\":\n return new Condition(attributes, definition.call, definition.args || []);\n\n case \"wait\":\n let duration: number | null = null;\n let durationMin: number | null = null;\n let durationMax: number | null = null;\n\n if (Array.isArray(definition.duration)) {\n durationMin = definition.duration[0];\n durationMax = definition.duration[1];\n } else if (isInteger(definition.duration)) {\n duration = definition.duration!;\n }\n\n return new Wait(attributes, duration, durationMin, durationMax);\n }\n}\n\n/**\n * Creates an array of node attribute instances based on the specified node definition.\n * @param definition The node definition.\n * @returns An array of node attribute instances based on the specified node definition.\n */\nfunction nodeAttributesFactory(definition: AnyNodeDefinition): Attribute[] {\n const attributes: Attribute[] = [];\n\n if (definition.while) {\n attributes.push(new While(definition.while.call, definition.while.args ?? []));\n }\n\n if (definition.until) {\n attributes.push(new Until(definition.until.call, definition.until.args ?? []));\n }\n\n if (definition.entry) {\n attributes.push(new Entry(definition.entry.call, definition.entry.args ?? []));\n }\n\n if (definition.step) {\n attributes.push(new Step(definition.step.call, definition.step.args ?? []));\n }\n\n if (definition.exit) {\n attributes.push(new Exit(definition.exit.call, definition.exit.args ?? []));\n }\n\n return attributes;\n}\n\n/**\n * Creates a mapping of root node identifers to root node definitions, mixing in globally registered subtree root node definitions.\n * @param definition The root node definitions.\n * @returns A mapping of root node identifers to root node definitions, including globally registered subtree root node definitions.\n */\nfunction createRootNodeDefinitionMap(definition: RootNodeDefinition[]): RootNodeDefinitionMap {\n // Create a mapping of root node identifers to root node definitions.\n const rootNodeMap: RootNodeDefinitionMap = {};\n\n // Add in any registered subtree root node definitions.\n for (const [name, rootNodeDefinition] of Object.entries(Lookup.getSubtrees())) {\n // The name used when registering the subtree will be used as the root node identifier.\n rootNodeMap[name] = { ...rootNodeDefinition, id: name };\n }\n\n // Populate the map with the root node definitions that were included with the tree definition.\n // We do this after adding any registered subtrees as we want these to take presedence.\n for (const rootNodeDefinition of definition) {\n rootNodeMap[rootNodeDefinition.id ?? MAIN_ROOT_NODE_KEY] = rootNodeDefinition;\n }\n\n return rootNodeMap;\n}\n\n/**\n * Applies a guard path to every leaf of the tree to evaluate as part of each update.\n * @param root The main root tree node.\n */\nfunction applyLeafNodeGuardPaths(root: Root) {\n const nodePaths: Node[][] = [];\n\n const findLeafNodes = (path: Node[], node: Node) => {\n // Add the current node to the path.\n path = path.concat(node);\n\n // Check whether the current node is a leaf node.\n if (node.isLeafNode()) {\n nodePaths.push(path);\n } else {\n (node as Composite | Decorator).getChildren().forEach((child) => findLeafNodes(path, child));\n }\n };\n\n // Find all leaf node paths, starting from the root.\n findLeafNodes([], root);\n\n nodePaths.forEach((path) => {\n // Each node in the current path will have to be assigned a guard path, working from the root outwards.\n for (let depth = 0; depth < path.length; depth++) {\n // Get the node in the path at the current depth.\n const currentNode = path[depth];\n\n // The node may already have been assigned a guard path, if so just skip it.\n if (currentNode.hasGuardPath()) {\n continue;\n }\n\n // Create the guard path for the current node.\n const guardPath = new GuardPath(\n path\n .slice(0, depth + 1)\n .map((node) => ({ node, guards: node.getGuardAttributes() }))\n .filter((details) => details.guards.length > 0)\n );\n\n // Assign the guard path to the current node.\n currentNode.setGuardPath(guardPath);\n }\n });\n}\n", "import State, { AnyState } from \"./State\";\nimport Lookup from \"./Lookup\";\nimport Node from \"./nodes/Node\";\nimport Root from \"./nodes/decorator/Root\";\nimport Composite from \"./nodes/composite/Composite\";\nimport Decorator from \"./nodes/decorator/Decorator\";\nimport { Agent, GlobalFunction } from \"./Agent\";\nimport { CallbackAttributeDetails } from \"./attributes/callbacks/Callback\";\nimport { GuardAttributeDetails } from \"./attributes/guards/Guard\";\nimport { BehaviourTreeOptions } from \"./BehaviourTreeOptions\";\nimport { convertMDSLToJSON } from \"./mdsl/MDSLDefinitionParser\";\nimport { RootNodeDefinition } from \"./BehaviourTreeDefinition\";\nimport { validateDefinition, validateJSONDefinition } from \"./BehaviourTreeDefinitionValidator\";\nimport buildRootNode from \"./BehaviourTreeBuilder\";\nimport { isNullOrUndefined } from \"./BehaviourTreeDefinitionUtilities\";\n\n// Purely for outside inspection of the tree.\nexport type FlattenedTreeNode = {\n id: string;\n type: string;\n caption: string;\n state: AnyState;\n guards: GuardAttributeDetails[];\n callbacks: CallbackAttributeDetails[];\n args: any[];\n parentId: string | null;\n};\n\n/**\n * A representation of a behaviour tree.\n */\nexport class BehaviourTree {\n /**\n * The main root tree node.\n */\n private readonly _rootNode: Root;\n\n /**\n * Creates a new instance of the BehaviourTree class.\n * @param definition The behaviour tree definition as either an MDSL string, root node definition object or array of root node definition objects.\n * @param agent The agent instance that this behaviour tree is modelling behaviour for.\n * @param options The behaviour tree options object.\n */\n constructor(\n definition: string | RootNodeDefinition | RootNodeDefinition[],\n private agent: Agent,\n private options: BehaviourTreeOptions = {}\n ) {\n // The tree definition must be defined.\n if (isNullOrUndefined(definition)) {\n throw new Error(\"tree definition not defined\");\n }\n\n // The agent must be defined and not null.\n if (typeof agent !== \"object\" || agent === null) {\n throw new Error(\"the agent must be an object and not null\");\n }\n\n // We should validate the definition before we try to build the tree nodes.\n const { succeeded, errorMessage, json } = validateDefinition(definition);\n\n // Did our validation fail without error?\n if (!succeeded) {\n throw new Error(`invalid definition: ${errorMessage}`);\n }\n\n // Double check that we did actually get our json definition as part of our definition validtion.\n if (!json) {\n throw new Error(\n \"expected json definition to be returned as part of successful definition validation response\"\n );\n }\n\n try {\n // Create the populated tree of behaviour tree nodes and get the root node.\n this._rootNode = buildRootNode(json);\n } catch (exception) {\n // There was an issue in trying build and populate the behaviour tree.\n throw new Error(`error building tree: ${(exception as Error).message}`);\n }\n }\n\n /**\n * Gets whether the tree is in the RUNNING state.\n * @returns true if the tree is in the RUNNING state, otherwise false.\n */\n isRunning() {\n return this._rootNode.getState() === State.RUNNING;\n }\n\n /**\n * Gets the current tree state of SUCCEEDED, FAILED, READY or RUNNING.\n * @returns The current tree state.\n */\n getState() {\n return this._rootNode.getState();\n }\n\n /**\n * Step the tree.\n * 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.\n * 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\n * 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.\n *\n * 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.\n */\n step() {\n // If the root node has already been stepped to completion then we need to reset it.\n if (this._rootNode.getState() === State.SUCCEEDED || this._rootNode.getState() === State.FAILED) {\n this._rootNode.reset();\n }\n\n try {\n this._rootNode.update(this.agent, this.options);\n } catch (exception) {\n throw new Error(`error stepping tree: ${(exception as Error).message}`);\n }\n }\n\n /**\n * Resets the tree from the root node outwards to each nested node, giving each a state of READY.\n */\n reset() {\n this._rootNode.reset();\n }\n\n /**\n * Gets the flattened details of every node in the tree.\n * @returns The flattened details of every node in the tree.\n */\n getFlattenedNodeDetails(): FlattenedTreeNode[] {\n // Create an empty flattened array of tree nodes.\n const flattenedTreeNodes: FlattenedTreeNode[] = [];\n\n /**\n * Helper function to process a node instance and push details into the flattened tree nodes array.\n * @param node The current node.\n * @param parentUid The UID of the node parent, or null if the node is the main root node.\n */\n const processNode = (node: Node, parentUid: string | null) => {\n // Get the guard and callback attribute details for this node.\n const guards = node\n .getAttributes()\n .filter((attribute) => attribute.isGuard())\n .map((attribute) => attribute.getDetails()) as GuardAttributeDetails[];\n const callbacks = node\n .getAttributes()\n .filter((attribute) => !attribute.isGuard())\n .map((attribute) => attribute.getDetails()) as CallbackAttributeDetails[];\n\n // Push the current node into the flattened nodes array.\n flattenedTreeNodes.push({\n id: node.getUid(),\n type: node.getType(),\n caption: node.getName(),\n state: node.getState(),\n guards,\n callbacks,\n args: node.getArguments(),\n parentId: parentUid\n });\n\n // Process each of the nodes children if it is not a leaf node.\n if (!node.isLeafNode()) {\n (node as Composite | Decorator)\n .getChildren()\n .forEach((child) => processNode(child, (node as Composite | Decorator).getUid()));\n }\n };\n\n // Convert the nested node structure into a flattened array of node details.\n processNode(this._rootNode, null);\n\n return flattenedTreeNodes;\n }\n\n /**\n * Registers the action/condition/guard/callback function or subtree with the given name.\n * @param name The name of the function or subtree to register.\n * @param value The function or subtree definition to register.\n */\n static register(name: string, value: GlobalFunction | string | RootNodeDefinition) {\n // Are we going to register a action/condition/guard/callback function?\n if (typeof value === \"function\") {\n Lookup.setFunc(name, value);\n return;\n }\n\n // We are not registering an action/condition/guard/callback function, so we must be registering a subtree.\n if (typeof value === \"string\") {\n let rootNodeDefinitions: RootNodeDefinition[];\n\n // We will assume that any string passed in will be a mdsl definition.\n try {\n rootNodeDefinitions = convertMDSLToJSON(value);\n } catch (exception) {\n throw new Error(`error registering definition, invalid MDSL: ${(exception as Error).message}`);\n }\n\n // This function should only ever be called with a definition containing a single unnamed root node.\n if (rootNodeDefinitions.length != 1 || rootNodeDefinitions[0].id !== null) {\n throw new Error(\"error registering definition: expected a single unnamed root node\");\n }\n\n try {\n // We should validate the subtree as we don't want invalid subtrees available via the lookup.\n const { succeeded, errorMessage } = validateJSONDefinition(rootNodeDefinitions[0]);\n\n // Did our validation fail without error?\n if (!succeeded) {\n throw new Error(errorMessage);\n }\n } catch (exception) {\n throw new Error(`error registering definition: ${(exception as Error).message}`);\n }\n\n // Everything seems hunky-dory, register the subtree.\n Lookup.setSubtree(name, rootNodeDefinitions[0]);\n } else if (typeof value === \"object\" && !Array.isArray(value)) {\n // We will assume that any object passed in is a root node definition.\n\n try {\n // We should validate the subtree as we don't want invalid subtrees available via the lookup.\n const { succeeded, errorMessage } = validateJSONDefinition(value);\n\n // Did our validation fail without error?\n if (!succeeded) {\n throw new Error(errorMessage);\n }\n } catch (exception) {\n throw new Error(`error registering definition: ${(exception as Error).message}`);\n }\n\n // Everything seems hunky-dory, register the subtree.\n Lookup.setSubtree(name, value);\n } else {\n throw new Error(\"unexpected value, expected string mdsl definition, root node json definition or function\");\n }\n }\n\n /**\n * Unregisters the registered action/condition/guard/callback function or subtree with the given name.\n * @param name The name of the registered action/condition/guard/callback function or subtree to unregister.\n */\n static unregister(name: string): void {\n Lookup.remove(name);\n }\n\n /**\n * Unregister all registered action/condition/guard/callback functions and subtrees.\n */\n static unregisterAll(): void {\n Lookup.empty();\n }\n}\n"], - "mappings": "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", + "sourcesContent": ["\"use strict\";\r\nObject.defineProperty(exports, \"__esModule\", { value: true });\r\nexports.Participant = void 0;\r\n/**\r\n * A participant that holds a number of tickets.\r\n */\r\nvar Participant = /** @class */ (function () {\r\n /**\r\n * Creates an instance of the Participant class.\r\n * @param participant The actual participant.\r\n * @param tickets The number of tickets held by the participant.\r\n */\r\n function Participant(participant, tickets) {\r\n if (tickets === void 0) { tickets = 1; }\r\n this._participant = participant;\r\n this._tickets = tickets;\r\n }\r\n Object.defineProperty(Participant.prototype, \"participant\", {\r\n /** Gets the actual participant. */\r\n get: function () {\r\n return this._participant;\r\n },\r\n enumerable: false,\r\n configurable: true\r\n });\r\n Object.defineProperty(Participant.prototype, \"tickets\", {\r\n /** Gets or sets the number of tickets held by the participant. */\r\n get: function () {\r\n return this._tickets;\r\n },\r\n set: function (value) {\r\n this._tickets = value;\r\n },\r\n enumerable: false,\r\n configurable: true\r\n });\r\n return Participant;\r\n}());\r\nexports.Participant = Participant;\r\n", "\"use strict\";\r\nObject.defineProperty(exports, \"__esModule\", { value: true });\r\nexports.isNaturalNumber = exports.isNullOrUndefined = void 0;\r\n/**\r\n * Gets whether the value provided is null or undefined.\r\n * @param value The value to check.\r\n * @returns Whether the value provided is null or undefined.\r\n */\r\nfunction isNullOrUndefined(value) {\r\n return value === null || value === undefined;\r\n}\r\nexports.isNullOrUndefined = isNullOrUndefined;\r\n/**\r\n * Gets whether the value provided is a natural number.\r\n * @param value The value to check.\r\n * @returns Whether the value provided is a natural number.\r\n */\r\nfunction isNaturalNumber(value) {\r\n return typeof value === \"number\" && value >= 1 && Math.floor(value) === value;\r\n}\r\nexports.isNaturalNumber = isNaturalNumber;\r\n", "\"use strict\";\r\nObject.defineProperty(exports, \"__esModule\", { value: true });\r\nexports.Lotto = void 0;\r\nvar Participant_1 = require(\"./Participant\");\r\nvar Utilities_1 = require(\"./Utilities\");\r\n/**\r\n * Represents a lotto consisting of a number of pickable ticket-holding participants.\r\n */\r\nvar Lotto = /** @class */ (function () {\r\n /**\r\n * Creates a new instance of Lotto.\r\n * @param customRandom The custom RNG to use in place of Math.random().\r\n */\r\n function Lotto(customRandom) {\r\n /** The array of participants that are holding tickets in the lotto. */\r\n this._participants = [];\r\n this._customRandom = customRandom;\r\n }\r\n /**\r\n * Adds a participant with the specified number of tickets, or adds to the participant ticket count if the participant already holds tickets.\r\n * @param participant The participant to add or to increase the ticket count for if they already hold tickets.\r\n * @param tickets The number of tickets, defaults to 1.\r\n * @returns The Lotto instance.\r\n */\r\n Lotto.prototype.add = function (participant, tickets) {\r\n if (tickets === void 0) { tickets = 1; }\r\n // Check that we have a valid ticket count.\r\n if (!(0, Utilities_1.isNaturalNumber)(tickets)) {\r\n throw new Error(\"tickets value must be a natural number\");\r\n }\r\n // Check whether this participant has already been added.\r\n var existingParticipant = this._participants.find(function (part) { return part.participant === participant; });\r\n if (existingParticipant) {\r\n // The participant has already been added to the lotto so just add to their ticket count.\r\n existingParticipant.tickets += tickets;\r\n }\r\n else {\r\n // The participant is not part of the lotto so we should add them.\r\n this._participants.push(new Participant_1.Participant(participant, tickets));\r\n }\r\n return this;\r\n };\r\n /**\r\n * Removes the specified number of tickets for the given participant from the draw, or all tickets if a ticket number is not defined.\r\n * @param participant The participant to remove tickets for.\r\n * @param tickets The number of tickets to remove, or undefined if all tickets are to be removed.\r\n * @returns The Lotto instance.\r\n */\r\n Lotto.prototype.remove = function (participant, tickets) {\r\n // Attempt to get the existing participant.\r\n var existingParticipant = this._participants.find(function (part) { return part.participant === participant; });\r\n // There is nothing to do if the specified participant isn't even part of the lotto.\r\n if (!existingParticipant) {\r\n return this;\r\n }\r\n // Check whether a tickets value was given.\r\n if (tickets !== undefined) {\r\n // Check that we have a valid ticket count.\r\n if (!(0, Utilities_1.isNaturalNumber)(tickets)) {\r\n throw new Error(\"tickets value must be a natural number\");\r\n }\r\n existingParticipant.tickets -= tickets;\r\n // If the participant no longer holds any tickets then they should be removed.\r\n if (existingParticipant.tickets < 1) {\r\n this._participants = this._participants.filter(function (part) { return part !== existingParticipant; });\r\n }\r\n }\r\n else {\r\n // We are removing all tickets for the participant so just remove them from the lotto.\r\n this._participants = this._participants.filter(function (part) { return part !== existingParticipant; });\r\n }\r\n return this;\r\n };\r\n /**\r\n * Draw a winning ticket and return the participant that holds the ticket.\r\n * @param options The draw options.\r\n * @returns The participant that holds the winning ticket.\r\n */\r\n Lotto.prototype.draw = function (options) {\r\n if (options === void 0) { options = {}; }\r\n // If we have no participants then just return null.\r\n if (this._participants.length === 0) {\r\n return null;\r\n }\r\n var redrawable = (0, Utilities_1.isNullOrUndefined)(options.redrawable) ? true : options.redrawable;\r\n var pickable = [];\r\n this._participants.forEach(function (_a) {\r\n var participant = _a.participant, tickets = _a.tickets;\r\n for (var ticketCount = 0; ticketCount < tickets; ticketCount++) {\r\n pickable.push(participant);\r\n }\r\n });\r\n var random;\r\n // We need a random floating-point number between 0 (inclusive) and 1 to scale up to pick our winner.\r\n // If a custom random function exists then we should use that or fall back to Math.random().\r\n if (this._customRandom) {\r\n // Call our custom random function to get a random floating-point number.\r\n random = this._customRandom();\r\n // Verify that the result of calling our custom random function is a number between 0 (inclusive) and 1.\r\n if (typeof random !== \"number\" || random < 0 || random >= 1) {\r\n throw new Error(\"the 'random' function provided did not return a number between 0 (inclusive) and 1\");\r\n }\r\n }\r\n else {\r\n // No custom random function was defined so just use good ol' Math.random().\r\n random = Math.random();\r\n }\r\n // Pick a winning participant.\r\n var winner = pickable[Math.floor(random * pickable.length)];\r\n // If the ticket isn't redrawable then we should remove a ticket from the winning participants ticket count.\r\n if (!redrawable) {\r\n this.remove(winner, 1);\r\n }\r\n // Return the winning participant.\r\n return winner;\r\n };\r\n /**\r\n * Draws multiple winning tickets and return an array of the participants that hold the winning tickets.\r\n * @param tickets The number of winning tickets to draw.\r\n * @param options The draw multiple options.\r\n * @returns An array of the participants that hold the winning tickets.\r\n */\r\n Lotto.prototype.drawMultiple = function (tickets, options) {\r\n if (options === void 0) { options = {}; }\r\n var uniqueResults = (0, Utilities_1.isNullOrUndefined)(options.unique) ? false : options.unique;\r\n // Handle cases where the user has asked for zero tickets (no idea why they would do this be we should trust them).\r\n if (tickets === 0) {\r\n return [];\r\n }\r\n // Now that we know out tickets value is not zero we should check that it is a valid natural number.\r\n if (!(0, Utilities_1.isNaturalNumber)(tickets)) {\r\n throw new Error(\"tickets value must be a natural number\");\r\n }\r\n var result = [];\r\n // Keep drawing tickets until we either reach the number of required tickets or we simply run out of tickets to draw.\r\n // We can run out of tickets to draw if 'options.redrawable' is explicity 'false' or we just had no participants when 'drawMultiple' was called.\r\n while (result.length < tickets && this._participants.length > 0) {\r\n result.push(this.draw(options));\r\n }\r\n // If the 'unique' draw option is set then we need to remove duplicates from the result list.\r\n if (uniqueResults) {\r\n // Create an array to store our unique results.\r\n var unique = [];\r\n // Iterate over all of our participants (with potential duplicates) and populate our array of unique values.\r\n for (var _i = 0, result_1 = result; _i < result_1.length; _i++) {\r\n var participant = result_1[_i];\r\n if (unique.indexOf(participant) === -1) {\r\n unique.push(participant);\r\n }\r\n }\r\n result = unique;\r\n }\r\n return result;\r\n };\r\n return Lotto;\r\n}());\r\nexports.Lotto = Lotto;\r\n", "\"use strict\";\r\nObject.defineProperty(exports, \"__esModule\", { value: true });\r\nexports.createLotto = void 0;\r\nvar Lotto_1 = require(\"./Lotto\");\r\n/**\r\n * A function that creates and returns a Lotto instance.\r\n * @param participantsOrOptions An array of initial participants or options relating to the creation of a Lotto instance.\r\n * @returns A new Lotto instance.\r\n */\r\nfunction createLotto(participantsOrOptions) {\r\n // If no initial participants or lotto options were provided as an argument then we can just return a new lotto instance now.\r\n if (!participantsOrOptions) {\r\n return new Lotto_1.Lotto();\r\n }\r\n // Check whether we were provided with an array of initial participants or a lotto options object.\r\n if (Array.isArray(participantsOrOptions)) {\r\n // We are dealing with a pre-defined array of participants.\r\n var participants = participantsOrOptions;\r\n var lotto_1 = new Lotto_1.Lotto();\r\n // If the lotto participants have been defined upfront then we will need to add them all to our lotto instance now.\r\n participants.forEach(function (_a) {\r\n var participant = _a[0], tokens = _a[1];\r\n return lotto_1.add(participant, tokens);\r\n });\r\n // Return the Lotto instance.\r\n return lotto_1;\r\n }\r\n else {\r\n // We are dealing with some lotto options.\r\n var random = participantsOrOptions.random, participants = participantsOrOptions.participants;\r\n // Create a Lotto instance passing the custom RNG function to use in place of Math.random() (which could be undefined).\r\n var lotto_2 = new Lotto_1.Lotto(random);\r\n // If the lotto participants have been defined upfront as part of the options then we will need to add them all to our lotto instance now.\r\n if (participants) {\r\n participants.forEach(function (_a) {\r\n var participant = _a[0], tokens = _a[1];\r\n return lotto_2.add(participant, tokens);\r\n });\r\n }\r\n // Return the Lotto instance.\r\n return lotto_2;\r\n }\r\n}\r\nexports.createLotto = createLotto;\r\n", "\"use strict\";\r\nObject.defineProperty(exports, \"__esModule\", { value: true });\r\nvar createLotto_1 = require(\"./createLotto\");\r\nexports.default = createLotto_1.createLotto;\r\n", "import State from \"./State\";\nimport { validateDefinition } from \"./BehaviourTreeDefinitionValidator\";\nimport { convertMDSLToJSON } from \"./mdsl/MDSLDefinitionParser\";\nimport { BehaviourTree, FlattenedTreeNode } from \"./BehaviourTree\";\nimport { BehaviourTreeOptions } from \"./BehaviourTreeOptions\";\n\nexport { BehaviourTree, State, convertMDSLToJSON, validateDefinition };\nexport type { FlattenedTreeNode, BehaviourTreeOptions };\n", "/**\n * Enumeration of node state types.\n */\nexport enum State {\n READY = \"mistreevous.ready\",\n RUNNING = \"mistreevous.running\",\n SUCCEEDED = \"mistreevous.succeeded\",\n FAILED = \"mistreevous.failed\"\n}\n\nexport { State as default };\n\nexport type CompleteState = State.SUCCEEDED | State.FAILED;\nexport type AnyState = State.READY | State.RUNNING | CompleteState;\n", "import {\n NodeDefinition,\n RootNodeDefinition,\n DecoratorNodeDefinition,\n CompositeNodeDefinition,\n AnyNodeDefinition,\n BranchNodeDefinition\n} from \"./BehaviourTreeDefinition\";\n\n/**\n * A type guard function that returns true if the specified node satisfies the RootNodeDefinition type.\n * @param node The node.\n * @returns A value of true if the specified node satisfies the RootNodeDefinition type.\n */\nexport function isRootNode(node: NodeDefinition): node is RootNodeDefinition {\n return node.type === \"root\";\n}\n\n/**\n * A type guard function that returns true if the specified node satisfies the BranchNodeDefinition type.\n * @param node The node.\n * @returns A value of true if the specified node satisfies the BranchNodeDefinition type.\n */\nexport function isBranchNode(node: NodeDefinition): node is BranchNodeDefinition {\n return node.type === \"branch\";\n}\n\n/**\n * A type guard function that returns true if the specified node satisfies the NodeDefinition type.\n * @param node The node.\n * @returns A value of true if the specified node satisfies the NodeDefinition type.\n */\nexport function isLeafNode(node: NodeDefinition): node is NodeDefinition {\n return [\"branch\", \"action\", \"condition\", \"wait\"].includes(node.type);\n}\n\n/**\n * A type guard function that returns true if the specified node satisfies the DecoratorNodeDefinition type.\n * @param node The node.\n * @returns A value of true if the specified node satisfies the DecoratorNodeDefinition type.\n */\nexport function isDecoratorNode(node: NodeDefinition): node is DecoratorNodeDefinition {\n return [\"root\", \"repeat\", \"retry\", \"flip\", \"succeed\", \"fail\"].includes(node.type);\n}\n\n/**\n * A type guard function that returns true if the specified node satisfies the CompositeNodeDefinition type.\n * @param node The node.\n * @returns A value of true if the specified node satisfies the CompositeNodeDefinition type.\n */\nexport function isCompositeNode(node: NodeDefinition): node is CompositeNodeDefinition {\n return [\"sequence\", \"selector\", \"lotto\", \"parallel\"].includes(node.type);\n}\n\n/**\n * Flatten a node definition into an array of all of its nested node definitions.\n * @param nodeDefinition The node definition to flatten.\n * @returns An array of all of nested node definitions.\n */\nexport function flattenDefinition(nodeDefinition: AnyNodeDefinition): AnyNodeDefinition[] {\n const nodes: AnyNodeDefinition[] = [];\n\n const processNode = (currentNodeDefinition: AnyNodeDefinition) => {\n nodes.push(currentNodeDefinition);\n\n if (isCompositeNode(currentNodeDefinition)) {\n currentNodeDefinition.children.forEach(processNode);\n } else if (isDecoratorNode(currentNodeDefinition)) {\n processNode(currentNodeDefinition.child);\n }\n };\n\n processNode(nodeDefinition);\n\n return nodes;\n}\n\n/**\n * Determines whether the passed value is an integer.\n * @param value The value to check.\n * @returns Whether the passed value is an integer.\n */\nexport function isInteger(value: unknown): boolean {\n return typeof value === \"number\" && Math.floor(value) === value;\n}\n\n/**\n * Determines whether the passed value is null or undefined.\n * @param value The value to check.\n * @returns Whether the passed value is null or undefined.\n */\nexport function isNullOrUndefined(value: unknown): boolean {\n return typeof value === \"undefined\" || value === null;\n}\n", "/**\n * A type defining an object that holds a reference to substitued string literals parsed from the definition.\n */\nexport type StringLiteralPlaceholders = { [key: string]: string };\n\n/**\n * Pop the next raw token from the specified array of tokens and throw an error if it wasn't the expected one.\n * @param tokens The array of tokens.\n * @param expected An optional string or array or items, one of which must match the next popped token.\n * @returns The popped token.\n */\nexport function popAndCheck(tokens: string[], expected?: string | string[]): string {\n // Get and remove the next token.\n const popped = tokens.shift();\n\n // We were expecting another token but there aren't any.\n if (popped === undefined) {\n throw new Error(\"unexpected end of definition\");\n }\n\n // Do we have an expected token/tokens array?\n if (expected != undefined) {\n // Get an array of expected values, if the popped token matches any then we are all good.\n const expectedValues = typeof expected === \"string\" ? [expected] : expected;\n\n // Check whether the popped token matches at least one of our expected items.\n var tokenMatchesExpectation = expectedValues.some((item) => popped.toUpperCase() === item.toUpperCase());\n\n // Throw an error if the popped token didn't match any of our expected items.\n if (!tokenMatchesExpectation) {\n const expectationString = expectedValues.map((item) => \"'\" + item + \"'\").join(\" or \");\n throw new Error(\"unexpected token found. Expected \" + expectationString + \" but got '\" + popped + \"'\");\n }\n }\n\n // Return the popped token.\n return popped;\n}\n\n/**\n * Swaps out any node/attribute argument string literals with placeholders.\n * @param definition The definition.\n * @returns An object containing a mapping of placeholders to original string values as well as the processed definition string.\n */\nexport function substituteStringLiterals(definition: string): {\n placeholders: StringLiteralPlaceholders;\n processedDefinition: string;\n} {\n // Create an object to hold the mapping of placeholders to original string values.\n const placeholders: StringLiteralPlaceholders = {};\n\n // Replace any string literals wrapped with double quotes in our definition with placeholders to be processed later.\n const processedDefinition = definition.replace(/\\\"(\\\\.|[^\"\\\\])*\\\"/g, (match) => {\n var strippedMatch = match.substring(1, match.length - 1);\n var placeholder = Object.keys(placeholders).find((key) => placeholders[key] === strippedMatch);\n\n // If we have no existing string literal match then create a new placeholder.\n if (!placeholder) {\n placeholder = `@@${Object.keys(placeholders).length}@@`;\n placeholders[placeholder] = strippedMatch;\n }\n\n return placeholder;\n });\n\n return { placeholders, processedDefinition };\n}\n\n/**\n * Parse the tree definition into an array of raw tokens.\n * @param definition The definition.\n * @returns An array of tokens parsed from the definition.\n */\nexport function parseTokensFromDefinition(definition: string): string[] {\n // Add some space around various important characters so that they can be plucked out easier as individual tokens.\n definition = definition.replace(/\\(/g, \" ( \");\n definition = definition.replace(/\\)/g, \" ) \");\n definition = definition.replace(/\\{/g, \" { \");\n definition = definition.replace(/\\}/g, \" } \");\n definition = definition.replace(/\\]/g, \" ] \");\n definition = definition.replace(/\\[/g, \" [ \");\n definition = definition.replace(/\\,/g, \" , \");\n\n // Split the definition into raw token form and return it.\n return definition.replace(/\\s+/g, \" \").trim().split(\" \");\n}\n", "import { StringLiteralPlaceholders, popAndCheck } from \"./MDSLUtilities\";\n\n/**\n * A type representing any node function argument.\n */\ntype Argument = {\n /**\n * The argument value.\n */\n value: T;\n /**\n * The argument type, used for validation.\n */\n type: string;\n};\n\ntype NullArgument = Argument & {\n type: \"null\";\n};\n\ntype BooleanArgument = Argument & {\n type: \"boolean\";\n};\n\ntype NumberArgument = Argument & {\n type: \"number\";\n /**\n * A flag defining whether the number argument value is a valid integer. (used for validation)\n */\n isInteger: boolean;\n};\n\ntype StringPlaceholderArgument = Argument & {\n type: \"string\";\n};\n\ntype IdentifierArgument = Argument & {\n type: \"identifier\";\n};\n\n/**\n * A type representing a reference to any node function argument.\n */\ntype AnyArgument = NullArgument | BooleanArgument | NumberArgument | StringPlaceholderArgument | IdentifierArgument;\n\n/**\n * Parse an array of argument definitions from the specified tokens array.\n * @param tokens The array tokens to parse the argument definitions from.\n * @param stringArgumentPlaceholders The mapping of string literal node argument placeholders to original values.\n * @param argumentValidator The argument validator function.\n * @param validationFailedMessage The exception message to throw if argument validation fails.\n * @returns An array of argument definitions parsed from the specified tokens array.\n */\nexport function parseArgumentTokens(\n tokens: string[],\n stringArgumentPlaceholders: StringLiteralPlaceholders\n): AnyArgument[] {\n const argumentList: AnyArgument[] = [];\n\n // If the next token is not a '[' or '(' then we have no arguments to parse.\n if (![\"[\", \"(\"].includes(tokens[0])) {\n return argumentList;\n }\n\n // Any lists of arguments will always be wrapped in '[]' for node arguments or '()' for attribute arguments.\n // We are looking for a '[' or '(' opener that wraps the argument tokens and the relevant closer.\n const closingToken = popAndCheck(tokens, [\"[\", \"(\"]) === \"[\" ? \"]\" : \")\";\n\n const argumentListTokens: string[] = [];\n\n // Grab all tokens between the '[' and ']' or '(' and ')'.\n while (tokens.length && tokens[0] !== closingToken) {\n // The next token is part of our arguments list.\n argumentListTokens.push(tokens.shift()!);\n }\n\n // Validate the order of the argument tokens. Each token must either be a ',' or a single argument that satisfies the validator.\n argumentListTokens.forEach((token, index) => {\n // Get whether this token should be an actual argument.\n const shouldBeArgumentToken = !(index & 1);\n\n // If the current token should be an actual argument then validate it, otherwise it should be a ',' token.\n if (shouldBeArgumentToken) {\n // Get the argument definition.\n const argumentDefinition = getArgumentDefinition(token, stringArgumentPlaceholders);\n\n // This is a valid argument!\n argumentList.push(argumentDefinition);\n } else {\n // The current token should be a ',' token.\n if (token !== \",\") {\n throw new Error(`invalid argument list, expected ',' or ']' but got '${token}'`);\n }\n }\n });\n\n // The arguments list should terminate with a ']' or ')' token, depending on the opener.\n popAndCheck(tokens, closingToken);\n\n // Return the arguments.\n return argumentList;\n}\n\n/**\n * Gets an argument value definition.\n * @param token The argument token.\n * @param stringArgumentPlaceholders The mapping of string literal node argument placeholders to original values.\n * @returns An argument value definition.\n */\nfunction getArgumentDefinition(token: string, stringArgumentPlaceholders: StringLiteralPlaceholders): AnyArgument {\n // Check whether the token represents a null value.\n if (token === \"null\") {\n return {\n value: null,\n type: \"null\"\n } as NullArgument;\n }\n\n // Check whether the token represents a boolean value.\n if (token === \"true\" || token === \"false\") {\n return {\n value: token === \"true\",\n type: \"boolean\"\n } as BooleanArgument;\n }\n\n // Check whether the token represents a number value.\n // TODO: Relies on broken isNaN - see MDN.\n // if (!Number.isNaN(token)) {\n if (!isNaN(token as any)) {\n return {\n value: parseFloat(token),\n isInteger: parseFloat(token) === parseInt(token, 10),\n type: \"number\"\n } as NumberArgument;\n }\n\n // Check whether the token is a placeholder (e.g. @@0@@) representing a string literal.\n if (token.match(/^@@\\d+@@$/g)) {\n return {\n value: stringArgumentPlaceholders[token].replace('\\\\\"', '\"'),\n type: \"string\"\n } as StringPlaceholderArgument;\n }\n\n // The only remaining option is that the argument value is an identifier.\n return {\n value: token,\n type: \"identifier\"\n } as IdentifierArgument;\n}\n", "import { NodeAttributeDefinition } from \"../BehaviourTreeDefinition\";\nimport { parseArgumentTokens } from \"./MDSLNodeArgumentParser\";\nimport { StringLiteralPlaceholders } from \"./MDSLUtilities\";\n\n/**\n * A type defining the attribute definitions of a node.\n */\ntype NodeAttributes = {\n while?: NodeAttributeDefinition;\n until?: NodeAttributeDefinition;\n entry?: NodeAttributeDefinition;\n exit?: NodeAttributeDefinition;\n step?: NodeAttributeDefinition;\n};\n\n/**\n * Parse any node attribute definitions from the specified tokens array.\n * @param tokens The array of remaining tokens.\n * @param stringArgumentPlaceholders The mapping of string literal node argument placeholders to original values.\n * @returns An object of attribute definitions defined by any directly following tokens.\n */\nexport function parseAttributeTokens(\n tokens: string[],\n stringArgumentPlaceholders: StringLiteralPlaceholders\n): NodeAttributes {\n const nodeAttributeNames: (keyof NodeAttributes)[] = [\"while\", \"until\", \"entry\", \"exit\", \"step\"];\n\n // Create an object to hold any attributes found.\n const attributes: NodeAttributes = {};\n\n // Try to get the name of the attribute for the next token.\n let nextAttributeName = tokens[0]?.toLowerCase() as keyof NodeAttributes;\n\n // Pull attribute tokens as well as their arguments off of the tokens stack until we have no more.\n while (nodeAttributeNames.includes(nextAttributeName)) {\n // Check to make sure that we have not already created an attribute definition of this type.\n if (attributes[nextAttributeName]) {\n throw new Error(`duplicate attribute '${tokens[0].toUpperCase()}' found for node`);\n }\n\n // Remove the attribute name token from the array of tokens.\n tokens.shift();\n\n // Grab the attribute arguments, assuming the first to be an identifier.\n const [attributeCallIdentifier, ...attributeArguments] = parseArgumentTokens(\n tokens,\n stringArgumentPlaceholders\n );\n\n // The first attribute argument has to be an identifer, this will reference an agent function.\n if (attributeCallIdentifier?.type !== \"identifier\") {\n throw new Error(\"expected agent function or registered function name identifier argument for attribute\");\n }\n\n // Any attribute arguments (other than the expected call identifier) must have a type of string, number, boolean or null.\n attributeArguments\n .filter((arg) => arg.type === \"identifier\")\n .forEach((arg) => {\n throw new Error(\n `invalid attribute argument value '${arg.value}', must be string, number, boolean or null`\n );\n });\n\n // Create the attribute definition and add it to the object of attribute definitions found.\n attributes[nextAttributeName] = {\n call: attributeCallIdentifier.value,\n args: attributeArguments.map(({ value }) => value)\n };\n\n // Try to get the next attribute name token, as there could be multiple.\n nextAttributeName = tokens[0]?.toLowerCase() as keyof NodeAttributes;\n }\n\n return attributes;\n}\n", "import {\n ActionNodeDefinition,\n AnyChildNodeDefinition,\n AnyNodeDefinition,\n BranchNodeDefinition,\n ConditionNodeDefinition,\n FailNodeDefinition,\n FlipNodeDefinition,\n LottoNodeDefinition,\n ParallelNodeDefinition,\n RepeatNodeDefinition,\n RetryNodeDefinition,\n RootNodeDefinition,\n SelectorNodeDefinition,\n SequenceNodeDefinition,\n SucceedNodeDefinition,\n WaitNodeDefinition\n} from \"../BehaviourTreeDefinition\";\nimport {\n isCompositeNode,\n isDecoratorNode,\n isLeafNode,\n isNullOrUndefined,\n isRootNode\n} from \"../BehaviourTreeDefinitionUtilities\";\nimport { parseArgumentTokens } from \"./MDSLNodeArgumentParser\";\nimport { parseAttributeTokens } from \"./MDSLNodeAttributeParser\";\nimport {\n StringLiteralPlaceholders,\n parseTokensFromDefinition,\n popAndCheck,\n substituteStringLiterals\n} from \"./MDSLUtilities\";\n\n/**\n * Convert the MDSL tree definition string into an equivalent JSON definition.\n * @param definition The tree definition string as MDSL.\n * @returns The root node JSON definitions.\n */\nexport function convertMDSLToJSON(definition: string): RootNodeDefinition[] {\n // Swap out any node/attribute argument string literals with a placeholder and get a mapping of placeholders to original values as well as the processed definition.\n const { placeholders, processedDefinition } = substituteStringLiterals(definition);\n\n // Parse our definition definition string into an array of raw tokens.\n const tokens = parseTokensFromDefinition(processedDefinition);\n\n return convertTokensToJSONDefinition(tokens, placeholders);\n}\n\n/**\n * Converts the specified tree definition tokens into a JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The root node JSON definitions.\n */\nfunction convertTokensToJSONDefinition(\n tokens: string[],\n stringLiteralPlaceholders: StringLiteralPlaceholders\n): RootNodeDefinition[] {\n // There must be at least 3 tokens for the tree definition to be valid. 'ROOT', '{' and '}'.\n if (tokens.length < 3) {\n throw new Error(\"invalid token count\");\n }\n\n // We should have a matching number of '{' and '}' tokens. If not, then there are scopes that have not been properly closed.\n if (tokens.filter((token) => token === \"{\").length !== tokens.filter((token) => token === \"}\").length) {\n throw new Error(\"scope character mismatch\");\n }\n\n // Create an array of tree stack arrays where root nodes will always be at the botton and the current composite/decorator node at the top.\n // There should be an element in this array for every root node defined and every element should be an array with a root note as the first element.\n // E.g. A definition with two root nodes defined:\n // [\n // [root, lotto, sequence],\n // [root, selector]\n // ]\n const treeStacks: [Partial, ...Partial[]][] = [];\n\n // Create an array of all root node definitions that we create.\n const rootNodes: Partial[] = [];\n\n // A helper function used to push node definitions onto the tree stack.\n const pushNode = (node: AnyNodeDefinition) => {\n // If the node is a root node then we need to create a new tree stack array with the root node at the root.\n if (isRootNode(node)) {\n // We need to double-check that this root node is not the child of another node.\n // We can do this by checking whether the top tree stack is not empty (contains an existing node)\n if (treeStacks[treeStacks.length - 1]?.length) {\n throw new Error(\"a root node cannot be the child of another node\");\n }\n\n // Add the root node definition to our array of all parsed root node definitions.\n rootNodes.push(node);\n\n // Add the root node definition to the root of a new tree stack.\n treeStacks.push([node]);\n\n return;\n }\n\n // All non-root nodes should be pushed after their root nodes so handle cases\n // where we may not have any tree stacks or our top-most tree stack is empty.\n if (!treeStacks.length || !treeStacks[treeStacks.length - 1].length) {\n throw new Error(\"expected root node at base of definition\");\n }\n\n // Get the current tree stack that we are populating.\n const topTreeStack = treeStacks[treeStacks.length - 1];\n\n // Get the top-most node in the current tree stack, this will be a composite/decorator node\n // for which we will populate its children array if composite or setting its child if a decorator.\n const topTreeStackTopNode = topTreeStack[topTreeStack.length - 1] as AnyNodeDefinition;\n\n // If the top-most node in the current root stack is a composite or decorator\n // node then the current node should be added as a child of the top-most node.\n if (isCompositeNode(topTreeStackTopNode)) {\n topTreeStackTopNode.children = topTreeStackTopNode.children || [];\n topTreeStackTopNode.children.push(node);\n } else if (isDecoratorNode(topTreeStackTopNode)) {\n // If the top node already has a child node set then throw an error as a decorator should only have a single child.\n if (topTreeStackTopNode.child) {\n throw new Error(\"a decorator node must only have a single child node\");\n }\n\n topTreeStackTopNode.child = node;\n }\n\n // If the node we are adding is also a composite or decorator node, then we should push it\n // onto the current tree stack, as subsequent nodes will be added as its child/children.\n if (!isLeafNode(node)) {\n topTreeStack.push(node);\n }\n };\n\n // A helper function used to pop the top-most node definition off of the tree stack and return it.\n const popNode = (): AnyNodeDefinition | null => {\n let poppedNode: AnyNodeDefinition | null = null;\n\n // Get the current tree stack that we are populating.\n const topTreeStack = treeStacks[treeStacks.length - 1];\n\n // Pop the top-most node in the current tree stack if there is one.\n if (topTreeStack.length) {\n poppedNode = topTreeStack.pop() as AnyNodeDefinition;\n }\n\n // We don't want any empty tree stacks in our stack of tree stacks.\n if (!topTreeStack.length) {\n treeStacks.pop();\n }\n\n return poppedNode;\n };\n\n // We should keep processing the raw tokens until we run out of them.\n while (tokens.length) {\n // Grab the next token.\n const token = tokens.shift()!;\n\n // How we create the next node depends on the current raw token value.\n switch (token.toUpperCase()) {\n case \"ROOT\": {\n pushNode(createRootNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"SUCCEED\": {\n pushNode(createSucceedNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"FAIL\": {\n pushNode(createFailNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"FLIP\": {\n pushNode(createFlipNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"REPEAT\": {\n pushNode(createRepeatNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"RETRY\": {\n pushNode(createRetryNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"SEQUENCE\": {\n pushNode(createSequenceNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"SELECTOR\": {\n pushNode(createSelectorNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"PARALLEL\": {\n pushNode(createParallelNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"LOTTO\": {\n pushNode(createLottoNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"ACTION\": {\n pushNode(createActionNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"CONDITION\": {\n pushNode(createConditionNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"WAIT\": {\n pushNode(createWaitNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"BRANCH\": {\n pushNode(createBranchNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"}\": {\n // The '}' character closes the current scope and means that we have to pop a node off of the current stack.\n const poppedNode = popNode();\n\n // Now that we have a node definition we can carry out any validation that may require the node to be fully populated.\n if (poppedNode) {\n validatePoppedNode(poppedNode);\n }\n\n break;\n }\n\n default: {\n throw new Error(`unexpected token: ${token}`);\n }\n }\n }\n\n return rootNodes as RootNodeDefinition[];\n}\n\n/**\n * Creates a root node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The root node JSON definition.\n */\nfunction createRootNode(tokens: string[], stringLiteralPlaceholders: StringLiteralPlaceholders): RootNodeDefinition {\n // Create the root node definition.\n let node = {\n type: \"root\"\n } as Partial;\n\n // Parse any node arguments, we should only have one if any which will be an identifier argument for the root identifier.\n const nodeArguments = parseArgumentTokens(tokens, stringLiteralPlaceholders);\n\n // Check whether any node arguments were defined.\n if (nodeArguments.length) {\n // We should only have one argument, if any, which will be an identifier argument for the root identifier.\n if (nodeArguments.length === 1 && nodeArguments[0].type === \"identifier\") {\n // The root node identifier will be the first and only node argument value.\n node.id = nodeArguments[0].value as string;\n } else {\n throw new Error(\"expected single root name argument\");\n }\n }\n\n // Grab any node attribute definitions and spread them into the node definition.\n node = { ...node, ...parseAttributeTokens(tokens, stringLiteralPlaceholders) };\n\n // This is a decorator node, so we expect an opening '{'.\n popAndCheck(tokens, \"{\");\n\n // Return the root node definition.\n return node as RootNodeDefinition;\n}\n\n/**\n * Creates a succeed node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The succeed node JSON definition.\n */\nfunction createSucceedNode(\n tokens: string[],\n stringLiteralPlaceholders: StringLiteralPlaceholders\n): SucceedNodeDefinition {\n const node = {\n type: \"succeed\",\n ...parseAttributeTokens(tokens, stringLiteralPlaceholders)\n } as SucceedNodeDefinition;\n\n // This is a decorator node, so we expect an opening '{'.\n popAndCheck(tokens, \"{\");\n\n // Return the succeed node definition.\n return node;\n}\n\n/**\n * Creates a fail node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The fail node JSON definition.\n */\nfunction createFailNode(tokens: string[], stringLiteralPlaceholders: StringLiteralPlaceholders): FailNodeDefinition {\n const node = {\n type: \"fail\",\n ...parseAttributeTokens(tokens, stringLiteralPlaceholders)\n } as FailNodeDefinition;\n\n // This is a decorator node, so we expect an opening '{'.\n popAndCheck(tokens, \"{\");\n\n // Return the fail node definition.\n return node;\n}\n\n/**\n * Creates a flip node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The flip node JSON definition.\n */\nfunction createFlipNode(tokens: string[], stringLiteralPlaceholders: StringLiteralPlaceholders): FlipNodeDefinition {\n const node = {\n type: \"flip\",\n ...parseAttributeTokens(tokens, stringLiteralPlaceholders)\n } as FlipNodeDefinition;\n\n // This is a decorator node, so we expect an opening '{'.\n popAndCheck(tokens, \"{\");\n\n // Return the flip node definition.\n return node;\n}\n\n/**\n * Creates a repeat node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The repeat node JSON definition.\n */\nfunction createRepeatNode(\n tokens: string[],\n stringLiteralPlaceholders: StringLiteralPlaceholders\n): RepeatNodeDefinition {\n let node = { type: \"repeat\" } as RepeatNodeDefinition;\n\n // Get the node arguments.\n const nodeArguments = parseArgumentTokens(tokens, stringLiteralPlaceholders);\n\n // The arguments of a repeat node are optional. We may have:\n // - No node arguments, in which case the repeat note will iterate indefinitely.\n // - One node argument which will be the explicit number of iterations to make.\n // - Two node arguments which define the min and max iteration bounds from which a random iteration count will be picked.\n if (nodeArguments.length) {\n // All repeat node arguments MUST be of type number and must be integer.\n nodeArguments\n .filter((arg) => arg.type !== \"number\" || !arg.isInteger)\n .forEach(() => {\n throw new Error(`repeat node iteration counts must be integer values`);\n });\n\n // We should have got one or two iteration counts.\n if (nodeArguments.length === 1) {\n // A static iteration count was defined.\n node.iterations = nodeArguments[0].value as number;\n\n // A repeat node must have a positive number of iterations if defined.\n if (node.iterations < 0) {\n throw new Error(\"a repeat node must have a positive number of iterations if defined\");\n }\n } else if (nodeArguments.length === 2) {\n // A minimum and maximum iteration count was defined.\n node.iterations = [nodeArguments[0].value as number, nodeArguments[1].value as number];\n\n // A repeat node must have a positive min and max iteration count if they are defined.\n if (node.iterations[0] < 0 || node.iterations[1] < 0) {\n throw new Error(\"a repeat node must have a positive minimum and maximum iteration count if defined\");\n }\n\n // A repeat node must not have an minimum iteration count that exceeds the maximum iteration count.\n if (node.iterations[0] > node.iterations[1]) {\n throw new Error(\n \"a repeat node must not have a minimum iteration count that exceeds the maximum iteration count\"\n );\n }\n } else {\n // An incorrect number of iteration counts was defined.\n throw new Error(\"invalid number of repeat node iteration count arguments defined\");\n }\n }\n\n // Grab any node attribute definitions and spread them into the node definition.\n node = { ...node, ...parseAttributeTokens(tokens, stringLiteralPlaceholders) };\n\n // This is a decorator node, so we expect an opening '{'.\n popAndCheck(tokens, \"{\");\n\n // Return the repeat node definition.\n return node;\n}\n\n/**\n * Creates a retry node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The retry node JSON definition.\n */\nfunction createRetryNode(tokens: string[], stringLiteralPlaceholders: StringLiteralPlaceholders): RetryNodeDefinition {\n let node = { type: \"retry\" } as RetryNodeDefinition;\n\n // Get the node arguments.\n const nodeArguments = parseArgumentTokens(tokens, stringLiteralPlaceholders);\n\n // The arguments of a retry node are optional. We may have:\n // - No node arguments, in which case the retry note will attempt indefinitely.\n // - One node argument which will be the explicit number of attempts to make.\n // - Two node arguments which define the min and max attempt bounds from which a random attempt count will be picked.\n if (nodeArguments.length) {\n // All retry node arguments MUST be of type number and must be integer.\n nodeArguments\n .filter((arg) => arg.type !== \"number\" || !arg.isInteger)\n .forEach(() => {\n throw new Error(`retry node attempt counts must be integer values`);\n });\n\n // We should have got one or two attempt counts.\n if (nodeArguments.length === 1) {\n // A static attempt count was defined.\n node.attempts = nodeArguments[0].value as number;\n\n // A retry node must have a positive number of attempts if defined.\n if (node.attempts < 0) {\n throw new Error(\"a retry node must have a positive number of attempts if defined\");\n }\n } else if (nodeArguments.length === 2) {\n // A minimum and maximum attempt count was defined.\n node.attempts = [nodeArguments[0].value as number, nodeArguments[1].value as number];\n\n // A retry node must have a positive min and max attempts count if they are defined.\n if (node.attempts[0] < 0 || node.attempts[1] < 0) {\n throw new Error(\"a retry node must have a positive minimum and maximum attempt count if defined\");\n }\n\n // A retry node must not have a minimum attempt count that exceeds the maximum attempt count.\n if (node.attempts[0] > node.attempts[1]) {\n throw new Error(\n \"a retry node must not have a minimum attempt count that exceeds the maximum attempt count\"\n );\n }\n } else {\n // An incorrect number of attempt counts was defined.\n throw new Error(\"invalid number of retry node attempt count arguments defined\");\n }\n }\n\n // Grab any node attribute definitions and spread them into the node definition.\n node = { ...node, ...parseAttributeTokens(tokens, stringLiteralPlaceholders) };\n\n // This is a decorator node, so we expect an opening '{'.\n popAndCheck(tokens, \"{\");\n\n // Return the retry node definition.\n return node;\n}\n\n/**\n * Creates a sequence node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The sequence node JSON definition.\n */\nfunction createSequenceNode(\n tokens: string[],\n stringLiteralPlaceholders: StringLiteralPlaceholders\n): SequenceNodeDefinition {\n const node = {\n type: \"sequence\",\n ...parseAttributeTokens(tokens, stringLiteralPlaceholders)\n } as SequenceNodeDefinition;\n\n // This is a composite node, so we expect an opening '{'.\n popAndCheck(tokens, \"{\");\n\n // Return the sequence node definition.\n return node;\n}\n\n/**\n * Creates a selector node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The selector node JSON definition.\n */\nfunction createSelectorNode(\n tokens: string[],\n stringLiteralPlaceholders: StringLiteralPlaceholders\n): SelectorNodeDefinition {\n const node = {\n type: \"selector\",\n ...parseAttributeTokens(tokens, stringLiteralPlaceholders)\n } as SelectorNodeDefinition;\n\n // This is a composite node, so we expect an opening '{'.\n popAndCheck(tokens, \"{\");\n\n // Return the selector node definition.\n return node;\n}\n\n/**\n * Creates a parallel node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The parallel node JSON definition.\n */\nfunction createParallelNode(\n tokens: string[],\n stringLiteralPlaceholders: StringLiteralPlaceholders\n): ParallelNodeDefinition {\n const node = {\n type: \"parallel\",\n ...parseAttributeTokens(tokens, stringLiteralPlaceholders)\n } as ParallelNodeDefinition;\n\n // This is a composite node, so we expect an opening '{'.\n popAndCheck(tokens, \"{\");\n\n // Return the parallel node definition.\n return node;\n}\n\n/**\n * Creates a lotto node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The lotto node JSON definition.\n */\nfunction createLottoNode(tokens: string[], stringLiteralPlaceholders: StringLiteralPlaceholders): LottoNodeDefinition {\n // If any node arguments have been defined then they must be our weights.\n const nodeArguments = parseArgumentTokens(tokens, stringLiteralPlaceholders);\n\n // All lotto node arguments MUST be of type number and must be positive integers.\n nodeArguments\n .filter((arg) => arg.type !== \"number\" || !arg.isInteger || arg.value < 0)\n .forEach(() => {\n throw new Error(`lotto node weight arguments must be positive integer values`);\n });\n\n const node = {\n type: \"lotto\",\n ...parseAttributeTokens(tokens, stringLiteralPlaceholders)\n } as LottoNodeDefinition;\n\n // Apply the weights if any were defined.\n if (nodeArguments.length) {\n node.weights = nodeArguments.map(({ value }) => value) as number[];\n }\n\n // This is a composite node, so we expect an opening '{'.\n popAndCheck(tokens, \"{\");\n\n // Return the lotto node definition.\n return node;\n}\n\n/**\n * Creates an action node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The action node JSON definition.\n */\nfunction createActionNode(\n tokens: string[],\n stringLiteralPlaceholders: StringLiteralPlaceholders\n): ActionNodeDefinition {\n // Parse any node arguments, we should have at least one which will be an identifier argument for the action name\n // and agent function to invoke for the action, all other arguments are to be passed as arguments to that function.\n const [actionNameIdentifier, ...agentFunctionArgs] = parseArgumentTokens(tokens, stringLiteralPlaceholders);\n\n // Our first argument MUST be defined and be an identifier as we require an action name argument.\n if (actionNameIdentifier?.type !== \"identifier\") {\n throw new Error(\"expected action name identifier argument\");\n }\n\n // Only the first argument should have been an identifier, all agent function arguments must be string, number, boolean or null.\n agentFunctionArgs\n .filter((arg) => arg.type === \"identifier\")\n .forEach((arg) => {\n throw new Error(\n `invalid action node argument value '${arg.value}', must be string, number, boolean or null`\n );\n });\n\n // Return the action node definition.\n return {\n type: \"action\",\n call: actionNameIdentifier.value,\n args: agentFunctionArgs.map(({ value }) => value),\n ...parseAttributeTokens(tokens, stringLiteralPlaceholders)\n };\n}\n\n/**\n * Creates a condition node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The condition node JSON definition.\n */\nfunction createConditionNode(\n tokens: string[],\n stringLiteralPlaceholders: StringLiteralPlaceholders\n): ConditionNodeDefinition {\n // Parse any node arguments, we should have at least one which will be an identifier argument for the condition name\n // and agent function to invoke for the condition, all other arguments are to be passed as arguments to that function.\n const [conditionNameIdentifier, ...agentFunctionArgs] = parseArgumentTokens(tokens, stringLiteralPlaceholders);\n\n // Our first argument MUST be defined and be an identifier as we require a condition name argument.\n if (conditionNameIdentifier?.type !== \"identifier\") {\n throw new Error(\"expected condition name identifier argument\");\n }\n\n // Only the first argument should have been an identifier, all agent function arguments must be string, number, boolean or null.\n agentFunctionArgs\n .filter((arg) => arg.type === \"identifier\")\n .forEach((arg) => {\n throw new Error(\n `invalid condition node argument value '${arg.value}', must be string, number, boolean or null`\n );\n });\n\n // Return the condition node definition.\n return {\n type: \"condition\",\n call: conditionNameIdentifier.value,\n args: agentFunctionArgs.map(({ value }) => value),\n ...parseAttributeTokens(tokens, stringLiteralPlaceholders)\n };\n}\n\n/**\n * Creates a wait node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The wait node JSON definition.\n */\nfunction createWaitNode(tokens: string[], stringLiteralPlaceholders: StringLiteralPlaceholders): WaitNodeDefinition {\n let node = { type: \"wait\" } as WaitNodeDefinition;\n\n // Get the node arguments.\n const nodeArguments = parseArgumentTokens(tokens, stringLiteralPlaceholders);\n\n // The arguments of a wait node are optional. We may have:\n // - No node arguments, in which case the wait will be indefinite until it is aborted.\n // - One node argument which will be the explicit duration of the wait.\n // - Two node arguments which define the min and max duration bounds from which a random duration will be picked.\n if (nodeArguments.length) {\n // All wait node arguments MUST be of type number and must be integer.\n nodeArguments\n .filter((arg) => arg.type !== \"number\" || !arg.isInteger)\n .forEach(() => {\n throw new Error(`wait node durations must be integer values`);\n });\n\n // We may have:\n // - One node argument which will be the explicit duration of the wait.\n // - Two node arguments which define the min and max duration bounds from which a random duration will be picked.\n // - Too many arguments, which is not valid.\n if (nodeArguments.length === 1) {\n // An explicit duration was defined.\n node.duration = nodeArguments[0].value as number;\n\n // If an explict duration was defined then it must be a positive number.\n if (node.duration < 0) {\n throw new Error(\"a wait node must have a positive duration\");\n }\n } else if (nodeArguments.length === 2) {\n // Min and max duration bounds were defined from which a random duration will be picked.\n node.duration = [nodeArguments[0].value as number, nodeArguments[1].value as number];\n\n // A wait node must have a positive min and max duration.\n if (node.duration[0] < 0 || node.duration[1] < 0) {\n throw new Error(\"a wait node must have a positive minimum and maximum duration\");\n }\n\n // A wait node must not have a minimum duration that exceeds the maximum duration.\n if (node.duration[0] > node.duration[1]) {\n throw new Error(\"a wait node must not have a minimum duration that exceeds the maximum duration\");\n }\n } else if (nodeArguments.length > 2) {\n // An incorrect number of duration arguments were defined.\n throw new Error(\"invalid number of wait node duration arguments defined\");\n }\n }\n\n // Return the wait node definition.\n return { ...node, ...parseAttributeTokens(tokens, stringLiteralPlaceholders) };\n}\n\n/**\n * Creates a branch node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The branch node JSON definition.\n */\nfunction createBranchNode(\n tokens: string[],\n stringLiteralPlaceholders: StringLiteralPlaceholders\n): BranchNodeDefinition {\n // Parse any node arguments, we should have one which will be an identifier argument for the root ref.\n const nodeArguments = parseArgumentTokens(tokens, stringLiteralPlaceholders);\n\n // We should have only a single identifer argument for a branch node, which is the root ref.\n if (nodeArguments.length !== 1 || nodeArguments[0].type !== \"identifier\") {\n throw new Error(\"expected single branch name argument\");\n }\n\n // Return the branch node definition.\n return { type: \"branch\", ref: nodeArguments[0].value };\n}\n\n/**\n * Validate a fully-populated node definition that was popped off of the tree stack.\n * @param definition The popped node to validate.\n */\nfunction validatePoppedNode(definition: AnyNodeDefinition): void {\n // Decorators MUST have a child defined.\n if (isDecoratorNode(definition) && isNullOrUndefined(definition.child)) {\n throw new Error(`a ${definition.type} node must have a single child node defined`);\n }\n\n // Composites MUST have at least one child defined.\n if (isCompositeNode(definition) && !definition.children?.length) {\n throw new Error(`a ${definition.type} node must have at least a single child node defined`);\n }\n\n // We need to make sure that lotto nodes that have weights defined have a number of weights matching the number of child nodes.\n if (definition.type === \"lotto\") {\n // Check whether a 'weights' property has been defined, if it has we expect it to be an array of weights.\n if (typeof definition.weights !== \"undefined\") {\n // Check that the weights property is an array of positive integers with an element for each child node element.\n if (definition.weights.length !== definition.children.length) {\n throw new Error(\n \"expected a number of weight arguments matching the number of child nodes for lotto node\"\n );\n }\n }\n }\n}\n", "import { RootNodeDefinition } from \"./BehaviourTreeDefinition\";\nimport { flattenDefinition, isBranchNode, isInteger } from \"./BehaviourTreeDefinitionUtilities\";\nimport { convertMDSLToJSON } from \"./mdsl/MDSLDefinitionParser\";\n\n/**\n * An object representing the result of validating a tree definition.\n */\nexport type DefinitionValidationResult = {\n /**\n * A flag defining whether validation succeeded.\n */\n succeeded: boolean;\n /**\n * A string containing the error message if validation did not succeed.\n */\n errorMessage?: string;\n /**\n * The definition as json if the validation was successful, or undefined if validation did not succeed.\n */\n json?: RootNodeDefinition[];\n};\n\n/**\n * Validates the specified behaviour tree definition in the form of JSON or MDSL, not taking any globally registered subtrees into consideration.\n * @param definition The behaviour tree definition in the form of JSON or MDSL.\n * @returns An object representing the result of validating the given tree definition.\n */\nexport function validateDefinition(definition: any): DefinitionValidationResult {\n // The definition must be defined.\n if (definition === null || typeof definition === \"undefined\") {\n return createValidationFailureResult(\"definition is null or undefined\");\n }\n\n // We are expecting a definition in one of three different forms:\n // - A string which we will assume is MDSL and we will parse this to JSON before validation.\n // - An array which we will assume is an array of root node definitions with at least one being the primary root node (no 'id' property)\n // - An object which we will assume is the primary root node and should not have an 'id' property.\n if (typeof definition === \"string\") {\n // The definition is a string which we can assume is MDSL, so attempt to validate it.\n return validateMDSLDefinition(definition);\n } else if (typeof definition === \"object\") {\n // The definition will either be an array (of root node definitions) or an object (the single primary root node definition).\n return validateJSONDefinition(definition);\n } else {\n return createValidationFailureResult(`unexpected definition type of '${typeof definition}'`);\n }\n}\n\n/**\n * Validates the specified behaviour tree definition in the form of MDSL.\n * @param definition The behaviour tree definition in the form of MDSL.\n * @returns An object representing the result of validating the given tree definition.\n */\nfunction validateMDSLDefinition(definition: string): DefinitionValidationResult {\n let rootNodeDefinitions;\n\n // The first thing the we need to do is to attempt to convert our MDSL into JSON.\n try {\n // The definition is a string which we can assume is MDSL, so attempt to parse it to a JSON definition in the form of an array of root node definitions.\n rootNodeDefinitions = convertMDSLToJSON(definition);\n } catch (exception) {\n // We failed to parse the JSON from the MDSL, this is likely to be the result of it not being a valid MDSL string.\n return createValidationFailureResult((exception as Error).message);\n }\n\n // Unpack all of the root node definitions into arrays of main ('id' defined) and sub ('id' not defined) root node definitions.\n const mainRootNodeDefinitions = rootNodeDefinitions.filter(({ id }) => typeof id === \"undefined\");\n const subRootNodeDefinitions = rootNodeDefinitions.filter(({ id }) => typeof id === \"string\" && id.length > 0);\n\n // We should ALWAYS have exactly one root node definition without an 'id' property defined, which is out main root node definition.\n if (mainRootNodeDefinitions.length !== 1) {\n return createValidationFailureResult(\n \"expected single unnamed root node at base of definition to act as main root\"\n );\n }\n\n // We should never have duplicate 'id' properties across our sub root node definitions.\n const subRootNodeIdenitifers: string[] = [];\n for (const { id } of subRootNodeDefinitions) {\n // Have we already come across this 'id' property value?\n if (subRootNodeIdenitifers.includes(id!)) {\n return createValidationFailureResult(`multiple root nodes found with duplicate name '${id}'`);\n }\n\n subRootNodeIdenitifers.push(id!);\n }\n\n try {\n // Validate our branch -> subtree links and check for any circular dependencies, we don't care about checking for broken subtree links here.\n validateBranchSubtreeLinks(rootNodeDefinitions, false);\n } catch (exception) {\n return createValidationFailureResult((exception as Error).message);\n }\n\n // Our definition was valid!\n return {\n succeeded: true,\n json: rootNodeDefinitions\n };\n}\n\n/**\n * Validates the specified behaviour tree definition in the form of JSON.\n * @param definition The behaviour tree definition in the form of JSON.\n * @returns An object representing the result of validating the given tree definition.\n */\nexport function validateJSONDefinition(\n definition: RootNodeDefinition | RootNodeDefinition[]\n): DefinitionValidationResult {\n // The definition will either be an array (of root node definitions) or an object (the single primary root node definition).\n const rootNodeDefinitions = Array.isArray(definition) ? definition : [definition];\n\n // Iterate over our array of root nodes and call validateNode for each, passing an initial depth of 0, wrapped in a try catch to handle validation failures.\n try {\n rootNodeDefinitions.forEach((rootNodeDefinition) => validateNode(rootNodeDefinition, 0));\n } catch (error) {\n // Handle cases where we have caught a thrown Error and return a failure result with the error message.\n if (error instanceof Error) {\n return createValidationFailureResult(error.message);\n }\n\n // No idea what happened here!\n return createValidationFailureResult(`unexpected error: ${error}`);\n }\n\n // Unpack all of the root node definitions into arrays of main ('id' defined) and sub ('id' not defined) root node definitions.\n const mainRootNodeDefinitions = rootNodeDefinitions.filter(({ id }) => typeof id === \"undefined\");\n const subRootNodeDefinitions = rootNodeDefinitions.filter(({ id }) => typeof id === \"string\" && id.length > 0);\n\n // We should ALWAYS have exactly one root node definition without an 'id' property defined, which is out main root node definition.\n if (mainRootNodeDefinitions.length !== 1) {\n return createValidationFailureResult(\n \"expected single root node without 'id' property defined to act as main root\"\n );\n }\n\n // We should never have duplicate 'id' properties across our sub root node definitions.\n const subRootNodeIdenitifers: string[] = [];\n for (const { id } of subRootNodeDefinitions) {\n // Have we already come across this 'id' property value?\n if (subRootNodeIdenitifers.includes(id!)) {\n return createValidationFailureResult(\n `multiple root nodes found with duplicate 'id' property value of '${id}'`\n );\n }\n\n subRootNodeIdenitifers.push(id!);\n }\n\n try {\n // Validate our branch -> subtree links and check for any circular dependencies, we don't care about checking for broken subtree links here.\n validateBranchSubtreeLinks(rootNodeDefinitions, false);\n } catch (exception) {\n return createValidationFailureResult((exception as Error).message);\n }\n\n // Our definition was valid!\n return {\n succeeded: true,\n json: rootNodeDefinitions\n };\n}\n\n/**\n * Validates the branch -> subtree links across all provided root node definitions.\n * This will not consider branch nodes that reference any globally registered subtrees unless includesGlobalSubtrees\n * is set to true, in which case we will also verify that there are no broken branch -> subtree links.\n * @param rootNodeDefinitions The array of root node definitions.\n * @param includesGlobalSubtrees A flag defining whether the array includes all global subtree root node definitions.\n */\nexport function validateBranchSubtreeLinks(rootNodeDefinitions: RootNodeDefinition[], includesGlobalSubtrees: boolean) {\n // Create a mapping of root node identifiers to other root nodes that they reference via branch nodes.\n // Below is an example of a mapping that includes a circular dependency (root => a => b => c => a)\n // [{ refs: [\"a\", \"b\"] }, { id: \"a\", refs: [\"b\"] }, { id: \"b\", refs: [\"c\"] }, { id: \"c\", refs: [\"a\"] }]\n const rootNodeMappings: { id: string | undefined; refs: string[] }[] = rootNodeDefinitions.map(\n (rootNodeDefinition) => ({\n id: rootNodeDefinition.id,\n refs: flattenDefinition(rootNodeDefinition)\n .filter(isBranchNode)\n .map(({ ref }) => ref)\n })\n );\n\n // A recursive function to walk through the mappings, keeping track of which root nodes we have visited in the form of a path of root node identifiers.\n const followRefs = (mapping: { id: string | undefined; refs: string[] }, path: (string | undefined)[] = []) => {\n // Have we found a circular dependency?\n if (path.includes(mapping.id)) {\n // We found a circular dependency! Get the bad path of root node identifiers.\n const badPath = [...path, mapping.id];\n\n // Create the formatted path value. [undefined, \"a\", \"b\", \"c\", \"a\"] would be formatted as \"a -> b -> c -> a\".\n const badPathFormatted = badPath.filter((element) => !!element).join(\" => \");\n\n // No need to continue, we found a circular dependency.\n throw new Error(`circular dependency found in branch node references: ${badPathFormatted}`);\n }\n\n for (const ref of mapping.refs) {\n // Find the mapping for the root node with an identifer matching the current ref.\n const subMapping = rootNodeMappings.find(({ id }) => id === ref);\n\n // We may not have a mapping for this ref, which is normal when we aren't considering all globally registered subtrees.\n if (subMapping) {\n followRefs(subMapping, [...path, mapping.id]);\n } else if (includesGlobalSubtrees) {\n // We found a reference to a root node that doesn't exist, which is a problem seeing as the root node definitons includes all globally registered subtrees.\n throw new Error(\n mapping.id\n ? `subtree '${mapping.id}' has branch node that references root node '${ref}' which has not been defined`\n : `primary tree has branch node that references root node '${ref}' which has not been defined`\n );\n }\n }\n };\n\n // Start looking for circular dependencies and broken references from the primary root node definition.\n followRefs(rootNodeMappings.find((mapping) => typeof mapping.id === \"undefined\")!);\n}\n\n/**\n * Validate an object that we expect to be a node definition.\n * @param definition An object that we expect to be a node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateNode(definition: any, depth: number): void {\n // Every node must be valid object and have a non-empty 'type' string property.\n if (typeof definition !== \"object\" || typeof definition.type !== \"string\" || definition.type.length === 0) {\n throw new Error(\n `node definition is not an object or 'type' property is not a non-empty string at depth '${depth}'`\n );\n }\n\n // How we validate this node definition will depend on its type.\n switch (definition.type) {\n case \"action\":\n validateActionNode(definition, depth);\n break;\n\n case \"condition\":\n validateConditionNode(definition, depth);\n break;\n\n case \"wait\":\n validateWaitNode(definition, depth);\n break;\n\n case \"branch\":\n validateBranchNode(definition, depth);\n break;\n\n case \"root\":\n validateRootNode(definition, depth);\n break;\n\n case \"succeed\":\n validateSucceedNode(definition, depth);\n break;\n\n case \"fail\":\n validateFailNode(definition, depth);\n break;\n\n case \"flip\":\n validateFlipNode(definition, depth);\n break;\n\n case \"repeat\":\n validateRepeatNode(definition, depth);\n break;\n\n case \"retry\":\n validateRetryNode(definition, depth);\n break;\n\n case \"sequence\":\n validateSequenceNode(definition, depth);\n break;\n\n case \"selector\":\n validateSelectorNode(definition, depth);\n break;\n\n case \"parallel\":\n validateParallelNode(definition, depth);\n break;\n\n case \"lotto\":\n validateLottoNode(definition, depth);\n break;\n\n default:\n throw new Error(`unexpected node type of '${definition.type}' at depth '${depth}'`);\n }\n}\n\n/**\n * Validate any attributes for a given node definition.\n * @param definition The node definition.\n * @param depth The depth of the node in the behaviour tree definition.\n */\nfunction validateNodeAttributes(definition: any, depth: number): void {\n // Validate each of the attribute types for this node.\n [\"while\", \"until\", \"entry\", \"exit\", \"step\"].forEach((attributeName) => {\n // Attempt to grab the definition for the current attribute from the node definition.\n const attributeDefinition = definition[attributeName];\n\n // All node attributes are optional, so there is nothing to do if the current attribute is not defined.\n if (typeof attributeDefinition === \"undefined\") {\n return;\n }\n\n // The attribute definition must be an object.\n if (typeof attributeDefinition !== \"object\") {\n throw new Error(\n `expected attribute '${attributeName}' to be an object for '${definition.type}' node at depth '${depth}'`\n );\n }\n\n // The 'call' property must be defined for any attribute definition.\n if (typeof attributeDefinition.call !== \"string\" || attributeDefinition.call.length === 0) {\n throw new Error(\n `expected 'call' property for attribute '${attributeName}' to be a non-empty string for '${definition.type}' node at depth '${depth}'`\n );\n }\n\n // If any node attribute arguments have been defined then they must have been defined in an array.\n if (typeof attributeDefinition.args !== \"undefined\" && !Array.isArray(attributeDefinition.args)) {\n throw new Error(\n `expected 'args' property for attribute '${attributeName}' to be an array for '${definition.type}' node at depth '${depth}'`\n );\n }\n });\n}\n\n/**\n * Validate an object that we expect to be a root node definition.\n * @param definition An object that we expect to be a root node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateRootNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"root\") {\n throw new Error(\"expected node type of 'root' for root node\");\n }\n\n // A root node cannot be the child of another node.\n if (depth > 0) {\n throw new Error(\"a root node cannot be the child of another node\");\n }\n\n // Check that, if the root node 'id' property is defined, it is a non-empty string.\n if (typeof definition.id !== \"undefined\" && (typeof definition.id !== \"string\" || definition.id.length === 0)) {\n throw new Error(\"expected non-empty string for 'id' property if defined for root node\");\n }\n\n // A root node is a decorator node, so must have a child node defined.\n if (typeof definition.child === \"undefined\") {\n throw new Error(\"expected property 'child' to be defined for root node\");\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n\n // Validate the child node of this decorator node.\n validateNode(definition.child, depth + 1);\n}\n\n/**\n * Validate an object that we expect to be a succeed node definition.\n * @param definition An object that we expect to be a succeed node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateSucceedNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"succeed\") {\n throw new Error(`expected node type of 'succeed' for succeed node at depth '${depth}'`);\n }\n\n // A succeed node is a decorator node, so must have a child node defined.\n if (typeof definition.child === \"undefined\") {\n throw new Error(`expected property 'child' to be defined for succeed node at depth '${depth}'`);\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n\n // Validate the child node of this decorator node.\n validateNode(definition.child, depth + 1);\n}\n\n/**\n * Validate an object that we expect to be a fail node definition.\n * @param definition An object that we expect to be a fail node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateFailNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"fail\") {\n throw new Error(`expected node type of 'fail' for fail node at depth '${depth}'`);\n }\n\n // A fail node is a decorator node, so must have a child node defined.\n if (typeof definition.child === \"undefined\") {\n throw new Error(`expected property 'child' to be defined for fail node at depth '${depth}'`);\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n\n // Validate the child node of this decorator node.\n validateNode(definition.child, depth + 1);\n}\n\n/**\n * Validate an object that we expect to be a flip node definition.\n * @param definition An object that we expect to be a flip node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateFlipNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"flip\") {\n throw new Error(`expected node type of 'flip' for flip node at depth '${depth}'`);\n }\n\n // A flip node is a decorator node, so must have a child node defined.\n if (typeof definition.child === \"undefined\") {\n throw new Error(`expected property 'child' to be defined for flip node at depth '${depth}'`);\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n\n // Validate the child node of this decorator node.\n validateNode(definition.child, depth + 1);\n}\n\n/**\n * Validate an object that we expect to be a repeat node definition.\n * @param definition An object that we expect to be a repeat node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateRepeatNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"repeat\") {\n throw new Error(`expected node type of 'repeat' for repeat node at depth '${depth}'`);\n }\n\n // A repeat node is a decorator node, so must have a child node defined.\n if (typeof definition.child === \"undefined\") {\n throw new Error(`expected property 'child' to be defined for repeat node at depth '${depth}'`);\n }\n\n // Check whether an 'iterations' property has been defined, it may not have been if this node is to repeat indefinitely.\n if (typeof definition.iterations !== \"undefined\") {\n if (Array.isArray(definition.iterations)) {\n // Check whether any elements of the array are not integer values.\n const containsNonInteger = !!definition.iterations.filter((value: unknown) => !isInteger(value)).length;\n\n // If the 'iterations' property is an array then it MUST contain two integer values.\n if (definition.iterations.length !== 2 || containsNonInteger) {\n throw new Error(\n `expected array containing two integer values for 'iterations' property if defined for repeat node at depth '${depth}'`\n );\n }\n\n // A repeat node must have a positive min and max iterations count if they are defined.\n if (definition.iterations[0] < 0 || definition.iterations[1] < 0) {\n throw new Error(\n `expected positive minimum and maximum iterations count for 'iterations' property if defined for repeat node at depth '${depth}'`\n );\n }\n\n // A repeat node must not have a minimum iterations count that exceeds the maximum iterations count.\n if (definition.iterations[0] > definition.iterations[1]) {\n throw new Error(\n `expected minimum iterations count that does not exceed the maximum iterations count for 'iterations' property if defined for repeat node at depth '${depth}'`\n );\n }\n } else if (isInteger(definition.iterations)) {\n // A repeat node must have a positive number of iterations if defined.\n if (definition.iterations < 0) {\n throw new Error(\n `expected positive iterations count for 'iterations' property if defined for repeat node at depth '${depth}'`\n );\n }\n } else {\n throw new Error(\n `expected integer value or array containing two integer values for 'iterations' property if defined for repeat node at depth '${depth}'`\n );\n }\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n\n // Validate the child node of this decorator node.\n validateNode(definition.child, depth + 1);\n}\n\n/**\n * Validate an object that we expect to be a retry node definition.\n * @param definition An object that we expect to be a retry node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateRetryNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"retry\") {\n throw new Error(`expected node type of 'retry' for retry node at depth '${depth}'`);\n }\n\n // A retry node is a decorator node, so must have a child node defined.\n if (typeof definition.child === \"undefined\") {\n throw new Error(`expected property 'child' to be defined for retry node at depth '${depth}'`);\n }\n\n // Check whether an 'attempts' property has been defined, it may not have been if this node is to retry indefinitely.\n if (typeof definition.attempts !== \"undefined\") {\n if (Array.isArray(definition.attempts)) {\n // Check whether any elements of the array are not integer values.\n const containsNonInteger = !!definition.attempts.filter((value: unknown) => !isInteger(value)).length;\n\n // If the 'attempts' property is an array then it MUST contain two integer values.\n if (definition.attempts.length !== 2 || containsNonInteger) {\n throw new Error(\n `expected array containing two integer values for 'attempts' property if defined for retry node at depth '${depth}'`\n );\n }\n\n // A retry node must have a positive min and max attempts count if they are defined.\n if (definition.attempts[0] < 0 || definition.attempts[1] < 0) {\n throw new Error(\n `expected positive minimum and maximum attempts count for 'attempts' property if defined for retry node at depth '${depth}'`\n );\n }\n\n // A retry node must not have a minimum attempts count that exceeds the maximum attempts count.\n if (definition.attempts[0] > definition.attempts[1]) {\n throw new Error(\n `expected minimum attempts count that does not exceed the maximum attempts count for 'attempts' property if defined for retry node at depth '${depth}'`\n );\n }\n } else if (isInteger(definition.attempts)) {\n // A retry node must have a positive number of attempts if defined.\n if (definition.attempts < 0) {\n throw new Error(\n `expected positive attempts count for 'attempts' property if defined for retry node at depth '${depth}'`\n );\n }\n } else {\n throw new Error(\n `expected integer value or array containing two integer values for 'attempts' property if defined for retry node at depth '${depth}'`\n );\n }\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n\n // Validate the child node of this decorator node.\n validateNode(definition.child, depth + 1);\n}\n\n/**\n * Validate an object that we expect to be a branch node definition.\n * @param definition An object that we expect to be a branch node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateBranchNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"branch\") {\n throw new Error(`expected node type of 'branch' for branch node at depth '${depth}'`);\n }\n\n // Check that the branch node 'ref' property is defined and is a non-empty string.\n if (typeof definition.ref !== \"string\" || definition.ref.length === 0) {\n throw new Error(`expected non-empty string for 'ref' property for branch node at depth '${depth}'`);\n }\n\n // It is invalid to define guard attributes for a branch node as they should be defined on the referenced root node.\n [\"while\", \"until\"].forEach((attributeName) => {\n if (typeof definition[attributeName] !== \"undefined\") {\n throw new Error(\n `guards should not be defined for branch nodes but guard '${attributeName}' was defined for branch node at depth '${depth}'`\n );\n }\n });\n\n // It is invalid to define callback attributes for a branch node as they should be defined on the referenced root node.\n [\"entry\", \"exit\", \"step\"].forEach((attributeName) => {\n if (typeof definition[attributeName] !== \"undefined\") {\n throw new Error(\n `callbacks should not be defined for branch nodes but callback '${attributeName}' was defined for branch node at depth '${depth}'`\n );\n }\n });\n}\n\n/**\n * Validate an object that we expect to be a action node definition.\n * @param definition An object that we expect to be a action node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateActionNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"action\") {\n throw new Error(`expected node type of 'action' for action node at depth '${depth}'`);\n }\n\n // The 'call' property must be defined for a action node definition.\n if (typeof definition.call !== \"string\" || definition.call.length === 0) {\n throw new Error(`expected non-empty string for 'call' property of action node at depth '${depth}'`);\n }\n\n // If any action function arguments have been defined then they must have been defined in an array.\n if (typeof definition.args !== \"undefined\" && !Array.isArray(definition.args)) {\n throw new Error(`expected array for 'args' property if defined for action node at depth '${depth}'`);\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n}\n\n/**\n * Validate an object that we expect to be a condition node definition.\n * @param definition An object that we expect to be a condition node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateConditionNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"condition\") {\n throw new Error(`expected node type of 'condition' for condition node at depth '${depth}'`);\n }\n\n // The 'call' property must be defined for a condition node definition.\n if (typeof definition.call !== \"string\" || definition.call.length === 0) {\n throw new Error(`expected non-empty string for 'call' property of condition node at depth '${depth}'`);\n }\n\n // If any condition function arguments have been defined then they must have been defined in an array.\n if (typeof definition.args !== \"undefined\" && !Array.isArray(definition.args)) {\n throw new Error(`expected array for 'args' property if defined for condition node at depth '${depth}'`);\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n}\n\n/**\n * Validate an object that we expect to be a wait node definition.\n * @param definition An object that we expect to be a wait node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateWaitNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"wait\") {\n throw new Error(`expected node type of 'wait' for wait node at depth '${depth}'`);\n }\n\n // Check whether a 'duration' property has been defined, it may not have been if this node is to wait indefinitely.\n if (typeof definition.duration !== \"undefined\") {\n if (Array.isArray(definition.duration)) {\n // Check whether any elements of the array are not integer values.\n const containsNonInteger = !!definition.duration.filter((value: unknown) => !isInteger(value)).length;\n\n // If the 'duration' property is an array then it MUST contain two integer values.\n if (definition.duration.length !== 2 || containsNonInteger) {\n throw new Error(\n `expected array containing two integer values for 'duration' property if defined for wait node at depth '${depth}'`\n );\n }\n\n // A wait node must have a positive min and max duration value if they are defined.\n if (definition.duration[0] < 0 || definition.duration[1] < 0) {\n throw new Error(\n `expected positive minimum and maximum duration for 'duration' property if defined for wait node at depth '${depth}'`\n );\n }\n\n // A wait node must not have a minimum duration value that exceeds the maximum duration value.\n if (definition.duration[0] > definition.duration[1]) {\n throw new Error(\n `expected minimum duration value that does not exceed the maximum duration value for 'duration' property if defined for wait node at depth '${depth}'`\n );\n }\n } else if (isInteger(definition.duration)) {\n // A wait node must have a positive duration value if defined.\n if (definition.duration < 0) {\n throw new Error(\n `expected positive duration value for 'duration' property if defined for wait node at depth '${depth}'`\n );\n }\n } else {\n throw new Error(\n `expected integer value or array containing two integer values for 'duration' property if defined for wait node at depth '${depth}'`\n );\n }\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n}\n\n/**\n * Validate an object that we expect to be a sequence node definition.\n * @param definition An object that we expect to be a sequence node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateSequenceNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"sequence\") {\n throw new Error(`expected node type of 'sequence' for sequence node at depth '${depth}'`);\n }\n\n // A sequence node is a composite node, so must have a children nodes array defined.\n if (!Array.isArray(definition.children) || definition.children.length === 0) {\n throw new Error(`expected non-empty 'children' array to be defined for sequence node at depth '${depth}'`);\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n\n // Validate the child nodes of this composite node.\n definition.children.forEach((child: any) => validateNode(child, depth + 1));\n}\n\n/**\n * Validate an object that we expect to be a selector node definition.\n * @param definition An object that we expect to be a selector node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateSelectorNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"selector\") {\n throw new Error(`expected node type of 'selector' for selector node at depth '${depth}'`);\n }\n\n // A selector node is a composite node, so must have a children nodes array defined.\n if (!Array.isArray(definition.children) || definition.children.length === 0) {\n throw new Error(`expected non-empty 'children' array to be defined for selector node at depth '${depth}'`);\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n\n // Validate the child nodes of this composite node.\n definition.children.forEach((child: any) => validateNode(child, depth + 1));\n}\n\n/**\n * Validate an object that we expect to be a parallel node definition.\n * @param definition An object that we expect to be a parallel node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateParallelNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"parallel\") {\n throw new Error(`expected node type of 'parallel' for parallel node at depth '${depth}'`);\n }\n\n // A parallel node is a composite node, so must have a children nodes array defined.\n if (!Array.isArray(definition.children) || definition.children.length === 0) {\n throw new Error(`expected non-empty 'children' array to be defined for parallel node at depth '${depth}'`);\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n\n // Validate the child nodes of this composite node.\n definition.children.forEach((child: any) => validateNode(child, depth + 1));\n}\n\n/**\n * Validate an object that we expect to be a lotto node definition.\n * @param definition An object that we expect to be a lotto node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateLottoNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"lotto\") {\n throw new Error(`expected node type of 'lotto' for lotto node at depth '${depth}'`);\n }\n\n // A lotto node is a composite node, so must have a children nodes array defined.\n if (!Array.isArray(definition.children) || definition.children.length === 0) {\n throw new Error(`expected non-empty 'children' array to be defined for lotto node at depth '${depth}'`);\n }\n\n // Check whether a 'weights' property has been defined, if it has we expect it to be an array of weights.\n if (typeof definition.weights !== \"undefined\") {\n // Check that the weights property is an array of positive integers with an element for each child node element.\n if (\n !Array.isArray(definition.weights) ||\n definition.weights.length !== definition.children.length ||\n definition.weights.filter((value: unknown) => !isInteger(value)).length ||\n definition.weights.filter((value: number) => value < 0).length\n ) {\n throw new Error(\n `expected an array of positive integer weight values with a length matching the number of child nodes for 'weights' property if defined for lotto node at depth '${depth}'`\n );\n }\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n\n // Validate the child nodes of this composite node.\n definition.children.forEach((child: any) => validateNode(child, depth + 1));\n}\n\n/**\n * A helper function to create a failure validation result with the given error message.\n * @param errorMessage The validation failure error message.\n * @returns A failure validation result with the given error message.\n */\nfunction createValidationFailureResult(errorMessage: string): DefinitionValidationResult {\n return { succeeded: false, errorMessage };\n}\n", "import { ActionResult, Agent, GlobalFunction } from \"./Agent\";\nimport { RootNodeDefinition } from \"./BehaviourTreeDefinition\";\n\nexport type InvokerFunction = (args: any[]) => ActionResult | boolean;\n\n/**\n * A singleton used to store and lookup registered functions and subtrees.\n */\nexport default class Lookup {\n /**\n * The object holding any registered functions keyed on function name.\n */\n private static registeredFunctions: { [key: string]: GlobalFunction } = {};\n /**\n * The object holding any registered subtree root node definitions keyed on tree name.\n */\n private static registeredSubtrees: { [key: string]: RootNodeDefinition } = {};\n\n /**\n * Gets the function with the specified name.\n * @param name The name of the function.\n * @returns The function with the specified name.\n */\n public static getFunc(name: string): GlobalFunction {\n return this.registeredFunctions[name];\n }\n\n /**\n * Sets the function with the specified name for later lookup.\n * @param name The name of the function.\n * @param func The function.\n */\n public static setFunc(name: string, func: GlobalFunction): void {\n this.registeredFunctions[name] = func;\n }\n\n /**\n * Gets the function invoker for the specified agent and function name.\n * If a function with the specified name exists on the agent object then it will\n * be returned, otherwise we will then check the registered functions for a match.\n * @param agent The agent instance that this behaviour tree is modelling behaviour for.\n * @param name The function name.\n * @returns The function invoker for the specified agent and function name.\n */\n static getFuncInvoker(agent: Agent, name: string): InvokerFunction | null {\n // Check whether the agent contains the specified function.\n const agentFunction = agent[name];\n if (agentFunction && typeof agentFunction === \"function\") {\n return (args: any[]) => agentFunction.apply(agent, args);\n }\n\n // The agent does not contain the specified function but it may have been registered at some point.\n if (this.registeredFunctions[name] && typeof this.registeredFunctions[name] === \"function\") {\n const registeredFunction = this.registeredFunctions[name];\n return (args: any[]) => registeredFunction(agent, ...args.map((arg) => arg.value));\n }\n\n // We have no function to invoke.\n return null;\n }\n\n /**\n * Gets all registered subtree root node definitions.\n */\n static getSubtrees(): { [key: string]: RootNodeDefinition } {\n return this.registeredSubtrees;\n }\n\n /**\n * Sets the subtree with the specified name for later lookup.\n * @param name The name of the subtree.\n * @param subtree The subtree.\n */\n static setSubtree(name: string, subtree: RootNodeDefinition) {\n this.registeredSubtrees[name] = subtree;\n }\n\n /**\n * Removes the registered function or subtree with the specified name.\n * @param name The name of the registered function or subtree.\n */\n static remove(name: string) {\n delete this.registeredFunctions[name];\n delete this.registeredSubtrees[name];\n }\n\n /**\n * Remove all registered functions and subtrees.\n */\n static empty() {\n this.registeredFunctions = {};\n this.registeredSubtrees = {};\n }\n}\n", "import Node from \"../../nodes/Node\";\n\n/**\n * An exception thrown when evaluating node guard path conditions and a conditions fails.\n */\nexport default class GuardUnsatisifedException extends Error {\n /**\n * @param source The node at which a guard condition failed.\n */\n constructor(private source: Node) {\n super(\"A guard path condition has failed\");\n }\n\n /**\n * Gets whether the specified node is the node at which a guard condition failed.\n * @param node The node to check against the source node.\n * @returns Whether the specified node is the node at which a guard condition failed.\n */\n isSourceNode = (node: Node) => node === this.source;\n}\n", "import { Agent } from \"../../Agent\";\nimport Guard from \"./Guard\";\nimport Node from \"../../nodes/Node\";\nimport GuardUnsatisifedException from \"./GuardUnsatisifedException\";\n\nexport type GuardPathPart = {\n node: Node;\n guards: Guard[];\n};\n\n/**\n * Represents a path of node guards along a root-to-leaf tree path.\n */\nexport default class GuardPath {\n /**\n * @param nodes An array of objects defining a node instance -> guard link, ordered by node depth.\n */\n constructor(private nodes: GuardPathPart[]) {}\n\n /**\n * Evaluate guard conditions for all guards in the tree path, moving outwards from the root.\n * @param agent The agent, required for guard evaluation.\n * @returns An evaluation results object.\n */\n evaluate = (agent: Agent) => {\n // We need to evaluate guard conditions for nodes up the tree, moving outwards from the root.\n for (const details of this.nodes) {\n // There can be multiple guards per node.\n for (const guard of details.guards) {\n // Check whether the guard condition passes, and throw an exception if not.\n if (!guard.isSatisfied(agent)) {\n throw new GuardUnsatisifedException(details.node);\n }\n }\n }\n };\n}\n", "import { BehaviourTreeOptions } from \"../BehaviourTreeOptions\";\nimport State, { AnyState } from \"../State\";\nimport { Agent } from \"../Agent\";\nimport Leaf from \"./leaf/Leaf\";\nimport Attribute from \"../attributes/Attribute\";\nimport Entry from \"../attributes/callbacks/Entry\";\nimport Exit from \"../attributes/callbacks/Exit\";\nimport Step from \"../attributes/callbacks/Step\";\nimport Guard from \"../attributes/guards/Guard\";\nimport GuardPath from \"../attributes/guards/GuardPath\";\nimport GuardUnsatisifedException from \"../attributes/guards/GuardUnsatisifedException\";\n\n/**\n * A base node.\n */\nexport default abstract class Node {\n /**\n * The node uid.\n */\n private readonly uid: string = createNodeUid();\n /**\n * The node state.\n */\n private state: AnyState = State.READY;\n /**\n * The guard path to evaluate as part of a node update.\n */\n private guardPath: GuardPath | undefined;\n\n /**\n * @param type The node type.\n * @param attributes The node attributes.\n * @param args The node argument definitions.\n */\n constructor(private type: string, private attributes: Attribute[], private args: any[]) {}\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected abstract onUpdate(agent: Agent, options: BehaviourTreeOptions): void;\n\n /**\n * Gets the name of the node.\n */\n public abstract getName(): string;\n\n /**\n * Gets whether this node is a leaf node.\n */\n public abstract isLeafNode: () => this is Leaf;\n\n /**\n * Gets/Sets the state of the node.\n */\n getState = (): AnyState => this.state;\n setState = (value: AnyState): void => {\n this.state = value;\n };\n\n /**\n * Gets the unique id of the node.\n */\n getUid = () => this.uid;\n\n /**\n * Gets the type of the node.\n */\n getType = () => this.type;\n\n /**\n * Gets the node attributes.\n */\n getAttributes = () => this.attributes;\n\n /**\n * Gets the node arguments.\n */\n getArguments = () => this.args;\n\n /**\n * Gets the node attribute with the specified type, or null if it does not exist.\n */\n getAttribute(type: \"entry\" | \"ENTRY\"): Entry;\n getAttribute(type: \"exit\" | \"EXIT\"): Exit;\n getAttribute(type: \"step\" | \"STEP\"): Step;\n getAttribute(type: string): Attribute {\n return (\n this.getAttributes().filter((decorator) => decorator.type.toUpperCase() === type.toUpperCase())[0] || null\n );\n }\n\n /**\n * Gets the node attributes.\n */\n getGuardAttributes = (): Guard[] => this.getAttributes().filter((decorator) => decorator.isGuard()) as Guard[];\n\n /**\n * Sets the guard path to evaluate as part of a node update.\n */\n setGuardPath = (value: GuardPath) => (this.guardPath = value);\n\n /**\n * Gets whether a guard path is assigned to this node.\n */\n hasGuardPath = () => !!this.guardPath;\n\n /**\n * Gets whether this node is in the specified state.\n * @param value The value to compare to the node state.\n */\n public is(value: AnyState): boolean {\n return this.state === value;\n }\n\n /**\n * Reset the state of the node.\n */\n public reset(): void {\n this.setState(State.READY);\n }\n\n /**\n * Abort the running of this node.\n * @param agent The agent.\n */\n public abort(agent: Agent): void {\n // There is nothing to do if this node is not in the running state.\n if (!this.is(State.RUNNING)) {\n return;\n }\n\n // Reset the state of this node.\n this.reset();\n\n this.getAttribute(\"exit\")?.callAgentFunction(agent, false, true);\n }\n\n /**\n * Update the node.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n * @returns The result of the update.\n */\n public update(agent: Agent, options: BehaviourTreeOptions): void {\n // If this node is already in a 'SUCCEEDED' or 'FAILED' state then there is nothing to do.\n if (this.is(State.SUCCEEDED) || this.is(State.FAILED)) {\n return;\n }\n\n try {\n // Evaluate all of the guard path conditions for the current tree path.\n this.guardPath!.evaluate(agent);\n\n // If this node is in the READY state then call the ENTRY for this node if it exists.\n if (this.is(State.READY)) {\n this.getAttribute(\"entry\")?.callAgentFunction(agent);\n }\n\n this.getAttribute(\"step\")?.callAgentFunction(agent);\n\n // Do the actual update.\n this.onUpdate(agent, options);\n\n // If this node is now in a 'SUCCEEDED' or 'FAILED' state then call the EXIT for this node if it exists.\n if (this.is(State.SUCCEEDED) || this.is(State.FAILED)) {\n this.getAttribute(\"exit\")?.callAgentFunction(agent, this.is(State.SUCCEEDED), false);\n }\n } catch (error) {\n // If the error is a GuardUnsatisfiedException then we need to determine if this node is the source.\n if (error instanceof GuardUnsatisifedException && error.isSourceNode(this)) {\n // Abort the current node.\n this.abort(agent);\n\n // Any node that is the source of an abort will be a failed node.\n this.setState(State.FAILED);\n } else {\n throw error;\n }\n }\n }\n}\n\n/**\n * Create a randomly generated node uid.\n * @returns A randomly generated node uid.\n */\nfunction createNodeUid(): string {\n var S4 = function () {\n return (((1 + Math.random()) * 0x10000) | 0).toString(16).substring(1);\n };\n return S4() + S4() + \"-\" + S4() + \"-\" + S4() + \"-\" + S4() + \"-\" + S4() + S4() + S4();\n}\n", "import Node from \"../Node\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\n\n/**\n * A composite node that wraps child nodes.\n */\nexport default abstract class Composite extends Node {\n /**\n * @param type The node type.\n * @param attributes The node attributes.\n * @param children The child nodes.\n */\n constructor(type: string, attributes: Attribute[], protected children: Node[]) {\n super(type, attributes, []);\n }\n\n /**\n * Gets whether this node is a leaf node.\n */\n isLeafNode = () => false;\n\n /**\n * Gets the children of this node.\n */\n getChildren = () => this.children;\n\n /**\n * Reset the state of the node.\n */\n reset = () => {\n // Reset the state of this node.\n this.setState(State.READY);\n\n // Reset the state of any child nodes.\n this.getChildren().forEach((child) => child.reset());\n };\n\n /**\n * Abort the running of this node.\n * @param agent The agent.\n */\n abort = (agent: Agent) => {\n // There is nothing to do if this node is not in the running state.\n if (!this.is(State.RUNNING)) {\n return;\n }\n\n // Abort any child nodes.\n this.getChildren().forEach((child) => child.abort(agent));\n\n // Reset the state of this node.\n this.reset();\n\n this.getAttribute(\"exit\")?.callAgentFunction(agent, false, true);\n };\n}\n", "import Composite from \"./Composite\";\nimport State from \"../../State\";\nimport Node from \"../Node\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A PARALLEL node.\n * The child nodes are executed concurrently until one fails or all succeed.\n */\nexport default class Parallel extends Composite {\n /**\n * @param attributes The node attributes.\n * @param children The child nodes.\n */\n constructor(attributes: Attribute[], children: Node[]) {\n super(\"parallel\", attributes, children);\n }\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // Keep a count of the number of succeeded child nodes.\n let succeededCount = 0;\n\n let hasChildFailed = false;\n\n // Iterate over all of the children of this node.\n for (const child of this.children) {\n // If the child has never been updated or is running then we will need to update it now.\n if (child.getState() === State.READY || child.getState() === State.RUNNING) {\n // Update the child of this node.\n child.update(agent, options);\n }\n\n // If the current child has a state of 'SUCCEEDED' then we should move on to the next child.\n if (child.getState() === State.SUCCEEDED) {\n // The child node has succeeded, keep track of this to determine if all children have.\n succeededCount++;\n\n // The child node succeeded, but we have not finished checking every child node yet.\n continue;\n }\n\n // If the current child has a state of 'FAILED' then this node is also a 'FAILED' node.\n if (child.getState() === State.FAILED) {\n hasChildFailed = true;\n\n // There is no need to check the rest of the children.\n break;\n }\n\n // The node should be in the 'RUNNING' state.\n if (child.getState() !== State.RUNNING) {\n // The child node was not in an expected state.\n throw new Error(\"child node was not in an expected state.\");\n }\n }\n\n if (hasChildFailed) {\n // This node is a 'FAILED' node.\n this.setState(State.FAILED);\n\n // Abort every running child.\n for (const child of this.children) {\n if (child.getState() === State.RUNNING) {\n child.abort(agent);\n }\n }\n } else {\n // If all children have succeeded then this node has also succeeded, otherwise it is still running.\n this.setState(succeededCount === this.children.length ? State.SUCCEEDED : State.RUNNING);\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => \"PARALLEL\";\n}\n", "import Composite from \"./Composite\";\nimport Node from \"../Node\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A SELECTOR node.\n * The child nodes are executed in sequence until one succeeds or all fail.\n */\nexport default class Selector extends Composite {\n /**\n * @param attributes The node attributes.\n * @param children The child nodes.\n */\n constructor(attributes: Attribute[], protected children: Node[]) {\n super(\"selector\", attributes, children);\n }\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // Iterate over all of the children of this node.\n for (const child of this.children) {\n // If the child has never been updated or is running then we will need to update it now.\n if (child.getState() === State.READY || child.getState() === State.RUNNING) {\n // Update the child of this node.\n child.update(agent, options);\n }\n\n // If the current child has a state of 'SUCCEEDED' then this node is also a 'SUCCEEDED' node.\n if (child.getState() === State.SUCCEEDED) {\n // This node is a 'SUCCEEDED' node.\n this.setState(State.SUCCEEDED);\n\n // There is no need to check the rest of the selector nodes.\n return;\n }\n\n // If the current child has a state of 'FAILED' then we should move on to the next child.\n if (child.getState() === State.FAILED) {\n // Find out if the current child is the last one in the selector.\n // If it is then this sequence node has also failed.\n if (this.children.indexOf(child) === this.children.length - 1) {\n // This node is a 'FAILED' node.\n this.setState(State.FAILED);\n\n // There is no need to check the rest of the selector as we have completed it.\n return;\n } else {\n // The child node failed, try the next one.\n continue;\n }\n }\n\n // The node should be in the 'RUNNING' state.\n if (child.getState() === State.RUNNING) {\n // This node is a 'RUNNING' node.\n this.setState(State.RUNNING);\n\n // There is no need to check the rest of the selector as the current child is still running.\n return;\n }\n\n // The child node was not in an expected state.\n throw new Error(\"child node was not in an expected state.\");\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => \"SELECTOR\";\n}\n", "import Composite from \"./Composite\";\nimport Node from \"../Node\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A SEQUENCE node.\n * The child nodes are executed in sequence until one fails or all succeed.\n */\nexport default class Sequence extends Composite {\n /**\n * @param attributes The node attributes.\n * @param children The child nodes.\n */\n constructor(attributes: Attribute[], protected children: Node[]) {\n super(\"sequence\", attributes, children);\n }\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // Iterate over all of the children of this node.\n for (const child of this.children) {\n // If the child has never been updated or is running then we will need to update it now.\n if (child.getState() === State.READY || child.getState() === State.RUNNING) {\n // Update the child of this node.\n child.update(agent, options);\n }\n\n // If the current child has a state of 'SUCCEEDED' then we should move on to the next child.\n if (child.getState() === State.SUCCEEDED) {\n // Find out if the current child is the last one in the sequence.\n // If it is then this sequence node has also succeeded.\n if (this.children.indexOf(child) === this.children.length - 1) {\n // This node is a 'SUCCEEDED' node.\n this.setState(State.SUCCEEDED);\n\n // There is no need to check the rest of the sequence as we have completed it.\n return;\n } else {\n // The child node succeeded, but we have not finished the sequence yet.\n continue;\n }\n }\n\n // If the current child has a state of 'FAILED' then this node is also a 'FAILED' node.\n if (child.getState() === State.FAILED) {\n // This node is a 'FAILED' node.\n this.setState(State.FAILED);\n\n // There is no need to check the rest of the sequence.\n return;\n }\n\n // The node should be in the 'RUNNING' state.\n if (child.getState() === State.RUNNING) {\n // This node is a 'RUNNING' node.\n this.setState(State.RUNNING);\n\n // There is no need to check the rest of the sequence as the current child is still running.\n return;\n }\n\n // The child node was not in an expected state.\n throw new Error(\"child node was not in an expected state.\");\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => \"SEQUENCE\";\n}\n", "import createLotto from \"lotto-draw\";\n\nimport Node from \"../Node\";\nimport Composite from \"./Composite\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A LOTTO node.\n * A winning child is picked on the initial update of this node, based on ticket weighting.\n * The state of this node will match the state of the winning child.\n */\nexport default class Lotto extends Composite {\n /**\n * @param attributes The node attributes.\n * @param weights The child node weights.\n * @param children The child nodes.\n */\n constructor(attributes: Attribute[], private weights: number[] | undefined, children: Node[]) {\n super(\"lotto\", attributes, children);\n }\n\n /**\n * The child node selected to be the active one.\n */\n private selectedChild: Node | undefined;\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // If this node is in the READY state then we need to pick a winning child node.\n if (this.is(State.READY)) {\n // Create a lotto draw with which to randomly pick a child node to become the active one.\n const lottoDraw = createLotto({\n // Hook up the optional 'random' behaviour tree function option to the one used by 'lotto-draw'.\n random: options.random,\n // Pass in each child node as a participant in the lotto draw with their respective ticket count.\n participants: this.children.map((child, index) => [child, this.weights?.[index] || 1])\n });\n\n // Randomly pick a child based on ticket weighting, this will become the active child for this composite node.\n this.selectedChild = lottoDraw.draw() || undefined;\n }\n\n // If something went wrong and we don't have an active child then we should throw an error.\n if (!this.selectedChild) {\n throw new Error(\"failed to update lotto node as it has no active child\");\n }\n\n // If the selected child has never been updated or is running then we will need to update it now.\n if (this.selectedChild.getState() === State.READY || this.selectedChild.getState() === State.RUNNING) {\n this.selectedChild.update(agent, options);\n }\n\n // The state of the lotto node is the state of its selected child.\n this.setState(this.selectedChild.getState());\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => (this.weights ? `LOTTO [${this.weights.join(\",\")}]` : \"LOTTO\");\n}\n", "import Node from \"../Node\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\n\n/**\n * A decorator node that wraps a single child node.\n */\nexport default abstract class Decorator extends Node {\n /**\n * @param type The node type.\n * @param attributes The node attributes.\n * @param child The child node.\n */\n constructor(type: string, attributes: Attribute[], protected child: Node) {\n super(type, attributes, []);\n }\n\n /**\n * Gets whether this node is a leaf node.\n */\n isLeafNode = () => false;\n\n /**\n * Gets the children of this node.\n */\n getChildren = () => [this.child];\n\n /**\n * Reset the state of the node.\n */\n reset = () => {\n // Reset the state of this node.\n this.setState(State.READY);\n\n // Reset the state of the child node.\n this.child.reset();\n };\n\n /**\n * Abort the running of this node.\n * @param agent The agent.\n */\n abort = (agent: Agent) => {\n // There is nothing to do if this node is not in the running state.\n if (!this.is(State.RUNNING)) {\n return;\n }\n\n // Abort the child node.\n this.child.abort(agent);\n\n // Reset the state of this node.\n this.reset();\n\n this.getAttribute(\"exit\")?.callAgentFunction(agent, false, true);\n };\n}\n", "import Node from \"../Node\";\nimport Decorator from \"./Decorator\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A Fail node.\n * This node wraps a single child and will always move to the 'FAILED' state when the child moves to a 'SUCCEEDED' or 'FAILED' state.\n */\nexport default class Fail extends Decorator {\n /**\n * @param attributes The node attributes.\n * @param child The child node.\n */\n constructor(attributes: Attribute[], child: Node) {\n super(\"fail\", attributes, child);\n }\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // If the child has never been updated or is running then we will need to update it now.\n if (this.child.getState() === State.READY || this.child.getState() === State.RUNNING) {\n this.child.update(agent, options);\n }\n\n // The state of this node will depend in the state of its child.\n switch (this.child.getState()) {\n case State.RUNNING:\n this.setState(State.RUNNING);\n break;\n\n case State.SUCCEEDED:\n case State.FAILED:\n this.setState(State.FAILED);\n break;\n\n default:\n this.setState(State.READY);\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => \"FAIL\";\n}\n", "import Decorator from \"./Decorator\";\nimport State from \"../../State\";\nimport Node from \"../Node\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A Flip node.\n * This node wraps a single child and will flip the state of the child state.\n */\nexport default class Flip extends Decorator {\n /**\n * @param attributes The node attributes.\n * @param child The child node.\n */\n constructor(attributes: Attribute[], child: Node) {\n super(\"flip\", attributes, child);\n }\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // If the child has never been updated or is running then we will need to update it now.\n if (this.child.getState() === State.READY || this.child.getState() === State.RUNNING) {\n this.child.update(agent, options);\n }\n\n // The state of this node will depend in the state of its child.\n switch (this.child.getState()) {\n case State.RUNNING:\n this.setState(State.RUNNING);\n break;\n\n case State.SUCCEEDED:\n this.setState(State.FAILED);\n break;\n\n case State.FAILED:\n this.setState(State.SUCCEEDED);\n break;\n\n default:\n this.setState(State.READY);\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => \"FLIP\";\n}\n", "import Node from \"../Node\";\nimport Decorator from \"./Decorator\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A REPEAT node.\n * The node has a single child which can have:\n * -- A number of iterations for which to repeat the child node.\n * -- An infinite repeat loop if neither an iteration count or a condition function is defined.\n * The REPEAT node will stop and have a 'FAILED' state if its child is ever in a 'FAILED' state after an update.\n * The REPEAT node will attempt to move on to the next iteration if its child is ever in a 'SUCCEEDED' state.\n */\nexport default class Repeat extends Decorator {\n /**\n * @param attributes The node attributes.\n * @param iterations The number of iterations to repeat the child node.\n * @param iterationsMin The minimum possible number of iterations to repeat the child node.\n * @param iterationsMax The maximum possible number of iterations to repeat the child node.\n * @param child The child node.\n */\n constructor(\n attributes: Attribute[],\n private iterations: number | null,\n private iterationsMin: number | null,\n private iterationsMax: number | null,\n child: Node\n ) {\n super(\"repeat\", attributes, child);\n }\n\n /**\n * The number of target iterations to make.\n */\n private targetIterationCount: number | null = null;\n\n /**\n * The current iteration count.\n */\n private currentIterationCount: number = 0;\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // If this node is in the READY state then we need to reset the child and the target iteration count.\n if (this.is(State.READY)) {\n // Reset the child node.\n this.child.reset();\n\n // Reset the current iteration count.\n this.currentIterationCount = 0;\n\n // Set the target iteration count.\n this.setTargetIterationCount(options);\n }\n\n // Do a check to see if we can iterate. If we can then this node will move into the 'RUNNING' state.\n // If we cannot iterate then we have hit our target iteration count, which means that the node has succeeded.\n if (this.canIterate()) {\n // This node is in the running state and can do its initial iteration.\n this.setState(State.RUNNING);\n\n // We may have already completed an iteration, meaning that the child node will be in the SUCCEEDED state.\n // If this is the case then we will have to reset the child node now.\n if (this.child.getState() === State.SUCCEEDED) {\n this.child.reset();\n }\n\n // Update the child of this node.\n this.child.update(agent, options);\n\n // If the child moved into the FAILED state when we updated it then there is nothing left to do and this node has also failed.\n // If it has moved into the SUCCEEDED state then we have completed the current iteration.\n if (this.child.getState() === State.FAILED) {\n // The child has failed, meaning that this node has failed.\n this.setState(State.FAILED);\n\n return;\n } else if (this.child.getState() === State.SUCCEEDED) {\n // We have completed an iteration.\n this.currentIterationCount += 1;\n }\n } else {\n // This node is in the 'SUCCEEDED' state as we cannot iterate any more.\n this.setState(State.SUCCEEDED);\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => {\n if (this.iterations !== null) {\n return `REPEAT ${this.iterations}x`;\n } else if (this.iterationsMin !== null && this.iterationsMax !== null) {\n return `REPEAT ${this.iterationsMin}x-${this.iterationsMax}x`;\n } else {\n return \"REPEAT\";\n }\n };\n\n /**\n * Reset the state of the node.\n */\n reset = () => {\n // Reset the state of this node.\n this.setState(State.READY);\n\n // Reset the current iteration count.\n this.currentIterationCount = 0;\n\n // Reset the child node.\n this.child.reset();\n };\n\n /**\n * Gets whether an iteration can be made.\n * @returns Whether an iteration can be made.\n */\n private canIterate = () => {\n if (this.targetIterationCount !== null) {\n // We can iterate as long as we have not reached our target iteration count.\n return this.currentIterationCount < this.targetIterationCount;\n }\n\n // If neither an iteration count or a condition function were defined then we can iterate indefinitely.\n return true;\n };\n\n /**\n * Sets the target iteration count.\n * @param options The behaviour tree options object.\n */\n private setTargetIterationCount = (options: BehaviourTreeOptions) => {\n // Are we dealing with an explicit iteration count or will we be randomly picking a iteration count between the min and max iteration count.\n if (this.iterations !== null) {\n this.targetIterationCount = this.iterations;\n } else if (this.iterationsMin !== null && this.iterationsMax !== null) {\n // We will be picking a random iteration count between a min and max iteration count, if the optional 'random'\n // behaviour tree function option is defined then we will be using that, otherwise we will fall back to using Math.random.\n const random = typeof options.random === \"function\" ? options.random : Math.random;\n\n // Pick a random iteration count between a min and max iteration count.\n this.targetIterationCount = Math.floor(\n random() * (this.iterationsMax - this.iterationsMin + 1) + this.iterationsMin\n );\n } else {\n this.targetIterationCount = null;\n }\n };\n}\n", "import Node from \"../Node\";\nimport Decorator from \"./Decorator\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A RETRY node.\n * The node has a single child which can have:\n * -- A number of iterations for which to repeat the child node.\n * -- An infinite repeat loop if neither an iteration count or a condition function is defined.\n * The RETRY node will stop and have a 'SUCCEEDED' state if its child is ever in a 'SUCCEEDED' state after an update.\n * The RETRY node will attempt to move on to the next iteration if its child is ever in a 'FAILED' state.\n */\nexport default class Retry extends Decorator {\n /**\n * @param attributes The node attributes.\n * @param attempts The number of attempts to retry the child node.\n * @param attemptsMin The minimum possible number of attempts to retry the child node.\n * @param attemptsMax The maximum possible number of attempts to retry the child node.\n * @param child The child node.\n */\n constructor(\n attributes: Attribute[],\n private attempts: number | null,\n private attemptsMin: number | null,\n private attemptsMax: number | null,\n child: Node\n ) {\n super(\"retry\", attributes, child);\n }\n\n /**\n * The number of target attempts to make.\n */\n private targetAttemptCount: number | null = null;\n\n /**\n * The current attempt count.\n */\n private currentAttemptCount: number = 0;\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // If this node is in the READY state then we need to reset the child and the target attempt count.\n if (this.is(State.READY)) {\n // Reset the child node.\n this.child.reset();\n\n // Reset the current attempt count.\n this.currentAttemptCount = 0;\n\n // Set the target attempt count.\n this.setTargetAttemptCount(options);\n }\n\n // Do a check to see if we can attempt. If we can then this node will move into the 'RUNNING' state.\n // If we cannot attempt then we have hit our target attempt count, which means that the node has succeeded.\n if (this.canAttempt()) {\n // This node is in the running state and can do its initial attempt.\n this.setState(State.RUNNING);\n\n // We may have already completed an attempt, meaning that the child node will be in the FAILED state.\n // If this is the case then we will have to reset the child node now.\n if (this.child.getState() === State.FAILED) {\n this.child.reset();\n }\n\n // Update the child of this node.\n this.child.update(agent, options);\n\n // If the child moved into the SUCCEEDED state when we updated it then there is nothing left to do and this node has also succeeded.\n // If it has moved into the FAILED state then we have completed the current attempt.\n if (this.child.getState() === State.SUCCEEDED) {\n // The child has succeeded, meaning that this node has succeeded.\n this.setState(State.SUCCEEDED);\n\n return;\n } else if (this.child.getState() === State.FAILED) {\n // We have completed an attempt.\n this.currentAttemptCount += 1;\n }\n } else {\n // This node is in the 'FAILED' state as we cannot iterate any more.\n this.setState(State.FAILED);\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => {\n if (this.attempts !== null) {\n return `RETRY ${this.attempts}x`;\n } else if (this.attemptsMin !== null && this.attemptsMax !== null) {\n return `RETRY ${this.attemptsMin}x-${this.attemptsMax}x`;\n } else {\n return \"RETRY\";\n }\n };\n\n /**\n * Reset the state of the node.\n */\n reset = () => {\n // Reset the state of this node.\n this.setState(State.READY);\n\n // Reset the current attempt count.\n this.currentAttemptCount = 0;\n\n // Reset the child node.\n this.child.reset();\n };\n\n /**\n * Gets whether an attempt can be made.\n * @returns Whether an attempt can be made.\n */\n canAttempt = () => {\n if (this.targetAttemptCount !== null) {\n // We can attempt as long as we have not reached our target attempt count.\n return this.currentAttemptCount < this.targetAttemptCount;\n }\n\n // If neither an attempt count or a condition function were defined then we can attempt indefinitely.\n return true;\n };\n\n /**\n * Sets the target attempt count.\n * @param options The behaviour tree options object.\n */\n setTargetAttemptCount = (options: BehaviourTreeOptions) => {\n // Are we dealing with an explicit attempt count or will we be randomly picking an attempt count between the min and max attempt count.\n if (this.attempts !== null) {\n this.targetAttemptCount = this.attempts;\n } else if (this.attemptsMin !== null && this.attemptsMax !== null) {\n // We will be picking a random attempt count between a min and max attempt count, if the optional 'random'\n // behaviour tree function option is defined then we will be using that, otherwise we will fall back to using Math.random.\n const random = typeof options.random === \"function\" ? options.random : Math.random;\n\n // Pick a random attempt count between a min and max attempt count.\n this.targetAttemptCount = Math.floor(\n random() * (this.attemptsMax - this.attemptsMin + 1) + this.attemptsMin\n );\n } else {\n this.targetAttemptCount = null;\n }\n };\n}\n", "import Node from \"../Node\";\nimport Decorator from \"./Decorator\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A Root node.\n * The root node will have a single child.\n */\nexport default class Root extends Decorator {\n /**\n * @param attributes The node attributes.\n * @param child The child node.\n */\n constructor(attributes: Attribute[], child: Node) {\n super(\"root\", attributes, child);\n }\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // If the child has never been updated or is running then we will need to update it now.\n if (this.child.getState() === State.READY || this.child.getState() === State.RUNNING) {\n // Update the child of this node.\n this.child.update(agent, options);\n }\n\n // The state of the root node is the state of its child.\n this.setState(this.child.getState());\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => \"ROOT\";\n}\n", "import Node from \"../Node\";\nimport Decorator from \"./Decorator\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A Succeed node.\n * This node wraps a single child and will always move to the 'SUCCEEDED' state when the child moves to a 'SUCCEEDED' or 'FAILED' state.\n */\nexport default class Succeed extends Decorator {\n /**\n * @param attributes The node attributes.\n * @param child The child node.\n */\n constructor(attributes: Attribute[], child: Node) {\n super(\"succeed\", attributes, child);\n }\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // If the child has never been updated or is running then we will need to update it now.\n if (this.child.getState() === State.READY || this.child.getState() === State.RUNNING) {\n this.child.update(agent, options);\n }\n\n // The state of this node will depend in the state of its child.\n switch (this.child.getState()) {\n case State.RUNNING:\n this.setState(State.RUNNING);\n break;\n\n case State.SUCCEEDED:\n case State.FAILED:\n this.setState(State.SUCCEEDED);\n break;\n\n default:\n this.setState(State.READY);\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => \"SUCCEED\";\n}\n", "import Node from \"../Node\";\n\n/**\n * A leaf node.\n */\nexport default abstract class Leaf extends Node {\n /**\n * Gets whether this node is a leaf node.\n */\n isLeafNode = () => true;\n}\n", "import { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\nimport State, { CompleteState } from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Leaf from \"./Leaf\";\nimport Lookup from \"../../Lookup\";\nimport Attribute from \"../../attributes/Attribute\";\n\n/**\n * The type representing a resolved/rejected update promise.\n */\ntype UpdatePromiseResult = {\n /**\n * Whether the promise was resolved rather than rejected.\n */\n isResolved: boolean;\n\n /**\n * The promise resolved value or rejection reason.\n */\n value: any;\n};\n\n/**\n * An Action leaf node.\n * This represents an immediate or ongoing state of behaviour.\n */\nexport default class Action extends Leaf {\n /**\n * @param attributes The node attributes.\n * @param actionName The action name.\n * @param actionArguments The array of action argument definitions.\n */\n constructor(attributes: Attribute[], private actionName: string, private actionArguments: any[]) {\n super(\"action\", attributes, actionArguments);\n }\n\n /**\n * Whether there is a pending update promise.\n */\n private isUsingUpdatePromise = false;\n\n /**\n * The finished state result of an update promise.\n */\n private updatePromiseResult: UpdatePromiseResult | null = null;\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // If the result of this action depends on an update promise then there is nothing to do until it settles.\n if (this.isUsingUpdatePromise) {\n // Are we still waiting for our update promise to settle?\n if (!this.updatePromiseResult) {\n return;\n }\n\n const { isResolved, value } = this.updatePromiseResult;\n\n // Our update promise settled, was it resolved or rejected?\n if (isResolved) {\n // Our promise resolved so check to make sure the result is a valid finished state.\n if (value !== State.SUCCEEDED && value !== State.FAILED) {\n throw new Error(\n \"action node promise resolved with an invalid value, expected a State.SUCCEEDED or State.FAILED value to be returned\"\n );\n }\n\n // Set the state of this node to match the state returned by the promise.\n this.setState(value);\n\n return;\n } else {\n // The promise was rejected, which isn't great.\n throw new Error(`action function '${this.actionName}' promise rejected with '${value}'`);\n }\n }\n\n // Attempt to get the invoker for the action function.\n const actionFuncInvoker = Lookup.getFuncInvoker(agent, this.actionName);\n\n // The action function should be defined.\n if (actionFuncInvoker === null) {\n throw new Error(\n `cannot update action node as the action '${this.actionName}' function is not defined on the agent and has not been registered`\n );\n }\n\n let actionFunctionResult;\n\n try {\n // Call the action function, the result of which may be:\n // - The finished state of this action node.\n // - A promise to return a finished node state.\n // - Undefined if the node should remain in the running state.\n actionFunctionResult = actionFuncInvoker(this.actionArguments) as CompleteState | Promise;\n } catch (error) {\n // The user was naughty and threw something.\n throw new Error(`action function '${this.actionName}' threw '${error}'`);\n }\n\n if (actionFunctionResult instanceof Promise) {\n actionFunctionResult.then(\n (result) => {\n // If 'isUpdatePromisePending' is not set then the promise was cleared as it was resolving, probably via an abort of reset.\n if (!this.isUsingUpdatePromise) {\n return;\n }\n\n // Set the resolved update promise result so that it can be handled on the next update of this node.\n this.updatePromiseResult = {\n isResolved: true,\n value: result\n };\n },\n (reason) => {\n // If 'isUpdatePromisePending' is not set then the promise was cleared as it was resolving, probably via an abort or reset.\n if (!this.isUsingUpdatePromise) {\n return;\n }\n\n // Set the rejected update promise result so that it can be handled on the next update of this node.\n this.updatePromiseResult = {\n isResolved: false,\n value: reason\n };\n }\n );\n\n // This node will be in the 'RUNNING' state until the update promise resolves.\n this.setState(State.RUNNING);\n\n // We are now waiting for the promise returned by the use to resolve before we know what state this node is in.\n this.isUsingUpdatePromise = true;\n } else {\n // Validate the returned value.\n this.validateUpdateResult(actionFunctionResult);\n\n // Set the state of this node, this may be undefined, which just means that the node is still in the 'RUNNING' state.\n this.setState(actionFunctionResult || State.RUNNING);\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => this.actionName;\n\n /**\n * Reset the state of the node.\n */\n reset = () => {\n // Reset the state of this node.\n this.setState(State.READY);\n\n // There is no longer an update promise that we care about.\n this.isUsingUpdatePromise = false;\n this.updatePromiseResult = null;\n };\n\n /**\n * Validate the result of an update function call.\n * @param result The result of an update function call.\n */\n private validateUpdateResult = (result: CompleteState | State.RUNNING) => {\n switch (result) {\n case State.SUCCEEDED:\n case State.FAILED:\n case State.RUNNING:\n case undefined:\n return;\n default:\n throw new Error(\n `expected action function '${this.actionName}' to return an optional State.SUCCEEDED or State.FAILED value but returned '${result}'`\n );\n }\n };\n}\n", "import { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Leaf from \"./Leaf\";\nimport Lookup from \"../../Lookup\";\nimport Attribute from \"../../attributes/Attribute\";\n\n/**\n * A Condition leaf node.\n * This will succeed or fail immediately based on an agent predicate, without moving to the 'RUNNING' state.\n */\nexport default class Condition extends Leaf {\n /**\n * @param attributes The node attributes.\n * @param conditionName The name of the condition function.\n * @param conditionArguments The array of condition argument definitions.\n */\n constructor(attributes: Attribute[], private conditionName: string, private conditionArguments: any[]) {\n super(\"condition\", attributes, conditionArguments);\n }\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // Attempt to get the invoker for the condition function.\n const conditionFuncInvoker = Lookup.getFuncInvoker(agent, this.conditionName);\n\n // The condition function should be defined.\n if (conditionFuncInvoker === null) {\n throw new Error(\n `cannot update condition node as the condition '${this.conditionName}' function is not defined on the agent and has not been registered`\n );\n }\n\n let conditionFunctionResult;\n\n try {\n // Call the condition function to determine the state of this node, the result of which should be a boolean.\n conditionFunctionResult = conditionFuncInvoker(this.conditionArguments);\n } catch (error) {\n // The user was naughty and threw something.\n throw new Error(`condition function '${this.conditionName}' threw '${error}'`);\n }\n\n // The result of calling the condition function must be a boolean value.\n if (typeof conditionFunctionResult !== \"boolean\") {\n throw new Error(\n `expected condition function '${this.conditionName}' to return a boolean but returned '${conditionFunctionResult}'`\n );\n }\n\n // Set the state of this node based on the result of calling the condition function.\n this.setState(!!conditionFunctionResult ? State.SUCCEEDED : State.FAILED);\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => this.conditionName;\n}\n", "import Leaf from \"./Leaf\";\nimport State from \"../../State\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { Agent } from \"../../Agent\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A WAIT node.\n * The state of this node will change to SUCCEEDED after a duration of time\n */\nexport default class Wait extends Leaf {\n /**\n * @param attributes The node attributes.\n * @param duration The duration that this node will wait to succeed in milliseconds.\n * @param durationMin The minimum possible duration in milliseconds that this node will wait to succeed.\n * @param durationMax The maximum possible duration in milliseconds that this node will wait to succeed.\n */\n constructor(\n attributes: Attribute[],\n private duration: number | null,\n private durationMin: number | null,\n private durationMax: number | null\n ) {\n super(\"wait\", attributes, []);\n }\n\n /**\n * The time in milliseconds at which this node was first updated.\n */\n private initialUpdateTime: number = 0;\n\n /**\n * The total duration in milliseconds that this node will be waiting for.\n */\n private totalDuration: number | null = null;\n\n /**\n * The duration in milliseconds that this node has been waiting for.\n */\n private waitedDuration: number = 0;\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // If this node is in the READY state then we need to set the initial update time.\n if (this.is(State.READY)) {\n // Set the initial update time.\n this.initialUpdateTime = new Date().getTime();\n\n // Set the initial waited duration.\n this.waitedDuration = 0;\n\n // Are we dealing with an explicit duration or will we be randomly picking a duration between the min and max duration.\n if (this.duration !== null) {\n this.totalDuration = this.duration;\n } else if (this.durationMin !== null && this.durationMax !== null) {\n // We will be picking a random duration between a min and max duration, if the optional 'random' behaviour tree\n // function option is defined then we will be using that, otherwise we will fall back to using Math.random.\n const random = typeof options.random === \"function\" ? options.random : Math.random;\n\n // Pick a random duration between a min and max duration.\n this.totalDuration = Math.floor(\n random() * (this.durationMax - this.durationMin + 1) + this.durationMin\n );\n } else {\n this.totalDuration = null;\n }\n\n // The node is now running until we finish waiting.\n this.setState(State.RUNNING);\n }\n\n // If we have no total duration then this wait node will wait indefinitely until it is aborted.\n if (this.totalDuration === null) {\n return;\n }\n\n // If we have a 'getDeltaTime' function defined as part of our options then we will use it to figure out how long we have waited for.\n if (typeof options.getDeltaTime === \"function\") {\n // Get the delta time.\n const deltaTime = options.getDeltaTime();\n\n // Our delta time must be a valid number and cannot be NaN.\n if (typeof deltaTime !== \"number\" || isNaN(deltaTime)) {\n throw new Error(\"The delta time must be a valid number and not NaN.\");\n }\n\n // Update the amount of time that this node has been waiting for based on the delta time.\n this.waitedDuration += deltaTime * 1000;\n } else {\n // We are not using a delta time, so we will just work out hom much time has passed since the first update.\n this.waitedDuration = new Date().getTime() - this.initialUpdateTime;\n }\n\n // Have we waited long enough?\n if (this.waitedDuration >= this.totalDuration) {\n // We have finished waiting!\n this.setState(State.SUCCEEDED);\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => {\n if (this.duration !== null) {\n return `WAIT ${this.duration}ms`;\n } else if (this.durationMin !== null && this.durationMax !== null) {\n return `WAIT ${this.durationMin}ms-${this.durationMax}ms`;\n } else {\n return \"WAIT\";\n }\n };\n}\n", "import Guard from \"./guards/Guard\";\n\nexport type AttributeDetails = {\n /** The attribute type. */\n type: string;\n\n /** The attribute arguments. */\n args: any[];\n};\n\n/**\n * A base node attribute.\n */\nexport default abstract class Attribute {\n /**\n * @param type The node attribute type.\n * @param args The array of attribute arguments.\n */\n constructor(public type: string, public args: any[]) {}\n\n /**\n * Gets the attribute details.\n */\n abstract getDetails(): TAttributeDetails;\n\n /**\n * Gets whether this attribute is a guard.\n */\n abstract isGuard: () => this is Guard;\n}\n", "import { Agent } from \"../../Agent\";\nimport Attribute, { AttributeDetails } from \"../Attribute\";\n\nexport type GuardAttributeDetails = {\n /** The name of the condition function that determines whether the guard is satisfied. */\n condition: string;\n} & AttributeDetails;\n\n/**\n * A base node guard attribute.\n */\nexport default abstract class Guard extends Attribute {\n /**\n * @param type The node attribute type.\n * @param args The array of decorator argument definitions.\n * @param condition The name of the condition function that determines whether the guard is satisfied.\n */\n constructor(type: string, args: any[], private condition: string) {\n super(type, args);\n }\n\n /**\n * Gets the name of the condition function that determines whether the guard is satisfied.\n */\n getCondition = () => this.condition;\n\n /**\n * Gets whether this attribute is a guard.\n */\n isGuard = () => true;\n\n /**\n * Gets the attribute details.\n */\n getDetails(): GuardAttributeDetails {\n return {\n type: this.type,\n args: this.args,\n condition: this.getCondition()\n };\n }\n\n /**\n * Gets whether the guard is satisfied.\n * @param agent The agent.\n * @returns Whether the guard is satisfied.\n */\n abstract isSatisfied(agent: Agent): boolean;\n}\n", "import Guard from \"./Guard\";\nimport Lookup from \"../../Lookup\";\nimport { Agent } from \"../../Agent\";\n\n/**\n * A WHILE guard which is satisfied as long as the given condition remains true.\n */\nexport default class While extends Guard {\n /**\n * @param condition The name of the condition function that determines whether the guard is satisfied.\n * @param args The array of decorator argument definitions.\n */\n constructor(condition: string, args: any[]) {\n super(\"while\", args, condition);\n }\n\n /**\n * Gets whether the guard is satisfied.\n * @param agent The agent.\n * @returns Whether the guard is satisfied.\n */\n isSatisfied = (agent: Agent) => {\n // Attempt to get the invoker for the condition function.\n const conditionFuncInvoker = Lookup.getFuncInvoker(agent, this.getCondition());\n\n // The condition function should be defined.\n if (conditionFuncInvoker === null) {\n throw new Error(\n `cannot evaluate node guard as the condition '${this.getCondition()}' function is not defined on the agent and has not been registered`\n );\n }\n\n // Call the condition function to determine whether this guard is satisfied.\n return !!conditionFuncInvoker(this.args);\n };\n}\n", "import Guard from \"./Guard\";\nimport Lookup from \"../../Lookup\";\nimport { Agent } from \"../../Agent\";\n\n/**\n * An UNTIL guard which is satisfied as long as the given condition remains false.\n */\nexport default class Until extends Guard {\n /**\n * @param condition The name of the condition function that determines whether the guard is satisfied.\n * @param args The array of decorator argument definitions.\n */\n constructor(condition: string, args: any[]) {\n super(\"until\", args, condition);\n }\n\n /**\n * Gets whether the guard is satisfied.\n * @param agent The agent.\n * @returns Whether the guard is satisfied.\n */\n isSatisfied = (agent: Agent) => {\n // Attempt to get the invoker for the condition function.\n const conditionFuncInvoker = Lookup.getFuncInvoker(agent, this.getCondition());\n\n // The condition function should be defined.\n if (conditionFuncInvoker === null) {\n throw new Error(\n `cannot evaluate node guard as the condition '${this.getCondition()}' function is not defined on the agent and has not been registered`\n );\n }\n\n // Call the condition function to determine whether this guard is satisfied.\n return !!!conditionFuncInvoker(this.args);\n };\n}\n", "import { Agent } from \"../../Agent\";\nimport Attribute, { AttributeDetails } from \"../Attribute\";\n\nexport type CallbackAttributeDetails = {\n /** The name of the agent function that is called. */\n functionName: string;\n} & AttributeDetails;\n\n/**\n * A base node callback attribute.\n */\nexport default abstract class Callback extends Attribute {\n /**\n * @param type The node attribute type.\n * @param args The array of decorator argument definitions.\n * @param functionName The name of the agent function to call.\n */\n constructor(type: string, args: any[], private functionName: string) {\n super(type, args);\n }\n\n /**\n * Gets the name of the agent function to call.\n */\n getFunctionName = () => this.functionName;\n\n /**\n * Gets whether this attribute is a guard.\n */\n isGuard = () => false;\n\n /**\n * Gets the attribute details.\n */\n getDetails(): CallbackAttributeDetails {\n return {\n type: this.type,\n args: this.args,\n functionName: this.getFunctionName()\n };\n }\n\n /**\n * Attempt to call the agent function that this callback refers to.\n * @param agent The agent.\n */\n abstract callAgentFunction: (agent: Agent, isSuccess: boolean, isAborted: boolean) => void;\n}\n", "import Callback from \"./Callback\";\nimport Lookup from \"../../Lookup\";\nimport { Agent } from \"../../Agent\";\n\n/**\n * An ENTRY callback which defines an agent function to call when the associated node is updated and moves out of running state.\n */\nexport default class Entry extends Callback {\n /**\n * @param functionName The name of the agent function to call.\n * @param args The array of callback argument definitions.\n */\n constructor(functionName: string, args: any[]) {\n super(\"entry\", args, functionName);\n }\n\n /**\n * Attempt to call the agent function that this callback refers to.\n * @param agent The agent.\n */\n callAgentFunction = (agent: Agent) => {\n // Attempt to get the invoker for the callback function.\n const callbackFuncInvoker = Lookup.getFuncInvoker(agent, this.getFunctionName());\n\n // The callback function should be defined.\n if (callbackFuncInvoker === null) {\n throw new Error(\n `cannot call entry function '${this.getFunctionName()}' as is not defined on the agent and has not been registered`\n );\n }\n\n // Call the callback function.\n callbackFuncInvoker(this.args);\n };\n}\n", "import Callback from \"./Callback\";\nimport Lookup from \"../../Lookup\";\nimport { Agent } from \"../../Agent\";\n\n/**\n * A STEP callback which defines an agent function to call when the associated node is updated.\n */\nexport default class Step extends Callback {\n /**\n * @param functionName The name of the agent function to call.\n * @param args The array of callback argument definitions.\n */\n constructor(functionName: string, args: any[]) {\n super(\"step\", args, functionName);\n }\n\n /**\n * Attempt to call the agent function that this callback refers to.\n * @param agent The agent.\n */\n callAgentFunction = (agent: Agent) => {\n // Attempt to get the invoker for the callback function.\n const callbackFuncInvoker = Lookup.getFuncInvoker(agent, this.getFunctionName());\n\n // The callback function should be defined.\n if (callbackFuncInvoker === null) {\n throw new Error(\n `cannot call step function '${this.getFunctionName()}' as is not defined on the agent and has not been registered`\n );\n }\n\n // Call the callback function.\n callbackFuncInvoker(this.args);\n };\n}\n", "import Callback from \"./Callback\";\nimport Lookup from \"../../Lookup\";\nimport { Agent } from \"../../Agent\";\n\n/**\n * An EXIT callback which defines an agent function to call when the associated node is updated and moves to a finished state or is aborted.\n */\nexport default class Exit extends Callback {\n /**\n * @param functionName The name of the agent function to call.\n * @param args The array of callback argument definitions.\n */\n constructor(functionName: string, args: any[]) {\n super(\"exit\", args, functionName);\n }\n\n /**\n * Attempt to call the agent function that this callback refers to.\n * @param agent The agent.\n * @param isSuccess Whether the decorated node was left with a success state.\n * @param isAborted Whether the decorated node was aborted.\n */\n callAgentFunction = (agent: Agent, isSuccess: boolean, isAborted: boolean) => {\n // Attempt to get the invoker for the callback function.\n const callbackFuncInvoker = Lookup.getFuncInvoker(agent, this.getFunctionName());\n\n // The callback function should be defined.\n if (callbackFuncInvoker === null) {\n throw new Error(\n `cannot call exit function '${this.getFunctionName()}' as is not defined on the agent and has not been registered`\n );\n }\n\n // Call the callback function\n callbackFuncInvoker([{ value: { succeeded: isSuccess, aborted: isAborted } }, ...this.args]);\n };\n}\n", "import { AnyNodeDefinition, RootNodeDefinition } from \"./BehaviourTreeDefinition\";\nimport GuardPath, { GuardPathPart } from \"./attributes/guards/GuardPath\";\nimport { validateBranchSubtreeLinks } from \"./BehaviourTreeDefinitionValidator\";\nimport { isInteger } from \"./BehaviourTreeDefinitionUtilities\";\nimport Node from \"./nodes/Node\";\nimport Composite from \"./nodes/composite/Composite\";\nimport Decorator from \"./nodes/decorator/Decorator\";\nimport Parallel from \"./nodes/composite/Parallel\";\nimport Selector from \"./nodes/composite/Selector\";\nimport Sequence from \"./nodes/composite/Sequence\";\nimport Lotto from \"./nodes/composite/Lotto\";\nimport Fail from \"./nodes/decorator/Fail\";\nimport Flip from \"./nodes/decorator/Flip\";\nimport Repeat from \"./nodes/decorator/Repeat\";\nimport Retry from \"./nodes/decorator/Retry\";\nimport Root from \"./nodes/decorator/Root\";\nimport Succeed from \"./nodes/decorator/Succeed\";\nimport Action from \"./nodes/leaf/Action\";\nimport Condition from \"./nodes/leaf/Condition\";\nimport Wait from \"./nodes/leaf/Wait\";\nimport Lookup from \"./Lookup\";\nimport Attribute from \"./attributes/Attribute\";\nimport While from \"./attributes/guards/While\";\nimport Until from \"./attributes/guards/Until\";\nimport Entry from \"./attributes/callbacks/Entry\";\nimport Step from \"./attributes/callbacks/Step\";\nimport Exit from \"./attributes/callbacks/Exit\";\n\n/**\n * A type representing any node instance in a behaviour tree.\n */\ntype AnyNode =\n | Root\n | Action\n | Condition\n | Wait\n | Sequence\n | Selector\n | Lotto\n | Parallel\n | Repeat\n | Retry\n | Flip\n | Succeed\n | Fail;\n\n/**\n * A type defining a mapping of root node identifiers to root node definitions.\n */\ntype RootNodeDefinitionMap = { [key: string | symbol]: RootNodeDefinition };\n\n/**\n * A symbol to use as the main root key in any root node mappings.\n */\nconst MAIN_ROOT_NODE_KEY = Symbol(\"__root__\");\n\n/**\n * Build and populate the root nodes based on the provided definition, assuming that the definition has been validated.\n * @param definition The root node definitions.\n * @returns The built and populated root node definitions.\n */\nexport default function buildRootNode(definition: RootNodeDefinition[]): Root {\n // Create a mapping of root node identifers to root node definitions, including globally registered subtree root node definitions.\n const rootNodeDefinitionMap = createRootNodeDefinitionMap(definition);\n\n // Now that we have all of our root node definitions (those part of the tree definition and those globally registered)\n // we should validate the branch-subtree links. This will also double-check that we dont have any circular dependencies\n // in our branch-subtree references and that we have no broken branch-subtree links.\n validateBranchSubtreeLinks(\n [rootNodeDefinitionMap[MAIN_ROOT_NODE_KEY], ...Object.values(rootNodeDefinitionMap)],\n true\n );\n\n // Create our populated tree of node instances, starting with our main root node.\n const rootNode = nodeFactory(rootNodeDefinitionMap[MAIN_ROOT_NODE_KEY], rootNodeDefinitionMap) as Root;\n\n // Set a guard path on every leaf of the tree to evaluate as part of each update.\n applyLeafNodeGuardPaths(rootNode);\n\n // We only need to return the main root node.\n return rootNode;\n}\n\n/**\n * A factory function which creates a node instance based on the specified definition.\n * @param definition The node definition.\n * @param rootNodeDefinitionMap The mapping of root node identifers to root node definitions, including globally registered subtree root node definitions.\n * @returns A node instance based on the specified definition.\n */\nfunction nodeFactory(definition: AnyNodeDefinition, rootNodeDefinitionMap: RootNodeDefinitionMap): AnyNode {\n // Get the attributes for the node.\n const attributes = nodeAttributesFactory(definition);\n\n // Create the node instance based on the definition type.\n switch (definition.type) {\n case \"root\":\n return new Root(attributes, nodeFactory(definition.child, rootNodeDefinitionMap));\n\n case \"repeat\":\n let iterations: number | null = null;\n let iterationsMin: number | null = null;\n let iterationsMax: number | null = null;\n\n if (Array.isArray(definition.iterations)) {\n iterationsMin = definition.iterations[0];\n iterationsMax = definition.iterations[1];\n } else if (isInteger(definition.iterations)) {\n iterations = definition.iterations!;\n }\n\n return new Repeat(\n attributes,\n iterations,\n iterationsMin,\n iterationsMax,\n nodeFactory(definition.child, rootNodeDefinitionMap)\n );\n\n case \"retry\":\n let attempts: number | null = null;\n let attemptsMin: number | null = null;\n let attemptsMax: number | null = null;\n\n if (Array.isArray(definition.attempts)) {\n attemptsMin = definition.attempts[0];\n attemptsMax = definition.attempts[1];\n } else if (isInteger(definition.attempts)) {\n attempts = definition.attempts!;\n }\n\n return new Retry(\n attributes,\n attempts,\n attemptsMin,\n attemptsMax,\n nodeFactory(definition.child, rootNodeDefinitionMap)\n );\n\n case \"flip\":\n return new Flip(attributes, nodeFactory(definition.child, rootNodeDefinitionMap));\n\n case \"succeed\":\n return new Succeed(attributes, nodeFactory(definition.child, rootNodeDefinitionMap));\n\n case \"fail\":\n return new Fail(attributes, nodeFactory(definition.child, rootNodeDefinitionMap));\n\n case \"sequence\":\n return new Sequence(\n attributes,\n definition.children.map((child) => nodeFactory(child, rootNodeDefinitionMap))\n );\n\n case \"selector\":\n return new Selector(\n attributes,\n definition.children.map((child) => nodeFactory(child, rootNodeDefinitionMap))\n );\n\n case \"parallel\":\n return new Parallel(\n attributes,\n definition.children.map((child) => nodeFactory(child, rootNodeDefinitionMap))\n );\n\n case \"lotto\":\n return new Lotto(\n attributes,\n definition.weights,\n definition.children.map((child) => nodeFactory(child, rootNodeDefinitionMap))\n );\n\n case \"branch\":\n return nodeFactory(rootNodeDefinitionMap[definition.ref].child, rootNodeDefinitionMap);\n\n case \"action\":\n return new Action(attributes, definition.call, definition.args || []);\n\n case \"condition\":\n return new Condition(attributes, definition.call, definition.args || []);\n\n case \"wait\":\n let duration: number | null = null;\n let durationMin: number | null = null;\n let durationMax: number | null = null;\n\n if (Array.isArray(definition.duration)) {\n durationMin = definition.duration[0];\n durationMax = definition.duration[1];\n } else if (isInteger(definition.duration)) {\n duration = definition.duration!;\n }\n\n return new Wait(attributes, duration, durationMin, durationMax);\n }\n}\n\n/**\n * Creates an array of node attribute instances based on the specified node definition.\n * @param definition The node definition.\n * @returns An array of node attribute instances based on the specified node definition.\n */\nfunction nodeAttributesFactory(definition: AnyNodeDefinition): Attribute[] {\n const attributes: Attribute[] = [];\n\n if (definition.while) {\n attributes.push(new While(definition.while.call, definition.while.args ?? []));\n }\n\n if (definition.until) {\n attributes.push(new Until(definition.until.call, definition.until.args ?? []));\n }\n\n if (definition.entry) {\n attributes.push(new Entry(definition.entry.call, definition.entry.args ?? []));\n }\n\n if (definition.step) {\n attributes.push(new Step(definition.step.call, definition.step.args ?? []));\n }\n\n if (definition.exit) {\n attributes.push(new Exit(definition.exit.call, definition.exit.args ?? []));\n }\n\n return attributes;\n}\n\n/**\n * Creates a mapping of root node identifers to root node definitions, mixing in globally registered subtree root node definitions.\n * @param definition The root node definitions.\n * @returns A mapping of root node identifers to root node definitions, including globally registered subtree root node definitions.\n */\nfunction createRootNodeDefinitionMap(definition: RootNodeDefinition[]): RootNodeDefinitionMap {\n // Create a mapping of root node identifers to root node definitions.\n const rootNodeMap: RootNodeDefinitionMap = {};\n\n // Add in any registered subtree root node definitions.\n for (const [name, rootNodeDefinition] of Object.entries(Lookup.getSubtrees())) {\n // The name used when registering the subtree will be used as the root node identifier.\n rootNodeMap[name] = { ...rootNodeDefinition, id: name };\n }\n\n // Populate the map with the root node definitions that were included with the tree definition.\n // We do this after adding any registered subtrees as we want these to take presedence.\n for (const rootNodeDefinition of definition) {\n rootNodeMap[rootNodeDefinition.id ?? MAIN_ROOT_NODE_KEY] = rootNodeDefinition;\n }\n\n return rootNodeMap;\n}\n\n/**\n * Applies a guard path to every leaf of the tree to evaluate as part of each update.\n * @param root The main root tree node.\n */\nfunction applyLeafNodeGuardPaths(root: Root) {\n const nodePaths: Node[][] = [];\n\n const findLeafNodes = (path: Node[], node: Node) => {\n // Add the current node to the path.\n path = path.concat(node);\n\n // Check whether the current node is a leaf node.\n if (node.isLeafNode()) {\n nodePaths.push(path);\n } else {\n (node as Composite | Decorator).getChildren().forEach((child) => findLeafNodes(path, child));\n }\n };\n\n // Find all leaf node paths, starting from the root.\n findLeafNodes([], root);\n\n nodePaths.forEach((path) => {\n // Each node in the current path will have to be assigned a guard path, working from the root outwards.\n for (let depth = 0; depth < path.length; depth++) {\n // Get the node in the path at the current depth.\n const currentNode = path[depth];\n\n // The node may already have been assigned a guard path, if so just skip it.\n if (currentNode.hasGuardPath()) {\n continue;\n }\n\n // Create the guard path for the current node.\n const guardPath = new GuardPath(\n path\n .slice(0, depth + 1)\n .map((node) => ({ node, guards: node.getGuardAttributes() }))\n .filter((details) => details.guards.length > 0)\n );\n\n // Assign the guard path to the current node.\n currentNode.setGuardPath(guardPath);\n }\n });\n}\n", "import State, { AnyState } from \"./State\";\nimport Lookup from \"./Lookup\";\nimport Node from \"./nodes/Node\";\nimport Root from \"./nodes/decorator/Root\";\nimport Composite from \"./nodes/composite/Composite\";\nimport Decorator from \"./nodes/decorator/Decorator\";\nimport { Agent, GlobalFunction } from \"./Agent\";\nimport { CallbackAttributeDetails } from \"./attributes/callbacks/Callback\";\nimport { GuardAttributeDetails } from \"./attributes/guards/Guard\";\nimport { BehaviourTreeOptions } from \"./BehaviourTreeOptions\";\nimport { convertMDSLToJSON } from \"./mdsl/MDSLDefinitionParser\";\nimport { RootNodeDefinition } from \"./BehaviourTreeDefinition\";\nimport { validateDefinition, validateJSONDefinition } from \"./BehaviourTreeDefinitionValidator\";\nimport buildRootNode from \"./BehaviourTreeBuilder\";\nimport { isNullOrUndefined } from \"./BehaviourTreeDefinitionUtilities\";\n\n// Purely for outside inspection of the tree.\nexport type FlattenedTreeNode = {\n id: string;\n type: string;\n caption: string;\n state: AnyState;\n guards: GuardAttributeDetails[];\n callbacks: CallbackAttributeDetails[];\n args: any[];\n parentId: string | null;\n};\n\n/**\n * A representation of a behaviour tree.\n */\nexport class BehaviourTree {\n /**\n * The main root tree node.\n */\n private readonly _rootNode: Root;\n\n /**\n * Creates a new instance of the BehaviourTree class.\n * @param definition The behaviour tree definition as either an MDSL string, root node definition object or array of root node definition objects.\n * @param agent The agent instance that this behaviour tree is modelling behaviour for.\n * @param options The behaviour tree options object.\n */\n constructor(\n definition: string | RootNodeDefinition | RootNodeDefinition[],\n private agent: Agent,\n private options: BehaviourTreeOptions = {}\n ) {\n // The tree definition must be defined.\n if (isNullOrUndefined(definition)) {\n throw new Error(\"tree definition not defined\");\n }\n\n // The agent must be defined and not null.\n if (typeof agent !== \"object\" || agent === null) {\n throw new Error(\"the agent must be an object and not null\");\n }\n\n // We should validate the definition before we try to build the tree nodes.\n const { succeeded, errorMessage, json } = validateDefinition(definition);\n\n // Did our validation fail without error?\n if (!succeeded) {\n throw new Error(`invalid definition: ${errorMessage}`);\n }\n\n // Double check that we did actually get our json definition as part of our definition validtion.\n if (!json) {\n throw new Error(\n \"expected json definition to be returned as part of successful definition validation response\"\n );\n }\n\n try {\n // Create the populated tree of behaviour tree nodes and get the root node.\n this._rootNode = buildRootNode(json);\n } catch (exception) {\n // There was an issue in trying build and populate the behaviour tree.\n throw new Error(`error building tree: ${(exception as Error).message}`);\n }\n }\n\n /**\n * Gets whether the tree is in the RUNNING state.\n * @returns true if the tree is in the RUNNING state, otherwise false.\n */\n isRunning() {\n return this._rootNode.getState() === State.RUNNING;\n }\n\n /**\n * Gets the current tree state of SUCCEEDED, FAILED, READY or RUNNING.\n * @returns The current tree state.\n */\n getState() {\n return this._rootNode.getState();\n }\n\n /**\n * Step the tree.\n * 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.\n * 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\n * 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.\n *\n * 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.\n */\n step() {\n // If the root node has already been stepped to completion then we need to reset it.\n if (this._rootNode.getState() === State.SUCCEEDED || this._rootNode.getState() === State.FAILED) {\n this._rootNode.reset();\n }\n\n try {\n this._rootNode.update(this.agent, this.options);\n } catch (exception) {\n throw new Error(`error stepping tree: ${(exception as Error).message}`);\n }\n }\n\n /**\n * Resets the tree from the root node outwards to each nested node, giving each a state of READY.\n */\n reset() {\n this._rootNode.reset();\n }\n\n /**\n * Gets the flattened details of every node in the tree.\n * @returns The flattened details of every node in the tree.\n */\n getFlattenedNodeDetails(): FlattenedTreeNode[] {\n // Create an empty flattened array of tree nodes.\n const flattenedTreeNodes: FlattenedTreeNode[] = [];\n\n /**\n * Helper function to process a node instance and push details into the flattened tree nodes array.\n * @param node The current node.\n * @param parentUid The UID of the node parent, or null if the node is the main root node.\n */\n const processNode = (node: Node, parentUid: string | null) => {\n // Get the guard and callback attribute details for this node.\n const guards = node\n .getAttributes()\n .filter((attribute) => attribute.isGuard())\n .map((attribute) => attribute.getDetails()) as GuardAttributeDetails[];\n const callbacks = node\n .getAttributes()\n .filter((attribute) => !attribute.isGuard())\n .map((attribute) => attribute.getDetails()) as CallbackAttributeDetails[];\n\n // Push the current node into the flattened nodes array.\n flattenedTreeNodes.push({\n id: node.getUid(),\n type: node.getType(),\n caption: node.getName(),\n state: node.getState(),\n guards,\n callbacks,\n args: node.getArguments(),\n parentId: parentUid\n });\n\n // Process each of the nodes children if it is not a leaf node.\n if (!node.isLeafNode()) {\n (node as Composite | Decorator)\n .getChildren()\n .forEach((child) => processNode(child, (node as Composite | Decorator).getUid()));\n }\n };\n\n // Convert the nested node structure into a flattened array of node details.\n processNode(this._rootNode, null);\n\n return flattenedTreeNodes;\n }\n\n /**\n * Registers the action/condition/guard/callback function or subtree with the given name.\n * @param name The name of the function or subtree to register.\n * @param value The function or subtree definition to register.\n */\n static register(name: string, value: GlobalFunction | string | RootNodeDefinition) {\n // Are we going to register a action/condition/guard/callback function?\n if (typeof value === \"function\") {\n Lookup.setFunc(name, value);\n return;\n }\n\n // We are not registering an action/condition/guard/callback function, so we must be registering a subtree.\n if (typeof value === \"string\") {\n let rootNodeDefinitions: RootNodeDefinition[];\n\n // We will assume that any string passed in will be a mdsl definition.\n try {\n rootNodeDefinitions = convertMDSLToJSON(value);\n } catch (exception) {\n throw new Error(`error registering definition, invalid MDSL: ${(exception as Error).message}`);\n }\n\n // This function should only ever be called with a definition containing a single unnamed root node.\n if (rootNodeDefinitions.length != 1 || rootNodeDefinitions[0].id !== null) {\n throw new Error(\"error registering definition: expected a single unnamed root node\");\n }\n\n try {\n // We should validate the subtree as we don't want invalid subtrees available via the lookup.\n const { succeeded, errorMessage } = validateJSONDefinition(rootNodeDefinitions[0]);\n\n // Did our validation fail without error?\n if (!succeeded) {\n throw new Error(errorMessage);\n }\n } catch (exception) {\n throw new Error(`error registering definition: ${(exception as Error).message}`);\n }\n\n // Everything seems hunky-dory, register the subtree.\n Lookup.setSubtree(name, rootNodeDefinitions[0]);\n } else if (typeof value === \"object\" && !Array.isArray(value)) {\n // We will assume that any object passed in is a root node definition.\n\n try {\n // We should validate the subtree as we don't want invalid subtrees available via the lookup.\n const { succeeded, errorMessage } = validateJSONDefinition(value);\n\n // Did our validation fail without error?\n if (!succeeded) {\n throw new Error(errorMessage);\n }\n } catch (exception) {\n throw new Error(`error registering definition: ${(exception as Error).message}`);\n }\n\n // Everything seems hunky-dory, register the subtree.\n Lookup.setSubtree(name, value);\n } else {\n throw new Error(\"unexpected value, expected string mdsl definition, root node json definition or function\");\n }\n }\n\n /**\n * Unregisters the registered action/condition/guard/callback function or subtree with the given name.\n * @param name The name of the registered action/condition/guard/callback function or subtree to unregister.\n */\n static unregister(name: string): void {\n Lookup.remove(name);\n }\n\n /**\n * Unregister all registered action/condition/guard/callback functions and subtrees.\n */\n static unregisterAll(): void {\n Lookup.empty();\n }\n}\n"], + "mappings": "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", "names": ["Participant", "isNullOrUndefined", "Lotto", "createLotto", "State", "createLotto"] } diff --git a/src/Agent.ts b/src/Agent.ts index ee600fc..59671c7 100644 --- a/src/Agent.ts +++ b/src/Agent.ts @@ -1,4 +1,4 @@ -import { CompleteState } from "./State"; +import State, { CompleteState } from "./State"; /** * A type representing an agent that a behavior tree instance would operate on. @@ -35,6 +35,6 @@ export type Agent = { export type ExitFunctionArg = { succeeded: boolean; aborted: boolean }; export type FunctionArg = number | string | boolean | null | ExitFunctionArg; -export type ActionResult = CompleteState | Promise | boolean | void; -export type AgentFunction = (this: Agent, ...args: FunctionArg[]) => ActionResult; -export type GlobalFunction = (agent: Agent, ...args: FunctionArg[]) => ActionResult; +export type ActionResult = CompleteState | Promise | State.RUNNING | void; +export type AgentFunction = (this: Agent, ...args: FunctionArg[]) => ActionResult | boolean; +export type GlobalFunction = (agent: Agent, ...args: FunctionArg[]) => ActionResult | boolean; diff --git a/src/BehaviourTreeBuilder.ts b/src/BehaviourTreeBuilder.ts index 56b129a..89d0c31 100644 --- a/src/BehaviourTreeBuilder.ts +++ b/src/BehaviourTreeBuilder.ts @@ -63,10 +63,13 @@ export default function buildRootNode(definition: RootNodeDefinition[]): Root { // Create a mapping of root node identifers to root node definitions, including globally registered subtree root node definitions. const rootNodeDefinitionMap = createRootNodeDefinitionMap(definition); - // Now that we have all of our root node definitons (those part of the tree definition and those globally - // registered) we should validate the definition. This will also double-check that we dont have any circular - // dependencies in our branch -> subtree references and that we have no broken branch -> subtree links. - validateBranchSubtreeLinks(definition, true); + // Now that we have all of our root node definitions (those part of the tree definition and those globally registered) + // we should validate the branch-subtree links. This will also double-check that we dont have any circular dependencies + // in our branch-subtree references and that we have no broken branch-subtree links. + validateBranchSubtreeLinks( + [rootNodeDefinitionMap[MAIN_ROOT_NODE_KEY], ...Object.values(rootNodeDefinitionMap)], + true + ); // Create our populated tree of node instances, starting with our main root node. const rootNode = nodeFactory(rootNodeDefinitionMap[MAIN_ROOT_NODE_KEY], rootNodeDefinitionMap) as Root; diff --git a/src/Lookup.ts b/src/Lookup.ts index 523274e..55369f1 100644 --- a/src/Lookup.ts +++ b/src/Lookup.ts @@ -1,7 +1,7 @@ import { ActionResult, Agent, GlobalFunction } from "./Agent"; import { RootNodeDefinition } from "./BehaviourTreeDefinition"; -export type InvokerFunction = (args: any[]) => ActionResult; +export type InvokerFunction = (args: any[]) => ActionResult | boolean; /** * A singleton used to store and lookup registered functions and subtrees. @@ -10,11 +10,11 @@ export default class Lookup { /** * The object holding any registered functions keyed on function name. */ - private static functionTable: { [key: string]: GlobalFunction } = {}; + private static registeredFunctions: { [key: string]: GlobalFunction } = {}; /** * The object holding any registered subtree root node definitions keyed on tree name. */ - private static subtreeTable: { [key: string]: RootNodeDefinition } = {}; + private static registeredSubtrees: { [key: string]: RootNodeDefinition } = {}; /** * Gets the function with the specified name. @@ -22,7 +22,7 @@ export default class Lookup { * @returns The function with the specified name. */ public static getFunc(name: string): GlobalFunction { - return this.functionTable[name]; + return this.registeredFunctions[name]; } /** @@ -31,7 +31,7 @@ export default class Lookup { * @param func The function. */ public static setFunc(name: string, func: GlobalFunction): void { - this.functionTable[name] = func; + this.registeredFunctions[name] = func; } /** @@ -44,14 +44,15 @@ export default class Lookup { */ static getFuncInvoker(agent: Agent, name: string): InvokerFunction | null { // Check whether the agent contains the specified function. - const foundOnAgent = agent[name]; - if (foundOnAgent && typeof foundOnAgent === "function") { - return (args: any[]): boolean | ActionResult => foundOnAgent.apply(agent, args); + const agentFunction = agent[name]; + if (agentFunction && typeof agentFunction === "function") { + return (args: any[]) => agentFunction.apply(agent, args); } // The agent does not contain the specified function but it may have been registered at some point. - if (this.functionTable[name] && typeof this.functionTable[name] === "function") { - return (args: any[]) => this.functionTable[name](agent, ...args.map((arg) => arg.value)); + if (this.registeredFunctions[name] && typeof this.registeredFunctions[name] === "function") { + const registeredFunction = this.registeredFunctions[name]; + return (args: any[]) => registeredFunction(agent, ...args.map((arg) => arg.value)); } // We have no function to invoke. @@ -62,7 +63,7 @@ export default class Lookup { * Gets all registered subtree root node definitions. */ static getSubtrees(): { [key: string]: RootNodeDefinition } { - return this.subtreeTable; + return this.registeredSubtrees; } /** @@ -71,7 +72,7 @@ export default class Lookup { * @param subtree The subtree. */ static setSubtree(name: string, subtree: RootNodeDefinition) { - this.subtreeTable[name] = subtree; + this.registeredSubtrees[name] = subtree; } /** @@ -79,15 +80,15 @@ export default class Lookup { * @param name The name of the registered function or subtree. */ static remove(name: string) { - delete this.functionTable[name]; - delete this.subtreeTable[name]; + delete this.registeredFunctions[name]; + delete this.registeredSubtrees[name]; } /** * Remove all registered functions and subtrees. */ static empty() { - this.functionTable = {}; - this.subtreeTable = {}; + this.registeredFunctions = {}; + this.registeredSubtrees = {}; } } diff --git a/src/mdsl/MDSLDefinitionParser.ts b/src/mdsl/MDSLDefinitionParser.ts index 25bcd20..e5f6158 100644 --- a/src/mdsl/MDSLDefinitionParser.ts +++ b/src/mdsl/MDSLDefinitionParser.ts @@ -259,9 +259,8 @@ function convertTokensToJSONDefinition( function createRootNode(tokens: string[], stringLiteralPlaceholders: StringLiteralPlaceholders): RootNodeDefinition { // Create the root node definition. let node = { - type: "root", - id: undefined - } as RootNodeDefinition; + type: "root" + } as Partial; // Parse any node arguments, we should only have one if any which will be an identifier argument for the root identifier. const nodeArguments = parseArgumentTokens(tokens, stringLiteralPlaceholders); @@ -284,7 +283,7 @@ function createRootNode(tokens: string[], stringLiteralPlaceholders: StringLiter popAndCheck(tokens, "{"); // Return the root node definition. - return node; + return node as RootNodeDefinition; } /** @@ -563,10 +562,14 @@ function createLottoNode(tokens: string[], stringLiteralPlaceholders: StringLite const node = { type: "lotto", - weights: nodeArguments.length ? nodeArguments.map(({ value }) => value) : undefined, ...parseAttributeTokens(tokens, stringLiteralPlaceholders) } as LottoNodeDefinition; + // Apply the weights if any were defined. + if (nodeArguments.length) { + node.weights = nodeArguments.map(({ value }) => value) as number[]; + } + // This is a composite node, so we expect an opening '{'. popAndCheck(tokens, "{"); diff --git a/src/mdsl/MDSLNodeAttributeParser.ts b/src/mdsl/MDSLNodeAttributeParser.ts index ee2ab01..f8cfe02 100644 --- a/src/mdsl/MDSLNodeAttributeParser.ts +++ b/src/mdsl/MDSLNodeAttributeParser.ts @@ -49,7 +49,7 @@ export function parseAttributeTokens( // The first attribute argument has to be an identifer, this will reference an agent function. if (attributeCallIdentifier?.type !== "identifier") { - throw new Error("expected agent function name identifier argument for attribute"); + throw new Error("expected agent function or registered function name identifier argument for attribute"); } // Any attribute arguments (other than the expected call identifier) must have a type of string, number, boolean or null. diff --git a/src/nodes/leaf/Action.ts b/src/nodes/leaf/Action.ts index 357e85e..6ad531a 100644 --- a/src/nodes/leaf/Action.ts +++ b/src/nodes/leaf/Action.ts @@ -164,15 +164,16 @@ export default class Action extends Leaf { * Validate the result of an update function call. * @param result The result of an update function call. */ - private validateUpdateResult = (result: CompleteState | boolean) => { + private validateUpdateResult = (result: CompleteState | State.RUNNING) => { switch (result) { case State.SUCCEEDED: case State.FAILED: + case State.RUNNING: case undefined: return; default: throw new Error( - `action '${this.actionName}' 'onUpdate' returned an invalid response, expected an optional State.SUCCEEDED or State.FAILED value to be returned` + `expected action function '${this.actionName}' to return an optional State.SUCCEEDED or State.FAILED value but returned '${result}'` ); } }; diff --git a/test/BehaviourTreeBuilder.spec.ts b/test/BehaviourTreeBuilder.spec.ts index fdd4fcd..582a8b5 100644 --- a/test/BehaviourTreeBuilder.spec.ts +++ b/test/BehaviourTreeBuilder.spec.ts @@ -1 +1,142 @@ -describe("The BehaviourTreeBuilder class", () => {}); +import { assert } from "chai"; + +import { RootNodeDefinition } from "../src/BehaviourTreeDefinition"; +import { BehaviourTree } from "../src/index"; +import buildRootNode from "../src/BehaviourTreeBuilder"; +import Sequence from "../src/nodes/composite/Sequence"; +import Action from "../src/nodes/leaf/Action"; +import Flip from "../src/nodes/decorator/Flip"; + +describe("The BehaviourTreeBuilder class has a buildRootNode function which takes an array of root node JSON definitions and", () => { + beforeEach(() => BehaviourTree.unregisterAll()); + + it("returns a populated Root node instance based on those definitions", () => { + const definition: RootNodeDefinition[] = [ + { + type: "root", + child: { + type: "sequence", + children: [ + { + type: "action", + call: "noop" + } + ] + } + } + ]; + + const rootNode = buildRootNode(definition); + + assert.isDefined(rootNode); + assert.strictEqual(rootNode.getType(), "root"); + + const sequenceNode = rootNode.getChildren()[0] as Sequence; + assert.isDefined(sequenceNode); + assert.strictEqual(sequenceNode.getType(), "sequence"); + assert.strictEqual(sequenceNode.getChildren().length, 1); + + const actionNode = sequenceNode.getChildren()[0] as Action; + assert.isDefined(actionNode); + assert.strictEqual(actionNode.getType(), "action"); + }); + + describe("resolves branch node definitions", () => { + describe("where the referenced subtree root node is", () => { + it("included as part of the definition", () => { + const definition: RootNodeDefinition[] = [ + { + type: "root", + child: { + type: "flip", + child: { + type: "branch", + ref: "sub-tree" + } + } + }, + { + type: "root", + id: "sub-tree", + child: { + type: "action", + call: "noop" + } + } + ]; + + const rootNode = buildRootNode(definition); + + assert.isDefined(rootNode); + assert.strictEqual(rootNode.getType(), "root"); + + const flipNode = rootNode.getChildren()[0] as Flip; + assert.isDefined(flipNode); + assert.strictEqual(flipNode.getType(), "flip"); + assert.strictEqual(flipNode.getChildren().length, 1); + + const actionNode = flipNode.getChildren()[0] as Action; + assert.isDefined(actionNode); + assert.strictEqual(actionNode.getType(), "action"); + }); + + it("globally registered", () => { + BehaviourTree.register("sub-tree", { + type: "root", + child: { + type: "action", + call: "noop" + } + }); + + const definition: RootNodeDefinition[] = [ + { + type: "root", + child: { + type: "flip", + child: { + type: "branch", + ref: "sub-tree" + } + } + } + ]; + + const rootNode = buildRootNode(definition); + + assert.isDefined(rootNode); + assert.strictEqual(rootNode.getType(), "root"); + + const flipNode = rootNode.getChildren()[0] as Flip; + assert.isDefined(flipNode); + assert.strictEqual(flipNode.getType(), "flip"); + assert.strictEqual(flipNode.getChildren().length, 1); + + const actionNode = flipNode.getChildren()[0] as Action; + assert.isDefined(actionNode); + assert.strictEqual(actionNode.getType(), "action"); + }); + }); + + it("and errors if any referenced subtree root node is not included as part of the definition and is not a globally registered subtree", () => { + const definition: RootNodeDefinition[] = [ + { + type: "root", + child: { + type: "flip", + child: { + type: "branch", + ref: "sub-tree" + } + } + } + ]; + + assert.throws( + () => buildRootNode(definition), + Error, + "primary tree has branch node that references root node 'sub-tree' which has not been defined" + ); + }); + }); +}); diff --git a/test/attributes/callbacks/Entry.spec.ts b/test/attributes/callbacks/Entry.spec.ts new file mode 100644 index 0000000..9efad9a --- /dev/null +++ b/test/attributes/callbacks/Entry.spec.ts @@ -0,0 +1,102 @@ +import { assert } from "chai"; +import sinon from "sinon"; + +import { BehaviourTree, State } from "../../../src/index"; +import { RootNodeDefinition } from "../../../src/BehaviourTreeDefinition"; + +describe("An Entry callback node attribute", () => { + describe("on tree initialisation", () => { + describe("will error if no function name is defined", () => { + it("(MDSL)", () => { + const definition = "root { action [noop] entry() }"; + assert.throws( + () => new BehaviourTree(definition, {}), + Error, + "expected agent function or registered function name identifier argument for attribute" + ); + }); + + it("(JSON)", () => { + const definition: RootNodeDefinition = { + type: "root", + child: { + type: "action", + call: "noop", + entry: {} as any + } + }; + assert.throws( + () => new BehaviourTree(definition, {}), + Error, + "expected 'call' property for attribute 'entry' to be a non-empty string for 'action' node at depth '1'" + ); + }); + }); + }); + + describe("when the node is updated as part of a tree step will call the entry function if it is the first time the node is being updated", () => { + it("(MDSL)", () => { + const definition = `root entry(onEntry, "root") { action [someAction] entry(onEntry, "action") }`; + const agent = { + someAction: () => State.RUNNING, + onEntry: sinon.stub() + }; + const tree = new BehaviourTree(definition, agent); + + assert.isNotTrue(agent.onEntry.called); + + tree.step(); + + assert.isTrue(tree.isRunning()); + assert.isTrue(agent.onEntry.calledTwice); + assert.isTrue(agent.onEntry.calledWith("root")); + assert.isTrue(agent.onEntry.calledWith("action")); + + agent.someAction = () => State.SUCCEEDED; + + tree.step(); + + assert.isFalse(tree.isRunning()); + assert.isTrue(agent.onEntry.calledTwice); + }); + + it("(MDSL)", () => { + const definition: RootNodeDefinition = { + type: "root", + entry: { + call: "onEntry", + args: ["root"] + }, + child: { + type: "action", + entry: { + call: "onEntry", + args: ["action"] + }, + call: "someAction" + } + }; + const agent = { + someAction: () => State.RUNNING, + onEntry: sinon.stub() + }; + const tree = new BehaviourTree(definition, agent); + + assert.isNotTrue(agent.onEntry.called); + + tree.step(); + + assert.isTrue(tree.isRunning()); + assert.isTrue(agent.onEntry.calledTwice); + assert.isTrue(agent.onEntry.calledWith("root")); + assert.isTrue(agent.onEntry.calledWith("action")); + + agent.someAction = () => State.SUCCEEDED; + + tree.step(); + + assert.isFalse(tree.isRunning()); + assert.isTrue(agent.onEntry.calledTwice); + }); + }); +}); diff --git a/test/attributes/callbacks/Exit.spec.ts b/test/attributes/callbacks/Exit.spec.ts new file mode 100644 index 0000000..cd8ad9d --- /dev/null +++ b/test/attributes/callbacks/Exit.spec.ts @@ -0,0 +1 @@ +describe("An Exit callback node attribute", () => {}); diff --git a/test/attributes/callbacks/Step.spec.ts b/test/attributes/callbacks/Step.spec.ts new file mode 100644 index 0000000..a635a5b --- /dev/null +++ b/test/attributes/callbacks/Step.spec.ts @@ -0,0 +1 @@ +describe("A Step callback node attribute", () => {}); diff --git a/test/attributes/guards/Until.spec.ts b/test/attributes/guards/Until.spec.ts new file mode 100644 index 0000000..49bf92c --- /dev/null +++ b/test/attributes/guards/Until.spec.ts @@ -0,0 +1 @@ +describe("An Until guard node attribute", () => {}); diff --git a/test/attributes/guards/While.spec.ts b/test/attributes/guards/While.spec.ts new file mode 100644 index 0000000..2575335 --- /dev/null +++ b/test/attributes/guards/While.spec.ts @@ -0,0 +1 @@ +describe("A While guard node attribute", () => {}); diff --git a/test/mdsl/MDSLDefinitionParser.spec.ts b/test/mdsl/MDSLDefinitionParser.spec.ts index 85176e7..a2ef418 100644 --- a/test/mdsl/MDSLDefinitionParser.spec.ts +++ b/test/mdsl/MDSLDefinitionParser.spec.ts @@ -1,9 +1,204 @@ import { assert } from "chai"; -import { findNode } from "../TestUtilities"; +import { RootNodeDefinition } from "../../src/BehaviourTreeDefinition"; +import { convertMDSLToJSON } from "../../src/mdsl/MDSLDefinitionParser"; -describe("The convertMDSLToJSON function", () => { - it("does stuff", () => { - // assert.strictEqual(mistreevous.convertMDSLToJSON("root {}"), JSON.stringify([{ type: "root" }])); +describe("The MDSLDefinitionParser class has a convertMDSLToJSON function which takes a string MDSL definition and", () => { + describe("errors when", () => { + it("there is an invalid token count", () => { + const mdslDefinition = "root {"; + + assert.throws(() => convertMDSLToJSON(mdslDefinition), Error, "invalid token count"); + }); + + it("there is a scope character mismatch", () => { + const mdslDefinition = "root { flip { action [noop] }"; + + assert.throws(() => convertMDSLToJSON(mdslDefinition), Error, "scope character mismatch"); + }); + + it("a root node is not defined as the base of the definition", () => { + const mdslDefinition = "flip { action [noop] }"; + + assert.throws(() => convertMDSLToJSON(mdslDefinition), Error, "expected root node at base of definition"); + }); + + it("a root node is the child of another node", () => { + const mdslDefinition = "root { flip { root { action [noop] } } }"; + + assert.throws( + () => convertMDSLToJSON(mdslDefinition), + Error, + "a root node cannot be the child of another node" + ); + }); + + it("a decorator node has multiple child nodes", () => { + const mdslDefinition = "root { flip { action [noop] action [noop] } }"; + + assert.throws( + () => convertMDSLToJSON(mdslDefinition), + Error, + "a decorator node must only have a single child node" + ); + }); + }); + + it("returns the corresponding JSON definition", () => { + const mdslDefinition = ` + root { + selector while(IsHungry) { + sequence { + condition [HasDollars, 15] + action [OrderFood, "Pizza"] entry(PlayMusic, "pizza-song") + } + sequence { + condition [HasIngredient, "Steak"] + condition [HasIngredient, "Lobster"] + action [CookFood, "Surf 'n' Turf"] + } + sequence { + condition [HasIngredient, "Egg"] + branch [CookEggs] + } + sequence { + condition [HasIngredient, "Oats"] + action [CookFood, "Gruel"] + } + action [Starve] entry(OnStarveEntry) exit(OnStarveExit) + } + } + + root [CookEggs] { + lotto [100, 100, 5] { + action [CookFood, "Omelette"] + action [CookFood, "Scrambled Eggs"] + action [CookFood, "Fried Egg Surprise!"] + } + } + `; + + const expectedOutputDefintion: RootNodeDefinition[] = [ + { + type: "root", + child: { + type: "selector", + while: { + call: "IsHungry", + args: [] + }, + children: [ + { + type: "sequence", + children: [ + { + type: "condition", + call: "HasDollars", + args: [15] + }, + { + type: "action", + call: "OrderFood", + args: ["Pizza"], + entry: { + call: "PlayMusic", + args: ["pizza-song"] + } + } + ] + }, + { + type: "sequence", + children: [ + { + type: "condition", + call: "HasIngredient", + args: ["Steak"] + }, + { + type: "condition", + call: "HasIngredient", + args: ["Lobster"] + }, + { + type: "action", + call: "CookFood", + args: ["Surf 'n' Turf"] + } + ] + }, + { + type: "sequence", + children: [ + { + type: "condition", + call: "HasIngredient", + args: ["Egg"] + }, + { + type: "branch", + ref: "CookEggs" + } + ] + }, + { + type: "sequence", + children: [ + { + type: "condition", + call: "HasIngredient", + args: ["Oats"] + }, + { + type: "action", + call: "CookFood", + args: ["Gruel"] + } + ] + }, + { + type: "action", + call: "Starve", + args: [], + entry: { + call: "OnStarveEntry", + args: [] + }, + exit: { + call: "OnStarveExit", + args: [] + } + } + ] + } + }, + { + type: "root", + id: "CookEggs", + child: { + type: "lotto", + weights: [100, 100, 5], + children: [ + { + type: "action", + call: "CookFood", + args: ["Omelette"] + }, + { + type: "action", + call: "CookFood", + args: ["Scrambled Eggs"] + }, + { + type: "action", + call: "CookFood", + args: ["Fried Egg Surprise!"] + } + ] + } + } + ]; + + assert.deepEqual(convertMDSLToJSON(mdslDefinition), expectedOutputDefintion); }); }); diff --git a/test/nodes/leaf/Action.spec.ts b/test/nodes/leaf/Action.spec.ts index 5baaa6e..f407211 100644 --- a/test/nodes/leaf/Action.spec.ts +++ b/test/nodes/leaf/Action.spec.ts @@ -390,6 +390,42 @@ describe("An Action node", () => { }); }); + describe("the function returns a value of State.RUNNING", () => { + it("(MDSL)", () => { + const definition = "root { action [doAction] }"; + const agent = { doAction: () => State.RUNNING }; + const tree = new BehaviourTree(definition, agent); + + let node = findNode(tree, "action", "doAction"); + assert.strictEqual(node.state, State.READY); + + tree.step(); + + node = findNode(tree, "action", "doAction"); + assert.strictEqual(node.state, State.RUNNING); + }); + + it("(JSON)", () => { + const definition: RootNodeDefinition = { + type: "root", + child: { + type: "action", + call: "doAction" + } + }; + const agent = { doAction: () => State.RUNNING }; + const tree = new BehaviourTree(definition, agent); + + let node = findNode(tree, "action", "doAction"); + assert.strictEqual(node.state, State.READY); + + tree.step(); + + node = findNode(tree, "action", "doAction"); + assert.strictEqual(node.state, State.RUNNING); + }); + }); + describe("the function returns a promise to return a value of State.SUCCEEDED or State.FAILED", () => { it("(MDSL)", (done) => { const definition = "root { action [doAction] }"; From 1b2a040e9522ceac1c69402ceefbed5b4200ae2a Mon Sep 17 00:00:00 2001 From: Nikolas Howard Date: Tue, 27 Feb 2024 17:50:54 +0000 Subject: [PATCH 39/48] specs --- test/nodes/leaf/Action.spec.ts | 36 ++++++++++++++++++++++++++++++++++ 1 file changed, 36 insertions(+) diff --git a/test/nodes/leaf/Action.spec.ts b/test/nodes/leaf/Action.spec.ts index f407211..84dedd1 100644 --- a/test/nodes/leaf/Action.spec.ts +++ b/test/nodes/leaf/Action.spec.ts @@ -220,6 +220,42 @@ describe("An Action node", () => { }); }); + describe("returns an unexpected value", () => { + it("(MDSL)", () => { + const definition = "root { action [doAction] }"; + const agent = { + doAction: () => "invalid-result" + }; + const tree = new BehaviourTree(definition, agent); + + assert.throws( + () => tree.step(), + Error, + "error stepping tree: expected action function 'doAction' to return an optional State.SUCCEEDED or State.FAILED value but returned 'invalid-result'" + ); + }); + + it("(JSON)", () => { + const definition: RootNodeDefinition = { + type: "root", + child: { + type: "action", + call: "doAction" + } + }; + const agent = { + doAction: () => "invalid-result" + }; + const tree = new BehaviourTree(definition, agent); + + assert.throws( + () => tree.step(), + Error, + "error stepping tree: expected action function 'doAction' to return an optional State.SUCCEEDED or State.FAILED value but returned 'invalid-result'" + ); + }); + }); + describe("returns a rejected promise", () => { it("(MDSL)", (done) => { const definition = "root { action [doAction] }"; From cf068a59830d7e264d57608639aed69567ac86ba Mon Sep 17 00:00:00 2001 From: Nikolas Howard Date: Tue, 27 Feb 2024 18:42:20 +0000 Subject: [PATCH 40/48] specs --- test/BehaviourTree.spec.ts | 16 ++++++++-------- test/nodes/composite/Lotto.spec.ts | 4 ++-- test/nodes/composite/Parallel.spec.ts | 24 ++++++++++++------------ test/nodes/composite/Selector.spec.ts | 4 ++-- test/nodes/composite/Sequence.spec.ts | 4 ++-- test/nodes/decorator/Fail.spec.ts | 4 ++-- test/nodes/decorator/Flip.spec.ts | 4 ++-- test/nodes/decorator/Root.spec.ts | 4 ++-- test/nodes/decorator/Succeed.spec.ts | 4 ++-- test/nodes/leaf/Action.spec.ts | 4 ++-- 10 files changed, 36 insertions(+), 36 deletions(-) diff --git a/test/BehaviourTree.spec.ts b/test/BehaviourTree.spec.ts index 047582c..80f1875 100644 --- a/test/BehaviourTree.spec.ts +++ b/test/BehaviourTree.spec.ts @@ -54,7 +54,7 @@ describe("A BehaviourTree instance", () => { describe("has a 'getState' function that returns the state of the root node", () => { it("(MDSL)", () => { const definition = "root { action [getActionResult] }"; - const agent = { getActionResult: () => {} }; + const agent = { getActionResult: () => State.RUNNING }; const tree = new BehaviourTree(definition, agent); assert.strictEqual(tree.getState(), State.READY); @@ -78,7 +78,7 @@ describe("A BehaviourTree instance", () => { call: "getActionResult" } }; - const agent = { getActionResult: () => {} }; + const agent = { getActionResult: () => State.RUNNING }; const tree = new BehaviourTree(definition, agent); assert.strictEqual(tree.getState(), State.READY); @@ -98,7 +98,7 @@ describe("A BehaviourTree instance", () => { describe("has an 'isRunning' function that returns a flag defining whether the tree is in a running state", () => { it("(MDSL)", () => { const definition = "root { action [getActionResult] }"; - const agent = { getActionResult: () => {} }; + const agent = { getActionResult: () => State.RUNNING }; const tree = new BehaviourTree(definition, agent); assert.strictEqual(tree.isRunning(), false); @@ -122,7 +122,7 @@ describe("A BehaviourTree instance", () => { call: "getActionResult" } }; - const agent = { getActionResult: () => {} }; + const agent = { getActionResult: () => State.RUNNING }; const tree = new BehaviourTree(definition, agent); assert.strictEqual(tree.isRunning(), false); @@ -203,7 +203,7 @@ describe("A BehaviourTree instance", () => { const agent = { getActionResult0: () => State.SUCCEEDED, getActionResult1: () => State.SUCCEEDED, - getActionResult2: () => {}, + getActionResult2: () => State.RUNNING, getActionResult3: () => State.SUCCEEDED }; const tree = new BehaviourTree(definition, agent); @@ -229,7 +229,7 @@ describe("A BehaviourTree instance", () => { assert.strictEqual(findNode(tree, "action", "getActionResult2").state, State.SUCCEEDED); assert.strictEqual(findNode(tree, "action", "getActionResult3").state, State.SUCCEEDED); - agent.getActionResult2 = () => undefined; + agent.getActionResult2 = () => State.RUNNING; tree.step(); @@ -267,7 +267,7 @@ describe("A BehaviourTree instance", () => { const agent = { getActionResult0: () => State.SUCCEEDED, getActionResult1: () => State.SUCCEEDED, - getActionResult2: () => {}, + getActionResult2: () => State.RUNNING, getActionResult3: () => State.SUCCEEDED }; const tree = new BehaviourTree(definition, agent); @@ -293,7 +293,7 @@ describe("A BehaviourTree instance", () => { assert.strictEqual(findNode(tree, "action", "getActionResult2").state, State.SUCCEEDED); assert.strictEqual(findNode(tree, "action", "getActionResult3").state, State.SUCCEEDED); - agent.getActionResult2 = () => undefined; + agent.getActionResult2 = () => State.RUNNING; tree.step(); diff --git a/test/nodes/composite/Lotto.spec.ts b/test/nodes/composite/Lotto.spec.ts index 455e01e..1c4d400 100644 --- a/test/nodes/composite/Lotto.spec.ts +++ b/test/nodes/composite/Lotto.spec.ts @@ -421,7 +421,7 @@ describe("A Lotto node", () => { describe("move to the RUNNING state if the selected child node is in the RUNNING state", () => { it("(MDSL)", () => { const definition = "root { lotto { action [someAction] } }"; - const agent = { someAction: () => {} }; + const agent = { someAction: () => State.RUNNING }; const tree = new BehaviourTree(definition, agent); let lottoNode = findNode(tree, "lotto"); @@ -450,7 +450,7 @@ describe("A Lotto node", () => { ] } }; - const agent = { someAction: () => {} }; + const agent = { someAction: () => State.RUNNING }; const tree = new BehaviourTree(definition, agent); let lottoNode = findNode(tree, "lotto"); diff --git a/test/nodes/composite/Parallel.spec.ts b/test/nodes/composite/Parallel.spec.ts index 83854fc..525cf24 100644 --- a/test/nodes/composite/Parallel.spec.ts +++ b/test/nodes/composite/Parallel.spec.ts @@ -39,8 +39,8 @@ describe("A Parallel node", () => { it("(MDSL)", () => { const definition = "root { parallel { action [actionRunning1] action [actionRunning2] } }"; const agent = { - actionRunning1: () => {}, - actionRunning2: () => {} + actionRunning1: () => State.RUNNING, + actionRunning2: () => State.RUNNING }; const tree = new BehaviourTree(definition, agent); @@ -75,8 +75,8 @@ describe("A Parallel node", () => { } }; const agent = { - actionRunning1: () => {}, - actionRunning2: () => {} + actionRunning1: () => State.RUNNING, + actionRunning2: () => State.RUNNING }; const tree = new BehaviourTree(definition, agent); @@ -98,8 +98,8 @@ describe("A Parallel node", () => { it("(MDSL)", () => { const definition = "root { parallel { action [action1] action [action2] } }"; const agent = { - action1: () => {}, - action2: () => {} + action1: () => State.RUNNING, + action2: () => State.RUNNING }; const tree = new BehaviourTree(definition, agent); @@ -143,8 +143,8 @@ describe("A Parallel node", () => { } }; const agent = { - action1: () => {}, - action2: () => {} + action1: () => State.RUNNING, + action2: () => State.RUNNING }; const tree = new BehaviourTree(definition, agent); @@ -175,8 +175,8 @@ describe("A Parallel node", () => { it("(MDSL)", () => { const definition = "root { parallel { action [action1] action [action2] } }"; const agent = { - action1: () => {}, - action2: () => {} + action1: () => State.RUNNING, + action2: () => State.RUNNING }; const tree = new BehaviourTree(definition, agent); @@ -229,8 +229,8 @@ describe("A Parallel node", () => { } }; const agent = { - action1: () => {}, - action2: () => {} + action1: () => State.RUNNING, + action2: () => State.RUNNING }; const tree = new BehaviourTree(definition, agent); diff --git a/test/nodes/composite/Selector.spec.ts b/test/nodes/composite/Selector.spec.ts index 016ed02..ab80bd3 100644 --- a/test/nodes/composite/Selector.spec.ts +++ b/test/nodes/composite/Selector.spec.ts @@ -170,7 +170,7 @@ describe("A Selector node", () => { "root { selector { action [actionFail] action [actionRunning] action [actionSucceed] } }"; const agent = { actionSucceed: () => State.SUCCEEDED, - actionRunning: () => {}, + actionRunning: () => State.RUNNING, actionFail: () => State.FAILED }; const tree = new BehaviourTree(definition, agent); @@ -213,7 +213,7 @@ describe("A Selector node", () => { }; const agent = { actionSucceed: () => State.SUCCEEDED, - actionRunning: () => {}, + actionRunning: () => State.RUNNING, actionFail: () => State.FAILED }; const tree = new BehaviourTree(definition, agent); diff --git a/test/nodes/composite/Sequence.spec.ts b/test/nodes/composite/Sequence.spec.ts index f7672db..dd6a1b0 100644 --- a/test/nodes/composite/Sequence.spec.ts +++ b/test/nodes/composite/Sequence.spec.ts @@ -159,7 +159,7 @@ describe("A Sequence node", () => { "root { sequence { action [actionSucceed] action [actionRunning] action [actionFail] } }"; const agent = { actionSucceed: () => State.SUCCEEDED, - actionRunning: () => {}, + actionRunning: () => State.RUNNING, actionFail: () => State.FAILED }; const tree = new BehaviourTree(definition, agent); @@ -202,7 +202,7 @@ describe("A Sequence node", () => { }; const agent = { actionSucceed: () => State.SUCCEEDED, - actionRunning: () => {}, + actionRunning: () => State.RUNNING, actionFail: () => State.FAILED }; const tree = new BehaviourTree(definition, agent); diff --git a/test/nodes/decorator/Fail.spec.ts b/test/nodes/decorator/Fail.spec.ts index 673101e..be16190 100644 --- a/test/nodes/decorator/Fail.spec.ts +++ b/test/nodes/decorator/Fail.spec.ts @@ -118,7 +118,7 @@ describe("A Fail node", () => { describe("move to the RUNNING state if the child node moves to the RUNNING state", () => { it("(MDSL)", () => { const definition = "root { fail { action [someAction] } }"; - const agent = { someAction: () => {} }; + const agent = { someAction: () => State.RUNNING }; const tree = new BehaviourTree(definition, agent); let node = findNode(tree, "fail", "FAIL"); @@ -141,7 +141,7 @@ describe("A Fail node", () => { } } }; - const agent = { someAction: () => {} }; + const agent = { someAction: () => State.RUNNING }; const tree = new BehaviourTree(definition, agent); let node = findNode(tree, "fail", "FAIL"); diff --git a/test/nodes/decorator/Flip.spec.ts b/test/nodes/decorator/Flip.spec.ts index d59f0e4..9309b24 100644 --- a/test/nodes/decorator/Flip.spec.ts +++ b/test/nodes/decorator/Flip.spec.ts @@ -116,7 +116,7 @@ describe("A Flip node", () => { describe("move to the RUNNING state if the child node does not move to the SUCCESS or FAILED state", () => { it("(MDSL)", () => { const definition = "root { flip { action [someAction] } }"; - const agent = { someAction: () => {} }; + const agent = { someAction: () => State.RUNNING }; const tree = new BehaviourTree(definition, agent); let node = findNode(tree, "flip", "FLIP"); @@ -139,7 +139,7 @@ describe("A Flip node", () => { } } }; - const agent = { someAction: () => {} }; + const agent = { someAction: () => State.RUNNING }; const tree = new BehaviourTree(definition, agent); let node = findNode(tree, "flip", "FLIP"); diff --git a/test/nodes/decorator/Root.spec.ts b/test/nodes/decorator/Root.spec.ts index 4a50959..a224197 100644 --- a/test/nodes/decorator/Root.spec.ts +++ b/test/nodes/decorator/Root.spec.ts @@ -99,7 +99,7 @@ describe("A Root node", () => { describe("move to the RUNNING state if the child node does not move to the SUCCESS or FAILED state", () => { it("(MDSL)", () => { const definition = "root { action [someAction] }"; - const agent = { someAction: () => {} }; + const agent = { someAction: () => State.RUNNING }; const tree = new BehaviourTree(definition, agent); assert.strictEqual(findNode(tree, "root").state, State.READY); @@ -117,7 +117,7 @@ describe("A Root node", () => { call: "someAction" } }; - const agent = { someAction: () => {} }; + const agent = { someAction: () => State.RUNNING }; const tree = new BehaviourTree(definition, agent); assert.strictEqual(findNode(tree, "root").state, State.READY); diff --git a/test/nodes/decorator/Succeed.spec.ts b/test/nodes/decorator/Succeed.spec.ts index 65cb922..0b6b4e9 100644 --- a/test/nodes/decorator/Succeed.spec.ts +++ b/test/nodes/decorator/Succeed.spec.ts @@ -118,7 +118,7 @@ describe("A Succeed node", () => { describe("move to the RUNNING state if the child node moves to the RUNNING state", () => { it("(MDSL)", () => { const definition = "root { succeed { action [someAction] } }"; - const agent = { someAction: () => {} }; + const agent = { someAction: () => State.RUNNING }; const tree = new BehaviourTree(definition, agent); let node = findNode(tree, "succeed", "SUCCEED"); @@ -141,7 +141,7 @@ describe("A Succeed node", () => { } } }; - const agent = { someAction: () => {} }; + const agent = { someAction: () => State.RUNNING }; const tree = new BehaviourTree(definition, agent); let node = findNode(tree, "succeed", "SUCCEED"); diff --git a/test/nodes/leaf/Action.spec.ts b/test/nodes/leaf/Action.spec.ts index 84dedd1..e0754a3 100644 --- a/test/nodes/leaf/Action.spec.ts +++ b/test/nodes/leaf/Action.spec.ts @@ -393,7 +393,7 @@ describe("An Action node", () => { describe("the function returns undefined", () => { it("(MDSL)", () => { const definition = "root { action [doAction] }"; - const agent = { doAction: () => {} }; + const agent = { doAction: () => State.RUNNING }; const tree = new BehaviourTree(definition, agent); let node = findNode(tree, "action", "doAction"); @@ -413,7 +413,7 @@ describe("An Action node", () => { call: "doAction" } }; - const agent = { doAction: () => {} }; + const agent = { doAction: () => State.RUNNING }; const tree = new BehaviourTree(definition, agent); let node = findNode(tree, "action", "doAction"); From dc312de8d740bf37a686123c80135cb38c5789b8 Mon Sep 17 00:00:00 2001 From: Nikolas Howard Date: Wed, 28 Feb 2024 13:41:48 +0000 Subject: [PATCH 41/48] Added Exit specs and fixed exit details arg --- dist/bundle.js | 2 +- dist/bundle.js.map | 4 +- dist/index.js | 2 +- dist/index.js.map | 4 +- src/attributes/callbacks/Exit.ts | 2 +- test/attributes/callbacks/Entry.spec.ts | 6 +- test/attributes/callbacks/Exit.spec.ts | 234 +++++++++++++++++++++++- 7 files changed, 243 insertions(+), 11 deletions(-) diff --git a/dist/bundle.js b/dist/bundle.js index f286b8b..c954fdc 100644 --- a/dist/bundle.js +++ b/dist/bundle.js @@ -2041,7 +2041,7 @@ var mistreevous = (() => { `cannot call exit function '${this.getFunctionName()}' as is not defined on the agent and has not been registered` ); } - callbackFuncInvoker([{ value: { succeeded: isSuccess, aborted: isAborted } }, ...this.args]); + callbackFuncInvoker([{ succeeded: isSuccess, aborted: isAborted }, ...this.args]); }; }; diff --git a/dist/bundle.js.map b/dist/bundle.js.map index 639768a..57837ad 100644 --- a/dist/bundle.js.map +++ b/dist/bundle.js.map @@ -1,7 +1,7 @@ { "version": 3, "sources": ["../node_modules/lotto-draw/dist/Participant.js", "../node_modules/lotto-draw/dist/Utilities.js", "../node_modules/lotto-draw/dist/Lotto.js", "../node_modules/lotto-draw/dist/createLotto.js", "../node_modules/lotto-draw/dist/index.js", "../src/index.ts", "../src/State.ts", "../src/BehaviourTreeDefinitionUtilities.ts", "../src/mdsl/MDSLUtilities.ts", "../src/mdsl/MDSLNodeArgumentParser.ts", "../src/mdsl/MDSLNodeAttributeParser.ts", "../src/mdsl/MDSLDefinitionParser.ts", "../src/BehaviourTreeDefinitionValidator.ts", "../src/Lookup.ts", "../src/attributes/guards/GuardUnsatisifedException.ts", "../src/attributes/guards/GuardPath.ts", "../src/nodes/Node.ts", "../src/nodes/composite/Composite.ts", "../src/nodes/composite/Parallel.ts", "../src/nodes/composite/Selector.ts", "../src/nodes/composite/Sequence.ts", "../src/nodes/composite/Lotto.ts", "../src/nodes/decorator/Decorator.ts", "../src/nodes/decorator/Fail.ts", "../src/nodes/decorator/Flip.ts", "../src/nodes/decorator/Repeat.ts", "../src/nodes/decorator/Retry.ts", "../src/nodes/decorator/Root.ts", "../src/nodes/decorator/Succeed.ts", "../src/nodes/leaf/Leaf.ts", "../src/nodes/leaf/Action.ts", "../src/nodes/leaf/Condition.ts", "../src/nodes/leaf/Wait.ts", "../src/attributes/Attribute.ts", "../src/attributes/guards/Guard.ts", "../src/attributes/guards/While.ts", "../src/attributes/guards/Until.ts", "../src/attributes/callbacks/Callback.ts", "../src/attributes/callbacks/Entry.ts", "../src/attributes/callbacks/Step.ts", "../src/attributes/callbacks/Exit.ts", "../src/BehaviourTreeBuilder.ts", "../src/BehaviourTree.ts"], - "sourcesContent": ["\"use strict\";\r\nObject.defineProperty(exports, \"__esModule\", { value: true });\r\nexports.Participant = void 0;\r\n/**\r\n * A participant that holds a number of tickets.\r\n */\r\nvar Participant = /** @class */ (function () {\r\n /**\r\n * Creates an instance of the Participant class.\r\n * @param participant The actual participant.\r\n * @param tickets The number of tickets held by the participant.\r\n */\r\n function Participant(participant, tickets) {\r\n if (tickets === void 0) { tickets = 1; }\r\n this._participant = participant;\r\n this._tickets = tickets;\r\n }\r\n Object.defineProperty(Participant.prototype, \"participant\", {\r\n /** Gets the actual participant. */\r\n get: function () {\r\n return this._participant;\r\n },\r\n enumerable: false,\r\n configurable: true\r\n });\r\n Object.defineProperty(Participant.prototype, \"tickets\", {\r\n /** Gets or sets the number of tickets held by the participant. */\r\n get: function () {\r\n return this._tickets;\r\n },\r\n set: function (value) {\r\n this._tickets = value;\r\n },\r\n enumerable: false,\r\n configurable: true\r\n });\r\n return Participant;\r\n}());\r\nexports.Participant = Participant;\r\n", "\"use strict\";\r\nObject.defineProperty(exports, \"__esModule\", { value: true });\r\nexports.isNaturalNumber = exports.isNullOrUndefined = void 0;\r\n/**\r\n * Gets whether the value provided is null or undefined.\r\n * @param value The value to check.\r\n * @returns Whether the value provided is null or undefined.\r\n */\r\nfunction isNullOrUndefined(value) {\r\n return value === null || value === undefined;\r\n}\r\nexports.isNullOrUndefined = isNullOrUndefined;\r\n/**\r\n * Gets whether the value provided is a natural number.\r\n * @param value The value to check.\r\n * @returns Whether the value provided is a natural number.\r\n */\r\nfunction isNaturalNumber(value) {\r\n return typeof value === \"number\" && value >= 1 && Math.floor(value) === value;\r\n}\r\nexports.isNaturalNumber = isNaturalNumber;\r\n", "\"use strict\";\r\nObject.defineProperty(exports, \"__esModule\", { value: true });\r\nexports.Lotto = void 0;\r\nvar Participant_1 = require(\"./Participant\");\r\nvar Utilities_1 = require(\"./Utilities\");\r\n/**\r\n * Represents a lotto consisting of a number of pickable ticket-holding participants.\r\n */\r\nvar Lotto = /** @class */ (function () {\r\n /**\r\n * Creates a new instance of Lotto.\r\n * @param customRandom The custom RNG to use in place of Math.random().\r\n */\r\n function Lotto(customRandom) {\r\n /** The array of participants that are holding tickets in the lotto. */\r\n this._participants = [];\r\n this._customRandom = customRandom;\r\n }\r\n /**\r\n * Adds a participant with the specified number of tickets, or adds to the participant ticket count if the participant already holds tickets.\r\n * @param participant The participant to add or to increase the ticket count for if they already hold tickets.\r\n * @param tickets The number of tickets, defaults to 1.\r\n * @returns The Lotto instance.\r\n */\r\n Lotto.prototype.add = function (participant, tickets) {\r\n if (tickets === void 0) { tickets = 1; }\r\n // Check that we have a valid ticket count.\r\n if (!(0, Utilities_1.isNaturalNumber)(tickets)) {\r\n throw new Error(\"tickets value must be a natural number\");\r\n }\r\n // Check whether this participant has already been added.\r\n var existingParticipant = this._participants.find(function (part) { return part.participant === participant; });\r\n if (existingParticipant) {\r\n // The participant has already been added to the lotto so just add to their ticket count.\r\n existingParticipant.tickets += tickets;\r\n }\r\n else {\r\n // The participant is not part of the lotto so we should add them.\r\n this._participants.push(new Participant_1.Participant(participant, tickets));\r\n }\r\n return this;\r\n };\r\n /**\r\n * Removes the specified number of tickets for the given participant from the draw, or all tickets if a ticket number is not defined.\r\n * @param participant The participant to remove tickets for.\r\n * @param tickets The number of tickets to remove, or undefined if all tickets are to be removed.\r\n * @returns The Lotto instance.\r\n */\r\n Lotto.prototype.remove = function (participant, tickets) {\r\n // Attempt to get the existing participant.\r\n var existingParticipant = this._participants.find(function (part) { return part.participant === participant; });\r\n // There is nothing to do if the specified participant isn't even part of the lotto.\r\n if (!existingParticipant) {\r\n return this;\r\n }\r\n // Check whether a tickets value was given.\r\n if (tickets !== undefined) {\r\n // Check that we have a valid ticket count.\r\n if (!(0, Utilities_1.isNaturalNumber)(tickets)) {\r\n throw new Error(\"tickets value must be a natural number\");\r\n }\r\n existingParticipant.tickets -= tickets;\r\n // If the participant no longer holds any tickets then they should be removed.\r\n if (existingParticipant.tickets < 1) {\r\n this._participants = this._participants.filter(function (part) { return part !== existingParticipant; });\r\n }\r\n }\r\n else {\r\n // We are removing all tickets for the participant so just remove them from the lotto.\r\n this._participants = this._participants.filter(function (part) { return part !== existingParticipant; });\r\n }\r\n return this;\r\n };\r\n /**\r\n * Draw a winning ticket and return the participant that holds the ticket.\r\n * @param options The draw options.\r\n * @returns The participant that holds the winning ticket.\r\n */\r\n Lotto.prototype.draw = function (options) {\r\n if (options === void 0) { options = {}; }\r\n // If we have no participants then just return null.\r\n if (this._participants.length === 0) {\r\n return null;\r\n }\r\n var redrawable = (0, Utilities_1.isNullOrUndefined)(options.redrawable) ? true : options.redrawable;\r\n var pickable = [];\r\n this._participants.forEach(function (_a) {\r\n var participant = _a.participant, tickets = _a.tickets;\r\n for (var ticketCount = 0; ticketCount < tickets; ticketCount++) {\r\n pickable.push(participant);\r\n }\r\n });\r\n var random;\r\n // We need a random floating-point number between 0 (inclusive) and 1 to scale up to pick our winner.\r\n // If a custom random function exists then we should use that or fall back to Math.random().\r\n if (this._customRandom) {\r\n // Call our custom random function to get a random floating-point number.\r\n random = this._customRandom();\r\n // Verify that the result of calling our custom random function is a number between 0 (inclusive) and 1.\r\n if (typeof random !== \"number\" || random < 0 || random >= 1) {\r\n throw new Error(\"the 'random' function provided did not return a number between 0 (inclusive) and 1\");\r\n }\r\n }\r\n else {\r\n // No custom random function was defined so just use good ol' Math.random().\r\n random = Math.random();\r\n }\r\n // Pick a winning participant.\r\n var winner = pickable[Math.floor(random * pickable.length)];\r\n // If the ticket isn't redrawable then we should remove a ticket from the winning participants ticket count.\r\n if (!redrawable) {\r\n this.remove(winner, 1);\r\n }\r\n // Return the winning participant.\r\n return winner;\r\n };\r\n /**\r\n * Draws multiple winning tickets and return an array of the participants that hold the winning tickets.\r\n * @param tickets The number of winning tickets to draw.\r\n * @param options The draw multiple options.\r\n * @returns An array of the participants that hold the winning tickets.\r\n */\r\n Lotto.prototype.drawMultiple = function (tickets, options) {\r\n if (options === void 0) { options = {}; }\r\n var uniqueResults = (0, Utilities_1.isNullOrUndefined)(options.unique) ? false : options.unique;\r\n // Handle cases where the user has asked for zero tickets (no idea why they would do this be we should trust them).\r\n if (tickets === 0) {\r\n return [];\r\n }\r\n // Now that we know out tickets value is not zero we should check that it is a valid natural number.\r\n if (!(0, Utilities_1.isNaturalNumber)(tickets)) {\r\n throw new Error(\"tickets value must be a natural number\");\r\n }\r\n var result = [];\r\n // Keep drawing tickets until we either reach the number of required tickets or we simply run out of tickets to draw.\r\n // We can run out of tickets to draw if 'options.redrawable' is explicity 'false' or we just had no participants when 'drawMultiple' was called.\r\n while (result.length < tickets && this._participants.length > 0) {\r\n result.push(this.draw(options));\r\n }\r\n // If the 'unique' draw option is set then we need to remove duplicates from the result list.\r\n if (uniqueResults) {\r\n // Create an array to store our unique results.\r\n var unique = [];\r\n // Iterate over all of our participants (with potential duplicates) and populate our array of unique values.\r\n for (var _i = 0, result_1 = result; _i < result_1.length; _i++) {\r\n var participant = result_1[_i];\r\n if (unique.indexOf(participant) === -1) {\r\n unique.push(participant);\r\n }\r\n }\r\n result = unique;\r\n }\r\n return result;\r\n };\r\n return Lotto;\r\n}());\r\nexports.Lotto = Lotto;\r\n", "\"use strict\";\r\nObject.defineProperty(exports, \"__esModule\", { value: true });\r\nexports.createLotto = void 0;\r\nvar Lotto_1 = require(\"./Lotto\");\r\n/**\r\n * A function that creates and returns a Lotto instance.\r\n * @param participantsOrOptions An array of initial participants or options relating to the creation of a Lotto instance.\r\n * @returns A new Lotto instance.\r\n */\r\nfunction createLotto(participantsOrOptions) {\r\n // If no initial participants or lotto options were provided as an argument then we can just return a new lotto instance now.\r\n if (!participantsOrOptions) {\r\n return new Lotto_1.Lotto();\r\n }\r\n // Check whether we were provided with an array of initial participants or a lotto options object.\r\n if (Array.isArray(participantsOrOptions)) {\r\n // We are dealing with a pre-defined array of participants.\r\n var participants = participantsOrOptions;\r\n var lotto_1 = new Lotto_1.Lotto();\r\n // If the lotto participants have been defined upfront then we will need to add them all to our lotto instance now.\r\n participants.forEach(function (_a) {\r\n var participant = _a[0], tokens = _a[1];\r\n return lotto_1.add(participant, tokens);\r\n });\r\n // Return the Lotto instance.\r\n return lotto_1;\r\n }\r\n else {\r\n // We are dealing with some lotto options.\r\n var random = participantsOrOptions.random, participants = participantsOrOptions.participants;\r\n // Create a Lotto instance passing the custom RNG function to use in place of Math.random() (which could be undefined).\r\n var lotto_2 = new Lotto_1.Lotto(random);\r\n // If the lotto participants have been defined upfront as part of the options then we will need to add them all to our lotto instance now.\r\n if (participants) {\r\n participants.forEach(function (_a) {\r\n var participant = _a[0], tokens = _a[1];\r\n return lotto_2.add(participant, tokens);\r\n });\r\n }\r\n // Return the Lotto instance.\r\n return lotto_2;\r\n }\r\n}\r\nexports.createLotto = createLotto;\r\n", "\"use strict\";\r\nObject.defineProperty(exports, \"__esModule\", { value: true });\r\nvar createLotto_1 = require(\"./createLotto\");\r\nexports.default = createLotto_1.createLotto;\r\n", "import State from \"./State\";\nimport { validateDefinition } from \"./BehaviourTreeDefinitionValidator\";\nimport { convertMDSLToJSON } from \"./mdsl/MDSLDefinitionParser\";\nimport { BehaviourTree, FlattenedTreeNode } from \"./BehaviourTree\";\nimport { BehaviourTreeOptions } from \"./BehaviourTreeOptions\";\n\nexport { BehaviourTree, State, convertMDSLToJSON, validateDefinition };\nexport type { FlattenedTreeNode, BehaviourTreeOptions };\n", "/**\n * Enumeration of node state types.\n */\nexport enum State {\n READY = \"mistreevous.ready\",\n RUNNING = \"mistreevous.running\",\n SUCCEEDED = \"mistreevous.succeeded\",\n FAILED = \"mistreevous.failed\"\n}\n\nexport { State as default };\n\nexport type CompleteState = State.SUCCEEDED | State.FAILED;\nexport type AnyState = State.READY | State.RUNNING | CompleteState;\n", "import {\n NodeDefinition,\n RootNodeDefinition,\n DecoratorNodeDefinition,\n CompositeNodeDefinition,\n AnyNodeDefinition,\n BranchNodeDefinition\n} from \"./BehaviourTreeDefinition\";\n\n/**\n * A type guard function that returns true if the specified node satisfies the RootNodeDefinition type.\n * @param node The node.\n * @returns A value of true if the specified node satisfies the RootNodeDefinition type.\n */\nexport function isRootNode(node: NodeDefinition): node is RootNodeDefinition {\n return node.type === \"root\";\n}\n\n/**\n * A type guard function that returns true if the specified node satisfies the BranchNodeDefinition type.\n * @param node The node.\n * @returns A value of true if the specified node satisfies the BranchNodeDefinition type.\n */\nexport function isBranchNode(node: NodeDefinition): node is BranchNodeDefinition {\n return node.type === \"branch\";\n}\n\n/**\n * A type guard function that returns true if the specified node satisfies the NodeDefinition type.\n * @param node The node.\n * @returns A value of true if the specified node satisfies the NodeDefinition type.\n */\nexport function isLeafNode(node: NodeDefinition): node is NodeDefinition {\n return [\"branch\", \"action\", \"condition\", \"wait\"].includes(node.type);\n}\n\n/**\n * A type guard function that returns true if the specified node satisfies the DecoratorNodeDefinition type.\n * @param node The node.\n * @returns A value of true if the specified node satisfies the DecoratorNodeDefinition type.\n */\nexport function isDecoratorNode(node: NodeDefinition): node is DecoratorNodeDefinition {\n return [\"root\", \"repeat\", \"retry\", \"flip\", \"succeed\", \"fail\"].includes(node.type);\n}\n\n/**\n * A type guard function that returns true if the specified node satisfies the CompositeNodeDefinition type.\n * @param node The node.\n * @returns A value of true if the specified node satisfies the CompositeNodeDefinition type.\n */\nexport function isCompositeNode(node: NodeDefinition): node is CompositeNodeDefinition {\n return [\"sequence\", \"selector\", \"lotto\", \"parallel\"].includes(node.type);\n}\n\n/**\n * Flatten a node definition into an array of all of its nested node definitions.\n * @param nodeDefinition The node definition to flatten.\n * @returns An array of all of nested node definitions.\n */\nexport function flattenDefinition(nodeDefinition: AnyNodeDefinition): AnyNodeDefinition[] {\n const nodes: AnyNodeDefinition[] = [];\n\n const processNode = (currentNodeDefinition: AnyNodeDefinition) => {\n nodes.push(currentNodeDefinition);\n\n if (isCompositeNode(currentNodeDefinition)) {\n currentNodeDefinition.children.forEach(processNode);\n } else if (isDecoratorNode(currentNodeDefinition)) {\n processNode(currentNodeDefinition.child);\n }\n };\n\n processNode(nodeDefinition);\n\n return nodes;\n}\n\n/**\n * Determines whether the passed value is an integer.\n * @param value The value to check.\n * @returns Whether the passed value is an integer.\n */\nexport function isInteger(value: unknown): boolean {\n return typeof value === \"number\" && Math.floor(value) === value;\n}\n\n/**\n * Determines whether the passed value is null or undefined.\n * @param value The value to check.\n * @returns Whether the passed value is null or undefined.\n */\nexport function isNullOrUndefined(value: unknown): boolean {\n return typeof value === \"undefined\" || value === null;\n}\n", "/**\n * A type defining an object that holds a reference to substitued string literals parsed from the definition.\n */\nexport type StringLiteralPlaceholders = { [key: string]: string };\n\n/**\n * Pop the next raw token from the specified array of tokens and throw an error if it wasn't the expected one.\n * @param tokens The array of tokens.\n * @param expected An optional string or array or items, one of which must match the next popped token.\n * @returns The popped token.\n */\nexport function popAndCheck(tokens: string[], expected?: string | string[]): string {\n // Get and remove the next token.\n const popped = tokens.shift();\n\n // We were expecting another token but there aren't any.\n if (popped === undefined) {\n throw new Error(\"unexpected end of definition\");\n }\n\n // Do we have an expected token/tokens array?\n if (expected != undefined) {\n // Get an array of expected values, if the popped token matches any then we are all good.\n const expectedValues = typeof expected === \"string\" ? [expected] : expected;\n\n // Check whether the popped token matches at least one of our expected items.\n var tokenMatchesExpectation = expectedValues.some((item) => popped.toUpperCase() === item.toUpperCase());\n\n // Throw an error if the popped token didn't match any of our expected items.\n if (!tokenMatchesExpectation) {\n const expectationString = expectedValues.map((item) => \"'\" + item + \"'\").join(\" or \");\n throw new Error(\"unexpected token found. Expected \" + expectationString + \" but got '\" + popped + \"'\");\n }\n }\n\n // Return the popped token.\n return popped;\n}\n\n/**\n * Swaps out any node/attribute argument string literals with placeholders.\n * @param definition The definition.\n * @returns An object containing a mapping of placeholders to original string values as well as the processed definition string.\n */\nexport function substituteStringLiterals(definition: string): {\n placeholders: StringLiteralPlaceholders;\n processedDefinition: string;\n} {\n // Create an object to hold the mapping of placeholders to original string values.\n const placeholders: StringLiteralPlaceholders = {};\n\n // Replace any string literals wrapped with double quotes in our definition with placeholders to be processed later.\n const processedDefinition = definition.replace(/\\\"(\\\\.|[^\"\\\\])*\\\"/g, (match) => {\n var strippedMatch = match.substring(1, match.length - 1);\n var placeholder = Object.keys(placeholders).find((key) => placeholders[key] === strippedMatch);\n\n // If we have no existing string literal match then create a new placeholder.\n if (!placeholder) {\n placeholder = `@@${Object.keys(placeholders).length}@@`;\n placeholders[placeholder] = strippedMatch;\n }\n\n return placeholder;\n });\n\n return { placeholders, processedDefinition };\n}\n\n/**\n * Parse the tree definition into an array of raw tokens.\n * @param definition The definition.\n * @returns An array of tokens parsed from the definition.\n */\nexport function parseTokensFromDefinition(definition: string): string[] {\n // Add some space around various important characters so that they can be plucked out easier as individual tokens.\n definition = definition.replace(/\\(/g, \" ( \");\n definition = definition.replace(/\\)/g, \" ) \");\n definition = definition.replace(/\\{/g, \" { \");\n definition = definition.replace(/\\}/g, \" } \");\n definition = definition.replace(/\\]/g, \" ] \");\n definition = definition.replace(/\\[/g, \" [ \");\n definition = definition.replace(/\\,/g, \" , \");\n\n // Split the definition into raw token form and return it.\n return definition.replace(/\\s+/g, \" \").trim().split(\" \");\n}\n", "import { StringLiteralPlaceholders, popAndCheck } from \"./MDSLUtilities\";\n\n/**\n * A type representing any node function argument.\n */\ntype Argument = {\n /**\n * The argument value.\n */\n value: T;\n /**\n * The argument type, used for validation.\n */\n type: string;\n};\n\ntype NullArgument = Argument & {\n type: \"null\";\n};\n\ntype BooleanArgument = Argument & {\n type: \"boolean\";\n};\n\ntype NumberArgument = Argument & {\n type: \"number\";\n /**\n * A flag defining whether the number argument value is a valid integer. (used for validation)\n */\n isInteger: boolean;\n};\n\ntype StringPlaceholderArgument = Argument & {\n type: \"string\";\n};\n\ntype IdentifierArgument = Argument & {\n type: \"identifier\";\n};\n\n/**\n * A type representing a reference to any node function argument.\n */\ntype AnyArgument = NullArgument | BooleanArgument | NumberArgument | StringPlaceholderArgument | IdentifierArgument;\n\n/**\n * Parse an array of argument definitions from the specified tokens array.\n * @param tokens The array tokens to parse the argument definitions from.\n * @param stringArgumentPlaceholders The mapping of string literal node argument placeholders to original values.\n * @param argumentValidator The argument validator function.\n * @param validationFailedMessage The exception message to throw if argument validation fails.\n * @returns An array of argument definitions parsed from the specified tokens array.\n */\nexport function parseArgumentTokens(\n tokens: string[],\n stringArgumentPlaceholders: StringLiteralPlaceholders\n): AnyArgument[] {\n const argumentList: AnyArgument[] = [];\n\n // If the next token is not a '[' or '(' then we have no arguments to parse.\n if (![\"[\", \"(\"].includes(tokens[0])) {\n return argumentList;\n }\n\n // Any lists of arguments will always be wrapped in '[]' for node arguments or '()' for attribute arguments.\n // We are looking for a '[' or '(' opener that wraps the argument tokens and the relevant closer.\n const closingToken = popAndCheck(tokens, [\"[\", \"(\"]) === \"[\" ? \"]\" : \")\";\n\n const argumentListTokens: string[] = [];\n\n // Grab all tokens between the '[' and ']' or '(' and ')'.\n while (tokens.length && tokens[0] !== closingToken) {\n // The next token is part of our arguments list.\n argumentListTokens.push(tokens.shift()!);\n }\n\n // Validate the order of the argument tokens. Each token must either be a ',' or a single argument that satisfies the validator.\n argumentListTokens.forEach((token, index) => {\n // Get whether this token should be an actual argument.\n const shouldBeArgumentToken = !(index & 1);\n\n // If the current token should be an actual argument then validate it, otherwise it should be a ',' token.\n if (shouldBeArgumentToken) {\n // Get the argument definition.\n const argumentDefinition = getArgumentDefinition(token, stringArgumentPlaceholders);\n\n // This is a valid argument!\n argumentList.push(argumentDefinition);\n } else {\n // The current token should be a ',' token.\n if (token !== \",\") {\n throw new Error(`invalid argument list, expected ',' or ']' but got '${token}'`);\n }\n }\n });\n\n // The arguments list should terminate with a ']' or ')' token, depending on the opener.\n popAndCheck(tokens, closingToken);\n\n // Return the arguments.\n return argumentList;\n}\n\n/**\n * Gets an argument value definition.\n * @param token The argument token.\n * @param stringArgumentPlaceholders The mapping of string literal node argument placeholders to original values.\n * @returns An argument value definition.\n */\nfunction getArgumentDefinition(token: string, stringArgumentPlaceholders: StringLiteralPlaceholders): AnyArgument {\n // Check whether the token represents a null value.\n if (token === \"null\") {\n return {\n value: null,\n type: \"null\"\n } as NullArgument;\n }\n\n // Check whether the token represents a boolean value.\n if (token === \"true\" || token === \"false\") {\n return {\n value: token === \"true\",\n type: \"boolean\"\n } as BooleanArgument;\n }\n\n // Check whether the token represents a number value.\n // TODO: Relies on broken isNaN - see MDN.\n // if (!Number.isNaN(token)) {\n if (!isNaN(token as any)) {\n return {\n value: parseFloat(token),\n isInteger: parseFloat(token) === parseInt(token, 10),\n type: \"number\"\n } as NumberArgument;\n }\n\n // Check whether the token is a placeholder (e.g. @@0@@) representing a string literal.\n if (token.match(/^@@\\d+@@$/g)) {\n return {\n value: stringArgumentPlaceholders[token].replace('\\\\\"', '\"'),\n type: \"string\"\n } as StringPlaceholderArgument;\n }\n\n // The only remaining option is that the argument value is an identifier.\n return {\n value: token,\n type: \"identifier\"\n } as IdentifierArgument;\n}\n", "import { NodeAttributeDefinition } from \"../BehaviourTreeDefinition\";\nimport { parseArgumentTokens } from \"./MDSLNodeArgumentParser\";\nimport { StringLiteralPlaceholders } from \"./MDSLUtilities\";\n\n/**\n * A type defining the attribute definitions of a node.\n */\ntype NodeAttributes = {\n while?: NodeAttributeDefinition;\n until?: NodeAttributeDefinition;\n entry?: NodeAttributeDefinition;\n exit?: NodeAttributeDefinition;\n step?: NodeAttributeDefinition;\n};\n\n/**\n * Parse any node attribute definitions from the specified tokens array.\n * @param tokens The array of remaining tokens.\n * @param stringArgumentPlaceholders The mapping of string literal node argument placeholders to original values.\n * @returns An object of attribute definitions defined by any directly following tokens.\n */\nexport function parseAttributeTokens(\n tokens: string[],\n stringArgumentPlaceholders: StringLiteralPlaceholders\n): NodeAttributes {\n const nodeAttributeNames: (keyof NodeAttributes)[] = [\"while\", \"until\", \"entry\", \"exit\", \"step\"];\n\n // Create an object to hold any attributes found.\n const attributes: NodeAttributes = {};\n\n // Try to get the name of the attribute for the next token.\n let nextAttributeName = tokens[0]?.toLowerCase() as keyof NodeAttributes;\n\n // Pull attribute tokens as well as their arguments off of the tokens stack until we have no more.\n while (nodeAttributeNames.includes(nextAttributeName)) {\n // Check to make sure that we have not already created an attribute definition of this type.\n if (attributes[nextAttributeName]) {\n throw new Error(`duplicate attribute '${tokens[0].toUpperCase()}' found for node`);\n }\n\n // Remove the attribute name token from the array of tokens.\n tokens.shift();\n\n // Grab the attribute arguments, assuming the first to be an identifier.\n const [attributeCallIdentifier, ...attributeArguments] = parseArgumentTokens(\n tokens,\n stringArgumentPlaceholders\n );\n\n // The first attribute argument has to be an identifer, this will reference an agent function.\n if (attributeCallIdentifier?.type !== \"identifier\") {\n throw new Error(\"expected agent function or registered function name identifier argument for attribute\");\n }\n\n // Any attribute arguments (other than the expected call identifier) must have a type of string, number, boolean or null.\n attributeArguments\n .filter((arg) => arg.type === \"identifier\")\n .forEach((arg) => {\n throw new Error(\n `invalid attribute argument value '${arg.value}', must be string, number, boolean or null`\n );\n });\n\n // Create the attribute definition and add it to the object of attribute definitions found.\n attributes[nextAttributeName] = {\n call: attributeCallIdentifier.value,\n args: attributeArguments.map(({ value }) => value)\n };\n\n // Try to get the next attribute name token, as there could be multiple.\n nextAttributeName = tokens[0]?.toLowerCase() as keyof NodeAttributes;\n }\n\n return attributes;\n}\n", "import {\n ActionNodeDefinition,\n AnyChildNodeDefinition,\n AnyNodeDefinition,\n BranchNodeDefinition,\n ConditionNodeDefinition,\n FailNodeDefinition,\n FlipNodeDefinition,\n LottoNodeDefinition,\n ParallelNodeDefinition,\n RepeatNodeDefinition,\n RetryNodeDefinition,\n RootNodeDefinition,\n SelectorNodeDefinition,\n SequenceNodeDefinition,\n SucceedNodeDefinition,\n WaitNodeDefinition\n} from \"../BehaviourTreeDefinition\";\nimport {\n isCompositeNode,\n isDecoratorNode,\n isLeafNode,\n isNullOrUndefined,\n isRootNode\n} from \"../BehaviourTreeDefinitionUtilities\";\nimport { parseArgumentTokens } from \"./MDSLNodeArgumentParser\";\nimport { parseAttributeTokens } from \"./MDSLNodeAttributeParser\";\nimport {\n StringLiteralPlaceholders,\n parseTokensFromDefinition,\n popAndCheck,\n substituteStringLiterals\n} from \"./MDSLUtilities\";\n\n/**\n * Convert the MDSL tree definition string into an equivalent JSON definition.\n * @param definition The tree definition string as MDSL.\n * @returns The root node JSON definitions.\n */\nexport function convertMDSLToJSON(definition: string): RootNodeDefinition[] {\n // Swap out any node/attribute argument string literals with a placeholder and get a mapping of placeholders to original values as well as the processed definition.\n const { placeholders, processedDefinition } = substituteStringLiterals(definition);\n\n // Parse our definition definition string into an array of raw tokens.\n const tokens = parseTokensFromDefinition(processedDefinition);\n\n return convertTokensToJSONDefinition(tokens, placeholders);\n}\n\n/**\n * Converts the specified tree definition tokens into a JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The root node JSON definitions.\n */\nfunction convertTokensToJSONDefinition(\n tokens: string[],\n stringLiteralPlaceholders: StringLiteralPlaceholders\n): RootNodeDefinition[] {\n // There must be at least 3 tokens for the tree definition to be valid. 'ROOT', '{' and '}'.\n if (tokens.length < 3) {\n throw new Error(\"invalid token count\");\n }\n\n // We should have a matching number of '{' and '}' tokens. If not, then there are scopes that have not been properly closed.\n if (tokens.filter((token) => token === \"{\").length !== tokens.filter((token) => token === \"}\").length) {\n throw new Error(\"scope character mismatch\");\n }\n\n // Create an array of tree stack arrays where root nodes will always be at the botton and the current composite/decorator node at the top.\n // There should be an element in this array for every root node defined and every element should be an array with a root note as the first element.\n // E.g. A definition with two root nodes defined:\n // [\n // [root, lotto, sequence],\n // [root, selector]\n // ]\n const treeStacks: [Partial, ...Partial[]][] = [];\n\n // Create an array of all root node definitions that we create.\n const rootNodes: Partial[] = [];\n\n // A helper function used to push node definitions onto the tree stack.\n const pushNode = (node: AnyNodeDefinition) => {\n // If the node is a root node then we need to create a new tree stack array with the root node at the root.\n if (isRootNode(node)) {\n // We need to double-check that this root node is not the child of another node.\n // We can do this by checking whether the top tree stack is not empty (contains an existing node)\n if (treeStacks[treeStacks.length - 1]?.length) {\n throw new Error(\"a root node cannot be the child of another node\");\n }\n\n // Add the root node definition to our array of all parsed root node definitions.\n rootNodes.push(node);\n\n // Add the root node definition to the root of a new tree stack.\n treeStacks.push([node]);\n\n return;\n }\n\n // All non-root nodes should be pushed after their root nodes so handle cases\n // where we may not have any tree stacks or our top-most tree stack is empty.\n if (!treeStacks.length || !treeStacks[treeStacks.length - 1].length) {\n throw new Error(\"expected root node at base of definition\");\n }\n\n // Get the current tree stack that we are populating.\n const topTreeStack = treeStacks[treeStacks.length - 1];\n\n // Get the top-most node in the current tree stack, this will be a composite/decorator node\n // for which we will populate its children array if composite or setting its child if a decorator.\n const topTreeStackTopNode = topTreeStack[topTreeStack.length - 1] as AnyNodeDefinition;\n\n // If the top-most node in the current root stack is a composite or decorator\n // node then the current node should be added as a child of the top-most node.\n if (isCompositeNode(topTreeStackTopNode)) {\n topTreeStackTopNode.children = topTreeStackTopNode.children || [];\n topTreeStackTopNode.children.push(node);\n } else if (isDecoratorNode(topTreeStackTopNode)) {\n // If the top node already has a child node set then throw an error as a decorator should only have a single child.\n if (topTreeStackTopNode.child) {\n throw new Error(\"a decorator node must only have a single child node\");\n }\n\n topTreeStackTopNode.child = node;\n }\n\n // If the node we are adding is also a composite or decorator node, then we should push it\n // onto the current tree stack, as subsequent nodes will be added as its child/children.\n if (!isLeafNode(node)) {\n topTreeStack.push(node);\n }\n };\n\n // A helper function used to pop the top-most node definition off of the tree stack and return it.\n const popNode = (): AnyNodeDefinition | null => {\n let poppedNode: AnyNodeDefinition | null = null;\n\n // Get the current tree stack that we are populating.\n const topTreeStack = treeStacks[treeStacks.length - 1];\n\n // Pop the top-most node in the current tree stack if there is one.\n if (topTreeStack.length) {\n poppedNode = topTreeStack.pop() as AnyNodeDefinition;\n }\n\n // We don't want any empty tree stacks in our stack of tree stacks.\n if (!topTreeStack.length) {\n treeStacks.pop();\n }\n\n return poppedNode;\n };\n\n // We should keep processing the raw tokens until we run out of them.\n while (tokens.length) {\n // Grab the next token.\n const token = tokens.shift()!;\n\n // How we create the next node depends on the current raw token value.\n switch (token.toUpperCase()) {\n case \"ROOT\": {\n pushNode(createRootNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"SUCCEED\": {\n pushNode(createSucceedNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"FAIL\": {\n pushNode(createFailNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"FLIP\": {\n pushNode(createFlipNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"REPEAT\": {\n pushNode(createRepeatNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"RETRY\": {\n pushNode(createRetryNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"SEQUENCE\": {\n pushNode(createSequenceNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"SELECTOR\": {\n pushNode(createSelectorNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"PARALLEL\": {\n pushNode(createParallelNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"LOTTO\": {\n pushNode(createLottoNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"ACTION\": {\n pushNode(createActionNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"CONDITION\": {\n pushNode(createConditionNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"WAIT\": {\n pushNode(createWaitNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"BRANCH\": {\n pushNode(createBranchNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"}\": {\n // The '}' character closes the current scope and means that we have to pop a node off of the current stack.\n const poppedNode = popNode();\n\n // Now that we have a node definition we can carry out any validation that may require the node to be fully populated.\n if (poppedNode) {\n validatePoppedNode(poppedNode);\n }\n\n break;\n }\n\n default: {\n throw new Error(`unexpected token: ${token}`);\n }\n }\n }\n\n return rootNodes as RootNodeDefinition[];\n}\n\n/**\n * Creates a root node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The root node JSON definition.\n */\nfunction createRootNode(tokens: string[], stringLiteralPlaceholders: StringLiteralPlaceholders): RootNodeDefinition {\n // Create the root node definition.\n let node = {\n type: \"root\"\n } as Partial;\n\n // Parse any node arguments, we should only have one if any which will be an identifier argument for the root identifier.\n const nodeArguments = parseArgumentTokens(tokens, stringLiteralPlaceholders);\n\n // Check whether any node arguments were defined.\n if (nodeArguments.length) {\n // We should only have one argument, if any, which will be an identifier argument for the root identifier.\n if (nodeArguments.length === 1 && nodeArguments[0].type === \"identifier\") {\n // The root node identifier will be the first and only node argument value.\n node.id = nodeArguments[0].value as string;\n } else {\n throw new Error(\"expected single root name argument\");\n }\n }\n\n // Grab any node attribute definitions and spread them into the node definition.\n node = { ...node, ...parseAttributeTokens(tokens, stringLiteralPlaceholders) };\n\n // This is a decorator node, so we expect an opening '{'.\n popAndCheck(tokens, \"{\");\n\n // Return the root node definition.\n return node as RootNodeDefinition;\n}\n\n/**\n * Creates a succeed node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The succeed node JSON definition.\n */\nfunction createSucceedNode(\n tokens: string[],\n stringLiteralPlaceholders: StringLiteralPlaceholders\n): SucceedNodeDefinition {\n const node = {\n type: \"succeed\",\n ...parseAttributeTokens(tokens, stringLiteralPlaceholders)\n } as SucceedNodeDefinition;\n\n // This is a decorator node, so we expect an opening '{'.\n popAndCheck(tokens, \"{\");\n\n // Return the succeed node definition.\n return node;\n}\n\n/**\n * Creates a fail node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The fail node JSON definition.\n */\nfunction createFailNode(tokens: string[], stringLiteralPlaceholders: StringLiteralPlaceholders): FailNodeDefinition {\n const node = {\n type: \"fail\",\n ...parseAttributeTokens(tokens, stringLiteralPlaceholders)\n } as FailNodeDefinition;\n\n // This is a decorator node, so we expect an opening '{'.\n popAndCheck(tokens, \"{\");\n\n // Return the fail node definition.\n return node;\n}\n\n/**\n * Creates a flip node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The flip node JSON definition.\n */\nfunction createFlipNode(tokens: string[], stringLiteralPlaceholders: StringLiteralPlaceholders): FlipNodeDefinition {\n const node = {\n type: \"flip\",\n ...parseAttributeTokens(tokens, stringLiteralPlaceholders)\n } as FlipNodeDefinition;\n\n // This is a decorator node, so we expect an opening '{'.\n popAndCheck(tokens, \"{\");\n\n // Return the flip node definition.\n return node;\n}\n\n/**\n * Creates a repeat node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The repeat node JSON definition.\n */\nfunction createRepeatNode(\n tokens: string[],\n stringLiteralPlaceholders: StringLiteralPlaceholders\n): RepeatNodeDefinition {\n let node = { type: \"repeat\" } as RepeatNodeDefinition;\n\n // Get the node arguments.\n const nodeArguments = parseArgumentTokens(tokens, stringLiteralPlaceholders);\n\n // The arguments of a repeat node are optional. We may have:\n // - No node arguments, in which case the repeat note will iterate indefinitely.\n // - One node argument which will be the explicit number of iterations to make.\n // - Two node arguments which define the min and max iteration bounds from which a random iteration count will be picked.\n if (nodeArguments.length) {\n // All repeat node arguments MUST be of type number and must be integer.\n nodeArguments\n .filter((arg) => arg.type !== \"number\" || !arg.isInteger)\n .forEach(() => {\n throw new Error(`repeat node iteration counts must be integer values`);\n });\n\n // We should have got one or two iteration counts.\n if (nodeArguments.length === 1) {\n // A static iteration count was defined.\n node.iterations = nodeArguments[0].value as number;\n\n // A repeat node must have a positive number of iterations if defined.\n if (node.iterations < 0) {\n throw new Error(\"a repeat node must have a positive number of iterations if defined\");\n }\n } else if (nodeArguments.length === 2) {\n // A minimum and maximum iteration count was defined.\n node.iterations = [nodeArguments[0].value as number, nodeArguments[1].value as number];\n\n // A repeat node must have a positive min and max iteration count if they are defined.\n if (node.iterations[0] < 0 || node.iterations[1] < 0) {\n throw new Error(\"a repeat node must have a positive minimum and maximum iteration count if defined\");\n }\n\n // A repeat node must not have an minimum iteration count that exceeds the maximum iteration count.\n if (node.iterations[0] > node.iterations[1]) {\n throw new Error(\n \"a repeat node must not have a minimum iteration count that exceeds the maximum iteration count\"\n );\n }\n } else {\n // An incorrect number of iteration counts was defined.\n throw new Error(\"invalid number of repeat node iteration count arguments defined\");\n }\n }\n\n // Grab any node attribute definitions and spread them into the node definition.\n node = { ...node, ...parseAttributeTokens(tokens, stringLiteralPlaceholders) };\n\n // This is a decorator node, so we expect an opening '{'.\n popAndCheck(tokens, \"{\");\n\n // Return the repeat node definition.\n return node;\n}\n\n/**\n * Creates a retry node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The retry node JSON definition.\n */\nfunction createRetryNode(tokens: string[], stringLiteralPlaceholders: StringLiteralPlaceholders): RetryNodeDefinition {\n let node = { type: \"retry\" } as RetryNodeDefinition;\n\n // Get the node arguments.\n const nodeArguments = parseArgumentTokens(tokens, stringLiteralPlaceholders);\n\n // The arguments of a retry node are optional. We may have:\n // - No node arguments, in which case the retry note will attempt indefinitely.\n // - One node argument which will be the explicit number of attempts to make.\n // - Two node arguments which define the min and max attempt bounds from which a random attempt count will be picked.\n if (nodeArguments.length) {\n // All retry node arguments MUST be of type number and must be integer.\n nodeArguments\n .filter((arg) => arg.type !== \"number\" || !arg.isInteger)\n .forEach(() => {\n throw new Error(`retry node attempt counts must be integer values`);\n });\n\n // We should have got one or two attempt counts.\n if (nodeArguments.length === 1) {\n // A static attempt count was defined.\n node.attempts = nodeArguments[0].value as number;\n\n // A retry node must have a positive number of attempts if defined.\n if (node.attempts < 0) {\n throw new Error(\"a retry node must have a positive number of attempts if defined\");\n }\n } else if (nodeArguments.length === 2) {\n // A minimum and maximum attempt count was defined.\n node.attempts = [nodeArguments[0].value as number, nodeArguments[1].value as number];\n\n // A retry node must have a positive min and max attempts count if they are defined.\n if (node.attempts[0] < 0 || node.attempts[1] < 0) {\n throw new Error(\"a retry node must have a positive minimum and maximum attempt count if defined\");\n }\n\n // A retry node must not have a minimum attempt count that exceeds the maximum attempt count.\n if (node.attempts[0] > node.attempts[1]) {\n throw new Error(\n \"a retry node must not have a minimum attempt count that exceeds the maximum attempt count\"\n );\n }\n } else {\n // An incorrect number of attempt counts was defined.\n throw new Error(\"invalid number of retry node attempt count arguments defined\");\n }\n }\n\n // Grab any node attribute definitions and spread them into the node definition.\n node = { ...node, ...parseAttributeTokens(tokens, stringLiteralPlaceholders) };\n\n // This is a decorator node, so we expect an opening '{'.\n popAndCheck(tokens, \"{\");\n\n // Return the retry node definition.\n return node;\n}\n\n/**\n * Creates a sequence node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The sequence node JSON definition.\n */\nfunction createSequenceNode(\n tokens: string[],\n stringLiteralPlaceholders: StringLiteralPlaceholders\n): SequenceNodeDefinition {\n const node = {\n type: \"sequence\",\n ...parseAttributeTokens(tokens, stringLiteralPlaceholders)\n } as SequenceNodeDefinition;\n\n // This is a composite node, so we expect an opening '{'.\n popAndCheck(tokens, \"{\");\n\n // Return the sequence node definition.\n return node;\n}\n\n/**\n * Creates a selector node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The selector node JSON definition.\n */\nfunction createSelectorNode(\n tokens: string[],\n stringLiteralPlaceholders: StringLiteralPlaceholders\n): SelectorNodeDefinition {\n const node = {\n type: \"selector\",\n ...parseAttributeTokens(tokens, stringLiteralPlaceholders)\n } as SelectorNodeDefinition;\n\n // This is a composite node, so we expect an opening '{'.\n popAndCheck(tokens, \"{\");\n\n // Return the selector node definition.\n return node;\n}\n\n/**\n * Creates a parallel node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The parallel node JSON definition.\n */\nfunction createParallelNode(\n tokens: string[],\n stringLiteralPlaceholders: StringLiteralPlaceholders\n): ParallelNodeDefinition {\n const node = {\n type: \"parallel\",\n ...parseAttributeTokens(tokens, stringLiteralPlaceholders)\n } as ParallelNodeDefinition;\n\n // This is a composite node, so we expect an opening '{'.\n popAndCheck(tokens, \"{\");\n\n // Return the parallel node definition.\n return node;\n}\n\n/**\n * Creates a lotto node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The lotto node JSON definition.\n */\nfunction createLottoNode(tokens: string[], stringLiteralPlaceholders: StringLiteralPlaceholders): LottoNodeDefinition {\n // If any node arguments have been defined then they must be our weights.\n const nodeArguments = parseArgumentTokens(tokens, stringLiteralPlaceholders);\n\n // All lotto node arguments MUST be of type number and must be positive integers.\n nodeArguments\n .filter((arg) => arg.type !== \"number\" || !arg.isInteger || arg.value < 0)\n .forEach(() => {\n throw new Error(`lotto node weight arguments must be positive integer values`);\n });\n\n const node = {\n type: \"lotto\",\n ...parseAttributeTokens(tokens, stringLiteralPlaceholders)\n } as LottoNodeDefinition;\n\n // Apply the weights if any were defined.\n if (nodeArguments.length) {\n node.weights = nodeArguments.map(({ value }) => value) as number[];\n }\n\n // This is a composite node, so we expect an opening '{'.\n popAndCheck(tokens, \"{\");\n\n // Return the lotto node definition.\n return node;\n}\n\n/**\n * Creates an action node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The action node JSON definition.\n */\nfunction createActionNode(\n tokens: string[],\n stringLiteralPlaceholders: StringLiteralPlaceholders\n): ActionNodeDefinition {\n // Parse any node arguments, we should have at least one which will be an identifier argument for the action name\n // and agent function to invoke for the action, all other arguments are to be passed as arguments to that function.\n const [actionNameIdentifier, ...agentFunctionArgs] = parseArgumentTokens(tokens, stringLiteralPlaceholders);\n\n // Our first argument MUST be defined and be an identifier as we require an action name argument.\n if (actionNameIdentifier?.type !== \"identifier\") {\n throw new Error(\"expected action name identifier argument\");\n }\n\n // Only the first argument should have been an identifier, all agent function arguments must be string, number, boolean or null.\n agentFunctionArgs\n .filter((arg) => arg.type === \"identifier\")\n .forEach((arg) => {\n throw new Error(\n `invalid action node argument value '${arg.value}', must be string, number, boolean or null`\n );\n });\n\n // Return the action node definition.\n return {\n type: \"action\",\n call: actionNameIdentifier.value,\n args: agentFunctionArgs.map(({ value }) => value),\n ...parseAttributeTokens(tokens, stringLiteralPlaceholders)\n };\n}\n\n/**\n * Creates a condition node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The condition node JSON definition.\n */\nfunction createConditionNode(\n tokens: string[],\n stringLiteralPlaceholders: StringLiteralPlaceholders\n): ConditionNodeDefinition {\n // Parse any node arguments, we should have at least one which will be an identifier argument for the condition name\n // and agent function to invoke for the condition, all other arguments are to be passed as arguments to that function.\n const [conditionNameIdentifier, ...agentFunctionArgs] = parseArgumentTokens(tokens, stringLiteralPlaceholders);\n\n // Our first argument MUST be defined and be an identifier as we require a condition name argument.\n if (conditionNameIdentifier?.type !== \"identifier\") {\n throw new Error(\"expected condition name identifier argument\");\n }\n\n // Only the first argument should have been an identifier, all agent function arguments must be string, number, boolean or null.\n agentFunctionArgs\n .filter((arg) => arg.type === \"identifier\")\n .forEach((arg) => {\n throw new Error(\n `invalid condition node argument value '${arg.value}', must be string, number, boolean or null`\n );\n });\n\n // Return the condition node definition.\n return {\n type: \"condition\",\n call: conditionNameIdentifier.value,\n args: agentFunctionArgs.map(({ value }) => value),\n ...parseAttributeTokens(tokens, stringLiteralPlaceholders)\n };\n}\n\n/**\n * Creates a wait node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The wait node JSON definition.\n */\nfunction createWaitNode(tokens: string[], stringLiteralPlaceholders: StringLiteralPlaceholders): WaitNodeDefinition {\n let node = { type: \"wait\" } as WaitNodeDefinition;\n\n // Get the node arguments.\n const nodeArguments = parseArgumentTokens(tokens, stringLiteralPlaceholders);\n\n // The arguments of a wait node are optional. We may have:\n // - No node arguments, in which case the wait will be indefinite until it is aborted.\n // - One node argument which will be the explicit duration of the wait.\n // - Two node arguments which define the min and max duration bounds from which a random duration will be picked.\n if (nodeArguments.length) {\n // All wait node arguments MUST be of type number and must be integer.\n nodeArguments\n .filter((arg) => arg.type !== \"number\" || !arg.isInteger)\n .forEach(() => {\n throw new Error(`wait node durations must be integer values`);\n });\n\n // We may have:\n // - One node argument which will be the explicit duration of the wait.\n // - Two node arguments which define the min and max duration bounds from which a random duration will be picked.\n // - Too many arguments, which is not valid.\n if (nodeArguments.length === 1) {\n // An explicit duration was defined.\n node.duration = nodeArguments[0].value as number;\n\n // If an explict duration was defined then it must be a positive number.\n if (node.duration < 0) {\n throw new Error(\"a wait node must have a positive duration\");\n }\n } else if (nodeArguments.length === 2) {\n // Min and max duration bounds were defined from which a random duration will be picked.\n node.duration = [nodeArguments[0].value as number, nodeArguments[1].value as number];\n\n // A wait node must have a positive min and max duration.\n if (node.duration[0] < 0 || node.duration[1] < 0) {\n throw new Error(\"a wait node must have a positive minimum and maximum duration\");\n }\n\n // A wait node must not have a minimum duration that exceeds the maximum duration.\n if (node.duration[0] > node.duration[1]) {\n throw new Error(\"a wait node must not have a minimum duration that exceeds the maximum duration\");\n }\n } else if (nodeArguments.length > 2) {\n // An incorrect number of duration arguments were defined.\n throw new Error(\"invalid number of wait node duration arguments defined\");\n }\n }\n\n // Return the wait node definition.\n return { ...node, ...parseAttributeTokens(tokens, stringLiteralPlaceholders) };\n}\n\n/**\n * Creates a branch node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The branch node JSON definition.\n */\nfunction createBranchNode(\n tokens: string[],\n stringLiteralPlaceholders: StringLiteralPlaceholders\n): BranchNodeDefinition {\n // Parse any node arguments, we should have one which will be an identifier argument for the root ref.\n const nodeArguments = parseArgumentTokens(tokens, stringLiteralPlaceholders);\n\n // We should have only a single identifer argument for a branch node, which is the root ref.\n if (nodeArguments.length !== 1 || nodeArguments[0].type !== \"identifier\") {\n throw new Error(\"expected single branch name argument\");\n }\n\n // Return the branch node definition.\n return { type: \"branch\", ref: nodeArguments[0].value };\n}\n\n/**\n * Validate a fully-populated node definition that was popped off of the tree stack.\n * @param definition The popped node to validate.\n */\nfunction validatePoppedNode(definition: AnyNodeDefinition): void {\n // Decorators MUST have a child defined.\n if (isDecoratorNode(definition) && isNullOrUndefined(definition.child)) {\n throw new Error(`a ${definition.type} node must have a single child node defined`);\n }\n\n // Composites MUST have at least one child defined.\n if (isCompositeNode(definition) && !definition.children?.length) {\n throw new Error(`a ${definition.type} node must have at least a single child node defined`);\n }\n\n // We need to make sure that lotto nodes that have weights defined have a number of weights matching the number of child nodes.\n if (definition.type === \"lotto\") {\n // Check whether a 'weights' property has been defined, if it has we expect it to be an array of weights.\n if (typeof definition.weights !== \"undefined\") {\n // Check that the weights property is an array of positive integers with an element for each child node element.\n if (definition.weights.length !== definition.children.length) {\n throw new Error(\n \"expected a number of weight arguments matching the number of child nodes for lotto node\"\n );\n }\n }\n }\n}\n", "import { RootNodeDefinition } from \"./BehaviourTreeDefinition\";\nimport { flattenDefinition, isBranchNode, isInteger } from \"./BehaviourTreeDefinitionUtilities\";\nimport { convertMDSLToJSON } from \"./mdsl/MDSLDefinitionParser\";\n\n/**\n * An object representing the result of validating a tree definition.\n */\nexport type DefinitionValidationResult = {\n /**\n * A flag defining whether validation succeeded.\n */\n succeeded: boolean;\n /**\n * A string containing the error message if validation did not succeed.\n */\n errorMessage?: string;\n /**\n * The definition as json if the validation was successful, or undefined if validation did not succeed.\n */\n json?: RootNodeDefinition[];\n};\n\n/**\n * Validates the specified behaviour tree definition in the form of JSON or MDSL, not taking any globally registered subtrees into consideration.\n * @param definition The behaviour tree definition in the form of JSON or MDSL.\n * @returns An object representing the result of validating the given tree definition.\n */\nexport function validateDefinition(definition: any): DefinitionValidationResult {\n // The definition must be defined.\n if (definition === null || typeof definition === \"undefined\") {\n return createValidationFailureResult(\"definition is null or undefined\");\n }\n\n // We are expecting a definition in one of three different forms:\n // - A string which we will assume is MDSL and we will parse this to JSON before validation.\n // - An array which we will assume is an array of root node definitions with at least one being the primary root node (no 'id' property)\n // - An object which we will assume is the primary root node and should not have an 'id' property.\n if (typeof definition === \"string\") {\n // The definition is a string which we can assume is MDSL, so attempt to validate it.\n return validateMDSLDefinition(definition);\n } else if (typeof definition === \"object\") {\n // The definition will either be an array (of root node definitions) or an object (the single primary root node definition).\n return validateJSONDefinition(definition);\n } else {\n return createValidationFailureResult(`unexpected definition type of '${typeof definition}'`);\n }\n}\n\n/**\n * Validates the specified behaviour tree definition in the form of MDSL.\n * @param definition The behaviour tree definition in the form of MDSL.\n * @returns An object representing the result of validating the given tree definition.\n */\nfunction validateMDSLDefinition(definition: string): DefinitionValidationResult {\n let rootNodeDefinitions;\n\n // The first thing the we need to do is to attempt to convert our MDSL into JSON.\n try {\n // The definition is a string which we can assume is MDSL, so attempt to parse it to a JSON definition in the form of an array of root node definitions.\n rootNodeDefinitions = convertMDSLToJSON(definition);\n } catch (exception) {\n // We failed to parse the JSON from the MDSL, this is likely to be the result of it not being a valid MDSL string.\n return createValidationFailureResult((exception as Error).message);\n }\n\n // Unpack all of the root node definitions into arrays of main ('id' defined) and sub ('id' not defined) root node definitions.\n const mainRootNodeDefinitions = rootNodeDefinitions.filter(({ id }) => typeof id === \"undefined\");\n const subRootNodeDefinitions = rootNodeDefinitions.filter(({ id }) => typeof id === \"string\" && id.length > 0);\n\n // We should ALWAYS have exactly one root node definition without an 'id' property defined, which is out main root node definition.\n if (mainRootNodeDefinitions.length !== 1) {\n return createValidationFailureResult(\n \"expected single unnamed root node at base of definition to act as main root\"\n );\n }\n\n // We should never have duplicate 'id' properties across our sub root node definitions.\n const subRootNodeIdenitifers: string[] = [];\n for (const { id } of subRootNodeDefinitions) {\n // Have we already come across this 'id' property value?\n if (subRootNodeIdenitifers.includes(id!)) {\n return createValidationFailureResult(`multiple root nodes found with duplicate name '${id}'`);\n }\n\n subRootNodeIdenitifers.push(id!);\n }\n\n try {\n // Validate our branch -> subtree links and check for any circular dependencies, we don't care about checking for broken subtree links here.\n validateBranchSubtreeLinks(rootNodeDefinitions, false);\n } catch (exception) {\n return createValidationFailureResult((exception as Error).message);\n }\n\n // Our definition was valid!\n return {\n succeeded: true,\n json: rootNodeDefinitions\n };\n}\n\n/**\n * Validates the specified behaviour tree definition in the form of JSON.\n * @param definition The behaviour tree definition in the form of JSON.\n * @returns An object representing the result of validating the given tree definition.\n */\nexport function validateJSONDefinition(\n definition: RootNodeDefinition | RootNodeDefinition[]\n): DefinitionValidationResult {\n // The definition will either be an array (of root node definitions) or an object (the single primary root node definition).\n const rootNodeDefinitions = Array.isArray(definition) ? definition : [definition];\n\n // Iterate over our array of root nodes and call validateNode for each, passing an initial depth of 0, wrapped in a try catch to handle validation failures.\n try {\n rootNodeDefinitions.forEach((rootNodeDefinition) => validateNode(rootNodeDefinition, 0));\n } catch (error) {\n // Handle cases where we have caught a thrown Error and return a failure result with the error message.\n if (error instanceof Error) {\n return createValidationFailureResult(error.message);\n }\n\n // No idea what happened here!\n return createValidationFailureResult(`unexpected error: ${error}`);\n }\n\n // Unpack all of the root node definitions into arrays of main ('id' defined) and sub ('id' not defined) root node definitions.\n const mainRootNodeDefinitions = rootNodeDefinitions.filter(({ id }) => typeof id === \"undefined\");\n const subRootNodeDefinitions = rootNodeDefinitions.filter(({ id }) => typeof id === \"string\" && id.length > 0);\n\n // We should ALWAYS have exactly one root node definition without an 'id' property defined, which is out main root node definition.\n if (mainRootNodeDefinitions.length !== 1) {\n return createValidationFailureResult(\n \"expected single root node without 'id' property defined to act as main root\"\n );\n }\n\n // We should never have duplicate 'id' properties across our sub root node definitions.\n const subRootNodeIdenitifers: string[] = [];\n for (const { id } of subRootNodeDefinitions) {\n // Have we already come across this 'id' property value?\n if (subRootNodeIdenitifers.includes(id!)) {\n return createValidationFailureResult(\n `multiple root nodes found with duplicate 'id' property value of '${id}'`\n );\n }\n\n subRootNodeIdenitifers.push(id!);\n }\n\n try {\n // Validate our branch -> subtree links and check for any circular dependencies, we don't care about checking for broken subtree links here.\n validateBranchSubtreeLinks(rootNodeDefinitions, false);\n } catch (exception) {\n return createValidationFailureResult((exception as Error).message);\n }\n\n // Our definition was valid!\n return {\n succeeded: true,\n json: rootNodeDefinitions\n };\n}\n\n/**\n * Validates the branch -> subtree links across all provided root node definitions.\n * This will not consider branch nodes that reference any globally registered subtrees unless includesGlobalSubtrees\n * is set to true, in which case we will also verify that there are no broken branch -> subtree links.\n * @param rootNodeDefinitions The array of root node definitions.\n * @param includesGlobalSubtrees A flag defining whether the array includes all global subtree root node definitions.\n */\nexport function validateBranchSubtreeLinks(rootNodeDefinitions: RootNodeDefinition[], includesGlobalSubtrees: boolean) {\n // Create a mapping of root node identifiers to other root nodes that they reference via branch nodes.\n // Below is an example of a mapping that includes a circular dependency (root => a => b => c => a)\n // [{ refs: [\"a\", \"b\"] }, { id: \"a\", refs: [\"b\"] }, { id: \"b\", refs: [\"c\"] }, { id: \"c\", refs: [\"a\"] }]\n const rootNodeMappings: { id: string | undefined; refs: string[] }[] = rootNodeDefinitions.map(\n (rootNodeDefinition) => ({\n id: rootNodeDefinition.id,\n refs: flattenDefinition(rootNodeDefinition)\n .filter(isBranchNode)\n .map(({ ref }) => ref)\n })\n );\n\n // A recursive function to walk through the mappings, keeping track of which root nodes we have visited in the form of a path of root node identifiers.\n const followRefs = (mapping: { id: string | undefined; refs: string[] }, path: (string | undefined)[] = []) => {\n // Have we found a circular dependency?\n if (path.includes(mapping.id)) {\n // We found a circular dependency! Get the bad path of root node identifiers.\n const badPath = [...path, mapping.id];\n\n // Create the formatted path value. [undefined, \"a\", \"b\", \"c\", \"a\"] would be formatted as \"a -> b -> c -> a\".\n const badPathFormatted = badPath.filter((element) => !!element).join(\" => \");\n\n // No need to continue, we found a circular dependency.\n throw new Error(`circular dependency found in branch node references: ${badPathFormatted}`);\n }\n\n for (const ref of mapping.refs) {\n // Find the mapping for the root node with an identifer matching the current ref.\n const subMapping = rootNodeMappings.find(({ id }) => id === ref);\n\n // We may not have a mapping for this ref, which is normal when we aren't considering all globally registered subtrees.\n if (subMapping) {\n followRefs(subMapping, [...path, mapping.id]);\n } else if (includesGlobalSubtrees) {\n // We found a reference to a root node that doesn't exist, which is a problem seeing as the root node definitons includes all globally registered subtrees.\n throw new Error(\n mapping.id\n ? `subtree '${mapping.id}' has branch node that references root node '${ref}' which has not been defined`\n : `primary tree has branch node that references root node '${ref}' which has not been defined`\n );\n }\n }\n };\n\n // Start looking for circular dependencies and broken references from the primary root node definition.\n followRefs(rootNodeMappings.find((mapping) => typeof mapping.id === \"undefined\")!);\n}\n\n/**\n * Validate an object that we expect to be a node definition.\n * @param definition An object that we expect to be a node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateNode(definition: any, depth: number): void {\n // Every node must be valid object and have a non-empty 'type' string property.\n if (typeof definition !== \"object\" || typeof definition.type !== \"string\" || definition.type.length === 0) {\n throw new Error(\n `node definition is not an object or 'type' property is not a non-empty string at depth '${depth}'`\n );\n }\n\n // How we validate this node definition will depend on its type.\n switch (definition.type) {\n case \"action\":\n validateActionNode(definition, depth);\n break;\n\n case \"condition\":\n validateConditionNode(definition, depth);\n break;\n\n case \"wait\":\n validateWaitNode(definition, depth);\n break;\n\n case \"branch\":\n validateBranchNode(definition, depth);\n break;\n\n case \"root\":\n validateRootNode(definition, depth);\n break;\n\n case \"succeed\":\n validateSucceedNode(definition, depth);\n break;\n\n case \"fail\":\n validateFailNode(definition, depth);\n break;\n\n case \"flip\":\n validateFlipNode(definition, depth);\n break;\n\n case \"repeat\":\n validateRepeatNode(definition, depth);\n break;\n\n case \"retry\":\n validateRetryNode(definition, depth);\n break;\n\n case \"sequence\":\n validateSequenceNode(definition, depth);\n break;\n\n case \"selector\":\n validateSelectorNode(definition, depth);\n break;\n\n case \"parallel\":\n validateParallelNode(definition, depth);\n break;\n\n case \"lotto\":\n validateLottoNode(definition, depth);\n break;\n\n default:\n throw new Error(`unexpected node type of '${definition.type}' at depth '${depth}'`);\n }\n}\n\n/**\n * Validate any attributes for a given node definition.\n * @param definition The node definition.\n * @param depth The depth of the node in the behaviour tree definition.\n */\nfunction validateNodeAttributes(definition: any, depth: number): void {\n // Validate each of the attribute types for this node.\n [\"while\", \"until\", \"entry\", \"exit\", \"step\"].forEach((attributeName) => {\n // Attempt to grab the definition for the current attribute from the node definition.\n const attributeDefinition = definition[attributeName];\n\n // All node attributes are optional, so there is nothing to do if the current attribute is not defined.\n if (typeof attributeDefinition === \"undefined\") {\n return;\n }\n\n // The attribute definition must be an object.\n if (typeof attributeDefinition !== \"object\") {\n throw new Error(\n `expected attribute '${attributeName}' to be an object for '${definition.type}' node at depth '${depth}'`\n );\n }\n\n // The 'call' property must be defined for any attribute definition.\n if (typeof attributeDefinition.call !== \"string\" || attributeDefinition.call.length === 0) {\n throw new Error(\n `expected 'call' property for attribute '${attributeName}' to be a non-empty string for '${definition.type}' node at depth '${depth}'`\n );\n }\n\n // If any node attribute arguments have been defined then they must have been defined in an array.\n if (typeof attributeDefinition.args !== \"undefined\" && !Array.isArray(attributeDefinition.args)) {\n throw new Error(\n `expected 'args' property for attribute '${attributeName}' to be an array for '${definition.type}' node at depth '${depth}'`\n );\n }\n });\n}\n\n/**\n * Validate an object that we expect to be a root node definition.\n * @param definition An object that we expect to be a root node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateRootNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"root\") {\n throw new Error(\"expected node type of 'root' for root node\");\n }\n\n // A root node cannot be the child of another node.\n if (depth > 0) {\n throw new Error(\"a root node cannot be the child of another node\");\n }\n\n // Check that, if the root node 'id' property is defined, it is a non-empty string.\n if (typeof definition.id !== \"undefined\" && (typeof definition.id !== \"string\" || definition.id.length === 0)) {\n throw new Error(\"expected non-empty string for 'id' property if defined for root node\");\n }\n\n // A root node is a decorator node, so must have a child node defined.\n if (typeof definition.child === \"undefined\") {\n throw new Error(\"expected property 'child' to be defined for root node\");\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n\n // Validate the child node of this decorator node.\n validateNode(definition.child, depth + 1);\n}\n\n/**\n * Validate an object that we expect to be a succeed node definition.\n * @param definition An object that we expect to be a succeed node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateSucceedNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"succeed\") {\n throw new Error(`expected node type of 'succeed' for succeed node at depth '${depth}'`);\n }\n\n // A succeed node is a decorator node, so must have a child node defined.\n if (typeof definition.child === \"undefined\") {\n throw new Error(`expected property 'child' to be defined for succeed node at depth '${depth}'`);\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n\n // Validate the child node of this decorator node.\n validateNode(definition.child, depth + 1);\n}\n\n/**\n * Validate an object that we expect to be a fail node definition.\n * @param definition An object that we expect to be a fail node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateFailNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"fail\") {\n throw new Error(`expected node type of 'fail' for fail node at depth '${depth}'`);\n }\n\n // A fail node is a decorator node, so must have a child node defined.\n if (typeof definition.child === \"undefined\") {\n throw new Error(`expected property 'child' to be defined for fail node at depth '${depth}'`);\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n\n // Validate the child node of this decorator node.\n validateNode(definition.child, depth + 1);\n}\n\n/**\n * Validate an object that we expect to be a flip node definition.\n * @param definition An object that we expect to be a flip node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateFlipNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"flip\") {\n throw new Error(`expected node type of 'flip' for flip node at depth '${depth}'`);\n }\n\n // A flip node is a decorator node, so must have a child node defined.\n if (typeof definition.child === \"undefined\") {\n throw new Error(`expected property 'child' to be defined for flip node at depth '${depth}'`);\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n\n // Validate the child node of this decorator node.\n validateNode(definition.child, depth + 1);\n}\n\n/**\n * Validate an object that we expect to be a repeat node definition.\n * @param definition An object that we expect to be a repeat node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateRepeatNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"repeat\") {\n throw new Error(`expected node type of 'repeat' for repeat node at depth '${depth}'`);\n }\n\n // A repeat node is a decorator node, so must have a child node defined.\n if (typeof definition.child === \"undefined\") {\n throw new Error(`expected property 'child' to be defined for repeat node at depth '${depth}'`);\n }\n\n // Check whether an 'iterations' property has been defined, it may not have been if this node is to repeat indefinitely.\n if (typeof definition.iterations !== \"undefined\") {\n if (Array.isArray(definition.iterations)) {\n // Check whether any elements of the array are not integer values.\n const containsNonInteger = !!definition.iterations.filter((value: unknown) => !isInteger(value)).length;\n\n // If the 'iterations' property is an array then it MUST contain two integer values.\n if (definition.iterations.length !== 2 || containsNonInteger) {\n throw new Error(\n `expected array containing two integer values for 'iterations' property if defined for repeat node at depth '${depth}'`\n );\n }\n\n // A repeat node must have a positive min and max iterations count if they are defined.\n if (definition.iterations[0] < 0 || definition.iterations[1] < 0) {\n throw new Error(\n `expected positive minimum and maximum iterations count for 'iterations' property if defined for repeat node at depth '${depth}'`\n );\n }\n\n // A repeat node must not have a minimum iterations count that exceeds the maximum iterations count.\n if (definition.iterations[0] > definition.iterations[1]) {\n throw new Error(\n `expected minimum iterations count that does not exceed the maximum iterations count for 'iterations' property if defined for repeat node at depth '${depth}'`\n );\n }\n } else if (isInteger(definition.iterations)) {\n // A repeat node must have a positive number of iterations if defined.\n if (definition.iterations < 0) {\n throw new Error(\n `expected positive iterations count for 'iterations' property if defined for repeat node at depth '${depth}'`\n );\n }\n } else {\n throw new Error(\n `expected integer value or array containing two integer values for 'iterations' property if defined for repeat node at depth '${depth}'`\n );\n }\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n\n // Validate the child node of this decorator node.\n validateNode(definition.child, depth + 1);\n}\n\n/**\n * Validate an object that we expect to be a retry node definition.\n * @param definition An object that we expect to be a retry node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateRetryNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"retry\") {\n throw new Error(`expected node type of 'retry' for retry node at depth '${depth}'`);\n }\n\n // A retry node is a decorator node, so must have a child node defined.\n if (typeof definition.child === \"undefined\") {\n throw new Error(`expected property 'child' to be defined for retry node at depth '${depth}'`);\n }\n\n // Check whether an 'attempts' property has been defined, it may not have been if this node is to retry indefinitely.\n if (typeof definition.attempts !== \"undefined\") {\n if (Array.isArray(definition.attempts)) {\n // Check whether any elements of the array are not integer values.\n const containsNonInteger = !!definition.attempts.filter((value: unknown) => !isInteger(value)).length;\n\n // If the 'attempts' property is an array then it MUST contain two integer values.\n if (definition.attempts.length !== 2 || containsNonInteger) {\n throw new Error(\n `expected array containing two integer values for 'attempts' property if defined for retry node at depth '${depth}'`\n );\n }\n\n // A retry node must have a positive min and max attempts count if they are defined.\n if (definition.attempts[0] < 0 || definition.attempts[1] < 0) {\n throw new Error(\n `expected positive minimum and maximum attempts count for 'attempts' property if defined for retry node at depth '${depth}'`\n );\n }\n\n // A retry node must not have a minimum attempts count that exceeds the maximum attempts count.\n if (definition.attempts[0] > definition.attempts[1]) {\n throw new Error(\n `expected minimum attempts count that does not exceed the maximum attempts count for 'attempts' property if defined for retry node at depth '${depth}'`\n );\n }\n } else if (isInteger(definition.attempts)) {\n // A retry node must have a positive number of attempts if defined.\n if (definition.attempts < 0) {\n throw new Error(\n `expected positive attempts count for 'attempts' property if defined for retry node at depth '${depth}'`\n );\n }\n } else {\n throw new Error(\n `expected integer value or array containing two integer values for 'attempts' property if defined for retry node at depth '${depth}'`\n );\n }\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n\n // Validate the child node of this decorator node.\n validateNode(definition.child, depth + 1);\n}\n\n/**\n * Validate an object that we expect to be a branch node definition.\n * @param definition An object that we expect to be a branch node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateBranchNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"branch\") {\n throw new Error(`expected node type of 'branch' for branch node at depth '${depth}'`);\n }\n\n // Check that the branch node 'ref' property is defined and is a non-empty string.\n if (typeof definition.ref !== \"string\" || definition.ref.length === 0) {\n throw new Error(`expected non-empty string for 'ref' property for branch node at depth '${depth}'`);\n }\n\n // It is invalid to define guard attributes for a branch node as they should be defined on the referenced root node.\n [\"while\", \"until\"].forEach((attributeName) => {\n if (typeof definition[attributeName] !== \"undefined\") {\n throw new Error(\n `guards should not be defined for branch nodes but guard '${attributeName}' was defined for branch node at depth '${depth}'`\n );\n }\n });\n\n // It is invalid to define callback attributes for a branch node as they should be defined on the referenced root node.\n [\"entry\", \"exit\", \"step\"].forEach((attributeName) => {\n if (typeof definition[attributeName] !== \"undefined\") {\n throw new Error(\n `callbacks should not be defined for branch nodes but callback '${attributeName}' was defined for branch node at depth '${depth}'`\n );\n }\n });\n}\n\n/**\n * Validate an object that we expect to be a action node definition.\n * @param definition An object that we expect to be a action node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateActionNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"action\") {\n throw new Error(`expected node type of 'action' for action node at depth '${depth}'`);\n }\n\n // The 'call' property must be defined for a action node definition.\n if (typeof definition.call !== \"string\" || definition.call.length === 0) {\n throw new Error(`expected non-empty string for 'call' property of action node at depth '${depth}'`);\n }\n\n // If any action function arguments have been defined then they must have been defined in an array.\n if (typeof definition.args !== \"undefined\" && !Array.isArray(definition.args)) {\n throw new Error(`expected array for 'args' property if defined for action node at depth '${depth}'`);\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n}\n\n/**\n * Validate an object that we expect to be a condition node definition.\n * @param definition An object that we expect to be a condition node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateConditionNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"condition\") {\n throw new Error(`expected node type of 'condition' for condition node at depth '${depth}'`);\n }\n\n // The 'call' property must be defined for a condition node definition.\n if (typeof definition.call !== \"string\" || definition.call.length === 0) {\n throw new Error(`expected non-empty string for 'call' property of condition node at depth '${depth}'`);\n }\n\n // If any condition function arguments have been defined then they must have been defined in an array.\n if (typeof definition.args !== \"undefined\" && !Array.isArray(definition.args)) {\n throw new Error(`expected array for 'args' property if defined for condition node at depth '${depth}'`);\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n}\n\n/**\n * Validate an object that we expect to be a wait node definition.\n * @param definition An object that we expect to be a wait node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateWaitNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"wait\") {\n throw new Error(`expected node type of 'wait' for wait node at depth '${depth}'`);\n }\n\n // Check whether a 'duration' property has been defined, it may not have been if this node is to wait indefinitely.\n if (typeof definition.duration !== \"undefined\") {\n if (Array.isArray(definition.duration)) {\n // Check whether any elements of the array are not integer values.\n const containsNonInteger = !!definition.duration.filter((value: unknown) => !isInteger(value)).length;\n\n // If the 'duration' property is an array then it MUST contain two integer values.\n if (definition.duration.length !== 2 || containsNonInteger) {\n throw new Error(\n `expected array containing two integer values for 'duration' property if defined for wait node at depth '${depth}'`\n );\n }\n\n // A wait node must have a positive min and max duration value if they are defined.\n if (definition.duration[0] < 0 || definition.duration[1] < 0) {\n throw new Error(\n `expected positive minimum and maximum duration for 'duration' property if defined for wait node at depth '${depth}'`\n );\n }\n\n // A wait node must not have a minimum duration value that exceeds the maximum duration value.\n if (definition.duration[0] > definition.duration[1]) {\n throw new Error(\n `expected minimum duration value that does not exceed the maximum duration value for 'duration' property if defined for wait node at depth '${depth}'`\n );\n }\n } else if (isInteger(definition.duration)) {\n // A wait node must have a positive duration value if defined.\n if (definition.duration < 0) {\n throw new Error(\n `expected positive duration value for 'duration' property if defined for wait node at depth '${depth}'`\n );\n }\n } else {\n throw new Error(\n `expected integer value or array containing two integer values for 'duration' property if defined for wait node at depth '${depth}'`\n );\n }\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n}\n\n/**\n * Validate an object that we expect to be a sequence node definition.\n * @param definition An object that we expect to be a sequence node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateSequenceNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"sequence\") {\n throw new Error(`expected node type of 'sequence' for sequence node at depth '${depth}'`);\n }\n\n // A sequence node is a composite node, so must have a children nodes array defined.\n if (!Array.isArray(definition.children) || definition.children.length === 0) {\n throw new Error(`expected non-empty 'children' array to be defined for sequence node at depth '${depth}'`);\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n\n // Validate the child nodes of this composite node.\n definition.children.forEach((child: any) => validateNode(child, depth + 1));\n}\n\n/**\n * Validate an object that we expect to be a selector node definition.\n * @param definition An object that we expect to be a selector node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateSelectorNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"selector\") {\n throw new Error(`expected node type of 'selector' for selector node at depth '${depth}'`);\n }\n\n // A selector node is a composite node, so must have a children nodes array defined.\n if (!Array.isArray(definition.children) || definition.children.length === 0) {\n throw new Error(`expected non-empty 'children' array to be defined for selector node at depth '${depth}'`);\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n\n // Validate the child nodes of this composite node.\n definition.children.forEach((child: any) => validateNode(child, depth + 1));\n}\n\n/**\n * Validate an object that we expect to be a parallel node definition.\n * @param definition An object that we expect to be a parallel node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateParallelNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"parallel\") {\n throw new Error(`expected node type of 'parallel' for parallel node at depth '${depth}'`);\n }\n\n // A parallel node is a composite node, so must have a children nodes array defined.\n if (!Array.isArray(definition.children) || definition.children.length === 0) {\n throw new Error(`expected non-empty 'children' array to be defined for parallel node at depth '${depth}'`);\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n\n // Validate the child nodes of this composite node.\n definition.children.forEach((child: any) => validateNode(child, depth + 1));\n}\n\n/**\n * Validate an object that we expect to be a lotto node definition.\n * @param definition An object that we expect to be a lotto node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateLottoNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"lotto\") {\n throw new Error(`expected node type of 'lotto' for lotto node at depth '${depth}'`);\n }\n\n // A lotto node is a composite node, so must have a children nodes array defined.\n if (!Array.isArray(definition.children) || definition.children.length === 0) {\n throw new Error(`expected non-empty 'children' array to be defined for lotto node at depth '${depth}'`);\n }\n\n // Check whether a 'weights' property has been defined, if it has we expect it to be an array of weights.\n if (typeof definition.weights !== \"undefined\") {\n // Check that the weights property is an array of positive integers with an element for each child node element.\n if (\n !Array.isArray(definition.weights) ||\n definition.weights.length !== definition.children.length ||\n definition.weights.filter((value: unknown) => !isInteger(value)).length ||\n definition.weights.filter((value: number) => value < 0).length\n ) {\n throw new Error(\n `expected an array of positive integer weight values with a length matching the number of child nodes for 'weights' property if defined for lotto node at depth '${depth}'`\n );\n }\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n\n // Validate the child nodes of this composite node.\n definition.children.forEach((child: any) => validateNode(child, depth + 1));\n}\n\n/**\n * A helper function to create a failure validation result with the given error message.\n * @param errorMessage The validation failure error message.\n * @returns A failure validation result with the given error message.\n */\nfunction createValidationFailureResult(errorMessage: string): DefinitionValidationResult {\n return { succeeded: false, errorMessage };\n}\n", "import { ActionResult, Agent, GlobalFunction } from \"./Agent\";\nimport { RootNodeDefinition } from \"./BehaviourTreeDefinition\";\n\nexport type InvokerFunction = (args: any[]) => ActionResult | boolean;\n\n/**\n * A singleton used to store and lookup registered functions and subtrees.\n */\nexport default class Lookup {\n /**\n * The object holding any registered functions keyed on function name.\n */\n private static registeredFunctions: { [key: string]: GlobalFunction } = {};\n /**\n * The object holding any registered subtree root node definitions keyed on tree name.\n */\n private static registeredSubtrees: { [key: string]: RootNodeDefinition } = {};\n\n /**\n * Gets the function with the specified name.\n * @param name The name of the function.\n * @returns The function with the specified name.\n */\n public static getFunc(name: string): GlobalFunction {\n return this.registeredFunctions[name];\n }\n\n /**\n * Sets the function with the specified name for later lookup.\n * @param name The name of the function.\n * @param func The function.\n */\n public static setFunc(name: string, func: GlobalFunction): void {\n this.registeredFunctions[name] = func;\n }\n\n /**\n * Gets the function invoker for the specified agent and function name.\n * If a function with the specified name exists on the agent object then it will\n * be returned, otherwise we will then check the registered functions for a match.\n * @param agent The agent instance that this behaviour tree is modelling behaviour for.\n * @param name The function name.\n * @returns The function invoker for the specified agent and function name.\n */\n static getFuncInvoker(agent: Agent, name: string): InvokerFunction | null {\n // Check whether the agent contains the specified function.\n const agentFunction = agent[name];\n if (agentFunction && typeof agentFunction === \"function\") {\n return (args: any[]) => agentFunction.apply(agent, args);\n }\n\n // The agent does not contain the specified function but it may have been registered at some point.\n if (this.registeredFunctions[name] && typeof this.registeredFunctions[name] === \"function\") {\n const registeredFunction = this.registeredFunctions[name];\n return (args: any[]) => registeredFunction(agent, ...args.map((arg) => arg.value));\n }\n\n // We have no function to invoke.\n return null;\n }\n\n /**\n * Gets all registered subtree root node definitions.\n */\n static getSubtrees(): { [key: string]: RootNodeDefinition } {\n return this.registeredSubtrees;\n }\n\n /**\n * Sets the subtree with the specified name for later lookup.\n * @param name The name of the subtree.\n * @param subtree The subtree.\n */\n static setSubtree(name: string, subtree: RootNodeDefinition) {\n this.registeredSubtrees[name] = subtree;\n }\n\n /**\n * Removes the registered function or subtree with the specified name.\n * @param name The name of the registered function or subtree.\n */\n static remove(name: string) {\n delete this.registeredFunctions[name];\n delete this.registeredSubtrees[name];\n }\n\n /**\n * Remove all registered functions and subtrees.\n */\n static empty() {\n this.registeredFunctions = {};\n this.registeredSubtrees = {};\n }\n}\n", "import Node from \"../../nodes/Node\";\n\n/**\n * An exception thrown when evaluating node guard path conditions and a conditions fails.\n */\nexport default class GuardUnsatisifedException extends Error {\n /**\n * @param source The node at which a guard condition failed.\n */\n constructor(private source: Node) {\n super(\"A guard path condition has failed\");\n }\n\n /**\n * Gets whether the specified node is the node at which a guard condition failed.\n * @param node The node to check against the source node.\n * @returns Whether the specified node is the node at which a guard condition failed.\n */\n isSourceNode = (node: Node) => node === this.source;\n}\n", "import { Agent } from \"../../Agent\";\nimport Guard from \"./Guard\";\nimport Node from \"../../nodes/Node\";\nimport GuardUnsatisifedException from \"./GuardUnsatisifedException\";\n\nexport type GuardPathPart = {\n node: Node;\n guards: Guard[];\n};\n\n/**\n * Represents a path of node guards along a root-to-leaf tree path.\n */\nexport default class GuardPath {\n /**\n * @param nodes An array of objects defining a node instance -> guard link, ordered by node depth.\n */\n constructor(private nodes: GuardPathPart[]) {}\n\n /**\n * Evaluate guard conditions for all guards in the tree path, moving outwards from the root.\n * @param agent The agent, required for guard evaluation.\n * @returns An evaluation results object.\n */\n evaluate = (agent: Agent) => {\n // We need to evaluate guard conditions for nodes up the tree, moving outwards from the root.\n for (const details of this.nodes) {\n // There can be multiple guards per node.\n for (const guard of details.guards) {\n // Check whether the guard condition passes, and throw an exception if not.\n if (!guard.isSatisfied(agent)) {\n throw new GuardUnsatisifedException(details.node);\n }\n }\n }\n };\n}\n", "import { BehaviourTreeOptions } from \"../BehaviourTreeOptions\";\nimport State, { AnyState } from \"../State\";\nimport { Agent } from \"../Agent\";\nimport Leaf from \"./leaf/Leaf\";\nimport Attribute from \"../attributes/Attribute\";\nimport Entry from \"../attributes/callbacks/Entry\";\nimport Exit from \"../attributes/callbacks/Exit\";\nimport Step from \"../attributes/callbacks/Step\";\nimport Guard from \"../attributes/guards/Guard\";\nimport GuardPath from \"../attributes/guards/GuardPath\";\nimport GuardUnsatisifedException from \"../attributes/guards/GuardUnsatisifedException\";\n\n/**\n * A base node.\n */\nexport default abstract class Node {\n /**\n * The node uid.\n */\n private readonly uid: string = createNodeUid();\n /**\n * The node state.\n */\n private state: AnyState = State.READY;\n /**\n * The guard path to evaluate as part of a node update.\n */\n private guardPath: GuardPath | undefined;\n\n /**\n * @param type The node type.\n * @param attributes The node attributes.\n * @param args The node argument definitions.\n */\n constructor(private type: string, private attributes: Attribute[], private args: any[]) {}\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected abstract onUpdate(agent: Agent, options: BehaviourTreeOptions): void;\n\n /**\n * Gets the name of the node.\n */\n public abstract getName(): string;\n\n /**\n * Gets whether this node is a leaf node.\n */\n public abstract isLeafNode: () => this is Leaf;\n\n /**\n * Gets/Sets the state of the node.\n */\n getState = (): AnyState => this.state;\n setState = (value: AnyState): void => {\n this.state = value;\n };\n\n /**\n * Gets the unique id of the node.\n */\n getUid = () => this.uid;\n\n /**\n * Gets the type of the node.\n */\n getType = () => this.type;\n\n /**\n * Gets the node attributes.\n */\n getAttributes = () => this.attributes;\n\n /**\n * Gets the node arguments.\n */\n getArguments = () => this.args;\n\n /**\n * Gets the node attribute with the specified type, or null if it does not exist.\n */\n getAttribute(type: \"entry\" | \"ENTRY\"): Entry;\n getAttribute(type: \"exit\" | \"EXIT\"): Exit;\n getAttribute(type: \"step\" | \"STEP\"): Step;\n getAttribute(type: string): Attribute {\n return (\n this.getAttributes().filter((decorator) => decorator.type.toUpperCase() === type.toUpperCase())[0] || null\n );\n }\n\n /**\n * Gets the node attributes.\n */\n getGuardAttributes = (): Guard[] => this.getAttributes().filter((decorator) => decorator.isGuard()) as Guard[];\n\n /**\n * Sets the guard path to evaluate as part of a node update.\n */\n setGuardPath = (value: GuardPath) => (this.guardPath = value);\n\n /**\n * Gets whether a guard path is assigned to this node.\n */\n hasGuardPath = () => !!this.guardPath;\n\n /**\n * Gets whether this node is in the specified state.\n * @param value The value to compare to the node state.\n */\n public is(value: AnyState): boolean {\n return this.state === value;\n }\n\n /**\n * Reset the state of the node.\n */\n public reset(): void {\n this.setState(State.READY);\n }\n\n /**\n * Abort the running of this node.\n * @param agent The agent.\n */\n public abort(agent: Agent): void {\n // There is nothing to do if this node is not in the running state.\n if (!this.is(State.RUNNING)) {\n return;\n }\n\n // Reset the state of this node.\n this.reset();\n\n this.getAttribute(\"exit\")?.callAgentFunction(agent, false, true);\n }\n\n /**\n * Update the node.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n * @returns The result of the update.\n */\n public update(agent: Agent, options: BehaviourTreeOptions): void {\n // If this node is already in a 'SUCCEEDED' or 'FAILED' state then there is nothing to do.\n if (this.is(State.SUCCEEDED) || this.is(State.FAILED)) {\n return;\n }\n\n try {\n // Evaluate all of the guard path conditions for the current tree path.\n this.guardPath!.evaluate(agent);\n\n // If this node is in the READY state then call the ENTRY for this node if it exists.\n if (this.is(State.READY)) {\n this.getAttribute(\"entry\")?.callAgentFunction(agent);\n }\n\n this.getAttribute(\"step\")?.callAgentFunction(agent);\n\n // Do the actual update.\n this.onUpdate(agent, options);\n\n // If this node is now in a 'SUCCEEDED' or 'FAILED' state then call the EXIT for this node if it exists.\n if (this.is(State.SUCCEEDED) || this.is(State.FAILED)) {\n this.getAttribute(\"exit\")?.callAgentFunction(agent, this.is(State.SUCCEEDED), false);\n }\n } catch (error) {\n // If the error is a GuardUnsatisfiedException then we need to determine if this node is the source.\n if (error instanceof GuardUnsatisifedException && error.isSourceNode(this)) {\n // Abort the current node.\n this.abort(agent);\n\n // Any node that is the source of an abort will be a failed node.\n this.setState(State.FAILED);\n } else {\n throw error;\n }\n }\n }\n}\n\n/**\n * Create a randomly generated node uid.\n * @returns A randomly generated node uid.\n */\nfunction createNodeUid(): string {\n var S4 = function () {\n return (((1 + Math.random()) * 0x10000) | 0).toString(16).substring(1);\n };\n return S4() + S4() + \"-\" + S4() + \"-\" + S4() + \"-\" + S4() + \"-\" + S4() + S4() + S4();\n}\n", "import Node from \"../Node\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\n\n/**\n * A composite node that wraps child nodes.\n */\nexport default abstract class Composite extends Node {\n /**\n * @param type The node type.\n * @param attributes The node attributes.\n * @param children The child nodes.\n */\n constructor(type: string, attributes: Attribute[], protected children: Node[]) {\n super(type, attributes, []);\n }\n\n /**\n * Gets whether this node is a leaf node.\n */\n isLeafNode = () => false;\n\n /**\n * Gets the children of this node.\n */\n getChildren = () => this.children;\n\n /**\n * Reset the state of the node.\n */\n reset = () => {\n // Reset the state of this node.\n this.setState(State.READY);\n\n // Reset the state of any child nodes.\n this.getChildren().forEach((child) => child.reset());\n };\n\n /**\n * Abort the running of this node.\n * @param agent The agent.\n */\n abort = (agent: Agent) => {\n // There is nothing to do if this node is not in the running state.\n if (!this.is(State.RUNNING)) {\n return;\n }\n\n // Abort any child nodes.\n this.getChildren().forEach((child) => child.abort(agent));\n\n // Reset the state of this node.\n this.reset();\n\n this.getAttribute(\"exit\")?.callAgentFunction(agent, false, true);\n };\n}\n", "import Composite from \"./Composite\";\nimport State from \"../../State\";\nimport Node from \"../Node\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A PARALLEL node.\n * The child nodes are executed concurrently until one fails or all succeed.\n */\nexport default class Parallel extends Composite {\n /**\n * @param attributes The node attributes.\n * @param children The child nodes.\n */\n constructor(attributes: Attribute[], children: Node[]) {\n super(\"parallel\", attributes, children);\n }\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // Keep a count of the number of succeeded child nodes.\n let succeededCount = 0;\n\n let hasChildFailed = false;\n\n // Iterate over all of the children of this node.\n for (const child of this.children) {\n // If the child has never been updated or is running then we will need to update it now.\n if (child.getState() === State.READY || child.getState() === State.RUNNING) {\n // Update the child of this node.\n child.update(agent, options);\n }\n\n // If the current child has a state of 'SUCCEEDED' then we should move on to the next child.\n if (child.getState() === State.SUCCEEDED) {\n // The child node has succeeded, keep track of this to determine if all children have.\n succeededCount++;\n\n // The child node succeeded, but we have not finished checking every child node yet.\n continue;\n }\n\n // If the current child has a state of 'FAILED' then this node is also a 'FAILED' node.\n if (child.getState() === State.FAILED) {\n hasChildFailed = true;\n\n // There is no need to check the rest of the children.\n break;\n }\n\n // The node should be in the 'RUNNING' state.\n if (child.getState() !== State.RUNNING) {\n // The child node was not in an expected state.\n throw new Error(\"child node was not in an expected state.\");\n }\n }\n\n if (hasChildFailed) {\n // This node is a 'FAILED' node.\n this.setState(State.FAILED);\n\n // Abort every running child.\n for (const child of this.children) {\n if (child.getState() === State.RUNNING) {\n child.abort(agent);\n }\n }\n } else {\n // If all children have succeeded then this node has also succeeded, otherwise it is still running.\n this.setState(succeededCount === this.children.length ? State.SUCCEEDED : State.RUNNING);\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => \"PARALLEL\";\n}\n", "import Composite from \"./Composite\";\nimport Node from \"../Node\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A SELECTOR node.\n * The child nodes are executed in sequence until one succeeds or all fail.\n */\nexport default class Selector extends Composite {\n /**\n * @param attributes The node attributes.\n * @param children The child nodes.\n */\n constructor(attributes: Attribute[], protected children: Node[]) {\n super(\"selector\", attributes, children);\n }\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // Iterate over all of the children of this node.\n for (const child of this.children) {\n // If the child has never been updated or is running then we will need to update it now.\n if (child.getState() === State.READY || child.getState() === State.RUNNING) {\n // Update the child of this node.\n child.update(agent, options);\n }\n\n // If the current child has a state of 'SUCCEEDED' then this node is also a 'SUCCEEDED' node.\n if (child.getState() === State.SUCCEEDED) {\n // This node is a 'SUCCEEDED' node.\n this.setState(State.SUCCEEDED);\n\n // There is no need to check the rest of the selector nodes.\n return;\n }\n\n // If the current child has a state of 'FAILED' then we should move on to the next child.\n if (child.getState() === State.FAILED) {\n // Find out if the current child is the last one in the selector.\n // If it is then this sequence node has also failed.\n if (this.children.indexOf(child) === this.children.length - 1) {\n // This node is a 'FAILED' node.\n this.setState(State.FAILED);\n\n // There is no need to check the rest of the selector as we have completed it.\n return;\n } else {\n // The child node failed, try the next one.\n continue;\n }\n }\n\n // The node should be in the 'RUNNING' state.\n if (child.getState() === State.RUNNING) {\n // This node is a 'RUNNING' node.\n this.setState(State.RUNNING);\n\n // There is no need to check the rest of the selector as the current child is still running.\n return;\n }\n\n // The child node was not in an expected state.\n throw new Error(\"child node was not in an expected state.\");\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => \"SELECTOR\";\n}\n", "import Composite from \"./Composite\";\nimport Node from \"../Node\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A SEQUENCE node.\n * The child nodes are executed in sequence until one fails or all succeed.\n */\nexport default class Sequence extends Composite {\n /**\n * @param attributes The node attributes.\n * @param children The child nodes.\n */\n constructor(attributes: Attribute[], protected children: Node[]) {\n super(\"sequence\", attributes, children);\n }\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // Iterate over all of the children of this node.\n for (const child of this.children) {\n // If the child has never been updated or is running then we will need to update it now.\n if (child.getState() === State.READY || child.getState() === State.RUNNING) {\n // Update the child of this node.\n child.update(agent, options);\n }\n\n // If the current child has a state of 'SUCCEEDED' then we should move on to the next child.\n if (child.getState() === State.SUCCEEDED) {\n // Find out if the current child is the last one in the sequence.\n // If it is then this sequence node has also succeeded.\n if (this.children.indexOf(child) === this.children.length - 1) {\n // This node is a 'SUCCEEDED' node.\n this.setState(State.SUCCEEDED);\n\n // There is no need to check the rest of the sequence as we have completed it.\n return;\n } else {\n // The child node succeeded, but we have not finished the sequence yet.\n continue;\n }\n }\n\n // If the current child has a state of 'FAILED' then this node is also a 'FAILED' node.\n if (child.getState() === State.FAILED) {\n // This node is a 'FAILED' node.\n this.setState(State.FAILED);\n\n // There is no need to check the rest of the sequence.\n return;\n }\n\n // The node should be in the 'RUNNING' state.\n if (child.getState() === State.RUNNING) {\n // This node is a 'RUNNING' node.\n this.setState(State.RUNNING);\n\n // There is no need to check the rest of the sequence as the current child is still running.\n return;\n }\n\n // The child node was not in an expected state.\n throw new Error(\"child node was not in an expected state.\");\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => \"SEQUENCE\";\n}\n", "import createLotto from \"lotto-draw\";\n\nimport Node from \"../Node\";\nimport Composite from \"./Composite\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A LOTTO node.\n * A winning child is picked on the initial update of this node, based on ticket weighting.\n * The state of this node will match the state of the winning child.\n */\nexport default class Lotto extends Composite {\n /**\n * @param attributes The node attributes.\n * @param weights The child node weights.\n * @param children The child nodes.\n */\n constructor(attributes: Attribute[], private weights: number[] | undefined, children: Node[]) {\n super(\"lotto\", attributes, children);\n }\n\n /**\n * The child node selected to be the active one.\n */\n private selectedChild: Node | undefined;\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // If this node is in the READY state then we need to pick a winning child node.\n if (this.is(State.READY)) {\n // Create a lotto draw with which to randomly pick a child node to become the active one.\n const lottoDraw = createLotto({\n // Hook up the optional 'random' behaviour tree function option to the one used by 'lotto-draw'.\n random: options.random,\n // Pass in each child node as a participant in the lotto draw with their respective ticket count.\n participants: this.children.map((child, index) => [child, this.weights?.[index] || 1])\n });\n\n // Randomly pick a child based on ticket weighting, this will become the active child for this composite node.\n this.selectedChild = lottoDraw.draw() || undefined;\n }\n\n // If something went wrong and we don't have an active child then we should throw an error.\n if (!this.selectedChild) {\n throw new Error(\"failed to update lotto node as it has no active child\");\n }\n\n // If the selected child has never been updated or is running then we will need to update it now.\n if (this.selectedChild.getState() === State.READY || this.selectedChild.getState() === State.RUNNING) {\n this.selectedChild.update(agent, options);\n }\n\n // The state of the lotto node is the state of its selected child.\n this.setState(this.selectedChild.getState());\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => (this.weights ? `LOTTO [${this.weights.join(\",\")}]` : \"LOTTO\");\n}\n", "import Node from \"../Node\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\n\n/**\n * A decorator node that wraps a single child node.\n */\nexport default abstract class Decorator extends Node {\n /**\n * @param type The node type.\n * @param attributes The node attributes.\n * @param child The child node.\n */\n constructor(type: string, attributes: Attribute[], protected child: Node) {\n super(type, attributes, []);\n }\n\n /**\n * Gets whether this node is a leaf node.\n */\n isLeafNode = () => false;\n\n /**\n * Gets the children of this node.\n */\n getChildren = () => [this.child];\n\n /**\n * Reset the state of the node.\n */\n reset = () => {\n // Reset the state of this node.\n this.setState(State.READY);\n\n // Reset the state of the child node.\n this.child.reset();\n };\n\n /**\n * Abort the running of this node.\n * @param agent The agent.\n */\n abort = (agent: Agent) => {\n // There is nothing to do if this node is not in the running state.\n if (!this.is(State.RUNNING)) {\n return;\n }\n\n // Abort the child node.\n this.child.abort(agent);\n\n // Reset the state of this node.\n this.reset();\n\n this.getAttribute(\"exit\")?.callAgentFunction(agent, false, true);\n };\n}\n", "import Node from \"../Node\";\nimport Decorator from \"./Decorator\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A Fail node.\n * This node wraps a single child and will always move to the 'FAILED' state when the child moves to a 'SUCCEEDED' or 'FAILED' state.\n */\nexport default class Fail extends Decorator {\n /**\n * @param attributes The node attributes.\n * @param child The child node.\n */\n constructor(attributes: Attribute[], child: Node) {\n super(\"fail\", attributes, child);\n }\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // If the child has never been updated or is running then we will need to update it now.\n if (this.child.getState() === State.READY || this.child.getState() === State.RUNNING) {\n this.child.update(agent, options);\n }\n\n // The state of this node will depend in the state of its child.\n switch (this.child.getState()) {\n case State.RUNNING:\n this.setState(State.RUNNING);\n break;\n\n case State.SUCCEEDED:\n case State.FAILED:\n this.setState(State.FAILED);\n break;\n\n default:\n this.setState(State.READY);\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => \"FAIL\";\n}\n", "import Decorator from \"./Decorator\";\nimport State from \"../../State\";\nimport Node from \"../Node\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A Flip node.\n * This node wraps a single child and will flip the state of the child state.\n */\nexport default class Flip extends Decorator {\n /**\n * @param attributes The node attributes.\n * @param child The child node.\n */\n constructor(attributes: Attribute[], child: Node) {\n super(\"flip\", attributes, child);\n }\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // If the child has never been updated or is running then we will need to update it now.\n if (this.child.getState() === State.READY || this.child.getState() === State.RUNNING) {\n this.child.update(agent, options);\n }\n\n // The state of this node will depend in the state of its child.\n switch (this.child.getState()) {\n case State.RUNNING:\n this.setState(State.RUNNING);\n break;\n\n case State.SUCCEEDED:\n this.setState(State.FAILED);\n break;\n\n case State.FAILED:\n this.setState(State.SUCCEEDED);\n break;\n\n default:\n this.setState(State.READY);\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => \"FLIP\";\n}\n", "import Node from \"../Node\";\nimport Decorator from \"./Decorator\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A REPEAT node.\n * The node has a single child which can have:\n * -- A number of iterations for which to repeat the child node.\n * -- An infinite repeat loop if neither an iteration count or a condition function is defined.\n * The REPEAT node will stop and have a 'FAILED' state if its child is ever in a 'FAILED' state after an update.\n * The REPEAT node will attempt to move on to the next iteration if its child is ever in a 'SUCCEEDED' state.\n */\nexport default class Repeat extends Decorator {\n /**\n * @param attributes The node attributes.\n * @param iterations The number of iterations to repeat the child node.\n * @param iterationsMin The minimum possible number of iterations to repeat the child node.\n * @param iterationsMax The maximum possible number of iterations to repeat the child node.\n * @param child The child node.\n */\n constructor(\n attributes: Attribute[],\n private iterations: number | null,\n private iterationsMin: number | null,\n private iterationsMax: number | null,\n child: Node\n ) {\n super(\"repeat\", attributes, child);\n }\n\n /**\n * The number of target iterations to make.\n */\n private targetIterationCount: number | null = null;\n\n /**\n * The current iteration count.\n */\n private currentIterationCount: number = 0;\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // If this node is in the READY state then we need to reset the child and the target iteration count.\n if (this.is(State.READY)) {\n // Reset the child node.\n this.child.reset();\n\n // Reset the current iteration count.\n this.currentIterationCount = 0;\n\n // Set the target iteration count.\n this.setTargetIterationCount(options);\n }\n\n // Do a check to see if we can iterate. If we can then this node will move into the 'RUNNING' state.\n // If we cannot iterate then we have hit our target iteration count, which means that the node has succeeded.\n if (this.canIterate()) {\n // This node is in the running state and can do its initial iteration.\n this.setState(State.RUNNING);\n\n // We may have already completed an iteration, meaning that the child node will be in the SUCCEEDED state.\n // If this is the case then we will have to reset the child node now.\n if (this.child.getState() === State.SUCCEEDED) {\n this.child.reset();\n }\n\n // Update the child of this node.\n this.child.update(agent, options);\n\n // If the child moved into the FAILED state when we updated it then there is nothing left to do and this node has also failed.\n // If it has moved into the SUCCEEDED state then we have completed the current iteration.\n if (this.child.getState() === State.FAILED) {\n // The child has failed, meaning that this node has failed.\n this.setState(State.FAILED);\n\n return;\n } else if (this.child.getState() === State.SUCCEEDED) {\n // We have completed an iteration.\n this.currentIterationCount += 1;\n }\n } else {\n // This node is in the 'SUCCEEDED' state as we cannot iterate any more.\n this.setState(State.SUCCEEDED);\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => {\n if (this.iterations !== null) {\n return `REPEAT ${this.iterations}x`;\n } else if (this.iterationsMin !== null && this.iterationsMax !== null) {\n return `REPEAT ${this.iterationsMin}x-${this.iterationsMax}x`;\n } else {\n return \"REPEAT\";\n }\n };\n\n /**\n * Reset the state of the node.\n */\n reset = () => {\n // Reset the state of this node.\n this.setState(State.READY);\n\n // Reset the current iteration count.\n this.currentIterationCount = 0;\n\n // Reset the child node.\n this.child.reset();\n };\n\n /**\n * Gets whether an iteration can be made.\n * @returns Whether an iteration can be made.\n */\n private canIterate = () => {\n if (this.targetIterationCount !== null) {\n // We can iterate as long as we have not reached our target iteration count.\n return this.currentIterationCount < this.targetIterationCount;\n }\n\n // If neither an iteration count or a condition function were defined then we can iterate indefinitely.\n return true;\n };\n\n /**\n * Sets the target iteration count.\n * @param options The behaviour tree options object.\n */\n private setTargetIterationCount = (options: BehaviourTreeOptions) => {\n // Are we dealing with an explicit iteration count or will we be randomly picking a iteration count between the min and max iteration count.\n if (this.iterations !== null) {\n this.targetIterationCount = this.iterations;\n } else if (this.iterationsMin !== null && this.iterationsMax !== null) {\n // We will be picking a random iteration count between a min and max iteration count, if the optional 'random'\n // behaviour tree function option is defined then we will be using that, otherwise we will fall back to using Math.random.\n const random = typeof options.random === \"function\" ? options.random : Math.random;\n\n // Pick a random iteration count between a min and max iteration count.\n this.targetIterationCount = Math.floor(\n random() * (this.iterationsMax - this.iterationsMin + 1) + this.iterationsMin\n );\n } else {\n this.targetIterationCount = null;\n }\n };\n}\n", "import Node from \"../Node\";\nimport Decorator from \"./Decorator\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A RETRY node.\n * The node has a single child which can have:\n * -- A number of iterations for which to repeat the child node.\n * -- An infinite repeat loop if neither an iteration count or a condition function is defined.\n * The RETRY node will stop and have a 'SUCCEEDED' state if its child is ever in a 'SUCCEEDED' state after an update.\n * The RETRY node will attempt to move on to the next iteration if its child is ever in a 'FAILED' state.\n */\nexport default class Retry extends Decorator {\n /**\n * @param attributes The node attributes.\n * @param attempts The number of attempts to retry the child node.\n * @param attemptsMin The minimum possible number of attempts to retry the child node.\n * @param attemptsMax The maximum possible number of attempts to retry the child node.\n * @param child The child node.\n */\n constructor(\n attributes: Attribute[],\n private attempts: number | null,\n private attemptsMin: number | null,\n private attemptsMax: number | null,\n child: Node\n ) {\n super(\"retry\", attributes, child);\n }\n\n /**\n * The number of target attempts to make.\n */\n private targetAttemptCount: number | null = null;\n\n /**\n * The current attempt count.\n */\n private currentAttemptCount: number = 0;\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // If this node is in the READY state then we need to reset the child and the target attempt count.\n if (this.is(State.READY)) {\n // Reset the child node.\n this.child.reset();\n\n // Reset the current attempt count.\n this.currentAttemptCount = 0;\n\n // Set the target attempt count.\n this.setTargetAttemptCount(options);\n }\n\n // Do a check to see if we can attempt. If we can then this node will move into the 'RUNNING' state.\n // If we cannot attempt then we have hit our target attempt count, which means that the node has succeeded.\n if (this.canAttempt()) {\n // This node is in the running state and can do its initial attempt.\n this.setState(State.RUNNING);\n\n // We may have already completed an attempt, meaning that the child node will be in the FAILED state.\n // If this is the case then we will have to reset the child node now.\n if (this.child.getState() === State.FAILED) {\n this.child.reset();\n }\n\n // Update the child of this node.\n this.child.update(agent, options);\n\n // If the child moved into the SUCCEEDED state when we updated it then there is nothing left to do and this node has also succeeded.\n // If it has moved into the FAILED state then we have completed the current attempt.\n if (this.child.getState() === State.SUCCEEDED) {\n // The child has succeeded, meaning that this node has succeeded.\n this.setState(State.SUCCEEDED);\n\n return;\n } else if (this.child.getState() === State.FAILED) {\n // We have completed an attempt.\n this.currentAttemptCount += 1;\n }\n } else {\n // This node is in the 'FAILED' state as we cannot iterate any more.\n this.setState(State.FAILED);\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => {\n if (this.attempts !== null) {\n return `RETRY ${this.attempts}x`;\n } else if (this.attemptsMin !== null && this.attemptsMax !== null) {\n return `RETRY ${this.attemptsMin}x-${this.attemptsMax}x`;\n } else {\n return \"RETRY\";\n }\n };\n\n /**\n * Reset the state of the node.\n */\n reset = () => {\n // Reset the state of this node.\n this.setState(State.READY);\n\n // Reset the current attempt count.\n this.currentAttemptCount = 0;\n\n // Reset the child node.\n this.child.reset();\n };\n\n /**\n * Gets whether an attempt can be made.\n * @returns Whether an attempt can be made.\n */\n canAttempt = () => {\n if (this.targetAttemptCount !== null) {\n // We can attempt as long as we have not reached our target attempt count.\n return this.currentAttemptCount < this.targetAttemptCount;\n }\n\n // If neither an attempt count or a condition function were defined then we can attempt indefinitely.\n return true;\n };\n\n /**\n * Sets the target attempt count.\n * @param options The behaviour tree options object.\n */\n setTargetAttemptCount = (options: BehaviourTreeOptions) => {\n // Are we dealing with an explicit attempt count or will we be randomly picking an attempt count between the min and max attempt count.\n if (this.attempts !== null) {\n this.targetAttemptCount = this.attempts;\n } else if (this.attemptsMin !== null && this.attemptsMax !== null) {\n // We will be picking a random attempt count between a min and max attempt count, if the optional 'random'\n // behaviour tree function option is defined then we will be using that, otherwise we will fall back to using Math.random.\n const random = typeof options.random === \"function\" ? options.random : Math.random;\n\n // Pick a random attempt count between a min and max attempt count.\n this.targetAttemptCount = Math.floor(\n random() * (this.attemptsMax - this.attemptsMin + 1) + this.attemptsMin\n );\n } else {\n this.targetAttemptCount = null;\n }\n };\n}\n", "import Node from \"../Node\";\nimport Decorator from \"./Decorator\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A Root node.\n * The root node will have a single child.\n */\nexport default class Root extends Decorator {\n /**\n * @param attributes The node attributes.\n * @param child The child node.\n */\n constructor(attributes: Attribute[], child: Node) {\n super(\"root\", attributes, child);\n }\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // If the child has never been updated or is running then we will need to update it now.\n if (this.child.getState() === State.READY || this.child.getState() === State.RUNNING) {\n // Update the child of this node.\n this.child.update(agent, options);\n }\n\n // The state of the root node is the state of its child.\n this.setState(this.child.getState());\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => \"ROOT\";\n}\n", "import Node from \"../Node\";\nimport Decorator from \"./Decorator\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A Succeed node.\n * This node wraps a single child and will always move to the 'SUCCEEDED' state when the child moves to a 'SUCCEEDED' or 'FAILED' state.\n */\nexport default class Succeed extends Decorator {\n /**\n * @param attributes The node attributes.\n * @param child The child node.\n */\n constructor(attributes: Attribute[], child: Node) {\n super(\"succeed\", attributes, child);\n }\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // If the child has never been updated or is running then we will need to update it now.\n if (this.child.getState() === State.READY || this.child.getState() === State.RUNNING) {\n this.child.update(agent, options);\n }\n\n // The state of this node will depend in the state of its child.\n switch (this.child.getState()) {\n case State.RUNNING:\n this.setState(State.RUNNING);\n break;\n\n case State.SUCCEEDED:\n case State.FAILED:\n this.setState(State.SUCCEEDED);\n break;\n\n default:\n this.setState(State.READY);\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => \"SUCCEED\";\n}\n", "import Node from \"../Node\";\n\n/**\n * A leaf node.\n */\nexport default abstract class Leaf extends Node {\n /**\n * Gets whether this node is a leaf node.\n */\n isLeafNode = () => true;\n}\n", "import { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\nimport State, { CompleteState } from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Leaf from \"./Leaf\";\nimport Lookup from \"../../Lookup\";\nimport Attribute from \"../../attributes/Attribute\";\n\n/**\n * The type representing a resolved/rejected update promise.\n */\ntype UpdatePromiseResult = {\n /**\n * Whether the promise was resolved rather than rejected.\n */\n isResolved: boolean;\n\n /**\n * The promise resolved value or rejection reason.\n */\n value: any;\n};\n\n/**\n * An Action leaf node.\n * This represents an immediate or ongoing state of behaviour.\n */\nexport default class Action extends Leaf {\n /**\n * @param attributes The node attributes.\n * @param actionName The action name.\n * @param actionArguments The array of action argument definitions.\n */\n constructor(attributes: Attribute[], private actionName: string, private actionArguments: any[]) {\n super(\"action\", attributes, actionArguments);\n }\n\n /**\n * Whether there is a pending update promise.\n */\n private isUsingUpdatePromise = false;\n\n /**\n * The finished state result of an update promise.\n */\n private updatePromiseResult: UpdatePromiseResult | null = null;\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // If the result of this action depends on an update promise then there is nothing to do until it settles.\n if (this.isUsingUpdatePromise) {\n // Are we still waiting for our update promise to settle?\n if (!this.updatePromiseResult) {\n return;\n }\n\n const { isResolved, value } = this.updatePromiseResult;\n\n // Our update promise settled, was it resolved or rejected?\n if (isResolved) {\n // Our promise resolved so check to make sure the result is a valid finished state.\n if (value !== State.SUCCEEDED && value !== State.FAILED) {\n throw new Error(\n \"action node promise resolved with an invalid value, expected a State.SUCCEEDED or State.FAILED value to be returned\"\n );\n }\n\n // Set the state of this node to match the state returned by the promise.\n this.setState(value);\n\n return;\n } else {\n // The promise was rejected, which isn't great.\n throw new Error(`action function '${this.actionName}' promise rejected with '${value}'`);\n }\n }\n\n // Attempt to get the invoker for the action function.\n const actionFuncInvoker = Lookup.getFuncInvoker(agent, this.actionName);\n\n // The action function should be defined.\n if (actionFuncInvoker === null) {\n throw new Error(\n `cannot update action node as the action '${this.actionName}' function is not defined on the agent and has not been registered`\n );\n }\n\n let actionFunctionResult;\n\n try {\n // Call the action function, the result of which may be:\n // - The finished state of this action node.\n // - A promise to return a finished node state.\n // - Undefined if the node should remain in the running state.\n actionFunctionResult = actionFuncInvoker(this.actionArguments) as CompleteState | Promise;\n } catch (error) {\n // The user was naughty and threw something.\n throw new Error(`action function '${this.actionName}' threw '${error}'`);\n }\n\n if (actionFunctionResult instanceof Promise) {\n actionFunctionResult.then(\n (result) => {\n // If 'isUpdatePromisePending' is not set then the promise was cleared as it was resolving, probably via an abort of reset.\n if (!this.isUsingUpdatePromise) {\n return;\n }\n\n // Set the resolved update promise result so that it can be handled on the next update of this node.\n this.updatePromiseResult = {\n isResolved: true,\n value: result\n };\n },\n (reason) => {\n // If 'isUpdatePromisePending' is not set then the promise was cleared as it was resolving, probably via an abort or reset.\n if (!this.isUsingUpdatePromise) {\n return;\n }\n\n // Set the rejected update promise result so that it can be handled on the next update of this node.\n this.updatePromiseResult = {\n isResolved: false,\n value: reason\n };\n }\n );\n\n // This node will be in the 'RUNNING' state until the update promise resolves.\n this.setState(State.RUNNING);\n\n // We are now waiting for the promise returned by the use to resolve before we know what state this node is in.\n this.isUsingUpdatePromise = true;\n } else {\n // Validate the returned value.\n this.validateUpdateResult(actionFunctionResult);\n\n // Set the state of this node, this may be undefined, which just means that the node is still in the 'RUNNING' state.\n this.setState(actionFunctionResult || State.RUNNING);\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => this.actionName;\n\n /**\n * Reset the state of the node.\n */\n reset = () => {\n // Reset the state of this node.\n this.setState(State.READY);\n\n // There is no longer an update promise that we care about.\n this.isUsingUpdatePromise = false;\n this.updatePromiseResult = null;\n };\n\n /**\n * Validate the result of an update function call.\n * @param result The result of an update function call.\n */\n private validateUpdateResult = (result: CompleteState | State.RUNNING) => {\n switch (result) {\n case State.SUCCEEDED:\n case State.FAILED:\n case State.RUNNING:\n case undefined:\n return;\n default:\n throw new Error(\n `expected action function '${this.actionName}' to return an optional State.SUCCEEDED or State.FAILED value but returned '${result}'`\n );\n }\n };\n}\n", "import { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Leaf from \"./Leaf\";\nimport Lookup from \"../../Lookup\";\nimport Attribute from \"../../attributes/Attribute\";\n\n/**\n * A Condition leaf node.\n * This will succeed or fail immediately based on an agent predicate, without moving to the 'RUNNING' state.\n */\nexport default class Condition extends Leaf {\n /**\n * @param attributes The node attributes.\n * @param conditionName The name of the condition function.\n * @param conditionArguments The array of condition argument definitions.\n */\n constructor(attributes: Attribute[], private conditionName: string, private conditionArguments: any[]) {\n super(\"condition\", attributes, conditionArguments);\n }\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // Attempt to get the invoker for the condition function.\n const conditionFuncInvoker = Lookup.getFuncInvoker(agent, this.conditionName);\n\n // The condition function should be defined.\n if (conditionFuncInvoker === null) {\n throw new Error(\n `cannot update condition node as the condition '${this.conditionName}' function is not defined on the agent and has not been registered`\n );\n }\n\n let conditionFunctionResult;\n\n try {\n // Call the condition function to determine the state of this node, the result of which should be a boolean.\n conditionFunctionResult = conditionFuncInvoker(this.conditionArguments);\n } catch (error) {\n // The user was naughty and threw something.\n throw new Error(`condition function '${this.conditionName}' threw '${error}'`);\n }\n\n // The result of calling the condition function must be a boolean value.\n if (typeof conditionFunctionResult !== \"boolean\") {\n throw new Error(\n `expected condition function '${this.conditionName}' to return a boolean but returned '${conditionFunctionResult}'`\n );\n }\n\n // Set the state of this node based on the result of calling the condition function.\n this.setState(!!conditionFunctionResult ? State.SUCCEEDED : State.FAILED);\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => this.conditionName;\n}\n", "import Leaf from \"./Leaf\";\nimport State from \"../../State\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { Agent } from \"../../Agent\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A WAIT node.\n * The state of this node will change to SUCCEEDED after a duration of time\n */\nexport default class Wait extends Leaf {\n /**\n * @param attributes The node attributes.\n * @param duration The duration that this node will wait to succeed in milliseconds.\n * @param durationMin The minimum possible duration in milliseconds that this node will wait to succeed.\n * @param durationMax The maximum possible duration in milliseconds that this node will wait to succeed.\n */\n constructor(\n attributes: Attribute[],\n private duration: number | null,\n private durationMin: number | null,\n private durationMax: number | null\n ) {\n super(\"wait\", attributes, []);\n }\n\n /**\n * The time in milliseconds at which this node was first updated.\n */\n private initialUpdateTime: number = 0;\n\n /**\n * The total duration in milliseconds that this node will be waiting for.\n */\n private totalDuration: number | null = null;\n\n /**\n * The duration in milliseconds that this node has been waiting for.\n */\n private waitedDuration: number = 0;\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // If this node is in the READY state then we need to set the initial update time.\n if (this.is(State.READY)) {\n // Set the initial update time.\n this.initialUpdateTime = new Date().getTime();\n\n // Set the initial waited duration.\n this.waitedDuration = 0;\n\n // Are we dealing with an explicit duration or will we be randomly picking a duration between the min and max duration.\n if (this.duration !== null) {\n this.totalDuration = this.duration;\n } else if (this.durationMin !== null && this.durationMax !== null) {\n // We will be picking a random duration between a min and max duration, if the optional 'random' behaviour tree\n // function option is defined then we will be using that, otherwise we will fall back to using Math.random.\n const random = typeof options.random === \"function\" ? options.random : Math.random;\n\n // Pick a random duration between a min and max duration.\n this.totalDuration = Math.floor(\n random() * (this.durationMax - this.durationMin + 1) + this.durationMin\n );\n } else {\n this.totalDuration = null;\n }\n\n // The node is now running until we finish waiting.\n this.setState(State.RUNNING);\n }\n\n // If we have no total duration then this wait node will wait indefinitely until it is aborted.\n if (this.totalDuration === null) {\n return;\n }\n\n // If we have a 'getDeltaTime' function defined as part of our options then we will use it to figure out how long we have waited for.\n if (typeof options.getDeltaTime === \"function\") {\n // Get the delta time.\n const deltaTime = options.getDeltaTime();\n\n // Our delta time must be a valid number and cannot be NaN.\n if (typeof deltaTime !== \"number\" || isNaN(deltaTime)) {\n throw new Error(\"The delta time must be a valid number and not NaN.\");\n }\n\n // Update the amount of time that this node has been waiting for based on the delta time.\n this.waitedDuration += deltaTime * 1000;\n } else {\n // We are not using a delta time, so we will just work out hom much time has passed since the first update.\n this.waitedDuration = new Date().getTime() - this.initialUpdateTime;\n }\n\n // Have we waited long enough?\n if (this.waitedDuration >= this.totalDuration) {\n // We have finished waiting!\n this.setState(State.SUCCEEDED);\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => {\n if (this.duration !== null) {\n return `WAIT ${this.duration}ms`;\n } else if (this.durationMin !== null && this.durationMax !== null) {\n return `WAIT ${this.durationMin}ms-${this.durationMax}ms`;\n } else {\n return \"WAIT\";\n }\n };\n}\n", "import Guard from \"./guards/Guard\";\n\nexport type AttributeDetails = {\n /** The attribute type. */\n type: string;\n\n /** The attribute arguments. */\n args: any[];\n};\n\n/**\n * A base node attribute.\n */\nexport default abstract class Attribute {\n /**\n * @param type The node attribute type.\n * @param args The array of attribute arguments.\n */\n constructor(public type: string, public args: any[]) {}\n\n /**\n * Gets the attribute details.\n */\n abstract getDetails(): TAttributeDetails;\n\n /**\n * Gets whether this attribute is a guard.\n */\n abstract isGuard: () => this is Guard;\n}\n", "import { Agent } from \"../../Agent\";\nimport Attribute, { AttributeDetails } from \"../Attribute\";\n\nexport type GuardAttributeDetails = {\n /** The name of the condition function that determines whether the guard is satisfied. */\n condition: string;\n} & AttributeDetails;\n\n/**\n * A base node guard attribute.\n */\nexport default abstract class Guard extends Attribute {\n /**\n * @param type The node attribute type.\n * @param args The array of decorator argument definitions.\n * @param condition The name of the condition function that determines whether the guard is satisfied.\n */\n constructor(type: string, args: any[], private condition: string) {\n super(type, args);\n }\n\n /**\n * Gets the name of the condition function that determines whether the guard is satisfied.\n */\n getCondition = () => this.condition;\n\n /**\n * Gets whether this attribute is a guard.\n */\n isGuard = () => true;\n\n /**\n * Gets the attribute details.\n */\n getDetails(): GuardAttributeDetails {\n return {\n type: this.type,\n args: this.args,\n condition: this.getCondition()\n };\n }\n\n /**\n * Gets whether the guard is satisfied.\n * @param agent The agent.\n * @returns Whether the guard is satisfied.\n */\n abstract isSatisfied(agent: Agent): boolean;\n}\n", "import Guard from \"./Guard\";\nimport Lookup from \"../../Lookup\";\nimport { Agent } from \"../../Agent\";\n\n/**\n * A WHILE guard which is satisfied as long as the given condition remains true.\n */\nexport default class While extends Guard {\n /**\n * @param condition The name of the condition function that determines whether the guard is satisfied.\n * @param args The array of decorator argument definitions.\n */\n constructor(condition: string, args: any[]) {\n super(\"while\", args, condition);\n }\n\n /**\n * Gets whether the guard is satisfied.\n * @param agent The agent.\n * @returns Whether the guard is satisfied.\n */\n isSatisfied = (agent: Agent) => {\n // Attempt to get the invoker for the condition function.\n const conditionFuncInvoker = Lookup.getFuncInvoker(agent, this.getCondition());\n\n // The condition function should be defined.\n if (conditionFuncInvoker === null) {\n throw new Error(\n `cannot evaluate node guard as the condition '${this.getCondition()}' function is not defined on the agent and has not been registered`\n );\n }\n\n // Call the condition function to determine whether this guard is satisfied.\n return !!conditionFuncInvoker(this.args);\n };\n}\n", "import Guard from \"./Guard\";\nimport Lookup from \"../../Lookup\";\nimport { Agent } from \"../../Agent\";\n\n/**\n * An UNTIL guard which is satisfied as long as the given condition remains false.\n */\nexport default class Until extends Guard {\n /**\n * @param condition The name of the condition function that determines whether the guard is satisfied.\n * @param args The array of decorator argument definitions.\n */\n constructor(condition: string, args: any[]) {\n super(\"until\", args, condition);\n }\n\n /**\n * Gets whether the guard is satisfied.\n * @param agent The agent.\n * @returns Whether the guard is satisfied.\n */\n isSatisfied = (agent: Agent) => {\n // Attempt to get the invoker for the condition function.\n const conditionFuncInvoker = Lookup.getFuncInvoker(agent, this.getCondition());\n\n // The condition function should be defined.\n if (conditionFuncInvoker === null) {\n throw new Error(\n `cannot evaluate node guard as the condition '${this.getCondition()}' function is not defined on the agent and has not been registered`\n );\n }\n\n // Call the condition function to determine whether this guard is satisfied.\n return !!!conditionFuncInvoker(this.args);\n };\n}\n", "import { Agent } from \"../../Agent\";\nimport Attribute, { AttributeDetails } from \"../Attribute\";\n\nexport type CallbackAttributeDetails = {\n /** The name of the agent function that is called. */\n functionName: string;\n} & AttributeDetails;\n\n/**\n * A base node callback attribute.\n */\nexport default abstract class Callback extends Attribute {\n /**\n * @param type The node attribute type.\n * @param args The array of decorator argument definitions.\n * @param functionName The name of the agent function to call.\n */\n constructor(type: string, args: any[], private functionName: string) {\n super(type, args);\n }\n\n /**\n * Gets the name of the agent function to call.\n */\n getFunctionName = () => this.functionName;\n\n /**\n * Gets whether this attribute is a guard.\n */\n isGuard = () => false;\n\n /**\n * Gets the attribute details.\n */\n getDetails(): CallbackAttributeDetails {\n return {\n type: this.type,\n args: this.args,\n functionName: this.getFunctionName()\n };\n }\n\n /**\n * Attempt to call the agent function that this callback refers to.\n * @param agent The agent.\n */\n abstract callAgentFunction: (agent: Agent, isSuccess: boolean, isAborted: boolean) => void;\n}\n", "import Callback from \"./Callback\";\nimport Lookup from \"../../Lookup\";\nimport { Agent } from \"../../Agent\";\n\n/**\n * An ENTRY callback which defines an agent function to call when the associated node is updated and moves out of running state.\n */\nexport default class Entry extends Callback {\n /**\n * @param functionName The name of the agent function to call.\n * @param args The array of callback argument definitions.\n */\n constructor(functionName: string, args: any[]) {\n super(\"entry\", args, functionName);\n }\n\n /**\n * Attempt to call the agent function that this callback refers to.\n * @param agent The agent.\n */\n callAgentFunction = (agent: Agent) => {\n // Attempt to get the invoker for the callback function.\n const callbackFuncInvoker = Lookup.getFuncInvoker(agent, this.getFunctionName());\n\n // The callback function should be defined.\n if (callbackFuncInvoker === null) {\n throw new Error(\n `cannot call entry function '${this.getFunctionName()}' as is not defined on the agent and has not been registered`\n );\n }\n\n // Call the callback function.\n callbackFuncInvoker(this.args);\n };\n}\n", "import Callback from \"./Callback\";\nimport Lookup from \"../../Lookup\";\nimport { Agent } from \"../../Agent\";\n\n/**\n * A STEP callback which defines an agent function to call when the associated node is updated.\n */\nexport default class Step extends Callback {\n /**\n * @param functionName The name of the agent function to call.\n * @param args The array of callback argument definitions.\n */\n constructor(functionName: string, args: any[]) {\n super(\"step\", args, functionName);\n }\n\n /**\n * Attempt to call the agent function that this callback refers to.\n * @param agent The agent.\n */\n callAgentFunction = (agent: Agent) => {\n // Attempt to get the invoker for the callback function.\n const callbackFuncInvoker = Lookup.getFuncInvoker(agent, this.getFunctionName());\n\n // The callback function should be defined.\n if (callbackFuncInvoker === null) {\n throw new Error(\n `cannot call step function '${this.getFunctionName()}' as is not defined on the agent and has not been registered`\n );\n }\n\n // Call the callback function.\n callbackFuncInvoker(this.args);\n };\n}\n", "import Callback from \"./Callback\";\nimport Lookup from \"../../Lookup\";\nimport { Agent } from \"../../Agent\";\n\n/**\n * An EXIT callback which defines an agent function to call when the associated node is updated and moves to a finished state or is aborted.\n */\nexport default class Exit extends Callback {\n /**\n * @param functionName The name of the agent function to call.\n * @param args The array of callback argument definitions.\n */\n constructor(functionName: string, args: any[]) {\n super(\"exit\", args, functionName);\n }\n\n /**\n * Attempt to call the agent function that this callback refers to.\n * @param agent The agent.\n * @param isSuccess Whether the decorated node was left with a success state.\n * @param isAborted Whether the decorated node was aborted.\n */\n callAgentFunction = (agent: Agent, isSuccess: boolean, isAborted: boolean) => {\n // Attempt to get the invoker for the callback function.\n const callbackFuncInvoker = Lookup.getFuncInvoker(agent, this.getFunctionName());\n\n // The callback function should be defined.\n if (callbackFuncInvoker === null) {\n throw new Error(\n `cannot call exit function '${this.getFunctionName()}' as is not defined on the agent and has not been registered`\n );\n }\n\n // Call the callback function\n callbackFuncInvoker([{ value: { succeeded: isSuccess, aborted: isAborted } }, ...this.args]);\n };\n}\n", "import { AnyNodeDefinition, RootNodeDefinition } from \"./BehaviourTreeDefinition\";\nimport GuardPath, { GuardPathPart } from \"./attributes/guards/GuardPath\";\nimport { validateBranchSubtreeLinks } from \"./BehaviourTreeDefinitionValidator\";\nimport { isInteger } from \"./BehaviourTreeDefinitionUtilities\";\nimport Node from \"./nodes/Node\";\nimport Composite from \"./nodes/composite/Composite\";\nimport Decorator from \"./nodes/decorator/Decorator\";\nimport Parallel from \"./nodes/composite/Parallel\";\nimport Selector from \"./nodes/composite/Selector\";\nimport Sequence from \"./nodes/composite/Sequence\";\nimport Lotto from \"./nodes/composite/Lotto\";\nimport Fail from \"./nodes/decorator/Fail\";\nimport Flip from \"./nodes/decorator/Flip\";\nimport Repeat from \"./nodes/decorator/Repeat\";\nimport Retry from \"./nodes/decorator/Retry\";\nimport Root from \"./nodes/decorator/Root\";\nimport Succeed from \"./nodes/decorator/Succeed\";\nimport Action from \"./nodes/leaf/Action\";\nimport Condition from \"./nodes/leaf/Condition\";\nimport Wait from \"./nodes/leaf/Wait\";\nimport Lookup from \"./Lookup\";\nimport Attribute from \"./attributes/Attribute\";\nimport While from \"./attributes/guards/While\";\nimport Until from \"./attributes/guards/Until\";\nimport Entry from \"./attributes/callbacks/Entry\";\nimport Step from \"./attributes/callbacks/Step\";\nimport Exit from \"./attributes/callbacks/Exit\";\n\n/**\n * A type representing any node instance in a behaviour tree.\n */\ntype AnyNode =\n | Root\n | Action\n | Condition\n | Wait\n | Sequence\n | Selector\n | Lotto\n | Parallel\n | Repeat\n | Retry\n | Flip\n | Succeed\n | Fail;\n\n/**\n * A type defining a mapping of root node identifiers to root node definitions.\n */\ntype RootNodeDefinitionMap = { [key: string | symbol]: RootNodeDefinition };\n\n/**\n * A symbol to use as the main root key in any root node mappings.\n */\nconst MAIN_ROOT_NODE_KEY = Symbol(\"__root__\");\n\n/**\n * Build and populate the root nodes based on the provided definition, assuming that the definition has been validated.\n * @param definition The root node definitions.\n * @returns The built and populated root node definitions.\n */\nexport default function buildRootNode(definition: RootNodeDefinition[]): Root {\n // Create a mapping of root node identifers to root node definitions, including globally registered subtree root node definitions.\n const rootNodeDefinitionMap = createRootNodeDefinitionMap(definition);\n\n // Now that we have all of our root node definitions (those part of the tree definition and those globally registered)\n // we should validate the branch-subtree links. This will also double-check that we dont have any circular dependencies\n // in our branch-subtree references and that we have no broken branch-subtree links.\n validateBranchSubtreeLinks(\n [rootNodeDefinitionMap[MAIN_ROOT_NODE_KEY], ...Object.values(rootNodeDefinitionMap)],\n true\n );\n\n // Create our populated tree of node instances, starting with our main root node.\n const rootNode = nodeFactory(rootNodeDefinitionMap[MAIN_ROOT_NODE_KEY], rootNodeDefinitionMap) as Root;\n\n // Set a guard path on every leaf of the tree to evaluate as part of each update.\n applyLeafNodeGuardPaths(rootNode);\n\n // We only need to return the main root node.\n return rootNode;\n}\n\n/**\n * A factory function which creates a node instance based on the specified definition.\n * @param definition The node definition.\n * @param rootNodeDefinitionMap The mapping of root node identifers to root node definitions, including globally registered subtree root node definitions.\n * @returns A node instance based on the specified definition.\n */\nfunction nodeFactory(definition: AnyNodeDefinition, rootNodeDefinitionMap: RootNodeDefinitionMap): AnyNode {\n // Get the attributes for the node.\n const attributes = nodeAttributesFactory(definition);\n\n // Create the node instance based on the definition type.\n switch (definition.type) {\n case \"root\":\n return new Root(attributes, nodeFactory(definition.child, rootNodeDefinitionMap));\n\n case \"repeat\":\n let iterations: number | null = null;\n let iterationsMin: number | null = null;\n let iterationsMax: number | null = null;\n\n if (Array.isArray(definition.iterations)) {\n iterationsMin = definition.iterations[0];\n iterationsMax = definition.iterations[1];\n } else if (isInteger(definition.iterations)) {\n iterations = definition.iterations!;\n }\n\n return new Repeat(\n attributes,\n iterations,\n iterationsMin,\n iterationsMax,\n nodeFactory(definition.child, rootNodeDefinitionMap)\n );\n\n case \"retry\":\n let attempts: number | null = null;\n let attemptsMin: number | null = null;\n let attemptsMax: number | null = null;\n\n if (Array.isArray(definition.attempts)) {\n attemptsMin = definition.attempts[0];\n attemptsMax = definition.attempts[1];\n } else if (isInteger(definition.attempts)) {\n attempts = definition.attempts!;\n }\n\n return new Retry(\n attributes,\n attempts,\n attemptsMin,\n attemptsMax,\n nodeFactory(definition.child, rootNodeDefinitionMap)\n );\n\n case \"flip\":\n return new Flip(attributes, nodeFactory(definition.child, rootNodeDefinitionMap));\n\n case \"succeed\":\n return new Succeed(attributes, nodeFactory(definition.child, rootNodeDefinitionMap));\n\n case \"fail\":\n return new Fail(attributes, nodeFactory(definition.child, rootNodeDefinitionMap));\n\n case \"sequence\":\n return new Sequence(\n attributes,\n definition.children.map((child) => nodeFactory(child, rootNodeDefinitionMap))\n );\n\n case \"selector\":\n return new Selector(\n attributes,\n definition.children.map((child) => nodeFactory(child, rootNodeDefinitionMap))\n );\n\n case \"parallel\":\n return new Parallel(\n attributes,\n definition.children.map((child) => nodeFactory(child, rootNodeDefinitionMap))\n );\n\n case \"lotto\":\n return new Lotto(\n attributes,\n definition.weights,\n definition.children.map((child) => nodeFactory(child, rootNodeDefinitionMap))\n );\n\n case \"branch\":\n return nodeFactory(rootNodeDefinitionMap[definition.ref].child, rootNodeDefinitionMap);\n\n case \"action\":\n return new Action(attributes, definition.call, definition.args || []);\n\n case \"condition\":\n return new Condition(attributes, definition.call, definition.args || []);\n\n case \"wait\":\n let duration: number | null = null;\n let durationMin: number | null = null;\n let durationMax: number | null = null;\n\n if (Array.isArray(definition.duration)) {\n durationMin = definition.duration[0];\n durationMax = definition.duration[1];\n } else if (isInteger(definition.duration)) {\n duration = definition.duration!;\n }\n\n return new Wait(attributes, duration, durationMin, durationMax);\n }\n}\n\n/**\n * Creates an array of node attribute instances based on the specified node definition.\n * @param definition The node definition.\n * @returns An array of node attribute instances based on the specified node definition.\n */\nfunction nodeAttributesFactory(definition: AnyNodeDefinition): Attribute[] {\n const attributes: Attribute[] = [];\n\n if (definition.while) {\n attributes.push(new While(definition.while.call, definition.while.args ?? []));\n }\n\n if (definition.until) {\n attributes.push(new Until(definition.until.call, definition.until.args ?? []));\n }\n\n if (definition.entry) {\n attributes.push(new Entry(definition.entry.call, definition.entry.args ?? []));\n }\n\n if (definition.step) {\n attributes.push(new Step(definition.step.call, definition.step.args ?? []));\n }\n\n if (definition.exit) {\n attributes.push(new Exit(definition.exit.call, definition.exit.args ?? []));\n }\n\n return attributes;\n}\n\n/**\n * Creates a mapping of root node identifers to root node definitions, mixing in globally registered subtree root node definitions.\n * @param definition The root node definitions.\n * @returns A mapping of root node identifers to root node definitions, including globally registered subtree root node definitions.\n */\nfunction createRootNodeDefinitionMap(definition: RootNodeDefinition[]): RootNodeDefinitionMap {\n // Create a mapping of root node identifers to root node definitions.\n const rootNodeMap: RootNodeDefinitionMap = {};\n\n // Add in any registered subtree root node definitions.\n for (const [name, rootNodeDefinition] of Object.entries(Lookup.getSubtrees())) {\n // The name used when registering the subtree will be used as the root node identifier.\n rootNodeMap[name] = { ...rootNodeDefinition, id: name };\n }\n\n // Populate the map with the root node definitions that were included with the tree definition.\n // We do this after adding any registered subtrees as we want these to take presedence.\n for (const rootNodeDefinition of definition) {\n rootNodeMap[rootNodeDefinition.id ?? MAIN_ROOT_NODE_KEY] = rootNodeDefinition;\n }\n\n return rootNodeMap;\n}\n\n/**\n * Applies a guard path to every leaf of the tree to evaluate as part of each update.\n * @param root The main root tree node.\n */\nfunction applyLeafNodeGuardPaths(root: Root) {\n const nodePaths: Node[][] = [];\n\n const findLeafNodes = (path: Node[], node: Node) => {\n // Add the current node to the path.\n path = path.concat(node);\n\n // Check whether the current node is a leaf node.\n if (node.isLeafNode()) {\n nodePaths.push(path);\n } else {\n (node as Composite | Decorator).getChildren().forEach((child) => findLeafNodes(path, child));\n }\n };\n\n // Find all leaf node paths, starting from the root.\n findLeafNodes([], root);\n\n nodePaths.forEach((path) => {\n // Each node in the current path will have to be assigned a guard path, working from the root outwards.\n for (let depth = 0; depth < path.length; depth++) {\n // Get the node in the path at the current depth.\n const currentNode = path[depth];\n\n // The node may already have been assigned a guard path, if so just skip it.\n if (currentNode.hasGuardPath()) {\n continue;\n }\n\n // Create the guard path for the current node.\n const guardPath = new GuardPath(\n path\n .slice(0, depth + 1)\n .map((node) => ({ node, guards: node.getGuardAttributes() }))\n .filter((details) => details.guards.length > 0)\n );\n\n // Assign the guard path to the current node.\n currentNode.setGuardPath(guardPath);\n }\n });\n}\n", "import State, { AnyState } from \"./State\";\nimport Lookup from \"./Lookup\";\nimport Node from \"./nodes/Node\";\nimport Root from \"./nodes/decorator/Root\";\nimport Composite from \"./nodes/composite/Composite\";\nimport Decorator from \"./nodes/decorator/Decorator\";\nimport { Agent, GlobalFunction } from \"./Agent\";\nimport { CallbackAttributeDetails } from \"./attributes/callbacks/Callback\";\nimport { GuardAttributeDetails } from \"./attributes/guards/Guard\";\nimport { BehaviourTreeOptions } from \"./BehaviourTreeOptions\";\nimport { convertMDSLToJSON } from \"./mdsl/MDSLDefinitionParser\";\nimport { RootNodeDefinition } from \"./BehaviourTreeDefinition\";\nimport { validateDefinition, validateJSONDefinition } from \"./BehaviourTreeDefinitionValidator\";\nimport buildRootNode from \"./BehaviourTreeBuilder\";\nimport { isNullOrUndefined } from \"./BehaviourTreeDefinitionUtilities\";\n\n// Purely for outside inspection of the tree.\nexport type FlattenedTreeNode = {\n id: string;\n type: string;\n caption: string;\n state: AnyState;\n guards: GuardAttributeDetails[];\n callbacks: CallbackAttributeDetails[];\n args: any[];\n parentId: string | null;\n};\n\n/**\n * A representation of a behaviour tree.\n */\nexport class BehaviourTree {\n /**\n * The main root tree node.\n */\n private readonly _rootNode: Root;\n\n /**\n * Creates a new instance of the BehaviourTree class.\n * @param definition The behaviour tree definition as either an MDSL string, root node definition object or array of root node definition objects.\n * @param agent The agent instance that this behaviour tree is modelling behaviour for.\n * @param options The behaviour tree options object.\n */\n constructor(\n definition: string | RootNodeDefinition | RootNodeDefinition[],\n private agent: Agent,\n private options: BehaviourTreeOptions = {}\n ) {\n // The tree definition must be defined.\n if (isNullOrUndefined(definition)) {\n throw new Error(\"tree definition not defined\");\n }\n\n // The agent must be defined and not null.\n if (typeof agent !== \"object\" || agent === null) {\n throw new Error(\"the agent must be an object and not null\");\n }\n\n // We should validate the definition before we try to build the tree nodes.\n const { succeeded, errorMessage, json } = validateDefinition(definition);\n\n // Did our validation fail without error?\n if (!succeeded) {\n throw new Error(`invalid definition: ${errorMessage}`);\n }\n\n // Double check that we did actually get our json definition as part of our definition validtion.\n if (!json) {\n throw new Error(\n \"expected json definition to be returned as part of successful definition validation response\"\n );\n }\n\n try {\n // Create the populated tree of behaviour tree nodes and get the root node.\n this._rootNode = buildRootNode(json);\n } catch (exception) {\n // There was an issue in trying build and populate the behaviour tree.\n throw new Error(`error building tree: ${(exception as Error).message}`);\n }\n }\n\n /**\n * Gets whether the tree is in the RUNNING state.\n * @returns true if the tree is in the RUNNING state, otherwise false.\n */\n isRunning() {\n return this._rootNode.getState() === State.RUNNING;\n }\n\n /**\n * Gets the current tree state of SUCCEEDED, FAILED, READY or RUNNING.\n * @returns The current tree state.\n */\n getState() {\n return this._rootNode.getState();\n }\n\n /**\n * Step the tree.\n * 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.\n * 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\n * 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.\n *\n * 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.\n */\n step() {\n // If the root node has already been stepped to completion then we need to reset it.\n if (this._rootNode.getState() === State.SUCCEEDED || this._rootNode.getState() === State.FAILED) {\n this._rootNode.reset();\n }\n\n try {\n this._rootNode.update(this.agent, this.options);\n } catch (exception) {\n throw new Error(`error stepping tree: ${(exception as Error).message}`);\n }\n }\n\n /**\n * Resets the tree from the root node outwards to each nested node, giving each a state of READY.\n */\n reset() {\n this._rootNode.reset();\n }\n\n /**\n * Gets the flattened details of every node in the tree.\n * @returns The flattened details of every node in the tree.\n */\n getFlattenedNodeDetails(): FlattenedTreeNode[] {\n // Create an empty flattened array of tree nodes.\n const flattenedTreeNodes: FlattenedTreeNode[] = [];\n\n /**\n * Helper function to process a node instance and push details into the flattened tree nodes array.\n * @param node The current node.\n * @param parentUid The UID of the node parent, or null if the node is the main root node.\n */\n const processNode = (node: Node, parentUid: string | null) => {\n // Get the guard and callback attribute details for this node.\n const guards = node\n .getAttributes()\n .filter((attribute) => attribute.isGuard())\n .map((attribute) => attribute.getDetails()) as GuardAttributeDetails[];\n const callbacks = node\n .getAttributes()\n .filter((attribute) => !attribute.isGuard())\n .map((attribute) => attribute.getDetails()) as CallbackAttributeDetails[];\n\n // Push the current node into the flattened nodes array.\n flattenedTreeNodes.push({\n id: node.getUid(),\n type: node.getType(),\n caption: node.getName(),\n state: node.getState(),\n guards,\n callbacks,\n args: node.getArguments(),\n parentId: parentUid\n });\n\n // Process each of the nodes children if it is not a leaf node.\n if (!node.isLeafNode()) {\n (node as Composite | Decorator)\n .getChildren()\n .forEach((child) => processNode(child, (node as Composite | Decorator).getUid()));\n }\n };\n\n // Convert the nested node structure into a flattened array of node details.\n processNode(this._rootNode, null);\n\n return flattenedTreeNodes;\n }\n\n /**\n * Registers the action/condition/guard/callback function or subtree with the given name.\n * @param name The name of the function or subtree to register.\n * @param value The function or subtree definition to register.\n */\n static register(name: string, value: GlobalFunction | string | RootNodeDefinition) {\n // Are we going to register a action/condition/guard/callback function?\n if (typeof value === \"function\") {\n Lookup.setFunc(name, value);\n return;\n }\n\n // We are not registering an action/condition/guard/callback function, so we must be registering a subtree.\n if (typeof value === \"string\") {\n let rootNodeDefinitions: RootNodeDefinition[];\n\n // We will assume that any string passed in will be a mdsl definition.\n try {\n rootNodeDefinitions = convertMDSLToJSON(value);\n } catch (exception) {\n throw new Error(`error registering definition, invalid MDSL: ${(exception as Error).message}`);\n }\n\n // This function should only ever be called with a definition containing a single unnamed root node.\n if (rootNodeDefinitions.length != 1 || rootNodeDefinitions[0].id !== null) {\n throw new Error(\"error registering definition: expected a single unnamed root node\");\n }\n\n try {\n // We should validate the subtree as we don't want invalid subtrees available via the lookup.\n const { succeeded, errorMessage } = validateJSONDefinition(rootNodeDefinitions[0]);\n\n // Did our validation fail without error?\n if (!succeeded) {\n throw new Error(errorMessage);\n }\n } catch (exception) {\n throw new Error(`error registering definition: ${(exception as Error).message}`);\n }\n\n // Everything seems hunky-dory, register the subtree.\n Lookup.setSubtree(name, rootNodeDefinitions[0]);\n } else if (typeof value === \"object\" && !Array.isArray(value)) {\n // We will assume that any object passed in is a root node definition.\n\n try {\n // We should validate the subtree as we don't want invalid subtrees available via the lookup.\n const { succeeded, errorMessage } = validateJSONDefinition(value);\n\n // Did our validation fail without error?\n if (!succeeded) {\n throw new Error(errorMessage);\n }\n } catch (exception) {\n throw new Error(`error registering definition: ${(exception as Error).message}`);\n }\n\n // Everything seems hunky-dory, register the subtree.\n Lookup.setSubtree(name, value);\n } else {\n throw new Error(\"unexpected value, expected string mdsl definition, root node json definition or function\");\n }\n }\n\n /**\n * Unregisters the registered action/condition/guard/callback function or subtree with the given name.\n * @param name The name of the registered action/condition/guard/callback function or subtree to unregister.\n */\n static unregister(name: string): void {\n Lookup.remove(name);\n }\n\n /**\n * Unregister all registered action/condition/guard/callback functions and subtrees.\n */\n static unregisterAll(): void {\n Lookup.empty();\n }\n}\n"], - "mappings": "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", + "sourcesContent": ["\"use strict\";\r\nObject.defineProperty(exports, \"__esModule\", { value: true });\r\nexports.Participant = void 0;\r\n/**\r\n * A participant that holds a number of tickets.\r\n */\r\nvar Participant = /** @class */ (function () {\r\n /**\r\n * Creates an instance of the Participant class.\r\n * @param participant The actual participant.\r\n * @param tickets The number of tickets held by the participant.\r\n */\r\n function Participant(participant, tickets) {\r\n if (tickets === void 0) { tickets = 1; }\r\n this._participant = participant;\r\n this._tickets = tickets;\r\n }\r\n Object.defineProperty(Participant.prototype, \"participant\", {\r\n /** Gets the actual participant. */\r\n get: function () {\r\n return this._participant;\r\n },\r\n enumerable: false,\r\n configurable: true\r\n });\r\n Object.defineProperty(Participant.prototype, \"tickets\", {\r\n /** Gets or sets the number of tickets held by the participant. */\r\n get: function () {\r\n return this._tickets;\r\n },\r\n set: function (value) {\r\n this._tickets = value;\r\n },\r\n enumerable: false,\r\n configurable: true\r\n });\r\n return Participant;\r\n}());\r\nexports.Participant = Participant;\r\n", "\"use strict\";\r\nObject.defineProperty(exports, \"__esModule\", { value: true });\r\nexports.isNaturalNumber = exports.isNullOrUndefined = void 0;\r\n/**\r\n * Gets whether the value provided is null or undefined.\r\n * @param value The value to check.\r\n * @returns Whether the value provided is null or undefined.\r\n */\r\nfunction isNullOrUndefined(value) {\r\n return value === null || value === undefined;\r\n}\r\nexports.isNullOrUndefined = isNullOrUndefined;\r\n/**\r\n * Gets whether the value provided is a natural number.\r\n * @param value The value to check.\r\n * @returns Whether the value provided is a natural number.\r\n */\r\nfunction isNaturalNumber(value) {\r\n return typeof value === \"number\" && value >= 1 && Math.floor(value) === value;\r\n}\r\nexports.isNaturalNumber = isNaturalNumber;\r\n", "\"use strict\";\r\nObject.defineProperty(exports, \"__esModule\", { value: true });\r\nexports.Lotto = void 0;\r\nvar Participant_1 = require(\"./Participant\");\r\nvar Utilities_1 = require(\"./Utilities\");\r\n/**\r\n * Represents a lotto consisting of a number of pickable ticket-holding participants.\r\n */\r\nvar Lotto = /** @class */ (function () {\r\n /**\r\n * Creates a new instance of Lotto.\r\n * @param customRandom The custom RNG to use in place of Math.random().\r\n */\r\n function Lotto(customRandom) {\r\n /** The array of participants that are holding tickets in the lotto. */\r\n this._participants = [];\r\n this._customRandom = customRandom;\r\n }\r\n /**\r\n * Adds a participant with the specified number of tickets, or adds to the participant ticket count if the participant already holds tickets.\r\n * @param participant The participant to add or to increase the ticket count for if they already hold tickets.\r\n * @param tickets The number of tickets, defaults to 1.\r\n * @returns The Lotto instance.\r\n */\r\n Lotto.prototype.add = function (participant, tickets) {\r\n if (tickets === void 0) { tickets = 1; }\r\n // Check that we have a valid ticket count.\r\n if (!(0, Utilities_1.isNaturalNumber)(tickets)) {\r\n throw new Error(\"tickets value must be a natural number\");\r\n }\r\n // Check whether this participant has already been added.\r\n var existingParticipant = this._participants.find(function (part) { return part.participant === participant; });\r\n if (existingParticipant) {\r\n // The participant has already been added to the lotto so just add to their ticket count.\r\n existingParticipant.tickets += tickets;\r\n }\r\n else {\r\n // The participant is not part of the lotto so we should add them.\r\n this._participants.push(new Participant_1.Participant(participant, tickets));\r\n }\r\n return this;\r\n };\r\n /**\r\n * Removes the specified number of tickets for the given participant from the draw, or all tickets if a ticket number is not defined.\r\n * @param participant The participant to remove tickets for.\r\n * @param tickets The number of tickets to remove, or undefined if all tickets are to be removed.\r\n * @returns The Lotto instance.\r\n */\r\n Lotto.prototype.remove = function (participant, tickets) {\r\n // Attempt to get the existing participant.\r\n var existingParticipant = this._participants.find(function (part) { return part.participant === participant; });\r\n // There is nothing to do if the specified participant isn't even part of the lotto.\r\n if (!existingParticipant) {\r\n return this;\r\n }\r\n // Check whether a tickets value was given.\r\n if (tickets !== undefined) {\r\n // Check that we have a valid ticket count.\r\n if (!(0, Utilities_1.isNaturalNumber)(tickets)) {\r\n throw new Error(\"tickets value must be a natural number\");\r\n }\r\n existingParticipant.tickets -= tickets;\r\n // If the participant no longer holds any tickets then they should be removed.\r\n if (existingParticipant.tickets < 1) {\r\n this._participants = this._participants.filter(function (part) { return part !== existingParticipant; });\r\n }\r\n }\r\n else {\r\n // We are removing all tickets for the participant so just remove them from the lotto.\r\n this._participants = this._participants.filter(function (part) { return part !== existingParticipant; });\r\n }\r\n return this;\r\n };\r\n /**\r\n * Draw a winning ticket and return the participant that holds the ticket.\r\n * @param options The draw options.\r\n * @returns The participant that holds the winning ticket.\r\n */\r\n Lotto.prototype.draw = function (options) {\r\n if (options === void 0) { options = {}; }\r\n // If we have no participants then just return null.\r\n if (this._participants.length === 0) {\r\n return null;\r\n }\r\n var redrawable = (0, Utilities_1.isNullOrUndefined)(options.redrawable) ? true : options.redrawable;\r\n var pickable = [];\r\n this._participants.forEach(function (_a) {\r\n var participant = _a.participant, tickets = _a.tickets;\r\n for (var ticketCount = 0; ticketCount < tickets; ticketCount++) {\r\n pickable.push(participant);\r\n }\r\n });\r\n var random;\r\n // We need a random floating-point number between 0 (inclusive) and 1 to scale up to pick our winner.\r\n // If a custom random function exists then we should use that or fall back to Math.random().\r\n if (this._customRandom) {\r\n // Call our custom random function to get a random floating-point number.\r\n random = this._customRandom();\r\n // Verify that the result of calling our custom random function is a number between 0 (inclusive) and 1.\r\n if (typeof random !== \"number\" || random < 0 || random >= 1) {\r\n throw new Error(\"the 'random' function provided did not return a number between 0 (inclusive) and 1\");\r\n }\r\n }\r\n else {\r\n // No custom random function was defined so just use good ol' Math.random().\r\n random = Math.random();\r\n }\r\n // Pick a winning participant.\r\n var winner = pickable[Math.floor(random * pickable.length)];\r\n // If the ticket isn't redrawable then we should remove a ticket from the winning participants ticket count.\r\n if (!redrawable) {\r\n this.remove(winner, 1);\r\n }\r\n // Return the winning participant.\r\n return winner;\r\n };\r\n /**\r\n * Draws multiple winning tickets and return an array of the participants that hold the winning tickets.\r\n * @param tickets The number of winning tickets to draw.\r\n * @param options The draw multiple options.\r\n * @returns An array of the participants that hold the winning tickets.\r\n */\r\n Lotto.prototype.drawMultiple = function (tickets, options) {\r\n if (options === void 0) { options = {}; }\r\n var uniqueResults = (0, Utilities_1.isNullOrUndefined)(options.unique) ? false : options.unique;\r\n // Handle cases where the user has asked for zero tickets (no idea why they would do this be we should trust them).\r\n if (tickets === 0) {\r\n return [];\r\n }\r\n // Now that we know out tickets value is not zero we should check that it is a valid natural number.\r\n if (!(0, Utilities_1.isNaturalNumber)(tickets)) {\r\n throw new Error(\"tickets value must be a natural number\");\r\n }\r\n var result = [];\r\n // Keep drawing tickets until we either reach the number of required tickets or we simply run out of tickets to draw.\r\n // We can run out of tickets to draw if 'options.redrawable' is explicity 'false' or we just had no participants when 'drawMultiple' was called.\r\n while (result.length < tickets && this._participants.length > 0) {\r\n result.push(this.draw(options));\r\n }\r\n // If the 'unique' draw option is set then we need to remove duplicates from the result list.\r\n if (uniqueResults) {\r\n // Create an array to store our unique results.\r\n var unique = [];\r\n // Iterate over all of our participants (with potential duplicates) and populate our array of unique values.\r\n for (var _i = 0, result_1 = result; _i < result_1.length; _i++) {\r\n var participant = result_1[_i];\r\n if (unique.indexOf(participant) === -1) {\r\n unique.push(participant);\r\n }\r\n }\r\n result = unique;\r\n }\r\n return result;\r\n };\r\n return Lotto;\r\n}());\r\nexports.Lotto = Lotto;\r\n", "\"use strict\";\r\nObject.defineProperty(exports, \"__esModule\", { value: true });\r\nexports.createLotto = void 0;\r\nvar Lotto_1 = require(\"./Lotto\");\r\n/**\r\n * A function that creates and returns a Lotto instance.\r\n * @param participantsOrOptions An array of initial participants or options relating to the creation of a Lotto instance.\r\n * @returns A new Lotto instance.\r\n */\r\nfunction createLotto(participantsOrOptions) {\r\n // If no initial participants or lotto options were provided as an argument then we can just return a new lotto instance now.\r\n if (!participantsOrOptions) {\r\n return new Lotto_1.Lotto();\r\n }\r\n // Check whether we were provided with an array of initial participants or a lotto options object.\r\n if (Array.isArray(participantsOrOptions)) {\r\n // We are dealing with a pre-defined array of participants.\r\n var participants = participantsOrOptions;\r\n var lotto_1 = new Lotto_1.Lotto();\r\n // If the lotto participants have been defined upfront then we will need to add them all to our lotto instance now.\r\n participants.forEach(function (_a) {\r\n var participant = _a[0], tokens = _a[1];\r\n return lotto_1.add(participant, tokens);\r\n });\r\n // Return the Lotto instance.\r\n return lotto_1;\r\n }\r\n else {\r\n // We are dealing with some lotto options.\r\n var random = participantsOrOptions.random, participants = participantsOrOptions.participants;\r\n // Create a Lotto instance passing the custom RNG function to use in place of Math.random() (which could be undefined).\r\n var lotto_2 = new Lotto_1.Lotto(random);\r\n // If the lotto participants have been defined upfront as part of the options then we will need to add them all to our lotto instance now.\r\n if (participants) {\r\n participants.forEach(function (_a) {\r\n var participant = _a[0], tokens = _a[1];\r\n return lotto_2.add(participant, tokens);\r\n });\r\n }\r\n // Return the Lotto instance.\r\n return lotto_2;\r\n }\r\n}\r\nexports.createLotto = createLotto;\r\n", "\"use strict\";\r\nObject.defineProperty(exports, \"__esModule\", { value: true });\r\nvar createLotto_1 = require(\"./createLotto\");\r\nexports.default = createLotto_1.createLotto;\r\n", "import State from \"./State\";\nimport { validateDefinition } from \"./BehaviourTreeDefinitionValidator\";\nimport { convertMDSLToJSON } from \"./mdsl/MDSLDefinitionParser\";\nimport { BehaviourTree, FlattenedTreeNode } from \"./BehaviourTree\";\nimport { BehaviourTreeOptions } from \"./BehaviourTreeOptions\";\n\nexport { BehaviourTree, State, convertMDSLToJSON, validateDefinition };\nexport type { FlattenedTreeNode, BehaviourTreeOptions };\n", "/**\n * Enumeration of node state types.\n */\nexport enum State {\n READY = \"mistreevous.ready\",\n RUNNING = \"mistreevous.running\",\n SUCCEEDED = \"mistreevous.succeeded\",\n FAILED = \"mistreevous.failed\"\n}\n\nexport { State as default };\n\nexport type CompleteState = State.SUCCEEDED | State.FAILED;\nexport type AnyState = State.READY | State.RUNNING | CompleteState;\n", "import {\n NodeDefinition,\n RootNodeDefinition,\n DecoratorNodeDefinition,\n CompositeNodeDefinition,\n AnyNodeDefinition,\n BranchNodeDefinition\n} from \"./BehaviourTreeDefinition\";\n\n/**\n * A type guard function that returns true if the specified node satisfies the RootNodeDefinition type.\n * @param node The node.\n * @returns A value of true if the specified node satisfies the RootNodeDefinition type.\n */\nexport function isRootNode(node: NodeDefinition): node is RootNodeDefinition {\n return node.type === \"root\";\n}\n\n/**\n * A type guard function that returns true if the specified node satisfies the BranchNodeDefinition type.\n * @param node The node.\n * @returns A value of true if the specified node satisfies the BranchNodeDefinition type.\n */\nexport function isBranchNode(node: NodeDefinition): node is BranchNodeDefinition {\n return node.type === \"branch\";\n}\n\n/**\n * A type guard function that returns true if the specified node satisfies the NodeDefinition type.\n * @param node The node.\n * @returns A value of true if the specified node satisfies the NodeDefinition type.\n */\nexport function isLeafNode(node: NodeDefinition): node is NodeDefinition {\n return [\"branch\", \"action\", \"condition\", \"wait\"].includes(node.type);\n}\n\n/**\n * A type guard function that returns true if the specified node satisfies the DecoratorNodeDefinition type.\n * @param node The node.\n * @returns A value of true if the specified node satisfies the DecoratorNodeDefinition type.\n */\nexport function isDecoratorNode(node: NodeDefinition): node is DecoratorNodeDefinition {\n return [\"root\", \"repeat\", \"retry\", \"flip\", \"succeed\", \"fail\"].includes(node.type);\n}\n\n/**\n * A type guard function that returns true if the specified node satisfies the CompositeNodeDefinition type.\n * @param node The node.\n * @returns A value of true if the specified node satisfies the CompositeNodeDefinition type.\n */\nexport function isCompositeNode(node: NodeDefinition): node is CompositeNodeDefinition {\n return [\"sequence\", \"selector\", \"lotto\", \"parallel\"].includes(node.type);\n}\n\n/**\n * Flatten a node definition into an array of all of its nested node definitions.\n * @param nodeDefinition The node definition to flatten.\n * @returns An array of all of nested node definitions.\n */\nexport function flattenDefinition(nodeDefinition: AnyNodeDefinition): AnyNodeDefinition[] {\n const nodes: AnyNodeDefinition[] = [];\n\n const processNode = (currentNodeDefinition: AnyNodeDefinition) => {\n nodes.push(currentNodeDefinition);\n\n if (isCompositeNode(currentNodeDefinition)) {\n currentNodeDefinition.children.forEach(processNode);\n } else if (isDecoratorNode(currentNodeDefinition)) {\n processNode(currentNodeDefinition.child);\n }\n };\n\n processNode(nodeDefinition);\n\n return nodes;\n}\n\n/**\n * Determines whether the passed value is an integer.\n * @param value The value to check.\n * @returns Whether the passed value is an integer.\n */\nexport function isInteger(value: unknown): boolean {\n return typeof value === \"number\" && Math.floor(value) === value;\n}\n\n/**\n * Determines whether the passed value is null or undefined.\n * @param value The value to check.\n * @returns Whether the passed value is null or undefined.\n */\nexport function isNullOrUndefined(value: unknown): boolean {\n return typeof value === \"undefined\" || value === null;\n}\n", "/**\n * A type defining an object that holds a reference to substitued string literals parsed from the definition.\n */\nexport type StringLiteralPlaceholders = { [key: string]: string };\n\n/**\n * Pop the next raw token from the specified array of tokens and throw an error if it wasn't the expected one.\n * @param tokens The array of tokens.\n * @param expected An optional string or array or items, one of which must match the next popped token.\n * @returns The popped token.\n */\nexport function popAndCheck(tokens: string[], expected?: string | string[]): string {\n // Get and remove the next token.\n const popped = tokens.shift();\n\n // We were expecting another token but there aren't any.\n if (popped === undefined) {\n throw new Error(\"unexpected end of definition\");\n }\n\n // Do we have an expected token/tokens array?\n if (expected != undefined) {\n // Get an array of expected values, if the popped token matches any then we are all good.\n const expectedValues = typeof expected === \"string\" ? [expected] : expected;\n\n // Check whether the popped token matches at least one of our expected items.\n var tokenMatchesExpectation = expectedValues.some((item) => popped.toUpperCase() === item.toUpperCase());\n\n // Throw an error if the popped token didn't match any of our expected items.\n if (!tokenMatchesExpectation) {\n const expectationString = expectedValues.map((item) => \"'\" + item + \"'\").join(\" or \");\n throw new Error(\"unexpected token found. Expected \" + expectationString + \" but got '\" + popped + \"'\");\n }\n }\n\n // Return the popped token.\n return popped;\n}\n\n/**\n * Swaps out any node/attribute argument string literals with placeholders.\n * @param definition The definition.\n * @returns An object containing a mapping of placeholders to original string values as well as the processed definition string.\n */\nexport function substituteStringLiterals(definition: string): {\n placeholders: StringLiteralPlaceholders;\n processedDefinition: string;\n} {\n // Create an object to hold the mapping of placeholders to original string values.\n const placeholders: StringLiteralPlaceholders = {};\n\n // Replace any string literals wrapped with double quotes in our definition with placeholders to be processed later.\n const processedDefinition = definition.replace(/\\\"(\\\\.|[^\"\\\\])*\\\"/g, (match) => {\n var strippedMatch = match.substring(1, match.length - 1);\n var placeholder = Object.keys(placeholders).find((key) => placeholders[key] === strippedMatch);\n\n // If we have no existing string literal match then create a new placeholder.\n if (!placeholder) {\n placeholder = `@@${Object.keys(placeholders).length}@@`;\n placeholders[placeholder] = strippedMatch;\n }\n\n return placeholder;\n });\n\n return { placeholders, processedDefinition };\n}\n\n/**\n * Parse the tree definition into an array of raw tokens.\n * @param definition The definition.\n * @returns An array of tokens parsed from the definition.\n */\nexport function parseTokensFromDefinition(definition: string): string[] {\n // Add some space around various important characters so that they can be plucked out easier as individual tokens.\n definition = definition.replace(/\\(/g, \" ( \");\n definition = definition.replace(/\\)/g, \" ) \");\n definition = definition.replace(/\\{/g, \" { \");\n definition = definition.replace(/\\}/g, \" } \");\n definition = definition.replace(/\\]/g, \" ] \");\n definition = definition.replace(/\\[/g, \" [ \");\n definition = definition.replace(/\\,/g, \" , \");\n\n // Split the definition into raw token form and return it.\n return definition.replace(/\\s+/g, \" \").trim().split(\" \");\n}\n", "import { StringLiteralPlaceholders, popAndCheck } from \"./MDSLUtilities\";\n\n/**\n * A type representing any node function argument.\n */\ntype Argument = {\n /**\n * The argument value.\n */\n value: T;\n /**\n * The argument type, used for validation.\n */\n type: string;\n};\n\ntype NullArgument = Argument & {\n type: \"null\";\n};\n\ntype BooleanArgument = Argument & {\n type: \"boolean\";\n};\n\ntype NumberArgument = Argument & {\n type: \"number\";\n /**\n * A flag defining whether the number argument value is a valid integer. (used for validation)\n */\n isInteger: boolean;\n};\n\ntype StringPlaceholderArgument = Argument & {\n type: \"string\";\n};\n\ntype IdentifierArgument = Argument & {\n type: \"identifier\";\n};\n\n/**\n * A type representing a reference to any node function argument.\n */\ntype AnyArgument = NullArgument | BooleanArgument | NumberArgument | StringPlaceholderArgument | IdentifierArgument;\n\n/**\n * Parse an array of argument definitions from the specified tokens array.\n * @param tokens The array tokens to parse the argument definitions from.\n * @param stringArgumentPlaceholders The mapping of string literal node argument placeholders to original values.\n * @param argumentValidator The argument validator function.\n * @param validationFailedMessage The exception message to throw if argument validation fails.\n * @returns An array of argument definitions parsed from the specified tokens array.\n */\nexport function parseArgumentTokens(\n tokens: string[],\n stringArgumentPlaceholders: StringLiteralPlaceholders\n): AnyArgument[] {\n const argumentList: AnyArgument[] = [];\n\n // If the next token is not a '[' or '(' then we have no arguments to parse.\n if (![\"[\", \"(\"].includes(tokens[0])) {\n return argumentList;\n }\n\n // Any lists of arguments will always be wrapped in '[]' for node arguments or '()' for attribute arguments.\n // We are looking for a '[' or '(' opener that wraps the argument tokens and the relevant closer.\n const closingToken = popAndCheck(tokens, [\"[\", \"(\"]) === \"[\" ? \"]\" : \")\";\n\n const argumentListTokens: string[] = [];\n\n // Grab all tokens between the '[' and ']' or '(' and ')'.\n while (tokens.length && tokens[0] !== closingToken) {\n // The next token is part of our arguments list.\n argumentListTokens.push(tokens.shift()!);\n }\n\n // Validate the order of the argument tokens. Each token must either be a ',' or a single argument that satisfies the validator.\n argumentListTokens.forEach((token, index) => {\n // Get whether this token should be an actual argument.\n const shouldBeArgumentToken = !(index & 1);\n\n // If the current token should be an actual argument then validate it, otherwise it should be a ',' token.\n if (shouldBeArgumentToken) {\n // Get the argument definition.\n const argumentDefinition = getArgumentDefinition(token, stringArgumentPlaceholders);\n\n // This is a valid argument!\n argumentList.push(argumentDefinition);\n } else {\n // The current token should be a ',' token.\n if (token !== \",\") {\n throw new Error(`invalid argument list, expected ',' or ']' but got '${token}'`);\n }\n }\n });\n\n // The arguments list should terminate with a ']' or ')' token, depending on the opener.\n popAndCheck(tokens, closingToken);\n\n // Return the arguments.\n return argumentList;\n}\n\n/**\n * Gets an argument value definition.\n * @param token The argument token.\n * @param stringArgumentPlaceholders The mapping of string literal node argument placeholders to original values.\n * @returns An argument value definition.\n */\nfunction getArgumentDefinition(token: string, stringArgumentPlaceholders: StringLiteralPlaceholders): AnyArgument {\n // Check whether the token represents a null value.\n if (token === \"null\") {\n return {\n value: null,\n type: \"null\"\n } as NullArgument;\n }\n\n // Check whether the token represents a boolean value.\n if (token === \"true\" || token === \"false\") {\n return {\n value: token === \"true\",\n type: \"boolean\"\n } as BooleanArgument;\n }\n\n // Check whether the token represents a number value.\n // TODO: Relies on broken isNaN - see MDN.\n // if (!Number.isNaN(token)) {\n if (!isNaN(token as any)) {\n return {\n value: parseFloat(token),\n isInteger: parseFloat(token) === parseInt(token, 10),\n type: \"number\"\n } as NumberArgument;\n }\n\n // Check whether the token is a placeholder (e.g. @@0@@) representing a string literal.\n if (token.match(/^@@\\d+@@$/g)) {\n return {\n value: stringArgumentPlaceholders[token].replace('\\\\\"', '\"'),\n type: \"string\"\n } as StringPlaceholderArgument;\n }\n\n // The only remaining option is that the argument value is an identifier.\n return {\n value: token,\n type: \"identifier\"\n } as IdentifierArgument;\n}\n", "import { NodeAttributeDefinition } from \"../BehaviourTreeDefinition\";\nimport { parseArgumentTokens } from \"./MDSLNodeArgumentParser\";\nimport { StringLiteralPlaceholders } from \"./MDSLUtilities\";\n\n/**\n * A type defining the attribute definitions of a node.\n */\ntype NodeAttributes = {\n while?: NodeAttributeDefinition;\n until?: NodeAttributeDefinition;\n entry?: NodeAttributeDefinition;\n exit?: NodeAttributeDefinition;\n step?: NodeAttributeDefinition;\n};\n\n/**\n * Parse any node attribute definitions from the specified tokens array.\n * @param tokens The array of remaining tokens.\n * @param stringArgumentPlaceholders The mapping of string literal node argument placeholders to original values.\n * @returns An object of attribute definitions defined by any directly following tokens.\n */\nexport function parseAttributeTokens(\n tokens: string[],\n stringArgumentPlaceholders: StringLiteralPlaceholders\n): NodeAttributes {\n const nodeAttributeNames: (keyof NodeAttributes)[] = [\"while\", \"until\", \"entry\", \"exit\", \"step\"];\n\n // Create an object to hold any attributes found.\n const attributes: NodeAttributes = {};\n\n // Try to get the name of the attribute for the next token.\n let nextAttributeName = tokens[0]?.toLowerCase() as keyof NodeAttributes;\n\n // Pull attribute tokens as well as their arguments off of the tokens stack until we have no more.\n while (nodeAttributeNames.includes(nextAttributeName)) {\n // Check to make sure that we have not already created an attribute definition of this type.\n if (attributes[nextAttributeName]) {\n throw new Error(`duplicate attribute '${tokens[0].toUpperCase()}' found for node`);\n }\n\n // Remove the attribute name token from the array of tokens.\n tokens.shift();\n\n // Grab the attribute arguments, assuming the first to be an identifier.\n const [attributeCallIdentifier, ...attributeArguments] = parseArgumentTokens(\n tokens,\n stringArgumentPlaceholders\n );\n\n // The first attribute argument has to be an identifer, this will reference an agent function.\n if (attributeCallIdentifier?.type !== \"identifier\") {\n throw new Error(\"expected agent function or registered function name identifier argument for attribute\");\n }\n\n // Any attribute arguments (other than the expected call identifier) must have a type of string, number, boolean or null.\n attributeArguments\n .filter((arg) => arg.type === \"identifier\")\n .forEach((arg) => {\n throw new Error(\n `invalid attribute argument value '${arg.value}', must be string, number, boolean or null`\n );\n });\n\n // Create the attribute definition and add it to the object of attribute definitions found.\n attributes[nextAttributeName] = {\n call: attributeCallIdentifier.value,\n args: attributeArguments.map(({ value }) => value)\n };\n\n // Try to get the next attribute name token, as there could be multiple.\n nextAttributeName = tokens[0]?.toLowerCase() as keyof NodeAttributes;\n }\n\n return attributes;\n}\n", "import {\n ActionNodeDefinition,\n AnyChildNodeDefinition,\n AnyNodeDefinition,\n BranchNodeDefinition,\n ConditionNodeDefinition,\n FailNodeDefinition,\n FlipNodeDefinition,\n LottoNodeDefinition,\n ParallelNodeDefinition,\n RepeatNodeDefinition,\n RetryNodeDefinition,\n RootNodeDefinition,\n SelectorNodeDefinition,\n SequenceNodeDefinition,\n SucceedNodeDefinition,\n WaitNodeDefinition\n} from \"../BehaviourTreeDefinition\";\nimport {\n isCompositeNode,\n isDecoratorNode,\n isLeafNode,\n isNullOrUndefined,\n isRootNode\n} from \"../BehaviourTreeDefinitionUtilities\";\nimport { parseArgumentTokens } from \"./MDSLNodeArgumentParser\";\nimport { parseAttributeTokens } from \"./MDSLNodeAttributeParser\";\nimport {\n StringLiteralPlaceholders,\n parseTokensFromDefinition,\n popAndCheck,\n substituteStringLiterals\n} from \"./MDSLUtilities\";\n\n/**\n * Convert the MDSL tree definition string into an equivalent JSON definition.\n * @param definition The tree definition string as MDSL.\n * @returns The root node JSON definitions.\n */\nexport function convertMDSLToJSON(definition: string): RootNodeDefinition[] {\n // Swap out any node/attribute argument string literals with a placeholder and get a mapping of placeholders to original values as well as the processed definition.\n const { placeholders, processedDefinition } = substituteStringLiterals(definition);\n\n // Parse our definition definition string into an array of raw tokens.\n const tokens = parseTokensFromDefinition(processedDefinition);\n\n return convertTokensToJSONDefinition(tokens, placeholders);\n}\n\n/**\n * Converts the specified tree definition tokens into a JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The root node JSON definitions.\n */\nfunction convertTokensToJSONDefinition(\n tokens: string[],\n stringLiteralPlaceholders: StringLiteralPlaceholders\n): RootNodeDefinition[] {\n // There must be at least 3 tokens for the tree definition to be valid. 'ROOT', '{' and '}'.\n if (tokens.length < 3) {\n throw new Error(\"invalid token count\");\n }\n\n // We should have a matching number of '{' and '}' tokens. If not, then there are scopes that have not been properly closed.\n if (tokens.filter((token) => token === \"{\").length !== tokens.filter((token) => token === \"}\").length) {\n throw new Error(\"scope character mismatch\");\n }\n\n // Create an array of tree stack arrays where root nodes will always be at the botton and the current composite/decorator node at the top.\n // There should be an element in this array for every root node defined and every element should be an array with a root note as the first element.\n // E.g. A definition with two root nodes defined:\n // [\n // [root, lotto, sequence],\n // [root, selector]\n // ]\n const treeStacks: [Partial, ...Partial[]][] = [];\n\n // Create an array of all root node definitions that we create.\n const rootNodes: Partial[] = [];\n\n // A helper function used to push node definitions onto the tree stack.\n const pushNode = (node: AnyNodeDefinition) => {\n // If the node is a root node then we need to create a new tree stack array with the root node at the root.\n if (isRootNode(node)) {\n // We need to double-check that this root node is not the child of another node.\n // We can do this by checking whether the top tree stack is not empty (contains an existing node)\n if (treeStacks[treeStacks.length - 1]?.length) {\n throw new Error(\"a root node cannot be the child of another node\");\n }\n\n // Add the root node definition to our array of all parsed root node definitions.\n rootNodes.push(node);\n\n // Add the root node definition to the root of a new tree stack.\n treeStacks.push([node]);\n\n return;\n }\n\n // All non-root nodes should be pushed after their root nodes so handle cases\n // where we may not have any tree stacks or our top-most tree stack is empty.\n if (!treeStacks.length || !treeStacks[treeStacks.length - 1].length) {\n throw new Error(\"expected root node at base of definition\");\n }\n\n // Get the current tree stack that we are populating.\n const topTreeStack = treeStacks[treeStacks.length - 1];\n\n // Get the top-most node in the current tree stack, this will be a composite/decorator node\n // for which we will populate its children array if composite or setting its child if a decorator.\n const topTreeStackTopNode = topTreeStack[topTreeStack.length - 1] as AnyNodeDefinition;\n\n // If the top-most node in the current root stack is a composite or decorator\n // node then the current node should be added as a child of the top-most node.\n if (isCompositeNode(topTreeStackTopNode)) {\n topTreeStackTopNode.children = topTreeStackTopNode.children || [];\n topTreeStackTopNode.children.push(node);\n } else if (isDecoratorNode(topTreeStackTopNode)) {\n // If the top node already has a child node set then throw an error as a decorator should only have a single child.\n if (topTreeStackTopNode.child) {\n throw new Error(\"a decorator node must only have a single child node\");\n }\n\n topTreeStackTopNode.child = node;\n }\n\n // If the node we are adding is also a composite or decorator node, then we should push it\n // onto the current tree stack, as subsequent nodes will be added as its child/children.\n if (!isLeafNode(node)) {\n topTreeStack.push(node);\n }\n };\n\n // A helper function used to pop the top-most node definition off of the tree stack and return it.\n const popNode = (): AnyNodeDefinition | null => {\n let poppedNode: AnyNodeDefinition | null = null;\n\n // Get the current tree stack that we are populating.\n const topTreeStack = treeStacks[treeStacks.length - 1];\n\n // Pop the top-most node in the current tree stack if there is one.\n if (topTreeStack.length) {\n poppedNode = topTreeStack.pop() as AnyNodeDefinition;\n }\n\n // We don't want any empty tree stacks in our stack of tree stacks.\n if (!topTreeStack.length) {\n treeStacks.pop();\n }\n\n return poppedNode;\n };\n\n // We should keep processing the raw tokens until we run out of them.\n while (tokens.length) {\n // Grab the next token.\n const token = tokens.shift()!;\n\n // How we create the next node depends on the current raw token value.\n switch (token.toUpperCase()) {\n case \"ROOT\": {\n pushNode(createRootNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"SUCCEED\": {\n pushNode(createSucceedNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"FAIL\": {\n pushNode(createFailNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"FLIP\": {\n pushNode(createFlipNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"REPEAT\": {\n pushNode(createRepeatNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"RETRY\": {\n pushNode(createRetryNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"SEQUENCE\": {\n pushNode(createSequenceNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"SELECTOR\": {\n pushNode(createSelectorNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"PARALLEL\": {\n pushNode(createParallelNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"LOTTO\": {\n pushNode(createLottoNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"ACTION\": {\n pushNode(createActionNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"CONDITION\": {\n pushNode(createConditionNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"WAIT\": {\n pushNode(createWaitNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"BRANCH\": {\n pushNode(createBranchNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"}\": {\n // The '}' character closes the current scope and means that we have to pop a node off of the current stack.\n const poppedNode = popNode();\n\n // Now that we have a node definition we can carry out any validation that may require the node to be fully populated.\n if (poppedNode) {\n validatePoppedNode(poppedNode);\n }\n\n break;\n }\n\n default: {\n throw new Error(`unexpected token: ${token}`);\n }\n }\n }\n\n return rootNodes as RootNodeDefinition[];\n}\n\n/**\n * Creates a root node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The root node JSON definition.\n */\nfunction createRootNode(tokens: string[], stringLiteralPlaceholders: StringLiteralPlaceholders): RootNodeDefinition {\n // Create the root node definition.\n let node = {\n type: \"root\"\n } as Partial;\n\n // Parse any node arguments, we should only have one if any which will be an identifier argument for the root identifier.\n const nodeArguments = parseArgumentTokens(tokens, stringLiteralPlaceholders);\n\n // Check whether any node arguments were defined.\n if (nodeArguments.length) {\n // We should only have one argument, if any, which will be an identifier argument for the root identifier.\n if (nodeArguments.length === 1 && nodeArguments[0].type === \"identifier\") {\n // The root node identifier will be the first and only node argument value.\n node.id = nodeArguments[0].value as string;\n } else {\n throw new Error(\"expected single root name argument\");\n }\n }\n\n // Grab any node attribute definitions and spread them into the node definition.\n node = { ...node, ...parseAttributeTokens(tokens, stringLiteralPlaceholders) };\n\n // This is a decorator node, so we expect an opening '{'.\n popAndCheck(tokens, \"{\");\n\n // Return the root node definition.\n return node as RootNodeDefinition;\n}\n\n/**\n * Creates a succeed node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The succeed node JSON definition.\n */\nfunction createSucceedNode(\n tokens: string[],\n stringLiteralPlaceholders: StringLiteralPlaceholders\n): SucceedNodeDefinition {\n const node = {\n type: \"succeed\",\n ...parseAttributeTokens(tokens, stringLiteralPlaceholders)\n } as SucceedNodeDefinition;\n\n // This is a decorator node, so we expect an opening '{'.\n popAndCheck(tokens, \"{\");\n\n // Return the succeed node definition.\n return node;\n}\n\n/**\n * Creates a fail node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The fail node JSON definition.\n */\nfunction createFailNode(tokens: string[], stringLiteralPlaceholders: StringLiteralPlaceholders): FailNodeDefinition {\n const node = {\n type: \"fail\",\n ...parseAttributeTokens(tokens, stringLiteralPlaceholders)\n } as FailNodeDefinition;\n\n // This is a decorator node, so we expect an opening '{'.\n popAndCheck(tokens, \"{\");\n\n // Return the fail node definition.\n return node;\n}\n\n/**\n * Creates a flip node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The flip node JSON definition.\n */\nfunction createFlipNode(tokens: string[], stringLiteralPlaceholders: StringLiteralPlaceholders): FlipNodeDefinition {\n const node = {\n type: \"flip\",\n ...parseAttributeTokens(tokens, stringLiteralPlaceholders)\n } as FlipNodeDefinition;\n\n // This is a decorator node, so we expect an opening '{'.\n popAndCheck(tokens, \"{\");\n\n // Return the flip node definition.\n return node;\n}\n\n/**\n * Creates a repeat node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The repeat node JSON definition.\n */\nfunction createRepeatNode(\n tokens: string[],\n stringLiteralPlaceholders: StringLiteralPlaceholders\n): RepeatNodeDefinition {\n let node = { type: \"repeat\" } as RepeatNodeDefinition;\n\n // Get the node arguments.\n const nodeArguments = parseArgumentTokens(tokens, stringLiteralPlaceholders);\n\n // The arguments of a repeat node are optional. We may have:\n // - No node arguments, in which case the repeat note will iterate indefinitely.\n // - One node argument which will be the explicit number of iterations to make.\n // - Two node arguments which define the min and max iteration bounds from which a random iteration count will be picked.\n if (nodeArguments.length) {\n // All repeat node arguments MUST be of type number and must be integer.\n nodeArguments\n .filter((arg) => arg.type !== \"number\" || !arg.isInteger)\n .forEach(() => {\n throw new Error(`repeat node iteration counts must be integer values`);\n });\n\n // We should have got one or two iteration counts.\n if (nodeArguments.length === 1) {\n // A static iteration count was defined.\n node.iterations = nodeArguments[0].value as number;\n\n // A repeat node must have a positive number of iterations if defined.\n if (node.iterations < 0) {\n throw new Error(\"a repeat node must have a positive number of iterations if defined\");\n }\n } else if (nodeArguments.length === 2) {\n // A minimum and maximum iteration count was defined.\n node.iterations = [nodeArguments[0].value as number, nodeArguments[1].value as number];\n\n // A repeat node must have a positive min and max iteration count if they are defined.\n if (node.iterations[0] < 0 || node.iterations[1] < 0) {\n throw new Error(\"a repeat node must have a positive minimum and maximum iteration count if defined\");\n }\n\n // A repeat node must not have an minimum iteration count that exceeds the maximum iteration count.\n if (node.iterations[0] > node.iterations[1]) {\n throw new Error(\n \"a repeat node must not have a minimum iteration count that exceeds the maximum iteration count\"\n );\n }\n } else {\n // An incorrect number of iteration counts was defined.\n throw new Error(\"invalid number of repeat node iteration count arguments defined\");\n }\n }\n\n // Grab any node attribute definitions and spread them into the node definition.\n node = { ...node, ...parseAttributeTokens(tokens, stringLiteralPlaceholders) };\n\n // This is a decorator node, so we expect an opening '{'.\n popAndCheck(tokens, \"{\");\n\n // Return the repeat node definition.\n return node;\n}\n\n/**\n * Creates a retry node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The retry node JSON definition.\n */\nfunction createRetryNode(tokens: string[], stringLiteralPlaceholders: StringLiteralPlaceholders): RetryNodeDefinition {\n let node = { type: \"retry\" } as RetryNodeDefinition;\n\n // Get the node arguments.\n const nodeArguments = parseArgumentTokens(tokens, stringLiteralPlaceholders);\n\n // The arguments of a retry node are optional. We may have:\n // - No node arguments, in which case the retry note will attempt indefinitely.\n // - One node argument which will be the explicit number of attempts to make.\n // - Two node arguments which define the min and max attempt bounds from which a random attempt count will be picked.\n if (nodeArguments.length) {\n // All retry node arguments MUST be of type number and must be integer.\n nodeArguments\n .filter((arg) => arg.type !== \"number\" || !arg.isInteger)\n .forEach(() => {\n throw new Error(`retry node attempt counts must be integer values`);\n });\n\n // We should have got one or two attempt counts.\n if (nodeArguments.length === 1) {\n // A static attempt count was defined.\n node.attempts = nodeArguments[0].value as number;\n\n // A retry node must have a positive number of attempts if defined.\n if (node.attempts < 0) {\n throw new Error(\"a retry node must have a positive number of attempts if defined\");\n }\n } else if (nodeArguments.length === 2) {\n // A minimum and maximum attempt count was defined.\n node.attempts = [nodeArguments[0].value as number, nodeArguments[1].value as number];\n\n // A retry node must have a positive min and max attempts count if they are defined.\n if (node.attempts[0] < 0 || node.attempts[1] < 0) {\n throw new Error(\"a retry node must have a positive minimum and maximum attempt count if defined\");\n }\n\n // A retry node must not have a minimum attempt count that exceeds the maximum attempt count.\n if (node.attempts[0] > node.attempts[1]) {\n throw new Error(\n \"a retry node must not have a minimum attempt count that exceeds the maximum attempt count\"\n );\n }\n } else {\n // An incorrect number of attempt counts was defined.\n throw new Error(\"invalid number of retry node attempt count arguments defined\");\n }\n }\n\n // Grab any node attribute definitions and spread them into the node definition.\n node = { ...node, ...parseAttributeTokens(tokens, stringLiteralPlaceholders) };\n\n // This is a decorator node, so we expect an opening '{'.\n popAndCheck(tokens, \"{\");\n\n // Return the retry node definition.\n return node;\n}\n\n/**\n * Creates a sequence node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The sequence node JSON definition.\n */\nfunction createSequenceNode(\n tokens: string[],\n stringLiteralPlaceholders: StringLiteralPlaceholders\n): SequenceNodeDefinition {\n const node = {\n type: \"sequence\",\n ...parseAttributeTokens(tokens, stringLiteralPlaceholders)\n } as SequenceNodeDefinition;\n\n // This is a composite node, so we expect an opening '{'.\n popAndCheck(tokens, \"{\");\n\n // Return the sequence node definition.\n return node;\n}\n\n/**\n * Creates a selector node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The selector node JSON definition.\n */\nfunction createSelectorNode(\n tokens: string[],\n stringLiteralPlaceholders: StringLiteralPlaceholders\n): SelectorNodeDefinition {\n const node = {\n type: \"selector\",\n ...parseAttributeTokens(tokens, stringLiteralPlaceholders)\n } as SelectorNodeDefinition;\n\n // This is a composite node, so we expect an opening '{'.\n popAndCheck(tokens, \"{\");\n\n // Return the selector node definition.\n return node;\n}\n\n/**\n * Creates a parallel node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The parallel node JSON definition.\n */\nfunction createParallelNode(\n tokens: string[],\n stringLiteralPlaceholders: StringLiteralPlaceholders\n): ParallelNodeDefinition {\n const node = {\n type: \"parallel\",\n ...parseAttributeTokens(tokens, stringLiteralPlaceholders)\n } as ParallelNodeDefinition;\n\n // This is a composite node, so we expect an opening '{'.\n popAndCheck(tokens, \"{\");\n\n // Return the parallel node definition.\n return node;\n}\n\n/**\n * Creates a lotto node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The lotto node JSON definition.\n */\nfunction createLottoNode(tokens: string[], stringLiteralPlaceholders: StringLiteralPlaceholders): LottoNodeDefinition {\n // If any node arguments have been defined then they must be our weights.\n const nodeArguments = parseArgumentTokens(tokens, stringLiteralPlaceholders);\n\n // All lotto node arguments MUST be of type number and must be positive integers.\n nodeArguments\n .filter((arg) => arg.type !== \"number\" || !arg.isInteger || arg.value < 0)\n .forEach(() => {\n throw new Error(`lotto node weight arguments must be positive integer values`);\n });\n\n const node = {\n type: \"lotto\",\n ...parseAttributeTokens(tokens, stringLiteralPlaceholders)\n } as LottoNodeDefinition;\n\n // Apply the weights if any were defined.\n if (nodeArguments.length) {\n node.weights = nodeArguments.map(({ value }) => value) as number[];\n }\n\n // This is a composite node, so we expect an opening '{'.\n popAndCheck(tokens, \"{\");\n\n // Return the lotto node definition.\n return node;\n}\n\n/**\n * Creates an action node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The action node JSON definition.\n */\nfunction createActionNode(\n tokens: string[],\n stringLiteralPlaceholders: StringLiteralPlaceholders\n): ActionNodeDefinition {\n // Parse any node arguments, we should have at least one which will be an identifier argument for the action name\n // and agent function to invoke for the action, all other arguments are to be passed as arguments to that function.\n const [actionNameIdentifier, ...agentFunctionArgs] = parseArgumentTokens(tokens, stringLiteralPlaceholders);\n\n // Our first argument MUST be defined and be an identifier as we require an action name argument.\n if (actionNameIdentifier?.type !== \"identifier\") {\n throw new Error(\"expected action name identifier argument\");\n }\n\n // Only the first argument should have been an identifier, all agent function arguments must be string, number, boolean or null.\n agentFunctionArgs\n .filter((arg) => arg.type === \"identifier\")\n .forEach((arg) => {\n throw new Error(\n `invalid action node argument value '${arg.value}', must be string, number, boolean or null`\n );\n });\n\n // Return the action node definition.\n return {\n type: \"action\",\n call: actionNameIdentifier.value,\n args: agentFunctionArgs.map(({ value }) => value),\n ...parseAttributeTokens(tokens, stringLiteralPlaceholders)\n };\n}\n\n/**\n * Creates a condition node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The condition node JSON definition.\n */\nfunction createConditionNode(\n tokens: string[],\n stringLiteralPlaceholders: StringLiteralPlaceholders\n): ConditionNodeDefinition {\n // Parse any node arguments, we should have at least one which will be an identifier argument for the condition name\n // and agent function to invoke for the condition, all other arguments are to be passed as arguments to that function.\n const [conditionNameIdentifier, ...agentFunctionArgs] = parseArgumentTokens(tokens, stringLiteralPlaceholders);\n\n // Our first argument MUST be defined and be an identifier as we require a condition name argument.\n if (conditionNameIdentifier?.type !== \"identifier\") {\n throw new Error(\"expected condition name identifier argument\");\n }\n\n // Only the first argument should have been an identifier, all agent function arguments must be string, number, boolean or null.\n agentFunctionArgs\n .filter((arg) => arg.type === \"identifier\")\n .forEach((arg) => {\n throw new Error(\n `invalid condition node argument value '${arg.value}', must be string, number, boolean or null`\n );\n });\n\n // Return the condition node definition.\n return {\n type: \"condition\",\n call: conditionNameIdentifier.value,\n args: agentFunctionArgs.map(({ value }) => value),\n ...parseAttributeTokens(tokens, stringLiteralPlaceholders)\n };\n}\n\n/**\n * Creates a wait node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The wait node JSON definition.\n */\nfunction createWaitNode(tokens: string[], stringLiteralPlaceholders: StringLiteralPlaceholders): WaitNodeDefinition {\n let node = { type: \"wait\" } as WaitNodeDefinition;\n\n // Get the node arguments.\n const nodeArguments = parseArgumentTokens(tokens, stringLiteralPlaceholders);\n\n // The arguments of a wait node are optional. We may have:\n // - No node arguments, in which case the wait will be indefinite until it is aborted.\n // - One node argument which will be the explicit duration of the wait.\n // - Two node arguments which define the min and max duration bounds from which a random duration will be picked.\n if (nodeArguments.length) {\n // All wait node arguments MUST be of type number and must be integer.\n nodeArguments\n .filter((arg) => arg.type !== \"number\" || !arg.isInteger)\n .forEach(() => {\n throw new Error(`wait node durations must be integer values`);\n });\n\n // We may have:\n // - One node argument which will be the explicit duration of the wait.\n // - Two node arguments which define the min and max duration bounds from which a random duration will be picked.\n // - Too many arguments, which is not valid.\n if (nodeArguments.length === 1) {\n // An explicit duration was defined.\n node.duration = nodeArguments[0].value as number;\n\n // If an explict duration was defined then it must be a positive number.\n if (node.duration < 0) {\n throw new Error(\"a wait node must have a positive duration\");\n }\n } else if (nodeArguments.length === 2) {\n // Min and max duration bounds were defined from which a random duration will be picked.\n node.duration = [nodeArguments[0].value as number, nodeArguments[1].value as number];\n\n // A wait node must have a positive min and max duration.\n if (node.duration[0] < 0 || node.duration[1] < 0) {\n throw new Error(\"a wait node must have a positive minimum and maximum duration\");\n }\n\n // A wait node must not have a minimum duration that exceeds the maximum duration.\n if (node.duration[0] > node.duration[1]) {\n throw new Error(\"a wait node must not have a minimum duration that exceeds the maximum duration\");\n }\n } else if (nodeArguments.length > 2) {\n // An incorrect number of duration arguments were defined.\n throw new Error(\"invalid number of wait node duration arguments defined\");\n }\n }\n\n // Return the wait node definition.\n return { ...node, ...parseAttributeTokens(tokens, stringLiteralPlaceholders) };\n}\n\n/**\n * Creates a branch node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The branch node JSON definition.\n */\nfunction createBranchNode(\n tokens: string[],\n stringLiteralPlaceholders: StringLiteralPlaceholders\n): BranchNodeDefinition {\n // Parse any node arguments, we should have one which will be an identifier argument for the root ref.\n const nodeArguments = parseArgumentTokens(tokens, stringLiteralPlaceholders);\n\n // We should have only a single identifer argument for a branch node, which is the root ref.\n if (nodeArguments.length !== 1 || nodeArguments[0].type !== \"identifier\") {\n throw new Error(\"expected single branch name argument\");\n }\n\n // Return the branch node definition.\n return { type: \"branch\", ref: nodeArguments[0].value };\n}\n\n/**\n * Validate a fully-populated node definition that was popped off of the tree stack.\n * @param definition The popped node to validate.\n */\nfunction validatePoppedNode(definition: AnyNodeDefinition): void {\n // Decorators MUST have a child defined.\n if (isDecoratorNode(definition) && isNullOrUndefined(definition.child)) {\n throw new Error(`a ${definition.type} node must have a single child node defined`);\n }\n\n // Composites MUST have at least one child defined.\n if (isCompositeNode(definition) && !definition.children?.length) {\n throw new Error(`a ${definition.type} node must have at least a single child node defined`);\n }\n\n // We need to make sure that lotto nodes that have weights defined have a number of weights matching the number of child nodes.\n if (definition.type === \"lotto\") {\n // Check whether a 'weights' property has been defined, if it has we expect it to be an array of weights.\n if (typeof definition.weights !== \"undefined\") {\n // Check that the weights property is an array of positive integers with an element for each child node element.\n if (definition.weights.length !== definition.children.length) {\n throw new Error(\n \"expected a number of weight arguments matching the number of child nodes for lotto node\"\n );\n }\n }\n }\n}\n", "import { RootNodeDefinition } from \"./BehaviourTreeDefinition\";\nimport { flattenDefinition, isBranchNode, isInteger } from \"./BehaviourTreeDefinitionUtilities\";\nimport { convertMDSLToJSON } from \"./mdsl/MDSLDefinitionParser\";\n\n/**\n * An object representing the result of validating a tree definition.\n */\nexport type DefinitionValidationResult = {\n /**\n * A flag defining whether validation succeeded.\n */\n succeeded: boolean;\n /**\n * A string containing the error message if validation did not succeed.\n */\n errorMessage?: string;\n /**\n * The definition as json if the validation was successful, or undefined if validation did not succeed.\n */\n json?: RootNodeDefinition[];\n};\n\n/**\n * Validates the specified behaviour tree definition in the form of JSON or MDSL, not taking any globally registered subtrees into consideration.\n * @param definition The behaviour tree definition in the form of JSON or MDSL.\n * @returns An object representing the result of validating the given tree definition.\n */\nexport function validateDefinition(definition: any): DefinitionValidationResult {\n // The definition must be defined.\n if (definition === null || typeof definition === \"undefined\") {\n return createValidationFailureResult(\"definition is null or undefined\");\n }\n\n // We are expecting a definition in one of three different forms:\n // - A string which we will assume is MDSL and we will parse this to JSON before validation.\n // - An array which we will assume is an array of root node definitions with at least one being the primary root node (no 'id' property)\n // - An object which we will assume is the primary root node and should not have an 'id' property.\n if (typeof definition === \"string\") {\n // The definition is a string which we can assume is MDSL, so attempt to validate it.\n return validateMDSLDefinition(definition);\n } else if (typeof definition === \"object\") {\n // The definition will either be an array (of root node definitions) or an object (the single primary root node definition).\n return validateJSONDefinition(definition);\n } else {\n return createValidationFailureResult(`unexpected definition type of '${typeof definition}'`);\n }\n}\n\n/**\n * Validates the specified behaviour tree definition in the form of MDSL.\n * @param definition The behaviour tree definition in the form of MDSL.\n * @returns An object representing the result of validating the given tree definition.\n */\nfunction validateMDSLDefinition(definition: string): DefinitionValidationResult {\n let rootNodeDefinitions;\n\n // The first thing the we need to do is to attempt to convert our MDSL into JSON.\n try {\n // The definition is a string which we can assume is MDSL, so attempt to parse it to a JSON definition in the form of an array of root node definitions.\n rootNodeDefinitions = convertMDSLToJSON(definition);\n } catch (exception) {\n // We failed to parse the JSON from the MDSL, this is likely to be the result of it not being a valid MDSL string.\n return createValidationFailureResult((exception as Error).message);\n }\n\n // Unpack all of the root node definitions into arrays of main ('id' defined) and sub ('id' not defined) root node definitions.\n const mainRootNodeDefinitions = rootNodeDefinitions.filter(({ id }) => typeof id === \"undefined\");\n const subRootNodeDefinitions = rootNodeDefinitions.filter(({ id }) => typeof id === \"string\" && id.length > 0);\n\n // We should ALWAYS have exactly one root node definition without an 'id' property defined, which is out main root node definition.\n if (mainRootNodeDefinitions.length !== 1) {\n return createValidationFailureResult(\n \"expected single unnamed root node at base of definition to act as main root\"\n );\n }\n\n // We should never have duplicate 'id' properties across our sub root node definitions.\n const subRootNodeIdenitifers: string[] = [];\n for (const { id } of subRootNodeDefinitions) {\n // Have we already come across this 'id' property value?\n if (subRootNodeIdenitifers.includes(id!)) {\n return createValidationFailureResult(`multiple root nodes found with duplicate name '${id}'`);\n }\n\n subRootNodeIdenitifers.push(id!);\n }\n\n try {\n // Validate our branch -> subtree links and check for any circular dependencies, we don't care about checking for broken subtree links here.\n validateBranchSubtreeLinks(rootNodeDefinitions, false);\n } catch (exception) {\n return createValidationFailureResult((exception as Error).message);\n }\n\n // Our definition was valid!\n return {\n succeeded: true,\n json: rootNodeDefinitions\n };\n}\n\n/**\n * Validates the specified behaviour tree definition in the form of JSON.\n * @param definition The behaviour tree definition in the form of JSON.\n * @returns An object representing the result of validating the given tree definition.\n */\nexport function validateJSONDefinition(\n definition: RootNodeDefinition | RootNodeDefinition[]\n): DefinitionValidationResult {\n // The definition will either be an array (of root node definitions) or an object (the single primary root node definition).\n const rootNodeDefinitions = Array.isArray(definition) ? definition : [definition];\n\n // Iterate over our array of root nodes and call validateNode for each, passing an initial depth of 0, wrapped in a try catch to handle validation failures.\n try {\n rootNodeDefinitions.forEach((rootNodeDefinition) => validateNode(rootNodeDefinition, 0));\n } catch (error) {\n // Handle cases where we have caught a thrown Error and return a failure result with the error message.\n if (error instanceof Error) {\n return createValidationFailureResult(error.message);\n }\n\n // No idea what happened here!\n return createValidationFailureResult(`unexpected error: ${error}`);\n }\n\n // Unpack all of the root node definitions into arrays of main ('id' defined) and sub ('id' not defined) root node definitions.\n const mainRootNodeDefinitions = rootNodeDefinitions.filter(({ id }) => typeof id === \"undefined\");\n const subRootNodeDefinitions = rootNodeDefinitions.filter(({ id }) => typeof id === \"string\" && id.length > 0);\n\n // We should ALWAYS have exactly one root node definition without an 'id' property defined, which is out main root node definition.\n if (mainRootNodeDefinitions.length !== 1) {\n return createValidationFailureResult(\n \"expected single root node without 'id' property defined to act as main root\"\n );\n }\n\n // We should never have duplicate 'id' properties across our sub root node definitions.\n const subRootNodeIdenitifers: string[] = [];\n for (const { id } of subRootNodeDefinitions) {\n // Have we already come across this 'id' property value?\n if (subRootNodeIdenitifers.includes(id!)) {\n return createValidationFailureResult(\n `multiple root nodes found with duplicate 'id' property value of '${id}'`\n );\n }\n\n subRootNodeIdenitifers.push(id!);\n }\n\n try {\n // Validate our branch -> subtree links and check for any circular dependencies, we don't care about checking for broken subtree links here.\n validateBranchSubtreeLinks(rootNodeDefinitions, false);\n } catch (exception) {\n return createValidationFailureResult((exception as Error).message);\n }\n\n // Our definition was valid!\n return {\n succeeded: true,\n json: rootNodeDefinitions\n };\n}\n\n/**\n * Validates the branch -> subtree links across all provided root node definitions.\n * This will not consider branch nodes that reference any globally registered subtrees unless includesGlobalSubtrees\n * is set to true, in which case we will also verify that there are no broken branch -> subtree links.\n * @param rootNodeDefinitions The array of root node definitions.\n * @param includesGlobalSubtrees A flag defining whether the array includes all global subtree root node definitions.\n */\nexport function validateBranchSubtreeLinks(rootNodeDefinitions: RootNodeDefinition[], includesGlobalSubtrees: boolean) {\n // Create a mapping of root node identifiers to other root nodes that they reference via branch nodes.\n // Below is an example of a mapping that includes a circular dependency (root => a => b => c => a)\n // [{ refs: [\"a\", \"b\"] }, { id: \"a\", refs: [\"b\"] }, { id: \"b\", refs: [\"c\"] }, { id: \"c\", refs: [\"a\"] }]\n const rootNodeMappings: { id: string | undefined; refs: string[] }[] = rootNodeDefinitions.map(\n (rootNodeDefinition) => ({\n id: rootNodeDefinition.id,\n refs: flattenDefinition(rootNodeDefinition)\n .filter(isBranchNode)\n .map(({ ref }) => ref)\n })\n );\n\n // A recursive function to walk through the mappings, keeping track of which root nodes we have visited in the form of a path of root node identifiers.\n const followRefs = (mapping: { id: string | undefined; refs: string[] }, path: (string | undefined)[] = []) => {\n // Have we found a circular dependency?\n if (path.includes(mapping.id)) {\n // We found a circular dependency! Get the bad path of root node identifiers.\n const badPath = [...path, mapping.id];\n\n // Create the formatted path value. [undefined, \"a\", \"b\", \"c\", \"a\"] would be formatted as \"a -> b -> c -> a\".\n const badPathFormatted = badPath.filter((element) => !!element).join(\" => \");\n\n // No need to continue, we found a circular dependency.\n throw new Error(`circular dependency found in branch node references: ${badPathFormatted}`);\n }\n\n for (const ref of mapping.refs) {\n // Find the mapping for the root node with an identifer matching the current ref.\n const subMapping = rootNodeMappings.find(({ id }) => id === ref);\n\n // We may not have a mapping for this ref, which is normal when we aren't considering all globally registered subtrees.\n if (subMapping) {\n followRefs(subMapping, [...path, mapping.id]);\n } else if (includesGlobalSubtrees) {\n // We found a reference to a root node that doesn't exist, which is a problem seeing as the root node definitons includes all globally registered subtrees.\n throw new Error(\n mapping.id\n ? `subtree '${mapping.id}' has branch node that references root node '${ref}' which has not been defined`\n : `primary tree has branch node that references root node '${ref}' which has not been defined`\n );\n }\n }\n };\n\n // Start looking for circular dependencies and broken references from the primary root node definition.\n followRefs(rootNodeMappings.find((mapping) => typeof mapping.id === \"undefined\")!);\n}\n\n/**\n * Validate an object that we expect to be a node definition.\n * @param definition An object that we expect to be a node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateNode(definition: any, depth: number): void {\n // Every node must be valid object and have a non-empty 'type' string property.\n if (typeof definition !== \"object\" || typeof definition.type !== \"string\" || definition.type.length === 0) {\n throw new Error(\n `node definition is not an object or 'type' property is not a non-empty string at depth '${depth}'`\n );\n }\n\n // How we validate this node definition will depend on its type.\n switch (definition.type) {\n case \"action\":\n validateActionNode(definition, depth);\n break;\n\n case \"condition\":\n validateConditionNode(definition, depth);\n break;\n\n case \"wait\":\n validateWaitNode(definition, depth);\n break;\n\n case \"branch\":\n validateBranchNode(definition, depth);\n break;\n\n case \"root\":\n validateRootNode(definition, depth);\n break;\n\n case \"succeed\":\n validateSucceedNode(definition, depth);\n break;\n\n case \"fail\":\n validateFailNode(definition, depth);\n break;\n\n case \"flip\":\n validateFlipNode(definition, depth);\n break;\n\n case \"repeat\":\n validateRepeatNode(definition, depth);\n break;\n\n case \"retry\":\n validateRetryNode(definition, depth);\n break;\n\n case \"sequence\":\n validateSequenceNode(definition, depth);\n break;\n\n case \"selector\":\n validateSelectorNode(definition, depth);\n break;\n\n case \"parallel\":\n validateParallelNode(definition, depth);\n break;\n\n case \"lotto\":\n validateLottoNode(definition, depth);\n break;\n\n default:\n throw new Error(`unexpected node type of '${definition.type}' at depth '${depth}'`);\n }\n}\n\n/**\n * Validate any attributes for a given node definition.\n * @param definition The node definition.\n * @param depth The depth of the node in the behaviour tree definition.\n */\nfunction validateNodeAttributes(definition: any, depth: number): void {\n // Validate each of the attribute types for this node.\n [\"while\", \"until\", \"entry\", \"exit\", \"step\"].forEach((attributeName) => {\n // Attempt to grab the definition for the current attribute from the node definition.\n const attributeDefinition = definition[attributeName];\n\n // All node attributes are optional, so there is nothing to do if the current attribute is not defined.\n if (typeof attributeDefinition === \"undefined\") {\n return;\n }\n\n // The attribute definition must be an object.\n if (typeof attributeDefinition !== \"object\") {\n throw new Error(\n `expected attribute '${attributeName}' to be an object for '${definition.type}' node at depth '${depth}'`\n );\n }\n\n // The 'call' property must be defined for any attribute definition.\n if (typeof attributeDefinition.call !== \"string\" || attributeDefinition.call.length === 0) {\n throw new Error(\n `expected 'call' property for attribute '${attributeName}' to be a non-empty string for '${definition.type}' node at depth '${depth}'`\n );\n }\n\n // If any node attribute arguments have been defined then they must have been defined in an array.\n if (typeof attributeDefinition.args !== \"undefined\" && !Array.isArray(attributeDefinition.args)) {\n throw new Error(\n `expected 'args' property for attribute '${attributeName}' to be an array for '${definition.type}' node at depth '${depth}'`\n );\n }\n });\n}\n\n/**\n * Validate an object that we expect to be a root node definition.\n * @param definition An object that we expect to be a root node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateRootNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"root\") {\n throw new Error(\"expected node type of 'root' for root node\");\n }\n\n // A root node cannot be the child of another node.\n if (depth > 0) {\n throw new Error(\"a root node cannot be the child of another node\");\n }\n\n // Check that, if the root node 'id' property is defined, it is a non-empty string.\n if (typeof definition.id !== \"undefined\" && (typeof definition.id !== \"string\" || definition.id.length === 0)) {\n throw new Error(\"expected non-empty string for 'id' property if defined for root node\");\n }\n\n // A root node is a decorator node, so must have a child node defined.\n if (typeof definition.child === \"undefined\") {\n throw new Error(\"expected property 'child' to be defined for root node\");\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n\n // Validate the child node of this decorator node.\n validateNode(definition.child, depth + 1);\n}\n\n/**\n * Validate an object that we expect to be a succeed node definition.\n * @param definition An object that we expect to be a succeed node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateSucceedNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"succeed\") {\n throw new Error(`expected node type of 'succeed' for succeed node at depth '${depth}'`);\n }\n\n // A succeed node is a decorator node, so must have a child node defined.\n if (typeof definition.child === \"undefined\") {\n throw new Error(`expected property 'child' to be defined for succeed node at depth '${depth}'`);\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n\n // Validate the child node of this decorator node.\n validateNode(definition.child, depth + 1);\n}\n\n/**\n * Validate an object that we expect to be a fail node definition.\n * @param definition An object that we expect to be a fail node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateFailNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"fail\") {\n throw new Error(`expected node type of 'fail' for fail node at depth '${depth}'`);\n }\n\n // A fail node is a decorator node, so must have a child node defined.\n if (typeof definition.child === \"undefined\") {\n throw new Error(`expected property 'child' to be defined for fail node at depth '${depth}'`);\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n\n // Validate the child node of this decorator node.\n validateNode(definition.child, depth + 1);\n}\n\n/**\n * Validate an object that we expect to be a flip node definition.\n * @param definition An object that we expect to be a flip node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateFlipNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"flip\") {\n throw new Error(`expected node type of 'flip' for flip node at depth '${depth}'`);\n }\n\n // A flip node is a decorator node, so must have a child node defined.\n if (typeof definition.child === \"undefined\") {\n throw new Error(`expected property 'child' to be defined for flip node at depth '${depth}'`);\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n\n // Validate the child node of this decorator node.\n validateNode(definition.child, depth + 1);\n}\n\n/**\n * Validate an object that we expect to be a repeat node definition.\n * @param definition An object that we expect to be a repeat node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateRepeatNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"repeat\") {\n throw new Error(`expected node type of 'repeat' for repeat node at depth '${depth}'`);\n }\n\n // A repeat node is a decorator node, so must have a child node defined.\n if (typeof definition.child === \"undefined\") {\n throw new Error(`expected property 'child' to be defined for repeat node at depth '${depth}'`);\n }\n\n // Check whether an 'iterations' property has been defined, it may not have been if this node is to repeat indefinitely.\n if (typeof definition.iterations !== \"undefined\") {\n if (Array.isArray(definition.iterations)) {\n // Check whether any elements of the array are not integer values.\n const containsNonInteger = !!definition.iterations.filter((value: unknown) => !isInteger(value)).length;\n\n // If the 'iterations' property is an array then it MUST contain two integer values.\n if (definition.iterations.length !== 2 || containsNonInteger) {\n throw new Error(\n `expected array containing two integer values for 'iterations' property if defined for repeat node at depth '${depth}'`\n );\n }\n\n // A repeat node must have a positive min and max iterations count if they are defined.\n if (definition.iterations[0] < 0 || definition.iterations[1] < 0) {\n throw new Error(\n `expected positive minimum and maximum iterations count for 'iterations' property if defined for repeat node at depth '${depth}'`\n );\n }\n\n // A repeat node must not have a minimum iterations count that exceeds the maximum iterations count.\n if (definition.iterations[0] > definition.iterations[1]) {\n throw new Error(\n `expected minimum iterations count that does not exceed the maximum iterations count for 'iterations' property if defined for repeat node at depth '${depth}'`\n );\n }\n } else if (isInteger(definition.iterations)) {\n // A repeat node must have a positive number of iterations if defined.\n if (definition.iterations < 0) {\n throw new Error(\n `expected positive iterations count for 'iterations' property if defined for repeat node at depth '${depth}'`\n );\n }\n } else {\n throw new Error(\n `expected integer value or array containing two integer values for 'iterations' property if defined for repeat node at depth '${depth}'`\n );\n }\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n\n // Validate the child node of this decorator node.\n validateNode(definition.child, depth + 1);\n}\n\n/**\n * Validate an object that we expect to be a retry node definition.\n * @param definition An object that we expect to be a retry node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateRetryNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"retry\") {\n throw new Error(`expected node type of 'retry' for retry node at depth '${depth}'`);\n }\n\n // A retry node is a decorator node, so must have a child node defined.\n if (typeof definition.child === \"undefined\") {\n throw new Error(`expected property 'child' to be defined for retry node at depth '${depth}'`);\n }\n\n // Check whether an 'attempts' property has been defined, it may not have been if this node is to retry indefinitely.\n if (typeof definition.attempts !== \"undefined\") {\n if (Array.isArray(definition.attempts)) {\n // Check whether any elements of the array are not integer values.\n const containsNonInteger = !!definition.attempts.filter((value: unknown) => !isInteger(value)).length;\n\n // If the 'attempts' property is an array then it MUST contain two integer values.\n if (definition.attempts.length !== 2 || containsNonInteger) {\n throw new Error(\n `expected array containing two integer values for 'attempts' property if defined for retry node at depth '${depth}'`\n );\n }\n\n // A retry node must have a positive min and max attempts count if they are defined.\n if (definition.attempts[0] < 0 || definition.attempts[1] < 0) {\n throw new Error(\n `expected positive minimum and maximum attempts count for 'attempts' property if defined for retry node at depth '${depth}'`\n );\n }\n\n // A retry node must not have a minimum attempts count that exceeds the maximum attempts count.\n if (definition.attempts[0] > definition.attempts[1]) {\n throw new Error(\n `expected minimum attempts count that does not exceed the maximum attempts count for 'attempts' property if defined for retry node at depth '${depth}'`\n );\n }\n } else if (isInteger(definition.attempts)) {\n // A retry node must have a positive number of attempts if defined.\n if (definition.attempts < 0) {\n throw new Error(\n `expected positive attempts count for 'attempts' property if defined for retry node at depth '${depth}'`\n );\n }\n } else {\n throw new Error(\n `expected integer value or array containing two integer values for 'attempts' property if defined for retry node at depth '${depth}'`\n );\n }\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n\n // Validate the child node of this decorator node.\n validateNode(definition.child, depth + 1);\n}\n\n/**\n * Validate an object that we expect to be a branch node definition.\n * @param definition An object that we expect to be a branch node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateBranchNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"branch\") {\n throw new Error(`expected node type of 'branch' for branch node at depth '${depth}'`);\n }\n\n // Check that the branch node 'ref' property is defined and is a non-empty string.\n if (typeof definition.ref !== \"string\" || definition.ref.length === 0) {\n throw new Error(`expected non-empty string for 'ref' property for branch node at depth '${depth}'`);\n }\n\n // It is invalid to define guard attributes for a branch node as they should be defined on the referenced root node.\n [\"while\", \"until\"].forEach((attributeName) => {\n if (typeof definition[attributeName] !== \"undefined\") {\n throw new Error(\n `guards should not be defined for branch nodes but guard '${attributeName}' was defined for branch node at depth '${depth}'`\n );\n }\n });\n\n // It is invalid to define callback attributes for a branch node as they should be defined on the referenced root node.\n [\"entry\", \"exit\", \"step\"].forEach((attributeName) => {\n if (typeof definition[attributeName] !== \"undefined\") {\n throw new Error(\n `callbacks should not be defined for branch nodes but callback '${attributeName}' was defined for branch node at depth '${depth}'`\n );\n }\n });\n}\n\n/**\n * Validate an object that we expect to be a action node definition.\n * @param definition An object that we expect to be a action node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateActionNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"action\") {\n throw new Error(`expected node type of 'action' for action node at depth '${depth}'`);\n }\n\n // The 'call' property must be defined for a action node definition.\n if (typeof definition.call !== \"string\" || definition.call.length === 0) {\n throw new Error(`expected non-empty string for 'call' property of action node at depth '${depth}'`);\n }\n\n // If any action function arguments have been defined then they must have been defined in an array.\n if (typeof definition.args !== \"undefined\" && !Array.isArray(definition.args)) {\n throw new Error(`expected array for 'args' property if defined for action node at depth '${depth}'`);\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n}\n\n/**\n * Validate an object that we expect to be a condition node definition.\n * @param definition An object that we expect to be a condition node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateConditionNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"condition\") {\n throw new Error(`expected node type of 'condition' for condition node at depth '${depth}'`);\n }\n\n // The 'call' property must be defined for a condition node definition.\n if (typeof definition.call !== \"string\" || definition.call.length === 0) {\n throw new Error(`expected non-empty string for 'call' property of condition node at depth '${depth}'`);\n }\n\n // If any condition function arguments have been defined then they must have been defined in an array.\n if (typeof definition.args !== \"undefined\" && !Array.isArray(definition.args)) {\n throw new Error(`expected array for 'args' property if defined for condition node at depth '${depth}'`);\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n}\n\n/**\n * Validate an object that we expect to be a wait node definition.\n * @param definition An object that we expect to be a wait node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateWaitNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"wait\") {\n throw new Error(`expected node type of 'wait' for wait node at depth '${depth}'`);\n }\n\n // Check whether a 'duration' property has been defined, it may not have been if this node is to wait indefinitely.\n if (typeof definition.duration !== \"undefined\") {\n if (Array.isArray(definition.duration)) {\n // Check whether any elements of the array are not integer values.\n const containsNonInteger = !!definition.duration.filter((value: unknown) => !isInteger(value)).length;\n\n // If the 'duration' property is an array then it MUST contain two integer values.\n if (definition.duration.length !== 2 || containsNonInteger) {\n throw new Error(\n `expected array containing two integer values for 'duration' property if defined for wait node at depth '${depth}'`\n );\n }\n\n // A wait node must have a positive min and max duration value if they are defined.\n if (definition.duration[0] < 0 || definition.duration[1] < 0) {\n throw new Error(\n `expected positive minimum and maximum duration for 'duration' property if defined for wait node at depth '${depth}'`\n );\n }\n\n // A wait node must not have a minimum duration value that exceeds the maximum duration value.\n if (definition.duration[0] > definition.duration[1]) {\n throw new Error(\n `expected minimum duration value that does not exceed the maximum duration value for 'duration' property if defined for wait node at depth '${depth}'`\n );\n }\n } else if (isInteger(definition.duration)) {\n // A wait node must have a positive duration value if defined.\n if (definition.duration < 0) {\n throw new Error(\n `expected positive duration value for 'duration' property if defined for wait node at depth '${depth}'`\n );\n }\n } else {\n throw new Error(\n `expected integer value or array containing two integer values for 'duration' property if defined for wait node at depth '${depth}'`\n );\n }\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n}\n\n/**\n * Validate an object that we expect to be a sequence node definition.\n * @param definition An object that we expect to be a sequence node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateSequenceNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"sequence\") {\n throw new Error(`expected node type of 'sequence' for sequence node at depth '${depth}'`);\n }\n\n // A sequence node is a composite node, so must have a children nodes array defined.\n if (!Array.isArray(definition.children) || definition.children.length === 0) {\n throw new Error(`expected non-empty 'children' array to be defined for sequence node at depth '${depth}'`);\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n\n // Validate the child nodes of this composite node.\n definition.children.forEach((child: any) => validateNode(child, depth + 1));\n}\n\n/**\n * Validate an object that we expect to be a selector node definition.\n * @param definition An object that we expect to be a selector node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateSelectorNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"selector\") {\n throw new Error(`expected node type of 'selector' for selector node at depth '${depth}'`);\n }\n\n // A selector node is a composite node, so must have a children nodes array defined.\n if (!Array.isArray(definition.children) || definition.children.length === 0) {\n throw new Error(`expected non-empty 'children' array to be defined for selector node at depth '${depth}'`);\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n\n // Validate the child nodes of this composite node.\n definition.children.forEach((child: any) => validateNode(child, depth + 1));\n}\n\n/**\n * Validate an object that we expect to be a parallel node definition.\n * @param definition An object that we expect to be a parallel node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateParallelNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"parallel\") {\n throw new Error(`expected node type of 'parallel' for parallel node at depth '${depth}'`);\n }\n\n // A parallel node is a composite node, so must have a children nodes array defined.\n if (!Array.isArray(definition.children) || definition.children.length === 0) {\n throw new Error(`expected non-empty 'children' array to be defined for parallel node at depth '${depth}'`);\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n\n // Validate the child nodes of this composite node.\n definition.children.forEach((child: any) => validateNode(child, depth + 1));\n}\n\n/**\n * Validate an object that we expect to be a lotto node definition.\n * @param definition An object that we expect to be a lotto node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateLottoNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"lotto\") {\n throw new Error(`expected node type of 'lotto' for lotto node at depth '${depth}'`);\n }\n\n // A lotto node is a composite node, so must have a children nodes array defined.\n if (!Array.isArray(definition.children) || definition.children.length === 0) {\n throw new Error(`expected non-empty 'children' array to be defined for lotto node at depth '${depth}'`);\n }\n\n // Check whether a 'weights' property has been defined, if it has we expect it to be an array of weights.\n if (typeof definition.weights !== \"undefined\") {\n // Check that the weights property is an array of positive integers with an element for each child node element.\n if (\n !Array.isArray(definition.weights) ||\n definition.weights.length !== definition.children.length ||\n definition.weights.filter((value: unknown) => !isInteger(value)).length ||\n definition.weights.filter((value: number) => value < 0).length\n ) {\n throw new Error(\n `expected an array of positive integer weight values with a length matching the number of child nodes for 'weights' property if defined for lotto node at depth '${depth}'`\n );\n }\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n\n // Validate the child nodes of this composite node.\n definition.children.forEach((child: any) => validateNode(child, depth + 1));\n}\n\n/**\n * A helper function to create a failure validation result with the given error message.\n * @param errorMessage The validation failure error message.\n * @returns A failure validation result with the given error message.\n */\nfunction createValidationFailureResult(errorMessage: string): DefinitionValidationResult {\n return { succeeded: false, errorMessage };\n}\n", "import { ActionResult, Agent, GlobalFunction } from \"./Agent\";\nimport { RootNodeDefinition } from \"./BehaviourTreeDefinition\";\n\nexport type InvokerFunction = (args: any[]) => ActionResult | boolean;\n\n/**\n * A singleton used to store and lookup registered functions and subtrees.\n */\nexport default class Lookup {\n /**\n * The object holding any registered functions keyed on function name.\n */\n private static registeredFunctions: { [key: string]: GlobalFunction } = {};\n /**\n * The object holding any registered subtree root node definitions keyed on tree name.\n */\n private static registeredSubtrees: { [key: string]: RootNodeDefinition } = {};\n\n /**\n * Gets the function with the specified name.\n * @param name The name of the function.\n * @returns The function with the specified name.\n */\n public static getFunc(name: string): GlobalFunction {\n return this.registeredFunctions[name];\n }\n\n /**\n * Sets the function with the specified name for later lookup.\n * @param name The name of the function.\n * @param func The function.\n */\n public static setFunc(name: string, func: GlobalFunction): void {\n this.registeredFunctions[name] = func;\n }\n\n /**\n * Gets the function invoker for the specified agent and function name.\n * If a function with the specified name exists on the agent object then it will\n * be returned, otherwise we will then check the registered functions for a match.\n * @param agent The agent instance that this behaviour tree is modelling behaviour for.\n * @param name The function name.\n * @returns The function invoker for the specified agent and function name.\n */\n static getFuncInvoker(agent: Agent, name: string): InvokerFunction | null {\n // Check whether the agent contains the specified function.\n const agentFunction = agent[name];\n if (agentFunction && typeof agentFunction === \"function\") {\n return (args: any[]) => agentFunction.apply(agent, args);\n }\n\n // The agent does not contain the specified function but it may have been registered at some point.\n if (this.registeredFunctions[name] && typeof this.registeredFunctions[name] === \"function\") {\n const registeredFunction = this.registeredFunctions[name];\n return (args: any[]) => registeredFunction(agent, ...args.map((arg) => arg.value));\n }\n\n // We have no function to invoke.\n return null;\n }\n\n /**\n * Gets all registered subtree root node definitions.\n */\n static getSubtrees(): { [key: string]: RootNodeDefinition } {\n return this.registeredSubtrees;\n }\n\n /**\n * Sets the subtree with the specified name for later lookup.\n * @param name The name of the subtree.\n * @param subtree The subtree.\n */\n static setSubtree(name: string, subtree: RootNodeDefinition) {\n this.registeredSubtrees[name] = subtree;\n }\n\n /**\n * Removes the registered function or subtree with the specified name.\n * @param name The name of the registered function or subtree.\n */\n static remove(name: string) {\n delete this.registeredFunctions[name];\n delete this.registeredSubtrees[name];\n }\n\n /**\n * Remove all registered functions and subtrees.\n */\n static empty() {\n this.registeredFunctions = {};\n this.registeredSubtrees = {};\n }\n}\n", "import Node from \"../../nodes/Node\";\n\n/**\n * An exception thrown when evaluating node guard path conditions and a conditions fails.\n */\nexport default class GuardUnsatisifedException extends Error {\n /**\n * @param source The node at which a guard condition failed.\n */\n constructor(private source: Node) {\n super(\"A guard path condition has failed\");\n }\n\n /**\n * Gets whether the specified node is the node at which a guard condition failed.\n * @param node The node to check against the source node.\n * @returns Whether the specified node is the node at which a guard condition failed.\n */\n isSourceNode = (node: Node) => node === this.source;\n}\n", "import { Agent } from \"../../Agent\";\nimport Guard from \"./Guard\";\nimport Node from \"../../nodes/Node\";\nimport GuardUnsatisifedException from \"./GuardUnsatisifedException\";\n\nexport type GuardPathPart = {\n node: Node;\n guards: Guard[];\n};\n\n/**\n * Represents a path of node guards along a root-to-leaf tree path.\n */\nexport default class GuardPath {\n /**\n * @param nodes An array of objects defining a node instance -> guard link, ordered by node depth.\n */\n constructor(private nodes: GuardPathPart[]) {}\n\n /**\n * Evaluate guard conditions for all guards in the tree path, moving outwards from the root.\n * @param agent The agent, required for guard evaluation.\n * @returns An evaluation results object.\n */\n evaluate = (agent: Agent) => {\n // We need to evaluate guard conditions for nodes up the tree, moving outwards from the root.\n for (const details of this.nodes) {\n // There can be multiple guards per node.\n for (const guard of details.guards) {\n // Check whether the guard condition passes, and throw an exception if not.\n if (!guard.isSatisfied(agent)) {\n throw new GuardUnsatisifedException(details.node);\n }\n }\n }\n };\n}\n", "import { BehaviourTreeOptions } from \"../BehaviourTreeOptions\";\nimport State, { AnyState } from \"../State\";\nimport { Agent } from \"../Agent\";\nimport Leaf from \"./leaf/Leaf\";\nimport Attribute from \"../attributes/Attribute\";\nimport Entry from \"../attributes/callbacks/Entry\";\nimport Exit from \"../attributes/callbacks/Exit\";\nimport Step from \"../attributes/callbacks/Step\";\nimport Guard from \"../attributes/guards/Guard\";\nimport GuardPath from \"../attributes/guards/GuardPath\";\nimport GuardUnsatisifedException from \"../attributes/guards/GuardUnsatisifedException\";\n\n/**\n * A base node.\n */\nexport default abstract class Node {\n /**\n * The node uid.\n */\n private readonly uid: string = createNodeUid();\n /**\n * The node state.\n */\n private state: AnyState = State.READY;\n /**\n * The guard path to evaluate as part of a node update.\n */\n private guardPath: GuardPath | undefined;\n\n /**\n * @param type The node type.\n * @param attributes The node attributes.\n * @param args The node argument definitions.\n */\n constructor(private type: string, private attributes: Attribute[], private args: any[]) {}\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected abstract onUpdate(agent: Agent, options: BehaviourTreeOptions): void;\n\n /**\n * Gets the name of the node.\n */\n public abstract getName(): string;\n\n /**\n * Gets whether this node is a leaf node.\n */\n public abstract isLeafNode: () => this is Leaf;\n\n /**\n * Gets/Sets the state of the node.\n */\n getState = (): AnyState => this.state;\n setState = (value: AnyState): void => {\n this.state = value;\n };\n\n /**\n * Gets the unique id of the node.\n */\n getUid = () => this.uid;\n\n /**\n * Gets the type of the node.\n */\n getType = () => this.type;\n\n /**\n * Gets the node attributes.\n */\n getAttributes = () => this.attributes;\n\n /**\n * Gets the node arguments.\n */\n getArguments = () => this.args;\n\n /**\n * Gets the node attribute with the specified type, or null if it does not exist.\n */\n getAttribute(type: \"entry\" | \"ENTRY\"): Entry;\n getAttribute(type: \"exit\" | \"EXIT\"): Exit;\n getAttribute(type: \"step\" | \"STEP\"): Step;\n getAttribute(type: string): Attribute {\n return (\n this.getAttributes().filter((decorator) => decorator.type.toUpperCase() === type.toUpperCase())[0] || null\n );\n }\n\n /**\n * Gets the node attributes.\n */\n getGuardAttributes = (): Guard[] => this.getAttributes().filter((decorator) => decorator.isGuard()) as Guard[];\n\n /**\n * Sets the guard path to evaluate as part of a node update.\n */\n setGuardPath = (value: GuardPath) => (this.guardPath = value);\n\n /**\n * Gets whether a guard path is assigned to this node.\n */\n hasGuardPath = () => !!this.guardPath;\n\n /**\n * Gets whether this node is in the specified state.\n * @param value The value to compare to the node state.\n */\n public is(value: AnyState): boolean {\n return this.state === value;\n }\n\n /**\n * Reset the state of the node.\n */\n public reset(): void {\n this.setState(State.READY);\n }\n\n /**\n * Abort the running of this node.\n * @param agent The agent.\n */\n public abort(agent: Agent): void {\n // There is nothing to do if this node is not in the running state.\n if (!this.is(State.RUNNING)) {\n return;\n }\n\n // Reset the state of this node.\n this.reset();\n\n this.getAttribute(\"exit\")?.callAgentFunction(agent, false, true);\n }\n\n /**\n * Update the node.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n * @returns The result of the update.\n */\n public update(agent: Agent, options: BehaviourTreeOptions): void {\n // If this node is already in a 'SUCCEEDED' or 'FAILED' state then there is nothing to do.\n if (this.is(State.SUCCEEDED) || this.is(State.FAILED)) {\n return;\n }\n\n try {\n // Evaluate all of the guard path conditions for the current tree path.\n this.guardPath!.evaluate(agent);\n\n // If this node is in the READY state then call the ENTRY for this node if it exists.\n if (this.is(State.READY)) {\n this.getAttribute(\"entry\")?.callAgentFunction(agent);\n }\n\n this.getAttribute(\"step\")?.callAgentFunction(agent);\n\n // Do the actual update.\n this.onUpdate(agent, options);\n\n // If this node is now in a 'SUCCEEDED' or 'FAILED' state then call the EXIT for this node if it exists.\n if (this.is(State.SUCCEEDED) || this.is(State.FAILED)) {\n this.getAttribute(\"exit\")?.callAgentFunction(agent, this.is(State.SUCCEEDED), false);\n }\n } catch (error) {\n // If the error is a GuardUnsatisfiedException then we need to determine if this node is the source.\n if (error instanceof GuardUnsatisifedException && error.isSourceNode(this)) {\n // Abort the current node.\n this.abort(agent);\n\n // Any node that is the source of an abort will be a failed node.\n this.setState(State.FAILED);\n } else {\n throw error;\n }\n }\n }\n}\n\n/**\n * Create a randomly generated node uid.\n * @returns A randomly generated node uid.\n */\nfunction createNodeUid(): string {\n var S4 = function () {\n return (((1 + Math.random()) * 0x10000) | 0).toString(16).substring(1);\n };\n return S4() + S4() + \"-\" + S4() + \"-\" + S4() + \"-\" + S4() + \"-\" + S4() + S4() + S4();\n}\n", "import Node from \"../Node\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\n\n/**\n * A composite node that wraps child nodes.\n */\nexport default abstract class Composite extends Node {\n /**\n * @param type The node type.\n * @param attributes The node attributes.\n * @param children The child nodes.\n */\n constructor(type: string, attributes: Attribute[], protected children: Node[]) {\n super(type, attributes, []);\n }\n\n /**\n * Gets whether this node is a leaf node.\n */\n isLeafNode = () => false;\n\n /**\n * Gets the children of this node.\n */\n getChildren = () => this.children;\n\n /**\n * Reset the state of the node.\n */\n reset = () => {\n // Reset the state of this node.\n this.setState(State.READY);\n\n // Reset the state of any child nodes.\n this.getChildren().forEach((child) => child.reset());\n };\n\n /**\n * Abort the running of this node.\n * @param agent The agent.\n */\n abort = (agent: Agent) => {\n // There is nothing to do if this node is not in the running state.\n if (!this.is(State.RUNNING)) {\n return;\n }\n\n // Abort any child nodes.\n this.getChildren().forEach((child) => child.abort(agent));\n\n // Reset the state of this node.\n this.reset();\n\n this.getAttribute(\"exit\")?.callAgentFunction(agent, false, true);\n };\n}\n", "import Composite from \"./Composite\";\nimport State from \"../../State\";\nimport Node from \"../Node\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A PARALLEL node.\n * The child nodes are executed concurrently until one fails or all succeed.\n */\nexport default class Parallel extends Composite {\n /**\n * @param attributes The node attributes.\n * @param children The child nodes.\n */\n constructor(attributes: Attribute[], children: Node[]) {\n super(\"parallel\", attributes, children);\n }\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // Keep a count of the number of succeeded child nodes.\n let succeededCount = 0;\n\n let hasChildFailed = false;\n\n // Iterate over all of the children of this node.\n for (const child of this.children) {\n // If the child has never been updated or is running then we will need to update it now.\n if (child.getState() === State.READY || child.getState() === State.RUNNING) {\n // Update the child of this node.\n child.update(agent, options);\n }\n\n // If the current child has a state of 'SUCCEEDED' then we should move on to the next child.\n if (child.getState() === State.SUCCEEDED) {\n // The child node has succeeded, keep track of this to determine if all children have.\n succeededCount++;\n\n // The child node succeeded, but we have not finished checking every child node yet.\n continue;\n }\n\n // If the current child has a state of 'FAILED' then this node is also a 'FAILED' node.\n if (child.getState() === State.FAILED) {\n hasChildFailed = true;\n\n // There is no need to check the rest of the children.\n break;\n }\n\n // The node should be in the 'RUNNING' state.\n if (child.getState() !== State.RUNNING) {\n // The child node was not in an expected state.\n throw new Error(\"child node was not in an expected state.\");\n }\n }\n\n if (hasChildFailed) {\n // This node is a 'FAILED' node.\n this.setState(State.FAILED);\n\n // Abort every running child.\n for (const child of this.children) {\n if (child.getState() === State.RUNNING) {\n child.abort(agent);\n }\n }\n } else {\n // If all children have succeeded then this node has also succeeded, otherwise it is still running.\n this.setState(succeededCount === this.children.length ? State.SUCCEEDED : State.RUNNING);\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => \"PARALLEL\";\n}\n", "import Composite from \"./Composite\";\nimport Node from \"../Node\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A SELECTOR node.\n * The child nodes are executed in sequence until one succeeds or all fail.\n */\nexport default class Selector extends Composite {\n /**\n * @param attributes The node attributes.\n * @param children The child nodes.\n */\n constructor(attributes: Attribute[], protected children: Node[]) {\n super(\"selector\", attributes, children);\n }\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // Iterate over all of the children of this node.\n for (const child of this.children) {\n // If the child has never been updated or is running then we will need to update it now.\n if (child.getState() === State.READY || child.getState() === State.RUNNING) {\n // Update the child of this node.\n child.update(agent, options);\n }\n\n // If the current child has a state of 'SUCCEEDED' then this node is also a 'SUCCEEDED' node.\n if (child.getState() === State.SUCCEEDED) {\n // This node is a 'SUCCEEDED' node.\n this.setState(State.SUCCEEDED);\n\n // There is no need to check the rest of the selector nodes.\n return;\n }\n\n // If the current child has a state of 'FAILED' then we should move on to the next child.\n if (child.getState() === State.FAILED) {\n // Find out if the current child is the last one in the selector.\n // If it is then this sequence node has also failed.\n if (this.children.indexOf(child) === this.children.length - 1) {\n // This node is a 'FAILED' node.\n this.setState(State.FAILED);\n\n // There is no need to check the rest of the selector as we have completed it.\n return;\n } else {\n // The child node failed, try the next one.\n continue;\n }\n }\n\n // The node should be in the 'RUNNING' state.\n if (child.getState() === State.RUNNING) {\n // This node is a 'RUNNING' node.\n this.setState(State.RUNNING);\n\n // There is no need to check the rest of the selector as the current child is still running.\n return;\n }\n\n // The child node was not in an expected state.\n throw new Error(\"child node was not in an expected state.\");\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => \"SELECTOR\";\n}\n", "import Composite from \"./Composite\";\nimport Node from \"../Node\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A SEQUENCE node.\n * The child nodes are executed in sequence until one fails or all succeed.\n */\nexport default class Sequence extends Composite {\n /**\n * @param attributes The node attributes.\n * @param children The child nodes.\n */\n constructor(attributes: Attribute[], protected children: Node[]) {\n super(\"sequence\", attributes, children);\n }\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // Iterate over all of the children of this node.\n for (const child of this.children) {\n // If the child has never been updated or is running then we will need to update it now.\n if (child.getState() === State.READY || child.getState() === State.RUNNING) {\n // Update the child of this node.\n child.update(agent, options);\n }\n\n // If the current child has a state of 'SUCCEEDED' then we should move on to the next child.\n if (child.getState() === State.SUCCEEDED) {\n // Find out if the current child is the last one in the sequence.\n // If it is then this sequence node has also succeeded.\n if (this.children.indexOf(child) === this.children.length - 1) {\n // This node is a 'SUCCEEDED' node.\n this.setState(State.SUCCEEDED);\n\n // There is no need to check the rest of the sequence as we have completed it.\n return;\n } else {\n // The child node succeeded, but we have not finished the sequence yet.\n continue;\n }\n }\n\n // If the current child has a state of 'FAILED' then this node is also a 'FAILED' node.\n if (child.getState() === State.FAILED) {\n // This node is a 'FAILED' node.\n this.setState(State.FAILED);\n\n // There is no need to check the rest of the sequence.\n return;\n }\n\n // The node should be in the 'RUNNING' state.\n if (child.getState() === State.RUNNING) {\n // This node is a 'RUNNING' node.\n this.setState(State.RUNNING);\n\n // There is no need to check the rest of the sequence as the current child is still running.\n return;\n }\n\n // The child node was not in an expected state.\n throw new Error(\"child node was not in an expected state.\");\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => \"SEQUENCE\";\n}\n", "import createLotto from \"lotto-draw\";\n\nimport Node from \"../Node\";\nimport Composite from \"./Composite\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A LOTTO node.\n * A winning child is picked on the initial update of this node, based on ticket weighting.\n * The state of this node will match the state of the winning child.\n */\nexport default class Lotto extends Composite {\n /**\n * @param attributes The node attributes.\n * @param weights The child node weights.\n * @param children The child nodes.\n */\n constructor(attributes: Attribute[], private weights: number[] | undefined, children: Node[]) {\n super(\"lotto\", attributes, children);\n }\n\n /**\n * The child node selected to be the active one.\n */\n private selectedChild: Node | undefined;\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // If this node is in the READY state then we need to pick a winning child node.\n if (this.is(State.READY)) {\n // Create a lotto draw with which to randomly pick a child node to become the active one.\n const lottoDraw = createLotto({\n // Hook up the optional 'random' behaviour tree function option to the one used by 'lotto-draw'.\n random: options.random,\n // Pass in each child node as a participant in the lotto draw with their respective ticket count.\n participants: this.children.map((child, index) => [child, this.weights?.[index] || 1])\n });\n\n // Randomly pick a child based on ticket weighting, this will become the active child for this composite node.\n this.selectedChild = lottoDraw.draw() || undefined;\n }\n\n // If something went wrong and we don't have an active child then we should throw an error.\n if (!this.selectedChild) {\n throw new Error(\"failed to update lotto node as it has no active child\");\n }\n\n // If the selected child has never been updated or is running then we will need to update it now.\n if (this.selectedChild.getState() === State.READY || this.selectedChild.getState() === State.RUNNING) {\n this.selectedChild.update(agent, options);\n }\n\n // The state of the lotto node is the state of its selected child.\n this.setState(this.selectedChild.getState());\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => (this.weights ? `LOTTO [${this.weights.join(\",\")}]` : \"LOTTO\");\n}\n", "import Node from \"../Node\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\n\n/**\n * A decorator node that wraps a single child node.\n */\nexport default abstract class Decorator extends Node {\n /**\n * @param type The node type.\n * @param attributes The node attributes.\n * @param child The child node.\n */\n constructor(type: string, attributes: Attribute[], protected child: Node) {\n super(type, attributes, []);\n }\n\n /**\n * Gets whether this node is a leaf node.\n */\n isLeafNode = () => false;\n\n /**\n * Gets the children of this node.\n */\n getChildren = () => [this.child];\n\n /**\n * Reset the state of the node.\n */\n reset = () => {\n // Reset the state of this node.\n this.setState(State.READY);\n\n // Reset the state of the child node.\n this.child.reset();\n };\n\n /**\n * Abort the running of this node.\n * @param agent The agent.\n */\n abort = (agent: Agent) => {\n // There is nothing to do if this node is not in the running state.\n if (!this.is(State.RUNNING)) {\n return;\n }\n\n // Abort the child node.\n this.child.abort(agent);\n\n // Reset the state of this node.\n this.reset();\n\n this.getAttribute(\"exit\")?.callAgentFunction(agent, false, true);\n };\n}\n", "import Node from \"../Node\";\nimport Decorator from \"./Decorator\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A Fail node.\n * This node wraps a single child and will always move to the 'FAILED' state when the child moves to a 'SUCCEEDED' or 'FAILED' state.\n */\nexport default class Fail extends Decorator {\n /**\n * @param attributes The node attributes.\n * @param child The child node.\n */\n constructor(attributes: Attribute[], child: Node) {\n super(\"fail\", attributes, child);\n }\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // If the child has never been updated or is running then we will need to update it now.\n if (this.child.getState() === State.READY || this.child.getState() === State.RUNNING) {\n this.child.update(agent, options);\n }\n\n // The state of this node will depend in the state of its child.\n switch (this.child.getState()) {\n case State.RUNNING:\n this.setState(State.RUNNING);\n break;\n\n case State.SUCCEEDED:\n case State.FAILED:\n this.setState(State.FAILED);\n break;\n\n default:\n this.setState(State.READY);\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => \"FAIL\";\n}\n", "import Decorator from \"./Decorator\";\nimport State from \"../../State\";\nimport Node from \"../Node\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A Flip node.\n * This node wraps a single child and will flip the state of the child state.\n */\nexport default class Flip extends Decorator {\n /**\n * @param attributes The node attributes.\n * @param child The child node.\n */\n constructor(attributes: Attribute[], child: Node) {\n super(\"flip\", attributes, child);\n }\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // If the child has never been updated or is running then we will need to update it now.\n if (this.child.getState() === State.READY || this.child.getState() === State.RUNNING) {\n this.child.update(agent, options);\n }\n\n // The state of this node will depend in the state of its child.\n switch (this.child.getState()) {\n case State.RUNNING:\n this.setState(State.RUNNING);\n break;\n\n case State.SUCCEEDED:\n this.setState(State.FAILED);\n break;\n\n case State.FAILED:\n this.setState(State.SUCCEEDED);\n break;\n\n default:\n this.setState(State.READY);\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => \"FLIP\";\n}\n", "import Node from \"../Node\";\nimport Decorator from \"./Decorator\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A REPEAT node.\n * The node has a single child which can have:\n * -- A number of iterations for which to repeat the child node.\n * -- An infinite repeat loop if neither an iteration count or a condition function is defined.\n * The REPEAT node will stop and have a 'FAILED' state if its child is ever in a 'FAILED' state after an update.\n * The REPEAT node will attempt to move on to the next iteration if its child is ever in a 'SUCCEEDED' state.\n */\nexport default class Repeat extends Decorator {\n /**\n * @param attributes The node attributes.\n * @param iterations The number of iterations to repeat the child node.\n * @param iterationsMin The minimum possible number of iterations to repeat the child node.\n * @param iterationsMax The maximum possible number of iterations to repeat the child node.\n * @param child The child node.\n */\n constructor(\n attributes: Attribute[],\n private iterations: number | null,\n private iterationsMin: number | null,\n private iterationsMax: number | null,\n child: Node\n ) {\n super(\"repeat\", attributes, child);\n }\n\n /**\n * The number of target iterations to make.\n */\n private targetIterationCount: number | null = null;\n\n /**\n * The current iteration count.\n */\n private currentIterationCount: number = 0;\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // If this node is in the READY state then we need to reset the child and the target iteration count.\n if (this.is(State.READY)) {\n // Reset the child node.\n this.child.reset();\n\n // Reset the current iteration count.\n this.currentIterationCount = 0;\n\n // Set the target iteration count.\n this.setTargetIterationCount(options);\n }\n\n // Do a check to see if we can iterate. If we can then this node will move into the 'RUNNING' state.\n // If we cannot iterate then we have hit our target iteration count, which means that the node has succeeded.\n if (this.canIterate()) {\n // This node is in the running state and can do its initial iteration.\n this.setState(State.RUNNING);\n\n // We may have already completed an iteration, meaning that the child node will be in the SUCCEEDED state.\n // If this is the case then we will have to reset the child node now.\n if (this.child.getState() === State.SUCCEEDED) {\n this.child.reset();\n }\n\n // Update the child of this node.\n this.child.update(agent, options);\n\n // If the child moved into the FAILED state when we updated it then there is nothing left to do and this node has also failed.\n // If it has moved into the SUCCEEDED state then we have completed the current iteration.\n if (this.child.getState() === State.FAILED) {\n // The child has failed, meaning that this node has failed.\n this.setState(State.FAILED);\n\n return;\n } else if (this.child.getState() === State.SUCCEEDED) {\n // We have completed an iteration.\n this.currentIterationCount += 1;\n }\n } else {\n // This node is in the 'SUCCEEDED' state as we cannot iterate any more.\n this.setState(State.SUCCEEDED);\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => {\n if (this.iterations !== null) {\n return `REPEAT ${this.iterations}x`;\n } else if (this.iterationsMin !== null && this.iterationsMax !== null) {\n return `REPEAT ${this.iterationsMin}x-${this.iterationsMax}x`;\n } else {\n return \"REPEAT\";\n }\n };\n\n /**\n * Reset the state of the node.\n */\n reset = () => {\n // Reset the state of this node.\n this.setState(State.READY);\n\n // Reset the current iteration count.\n this.currentIterationCount = 0;\n\n // Reset the child node.\n this.child.reset();\n };\n\n /**\n * Gets whether an iteration can be made.\n * @returns Whether an iteration can be made.\n */\n private canIterate = () => {\n if (this.targetIterationCount !== null) {\n // We can iterate as long as we have not reached our target iteration count.\n return this.currentIterationCount < this.targetIterationCount;\n }\n\n // If neither an iteration count or a condition function were defined then we can iterate indefinitely.\n return true;\n };\n\n /**\n * Sets the target iteration count.\n * @param options The behaviour tree options object.\n */\n private setTargetIterationCount = (options: BehaviourTreeOptions) => {\n // Are we dealing with an explicit iteration count or will we be randomly picking a iteration count between the min and max iteration count.\n if (this.iterations !== null) {\n this.targetIterationCount = this.iterations;\n } else if (this.iterationsMin !== null && this.iterationsMax !== null) {\n // We will be picking a random iteration count between a min and max iteration count, if the optional 'random'\n // behaviour tree function option is defined then we will be using that, otherwise we will fall back to using Math.random.\n const random = typeof options.random === \"function\" ? options.random : Math.random;\n\n // Pick a random iteration count between a min and max iteration count.\n this.targetIterationCount = Math.floor(\n random() * (this.iterationsMax - this.iterationsMin + 1) + this.iterationsMin\n );\n } else {\n this.targetIterationCount = null;\n }\n };\n}\n", "import Node from \"../Node\";\nimport Decorator from \"./Decorator\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A RETRY node.\n * The node has a single child which can have:\n * -- A number of iterations for which to repeat the child node.\n * -- An infinite repeat loop if neither an iteration count or a condition function is defined.\n * The RETRY node will stop and have a 'SUCCEEDED' state if its child is ever in a 'SUCCEEDED' state after an update.\n * The RETRY node will attempt to move on to the next iteration if its child is ever in a 'FAILED' state.\n */\nexport default class Retry extends Decorator {\n /**\n * @param attributes The node attributes.\n * @param attempts The number of attempts to retry the child node.\n * @param attemptsMin The minimum possible number of attempts to retry the child node.\n * @param attemptsMax The maximum possible number of attempts to retry the child node.\n * @param child The child node.\n */\n constructor(\n attributes: Attribute[],\n private attempts: number | null,\n private attemptsMin: number | null,\n private attemptsMax: number | null,\n child: Node\n ) {\n super(\"retry\", attributes, child);\n }\n\n /**\n * The number of target attempts to make.\n */\n private targetAttemptCount: number | null = null;\n\n /**\n * The current attempt count.\n */\n private currentAttemptCount: number = 0;\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // If this node is in the READY state then we need to reset the child and the target attempt count.\n if (this.is(State.READY)) {\n // Reset the child node.\n this.child.reset();\n\n // Reset the current attempt count.\n this.currentAttemptCount = 0;\n\n // Set the target attempt count.\n this.setTargetAttemptCount(options);\n }\n\n // Do a check to see if we can attempt. If we can then this node will move into the 'RUNNING' state.\n // If we cannot attempt then we have hit our target attempt count, which means that the node has succeeded.\n if (this.canAttempt()) {\n // This node is in the running state and can do its initial attempt.\n this.setState(State.RUNNING);\n\n // We may have already completed an attempt, meaning that the child node will be in the FAILED state.\n // If this is the case then we will have to reset the child node now.\n if (this.child.getState() === State.FAILED) {\n this.child.reset();\n }\n\n // Update the child of this node.\n this.child.update(agent, options);\n\n // If the child moved into the SUCCEEDED state when we updated it then there is nothing left to do and this node has also succeeded.\n // If it has moved into the FAILED state then we have completed the current attempt.\n if (this.child.getState() === State.SUCCEEDED) {\n // The child has succeeded, meaning that this node has succeeded.\n this.setState(State.SUCCEEDED);\n\n return;\n } else if (this.child.getState() === State.FAILED) {\n // We have completed an attempt.\n this.currentAttemptCount += 1;\n }\n } else {\n // This node is in the 'FAILED' state as we cannot iterate any more.\n this.setState(State.FAILED);\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => {\n if (this.attempts !== null) {\n return `RETRY ${this.attempts}x`;\n } else if (this.attemptsMin !== null && this.attemptsMax !== null) {\n return `RETRY ${this.attemptsMin}x-${this.attemptsMax}x`;\n } else {\n return \"RETRY\";\n }\n };\n\n /**\n * Reset the state of the node.\n */\n reset = () => {\n // Reset the state of this node.\n this.setState(State.READY);\n\n // Reset the current attempt count.\n this.currentAttemptCount = 0;\n\n // Reset the child node.\n this.child.reset();\n };\n\n /**\n * Gets whether an attempt can be made.\n * @returns Whether an attempt can be made.\n */\n canAttempt = () => {\n if (this.targetAttemptCount !== null) {\n // We can attempt as long as we have not reached our target attempt count.\n return this.currentAttemptCount < this.targetAttemptCount;\n }\n\n // If neither an attempt count or a condition function were defined then we can attempt indefinitely.\n return true;\n };\n\n /**\n * Sets the target attempt count.\n * @param options The behaviour tree options object.\n */\n setTargetAttemptCount = (options: BehaviourTreeOptions) => {\n // Are we dealing with an explicit attempt count or will we be randomly picking an attempt count between the min and max attempt count.\n if (this.attempts !== null) {\n this.targetAttemptCount = this.attempts;\n } else if (this.attemptsMin !== null && this.attemptsMax !== null) {\n // We will be picking a random attempt count between a min and max attempt count, if the optional 'random'\n // behaviour tree function option is defined then we will be using that, otherwise we will fall back to using Math.random.\n const random = typeof options.random === \"function\" ? options.random : Math.random;\n\n // Pick a random attempt count between a min and max attempt count.\n this.targetAttemptCount = Math.floor(\n random() * (this.attemptsMax - this.attemptsMin + 1) + this.attemptsMin\n );\n } else {\n this.targetAttemptCount = null;\n }\n };\n}\n", "import Node from \"../Node\";\nimport Decorator from \"./Decorator\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A Root node.\n * The root node will have a single child.\n */\nexport default class Root extends Decorator {\n /**\n * @param attributes The node attributes.\n * @param child The child node.\n */\n constructor(attributes: Attribute[], child: Node) {\n super(\"root\", attributes, child);\n }\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // If the child has never been updated or is running then we will need to update it now.\n if (this.child.getState() === State.READY || this.child.getState() === State.RUNNING) {\n // Update the child of this node.\n this.child.update(agent, options);\n }\n\n // The state of the root node is the state of its child.\n this.setState(this.child.getState());\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => \"ROOT\";\n}\n", "import Node from \"../Node\";\nimport Decorator from \"./Decorator\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A Succeed node.\n * This node wraps a single child and will always move to the 'SUCCEEDED' state when the child moves to a 'SUCCEEDED' or 'FAILED' state.\n */\nexport default class Succeed extends Decorator {\n /**\n * @param attributes The node attributes.\n * @param child The child node.\n */\n constructor(attributes: Attribute[], child: Node) {\n super(\"succeed\", attributes, child);\n }\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // If the child has never been updated or is running then we will need to update it now.\n if (this.child.getState() === State.READY || this.child.getState() === State.RUNNING) {\n this.child.update(agent, options);\n }\n\n // The state of this node will depend in the state of its child.\n switch (this.child.getState()) {\n case State.RUNNING:\n this.setState(State.RUNNING);\n break;\n\n case State.SUCCEEDED:\n case State.FAILED:\n this.setState(State.SUCCEEDED);\n break;\n\n default:\n this.setState(State.READY);\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => \"SUCCEED\";\n}\n", "import Node from \"../Node\";\n\n/**\n * A leaf node.\n */\nexport default abstract class Leaf extends Node {\n /**\n * Gets whether this node is a leaf node.\n */\n isLeafNode = () => true;\n}\n", "import { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\nimport State, { CompleteState } from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Leaf from \"./Leaf\";\nimport Lookup from \"../../Lookup\";\nimport Attribute from \"../../attributes/Attribute\";\n\n/**\n * The type representing a resolved/rejected update promise.\n */\ntype UpdatePromiseResult = {\n /**\n * Whether the promise was resolved rather than rejected.\n */\n isResolved: boolean;\n\n /**\n * The promise resolved value or rejection reason.\n */\n value: any;\n};\n\n/**\n * An Action leaf node.\n * This represents an immediate or ongoing state of behaviour.\n */\nexport default class Action extends Leaf {\n /**\n * @param attributes The node attributes.\n * @param actionName The action name.\n * @param actionArguments The array of action argument definitions.\n */\n constructor(attributes: Attribute[], private actionName: string, private actionArguments: any[]) {\n super(\"action\", attributes, actionArguments);\n }\n\n /**\n * Whether there is a pending update promise.\n */\n private isUsingUpdatePromise = false;\n\n /**\n * The finished state result of an update promise.\n */\n private updatePromiseResult: UpdatePromiseResult | null = null;\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // If the result of this action depends on an update promise then there is nothing to do until it settles.\n if (this.isUsingUpdatePromise) {\n // Are we still waiting for our update promise to settle?\n if (!this.updatePromiseResult) {\n return;\n }\n\n const { isResolved, value } = this.updatePromiseResult;\n\n // Our update promise settled, was it resolved or rejected?\n if (isResolved) {\n // Our promise resolved so check to make sure the result is a valid finished state.\n if (value !== State.SUCCEEDED && value !== State.FAILED) {\n throw new Error(\n \"action node promise resolved with an invalid value, expected a State.SUCCEEDED or State.FAILED value to be returned\"\n );\n }\n\n // Set the state of this node to match the state returned by the promise.\n this.setState(value);\n\n return;\n } else {\n // The promise was rejected, which isn't great.\n throw new Error(`action function '${this.actionName}' promise rejected with '${value}'`);\n }\n }\n\n // Attempt to get the invoker for the action function.\n const actionFuncInvoker = Lookup.getFuncInvoker(agent, this.actionName);\n\n // The action function should be defined.\n if (actionFuncInvoker === null) {\n throw new Error(\n `cannot update action node as the action '${this.actionName}' function is not defined on the agent and has not been registered`\n );\n }\n\n let actionFunctionResult;\n\n try {\n // Call the action function, the result of which may be:\n // - The finished state of this action node.\n // - A promise to return a finished node state.\n // - Undefined if the node should remain in the running state.\n actionFunctionResult = actionFuncInvoker(this.actionArguments) as CompleteState | Promise;\n } catch (error) {\n // The user was naughty and threw something.\n throw new Error(`action function '${this.actionName}' threw '${error}'`);\n }\n\n if (actionFunctionResult instanceof Promise) {\n actionFunctionResult.then(\n (result) => {\n // If 'isUpdatePromisePending' is not set then the promise was cleared as it was resolving, probably via an abort of reset.\n if (!this.isUsingUpdatePromise) {\n return;\n }\n\n // Set the resolved update promise result so that it can be handled on the next update of this node.\n this.updatePromiseResult = {\n isResolved: true,\n value: result\n };\n },\n (reason) => {\n // If 'isUpdatePromisePending' is not set then the promise was cleared as it was resolving, probably via an abort or reset.\n if (!this.isUsingUpdatePromise) {\n return;\n }\n\n // Set the rejected update promise result so that it can be handled on the next update of this node.\n this.updatePromiseResult = {\n isResolved: false,\n value: reason\n };\n }\n );\n\n // This node will be in the 'RUNNING' state until the update promise resolves.\n this.setState(State.RUNNING);\n\n // We are now waiting for the promise returned by the use to resolve before we know what state this node is in.\n this.isUsingUpdatePromise = true;\n } else {\n // Validate the returned value.\n this.validateUpdateResult(actionFunctionResult);\n\n // Set the state of this node, this may be undefined, which just means that the node is still in the 'RUNNING' state.\n this.setState(actionFunctionResult || State.RUNNING);\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => this.actionName;\n\n /**\n * Reset the state of the node.\n */\n reset = () => {\n // Reset the state of this node.\n this.setState(State.READY);\n\n // There is no longer an update promise that we care about.\n this.isUsingUpdatePromise = false;\n this.updatePromiseResult = null;\n };\n\n /**\n * Validate the result of an update function call.\n * @param result The result of an update function call.\n */\n private validateUpdateResult = (result: CompleteState | State.RUNNING) => {\n switch (result) {\n case State.SUCCEEDED:\n case State.FAILED:\n case State.RUNNING:\n case undefined:\n return;\n default:\n throw new Error(\n `expected action function '${this.actionName}' to return an optional State.SUCCEEDED or State.FAILED value but returned '${result}'`\n );\n }\n };\n}\n", "import { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Leaf from \"./Leaf\";\nimport Lookup from \"../../Lookup\";\nimport Attribute from \"../../attributes/Attribute\";\n\n/**\n * A Condition leaf node.\n * This will succeed or fail immediately based on an agent predicate, without moving to the 'RUNNING' state.\n */\nexport default class Condition extends Leaf {\n /**\n * @param attributes The node attributes.\n * @param conditionName The name of the condition function.\n * @param conditionArguments The array of condition argument definitions.\n */\n constructor(attributes: Attribute[], private conditionName: string, private conditionArguments: any[]) {\n super(\"condition\", attributes, conditionArguments);\n }\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // Attempt to get the invoker for the condition function.\n const conditionFuncInvoker = Lookup.getFuncInvoker(agent, this.conditionName);\n\n // The condition function should be defined.\n if (conditionFuncInvoker === null) {\n throw new Error(\n `cannot update condition node as the condition '${this.conditionName}' function is not defined on the agent and has not been registered`\n );\n }\n\n let conditionFunctionResult;\n\n try {\n // Call the condition function to determine the state of this node, the result of which should be a boolean.\n conditionFunctionResult = conditionFuncInvoker(this.conditionArguments);\n } catch (error) {\n // The user was naughty and threw something.\n throw new Error(`condition function '${this.conditionName}' threw '${error}'`);\n }\n\n // The result of calling the condition function must be a boolean value.\n if (typeof conditionFunctionResult !== \"boolean\") {\n throw new Error(\n `expected condition function '${this.conditionName}' to return a boolean but returned '${conditionFunctionResult}'`\n );\n }\n\n // Set the state of this node based on the result of calling the condition function.\n this.setState(!!conditionFunctionResult ? State.SUCCEEDED : State.FAILED);\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => this.conditionName;\n}\n", "import Leaf from \"./Leaf\";\nimport State from \"../../State\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { Agent } from \"../../Agent\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A WAIT node.\n * The state of this node will change to SUCCEEDED after a duration of time\n */\nexport default class Wait extends Leaf {\n /**\n * @param attributes The node attributes.\n * @param duration The duration that this node will wait to succeed in milliseconds.\n * @param durationMin The minimum possible duration in milliseconds that this node will wait to succeed.\n * @param durationMax The maximum possible duration in milliseconds that this node will wait to succeed.\n */\n constructor(\n attributes: Attribute[],\n private duration: number | null,\n private durationMin: number | null,\n private durationMax: number | null\n ) {\n super(\"wait\", attributes, []);\n }\n\n /**\n * The time in milliseconds at which this node was first updated.\n */\n private initialUpdateTime: number = 0;\n\n /**\n * The total duration in milliseconds that this node will be waiting for.\n */\n private totalDuration: number | null = null;\n\n /**\n * The duration in milliseconds that this node has been waiting for.\n */\n private waitedDuration: number = 0;\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // If this node is in the READY state then we need to set the initial update time.\n if (this.is(State.READY)) {\n // Set the initial update time.\n this.initialUpdateTime = new Date().getTime();\n\n // Set the initial waited duration.\n this.waitedDuration = 0;\n\n // Are we dealing with an explicit duration or will we be randomly picking a duration between the min and max duration.\n if (this.duration !== null) {\n this.totalDuration = this.duration;\n } else if (this.durationMin !== null && this.durationMax !== null) {\n // We will be picking a random duration between a min and max duration, if the optional 'random' behaviour tree\n // function option is defined then we will be using that, otherwise we will fall back to using Math.random.\n const random = typeof options.random === \"function\" ? options.random : Math.random;\n\n // Pick a random duration between a min and max duration.\n this.totalDuration = Math.floor(\n random() * (this.durationMax - this.durationMin + 1) + this.durationMin\n );\n } else {\n this.totalDuration = null;\n }\n\n // The node is now running until we finish waiting.\n this.setState(State.RUNNING);\n }\n\n // If we have no total duration then this wait node will wait indefinitely until it is aborted.\n if (this.totalDuration === null) {\n return;\n }\n\n // If we have a 'getDeltaTime' function defined as part of our options then we will use it to figure out how long we have waited for.\n if (typeof options.getDeltaTime === \"function\") {\n // Get the delta time.\n const deltaTime = options.getDeltaTime();\n\n // Our delta time must be a valid number and cannot be NaN.\n if (typeof deltaTime !== \"number\" || isNaN(deltaTime)) {\n throw new Error(\"The delta time must be a valid number and not NaN.\");\n }\n\n // Update the amount of time that this node has been waiting for based on the delta time.\n this.waitedDuration += deltaTime * 1000;\n } else {\n // We are not using a delta time, so we will just work out hom much time has passed since the first update.\n this.waitedDuration = new Date().getTime() - this.initialUpdateTime;\n }\n\n // Have we waited long enough?\n if (this.waitedDuration >= this.totalDuration) {\n // We have finished waiting!\n this.setState(State.SUCCEEDED);\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => {\n if (this.duration !== null) {\n return `WAIT ${this.duration}ms`;\n } else if (this.durationMin !== null && this.durationMax !== null) {\n return `WAIT ${this.durationMin}ms-${this.durationMax}ms`;\n } else {\n return \"WAIT\";\n }\n };\n}\n", "import Guard from \"./guards/Guard\";\n\nexport type AttributeDetails = {\n /** The attribute type. */\n type: string;\n\n /** The attribute arguments. */\n args: any[];\n};\n\n/**\n * A base node attribute.\n */\nexport default abstract class Attribute {\n /**\n * @param type The node attribute type.\n * @param args The array of attribute arguments.\n */\n constructor(public type: string, public args: any[]) {}\n\n /**\n * Gets the attribute details.\n */\n abstract getDetails(): TAttributeDetails;\n\n /**\n * Gets whether this attribute is a guard.\n */\n abstract isGuard: () => this is Guard;\n}\n", "import { Agent } from \"../../Agent\";\nimport Attribute, { AttributeDetails } from \"../Attribute\";\n\nexport type GuardAttributeDetails = {\n /** The name of the condition function that determines whether the guard is satisfied. */\n condition: string;\n} & AttributeDetails;\n\n/**\n * A base node guard attribute.\n */\nexport default abstract class Guard extends Attribute {\n /**\n * @param type The node attribute type.\n * @param args The array of decorator argument definitions.\n * @param condition The name of the condition function that determines whether the guard is satisfied.\n */\n constructor(type: string, args: any[], private condition: string) {\n super(type, args);\n }\n\n /**\n * Gets the name of the condition function that determines whether the guard is satisfied.\n */\n getCondition = () => this.condition;\n\n /**\n * Gets whether this attribute is a guard.\n */\n isGuard = () => true;\n\n /**\n * Gets the attribute details.\n */\n getDetails(): GuardAttributeDetails {\n return {\n type: this.type,\n args: this.args,\n condition: this.getCondition()\n };\n }\n\n /**\n * Gets whether the guard is satisfied.\n * @param agent The agent.\n * @returns Whether the guard is satisfied.\n */\n abstract isSatisfied(agent: Agent): boolean;\n}\n", "import Guard from \"./Guard\";\nimport Lookup from \"../../Lookup\";\nimport { Agent } from \"../../Agent\";\n\n/**\n * A WHILE guard which is satisfied as long as the given condition remains true.\n */\nexport default class While extends Guard {\n /**\n * @param condition The name of the condition function that determines whether the guard is satisfied.\n * @param args The array of decorator argument definitions.\n */\n constructor(condition: string, args: any[]) {\n super(\"while\", args, condition);\n }\n\n /**\n * Gets whether the guard is satisfied.\n * @param agent The agent.\n * @returns Whether the guard is satisfied.\n */\n isSatisfied = (agent: Agent) => {\n // Attempt to get the invoker for the condition function.\n const conditionFuncInvoker = Lookup.getFuncInvoker(agent, this.getCondition());\n\n // The condition function should be defined.\n if (conditionFuncInvoker === null) {\n throw new Error(\n `cannot evaluate node guard as the condition '${this.getCondition()}' function is not defined on the agent and has not been registered`\n );\n }\n\n // Call the condition function to determine whether this guard is satisfied.\n return !!conditionFuncInvoker(this.args);\n };\n}\n", "import Guard from \"./Guard\";\nimport Lookup from \"../../Lookup\";\nimport { Agent } from \"../../Agent\";\n\n/**\n * An UNTIL guard which is satisfied as long as the given condition remains false.\n */\nexport default class Until extends Guard {\n /**\n * @param condition The name of the condition function that determines whether the guard is satisfied.\n * @param args The array of decorator argument definitions.\n */\n constructor(condition: string, args: any[]) {\n super(\"until\", args, condition);\n }\n\n /**\n * Gets whether the guard is satisfied.\n * @param agent The agent.\n * @returns Whether the guard is satisfied.\n */\n isSatisfied = (agent: Agent) => {\n // Attempt to get the invoker for the condition function.\n const conditionFuncInvoker = Lookup.getFuncInvoker(agent, this.getCondition());\n\n // The condition function should be defined.\n if (conditionFuncInvoker === null) {\n throw new Error(\n `cannot evaluate node guard as the condition '${this.getCondition()}' function is not defined on the agent and has not been registered`\n );\n }\n\n // Call the condition function to determine whether this guard is satisfied.\n return !!!conditionFuncInvoker(this.args);\n };\n}\n", "import { Agent } from \"../../Agent\";\nimport Attribute, { AttributeDetails } from \"../Attribute\";\n\nexport type CallbackAttributeDetails = {\n /** The name of the agent function that is called. */\n functionName: string;\n} & AttributeDetails;\n\n/**\n * A base node callback attribute.\n */\nexport default abstract class Callback extends Attribute {\n /**\n * @param type The node attribute type.\n * @param args The array of decorator argument definitions.\n * @param functionName The name of the agent function to call.\n */\n constructor(type: string, args: any[], private functionName: string) {\n super(type, args);\n }\n\n /**\n * Gets the name of the agent function to call.\n */\n getFunctionName = () => this.functionName;\n\n /**\n * Gets whether this attribute is a guard.\n */\n isGuard = () => false;\n\n /**\n * Gets the attribute details.\n */\n getDetails(): CallbackAttributeDetails {\n return {\n type: this.type,\n args: this.args,\n functionName: this.getFunctionName()\n };\n }\n\n /**\n * Attempt to call the agent function that this callback refers to.\n * @param agent The agent.\n */\n abstract callAgentFunction: (agent: Agent, isSuccess: boolean, isAborted: boolean) => void;\n}\n", "import Callback from \"./Callback\";\nimport Lookup from \"../../Lookup\";\nimport { Agent } from \"../../Agent\";\n\n/**\n * An ENTRY callback which defines an agent function to call when the associated node is updated and moves out of running state.\n */\nexport default class Entry extends Callback {\n /**\n * @param functionName The name of the agent function to call.\n * @param args The array of callback argument definitions.\n */\n constructor(functionName: string, args: any[]) {\n super(\"entry\", args, functionName);\n }\n\n /**\n * Attempt to call the agent function that this callback refers to.\n * @param agent The agent.\n */\n callAgentFunction = (agent: Agent) => {\n // Attempt to get the invoker for the callback function.\n const callbackFuncInvoker = Lookup.getFuncInvoker(agent, this.getFunctionName());\n\n // The callback function should be defined.\n if (callbackFuncInvoker === null) {\n throw new Error(\n `cannot call entry function '${this.getFunctionName()}' as is not defined on the agent and has not been registered`\n );\n }\n\n // Call the callback function.\n callbackFuncInvoker(this.args);\n };\n}\n", "import Callback from \"./Callback\";\nimport Lookup from \"../../Lookup\";\nimport { Agent } from \"../../Agent\";\n\n/**\n * A STEP callback which defines an agent function to call when the associated node is updated.\n */\nexport default class Step extends Callback {\n /**\n * @param functionName The name of the agent function to call.\n * @param args The array of callback argument definitions.\n */\n constructor(functionName: string, args: any[]) {\n super(\"step\", args, functionName);\n }\n\n /**\n * Attempt to call the agent function that this callback refers to.\n * @param agent The agent.\n */\n callAgentFunction = (agent: Agent) => {\n // Attempt to get the invoker for the callback function.\n const callbackFuncInvoker = Lookup.getFuncInvoker(agent, this.getFunctionName());\n\n // The callback function should be defined.\n if (callbackFuncInvoker === null) {\n throw new Error(\n `cannot call step function '${this.getFunctionName()}' as is not defined on the agent and has not been registered`\n );\n }\n\n // Call the callback function.\n callbackFuncInvoker(this.args);\n };\n}\n", "import Callback from \"./Callback\";\nimport Lookup from \"../../Lookup\";\nimport { Agent } from \"../../Agent\";\n\n/**\n * An EXIT callback which defines an agent function to call when the associated node is updated and moves to a finished state or is aborted.\n */\nexport default class Exit extends Callback {\n /**\n * @param functionName The name of the agent function to call.\n * @param args The array of callback argument definitions.\n */\n constructor(functionName: string, args: any[]) {\n super(\"exit\", args, functionName);\n }\n\n /**\n * Attempt to call the agent function that this callback refers to.\n * @param agent The agent.\n * @param isSuccess Whether the decorated node was left with a success state.\n * @param isAborted Whether the decorated node was aborted.\n */\n callAgentFunction = (agent: Agent, isSuccess: boolean, isAborted: boolean) => {\n // Attempt to get the invoker for the callback function.\n const callbackFuncInvoker = Lookup.getFuncInvoker(agent, this.getFunctionName());\n\n // The callback function should be defined.\n if (callbackFuncInvoker === null) {\n throw new Error(\n `cannot call exit function '${this.getFunctionName()}' as is not defined on the agent and has not been registered`\n );\n }\n\n // Call the callback function\n callbackFuncInvoker([{ succeeded: isSuccess, aborted: isAborted }, ...this.args]);\n };\n}\n", "import { AnyNodeDefinition, RootNodeDefinition } from \"./BehaviourTreeDefinition\";\nimport GuardPath, { GuardPathPart } from \"./attributes/guards/GuardPath\";\nimport { validateBranchSubtreeLinks } from \"./BehaviourTreeDefinitionValidator\";\nimport { isInteger } from \"./BehaviourTreeDefinitionUtilities\";\nimport Node from \"./nodes/Node\";\nimport Composite from \"./nodes/composite/Composite\";\nimport Decorator from \"./nodes/decorator/Decorator\";\nimport Parallel from \"./nodes/composite/Parallel\";\nimport Selector from \"./nodes/composite/Selector\";\nimport Sequence from \"./nodes/composite/Sequence\";\nimport Lotto from \"./nodes/composite/Lotto\";\nimport Fail from \"./nodes/decorator/Fail\";\nimport Flip from \"./nodes/decorator/Flip\";\nimport Repeat from \"./nodes/decorator/Repeat\";\nimport Retry from \"./nodes/decorator/Retry\";\nimport Root from \"./nodes/decorator/Root\";\nimport Succeed from \"./nodes/decorator/Succeed\";\nimport Action from \"./nodes/leaf/Action\";\nimport Condition from \"./nodes/leaf/Condition\";\nimport Wait from \"./nodes/leaf/Wait\";\nimport Lookup from \"./Lookup\";\nimport Attribute from \"./attributes/Attribute\";\nimport While from \"./attributes/guards/While\";\nimport Until from \"./attributes/guards/Until\";\nimport Entry from \"./attributes/callbacks/Entry\";\nimport Step from \"./attributes/callbacks/Step\";\nimport Exit from \"./attributes/callbacks/Exit\";\n\n/**\n * A type representing any node instance in a behaviour tree.\n */\ntype AnyNode =\n | Root\n | Action\n | Condition\n | Wait\n | Sequence\n | Selector\n | Lotto\n | Parallel\n | Repeat\n | Retry\n | Flip\n | Succeed\n | Fail;\n\n/**\n * A type defining a mapping of root node identifiers to root node definitions.\n */\ntype RootNodeDefinitionMap = { [key: string | symbol]: RootNodeDefinition };\n\n/**\n * A symbol to use as the main root key in any root node mappings.\n */\nconst MAIN_ROOT_NODE_KEY = Symbol(\"__root__\");\n\n/**\n * Build and populate the root nodes based on the provided definition, assuming that the definition has been validated.\n * @param definition The root node definitions.\n * @returns The built and populated root node definitions.\n */\nexport default function buildRootNode(definition: RootNodeDefinition[]): Root {\n // Create a mapping of root node identifers to root node definitions, including globally registered subtree root node definitions.\n const rootNodeDefinitionMap = createRootNodeDefinitionMap(definition);\n\n // Now that we have all of our root node definitions (those part of the tree definition and those globally registered)\n // we should validate the branch-subtree links. This will also double-check that we dont have any circular dependencies\n // in our branch-subtree references and that we have no broken branch-subtree links.\n validateBranchSubtreeLinks(\n [rootNodeDefinitionMap[MAIN_ROOT_NODE_KEY], ...Object.values(rootNodeDefinitionMap)],\n true\n );\n\n // Create our populated tree of node instances, starting with our main root node.\n const rootNode = nodeFactory(rootNodeDefinitionMap[MAIN_ROOT_NODE_KEY], rootNodeDefinitionMap) as Root;\n\n // Set a guard path on every leaf of the tree to evaluate as part of each update.\n applyLeafNodeGuardPaths(rootNode);\n\n // We only need to return the main root node.\n return rootNode;\n}\n\n/**\n * A factory function which creates a node instance based on the specified definition.\n * @param definition The node definition.\n * @param rootNodeDefinitionMap The mapping of root node identifers to root node definitions, including globally registered subtree root node definitions.\n * @returns A node instance based on the specified definition.\n */\nfunction nodeFactory(definition: AnyNodeDefinition, rootNodeDefinitionMap: RootNodeDefinitionMap): AnyNode {\n // Get the attributes for the node.\n const attributes = nodeAttributesFactory(definition);\n\n // Create the node instance based on the definition type.\n switch (definition.type) {\n case \"root\":\n return new Root(attributes, nodeFactory(definition.child, rootNodeDefinitionMap));\n\n case \"repeat\":\n let iterations: number | null = null;\n let iterationsMin: number | null = null;\n let iterationsMax: number | null = null;\n\n if (Array.isArray(definition.iterations)) {\n iterationsMin = definition.iterations[0];\n iterationsMax = definition.iterations[1];\n } else if (isInteger(definition.iterations)) {\n iterations = definition.iterations!;\n }\n\n return new Repeat(\n attributes,\n iterations,\n iterationsMin,\n iterationsMax,\n nodeFactory(definition.child, rootNodeDefinitionMap)\n );\n\n case \"retry\":\n let attempts: number | null = null;\n let attemptsMin: number | null = null;\n let attemptsMax: number | null = null;\n\n if (Array.isArray(definition.attempts)) {\n attemptsMin = definition.attempts[0];\n attemptsMax = definition.attempts[1];\n } else if (isInteger(definition.attempts)) {\n attempts = definition.attempts!;\n }\n\n return new Retry(\n attributes,\n attempts,\n attemptsMin,\n attemptsMax,\n nodeFactory(definition.child, rootNodeDefinitionMap)\n );\n\n case \"flip\":\n return new Flip(attributes, nodeFactory(definition.child, rootNodeDefinitionMap));\n\n case \"succeed\":\n return new Succeed(attributes, nodeFactory(definition.child, rootNodeDefinitionMap));\n\n case \"fail\":\n return new Fail(attributes, nodeFactory(definition.child, rootNodeDefinitionMap));\n\n case \"sequence\":\n return new Sequence(\n attributes,\n definition.children.map((child) => nodeFactory(child, rootNodeDefinitionMap))\n );\n\n case \"selector\":\n return new Selector(\n attributes,\n definition.children.map((child) => nodeFactory(child, rootNodeDefinitionMap))\n );\n\n case \"parallel\":\n return new Parallel(\n attributes,\n definition.children.map((child) => nodeFactory(child, rootNodeDefinitionMap))\n );\n\n case \"lotto\":\n return new Lotto(\n attributes,\n definition.weights,\n definition.children.map((child) => nodeFactory(child, rootNodeDefinitionMap))\n );\n\n case \"branch\":\n return nodeFactory(rootNodeDefinitionMap[definition.ref].child, rootNodeDefinitionMap);\n\n case \"action\":\n return new Action(attributes, definition.call, definition.args || []);\n\n case \"condition\":\n return new Condition(attributes, definition.call, definition.args || []);\n\n case \"wait\":\n let duration: number | null = null;\n let durationMin: number | null = null;\n let durationMax: number | null = null;\n\n if (Array.isArray(definition.duration)) {\n durationMin = definition.duration[0];\n durationMax = definition.duration[1];\n } else if (isInteger(definition.duration)) {\n duration = definition.duration!;\n }\n\n return new Wait(attributes, duration, durationMin, durationMax);\n }\n}\n\n/**\n * Creates an array of node attribute instances based on the specified node definition.\n * @param definition The node definition.\n * @returns An array of node attribute instances based on the specified node definition.\n */\nfunction nodeAttributesFactory(definition: AnyNodeDefinition): Attribute[] {\n const attributes: Attribute[] = [];\n\n if (definition.while) {\n attributes.push(new While(definition.while.call, definition.while.args ?? []));\n }\n\n if (definition.until) {\n attributes.push(new Until(definition.until.call, definition.until.args ?? []));\n }\n\n if (definition.entry) {\n attributes.push(new Entry(definition.entry.call, definition.entry.args ?? []));\n }\n\n if (definition.step) {\n attributes.push(new Step(definition.step.call, definition.step.args ?? []));\n }\n\n if (definition.exit) {\n attributes.push(new Exit(definition.exit.call, definition.exit.args ?? []));\n }\n\n return attributes;\n}\n\n/**\n * Creates a mapping of root node identifers to root node definitions, mixing in globally registered subtree root node definitions.\n * @param definition The root node definitions.\n * @returns A mapping of root node identifers to root node definitions, including globally registered subtree root node definitions.\n */\nfunction createRootNodeDefinitionMap(definition: RootNodeDefinition[]): RootNodeDefinitionMap {\n // Create a mapping of root node identifers to root node definitions.\n const rootNodeMap: RootNodeDefinitionMap = {};\n\n // Add in any registered subtree root node definitions.\n for (const [name, rootNodeDefinition] of Object.entries(Lookup.getSubtrees())) {\n // The name used when registering the subtree will be used as the root node identifier.\n rootNodeMap[name] = { ...rootNodeDefinition, id: name };\n }\n\n // Populate the map with the root node definitions that were included with the tree definition.\n // We do this after adding any registered subtrees as we want these to take presedence.\n for (const rootNodeDefinition of definition) {\n rootNodeMap[rootNodeDefinition.id ?? MAIN_ROOT_NODE_KEY] = rootNodeDefinition;\n }\n\n return rootNodeMap;\n}\n\n/**\n * Applies a guard path to every leaf of the tree to evaluate as part of each update.\n * @param root The main root tree node.\n */\nfunction applyLeafNodeGuardPaths(root: Root) {\n const nodePaths: Node[][] = [];\n\n const findLeafNodes = (path: Node[], node: Node) => {\n // Add the current node to the path.\n path = path.concat(node);\n\n // Check whether the current node is a leaf node.\n if (node.isLeafNode()) {\n nodePaths.push(path);\n } else {\n (node as Composite | Decorator).getChildren().forEach((child) => findLeafNodes(path, child));\n }\n };\n\n // Find all leaf node paths, starting from the root.\n findLeafNodes([], root);\n\n nodePaths.forEach((path) => {\n // Each node in the current path will have to be assigned a guard path, working from the root outwards.\n for (let depth = 0; depth < path.length; depth++) {\n // Get the node in the path at the current depth.\n const currentNode = path[depth];\n\n // The node may already have been assigned a guard path, if so just skip it.\n if (currentNode.hasGuardPath()) {\n continue;\n }\n\n // Create the guard path for the current node.\n const guardPath = new GuardPath(\n path\n .slice(0, depth + 1)\n .map((node) => ({ node, guards: node.getGuardAttributes() }))\n .filter((details) => details.guards.length > 0)\n );\n\n // Assign the guard path to the current node.\n currentNode.setGuardPath(guardPath);\n }\n });\n}\n", "import State, { AnyState } from \"./State\";\nimport Lookup from \"./Lookup\";\nimport Node from \"./nodes/Node\";\nimport Root from \"./nodes/decorator/Root\";\nimport Composite from \"./nodes/composite/Composite\";\nimport Decorator from \"./nodes/decorator/Decorator\";\nimport { Agent, GlobalFunction } from \"./Agent\";\nimport { CallbackAttributeDetails } from \"./attributes/callbacks/Callback\";\nimport { GuardAttributeDetails } from \"./attributes/guards/Guard\";\nimport { BehaviourTreeOptions } from \"./BehaviourTreeOptions\";\nimport { convertMDSLToJSON } from \"./mdsl/MDSLDefinitionParser\";\nimport { RootNodeDefinition } from \"./BehaviourTreeDefinition\";\nimport { validateDefinition, validateJSONDefinition } from \"./BehaviourTreeDefinitionValidator\";\nimport buildRootNode from \"./BehaviourTreeBuilder\";\nimport { isNullOrUndefined } from \"./BehaviourTreeDefinitionUtilities\";\n\n// Purely for outside inspection of the tree.\nexport type FlattenedTreeNode = {\n id: string;\n type: string;\n caption: string;\n state: AnyState;\n guards: GuardAttributeDetails[];\n callbacks: CallbackAttributeDetails[];\n args: any[];\n parentId: string | null;\n};\n\n/**\n * A representation of a behaviour tree.\n */\nexport class BehaviourTree {\n /**\n * The main root tree node.\n */\n private readonly _rootNode: Root;\n\n /**\n * Creates a new instance of the BehaviourTree class.\n * @param definition The behaviour tree definition as either an MDSL string, root node definition object or array of root node definition objects.\n * @param agent The agent instance that this behaviour tree is modelling behaviour for.\n * @param options The behaviour tree options object.\n */\n constructor(\n definition: string | RootNodeDefinition | RootNodeDefinition[],\n private agent: Agent,\n private options: BehaviourTreeOptions = {}\n ) {\n // The tree definition must be defined.\n if (isNullOrUndefined(definition)) {\n throw new Error(\"tree definition not defined\");\n }\n\n // The agent must be defined and not null.\n if (typeof agent !== \"object\" || agent === null) {\n throw new Error(\"the agent must be an object and not null\");\n }\n\n // We should validate the definition before we try to build the tree nodes.\n const { succeeded, errorMessage, json } = validateDefinition(definition);\n\n // Did our validation fail without error?\n if (!succeeded) {\n throw new Error(`invalid definition: ${errorMessage}`);\n }\n\n // Double check that we did actually get our json definition as part of our definition validtion.\n if (!json) {\n throw new Error(\n \"expected json definition to be returned as part of successful definition validation response\"\n );\n }\n\n try {\n // Create the populated tree of behaviour tree nodes and get the root node.\n this._rootNode = buildRootNode(json);\n } catch (exception) {\n // There was an issue in trying build and populate the behaviour tree.\n throw new Error(`error building tree: ${(exception as Error).message}`);\n }\n }\n\n /**\n * Gets whether the tree is in the RUNNING state.\n * @returns true if the tree is in the RUNNING state, otherwise false.\n */\n isRunning() {\n return this._rootNode.getState() === State.RUNNING;\n }\n\n /**\n * Gets the current tree state of SUCCEEDED, FAILED, READY or RUNNING.\n * @returns The current tree state.\n */\n getState() {\n return this._rootNode.getState();\n }\n\n /**\n * Step the tree.\n * 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.\n * 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\n * 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.\n *\n * 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.\n */\n step() {\n // If the root node has already been stepped to completion then we need to reset it.\n if (this._rootNode.getState() === State.SUCCEEDED || this._rootNode.getState() === State.FAILED) {\n this._rootNode.reset();\n }\n\n try {\n this._rootNode.update(this.agent, this.options);\n } catch (exception) {\n throw new Error(`error stepping tree: ${(exception as Error).message}`);\n }\n }\n\n /**\n * Resets the tree from the root node outwards to each nested node, giving each a state of READY.\n */\n reset() {\n this._rootNode.reset();\n }\n\n /**\n * Gets the flattened details of every node in the tree.\n * @returns The flattened details of every node in the tree.\n */\n getFlattenedNodeDetails(): FlattenedTreeNode[] {\n // Create an empty flattened array of tree nodes.\n const flattenedTreeNodes: FlattenedTreeNode[] = [];\n\n /**\n * Helper function to process a node instance and push details into the flattened tree nodes array.\n * @param node The current node.\n * @param parentUid The UID of the node parent, or null if the node is the main root node.\n */\n const processNode = (node: Node, parentUid: string | null) => {\n // Get the guard and callback attribute details for this node.\n const guards = node\n .getAttributes()\n .filter((attribute) => attribute.isGuard())\n .map((attribute) => attribute.getDetails()) as GuardAttributeDetails[];\n const callbacks = node\n .getAttributes()\n .filter((attribute) => !attribute.isGuard())\n .map((attribute) => attribute.getDetails()) as CallbackAttributeDetails[];\n\n // Push the current node into the flattened nodes array.\n flattenedTreeNodes.push({\n id: node.getUid(),\n type: node.getType(),\n caption: node.getName(),\n state: node.getState(),\n guards,\n callbacks,\n args: node.getArguments(),\n parentId: parentUid\n });\n\n // Process each of the nodes children if it is not a leaf node.\n if (!node.isLeafNode()) {\n (node as Composite | Decorator)\n .getChildren()\n .forEach((child) => processNode(child, (node as Composite | Decorator).getUid()));\n }\n };\n\n // Convert the nested node structure into a flattened array of node details.\n processNode(this._rootNode, null);\n\n return flattenedTreeNodes;\n }\n\n /**\n * Registers the action/condition/guard/callback function or subtree with the given name.\n * @param name The name of the function or subtree to register.\n * @param value The function or subtree definition to register.\n */\n static register(name: string, value: GlobalFunction | string | RootNodeDefinition) {\n // Are we going to register a action/condition/guard/callback function?\n if (typeof value === \"function\") {\n Lookup.setFunc(name, value);\n return;\n }\n\n // We are not registering an action/condition/guard/callback function, so we must be registering a subtree.\n if (typeof value === \"string\") {\n let rootNodeDefinitions: RootNodeDefinition[];\n\n // We will assume that any string passed in will be a mdsl definition.\n try {\n rootNodeDefinitions = convertMDSLToJSON(value);\n } catch (exception) {\n throw new Error(`error registering definition, invalid MDSL: ${(exception as Error).message}`);\n }\n\n // This function should only ever be called with a definition containing a single unnamed root node.\n if (rootNodeDefinitions.length != 1 || rootNodeDefinitions[0].id !== null) {\n throw new Error(\"error registering definition: expected a single unnamed root node\");\n }\n\n try {\n // We should validate the subtree as we don't want invalid subtrees available via the lookup.\n const { succeeded, errorMessage } = validateJSONDefinition(rootNodeDefinitions[0]);\n\n // Did our validation fail without error?\n if (!succeeded) {\n throw new Error(errorMessage);\n }\n } catch (exception) {\n throw new Error(`error registering definition: ${(exception as Error).message}`);\n }\n\n // Everything seems hunky-dory, register the subtree.\n Lookup.setSubtree(name, rootNodeDefinitions[0]);\n } else if (typeof value === \"object\" && !Array.isArray(value)) {\n // We will assume that any object passed in is a root node definition.\n\n try {\n // We should validate the subtree as we don't want invalid subtrees available via the lookup.\n const { succeeded, errorMessage } = validateJSONDefinition(value);\n\n // Did our validation fail without error?\n if (!succeeded) {\n throw new Error(errorMessage);\n }\n } catch (exception) {\n throw new Error(`error registering definition: ${(exception as Error).message}`);\n }\n\n // Everything seems hunky-dory, register the subtree.\n Lookup.setSubtree(name, value);\n } else {\n throw new Error(\"unexpected value, expected string mdsl definition, root node json definition or function\");\n }\n }\n\n /**\n * Unregisters the registered action/condition/guard/callback function or subtree with the given name.\n * @param name The name of the registered action/condition/guard/callback function or subtree to unregister.\n */\n static unregister(name: string): void {\n Lookup.remove(name);\n }\n\n /**\n * Unregister all registered action/condition/guard/callback functions and subtrees.\n */\n static unregisterAll(): void {\n Lookup.empty();\n }\n}\n"], + "mappings": "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", "names": ["Participant", "isNullOrUndefined", "Lotto", "createLotto", "State", "createLotto"] } diff --git a/dist/index.js b/dist/index.js index 8d3b7be..80a508d 100644 --- a/dist/index.js +++ b/dist/index.js @@ -2041,7 +2041,7 @@ var Exit = class extends Callback { `cannot call exit function '${this.getFunctionName()}' as is not defined on the agent and has not been registered` ); } - callbackFuncInvoker([{ value: { succeeded: isSuccess, aborted: isAborted } }, ...this.args]); + callbackFuncInvoker([{ succeeded: isSuccess, aborted: isAborted }, ...this.args]); }; }; diff --git a/dist/index.js.map b/dist/index.js.map index 548a5ac..c80981e 100644 --- a/dist/index.js.map +++ b/dist/index.js.map @@ -1,7 +1,7 @@ { "version": 3, "sources": ["../node_modules/lotto-draw/dist/Participant.js", "../node_modules/lotto-draw/dist/Utilities.js", "../node_modules/lotto-draw/dist/Lotto.js", "../node_modules/lotto-draw/dist/createLotto.js", "../node_modules/lotto-draw/dist/index.js", "../src/index.ts", "../src/State.ts", "../src/BehaviourTreeDefinitionUtilities.ts", "../src/mdsl/MDSLUtilities.ts", "../src/mdsl/MDSLNodeArgumentParser.ts", "../src/mdsl/MDSLNodeAttributeParser.ts", "../src/mdsl/MDSLDefinitionParser.ts", "../src/BehaviourTreeDefinitionValidator.ts", "../src/Lookup.ts", "../src/attributes/guards/GuardUnsatisifedException.ts", "../src/attributes/guards/GuardPath.ts", "../src/nodes/Node.ts", "../src/nodes/composite/Composite.ts", "../src/nodes/composite/Parallel.ts", "../src/nodes/composite/Selector.ts", "../src/nodes/composite/Sequence.ts", "../src/nodes/composite/Lotto.ts", "../src/nodes/decorator/Decorator.ts", "../src/nodes/decorator/Fail.ts", "../src/nodes/decorator/Flip.ts", "../src/nodes/decorator/Repeat.ts", "../src/nodes/decorator/Retry.ts", "../src/nodes/decorator/Root.ts", "../src/nodes/decorator/Succeed.ts", "../src/nodes/leaf/Leaf.ts", "../src/nodes/leaf/Action.ts", "../src/nodes/leaf/Condition.ts", "../src/nodes/leaf/Wait.ts", "../src/attributes/Attribute.ts", "../src/attributes/guards/Guard.ts", "../src/attributes/guards/While.ts", "../src/attributes/guards/Until.ts", "../src/attributes/callbacks/Callback.ts", "../src/attributes/callbacks/Entry.ts", "../src/attributes/callbacks/Step.ts", "../src/attributes/callbacks/Exit.ts", "../src/BehaviourTreeBuilder.ts", "../src/BehaviourTree.ts"], - "sourcesContent": ["\"use strict\";\r\nObject.defineProperty(exports, \"__esModule\", { value: true });\r\nexports.Participant = void 0;\r\n/**\r\n * A participant that holds a number of tickets.\r\n */\r\nvar Participant = /** @class */ (function () {\r\n /**\r\n * Creates an instance of the Participant class.\r\n * @param participant The actual participant.\r\n * @param tickets The number of tickets held by the participant.\r\n */\r\n function Participant(participant, tickets) {\r\n if (tickets === void 0) { tickets = 1; }\r\n this._participant = participant;\r\n this._tickets = tickets;\r\n }\r\n Object.defineProperty(Participant.prototype, \"participant\", {\r\n /** Gets the actual participant. */\r\n get: function () {\r\n return this._participant;\r\n },\r\n enumerable: false,\r\n configurable: true\r\n });\r\n Object.defineProperty(Participant.prototype, \"tickets\", {\r\n /** Gets or sets the number of tickets held by the participant. */\r\n get: function () {\r\n return this._tickets;\r\n },\r\n set: function (value) {\r\n this._tickets = value;\r\n },\r\n enumerable: false,\r\n configurable: true\r\n });\r\n return Participant;\r\n}());\r\nexports.Participant = Participant;\r\n", "\"use strict\";\r\nObject.defineProperty(exports, \"__esModule\", { value: true });\r\nexports.isNaturalNumber = exports.isNullOrUndefined = void 0;\r\n/**\r\n * Gets whether the value provided is null or undefined.\r\n * @param value The value to check.\r\n * @returns Whether the value provided is null or undefined.\r\n */\r\nfunction isNullOrUndefined(value) {\r\n return value === null || value === undefined;\r\n}\r\nexports.isNullOrUndefined = isNullOrUndefined;\r\n/**\r\n * Gets whether the value provided is a natural number.\r\n * @param value The value to check.\r\n * @returns Whether the value provided is a natural number.\r\n */\r\nfunction isNaturalNumber(value) {\r\n return typeof value === \"number\" && value >= 1 && Math.floor(value) === value;\r\n}\r\nexports.isNaturalNumber = isNaturalNumber;\r\n", "\"use strict\";\r\nObject.defineProperty(exports, \"__esModule\", { value: true });\r\nexports.Lotto = void 0;\r\nvar Participant_1 = require(\"./Participant\");\r\nvar Utilities_1 = require(\"./Utilities\");\r\n/**\r\n * Represents a lotto consisting of a number of pickable ticket-holding participants.\r\n */\r\nvar Lotto = /** @class */ (function () {\r\n /**\r\n * Creates a new instance of Lotto.\r\n * @param customRandom The custom RNG to use in place of Math.random().\r\n */\r\n function Lotto(customRandom) {\r\n /** The array of participants that are holding tickets in the lotto. */\r\n this._participants = [];\r\n this._customRandom = customRandom;\r\n }\r\n /**\r\n * Adds a participant with the specified number of tickets, or adds to the participant ticket count if the participant already holds tickets.\r\n * @param participant The participant to add or to increase the ticket count for if they already hold tickets.\r\n * @param tickets The number of tickets, defaults to 1.\r\n * @returns The Lotto instance.\r\n */\r\n Lotto.prototype.add = function (participant, tickets) {\r\n if (tickets === void 0) { tickets = 1; }\r\n // Check that we have a valid ticket count.\r\n if (!(0, Utilities_1.isNaturalNumber)(tickets)) {\r\n throw new Error(\"tickets value must be a natural number\");\r\n }\r\n // Check whether this participant has already been added.\r\n var existingParticipant = this._participants.find(function (part) { return part.participant === participant; });\r\n if (existingParticipant) {\r\n // The participant has already been added to the lotto so just add to their ticket count.\r\n existingParticipant.tickets += tickets;\r\n }\r\n else {\r\n // The participant is not part of the lotto so we should add them.\r\n this._participants.push(new Participant_1.Participant(participant, tickets));\r\n }\r\n return this;\r\n };\r\n /**\r\n * Removes the specified number of tickets for the given participant from the draw, or all tickets if a ticket number is not defined.\r\n * @param participant The participant to remove tickets for.\r\n * @param tickets The number of tickets to remove, or undefined if all tickets are to be removed.\r\n * @returns The Lotto instance.\r\n */\r\n Lotto.prototype.remove = function (participant, tickets) {\r\n // Attempt to get the existing participant.\r\n var existingParticipant = this._participants.find(function (part) { return part.participant === participant; });\r\n // There is nothing to do if the specified participant isn't even part of the lotto.\r\n if (!existingParticipant) {\r\n return this;\r\n }\r\n // Check whether a tickets value was given.\r\n if (tickets !== undefined) {\r\n // Check that we have a valid ticket count.\r\n if (!(0, Utilities_1.isNaturalNumber)(tickets)) {\r\n throw new Error(\"tickets value must be a natural number\");\r\n }\r\n existingParticipant.tickets -= tickets;\r\n // If the participant no longer holds any tickets then they should be removed.\r\n if (existingParticipant.tickets < 1) {\r\n this._participants = this._participants.filter(function (part) { return part !== existingParticipant; });\r\n }\r\n }\r\n else {\r\n // We are removing all tickets for the participant so just remove them from the lotto.\r\n this._participants = this._participants.filter(function (part) { return part !== existingParticipant; });\r\n }\r\n return this;\r\n };\r\n /**\r\n * Draw a winning ticket and return the participant that holds the ticket.\r\n * @param options The draw options.\r\n * @returns The participant that holds the winning ticket.\r\n */\r\n Lotto.prototype.draw = function (options) {\r\n if (options === void 0) { options = {}; }\r\n // If we have no participants then just return null.\r\n if (this._participants.length === 0) {\r\n return null;\r\n }\r\n var redrawable = (0, Utilities_1.isNullOrUndefined)(options.redrawable) ? true : options.redrawable;\r\n var pickable = [];\r\n this._participants.forEach(function (_a) {\r\n var participant = _a.participant, tickets = _a.tickets;\r\n for (var ticketCount = 0; ticketCount < tickets; ticketCount++) {\r\n pickable.push(participant);\r\n }\r\n });\r\n var random;\r\n // We need a random floating-point number between 0 (inclusive) and 1 to scale up to pick our winner.\r\n // If a custom random function exists then we should use that or fall back to Math.random().\r\n if (this._customRandom) {\r\n // Call our custom random function to get a random floating-point number.\r\n random = this._customRandom();\r\n // Verify that the result of calling our custom random function is a number between 0 (inclusive) and 1.\r\n if (typeof random !== \"number\" || random < 0 || random >= 1) {\r\n throw new Error(\"the 'random' function provided did not return a number between 0 (inclusive) and 1\");\r\n }\r\n }\r\n else {\r\n // No custom random function was defined so just use good ol' Math.random().\r\n random = Math.random();\r\n }\r\n // Pick a winning participant.\r\n var winner = pickable[Math.floor(random * pickable.length)];\r\n // If the ticket isn't redrawable then we should remove a ticket from the winning participants ticket count.\r\n if (!redrawable) {\r\n this.remove(winner, 1);\r\n }\r\n // Return the winning participant.\r\n return winner;\r\n };\r\n /**\r\n * Draws multiple winning tickets and return an array of the participants that hold the winning tickets.\r\n * @param tickets The number of winning tickets to draw.\r\n * @param options The draw multiple options.\r\n * @returns An array of the participants that hold the winning tickets.\r\n */\r\n Lotto.prototype.drawMultiple = function (tickets, options) {\r\n if (options === void 0) { options = {}; }\r\n var uniqueResults = (0, Utilities_1.isNullOrUndefined)(options.unique) ? false : options.unique;\r\n // Handle cases where the user has asked for zero tickets (no idea why they would do this be we should trust them).\r\n if (tickets === 0) {\r\n return [];\r\n }\r\n // Now that we know out tickets value is not zero we should check that it is a valid natural number.\r\n if (!(0, Utilities_1.isNaturalNumber)(tickets)) {\r\n throw new Error(\"tickets value must be a natural number\");\r\n }\r\n var result = [];\r\n // Keep drawing tickets until we either reach the number of required tickets or we simply run out of tickets to draw.\r\n // We can run out of tickets to draw if 'options.redrawable' is explicity 'false' or we just had no participants when 'drawMultiple' was called.\r\n while (result.length < tickets && this._participants.length > 0) {\r\n result.push(this.draw(options));\r\n }\r\n // If the 'unique' draw option is set then we need to remove duplicates from the result list.\r\n if (uniqueResults) {\r\n // Create an array to store our unique results.\r\n var unique = [];\r\n // Iterate over all of our participants (with potential duplicates) and populate our array of unique values.\r\n for (var _i = 0, result_1 = result; _i < result_1.length; _i++) {\r\n var participant = result_1[_i];\r\n if (unique.indexOf(participant) === -1) {\r\n unique.push(participant);\r\n }\r\n }\r\n result = unique;\r\n }\r\n return result;\r\n };\r\n return Lotto;\r\n}());\r\nexports.Lotto = Lotto;\r\n", "\"use strict\";\r\nObject.defineProperty(exports, \"__esModule\", { value: true });\r\nexports.createLotto = void 0;\r\nvar Lotto_1 = require(\"./Lotto\");\r\n/**\r\n * A function that creates and returns a Lotto instance.\r\n * @param participantsOrOptions An array of initial participants or options relating to the creation of a Lotto instance.\r\n * @returns A new Lotto instance.\r\n */\r\nfunction createLotto(participantsOrOptions) {\r\n // If no initial participants or lotto options were provided as an argument then we can just return a new lotto instance now.\r\n if (!participantsOrOptions) {\r\n return new Lotto_1.Lotto();\r\n }\r\n // Check whether we were provided with an array of initial participants or a lotto options object.\r\n if (Array.isArray(participantsOrOptions)) {\r\n // We are dealing with a pre-defined array of participants.\r\n var participants = participantsOrOptions;\r\n var lotto_1 = new Lotto_1.Lotto();\r\n // If the lotto participants have been defined upfront then we will need to add them all to our lotto instance now.\r\n participants.forEach(function (_a) {\r\n var participant = _a[0], tokens = _a[1];\r\n return lotto_1.add(participant, tokens);\r\n });\r\n // Return the Lotto instance.\r\n return lotto_1;\r\n }\r\n else {\r\n // We are dealing with some lotto options.\r\n var random = participantsOrOptions.random, participants = participantsOrOptions.participants;\r\n // Create a Lotto instance passing the custom RNG function to use in place of Math.random() (which could be undefined).\r\n var lotto_2 = new Lotto_1.Lotto(random);\r\n // If the lotto participants have been defined upfront as part of the options then we will need to add them all to our lotto instance now.\r\n if (participants) {\r\n participants.forEach(function (_a) {\r\n var participant = _a[0], tokens = _a[1];\r\n return lotto_2.add(participant, tokens);\r\n });\r\n }\r\n // Return the Lotto instance.\r\n return lotto_2;\r\n }\r\n}\r\nexports.createLotto = createLotto;\r\n", "\"use strict\";\r\nObject.defineProperty(exports, \"__esModule\", { value: true });\r\nvar createLotto_1 = require(\"./createLotto\");\r\nexports.default = createLotto_1.createLotto;\r\n", "import State from \"./State\";\nimport { validateDefinition } from \"./BehaviourTreeDefinitionValidator\";\nimport { convertMDSLToJSON } from \"./mdsl/MDSLDefinitionParser\";\nimport { BehaviourTree, FlattenedTreeNode } from \"./BehaviourTree\";\nimport { BehaviourTreeOptions } from \"./BehaviourTreeOptions\";\n\nexport { BehaviourTree, State, convertMDSLToJSON, validateDefinition };\nexport type { FlattenedTreeNode, BehaviourTreeOptions };\n", "/**\n * Enumeration of node state types.\n */\nexport enum State {\n READY = \"mistreevous.ready\",\n RUNNING = \"mistreevous.running\",\n SUCCEEDED = \"mistreevous.succeeded\",\n FAILED = \"mistreevous.failed\"\n}\n\nexport { State as default };\n\nexport type CompleteState = State.SUCCEEDED | State.FAILED;\nexport type AnyState = State.READY | State.RUNNING | CompleteState;\n", "import {\n NodeDefinition,\n RootNodeDefinition,\n DecoratorNodeDefinition,\n CompositeNodeDefinition,\n AnyNodeDefinition,\n BranchNodeDefinition\n} from \"./BehaviourTreeDefinition\";\n\n/**\n * A type guard function that returns true if the specified node satisfies the RootNodeDefinition type.\n * @param node The node.\n * @returns A value of true if the specified node satisfies the RootNodeDefinition type.\n */\nexport function isRootNode(node: NodeDefinition): node is RootNodeDefinition {\n return node.type === \"root\";\n}\n\n/**\n * A type guard function that returns true if the specified node satisfies the BranchNodeDefinition type.\n * @param node The node.\n * @returns A value of true if the specified node satisfies the BranchNodeDefinition type.\n */\nexport function isBranchNode(node: NodeDefinition): node is BranchNodeDefinition {\n return node.type === \"branch\";\n}\n\n/**\n * A type guard function that returns true if the specified node satisfies the NodeDefinition type.\n * @param node The node.\n * @returns A value of true if the specified node satisfies the NodeDefinition type.\n */\nexport function isLeafNode(node: NodeDefinition): node is NodeDefinition {\n return [\"branch\", \"action\", \"condition\", \"wait\"].includes(node.type);\n}\n\n/**\n * A type guard function that returns true if the specified node satisfies the DecoratorNodeDefinition type.\n * @param node The node.\n * @returns A value of true if the specified node satisfies the DecoratorNodeDefinition type.\n */\nexport function isDecoratorNode(node: NodeDefinition): node is DecoratorNodeDefinition {\n return [\"root\", \"repeat\", \"retry\", \"flip\", \"succeed\", \"fail\"].includes(node.type);\n}\n\n/**\n * A type guard function that returns true if the specified node satisfies the CompositeNodeDefinition type.\n * @param node The node.\n * @returns A value of true if the specified node satisfies the CompositeNodeDefinition type.\n */\nexport function isCompositeNode(node: NodeDefinition): node is CompositeNodeDefinition {\n return [\"sequence\", \"selector\", \"lotto\", \"parallel\"].includes(node.type);\n}\n\n/**\n * Flatten a node definition into an array of all of its nested node definitions.\n * @param nodeDefinition The node definition to flatten.\n * @returns An array of all of nested node definitions.\n */\nexport function flattenDefinition(nodeDefinition: AnyNodeDefinition): AnyNodeDefinition[] {\n const nodes: AnyNodeDefinition[] = [];\n\n const processNode = (currentNodeDefinition: AnyNodeDefinition) => {\n nodes.push(currentNodeDefinition);\n\n if (isCompositeNode(currentNodeDefinition)) {\n currentNodeDefinition.children.forEach(processNode);\n } else if (isDecoratorNode(currentNodeDefinition)) {\n processNode(currentNodeDefinition.child);\n }\n };\n\n processNode(nodeDefinition);\n\n return nodes;\n}\n\n/**\n * Determines whether the passed value is an integer.\n * @param value The value to check.\n * @returns Whether the passed value is an integer.\n */\nexport function isInteger(value: unknown): boolean {\n return typeof value === \"number\" && Math.floor(value) === value;\n}\n\n/**\n * Determines whether the passed value is null or undefined.\n * @param value The value to check.\n * @returns Whether the passed value is null or undefined.\n */\nexport function isNullOrUndefined(value: unknown): boolean {\n return typeof value === \"undefined\" || value === null;\n}\n", "/**\n * A type defining an object that holds a reference to substitued string literals parsed from the definition.\n */\nexport type StringLiteralPlaceholders = { [key: string]: string };\n\n/**\n * Pop the next raw token from the specified array of tokens and throw an error if it wasn't the expected one.\n * @param tokens The array of tokens.\n * @param expected An optional string or array or items, one of which must match the next popped token.\n * @returns The popped token.\n */\nexport function popAndCheck(tokens: string[], expected?: string | string[]): string {\n // Get and remove the next token.\n const popped = tokens.shift();\n\n // We were expecting another token but there aren't any.\n if (popped === undefined) {\n throw new Error(\"unexpected end of definition\");\n }\n\n // Do we have an expected token/tokens array?\n if (expected != undefined) {\n // Get an array of expected values, if the popped token matches any then we are all good.\n const expectedValues = typeof expected === \"string\" ? [expected] : expected;\n\n // Check whether the popped token matches at least one of our expected items.\n var tokenMatchesExpectation = expectedValues.some((item) => popped.toUpperCase() === item.toUpperCase());\n\n // Throw an error if the popped token didn't match any of our expected items.\n if (!tokenMatchesExpectation) {\n const expectationString = expectedValues.map((item) => \"'\" + item + \"'\").join(\" or \");\n throw new Error(\"unexpected token found. Expected \" + expectationString + \" but got '\" + popped + \"'\");\n }\n }\n\n // Return the popped token.\n return popped;\n}\n\n/**\n * Swaps out any node/attribute argument string literals with placeholders.\n * @param definition The definition.\n * @returns An object containing a mapping of placeholders to original string values as well as the processed definition string.\n */\nexport function substituteStringLiterals(definition: string): {\n placeholders: StringLiteralPlaceholders;\n processedDefinition: string;\n} {\n // Create an object to hold the mapping of placeholders to original string values.\n const placeholders: StringLiteralPlaceholders = {};\n\n // Replace any string literals wrapped with double quotes in our definition with placeholders to be processed later.\n const processedDefinition = definition.replace(/\\\"(\\\\.|[^\"\\\\])*\\\"/g, (match) => {\n var strippedMatch = match.substring(1, match.length - 1);\n var placeholder = Object.keys(placeholders).find((key) => placeholders[key] === strippedMatch);\n\n // If we have no existing string literal match then create a new placeholder.\n if (!placeholder) {\n placeholder = `@@${Object.keys(placeholders).length}@@`;\n placeholders[placeholder] = strippedMatch;\n }\n\n return placeholder;\n });\n\n return { placeholders, processedDefinition };\n}\n\n/**\n * Parse the tree definition into an array of raw tokens.\n * @param definition The definition.\n * @returns An array of tokens parsed from the definition.\n */\nexport function parseTokensFromDefinition(definition: string): string[] {\n // Add some space around various important characters so that they can be plucked out easier as individual tokens.\n definition = definition.replace(/\\(/g, \" ( \");\n definition = definition.replace(/\\)/g, \" ) \");\n definition = definition.replace(/\\{/g, \" { \");\n definition = definition.replace(/\\}/g, \" } \");\n definition = definition.replace(/\\]/g, \" ] \");\n definition = definition.replace(/\\[/g, \" [ \");\n definition = definition.replace(/\\,/g, \" , \");\n\n // Split the definition into raw token form and return it.\n return definition.replace(/\\s+/g, \" \").trim().split(\" \");\n}\n", "import { StringLiteralPlaceholders, popAndCheck } from \"./MDSLUtilities\";\n\n/**\n * A type representing any node function argument.\n */\ntype Argument = {\n /**\n * The argument value.\n */\n value: T;\n /**\n * The argument type, used for validation.\n */\n type: string;\n};\n\ntype NullArgument = Argument & {\n type: \"null\";\n};\n\ntype BooleanArgument = Argument & {\n type: \"boolean\";\n};\n\ntype NumberArgument = Argument & {\n type: \"number\";\n /**\n * A flag defining whether the number argument value is a valid integer. (used for validation)\n */\n isInteger: boolean;\n};\n\ntype StringPlaceholderArgument = Argument & {\n type: \"string\";\n};\n\ntype IdentifierArgument = Argument & {\n type: \"identifier\";\n};\n\n/**\n * A type representing a reference to any node function argument.\n */\ntype AnyArgument = NullArgument | BooleanArgument | NumberArgument | StringPlaceholderArgument | IdentifierArgument;\n\n/**\n * Parse an array of argument definitions from the specified tokens array.\n * @param tokens The array tokens to parse the argument definitions from.\n * @param stringArgumentPlaceholders The mapping of string literal node argument placeholders to original values.\n * @param argumentValidator The argument validator function.\n * @param validationFailedMessage The exception message to throw if argument validation fails.\n * @returns An array of argument definitions parsed from the specified tokens array.\n */\nexport function parseArgumentTokens(\n tokens: string[],\n stringArgumentPlaceholders: StringLiteralPlaceholders\n): AnyArgument[] {\n const argumentList: AnyArgument[] = [];\n\n // If the next token is not a '[' or '(' then we have no arguments to parse.\n if (![\"[\", \"(\"].includes(tokens[0])) {\n return argumentList;\n }\n\n // Any lists of arguments will always be wrapped in '[]' for node arguments or '()' for attribute arguments.\n // We are looking for a '[' or '(' opener that wraps the argument tokens and the relevant closer.\n const closingToken = popAndCheck(tokens, [\"[\", \"(\"]) === \"[\" ? \"]\" : \")\";\n\n const argumentListTokens: string[] = [];\n\n // Grab all tokens between the '[' and ']' or '(' and ')'.\n while (tokens.length && tokens[0] !== closingToken) {\n // The next token is part of our arguments list.\n argumentListTokens.push(tokens.shift()!);\n }\n\n // Validate the order of the argument tokens. Each token must either be a ',' or a single argument that satisfies the validator.\n argumentListTokens.forEach((token, index) => {\n // Get whether this token should be an actual argument.\n const shouldBeArgumentToken = !(index & 1);\n\n // If the current token should be an actual argument then validate it, otherwise it should be a ',' token.\n if (shouldBeArgumentToken) {\n // Get the argument definition.\n const argumentDefinition = getArgumentDefinition(token, stringArgumentPlaceholders);\n\n // This is a valid argument!\n argumentList.push(argumentDefinition);\n } else {\n // The current token should be a ',' token.\n if (token !== \",\") {\n throw new Error(`invalid argument list, expected ',' or ']' but got '${token}'`);\n }\n }\n });\n\n // The arguments list should terminate with a ']' or ')' token, depending on the opener.\n popAndCheck(tokens, closingToken);\n\n // Return the arguments.\n return argumentList;\n}\n\n/**\n * Gets an argument value definition.\n * @param token The argument token.\n * @param stringArgumentPlaceholders The mapping of string literal node argument placeholders to original values.\n * @returns An argument value definition.\n */\nfunction getArgumentDefinition(token: string, stringArgumentPlaceholders: StringLiteralPlaceholders): AnyArgument {\n // Check whether the token represents a null value.\n if (token === \"null\") {\n return {\n value: null,\n type: \"null\"\n } as NullArgument;\n }\n\n // Check whether the token represents a boolean value.\n if (token === \"true\" || token === \"false\") {\n return {\n value: token === \"true\",\n type: \"boolean\"\n } as BooleanArgument;\n }\n\n // Check whether the token represents a number value.\n // TODO: Relies on broken isNaN - see MDN.\n // if (!Number.isNaN(token)) {\n if (!isNaN(token as any)) {\n return {\n value: parseFloat(token),\n isInteger: parseFloat(token) === parseInt(token, 10),\n type: \"number\"\n } as NumberArgument;\n }\n\n // Check whether the token is a placeholder (e.g. @@0@@) representing a string literal.\n if (token.match(/^@@\\d+@@$/g)) {\n return {\n value: stringArgumentPlaceholders[token].replace('\\\\\"', '\"'),\n type: \"string\"\n } as StringPlaceholderArgument;\n }\n\n // The only remaining option is that the argument value is an identifier.\n return {\n value: token,\n type: \"identifier\"\n } as IdentifierArgument;\n}\n", "import { NodeAttributeDefinition } from \"../BehaviourTreeDefinition\";\nimport { parseArgumentTokens } from \"./MDSLNodeArgumentParser\";\nimport { StringLiteralPlaceholders } from \"./MDSLUtilities\";\n\n/**\n * A type defining the attribute definitions of a node.\n */\ntype NodeAttributes = {\n while?: NodeAttributeDefinition;\n until?: NodeAttributeDefinition;\n entry?: NodeAttributeDefinition;\n exit?: NodeAttributeDefinition;\n step?: NodeAttributeDefinition;\n};\n\n/**\n * Parse any node attribute definitions from the specified tokens array.\n * @param tokens The array of remaining tokens.\n * @param stringArgumentPlaceholders The mapping of string literal node argument placeholders to original values.\n * @returns An object of attribute definitions defined by any directly following tokens.\n */\nexport function parseAttributeTokens(\n tokens: string[],\n stringArgumentPlaceholders: StringLiteralPlaceholders\n): NodeAttributes {\n const nodeAttributeNames: (keyof NodeAttributes)[] = [\"while\", \"until\", \"entry\", \"exit\", \"step\"];\n\n // Create an object to hold any attributes found.\n const attributes: NodeAttributes = {};\n\n // Try to get the name of the attribute for the next token.\n let nextAttributeName = tokens[0]?.toLowerCase() as keyof NodeAttributes;\n\n // Pull attribute tokens as well as their arguments off of the tokens stack until we have no more.\n while (nodeAttributeNames.includes(nextAttributeName)) {\n // Check to make sure that we have not already created an attribute definition of this type.\n if (attributes[nextAttributeName]) {\n throw new Error(`duplicate attribute '${tokens[0].toUpperCase()}' found for node`);\n }\n\n // Remove the attribute name token from the array of tokens.\n tokens.shift();\n\n // Grab the attribute arguments, assuming the first to be an identifier.\n const [attributeCallIdentifier, ...attributeArguments] = parseArgumentTokens(\n tokens,\n stringArgumentPlaceholders\n );\n\n // The first attribute argument has to be an identifer, this will reference an agent function.\n if (attributeCallIdentifier?.type !== \"identifier\") {\n throw new Error(\"expected agent function or registered function name identifier argument for attribute\");\n }\n\n // Any attribute arguments (other than the expected call identifier) must have a type of string, number, boolean or null.\n attributeArguments\n .filter((arg) => arg.type === \"identifier\")\n .forEach((arg) => {\n throw new Error(\n `invalid attribute argument value '${arg.value}', must be string, number, boolean or null`\n );\n });\n\n // Create the attribute definition and add it to the object of attribute definitions found.\n attributes[nextAttributeName] = {\n call: attributeCallIdentifier.value,\n args: attributeArguments.map(({ value }) => value)\n };\n\n // Try to get the next attribute name token, as there could be multiple.\n nextAttributeName = tokens[0]?.toLowerCase() as keyof NodeAttributes;\n }\n\n return attributes;\n}\n", "import {\n ActionNodeDefinition,\n AnyChildNodeDefinition,\n AnyNodeDefinition,\n BranchNodeDefinition,\n ConditionNodeDefinition,\n FailNodeDefinition,\n FlipNodeDefinition,\n LottoNodeDefinition,\n ParallelNodeDefinition,\n RepeatNodeDefinition,\n RetryNodeDefinition,\n RootNodeDefinition,\n SelectorNodeDefinition,\n SequenceNodeDefinition,\n SucceedNodeDefinition,\n WaitNodeDefinition\n} from \"../BehaviourTreeDefinition\";\nimport {\n isCompositeNode,\n isDecoratorNode,\n isLeafNode,\n isNullOrUndefined,\n isRootNode\n} from \"../BehaviourTreeDefinitionUtilities\";\nimport { parseArgumentTokens } from \"./MDSLNodeArgumentParser\";\nimport { parseAttributeTokens } from \"./MDSLNodeAttributeParser\";\nimport {\n StringLiteralPlaceholders,\n parseTokensFromDefinition,\n popAndCheck,\n substituteStringLiterals\n} from \"./MDSLUtilities\";\n\n/**\n * Convert the MDSL tree definition string into an equivalent JSON definition.\n * @param definition The tree definition string as MDSL.\n * @returns The root node JSON definitions.\n */\nexport function convertMDSLToJSON(definition: string): RootNodeDefinition[] {\n // Swap out any node/attribute argument string literals with a placeholder and get a mapping of placeholders to original values as well as the processed definition.\n const { placeholders, processedDefinition } = substituteStringLiterals(definition);\n\n // Parse our definition definition string into an array of raw tokens.\n const tokens = parseTokensFromDefinition(processedDefinition);\n\n return convertTokensToJSONDefinition(tokens, placeholders);\n}\n\n/**\n * Converts the specified tree definition tokens into a JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The root node JSON definitions.\n */\nfunction convertTokensToJSONDefinition(\n tokens: string[],\n stringLiteralPlaceholders: StringLiteralPlaceholders\n): RootNodeDefinition[] {\n // There must be at least 3 tokens for the tree definition to be valid. 'ROOT', '{' and '}'.\n if (tokens.length < 3) {\n throw new Error(\"invalid token count\");\n }\n\n // We should have a matching number of '{' and '}' tokens. If not, then there are scopes that have not been properly closed.\n if (tokens.filter((token) => token === \"{\").length !== tokens.filter((token) => token === \"}\").length) {\n throw new Error(\"scope character mismatch\");\n }\n\n // Create an array of tree stack arrays where root nodes will always be at the botton and the current composite/decorator node at the top.\n // There should be an element in this array for every root node defined and every element should be an array with a root note as the first element.\n // E.g. A definition with two root nodes defined:\n // [\n // [root, lotto, sequence],\n // [root, selector]\n // ]\n const treeStacks: [Partial, ...Partial[]][] = [];\n\n // Create an array of all root node definitions that we create.\n const rootNodes: Partial[] = [];\n\n // A helper function used to push node definitions onto the tree stack.\n const pushNode = (node: AnyNodeDefinition) => {\n // If the node is a root node then we need to create a new tree stack array with the root node at the root.\n if (isRootNode(node)) {\n // We need to double-check that this root node is not the child of another node.\n // We can do this by checking whether the top tree stack is not empty (contains an existing node)\n if (treeStacks[treeStacks.length - 1]?.length) {\n throw new Error(\"a root node cannot be the child of another node\");\n }\n\n // Add the root node definition to our array of all parsed root node definitions.\n rootNodes.push(node);\n\n // Add the root node definition to the root of a new tree stack.\n treeStacks.push([node]);\n\n return;\n }\n\n // All non-root nodes should be pushed after their root nodes so handle cases\n // where we may not have any tree stacks or our top-most tree stack is empty.\n if (!treeStacks.length || !treeStacks[treeStacks.length - 1].length) {\n throw new Error(\"expected root node at base of definition\");\n }\n\n // Get the current tree stack that we are populating.\n const topTreeStack = treeStacks[treeStacks.length - 1];\n\n // Get the top-most node in the current tree stack, this will be a composite/decorator node\n // for which we will populate its children array if composite or setting its child if a decorator.\n const topTreeStackTopNode = topTreeStack[topTreeStack.length - 1] as AnyNodeDefinition;\n\n // If the top-most node in the current root stack is a composite or decorator\n // node then the current node should be added as a child of the top-most node.\n if (isCompositeNode(topTreeStackTopNode)) {\n topTreeStackTopNode.children = topTreeStackTopNode.children || [];\n topTreeStackTopNode.children.push(node);\n } else if (isDecoratorNode(topTreeStackTopNode)) {\n // If the top node already has a child node set then throw an error as a decorator should only have a single child.\n if (topTreeStackTopNode.child) {\n throw new Error(\"a decorator node must only have a single child node\");\n }\n\n topTreeStackTopNode.child = node;\n }\n\n // If the node we are adding is also a composite or decorator node, then we should push it\n // onto the current tree stack, as subsequent nodes will be added as its child/children.\n if (!isLeafNode(node)) {\n topTreeStack.push(node);\n }\n };\n\n // A helper function used to pop the top-most node definition off of the tree stack and return it.\n const popNode = (): AnyNodeDefinition | null => {\n let poppedNode: AnyNodeDefinition | null = null;\n\n // Get the current tree stack that we are populating.\n const topTreeStack = treeStacks[treeStacks.length - 1];\n\n // Pop the top-most node in the current tree stack if there is one.\n if (topTreeStack.length) {\n poppedNode = topTreeStack.pop() as AnyNodeDefinition;\n }\n\n // We don't want any empty tree stacks in our stack of tree stacks.\n if (!topTreeStack.length) {\n treeStacks.pop();\n }\n\n return poppedNode;\n };\n\n // We should keep processing the raw tokens until we run out of them.\n while (tokens.length) {\n // Grab the next token.\n const token = tokens.shift()!;\n\n // How we create the next node depends on the current raw token value.\n switch (token.toUpperCase()) {\n case \"ROOT\": {\n pushNode(createRootNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"SUCCEED\": {\n pushNode(createSucceedNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"FAIL\": {\n pushNode(createFailNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"FLIP\": {\n pushNode(createFlipNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"REPEAT\": {\n pushNode(createRepeatNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"RETRY\": {\n pushNode(createRetryNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"SEQUENCE\": {\n pushNode(createSequenceNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"SELECTOR\": {\n pushNode(createSelectorNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"PARALLEL\": {\n pushNode(createParallelNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"LOTTO\": {\n pushNode(createLottoNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"ACTION\": {\n pushNode(createActionNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"CONDITION\": {\n pushNode(createConditionNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"WAIT\": {\n pushNode(createWaitNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"BRANCH\": {\n pushNode(createBranchNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"}\": {\n // The '}' character closes the current scope and means that we have to pop a node off of the current stack.\n const poppedNode = popNode();\n\n // Now that we have a node definition we can carry out any validation that may require the node to be fully populated.\n if (poppedNode) {\n validatePoppedNode(poppedNode);\n }\n\n break;\n }\n\n default: {\n throw new Error(`unexpected token: ${token}`);\n }\n }\n }\n\n return rootNodes as RootNodeDefinition[];\n}\n\n/**\n * Creates a root node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The root node JSON definition.\n */\nfunction createRootNode(tokens: string[], stringLiteralPlaceholders: StringLiteralPlaceholders): RootNodeDefinition {\n // Create the root node definition.\n let node = {\n type: \"root\"\n } as Partial;\n\n // Parse any node arguments, we should only have one if any which will be an identifier argument for the root identifier.\n const nodeArguments = parseArgumentTokens(tokens, stringLiteralPlaceholders);\n\n // Check whether any node arguments were defined.\n if (nodeArguments.length) {\n // We should only have one argument, if any, which will be an identifier argument for the root identifier.\n if (nodeArguments.length === 1 && nodeArguments[0].type === \"identifier\") {\n // The root node identifier will be the first and only node argument value.\n node.id = nodeArguments[0].value as string;\n } else {\n throw new Error(\"expected single root name argument\");\n }\n }\n\n // Grab any node attribute definitions and spread them into the node definition.\n node = { ...node, ...parseAttributeTokens(tokens, stringLiteralPlaceholders) };\n\n // This is a decorator node, so we expect an opening '{'.\n popAndCheck(tokens, \"{\");\n\n // Return the root node definition.\n return node as RootNodeDefinition;\n}\n\n/**\n * Creates a succeed node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The succeed node JSON definition.\n */\nfunction createSucceedNode(\n tokens: string[],\n stringLiteralPlaceholders: StringLiteralPlaceholders\n): SucceedNodeDefinition {\n const node = {\n type: \"succeed\",\n ...parseAttributeTokens(tokens, stringLiteralPlaceholders)\n } as SucceedNodeDefinition;\n\n // This is a decorator node, so we expect an opening '{'.\n popAndCheck(tokens, \"{\");\n\n // Return the succeed node definition.\n return node;\n}\n\n/**\n * Creates a fail node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The fail node JSON definition.\n */\nfunction createFailNode(tokens: string[], stringLiteralPlaceholders: StringLiteralPlaceholders): FailNodeDefinition {\n const node = {\n type: \"fail\",\n ...parseAttributeTokens(tokens, stringLiteralPlaceholders)\n } as FailNodeDefinition;\n\n // This is a decorator node, so we expect an opening '{'.\n popAndCheck(tokens, \"{\");\n\n // Return the fail node definition.\n return node;\n}\n\n/**\n * Creates a flip node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The flip node JSON definition.\n */\nfunction createFlipNode(tokens: string[], stringLiteralPlaceholders: StringLiteralPlaceholders): FlipNodeDefinition {\n const node = {\n type: \"flip\",\n ...parseAttributeTokens(tokens, stringLiteralPlaceholders)\n } as FlipNodeDefinition;\n\n // This is a decorator node, so we expect an opening '{'.\n popAndCheck(tokens, \"{\");\n\n // Return the flip node definition.\n return node;\n}\n\n/**\n * Creates a repeat node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The repeat node JSON definition.\n */\nfunction createRepeatNode(\n tokens: string[],\n stringLiteralPlaceholders: StringLiteralPlaceholders\n): RepeatNodeDefinition {\n let node = { type: \"repeat\" } as RepeatNodeDefinition;\n\n // Get the node arguments.\n const nodeArguments = parseArgumentTokens(tokens, stringLiteralPlaceholders);\n\n // The arguments of a repeat node are optional. We may have:\n // - No node arguments, in which case the repeat note will iterate indefinitely.\n // - One node argument which will be the explicit number of iterations to make.\n // - Two node arguments which define the min and max iteration bounds from which a random iteration count will be picked.\n if (nodeArguments.length) {\n // All repeat node arguments MUST be of type number and must be integer.\n nodeArguments\n .filter((arg) => arg.type !== \"number\" || !arg.isInteger)\n .forEach(() => {\n throw new Error(`repeat node iteration counts must be integer values`);\n });\n\n // We should have got one or two iteration counts.\n if (nodeArguments.length === 1) {\n // A static iteration count was defined.\n node.iterations = nodeArguments[0].value as number;\n\n // A repeat node must have a positive number of iterations if defined.\n if (node.iterations < 0) {\n throw new Error(\"a repeat node must have a positive number of iterations if defined\");\n }\n } else if (nodeArguments.length === 2) {\n // A minimum and maximum iteration count was defined.\n node.iterations = [nodeArguments[0].value as number, nodeArguments[1].value as number];\n\n // A repeat node must have a positive min and max iteration count if they are defined.\n if (node.iterations[0] < 0 || node.iterations[1] < 0) {\n throw new Error(\"a repeat node must have a positive minimum and maximum iteration count if defined\");\n }\n\n // A repeat node must not have an minimum iteration count that exceeds the maximum iteration count.\n if (node.iterations[0] > node.iterations[1]) {\n throw new Error(\n \"a repeat node must not have a minimum iteration count that exceeds the maximum iteration count\"\n );\n }\n } else {\n // An incorrect number of iteration counts was defined.\n throw new Error(\"invalid number of repeat node iteration count arguments defined\");\n }\n }\n\n // Grab any node attribute definitions and spread them into the node definition.\n node = { ...node, ...parseAttributeTokens(tokens, stringLiteralPlaceholders) };\n\n // This is a decorator node, so we expect an opening '{'.\n popAndCheck(tokens, \"{\");\n\n // Return the repeat node definition.\n return node;\n}\n\n/**\n * Creates a retry node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The retry node JSON definition.\n */\nfunction createRetryNode(tokens: string[], stringLiteralPlaceholders: StringLiteralPlaceholders): RetryNodeDefinition {\n let node = { type: \"retry\" } as RetryNodeDefinition;\n\n // Get the node arguments.\n const nodeArguments = parseArgumentTokens(tokens, stringLiteralPlaceholders);\n\n // The arguments of a retry node are optional. We may have:\n // - No node arguments, in which case the retry note will attempt indefinitely.\n // - One node argument which will be the explicit number of attempts to make.\n // - Two node arguments which define the min and max attempt bounds from which a random attempt count will be picked.\n if (nodeArguments.length) {\n // All retry node arguments MUST be of type number and must be integer.\n nodeArguments\n .filter((arg) => arg.type !== \"number\" || !arg.isInteger)\n .forEach(() => {\n throw new Error(`retry node attempt counts must be integer values`);\n });\n\n // We should have got one or two attempt counts.\n if (nodeArguments.length === 1) {\n // A static attempt count was defined.\n node.attempts = nodeArguments[0].value as number;\n\n // A retry node must have a positive number of attempts if defined.\n if (node.attempts < 0) {\n throw new Error(\"a retry node must have a positive number of attempts if defined\");\n }\n } else if (nodeArguments.length === 2) {\n // A minimum and maximum attempt count was defined.\n node.attempts = [nodeArguments[0].value as number, nodeArguments[1].value as number];\n\n // A retry node must have a positive min and max attempts count if they are defined.\n if (node.attempts[0] < 0 || node.attempts[1] < 0) {\n throw new Error(\"a retry node must have a positive minimum and maximum attempt count if defined\");\n }\n\n // A retry node must not have a minimum attempt count that exceeds the maximum attempt count.\n if (node.attempts[0] > node.attempts[1]) {\n throw new Error(\n \"a retry node must not have a minimum attempt count that exceeds the maximum attempt count\"\n );\n }\n } else {\n // An incorrect number of attempt counts was defined.\n throw new Error(\"invalid number of retry node attempt count arguments defined\");\n }\n }\n\n // Grab any node attribute definitions and spread them into the node definition.\n node = { ...node, ...parseAttributeTokens(tokens, stringLiteralPlaceholders) };\n\n // This is a decorator node, so we expect an opening '{'.\n popAndCheck(tokens, \"{\");\n\n // Return the retry node definition.\n return node;\n}\n\n/**\n * Creates a sequence node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The sequence node JSON definition.\n */\nfunction createSequenceNode(\n tokens: string[],\n stringLiteralPlaceholders: StringLiteralPlaceholders\n): SequenceNodeDefinition {\n const node = {\n type: \"sequence\",\n ...parseAttributeTokens(tokens, stringLiteralPlaceholders)\n } as SequenceNodeDefinition;\n\n // This is a composite node, so we expect an opening '{'.\n popAndCheck(tokens, \"{\");\n\n // Return the sequence node definition.\n return node;\n}\n\n/**\n * Creates a selector node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The selector node JSON definition.\n */\nfunction createSelectorNode(\n tokens: string[],\n stringLiteralPlaceholders: StringLiteralPlaceholders\n): SelectorNodeDefinition {\n const node = {\n type: \"selector\",\n ...parseAttributeTokens(tokens, stringLiteralPlaceholders)\n } as SelectorNodeDefinition;\n\n // This is a composite node, so we expect an opening '{'.\n popAndCheck(tokens, \"{\");\n\n // Return the selector node definition.\n return node;\n}\n\n/**\n * Creates a parallel node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The parallel node JSON definition.\n */\nfunction createParallelNode(\n tokens: string[],\n stringLiteralPlaceholders: StringLiteralPlaceholders\n): ParallelNodeDefinition {\n const node = {\n type: \"parallel\",\n ...parseAttributeTokens(tokens, stringLiteralPlaceholders)\n } as ParallelNodeDefinition;\n\n // This is a composite node, so we expect an opening '{'.\n popAndCheck(tokens, \"{\");\n\n // Return the parallel node definition.\n return node;\n}\n\n/**\n * Creates a lotto node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The lotto node JSON definition.\n */\nfunction createLottoNode(tokens: string[], stringLiteralPlaceholders: StringLiteralPlaceholders): LottoNodeDefinition {\n // If any node arguments have been defined then they must be our weights.\n const nodeArguments = parseArgumentTokens(tokens, stringLiteralPlaceholders);\n\n // All lotto node arguments MUST be of type number and must be positive integers.\n nodeArguments\n .filter((arg) => arg.type !== \"number\" || !arg.isInteger || arg.value < 0)\n .forEach(() => {\n throw new Error(`lotto node weight arguments must be positive integer values`);\n });\n\n const node = {\n type: \"lotto\",\n ...parseAttributeTokens(tokens, stringLiteralPlaceholders)\n } as LottoNodeDefinition;\n\n // Apply the weights if any were defined.\n if (nodeArguments.length) {\n node.weights = nodeArguments.map(({ value }) => value) as number[];\n }\n\n // This is a composite node, so we expect an opening '{'.\n popAndCheck(tokens, \"{\");\n\n // Return the lotto node definition.\n return node;\n}\n\n/**\n * Creates an action node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The action node JSON definition.\n */\nfunction createActionNode(\n tokens: string[],\n stringLiteralPlaceholders: StringLiteralPlaceholders\n): ActionNodeDefinition {\n // Parse any node arguments, we should have at least one which will be an identifier argument for the action name\n // and agent function to invoke for the action, all other arguments are to be passed as arguments to that function.\n const [actionNameIdentifier, ...agentFunctionArgs] = parseArgumentTokens(tokens, stringLiteralPlaceholders);\n\n // Our first argument MUST be defined and be an identifier as we require an action name argument.\n if (actionNameIdentifier?.type !== \"identifier\") {\n throw new Error(\"expected action name identifier argument\");\n }\n\n // Only the first argument should have been an identifier, all agent function arguments must be string, number, boolean or null.\n agentFunctionArgs\n .filter((arg) => arg.type === \"identifier\")\n .forEach((arg) => {\n throw new Error(\n `invalid action node argument value '${arg.value}', must be string, number, boolean or null`\n );\n });\n\n // Return the action node definition.\n return {\n type: \"action\",\n call: actionNameIdentifier.value,\n args: agentFunctionArgs.map(({ value }) => value),\n ...parseAttributeTokens(tokens, stringLiteralPlaceholders)\n };\n}\n\n/**\n * Creates a condition node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The condition node JSON definition.\n */\nfunction createConditionNode(\n tokens: string[],\n stringLiteralPlaceholders: StringLiteralPlaceholders\n): ConditionNodeDefinition {\n // Parse any node arguments, we should have at least one which will be an identifier argument for the condition name\n // and agent function to invoke for the condition, all other arguments are to be passed as arguments to that function.\n const [conditionNameIdentifier, ...agentFunctionArgs] = parseArgumentTokens(tokens, stringLiteralPlaceholders);\n\n // Our first argument MUST be defined and be an identifier as we require a condition name argument.\n if (conditionNameIdentifier?.type !== \"identifier\") {\n throw new Error(\"expected condition name identifier argument\");\n }\n\n // Only the first argument should have been an identifier, all agent function arguments must be string, number, boolean or null.\n agentFunctionArgs\n .filter((arg) => arg.type === \"identifier\")\n .forEach((arg) => {\n throw new Error(\n `invalid condition node argument value '${arg.value}', must be string, number, boolean or null`\n );\n });\n\n // Return the condition node definition.\n return {\n type: \"condition\",\n call: conditionNameIdentifier.value,\n args: agentFunctionArgs.map(({ value }) => value),\n ...parseAttributeTokens(tokens, stringLiteralPlaceholders)\n };\n}\n\n/**\n * Creates a wait node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The wait node JSON definition.\n */\nfunction createWaitNode(tokens: string[], stringLiteralPlaceholders: StringLiteralPlaceholders): WaitNodeDefinition {\n let node = { type: \"wait\" } as WaitNodeDefinition;\n\n // Get the node arguments.\n const nodeArguments = parseArgumentTokens(tokens, stringLiteralPlaceholders);\n\n // The arguments of a wait node are optional. We may have:\n // - No node arguments, in which case the wait will be indefinite until it is aborted.\n // - One node argument which will be the explicit duration of the wait.\n // - Two node arguments which define the min and max duration bounds from which a random duration will be picked.\n if (nodeArguments.length) {\n // All wait node arguments MUST be of type number and must be integer.\n nodeArguments\n .filter((arg) => arg.type !== \"number\" || !arg.isInteger)\n .forEach(() => {\n throw new Error(`wait node durations must be integer values`);\n });\n\n // We may have:\n // - One node argument which will be the explicit duration of the wait.\n // - Two node arguments which define the min and max duration bounds from which a random duration will be picked.\n // - Too many arguments, which is not valid.\n if (nodeArguments.length === 1) {\n // An explicit duration was defined.\n node.duration = nodeArguments[0].value as number;\n\n // If an explict duration was defined then it must be a positive number.\n if (node.duration < 0) {\n throw new Error(\"a wait node must have a positive duration\");\n }\n } else if (nodeArguments.length === 2) {\n // Min and max duration bounds were defined from which a random duration will be picked.\n node.duration = [nodeArguments[0].value as number, nodeArguments[1].value as number];\n\n // A wait node must have a positive min and max duration.\n if (node.duration[0] < 0 || node.duration[1] < 0) {\n throw new Error(\"a wait node must have a positive minimum and maximum duration\");\n }\n\n // A wait node must not have a minimum duration that exceeds the maximum duration.\n if (node.duration[0] > node.duration[1]) {\n throw new Error(\"a wait node must not have a minimum duration that exceeds the maximum duration\");\n }\n } else if (nodeArguments.length > 2) {\n // An incorrect number of duration arguments were defined.\n throw new Error(\"invalid number of wait node duration arguments defined\");\n }\n }\n\n // Return the wait node definition.\n return { ...node, ...parseAttributeTokens(tokens, stringLiteralPlaceholders) };\n}\n\n/**\n * Creates a branch node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The branch node JSON definition.\n */\nfunction createBranchNode(\n tokens: string[],\n stringLiteralPlaceholders: StringLiteralPlaceholders\n): BranchNodeDefinition {\n // Parse any node arguments, we should have one which will be an identifier argument for the root ref.\n const nodeArguments = parseArgumentTokens(tokens, stringLiteralPlaceholders);\n\n // We should have only a single identifer argument for a branch node, which is the root ref.\n if (nodeArguments.length !== 1 || nodeArguments[0].type !== \"identifier\") {\n throw new Error(\"expected single branch name argument\");\n }\n\n // Return the branch node definition.\n return { type: \"branch\", ref: nodeArguments[0].value };\n}\n\n/**\n * Validate a fully-populated node definition that was popped off of the tree stack.\n * @param definition The popped node to validate.\n */\nfunction validatePoppedNode(definition: AnyNodeDefinition): void {\n // Decorators MUST have a child defined.\n if (isDecoratorNode(definition) && isNullOrUndefined(definition.child)) {\n throw new Error(`a ${definition.type} node must have a single child node defined`);\n }\n\n // Composites MUST have at least one child defined.\n if (isCompositeNode(definition) && !definition.children?.length) {\n throw new Error(`a ${definition.type} node must have at least a single child node defined`);\n }\n\n // We need to make sure that lotto nodes that have weights defined have a number of weights matching the number of child nodes.\n if (definition.type === \"lotto\") {\n // Check whether a 'weights' property has been defined, if it has we expect it to be an array of weights.\n if (typeof definition.weights !== \"undefined\") {\n // Check that the weights property is an array of positive integers with an element for each child node element.\n if (definition.weights.length !== definition.children.length) {\n throw new Error(\n \"expected a number of weight arguments matching the number of child nodes for lotto node\"\n );\n }\n }\n }\n}\n", "import { RootNodeDefinition } from \"./BehaviourTreeDefinition\";\nimport { flattenDefinition, isBranchNode, isInteger } from \"./BehaviourTreeDefinitionUtilities\";\nimport { convertMDSLToJSON } from \"./mdsl/MDSLDefinitionParser\";\n\n/**\n * An object representing the result of validating a tree definition.\n */\nexport type DefinitionValidationResult = {\n /**\n * A flag defining whether validation succeeded.\n */\n succeeded: boolean;\n /**\n * A string containing the error message if validation did not succeed.\n */\n errorMessage?: string;\n /**\n * The definition as json if the validation was successful, or undefined if validation did not succeed.\n */\n json?: RootNodeDefinition[];\n};\n\n/**\n * Validates the specified behaviour tree definition in the form of JSON or MDSL, not taking any globally registered subtrees into consideration.\n * @param definition The behaviour tree definition in the form of JSON or MDSL.\n * @returns An object representing the result of validating the given tree definition.\n */\nexport function validateDefinition(definition: any): DefinitionValidationResult {\n // The definition must be defined.\n if (definition === null || typeof definition === \"undefined\") {\n return createValidationFailureResult(\"definition is null or undefined\");\n }\n\n // We are expecting a definition in one of three different forms:\n // - A string which we will assume is MDSL and we will parse this to JSON before validation.\n // - An array which we will assume is an array of root node definitions with at least one being the primary root node (no 'id' property)\n // - An object which we will assume is the primary root node and should not have an 'id' property.\n if (typeof definition === \"string\") {\n // The definition is a string which we can assume is MDSL, so attempt to validate it.\n return validateMDSLDefinition(definition);\n } else if (typeof definition === \"object\") {\n // The definition will either be an array (of root node definitions) or an object (the single primary root node definition).\n return validateJSONDefinition(definition);\n } else {\n return createValidationFailureResult(`unexpected definition type of '${typeof definition}'`);\n }\n}\n\n/**\n * Validates the specified behaviour tree definition in the form of MDSL.\n * @param definition The behaviour tree definition in the form of MDSL.\n * @returns An object representing the result of validating the given tree definition.\n */\nfunction validateMDSLDefinition(definition: string): DefinitionValidationResult {\n let rootNodeDefinitions;\n\n // The first thing the we need to do is to attempt to convert our MDSL into JSON.\n try {\n // The definition is a string which we can assume is MDSL, so attempt to parse it to a JSON definition in the form of an array of root node definitions.\n rootNodeDefinitions = convertMDSLToJSON(definition);\n } catch (exception) {\n // We failed to parse the JSON from the MDSL, this is likely to be the result of it not being a valid MDSL string.\n return createValidationFailureResult((exception as Error).message);\n }\n\n // Unpack all of the root node definitions into arrays of main ('id' defined) and sub ('id' not defined) root node definitions.\n const mainRootNodeDefinitions = rootNodeDefinitions.filter(({ id }) => typeof id === \"undefined\");\n const subRootNodeDefinitions = rootNodeDefinitions.filter(({ id }) => typeof id === \"string\" && id.length > 0);\n\n // We should ALWAYS have exactly one root node definition without an 'id' property defined, which is out main root node definition.\n if (mainRootNodeDefinitions.length !== 1) {\n return createValidationFailureResult(\n \"expected single unnamed root node at base of definition to act as main root\"\n );\n }\n\n // We should never have duplicate 'id' properties across our sub root node definitions.\n const subRootNodeIdenitifers: string[] = [];\n for (const { id } of subRootNodeDefinitions) {\n // Have we already come across this 'id' property value?\n if (subRootNodeIdenitifers.includes(id!)) {\n return createValidationFailureResult(`multiple root nodes found with duplicate name '${id}'`);\n }\n\n subRootNodeIdenitifers.push(id!);\n }\n\n try {\n // Validate our branch -> subtree links and check for any circular dependencies, we don't care about checking for broken subtree links here.\n validateBranchSubtreeLinks(rootNodeDefinitions, false);\n } catch (exception) {\n return createValidationFailureResult((exception as Error).message);\n }\n\n // Our definition was valid!\n return {\n succeeded: true,\n json: rootNodeDefinitions\n };\n}\n\n/**\n * Validates the specified behaviour tree definition in the form of JSON.\n * @param definition The behaviour tree definition in the form of JSON.\n * @returns An object representing the result of validating the given tree definition.\n */\nexport function validateJSONDefinition(\n definition: RootNodeDefinition | RootNodeDefinition[]\n): DefinitionValidationResult {\n // The definition will either be an array (of root node definitions) or an object (the single primary root node definition).\n const rootNodeDefinitions = Array.isArray(definition) ? definition : [definition];\n\n // Iterate over our array of root nodes and call validateNode for each, passing an initial depth of 0, wrapped in a try catch to handle validation failures.\n try {\n rootNodeDefinitions.forEach((rootNodeDefinition) => validateNode(rootNodeDefinition, 0));\n } catch (error) {\n // Handle cases where we have caught a thrown Error and return a failure result with the error message.\n if (error instanceof Error) {\n return createValidationFailureResult(error.message);\n }\n\n // No idea what happened here!\n return createValidationFailureResult(`unexpected error: ${error}`);\n }\n\n // Unpack all of the root node definitions into arrays of main ('id' defined) and sub ('id' not defined) root node definitions.\n const mainRootNodeDefinitions = rootNodeDefinitions.filter(({ id }) => typeof id === \"undefined\");\n const subRootNodeDefinitions = rootNodeDefinitions.filter(({ id }) => typeof id === \"string\" && id.length > 0);\n\n // We should ALWAYS have exactly one root node definition without an 'id' property defined, which is out main root node definition.\n if (mainRootNodeDefinitions.length !== 1) {\n return createValidationFailureResult(\n \"expected single root node without 'id' property defined to act as main root\"\n );\n }\n\n // We should never have duplicate 'id' properties across our sub root node definitions.\n const subRootNodeIdenitifers: string[] = [];\n for (const { id } of subRootNodeDefinitions) {\n // Have we already come across this 'id' property value?\n if (subRootNodeIdenitifers.includes(id!)) {\n return createValidationFailureResult(\n `multiple root nodes found with duplicate 'id' property value of '${id}'`\n );\n }\n\n subRootNodeIdenitifers.push(id!);\n }\n\n try {\n // Validate our branch -> subtree links and check for any circular dependencies, we don't care about checking for broken subtree links here.\n validateBranchSubtreeLinks(rootNodeDefinitions, false);\n } catch (exception) {\n return createValidationFailureResult((exception as Error).message);\n }\n\n // Our definition was valid!\n return {\n succeeded: true,\n json: rootNodeDefinitions\n };\n}\n\n/**\n * Validates the branch -> subtree links across all provided root node definitions.\n * This will not consider branch nodes that reference any globally registered subtrees unless includesGlobalSubtrees\n * is set to true, in which case we will also verify that there are no broken branch -> subtree links.\n * @param rootNodeDefinitions The array of root node definitions.\n * @param includesGlobalSubtrees A flag defining whether the array includes all global subtree root node definitions.\n */\nexport function validateBranchSubtreeLinks(rootNodeDefinitions: RootNodeDefinition[], includesGlobalSubtrees: boolean) {\n // Create a mapping of root node identifiers to other root nodes that they reference via branch nodes.\n // Below is an example of a mapping that includes a circular dependency (root => a => b => c => a)\n // [{ refs: [\"a\", \"b\"] }, { id: \"a\", refs: [\"b\"] }, { id: \"b\", refs: [\"c\"] }, { id: \"c\", refs: [\"a\"] }]\n const rootNodeMappings: { id: string | undefined; refs: string[] }[] = rootNodeDefinitions.map(\n (rootNodeDefinition) => ({\n id: rootNodeDefinition.id,\n refs: flattenDefinition(rootNodeDefinition)\n .filter(isBranchNode)\n .map(({ ref }) => ref)\n })\n );\n\n // A recursive function to walk through the mappings, keeping track of which root nodes we have visited in the form of a path of root node identifiers.\n const followRefs = (mapping: { id: string | undefined; refs: string[] }, path: (string | undefined)[] = []) => {\n // Have we found a circular dependency?\n if (path.includes(mapping.id)) {\n // We found a circular dependency! Get the bad path of root node identifiers.\n const badPath = [...path, mapping.id];\n\n // Create the formatted path value. [undefined, \"a\", \"b\", \"c\", \"a\"] would be formatted as \"a -> b -> c -> a\".\n const badPathFormatted = badPath.filter((element) => !!element).join(\" => \");\n\n // No need to continue, we found a circular dependency.\n throw new Error(`circular dependency found in branch node references: ${badPathFormatted}`);\n }\n\n for (const ref of mapping.refs) {\n // Find the mapping for the root node with an identifer matching the current ref.\n const subMapping = rootNodeMappings.find(({ id }) => id === ref);\n\n // We may not have a mapping for this ref, which is normal when we aren't considering all globally registered subtrees.\n if (subMapping) {\n followRefs(subMapping, [...path, mapping.id]);\n } else if (includesGlobalSubtrees) {\n // We found a reference to a root node that doesn't exist, which is a problem seeing as the root node definitons includes all globally registered subtrees.\n throw new Error(\n mapping.id\n ? `subtree '${mapping.id}' has branch node that references root node '${ref}' which has not been defined`\n : `primary tree has branch node that references root node '${ref}' which has not been defined`\n );\n }\n }\n };\n\n // Start looking for circular dependencies and broken references from the primary root node definition.\n followRefs(rootNodeMappings.find((mapping) => typeof mapping.id === \"undefined\")!);\n}\n\n/**\n * Validate an object that we expect to be a node definition.\n * @param definition An object that we expect to be a node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateNode(definition: any, depth: number): void {\n // Every node must be valid object and have a non-empty 'type' string property.\n if (typeof definition !== \"object\" || typeof definition.type !== \"string\" || definition.type.length === 0) {\n throw new Error(\n `node definition is not an object or 'type' property is not a non-empty string at depth '${depth}'`\n );\n }\n\n // How we validate this node definition will depend on its type.\n switch (definition.type) {\n case \"action\":\n validateActionNode(definition, depth);\n break;\n\n case \"condition\":\n validateConditionNode(definition, depth);\n break;\n\n case \"wait\":\n validateWaitNode(definition, depth);\n break;\n\n case \"branch\":\n validateBranchNode(definition, depth);\n break;\n\n case \"root\":\n validateRootNode(definition, depth);\n break;\n\n case \"succeed\":\n validateSucceedNode(definition, depth);\n break;\n\n case \"fail\":\n validateFailNode(definition, depth);\n break;\n\n case \"flip\":\n validateFlipNode(definition, depth);\n break;\n\n case \"repeat\":\n validateRepeatNode(definition, depth);\n break;\n\n case \"retry\":\n validateRetryNode(definition, depth);\n break;\n\n case \"sequence\":\n validateSequenceNode(definition, depth);\n break;\n\n case \"selector\":\n validateSelectorNode(definition, depth);\n break;\n\n case \"parallel\":\n validateParallelNode(definition, depth);\n break;\n\n case \"lotto\":\n validateLottoNode(definition, depth);\n break;\n\n default:\n throw new Error(`unexpected node type of '${definition.type}' at depth '${depth}'`);\n }\n}\n\n/**\n * Validate any attributes for a given node definition.\n * @param definition The node definition.\n * @param depth The depth of the node in the behaviour tree definition.\n */\nfunction validateNodeAttributes(definition: any, depth: number): void {\n // Validate each of the attribute types for this node.\n [\"while\", \"until\", \"entry\", \"exit\", \"step\"].forEach((attributeName) => {\n // Attempt to grab the definition for the current attribute from the node definition.\n const attributeDefinition = definition[attributeName];\n\n // All node attributes are optional, so there is nothing to do if the current attribute is not defined.\n if (typeof attributeDefinition === \"undefined\") {\n return;\n }\n\n // The attribute definition must be an object.\n if (typeof attributeDefinition !== \"object\") {\n throw new Error(\n `expected attribute '${attributeName}' to be an object for '${definition.type}' node at depth '${depth}'`\n );\n }\n\n // The 'call' property must be defined for any attribute definition.\n if (typeof attributeDefinition.call !== \"string\" || attributeDefinition.call.length === 0) {\n throw new Error(\n `expected 'call' property for attribute '${attributeName}' to be a non-empty string for '${definition.type}' node at depth '${depth}'`\n );\n }\n\n // If any node attribute arguments have been defined then they must have been defined in an array.\n if (typeof attributeDefinition.args !== \"undefined\" && !Array.isArray(attributeDefinition.args)) {\n throw new Error(\n `expected 'args' property for attribute '${attributeName}' to be an array for '${definition.type}' node at depth '${depth}'`\n );\n }\n });\n}\n\n/**\n * Validate an object that we expect to be a root node definition.\n * @param definition An object that we expect to be a root node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateRootNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"root\") {\n throw new Error(\"expected node type of 'root' for root node\");\n }\n\n // A root node cannot be the child of another node.\n if (depth > 0) {\n throw new Error(\"a root node cannot be the child of another node\");\n }\n\n // Check that, if the root node 'id' property is defined, it is a non-empty string.\n if (typeof definition.id !== \"undefined\" && (typeof definition.id !== \"string\" || definition.id.length === 0)) {\n throw new Error(\"expected non-empty string for 'id' property if defined for root node\");\n }\n\n // A root node is a decorator node, so must have a child node defined.\n if (typeof definition.child === \"undefined\") {\n throw new Error(\"expected property 'child' to be defined for root node\");\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n\n // Validate the child node of this decorator node.\n validateNode(definition.child, depth + 1);\n}\n\n/**\n * Validate an object that we expect to be a succeed node definition.\n * @param definition An object that we expect to be a succeed node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateSucceedNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"succeed\") {\n throw new Error(`expected node type of 'succeed' for succeed node at depth '${depth}'`);\n }\n\n // A succeed node is a decorator node, so must have a child node defined.\n if (typeof definition.child === \"undefined\") {\n throw new Error(`expected property 'child' to be defined for succeed node at depth '${depth}'`);\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n\n // Validate the child node of this decorator node.\n validateNode(definition.child, depth + 1);\n}\n\n/**\n * Validate an object that we expect to be a fail node definition.\n * @param definition An object that we expect to be a fail node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateFailNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"fail\") {\n throw new Error(`expected node type of 'fail' for fail node at depth '${depth}'`);\n }\n\n // A fail node is a decorator node, so must have a child node defined.\n if (typeof definition.child === \"undefined\") {\n throw new Error(`expected property 'child' to be defined for fail node at depth '${depth}'`);\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n\n // Validate the child node of this decorator node.\n validateNode(definition.child, depth + 1);\n}\n\n/**\n * Validate an object that we expect to be a flip node definition.\n * @param definition An object that we expect to be a flip node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateFlipNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"flip\") {\n throw new Error(`expected node type of 'flip' for flip node at depth '${depth}'`);\n }\n\n // A flip node is a decorator node, so must have a child node defined.\n if (typeof definition.child === \"undefined\") {\n throw new Error(`expected property 'child' to be defined for flip node at depth '${depth}'`);\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n\n // Validate the child node of this decorator node.\n validateNode(definition.child, depth + 1);\n}\n\n/**\n * Validate an object that we expect to be a repeat node definition.\n * @param definition An object that we expect to be a repeat node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateRepeatNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"repeat\") {\n throw new Error(`expected node type of 'repeat' for repeat node at depth '${depth}'`);\n }\n\n // A repeat node is a decorator node, so must have a child node defined.\n if (typeof definition.child === \"undefined\") {\n throw new Error(`expected property 'child' to be defined for repeat node at depth '${depth}'`);\n }\n\n // Check whether an 'iterations' property has been defined, it may not have been if this node is to repeat indefinitely.\n if (typeof definition.iterations !== \"undefined\") {\n if (Array.isArray(definition.iterations)) {\n // Check whether any elements of the array are not integer values.\n const containsNonInteger = !!definition.iterations.filter((value: unknown) => !isInteger(value)).length;\n\n // If the 'iterations' property is an array then it MUST contain two integer values.\n if (definition.iterations.length !== 2 || containsNonInteger) {\n throw new Error(\n `expected array containing two integer values for 'iterations' property if defined for repeat node at depth '${depth}'`\n );\n }\n\n // A repeat node must have a positive min and max iterations count if they are defined.\n if (definition.iterations[0] < 0 || definition.iterations[1] < 0) {\n throw new Error(\n `expected positive minimum and maximum iterations count for 'iterations' property if defined for repeat node at depth '${depth}'`\n );\n }\n\n // A repeat node must not have a minimum iterations count that exceeds the maximum iterations count.\n if (definition.iterations[0] > definition.iterations[1]) {\n throw new Error(\n `expected minimum iterations count that does not exceed the maximum iterations count for 'iterations' property if defined for repeat node at depth '${depth}'`\n );\n }\n } else if (isInteger(definition.iterations)) {\n // A repeat node must have a positive number of iterations if defined.\n if (definition.iterations < 0) {\n throw new Error(\n `expected positive iterations count for 'iterations' property if defined for repeat node at depth '${depth}'`\n );\n }\n } else {\n throw new Error(\n `expected integer value or array containing two integer values for 'iterations' property if defined for repeat node at depth '${depth}'`\n );\n }\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n\n // Validate the child node of this decorator node.\n validateNode(definition.child, depth + 1);\n}\n\n/**\n * Validate an object that we expect to be a retry node definition.\n * @param definition An object that we expect to be a retry node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateRetryNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"retry\") {\n throw new Error(`expected node type of 'retry' for retry node at depth '${depth}'`);\n }\n\n // A retry node is a decorator node, so must have a child node defined.\n if (typeof definition.child === \"undefined\") {\n throw new Error(`expected property 'child' to be defined for retry node at depth '${depth}'`);\n }\n\n // Check whether an 'attempts' property has been defined, it may not have been if this node is to retry indefinitely.\n if (typeof definition.attempts !== \"undefined\") {\n if (Array.isArray(definition.attempts)) {\n // Check whether any elements of the array are not integer values.\n const containsNonInteger = !!definition.attempts.filter((value: unknown) => !isInteger(value)).length;\n\n // If the 'attempts' property is an array then it MUST contain two integer values.\n if (definition.attempts.length !== 2 || containsNonInteger) {\n throw new Error(\n `expected array containing two integer values for 'attempts' property if defined for retry node at depth '${depth}'`\n );\n }\n\n // A retry node must have a positive min and max attempts count if they are defined.\n if (definition.attempts[0] < 0 || definition.attempts[1] < 0) {\n throw new Error(\n `expected positive minimum and maximum attempts count for 'attempts' property if defined for retry node at depth '${depth}'`\n );\n }\n\n // A retry node must not have a minimum attempts count that exceeds the maximum attempts count.\n if (definition.attempts[0] > definition.attempts[1]) {\n throw new Error(\n `expected minimum attempts count that does not exceed the maximum attempts count for 'attempts' property if defined for retry node at depth '${depth}'`\n );\n }\n } else if (isInteger(definition.attempts)) {\n // A retry node must have a positive number of attempts if defined.\n if (definition.attempts < 0) {\n throw new Error(\n `expected positive attempts count for 'attempts' property if defined for retry node at depth '${depth}'`\n );\n }\n } else {\n throw new Error(\n `expected integer value or array containing two integer values for 'attempts' property if defined for retry node at depth '${depth}'`\n );\n }\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n\n // Validate the child node of this decorator node.\n validateNode(definition.child, depth + 1);\n}\n\n/**\n * Validate an object that we expect to be a branch node definition.\n * @param definition An object that we expect to be a branch node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateBranchNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"branch\") {\n throw new Error(`expected node type of 'branch' for branch node at depth '${depth}'`);\n }\n\n // Check that the branch node 'ref' property is defined and is a non-empty string.\n if (typeof definition.ref !== \"string\" || definition.ref.length === 0) {\n throw new Error(`expected non-empty string for 'ref' property for branch node at depth '${depth}'`);\n }\n\n // It is invalid to define guard attributes for a branch node as they should be defined on the referenced root node.\n [\"while\", \"until\"].forEach((attributeName) => {\n if (typeof definition[attributeName] !== \"undefined\") {\n throw new Error(\n `guards should not be defined for branch nodes but guard '${attributeName}' was defined for branch node at depth '${depth}'`\n );\n }\n });\n\n // It is invalid to define callback attributes for a branch node as they should be defined on the referenced root node.\n [\"entry\", \"exit\", \"step\"].forEach((attributeName) => {\n if (typeof definition[attributeName] !== \"undefined\") {\n throw new Error(\n `callbacks should not be defined for branch nodes but callback '${attributeName}' was defined for branch node at depth '${depth}'`\n );\n }\n });\n}\n\n/**\n * Validate an object that we expect to be a action node definition.\n * @param definition An object that we expect to be a action node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateActionNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"action\") {\n throw new Error(`expected node type of 'action' for action node at depth '${depth}'`);\n }\n\n // The 'call' property must be defined for a action node definition.\n if (typeof definition.call !== \"string\" || definition.call.length === 0) {\n throw new Error(`expected non-empty string for 'call' property of action node at depth '${depth}'`);\n }\n\n // If any action function arguments have been defined then they must have been defined in an array.\n if (typeof definition.args !== \"undefined\" && !Array.isArray(definition.args)) {\n throw new Error(`expected array for 'args' property if defined for action node at depth '${depth}'`);\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n}\n\n/**\n * Validate an object that we expect to be a condition node definition.\n * @param definition An object that we expect to be a condition node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateConditionNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"condition\") {\n throw new Error(`expected node type of 'condition' for condition node at depth '${depth}'`);\n }\n\n // The 'call' property must be defined for a condition node definition.\n if (typeof definition.call !== \"string\" || definition.call.length === 0) {\n throw new Error(`expected non-empty string for 'call' property of condition node at depth '${depth}'`);\n }\n\n // If any condition function arguments have been defined then they must have been defined in an array.\n if (typeof definition.args !== \"undefined\" && !Array.isArray(definition.args)) {\n throw new Error(`expected array for 'args' property if defined for condition node at depth '${depth}'`);\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n}\n\n/**\n * Validate an object that we expect to be a wait node definition.\n * @param definition An object that we expect to be a wait node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateWaitNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"wait\") {\n throw new Error(`expected node type of 'wait' for wait node at depth '${depth}'`);\n }\n\n // Check whether a 'duration' property has been defined, it may not have been if this node is to wait indefinitely.\n if (typeof definition.duration !== \"undefined\") {\n if (Array.isArray(definition.duration)) {\n // Check whether any elements of the array are not integer values.\n const containsNonInteger = !!definition.duration.filter((value: unknown) => !isInteger(value)).length;\n\n // If the 'duration' property is an array then it MUST contain two integer values.\n if (definition.duration.length !== 2 || containsNonInteger) {\n throw new Error(\n `expected array containing two integer values for 'duration' property if defined for wait node at depth '${depth}'`\n );\n }\n\n // A wait node must have a positive min and max duration value if they are defined.\n if (definition.duration[0] < 0 || definition.duration[1] < 0) {\n throw new Error(\n `expected positive minimum and maximum duration for 'duration' property if defined for wait node at depth '${depth}'`\n );\n }\n\n // A wait node must not have a minimum duration value that exceeds the maximum duration value.\n if (definition.duration[0] > definition.duration[1]) {\n throw new Error(\n `expected minimum duration value that does not exceed the maximum duration value for 'duration' property if defined for wait node at depth '${depth}'`\n );\n }\n } else if (isInteger(definition.duration)) {\n // A wait node must have a positive duration value if defined.\n if (definition.duration < 0) {\n throw new Error(\n `expected positive duration value for 'duration' property if defined for wait node at depth '${depth}'`\n );\n }\n } else {\n throw new Error(\n `expected integer value or array containing two integer values for 'duration' property if defined for wait node at depth '${depth}'`\n );\n }\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n}\n\n/**\n * Validate an object that we expect to be a sequence node definition.\n * @param definition An object that we expect to be a sequence node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateSequenceNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"sequence\") {\n throw new Error(`expected node type of 'sequence' for sequence node at depth '${depth}'`);\n }\n\n // A sequence node is a composite node, so must have a children nodes array defined.\n if (!Array.isArray(definition.children) || definition.children.length === 0) {\n throw new Error(`expected non-empty 'children' array to be defined for sequence node at depth '${depth}'`);\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n\n // Validate the child nodes of this composite node.\n definition.children.forEach((child: any) => validateNode(child, depth + 1));\n}\n\n/**\n * Validate an object that we expect to be a selector node definition.\n * @param definition An object that we expect to be a selector node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateSelectorNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"selector\") {\n throw new Error(`expected node type of 'selector' for selector node at depth '${depth}'`);\n }\n\n // A selector node is a composite node, so must have a children nodes array defined.\n if (!Array.isArray(definition.children) || definition.children.length === 0) {\n throw new Error(`expected non-empty 'children' array to be defined for selector node at depth '${depth}'`);\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n\n // Validate the child nodes of this composite node.\n definition.children.forEach((child: any) => validateNode(child, depth + 1));\n}\n\n/**\n * Validate an object that we expect to be a parallel node definition.\n * @param definition An object that we expect to be a parallel node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateParallelNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"parallel\") {\n throw new Error(`expected node type of 'parallel' for parallel node at depth '${depth}'`);\n }\n\n // A parallel node is a composite node, so must have a children nodes array defined.\n if (!Array.isArray(definition.children) || definition.children.length === 0) {\n throw new Error(`expected non-empty 'children' array to be defined for parallel node at depth '${depth}'`);\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n\n // Validate the child nodes of this composite node.\n definition.children.forEach((child: any) => validateNode(child, depth + 1));\n}\n\n/**\n * Validate an object that we expect to be a lotto node definition.\n * @param definition An object that we expect to be a lotto node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateLottoNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"lotto\") {\n throw new Error(`expected node type of 'lotto' for lotto node at depth '${depth}'`);\n }\n\n // A lotto node is a composite node, so must have a children nodes array defined.\n if (!Array.isArray(definition.children) || definition.children.length === 0) {\n throw new Error(`expected non-empty 'children' array to be defined for lotto node at depth '${depth}'`);\n }\n\n // Check whether a 'weights' property has been defined, if it has we expect it to be an array of weights.\n if (typeof definition.weights !== \"undefined\") {\n // Check that the weights property is an array of positive integers with an element for each child node element.\n if (\n !Array.isArray(definition.weights) ||\n definition.weights.length !== definition.children.length ||\n definition.weights.filter((value: unknown) => !isInteger(value)).length ||\n definition.weights.filter((value: number) => value < 0).length\n ) {\n throw new Error(\n `expected an array of positive integer weight values with a length matching the number of child nodes for 'weights' property if defined for lotto node at depth '${depth}'`\n );\n }\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n\n // Validate the child nodes of this composite node.\n definition.children.forEach((child: any) => validateNode(child, depth + 1));\n}\n\n/**\n * A helper function to create a failure validation result with the given error message.\n * @param errorMessage The validation failure error message.\n * @returns A failure validation result with the given error message.\n */\nfunction createValidationFailureResult(errorMessage: string): DefinitionValidationResult {\n return { succeeded: false, errorMessage };\n}\n", "import { ActionResult, Agent, GlobalFunction } from \"./Agent\";\nimport { RootNodeDefinition } from \"./BehaviourTreeDefinition\";\n\nexport type InvokerFunction = (args: any[]) => ActionResult | boolean;\n\n/**\n * A singleton used to store and lookup registered functions and subtrees.\n */\nexport default class Lookup {\n /**\n * The object holding any registered functions keyed on function name.\n */\n private static registeredFunctions: { [key: string]: GlobalFunction } = {};\n /**\n * The object holding any registered subtree root node definitions keyed on tree name.\n */\n private static registeredSubtrees: { [key: string]: RootNodeDefinition } = {};\n\n /**\n * Gets the function with the specified name.\n * @param name The name of the function.\n * @returns The function with the specified name.\n */\n public static getFunc(name: string): GlobalFunction {\n return this.registeredFunctions[name];\n }\n\n /**\n * Sets the function with the specified name for later lookup.\n * @param name The name of the function.\n * @param func The function.\n */\n public static setFunc(name: string, func: GlobalFunction): void {\n this.registeredFunctions[name] = func;\n }\n\n /**\n * Gets the function invoker for the specified agent and function name.\n * If a function with the specified name exists on the agent object then it will\n * be returned, otherwise we will then check the registered functions for a match.\n * @param agent The agent instance that this behaviour tree is modelling behaviour for.\n * @param name The function name.\n * @returns The function invoker for the specified agent and function name.\n */\n static getFuncInvoker(agent: Agent, name: string): InvokerFunction | null {\n // Check whether the agent contains the specified function.\n const agentFunction = agent[name];\n if (agentFunction && typeof agentFunction === \"function\") {\n return (args: any[]) => agentFunction.apply(agent, args);\n }\n\n // The agent does not contain the specified function but it may have been registered at some point.\n if (this.registeredFunctions[name] && typeof this.registeredFunctions[name] === \"function\") {\n const registeredFunction = this.registeredFunctions[name];\n return (args: any[]) => registeredFunction(agent, ...args.map((arg) => arg.value));\n }\n\n // We have no function to invoke.\n return null;\n }\n\n /**\n * Gets all registered subtree root node definitions.\n */\n static getSubtrees(): { [key: string]: RootNodeDefinition } {\n return this.registeredSubtrees;\n }\n\n /**\n * Sets the subtree with the specified name for later lookup.\n * @param name The name of the subtree.\n * @param subtree The subtree.\n */\n static setSubtree(name: string, subtree: RootNodeDefinition) {\n this.registeredSubtrees[name] = subtree;\n }\n\n /**\n * Removes the registered function or subtree with the specified name.\n * @param name The name of the registered function or subtree.\n */\n static remove(name: string) {\n delete this.registeredFunctions[name];\n delete this.registeredSubtrees[name];\n }\n\n /**\n * Remove all registered functions and subtrees.\n */\n static empty() {\n this.registeredFunctions = {};\n this.registeredSubtrees = {};\n }\n}\n", "import Node from \"../../nodes/Node\";\n\n/**\n * An exception thrown when evaluating node guard path conditions and a conditions fails.\n */\nexport default class GuardUnsatisifedException extends Error {\n /**\n * @param source The node at which a guard condition failed.\n */\n constructor(private source: Node) {\n super(\"A guard path condition has failed\");\n }\n\n /**\n * Gets whether the specified node is the node at which a guard condition failed.\n * @param node The node to check against the source node.\n * @returns Whether the specified node is the node at which a guard condition failed.\n */\n isSourceNode = (node: Node) => node === this.source;\n}\n", "import { Agent } from \"../../Agent\";\nimport Guard from \"./Guard\";\nimport Node from \"../../nodes/Node\";\nimport GuardUnsatisifedException from \"./GuardUnsatisifedException\";\n\nexport type GuardPathPart = {\n node: Node;\n guards: Guard[];\n};\n\n/**\n * Represents a path of node guards along a root-to-leaf tree path.\n */\nexport default class GuardPath {\n /**\n * @param nodes An array of objects defining a node instance -> guard link, ordered by node depth.\n */\n constructor(private nodes: GuardPathPart[]) {}\n\n /**\n * Evaluate guard conditions for all guards in the tree path, moving outwards from the root.\n * @param agent The agent, required for guard evaluation.\n * @returns An evaluation results object.\n */\n evaluate = (agent: Agent) => {\n // We need to evaluate guard conditions for nodes up the tree, moving outwards from the root.\n for (const details of this.nodes) {\n // There can be multiple guards per node.\n for (const guard of details.guards) {\n // Check whether the guard condition passes, and throw an exception if not.\n if (!guard.isSatisfied(agent)) {\n throw new GuardUnsatisifedException(details.node);\n }\n }\n }\n };\n}\n", "import { BehaviourTreeOptions } from \"../BehaviourTreeOptions\";\nimport State, { AnyState } from \"../State\";\nimport { Agent } from \"../Agent\";\nimport Leaf from \"./leaf/Leaf\";\nimport Attribute from \"../attributes/Attribute\";\nimport Entry from \"../attributes/callbacks/Entry\";\nimport Exit from \"../attributes/callbacks/Exit\";\nimport Step from \"../attributes/callbacks/Step\";\nimport Guard from \"../attributes/guards/Guard\";\nimport GuardPath from \"../attributes/guards/GuardPath\";\nimport GuardUnsatisifedException from \"../attributes/guards/GuardUnsatisifedException\";\n\n/**\n * A base node.\n */\nexport default abstract class Node {\n /**\n * The node uid.\n */\n private readonly uid: string = createNodeUid();\n /**\n * The node state.\n */\n private state: AnyState = State.READY;\n /**\n * The guard path to evaluate as part of a node update.\n */\n private guardPath: GuardPath | undefined;\n\n /**\n * @param type The node type.\n * @param attributes The node attributes.\n * @param args The node argument definitions.\n */\n constructor(private type: string, private attributes: Attribute[], private args: any[]) {}\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected abstract onUpdate(agent: Agent, options: BehaviourTreeOptions): void;\n\n /**\n * Gets the name of the node.\n */\n public abstract getName(): string;\n\n /**\n * Gets whether this node is a leaf node.\n */\n public abstract isLeafNode: () => this is Leaf;\n\n /**\n * Gets/Sets the state of the node.\n */\n getState = (): AnyState => this.state;\n setState = (value: AnyState): void => {\n this.state = value;\n };\n\n /**\n * Gets the unique id of the node.\n */\n getUid = () => this.uid;\n\n /**\n * Gets the type of the node.\n */\n getType = () => this.type;\n\n /**\n * Gets the node attributes.\n */\n getAttributes = () => this.attributes;\n\n /**\n * Gets the node arguments.\n */\n getArguments = () => this.args;\n\n /**\n * Gets the node attribute with the specified type, or null if it does not exist.\n */\n getAttribute(type: \"entry\" | \"ENTRY\"): Entry;\n getAttribute(type: \"exit\" | \"EXIT\"): Exit;\n getAttribute(type: \"step\" | \"STEP\"): Step;\n getAttribute(type: string): Attribute {\n return (\n this.getAttributes().filter((decorator) => decorator.type.toUpperCase() === type.toUpperCase())[0] || null\n );\n }\n\n /**\n * Gets the node attributes.\n */\n getGuardAttributes = (): Guard[] => this.getAttributes().filter((decorator) => decorator.isGuard()) as Guard[];\n\n /**\n * Sets the guard path to evaluate as part of a node update.\n */\n setGuardPath = (value: GuardPath) => (this.guardPath = value);\n\n /**\n * Gets whether a guard path is assigned to this node.\n */\n hasGuardPath = () => !!this.guardPath;\n\n /**\n * Gets whether this node is in the specified state.\n * @param value The value to compare to the node state.\n */\n public is(value: AnyState): boolean {\n return this.state === value;\n }\n\n /**\n * Reset the state of the node.\n */\n public reset(): void {\n this.setState(State.READY);\n }\n\n /**\n * Abort the running of this node.\n * @param agent The agent.\n */\n public abort(agent: Agent): void {\n // There is nothing to do if this node is not in the running state.\n if (!this.is(State.RUNNING)) {\n return;\n }\n\n // Reset the state of this node.\n this.reset();\n\n this.getAttribute(\"exit\")?.callAgentFunction(agent, false, true);\n }\n\n /**\n * Update the node.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n * @returns The result of the update.\n */\n public update(agent: Agent, options: BehaviourTreeOptions): void {\n // If this node is already in a 'SUCCEEDED' or 'FAILED' state then there is nothing to do.\n if (this.is(State.SUCCEEDED) || this.is(State.FAILED)) {\n return;\n }\n\n try {\n // Evaluate all of the guard path conditions for the current tree path.\n this.guardPath!.evaluate(agent);\n\n // If this node is in the READY state then call the ENTRY for this node if it exists.\n if (this.is(State.READY)) {\n this.getAttribute(\"entry\")?.callAgentFunction(agent);\n }\n\n this.getAttribute(\"step\")?.callAgentFunction(agent);\n\n // Do the actual update.\n this.onUpdate(agent, options);\n\n // If this node is now in a 'SUCCEEDED' or 'FAILED' state then call the EXIT for this node if it exists.\n if (this.is(State.SUCCEEDED) || this.is(State.FAILED)) {\n this.getAttribute(\"exit\")?.callAgentFunction(agent, this.is(State.SUCCEEDED), false);\n }\n } catch (error) {\n // If the error is a GuardUnsatisfiedException then we need to determine if this node is the source.\n if (error instanceof GuardUnsatisifedException && error.isSourceNode(this)) {\n // Abort the current node.\n this.abort(agent);\n\n // Any node that is the source of an abort will be a failed node.\n this.setState(State.FAILED);\n } else {\n throw error;\n }\n }\n }\n}\n\n/**\n * Create a randomly generated node uid.\n * @returns A randomly generated node uid.\n */\nfunction createNodeUid(): string {\n var S4 = function () {\n return (((1 + Math.random()) * 0x10000) | 0).toString(16).substring(1);\n };\n return S4() + S4() + \"-\" + S4() + \"-\" + S4() + \"-\" + S4() + \"-\" + S4() + S4() + S4();\n}\n", "import Node from \"../Node\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\n\n/**\n * A composite node that wraps child nodes.\n */\nexport default abstract class Composite extends Node {\n /**\n * @param type The node type.\n * @param attributes The node attributes.\n * @param children The child nodes.\n */\n constructor(type: string, attributes: Attribute[], protected children: Node[]) {\n super(type, attributes, []);\n }\n\n /**\n * Gets whether this node is a leaf node.\n */\n isLeafNode = () => false;\n\n /**\n * Gets the children of this node.\n */\n getChildren = () => this.children;\n\n /**\n * Reset the state of the node.\n */\n reset = () => {\n // Reset the state of this node.\n this.setState(State.READY);\n\n // Reset the state of any child nodes.\n this.getChildren().forEach((child) => child.reset());\n };\n\n /**\n * Abort the running of this node.\n * @param agent The agent.\n */\n abort = (agent: Agent) => {\n // There is nothing to do if this node is not in the running state.\n if (!this.is(State.RUNNING)) {\n return;\n }\n\n // Abort any child nodes.\n this.getChildren().forEach((child) => child.abort(agent));\n\n // Reset the state of this node.\n this.reset();\n\n this.getAttribute(\"exit\")?.callAgentFunction(agent, false, true);\n };\n}\n", "import Composite from \"./Composite\";\nimport State from \"../../State\";\nimport Node from \"../Node\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A PARALLEL node.\n * The child nodes are executed concurrently until one fails or all succeed.\n */\nexport default class Parallel extends Composite {\n /**\n * @param attributes The node attributes.\n * @param children The child nodes.\n */\n constructor(attributes: Attribute[], children: Node[]) {\n super(\"parallel\", attributes, children);\n }\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // Keep a count of the number of succeeded child nodes.\n let succeededCount = 0;\n\n let hasChildFailed = false;\n\n // Iterate over all of the children of this node.\n for (const child of this.children) {\n // If the child has never been updated or is running then we will need to update it now.\n if (child.getState() === State.READY || child.getState() === State.RUNNING) {\n // Update the child of this node.\n child.update(agent, options);\n }\n\n // If the current child has a state of 'SUCCEEDED' then we should move on to the next child.\n if (child.getState() === State.SUCCEEDED) {\n // The child node has succeeded, keep track of this to determine if all children have.\n succeededCount++;\n\n // The child node succeeded, but we have not finished checking every child node yet.\n continue;\n }\n\n // If the current child has a state of 'FAILED' then this node is also a 'FAILED' node.\n if (child.getState() === State.FAILED) {\n hasChildFailed = true;\n\n // There is no need to check the rest of the children.\n break;\n }\n\n // The node should be in the 'RUNNING' state.\n if (child.getState() !== State.RUNNING) {\n // The child node was not in an expected state.\n throw new Error(\"child node was not in an expected state.\");\n }\n }\n\n if (hasChildFailed) {\n // This node is a 'FAILED' node.\n this.setState(State.FAILED);\n\n // Abort every running child.\n for (const child of this.children) {\n if (child.getState() === State.RUNNING) {\n child.abort(agent);\n }\n }\n } else {\n // If all children have succeeded then this node has also succeeded, otherwise it is still running.\n this.setState(succeededCount === this.children.length ? State.SUCCEEDED : State.RUNNING);\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => \"PARALLEL\";\n}\n", "import Composite from \"./Composite\";\nimport Node from \"../Node\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A SELECTOR node.\n * The child nodes are executed in sequence until one succeeds or all fail.\n */\nexport default class Selector extends Composite {\n /**\n * @param attributes The node attributes.\n * @param children The child nodes.\n */\n constructor(attributes: Attribute[], protected children: Node[]) {\n super(\"selector\", attributes, children);\n }\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // Iterate over all of the children of this node.\n for (const child of this.children) {\n // If the child has never been updated or is running then we will need to update it now.\n if (child.getState() === State.READY || child.getState() === State.RUNNING) {\n // Update the child of this node.\n child.update(agent, options);\n }\n\n // If the current child has a state of 'SUCCEEDED' then this node is also a 'SUCCEEDED' node.\n if (child.getState() === State.SUCCEEDED) {\n // This node is a 'SUCCEEDED' node.\n this.setState(State.SUCCEEDED);\n\n // There is no need to check the rest of the selector nodes.\n return;\n }\n\n // If the current child has a state of 'FAILED' then we should move on to the next child.\n if (child.getState() === State.FAILED) {\n // Find out if the current child is the last one in the selector.\n // If it is then this sequence node has also failed.\n if (this.children.indexOf(child) === this.children.length - 1) {\n // This node is a 'FAILED' node.\n this.setState(State.FAILED);\n\n // There is no need to check the rest of the selector as we have completed it.\n return;\n } else {\n // The child node failed, try the next one.\n continue;\n }\n }\n\n // The node should be in the 'RUNNING' state.\n if (child.getState() === State.RUNNING) {\n // This node is a 'RUNNING' node.\n this.setState(State.RUNNING);\n\n // There is no need to check the rest of the selector as the current child is still running.\n return;\n }\n\n // The child node was not in an expected state.\n throw new Error(\"child node was not in an expected state.\");\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => \"SELECTOR\";\n}\n", "import Composite from \"./Composite\";\nimport Node from \"../Node\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A SEQUENCE node.\n * The child nodes are executed in sequence until one fails or all succeed.\n */\nexport default class Sequence extends Composite {\n /**\n * @param attributes The node attributes.\n * @param children The child nodes.\n */\n constructor(attributes: Attribute[], protected children: Node[]) {\n super(\"sequence\", attributes, children);\n }\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // Iterate over all of the children of this node.\n for (const child of this.children) {\n // If the child has never been updated or is running then we will need to update it now.\n if (child.getState() === State.READY || child.getState() === State.RUNNING) {\n // Update the child of this node.\n child.update(agent, options);\n }\n\n // If the current child has a state of 'SUCCEEDED' then we should move on to the next child.\n if (child.getState() === State.SUCCEEDED) {\n // Find out if the current child is the last one in the sequence.\n // If it is then this sequence node has also succeeded.\n if (this.children.indexOf(child) === this.children.length - 1) {\n // This node is a 'SUCCEEDED' node.\n this.setState(State.SUCCEEDED);\n\n // There is no need to check the rest of the sequence as we have completed it.\n return;\n } else {\n // The child node succeeded, but we have not finished the sequence yet.\n continue;\n }\n }\n\n // If the current child has a state of 'FAILED' then this node is also a 'FAILED' node.\n if (child.getState() === State.FAILED) {\n // This node is a 'FAILED' node.\n this.setState(State.FAILED);\n\n // There is no need to check the rest of the sequence.\n return;\n }\n\n // The node should be in the 'RUNNING' state.\n if (child.getState() === State.RUNNING) {\n // This node is a 'RUNNING' node.\n this.setState(State.RUNNING);\n\n // There is no need to check the rest of the sequence as the current child is still running.\n return;\n }\n\n // The child node was not in an expected state.\n throw new Error(\"child node was not in an expected state.\");\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => \"SEQUENCE\";\n}\n", "import createLotto from \"lotto-draw\";\n\nimport Node from \"../Node\";\nimport Composite from \"./Composite\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A LOTTO node.\n * A winning child is picked on the initial update of this node, based on ticket weighting.\n * The state of this node will match the state of the winning child.\n */\nexport default class Lotto extends Composite {\n /**\n * @param attributes The node attributes.\n * @param weights The child node weights.\n * @param children The child nodes.\n */\n constructor(attributes: Attribute[], private weights: number[] | undefined, children: Node[]) {\n super(\"lotto\", attributes, children);\n }\n\n /**\n * The child node selected to be the active one.\n */\n private selectedChild: Node | undefined;\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // If this node is in the READY state then we need to pick a winning child node.\n if (this.is(State.READY)) {\n // Create a lotto draw with which to randomly pick a child node to become the active one.\n const lottoDraw = createLotto({\n // Hook up the optional 'random' behaviour tree function option to the one used by 'lotto-draw'.\n random: options.random,\n // Pass in each child node as a participant in the lotto draw with their respective ticket count.\n participants: this.children.map((child, index) => [child, this.weights?.[index] || 1])\n });\n\n // Randomly pick a child based on ticket weighting, this will become the active child for this composite node.\n this.selectedChild = lottoDraw.draw() || undefined;\n }\n\n // If something went wrong and we don't have an active child then we should throw an error.\n if (!this.selectedChild) {\n throw new Error(\"failed to update lotto node as it has no active child\");\n }\n\n // If the selected child has never been updated or is running then we will need to update it now.\n if (this.selectedChild.getState() === State.READY || this.selectedChild.getState() === State.RUNNING) {\n this.selectedChild.update(agent, options);\n }\n\n // The state of the lotto node is the state of its selected child.\n this.setState(this.selectedChild.getState());\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => (this.weights ? `LOTTO [${this.weights.join(\",\")}]` : \"LOTTO\");\n}\n", "import Node from \"../Node\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\n\n/**\n * A decorator node that wraps a single child node.\n */\nexport default abstract class Decorator extends Node {\n /**\n * @param type The node type.\n * @param attributes The node attributes.\n * @param child The child node.\n */\n constructor(type: string, attributes: Attribute[], protected child: Node) {\n super(type, attributes, []);\n }\n\n /**\n * Gets whether this node is a leaf node.\n */\n isLeafNode = () => false;\n\n /**\n * Gets the children of this node.\n */\n getChildren = () => [this.child];\n\n /**\n * Reset the state of the node.\n */\n reset = () => {\n // Reset the state of this node.\n this.setState(State.READY);\n\n // Reset the state of the child node.\n this.child.reset();\n };\n\n /**\n * Abort the running of this node.\n * @param agent The agent.\n */\n abort = (agent: Agent) => {\n // There is nothing to do if this node is not in the running state.\n if (!this.is(State.RUNNING)) {\n return;\n }\n\n // Abort the child node.\n this.child.abort(agent);\n\n // Reset the state of this node.\n this.reset();\n\n this.getAttribute(\"exit\")?.callAgentFunction(agent, false, true);\n };\n}\n", "import Node from \"../Node\";\nimport Decorator from \"./Decorator\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A Fail node.\n * This node wraps a single child and will always move to the 'FAILED' state when the child moves to a 'SUCCEEDED' or 'FAILED' state.\n */\nexport default class Fail extends Decorator {\n /**\n * @param attributes The node attributes.\n * @param child The child node.\n */\n constructor(attributes: Attribute[], child: Node) {\n super(\"fail\", attributes, child);\n }\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // If the child has never been updated or is running then we will need to update it now.\n if (this.child.getState() === State.READY || this.child.getState() === State.RUNNING) {\n this.child.update(agent, options);\n }\n\n // The state of this node will depend in the state of its child.\n switch (this.child.getState()) {\n case State.RUNNING:\n this.setState(State.RUNNING);\n break;\n\n case State.SUCCEEDED:\n case State.FAILED:\n this.setState(State.FAILED);\n break;\n\n default:\n this.setState(State.READY);\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => \"FAIL\";\n}\n", "import Decorator from \"./Decorator\";\nimport State from \"../../State\";\nimport Node from \"../Node\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A Flip node.\n * This node wraps a single child and will flip the state of the child state.\n */\nexport default class Flip extends Decorator {\n /**\n * @param attributes The node attributes.\n * @param child The child node.\n */\n constructor(attributes: Attribute[], child: Node) {\n super(\"flip\", attributes, child);\n }\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // If the child has never been updated or is running then we will need to update it now.\n if (this.child.getState() === State.READY || this.child.getState() === State.RUNNING) {\n this.child.update(agent, options);\n }\n\n // The state of this node will depend in the state of its child.\n switch (this.child.getState()) {\n case State.RUNNING:\n this.setState(State.RUNNING);\n break;\n\n case State.SUCCEEDED:\n this.setState(State.FAILED);\n break;\n\n case State.FAILED:\n this.setState(State.SUCCEEDED);\n break;\n\n default:\n this.setState(State.READY);\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => \"FLIP\";\n}\n", "import Node from \"../Node\";\nimport Decorator from \"./Decorator\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A REPEAT node.\n * The node has a single child which can have:\n * -- A number of iterations for which to repeat the child node.\n * -- An infinite repeat loop if neither an iteration count or a condition function is defined.\n * The REPEAT node will stop and have a 'FAILED' state if its child is ever in a 'FAILED' state after an update.\n * The REPEAT node will attempt to move on to the next iteration if its child is ever in a 'SUCCEEDED' state.\n */\nexport default class Repeat extends Decorator {\n /**\n * @param attributes The node attributes.\n * @param iterations The number of iterations to repeat the child node.\n * @param iterationsMin The minimum possible number of iterations to repeat the child node.\n * @param iterationsMax The maximum possible number of iterations to repeat the child node.\n * @param child The child node.\n */\n constructor(\n attributes: Attribute[],\n private iterations: number | null,\n private iterationsMin: number | null,\n private iterationsMax: number | null,\n child: Node\n ) {\n super(\"repeat\", attributes, child);\n }\n\n /**\n * The number of target iterations to make.\n */\n private targetIterationCount: number | null = null;\n\n /**\n * The current iteration count.\n */\n private currentIterationCount: number = 0;\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // If this node is in the READY state then we need to reset the child and the target iteration count.\n if (this.is(State.READY)) {\n // Reset the child node.\n this.child.reset();\n\n // Reset the current iteration count.\n this.currentIterationCount = 0;\n\n // Set the target iteration count.\n this.setTargetIterationCount(options);\n }\n\n // Do a check to see if we can iterate. If we can then this node will move into the 'RUNNING' state.\n // If we cannot iterate then we have hit our target iteration count, which means that the node has succeeded.\n if (this.canIterate()) {\n // This node is in the running state and can do its initial iteration.\n this.setState(State.RUNNING);\n\n // We may have already completed an iteration, meaning that the child node will be in the SUCCEEDED state.\n // If this is the case then we will have to reset the child node now.\n if (this.child.getState() === State.SUCCEEDED) {\n this.child.reset();\n }\n\n // Update the child of this node.\n this.child.update(agent, options);\n\n // If the child moved into the FAILED state when we updated it then there is nothing left to do and this node has also failed.\n // If it has moved into the SUCCEEDED state then we have completed the current iteration.\n if (this.child.getState() === State.FAILED) {\n // The child has failed, meaning that this node has failed.\n this.setState(State.FAILED);\n\n return;\n } else if (this.child.getState() === State.SUCCEEDED) {\n // We have completed an iteration.\n this.currentIterationCount += 1;\n }\n } else {\n // This node is in the 'SUCCEEDED' state as we cannot iterate any more.\n this.setState(State.SUCCEEDED);\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => {\n if (this.iterations !== null) {\n return `REPEAT ${this.iterations}x`;\n } else if (this.iterationsMin !== null && this.iterationsMax !== null) {\n return `REPEAT ${this.iterationsMin}x-${this.iterationsMax}x`;\n } else {\n return \"REPEAT\";\n }\n };\n\n /**\n * Reset the state of the node.\n */\n reset = () => {\n // Reset the state of this node.\n this.setState(State.READY);\n\n // Reset the current iteration count.\n this.currentIterationCount = 0;\n\n // Reset the child node.\n this.child.reset();\n };\n\n /**\n * Gets whether an iteration can be made.\n * @returns Whether an iteration can be made.\n */\n private canIterate = () => {\n if (this.targetIterationCount !== null) {\n // We can iterate as long as we have not reached our target iteration count.\n return this.currentIterationCount < this.targetIterationCount;\n }\n\n // If neither an iteration count or a condition function were defined then we can iterate indefinitely.\n return true;\n };\n\n /**\n * Sets the target iteration count.\n * @param options The behaviour tree options object.\n */\n private setTargetIterationCount = (options: BehaviourTreeOptions) => {\n // Are we dealing with an explicit iteration count or will we be randomly picking a iteration count between the min and max iteration count.\n if (this.iterations !== null) {\n this.targetIterationCount = this.iterations;\n } else if (this.iterationsMin !== null && this.iterationsMax !== null) {\n // We will be picking a random iteration count between a min and max iteration count, if the optional 'random'\n // behaviour tree function option is defined then we will be using that, otherwise we will fall back to using Math.random.\n const random = typeof options.random === \"function\" ? options.random : Math.random;\n\n // Pick a random iteration count between a min and max iteration count.\n this.targetIterationCount = Math.floor(\n random() * (this.iterationsMax - this.iterationsMin + 1) + this.iterationsMin\n );\n } else {\n this.targetIterationCount = null;\n }\n };\n}\n", "import Node from \"../Node\";\nimport Decorator from \"./Decorator\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A RETRY node.\n * The node has a single child which can have:\n * -- A number of iterations for which to repeat the child node.\n * -- An infinite repeat loop if neither an iteration count or a condition function is defined.\n * The RETRY node will stop and have a 'SUCCEEDED' state if its child is ever in a 'SUCCEEDED' state after an update.\n * The RETRY node will attempt to move on to the next iteration if its child is ever in a 'FAILED' state.\n */\nexport default class Retry extends Decorator {\n /**\n * @param attributes The node attributes.\n * @param attempts The number of attempts to retry the child node.\n * @param attemptsMin The minimum possible number of attempts to retry the child node.\n * @param attemptsMax The maximum possible number of attempts to retry the child node.\n * @param child The child node.\n */\n constructor(\n attributes: Attribute[],\n private attempts: number | null,\n private attemptsMin: number | null,\n private attemptsMax: number | null,\n child: Node\n ) {\n super(\"retry\", attributes, child);\n }\n\n /**\n * The number of target attempts to make.\n */\n private targetAttemptCount: number | null = null;\n\n /**\n * The current attempt count.\n */\n private currentAttemptCount: number = 0;\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // If this node is in the READY state then we need to reset the child and the target attempt count.\n if (this.is(State.READY)) {\n // Reset the child node.\n this.child.reset();\n\n // Reset the current attempt count.\n this.currentAttemptCount = 0;\n\n // Set the target attempt count.\n this.setTargetAttemptCount(options);\n }\n\n // Do a check to see if we can attempt. If we can then this node will move into the 'RUNNING' state.\n // If we cannot attempt then we have hit our target attempt count, which means that the node has succeeded.\n if (this.canAttempt()) {\n // This node is in the running state and can do its initial attempt.\n this.setState(State.RUNNING);\n\n // We may have already completed an attempt, meaning that the child node will be in the FAILED state.\n // If this is the case then we will have to reset the child node now.\n if (this.child.getState() === State.FAILED) {\n this.child.reset();\n }\n\n // Update the child of this node.\n this.child.update(agent, options);\n\n // If the child moved into the SUCCEEDED state when we updated it then there is nothing left to do and this node has also succeeded.\n // If it has moved into the FAILED state then we have completed the current attempt.\n if (this.child.getState() === State.SUCCEEDED) {\n // The child has succeeded, meaning that this node has succeeded.\n this.setState(State.SUCCEEDED);\n\n return;\n } else if (this.child.getState() === State.FAILED) {\n // We have completed an attempt.\n this.currentAttemptCount += 1;\n }\n } else {\n // This node is in the 'FAILED' state as we cannot iterate any more.\n this.setState(State.FAILED);\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => {\n if (this.attempts !== null) {\n return `RETRY ${this.attempts}x`;\n } else if (this.attemptsMin !== null && this.attemptsMax !== null) {\n return `RETRY ${this.attemptsMin}x-${this.attemptsMax}x`;\n } else {\n return \"RETRY\";\n }\n };\n\n /**\n * Reset the state of the node.\n */\n reset = () => {\n // Reset the state of this node.\n this.setState(State.READY);\n\n // Reset the current attempt count.\n this.currentAttemptCount = 0;\n\n // Reset the child node.\n this.child.reset();\n };\n\n /**\n * Gets whether an attempt can be made.\n * @returns Whether an attempt can be made.\n */\n canAttempt = () => {\n if (this.targetAttemptCount !== null) {\n // We can attempt as long as we have not reached our target attempt count.\n return this.currentAttemptCount < this.targetAttemptCount;\n }\n\n // If neither an attempt count or a condition function were defined then we can attempt indefinitely.\n return true;\n };\n\n /**\n * Sets the target attempt count.\n * @param options The behaviour tree options object.\n */\n setTargetAttemptCount = (options: BehaviourTreeOptions) => {\n // Are we dealing with an explicit attempt count or will we be randomly picking an attempt count between the min and max attempt count.\n if (this.attempts !== null) {\n this.targetAttemptCount = this.attempts;\n } else if (this.attemptsMin !== null && this.attemptsMax !== null) {\n // We will be picking a random attempt count between a min and max attempt count, if the optional 'random'\n // behaviour tree function option is defined then we will be using that, otherwise we will fall back to using Math.random.\n const random = typeof options.random === \"function\" ? options.random : Math.random;\n\n // Pick a random attempt count between a min and max attempt count.\n this.targetAttemptCount = Math.floor(\n random() * (this.attemptsMax - this.attemptsMin + 1) + this.attemptsMin\n );\n } else {\n this.targetAttemptCount = null;\n }\n };\n}\n", "import Node from \"../Node\";\nimport Decorator from \"./Decorator\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A Root node.\n * The root node will have a single child.\n */\nexport default class Root extends Decorator {\n /**\n * @param attributes The node attributes.\n * @param child The child node.\n */\n constructor(attributes: Attribute[], child: Node) {\n super(\"root\", attributes, child);\n }\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // If the child has never been updated or is running then we will need to update it now.\n if (this.child.getState() === State.READY || this.child.getState() === State.RUNNING) {\n // Update the child of this node.\n this.child.update(agent, options);\n }\n\n // The state of the root node is the state of its child.\n this.setState(this.child.getState());\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => \"ROOT\";\n}\n", "import Node from \"../Node\";\nimport Decorator from \"./Decorator\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A Succeed node.\n * This node wraps a single child and will always move to the 'SUCCEEDED' state when the child moves to a 'SUCCEEDED' or 'FAILED' state.\n */\nexport default class Succeed extends Decorator {\n /**\n * @param attributes The node attributes.\n * @param child The child node.\n */\n constructor(attributes: Attribute[], child: Node) {\n super(\"succeed\", attributes, child);\n }\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // If the child has never been updated or is running then we will need to update it now.\n if (this.child.getState() === State.READY || this.child.getState() === State.RUNNING) {\n this.child.update(agent, options);\n }\n\n // The state of this node will depend in the state of its child.\n switch (this.child.getState()) {\n case State.RUNNING:\n this.setState(State.RUNNING);\n break;\n\n case State.SUCCEEDED:\n case State.FAILED:\n this.setState(State.SUCCEEDED);\n break;\n\n default:\n this.setState(State.READY);\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => \"SUCCEED\";\n}\n", "import Node from \"../Node\";\n\n/**\n * A leaf node.\n */\nexport default abstract class Leaf extends Node {\n /**\n * Gets whether this node is a leaf node.\n */\n isLeafNode = () => true;\n}\n", "import { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\nimport State, { CompleteState } from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Leaf from \"./Leaf\";\nimport Lookup from \"../../Lookup\";\nimport Attribute from \"../../attributes/Attribute\";\n\n/**\n * The type representing a resolved/rejected update promise.\n */\ntype UpdatePromiseResult = {\n /**\n * Whether the promise was resolved rather than rejected.\n */\n isResolved: boolean;\n\n /**\n * The promise resolved value or rejection reason.\n */\n value: any;\n};\n\n/**\n * An Action leaf node.\n * This represents an immediate or ongoing state of behaviour.\n */\nexport default class Action extends Leaf {\n /**\n * @param attributes The node attributes.\n * @param actionName The action name.\n * @param actionArguments The array of action argument definitions.\n */\n constructor(attributes: Attribute[], private actionName: string, private actionArguments: any[]) {\n super(\"action\", attributes, actionArguments);\n }\n\n /**\n * Whether there is a pending update promise.\n */\n private isUsingUpdatePromise = false;\n\n /**\n * The finished state result of an update promise.\n */\n private updatePromiseResult: UpdatePromiseResult | null = null;\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // If the result of this action depends on an update promise then there is nothing to do until it settles.\n if (this.isUsingUpdatePromise) {\n // Are we still waiting for our update promise to settle?\n if (!this.updatePromiseResult) {\n return;\n }\n\n const { isResolved, value } = this.updatePromiseResult;\n\n // Our update promise settled, was it resolved or rejected?\n if (isResolved) {\n // Our promise resolved so check to make sure the result is a valid finished state.\n if (value !== State.SUCCEEDED && value !== State.FAILED) {\n throw new Error(\n \"action node promise resolved with an invalid value, expected a State.SUCCEEDED or State.FAILED value to be returned\"\n );\n }\n\n // Set the state of this node to match the state returned by the promise.\n this.setState(value);\n\n return;\n } else {\n // The promise was rejected, which isn't great.\n throw new Error(`action function '${this.actionName}' promise rejected with '${value}'`);\n }\n }\n\n // Attempt to get the invoker for the action function.\n const actionFuncInvoker = Lookup.getFuncInvoker(agent, this.actionName);\n\n // The action function should be defined.\n if (actionFuncInvoker === null) {\n throw new Error(\n `cannot update action node as the action '${this.actionName}' function is not defined on the agent and has not been registered`\n );\n }\n\n let actionFunctionResult;\n\n try {\n // Call the action function, the result of which may be:\n // - The finished state of this action node.\n // - A promise to return a finished node state.\n // - Undefined if the node should remain in the running state.\n actionFunctionResult = actionFuncInvoker(this.actionArguments) as CompleteState | Promise;\n } catch (error) {\n // The user was naughty and threw something.\n throw new Error(`action function '${this.actionName}' threw '${error}'`);\n }\n\n if (actionFunctionResult instanceof Promise) {\n actionFunctionResult.then(\n (result) => {\n // If 'isUpdatePromisePending' is not set then the promise was cleared as it was resolving, probably via an abort of reset.\n if (!this.isUsingUpdatePromise) {\n return;\n }\n\n // Set the resolved update promise result so that it can be handled on the next update of this node.\n this.updatePromiseResult = {\n isResolved: true,\n value: result\n };\n },\n (reason) => {\n // If 'isUpdatePromisePending' is not set then the promise was cleared as it was resolving, probably via an abort or reset.\n if (!this.isUsingUpdatePromise) {\n return;\n }\n\n // Set the rejected update promise result so that it can be handled on the next update of this node.\n this.updatePromiseResult = {\n isResolved: false,\n value: reason\n };\n }\n );\n\n // This node will be in the 'RUNNING' state until the update promise resolves.\n this.setState(State.RUNNING);\n\n // We are now waiting for the promise returned by the use to resolve before we know what state this node is in.\n this.isUsingUpdatePromise = true;\n } else {\n // Validate the returned value.\n this.validateUpdateResult(actionFunctionResult);\n\n // Set the state of this node, this may be undefined, which just means that the node is still in the 'RUNNING' state.\n this.setState(actionFunctionResult || State.RUNNING);\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => this.actionName;\n\n /**\n * Reset the state of the node.\n */\n reset = () => {\n // Reset the state of this node.\n this.setState(State.READY);\n\n // There is no longer an update promise that we care about.\n this.isUsingUpdatePromise = false;\n this.updatePromiseResult = null;\n };\n\n /**\n * Validate the result of an update function call.\n * @param result The result of an update function call.\n */\n private validateUpdateResult = (result: CompleteState | State.RUNNING) => {\n switch (result) {\n case State.SUCCEEDED:\n case State.FAILED:\n case State.RUNNING:\n case undefined:\n return;\n default:\n throw new Error(\n `expected action function '${this.actionName}' to return an optional State.SUCCEEDED or State.FAILED value but returned '${result}'`\n );\n }\n };\n}\n", "import { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Leaf from \"./Leaf\";\nimport Lookup from \"../../Lookup\";\nimport Attribute from \"../../attributes/Attribute\";\n\n/**\n * A Condition leaf node.\n * This will succeed or fail immediately based on an agent predicate, without moving to the 'RUNNING' state.\n */\nexport default class Condition extends Leaf {\n /**\n * @param attributes The node attributes.\n * @param conditionName The name of the condition function.\n * @param conditionArguments The array of condition argument definitions.\n */\n constructor(attributes: Attribute[], private conditionName: string, private conditionArguments: any[]) {\n super(\"condition\", attributes, conditionArguments);\n }\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // Attempt to get the invoker for the condition function.\n const conditionFuncInvoker = Lookup.getFuncInvoker(agent, this.conditionName);\n\n // The condition function should be defined.\n if (conditionFuncInvoker === null) {\n throw new Error(\n `cannot update condition node as the condition '${this.conditionName}' function is not defined on the agent and has not been registered`\n );\n }\n\n let conditionFunctionResult;\n\n try {\n // Call the condition function to determine the state of this node, the result of which should be a boolean.\n conditionFunctionResult = conditionFuncInvoker(this.conditionArguments);\n } catch (error) {\n // The user was naughty and threw something.\n throw new Error(`condition function '${this.conditionName}' threw '${error}'`);\n }\n\n // The result of calling the condition function must be a boolean value.\n if (typeof conditionFunctionResult !== \"boolean\") {\n throw new Error(\n `expected condition function '${this.conditionName}' to return a boolean but returned '${conditionFunctionResult}'`\n );\n }\n\n // Set the state of this node based on the result of calling the condition function.\n this.setState(!!conditionFunctionResult ? State.SUCCEEDED : State.FAILED);\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => this.conditionName;\n}\n", "import Leaf from \"./Leaf\";\nimport State from \"../../State\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { Agent } from \"../../Agent\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A WAIT node.\n * The state of this node will change to SUCCEEDED after a duration of time\n */\nexport default class Wait extends Leaf {\n /**\n * @param attributes The node attributes.\n * @param duration The duration that this node will wait to succeed in milliseconds.\n * @param durationMin The minimum possible duration in milliseconds that this node will wait to succeed.\n * @param durationMax The maximum possible duration in milliseconds that this node will wait to succeed.\n */\n constructor(\n attributes: Attribute[],\n private duration: number | null,\n private durationMin: number | null,\n private durationMax: number | null\n ) {\n super(\"wait\", attributes, []);\n }\n\n /**\n * The time in milliseconds at which this node was first updated.\n */\n private initialUpdateTime: number = 0;\n\n /**\n * The total duration in milliseconds that this node will be waiting for.\n */\n private totalDuration: number | null = null;\n\n /**\n * The duration in milliseconds that this node has been waiting for.\n */\n private waitedDuration: number = 0;\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // If this node is in the READY state then we need to set the initial update time.\n if (this.is(State.READY)) {\n // Set the initial update time.\n this.initialUpdateTime = new Date().getTime();\n\n // Set the initial waited duration.\n this.waitedDuration = 0;\n\n // Are we dealing with an explicit duration or will we be randomly picking a duration between the min and max duration.\n if (this.duration !== null) {\n this.totalDuration = this.duration;\n } else if (this.durationMin !== null && this.durationMax !== null) {\n // We will be picking a random duration between a min and max duration, if the optional 'random' behaviour tree\n // function option is defined then we will be using that, otherwise we will fall back to using Math.random.\n const random = typeof options.random === \"function\" ? options.random : Math.random;\n\n // Pick a random duration between a min and max duration.\n this.totalDuration = Math.floor(\n random() * (this.durationMax - this.durationMin + 1) + this.durationMin\n );\n } else {\n this.totalDuration = null;\n }\n\n // The node is now running until we finish waiting.\n this.setState(State.RUNNING);\n }\n\n // If we have no total duration then this wait node will wait indefinitely until it is aborted.\n if (this.totalDuration === null) {\n return;\n }\n\n // If we have a 'getDeltaTime' function defined as part of our options then we will use it to figure out how long we have waited for.\n if (typeof options.getDeltaTime === \"function\") {\n // Get the delta time.\n const deltaTime = options.getDeltaTime();\n\n // Our delta time must be a valid number and cannot be NaN.\n if (typeof deltaTime !== \"number\" || isNaN(deltaTime)) {\n throw new Error(\"The delta time must be a valid number and not NaN.\");\n }\n\n // Update the amount of time that this node has been waiting for based on the delta time.\n this.waitedDuration += deltaTime * 1000;\n } else {\n // We are not using a delta time, so we will just work out hom much time has passed since the first update.\n this.waitedDuration = new Date().getTime() - this.initialUpdateTime;\n }\n\n // Have we waited long enough?\n if (this.waitedDuration >= this.totalDuration) {\n // We have finished waiting!\n this.setState(State.SUCCEEDED);\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => {\n if (this.duration !== null) {\n return `WAIT ${this.duration}ms`;\n } else if (this.durationMin !== null && this.durationMax !== null) {\n return `WAIT ${this.durationMin}ms-${this.durationMax}ms`;\n } else {\n return \"WAIT\";\n }\n };\n}\n", "import Guard from \"./guards/Guard\";\n\nexport type AttributeDetails = {\n /** The attribute type. */\n type: string;\n\n /** The attribute arguments. */\n args: any[];\n};\n\n/**\n * A base node attribute.\n */\nexport default abstract class Attribute {\n /**\n * @param type The node attribute type.\n * @param args The array of attribute arguments.\n */\n constructor(public type: string, public args: any[]) {}\n\n /**\n * Gets the attribute details.\n */\n abstract getDetails(): TAttributeDetails;\n\n /**\n * Gets whether this attribute is a guard.\n */\n abstract isGuard: () => this is Guard;\n}\n", "import { Agent } from \"../../Agent\";\nimport Attribute, { AttributeDetails } from \"../Attribute\";\n\nexport type GuardAttributeDetails = {\n /** The name of the condition function that determines whether the guard is satisfied. */\n condition: string;\n} & AttributeDetails;\n\n/**\n * A base node guard attribute.\n */\nexport default abstract class Guard extends Attribute {\n /**\n * @param type The node attribute type.\n * @param args The array of decorator argument definitions.\n * @param condition The name of the condition function that determines whether the guard is satisfied.\n */\n constructor(type: string, args: any[], private condition: string) {\n super(type, args);\n }\n\n /**\n * Gets the name of the condition function that determines whether the guard is satisfied.\n */\n getCondition = () => this.condition;\n\n /**\n * Gets whether this attribute is a guard.\n */\n isGuard = () => true;\n\n /**\n * Gets the attribute details.\n */\n getDetails(): GuardAttributeDetails {\n return {\n type: this.type,\n args: this.args,\n condition: this.getCondition()\n };\n }\n\n /**\n * Gets whether the guard is satisfied.\n * @param agent The agent.\n * @returns Whether the guard is satisfied.\n */\n abstract isSatisfied(agent: Agent): boolean;\n}\n", "import Guard from \"./Guard\";\nimport Lookup from \"../../Lookup\";\nimport { Agent } from \"../../Agent\";\n\n/**\n * A WHILE guard which is satisfied as long as the given condition remains true.\n */\nexport default class While extends Guard {\n /**\n * @param condition The name of the condition function that determines whether the guard is satisfied.\n * @param args The array of decorator argument definitions.\n */\n constructor(condition: string, args: any[]) {\n super(\"while\", args, condition);\n }\n\n /**\n * Gets whether the guard is satisfied.\n * @param agent The agent.\n * @returns Whether the guard is satisfied.\n */\n isSatisfied = (agent: Agent) => {\n // Attempt to get the invoker for the condition function.\n const conditionFuncInvoker = Lookup.getFuncInvoker(agent, this.getCondition());\n\n // The condition function should be defined.\n if (conditionFuncInvoker === null) {\n throw new Error(\n `cannot evaluate node guard as the condition '${this.getCondition()}' function is not defined on the agent and has not been registered`\n );\n }\n\n // Call the condition function to determine whether this guard is satisfied.\n return !!conditionFuncInvoker(this.args);\n };\n}\n", "import Guard from \"./Guard\";\nimport Lookup from \"../../Lookup\";\nimport { Agent } from \"../../Agent\";\n\n/**\n * An UNTIL guard which is satisfied as long as the given condition remains false.\n */\nexport default class Until extends Guard {\n /**\n * @param condition The name of the condition function that determines whether the guard is satisfied.\n * @param args The array of decorator argument definitions.\n */\n constructor(condition: string, args: any[]) {\n super(\"until\", args, condition);\n }\n\n /**\n * Gets whether the guard is satisfied.\n * @param agent The agent.\n * @returns Whether the guard is satisfied.\n */\n isSatisfied = (agent: Agent) => {\n // Attempt to get the invoker for the condition function.\n const conditionFuncInvoker = Lookup.getFuncInvoker(agent, this.getCondition());\n\n // The condition function should be defined.\n if (conditionFuncInvoker === null) {\n throw new Error(\n `cannot evaluate node guard as the condition '${this.getCondition()}' function is not defined on the agent and has not been registered`\n );\n }\n\n // Call the condition function to determine whether this guard is satisfied.\n return !!!conditionFuncInvoker(this.args);\n };\n}\n", "import { Agent } from \"../../Agent\";\nimport Attribute, { AttributeDetails } from \"../Attribute\";\n\nexport type CallbackAttributeDetails = {\n /** The name of the agent function that is called. */\n functionName: string;\n} & AttributeDetails;\n\n/**\n * A base node callback attribute.\n */\nexport default abstract class Callback extends Attribute {\n /**\n * @param type The node attribute type.\n * @param args The array of decorator argument definitions.\n * @param functionName The name of the agent function to call.\n */\n constructor(type: string, args: any[], private functionName: string) {\n super(type, args);\n }\n\n /**\n * Gets the name of the agent function to call.\n */\n getFunctionName = () => this.functionName;\n\n /**\n * Gets whether this attribute is a guard.\n */\n isGuard = () => false;\n\n /**\n * Gets the attribute details.\n */\n getDetails(): CallbackAttributeDetails {\n return {\n type: this.type,\n args: this.args,\n functionName: this.getFunctionName()\n };\n }\n\n /**\n * Attempt to call the agent function that this callback refers to.\n * @param agent The agent.\n */\n abstract callAgentFunction: (agent: Agent, isSuccess: boolean, isAborted: boolean) => void;\n}\n", "import Callback from \"./Callback\";\nimport Lookup from \"../../Lookup\";\nimport { Agent } from \"../../Agent\";\n\n/**\n * An ENTRY callback which defines an agent function to call when the associated node is updated and moves out of running state.\n */\nexport default class Entry extends Callback {\n /**\n * @param functionName The name of the agent function to call.\n * @param args The array of callback argument definitions.\n */\n constructor(functionName: string, args: any[]) {\n super(\"entry\", args, functionName);\n }\n\n /**\n * Attempt to call the agent function that this callback refers to.\n * @param agent The agent.\n */\n callAgentFunction = (agent: Agent) => {\n // Attempt to get the invoker for the callback function.\n const callbackFuncInvoker = Lookup.getFuncInvoker(agent, this.getFunctionName());\n\n // The callback function should be defined.\n if (callbackFuncInvoker === null) {\n throw new Error(\n `cannot call entry function '${this.getFunctionName()}' as is not defined on the agent and has not been registered`\n );\n }\n\n // Call the callback function.\n callbackFuncInvoker(this.args);\n };\n}\n", "import Callback from \"./Callback\";\nimport Lookup from \"../../Lookup\";\nimport { Agent } from \"../../Agent\";\n\n/**\n * A STEP callback which defines an agent function to call when the associated node is updated.\n */\nexport default class Step extends Callback {\n /**\n * @param functionName The name of the agent function to call.\n * @param args The array of callback argument definitions.\n */\n constructor(functionName: string, args: any[]) {\n super(\"step\", args, functionName);\n }\n\n /**\n * Attempt to call the agent function that this callback refers to.\n * @param agent The agent.\n */\n callAgentFunction = (agent: Agent) => {\n // Attempt to get the invoker for the callback function.\n const callbackFuncInvoker = Lookup.getFuncInvoker(agent, this.getFunctionName());\n\n // The callback function should be defined.\n if (callbackFuncInvoker === null) {\n throw new Error(\n `cannot call step function '${this.getFunctionName()}' as is not defined on the agent and has not been registered`\n );\n }\n\n // Call the callback function.\n callbackFuncInvoker(this.args);\n };\n}\n", "import Callback from \"./Callback\";\nimport Lookup from \"../../Lookup\";\nimport { Agent } from \"../../Agent\";\n\n/**\n * An EXIT callback which defines an agent function to call when the associated node is updated and moves to a finished state or is aborted.\n */\nexport default class Exit extends Callback {\n /**\n * @param functionName The name of the agent function to call.\n * @param args The array of callback argument definitions.\n */\n constructor(functionName: string, args: any[]) {\n super(\"exit\", args, functionName);\n }\n\n /**\n * Attempt to call the agent function that this callback refers to.\n * @param agent The agent.\n * @param isSuccess Whether the decorated node was left with a success state.\n * @param isAborted Whether the decorated node was aborted.\n */\n callAgentFunction = (agent: Agent, isSuccess: boolean, isAborted: boolean) => {\n // Attempt to get the invoker for the callback function.\n const callbackFuncInvoker = Lookup.getFuncInvoker(agent, this.getFunctionName());\n\n // The callback function should be defined.\n if (callbackFuncInvoker === null) {\n throw new Error(\n `cannot call exit function '${this.getFunctionName()}' as is not defined on the agent and has not been registered`\n );\n }\n\n // Call the callback function\n callbackFuncInvoker([{ value: { succeeded: isSuccess, aborted: isAborted } }, ...this.args]);\n };\n}\n", "import { AnyNodeDefinition, RootNodeDefinition } from \"./BehaviourTreeDefinition\";\nimport GuardPath, { GuardPathPart } from \"./attributes/guards/GuardPath\";\nimport { validateBranchSubtreeLinks } from \"./BehaviourTreeDefinitionValidator\";\nimport { isInteger } from \"./BehaviourTreeDefinitionUtilities\";\nimport Node from \"./nodes/Node\";\nimport Composite from \"./nodes/composite/Composite\";\nimport Decorator from \"./nodes/decorator/Decorator\";\nimport Parallel from \"./nodes/composite/Parallel\";\nimport Selector from \"./nodes/composite/Selector\";\nimport Sequence from \"./nodes/composite/Sequence\";\nimport Lotto from \"./nodes/composite/Lotto\";\nimport Fail from \"./nodes/decorator/Fail\";\nimport Flip from \"./nodes/decorator/Flip\";\nimport Repeat from \"./nodes/decorator/Repeat\";\nimport Retry from \"./nodes/decorator/Retry\";\nimport Root from \"./nodes/decorator/Root\";\nimport Succeed from \"./nodes/decorator/Succeed\";\nimport Action from \"./nodes/leaf/Action\";\nimport Condition from \"./nodes/leaf/Condition\";\nimport Wait from \"./nodes/leaf/Wait\";\nimport Lookup from \"./Lookup\";\nimport Attribute from \"./attributes/Attribute\";\nimport While from \"./attributes/guards/While\";\nimport Until from \"./attributes/guards/Until\";\nimport Entry from \"./attributes/callbacks/Entry\";\nimport Step from \"./attributes/callbacks/Step\";\nimport Exit from \"./attributes/callbacks/Exit\";\n\n/**\n * A type representing any node instance in a behaviour tree.\n */\ntype AnyNode =\n | Root\n | Action\n | Condition\n | Wait\n | Sequence\n | Selector\n | Lotto\n | Parallel\n | Repeat\n | Retry\n | Flip\n | Succeed\n | Fail;\n\n/**\n * A type defining a mapping of root node identifiers to root node definitions.\n */\ntype RootNodeDefinitionMap = { [key: string | symbol]: RootNodeDefinition };\n\n/**\n * A symbol to use as the main root key in any root node mappings.\n */\nconst MAIN_ROOT_NODE_KEY = Symbol(\"__root__\");\n\n/**\n * Build and populate the root nodes based on the provided definition, assuming that the definition has been validated.\n * @param definition The root node definitions.\n * @returns The built and populated root node definitions.\n */\nexport default function buildRootNode(definition: RootNodeDefinition[]): Root {\n // Create a mapping of root node identifers to root node definitions, including globally registered subtree root node definitions.\n const rootNodeDefinitionMap = createRootNodeDefinitionMap(definition);\n\n // Now that we have all of our root node definitions (those part of the tree definition and those globally registered)\n // we should validate the branch-subtree links. This will also double-check that we dont have any circular dependencies\n // in our branch-subtree references and that we have no broken branch-subtree links.\n validateBranchSubtreeLinks(\n [rootNodeDefinitionMap[MAIN_ROOT_NODE_KEY], ...Object.values(rootNodeDefinitionMap)],\n true\n );\n\n // Create our populated tree of node instances, starting with our main root node.\n const rootNode = nodeFactory(rootNodeDefinitionMap[MAIN_ROOT_NODE_KEY], rootNodeDefinitionMap) as Root;\n\n // Set a guard path on every leaf of the tree to evaluate as part of each update.\n applyLeafNodeGuardPaths(rootNode);\n\n // We only need to return the main root node.\n return rootNode;\n}\n\n/**\n * A factory function which creates a node instance based on the specified definition.\n * @param definition The node definition.\n * @param rootNodeDefinitionMap The mapping of root node identifers to root node definitions, including globally registered subtree root node definitions.\n * @returns A node instance based on the specified definition.\n */\nfunction nodeFactory(definition: AnyNodeDefinition, rootNodeDefinitionMap: RootNodeDefinitionMap): AnyNode {\n // Get the attributes for the node.\n const attributes = nodeAttributesFactory(definition);\n\n // Create the node instance based on the definition type.\n switch (definition.type) {\n case \"root\":\n return new Root(attributes, nodeFactory(definition.child, rootNodeDefinitionMap));\n\n case \"repeat\":\n let iterations: number | null = null;\n let iterationsMin: number | null = null;\n let iterationsMax: number | null = null;\n\n if (Array.isArray(definition.iterations)) {\n iterationsMin = definition.iterations[0];\n iterationsMax = definition.iterations[1];\n } else if (isInteger(definition.iterations)) {\n iterations = definition.iterations!;\n }\n\n return new Repeat(\n attributes,\n iterations,\n iterationsMin,\n iterationsMax,\n nodeFactory(definition.child, rootNodeDefinitionMap)\n );\n\n case \"retry\":\n let attempts: number | null = null;\n let attemptsMin: number | null = null;\n let attemptsMax: number | null = null;\n\n if (Array.isArray(definition.attempts)) {\n attemptsMin = definition.attempts[0];\n attemptsMax = definition.attempts[1];\n } else if (isInteger(definition.attempts)) {\n attempts = definition.attempts!;\n }\n\n return new Retry(\n attributes,\n attempts,\n attemptsMin,\n attemptsMax,\n nodeFactory(definition.child, rootNodeDefinitionMap)\n );\n\n case \"flip\":\n return new Flip(attributes, nodeFactory(definition.child, rootNodeDefinitionMap));\n\n case \"succeed\":\n return new Succeed(attributes, nodeFactory(definition.child, rootNodeDefinitionMap));\n\n case \"fail\":\n return new Fail(attributes, nodeFactory(definition.child, rootNodeDefinitionMap));\n\n case \"sequence\":\n return new Sequence(\n attributes,\n definition.children.map((child) => nodeFactory(child, rootNodeDefinitionMap))\n );\n\n case \"selector\":\n return new Selector(\n attributes,\n definition.children.map((child) => nodeFactory(child, rootNodeDefinitionMap))\n );\n\n case \"parallel\":\n return new Parallel(\n attributes,\n definition.children.map((child) => nodeFactory(child, rootNodeDefinitionMap))\n );\n\n case \"lotto\":\n return new Lotto(\n attributes,\n definition.weights,\n definition.children.map((child) => nodeFactory(child, rootNodeDefinitionMap))\n );\n\n case \"branch\":\n return nodeFactory(rootNodeDefinitionMap[definition.ref].child, rootNodeDefinitionMap);\n\n case \"action\":\n return new Action(attributes, definition.call, definition.args || []);\n\n case \"condition\":\n return new Condition(attributes, definition.call, definition.args || []);\n\n case \"wait\":\n let duration: number | null = null;\n let durationMin: number | null = null;\n let durationMax: number | null = null;\n\n if (Array.isArray(definition.duration)) {\n durationMin = definition.duration[0];\n durationMax = definition.duration[1];\n } else if (isInteger(definition.duration)) {\n duration = definition.duration!;\n }\n\n return new Wait(attributes, duration, durationMin, durationMax);\n }\n}\n\n/**\n * Creates an array of node attribute instances based on the specified node definition.\n * @param definition The node definition.\n * @returns An array of node attribute instances based on the specified node definition.\n */\nfunction nodeAttributesFactory(definition: AnyNodeDefinition): Attribute[] {\n const attributes: Attribute[] = [];\n\n if (definition.while) {\n attributes.push(new While(definition.while.call, definition.while.args ?? []));\n }\n\n if (definition.until) {\n attributes.push(new Until(definition.until.call, definition.until.args ?? []));\n }\n\n if (definition.entry) {\n attributes.push(new Entry(definition.entry.call, definition.entry.args ?? []));\n }\n\n if (definition.step) {\n attributes.push(new Step(definition.step.call, definition.step.args ?? []));\n }\n\n if (definition.exit) {\n attributes.push(new Exit(definition.exit.call, definition.exit.args ?? []));\n }\n\n return attributes;\n}\n\n/**\n * Creates a mapping of root node identifers to root node definitions, mixing in globally registered subtree root node definitions.\n * @param definition The root node definitions.\n * @returns A mapping of root node identifers to root node definitions, including globally registered subtree root node definitions.\n */\nfunction createRootNodeDefinitionMap(definition: RootNodeDefinition[]): RootNodeDefinitionMap {\n // Create a mapping of root node identifers to root node definitions.\n const rootNodeMap: RootNodeDefinitionMap = {};\n\n // Add in any registered subtree root node definitions.\n for (const [name, rootNodeDefinition] of Object.entries(Lookup.getSubtrees())) {\n // The name used when registering the subtree will be used as the root node identifier.\n rootNodeMap[name] = { ...rootNodeDefinition, id: name };\n }\n\n // Populate the map with the root node definitions that were included with the tree definition.\n // We do this after adding any registered subtrees as we want these to take presedence.\n for (const rootNodeDefinition of definition) {\n rootNodeMap[rootNodeDefinition.id ?? MAIN_ROOT_NODE_KEY] = rootNodeDefinition;\n }\n\n return rootNodeMap;\n}\n\n/**\n * Applies a guard path to every leaf of the tree to evaluate as part of each update.\n * @param root The main root tree node.\n */\nfunction applyLeafNodeGuardPaths(root: Root) {\n const nodePaths: Node[][] = [];\n\n const findLeafNodes = (path: Node[], node: Node) => {\n // Add the current node to the path.\n path = path.concat(node);\n\n // Check whether the current node is a leaf node.\n if (node.isLeafNode()) {\n nodePaths.push(path);\n } else {\n (node as Composite | Decorator).getChildren().forEach((child) => findLeafNodes(path, child));\n }\n };\n\n // Find all leaf node paths, starting from the root.\n findLeafNodes([], root);\n\n nodePaths.forEach((path) => {\n // Each node in the current path will have to be assigned a guard path, working from the root outwards.\n for (let depth = 0; depth < path.length; depth++) {\n // Get the node in the path at the current depth.\n const currentNode = path[depth];\n\n // The node may already have been assigned a guard path, if so just skip it.\n if (currentNode.hasGuardPath()) {\n continue;\n }\n\n // Create the guard path for the current node.\n const guardPath = new GuardPath(\n path\n .slice(0, depth + 1)\n .map((node) => ({ node, guards: node.getGuardAttributes() }))\n .filter((details) => details.guards.length > 0)\n );\n\n // Assign the guard path to the current node.\n currentNode.setGuardPath(guardPath);\n }\n });\n}\n", "import State, { AnyState } from \"./State\";\nimport Lookup from \"./Lookup\";\nimport Node from \"./nodes/Node\";\nimport Root from \"./nodes/decorator/Root\";\nimport Composite from \"./nodes/composite/Composite\";\nimport Decorator from \"./nodes/decorator/Decorator\";\nimport { Agent, GlobalFunction } from \"./Agent\";\nimport { CallbackAttributeDetails } from \"./attributes/callbacks/Callback\";\nimport { GuardAttributeDetails } from \"./attributes/guards/Guard\";\nimport { BehaviourTreeOptions } from \"./BehaviourTreeOptions\";\nimport { convertMDSLToJSON } from \"./mdsl/MDSLDefinitionParser\";\nimport { RootNodeDefinition } from \"./BehaviourTreeDefinition\";\nimport { validateDefinition, validateJSONDefinition } from \"./BehaviourTreeDefinitionValidator\";\nimport buildRootNode from \"./BehaviourTreeBuilder\";\nimport { isNullOrUndefined } from \"./BehaviourTreeDefinitionUtilities\";\n\n// Purely for outside inspection of the tree.\nexport type FlattenedTreeNode = {\n id: string;\n type: string;\n caption: string;\n state: AnyState;\n guards: GuardAttributeDetails[];\n callbacks: CallbackAttributeDetails[];\n args: any[];\n parentId: string | null;\n};\n\n/**\n * A representation of a behaviour tree.\n */\nexport class BehaviourTree {\n /**\n * The main root tree node.\n */\n private readonly _rootNode: Root;\n\n /**\n * Creates a new instance of the BehaviourTree class.\n * @param definition The behaviour tree definition as either an MDSL string, root node definition object or array of root node definition objects.\n * @param agent The agent instance that this behaviour tree is modelling behaviour for.\n * @param options The behaviour tree options object.\n */\n constructor(\n definition: string | RootNodeDefinition | RootNodeDefinition[],\n private agent: Agent,\n private options: BehaviourTreeOptions = {}\n ) {\n // The tree definition must be defined.\n if (isNullOrUndefined(definition)) {\n throw new Error(\"tree definition not defined\");\n }\n\n // The agent must be defined and not null.\n if (typeof agent !== \"object\" || agent === null) {\n throw new Error(\"the agent must be an object and not null\");\n }\n\n // We should validate the definition before we try to build the tree nodes.\n const { succeeded, errorMessage, json } = validateDefinition(definition);\n\n // Did our validation fail without error?\n if (!succeeded) {\n throw new Error(`invalid definition: ${errorMessage}`);\n }\n\n // Double check that we did actually get our json definition as part of our definition validtion.\n if (!json) {\n throw new Error(\n \"expected json definition to be returned as part of successful definition validation response\"\n );\n }\n\n try {\n // Create the populated tree of behaviour tree nodes and get the root node.\n this._rootNode = buildRootNode(json);\n } catch (exception) {\n // There was an issue in trying build and populate the behaviour tree.\n throw new Error(`error building tree: ${(exception as Error).message}`);\n }\n }\n\n /**\n * Gets whether the tree is in the RUNNING state.\n * @returns true if the tree is in the RUNNING state, otherwise false.\n */\n isRunning() {\n return this._rootNode.getState() === State.RUNNING;\n }\n\n /**\n * Gets the current tree state of SUCCEEDED, FAILED, READY or RUNNING.\n * @returns The current tree state.\n */\n getState() {\n return this._rootNode.getState();\n }\n\n /**\n * Step the tree.\n * 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.\n * 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\n * 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.\n *\n * 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.\n */\n step() {\n // If the root node has already been stepped to completion then we need to reset it.\n if (this._rootNode.getState() === State.SUCCEEDED || this._rootNode.getState() === State.FAILED) {\n this._rootNode.reset();\n }\n\n try {\n this._rootNode.update(this.agent, this.options);\n } catch (exception) {\n throw new Error(`error stepping tree: ${(exception as Error).message}`);\n }\n }\n\n /**\n * Resets the tree from the root node outwards to each nested node, giving each a state of READY.\n */\n reset() {\n this._rootNode.reset();\n }\n\n /**\n * Gets the flattened details of every node in the tree.\n * @returns The flattened details of every node in the tree.\n */\n getFlattenedNodeDetails(): FlattenedTreeNode[] {\n // Create an empty flattened array of tree nodes.\n const flattenedTreeNodes: FlattenedTreeNode[] = [];\n\n /**\n * Helper function to process a node instance and push details into the flattened tree nodes array.\n * @param node The current node.\n * @param parentUid The UID of the node parent, or null if the node is the main root node.\n */\n const processNode = (node: Node, parentUid: string | null) => {\n // Get the guard and callback attribute details for this node.\n const guards = node\n .getAttributes()\n .filter((attribute) => attribute.isGuard())\n .map((attribute) => attribute.getDetails()) as GuardAttributeDetails[];\n const callbacks = node\n .getAttributes()\n .filter((attribute) => !attribute.isGuard())\n .map((attribute) => attribute.getDetails()) as CallbackAttributeDetails[];\n\n // Push the current node into the flattened nodes array.\n flattenedTreeNodes.push({\n id: node.getUid(),\n type: node.getType(),\n caption: node.getName(),\n state: node.getState(),\n guards,\n callbacks,\n args: node.getArguments(),\n parentId: parentUid\n });\n\n // Process each of the nodes children if it is not a leaf node.\n if (!node.isLeafNode()) {\n (node as Composite | Decorator)\n .getChildren()\n .forEach((child) => processNode(child, (node as Composite | Decorator).getUid()));\n }\n };\n\n // Convert the nested node structure into a flattened array of node details.\n processNode(this._rootNode, null);\n\n return flattenedTreeNodes;\n }\n\n /**\n * Registers the action/condition/guard/callback function or subtree with the given name.\n * @param name The name of the function or subtree to register.\n * @param value The function or subtree definition to register.\n */\n static register(name: string, value: GlobalFunction | string | RootNodeDefinition) {\n // Are we going to register a action/condition/guard/callback function?\n if (typeof value === \"function\") {\n Lookup.setFunc(name, value);\n return;\n }\n\n // We are not registering an action/condition/guard/callback function, so we must be registering a subtree.\n if (typeof value === \"string\") {\n let rootNodeDefinitions: RootNodeDefinition[];\n\n // We will assume that any string passed in will be a mdsl definition.\n try {\n rootNodeDefinitions = convertMDSLToJSON(value);\n } catch (exception) {\n throw new Error(`error registering definition, invalid MDSL: ${(exception as Error).message}`);\n }\n\n // This function should only ever be called with a definition containing a single unnamed root node.\n if (rootNodeDefinitions.length != 1 || rootNodeDefinitions[0].id !== null) {\n throw new Error(\"error registering definition: expected a single unnamed root node\");\n }\n\n try {\n // We should validate the subtree as we don't want invalid subtrees available via the lookup.\n const { succeeded, errorMessage } = validateJSONDefinition(rootNodeDefinitions[0]);\n\n // Did our validation fail without error?\n if (!succeeded) {\n throw new Error(errorMessage);\n }\n } catch (exception) {\n throw new Error(`error registering definition: ${(exception as Error).message}`);\n }\n\n // Everything seems hunky-dory, register the subtree.\n Lookup.setSubtree(name, rootNodeDefinitions[0]);\n } else if (typeof value === \"object\" && !Array.isArray(value)) {\n // We will assume that any object passed in is a root node definition.\n\n try {\n // We should validate the subtree as we don't want invalid subtrees available via the lookup.\n const { succeeded, errorMessage } = validateJSONDefinition(value);\n\n // Did our validation fail without error?\n if (!succeeded) {\n throw new Error(errorMessage);\n }\n } catch (exception) {\n throw new Error(`error registering definition: ${(exception as Error).message}`);\n }\n\n // Everything seems hunky-dory, register the subtree.\n Lookup.setSubtree(name, value);\n } else {\n throw new Error(\"unexpected value, expected string mdsl definition, root node json definition or function\");\n }\n }\n\n /**\n * Unregisters the registered action/condition/guard/callback function or subtree with the given name.\n * @param name The name of the registered action/condition/guard/callback function or subtree to unregister.\n */\n static unregister(name: string): void {\n Lookup.remove(name);\n }\n\n /**\n * Unregister all registered action/condition/guard/callback functions and subtrees.\n */\n static unregisterAll(): void {\n Lookup.empty();\n }\n}\n"], - "mappings": "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", + "sourcesContent": ["\"use strict\";\r\nObject.defineProperty(exports, \"__esModule\", { value: true });\r\nexports.Participant = void 0;\r\n/**\r\n * A participant that holds a number of tickets.\r\n */\r\nvar Participant = /** @class */ (function () {\r\n /**\r\n * Creates an instance of the Participant class.\r\n * @param participant The actual participant.\r\n * @param tickets The number of tickets held by the participant.\r\n */\r\n function Participant(participant, tickets) {\r\n if (tickets === void 0) { tickets = 1; }\r\n this._participant = participant;\r\n this._tickets = tickets;\r\n }\r\n Object.defineProperty(Participant.prototype, \"participant\", {\r\n /** Gets the actual participant. */\r\n get: function () {\r\n return this._participant;\r\n },\r\n enumerable: false,\r\n configurable: true\r\n });\r\n Object.defineProperty(Participant.prototype, \"tickets\", {\r\n /** Gets or sets the number of tickets held by the participant. */\r\n get: function () {\r\n return this._tickets;\r\n },\r\n set: function (value) {\r\n this._tickets = value;\r\n },\r\n enumerable: false,\r\n configurable: true\r\n });\r\n return Participant;\r\n}());\r\nexports.Participant = Participant;\r\n", "\"use strict\";\r\nObject.defineProperty(exports, \"__esModule\", { value: true });\r\nexports.isNaturalNumber = exports.isNullOrUndefined = void 0;\r\n/**\r\n * Gets whether the value provided is null or undefined.\r\n * @param value The value to check.\r\n * @returns Whether the value provided is null or undefined.\r\n */\r\nfunction isNullOrUndefined(value) {\r\n return value === null || value === undefined;\r\n}\r\nexports.isNullOrUndefined = isNullOrUndefined;\r\n/**\r\n * Gets whether the value provided is a natural number.\r\n * @param value The value to check.\r\n * @returns Whether the value provided is a natural number.\r\n */\r\nfunction isNaturalNumber(value) {\r\n return typeof value === \"number\" && value >= 1 && Math.floor(value) === value;\r\n}\r\nexports.isNaturalNumber = isNaturalNumber;\r\n", "\"use strict\";\r\nObject.defineProperty(exports, \"__esModule\", { value: true });\r\nexports.Lotto = void 0;\r\nvar Participant_1 = require(\"./Participant\");\r\nvar Utilities_1 = require(\"./Utilities\");\r\n/**\r\n * Represents a lotto consisting of a number of pickable ticket-holding participants.\r\n */\r\nvar Lotto = /** @class */ (function () {\r\n /**\r\n * Creates a new instance of Lotto.\r\n * @param customRandom The custom RNG to use in place of Math.random().\r\n */\r\n function Lotto(customRandom) {\r\n /** The array of participants that are holding tickets in the lotto. */\r\n this._participants = [];\r\n this._customRandom = customRandom;\r\n }\r\n /**\r\n * Adds a participant with the specified number of tickets, or adds to the participant ticket count if the participant already holds tickets.\r\n * @param participant The participant to add or to increase the ticket count for if they already hold tickets.\r\n * @param tickets The number of tickets, defaults to 1.\r\n * @returns The Lotto instance.\r\n */\r\n Lotto.prototype.add = function (participant, tickets) {\r\n if (tickets === void 0) { tickets = 1; }\r\n // Check that we have a valid ticket count.\r\n if (!(0, Utilities_1.isNaturalNumber)(tickets)) {\r\n throw new Error(\"tickets value must be a natural number\");\r\n }\r\n // Check whether this participant has already been added.\r\n var existingParticipant = this._participants.find(function (part) { return part.participant === participant; });\r\n if (existingParticipant) {\r\n // The participant has already been added to the lotto so just add to their ticket count.\r\n existingParticipant.tickets += tickets;\r\n }\r\n else {\r\n // The participant is not part of the lotto so we should add them.\r\n this._participants.push(new Participant_1.Participant(participant, tickets));\r\n }\r\n return this;\r\n };\r\n /**\r\n * Removes the specified number of tickets for the given participant from the draw, or all tickets if a ticket number is not defined.\r\n * @param participant The participant to remove tickets for.\r\n * @param tickets The number of tickets to remove, or undefined if all tickets are to be removed.\r\n * @returns The Lotto instance.\r\n */\r\n Lotto.prototype.remove = function (participant, tickets) {\r\n // Attempt to get the existing participant.\r\n var existingParticipant = this._participants.find(function (part) { return part.participant === participant; });\r\n // There is nothing to do if the specified participant isn't even part of the lotto.\r\n if (!existingParticipant) {\r\n return this;\r\n }\r\n // Check whether a tickets value was given.\r\n if (tickets !== undefined) {\r\n // Check that we have a valid ticket count.\r\n if (!(0, Utilities_1.isNaturalNumber)(tickets)) {\r\n throw new Error(\"tickets value must be a natural number\");\r\n }\r\n existingParticipant.tickets -= tickets;\r\n // If the participant no longer holds any tickets then they should be removed.\r\n if (existingParticipant.tickets < 1) {\r\n this._participants = this._participants.filter(function (part) { return part !== existingParticipant; });\r\n }\r\n }\r\n else {\r\n // We are removing all tickets for the participant so just remove them from the lotto.\r\n this._participants = this._participants.filter(function (part) { return part !== existingParticipant; });\r\n }\r\n return this;\r\n };\r\n /**\r\n * Draw a winning ticket and return the participant that holds the ticket.\r\n * @param options The draw options.\r\n * @returns The participant that holds the winning ticket.\r\n */\r\n Lotto.prototype.draw = function (options) {\r\n if (options === void 0) { options = {}; }\r\n // If we have no participants then just return null.\r\n if (this._participants.length === 0) {\r\n return null;\r\n }\r\n var redrawable = (0, Utilities_1.isNullOrUndefined)(options.redrawable) ? true : options.redrawable;\r\n var pickable = [];\r\n this._participants.forEach(function (_a) {\r\n var participant = _a.participant, tickets = _a.tickets;\r\n for (var ticketCount = 0; ticketCount < tickets; ticketCount++) {\r\n pickable.push(participant);\r\n }\r\n });\r\n var random;\r\n // We need a random floating-point number between 0 (inclusive) and 1 to scale up to pick our winner.\r\n // If a custom random function exists then we should use that or fall back to Math.random().\r\n if (this._customRandom) {\r\n // Call our custom random function to get a random floating-point number.\r\n random = this._customRandom();\r\n // Verify that the result of calling our custom random function is a number between 0 (inclusive) and 1.\r\n if (typeof random !== \"number\" || random < 0 || random >= 1) {\r\n throw new Error(\"the 'random' function provided did not return a number between 0 (inclusive) and 1\");\r\n }\r\n }\r\n else {\r\n // No custom random function was defined so just use good ol' Math.random().\r\n random = Math.random();\r\n }\r\n // Pick a winning participant.\r\n var winner = pickable[Math.floor(random * pickable.length)];\r\n // If the ticket isn't redrawable then we should remove a ticket from the winning participants ticket count.\r\n if (!redrawable) {\r\n this.remove(winner, 1);\r\n }\r\n // Return the winning participant.\r\n return winner;\r\n };\r\n /**\r\n * Draws multiple winning tickets and return an array of the participants that hold the winning tickets.\r\n * @param tickets The number of winning tickets to draw.\r\n * @param options The draw multiple options.\r\n * @returns An array of the participants that hold the winning tickets.\r\n */\r\n Lotto.prototype.drawMultiple = function (tickets, options) {\r\n if (options === void 0) { options = {}; }\r\n var uniqueResults = (0, Utilities_1.isNullOrUndefined)(options.unique) ? false : options.unique;\r\n // Handle cases where the user has asked for zero tickets (no idea why they would do this be we should trust them).\r\n if (tickets === 0) {\r\n return [];\r\n }\r\n // Now that we know out tickets value is not zero we should check that it is a valid natural number.\r\n if (!(0, Utilities_1.isNaturalNumber)(tickets)) {\r\n throw new Error(\"tickets value must be a natural number\");\r\n }\r\n var result = [];\r\n // Keep drawing tickets until we either reach the number of required tickets or we simply run out of tickets to draw.\r\n // We can run out of tickets to draw if 'options.redrawable' is explicity 'false' or we just had no participants when 'drawMultiple' was called.\r\n while (result.length < tickets && this._participants.length > 0) {\r\n result.push(this.draw(options));\r\n }\r\n // If the 'unique' draw option is set then we need to remove duplicates from the result list.\r\n if (uniqueResults) {\r\n // Create an array to store our unique results.\r\n var unique = [];\r\n // Iterate over all of our participants (with potential duplicates) and populate our array of unique values.\r\n for (var _i = 0, result_1 = result; _i < result_1.length; _i++) {\r\n var participant = result_1[_i];\r\n if (unique.indexOf(participant) === -1) {\r\n unique.push(participant);\r\n }\r\n }\r\n result = unique;\r\n }\r\n return result;\r\n };\r\n return Lotto;\r\n}());\r\nexports.Lotto = Lotto;\r\n", "\"use strict\";\r\nObject.defineProperty(exports, \"__esModule\", { value: true });\r\nexports.createLotto = void 0;\r\nvar Lotto_1 = require(\"./Lotto\");\r\n/**\r\n * A function that creates and returns a Lotto instance.\r\n * @param participantsOrOptions An array of initial participants or options relating to the creation of a Lotto instance.\r\n * @returns A new Lotto instance.\r\n */\r\nfunction createLotto(participantsOrOptions) {\r\n // If no initial participants or lotto options were provided as an argument then we can just return a new lotto instance now.\r\n if (!participantsOrOptions) {\r\n return new Lotto_1.Lotto();\r\n }\r\n // Check whether we were provided with an array of initial participants or a lotto options object.\r\n if (Array.isArray(participantsOrOptions)) {\r\n // We are dealing with a pre-defined array of participants.\r\n var participants = participantsOrOptions;\r\n var lotto_1 = new Lotto_1.Lotto();\r\n // If the lotto participants have been defined upfront then we will need to add them all to our lotto instance now.\r\n participants.forEach(function (_a) {\r\n var participant = _a[0], tokens = _a[1];\r\n return lotto_1.add(participant, tokens);\r\n });\r\n // Return the Lotto instance.\r\n return lotto_1;\r\n }\r\n else {\r\n // We are dealing with some lotto options.\r\n var random = participantsOrOptions.random, participants = participantsOrOptions.participants;\r\n // Create a Lotto instance passing the custom RNG function to use in place of Math.random() (which could be undefined).\r\n var lotto_2 = new Lotto_1.Lotto(random);\r\n // If the lotto participants have been defined upfront as part of the options then we will need to add them all to our lotto instance now.\r\n if (participants) {\r\n participants.forEach(function (_a) {\r\n var participant = _a[0], tokens = _a[1];\r\n return lotto_2.add(participant, tokens);\r\n });\r\n }\r\n // Return the Lotto instance.\r\n return lotto_2;\r\n }\r\n}\r\nexports.createLotto = createLotto;\r\n", "\"use strict\";\r\nObject.defineProperty(exports, \"__esModule\", { value: true });\r\nvar createLotto_1 = require(\"./createLotto\");\r\nexports.default = createLotto_1.createLotto;\r\n", "import State from \"./State\";\nimport { validateDefinition } from \"./BehaviourTreeDefinitionValidator\";\nimport { convertMDSLToJSON } from \"./mdsl/MDSLDefinitionParser\";\nimport { BehaviourTree, FlattenedTreeNode } from \"./BehaviourTree\";\nimport { BehaviourTreeOptions } from \"./BehaviourTreeOptions\";\n\nexport { BehaviourTree, State, convertMDSLToJSON, validateDefinition };\nexport type { FlattenedTreeNode, BehaviourTreeOptions };\n", "/**\n * Enumeration of node state types.\n */\nexport enum State {\n READY = \"mistreevous.ready\",\n RUNNING = \"mistreevous.running\",\n SUCCEEDED = \"mistreevous.succeeded\",\n FAILED = \"mistreevous.failed\"\n}\n\nexport { State as default };\n\nexport type CompleteState = State.SUCCEEDED | State.FAILED;\nexport type AnyState = State.READY | State.RUNNING | CompleteState;\n", "import {\n NodeDefinition,\n RootNodeDefinition,\n DecoratorNodeDefinition,\n CompositeNodeDefinition,\n AnyNodeDefinition,\n BranchNodeDefinition\n} from \"./BehaviourTreeDefinition\";\n\n/**\n * A type guard function that returns true if the specified node satisfies the RootNodeDefinition type.\n * @param node The node.\n * @returns A value of true if the specified node satisfies the RootNodeDefinition type.\n */\nexport function isRootNode(node: NodeDefinition): node is RootNodeDefinition {\n return node.type === \"root\";\n}\n\n/**\n * A type guard function that returns true if the specified node satisfies the BranchNodeDefinition type.\n * @param node The node.\n * @returns A value of true if the specified node satisfies the BranchNodeDefinition type.\n */\nexport function isBranchNode(node: NodeDefinition): node is BranchNodeDefinition {\n return node.type === \"branch\";\n}\n\n/**\n * A type guard function that returns true if the specified node satisfies the NodeDefinition type.\n * @param node The node.\n * @returns A value of true if the specified node satisfies the NodeDefinition type.\n */\nexport function isLeafNode(node: NodeDefinition): node is NodeDefinition {\n return [\"branch\", \"action\", \"condition\", \"wait\"].includes(node.type);\n}\n\n/**\n * A type guard function that returns true if the specified node satisfies the DecoratorNodeDefinition type.\n * @param node The node.\n * @returns A value of true if the specified node satisfies the DecoratorNodeDefinition type.\n */\nexport function isDecoratorNode(node: NodeDefinition): node is DecoratorNodeDefinition {\n return [\"root\", \"repeat\", \"retry\", \"flip\", \"succeed\", \"fail\"].includes(node.type);\n}\n\n/**\n * A type guard function that returns true if the specified node satisfies the CompositeNodeDefinition type.\n * @param node The node.\n * @returns A value of true if the specified node satisfies the CompositeNodeDefinition type.\n */\nexport function isCompositeNode(node: NodeDefinition): node is CompositeNodeDefinition {\n return [\"sequence\", \"selector\", \"lotto\", \"parallel\"].includes(node.type);\n}\n\n/**\n * Flatten a node definition into an array of all of its nested node definitions.\n * @param nodeDefinition The node definition to flatten.\n * @returns An array of all of nested node definitions.\n */\nexport function flattenDefinition(nodeDefinition: AnyNodeDefinition): AnyNodeDefinition[] {\n const nodes: AnyNodeDefinition[] = [];\n\n const processNode = (currentNodeDefinition: AnyNodeDefinition) => {\n nodes.push(currentNodeDefinition);\n\n if (isCompositeNode(currentNodeDefinition)) {\n currentNodeDefinition.children.forEach(processNode);\n } else if (isDecoratorNode(currentNodeDefinition)) {\n processNode(currentNodeDefinition.child);\n }\n };\n\n processNode(nodeDefinition);\n\n return nodes;\n}\n\n/**\n * Determines whether the passed value is an integer.\n * @param value The value to check.\n * @returns Whether the passed value is an integer.\n */\nexport function isInteger(value: unknown): boolean {\n return typeof value === \"number\" && Math.floor(value) === value;\n}\n\n/**\n * Determines whether the passed value is null or undefined.\n * @param value The value to check.\n * @returns Whether the passed value is null or undefined.\n */\nexport function isNullOrUndefined(value: unknown): boolean {\n return typeof value === \"undefined\" || value === null;\n}\n", "/**\n * A type defining an object that holds a reference to substitued string literals parsed from the definition.\n */\nexport type StringLiteralPlaceholders = { [key: string]: string };\n\n/**\n * Pop the next raw token from the specified array of tokens and throw an error if it wasn't the expected one.\n * @param tokens The array of tokens.\n * @param expected An optional string or array or items, one of which must match the next popped token.\n * @returns The popped token.\n */\nexport function popAndCheck(tokens: string[], expected?: string | string[]): string {\n // Get and remove the next token.\n const popped = tokens.shift();\n\n // We were expecting another token but there aren't any.\n if (popped === undefined) {\n throw new Error(\"unexpected end of definition\");\n }\n\n // Do we have an expected token/tokens array?\n if (expected != undefined) {\n // Get an array of expected values, if the popped token matches any then we are all good.\n const expectedValues = typeof expected === \"string\" ? [expected] : expected;\n\n // Check whether the popped token matches at least one of our expected items.\n var tokenMatchesExpectation = expectedValues.some((item) => popped.toUpperCase() === item.toUpperCase());\n\n // Throw an error if the popped token didn't match any of our expected items.\n if (!tokenMatchesExpectation) {\n const expectationString = expectedValues.map((item) => \"'\" + item + \"'\").join(\" or \");\n throw new Error(\"unexpected token found. Expected \" + expectationString + \" but got '\" + popped + \"'\");\n }\n }\n\n // Return the popped token.\n return popped;\n}\n\n/**\n * Swaps out any node/attribute argument string literals with placeholders.\n * @param definition The definition.\n * @returns An object containing a mapping of placeholders to original string values as well as the processed definition string.\n */\nexport function substituteStringLiterals(definition: string): {\n placeholders: StringLiteralPlaceholders;\n processedDefinition: string;\n} {\n // Create an object to hold the mapping of placeholders to original string values.\n const placeholders: StringLiteralPlaceholders = {};\n\n // Replace any string literals wrapped with double quotes in our definition with placeholders to be processed later.\n const processedDefinition = definition.replace(/\\\"(\\\\.|[^\"\\\\])*\\\"/g, (match) => {\n var strippedMatch = match.substring(1, match.length - 1);\n var placeholder = Object.keys(placeholders).find((key) => placeholders[key] === strippedMatch);\n\n // If we have no existing string literal match then create a new placeholder.\n if (!placeholder) {\n placeholder = `@@${Object.keys(placeholders).length}@@`;\n placeholders[placeholder] = strippedMatch;\n }\n\n return placeholder;\n });\n\n return { placeholders, processedDefinition };\n}\n\n/**\n * Parse the tree definition into an array of raw tokens.\n * @param definition The definition.\n * @returns An array of tokens parsed from the definition.\n */\nexport function parseTokensFromDefinition(definition: string): string[] {\n // Add some space around various important characters so that they can be plucked out easier as individual tokens.\n definition = definition.replace(/\\(/g, \" ( \");\n definition = definition.replace(/\\)/g, \" ) \");\n definition = definition.replace(/\\{/g, \" { \");\n definition = definition.replace(/\\}/g, \" } \");\n definition = definition.replace(/\\]/g, \" ] \");\n definition = definition.replace(/\\[/g, \" [ \");\n definition = definition.replace(/\\,/g, \" , \");\n\n // Split the definition into raw token form and return it.\n return definition.replace(/\\s+/g, \" \").trim().split(\" \");\n}\n", "import { StringLiteralPlaceholders, popAndCheck } from \"./MDSLUtilities\";\n\n/**\n * A type representing any node function argument.\n */\ntype Argument = {\n /**\n * The argument value.\n */\n value: T;\n /**\n * The argument type, used for validation.\n */\n type: string;\n};\n\ntype NullArgument = Argument & {\n type: \"null\";\n};\n\ntype BooleanArgument = Argument & {\n type: \"boolean\";\n};\n\ntype NumberArgument = Argument & {\n type: \"number\";\n /**\n * A flag defining whether the number argument value is a valid integer. (used for validation)\n */\n isInteger: boolean;\n};\n\ntype StringPlaceholderArgument = Argument & {\n type: \"string\";\n};\n\ntype IdentifierArgument = Argument & {\n type: \"identifier\";\n};\n\n/**\n * A type representing a reference to any node function argument.\n */\ntype AnyArgument = NullArgument | BooleanArgument | NumberArgument | StringPlaceholderArgument | IdentifierArgument;\n\n/**\n * Parse an array of argument definitions from the specified tokens array.\n * @param tokens The array tokens to parse the argument definitions from.\n * @param stringArgumentPlaceholders The mapping of string literal node argument placeholders to original values.\n * @param argumentValidator The argument validator function.\n * @param validationFailedMessage The exception message to throw if argument validation fails.\n * @returns An array of argument definitions parsed from the specified tokens array.\n */\nexport function parseArgumentTokens(\n tokens: string[],\n stringArgumentPlaceholders: StringLiteralPlaceholders\n): AnyArgument[] {\n const argumentList: AnyArgument[] = [];\n\n // If the next token is not a '[' or '(' then we have no arguments to parse.\n if (![\"[\", \"(\"].includes(tokens[0])) {\n return argumentList;\n }\n\n // Any lists of arguments will always be wrapped in '[]' for node arguments or '()' for attribute arguments.\n // We are looking for a '[' or '(' opener that wraps the argument tokens and the relevant closer.\n const closingToken = popAndCheck(tokens, [\"[\", \"(\"]) === \"[\" ? \"]\" : \")\";\n\n const argumentListTokens: string[] = [];\n\n // Grab all tokens between the '[' and ']' or '(' and ')'.\n while (tokens.length && tokens[0] !== closingToken) {\n // The next token is part of our arguments list.\n argumentListTokens.push(tokens.shift()!);\n }\n\n // Validate the order of the argument tokens. Each token must either be a ',' or a single argument that satisfies the validator.\n argumentListTokens.forEach((token, index) => {\n // Get whether this token should be an actual argument.\n const shouldBeArgumentToken = !(index & 1);\n\n // If the current token should be an actual argument then validate it, otherwise it should be a ',' token.\n if (shouldBeArgumentToken) {\n // Get the argument definition.\n const argumentDefinition = getArgumentDefinition(token, stringArgumentPlaceholders);\n\n // This is a valid argument!\n argumentList.push(argumentDefinition);\n } else {\n // The current token should be a ',' token.\n if (token !== \",\") {\n throw new Error(`invalid argument list, expected ',' or ']' but got '${token}'`);\n }\n }\n });\n\n // The arguments list should terminate with a ']' or ')' token, depending on the opener.\n popAndCheck(tokens, closingToken);\n\n // Return the arguments.\n return argumentList;\n}\n\n/**\n * Gets an argument value definition.\n * @param token The argument token.\n * @param stringArgumentPlaceholders The mapping of string literal node argument placeholders to original values.\n * @returns An argument value definition.\n */\nfunction getArgumentDefinition(token: string, stringArgumentPlaceholders: StringLiteralPlaceholders): AnyArgument {\n // Check whether the token represents a null value.\n if (token === \"null\") {\n return {\n value: null,\n type: \"null\"\n } as NullArgument;\n }\n\n // Check whether the token represents a boolean value.\n if (token === \"true\" || token === \"false\") {\n return {\n value: token === \"true\",\n type: \"boolean\"\n } as BooleanArgument;\n }\n\n // Check whether the token represents a number value.\n // TODO: Relies on broken isNaN - see MDN.\n // if (!Number.isNaN(token)) {\n if (!isNaN(token as any)) {\n return {\n value: parseFloat(token),\n isInteger: parseFloat(token) === parseInt(token, 10),\n type: \"number\"\n } as NumberArgument;\n }\n\n // Check whether the token is a placeholder (e.g. @@0@@) representing a string literal.\n if (token.match(/^@@\\d+@@$/g)) {\n return {\n value: stringArgumentPlaceholders[token].replace('\\\\\"', '\"'),\n type: \"string\"\n } as StringPlaceholderArgument;\n }\n\n // The only remaining option is that the argument value is an identifier.\n return {\n value: token,\n type: \"identifier\"\n } as IdentifierArgument;\n}\n", "import { NodeAttributeDefinition } from \"../BehaviourTreeDefinition\";\nimport { parseArgumentTokens } from \"./MDSLNodeArgumentParser\";\nimport { StringLiteralPlaceholders } from \"./MDSLUtilities\";\n\n/**\n * A type defining the attribute definitions of a node.\n */\ntype NodeAttributes = {\n while?: NodeAttributeDefinition;\n until?: NodeAttributeDefinition;\n entry?: NodeAttributeDefinition;\n exit?: NodeAttributeDefinition;\n step?: NodeAttributeDefinition;\n};\n\n/**\n * Parse any node attribute definitions from the specified tokens array.\n * @param tokens The array of remaining tokens.\n * @param stringArgumentPlaceholders The mapping of string literal node argument placeholders to original values.\n * @returns An object of attribute definitions defined by any directly following tokens.\n */\nexport function parseAttributeTokens(\n tokens: string[],\n stringArgumentPlaceholders: StringLiteralPlaceholders\n): NodeAttributes {\n const nodeAttributeNames: (keyof NodeAttributes)[] = [\"while\", \"until\", \"entry\", \"exit\", \"step\"];\n\n // Create an object to hold any attributes found.\n const attributes: NodeAttributes = {};\n\n // Try to get the name of the attribute for the next token.\n let nextAttributeName = tokens[0]?.toLowerCase() as keyof NodeAttributes;\n\n // Pull attribute tokens as well as their arguments off of the tokens stack until we have no more.\n while (nodeAttributeNames.includes(nextAttributeName)) {\n // Check to make sure that we have not already created an attribute definition of this type.\n if (attributes[nextAttributeName]) {\n throw new Error(`duplicate attribute '${tokens[0].toUpperCase()}' found for node`);\n }\n\n // Remove the attribute name token from the array of tokens.\n tokens.shift();\n\n // Grab the attribute arguments, assuming the first to be an identifier.\n const [attributeCallIdentifier, ...attributeArguments] = parseArgumentTokens(\n tokens,\n stringArgumentPlaceholders\n );\n\n // The first attribute argument has to be an identifer, this will reference an agent function.\n if (attributeCallIdentifier?.type !== \"identifier\") {\n throw new Error(\"expected agent function or registered function name identifier argument for attribute\");\n }\n\n // Any attribute arguments (other than the expected call identifier) must have a type of string, number, boolean or null.\n attributeArguments\n .filter((arg) => arg.type === \"identifier\")\n .forEach((arg) => {\n throw new Error(\n `invalid attribute argument value '${arg.value}', must be string, number, boolean or null`\n );\n });\n\n // Create the attribute definition and add it to the object of attribute definitions found.\n attributes[nextAttributeName] = {\n call: attributeCallIdentifier.value,\n args: attributeArguments.map(({ value }) => value)\n };\n\n // Try to get the next attribute name token, as there could be multiple.\n nextAttributeName = tokens[0]?.toLowerCase() as keyof NodeAttributes;\n }\n\n return attributes;\n}\n", "import {\n ActionNodeDefinition,\n AnyChildNodeDefinition,\n AnyNodeDefinition,\n BranchNodeDefinition,\n ConditionNodeDefinition,\n FailNodeDefinition,\n FlipNodeDefinition,\n LottoNodeDefinition,\n ParallelNodeDefinition,\n RepeatNodeDefinition,\n RetryNodeDefinition,\n RootNodeDefinition,\n SelectorNodeDefinition,\n SequenceNodeDefinition,\n SucceedNodeDefinition,\n WaitNodeDefinition\n} from \"../BehaviourTreeDefinition\";\nimport {\n isCompositeNode,\n isDecoratorNode,\n isLeafNode,\n isNullOrUndefined,\n isRootNode\n} from \"../BehaviourTreeDefinitionUtilities\";\nimport { parseArgumentTokens } from \"./MDSLNodeArgumentParser\";\nimport { parseAttributeTokens } from \"./MDSLNodeAttributeParser\";\nimport {\n StringLiteralPlaceholders,\n parseTokensFromDefinition,\n popAndCheck,\n substituteStringLiterals\n} from \"./MDSLUtilities\";\n\n/**\n * Convert the MDSL tree definition string into an equivalent JSON definition.\n * @param definition The tree definition string as MDSL.\n * @returns The root node JSON definitions.\n */\nexport function convertMDSLToJSON(definition: string): RootNodeDefinition[] {\n // Swap out any node/attribute argument string literals with a placeholder and get a mapping of placeholders to original values as well as the processed definition.\n const { placeholders, processedDefinition } = substituteStringLiterals(definition);\n\n // Parse our definition definition string into an array of raw tokens.\n const tokens = parseTokensFromDefinition(processedDefinition);\n\n return convertTokensToJSONDefinition(tokens, placeholders);\n}\n\n/**\n * Converts the specified tree definition tokens into a JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The root node JSON definitions.\n */\nfunction convertTokensToJSONDefinition(\n tokens: string[],\n stringLiteralPlaceholders: StringLiteralPlaceholders\n): RootNodeDefinition[] {\n // There must be at least 3 tokens for the tree definition to be valid. 'ROOT', '{' and '}'.\n if (tokens.length < 3) {\n throw new Error(\"invalid token count\");\n }\n\n // We should have a matching number of '{' and '}' tokens. If not, then there are scopes that have not been properly closed.\n if (tokens.filter((token) => token === \"{\").length !== tokens.filter((token) => token === \"}\").length) {\n throw new Error(\"scope character mismatch\");\n }\n\n // Create an array of tree stack arrays where root nodes will always be at the botton and the current composite/decorator node at the top.\n // There should be an element in this array for every root node defined and every element should be an array with a root note as the first element.\n // E.g. A definition with two root nodes defined:\n // [\n // [root, lotto, sequence],\n // [root, selector]\n // ]\n const treeStacks: [Partial, ...Partial[]][] = [];\n\n // Create an array of all root node definitions that we create.\n const rootNodes: Partial[] = [];\n\n // A helper function used to push node definitions onto the tree stack.\n const pushNode = (node: AnyNodeDefinition) => {\n // If the node is a root node then we need to create a new tree stack array with the root node at the root.\n if (isRootNode(node)) {\n // We need to double-check that this root node is not the child of another node.\n // We can do this by checking whether the top tree stack is not empty (contains an existing node)\n if (treeStacks[treeStacks.length - 1]?.length) {\n throw new Error(\"a root node cannot be the child of another node\");\n }\n\n // Add the root node definition to our array of all parsed root node definitions.\n rootNodes.push(node);\n\n // Add the root node definition to the root of a new tree stack.\n treeStacks.push([node]);\n\n return;\n }\n\n // All non-root nodes should be pushed after their root nodes so handle cases\n // where we may not have any tree stacks or our top-most tree stack is empty.\n if (!treeStacks.length || !treeStacks[treeStacks.length - 1].length) {\n throw new Error(\"expected root node at base of definition\");\n }\n\n // Get the current tree stack that we are populating.\n const topTreeStack = treeStacks[treeStacks.length - 1];\n\n // Get the top-most node in the current tree stack, this will be a composite/decorator node\n // for which we will populate its children array if composite or setting its child if a decorator.\n const topTreeStackTopNode = topTreeStack[topTreeStack.length - 1] as AnyNodeDefinition;\n\n // If the top-most node in the current root stack is a composite or decorator\n // node then the current node should be added as a child of the top-most node.\n if (isCompositeNode(topTreeStackTopNode)) {\n topTreeStackTopNode.children = topTreeStackTopNode.children || [];\n topTreeStackTopNode.children.push(node);\n } else if (isDecoratorNode(topTreeStackTopNode)) {\n // If the top node already has a child node set then throw an error as a decorator should only have a single child.\n if (topTreeStackTopNode.child) {\n throw new Error(\"a decorator node must only have a single child node\");\n }\n\n topTreeStackTopNode.child = node;\n }\n\n // If the node we are adding is also a composite or decorator node, then we should push it\n // onto the current tree stack, as subsequent nodes will be added as its child/children.\n if (!isLeafNode(node)) {\n topTreeStack.push(node);\n }\n };\n\n // A helper function used to pop the top-most node definition off of the tree stack and return it.\n const popNode = (): AnyNodeDefinition | null => {\n let poppedNode: AnyNodeDefinition | null = null;\n\n // Get the current tree stack that we are populating.\n const topTreeStack = treeStacks[treeStacks.length - 1];\n\n // Pop the top-most node in the current tree stack if there is one.\n if (topTreeStack.length) {\n poppedNode = topTreeStack.pop() as AnyNodeDefinition;\n }\n\n // We don't want any empty tree stacks in our stack of tree stacks.\n if (!topTreeStack.length) {\n treeStacks.pop();\n }\n\n return poppedNode;\n };\n\n // We should keep processing the raw tokens until we run out of them.\n while (tokens.length) {\n // Grab the next token.\n const token = tokens.shift()!;\n\n // How we create the next node depends on the current raw token value.\n switch (token.toUpperCase()) {\n case \"ROOT\": {\n pushNode(createRootNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"SUCCEED\": {\n pushNode(createSucceedNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"FAIL\": {\n pushNode(createFailNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"FLIP\": {\n pushNode(createFlipNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"REPEAT\": {\n pushNode(createRepeatNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"RETRY\": {\n pushNode(createRetryNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"SEQUENCE\": {\n pushNode(createSequenceNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"SELECTOR\": {\n pushNode(createSelectorNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"PARALLEL\": {\n pushNode(createParallelNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"LOTTO\": {\n pushNode(createLottoNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"ACTION\": {\n pushNode(createActionNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"CONDITION\": {\n pushNode(createConditionNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"WAIT\": {\n pushNode(createWaitNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"BRANCH\": {\n pushNode(createBranchNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"}\": {\n // The '}' character closes the current scope and means that we have to pop a node off of the current stack.\n const poppedNode = popNode();\n\n // Now that we have a node definition we can carry out any validation that may require the node to be fully populated.\n if (poppedNode) {\n validatePoppedNode(poppedNode);\n }\n\n break;\n }\n\n default: {\n throw new Error(`unexpected token: ${token}`);\n }\n }\n }\n\n return rootNodes as RootNodeDefinition[];\n}\n\n/**\n * Creates a root node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The root node JSON definition.\n */\nfunction createRootNode(tokens: string[], stringLiteralPlaceholders: StringLiteralPlaceholders): RootNodeDefinition {\n // Create the root node definition.\n let node = {\n type: \"root\"\n } as Partial;\n\n // Parse any node arguments, we should only have one if any which will be an identifier argument for the root identifier.\n const nodeArguments = parseArgumentTokens(tokens, stringLiteralPlaceholders);\n\n // Check whether any node arguments were defined.\n if (nodeArguments.length) {\n // We should only have one argument, if any, which will be an identifier argument for the root identifier.\n if (nodeArguments.length === 1 && nodeArguments[0].type === \"identifier\") {\n // The root node identifier will be the first and only node argument value.\n node.id = nodeArguments[0].value as string;\n } else {\n throw new Error(\"expected single root name argument\");\n }\n }\n\n // Grab any node attribute definitions and spread them into the node definition.\n node = { ...node, ...parseAttributeTokens(tokens, stringLiteralPlaceholders) };\n\n // This is a decorator node, so we expect an opening '{'.\n popAndCheck(tokens, \"{\");\n\n // Return the root node definition.\n return node as RootNodeDefinition;\n}\n\n/**\n * Creates a succeed node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The succeed node JSON definition.\n */\nfunction createSucceedNode(\n tokens: string[],\n stringLiteralPlaceholders: StringLiteralPlaceholders\n): SucceedNodeDefinition {\n const node = {\n type: \"succeed\",\n ...parseAttributeTokens(tokens, stringLiteralPlaceholders)\n } as SucceedNodeDefinition;\n\n // This is a decorator node, so we expect an opening '{'.\n popAndCheck(tokens, \"{\");\n\n // Return the succeed node definition.\n return node;\n}\n\n/**\n * Creates a fail node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The fail node JSON definition.\n */\nfunction createFailNode(tokens: string[], stringLiteralPlaceholders: StringLiteralPlaceholders): FailNodeDefinition {\n const node = {\n type: \"fail\",\n ...parseAttributeTokens(tokens, stringLiteralPlaceholders)\n } as FailNodeDefinition;\n\n // This is a decorator node, so we expect an opening '{'.\n popAndCheck(tokens, \"{\");\n\n // Return the fail node definition.\n return node;\n}\n\n/**\n * Creates a flip node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The flip node JSON definition.\n */\nfunction createFlipNode(tokens: string[], stringLiteralPlaceholders: StringLiteralPlaceholders): FlipNodeDefinition {\n const node = {\n type: \"flip\",\n ...parseAttributeTokens(tokens, stringLiteralPlaceholders)\n } as FlipNodeDefinition;\n\n // This is a decorator node, so we expect an opening '{'.\n popAndCheck(tokens, \"{\");\n\n // Return the flip node definition.\n return node;\n}\n\n/**\n * Creates a repeat node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The repeat node JSON definition.\n */\nfunction createRepeatNode(\n tokens: string[],\n stringLiteralPlaceholders: StringLiteralPlaceholders\n): RepeatNodeDefinition {\n let node = { type: \"repeat\" } as RepeatNodeDefinition;\n\n // Get the node arguments.\n const nodeArguments = parseArgumentTokens(tokens, stringLiteralPlaceholders);\n\n // The arguments of a repeat node are optional. We may have:\n // - No node arguments, in which case the repeat note will iterate indefinitely.\n // - One node argument which will be the explicit number of iterations to make.\n // - Two node arguments which define the min and max iteration bounds from which a random iteration count will be picked.\n if (nodeArguments.length) {\n // All repeat node arguments MUST be of type number and must be integer.\n nodeArguments\n .filter((arg) => arg.type !== \"number\" || !arg.isInteger)\n .forEach(() => {\n throw new Error(`repeat node iteration counts must be integer values`);\n });\n\n // We should have got one or two iteration counts.\n if (nodeArguments.length === 1) {\n // A static iteration count was defined.\n node.iterations = nodeArguments[0].value as number;\n\n // A repeat node must have a positive number of iterations if defined.\n if (node.iterations < 0) {\n throw new Error(\"a repeat node must have a positive number of iterations if defined\");\n }\n } else if (nodeArguments.length === 2) {\n // A minimum and maximum iteration count was defined.\n node.iterations = [nodeArguments[0].value as number, nodeArguments[1].value as number];\n\n // A repeat node must have a positive min and max iteration count if they are defined.\n if (node.iterations[0] < 0 || node.iterations[1] < 0) {\n throw new Error(\"a repeat node must have a positive minimum and maximum iteration count if defined\");\n }\n\n // A repeat node must not have an minimum iteration count that exceeds the maximum iteration count.\n if (node.iterations[0] > node.iterations[1]) {\n throw new Error(\n \"a repeat node must not have a minimum iteration count that exceeds the maximum iteration count\"\n );\n }\n } else {\n // An incorrect number of iteration counts was defined.\n throw new Error(\"invalid number of repeat node iteration count arguments defined\");\n }\n }\n\n // Grab any node attribute definitions and spread them into the node definition.\n node = { ...node, ...parseAttributeTokens(tokens, stringLiteralPlaceholders) };\n\n // This is a decorator node, so we expect an opening '{'.\n popAndCheck(tokens, \"{\");\n\n // Return the repeat node definition.\n return node;\n}\n\n/**\n * Creates a retry node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The retry node JSON definition.\n */\nfunction createRetryNode(tokens: string[], stringLiteralPlaceholders: StringLiteralPlaceholders): RetryNodeDefinition {\n let node = { type: \"retry\" } as RetryNodeDefinition;\n\n // Get the node arguments.\n const nodeArguments = parseArgumentTokens(tokens, stringLiteralPlaceholders);\n\n // The arguments of a retry node are optional. We may have:\n // - No node arguments, in which case the retry note will attempt indefinitely.\n // - One node argument which will be the explicit number of attempts to make.\n // - Two node arguments which define the min and max attempt bounds from which a random attempt count will be picked.\n if (nodeArguments.length) {\n // All retry node arguments MUST be of type number and must be integer.\n nodeArguments\n .filter((arg) => arg.type !== \"number\" || !arg.isInteger)\n .forEach(() => {\n throw new Error(`retry node attempt counts must be integer values`);\n });\n\n // We should have got one or two attempt counts.\n if (nodeArguments.length === 1) {\n // A static attempt count was defined.\n node.attempts = nodeArguments[0].value as number;\n\n // A retry node must have a positive number of attempts if defined.\n if (node.attempts < 0) {\n throw new Error(\"a retry node must have a positive number of attempts if defined\");\n }\n } else if (nodeArguments.length === 2) {\n // A minimum and maximum attempt count was defined.\n node.attempts = [nodeArguments[0].value as number, nodeArguments[1].value as number];\n\n // A retry node must have a positive min and max attempts count if they are defined.\n if (node.attempts[0] < 0 || node.attempts[1] < 0) {\n throw new Error(\"a retry node must have a positive minimum and maximum attempt count if defined\");\n }\n\n // A retry node must not have a minimum attempt count that exceeds the maximum attempt count.\n if (node.attempts[0] > node.attempts[1]) {\n throw new Error(\n \"a retry node must not have a minimum attempt count that exceeds the maximum attempt count\"\n );\n }\n } else {\n // An incorrect number of attempt counts was defined.\n throw new Error(\"invalid number of retry node attempt count arguments defined\");\n }\n }\n\n // Grab any node attribute definitions and spread them into the node definition.\n node = { ...node, ...parseAttributeTokens(tokens, stringLiteralPlaceholders) };\n\n // This is a decorator node, so we expect an opening '{'.\n popAndCheck(tokens, \"{\");\n\n // Return the retry node definition.\n return node;\n}\n\n/**\n * Creates a sequence node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The sequence node JSON definition.\n */\nfunction createSequenceNode(\n tokens: string[],\n stringLiteralPlaceholders: StringLiteralPlaceholders\n): SequenceNodeDefinition {\n const node = {\n type: \"sequence\",\n ...parseAttributeTokens(tokens, stringLiteralPlaceholders)\n } as SequenceNodeDefinition;\n\n // This is a composite node, so we expect an opening '{'.\n popAndCheck(tokens, \"{\");\n\n // Return the sequence node definition.\n return node;\n}\n\n/**\n * Creates a selector node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The selector node JSON definition.\n */\nfunction createSelectorNode(\n tokens: string[],\n stringLiteralPlaceholders: StringLiteralPlaceholders\n): SelectorNodeDefinition {\n const node = {\n type: \"selector\",\n ...parseAttributeTokens(tokens, stringLiteralPlaceholders)\n } as SelectorNodeDefinition;\n\n // This is a composite node, so we expect an opening '{'.\n popAndCheck(tokens, \"{\");\n\n // Return the selector node definition.\n return node;\n}\n\n/**\n * Creates a parallel node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The parallel node JSON definition.\n */\nfunction createParallelNode(\n tokens: string[],\n stringLiteralPlaceholders: StringLiteralPlaceholders\n): ParallelNodeDefinition {\n const node = {\n type: \"parallel\",\n ...parseAttributeTokens(tokens, stringLiteralPlaceholders)\n } as ParallelNodeDefinition;\n\n // This is a composite node, so we expect an opening '{'.\n popAndCheck(tokens, \"{\");\n\n // Return the parallel node definition.\n return node;\n}\n\n/**\n * Creates a lotto node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The lotto node JSON definition.\n */\nfunction createLottoNode(tokens: string[], stringLiteralPlaceholders: StringLiteralPlaceholders): LottoNodeDefinition {\n // If any node arguments have been defined then they must be our weights.\n const nodeArguments = parseArgumentTokens(tokens, stringLiteralPlaceholders);\n\n // All lotto node arguments MUST be of type number and must be positive integers.\n nodeArguments\n .filter((arg) => arg.type !== \"number\" || !arg.isInteger || arg.value < 0)\n .forEach(() => {\n throw new Error(`lotto node weight arguments must be positive integer values`);\n });\n\n const node = {\n type: \"lotto\",\n ...parseAttributeTokens(tokens, stringLiteralPlaceholders)\n } as LottoNodeDefinition;\n\n // Apply the weights if any were defined.\n if (nodeArguments.length) {\n node.weights = nodeArguments.map(({ value }) => value) as number[];\n }\n\n // This is a composite node, so we expect an opening '{'.\n popAndCheck(tokens, \"{\");\n\n // Return the lotto node definition.\n return node;\n}\n\n/**\n * Creates an action node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The action node JSON definition.\n */\nfunction createActionNode(\n tokens: string[],\n stringLiteralPlaceholders: StringLiteralPlaceholders\n): ActionNodeDefinition {\n // Parse any node arguments, we should have at least one which will be an identifier argument for the action name\n // and agent function to invoke for the action, all other arguments are to be passed as arguments to that function.\n const [actionNameIdentifier, ...agentFunctionArgs] = parseArgumentTokens(tokens, stringLiteralPlaceholders);\n\n // Our first argument MUST be defined and be an identifier as we require an action name argument.\n if (actionNameIdentifier?.type !== \"identifier\") {\n throw new Error(\"expected action name identifier argument\");\n }\n\n // Only the first argument should have been an identifier, all agent function arguments must be string, number, boolean or null.\n agentFunctionArgs\n .filter((arg) => arg.type === \"identifier\")\n .forEach((arg) => {\n throw new Error(\n `invalid action node argument value '${arg.value}', must be string, number, boolean or null`\n );\n });\n\n // Return the action node definition.\n return {\n type: \"action\",\n call: actionNameIdentifier.value,\n args: agentFunctionArgs.map(({ value }) => value),\n ...parseAttributeTokens(tokens, stringLiteralPlaceholders)\n };\n}\n\n/**\n * Creates a condition node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The condition node JSON definition.\n */\nfunction createConditionNode(\n tokens: string[],\n stringLiteralPlaceholders: StringLiteralPlaceholders\n): ConditionNodeDefinition {\n // Parse any node arguments, we should have at least one which will be an identifier argument for the condition name\n // and agent function to invoke for the condition, all other arguments are to be passed as arguments to that function.\n const [conditionNameIdentifier, ...agentFunctionArgs] = parseArgumentTokens(tokens, stringLiteralPlaceholders);\n\n // Our first argument MUST be defined and be an identifier as we require a condition name argument.\n if (conditionNameIdentifier?.type !== \"identifier\") {\n throw new Error(\"expected condition name identifier argument\");\n }\n\n // Only the first argument should have been an identifier, all agent function arguments must be string, number, boolean or null.\n agentFunctionArgs\n .filter((arg) => arg.type === \"identifier\")\n .forEach((arg) => {\n throw new Error(\n `invalid condition node argument value '${arg.value}', must be string, number, boolean or null`\n );\n });\n\n // Return the condition node definition.\n return {\n type: \"condition\",\n call: conditionNameIdentifier.value,\n args: agentFunctionArgs.map(({ value }) => value),\n ...parseAttributeTokens(tokens, stringLiteralPlaceholders)\n };\n}\n\n/**\n * Creates a wait node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The wait node JSON definition.\n */\nfunction createWaitNode(tokens: string[], stringLiteralPlaceholders: StringLiteralPlaceholders): WaitNodeDefinition {\n let node = { type: \"wait\" } as WaitNodeDefinition;\n\n // Get the node arguments.\n const nodeArguments = parseArgumentTokens(tokens, stringLiteralPlaceholders);\n\n // The arguments of a wait node are optional. We may have:\n // - No node arguments, in which case the wait will be indefinite until it is aborted.\n // - One node argument which will be the explicit duration of the wait.\n // - Two node arguments which define the min and max duration bounds from which a random duration will be picked.\n if (nodeArguments.length) {\n // All wait node arguments MUST be of type number and must be integer.\n nodeArguments\n .filter((arg) => arg.type !== \"number\" || !arg.isInteger)\n .forEach(() => {\n throw new Error(`wait node durations must be integer values`);\n });\n\n // We may have:\n // - One node argument which will be the explicit duration of the wait.\n // - Two node arguments which define the min and max duration bounds from which a random duration will be picked.\n // - Too many arguments, which is not valid.\n if (nodeArguments.length === 1) {\n // An explicit duration was defined.\n node.duration = nodeArguments[0].value as number;\n\n // If an explict duration was defined then it must be a positive number.\n if (node.duration < 0) {\n throw new Error(\"a wait node must have a positive duration\");\n }\n } else if (nodeArguments.length === 2) {\n // Min and max duration bounds were defined from which a random duration will be picked.\n node.duration = [nodeArguments[0].value as number, nodeArguments[1].value as number];\n\n // A wait node must have a positive min and max duration.\n if (node.duration[0] < 0 || node.duration[1] < 0) {\n throw new Error(\"a wait node must have a positive minimum and maximum duration\");\n }\n\n // A wait node must not have a minimum duration that exceeds the maximum duration.\n if (node.duration[0] > node.duration[1]) {\n throw new Error(\"a wait node must not have a minimum duration that exceeds the maximum duration\");\n }\n } else if (nodeArguments.length > 2) {\n // An incorrect number of duration arguments were defined.\n throw new Error(\"invalid number of wait node duration arguments defined\");\n }\n }\n\n // Return the wait node definition.\n return { ...node, ...parseAttributeTokens(tokens, stringLiteralPlaceholders) };\n}\n\n/**\n * Creates a branch node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The branch node JSON definition.\n */\nfunction createBranchNode(\n tokens: string[],\n stringLiteralPlaceholders: StringLiteralPlaceholders\n): BranchNodeDefinition {\n // Parse any node arguments, we should have one which will be an identifier argument for the root ref.\n const nodeArguments = parseArgumentTokens(tokens, stringLiteralPlaceholders);\n\n // We should have only a single identifer argument for a branch node, which is the root ref.\n if (nodeArguments.length !== 1 || nodeArguments[0].type !== \"identifier\") {\n throw new Error(\"expected single branch name argument\");\n }\n\n // Return the branch node definition.\n return { type: \"branch\", ref: nodeArguments[0].value };\n}\n\n/**\n * Validate a fully-populated node definition that was popped off of the tree stack.\n * @param definition The popped node to validate.\n */\nfunction validatePoppedNode(definition: AnyNodeDefinition): void {\n // Decorators MUST have a child defined.\n if (isDecoratorNode(definition) && isNullOrUndefined(definition.child)) {\n throw new Error(`a ${definition.type} node must have a single child node defined`);\n }\n\n // Composites MUST have at least one child defined.\n if (isCompositeNode(definition) && !definition.children?.length) {\n throw new Error(`a ${definition.type} node must have at least a single child node defined`);\n }\n\n // We need to make sure that lotto nodes that have weights defined have a number of weights matching the number of child nodes.\n if (definition.type === \"lotto\") {\n // Check whether a 'weights' property has been defined, if it has we expect it to be an array of weights.\n if (typeof definition.weights !== \"undefined\") {\n // Check that the weights property is an array of positive integers with an element for each child node element.\n if (definition.weights.length !== definition.children.length) {\n throw new Error(\n \"expected a number of weight arguments matching the number of child nodes for lotto node\"\n );\n }\n }\n }\n}\n", "import { RootNodeDefinition } from \"./BehaviourTreeDefinition\";\nimport { flattenDefinition, isBranchNode, isInteger } from \"./BehaviourTreeDefinitionUtilities\";\nimport { convertMDSLToJSON } from \"./mdsl/MDSLDefinitionParser\";\n\n/**\n * An object representing the result of validating a tree definition.\n */\nexport type DefinitionValidationResult = {\n /**\n * A flag defining whether validation succeeded.\n */\n succeeded: boolean;\n /**\n * A string containing the error message if validation did not succeed.\n */\n errorMessage?: string;\n /**\n * The definition as json if the validation was successful, or undefined if validation did not succeed.\n */\n json?: RootNodeDefinition[];\n};\n\n/**\n * Validates the specified behaviour tree definition in the form of JSON or MDSL, not taking any globally registered subtrees into consideration.\n * @param definition The behaviour tree definition in the form of JSON or MDSL.\n * @returns An object representing the result of validating the given tree definition.\n */\nexport function validateDefinition(definition: any): DefinitionValidationResult {\n // The definition must be defined.\n if (definition === null || typeof definition === \"undefined\") {\n return createValidationFailureResult(\"definition is null or undefined\");\n }\n\n // We are expecting a definition in one of three different forms:\n // - A string which we will assume is MDSL and we will parse this to JSON before validation.\n // - An array which we will assume is an array of root node definitions with at least one being the primary root node (no 'id' property)\n // - An object which we will assume is the primary root node and should not have an 'id' property.\n if (typeof definition === \"string\") {\n // The definition is a string which we can assume is MDSL, so attempt to validate it.\n return validateMDSLDefinition(definition);\n } else if (typeof definition === \"object\") {\n // The definition will either be an array (of root node definitions) or an object (the single primary root node definition).\n return validateJSONDefinition(definition);\n } else {\n return createValidationFailureResult(`unexpected definition type of '${typeof definition}'`);\n }\n}\n\n/**\n * Validates the specified behaviour tree definition in the form of MDSL.\n * @param definition The behaviour tree definition in the form of MDSL.\n * @returns An object representing the result of validating the given tree definition.\n */\nfunction validateMDSLDefinition(definition: string): DefinitionValidationResult {\n let rootNodeDefinitions;\n\n // The first thing the we need to do is to attempt to convert our MDSL into JSON.\n try {\n // The definition is a string which we can assume is MDSL, so attempt to parse it to a JSON definition in the form of an array of root node definitions.\n rootNodeDefinitions = convertMDSLToJSON(definition);\n } catch (exception) {\n // We failed to parse the JSON from the MDSL, this is likely to be the result of it not being a valid MDSL string.\n return createValidationFailureResult((exception as Error).message);\n }\n\n // Unpack all of the root node definitions into arrays of main ('id' defined) and sub ('id' not defined) root node definitions.\n const mainRootNodeDefinitions = rootNodeDefinitions.filter(({ id }) => typeof id === \"undefined\");\n const subRootNodeDefinitions = rootNodeDefinitions.filter(({ id }) => typeof id === \"string\" && id.length > 0);\n\n // We should ALWAYS have exactly one root node definition without an 'id' property defined, which is out main root node definition.\n if (mainRootNodeDefinitions.length !== 1) {\n return createValidationFailureResult(\n \"expected single unnamed root node at base of definition to act as main root\"\n );\n }\n\n // We should never have duplicate 'id' properties across our sub root node definitions.\n const subRootNodeIdenitifers: string[] = [];\n for (const { id } of subRootNodeDefinitions) {\n // Have we already come across this 'id' property value?\n if (subRootNodeIdenitifers.includes(id!)) {\n return createValidationFailureResult(`multiple root nodes found with duplicate name '${id}'`);\n }\n\n subRootNodeIdenitifers.push(id!);\n }\n\n try {\n // Validate our branch -> subtree links and check for any circular dependencies, we don't care about checking for broken subtree links here.\n validateBranchSubtreeLinks(rootNodeDefinitions, false);\n } catch (exception) {\n return createValidationFailureResult((exception as Error).message);\n }\n\n // Our definition was valid!\n return {\n succeeded: true,\n json: rootNodeDefinitions\n };\n}\n\n/**\n * Validates the specified behaviour tree definition in the form of JSON.\n * @param definition The behaviour tree definition in the form of JSON.\n * @returns An object representing the result of validating the given tree definition.\n */\nexport function validateJSONDefinition(\n definition: RootNodeDefinition | RootNodeDefinition[]\n): DefinitionValidationResult {\n // The definition will either be an array (of root node definitions) or an object (the single primary root node definition).\n const rootNodeDefinitions = Array.isArray(definition) ? definition : [definition];\n\n // Iterate over our array of root nodes and call validateNode for each, passing an initial depth of 0, wrapped in a try catch to handle validation failures.\n try {\n rootNodeDefinitions.forEach((rootNodeDefinition) => validateNode(rootNodeDefinition, 0));\n } catch (error) {\n // Handle cases where we have caught a thrown Error and return a failure result with the error message.\n if (error instanceof Error) {\n return createValidationFailureResult(error.message);\n }\n\n // No idea what happened here!\n return createValidationFailureResult(`unexpected error: ${error}`);\n }\n\n // Unpack all of the root node definitions into arrays of main ('id' defined) and sub ('id' not defined) root node definitions.\n const mainRootNodeDefinitions = rootNodeDefinitions.filter(({ id }) => typeof id === \"undefined\");\n const subRootNodeDefinitions = rootNodeDefinitions.filter(({ id }) => typeof id === \"string\" && id.length > 0);\n\n // We should ALWAYS have exactly one root node definition without an 'id' property defined, which is out main root node definition.\n if (mainRootNodeDefinitions.length !== 1) {\n return createValidationFailureResult(\n \"expected single root node without 'id' property defined to act as main root\"\n );\n }\n\n // We should never have duplicate 'id' properties across our sub root node definitions.\n const subRootNodeIdenitifers: string[] = [];\n for (const { id } of subRootNodeDefinitions) {\n // Have we already come across this 'id' property value?\n if (subRootNodeIdenitifers.includes(id!)) {\n return createValidationFailureResult(\n `multiple root nodes found with duplicate 'id' property value of '${id}'`\n );\n }\n\n subRootNodeIdenitifers.push(id!);\n }\n\n try {\n // Validate our branch -> subtree links and check for any circular dependencies, we don't care about checking for broken subtree links here.\n validateBranchSubtreeLinks(rootNodeDefinitions, false);\n } catch (exception) {\n return createValidationFailureResult((exception as Error).message);\n }\n\n // Our definition was valid!\n return {\n succeeded: true,\n json: rootNodeDefinitions\n };\n}\n\n/**\n * Validates the branch -> subtree links across all provided root node definitions.\n * This will not consider branch nodes that reference any globally registered subtrees unless includesGlobalSubtrees\n * is set to true, in which case we will also verify that there are no broken branch -> subtree links.\n * @param rootNodeDefinitions The array of root node definitions.\n * @param includesGlobalSubtrees A flag defining whether the array includes all global subtree root node definitions.\n */\nexport function validateBranchSubtreeLinks(rootNodeDefinitions: RootNodeDefinition[], includesGlobalSubtrees: boolean) {\n // Create a mapping of root node identifiers to other root nodes that they reference via branch nodes.\n // Below is an example of a mapping that includes a circular dependency (root => a => b => c => a)\n // [{ refs: [\"a\", \"b\"] }, { id: \"a\", refs: [\"b\"] }, { id: \"b\", refs: [\"c\"] }, { id: \"c\", refs: [\"a\"] }]\n const rootNodeMappings: { id: string | undefined; refs: string[] }[] = rootNodeDefinitions.map(\n (rootNodeDefinition) => ({\n id: rootNodeDefinition.id,\n refs: flattenDefinition(rootNodeDefinition)\n .filter(isBranchNode)\n .map(({ ref }) => ref)\n })\n );\n\n // A recursive function to walk through the mappings, keeping track of which root nodes we have visited in the form of a path of root node identifiers.\n const followRefs = (mapping: { id: string | undefined; refs: string[] }, path: (string | undefined)[] = []) => {\n // Have we found a circular dependency?\n if (path.includes(mapping.id)) {\n // We found a circular dependency! Get the bad path of root node identifiers.\n const badPath = [...path, mapping.id];\n\n // Create the formatted path value. [undefined, \"a\", \"b\", \"c\", \"a\"] would be formatted as \"a -> b -> c -> a\".\n const badPathFormatted = badPath.filter((element) => !!element).join(\" => \");\n\n // No need to continue, we found a circular dependency.\n throw new Error(`circular dependency found in branch node references: ${badPathFormatted}`);\n }\n\n for (const ref of mapping.refs) {\n // Find the mapping for the root node with an identifer matching the current ref.\n const subMapping = rootNodeMappings.find(({ id }) => id === ref);\n\n // We may not have a mapping for this ref, which is normal when we aren't considering all globally registered subtrees.\n if (subMapping) {\n followRefs(subMapping, [...path, mapping.id]);\n } else if (includesGlobalSubtrees) {\n // We found a reference to a root node that doesn't exist, which is a problem seeing as the root node definitons includes all globally registered subtrees.\n throw new Error(\n mapping.id\n ? `subtree '${mapping.id}' has branch node that references root node '${ref}' which has not been defined`\n : `primary tree has branch node that references root node '${ref}' which has not been defined`\n );\n }\n }\n };\n\n // Start looking for circular dependencies and broken references from the primary root node definition.\n followRefs(rootNodeMappings.find((mapping) => typeof mapping.id === \"undefined\")!);\n}\n\n/**\n * Validate an object that we expect to be a node definition.\n * @param definition An object that we expect to be a node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateNode(definition: any, depth: number): void {\n // Every node must be valid object and have a non-empty 'type' string property.\n if (typeof definition !== \"object\" || typeof definition.type !== \"string\" || definition.type.length === 0) {\n throw new Error(\n `node definition is not an object or 'type' property is not a non-empty string at depth '${depth}'`\n );\n }\n\n // How we validate this node definition will depend on its type.\n switch (definition.type) {\n case \"action\":\n validateActionNode(definition, depth);\n break;\n\n case \"condition\":\n validateConditionNode(definition, depth);\n break;\n\n case \"wait\":\n validateWaitNode(definition, depth);\n break;\n\n case \"branch\":\n validateBranchNode(definition, depth);\n break;\n\n case \"root\":\n validateRootNode(definition, depth);\n break;\n\n case \"succeed\":\n validateSucceedNode(definition, depth);\n break;\n\n case \"fail\":\n validateFailNode(definition, depth);\n break;\n\n case \"flip\":\n validateFlipNode(definition, depth);\n break;\n\n case \"repeat\":\n validateRepeatNode(definition, depth);\n break;\n\n case \"retry\":\n validateRetryNode(definition, depth);\n break;\n\n case \"sequence\":\n validateSequenceNode(definition, depth);\n break;\n\n case \"selector\":\n validateSelectorNode(definition, depth);\n break;\n\n case \"parallel\":\n validateParallelNode(definition, depth);\n break;\n\n case \"lotto\":\n validateLottoNode(definition, depth);\n break;\n\n default:\n throw new Error(`unexpected node type of '${definition.type}' at depth '${depth}'`);\n }\n}\n\n/**\n * Validate any attributes for a given node definition.\n * @param definition The node definition.\n * @param depth The depth of the node in the behaviour tree definition.\n */\nfunction validateNodeAttributes(definition: any, depth: number): void {\n // Validate each of the attribute types for this node.\n [\"while\", \"until\", \"entry\", \"exit\", \"step\"].forEach((attributeName) => {\n // Attempt to grab the definition for the current attribute from the node definition.\n const attributeDefinition = definition[attributeName];\n\n // All node attributes are optional, so there is nothing to do if the current attribute is not defined.\n if (typeof attributeDefinition === \"undefined\") {\n return;\n }\n\n // The attribute definition must be an object.\n if (typeof attributeDefinition !== \"object\") {\n throw new Error(\n `expected attribute '${attributeName}' to be an object for '${definition.type}' node at depth '${depth}'`\n );\n }\n\n // The 'call' property must be defined for any attribute definition.\n if (typeof attributeDefinition.call !== \"string\" || attributeDefinition.call.length === 0) {\n throw new Error(\n `expected 'call' property for attribute '${attributeName}' to be a non-empty string for '${definition.type}' node at depth '${depth}'`\n );\n }\n\n // If any node attribute arguments have been defined then they must have been defined in an array.\n if (typeof attributeDefinition.args !== \"undefined\" && !Array.isArray(attributeDefinition.args)) {\n throw new Error(\n `expected 'args' property for attribute '${attributeName}' to be an array for '${definition.type}' node at depth '${depth}'`\n );\n }\n });\n}\n\n/**\n * Validate an object that we expect to be a root node definition.\n * @param definition An object that we expect to be a root node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateRootNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"root\") {\n throw new Error(\"expected node type of 'root' for root node\");\n }\n\n // A root node cannot be the child of another node.\n if (depth > 0) {\n throw new Error(\"a root node cannot be the child of another node\");\n }\n\n // Check that, if the root node 'id' property is defined, it is a non-empty string.\n if (typeof definition.id !== \"undefined\" && (typeof definition.id !== \"string\" || definition.id.length === 0)) {\n throw new Error(\"expected non-empty string for 'id' property if defined for root node\");\n }\n\n // A root node is a decorator node, so must have a child node defined.\n if (typeof definition.child === \"undefined\") {\n throw new Error(\"expected property 'child' to be defined for root node\");\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n\n // Validate the child node of this decorator node.\n validateNode(definition.child, depth + 1);\n}\n\n/**\n * Validate an object that we expect to be a succeed node definition.\n * @param definition An object that we expect to be a succeed node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateSucceedNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"succeed\") {\n throw new Error(`expected node type of 'succeed' for succeed node at depth '${depth}'`);\n }\n\n // A succeed node is a decorator node, so must have a child node defined.\n if (typeof definition.child === \"undefined\") {\n throw new Error(`expected property 'child' to be defined for succeed node at depth '${depth}'`);\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n\n // Validate the child node of this decorator node.\n validateNode(definition.child, depth + 1);\n}\n\n/**\n * Validate an object that we expect to be a fail node definition.\n * @param definition An object that we expect to be a fail node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateFailNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"fail\") {\n throw new Error(`expected node type of 'fail' for fail node at depth '${depth}'`);\n }\n\n // A fail node is a decorator node, so must have a child node defined.\n if (typeof definition.child === \"undefined\") {\n throw new Error(`expected property 'child' to be defined for fail node at depth '${depth}'`);\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n\n // Validate the child node of this decorator node.\n validateNode(definition.child, depth + 1);\n}\n\n/**\n * Validate an object that we expect to be a flip node definition.\n * @param definition An object that we expect to be a flip node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateFlipNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"flip\") {\n throw new Error(`expected node type of 'flip' for flip node at depth '${depth}'`);\n }\n\n // A flip node is a decorator node, so must have a child node defined.\n if (typeof definition.child === \"undefined\") {\n throw new Error(`expected property 'child' to be defined for flip node at depth '${depth}'`);\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n\n // Validate the child node of this decorator node.\n validateNode(definition.child, depth + 1);\n}\n\n/**\n * Validate an object that we expect to be a repeat node definition.\n * @param definition An object that we expect to be a repeat node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateRepeatNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"repeat\") {\n throw new Error(`expected node type of 'repeat' for repeat node at depth '${depth}'`);\n }\n\n // A repeat node is a decorator node, so must have a child node defined.\n if (typeof definition.child === \"undefined\") {\n throw new Error(`expected property 'child' to be defined for repeat node at depth '${depth}'`);\n }\n\n // Check whether an 'iterations' property has been defined, it may not have been if this node is to repeat indefinitely.\n if (typeof definition.iterations !== \"undefined\") {\n if (Array.isArray(definition.iterations)) {\n // Check whether any elements of the array are not integer values.\n const containsNonInteger = !!definition.iterations.filter((value: unknown) => !isInteger(value)).length;\n\n // If the 'iterations' property is an array then it MUST contain two integer values.\n if (definition.iterations.length !== 2 || containsNonInteger) {\n throw new Error(\n `expected array containing two integer values for 'iterations' property if defined for repeat node at depth '${depth}'`\n );\n }\n\n // A repeat node must have a positive min and max iterations count if they are defined.\n if (definition.iterations[0] < 0 || definition.iterations[1] < 0) {\n throw new Error(\n `expected positive minimum and maximum iterations count for 'iterations' property if defined for repeat node at depth '${depth}'`\n );\n }\n\n // A repeat node must not have a minimum iterations count that exceeds the maximum iterations count.\n if (definition.iterations[0] > definition.iterations[1]) {\n throw new Error(\n `expected minimum iterations count that does not exceed the maximum iterations count for 'iterations' property if defined for repeat node at depth '${depth}'`\n );\n }\n } else if (isInteger(definition.iterations)) {\n // A repeat node must have a positive number of iterations if defined.\n if (definition.iterations < 0) {\n throw new Error(\n `expected positive iterations count for 'iterations' property if defined for repeat node at depth '${depth}'`\n );\n }\n } else {\n throw new Error(\n `expected integer value or array containing two integer values for 'iterations' property if defined for repeat node at depth '${depth}'`\n );\n }\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n\n // Validate the child node of this decorator node.\n validateNode(definition.child, depth + 1);\n}\n\n/**\n * Validate an object that we expect to be a retry node definition.\n * @param definition An object that we expect to be a retry node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateRetryNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"retry\") {\n throw new Error(`expected node type of 'retry' for retry node at depth '${depth}'`);\n }\n\n // A retry node is a decorator node, so must have a child node defined.\n if (typeof definition.child === \"undefined\") {\n throw new Error(`expected property 'child' to be defined for retry node at depth '${depth}'`);\n }\n\n // Check whether an 'attempts' property has been defined, it may not have been if this node is to retry indefinitely.\n if (typeof definition.attempts !== \"undefined\") {\n if (Array.isArray(definition.attempts)) {\n // Check whether any elements of the array are not integer values.\n const containsNonInteger = !!definition.attempts.filter((value: unknown) => !isInteger(value)).length;\n\n // If the 'attempts' property is an array then it MUST contain two integer values.\n if (definition.attempts.length !== 2 || containsNonInteger) {\n throw new Error(\n `expected array containing two integer values for 'attempts' property if defined for retry node at depth '${depth}'`\n );\n }\n\n // A retry node must have a positive min and max attempts count if they are defined.\n if (definition.attempts[0] < 0 || definition.attempts[1] < 0) {\n throw new Error(\n `expected positive minimum and maximum attempts count for 'attempts' property if defined for retry node at depth '${depth}'`\n );\n }\n\n // A retry node must not have a minimum attempts count that exceeds the maximum attempts count.\n if (definition.attempts[0] > definition.attempts[1]) {\n throw new Error(\n `expected minimum attempts count that does not exceed the maximum attempts count for 'attempts' property if defined for retry node at depth '${depth}'`\n );\n }\n } else if (isInteger(definition.attempts)) {\n // A retry node must have a positive number of attempts if defined.\n if (definition.attempts < 0) {\n throw new Error(\n `expected positive attempts count for 'attempts' property if defined for retry node at depth '${depth}'`\n );\n }\n } else {\n throw new Error(\n `expected integer value or array containing two integer values for 'attempts' property if defined for retry node at depth '${depth}'`\n );\n }\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n\n // Validate the child node of this decorator node.\n validateNode(definition.child, depth + 1);\n}\n\n/**\n * Validate an object that we expect to be a branch node definition.\n * @param definition An object that we expect to be a branch node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateBranchNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"branch\") {\n throw new Error(`expected node type of 'branch' for branch node at depth '${depth}'`);\n }\n\n // Check that the branch node 'ref' property is defined and is a non-empty string.\n if (typeof definition.ref !== \"string\" || definition.ref.length === 0) {\n throw new Error(`expected non-empty string for 'ref' property for branch node at depth '${depth}'`);\n }\n\n // It is invalid to define guard attributes for a branch node as they should be defined on the referenced root node.\n [\"while\", \"until\"].forEach((attributeName) => {\n if (typeof definition[attributeName] !== \"undefined\") {\n throw new Error(\n `guards should not be defined for branch nodes but guard '${attributeName}' was defined for branch node at depth '${depth}'`\n );\n }\n });\n\n // It is invalid to define callback attributes for a branch node as they should be defined on the referenced root node.\n [\"entry\", \"exit\", \"step\"].forEach((attributeName) => {\n if (typeof definition[attributeName] !== \"undefined\") {\n throw new Error(\n `callbacks should not be defined for branch nodes but callback '${attributeName}' was defined for branch node at depth '${depth}'`\n );\n }\n });\n}\n\n/**\n * Validate an object that we expect to be a action node definition.\n * @param definition An object that we expect to be a action node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateActionNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"action\") {\n throw new Error(`expected node type of 'action' for action node at depth '${depth}'`);\n }\n\n // The 'call' property must be defined for a action node definition.\n if (typeof definition.call !== \"string\" || definition.call.length === 0) {\n throw new Error(`expected non-empty string for 'call' property of action node at depth '${depth}'`);\n }\n\n // If any action function arguments have been defined then they must have been defined in an array.\n if (typeof definition.args !== \"undefined\" && !Array.isArray(definition.args)) {\n throw new Error(`expected array for 'args' property if defined for action node at depth '${depth}'`);\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n}\n\n/**\n * Validate an object that we expect to be a condition node definition.\n * @param definition An object that we expect to be a condition node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateConditionNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"condition\") {\n throw new Error(`expected node type of 'condition' for condition node at depth '${depth}'`);\n }\n\n // The 'call' property must be defined for a condition node definition.\n if (typeof definition.call !== \"string\" || definition.call.length === 0) {\n throw new Error(`expected non-empty string for 'call' property of condition node at depth '${depth}'`);\n }\n\n // If any condition function arguments have been defined then they must have been defined in an array.\n if (typeof definition.args !== \"undefined\" && !Array.isArray(definition.args)) {\n throw new Error(`expected array for 'args' property if defined for condition node at depth '${depth}'`);\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n}\n\n/**\n * Validate an object that we expect to be a wait node definition.\n * @param definition An object that we expect to be a wait node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateWaitNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"wait\") {\n throw new Error(`expected node type of 'wait' for wait node at depth '${depth}'`);\n }\n\n // Check whether a 'duration' property has been defined, it may not have been if this node is to wait indefinitely.\n if (typeof definition.duration !== \"undefined\") {\n if (Array.isArray(definition.duration)) {\n // Check whether any elements of the array are not integer values.\n const containsNonInteger = !!definition.duration.filter((value: unknown) => !isInteger(value)).length;\n\n // If the 'duration' property is an array then it MUST contain two integer values.\n if (definition.duration.length !== 2 || containsNonInteger) {\n throw new Error(\n `expected array containing two integer values for 'duration' property if defined for wait node at depth '${depth}'`\n );\n }\n\n // A wait node must have a positive min and max duration value if they are defined.\n if (definition.duration[0] < 0 || definition.duration[1] < 0) {\n throw new Error(\n `expected positive minimum and maximum duration for 'duration' property if defined for wait node at depth '${depth}'`\n );\n }\n\n // A wait node must not have a minimum duration value that exceeds the maximum duration value.\n if (definition.duration[0] > definition.duration[1]) {\n throw new Error(\n `expected minimum duration value that does not exceed the maximum duration value for 'duration' property if defined for wait node at depth '${depth}'`\n );\n }\n } else if (isInteger(definition.duration)) {\n // A wait node must have a positive duration value if defined.\n if (definition.duration < 0) {\n throw new Error(\n `expected positive duration value for 'duration' property if defined for wait node at depth '${depth}'`\n );\n }\n } else {\n throw new Error(\n `expected integer value or array containing two integer values for 'duration' property if defined for wait node at depth '${depth}'`\n );\n }\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n}\n\n/**\n * Validate an object that we expect to be a sequence node definition.\n * @param definition An object that we expect to be a sequence node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateSequenceNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"sequence\") {\n throw new Error(`expected node type of 'sequence' for sequence node at depth '${depth}'`);\n }\n\n // A sequence node is a composite node, so must have a children nodes array defined.\n if (!Array.isArray(definition.children) || definition.children.length === 0) {\n throw new Error(`expected non-empty 'children' array to be defined for sequence node at depth '${depth}'`);\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n\n // Validate the child nodes of this composite node.\n definition.children.forEach((child: any) => validateNode(child, depth + 1));\n}\n\n/**\n * Validate an object that we expect to be a selector node definition.\n * @param definition An object that we expect to be a selector node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateSelectorNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"selector\") {\n throw new Error(`expected node type of 'selector' for selector node at depth '${depth}'`);\n }\n\n // A selector node is a composite node, so must have a children nodes array defined.\n if (!Array.isArray(definition.children) || definition.children.length === 0) {\n throw new Error(`expected non-empty 'children' array to be defined for selector node at depth '${depth}'`);\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n\n // Validate the child nodes of this composite node.\n definition.children.forEach((child: any) => validateNode(child, depth + 1));\n}\n\n/**\n * Validate an object that we expect to be a parallel node definition.\n * @param definition An object that we expect to be a parallel node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateParallelNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"parallel\") {\n throw new Error(`expected node type of 'parallel' for parallel node at depth '${depth}'`);\n }\n\n // A parallel node is a composite node, so must have a children nodes array defined.\n if (!Array.isArray(definition.children) || definition.children.length === 0) {\n throw new Error(`expected non-empty 'children' array to be defined for parallel node at depth '${depth}'`);\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n\n // Validate the child nodes of this composite node.\n definition.children.forEach((child: any) => validateNode(child, depth + 1));\n}\n\n/**\n * Validate an object that we expect to be a lotto node definition.\n * @param definition An object that we expect to be a lotto node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateLottoNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"lotto\") {\n throw new Error(`expected node type of 'lotto' for lotto node at depth '${depth}'`);\n }\n\n // A lotto node is a composite node, so must have a children nodes array defined.\n if (!Array.isArray(definition.children) || definition.children.length === 0) {\n throw new Error(`expected non-empty 'children' array to be defined for lotto node at depth '${depth}'`);\n }\n\n // Check whether a 'weights' property has been defined, if it has we expect it to be an array of weights.\n if (typeof definition.weights !== \"undefined\") {\n // Check that the weights property is an array of positive integers with an element for each child node element.\n if (\n !Array.isArray(definition.weights) ||\n definition.weights.length !== definition.children.length ||\n definition.weights.filter((value: unknown) => !isInteger(value)).length ||\n definition.weights.filter((value: number) => value < 0).length\n ) {\n throw new Error(\n `expected an array of positive integer weight values with a length matching the number of child nodes for 'weights' property if defined for lotto node at depth '${depth}'`\n );\n }\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n\n // Validate the child nodes of this composite node.\n definition.children.forEach((child: any) => validateNode(child, depth + 1));\n}\n\n/**\n * A helper function to create a failure validation result with the given error message.\n * @param errorMessage The validation failure error message.\n * @returns A failure validation result with the given error message.\n */\nfunction createValidationFailureResult(errorMessage: string): DefinitionValidationResult {\n return { succeeded: false, errorMessage };\n}\n", "import { ActionResult, Agent, GlobalFunction } from \"./Agent\";\nimport { RootNodeDefinition } from \"./BehaviourTreeDefinition\";\n\nexport type InvokerFunction = (args: any[]) => ActionResult | boolean;\n\n/**\n * A singleton used to store and lookup registered functions and subtrees.\n */\nexport default class Lookup {\n /**\n * The object holding any registered functions keyed on function name.\n */\n private static registeredFunctions: { [key: string]: GlobalFunction } = {};\n /**\n * The object holding any registered subtree root node definitions keyed on tree name.\n */\n private static registeredSubtrees: { [key: string]: RootNodeDefinition } = {};\n\n /**\n * Gets the function with the specified name.\n * @param name The name of the function.\n * @returns The function with the specified name.\n */\n public static getFunc(name: string): GlobalFunction {\n return this.registeredFunctions[name];\n }\n\n /**\n * Sets the function with the specified name for later lookup.\n * @param name The name of the function.\n * @param func The function.\n */\n public static setFunc(name: string, func: GlobalFunction): void {\n this.registeredFunctions[name] = func;\n }\n\n /**\n * Gets the function invoker for the specified agent and function name.\n * If a function with the specified name exists on the agent object then it will\n * be returned, otherwise we will then check the registered functions for a match.\n * @param agent The agent instance that this behaviour tree is modelling behaviour for.\n * @param name The function name.\n * @returns The function invoker for the specified agent and function name.\n */\n static getFuncInvoker(agent: Agent, name: string): InvokerFunction | null {\n // Check whether the agent contains the specified function.\n const agentFunction = agent[name];\n if (agentFunction && typeof agentFunction === \"function\") {\n return (args: any[]) => agentFunction.apply(agent, args);\n }\n\n // The agent does not contain the specified function but it may have been registered at some point.\n if (this.registeredFunctions[name] && typeof this.registeredFunctions[name] === \"function\") {\n const registeredFunction = this.registeredFunctions[name];\n return (args: any[]) => registeredFunction(agent, ...args.map((arg) => arg.value));\n }\n\n // We have no function to invoke.\n return null;\n }\n\n /**\n * Gets all registered subtree root node definitions.\n */\n static getSubtrees(): { [key: string]: RootNodeDefinition } {\n return this.registeredSubtrees;\n }\n\n /**\n * Sets the subtree with the specified name for later lookup.\n * @param name The name of the subtree.\n * @param subtree The subtree.\n */\n static setSubtree(name: string, subtree: RootNodeDefinition) {\n this.registeredSubtrees[name] = subtree;\n }\n\n /**\n * Removes the registered function or subtree with the specified name.\n * @param name The name of the registered function or subtree.\n */\n static remove(name: string) {\n delete this.registeredFunctions[name];\n delete this.registeredSubtrees[name];\n }\n\n /**\n * Remove all registered functions and subtrees.\n */\n static empty() {\n this.registeredFunctions = {};\n this.registeredSubtrees = {};\n }\n}\n", "import Node from \"../../nodes/Node\";\n\n/**\n * An exception thrown when evaluating node guard path conditions and a conditions fails.\n */\nexport default class GuardUnsatisifedException extends Error {\n /**\n * @param source The node at which a guard condition failed.\n */\n constructor(private source: Node) {\n super(\"A guard path condition has failed\");\n }\n\n /**\n * Gets whether the specified node is the node at which a guard condition failed.\n * @param node The node to check against the source node.\n * @returns Whether the specified node is the node at which a guard condition failed.\n */\n isSourceNode = (node: Node) => node === this.source;\n}\n", "import { Agent } from \"../../Agent\";\nimport Guard from \"./Guard\";\nimport Node from \"../../nodes/Node\";\nimport GuardUnsatisifedException from \"./GuardUnsatisifedException\";\n\nexport type GuardPathPart = {\n node: Node;\n guards: Guard[];\n};\n\n/**\n * Represents a path of node guards along a root-to-leaf tree path.\n */\nexport default class GuardPath {\n /**\n * @param nodes An array of objects defining a node instance -> guard link, ordered by node depth.\n */\n constructor(private nodes: GuardPathPart[]) {}\n\n /**\n * Evaluate guard conditions for all guards in the tree path, moving outwards from the root.\n * @param agent The agent, required for guard evaluation.\n * @returns An evaluation results object.\n */\n evaluate = (agent: Agent) => {\n // We need to evaluate guard conditions for nodes up the tree, moving outwards from the root.\n for (const details of this.nodes) {\n // There can be multiple guards per node.\n for (const guard of details.guards) {\n // Check whether the guard condition passes, and throw an exception if not.\n if (!guard.isSatisfied(agent)) {\n throw new GuardUnsatisifedException(details.node);\n }\n }\n }\n };\n}\n", "import { BehaviourTreeOptions } from \"../BehaviourTreeOptions\";\nimport State, { AnyState } from \"../State\";\nimport { Agent } from \"../Agent\";\nimport Leaf from \"./leaf/Leaf\";\nimport Attribute from \"../attributes/Attribute\";\nimport Entry from \"../attributes/callbacks/Entry\";\nimport Exit from \"../attributes/callbacks/Exit\";\nimport Step from \"../attributes/callbacks/Step\";\nimport Guard from \"../attributes/guards/Guard\";\nimport GuardPath from \"../attributes/guards/GuardPath\";\nimport GuardUnsatisifedException from \"../attributes/guards/GuardUnsatisifedException\";\n\n/**\n * A base node.\n */\nexport default abstract class Node {\n /**\n * The node uid.\n */\n private readonly uid: string = createNodeUid();\n /**\n * The node state.\n */\n private state: AnyState = State.READY;\n /**\n * The guard path to evaluate as part of a node update.\n */\n private guardPath: GuardPath | undefined;\n\n /**\n * @param type The node type.\n * @param attributes The node attributes.\n * @param args The node argument definitions.\n */\n constructor(private type: string, private attributes: Attribute[], private args: any[]) {}\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected abstract onUpdate(agent: Agent, options: BehaviourTreeOptions): void;\n\n /**\n * Gets the name of the node.\n */\n public abstract getName(): string;\n\n /**\n * Gets whether this node is a leaf node.\n */\n public abstract isLeafNode: () => this is Leaf;\n\n /**\n * Gets/Sets the state of the node.\n */\n getState = (): AnyState => this.state;\n setState = (value: AnyState): void => {\n this.state = value;\n };\n\n /**\n * Gets the unique id of the node.\n */\n getUid = () => this.uid;\n\n /**\n * Gets the type of the node.\n */\n getType = () => this.type;\n\n /**\n * Gets the node attributes.\n */\n getAttributes = () => this.attributes;\n\n /**\n * Gets the node arguments.\n */\n getArguments = () => this.args;\n\n /**\n * Gets the node attribute with the specified type, or null if it does not exist.\n */\n getAttribute(type: \"entry\" | \"ENTRY\"): Entry;\n getAttribute(type: \"exit\" | \"EXIT\"): Exit;\n getAttribute(type: \"step\" | \"STEP\"): Step;\n getAttribute(type: string): Attribute {\n return (\n this.getAttributes().filter((decorator) => decorator.type.toUpperCase() === type.toUpperCase())[0] || null\n );\n }\n\n /**\n * Gets the node attributes.\n */\n getGuardAttributes = (): Guard[] => this.getAttributes().filter((decorator) => decorator.isGuard()) as Guard[];\n\n /**\n * Sets the guard path to evaluate as part of a node update.\n */\n setGuardPath = (value: GuardPath) => (this.guardPath = value);\n\n /**\n * Gets whether a guard path is assigned to this node.\n */\n hasGuardPath = () => !!this.guardPath;\n\n /**\n * Gets whether this node is in the specified state.\n * @param value The value to compare to the node state.\n */\n public is(value: AnyState): boolean {\n return this.state === value;\n }\n\n /**\n * Reset the state of the node.\n */\n public reset(): void {\n this.setState(State.READY);\n }\n\n /**\n * Abort the running of this node.\n * @param agent The agent.\n */\n public abort(agent: Agent): void {\n // There is nothing to do if this node is not in the running state.\n if (!this.is(State.RUNNING)) {\n return;\n }\n\n // Reset the state of this node.\n this.reset();\n\n this.getAttribute(\"exit\")?.callAgentFunction(agent, false, true);\n }\n\n /**\n * Update the node.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n * @returns The result of the update.\n */\n public update(agent: Agent, options: BehaviourTreeOptions): void {\n // If this node is already in a 'SUCCEEDED' or 'FAILED' state then there is nothing to do.\n if (this.is(State.SUCCEEDED) || this.is(State.FAILED)) {\n return;\n }\n\n try {\n // Evaluate all of the guard path conditions for the current tree path.\n this.guardPath!.evaluate(agent);\n\n // If this node is in the READY state then call the ENTRY for this node if it exists.\n if (this.is(State.READY)) {\n this.getAttribute(\"entry\")?.callAgentFunction(agent);\n }\n\n this.getAttribute(\"step\")?.callAgentFunction(agent);\n\n // Do the actual update.\n this.onUpdate(agent, options);\n\n // If this node is now in a 'SUCCEEDED' or 'FAILED' state then call the EXIT for this node if it exists.\n if (this.is(State.SUCCEEDED) || this.is(State.FAILED)) {\n this.getAttribute(\"exit\")?.callAgentFunction(agent, this.is(State.SUCCEEDED), false);\n }\n } catch (error) {\n // If the error is a GuardUnsatisfiedException then we need to determine if this node is the source.\n if (error instanceof GuardUnsatisifedException && error.isSourceNode(this)) {\n // Abort the current node.\n this.abort(agent);\n\n // Any node that is the source of an abort will be a failed node.\n this.setState(State.FAILED);\n } else {\n throw error;\n }\n }\n }\n}\n\n/**\n * Create a randomly generated node uid.\n * @returns A randomly generated node uid.\n */\nfunction createNodeUid(): string {\n var S4 = function () {\n return (((1 + Math.random()) * 0x10000) | 0).toString(16).substring(1);\n };\n return S4() + S4() + \"-\" + S4() + \"-\" + S4() + \"-\" + S4() + \"-\" + S4() + S4() + S4();\n}\n", "import Node from \"../Node\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\n\n/**\n * A composite node that wraps child nodes.\n */\nexport default abstract class Composite extends Node {\n /**\n * @param type The node type.\n * @param attributes The node attributes.\n * @param children The child nodes.\n */\n constructor(type: string, attributes: Attribute[], protected children: Node[]) {\n super(type, attributes, []);\n }\n\n /**\n * Gets whether this node is a leaf node.\n */\n isLeafNode = () => false;\n\n /**\n * Gets the children of this node.\n */\n getChildren = () => this.children;\n\n /**\n * Reset the state of the node.\n */\n reset = () => {\n // Reset the state of this node.\n this.setState(State.READY);\n\n // Reset the state of any child nodes.\n this.getChildren().forEach((child) => child.reset());\n };\n\n /**\n * Abort the running of this node.\n * @param agent The agent.\n */\n abort = (agent: Agent) => {\n // There is nothing to do if this node is not in the running state.\n if (!this.is(State.RUNNING)) {\n return;\n }\n\n // Abort any child nodes.\n this.getChildren().forEach((child) => child.abort(agent));\n\n // Reset the state of this node.\n this.reset();\n\n this.getAttribute(\"exit\")?.callAgentFunction(agent, false, true);\n };\n}\n", "import Composite from \"./Composite\";\nimport State from \"../../State\";\nimport Node from \"../Node\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A PARALLEL node.\n * The child nodes are executed concurrently until one fails or all succeed.\n */\nexport default class Parallel extends Composite {\n /**\n * @param attributes The node attributes.\n * @param children The child nodes.\n */\n constructor(attributes: Attribute[], children: Node[]) {\n super(\"parallel\", attributes, children);\n }\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // Keep a count of the number of succeeded child nodes.\n let succeededCount = 0;\n\n let hasChildFailed = false;\n\n // Iterate over all of the children of this node.\n for (const child of this.children) {\n // If the child has never been updated or is running then we will need to update it now.\n if (child.getState() === State.READY || child.getState() === State.RUNNING) {\n // Update the child of this node.\n child.update(agent, options);\n }\n\n // If the current child has a state of 'SUCCEEDED' then we should move on to the next child.\n if (child.getState() === State.SUCCEEDED) {\n // The child node has succeeded, keep track of this to determine if all children have.\n succeededCount++;\n\n // The child node succeeded, but we have not finished checking every child node yet.\n continue;\n }\n\n // If the current child has a state of 'FAILED' then this node is also a 'FAILED' node.\n if (child.getState() === State.FAILED) {\n hasChildFailed = true;\n\n // There is no need to check the rest of the children.\n break;\n }\n\n // The node should be in the 'RUNNING' state.\n if (child.getState() !== State.RUNNING) {\n // The child node was not in an expected state.\n throw new Error(\"child node was not in an expected state.\");\n }\n }\n\n if (hasChildFailed) {\n // This node is a 'FAILED' node.\n this.setState(State.FAILED);\n\n // Abort every running child.\n for (const child of this.children) {\n if (child.getState() === State.RUNNING) {\n child.abort(agent);\n }\n }\n } else {\n // If all children have succeeded then this node has also succeeded, otherwise it is still running.\n this.setState(succeededCount === this.children.length ? State.SUCCEEDED : State.RUNNING);\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => \"PARALLEL\";\n}\n", "import Composite from \"./Composite\";\nimport Node from \"../Node\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A SELECTOR node.\n * The child nodes are executed in sequence until one succeeds or all fail.\n */\nexport default class Selector extends Composite {\n /**\n * @param attributes The node attributes.\n * @param children The child nodes.\n */\n constructor(attributes: Attribute[], protected children: Node[]) {\n super(\"selector\", attributes, children);\n }\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // Iterate over all of the children of this node.\n for (const child of this.children) {\n // If the child has never been updated or is running then we will need to update it now.\n if (child.getState() === State.READY || child.getState() === State.RUNNING) {\n // Update the child of this node.\n child.update(agent, options);\n }\n\n // If the current child has a state of 'SUCCEEDED' then this node is also a 'SUCCEEDED' node.\n if (child.getState() === State.SUCCEEDED) {\n // This node is a 'SUCCEEDED' node.\n this.setState(State.SUCCEEDED);\n\n // There is no need to check the rest of the selector nodes.\n return;\n }\n\n // If the current child has a state of 'FAILED' then we should move on to the next child.\n if (child.getState() === State.FAILED) {\n // Find out if the current child is the last one in the selector.\n // If it is then this sequence node has also failed.\n if (this.children.indexOf(child) === this.children.length - 1) {\n // This node is a 'FAILED' node.\n this.setState(State.FAILED);\n\n // There is no need to check the rest of the selector as we have completed it.\n return;\n } else {\n // The child node failed, try the next one.\n continue;\n }\n }\n\n // The node should be in the 'RUNNING' state.\n if (child.getState() === State.RUNNING) {\n // This node is a 'RUNNING' node.\n this.setState(State.RUNNING);\n\n // There is no need to check the rest of the selector as the current child is still running.\n return;\n }\n\n // The child node was not in an expected state.\n throw new Error(\"child node was not in an expected state.\");\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => \"SELECTOR\";\n}\n", "import Composite from \"./Composite\";\nimport Node from \"../Node\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A SEQUENCE node.\n * The child nodes are executed in sequence until one fails or all succeed.\n */\nexport default class Sequence extends Composite {\n /**\n * @param attributes The node attributes.\n * @param children The child nodes.\n */\n constructor(attributes: Attribute[], protected children: Node[]) {\n super(\"sequence\", attributes, children);\n }\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // Iterate over all of the children of this node.\n for (const child of this.children) {\n // If the child has never been updated or is running then we will need to update it now.\n if (child.getState() === State.READY || child.getState() === State.RUNNING) {\n // Update the child of this node.\n child.update(agent, options);\n }\n\n // If the current child has a state of 'SUCCEEDED' then we should move on to the next child.\n if (child.getState() === State.SUCCEEDED) {\n // Find out if the current child is the last one in the sequence.\n // If it is then this sequence node has also succeeded.\n if (this.children.indexOf(child) === this.children.length - 1) {\n // This node is a 'SUCCEEDED' node.\n this.setState(State.SUCCEEDED);\n\n // There is no need to check the rest of the sequence as we have completed it.\n return;\n } else {\n // The child node succeeded, but we have not finished the sequence yet.\n continue;\n }\n }\n\n // If the current child has a state of 'FAILED' then this node is also a 'FAILED' node.\n if (child.getState() === State.FAILED) {\n // This node is a 'FAILED' node.\n this.setState(State.FAILED);\n\n // There is no need to check the rest of the sequence.\n return;\n }\n\n // The node should be in the 'RUNNING' state.\n if (child.getState() === State.RUNNING) {\n // This node is a 'RUNNING' node.\n this.setState(State.RUNNING);\n\n // There is no need to check the rest of the sequence as the current child is still running.\n return;\n }\n\n // The child node was not in an expected state.\n throw new Error(\"child node was not in an expected state.\");\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => \"SEQUENCE\";\n}\n", "import createLotto from \"lotto-draw\";\n\nimport Node from \"../Node\";\nimport Composite from \"./Composite\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A LOTTO node.\n * A winning child is picked on the initial update of this node, based on ticket weighting.\n * The state of this node will match the state of the winning child.\n */\nexport default class Lotto extends Composite {\n /**\n * @param attributes The node attributes.\n * @param weights The child node weights.\n * @param children The child nodes.\n */\n constructor(attributes: Attribute[], private weights: number[] | undefined, children: Node[]) {\n super(\"lotto\", attributes, children);\n }\n\n /**\n * The child node selected to be the active one.\n */\n private selectedChild: Node | undefined;\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // If this node is in the READY state then we need to pick a winning child node.\n if (this.is(State.READY)) {\n // Create a lotto draw with which to randomly pick a child node to become the active one.\n const lottoDraw = createLotto({\n // Hook up the optional 'random' behaviour tree function option to the one used by 'lotto-draw'.\n random: options.random,\n // Pass in each child node as a participant in the lotto draw with their respective ticket count.\n participants: this.children.map((child, index) => [child, this.weights?.[index] || 1])\n });\n\n // Randomly pick a child based on ticket weighting, this will become the active child for this composite node.\n this.selectedChild = lottoDraw.draw() || undefined;\n }\n\n // If something went wrong and we don't have an active child then we should throw an error.\n if (!this.selectedChild) {\n throw new Error(\"failed to update lotto node as it has no active child\");\n }\n\n // If the selected child has never been updated or is running then we will need to update it now.\n if (this.selectedChild.getState() === State.READY || this.selectedChild.getState() === State.RUNNING) {\n this.selectedChild.update(agent, options);\n }\n\n // The state of the lotto node is the state of its selected child.\n this.setState(this.selectedChild.getState());\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => (this.weights ? `LOTTO [${this.weights.join(\",\")}]` : \"LOTTO\");\n}\n", "import Node from \"../Node\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\n\n/**\n * A decorator node that wraps a single child node.\n */\nexport default abstract class Decorator extends Node {\n /**\n * @param type The node type.\n * @param attributes The node attributes.\n * @param child The child node.\n */\n constructor(type: string, attributes: Attribute[], protected child: Node) {\n super(type, attributes, []);\n }\n\n /**\n * Gets whether this node is a leaf node.\n */\n isLeafNode = () => false;\n\n /**\n * Gets the children of this node.\n */\n getChildren = () => [this.child];\n\n /**\n * Reset the state of the node.\n */\n reset = () => {\n // Reset the state of this node.\n this.setState(State.READY);\n\n // Reset the state of the child node.\n this.child.reset();\n };\n\n /**\n * Abort the running of this node.\n * @param agent The agent.\n */\n abort = (agent: Agent) => {\n // There is nothing to do if this node is not in the running state.\n if (!this.is(State.RUNNING)) {\n return;\n }\n\n // Abort the child node.\n this.child.abort(agent);\n\n // Reset the state of this node.\n this.reset();\n\n this.getAttribute(\"exit\")?.callAgentFunction(agent, false, true);\n };\n}\n", "import Node from \"../Node\";\nimport Decorator from \"./Decorator\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A Fail node.\n * This node wraps a single child and will always move to the 'FAILED' state when the child moves to a 'SUCCEEDED' or 'FAILED' state.\n */\nexport default class Fail extends Decorator {\n /**\n * @param attributes The node attributes.\n * @param child The child node.\n */\n constructor(attributes: Attribute[], child: Node) {\n super(\"fail\", attributes, child);\n }\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // If the child has never been updated or is running then we will need to update it now.\n if (this.child.getState() === State.READY || this.child.getState() === State.RUNNING) {\n this.child.update(agent, options);\n }\n\n // The state of this node will depend in the state of its child.\n switch (this.child.getState()) {\n case State.RUNNING:\n this.setState(State.RUNNING);\n break;\n\n case State.SUCCEEDED:\n case State.FAILED:\n this.setState(State.FAILED);\n break;\n\n default:\n this.setState(State.READY);\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => \"FAIL\";\n}\n", "import Decorator from \"./Decorator\";\nimport State from \"../../State\";\nimport Node from \"../Node\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A Flip node.\n * This node wraps a single child and will flip the state of the child state.\n */\nexport default class Flip extends Decorator {\n /**\n * @param attributes The node attributes.\n * @param child The child node.\n */\n constructor(attributes: Attribute[], child: Node) {\n super(\"flip\", attributes, child);\n }\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // If the child has never been updated or is running then we will need to update it now.\n if (this.child.getState() === State.READY || this.child.getState() === State.RUNNING) {\n this.child.update(agent, options);\n }\n\n // The state of this node will depend in the state of its child.\n switch (this.child.getState()) {\n case State.RUNNING:\n this.setState(State.RUNNING);\n break;\n\n case State.SUCCEEDED:\n this.setState(State.FAILED);\n break;\n\n case State.FAILED:\n this.setState(State.SUCCEEDED);\n break;\n\n default:\n this.setState(State.READY);\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => \"FLIP\";\n}\n", "import Node from \"../Node\";\nimport Decorator from \"./Decorator\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A REPEAT node.\n * The node has a single child which can have:\n * -- A number of iterations for which to repeat the child node.\n * -- An infinite repeat loop if neither an iteration count or a condition function is defined.\n * The REPEAT node will stop and have a 'FAILED' state if its child is ever in a 'FAILED' state after an update.\n * The REPEAT node will attempt to move on to the next iteration if its child is ever in a 'SUCCEEDED' state.\n */\nexport default class Repeat extends Decorator {\n /**\n * @param attributes The node attributes.\n * @param iterations The number of iterations to repeat the child node.\n * @param iterationsMin The minimum possible number of iterations to repeat the child node.\n * @param iterationsMax The maximum possible number of iterations to repeat the child node.\n * @param child The child node.\n */\n constructor(\n attributes: Attribute[],\n private iterations: number | null,\n private iterationsMin: number | null,\n private iterationsMax: number | null,\n child: Node\n ) {\n super(\"repeat\", attributes, child);\n }\n\n /**\n * The number of target iterations to make.\n */\n private targetIterationCount: number | null = null;\n\n /**\n * The current iteration count.\n */\n private currentIterationCount: number = 0;\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // If this node is in the READY state then we need to reset the child and the target iteration count.\n if (this.is(State.READY)) {\n // Reset the child node.\n this.child.reset();\n\n // Reset the current iteration count.\n this.currentIterationCount = 0;\n\n // Set the target iteration count.\n this.setTargetIterationCount(options);\n }\n\n // Do a check to see if we can iterate. If we can then this node will move into the 'RUNNING' state.\n // If we cannot iterate then we have hit our target iteration count, which means that the node has succeeded.\n if (this.canIterate()) {\n // This node is in the running state and can do its initial iteration.\n this.setState(State.RUNNING);\n\n // We may have already completed an iteration, meaning that the child node will be in the SUCCEEDED state.\n // If this is the case then we will have to reset the child node now.\n if (this.child.getState() === State.SUCCEEDED) {\n this.child.reset();\n }\n\n // Update the child of this node.\n this.child.update(agent, options);\n\n // If the child moved into the FAILED state when we updated it then there is nothing left to do and this node has also failed.\n // If it has moved into the SUCCEEDED state then we have completed the current iteration.\n if (this.child.getState() === State.FAILED) {\n // The child has failed, meaning that this node has failed.\n this.setState(State.FAILED);\n\n return;\n } else if (this.child.getState() === State.SUCCEEDED) {\n // We have completed an iteration.\n this.currentIterationCount += 1;\n }\n } else {\n // This node is in the 'SUCCEEDED' state as we cannot iterate any more.\n this.setState(State.SUCCEEDED);\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => {\n if (this.iterations !== null) {\n return `REPEAT ${this.iterations}x`;\n } else if (this.iterationsMin !== null && this.iterationsMax !== null) {\n return `REPEAT ${this.iterationsMin}x-${this.iterationsMax}x`;\n } else {\n return \"REPEAT\";\n }\n };\n\n /**\n * Reset the state of the node.\n */\n reset = () => {\n // Reset the state of this node.\n this.setState(State.READY);\n\n // Reset the current iteration count.\n this.currentIterationCount = 0;\n\n // Reset the child node.\n this.child.reset();\n };\n\n /**\n * Gets whether an iteration can be made.\n * @returns Whether an iteration can be made.\n */\n private canIterate = () => {\n if (this.targetIterationCount !== null) {\n // We can iterate as long as we have not reached our target iteration count.\n return this.currentIterationCount < this.targetIterationCount;\n }\n\n // If neither an iteration count or a condition function were defined then we can iterate indefinitely.\n return true;\n };\n\n /**\n * Sets the target iteration count.\n * @param options The behaviour tree options object.\n */\n private setTargetIterationCount = (options: BehaviourTreeOptions) => {\n // Are we dealing with an explicit iteration count or will we be randomly picking a iteration count between the min and max iteration count.\n if (this.iterations !== null) {\n this.targetIterationCount = this.iterations;\n } else if (this.iterationsMin !== null && this.iterationsMax !== null) {\n // We will be picking a random iteration count between a min and max iteration count, if the optional 'random'\n // behaviour tree function option is defined then we will be using that, otherwise we will fall back to using Math.random.\n const random = typeof options.random === \"function\" ? options.random : Math.random;\n\n // Pick a random iteration count between a min and max iteration count.\n this.targetIterationCount = Math.floor(\n random() * (this.iterationsMax - this.iterationsMin + 1) + this.iterationsMin\n );\n } else {\n this.targetIterationCount = null;\n }\n };\n}\n", "import Node from \"../Node\";\nimport Decorator from \"./Decorator\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A RETRY node.\n * The node has a single child which can have:\n * -- A number of iterations for which to repeat the child node.\n * -- An infinite repeat loop if neither an iteration count or a condition function is defined.\n * The RETRY node will stop and have a 'SUCCEEDED' state if its child is ever in a 'SUCCEEDED' state after an update.\n * The RETRY node will attempt to move on to the next iteration if its child is ever in a 'FAILED' state.\n */\nexport default class Retry extends Decorator {\n /**\n * @param attributes The node attributes.\n * @param attempts The number of attempts to retry the child node.\n * @param attemptsMin The minimum possible number of attempts to retry the child node.\n * @param attemptsMax The maximum possible number of attempts to retry the child node.\n * @param child The child node.\n */\n constructor(\n attributes: Attribute[],\n private attempts: number | null,\n private attemptsMin: number | null,\n private attemptsMax: number | null,\n child: Node\n ) {\n super(\"retry\", attributes, child);\n }\n\n /**\n * The number of target attempts to make.\n */\n private targetAttemptCount: number | null = null;\n\n /**\n * The current attempt count.\n */\n private currentAttemptCount: number = 0;\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // If this node is in the READY state then we need to reset the child and the target attempt count.\n if (this.is(State.READY)) {\n // Reset the child node.\n this.child.reset();\n\n // Reset the current attempt count.\n this.currentAttemptCount = 0;\n\n // Set the target attempt count.\n this.setTargetAttemptCount(options);\n }\n\n // Do a check to see if we can attempt. If we can then this node will move into the 'RUNNING' state.\n // If we cannot attempt then we have hit our target attempt count, which means that the node has succeeded.\n if (this.canAttempt()) {\n // This node is in the running state and can do its initial attempt.\n this.setState(State.RUNNING);\n\n // We may have already completed an attempt, meaning that the child node will be in the FAILED state.\n // If this is the case then we will have to reset the child node now.\n if (this.child.getState() === State.FAILED) {\n this.child.reset();\n }\n\n // Update the child of this node.\n this.child.update(agent, options);\n\n // If the child moved into the SUCCEEDED state when we updated it then there is nothing left to do and this node has also succeeded.\n // If it has moved into the FAILED state then we have completed the current attempt.\n if (this.child.getState() === State.SUCCEEDED) {\n // The child has succeeded, meaning that this node has succeeded.\n this.setState(State.SUCCEEDED);\n\n return;\n } else if (this.child.getState() === State.FAILED) {\n // We have completed an attempt.\n this.currentAttemptCount += 1;\n }\n } else {\n // This node is in the 'FAILED' state as we cannot iterate any more.\n this.setState(State.FAILED);\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => {\n if (this.attempts !== null) {\n return `RETRY ${this.attempts}x`;\n } else if (this.attemptsMin !== null && this.attemptsMax !== null) {\n return `RETRY ${this.attemptsMin}x-${this.attemptsMax}x`;\n } else {\n return \"RETRY\";\n }\n };\n\n /**\n * Reset the state of the node.\n */\n reset = () => {\n // Reset the state of this node.\n this.setState(State.READY);\n\n // Reset the current attempt count.\n this.currentAttemptCount = 0;\n\n // Reset the child node.\n this.child.reset();\n };\n\n /**\n * Gets whether an attempt can be made.\n * @returns Whether an attempt can be made.\n */\n canAttempt = () => {\n if (this.targetAttemptCount !== null) {\n // We can attempt as long as we have not reached our target attempt count.\n return this.currentAttemptCount < this.targetAttemptCount;\n }\n\n // If neither an attempt count or a condition function were defined then we can attempt indefinitely.\n return true;\n };\n\n /**\n * Sets the target attempt count.\n * @param options The behaviour tree options object.\n */\n setTargetAttemptCount = (options: BehaviourTreeOptions) => {\n // Are we dealing with an explicit attempt count or will we be randomly picking an attempt count between the min and max attempt count.\n if (this.attempts !== null) {\n this.targetAttemptCount = this.attempts;\n } else if (this.attemptsMin !== null && this.attemptsMax !== null) {\n // We will be picking a random attempt count between a min and max attempt count, if the optional 'random'\n // behaviour tree function option is defined then we will be using that, otherwise we will fall back to using Math.random.\n const random = typeof options.random === \"function\" ? options.random : Math.random;\n\n // Pick a random attempt count between a min and max attempt count.\n this.targetAttemptCount = Math.floor(\n random() * (this.attemptsMax - this.attemptsMin + 1) + this.attemptsMin\n );\n } else {\n this.targetAttemptCount = null;\n }\n };\n}\n", "import Node from \"../Node\";\nimport Decorator from \"./Decorator\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A Root node.\n * The root node will have a single child.\n */\nexport default class Root extends Decorator {\n /**\n * @param attributes The node attributes.\n * @param child The child node.\n */\n constructor(attributes: Attribute[], child: Node) {\n super(\"root\", attributes, child);\n }\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // If the child has never been updated or is running then we will need to update it now.\n if (this.child.getState() === State.READY || this.child.getState() === State.RUNNING) {\n // Update the child of this node.\n this.child.update(agent, options);\n }\n\n // The state of the root node is the state of its child.\n this.setState(this.child.getState());\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => \"ROOT\";\n}\n", "import Node from \"../Node\";\nimport Decorator from \"./Decorator\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A Succeed node.\n * This node wraps a single child and will always move to the 'SUCCEEDED' state when the child moves to a 'SUCCEEDED' or 'FAILED' state.\n */\nexport default class Succeed extends Decorator {\n /**\n * @param attributes The node attributes.\n * @param child The child node.\n */\n constructor(attributes: Attribute[], child: Node) {\n super(\"succeed\", attributes, child);\n }\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // If the child has never been updated or is running then we will need to update it now.\n if (this.child.getState() === State.READY || this.child.getState() === State.RUNNING) {\n this.child.update(agent, options);\n }\n\n // The state of this node will depend in the state of its child.\n switch (this.child.getState()) {\n case State.RUNNING:\n this.setState(State.RUNNING);\n break;\n\n case State.SUCCEEDED:\n case State.FAILED:\n this.setState(State.SUCCEEDED);\n break;\n\n default:\n this.setState(State.READY);\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => \"SUCCEED\";\n}\n", "import Node from \"../Node\";\n\n/**\n * A leaf node.\n */\nexport default abstract class Leaf extends Node {\n /**\n * Gets whether this node is a leaf node.\n */\n isLeafNode = () => true;\n}\n", "import { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\nimport State, { CompleteState } from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Leaf from \"./Leaf\";\nimport Lookup from \"../../Lookup\";\nimport Attribute from \"../../attributes/Attribute\";\n\n/**\n * The type representing a resolved/rejected update promise.\n */\ntype UpdatePromiseResult = {\n /**\n * Whether the promise was resolved rather than rejected.\n */\n isResolved: boolean;\n\n /**\n * The promise resolved value or rejection reason.\n */\n value: any;\n};\n\n/**\n * An Action leaf node.\n * This represents an immediate or ongoing state of behaviour.\n */\nexport default class Action extends Leaf {\n /**\n * @param attributes The node attributes.\n * @param actionName The action name.\n * @param actionArguments The array of action argument definitions.\n */\n constructor(attributes: Attribute[], private actionName: string, private actionArguments: any[]) {\n super(\"action\", attributes, actionArguments);\n }\n\n /**\n * Whether there is a pending update promise.\n */\n private isUsingUpdatePromise = false;\n\n /**\n * The finished state result of an update promise.\n */\n private updatePromiseResult: UpdatePromiseResult | null = null;\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // If the result of this action depends on an update promise then there is nothing to do until it settles.\n if (this.isUsingUpdatePromise) {\n // Are we still waiting for our update promise to settle?\n if (!this.updatePromiseResult) {\n return;\n }\n\n const { isResolved, value } = this.updatePromiseResult;\n\n // Our update promise settled, was it resolved or rejected?\n if (isResolved) {\n // Our promise resolved so check to make sure the result is a valid finished state.\n if (value !== State.SUCCEEDED && value !== State.FAILED) {\n throw new Error(\n \"action node promise resolved with an invalid value, expected a State.SUCCEEDED or State.FAILED value to be returned\"\n );\n }\n\n // Set the state of this node to match the state returned by the promise.\n this.setState(value);\n\n return;\n } else {\n // The promise was rejected, which isn't great.\n throw new Error(`action function '${this.actionName}' promise rejected with '${value}'`);\n }\n }\n\n // Attempt to get the invoker for the action function.\n const actionFuncInvoker = Lookup.getFuncInvoker(agent, this.actionName);\n\n // The action function should be defined.\n if (actionFuncInvoker === null) {\n throw new Error(\n `cannot update action node as the action '${this.actionName}' function is not defined on the agent and has not been registered`\n );\n }\n\n let actionFunctionResult;\n\n try {\n // Call the action function, the result of which may be:\n // - The finished state of this action node.\n // - A promise to return a finished node state.\n // - Undefined if the node should remain in the running state.\n actionFunctionResult = actionFuncInvoker(this.actionArguments) as CompleteState | Promise;\n } catch (error) {\n // The user was naughty and threw something.\n throw new Error(`action function '${this.actionName}' threw '${error}'`);\n }\n\n if (actionFunctionResult instanceof Promise) {\n actionFunctionResult.then(\n (result) => {\n // If 'isUpdatePromisePending' is not set then the promise was cleared as it was resolving, probably via an abort of reset.\n if (!this.isUsingUpdatePromise) {\n return;\n }\n\n // Set the resolved update promise result so that it can be handled on the next update of this node.\n this.updatePromiseResult = {\n isResolved: true,\n value: result\n };\n },\n (reason) => {\n // If 'isUpdatePromisePending' is not set then the promise was cleared as it was resolving, probably via an abort or reset.\n if (!this.isUsingUpdatePromise) {\n return;\n }\n\n // Set the rejected update promise result so that it can be handled on the next update of this node.\n this.updatePromiseResult = {\n isResolved: false,\n value: reason\n };\n }\n );\n\n // This node will be in the 'RUNNING' state until the update promise resolves.\n this.setState(State.RUNNING);\n\n // We are now waiting for the promise returned by the use to resolve before we know what state this node is in.\n this.isUsingUpdatePromise = true;\n } else {\n // Validate the returned value.\n this.validateUpdateResult(actionFunctionResult);\n\n // Set the state of this node, this may be undefined, which just means that the node is still in the 'RUNNING' state.\n this.setState(actionFunctionResult || State.RUNNING);\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => this.actionName;\n\n /**\n * Reset the state of the node.\n */\n reset = () => {\n // Reset the state of this node.\n this.setState(State.READY);\n\n // There is no longer an update promise that we care about.\n this.isUsingUpdatePromise = false;\n this.updatePromiseResult = null;\n };\n\n /**\n * Validate the result of an update function call.\n * @param result The result of an update function call.\n */\n private validateUpdateResult = (result: CompleteState | State.RUNNING) => {\n switch (result) {\n case State.SUCCEEDED:\n case State.FAILED:\n case State.RUNNING:\n case undefined:\n return;\n default:\n throw new Error(\n `expected action function '${this.actionName}' to return an optional State.SUCCEEDED or State.FAILED value but returned '${result}'`\n );\n }\n };\n}\n", "import { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Leaf from \"./Leaf\";\nimport Lookup from \"../../Lookup\";\nimport Attribute from \"../../attributes/Attribute\";\n\n/**\n * A Condition leaf node.\n * This will succeed or fail immediately based on an agent predicate, without moving to the 'RUNNING' state.\n */\nexport default class Condition extends Leaf {\n /**\n * @param attributes The node attributes.\n * @param conditionName The name of the condition function.\n * @param conditionArguments The array of condition argument definitions.\n */\n constructor(attributes: Attribute[], private conditionName: string, private conditionArguments: any[]) {\n super(\"condition\", attributes, conditionArguments);\n }\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // Attempt to get the invoker for the condition function.\n const conditionFuncInvoker = Lookup.getFuncInvoker(agent, this.conditionName);\n\n // The condition function should be defined.\n if (conditionFuncInvoker === null) {\n throw new Error(\n `cannot update condition node as the condition '${this.conditionName}' function is not defined on the agent and has not been registered`\n );\n }\n\n let conditionFunctionResult;\n\n try {\n // Call the condition function to determine the state of this node, the result of which should be a boolean.\n conditionFunctionResult = conditionFuncInvoker(this.conditionArguments);\n } catch (error) {\n // The user was naughty and threw something.\n throw new Error(`condition function '${this.conditionName}' threw '${error}'`);\n }\n\n // The result of calling the condition function must be a boolean value.\n if (typeof conditionFunctionResult !== \"boolean\") {\n throw new Error(\n `expected condition function '${this.conditionName}' to return a boolean but returned '${conditionFunctionResult}'`\n );\n }\n\n // Set the state of this node based on the result of calling the condition function.\n this.setState(!!conditionFunctionResult ? State.SUCCEEDED : State.FAILED);\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => this.conditionName;\n}\n", "import Leaf from \"./Leaf\";\nimport State from \"../../State\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { Agent } from \"../../Agent\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A WAIT node.\n * The state of this node will change to SUCCEEDED after a duration of time\n */\nexport default class Wait extends Leaf {\n /**\n * @param attributes The node attributes.\n * @param duration The duration that this node will wait to succeed in milliseconds.\n * @param durationMin The minimum possible duration in milliseconds that this node will wait to succeed.\n * @param durationMax The maximum possible duration in milliseconds that this node will wait to succeed.\n */\n constructor(\n attributes: Attribute[],\n private duration: number | null,\n private durationMin: number | null,\n private durationMax: number | null\n ) {\n super(\"wait\", attributes, []);\n }\n\n /**\n * The time in milliseconds at which this node was first updated.\n */\n private initialUpdateTime: number = 0;\n\n /**\n * The total duration in milliseconds that this node will be waiting for.\n */\n private totalDuration: number | null = null;\n\n /**\n * The duration in milliseconds that this node has been waiting for.\n */\n private waitedDuration: number = 0;\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // If this node is in the READY state then we need to set the initial update time.\n if (this.is(State.READY)) {\n // Set the initial update time.\n this.initialUpdateTime = new Date().getTime();\n\n // Set the initial waited duration.\n this.waitedDuration = 0;\n\n // Are we dealing with an explicit duration or will we be randomly picking a duration between the min and max duration.\n if (this.duration !== null) {\n this.totalDuration = this.duration;\n } else if (this.durationMin !== null && this.durationMax !== null) {\n // We will be picking a random duration between a min and max duration, if the optional 'random' behaviour tree\n // function option is defined then we will be using that, otherwise we will fall back to using Math.random.\n const random = typeof options.random === \"function\" ? options.random : Math.random;\n\n // Pick a random duration between a min and max duration.\n this.totalDuration = Math.floor(\n random() * (this.durationMax - this.durationMin + 1) + this.durationMin\n );\n } else {\n this.totalDuration = null;\n }\n\n // The node is now running until we finish waiting.\n this.setState(State.RUNNING);\n }\n\n // If we have no total duration then this wait node will wait indefinitely until it is aborted.\n if (this.totalDuration === null) {\n return;\n }\n\n // If we have a 'getDeltaTime' function defined as part of our options then we will use it to figure out how long we have waited for.\n if (typeof options.getDeltaTime === \"function\") {\n // Get the delta time.\n const deltaTime = options.getDeltaTime();\n\n // Our delta time must be a valid number and cannot be NaN.\n if (typeof deltaTime !== \"number\" || isNaN(deltaTime)) {\n throw new Error(\"The delta time must be a valid number and not NaN.\");\n }\n\n // Update the amount of time that this node has been waiting for based on the delta time.\n this.waitedDuration += deltaTime * 1000;\n } else {\n // We are not using a delta time, so we will just work out hom much time has passed since the first update.\n this.waitedDuration = new Date().getTime() - this.initialUpdateTime;\n }\n\n // Have we waited long enough?\n if (this.waitedDuration >= this.totalDuration) {\n // We have finished waiting!\n this.setState(State.SUCCEEDED);\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => {\n if (this.duration !== null) {\n return `WAIT ${this.duration}ms`;\n } else if (this.durationMin !== null && this.durationMax !== null) {\n return `WAIT ${this.durationMin}ms-${this.durationMax}ms`;\n } else {\n return \"WAIT\";\n }\n };\n}\n", "import Guard from \"./guards/Guard\";\n\nexport type AttributeDetails = {\n /** The attribute type. */\n type: string;\n\n /** The attribute arguments. */\n args: any[];\n};\n\n/**\n * A base node attribute.\n */\nexport default abstract class Attribute {\n /**\n * @param type The node attribute type.\n * @param args The array of attribute arguments.\n */\n constructor(public type: string, public args: any[]) {}\n\n /**\n * Gets the attribute details.\n */\n abstract getDetails(): TAttributeDetails;\n\n /**\n * Gets whether this attribute is a guard.\n */\n abstract isGuard: () => this is Guard;\n}\n", "import { Agent } from \"../../Agent\";\nimport Attribute, { AttributeDetails } from \"../Attribute\";\n\nexport type GuardAttributeDetails = {\n /** The name of the condition function that determines whether the guard is satisfied. */\n condition: string;\n} & AttributeDetails;\n\n/**\n * A base node guard attribute.\n */\nexport default abstract class Guard extends Attribute {\n /**\n * @param type The node attribute type.\n * @param args The array of decorator argument definitions.\n * @param condition The name of the condition function that determines whether the guard is satisfied.\n */\n constructor(type: string, args: any[], private condition: string) {\n super(type, args);\n }\n\n /**\n * Gets the name of the condition function that determines whether the guard is satisfied.\n */\n getCondition = () => this.condition;\n\n /**\n * Gets whether this attribute is a guard.\n */\n isGuard = () => true;\n\n /**\n * Gets the attribute details.\n */\n getDetails(): GuardAttributeDetails {\n return {\n type: this.type,\n args: this.args,\n condition: this.getCondition()\n };\n }\n\n /**\n * Gets whether the guard is satisfied.\n * @param agent The agent.\n * @returns Whether the guard is satisfied.\n */\n abstract isSatisfied(agent: Agent): boolean;\n}\n", "import Guard from \"./Guard\";\nimport Lookup from \"../../Lookup\";\nimport { Agent } from \"../../Agent\";\n\n/**\n * A WHILE guard which is satisfied as long as the given condition remains true.\n */\nexport default class While extends Guard {\n /**\n * @param condition The name of the condition function that determines whether the guard is satisfied.\n * @param args The array of decorator argument definitions.\n */\n constructor(condition: string, args: any[]) {\n super(\"while\", args, condition);\n }\n\n /**\n * Gets whether the guard is satisfied.\n * @param agent The agent.\n * @returns Whether the guard is satisfied.\n */\n isSatisfied = (agent: Agent) => {\n // Attempt to get the invoker for the condition function.\n const conditionFuncInvoker = Lookup.getFuncInvoker(agent, this.getCondition());\n\n // The condition function should be defined.\n if (conditionFuncInvoker === null) {\n throw new Error(\n `cannot evaluate node guard as the condition '${this.getCondition()}' function is not defined on the agent and has not been registered`\n );\n }\n\n // Call the condition function to determine whether this guard is satisfied.\n return !!conditionFuncInvoker(this.args);\n };\n}\n", "import Guard from \"./Guard\";\nimport Lookup from \"../../Lookup\";\nimport { Agent } from \"../../Agent\";\n\n/**\n * An UNTIL guard which is satisfied as long as the given condition remains false.\n */\nexport default class Until extends Guard {\n /**\n * @param condition The name of the condition function that determines whether the guard is satisfied.\n * @param args The array of decorator argument definitions.\n */\n constructor(condition: string, args: any[]) {\n super(\"until\", args, condition);\n }\n\n /**\n * Gets whether the guard is satisfied.\n * @param agent The agent.\n * @returns Whether the guard is satisfied.\n */\n isSatisfied = (agent: Agent) => {\n // Attempt to get the invoker for the condition function.\n const conditionFuncInvoker = Lookup.getFuncInvoker(agent, this.getCondition());\n\n // The condition function should be defined.\n if (conditionFuncInvoker === null) {\n throw new Error(\n `cannot evaluate node guard as the condition '${this.getCondition()}' function is not defined on the agent and has not been registered`\n );\n }\n\n // Call the condition function to determine whether this guard is satisfied.\n return !!!conditionFuncInvoker(this.args);\n };\n}\n", "import { Agent } from \"../../Agent\";\nimport Attribute, { AttributeDetails } from \"../Attribute\";\n\nexport type CallbackAttributeDetails = {\n /** The name of the agent function that is called. */\n functionName: string;\n} & AttributeDetails;\n\n/**\n * A base node callback attribute.\n */\nexport default abstract class Callback extends Attribute {\n /**\n * @param type The node attribute type.\n * @param args The array of decorator argument definitions.\n * @param functionName The name of the agent function to call.\n */\n constructor(type: string, args: any[], private functionName: string) {\n super(type, args);\n }\n\n /**\n * Gets the name of the agent function to call.\n */\n getFunctionName = () => this.functionName;\n\n /**\n * Gets whether this attribute is a guard.\n */\n isGuard = () => false;\n\n /**\n * Gets the attribute details.\n */\n getDetails(): CallbackAttributeDetails {\n return {\n type: this.type,\n args: this.args,\n functionName: this.getFunctionName()\n };\n }\n\n /**\n * Attempt to call the agent function that this callback refers to.\n * @param agent The agent.\n */\n abstract callAgentFunction: (agent: Agent, isSuccess: boolean, isAborted: boolean) => void;\n}\n", "import Callback from \"./Callback\";\nimport Lookup from \"../../Lookup\";\nimport { Agent } from \"../../Agent\";\n\n/**\n * An ENTRY callback which defines an agent function to call when the associated node is updated and moves out of running state.\n */\nexport default class Entry extends Callback {\n /**\n * @param functionName The name of the agent function to call.\n * @param args The array of callback argument definitions.\n */\n constructor(functionName: string, args: any[]) {\n super(\"entry\", args, functionName);\n }\n\n /**\n * Attempt to call the agent function that this callback refers to.\n * @param agent The agent.\n */\n callAgentFunction = (agent: Agent) => {\n // Attempt to get the invoker for the callback function.\n const callbackFuncInvoker = Lookup.getFuncInvoker(agent, this.getFunctionName());\n\n // The callback function should be defined.\n if (callbackFuncInvoker === null) {\n throw new Error(\n `cannot call entry function '${this.getFunctionName()}' as is not defined on the agent and has not been registered`\n );\n }\n\n // Call the callback function.\n callbackFuncInvoker(this.args);\n };\n}\n", "import Callback from \"./Callback\";\nimport Lookup from \"../../Lookup\";\nimport { Agent } from \"../../Agent\";\n\n/**\n * A STEP callback which defines an agent function to call when the associated node is updated.\n */\nexport default class Step extends Callback {\n /**\n * @param functionName The name of the agent function to call.\n * @param args The array of callback argument definitions.\n */\n constructor(functionName: string, args: any[]) {\n super(\"step\", args, functionName);\n }\n\n /**\n * Attempt to call the agent function that this callback refers to.\n * @param agent The agent.\n */\n callAgentFunction = (agent: Agent) => {\n // Attempt to get the invoker for the callback function.\n const callbackFuncInvoker = Lookup.getFuncInvoker(agent, this.getFunctionName());\n\n // The callback function should be defined.\n if (callbackFuncInvoker === null) {\n throw new Error(\n `cannot call step function '${this.getFunctionName()}' as is not defined on the agent and has not been registered`\n );\n }\n\n // Call the callback function.\n callbackFuncInvoker(this.args);\n };\n}\n", "import Callback from \"./Callback\";\nimport Lookup from \"../../Lookup\";\nimport { Agent } from \"../../Agent\";\n\n/**\n * An EXIT callback which defines an agent function to call when the associated node is updated and moves to a finished state or is aborted.\n */\nexport default class Exit extends Callback {\n /**\n * @param functionName The name of the agent function to call.\n * @param args The array of callback argument definitions.\n */\n constructor(functionName: string, args: any[]) {\n super(\"exit\", args, functionName);\n }\n\n /**\n * Attempt to call the agent function that this callback refers to.\n * @param agent The agent.\n * @param isSuccess Whether the decorated node was left with a success state.\n * @param isAborted Whether the decorated node was aborted.\n */\n callAgentFunction = (agent: Agent, isSuccess: boolean, isAborted: boolean) => {\n // Attempt to get the invoker for the callback function.\n const callbackFuncInvoker = Lookup.getFuncInvoker(agent, this.getFunctionName());\n\n // The callback function should be defined.\n if (callbackFuncInvoker === null) {\n throw new Error(\n `cannot call exit function '${this.getFunctionName()}' as is not defined on the agent and has not been registered`\n );\n }\n\n // Call the callback function\n callbackFuncInvoker([{ succeeded: isSuccess, aborted: isAborted }, ...this.args]);\n };\n}\n", "import { AnyNodeDefinition, RootNodeDefinition } from \"./BehaviourTreeDefinition\";\nimport GuardPath, { GuardPathPart } from \"./attributes/guards/GuardPath\";\nimport { validateBranchSubtreeLinks } from \"./BehaviourTreeDefinitionValidator\";\nimport { isInteger } from \"./BehaviourTreeDefinitionUtilities\";\nimport Node from \"./nodes/Node\";\nimport Composite from \"./nodes/composite/Composite\";\nimport Decorator from \"./nodes/decorator/Decorator\";\nimport Parallel from \"./nodes/composite/Parallel\";\nimport Selector from \"./nodes/composite/Selector\";\nimport Sequence from \"./nodes/composite/Sequence\";\nimport Lotto from \"./nodes/composite/Lotto\";\nimport Fail from \"./nodes/decorator/Fail\";\nimport Flip from \"./nodes/decorator/Flip\";\nimport Repeat from \"./nodes/decorator/Repeat\";\nimport Retry from \"./nodes/decorator/Retry\";\nimport Root from \"./nodes/decorator/Root\";\nimport Succeed from \"./nodes/decorator/Succeed\";\nimport Action from \"./nodes/leaf/Action\";\nimport Condition from \"./nodes/leaf/Condition\";\nimport Wait from \"./nodes/leaf/Wait\";\nimport Lookup from \"./Lookup\";\nimport Attribute from \"./attributes/Attribute\";\nimport While from \"./attributes/guards/While\";\nimport Until from \"./attributes/guards/Until\";\nimport Entry from \"./attributes/callbacks/Entry\";\nimport Step from \"./attributes/callbacks/Step\";\nimport Exit from \"./attributes/callbacks/Exit\";\n\n/**\n * A type representing any node instance in a behaviour tree.\n */\ntype AnyNode =\n | Root\n | Action\n | Condition\n | Wait\n | Sequence\n | Selector\n | Lotto\n | Parallel\n | Repeat\n | Retry\n | Flip\n | Succeed\n | Fail;\n\n/**\n * A type defining a mapping of root node identifiers to root node definitions.\n */\ntype RootNodeDefinitionMap = { [key: string | symbol]: RootNodeDefinition };\n\n/**\n * A symbol to use as the main root key in any root node mappings.\n */\nconst MAIN_ROOT_NODE_KEY = Symbol(\"__root__\");\n\n/**\n * Build and populate the root nodes based on the provided definition, assuming that the definition has been validated.\n * @param definition The root node definitions.\n * @returns The built and populated root node definitions.\n */\nexport default function buildRootNode(definition: RootNodeDefinition[]): Root {\n // Create a mapping of root node identifers to root node definitions, including globally registered subtree root node definitions.\n const rootNodeDefinitionMap = createRootNodeDefinitionMap(definition);\n\n // Now that we have all of our root node definitions (those part of the tree definition and those globally registered)\n // we should validate the branch-subtree links. This will also double-check that we dont have any circular dependencies\n // in our branch-subtree references and that we have no broken branch-subtree links.\n validateBranchSubtreeLinks(\n [rootNodeDefinitionMap[MAIN_ROOT_NODE_KEY], ...Object.values(rootNodeDefinitionMap)],\n true\n );\n\n // Create our populated tree of node instances, starting with our main root node.\n const rootNode = nodeFactory(rootNodeDefinitionMap[MAIN_ROOT_NODE_KEY], rootNodeDefinitionMap) as Root;\n\n // Set a guard path on every leaf of the tree to evaluate as part of each update.\n applyLeafNodeGuardPaths(rootNode);\n\n // We only need to return the main root node.\n return rootNode;\n}\n\n/**\n * A factory function which creates a node instance based on the specified definition.\n * @param definition The node definition.\n * @param rootNodeDefinitionMap The mapping of root node identifers to root node definitions, including globally registered subtree root node definitions.\n * @returns A node instance based on the specified definition.\n */\nfunction nodeFactory(definition: AnyNodeDefinition, rootNodeDefinitionMap: RootNodeDefinitionMap): AnyNode {\n // Get the attributes for the node.\n const attributes = nodeAttributesFactory(definition);\n\n // Create the node instance based on the definition type.\n switch (definition.type) {\n case \"root\":\n return new Root(attributes, nodeFactory(definition.child, rootNodeDefinitionMap));\n\n case \"repeat\":\n let iterations: number | null = null;\n let iterationsMin: number | null = null;\n let iterationsMax: number | null = null;\n\n if (Array.isArray(definition.iterations)) {\n iterationsMin = definition.iterations[0];\n iterationsMax = definition.iterations[1];\n } else if (isInteger(definition.iterations)) {\n iterations = definition.iterations!;\n }\n\n return new Repeat(\n attributes,\n iterations,\n iterationsMin,\n iterationsMax,\n nodeFactory(definition.child, rootNodeDefinitionMap)\n );\n\n case \"retry\":\n let attempts: number | null = null;\n let attemptsMin: number | null = null;\n let attemptsMax: number | null = null;\n\n if (Array.isArray(definition.attempts)) {\n attemptsMin = definition.attempts[0];\n attemptsMax = definition.attempts[1];\n } else if (isInteger(definition.attempts)) {\n attempts = definition.attempts!;\n }\n\n return new Retry(\n attributes,\n attempts,\n attemptsMin,\n attemptsMax,\n nodeFactory(definition.child, rootNodeDefinitionMap)\n );\n\n case \"flip\":\n return new Flip(attributes, nodeFactory(definition.child, rootNodeDefinitionMap));\n\n case \"succeed\":\n return new Succeed(attributes, nodeFactory(definition.child, rootNodeDefinitionMap));\n\n case \"fail\":\n return new Fail(attributes, nodeFactory(definition.child, rootNodeDefinitionMap));\n\n case \"sequence\":\n return new Sequence(\n attributes,\n definition.children.map((child) => nodeFactory(child, rootNodeDefinitionMap))\n );\n\n case \"selector\":\n return new Selector(\n attributes,\n definition.children.map((child) => nodeFactory(child, rootNodeDefinitionMap))\n );\n\n case \"parallel\":\n return new Parallel(\n attributes,\n definition.children.map((child) => nodeFactory(child, rootNodeDefinitionMap))\n );\n\n case \"lotto\":\n return new Lotto(\n attributes,\n definition.weights,\n definition.children.map((child) => nodeFactory(child, rootNodeDefinitionMap))\n );\n\n case \"branch\":\n return nodeFactory(rootNodeDefinitionMap[definition.ref].child, rootNodeDefinitionMap);\n\n case \"action\":\n return new Action(attributes, definition.call, definition.args || []);\n\n case \"condition\":\n return new Condition(attributes, definition.call, definition.args || []);\n\n case \"wait\":\n let duration: number | null = null;\n let durationMin: number | null = null;\n let durationMax: number | null = null;\n\n if (Array.isArray(definition.duration)) {\n durationMin = definition.duration[0];\n durationMax = definition.duration[1];\n } else if (isInteger(definition.duration)) {\n duration = definition.duration!;\n }\n\n return new Wait(attributes, duration, durationMin, durationMax);\n }\n}\n\n/**\n * Creates an array of node attribute instances based on the specified node definition.\n * @param definition The node definition.\n * @returns An array of node attribute instances based on the specified node definition.\n */\nfunction nodeAttributesFactory(definition: AnyNodeDefinition): Attribute[] {\n const attributes: Attribute[] = [];\n\n if (definition.while) {\n attributes.push(new While(definition.while.call, definition.while.args ?? []));\n }\n\n if (definition.until) {\n attributes.push(new Until(definition.until.call, definition.until.args ?? []));\n }\n\n if (definition.entry) {\n attributes.push(new Entry(definition.entry.call, definition.entry.args ?? []));\n }\n\n if (definition.step) {\n attributes.push(new Step(definition.step.call, definition.step.args ?? []));\n }\n\n if (definition.exit) {\n attributes.push(new Exit(definition.exit.call, definition.exit.args ?? []));\n }\n\n return attributes;\n}\n\n/**\n * Creates a mapping of root node identifers to root node definitions, mixing in globally registered subtree root node definitions.\n * @param definition The root node definitions.\n * @returns A mapping of root node identifers to root node definitions, including globally registered subtree root node definitions.\n */\nfunction createRootNodeDefinitionMap(definition: RootNodeDefinition[]): RootNodeDefinitionMap {\n // Create a mapping of root node identifers to root node definitions.\n const rootNodeMap: RootNodeDefinitionMap = {};\n\n // Add in any registered subtree root node definitions.\n for (const [name, rootNodeDefinition] of Object.entries(Lookup.getSubtrees())) {\n // The name used when registering the subtree will be used as the root node identifier.\n rootNodeMap[name] = { ...rootNodeDefinition, id: name };\n }\n\n // Populate the map with the root node definitions that were included with the tree definition.\n // We do this after adding any registered subtrees as we want these to take presedence.\n for (const rootNodeDefinition of definition) {\n rootNodeMap[rootNodeDefinition.id ?? MAIN_ROOT_NODE_KEY] = rootNodeDefinition;\n }\n\n return rootNodeMap;\n}\n\n/**\n * Applies a guard path to every leaf of the tree to evaluate as part of each update.\n * @param root The main root tree node.\n */\nfunction applyLeafNodeGuardPaths(root: Root) {\n const nodePaths: Node[][] = [];\n\n const findLeafNodes = (path: Node[], node: Node) => {\n // Add the current node to the path.\n path = path.concat(node);\n\n // Check whether the current node is a leaf node.\n if (node.isLeafNode()) {\n nodePaths.push(path);\n } else {\n (node as Composite | Decorator).getChildren().forEach((child) => findLeafNodes(path, child));\n }\n };\n\n // Find all leaf node paths, starting from the root.\n findLeafNodes([], root);\n\n nodePaths.forEach((path) => {\n // Each node in the current path will have to be assigned a guard path, working from the root outwards.\n for (let depth = 0; depth < path.length; depth++) {\n // Get the node in the path at the current depth.\n const currentNode = path[depth];\n\n // The node may already have been assigned a guard path, if so just skip it.\n if (currentNode.hasGuardPath()) {\n continue;\n }\n\n // Create the guard path for the current node.\n const guardPath = new GuardPath(\n path\n .slice(0, depth + 1)\n .map((node) => ({ node, guards: node.getGuardAttributes() }))\n .filter((details) => details.guards.length > 0)\n );\n\n // Assign the guard path to the current node.\n currentNode.setGuardPath(guardPath);\n }\n });\n}\n", "import State, { AnyState } from \"./State\";\nimport Lookup from \"./Lookup\";\nimport Node from \"./nodes/Node\";\nimport Root from \"./nodes/decorator/Root\";\nimport Composite from \"./nodes/composite/Composite\";\nimport Decorator from \"./nodes/decorator/Decorator\";\nimport { Agent, GlobalFunction } from \"./Agent\";\nimport { CallbackAttributeDetails } from \"./attributes/callbacks/Callback\";\nimport { GuardAttributeDetails } from \"./attributes/guards/Guard\";\nimport { BehaviourTreeOptions } from \"./BehaviourTreeOptions\";\nimport { convertMDSLToJSON } from \"./mdsl/MDSLDefinitionParser\";\nimport { RootNodeDefinition } from \"./BehaviourTreeDefinition\";\nimport { validateDefinition, validateJSONDefinition } from \"./BehaviourTreeDefinitionValidator\";\nimport buildRootNode from \"./BehaviourTreeBuilder\";\nimport { isNullOrUndefined } from \"./BehaviourTreeDefinitionUtilities\";\n\n// Purely for outside inspection of the tree.\nexport type FlattenedTreeNode = {\n id: string;\n type: string;\n caption: string;\n state: AnyState;\n guards: GuardAttributeDetails[];\n callbacks: CallbackAttributeDetails[];\n args: any[];\n parentId: string | null;\n};\n\n/**\n * A representation of a behaviour tree.\n */\nexport class BehaviourTree {\n /**\n * The main root tree node.\n */\n private readonly _rootNode: Root;\n\n /**\n * Creates a new instance of the BehaviourTree class.\n * @param definition The behaviour tree definition as either an MDSL string, root node definition object or array of root node definition objects.\n * @param agent The agent instance that this behaviour tree is modelling behaviour for.\n * @param options The behaviour tree options object.\n */\n constructor(\n definition: string | RootNodeDefinition | RootNodeDefinition[],\n private agent: Agent,\n private options: BehaviourTreeOptions = {}\n ) {\n // The tree definition must be defined.\n if (isNullOrUndefined(definition)) {\n throw new Error(\"tree definition not defined\");\n }\n\n // The agent must be defined and not null.\n if (typeof agent !== \"object\" || agent === null) {\n throw new Error(\"the agent must be an object and not null\");\n }\n\n // We should validate the definition before we try to build the tree nodes.\n const { succeeded, errorMessage, json } = validateDefinition(definition);\n\n // Did our validation fail without error?\n if (!succeeded) {\n throw new Error(`invalid definition: ${errorMessage}`);\n }\n\n // Double check that we did actually get our json definition as part of our definition validtion.\n if (!json) {\n throw new Error(\n \"expected json definition to be returned as part of successful definition validation response\"\n );\n }\n\n try {\n // Create the populated tree of behaviour tree nodes and get the root node.\n this._rootNode = buildRootNode(json);\n } catch (exception) {\n // There was an issue in trying build and populate the behaviour tree.\n throw new Error(`error building tree: ${(exception as Error).message}`);\n }\n }\n\n /**\n * Gets whether the tree is in the RUNNING state.\n * @returns true if the tree is in the RUNNING state, otherwise false.\n */\n isRunning() {\n return this._rootNode.getState() === State.RUNNING;\n }\n\n /**\n * Gets the current tree state of SUCCEEDED, FAILED, READY or RUNNING.\n * @returns The current tree state.\n */\n getState() {\n return this._rootNode.getState();\n }\n\n /**\n * Step the tree.\n * 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.\n * 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\n * 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.\n *\n * 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.\n */\n step() {\n // If the root node has already been stepped to completion then we need to reset it.\n if (this._rootNode.getState() === State.SUCCEEDED || this._rootNode.getState() === State.FAILED) {\n this._rootNode.reset();\n }\n\n try {\n this._rootNode.update(this.agent, this.options);\n } catch (exception) {\n throw new Error(`error stepping tree: ${(exception as Error).message}`);\n }\n }\n\n /**\n * Resets the tree from the root node outwards to each nested node, giving each a state of READY.\n */\n reset() {\n this._rootNode.reset();\n }\n\n /**\n * Gets the flattened details of every node in the tree.\n * @returns The flattened details of every node in the tree.\n */\n getFlattenedNodeDetails(): FlattenedTreeNode[] {\n // Create an empty flattened array of tree nodes.\n const flattenedTreeNodes: FlattenedTreeNode[] = [];\n\n /**\n * Helper function to process a node instance and push details into the flattened tree nodes array.\n * @param node The current node.\n * @param parentUid The UID of the node parent, or null if the node is the main root node.\n */\n const processNode = (node: Node, parentUid: string | null) => {\n // Get the guard and callback attribute details for this node.\n const guards = node\n .getAttributes()\n .filter((attribute) => attribute.isGuard())\n .map((attribute) => attribute.getDetails()) as GuardAttributeDetails[];\n const callbacks = node\n .getAttributes()\n .filter((attribute) => !attribute.isGuard())\n .map((attribute) => attribute.getDetails()) as CallbackAttributeDetails[];\n\n // Push the current node into the flattened nodes array.\n flattenedTreeNodes.push({\n id: node.getUid(),\n type: node.getType(),\n caption: node.getName(),\n state: node.getState(),\n guards,\n callbacks,\n args: node.getArguments(),\n parentId: parentUid\n });\n\n // Process each of the nodes children if it is not a leaf node.\n if (!node.isLeafNode()) {\n (node as Composite | Decorator)\n .getChildren()\n .forEach((child) => processNode(child, (node as Composite | Decorator).getUid()));\n }\n };\n\n // Convert the nested node structure into a flattened array of node details.\n processNode(this._rootNode, null);\n\n return flattenedTreeNodes;\n }\n\n /**\n * Registers the action/condition/guard/callback function or subtree with the given name.\n * @param name The name of the function or subtree to register.\n * @param value The function or subtree definition to register.\n */\n static register(name: string, value: GlobalFunction | string | RootNodeDefinition) {\n // Are we going to register a action/condition/guard/callback function?\n if (typeof value === \"function\") {\n Lookup.setFunc(name, value);\n return;\n }\n\n // We are not registering an action/condition/guard/callback function, so we must be registering a subtree.\n if (typeof value === \"string\") {\n let rootNodeDefinitions: RootNodeDefinition[];\n\n // We will assume that any string passed in will be a mdsl definition.\n try {\n rootNodeDefinitions = convertMDSLToJSON(value);\n } catch (exception) {\n throw new Error(`error registering definition, invalid MDSL: ${(exception as Error).message}`);\n }\n\n // This function should only ever be called with a definition containing a single unnamed root node.\n if (rootNodeDefinitions.length != 1 || rootNodeDefinitions[0].id !== null) {\n throw new Error(\"error registering definition: expected a single unnamed root node\");\n }\n\n try {\n // We should validate the subtree as we don't want invalid subtrees available via the lookup.\n const { succeeded, errorMessage } = validateJSONDefinition(rootNodeDefinitions[0]);\n\n // Did our validation fail without error?\n if (!succeeded) {\n throw new Error(errorMessage);\n }\n } catch (exception) {\n throw new Error(`error registering definition: ${(exception as Error).message}`);\n }\n\n // Everything seems hunky-dory, register the subtree.\n Lookup.setSubtree(name, rootNodeDefinitions[0]);\n } else if (typeof value === \"object\" && !Array.isArray(value)) {\n // We will assume that any object passed in is a root node definition.\n\n try {\n // We should validate the subtree as we don't want invalid subtrees available via the lookup.\n const { succeeded, errorMessage } = validateJSONDefinition(value);\n\n // Did our validation fail without error?\n if (!succeeded) {\n throw new Error(errorMessage);\n }\n } catch (exception) {\n throw new Error(`error registering definition: ${(exception as Error).message}`);\n }\n\n // Everything seems hunky-dory, register the subtree.\n Lookup.setSubtree(name, value);\n } else {\n throw new Error(\"unexpected value, expected string mdsl definition, root node json definition or function\");\n }\n }\n\n /**\n * Unregisters the registered action/condition/guard/callback function or subtree with the given name.\n * @param name The name of the registered action/condition/guard/callback function or subtree to unregister.\n */\n static unregister(name: string): void {\n Lookup.remove(name);\n }\n\n /**\n * Unregister all registered action/condition/guard/callback functions and subtrees.\n */\n static unregisterAll(): void {\n Lookup.empty();\n }\n}\n"], + "mappings": "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", "names": ["Participant", "isNullOrUndefined", "Lotto", "createLotto", "State", "createLotto"] } diff --git a/src/attributes/callbacks/Exit.ts b/src/attributes/callbacks/Exit.ts index 5790f6b..a4dc6eb 100644 --- a/src/attributes/callbacks/Exit.ts +++ b/src/attributes/callbacks/Exit.ts @@ -32,6 +32,6 @@ export default class Exit extends Callback { } // Call the callback function - callbackFuncInvoker([{ value: { succeeded: isSuccess, aborted: isAborted } }, ...this.args]); + callbackFuncInvoker([{ succeeded: isSuccess, aborted: isAborted }, ...this.args]); }; } diff --git a/test/attributes/callbacks/Entry.spec.ts b/test/attributes/callbacks/Entry.spec.ts index 9efad9a..7119b62 100644 --- a/test/attributes/callbacks/Entry.spec.ts +++ b/test/attributes/callbacks/Entry.spec.ts @@ -12,7 +12,7 @@ describe("An Entry callback node attribute", () => { assert.throws( () => new BehaviourTree(definition, {}), Error, - "expected agent function or registered function name identifier argument for attribute" + "invalid definition: expected agent function or registered function name identifier argument for attribute" ); }); @@ -28,7 +28,7 @@ describe("An Entry callback node attribute", () => { assert.throws( () => new BehaviourTree(definition, {}), Error, - "expected 'call' property for attribute 'entry' to be a non-empty string for 'action' node at depth '1'" + "invalid definition: expected 'call' property for attribute 'entry' to be a non-empty string for 'action' node at depth '1'" ); }); }); @@ -60,7 +60,7 @@ describe("An Entry callback node attribute", () => { assert.isTrue(agent.onEntry.calledTwice); }); - it("(MDSL)", () => { + it("(JSON)", () => { const definition: RootNodeDefinition = { type: "root", entry: { diff --git a/test/attributes/callbacks/Exit.spec.ts b/test/attributes/callbacks/Exit.spec.ts index cd8ad9d..45e671b 100644 --- a/test/attributes/callbacks/Exit.spec.ts +++ b/test/attributes/callbacks/Exit.spec.ts @@ -1 +1,233 @@ -describe("An Exit callback node attribute", () => {}); +import { assert } from "chai"; +import sinon from "sinon"; + +import { BehaviourTree, State } from "../../../src/index"; +import { RootNodeDefinition } from "../../../src/BehaviourTreeDefinition"; + +describe("An Exit callback node attribute", () => { + describe("on tree initialisation", () => { + describe("will error if no function name is defined", () => { + it("(MDSL)", () => { + const definition = "root { action [noop] exit() }"; + assert.throws( + () => new BehaviourTree(definition, {}), + Error, + "invalid definition: expected agent function or registered function name identifier argument for attribute" + ); + }); + + it("(JSON)", () => { + const definition: RootNodeDefinition = { + type: "root", + child: { + type: "action", + call: "noop", + exit: {} as any + } + }; + assert.throws( + () => new BehaviourTree(definition, {}), + Error, + "invalid definition: expected 'call' property for attribute 'exit' to be a non-empty string for 'action' node at depth '1'" + ); + }); + }); + }); + + describe("when the node is updated as part of a tree step will call the exit function when the node moves out of the RUNNING state", () => { + describe("and to a SUCCEEDED state", () => { + it("(MDSL)", () => { + const definition = `root exit(onExit, "root") { action [someAction] exit(onExit, "action") }`; + const agent = { + someAction: () => State.RUNNING, + onExit: sinon.stub() + }; + const tree = new BehaviourTree(definition, agent); + + tree.step(); + + assert.isNotTrue(agent.onExit.called); + assert.isTrue(tree.isRunning()); + + agent.someAction = () => State.SUCCEEDED; + + tree.step(); + + assert.isFalse(tree.isRunning()); + assert.isTrue(agent.onExit.calledTwice); + assert.isTrue(agent.onExit.calledWith(sinon.match({ succeeded: true, aborted: false }), "root")); + assert.isTrue(agent.onExit.calledWith(sinon.match({ succeeded: true, aborted: false }), "action")); + }); + + it("(JSON)", () => { + const definition: RootNodeDefinition = { + type: "root", + exit: { + call: "onExit", + args: ["root"] + }, + child: { + type: "action", + exit: { + call: "onExit", + args: ["action"] + }, + call: "someAction" + } + }; + const agent = { + someAction: () => State.RUNNING, + onExit: sinon.stub() + }; + const tree = new BehaviourTree(definition, agent); + + tree.step(); + + assert.isNotTrue(agent.onExit.called); + assert.isTrue(tree.isRunning()); + + agent.someAction = () => State.SUCCEEDED; + + tree.step(); + + assert.isFalse(tree.isRunning()); + assert.isTrue(agent.onExit.calledTwice); + assert.isTrue(agent.onExit.calledWith(sinon.match({ succeeded: true, aborted: false }), "root")); + assert.isTrue(agent.onExit.calledWith(sinon.match({ succeeded: true, aborted: false }), "action")); + }); + }); + + describe("and to a FAILED state when the node execution", () => { + describe("was not aborted", () => { + it("(MDSL)", () => { + const definition = `root exit(onExit, "root") { action [someAction] exit(onExit, "action") }`; + const agent = { + someAction: () => State.RUNNING, + onExit: sinon.stub() + }; + const tree = new BehaviourTree(definition, agent); + + tree.step(); + + assert.isNotTrue(agent.onExit.called); + assert.isTrue(tree.isRunning()); + + agent.someAction = () => State.FAILED; + + tree.step(); + + assert.isFalse(tree.isRunning()); + assert.isTrue(agent.onExit.calledTwice); + assert.isTrue(agent.onExit.calledWith(sinon.match({ succeeded: false, aborted: false }), "root")); + assert.isTrue(agent.onExit.calledWith(sinon.match({ succeeded: false, aborted: false }), "action")); + }); + + it("(JSON)", () => { + const definition: RootNodeDefinition = { + type: "root", + exit: { + call: "onExit", + args: ["root"] + }, + child: { + type: "action", + exit: { + call: "onExit", + args: ["action"] + }, + call: "someAction" + } + }; + const agent = { + someAction: () => State.RUNNING, + onExit: sinon.stub() + }; + const tree = new BehaviourTree(definition, agent); + + tree.step(); + + assert.isNotTrue(agent.onExit.called); + assert.isTrue(tree.isRunning()); + + agent.someAction = () => State.FAILED; + + tree.step(); + + assert.isFalse(tree.isRunning()); + assert.isTrue(agent.onExit.calledTwice); + assert.isTrue(agent.onExit.calledWith(sinon.match({ succeeded: false, aborted: false }), "root")); + assert.isTrue(agent.onExit.calledWith(sinon.match({ succeeded: false, aborted: false }), "action")); + }); + }); + + describe("was aborted", () => { + it("(MDSL)", () => { + const definition = `root exit(onExit, "root") { action [someAction] exit(onExit, "action") while(someCondition) }`; + const agent = { + someAction: () => State.RUNNING, + someCondition: () => true, + onExit: sinon.stub() + }; + const tree = new BehaviourTree(definition, agent); + + tree.step(); + + assert.isNotTrue(agent.onExit.called); + assert.isTrue(tree.isRunning()); + + // Cause the running action node to be aborted on the next tree step. + agent.someCondition = () => false; + + tree.step(); + + assert.isFalse(tree.isRunning()); + assert.isTrue(agent.onExit.calledTwice); + assert.isTrue(agent.onExit.calledWith(sinon.match({ succeeded: false, aborted: false }), "root")); + assert.isTrue(agent.onExit.calledWith(sinon.match({ succeeded: false, aborted: true }), "action")); + }); + + it("(JSON)", () => { + const definition: RootNodeDefinition = { + type: "root", + exit: { + call: "onExit", + args: ["root"] + }, + child: { + type: "action", + exit: { + call: "onExit", + args: ["action"] + }, + while: { + call: "someCondition" + }, + call: "someAction" + } + }; + const agent = { + someAction: () => State.RUNNING, + someCondition: () => true, + onExit: sinon.stub() + }; + const tree = new BehaviourTree(definition, agent); + + tree.step(); + + assert.isNotTrue(agent.onExit.called); + assert.isTrue(tree.isRunning()); + + // Cause the running action node to be aborted on the next tree step. + agent.someCondition = () => false; + + tree.step(); + + assert.isFalse(tree.isRunning()); + assert.isTrue(agent.onExit.calledTwice); + assert.isTrue(agent.onExit.calledWith(sinon.match({ succeeded: false, aborted: false }), "root")); + assert.isTrue(agent.onExit.calledWith(sinon.match({ succeeded: false, aborted: true }), "action")); + }); + }); + }); + }); +}); From 758adb49db6006c4d1b2443fb3c9b05cb5086fe7 Mon Sep 17 00:00:00 2001 From: Nikolas Howard Date: Wed, 28 Feb 2024 13:56:37 +0000 Subject: [PATCH 42/48] Step specs --- test/attributes/callbacks/Step.spec.ts | 123 ++++++++++++++++++++++++- test/nodes/decorator/Fail.spec.ts | 16 ++-- test/nodes/decorator/Flip.spec.ts | 25 +++-- test/nodes/decorator/Succeed.spec.ts | 24 ++--- 4 files changed, 154 insertions(+), 34 deletions(-) diff --git a/test/attributes/callbacks/Step.spec.ts b/test/attributes/callbacks/Step.spec.ts index a635a5b..b2297af 100644 --- a/test/attributes/callbacks/Step.spec.ts +++ b/test/attributes/callbacks/Step.spec.ts @@ -1 +1,122 @@ -describe("A Step callback node attribute", () => {}); +import { assert } from "chai"; +import sinon from "sinon"; + +import { BehaviourTree, State } from "../../../src/index"; +import { RootNodeDefinition } from "../../../src/BehaviourTreeDefinition"; + +describe("A Step callback node attribute", () => { + describe("on tree initialisation", () => { + describe("will error if no function name is defined", () => { + it("(MDSL)", () => { + const definition = "root { action [noop] step() }"; + assert.throws( + () => new BehaviourTree(definition, {}), + Error, + "invalid definition: expected agent function or registered function name identifier argument for attribute" + ); + }); + + it("(JSON)", () => { + const definition: RootNodeDefinition = { + type: "root", + child: { + type: "action", + call: "noop", + step: {} as any + } + }; + assert.throws( + () => new BehaviourTree(definition, {}), + Error, + "invalid definition: expected 'call' property for attribute 'step' to be a non-empty string for 'action' node at depth '1'" + ); + }); + }); + }); + + describe("when the node is updated as part of a tree step will call the step function", () => { + it("(MDSL)", () => { + const definition = `root step(onRootStep, "root") { action [someAction] step(onActionStep, "action") }`; + const agent = { + someAction: () => State.RUNNING, + onRootStep: sinon.stub(), + onActionStep: sinon.stub() + }; + const tree = new BehaviourTree(definition, agent); + + assert.isNotTrue(agent.onRootStep.called); + assert.isNotTrue(agent.onActionStep.called); + + tree.step(); + + assert.isTrue(tree.isRunning()); + assert.isTrue(agent.onRootStep.calledOnce); + assert.isTrue(agent.onActionStep.calledOnce); + assert.isTrue(agent.onRootStep.calledWith("root")); + assert.isTrue(agent.onActionStep.calledWith("action")); + + tree.step(); + + assert.isTrue(tree.isRunning()); + assert.isTrue(agent.onRootStep.calledTwice); + assert.isTrue(agent.onActionStep.calledTwice); + + agent.someAction = () => State.SUCCEEDED; + + tree.step(); + + assert.isFalse(tree.isRunning()); + assert.isTrue(agent.onRootStep.calledThrice); + assert.isTrue(agent.onActionStep.calledThrice); + }); + + it("(JSON)", () => { + const definition: RootNodeDefinition = { + type: "root", + step: { + call: "onRootStep", + args: ["root"] + }, + child: { + type: "action", + step: { + call: "onActionStep", + args: ["action"] + }, + call: "someAction" + } + }; + const agent = { + someAction: () => State.RUNNING, + onRootStep: sinon.stub(), + onActionStep: sinon.stub() + }; + const tree = new BehaviourTree(definition, agent); + + assert.isNotTrue(agent.onRootStep.called); + assert.isNotTrue(agent.onActionStep.called); + + tree.step(); + + assert.isTrue(tree.isRunning()); + assert.isTrue(agent.onRootStep.calledOnce); + assert.isTrue(agent.onActionStep.calledOnce); + assert.isTrue(agent.onRootStep.calledWith("root")); + assert.isTrue(agent.onActionStep.calledWith("action")); + + tree.step(); + + assert.isTrue(tree.isRunning()); + assert.isTrue(agent.onRootStep.calledTwice); + assert.isTrue(agent.onActionStep.calledTwice); + + agent.someAction = () => State.SUCCEEDED; + + tree.step(); + + assert.isFalse(tree.isRunning()); + assert.isTrue(agent.onRootStep.calledThrice); + assert.isTrue(agent.onActionStep.calledThrice); + }); + }); +}); diff --git a/test/nodes/decorator/Fail.spec.ts b/test/nodes/decorator/Fail.spec.ts index be16190..c441bfa 100644 --- a/test/nodes/decorator/Fail.spec.ts +++ b/test/nodes/decorator/Fail.spec.ts @@ -81,12 +81,12 @@ describe("A Fail node", () => { const agent = { someCondition: () => true }; const tree = new BehaviourTree(definition, agent); - let node = findNode(tree, "fail", "FAIL"); + let node = findNode(tree, "fail"); assert.strictEqual(node.state, State.READY); tree.step(); - node = findNode(tree, "fail", "FAIL"); + node = findNode(tree, "fail"); assert.strictEqual(node.state, State.FAILED); }); @@ -104,12 +104,12 @@ describe("A Fail node", () => { const agent = { someCondition: () => true }; const tree = new BehaviourTree(definition, agent); - let node = findNode(tree, "fail", "FAIL"); + let node = findNode(tree, "fail"); assert.strictEqual(node.state, State.READY); tree.step(); - node = findNode(tree, "fail", "FAIL"); + node = findNode(tree, "fail"); assert.strictEqual(node.state, State.FAILED); }); }); @@ -121,12 +121,12 @@ describe("A Fail node", () => { const agent = { someAction: () => State.RUNNING }; const tree = new BehaviourTree(definition, agent); - let node = findNode(tree, "fail", "FAIL"); + let node = findNode(tree, "fail"); assert.strictEqual(node.state, State.READY); tree.step(); - node = findNode(tree, "fail", "FAIL"); + node = findNode(tree, "fail"); assert.strictEqual(node.state, State.RUNNING); }); @@ -144,12 +144,12 @@ describe("A Fail node", () => { const agent = { someAction: () => State.RUNNING }; const tree = new BehaviourTree(definition, agent); - let node = findNode(tree, "fail", "FAIL"); + let node = findNode(tree, "fail"); assert.strictEqual(node.state, State.READY); tree.step(); - node = findNode(tree, "fail", "FAIL"); + node = findNode(tree, "fail"); assert.strictEqual(node.state, State.RUNNING); }); }); diff --git a/test/nodes/decorator/Flip.spec.ts b/test/nodes/decorator/Flip.spec.ts index 9309b24..5081102 100644 --- a/test/nodes/decorator/Flip.spec.ts +++ b/test/nodes/decorator/Flip.spec.ts @@ -2,7 +2,6 @@ import { assert } from "chai"; import { BehaviourTree, State } from "../../../src/index"; import { RootNodeDefinition } from "../../../src/BehaviourTreeDefinition"; -import { Agent } from "../../../src/Agent"; import { findNode } from "../../TestUtilities"; @@ -41,12 +40,12 @@ describe("A Flip node", () => { const agent = { someCondition: () => false }; const tree = new BehaviourTree(definition, agent); - let node = findNode(tree, "flip", "FLIP"); + let node = findNode(tree, "flip"); assert.strictEqual(node.state, State.READY); tree.step(); - node = findNode(tree, "flip", "FLIP"); + node = findNode(tree, "flip"); assert.strictEqual(node.state, State.SUCCEEDED); }); @@ -64,12 +63,12 @@ describe("A Flip node", () => { const agent = { someCondition: () => false }; const tree = new BehaviourTree(definition, agent); - let node = findNode(tree, "flip", "FLIP"); + let node = findNode(tree, "flip"); assert.strictEqual(node.state, State.READY); tree.step(); - node = findNode(tree, "flip", "FLIP"); + node = findNode(tree, "flip"); assert.strictEqual(node.state, State.SUCCEEDED); }); }); @@ -80,12 +79,12 @@ describe("A Flip node", () => { const agent = { someCondition: () => true }; const tree = new BehaviourTree(definition, agent); - let node = findNode(tree, "flip", "FLIP"); + let node = findNode(tree, "flip"); assert.strictEqual(node.state, State.READY); tree.step(); - node = findNode(tree, "flip", "FLIP"); + node = findNode(tree, "flip"); assert.strictEqual(node.state, State.FAILED); }); @@ -103,12 +102,12 @@ describe("A Flip node", () => { const agent = { someCondition: () => true }; const tree = new BehaviourTree(definition, agent); - let node = findNode(tree, "flip", "FLIP"); + let node = findNode(tree, "flip"); assert.strictEqual(node.state, State.READY); tree.step(); - node = findNode(tree, "flip", "FLIP"); + node = findNode(tree, "flip"); assert.strictEqual(node.state, State.FAILED); }); }); @@ -119,12 +118,12 @@ describe("A Flip node", () => { const agent = { someAction: () => State.RUNNING }; const tree = new BehaviourTree(definition, agent); - let node = findNode(tree, "flip", "FLIP"); + let node = findNode(tree, "flip"); assert.strictEqual(node.state, State.READY); tree.step(); - node = findNode(tree, "flip", "FLIP"); + node = findNode(tree, "flip"); assert.strictEqual(node.state, State.RUNNING); }); @@ -142,12 +141,12 @@ describe("A Flip node", () => { const agent = { someAction: () => State.RUNNING }; const tree = new BehaviourTree(definition, agent); - let node = findNode(tree, "flip", "FLIP"); + let node = findNode(tree, "flip"); assert.strictEqual(node.state, State.READY); tree.step(); - node = findNode(tree, "flip", "FLIP"); + node = findNode(tree, "flip"); assert.strictEqual(node.state, State.RUNNING); }); }); diff --git a/test/nodes/decorator/Succeed.spec.ts b/test/nodes/decorator/Succeed.spec.ts index 0b6b4e9..ed57452 100644 --- a/test/nodes/decorator/Succeed.spec.ts +++ b/test/nodes/decorator/Succeed.spec.ts @@ -42,12 +42,12 @@ describe("A Succeed node", () => { const agent = { someCondition: () => false }; const tree = new BehaviourTree(definition, agent); - let node = findNode(tree, "succeed", "SUCCEED"); + let node = findNode(tree, "succeed"); assert.strictEqual(node.state, State.READY); tree.step(); - node = findNode(tree, "succeed", "SUCCEED"); + node = findNode(tree, "succeed"); assert.strictEqual(node.state, State.SUCCEEDED); }); @@ -65,12 +65,12 @@ describe("A Succeed node", () => { const agent = { someCondition: () => false }; const tree = new BehaviourTree(definition, agent); - let node = findNode(tree, "succeed", "SUCCEED"); + let node = findNode(tree, "succeed"); assert.strictEqual(node.state, State.READY); tree.step(); - node = findNode(tree, "succeed", "SUCCEED"); + node = findNode(tree, "succeed"); assert.strictEqual(node.state, State.SUCCEEDED); }); }); @@ -81,12 +81,12 @@ describe("A Succeed node", () => { const agent = { someCondition: () => true }; const tree = new BehaviourTree(definition, agent); - let node = findNode(tree, "succeed", "SUCCEED"); + let node = findNode(tree, "succeed"); assert.strictEqual(node.state, State.READY); tree.step(); - node = findNode(tree, "succeed", "SUCCEED"); + node = findNode(tree, "succeed"); assert.strictEqual(node.state, State.SUCCEEDED); }); @@ -104,12 +104,12 @@ describe("A Succeed node", () => { const agent = { someCondition: () => true }; const tree = new BehaviourTree(definition, agent); - let node = findNode(tree, "succeed", "SUCCEED"); + let node = findNode(tree, "succeed"); assert.strictEqual(node.state, State.READY); tree.step(); - node = findNode(tree, "succeed", "SUCCEED"); + node = findNode(tree, "succeed"); assert.strictEqual(node.state, State.SUCCEEDED); }); }); @@ -121,12 +121,12 @@ describe("A Succeed node", () => { const agent = { someAction: () => State.RUNNING }; const tree = new BehaviourTree(definition, agent); - let node = findNode(tree, "succeed", "SUCCEED"); + let node = findNode(tree, "succeed"); assert.strictEqual(node.state, State.READY); tree.step(); - node = findNode(tree, "succeed", "SUCCEED"); + node = findNode(tree, "succeed"); assert.strictEqual(node.state, State.RUNNING); }); @@ -144,12 +144,12 @@ describe("A Succeed node", () => { const agent = { someAction: () => State.RUNNING }; const tree = new BehaviourTree(definition, agent); - let node = findNode(tree, "succeed", "SUCCEED"); + let node = findNode(tree, "succeed"); assert.strictEqual(node.state, State.READY); tree.step(); - node = findNode(tree, "succeed", "SUCCEED"); + node = findNode(tree, "succeed"); assert.strictEqual(node.state, State.RUNNING); }); }); From 858c0e4de0bbed7714fd7be8b619fc61fc01bed2 Mon Sep 17 00:00:00 2001 From: Nikolas Howard Date: Thu, 29 Feb 2024 17:45:17 +0000 Subject: [PATCH 43/48] Until While specs and error handling --- dist/bundle.js | 26 ++- dist/bundle.js.map | 4 +- dist/index.js | 26 ++- dist/index.js.map | 4 +- src/attributes/guards/Until.ts | 21 +- src/attributes/guards/While.ts | 21 +- test/attributes/guards/Until.spec.ts | 317 ++++++++++++++++++++++++++- test/attributes/guards/While.spec.ts | 317 ++++++++++++++++++++++++++- test/nodes/leaf/Action.spec.ts | 8 +- 9 files changed, 726 insertions(+), 18 deletions(-) diff --git a/dist/bundle.js b/dist/bundle.js index c954fdc..7d3ef95 100644 --- a/dist/bundle.js +++ b/dist/bundle.js @@ -1960,7 +1960,18 @@ var mistreevous = (() => { `cannot evaluate node guard as the condition '${this.getCondition()}' function is not defined on the agent and has not been registered` ); } - return !!conditionFuncInvoker(this.args); + let conditionFunctionResult; + try { + conditionFunctionResult = conditionFuncInvoker(this.args); + } catch (error) { + throw new Error(`guard condition function '${this.getCondition()}' threw '${error}'`); + } + if (typeof conditionFunctionResult !== "boolean") { + throw new Error( + `expected guard condition function '${this.getCondition()}' to return a boolean but returned '${conditionFunctionResult}'` + ); + } + return conditionFunctionResult; }; }; @@ -1976,7 +1987,18 @@ var mistreevous = (() => { `cannot evaluate node guard as the condition '${this.getCondition()}' function is not defined on the agent and has not been registered` ); } - return !!!conditionFuncInvoker(this.args); + let conditionFunctionResult; + try { + conditionFunctionResult = conditionFuncInvoker(this.args); + } catch (error) { + throw new Error(`guard condition function '${this.getCondition()}' threw '${error}'`); + } + if (typeof conditionFunctionResult !== "boolean") { + throw new Error( + `expected guard condition function '${this.getCondition()}' to return a boolean but returned '${conditionFunctionResult}'` + ); + } + return !conditionFunctionResult; }; }; diff --git a/dist/bundle.js.map b/dist/bundle.js.map index 57837ad..afcf63b 100644 --- a/dist/bundle.js.map +++ b/dist/bundle.js.map @@ -1,7 +1,7 @@ { "version": 3, "sources": ["../node_modules/lotto-draw/dist/Participant.js", "../node_modules/lotto-draw/dist/Utilities.js", "../node_modules/lotto-draw/dist/Lotto.js", "../node_modules/lotto-draw/dist/createLotto.js", "../node_modules/lotto-draw/dist/index.js", "../src/index.ts", "../src/State.ts", "../src/BehaviourTreeDefinitionUtilities.ts", "../src/mdsl/MDSLUtilities.ts", "../src/mdsl/MDSLNodeArgumentParser.ts", "../src/mdsl/MDSLNodeAttributeParser.ts", "../src/mdsl/MDSLDefinitionParser.ts", "../src/BehaviourTreeDefinitionValidator.ts", "../src/Lookup.ts", "../src/attributes/guards/GuardUnsatisifedException.ts", "../src/attributes/guards/GuardPath.ts", "../src/nodes/Node.ts", "../src/nodes/composite/Composite.ts", "../src/nodes/composite/Parallel.ts", "../src/nodes/composite/Selector.ts", "../src/nodes/composite/Sequence.ts", "../src/nodes/composite/Lotto.ts", "../src/nodes/decorator/Decorator.ts", "../src/nodes/decorator/Fail.ts", "../src/nodes/decorator/Flip.ts", "../src/nodes/decorator/Repeat.ts", "../src/nodes/decorator/Retry.ts", "../src/nodes/decorator/Root.ts", "../src/nodes/decorator/Succeed.ts", "../src/nodes/leaf/Leaf.ts", "../src/nodes/leaf/Action.ts", "../src/nodes/leaf/Condition.ts", "../src/nodes/leaf/Wait.ts", "../src/attributes/Attribute.ts", "../src/attributes/guards/Guard.ts", "../src/attributes/guards/While.ts", "../src/attributes/guards/Until.ts", "../src/attributes/callbacks/Callback.ts", "../src/attributes/callbacks/Entry.ts", "../src/attributes/callbacks/Step.ts", "../src/attributes/callbacks/Exit.ts", "../src/BehaviourTreeBuilder.ts", "../src/BehaviourTree.ts"], - "sourcesContent": ["\"use strict\";\r\nObject.defineProperty(exports, \"__esModule\", { value: true });\r\nexports.Participant = void 0;\r\n/**\r\n * A participant that holds a number of tickets.\r\n */\r\nvar Participant = /** @class */ (function () {\r\n /**\r\n * Creates an instance of the Participant class.\r\n * @param participant The actual participant.\r\n * @param tickets The number of tickets held by the participant.\r\n */\r\n function Participant(participant, tickets) {\r\n if (tickets === void 0) { tickets = 1; }\r\n this._participant = participant;\r\n this._tickets = tickets;\r\n }\r\n Object.defineProperty(Participant.prototype, \"participant\", {\r\n /** Gets the actual participant. */\r\n get: function () {\r\n return this._participant;\r\n },\r\n enumerable: false,\r\n configurable: true\r\n });\r\n Object.defineProperty(Participant.prototype, \"tickets\", {\r\n /** Gets or sets the number of tickets held by the participant. */\r\n get: function () {\r\n return this._tickets;\r\n },\r\n set: function (value) {\r\n this._tickets = value;\r\n },\r\n enumerable: false,\r\n configurable: true\r\n });\r\n return Participant;\r\n}());\r\nexports.Participant = Participant;\r\n", "\"use strict\";\r\nObject.defineProperty(exports, \"__esModule\", { value: true });\r\nexports.isNaturalNumber = exports.isNullOrUndefined = void 0;\r\n/**\r\n * Gets whether the value provided is null or undefined.\r\n * @param value The value to check.\r\n * @returns Whether the value provided is null or undefined.\r\n */\r\nfunction isNullOrUndefined(value) {\r\n return value === null || value === undefined;\r\n}\r\nexports.isNullOrUndefined = isNullOrUndefined;\r\n/**\r\n * Gets whether the value provided is a natural number.\r\n * @param value The value to check.\r\n * @returns Whether the value provided is a natural number.\r\n */\r\nfunction isNaturalNumber(value) {\r\n return typeof value === \"number\" && value >= 1 && Math.floor(value) === value;\r\n}\r\nexports.isNaturalNumber = isNaturalNumber;\r\n", "\"use strict\";\r\nObject.defineProperty(exports, \"__esModule\", { value: true });\r\nexports.Lotto = void 0;\r\nvar Participant_1 = require(\"./Participant\");\r\nvar Utilities_1 = require(\"./Utilities\");\r\n/**\r\n * Represents a lotto consisting of a number of pickable ticket-holding participants.\r\n */\r\nvar Lotto = /** @class */ (function () {\r\n /**\r\n * Creates a new instance of Lotto.\r\n * @param customRandom The custom RNG to use in place of Math.random().\r\n */\r\n function Lotto(customRandom) {\r\n /** The array of participants that are holding tickets in the lotto. */\r\n this._participants = [];\r\n this._customRandom = customRandom;\r\n }\r\n /**\r\n * Adds a participant with the specified number of tickets, or adds to the participant ticket count if the participant already holds tickets.\r\n * @param participant The participant to add or to increase the ticket count for if they already hold tickets.\r\n * @param tickets The number of tickets, defaults to 1.\r\n * @returns The Lotto instance.\r\n */\r\n Lotto.prototype.add = function (participant, tickets) {\r\n if (tickets === void 0) { tickets = 1; }\r\n // Check that we have a valid ticket count.\r\n if (!(0, Utilities_1.isNaturalNumber)(tickets)) {\r\n throw new Error(\"tickets value must be a natural number\");\r\n }\r\n // Check whether this participant has already been added.\r\n var existingParticipant = this._participants.find(function (part) { return part.participant === participant; });\r\n if (existingParticipant) {\r\n // The participant has already been added to the lotto so just add to their ticket count.\r\n existingParticipant.tickets += tickets;\r\n }\r\n else {\r\n // The participant is not part of the lotto so we should add them.\r\n this._participants.push(new Participant_1.Participant(participant, tickets));\r\n }\r\n return this;\r\n };\r\n /**\r\n * Removes the specified number of tickets for the given participant from the draw, or all tickets if a ticket number is not defined.\r\n * @param participant The participant to remove tickets for.\r\n * @param tickets The number of tickets to remove, or undefined if all tickets are to be removed.\r\n * @returns The Lotto instance.\r\n */\r\n Lotto.prototype.remove = function (participant, tickets) {\r\n // Attempt to get the existing participant.\r\n var existingParticipant = this._participants.find(function (part) { return part.participant === participant; });\r\n // There is nothing to do if the specified participant isn't even part of the lotto.\r\n if (!existingParticipant) {\r\n return this;\r\n }\r\n // Check whether a tickets value was given.\r\n if (tickets !== undefined) {\r\n // Check that we have a valid ticket count.\r\n if (!(0, Utilities_1.isNaturalNumber)(tickets)) {\r\n throw new Error(\"tickets value must be a natural number\");\r\n }\r\n existingParticipant.tickets -= tickets;\r\n // If the participant no longer holds any tickets then they should be removed.\r\n if (existingParticipant.tickets < 1) {\r\n this._participants = this._participants.filter(function (part) { return part !== existingParticipant; });\r\n }\r\n }\r\n else {\r\n // We are removing all tickets for the participant so just remove them from the lotto.\r\n this._participants = this._participants.filter(function (part) { return part !== existingParticipant; });\r\n }\r\n return this;\r\n };\r\n /**\r\n * Draw a winning ticket and return the participant that holds the ticket.\r\n * @param options The draw options.\r\n * @returns The participant that holds the winning ticket.\r\n */\r\n Lotto.prototype.draw = function (options) {\r\n if (options === void 0) { options = {}; }\r\n // If we have no participants then just return null.\r\n if (this._participants.length === 0) {\r\n return null;\r\n }\r\n var redrawable = (0, Utilities_1.isNullOrUndefined)(options.redrawable) ? true : options.redrawable;\r\n var pickable = [];\r\n this._participants.forEach(function (_a) {\r\n var participant = _a.participant, tickets = _a.tickets;\r\n for (var ticketCount = 0; ticketCount < tickets; ticketCount++) {\r\n pickable.push(participant);\r\n }\r\n });\r\n var random;\r\n // We need a random floating-point number between 0 (inclusive) and 1 to scale up to pick our winner.\r\n // If a custom random function exists then we should use that or fall back to Math.random().\r\n if (this._customRandom) {\r\n // Call our custom random function to get a random floating-point number.\r\n random = this._customRandom();\r\n // Verify that the result of calling our custom random function is a number between 0 (inclusive) and 1.\r\n if (typeof random !== \"number\" || random < 0 || random >= 1) {\r\n throw new Error(\"the 'random' function provided did not return a number between 0 (inclusive) and 1\");\r\n }\r\n }\r\n else {\r\n // No custom random function was defined so just use good ol' Math.random().\r\n random = Math.random();\r\n }\r\n // Pick a winning participant.\r\n var winner = pickable[Math.floor(random * pickable.length)];\r\n // If the ticket isn't redrawable then we should remove a ticket from the winning participants ticket count.\r\n if (!redrawable) {\r\n this.remove(winner, 1);\r\n }\r\n // Return the winning participant.\r\n return winner;\r\n };\r\n /**\r\n * Draws multiple winning tickets and return an array of the participants that hold the winning tickets.\r\n * @param tickets The number of winning tickets to draw.\r\n * @param options The draw multiple options.\r\n * @returns An array of the participants that hold the winning tickets.\r\n */\r\n Lotto.prototype.drawMultiple = function (tickets, options) {\r\n if (options === void 0) { options = {}; }\r\n var uniqueResults = (0, Utilities_1.isNullOrUndefined)(options.unique) ? false : options.unique;\r\n // Handle cases where the user has asked for zero tickets (no idea why they would do this be we should trust them).\r\n if (tickets === 0) {\r\n return [];\r\n }\r\n // Now that we know out tickets value is not zero we should check that it is a valid natural number.\r\n if (!(0, Utilities_1.isNaturalNumber)(tickets)) {\r\n throw new Error(\"tickets value must be a natural number\");\r\n }\r\n var result = [];\r\n // Keep drawing tickets until we either reach the number of required tickets or we simply run out of tickets to draw.\r\n // We can run out of tickets to draw if 'options.redrawable' is explicity 'false' or we just had no participants when 'drawMultiple' was called.\r\n while (result.length < tickets && this._participants.length > 0) {\r\n result.push(this.draw(options));\r\n }\r\n // If the 'unique' draw option is set then we need to remove duplicates from the result list.\r\n if (uniqueResults) {\r\n // Create an array to store our unique results.\r\n var unique = [];\r\n // Iterate over all of our participants (with potential duplicates) and populate our array of unique values.\r\n for (var _i = 0, result_1 = result; _i < result_1.length; _i++) {\r\n var participant = result_1[_i];\r\n if (unique.indexOf(participant) === -1) {\r\n unique.push(participant);\r\n }\r\n }\r\n result = unique;\r\n }\r\n return result;\r\n };\r\n return Lotto;\r\n}());\r\nexports.Lotto = Lotto;\r\n", "\"use strict\";\r\nObject.defineProperty(exports, \"__esModule\", { value: true });\r\nexports.createLotto = void 0;\r\nvar Lotto_1 = require(\"./Lotto\");\r\n/**\r\n * A function that creates and returns a Lotto instance.\r\n * @param participantsOrOptions An array of initial participants or options relating to the creation of a Lotto instance.\r\n * @returns A new Lotto instance.\r\n */\r\nfunction createLotto(participantsOrOptions) {\r\n // If no initial participants or lotto options were provided as an argument then we can just return a new lotto instance now.\r\n if (!participantsOrOptions) {\r\n return new Lotto_1.Lotto();\r\n }\r\n // Check whether we were provided with an array of initial participants or a lotto options object.\r\n if (Array.isArray(participantsOrOptions)) {\r\n // We are dealing with a pre-defined array of participants.\r\n var participants = participantsOrOptions;\r\n var lotto_1 = new Lotto_1.Lotto();\r\n // If the lotto participants have been defined upfront then we will need to add them all to our lotto instance now.\r\n participants.forEach(function (_a) {\r\n var participant = _a[0], tokens = _a[1];\r\n return lotto_1.add(participant, tokens);\r\n });\r\n // Return the Lotto instance.\r\n return lotto_1;\r\n }\r\n else {\r\n // We are dealing with some lotto options.\r\n var random = participantsOrOptions.random, participants = participantsOrOptions.participants;\r\n // Create a Lotto instance passing the custom RNG function to use in place of Math.random() (which could be undefined).\r\n var lotto_2 = new Lotto_1.Lotto(random);\r\n // If the lotto participants have been defined upfront as part of the options then we will need to add them all to our lotto instance now.\r\n if (participants) {\r\n participants.forEach(function (_a) {\r\n var participant = _a[0], tokens = _a[1];\r\n return lotto_2.add(participant, tokens);\r\n });\r\n }\r\n // Return the Lotto instance.\r\n return lotto_2;\r\n }\r\n}\r\nexports.createLotto = createLotto;\r\n", "\"use strict\";\r\nObject.defineProperty(exports, \"__esModule\", { value: true });\r\nvar createLotto_1 = require(\"./createLotto\");\r\nexports.default = createLotto_1.createLotto;\r\n", "import State from \"./State\";\nimport { validateDefinition } from \"./BehaviourTreeDefinitionValidator\";\nimport { convertMDSLToJSON } from \"./mdsl/MDSLDefinitionParser\";\nimport { BehaviourTree, FlattenedTreeNode } from \"./BehaviourTree\";\nimport { BehaviourTreeOptions } from \"./BehaviourTreeOptions\";\n\nexport { BehaviourTree, State, convertMDSLToJSON, validateDefinition };\nexport type { FlattenedTreeNode, BehaviourTreeOptions };\n", "/**\n * Enumeration of node state types.\n */\nexport enum State {\n READY = \"mistreevous.ready\",\n RUNNING = \"mistreevous.running\",\n SUCCEEDED = \"mistreevous.succeeded\",\n FAILED = \"mistreevous.failed\"\n}\n\nexport { State as default };\n\nexport type CompleteState = State.SUCCEEDED | State.FAILED;\nexport type AnyState = State.READY | State.RUNNING | CompleteState;\n", "import {\n NodeDefinition,\n RootNodeDefinition,\n DecoratorNodeDefinition,\n CompositeNodeDefinition,\n AnyNodeDefinition,\n BranchNodeDefinition\n} from \"./BehaviourTreeDefinition\";\n\n/**\n * A type guard function that returns true if the specified node satisfies the RootNodeDefinition type.\n * @param node The node.\n * @returns A value of true if the specified node satisfies the RootNodeDefinition type.\n */\nexport function isRootNode(node: NodeDefinition): node is RootNodeDefinition {\n return node.type === \"root\";\n}\n\n/**\n * A type guard function that returns true if the specified node satisfies the BranchNodeDefinition type.\n * @param node The node.\n * @returns A value of true if the specified node satisfies the BranchNodeDefinition type.\n */\nexport function isBranchNode(node: NodeDefinition): node is BranchNodeDefinition {\n return node.type === \"branch\";\n}\n\n/**\n * A type guard function that returns true if the specified node satisfies the NodeDefinition type.\n * @param node The node.\n * @returns A value of true if the specified node satisfies the NodeDefinition type.\n */\nexport function isLeafNode(node: NodeDefinition): node is NodeDefinition {\n return [\"branch\", \"action\", \"condition\", \"wait\"].includes(node.type);\n}\n\n/**\n * A type guard function that returns true if the specified node satisfies the DecoratorNodeDefinition type.\n * @param node The node.\n * @returns A value of true if the specified node satisfies the DecoratorNodeDefinition type.\n */\nexport function isDecoratorNode(node: NodeDefinition): node is DecoratorNodeDefinition {\n return [\"root\", \"repeat\", \"retry\", \"flip\", \"succeed\", \"fail\"].includes(node.type);\n}\n\n/**\n * A type guard function that returns true if the specified node satisfies the CompositeNodeDefinition type.\n * @param node The node.\n * @returns A value of true if the specified node satisfies the CompositeNodeDefinition type.\n */\nexport function isCompositeNode(node: NodeDefinition): node is CompositeNodeDefinition {\n return [\"sequence\", \"selector\", \"lotto\", \"parallel\"].includes(node.type);\n}\n\n/**\n * Flatten a node definition into an array of all of its nested node definitions.\n * @param nodeDefinition The node definition to flatten.\n * @returns An array of all of nested node definitions.\n */\nexport function flattenDefinition(nodeDefinition: AnyNodeDefinition): AnyNodeDefinition[] {\n const nodes: AnyNodeDefinition[] = [];\n\n const processNode = (currentNodeDefinition: AnyNodeDefinition) => {\n nodes.push(currentNodeDefinition);\n\n if (isCompositeNode(currentNodeDefinition)) {\n currentNodeDefinition.children.forEach(processNode);\n } else if (isDecoratorNode(currentNodeDefinition)) {\n processNode(currentNodeDefinition.child);\n }\n };\n\n processNode(nodeDefinition);\n\n return nodes;\n}\n\n/**\n * Determines whether the passed value is an integer.\n * @param value The value to check.\n * @returns Whether the passed value is an integer.\n */\nexport function isInteger(value: unknown): boolean {\n return typeof value === \"number\" && Math.floor(value) === value;\n}\n\n/**\n * Determines whether the passed value is null or undefined.\n * @param value The value to check.\n * @returns Whether the passed value is null or undefined.\n */\nexport function isNullOrUndefined(value: unknown): boolean {\n return typeof value === \"undefined\" || value === null;\n}\n", "/**\n * A type defining an object that holds a reference to substitued string literals parsed from the definition.\n */\nexport type StringLiteralPlaceholders = { [key: string]: string };\n\n/**\n * Pop the next raw token from the specified array of tokens and throw an error if it wasn't the expected one.\n * @param tokens The array of tokens.\n * @param expected An optional string or array or items, one of which must match the next popped token.\n * @returns The popped token.\n */\nexport function popAndCheck(tokens: string[], expected?: string | string[]): string {\n // Get and remove the next token.\n const popped = tokens.shift();\n\n // We were expecting another token but there aren't any.\n if (popped === undefined) {\n throw new Error(\"unexpected end of definition\");\n }\n\n // Do we have an expected token/tokens array?\n if (expected != undefined) {\n // Get an array of expected values, if the popped token matches any then we are all good.\n const expectedValues = typeof expected === \"string\" ? [expected] : expected;\n\n // Check whether the popped token matches at least one of our expected items.\n var tokenMatchesExpectation = expectedValues.some((item) => popped.toUpperCase() === item.toUpperCase());\n\n // Throw an error if the popped token didn't match any of our expected items.\n if (!tokenMatchesExpectation) {\n const expectationString = expectedValues.map((item) => \"'\" + item + \"'\").join(\" or \");\n throw new Error(\"unexpected token found. Expected \" + expectationString + \" but got '\" + popped + \"'\");\n }\n }\n\n // Return the popped token.\n return popped;\n}\n\n/**\n * Swaps out any node/attribute argument string literals with placeholders.\n * @param definition The definition.\n * @returns An object containing a mapping of placeholders to original string values as well as the processed definition string.\n */\nexport function substituteStringLiterals(definition: string): {\n placeholders: StringLiteralPlaceholders;\n processedDefinition: string;\n} {\n // Create an object to hold the mapping of placeholders to original string values.\n const placeholders: StringLiteralPlaceholders = {};\n\n // Replace any string literals wrapped with double quotes in our definition with placeholders to be processed later.\n const processedDefinition = definition.replace(/\\\"(\\\\.|[^\"\\\\])*\\\"/g, (match) => {\n var strippedMatch = match.substring(1, match.length - 1);\n var placeholder = Object.keys(placeholders).find((key) => placeholders[key] === strippedMatch);\n\n // If we have no existing string literal match then create a new placeholder.\n if (!placeholder) {\n placeholder = `@@${Object.keys(placeholders).length}@@`;\n placeholders[placeholder] = strippedMatch;\n }\n\n return placeholder;\n });\n\n return { placeholders, processedDefinition };\n}\n\n/**\n * Parse the tree definition into an array of raw tokens.\n * @param definition The definition.\n * @returns An array of tokens parsed from the definition.\n */\nexport function parseTokensFromDefinition(definition: string): string[] {\n // Add some space around various important characters so that they can be plucked out easier as individual tokens.\n definition = definition.replace(/\\(/g, \" ( \");\n definition = definition.replace(/\\)/g, \" ) \");\n definition = definition.replace(/\\{/g, \" { \");\n definition = definition.replace(/\\}/g, \" } \");\n definition = definition.replace(/\\]/g, \" ] \");\n definition = definition.replace(/\\[/g, \" [ \");\n definition = definition.replace(/\\,/g, \" , \");\n\n // Split the definition into raw token form and return it.\n return definition.replace(/\\s+/g, \" \").trim().split(\" \");\n}\n", "import { StringLiteralPlaceholders, popAndCheck } from \"./MDSLUtilities\";\n\n/**\n * A type representing any node function argument.\n */\ntype Argument = {\n /**\n * The argument value.\n */\n value: T;\n /**\n * The argument type, used for validation.\n */\n type: string;\n};\n\ntype NullArgument = Argument & {\n type: \"null\";\n};\n\ntype BooleanArgument = Argument & {\n type: \"boolean\";\n};\n\ntype NumberArgument = Argument & {\n type: \"number\";\n /**\n * A flag defining whether the number argument value is a valid integer. (used for validation)\n */\n isInteger: boolean;\n};\n\ntype StringPlaceholderArgument = Argument & {\n type: \"string\";\n};\n\ntype IdentifierArgument = Argument & {\n type: \"identifier\";\n};\n\n/**\n * A type representing a reference to any node function argument.\n */\ntype AnyArgument = NullArgument | BooleanArgument | NumberArgument | StringPlaceholderArgument | IdentifierArgument;\n\n/**\n * Parse an array of argument definitions from the specified tokens array.\n * @param tokens The array tokens to parse the argument definitions from.\n * @param stringArgumentPlaceholders The mapping of string literal node argument placeholders to original values.\n * @param argumentValidator The argument validator function.\n * @param validationFailedMessage The exception message to throw if argument validation fails.\n * @returns An array of argument definitions parsed from the specified tokens array.\n */\nexport function parseArgumentTokens(\n tokens: string[],\n stringArgumentPlaceholders: StringLiteralPlaceholders\n): AnyArgument[] {\n const argumentList: AnyArgument[] = [];\n\n // If the next token is not a '[' or '(' then we have no arguments to parse.\n if (![\"[\", \"(\"].includes(tokens[0])) {\n return argumentList;\n }\n\n // Any lists of arguments will always be wrapped in '[]' for node arguments or '()' for attribute arguments.\n // We are looking for a '[' or '(' opener that wraps the argument tokens and the relevant closer.\n const closingToken = popAndCheck(tokens, [\"[\", \"(\"]) === \"[\" ? \"]\" : \")\";\n\n const argumentListTokens: string[] = [];\n\n // Grab all tokens between the '[' and ']' or '(' and ')'.\n while (tokens.length && tokens[0] !== closingToken) {\n // The next token is part of our arguments list.\n argumentListTokens.push(tokens.shift()!);\n }\n\n // Validate the order of the argument tokens. Each token must either be a ',' or a single argument that satisfies the validator.\n argumentListTokens.forEach((token, index) => {\n // Get whether this token should be an actual argument.\n const shouldBeArgumentToken = !(index & 1);\n\n // If the current token should be an actual argument then validate it, otherwise it should be a ',' token.\n if (shouldBeArgumentToken) {\n // Get the argument definition.\n const argumentDefinition = getArgumentDefinition(token, stringArgumentPlaceholders);\n\n // This is a valid argument!\n argumentList.push(argumentDefinition);\n } else {\n // The current token should be a ',' token.\n if (token !== \",\") {\n throw new Error(`invalid argument list, expected ',' or ']' but got '${token}'`);\n }\n }\n });\n\n // The arguments list should terminate with a ']' or ')' token, depending on the opener.\n popAndCheck(tokens, closingToken);\n\n // Return the arguments.\n return argumentList;\n}\n\n/**\n * Gets an argument value definition.\n * @param token The argument token.\n * @param stringArgumentPlaceholders The mapping of string literal node argument placeholders to original values.\n * @returns An argument value definition.\n */\nfunction getArgumentDefinition(token: string, stringArgumentPlaceholders: StringLiteralPlaceholders): AnyArgument {\n // Check whether the token represents a null value.\n if (token === \"null\") {\n return {\n value: null,\n type: \"null\"\n } as NullArgument;\n }\n\n // Check whether the token represents a boolean value.\n if (token === \"true\" || token === \"false\") {\n return {\n value: token === \"true\",\n type: \"boolean\"\n } as BooleanArgument;\n }\n\n // Check whether the token represents a number value.\n // TODO: Relies on broken isNaN - see MDN.\n // if (!Number.isNaN(token)) {\n if (!isNaN(token as any)) {\n return {\n value: parseFloat(token),\n isInteger: parseFloat(token) === parseInt(token, 10),\n type: \"number\"\n } as NumberArgument;\n }\n\n // Check whether the token is a placeholder (e.g. @@0@@) representing a string literal.\n if (token.match(/^@@\\d+@@$/g)) {\n return {\n value: stringArgumentPlaceholders[token].replace('\\\\\"', '\"'),\n type: \"string\"\n } as StringPlaceholderArgument;\n }\n\n // The only remaining option is that the argument value is an identifier.\n return {\n value: token,\n type: \"identifier\"\n } as IdentifierArgument;\n}\n", "import { NodeAttributeDefinition } from \"../BehaviourTreeDefinition\";\nimport { parseArgumentTokens } from \"./MDSLNodeArgumentParser\";\nimport { StringLiteralPlaceholders } from \"./MDSLUtilities\";\n\n/**\n * A type defining the attribute definitions of a node.\n */\ntype NodeAttributes = {\n while?: NodeAttributeDefinition;\n until?: NodeAttributeDefinition;\n entry?: NodeAttributeDefinition;\n exit?: NodeAttributeDefinition;\n step?: NodeAttributeDefinition;\n};\n\n/**\n * Parse any node attribute definitions from the specified tokens array.\n * @param tokens The array of remaining tokens.\n * @param stringArgumentPlaceholders The mapping of string literal node argument placeholders to original values.\n * @returns An object of attribute definitions defined by any directly following tokens.\n */\nexport function parseAttributeTokens(\n tokens: string[],\n stringArgumentPlaceholders: StringLiteralPlaceholders\n): NodeAttributes {\n const nodeAttributeNames: (keyof NodeAttributes)[] = [\"while\", \"until\", \"entry\", \"exit\", \"step\"];\n\n // Create an object to hold any attributes found.\n const attributes: NodeAttributes = {};\n\n // Try to get the name of the attribute for the next token.\n let nextAttributeName = tokens[0]?.toLowerCase() as keyof NodeAttributes;\n\n // Pull attribute tokens as well as their arguments off of the tokens stack until we have no more.\n while (nodeAttributeNames.includes(nextAttributeName)) {\n // Check to make sure that we have not already created an attribute definition of this type.\n if (attributes[nextAttributeName]) {\n throw new Error(`duplicate attribute '${tokens[0].toUpperCase()}' found for node`);\n }\n\n // Remove the attribute name token from the array of tokens.\n tokens.shift();\n\n // Grab the attribute arguments, assuming the first to be an identifier.\n const [attributeCallIdentifier, ...attributeArguments] = parseArgumentTokens(\n tokens,\n stringArgumentPlaceholders\n );\n\n // The first attribute argument has to be an identifer, this will reference an agent function.\n if (attributeCallIdentifier?.type !== \"identifier\") {\n throw new Error(\"expected agent function or registered function name identifier argument for attribute\");\n }\n\n // Any attribute arguments (other than the expected call identifier) must have a type of string, number, boolean or null.\n attributeArguments\n .filter((arg) => arg.type === \"identifier\")\n .forEach((arg) => {\n throw new Error(\n `invalid attribute argument value '${arg.value}', must be string, number, boolean or null`\n );\n });\n\n // Create the attribute definition and add it to the object of attribute definitions found.\n attributes[nextAttributeName] = {\n call: attributeCallIdentifier.value,\n args: attributeArguments.map(({ value }) => value)\n };\n\n // Try to get the next attribute name token, as there could be multiple.\n nextAttributeName = tokens[0]?.toLowerCase() as keyof NodeAttributes;\n }\n\n return attributes;\n}\n", "import {\n ActionNodeDefinition,\n AnyChildNodeDefinition,\n AnyNodeDefinition,\n BranchNodeDefinition,\n ConditionNodeDefinition,\n FailNodeDefinition,\n FlipNodeDefinition,\n LottoNodeDefinition,\n ParallelNodeDefinition,\n RepeatNodeDefinition,\n RetryNodeDefinition,\n RootNodeDefinition,\n SelectorNodeDefinition,\n SequenceNodeDefinition,\n SucceedNodeDefinition,\n WaitNodeDefinition\n} from \"../BehaviourTreeDefinition\";\nimport {\n isCompositeNode,\n isDecoratorNode,\n isLeafNode,\n isNullOrUndefined,\n isRootNode\n} from \"../BehaviourTreeDefinitionUtilities\";\nimport { parseArgumentTokens } from \"./MDSLNodeArgumentParser\";\nimport { parseAttributeTokens } from \"./MDSLNodeAttributeParser\";\nimport {\n StringLiteralPlaceholders,\n parseTokensFromDefinition,\n popAndCheck,\n substituteStringLiterals\n} from \"./MDSLUtilities\";\n\n/**\n * Convert the MDSL tree definition string into an equivalent JSON definition.\n * @param definition The tree definition string as MDSL.\n * @returns The root node JSON definitions.\n */\nexport function convertMDSLToJSON(definition: string): RootNodeDefinition[] {\n // Swap out any node/attribute argument string literals with a placeholder and get a mapping of placeholders to original values as well as the processed definition.\n const { placeholders, processedDefinition } = substituteStringLiterals(definition);\n\n // Parse our definition definition string into an array of raw tokens.\n const tokens = parseTokensFromDefinition(processedDefinition);\n\n return convertTokensToJSONDefinition(tokens, placeholders);\n}\n\n/**\n * Converts the specified tree definition tokens into a JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The root node JSON definitions.\n */\nfunction convertTokensToJSONDefinition(\n tokens: string[],\n stringLiteralPlaceholders: StringLiteralPlaceholders\n): RootNodeDefinition[] {\n // There must be at least 3 tokens for the tree definition to be valid. 'ROOT', '{' and '}'.\n if (tokens.length < 3) {\n throw new Error(\"invalid token count\");\n }\n\n // We should have a matching number of '{' and '}' tokens. If not, then there are scopes that have not been properly closed.\n if (tokens.filter((token) => token === \"{\").length !== tokens.filter((token) => token === \"}\").length) {\n throw new Error(\"scope character mismatch\");\n }\n\n // Create an array of tree stack arrays where root nodes will always be at the botton and the current composite/decorator node at the top.\n // There should be an element in this array for every root node defined and every element should be an array with a root note as the first element.\n // E.g. A definition with two root nodes defined:\n // [\n // [root, lotto, sequence],\n // [root, selector]\n // ]\n const treeStacks: [Partial, ...Partial[]][] = [];\n\n // Create an array of all root node definitions that we create.\n const rootNodes: Partial[] = [];\n\n // A helper function used to push node definitions onto the tree stack.\n const pushNode = (node: AnyNodeDefinition) => {\n // If the node is a root node then we need to create a new tree stack array with the root node at the root.\n if (isRootNode(node)) {\n // We need to double-check that this root node is not the child of another node.\n // We can do this by checking whether the top tree stack is not empty (contains an existing node)\n if (treeStacks[treeStacks.length - 1]?.length) {\n throw new Error(\"a root node cannot be the child of another node\");\n }\n\n // Add the root node definition to our array of all parsed root node definitions.\n rootNodes.push(node);\n\n // Add the root node definition to the root of a new tree stack.\n treeStacks.push([node]);\n\n return;\n }\n\n // All non-root nodes should be pushed after their root nodes so handle cases\n // where we may not have any tree stacks or our top-most tree stack is empty.\n if (!treeStacks.length || !treeStacks[treeStacks.length - 1].length) {\n throw new Error(\"expected root node at base of definition\");\n }\n\n // Get the current tree stack that we are populating.\n const topTreeStack = treeStacks[treeStacks.length - 1];\n\n // Get the top-most node in the current tree stack, this will be a composite/decorator node\n // for which we will populate its children array if composite or setting its child if a decorator.\n const topTreeStackTopNode = topTreeStack[topTreeStack.length - 1] as AnyNodeDefinition;\n\n // If the top-most node in the current root stack is a composite or decorator\n // node then the current node should be added as a child of the top-most node.\n if (isCompositeNode(topTreeStackTopNode)) {\n topTreeStackTopNode.children = topTreeStackTopNode.children || [];\n topTreeStackTopNode.children.push(node);\n } else if (isDecoratorNode(topTreeStackTopNode)) {\n // If the top node already has a child node set then throw an error as a decorator should only have a single child.\n if (topTreeStackTopNode.child) {\n throw new Error(\"a decorator node must only have a single child node\");\n }\n\n topTreeStackTopNode.child = node;\n }\n\n // If the node we are adding is also a composite or decorator node, then we should push it\n // onto the current tree stack, as subsequent nodes will be added as its child/children.\n if (!isLeafNode(node)) {\n topTreeStack.push(node);\n }\n };\n\n // A helper function used to pop the top-most node definition off of the tree stack and return it.\n const popNode = (): AnyNodeDefinition | null => {\n let poppedNode: AnyNodeDefinition | null = null;\n\n // Get the current tree stack that we are populating.\n const topTreeStack = treeStacks[treeStacks.length - 1];\n\n // Pop the top-most node in the current tree stack if there is one.\n if (topTreeStack.length) {\n poppedNode = topTreeStack.pop() as AnyNodeDefinition;\n }\n\n // We don't want any empty tree stacks in our stack of tree stacks.\n if (!topTreeStack.length) {\n treeStacks.pop();\n }\n\n return poppedNode;\n };\n\n // We should keep processing the raw tokens until we run out of them.\n while (tokens.length) {\n // Grab the next token.\n const token = tokens.shift()!;\n\n // How we create the next node depends on the current raw token value.\n switch (token.toUpperCase()) {\n case \"ROOT\": {\n pushNode(createRootNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"SUCCEED\": {\n pushNode(createSucceedNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"FAIL\": {\n pushNode(createFailNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"FLIP\": {\n pushNode(createFlipNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"REPEAT\": {\n pushNode(createRepeatNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"RETRY\": {\n pushNode(createRetryNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"SEQUENCE\": {\n pushNode(createSequenceNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"SELECTOR\": {\n pushNode(createSelectorNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"PARALLEL\": {\n pushNode(createParallelNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"LOTTO\": {\n pushNode(createLottoNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"ACTION\": {\n pushNode(createActionNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"CONDITION\": {\n pushNode(createConditionNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"WAIT\": {\n pushNode(createWaitNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"BRANCH\": {\n pushNode(createBranchNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"}\": {\n // The '}' character closes the current scope and means that we have to pop a node off of the current stack.\n const poppedNode = popNode();\n\n // Now that we have a node definition we can carry out any validation that may require the node to be fully populated.\n if (poppedNode) {\n validatePoppedNode(poppedNode);\n }\n\n break;\n }\n\n default: {\n throw new Error(`unexpected token: ${token}`);\n }\n }\n }\n\n return rootNodes as RootNodeDefinition[];\n}\n\n/**\n * Creates a root node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The root node JSON definition.\n */\nfunction createRootNode(tokens: string[], stringLiteralPlaceholders: StringLiteralPlaceholders): RootNodeDefinition {\n // Create the root node definition.\n let node = {\n type: \"root\"\n } as Partial;\n\n // Parse any node arguments, we should only have one if any which will be an identifier argument for the root identifier.\n const nodeArguments = parseArgumentTokens(tokens, stringLiteralPlaceholders);\n\n // Check whether any node arguments were defined.\n if (nodeArguments.length) {\n // We should only have one argument, if any, which will be an identifier argument for the root identifier.\n if (nodeArguments.length === 1 && nodeArguments[0].type === \"identifier\") {\n // The root node identifier will be the first and only node argument value.\n node.id = nodeArguments[0].value as string;\n } else {\n throw new Error(\"expected single root name argument\");\n }\n }\n\n // Grab any node attribute definitions and spread them into the node definition.\n node = { ...node, ...parseAttributeTokens(tokens, stringLiteralPlaceholders) };\n\n // This is a decorator node, so we expect an opening '{'.\n popAndCheck(tokens, \"{\");\n\n // Return the root node definition.\n return node as RootNodeDefinition;\n}\n\n/**\n * Creates a succeed node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The succeed node JSON definition.\n */\nfunction createSucceedNode(\n tokens: string[],\n stringLiteralPlaceholders: StringLiteralPlaceholders\n): SucceedNodeDefinition {\n const node = {\n type: \"succeed\",\n ...parseAttributeTokens(tokens, stringLiteralPlaceholders)\n } as SucceedNodeDefinition;\n\n // This is a decorator node, so we expect an opening '{'.\n popAndCheck(tokens, \"{\");\n\n // Return the succeed node definition.\n return node;\n}\n\n/**\n * Creates a fail node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The fail node JSON definition.\n */\nfunction createFailNode(tokens: string[], stringLiteralPlaceholders: StringLiteralPlaceholders): FailNodeDefinition {\n const node = {\n type: \"fail\",\n ...parseAttributeTokens(tokens, stringLiteralPlaceholders)\n } as FailNodeDefinition;\n\n // This is a decorator node, so we expect an opening '{'.\n popAndCheck(tokens, \"{\");\n\n // Return the fail node definition.\n return node;\n}\n\n/**\n * Creates a flip node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The flip node JSON definition.\n */\nfunction createFlipNode(tokens: string[], stringLiteralPlaceholders: StringLiteralPlaceholders): FlipNodeDefinition {\n const node = {\n type: \"flip\",\n ...parseAttributeTokens(tokens, stringLiteralPlaceholders)\n } as FlipNodeDefinition;\n\n // This is a decorator node, so we expect an opening '{'.\n popAndCheck(tokens, \"{\");\n\n // Return the flip node definition.\n return node;\n}\n\n/**\n * Creates a repeat node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The repeat node JSON definition.\n */\nfunction createRepeatNode(\n tokens: string[],\n stringLiteralPlaceholders: StringLiteralPlaceholders\n): RepeatNodeDefinition {\n let node = { type: \"repeat\" } as RepeatNodeDefinition;\n\n // Get the node arguments.\n const nodeArguments = parseArgumentTokens(tokens, stringLiteralPlaceholders);\n\n // The arguments of a repeat node are optional. We may have:\n // - No node arguments, in which case the repeat note will iterate indefinitely.\n // - One node argument which will be the explicit number of iterations to make.\n // - Two node arguments which define the min and max iteration bounds from which a random iteration count will be picked.\n if (nodeArguments.length) {\n // All repeat node arguments MUST be of type number and must be integer.\n nodeArguments\n .filter((arg) => arg.type !== \"number\" || !arg.isInteger)\n .forEach(() => {\n throw new Error(`repeat node iteration counts must be integer values`);\n });\n\n // We should have got one or two iteration counts.\n if (nodeArguments.length === 1) {\n // A static iteration count was defined.\n node.iterations = nodeArguments[0].value as number;\n\n // A repeat node must have a positive number of iterations if defined.\n if (node.iterations < 0) {\n throw new Error(\"a repeat node must have a positive number of iterations if defined\");\n }\n } else if (nodeArguments.length === 2) {\n // A minimum and maximum iteration count was defined.\n node.iterations = [nodeArguments[0].value as number, nodeArguments[1].value as number];\n\n // A repeat node must have a positive min and max iteration count if they are defined.\n if (node.iterations[0] < 0 || node.iterations[1] < 0) {\n throw new Error(\"a repeat node must have a positive minimum and maximum iteration count if defined\");\n }\n\n // A repeat node must not have an minimum iteration count that exceeds the maximum iteration count.\n if (node.iterations[0] > node.iterations[1]) {\n throw new Error(\n \"a repeat node must not have a minimum iteration count that exceeds the maximum iteration count\"\n );\n }\n } else {\n // An incorrect number of iteration counts was defined.\n throw new Error(\"invalid number of repeat node iteration count arguments defined\");\n }\n }\n\n // Grab any node attribute definitions and spread them into the node definition.\n node = { ...node, ...parseAttributeTokens(tokens, stringLiteralPlaceholders) };\n\n // This is a decorator node, so we expect an opening '{'.\n popAndCheck(tokens, \"{\");\n\n // Return the repeat node definition.\n return node;\n}\n\n/**\n * Creates a retry node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The retry node JSON definition.\n */\nfunction createRetryNode(tokens: string[], stringLiteralPlaceholders: StringLiteralPlaceholders): RetryNodeDefinition {\n let node = { type: \"retry\" } as RetryNodeDefinition;\n\n // Get the node arguments.\n const nodeArguments = parseArgumentTokens(tokens, stringLiteralPlaceholders);\n\n // The arguments of a retry node are optional. We may have:\n // - No node arguments, in which case the retry note will attempt indefinitely.\n // - One node argument which will be the explicit number of attempts to make.\n // - Two node arguments which define the min and max attempt bounds from which a random attempt count will be picked.\n if (nodeArguments.length) {\n // All retry node arguments MUST be of type number and must be integer.\n nodeArguments\n .filter((arg) => arg.type !== \"number\" || !arg.isInteger)\n .forEach(() => {\n throw new Error(`retry node attempt counts must be integer values`);\n });\n\n // We should have got one or two attempt counts.\n if (nodeArguments.length === 1) {\n // A static attempt count was defined.\n node.attempts = nodeArguments[0].value as number;\n\n // A retry node must have a positive number of attempts if defined.\n if (node.attempts < 0) {\n throw new Error(\"a retry node must have a positive number of attempts if defined\");\n }\n } else if (nodeArguments.length === 2) {\n // A minimum and maximum attempt count was defined.\n node.attempts = [nodeArguments[0].value as number, nodeArguments[1].value as number];\n\n // A retry node must have a positive min and max attempts count if they are defined.\n if (node.attempts[0] < 0 || node.attempts[1] < 0) {\n throw new Error(\"a retry node must have a positive minimum and maximum attempt count if defined\");\n }\n\n // A retry node must not have a minimum attempt count that exceeds the maximum attempt count.\n if (node.attempts[0] > node.attempts[1]) {\n throw new Error(\n \"a retry node must not have a minimum attempt count that exceeds the maximum attempt count\"\n );\n }\n } else {\n // An incorrect number of attempt counts was defined.\n throw new Error(\"invalid number of retry node attempt count arguments defined\");\n }\n }\n\n // Grab any node attribute definitions and spread them into the node definition.\n node = { ...node, ...parseAttributeTokens(tokens, stringLiteralPlaceholders) };\n\n // This is a decorator node, so we expect an opening '{'.\n popAndCheck(tokens, \"{\");\n\n // Return the retry node definition.\n return node;\n}\n\n/**\n * Creates a sequence node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The sequence node JSON definition.\n */\nfunction createSequenceNode(\n tokens: string[],\n stringLiteralPlaceholders: StringLiteralPlaceholders\n): SequenceNodeDefinition {\n const node = {\n type: \"sequence\",\n ...parseAttributeTokens(tokens, stringLiteralPlaceholders)\n } as SequenceNodeDefinition;\n\n // This is a composite node, so we expect an opening '{'.\n popAndCheck(tokens, \"{\");\n\n // Return the sequence node definition.\n return node;\n}\n\n/**\n * Creates a selector node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The selector node JSON definition.\n */\nfunction createSelectorNode(\n tokens: string[],\n stringLiteralPlaceholders: StringLiteralPlaceholders\n): SelectorNodeDefinition {\n const node = {\n type: \"selector\",\n ...parseAttributeTokens(tokens, stringLiteralPlaceholders)\n } as SelectorNodeDefinition;\n\n // This is a composite node, so we expect an opening '{'.\n popAndCheck(tokens, \"{\");\n\n // Return the selector node definition.\n return node;\n}\n\n/**\n * Creates a parallel node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The parallel node JSON definition.\n */\nfunction createParallelNode(\n tokens: string[],\n stringLiteralPlaceholders: StringLiteralPlaceholders\n): ParallelNodeDefinition {\n const node = {\n type: \"parallel\",\n ...parseAttributeTokens(tokens, stringLiteralPlaceholders)\n } as ParallelNodeDefinition;\n\n // This is a composite node, so we expect an opening '{'.\n popAndCheck(tokens, \"{\");\n\n // Return the parallel node definition.\n return node;\n}\n\n/**\n * Creates a lotto node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The lotto node JSON definition.\n */\nfunction createLottoNode(tokens: string[], stringLiteralPlaceholders: StringLiteralPlaceholders): LottoNodeDefinition {\n // If any node arguments have been defined then they must be our weights.\n const nodeArguments = parseArgumentTokens(tokens, stringLiteralPlaceholders);\n\n // All lotto node arguments MUST be of type number and must be positive integers.\n nodeArguments\n .filter((arg) => arg.type !== \"number\" || !arg.isInteger || arg.value < 0)\n .forEach(() => {\n throw new Error(`lotto node weight arguments must be positive integer values`);\n });\n\n const node = {\n type: \"lotto\",\n ...parseAttributeTokens(tokens, stringLiteralPlaceholders)\n } as LottoNodeDefinition;\n\n // Apply the weights if any were defined.\n if (nodeArguments.length) {\n node.weights = nodeArguments.map(({ value }) => value) as number[];\n }\n\n // This is a composite node, so we expect an opening '{'.\n popAndCheck(tokens, \"{\");\n\n // Return the lotto node definition.\n return node;\n}\n\n/**\n * Creates an action node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The action node JSON definition.\n */\nfunction createActionNode(\n tokens: string[],\n stringLiteralPlaceholders: StringLiteralPlaceholders\n): ActionNodeDefinition {\n // Parse any node arguments, we should have at least one which will be an identifier argument for the action name\n // and agent function to invoke for the action, all other arguments are to be passed as arguments to that function.\n const [actionNameIdentifier, ...agentFunctionArgs] = parseArgumentTokens(tokens, stringLiteralPlaceholders);\n\n // Our first argument MUST be defined and be an identifier as we require an action name argument.\n if (actionNameIdentifier?.type !== \"identifier\") {\n throw new Error(\"expected action name identifier argument\");\n }\n\n // Only the first argument should have been an identifier, all agent function arguments must be string, number, boolean or null.\n agentFunctionArgs\n .filter((arg) => arg.type === \"identifier\")\n .forEach((arg) => {\n throw new Error(\n `invalid action node argument value '${arg.value}', must be string, number, boolean or null`\n );\n });\n\n // Return the action node definition.\n return {\n type: \"action\",\n call: actionNameIdentifier.value,\n args: agentFunctionArgs.map(({ value }) => value),\n ...parseAttributeTokens(tokens, stringLiteralPlaceholders)\n };\n}\n\n/**\n * Creates a condition node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The condition node JSON definition.\n */\nfunction createConditionNode(\n tokens: string[],\n stringLiteralPlaceholders: StringLiteralPlaceholders\n): ConditionNodeDefinition {\n // Parse any node arguments, we should have at least one which will be an identifier argument for the condition name\n // and agent function to invoke for the condition, all other arguments are to be passed as arguments to that function.\n const [conditionNameIdentifier, ...agentFunctionArgs] = parseArgumentTokens(tokens, stringLiteralPlaceholders);\n\n // Our first argument MUST be defined and be an identifier as we require a condition name argument.\n if (conditionNameIdentifier?.type !== \"identifier\") {\n throw new Error(\"expected condition name identifier argument\");\n }\n\n // Only the first argument should have been an identifier, all agent function arguments must be string, number, boolean or null.\n agentFunctionArgs\n .filter((arg) => arg.type === \"identifier\")\n .forEach((arg) => {\n throw new Error(\n `invalid condition node argument value '${arg.value}', must be string, number, boolean or null`\n );\n });\n\n // Return the condition node definition.\n return {\n type: \"condition\",\n call: conditionNameIdentifier.value,\n args: agentFunctionArgs.map(({ value }) => value),\n ...parseAttributeTokens(tokens, stringLiteralPlaceholders)\n };\n}\n\n/**\n * Creates a wait node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The wait node JSON definition.\n */\nfunction createWaitNode(tokens: string[], stringLiteralPlaceholders: StringLiteralPlaceholders): WaitNodeDefinition {\n let node = { type: \"wait\" } as WaitNodeDefinition;\n\n // Get the node arguments.\n const nodeArguments = parseArgumentTokens(tokens, stringLiteralPlaceholders);\n\n // The arguments of a wait node are optional. We may have:\n // - No node arguments, in which case the wait will be indefinite until it is aborted.\n // - One node argument which will be the explicit duration of the wait.\n // - Two node arguments which define the min and max duration bounds from which a random duration will be picked.\n if (nodeArguments.length) {\n // All wait node arguments MUST be of type number and must be integer.\n nodeArguments\n .filter((arg) => arg.type !== \"number\" || !arg.isInteger)\n .forEach(() => {\n throw new Error(`wait node durations must be integer values`);\n });\n\n // We may have:\n // - One node argument which will be the explicit duration of the wait.\n // - Two node arguments which define the min and max duration bounds from which a random duration will be picked.\n // - Too many arguments, which is not valid.\n if (nodeArguments.length === 1) {\n // An explicit duration was defined.\n node.duration = nodeArguments[0].value as number;\n\n // If an explict duration was defined then it must be a positive number.\n if (node.duration < 0) {\n throw new Error(\"a wait node must have a positive duration\");\n }\n } else if (nodeArguments.length === 2) {\n // Min and max duration bounds were defined from which a random duration will be picked.\n node.duration = [nodeArguments[0].value as number, nodeArguments[1].value as number];\n\n // A wait node must have a positive min and max duration.\n if (node.duration[0] < 0 || node.duration[1] < 0) {\n throw new Error(\"a wait node must have a positive minimum and maximum duration\");\n }\n\n // A wait node must not have a minimum duration that exceeds the maximum duration.\n if (node.duration[0] > node.duration[1]) {\n throw new Error(\"a wait node must not have a minimum duration that exceeds the maximum duration\");\n }\n } else if (nodeArguments.length > 2) {\n // An incorrect number of duration arguments were defined.\n throw new Error(\"invalid number of wait node duration arguments defined\");\n }\n }\n\n // Return the wait node definition.\n return { ...node, ...parseAttributeTokens(tokens, stringLiteralPlaceholders) };\n}\n\n/**\n * Creates a branch node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The branch node JSON definition.\n */\nfunction createBranchNode(\n tokens: string[],\n stringLiteralPlaceholders: StringLiteralPlaceholders\n): BranchNodeDefinition {\n // Parse any node arguments, we should have one which will be an identifier argument for the root ref.\n const nodeArguments = parseArgumentTokens(tokens, stringLiteralPlaceholders);\n\n // We should have only a single identifer argument for a branch node, which is the root ref.\n if (nodeArguments.length !== 1 || nodeArguments[0].type !== \"identifier\") {\n throw new Error(\"expected single branch name argument\");\n }\n\n // Return the branch node definition.\n return { type: \"branch\", ref: nodeArguments[0].value };\n}\n\n/**\n * Validate a fully-populated node definition that was popped off of the tree stack.\n * @param definition The popped node to validate.\n */\nfunction validatePoppedNode(definition: AnyNodeDefinition): void {\n // Decorators MUST have a child defined.\n if (isDecoratorNode(definition) && isNullOrUndefined(definition.child)) {\n throw new Error(`a ${definition.type} node must have a single child node defined`);\n }\n\n // Composites MUST have at least one child defined.\n if (isCompositeNode(definition) && !definition.children?.length) {\n throw new Error(`a ${definition.type} node must have at least a single child node defined`);\n }\n\n // We need to make sure that lotto nodes that have weights defined have a number of weights matching the number of child nodes.\n if (definition.type === \"lotto\") {\n // Check whether a 'weights' property has been defined, if it has we expect it to be an array of weights.\n if (typeof definition.weights !== \"undefined\") {\n // Check that the weights property is an array of positive integers with an element for each child node element.\n if (definition.weights.length !== definition.children.length) {\n throw new Error(\n \"expected a number of weight arguments matching the number of child nodes for lotto node\"\n );\n }\n }\n }\n}\n", "import { RootNodeDefinition } from \"./BehaviourTreeDefinition\";\nimport { flattenDefinition, isBranchNode, isInteger } from \"./BehaviourTreeDefinitionUtilities\";\nimport { convertMDSLToJSON } from \"./mdsl/MDSLDefinitionParser\";\n\n/**\n * An object representing the result of validating a tree definition.\n */\nexport type DefinitionValidationResult = {\n /**\n * A flag defining whether validation succeeded.\n */\n succeeded: boolean;\n /**\n * A string containing the error message if validation did not succeed.\n */\n errorMessage?: string;\n /**\n * The definition as json if the validation was successful, or undefined if validation did not succeed.\n */\n json?: RootNodeDefinition[];\n};\n\n/**\n * Validates the specified behaviour tree definition in the form of JSON or MDSL, not taking any globally registered subtrees into consideration.\n * @param definition The behaviour tree definition in the form of JSON or MDSL.\n * @returns An object representing the result of validating the given tree definition.\n */\nexport function validateDefinition(definition: any): DefinitionValidationResult {\n // The definition must be defined.\n if (definition === null || typeof definition === \"undefined\") {\n return createValidationFailureResult(\"definition is null or undefined\");\n }\n\n // We are expecting a definition in one of three different forms:\n // - A string which we will assume is MDSL and we will parse this to JSON before validation.\n // - An array which we will assume is an array of root node definitions with at least one being the primary root node (no 'id' property)\n // - An object which we will assume is the primary root node and should not have an 'id' property.\n if (typeof definition === \"string\") {\n // The definition is a string which we can assume is MDSL, so attempt to validate it.\n return validateMDSLDefinition(definition);\n } else if (typeof definition === \"object\") {\n // The definition will either be an array (of root node definitions) or an object (the single primary root node definition).\n return validateJSONDefinition(definition);\n } else {\n return createValidationFailureResult(`unexpected definition type of '${typeof definition}'`);\n }\n}\n\n/**\n * Validates the specified behaviour tree definition in the form of MDSL.\n * @param definition The behaviour tree definition in the form of MDSL.\n * @returns An object representing the result of validating the given tree definition.\n */\nfunction validateMDSLDefinition(definition: string): DefinitionValidationResult {\n let rootNodeDefinitions;\n\n // The first thing the we need to do is to attempt to convert our MDSL into JSON.\n try {\n // The definition is a string which we can assume is MDSL, so attempt to parse it to a JSON definition in the form of an array of root node definitions.\n rootNodeDefinitions = convertMDSLToJSON(definition);\n } catch (exception) {\n // We failed to parse the JSON from the MDSL, this is likely to be the result of it not being a valid MDSL string.\n return createValidationFailureResult((exception as Error).message);\n }\n\n // Unpack all of the root node definitions into arrays of main ('id' defined) and sub ('id' not defined) root node definitions.\n const mainRootNodeDefinitions = rootNodeDefinitions.filter(({ id }) => typeof id === \"undefined\");\n const subRootNodeDefinitions = rootNodeDefinitions.filter(({ id }) => typeof id === \"string\" && id.length > 0);\n\n // We should ALWAYS have exactly one root node definition without an 'id' property defined, which is out main root node definition.\n if (mainRootNodeDefinitions.length !== 1) {\n return createValidationFailureResult(\n \"expected single unnamed root node at base of definition to act as main root\"\n );\n }\n\n // We should never have duplicate 'id' properties across our sub root node definitions.\n const subRootNodeIdenitifers: string[] = [];\n for (const { id } of subRootNodeDefinitions) {\n // Have we already come across this 'id' property value?\n if (subRootNodeIdenitifers.includes(id!)) {\n return createValidationFailureResult(`multiple root nodes found with duplicate name '${id}'`);\n }\n\n subRootNodeIdenitifers.push(id!);\n }\n\n try {\n // Validate our branch -> subtree links and check for any circular dependencies, we don't care about checking for broken subtree links here.\n validateBranchSubtreeLinks(rootNodeDefinitions, false);\n } catch (exception) {\n return createValidationFailureResult((exception as Error).message);\n }\n\n // Our definition was valid!\n return {\n succeeded: true,\n json: rootNodeDefinitions\n };\n}\n\n/**\n * Validates the specified behaviour tree definition in the form of JSON.\n * @param definition The behaviour tree definition in the form of JSON.\n * @returns An object representing the result of validating the given tree definition.\n */\nexport function validateJSONDefinition(\n definition: RootNodeDefinition | RootNodeDefinition[]\n): DefinitionValidationResult {\n // The definition will either be an array (of root node definitions) or an object (the single primary root node definition).\n const rootNodeDefinitions = Array.isArray(definition) ? definition : [definition];\n\n // Iterate over our array of root nodes and call validateNode for each, passing an initial depth of 0, wrapped in a try catch to handle validation failures.\n try {\n rootNodeDefinitions.forEach((rootNodeDefinition) => validateNode(rootNodeDefinition, 0));\n } catch (error) {\n // Handle cases where we have caught a thrown Error and return a failure result with the error message.\n if (error instanceof Error) {\n return createValidationFailureResult(error.message);\n }\n\n // No idea what happened here!\n return createValidationFailureResult(`unexpected error: ${error}`);\n }\n\n // Unpack all of the root node definitions into arrays of main ('id' defined) and sub ('id' not defined) root node definitions.\n const mainRootNodeDefinitions = rootNodeDefinitions.filter(({ id }) => typeof id === \"undefined\");\n const subRootNodeDefinitions = rootNodeDefinitions.filter(({ id }) => typeof id === \"string\" && id.length > 0);\n\n // We should ALWAYS have exactly one root node definition without an 'id' property defined, which is out main root node definition.\n if (mainRootNodeDefinitions.length !== 1) {\n return createValidationFailureResult(\n \"expected single root node without 'id' property defined to act as main root\"\n );\n }\n\n // We should never have duplicate 'id' properties across our sub root node definitions.\n const subRootNodeIdenitifers: string[] = [];\n for (const { id } of subRootNodeDefinitions) {\n // Have we already come across this 'id' property value?\n if (subRootNodeIdenitifers.includes(id!)) {\n return createValidationFailureResult(\n `multiple root nodes found with duplicate 'id' property value of '${id}'`\n );\n }\n\n subRootNodeIdenitifers.push(id!);\n }\n\n try {\n // Validate our branch -> subtree links and check for any circular dependencies, we don't care about checking for broken subtree links here.\n validateBranchSubtreeLinks(rootNodeDefinitions, false);\n } catch (exception) {\n return createValidationFailureResult((exception as Error).message);\n }\n\n // Our definition was valid!\n return {\n succeeded: true,\n json: rootNodeDefinitions\n };\n}\n\n/**\n * Validates the branch -> subtree links across all provided root node definitions.\n * This will not consider branch nodes that reference any globally registered subtrees unless includesGlobalSubtrees\n * is set to true, in which case we will also verify that there are no broken branch -> subtree links.\n * @param rootNodeDefinitions The array of root node definitions.\n * @param includesGlobalSubtrees A flag defining whether the array includes all global subtree root node definitions.\n */\nexport function validateBranchSubtreeLinks(rootNodeDefinitions: RootNodeDefinition[], includesGlobalSubtrees: boolean) {\n // Create a mapping of root node identifiers to other root nodes that they reference via branch nodes.\n // Below is an example of a mapping that includes a circular dependency (root => a => b => c => a)\n // [{ refs: [\"a\", \"b\"] }, { id: \"a\", refs: [\"b\"] }, { id: \"b\", refs: [\"c\"] }, { id: \"c\", refs: [\"a\"] }]\n const rootNodeMappings: { id: string | undefined; refs: string[] }[] = rootNodeDefinitions.map(\n (rootNodeDefinition) => ({\n id: rootNodeDefinition.id,\n refs: flattenDefinition(rootNodeDefinition)\n .filter(isBranchNode)\n .map(({ ref }) => ref)\n })\n );\n\n // A recursive function to walk through the mappings, keeping track of which root nodes we have visited in the form of a path of root node identifiers.\n const followRefs = (mapping: { id: string | undefined; refs: string[] }, path: (string | undefined)[] = []) => {\n // Have we found a circular dependency?\n if (path.includes(mapping.id)) {\n // We found a circular dependency! Get the bad path of root node identifiers.\n const badPath = [...path, mapping.id];\n\n // Create the formatted path value. [undefined, \"a\", \"b\", \"c\", \"a\"] would be formatted as \"a -> b -> c -> a\".\n const badPathFormatted = badPath.filter((element) => !!element).join(\" => \");\n\n // No need to continue, we found a circular dependency.\n throw new Error(`circular dependency found in branch node references: ${badPathFormatted}`);\n }\n\n for (const ref of mapping.refs) {\n // Find the mapping for the root node with an identifer matching the current ref.\n const subMapping = rootNodeMappings.find(({ id }) => id === ref);\n\n // We may not have a mapping for this ref, which is normal when we aren't considering all globally registered subtrees.\n if (subMapping) {\n followRefs(subMapping, [...path, mapping.id]);\n } else if (includesGlobalSubtrees) {\n // We found a reference to a root node that doesn't exist, which is a problem seeing as the root node definitons includes all globally registered subtrees.\n throw new Error(\n mapping.id\n ? `subtree '${mapping.id}' has branch node that references root node '${ref}' which has not been defined`\n : `primary tree has branch node that references root node '${ref}' which has not been defined`\n );\n }\n }\n };\n\n // Start looking for circular dependencies and broken references from the primary root node definition.\n followRefs(rootNodeMappings.find((mapping) => typeof mapping.id === \"undefined\")!);\n}\n\n/**\n * Validate an object that we expect to be a node definition.\n * @param definition An object that we expect to be a node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateNode(definition: any, depth: number): void {\n // Every node must be valid object and have a non-empty 'type' string property.\n if (typeof definition !== \"object\" || typeof definition.type !== \"string\" || definition.type.length === 0) {\n throw new Error(\n `node definition is not an object or 'type' property is not a non-empty string at depth '${depth}'`\n );\n }\n\n // How we validate this node definition will depend on its type.\n switch (definition.type) {\n case \"action\":\n validateActionNode(definition, depth);\n break;\n\n case \"condition\":\n validateConditionNode(definition, depth);\n break;\n\n case \"wait\":\n validateWaitNode(definition, depth);\n break;\n\n case \"branch\":\n validateBranchNode(definition, depth);\n break;\n\n case \"root\":\n validateRootNode(definition, depth);\n break;\n\n case \"succeed\":\n validateSucceedNode(definition, depth);\n break;\n\n case \"fail\":\n validateFailNode(definition, depth);\n break;\n\n case \"flip\":\n validateFlipNode(definition, depth);\n break;\n\n case \"repeat\":\n validateRepeatNode(definition, depth);\n break;\n\n case \"retry\":\n validateRetryNode(definition, depth);\n break;\n\n case \"sequence\":\n validateSequenceNode(definition, depth);\n break;\n\n case \"selector\":\n validateSelectorNode(definition, depth);\n break;\n\n case \"parallel\":\n validateParallelNode(definition, depth);\n break;\n\n case \"lotto\":\n validateLottoNode(definition, depth);\n break;\n\n default:\n throw new Error(`unexpected node type of '${definition.type}' at depth '${depth}'`);\n }\n}\n\n/**\n * Validate any attributes for a given node definition.\n * @param definition The node definition.\n * @param depth The depth of the node in the behaviour tree definition.\n */\nfunction validateNodeAttributes(definition: any, depth: number): void {\n // Validate each of the attribute types for this node.\n [\"while\", \"until\", \"entry\", \"exit\", \"step\"].forEach((attributeName) => {\n // Attempt to grab the definition for the current attribute from the node definition.\n const attributeDefinition = definition[attributeName];\n\n // All node attributes are optional, so there is nothing to do if the current attribute is not defined.\n if (typeof attributeDefinition === \"undefined\") {\n return;\n }\n\n // The attribute definition must be an object.\n if (typeof attributeDefinition !== \"object\") {\n throw new Error(\n `expected attribute '${attributeName}' to be an object for '${definition.type}' node at depth '${depth}'`\n );\n }\n\n // The 'call' property must be defined for any attribute definition.\n if (typeof attributeDefinition.call !== \"string\" || attributeDefinition.call.length === 0) {\n throw new Error(\n `expected 'call' property for attribute '${attributeName}' to be a non-empty string for '${definition.type}' node at depth '${depth}'`\n );\n }\n\n // If any node attribute arguments have been defined then they must have been defined in an array.\n if (typeof attributeDefinition.args !== \"undefined\" && !Array.isArray(attributeDefinition.args)) {\n throw new Error(\n `expected 'args' property for attribute '${attributeName}' to be an array for '${definition.type}' node at depth '${depth}'`\n );\n }\n });\n}\n\n/**\n * Validate an object that we expect to be a root node definition.\n * @param definition An object that we expect to be a root node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateRootNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"root\") {\n throw new Error(\"expected node type of 'root' for root node\");\n }\n\n // A root node cannot be the child of another node.\n if (depth > 0) {\n throw new Error(\"a root node cannot be the child of another node\");\n }\n\n // Check that, if the root node 'id' property is defined, it is a non-empty string.\n if (typeof definition.id !== \"undefined\" && (typeof definition.id !== \"string\" || definition.id.length === 0)) {\n throw new Error(\"expected non-empty string for 'id' property if defined for root node\");\n }\n\n // A root node is a decorator node, so must have a child node defined.\n if (typeof definition.child === \"undefined\") {\n throw new Error(\"expected property 'child' to be defined for root node\");\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n\n // Validate the child node of this decorator node.\n validateNode(definition.child, depth + 1);\n}\n\n/**\n * Validate an object that we expect to be a succeed node definition.\n * @param definition An object that we expect to be a succeed node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateSucceedNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"succeed\") {\n throw new Error(`expected node type of 'succeed' for succeed node at depth '${depth}'`);\n }\n\n // A succeed node is a decorator node, so must have a child node defined.\n if (typeof definition.child === \"undefined\") {\n throw new Error(`expected property 'child' to be defined for succeed node at depth '${depth}'`);\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n\n // Validate the child node of this decorator node.\n validateNode(definition.child, depth + 1);\n}\n\n/**\n * Validate an object that we expect to be a fail node definition.\n * @param definition An object that we expect to be a fail node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateFailNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"fail\") {\n throw new Error(`expected node type of 'fail' for fail node at depth '${depth}'`);\n }\n\n // A fail node is a decorator node, so must have a child node defined.\n if (typeof definition.child === \"undefined\") {\n throw new Error(`expected property 'child' to be defined for fail node at depth '${depth}'`);\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n\n // Validate the child node of this decorator node.\n validateNode(definition.child, depth + 1);\n}\n\n/**\n * Validate an object that we expect to be a flip node definition.\n * @param definition An object that we expect to be a flip node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateFlipNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"flip\") {\n throw new Error(`expected node type of 'flip' for flip node at depth '${depth}'`);\n }\n\n // A flip node is a decorator node, so must have a child node defined.\n if (typeof definition.child === \"undefined\") {\n throw new Error(`expected property 'child' to be defined for flip node at depth '${depth}'`);\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n\n // Validate the child node of this decorator node.\n validateNode(definition.child, depth + 1);\n}\n\n/**\n * Validate an object that we expect to be a repeat node definition.\n * @param definition An object that we expect to be a repeat node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateRepeatNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"repeat\") {\n throw new Error(`expected node type of 'repeat' for repeat node at depth '${depth}'`);\n }\n\n // A repeat node is a decorator node, so must have a child node defined.\n if (typeof definition.child === \"undefined\") {\n throw new Error(`expected property 'child' to be defined for repeat node at depth '${depth}'`);\n }\n\n // Check whether an 'iterations' property has been defined, it may not have been if this node is to repeat indefinitely.\n if (typeof definition.iterations !== \"undefined\") {\n if (Array.isArray(definition.iterations)) {\n // Check whether any elements of the array are not integer values.\n const containsNonInteger = !!definition.iterations.filter((value: unknown) => !isInteger(value)).length;\n\n // If the 'iterations' property is an array then it MUST contain two integer values.\n if (definition.iterations.length !== 2 || containsNonInteger) {\n throw new Error(\n `expected array containing two integer values for 'iterations' property if defined for repeat node at depth '${depth}'`\n );\n }\n\n // A repeat node must have a positive min and max iterations count if they are defined.\n if (definition.iterations[0] < 0 || definition.iterations[1] < 0) {\n throw new Error(\n `expected positive minimum and maximum iterations count for 'iterations' property if defined for repeat node at depth '${depth}'`\n );\n }\n\n // A repeat node must not have a minimum iterations count that exceeds the maximum iterations count.\n if (definition.iterations[0] > definition.iterations[1]) {\n throw new Error(\n `expected minimum iterations count that does not exceed the maximum iterations count for 'iterations' property if defined for repeat node at depth '${depth}'`\n );\n }\n } else if (isInteger(definition.iterations)) {\n // A repeat node must have a positive number of iterations if defined.\n if (definition.iterations < 0) {\n throw new Error(\n `expected positive iterations count for 'iterations' property if defined for repeat node at depth '${depth}'`\n );\n }\n } else {\n throw new Error(\n `expected integer value or array containing two integer values for 'iterations' property if defined for repeat node at depth '${depth}'`\n );\n }\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n\n // Validate the child node of this decorator node.\n validateNode(definition.child, depth + 1);\n}\n\n/**\n * Validate an object that we expect to be a retry node definition.\n * @param definition An object that we expect to be a retry node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateRetryNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"retry\") {\n throw new Error(`expected node type of 'retry' for retry node at depth '${depth}'`);\n }\n\n // A retry node is a decorator node, so must have a child node defined.\n if (typeof definition.child === \"undefined\") {\n throw new Error(`expected property 'child' to be defined for retry node at depth '${depth}'`);\n }\n\n // Check whether an 'attempts' property has been defined, it may not have been if this node is to retry indefinitely.\n if (typeof definition.attempts !== \"undefined\") {\n if (Array.isArray(definition.attempts)) {\n // Check whether any elements of the array are not integer values.\n const containsNonInteger = !!definition.attempts.filter((value: unknown) => !isInteger(value)).length;\n\n // If the 'attempts' property is an array then it MUST contain two integer values.\n if (definition.attempts.length !== 2 || containsNonInteger) {\n throw new Error(\n `expected array containing two integer values for 'attempts' property if defined for retry node at depth '${depth}'`\n );\n }\n\n // A retry node must have a positive min and max attempts count if they are defined.\n if (definition.attempts[0] < 0 || definition.attempts[1] < 0) {\n throw new Error(\n `expected positive minimum and maximum attempts count for 'attempts' property if defined for retry node at depth '${depth}'`\n );\n }\n\n // A retry node must not have a minimum attempts count that exceeds the maximum attempts count.\n if (definition.attempts[0] > definition.attempts[1]) {\n throw new Error(\n `expected minimum attempts count that does not exceed the maximum attempts count for 'attempts' property if defined for retry node at depth '${depth}'`\n );\n }\n } else if (isInteger(definition.attempts)) {\n // A retry node must have a positive number of attempts if defined.\n if (definition.attempts < 0) {\n throw new Error(\n `expected positive attempts count for 'attempts' property if defined for retry node at depth '${depth}'`\n );\n }\n } else {\n throw new Error(\n `expected integer value or array containing two integer values for 'attempts' property if defined for retry node at depth '${depth}'`\n );\n }\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n\n // Validate the child node of this decorator node.\n validateNode(definition.child, depth + 1);\n}\n\n/**\n * Validate an object that we expect to be a branch node definition.\n * @param definition An object that we expect to be a branch node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateBranchNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"branch\") {\n throw new Error(`expected node type of 'branch' for branch node at depth '${depth}'`);\n }\n\n // Check that the branch node 'ref' property is defined and is a non-empty string.\n if (typeof definition.ref !== \"string\" || definition.ref.length === 0) {\n throw new Error(`expected non-empty string for 'ref' property for branch node at depth '${depth}'`);\n }\n\n // It is invalid to define guard attributes for a branch node as they should be defined on the referenced root node.\n [\"while\", \"until\"].forEach((attributeName) => {\n if (typeof definition[attributeName] !== \"undefined\") {\n throw new Error(\n `guards should not be defined for branch nodes but guard '${attributeName}' was defined for branch node at depth '${depth}'`\n );\n }\n });\n\n // It is invalid to define callback attributes for a branch node as they should be defined on the referenced root node.\n [\"entry\", \"exit\", \"step\"].forEach((attributeName) => {\n if (typeof definition[attributeName] !== \"undefined\") {\n throw new Error(\n `callbacks should not be defined for branch nodes but callback '${attributeName}' was defined for branch node at depth '${depth}'`\n );\n }\n });\n}\n\n/**\n * Validate an object that we expect to be a action node definition.\n * @param definition An object that we expect to be a action node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateActionNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"action\") {\n throw new Error(`expected node type of 'action' for action node at depth '${depth}'`);\n }\n\n // The 'call' property must be defined for a action node definition.\n if (typeof definition.call !== \"string\" || definition.call.length === 0) {\n throw new Error(`expected non-empty string for 'call' property of action node at depth '${depth}'`);\n }\n\n // If any action function arguments have been defined then they must have been defined in an array.\n if (typeof definition.args !== \"undefined\" && !Array.isArray(definition.args)) {\n throw new Error(`expected array for 'args' property if defined for action node at depth '${depth}'`);\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n}\n\n/**\n * Validate an object that we expect to be a condition node definition.\n * @param definition An object that we expect to be a condition node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateConditionNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"condition\") {\n throw new Error(`expected node type of 'condition' for condition node at depth '${depth}'`);\n }\n\n // The 'call' property must be defined for a condition node definition.\n if (typeof definition.call !== \"string\" || definition.call.length === 0) {\n throw new Error(`expected non-empty string for 'call' property of condition node at depth '${depth}'`);\n }\n\n // If any condition function arguments have been defined then they must have been defined in an array.\n if (typeof definition.args !== \"undefined\" && !Array.isArray(definition.args)) {\n throw new Error(`expected array for 'args' property if defined for condition node at depth '${depth}'`);\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n}\n\n/**\n * Validate an object that we expect to be a wait node definition.\n * @param definition An object that we expect to be a wait node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateWaitNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"wait\") {\n throw new Error(`expected node type of 'wait' for wait node at depth '${depth}'`);\n }\n\n // Check whether a 'duration' property has been defined, it may not have been if this node is to wait indefinitely.\n if (typeof definition.duration !== \"undefined\") {\n if (Array.isArray(definition.duration)) {\n // Check whether any elements of the array are not integer values.\n const containsNonInteger = !!definition.duration.filter((value: unknown) => !isInteger(value)).length;\n\n // If the 'duration' property is an array then it MUST contain two integer values.\n if (definition.duration.length !== 2 || containsNonInteger) {\n throw new Error(\n `expected array containing two integer values for 'duration' property if defined for wait node at depth '${depth}'`\n );\n }\n\n // A wait node must have a positive min and max duration value if they are defined.\n if (definition.duration[0] < 0 || definition.duration[1] < 0) {\n throw new Error(\n `expected positive minimum and maximum duration for 'duration' property if defined for wait node at depth '${depth}'`\n );\n }\n\n // A wait node must not have a minimum duration value that exceeds the maximum duration value.\n if (definition.duration[0] > definition.duration[1]) {\n throw new Error(\n `expected minimum duration value that does not exceed the maximum duration value for 'duration' property if defined for wait node at depth '${depth}'`\n );\n }\n } else if (isInteger(definition.duration)) {\n // A wait node must have a positive duration value if defined.\n if (definition.duration < 0) {\n throw new Error(\n `expected positive duration value for 'duration' property if defined for wait node at depth '${depth}'`\n );\n }\n } else {\n throw new Error(\n `expected integer value or array containing two integer values for 'duration' property if defined for wait node at depth '${depth}'`\n );\n }\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n}\n\n/**\n * Validate an object that we expect to be a sequence node definition.\n * @param definition An object that we expect to be a sequence node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateSequenceNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"sequence\") {\n throw new Error(`expected node type of 'sequence' for sequence node at depth '${depth}'`);\n }\n\n // A sequence node is a composite node, so must have a children nodes array defined.\n if (!Array.isArray(definition.children) || definition.children.length === 0) {\n throw new Error(`expected non-empty 'children' array to be defined for sequence node at depth '${depth}'`);\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n\n // Validate the child nodes of this composite node.\n definition.children.forEach((child: any) => validateNode(child, depth + 1));\n}\n\n/**\n * Validate an object that we expect to be a selector node definition.\n * @param definition An object that we expect to be a selector node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateSelectorNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"selector\") {\n throw new Error(`expected node type of 'selector' for selector node at depth '${depth}'`);\n }\n\n // A selector node is a composite node, so must have a children nodes array defined.\n if (!Array.isArray(definition.children) || definition.children.length === 0) {\n throw new Error(`expected non-empty 'children' array to be defined for selector node at depth '${depth}'`);\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n\n // Validate the child nodes of this composite node.\n definition.children.forEach((child: any) => validateNode(child, depth + 1));\n}\n\n/**\n * Validate an object that we expect to be a parallel node definition.\n * @param definition An object that we expect to be a parallel node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateParallelNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"parallel\") {\n throw new Error(`expected node type of 'parallel' for parallel node at depth '${depth}'`);\n }\n\n // A parallel node is a composite node, so must have a children nodes array defined.\n if (!Array.isArray(definition.children) || definition.children.length === 0) {\n throw new Error(`expected non-empty 'children' array to be defined for parallel node at depth '${depth}'`);\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n\n // Validate the child nodes of this composite node.\n definition.children.forEach((child: any) => validateNode(child, depth + 1));\n}\n\n/**\n * Validate an object that we expect to be a lotto node definition.\n * @param definition An object that we expect to be a lotto node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateLottoNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"lotto\") {\n throw new Error(`expected node type of 'lotto' for lotto node at depth '${depth}'`);\n }\n\n // A lotto node is a composite node, so must have a children nodes array defined.\n if (!Array.isArray(definition.children) || definition.children.length === 0) {\n throw new Error(`expected non-empty 'children' array to be defined for lotto node at depth '${depth}'`);\n }\n\n // Check whether a 'weights' property has been defined, if it has we expect it to be an array of weights.\n if (typeof definition.weights !== \"undefined\") {\n // Check that the weights property is an array of positive integers with an element for each child node element.\n if (\n !Array.isArray(definition.weights) ||\n definition.weights.length !== definition.children.length ||\n definition.weights.filter((value: unknown) => !isInteger(value)).length ||\n definition.weights.filter((value: number) => value < 0).length\n ) {\n throw new Error(\n `expected an array of positive integer weight values with a length matching the number of child nodes for 'weights' property if defined for lotto node at depth '${depth}'`\n );\n }\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n\n // Validate the child nodes of this composite node.\n definition.children.forEach((child: any) => validateNode(child, depth + 1));\n}\n\n/**\n * A helper function to create a failure validation result with the given error message.\n * @param errorMessage The validation failure error message.\n * @returns A failure validation result with the given error message.\n */\nfunction createValidationFailureResult(errorMessage: string): DefinitionValidationResult {\n return { succeeded: false, errorMessage };\n}\n", "import { ActionResult, Agent, GlobalFunction } from \"./Agent\";\nimport { RootNodeDefinition } from \"./BehaviourTreeDefinition\";\n\nexport type InvokerFunction = (args: any[]) => ActionResult | boolean;\n\n/**\n * A singleton used to store and lookup registered functions and subtrees.\n */\nexport default class Lookup {\n /**\n * The object holding any registered functions keyed on function name.\n */\n private static registeredFunctions: { [key: string]: GlobalFunction } = {};\n /**\n * The object holding any registered subtree root node definitions keyed on tree name.\n */\n private static registeredSubtrees: { [key: string]: RootNodeDefinition } = {};\n\n /**\n * Gets the function with the specified name.\n * @param name The name of the function.\n * @returns The function with the specified name.\n */\n public static getFunc(name: string): GlobalFunction {\n return this.registeredFunctions[name];\n }\n\n /**\n * Sets the function with the specified name for later lookup.\n * @param name The name of the function.\n * @param func The function.\n */\n public static setFunc(name: string, func: GlobalFunction): void {\n this.registeredFunctions[name] = func;\n }\n\n /**\n * Gets the function invoker for the specified agent and function name.\n * If a function with the specified name exists on the agent object then it will\n * be returned, otherwise we will then check the registered functions for a match.\n * @param agent The agent instance that this behaviour tree is modelling behaviour for.\n * @param name The function name.\n * @returns The function invoker for the specified agent and function name.\n */\n static getFuncInvoker(agent: Agent, name: string): InvokerFunction | null {\n // Check whether the agent contains the specified function.\n const agentFunction = agent[name];\n if (agentFunction && typeof agentFunction === \"function\") {\n return (args: any[]) => agentFunction.apply(agent, args);\n }\n\n // The agent does not contain the specified function but it may have been registered at some point.\n if (this.registeredFunctions[name] && typeof this.registeredFunctions[name] === \"function\") {\n const registeredFunction = this.registeredFunctions[name];\n return (args: any[]) => registeredFunction(agent, ...args.map((arg) => arg.value));\n }\n\n // We have no function to invoke.\n return null;\n }\n\n /**\n * Gets all registered subtree root node definitions.\n */\n static getSubtrees(): { [key: string]: RootNodeDefinition } {\n return this.registeredSubtrees;\n }\n\n /**\n * Sets the subtree with the specified name for later lookup.\n * @param name The name of the subtree.\n * @param subtree The subtree.\n */\n static setSubtree(name: string, subtree: RootNodeDefinition) {\n this.registeredSubtrees[name] = subtree;\n }\n\n /**\n * Removes the registered function or subtree with the specified name.\n * @param name The name of the registered function or subtree.\n */\n static remove(name: string) {\n delete this.registeredFunctions[name];\n delete this.registeredSubtrees[name];\n }\n\n /**\n * Remove all registered functions and subtrees.\n */\n static empty() {\n this.registeredFunctions = {};\n this.registeredSubtrees = {};\n }\n}\n", "import Node from \"../../nodes/Node\";\n\n/**\n * An exception thrown when evaluating node guard path conditions and a conditions fails.\n */\nexport default class GuardUnsatisifedException extends Error {\n /**\n * @param source The node at which a guard condition failed.\n */\n constructor(private source: Node) {\n super(\"A guard path condition has failed\");\n }\n\n /**\n * Gets whether the specified node is the node at which a guard condition failed.\n * @param node The node to check against the source node.\n * @returns Whether the specified node is the node at which a guard condition failed.\n */\n isSourceNode = (node: Node) => node === this.source;\n}\n", "import { Agent } from \"../../Agent\";\nimport Guard from \"./Guard\";\nimport Node from \"../../nodes/Node\";\nimport GuardUnsatisifedException from \"./GuardUnsatisifedException\";\n\nexport type GuardPathPart = {\n node: Node;\n guards: Guard[];\n};\n\n/**\n * Represents a path of node guards along a root-to-leaf tree path.\n */\nexport default class GuardPath {\n /**\n * @param nodes An array of objects defining a node instance -> guard link, ordered by node depth.\n */\n constructor(private nodes: GuardPathPart[]) {}\n\n /**\n * Evaluate guard conditions for all guards in the tree path, moving outwards from the root.\n * @param agent The agent, required for guard evaluation.\n * @returns An evaluation results object.\n */\n evaluate = (agent: Agent) => {\n // We need to evaluate guard conditions for nodes up the tree, moving outwards from the root.\n for (const details of this.nodes) {\n // There can be multiple guards per node.\n for (const guard of details.guards) {\n // Check whether the guard condition passes, and throw an exception if not.\n if (!guard.isSatisfied(agent)) {\n throw new GuardUnsatisifedException(details.node);\n }\n }\n }\n };\n}\n", "import { BehaviourTreeOptions } from \"../BehaviourTreeOptions\";\nimport State, { AnyState } from \"../State\";\nimport { Agent } from \"../Agent\";\nimport Leaf from \"./leaf/Leaf\";\nimport Attribute from \"../attributes/Attribute\";\nimport Entry from \"../attributes/callbacks/Entry\";\nimport Exit from \"../attributes/callbacks/Exit\";\nimport Step from \"../attributes/callbacks/Step\";\nimport Guard from \"../attributes/guards/Guard\";\nimport GuardPath from \"../attributes/guards/GuardPath\";\nimport GuardUnsatisifedException from \"../attributes/guards/GuardUnsatisifedException\";\n\n/**\n * A base node.\n */\nexport default abstract class Node {\n /**\n * The node uid.\n */\n private readonly uid: string = createNodeUid();\n /**\n * The node state.\n */\n private state: AnyState = State.READY;\n /**\n * The guard path to evaluate as part of a node update.\n */\n private guardPath: GuardPath | undefined;\n\n /**\n * @param type The node type.\n * @param attributes The node attributes.\n * @param args The node argument definitions.\n */\n constructor(private type: string, private attributes: Attribute[], private args: any[]) {}\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected abstract onUpdate(agent: Agent, options: BehaviourTreeOptions): void;\n\n /**\n * Gets the name of the node.\n */\n public abstract getName(): string;\n\n /**\n * Gets whether this node is a leaf node.\n */\n public abstract isLeafNode: () => this is Leaf;\n\n /**\n * Gets/Sets the state of the node.\n */\n getState = (): AnyState => this.state;\n setState = (value: AnyState): void => {\n this.state = value;\n };\n\n /**\n * Gets the unique id of the node.\n */\n getUid = () => this.uid;\n\n /**\n * Gets the type of the node.\n */\n getType = () => this.type;\n\n /**\n * Gets the node attributes.\n */\n getAttributes = () => this.attributes;\n\n /**\n * Gets the node arguments.\n */\n getArguments = () => this.args;\n\n /**\n * Gets the node attribute with the specified type, or null if it does not exist.\n */\n getAttribute(type: \"entry\" | \"ENTRY\"): Entry;\n getAttribute(type: \"exit\" | \"EXIT\"): Exit;\n getAttribute(type: \"step\" | \"STEP\"): Step;\n getAttribute(type: string): Attribute {\n return (\n this.getAttributes().filter((decorator) => decorator.type.toUpperCase() === type.toUpperCase())[0] || null\n );\n }\n\n /**\n * Gets the node attributes.\n */\n getGuardAttributes = (): Guard[] => this.getAttributes().filter((decorator) => decorator.isGuard()) as Guard[];\n\n /**\n * Sets the guard path to evaluate as part of a node update.\n */\n setGuardPath = (value: GuardPath) => (this.guardPath = value);\n\n /**\n * Gets whether a guard path is assigned to this node.\n */\n hasGuardPath = () => !!this.guardPath;\n\n /**\n * Gets whether this node is in the specified state.\n * @param value The value to compare to the node state.\n */\n public is(value: AnyState): boolean {\n return this.state === value;\n }\n\n /**\n * Reset the state of the node.\n */\n public reset(): void {\n this.setState(State.READY);\n }\n\n /**\n * Abort the running of this node.\n * @param agent The agent.\n */\n public abort(agent: Agent): void {\n // There is nothing to do if this node is not in the running state.\n if (!this.is(State.RUNNING)) {\n return;\n }\n\n // Reset the state of this node.\n this.reset();\n\n this.getAttribute(\"exit\")?.callAgentFunction(agent, false, true);\n }\n\n /**\n * Update the node.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n * @returns The result of the update.\n */\n public update(agent: Agent, options: BehaviourTreeOptions): void {\n // If this node is already in a 'SUCCEEDED' or 'FAILED' state then there is nothing to do.\n if (this.is(State.SUCCEEDED) || this.is(State.FAILED)) {\n return;\n }\n\n try {\n // Evaluate all of the guard path conditions for the current tree path.\n this.guardPath!.evaluate(agent);\n\n // If this node is in the READY state then call the ENTRY for this node if it exists.\n if (this.is(State.READY)) {\n this.getAttribute(\"entry\")?.callAgentFunction(agent);\n }\n\n this.getAttribute(\"step\")?.callAgentFunction(agent);\n\n // Do the actual update.\n this.onUpdate(agent, options);\n\n // If this node is now in a 'SUCCEEDED' or 'FAILED' state then call the EXIT for this node if it exists.\n if (this.is(State.SUCCEEDED) || this.is(State.FAILED)) {\n this.getAttribute(\"exit\")?.callAgentFunction(agent, this.is(State.SUCCEEDED), false);\n }\n } catch (error) {\n // If the error is a GuardUnsatisfiedException then we need to determine if this node is the source.\n if (error instanceof GuardUnsatisifedException && error.isSourceNode(this)) {\n // Abort the current node.\n this.abort(agent);\n\n // Any node that is the source of an abort will be a failed node.\n this.setState(State.FAILED);\n } else {\n throw error;\n }\n }\n }\n}\n\n/**\n * Create a randomly generated node uid.\n * @returns A randomly generated node uid.\n */\nfunction createNodeUid(): string {\n var S4 = function () {\n return (((1 + Math.random()) * 0x10000) | 0).toString(16).substring(1);\n };\n return S4() + S4() + \"-\" + S4() + \"-\" + S4() + \"-\" + S4() + \"-\" + S4() + S4() + S4();\n}\n", "import Node from \"../Node\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\n\n/**\n * A composite node that wraps child nodes.\n */\nexport default abstract class Composite extends Node {\n /**\n * @param type The node type.\n * @param attributes The node attributes.\n * @param children The child nodes.\n */\n constructor(type: string, attributes: Attribute[], protected children: Node[]) {\n super(type, attributes, []);\n }\n\n /**\n * Gets whether this node is a leaf node.\n */\n isLeafNode = () => false;\n\n /**\n * Gets the children of this node.\n */\n getChildren = () => this.children;\n\n /**\n * Reset the state of the node.\n */\n reset = () => {\n // Reset the state of this node.\n this.setState(State.READY);\n\n // Reset the state of any child nodes.\n this.getChildren().forEach((child) => child.reset());\n };\n\n /**\n * Abort the running of this node.\n * @param agent The agent.\n */\n abort = (agent: Agent) => {\n // There is nothing to do if this node is not in the running state.\n if (!this.is(State.RUNNING)) {\n return;\n }\n\n // Abort any child nodes.\n this.getChildren().forEach((child) => child.abort(agent));\n\n // Reset the state of this node.\n this.reset();\n\n this.getAttribute(\"exit\")?.callAgentFunction(agent, false, true);\n };\n}\n", "import Composite from \"./Composite\";\nimport State from \"../../State\";\nimport Node from \"../Node\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A PARALLEL node.\n * The child nodes are executed concurrently until one fails or all succeed.\n */\nexport default class Parallel extends Composite {\n /**\n * @param attributes The node attributes.\n * @param children The child nodes.\n */\n constructor(attributes: Attribute[], children: Node[]) {\n super(\"parallel\", attributes, children);\n }\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // Keep a count of the number of succeeded child nodes.\n let succeededCount = 0;\n\n let hasChildFailed = false;\n\n // Iterate over all of the children of this node.\n for (const child of this.children) {\n // If the child has never been updated or is running then we will need to update it now.\n if (child.getState() === State.READY || child.getState() === State.RUNNING) {\n // Update the child of this node.\n child.update(agent, options);\n }\n\n // If the current child has a state of 'SUCCEEDED' then we should move on to the next child.\n if (child.getState() === State.SUCCEEDED) {\n // The child node has succeeded, keep track of this to determine if all children have.\n succeededCount++;\n\n // The child node succeeded, but we have not finished checking every child node yet.\n continue;\n }\n\n // If the current child has a state of 'FAILED' then this node is also a 'FAILED' node.\n if (child.getState() === State.FAILED) {\n hasChildFailed = true;\n\n // There is no need to check the rest of the children.\n break;\n }\n\n // The node should be in the 'RUNNING' state.\n if (child.getState() !== State.RUNNING) {\n // The child node was not in an expected state.\n throw new Error(\"child node was not in an expected state.\");\n }\n }\n\n if (hasChildFailed) {\n // This node is a 'FAILED' node.\n this.setState(State.FAILED);\n\n // Abort every running child.\n for (const child of this.children) {\n if (child.getState() === State.RUNNING) {\n child.abort(agent);\n }\n }\n } else {\n // If all children have succeeded then this node has also succeeded, otherwise it is still running.\n this.setState(succeededCount === this.children.length ? State.SUCCEEDED : State.RUNNING);\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => \"PARALLEL\";\n}\n", "import Composite from \"./Composite\";\nimport Node from \"../Node\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A SELECTOR node.\n * The child nodes are executed in sequence until one succeeds or all fail.\n */\nexport default class Selector extends Composite {\n /**\n * @param attributes The node attributes.\n * @param children The child nodes.\n */\n constructor(attributes: Attribute[], protected children: Node[]) {\n super(\"selector\", attributes, children);\n }\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // Iterate over all of the children of this node.\n for (const child of this.children) {\n // If the child has never been updated or is running then we will need to update it now.\n if (child.getState() === State.READY || child.getState() === State.RUNNING) {\n // Update the child of this node.\n child.update(agent, options);\n }\n\n // If the current child has a state of 'SUCCEEDED' then this node is also a 'SUCCEEDED' node.\n if (child.getState() === State.SUCCEEDED) {\n // This node is a 'SUCCEEDED' node.\n this.setState(State.SUCCEEDED);\n\n // There is no need to check the rest of the selector nodes.\n return;\n }\n\n // If the current child has a state of 'FAILED' then we should move on to the next child.\n if (child.getState() === State.FAILED) {\n // Find out if the current child is the last one in the selector.\n // If it is then this sequence node has also failed.\n if (this.children.indexOf(child) === this.children.length - 1) {\n // This node is a 'FAILED' node.\n this.setState(State.FAILED);\n\n // There is no need to check the rest of the selector as we have completed it.\n return;\n } else {\n // The child node failed, try the next one.\n continue;\n }\n }\n\n // The node should be in the 'RUNNING' state.\n if (child.getState() === State.RUNNING) {\n // This node is a 'RUNNING' node.\n this.setState(State.RUNNING);\n\n // There is no need to check the rest of the selector as the current child is still running.\n return;\n }\n\n // The child node was not in an expected state.\n throw new Error(\"child node was not in an expected state.\");\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => \"SELECTOR\";\n}\n", "import Composite from \"./Composite\";\nimport Node from \"../Node\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A SEQUENCE node.\n * The child nodes are executed in sequence until one fails or all succeed.\n */\nexport default class Sequence extends Composite {\n /**\n * @param attributes The node attributes.\n * @param children The child nodes.\n */\n constructor(attributes: Attribute[], protected children: Node[]) {\n super(\"sequence\", attributes, children);\n }\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // Iterate over all of the children of this node.\n for (const child of this.children) {\n // If the child has never been updated or is running then we will need to update it now.\n if (child.getState() === State.READY || child.getState() === State.RUNNING) {\n // Update the child of this node.\n child.update(agent, options);\n }\n\n // If the current child has a state of 'SUCCEEDED' then we should move on to the next child.\n if (child.getState() === State.SUCCEEDED) {\n // Find out if the current child is the last one in the sequence.\n // If it is then this sequence node has also succeeded.\n if (this.children.indexOf(child) === this.children.length - 1) {\n // This node is a 'SUCCEEDED' node.\n this.setState(State.SUCCEEDED);\n\n // There is no need to check the rest of the sequence as we have completed it.\n return;\n } else {\n // The child node succeeded, but we have not finished the sequence yet.\n continue;\n }\n }\n\n // If the current child has a state of 'FAILED' then this node is also a 'FAILED' node.\n if (child.getState() === State.FAILED) {\n // This node is a 'FAILED' node.\n this.setState(State.FAILED);\n\n // There is no need to check the rest of the sequence.\n return;\n }\n\n // The node should be in the 'RUNNING' state.\n if (child.getState() === State.RUNNING) {\n // This node is a 'RUNNING' node.\n this.setState(State.RUNNING);\n\n // There is no need to check the rest of the sequence as the current child is still running.\n return;\n }\n\n // The child node was not in an expected state.\n throw new Error(\"child node was not in an expected state.\");\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => \"SEQUENCE\";\n}\n", "import createLotto from \"lotto-draw\";\n\nimport Node from \"../Node\";\nimport Composite from \"./Composite\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A LOTTO node.\n * A winning child is picked on the initial update of this node, based on ticket weighting.\n * The state of this node will match the state of the winning child.\n */\nexport default class Lotto extends Composite {\n /**\n * @param attributes The node attributes.\n * @param weights The child node weights.\n * @param children The child nodes.\n */\n constructor(attributes: Attribute[], private weights: number[] | undefined, children: Node[]) {\n super(\"lotto\", attributes, children);\n }\n\n /**\n * The child node selected to be the active one.\n */\n private selectedChild: Node | undefined;\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // If this node is in the READY state then we need to pick a winning child node.\n if (this.is(State.READY)) {\n // Create a lotto draw with which to randomly pick a child node to become the active one.\n const lottoDraw = createLotto({\n // Hook up the optional 'random' behaviour tree function option to the one used by 'lotto-draw'.\n random: options.random,\n // Pass in each child node as a participant in the lotto draw with their respective ticket count.\n participants: this.children.map((child, index) => [child, this.weights?.[index] || 1])\n });\n\n // Randomly pick a child based on ticket weighting, this will become the active child for this composite node.\n this.selectedChild = lottoDraw.draw() || undefined;\n }\n\n // If something went wrong and we don't have an active child then we should throw an error.\n if (!this.selectedChild) {\n throw new Error(\"failed to update lotto node as it has no active child\");\n }\n\n // If the selected child has never been updated or is running then we will need to update it now.\n if (this.selectedChild.getState() === State.READY || this.selectedChild.getState() === State.RUNNING) {\n this.selectedChild.update(agent, options);\n }\n\n // The state of the lotto node is the state of its selected child.\n this.setState(this.selectedChild.getState());\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => (this.weights ? `LOTTO [${this.weights.join(\",\")}]` : \"LOTTO\");\n}\n", "import Node from \"../Node\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\n\n/**\n * A decorator node that wraps a single child node.\n */\nexport default abstract class Decorator extends Node {\n /**\n * @param type The node type.\n * @param attributes The node attributes.\n * @param child The child node.\n */\n constructor(type: string, attributes: Attribute[], protected child: Node) {\n super(type, attributes, []);\n }\n\n /**\n * Gets whether this node is a leaf node.\n */\n isLeafNode = () => false;\n\n /**\n * Gets the children of this node.\n */\n getChildren = () => [this.child];\n\n /**\n * Reset the state of the node.\n */\n reset = () => {\n // Reset the state of this node.\n this.setState(State.READY);\n\n // Reset the state of the child node.\n this.child.reset();\n };\n\n /**\n * Abort the running of this node.\n * @param agent The agent.\n */\n abort = (agent: Agent) => {\n // There is nothing to do if this node is not in the running state.\n if (!this.is(State.RUNNING)) {\n return;\n }\n\n // Abort the child node.\n this.child.abort(agent);\n\n // Reset the state of this node.\n this.reset();\n\n this.getAttribute(\"exit\")?.callAgentFunction(agent, false, true);\n };\n}\n", "import Node from \"../Node\";\nimport Decorator from \"./Decorator\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A Fail node.\n * This node wraps a single child and will always move to the 'FAILED' state when the child moves to a 'SUCCEEDED' or 'FAILED' state.\n */\nexport default class Fail extends Decorator {\n /**\n * @param attributes The node attributes.\n * @param child The child node.\n */\n constructor(attributes: Attribute[], child: Node) {\n super(\"fail\", attributes, child);\n }\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // If the child has never been updated or is running then we will need to update it now.\n if (this.child.getState() === State.READY || this.child.getState() === State.RUNNING) {\n this.child.update(agent, options);\n }\n\n // The state of this node will depend in the state of its child.\n switch (this.child.getState()) {\n case State.RUNNING:\n this.setState(State.RUNNING);\n break;\n\n case State.SUCCEEDED:\n case State.FAILED:\n this.setState(State.FAILED);\n break;\n\n default:\n this.setState(State.READY);\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => \"FAIL\";\n}\n", "import Decorator from \"./Decorator\";\nimport State from \"../../State\";\nimport Node from \"../Node\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A Flip node.\n * This node wraps a single child and will flip the state of the child state.\n */\nexport default class Flip extends Decorator {\n /**\n * @param attributes The node attributes.\n * @param child The child node.\n */\n constructor(attributes: Attribute[], child: Node) {\n super(\"flip\", attributes, child);\n }\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // If the child has never been updated or is running then we will need to update it now.\n if (this.child.getState() === State.READY || this.child.getState() === State.RUNNING) {\n this.child.update(agent, options);\n }\n\n // The state of this node will depend in the state of its child.\n switch (this.child.getState()) {\n case State.RUNNING:\n this.setState(State.RUNNING);\n break;\n\n case State.SUCCEEDED:\n this.setState(State.FAILED);\n break;\n\n case State.FAILED:\n this.setState(State.SUCCEEDED);\n break;\n\n default:\n this.setState(State.READY);\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => \"FLIP\";\n}\n", "import Node from \"../Node\";\nimport Decorator from \"./Decorator\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A REPEAT node.\n * The node has a single child which can have:\n * -- A number of iterations for which to repeat the child node.\n * -- An infinite repeat loop if neither an iteration count or a condition function is defined.\n * The REPEAT node will stop and have a 'FAILED' state if its child is ever in a 'FAILED' state after an update.\n * The REPEAT node will attempt to move on to the next iteration if its child is ever in a 'SUCCEEDED' state.\n */\nexport default class Repeat extends Decorator {\n /**\n * @param attributes The node attributes.\n * @param iterations The number of iterations to repeat the child node.\n * @param iterationsMin The minimum possible number of iterations to repeat the child node.\n * @param iterationsMax The maximum possible number of iterations to repeat the child node.\n * @param child The child node.\n */\n constructor(\n attributes: Attribute[],\n private iterations: number | null,\n private iterationsMin: number | null,\n private iterationsMax: number | null,\n child: Node\n ) {\n super(\"repeat\", attributes, child);\n }\n\n /**\n * The number of target iterations to make.\n */\n private targetIterationCount: number | null = null;\n\n /**\n * The current iteration count.\n */\n private currentIterationCount: number = 0;\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // If this node is in the READY state then we need to reset the child and the target iteration count.\n if (this.is(State.READY)) {\n // Reset the child node.\n this.child.reset();\n\n // Reset the current iteration count.\n this.currentIterationCount = 0;\n\n // Set the target iteration count.\n this.setTargetIterationCount(options);\n }\n\n // Do a check to see if we can iterate. If we can then this node will move into the 'RUNNING' state.\n // If we cannot iterate then we have hit our target iteration count, which means that the node has succeeded.\n if (this.canIterate()) {\n // This node is in the running state and can do its initial iteration.\n this.setState(State.RUNNING);\n\n // We may have already completed an iteration, meaning that the child node will be in the SUCCEEDED state.\n // If this is the case then we will have to reset the child node now.\n if (this.child.getState() === State.SUCCEEDED) {\n this.child.reset();\n }\n\n // Update the child of this node.\n this.child.update(agent, options);\n\n // If the child moved into the FAILED state when we updated it then there is nothing left to do and this node has also failed.\n // If it has moved into the SUCCEEDED state then we have completed the current iteration.\n if (this.child.getState() === State.FAILED) {\n // The child has failed, meaning that this node has failed.\n this.setState(State.FAILED);\n\n return;\n } else if (this.child.getState() === State.SUCCEEDED) {\n // We have completed an iteration.\n this.currentIterationCount += 1;\n }\n } else {\n // This node is in the 'SUCCEEDED' state as we cannot iterate any more.\n this.setState(State.SUCCEEDED);\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => {\n if (this.iterations !== null) {\n return `REPEAT ${this.iterations}x`;\n } else if (this.iterationsMin !== null && this.iterationsMax !== null) {\n return `REPEAT ${this.iterationsMin}x-${this.iterationsMax}x`;\n } else {\n return \"REPEAT\";\n }\n };\n\n /**\n * Reset the state of the node.\n */\n reset = () => {\n // Reset the state of this node.\n this.setState(State.READY);\n\n // Reset the current iteration count.\n this.currentIterationCount = 0;\n\n // Reset the child node.\n this.child.reset();\n };\n\n /**\n * Gets whether an iteration can be made.\n * @returns Whether an iteration can be made.\n */\n private canIterate = () => {\n if (this.targetIterationCount !== null) {\n // We can iterate as long as we have not reached our target iteration count.\n return this.currentIterationCount < this.targetIterationCount;\n }\n\n // If neither an iteration count or a condition function were defined then we can iterate indefinitely.\n return true;\n };\n\n /**\n * Sets the target iteration count.\n * @param options The behaviour tree options object.\n */\n private setTargetIterationCount = (options: BehaviourTreeOptions) => {\n // Are we dealing with an explicit iteration count or will we be randomly picking a iteration count between the min and max iteration count.\n if (this.iterations !== null) {\n this.targetIterationCount = this.iterations;\n } else if (this.iterationsMin !== null && this.iterationsMax !== null) {\n // We will be picking a random iteration count between a min and max iteration count, if the optional 'random'\n // behaviour tree function option is defined then we will be using that, otherwise we will fall back to using Math.random.\n const random = typeof options.random === \"function\" ? options.random : Math.random;\n\n // Pick a random iteration count between a min and max iteration count.\n this.targetIterationCount = Math.floor(\n random() * (this.iterationsMax - this.iterationsMin + 1) + this.iterationsMin\n );\n } else {\n this.targetIterationCount = null;\n }\n };\n}\n", "import Node from \"../Node\";\nimport Decorator from \"./Decorator\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A RETRY node.\n * The node has a single child which can have:\n * -- A number of iterations for which to repeat the child node.\n * -- An infinite repeat loop if neither an iteration count or a condition function is defined.\n * The RETRY node will stop and have a 'SUCCEEDED' state if its child is ever in a 'SUCCEEDED' state after an update.\n * The RETRY node will attempt to move on to the next iteration if its child is ever in a 'FAILED' state.\n */\nexport default class Retry extends Decorator {\n /**\n * @param attributes The node attributes.\n * @param attempts The number of attempts to retry the child node.\n * @param attemptsMin The minimum possible number of attempts to retry the child node.\n * @param attemptsMax The maximum possible number of attempts to retry the child node.\n * @param child The child node.\n */\n constructor(\n attributes: Attribute[],\n private attempts: number | null,\n private attemptsMin: number | null,\n private attemptsMax: number | null,\n child: Node\n ) {\n super(\"retry\", attributes, child);\n }\n\n /**\n * The number of target attempts to make.\n */\n private targetAttemptCount: number | null = null;\n\n /**\n * The current attempt count.\n */\n private currentAttemptCount: number = 0;\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // If this node is in the READY state then we need to reset the child and the target attempt count.\n if (this.is(State.READY)) {\n // Reset the child node.\n this.child.reset();\n\n // Reset the current attempt count.\n this.currentAttemptCount = 0;\n\n // Set the target attempt count.\n this.setTargetAttemptCount(options);\n }\n\n // Do a check to see if we can attempt. If we can then this node will move into the 'RUNNING' state.\n // If we cannot attempt then we have hit our target attempt count, which means that the node has succeeded.\n if (this.canAttempt()) {\n // This node is in the running state and can do its initial attempt.\n this.setState(State.RUNNING);\n\n // We may have already completed an attempt, meaning that the child node will be in the FAILED state.\n // If this is the case then we will have to reset the child node now.\n if (this.child.getState() === State.FAILED) {\n this.child.reset();\n }\n\n // Update the child of this node.\n this.child.update(agent, options);\n\n // If the child moved into the SUCCEEDED state when we updated it then there is nothing left to do and this node has also succeeded.\n // If it has moved into the FAILED state then we have completed the current attempt.\n if (this.child.getState() === State.SUCCEEDED) {\n // The child has succeeded, meaning that this node has succeeded.\n this.setState(State.SUCCEEDED);\n\n return;\n } else if (this.child.getState() === State.FAILED) {\n // We have completed an attempt.\n this.currentAttemptCount += 1;\n }\n } else {\n // This node is in the 'FAILED' state as we cannot iterate any more.\n this.setState(State.FAILED);\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => {\n if (this.attempts !== null) {\n return `RETRY ${this.attempts}x`;\n } else if (this.attemptsMin !== null && this.attemptsMax !== null) {\n return `RETRY ${this.attemptsMin}x-${this.attemptsMax}x`;\n } else {\n return \"RETRY\";\n }\n };\n\n /**\n * Reset the state of the node.\n */\n reset = () => {\n // Reset the state of this node.\n this.setState(State.READY);\n\n // Reset the current attempt count.\n this.currentAttemptCount = 0;\n\n // Reset the child node.\n this.child.reset();\n };\n\n /**\n * Gets whether an attempt can be made.\n * @returns Whether an attempt can be made.\n */\n canAttempt = () => {\n if (this.targetAttemptCount !== null) {\n // We can attempt as long as we have not reached our target attempt count.\n return this.currentAttemptCount < this.targetAttemptCount;\n }\n\n // If neither an attempt count or a condition function were defined then we can attempt indefinitely.\n return true;\n };\n\n /**\n * Sets the target attempt count.\n * @param options The behaviour tree options object.\n */\n setTargetAttemptCount = (options: BehaviourTreeOptions) => {\n // Are we dealing with an explicit attempt count or will we be randomly picking an attempt count between the min and max attempt count.\n if (this.attempts !== null) {\n this.targetAttemptCount = this.attempts;\n } else if (this.attemptsMin !== null && this.attemptsMax !== null) {\n // We will be picking a random attempt count between a min and max attempt count, if the optional 'random'\n // behaviour tree function option is defined then we will be using that, otherwise we will fall back to using Math.random.\n const random = typeof options.random === \"function\" ? options.random : Math.random;\n\n // Pick a random attempt count between a min and max attempt count.\n this.targetAttemptCount = Math.floor(\n random() * (this.attemptsMax - this.attemptsMin + 1) + this.attemptsMin\n );\n } else {\n this.targetAttemptCount = null;\n }\n };\n}\n", "import Node from \"../Node\";\nimport Decorator from \"./Decorator\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A Root node.\n * The root node will have a single child.\n */\nexport default class Root extends Decorator {\n /**\n * @param attributes The node attributes.\n * @param child The child node.\n */\n constructor(attributes: Attribute[], child: Node) {\n super(\"root\", attributes, child);\n }\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // If the child has never been updated or is running then we will need to update it now.\n if (this.child.getState() === State.READY || this.child.getState() === State.RUNNING) {\n // Update the child of this node.\n this.child.update(agent, options);\n }\n\n // The state of the root node is the state of its child.\n this.setState(this.child.getState());\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => \"ROOT\";\n}\n", "import Node from \"../Node\";\nimport Decorator from \"./Decorator\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A Succeed node.\n * This node wraps a single child and will always move to the 'SUCCEEDED' state when the child moves to a 'SUCCEEDED' or 'FAILED' state.\n */\nexport default class Succeed extends Decorator {\n /**\n * @param attributes The node attributes.\n * @param child The child node.\n */\n constructor(attributes: Attribute[], child: Node) {\n super(\"succeed\", attributes, child);\n }\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // If the child has never been updated or is running then we will need to update it now.\n if (this.child.getState() === State.READY || this.child.getState() === State.RUNNING) {\n this.child.update(agent, options);\n }\n\n // The state of this node will depend in the state of its child.\n switch (this.child.getState()) {\n case State.RUNNING:\n this.setState(State.RUNNING);\n break;\n\n case State.SUCCEEDED:\n case State.FAILED:\n this.setState(State.SUCCEEDED);\n break;\n\n default:\n this.setState(State.READY);\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => \"SUCCEED\";\n}\n", "import Node from \"../Node\";\n\n/**\n * A leaf node.\n */\nexport default abstract class Leaf extends Node {\n /**\n * Gets whether this node is a leaf node.\n */\n isLeafNode = () => true;\n}\n", "import { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\nimport State, { CompleteState } from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Leaf from \"./Leaf\";\nimport Lookup from \"../../Lookup\";\nimport Attribute from \"../../attributes/Attribute\";\n\n/**\n * The type representing a resolved/rejected update promise.\n */\ntype UpdatePromiseResult = {\n /**\n * Whether the promise was resolved rather than rejected.\n */\n isResolved: boolean;\n\n /**\n * The promise resolved value or rejection reason.\n */\n value: any;\n};\n\n/**\n * An Action leaf node.\n * This represents an immediate or ongoing state of behaviour.\n */\nexport default class Action extends Leaf {\n /**\n * @param attributes The node attributes.\n * @param actionName The action name.\n * @param actionArguments The array of action argument definitions.\n */\n constructor(attributes: Attribute[], private actionName: string, private actionArguments: any[]) {\n super(\"action\", attributes, actionArguments);\n }\n\n /**\n * Whether there is a pending update promise.\n */\n private isUsingUpdatePromise = false;\n\n /**\n * The finished state result of an update promise.\n */\n private updatePromiseResult: UpdatePromiseResult | null = null;\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // If the result of this action depends on an update promise then there is nothing to do until it settles.\n if (this.isUsingUpdatePromise) {\n // Are we still waiting for our update promise to settle?\n if (!this.updatePromiseResult) {\n return;\n }\n\n const { isResolved, value } = this.updatePromiseResult;\n\n // Our update promise settled, was it resolved or rejected?\n if (isResolved) {\n // Our promise resolved so check to make sure the result is a valid finished state.\n if (value !== State.SUCCEEDED && value !== State.FAILED) {\n throw new Error(\n \"action node promise resolved with an invalid value, expected a State.SUCCEEDED or State.FAILED value to be returned\"\n );\n }\n\n // Set the state of this node to match the state returned by the promise.\n this.setState(value);\n\n return;\n } else {\n // The promise was rejected, which isn't great.\n throw new Error(`action function '${this.actionName}' promise rejected with '${value}'`);\n }\n }\n\n // Attempt to get the invoker for the action function.\n const actionFuncInvoker = Lookup.getFuncInvoker(agent, this.actionName);\n\n // The action function should be defined.\n if (actionFuncInvoker === null) {\n throw new Error(\n `cannot update action node as the action '${this.actionName}' function is not defined on the agent and has not been registered`\n );\n }\n\n let actionFunctionResult;\n\n try {\n // Call the action function, the result of which may be:\n // - The finished state of this action node.\n // - A promise to return a finished node state.\n // - Undefined if the node should remain in the running state.\n actionFunctionResult = actionFuncInvoker(this.actionArguments) as CompleteState | Promise;\n } catch (error) {\n // The user was naughty and threw something.\n throw new Error(`action function '${this.actionName}' threw '${error}'`);\n }\n\n if (actionFunctionResult instanceof Promise) {\n actionFunctionResult.then(\n (result) => {\n // If 'isUpdatePromisePending' is not set then the promise was cleared as it was resolving, probably via an abort of reset.\n if (!this.isUsingUpdatePromise) {\n return;\n }\n\n // Set the resolved update promise result so that it can be handled on the next update of this node.\n this.updatePromiseResult = {\n isResolved: true,\n value: result\n };\n },\n (reason) => {\n // If 'isUpdatePromisePending' is not set then the promise was cleared as it was resolving, probably via an abort or reset.\n if (!this.isUsingUpdatePromise) {\n return;\n }\n\n // Set the rejected update promise result so that it can be handled on the next update of this node.\n this.updatePromiseResult = {\n isResolved: false,\n value: reason\n };\n }\n );\n\n // This node will be in the 'RUNNING' state until the update promise resolves.\n this.setState(State.RUNNING);\n\n // We are now waiting for the promise returned by the use to resolve before we know what state this node is in.\n this.isUsingUpdatePromise = true;\n } else {\n // Validate the returned value.\n this.validateUpdateResult(actionFunctionResult);\n\n // Set the state of this node, this may be undefined, which just means that the node is still in the 'RUNNING' state.\n this.setState(actionFunctionResult || State.RUNNING);\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => this.actionName;\n\n /**\n * Reset the state of the node.\n */\n reset = () => {\n // Reset the state of this node.\n this.setState(State.READY);\n\n // There is no longer an update promise that we care about.\n this.isUsingUpdatePromise = false;\n this.updatePromiseResult = null;\n };\n\n /**\n * Validate the result of an update function call.\n * @param result The result of an update function call.\n */\n private validateUpdateResult = (result: CompleteState | State.RUNNING) => {\n switch (result) {\n case State.SUCCEEDED:\n case State.FAILED:\n case State.RUNNING:\n case undefined:\n return;\n default:\n throw new Error(\n `expected action function '${this.actionName}' to return an optional State.SUCCEEDED or State.FAILED value but returned '${result}'`\n );\n }\n };\n}\n", "import { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Leaf from \"./Leaf\";\nimport Lookup from \"../../Lookup\";\nimport Attribute from \"../../attributes/Attribute\";\n\n/**\n * A Condition leaf node.\n * This will succeed or fail immediately based on an agent predicate, without moving to the 'RUNNING' state.\n */\nexport default class Condition extends Leaf {\n /**\n * @param attributes The node attributes.\n * @param conditionName The name of the condition function.\n * @param conditionArguments The array of condition argument definitions.\n */\n constructor(attributes: Attribute[], private conditionName: string, private conditionArguments: any[]) {\n super(\"condition\", attributes, conditionArguments);\n }\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // Attempt to get the invoker for the condition function.\n const conditionFuncInvoker = Lookup.getFuncInvoker(agent, this.conditionName);\n\n // The condition function should be defined.\n if (conditionFuncInvoker === null) {\n throw new Error(\n `cannot update condition node as the condition '${this.conditionName}' function is not defined on the agent and has not been registered`\n );\n }\n\n let conditionFunctionResult;\n\n try {\n // Call the condition function to determine the state of this node, the result of which should be a boolean.\n conditionFunctionResult = conditionFuncInvoker(this.conditionArguments);\n } catch (error) {\n // The user was naughty and threw something.\n throw new Error(`condition function '${this.conditionName}' threw '${error}'`);\n }\n\n // The result of calling the condition function must be a boolean value.\n if (typeof conditionFunctionResult !== \"boolean\") {\n throw new Error(\n `expected condition function '${this.conditionName}' to return a boolean but returned '${conditionFunctionResult}'`\n );\n }\n\n // Set the state of this node based on the result of calling the condition function.\n this.setState(!!conditionFunctionResult ? State.SUCCEEDED : State.FAILED);\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => this.conditionName;\n}\n", "import Leaf from \"./Leaf\";\nimport State from \"../../State\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { Agent } from \"../../Agent\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A WAIT node.\n * The state of this node will change to SUCCEEDED after a duration of time\n */\nexport default class Wait extends Leaf {\n /**\n * @param attributes The node attributes.\n * @param duration The duration that this node will wait to succeed in milliseconds.\n * @param durationMin The minimum possible duration in milliseconds that this node will wait to succeed.\n * @param durationMax The maximum possible duration in milliseconds that this node will wait to succeed.\n */\n constructor(\n attributes: Attribute[],\n private duration: number | null,\n private durationMin: number | null,\n private durationMax: number | null\n ) {\n super(\"wait\", attributes, []);\n }\n\n /**\n * The time in milliseconds at which this node was first updated.\n */\n private initialUpdateTime: number = 0;\n\n /**\n * The total duration in milliseconds that this node will be waiting for.\n */\n private totalDuration: number | null = null;\n\n /**\n * The duration in milliseconds that this node has been waiting for.\n */\n private waitedDuration: number = 0;\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // If this node is in the READY state then we need to set the initial update time.\n if (this.is(State.READY)) {\n // Set the initial update time.\n this.initialUpdateTime = new Date().getTime();\n\n // Set the initial waited duration.\n this.waitedDuration = 0;\n\n // Are we dealing with an explicit duration or will we be randomly picking a duration between the min and max duration.\n if (this.duration !== null) {\n this.totalDuration = this.duration;\n } else if (this.durationMin !== null && this.durationMax !== null) {\n // We will be picking a random duration between a min and max duration, if the optional 'random' behaviour tree\n // function option is defined then we will be using that, otherwise we will fall back to using Math.random.\n const random = typeof options.random === \"function\" ? options.random : Math.random;\n\n // Pick a random duration between a min and max duration.\n this.totalDuration = Math.floor(\n random() * (this.durationMax - this.durationMin + 1) + this.durationMin\n );\n } else {\n this.totalDuration = null;\n }\n\n // The node is now running until we finish waiting.\n this.setState(State.RUNNING);\n }\n\n // If we have no total duration then this wait node will wait indefinitely until it is aborted.\n if (this.totalDuration === null) {\n return;\n }\n\n // If we have a 'getDeltaTime' function defined as part of our options then we will use it to figure out how long we have waited for.\n if (typeof options.getDeltaTime === \"function\") {\n // Get the delta time.\n const deltaTime = options.getDeltaTime();\n\n // Our delta time must be a valid number and cannot be NaN.\n if (typeof deltaTime !== \"number\" || isNaN(deltaTime)) {\n throw new Error(\"The delta time must be a valid number and not NaN.\");\n }\n\n // Update the amount of time that this node has been waiting for based on the delta time.\n this.waitedDuration += deltaTime * 1000;\n } else {\n // We are not using a delta time, so we will just work out hom much time has passed since the first update.\n this.waitedDuration = new Date().getTime() - this.initialUpdateTime;\n }\n\n // Have we waited long enough?\n if (this.waitedDuration >= this.totalDuration) {\n // We have finished waiting!\n this.setState(State.SUCCEEDED);\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => {\n if (this.duration !== null) {\n return `WAIT ${this.duration}ms`;\n } else if (this.durationMin !== null && this.durationMax !== null) {\n return `WAIT ${this.durationMin}ms-${this.durationMax}ms`;\n } else {\n return \"WAIT\";\n }\n };\n}\n", "import Guard from \"./guards/Guard\";\n\nexport type AttributeDetails = {\n /** The attribute type. */\n type: string;\n\n /** The attribute arguments. */\n args: any[];\n};\n\n/**\n * A base node attribute.\n */\nexport default abstract class Attribute {\n /**\n * @param type The node attribute type.\n * @param args The array of attribute arguments.\n */\n constructor(public type: string, public args: any[]) {}\n\n /**\n * Gets the attribute details.\n */\n abstract getDetails(): TAttributeDetails;\n\n /**\n * Gets whether this attribute is a guard.\n */\n abstract isGuard: () => this is Guard;\n}\n", "import { Agent } from \"../../Agent\";\nimport Attribute, { AttributeDetails } from \"../Attribute\";\n\nexport type GuardAttributeDetails = {\n /** The name of the condition function that determines whether the guard is satisfied. */\n condition: string;\n} & AttributeDetails;\n\n/**\n * A base node guard attribute.\n */\nexport default abstract class Guard extends Attribute {\n /**\n * @param type The node attribute type.\n * @param args The array of decorator argument definitions.\n * @param condition The name of the condition function that determines whether the guard is satisfied.\n */\n constructor(type: string, args: any[], private condition: string) {\n super(type, args);\n }\n\n /**\n * Gets the name of the condition function that determines whether the guard is satisfied.\n */\n getCondition = () => this.condition;\n\n /**\n * Gets whether this attribute is a guard.\n */\n isGuard = () => true;\n\n /**\n * Gets the attribute details.\n */\n getDetails(): GuardAttributeDetails {\n return {\n type: this.type,\n args: this.args,\n condition: this.getCondition()\n };\n }\n\n /**\n * Gets whether the guard is satisfied.\n * @param agent The agent.\n * @returns Whether the guard is satisfied.\n */\n abstract isSatisfied(agent: Agent): boolean;\n}\n", "import Guard from \"./Guard\";\nimport Lookup from \"../../Lookup\";\nimport { Agent } from \"../../Agent\";\n\n/**\n * A WHILE guard which is satisfied as long as the given condition remains true.\n */\nexport default class While extends Guard {\n /**\n * @param condition The name of the condition function that determines whether the guard is satisfied.\n * @param args The array of decorator argument definitions.\n */\n constructor(condition: string, args: any[]) {\n super(\"while\", args, condition);\n }\n\n /**\n * Gets whether the guard is satisfied.\n * @param agent The agent.\n * @returns Whether the guard is satisfied.\n */\n isSatisfied = (agent: Agent) => {\n // Attempt to get the invoker for the condition function.\n const conditionFuncInvoker = Lookup.getFuncInvoker(agent, this.getCondition());\n\n // The condition function should be defined.\n if (conditionFuncInvoker === null) {\n throw new Error(\n `cannot evaluate node guard as the condition '${this.getCondition()}' function is not defined on the agent and has not been registered`\n );\n }\n\n // Call the condition function to determine whether this guard is satisfied.\n return !!conditionFuncInvoker(this.args);\n };\n}\n", "import Guard from \"./Guard\";\nimport Lookup from \"../../Lookup\";\nimport { Agent } from \"../../Agent\";\n\n/**\n * An UNTIL guard which is satisfied as long as the given condition remains false.\n */\nexport default class Until extends Guard {\n /**\n * @param condition The name of the condition function that determines whether the guard is satisfied.\n * @param args The array of decorator argument definitions.\n */\n constructor(condition: string, args: any[]) {\n super(\"until\", args, condition);\n }\n\n /**\n * Gets whether the guard is satisfied.\n * @param agent The agent.\n * @returns Whether the guard is satisfied.\n */\n isSatisfied = (agent: Agent) => {\n // Attempt to get the invoker for the condition function.\n const conditionFuncInvoker = Lookup.getFuncInvoker(agent, this.getCondition());\n\n // The condition function should be defined.\n if (conditionFuncInvoker === null) {\n throw new Error(\n `cannot evaluate node guard as the condition '${this.getCondition()}' function is not defined on the agent and has not been registered`\n );\n }\n\n // Call the condition function to determine whether this guard is satisfied.\n return !!!conditionFuncInvoker(this.args);\n };\n}\n", "import { Agent } from \"../../Agent\";\nimport Attribute, { AttributeDetails } from \"../Attribute\";\n\nexport type CallbackAttributeDetails = {\n /** The name of the agent function that is called. */\n functionName: string;\n} & AttributeDetails;\n\n/**\n * A base node callback attribute.\n */\nexport default abstract class Callback extends Attribute {\n /**\n * @param type The node attribute type.\n * @param args The array of decorator argument definitions.\n * @param functionName The name of the agent function to call.\n */\n constructor(type: string, args: any[], private functionName: string) {\n super(type, args);\n }\n\n /**\n * Gets the name of the agent function to call.\n */\n getFunctionName = () => this.functionName;\n\n /**\n * Gets whether this attribute is a guard.\n */\n isGuard = () => false;\n\n /**\n * Gets the attribute details.\n */\n getDetails(): CallbackAttributeDetails {\n return {\n type: this.type,\n args: this.args,\n functionName: this.getFunctionName()\n };\n }\n\n /**\n * Attempt to call the agent function that this callback refers to.\n * @param agent The agent.\n */\n abstract callAgentFunction: (agent: Agent, isSuccess: boolean, isAborted: boolean) => void;\n}\n", "import Callback from \"./Callback\";\nimport Lookup from \"../../Lookup\";\nimport { Agent } from \"../../Agent\";\n\n/**\n * An ENTRY callback which defines an agent function to call when the associated node is updated and moves out of running state.\n */\nexport default class Entry extends Callback {\n /**\n * @param functionName The name of the agent function to call.\n * @param args The array of callback argument definitions.\n */\n constructor(functionName: string, args: any[]) {\n super(\"entry\", args, functionName);\n }\n\n /**\n * Attempt to call the agent function that this callback refers to.\n * @param agent The agent.\n */\n callAgentFunction = (agent: Agent) => {\n // Attempt to get the invoker for the callback function.\n const callbackFuncInvoker = Lookup.getFuncInvoker(agent, this.getFunctionName());\n\n // The callback function should be defined.\n if (callbackFuncInvoker === null) {\n throw new Error(\n `cannot call entry function '${this.getFunctionName()}' as is not defined on the agent and has not been registered`\n );\n }\n\n // Call the callback function.\n callbackFuncInvoker(this.args);\n };\n}\n", "import Callback from \"./Callback\";\nimport Lookup from \"../../Lookup\";\nimport { Agent } from \"../../Agent\";\n\n/**\n * A STEP callback which defines an agent function to call when the associated node is updated.\n */\nexport default class Step extends Callback {\n /**\n * @param functionName The name of the agent function to call.\n * @param args The array of callback argument definitions.\n */\n constructor(functionName: string, args: any[]) {\n super(\"step\", args, functionName);\n }\n\n /**\n * Attempt to call the agent function that this callback refers to.\n * @param agent The agent.\n */\n callAgentFunction = (agent: Agent) => {\n // Attempt to get the invoker for the callback function.\n const callbackFuncInvoker = Lookup.getFuncInvoker(agent, this.getFunctionName());\n\n // The callback function should be defined.\n if (callbackFuncInvoker === null) {\n throw new Error(\n `cannot call step function '${this.getFunctionName()}' as is not defined on the agent and has not been registered`\n );\n }\n\n // Call the callback function.\n callbackFuncInvoker(this.args);\n };\n}\n", "import Callback from \"./Callback\";\nimport Lookup from \"../../Lookup\";\nimport { Agent } from \"../../Agent\";\n\n/**\n * An EXIT callback which defines an agent function to call when the associated node is updated and moves to a finished state or is aborted.\n */\nexport default class Exit extends Callback {\n /**\n * @param functionName The name of the agent function to call.\n * @param args The array of callback argument definitions.\n */\n constructor(functionName: string, args: any[]) {\n super(\"exit\", args, functionName);\n }\n\n /**\n * Attempt to call the agent function that this callback refers to.\n * @param agent The agent.\n * @param isSuccess Whether the decorated node was left with a success state.\n * @param isAborted Whether the decorated node was aborted.\n */\n callAgentFunction = (agent: Agent, isSuccess: boolean, isAborted: boolean) => {\n // Attempt to get the invoker for the callback function.\n const callbackFuncInvoker = Lookup.getFuncInvoker(agent, this.getFunctionName());\n\n // The callback function should be defined.\n if (callbackFuncInvoker === null) {\n throw new Error(\n `cannot call exit function '${this.getFunctionName()}' as is not defined on the agent and has not been registered`\n );\n }\n\n // Call the callback function\n callbackFuncInvoker([{ succeeded: isSuccess, aborted: isAborted }, ...this.args]);\n };\n}\n", "import { AnyNodeDefinition, RootNodeDefinition } from \"./BehaviourTreeDefinition\";\nimport GuardPath, { GuardPathPart } from \"./attributes/guards/GuardPath\";\nimport { validateBranchSubtreeLinks } from \"./BehaviourTreeDefinitionValidator\";\nimport { isInteger } from \"./BehaviourTreeDefinitionUtilities\";\nimport Node from \"./nodes/Node\";\nimport Composite from \"./nodes/composite/Composite\";\nimport Decorator from \"./nodes/decorator/Decorator\";\nimport Parallel from \"./nodes/composite/Parallel\";\nimport Selector from \"./nodes/composite/Selector\";\nimport Sequence from \"./nodes/composite/Sequence\";\nimport Lotto from \"./nodes/composite/Lotto\";\nimport Fail from \"./nodes/decorator/Fail\";\nimport Flip from \"./nodes/decorator/Flip\";\nimport Repeat from \"./nodes/decorator/Repeat\";\nimport Retry from \"./nodes/decorator/Retry\";\nimport Root from \"./nodes/decorator/Root\";\nimport Succeed from \"./nodes/decorator/Succeed\";\nimport Action from \"./nodes/leaf/Action\";\nimport Condition from \"./nodes/leaf/Condition\";\nimport Wait from \"./nodes/leaf/Wait\";\nimport Lookup from \"./Lookup\";\nimport Attribute from \"./attributes/Attribute\";\nimport While from \"./attributes/guards/While\";\nimport Until from \"./attributes/guards/Until\";\nimport Entry from \"./attributes/callbacks/Entry\";\nimport Step from \"./attributes/callbacks/Step\";\nimport Exit from \"./attributes/callbacks/Exit\";\n\n/**\n * A type representing any node instance in a behaviour tree.\n */\ntype AnyNode =\n | Root\n | Action\n | Condition\n | Wait\n | Sequence\n | Selector\n | Lotto\n | Parallel\n | Repeat\n | Retry\n | Flip\n | Succeed\n | Fail;\n\n/**\n * A type defining a mapping of root node identifiers to root node definitions.\n */\ntype RootNodeDefinitionMap = { [key: string | symbol]: RootNodeDefinition };\n\n/**\n * A symbol to use as the main root key in any root node mappings.\n */\nconst MAIN_ROOT_NODE_KEY = Symbol(\"__root__\");\n\n/**\n * Build and populate the root nodes based on the provided definition, assuming that the definition has been validated.\n * @param definition The root node definitions.\n * @returns The built and populated root node definitions.\n */\nexport default function buildRootNode(definition: RootNodeDefinition[]): Root {\n // Create a mapping of root node identifers to root node definitions, including globally registered subtree root node definitions.\n const rootNodeDefinitionMap = createRootNodeDefinitionMap(definition);\n\n // Now that we have all of our root node definitions (those part of the tree definition and those globally registered)\n // we should validate the branch-subtree links. This will also double-check that we dont have any circular dependencies\n // in our branch-subtree references and that we have no broken branch-subtree links.\n validateBranchSubtreeLinks(\n [rootNodeDefinitionMap[MAIN_ROOT_NODE_KEY], ...Object.values(rootNodeDefinitionMap)],\n true\n );\n\n // Create our populated tree of node instances, starting with our main root node.\n const rootNode = nodeFactory(rootNodeDefinitionMap[MAIN_ROOT_NODE_KEY], rootNodeDefinitionMap) as Root;\n\n // Set a guard path on every leaf of the tree to evaluate as part of each update.\n applyLeafNodeGuardPaths(rootNode);\n\n // We only need to return the main root node.\n return rootNode;\n}\n\n/**\n * A factory function which creates a node instance based on the specified definition.\n * @param definition The node definition.\n * @param rootNodeDefinitionMap The mapping of root node identifers to root node definitions, including globally registered subtree root node definitions.\n * @returns A node instance based on the specified definition.\n */\nfunction nodeFactory(definition: AnyNodeDefinition, rootNodeDefinitionMap: RootNodeDefinitionMap): AnyNode {\n // Get the attributes for the node.\n const attributes = nodeAttributesFactory(definition);\n\n // Create the node instance based on the definition type.\n switch (definition.type) {\n case \"root\":\n return new Root(attributes, nodeFactory(definition.child, rootNodeDefinitionMap));\n\n case \"repeat\":\n let iterations: number | null = null;\n let iterationsMin: number | null = null;\n let iterationsMax: number | null = null;\n\n if (Array.isArray(definition.iterations)) {\n iterationsMin = definition.iterations[0];\n iterationsMax = definition.iterations[1];\n } else if (isInteger(definition.iterations)) {\n iterations = definition.iterations!;\n }\n\n return new Repeat(\n attributes,\n iterations,\n iterationsMin,\n iterationsMax,\n nodeFactory(definition.child, rootNodeDefinitionMap)\n );\n\n case \"retry\":\n let attempts: number | null = null;\n let attemptsMin: number | null = null;\n let attemptsMax: number | null = null;\n\n if (Array.isArray(definition.attempts)) {\n attemptsMin = definition.attempts[0];\n attemptsMax = definition.attempts[1];\n } else if (isInteger(definition.attempts)) {\n attempts = definition.attempts!;\n }\n\n return new Retry(\n attributes,\n attempts,\n attemptsMin,\n attemptsMax,\n nodeFactory(definition.child, rootNodeDefinitionMap)\n );\n\n case \"flip\":\n return new Flip(attributes, nodeFactory(definition.child, rootNodeDefinitionMap));\n\n case \"succeed\":\n return new Succeed(attributes, nodeFactory(definition.child, rootNodeDefinitionMap));\n\n case \"fail\":\n return new Fail(attributes, nodeFactory(definition.child, rootNodeDefinitionMap));\n\n case \"sequence\":\n return new Sequence(\n attributes,\n definition.children.map((child) => nodeFactory(child, rootNodeDefinitionMap))\n );\n\n case \"selector\":\n return new Selector(\n attributes,\n definition.children.map((child) => nodeFactory(child, rootNodeDefinitionMap))\n );\n\n case \"parallel\":\n return new Parallel(\n attributes,\n definition.children.map((child) => nodeFactory(child, rootNodeDefinitionMap))\n );\n\n case \"lotto\":\n return new Lotto(\n attributes,\n definition.weights,\n definition.children.map((child) => nodeFactory(child, rootNodeDefinitionMap))\n );\n\n case \"branch\":\n return nodeFactory(rootNodeDefinitionMap[definition.ref].child, rootNodeDefinitionMap);\n\n case \"action\":\n return new Action(attributes, definition.call, definition.args || []);\n\n case \"condition\":\n return new Condition(attributes, definition.call, definition.args || []);\n\n case \"wait\":\n let duration: number | null = null;\n let durationMin: number | null = null;\n let durationMax: number | null = null;\n\n if (Array.isArray(definition.duration)) {\n durationMin = definition.duration[0];\n durationMax = definition.duration[1];\n } else if (isInteger(definition.duration)) {\n duration = definition.duration!;\n }\n\n return new Wait(attributes, duration, durationMin, durationMax);\n }\n}\n\n/**\n * Creates an array of node attribute instances based on the specified node definition.\n * @param definition The node definition.\n * @returns An array of node attribute instances based on the specified node definition.\n */\nfunction nodeAttributesFactory(definition: AnyNodeDefinition): Attribute[] {\n const attributes: Attribute[] = [];\n\n if (definition.while) {\n attributes.push(new While(definition.while.call, definition.while.args ?? []));\n }\n\n if (definition.until) {\n attributes.push(new Until(definition.until.call, definition.until.args ?? []));\n }\n\n if (definition.entry) {\n attributes.push(new Entry(definition.entry.call, definition.entry.args ?? []));\n }\n\n if (definition.step) {\n attributes.push(new Step(definition.step.call, definition.step.args ?? []));\n }\n\n if (definition.exit) {\n attributes.push(new Exit(definition.exit.call, definition.exit.args ?? []));\n }\n\n return attributes;\n}\n\n/**\n * Creates a mapping of root node identifers to root node definitions, mixing in globally registered subtree root node definitions.\n * @param definition The root node definitions.\n * @returns A mapping of root node identifers to root node definitions, including globally registered subtree root node definitions.\n */\nfunction createRootNodeDefinitionMap(definition: RootNodeDefinition[]): RootNodeDefinitionMap {\n // Create a mapping of root node identifers to root node definitions.\n const rootNodeMap: RootNodeDefinitionMap = {};\n\n // Add in any registered subtree root node definitions.\n for (const [name, rootNodeDefinition] of Object.entries(Lookup.getSubtrees())) {\n // The name used when registering the subtree will be used as the root node identifier.\n rootNodeMap[name] = { ...rootNodeDefinition, id: name };\n }\n\n // Populate the map with the root node definitions that were included with the tree definition.\n // We do this after adding any registered subtrees as we want these to take presedence.\n for (const rootNodeDefinition of definition) {\n rootNodeMap[rootNodeDefinition.id ?? MAIN_ROOT_NODE_KEY] = rootNodeDefinition;\n }\n\n return rootNodeMap;\n}\n\n/**\n * Applies a guard path to every leaf of the tree to evaluate as part of each update.\n * @param root The main root tree node.\n */\nfunction applyLeafNodeGuardPaths(root: Root) {\n const nodePaths: Node[][] = [];\n\n const findLeafNodes = (path: Node[], node: Node) => {\n // Add the current node to the path.\n path = path.concat(node);\n\n // Check whether the current node is a leaf node.\n if (node.isLeafNode()) {\n nodePaths.push(path);\n } else {\n (node as Composite | Decorator).getChildren().forEach((child) => findLeafNodes(path, child));\n }\n };\n\n // Find all leaf node paths, starting from the root.\n findLeafNodes([], root);\n\n nodePaths.forEach((path) => {\n // Each node in the current path will have to be assigned a guard path, working from the root outwards.\n for (let depth = 0; depth < path.length; depth++) {\n // Get the node in the path at the current depth.\n const currentNode = path[depth];\n\n // The node may already have been assigned a guard path, if so just skip it.\n if (currentNode.hasGuardPath()) {\n continue;\n }\n\n // Create the guard path for the current node.\n const guardPath = new GuardPath(\n path\n .slice(0, depth + 1)\n .map((node) => ({ node, guards: node.getGuardAttributes() }))\n .filter((details) => details.guards.length > 0)\n );\n\n // Assign the guard path to the current node.\n currentNode.setGuardPath(guardPath);\n }\n });\n}\n", "import State, { AnyState } from \"./State\";\nimport Lookup from \"./Lookup\";\nimport Node from \"./nodes/Node\";\nimport Root from \"./nodes/decorator/Root\";\nimport Composite from \"./nodes/composite/Composite\";\nimport Decorator from \"./nodes/decorator/Decorator\";\nimport { Agent, GlobalFunction } from \"./Agent\";\nimport { CallbackAttributeDetails } from \"./attributes/callbacks/Callback\";\nimport { GuardAttributeDetails } from \"./attributes/guards/Guard\";\nimport { BehaviourTreeOptions } from \"./BehaviourTreeOptions\";\nimport { convertMDSLToJSON } from \"./mdsl/MDSLDefinitionParser\";\nimport { RootNodeDefinition } from \"./BehaviourTreeDefinition\";\nimport { validateDefinition, validateJSONDefinition } from \"./BehaviourTreeDefinitionValidator\";\nimport buildRootNode from \"./BehaviourTreeBuilder\";\nimport { isNullOrUndefined } from \"./BehaviourTreeDefinitionUtilities\";\n\n// Purely for outside inspection of the tree.\nexport type FlattenedTreeNode = {\n id: string;\n type: string;\n caption: string;\n state: AnyState;\n guards: GuardAttributeDetails[];\n callbacks: CallbackAttributeDetails[];\n args: any[];\n parentId: string | null;\n};\n\n/**\n * A representation of a behaviour tree.\n */\nexport class BehaviourTree {\n /**\n * The main root tree node.\n */\n private readonly _rootNode: Root;\n\n /**\n * Creates a new instance of the BehaviourTree class.\n * @param definition The behaviour tree definition as either an MDSL string, root node definition object or array of root node definition objects.\n * @param agent The agent instance that this behaviour tree is modelling behaviour for.\n * @param options The behaviour tree options object.\n */\n constructor(\n definition: string | RootNodeDefinition | RootNodeDefinition[],\n private agent: Agent,\n private options: BehaviourTreeOptions = {}\n ) {\n // The tree definition must be defined.\n if (isNullOrUndefined(definition)) {\n throw new Error(\"tree definition not defined\");\n }\n\n // The agent must be defined and not null.\n if (typeof agent !== \"object\" || agent === null) {\n throw new Error(\"the agent must be an object and not null\");\n }\n\n // We should validate the definition before we try to build the tree nodes.\n const { succeeded, errorMessage, json } = validateDefinition(definition);\n\n // Did our validation fail without error?\n if (!succeeded) {\n throw new Error(`invalid definition: ${errorMessage}`);\n }\n\n // Double check that we did actually get our json definition as part of our definition validtion.\n if (!json) {\n throw new Error(\n \"expected json definition to be returned as part of successful definition validation response\"\n );\n }\n\n try {\n // Create the populated tree of behaviour tree nodes and get the root node.\n this._rootNode = buildRootNode(json);\n } catch (exception) {\n // There was an issue in trying build and populate the behaviour tree.\n throw new Error(`error building tree: ${(exception as Error).message}`);\n }\n }\n\n /**\n * Gets whether the tree is in the RUNNING state.\n * @returns true if the tree is in the RUNNING state, otherwise false.\n */\n isRunning() {\n return this._rootNode.getState() === State.RUNNING;\n }\n\n /**\n * Gets the current tree state of SUCCEEDED, FAILED, READY or RUNNING.\n * @returns The current tree state.\n */\n getState() {\n return this._rootNode.getState();\n }\n\n /**\n * Step the tree.\n * 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.\n * 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\n * 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.\n *\n * 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.\n */\n step() {\n // If the root node has already been stepped to completion then we need to reset it.\n if (this._rootNode.getState() === State.SUCCEEDED || this._rootNode.getState() === State.FAILED) {\n this._rootNode.reset();\n }\n\n try {\n this._rootNode.update(this.agent, this.options);\n } catch (exception) {\n throw new Error(`error stepping tree: ${(exception as Error).message}`);\n }\n }\n\n /**\n * Resets the tree from the root node outwards to each nested node, giving each a state of READY.\n */\n reset() {\n this._rootNode.reset();\n }\n\n /**\n * Gets the flattened details of every node in the tree.\n * @returns The flattened details of every node in the tree.\n */\n getFlattenedNodeDetails(): FlattenedTreeNode[] {\n // Create an empty flattened array of tree nodes.\n const flattenedTreeNodes: FlattenedTreeNode[] = [];\n\n /**\n * Helper function to process a node instance and push details into the flattened tree nodes array.\n * @param node The current node.\n * @param parentUid The UID of the node parent, or null if the node is the main root node.\n */\n const processNode = (node: Node, parentUid: string | null) => {\n // Get the guard and callback attribute details for this node.\n const guards = node\n .getAttributes()\n .filter((attribute) => attribute.isGuard())\n .map((attribute) => attribute.getDetails()) as GuardAttributeDetails[];\n const callbacks = node\n .getAttributes()\n .filter((attribute) => !attribute.isGuard())\n .map((attribute) => attribute.getDetails()) as CallbackAttributeDetails[];\n\n // Push the current node into the flattened nodes array.\n flattenedTreeNodes.push({\n id: node.getUid(),\n type: node.getType(),\n caption: node.getName(),\n state: node.getState(),\n guards,\n callbacks,\n args: node.getArguments(),\n parentId: parentUid\n });\n\n // Process each of the nodes children if it is not a leaf node.\n if (!node.isLeafNode()) {\n (node as Composite | Decorator)\n .getChildren()\n .forEach((child) => processNode(child, (node as Composite | Decorator).getUid()));\n }\n };\n\n // Convert the nested node structure into a flattened array of node details.\n processNode(this._rootNode, null);\n\n return flattenedTreeNodes;\n }\n\n /**\n * Registers the action/condition/guard/callback function or subtree with the given name.\n * @param name The name of the function or subtree to register.\n * @param value The function or subtree definition to register.\n */\n static register(name: string, value: GlobalFunction | string | RootNodeDefinition) {\n // Are we going to register a action/condition/guard/callback function?\n if (typeof value === \"function\") {\n Lookup.setFunc(name, value);\n return;\n }\n\n // We are not registering an action/condition/guard/callback function, so we must be registering a subtree.\n if (typeof value === \"string\") {\n let rootNodeDefinitions: RootNodeDefinition[];\n\n // We will assume that any string passed in will be a mdsl definition.\n try {\n rootNodeDefinitions = convertMDSLToJSON(value);\n } catch (exception) {\n throw new Error(`error registering definition, invalid MDSL: ${(exception as Error).message}`);\n }\n\n // This function should only ever be called with a definition containing a single unnamed root node.\n if (rootNodeDefinitions.length != 1 || rootNodeDefinitions[0].id !== null) {\n throw new Error(\"error registering definition: expected a single unnamed root node\");\n }\n\n try {\n // We should validate the subtree as we don't want invalid subtrees available via the lookup.\n const { succeeded, errorMessage } = validateJSONDefinition(rootNodeDefinitions[0]);\n\n // Did our validation fail without error?\n if (!succeeded) {\n throw new Error(errorMessage);\n }\n } catch (exception) {\n throw new Error(`error registering definition: ${(exception as Error).message}`);\n }\n\n // Everything seems hunky-dory, register the subtree.\n Lookup.setSubtree(name, rootNodeDefinitions[0]);\n } else if (typeof value === \"object\" && !Array.isArray(value)) {\n // We will assume that any object passed in is a root node definition.\n\n try {\n // We should validate the subtree as we don't want invalid subtrees available via the lookup.\n const { succeeded, errorMessage } = validateJSONDefinition(value);\n\n // Did our validation fail without error?\n if (!succeeded) {\n throw new Error(errorMessage);\n }\n } catch (exception) {\n throw new Error(`error registering definition: ${(exception as Error).message}`);\n }\n\n // Everything seems hunky-dory, register the subtree.\n Lookup.setSubtree(name, value);\n } else {\n throw new Error(\"unexpected value, expected string mdsl definition, root node json definition or function\");\n }\n }\n\n /**\n * Unregisters the registered action/condition/guard/callback function or subtree with the given name.\n * @param name The name of the registered action/condition/guard/callback function or subtree to unregister.\n */\n static unregister(name: string): void {\n Lookup.remove(name);\n }\n\n /**\n * Unregister all registered action/condition/guard/callback functions and subtrees.\n */\n static unregisterAll(): void {\n Lookup.empty();\n }\n}\n"], - "mappings": "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", + "sourcesContent": ["\"use strict\";\r\nObject.defineProperty(exports, \"__esModule\", { value: true });\r\nexports.Participant = void 0;\r\n/**\r\n * A participant that holds a number of tickets.\r\n */\r\nvar Participant = /** @class */ (function () {\r\n /**\r\n * Creates an instance of the Participant class.\r\n * @param participant The actual participant.\r\n * @param tickets The number of tickets held by the participant.\r\n */\r\n function Participant(participant, tickets) {\r\n if (tickets === void 0) { tickets = 1; }\r\n this._participant = participant;\r\n this._tickets = tickets;\r\n }\r\n Object.defineProperty(Participant.prototype, \"participant\", {\r\n /** Gets the actual participant. */\r\n get: function () {\r\n return this._participant;\r\n },\r\n enumerable: false,\r\n configurable: true\r\n });\r\n Object.defineProperty(Participant.prototype, \"tickets\", {\r\n /** Gets or sets the number of tickets held by the participant. */\r\n get: function () {\r\n return this._tickets;\r\n },\r\n set: function (value) {\r\n this._tickets = value;\r\n },\r\n enumerable: false,\r\n configurable: true\r\n });\r\n return Participant;\r\n}());\r\nexports.Participant = Participant;\r\n", "\"use strict\";\r\nObject.defineProperty(exports, \"__esModule\", { value: true });\r\nexports.isNaturalNumber = exports.isNullOrUndefined = void 0;\r\n/**\r\n * Gets whether the value provided is null or undefined.\r\n * @param value The value to check.\r\n * @returns Whether the value provided is null or undefined.\r\n */\r\nfunction isNullOrUndefined(value) {\r\n return value === null || value === undefined;\r\n}\r\nexports.isNullOrUndefined = isNullOrUndefined;\r\n/**\r\n * Gets whether the value provided is a natural number.\r\n * @param value The value to check.\r\n * @returns Whether the value provided is a natural number.\r\n */\r\nfunction isNaturalNumber(value) {\r\n return typeof value === \"number\" && value >= 1 && Math.floor(value) === value;\r\n}\r\nexports.isNaturalNumber = isNaturalNumber;\r\n", "\"use strict\";\r\nObject.defineProperty(exports, \"__esModule\", { value: true });\r\nexports.Lotto = void 0;\r\nvar Participant_1 = require(\"./Participant\");\r\nvar Utilities_1 = require(\"./Utilities\");\r\n/**\r\n * Represents a lotto consisting of a number of pickable ticket-holding participants.\r\n */\r\nvar Lotto = /** @class */ (function () {\r\n /**\r\n * Creates a new instance of Lotto.\r\n * @param customRandom The custom RNG to use in place of Math.random().\r\n */\r\n function Lotto(customRandom) {\r\n /** The array of participants that are holding tickets in the lotto. */\r\n this._participants = [];\r\n this._customRandom = customRandom;\r\n }\r\n /**\r\n * Adds a participant with the specified number of tickets, or adds to the participant ticket count if the participant already holds tickets.\r\n * @param participant The participant to add or to increase the ticket count for if they already hold tickets.\r\n * @param tickets The number of tickets, defaults to 1.\r\n * @returns The Lotto instance.\r\n */\r\n Lotto.prototype.add = function (participant, tickets) {\r\n if (tickets === void 0) { tickets = 1; }\r\n // Check that we have a valid ticket count.\r\n if (!(0, Utilities_1.isNaturalNumber)(tickets)) {\r\n throw new Error(\"tickets value must be a natural number\");\r\n }\r\n // Check whether this participant has already been added.\r\n var existingParticipant = this._participants.find(function (part) { return part.participant === participant; });\r\n if (existingParticipant) {\r\n // The participant has already been added to the lotto so just add to their ticket count.\r\n existingParticipant.tickets += tickets;\r\n }\r\n else {\r\n // The participant is not part of the lotto so we should add them.\r\n this._participants.push(new Participant_1.Participant(participant, tickets));\r\n }\r\n return this;\r\n };\r\n /**\r\n * Removes the specified number of tickets for the given participant from the draw, or all tickets if a ticket number is not defined.\r\n * @param participant The participant to remove tickets for.\r\n * @param tickets The number of tickets to remove, or undefined if all tickets are to be removed.\r\n * @returns The Lotto instance.\r\n */\r\n Lotto.prototype.remove = function (participant, tickets) {\r\n // Attempt to get the existing participant.\r\n var existingParticipant = this._participants.find(function (part) { return part.participant === participant; });\r\n // There is nothing to do if the specified participant isn't even part of the lotto.\r\n if (!existingParticipant) {\r\n return this;\r\n }\r\n // Check whether a tickets value was given.\r\n if (tickets !== undefined) {\r\n // Check that we have a valid ticket count.\r\n if (!(0, Utilities_1.isNaturalNumber)(tickets)) {\r\n throw new Error(\"tickets value must be a natural number\");\r\n }\r\n existingParticipant.tickets -= tickets;\r\n // If the participant no longer holds any tickets then they should be removed.\r\n if (existingParticipant.tickets < 1) {\r\n this._participants = this._participants.filter(function (part) { return part !== existingParticipant; });\r\n }\r\n }\r\n else {\r\n // We are removing all tickets for the participant so just remove them from the lotto.\r\n this._participants = this._participants.filter(function (part) { return part !== existingParticipant; });\r\n }\r\n return this;\r\n };\r\n /**\r\n * Draw a winning ticket and return the participant that holds the ticket.\r\n * @param options The draw options.\r\n * @returns The participant that holds the winning ticket.\r\n */\r\n Lotto.prototype.draw = function (options) {\r\n if (options === void 0) { options = {}; }\r\n // If we have no participants then just return null.\r\n if (this._participants.length === 0) {\r\n return null;\r\n }\r\n var redrawable = (0, Utilities_1.isNullOrUndefined)(options.redrawable) ? true : options.redrawable;\r\n var pickable = [];\r\n this._participants.forEach(function (_a) {\r\n var participant = _a.participant, tickets = _a.tickets;\r\n for (var ticketCount = 0; ticketCount < tickets; ticketCount++) {\r\n pickable.push(participant);\r\n }\r\n });\r\n var random;\r\n // We need a random floating-point number between 0 (inclusive) and 1 to scale up to pick our winner.\r\n // If a custom random function exists then we should use that or fall back to Math.random().\r\n if (this._customRandom) {\r\n // Call our custom random function to get a random floating-point number.\r\n random = this._customRandom();\r\n // Verify that the result of calling our custom random function is a number between 0 (inclusive) and 1.\r\n if (typeof random !== \"number\" || random < 0 || random >= 1) {\r\n throw new Error(\"the 'random' function provided did not return a number between 0 (inclusive) and 1\");\r\n }\r\n }\r\n else {\r\n // No custom random function was defined so just use good ol' Math.random().\r\n random = Math.random();\r\n }\r\n // Pick a winning participant.\r\n var winner = pickable[Math.floor(random * pickable.length)];\r\n // If the ticket isn't redrawable then we should remove a ticket from the winning participants ticket count.\r\n if (!redrawable) {\r\n this.remove(winner, 1);\r\n }\r\n // Return the winning participant.\r\n return winner;\r\n };\r\n /**\r\n * Draws multiple winning tickets and return an array of the participants that hold the winning tickets.\r\n * @param tickets The number of winning tickets to draw.\r\n * @param options The draw multiple options.\r\n * @returns An array of the participants that hold the winning tickets.\r\n */\r\n Lotto.prototype.drawMultiple = function (tickets, options) {\r\n if (options === void 0) { options = {}; }\r\n var uniqueResults = (0, Utilities_1.isNullOrUndefined)(options.unique) ? false : options.unique;\r\n // Handle cases where the user has asked for zero tickets (no idea why they would do this be we should trust them).\r\n if (tickets === 0) {\r\n return [];\r\n }\r\n // Now that we know out tickets value is not zero we should check that it is a valid natural number.\r\n if (!(0, Utilities_1.isNaturalNumber)(tickets)) {\r\n throw new Error(\"tickets value must be a natural number\");\r\n }\r\n var result = [];\r\n // Keep drawing tickets until we either reach the number of required tickets or we simply run out of tickets to draw.\r\n // We can run out of tickets to draw if 'options.redrawable' is explicity 'false' or we just had no participants when 'drawMultiple' was called.\r\n while (result.length < tickets && this._participants.length > 0) {\r\n result.push(this.draw(options));\r\n }\r\n // If the 'unique' draw option is set then we need to remove duplicates from the result list.\r\n if (uniqueResults) {\r\n // Create an array to store our unique results.\r\n var unique = [];\r\n // Iterate over all of our participants (with potential duplicates) and populate our array of unique values.\r\n for (var _i = 0, result_1 = result; _i < result_1.length; _i++) {\r\n var participant = result_1[_i];\r\n if (unique.indexOf(participant) === -1) {\r\n unique.push(participant);\r\n }\r\n }\r\n result = unique;\r\n }\r\n return result;\r\n };\r\n return Lotto;\r\n}());\r\nexports.Lotto = Lotto;\r\n", "\"use strict\";\r\nObject.defineProperty(exports, \"__esModule\", { value: true });\r\nexports.createLotto = void 0;\r\nvar Lotto_1 = require(\"./Lotto\");\r\n/**\r\n * A function that creates and returns a Lotto instance.\r\n * @param participantsOrOptions An array of initial participants or options relating to the creation of a Lotto instance.\r\n * @returns A new Lotto instance.\r\n */\r\nfunction createLotto(participantsOrOptions) {\r\n // If no initial participants or lotto options were provided as an argument then we can just return a new lotto instance now.\r\n if (!participantsOrOptions) {\r\n return new Lotto_1.Lotto();\r\n }\r\n // Check whether we were provided with an array of initial participants or a lotto options object.\r\n if (Array.isArray(participantsOrOptions)) {\r\n // We are dealing with a pre-defined array of participants.\r\n var participants = participantsOrOptions;\r\n var lotto_1 = new Lotto_1.Lotto();\r\n // If the lotto participants have been defined upfront then we will need to add them all to our lotto instance now.\r\n participants.forEach(function (_a) {\r\n var participant = _a[0], tokens = _a[1];\r\n return lotto_1.add(participant, tokens);\r\n });\r\n // Return the Lotto instance.\r\n return lotto_1;\r\n }\r\n else {\r\n // We are dealing with some lotto options.\r\n var random = participantsOrOptions.random, participants = participantsOrOptions.participants;\r\n // Create a Lotto instance passing the custom RNG function to use in place of Math.random() (which could be undefined).\r\n var lotto_2 = new Lotto_1.Lotto(random);\r\n // If the lotto participants have been defined upfront as part of the options then we will need to add them all to our lotto instance now.\r\n if (participants) {\r\n participants.forEach(function (_a) {\r\n var participant = _a[0], tokens = _a[1];\r\n return lotto_2.add(participant, tokens);\r\n });\r\n }\r\n // Return the Lotto instance.\r\n return lotto_2;\r\n }\r\n}\r\nexports.createLotto = createLotto;\r\n", "\"use strict\";\r\nObject.defineProperty(exports, \"__esModule\", { value: true });\r\nvar createLotto_1 = require(\"./createLotto\");\r\nexports.default = createLotto_1.createLotto;\r\n", "import State from \"./State\";\nimport { validateDefinition } from \"./BehaviourTreeDefinitionValidator\";\nimport { convertMDSLToJSON } from \"./mdsl/MDSLDefinitionParser\";\nimport { BehaviourTree, FlattenedTreeNode } from \"./BehaviourTree\";\nimport { BehaviourTreeOptions } from \"./BehaviourTreeOptions\";\n\nexport { BehaviourTree, State, convertMDSLToJSON, validateDefinition };\nexport type { FlattenedTreeNode, BehaviourTreeOptions };\n", "/**\n * Enumeration of node state types.\n */\nexport enum State {\n READY = \"mistreevous.ready\",\n RUNNING = \"mistreevous.running\",\n SUCCEEDED = \"mistreevous.succeeded\",\n FAILED = \"mistreevous.failed\"\n}\n\nexport { State as default };\n\nexport type CompleteState = State.SUCCEEDED | State.FAILED;\nexport type AnyState = State.READY | State.RUNNING | CompleteState;\n", "import {\n NodeDefinition,\n RootNodeDefinition,\n DecoratorNodeDefinition,\n CompositeNodeDefinition,\n AnyNodeDefinition,\n BranchNodeDefinition\n} from \"./BehaviourTreeDefinition\";\n\n/**\n * A type guard function that returns true if the specified node satisfies the RootNodeDefinition type.\n * @param node The node.\n * @returns A value of true if the specified node satisfies the RootNodeDefinition type.\n */\nexport function isRootNode(node: NodeDefinition): node is RootNodeDefinition {\n return node.type === \"root\";\n}\n\n/**\n * A type guard function that returns true if the specified node satisfies the BranchNodeDefinition type.\n * @param node The node.\n * @returns A value of true if the specified node satisfies the BranchNodeDefinition type.\n */\nexport function isBranchNode(node: NodeDefinition): node is BranchNodeDefinition {\n return node.type === \"branch\";\n}\n\n/**\n * A type guard function that returns true if the specified node satisfies the NodeDefinition type.\n * @param node The node.\n * @returns A value of true if the specified node satisfies the NodeDefinition type.\n */\nexport function isLeafNode(node: NodeDefinition): node is NodeDefinition {\n return [\"branch\", \"action\", \"condition\", \"wait\"].includes(node.type);\n}\n\n/**\n * A type guard function that returns true if the specified node satisfies the DecoratorNodeDefinition type.\n * @param node The node.\n * @returns A value of true if the specified node satisfies the DecoratorNodeDefinition type.\n */\nexport function isDecoratorNode(node: NodeDefinition): node is DecoratorNodeDefinition {\n return [\"root\", \"repeat\", \"retry\", \"flip\", \"succeed\", \"fail\"].includes(node.type);\n}\n\n/**\n * A type guard function that returns true if the specified node satisfies the CompositeNodeDefinition type.\n * @param node The node.\n * @returns A value of true if the specified node satisfies the CompositeNodeDefinition type.\n */\nexport function isCompositeNode(node: NodeDefinition): node is CompositeNodeDefinition {\n return [\"sequence\", \"selector\", \"lotto\", \"parallel\"].includes(node.type);\n}\n\n/**\n * Flatten a node definition into an array of all of its nested node definitions.\n * @param nodeDefinition The node definition to flatten.\n * @returns An array of all of nested node definitions.\n */\nexport function flattenDefinition(nodeDefinition: AnyNodeDefinition): AnyNodeDefinition[] {\n const nodes: AnyNodeDefinition[] = [];\n\n const processNode = (currentNodeDefinition: AnyNodeDefinition) => {\n nodes.push(currentNodeDefinition);\n\n if (isCompositeNode(currentNodeDefinition)) {\n currentNodeDefinition.children.forEach(processNode);\n } else if (isDecoratorNode(currentNodeDefinition)) {\n processNode(currentNodeDefinition.child);\n }\n };\n\n processNode(nodeDefinition);\n\n return nodes;\n}\n\n/**\n * Determines whether the passed value is an integer.\n * @param value The value to check.\n * @returns Whether the passed value is an integer.\n */\nexport function isInteger(value: unknown): boolean {\n return typeof value === \"number\" && Math.floor(value) === value;\n}\n\n/**\n * Determines whether the passed value is null or undefined.\n * @param value The value to check.\n * @returns Whether the passed value is null or undefined.\n */\nexport function isNullOrUndefined(value: unknown): boolean {\n return typeof value === \"undefined\" || value === null;\n}\n", "/**\n * A type defining an object that holds a reference to substitued string literals parsed from the definition.\n */\nexport type StringLiteralPlaceholders = { [key: string]: string };\n\n/**\n * Pop the next raw token from the specified array of tokens and throw an error if it wasn't the expected one.\n * @param tokens The array of tokens.\n * @param expected An optional string or array or items, one of which must match the next popped token.\n * @returns The popped token.\n */\nexport function popAndCheck(tokens: string[], expected?: string | string[]): string {\n // Get and remove the next token.\n const popped = tokens.shift();\n\n // We were expecting another token but there aren't any.\n if (popped === undefined) {\n throw new Error(\"unexpected end of definition\");\n }\n\n // Do we have an expected token/tokens array?\n if (expected != undefined) {\n // Get an array of expected values, if the popped token matches any then we are all good.\n const expectedValues = typeof expected === \"string\" ? [expected] : expected;\n\n // Check whether the popped token matches at least one of our expected items.\n var tokenMatchesExpectation = expectedValues.some((item) => popped.toUpperCase() === item.toUpperCase());\n\n // Throw an error if the popped token didn't match any of our expected items.\n if (!tokenMatchesExpectation) {\n const expectationString = expectedValues.map((item) => \"'\" + item + \"'\").join(\" or \");\n throw new Error(\"unexpected token found. Expected \" + expectationString + \" but got '\" + popped + \"'\");\n }\n }\n\n // Return the popped token.\n return popped;\n}\n\n/**\n * Swaps out any node/attribute argument string literals with placeholders.\n * @param definition The definition.\n * @returns An object containing a mapping of placeholders to original string values as well as the processed definition string.\n */\nexport function substituteStringLiterals(definition: string): {\n placeholders: StringLiteralPlaceholders;\n processedDefinition: string;\n} {\n // Create an object to hold the mapping of placeholders to original string values.\n const placeholders: StringLiteralPlaceholders = {};\n\n // Replace any string literals wrapped with double quotes in our definition with placeholders to be processed later.\n const processedDefinition = definition.replace(/\\\"(\\\\.|[^\"\\\\])*\\\"/g, (match) => {\n var strippedMatch = match.substring(1, match.length - 1);\n var placeholder = Object.keys(placeholders).find((key) => placeholders[key] === strippedMatch);\n\n // If we have no existing string literal match then create a new placeholder.\n if (!placeholder) {\n placeholder = `@@${Object.keys(placeholders).length}@@`;\n placeholders[placeholder] = strippedMatch;\n }\n\n return placeholder;\n });\n\n return { placeholders, processedDefinition };\n}\n\n/**\n * Parse the tree definition into an array of raw tokens.\n * @param definition The definition.\n * @returns An array of tokens parsed from the definition.\n */\nexport function parseTokensFromDefinition(definition: string): string[] {\n // Add some space around various important characters so that they can be plucked out easier as individual tokens.\n definition = definition.replace(/\\(/g, \" ( \");\n definition = definition.replace(/\\)/g, \" ) \");\n definition = definition.replace(/\\{/g, \" { \");\n definition = definition.replace(/\\}/g, \" } \");\n definition = definition.replace(/\\]/g, \" ] \");\n definition = definition.replace(/\\[/g, \" [ \");\n definition = definition.replace(/\\,/g, \" , \");\n\n // Split the definition into raw token form and return it.\n return definition.replace(/\\s+/g, \" \").trim().split(\" \");\n}\n", "import { StringLiteralPlaceholders, popAndCheck } from \"./MDSLUtilities\";\n\n/**\n * A type representing any node function argument.\n */\ntype Argument = {\n /**\n * The argument value.\n */\n value: T;\n /**\n * The argument type, used for validation.\n */\n type: string;\n};\n\ntype NullArgument = Argument & {\n type: \"null\";\n};\n\ntype BooleanArgument = Argument & {\n type: \"boolean\";\n};\n\ntype NumberArgument = Argument & {\n type: \"number\";\n /**\n * A flag defining whether the number argument value is a valid integer. (used for validation)\n */\n isInteger: boolean;\n};\n\ntype StringPlaceholderArgument = Argument & {\n type: \"string\";\n};\n\ntype IdentifierArgument = Argument & {\n type: \"identifier\";\n};\n\n/**\n * A type representing a reference to any node function argument.\n */\ntype AnyArgument = NullArgument | BooleanArgument | NumberArgument | StringPlaceholderArgument | IdentifierArgument;\n\n/**\n * Parse an array of argument definitions from the specified tokens array.\n * @param tokens The array tokens to parse the argument definitions from.\n * @param stringArgumentPlaceholders The mapping of string literal node argument placeholders to original values.\n * @param argumentValidator The argument validator function.\n * @param validationFailedMessage The exception message to throw if argument validation fails.\n * @returns An array of argument definitions parsed from the specified tokens array.\n */\nexport function parseArgumentTokens(\n tokens: string[],\n stringArgumentPlaceholders: StringLiteralPlaceholders\n): AnyArgument[] {\n const argumentList: AnyArgument[] = [];\n\n // If the next token is not a '[' or '(' then we have no arguments to parse.\n if (![\"[\", \"(\"].includes(tokens[0])) {\n return argumentList;\n }\n\n // Any lists of arguments will always be wrapped in '[]' for node arguments or '()' for attribute arguments.\n // We are looking for a '[' or '(' opener that wraps the argument tokens and the relevant closer.\n const closingToken = popAndCheck(tokens, [\"[\", \"(\"]) === \"[\" ? \"]\" : \")\";\n\n const argumentListTokens: string[] = [];\n\n // Grab all tokens between the '[' and ']' or '(' and ')'.\n while (tokens.length && tokens[0] !== closingToken) {\n // The next token is part of our arguments list.\n argumentListTokens.push(tokens.shift()!);\n }\n\n // Validate the order of the argument tokens. Each token must either be a ',' or a single argument that satisfies the validator.\n argumentListTokens.forEach((token, index) => {\n // Get whether this token should be an actual argument.\n const shouldBeArgumentToken = !(index & 1);\n\n // If the current token should be an actual argument then validate it, otherwise it should be a ',' token.\n if (shouldBeArgumentToken) {\n // Get the argument definition.\n const argumentDefinition = getArgumentDefinition(token, stringArgumentPlaceholders);\n\n // This is a valid argument!\n argumentList.push(argumentDefinition);\n } else {\n // The current token should be a ',' token.\n if (token !== \",\") {\n throw new Error(`invalid argument list, expected ',' or ']' but got '${token}'`);\n }\n }\n });\n\n // The arguments list should terminate with a ']' or ')' token, depending on the opener.\n popAndCheck(tokens, closingToken);\n\n // Return the arguments.\n return argumentList;\n}\n\n/**\n * Gets an argument value definition.\n * @param token The argument token.\n * @param stringArgumentPlaceholders The mapping of string literal node argument placeholders to original values.\n * @returns An argument value definition.\n */\nfunction getArgumentDefinition(token: string, stringArgumentPlaceholders: StringLiteralPlaceholders): AnyArgument {\n // Check whether the token represents a null value.\n if (token === \"null\") {\n return {\n value: null,\n type: \"null\"\n } as NullArgument;\n }\n\n // Check whether the token represents a boolean value.\n if (token === \"true\" || token === \"false\") {\n return {\n value: token === \"true\",\n type: \"boolean\"\n } as BooleanArgument;\n }\n\n // Check whether the token represents a number value.\n // TODO: Relies on broken isNaN - see MDN.\n // if (!Number.isNaN(token)) {\n if (!isNaN(token as any)) {\n return {\n value: parseFloat(token),\n isInteger: parseFloat(token) === parseInt(token, 10),\n type: \"number\"\n } as NumberArgument;\n }\n\n // Check whether the token is a placeholder (e.g. @@0@@) representing a string literal.\n if (token.match(/^@@\\d+@@$/g)) {\n return {\n value: stringArgumentPlaceholders[token].replace('\\\\\"', '\"'),\n type: \"string\"\n } as StringPlaceholderArgument;\n }\n\n // The only remaining option is that the argument value is an identifier.\n return {\n value: token,\n type: \"identifier\"\n } as IdentifierArgument;\n}\n", "import { NodeAttributeDefinition } from \"../BehaviourTreeDefinition\";\nimport { parseArgumentTokens } from \"./MDSLNodeArgumentParser\";\nimport { StringLiteralPlaceholders } from \"./MDSLUtilities\";\n\n/**\n * A type defining the attribute definitions of a node.\n */\ntype NodeAttributes = {\n while?: NodeAttributeDefinition;\n until?: NodeAttributeDefinition;\n entry?: NodeAttributeDefinition;\n exit?: NodeAttributeDefinition;\n step?: NodeAttributeDefinition;\n};\n\n/**\n * Parse any node attribute definitions from the specified tokens array.\n * @param tokens The array of remaining tokens.\n * @param stringArgumentPlaceholders The mapping of string literal node argument placeholders to original values.\n * @returns An object of attribute definitions defined by any directly following tokens.\n */\nexport function parseAttributeTokens(\n tokens: string[],\n stringArgumentPlaceholders: StringLiteralPlaceholders\n): NodeAttributes {\n const nodeAttributeNames: (keyof NodeAttributes)[] = [\"while\", \"until\", \"entry\", \"exit\", \"step\"];\n\n // Create an object to hold any attributes found.\n const attributes: NodeAttributes = {};\n\n // Try to get the name of the attribute for the next token.\n let nextAttributeName = tokens[0]?.toLowerCase() as keyof NodeAttributes;\n\n // Pull attribute tokens as well as their arguments off of the tokens stack until we have no more.\n while (nodeAttributeNames.includes(nextAttributeName)) {\n // Check to make sure that we have not already created an attribute definition of this type.\n if (attributes[nextAttributeName]) {\n throw new Error(`duplicate attribute '${tokens[0].toUpperCase()}' found for node`);\n }\n\n // Remove the attribute name token from the array of tokens.\n tokens.shift();\n\n // Grab the attribute arguments, assuming the first to be an identifier.\n const [attributeCallIdentifier, ...attributeArguments] = parseArgumentTokens(\n tokens,\n stringArgumentPlaceholders\n );\n\n // The first attribute argument has to be an identifer, this will reference an agent function.\n if (attributeCallIdentifier?.type !== \"identifier\") {\n throw new Error(\"expected agent function or registered function name identifier argument for attribute\");\n }\n\n // Any attribute arguments (other than the expected call identifier) must have a type of string, number, boolean or null.\n attributeArguments\n .filter((arg) => arg.type === \"identifier\")\n .forEach((arg) => {\n throw new Error(\n `invalid attribute argument value '${arg.value}', must be string, number, boolean or null`\n );\n });\n\n // Create the attribute definition and add it to the object of attribute definitions found.\n attributes[nextAttributeName] = {\n call: attributeCallIdentifier.value,\n args: attributeArguments.map(({ value }) => value)\n };\n\n // Try to get the next attribute name token, as there could be multiple.\n nextAttributeName = tokens[0]?.toLowerCase() as keyof NodeAttributes;\n }\n\n return attributes;\n}\n", "import {\n ActionNodeDefinition,\n AnyChildNodeDefinition,\n AnyNodeDefinition,\n BranchNodeDefinition,\n ConditionNodeDefinition,\n FailNodeDefinition,\n FlipNodeDefinition,\n LottoNodeDefinition,\n ParallelNodeDefinition,\n RepeatNodeDefinition,\n RetryNodeDefinition,\n RootNodeDefinition,\n SelectorNodeDefinition,\n SequenceNodeDefinition,\n SucceedNodeDefinition,\n WaitNodeDefinition\n} from \"../BehaviourTreeDefinition\";\nimport {\n isCompositeNode,\n isDecoratorNode,\n isLeafNode,\n isNullOrUndefined,\n isRootNode\n} from \"../BehaviourTreeDefinitionUtilities\";\nimport { parseArgumentTokens } from \"./MDSLNodeArgumentParser\";\nimport { parseAttributeTokens } from \"./MDSLNodeAttributeParser\";\nimport {\n StringLiteralPlaceholders,\n parseTokensFromDefinition,\n popAndCheck,\n substituteStringLiterals\n} from \"./MDSLUtilities\";\n\n/**\n * Convert the MDSL tree definition string into an equivalent JSON definition.\n * @param definition The tree definition string as MDSL.\n * @returns The root node JSON definitions.\n */\nexport function convertMDSLToJSON(definition: string): RootNodeDefinition[] {\n // Swap out any node/attribute argument string literals with a placeholder and get a mapping of placeholders to original values as well as the processed definition.\n const { placeholders, processedDefinition } = substituteStringLiterals(definition);\n\n // Parse our definition definition string into an array of raw tokens.\n const tokens = parseTokensFromDefinition(processedDefinition);\n\n return convertTokensToJSONDefinition(tokens, placeholders);\n}\n\n/**\n * Converts the specified tree definition tokens into a JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The root node JSON definitions.\n */\nfunction convertTokensToJSONDefinition(\n tokens: string[],\n stringLiteralPlaceholders: StringLiteralPlaceholders\n): RootNodeDefinition[] {\n // There must be at least 3 tokens for the tree definition to be valid. 'ROOT', '{' and '}'.\n if (tokens.length < 3) {\n throw new Error(\"invalid token count\");\n }\n\n // We should have a matching number of '{' and '}' tokens. If not, then there are scopes that have not been properly closed.\n if (tokens.filter((token) => token === \"{\").length !== tokens.filter((token) => token === \"}\").length) {\n throw new Error(\"scope character mismatch\");\n }\n\n // Create an array of tree stack arrays where root nodes will always be at the botton and the current composite/decorator node at the top.\n // There should be an element in this array for every root node defined and every element should be an array with a root note as the first element.\n // E.g. A definition with two root nodes defined:\n // [\n // [root, lotto, sequence],\n // [root, selector]\n // ]\n const treeStacks: [Partial, ...Partial[]][] = [];\n\n // Create an array of all root node definitions that we create.\n const rootNodes: Partial[] = [];\n\n // A helper function used to push node definitions onto the tree stack.\n const pushNode = (node: AnyNodeDefinition) => {\n // If the node is a root node then we need to create a new tree stack array with the root node at the root.\n if (isRootNode(node)) {\n // We need to double-check that this root node is not the child of another node.\n // We can do this by checking whether the top tree stack is not empty (contains an existing node)\n if (treeStacks[treeStacks.length - 1]?.length) {\n throw new Error(\"a root node cannot be the child of another node\");\n }\n\n // Add the root node definition to our array of all parsed root node definitions.\n rootNodes.push(node);\n\n // Add the root node definition to the root of a new tree stack.\n treeStacks.push([node]);\n\n return;\n }\n\n // All non-root nodes should be pushed after their root nodes so handle cases\n // where we may not have any tree stacks or our top-most tree stack is empty.\n if (!treeStacks.length || !treeStacks[treeStacks.length - 1].length) {\n throw new Error(\"expected root node at base of definition\");\n }\n\n // Get the current tree stack that we are populating.\n const topTreeStack = treeStacks[treeStacks.length - 1];\n\n // Get the top-most node in the current tree stack, this will be a composite/decorator node\n // for which we will populate its children array if composite or setting its child if a decorator.\n const topTreeStackTopNode = topTreeStack[topTreeStack.length - 1] as AnyNodeDefinition;\n\n // If the top-most node in the current root stack is a composite or decorator\n // node then the current node should be added as a child of the top-most node.\n if (isCompositeNode(topTreeStackTopNode)) {\n topTreeStackTopNode.children = topTreeStackTopNode.children || [];\n topTreeStackTopNode.children.push(node);\n } else if (isDecoratorNode(topTreeStackTopNode)) {\n // If the top node already has a child node set then throw an error as a decorator should only have a single child.\n if (topTreeStackTopNode.child) {\n throw new Error(\"a decorator node must only have a single child node\");\n }\n\n topTreeStackTopNode.child = node;\n }\n\n // If the node we are adding is also a composite or decorator node, then we should push it\n // onto the current tree stack, as subsequent nodes will be added as its child/children.\n if (!isLeafNode(node)) {\n topTreeStack.push(node);\n }\n };\n\n // A helper function used to pop the top-most node definition off of the tree stack and return it.\n const popNode = (): AnyNodeDefinition | null => {\n let poppedNode: AnyNodeDefinition | null = null;\n\n // Get the current tree stack that we are populating.\n const topTreeStack = treeStacks[treeStacks.length - 1];\n\n // Pop the top-most node in the current tree stack if there is one.\n if (topTreeStack.length) {\n poppedNode = topTreeStack.pop() as AnyNodeDefinition;\n }\n\n // We don't want any empty tree stacks in our stack of tree stacks.\n if (!topTreeStack.length) {\n treeStacks.pop();\n }\n\n return poppedNode;\n };\n\n // We should keep processing the raw tokens until we run out of them.\n while (tokens.length) {\n // Grab the next token.\n const token = tokens.shift()!;\n\n // How we create the next node depends on the current raw token value.\n switch (token.toUpperCase()) {\n case \"ROOT\": {\n pushNode(createRootNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"SUCCEED\": {\n pushNode(createSucceedNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"FAIL\": {\n pushNode(createFailNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"FLIP\": {\n pushNode(createFlipNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"REPEAT\": {\n pushNode(createRepeatNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"RETRY\": {\n pushNode(createRetryNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"SEQUENCE\": {\n pushNode(createSequenceNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"SELECTOR\": {\n pushNode(createSelectorNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"PARALLEL\": {\n pushNode(createParallelNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"LOTTO\": {\n pushNode(createLottoNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"ACTION\": {\n pushNode(createActionNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"CONDITION\": {\n pushNode(createConditionNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"WAIT\": {\n pushNode(createWaitNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"BRANCH\": {\n pushNode(createBranchNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"}\": {\n // The '}' character closes the current scope and means that we have to pop a node off of the current stack.\n const poppedNode = popNode();\n\n // Now that we have a node definition we can carry out any validation that may require the node to be fully populated.\n if (poppedNode) {\n validatePoppedNode(poppedNode);\n }\n\n break;\n }\n\n default: {\n throw new Error(`unexpected token: ${token}`);\n }\n }\n }\n\n return rootNodes as RootNodeDefinition[];\n}\n\n/**\n * Creates a root node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The root node JSON definition.\n */\nfunction createRootNode(tokens: string[], stringLiteralPlaceholders: StringLiteralPlaceholders): RootNodeDefinition {\n // Create the root node definition.\n let node = {\n type: \"root\"\n } as Partial;\n\n // Parse any node arguments, we should only have one if any which will be an identifier argument for the root identifier.\n const nodeArguments = parseArgumentTokens(tokens, stringLiteralPlaceholders);\n\n // Check whether any node arguments were defined.\n if (nodeArguments.length) {\n // We should only have one argument, if any, which will be an identifier argument for the root identifier.\n if (nodeArguments.length === 1 && nodeArguments[0].type === \"identifier\") {\n // The root node identifier will be the first and only node argument value.\n node.id = nodeArguments[0].value as string;\n } else {\n throw new Error(\"expected single root name argument\");\n }\n }\n\n // Grab any node attribute definitions and spread them into the node definition.\n node = { ...node, ...parseAttributeTokens(tokens, stringLiteralPlaceholders) };\n\n // This is a decorator node, so we expect an opening '{'.\n popAndCheck(tokens, \"{\");\n\n // Return the root node definition.\n return node as RootNodeDefinition;\n}\n\n/**\n * Creates a succeed node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The succeed node JSON definition.\n */\nfunction createSucceedNode(\n tokens: string[],\n stringLiteralPlaceholders: StringLiteralPlaceholders\n): SucceedNodeDefinition {\n const node = {\n type: \"succeed\",\n ...parseAttributeTokens(tokens, stringLiteralPlaceholders)\n } as SucceedNodeDefinition;\n\n // This is a decorator node, so we expect an opening '{'.\n popAndCheck(tokens, \"{\");\n\n // Return the succeed node definition.\n return node;\n}\n\n/**\n * Creates a fail node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The fail node JSON definition.\n */\nfunction createFailNode(tokens: string[], stringLiteralPlaceholders: StringLiteralPlaceholders): FailNodeDefinition {\n const node = {\n type: \"fail\",\n ...parseAttributeTokens(tokens, stringLiteralPlaceholders)\n } as FailNodeDefinition;\n\n // This is a decorator node, so we expect an opening '{'.\n popAndCheck(tokens, \"{\");\n\n // Return the fail node definition.\n return node;\n}\n\n/**\n * Creates a flip node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The flip node JSON definition.\n */\nfunction createFlipNode(tokens: string[], stringLiteralPlaceholders: StringLiteralPlaceholders): FlipNodeDefinition {\n const node = {\n type: \"flip\",\n ...parseAttributeTokens(tokens, stringLiteralPlaceholders)\n } as FlipNodeDefinition;\n\n // This is a decorator node, so we expect an opening '{'.\n popAndCheck(tokens, \"{\");\n\n // Return the flip node definition.\n return node;\n}\n\n/**\n * Creates a repeat node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The repeat node JSON definition.\n */\nfunction createRepeatNode(\n tokens: string[],\n stringLiteralPlaceholders: StringLiteralPlaceholders\n): RepeatNodeDefinition {\n let node = { type: \"repeat\" } as RepeatNodeDefinition;\n\n // Get the node arguments.\n const nodeArguments = parseArgumentTokens(tokens, stringLiteralPlaceholders);\n\n // The arguments of a repeat node are optional. We may have:\n // - No node arguments, in which case the repeat note will iterate indefinitely.\n // - One node argument which will be the explicit number of iterations to make.\n // - Two node arguments which define the min and max iteration bounds from which a random iteration count will be picked.\n if (nodeArguments.length) {\n // All repeat node arguments MUST be of type number and must be integer.\n nodeArguments\n .filter((arg) => arg.type !== \"number\" || !arg.isInteger)\n .forEach(() => {\n throw new Error(`repeat node iteration counts must be integer values`);\n });\n\n // We should have got one or two iteration counts.\n if (nodeArguments.length === 1) {\n // A static iteration count was defined.\n node.iterations = nodeArguments[0].value as number;\n\n // A repeat node must have a positive number of iterations if defined.\n if (node.iterations < 0) {\n throw new Error(\"a repeat node must have a positive number of iterations if defined\");\n }\n } else if (nodeArguments.length === 2) {\n // A minimum and maximum iteration count was defined.\n node.iterations = [nodeArguments[0].value as number, nodeArguments[1].value as number];\n\n // A repeat node must have a positive min and max iteration count if they are defined.\n if (node.iterations[0] < 0 || node.iterations[1] < 0) {\n throw new Error(\"a repeat node must have a positive minimum and maximum iteration count if defined\");\n }\n\n // A repeat node must not have an minimum iteration count that exceeds the maximum iteration count.\n if (node.iterations[0] > node.iterations[1]) {\n throw new Error(\n \"a repeat node must not have a minimum iteration count that exceeds the maximum iteration count\"\n );\n }\n } else {\n // An incorrect number of iteration counts was defined.\n throw new Error(\"invalid number of repeat node iteration count arguments defined\");\n }\n }\n\n // Grab any node attribute definitions and spread them into the node definition.\n node = { ...node, ...parseAttributeTokens(tokens, stringLiteralPlaceholders) };\n\n // This is a decorator node, so we expect an opening '{'.\n popAndCheck(tokens, \"{\");\n\n // Return the repeat node definition.\n return node;\n}\n\n/**\n * Creates a retry node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The retry node JSON definition.\n */\nfunction createRetryNode(tokens: string[], stringLiteralPlaceholders: StringLiteralPlaceholders): RetryNodeDefinition {\n let node = { type: \"retry\" } as RetryNodeDefinition;\n\n // Get the node arguments.\n const nodeArguments = parseArgumentTokens(tokens, stringLiteralPlaceholders);\n\n // The arguments of a retry node are optional. We may have:\n // - No node arguments, in which case the retry note will attempt indefinitely.\n // - One node argument which will be the explicit number of attempts to make.\n // - Two node arguments which define the min and max attempt bounds from which a random attempt count will be picked.\n if (nodeArguments.length) {\n // All retry node arguments MUST be of type number and must be integer.\n nodeArguments\n .filter((arg) => arg.type !== \"number\" || !arg.isInteger)\n .forEach(() => {\n throw new Error(`retry node attempt counts must be integer values`);\n });\n\n // We should have got one or two attempt counts.\n if (nodeArguments.length === 1) {\n // A static attempt count was defined.\n node.attempts = nodeArguments[0].value as number;\n\n // A retry node must have a positive number of attempts if defined.\n if (node.attempts < 0) {\n throw new Error(\"a retry node must have a positive number of attempts if defined\");\n }\n } else if (nodeArguments.length === 2) {\n // A minimum and maximum attempt count was defined.\n node.attempts = [nodeArguments[0].value as number, nodeArguments[1].value as number];\n\n // A retry node must have a positive min and max attempts count if they are defined.\n if (node.attempts[0] < 0 || node.attempts[1] < 0) {\n throw new Error(\"a retry node must have a positive minimum and maximum attempt count if defined\");\n }\n\n // A retry node must not have a minimum attempt count that exceeds the maximum attempt count.\n if (node.attempts[0] > node.attempts[1]) {\n throw new Error(\n \"a retry node must not have a minimum attempt count that exceeds the maximum attempt count\"\n );\n }\n } else {\n // An incorrect number of attempt counts was defined.\n throw new Error(\"invalid number of retry node attempt count arguments defined\");\n }\n }\n\n // Grab any node attribute definitions and spread them into the node definition.\n node = { ...node, ...parseAttributeTokens(tokens, stringLiteralPlaceholders) };\n\n // This is a decorator node, so we expect an opening '{'.\n popAndCheck(tokens, \"{\");\n\n // Return the retry node definition.\n return node;\n}\n\n/**\n * Creates a sequence node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The sequence node JSON definition.\n */\nfunction createSequenceNode(\n tokens: string[],\n stringLiteralPlaceholders: StringLiteralPlaceholders\n): SequenceNodeDefinition {\n const node = {\n type: \"sequence\",\n ...parseAttributeTokens(tokens, stringLiteralPlaceholders)\n } as SequenceNodeDefinition;\n\n // This is a composite node, so we expect an opening '{'.\n popAndCheck(tokens, \"{\");\n\n // Return the sequence node definition.\n return node;\n}\n\n/**\n * Creates a selector node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The selector node JSON definition.\n */\nfunction createSelectorNode(\n tokens: string[],\n stringLiteralPlaceholders: StringLiteralPlaceholders\n): SelectorNodeDefinition {\n const node = {\n type: \"selector\",\n ...parseAttributeTokens(tokens, stringLiteralPlaceholders)\n } as SelectorNodeDefinition;\n\n // This is a composite node, so we expect an opening '{'.\n popAndCheck(tokens, \"{\");\n\n // Return the selector node definition.\n return node;\n}\n\n/**\n * Creates a parallel node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The parallel node JSON definition.\n */\nfunction createParallelNode(\n tokens: string[],\n stringLiteralPlaceholders: StringLiteralPlaceholders\n): ParallelNodeDefinition {\n const node = {\n type: \"parallel\",\n ...parseAttributeTokens(tokens, stringLiteralPlaceholders)\n } as ParallelNodeDefinition;\n\n // This is a composite node, so we expect an opening '{'.\n popAndCheck(tokens, \"{\");\n\n // Return the parallel node definition.\n return node;\n}\n\n/**\n * Creates a lotto node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The lotto node JSON definition.\n */\nfunction createLottoNode(tokens: string[], stringLiteralPlaceholders: StringLiteralPlaceholders): LottoNodeDefinition {\n // If any node arguments have been defined then they must be our weights.\n const nodeArguments = parseArgumentTokens(tokens, stringLiteralPlaceholders);\n\n // All lotto node arguments MUST be of type number and must be positive integers.\n nodeArguments\n .filter((arg) => arg.type !== \"number\" || !arg.isInteger || arg.value < 0)\n .forEach(() => {\n throw new Error(`lotto node weight arguments must be positive integer values`);\n });\n\n const node = {\n type: \"lotto\",\n ...parseAttributeTokens(tokens, stringLiteralPlaceholders)\n } as LottoNodeDefinition;\n\n // Apply the weights if any were defined.\n if (nodeArguments.length) {\n node.weights = nodeArguments.map(({ value }) => value) as number[];\n }\n\n // This is a composite node, so we expect an opening '{'.\n popAndCheck(tokens, \"{\");\n\n // Return the lotto node definition.\n return node;\n}\n\n/**\n * Creates an action node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The action node JSON definition.\n */\nfunction createActionNode(\n tokens: string[],\n stringLiteralPlaceholders: StringLiteralPlaceholders\n): ActionNodeDefinition {\n // Parse any node arguments, we should have at least one which will be an identifier argument for the action name\n // and agent function to invoke for the action, all other arguments are to be passed as arguments to that function.\n const [actionNameIdentifier, ...agentFunctionArgs] = parseArgumentTokens(tokens, stringLiteralPlaceholders);\n\n // Our first argument MUST be defined and be an identifier as we require an action name argument.\n if (actionNameIdentifier?.type !== \"identifier\") {\n throw new Error(\"expected action name identifier argument\");\n }\n\n // Only the first argument should have been an identifier, all agent function arguments must be string, number, boolean or null.\n agentFunctionArgs\n .filter((arg) => arg.type === \"identifier\")\n .forEach((arg) => {\n throw new Error(\n `invalid action node argument value '${arg.value}', must be string, number, boolean or null`\n );\n });\n\n // Return the action node definition.\n return {\n type: \"action\",\n call: actionNameIdentifier.value,\n args: agentFunctionArgs.map(({ value }) => value),\n ...parseAttributeTokens(tokens, stringLiteralPlaceholders)\n };\n}\n\n/**\n * Creates a condition node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The condition node JSON definition.\n */\nfunction createConditionNode(\n tokens: string[],\n stringLiteralPlaceholders: StringLiteralPlaceholders\n): ConditionNodeDefinition {\n // Parse any node arguments, we should have at least one which will be an identifier argument for the condition name\n // and agent function to invoke for the condition, all other arguments are to be passed as arguments to that function.\n const [conditionNameIdentifier, ...agentFunctionArgs] = parseArgumentTokens(tokens, stringLiteralPlaceholders);\n\n // Our first argument MUST be defined and be an identifier as we require a condition name argument.\n if (conditionNameIdentifier?.type !== \"identifier\") {\n throw new Error(\"expected condition name identifier argument\");\n }\n\n // Only the first argument should have been an identifier, all agent function arguments must be string, number, boolean or null.\n agentFunctionArgs\n .filter((arg) => arg.type === \"identifier\")\n .forEach((arg) => {\n throw new Error(\n `invalid condition node argument value '${arg.value}', must be string, number, boolean or null`\n );\n });\n\n // Return the condition node definition.\n return {\n type: \"condition\",\n call: conditionNameIdentifier.value,\n args: agentFunctionArgs.map(({ value }) => value),\n ...parseAttributeTokens(tokens, stringLiteralPlaceholders)\n };\n}\n\n/**\n * Creates a wait node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The wait node JSON definition.\n */\nfunction createWaitNode(tokens: string[], stringLiteralPlaceholders: StringLiteralPlaceholders): WaitNodeDefinition {\n let node = { type: \"wait\" } as WaitNodeDefinition;\n\n // Get the node arguments.\n const nodeArguments = parseArgumentTokens(tokens, stringLiteralPlaceholders);\n\n // The arguments of a wait node are optional. We may have:\n // - No node arguments, in which case the wait will be indefinite until it is aborted.\n // - One node argument which will be the explicit duration of the wait.\n // - Two node arguments which define the min and max duration bounds from which a random duration will be picked.\n if (nodeArguments.length) {\n // All wait node arguments MUST be of type number and must be integer.\n nodeArguments\n .filter((arg) => arg.type !== \"number\" || !arg.isInteger)\n .forEach(() => {\n throw new Error(`wait node durations must be integer values`);\n });\n\n // We may have:\n // - One node argument which will be the explicit duration of the wait.\n // - Two node arguments which define the min and max duration bounds from which a random duration will be picked.\n // - Too many arguments, which is not valid.\n if (nodeArguments.length === 1) {\n // An explicit duration was defined.\n node.duration = nodeArguments[0].value as number;\n\n // If an explict duration was defined then it must be a positive number.\n if (node.duration < 0) {\n throw new Error(\"a wait node must have a positive duration\");\n }\n } else if (nodeArguments.length === 2) {\n // Min and max duration bounds were defined from which a random duration will be picked.\n node.duration = [nodeArguments[0].value as number, nodeArguments[1].value as number];\n\n // A wait node must have a positive min and max duration.\n if (node.duration[0] < 0 || node.duration[1] < 0) {\n throw new Error(\"a wait node must have a positive minimum and maximum duration\");\n }\n\n // A wait node must not have a minimum duration that exceeds the maximum duration.\n if (node.duration[0] > node.duration[1]) {\n throw new Error(\"a wait node must not have a minimum duration that exceeds the maximum duration\");\n }\n } else if (nodeArguments.length > 2) {\n // An incorrect number of duration arguments were defined.\n throw new Error(\"invalid number of wait node duration arguments defined\");\n }\n }\n\n // Return the wait node definition.\n return { ...node, ...parseAttributeTokens(tokens, stringLiteralPlaceholders) };\n}\n\n/**\n * Creates a branch node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The branch node JSON definition.\n */\nfunction createBranchNode(\n tokens: string[],\n stringLiteralPlaceholders: StringLiteralPlaceholders\n): BranchNodeDefinition {\n // Parse any node arguments, we should have one which will be an identifier argument for the root ref.\n const nodeArguments = parseArgumentTokens(tokens, stringLiteralPlaceholders);\n\n // We should have only a single identifer argument for a branch node, which is the root ref.\n if (nodeArguments.length !== 1 || nodeArguments[0].type !== \"identifier\") {\n throw new Error(\"expected single branch name argument\");\n }\n\n // Return the branch node definition.\n return { type: \"branch\", ref: nodeArguments[0].value };\n}\n\n/**\n * Validate a fully-populated node definition that was popped off of the tree stack.\n * @param definition The popped node to validate.\n */\nfunction validatePoppedNode(definition: AnyNodeDefinition): void {\n // Decorators MUST have a child defined.\n if (isDecoratorNode(definition) && isNullOrUndefined(definition.child)) {\n throw new Error(`a ${definition.type} node must have a single child node defined`);\n }\n\n // Composites MUST have at least one child defined.\n if (isCompositeNode(definition) && !definition.children?.length) {\n throw new Error(`a ${definition.type} node must have at least a single child node defined`);\n }\n\n // We need to make sure that lotto nodes that have weights defined have a number of weights matching the number of child nodes.\n if (definition.type === \"lotto\") {\n // Check whether a 'weights' property has been defined, if it has we expect it to be an array of weights.\n if (typeof definition.weights !== \"undefined\") {\n // Check that the weights property is an array of positive integers with an element for each child node element.\n if (definition.weights.length !== definition.children.length) {\n throw new Error(\n \"expected a number of weight arguments matching the number of child nodes for lotto node\"\n );\n }\n }\n }\n}\n", "import { RootNodeDefinition } from \"./BehaviourTreeDefinition\";\nimport { flattenDefinition, isBranchNode, isInteger } from \"./BehaviourTreeDefinitionUtilities\";\nimport { convertMDSLToJSON } from \"./mdsl/MDSLDefinitionParser\";\n\n/**\n * An object representing the result of validating a tree definition.\n */\nexport type DefinitionValidationResult = {\n /**\n * A flag defining whether validation succeeded.\n */\n succeeded: boolean;\n /**\n * A string containing the error message if validation did not succeed.\n */\n errorMessage?: string;\n /**\n * The definition as json if the validation was successful, or undefined if validation did not succeed.\n */\n json?: RootNodeDefinition[];\n};\n\n/**\n * Validates the specified behaviour tree definition in the form of JSON or MDSL, not taking any globally registered subtrees into consideration.\n * @param definition The behaviour tree definition in the form of JSON or MDSL.\n * @returns An object representing the result of validating the given tree definition.\n */\nexport function validateDefinition(definition: any): DefinitionValidationResult {\n // The definition must be defined.\n if (definition === null || typeof definition === \"undefined\") {\n return createValidationFailureResult(\"definition is null or undefined\");\n }\n\n // We are expecting a definition in one of three different forms:\n // - A string which we will assume is MDSL and we will parse this to JSON before validation.\n // - An array which we will assume is an array of root node definitions with at least one being the primary root node (no 'id' property)\n // - An object which we will assume is the primary root node and should not have an 'id' property.\n if (typeof definition === \"string\") {\n // The definition is a string which we can assume is MDSL, so attempt to validate it.\n return validateMDSLDefinition(definition);\n } else if (typeof definition === \"object\") {\n // The definition will either be an array (of root node definitions) or an object (the single primary root node definition).\n return validateJSONDefinition(definition);\n } else {\n return createValidationFailureResult(`unexpected definition type of '${typeof definition}'`);\n }\n}\n\n/**\n * Validates the specified behaviour tree definition in the form of MDSL.\n * @param definition The behaviour tree definition in the form of MDSL.\n * @returns An object representing the result of validating the given tree definition.\n */\nfunction validateMDSLDefinition(definition: string): DefinitionValidationResult {\n let rootNodeDefinitions;\n\n // The first thing the we need to do is to attempt to convert our MDSL into JSON.\n try {\n // The definition is a string which we can assume is MDSL, so attempt to parse it to a JSON definition in the form of an array of root node definitions.\n rootNodeDefinitions = convertMDSLToJSON(definition);\n } catch (exception) {\n // We failed to parse the JSON from the MDSL, this is likely to be the result of it not being a valid MDSL string.\n return createValidationFailureResult((exception as Error).message);\n }\n\n // Unpack all of the root node definitions into arrays of main ('id' defined) and sub ('id' not defined) root node definitions.\n const mainRootNodeDefinitions = rootNodeDefinitions.filter(({ id }) => typeof id === \"undefined\");\n const subRootNodeDefinitions = rootNodeDefinitions.filter(({ id }) => typeof id === \"string\" && id.length > 0);\n\n // We should ALWAYS have exactly one root node definition without an 'id' property defined, which is out main root node definition.\n if (mainRootNodeDefinitions.length !== 1) {\n return createValidationFailureResult(\n \"expected single unnamed root node at base of definition to act as main root\"\n );\n }\n\n // We should never have duplicate 'id' properties across our sub root node definitions.\n const subRootNodeIdenitifers: string[] = [];\n for (const { id } of subRootNodeDefinitions) {\n // Have we already come across this 'id' property value?\n if (subRootNodeIdenitifers.includes(id!)) {\n return createValidationFailureResult(`multiple root nodes found with duplicate name '${id}'`);\n }\n\n subRootNodeIdenitifers.push(id!);\n }\n\n try {\n // Validate our branch -> subtree links and check for any circular dependencies, we don't care about checking for broken subtree links here.\n validateBranchSubtreeLinks(rootNodeDefinitions, false);\n } catch (exception) {\n return createValidationFailureResult((exception as Error).message);\n }\n\n // Our definition was valid!\n return {\n succeeded: true,\n json: rootNodeDefinitions\n };\n}\n\n/**\n * Validates the specified behaviour tree definition in the form of JSON.\n * @param definition The behaviour tree definition in the form of JSON.\n * @returns An object representing the result of validating the given tree definition.\n */\nexport function validateJSONDefinition(\n definition: RootNodeDefinition | RootNodeDefinition[]\n): DefinitionValidationResult {\n // The definition will either be an array (of root node definitions) or an object (the single primary root node definition).\n const rootNodeDefinitions = Array.isArray(definition) ? definition : [definition];\n\n // Iterate over our array of root nodes and call validateNode for each, passing an initial depth of 0, wrapped in a try catch to handle validation failures.\n try {\n rootNodeDefinitions.forEach((rootNodeDefinition) => validateNode(rootNodeDefinition, 0));\n } catch (error) {\n // Handle cases where we have caught a thrown Error and return a failure result with the error message.\n if (error instanceof Error) {\n return createValidationFailureResult(error.message);\n }\n\n // No idea what happened here!\n return createValidationFailureResult(`unexpected error: ${error}`);\n }\n\n // Unpack all of the root node definitions into arrays of main ('id' defined) and sub ('id' not defined) root node definitions.\n const mainRootNodeDefinitions = rootNodeDefinitions.filter(({ id }) => typeof id === \"undefined\");\n const subRootNodeDefinitions = rootNodeDefinitions.filter(({ id }) => typeof id === \"string\" && id.length > 0);\n\n // We should ALWAYS have exactly one root node definition without an 'id' property defined, which is out main root node definition.\n if (mainRootNodeDefinitions.length !== 1) {\n return createValidationFailureResult(\n \"expected single root node without 'id' property defined to act as main root\"\n );\n }\n\n // We should never have duplicate 'id' properties across our sub root node definitions.\n const subRootNodeIdenitifers: string[] = [];\n for (const { id } of subRootNodeDefinitions) {\n // Have we already come across this 'id' property value?\n if (subRootNodeIdenitifers.includes(id!)) {\n return createValidationFailureResult(\n `multiple root nodes found with duplicate 'id' property value of '${id}'`\n );\n }\n\n subRootNodeIdenitifers.push(id!);\n }\n\n try {\n // Validate our branch -> subtree links and check for any circular dependencies, we don't care about checking for broken subtree links here.\n validateBranchSubtreeLinks(rootNodeDefinitions, false);\n } catch (exception) {\n return createValidationFailureResult((exception as Error).message);\n }\n\n // Our definition was valid!\n return {\n succeeded: true,\n json: rootNodeDefinitions\n };\n}\n\n/**\n * Validates the branch -> subtree links across all provided root node definitions.\n * This will not consider branch nodes that reference any globally registered subtrees unless includesGlobalSubtrees\n * is set to true, in which case we will also verify that there are no broken branch -> subtree links.\n * @param rootNodeDefinitions The array of root node definitions.\n * @param includesGlobalSubtrees A flag defining whether the array includes all global subtree root node definitions.\n */\nexport function validateBranchSubtreeLinks(rootNodeDefinitions: RootNodeDefinition[], includesGlobalSubtrees: boolean) {\n // Create a mapping of root node identifiers to other root nodes that they reference via branch nodes.\n // Below is an example of a mapping that includes a circular dependency (root => a => b => c => a)\n // [{ refs: [\"a\", \"b\"] }, { id: \"a\", refs: [\"b\"] }, { id: \"b\", refs: [\"c\"] }, { id: \"c\", refs: [\"a\"] }]\n const rootNodeMappings: { id: string | undefined; refs: string[] }[] = rootNodeDefinitions.map(\n (rootNodeDefinition) => ({\n id: rootNodeDefinition.id,\n refs: flattenDefinition(rootNodeDefinition)\n .filter(isBranchNode)\n .map(({ ref }) => ref)\n })\n );\n\n // A recursive function to walk through the mappings, keeping track of which root nodes we have visited in the form of a path of root node identifiers.\n const followRefs = (mapping: { id: string | undefined; refs: string[] }, path: (string | undefined)[] = []) => {\n // Have we found a circular dependency?\n if (path.includes(mapping.id)) {\n // We found a circular dependency! Get the bad path of root node identifiers.\n const badPath = [...path, mapping.id];\n\n // Create the formatted path value. [undefined, \"a\", \"b\", \"c\", \"a\"] would be formatted as \"a -> b -> c -> a\".\n const badPathFormatted = badPath.filter((element) => !!element).join(\" => \");\n\n // No need to continue, we found a circular dependency.\n throw new Error(`circular dependency found in branch node references: ${badPathFormatted}`);\n }\n\n for (const ref of mapping.refs) {\n // Find the mapping for the root node with an identifer matching the current ref.\n const subMapping = rootNodeMappings.find(({ id }) => id === ref);\n\n // We may not have a mapping for this ref, which is normal when we aren't considering all globally registered subtrees.\n if (subMapping) {\n followRefs(subMapping, [...path, mapping.id]);\n } else if (includesGlobalSubtrees) {\n // We found a reference to a root node that doesn't exist, which is a problem seeing as the root node definitons includes all globally registered subtrees.\n throw new Error(\n mapping.id\n ? `subtree '${mapping.id}' has branch node that references root node '${ref}' which has not been defined`\n : `primary tree has branch node that references root node '${ref}' which has not been defined`\n );\n }\n }\n };\n\n // Start looking for circular dependencies and broken references from the primary root node definition.\n followRefs(rootNodeMappings.find((mapping) => typeof mapping.id === \"undefined\")!);\n}\n\n/**\n * Validate an object that we expect to be a node definition.\n * @param definition An object that we expect to be a node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateNode(definition: any, depth: number): void {\n // Every node must be valid object and have a non-empty 'type' string property.\n if (typeof definition !== \"object\" || typeof definition.type !== \"string\" || definition.type.length === 0) {\n throw new Error(\n `node definition is not an object or 'type' property is not a non-empty string at depth '${depth}'`\n );\n }\n\n // How we validate this node definition will depend on its type.\n switch (definition.type) {\n case \"action\":\n validateActionNode(definition, depth);\n break;\n\n case \"condition\":\n validateConditionNode(definition, depth);\n break;\n\n case \"wait\":\n validateWaitNode(definition, depth);\n break;\n\n case \"branch\":\n validateBranchNode(definition, depth);\n break;\n\n case \"root\":\n validateRootNode(definition, depth);\n break;\n\n case \"succeed\":\n validateSucceedNode(definition, depth);\n break;\n\n case \"fail\":\n validateFailNode(definition, depth);\n break;\n\n case \"flip\":\n validateFlipNode(definition, depth);\n break;\n\n case \"repeat\":\n validateRepeatNode(definition, depth);\n break;\n\n case \"retry\":\n validateRetryNode(definition, depth);\n break;\n\n case \"sequence\":\n validateSequenceNode(definition, depth);\n break;\n\n case \"selector\":\n validateSelectorNode(definition, depth);\n break;\n\n case \"parallel\":\n validateParallelNode(definition, depth);\n break;\n\n case \"lotto\":\n validateLottoNode(definition, depth);\n break;\n\n default:\n throw new Error(`unexpected node type of '${definition.type}' at depth '${depth}'`);\n }\n}\n\n/**\n * Validate any attributes for a given node definition.\n * @param definition The node definition.\n * @param depth The depth of the node in the behaviour tree definition.\n */\nfunction validateNodeAttributes(definition: any, depth: number): void {\n // Validate each of the attribute types for this node.\n [\"while\", \"until\", \"entry\", \"exit\", \"step\"].forEach((attributeName) => {\n // Attempt to grab the definition for the current attribute from the node definition.\n const attributeDefinition = definition[attributeName];\n\n // All node attributes are optional, so there is nothing to do if the current attribute is not defined.\n if (typeof attributeDefinition === \"undefined\") {\n return;\n }\n\n // The attribute definition must be an object.\n if (typeof attributeDefinition !== \"object\") {\n throw new Error(\n `expected attribute '${attributeName}' to be an object for '${definition.type}' node at depth '${depth}'`\n );\n }\n\n // The 'call' property must be defined for any attribute definition.\n if (typeof attributeDefinition.call !== \"string\" || attributeDefinition.call.length === 0) {\n throw new Error(\n `expected 'call' property for attribute '${attributeName}' to be a non-empty string for '${definition.type}' node at depth '${depth}'`\n );\n }\n\n // If any node attribute arguments have been defined then they must have been defined in an array.\n if (typeof attributeDefinition.args !== \"undefined\" && !Array.isArray(attributeDefinition.args)) {\n throw new Error(\n `expected 'args' property for attribute '${attributeName}' to be an array for '${definition.type}' node at depth '${depth}'`\n );\n }\n });\n}\n\n/**\n * Validate an object that we expect to be a root node definition.\n * @param definition An object that we expect to be a root node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateRootNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"root\") {\n throw new Error(\"expected node type of 'root' for root node\");\n }\n\n // A root node cannot be the child of another node.\n if (depth > 0) {\n throw new Error(\"a root node cannot be the child of another node\");\n }\n\n // Check that, if the root node 'id' property is defined, it is a non-empty string.\n if (typeof definition.id !== \"undefined\" && (typeof definition.id !== \"string\" || definition.id.length === 0)) {\n throw new Error(\"expected non-empty string for 'id' property if defined for root node\");\n }\n\n // A root node is a decorator node, so must have a child node defined.\n if (typeof definition.child === \"undefined\") {\n throw new Error(\"expected property 'child' to be defined for root node\");\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n\n // Validate the child node of this decorator node.\n validateNode(definition.child, depth + 1);\n}\n\n/**\n * Validate an object that we expect to be a succeed node definition.\n * @param definition An object that we expect to be a succeed node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateSucceedNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"succeed\") {\n throw new Error(`expected node type of 'succeed' for succeed node at depth '${depth}'`);\n }\n\n // A succeed node is a decorator node, so must have a child node defined.\n if (typeof definition.child === \"undefined\") {\n throw new Error(`expected property 'child' to be defined for succeed node at depth '${depth}'`);\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n\n // Validate the child node of this decorator node.\n validateNode(definition.child, depth + 1);\n}\n\n/**\n * Validate an object that we expect to be a fail node definition.\n * @param definition An object that we expect to be a fail node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateFailNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"fail\") {\n throw new Error(`expected node type of 'fail' for fail node at depth '${depth}'`);\n }\n\n // A fail node is a decorator node, so must have a child node defined.\n if (typeof definition.child === \"undefined\") {\n throw new Error(`expected property 'child' to be defined for fail node at depth '${depth}'`);\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n\n // Validate the child node of this decorator node.\n validateNode(definition.child, depth + 1);\n}\n\n/**\n * Validate an object that we expect to be a flip node definition.\n * @param definition An object that we expect to be a flip node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateFlipNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"flip\") {\n throw new Error(`expected node type of 'flip' for flip node at depth '${depth}'`);\n }\n\n // A flip node is a decorator node, so must have a child node defined.\n if (typeof definition.child === \"undefined\") {\n throw new Error(`expected property 'child' to be defined for flip node at depth '${depth}'`);\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n\n // Validate the child node of this decorator node.\n validateNode(definition.child, depth + 1);\n}\n\n/**\n * Validate an object that we expect to be a repeat node definition.\n * @param definition An object that we expect to be a repeat node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateRepeatNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"repeat\") {\n throw new Error(`expected node type of 'repeat' for repeat node at depth '${depth}'`);\n }\n\n // A repeat node is a decorator node, so must have a child node defined.\n if (typeof definition.child === \"undefined\") {\n throw new Error(`expected property 'child' to be defined for repeat node at depth '${depth}'`);\n }\n\n // Check whether an 'iterations' property has been defined, it may not have been if this node is to repeat indefinitely.\n if (typeof definition.iterations !== \"undefined\") {\n if (Array.isArray(definition.iterations)) {\n // Check whether any elements of the array are not integer values.\n const containsNonInteger = !!definition.iterations.filter((value: unknown) => !isInteger(value)).length;\n\n // If the 'iterations' property is an array then it MUST contain two integer values.\n if (definition.iterations.length !== 2 || containsNonInteger) {\n throw new Error(\n `expected array containing two integer values for 'iterations' property if defined for repeat node at depth '${depth}'`\n );\n }\n\n // A repeat node must have a positive min and max iterations count if they are defined.\n if (definition.iterations[0] < 0 || definition.iterations[1] < 0) {\n throw new Error(\n `expected positive minimum and maximum iterations count for 'iterations' property if defined for repeat node at depth '${depth}'`\n );\n }\n\n // A repeat node must not have a minimum iterations count that exceeds the maximum iterations count.\n if (definition.iterations[0] > definition.iterations[1]) {\n throw new Error(\n `expected minimum iterations count that does not exceed the maximum iterations count for 'iterations' property if defined for repeat node at depth '${depth}'`\n );\n }\n } else if (isInteger(definition.iterations)) {\n // A repeat node must have a positive number of iterations if defined.\n if (definition.iterations < 0) {\n throw new Error(\n `expected positive iterations count for 'iterations' property if defined for repeat node at depth '${depth}'`\n );\n }\n } else {\n throw new Error(\n `expected integer value or array containing two integer values for 'iterations' property if defined for repeat node at depth '${depth}'`\n );\n }\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n\n // Validate the child node of this decorator node.\n validateNode(definition.child, depth + 1);\n}\n\n/**\n * Validate an object that we expect to be a retry node definition.\n * @param definition An object that we expect to be a retry node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateRetryNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"retry\") {\n throw new Error(`expected node type of 'retry' for retry node at depth '${depth}'`);\n }\n\n // A retry node is a decorator node, so must have a child node defined.\n if (typeof definition.child === \"undefined\") {\n throw new Error(`expected property 'child' to be defined for retry node at depth '${depth}'`);\n }\n\n // Check whether an 'attempts' property has been defined, it may not have been if this node is to retry indefinitely.\n if (typeof definition.attempts !== \"undefined\") {\n if (Array.isArray(definition.attempts)) {\n // Check whether any elements of the array are not integer values.\n const containsNonInteger = !!definition.attempts.filter((value: unknown) => !isInteger(value)).length;\n\n // If the 'attempts' property is an array then it MUST contain two integer values.\n if (definition.attempts.length !== 2 || containsNonInteger) {\n throw new Error(\n `expected array containing two integer values for 'attempts' property if defined for retry node at depth '${depth}'`\n );\n }\n\n // A retry node must have a positive min and max attempts count if they are defined.\n if (definition.attempts[0] < 0 || definition.attempts[1] < 0) {\n throw new Error(\n `expected positive minimum and maximum attempts count for 'attempts' property if defined for retry node at depth '${depth}'`\n );\n }\n\n // A retry node must not have a minimum attempts count that exceeds the maximum attempts count.\n if (definition.attempts[0] > definition.attempts[1]) {\n throw new Error(\n `expected minimum attempts count that does not exceed the maximum attempts count for 'attempts' property if defined for retry node at depth '${depth}'`\n );\n }\n } else if (isInteger(definition.attempts)) {\n // A retry node must have a positive number of attempts if defined.\n if (definition.attempts < 0) {\n throw new Error(\n `expected positive attempts count for 'attempts' property if defined for retry node at depth '${depth}'`\n );\n }\n } else {\n throw new Error(\n `expected integer value or array containing two integer values for 'attempts' property if defined for retry node at depth '${depth}'`\n );\n }\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n\n // Validate the child node of this decorator node.\n validateNode(definition.child, depth + 1);\n}\n\n/**\n * Validate an object that we expect to be a branch node definition.\n * @param definition An object that we expect to be a branch node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateBranchNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"branch\") {\n throw new Error(`expected node type of 'branch' for branch node at depth '${depth}'`);\n }\n\n // Check that the branch node 'ref' property is defined and is a non-empty string.\n if (typeof definition.ref !== \"string\" || definition.ref.length === 0) {\n throw new Error(`expected non-empty string for 'ref' property for branch node at depth '${depth}'`);\n }\n\n // It is invalid to define guard attributes for a branch node as they should be defined on the referenced root node.\n [\"while\", \"until\"].forEach((attributeName) => {\n if (typeof definition[attributeName] !== \"undefined\") {\n throw new Error(\n `guards should not be defined for branch nodes but guard '${attributeName}' was defined for branch node at depth '${depth}'`\n );\n }\n });\n\n // It is invalid to define callback attributes for a branch node as they should be defined on the referenced root node.\n [\"entry\", \"exit\", \"step\"].forEach((attributeName) => {\n if (typeof definition[attributeName] !== \"undefined\") {\n throw new Error(\n `callbacks should not be defined for branch nodes but callback '${attributeName}' was defined for branch node at depth '${depth}'`\n );\n }\n });\n}\n\n/**\n * Validate an object that we expect to be a action node definition.\n * @param definition An object that we expect to be a action node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateActionNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"action\") {\n throw new Error(`expected node type of 'action' for action node at depth '${depth}'`);\n }\n\n // The 'call' property must be defined for a action node definition.\n if (typeof definition.call !== \"string\" || definition.call.length === 0) {\n throw new Error(`expected non-empty string for 'call' property of action node at depth '${depth}'`);\n }\n\n // If any action function arguments have been defined then they must have been defined in an array.\n if (typeof definition.args !== \"undefined\" && !Array.isArray(definition.args)) {\n throw new Error(`expected array for 'args' property if defined for action node at depth '${depth}'`);\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n}\n\n/**\n * Validate an object that we expect to be a condition node definition.\n * @param definition An object that we expect to be a condition node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateConditionNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"condition\") {\n throw new Error(`expected node type of 'condition' for condition node at depth '${depth}'`);\n }\n\n // The 'call' property must be defined for a condition node definition.\n if (typeof definition.call !== \"string\" || definition.call.length === 0) {\n throw new Error(`expected non-empty string for 'call' property of condition node at depth '${depth}'`);\n }\n\n // If any condition function arguments have been defined then they must have been defined in an array.\n if (typeof definition.args !== \"undefined\" && !Array.isArray(definition.args)) {\n throw new Error(`expected array for 'args' property if defined for condition node at depth '${depth}'`);\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n}\n\n/**\n * Validate an object that we expect to be a wait node definition.\n * @param definition An object that we expect to be a wait node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateWaitNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"wait\") {\n throw new Error(`expected node type of 'wait' for wait node at depth '${depth}'`);\n }\n\n // Check whether a 'duration' property has been defined, it may not have been if this node is to wait indefinitely.\n if (typeof definition.duration !== \"undefined\") {\n if (Array.isArray(definition.duration)) {\n // Check whether any elements of the array are not integer values.\n const containsNonInteger = !!definition.duration.filter((value: unknown) => !isInteger(value)).length;\n\n // If the 'duration' property is an array then it MUST contain two integer values.\n if (definition.duration.length !== 2 || containsNonInteger) {\n throw new Error(\n `expected array containing two integer values for 'duration' property if defined for wait node at depth '${depth}'`\n );\n }\n\n // A wait node must have a positive min and max duration value if they are defined.\n if (definition.duration[0] < 0 || definition.duration[1] < 0) {\n throw new Error(\n `expected positive minimum and maximum duration for 'duration' property if defined for wait node at depth '${depth}'`\n );\n }\n\n // A wait node must not have a minimum duration value that exceeds the maximum duration value.\n if (definition.duration[0] > definition.duration[1]) {\n throw new Error(\n `expected minimum duration value that does not exceed the maximum duration value for 'duration' property if defined for wait node at depth '${depth}'`\n );\n }\n } else if (isInteger(definition.duration)) {\n // A wait node must have a positive duration value if defined.\n if (definition.duration < 0) {\n throw new Error(\n `expected positive duration value for 'duration' property if defined for wait node at depth '${depth}'`\n );\n }\n } else {\n throw new Error(\n `expected integer value or array containing two integer values for 'duration' property if defined for wait node at depth '${depth}'`\n );\n }\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n}\n\n/**\n * Validate an object that we expect to be a sequence node definition.\n * @param definition An object that we expect to be a sequence node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateSequenceNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"sequence\") {\n throw new Error(`expected node type of 'sequence' for sequence node at depth '${depth}'`);\n }\n\n // A sequence node is a composite node, so must have a children nodes array defined.\n if (!Array.isArray(definition.children) || definition.children.length === 0) {\n throw new Error(`expected non-empty 'children' array to be defined for sequence node at depth '${depth}'`);\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n\n // Validate the child nodes of this composite node.\n definition.children.forEach((child: any) => validateNode(child, depth + 1));\n}\n\n/**\n * Validate an object that we expect to be a selector node definition.\n * @param definition An object that we expect to be a selector node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateSelectorNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"selector\") {\n throw new Error(`expected node type of 'selector' for selector node at depth '${depth}'`);\n }\n\n // A selector node is a composite node, so must have a children nodes array defined.\n if (!Array.isArray(definition.children) || definition.children.length === 0) {\n throw new Error(`expected non-empty 'children' array to be defined for selector node at depth '${depth}'`);\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n\n // Validate the child nodes of this composite node.\n definition.children.forEach((child: any) => validateNode(child, depth + 1));\n}\n\n/**\n * Validate an object that we expect to be a parallel node definition.\n * @param definition An object that we expect to be a parallel node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateParallelNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"parallel\") {\n throw new Error(`expected node type of 'parallel' for parallel node at depth '${depth}'`);\n }\n\n // A parallel node is a composite node, so must have a children nodes array defined.\n if (!Array.isArray(definition.children) || definition.children.length === 0) {\n throw new Error(`expected non-empty 'children' array to be defined for parallel node at depth '${depth}'`);\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n\n // Validate the child nodes of this composite node.\n definition.children.forEach((child: any) => validateNode(child, depth + 1));\n}\n\n/**\n * Validate an object that we expect to be a lotto node definition.\n * @param definition An object that we expect to be a lotto node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateLottoNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"lotto\") {\n throw new Error(`expected node type of 'lotto' for lotto node at depth '${depth}'`);\n }\n\n // A lotto node is a composite node, so must have a children nodes array defined.\n if (!Array.isArray(definition.children) || definition.children.length === 0) {\n throw new Error(`expected non-empty 'children' array to be defined for lotto node at depth '${depth}'`);\n }\n\n // Check whether a 'weights' property has been defined, if it has we expect it to be an array of weights.\n if (typeof definition.weights !== \"undefined\") {\n // Check that the weights property is an array of positive integers with an element for each child node element.\n if (\n !Array.isArray(definition.weights) ||\n definition.weights.length !== definition.children.length ||\n definition.weights.filter((value: unknown) => !isInteger(value)).length ||\n definition.weights.filter((value: number) => value < 0).length\n ) {\n throw new Error(\n `expected an array of positive integer weight values with a length matching the number of child nodes for 'weights' property if defined for lotto node at depth '${depth}'`\n );\n }\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n\n // Validate the child nodes of this composite node.\n definition.children.forEach((child: any) => validateNode(child, depth + 1));\n}\n\n/**\n * A helper function to create a failure validation result with the given error message.\n * @param errorMessage The validation failure error message.\n * @returns A failure validation result with the given error message.\n */\nfunction createValidationFailureResult(errorMessage: string): DefinitionValidationResult {\n return { succeeded: false, errorMessage };\n}\n", "import { ActionResult, Agent, GlobalFunction } from \"./Agent\";\nimport { RootNodeDefinition } from \"./BehaviourTreeDefinition\";\n\nexport type InvokerFunction = (args: any[]) => ActionResult | boolean;\n\n/**\n * A singleton used to store and lookup registered functions and subtrees.\n */\nexport default class Lookup {\n /**\n * The object holding any registered functions keyed on function name.\n */\n private static registeredFunctions: { [key: string]: GlobalFunction } = {};\n /**\n * The object holding any registered subtree root node definitions keyed on tree name.\n */\n private static registeredSubtrees: { [key: string]: RootNodeDefinition } = {};\n\n /**\n * Gets the function with the specified name.\n * @param name The name of the function.\n * @returns The function with the specified name.\n */\n public static getFunc(name: string): GlobalFunction {\n return this.registeredFunctions[name];\n }\n\n /**\n * Sets the function with the specified name for later lookup.\n * @param name The name of the function.\n * @param func The function.\n */\n public static setFunc(name: string, func: GlobalFunction): void {\n this.registeredFunctions[name] = func;\n }\n\n /**\n * Gets the function invoker for the specified agent and function name.\n * If a function with the specified name exists on the agent object then it will\n * be returned, otherwise we will then check the registered functions for a match.\n * @param agent The agent instance that this behaviour tree is modelling behaviour for.\n * @param name The function name.\n * @returns The function invoker for the specified agent and function name.\n */\n static getFuncInvoker(agent: Agent, name: string): InvokerFunction | null {\n // Check whether the agent contains the specified function.\n const agentFunction = agent[name];\n if (agentFunction && typeof agentFunction === \"function\") {\n return (args: any[]) => agentFunction.apply(agent, args);\n }\n\n // The agent does not contain the specified function but it may have been registered at some point.\n if (this.registeredFunctions[name] && typeof this.registeredFunctions[name] === \"function\") {\n const registeredFunction = this.registeredFunctions[name];\n return (args: any[]) => registeredFunction(agent, ...args.map((arg) => arg.value));\n }\n\n // We have no function to invoke.\n return null;\n }\n\n /**\n * Gets all registered subtree root node definitions.\n */\n static getSubtrees(): { [key: string]: RootNodeDefinition } {\n return this.registeredSubtrees;\n }\n\n /**\n * Sets the subtree with the specified name for later lookup.\n * @param name The name of the subtree.\n * @param subtree The subtree.\n */\n static setSubtree(name: string, subtree: RootNodeDefinition) {\n this.registeredSubtrees[name] = subtree;\n }\n\n /**\n * Removes the registered function or subtree with the specified name.\n * @param name The name of the registered function or subtree.\n */\n static remove(name: string) {\n delete this.registeredFunctions[name];\n delete this.registeredSubtrees[name];\n }\n\n /**\n * Remove all registered functions and subtrees.\n */\n static empty() {\n this.registeredFunctions = {};\n this.registeredSubtrees = {};\n }\n}\n", "import Node from \"../../nodes/Node\";\n\n/**\n * An exception thrown when evaluating node guard path conditions and a conditions fails.\n */\nexport default class GuardUnsatisifedException extends Error {\n /**\n * @param source The node at which a guard condition failed.\n */\n constructor(private source: Node) {\n super(\"A guard path condition has failed\");\n }\n\n /**\n * Gets whether the specified node is the node at which a guard condition failed.\n * @param node The node to check against the source node.\n * @returns Whether the specified node is the node at which a guard condition failed.\n */\n isSourceNode = (node: Node) => node === this.source;\n}\n", "import { Agent } from \"../../Agent\";\nimport Guard from \"./Guard\";\nimport Node from \"../../nodes/Node\";\nimport GuardUnsatisifedException from \"./GuardUnsatisifedException\";\n\nexport type GuardPathPart = {\n node: Node;\n guards: Guard[];\n};\n\n/**\n * Represents a path of node guards along a root-to-leaf tree path.\n */\nexport default class GuardPath {\n /**\n * @param nodes An array of objects defining a node instance -> guard link, ordered by node depth.\n */\n constructor(private nodes: GuardPathPart[]) {}\n\n /**\n * Evaluate guard conditions for all guards in the tree path, moving outwards from the root.\n * @param agent The agent, required for guard evaluation.\n * @returns An evaluation results object.\n */\n evaluate = (agent: Agent) => {\n // We need to evaluate guard conditions for nodes up the tree, moving outwards from the root.\n for (const details of this.nodes) {\n // There can be multiple guards per node.\n for (const guard of details.guards) {\n // Check whether the guard condition passes, and throw an exception if not.\n if (!guard.isSatisfied(agent)) {\n throw new GuardUnsatisifedException(details.node);\n }\n }\n }\n };\n}\n", "import { BehaviourTreeOptions } from \"../BehaviourTreeOptions\";\nimport State, { AnyState } from \"../State\";\nimport { Agent } from \"../Agent\";\nimport Leaf from \"./leaf/Leaf\";\nimport Attribute from \"../attributes/Attribute\";\nimport Entry from \"../attributes/callbacks/Entry\";\nimport Exit from \"../attributes/callbacks/Exit\";\nimport Step from \"../attributes/callbacks/Step\";\nimport Guard from \"../attributes/guards/Guard\";\nimport GuardPath from \"../attributes/guards/GuardPath\";\nimport GuardUnsatisifedException from \"../attributes/guards/GuardUnsatisifedException\";\n\n/**\n * A base node.\n */\nexport default abstract class Node {\n /**\n * The node uid.\n */\n private readonly uid: string = createNodeUid();\n /**\n * The node state.\n */\n private state: AnyState = State.READY;\n /**\n * The guard path to evaluate as part of a node update.\n */\n private guardPath: GuardPath | undefined;\n\n /**\n * @param type The node type.\n * @param attributes The node attributes.\n * @param args The node argument definitions.\n */\n constructor(private type: string, private attributes: Attribute[], private args: any[]) {}\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected abstract onUpdate(agent: Agent, options: BehaviourTreeOptions): void;\n\n /**\n * Gets the name of the node.\n */\n public abstract getName(): string;\n\n /**\n * Gets whether this node is a leaf node.\n */\n public abstract isLeafNode: () => this is Leaf;\n\n /**\n * Gets/Sets the state of the node.\n */\n getState = (): AnyState => this.state;\n setState = (value: AnyState): void => {\n this.state = value;\n };\n\n /**\n * Gets the unique id of the node.\n */\n getUid = () => this.uid;\n\n /**\n * Gets the type of the node.\n */\n getType = () => this.type;\n\n /**\n * Gets the node attributes.\n */\n getAttributes = () => this.attributes;\n\n /**\n * Gets the node arguments.\n */\n getArguments = () => this.args;\n\n /**\n * Gets the node attribute with the specified type, or null if it does not exist.\n */\n getAttribute(type: \"entry\" | \"ENTRY\"): Entry;\n getAttribute(type: \"exit\" | \"EXIT\"): Exit;\n getAttribute(type: \"step\" | \"STEP\"): Step;\n getAttribute(type: string): Attribute {\n return (\n this.getAttributes().filter((decorator) => decorator.type.toUpperCase() === type.toUpperCase())[0] || null\n );\n }\n\n /**\n * Gets the node attributes.\n */\n getGuardAttributes = (): Guard[] => this.getAttributes().filter((decorator) => decorator.isGuard()) as Guard[];\n\n /**\n * Sets the guard path to evaluate as part of a node update.\n */\n setGuardPath = (value: GuardPath) => (this.guardPath = value);\n\n /**\n * Gets whether a guard path is assigned to this node.\n */\n hasGuardPath = () => !!this.guardPath;\n\n /**\n * Gets whether this node is in the specified state.\n * @param value The value to compare to the node state.\n */\n public is(value: AnyState): boolean {\n return this.state === value;\n }\n\n /**\n * Reset the state of the node.\n */\n public reset(): void {\n this.setState(State.READY);\n }\n\n /**\n * Abort the running of this node.\n * @param agent The agent.\n */\n public abort(agent: Agent): void {\n // There is nothing to do if this node is not in the running state.\n if (!this.is(State.RUNNING)) {\n return;\n }\n\n // Reset the state of this node.\n this.reset();\n\n this.getAttribute(\"exit\")?.callAgentFunction(agent, false, true);\n }\n\n /**\n * Update the node.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n * @returns The result of the update.\n */\n public update(agent: Agent, options: BehaviourTreeOptions): void {\n // If this node is already in a 'SUCCEEDED' or 'FAILED' state then there is nothing to do.\n if (this.is(State.SUCCEEDED) || this.is(State.FAILED)) {\n return;\n }\n\n try {\n // Evaluate all of the guard path conditions for the current tree path.\n this.guardPath!.evaluate(agent);\n\n // If this node is in the READY state then call the ENTRY for this node if it exists.\n if (this.is(State.READY)) {\n this.getAttribute(\"entry\")?.callAgentFunction(agent);\n }\n\n this.getAttribute(\"step\")?.callAgentFunction(agent);\n\n // Do the actual update.\n this.onUpdate(agent, options);\n\n // If this node is now in a 'SUCCEEDED' or 'FAILED' state then call the EXIT for this node if it exists.\n if (this.is(State.SUCCEEDED) || this.is(State.FAILED)) {\n this.getAttribute(\"exit\")?.callAgentFunction(agent, this.is(State.SUCCEEDED), false);\n }\n } catch (error) {\n // If the error is a GuardUnsatisfiedException then we need to determine if this node is the source.\n if (error instanceof GuardUnsatisifedException && error.isSourceNode(this)) {\n // Abort the current node.\n this.abort(agent);\n\n // Any node that is the source of an abort will be a failed node.\n this.setState(State.FAILED);\n } else {\n throw error;\n }\n }\n }\n}\n\n/**\n * Create a randomly generated node uid.\n * @returns A randomly generated node uid.\n */\nfunction createNodeUid(): string {\n var S4 = function () {\n return (((1 + Math.random()) * 0x10000) | 0).toString(16).substring(1);\n };\n return S4() + S4() + \"-\" + S4() + \"-\" + S4() + \"-\" + S4() + \"-\" + S4() + S4() + S4();\n}\n", "import Node from \"../Node\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\n\n/**\n * A composite node that wraps child nodes.\n */\nexport default abstract class Composite extends Node {\n /**\n * @param type The node type.\n * @param attributes The node attributes.\n * @param children The child nodes.\n */\n constructor(type: string, attributes: Attribute[], protected children: Node[]) {\n super(type, attributes, []);\n }\n\n /**\n * Gets whether this node is a leaf node.\n */\n isLeafNode = () => false;\n\n /**\n * Gets the children of this node.\n */\n getChildren = () => this.children;\n\n /**\n * Reset the state of the node.\n */\n reset = () => {\n // Reset the state of this node.\n this.setState(State.READY);\n\n // Reset the state of any child nodes.\n this.getChildren().forEach((child) => child.reset());\n };\n\n /**\n * Abort the running of this node.\n * @param agent The agent.\n */\n abort = (agent: Agent) => {\n // There is nothing to do if this node is not in the running state.\n if (!this.is(State.RUNNING)) {\n return;\n }\n\n // Abort any child nodes.\n this.getChildren().forEach((child) => child.abort(agent));\n\n // Reset the state of this node.\n this.reset();\n\n this.getAttribute(\"exit\")?.callAgentFunction(agent, false, true);\n };\n}\n", "import Composite from \"./Composite\";\nimport State from \"../../State\";\nimport Node from \"../Node\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A PARALLEL node.\n * The child nodes are executed concurrently until one fails or all succeed.\n */\nexport default class Parallel extends Composite {\n /**\n * @param attributes The node attributes.\n * @param children The child nodes.\n */\n constructor(attributes: Attribute[], children: Node[]) {\n super(\"parallel\", attributes, children);\n }\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // Keep a count of the number of succeeded child nodes.\n let succeededCount = 0;\n\n let hasChildFailed = false;\n\n // Iterate over all of the children of this node.\n for (const child of this.children) {\n // If the child has never been updated or is running then we will need to update it now.\n if (child.getState() === State.READY || child.getState() === State.RUNNING) {\n // Update the child of this node.\n child.update(agent, options);\n }\n\n // If the current child has a state of 'SUCCEEDED' then we should move on to the next child.\n if (child.getState() === State.SUCCEEDED) {\n // The child node has succeeded, keep track of this to determine if all children have.\n succeededCount++;\n\n // The child node succeeded, but we have not finished checking every child node yet.\n continue;\n }\n\n // If the current child has a state of 'FAILED' then this node is also a 'FAILED' node.\n if (child.getState() === State.FAILED) {\n hasChildFailed = true;\n\n // There is no need to check the rest of the children.\n break;\n }\n\n // The node should be in the 'RUNNING' state.\n if (child.getState() !== State.RUNNING) {\n // The child node was not in an expected state.\n throw new Error(\"child node was not in an expected state.\");\n }\n }\n\n if (hasChildFailed) {\n // This node is a 'FAILED' node.\n this.setState(State.FAILED);\n\n // Abort every running child.\n for (const child of this.children) {\n if (child.getState() === State.RUNNING) {\n child.abort(agent);\n }\n }\n } else {\n // If all children have succeeded then this node has also succeeded, otherwise it is still running.\n this.setState(succeededCount === this.children.length ? State.SUCCEEDED : State.RUNNING);\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => \"PARALLEL\";\n}\n", "import Composite from \"./Composite\";\nimport Node from \"../Node\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A SELECTOR node.\n * The child nodes are executed in sequence until one succeeds or all fail.\n */\nexport default class Selector extends Composite {\n /**\n * @param attributes The node attributes.\n * @param children The child nodes.\n */\n constructor(attributes: Attribute[], protected children: Node[]) {\n super(\"selector\", attributes, children);\n }\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // Iterate over all of the children of this node.\n for (const child of this.children) {\n // If the child has never been updated or is running then we will need to update it now.\n if (child.getState() === State.READY || child.getState() === State.RUNNING) {\n // Update the child of this node.\n child.update(agent, options);\n }\n\n // If the current child has a state of 'SUCCEEDED' then this node is also a 'SUCCEEDED' node.\n if (child.getState() === State.SUCCEEDED) {\n // This node is a 'SUCCEEDED' node.\n this.setState(State.SUCCEEDED);\n\n // There is no need to check the rest of the selector nodes.\n return;\n }\n\n // If the current child has a state of 'FAILED' then we should move on to the next child.\n if (child.getState() === State.FAILED) {\n // Find out if the current child is the last one in the selector.\n // If it is then this sequence node has also failed.\n if (this.children.indexOf(child) === this.children.length - 1) {\n // This node is a 'FAILED' node.\n this.setState(State.FAILED);\n\n // There is no need to check the rest of the selector as we have completed it.\n return;\n } else {\n // The child node failed, try the next one.\n continue;\n }\n }\n\n // The node should be in the 'RUNNING' state.\n if (child.getState() === State.RUNNING) {\n // This node is a 'RUNNING' node.\n this.setState(State.RUNNING);\n\n // There is no need to check the rest of the selector as the current child is still running.\n return;\n }\n\n // The child node was not in an expected state.\n throw new Error(\"child node was not in an expected state.\");\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => \"SELECTOR\";\n}\n", "import Composite from \"./Composite\";\nimport Node from \"../Node\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A SEQUENCE node.\n * The child nodes are executed in sequence until one fails or all succeed.\n */\nexport default class Sequence extends Composite {\n /**\n * @param attributes The node attributes.\n * @param children The child nodes.\n */\n constructor(attributes: Attribute[], protected children: Node[]) {\n super(\"sequence\", attributes, children);\n }\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // Iterate over all of the children of this node.\n for (const child of this.children) {\n // If the child has never been updated or is running then we will need to update it now.\n if (child.getState() === State.READY || child.getState() === State.RUNNING) {\n // Update the child of this node.\n child.update(agent, options);\n }\n\n // If the current child has a state of 'SUCCEEDED' then we should move on to the next child.\n if (child.getState() === State.SUCCEEDED) {\n // Find out if the current child is the last one in the sequence.\n // If it is then this sequence node has also succeeded.\n if (this.children.indexOf(child) === this.children.length - 1) {\n // This node is a 'SUCCEEDED' node.\n this.setState(State.SUCCEEDED);\n\n // There is no need to check the rest of the sequence as we have completed it.\n return;\n } else {\n // The child node succeeded, but we have not finished the sequence yet.\n continue;\n }\n }\n\n // If the current child has a state of 'FAILED' then this node is also a 'FAILED' node.\n if (child.getState() === State.FAILED) {\n // This node is a 'FAILED' node.\n this.setState(State.FAILED);\n\n // There is no need to check the rest of the sequence.\n return;\n }\n\n // The node should be in the 'RUNNING' state.\n if (child.getState() === State.RUNNING) {\n // This node is a 'RUNNING' node.\n this.setState(State.RUNNING);\n\n // There is no need to check the rest of the sequence as the current child is still running.\n return;\n }\n\n // The child node was not in an expected state.\n throw new Error(\"child node was not in an expected state.\");\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => \"SEQUENCE\";\n}\n", "import createLotto from \"lotto-draw\";\n\nimport Node from \"../Node\";\nimport Composite from \"./Composite\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A LOTTO node.\n * A winning child is picked on the initial update of this node, based on ticket weighting.\n * The state of this node will match the state of the winning child.\n */\nexport default class Lotto extends Composite {\n /**\n * @param attributes The node attributes.\n * @param weights The child node weights.\n * @param children The child nodes.\n */\n constructor(attributes: Attribute[], private weights: number[] | undefined, children: Node[]) {\n super(\"lotto\", attributes, children);\n }\n\n /**\n * The child node selected to be the active one.\n */\n private selectedChild: Node | undefined;\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // If this node is in the READY state then we need to pick a winning child node.\n if (this.is(State.READY)) {\n // Create a lotto draw with which to randomly pick a child node to become the active one.\n const lottoDraw = createLotto({\n // Hook up the optional 'random' behaviour tree function option to the one used by 'lotto-draw'.\n random: options.random,\n // Pass in each child node as a participant in the lotto draw with their respective ticket count.\n participants: this.children.map((child, index) => [child, this.weights?.[index] || 1])\n });\n\n // Randomly pick a child based on ticket weighting, this will become the active child for this composite node.\n this.selectedChild = lottoDraw.draw() || undefined;\n }\n\n // If something went wrong and we don't have an active child then we should throw an error.\n if (!this.selectedChild) {\n throw new Error(\"failed to update lotto node as it has no active child\");\n }\n\n // If the selected child has never been updated or is running then we will need to update it now.\n if (this.selectedChild.getState() === State.READY || this.selectedChild.getState() === State.RUNNING) {\n this.selectedChild.update(agent, options);\n }\n\n // The state of the lotto node is the state of its selected child.\n this.setState(this.selectedChild.getState());\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => (this.weights ? `LOTTO [${this.weights.join(\",\")}]` : \"LOTTO\");\n}\n", "import Node from \"../Node\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\n\n/**\n * A decorator node that wraps a single child node.\n */\nexport default abstract class Decorator extends Node {\n /**\n * @param type The node type.\n * @param attributes The node attributes.\n * @param child The child node.\n */\n constructor(type: string, attributes: Attribute[], protected child: Node) {\n super(type, attributes, []);\n }\n\n /**\n * Gets whether this node is a leaf node.\n */\n isLeafNode = () => false;\n\n /**\n * Gets the children of this node.\n */\n getChildren = () => [this.child];\n\n /**\n * Reset the state of the node.\n */\n reset = () => {\n // Reset the state of this node.\n this.setState(State.READY);\n\n // Reset the state of the child node.\n this.child.reset();\n };\n\n /**\n * Abort the running of this node.\n * @param agent The agent.\n */\n abort = (agent: Agent) => {\n // There is nothing to do if this node is not in the running state.\n if (!this.is(State.RUNNING)) {\n return;\n }\n\n // Abort the child node.\n this.child.abort(agent);\n\n // Reset the state of this node.\n this.reset();\n\n this.getAttribute(\"exit\")?.callAgentFunction(agent, false, true);\n };\n}\n", "import Node from \"../Node\";\nimport Decorator from \"./Decorator\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A Fail node.\n * This node wraps a single child and will always move to the 'FAILED' state when the child moves to a 'SUCCEEDED' or 'FAILED' state.\n */\nexport default class Fail extends Decorator {\n /**\n * @param attributes The node attributes.\n * @param child The child node.\n */\n constructor(attributes: Attribute[], child: Node) {\n super(\"fail\", attributes, child);\n }\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // If the child has never been updated or is running then we will need to update it now.\n if (this.child.getState() === State.READY || this.child.getState() === State.RUNNING) {\n this.child.update(agent, options);\n }\n\n // The state of this node will depend in the state of its child.\n switch (this.child.getState()) {\n case State.RUNNING:\n this.setState(State.RUNNING);\n break;\n\n case State.SUCCEEDED:\n case State.FAILED:\n this.setState(State.FAILED);\n break;\n\n default:\n this.setState(State.READY);\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => \"FAIL\";\n}\n", "import Decorator from \"./Decorator\";\nimport State from \"../../State\";\nimport Node from \"../Node\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A Flip node.\n * This node wraps a single child and will flip the state of the child state.\n */\nexport default class Flip extends Decorator {\n /**\n * @param attributes The node attributes.\n * @param child The child node.\n */\n constructor(attributes: Attribute[], child: Node) {\n super(\"flip\", attributes, child);\n }\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // If the child has never been updated or is running then we will need to update it now.\n if (this.child.getState() === State.READY || this.child.getState() === State.RUNNING) {\n this.child.update(agent, options);\n }\n\n // The state of this node will depend in the state of its child.\n switch (this.child.getState()) {\n case State.RUNNING:\n this.setState(State.RUNNING);\n break;\n\n case State.SUCCEEDED:\n this.setState(State.FAILED);\n break;\n\n case State.FAILED:\n this.setState(State.SUCCEEDED);\n break;\n\n default:\n this.setState(State.READY);\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => \"FLIP\";\n}\n", "import Node from \"../Node\";\nimport Decorator from \"./Decorator\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A REPEAT node.\n * The node has a single child which can have:\n * -- A number of iterations for which to repeat the child node.\n * -- An infinite repeat loop if neither an iteration count or a condition function is defined.\n * The REPEAT node will stop and have a 'FAILED' state if its child is ever in a 'FAILED' state after an update.\n * The REPEAT node will attempt to move on to the next iteration if its child is ever in a 'SUCCEEDED' state.\n */\nexport default class Repeat extends Decorator {\n /**\n * @param attributes The node attributes.\n * @param iterations The number of iterations to repeat the child node.\n * @param iterationsMin The minimum possible number of iterations to repeat the child node.\n * @param iterationsMax The maximum possible number of iterations to repeat the child node.\n * @param child The child node.\n */\n constructor(\n attributes: Attribute[],\n private iterations: number | null,\n private iterationsMin: number | null,\n private iterationsMax: number | null,\n child: Node\n ) {\n super(\"repeat\", attributes, child);\n }\n\n /**\n * The number of target iterations to make.\n */\n private targetIterationCount: number | null = null;\n\n /**\n * The current iteration count.\n */\n private currentIterationCount: number = 0;\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // If this node is in the READY state then we need to reset the child and the target iteration count.\n if (this.is(State.READY)) {\n // Reset the child node.\n this.child.reset();\n\n // Reset the current iteration count.\n this.currentIterationCount = 0;\n\n // Set the target iteration count.\n this.setTargetIterationCount(options);\n }\n\n // Do a check to see if we can iterate. If we can then this node will move into the 'RUNNING' state.\n // If we cannot iterate then we have hit our target iteration count, which means that the node has succeeded.\n if (this.canIterate()) {\n // This node is in the running state and can do its initial iteration.\n this.setState(State.RUNNING);\n\n // We may have already completed an iteration, meaning that the child node will be in the SUCCEEDED state.\n // If this is the case then we will have to reset the child node now.\n if (this.child.getState() === State.SUCCEEDED) {\n this.child.reset();\n }\n\n // Update the child of this node.\n this.child.update(agent, options);\n\n // If the child moved into the FAILED state when we updated it then there is nothing left to do and this node has also failed.\n // If it has moved into the SUCCEEDED state then we have completed the current iteration.\n if (this.child.getState() === State.FAILED) {\n // The child has failed, meaning that this node has failed.\n this.setState(State.FAILED);\n\n return;\n } else if (this.child.getState() === State.SUCCEEDED) {\n // We have completed an iteration.\n this.currentIterationCount += 1;\n }\n } else {\n // This node is in the 'SUCCEEDED' state as we cannot iterate any more.\n this.setState(State.SUCCEEDED);\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => {\n if (this.iterations !== null) {\n return `REPEAT ${this.iterations}x`;\n } else if (this.iterationsMin !== null && this.iterationsMax !== null) {\n return `REPEAT ${this.iterationsMin}x-${this.iterationsMax}x`;\n } else {\n return \"REPEAT\";\n }\n };\n\n /**\n * Reset the state of the node.\n */\n reset = () => {\n // Reset the state of this node.\n this.setState(State.READY);\n\n // Reset the current iteration count.\n this.currentIterationCount = 0;\n\n // Reset the child node.\n this.child.reset();\n };\n\n /**\n * Gets whether an iteration can be made.\n * @returns Whether an iteration can be made.\n */\n private canIterate = () => {\n if (this.targetIterationCount !== null) {\n // We can iterate as long as we have not reached our target iteration count.\n return this.currentIterationCount < this.targetIterationCount;\n }\n\n // If neither an iteration count or a condition function were defined then we can iterate indefinitely.\n return true;\n };\n\n /**\n * Sets the target iteration count.\n * @param options The behaviour tree options object.\n */\n private setTargetIterationCount = (options: BehaviourTreeOptions) => {\n // Are we dealing with an explicit iteration count or will we be randomly picking a iteration count between the min and max iteration count.\n if (this.iterations !== null) {\n this.targetIterationCount = this.iterations;\n } else if (this.iterationsMin !== null && this.iterationsMax !== null) {\n // We will be picking a random iteration count between a min and max iteration count, if the optional 'random'\n // behaviour tree function option is defined then we will be using that, otherwise we will fall back to using Math.random.\n const random = typeof options.random === \"function\" ? options.random : Math.random;\n\n // Pick a random iteration count between a min and max iteration count.\n this.targetIterationCount = Math.floor(\n random() * (this.iterationsMax - this.iterationsMin + 1) + this.iterationsMin\n );\n } else {\n this.targetIterationCount = null;\n }\n };\n}\n", "import Node from \"../Node\";\nimport Decorator from \"./Decorator\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A RETRY node.\n * The node has a single child which can have:\n * -- A number of iterations for which to repeat the child node.\n * -- An infinite repeat loop if neither an iteration count or a condition function is defined.\n * The RETRY node will stop and have a 'SUCCEEDED' state if its child is ever in a 'SUCCEEDED' state after an update.\n * The RETRY node will attempt to move on to the next iteration if its child is ever in a 'FAILED' state.\n */\nexport default class Retry extends Decorator {\n /**\n * @param attributes The node attributes.\n * @param attempts The number of attempts to retry the child node.\n * @param attemptsMin The minimum possible number of attempts to retry the child node.\n * @param attemptsMax The maximum possible number of attempts to retry the child node.\n * @param child The child node.\n */\n constructor(\n attributes: Attribute[],\n private attempts: number | null,\n private attemptsMin: number | null,\n private attemptsMax: number | null,\n child: Node\n ) {\n super(\"retry\", attributes, child);\n }\n\n /**\n * The number of target attempts to make.\n */\n private targetAttemptCount: number | null = null;\n\n /**\n * The current attempt count.\n */\n private currentAttemptCount: number = 0;\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // If this node is in the READY state then we need to reset the child and the target attempt count.\n if (this.is(State.READY)) {\n // Reset the child node.\n this.child.reset();\n\n // Reset the current attempt count.\n this.currentAttemptCount = 0;\n\n // Set the target attempt count.\n this.setTargetAttemptCount(options);\n }\n\n // Do a check to see if we can attempt. If we can then this node will move into the 'RUNNING' state.\n // If we cannot attempt then we have hit our target attempt count, which means that the node has succeeded.\n if (this.canAttempt()) {\n // This node is in the running state and can do its initial attempt.\n this.setState(State.RUNNING);\n\n // We may have already completed an attempt, meaning that the child node will be in the FAILED state.\n // If this is the case then we will have to reset the child node now.\n if (this.child.getState() === State.FAILED) {\n this.child.reset();\n }\n\n // Update the child of this node.\n this.child.update(agent, options);\n\n // If the child moved into the SUCCEEDED state when we updated it then there is nothing left to do and this node has also succeeded.\n // If it has moved into the FAILED state then we have completed the current attempt.\n if (this.child.getState() === State.SUCCEEDED) {\n // The child has succeeded, meaning that this node has succeeded.\n this.setState(State.SUCCEEDED);\n\n return;\n } else if (this.child.getState() === State.FAILED) {\n // We have completed an attempt.\n this.currentAttemptCount += 1;\n }\n } else {\n // This node is in the 'FAILED' state as we cannot iterate any more.\n this.setState(State.FAILED);\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => {\n if (this.attempts !== null) {\n return `RETRY ${this.attempts}x`;\n } else if (this.attemptsMin !== null && this.attemptsMax !== null) {\n return `RETRY ${this.attemptsMin}x-${this.attemptsMax}x`;\n } else {\n return \"RETRY\";\n }\n };\n\n /**\n * Reset the state of the node.\n */\n reset = () => {\n // Reset the state of this node.\n this.setState(State.READY);\n\n // Reset the current attempt count.\n this.currentAttemptCount = 0;\n\n // Reset the child node.\n this.child.reset();\n };\n\n /**\n * Gets whether an attempt can be made.\n * @returns Whether an attempt can be made.\n */\n canAttempt = () => {\n if (this.targetAttemptCount !== null) {\n // We can attempt as long as we have not reached our target attempt count.\n return this.currentAttemptCount < this.targetAttemptCount;\n }\n\n // If neither an attempt count or a condition function were defined then we can attempt indefinitely.\n return true;\n };\n\n /**\n * Sets the target attempt count.\n * @param options The behaviour tree options object.\n */\n setTargetAttemptCount = (options: BehaviourTreeOptions) => {\n // Are we dealing with an explicit attempt count or will we be randomly picking an attempt count between the min and max attempt count.\n if (this.attempts !== null) {\n this.targetAttemptCount = this.attempts;\n } else if (this.attemptsMin !== null && this.attemptsMax !== null) {\n // We will be picking a random attempt count between a min and max attempt count, if the optional 'random'\n // behaviour tree function option is defined then we will be using that, otherwise we will fall back to using Math.random.\n const random = typeof options.random === \"function\" ? options.random : Math.random;\n\n // Pick a random attempt count between a min and max attempt count.\n this.targetAttemptCount = Math.floor(\n random() * (this.attemptsMax - this.attemptsMin + 1) + this.attemptsMin\n );\n } else {\n this.targetAttemptCount = null;\n }\n };\n}\n", "import Node from \"../Node\";\nimport Decorator from \"./Decorator\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A Root node.\n * The root node will have a single child.\n */\nexport default class Root extends Decorator {\n /**\n * @param attributes The node attributes.\n * @param child The child node.\n */\n constructor(attributes: Attribute[], child: Node) {\n super(\"root\", attributes, child);\n }\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // If the child has never been updated or is running then we will need to update it now.\n if (this.child.getState() === State.READY || this.child.getState() === State.RUNNING) {\n // Update the child of this node.\n this.child.update(agent, options);\n }\n\n // The state of the root node is the state of its child.\n this.setState(this.child.getState());\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => \"ROOT\";\n}\n", "import Node from \"../Node\";\nimport Decorator from \"./Decorator\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A Succeed node.\n * This node wraps a single child and will always move to the 'SUCCEEDED' state when the child moves to a 'SUCCEEDED' or 'FAILED' state.\n */\nexport default class Succeed extends Decorator {\n /**\n * @param attributes The node attributes.\n * @param child The child node.\n */\n constructor(attributes: Attribute[], child: Node) {\n super(\"succeed\", attributes, child);\n }\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // If the child has never been updated or is running then we will need to update it now.\n if (this.child.getState() === State.READY || this.child.getState() === State.RUNNING) {\n this.child.update(agent, options);\n }\n\n // The state of this node will depend in the state of its child.\n switch (this.child.getState()) {\n case State.RUNNING:\n this.setState(State.RUNNING);\n break;\n\n case State.SUCCEEDED:\n case State.FAILED:\n this.setState(State.SUCCEEDED);\n break;\n\n default:\n this.setState(State.READY);\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => \"SUCCEED\";\n}\n", "import Node from \"../Node\";\n\n/**\n * A leaf node.\n */\nexport default abstract class Leaf extends Node {\n /**\n * Gets whether this node is a leaf node.\n */\n isLeafNode = () => true;\n}\n", "import { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\nimport State, { CompleteState } from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Leaf from \"./Leaf\";\nimport Lookup from \"../../Lookup\";\nimport Attribute from \"../../attributes/Attribute\";\n\n/**\n * The type representing a resolved/rejected update promise.\n */\ntype UpdatePromiseResult = {\n /**\n * Whether the promise was resolved rather than rejected.\n */\n isResolved: boolean;\n\n /**\n * The promise resolved value or rejection reason.\n */\n value: any;\n};\n\n/**\n * An Action leaf node.\n * This represents an immediate or ongoing state of behaviour.\n */\nexport default class Action extends Leaf {\n /**\n * @param attributes The node attributes.\n * @param actionName The action name.\n * @param actionArguments The array of action argument definitions.\n */\n constructor(attributes: Attribute[], private actionName: string, private actionArguments: any[]) {\n super(\"action\", attributes, actionArguments);\n }\n\n /**\n * Whether there is a pending update promise.\n */\n private isUsingUpdatePromise = false;\n\n /**\n * The finished state result of an update promise.\n */\n private updatePromiseResult: UpdatePromiseResult | null = null;\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // If the result of this action depends on an update promise then there is nothing to do until it settles.\n if (this.isUsingUpdatePromise) {\n // Are we still waiting for our update promise to settle?\n if (!this.updatePromiseResult) {\n return;\n }\n\n const { isResolved, value } = this.updatePromiseResult;\n\n // Our update promise settled, was it resolved or rejected?\n if (isResolved) {\n // Our promise resolved so check to make sure the result is a valid finished state.\n if (value !== State.SUCCEEDED && value !== State.FAILED) {\n throw new Error(\n \"action node promise resolved with an invalid value, expected a State.SUCCEEDED or State.FAILED value to be returned\"\n );\n }\n\n // Set the state of this node to match the state returned by the promise.\n this.setState(value);\n\n return;\n } else {\n // The promise was rejected, which isn't great.\n throw new Error(`action function '${this.actionName}' promise rejected with '${value}'`);\n }\n }\n\n // Attempt to get the invoker for the action function.\n const actionFuncInvoker = Lookup.getFuncInvoker(agent, this.actionName);\n\n // The action function should be defined.\n if (actionFuncInvoker === null) {\n throw new Error(\n `cannot update action node as the action '${this.actionName}' function is not defined on the agent and has not been registered`\n );\n }\n\n let actionFunctionResult;\n\n try {\n // Call the action function, the result of which may be:\n // - The finished state of this action node.\n // - A promise to return a finished node state.\n // - Undefined if the node should remain in the running state.\n actionFunctionResult = actionFuncInvoker(this.actionArguments) as CompleteState | Promise;\n } catch (error) {\n // The user was naughty and threw something.\n throw new Error(`action function '${this.actionName}' threw '${error}'`);\n }\n\n if (actionFunctionResult instanceof Promise) {\n actionFunctionResult.then(\n (result) => {\n // If 'isUpdatePromisePending' is not set then the promise was cleared as it was resolving, probably via an abort of reset.\n if (!this.isUsingUpdatePromise) {\n return;\n }\n\n // Set the resolved update promise result so that it can be handled on the next update of this node.\n this.updatePromiseResult = {\n isResolved: true,\n value: result\n };\n },\n (reason) => {\n // If 'isUpdatePromisePending' is not set then the promise was cleared as it was resolving, probably via an abort or reset.\n if (!this.isUsingUpdatePromise) {\n return;\n }\n\n // Set the rejected update promise result so that it can be handled on the next update of this node.\n this.updatePromiseResult = {\n isResolved: false,\n value: reason\n };\n }\n );\n\n // This node will be in the 'RUNNING' state until the update promise resolves.\n this.setState(State.RUNNING);\n\n // We are now waiting for the promise returned by the use to resolve before we know what state this node is in.\n this.isUsingUpdatePromise = true;\n } else {\n // Validate the returned value.\n this.validateUpdateResult(actionFunctionResult);\n\n // Set the state of this node, this may be undefined, which just means that the node is still in the 'RUNNING' state.\n this.setState(actionFunctionResult || State.RUNNING);\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => this.actionName;\n\n /**\n * Reset the state of the node.\n */\n reset = () => {\n // Reset the state of this node.\n this.setState(State.READY);\n\n // There is no longer an update promise that we care about.\n this.isUsingUpdatePromise = false;\n this.updatePromiseResult = null;\n };\n\n /**\n * Validate the result of an update function call.\n * @param result The result of an update function call.\n */\n private validateUpdateResult = (result: CompleteState | State.RUNNING) => {\n switch (result) {\n case State.SUCCEEDED:\n case State.FAILED:\n case State.RUNNING:\n case undefined:\n return;\n default:\n throw new Error(\n `expected action function '${this.actionName}' to return an optional State.SUCCEEDED or State.FAILED value but returned '${result}'`\n );\n }\n };\n}\n", "import { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Leaf from \"./Leaf\";\nimport Lookup from \"../../Lookup\";\nimport Attribute from \"../../attributes/Attribute\";\n\n/**\n * A Condition leaf node.\n * This will succeed or fail immediately based on an agent predicate, without moving to the 'RUNNING' state.\n */\nexport default class Condition extends Leaf {\n /**\n * @param attributes The node attributes.\n * @param conditionName The name of the condition function.\n * @param conditionArguments The array of condition argument definitions.\n */\n constructor(attributes: Attribute[], private conditionName: string, private conditionArguments: any[]) {\n super(\"condition\", attributes, conditionArguments);\n }\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // Attempt to get the invoker for the condition function.\n const conditionFuncInvoker = Lookup.getFuncInvoker(agent, this.conditionName);\n\n // The condition function should be defined.\n if (conditionFuncInvoker === null) {\n throw new Error(\n `cannot update condition node as the condition '${this.conditionName}' function is not defined on the agent and has not been registered`\n );\n }\n\n let conditionFunctionResult;\n\n try {\n // Call the condition function to determine the state of this node, the result of which should be a boolean.\n conditionFunctionResult = conditionFuncInvoker(this.conditionArguments);\n } catch (error) {\n // The user was naughty and threw something.\n throw new Error(`condition function '${this.conditionName}' threw '${error}'`);\n }\n\n // The result of calling the condition function must be a boolean value.\n if (typeof conditionFunctionResult !== \"boolean\") {\n throw new Error(\n `expected condition function '${this.conditionName}' to return a boolean but returned '${conditionFunctionResult}'`\n );\n }\n\n // Set the state of this node based on the result of calling the condition function.\n this.setState(!!conditionFunctionResult ? State.SUCCEEDED : State.FAILED);\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => this.conditionName;\n}\n", "import Leaf from \"./Leaf\";\nimport State from \"../../State\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { Agent } from \"../../Agent\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A WAIT node.\n * The state of this node will change to SUCCEEDED after a duration of time\n */\nexport default class Wait extends Leaf {\n /**\n * @param attributes The node attributes.\n * @param duration The duration that this node will wait to succeed in milliseconds.\n * @param durationMin The minimum possible duration in milliseconds that this node will wait to succeed.\n * @param durationMax The maximum possible duration in milliseconds that this node will wait to succeed.\n */\n constructor(\n attributes: Attribute[],\n private duration: number | null,\n private durationMin: number | null,\n private durationMax: number | null\n ) {\n super(\"wait\", attributes, []);\n }\n\n /**\n * The time in milliseconds at which this node was first updated.\n */\n private initialUpdateTime: number = 0;\n\n /**\n * The total duration in milliseconds that this node will be waiting for.\n */\n private totalDuration: number | null = null;\n\n /**\n * The duration in milliseconds that this node has been waiting for.\n */\n private waitedDuration: number = 0;\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // If this node is in the READY state then we need to set the initial update time.\n if (this.is(State.READY)) {\n // Set the initial update time.\n this.initialUpdateTime = new Date().getTime();\n\n // Set the initial waited duration.\n this.waitedDuration = 0;\n\n // Are we dealing with an explicit duration or will we be randomly picking a duration between the min and max duration.\n if (this.duration !== null) {\n this.totalDuration = this.duration;\n } else if (this.durationMin !== null && this.durationMax !== null) {\n // We will be picking a random duration between a min and max duration, if the optional 'random' behaviour tree\n // function option is defined then we will be using that, otherwise we will fall back to using Math.random.\n const random = typeof options.random === \"function\" ? options.random : Math.random;\n\n // Pick a random duration between a min and max duration.\n this.totalDuration = Math.floor(\n random() * (this.durationMax - this.durationMin + 1) + this.durationMin\n );\n } else {\n this.totalDuration = null;\n }\n\n // The node is now running until we finish waiting.\n this.setState(State.RUNNING);\n }\n\n // If we have no total duration then this wait node will wait indefinitely until it is aborted.\n if (this.totalDuration === null) {\n return;\n }\n\n // If we have a 'getDeltaTime' function defined as part of our options then we will use it to figure out how long we have waited for.\n if (typeof options.getDeltaTime === \"function\") {\n // Get the delta time.\n const deltaTime = options.getDeltaTime();\n\n // Our delta time must be a valid number and cannot be NaN.\n if (typeof deltaTime !== \"number\" || isNaN(deltaTime)) {\n throw new Error(\"The delta time must be a valid number and not NaN.\");\n }\n\n // Update the amount of time that this node has been waiting for based on the delta time.\n this.waitedDuration += deltaTime * 1000;\n } else {\n // We are not using a delta time, so we will just work out hom much time has passed since the first update.\n this.waitedDuration = new Date().getTime() - this.initialUpdateTime;\n }\n\n // Have we waited long enough?\n if (this.waitedDuration >= this.totalDuration) {\n // We have finished waiting!\n this.setState(State.SUCCEEDED);\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => {\n if (this.duration !== null) {\n return `WAIT ${this.duration}ms`;\n } else if (this.durationMin !== null && this.durationMax !== null) {\n return `WAIT ${this.durationMin}ms-${this.durationMax}ms`;\n } else {\n return \"WAIT\";\n }\n };\n}\n", "import Guard from \"./guards/Guard\";\n\nexport type AttributeDetails = {\n /** The attribute type. */\n type: string;\n\n /** The attribute arguments. */\n args: any[];\n};\n\n/**\n * A base node attribute.\n */\nexport default abstract class Attribute {\n /**\n * @param type The node attribute type.\n * @param args The array of attribute arguments.\n */\n constructor(public type: string, public args: any[]) {}\n\n /**\n * Gets the attribute details.\n */\n abstract getDetails(): TAttributeDetails;\n\n /**\n * Gets whether this attribute is a guard.\n */\n abstract isGuard: () => this is Guard;\n}\n", "import { Agent } from \"../../Agent\";\nimport Attribute, { AttributeDetails } from \"../Attribute\";\n\nexport type GuardAttributeDetails = {\n /** The name of the condition function that determines whether the guard is satisfied. */\n condition: string;\n} & AttributeDetails;\n\n/**\n * A base node guard attribute.\n */\nexport default abstract class Guard extends Attribute {\n /**\n * @param type The node attribute type.\n * @param args The array of decorator argument definitions.\n * @param condition The name of the condition function that determines whether the guard is satisfied.\n */\n constructor(type: string, args: any[], private condition: string) {\n super(type, args);\n }\n\n /**\n * Gets the name of the condition function that determines whether the guard is satisfied.\n */\n getCondition = () => this.condition;\n\n /**\n * Gets whether this attribute is a guard.\n */\n isGuard = () => true;\n\n /**\n * Gets the attribute details.\n */\n getDetails(): GuardAttributeDetails {\n return {\n type: this.type,\n args: this.args,\n condition: this.getCondition()\n };\n }\n\n /**\n * Gets whether the guard is satisfied.\n * @param agent The agent.\n * @returns Whether the guard is satisfied.\n */\n abstract isSatisfied(agent: Agent): boolean;\n}\n", "import Guard from \"./Guard\";\nimport Lookup from \"../../Lookup\";\nimport { Agent } from \"../../Agent\";\n\n/**\n * A WHILE guard which is satisfied as long as the given condition remains true.\n */\nexport default class While extends Guard {\n /**\n * @param condition The name of the condition function that determines whether the guard is satisfied.\n * @param args The array of decorator argument definitions.\n */\n constructor(condition: string, args: any[]) {\n super(\"while\", args, condition);\n }\n\n /**\n * Gets whether the guard is satisfied.\n * @param agent The agent.\n * @returns Whether the guard is satisfied.\n */\n isSatisfied = (agent: Agent) => {\n // Attempt to get the invoker for the condition function.\n const conditionFuncInvoker = Lookup.getFuncInvoker(agent, this.getCondition());\n\n // The condition function should be defined.\n if (conditionFuncInvoker === null) {\n throw new Error(\n `cannot evaluate node guard as the condition '${this.getCondition()}' function is not defined on the agent and has not been registered`\n );\n }\n\n let conditionFunctionResult;\n\n try {\n // Call the guard condition function to determine the state of this node, the result of which should be a boolean.\n conditionFunctionResult = conditionFuncInvoker(this.args);\n } catch (error) {\n // The user was naughty and threw something.\n throw new Error(`guard condition function '${this.getCondition()}' threw '${error}'`);\n }\n\n // The result of calling the guard condition function must be a boolean value.\n if (typeof conditionFunctionResult !== \"boolean\") {\n throw new Error(\n `expected guard condition function '${this.getCondition()}' to return a boolean but returned '${conditionFunctionResult}'`\n );\n }\n\n // Return whether this guard is satisfied.\n return conditionFunctionResult;\n };\n}\n", "import Guard from \"./Guard\";\nimport Lookup from \"../../Lookup\";\nimport { Agent } from \"../../Agent\";\n\n/**\n * An UNTIL guard which is satisfied as long as the given condition remains false.\n */\nexport default class Until extends Guard {\n /**\n * @param condition The name of the condition function that determines whether the guard is satisfied.\n * @param args The array of decorator argument definitions.\n */\n constructor(condition: string, args: any[]) {\n super(\"until\", args, condition);\n }\n\n /**\n * Gets whether the guard is satisfied.\n * @param agent The agent.\n * @returns Whether the guard is satisfied.\n */\n isSatisfied = (agent: Agent) => {\n // Attempt to get the invoker for the condition function.\n const conditionFuncInvoker = Lookup.getFuncInvoker(agent, this.getCondition());\n\n // The condition function should be defined.\n if (conditionFuncInvoker === null) {\n throw new Error(\n `cannot evaluate node guard as the condition '${this.getCondition()}' function is not defined on the agent and has not been registered`\n );\n }\n\n let conditionFunctionResult;\n\n try {\n // Call the guard condition function to determine the state of this node, the result of which should be a boolean.\n conditionFunctionResult = conditionFuncInvoker(this.args);\n } catch (error) {\n // The user was naughty and threw something.\n throw new Error(`guard condition function '${this.getCondition()}' threw '${error}'`);\n }\n\n // The result of calling the guard condition function must be a boolean value.\n if (typeof conditionFunctionResult !== \"boolean\") {\n throw new Error(\n `expected guard condition function '${this.getCondition()}' to return a boolean but returned '${conditionFunctionResult}'`\n );\n }\n\n // Return whether this guard is satisfied.\n return !conditionFunctionResult;\n };\n}\n", "import { Agent } from \"../../Agent\";\nimport Attribute, { AttributeDetails } from \"../Attribute\";\n\nexport type CallbackAttributeDetails = {\n /** The name of the agent function that is called. */\n functionName: string;\n} & AttributeDetails;\n\n/**\n * A base node callback attribute.\n */\nexport default abstract class Callback extends Attribute {\n /**\n * @param type The node attribute type.\n * @param args The array of decorator argument definitions.\n * @param functionName The name of the agent function to call.\n */\n constructor(type: string, args: any[], private functionName: string) {\n super(type, args);\n }\n\n /**\n * Gets the name of the agent function to call.\n */\n getFunctionName = () => this.functionName;\n\n /**\n * Gets whether this attribute is a guard.\n */\n isGuard = () => false;\n\n /**\n * Gets the attribute details.\n */\n getDetails(): CallbackAttributeDetails {\n return {\n type: this.type,\n args: this.args,\n functionName: this.getFunctionName()\n };\n }\n\n /**\n * Attempt to call the agent function that this callback refers to.\n * @param agent The agent.\n */\n abstract callAgentFunction: (agent: Agent, isSuccess: boolean, isAborted: boolean) => void;\n}\n", "import Callback from \"./Callback\";\nimport Lookup from \"../../Lookup\";\nimport { Agent } from \"../../Agent\";\n\n/**\n * An ENTRY callback which defines an agent function to call when the associated node is updated and moves out of running state.\n */\nexport default class Entry extends Callback {\n /**\n * @param functionName The name of the agent function to call.\n * @param args The array of callback argument definitions.\n */\n constructor(functionName: string, args: any[]) {\n super(\"entry\", args, functionName);\n }\n\n /**\n * Attempt to call the agent function that this callback refers to.\n * @param agent The agent.\n */\n callAgentFunction = (agent: Agent) => {\n // Attempt to get the invoker for the callback function.\n const callbackFuncInvoker = Lookup.getFuncInvoker(agent, this.getFunctionName());\n\n // The callback function should be defined.\n if (callbackFuncInvoker === null) {\n throw new Error(\n `cannot call entry function '${this.getFunctionName()}' as is not defined on the agent and has not been registered`\n );\n }\n\n // Call the callback function.\n callbackFuncInvoker(this.args);\n };\n}\n", "import Callback from \"./Callback\";\nimport Lookup from \"../../Lookup\";\nimport { Agent } from \"../../Agent\";\n\n/**\n * A STEP callback which defines an agent function to call when the associated node is updated.\n */\nexport default class Step extends Callback {\n /**\n * @param functionName The name of the agent function to call.\n * @param args The array of callback argument definitions.\n */\n constructor(functionName: string, args: any[]) {\n super(\"step\", args, functionName);\n }\n\n /**\n * Attempt to call the agent function that this callback refers to.\n * @param agent The agent.\n */\n callAgentFunction = (agent: Agent) => {\n // Attempt to get the invoker for the callback function.\n const callbackFuncInvoker = Lookup.getFuncInvoker(agent, this.getFunctionName());\n\n // The callback function should be defined.\n if (callbackFuncInvoker === null) {\n throw new Error(\n `cannot call step function '${this.getFunctionName()}' as is not defined on the agent and has not been registered`\n );\n }\n\n // Call the callback function.\n callbackFuncInvoker(this.args);\n };\n}\n", "import Callback from \"./Callback\";\nimport Lookup from \"../../Lookup\";\nimport { Agent } from \"../../Agent\";\n\n/**\n * An EXIT callback which defines an agent function to call when the associated node is updated and moves to a finished state or is aborted.\n */\nexport default class Exit extends Callback {\n /**\n * @param functionName The name of the agent function to call.\n * @param args The array of callback argument definitions.\n */\n constructor(functionName: string, args: any[]) {\n super(\"exit\", args, functionName);\n }\n\n /**\n * Attempt to call the agent function that this callback refers to.\n * @param agent The agent.\n * @param isSuccess Whether the decorated node was left with a success state.\n * @param isAborted Whether the decorated node was aborted.\n */\n callAgentFunction = (agent: Agent, isSuccess: boolean, isAborted: boolean) => {\n // Attempt to get the invoker for the callback function.\n const callbackFuncInvoker = Lookup.getFuncInvoker(agent, this.getFunctionName());\n\n // The callback function should be defined.\n if (callbackFuncInvoker === null) {\n throw new Error(\n `cannot call exit function '${this.getFunctionName()}' as is not defined on the agent and has not been registered`\n );\n }\n\n // Call the callback function\n callbackFuncInvoker([{ succeeded: isSuccess, aborted: isAborted }, ...this.args]);\n };\n}\n", "import { AnyNodeDefinition, RootNodeDefinition } from \"./BehaviourTreeDefinition\";\nimport GuardPath, { GuardPathPart } from \"./attributes/guards/GuardPath\";\nimport { validateBranchSubtreeLinks } from \"./BehaviourTreeDefinitionValidator\";\nimport { isInteger } from \"./BehaviourTreeDefinitionUtilities\";\nimport Node from \"./nodes/Node\";\nimport Composite from \"./nodes/composite/Composite\";\nimport Decorator from \"./nodes/decorator/Decorator\";\nimport Parallel from \"./nodes/composite/Parallel\";\nimport Selector from \"./nodes/composite/Selector\";\nimport Sequence from \"./nodes/composite/Sequence\";\nimport Lotto from \"./nodes/composite/Lotto\";\nimport Fail from \"./nodes/decorator/Fail\";\nimport Flip from \"./nodes/decorator/Flip\";\nimport Repeat from \"./nodes/decorator/Repeat\";\nimport Retry from \"./nodes/decorator/Retry\";\nimport Root from \"./nodes/decorator/Root\";\nimport Succeed from \"./nodes/decorator/Succeed\";\nimport Action from \"./nodes/leaf/Action\";\nimport Condition from \"./nodes/leaf/Condition\";\nimport Wait from \"./nodes/leaf/Wait\";\nimport Lookup from \"./Lookup\";\nimport Attribute from \"./attributes/Attribute\";\nimport While from \"./attributes/guards/While\";\nimport Until from \"./attributes/guards/Until\";\nimport Entry from \"./attributes/callbacks/Entry\";\nimport Step from \"./attributes/callbacks/Step\";\nimport Exit from \"./attributes/callbacks/Exit\";\n\n/**\n * A type representing any node instance in a behaviour tree.\n */\ntype AnyNode =\n | Root\n | Action\n | Condition\n | Wait\n | Sequence\n | Selector\n | Lotto\n | Parallel\n | Repeat\n | Retry\n | Flip\n | Succeed\n | Fail;\n\n/**\n * A type defining a mapping of root node identifiers to root node definitions.\n */\ntype RootNodeDefinitionMap = { [key: string | symbol]: RootNodeDefinition };\n\n/**\n * A symbol to use as the main root key in any root node mappings.\n */\nconst MAIN_ROOT_NODE_KEY = Symbol(\"__root__\");\n\n/**\n * Build and populate the root nodes based on the provided definition, assuming that the definition has been validated.\n * @param definition The root node definitions.\n * @returns The built and populated root node definitions.\n */\nexport default function buildRootNode(definition: RootNodeDefinition[]): Root {\n // Create a mapping of root node identifers to root node definitions, including globally registered subtree root node definitions.\n const rootNodeDefinitionMap = createRootNodeDefinitionMap(definition);\n\n // Now that we have all of our root node definitions (those part of the tree definition and those globally registered)\n // we should validate the branch-subtree links. This will also double-check that we dont have any circular dependencies\n // in our branch-subtree references and that we have no broken branch-subtree links.\n validateBranchSubtreeLinks(\n [rootNodeDefinitionMap[MAIN_ROOT_NODE_KEY], ...Object.values(rootNodeDefinitionMap)],\n true\n );\n\n // Create our populated tree of node instances, starting with our main root node.\n const rootNode = nodeFactory(rootNodeDefinitionMap[MAIN_ROOT_NODE_KEY], rootNodeDefinitionMap) as Root;\n\n // Set a guard path on every leaf of the tree to evaluate as part of each update.\n applyLeafNodeGuardPaths(rootNode);\n\n // We only need to return the main root node.\n return rootNode;\n}\n\n/**\n * A factory function which creates a node instance based on the specified definition.\n * @param definition The node definition.\n * @param rootNodeDefinitionMap The mapping of root node identifers to root node definitions, including globally registered subtree root node definitions.\n * @returns A node instance based on the specified definition.\n */\nfunction nodeFactory(definition: AnyNodeDefinition, rootNodeDefinitionMap: RootNodeDefinitionMap): AnyNode {\n // Get the attributes for the node.\n const attributes = nodeAttributesFactory(definition);\n\n // Create the node instance based on the definition type.\n switch (definition.type) {\n case \"root\":\n return new Root(attributes, nodeFactory(definition.child, rootNodeDefinitionMap));\n\n case \"repeat\":\n let iterations: number | null = null;\n let iterationsMin: number | null = null;\n let iterationsMax: number | null = null;\n\n if (Array.isArray(definition.iterations)) {\n iterationsMin = definition.iterations[0];\n iterationsMax = definition.iterations[1];\n } else if (isInteger(definition.iterations)) {\n iterations = definition.iterations!;\n }\n\n return new Repeat(\n attributes,\n iterations,\n iterationsMin,\n iterationsMax,\n nodeFactory(definition.child, rootNodeDefinitionMap)\n );\n\n case \"retry\":\n let attempts: number | null = null;\n let attemptsMin: number | null = null;\n let attemptsMax: number | null = null;\n\n if (Array.isArray(definition.attempts)) {\n attemptsMin = definition.attempts[0];\n attemptsMax = definition.attempts[1];\n } else if (isInteger(definition.attempts)) {\n attempts = definition.attempts!;\n }\n\n return new Retry(\n attributes,\n attempts,\n attemptsMin,\n attemptsMax,\n nodeFactory(definition.child, rootNodeDefinitionMap)\n );\n\n case \"flip\":\n return new Flip(attributes, nodeFactory(definition.child, rootNodeDefinitionMap));\n\n case \"succeed\":\n return new Succeed(attributes, nodeFactory(definition.child, rootNodeDefinitionMap));\n\n case \"fail\":\n return new Fail(attributes, nodeFactory(definition.child, rootNodeDefinitionMap));\n\n case \"sequence\":\n return new Sequence(\n attributes,\n definition.children.map((child) => nodeFactory(child, rootNodeDefinitionMap))\n );\n\n case \"selector\":\n return new Selector(\n attributes,\n definition.children.map((child) => nodeFactory(child, rootNodeDefinitionMap))\n );\n\n case \"parallel\":\n return new Parallel(\n attributes,\n definition.children.map((child) => nodeFactory(child, rootNodeDefinitionMap))\n );\n\n case \"lotto\":\n return new Lotto(\n attributes,\n definition.weights,\n definition.children.map((child) => nodeFactory(child, rootNodeDefinitionMap))\n );\n\n case \"branch\":\n return nodeFactory(rootNodeDefinitionMap[definition.ref].child, rootNodeDefinitionMap);\n\n case \"action\":\n return new Action(attributes, definition.call, definition.args || []);\n\n case \"condition\":\n return new Condition(attributes, definition.call, definition.args || []);\n\n case \"wait\":\n let duration: number | null = null;\n let durationMin: number | null = null;\n let durationMax: number | null = null;\n\n if (Array.isArray(definition.duration)) {\n durationMin = definition.duration[0];\n durationMax = definition.duration[1];\n } else if (isInteger(definition.duration)) {\n duration = definition.duration!;\n }\n\n return new Wait(attributes, duration, durationMin, durationMax);\n }\n}\n\n/**\n * Creates an array of node attribute instances based on the specified node definition.\n * @param definition The node definition.\n * @returns An array of node attribute instances based on the specified node definition.\n */\nfunction nodeAttributesFactory(definition: AnyNodeDefinition): Attribute[] {\n const attributes: Attribute[] = [];\n\n if (definition.while) {\n attributes.push(new While(definition.while.call, definition.while.args ?? []));\n }\n\n if (definition.until) {\n attributes.push(new Until(definition.until.call, definition.until.args ?? []));\n }\n\n if (definition.entry) {\n attributes.push(new Entry(definition.entry.call, definition.entry.args ?? []));\n }\n\n if (definition.step) {\n attributes.push(new Step(definition.step.call, definition.step.args ?? []));\n }\n\n if (definition.exit) {\n attributes.push(new Exit(definition.exit.call, definition.exit.args ?? []));\n }\n\n return attributes;\n}\n\n/**\n * Creates a mapping of root node identifers to root node definitions, mixing in globally registered subtree root node definitions.\n * @param definition The root node definitions.\n * @returns A mapping of root node identifers to root node definitions, including globally registered subtree root node definitions.\n */\nfunction createRootNodeDefinitionMap(definition: RootNodeDefinition[]): RootNodeDefinitionMap {\n // Create a mapping of root node identifers to root node definitions.\n const rootNodeMap: RootNodeDefinitionMap = {};\n\n // Add in any registered subtree root node definitions.\n for (const [name, rootNodeDefinition] of Object.entries(Lookup.getSubtrees())) {\n // The name used when registering the subtree will be used as the root node identifier.\n rootNodeMap[name] = { ...rootNodeDefinition, id: name };\n }\n\n // Populate the map with the root node definitions that were included with the tree definition.\n // We do this after adding any registered subtrees as we want these to take presedence.\n for (const rootNodeDefinition of definition) {\n rootNodeMap[rootNodeDefinition.id ?? MAIN_ROOT_NODE_KEY] = rootNodeDefinition;\n }\n\n return rootNodeMap;\n}\n\n/**\n * Applies a guard path to every leaf of the tree to evaluate as part of each update.\n * @param root The main root tree node.\n */\nfunction applyLeafNodeGuardPaths(root: Root) {\n const nodePaths: Node[][] = [];\n\n const findLeafNodes = (path: Node[], node: Node) => {\n // Add the current node to the path.\n path = path.concat(node);\n\n // Check whether the current node is a leaf node.\n if (node.isLeafNode()) {\n nodePaths.push(path);\n } else {\n (node as Composite | Decorator).getChildren().forEach((child) => findLeafNodes(path, child));\n }\n };\n\n // Find all leaf node paths, starting from the root.\n findLeafNodes([], root);\n\n nodePaths.forEach((path) => {\n // Each node in the current path will have to be assigned a guard path, working from the root outwards.\n for (let depth = 0; depth < path.length; depth++) {\n // Get the node in the path at the current depth.\n const currentNode = path[depth];\n\n // The node may already have been assigned a guard path, if so just skip it.\n if (currentNode.hasGuardPath()) {\n continue;\n }\n\n // Create the guard path for the current node.\n const guardPath = new GuardPath(\n path\n .slice(0, depth + 1)\n .map((node) => ({ node, guards: node.getGuardAttributes() }))\n .filter((details) => details.guards.length > 0)\n );\n\n // Assign the guard path to the current node.\n currentNode.setGuardPath(guardPath);\n }\n });\n}\n", "import State, { AnyState } from \"./State\";\nimport Lookup from \"./Lookup\";\nimport Node from \"./nodes/Node\";\nimport Root from \"./nodes/decorator/Root\";\nimport Composite from \"./nodes/composite/Composite\";\nimport Decorator from \"./nodes/decorator/Decorator\";\nimport { Agent, GlobalFunction } from \"./Agent\";\nimport { CallbackAttributeDetails } from \"./attributes/callbacks/Callback\";\nimport { GuardAttributeDetails } from \"./attributes/guards/Guard\";\nimport { BehaviourTreeOptions } from \"./BehaviourTreeOptions\";\nimport { convertMDSLToJSON } from \"./mdsl/MDSLDefinitionParser\";\nimport { RootNodeDefinition } from \"./BehaviourTreeDefinition\";\nimport { validateDefinition, validateJSONDefinition } from \"./BehaviourTreeDefinitionValidator\";\nimport buildRootNode from \"./BehaviourTreeBuilder\";\nimport { isNullOrUndefined } from \"./BehaviourTreeDefinitionUtilities\";\n\n// Purely for outside inspection of the tree.\nexport type FlattenedTreeNode = {\n id: string;\n type: string;\n caption: string;\n state: AnyState;\n guards: GuardAttributeDetails[];\n callbacks: CallbackAttributeDetails[];\n args: any[];\n parentId: string | null;\n};\n\n/**\n * A representation of a behaviour tree.\n */\nexport class BehaviourTree {\n /**\n * The main root tree node.\n */\n private readonly _rootNode: Root;\n\n /**\n * Creates a new instance of the BehaviourTree class.\n * @param definition The behaviour tree definition as either an MDSL string, root node definition object or array of root node definition objects.\n * @param agent The agent instance that this behaviour tree is modelling behaviour for.\n * @param options The behaviour tree options object.\n */\n constructor(\n definition: string | RootNodeDefinition | RootNodeDefinition[],\n private agent: Agent,\n private options: BehaviourTreeOptions = {}\n ) {\n // The tree definition must be defined.\n if (isNullOrUndefined(definition)) {\n throw new Error(\"tree definition not defined\");\n }\n\n // The agent must be defined and not null.\n if (typeof agent !== \"object\" || agent === null) {\n throw new Error(\"the agent must be an object and not null\");\n }\n\n // We should validate the definition before we try to build the tree nodes.\n const { succeeded, errorMessage, json } = validateDefinition(definition);\n\n // Did our validation fail without error?\n if (!succeeded) {\n throw new Error(`invalid definition: ${errorMessage}`);\n }\n\n // Double check that we did actually get our json definition as part of our definition validtion.\n if (!json) {\n throw new Error(\n \"expected json definition to be returned as part of successful definition validation response\"\n );\n }\n\n try {\n // Create the populated tree of behaviour tree nodes and get the root node.\n this._rootNode = buildRootNode(json);\n } catch (exception) {\n // There was an issue in trying build and populate the behaviour tree.\n throw new Error(`error building tree: ${(exception as Error).message}`);\n }\n }\n\n /**\n * Gets whether the tree is in the RUNNING state.\n * @returns true if the tree is in the RUNNING state, otherwise false.\n */\n isRunning() {\n return this._rootNode.getState() === State.RUNNING;\n }\n\n /**\n * Gets the current tree state of SUCCEEDED, FAILED, READY or RUNNING.\n * @returns The current tree state.\n */\n getState() {\n return this._rootNode.getState();\n }\n\n /**\n * Step the tree.\n * 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.\n * 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\n * 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.\n *\n * 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.\n */\n step() {\n // If the root node has already been stepped to completion then we need to reset it.\n if (this._rootNode.getState() === State.SUCCEEDED || this._rootNode.getState() === State.FAILED) {\n this._rootNode.reset();\n }\n\n try {\n this._rootNode.update(this.agent, this.options);\n } catch (exception) {\n throw new Error(`error stepping tree: ${(exception as Error).message}`);\n }\n }\n\n /**\n * Resets the tree from the root node outwards to each nested node, giving each a state of READY.\n */\n reset() {\n this._rootNode.reset();\n }\n\n /**\n * Gets the flattened details of every node in the tree.\n * @returns The flattened details of every node in the tree.\n */\n getFlattenedNodeDetails(): FlattenedTreeNode[] {\n // Create an empty flattened array of tree nodes.\n const flattenedTreeNodes: FlattenedTreeNode[] = [];\n\n /**\n * Helper function to process a node instance and push details into the flattened tree nodes array.\n * @param node The current node.\n * @param parentUid The UID of the node parent, or null if the node is the main root node.\n */\n const processNode = (node: Node, parentUid: string | null) => {\n // Get the guard and callback attribute details for this node.\n const guards = node\n .getAttributes()\n .filter((attribute) => attribute.isGuard())\n .map((attribute) => attribute.getDetails()) as GuardAttributeDetails[];\n const callbacks = node\n .getAttributes()\n .filter((attribute) => !attribute.isGuard())\n .map((attribute) => attribute.getDetails()) as CallbackAttributeDetails[];\n\n // Push the current node into the flattened nodes array.\n flattenedTreeNodes.push({\n id: node.getUid(),\n type: node.getType(),\n caption: node.getName(),\n state: node.getState(),\n guards,\n callbacks,\n args: node.getArguments(),\n parentId: parentUid\n });\n\n // Process each of the nodes children if it is not a leaf node.\n if (!node.isLeafNode()) {\n (node as Composite | Decorator)\n .getChildren()\n .forEach((child) => processNode(child, (node as Composite | Decorator).getUid()));\n }\n };\n\n // Convert the nested node structure into a flattened array of node details.\n processNode(this._rootNode, null);\n\n return flattenedTreeNodes;\n }\n\n /**\n * Registers the action/condition/guard/callback function or subtree with the given name.\n * @param name The name of the function or subtree to register.\n * @param value The function or subtree definition to register.\n */\n static register(name: string, value: GlobalFunction | string | RootNodeDefinition) {\n // Are we going to register a action/condition/guard/callback function?\n if (typeof value === \"function\") {\n Lookup.setFunc(name, value);\n return;\n }\n\n // We are not registering an action/condition/guard/callback function, so we must be registering a subtree.\n if (typeof value === \"string\") {\n let rootNodeDefinitions: RootNodeDefinition[];\n\n // We will assume that any string passed in will be a mdsl definition.\n try {\n rootNodeDefinitions = convertMDSLToJSON(value);\n } catch (exception) {\n throw new Error(`error registering definition, invalid MDSL: ${(exception as Error).message}`);\n }\n\n // This function should only ever be called with a definition containing a single unnamed root node.\n if (rootNodeDefinitions.length != 1 || rootNodeDefinitions[0].id !== null) {\n throw new Error(\"error registering definition: expected a single unnamed root node\");\n }\n\n try {\n // We should validate the subtree as we don't want invalid subtrees available via the lookup.\n const { succeeded, errorMessage } = validateJSONDefinition(rootNodeDefinitions[0]);\n\n // Did our validation fail without error?\n if (!succeeded) {\n throw new Error(errorMessage);\n }\n } catch (exception) {\n throw new Error(`error registering definition: ${(exception as Error).message}`);\n }\n\n // Everything seems hunky-dory, register the subtree.\n Lookup.setSubtree(name, rootNodeDefinitions[0]);\n } else if (typeof value === \"object\" && !Array.isArray(value)) {\n // We will assume that any object passed in is a root node definition.\n\n try {\n // We should validate the subtree as we don't want invalid subtrees available via the lookup.\n const { succeeded, errorMessage } = validateJSONDefinition(value);\n\n // Did our validation fail without error?\n if (!succeeded) {\n throw new Error(errorMessage);\n }\n } catch (exception) {\n throw new Error(`error registering definition: ${(exception as Error).message}`);\n }\n\n // Everything seems hunky-dory, register the subtree.\n Lookup.setSubtree(name, value);\n } else {\n throw new Error(\"unexpected value, expected string mdsl definition, root node json definition or function\");\n }\n }\n\n /**\n * Unregisters the registered action/condition/guard/callback function or subtree with the given name.\n * @param name The name of the registered action/condition/guard/callback function or subtree to unregister.\n */\n static unregister(name: string): void {\n Lookup.remove(name);\n }\n\n /**\n * Unregister all registered action/condition/guard/callback functions and subtrees.\n */\n static unregisterAll(): void {\n Lookup.empty();\n }\n}\n"], + "mappings": "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", "names": ["Participant", "isNullOrUndefined", "Lotto", "createLotto", "State", "createLotto"] } diff --git a/dist/index.js b/dist/index.js index 80a508d..6169c18 100644 --- a/dist/index.js +++ b/dist/index.js @@ -1960,7 +1960,18 @@ var While = class extends Guard { `cannot evaluate node guard as the condition '${this.getCondition()}' function is not defined on the agent and has not been registered` ); } - return !!conditionFuncInvoker(this.args); + let conditionFunctionResult; + try { + conditionFunctionResult = conditionFuncInvoker(this.args); + } catch (error) { + throw new Error(`guard condition function '${this.getCondition()}' threw '${error}'`); + } + if (typeof conditionFunctionResult !== "boolean") { + throw new Error( + `expected guard condition function '${this.getCondition()}' to return a boolean but returned '${conditionFunctionResult}'` + ); + } + return conditionFunctionResult; }; }; @@ -1976,7 +1987,18 @@ var Until = class extends Guard { `cannot evaluate node guard as the condition '${this.getCondition()}' function is not defined on the agent and has not been registered` ); } - return !!!conditionFuncInvoker(this.args); + let conditionFunctionResult; + try { + conditionFunctionResult = conditionFuncInvoker(this.args); + } catch (error) { + throw new Error(`guard condition function '${this.getCondition()}' threw '${error}'`); + } + if (typeof conditionFunctionResult !== "boolean") { + throw new Error( + `expected guard condition function '${this.getCondition()}' to return a boolean but returned '${conditionFunctionResult}'` + ); + } + return !conditionFunctionResult; }; }; diff --git a/dist/index.js.map b/dist/index.js.map index c80981e..f753e35 100644 --- a/dist/index.js.map +++ b/dist/index.js.map @@ -1,7 +1,7 @@ { "version": 3, "sources": ["../node_modules/lotto-draw/dist/Participant.js", "../node_modules/lotto-draw/dist/Utilities.js", "../node_modules/lotto-draw/dist/Lotto.js", "../node_modules/lotto-draw/dist/createLotto.js", "../node_modules/lotto-draw/dist/index.js", "../src/index.ts", "../src/State.ts", "../src/BehaviourTreeDefinitionUtilities.ts", "../src/mdsl/MDSLUtilities.ts", "../src/mdsl/MDSLNodeArgumentParser.ts", "../src/mdsl/MDSLNodeAttributeParser.ts", "../src/mdsl/MDSLDefinitionParser.ts", "../src/BehaviourTreeDefinitionValidator.ts", "../src/Lookup.ts", "../src/attributes/guards/GuardUnsatisifedException.ts", "../src/attributes/guards/GuardPath.ts", "../src/nodes/Node.ts", "../src/nodes/composite/Composite.ts", "../src/nodes/composite/Parallel.ts", "../src/nodes/composite/Selector.ts", "../src/nodes/composite/Sequence.ts", "../src/nodes/composite/Lotto.ts", "../src/nodes/decorator/Decorator.ts", "../src/nodes/decorator/Fail.ts", "../src/nodes/decorator/Flip.ts", "../src/nodes/decorator/Repeat.ts", "../src/nodes/decorator/Retry.ts", "../src/nodes/decorator/Root.ts", "../src/nodes/decorator/Succeed.ts", "../src/nodes/leaf/Leaf.ts", "../src/nodes/leaf/Action.ts", "../src/nodes/leaf/Condition.ts", "../src/nodes/leaf/Wait.ts", "../src/attributes/Attribute.ts", "../src/attributes/guards/Guard.ts", "../src/attributes/guards/While.ts", "../src/attributes/guards/Until.ts", "../src/attributes/callbacks/Callback.ts", "../src/attributes/callbacks/Entry.ts", "../src/attributes/callbacks/Step.ts", "../src/attributes/callbacks/Exit.ts", "../src/BehaviourTreeBuilder.ts", "../src/BehaviourTree.ts"], - "sourcesContent": ["\"use strict\";\r\nObject.defineProperty(exports, \"__esModule\", { value: true });\r\nexports.Participant = void 0;\r\n/**\r\n * A participant that holds a number of tickets.\r\n */\r\nvar Participant = /** @class */ (function () {\r\n /**\r\n * Creates an instance of the Participant class.\r\n * @param participant The actual participant.\r\n * @param tickets The number of tickets held by the participant.\r\n */\r\n function Participant(participant, tickets) {\r\n if (tickets === void 0) { tickets = 1; }\r\n this._participant = participant;\r\n this._tickets = tickets;\r\n }\r\n Object.defineProperty(Participant.prototype, \"participant\", {\r\n /** Gets the actual participant. */\r\n get: function () {\r\n return this._participant;\r\n },\r\n enumerable: false,\r\n configurable: true\r\n });\r\n Object.defineProperty(Participant.prototype, \"tickets\", {\r\n /** Gets or sets the number of tickets held by the participant. */\r\n get: function () {\r\n return this._tickets;\r\n },\r\n set: function (value) {\r\n this._tickets = value;\r\n },\r\n enumerable: false,\r\n configurable: true\r\n });\r\n return Participant;\r\n}());\r\nexports.Participant = Participant;\r\n", "\"use strict\";\r\nObject.defineProperty(exports, \"__esModule\", { value: true });\r\nexports.isNaturalNumber = exports.isNullOrUndefined = void 0;\r\n/**\r\n * Gets whether the value provided is null or undefined.\r\n * @param value The value to check.\r\n * @returns Whether the value provided is null or undefined.\r\n */\r\nfunction isNullOrUndefined(value) {\r\n return value === null || value === undefined;\r\n}\r\nexports.isNullOrUndefined = isNullOrUndefined;\r\n/**\r\n * Gets whether the value provided is a natural number.\r\n * @param value The value to check.\r\n * @returns Whether the value provided is a natural number.\r\n */\r\nfunction isNaturalNumber(value) {\r\n return typeof value === \"number\" && value >= 1 && Math.floor(value) === value;\r\n}\r\nexports.isNaturalNumber = isNaturalNumber;\r\n", "\"use strict\";\r\nObject.defineProperty(exports, \"__esModule\", { value: true });\r\nexports.Lotto = void 0;\r\nvar Participant_1 = require(\"./Participant\");\r\nvar Utilities_1 = require(\"./Utilities\");\r\n/**\r\n * Represents a lotto consisting of a number of pickable ticket-holding participants.\r\n */\r\nvar Lotto = /** @class */ (function () {\r\n /**\r\n * Creates a new instance of Lotto.\r\n * @param customRandom The custom RNG to use in place of Math.random().\r\n */\r\n function Lotto(customRandom) {\r\n /** The array of participants that are holding tickets in the lotto. */\r\n this._participants = [];\r\n this._customRandom = customRandom;\r\n }\r\n /**\r\n * Adds a participant with the specified number of tickets, or adds to the participant ticket count if the participant already holds tickets.\r\n * @param participant The participant to add or to increase the ticket count for if they already hold tickets.\r\n * @param tickets The number of tickets, defaults to 1.\r\n * @returns The Lotto instance.\r\n */\r\n Lotto.prototype.add = function (participant, tickets) {\r\n if (tickets === void 0) { tickets = 1; }\r\n // Check that we have a valid ticket count.\r\n if (!(0, Utilities_1.isNaturalNumber)(tickets)) {\r\n throw new Error(\"tickets value must be a natural number\");\r\n }\r\n // Check whether this participant has already been added.\r\n var existingParticipant = this._participants.find(function (part) { return part.participant === participant; });\r\n if (existingParticipant) {\r\n // The participant has already been added to the lotto so just add to their ticket count.\r\n existingParticipant.tickets += tickets;\r\n }\r\n else {\r\n // The participant is not part of the lotto so we should add them.\r\n this._participants.push(new Participant_1.Participant(participant, tickets));\r\n }\r\n return this;\r\n };\r\n /**\r\n * Removes the specified number of tickets for the given participant from the draw, or all tickets if a ticket number is not defined.\r\n * @param participant The participant to remove tickets for.\r\n * @param tickets The number of tickets to remove, or undefined if all tickets are to be removed.\r\n * @returns The Lotto instance.\r\n */\r\n Lotto.prototype.remove = function (participant, tickets) {\r\n // Attempt to get the existing participant.\r\n var existingParticipant = this._participants.find(function (part) { return part.participant === participant; });\r\n // There is nothing to do if the specified participant isn't even part of the lotto.\r\n if (!existingParticipant) {\r\n return this;\r\n }\r\n // Check whether a tickets value was given.\r\n if (tickets !== undefined) {\r\n // Check that we have a valid ticket count.\r\n if (!(0, Utilities_1.isNaturalNumber)(tickets)) {\r\n throw new Error(\"tickets value must be a natural number\");\r\n }\r\n existingParticipant.tickets -= tickets;\r\n // If the participant no longer holds any tickets then they should be removed.\r\n if (existingParticipant.tickets < 1) {\r\n this._participants = this._participants.filter(function (part) { return part !== existingParticipant; });\r\n }\r\n }\r\n else {\r\n // We are removing all tickets for the participant so just remove them from the lotto.\r\n this._participants = this._participants.filter(function (part) { return part !== existingParticipant; });\r\n }\r\n return this;\r\n };\r\n /**\r\n * Draw a winning ticket and return the participant that holds the ticket.\r\n * @param options The draw options.\r\n * @returns The participant that holds the winning ticket.\r\n */\r\n Lotto.prototype.draw = function (options) {\r\n if (options === void 0) { options = {}; }\r\n // If we have no participants then just return null.\r\n if (this._participants.length === 0) {\r\n return null;\r\n }\r\n var redrawable = (0, Utilities_1.isNullOrUndefined)(options.redrawable) ? true : options.redrawable;\r\n var pickable = [];\r\n this._participants.forEach(function (_a) {\r\n var participant = _a.participant, tickets = _a.tickets;\r\n for (var ticketCount = 0; ticketCount < tickets; ticketCount++) {\r\n pickable.push(participant);\r\n }\r\n });\r\n var random;\r\n // We need a random floating-point number between 0 (inclusive) and 1 to scale up to pick our winner.\r\n // If a custom random function exists then we should use that or fall back to Math.random().\r\n if (this._customRandom) {\r\n // Call our custom random function to get a random floating-point number.\r\n random = this._customRandom();\r\n // Verify that the result of calling our custom random function is a number between 0 (inclusive) and 1.\r\n if (typeof random !== \"number\" || random < 0 || random >= 1) {\r\n throw new Error(\"the 'random' function provided did not return a number between 0 (inclusive) and 1\");\r\n }\r\n }\r\n else {\r\n // No custom random function was defined so just use good ol' Math.random().\r\n random = Math.random();\r\n }\r\n // Pick a winning participant.\r\n var winner = pickable[Math.floor(random * pickable.length)];\r\n // If the ticket isn't redrawable then we should remove a ticket from the winning participants ticket count.\r\n if (!redrawable) {\r\n this.remove(winner, 1);\r\n }\r\n // Return the winning participant.\r\n return winner;\r\n };\r\n /**\r\n * Draws multiple winning tickets and return an array of the participants that hold the winning tickets.\r\n * @param tickets The number of winning tickets to draw.\r\n * @param options The draw multiple options.\r\n * @returns An array of the participants that hold the winning tickets.\r\n */\r\n Lotto.prototype.drawMultiple = function (tickets, options) {\r\n if (options === void 0) { options = {}; }\r\n var uniqueResults = (0, Utilities_1.isNullOrUndefined)(options.unique) ? false : options.unique;\r\n // Handle cases where the user has asked for zero tickets (no idea why they would do this be we should trust them).\r\n if (tickets === 0) {\r\n return [];\r\n }\r\n // Now that we know out tickets value is not zero we should check that it is a valid natural number.\r\n if (!(0, Utilities_1.isNaturalNumber)(tickets)) {\r\n throw new Error(\"tickets value must be a natural number\");\r\n }\r\n var result = [];\r\n // Keep drawing tickets until we either reach the number of required tickets or we simply run out of tickets to draw.\r\n // We can run out of tickets to draw if 'options.redrawable' is explicity 'false' or we just had no participants when 'drawMultiple' was called.\r\n while (result.length < tickets && this._participants.length > 0) {\r\n result.push(this.draw(options));\r\n }\r\n // If the 'unique' draw option is set then we need to remove duplicates from the result list.\r\n if (uniqueResults) {\r\n // Create an array to store our unique results.\r\n var unique = [];\r\n // Iterate over all of our participants (with potential duplicates) and populate our array of unique values.\r\n for (var _i = 0, result_1 = result; _i < result_1.length; _i++) {\r\n var participant = result_1[_i];\r\n if (unique.indexOf(participant) === -1) {\r\n unique.push(participant);\r\n }\r\n }\r\n result = unique;\r\n }\r\n return result;\r\n };\r\n return Lotto;\r\n}());\r\nexports.Lotto = Lotto;\r\n", "\"use strict\";\r\nObject.defineProperty(exports, \"__esModule\", { value: true });\r\nexports.createLotto = void 0;\r\nvar Lotto_1 = require(\"./Lotto\");\r\n/**\r\n * A function that creates and returns a Lotto instance.\r\n * @param participantsOrOptions An array of initial participants or options relating to the creation of a Lotto instance.\r\n * @returns A new Lotto instance.\r\n */\r\nfunction createLotto(participantsOrOptions) {\r\n // If no initial participants or lotto options were provided as an argument then we can just return a new lotto instance now.\r\n if (!participantsOrOptions) {\r\n return new Lotto_1.Lotto();\r\n }\r\n // Check whether we were provided with an array of initial participants or a lotto options object.\r\n if (Array.isArray(participantsOrOptions)) {\r\n // We are dealing with a pre-defined array of participants.\r\n var participants = participantsOrOptions;\r\n var lotto_1 = new Lotto_1.Lotto();\r\n // If the lotto participants have been defined upfront then we will need to add them all to our lotto instance now.\r\n participants.forEach(function (_a) {\r\n var participant = _a[0], tokens = _a[1];\r\n return lotto_1.add(participant, tokens);\r\n });\r\n // Return the Lotto instance.\r\n return lotto_1;\r\n }\r\n else {\r\n // We are dealing with some lotto options.\r\n var random = participantsOrOptions.random, participants = participantsOrOptions.participants;\r\n // Create a Lotto instance passing the custom RNG function to use in place of Math.random() (which could be undefined).\r\n var lotto_2 = new Lotto_1.Lotto(random);\r\n // If the lotto participants have been defined upfront as part of the options then we will need to add them all to our lotto instance now.\r\n if (participants) {\r\n participants.forEach(function (_a) {\r\n var participant = _a[0], tokens = _a[1];\r\n return lotto_2.add(participant, tokens);\r\n });\r\n }\r\n // Return the Lotto instance.\r\n return lotto_2;\r\n }\r\n}\r\nexports.createLotto = createLotto;\r\n", "\"use strict\";\r\nObject.defineProperty(exports, \"__esModule\", { value: true });\r\nvar createLotto_1 = require(\"./createLotto\");\r\nexports.default = createLotto_1.createLotto;\r\n", "import State from \"./State\";\nimport { validateDefinition } from \"./BehaviourTreeDefinitionValidator\";\nimport { convertMDSLToJSON } from \"./mdsl/MDSLDefinitionParser\";\nimport { BehaviourTree, FlattenedTreeNode } from \"./BehaviourTree\";\nimport { BehaviourTreeOptions } from \"./BehaviourTreeOptions\";\n\nexport { BehaviourTree, State, convertMDSLToJSON, validateDefinition };\nexport type { FlattenedTreeNode, BehaviourTreeOptions };\n", "/**\n * Enumeration of node state types.\n */\nexport enum State {\n READY = \"mistreevous.ready\",\n RUNNING = \"mistreevous.running\",\n SUCCEEDED = \"mistreevous.succeeded\",\n FAILED = \"mistreevous.failed\"\n}\n\nexport { State as default };\n\nexport type CompleteState = State.SUCCEEDED | State.FAILED;\nexport type AnyState = State.READY | State.RUNNING | CompleteState;\n", "import {\n NodeDefinition,\n RootNodeDefinition,\n DecoratorNodeDefinition,\n CompositeNodeDefinition,\n AnyNodeDefinition,\n BranchNodeDefinition\n} from \"./BehaviourTreeDefinition\";\n\n/**\n * A type guard function that returns true if the specified node satisfies the RootNodeDefinition type.\n * @param node The node.\n * @returns A value of true if the specified node satisfies the RootNodeDefinition type.\n */\nexport function isRootNode(node: NodeDefinition): node is RootNodeDefinition {\n return node.type === \"root\";\n}\n\n/**\n * A type guard function that returns true if the specified node satisfies the BranchNodeDefinition type.\n * @param node The node.\n * @returns A value of true if the specified node satisfies the BranchNodeDefinition type.\n */\nexport function isBranchNode(node: NodeDefinition): node is BranchNodeDefinition {\n return node.type === \"branch\";\n}\n\n/**\n * A type guard function that returns true if the specified node satisfies the NodeDefinition type.\n * @param node The node.\n * @returns A value of true if the specified node satisfies the NodeDefinition type.\n */\nexport function isLeafNode(node: NodeDefinition): node is NodeDefinition {\n return [\"branch\", \"action\", \"condition\", \"wait\"].includes(node.type);\n}\n\n/**\n * A type guard function that returns true if the specified node satisfies the DecoratorNodeDefinition type.\n * @param node The node.\n * @returns A value of true if the specified node satisfies the DecoratorNodeDefinition type.\n */\nexport function isDecoratorNode(node: NodeDefinition): node is DecoratorNodeDefinition {\n return [\"root\", \"repeat\", \"retry\", \"flip\", \"succeed\", \"fail\"].includes(node.type);\n}\n\n/**\n * A type guard function that returns true if the specified node satisfies the CompositeNodeDefinition type.\n * @param node The node.\n * @returns A value of true if the specified node satisfies the CompositeNodeDefinition type.\n */\nexport function isCompositeNode(node: NodeDefinition): node is CompositeNodeDefinition {\n return [\"sequence\", \"selector\", \"lotto\", \"parallel\"].includes(node.type);\n}\n\n/**\n * Flatten a node definition into an array of all of its nested node definitions.\n * @param nodeDefinition The node definition to flatten.\n * @returns An array of all of nested node definitions.\n */\nexport function flattenDefinition(nodeDefinition: AnyNodeDefinition): AnyNodeDefinition[] {\n const nodes: AnyNodeDefinition[] = [];\n\n const processNode = (currentNodeDefinition: AnyNodeDefinition) => {\n nodes.push(currentNodeDefinition);\n\n if (isCompositeNode(currentNodeDefinition)) {\n currentNodeDefinition.children.forEach(processNode);\n } else if (isDecoratorNode(currentNodeDefinition)) {\n processNode(currentNodeDefinition.child);\n }\n };\n\n processNode(nodeDefinition);\n\n return nodes;\n}\n\n/**\n * Determines whether the passed value is an integer.\n * @param value The value to check.\n * @returns Whether the passed value is an integer.\n */\nexport function isInteger(value: unknown): boolean {\n return typeof value === \"number\" && Math.floor(value) === value;\n}\n\n/**\n * Determines whether the passed value is null or undefined.\n * @param value The value to check.\n * @returns Whether the passed value is null or undefined.\n */\nexport function isNullOrUndefined(value: unknown): boolean {\n return typeof value === \"undefined\" || value === null;\n}\n", "/**\n * A type defining an object that holds a reference to substitued string literals parsed from the definition.\n */\nexport type StringLiteralPlaceholders = { [key: string]: string };\n\n/**\n * Pop the next raw token from the specified array of tokens and throw an error if it wasn't the expected one.\n * @param tokens The array of tokens.\n * @param expected An optional string or array or items, one of which must match the next popped token.\n * @returns The popped token.\n */\nexport function popAndCheck(tokens: string[], expected?: string | string[]): string {\n // Get and remove the next token.\n const popped = tokens.shift();\n\n // We were expecting another token but there aren't any.\n if (popped === undefined) {\n throw new Error(\"unexpected end of definition\");\n }\n\n // Do we have an expected token/tokens array?\n if (expected != undefined) {\n // Get an array of expected values, if the popped token matches any then we are all good.\n const expectedValues = typeof expected === \"string\" ? [expected] : expected;\n\n // Check whether the popped token matches at least one of our expected items.\n var tokenMatchesExpectation = expectedValues.some((item) => popped.toUpperCase() === item.toUpperCase());\n\n // Throw an error if the popped token didn't match any of our expected items.\n if (!tokenMatchesExpectation) {\n const expectationString = expectedValues.map((item) => \"'\" + item + \"'\").join(\" or \");\n throw new Error(\"unexpected token found. Expected \" + expectationString + \" but got '\" + popped + \"'\");\n }\n }\n\n // Return the popped token.\n return popped;\n}\n\n/**\n * Swaps out any node/attribute argument string literals with placeholders.\n * @param definition The definition.\n * @returns An object containing a mapping of placeholders to original string values as well as the processed definition string.\n */\nexport function substituteStringLiterals(definition: string): {\n placeholders: StringLiteralPlaceholders;\n processedDefinition: string;\n} {\n // Create an object to hold the mapping of placeholders to original string values.\n const placeholders: StringLiteralPlaceholders = {};\n\n // Replace any string literals wrapped with double quotes in our definition with placeholders to be processed later.\n const processedDefinition = definition.replace(/\\\"(\\\\.|[^\"\\\\])*\\\"/g, (match) => {\n var strippedMatch = match.substring(1, match.length - 1);\n var placeholder = Object.keys(placeholders).find((key) => placeholders[key] === strippedMatch);\n\n // If we have no existing string literal match then create a new placeholder.\n if (!placeholder) {\n placeholder = `@@${Object.keys(placeholders).length}@@`;\n placeholders[placeholder] = strippedMatch;\n }\n\n return placeholder;\n });\n\n return { placeholders, processedDefinition };\n}\n\n/**\n * Parse the tree definition into an array of raw tokens.\n * @param definition The definition.\n * @returns An array of tokens parsed from the definition.\n */\nexport function parseTokensFromDefinition(definition: string): string[] {\n // Add some space around various important characters so that they can be plucked out easier as individual tokens.\n definition = definition.replace(/\\(/g, \" ( \");\n definition = definition.replace(/\\)/g, \" ) \");\n definition = definition.replace(/\\{/g, \" { \");\n definition = definition.replace(/\\}/g, \" } \");\n definition = definition.replace(/\\]/g, \" ] \");\n definition = definition.replace(/\\[/g, \" [ \");\n definition = definition.replace(/\\,/g, \" , \");\n\n // Split the definition into raw token form and return it.\n return definition.replace(/\\s+/g, \" \").trim().split(\" \");\n}\n", "import { StringLiteralPlaceholders, popAndCheck } from \"./MDSLUtilities\";\n\n/**\n * A type representing any node function argument.\n */\ntype Argument = {\n /**\n * The argument value.\n */\n value: T;\n /**\n * The argument type, used for validation.\n */\n type: string;\n};\n\ntype NullArgument = Argument & {\n type: \"null\";\n};\n\ntype BooleanArgument = Argument & {\n type: \"boolean\";\n};\n\ntype NumberArgument = Argument & {\n type: \"number\";\n /**\n * A flag defining whether the number argument value is a valid integer. (used for validation)\n */\n isInteger: boolean;\n};\n\ntype StringPlaceholderArgument = Argument & {\n type: \"string\";\n};\n\ntype IdentifierArgument = Argument & {\n type: \"identifier\";\n};\n\n/**\n * A type representing a reference to any node function argument.\n */\ntype AnyArgument = NullArgument | BooleanArgument | NumberArgument | StringPlaceholderArgument | IdentifierArgument;\n\n/**\n * Parse an array of argument definitions from the specified tokens array.\n * @param tokens The array tokens to parse the argument definitions from.\n * @param stringArgumentPlaceholders The mapping of string literal node argument placeholders to original values.\n * @param argumentValidator The argument validator function.\n * @param validationFailedMessage The exception message to throw if argument validation fails.\n * @returns An array of argument definitions parsed from the specified tokens array.\n */\nexport function parseArgumentTokens(\n tokens: string[],\n stringArgumentPlaceholders: StringLiteralPlaceholders\n): AnyArgument[] {\n const argumentList: AnyArgument[] = [];\n\n // If the next token is not a '[' or '(' then we have no arguments to parse.\n if (![\"[\", \"(\"].includes(tokens[0])) {\n return argumentList;\n }\n\n // Any lists of arguments will always be wrapped in '[]' for node arguments or '()' for attribute arguments.\n // We are looking for a '[' or '(' opener that wraps the argument tokens and the relevant closer.\n const closingToken = popAndCheck(tokens, [\"[\", \"(\"]) === \"[\" ? \"]\" : \")\";\n\n const argumentListTokens: string[] = [];\n\n // Grab all tokens between the '[' and ']' or '(' and ')'.\n while (tokens.length && tokens[0] !== closingToken) {\n // The next token is part of our arguments list.\n argumentListTokens.push(tokens.shift()!);\n }\n\n // Validate the order of the argument tokens. Each token must either be a ',' or a single argument that satisfies the validator.\n argumentListTokens.forEach((token, index) => {\n // Get whether this token should be an actual argument.\n const shouldBeArgumentToken = !(index & 1);\n\n // If the current token should be an actual argument then validate it, otherwise it should be a ',' token.\n if (shouldBeArgumentToken) {\n // Get the argument definition.\n const argumentDefinition = getArgumentDefinition(token, stringArgumentPlaceholders);\n\n // This is a valid argument!\n argumentList.push(argumentDefinition);\n } else {\n // The current token should be a ',' token.\n if (token !== \",\") {\n throw new Error(`invalid argument list, expected ',' or ']' but got '${token}'`);\n }\n }\n });\n\n // The arguments list should terminate with a ']' or ')' token, depending on the opener.\n popAndCheck(tokens, closingToken);\n\n // Return the arguments.\n return argumentList;\n}\n\n/**\n * Gets an argument value definition.\n * @param token The argument token.\n * @param stringArgumentPlaceholders The mapping of string literal node argument placeholders to original values.\n * @returns An argument value definition.\n */\nfunction getArgumentDefinition(token: string, stringArgumentPlaceholders: StringLiteralPlaceholders): AnyArgument {\n // Check whether the token represents a null value.\n if (token === \"null\") {\n return {\n value: null,\n type: \"null\"\n } as NullArgument;\n }\n\n // Check whether the token represents a boolean value.\n if (token === \"true\" || token === \"false\") {\n return {\n value: token === \"true\",\n type: \"boolean\"\n } as BooleanArgument;\n }\n\n // Check whether the token represents a number value.\n // TODO: Relies on broken isNaN - see MDN.\n // if (!Number.isNaN(token)) {\n if (!isNaN(token as any)) {\n return {\n value: parseFloat(token),\n isInteger: parseFloat(token) === parseInt(token, 10),\n type: \"number\"\n } as NumberArgument;\n }\n\n // Check whether the token is a placeholder (e.g. @@0@@) representing a string literal.\n if (token.match(/^@@\\d+@@$/g)) {\n return {\n value: stringArgumentPlaceholders[token].replace('\\\\\"', '\"'),\n type: \"string\"\n } as StringPlaceholderArgument;\n }\n\n // The only remaining option is that the argument value is an identifier.\n return {\n value: token,\n type: \"identifier\"\n } as IdentifierArgument;\n}\n", "import { NodeAttributeDefinition } from \"../BehaviourTreeDefinition\";\nimport { parseArgumentTokens } from \"./MDSLNodeArgumentParser\";\nimport { StringLiteralPlaceholders } from \"./MDSLUtilities\";\n\n/**\n * A type defining the attribute definitions of a node.\n */\ntype NodeAttributes = {\n while?: NodeAttributeDefinition;\n until?: NodeAttributeDefinition;\n entry?: NodeAttributeDefinition;\n exit?: NodeAttributeDefinition;\n step?: NodeAttributeDefinition;\n};\n\n/**\n * Parse any node attribute definitions from the specified tokens array.\n * @param tokens The array of remaining tokens.\n * @param stringArgumentPlaceholders The mapping of string literal node argument placeholders to original values.\n * @returns An object of attribute definitions defined by any directly following tokens.\n */\nexport function parseAttributeTokens(\n tokens: string[],\n stringArgumentPlaceholders: StringLiteralPlaceholders\n): NodeAttributes {\n const nodeAttributeNames: (keyof NodeAttributes)[] = [\"while\", \"until\", \"entry\", \"exit\", \"step\"];\n\n // Create an object to hold any attributes found.\n const attributes: NodeAttributes = {};\n\n // Try to get the name of the attribute for the next token.\n let nextAttributeName = tokens[0]?.toLowerCase() as keyof NodeAttributes;\n\n // Pull attribute tokens as well as their arguments off of the tokens stack until we have no more.\n while (nodeAttributeNames.includes(nextAttributeName)) {\n // Check to make sure that we have not already created an attribute definition of this type.\n if (attributes[nextAttributeName]) {\n throw new Error(`duplicate attribute '${tokens[0].toUpperCase()}' found for node`);\n }\n\n // Remove the attribute name token from the array of tokens.\n tokens.shift();\n\n // Grab the attribute arguments, assuming the first to be an identifier.\n const [attributeCallIdentifier, ...attributeArguments] = parseArgumentTokens(\n tokens,\n stringArgumentPlaceholders\n );\n\n // The first attribute argument has to be an identifer, this will reference an agent function.\n if (attributeCallIdentifier?.type !== \"identifier\") {\n throw new Error(\"expected agent function or registered function name identifier argument for attribute\");\n }\n\n // Any attribute arguments (other than the expected call identifier) must have a type of string, number, boolean or null.\n attributeArguments\n .filter((arg) => arg.type === \"identifier\")\n .forEach((arg) => {\n throw new Error(\n `invalid attribute argument value '${arg.value}', must be string, number, boolean or null`\n );\n });\n\n // Create the attribute definition and add it to the object of attribute definitions found.\n attributes[nextAttributeName] = {\n call: attributeCallIdentifier.value,\n args: attributeArguments.map(({ value }) => value)\n };\n\n // Try to get the next attribute name token, as there could be multiple.\n nextAttributeName = tokens[0]?.toLowerCase() as keyof NodeAttributes;\n }\n\n return attributes;\n}\n", "import {\n ActionNodeDefinition,\n AnyChildNodeDefinition,\n AnyNodeDefinition,\n BranchNodeDefinition,\n ConditionNodeDefinition,\n FailNodeDefinition,\n FlipNodeDefinition,\n LottoNodeDefinition,\n ParallelNodeDefinition,\n RepeatNodeDefinition,\n RetryNodeDefinition,\n RootNodeDefinition,\n SelectorNodeDefinition,\n SequenceNodeDefinition,\n SucceedNodeDefinition,\n WaitNodeDefinition\n} from \"../BehaviourTreeDefinition\";\nimport {\n isCompositeNode,\n isDecoratorNode,\n isLeafNode,\n isNullOrUndefined,\n isRootNode\n} from \"../BehaviourTreeDefinitionUtilities\";\nimport { parseArgumentTokens } from \"./MDSLNodeArgumentParser\";\nimport { parseAttributeTokens } from \"./MDSLNodeAttributeParser\";\nimport {\n StringLiteralPlaceholders,\n parseTokensFromDefinition,\n popAndCheck,\n substituteStringLiterals\n} from \"./MDSLUtilities\";\n\n/**\n * Convert the MDSL tree definition string into an equivalent JSON definition.\n * @param definition The tree definition string as MDSL.\n * @returns The root node JSON definitions.\n */\nexport function convertMDSLToJSON(definition: string): RootNodeDefinition[] {\n // Swap out any node/attribute argument string literals with a placeholder and get a mapping of placeholders to original values as well as the processed definition.\n const { placeholders, processedDefinition } = substituteStringLiterals(definition);\n\n // Parse our definition definition string into an array of raw tokens.\n const tokens = parseTokensFromDefinition(processedDefinition);\n\n return convertTokensToJSONDefinition(tokens, placeholders);\n}\n\n/**\n * Converts the specified tree definition tokens into a JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The root node JSON definitions.\n */\nfunction convertTokensToJSONDefinition(\n tokens: string[],\n stringLiteralPlaceholders: StringLiteralPlaceholders\n): RootNodeDefinition[] {\n // There must be at least 3 tokens for the tree definition to be valid. 'ROOT', '{' and '}'.\n if (tokens.length < 3) {\n throw new Error(\"invalid token count\");\n }\n\n // We should have a matching number of '{' and '}' tokens. If not, then there are scopes that have not been properly closed.\n if (tokens.filter((token) => token === \"{\").length !== tokens.filter((token) => token === \"}\").length) {\n throw new Error(\"scope character mismatch\");\n }\n\n // Create an array of tree stack arrays where root nodes will always be at the botton and the current composite/decorator node at the top.\n // There should be an element in this array for every root node defined and every element should be an array with a root note as the first element.\n // E.g. A definition with two root nodes defined:\n // [\n // [root, lotto, sequence],\n // [root, selector]\n // ]\n const treeStacks: [Partial, ...Partial[]][] = [];\n\n // Create an array of all root node definitions that we create.\n const rootNodes: Partial[] = [];\n\n // A helper function used to push node definitions onto the tree stack.\n const pushNode = (node: AnyNodeDefinition) => {\n // If the node is a root node then we need to create a new tree stack array with the root node at the root.\n if (isRootNode(node)) {\n // We need to double-check that this root node is not the child of another node.\n // We can do this by checking whether the top tree stack is not empty (contains an existing node)\n if (treeStacks[treeStacks.length - 1]?.length) {\n throw new Error(\"a root node cannot be the child of another node\");\n }\n\n // Add the root node definition to our array of all parsed root node definitions.\n rootNodes.push(node);\n\n // Add the root node definition to the root of a new tree stack.\n treeStacks.push([node]);\n\n return;\n }\n\n // All non-root nodes should be pushed after their root nodes so handle cases\n // where we may not have any tree stacks or our top-most tree stack is empty.\n if (!treeStacks.length || !treeStacks[treeStacks.length - 1].length) {\n throw new Error(\"expected root node at base of definition\");\n }\n\n // Get the current tree stack that we are populating.\n const topTreeStack = treeStacks[treeStacks.length - 1];\n\n // Get the top-most node in the current tree stack, this will be a composite/decorator node\n // for which we will populate its children array if composite or setting its child if a decorator.\n const topTreeStackTopNode = topTreeStack[topTreeStack.length - 1] as AnyNodeDefinition;\n\n // If the top-most node in the current root stack is a composite or decorator\n // node then the current node should be added as a child of the top-most node.\n if (isCompositeNode(topTreeStackTopNode)) {\n topTreeStackTopNode.children = topTreeStackTopNode.children || [];\n topTreeStackTopNode.children.push(node);\n } else if (isDecoratorNode(topTreeStackTopNode)) {\n // If the top node already has a child node set then throw an error as a decorator should only have a single child.\n if (topTreeStackTopNode.child) {\n throw new Error(\"a decorator node must only have a single child node\");\n }\n\n topTreeStackTopNode.child = node;\n }\n\n // If the node we are adding is also a composite or decorator node, then we should push it\n // onto the current tree stack, as subsequent nodes will be added as its child/children.\n if (!isLeafNode(node)) {\n topTreeStack.push(node);\n }\n };\n\n // A helper function used to pop the top-most node definition off of the tree stack and return it.\n const popNode = (): AnyNodeDefinition | null => {\n let poppedNode: AnyNodeDefinition | null = null;\n\n // Get the current tree stack that we are populating.\n const topTreeStack = treeStacks[treeStacks.length - 1];\n\n // Pop the top-most node in the current tree stack if there is one.\n if (topTreeStack.length) {\n poppedNode = topTreeStack.pop() as AnyNodeDefinition;\n }\n\n // We don't want any empty tree stacks in our stack of tree stacks.\n if (!topTreeStack.length) {\n treeStacks.pop();\n }\n\n return poppedNode;\n };\n\n // We should keep processing the raw tokens until we run out of them.\n while (tokens.length) {\n // Grab the next token.\n const token = tokens.shift()!;\n\n // How we create the next node depends on the current raw token value.\n switch (token.toUpperCase()) {\n case \"ROOT\": {\n pushNode(createRootNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"SUCCEED\": {\n pushNode(createSucceedNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"FAIL\": {\n pushNode(createFailNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"FLIP\": {\n pushNode(createFlipNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"REPEAT\": {\n pushNode(createRepeatNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"RETRY\": {\n pushNode(createRetryNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"SEQUENCE\": {\n pushNode(createSequenceNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"SELECTOR\": {\n pushNode(createSelectorNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"PARALLEL\": {\n pushNode(createParallelNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"LOTTO\": {\n pushNode(createLottoNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"ACTION\": {\n pushNode(createActionNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"CONDITION\": {\n pushNode(createConditionNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"WAIT\": {\n pushNode(createWaitNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"BRANCH\": {\n pushNode(createBranchNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"}\": {\n // The '}' character closes the current scope and means that we have to pop a node off of the current stack.\n const poppedNode = popNode();\n\n // Now that we have a node definition we can carry out any validation that may require the node to be fully populated.\n if (poppedNode) {\n validatePoppedNode(poppedNode);\n }\n\n break;\n }\n\n default: {\n throw new Error(`unexpected token: ${token}`);\n }\n }\n }\n\n return rootNodes as RootNodeDefinition[];\n}\n\n/**\n * Creates a root node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The root node JSON definition.\n */\nfunction createRootNode(tokens: string[], stringLiteralPlaceholders: StringLiteralPlaceholders): RootNodeDefinition {\n // Create the root node definition.\n let node = {\n type: \"root\"\n } as Partial;\n\n // Parse any node arguments, we should only have one if any which will be an identifier argument for the root identifier.\n const nodeArguments = parseArgumentTokens(tokens, stringLiteralPlaceholders);\n\n // Check whether any node arguments were defined.\n if (nodeArguments.length) {\n // We should only have one argument, if any, which will be an identifier argument for the root identifier.\n if (nodeArguments.length === 1 && nodeArguments[0].type === \"identifier\") {\n // The root node identifier will be the first and only node argument value.\n node.id = nodeArguments[0].value as string;\n } else {\n throw new Error(\"expected single root name argument\");\n }\n }\n\n // Grab any node attribute definitions and spread them into the node definition.\n node = { ...node, ...parseAttributeTokens(tokens, stringLiteralPlaceholders) };\n\n // This is a decorator node, so we expect an opening '{'.\n popAndCheck(tokens, \"{\");\n\n // Return the root node definition.\n return node as RootNodeDefinition;\n}\n\n/**\n * Creates a succeed node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The succeed node JSON definition.\n */\nfunction createSucceedNode(\n tokens: string[],\n stringLiteralPlaceholders: StringLiteralPlaceholders\n): SucceedNodeDefinition {\n const node = {\n type: \"succeed\",\n ...parseAttributeTokens(tokens, stringLiteralPlaceholders)\n } as SucceedNodeDefinition;\n\n // This is a decorator node, so we expect an opening '{'.\n popAndCheck(tokens, \"{\");\n\n // Return the succeed node definition.\n return node;\n}\n\n/**\n * Creates a fail node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The fail node JSON definition.\n */\nfunction createFailNode(tokens: string[], stringLiteralPlaceholders: StringLiteralPlaceholders): FailNodeDefinition {\n const node = {\n type: \"fail\",\n ...parseAttributeTokens(tokens, stringLiteralPlaceholders)\n } as FailNodeDefinition;\n\n // This is a decorator node, so we expect an opening '{'.\n popAndCheck(tokens, \"{\");\n\n // Return the fail node definition.\n return node;\n}\n\n/**\n * Creates a flip node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The flip node JSON definition.\n */\nfunction createFlipNode(tokens: string[], stringLiteralPlaceholders: StringLiteralPlaceholders): FlipNodeDefinition {\n const node = {\n type: \"flip\",\n ...parseAttributeTokens(tokens, stringLiteralPlaceholders)\n } as FlipNodeDefinition;\n\n // This is a decorator node, so we expect an opening '{'.\n popAndCheck(tokens, \"{\");\n\n // Return the flip node definition.\n return node;\n}\n\n/**\n * Creates a repeat node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The repeat node JSON definition.\n */\nfunction createRepeatNode(\n tokens: string[],\n stringLiteralPlaceholders: StringLiteralPlaceholders\n): RepeatNodeDefinition {\n let node = { type: \"repeat\" } as RepeatNodeDefinition;\n\n // Get the node arguments.\n const nodeArguments = parseArgumentTokens(tokens, stringLiteralPlaceholders);\n\n // The arguments of a repeat node are optional. We may have:\n // - No node arguments, in which case the repeat note will iterate indefinitely.\n // - One node argument which will be the explicit number of iterations to make.\n // - Two node arguments which define the min and max iteration bounds from which a random iteration count will be picked.\n if (nodeArguments.length) {\n // All repeat node arguments MUST be of type number and must be integer.\n nodeArguments\n .filter((arg) => arg.type !== \"number\" || !arg.isInteger)\n .forEach(() => {\n throw new Error(`repeat node iteration counts must be integer values`);\n });\n\n // We should have got one or two iteration counts.\n if (nodeArguments.length === 1) {\n // A static iteration count was defined.\n node.iterations = nodeArguments[0].value as number;\n\n // A repeat node must have a positive number of iterations if defined.\n if (node.iterations < 0) {\n throw new Error(\"a repeat node must have a positive number of iterations if defined\");\n }\n } else if (nodeArguments.length === 2) {\n // A minimum and maximum iteration count was defined.\n node.iterations = [nodeArguments[0].value as number, nodeArguments[1].value as number];\n\n // A repeat node must have a positive min and max iteration count if they are defined.\n if (node.iterations[0] < 0 || node.iterations[1] < 0) {\n throw new Error(\"a repeat node must have a positive minimum and maximum iteration count if defined\");\n }\n\n // A repeat node must not have an minimum iteration count that exceeds the maximum iteration count.\n if (node.iterations[0] > node.iterations[1]) {\n throw new Error(\n \"a repeat node must not have a minimum iteration count that exceeds the maximum iteration count\"\n );\n }\n } else {\n // An incorrect number of iteration counts was defined.\n throw new Error(\"invalid number of repeat node iteration count arguments defined\");\n }\n }\n\n // Grab any node attribute definitions and spread them into the node definition.\n node = { ...node, ...parseAttributeTokens(tokens, stringLiteralPlaceholders) };\n\n // This is a decorator node, so we expect an opening '{'.\n popAndCheck(tokens, \"{\");\n\n // Return the repeat node definition.\n return node;\n}\n\n/**\n * Creates a retry node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The retry node JSON definition.\n */\nfunction createRetryNode(tokens: string[], stringLiteralPlaceholders: StringLiteralPlaceholders): RetryNodeDefinition {\n let node = { type: \"retry\" } as RetryNodeDefinition;\n\n // Get the node arguments.\n const nodeArguments = parseArgumentTokens(tokens, stringLiteralPlaceholders);\n\n // The arguments of a retry node are optional. We may have:\n // - No node arguments, in which case the retry note will attempt indefinitely.\n // - One node argument which will be the explicit number of attempts to make.\n // - Two node arguments which define the min and max attempt bounds from which a random attempt count will be picked.\n if (nodeArguments.length) {\n // All retry node arguments MUST be of type number and must be integer.\n nodeArguments\n .filter((arg) => arg.type !== \"number\" || !arg.isInteger)\n .forEach(() => {\n throw new Error(`retry node attempt counts must be integer values`);\n });\n\n // We should have got one or two attempt counts.\n if (nodeArguments.length === 1) {\n // A static attempt count was defined.\n node.attempts = nodeArguments[0].value as number;\n\n // A retry node must have a positive number of attempts if defined.\n if (node.attempts < 0) {\n throw new Error(\"a retry node must have a positive number of attempts if defined\");\n }\n } else if (nodeArguments.length === 2) {\n // A minimum and maximum attempt count was defined.\n node.attempts = [nodeArguments[0].value as number, nodeArguments[1].value as number];\n\n // A retry node must have a positive min and max attempts count if they are defined.\n if (node.attempts[0] < 0 || node.attempts[1] < 0) {\n throw new Error(\"a retry node must have a positive minimum and maximum attempt count if defined\");\n }\n\n // A retry node must not have a minimum attempt count that exceeds the maximum attempt count.\n if (node.attempts[0] > node.attempts[1]) {\n throw new Error(\n \"a retry node must not have a minimum attempt count that exceeds the maximum attempt count\"\n );\n }\n } else {\n // An incorrect number of attempt counts was defined.\n throw new Error(\"invalid number of retry node attempt count arguments defined\");\n }\n }\n\n // Grab any node attribute definitions and spread them into the node definition.\n node = { ...node, ...parseAttributeTokens(tokens, stringLiteralPlaceholders) };\n\n // This is a decorator node, so we expect an opening '{'.\n popAndCheck(tokens, \"{\");\n\n // Return the retry node definition.\n return node;\n}\n\n/**\n * Creates a sequence node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The sequence node JSON definition.\n */\nfunction createSequenceNode(\n tokens: string[],\n stringLiteralPlaceholders: StringLiteralPlaceholders\n): SequenceNodeDefinition {\n const node = {\n type: \"sequence\",\n ...parseAttributeTokens(tokens, stringLiteralPlaceholders)\n } as SequenceNodeDefinition;\n\n // This is a composite node, so we expect an opening '{'.\n popAndCheck(tokens, \"{\");\n\n // Return the sequence node definition.\n return node;\n}\n\n/**\n * Creates a selector node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The selector node JSON definition.\n */\nfunction createSelectorNode(\n tokens: string[],\n stringLiteralPlaceholders: StringLiteralPlaceholders\n): SelectorNodeDefinition {\n const node = {\n type: \"selector\",\n ...parseAttributeTokens(tokens, stringLiteralPlaceholders)\n } as SelectorNodeDefinition;\n\n // This is a composite node, so we expect an opening '{'.\n popAndCheck(tokens, \"{\");\n\n // Return the selector node definition.\n return node;\n}\n\n/**\n * Creates a parallel node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The parallel node JSON definition.\n */\nfunction createParallelNode(\n tokens: string[],\n stringLiteralPlaceholders: StringLiteralPlaceholders\n): ParallelNodeDefinition {\n const node = {\n type: \"parallel\",\n ...parseAttributeTokens(tokens, stringLiteralPlaceholders)\n } as ParallelNodeDefinition;\n\n // This is a composite node, so we expect an opening '{'.\n popAndCheck(tokens, \"{\");\n\n // Return the parallel node definition.\n return node;\n}\n\n/**\n * Creates a lotto node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The lotto node JSON definition.\n */\nfunction createLottoNode(tokens: string[], stringLiteralPlaceholders: StringLiteralPlaceholders): LottoNodeDefinition {\n // If any node arguments have been defined then they must be our weights.\n const nodeArguments = parseArgumentTokens(tokens, stringLiteralPlaceholders);\n\n // All lotto node arguments MUST be of type number and must be positive integers.\n nodeArguments\n .filter((arg) => arg.type !== \"number\" || !arg.isInteger || arg.value < 0)\n .forEach(() => {\n throw new Error(`lotto node weight arguments must be positive integer values`);\n });\n\n const node = {\n type: \"lotto\",\n ...parseAttributeTokens(tokens, stringLiteralPlaceholders)\n } as LottoNodeDefinition;\n\n // Apply the weights if any were defined.\n if (nodeArguments.length) {\n node.weights = nodeArguments.map(({ value }) => value) as number[];\n }\n\n // This is a composite node, so we expect an opening '{'.\n popAndCheck(tokens, \"{\");\n\n // Return the lotto node definition.\n return node;\n}\n\n/**\n * Creates an action node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The action node JSON definition.\n */\nfunction createActionNode(\n tokens: string[],\n stringLiteralPlaceholders: StringLiteralPlaceholders\n): ActionNodeDefinition {\n // Parse any node arguments, we should have at least one which will be an identifier argument for the action name\n // and agent function to invoke for the action, all other arguments are to be passed as arguments to that function.\n const [actionNameIdentifier, ...agentFunctionArgs] = parseArgumentTokens(tokens, stringLiteralPlaceholders);\n\n // Our first argument MUST be defined and be an identifier as we require an action name argument.\n if (actionNameIdentifier?.type !== \"identifier\") {\n throw new Error(\"expected action name identifier argument\");\n }\n\n // Only the first argument should have been an identifier, all agent function arguments must be string, number, boolean or null.\n agentFunctionArgs\n .filter((arg) => arg.type === \"identifier\")\n .forEach((arg) => {\n throw new Error(\n `invalid action node argument value '${arg.value}', must be string, number, boolean or null`\n );\n });\n\n // Return the action node definition.\n return {\n type: \"action\",\n call: actionNameIdentifier.value,\n args: agentFunctionArgs.map(({ value }) => value),\n ...parseAttributeTokens(tokens, stringLiteralPlaceholders)\n };\n}\n\n/**\n * Creates a condition node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The condition node JSON definition.\n */\nfunction createConditionNode(\n tokens: string[],\n stringLiteralPlaceholders: StringLiteralPlaceholders\n): ConditionNodeDefinition {\n // Parse any node arguments, we should have at least one which will be an identifier argument for the condition name\n // and agent function to invoke for the condition, all other arguments are to be passed as arguments to that function.\n const [conditionNameIdentifier, ...agentFunctionArgs] = parseArgumentTokens(tokens, stringLiteralPlaceholders);\n\n // Our first argument MUST be defined and be an identifier as we require a condition name argument.\n if (conditionNameIdentifier?.type !== \"identifier\") {\n throw new Error(\"expected condition name identifier argument\");\n }\n\n // Only the first argument should have been an identifier, all agent function arguments must be string, number, boolean or null.\n agentFunctionArgs\n .filter((arg) => arg.type === \"identifier\")\n .forEach((arg) => {\n throw new Error(\n `invalid condition node argument value '${arg.value}', must be string, number, boolean or null`\n );\n });\n\n // Return the condition node definition.\n return {\n type: \"condition\",\n call: conditionNameIdentifier.value,\n args: agentFunctionArgs.map(({ value }) => value),\n ...parseAttributeTokens(tokens, stringLiteralPlaceholders)\n };\n}\n\n/**\n * Creates a wait node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The wait node JSON definition.\n */\nfunction createWaitNode(tokens: string[], stringLiteralPlaceholders: StringLiteralPlaceholders): WaitNodeDefinition {\n let node = { type: \"wait\" } as WaitNodeDefinition;\n\n // Get the node arguments.\n const nodeArguments = parseArgumentTokens(tokens, stringLiteralPlaceholders);\n\n // The arguments of a wait node are optional. We may have:\n // - No node arguments, in which case the wait will be indefinite until it is aborted.\n // - One node argument which will be the explicit duration of the wait.\n // - Two node arguments which define the min and max duration bounds from which a random duration will be picked.\n if (nodeArguments.length) {\n // All wait node arguments MUST be of type number and must be integer.\n nodeArguments\n .filter((arg) => arg.type !== \"number\" || !arg.isInteger)\n .forEach(() => {\n throw new Error(`wait node durations must be integer values`);\n });\n\n // We may have:\n // - One node argument which will be the explicit duration of the wait.\n // - Two node arguments which define the min and max duration bounds from which a random duration will be picked.\n // - Too many arguments, which is not valid.\n if (nodeArguments.length === 1) {\n // An explicit duration was defined.\n node.duration = nodeArguments[0].value as number;\n\n // If an explict duration was defined then it must be a positive number.\n if (node.duration < 0) {\n throw new Error(\"a wait node must have a positive duration\");\n }\n } else if (nodeArguments.length === 2) {\n // Min and max duration bounds were defined from which a random duration will be picked.\n node.duration = [nodeArguments[0].value as number, nodeArguments[1].value as number];\n\n // A wait node must have a positive min and max duration.\n if (node.duration[0] < 0 || node.duration[1] < 0) {\n throw new Error(\"a wait node must have a positive minimum and maximum duration\");\n }\n\n // A wait node must not have a minimum duration that exceeds the maximum duration.\n if (node.duration[0] > node.duration[1]) {\n throw new Error(\"a wait node must not have a minimum duration that exceeds the maximum duration\");\n }\n } else if (nodeArguments.length > 2) {\n // An incorrect number of duration arguments were defined.\n throw new Error(\"invalid number of wait node duration arguments defined\");\n }\n }\n\n // Return the wait node definition.\n return { ...node, ...parseAttributeTokens(tokens, stringLiteralPlaceholders) };\n}\n\n/**\n * Creates a branch node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The branch node JSON definition.\n */\nfunction createBranchNode(\n tokens: string[],\n stringLiteralPlaceholders: StringLiteralPlaceholders\n): BranchNodeDefinition {\n // Parse any node arguments, we should have one which will be an identifier argument for the root ref.\n const nodeArguments = parseArgumentTokens(tokens, stringLiteralPlaceholders);\n\n // We should have only a single identifer argument for a branch node, which is the root ref.\n if (nodeArguments.length !== 1 || nodeArguments[0].type !== \"identifier\") {\n throw new Error(\"expected single branch name argument\");\n }\n\n // Return the branch node definition.\n return { type: \"branch\", ref: nodeArguments[0].value };\n}\n\n/**\n * Validate a fully-populated node definition that was popped off of the tree stack.\n * @param definition The popped node to validate.\n */\nfunction validatePoppedNode(definition: AnyNodeDefinition): void {\n // Decorators MUST have a child defined.\n if (isDecoratorNode(definition) && isNullOrUndefined(definition.child)) {\n throw new Error(`a ${definition.type} node must have a single child node defined`);\n }\n\n // Composites MUST have at least one child defined.\n if (isCompositeNode(definition) && !definition.children?.length) {\n throw new Error(`a ${definition.type} node must have at least a single child node defined`);\n }\n\n // We need to make sure that lotto nodes that have weights defined have a number of weights matching the number of child nodes.\n if (definition.type === \"lotto\") {\n // Check whether a 'weights' property has been defined, if it has we expect it to be an array of weights.\n if (typeof definition.weights !== \"undefined\") {\n // Check that the weights property is an array of positive integers with an element for each child node element.\n if (definition.weights.length !== definition.children.length) {\n throw new Error(\n \"expected a number of weight arguments matching the number of child nodes for lotto node\"\n );\n }\n }\n }\n}\n", "import { RootNodeDefinition } from \"./BehaviourTreeDefinition\";\nimport { flattenDefinition, isBranchNode, isInteger } from \"./BehaviourTreeDefinitionUtilities\";\nimport { convertMDSLToJSON } from \"./mdsl/MDSLDefinitionParser\";\n\n/**\n * An object representing the result of validating a tree definition.\n */\nexport type DefinitionValidationResult = {\n /**\n * A flag defining whether validation succeeded.\n */\n succeeded: boolean;\n /**\n * A string containing the error message if validation did not succeed.\n */\n errorMessage?: string;\n /**\n * The definition as json if the validation was successful, or undefined if validation did not succeed.\n */\n json?: RootNodeDefinition[];\n};\n\n/**\n * Validates the specified behaviour tree definition in the form of JSON or MDSL, not taking any globally registered subtrees into consideration.\n * @param definition The behaviour tree definition in the form of JSON or MDSL.\n * @returns An object representing the result of validating the given tree definition.\n */\nexport function validateDefinition(definition: any): DefinitionValidationResult {\n // The definition must be defined.\n if (definition === null || typeof definition === \"undefined\") {\n return createValidationFailureResult(\"definition is null or undefined\");\n }\n\n // We are expecting a definition in one of three different forms:\n // - A string which we will assume is MDSL and we will parse this to JSON before validation.\n // - An array which we will assume is an array of root node definitions with at least one being the primary root node (no 'id' property)\n // - An object which we will assume is the primary root node and should not have an 'id' property.\n if (typeof definition === \"string\") {\n // The definition is a string which we can assume is MDSL, so attempt to validate it.\n return validateMDSLDefinition(definition);\n } else if (typeof definition === \"object\") {\n // The definition will either be an array (of root node definitions) or an object (the single primary root node definition).\n return validateJSONDefinition(definition);\n } else {\n return createValidationFailureResult(`unexpected definition type of '${typeof definition}'`);\n }\n}\n\n/**\n * Validates the specified behaviour tree definition in the form of MDSL.\n * @param definition The behaviour tree definition in the form of MDSL.\n * @returns An object representing the result of validating the given tree definition.\n */\nfunction validateMDSLDefinition(definition: string): DefinitionValidationResult {\n let rootNodeDefinitions;\n\n // The first thing the we need to do is to attempt to convert our MDSL into JSON.\n try {\n // The definition is a string which we can assume is MDSL, so attempt to parse it to a JSON definition in the form of an array of root node definitions.\n rootNodeDefinitions = convertMDSLToJSON(definition);\n } catch (exception) {\n // We failed to parse the JSON from the MDSL, this is likely to be the result of it not being a valid MDSL string.\n return createValidationFailureResult((exception as Error).message);\n }\n\n // Unpack all of the root node definitions into arrays of main ('id' defined) and sub ('id' not defined) root node definitions.\n const mainRootNodeDefinitions = rootNodeDefinitions.filter(({ id }) => typeof id === \"undefined\");\n const subRootNodeDefinitions = rootNodeDefinitions.filter(({ id }) => typeof id === \"string\" && id.length > 0);\n\n // We should ALWAYS have exactly one root node definition without an 'id' property defined, which is out main root node definition.\n if (mainRootNodeDefinitions.length !== 1) {\n return createValidationFailureResult(\n \"expected single unnamed root node at base of definition to act as main root\"\n );\n }\n\n // We should never have duplicate 'id' properties across our sub root node definitions.\n const subRootNodeIdenitifers: string[] = [];\n for (const { id } of subRootNodeDefinitions) {\n // Have we already come across this 'id' property value?\n if (subRootNodeIdenitifers.includes(id!)) {\n return createValidationFailureResult(`multiple root nodes found with duplicate name '${id}'`);\n }\n\n subRootNodeIdenitifers.push(id!);\n }\n\n try {\n // Validate our branch -> subtree links and check for any circular dependencies, we don't care about checking for broken subtree links here.\n validateBranchSubtreeLinks(rootNodeDefinitions, false);\n } catch (exception) {\n return createValidationFailureResult((exception as Error).message);\n }\n\n // Our definition was valid!\n return {\n succeeded: true,\n json: rootNodeDefinitions\n };\n}\n\n/**\n * Validates the specified behaviour tree definition in the form of JSON.\n * @param definition The behaviour tree definition in the form of JSON.\n * @returns An object representing the result of validating the given tree definition.\n */\nexport function validateJSONDefinition(\n definition: RootNodeDefinition | RootNodeDefinition[]\n): DefinitionValidationResult {\n // The definition will either be an array (of root node definitions) or an object (the single primary root node definition).\n const rootNodeDefinitions = Array.isArray(definition) ? definition : [definition];\n\n // Iterate over our array of root nodes and call validateNode for each, passing an initial depth of 0, wrapped in a try catch to handle validation failures.\n try {\n rootNodeDefinitions.forEach((rootNodeDefinition) => validateNode(rootNodeDefinition, 0));\n } catch (error) {\n // Handle cases where we have caught a thrown Error and return a failure result with the error message.\n if (error instanceof Error) {\n return createValidationFailureResult(error.message);\n }\n\n // No idea what happened here!\n return createValidationFailureResult(`unexpected error: ${error}`);\n }\n\n // Unpack all of the root node definitions into arrays of main ('id' defined) and sub ('id' not defined) root node definitions.\n const mainRootNodeDefinitions = rootNodeDefinitions.filter(({ id }) => typeof id === \"undefined\");\n const subRootNodeDefinitions = rootNodeDefinitions.filter(({ id }) => typeof id === \"string\" && id.length > 0);\n\n // We should ALWAYS have exactly one root node definition without an 'id' property defined, which is out main root node definition.\n if (mainRootNodeDefinitions.length !== 1) {\n return createValidationFailureResult(\n \"expected single root node without 'id' property defined to act as main root\"\n );\n }\n\n // We should never have duplicate 'id' properties across our sub root node definitions.\n const subRootNodeIdenitifers: string[] = [];\n for (const { id } of subRootNodeDefinitions) {\n // Have we already come across this 'id' property value?\n if (subRootNodeIdenitifers.includes(id!)) {\n return createValidationFailureResult(\n `multiple root nodes found with duplicate 'id' property value of '${id}'`\n );\n }\n\n subRootNodeIdenitifers.push(id!);\n }\n\n try {\n // Validate our branch -> subtree links and check for any circular dependencies, we don't care about checking for broken subtree links here.\n validateBranchSubtreeLinks(rootNodeDefinitions, false);\n } catch (exception) {\n return createValidationFailureResult((exception as Error).message);\n }\n\n // Our definition was valid!\n return {\n succeeded: true,\n json: rootNodeDefinitions\n };\n}\n\n/**\n * Validates the branch -> subtree links across all provided root node definitions.\n * This will not consider branch nodes that reference any globally registered subtrees unless includesGlobalSubtrees\n * is set to true, in which case we will also verify that there are no broken branch -> subtree links.\n * @param rootNodeDefinitions The array of root node definitions.\n * @param includesGlobalSubtrees A flag defining whether the array includes all global subtree root node definitions.\n */\nexport function validateBranchSubtreeLinks(rootNodeDefinitions: RootNodeDefinition[], includesGlobalSubtrees: boolean) {\n // Create a mapping of root node identifiers to other root nodes that they reference via branch nodes.\n // Below is an example of a mapping that includes a circular dependency (root => a => b => c => a)\n // [{ refs: [\"a\", \"b\"] }, { id: \"a\", refs: [\"b\"] }, { id: \"b\", refs: [\"c\"] }, { id: \"c\", refs: [\"a\"] }]\n const rootNodeMappings: { id: string | undefined; refs: string[] }[] = rootNodeDefinitions.map(\n (rootNodeDefinition) => ({\n id: rootNodeDefinition.id,\n refs: flattenDefinition(rootNodeDefinition)\n .filter(isBranchNode)\n .map(({ ref }) => ref)\n })\n );\n\n // A recursive function to walk through the mappings, keeping track of which root nodes we have visited in the form of a path of root node identifiers.\n const followRefs = (mapping: { id: string | undefined; refs: string[] }, path: (string | undefined)[] = []) => {\n // Have we found a circular dependency?\n if (path.includes(mapping.id)) {\n // We found a circular dependency! Get the bad path of root node identifiers.\n const badPath = [...path, mapping.id];\n\n // Create the formatted path value. [undefined, \"a\", \"b\", \"c\", \"a\"] would be formatted as \"a -> b -> c -> a\".\n const badPathFormatted = badPath.filter((element) => !!element).join(\" => \");\n\n // No need to continue, we found a circular dependency.\n throw new Error(`circular dependency found in branch node references: ${badPathFormatted}`);\n }\n\n for (const ref of mapping.refs) {\n // Find the mapping for the root node with an identifer matching the current ref.\n const subMapping = rootNodeMappings.find(({ id }) => id === ref);\n\n // We may not have a mapping for this ref, which is normal when we aren't considering all globally registered subtrees.\n if (subMapping) {\n followRefs(subMapping, [...path, mapping.id]);\n } else if (includesGlobalSubtrees) {\n // We found a reference to a root node that doesn't exist, which is a problem seeing as the root node definitons includes all globally registered subtrees.\n throw new Error(\n mapping.id\n ? `subtree '${mapping.id}' has branch node that references root node '${ref}' which has not been defined`\n : `primary tree has branch node that references root node '${ref}' which has not been defined`\n );\n }\n }\n };\n\n // Start looking for circular dependencies and broken references from the primary root node definition.\n followRefs(rootNodeMappings.find((mapping) => typeof mapping.id === \"undefined\")!);\n}\n\n/**\n * Validate an object that we expect to be a node definition.\n * @param definition An object that we expect to be a node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateNode(definition: any, depth: number): void {\n // Every node must be valid object and have a non-empty 'type' string property.\n if (typeof definition !== \"object\" || typeof definition.type !== \"string\" || definition.type.length === 0) {\n throw new Error(\n `node definition is not an object or 'type' property is not a non-empty string at depth '${depth}'`\n );\n }\n\n // How we validate this node definition will depend on its type.\n switch (definition.type) {\n case \"action\":\n validateActionNode(definition, depth);\n break;\n\n case \"condition\":\n validateConditionNode(definition, depth);\n break;\n\n case \"wait\":\n validateWaitNode(definition, depth);\n break;\n\n case \"branch\":\n validateBranchNode(definition, depth);\n break;\n\n case \"root\":\n validateRootNode(definition, depth);\n break;\n\n case \"succeed\":\n validateSucceedNode(definition, depth);\n break;\n\n case \"fail\":\n validateFailNode(definition, depth);\n break;\n\n case \"flip\":\n validateFlipNode(definition, depth);\n break;\n\n case \"repeat\":\n validateRepeatNode(definition, depth);\n break;\n\n case \"retry\":\n validateRetryNode(definition, depth);\n break;\n\n case \"sequence\":\n validateSequenceNode(definition, depth);\n break;\n\n case \"selector\":\n validateSelectorNode(definition, depth);\n break;\n\n case \"parallel\":\n validateParallelNode(definition, depth);\n break;\n\n case \"lotto\":\n validateLottoNode(definition, depth);\n break;\n\n default:\n throw new Error(`unexpected node type of '${definition.type}' at depth '${depth}'`);\n }\n}\n\n/**\n * Validate any attributes for a given node definition.\n * @param definition The node definition.\n * @param depth The depth of the node in the behaviour tree definition.\n */\nfunction validateNodeAttributes(definition: any, depth: number): void {\n // Validate each of the attribute types for this node.\n [\"while\", \"until\", \"entry\", \"exit\", \"step\"].forEach((attributeName) => {\n // Attempt to grab the definition for the current attribute from the node definition.\n const attributeDefinition = definition[attributeName];\n\n // All node attributes are optional, so there is nothing to do if the current attribute is not defined.\n if (typeof attributeDefinition === \"undefined\") {\n return;\n }\n\n // The attribute definition must be an object.\n if (typeof attributeDefinition !== \"object\") {\n throw new Error(\n `expected attribute '${attributeName}' to be an object for '${definition.type}' node at depth '${depth}'`\n );\n }\n\n // The 'call' property must be defined for any attribute definition.\n if (typeof attributeDefinition.call !== \"string\" || attributeDefinition.call.length === 0) {\n throw new Error(\n `expected 'call' property for attribute '${attributeName}' to be a non-empty string for '${definition.type}' node at depth '${depth}'`\n );\n }\n\n // If any node attribute arguments have been defined then they must have been defined in an array.\n if (typeof attributeDefinition.args !== \"undefined\" && !Array.isArray(attributeDefinition.args)) {\n throw new Error(\n `expected 'args' property for attribute '${attributeName}' to be an array for '${definition.type}' node at depth '${depth}'`\n );\n }\n });\n}\n\n/**\n * Validate an object that we expect to be a root node definition.\n * @param definition An object that we expect to be a root node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateRootNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"root\") {\n throw new Error(\"expected node type of 'root' for root node\");\n }\n\n // A root node cannot be the child of another node.\n if (depth > 0) {\n throw new Error(\"a root node cannot be the child of another node\");\n }\n\n // Check that, if the root node 'id' property is defined, it is a non-empty string.\n if (typeof definition.id !== \"undefined\" && (typeof definition.id !== \"string\" || definition.id.length === 0)) {\n throw new Error(\"expected non-empty string for 'id' property if defined for root node\");\n }\n\n // A root node is a decorator node, so must have a child node defined.\n if (typeof definition.child === \"undefined\") {\n throw new Error(\"expected property 'child' to be defined for root node\");\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n\n // Validate the child node of this decorator node.\n validateNode(definition.child, depth + 1);\n}\n\n/**\n * Validate an object that we expect to be a succeed node definition.\n * @param definition An object that we expect to be a succeed node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateSucceedNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"succeed\") {\n throw new Error(`expected node type of 'succeed' for succeed node at depth '${depth}'`);\n }\n\n // A succeed node is a decorator node, so must have a child node defined.\n if (typeof definition.child === \"undefined\") {\n throw new Error(`expected property 'child' to be defined for succeed node at depth '${depth}'`);\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n\n // Validate the child node of this decorator node.\n validateNode(definition.child, depth + 1);\n}\n\n/**\n * Validate an object that we expect to be a fail node definition.\n * @param definition An object that we expect to be a fail node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateFailNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"fail\") {\n throw new Error(`expected node type of 'fail' for fail node at depth '${depth}'`);\n }\n\n // A fail node is a decorator node, so must have a child node defined.\n if (typeof definition.child === \"undefined\") {\n throw new Error(`expected property 'child' to be defined for fail node at depth '${depth}'`);\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n\n // Validate the child node of this decorator node.\n validateNode(definition.child, depth + 1);\n}\n\n/**\n * Validate an object that we expect to be a flip node definition.\n * @param definition An object that we expect to be a flip node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateFlipNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"flip\") {\n throw new Error(`expected node type of 'flip' for flip node at depth '${depth}'`);\n }\n\n // A flip node is a decorator node, so must have a child node defined.\n if (typeof definition.child === \"undefined\") {\n throw new Error(`expected property 'child' to be defined for flip node at depth '${depth}'`);\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n\n // Validate the child node of this decorator node.\n validateNode(definition.child, depth + 1);\n}\n\n/**\n * Validate an object that we expect to be a repeat node definition.\n * @param definition An object that we expect to be a repeat node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateRepeatNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"repeat\") {\n throw new Error(`expected node type of 'repeat' for repeat node at depth '${depth}'`);\n }\n\n // A repeat node is a decorator node, so must have a child node defined.\n if (typeof definition.child === \"undefined\") {\n throw new Error(`expected property 'child' to be defined for repeat node at depth '${depth}'`);\n }\n\n // Check whether an 'iterations' property has been defined, it may not have been if this node is to repeat indefinitely.\n if (typeof definition.iterations !== \"undefined\") {\n if (Array.isArray(definition.iterations)) {\n // Check whether any elements of the array are not integer values.\n const containsNonInteger = !!definition.iterations.filter((value: unknown) => !isInteger(value)).length;\n\n // If the 'iterations' property is an array then it MUST contain two integer values.\n if (definition.iterations.length !== 2 || containsNonInteger) {\n throw new Error(\n `expected array containing two integer values for 'iterations' property if defined for repeat node at depth '${depth}'`\n );\n }\n\n // A repeat node must have a positive min and max iterations count if they are defined.\n if (definition.iterations[0] < 0 || definition.iterations[1] < 0) {\n throw new Error(\n `expected positive minimum and maximum iterations count for 'iterations' property if defined for repeat node at depth '${depth}'`\n );\n }\n\n // A repeat node must not have a minimum iterations count that exceeds the maximum iterations count.\n if (definition.iterations[0] > definition.iterations[1]) {\n throw new Error(\n `expected minimum iterations count that does not exceed the maximum iterations count for 'iterations' property if defined for repeat node at depth '${depth}'`\n );\n }\n } else if (isInteger(definition.iterations)) {\n // A repeat node must have a positive number of iterations if defined.\n if (definition.iterations < 0) {\n throw new Error(\n `expected positive iterations count for 'iterations' property if defined for repeat node at depth '${depth}'`\n );\n }\n } else {\n throw new Error(\n `expected integer value or array containing two integer values for 'iterations' property if defined for repeat node at depth '${depth}'`\n );\n }\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n\n // Validate the child node of this decorator node.\n validateNode(definition.child, depth + 1);\n}\n\n/**\n * Validate an object that we expect to be a retry node definition.\n * @param definition An object that we expect to be a retry node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateRetryNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"retry\") {\n throw new Error(`expected node type of 'retry' for retry node at depth '${depth}'`);\n }\n\n // A retry node is a decorator node, so must have a child node defined.\n if (typeof definition.child === \"undefined\") {\n throw new Error(`expected property 'child' to be defined for retry node at depth '${depth}'`);\n }\n\n // Check whether an 'attempts' property has been defined, it may not have been if this node is to retry indefinitely.\n if (typeof definition.attempts !== \"undefined\") {\n if (Array.isArray(definition.attempts)) {\n // Check whether any elements of the array are not integer values.\n const containsNonInteger = !!definition.attempts.filter((value: unknown) => !isInteger(value)).length;\n\n // If the 'attempts' property is an array then it MUST contain two integer values.\n if (definition.attempts.length !== 2 || containsNonInteger) {\n throw new Error(\n `expected array containing two integer values for 'attempts' property if defined for retry node at depth '${depth}'`\n );\n }\n\n // A retry node must have a positive min and max attempts count if they are defined.\n if (definition.attempts[0] < 0 || definition.attempts[1] < 0) {\n throw new Error(\n `expected positive minimum and maximum attempts count for 'attempts' property if defined for retry node at depth '${depth}'`\n );\n }\n\n // A retry node must not have a minimum attempts count that exceeds the maximum attempts count.\n if (definition.attempts[0] > definition.attempts[1]) {\n throw new Error(\n `expected minimum attempts count that does not exceed the maximum attempts count for 'attempts' property if defined for retry node at depth '${depth}'`\n );\n }\n } else if (isInteger(definition.attempts)) {\n // A retry node must have a positive number of attempts if defined.\n if (definition.attempts < 0) {\n throw new Error(\n `expected positive attempts count for 'attempts' property if defined for retry node at depth '${depth}'`\n );\n }\n } else {\n throw new Error(\n `expected integer value or array containing two integer values for 'attempts' property if defined for retry node at depth '${depth}'`\n );\n }\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n\n // Validate the child node of this decorator node.\n validateNode(definition.child, depth + 1);\n}\n\n/**\n * Validate an object that we expect to be a branch node definition.\n * @param definition An object that we expect to be a branch node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateBranchNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"branch\") {\n throw new Error(`expected node type of 'branch' for branch node at depth '${depth}'`);\n }\n\n // Check that the branch node 'ref' property is defined and is a non-empty string.\n if (typeof definition.ref !== \"string\" || definition.ref.length === 0) {\n throw new Error(`expected non-empty string for 'ref' property for branch node at depth '${depth}'`);\n }\n\n // It is invalid to define guard attributes for a branch node as they should be defined on the referenced root node.\n [\"while\", \"until\"].forEach((attributeName) => {\n if (typeof definition[attributeName] !== \"undefined\") {\n throw new Error(\n `guards should not be defined for branch nodes but guard '${attributeName}' was defined for branch node at depth '${depth}'`\n );\n }\n });\n\n // It is invalid to define callback attributes for a branch node as they should be defined on the referenced root node.\n [\"entry\", \"exit\", \"step\"].forEach((attributeName) => {\n if (typeof definition[attributeName] !== \"undefined\") {\n throw new Error(\n `callbacks should not be defined for branch nodes but callback '${attributeName}' was defined for branch node at depth '${depth}'`\n );\n }\n });\n}\n\n/**\n * Validate an object that we expect to be a action node definition.\n * @param definition An object that we expect to be a action node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateActionNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"action\") {\n throw new Error(`expected node type of 'action' for action node at depth '${depth}'`);\n }\n\n // The 'call' property must be defined for a action node definition.\n if (typeof definition.call !== \"string\" || definition.call.length === 0) {\n throw new Error(`expected non-empty string for 'call' property of action node at depth '${depth}'`);\n }\n\n // If any action function arguments have been defined then they must have been defined in an array.\n if (typeof definition.args !== \"undefined\" && !Array.isArray(definition.args)) {\n throw new Error(`expected array for 'args' property if defined for action node at depth '${depth}'`);\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n}\n\n/**\n * Validate an object that we expect to be a condition node definition.\n * @param definition An object that we expect to be a condition node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateConditionNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"condition\") {\n throw new Error(`expected node type of 'condition' for condition node at depth '${depth}'`);\n }\n\n // The 'call' property must be defined for a condition node definition.\n if (typeof definition.call !== \"string\" || definition.call.length === 0) {\n throw new Error(`expected non-empty string for 'call' property of condition node at depth '${depth}'`);\n }\n\n // If any condition function arguments have been defined then they must have been defined in an array.\n if (typeof definition.args !== \"undefined\" && !Array.isArray(definition.args)) {\n throw new Error(`expected array for 'args' property if defined for condition node at depth '${depth}'`);\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n}\n\n/**\n * Validate an object that we expect to be a wait node definition.\n * @param definition An object that we expect to be a wait node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateWaitNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"wait\") {\n throw new Error(`expected node type of 'wait' for wait node at depth '${depth}'`);\n }\n\n // Check whether a 'duration' property has been defined, it may not have been if this node is to wait indefinitely.\n if (typeof definition.duration !== \"undefined\") {\n if (Array.isArray(definition.duration)) {\n // Check whether any elements of the array are not integer values.\n const containsNonInteger = !!definition.duration.filter((value: unknown) => !isInteger(value)).length;\n\n // If the 'duration' property is an array then it MUST contain two integer values.\n if (definition.duration.length !== 2 || containsNonInteger) {\n throw new Error(\n `expected array containing two integer values for 'duration' property if defined for wait node at depth '${depth}'`\n );\n }\n\n // A wait node must have a positive min and max duration value if they are defined.\n if (definition.duration[0] < 0 || definition.duration[1] < 0) {\n throw new Error(\n `expected positive minimum and maximum duration for 'duration' property if defined for wait node at depth '${depth}'`\n );\n }\n\n // A wait node must not have a minimum duration value that exceeds the maximum duration value.\n if (definition.duration[0] > definition.duration[1]) {\n throw new Error(\n `expected minimum duration value that does not exceed the maximum duration value for 'duration' property if defined for wait node at depth '${depth}'`\n );\n }\n } else if (isInteger(definition.duration)) {\n // A wait node must have a positive duration value if defined.\n if (definition.duration < 0) {\n throw new Error(\n `expected positive duration value for 'duration' property if defined for wait node at depth '${depth}'`\n );\n }\n } else {\n throw new Error(\n `expected integer value or array containing two integer values for 'duration' property if defined for wait node at depth '${depth}'`\n );\n }\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n}\n\n/**\n * Validate an object that we expect to be a sequence node definition.\n * @param definition An object that we expect to be a sequence node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateSequenceNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"sequence\") {\n throw new Error(`expected node type of 'sequence' for sequence node at depth '${depth}'`);\n }\n\n // A sequence node is a composite node, so must have a children nodes array defined.\n if (!Array.isArray(definition.children) || definition.children.length === 0) {\n throw new Error(`expected non-empty 'children' array to be defined for sequence node at depth '${depth}'`);\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n\n // Validate the child nodes of this composite node.\n definition.children.forEach((child: any) => validateNode(child, depth + 1));\n}\n\n/**\n * Validate an object that we expect to be a selector node definition.\n * @param definition An object that we expect to be a selector node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateSelectorNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"selector\") {\n throw new Error(`expected node type of 'selector' for selector node at depth '${depth}'`);\n }\n\n // A selector node is a composite node, so must have a children nodes array defined.\n if (!Array.isArray(definition.children) || definition.children.length === 0) {\n throw new Error(`expected non-empty 'children' array to be defined for selector node at depth '${depth}'`);\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n\n // Validate the child nodes of this composite node.\n definition.children.forEach((child: any) => validateNode(child, depth + 1));\n}\n\n/**\n * Validate an object that we expect to be a parallel node definition.\n * @param definition An object that we expect to be a parallel node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateParallelNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"parallel\") {\n throw new Error(`expected node type of 'parallel' for parallel node at depth '${depth}'`);\n }\n\n // A parallel node is a composite node, so must have a children nodes array defined.\n if (!Array.isArray(definition.children) || definition.children.length === 0) {\n throw new Error(`expected non-empty 'children' array to be defined for parallel node at depth '${depth}'`);\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n\n // Validate the child nodes of this composite node.\n definition.children.forEach((child: any) => validateNode(child, depth + 1));\n}\n\n/**\n * Validate an object that we expect to be a lotto node definition.\n * @param definition An object that we expect to be a lotto node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateLottoNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"lotto\") {\n throw new Error(`expected node type of 'lotto' for lotto node at depth '${depth}'`);\n }\n\n // A lotto node is a composite node, so must have a children nodes array defined.\n if (!Array.isArray(definition.children) || definition.children.length === 0) {\n throw new Error(`expected non-empty 'children' array to be defined for lotto node at depth '${depth}'`);\n }\n\n // Check whether a 'weights' property has been defined, if it has we expect it to be an array of weights.\n if (typeof definition.weights !== \"undefined\") {\n // Check that the weights property is an array of positive integers with an element for each child node element.\n if (\n !Array.isArray(definition.weights) ||\n definition.weights.length !== definition.children.length ||\n definition.weights.filter((value: unknown) => !isInteger(value)).length ||\n definition.weights.filter((value: number) => value < 0).length\n ) {\n throw new Error(\n `expected an array of positive integer weight values with a length matching the number of child nodes for 'weights' property if defined for lotto node at depth '${depth}'`\n );\n }\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n\n // Validate the child nodes of this composite node.\n definition.children.forEach((child: any) => validateNode(child, depth + 1));\n}\n\n/**\n * A helper function to create a failure validation result with the given error message.\n * @param errorMessage The validation failure error message.\n * @returns A failure validation result with the given error message.\n */\nfunction createValidationFailureResult(errorMessage: string): DefinitionValidationResult {\n return { succeeded: false, errorMessage };\n}\n", "import { ActionResult, Agent, GlobalFunction } from \"./Agent\";\nimport { RootNodeDefinition } from \"./BehaviourTreeDefinition\";\n\nexport type InvokerFunction = (args: any[]) => ActionResult | boolean;\n\n/**\n * A singleton used to store and lookup registered functions and subtrees.\n */\nexport default class Lookup {\n /**\n * The object holding any registered functions keyed on function name.\n */\n private static registeredFunctions: { [key: string]: GlobalFunction } = {};\n /**\n * The object holding any registered subtree root node definitions keyed on tree name.\n */\n private static registeredSubtrees: { [key: string]: RootNodeDefinition } = {};\n\n /**\n * Gets the function with the specified name.\n * @param name The name of the function.\n * @returns The function with the specified name.\n */\n public static getFunc(name: string): GlobalFunction {\n return this.registeredFunctions[name];\n }\n\n /**\n * Sets the function with the specified name for later lookup.\n * @param name The name of the function.\n * @param func The function.\n */\n public static setFunc(name: string, func: GlobalFunction): void {\n this.registeredFunctions[name] = func;\n }\n\n /**\n * Gets the function invoker for the specified agent and function name.\n * If a function with the specified name exists on the agent object then it will\n * be returned, otherwise we will then check the registered functions for a match.\n * @param agent The agent instance that this behaviour tree is modelling behaviour for.\n * @param name The function name.\n * @returns The function invoker for the specified agent and function name.\n */\n static getFuncInvoker(agent: Agent, name: string): InvokerFunction | null {\n // Check whether the agent contains the specified function.\n const agentFunction = agent[name];\n if (agentFunction && typeof agentFunction === \"function\") {\n return (args: any[]) => agentFunction.apply(agent, args);\n }\n\n // The agent does not contain the specified function but it may have been registered at some point.\n if (this.registeredFunctions[name] && typeof this.registeredFunctions[name] === \"function\") {\n const registeredFunction = this.registeredFunctions[name];\n return (args: any[]) => registeredFunction(agent, ...args.map((arg) => arg.value));\n }\n\n // We have no function to invoke.\n return null;\n }\n\n /**\n * Gets all registered subtree root node definitions.\n */\n static getSubtrees(): { [key: string]: RootNodeDefinition } {\n return this.registeredSubtrees;\n }\n\n /**\n * Sets the subtree with the specified name for later lookup.\n * @param name The name of the subtree.\n * @param subtree The subtree.\n */\n static setSubtree(name: string, subtree: RootNodeDefinition) {\n this.registeredSubtrees[name] = subtree;\n }\n\n /**\n * Removes the registered function or subtree with the specified name.\n * @param name The name of the registered function or subtree.\n */\n static remove(name: string) {\n delete this.registeredFunctions[name];\n delete this.registeredSubtrees[name];\n }\n\n /**\n * Remove all registered functions and subtrees.\n */\n static empty() {\n this.registeredFunctions = {};\n this.registeredSubtrees = {};\n }\n}\n", "import Node from \"../../nodes/Node\";\n\n/**\n * An exception thrown when evaluating node guard path conditions and a conditions fails.\n */\nexport default class GuardUnsatisifedException extends Error {\n /**\n * @param source The node at which a guard condition failed.\n */\n constructor(private source: Node) {\n super(\"A guard path condition has failed\");\n }\n\n /**\n * Gets whether the specified node is the node at which a guard condition failed.\n * @param node The node to check against the source node.\n * @returns Whether the specified node is the node at which a guard condition failed.\n */\n isSourceNode = (node: Node) => node === this.source;\n}\n", "import { Agent } from \"../../Agent\";\nimport Guard from \"./Guard\";\nimport Node from \"../../nodes/Node\";\nimport GuardUnsatisifedException from \"./GuardUnsatisifedException\";\n\nexport type GuardPathPart = {\n node: Node;\n guards: Guard[];\n};\n\n/**\n * Represents a path of node guards along a root-to-leaf tree path.\n */\nexport default class GuardPath {\n /**\n * @param nodes An array of objects defining a node instance -> guard link, ordered by node depth.\n */\n constructor(private nodes: GuardPathPart[]) {}\n\n /**\n * Evaluate guard conditions for all guards in the tree path, moving outwards from the root.\n * @param agent The agent, required for guard evaluation.\n * @returns An evaluation results object.\n */\n evaluate = (agent: Agent) => {\n // We need to evaluate guard conditions for nodes up the tree, moving outwards from the root.\n for (const details of this.nodes) {\n // There can be multiple guards per node.\n for (const guard of details.guards) {\n // Check whether the guard condition passes, and throw an exception if not.\n if (!guard.isSatisfied(agent)) {\n throw new GuardUnsatisifedException(details.node);\n }\n }\n }\n };\n}\n", "import { BehaviourTreeOptions } from \"../BehaviourTreeOptions\";\nimport State, { AnyState } from \"../State\";\nimport { Agent } from \"../Agent\";\nimport Leaf from \"./leaf/Leaf\";\nimport Attribute from \"../attributes/Attribute\";\nimport Entry from \"../attributes/callbacks/Entry\";\nimport Exit from \"../attributes/callbacks/Exit\";\nimport Step from \"../attributes/callbacks/Step\";\nimport Guard from \"../attributes/guards/Guard\";\nimport GuardPath from \"../attributes/guards/GuardPath\";\nimport GuardUnsatisifedException from \"../attributes/guards/GuardUnsatisifedException\";\n\n/**\n * A base node.\n */\nexport default abstract class Node {\n /**\n * The node uid.\n */\n private readonly uid: string = createNodeUid();\n /**\n * The node state.\n */\n private state: AnyState = State.READY;\n /**\n * The guard path to evaluate as part of a node update.\n */\n private guardPath: GuardPath | undefined;\n\n /**\n * @param type The node type.\n * @param attributes The node attributes.\n * @param args The node argument definitions.\n */\n constructor(private type: string, private attributes: Attribute[], private args: any[]) {}\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected abstract onUpdate(agent: Agent, options: BehaviourTreeOptions): void;\n\n /**\n * Gets the name of the node.\n */\n public abstract getName(): string;\n\n /**\n * Gets whether this node is a leaf node.\n */\n public abstract isLeafNode: () => this is Leaf;\n\n /**\n * Gets/Sets the state of the node.\n */\n getState = (): AnyState => this.state;\n setState = (value: AnyState): void => {\n this.state = value;\n };\n\n /**\n * Gets the unique id of the node.\n */\n getUid = () => this.uid;\n\n /**\n * Gets the type of the node.\n */\n getType = () => this.type;\n\n /**\n * Gets the node attributes.\n */\n getAttributes = () => this.attributes;\n\n /**\n * Gets the node arguments.\n */\n getArguments = () => this.args;\n\n /**\n * Gets the node attribute with the specified type, or null if it does not exist.\n */\n getAttribute(type: \"entry\" | \"ENTRY\"): Entry;\n getAttribute(type: \"exit\" | \"EXIT\"): Exit;\n getAttribute(type: \"step\" | \"STEP\"): Step;\n getAttribute(type: string): Attribute {\n return (\n this.getAttributes().filter((decorator) => decorator.type.toUpperCase() === type.toUpperCase())[0] || null\n );\n }\n\n /**\n * Gets the node attributes.\n */\n getGuardAttributes = (): Guard[] => this.getAttributes().filter((decorator) => decorator.isGuard()) as Guard[];\n\n /**\n * Sets the guard path to evaluate as part of a node update.\n */\n setGuardPath = (value: GuardPath) => (this.guardPath = value);\n\n /**\n * Gets whether a guard path is assigned to this node.\n */\n hasGuardPath = () => !!this.guardPath;\n\n /**\n * Gets whether this node is in the specified state.\n * @param value The value to compare to the node state.\n */\n public is(value: AnyState): boolean {\n return this.state === value;\n }\n\n /**\n * Reset the state of the node.\n */\n public reset(): void {\n this.setState(State.READY);\n }\n\n /**\n * Abort the running of this node.\n * @param agent The agent.\n */\n public abort(agent: Agent): void {\n // There is nothing to do if this node is not in the running state.\n if (!this.is(State.RUNNING)) {\n return;\n }\n\n // Reset the state of this node.\n this.reset();\n\n this.getAttribute(\"exit\")?.callAgentFunction(agent, false, true);\n }\n\n /**\n * Update the node.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n * @returns The result of the update.\n */\n public update(agent: Agent, options: BehaviourTreeOptions): void {\n // If this node is already in a 'SUCCEEDED' or 'FAILED' state then there is nothing to do.\n if (this.is(State.SUCCEEDED) || this.is(State.FAILED)) {\n return;\n }\n\n try {\n // Evaluate all of the guard path conditions for the current tree path.\n this.guardPath!.evaluate(agent);\n\n // If this node is in the READY state then call the ENTRY for this node if it exists.\n if (this.is(State.READY)) {\n this.getAttribute(\"entry\")?.callAgentFunction(agent);\n }\n\n this.getAttribute(\"step\")?.callAgentFunction(agent);\n\n // Do the actual update.\n this.onUpdate(agent, options);\n\n // If this node is now in a 'SUCCEEDED' or 'FAILED' state then call the EXIT for this node if it exists.\n if (this.is(State.SUCCEEDED) || this.is(State.FAILED)) {\n this.getAttribute(\"exit\")?.callAgentFunction(agent, this.is(State.SUCCEEDED), false);\n }\n } catch (error) {\n // If the error is a GuardUnsatisfiedException then we need to determine if this node is the source.\n if (error instanceof GuardUnsatisifedException && error.isSourceNode(this)) {\n // Abort the current node.\n this.abort(agent);\n\n // Any node that is the source of an abort will be a failed node.\n this.setState(State.FAILED);\n } else {\n throw error;\n }\n }\n }\n}\n\n/**\n * Create a randomly generated node uid.\n * @returns A randomly generated node uid.\n */\nfunction createNodeUid(): string {\n var S4 = function () {\n return (((1 + Math.random()) * 0x10000) | 0).toString(16).substring(1);\n };\n return S4() + S4() + \"-\" + S4() + \"-\" + S4() + \"-\" + S4() + \"-\" + S4() + S4() + S4();\n}\n", "import Node from \"../Node\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\n\n/**\n * A composite node that wraps child nodes.\n */\nexport default abstract class Composite extends Node {\n /**\n * @param type The node type.\n * @param attributes The node attributes.\n * @param children The child nodes.\n */\n constructor(type: string, attributes: Attribute[], protected children: Node[]) {\n super(type, attributes, []);\n }\n\n /**\n * Gets whether this node is a leaf node.\n */\n isLeafNode = () => false;\n\n /**\n * Gets the children of this node.\n */\n getChildren = () => this.children;\n\n /**\n * Reset the state of the node.\n */\n reset = () => {\n // Reset the state of this node.\n this.setState(State.READY);\n\n // Reset the state of any child nodes.\n this.getChildren().forEach((child) => child.reset());\n };\n\n /**\n * Abort the running of this node.\n * @param agent The agent.\n */\n abort = (agent: Agent) => {\n // There is nothing to do if this node is not in the running state.\n if (!this.is(State.RUNNING)) {\n return;\n }\n\n // Abort any child nodes.\n this.getChildren().forEach((child) => child.abort(agent));\n\n // Reset the state of this node.\n this.reset();\n\n this.getAttribute(\"exit\")?.callAgentFunction(agent, false, true);\n };\n}\n", "import Composite from \"./Composite\";\nimport State from \"../../State\";\nimport Node from \"../Node\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A PARALLEL node.\n * The child nodes are executed concurrently until one fails or all succeed.\n */\nexport default class Parallel extends Composite {\n /**\n * @param attributes The node attributes.\n * @param children The child nodes.\n */\n constructor(attributes: Attribute[], children: Node[]) {\n super(\"parallel\", attributes, children);\n }\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // Keep a count of the number of succeeded child nodes.\n let succeededCount = 0;\n\n let hasChildFailed = false;\n\n // Iterate over all of the children of this node.\n for (const child of this.children) {\n // If the child has never been updated or is running then we will need to update it now.\n if (child.getState() === State.READY || child.getState() === State.RUNNING) {\n // Update the child of this node.\n child.update(agent, options);\n }\n\n // If the current child has a state of 'SUCCEEDED' then we should move on to the next child.\n if (child.getState() === State.SUCCEEDED) {\n // The child node has succeeded, keep track of this to determine if all children have.\n succeededCount++;\n\n // The child node succeeded, but we have not finished checking every child node yet.\n continue;\n }\n\n // If the current child has a state of 'FAILED' then this node is also a 'FAILED' node.\n if (child.getState() === State.FAILED) {\n hasChildFailed = true;\n\n // There is no need to check the rest of the children.\n break;\n }\n\n // The node should be in the 'RUNNING' state.\n if (child.getState() !== State.RUNNING) {\n // The child node was not in an expected state.\n throw new Error(\"child node was not in an expected state.\");\n }\n }\n\n if (hasChildFailed) {\n // This node is a 'FAILED' node.\n this.setState(State.FAILED);\n\n // Abort every running child.\n for (const child of this.children) {\n if (child.getState() === State.RUNNING) {\n child.abort(agent);\n }\n }\n } else {\n // If all children have succeeded then this node has also succeeded, otherwise it is still running.\n this.setState(succeededCount === this.children.length ? State.SUCCEEDED : State.RUNNING);\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => \"PARALLEL\";\n}\n", "import Composite from \"./Composite\";\nimport Node from \"../Node\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A SELECTOR node.\n * The child nodes are executed in sequence until one succeeds or all fail.\n */\nexport default class Selector extends Composite {\n /**\n * @param attributes The node attributes.\n * @param children The child nodes.\n */\n constructor(attributes: Attribute[], protected children: Node[]) {\n super(\"selector\", attributes, children);\n }\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // Iterate over all of the children of this node.\n for (const child of this.children) {\n // If the child has never been updated or is running then we will need to update it now.\n if (child.getState() === State.READY || child.getState() === State.RUNNING) {\n // Update the child of this node.\n child.update(agent, options);\n }\n\n // If the current child has a state of 'SUCCEEDED' then this node is also a 'SUCCEEDED' node.\n if (child.getState() === State.SUCCEEDED) {\n // This node is a 'SUCCEEDED' node.\n this.setState(State.SUCCEEDED);\n\n // There is no need to check the rest of the selector nodes.\n return;\n }\n\n // If the current child has a state of 'FAILED' then we should move on to the next child.\n if (child.getState() === State.FAILED) {\n // Find out if the current child is the last one in the selector.\n // If it is then this sequence node has also failed.\n if (this.children.indexOf(child) === this.children.length - 1) {\n // This node is a 'FAILED' node.\n this.setState(State.FAILED);\n\n // There is no need to check the rest of the selector as we have completed it.\n return;\n } else {\n // The child node failed, try the next one.\n continue;\n }\n }\n\n // The node should be in the 'RUNNING' state.\n if (child.getState() === State.RUNNING) {\n // This node is a 'RUNNING' node.\n this.setState(State.RUNNING);\n\n // There is no need to check the rest of the selector as the current child is still running.\n return;\n }\n\n // The child node was not in an expected state.\n throw new Error(\"child node was not in an expected state.\");\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => \"SELECTOR\";\n}\n", "import Composite from \"./Composite\";\nimport Node from \"../Node\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A SEQUENCE node.\n * The child nodes are executed in sequence until one fails or all succeed.\n */\nexport default class Sequence extends Composite {\n /**\n * @param attributes The node attributes.\n * @param children The child nodes.\n */\n constructor(attributes: Attribute[], protected children: Node[]) {\n super(\"sequence\", attributes, children);\n }\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // Iterate over all of the children of this node.\n for (const child of this.children) {\n // If the child has never been updated or is running then we will need to update it now.\n if (child.getState() === State.READY || child.getState() === State.RUNNING) {\n // Update the child of this node.\n child.update(agent, options);\n }\n\n // If the current child has a state of 'SUCCEEDED' then we should move on to the next child.\n if (child.getState() === State.SUCCEEDED) {\n // Find out if the current child is the last one in the sequence.\n // If it is then this sequence node has also succeeded.\n if (this.children.indexOf(child) === this.children.length - 1) {\n // This node is a 'SUCCEEDED' node.\n this.setState(State.SUCCEEDED);\n\n // There is no need to check the rest of the sequence as we have completed it.\n return;\n } else {\n // The child node succeeded, but we have not finished the sequence yet.\n continue;\n }\n }\n\n // If the current child has a state of 'FAILED' then this node is also a 'FAILED' node.\n if (child.getState() === State.FAILED) {\n // This node is a 'FAILED' node.\n this.setState(State.FAILED);\n\n // There is no need to check the rest of the sequence.\n return;\n }\n\n // The node should be in the 'RUNNING' state.\n if (child.getState() === State.RUNNING) {\n // This node is a 'RUNNING' node.\n this.setState(State.RUNNING);\n\n // There is no need to check the rest of the sequence as the current child is still running.\n return;\n }\n\n // The child node was not in an expected state.\n throw new Error(\"child node was not in an expected state.\");\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => \"SEQUENCE\";\n}\n", "import createLotto from \"lotto-draw\";\n\nimport Node from \"../Node\";\nimport Composite from \"./Composite\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A LOTTO node.\n * A winning child is picked on the initial update of this node, based on ticket weighting.\n * The state of this node will match the state of the winning child.\n */\nexport default class Lotto extends Composite {\n /**\n * @param attributes The node attributes.\n * @param weights The child node weights.\n * @param children The child nodes.\n */\n constructor(attributes: Attribute[], private weights: number[] | undefined, children: Node[]) {\n super(\"lotto\", attributes, children);\n }\n\n /**\n * The child node selected to be the active one.\n */\n private selectedChild: Node | undefined;\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // If this node is in the READY state then we need to pick a winning child node.\n if (this.is(State.READY)) {\n // Create a lotto draw with which to randomly pick a child node to become the active one.\n const lottoDraw = createLotto({\n // Hook up the optional 'random' behaviour tree function option to the one used by 'lotto-draw'.\n random: options.random,\n // Pass in each child node as a participant in the lotto draw with their respective ticket count.\n participants: this.children.map((child, index) => [child, this.weights?.[index] || 1])\n });\n\n // Randomly pick a child based on ticket weighting, this will become the active child for this composite node.\n this.selectedChild = lottoDraw.draw() || undefined;\n }\n\n // If something went wrong and we don't have an active child then we should throw an error.\n if (!this.selectedChild) {\n throw new Error(\"failed to update lotto node as it has no active child\");\n }\n\n // If the selected child has never been updated or is running then we will need to update it now.\n if (this.selectedChild.getState() === State.READY || this.selectedChild.getState() === State.RUNNING) {\n this.selectedChild.update(agent, options);\n }\n\n // The state of the lotto node is the state of its selected child.\n this.setState(this.selectedChild.getState());\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => (this.weights ? `LOTTO [${this.weights.join(\",\")}]` : \"LOTTO\");\n}\n", "import Node from \"../Node\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\n\n/**\n * A decorator node that wraps a single child node.\n */\nexport default abstract class Decorator extends Node {\n /**\n * @param type The node type.\n * @param attributes The node attributes.\n * @param child The child node.\n */\n constructor(type: string, attributes: Attribute[], protected child: Node) {\n super(type, attributes, []);\n }\n\n /**\n * Gets whether this node is a leaf node.\n */\n isLeafNode = () => false;\n\n /**\n * Gets the children of this node.\n */\n getChildren = () => [this.child];\n\n /**\n * Reset the state of the node.\n */\n reset = () => {\n // Reset the state of this node.\n this.setState(State.READY);\n\n // Reset the state of the child node.\n this.child.reset();\n };\n\n /**\n * Abort the running of this node.\n * @param agent The agent.\n */\n abort = (agent: Agent) => {\n // There is nothing to do if this node is not in the running state.\n if (!this.is(State.RUNNING)) {\n return;\n }\n\n // Abort the child node.\n this.child.abort(agent);\n\n // Reset the state of this node.\n this.reset();\n\n this.getAttribute(\"exit\")?.callAgentFunction(agent, false, true);\n };\n}\n", "import Node from \"../Node\";\nimport Decorator from \"./Decorator\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A Fail node.\n * This node wraps a single child and will always move to the 'FAILED' state when the child moves to a 'SUCCEEDED' or 'FAILED' state.\n */\nexport default class Fail extends Decorator {\n /**\n * @param attributes The node attributes.\n * @param child The child node.\n */\n constructor(attributes: Attribute[], child: Node) {\n super(\"fail\", attributes, child);\n }\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // If the child has never been updated or is running then we will need to update it now.\n if (this.child.getState() === State.READY || this.child.getState() === State.RUNNING) {\n this.child.update(agent, options);\n }\n\n // The state of this node will depend in the state of its child.\n switch (this.child.getState()) {\n case State.RUNNING:\n this.setState(State.RUNNING);\n break;\n\n case State.SUCCEEDED:\n case State.FAILED:\n this.setState(State.FAILED);\n break;\n\n default:\n this.setState(State.READY);\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => \"FAIL\";\n}\n", "import Decorator from \"./Decorator\";\nimport State from \"../../State\";\nimport Node from \"../Node\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A Flip node.\n * This node wraps a single child and will flip the state of the child state.\n */\nexport default class Flip extends Decorator {\n /**\n * @param attributes The node attributes.\n * @param child The child node.\n */\n constructor(attributes: Attribute[], child: Node) {\n super(\"flip\", attributes, child);\n }\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // If the child has never been updated or is running then we will need to update it now.\n if (this.child.getState() === State.READY || this.child.getState() === State.RUNNING) {\n this.child.update(agent, options);\n }\n\n // The state of this node will depend in the state of its child.\n switch (this.child.getState()) {\n case State.RUNNING:\n this.setState(State.RUNNING);\n break;\n\n case State.SUCCEEDED:\n this.setState(State.FAILED);\n break;\n\n case State.FAILED:\n this.setState(State.SUCCEEDED);\n break;\n\n default:\n this.setState(State.READY);\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => \"FLIP\";\n}\n", "import Node from \"../Node\";\nimport Decorator from \"./Decorator\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A REPEAT node.\n * The node has a single child which can have:\n * -- A number of iterations for which to repeat the child node.\n * -- An infinite repeat loop if neither an iteration count or a condition function is defined.\n * The REPEAT node will stop and have a 'FAILED' state if its child is ever in a 'FAILED' state after an update.\n * The REPEAT node will attempt to move on to the next iteration if its child is ever in a 'SUCCEEDED' state.\n */\nexport default class Repeat extends Decorator {\n /**\n * @param attributes The node attributes.\n * @param iterations The number of iterations to repeat the child node.\n * @param iterationsMin The minimum possible number of iterations to repeat the child node.\n * @param iterationsMax The maximum possible number of iterations to repeat the child node.\n * @param child The child node.\n */\n constructor(\n attributes: Attribute[],\n private iterations: number | null,\n private iterationsMin: number | null,\n private iterationsMax: number | null,\n child: Node\n ) {\n super(\"repeat\", attributes, child);\n }\n\n /**\n * The number of target iterations to make.\n */\n private targetIterationCount: number | null = null;\n\n /**\n * The current iteration count.\n */\n private currentIterationCount: number = 0;\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // If this node is in the READY state then we need to reset the child and the target iteration count.\n if (this.is(State.READY)) {\n // Reset the child node.\n this.child.reset();\n\n // Reset the current iteration count.\n this.currentIterationCount = 0;\n\n // Set the target iteration count.\n this.setTargetIterationCount(options);\n }\n\n // Do a check to see if we can iterate. If we can then this node will move into the 'RUNNING' state.\n // If we cannot iterate then we have hit our target iteration count, which means that the node has succeeded.\n if (this.canIterate()) {\n // This node is in the running state and can do its initial iteration.\n this.setState(State.RUNNING);\n\n // We may have already completed an iteration, meaning that the child node will be in the SUCCEEDED state.\n // If this is the case then we will have to reset the child node now.\n if (this.child.getState() === State.SUCCEEDED) {\n this.child.reset();\n }\n\n // Update the child of this node.\n this.child.update(agent, options);\n\n // If the child moved into the FAILED state when we updated it then there is nothing left to do and this node has also failed.\n // If it has moved into the SUCCEEDED state then we have completed the current iteration.\n if (this.child.getState() === State.FAILED) {\n // The child has failed, meaning that this node has failed.\n this.setState(State.FAILED);\n\n return;\n } else if (this.child.getState() === State.SUCCEEDED) {\n // We have completed an iteration.\n this.currentIterationCount += 1;\n }\n } else {\n // This node is in the 'SUCCEEDED' state as we cannot iterate any more.\n this.setState(State.SUCCEEDED);\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => {\n if (this.iterations !== null) {\n return `REPEAT ${this.iterations}x`;\n } else if (this.iterationsMin !== null && this.iterationsMax !== null) {\n return `REPEAT ${this.iterationsMin}x-${this.iterationsMax}x`;\n } else {\n return \"REPEAT\";\n }\n };\n\n /**\n * Reset the state of the node.\n */\n reset = () => {\n // Reset the state of this node.\n this.setState(State.READY);\n\n // Reset the current iteration count.\n this.currentIterationCount = 0;\n\n // Reset the child node.\n this.child.reset();\n };\n\n /**\n * Gets whether an iteration can be made.\n * @returns Whether an iteration can be made.\n */\n private canIterate = () => {\n if (this.targetIterationCount !== null) {\n // We can iterate as long as we have not reached our target iteration count.\n return this.currentIterationCount < this.targetIterationCount;\n }\n\n // If neither an iteration count or a condition function were defined then we can iterate indefinitely.\n return true;\n };\n\n /**\n * Sets the target iteration count.\n * @param options The behaviour tree options object.\n */\n private setTargetIterationCount = (options: BehaviourTreeOptions) => {\n // Are we dealing with an explicit iteration count or will we be randomly picking a iteration count between the min and max iteration count.\n if (this.iterations !== null) {\n this.targetIterationCount = this.iterations;\n } else if (this.iterationsMin !== null && this.iterationsMax !== null) {\n // We will be picking a random iteration count between a min and max iteration count, if the optional 'random'\n // behaviour tree function option is defined then we will be using that, otherwise we will fall back to using Math.random.\n const random = typeof options.random === \"function\" ? options.random : Math.random;\n\n // Pick a random iteration count between a min and max iteration count.\n this.targetIterationCount = Math.floor(\n random() * (this.iterationsMax - this.iterationsMin + 1) + this.iterationsMin\n );\n } else {\n this.targetIterationCount = null;\n }\n };\n}\n", "import Node from \"../Node\";\nimport Decorator from \"./Decorator\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A RETRY node.\n * The node has a single child which can have:\n * -- A number of iterations for which to repeat the child node.\n * -- An infinite repeat loop if neither an iteration count or a condition function is defined.\n * The RETRY node will stop and have a 'SUCCEEDED' state if its child is ever in a 'SUCCEEDED' state after an update.\n * The RETRY node will attempt to move on to the next iteration if its child is ever in a 'FAILED' state.\n */\nexport default class Retry extends Decorator {\n /**\n * @param attributes The node attributes.\n * @param attempts The number of attempts to retry the child node.\n * @param attemptsMin The minimum possible number of attempts to retry the child node.\n * @param attemptsMax The maximum possible number of attempts to retry the child node.\n * @param child The child node.\n */\n constructor(\n attributes: Attribute[],\n private attempts: number | null,\n private attemptsMin: number | null,\n private attemptsMax: number | null,\n child: Node\n ) {\n super(\"retry\", attributes, child);\n }\n\n /**\n * The number of target attempts to make.\n */\n private targetAttemptCount: number | null = null;\n\n /**\n * The current attempt count.\n */\n private currentAttemptCount: number = 0;\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // If this node is in the READY state then we need to reset the child and the target attempt count.\n if (this.is(State.READY)) {\n // Reset the child node.\n this.child.reset();\n\n // Reset the current attempt count.\n this.currentAttemptCount = 0;\n\n // Set the target attempt count.\n this.setTargetAttemptCount(options);\n }\n\n // Do a check to see if we can attempt. If we can then this node will move into the 'RUNNING' state.\n // If we cannot attempt then we have hit our target attempt count, which means that the node has succeeded.\n if (this.canAttempt()) {\n // This node is in the running state and can do its initial attempt.\n this.setState(State.RUNNING);\n\n // We may have already completed an attempt, meaning that the child node will be in the FAILED state.\n // If this is the case then we will have to reset the child node now.\n if (this.child.getState() === State.FAILED) {\n this.child.reset();\n }\n\n // Update the child of this node.\n this.child.update(agent, options);\n\n // If the child moved into the SUCCEEDED state when we updated it then there is nothing left to do and this node has also succeeded.\n // If it has moved into the FAILED state then we have completed the current attempt.\n if (this.child.getState() === State.SUCCEEDED) {\n // The child has succeeded, meaning that this node has succeeded.\n this.setState(State.SUCCEEDED);\n\n return;\n } else if (this.child.getState() === State.FAILED) {\n // We have completed an attempt.\n this.currentAttemptCount += 1;\n }\n } else {\n // This node is in the 'FAILED' state as we cannot iterate any more.\n this.setState(State.FAILED);\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => {\n if (this.attempts !== null) {\n return `RETRY ${this.attempts}x`;\n } else if (this.attemptsMin !== null && this.attemptsMax !== null) {\n return `RETRY ${this.attemptsMin}x-${this.attemptsMax}x`;\n } else {\n return \"RETRY\";\n }\n };\n\n /**\n * Reset the state of the node.\n */\n reset = () => {\n // Reset the state of this node.\n this.setState(State.READY);\n\n // Reset the current attempt count.\n this.currentAttemptCount = 0;\n\n // Reset the child node.\n this.child.reset();\n };\n\n /**\n * Gets whether an attempt can be made.\n * @returns Whether an attempt can be made.\n */\n canAttempt = () => {\n if (this.targetAttemptCount !== null) {\n // We can attempt as long as we have not reached our target attempt count.\n return this.currentAttemptCount < this.targetAttemptCount;\n }\n\n // If neither an attempt count or a condition function were defined then we can attempt indefinitely.\n return true;\n };\n\n /**\n * Sets the target attempt count.\n * @param options The behaviour tree options object.\n */\n setTargetAttemptCount = (options: BehaviourTreeOptions) => {\n // Are we dealing with an explicit attempt count or will we be randomly picking an attempt count between the min and max attempt count.\n if (this.attempts !== null) {\n this.targetAttemptCount = this.attempts;\n } else if (this.attemptsMin !== null && this.attemptsMax !== null) {\n // We will be picking a random attempt count between a min and max attempt count, if the optional 'random'\n // behaviour tree function option is defined then we will be using that, otherwise we will fall back to using Math.random.\n const random = typeof options.random === \"function\" ? options.random : Math.random;\n\n // Pick a random attempt count between a min and max attempt count.\n this.targetAttemptCount = Math.floor(\n random() * (this.attemptsMax - this.attemptsMin + 1) + this.attemptsMin\n );\n } else {\n this.targetAttemptCount = null;\n }\n };\n}\n", "import Node from \"../Node\";\nimport Decorator from \"./Decorator\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A Root node.\n * The root node will have a single child.\n */\nexport default class Root extends Decorator {\n /**\n * @param attributes The node attributes.\n * @param child The child node.\n */\n constructor(attributes: Attribute[], child: Node) {\n super(\"root\", attributes, child);\n }\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // If the child has never been updated or is running then we will need to update it now.\n if (this.child.getState() === State.READY || this.child.getState() === State.RUNNING) {\n // Update the child of this node.\n this.child.update(agent, options);\n }\n\n // The state of the root node is the state of its child.\n this.setState(this.child.getState());\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => \"ROOT\";\n}\n", "import Node from \"../Node\";\nimport Decorator from \"./Decorator\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A Succeed node.\n * This node wraps a single child and will always move to the 'SUCCEEDED' state when the child moves to a 'SUCCEEDED' or 'FAILED' state.\n */\nexport default class Succeed extends Decorator {\n /**\n * @param attributes The node attributes.\n * @param child The child node.\n */\n constructor(attributes: Attribute[], child: Node) {\n super(\"succeed\", attributes, child);\n }\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // If the child has never been updated or is running then we will need to update it now.\n if (this.child.getState() === State.READY || this.child.getState() === State.RUNNING) {\n this.child.update(agent, options);\n }\n\n // The state of this node will depend in the state of its child.\n switch (this.child.getState()) {\n case State.RUNNING:\n this.setState(State.RUNNING);\n break;\n\n case State.SUCCEEDED:\n case State.FAILED:\n this.setState(State.SUCCEEDED);\n break;\n\n default:\n this.setState(State.READY);\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => \"SUCCEED\";\n}\n", "import Node from \"../Node\";\n\n/**\n * A leaf node.\n */\nexport default abstract class Leaf extends Node {\n /**\n * Gets whether this node is a leaf node.\n */\n isLeafNode = () => true;\n}\n", "import { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\nimport State, { CompleteState } from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Leaf from \"./Leaf\";\nimport Lookup from \"../../Lookup\";\nimport Attribute from \"../../attributes/Attribute\";\n\n/**\n * The type representing a resolved/rejected update promise.\n */\ntype UpdatePromiseResult = {\n /**\n * Whether the promise was resolved rather than rejected.\n */\n isResolved: boolean;\n\n /**\n * The promise resolved value or rejection reason.\n */\n value: any;\n};\n\n/**\n * An Action leaf node.\n * This represents an immediate or ongoing state of behaviour.\n */\nexport default class Action extends Leaf {\n /**\n * @param attributes The node attributes.\n * @param actionName The action name.\n * @param actionArguments The array of action argument definitions.\n */\n constructor(attributes: Attribute[], private actionName: string, private actionArguments: any[]) {\n super(\"action\", attributes, actionArguments);\n }\n\n /**\n * Whether there is a pending update promise.\n */\n private isUsingUpdatePromise = false;\n\n /**\n * The finished state result of an update promise.\n */\n private updatePromiseResult: UpdatePromiseResult | null = null;\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // If the result of this action depends on an update promise then there is nothing to do until it settles.\n if (this.isUsingUpdatePromise) {\n // Are we still waiting for our update promise to settle?\n if (!this.updatePromiseResult) {\n return;\n }\n\n const { isResolved, value } = this.updatePromiseResult;\n\n // Our update promise settled, was it resolved or rejected?\n if (isResolved) {\n // Our promise resolved so check to make sure the result is a valid finished state.\n if (value !== State.SUCCEEDED && value !== State.FAILED) {\n throw new Error(\n \"action node promise resolved with an invalid value, expected a State.SUCCEEDED or State.FAILED value to be returned\"\n );\n }\n\n // Set the state of this node to match the state returned by the promise.\n this.setState(value);\n\n return;\n } else {\n // The promise was rejected, which isn't great.\n throw new Error(`action function '${this.actionName}' promise rejected with '${value}'`);\n }\n }\n\n // Attempt to get the invoker for the action function.\n const actionFuncInvoker = Lookup.getFuncInvoker(agent, this.actionName);\n\n // The action function should be defined.\n if (actionFuncInvoker === null) {\n throw new Error(\n `cannot update action node as the action '${this.actionName}' function is not defined on the agent and has not been registered`\n );\n }\n\n let actionFunctionResult;\n\n try {\n // Call the action function, the result of which may be:\n // - The finished state of this action node.\n // - A promise to return a finished node state.\n // - Undefined if the node should remain in the running state.\n actionFunctionResult = actionFuncInvoker(this.actionArguments) as CompleteState | Promise;\n } catch (error) {\n // The user was naughty and threw something.\n throw new Error(`action function '${this.actionName}' threw '${error}'`);\n }\n\n if (actionFunctionResult instanceof Promise) {\n actionFunctionResult.then(\n (result) => {\n // If 'isUpdatePromisePending' is not set then the promise was cleared as it was resolving, probably via an abort of reset.\n if (!this.isUsingUpdatePromise) {\n return;\n }\n\n // Set the resolved update promise result so that it can be handled on the next update of this node.\n this.updatePromiseResult = {\n isResolved: true,\n value: result\n };\n },\n (reason) => {\n // If 'isUpdatePromisePending' is not set then the promise was cleared as it was resolving, probably via an abort or reset.\n if (!this.isUsingUpdatePromise) {\n return;\n }\n\n // Set the rejected update promise result so that it can be handled on the next update of this node.\n this.updatePromiseResult = {\n isResolved: false,\n value: reason\n };\n }\n );\n\n // This node will be in the 'RUNNING' state until the update promise resolves.\n this.setState(State.RUNNING);\n\n // We are now waiting for the promise returned by the use to resolve before we know what state this node is in.\n this.isUsingUpdatePromise = true;\n } else {\n // Validate the returned value.\n this.validateUpdateResult(actionFunctionResult);\n\n // Set the state of this node, this may be undefined, which just means that the node is still in the 'RUNNING' state.\n this.setState(actionFunctionResult || State.RUNNING);\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => this.actionName;\n\n /**\n * Reset the state of the node.\n */\n reset = () => {\n // Reset the state of this node.\n this.setState(State.READY);\n\n // There is no longer an update promise that we care about.\n this.isUsingUpdatePromise = false;\n this.updatePromiseResult = null;\n };\n\n /**\n * Validate the result of an update function call.\n * @param result The result of an update function call.\n */\n private validateUpdateResult = (result: CompleteState | State.RUNNING) => {\n switch (result) {\n case State.SUCCEEDED:\n case State.FAILED:\n case State.RUNNING:\n case undefined:\n return;\n default:\n throw new Error(\n `expected action function '${this.actionName}' to return an optional State.SUCCEEDED or State.FAILED value but returned '${result}'`\n );\n }\n };\n}\n", "import { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Leaf from \"./Leaf\";\nimport Lookup from \"../../Lookup\";\nimport Attribute from \"../../attributes/Attribute\";\n\n/**\n * A Condition leaf node.\n * This will succeed or fail immediately based on an agent predicate, without moving to the 'RUNNING' state.\n */\nexport default class Condition extends Leaf {\n /**\n * @param attributes The node attributes.\n * @param conditionName The name of the condition function.\n * @param conditionArguments The array of condition argument definitions.\n */\n constructor(attributes: Attribute[], private conditionName: string, private conditionArguments: any[]) {\n super(\"condition\", attributes, conditionArguments);\n }\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // Attempt to get the invoker for the condition function.\n const conditionFuncInvoker = Lookup.getFuncInvoker(agent, this.conditionName);\n\n // The condition function should be defined.\n if (conditionFuncInvoker === null) {\n throw new Error(\n `cannot update condition node as the condition '${this.conditionName}' function is not defined on the agent and has not been registered`\n );\n }\n\n let conditionFunctionResult;\n\n try {\n // Call the condition function to determine the state of this node, the result of which should be a boolean.\n conditionFunctionResult = conditionFuncInvoker(this.conditionArguments);\n } catch (error) {\n // The user was naughty and threw something.\n throw new Error(`condition function '${this.conditionName}' threw '${error}'`);\n }\n\n // The result of calling the condition function must be a boolean value.\n if (typeof conditionFunctionResult !== \"boolean\") {\n throw new Error(\n `expected condition function '${this.conditionName}' to return a boolean but returned '${conditionFunctionResult}'`\n );\n }\n\n // Set the state of this node based on the result of calling the condition function.\n this.setState(!!conditionFunctionResult ? State.SUCCEEDED : State.FAILED);\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => this.conditionName;\n}\n", "import Leaf from \"./Leaf\";\nimport State from \"../../State\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { Agent } from \"../../Agent\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A WAIT node.\n * The state of this node will change to SUCCEEDED after a duration of time\n */\nexport default class Wait extends Leaf {\n /**\n * @param attributes The node attributes.\n * @param duration The duration that this node will wait to succeed in milliseconds.\n * @param durationMin The minimum possible duration in milliseconds that this node will wait to succeed.\n * @param durationMax The maximum possible duration in milliseconds that this node will wait to succeed.\n */\n constructor(\n attributes: Attribute[],\n private duration: number | null,\n private durationMin: number | null,\n private durationMax: number | null\n ) {\n super(\"wait\", attributes, []);\n }\n\n /**\n * The time in milliseconds at which this node was first updated.\n */\n private initialUpdateTime: number = 0;\n\n /**\n * The total duration in milliseconds that this node will be waiting for.\n */\n private totalDuration: number | null = null;\n\n /**\n * The duration in milliseconds that this node has been waiting for.\n */\n private waitedDuration: number = 0;\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // If this node is in the READY state then we need to set the initial update time.\n if (this.is(State.READY)) {\n // Set the initial update time.\n this.initialUpdateTime = new Date().getTime();\n\n // Set the initial waited duration.\n this.waitedDuration = 0;\n\n // Are we dealing with an explicit duration or will we be randomly picking a duration between the min and max duration.\n if (this.duration !== null) {\n this.totalDuration = this.duration;\n } else if (this.durationMin !== null && this.durationMax !== null) {\n // We will be picking a random duration between a min and max duration, if the optional 'random' behaviour tree\n // function option is defined then we will be using that, otherwise we will fall back to using Math.random.\n const random = typeof options.random === \"function\" ? options.random : Math.random;\n\n // Pick a random duration between a min and max duration.\n this.totalDuration = Math.floor(\n random() * (this.durationMax - this.durationMin + 1) + this.durationMin\n );\n } else {\n this.totalDuration = null;\n }\n\n // The node is now running until we finish waiting.\n this.setState(State.RUNNING);\n }\n\n // If we have no total duration then this wait node will wait indefinitely until it is aborted.\n if (this.totalDuration === null) {\n return;\n }\n\n // If we have a 'getDeltaTime' function defined as part of our options then we will use it to figure out how long we have waited for.\n if (typeof options.getDeltaTime === \"function\") {\n // Get the delta time.\n const deltaTime = options.getDeltaTime();\n\n // Our delta time must be a valid number and cannot be NaN.\n if (typeof deltaTime !== \"number\" || isNaN(deltaTime)) {\n throw new Error(\"The delta time must be a valid number and not NaN.\");\n }\n\n // Update the amount of time that this node has been waiting for based on the delta time.\n this.waitedDuration += deltaTime * 1000;\n } else {\n // We are not using a delta time, so we will just work out hom much time has passed since the first update.\n this.waitedDuration = new Date().getTime() - this.initialUpdateTime;\n }\n\n // Have we waited long enough?\n if (this.waitedDuration >= this.totalDuration) {\n // We have finished waiting!\n this.setState(State.SUCCEEDED);\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => {\n if (this.duration !== null) {\n return `WAIT ${this.duration}ms`;\n } else if (this.durationMin !== null && this.durationMax !== null) {\n return `WAIT ${this.durationMin}ms-${this.durationMax}ms`;\n } else {\n return \"WAIT\";\n }\n };\n}\n", "import Guard from \"./guards/Guard\";\n\nexport type AttributeDetails = {\n /** The attribute type. */\n type: string;\n\n /** The attribute arguments. */\n args: any[];\n};\n\n/**\n * A base node attribute.\n */\nexport default abstract class Attribute {\n /**\n * @param type The node attribute type.\n * @param args The array of attribute arguments.\n */\n constructor(public type: string, public args: any[]) {}\n\n /**\n * Gets the attribute details.\n */\n abstract getDetails(): TAttributeDetails;\n\n /**\n * Gets whether this attribute is a guard.\n */\n abstract isGuard: () => this is Guard;\n}\n", "import { Agent } from \"../../Agent\";\nimport Attribute, { AttributeDetails } from \"../Attribute\";\n\nexport type GuardAttributeDetails = {\n /** The name of the condition function that determines whether the guard is satisfied. */\n condition: string;\n} & AttributeDetails;\n\n/**\n * A base node guard attribute.\n */\nexport default abstract class Guard extends Attribute {\n /**\n * @param type The node attribute type.\n * @param args The array of decorator argument definitions.\n * @param condition The name of the condition function that determines whether the guard is satisfied.\n */\n constructor(type: string, args: any[], private condition: string) {\n super(type, args);\n }\n\n /**\n * Gets the name of the condition function that determines whether the guard is satisfied.\n */\n getCondition = () => this.condition;\n\n /**\n * Gets whether this attribute is a guard.\n */\n isGuard = () => true;\n\n /**\n * Gets the attribute details.\n */\n getDetails(): GuardAttributeDetails {\n return {\n type: this.type,\n args: this.args,\n condition: this.getCondition()\n };\n }\n\n /**\n * Gets whether the guard is satisfied.\n * @param agent The agent.\n * @returns Whether the guard is satisfied.\n */\n abstract isSatisfied(agent: Agent): boolean;\n}\n", "import Guard from \"./Guard\";\nimport Lookup from \"../../Lookup\";\nimport { Agent } from \"../../Agent\";\n\n/**\n * A WHILE guard which is satisfied as long as the given condition remains true.\n */\nexport default class While extends Guard {\n /**\n * @param condition The name of the condition function that determines whether the guard is satisfied.\n * @param args The array of decorator argument definitions.\n */\n constructor(condition: string, args: any[]) {\n super(\"while\", args, condition);\n }\n\n /**\n * Gets whether the guard is satisfied.\n * @param agent The agent.\n * @returns Whether the guard is satisfied.\n */\n isSatisfied = (agent: Agent) => {\n // Attempt to get the invoker for the condition function.\n const conditionFuncInvoker = Lookup.getFuncInvoker(agent, this.getCondition());\n\n // The condition function should be defined.\n if (conditionFuncInvoker === null) {\n throw new Error(\n `cannot evaluate node guard as the condition '${this.getCondition()}' function is not defined on the agent and has not been registered`\n );\n }\n\n // Call the condition function to determine whether this guard is satisfied.\n return !!conditionFuncInvoker(this.args);\n };\n}\n", "import Guard from \"./Guard\";\nimport Lookup from \"../../Lookup\";\nimport { Agent } from \"../../Agent\";\n\n/**\n * An UNTIL guard which is satisfied as long as the given condition remains false.\n */\nexport default class Until extends Guard {\n /**\n * @param condition The name of the condition function that determines whether the guard is satisfied.\n * @param args The array of decorator argument definitions.\n */\n constructor(condition: string, args: any[]) {\n super(\"until\", args, condition);\n }\n\n /**\n * Gets whether the guard is satisfied.\n * @param agent The agent.\n * @returns Whether the guard is satisfied.\n */\n isSatisfied = (agent: Agent) => {\n // Attempt to get the invoker for the condition function.\n const conditionFuncInvoker = Lookup.getFuncInvoker(agent, this.getCondition());\n\n // The condition function should be defined.\n if (conditionFuncInvoker === null) {\n throw new Error(\n `cannot evaluate node guard as the condition '${this.getCondition()}' function is not defined on the agent and has not been registered`\n );\n }\n\n // Call the condition function to determine whether this guard is satisfied.\n return !!!conditionFuncInvoker(this.args);\n };\n}\n", "import { Agent } from \"../../Agent\";\nimport Attribute, { AttributeDetails } from \"../Attribute\";\n\nexport type CallbackAttributeDetails = {\n /** The name of the agent function that is called. */\n functionName: string;\n} & AttributeDetails;\n\n/**\n * A base node callback attribute.\n */\nexport default abstract class Callback extends Attribute {\n /**\n * @param type The node attribute type.\n * @param args The array of decorator argument definitions.\n * @param functionName The name of the agent function to call.\n */\n constructor(type: string, args: any[], private functionName: string) {\n super(type, args);\n }\n\n /**\n * Gets the name of the agent function to call.\n */\n getFunctionName = () => this.functionName;\n\n /**\n * Gets whether this attribute is a guard.\n */\n isGuard = () => false;\n\n /**\n * Gets the attribute details.\n */\n getDetails(): CallbackAttributeDetails {\n return {\n type: this.type,\n args: this.args,\n functionName: this.getFunctionName()\n };\n }\n\n /**\n * Attempt to call the agent function that this callback refers to.\n * @param agent The agent.\n */\n abstract callAgentFunction: (agent: Agent, isSuccess: boolean, isAborted: boolean) => void;\n}\n", "import Callback from \"./Callback\";\nimport Lookup from \"../../Lookup\";\nimport { Agent } from \"../../Agent\";\n\n/**\n * An ENTRY callback which defines an agent function to call when the associated node is updated and moves out of running state.\n */\nexport default class Entry extends Callback {\n /**\n * @param functionName The name of the agent function to call.\n * @param args The array of callback argument definitions.\n */\n constructor(functionName: string, args: any[]) {\n super(\"entry\", args, functionName);\n }\n\n /**\n * Attempt to call the agent function that this callback refers to.\n * @param agent The agent.\n */\n callAgentFunction = (agent: Agent) => {\n // Attempt to get the invoker for the callback function.\n const callbackFuncInvoker = Lookup.getFuncInvoker(agent, this.getFunctionName());\n\n // The callback function should be defined.\n if (callbackFuncInvoker === null) {\n throw new Error(\n `cannot call entry function '${this.getFunctionName()}' as is not defined on the agent and has not been registered`\n );\n }\n\n // Call the callback function.\n callbackFuncInvoker(this.args);\n };\n}\n", "import Callback from \"./Callback\";\nimport Lookup from \"../../Lookup\";\nimport { Agent } from \"../../Agent\";\n\n/**\n * A STEP callback which defines an agent function to call when the associated node is updated.\n */\nexport default class Step extends Callback {\n /**\n * @param functionName The name of the agent function to call.\n * @param args The array of callback argument definitions.\n */\n constructor(functionName: string, args: any[]) {\n super(\"step\", args, functionName);\n }\n\n /**\n * Attempt to call the agent function that this callback refers to.\n * @param agent The agent.\n */\n callAgentFunction = (agent: Agent) => {\n // Attempt to get the invoker for the callback function.\n const callbackFuncInvoker = Lookup.getFuncInvoker(agent, this.getFunctionName());\n\n // The callback function should be defined.\n if (callbackFuncInvoker === null) {\n throw new Error(\n `cannot call step function '${this.getFunctionName()}' as is not defined on the agent and has not been registered`\n );\n }\n\n // Call the callback function.\n callbackFuncInvoker(this.args);\n };\n}\n", "import Callback from \"./Callback\";\nimport Lookup from \"../../Lookup\";\nimport { Agent } from \"../../Agent\";\n\n/**\n * An EXIT callback which defines an agent function to call when the associated node is updated and moves to a finished state or is aborted.\n */\nexport default class Exit extends Callback {\n /**\n * @param functionName The name of the agent function to call.\n * @param args The array of callback argument definitions.\n */\n constructor(functionName: string, args: any[]) {\n super(\"exit\", args, functionName);\n }\n\n /**\n * Attempt to call the agent function that this callback refers to.\n * @param agent The agent.\n * @param isSuccess Whether the decorated node was left with a success state.\n * @param isAborted Whether the decorated node was aborted.\n */\n callAgentFunction = (agent: Agent, isSuccess: boolean, isAborted: boolean) => {\n // Attempt to get the invoker for the callback function.\n const callbackFuncInvoker = Lookup.getFuncInvoker(agent, this.getFunctionName());\n\n // The callback function should be defined.\n if (callbackFuncInvoker === null) {\n throw new Error(\n `cannot call exit function '${this.getFunctionName()}' as is not defined on the agent and has not been registered`\n );\n }\n\n // Call the callback function\n callbackFuncInvoker([{ succeeded: isSuccess, aborted: isAborted }, ...this.args]);\n };\n}\n", "import { AnyNodeDefinition, RootNodeDefinition } from \"./BehaviourTreeDefinition\";\nimport GuardPath, { GuardPathPart } from \"./attributes/guards/GuardPath\";\nimport { validateBranchSubtreeLinks } from \"./BehaviourTreeDefinitionValidator\";\nimport { isInteger } from \"./BehaviourTreeDefinitionUtilities\";\nimport Node from \"./nodes/Node\";\nimport Composite from \"./nodes/composite/Composite\";\nimport Decorator from \"./nodes/decorator/Decorator\";\nimport Parallel from \"./nodes/composite/Parallel\";\nimport Selector from \"./nodes/composite/Selector\";\nimport Sequence from \"./nodes/composite/Sequence\";\nimport Lotto from \"./nodes/composite/Lotto\";\nimport Fail from \"./nodes/decorator/Fail\";\nimport Flip from \"./nodes/decorator/Flip\";\nimport Repeat from \"./nodes/decorator/Repeat\";\nimport Retry from \"./nodes/decorator/Retry\";\nimport Root from \"./nodes/decorator/Root\";\nimport Succeed from \"./nodes/decorator/Succeed\";\nimport Action from \"./nodes/leaf/Action\";\nimport Condition from \"./nodes/leaf/Condition\";\nimport Wait from \"./nodes/leaf/Wait\";\nimport Lookup from \"./Lookup\";\nimport Attribute from \"./attributes/Attribute\";\nimport While from \"./attributes/guards/While\";\nimport Until from \"./attributes/guards/Until\";\nimport Entry from \"./attributes/callbacks/Entry\";\nimport Step from \"./attributes/callbacks/Step\";\nimport Exit from \"./attributes/callbacks/Exit\";\n\n/**\n * A type representing any node instance in a behaviour tree.\n */\ntype AnyNode =\n | Root\n | Action\n | Condition\n | Wait\n | Sequence\n | Selector\n | Lotto\n | Parallel\n | Repeat\n | Retry\n | Flip\n | Succeed\n | Fail;\n\n/**\n * A type defining a mapping of root node identifiers to root node definitions.\n */\ntype RootNodeDefinitionMap = { [key: string | symbol]: RootNodeDefinition };\n\n/**\n * A symbol to use as the main root key in any root node mappings.\n */\nconst MAIN_ROOT_NODE_KEY = Symbol(\"__root__\");\n\n/**\n * Build and populate the root nodes based on the provided definition, assuming that the definition has been validated.\n * @param definition The root node definitions.\n * @returns The built and populated root node definitions.\n */\nexport default function buildRootNode(definition: RootNodeDefinition[]): Root {\n // Create a mapping of root node identifers to root node definitions, including globally registered subtree root node definitions.\n const rootNodeDefinitionMap = createRootNodeDefinitionMap(definition);\n\n // Now that we have all of our root node definitions (those part of the tree definition and those globally registered)\n // we should validate the branch-subtree links. This will also double-check that we dont have any circular dependencies\n // in our branch-subtree references and that we have no broken branch-subtree links.\n validateBranchSubtreeLinks(\n [rootNodeDefinitionMap[MAIN_ROOT_NODE_KEY], ...Object.values(rootNodeDefinitionMap)],\n true\n );\n\n // Create our populated tree of node instances, starting with our main root node.\n const rootNode = nodeFactory(rootNodeDefinitionMap[MAIN_ROOT_NODE_KEY], rootNodeDefinitionMap) as Root;\n\n // Set a guard path on every leaf of the tree to evaluate as part of each update.\n applyLeafNodeGuardPaths(rootNode);\n\n // We only need to return the main root node.\n return rootNode;\n}\n\n/**\n * A factory function which creates a node instance based on the specified definition.\n * @param definition The node definition.\n * @param rootNodeDefinitionMap The mapping of root node identifers to root node definitions, including globally registered subtree root node definitions.\n * @returns A node instance based on the specified definition.\n */\nfunction nodeFactory(definition: AnyNodeDefinition, rootNodeDefinitionMap: RootNodeDefinitionMap): AnyNode {\n // Get the attributes for the node.\n const attributes = nodeAttributesFactory(definition);\n\n // Create the node instance based on the definition type.\n switch (definition.type) {\n case \"root\":\n return new Root(attributes, nodeFactory(definition.child, rootNodeDefinitionMap));\n\n case \"repeat\":\n let iterations: number | null = null;\n let iterationsMin: number | null = null;\n let iterationsMax: number | null = null;\n\n if (Array.isArray(definition.iterations)) {\n iterationsMin = definition.iterations[0];\n iterationsMax = definition.iterations[1];\n } else if (isInteger(definition.iterations)) {\n iterations = definition.iterations!;\n }\n\n return new Repeat(\n attributes,\n iterations,\n iterationsMin,\n iterationsMax,\n nodeFactory(definition.child, rootNodeDefinitionMap)\n );\n\n case \"retry\":\n let attempts: number | null = null;\n let attemptsMin: number | null = null;\n let attemptsMax: number | null = null;\n\n if (Array.isArray(definition.attempts)) {\n attemptsMin = definition.attempts[0];\n attemptsMax = definition.attempts[1];\n } else if (isInteger(definition.attempts)) {\n attempts = definition.attempts!;\n }\n\n return new Retry(\n attributes,\n attempts,\n attemptsMin,\n attemptsMax,\n nodeFactory(definition.child, rootNodeDefinitionMap)\n );\n\n case \"flip\":\n return new Flip(attributes, nodeFactory(definition.child, rootNodeDefinitionMap));\n\n case \"succeed\":\n return new Succeed(attributes, nodeFactory(definition.child, rootNodeDefinitionMap));\n\n case \"fail\":\n return new Fail(attributes, nodeFactory(definition.child, rootNodeDefinitionMap));\n\n case \"sequence\":\n return new Sequence(\n attributes,\n definition.children.map((child) => nodeFactory(child, rootNodeDefinitionMap))\n );\n\n case \"selector\":\n return new Selector(\n attributes,\n definition.children.map((child) => nodeFactory(child, rootNodeDefinitionMap))\n );\n\n case \"parallel\":\n return new Parallel(\n attributes,\n definition.children.map((child) => nodeFactory(child, rootNodeDefinitionMap))\n );\n\n case \"lotto\":\n return new Lotto(\n attributes,\n definition.weights,\n definition.children.map((child) => nodeFactory(child, rootNodeDefinitionMap))\n );\n\n case \"branch\":\n return nodeFactory(rootNodeDefinitionMap[definition.ref].child, rootNodeDefinitionMap);\n\n case \"action\":\n return new Action(attributes, definition.call, definition.args || []);\n\n case \"condition\":\n return new Condition(attributes, definition.call, definition.args || []);\n\n case \"wait\":\n let duration: number | null = null;\n let durationMin: number | null = null;\n let durationMax: number | null = null;\n\n if (Array.isArray(definition.duration)) {\n durationMin = definition.duration[0];\n durationMax = definition.duration[1];\n } else if (isInteger(definition.duration)) {\n duration = definition.duration!;\n }\n\n return new Wait(attributes, duration, durationMin, durationMax);\n }\n}\n\n/**\n * Creates an array of node attribute instances based on the specified node definition.\n * @param definition The node definition.\n * @returns An array of node attribute instances based on the specified node definition.\n */\nfunction nodeAttributesFactory(definition: AnyNodeDefinition): Attribute[] {\n const attributes: Attribute[] = [];\n\n if (definition.while) {\n attributes.push(new While(definition.while.call, definition.while.args ?? []));\n }\n\n if (definition.until) {\n attributes.push(new Until(definition.until.call, definition.until.args ?? []));\n }\n\n if (definition.entry) {\n attributes.push(new Entry(definition.entry.call, definition.entry.args ?? []));\n }\n\n if (definition.step) {\n attributes.push(new Step(definition.step.call, definition.step.args ?? []));\n }\n\n if (definition.exit) {\n attributes.push(new Exit(definition.exit.call, definition.exit.args ?? []));\n }\n\n return attributes;\n}\n\n/**\n * Creates a mapping of root node identifers to root node definitions, mixing in globally registered subtree root node definitions.\n * @param definition The root node definitions.\n * @returns A mapping of root node identifers to root node definitions, including globally registered subtree root node definitions.\n */\nfunction createRootNodeDefinitionMap(definition: RootNodeDefinition[]): RootNodeDefinitionMap {\n // Create a mapping of root node identifers to root node definitions.\n const rootNodeMap: RootNodeDefinitionMap = {};\n\n // Add in any registered subtree root node definitions.\n for (const [name, rootNodeDefinition] of Object.entries(Lookup.getSubtrees())) {\n // The name used when registering the subtree will be used as the root node identifier.\n rootNodeMap[name] = { ...rootNodeDefinition, id: name };\n }\n\n // Populate the map with the root node definitions that were included with the tree definition.\n // We do this after adding any registered subtrees as we want these to take presedence.\n for (const rootNodeDefinition of definition) {\n rootNodeMap[rootNodeDefinition.id ?? MAIN_ROOT_NODE_KEY] = rootNodeDefinition;\n }\n\n return rootNodeMap;\n}\n\n/**\n * Applies a guard path to every leaf of the tree to evaluate as part of each update.\n * @param root The main root tree node.\n */\nfunction applyLeafNodeGuardPaths(root: Root) {\n const nodePaths: Node[][] = [];\n\n const findLeafNodes = (path: Node[], node: Node) => {\n // Add the current node to the path.\n path = path.concat(node);\n\n // Check whether the current node is a leaf node.\n if (node.isLeafNode()) {\n nodePaths.push(path);\n } else {\n (node as Composite | Decorator).getChildren().forEach((child) => findLeafNodes(path, child));\n }\n };\n\n // Find all leaf node paths, starting from the root.\n findLeafNodes([], root);\n\n nodePaths.forEach((path) => {\n // Each node in the current path will have to be assigned a guard path, working from the root outwards.\n for (let depth = 0; depth < path.length; depth++) {\n // Get the node in the path at the current depth.\n const currentNode = path[depth];\n\n // The node may already have been assigned a guard path, if so just skip it.\n if (currentNode.hasGuardPath()) {\n continue;\n }\n\n // Create the guard path for the current node.\n const guardPath = new GuardPath(\n path\n .slice(0, depth + 1)\n .map((node) => ({ node, guards: node.getGuardAttributes() }))\n .filter((details) => details.guards.length > 0)\n );\n\n // Assign the guard path to the current node.\n currentNode.setGuardPath(guardPath);\n }\n });\n}\n", "import State, { AnyState } from \"./State\";\nimport Lookup from \"./Lookup\";\nimport Node from \"./nodes/Node\";\nimport Root from \"./nodes/decorator/Root\";\nimport Composite from \"./nodes/composite/Composite\";\nimport Decorator from \"./nodes/decorator/Decorator\";\nimport { Agent, GlobalFunction } from \"./Agent\";\nimport { CallbackAttributeDetails } from \"./attributes/callbacks/Callback\";\nimport { GuardAttributeDetails } from \"./attributes/guards/Guard\";\nimport { BehaviourTreeOptions } from \"./BehaviourTreeOptions\";\nimport { convertMDSLToJSON } from \"./mdsl/MDSLDefinitionParser\";\nimport { RootNodeDefinition } from \"./BehaviourTreeDefinition\";\nimport { validateDefinition, validateJSONDefinition } from \"./BehaviourTreeDefinitionValidator\";\nimport buildRootNode from \"./BehaviourTreeBuilder\";\nimport { isNullOrUndefined } from \"./BehaviourTreeDefinitionUtilities\";\n\n// Purely for outside inspection of the tree.\nexport type FlattenedTreeNode = {\n id: string;\n type: string;\n caption: string;\n state: AnyState;\n guards: GuardAttributeDetails[];\n callbacks: CallbackAttributeDetails[];\n args: any[];\n parentId: string | null;\n};\n\n/**\n * A representation of a behaviour tree.\n */\nexport class BehaviourTree {\n /**\n * The main root tree node.\n */\n private readonly _rootNode: Root;\n\n /**\n * Creates a new instance of the BehaviourTree class.\n * @param definition The behaviour tree definition as either an MDSL string, root node definition object or array of root node definition objects.\n * @param agent The agent instance that this behaviour tree is modelling behaviour for.\n * @param options The behaviour tree options object.\n */\n constructor(\n definition: string | RootNodeDefinition | RootNodeDefinition[],\n private agent: Agent,\n private options: BehaviourTreeOptions = {}\n ) {\n // The tree definition must be defined.\n if (isNullOrUndefined(definition)) {\n throw new Error(\"tree definition not defined\");\n }\n\n // The agent must be defined and not null.\n if (typeof agent !== \"object\" || agent === null) {\n throw new Error(\"the agent must be an object and not null\");\n }\n\n // We should validate the definition before we try to build the tree nodes.\n const { succeeded, errorMessage, json } = validateDefinition(definition);\n\n // Did our validation fail without error?\n if (!succeeded) {\n throw new Error(`invalid definition: ${errorMessage}`);\n }\n\n // Double check that we did actually get our json definition as part of our definition validtion.\n if (!json) {\n throw new Error(\n \"expected json definition to be returned as part of successful definition validation response\"\n );\n }\n\n try {\n // Create the populated tree of behaviour tree nodes and get the root node.\n this._rootNode = buildRootNode(json);\n } catch (exception) {\n // There was an issue in trying build and populate the behaviour tree.\n throw new Error(`error building tree: ${(exception as Error).message}`);\n }\n }\n\n /**\n * Gets whether the tree is in the RUNNING state.\n * @returns true if the tree is in the RUNNING state, otherwise false.\n */\n isRunning() {\n return this._rootNode.getState() === State.RUNNING;\n }\n\n /**\n * Gets the current tree state of SUCCEEDED, FAILED, READY or RUNNING.\n * @returns The current tree state.\n */\n getState() {\n return this._rootNode.getState();\n }\n\n /**\n * Step the tree.\n * 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.\n * 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\n * 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.\n *\n * 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.\n */\n step() {\n // If the root node has already been stepped to completion then we need to reset it.\n if (this._rootNode.getState() === State.SUCCEEDED || this._rootNode.getState() === State.FAILED) {\n this._rootNode.reset();\n }\n\n try {\n this._rootNode.update(this.agent, this.options);\n } catch (exception) {\n throw new Error(`error stepping tree: ${(exception as Error).message}`);\n }\n }\n\n /**\n * Resets the tree from the root node outwards to each nested node, giving each a state of READY.\n */\n reset() {\n this._rootNode.reset();\n }\n\n /**\n * Gets the flattened details of every node in the tree.\n * @returns The flattened details of every node in the tree.\n */\n getFlattenedNodeDetails(): FlattenedTreeNode[] {\n // Create an empty flattened array of tree nodes.\n const flattenedTreeNodes: FlattenedTreeNode[] = [];\n\n /**\n * Helper function to process a node instance and push details into the flattened tree nodes array.\n * @param node The current node.\n * @param parentUid The UID of the node parent, or null if the node is the main root node.\n */\n const processNode = (node: Node, parentUid: string | null) => {\n // Get the guard and callback attribute details for this node.\n const guards = node\n .getAttributes()\n .filter((attribute) => attribute.isGuard())\n .map((attribute) => attribute.getDetails()) as GuardAttributeDetails[];\n const callbacks = node\n .getAttributes()\n .filter((attribute) => !attribute.isGuard())\n .map((attribute) => attribute.getDetails()) as CallbackAttributeDetails[];\n\n // Push the current node into the flattened nodes array.\n flattenedTreeNodes.push({\n id: node.getUid(),\n type: node.getType(),\n caption: node.getName(),\n state: node.getState(),\n guards,\n callbacks,\n args: node.getArguments(),\n parentId: parentUid\n });\n\n // Process each of the nodes children if it is not a leaf node.\n if (!node.isLeafNode()) {\n (node as Composite | Decorator)\n .getChildren()\n .forEach((child) => processNode(child, (node as Composite | Decorator).getUid()));\n }\n };\n\n // Convert the nested node structure into a flattened array of node details.\n processNode(this._rootNode, null);\n\n return flattenedTreeNodes;\n }\n\n /**\n * Registers the action/condition/guard/callback function or subtree with the given name.\n * @param name The name of the function or subtree to register.\n * @param value The function or subtree definition to register.\n */\n static register(name: string, value: GlobalFunction | string | RootNodeDefinition) {\n // Are we going to register a action/condition/guard/callback function?\n if (typeof value === \"function\") {\n Lookup.setFunc(name, value);\n return;\n }\n\n // We are not registering an action/condition/guard/callback function, so we must be registering a subtree.\n if (typeof value === \"string\") {\n let rootNodeDefinitions: RootNodeDefinition[];\n\n // We will assume that any string passed in will be a mdsl definition.\n try {\n rootNodeDefinitions = convertMDSLToJSON(value);\n } catch (exception) {\n throw new Error(`error registering definition, invalid MDSL: ${(exception as Error).message}`);\n }\n\n // This function should only ever be called with a definition containing a single unnamed root node.\n if (rootNodeDefinitions.length != 1 || rootNodeDefinitions[0].id !== null) {\n throw new Error(\"error registering definition: expected a single unnamed root node\");\n }\n\n try {\n // We should validate the subtree as we don't want invalid subtrees available via the lookup.\n const { succeeded, errorMessage } = validateJSONDefinition(rootNodeDefinitions[0]);\n\n // Did our validation fail without error?\n if (!succeeded) {\n throw new Error(errorMessage);\n }\n } catch (exception) {\n throw new Error(`error registering definition: ${(exception as Error).message}`);\n }\n\n // Everything seems hunky-dory, register the subtree.\n Lookup.setSubtree(name, rootNodeDefinitions[0]);\n } else if (typeof value === \"object\" && !Array.isArray(value)) {\n // We will assume that any object passed in is a root node definition.\n\n try {\n // We should validate the subtree as we don't want invalid subtrees available via the lookup.\n const { succeeded, errorMessage } = validateJSONDefinition(value);\n\n // Did our validation fail without error?\n if (!succeeded) {\n throw new Error(errorMessage);\n }\n } catch (exception) {\n throw new Error(`error registering definition: ${(exception as Error).message}`);\n }\n\n // Everything seems hunky-dory, register the subtree.\n Lookup.setSubtree(name, value);\n } else {\n throw new Error(\"unexpected value, expected string mdsl definition, root node json definition or function\");\n }\n }\n\n /**\n * Unregisters the registered action/condition/guard/callback function or subtree with the given name.\n * @param name The name of the registered action/condition/guard/callback function or subtree to unregister.\n */\n static unregister(name: string): void {\n Lookup.remove(name);\n }\n\n /**\n * Unregister all registered action/condition/guard/callback functions and subtrees.\n */\n static unregisterAll(): void {\n Lookup.empty();\n }\n}\n"], - "mappings": "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", + "sourcesContent": ["\"use strict\";\r\nObject.defineProperty(exports, \"__esModule\", { value: true });\r\nexports.Participant = void 0;\r\n/**\r\n * A participant that holds a number of tickets.\r\n */\r\nvar Participant = /** @class */ (function () {\r\n /**\r\n * Creates an instance of the Participant class.\r\n * @param participant The actual participant.\r\n * @param tickets The number of tickets held by the participant.\r\n */\r\n function Participant(participant, tickets) {\r\n if (tickets === void 0) { tickets = 1; }\r\n this._participant = participant;\r\n this._tickets = tickets;\r\n }\r\n Object.defineProperty(Participant.prototype, \"participant\", {\r\n /** Gets the actual participant. */\r\n get: function () {\r\n return this._participant;\r\n },\r\n enumerable: false,\r\n configurable: true\r\n });\r\n Object.defineProperty(Participant.prototype, \"tickets\", {\r\n /** Gets or sets the number of tickets held by the participant. */\r\n get: function () {\r\n return this._tickets;\r\n },\r\n set: function (value) {\r\n this._tickets = value;\r\n },\r\n enumerable: false,\r\n configurable: true\r\n });\r\n return Participant;\r\n}());\r\nexports.Participant = Participant;\r\n", "\"use strict\";\r\nObject.defineProperty(exports, \"__esModule\", { value: true });\r\nexports.isNaturalNumber = exports.isNullOrUndefined = void 0;\r\n/**\r\n * Gets whether the value provided is null or undefined.\r\n * @param value The value to check.\r\n * @returns Whether the value provided is null or undefined.\r\n */\r\nfunction isNullOrUndefined(value) {\r\n return value === null || value === undefined;\r\n}\r\nexports.isNullOrUndefined = isNullOrUndefined;\r\n/**\r\n * Gets whether the value provided is a natural number.\r\n * @param value The value to check.\r\n * @returns Whether the value provided is a natural number.\r\n */\r\nfunction isNaturalNumber(value) {\r\n return typeof value === \"number\" && value >= 1 && Math.floor(value) === value;\r\n}\r\nexports.isNaturalNumber = isNaturalNumber;\r\n", "\"use strict\";\r\nObject.defineProperty(exports, \"__esModule\", { value: true });\r\nexports.Lotto = void 0;\r\nvar Participant_1 = require(\"./Participant\");\r\nvar Utilities_1 = require(\"./Utilities\");\r\n/**\r\n * Represents a lotto consisting of a number of pickable ticket-holding participants.\r\n */\r\nvar Lotto = /** @class */ (function () {\r\n /**\r\n * Creates a new instance of Lotto.\r\n * @param customRandom The custom RNG to use in place of Math.random().\r\n */\r\n function Lotto(customRandom) {\r\n /** The array of participants that are holding tickets in the lotto. */\r\n this._participants = [];\r\n this._customRandom = customRandom;\r\n }\r\n /**\r\n * Adds a participant with the specified number of tickets, or adds to the participant ticket count if the participant already holds tickets.\r\n * @param participant The participant to add or to increase the ticket count for if they already hold tickets.\r\n * @param tickets The number of tickets, defaults to 1.\r\n * @returns The Lotto instance.\r\n */\r\n Lotto.prototype.add = function (participant, tickets) {\r\n if (tickets === void 0) { tickets = 1; }\r\n // Check that we have a valid ticket count.\r\n if (!(0, Utilities_1.isNaturalNumber)(tickets)) {\r\n throw new Error(\"tickets value must be a natural number\");\r\n }\r\n // Check whether this participant has already been added.\r\n var existingParticipant = this._participants.find(function (part) { return part.participant === participant; });\r\n if (existingParticipant) {\r\n // The participant has already been added to the lotto so just add to their ticket count.\r\n existingParticipant.tickets += tickets;\r\n }\r\n else {\r\n // The participant is not part of the lotto so we should add them.\r\n this._participants.push(new Participant_1.Participant(participant, tickets));\r\n }\r\n return this;\r\n };\r\n /**\r\n * Removes the specified number of tickets for the given participant from the draw, or all tickets if a ticket number is not defined.\r\n * @param participant The participant to remove tickets for.\r\n * @param tickets The number of tickets to remove, or undefined if all tickets are to be removed.\r\n * @returns The Lotto instance.\r\n */\r\n Lotto.prototype.remove = function (participant, tickets) {\r\n // Attempt to get the existing participant.\r\n var existingParticipant = this._participants.find(function (part) { return part.participant === participant; });\r\n // There is nothing to do if the specified participant isn't even part of the lotto.\r\n if (!existingParticipant) {\r\n return this;\r\n }\r\n // Check whether a tickets value was given.\r\n if (tickets !== undefined) {\r\n // Check that we have a valid ticket count.\r\n if (!(0, Utilities_1.isNaturalNumber)(tickets)) {\r\n throw new Error(\"tickets value must be a natural number\");\r\n }\r\n existingParticipant.tickets -= tickets;\r\n // If the participant no longer holds any tickets then they should be removed.\r\n if (existingParticipant.tickets < 1) {\r\n this._participants = this._participants.filter(function (part) { return part !== existingParticipant; });\r\n }\r\n }\r\n else {\r\n // We are removing all tickets for the participant so just remove them from the lotto.\r\n this._participants = this._participants.filter(function (part) { return part !== existingParticipant; });\r\n }\r\n return this;\r\n };\r\n /**\r\n * Draw a winning ticket and return the participant that holds the ticket.\r\n * @param options The draw options.\r\n * @returns The participant that holds the winning ticket.\r\n */\r\n Lotto.prototype.draw = function (options) {\r\n if (options === void 0) { options = {}; }\r\n // If we have no participants then just return null.\r\n if (this._participants.length === 0) {\r\n return null;\r\n }\r\n var redrawable = (0, Utilities_1.isNullOrUndefined)(options.redrawable) ? true : options.redrawable;\r\n var pickable = [];\r\n this._participants.forEach(function (_a) {\r\n var participant = _a.participant, tickets = _a.tickets;\r\n for (var ticketCount = 0; ticketCount < tickets; ticketCount++) {\r\n pickable.push(participant);\r\n }\r\n });\r\n var random;\r\n // We need a random floating-point number between 0 (inclusive) and 1 to scale up to pick our winner.\r\n // If a custom random function exists then we should use that or fall back to Math.random().\r\n if (this._customRandom) {\r\n // Call our custom random function to get a random floating-point number.\r\n random = this._customRandom();\r\n // Verify that the result of calling our custom random function is a number between 0 (inclusive) and 1.\r\n if (typeof random !== \"number\" || random < 0 || random >= 1) {\r\n throw new Error(\"the 'random' function provided did not return a number between 0 (inclusive) and 1\");\r\n }\r\n }\r\n else {\r\n // No custom random function was defined so just use good ol' Math.random().\r\n random = Math.random();\r\n }\r\n // Pick a winning participant.\r\n var winner = pickable[Math.floor(random * pickable.length)];\r\n // If the ticket isn't redrawable then we should remove a ticket from the winning participants ticket count.\r\n if (!redrawable) {\r\n this.remove(winner, 1);\r\n }\r\n // Return the winning participant.\r\n return winner;\r\n };\r\n /**\r\n * Draws multiple winning tickets and return an array of the participants that hold the winning tickets.\r\n * @param tickets The number of winning tickets to draw.\r\n * @param options The draw multiple options.\r\n * @returns An array of the participants that hold the winning tickets.\r\n */\r\n Lotto.prototype.drawMultiple = function (tickets, options) {\r\n if (options === void 0) { options = {}; }\r\n var uniqueResults = (0, Utilities_1.isNullOrUndefined)(options.unique) ? false : options.unique;\r\n // Handle cases where the user has asked for zero tickets (no idea why they would do this be we should trust them).\r\n if (tickets === 0) {\r\n return [];\r\n }\r\n // Now that we know out tickets value is not zero we should check that it is a valid natural number.\r\n if (!(0, Utilities_1.isNaturalNumber)(tickets)) {\r\n throw new Error(\"tickets value must be a natural number\");\r\n }\r\n var result = [];\r\n // Keep drawing tickets until we either reach the number of required tickets or we simply run out of tickets to draw.\r\n // We can run out of tickets to draw if 'options.redrawable' is explicity 'false' or we just had no participants when 'drawMultiple' was called.\r\n while (result.length < tickets && this._participants.length > 0) {\r\n result.push(this.draw(options));\r\n }\r\n // If the 'unique' draw option is set then we need to remove duplicates from the result list.\r\n if (uniqueResults) {\r\n // Create an array to store our unique results.\r\n var unique = [];\r\n // Iterate over all of our participants (with potential duplicates) and populate our array of unique values.\r\n for (var _i = 0, result_1 = result; _i < result_1.length; _i++) {\r\n var participant = result_1[_i];\r\n if (unique.indexOf(participant) === -1) {\r\n unique.push(participant);\r\n }\r\n }\r\n result = unique;\r\n }\r\n return result;\r\n };\r\n return Lotto;\r\n}());\r\nexports.Lotto = Lotto;\r\n", "\"use strict\";\r\nObject.defineProperty(exports, \"__esModule\", { value: true });\r\nexports.createLotto = void 0;\r\nvar Lotto_1 = require(\"./Lotto\");\r\n/**\r\n * A function that creates and returns a Lotto instance.\r\n * @param participantsOrOptions An array of initial participants or options relating to the creation of a Lotto instance.\r\n * @returns A new Lotto instance.\r\n */\r\nfunction createLotto(participantsOrOptions) {\r\n // If no initial participants or lotto options were provided as an argument then we can just return a new lotto instance now.\r\n if (!participantsOrOptions) {\r\n return new Lotto_1.Lotto();\r\n }\r\n // Check whether we were provided with an array of initial participants or a lotto options object.\r\n if (Array.isArray(participantsOrOptions)) {\r\n // We are dealing with a pre-defined array of participants.\r\n var participants = participantsOrOptions;\r\n var lotto_1 = new Lotto_1.Lotto();\r\n // If the lotto participants have been defined upfront then we will need to add them all to our lotto instance now.\r\n participants.forEach(function (_a) {\r\n var participant = _a[0], tokens = _a[1];\r\n return lotto_1.add(participant, tokens);\r\n });\r\n // Return the Lotto instance.\r\n return lotto_1;\r\n }\r\n else {\r\n // We are dealing with some lotto options.\r\n var random = participantsOrOptions.random, participants = participantsOrOptions.participants;\r\n // Create a Lotto instance passing the custom RNG function to use in place of Math.random() (which could be undefined).\r\n var lotto_2 = new Lotto_1.Lotto(random);\r\n // If the lotto participants have been defined upfront as part of the options then we will need to add them all to our lotto instance now.\r\n if (participants) {\r\n participants.forEach(function (_a) {\r\n var participant = _a[0], tokens = _a[1];\r\n return lotto_2.add(participant, tokens);\r\n });\r\n }\r\n // Return the Lotto instance.\r\n return lotto_2;\r\n }\r\n}\r\nexports.createLotto = createLotto;\r\n", "\"use strict\";\r\nObject.defineProperty(exports, \"__esModule\", { value: true });\r\nvar createLotto_1 = require(\"./createLotto\");\r\nexports.default = createLotto_1.createLotto;\r\n", "import State from \"./State\";\nimport { validateDefinition } from \"./BehaviourTreeDefinitionValidator\";\nimport { convertMDSLToJSON } from \"./mdsl/MDSLDefinitionParser\";\nimport { BehaviourTree, FlattenedTreeNode } from \"./BehaviourTree\";\nimport { BehaviourTreeOptions } from \"./BehaviourTreeOptions\";\n\nexport { BehaviourTree, State, convertMDSLToJSON, validateDefinition };\nexport type { FlattenedTreeNode, BehaviourTreeOptions };\n", "/**\n * Enumeration of node state types.\n */\nexport enum State {\n READY = \"mistreevous.ready\",\n RUNNING = \"mistreevous.running\",\n SUCCEEDED = \"mistreevous.succeeded\",\n FAILED = \"mistreevous.failed\"\n}\n\nexport { State as default };\n\nexport type CompleteState = State.SUCCEEDED | State.FAILED;\nexport type AnyState = State.READY | State.RUNNING | CompleteState;\n", "import {\n NodeDefinition,\n RootNodeDefinition,\n DecoratorNodeDefinition,\n CompositeNodeDefinition,\n AnyNodeDefinition,\n BranchNodeDefinition\n} from \"./BehaviourTreeDefinition\";\n\n/**\n * A type guard function that returns true if the specified node satisfies the RootNodeDefinition type.\n * @param node The node.\n * @returns A value of true if the specified node satisfies the RootNodeDefinition type.\n */\nexport function isRootNode(node: NodeDefinition): node is RootNodeDefinition {\n return node.type === \"root\";\n}\n\n/**\n * A type guard function that returns true if the specified node satisfies the BranchNodeDefinition type.\n * @param node The node.\n * @returns A value of true if the specified node satisfies the BranchNodeDefinition type.\n */\nexport function isBranchNode(node: NodeDefinition): node is BranchNodeDefinition {\n return node.type === \"branch\";\n}\n\n/**\n * A type guard function that returns true if the specified node satisfies the NodeDefinition type.\n * @param node The node.\n * @returns A value of true if the specified node satisfies the NodeDefinition type.\n */\nexport function isLeafNode(node: NodeDefinition): node is NodeDefinition {\n return [\"branch\", \"action\", \"condition\", \"wait\"].includes(node.type);\n}\n\n/**\n * A type guard function that returns true if the specified node satisfies the DecoratorNodeDefinition type.\n * @param node The node.\n * @returns A value of true if the specified node satisfies the DecoratorNodeDefinition type.\n */\nexport function isDecoratorNode(node: NodeDefinition): node is DecoratorNodeDefinition {\n return [\"root\", \"repeat\", \"retry\", \"flip\", \"succeed\", \"fail\"].includes(node.type);\n}\n\n/**\n * A type guard function that returns true if the specified node satisfies the CompositeNodeDefinition type.\n * @param node The node.\n * @returns A value of true if the specified node satisfies the CompositeNodeDefinition type.\n */\nexport function isCompositeNode(node: NodeDefinition): node is CompositeNodeDefinition {\n return [\"sequence\", \"selector\", \"lotto\", \"parallel\"].includes(node.type);\n}\n\n/**\n * Flatten a node definition into an array of all of its nested node definitions.\n * @param nodeDefinition The node definition to flatten.\n * @returns An array of all of nested node definitions.\n */\nexport function flattenDefinition(nodeDefinition: AnyNodeDefinition): AnyNodeDefinition[] {\n const nodes: AnyNodeDefinition[] = [];\n\n const processNode = (currentNodeDefinition: AnyNodeDefinition) => {\n nodes.push(currentNodeDefinition);\n\n if (isCompositeNode(currentNodeDefinition)) {\n currentNodeDefinition.children.forEach(processNode);\n } else if (isDecoratorNode(currentNodeDefinition)) {\n processNode(currentNodeDefinition.child);\n }\n };\n\n processNode(nodeDefinition);\n\n return nodes;\n}\n\n/**\n * Determines whether the passed value is an integer.\n * @param value The value to check.\n * @returns Whether the passed value is an integer.\n */\nexport function isInteger(value: unknown): boolean {\n return typeof value === \"number\" && Math.floor(value) === value;\n}\n\n/**\n * Determines whether the passed value is null or undefined.\n * @param value The value to check.\n * @returns Whether the passed value is null or undefined.\n */\nexport function isNullOrUndefined(value: unknown): boolean {\n return typeof value === \"undefined\" || value === null;\n}\n", "/**\n * A type defining an object that holds a reference to substitued string literals parsed from the definition.\n */\nexport type StringLiteralPlaceholders = { [key: string]: string };\n\n/**\n * Pop the next raw token from the specified array of tokens and throw an error if it wasn't the expected one.\n * @param tokens The array of tokens.\n * @param expected An optional string or array or items, one of which must match the next popped token.\n * @returns The popped token.\n */\nexport function popAndCheck(tokens: string[], expected?: string | string[]): string {\n // Get and remove the next token.\n const popped = tokens.shift();\n\n // We were expecting another token but there aren't any.\n if (popped === undefined) {\n throw new Error(\"unexpected end of definition\");\n }\n\n // Do we have an expected token/tokens array?\n if (expected != undefined) {\n // Get an array of expected values, if the popped token matches any then we are all good.\n const expectedValues = typeof expected === \"string\" ? [expected] : expected;\n\n // Check whether the popped token matches at least one of our expected items.\n var tokenMatchesExpectation = expectedValues.some((item) => popped.toUpperCase() === item.toUpperCase());\n\n // Throw an error if the popped token didn't match any of our expected items.\n if (!tokenMatchesExpectation) {\n const expectationString = expectedValues.map((item) => \"'\" + item + \"'\").join(\" or \");\n throw new Error(\"unexpected token found. Expected \" + expectationString + \" but got '\" + popped + \"'\");\n }\n }\n\n // Return the popped token.\n return popped;\n}\n\n/**\n * Swaps out any node/attribute argument string literals with placeholders.\n * @param definition The definition.\n * @returns An object containing a mapping of placeholders to original string values as well as the processed definition string.\n */\nexport function substituteStringLiterals(definition: string): {\n placeholders: StringLiteralPlaceholders;\n processedDefinition: string;\n} {\n // Create an object to hold the mapping of placeholders to original string values.\n const placeholders: StringLiteralPlaceholders = {};\n\n // Replace any string literals wrapped with double quotes in our definition with placeholders to be processed later.\n const processedDefinition = definition.replace(/\\\"(\\\\.|[^\"\\\\])*\\\"/g, (match) => {\n var strippedMatch = match.substring(1, match.length - 1);\n var placeholder = Object.keys(placeholders).find((key) => placeholders[key] === strippedMatch);\n\n // If we have no existing string literal match then create a new placeholder.\n if (!placeholder) {\n placeholder = `@@${Object.keys(placeholders).length}@@`;\n placeholders[placeholder] = strippedMatch;\n }\n\n return placeholder;\n });\n\n return { placeholders, processedDefinition };\n}\n\n/**\n * Parse the tree definition into an array of raw tokens.\n * @param definition The definition.\n * @returns An array of tokens parsed from the definition.\n */\nexport function parseTokensFromDefinition(definition: string): string[] {\n // Add some space around various important characters so that they can be plucked out easier as individual tokens.\n definition = definition.replace(/\\(/g, \" ( \");\n definition = definition.replace(/\\)/g, \" ) \");\n definition = definition.replace(/\\{/g, \" { \");\n definition = definition.replace(/\\}/g, \" } \");\n definition = definition.replace(/\\]/g, \" ] \");\n definition = definition.replace(/\\[/g, \" [ \");\n definition = definition.replace(/\\,/g, \" , \");\n\n // Split the definition into raw token form and return it.\n return definition.replace(/\\s+/g, \" \").trim().split(\" \");\n}\n", "import { StringLiteralPlaceholders, popAndCheck } from \"./MDSLUtilities\";\n\n/**\n * A type representing any node function argument.\n */\ntype Argument = {\n /**\n * The argument value.\n */\n value: T;\n /**\n * The argument type, used for validation.\n */\n type: string;\n};\n\ntype NullArgument = Argument & {\n type: \"null\";\n};\n\ntype BooleanArgument = Argument & {\n type: \"boolean\";\n};\n\ntype NumberArgument = Argument & {\n type: \"number\";\n /**\n * A flag defining whether the number argument value is a valid integer. (used for validation)\n */\n isInteger: boolean;\n};\n\ntype StringPlaceholderArgument = Argument & {\n type: \"string\";\n};\n\ntype IdentifierArgument = Argument & {\n type: \"identifier\";\n};\n\n/**\n * A type representing a reference to any node function argument.\n */\ntype AnyArgument = NullArgument | BooleanArgument | NumberArgument | StringPlaceholderArgument | IdentifierArgument;\n\n/**\n * Parse an array of argument definitions from the specified tokens array.\n * @param tokens The array tokens to parse the argument definitions from.\n * @param stringArgumentPlaceholders The mapping of string literal node argument placeholders to original values.\n * @param argumentValidator The argument validator function.\n * @param validationFailedMessage The exception message to throw if argument validation fails.\n * @returns An array of argument definitions parsed from the specified tokens array.\n */\nexport function parseArgumentTokens(\n tokens: string[],\n stringArgumentPlaceholders: StringLiteralPlaceholders\n): AnyArgument[] {\n const argumentList: AnyArgument[] = [];\n\n // If the next token is not a '[' or '(' then we have no arguments to parse.\n if (![\"[\", \"(\"].includes(tokens[0])) {\n return argumentList;\n }\n\n // Any lists of arguments will always be wrapped in '[]' for node arguments or '()' for attribute arguments.\n // We are looking for a '[' or '(' opener that wraps the argument tokens and the relevant closer.\n const closingToken = popAndCheck(tokens, [\"[\", \"(\"]) === \"[\" ? \"]\" : \")\";\n\n const argumentListTokens: string[] = [];\n\n // Grab all tokens between the '[' and ']' or '(' and ')'.\n while (tokens.length && tokens[0] !== closingToken) {\n // The next token is part of our arguments list.\n argumentListTokens.push(tokens.shift()!);\n }\n\n // Validate the order of the argument tokens. Each token must either be a ',' or a single argument that satisfies the validator.\n argumentListTokens.forEach((token, index) => {\n // Get whether this token should be an actual argument.\n const shouldBeArgumentToken = !(index & 1);\n\n // If the current token should be an actual argument then validate it, otherwise it should be a ',' token.\n if (shouldBeArgumentToken) {\n // Get the argument definition.\n const argumentDefinition = getArgumentDefinition(token, stringArgumentPlaceholders);\n\n // This is a valid argument!\n argumentList.push(argumentDefinition);\n } else {\n // The current token should be a ',' token.\n if (token !== \",\") {\n throw new Error(`invalid argument list, expected ',' or ']' but got '${token}'`);\n }\n }\n });\n\n // The arguments list should terminate with a ']' or ')' token, depending on the opener.\n popAndCheck(tokens, closingToken);\n\n // Return the arguments.\n return argumentList;\n}\n\n/**\n * Gets an argument value definition.\n * @param token The argument token.\n * @param stringArgumentPlaceholders The mapping of string literal node argument placeholders to original values.\n * @returns An argument value definition.\n */\nfunction getArgumentDefinition(token: string, stringArgumentPlaceholders: StringLiteralPlaceholders): AnyArgument {\n // Check whether the token represents a null value.\n if (token === \"null\") {\n return {\n value: null,\n type: \"null\"\n } as NullArgument;\n }\n\n // Check whether the token represents a boolean value.\n if (token === \"true\" || token === \"false\") {\n return {\n value: token === \"true\",\n type: \"boolean\"\n } as BooleanArgument;\n }\n\n // Check whether the token represents a number value.\n // TODO: Relies on broken isNaN - see MDN.\n // if (!Number.isNaN(token)) {\n if (!isNaN(token as any)) {\n return {\n value: parseFloat(token),\n isInteger: parseFloat(token) === parseInt(token, 10),\n type: \"number\"\n } as NumberArgument;\n }\n\n // Check whether the token is a placeholder (e.g. @@0@@) representing a string literal.\n if (token.match(/^@@\\d+@@$/g)) {\n return {\n value: stringArgumentPlaceholders[token].replace('\\\\\"', '\"'),\n type: \"string\"\n } as StringPlaceholderArgument;\n }\n\n // The only remaining option is that the argument value is an identifier.\n return {\n value: token,\n type: \"identifier\"\n } as IdentifierArgument;\n}\n", "import { NodeAttributeDefinition } from \"../BehaviourTreeDefinition\";\nimport { parseArgumentTokens } from \"./MDSLNodeArgumentParser\";\nimport { StringLiteralPlaceholders } from \"./MDSLUtilities\";\n\n/**\n * A type defining the attribute definitions of a node.\n */\ntype NodeAttributes = {\n while?: NodeAttributeDefinition;\n until?: NodeAttributeDefinition;\n entry?: NodeAttributeDefinition;\n exit?: NodeAttributeDefinition;\n step?: NodeAttributeDefinition;\n};\n\n/**\n * Parse any node attribute definitions from the specified tokens array.\n * @param tokens The array of remaining tokens.\n * @param stringArgumentPlaceholders The mapping of string literal node argument placeholders to original values.\n * @returns An object of attribute definitions defined by any directly following tokens.\n */\nexport function parseAttributeTokens(\n tokens: string[],\n stringArgumentPlaceholders: StringLiteralPlaceholders\n): NodeAttributes {\n const nodeAttributeNames: (keyof NodeAttributes)[] = [\"while\", \"until\", \"entry\", \"exit\", \"step\"];\n\n // Create an object to hold any attributes found.\n const attributes: NodeAttributes = {};\n\n // Try to get the name of the attribute for the next token.\n let nextAttributeName = tokens[0]?.toLowerCase() as keyof NodeAttributes;\n\n // Pull attribute tokens as well as their arguments off of the tokens stack until we have no more.\n while (nodeAttributeNames.includes(nextAttributeName)) {\n // Check to make sure that we have not already created an attribute definition of this type.\n if (attributes[nextAttributeName]) {\n throw new Error(`duplicate attribute '${tokens[0].toUpperCase()}' found for node`);\n }\n\n // Remove the attribute name token from the array of tokens.\n tokens.shift();\n\n // Grab the attribute arguments, assuming the first to be an identifier.\n const [attributeCallIdentifier, ...attributeArguments] = parseArgumentTokens(\n tokens,\n stringArgumentPlaceholders\n );\n\n // The first attribute argument has to be an identifer, this will reference an agent function.\n if (attributeCallIdentifier?.type !== \"identifier\") {\n throw new Error(\"expected agent function or registered function name identifier argument for attribute\");\n }\n\n // Any attribute arguments (other than the expected call identifier) must have a type of string, number, boolean or null.\n attributeArguments\n .filter((arg) => arg.type === \"identifier\")\n .forEach((arg) => {\n throw new Error(\n `invalid attribute argument value '${arg.value}', must be string, number, boolean or null`\n );\n });\n\n // Create the attribute definition and add it to the object of attribute definitions found.\n attributes[nextAttributeName] = {\n call: attributeCallIdentifier.value,\n args: attributeArguments.map(({ value }) => value)\n };\n\n // Try to get the next attribute name token, as there could be multiple.\n nextAttributeName = tokens[0]?.toLowerCase() as keyof NodeAttributes;\n }\n\n return attributes;\n}\n", "import {\n ActionNodeDefinition,\n AnyChildNodeDefinition,\n AnyNodeDefinition,\n BranchNodeDefinition,\n ConditionNodeDefinition,\n FailNodeDefinition,\n FlipNodeDefinition,\n LottoNodeDefinition,\n ParallelNodeDefinition,\n RepeatNodeDefinition,\n RetryNodeDefinition,\n RootNodeDefinition,\n SelectorNodeDefinition,\n SequenceNodeDefinition,\n SucceedNodeDefinition,\n WaitNodeDefinition\n} from \"../BehaviourTreeDefinition\";\nimport {\n isCompositeNode,\n isDecoratorNode,\n isLeafNode,\n isNullOrUndefined,\n isRootNode\n} from \"../BehaviourTreeDefinitionUtilities\";\nimport { parseArgumentTokens } from \"./MDSLNodeArgumentParser\";\nimport { parseAttributeTokens } from \"./MDSLNodeAttributeParser\";\nimport {\n StringLiteralPlaceholders,\n parseTokensFromDefinition,\n popAndCheck,\n substituteStringLiterals\n} from \"./MDSLUtilities\";\n\n/**\n * Convert the MDSL tree definition string into an equivalent JSON definition.\n * @param definition The tree definition string as MDSL.\n * @returns The root node JSON definitions.\n */\nexport function convertMDSLToJSON(definition: string): RootNodeDefinition[] {\n // Swap out any node/attribute argument string literals with a placeholder and get a mapping of placeholders to original values as well as the processed definition.\n const { placeholders, processedDefinition } = substituteStringLiterals(definition);\n\n // Parse our definition definition string into an array of raw tokens.\n const tokens = parseTokensFromDefinition(processedDefinition);\n\n return convertTokensToJSONDefinition(tokens, placeholders);\n}\n\n/**\n * Converts the specified tree definition tokens into a JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The root node JSON definitions.\n */\nfunction convertTokensToJSONDefinition(\n tokens: string[],\n stringLiteralPlaceholders: StringLiteralPlaceholders\n): RootNodeDefinition[] {\n // There must be at least 3 tokens for the tree definition to be valid. 'ROOT', '{' and '}'.\n if (tokens.length < 3) {\n throw new Error(\"invalid token count\");\n }\n\n // We should have a matching number of '{' and '}' tokens. If not, then there are scopes that have not been properly closed.\n if (tokens.filter((token) => token === \"{\").length !== tokens.filter((token) => token === \"}\").length) {\n throw new Error(\"scope character mismatch\");\n }\n\n // Create an array of tree stack arrays where root nodes will always be at the botton and the current composite/decorator node at the top.\n // There should be an element in this array for every root node defined and every element should be an array with a root note as the first element.\n // E.g. A definition with two root nodes defined:\n // [\n // [root, lotto, sequence],\n // [root, selector]\n // ]\n const treeStacks: [Partial, ...Partial[]][] = [];\n\n // Create an array of all root node definitions that we create.\n const rootNodes: Partial[] = [];\n\n // A helper function used to push node definitions onto the tree stack.\n const pushNode = (node: AnyNodeDefinition) => {\n // If the node is a root node then we need to create a new tree stack array with the root node at the root.\n if (isRootNode(node)) {\n // We need to double-check that this root node is not the child of another node.\n // We can do this by checking whether the top tree stack is not empty (contains an existing node)\n if (treeStacks[treeStacks.length - 1]?.length) {\n throw new Error(\"a root node cannot be the child of another node\");\n }\n\n // Add the root node definition to our array of all parsed root node definitions.\n rootNodes.push(node);\n\n // Add the root node definition to the root of a new tree stack.\n treeStacks.push([node]);\n\n return;\n }\n\n // All non-root nodes should be pushed after their root nodes so handle cases\n // where we may not have any tree stacks or our top-most tree stack is empty.\n if (!treeStacks.length || !treeStacks[treeStacks.length - 1].length) {\n throw new Error(\"expected root node at base of definition\");\n }\n\n // Get the current tree stack that we are populating.\n const topTreeStack = treeStacks[treeStacks.length - 1];\n\n // Get the top-most node in the current tree stack, this will be a composite/decorator node\n // for which we will populate its children array if composite or setting its child if a decorator.\n const topTreeStackTopNode = topTreeStack[topTreeStack.length - 1] as AnyNodeDefinition;\n\n // If the top-most node in the current root stack is a composite or decorator\n // node then the current node should be added as a child of the top-most node.\n if (isCompositeNode(topTreeStackTopNode)) {\n topTreeStackTopNode.children = topTreeStackTopNode.children || [];\n topTreeStackTopNode.children.push(node);\n } else if (isDecoratorNode(topTreeStackTopNode)) {\n // If the top node already has a child node set then throw an error as a decorator should only have a single child.\n if (topTreeStackTopNode.child) {\n throw new Error(\"a decorator node must only have a single child node\");\n }\n\n topTreeStackTopNode.child = node;\n }\n\n // If the node we are adding is also a composite or decorator node, then we should push it\n // onto the current tree stack, as subsequent nodes will be added as its child/children.\n if (!isLeafNode(node)) {\n topTreeStack.push(node);\n }\n };\n\n // A helper function used to pop the top-most node definition off of the tree stack and return it.\n const popNode = (): AnyNodeDefinition | null => {\n let poppedNode: AnyNodeDefinition | null = null;\n\n // Get the current tree stack that we are populating.\n const topTreeStack = treeStacks[treeStacks.length - 1];\n\n // Pop the top-most node in the current tree stack if there is one.\n if (topTreeStack.length) {\n poppedNode = topTreeStack.pop() as AnyNodeDefinition;\n }\n\n // We don't want any empty tree stacks in our stack of tree stacks.\n if (!topTreeStack.length) {\n treeStacks.pop();\n }\n\n return poppedNode;\n };\n\n // We should keep processing the raw tokens until we run out of them.\n while (tokens.length) {\n // Grab the next token.\n const token = tokens.shift()!;\n\n // How we create the next node depends on the current raw token value.\n switch (token.toUpperCase()) {\n case \"ROOT\": {\n pushNode(createRootNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"SUCCEED\": {\n pushNode(createSucceedNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"FAIL\": {\n pushNode(createFailNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"FLIP\": {\n pushNode(createFlipNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"REPEAT\": {\n pushNode(createRepeatNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"RETRY\": {\n pushNode(createRetryNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"SEQUENCE\": {\n pushNode(createSequenceNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"SELECTOR\": {\n pushNode(createSelectorNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"PARALLEL\": {\n pushNode(createParallelNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"LOTTO\": {\n pushNode(createLottoNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"ACTION\": {\n pushNode(createActionNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"CONDITION\": {\n pushNode(createConditionNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"WAIT\": {\n pushNode(createWaitNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"BRANCH\": {\n pushNode(createBranchNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"}\": {\n // The '}' character closes the current scope and means that we have to pop a node off of the current stack.\n const poppedNode = popNode();\n\n // Now that we have a node definition we can carry out any validation that may require the node to be fully populated.\n if (poppedNode) {\n validatePoppedNode(poppedNode);\n }\n\n break;\n }\n\n default: {\n throw new Error(`unexpected token: ${token}`);\n }\n }\n }\n\n return rootNodes as RootNodeDefinition[];\n}\n\n/**\n * Creates a root node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The root node JSON definition.\n */\nfunction createRootNode(tokens: string[], stringLiteralPlaceholders: StringLiteralPlaceholders): RootNodeDefinition {\n // Create the root node definition.\n let node = {\n type: \"root\"\n } as Partial;\n\n // Parse any node arguments, we should only have one if any which will be an identifier argument for the root identifier.\n const nodeArguments = parseArgumentTokens(tokens, stringLiteralPlaceholders);\n\n // Check whether any node arguments were defined.\n if (nodeArguments.length) {\n // We should only have one argument, if any, which will be an identifier argument for the root identifier.\n if (nodeArguments.length === 1 && nodeArguments[0].type === \"identifier\") {\n // The root node identifier will be the first and only node argument value.\n node.id = nodeArguments[0].value as string;\n } else {\n throw new Error(\"expected single root name argument\");\n }\n }\n\n // Grab any node attribute definitions and spread them into the node definition.\n node = { ...node, ...parseAttributeTokens(tokens, stringLiteralPlaceholders) };\n\n // This is a decorator node, so we expect an opening '{'.\n popAndCheck(tokens, \"{\");\n\n // Return the root node definition.\n return node as RootNodeDefinition;\n}\n\n/**\n * Creates a succeed node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The succeed node JSON definition.\n */\nfunction createSucceedNode(\n tokens: string[],\n stringLiteralPlaceholders: StringLiteralPlaceholders\n): SucceedNodeDefinition {\n const node = {\n type: \"succeed\",\n ...parseAttributeTokens(tokens, stringLiteralPlaceholders)\n } as SucceedNodeDefinition;\n\n // This is a decorator node, so we expect an opening '{'.\n popAndCheck(tokens, \"{\");\n\n // Return the succeed node definition.\n return node;\n}\n\n/**\n * Creates a fail node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The fail node JSON definition.\n */\nfunction createFailNode(tokens: string[], stringLiteralPlaceholders: StringLiteralPlaceholders): FailNodeDefinition {\n const node = {\n type: \"fail\",\n ...parseAttributeTokens(tokens, stringLiteralPlaceholders)\n } as FailNodeDefinition;\n\n // This is a decorator node, so we expect an opening '{'.\n popAndCheck(tokens, \"{\");\n\n // Return the fail node definition.\n return node;\n}\n\n/**\n * Creates a flip node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The flip node JSON definition.\n */\nfunction createFlipNode(tokens: string[], stringLiteralPlaceholders: StringLiteralPlaceholders): FlipNodeDefinition {\n const node = {\n type: \"flip\",\n ...parseAttributeTokens(tokens, stringLiteralPlaceholders)\n } as FlipNodeDefinition;\n\n // This is a decorator node, so we expect an opening '{'.\n popAndCheck(tokens, \"{\");\n\n // Return the flip node definition.\n return node;\n}\n\n/**\n * Creates a repeat node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The repeat node JSON definition.\n */\nfunction createRepeatNode(\n tokens: string[],\n stringLiteralPlaceholders: StringLiteralPlaceholders\n): RepeatNodeDefinition {\n let node = { type: \"repeat\" } as RepeatNodeDefinition;\n\n // Get the node arguments.\n const nodeArguments = parseArgumentTokens(tokens, stringLiteralPlaceholders);\n\n // The arguments of a repeat node are optional. We may have:\n // - No node arguments, in which case the repeat note will iterate indefinitely.\n // - One node argument which will be the explicit number of iterations to make.\n // - Two node arguments which define the min and max iteration bounds from which a random iteration count will be picked.\n if (nodeArguments.length) {\n // All repeat node arguments MUST be of type number and must be integer.\n nodeArguments\n .filter((arg) => arg.type !== \"number\" || !arg.isInteger)\n .forEach(() => {\n throw new Error(`repeat node iteration counts must be integer values`);\n });\n\n // We should have got one or two iteration counts.\n if (nodeArguments.length === 1) {\n // A static iteration count was defined.\n node.iterations = nodeArguments[0].value as number;\n\n // A repeat node must have a positive number of iterations if defined.\n if (node.iterations < 0) {\n throw new Error(\"a repeat node must have a positive number of iterations if defined\");\n }\n } else if (nodeArguments.length === 2) {\n // A minimum and maximum iteration count was defined.\n node.iterations = [nodeArguments[0].value as number, nodeArguments[1].value as number];\n\n // A repeat node must have a positive min and max iteration count if they are defined.\n if (node.iterations[0] < 0 || node.iterations[1] < 0) {\n throw new Error(\"a repeat node must have a positive minimum and maximum iteration count if defined\");\n }\n\n // A repeat node must not have an minimum iteration count that exceeds the maximum iteration count.\n if (node.iterations[0] > node.iterations[1]) {\n throw new Error(\n \"a repeat node must not have a minimum iteration count that exceeds the maximum iteration count\"\n );\n }\n } else {\n // An incorrect number of iteration counts was defined.\n throw new Error(\"invalid number of repeat node iteration count arguments defined\");\n }\n }\n\n // Grab any node attribute definitions and spread them into the node definition.\n node = { ...node, ...parseAttributeTokens(tokens, stringLiteralPlaceholders) };\n\n // This is a decorator node, so we expect an opening '{'.\n popAndCheck(tokens, \"{\");\n\n // Return the repeat node definition.\n return node;\n}\n\n/**\n * Creates a retry node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The retry node JSON definition.\n */\nfunction createRetryNode(tokens: string[], stringLiteralPlaceholders: StringLiteralPlaceholders): RetryNodeDefinition {\n let node = { type: \"retry\" } as RetryNodeDefinition;\n\n // Get the node arguments.\n const nodeArguments = parseArgumentTokens(tokens, stringLiteralPlaceholders);\n\n // The arguments of a retry node are optional. We may have:\n // - No node arguments, in which case the retry note will attempt indefinitely.\n // - One node argument which will be the explicit number of attempts to make.\n // - Two node arguments which define the min and max attempt bounds from which a random attempt count will be picked.\n if (nodeArguments.length) {\n // All retry node arguments MUST be of type number and must be integer.\n nodeArguments\n .filter((arg) => arg.type !== \"number\" || !arg.isInteger)\n .forEach(() => {\n throw new Error(`retry node attempt counts must be integer values`);\n });\n\n // We should have got one or two attempt counts.\n if (nodeArguments.length === 1) {\n // A static attempt count was defined.\n node.attempts = nodeArguments[0].value as number;\n\n // A retry node must have a positive number of attempts if defined.\n if (node.attempts < 0) {\n throw new Error(\"a retry node must have a positive number of attempts if defined\");\n }\n } else if (nodeArguments.length === 2) {\n // A minimum and maximum attempt count was defined.\n node.attempts = [nodeArguments[0].value as number, nodeArguments[1].value as number];\n\n // A retry node must have a positive min and max attempts count if they are defined.\n if (node.attempts[0] < 0 || node.attempts[1] < 0) {\n throw new Error(\"a retry node must have a positive minimum and maximum attempt count if defined\");\n }\n\n // A retry node must not have a minimum attempt count that exceeds the maximum attempt count.\n if (node.attempts[0] > node.attempts[1]) {\n throw new Error(\n \"a retry node must not have a minimum attempt count that exceeds the maximum attempt count\"\n );\n }\n } else {\n // An incorrect number of attempt counts was defined.\n throw new Error(\"invalid number of retry node attempt count arguments defined\");\n }\n }\n\n // Grab any node attribute definitions and spread them into the node definition.\n node = { ...node, ...parseAttributeTokens(tokens, stringLiteralPlaceholders) };\n\n // This is a decorator node, so we expect an opening '{'.\n popAndCheck(tokens, \"{\");\n\n // Return the retry node definition.\n return node;\n}\n\n/**\n * Creates a sequence node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The sequence node JSON definition.\n */\nfunction createSequenceNode(\n tokens: string[],\n stringLiteralPlaceholders: StringLiteralPlaceholders\n): SequenceNodeDefinition {\n const node = {\n type: \"sequence\",\n ...parseAttributeTokens(tokens, stringLiteralPlaceholders)\n } as SequenceNodeDefinition;\n\n // This is a composite node, so we expect an opening '{'.\n popAndCheck(tokens, \"{\");\n\n // Return the sequence node definition.\n return node;\n}\n\n/**\n * Creates a selector node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The selector node JSON definition.\n */\nfunction createSelectorNode(\n tokens: string[],\n stringLiteralPlaceholders: StringLiteralPlaceholders\n): SelectorNodeDefinition {\n const node = {\n type: \"selector\",\n ...parseAttributeTokens(tokens, stringLiteralPlaceholders)\n } as SelectorNodeDefinition;\n\n // This is a composite node, so we expect an opening '{'.\n popAndCheck(tokens, \"{\");\n\n // Return the selector node definition.\n return node;\n}\n\n/**\n * Creates a parallel node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The parallel node JSON definition.\n */\nfunction createParallelNode(\n tokens: string[],\n stringLiteralPlaceholders: StringLiteralPlaceholders\n): ParallelNodeDefinition {\n const node = {\n type: \"parallel\",\n ...parseAttributeTokens(tokens, stringLiteralPlaceholders)\n } as ParallelNodeDefinition;\n\n // This is a composite node, so we expect an opening '{'.\n popAndCheck(tokens, \"{\");\n\n // Return the parallel node definition.\n return node;\n}\n\n/**\n * Creates a lotto node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The lotto node JSON definition.\n */\nfunction createLottoNode(tokens: string[], stringLiteralPlaceholders: StringLiteralPlaceholders): LottoNodeDefinition {\n // If any node arguments have been defined then they must be our weights.\n const nodeArguments = parseArgumentTokens(tokens, stringLiteralPlaceholders);\n\n // All lotto node arguments MUST be of type number and must be positive integers.\n nodeArguments\n .filter((arg) => arg.type !== \"number\" || !arg.isInteger || arg.value < 0)\n .forEach(() => {\n throw new Error(`lotto node weight arguments must be positive integer values`);\n });\n\n const node = {\n type: \"lotto\",\n ...parseAttributeTokens(tokens, stringLiteralPlaceholders)\n } as LottoNodeDefinition;\n\n // Apply the weights if any were defined.\n if (nodeArguments.length) {\n node.weights = nodeArguments.map(({ value }) => value) as number[];\n }\n\n // This is a composite node, so we expect an opening '{'.\n popAndCheck(tokens, \"{\");\n\n // Return the lotto node definition.\n return node;\n}\n\n/**\n * Creates an action node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The action node JSON definition.\n */\nfunction createActionNode(\n tokens: string[],\n stringLiteralPlaceholders: StringLiteralPlaceholders\n): ActionNodeDefinition {\n // Parse any node arguments, we should have at least one which will be an identifier argument for the action name\n // and agent function to invoke for the action, all other arguments are to be passed as arguments to that function.\n const [actionNameIdentifier, ...agentFunctionArgs] = parseArgumentTokens(tokens, stringLiteralPlaceholders);\n\n // Our first argument MUST be defined and be an identifier as we require an action name argument.\n if (actionNameIdentifier?.type !== \"identifier\") {\n throw new Error(\"expected action name identifier argument\");\n }\n\n // Only the first argument should have been an identifier, all agent function arguments must be string, number, boolean or null.\n agentFunctionArgs\n .filter((arg) => arg.type === \"identifier\")\n .forEach((arg) => {\n throw new Error(\n `invalid action node argument value '${arg.value}', must be string, number, boolean or null`\n );\n });\n\n // Return the action node definition.\n return {\n type: \"action\",\n call: actionNameIdentifier.value,\n args: agentFunctionArgs.map(({ value }) => value),\n ...parseAttributeTokens(tokens, stringLiteralPlaceholders)\n };\n}\n\n/**\n * Creates a condition node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The condition node JSON definition.\n */\nfunction createConditionNode(\n tokens: string[],\n stringLiteralPlaceholders: StringLiteralPlaceholders\n): ConditionNodeDefinition {\n // Parse any node arguments, we should have at least one which will be an identifier argument for the condition name\n // and agent function to invoke for the condition, all other arguments are to be passed as arguments to that function.\n const [conditionNameIdentifier, ...agentFunctionArgs] = parseArgumentTokens(tokens, stringLiteralPlaceholders);\n\n // Our first argument MUST be defined and be an identifier as we require a condition name argument.\n if (conditionNameIdentifier?.type !== \"identifier\") {\n throw new Error(\"expected condition name identifier argument\");\n }\n\n // Only the first argument should have been an identifier, all agent function arguments must be string, number, boolean or null.\n agentFunctionArgs\n .filter((arg) => arg.type === \"identifier\")\n .forEach((arg) => {\n throw new Error(\n `invalid condition node argument value '${arg.value}', must be string, number, boolean or null`\n );\n });\n\n // Return the condition node definition.\n return {\n type: \"condition\",\n call: conditionNameIdentifier.value,\n args: agentFunctionArgs.map(({ value }) => value),\n ...parseAttributeTokens(tokens, stringLiteralPlaceholders)\n };\n}\n\n/**\n * Creates a wait node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The wait node JSON definition.\n */\nfunction createWaitNode(tokens: string[], stringLiteralPlaceholders: StringLiteralPlaceholders): WaitNodeDefinition {\n let node = { type: \"wait\" } as WaitNodeDefinition;\n\n // Get the node arguments.\n const nodeArguments = parseArgumentTokens(tokens, stringLiteralPlaceholders);\n\n // The arguments of a wait node are optional. We may have:\n // - No node arguments, in which case the wait will be indefinite until it is aborted.\n // - One node argument which will be the explicit duration of the wait.\n // - Two node arguments which define the min and max duration bounds from which a random duration will be picked.\n if (nodeArguments.length) {\n // All wait node arguments MUST be of type number and must be integer.\n nodeArguments\n .filter((arg) => arg.type !== \"number\" || !arg.isInteger)\n .forEach(() => {\n throw new Error(`wait node durations must be integer values`);\n });\n\n // We may have:\n // - One node argument which will be the explicit duration of the wait.\n // - Two node arguments which define the min and max duration bounds from which a random duration will be picked.\n // - Too many arguments, which is not valid.\n if (nodeArguments.length === 1) {\n // An explicit duration was defined.\n node.duration = nodeArguments[0].value as number;\n\n // If an explict duration was defined then it must be a positive number.\n if (node.duration < 0) {\n throw new Error(\"a wait node must have a positive duration\");\n }\n } else if (nodeArguments.length === 2) {\n // Min and max duration bounds were defined from which a random duration will be picked.\n node.duration = [nodeArguments[0].value as number, nodeArguments[1].value as number];\n\n // A wait node must have a positive min and max duration.\n if (node.duration[0] < 0 || node.duration[1] < 0) {\n throw new Error(\"a wait node must have a positive minimum and maximum duration\");\n }\n\n // A wait node must not have a minimum duration that exceeds the maximum duration.\n if (node.duration[0] > node.duration[1]) {\n throw new Error(\"a wait node must not have a minimum duration that exceeds the maximum duration\");\n }\n } else if (nodeArguments.length > 2) {\n // An incorrect number of duration arguments were defined.\n throw new Error(\"invalid number of wait node duration arguments defined\");\n }\n }\n\n // Return the wait node definition.\n return { ...node, ...parseAttributeTokens(tokens, stringLiteralPlaceholders) };\n}\n\n/**\n * Creates a branch node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The branch node JSON definition.\n */\nfunction createBranchNode(\n tokens: string[],\n stringLiteralPlaceholders: StringLiteralPlaceholders\n): BranchNodeDefinition {\n // Parse any node arguments, we should have one which will be an identifier argument for the root ref.\n const nodeArguments = parseArgumentTokens(tokens, stringLiteralPlaceholders);\n\n // We should have only a single identifer argument for a branch node, which is the root ref.\n if (nodeArguments.length !== 1 || nodeArguments[0].type !== \"identifier\") {\n throw new Error(\"expected single branch name argument\");\n }\n\n // Return the branch node definition.\n return { type: \"branch\", ref: nodeArguments[0].value };\n}\n\n/**\n * Validate a fully-populated node definition that was popped off of the tree stack.\n * @param definition The popped node to validate.\n */\nfunction validatePoppedNode(definition: AnyNodeDefinition): void {\n // Decorators MUST have a child defined.\n if (isDecoratorNode(definition) && isNullOrUndefined(definition.child)) {\n throw new Error(`a ${definition.type} node must have a single child node defined`);\n }\n\n // Composites MUST have at least one child defined.\n if (isCompositeNode(definition) && !definition.children?.length) {\n throw new Error(`a ${definition.type} node must have at least a single child node defined`);\n }\n\n // We need to make sure that lotto nodes that have weights defined have a number of weights matching the number of child nodes.\n if (definition.type === \"lotto\") {\n // Check whether a 'weights' property has been defined, if it has we expect it to be an array of weights.\n if (typeof definition.weights !== \"undefined\") {\n // Check that the weights property is an array of positive integers with an element for each child node element.\n if (definition.weights.length !== definition.children.length) {\n throw new Error(\n \"expected a number of weight arguments matching the number of child nodes for lotto node\"\n );\n }\n }\n }\n}\n", "import { RootNodeDefinition } from \"./BehaviourTreeDefinition\";\nimport { flattenDefinition, isBranchNode, isInteger } from \"./BehaviourTreeDefinitionUtilities\";\nimport { convertMDSLToJSON } from \"./mdsl/MDSLDefinitionParser\";\n\n/**\n * An object representing the result of validating a tree definition.\n */\nexport type DefinitionValidationResult = {\n /**\n * A flag defining whether validation succeeded.\n */\n succeeded: boolean;\n /**\n * A string containing the error message if validation did not succeed.\n */\n errorMessage?: string;\n /**\n * The definition as json if the validation was successful, or undefined if validation did not succeed.\n */\n json?: RootNodeDefinition[];\n};\n\n/**\n * Validates the specified behaviour tree definition in the form of JSON or MDSL, not taking any globally registered subtrees into consideration.\n * @param definition The behaviour tree definition in the form of JSON or MDSL.\n * @returns An object representing the result of validating the given tree definition.\n */\nexport function validateDefinition(definition: any): DefinitionValidationResult {\n // The definition must be defined.\n if (definition === null || typeof definition === \"undefined\") {\n return createValidationFailureResult(\"definition is null or undefined\");\n }\n\n // We are expecting a definition in one of three different forms:\n // - A string which we will assume is MDSL and we will parse this to JSON before validation.\n // - An array which we will assume is an array of root node definitions with at least one being the primary root node (no 'id' property)\n // - An object which we will assume is the primary root node and should not have an 'id' property.\n if (typeof definition === \"string\") {\n // The definition is a string which we can assume is MDSL, so attempt to validate it.\n return validateMDSLDefinition(definition);\n } else if (typeof definition === \"object\") {\n // The definition will either be an array (of root node definitions) or an object (the single primary root node definition).\n return validateJSONDefinition(definition);\n } else {\n return createValidationFailureResult(`unexpected definition type of '${typeof definition}'`);\n }\n}\n\n/**\n * Validates the specified behaviour tree definition in the form of MDSL.\n * @param definition The behaviour tree definition in the form of MDSL.\n * @returns An object representing the result of validating the given tree definition.\n */\nfunction validateMDSLDefinition(definition: string): DefinitionValidationResult {\n let rootNodeDefinitions;\n\n // The first thing the we need to do is to attempt to convert our MDSL into JSON.\n try {\n // The definition is a string which we can assume is MDSL, so attempt to parse it to a JSON definition in the form of an array of root node definitions.\n rootNodeDefinitions = convertMDSLToJSON(definition);\n } catch (exception) {\n // We failed to parse the JSON from the MDSL, this is likely to be the result of it not being a valid MDSL string.\n return createValidationFailureResult((exception as Error).message);\n }\n\n // Unpack all of the root node definitions into arrays of main ('id' defined) and sub ('id' not defined) root node definitions.\n const mainRootNodeDefinitions = rootNodeDefinitions.filter(({ id }) => typeof id === \"undefined\");\n const subRootNodeDefinitions = rootNodeDefinitions.filter(({ id }) => typeof id === \"string\" && id.length > 0);\n\n // We should ALWAYS have exactly one root node definition without an 'id' property defined, which is out main root node definition.\n if (mainRootNodeDefinitions.length !== 1) {\n return createValidationFailureResult(\n \"expected single unnamed root node at base of definition to act as main root\"\n );\n }\n\n // We should never have duplicate 'id' properties across our sub root node definitions.\n const subRootNodeIdenitifers: string[] = [];\n for (const { id } of subRootNodeDefinitions) {\n // Have we already come across this 'id' property value?\n if (subRootNodeIdenitifers.includes(id!)) {\n return createValidationFailureResult(`multiple root nodes found with duplicate name '${id}'`);\n }\n\n subRootNodeIdenitifers.push(id!);\n }\n\n try {\n // Validate our branch -> subtree links and check for any circular dependencies, we don't care about checking for broken subtree links here.\n validateBranchSubtreeLinks(rootNodeDefinitions, false);\n } catch (exception) {\n return createValidationFailureResult((exception as Error).message);\n }\n\n // Our definition was valid!\n return {\n succeeded: true,\n json: rootNodeDefinitions\n };\n}\n\n/**\n * Validates the specified behaviour tree definition in the form of JSON.\n * @param definition The behaviour tree definition in the form of JSON.\n * @returns An object representing the result of validating the given tree definition.\n */\nexport function validateJSONDefinition(\n definition: RootNodeDefinition | RootNodeDefinition[]\n): DefinitionValidationResult {\n // The definition will either be an array (of root node definitions) or an object (the single primary root node definition).\n const rootNodeDefinitions = Array.isArray(definition) ? definition : [definition];\n\n // Iterate over our array of root nodes and call validateNode for each, passing an initial depth of 0, wrapped in a try catch to handle validation failures.\n try {\n rootNodeDefinitions.forEach((rootNodeDefinition) => validateNode(rootNodeDefinition, 0));\n } catch (error) {\n // Handle cases where we have caught a thrown Error and return a failure result with the error message.\n if (error instanceof Error) {\n return createValidationFailureResult(error.message);\n }\n\n // No idea what happened here!\n return createValidationFailureResult(`unexpected error: ${error}`);\n }\n\n // Unpack all of the root node definitions into arrays of main ('id' defined) and sub ('id' not defined) root node definitions.\n const mainRootNodeDefinitions = rootNodeDefinitions.filter(({ id }) => typeof id === \"undefined\");\n const subRootNodeDefinitions = rootNodeDefinitions.filter(({ id }) => typeof id === \"string\" && id.length > 0);\n\n // We should ALWAYS have exactly one root node definition without an 'id' property defined, which is out main root node definition.\n if (mainRootNodeDefinitions.length !== 1) {\n return createValidationFailureResult(\n \"expected single root node without 'id' property defined to act as main root\"\n );\n }\n\n // We should never have duplicate 'id' properties across our sub root node definitions.\n const subRootNodeIdenitifers: string[] = [];\n for (const { id } of subRootNodeDefinitions) {\n // Have we already come across this 'id' property value?\n if (subRootNodeIdenitifers.includes(id!)) {\n return createValidationFailureResult(\n `multiple root nodes found with duplicate 'id' property value of '${id}'`\n );\n }\n\n subRootNodeIdenitifers.push(id!);\n }\n\n try {\n // Validate our branch -> subtree links and check for any circular dependencies, we don't care about checking for broken subtree links here.\n validateBranchSubtreeLinks(rootNodeDefinitions, false);\n } catch (exception) {\n return createValidationFailureResult((exception as Error).message);\n }\n\n // Our definition was valid!\n return {\n succeeded: true,\n json: rootNodeDefinitions\n };\n}\n\n/**\n * Validates the branch -> subtree links across all provided root node definitions.\n * This will not consider branch nodes that reference any globally registered subtrees unless includesGlobalSubtrees\n * is set to true, in which case we will also verify that there are no broken branch -> subtree links.\n * @param rootNodeDefinitions The array of root node definitions.\n * @param includesGlobalSubtrees A flag defining whether the array includes all global subtree root node definitions.\n */\nexport function validateBranchSubtreeLinks(rootNodeDefinitions: RootNodeDefinition[], includesGlobalSubtrees: boolean) {\n // Create a mapping of root node identifiers to other root nodes that they reference via branch nodes.\n // Below is an example of a mapping that includes a circular dependency (root => a => b => c => a)\n // [{ refs: [\"a\", \"b\"] }, { id: \"a\", refs: [\"b\"] }, { id: \"b\", refs: [\"c\"] }, { id: \"c\", refs: [\"a\"] }]\n const rootNodeMappings: { id: string | undefined; refs: string[] }[] = rootNodeDefinitions.map(\n (rootNodeDefinition) => ({\n id: rootNodeDefinition.id,\n refs: flattenDefinition(rootNodeDefinition)\n .filter(isBranchNode)\n .map(({ ref }) => ref)\n })\n );\n\n // A recursive function to walk through the mappings, keeping track of which root nodes we have visited in the form of a path of root node identifiers.\n const followRefs = (mapping: { id: string | undefined; refs: string[] }, path: (string | undefined)[] = []) => {\n // Have we found a circular dependency?\n if (path.includes(mapping.id)) {\n // We found a circular dependency! Get the bad path of root node identifiers.\n const badPath = [...path, mapping.id];\n\n // Create the formatted path value. [undefined, \"a\", \"b\", \"c\", \"a\"] would be formatted as \"a -> b -> c -> a\".\n const badPathFormatted = badPath.filter((element) => !!element).join(\" => \");\n\n // No need to continue, we found a circular dependency.\n throw new Error(`circular dependency found in branch node references: ${badPathFormatted}`);\n }\n\n for (const ref of mapping.refs) {\n // Find the mapping for the root node with an identifer matching the current ref.\n const subMapping = rootNodeMappings.find(({ id }) => id === ref);\n\n // We may not have a mapping for this ref, which is normal when we aren't considering all globally registered subtrees.\n if (subMapping) {\n followRefs(subMapping, [...path, mapping.id]);\n } else if (includesGlobalSubtrees) {\n // We found a reference to a root node that doesn't exist, which is a problem seeing as the root node definitons includes all globally registered subtrees.\n throw new Error(\n mapping.id\n ? `subtree '${mapping.id}' has branch node that references root node '${ref}' which has not been defined`\n : `primary tree has branch node that references root node '${ref}' which has not been defined`\n );\n }\n }\n };\n\n // Start looking for circular dependencies and broken references from the primary root node definition.\n followRefs(rootNodeMappings.find((mapping) => typeof mapping.id === \"undefined\")!);\n}\n\n/**\n * Validate an object that we expect to be a node definition.\n * @param definition An object that we expect to be a node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateNode(definition: any, depth: number): void {\n // Every node must be valid object and have a non-empty 'type' string property.\n if (typeof definition !== \"object\" || typeof definition.type !== \"string\" || definition.type.length === 0) {\n throw new Error(\n `node definition is not an object or 'type' property is not a non-empty string at depth '${depth}'`\n );\n }\n\n // How we validate this node definition will depend on its type.\n switch (definition.type) {\n case \"action\":\n validateActionNode(definition, depth);\n break;\n\n case \"condition\":\n validateConditionNode(definition, depth);\n break;\n\n case \"wait\":\n validateWaitNode(definition, depth);\n break;\n\n case \"branch\":\n validateBranchNode(definition, depth);\n break;\n\n case \"root\":\n validateRootNode(definition, depth);\n break;\n\n case \"succeed\":\n validateSucceedNode(definition, depth);\n break;\n\n case \"fail\":\n validateFailNode(definition, depth);\n break;\n\n case \"flip\":\n validateFlipNode(definition, depth);\n break;\n\n case \"repeat\":\n validateRepeatNode(definition, depth);\n break;\n\n case \"retry\":\n validateRetryNode(definition, depth);\n break;\n\n case \"sequence\":\n validateSequenceNode(definition, depth);\n break;\n\n case \"selector\":\n validateSelectorNode(definition, depth);\n break;\n\n case \"parallel\":\n validateParallelNode(definition, depth);\n break;\n\n case \"lotto\":\n validateLottoNode(definition, depth);\n break;\n\n default:\n throw new Error(`unexpected node type of '${definition.type}' at depth '${depth}'`);\n }\n}\n\n/**\n * Validate any attributes for a given node definition.\n * @param definition The node definition.\n * @param depth The depth of the node in the behaviour tree definition.\n */\nfunction validateNodeAttributes(definition: any, depth: number): void {\n // Validate each of the attribute types for this node.\n [\"while\", \"until\", \"entry\", \"exit\", \"step\"].forEach((attributeName) => {\n // Attempt to grab the definition for the current attribute from the node definition.\n const attributeDefinition = definition[attributeName];\n\n // All node attributes are optional, so there is nothing to do if the current attribute is not defined.\n if (typeof attributeDefinition === \"undefined\") {\n return;\n }\n\n // The attribute definition must be an object.\n if (typeof attributeDefinition !== \"object\") {\n throw new Error(\n `expected attribute '${attributeName}' to be an object for '${definition.type}' node at depth '${depth}'`\n );\n }\n\n // The 'call' property must be defined for any attribute definition.\n if (typeof attributeDefinition.call !== \"string\" || attributeDefinition.call.length === 0) {\n throw new Error(\n `expected 'call' property for attribute '${attributeName}' to be a non-empty string for '${definition.type}' node at depth '${depth}'`\n );\n }\n\n // If any node attribute arguments have been defined then they must have been defined in an array.\n if (typeof attributeDefinition.args !== \"undefined\" && !Array.isArray(attributeDefinition.args)) {\n throw new Error(\n `expected 'args' property for attribute '${attributeName}' to be an array for '${definition.type}' node at depth '${depth}'`\n );\n }\n });\n}\n\n/**\n * Validate an object that we expect to be a root node definition.\n * @param definition An object that we expect to be a root node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateRootNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"root\") {\n throw new Error(\"expected node type of 'root' for root node\");\n }\n\n // A root node cannot be the child of another node.\n if (depth > 0) {\n throw new Error(\"a root node cannot be the child of another node\");\n }\n\n // Check that, if the root node 'id' property is defined, it is a non-empty string.\n if (typeof definition.id !== \"undefined\" && (typeof definition.id !== \"string\" || definition.id.length === 0)) {\n throw new Error(\"expected non-empty string for 'id' property if defined for root node\");\n }\n\n // A root node is a decorator node, so must have a child node defined.\n if (typeof definition.child === \"undefined\") {\n throw new Error(\"expected property 'child' to be defined for root node\");\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n\n // Validate the child node of this decorator node.\n validateNode(definition.child, depth + 1);\n}\n\n/**\n * Validate an object that we expect to be a succeed node definition.\n * @param definition An object that we expect to be a succeed node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateSucceedNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"succeed\") {\n throw new Error(`expected node type of 'succeed' for succeed node at depth '${depth}'`);\n }\n\n // A succeed node is a decorator node, so must have a child node defined.\n if (typeof definition.child === \"undefined\") {\n throw new Error(`expected property 'child' to be defined for succeed node at depth '${depth}'`);\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n\n // Validate the child node of this decorator node.\n validateNode(definition.child, depth + 1);\n}\n\n/**\n * Validate an object that we expect to be a fail node definition.\n * @param definition An object that we expect to be a fail node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateFailNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"fail\") {\n throw new Error(`expected node type of 'fail' for fail node at depth '${depth}'`);\n }\n\n // A fail node is a decorator node, so must have a child node defined.\n if (typeof definition.child === \"undefined\") {\n throw new Error(`expected property 'child' to be defined for fail node at depth '${depth}'`);\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n\n // Validate the child node of this decorator node.\n validateNode(definition.child, depth + 1);\n}\n\n/**\n * Validate an object that we expect to be a flip node definition.\n * @param definition An object that we expect to be a flip node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateFlipNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"flip\") {\n throw new Error(`expected node type of 'flip' for flip node at depth '${depth}'`);\n }\n\n // A flip node is a decorator node, so must have a child node defined.\n if (typeof definition.child === \"undefined\") {\n throw new Error(`expected property 'child' to be defined for flip node at depth '${depth}'`);\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n\n // Validate the child node of this decorator node.\n validateNode(definition.child, depth + 1);\n}\n\n/**\n * Validate an object that we expect to be a repeat node definition.\n * @param definition An object that we expect to be a repeat node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateRepeatNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"repeat\") {\n throw new Error(`expected node type of 'repeat' for repeat node at depth '${depth}'`);\n }\n\n // A repeat node is a decorator node, so must have a child node defined.\n if (typeof definition.child === \"undefined\") {\n throw new Error(`expected property 'child' to be defined for repeat node at depth '${depth}'`);\n }\n\n // Check whether an 'iterations' property has been defined, it may not have been if this node is to repeat indefinitely.\n if (typeof definition.iterations !== \"undefined\") {\n if (Array.isArray(definition.iterations)) {\n // Check whether any elements of the array are not integer values.\n const containsNonInteger = !!definition.iterations.filter((value: unknown) => !isInteger(value)).length;\n\n // If the 'iterations' property is an array then it MUST contain two integer values.\n if (definition.iterations.length !== 2 || containsNonInteger) {\n throw new Error(\n `expected array containing two integer values for 'iterations' property if defined for repeat node at depth '${depth}'`\n );\n }\n\n // A repeat node must have a positive min and max iterations count if they are defined.\n if (definition.iterations[0] < 0 || definition.iterations[1] < 0) {\n throw new Error(\n `expected positive minimum and maximum iterations count for 'iterations' property if defined for repeat node at depth '${depth}'`\n );\n }\n\n // A repeat node must not have a minimum iterations count that exceeds the maximum iterations count.\n if (definition.iterations[0] > definition.iterations[1]) {\n throw new Error(\n `expected minimum iterations count that does not exceed the maximum iterations count for 'iterations' property if defined for repeat node at depth '${depth}'`\n );\n }\n } else if (isInteger(definition.iterations)) {\n // A repeat node must have a positive number of iterations if defined.\n if (definition.iterations < 0) {\n throw new Error(\n `expected positive iterations count for 'iterations' property if defined for repeat node at depth '${depth}'`\n );\n }\n } else {\n throw new Error(\n `expected integer value or array containing two integer values for 'iterations' property if defined for repeat node at depth '${depth}'`\n );\n }\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n\n // Validate the child node of this decorator node.\n validateNode(definition.child, depth + 1);\n}\n\n/**\n * Validate an object that we expect to be a retry node definition.\n * @param definition An object that we expect to be a retry node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateRetryNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"retry\") {\n throw new Error(`expected node type of 'retry' for retry node at depth '${depth}'`);\n }\n\n // A retry node is a decorator node, so must have a child node defined.\n if (typeof definition.child === \"undefined\") {\n throw new Error(`expected property 'child' to be defined for retry node at depth '${depth}'`);\n }\n\n // Check whether an 'attempts' property has been defined, it may not have been if this node is to retry indefinitely.\n if (typeof definition.attempts !== \"undefined\") {\n if (Array.isArray(definition.attempts)) {\n // Check whether any elements of the array are not integer values.\n const containsNonInteger = !!definition.attempts.filter((value: unknown) => !isInteger(value)).length;\n\n // If the 'attempts' property is an array then it MUST contain two integer values.\n if (definition.attempts.length !== 2 || containsNonInteger) {\n throw new Error(\n `expected array containing two integer values for 'attempts' property if defined for retry node at depth '${depth}'`\n );\n }\n\n // A retry node must have a positive min and max attempts count if they are defined.\n if (definition.attempts[0] < 0 || definition.attempts[1] < 0) {\n throw new Error(\n `expected positive minimum and maximum attempts count for 'attempts' property if defined for retry node at depth '${depth}'`\n );\n }\n\n // A retry node must not have a minimum attempts count that exceeds the maximum attempts count.\n if (definition.attempts[0] > definition.attempts[1]) {\n throw new Error(\n `expected minimum attempts count that does not exceed the maximum attempts count for 'attempts' property if defined for retry node at depth '${depth}'`\n );\n }\n } else if (isInteger(definition.attempts)) {\n // A retry node must have a positive number of attempts if defined.\n if (definition.attempts < 0) {\n throw new Error(\n `expected positive attempts count for 'attempts' property if defined for retry node at depth '${depth}'`\n );\n }\n } else {\n throw new Error(\n `expected integer value or array containing two integer values for 'attempts' property if defined for retry node at depth '${depth}'`\n );\n }\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n\n // Validate the child node of this decorator node.\n validateNode(definition.child, depth + 1);\n}\n\n/**\n * Validate an object that we expect to be a branch node definition.\n * @param definition An object that we expect to be a branch node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateBranchNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"branch\") {\n throw new Error(`expected node type of 'branch' for branch node at depth '${depth}'`);\n }\n\n // Check that the branch node 'ref' property is defined and is a non-empty string.\n if (typeof definition.ref !== \"string\" || definition.ref.length === 0) {\n throw new Error(`expected non-empty string for 'ref' property for branch node at depth '${depth}'`);\n }\n\n // It is invalid to define guard attributes for a branch node as they should be defined on the referenced root node.\n [\"while\", \"until\"].forEach((attributeName) => {\n if (typeof definition[attributeName] !== \"undefined\") {\n throw new Error(\n `guards should not be defined for branch nodes but guard '${attributeName}' was defined for branch node at depth '${depth}'`\n );\n }\n });\n\n // It is invalid to define callback attributes for a branch node as they should be defined on the referenced root node.\n [\"entry\", \"exit\", \"step\"].forEach((attributeName) => {\n if (typeof definition[attributeName] !== \"undefined\") {\n throw new Error(\n `callbacks should not be defined for branch nodes but callback '${attributeName}' was defined for branch node at depth '${depth}'`\n );\n }\n });\n}\n\n/**\n * Validate an object that we expect to be a action node definition.\n * @param definition An object that we expect to be a action node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateActionNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"action\") {\n throw new Error(`expected node type of 'action' for action node at depth '${depth}'`);\n }\n\n // The 'call' property must be defined for a action node definition.\n if (typeof definition.call !== \"string\" || definition.call.length === 0) {\n throw new Error(`expected non-empty string for 'call' property of action node at depth '${depth}'`);\n }\n\n // If any action function arguments have been defined then they must have been defined in an array.\n if (typeof definition.args !== \"undefined\" && !Array.isArray(definition.args)) {\n throw new Error(`expected array for 'args' property if defined for action node at depth '${depth}'`);\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n}\n\n/**\n * Validate an object that we expect to be a condition node definition.\n * @param definition An object that we expect to be a condition node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateConditionNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"condition\") {\n throw new Error(`expected node type of 'condition' for condition node at depth '${depth}'`);\n }\n\n // The 'call' property must be defined for a condition node definition.\n if (typeof definition.call !== \"string\" || definition.call.length === 0) {\n throw new Error(`expected non-empty string for 'call' property of condition node at depth '${depth}'`);\n }\n\n // If any condition function arguments have been defined then they must have been defined in an array.\n if (typeof definition.args !== \"undefined\" && !Array.isArray(definition.args)) {\n throw new Error(`expected array for 'args' property if defined for condition node at depth '${depth}'`);\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n}\n\n/**\n * Validate an object that we expect to be a wait node definition.\n * @param definition An object that we expect to be a wait node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateWaitNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"wait\") {\n throw new Error(`expected node type of 'wait' for wait node at depth '${depth}'`);\n }\n\n // Check whether a 'duration' property has been defined, it may not have been if this node is to wait indefinitely.\n if (typeof definition.duration !== \"undefined\") {\n if (Array.isArray(definition.duration)) {\n // Check whether any elements of the array are not integer values.\n const containsNonInteger = !!definition.duration.filter((value: unknown) => !isInteger(value)).length;\n\n // If the 'duration' property is an array then it MUST contain two integer values.\n if (definition.duration.length !== 2 || containsNonInteger) {\n throw new Error(\n `expected array containing two integer values for 'duration' property if defined for wait node at depth '${depth}'`\n );\n }\n\n // A wait node must have a positive min and max duration value if they are defined.\n if (definition.duration[0] < 0 || definition.duration[1] < 0) {\n throw new Error(\n `expected positive minimum and maximum duration for 'duration' property if defined for wait node at depth '${depth}'`\n );\n }\n\n // A wait node must not have a minimum duration value that exceeds the maximum duration value.\n if (definition.duration[0] > definition.duration[1]) {\n throw new Error(\n `expected minimum duration value that does not exceed the maximum duration value for 'duration' property if defined for wait node at depth '${depth}'`\n );\n }\n } else if (isInteger(definition.duration)) {\n // A wait node must have a positive duration value if defined.\n if (definition.duration < 0) {\n throw new Error(\n `expected positive duration value for 'duration' property if defined for wait node at depth '${depth}'`\n );\n }\n } else {\n throw new Error(\n `expected integer value or array containing two integer values for 'duration' property if defined for wait node at depth '${depth}'`\n );\n }\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n}\n\n/**\n * Validate an object that we expect to be a sequence node definition.\n * @param definition An object that we expect to be a sequence node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateSequenceNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"sequence\") {\n throw new Error(`expected node type of 'sequence' for sequence node at depth '${depth}'`);\n }\n\n // A sequence node is a composite node, so must have a children nodes array defined.\n if (!Array.isArray(definition.children) || definition.children.length === 0) {\n throw new Error(`expected non-empty 'children' array to be defined for sequence node at depth '${depth}'`);\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n\n // Validate the child nodes of this composite node.\n definition.children.forEach((child: any) => validateNode(child, depth + 1));\n}\n\n/**\n * Validate an object that we expect to be a selector node definition.\n * @param definition An object that we expect to be a selector node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateSelectorNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"selector\") {\n throw new Error(`expected node type of 'selector' for selector node at depth '${depth}'`);\n }\n\n // A selector node is a composite node, so must have a children nodes array defined.\n if (!Array.isArray(definition.children) || definition.children.length === 0) {\n throw new Error(`expected non-empty 'children' array to be defined for selector node at depth '${depth}'`);\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n\n // Validate the child nodes of this composite node.\n definition.children.forEach((child: any) => validateNode(child, depth + 1));\n}\n\n/**\n * Validate an object that we expect to be a parallel node definition.\n * @param definition An object that we expect to be a parallel node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateParallelNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"parallel\") {\n throw new Error(`expected node type of 'parallel' for parallel node at depth '${depth}'`);\n }\n\n // A parallel node is a composite node, so must have a children nodes array defined.\n if (!Array.isArray(definition.children) || definition.children.length === 0) {\n throw new Error(`expected non-empty 'children' array to be defined for parallel node at depth '${depth}'`);\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n\n // Validate the child nodes of this composite node.\n definition.children.forEach((child: any) => validateNode(child, depth + 1));\n}\n\n/**\n * Validate an object that we expect to be a lotto node definition.\n * @param definition An object that we expect to be a lotto node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateLottoNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"lotto\") {\n throw new Error(`expected node type of 'lotto' for lotto node at depth '${depth}'`);\n }\n\n // A lotto node is a composite node, so must have a children nodes array defined.\n if (!Array.isArray(definition.children) || definition.children.length === 0) {\n throw new Error(`expected non-empty 'children' array to be defined for lotto node at depth '${depth}'`);\n }\n\n // Check whether a 'weights' property has been defined, if it has we expect it to be an array of weights.\n if (typeof definition.weights !== \"undefined\") {\n // Check that the weights property is an array of positive integers with an element for each child node element.\n if (\n !Array.isArray(definition.weights) ||\n definition.weights.length !== definition.children.length ||\n definition.weights.filter((value: unknown) => !isInteger(value)).length ||\n definition.weights.filter((value: number) => value < 0).length\n ) {\n throw new Error(\n `expected an array of positive integer weight values with a length matching the number of child nodes for 'weights' property if defined for lotto node at depth '${depth}'`\n );\n }\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n\n // Validate the child nodes of this composite node.\n definition.children.forEach((child: any) => validateNode(child, depth + 1));\n}\n\n/**\n * A helper function to create a failure validation result with the given error message.\n * @param errorMessage The validation failure error message.\n * @returns A failure validation result with the given error message.\n */\nfunction createValidationFailureResult(errorMessage: string): DefinitionValidationResult {\n return { succeeded: false, errorMessage };\n}\n", "import { ActionResult, Agent, GlobalFunction } from \"./Agent\";\nimport { RootNodeDefinition } from \"./BehaviourTreeDefinition\";\n\nexport type InvokerFunction = (args: any[]) => ActionResult | boolean;\n\n/**\n * A singleton used to store and lookup registered functions and subtrees.\n */\nexport default class Lookup {\n /**\n * The object holding any registered functions keyed on function name.\n */\n private static registeredFunctions: { [key: string]: GlobalFunction } = {};\n /**\n * The object holding any registered subtree root node definitions keyed on tree name.\n */\n private static registeredSubtrees: { [key: string]: RootNodeDefinition } = {};\n\n /**\n * Gets the function with the specified name.\n * @param name The name of the function.\n * @returns The function with the specified name.\n */\n public static getFunc(name: string): GlobalFunction {\n return this.registeredFunctions[name];\n }\n\n /**\n * Sets the function with the specified name for later lookup.\n * @param name The name of the function.\n * @param func The function.\n */\n public static setFunc(name: string, func: GlobalFunction): void {\n this.registeredFunctions[name] = func;\n }\n\n /**\n * Gets the function invoker for the specified agent and function name.\n * If a function with the specified name exists on the agent object then it will\n * be returned, otherwise we will then check the registered functions for a match.\n * @param agent The agent instance that this behaviour tree is modelling behaviour for.\n * @param name The function name.\n * @returns The function invoker for the specified agent and function name.\n */\n static getFuncInvoker(agent: Agent, name: string): InvokerFunction | null {\n // Check whether the agent contains the specified function.\n const agentFunction = agent[name];\n if (agentFunction && typeof agentFunction === \"function\") {\n return (args: any[]) => agentFunction.apply(agent, args);\n }\n\n // The agent does not contain the specified function but it may have been registered at some point.\n if (this.registeredFunctions[name] && typeof this.registeredFunctions[name] === \"function\") {\n const registeredFunction = this.registeredFunctions[name];\n return (args: any[]) => registeredFunction(agent, ...args.map((arg) => arg.value));\n }\n\n // We have no function to invoke.\n return null;\n }\n\n /**\n * Gets all registered subtree root node definitions.\n */\n static getSubtrees(): { [key: string]: RootNodeDefinition } {\n return this.registeredSubtrees;\n }\n\n /**\n * Sets the subtree with the specified name for later lookup.\n * @param name The name of the subtree.\n * @param subtree The subtree.\n */\n static setSubtree(name: string, subtree: RootNodeDefinition) {\n this.registeredSubtrees[name] = subtree;\n }\n\n /**\n * Removes the registered function or subtree with the specified name.\n * @param name The name of the registered function or subtree.\n */\n static remove(name: string) {\n delete this.registeredFunctions[name];\n delete this.registeredSubtrees[name];\n }\n\n /**\n * Remove all registered functions and subtrees.\n */\n static empty() {\n this.registeredFunctions = {};\n this.registeredSubtrees = {};\n }\n}\n", "import Node from \"../../nodes/Node\";\n\n/**\n * An exception thrown when evaluating node guard path conditions and a conditions fails.\n */\nexport default class GuardUnsatisifedException extends Error {\n /**\n * @param source The node at which a guard condition failed.\n */\n constructor(private source: Node) {\n super(\"A guard path condition has failed\");\n }\n\n /**\n * Gets whether the specified node is the node at which a guard condition failed.\n * @param node The node to check against the source node.\n * @returns Whether the specified node is the node at which a guard condition failed.\n */\n isSourceNode = (node: Node) => node === this.source;\n}\n", "import { Agent } from \"../../Agent\";\nimport Guard from \"./Guard\";\nimport Node from \"../../nodes/Node\";\nimport GuardUnsatisifedException from \"./GuardUnsatisifedException\";\n\nexport type GuardPathPart = {\n node: Node;\n guards: Guard[];\n};\n\n/**\n * Represents a path of node guards along a root-to-leaf tree path.\n */\nexport default class GuardPath {\n /**\n * @param nodes An array of objects defining a node instance -> guard link, ordered by node depth.\n */\n constructor(private nodes: GuardPathPart[]) {}\n\n /**\n * Evaluate guard conditions for all guards in the tree path, moving outwards from the root.\n * @param agent The agent, required for guard evaluation.\n * @returns An evaluation results object.\n */\n evaluate = (agent: Agent) => {\n // We need to evaluate guard conditions for nodes up the tree, moving outwards from the root.\n for (const details of this.nodes) {\n // There can be multiple guards per node.\n for (const guard of details.guards) {\n // Check whether the guard condition passes, and throw an exception if not.\n if (!guard.isSatisfied(agent)) {\n throw new GuardUnsatisifedException(details.node);\n }\n }\n }\n };\n}\n", "import { BehaviourTreeOptions } from \"../BehaviourTreeOptions\";\nimport State, { AnyState } from \"../State\";\nimport { Agent } from \"../Agent\";\nimport Leaf from \"./leaf/Leaf\";\nimport Attribute from \"../attributes/Attribute\";\nimport Entry from \"../attributes/callbacks/Entry\";\nimport Exit from \"../attributes/callbacks/Exit\";\nimport Step from \"../attributes/callbacks/Step\";\nimport Guard from \"../attributes/guards/Guard\";\nimport GuardPath from \"../attributes/guards/GuardPath\";\nimport GuardUnsatisifedException from \"../attributes/guards/GuardUnsatisifedException\";\n\n/**\n * A base node.\n */\nexport default abstract class Node {\n /**\n * The node uid.\n */\n private readonly uid: string = createNodeUid();\n /**\n * The node state.\n */\n private state: AnyState = State.READY;\n /**\n * The guard path to evaluate as part of a node update.\n */\n private guardPath: GuardPath | undefined;\n\n /**\n * @param type The node type.\n * @param attributes The node attributes.\n * @param args The node argument definitions.\n */\n constructor(private type: string, private attributes: Attribute[], private args: any[]) {}\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected abstract onUpdate(agent: Agent, options: BehaviourTreeOptions): void;\n\n /**\n * Gets the name of the node.\n */\n public abstract getName(): string;\n\n /**\n * Gets whether this node is a leaf node.\n */\n public abstract isLeafNode: () => this is Leaf;\n\n /**\n * Gets/Sets the state of the node.\n */\n getState = (): AnyState => this.state;\n setState = (value: AnyState): void => {\n this.state = value;\n };\n\n /**\n * Gets the unique id of the node.\n */\n getUid = () => this.uid;\n\n /**\n * Gets the type of the node.\n */\n getType = () => this.type;\n\n /**\n * Gets the node attributes.\n */\n getAttributes = () => this.attributes;\n\n /**\n * Gets the node arguments.\n */\n getArguments = () => this.args;\n\n /**\n * Gets the node attribute with the specified type, or null if it does not exist.\n */\n getAttribute(type: \"entry\" | \"ENTRY\"): Entry;\n getAttribute(type: \"exit\" | \"EXIT\"): Exit;\n getAttribute(type: \"step\" | \"STEP\"): Step;\n getAttribute(type: string): Attribute {\n return (\n this.getAttributes().filter((decorator) => decorator.type.toUpperCase() === type.toUpperCase())[0] || null\n );\n }\n\n /**\n * Gets the node attributes.\n */\n getGuardAttributes = (): Guard[] => this.getAttributes().filter((decorator) => decorator.isGuard()) as Guard[];\n\n /**\n * Sets the guard path to evaluate as part of a node update.\n */\n setGuardPath = (value: GuardPath) => (this.guardPath = value);\n\n /**\n * Gets whether a guard path is assigned to this node.\n */\n hasGuardPath = () => !!this.guardPath;\n\n /**\n * Gets whether this node is in the specified state.\n * @param value The value to compare to the node state.\n */\n public is(value: AnyState): boolean {\n return this.state === value;\n }\n\n /**\n * Reset the state of the node.\n */\n public reset(): void {\n this.setState(State.READY);\n }\n\n /**\n * Abort the running of this node.\n * @param agent The agent.\n */\n public abort(agent: Agent): void {\n // There is nothing to do if this node is not in the running state.\n if (!this.is(State.RUNNING)) {\n return;\n }\n\n // Reset the state of this node.\n this.reset();\n\n this.getAttribute(\"exit\")?.callAgentFunction(agent, false, true);\n }\n\n /**\n * Update the node.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n * @returns The result of the update.\n */\n public update(agent: Agent, options: BehaviourTreeOptions): void {\n // If this node is already in a 'SUCCEEDED' or 'FAILED' state then there is nothing to do.\n if (this.is(State.SUCCEEDED) || this.is(State.FAILED)) {\n return;\n }\n\n try {\n // Evaluate all of the guard path conditions for the current tree path.\n this.guardPath!.evaluate(agent);\n\n // If this node is in the READY state then call the ENTRY for this node if it exists.\n if (this.is(State.READY)) {\n this.getAttribute(\"entry\")?.callAgentFunction(agent);\n }\n\n this.getAttribute(\"step\")?.callAgentFunction(agent);\n\n // Do the actual update.\n this.onUpdate(agent, options);\n\n // If this node is now in a 'SUCCEEDED' or 'FAILED' state then call the EXIT for this node if it exists.\n if (this.is(State.SUCCEEDED) || this.is(State.FAILED)) {\n this.getAttribute(\"exit\")?.callAgentFunction(agent, this.is(State.SUCCEEDED), false);\n }\n } catch (error) {\n // If the error is a GuardUnsatisfiedException then we need to determine if this node is the source.\n if (error instanceof GuardUnsatisifedException && error.isSourceNode(this)) {\n // Abort the current node.\n this.abort(agent);\n\n // Any node that is the source of an abort will be a failed node.\n this.setState(State.FAILED);\n } else {\n throw error;\n }\n }\n }\n}\n\n/**\n * Create a randomly generated node uid.\n * @returns A randomly generated node uid.\n */\nfunction createNodeUid(): string {\n var S4 = function () {\n return (((1 + Math.random()) * 0x10000) | 0).toString(16).substring(1);\n };\n return S4() + S4() + \"-\" + S4() + \"-\" + S4() + \"-\" + S4() + \"-\" + S4() + S4() + S4();\n}\n", "import Node from \"../Node\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\n\n/**\n * A composite node that wraps child nodes.\n */\nexport default abstract class Composite extends Node {\n /**\n * @param type The node type.\n * @param attributes The node attributes.\n * @param children The child nodes.\n */\n constructor(type: string, attributes: Attribute[], protected children: Node[]) {\n super(type, attributes, []);\n }\n\n /**\n * Gets whether this node is a leaf node.\n */\n isLeafNode = () => false;\n\n /**\n * Gets the children of this node.\n */\n getChildren = () => this.children;\n\n /**\n * Reset the state of the node.\n */\n reset = () => {\n // Reset the state of this node.\n this.setState(State.READY);\n\n // Reset the state of any child nodes.\n this.getChildren().forEach((child) => child.reset());\n };\n\n /**\n * Abort the running of this node.\n * @param agent The agent.\n */\n abort = (agent: Agent) => {\n // There is nothing to do if this node is not in the running state.\n if (!this.is(State.RUNNING)) {\n return;\n }\n\n // Abort any child nodes.\n this.getChildren().forEach((child) => child.abort(agent));\n\n // Reset the state of this node.\n this.reset();\n\n this.getAttribute(\"exit\")?.callAgentFunction(agent, false, true);\n };\n}\n", "import Composite from \"./Composite\";\nimport State from \"../../State\";\nimport Node from \"../Node\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A PARALLEL node.\n * The child nodes are executed concurrently until one fails or all succeed.\n */\nexport default class Parallel extends Composite {\n /**\n * @param attributes The node attributes.\n * @param children The child nodes.\n */\n constructor(attributes: Attribute[], children: Node[]) {\n super(\"parallel\", attributes, children);\n }\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // Keep a count of the number of succeeded child nodes.\n let succeededCount = 0;\n\n let hasChildFailed = false;\n\n // Iterate over all of the children of this node.\n for (const child of this.children) {\n // If the child has never been updated or is running then we will need to update it now.\n if (child.getState() === State.READY || child.getState() === State.RUNNING) {\n // Update the child of this node.\n child.update(agent, options);\n }\n\n // If the current child has a state of 'SUCCEEDED' then we should move on to the next child.\n if (child.getState() === State.SUCCEEDED) {\n // The child node has succeeded, keep track of this to determine if all children have.\n succeededCount++;\n\n // The child node succeeded, but we have not finished checking every child node yet.\n continue;\n }\n\n // If the current child has a state of 'FAILED' then this node is also a 'FAILED' node.\n if (child.getState() === State.FAILED) {\n hasChildFailed = true;\n\n // There is no need to check the rest of the children.\n break;\n }\n\n // The node should be in the 'RUNNING' state.\n if (child.getState() !== State.RUNNING) {\n // The child node was not in an expected state.\n throw new Error(\"child node was not in an expected state.\");\n }\n }\n\n if (hasChildFailed) {\n // This node is a 'FAILED' node.\n this.setState(State.FAILED);\n\n // Abort every running child.\n for (const child of this.children) {\n if (child.getState() === State.RUNNING) {\n child.abort(agent);\n }\n }\n } else {\n // If all children have succeeded then this node has also succeeded, otherwise it is still running.\n this.setState(succeededCount === this.children.length ? State.SUCCEEDED : State.RUNNING);\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => \"PARALLEL\";\n}\n", "import Composite from \"./Composite\";\nimport Node from \"../Node\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A SELECTOR node.\n * The child nodes are executed in sequence until one succeeds or all fail.\n */\nexport default class Selector extends Composite {\n /**\n * @param attributes The node attributes.\n * @param children The child nodes.\n */\n constructor(attributes: Attribute[], protected children: Node[]) {\n super(\"selector\", attributes, children);\n }\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // Iterate over all of the children of this node.\n for (const child of this.children) {\n // If the child has never been updated or is running then we will need to update it now.\n if (child.getState() === State.READY || child.getState() === State.RUNNING) {\n // Update the child of this node.\n child.update(agent, options);\n }\n\n // If the current child has a state of 'SUCCEEDED' then this node is also a 'SUCCEEDED' node.\n if (child.getState() === State.SUCCEEDED) {\n // This node is a 'SUCCEEDED' node.\n this.setState(State.SUCCEEDED);\n\n // There is no need to check the rest of the selector nodes.\n return;\n }\n\n // If the current child has a state of 'FAILED' then we should move on to the next child.\n if (child.getState() === State.FAILED) {\n // Find out if the current child is the last one in the selector.\n // If it is then this sequence node has also failed.\n if (this.children.indexOf(child) === this.children.length - 1) {\n // This node is a 'FAILED' node.\n this.setState(State.FAILED);\n\n // There is no need to check the rest of the selector as we have completed it.\n return;\n } else {\n // The child node failed, try the next one.\n continue;\n }\n }\n\n // The node should be in the 'RUNNING' state.\n if (child.getState() === State.RUNNING) {\n // This node is a 'RUNNING' node.\n this.setState(State.RUNNING);\n\n // There is no need to check the rest of the selector as the current child is still running.\n return;\n }\n\n // The child node was not in an expected state.\n throw new Error(\"child node was not in an expected state.\");\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => \"SELECTOR\";\n}\n", "import Composite from \"./Composite\";\nimport Node from \"../Node\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A SEQUENCE node.\n * The child nodes are executed in sequence until one fails or all succeed.\n */\nexport default class Sequence extends Composite {\n /**\n * @param attributes The node attributes.\n * @param children The child nodes.\n */\n constructor(attributes: Attribute[], protected children: Node[]) {\n super(\"sequence\", attributes, children);\n }\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // Iterate over all of the children of this node.\n for (const child of this.children) {\n // If the child has never been updated or is running then we will need to update it now.\n if (child.getState() === State.READY || child.getState() === State.RUNNING) {\n // Update the child of this node.\n child.update(agent, options);\n }\n\n // If the current child has a state of 'SUCCEEDED' then we should move on to the next child.\n if (child.getState() === State.SUCCEEDED) {\n // Find out if the current child is the last one in the sequence.\n // If it is then this sequence node has also succeeded.\n if (this.children.indexOf(child) === this.children.length - 1) {\n // This node is a 'SUCCEEDED' node.\n this.setState(State.SUCCEEDED);\n\n // There is no need to check the rest of the sequence as we have completed it.\n return;\n } else {\n // The child node succeeded, but we have not finished the sequence yet.\n continue;\n }\n }\n\n // If the current child has a state of 'FAILED' then this node is also a 'FAILED' node.\n if (child.getState() === State.FAILED) {\n // This node is a 'FAILED' node.\n this.setState(State.FAILED);\n\n // There is no need to check the rest of the sequence.\n return;\n }\n\n // The node should be in the 'RUNNING' state.\n if (child.getState() === State.RUNNING) {\n // This node is a 'RUNNING' node.\n this.setState(State.RUNNING);\n\n // There is no need to check the rest of the sequence as the current child is still running.\n return;\n }\n\n // The child node was not in an expected state.\n throw new Error(\"child node was not in an expected state.\");\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => \"SEQUENCE\";\n}\n", "import createLotto from \"lotto-draw\";\n\nimport Node from \"../Node\";\nimport Composite from \"./Composite\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A LOTTO node.\n * A winning child is picked on the initial update of this node, based on ticket weighting.\n * The state of this node will match the state of the winning child.\n */\nexport default class Lotto extends Composite {\n /**\n * @param attributes The node attributes.\n * @param weights The child node weights.\n * @param children The child nodes.\n */\n constructor(attributes: Attribute[], private weights: number[] | undefined, children: Node[]) {\n super(\"lotto\", attributes, children);\n }\n\n /**\n * The child node selected to be the active one.\n */\n private selectedChild: Node | undefined;\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // If this node is in the READY state then we need to pick a winning child node.\n if (this.is(State.READY)) {\n // Create a lotto draw with which to randomly pick a child node to become the active one.\n const lottoDraw = createLotto({\n // Hook up the optional 'random' behaviour tree function option to the one used by 'lotto-draw'.\n random: options.random,\n // Pass in each child node as a participant in the lotto draw with their respective ticket count.\n participants: this.children.map((child, index) => [child, this.weights?.[index] || 1])\n });\n\n // Randomly pick a child based on ticket weighting, this will become the active child for this composite node.\n this.selectedChild = lottoDraw.draw() || undefined;\n }\n\n // If something went wrong and we don't have an active child then we should throw an error.\n if (!this.selectedChild) {\n throw new Error(\"failed to update lotto node as it has no active child\");\n }\n\n // If the selected child has never been updated or is running then we will need to update it now.\n if (this.selectedChild.getState() === State.READY || this.selectedChild.getState() === State.RUNNING) {\n this.selectedChild.update(agent, options);\n }\n\n // The state of the lotto node is the state of its selected child.\n this.setState(this.selectedChild.getState());\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => (this.weights ? `LOTTO [${this.weights.join(\",\")}]` : \"LOTTO\");\n}\n", "import Node from \"../Node\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\n\n/**\n * A decorator node that wraps a single child node.\n */\nexport default abstract class Decorator extends Node {\n /**\n * @param type The node type.\n * @param attributes The node attributes.\n * @param child The child node.\n */\n constructor(type: string, attributes: Attribute[], protected child: Node) {\n super(type, attributes, []);\n }\n\n /**\n * Gets whether this node is a leaf node.\n */\n isLeafNode = () => false;\n\n /**\n * Gets the children of this node.\n */\n getChildren = () => [this.child];\n\n /**\n * Reset the state of the node.\n */\n reset = () => {\n // Reset the state of this node.\n this.setState(State.READY);\n\n // Reset the state of the child node.\n this.child.reset();\n };\n\n /**\n * Abort the running of this node.\n * @param agent The agent.\n */\n abort = (agent: Agent) => {\n // There is nothing to do if this node is not in the running state.\n if (!this.is(State.RUNNING)) {\n return;\n }\n\n // Abort the child node.\n this.child.abort(agent);\n\n // Reset the state of this node.\n this.reset();\n\n this.getAttribute(\"exit\")?.callAgentFunction(agent, false, true);\n };\n}\n", "import Node from \"../Node\";\nimport Decorator from \"./Decorator\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A Fail node.\n * This node wraps a single child and will always move to the 'FAILED' state when the child moves to a 'SUCCEEDED' or 'FAILED' state.\n */\nexport default class Fail extends Decorator {\n /**\n * @param attributes The node attributes.\n * @param child The child node.\n */\n constructor(attributes: Attribute[], child: Node) {\n super(\"fail\", attributes, child);\n }\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // If the child has never been updated or is running then we will need to update it now.\n if (this.child.getState() === State.READY || this.child.getState() === State.RUNNING) {\n this.child.update(agent, options);\n }\n\n // The state of this node will depend in the state of its child.\n switch (this.child.getState()) {\n case State.RUNNING:\n this.setState(State.RUNNING);\n break;\n\n case State.SUCCEEDED:\n case State.FAILED:\n this.setState(State.FAILED);\n break;\n\n default:\n this.setState(State.READY);\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => \"FAIL\";\n}\n", "import Decorator from \"./Decorator\";\nimport State from \"../../State\";\nimport Node from \"../Node\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A Flip node.\n * This node wraps a single child and will flip the state of the child state.\n */\nexport default class Flip extends Decorator {\n /**\n * @param attributes The node attributes.\n * @param child The child node.\n */\n constructor(attributes: Attribute[], child: Node) {\n super(\"flip\", attributes, child);\n }\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // If the child has never been updated or is running then we will need to update it now.\n if (this.child.getState() === State.READY || this.child.getState() === State.RUNNING) {\n this.child.update(agent, options);\n }\n\n // The state of this node will depend in the state of its child.\n switch (this.child.getState()) {\n case State.RUNNING:\n this.setState(State.RUNNING);\n break;\n\n case State.SUCCEEDED:\n this.setState(State.FAILED);\n break;\n\n case State.FAILED:\n this.setState(State.SUCCEEDED);\n break;\n\n default:\n this.setState(State.READY);\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => \"FLIP\";\n}\n", "import Node from \"../Node\";\nimport Decorator from \"./Decorator\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A REPEAT node.\n * The node has a single child which can have:\n * -- A number of iterations for which to repeat the child node.\n * -- An infinite repeat loop if neither an iteration count or a condition function is defined.\n * The REPEAT node will stop and have a 'FAILED' state if its child is ever in a 'FAILED' state after an update.\n * The REPEAT node will attempt to move on to the next iteration if its child is ever in a 'SUCCEEDED' state.\n */\nexport default class Repeat extends Decorator {\n /**\n * @param attributes The node attributes.\n * @param iterations The number of iterations to repeat the child node.\n * @param iterationsMin The minimum possible number of iterations to repeat the child node.\n * @param iterationsMax The maximum possible number of iterations to repeat the child node.\n * @param child The child node.\n */\n constructor(\n attributes: Attribute[],\n private iterations: number | null,\n private iterationsMin: number | null,\n private iterationsMax: number | null,\n child: Node\n ) {\n super(\"repeat\", attributes, child);\n }\n\n /**\n * The number of target iterations to make.\n */\n private targetIterationCount: number | null = null;\n\n /**\n * The current iteration count.\n */\n private currentIterationCount: number = 0;\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // If this node is in the READY state then we need to reset the child and the target iteration count.\n if (this.is(State.READY)) {\n // Reset the child node.\n this.child.reset();\n\n // Reset the current iteration count.\n this.currentIterationCount = 0;\n\n // Set the target iteration count.\n this.setTargetIterationCount(options);\n }\n\n // Do a check to see if we can iterate. If we can then this node will move into the 'RUNNING' state.\n // If we cannot iterate then we have hit our target iteration count, which means that the node has succeeded.\n if (this.canIterate()) {\n // This node is in the running state and can do its initial iteration.\n this.setState(State.RUNNING);\n\n // We may have already completed an iteration, meaning that the child node will be in the SUCCEEDED state.\n // If this is the case then we will have to reset the child node now.\n if (this.child.getState() === State.SUCCEEDED) {\n this.child.reset();\n }\n\n // Update the child of this node.\n this.child.update(agent, options);\n\n // If the child moved into the FAILED state when we updated it then there is nothing left to do and this node has also failed.\n // If it has moved into the SUCCEEDED state then we have completed the current iteration.\n if (this.child.getState() === State.FAILED) {\n // The child has failed, meaning that this node has failed.\n this.setState(State.FAILED);\n\n return;\n } else if (this.child.getState() === State.SUCCEEDED) {\n // We have completed an iteration.\n this.currentIterationCount += 1;\n }\n } else {\n // This node is in the 'SUCCEEDED' state as we cannot iterate any more.\n this.setState(State.SUCCEEDED);\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => {\n if (this.iterations !== null) {\n return `REPEAT ${this.iterations}x`;\n } else if (this.iterationsMin !== null && this.iterationsMax !== null) {\n return `REPEAT ${this.iterationsMin}x-${this.iterationsMax}x`;\n } else {\n return \"REPEAT\";\n }\n };\n\n /**\n * Reset the state of the node.\n */\n reset = () => {\n // Reset the state of this node.\n this.setState(State.READY);\n\n // Reset the current iteration count.\n this.currentIterationCount = 0;\n\n // Reset the child node.\n this.child.reset();\n };\n\n /**\n * Gets whether an iteration can be made.\n * @returns Whether an iteration can be made.\n */\n private canIterate = () => {\n if (this.targetIterationCount !== null) {\n // We can iterate as long as we have not reached our target iteration count.\n return this.currentIterationCount < this.targetIterationCount;\n }\n\n // If neither an iteration count or a condition function were defined then we can iterate indefinitely.\n return true;\n };\n\n /**\n * Sets the target iteration count.\n * @param options The behaviour tree options object.\n */\n private setTargetIterationCount = (options: BehaviourTreeOptions) => {\n // Are we dealing with an explicit iteration count or will we be randomly picking a iteration count between the min and max iteration count.\n if (this.iterations !== null) {\n this.targetIterationCount = this.iterations;\n } else if (this.iterationsMin !== null && this.iterationsMax !== null) {\n // We will be picking a random iteration count between a min and max iteration count, if the optional 'random'\n // behaviour tree function option is defined then we will be using that, otherwise we will fall back to using Math.random.\n const random = typeof options.random === \"function\" ? options.random : Math.random;\n\n // Pick a random iteration count between a min and max iteration count.\n this.targetIterationCount = Math.floor(\n random() * (this.iterationsMax - this.iterationsMin + 1) + this.iterationsMin\n );\n } else {\n this.targetIterationCount = null;\n }\n };\n}\n", "import Node from \"../Node\";\nimport Decorator from \"./Decorator\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A RETRY node.\n * The node has a single child which can have:\n * -- A number of iterations for which to repeat the child node.\n * -- An infinite repeat loop if neither an iteration count or a condition function is defined.\n * The RETRY node will stop and have a 'SUCCEEDED' state if its child is ever in a 'SUCCEEDED' state after an update.\n * The RETRY node will attempt to move on to the next iteration if its child is ever in a 'FAILED' state.\n */\nexport default class Retry extends Decorator {\n /**\n * @param attributes The node attributes.\n * @param attempts The number of attempts to retry the child node.\n * @param attemptsMin The minimum possible number of attempts to retry the child node.\n * @param attemptsMax The maximum possible number of attempts to retry the child node.\n * @param child The child node.\n */\n constructor(\n attributes: Attribute[],\n private attempts: number | null,\n private attemptsMin: number | null,\n private attemptsMax: number | null,\n child: Node\n ) {\n super(\"retry\", attributes, child);\n }\n\n /**\n * The number of target attempts to make.\n */\n private targetAttemptCount: number | null = null;\n\n /**\n * The current attempt count.\n */\n private currentAttemptCount: number = 0;\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // If this node is in the READY state then we need to reset the child and the target attempt count.\n if (this.is(State.READY)) {\n // Reset the child node.\n this.child.reset();\n\n // Reset the current attempt count.\n this.currentAttemptCount = 0;\n\n // Set the target attempt count.\n this.setTargetAttemptCount(options);\n }\n\n // Do a check to see if we can attempt. If we can then this node will move into the 'RUNNING' state.\n // If we cannot attempt then we have hit our target attempt count, which means that the node has succeeded.\n if (this.canAttempt()) {\n // This node is in the running state and can do its initial attempt.\n this.setState(State.RUNNING);\n\n // We may have already completed an attempt, meaning that the child node will be in the FAILED state.\n // If this is the case then we will have to reset the child node now.\n if (this.child.getState() === State.FAILED) {\n this.child.reset();\n }\n\n // Update the child of this node.\n this.child.update(agent, options);\n\n // If the child moved into the SUCCEEDED state when we updated it then there is nothing left to do and this node has also succeeded.\n // If it has moved into the FAILED state then we have completed the current attempt.\n if (this.child.getState() === State.SUCCEEDED) {\n // The child has succeeded, meaning that this node has succeeded.\n this.setState(State.SUCCEEDED);\n\n return;\n } else if (this.child.getState() === State.FAILED) {\n // We have completed an attempt.\n this.currentAttemptCount += 1;\n }\n } else {\n // This node is in the 'FAILED' state as we cannot iterate any more.\n this.setState(State.FAILED);\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => {\n if (this.attempts !== null) {\n return `RETRY ${this.attempts}x`;\n } else if (this.attemptsMin !== null && this.attemptsMax !== null) {\n return `RETRY ${this.attemptsMin}x-${this.attemptsMax}x`;\n } else {\n return \"RETRY\";\n }\n };\n\n /**\n * Reset the state of the node.\n */\n reset = () => {\n // Reset the state of this node.\n this.setState(State.READY);\n\n // Reset the current attempt count.\n this.currentAttemptCount = 0;\n\n // Reset the child node.\n this.child.reset();\n };\n\n /**\n * Gets whether an attempt can be made.\n * @returns Whether an attempt can be made.\n */\n canAttempt = () => {\n if (this.targetAttemptCount !== null) {\n // We can attempt as long as we have not reached our target attempt count.\n return this.currentAttemptCount < this.targetAttemptCount;\n }\n\n // If neither an attempt count or a condition function were defined then we can attempt indefinitely.\n return true;\n };\n\n /**\n * Sets the target attempt count.\n * @param options The behaviour tree options object.\n */\n setTargetAttemptCount = (options: BehaviourTreeOptions) => {\n // Are we dealing with an explicit attempt count or will we be randomly picking an attempt count between the min and max attempt count.\n if (this.attempts !== null) {\n this.targetAttemptCount = this.attempts;\n } else if (this.attemptsMin !== null && this.attemptsMax !== null) {\n // We will be picking a random attempt count between a min and max attempt count, if the optional 'random'\n // behaviour tree function option is defined then we will be using that, otherwise we will fall back to using Math.random.\n const random = typeof options.random === \"function\" ? options.random : Math.random;\n\n // Pick a random attempt count between a min and max attempt count.\n this.targetAttemptCount = Math.floor(\n random() * (this.attemptsMax - this.attemptsMin + 1) + this.attemptsMin\n );\n } else {\n this.targetAttemptCount = null;\n }\n };\n}\n", "import Node from \"../Node\";\nimport Decorator from \"./Decorator\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A Root node.\n * The root node will have a single child.\n */\nexport default class Root extends Decorator {\n /**\n * @param attributes The node attributes.\n * @param child The child node.\n */\n constructor(attributes: Attribute[], child: Node) {\n super(\"root\", attributes, child);\n }\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // If the child has never been updated or is running then we will need to update it now.\n if (this.child.getState() === State.READY || this.child.getState() === State.RUNNING) {\n // Update the child of this node.\n this.child.update(agent, options);\n }\n\n // The state of the root node is the state of its child.\n this.setState(this.child.getState());\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => \"ROOT\";\n}\n", "import Node from \"../Node\";\nimport Decorator from \"./Decorator\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A Succeed node.\n * This node wraps a single child and will always move to the 'SUCCEEDED' state when the child moves to a 'SUCCEEDED' or 'FAILED' state.\n */\nexport default class Succeed extends Decorator {\n /**\n * @param attributes The node attributes.\n * @param child The child node.\n */\n constructor(attributes: Attribute[], child: Node) {\n super(\"succeed\", attributes, child);\n }\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // If the child has never been updated or is running then we will need to update it now.\n if (this.child.getState() === State.READY || this.child.getState() === State.RUNNING) {\n this.child.update(agent, options);\n }\n\n // The state of this node will depend in the state of its child.\n switch (this.child.getState()) {\n case State.RUNNING:\n this.setState(State.RUNNING);\n break;\n\n case State.SUCCEEDED:\n case State.FAILED:\n this.setState(State.SUCCEEDED);\n break;\n\n default:\n this.setState(State.READY);\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => \"SUCCEED\";\n}\n", "import Node from \"../Node\";\n\n/**\n * A leaf node.\n */\nexport default abstract class Leaf extends Node {\n /**\n * Gets whether this node is a leaf node.\n */\n isLeafNode = () => true;\n}\n", "import { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\nimport State, { CompleteState } from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Leaf from \"./Leaf\";\nimport Lookup from \"../../Lookup\";\nimport Attribute from \"../../attributes/Attribute\";\n\n/**\n * The type representing a resolved/rejected update promise.\n */\ntype UpdatePromiseResult = {\n /**\n * Whether the promise was resolved rather than rejected.\n */\n isResolved: boolean;\n\n /**\n * The promise resolved value or rejection reason.\n */\n value: any;\n};\n\n/**\n * An Action leaf node.\n * This represents an immediate or ongoing state of behaviour.\n */\nexport default class Action extends Leaf {\n /**\n * @param attributes The node attributes.\n * @param actionName The action name.\n * @param actionArguments The array of action argument definitions.\n */\n constructor(attributes: Attribute[], private actionName: string, private actionArguments: any[]) {\n super(\"action\", attributes, actionArguments);\n }\n\n /**\n * Whether there is a pending update promise.\n */\n private isUsingUpdatePromise = false;\n\n /**\n * The finished state result of an update promise.\n */\n private updatePromiseResult: UpdatePromiseResult | null = null;\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // If the result of this action depends on an update promise then there is nothing to do until it settles.\n if (this.isUsingUpdatePromise) {\n // Are we still waiting for our update promise to settle?\n if (!this.updatePromiseResult) {\n return;\n }\n\n const { isResolved, value } = this.updatePromiseResult;\n\n // Our update promise settled, was it resolved or rejected?\n if (isResolved) {\n // Our promise resolved so check to make sure the result is a valid finished state.\n if (value !== State.SUCCEEDED && value !== State.FAILED) {\n throw new Error(\n \"action node promise resolved with an invalid value, expected a State.SUCCEEDED or State.FAILED value to be returned\"\n );\n }\n\n // Set the state of this node to match the state returned by the promise.\n this.setState(value);\n\n return;\n } else {\n // The promise was rejected, which isn't great.\n throw new Error(`action function '${this.actionName}' promise rejected with '${value}'`);\n }\n }\n\n // Attempt to get the invoker for the action function.\n const actionFuncInvoker = Lookup.getFuncInvoker(agent, this.actionName);\n\n // The action function should be defined.\n if (actionFuncInvoker === null) {\n throw new Error(\n `cannot update action node as the action '${this.actionName}' function is not defined on the agent and has not been registered`\n );\n }\n\n let actionFunctionResult;\n\n try {\n // Call the action function, the result of which may be:\n // - The finished state of this action node.\n // - A promise to return a finished node state.\n // - Undefined if the node should remain in the running state.\n actionFunctionResult = actionFuncInvoker(this.actionArguments) as CompleteState | Promise;\n } catch (error) {\n // The user was naughty and threw something.\n throw new Error(`action function '${this.actionName}' threw '${error}'`);\n }\n\n if (actionFunctionResult instanceof Promise) {\n actionFunctionResult.then(\n (result) => {\n // If 'isUpdatePromisePending' is not set then the promise was cleared as it was resolving, probably via an abort of reset.\n if (!this.isUsingUpdatePromise) {\n return;\n }\n\n // Set the resolved update promise result so that it can be handled on the next update of this node.\n this.updatePromiseResult = {\n isResolved: true,\n value: result\n };\n },\n (reason) => {\n // If 'isUpdatePromisePending' is not set then the promise was cleared as it was resolving, probably via an abort or reset.\n if (!this.isUsingUpdatePromise) {\n return;\n }\n\n // Set the rejected update promise result so that it can be handled on the next update of this node.\n this.updatePromiseResult = {\n isResolved: false,\n value: reason\n };\n }\n );\n\n // This node will be in the 'RUNNING' state until the update promise resolves.\n this.setState(State.RUNNING);\n\n // We are now waiting for the promise returned by the use to resolve before we know what state this node is in.\n this.isUsingUpdatePromise = true;\n } else {\n // Validate the returned value.\n this.validateUpdateResult(actionFunctionResult);\n\n // Set the state of this node, this may be undefined, which just means that the node is still in the 'RUNNING' state.\n this.setState(actionFunctionResult || State.RUNNING);\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => this.actionName;\n\n /**\n * Reset the state of the node.\n */\n reset = () => {\n // Reset the state of this node.\n this.setState(State.READY);\n\n // There is no longer an update promise that we care about.\n this.isUsingUpdatePromise = false;\n this.updatePromiseResult = null;\n };\n\n /**\n * Validate the result of an update function call.\n * @param result The result of an update function call.\n */\n private validateUpdateResult = (result: CompleteState | State.RUNNING) => {\n switch (result) {\n case State.SUCCEEDED:\n case State.FAILED:\n case State.RUNNING:\n case undefined:\n return;\n default:\n throw new Error(\n `expected action function '${this.actionName}' to return an optional State.SUCCEEDED or State.FAILED value but returned '${result}'`\n );\n }\n };\n}\n", "import { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Leaf from \"./Leaf\";\nimport Lookup from \"../../Lookup\";\nimport Attribute from \"../../attributes/Attribute\";\n\n/**\n * A Condition leaf node.\n * This will succeed or fail immediately based on an agent predicate, without moving to the 'RUNNING' state.\n */\nexport default class Condition extends Leaf {\n /**\n * @param attributes The node attributes.\n * @param conditionName The name of the condition function.\n * @param conditionArguments The array of condition argument definitions.\n */\n constructor(attributes: Attribute[], private conditionName: string, private conditionArguments: any[]) {\n super(\"condition\", attributes, conditionArguments);\n }\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // Attempt to get the invoker for the condition function.\n const conditionFuncInvoker = Lookup.getFuncInvoker(agent, this.conditionName);\n\n // The condition function should be defined.\n if (conditionFuncInvoker === null) {\n throw new Error(\n `cannot update condition node as the condition '${this.conditionName}' function is not defined on the agent and has not been registered`\n );\n }\n\n let conditionFunctionResult;\n\n try {\n // Call the condition function to determine the state of this node, the result of which should be a boolean.\n conditionFunctionResult = conditionFuncInvoker(this.conditionArguments);\n } catch (error) {\n // The user was naughty and threw something.\n throw new Error(`condition function '${this.conditionName}' threw '${error}'`);\n }\n\n // The result of calling the condition function must be a boolean value.\n if (typeof conditionFunctionResult !== \"boolean\") {\n throw new Error(\n `expected condition function '${this.conditionName}' to return a boolean but returned '${conditionFunctionResult}'`\n );\n }\n\n // Set the state of this node based on the result of calling the condition function.\n this.setState(!!conditionFunctionResult ? State.SUCCEEDED : State.FAILED);\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => this.conditionName;\n}\n", "import Leaf from \"./Leaf\";\nimport State from \"../../State\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { Agent } from \"../../Agent\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A WAIT node.\n * The state of this node will change to SUCCEEDED after a duration of time\n */\nexport default class Wait extends Leaf {\n /**\n * @param attributes The node attributes.\n * @param duration The duration that this node will wait to succeed in milliseconds.\n * @param durationMin The minimum possible duration in milliseconds that this node will wait to succeed.\n * @param durationMax The maximum possible duration in milliseconds that this node will wait to succeed.\n */\n constructor(\n attributes: Attribute[],\n private duration: number | null,\n private durationMin: number | null,\n private durationMax: number | null\n ) {\n super(\"wait\", attributes, []);\n }\n\n /**\n * The time in milliseconds at which this node was first updated.\n */\n private initialUpdateTime: number = 0;\n\n /**\n * The total duration in milliseconds that this node will be waiting for.\n */\n private totalDuration: number | null = null;\n\n /**\n * The duration in milliseconds that this node has been waiting for.\n */\n private waitedDuration: number = 0;\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // If this node is in the READY state then we need to set the initial update time.\n if (this.is(State.READY)) {\n // Set the initial update time.\n this.initialUpdateTime = new Date().getTime();\n\n // Set the initial waited duration.\n this.waitedDuration = 0;\n\n // Are we dealing with an explicit duration or will we be randomly picking a duration between the min and max duration.\n if (this.duration !== null) {\n this.totalDuration = this.duration;\n } else if (this.durationMin !== null && this.durationMax !== null) {\n // We will be picking a random duration between a min and max duration, if the optional 'random' behaviour tree\n // function option is defined then we will be using that, otherwise we will fall back to using Math.random.\n const random = typeof options.random === \"function\" ? options.random : Math.random;\n\n // Pick a random duration between a min and max duration.\n this.totalDuration = Math.floor(\n random() * (this.durationMax - this.durationMin + 1) + this.durationMin\n );\n } else {\n this.totalDuration = null;\n }\n\n // The node is now running until we finish waiting.\n this.setState(State.RUNNING);\n }\n\n // If we have no total duration then this wait node will wait indefinitely until it is aborted.\n if (this.totalDuration === null) {\n return;\n }\n\n // If we have a 'getDeltaTime' function defined as part of our options then we will use it to figure out how long we have waited for.\n if (typeof options.getDeltaTime === \"function\") {\n // Get the delta time.\n const deltaTime = options.getDeltaTime();\n\n // Our delta time must be a valid number and cannot be NaN.\n if (typeof deltaTime !== \"number\" || isNaN(deltaTime)) {\n throw new Error(\"The delta time must be a valid number and not NaN.\");\n }\n\n // Update the amount of time that this node has been waiting for based on the delta time.\n this.waitedDuration += deltaTime * 1000;\n } else {\n // We are not using a delta time, so we will just work out hom much time has passed since the first update.\n this.waitedDuration = new Date().getTime() - this.initialUpdateTime;\n }\n\n // Have we waited long enough?\n if (this.waitedDuration >= this.totalDuration) {\n // We have finished waiting!\n this.setState(State.SUCCEEDED);\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => {\n if (this.duration !== null) {\n return `WAIT ${this.duration}ms`;\n } else if (this.durationMin !== null && this.durationMax !== null) {\n return `WAIT ${this.durationMin}ms-${this.durationMax}ms`;\n } else {\n return \"WAIT\";\n }\n };\n}\n", "import Guard from \"./guards/Guard\";\n\nexport type AttributeDetails = {\n /** The attribute type. */\n type: string;\n\n /** The attribute arguments. */\n args: any[];\n};\n\n/**\n * A base node attribute.\n */\nexport default abstract class Attribute {\n /**\n * @param type The node attribute type.\n * @param args The array of attribute arguments.\n */\n constructor(public type: string, public args: any[]) {}\n\n /**\n * Gets the attribute details.\n */\n abstract getDetails(): TAttributeDetails;\n\n /**\n * Gets whether this attribute is a guard.\n */\n abstract isGuard: () => this is Guard;\n}\n", "import { Agent } from \"../../Agent\";\nimport Attribute, { AttributeDetails } from \"../Attribute\";\n\nexport type GuardAttributeDetails = {\n /** The name of the condition function that determines whether the guard is satisfied. */\n condition: string;\n} & AttributeDetails;\n\n/**\n * A base node guard attribute.\n */\nexport default abstract class Guard extends Attribute {\n /**\n * @param type The node attribute type.\n * @param args The array of decorator argument definitions.\n * @param condition The name of the condition function that determines whether the guard is satisfied.\n */\n constructor(type: string, args: any[], private condition: string) {\n super(type, args);\n }\n\n /**\n * Gets the name of the condition function that determines whether the guard is satisfied.\n */\n getCondition = () => this.condition;\n\n /**\n * Gets whether this attribute is a guard.\n */\n isGuard = () => true;\n\n /**\n * Gets the attribute details.\n */\n getDetails(): GuardAttributeDetails {\n return {\n type: this.type,\n args: this.args,\n condition: this.getCondition()\n };\n }\n\n /**\n * Gets whether the guard is satisfied.\n * @param agent The agent.\n * @returns Whether the guard is satisfied.\n */\n abstract isSatisfied(agent: Agent): boolean;\n}\n", "import Guard from \"./Guard\";\nimport Lookup from \"../../Lookup\";\nimport { Agent } from \"../../Agent\";\n\n/**\n * A WHILE guard which is satisfied as long as the given condition remains true.\n */\nexport default class While extends Guard {\n /**\n * @param condition The name of the condition function that determines whether the guard is satisfied.\n * @param args The array of decorator argument definitions.\n */\n constructor(condition: string, args: any[]) {\n super(\"while\", args, condition);\n }\n\n /**\n * Gets whether the guard is satisfied.\n * @param agent The agent.\n * @returns Whether the guard is satisfied.\n */\n isSatisfied = (agent: Agent) => {\n // Attempt to get the invoker for the condition function.\n const conditionFuncInvoker = Lookup.getFuncInvoker(agent, this.getCondition());\n\n // The condition function should be defined.\n if (conditionFuncInvoker === null) {\n throw new Error(\n `cannot evaluate node guard as the condition '${this.getCondition()}' function is not defined on the agent and has not been registered`\n );\n }\n\n let conditionFunctionResult;\n\n try {\n // Call the guard condition function to determine the state of this node, the result of which should be a boolean.\n conditionFunctionResult = conditionFuncInvoker(this.args);\n } catch (error) {\n // The user was naughty and threw something.\n throw new Error(`guard condition function '${this.getCondition()}' threw '${error}'`);\n }\n\n // The result of calling the guard condition function must be a boolean value.\n if (typeof conditionFunctionResult !== \"boolean\") {\n throw new Error(\n `expected guard condition function '${this.getCondition()}' to return a boolean but returned '${conditionFunctionResult}'`\n );\n }\n\n // Return whether this guard is satisfied.\n return conditionFunctionResult;\n };\n}\n", "import Guard from \"./Guard\";\nimport Lookup from \"../../Lookup\";\nimport { Agent } from \"../../Agent\";\n\n/**\n * An UNTIL guard which is satisfied as long as the given condition remains false.\n */\nexport default class Until extends Guard {\n /**\n * @param condition The name of the condition function that determines whether the guard is satisfied.\n * @param args The array of decorator argument definitions.\n */\n constructor(condition: string, args: any[]) {\n super(\"until\", args, condition);\n }\n\n /**\n * Gets whether the guard is satisfied.\n * @param agent The agent.\n * @returns Whether the guard is satisfied.\n */\n isSatisfied = (agent: Agent) => {\n // Attempt to get the invoker for the condition function.\n const conditionFuncInvoker = Lookup.getFuncInvoker(agent, this.getCondition());\n\n // The condition function should be defined.\n if (conditionFuncInvoker === null) {\n throw new Error(\n `cannot evaluate node guard as the condition '${this.getCondition()}' function is not defined on the agent and has not been registered`\n );\n }\n\n let conditionFunctionResult;\n\n try {\n // Call the guard condition function to determine the state of this node, the result of which should be a boolean.\n conditionFunctionResult = conditionFuncInvoker(this.args);\n } catch (error) {\n // The user was naughty and threw something.\n throw new Error(`guard condition function '${this.getCondition()}' threw '${error}'`);\n }\n\n // The result of calling the guard condition function must be a boolean value.\n if (typeof conditionFunctionResult !== \"boolean\") {\n throw new Error(\n `expected guard condition function '${this.getCondition()}' to return a boolean but returned '${conditionFunctionResult}'`\n );\n }\n\n // Return whether this guard is satisfied.\n return !conditionFunctionResult;\n };\n}\n", "import { Agent } from \"../../Agent\";\nimport Attribute, { AttributeDetails } from \"../Attribute\";\n\nexport type CallbackAttributeDetails = {\n /** The name of the agent function that is called. */\n functionName: string;\n} & AttributeDetails;\n\n/**\n * A base node callback attribute.\n */\nexport default abstract class Callback extends Attribute {\n /**\n * @param type The node attribute type.\n * @param args The array of decorator argument definitions.\n * @param functionName The name of the agent function to call.\n */\n constructor(type: string, args: any[], private functionName: string) {\n super(type, args);\n }\n\n /**\n * Gets the name of the agent function to call.\n */\n getFunctionName = () => this.functionName;\n\n /**\n * Gets whether this attribute is a guard.\n */\n isGuard = () => false;\n\n /**\n * Gets the attribute details.\n */\n getDetails(): CallbackAttributeDetails {\n return {\n type: this.type,\n args: this.args,\n functionName: this.getFunctionName()\n };\n }\n\n /**\n * Attempt to call the agent function that this callback refers to.\n * @param agent The agent.\n */\n abstract callAgentFunction: (agent: Agent, isSuccess: boolean, isAborted: boolean) => void;\n}\n", "import Callback from \"./Callback\";\nimport Lookup from \"../../Lookup\";\nimport { Agent } from \"../../Agent\";\n\n/**\n * An ENTRY callback which defines an agent function to call when the associated node is updated and moves out of running state.\n */\nexport default class Entry extends Callback {\n /**\n * @param functionName The name of the agent function to call.\n * @param args The array of callback argument definitions.\n */\n constructor(functionName: string, args: any[]) {\n super(\"entry\", args, functionName);\n }\n\n /**\n * Attempt to call the agent function that this callback refers to.\n * @param agent The agent.\n */\n callAgentFunction = (agent: Agent) => {\n // Attempt to get the invoker for the callback function.\n const callbackFuncInvoker = Lookup.getFuncInvoker(agent, this.getFunctionName());\n\n // The callback function should be defined.\n if (callbackFuncInvoker === null) {\n throw new Error(\n `cannot call entry function '${this.getFunctionName()}' as is not defined on the agent and has not been registered`\n );\n }\n\n // Call the callback function.\n callbackFuncInvoker(this.args);\n };\n}\n", "import Callback from \"./Callback\";\nimport Lookup from \"../../Lookup\";\nimport { Agent } from \"../../Agent\";\n\n/**\n * A STEP callback which defines an agent function to call when the associated node is updated.\n */\nexport default class Step extends Callback {\n /**\n * @param functionName The name of the agent function to call.\n * @param args The array of callback argument definitions.\n */\n constructor(functionName: string, args: any[]) {\n super(\"step\", args, functionName);\n }\n\n /**\n * Attempt to call the agent function that this callback refers to.\n * @param agent The agent.\n */\n callAgentFunction = (agent: Agent) => {\n // Attempt to get the invoker for the callback function.\n const callbackFuncInvoker = Lookup.getFuncInvoker(agent, this.getFunctionName());\n\n // The callback function should be defined.\n if (callbackFuncInvoker === null) {\n throw new Error(\n `cannot call step function '${this.getFunctionName()}' as is not defined on the agent and has not been registered`\n );\n }\n\n // Call the callback function.\n callbackFuncInvoker(this.args);\n };\n}\n", "import Callback from \"./Callback\";\nimport Lookup from \"../../Lookup\";\nimport { Agent } from \"../../Agent\";\n\n/**\n * An EXIT callback which defines an agent function to call when the associated node is updated and moves to a finished state or is aborted.\n */\nexport default class Exit extends Callback {\n /**\n * @param functionName The name of the agent function to call.\n * @param args The array of callback argument definitions.\n */\n constructor(functionName: string, args: any[]) {\n super(\"exit\", args, functionName);\n }\n\n /**\n * Attempt to call the agent function that this callback refers to.\n * @param agent The agent.\n * @param isSuccess Whether the decorated node was left with a success state.\n * @param isAborted Whether the decorated node was aborted.\n */\n callAgentFunction = (agent: Agent, isSuccess: boolean, isAborted: boolean) => {\n // Attempt to get the invoker for the callback function.\n const callbackFuncInvoker = Lookup.getFuncInvoker(agent, this.getFunctionName());\n\n // The callback function should be defined.\n if (callbackFuncInvoker === null) {\n throw new Error(\n `cannot call exit function '${this.getFunctionName()}' as is not defined on the agent and has not been registered`\n );\n }\n\n // Call the callback function\n callbackFuncInvoker([{ succeeded: isSuccess, aborted: isAborted }, ...this.args]);\n };\n}\n", "import { AnyNodeDefinition, RootNodeDefinition } from \"./BehaviourTreeDefinition\";\nimport GuardPath, { GuardPathPart } from \"./attributes/guards/GuardPath\";\nimport { validateBranchSubtreeLinks } from \"./BehaviourTreeDefinitionValidator\";\nimport { isInteger } from \"./BehaviourTreeDefinitionUtilities\";\nimport Node from \"./nodes/Node\";\nimport Composite from \"./nodes/composite/Composite\";\nimport Decorator from \"./nodes/decorator/Decorator\";\nimport Parallel from \"./nodes/composite/Parallel\";\nimport Selector from \"./nodes/composite/Selector\";\nimport Sequence from \"./nodes/composite/Sequence\";\nimport Lotto from \"./nodes/composite/Lotto\";\nimport Fail from \"./nodes/decorator/Fail\";\nimport Flip from \"./nodes/decorator/Flip\";\nimport Repeat from \"./nodes/decorator/Repeat\";\nimport Retry from \"./nodes/decorator/Retry\";\nimport Root from \"./nodes/decorator/Root\";\nimport Succeed from \"./nodes/decorator/Succeed\";\nimport Action from \"./nodes/leaf/Action\";\nimport Condition from \"./nodes/leaf/Condition\";\nimport Wait from \"./nodes/leaf/Wait\";\nimport Lookup from \"./Lookup\";\nimport Attribute from \"./attributes/Attribute\";\nimport While from \"./attributes/guards/While\";\nimport Until from \"./attributes/guards/Until\";\nimport Entry from \"./attributes/callbacks/Entry\";\nimport Step from \"./attributes/callbacks/Step\";\nimport Exit from \"./attributes/callbacks/Exit\";\n\n/**\n * A type representing any node instance in a behaviour tree.\n */\ntype AnyNode =\n | Root\n | Action\n | Condition\n | Wait\n | Sequence\n | Selector\n | Lotto\n | Parallel\n | Repeat\n | Retry\n | Flip\n | Succeed\n | Fail;\n\n/**\n * A type defining a mapping of root node identifiers to root node definitions.\n */\ntype RootNodeDefinitionMap = { [key: string | symbol]: RootNodeDefinition };\n\n/**\n * A symbol to use as the main root key in any root node mappings.\n */\nconst MAIN_ROOT_NODE_KEY = Symbol(\"__root__\");\n\n/**\n * Build and populate the root nodes based on the provided definition, assuming that the definition has been validated.\n * @param definition The root node definitions.\n * @returns The built and populated root node definitions.\n */\nexport default function buildRootNode(definition: RootNodeDefinition[]): Root {\n // Create a mapping of root node identifers to root node definitions, including globally registered subtree root node definitions.\n const rootNodeDefinitionMap = createRootNodeDefinitionMap(definition);\n\n // Now that we have all of our root node definitions (those part of the tree definition and those globally registered)\n // we should validate the branch-subtree links. This will also double-check that we dont have any circular dependencies\n // in our branch-subtree references and that we have no broken branch-subtree links.\n validateBranchSubtreeLinks(\n [rootNodeDefinitionMap[MAIN_ROOT_NODE_KEY], ...Object.values(rootNodeDefinitionMap)],\n true\n );\n\n // Create our populated tree of node instances, starting with our main root node.\n const rootNode = nodeFactory(rootNodeDefinitionMap[MAIN_ROOT_NODE_KEY], rootNodeDefinitionMap) as Root;\n\n // Set a guard path on every leaf of the tree to evaluate as part of each update.\n applyLeafNodeGuardPaths(rootNode);\n\n // We only need to return the main root node.\n return rootNode;\n}\n\n/**\n * A factory function which creates a node instance based on the specified definition.\n * @param definition The node definition.\n * @param rootNodeDefinitionMap The mapping of root node identifers to root node definitions, including globally registered subtree root node definitions.\n * @returns A node instance based on the specified definition.\n */\nfunction nodeFactory(definition: AnyNodeDefinition, rootNodeDefinitionMap: RootNodeDefinitionMap): AnyNode {\n // Get the attributes for the node.\n const attributes = nodeAttributesFactory(definition);\n\n // Create the node instance based on the definition type.\n switch (definition.type) {\n case \"root\":\n return new Root(attributes, nodeFactory(definition.child, rootNodeDefinitionMap));\n\n case \"repeat\":\n let iterations: number | null = null;\n let iterationsMin: number | null = null;\n let iterationsMax: number | null = null;\n\n if (Array.isArray(definition.iterations)) {\n iterationsMin = definition.iterations[0];\n iterationsMax = definition.iterations[1];\n } else if (isInteger(definition.iterations)) {\n iterations = definition.iterations!;\n }\n\n return new Repeat(\n attributes,\n iterations,\n iterationsMin,\n iterationsMax,\n nodeFactory(definition.child, rootNodeDefinitionMap)\n );\n\n case \"retry\":\n let attempts: number | null = null;\n let attemptsMin: number | null = null;\n let attemptsMax: number | null = null;\n\n if (Array.isArray(definition.attempts)) {\n attemptsMin = definition.attempts[0];\n attemptsMax = definition.attempts[1];\n } else if (isInteger(definition.attempts)) {\n attempts = definition.attempts!;\n }\n\n return new Retry(\n attributes,\n attempts,\n attemptsMin,\n attemptsMax,\n nodeFactory(definition.child, rootNodeDefinitionMap)\n );\n\n case \"flip\":\n return new Flip(attributes, nodeFactory(definition.child, rootNodeDefinitionMap));\n\n case \"succeed\":\n return new Succeed(attributes, nodeFactory(definition.child, rootNodeDefinitionMap));\n\n case \"fail\":\n return new Fail(attributes, nodeFactory(definition.child, rootNodeDefinitionMap));\n\n case \"sequence\":\n return new Sequence(\n attributes,\n definition.children.map((child) => nodeFactory(child, rootNodeDefinitionMap))\n );\n\n case \"selector\":\n return new Selector(\n attributes,\n definition.children.map((child) => nodeFactory(child, rootNodeDefinitionMap))\n );\n\n case \"parallel\":\n return new Parallel(\n attributes,\n definition.children.map((child) => nodeFactory(child, rootNodeDefinitionMap))\n );\n\n case \"lotto\":\n return new Lotto(\n attributes,\n definition.weights,\n definition.children.map((child) => nodeFactory(child, rootNodeDefinitionMap))\n );\n\n case \"branch\":\n return nodeFactory(rootNodeDefinitionMap[definition.ref].child, rootNodeDefinitionMap);\n\n case \"action\":\n return new Action(attributes, definition.call, definition.args || []);\n\n case \"condition\":\n return new Condition(attributes, definition.call, definition.args || []);\n\n case \"wait\":\n let duration: number | null = null;\n let durationMin: number | null = null;\n let durationMax: number | null = null;\n\n if (Array.isArray(definition.duration)) {\n durationMin = definition.duration[0];\n durationMax = definition.duration[1];\n } else if (isInteger(definition.duration)) {\n duration = definition.duration!;\n }\n\n return new Wait(attributes, duration, durationMin, durationMax);\n }\n}\n\n/**\n * Creates an array of node attribute instances based on the specified node definition.\n * @param definition The node definition.\n * @returns An array of node attribute instances based on the specified node definition.\n */\nfunction nodeAttributesFactory(definition: AnyNodeDefinition): Attribute[] {\n const attributes: Attribute[] = [];\n\n if (definition.while) {\n attributes.push(new While(definition.while.call, definition.while.args ?? []));\n }\n\n if (definition.until) {\n attributes.push(new Until(definition.until.call, definition.until.args ?? []));\n }\n\n if (definition.entry) {\n attributes.push(new Entry(definition.entry.call, definition.entry.args ?? []));\n }\n\n if (definition.step) {\n attributes.push(new Step(definition.step.call, definition.step.args ?? []));\n }\n\n if (definition.exit) {\n attributes.push(new Exit(definition.exit.call, definition.exit.args ?? []));\n }\n\n return attributes;\n}\n\n/**\n * Creates a mapping of root node identifers to root node definitions, mixing in globally registered subtree root node definitions.\n * @param definition The root node definitions.\n * @returns A mapping of root node identifers to root node definitions, including globally registered subtree root node definitions.\n */\nfunction createRootNodeDefinitionMap(definition: RootNodeDefinition[]): RootNodeDefinitionMap {\n // Create a mapping of root node identifers to root node definitions.\n const rootNodeMap: RootNodeDefinitionMap = {};\n\n // Add in any registered subtree root node definitions.\n for (const [name, rootNodeDefinition] of Object.entries(Lookup.getSubtrees())) {\n // The name used when registering the subtree will be used as the root node identifier.\n rootNodeMap[name] = { ...rootNodeDefinition, id: name };\n }\n\n // Populate the map with the root node definitions that were included with the tree definition.\n // We do this after adding any registered subtrees as we want these to take presedence.\n for (const rootNodeDefinition of definition) {\n rootNodeMap[rootNodeDefinition.id ?? MAIN_ROOT_NODE_KEY] = rootNodeDefinition;\n }\n\n return rootNodeMap;\n}\n\n/**\n * Applies a guard path to every leaf of the tree to evaluate as part of each update.\n * @param root The main root tree node.\n */\nfunction applyLeafNodeGuardPaths(root: Root) {\n const nodePaths: Node[][] = [];\n\n const findLeafNodes = (path: Node[], node: Node) => {\n // Add the current node to the path.\n path = path.concat(node);\n\n // Check whether the current node is a leaf node.\n if (node.isLeafNode()) {\n nodePaths.push(path);\n } else {\n (node as Composite | Decorator).getChildren().forEach((child) => findLeafNodes(path, child));\n }\n };\n\n // Find all leaf node paths, starting from the root.\n findLeafNodes([], root);\n\n nodePaths.forEach((path) => {\n // Each node in the current path will have to be assigned a guard path, working from the root outwards.\n for (let depth = 0; depth < path.length; depth++) {\n // Get the node in the path at the current depth.\n const currentNode = path[depth];\n\n // The node may already have been assigned a guard path, if so just skip it.\n if (currentNode.hasGuardPath()) {\n continue;\n }\n\n // Create the guard path for the current node.\n const guardPath = new GuardPath(\n path\n .slice(0, depth + 1)\n .map((node) => ({ node, guards: node.getGuardAttributes() }))\n .filter((details) => details.guards.length > 0)\n );\n\n // Assign the guard path to the current node.\n currentNode.setGuardPath(guardPath);\n }\n });\n}\n", "import State, { AnyState } from \"./State\";\nimport Lookup from \"./Lookup\";\nimport Node from \"./nodes/Node\";\nimport Root from \"./nodes/decorator/Root\";\nimport Composite from \"./nodes/composite/Composite\";\nimport Decorator from \"./nodes/decorator/Decorator\";\nimport { Agent, GlobalFunction } from \"./Agent\";\nimport { CallbackAttributeDetails } from \"./attributes/callbacks/Callback\";\nimport { GuardAttributeDetails } from \"./attributes/guards/Guard\";\nimport { BehaviourTreeOptions } from \"./BehaviourTreeOptions\";\nimport { convertMDSLToJSON } from \"./mdsl/MDSLDefinitionParser\";\nimport { RootNodeDefinition } from \"./BehaviourTreeDefinition\";\nimport { validateDefinition, validateJSONDefinition } from \"./BehaviourTreeDefinitionValidator\";\nimport buildRootNode from \"./BehaviourTreeBuilder\";\nimport { isNullOrUndefined } from \"./BehaviourTreeDefinitionUtilities\";\n\n// Purely for outside inspection of the tree.\nexport type FlattenedTreeNode = {\n id: string;\n type: string;\n caption: string;\n state: AnyState;\n guards: GuardAttributeDetails[];\n callbacks: CallbackAttributeDetails[];\n args: any[];\n parentId: string | null;\n};\n\n/**\n * A representation of a behaviour tree.\n */\nexport class BehaviourTree {\n /**\n * The main root tree node.\n */\n private readonly _rootNode: Root;\n\n /**\n * Creates a new instance of the BehaviourTree class.\n * @param definition The behaviour tree definition as either an MDSL string, root node definition object or array of root node definition objects.\n * @param agent The agent instance that this behaviour tree is modelling behaviour for.\n * @param options The behaviour tree options object.\n */\n constructor(\n definition: string | RootNodeDefinition | RootNodeDefinition[],\n private agent: Agent,\n private options: BehaviourTreeOptions = {}\n ) {\n // The tree definition must be defined.\n if (isNullOrUndefined(definition)) {\n throw new Error(\"tree definition not defined\");\n }\n\n // The agent must be defined and not null.\n if (typeof agent !== \"object\" || agent === null) {\n throw new Error(\"the agent must be an object and not null\");\n }\n\n // We should validate the definition before we try to build the tree nodes.\n const { succeeded, errorMessage, json } = validateDefinition(definition);\n\n // Did our validation fail without error?\n if (!succeeded) {\n throw new Error(`invalid definition: ${errorMessage}`);\n }\n\n // Double check that we did actually get our json definition as part of our definition validtion.\n if (!json) {\n throw new Error(\n \"expected json definition to be returned as part of successful definition validation response\"\n );\n }\n\n try {\n // Create the populated tree of behaviour tree nodes and get the root node.\n this._rootNode = buildRootNode(json);\n } catch (exception) {\n // There was an issue in trying build and populate the behaviour tree.\n throw new Error(`error building tree: ${(exception as Error).message}`);\n }\n }\n\n /**\n * Gets whether the tree is in the RUNNING state.\n * @returns true if the tree is in the RUNNING state, otherwise false.\n */\n isRunning() {\n return this._rootNode.getState() === State.RUNNING;\n }\n\n /**\n * Gets the current tree state of SUCCEEDED, FAILED, READY or RUNNING.\n * @returns The current tree state.\n */\n getState() {\n return this._rootNode.getState();\n }\n\n /**\n * Step the tree.\n * 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.\n * 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\n * 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.\n *\n * 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.\n */\n step() {\n // If the root node has already been stepped to completion then we need to reset it.\n if (this._rootNode.getState() === State.SUCCEEDED || this._rootNode.getState() === State.FAILED) {\n this._rootNode.reset();\n }\n\n try {\n this._rootNode.update(this.agent, this.options);\n } catch (exception) {\n throw new Error(`error stepping tree: ${(exception as Error).message}`);\n }\n }\n\n /**\n * Resets the tree from the root node outwards to each nested node, giving each a state of READY.\n */\n reset() {\n this._rootNode.reset();\n }\n\n /**\n * Gets the flattened details of every node in the tree.\n * @returns The flattened details of every node in the tree.\n */\n getFlattenedNodeDetails(): FlattenedTreeNode[] {\n // Create an empty flattened array of tree nodes.\n const flattenedTreeNodes: FlattenedTreeNode[] = [];\n\n /**\n * Helper function to process a node instance and push details into the flattened tree nodes array.\n * @param node The current node.\n * @param parentUid The UID of the node parent, or null if the node is the main root node.\n */\n const processNode = (node: Node, parentUid: string | null) => {\n // Get the guard and callback attribute details for this node.\n const guards = node\n .getAttributes()\n .filter((attribute) => attribute.isGuard())\n .map((attribute) => attribute.getDetails()) as GuardAttributeDetails[];\n const callbacks = node\n .getAttributes()\n .filter((attribute) => !attribute.isGuard())\n .map((attribute) => attribute.getDetails()) as CallbackAttributeDetails[];\n\n // Push the current node into the flattened nodes array.\n flattenedTreeNodes.push({\n id: node.getUid(),\n type: node.getType(),\n caption: node.getName(),\n state: node.getState(),\n guards,\n callbacks,\n args: node.getArguments(),\n parentId: parentUid\n });\n\n // Process each of the nodes children if it is not a leaf node.\n if (!node.isLeafNode()) {\n (node as Composite | Decorator)\n .getChildren()\n .forEach((child) => processNode(child, (node as Composite | Decorator).getUid()));\n }\n };\n\n // Convert the nested node structure into a flattened array of node details.\n processNode(this._rootNode, null);\n\n return flattenedTreeNodes;\n }\n\n /**\n * Registers the action/condition/guard/callback function or subtree with the given name.\n * @param name The name of the function or subtree to register.\n * @param value The function or subtree definition to register.\n */\n static register(name: string, value: GlobalFunction | string | RootNodeDefinition) {\n // Are we going to register a action/condition/guard/callback function?\n if (typeof value === \"function\") {\n Lookup.setFunc(name, value);\n return;\n }\n\n // We are not registering an action/condition/guard/callback function, so we must be registering a subtree.\n if (typeof value === \"string\") {\n let rootNodeDefinitions: RootNodeDefinition[];\n\n // We will assume that any string passed in will be a mdsl definition.\n try {\n rootNodeDefinitions = convertMDSLToJSON(value);\n } catch (exception) {\n throw new Error(`error registering definition, invalid MDSL: ${(exception as Error).message}`);\n }\n\n // This function should only ever be called with a definition containing a single unnamed root node.\n if (rootNodeDefinitions.length != 1 || rootNodeDefinitions[0].id !== null) {\n throw new Error(\"error registering definition: expected a single unnamed root node\");\n }\n\n try {\n // We should validate the subtree as we don't want invalid subtrees available via the lookup.\n const { succeeded, errorMessage } = validateJSONDefinition(rootNodeDefinitions[0]);\n\n // Did our validation fail without error?\n if (!succeeded) {\n throw new Error(errorMessage);\n }\n } catch (exception) {\n throw new Error(`error registering definition: ${(exception as Error).message}`);\n }\n\n // Everything seems hunky-dory, register the subtree.\n Lookup.setSubtree(name, rootNodeDefinitions[0]);\n } else if (typeof value === \"object\" && !Array.isArray(value)) {\n // We will assume that any object passed in is a root node definition.\n\n try {\n // We should validate the subtree as we don't want invalid subtrees available via the lookup.\n const { succeeded, errorMessage } = validateJSONDefinition(value);\n\n // Did our validation fail without error?\n if (!succeeded) {\n throw new Error(errorMessage);\n }\n } catch (exception) {\n throw new Error(`error registering definition: ${(exception as Error).message}`);\n }\n\n // Everything seems hunky-dory, register the subtree.\n Lookup.setSubtree(name, value);\n } else {\n throw new Error(\"unexpected value, expected string mdsl definition, root node json definition or function\");\n }\n }\n\n /**\n * Unregisters the registered action/condition/guard/callback function or subtree with the given name.\n * @param name The name of the registered action/condition/guard/callback function or subtree to unregister.\n */\n static unregister(name: string): void {\n Lookup.remove(name);\n }\n\n /**\n * Unregister all registered action/condition/guard/callback functions and subtrees.\n */\n static unregisterAll(): void {\n Lookup.empty();\n }\n}\n"], + "mappings": "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", "names": ["Participant", "isNullOrUndefined", "Lotto", "createLotto", "State", "createLotto"] } diff --git a/src/attributes/guards/Until.ts b/src/attributes/guards/Until.ts index 4152bc9..542f2a8 100644 --- a/src/attributes/guards/Until.ts +++ b/src/attributes/guards/Until.ts @@ -30,7 +30,24 @@ export default class Until extends Guard { ); } - // Call the condition function to determine whether this guard is satisfied. - return !!!conditionFuncInvoker(this.args); + let conditionFunctionResult; + + try { + // Call the guard condition function to determine the state of this node, the result of which should be a boolean. + conditionFunctionResult = conditionFuncInvoker(this.args); + } catch (error) { + // The user was naughty and threw something. + throw new Error(`guard condition function '${this.getCondition()}' threw '${error}'`); + } + + // The result of calling the guard condition function must be a boolean value. + if (typeof conditionFunctionResult !== "boolean") { + throw new Error( + `expected guard condition function '${this.getCondition()}' to return a boolean but returned '${conditionFunctionResult}'` + ); + } + + // Return whether this guard is satisfied. + return !conditionFunctionResult; }; } diff --git a/src/attributes/guards/While.ts b/src/attributes/guards/While.ts index 13be8dc..c189891 100644 --- a/src/attributes/guards/While.ts +++ b/src/attributes/guards/While.ts @@ -30,7 +30,24 @@ export default class While extends Guard { ); } - // Call the condition function to determine whether this guard is satisfied. - return !!conditionFuncInvoker(this.args); + let conditionFunctionResult; + + try { + // Call the guard condition function to determine the state of this node, the result of which should be a boolean. + conditionFunctionResult = conditionFuncInvoker(this.args); + } catch (error) { + // The user was naughty and threw something. + throw new Error(`guard condition function '${this.getCondition()}' threw '${error}'`); + } + + // The result of calling the guard condition function must be a boolean value. + if (typeof conditionFunctionResult !== "boolean") { + throw new Error( + `expected guard condition function '${this.getCondition()}' to return a boolean but returned '${conditionFunctionResult}'` + ); + } + + // Return whether this guard is satisfied. + return conditionFunctionResult; }; } diff --git a/test/attributes/guards/Until.spec.ts b/test/attributes/guards/Until.spec.ts index 49bf92c..4c4f71e 100644 --- a/test/attributes/guards/Until.spec.ts +++ b/test/attributes/guards/Until.spec.ts @@ -1 +1,316 @@ -describe("An Until guard node attribute", () => {}); +import { assert } from "chai"; +import sinon from "sinon"; + +import { BehaviourTree, State } from "../../../src/index"; +import { RootNodeDefinition } from "../../../src/BehaviourTreeDefinition"; +import { findNode } from "../../TestUtilities"; + +describe("An Until guard node attribute", () => { + describe("on tree initialisation", () => { + describe("will error if no function name is defined", () => { + it("(MDSL)", () => { + const definition = "root { action [noop] until() }"; + assert.throws( + () => new BehaviourTree(definition, {}), + Error, + "invalid definition: expected agent function or registered function name identifier argument for attribute" + ); + }); + + it("(JSON)", () => { + const definition: RootNodeDefinition = { + type: "root", + child: { + type: "action", + call: "noop", + until: {} as any + } + }; + assert.throws( + () => new BehaviourTree(definition, {}), + Error, + "invalid definition: expected 'call' property for attribute 'until' to be a non-empty string for 'action' node at depth '1'" + ); + }); + }); + }); + + describe("when the node is updated as part of a tree step will call the guard function and", () => { + describe("abort the running node and an child nodes and move them to a FAILED state if the function returns a value of true", () => { + it("(MDSL)", () => { + const definition = `root { sequence until(someCondition, "condition-argument") { action [someAction] exit(onActionExit) } }`; + const agent = { + someAction: () => State.RUNNING, + someCondition: sinon.stub().returns(false), + onActionExit: sinon.stub() + }; + const tree = new BehaviourTree(definition, agent); + + tree.step(); + + assert.isTrue(tree.isRunning()); + assert.isTrue(agent.someCondition.calledWith("condition-argument")); + assert.strictEqual(findNode(tree, "root").state, State.RUNNING); + assert.strictEqual(findNode(tree, "sequence").state, State.RUNNING); + assert.strictEqual(findNode(tree, "action").state, State.RUNNING); + + agent.someCondition.returns(true); + + tree.step(); + + assert.isFalse(tree.isRunning()); + assert.isTrue(agent.someCondition.calledWith("condition-argument")); + assert.isTrue(agent.onActionExit.calledWith(sinon.match({ succeeded: false, aborted: true }))); + assert.strictEqual(findNode(tree, "root").state, State.FAILED); + assert.strictEqual(findNode(tree, "sequence").state, State.FAILED); + assert.strictEqual(findNode(tree, "action").state, State.READY); + + tree.reset(); + + assert.isFalse(tree.isRunning()); + assert.strictEqual(findNode(tree, "root").state, State.READY); + assert.strictEqual(findNode(tree, "sequence").state, State.READY); + assert.strictEqual(findNode(tree, "action").state, State.READY); + + tree.step(); + + assert.isFalse(tree.isRunning()); + assert.strictEqual(findNode(tree, "root").state, State.FAILED); + assert.strictEqual(findNode(tree, "sequence").state, State.FAILED); + assert.strictEqual(findNode(tree, "action").state, State.READY); + }); + + it("(JSON)", () => { + const definition: RootNodeDefinition = { + type: "root", + child: { + type: "sequence", + until: { + call: "someCondition", + args: ["condition-argument"] + }, + children: [ + { + type: "action", + exit: { + call: "onActionExit" + }, + call: "someAction" + } + ] + } + }; + const agent = { + someAction: () => State.RUNNING, + someCondition: sinon.stub().returns(false), + onActionExit: sinon.stub() + }; + const tree = new BehaviourTree(definition, agent); + + tree.step(); + + assert.isTrue(tree.isRunning()); + assert.isTrue(agent.someCondition.calledWith("condition-argument")); + assert.strictEqual(findNode(tree, "root").state, State.RUNNING); + assert.strictEqual(findNode(tree, "sequence").state, State.RUNNING); + assert.strictEqual(findNode(tree, "action").state, State.RUNNING); + + agent.someCondition.returns(true); + + tree.step(); + + assert.isFalse(tree.isRunning()); + assert.isTrue(agent.someCondition.calledWith("condition-argument")); + assert.isTrue(agent.onActionExit.calledWith(sinon.match({ succeeded: false, aborted: true }))); + assert.strictEqual(findNode(tree, "root").state, State.FAILED); + assert.strictEqual(findNode(tree, "sequence").state, State.FAILED); + assert.strictEqual(findNode(tree, "action").state, State.READY); + + tree.reset(); + + assert.isFalse(tree.isRunning()); + assert.strictEqual(findNode(tree, "root").state, State.READY); + assert.strictEqual(findNode(tree, "sequence").state, State.READY); + assert.strictEqual(findNode(tree, "action").state, State.READY); + + tree.step(); + + assert.isFalse(tree.isRunning()); + assert.strictEqual(findNode(tree, "root").state, State.FAILED); + assert.strictEqual(findNode(tree, "sequence").state, State.FAILED); + assert.strictEqual(findNode(tree, "action").state, State.READY); + }); + }); + + describe("does nothing if the function returns a value of false", () => { + it("(MDSL)", () => { + const definition = `root { sequence until(someCondition, "condition-argument") { action [someAction] } }`; + const agent = { + someAction: () => State.RUNNING, + someCondition: sinon.stub().returns(false) + }; + const tree = new BehaviourTree(definition, agent); + + tree.step(); + + assert.isTrue(tree.isRunning()); + assert.isTrue(agent.someCondition.calledWith("condition-argument")); + assert.strictEqual(findNode(tree, "root").state, State.RUNNING); + assert.strictEqual(findNode(tree, "sequence").state, State.RUNNING); + assert.strictEqual(findNode(tree, "action").state, State.RUNNING); + + agent.someAction = () => State.SUCCEEDED; + + tree.step(); + + assert.isFalse(tree.isRunning()); + assert.isTrue(agent.someCondition.calledWith("condition-argument")); + assert.strictEqual(findNode(tree, "root").state, State.SUCCEEDED); + assert.strictEqual(findNode(tree, "sequence").state, State.SUCCEEDED); + assert.strictEqual(findNode(tree, "action").state, State.SUCCEEDED); + }); + + it("(JSON)", () => { + const definition: RootNodeDefinition = { + type: "root", + child: { + type: "sequence", + until: { + call: "someCondition", + args: ["condition-argument"] + }, + children: [ + { + type: "action", + call: "someAction" + } + ] + } + }; + const agent = { + someAction: () => State.RUNNING, + someCondition: sinon.stub().returns(false) + }; + const tree = new BehaviourTree(definition, agent); + + tree.step(); + + assert.isTrue(tree.isRunning()); + assert.isTrue(agent.someCondition.calledWith("condition-argument")); + assert.strictEqual(findNode(tree, "root").state, State.RUNNING); + assert.strictEqual(findNode(tree, "sequence").state, State.RUNNING); + assert.strictEqual(findNode(tree, "action").state, State.RUNNING); + + agent.someAction = () => State.SUCCEEDED; + + tree.step(); + + assert.isFalse(tree.isRunning()); + assert.isTrue(agent.someCondition.calledWith("condition-argument")); + assert.strictEqual(findNode(tree, "root").state, State.SUCCEEDED); + assert.strictEqual(findNode(tree, "sequence").state, State.SUCCEEDED); + assert.strictEqual(findNode(tree, "action").state, State.SUCCEEDED); + }); + }); + + describe("throws an error if the guard condition function ", () => { + describe("does not return a boolean value", () => { + it("(MDSL)", () => { + const definition = `root { sequence until(someCondition, "condition-argument") { action [someAction] } }`; + const agent = { + someAction: () => State.RUNNING, + someCondition: () => "invalid-response" + }; + const tree = new BehaviourTree(definition, agent); + + assert.throws( + () => tree.step(), + Error, + "expected guard condition function 'someCondition' to return a boolean but returned 'invalid-response'" + ); + }); + + it("(JSON)", () => { + const definition: RootNodeDefinition = { + type: "root", + child: { + type: "sequence", + until: { + call: "someCondition", + args: ["condition-argument"] + }, + children: [ + { + type: "action", + call: "someAction" + } + ] + } + }; + const agent = { + someAction: () => State.RUNNING, + someCondition: () => "invalid-response" + }; + const tree = new BehaviourTree(definition, agent); + + assert.throws( + () => tree.step(), + Error, + "expected guard condition function 'someCondition' to return a boolean but returned 'invalid-response'" + ); + }); + }); + + describe("throws an exception", () => { + it("(MDSL)", () => { + const definition = `root { sequence until(someCondition, "condition-argument") { action [someAction] } }`; + const agent = { + someAction: () => State.RUNNING, + someCondition: () => { + throw new Error("some-error"); + } + }; + const tree = new BehaviourTree(definition, agent); + + assert.throws( + () => tree.step(), + Error, + "error stepping tree: guard condition function 'someCondition' threw 'Error: some-error'" + ); + }); + + it("(JSON)", () => { + const definition: RootNodeDefinition = { + type: "root", + child: { + type: "sequence", + until: { + call: "someCondition", + args: ["condition-argument"] + }, + children: [ + { + type: "action", + call: "someAction" + } + ] + } + }; + const agent = { + someAction: () => State.RUNNING, + someCondition: () => { + throw new Error("some-error"); + } + }; + const tree = new BehaviourTree(definition, agent); + + assert.throws( + () => tree.step(), + Error, + "error stepping tree: guard condition function 'someCondition' threw 'Error: some-error'" + ); + }); + }); + }); + }); +}); diff --git a/test/attributes/guards/While.spec.ts b/test/attributes/guards/While.spec.ts index 2575335..357ea59 100644 --- a/test/attributes/guards/While.spec.ts +++ b/test/attributes/guards/While.spec.ts @@ -1 +1,316 @@ -describe("A While guard node attribute", () => {}); +import { assert } from "chai"; +import sinon from "sinon"; + +import { BehaviourTree, State } from "../../../src/index"; +import { RootNodeDefinition } from "../../../src/BehaviourTreeDefinition"; +import { findNode } from "../../TestUtilities"; + +describe("A While guard node attribute", () => { + describe("on tree initialisation", () => { + describe("will error if no function name is defined", () => { + it("(MDSL)", () => { + const definition = "root { action [noop] while() }"; + assert.throws( + () => new BehaviourTree(definition, {}), + Error, + "invalid definition: expected agent function or registered function name identifier argument for attribute" + ); + }); + + it("(JSON)", () => { + const definition: RootNodeDefinition = { + type: "root", + child: { + type: "action", + call: "noop", + while: {} as any + } + }; + assert.throws( + () => new BehaviourTree(definition, {}), + Error, + "invalid definition: expected 'call' property for attribute 'while' to be a non-empty string for 'action' node at depth '1'" + ); + }); + }); + }); + + describe("when the node is updated as part of a tree step will call the guard function and", () => { + describe("abort the running node and an child nodes and move them to a FAILED state if the function returns a value of false", () => { + it("(MDSL)", () => { + const definition = `root { sequence while(someCondition, "condition-argument") { action [someAction] exit(onActionExit) } }`; + const agent = { + someAction: () => State.RUNNING, + someCondition: sinon.stub().returns(true), + onActionExit: sinon.stub() + }; + const tree = new BehaviourTree(definition, agent); + + tree.step(); + + assert.isTrue(tree.isRunning()); + assert.isTrue(agent.someCondition.calledWith("condition-argument")); + assert.strictEqual(findNode(tree, "root").state, State.RUNNING); + assert.strictEqual(findNode(tree, "sequence").state, State.RUNNING); + assert.strictEqual(findNode(tree, "action").state, State.RUNNING); + + agent.someCondition.returns(false); + + tree.step(); + + assert.isFalse(tree.isRunning()); + assert.isTrue(agent.someCondition.calledWith("condition-argument")); + assert.isTrue(agent.onActionExit.calledWith(sinon.match({ succeeded: false, aborted: true }))); + assert.strictEqual(findNode(tree, "root").state, State.FAILED); + assert.strictEqual(findNode(tree, "sequence").state, State.FAILED); + assert.strictEqual(findNode(tree, "action").state, State.READY); + + tree.reset(); + + assert.isFalse(tree.isRunning()); + assert.strictEqual(findNode(tree, "root").state, State.READY); + assert.strictEqual(findNode(tree, "sequence").state, State.READY); + assert.strictEqual(findNode(tree, "action").state, State.READY); + + tree.step(); + + assert.isFalse(tree.isRunning()); + assert.strictEqual(findNode(tree, "root").state, State.FAILED); + assert.strictEqual(findNode(tree, "sequence").state, State.FAILED); + assert.strictEqual(findNode(tree, "action").state, State.READY); + }); + + it("(JSON)", () => { + const definition: RootNodeDefinition = { + type: "root", + child: { + type: "sequence", + while: { + call: "someCondition", + args: ["condition-argument"] + }, + children: [ + { + type: "action", + exit: { + call: "onActionExit" + }, + call: "someAction" + } + ] + } + }; + const agent = { + someAction: () => State.RUNNING, + someCondition: sinon.stub().returns(true), + onActionExit: sinon.stub() + }; + const tree = new BehaviourTree(definition, agent); + + tree.step(); + + assert.isTrue(tree.isRunning()); + assert.isTrue(agent.someCondition.calledWith("condition-argument")); + assert.strictEqual(findNode(tree, "root").state, State.RUNNING); + assert.strictEqual(findNode(tree, "sequence").state, State.RUNNING); + assert.strictEqual(findNode(tree, "action").state, State.RUNNING); + + agent.someCondition.returns(false); + + tree.step(); + + assert.isFalse(tree.isRunning()); + assert.isTrue(agent.someCondition.calledWith("condition-argument")); + assert.isTrue(agent.onActionExit.calledWith(sinon.match({ succeeded: false, aborted: true }))); + assert.strictEqual(findNode(tree, "root").state, State.FAILED); + assert.strictEqual(findNode(tree, "sequence").state, State.FAILED); + assert.strictEqual(findNode(tree, "action").state, State.READY); + + tree.reset(); + + assert.isFalse(tree.isRunning()); + assert.strictEqual(findNode(tree, "root").state, State.READY); + assert.strictEqual(findNode(tree, "sequence").state, State.READY); + assert.strictEqual(findNode(tree, "action").state, State.READY); + + tree.step(); + + assert.isFalse(tree.isRunning()); + assert.strictEqual(findNode(tree, "root").state, State.FAILED); + assert.strictEqual(findNode(tree, "sequence").state, State.FAILED); + assert.strictEqual(findNode(tree, "action").state, State.READY); + }); + }); + + describe("does nothing if the function returns a value of true", () => { + it("(MDSL)", () => { + const definition = `root { sequence while(someCondition, "condition-argument") { action [someAction] } }`; + const agent = { + someAction: () => State.RUNNING, + someCondition: sinon.stub().returns(true) + }; + const tree = new BehaviourTree(definition, agent); + + tree.step(); + + assert.isTrue(tree.isRunning()); + assert.isTrue(agent.someCondition.calledWith("condition-argument")); + assert.strictEqual(findNode(tree, "root").state, State.RUNNING); + assert.strictEqual(findNode(tree, "sequence").state, State.RUNNING); + assert.strictEqual(findNode(tree, "action").state, State.RUNNING); + + agent.someAction = () => State.SUCCEEDED; + + tree.step(); + + assert.isFalse(tree.isRunning()); + assert.isTrue(agent.someCondition.calledWith("condition-argument")); + assert.strictEqual(findNode(tree, "root").state, State.SUCCEEDED); + assert.strictEqual(findNode(tree, "sequence").state, State.SUCCEEDED); + assert.strictEqual(findNode(tree, "action").state, State.SUCCEEDED); + }); + + it("(JSON)", () => { + const definition: RootNodeDefinition = { + type: "root", + child: { + type: "sequence", + while: { + call: "someCondition", + args: ["condition-argument"] + }, + children: [ + { + type: "action", + call: "someAction" + } + ] + } + }; + const agent = { + someAction: () => State.RUNNING, + someCondition: sinon.stub().returns(true) + }; + const tree = new BehaviourTree(definition, agent); + + tree.step(); + + assert.isTrue(tree.isRunning()); + assert.isTrue(agent.someCondition.calledWith("condition-argument")); + assert.strictEqual(findNode(tree, "root").state, State.RUNNING); + assert.strictEqual(findNode(tree, "sequence").state, State.RUNNING); + assert.strictEqual(findNode(tree, "action").state, State.RUNNING); + + agent.someAction = () => State.SUCCEEDED; + + tree.step(); + + assert.isFalse(tree.isRunning()); + assert.isTrue(agent.someCondition.calledWith("condition-argument")); + assert.strictEqual(findNode(tree, "root").state, State.SUCCEEDED); + assert.strictEqual(findNode(tree, "sequence").state, State.SUCCEEDED); + assert.strictEqual(findNode(tree, "action").state, State.SUCCEEDED); + }); + }); + + describe("throws an error if the guard condition function ", () => { + describe("does not return a boolean value", () => { + it("(MDSL)", () => { + const definition = `root { sequence while(someCondition, "condition-argument") { action [someAction] } }`; + const agent = { + someAction: () => State.RUNNING, + someCondition: () => "invalid-response" + }; + const tree = new BehaviourTree(definition, agent); + + assert.throws( + () => tree.step(), + Error, + "expected guard condition function 'someCondition' to return a boolean but returned 'invalid-response'" + ); + }); + + it("(JSON)", () => { + const definition: RootNodeDefinition = { + type: "root", + child: { + type: "sequence", + while: { + call: "someCondition", + args: ["condition-argument"] + }, + children: [ + { + type: "action", + call: "someAction" + } + ] + } + }; + const agent = { + someAction: () => State.RUNNING, + someCondition: () => "invalid-response" + }; + const tree = new BehaviourTree(definition, agent); + + assert.throws( + () => tree.step(), + Error, + "expected guard condition function 'someCondition' to return a boolean but returned 'invalid-response'" + ); + }); + }); + + describe("throws an exception", () => { + it("(MDSL)", () => { + const definition = `root { sequence while(someCondition, "condition-argument") { action [someAction] } }`; + const agent = { + someAction: () => State.RUNNING, + someCondition: () => { + throw new Error("some-error"); + } + }; + const tree = new BehaviourTree(definition, agent); + + assert.throws( + () => tree.step(), + Error, + "error stepping tree: guard condition function 'someCondition' threw 'Error: some-error'" + ); + }); + + it("(JSON)", () => { + const definition: RootNodeDefinition = { + type: "root", + child: { + type: "sequence", + while: { + call: "someCondition", + args: ["condition-argument"] + }, + children: [ + { + type: "action", + call: "someAction" + } + ] + } + }; + const agent = { + someAction: () => State.RUNNING, + someCondition: () => { + throw new Error("some-error"); + } + }; + const tree = new BehaviourTree(definition, agent); + + assert.throws( + () => tree.step(), + Error, + "error stepping tree: guard condition function 'someCondition' threw 'Error: some-error'" + ); + }); + }); + }); + }); +}); diff --git a/test/nodes/leaf/Action.spec.ts b/test/nodes/leaf/Action.spec.ts index e0754a3..7c18e23 100644 --- a/test/nodes/leaf/Action.spec.ts +++ b/test/nodes/leaf/Action.spec.ts @@ -145,7 +145,7 @@ describe("An Action node", () => { const definition = "root { action [doAction] }"; const agent = { doAction: () => { - throw new Error("Disaster!"); + throw new Error("some-error"); } }; const tree = new BehaviourTree(definition, agent); @@ -153,7 +153,7 @@ describe("An Action node", () => { assert.throws( () => tree.step(), Error, - "error stepping tree: action function 'doAction' threw 'Error: Disaster!'" + "error stepping tree: action function 'doAction' threw 'Error: some-error'" ); }); @@ -167,7 +167,7 @@ describe("An Action node", () => { }; const agent = { doAction: () => { - throw new Error("Disaster!"); + throw new Error("some-error"); } }; const tree = new BehaviourTree(definition, agent); @@ -175,7 +175,7 @@ describe("An Action node", () => { assert.throws( () => tree.step(), Error, - "error stepping tree: action function 'doAction' threw 'Error: Disaster!'" + "error stepping tree: action function 'doAction' threw 'Error: some-error'" ); }); }); From 1aa77121350eb14fccda15c621dfd38e00565ee0 Mon Sep 17 00:00:00 2001 From: Nikolas Howard Date: Fri, 1 Mar 2024 09:05:13 +0000 Subject: [PATCH 44/48] Improved error logging for agent functions --- dist/bundle.js | 24 ++++- dist/bundle.js.map | 4 +- dist/index.js | 24 ++++- dist/index.js.map | 4 +- src/attributes/guards/Until.ts | 8 +- src/attributes/guards/While.ts | 8 +- src/nodes/leaf/Action.ts | 8 +- src/nodes/leaf/Condition.ts | 8 +- test/attributes/guards/Until.spec.ts | 4 +- test/attributes/guards/While.spec.ts | 4 +- test/nodes/leaf/Action.spec.ts | 12 +-- test/nodes/leaf/Condition.spec.ts | 132 ++++++++++++++++++++++----- 12 files changed, 185 insertions(+), 55 deletions(-) diff --git a/dist/bundle.js b/dist/bundle.js index 7d3ef95..b212378 100644 --- a/dist/bundle.js +++ b/dist/bundle.js @@ -1788,7 +1788,11 @@ var mistreevous = (() => { try { actionFunctionResult = actionFuncInvoker(this.actionArguments); } catch (error) { - throw new Error(`action function '${this.actionName}' threw '${error}'`); + if (error instanceof Error) { + throw new Error(`action function '${this.actionName}' threw: ${error.stack}`); + } else { + throw new Error(`action function '${this.actionName}' threw: ${error}`); + } } if (actionFunctionResult instanceof Promise) { actionFunctionResult.then( @@ -1857,7 +1861,11 @@ var mistreevous = (() => { try { conditionFunctionResult = conditionFuncInvoker(this.conditionArguments); } catch (error) { - throw new Error(`condition function '${this.conditionName}' threw '${error}'`); + if (error instanceof Error) { + throw new Error(`condition function '${this.conditionName}' threw: ${error.stack}`); + } else { + throw new Error(`condition function '${this.conditionName}' threw: ${error}`); + } } if (typeof conditionFunctionResult !== "boolean") { throw new Error( @@ -1964,7 +1972,11 @@ var mistreevous = (() => { try { conditionFunctionResult = conditionFuncInvoker(this.args); } catch (error) { - throw new Error(`guard condition function '${this.getCondition()}' threw '${error}'`); + if (error instanceof Error) { + throw new Error(`guard condition function '${this.getCondition()}' threw: ${error.stack}`); + } else { + throw new Error(`guard condition function '${this.getCondition()}' threw: ${error}`); + } } if (typeof conditionFunctionResult !== "boolean") { throw new Error( @@ -1991,7 +2003,11 @@ var mistreevous = (() => { try { conditionFunctionResult = conditionFuncInvoker(this.args); } catch (error) { - throw new Error(`guard condition function '${this.getCondition()}' threw '${error}'`); + if (error instanceof Error) { + throw new Error(`guard condition function '${this.getCondition()}' threw: ${error.stack}`); + } else { + throw new Error(`guard condition function '${this.getCondition()}' threw: ${error}`); + } } if (typeof conditionFunctionResult !== "boolean") { throw new Error( diff --git a/dist/bundle.js.map b/dist/bundle.js.map index afcf63b..558a46f 100644 --- a/dist/bundle.js.map +++ b/dist/bundle.js.map @@ -1,7 +1,7 @@ { "version": 3, "sources": ["../node_modules/lotto-draw/dist/Participant.js", "../node_modules/lotto-draw/dist/Utilities.js", "../node_modules/lotto-draw/dist/Lotto.js", "../node_modules/lotto-draw/dist/createLotto.js", "../node_modules/lotto-draw/dist/index.js", "../src/index.ts", "../src/State.ts", "../src/BehaviourTreeDefinitionUtilities.ts", "../src/mdsl/MDSLUtilities.ts", "../src/mdsl/MDSLNodeArgumentParser.ts", "../src/mdsl/MDSLNodeAttributeParser.ts", "../src/mdsl/MDSLDefinitionParser.ts", "../src/BehaviourTreeDefinitionValidator.ts", "../src/Lookup.ts", "../src/attributes/guards/GuardUnsatisifedException.ts", "../src/attributes/guards/GuardPath.ts", "../src/nodes/Node.ts", "../src/nodes/composite/Composite.ts", "../src/nodes/composite/Parallel.ts", "../src/nodes/composite/Selector.ts", "../src/nodes/composite/Sequence.ts", "../src/nodes/composite/Lotto.ts", "../src/nodes/decorator/Decorator.ts", "../src/nodes/decorator/Fail.ts", "../src/nodes/decorator/Flip.ts", "../src/nodes/decorator/Repeat.ts", "../src/nodes/decorator/Retry.ts", "../src/nodes/decorator/Root.ts", "../src/nodes/decorator/Succeed.ts", "../src/nodes/leaf/Leaf.ts", "../src/nodes/leaf/Action.ts", "../src/nodes/leaf/Condition.ts", "../src/nodes/leaf/Wait.ts", "../src/attributes/Attribute.ts", "../src/attributes/guards/Guard.ts", "../src/attributes/guards/While.ts", "../src/attributes/guards/Until.ts", "../src/attributes/callbacks/Callback.ts", "../src/attributes/callbacks/Entry.ts", "../src/attributes/callbacks/Step.ts", "../src/attributes/callbacks/Exit.ts", "../src/BehaviourTreeBuilder.ts", "../src/BehaviourTree.ts"], - "sourcesContent": ["\"use strict\";\r\nObject.defineProperty(exports, \"__esModule\", { value: true });\r\nexports.Participant = void 0;\r\n/**\r\n * A participant that holds a number of tickets.\r\n */\r\nvar Participant = /** @class */ (function () {\r\n /**\r\n * Creates an instance of the Participant class.\r\n * @param participant The actual participant.\r\n * @param tickets The number of tickets held by the participant.\r\n */\r\n function Participant(participant, tickets) {\r\n if (tickets === void 0) { tickets = 1; }\r\n this._participant = participant;\r\n this._tickets = tickets;\r\n }\r\n Object.defineProperty(Participant.prototype, \"participant\", {\r\n /** Gets the actual participant. */\r\n get: function () {\r\n return this._participant;\r\n },\r\n enumerable: false,\r\n configurable: true\r\n });\r\n Object.defineProperty(Participant.prototype, \"tickets\", {\r\n /** Gets or sets the number of tickets held by the participant. */\r\n get: function () {\r\n return this._tickets;\r\n },\r\n set: function (value) {\r\n this._tickets = value;\r\n },\r\n enumerable: false,\r\n configurable: true\r\n });\r\n return Participant;\r\n}());\r\nexports.Participant = Participant;\r\n", "\"use strict\";\r\nObject.defineProperty(exports, \"__esModule\", { value: true });\r\nexports.isNaturalNumber = exports.isNullOrUndefined = void 0;\r\n/**\r\n * Gets whether the value provided is null or undefined.\r\n * @param value The value to check.\r\n * @returns Whether the value provided is null or undefined.\r\n */\r\nfunction isNullOrUndefined(value) {\r\n return value === null || value === undefined;\r\n}\r\nexports.isNullOrUndefined = isNullOrUndefined;\r\n/**\r\n * Gets whether the value provided is a natural number.\r\n * @param value The value to check.\r\n * @returns Whether the value provided is a natural number.\r\n */\r\nfunction isNaturalNumber(value) {\r\n return typeof value === \"number\" && value >= 1 && Math.floor(value) === value;\r\n}\r\nexports.isNaturalNumber = isNaturalNumber;\r\n", "\"use strict\";\r\nObject.defineProperty(exports, \"__esModule\", { value: true });\r\nexports.Lotto = void 0;\r\nvar Participant_1 = require(\"./Participant\");\r\nvar Utilities_1 = require(\"./Utilities\");\r\n/**\r\n * Represents a lotto consisting of a number of pickable ticket-holding participants.\r\n */\r\nvar Lotto = /** @class */ (function () {\r\n /**\r\n * Creates a new instance of Lotto.\r\n * @param customRandom The custom RNG to use in place of Math.random().\r\n */\r\n function Lotto(customRandom) {\r\n /** The array of participants that are holding tickets in the lotto. */\r\n this._participants = [];\r\n this._customRandom = customRandom;\r\n }\r\n /**\r\n * Adds a participant with the specified number of tickets, or adds to the participant ticket count if the participant already holds tickets.\r\n * @param participant The participant to add or to increase the ticket count for if they already hold tickets.\r\n * @param tickets The number of tickets, defaults to 1.\r\n * @returns The Lotto instance.\r\n */\r\n Lotto.prototype.add = function (participant, tickets) {\r\n if (tickets === void 0) { tickets = 1; }\r\n // Check that we have a valid ticket count.\r\n if (!(0, Utilities_1.isNaturalNumber)(tickets)) {\r\n throw new Error(\"tickets value must be a natural number\");\r\n }\r\n // Check whether this participant has already been added.\r\n var existingParticipant = this._participants.find(function (part) { return part.participant === participant; });\r\n if (existingParticipant) {\r\n // The participant has already been added to the lotto so just add to their ticket count.\r\n existingParticipant.tickets += tickets;\r\n }\r\n else {\r\n // The participant is not part of the lotto so we should add them.\r\n this._participants.push(new Participant_1.Participant(participant, tickets));\r\n }\r\n return this;\r\n };\r\n /**\r\n * Removes the specified number of tickets for the given participant from the draw, or all tickets if a ticket number is not defined.\r\n * @param participant The participant to remove tickets for.\r\n * @param tickets The number of tickets to remove, or undefined if all tickets are to be removed.\r\n * @returns The Lotto instance.\r\n */\r\n Lotto.prototype.remove = function (participant, tickets) {\r\n // Attempt to get the existing participant.\r\n var existingParticipant = this._participants.find(function (part) { return part.participant === participant; });\r\n // There is nothing to do if the specified participant isn't even part of the lotto.\r\n if (!existingParticipant) {\r\n return this;\r\n }\r\n // Check whether a tickets value was given.\r\n if (tickets !== undefined) {\r\n // Check that we have a valid ticket count.\r\n if (!(0, Utilities_1.isNaturalNumber)(tickets)) {\r\n throw new Error(\"tickets value must be a natural number\");\r\n }\r\n existingParticipant.tickets -= tickets;\r\n // If the participant no longer holds any tickets then they should be removed.\r\n if (existingParticipant.tickets < 1) {\r\n this._participants = this._participants.filter(function (part) { return part !== existingParticipant; });\r\n }\r\n }\r\n else {\r\n // We are removing all tickets for the participant so just remove them from the lotto.\r\n this._participants = this._participants.filter(function (part) { return part !== existingParticipant; });\r\n }\r\n return this;\r\n };\r\n /**\r\n * Draw a winning ticket and return the participant that holds the ticket.\r\n * @param options The draw options.\r\n * @returns The participant that holds the winning ticket.\r\n */\r\n Lotto.prototype.draw = function (options) {\r\n if (options === void 0) { options = {}; }\r\n // If we have no participants then just return null.\r\n if (this._participants.length === 0) {\r\n return null;\r\n }\r\n var redrawable = (0, Utilities_1.isNullOrUndefined)(options.redrawable) ? true : options.redrawable;\r\n var pickable = [];\r\n this._participants.forEach(function (_a) {\r\n var participant = _a.participant, tickets = _a.tickets;\r\n for (var ticketCount = 0; ticketCount < tickets; ticketCount++) {\r\n pickable.push(participant);\r\n }\r\n });\r\n var random;\r\n // We need a random floating-point number between 0 (inclusive) and 1 to scale up to pick our winner.\r\n // If a custom random function exists then we should use that or fall back to Math.random().\r\n if (this._customRandom) {\r\n // Call our custom random function to get a random floating-point number.\r\n random = this._customRandom();\r\n // Verify that the result of calling our custom random function is a number between 0 (inclusive) and 1.\r\n if (typeof random !== \"number\" || random < 0 || random >= 1) {\r\n throw new Error(\"the 'random' function provided did not return a number between 0 (inclusive) and 1\");\r\n }\r\n }\r\n else {\r\n // No custom random function was defined so just use good ol' Math.random().\r\n random = Math.random();\r\n }\r\n // Pick a winning participant.\r\n var winner = pickable[Math.floor(random * pickable.length)];\r\n // If the ticket isn't redrawable then we should remove a ticket from the winning participants ticket count.\r\n if (!redrawable) {\r\n this.remove(winner, 1);\r\n }\r\n // Return the winning participant.\r\n return winner;\r\n };\r\n /**\r\n * Draws multiple winning tickets and return an array of the participants that hold the winning tickets.\r\n * @param tickets The number of winning tickets to draw.\r\n * @param options The draw multiple options.\r\n * @returns An array of the participants that hold the winning tickets.\r\n */\r\n Lotto.prototype.drawMultiple = function (tickets, options) {\r\n if (options === void 0) { options = {}; }\r\n var uniqueResults = (0, Utilities_1.isNullOrUndefined)(options.unique) ? false : options.unique;\r\n // Handle cases where the user has asked for zero tickets (no idea why they would do this be we should trust them).\r\n if (tickets === 0) {\r\n return [];\r\n }\r\n // Now that we know out tickets value is not zero we should check that it is a valid natural number.\r\n if (!(0, Utilities_1.isNaturalNumber)(tickets)) {\r\n throw new Error(\"tickets value must be a natural number\");\r\n }\r\n var result = [];\r\n // Keep drawing tickets until we either reach the number of required tickets or we simply run out of tickets to draw.\r\n // We can run out of tickets to draw if 'options.redrawable' is explicity 'false' or we just had no participants when 'drawMultiple' was called.\r\n while (result.length < tickets && this._participants.length > 0) {\r\n result.push(this.draw(options));\r\n }\r\n // If the 'unique' draw option is set then we need to remove duplicates from the result list.\r\n if (uniqueResults) {\r\n // Create an array to store our unique results.\r\n var unique = [];\r\n // Iterate over all of our participants (with potential duplicates) and populate our array of unique values.\r\n for (var _i = 0, result_1 = result; _i < result_1.length; _i++) {\r\n var participant = result_1[_i];\r\n if (unique.indexOf(participant) === -1) {\r\n unique.push(participant);\r\n }\r\n }\r\n result = unique;\r\n }\r\n return result;\r\n };\r\n return Lotto;\r\n}());\r\nexports.Lotto = Lotto;\r\n", "\"use strict\";\r\nObject.defineProperty(exports, \"__esModule\", { value: true });\r\nexports.createLotto = void 0;\r\nvar Lotto_1 = require(\"./Lotto\");\r\n/**\r\n * A function that creates and returns a Lotto instance.\r\n * @param participantsOrOptions An array of initial participants or options relating to the creation of a Lotto instance.\r\n * @returns A new Lotto instance.\r\n */\r\nfunction createLotto(participantsOrOptions) {\r\n // If no initial participants or lotto options were provided as an argument then we can just return a new lotto instance now.\r\n if (!participantsOrOptions) {\r\n return new Lotto_1.Lotto();\r\n }\r\n // Check whether we were provided with an array of initial participants or a lotto options object.\r\n if (Array.isArray(participantsOrOptions)) {\r\n // We are dealing with a pre-defined array of participants.\r\n var participants = participantsOrOptions;\r\n var lotto_1 = new Lotto_1.Lotto();\r\n // If the lotto participants have been defined upfront then we will need to add them all to our lotto instance now.\r\n participants.forEach(function (_a) {\r\n var participant = _a[0], tokens = _a[1];\r\n return lotto_1.add(participant, tokens);\r\n });\r\n // Return the Lotto instance.\r\n return lotto_1;\r\n }\r\n else {\r\n // We are dealing with some lotto options.\r\n var random = participantsOrOptions.random, participants = participantsOrOptions.participants;\r\n // Create a Lotto instance passing the custom RNG function to use in place of Math.random() (which could be undefined).\r\n var lotto_2 = new Lotto_1.Lotto(random);\r\n // If the lotto participants have been defined upfront as part of the options then we will need to add them all to our lotto instance now.\r\n if (participants) {\r\n participants.forEach(function (_a) {\r\n var participant = _a[0], tokens = _a[1];\r\n return lotto_2.add(participant, tokens);\r\n });\r\n }\r\n // Return the Lotto instance.\r\n return lotto_2;\r\n }\r\n}\r\nexports.createLotto = createLotto;\r\n", "\"use strict\";\r\nObject.defineProperty(exports, \"__esModule\", { value: true });\r\nvar createLotto_1 = require(\"./createLotto\");\r\nexports.default = createLotto_1.createLotto;\r\n", "import State from \"./State\";\nimport { validateDefinition } from \"./BehaviourTreeDefinitionValidator\";\nimport { convertMDSLToJSON } from \"./mdsl/MDSLDefinitionParser\";\nimport { BehaviourTree, FlattenedTreeNode } from \"./BehaviourTree\";\nimport { BehaviourTreeOptions } from \"./BehaviourTreeOptions\";\n\nexport { BehaviourTree, State, convertMDSLToJSON, validateDefinition };\nexport type { FlattenedTreeNode, BehaviourTreeOptions };\n", "/**\n * Enumeration of node state types.\n */\nexport enum State {\n READY = \"mistreevous.ready\",\n RUNNING = \"mistreevous.running\",\n SUCCEEDED = \"mistreevous.succeeded\",\n FAILED = \"mistreevous.failed\"\n}\n\nexport { State as default };\n\nexport type CompleteState = State.SUCCEEDED | State.FAILED;\nexport type AnyState = State.READY | State.RUNNING | CompleteState;\n", "import {\n NodeDefinition,\n RootNodeDefinition,\n DecoratorNodeDefinition,\n CompositeNodeDefinition,\n AnyNodeDefinition,\n BranchNodeDefinition\n} from \"./BehaviourTreeDefinition\";\n\n/**\n * A type guard function that returns true if the specified node satisfies the RootNodeDefinition type.\n * @param node The node.\n * @returns A value of true if the specified node satisfies the RootNodeDefinition type.\n */\nexport function isRootNode(node: NodeDefinition): node is RootNodeDefinition {\n return node.type === \"root\";\n}\n\n/**\n * A type guard function that returns true if the specified node satisfies the BranchNodeDefinition type.\n * @param node The node.\n * @returns A value of true if the specified node satisfies the BranchNodeDefinition type.\n */\nexport function isBranchNode(node: NodeDefinition): node is BranchNodeDefinition {\n return node.type === \"branch\";\n}\n\n/**\n * A type guard function that returns true if the specified node satisfies the NodeDefinition type.\n * @param node The node.\n * @returns A value of true if the specified node satisfies the NodeDefinition type.\n */\nexport function isLeafNode(node: NodeDefinition): node is NodeDefinition {\n return [\"branch\", \"action\", \"condition\", \"wait\"].includes(node.type);\n}\n\n/**\n * A type guard function that returns true if the specified node satisfies the DecoratorNodeDefinition type.\n * @param node The node.\n * @returns A value of true if the specified node satisfies the DecoratorNodeDefinition type.\n */\nexport function isDecoratorNode(node: NodeDefinition): node is DecoratorNodeDefinition {\n return [\"root\", \"repeat\", \"retry\", \"flip\", \"succeed\", \"fail\"].includes(node.type);\n}\n\n/**\n * A type guard function that returns true if the specified node satisfies the CompositeNodeDefinition type.\n * @param node The node.\n * @returns A value of true if the specified node satisfies the CompositeNodeDefinition type.\n */\nexport function isCompositeNode(node: NodeDefinition): node is CompositeNodeDefinition {\n return [\"sequence\", \"selector\", \"lotto\", \"parallel\"].includes(node.type);\n}\n\n/**\n * Flatten a node definition into an array of all of its nested node definitions.\n * @param nodeDefinition The node definition to flatten.\n * @returns An array of all of nested node definitions.\n */\nexport function flattenDefinition(nodeDefinition: AnyNodeDefinition): AnyNodeDefinition[] {\n const nodes: AnyNodeDefinition[] = [];\n\n const processNode = (currentNodeDefinition: AnyNodeDefinition) => {\n nodes.push(currentNodeDefinition);\n\n if (isCompositeNode(currentNodeDefinition)) {\n currentNodeDefinition.children.forEach(processNode);\n } else if (isDecoratorNode(currentNodeDefinition)) {\n processNode(currentNodeDefinition.child);\n }\n };\n\n processNode(nodeDefinition);\n\n return nodes;\n}\n\n/**\n * Determines whether the passed value is an integer.\n * @param value The value to check.\n * @returns Whether the passed value is an integer.\n */\nexport function isInteger(value: unknown): boolean {\n return typeof value === \"number\" && Math.floor(value) === value;\n}\n\n/**\n * Determines whether the passed value is null or undefined.\n * @param value The value to check.\n * @returns Whether the passed value is null or undefined.\n */\nexport function isNullOrUndefined(value: unknown): boolean {\n return typeof value === \"undefined\" || value === null;\n}\n", "/**\n * A type defining an object that holds a reference to substitued string literals parsed from the definition.\n */\nexport type StringLiteralPlaceholders = { [key: string]: string };\n\n/**\n * Pop the next raw token from the specified array of tokens and throw an error if it wasn't the expected one.\n * @param tokens The array of tokens.\n * @param expected An optional string or array or items, one of which must match the next popped token.\n * @returns The popped token.\n */\nexport function popAndCheck(tokens: string[], expected?: string | string[]): string {\n // Get and remove the next token.\n const popped = tokens.shift();\n\n // We were expecting another token but there aren't any.\n if (popped === undefined) {\n throw new Error(\"unexpected end of definition\");\n }\n\n // Do we have an expected token/tokens array?\n if (expected != undefined) {\n // Get an array of expected values, if the popped token matches any then we are all good.\n const expectedValues = typeof expected === \"string\" ? [expected] : expected;\n\n // Check whether the popped token matches at least one of our expected items.\n var tokenMatchesExpectation = expectedValues.some((item) => popped.toUpperCase() === item.toUpperCase());\n\n // Throw an error if the popped token didn't match any of our expected items.\n if (!tokenMatchesExpectation) {\n const expectationString = expectedValues.map((item) => \"'\" + item + \"'\").join(\" or \");\n throw new Error(\"unexpected token found. Expected \" + expectationString + \" but got '\" + popped + \"'\");\n }\n }\n\n // Return the popped token.\n return popped;\n}\n\n/**\n * Swaps out any node/attribute argument string literals with placeholders.\n * @param definition The definition.\n * @returns An object containing a mapping of placeholders to original string values as well as the processed definition string.\n */\nexport function substituteStringLiterals(definition: string): {\n placeholders: StringLiteralPlaceholders;\n processedDefinition: string;\n} {\n // Create an object to hold the mapping of placeholders to original string values.\n const placeholders: StringLiteralPlaceholders = {};\n\n // Replace any string literals wrapped with double quotes in our definition with placeholders to be processed later.\n const processedDefinition = definition.replace(/\\\"(\\\\.|[^\"\\\\])*\\\"/g, (match) => {\n var strippedMatch = match.substring(1, match.length - 1);\n var placeholder = Object.keys(placeholders).find((key) => placeholders[key] === strippedMatch);\n\n // If we have no existing string literal match then create a new placeholder.\n if (!placeholder) {\n placeholder = `@@${Object.keys(placeholders).length}@@`;\n placeholders[placeholder] = strippedMatch;\n }\n\n return placeholder;\n });\n\n return { placeholders, processedDefinition };\n}\n\n/**\n * Parse the tree definition into an array of raw tokens.\n * @param definition The definition.\n * @returns An array of tokens parsed from the definition.\n */\nexport function parseTokensFromDefinition(definition: string): string[] {\n // Add some space around various important characters so that they can be plucked out easier as individual tokens.\n definition = definition.replace(/\\(/g, \" ( \");\n definition = definition.replace(/\\)/g, \" ) \");\n definition = definition.replace(/\\{/g, \" { \");\n definition = definition.replace(/\\}/g, \" } \");\n definition = definition.replace(/\\]/g, \" ] \");\n definition = definition.replace(/\\[/g, \" [ \");\n definition = definition.replace(/\\,/g, \" , \");\n\n // Split the definition into raw token form and return it.\n return definition.replace(/\\s+/g, \" \").trim().split(\" \");\n}\n", "import { StringLiteralPlaceholders, popAndCheck } from \"./MDSLUtilities\";\n\n/**\n * A type representing any node function argument.\n */\ntype Argument = {\n /**\n * The argument value.\n */\n value: T;\n /**\n * The argument type, used for validation.\n */\n type: string;\n};\n\ntype NullArgument = Argument & {\n type: \"null\";\n};\n\ntype BooleanArgument = Argument & {\n type: \"boolean\";\n};\n\ntype NumberArgument = Argument & {\n type: \"number\";\n /**\n * A flag defining whether the number argument value is a valid integer. (used for validation)\n */\n isInteger: boolean;\n};\n\ntype StringPlaceholderArgument = Argument & {\n type: \"string\";\n};\n\ntype IdentifierArgument = Argument & {\n type: \"identifier\";\n};\n\n/**\n * A type representing a reference to any node function argument.\n */\ntype AnyArgument = NullArgument | BooleanArgument | NumberArgument | StringPlaceholderArgument | IdentifierArgument;\n\n/**\n * Parse an array of argument definitions from the specified tokens array.\n * @param tokens The array tokens to parse the argument definitions from.\n * @param stringArgumentPlaceholders The mapping of string literal node argument placeholders to original values.\n * @param argumentValidator The argument validator function.\n * @param validationFailedMessage The exception message to throw if argument validation fails.\n * @returns An array of argument definitions parsed from the specified tokens array.\n */\nexport function parseArgumentTokens(\n tokens: string[],\n stringArgumentPlaceholders: StringLiteralPlaceholders\n): AnyArgument[] {\n const argumentList: AnyArgument[] = [];\n\n // If the next token is not a '[' or '(' then we have no arguments to parse.\n if (![\"[\", \"(\"].includes(tokens[0])) {\n return argumentList;\n }\n\n // Any lists of arguments will always be wrapped in '[]' for node arguments or '()' for attribute arguments.\n // We are looking for a '[' or '(' opener that wraps the argument tokens and the relevant closer.\n const closingToken = popAndCheck(tokens, [\"[\", \"(\"]) === \"[\" ? \"]\" : \")\";\n\n const argumentListTokens: string[] = [];\n\n // Grab all tokens between the '[' and ']' or '(' and ')'.\n while (tokens.length && tokens[0] !== closingToken) {\n // The next token is part of our arguments list.\n argumentListTokens.push(tokens.shift()!);\n }\n\n // Validate the order of the argument tokens. Each token must either be a ',' or a single argument that satisfies the validator.\n argumentListTokens.forEach((token, index) => {\n // Get whether this token should be an actual argument.\n const shouldBeArgumentToken = !(index & 1);\n\n // If the current token should be an actual argument then validate it, otherwise it should be a ',' token.\n if (shouldBeArgumentToken) {\n // Get the argument definition.\n const argumentDefinition = getArgumentDefinition(token, stringArgumentPlaceholders);\n\n // This is a valid argument!\n argumentList.push(argumentDefinition);\n } else {\n // The current token should be a ',' token.\n if (token !== \",\") {\n throw new Error(`invalid argument list, expected ',' or ']' but got '${token}'`);\n }\n }\n });\n\n // The arguments list should terminate with a ']' or ')' token, depending on the opener.\n popAndCheck(tokens, closingToken);\n\n // Return the arguments.\n return argumentList;\n}\n\n/**\n * Gets an argument value definition.\n * @param token The argument token.\n * @param stringArgumentPlaceholders The mapping of string literal node argument placeholders to original values.\n * @returns An argument value definition.\n */\nfunction getArgumentDefinition(token: string, stringArgumentPlaceholders: StringLiteralPlaceholders): AnyArgument {\n // Check whether the token represents a null value.\n if (token === \"null\") {\n return {\n value: null,\n type: \"null\"\n } as NullArgument;\n }\n\n // Check whether the token represents a boolean value.\n if (token === \"true\" || token === \"false\") {\n return {\n value: token === \"true\",\n type: \"boolean\"\n } as BooleanArgument;\n }\n\n // Check whether the token represents a number value.\n // TODO: Relies on broken isNaN - see MDN.\n // if (!Number.isNaN(token)) {\n if (!isNaN(token as any)) {\n return {\n value: parseFloat(token),\n isInteger: parseFloat(token) === parseInt(token, 10),\n type: \"number\"\n } as NumberArgument;\n }\n\n // Check whether the token is a placeholder (e.g. @@0@@) representing a string literal.\n if (token.match(/^@@\\d+@@$/g)) {\n return {\n value: stringArgumentPlaceholders[token].replace('\\\\\"', '\"'),\n type: \"string\"\n } as StringPlaceholderArgument;\n }\n\n // The only remaining option is that the argument value is an identifier.\n return {\n value: token,\n type: \"identifier\"\n } as IdentifierArgument;\n}\n", "import { NodeAttributeDefinition } from \"../BehaviourTreeDefinition\";\nimport { parseArgumentTokens } from \"./MDSLNodeArgumentParser\";\nimport { StringLiteralPlaceholders } from \"./MDSLUtilities\";\n\n/**\n * A type defining the attribute definitions of a node.\n */\ntype NodeAttributes = {\n while?: NodeAttributeDefinition;\n until?: NodeAttributeDefinition;\n entry?: NodeAttributeDefinition;\n exit?: NodeAttributeDefinition;\n step?: NodeAttributeDefinition;\n};\n\n/**\n * Parse any node attribute definitions from the specified tokens array.\n * @param tokens The array of remaining tokens.\n * @param stringArgumentPlaceholders The mapping of string literal node argument placeholders to original values.\n * @returns An object of attribute definitions defined by any directly following tokens.\n */\nexport function parseAttributeTokens(\n tokens: string[],\n stringArgumentPlaceholders: StringLiteralPlaceholders\n): NodeAttributes {\n const nodeAttributeNames: (keyof NodeAttributes)[] = [\"while\", \"until\", \"entry\", \"exit\", \"step\"];\n\n // Create an object to hold any attributes found.\n const attributes: NodeAttributes = {};\n\n // Try to get the name of the attribute for the next token.\n let nextAttributeName = tokens[0]?.toLowerCase() as keyof NodeAttributes;\n\n // Pull attribute tokens as well as their arguments off of the tokens stack until we have no more.\n while (nodeAttributeNames.includes(nextAttributeName)) {\n // Check to make sure that we have not already created an attribute definition of this type.\n if (attributes[nextAttributeName]) {\n throw new Error(`duplicate attribute '${tokens[0].toUpperCase()}' found for node`);\n }\n\n // Remove the attribute name token from the array of tokens.\n tokens.shift();\n\n // Grab the attribute arguments, assuming the first to be an identifier.\n const [attributeCallIdentifier, ...attributeArguments] = parseArgumentTokens(\n tokens,\n stringArgumentPlaceholders\n );\n\n // The first attribute argument has to be an identifer, this will reference an agent function.\n if (attributeCallIdentifier?.type !== \"identifier\") {\n throw new Error(\"expected agent function or registered function name identifier argument for attribute\");\n }\n\n // Any attribute arguments (other than the expected call identifier) must have a type of string, number, boolean or null.\n attributeArguments\n .filter((arg) => arg.type === \"identifier\")\n .forEach((arg) => {\n throw new Error(\n `invalid attribute argument value '${arg.value}', must be string, number, boolean or null`\n );\n });\n\n // Create the attribute definition and add it to the object of attribute definitions found.\n attributes[nextAttributeName] = {\n call: attributeCallIdentifier.value,\n args: attributeArguments.map(({ value }) => value)\n };\n\n // Try to get the next attribute name token, as there could be multiple.\n nextAttributeName = tokens[0]?.toLowerCase() as keyof NodeAttributes;\n }\n\n return attributes;\n}\n", "import {\n ActionNodeDefinition,\n AnyChildNodeDefinition,\n AnyNodeDefinition,\n BranchNodeDefinition,\n ConditionNodeDefinition,\n FailNodeDefinition,\n FlipNodeDefinition,\n LottoNodeDefinition,\n ParallelNodeDefinition,\n RepeatNodeDefinition,\n RetryNodeDefinition,\n RootNodeDefinition,\n SelectorNodeDefinition,\n SequenceNodeDefinition,\n SucceedNodeDefinition,\n WaitNodeDefinition\n} from \"../BehaviourTreeDefinition\";\nimport {\n isCompositeNode,\n isDecoratorNode,\n isLeafNode,\n isNullOrUndefined,\n isRootNode\n} from \"../BehaviourTreeDefinitionUtilities\";\nimport { parseArgumentTokens } from \"./MDSLNodeArgumentParser\";\nimport { parseAttributeTokens } from \"./MDSLNodeAttributeParser\";\nimport {\n StringLiteralPlaceholders,\n parseTokensFromDefinition,\n popAndCheck,\n substituteStringLiterals\n} from \"./MDSLUtilities\";\n\n/**\n * Convert the MDSL tree definition string into an equivalent JSON definition.\n * @param definition The tree definition string as MDSL.\n * @returns The root node JSON definitions.\n */\nexport function convertMDSLToJSON(definition: string): RootNodeDefinition[] {\n // Swap out any node/attribute argument string literals with a placeholder and get a mapping of placeholders to original values as well as the processed definition.\n const { placeholders, processedDefinition } = substituteStringLiterals(definition);\n\n // Parse our definition definition string into an array of raw tokens.\n const tokens = parseTokensFromDefinition(processedDefinition);\n\n return convertTokensToJSONDefinition(tokens, placeholders);\n}\n\n/**\n * Converts the specified tree definition tokens into a JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The root node JSON definitions.\n */\nfunction convertTokensToJSONDefinition(\n tokens: string[],\n stringLiteralPlaceholders: StringLiteralPlaceholders\n): RootNodeDefinition[] {\n // There must be at least 3 tokens for the tree definition to be valid. 'ROOT', '{' and '}'.\n if (tokens.length < 3) {\n throw new Error(\"invalid token count\");\n }\n\n // We should have a matching number of '{' and '}' tokens. If not, then there are scopes that have not been properly closed.\n if (tokens.filter((token) => token === \"{\").length !== tokens.filter((token) => token === \"}\").length) {\n throw new Error(\"scope character mismatch\");\n }\n\n // Create an array of tree stack arrays where root nodes will always be at the botton and the current composite/decorator node at the top.\n // There should be an element in this array for every root node defined and every element should be an array with a root note as the first element.\n // E.g. A definition with two root nodes defined:\n // [\n // [root, lotto, sequence],\n // [root, selector]\n // ]\n const treeStacks: [Partial, ...Partial[]][] = [];\n\n // Create an array of all root node definitions that we create.\n const rootNodes: Partial[] = [];\n\n // A helper function used to push node definitions onto the tree stack.\n const pushNode = (node: AnyNodeDefinition) => {\n // If the node is a root node then we need to create a new tree stack array with the root node at the root.\n if (isRootNode(node)) {\n // We need to double-check that this root node is not the child of another node.\n // We can do this by checking whether the top tree stack is not empty (contains an existing node)\n if (treeStacks[treeStacks.length - 1]?.length) {\n throw new Error(\"a root node cannot be the child of another node\");\n }\n\n // Add the root node definition to our array of all parsed root node definitions.\n rootNodes.push(node);\n\n // Add the root node definition to the root of a new tree stack.\n treeStacks.push([node]);\n\n return;\n }\n\n // All non-root nodes should be pushed after their root nodes so handle cases\n // where we may not have any tree stacks or our top-most tree stack is empty.\n if (!treeStacks.length || !treeStacks[treeStacks.length - 1].length) {\n throw new Error(\"expected root node at base of definition\");\n }\n\n // Get the current tree stack that we are populating.\n const topTreeStack = treeStacks[treeStacks.length - 1];\n\n // Get the top-most node in the current tree stack, this will be a composite/decorator node\n // for which we will populate its children array if composite or setting its child if a decorator.\n const topTreeStackTopNode = topTreeStack[topTreeStack.length - 1] as AnyNodeDefinition;\n\n // If the top-most node in the current root stack is a composite or decorator\n // node then the current node should be added as a child of the top-most node.\n if (isCompositeNode(topTreeStackTopNode)) {\n topTreeStackTopNode.children = topTreeStackTopNode.children || [];\n topTreeStackTopNode.children.push(node);\n } else if (isDecoratorNode(topTreeStackTopNode)) {\n // If the top node already has a child node set then throw an error as a decorator should only have a single child.\n if (topTreeStackTopNode.child) {\n throw new Error(\"a decorator node must only have a single child node\");\n }\n\n topTreeStackTopNode.child = node;\n }\n\n // If the node we are adding is also a composite or decorator node, then we should push it\n // onto the current tree stack, as subsequent nodes will be added as its child/children.\n if (!isLeafNode(node)) {\n topTreeStack.push(node);\n }\n };\n\n // A helper function used to pop the top-most node definition off of the tree stack and return it.\n const popNode = (): AnyNodeDefinition | null => {\n let poppedNode: AnyNodeDefinition | null = null;\n\n // Get the current tree stack that we are populating.\n const topTreeStack = treeStacks[treeStacks.length - 1];\n\n // Pop the top-most node in the current tree stack if there is one.\n if (topTreeStack.length) {\n poppedNode = topTreeStack.pop() as AnyNodeDefinition;\n }\n\n // We don't want any empty tree stacks in our stack of tree stacks.\n if (!topTreeStack.length) {\n treeStacks.pop();\n }\n\n return poppedNode;\n };\n\n // We should keep processing the raw tokens until we run out of them.\n while (tokens.length) {\n // Grab the next token.\n const token = tokens.shift()!;\n\n // How we create the next node depends on the current raw token value.\n switch (token.toUpperCase()) {\n case \"ROOT\": {\n pushNode(createRootNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"SUCCEED\": {\n pushNode(createSucceedNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"FAIL\": {\n pushNode(createFailNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"FLIP\": {\n pushNode(createFlipNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"REPEAT\": {\n pushNode(createRepeatNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"RETRY\": {\n pushNode(createRetryNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"SEQUENCE\": {\n pushNode(createSequenceNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"SELECTOR\": {\n pushNode(createSelectorNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"PARALLEL\": {\n pushNode(createParallelNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"LOTTO\": {\n pushNode(createLottoNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"ACTION\": {\n pushNode(createActionNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"CONDITION\": {\n pushNode(createConditionNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"WAIT\": {\n pushNode(createWaitNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"BRANCH\": {\n pushNode(createBranchNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"}\": {\n // The '}' character closes the current scope and means that we have to pop a node off of the current stack.\n const poppedNode = popNode();\n\n // Now that we have a node definition we can carry out any validation that may require the node to be fully populated.\n if (poppedNode) {\n validatePoppedNode(poppedNode);\n }\n\n break;\n }\n\n default: {\n throw new Error(`unexpected token: ${token}`);\n }\n }\n }\n\n return rootNodes as RootNodeDefinition[];\n}\n\n/**\n * Creates a root node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The root node JSON definition.\n */\nfunction createRootNode(tokens: string[], stringLiteralPlaceholders: StringLiteralPlaceholders): RootNodeDefinition {\n // Create the root node definition.\n let node = {\n type: \"root\"\n } as Partial;\n\n // Parse any node arguments, we should only have one if any which will be an identifier argument for the root identifier.\n const nodeArguments = parseArgumentTokens(tokens, stringLiteralPlaceholders);\n\n // Check whether any node arguments were defined.\n if (nodeArguments.length) {\n // We should only have one argument, if any, which will be an identifier argument for the root identifier.\n if (nodeArguments.length === 1 && nodeArguments[0].type === \"identifier\") {\n // The root node identifier will be the first and only node argument value.\n node.id = nodeArguments[0].value as string;\n } else {\n throw new Error(\"expected single root name argument\");\n }\n }\n\n // Grab any node attribute definitions and spread them into the node definition.\n node = { ...node, ...parseAttributeTokens(tokens, stringLiteralPlaceholders) };\n\n // This is a decorator node, so we expect an opening '{'.\n popAndCheck(tokens, \"{\");\n\n // Return the root node definition.\n return node as RootNodeDefinition;\n}\n\n/**\n * Creates a succeed node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The succeed node JSON definition.\n */\nfunction createSucceedNode(\n tokens: string[],\n stringLiteralPlaceholders: StringLiteralPlaceholders\n): SucceedNodeDefinition {\n const node = {\n type: \"succeed\",\n ...parseAttributeTokens(tokens, stringLiteralPlaceholders)\n } as SucceedNodeDefinition;\n\n // This is a decorator node, so we expect an opening '{'.\n popAndCheck(tokens, \"{\");\n\n // Return the succeed node definition.\n return node;\n}\n\n/**\n * Creates a fail node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The fail node JSON definition.\n */\nfunction createFailNode(tokens: string[], stringLiteralPlaceholders: StringLiteralPlaceholders): FailNodeDefinition {\n const node = {\n type: \"fail\",\n ...parseAttributeTokens(tokens, stringLiteralPlaceholders)\n } as FailNodeDefinition;\n\n // This is a decorator node, so we expect an opening '{'.\n popAndCheck(tokens, \"{\");\n\n // Return the fail node definition.\n return node;\n}\n\n/**\n * Creates a flip node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The flip node JSON definition.\n */\nfunction createFlipNode(tokens: string[], stringLiteralPlaceholders: StringLiteralPlaceholders): FlipNodeDefinition {\n const node = {\n type: \"flip\",\n ...parseAttributeTokens(tokens, stringLiteralPlaceholders)\n } as FlipNodeDefinition;\n\n // This is a decorator node, so we expect an opening '{'.\n popAndCheck(tokens, \"{\");\n\n // Return the flip node definition.\n return node;\n}\n\n/**\n * Creates a repeat node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The repeat node JSON definition.\n */\nfunction createRepeatNode(\n tokens: string[],\n stringLiteralPlaceholders: StringLiteralPlaceholders\n): RepeatNodeDefinition {\n let node = { type: \"repeat\" } as RepeatNodeDefinition;\n\n // Get the node arguments.\n const nodeArguments = parseArgumentTokens(tokens, stringLiteralPlaceholders);\n\n // The arguments of a repeat node are optional. We may have:\n // - No node arguments, in which case the repeat note will iterate indefinitely.\n // - One node argument which will be the explicit number of iterations to make.\n // - Two node arguments which define the min and max iteration bounds from which a random iteration count will be picked.\n if (nodeArguments.length) {\n // All repeat node arguments MUST be of type number and must be integer.\n nodeArguments\n .filter((arg) => arg.type !== \"number\" || !arg.isInteger)\n .forEach(() => {\n throw new Error(`repeat node iteration counts must be integer values`);\n });\n\n // We should have got one or two iteration counts.\n if (nodeArguments.length === 1) {\n // A static iteration count was defined.\n node.iterations = nodeArguments[0].value as number;\n\n // A repeat node must have a positive number of iterations if defined.\n if (node.iterations < 0) {\n throw new Error(\"a repeat node must have a positive number of iterations if defined\");\n }\n } else if (nodeArguments.length === 2) {\n // A minimum and maximum iteration count was defined.\n node.iterations = [nodeArguments[0].value as number, nodeArguments[1].value as number];\n\n // A repeat node must have a positive min and max iteration count if they are defined.\n if (node.iterations[0] < 0 || node.iterations[1] < 0) {\n throw new Error(\"a repeat node must have a positive minimum and maximum iteration count if defined\");\n }\n\n // A repeat node must not have an minimum iteration count that exceeds the maximum iteration count.\n if (node.iterations[0] > node.iterations[1]) {\n throw new Error(\n \"a repeat node must not have a minimum iteration count that exceeds the maximum iteration count\"\n );\n }\n } else {\n // An incorrect number of iteration counts was defined.\n throw new Error(\"invalid number of repeat node iteration count arguments defined\");\n }\n }\n\n // Grab any node attribute definitions and spread them into the node definition.\n node = { ...node, ...parseAttributeTokens(tokens, stringLiteralPlaceholders) };\n\n // This is a decorator node, so we expect an opening '{'.\n popAndCheck(tokens, \"{\");\n\n // Return the repeat node definition.\n return node;\n}\n\n/**\n * Creates a retry node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The retry node JSON definition.\n */\nfunction createRetryNode(tokens: string[], stringLiteralPlaceholders: StringLiteralPlaceholders): RetryNodeDefinition {\n let node = { type: \"retry\" } as RetryNodeDefinition;\n\n // Get the node arguments.\n const nodeArguments = parseArgumentTokens(tokens, stringLiteralPlaceholders);\n\n // The arguments of a retry node are optional. We may have:\n // - No node arguments, in which case the retry note will attempt indefinitely.\n // - One node argument which will be the explicit number of attempts to make.\n // - Two node arguments which define the min and max attempt bounds from which a random attempt count will be picked.\n if (nodeArguments.length) {\n // All retry node arguments MUST be of type number and must be integer.\n nodeArguments\n .filter((arg) => arg.type !== \"number\" || !arg.isInteger)\n .forEach(() => {\n throw new Error(`retry node attempt counts must be integer values`);\n });\n\n // We should have got one or two attempt counts.\n if (nodeArguments.length === 1) {\n // A static attempt count was defined.\n node.attempts = nodeArguments[0].value as number;\n\n // A retry node must have a positive number of attempts if defined.\n if (node.attempts < 0) {\n throw new Error(\"a retry node must have a positive number of attempts if defined\");\n }\n } else if (nodeArguments.length === 2) {\n // A minimum and maximum attempt count was defined.\n node.attempts = [nodeArguments[0].value as number, nodeArguments[1].value as number];\n\n // A retry node must have a positive min and max attempts count if they are defined.\n if (node.attempts[0] < 0 || node.attempts[1] < 0) {\n throw new Error(\"a retry node must have a positive minimum and maximum attempt count if defined\");\n }\n\n // A retry node must not have a minimum attempt count that exceeds the maximum attempt count.\n if (node.attempts[0] > node.attempts[1]) {\n throw new Error(\n \"a retry node must not have a minimum attempt count that exceeds the maximum attempt count\"\n );\n }\n } else {\n // An incorrect number of attempt counts was defined.\n throw new Error(\"invalid number of retry node attempt count arguments defined\");\n }\n }\n\n // Grab any node attribute definitions and spread them into the node definition.\n node = { ...node, ...parseAttributeTokens(tokens, stringLiteralPlaceholders) };\n\n // This is a decorator node, so we expect an opening '{'.\n popAndCheck(tokens, \"{\");\n\n // Return the retry node definition.\n return node;\n}\n\n/**\n * Creates a sequence node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The sequence node JSON definition.\n */\nfunction createSequenceNode(\n tokens: string[],\n stringLiteralPlaceholders: StringLiteralPlaceholders\n): SequenceNodeDefinition {\n const node = {\n type: \"sequence\",\n ...parseAttributeTokens(tokens, stringLiteralPlaceholders)\n } as SequenceNodeDefinition;\n\n // This is a composite node, so we expect an opening '{'.\n popAndCheck(tokens, \"{\");\n\n // Return the sequence node definition.\n return node;\n}\n\n/**\n * Creates a selector node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The selector node JSON definition.\n */\nfunction createSelectorNode(\n tokens: string[],\n stringLiteralPlaceholders: StringLiteralPlaceholders\n): SelectorNodeDefinition {\n const node = {\n type: \"selector\",\n ...parseAttributeTokens(tokens, stringLiteralPlaceholders)\n } as SelectorNodeDefinition;\n\n // This is a composite node, so we expect an opening '{'.\n popAndCheck(tokens, \"{\");\n\n // Return the selector node definition.\n return node;\n}\n\n/**\n * Creates a parallel node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The parallel node JSON definition.\n */\nfunction createParallelNode(\n tokens: string[],\n stringLiteralPlaceholders: StringLiteralPlaceholders\n): ParallelNodeDefinition {\n const node = {\n type: \"parallel\",\n ...parseAttributeTokens(tokens, stringLiteralPlaceholders)\n } as ParallelNodeDefinition;\n\n // This is a composite node, so we expect an opening '{'.\n popAndCheck(tokens, \"{\");\n\n // Return the parallel node definition.\n return node;\n}\n\n/**\n * Creates a lotto node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The lotto node JSON definition.\n */\nfunction createLottoNode(tokens: string[], stringLiteralPlaceholders: StringLiteralPlaceholders): LottoNodeDefinition {\n // If any node arguments have been defined then they must be our weights.\n const nodeArguments = parseArgumentTokens(tokens, stringLiteralPlaceholders);\n\n // All lotto node arguments MUST be of type number and must be positive integers.\n nodeArguments\n .filter((arg) => arg.type !== \"number\" || !arg.isInteger || arg.value < 0)\n .forEach(() => {\n throw new Error(`lotto node weight arguments must be positive integer values`);\n });\n\n const node = {\n type: \"lotto\",\n ...parseAttributeTokens(tokens, stringLiteralPlaceholders)\n } as LottoNodeDefinition;\n\n // Apply the weights if any were defined.\n if (nodeArguments.length) {\n node.weights = nodeArguments.map(({ value }) => value) as number[];\n }\n\n // This is a composite node, so we expect an opening '{'.\n popAndCheck(tokens, \"{\");\n\n // Return the lotto node definition.\n return node;\n}\n\n/**\n * Creates an action node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The action node JSON definition.\n */\nfunction createActionNode(\n tokens: string[],\n stringLiteralPlaceholders: StringLiteralPlaceholders\n): ActionNodeDefinition {\n // Parse any node arguments, we should have at least one which will be an identifier argument for the action name\n // and agent function to invoke for the action, all other arguments are to be passed as arguments to that function.\n const [actionNameIdentifier, ...agentFunctionArgs] = parseArgumentTokens(tokens, stringLiteralPlaceholders);\n\n // Our first argument MUST be defined and be an identifier as we require an action name argument.\n if (actionNameIdentifier?.type !== \"identifier\") {\n throw new Error(\"expected action name identifier argument\");\n }\n\n // Only the first argument should have been an identifier, all agent function arguments must be string, number, boolean or null.\n agentFunctionArgs\n .filter((arg) => arg.type === \"identifier\")\n .forEach((arg) => {\n throw new Error(\n `invalid action node argument value '${arg.value}', must be string, number, boolean or null`\n );\n });\n\n // Return the action node definition.\n return {\n type: \"action\",\n call: actionNameIdentifier.value,\n args: agentFunctionArgs.map(({ value }) => value),\n ...parseAttributeTokens(tokens, stringLiteralPlaceholders)\n };\n}\n\n/**\n * Creates a condition node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The condition node JSON definition.\n */\nfunction createConditionNode(\n tokens: string[],\n stringLiteralPlaceholders: StringLiteralPlaceholders\n): ConditionNodeDefinition {\n // Parse any node arguments, we should have at least one which will be an identifier argument for the condition name\n // and agent function to invoke for the condition, all other arguments are to be passed as arguments to that function.\n const [conditionNameIdentifier, ...agentFunctionArgs] = parseArgumentTokens(tokens, stringLiteralPlaceholders);\n\n // Our first argument MUST be defined and be an identifier as we require a condition name argument.\n if (conditionNameIdentifier?.type !== \"identifier\") {\n throw new Error(\"expected condition name identifier argument\");\n }\n\n // Only the first argument should have been an identifier, all agent function arguments must be string, number, boolean or null.\n agentFunctionArgs\n .filter((arg) => arg.type === \"identifier\")\n .forEach((arg) => {\n throw new Error(\n `invalid condition node argument value '${arg.value}', must be string, number, boolean or null`\n );\n });\n\n // Return the condition node definition.\n return {\n type: \"condition\",\n call: conditionNameIdentifier.value,\n args: agentFunctionArgs.map(({ value }) => value),\n ...parseAttributeTokens(tokens, stringLiteralPlaceholders)\n };\n}\n\n/**\n * Creates a wait node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The wait node JSON definition.\n */\nfunction createWaitNode(tokens: string[], stringLiteralPlaceholders: StringLiteralPlaceholders): WaitNodeDefinition {\n let node = { type: \"wait\" } as WaitNodeDefinition;\n\n // Get the node arguments.\n const nodeArguments = parseArgumentTokens(tokens, stringLiteralPlaceholders);\n\n // The arguments of a wait node are optional. We may have:\n // - No node arguments, in which case the wait will be indefinite until it is aborted.\n // - One node argument which will be the explicit duration of the wait.\n // - Two node arguments which define the min and max duration bounds from which a random duration will be picked.\n if (nodeArguments.length) {\n // All wait node arguments MUST be of type number and must be integer.\n nodeArguments\n .filter((arg) => arg.type !== \"number\" || !arg.isInteger)\n .forEach(() => {\n throw new Error(`wait node durations must be integer values`);\n });\n\n // We may have:\n // - One node argument which will be the explicit duration of the wait.\n // - Two node arguments which define the min and max duration bounds from which a random duration will be picked.\n // - Too many arguments, which is not valid.\n if (nodeArguments.length === 1) {\n // An explicit duration was defined.\n node.duration = nodeArguments[0].value as number;\n\n // If an explict duration was defined then it must be a positive number.\n if (node.duration < 0) {\n throw new Error(\"a wait node must have a positive duration\");\n }\n } else if (nodeArguments.length === 2) {\n // Min and max duration bounds were defined from which a random duration will be picked.\n node.duration = [nodeArguments[0].value as number, nodeArguments[1].value as number];\n\n // A wait node must have a positive min and max duration.\n if (node.duration[0] < 0 || node.duration[1] < 0) {\n throw new Error(\"a wait node must have a positive minimum and maximum duration\");\n }\n\n // A wait node must not have a minimum duration that exceeds the maximum duration.\n if (node.duration[0] > node.duration[1]) {\n throw new Error(\"a wait node must not have a minimum duration that exceeds the maximum duration\");\n }\n } else if (nodeArguments.length > 2) {\n // An incorrect number of duration arguments were defined.\n throw new Error(\"invalid number of wait node duration arguments defined\");\n }\n }\n\n // Return the wait node definition.\n return { ...node, ...parseAttributeTokens(tokens, stringLiteralPlaceholders) };\n}\n\n/**\n * Creates a branch node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The branch node JSON definition.\n */\nfunction createBranchNode(\n tokens: string[],\n stringLiteralPlaceholders: StringLiteralPlaceholders\n): BranchNodeDefinition {\n // Parse any node arguments, we should have one which will be an identifier argument for the root ref.\n const nodeArguments = parseArgumentTokens(tokens, stringLiteralPlaceholders);\n\n // We should have only a single identifer argument for a branch node, which is the root ref.\n if (nodeArguments.length !== 1 || nodeArguments[0].type !== \"identifier\") {\n throw new Error(\"expected single branch name argument\");\n }\n\n // Return the branch node definition.\n return { type: \"branch\", ref: nodeArguments[0].value };\n}\n\n/**\n * Validate a fully-populated node definition that was popped off of the tree stack.\n * @param definition The popped node to validate.\n */\nfunction validatePoppedNode(definition: AnyNodeDefinition): void {\n // Decorators MUST have a child defined.\n if (isDecoratorNode(definition) && isNullOrUndefined(definition.child)) {\n throw new Error(`a ${definition.type} node must have a single child node defined`);\n }\n\n // Composites MUST have at least one child defined.\n if (isCompositeNode(definition) && !definition.children?.length) {\n throw new Error(`a ${definition.type} node must have at least a single child node defined`);\n }\n\n // We need to make sure that lotto nodes that have weights defined have a number of weights matching the number of child nodes.\n if (definition.type === \"lotto\") {\n // Check whether a 'weights' property has been defined, if it has we expect it to be an array of weights.\n if (typeof definition.weights !== \"undefined\") {\n // Check that the weights property is an array of positive integers with an element for each child node element.\n if (definition.weights.length !== definition.children.length) {\n throw new Error(\n \"expected a number of weight arguments matching the number of child nodes for lotto node\"\n );\n }\n }\n }\n}\n", "import { RootNodeDefinition } from \"./BehaviourTreeDefinition\";\nimport { flattenDefinition, isBranchNode, isInteger } from \"./BehaviourTreeDefinitionUtilities\";\nimport { convertMDSLToJSON } from \"./mdsl/MDSLDefinitionParser\";\n\n/**\n * An object representing the result of validating a tree definition.\n */\nexport type DefinitionValidationResult = {\n /**\n * A flag defining whether validation succeeded.\n */\n succeeded: boolean;\n /**\n * A string containing the error message if validation did not succeed.\n */\n errorMessage?: string;\n /**\n * The definition as json if the validation was successful, or undefined if validation did not succeed.\n */\n json?: RootNodeDefinition[];\n};\n\n/**\n * Validates the specified behaviour tree definition in the form of JSON or MDSL, not taking any globally registered subtrees into consideration.\n * @param definition The behaviour tree definition in the form of JSON or MDSL.\n * @returns An object representing the result of validating the given tree definition.\n */\nexport function validateDefinition(definition: any): DefinitionValidationResult {\n // The definition must be defined.\n if (definition === null || typeof definition === \"undefined\") {\n return createValidationFailureResult(\"definition is null or undefined\");\n }\n\n // We are expecting a definition in one of three different forms:\n // - A string which we will assume is MDSL and we will parse this to JSON before validation.\n // - An array which we will assume is an array of root node definitions with at least one being the primary root node (no 'id' property)\n // - An object which we will assume is the primary root node and should not have an 'id' property.\n if (typeof definition === \"string\") {\n // The definition is a string which we can assume is MDSL, so attempt to validate it.\n return validateMDSLDefinition(definition);\n } else if (typeof definition === \"object\") {\n // The definition will either be an array (of root node definitions) or an object (the single primary root node definition).\n return validateJSONDefinition(definition);\n } else {\n return createValidationFailureResult(`unexpected definition type of '${typeof definition}'`);\n }\n}\n\n/**\n * Validates the specified behaviour tree definition in the form of MDSL.\n * @param definition The behaviour tree definition in the form of MDSL.\n * @returns An object representing the result of validating the given tree definition.\n */\nfunction validateMDSLDefinition(definition: string): DefinitionValidationResult {\n let rootNodeDefinitions;\n\n // The first thing the we need to do is to attempt to convert our MDSL into JSON.\n try {\n // The definition is a string which we can assume is MDSL, so attempt to parse it to a JSON definition in the form of an array of root node definitions.\n rootNodeDefinitions = convertMDSLToJSON(definition);\n } catch (exception) {\n // We failed to parse the JSON from the MDSL, this is likely to be the result of it not being a valid MDSL string.\n return createValidationFailureResult((exception as Error).message);\n }\n\n // Unpack all of the root node definitions into arrays of main ('id' defined) and sub ('id' not defined) root node definitions.\n const mainRootNodeDefinitions = rootNodeDefinitions.filter(({ id }) => typeof id === \"undefined\");\n const subRootNodeDefinitions = rootNodeDefinitions.filter(({ id }) => typeof id === \"string\" && id.length > 0);\n\n // We should ALWAYS have exactly one root node definition without an 'id' property defined, which is out main root node definition.\n if (mainRootNodeDefinitions.length !== 1) {\n return createValidationFailureResult(\n \"expected single unnamed root node at base of definition to act as main root\"\n );\n }\n\n // We should never have duplicate 'id' properties across our sub root node definitions.\n const subRootNodeIdenitifers: string[] = [];\n for (const { id } of subRootNodeDefinitions) {\n // Have we already come across this 'id' property value?\n if (subRootNodeIdenitifers.includes(id!)) {\n return createValidationFailureResult(`multiple root nodes found with duplicate name '${id}'`);\n }\n\n subRootNodeIdenitifers.push(id!);\n }\n\n try {\n // Validate our branch -> subtree links and check for any circular dependencies, we don't care about checking for broken subtree links here.\n validateBranchSubtreeLinks(rootNodeDefinitions, false);\n } catch (exception) {\n return createValidationFailureResult((exception as Error).message);\n }\n\n // Our definition was valid!\n return {\n succeeded: true,\n json: rootNodeDefinitions\n };\n}\n\n/**\n * Validates the specified behaviour tree definition in the form of JSON.\n * @param definition The behaviour tree definition in the form of JSON.\n * @returns An object representing the result of validating the given tree definition.\n */\nexport function validateJSONDefinition(\n definition: RootNodeDefinition | RootNodeDefinition[]\n): DefinitionValidationResult {\n // The definition will either be an array (of root node definitions) or an object (the single primary root node definition).\n const rootNodeDefinitions = Array.isArray(definition) ? definition : [definition];\n\n // Iterate over our array of root nodes and call validateNode for each, passing an initial depth of 0, wrapped in a try catch to handle validation failures.\n try {\n rootNodeDefinitions.forEach((rootNodeDefinition) => validateNode(rootNodeDefinition, 0));\n } catch (error) {\n // Handle cases where we have caught a thrown Error and return a failure result with the error message.\n if (error instanceof Error) {\n return createValidationFailureResult(error.message);\n }\n\n // No idea what happened here!\n return createValidationFailureResult(`unexpected error: ${error}`);\n }\n\n // Unpack all of the root node definitions into arrays of main ('id' defined) and sub ('id' not defined) root node definitions.\n const mainRootNodeDefinitions = rootNodeDefinitions.filter(({ id }) => typeof id === \"undefined\");\n const subRootNodeDefinitions = rootNodeDefinitions.filter(({ id }) => typeof id === \"string\" && id.length > 0);\n\n // We should ALWAYS have exactly one root node definition without an 'id' property defined, which is out main root node definition.\n if (mainRootNodeDefinitions.length !== 1) {\n return createValidationFailureResult(\n \"expected single root node without 'id' property defined to act as main root\"\n );\n }\n\n // We should never have duplicate 'id' properties across our sub root node definitions.\n const subRootNodeIdenitifers: string[] = [];\n for (const { id } of subRootNodeDefinitions) {\n // Have we already come across this 'id' property value?\n if (subRootNodeIdenitifers.includes(id!)) {\n return createValidationFailureResult(\n `multiple root nodes found with duplicate 'id' property value of '${id}'`\n );\n }\n\n subRootNodeIdenitifers.push(id!);\n }\n\n try {\n // Validate our branch -> subtree links and check for any circular dependencies, we don't care about checking for broken subtree links here.\n validateBranchSubtreeLinks(rootNodeDefinitions, false);\n } catch (exception) {\n return createValidationFailureResult((exception as Error).message);\n }\n\n // Our definition was valid!\n return {\n succeeded: true,\n json: rootNodeDefinitions\n };\n}\n\n/**\n * Validates the branch -> subtree links across all provided root node definitions.\n * This will not consider branch nodes that reference any globally registered subtrees unless includesGlobalSubtrees\n * is set to true, in which case we will also verify that there are no broken branch -> subtree links.\n * @param rootNodeDefinitions The array of root node definitions.\n * @param includesGlobalSubtrees A flag defining whether the array includes all global subtree root node definitions.\n */\nexport function validateBranchSubtreeLinks(rootNodeDefinitions: RootNodeDefinition[], includesGlobalSubtrees: boolean) {\n // Create a mapping of root node identifiers to other root nodes that they reference via branch nodes.\n // Below is an example of a mapping that includes a circular dependency (root => a => b => c => a)\n // [{ refs: [\"a\", \"b\"] }, { id: \"a\", refs: [\"b\"] }, { id: \"b\", refs: [\"c\"] }, { id: \"c\", refs: [\"a\"] }]\n const rootNodeMappings: { id: string | undefined; refs: string[] }[] = rootNodeDefinitions.map(\n (rootNodeDefinition) => ({\n id: rootNodeDefinition.id,\n refs: flattenDefinition(rootNodeDefinition)\n .filter(isBranchNode)\n .map(({ ref }) => ref)\n })\n );\n\n // A recursive function to walk through the mappings, keeping track of which root nodes we have visited in the form of a path of root node identifiers.\n const followRefs = (mapping: { id: string | undefined; refs: string[] }, path: (string | undefined)[] = []) => {\n // Have we found a circular dependency?\n if (path.includes(mapping.id)) {\n // We found a circular dependency! Get the bad path of root node identifiers.\n const badPath = [...path, mapping.id];\n\n // Create the formatted path value. [undefined, \"a\", \"b\", \"c\", \"a\"] would be formatted as \"a -> b -> c -> a\".\n const badPathFormatted = badPath.filter((element) => !!element).join(\" => \");\n\n // No need to continue, we found a circular dependency.\n throw new Error(`circular dependency found in branch node references: ${badPathFormatted}`);\n }\n\n for (const ref of mapping.refs) {\n // Find the mapping for the root node with an identifer matching the current ref.\n const subMapping = rootNodeMappings.find(({ id }) => id === ref);\n\n // We may not have a mapping for this ref, which is normal when we aren't considering all globally registered subtrees.\n if (subMapping) {\n followRefs(subMapping, [...path, mapping.id]);\n } else if (includesGlobalSubtrees) {\n // We found a reference to a root node that doesn't exist, which is a problem seeing as the root node definitons includes all globally registered subtrees.\n throw new Error(\n mapping.id\n ? `subtree '${mapping.id}' has branch node that references root node '${ref}' which has not been defined`\n : `primary tree has branch node that references root node '${ref}' which has not been defined`\n );\n }\n }\n };\n\n // Start looking for circular dependencies and broken references from the primary root node definition.\n followRefs(rootNodeMappings.find((mapping) => typeof mapping.id === \"undefined\")!);\n}\n\n/**\n * Validate an object that we expect to be a node definition.\n * @param definition An object that we expect to be a node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateNode(definition: any, depth: number): void {\n // Every node must be valid object and have a non-empty 'type' string property.\n if (typeof definition !== \"object\" || typeof definition.type !== \"string\" || definition.type.length === 0) {\n throw new Error(\n `node definition is not an object or 'type' property is not a non-empty string at depth '${depth}'`\n );\n }\n\n // How we validate this node definition will depend on its type.\n switch (definition.type) {\n case \"action\":\n validateActionNode(definition, depth);\n break;\n\n case \"condition\":\n validateConditionNode(definition, depth);\n break;\n\n case \"wait\":\n validateWaitNode(definition, depth);\n break;\n\n case \"branch\":\n validateBranchNode(definition, depth);\n break;\n\n case \"root\":\n validateRootNode(definition, depth);\n break;\n\n case \"succeed\":\n validateSucceedNode(definition, depth);\n break;\n\n case \"fail\":\n validateFailNode(definition, depth);\n break;\n\n case \"flip\":\n validateFlipNode(definition, depth);\n break;\n\n case \"repeat\":\n validateRepeatNode(definition, depth);\n break;\n\n case \"retry\":\n validateRetryNode(definition, depth);\n break;\n\n case \"sequence\":\n validateSequenceNode(definition, depth);\n break;\n\n case \"selector\":\n validateSelectorNode(definition, depth);\n break;\n\n case \"parallel\":\n validateParallelNode(definition, depth);\n break;\n\n case \"lotto\":\n validateLottoNode(definition, depth);\n break;\n\n default:\n throw new Error(`unexpected node type of '${definition.type}' at depth '${depth}'`);\n }\n}\n\n/**\n * Validate any attributes for a given node definition.\n * @param definition The node definition.\n * @param depth The depth of the node in the behaviour tree definition.\n */\nfunction validateNodeAttributes(definition: any, depth: number): void {\n // Validate each of the attribute types for this node.\n [\"while\", \"until\", \"entry\", \"exit\", \"step\"].forEach((attributeName) => {\n // Attempt to grab the definition for the current attribute from the node definition.\n const attributeDefinition = definition[attributeName];\n\n // All node attributes are optional, so there is nothing to do if the current attribute is not defined.\n if (typeof attributeDefinition === \"undefined\") {\n return;\n }\n\n // The attribute definition must be an object.\n if (typeof attributeDefinition !== \"object\") {\n throw new Error(\n `expected attribute '${attributeName}' to be an object for '${definition.type}' node at depth '${depth}'`\n );\n }\n\n // The 'call' property must be defined for any attribute definition.\n if (typeof attributeDefinition.call !== \"string\" || attributeDefinition.call.length === 0) {\n throw new Error(\n `expected 'call' property for attribute '${attributeName}' to be a non-empty string for '${definition.type}' node at depth '${depth}'`\n );\n }\n\n // If any node attribute arguments have been defined then they must have been defined in an array.\n if (typeof attributeDefinition.args !== \"undefined\" && !Array.isArray(attributeDefinition.args)) {\n throw new Error(\n `expected 'args' property for attribute '${attributeName}' to be an array for '${definition.type}' node at depth '${depth}'`\n );\n }\n });\n}\n\n/**\n * Validate an object that we expect to be a root node definition.\n * @param definition An object that we expect to be a root node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateRootNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"root\") {\n throw new Error(\"expected node type of 'root' for root node\");\n }\n\n // A root node cannot be the child of another node.\n if (depth > 0) {\n throw new Error(\"a root node cannot be the child of another node\");\n }\n\n // Check that, if the root node 'id' property is defined, it is a non-empty string.\n if (typeof definition.id !== \"undefined\" && (typeof definition.id !== \"string\" || definition.id.length === 0)) {\n throw new Error(\"expected non-empty string for 'id' property if defined for root node\");\n }\n\n // A root node is a decorator node, so must have a child node defined.\n if (typeof definition.child === \"undefined\") {\n throw new Error(\"expected property 'child' to be defined for root node\");\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n\n // Validate the child node of this decorator node.\n validateNode(definition.child, depth + 1);\n}\n\n/**\n * Validate an object that we expect to be a succeed node definition.\n * @param definition An object that we expect to be a succeed node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateSucceedNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"succeed\") {\n throw new Error(`expected node type of 'succeed' for succeed node at depth '${depth}'`);\n }\n\n // A succeed node is a decorator node, so must have a child node defined.\n if (typeof definition.child === \"undefined\") {\n throw new Error(`expected property 'child' to be defined for succeed node at depth '${depth}'`);\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n\n // Validate the child node of this decorator node.\n validateNode(definition.child, depth + 1);\n}\n\n/**\n * Validate an object that we expect to be a fail node definition.\n * @param definition An object that we expect to be a fail node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateFailNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"fail\") {\n throw new Error(`expected node type of 'fail' for fail node at depth '${depth}'`);\n }\n\n // A fail node is a decorator node, so must have a child node defined.\n if (typeof definition.child === \"undefined\") {\n throw new Error(`expected property 'child' to be defined for fail node at depth '${depth}'`);\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n\n // Validate the child node of this decorator node.\n validateNode(definition.child, depth + 1);\n}\n\n/**\n * Validate an object that we expect to be a flip node definition.\n * @param definition An object that we expect to be a flip node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateFlipNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"flip\") {\n throw new Error(`expected node type of 'flip' for flip node at depth '${depth}'`);\n }\n\n // A flip node is a decorator node, so must have a child node defined.\n if (typeof definition.child === \"undefined\") {\n throw new Error(`expected property 'child' to be defined for flip node at depth '${depth}'`);\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n\n // Validate the child node of this decorator node.\n validateNode(definition.child, depth + 1);\n}\n\n/**\n * Validate an object that we expect to be a repeat node definition.\n * @param definition An object that we expect to be a repeat node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateRepeatNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"repeat\") {\n throw new Error(`expected node type of 'repeat' for repeat node at depth '${depth}'`);\n }\n\n // A repeat node is a decorator node, so must have a child node defined.\n if (typeof definition.child === \"undefined\") {\n throw new Error(`expected property 'child' to be defined for repeat node at depth '${depth}'`);\n }\n\n // Check whether an 'iterations' property has been defined, it may not have been if this node is to repeat indefinitely.\n if (typeof definition.iterations !== \"undefined\") {\n if (Array.isArray(definition.iterations)) {\n // Check whether any elements of the array are not integer values.\n const containsNonInteger = !!definition.iterations.filter((value: unknown) => !isInteger(value)).length;\n\n // If the 'iterations' property is an array then it MUST contain two integer values.\n if (definition.iterations.length !== 2 || containsNonInteger) {\n throw new Error(\n `expected array containing two integer values for 'iterations' property if defined for repeat node at depth '${depth}'`\n );\n }\n\n // A repeat node must have a positive min and max iterations count if they are defined.\n if (definition.iterations[0] < 0 || definition.iterations[1] < 0) {\n throw new Error(\n `expected positive minimum and maximum iterations count for 'iterations' property if defined for repeat node at depth '${depth}'`\n );\n }\n\n // A repeat node must not have a minimum iterations count that exceeds the maximum iterations count.\n if (definition.iterations[0] > definition.iterations[1]) {\n throw new Error(\n `expected minimum iterations count that does not exceed the maximum iterations count for 'iterations' property if defined for repeat node at depth '${depth}'`\n );\n }\n } else if (isInteger(definition.iterations)) {\n // A repeat node must have a positive number of iterations if defined.\n if (definition.iterations < 0) {\n throw new Error(\n `expected positive iterations count for 'iterations' property if defined for repeat node at depth '${depth}'`\n );\n }\n } else {\n throw new Error(\n `expected integer value or array containing two integer values for 'iterations' property if defined for repeat node at depth '${depth}'`\n );\n }\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n\n // Validate the child node of this decorator node.\n validateNode(definition.child, depth + 1);\n}\n\n/**\n * Validate an object that we expect to be a retry node definition.\n * @param definition An object that we expect to be a retry node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateRetryNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"retry\") {\n throw new Error(`expected node type of 'retry' for retry node at depth '${depth}'`);\n }\n\n // A retry node is a decorator node, so must have a child node defined.\n if (typeof definition.child === \"undefined\") {\n throw new Error(`expected property 'child' to be defined for retry node at depth '${depth}'`);\n }\n\n // Check whether an 'attempts' property has been defined, it may not have been if this node is to retry indefinitely.\n if (typeof definition.attempts !== \"undefined\") {\n if (Array.isArray(definition.attempts)) {\n // Check whether any elements of the array are not integer values.\n const containsNonInteger = !!definition.attempts.filter((value: unknown) => !isInteger(value)).length;\n\n // If the 'attempts' property is an array then it MUST contain two integer values.\n if (definition.attempts.length !== 2 || containsNonInteger) {\n throw new Error(\n `expected array containing two integer values for 'attempts' property if defined for retry node at depth '${depth}'`\n );\n }\n\n // A retry node must have a positive min and max attempts count if they are defined.\n if (definition.attempts[0] < 0 || definition.attempts[1] < 0) {\n throw new Error(\n `expected positive minimum and maximum attempts count for 'attempts' property if defined for retry node at depth '${depth}'`\n );\n }\n\n // A retry node must not have a minimum attempts count that exceeds the maximum attempts count.\n if (definition.attempts[0] > definition.attempts[1]) {\n throw new Error(\n `expected minimum attempts count that does not exceed the maximum attempts count for 'attempts' property if defined for retry node at depth '${depth}'`\n );\n }\n } else if (isInteger(definition.attempts)) {\n // A retry node must have a positive number of attempts if defined.\n if (definition.attempts < 0) {\n throw new Error(\n `expected positive attempts count for 'attempts' property if defined for retry node at depth '${depth}'`\n );\n }\n } else {\n throw new Error(\n `expected integer value or array containing two integer values for 'attempts' property if defined for retry node at depth '${depth}'`\n );\n }\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n\n // Validate the child node of this decorator node.\n validateNode(definition.child, depth + 1);\n}\n\n/**\n * Validate an object that we expect to be a branch node definition.\n * @param definition An object that we expect to be a branch node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateBranchNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"branch\") {\n throw new Error(`expected node type of 'branch' for branch node at depth '${depth}'`);\n }\n\n // Check that the branch node 'ref' property is defined and is a non-empty string.\n if (typeof definition.ref !== \"string\" || definition.ref.length === 0) {\n throw new Error(`expected non-empty string for 'ref' property for branch node at depth '${depth}'`);\n }\n\n // It is invalid to define guard attributes for a branch node as they should be defined on the referenced root node.\n [\"while\", \"until\"].forEach((attributeName) => {\n if (typeof definition[attributeName] !== \"undefined\") {\n throw new Error(\n `guards should not be defined for branch nodes but guard '${attributeName}' was defined for branch node at depth '${depth}'`\n );\n }\n });\n\n // It is invalid to define callback attributes for a branch node as they should be defined on the referenced root node.\n [\"entry\", \"exit\", \"step\"].forEach((attributeName) => {\n if (typeof definition[attributeName] !== \"undefined\") {\n throw new Error(\n `callbacks should not be defined for branch nodes but callback '${attributeName}' was defined for branch node at depth '${depth}'`\n );\n }\n });\n}\n\n/**\n * Validate an object that we expect to be a action node definition.\n * @param definition An object that we expect to be a action node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateActionNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"action\") {\n throw new Error(`expected node type of 'action' for action node at depth '${depth}'`);\n }\n\n // The 'call' property must be defined for a action node definition.\n if (typeof definition.call !== \"string\" || definition.call.length === 0) {\n throw new Error(`expected non-empty string for 'call' property of action node at depth '${depth}'`);\n }\n\n // If any action function arguments have been defined then they must have been defined in an array.\n if (typeof definition.args !== \"undefined\" && !Array.isArray(definition.args)) {\n throw new Error(`expected array for 'args' property if defined for action node at depth '${depth}'`);\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n}\n\n/**\n * Validate an object that we expect to be a condition node definition.\n * @param definition An object that we expect to be a condition node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateConditionNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"condition\") {\n throw new Error(`expected node type of 'condition' for condition node at depth '${depth}'`);\n }\n\n // The 'call' property must be defined for a condition node definition.\n if (typeof definition.call !== \"string\" || definition.call.length === 0) {\n throw new Error(`expected non-empty string for 'call' property of condition node at depth '${depth}'`);\n }\n\n // If any condition function arguments have been defined then they must have been defined in an array.\n if (typeof definition.args !== \"undefined\" && !Array.isArray(definition.args)) {\n throw new Error(`expected array for 'args' property if defined for condition node at depth '${depth}'`);\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n}\n\n/**\n * Validate an object that we expect to be a wait node definition.\n * @param definition An object that we expect to be a wait node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateWaitNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"wait\") {\n throw new Error(`expected node type of 'wait' for wait node at depth '${depth}'`);\n }\n\n // Check whether a 'duration' property has been defined, it may not have been if this node is to wait indefinitely.\n if (typeof definition.duration !== \"undefined\") {\n if (Array.isArray(definition.duration)) {\n // Check whether any elements of the array are not integer values.\n const containsNonInteger = !!definition.duration.filter((value: unknown) => !isInteger(value)).length;\n\n // If the 'duration' property is an array then it MUST contain two integer values.\n if (definition.duration.length !== 2 || containsNonInteger) {\n throw new Error(\n `expected array containing two integer values for 'duration' property if defined for wait node at depth '${depth}'`\n );\n }\n\n // A wait node must have a positive min and max duration value if they are defined.\n if (definition.duration[0] < 0 || definition.duration[1] < 0) {\n throw new Error(\n `expected positive minimum and maximum duration for 'duration' property if defined for wait node at depth '${depth}'`\n );\n }\n\n // A wait node must not have a minimum duration value that exceeds the maximum duration value.\n if (definition.duration[0] > definition.duration[1]) {\n throw new Error(\n `expected minimum duration value that does not exceed the maximum duration value for 'duration' property if defined for wait node at depth '${depth}'`\n );\n }\n } else if (isInteger(definition.duration)) {\n // A wait node must have a positive duration value if defined.\n if (definition.duration < 0) {\n throw new Error(\n `expected positive duration value for 'duration' property if defined for wait node at depth '${depth}'`\n );\n }\n } else {\n throw new Error(\n `expected integer value or array containing two integer values for 'duration' property if defined for wait node at depth '${depth}'`\n );\n }\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n}\n\n/**\n * Validate an object that we expect to be a sequence node definition.\n * @param definition An object that we expect to be a sequence node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateSequenceNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"sequence\") {\n throw new Error(`expected node type of 'sequence' for sequence node at depth '${depth}'`);\n }\n\n // A sequence node is a composite node, so must have a children nodes array defined.\n if (!Array.isArray(definition.children) || definition.children.length === 0) {\n throw new Error(`expected non-empty 'children' array to be defined for sequence node at depth '${depth}'`);\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n\n // Validate the child nodes of this composite node.\n definition.children.forEach((child: any) => validateNode(child, depth + 1));\n}\n\n/**\n * Validate an object that we expect to be a selector node definition.\n * @param definition An object that we expect to be a selector node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateSelectorNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"selector\") {\n throw new Error(`expected node type of 'selector' for selector node at depth '${depth}'`);\n }\n\n // A selector node is a composite node, so must have a children nodes array defined.\n if (!Array.isArray(definition.children) || definition.children.length === 0) {\n throw new Error(`expected non-empty 'children' array to be defined for selector node at depth '${depth}'`);\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n\n // Validate the child nodes of this composite node.\n definition.children.forEach((child: any) => validateNode(child, depth + 1));\n}\n\n/**\n * Validate an object that we expect to be a parallel node definition.\n * @param definition An object that we expect to be a parallel node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateParallelNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"parallel\") {\n throw new Error(`expected node type of 'parallel' for parallel node at depth '${depth}'`);\n }\n\n // A parallel node is a composite node, so must have a children nodes array defined.\n if (!Array.isArray(definition.children) || definition.children.length === 0) {\n throw new Error(`expected non-empty 'children' array to be defined for parallel node at depth '${depth}'`);\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n\n // Validate the child nodes of this composite node.\n definition.children.forEach((child: any) => validateNode(child, depth + 1));\n}\n\n/**\n * Validate an object that we expect to be a lotto node definition.\n * @param definition An object that we expect to be a lotto node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateLottoNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"lotto\") {\n throw new Error(`expected node type of 'lotto' for lotto node at depth '${depth}'`);\n }\n\n // A lotto node is a composite node, so must have a children nodes array defined.\n if (!Array.isArray(definition.children) || definition.children.length === 0) {\n throw new Error(`expected non-empty 'children' array to be defined for lotto node at depth '${depth}'`);\n }\n\n // Check whether a 'weights' property has been defined, if it has we expect it to be an array of weights.\n if (typeof definition.weights !== \"undefined\") {\n // Check that the weights property is an array of positive integers with an element for each child node element.\n if (\n !Array.isArray(definition.weights) ||\n definition.weights.length !== definition.children.length ||\n definition.weights.filter((value: unknown) => !isInteger(value)).length ||\n definition.weights.filter((value: number) => value < 0).length\n ) {\n throw new Error(\n `expected an array of positive integer weight values with a length matching the number of child nodes for 'weights' property if defined for lotto node at depth '${depth}'`\n );\n }\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n\n // Validate the child nodes of this composite node.\n definition.children.forEach((child: any) => validateNode(child, depth + 1));\n}\n\n/**\n * A helper function to create a failure validation result with the given error message.\n * @param errorMessage The validation failure error message.\n * @returns A failure validation result with the given error message.\n */\nfunction createValidationFailureResult(errorMessage: string): DefinitionValidationResult {\n return { succeeded: false, errorMessage };\n}\n", "import { ActionResult, Agent, GlobalFunction } from \"./Agent\";\nimport { RootNodeDefinition } from \"./BehaviourTreeDefinition\";\n\nexport type InvokerFunction = (args: any[]) => ActionResult | boolean;\n\n/**\n * A singleton used to store and lookup registered functions and subtrees.\n */\nexport default class Lookup {\n /**\n * The object holding any registered functions keyed on function name.\n */\n private static registeredFunctions: { [key: string]: GlobalFunction } = {};\n /**\n * The object holding any registered subtree root node definitions keyed on tree name.\n */\n private static registeredSubtrees: { [key: string]: RootNodeDefinition } = {};\n\n /**\n * Gets the function with the specified name.\n * @param name The name of the function.\n * @returns The function with the specified name.\n */\n public static getFunc(name: string): GlobalFunction {\n return this.registeredFunctions[name];\n }\n\n /**\n * Sets the function with the specified name for later lookup.\n * @param name The name of the function.\n * @param func The function.\n */\n public static setFunc(name: string, func: GlobalFunction): void {\n this.registeredFunctions[name] = func;\n }\n\n /**\n * Gets the function invoker for the specified agent and function name.\n * If a function with the specified name exists on the agent object then it will\n * be returned, otherwise we will then check the registered functions for a match.\n * @param agent The agent instance that this behaviour tree is modelling behaviour for.\n * @param name The function name.\n * @returns The function invoker for the specified agent and function name.\n */\n static getFuncInvoker(agent: Agent, name: string): InvokerFunction | null {\n // Check whether the agent contains the specified function.\n const agentFunction = agent[name];\n if (agentFunction && typeof agentFunction === \"function\") {\n return (args: any[]) => agentFunction.apply(agent, args);\n }\n\n // The agent does not contain the specified function but it may have been registered at some point.\n if (this.registeredFunctions[name] && typeof this.registeredFunctions[name] === \"function\") {\n const registeredFunction = this.registeredFunctions[name];\n return (args: any[]) => registeredFunction(agent, ...args.map((arg) => arg.value));\n }\n\n // We have no function to invoke.\n return null;\n }\n\n /**\n * Gets all registered subtree root node definitions.\n */\n static getSubtrees(): { [key: string]: RootNodeDefinition } {\n return this.registeredSubtrees;\n }\n\n /**\n * Sets the subtree with the specified name for later lookup.\n * @param name The name of the subtree.\n * @param subtree The subtree.\n */\n static setSubtree(name: string, subtree: RootNodeDefinition) {\n this.registeredSubtrees[name] = subtree;\n }\n\n /**\n * Removes the registered function or subtree with the specified name.\n * @param name The name of the registered function or subtree.\n */\n static remove(name: string) {\n delete this.registeredFunctions[name];\n delete this.registeredSubtrees[name];\n }\n\n /**\n * Remove all registered functions and subtrees.\n */\n static empty() {\n this.registeredFunctions = {};\n this.registeredSubtrees = {};\n }\n}\n", "import Node from \"../../nodes/Node\";\n\n/**\n * An exception thrown when evaluating node guard path conditions and a conditions fails.\n */\nexport default class GuardUnsatisifedException extends Error {\n /**\n * @param source The node at which a guard condition failed.\n */\n constructor(private source: Node) {\n super(\"A guard path condition has failed\");\n }\n\n /**\n * Gets whether the specified node is the node at which a guard condition failed.\n * @param node The node to check against the source node.\n * @returns Whether the specified node is the node at which a guard condition failed.\n */\n isSourceNode = (node: Node) => node === this.source;\n}\n", "import { Agent } from \"../../Agent\";\nimport Guard from \"./Guard\";\nimport Node from \"../../nodes/Node\";\nimport GuardUnsatisifedException from \"./GuardUnsatisifedException\";\n\nexport type GuardPathPart = {\n node: Node;\n guards: Guard[];\n};\n\n/**\n * Represents a path of node guards along a root-to-leaf tree path.\n */\nexport default class GuardPath {\n /**\n * @param nodes An array of objects defining a node instance -> guard link, ordered by node depth.\n */\n constructor(private nodes: GuardPathPart[]) {}\n\n /**\n * Evaluate guard conditions for all guards in the tree path, moving outwards from the root.\n * @param agent The agent, required for guard evaluation.\n * @returns An evaluation results object.\n */\n evaluate = (agent: Agent) => {\n // We need to evaluate guard conditions for nodes up the tree, moving outwards from the root.\n for (const details of this.nodes) {\n // There can be multiple guards per node.\n for (const guard of details.guards) {\n // Check whether the guard condition passes, and throw an exception if not.\n if (!guard.isSatisfied(agent)) {\n throw new GuardUnsatisifedException(details.node);\n }\n }\n }\n };\n}\n", "import { BehaviourTreeOptions } from \"../BehaviourTreeOptions\";\nimport State, { AnyState } from \"../State\";\nimport { Agent } from \"../Agent\";\nimport Leaf from \"./leaf/Leaf\";\nimport Attribute from \"../attributes/Attribute\";\nimport Entry from \"../attributes/callbacks/Entry\";\nimport Exit from \"../attributes/callbacks/Exit\";\nimport Step from \"../attributes/callbacks/Step\";\nimport Guard from \"../attributes/guards/Guard\";\nimport GuardPath from \"../attributes/guards/GuardPath\";\nimport GuardUnsatisifedException from \"../attributes/guards/GuardUnsatisifedException\";\n\n/**\n * A base node.\n */\nexport default abstract class Node {\n /**\n * The node uid.\n */\n private readonly uid: string = createNodeUid();\n /**\n * The node state.\n */\n private state: AnyState = State.READY;\n /**\n * The guard path to evaluate as part of a node update.\n */\n private guardPath: GuardPath | undefined;\n\n /**\n * @param type The node type.\n * @param attributes The node attributes.\n * @param args The node argument definitions.\n */\n constructor(private type: string, private attributes: Attribute[], private args: any[]) {}\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected abstract onUpdate(agent: Agent, options: BehaviourTreeOptions): void;\n\n /**\n * Gets the name of the node.\n */\n public abstract getName(): string;\n\n /**\n * Gets whether this node is a leaf node.\n */\n public abstract isLeafNode: () => this is Leaf;\n\n /**\n * Gets/Sets the state of the node.\n */\n getState = (): AnyState => this.state;\n setState = (value: AnyState): void => {\n this.state = value;\n };\n\n /**\n * Gets the unique id of the node.\n */\n getUid = () => this.uid;\n\n /**\n * Gets the type of the node.\n */\n getType = () => this.type;\n\n /**\n * Gets the node attributes.\n */\n getAttributes = () => this.attributes;\n\n /**\n * Gets the node arguments.\n */\n getArguments = () => this.args;\n\n /**\n * Gets the node attribute with the specified type, or null if it does not exist.\n */\n getAttribute(type: \"entry\" | \"ENTRY\"): Entry;\n getAttribute(type: \"exit\" | \"EXIT\"): Exit;\n getAttribute(type: \"step\" | \"STEP\"): Step;\n getAttribute(type: string): Attribute {\n return (\n this.getAttributes().filter((decorator) => decorator.type.toUpperCase() === type.toUpperCase())[0] || null\n );\n }\n\n /**\n * Gets the node attributes.\n */\n getGuardAttributes = (): Guard[] => this.getAttributes().filter((decorator) => decorator.isGuard()) as Guard[];\n\n /**\n * Sets the guard path to evaluate as part of a node update.\n */\n setGuardPath = (value: GuardPath) => (this.guardPath = value);\n\n /**\n * Gets whether a guard path is assigned to this node.\n */\n hasGuardPath = () => !!this.guardPath;\n\n /**\n * Gets whether this node is in the specified state.\n * @param value The value to compare to the node state.\n */\n public is(value: AnyState): boolean {\n return this.state === value;\n }\n\n /**\n * Reset the state of the node.\n */\n public reset(): void {\n this.setState(State.READY);\n }\n\n /**\n * Abort the running of this node.\n * @param agent The agent.\n */\n public abort(agent: Agent): void {\n // There is nothing to do if this node is not in the running state.\n if (!this.is(State.RUNNING)) {\n return;\n }\n\n // Reset the state of this node.\n this.reset();\n\n this.getAttribute(\"exit\")?.callAgentFunction(agent, false, true);\n }\n\n /**\n * Update the node.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n * @returns The result of the update.\n */\n public update(agent: Agent, options: BehaviourTreeOptions): void {\n // If this node is already in a 'SUCCEEDED' or 'FAILED' state then there is nothing to do.\n if (this.is(State.SUCCEEDED) || this.is(State.FAILED)) {\n return;\n }\n\n try {\n // Evaluate all of the guard path conditions for the current tree path.\n this.guardPath!.evaluate(agent);\n\n // If this node is in the READY state then call the ENTRY for this node if it exists.\n if (this.is(State.READY)) {\n this.getAttribute(\"entry\")?.callAgentFunction(agent);\n }\n\n this.getAttribute(\"step\")?.callAgentFunction(agent);\n\n // Do the actual update.\n this.onUpdate(agent, options);\n\n // If this node is now in a 'SUCCEEDED' or 'FAILED' state then call the EXIT for this node if it exists.\n if (this.is(State.SUCCEEDED) || this.is(State.FAILED)) {\n this.getAttribute(\"exit\")?.callAgentFunction(agent, this.is(State.SUCCEEDED), false);\n }\n } catch (error) {\n // If the error is a GuardUnsatisfiedException then we need to determine if this node is the source.\n if (error instanceof GuardUnsatisifedException && error.isSourceNode(this)) {\n // Abort the current node.\n this.abort(agent);\n\n // Any node that is the source of an abort will be a failed node.\n this.setState(State.FAILED);\n } else {\n throw error;\n }\n }\n }\n}\n\n/**\n * Create a randomly generated node uid.\n * @returns A randomly generated node uid.\n */\nfunction createNodeUid(): string {\n var S4 = function () {\n return (((1 + Math.random()) * 0x10000) | 0).toString(16).substring(1);\n };\n return S4() + S4() + \"-\" + S4() + \"-\" + S4() + \"-\" + S4() + \"-\" + S4() + S4() + S4();\n}\n", "import Node from \"../Node\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\n\n/**\n * A composite node that wraps child nodes.\n */\nexport default abstract class Composite extends Node {\n /**\n * @param type The node type.\n * @param attributes The node attributes.\n * @param children The child nodes.\n */\n constructor(type: string, attributes: Attribute[], protected children: Node[]) {\n super(type, attributes, []);\n }\n\n /**\n * Gets whether this node is a leaf node.\n */\n isLeafNode = () => false;\n\n /**\n * Gets the children of this node.\n */\n getChildren = () => this.children;\n\n /**\n * Reset the state of the node.\n */\n reset = () => {\n // Reset the state of this node.\n this.setState(State.READY);\n\n // Reset the state of any child nodes.\n this.getChildren().forEach((child) => child.reset());\n };\n\n /**\n * Abort the running of this node.\n * @param agent The agent.\n */\n abort = (agent: Agent) => {\n // There is nothing to do if this node is not in the running state.\n if (!this.is(State.RUNNING)) {\n return;\n }\n\n // Abort any child nodes.\n this.getChildren().forEach((child) => child.abort(agent));\n\n // Reset the state of this node.\n this.reset();\n\n this.getAttribute(\"exit\")?.callAgentFunction(agent, false, true);\n };\n}\n", "import Composite from \"./Composite\";\nimport State from \"../../State\";\nimport Node from \"../Node\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A PARALLEL node.\n * The child nodes are executed concurrently until one fails or all succeed.\n */\nexport default class Parallel extends Composite {\n /**\n * @param attributes The node attributes.\n * @param children The child nodes.\n */\n constructor(attributes: Attribute[], children: Node[]) {\n super(\"parallel\", attributes, children);\n }\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // Keep a count of the number of succeeded child nodes.\n let succeededCount = 0;\n\n let hasChildFailed = false;\n\n // Iterate over all of the children of this node.\n for (const child of this.children) {\n // If the child has never been updated or is running then we will need to update it now.\n if (child.getState() === State.READY || child.getState() === State.RUNNING) {\n // Update the child of this node.\n child.update(agent, options);\n }\n\n // If the current child has a state of 'SUCCEEDED' then we should move on to the next child.\n if (child.getState() === State.SUCCEEDED) {\n // The child node has succeeded, keep track of this to determine if all children have.\n succeededCount++;\n\n // The child node succeeded, but we have not finished checking every child node yet.\n continue;\n }\n\n // If the current child has a state of 'FAILED' then this node is also a 'FAILED' node.\n if (child.getState() === State.FAILED) {\n hasChildFailed = true;\n\n // There is no need to check the rest of the children.\n break;\n }\n\n // The node should be in the 'RUNNING' state.\n if (child.getState() !== State.RUNNING) {\n // The child node was not in an expected state.\n throw new Error(\"child node was not in an expected state.\");\n }\n }\n\n if (hasChildFailed) {\n // This node is a 'FAILED' node.\n this.setState(State.FAILED);\n\n // Abort every running child.\n for (const child of this.children) {\n if (child.getState() === State.RUNNING) {\n child.abort(agent);\n }\n }\n } else {\n // If all children have succeeded then this node has also succeeded, otherwise it is still running.\n this.setState(succeededCount === this.children.length ? State.SUCCEEDED : State.RUNNING);\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => \"PARALLEL\";\n}\n", "import Composite from \"./Composite\";\nimport Node from \"../Node\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A SELECTOR node.\n * The child nodes are executed in sequence until one succeeds or all fail.\n */\nexport default class Selector extends Composite {\n /**\n * @param attributes The node attributes.\n * @param children The child nodes.\n */\n constructor(attributes: Attribute[], protected children: Node[]) {\n super(\"selector\", attributes, children);\n }\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // Iterate over all of the children of this node.\n for (const child of this.children) {\n // If the child has never been updated or is running then we will need to update it now.\n if (child.getState() === State.READY || child.getState() === State.RUNNING) {\n // Update the child of this node.\n child.update(agent, options);\n }\n\n // If the current child has a state of 'SUCCEEDED' then this node is also a 'SUCCEEDED' node.\n if (child.getState() === State.SUCCEEDED) {\n // This node is a 'SUCCEEDED' node.\n this.setState(State.SUCCEEDED);\n\n // There is no need to check the rest of the selector nodes.\n return;\n }\n\n // If the current child has a state of 'FAILED' then we should move on to the next child.\n if (child.getState() === State.FAILED) {\n // Find out if the current child is the last one in the selector.\n // If it is then this sequence node has also failed.\n if (this.children.indexOf(child) === this.children.length - 1) {\n // This node is a 'FAILED' node.\n this.setState(State.FAILED);\n\n // There is no need to check the rest of the selector as we have completed it.\n return;\n } else {\n // The child node failed, try the next one.\n continue;\n }\n }\n\n // The node should be in the 'RUNNING' state.\n if (child.getState() === State.RUNNING) {\n // This node is a 'RUNNING' node.\n this.setState(State.RUNNING);\n\n // There is no need to check the rest of the selector as the current child is still running.\n return;\n }\n\n // The child node was not in an expected state.\n throw new Error(\"child node was not in an expected state.\");\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => \"SELECTOR\";\n}\n", "import Composite from \"./Composite\";\nimport Node from \"../Node\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A SEQUENCE node.\n * The child nodes are executed in sequence until one fails or all succeed.\n */\nexport default class Sequence extends Composite {\n /**\n * @param attributes The node attributes.\n * @param children The child nodes.\n */\n constructor(attributes: Attribute[], protected children: Node[]) {\n super(\"sequence\", attributes, children);\n }\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // Iterate over all of the children of this node.\n for (const child of this.children) {\n // If the child has never been updated or is running then we will need to update it now.\n if (child.getState() === State.READY || child.getState() === State.RUNNING) {\n // Update the child of this node.\n child.update(agent, options);\n }\n\n // If the current child has a state of 'SUCCEEDED' then we should move on to the next child.\n if (child.getState() === State.SUCCEEDED) {\n // Find out if the current child is the last one in the sequence.\n // If it is then this sequence node has also succeeded.\n if (this.children.indexOf(child) === this.children.length - 1) {\n // This node is a 'SUCCEEDED' node.\n this.setState(State.SUCCEEDED);\n\n // There is no need to check the rest of the sequence as we have completed it.\n return;\n } else {\n // The child node succeeded, but we have not finished the sequence yet.\n continue;\n }\n }\n\n // If the current child has a state of 'FAILED' then this node is also a 'FAILED' node.\n if (child.getState() === State.FAILED) {\n // This node is a 'FAILED' node.\n this.setState(State.FAILED);\n\n // There is no need to check the rest of the sequence.\n return;\n }\n\n // The node should be in the 'RUNNING' state.\n if (child.getState() === State.RUNNING) {\n // This node is a 'RUNNING' node.\n this.setState(State.RUNNING);\n\n // There is no need to check the rest of the sequence as the current child is still running.\n return;\n }\n\n // The child node was not in an expected state.\n throw new Error(\"child node was not in an expected state.\");\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => \"SEQUENCE\";\n}\n", "import createLotto from \"lotto-draw\";\n\nimport Node from \"../Node\";\nimport Composite from \"./Composite\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A LOTTO node.\n * A winning child is picked on the initial update of this node, based on ticket weighting.\n * The state of this node will match the state of the winning child.\n */\nexport default class Lotto extends Composite {\n /**\n * @param attributes The node attributes.\n * @param weights The child node weights.\n * @param children The child nodes.\n */\n constructor(attributes: Attribute[], private weights: number[] | undefined, children: Node[]) {\n super(\"lotto\", attributes, children);\n }\n\n /**\n * The child node selected to be the active one.\n */\n private selectedChild: Node | undefined;\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // If this node is in the READY state then we need to pick a winning child node.\n if (this.is(State.READY)) {\n // Create a lotto draw with which to randomly pick a child node to become the active one.\n const lottoDraw = createLotto({\n // Hook up the optional 'random' behaviour tree function option to the one used by 'lotto-draw'.\n random: options.random,\n // Pass in each child node as a participant in the lotto draw with their respective ticket count.\n participants: this.children.map((child, index) => [child, this.weights?.[index] || 1])\n });\n\n // Randomly pick a child based on ticket weighting, this will become the active child for this composite node.\n this.selectedChild = lottoDraw.draw() || undefined;\n }\n\n // If something went wrong and we don't have an active child then we should throw an error.\n if (!this.selectedChild) {\n throw new Error(\"failed to update lotto node as it has no active child\");\n }\n\n // If the selected child has never been updated or is running then we will need to update it now.\n if (this.selectedChild.getState() === State.READY || this.selectedChild.getState() === State.RUNNING) {\n this.selectedChild.update(agent, options);\n }\n\n // The state of the lotto node is the state of its selected child.\n this.setState(this.selectedChild.getState());\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => (this.weights ? `LOTTO [${this.weights.join(\",\")}]` : \"LOTTO\");\n}\n", "import Node from \"../Node\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\n\n/**\n * A decorator node that wraps a single child node.\n */\nexport default abstract class Decorator extends Node {\n /**\n * @param type The node type.\n * @param attributes The node attributes.\n * @param child The child node.\n */\n constructor(type: string, attributes: Attribute[], protected child: Node) {\n super(type, attributes, []);\n }\n\n /**\n * Gets whether this node is a leaf node.\n */\n isLeafNode = () => false;\n\n /**\n * Gets the children of this node.\n */\n getChildren = () => [this.child];\n\n /**\n * Reset the state of the node.\n */\n reset = () => {\n // Reset the state of this node.\n this.setState(State.READY);\n\n // Reset the state of the child node.\n this.child.reset();\n };\n\n /**\n * Abort the running of this node.\n * @param agent The agent.\n */\n abort = (agent: Agent) => {\n // There is nothing to do if this node is not in the running state.\n if (!this.is(State.RUNNING)) {\n return;\n }\n\n // Abort the child node.\n this.child.abort(agent);\n\n // Reset the state of this node.\n this.reset();\n\n this.getAttribute(\"exit\")?.callAgentFunction(agent, false, true);\n };\n}\n", "import Node from \"../Node\";\nimport Decorator from \"./Decorator\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A Fail node.\n * This node wraps a single child and will always move to the 'FAILED' state when the child moves to a 'SUCCEEDED' or 'FAILED' state.\n */\nexport default class Fail extends Decorator {\n /**\n * @param attributes The node attributes.\n * @param child The child node.\n */\n constructor(attributes: Attribute[], child: Node) {\n super(\"fail\", attributes, child);\n }\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // If the child has never been updated or is running then we will need to update it now.\n if (this.child.getState() === State.READY || this.child.getState() === State.RUNNING) {\n this.child.update(agent, options);\n }\n\n // The state of this node will depend in the state of its child.\n switch (this.child.getState()) {\n case State.RUNNING:\n this.setState(State.RUNNING);\n break;\n\n case State.SUCCEEDED:\n case State.FAILED:\n this.setState(State.FAILED);\n break;\n\n default:\n this.setState(State.READY);\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => \"FAIL\";\n}\n", "import Decorator from \"./Decorator\";\nimport State from \"../../State\";\nimport Node from \"../Node\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A Flip node.\n * This node wraps a single child and will flip the state of the child state.\n */\nexport default class Flip extends Decorator {\n /**\n * @param attributes The node attributes.\n * @param child The child node.\n */\n constructor(attributes: Attribute[], child: Node) {\n super(\"flip\", attributes, child);\n }\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // If the child has never been updated or is running then we will need to update it now.\n if (this.child.getState() === State.READY || this.child.getState() === State.RUNNING) {\n this.child.update(agent, options);\n }\n\n // The state of this node will depend in the state of its child.\n switch (this.child.getState()) {\n case State.RUNNING:\n this.setState(State.RUNNING);\n break;\n\n case State.SUCCEEDED:\n this.setState(State.FAILED);\n break;\n\n case State.FAILED:\n this.setState(State.SUCCEEDED);\n break;\n\n default:\n this.setState(State.READY);\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => \"FLIP\";\n}\n", "import Node from \"../Node\";\nimport Decorator from \"./Decorator\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A REPEAT node.\n * The node has a single child which can have:\n * -- A number of iterations for which to repeat the child node.\n * -- An infinite repeat loop if neither an iteration count or a condition function is defined.\n * The REPEAT node will stop and have a 'FAILED' state if its child is ever in a 'FAILED' state after an update.\n * The REPEAT node will attempt to move on to the next iteration if its child is ever in a 'SUCCEEDED' state.\n */\nexport default class Repeat extends Decorator {\n /**\n * @param attributes The node attributes.\n * @param iterations The number of iterations to repeat the child node.\n * @param iterationsMin The minimum possible number of iterations to repeat the child node.\n * @param iterationsMax The maximum possible number of iterations to repeat the child node.\n * @param child The child node.\n */\n constructor(\n attributes: Attribute[],\n private iterations: number | null,\n private iterationsMin: number | null,\n private iterationsMax: number | null,\n child: Node\n ) {\n super(\"repeat\", attributes, child);\n }\n\n /**\n * The number of target iterations to make.\n */\n private targetIterationCount: number | null = null;\n\n /**\n * The current iteration count.\n */\n private currentIterationCount: number = 0;\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // If this node is in the READY state then we need to reset the child and the target iteration count.\n if (this.is(State.READY)) {\n // Reset the child node.\n this.child.reset();\n\n // Reset the current iteration count.\n this.currentIterationCount = 0;\n\n // Set the target iteration count.\n this.setTargetIterationCount(options);\n }\n\n // Do a check to see if we can iterate. If we can then this node will move into the 'RUNNING' state.\n // If we cannot iterate then we have hit our target iteration count, which means that the node has succeeded.\n if (this.canIterate()) {\n // This node is in the running state and can do its initial iteration.\n this.setState(State.RUNNING);\n\n // We may have already completed an iteration, meaning that the child node will be in the SUCCEEDED state.\n // If this is the case then we will have to reset the child node now.\n if (this.child.getState() === State.SUCCEEDED) {\n this.child.reset();\n }\n\n // Update the child of this node.\n this.child.update(agent, options);\n\n // If the child moved into the FAILED state when we updated it then there is nothing left to do and this node has also failed.\n // If it has moved into the SUCCEEDED state then we have completed the current iteration.\n if (this.child.getState() === State.FAILED) {\n // The child has failed, meaning that this node has failed.\n this.setState(State.FAILED);\n\n return;\n } else if (this.child.getState() === State.SUCCEEDED) {\n // We have completed an iteration.\n this.currentIterationCount += 1;\n }\n } else {\n // This node is in the 'SUCCEEDED' state as we cannot iterate any more.\n this.setState(State.SUCCEEDED);\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => {\n if (this.iterations !== null) {\n return `REPEAT ${this.iterations}x`;\n } else if (this.iterationsMin !== null && this.iterationsMax !== null) {\n return `REPEAT ${this.iterationsMin}x-${this.iterationsMax}x`;\n } else {\n return \"REPEAT\";\n }\n };\n\n /**\n * Reset the state of the node.\n */\n reset = () => {\n // Reset the state of this node.\n this.setState(State.READY);\n\n // Reset the current iteration count.\n this.currentIterationCount = 0;\n\n // Reset the child node.\n this.child.reset();\n };\n\n /**\n * Gets whether an iteration can be made.\n * @returns Whether an iteration can be made.\n */\n private canIterate = () => {\n if (this.targetIterationCount !== null) {\n // We can iterate as long as we have not reached our target iteration count.\n return this.currentIterationCount < this.targetIterationCount;\n }\n\n // If neither an iteration count or a condition function were defined then we can iterate indefinitely.\n return true;\n };\n\n /**\n * Sets the target iteration count.\n * @param options The behaviour tree options object.\n */\n private setTargetIterationCount = (options: BehaviourTreeOptions) => {\n // Are we dealing with an explicit iteration count or will we be randomly picking a iteration count between the min and max iteration count.\n if (this.iterations !== null) {\n this.targetIterationCount = this.iterations;\n } else if (this.iterationsMin !== null && this.iterationsMax !== null) {\n // We will be picking a random iteration count between a min and max iteration count, if the optional 'random'\n // behaviour tree function option is defined then we will be using that, otherwise we will fall back to using Math.random.\n const random = typeof options.random === \"function\" ? options.random : Math.random;\n\n // Pick a random iteration count between a min and max iteration count.\n this.targetIterationCount = Math.floor(\n random() * (this.iterationsMax - this.iterationsMin + 1) + this.iterationsMin\n );\n } else {\n this.targetIterationCount = null;\n }\n };\n}\n", "import Node from \"../Node\";\nimport Decorator from \"./Decorator\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A RETRY node.\n * The node has a single child which can have:\n * -- A number of iterations for which to repeat the child node.\n * -- An infinite repeat loop if neither an iteration count or a condition function is defined.\n * The RETRY node will stop and have a 'SUCCEEDED' state if its child is ever in a 'SUCCEEDED' state after an update.\n * The RETRY node will attempt to move on to the next iteration if its child is ever in a 'FAILED' state.\n */\nexport default class Retry extends Decorator {\n /**\n * @param attributes The node attributes.\n * @param attempts The number of attempts to retry the child node.\n * @param attemptsMin The minimum possible number of attempts to retry the child node.\n * @param attemptsMax The maximum possible number of attempts to retry the child node.\n * @param child The child node.\n */\n constructor(\n attributes: Attribute[],\n private attempts: number | null,\n private attemptsMin: number | null,\n private attemptsMax: number | null,\n child: Node\n ) {\n super(\"retry\", attributes, child);\n }\n\n /**\n * The number of target attempts to make.\n */\n private targetAttemptCount: number | null = null;\n\n /**\n * The current attempt count.\n */\n private currentAttemptCount: number = 0;\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // If this node is in the READY state then we need to reset the child and the target attempt count.\n if (this.is(State.READY)) {\n // Reset the child node.\n this.child.reset();\n\n // Reset the current attempt count.\n this.currentAttemptCount = 0;\n\n // Set the target attempt count.\n this.setTargetAttemptCount(options);\n }\n\n // Do a check to see if we can attempt. If we can then this node will move into the 'RUNNING' state.\n // If we cannot attempt then we have hit our target attempt count, which means that the node has succeeded.\n if (this.canAttempt()) {\n // This node is in the running state and can do its initial attempt.\n this.setState(State.RUNNING);\n\n // We may have already completed an attempt, meaning that the child node will be in the FAILED state.\n // If this is the case then we will have to reset the child node now.\n if (this.child.getState() === State.FAILED) {\n this.child.reset();\n }\n\n // Update the child of this node.\n this.child.update(agent, options);\n\n // If the child moved into the SUCCEEDED state when we updated it then there is nothing left to do and this node has also succeeded.\n // If it has moved into the FAILED state then we have completed the current attempt.\n if (this.child.getState() === State.SUCCEEDED) {\n // The child has succeeded, meaning that this node has succeeded.\n this.setState(State.SUCCEEDED);\n\n return;\n } else if (this.child.getState() === State.FAILED) {\n // We have completed an attempt.\n this.currentAttemptCount += 1;\n }\n } else {\n // This node is in the 'FAILED' state as we cannot iterate any more.\n this.setState(State.FAILED);\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => {\n if (this.attempts !== null) {\n return `RETRY ${this.attempts}x`;\n } else if (this.attemptsMin !== null && this.attemptsMax !== null) {\n return `RETRY ${this.attemptsMin}x-${this.attemptsMax}x`;\n } else {\n return \"RETRY\";\n }\n };\n\n /**\n * Reset the state of the node.\n */\n reset = () => {\n // Reset the state of this node.\n this.setState(State.READY);\n\n // Reset the current attempt count.\n this.currentAttemptCount = 0;\n\n // Reset the child node.\n this.child.reset();\n };\n\n /**\n * Gets whether an attempt can be made.\n * @returns Whether an attempt can be made.\n */\n canAttempt = () => {\n if (this.targetAttemptCount !== null) {\n // We can attempt as long as we have not reached our target attempt count.\n return this.currentAttemptCount < this.targetAttemptCount;\n }\n\n // If neither an attempt count or a condition function were defined then we can attempt indefinitely.\n return true;\n };\n\n /**\n * Sets the target attempt count.\n * @param options The behaviour tree options object.\n */\n setTargetAttemptCount = (options: BehaviourTreeOptions) => {\n // Are we dealing with an explicit attempt count or will we be randomly picking an attempt count between the min and max attempt count.\n if (this.attempts !== null) {\n this.targetAttemptCount = this.attempts;\n } else if (this.attemptsMin !== null && this.attemptsMax !== null) {\n // We will be picking a random attempt count between a min and max attempt count, if the optional 'random'\n // behaviour tree function option is defined then we will be using that, otherwise we will fall back to using Math.random.\n const random = typeof options.random === \"function\" ? options.random : Math.random;\n\n // Pick a random attempt count between a min and max attempt count.\n this.targetAttemptCount = Math.floor(\n random() * (this.attemptsMax - this.attemptsMin + 1) + this.attemptsMin\n );\n } else {\n this.targetAttemptCount = null;\n }\n };\n}\n", "import Node from \"../Node\";\nimport Decorator from \"./Decorator\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A Root node.\n * The root node will have a single child.\n */\nexport default class Root extends Decorator {\n /**\n * @param attributes The node attributes.\n * @param child The child node.\n */\n constructor(attributes: Attribute[], child: Node) {\n super(\"root\", attributes, child);\n }\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // If the child has never been updated or is running then we will need to update it now.\n if (this.child.getState() === State.READY || this.child.getState() === State.RUNNING) {\n // Update the child of this node.\n this.child.update(agent, options);\n }\n\n // The state of the root node is the state of its child.\n this.setState(this.child.getState());\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => \"ROOT\";\n}\n", "import Node from \"../Node\";\nimport Decorator from \"./Decorator\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A Succeed node.\n * This node wraps a single child and will always move to the 'SUCCEEDED' state when the child moves to a 'SUCCEEDED' or 'FAILED' state.\n */\nexport default class Succeed extends Decorator {\n /**\n * @param attributes The node attributes.\n * @param child The child node.\n */\n constructor(attributes: Attribute[], child: Node) {\n super(\"succeed\", attributes, child);\n }\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // If the child has never been updated or is running then we will need to update it now.\n if (this.child.getState() === State.READY || this.child.getState() === State.RUNNING) {\n this.child.update(agent, options);\n }\n\n // The state of this node will depend in the state of its child.\n switch (this.child.getState()) {\n case State.RUNNING:\n this.setState(State.RUNNING);\n break;\n\n case State.SUCCEEDED:\n case State.FAILED:\n this.setState(State.SUCCEEDED);\n break;\n\n default:\n this.setState(State.READY);\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => \"SUCCEED\";\n}\n", "import Node from \"../Node\";\n\n/**\n * A leaf node.\n */\nexport default abstract class Leaf extends Node {\n /**\n * Gets whether this node is a leaf node.\n */\n isLeafNode = () => true;\n}\n", "import { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\nimport State, { CompleteState } from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Leaf from \"./Leaf\";\nimport Lookup from \"../../Lookup\";\nimport Attribute from \"../../attributes/Attribute\";\n\n/**\n * The type representing a resolved/rejected update promise.\n */\ntype UpdatePromiseResult = {\n /**\n * Whether the promise was resolved rather than rejected.\n */\n isResolved: boolean;\n\n /**\n * The promise resolved value or rejection reason.\n */\n value: any;\n};\n\n/**\n * An Action leaf node.\n * This represents an immediate or ongoing state of behaviour.\n */\nexport default class Action extends Leaf {\n /**\n * @param attributes The node attributes.\n * @param actionName The action name.\n * @param actionArguments The array of action argument definitions.\n */\n constructor(attributes: Attribute[], private actionName: string, private actionArguments: any[]) {\n super(\"action\", attributes, actionArguments);\n }\n\n /**\n * Whether there is a pending update promise.\n */\n private isUsingUpdatePromise = false;\n\n /**\n * The finished state result of an update promise.\n */\n private updatePromiseResult: UpdatePromiseResult | null = null;\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // If the result of this action depends on an update promise then there is nothing to do until it settles.\n if (this.isUsingUpdatePromise) {\n // Are we still waiting for our update promise to settle?\n if (!this.updatePromiseResult) {\n return;\n }\n\n const { isResolved, value } = this.updatePromiseResult;\n\n // Our update promise settled, was it resolved or rejected?\n if (isResolved) {\n // Our promise resolved so check to make sure the result is a valid finished state.\n if (value !== State.SUCCEEDED && value !== State.FAILED) {\n throw new Error(\n \"action node promise resolved with an invalid value, expected a State.SUCCEEDED or State.FAILED value to be returned\"\n );\n }\n\n // Set the state of this node to match the state returned by the promise.\n this.setState(value);\n\n return;\n } else {\n // The promise was rejected, which isn't great.\n throw new Error(`action function '${this.actionName}' promise rejected with '${value}'`);\n }\n }\n\n // Attempt to get the invoker for the action function.\n const actionFuncInvoker = Lookup.getFuncInvoker(agent, this.actionName);\n\n // The action function should be defined.\n if (actionFuncInvoker === null) {\n throw new Error(\n `cannot update action node as the action '${this.actionName}' function is not defined on the agent and has not been registered`\n );\n }\n\n let actionFunctionResult;\n\n try {\n // Call the action function, the result of which may be:\n // - The finished state of this action node.\n // - A promise to return a finished node state.\n // - Undefined if the node should remain in the running state.\n actionFunctionResult = actionFuncInvoker(this.actionArguments) as CompleteState | Promise;\n } catch (error) {\n // The user was naughty and threw something.\n throw new Error(`action function '${this.actionName}' threw '${error}'`);\n }\n\n if (actionFunctionResult instanceof Promise) {\n actionFunctionResult.then(\n (result) => {\n // If 'isUpdatePromisePending' is not set then the promise was cleared as it was resolving, probably via an abort of reset.\n if (!this.isUsingUpdatePromise) {\n return;\n }\n\n // Set the resolved update promise result so that it can be handled on the next update of this node.\n this.updatePromiseResult = {\n isResolved: true,\n value: result\n };\n },\n (reason) => {\n // If 'isUpdatePromisePending' is not set then the promise was cleared as it was resolving, probably via an abort or reset.\n if (!this.isUsingUpdatePromise) {\n return;\n }\n\n // Set the rejected update promise result so that it can be handled on the next update of this node.\n this.updatePromiseResult = {\n isResolved: false,\n value: reason\n };\n }\n );\n\n // This node will be in the 'RUNNING' state until the update promise resolves.\n this.setState(State.RUNNING);\n\n // We are now waiting for the promise returned by the use to resolve before we know what state this node is in.\n this.isUsingUpdatePromise = true;\n } else {\n // Validate the returned value.\n this.validateUpdateResult(actionFunctionResult);\n\n // Set the state of this node, this may be undefined, which just means that the node is still in the 'RUNNING' state.\n this.setState(actionFunctionResult || State.RUNNING);\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => this.actionName;\n\n /**\n * Reset the state of the node.\n */\n reset = () => {\n // Reset the state of this node.\n this.setState(State.READY);\n\n // There is no longer an update promise that we care about.\n this.isUsingUpdatePromise = false;\n this.updatePromiseResult = null;\n };\n\n /**\n * Validate the result of an update function call.\n * @param result The result of an update function call.\n */\n private validateUpdateResult = (result: CompleteState | State.RUNNING) => {\n switch (result) {\n case State.SUCCEEDED:\n case State.FAILED:\n case State.RUNNING:\n case undefined:\n return;\n default:\n throw new Error(\n `expected action function '${this.actionName}' to return an optional State.SUCCEEDED or State.FAILED value but returned '${result}'`\n );\n }\n };\n}\n", "import { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Leaf from \"./Leaf\";\nimport Lookup from \"../../Lookup\";\nimport Attribute from \"../../attributes/Attribute\";\n\n/**\n * A Condition leaf node.\n * This will succeed or fail immediately based on an agent predicate, without moving to the 'RUNNING' state.\n */\nexport default class Condition extends Leaf {\n /**\n * @param attributes The node attributes.\n * @param conditionName The name of the condition function.\n * @param conditionArguments The array of condition argument definitions.\n */\n constructor(attributes: Attribute[], private conditionName: string, private conditionArguments: any[]) {\n super(\"condition\", attributes, conditionArguments);\n }\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // Attempt to get the invoker for the condition function.\n const conditionFuncInvoker = Lookup.getFuncInvoker(agent, this.conditionName);\n\n // The condition function should be defined.\n if (conditionFuncInvoker === null) {\n throw new Error(\n `cannot update condition node as the condition '${this.conditionName}' function is not defined on the agent and has not been registered`\n );\n }\n\n let conditionFunctionResult;\n\n try {\n // Call the condition function to determine the state of this node, the result of which should be a boolean.\n conditionFunctionResult = conditionFuncInvoker(this.conditionArguments);\n } catch (error) {\n // The user was naughty and threw something.\n throw new Error(`condition function '${this.conditionName}' threw '${error}'`);\n }\n\n // The result of calling the condition function must be a boolean value.\n if (typeof conditionFunctionResult !== \"boolean\") {\n throw new Error(\n `expected condition function '${this.conditionName}' to return a boolean but returned '${conditionFunctionResult}'`\n );\n }\n\n // Set the state of this node based on the result of calling the condition function.\n this.setState(!!conditionFunctionResult ? State.SUCCEEDED : State.FAILED);\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => this.conditionName;\n}\n", "import Leaf from \"./Leaf\";\nimport State from \"../../State\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { Agent } from \"../../Agent\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A WAIT node.\n * The state of this node will change to SUCCEEDED after a duration of time\n */\nexport default class Wait extends Leaf {\n /**\n * @param attributes The node attributes.\n * @param duration The duration that this node will wait to succeed in milliseconds.\n * @param durationMin The minimum possible duration in milliseconds that this node will wait to succeed.\n * @param durationMax The maximum possible duration in milliseconds that this node will wait to succeed.\n */\n constructor(\n attributes: Attribute[],\n private duration: number | null,\n private durationMin: number | null,\n private durationMax: number | null\n ) {\n super(\"wait\", attributes, []);\n }\n\n /**\n * The time in milliseconds at which this node was first updated.\n */\n private initialUpdateTime: number = 0;\n\n /**\n * The total duration in milliseconds that this node will be waiting for.\n */\n private totalDuration: number | null = null;\n\n /**\n * The duration in milliseconds that this node has been waiting for.\n */\n private waitedDuration: number = 0;\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // If this node is in the READY state then we need to set the initial update time.\n if (this.is(State.READY)) {\n // Set the initial update time.\n this.initialUpdateTime = new Date().getTime();\n\n // Set the initial waited duration.\n this.waitedDuration = 0;\n\n // Are we dealing with an explicit duration or will we be randomly picking a duration between the min and max duration.\n if (this.duration !== null) {\n this.totalDuration = this.duration;\n } else if (this.durationMin !== null && this.durationMax !== null) {\n // We will be picking a random duration between a min and max duration, if the optional 'random' behaviour tree\n // function option is defined then we will be using that, otherwise we will fall back to using Math.random.\n const random = typeof options.random === \"function\" ? options.random : Math.random;\n\n // Pick a random duration between a min and max duration.\n this.totalDuration = Math.floor(\n random() * (this.durationMax - this.durationMin + 1) + this.durationMin\n );\n } else {\n this.totalDuration = null;\n }\n\n // The node is now running until we finish waiting.\n this.setState(State.RUNNING);\n }\n\n // If we have no total duration then this wait node will wait indefinitely until it is aborted.\n if (this.totalDuration === null) {\n return;\n }\n\n // If we have a 'getDeltaTime' function defined as part of our options then we will use it to figure out how long we have waited for.\n if (typeof options.getDeltaTime === \"function\") {\n // Get the delta time.\n const deltaTime = options.getDeltaTime();\n\n // Our delta time must be a valid number and cannot be NaN.\n if (typeof deltaTime !== \"number\" || isNaN(deltaTime)) {\n throw new Error(\"The delta time must be a valid number and not NaN.\");\n }\n\n // Update the amount of time that this node has been waiting for based on the delta time.\n this.waitedDuration += deltaTime * 1000;\n } else {\n // We are not using a delta time, so we will just work out hom much time has passed since the first update.\n this.waitedDuration = new Date().getTime() - this.initialUpdateTime;\n }\n\n // Have we waited long enough?\n if (this.waitedDuration >= this.totalDuration) {\n // We have finished waiting!\n this.setState(State.SUCCEEDED);\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => {\n if (this.duration !== null) {\n return `WAIT ${this.duration}ms`;\n } else if (this.durationMin !== null && this.durationMax !== null) {\n return `WAIT ${this.durationMin}ms-${this.durationMax}ms`;\n } else {\n return \"WAIT\";\n }\n };\n}\n", "import Guard from \"./guards/Guard\";\n\nexport type AttributeDetails = {\n /** The attribute type. */\n type: string;\n\n /** The attribute arguments. */\n args: any[];\n};\n\n/**\n * A base node attribute.\n */\nexport default abstract class Attribute {\n /**\n * @param type The node attribute type.\n * @param args The array of attribute arguments.\n */\n constructor(public type: string, public args: any[]) {}\n\n /**\n * Gets the attribute details.\n */\n abstract getDetails(): TAttributeDetails;\n\n /**\n * Gets whether this attribute is a guard.\n */\n abstract isGuard: () => this is Guard;\n}\n", "import { Agent } from \"../../Agent\";\nimport Attribute, { AttributeDetails } from \"../Attribute\";\n\nexport type GuardAttributeDetails = {\n /** The name of the condition function that determines whether the guard is satisfied. */\n condition: string;\n} & AttributeDetails;\n\n/**\n * A base node guard attribute.\n */\nexport default abstract class Guard extends Attribute {\n /**\n * @param type The node attribute type.\n * @param args The array of decorator argument definitions.\n * @param condition The name of the condition function that determines whether the guard is satisfied.\n */\n constructor(type: string, args: any[], private condition: string) {\n super(type, args);\n }\n\n /**\n * Gets the name of the condition function that determines whether the guard is satisfied.\n */\n getCondition = () => this.condition;\n\n /**\n * Gets whether this attribute is a guard.\n */\n isGuard = () => true;\n\n /**\n * Gets the attribute details.\n */\n getDetails(): GuardAttributeDetails {\n return {\n type: this.type,\n args: this.args,\n condition: this.getCondition()\n };\n }\n\n /**\n * Gets whether the guard is satisfied.\n * @param agent The agent.\n * @returns Whether the guard is satisfied.\n */\n abstract isSatisfied(agent: Agent): boolean;\n}\n", "import Guard from \"./Guard\";\nimport Lookup from \"../../Lookup\";\nimport { Agent } from \"../../Agent\";\n\n/**\n * A WHILE guard which is satisfied as long as the given condition remains true.\n */\nexport default class While extends Guard {\n /**\n * @param condition The name of the condition function that determines whether the guard is satisfied.\n * @param args The array of decorator argument definitions.\n */\n constructor(condition: string, args: any[]) {\n super(\"while\", args, condition);\n }\n\n /**\n * Gets whether the guard is satisfied.\n * @param agent The agent.\n * @returns Whether the guard is satisfied.\n */\n isSatisfied = (agent: Agent) => {\n // Attempt to get the invoker for the condition function.\n const conditionFuncInvoker = Lookup.getFuncInvoker(agent, this.getCondition());\n\n // The condition function should be defined.\n if (conditionFuncInvoker === null) {\n throw new Error(\n `cannot evaluate node guard as the condition '${this.getCondition()}' function is not defined on the agent and has not been registered`\n );\n }\n\n let conditionFunctionResult;\n\n try {\n // Call the guard condition function to determine the state of this node, the result of which should be a boolean.\n conditionFunctionResult = conditionFuncInvoker(this.args);\n } catch (error) {\n // The user was naughty and threw something.\n throw new Error(`guard condition function '${this.getCondition()}' threw '${error}'`);\n }\n\n // The result of calling the guard condition function must be a boolean value.\n if (typeof conditionFunctionResult !== \"boolean\") {\n throw new Error(\n `expected guard condition function '${this.getCondition()}' to return a boolean but returned '${conditionFunctionResult}'`\n );\n }\n\n // Return whether this guard is satisfied.\n return conditionFunctionResult;\n };\n}\n", "import Guard from \"./Guard\";\nimport Lookup from \"../../Lookup\";\nimport { Agent } from \"../../Agent\";\n\n/**\n * An UNTIL guard which is satisfied as long as the given condition remains false.\n */\nexport default class Until extends Guard {\n /**\n * @param condition The name of the condition function that determines whether the guard is satisfied.\n * @param args The array of decorator argument definitions.\n */\n constructor(condition: string, args: any[]) {\n super(\"until\", args, condition);\n }\n\n /**\n * Gets whether the guard is satisfied.\n * @param agent The agent.\n * @returns Whether the guard is satisfied.\n */\n isSatisfied = (agent: Agent) => {\n // Attempt to get the invoker for the condition function.\n const conditionFuncInvoker = Lookup.getFuncInvoker(agent, this.getCondition());\n\n // The condition function should be defined.\n if (conditionFuncInvoker === null) {\n throw new Error(\n `cannot evaluate node guard as the condition '${this.getCondition()}' function is not defined on the agent and has not been registered`\n );\n }\n\n let conditionFunctionResult;\n\n try {\n // Call the guard condition function to determine the state of this node, the result of which should be a boolean.\n conditionFunctionResult = conditionFuncInvoker(this.args);\n } catch (error) {\n // The user was naughty and threw something.\n throw new Error(`guard condition function '${this.getCondition()}' threw '${error}'`);\n }\n\n // The result of calling the guard condition function must be a boolean value.\n if (typeof conditionFunctionResult !== \"boolean\") {\n throw new Error(\n `expected guard condition function '${this.getCondition()}' to return a boolean but returned '${conditionFunctionResult}'`\n );\n }\n\n // Return whether this guard is satisfied.\n return !conditionFunctionResult;\n };\n}\n", "import { Agent } from \"../../Agent\";\nimport Attribute, { AttributeDetails } from \"../Attribute\";\n\nexport type CallbackAttributeDetails = {\n /** The name of the agent function that is called. */\n functionName: string;\n} & AttributeDetails;\n\n/**\n * A base node callback attribute.\n */\nexport default abstract class Callback extends Attribute {\n /**\n * @param type The node attribute type.\n * @param args The array of decorator argument definitions.\n * @param functionName The name of the agent function to call.\n */\n constructor(type: string, args: any[], private functionName: string) {\n super(type, args);\n }\n\n /**\n * Gets the name of the agent function to call.\n */\n getFunctionName = () => this.functionName;\n\n /**\n * Gets whether this attribute is a guard.\n */\n isGuard = () => false;\n\n /**\n * Gets the attribute details.\n */\n getDetails(): CallbackAttributeDetails {\n return {\n type: this.type,\n args: this.args,\n functionName: this.getFunctionName()\n };\n }\n\n /**\n * Attempt to call the agent function that this callback refers to.\n * @param agent The agent.\n */\n abstract callAgentFunction: (agent: Agent, isSuccess: boolean, isAborted: boolean) => void;\n}\n", "import Callback from \"./Callback\";\nimport Lookup from \"../../Lookup\";\nimport { Agent } from \"../../Agent\";\n\n/**\n * An ENTRY callback which defines an agent function to call when the associated node is updated and moves out of running state.\n */\nexport default class Entry extends Callback {\n /**\n * @param functionName The name of the agent function to call.\n * @param args The array of callback argument definitions.\n */\n constructor(functionName: string, args: any[]) {\n super(\"entry\", args, functionName);\n }\n\n /**\n * Attempt to call the agent function that this callback refers to.\n * @param agent The agent.\n */\n callAgentFunction = (agent: Agent) => {\n // Attempt to get the invoker for the callback function.\n const callbackFuncInvoker = Lookup.getFuncInvoker(agent, this.getFunctionName());\n\n // The callback function should be defined.\n if (callbackFuncInvoker === null) {\n throw new Error(\n `cannot call entry function '${this.getFunctionName()}' as is not defined on the agent and has not been registered`\n );\n }\n\n // Call the callback function.\n callbackFuncInvoker(this.args);\n };\n}\n", "import Callback from \"./Callback\";\nimport Lookup from \"../../Lookup\";\nimport { Agent } from \"../../Agent\";\n\n/**\n * A STEP callback which defines an agent function to call when the associated node is updated.\n */\nexport default class Step extends Callback {\n /**\n * @param functionName The name of the agent function to call.\n * @param args The array of callback argument definitions.\n */\n constructor(functionName: string, args: any[]) {\n super(\"step\", args, functionName);\n }\n\n /**\n * Attempt to call the agent function that this callback refers to.\n * @param agent The agent.\n */\n callAgentFunction = (agent: Agent) => {\n // Attempt to get the invoker for the callback function.\n const callbackFuncInvoker = Lookup.getFuncInvoker(agent, this.getFunctionName());\n\n // The callback function should be defined.\n if (callbackFuncInvoker === null) {\n throw new Error(\n `cannot call step function '${this.getFunctionName()}' as is not defined on the agent and has not been registered`\n );\n }\n\n // Call the callback function.\n callbackFuncInvoker(this.args);\n };\n}\n", "import Callback from \"./Callback\";\nimport Lookup from \"../../Lookup\";\nimport { Agent } from \"../../Agent\";\n\n/**\n * An EXIT callback which defines an agent function to call when the associated node is updated and moves to a finished state or is aborted.\n */\nexport default class Exit extends Callback {\n /**\n * @param functionName The name of the agent function to call.\n * @param args The array of callback argument definitions.\n */\n constructor(functionName: string, args: any[]) {\n super(\"exit\", args, functionName);\n }\n\n /**\n * Attempt to call the agent function that this callback refers to.\n * @param agent The agent.\n * @param isSuccess Whether the decorated node was left with a success state.\n * @param isAborted Whether the decorated node was aborted.\n */\n callAgentFunction = (agent: Agent, isSuccess: boolean, isAborted: boolean) => {\n // Attempt to get the invoker for the callback function.\n const callbackFuncInvoker = Lookup.getFuncInvoker(agent, this.getFunctionName());\n\n // The callback function should be defined.\n if (callbackFuncInvoker === null) {\n throw new Error(\n `cannot call exit function '${this.getFunctionName()}' as is not defined on the agent and has not been registered`\n );\n }\n\n // Call the callback function\n callbackFuncInvoker([{ succeeded: isSuccess, aborted: isAborted }, ...this.args]);\n };\n}\n", "import { AnyNodeDefinition, RootNodeDefinition } from \"./BehaviourTreeDefinition\";\nimport GuardPath, { GuardPathPart } from \"./attributes/guards/GuardPath\";\nimport { validateBranchSubtreeLinks } from \"./BehaviourTreeDefinitionValidator\";\nimport { isInteger } from \"./BehaviourTreeDefinitionUtilities\";\nimport Node from \"./nodes/Node\";\nimport Composite from \"./nodes/composite/Composite\";\nimport Decorator from \"./nodes/decorator/Decorator\";\nimport Parallel from \"./nodes/composite/Parallel\";\nimport Selector from \"./nodes/composite/Selector\";\nimport Sequence from \"./nodes/composite/Sequence\";\nimport Lotto from \"./nodes/composite/Lotto\";\nimport Fail from \"./nodes/decorator/Fail\";\nimport Flip from \"./nodes/decorator/Flip\";\nimport Repeat from \"./nodes/decorator/Repeat\";\nimport Retry from \"./nodes/decorator/Retry\";\nimport Root from \"./nodes/decorator/Root\";\nimport Succeed from \"./nodes/decorator/Succeed\";\nimport Action from \"./nodes/leaf/Action\";\nimport Condition from \"./nodes/leaf/Condition\";\nimport Wait from \"./nodes/leaf/Wait\";\nimport Lookup from \"./Lookup\";\nimport Attribute from \"./attributes/Attribute\";\nimport While from \"./attributes/guards/While\";\nimport Until from \"./attributes/guards/Until\";\nimport Entry from \"./attributes/callbacks/Entry\";\nimport Step from \"./attributes/callbacks/Step\";\nimport Exit from \"./attributes/callbacks/Exit\";\n\n/**\n * A type representing any node instance in a behaviour tree.\n */\ntype AnyNode =\n | Root\n | Action\n | Condition\n | Wait\n | Sequence\n | Selector\n | Lotto\n | Parallel\n | Repeat\n | Retry\n | Flip\n | Succeed\n | Fail;\n\n/**\n * A type defining a mapping of root node identifiers to root node definitions.\n */\ntype RootNodeDefinitionMap = { [key: string | symbol]: RootNodeDefinition };\n\n/**\n * A symbol to use as the main root key in any root node mappings.\n */\nconst MAIN_ROOT_NODE_KEY = Symbol(\"__root__\");\n\n/**\n * Build and populate the root nodes based on the provided definition, assuming that the definition has been validated.\n * @param definition The root node definitions.\n * @returns The built and populated root node definitions.\n */\nexport default function buildRootNode(definition: RootNodeDefinition[]): Root {\n // Create a mapping of root node identifers to root node definitions, including globally registered subtree root node definitions.\n const rootNodeDefinitionMap = createRootNodeDefinitionMap(definition);\n\n // Now that we have all of our root node definitions (those part of the tree definition and those globally registered)\n // we should validate the branch-subtree links. This will also double-check that we dont have any circular dependencies\n // in our branch-subtree references and that we have no broken branch-subtree links.\n validateBranchSubtreeLinks(\n [rootNodeDefinitionMap[MAIN_ROOT_NODE_KEY], ...Object.values(rootNodeDefinitionMap)],\n true\n );\n\n // Create our populated tree of node instances, starting with our main root node.\n const rootNode = nodeFactory(rootNodeDefinitionMap[MAIN_ROOT_NODE_KEY], rootNodeDefinitionMap) as Root;\n\n // Set a guard path on every leaf of the tree to evaluate as part of each update.\n applyLeafNodeGuardPaths(rootNode);\n\n // We only need to return the main root node.\n return rootNode;\n}\n\n/**\n * A factory function which creates a node instance based on the specified definition.\n * @param definition The node definition.\n * @param rootNodeDefinitionMap The mapping of root node identifers to root node definitions, including globally registered subtree root node definitions.\n * @returns A node instance based on the specified definition.\n */\nfunction nodeFactory(definition: AnyNodeDefinition, rootNodeDefinitionMap: RootNodeDefinitionMap): AnyNode {\n // Get the attributes for the node.\n const attributes = nodeAttributesFactory(definition);\n\n // Create the node instance based on the definition type.\n switch (definition.type) {\n case \"root\":\n return new Root(attributes, nodeFactory(definition.child, rootNodeDefinitionMap));\n\n case \"repeat\":\n let iterations: number | null = null;\n let iterationsMin: number | null = null;\n let iterationsMax: number | null = null;\n\n if (Array.isArray(definition.iterations)) {\n iterationsMin = definition.iterations[0];\n iterationsMax = definition.iterations[1];\n } else if (isInteger(definition.iterations)) {\n iterations = definition.iterations!;\n }\n\n return new Repeat(\n attributes,\n iterations,\n iterationsMin,\n iterationsMax,\n nodeFactory(definition.child, rootNodeDefinitionMap)\n );\n\n case \"retry\":\n let attempts: number | null = null;\n let attemptsMin: number | null = null;\n let attemptsMax: number | null = null;\n\n if (Array.isArray(definition.attempts)) {\n attemptsMin = definition.attempts[0];\n attemptsMax = definition.attempts[1];\n } else if (isInteger(definition.attempts)) {\n attempts = definition.attempts!;\n }\n\n return new Retry(\n attributes,\n attempts,\n attemptsMin,\n attemptsMax,\n nodeFactory(definition.child, rootNodeDefinitionMap)\n );\n\n case \"flip\":\n return new Flip(attributes, nodeFactory(definition.child, rootNodeDefinitionMap));\n\n case \"succeed\":\n return new Succeed(attributes, nodeFactory(definition.child, rootNodeDefinitionMap));\n\n case \"fail\":\n return new Fail(attributes, nodeFactory(definition.child, rootNodeDefinitionMap));\n\n case \"sequence\":\n return new Sequence(\n attributes,\n definition.children.map((child) => nodeFactory(child, rootNodeDefinitionMap))\n );\n\n case \"selector\":\n return new Selector(\n attributes,\n definition.children.map((child) => nodeFactory(child, rootNodeDefinitionMap))\n );\n\n case \"parallel\":\n return new Parallel(\n attributes,\n definition.children.map((child) => nodeFactory(child, rootNodeDefinitionMap))\n );\n\n case \"lotto\":\n return new Lotto(\n attributes,\n definition.weights,\n definition.children.map((child) => nodeFactory(child, rootNodeDefinitionMap))\n );\n\n case \"branch\":\n return nodeFactory(rootNodeDefinitionMap[definition.ref].child, rootNodeDefinitionMap);\n\n case \"action\":\n return new Action(attributes, definition.call, definition.args || []);\n\n case \"condition\":\n return new Condition(attributes, definition.call, definition.args || []);\n\n case \"wait\":\n let duration: number | null = null;\n let durationMin: number | null = null;\n let durationMax: number | null = null;\n\n if (Array.isArray(definition.duration)) {\n durationMin = definition.duration[0];\n durationMax = definition.duration[1];\n } else if (isInteger(definition.duration)) {\n duration = definition.duration!;\n }\n\n return new Wait(attributes, duration, durationMin, durationMax);\n }\n}\n\n/**\n * Creates an array of node attribute instances based on the specified node definition.\n * @param definition The node definition.\n * @returns An array of node attribute instances based on the specified node definition.\n */\nfunction nodeAttributesFactory(definition: AnyNodeDefinition): Attribute[] {\n const attributes: Attribute[] = [];\n\n if (definition.while) {\n attributes.push(new While(definition.while.call, definition.while.args ?? []));\n }\n\n if (definition.until) {\n attributes.push(new Until(definition.until.call, definition.until.args ?? []));\n }\n\n if (definition.entry) {\n attributes.push(new Entry(definition.entry.call, definition.entry.args ?? []));\n }\n\n if (definition.step) {\n attributes.push(new Step(definition.step.call, definition.step.args ?? []));\n }\n\n if (definition.exit) {\n attributes.push(new Exit(definition.exit.call, definition.exit.args ?? []));\n }\n\n return attributes;\n}\n\n/**\n * Creates a mapping of root node identifers to root node definitions, mixing in globally registered subtree root node definitions.\n * @param definition The root node definitions.\n * @returns A mapping of root node identifers to root node definitions, including globally registered subtree root node definitions.\n */\nfunction createRootNodeDefinitionMap(definition: RootNodeDefinition[]): RootNodeDefinitionMap {\n // Create a mapping of root node identifers to root node definitions.\n const rootNodeMap: RootNodeDefinitionMap = {};\n\n // Add in any registered subtree root node definitions.\n for (const [name, rootNodeDefinition] of Object.entries(Lookup.getSubtrees())) {\n // The name used when registering the subtree will be used as the root node identifier.\n rootNodeMap[name] = { ...rootNodeDefinition, id: name };\n }\n\n // Populate the map with the root node definitions that were included with the tree definition.\n // We do this after adding any registered subtrees as we want these to take presedence.\n for (const rootNodeDefinition of definition) {\n rootNodeMap[rootNodeDefinition.id ?? MAIN_ROOT_NODE_KEY] = rootNodeDefinition;\n }\n\n return rootNodeMap;\n}\n\n/**\n * Applies a guard path to every leaf of the tree to evaluate as part of each update.\n * @param root The main root tree node.\n */\nfunction applyLeafNodeGuardPaths(root: Root) {\n const nodePaths: Node[][] = [];\n\n const findLeafNodes = (path: Node[], node: Node) => {\n // Add the current node to the path.\n path = path.concat(node);\n\n // Check whether the current node is a leaf node.\n if (node.isLeafNode()) {\n nodePaths.push(path);\n } else {\n (node as Composite | Decorator).getChildren().forEach((child) => findLeafNodes(path, child));\n }\n };\n\n // Find all leaf node paths, starting from the root.\n findLeafNodes([], root);\n\n nodePaths.forEach((path) => {\n // Each node in the current path will have to be assigned a guard path, working from the root outwards.\n for (let depth = 0; depth < path.length; depth++) {\n // Get the node in the path at the current depth.\n const currentNode = path[depth];\n\n // The node may already have been assigned a guard path, if so just skip it.\n if (currentNode.hasGuardPath()) {\n continue;\n }\n\n // Create the guard path for the current node.\n const guardPath = new GuardPath(\n path\n .slice(0, depth + 1)\n .map((node) => ({ node, guards: node.getGuardAttributes() }))\n .filter((details) => details.guards.length > 0)\n );\n\n // Assign the guard path to the current node.\n currentNode.setGuardPath(guardPath);\n }\n });\n}\n", "import State, { AnyState } from \"./State\";\nimport Lookup from \"./Lookup\";\nimport Node from \"./nodes/Node\";\nimport Root from \"./nodes/decorator/Root\";\nimport Composite from \"./nodes/composite/Composite\";\nimport Decorator from \"./nodes/decorator/Decorator\";\nimport { Agent, GlobalFunction } from \"./Agent\";\nimport { CallbackAttributeDetails } from \"./attributes/callbacks/Callback\";\nimport { GuardAttributeDetails } from \"./attributes/guards/Guard\";\nimport { BehaviourTreeOptions } from \"./BehaviourTreeOptions\";\nimport { convertMDSLToJSON } from \"./mdsl/MDSLDefinitionParser\";\nimport { RootNodeDefinition } from \"./BehaviourTreeDefinition\";\nimport { validateDefinition, validateJSONDefinition } from \"./BehaviourTreeDefinitionValidator\";\nimport buildRootNode from \"./BehaviourTreeBuilder\";\nimport { isNullOrUndefined } from \"./BehaviourTreeDefinitionUtilities\";\n\n// Purely for outside inspection of the tree.\nexport type FlattenedTreeNode = {\n id: string;\n type: string;\n caption: string;\n state: AnyState;\n guards: GuardAttributeDetails[];\n callbacks: CallbackAttributeDetails[];\n args: any[];\n parentId: string | null;\n};\n\n/**\n * A representation of a behaviour tree.\n */\nexport class BehaviourTree {\n /**\n * The main root tree node.\n */\n private readonly _rootNode: Root;\n\n /**\n * Creates a new instance of the BehaviourTree class.\n * @param definition The behaviour tree definition as either an MDSL string, root node definition object or array of root node definition objects.\n * @param agent The agent instance that this behaviour tree is modelling behaviour for.\n * @param options The behaviour tree options object.\n */\n constructor(\n definition: string | RootNodeDefinition | RootNodeDefinition[],\n private agent: Agent,\n private options: BehaviourTreeOptions = {}\n ) {\n // The tree definition must be defined.\n if (isNullOrUndefined(definition)) {\n throw new Error(\"tree definition not defined\");\n }\n\n // The agent must be defined and not null.\n if (typeof agent !== \"object\" || agent === null) {\n throw new Error(\"the agent must be an object and not null\");\n }\n\n // We should validate the definition before we try to build the tree nodes.\n const { succeeded, errorMessage, json } = validateDefinition(definition);\n\n // Did our validation fail without error?\n if (!succeeded) {\n throw new Error(`invalid definition: ${errorMessage}`);\n }\n\n // Double check that we did actually get our json definition as part of our definition validtion.\n if (!json) {\n throw new Error(\n \"expected json definition to be returned as part of successful definition validation response\"\n );\n }\n\n try {\n // Create the populated tree of behaviour tree nodes and get the root node.\n this._rootNode = buildRootNode(json);\n } catch (exception) {\n // There was an issue in trying build and populate the behaviour tree.\n throw new Error(`error building tree: ${(exception as Error).message}`);\n }\n }\n\n /**\n * Gets whether the tree is in the RUNNING state.\n * @returns true if the tree is in the RUNNING state, otherwise false.\n */\n isRunning() {\n return this._rootNode.getState() === State.RUNNING;\n }\n\n /**\n * Gets the current tree state of SUCCEEDED, FAILED, READY or RUNNING.\n * @returns The current tree state.\n */\n getState() {\n return this._rootNode.getState();\n }\n\n /**\n * Step the tree.\n * 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.\n * 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\n * 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.\n *\n * 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.\n */\n step() {\n // If the root node has already been stepped to completion then we need to reset it.\n if (this._rootNode.getState() === State.SUCCEEDED || this._rootNode.getState() === State.FAILED) {\n this._rootNode.reset();\n }\n\n try {\n this._rootNode.update(this.agent, this.options);\n } catch (exception) {\n throw new Error(`error stepping tree: ${(exception as Error).message}`);\n }\n }\n\n /**\n * Resets the tree from the root node outwards to each nested node, giving each a state of READY.\n */\n reset() {\n this._rootNode.reset();\n }\n\n /**\n * Gets the flattened details of every node in the tree.\n * @returns The flattened details of every node in the tree.\n */\n getFlattenedNodeDetails(): FlattenedTreeNode[] {\n // Create an empty flattened array of tree nodes.\n const flattenedTreeNodes: FlattenedTreeNode[] = [];\n\n /**\n * Helper function to process a node instance and push details into the flattened tree nodes array.\n * @param node The current node.\n * @param parentUid The UID of the node parent, or null if the node is the main root node.\n */\n const processNode = (node: Node, parentUid: string | null) => {\n // Get the guard and callback attribute details for this node.\n const guards = node\n .getAttributes()\n .filter((attribute) => attribute.isGuard())\n .map((attribute) => attribute.getDetails()) as GuardAttributeDetails[];\n const callbacks = node\n .getAttributes()\n .filter((attribute) => !attribute.isGuard())\n .map((attribute) => attribute.getDetails()) as CallbackAttributeDetails[];\n\n // Push the current node into the flattened nodes array.\n flattenedTreeNodes.push({\n id: node.getUid(),\n type: node.getType(),\n caption: node.getName(),\n state: node.getState(),\n guards,\n callbacks,\n args: node.getArguments(),\n parentId: parentUid\n });\n\n // Process each of the nodes children if it is not a leaf node.\n if (!node.isLeafNode()) {\n (node as Composite | Decorator)\n .getChildren()\n .forEach((child) => processNode(child, (node as Composite | Decorator).getUid()));\n }\n };\n\n // Convert the nested node structure into a flattened array of node details.\n processNode(this._rootNode, null);\n\n return flattenedTreeNodes;\n }\n\n /**\n * Registers the action/condition/guard/callback function or subtree with the given name.\n * @param name The name of the function or subtree to register.\n * @param value The function or subtree definition to register.\n */\n static register(name: string, value: GlobalFunction | string | RootNodeDefinition) {\n // Are we going to register a action/condition/guard/callback function?\n if (typeof value === \"function\") {\n Lookup.setFunc(name, value);\n return;\n }\n\n // We are not registering an action/condition/guard/callback function, so we must be registering a subtree.\n if (typeof value === \"string\") {\n let rootNodeDefinitions: RootNodeDefinition[];\n\n // We will assume that any string passed in will be a mdsl definition.\n try {\n rootNodeDefinitions = convertMDSLToJSON(value);\n } catch (exception) {\n throw new Error(`error registering definition, invalid MDSL: ${(exception as Error).message}`);\n }\n\n // This function should only ever be called with a definition containing a single unnamed root node.\n if (rootNodeDefinitions.length != 1 || rootNodeDefinitions[0].id !== null) {\n throw new Error(\"error registering definition: expected a single unnamed root node\");\n }\n\n try {\n // We should validate the subtree as we don't want invalid subtrees available via the lookup.\n const { succeeded, errorMessage } = validateJSONDefinition(rootNodeDefinitions[0]);\n\n // Did our validation fail without error?\n if (!succeeded) {\n throw new Error(errorMessage);\n }\n } catch (exception) {\n throw new Error(`error registering definition: ${(exception as Error).message}`);\n }\n\n // Everything seems hunky-dory, register the subtree.\n Lookup.setSubtree(name, rootNodeDefinitions[0]);\n } else if (typeof value === \"object\" && !Array.isArray(value)) {\n // We will assume that any object passed in is a root node definition.\n\n try {\n // We should validate the subtree as we don't want invalid subtrees available via the lookup.\n const { succeeded, errorMessage } = validateJSONDefinition(value);\n\n // Did our validation fail without error?\n if (!succeeded) {\n throw new Error(errorMessage);\n }\n } catch (exception) {\n throw new Error(`error registering definition: ${(exception as Error).message}`);\n }\n\n // Everything seems hunky-dory, register the subtree.\n Lookup.setSubtree(name, value);\n } else {\n throw new Error(\"unexpected value, expected string mdsl definition, root node json definition or function\");\n }\n }\n\n /**\n * Unregisters the registered action/condition/guard/callback function or subtree with the given name.\n * @param name The name of the registered action/condition/guard/callback function or subtree to unregister.\n */\n static unregister(name: string): void {\n Lookup.remove(name);\n }\n\n /**\n * Unregister all registered action/condition/guard/callback functions and subtrees.\n */\n static unregisterAll(): void {\n Lookup.empty();\n }\n}\n"], - "mappings": "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", + "sourcesContent": ["\"use strict\";\r\nObject.defineProperty(exports, \"__esModule\", { value: true });\r\nexports.Participant = void 0;\r\n/**\r\n * A participant that holds a number of tickets.\r\n */\r\nvar Participant = /** @class */ (function () {\r\n /**\r\n * Creates an instance of the Participant class.\r\n * @param participant The actual participant.\r\n * @param tickets The number of tickets held by the participant.\r\n */\r\n function Participant(participant, tickets) {\r\n if (tickets === void 0) { tickets = 1; }\r\n this._participant = participant;\r\n this._tickets = tickets;\r\n }\r\n Object.defineProperty(Participant.prototype, \"participant\", {\r\n /** Gets the actual participant. */\r\n get: function () {\r\n return this._participant;\r\n },\r\n enumerable: false,\r\n configurable: true\r\n });\r\n Object.defineProperty(Participant.prototype, \"tickets\", {\r\n /** Gets or sets the number of tickets held by the participant. */\r\n get: function () {\r\n return this._tickets;\r\n },\r\n set: function (value) {\r\n this._tickets = value;\r\n },\r\n enumerable: false,\r\n configurable: true\r\n });\r\n return Participant;\r\n}());\r\nexports.Participant = Participant;\r\n", "\"use strict\";\r\nObject.defineProperty(exports, \"__esModule\", { value: true });\r\nexports.isNaturalNumber = exports.isNullOrUndefined = void 0;\r\n/**\r\n * Gets whether the value provided is null or undefined.\r\n * @param value The value to check.\r\n * @returns Whether the value provided is null or undefined.\r\n */\r\nfunction isNullOrUndefined(value) {\r\n return value === null || value === undefined;\r\n}\r\nexports.isNullOrUndefined = isNullOrUndefined;\r\n/**\r\n * Gets whether the value provided is a natural number.\r\n * @param value The value to check.\r\n * @returns Whether the value provided is a natural number.\r\n */\r\nfunction isNaturalNumber(value) {\r\n return typeof value === \"number\" && value >= 1 && Math.floor(value) === value;\r\n}\r\nexports.isNaturalNumber = isNaturalNumber;\r\n", "\"use strict\";\r\nObject.defineProperty(exports, \"__esModule\", { value: true });\r\nexports.Lotto = void 0;\r\nvar Participant_1 = require(\"./Participant\");\r\nvar Utilities_1 = require(\"./Utilities\");\r\n/**\r\n * Represents a lotto consisting of a number of pickable ticket-holding participants.\r\n */\r\nvar Lotto = /** @class */ (function () {\r\n /**\r\n * Creates a new instance of Lotto.\r\n * @param customRandom The custom RNG to use in place of Math.random().\r\n */\r\n function Lotto(customRandom) {\r\n /** The array of participants that are holding tickets in the lotto. */\r\n this._participants = [];\r\n this._customRandom = customRandom;\r\n }\r\n /**\r\n * Adds a participant with the specified number of tickets, or adds to the participant ticket count if the participant already holds tickets.\r\n * @param participant The participant to add or to increase the ticket count for if they already hold tickets.\r\n * @param tickets The number of tickets, defaults to 1.\r\n * @returns The Lotto instance.\r\n */\r\n Lotto.prototype.add = function (participant, tickets) {\r\n if (tickets === void 0) { tickets = 1; }\r\n // Check that we have a valid ticket count.\r\n if (!(0, Utilities_1.isNaturalNumber)(tickets)) {\r\n throw new Error(\"tickets value must be a natural number\");\r\n }\r\n // Check whether this participant has already been added.\r\n var existingParticipant = this._participants.find(function (part) { return part.participant === participant; });\r\n if (existingParticipant) {\r\n // The participant has already been added to the lotto so just add to their ticket count.\r\n existingParticipant.tickets += tickets;\r\n }\r\n else {\r\n // The participant is not part of the lotto so we should add them.\r\n this._participants.push(new Participant_1.Participant(participant, tickets));\r\n }\r\n return this;\r\n };\r\n /**\r\n * Removes the specified number of tickets for the given participant from the draw, or all tickets if a ticket number is not defined.\r\n * @param participant The participant to remove tickets for.\r\n * @param tickets The number of tickets to remove, or undefined if all tickets are to be removed.\r\n * @returns The Lotto instance.\r\n */\r\n Lotto.prototype.remove = function (participant, tickets) {\r\n // Attempt to get the existing participant.\r\n var existingParticipant = this._participants.find(function (part) { return part.participant === participant; });\r\n // There is nothing to do if the specified participant isn't even part of the lotto.\r\n if (!existingParticipant) {\r\n return this;\r\n }\r\n // Check whether a tickets value was given.\r\n if (tickets !== undefined) {\r\n // Check that we have a valid ticket count.\r\n if (!(0, Utilities_1.isNaturalNumber)(tickets)) {\r\n throw new Error(\"tickets value must be a natural number\");\r\n }\r\n existingParticipant.tickets -= tickets;\r\n // If the participant no longer holds any tickets then they should be removed.\r\n if (existingParticipant.tickets < 1) {\r\n this._participants = this._participants.filter(function (part) { return part !== existingParticipant; });\r\n }\r\n }\r\n else {\r\n // We are removing all tickets for the participant so just remove them from the lotto.\r\n this._participants = this._participants.filter(function (part) { return part !== existingParticipant; });\r\n }\r\n return this;\r\n };\r\n /**\r\n * Draw a winning ticket and return the participant that holds the ticket.\r\n * @param options The draw options.\r\n * @returns The participant that holds the winning ticket.\r\n */\r\n Lotto.prototype.draw = function (options) {\r\n if (options === void 0) { options = {}; }\r\n // If we have no participants then just return null.\r\n if (this._participants.length === 0) {\r\n return null;\r\n }\r\n var redrawable = (0, Utilities_1.isNullOrUndefined)(options.redrawable) ? true : options.redrawable;\r\n var pickable = [];\r\n this._participants.forEach(function (_a) {\r\n var participant = _a.participant, tickets = _a.tickets;\r\n for (var ticketCount = 0; ticketCount < tickets; ticketCount++) {\r\n pickable.push(participant);\r\n }\r\n });\r\n var random;\r\n // We need a random floating-point number between 0 (inclusive) and 1 to scale up to pick our winner.\r\n // If a custom random function exists then we should use that or fall back to Math.random().\r\n if (this._customRandom) {\r\n // Call our custom random function to get a random floating-point number.\r\n random = this._customRandom();\r\n // Verify that the result of calling our custom random function is a number between 0 (inclusive) and 1.\r\n if (typeof random !== \"number\" || random < 0 || random >= 1) {\r\n throw new Error(\"the 'random' function provided did not return a number between 0 (inclusive) and 1\");\r\n }\r\n }\r\n else {\r\n // No custom random function was defined so just use good ol' Math.random().\r\n random = Math.random();\r\n }\r\n // Pick a winning participant.\r\n var winner = pickable[Math.floor(random * pickable.length)];\r\n // If the ticket isn't redrawable then we should remove a ticket from the winning participants ticket count.\r\n if (!redrawable) {\r\n this.remove(winner, 1);\r\n }\r\n // Return the winning participant.\r\n return winner;\r\n };\r\n /**\r\n * Draws multiple winning tickets and return an array of the participants that hold the winning tickets.\r\n * @param tickets The number of winning tickets to draw.\r\n * @param options The draw multiple options.\r\n * @returns An array of the participants that hold the winning tickets.\r\n */\r\n Lotto.prototype.drawMultiple = function (tickets, options) {\r\n if (options === void 0) { options = {}; }\r\n var uniqueResults = (0, Utilities_1.isNullOrUndefined)(options.unique) ? false : options.unique;\r\n // Handle cases where the user has asked for zero tickets (no idea why they would do this be we should trust them).\r\n if (tickets === 0) {\r\n return [];\r\n }\r\n // Now that we know out tickets value is not zero we should check that it is a valid natural number.\r\n if (!(0, Utilities_1.isNaturalNumber)(tickets)) {\r\n throw new Error(\"tickets value must be a natural number\");\r\n }\r\n var result = [];\r\n // Keep drawing tickets until we either reach the number of required tickets or we simply run out of tickets to draw.\r\n // We can run out of tickets to draw if 'options.redrawable' is explicity 'false' or we just had no participants when 'drawMultiple' was called.\r\n while (result.length < tickets && this._participants.length > 0) {\r\n result.push(this.draw(options));\r\n }\r\n // If the 'unique' draw option is set then we need to remove duplicates from the result list.\r\n if (uniqueResults) {\r\n // Create an array to store our unique results.\r\n var unique = [];\r\n // Iterate over all of our participants (with potential duplicates) and populate our array of unique values.\r\n for (var _i = 0, result_1 = result; _i < result_1.length; _i++) {\r\n var participant = result_1[_i];\r\n if (unique.indexOf(participant) === -1) {\r\n unique.push(participant);\r\n }\r\n }\r\n result = unique;\r\n }\r\n return result;\r\n };\r\n return Lotto;\r\n}());\r\nexports.Lotto = Lotto;\r\n", "\"use strict\";\r\nObject.defineProperty(exports, \"__esModule\", { value: true });\r\nexports.createLotto = void 0;\r\nvar Lotto_1 = require(\"./Lotto\");\r\n/**\r\n * A function that creates and returns a Lotto instance.\r\n * @param participantsOrOptions An array of initial participants or options relating to the creation of a Lotto instance.\r\n * @returns A new Lotto instance.\r\n */\r\nfunction createLotto(participantsOrOptions) {\r\n // If no initial participants or lotto options were provided as an argument then we can just return a new lotto instance now.\r\n if (!participantsOrOptions) {\r\n return new Lotto_1.Lotto();\r\n }\r\n // Check whether we were provided with an array of initial participants or a lotto options object.\r\n if (Array.isArray(participantsOrOptions)) {\r\n // We are dealing with a pre-defined array of participants.\r\n var participants = participantsOrOptions;\r\n var lotto_1 = new Lotto_1.Lotto();\r\n // If the lotto participants have been defined upfront then we will need to add them all to our lotto instance now.\r\n participants.forEach(function (_a) {\r\n var participant = _a[0], tokens = _a[1];\r\n return lotto_1.add(participant, tokens);\r\n });\r\n // Return the Lotto instance.\r\n return lotto_1;\r\n }\r\n else {\r\n // We are dealing with some lotto options.\r\n var random = participantsOrOptions.random, participants = participantsOrOptions.participants;\r\n // Create a Lotto instance passing the custom RNG function to use in place of Math.random() (which could be undefined).\r\n var lotto_2 = new Lotto_1.Lotto(random);\r\n // If the lotto participants have been defined upfront as part of the options then we will need to add them all to our lotto instance now.\r\n if (participants) {\r\n participants.forEach(function (_a) {\r\n var participant = _a[0], tokens = _a[1];\r\n return lotto_2.add(participant, tokens);\r\n });\r\n }\r\n // Return the Lotto instance.\r\n return lotto_2;\r\n }\r\n}\r\nexports.createLotto = createLotto;\r\n", "\"use strict\";\r\nObject.defineProperty(exports, \"__esModule\", { value: true });\r\nvar createLotto_1 = require(\"./createLotto\");\r\nexports.default = createLotto_1.createLotto;\r\n", "import State from \"./State\";\nimport { validateDefinition } from \"./BehaviourTreeDefinitionValidator\";\nimport { convertMDSLToJSON } from \"./mdsl/MDSLDefinitionParser\";\nimport { BehaviourTree, FlattenedTreeNode } from \"./BehaviourTree\";\nimport { BehaviourTreeOptions } from \"./BehaviourTreeOptions\";\n\nexport { BehaviourTree, State, convertMDSLToJSON, validateDefinition };\nexport type { FlattenedTreeNode, BehaviourTreeOptions };\n", "/**\n * Enumeration of node state types.\n */\nexport enum State {\n READY = \"mistreevous.ready\",\n RUNNING = \"mistreevous.running\",\n SUCCEEDED = \"mistreevous.succeeded\",\n FAILED = \"mistreevous.failed\"\n}\n\nexport { State as default };\n\nexport type CompleteState = State.SUCCEEDED | State.FAILED;\nexport type AnyState = State.READY | State.RUNNING | CompleteState;\n", "import {\n NodeDefinition,\n RootNodeDefinition,\n DecoratorNodeDefinition,\n CompositeNodeDefinition,\n AnyNodeDefinition,\n BranchNodeDefinition\n} from \"./BehaviourTreeDefinition\";\n\n/**\n * A type guard function that returns true if the specified node satisfies the RootNodeDefinition type.\n * @param node The node.\n * @returns A value of true if the specified node satisfies the RootNodeDefinition type.\n */\nexport function isRootNode(node: NodeDefinition): node is RootNodeDefinition {\n return node.type === \"root\";\n}\n\n/**\n * A type guard function that returns true if the specified node satisfies the BranchNodeDefinition type.\n * @param node The node.\n * @returns A value of true if the specified node satisfies the BranchNodeDefinition type.\n */\nexport function isBranchNode(node: NodeDefinition): node is BranchNodeDefinition {\n return node.type === \"branch\";\n}\n\n/**\n * A type guard function that returns true if the specified node satisfies the NodeDefinition type.\n * @param node The node.\n * @returns A value of true if the specified node satisfies the NodeDefinition type.\n */\nexport function isLeafNode(node: NodeDefinition): node is NodeDefinition {\n return [\"branch\", \"action\", \"condition\", \"wait\"].includes(node.type);\n}\n\n/**\n * A type guard function that returns true if the specified node satisfies the DecoratorNodeDefinition type.\n * @param node The node.\n * @returns A value of true if the specified node satisfies the DecoratorNodeDefinition type.\n */\nexport function isDecoratorNode(node: NodeDefinition): node is DecoratorNodeDefinition {\n return [\"root\", \"repeat\", \"retry\", \"flip\", \"succeed\", \"fail\"].includes(node.type);\n}\n\n/**\n * A type guard function that returns true if the specified node satisfies the CompositeNodeDefinition type.\n * @param node The node.\n * @returns A value of true if the specified node satisfies the CompositeNodeDefinition type.\n */\nexport function isCompositeNode(node: NodeDefinition): node is CompositeNodeDefinition {\n return [\"sequence\", \"selector\", \"lotto\", \"parallel\"].includes(node.type);\n}\n\n/**\n * Flatten a node definition into an array of all of its nested node definitions.\n * @param nodeDefinition The node definition to flatten.\n * @returns An array of all of nested node definitions.\n */\nexport function flattenDefinition(nodeDefinition: AnyNodeDefinition): AnyNodeDefinition[] {\n const nodes: AnyNodeDefinition[] = [];\n\n const processNode = (currentNodeDefinition: AnyNodeDefinition) => {\n nodes.push(currentNodeDefinition);\n\n if (isCompositeNode(currentNodeDefinition)) {\n currentNodeDefinition.children.forEach(processNode);\n } else if (isDecoratorNode(currentNodeDefinition)) {\n processNode(currentNodeDefinition.child);\n }\n };\n\n processNode(nodeDefinition);\n\n return nodes;\n}\n\n/**\n * Determines whether the passed value is an integer.\n * @param value The value to check.\n * @returns Whether the passed value is an integer.\n */\nexport function isInteger(value: unknown): boolean {\n return typeof value === \"number\" && Math.floor(value) === value;\n}\n\n/**\n * Determines whether the passed value is null or undefined.\n * @param value The value to check.\n * @returns Whether the passed value is null or undefined.\n */\nexport function isNullOrUndefined(value: unknown): boolean {\n return typeof value === \"undefined\" || value === null;\n}\n", "/**\n * A type defining an object that holds a reference to substitued string literals parsed from the definition.\n */\nexport type StringLiteralPlaceholders = { [key: string]: string };\n\n/**\n * Pop the next raw token from the specified array of tokens and throw an error if it wasn't the expected one.\n * @param tokens The array of tokens.\n * @param expected An optional string or array or items, one of which must match the next popped token.\n * @returns The popped token.\n */\nexport function popAndCheck(tokens: string[], expected?: string | string[]): string {\n // Get and remove the next token.\n const popped = tokens.shift();\n\n // We were expecting another token but there aren't any.\n if (popped === undefined) {\n throw new Error(\"unexpected end of definition\");\n }\n\n // Do we have an expected token/tokens array?\n if (expected != undefined) {\n // Get an array of expected values, if the popped token matches any then we are all good.\n const expectedValues = typeof expected === \"string\" ? [expected] : expected;\n\n // Check whether the popped token matches at least one of our expected items.\n var tokenMatchesExpectation = expectedValues.some((item) => popped.toUpperCase() === item.toUpperCase());\n\n // Throw an error if the popped token didn't match any of our expected items.\n if (!tokenMatchesExpectation) {\n const expectationString = expectedValues.map((item) => \"'\" + item + \"'\").join(\" or \");\n throw new Error(\"unexpected token found. Expected \" + expectationString + \" but got '\" + popped + \"'\");\n }\n }\n\n // Return the popped token.\n return popped;\n}\n\n/**\n * Swaps out any node/attribute argument string literals with placeholders.\n * @param definition The definition.\n * @returns An object containing a mapping of placeholders to original string values as well as the processed definition string.\n */\nexport function substituteStringLiterals(definition: string): {\n placeholders: StringLiteralPlaceholders;\n processedDefinition: string;\n} {\n // Create an object to hold the mapping of placeholders to original string values.\n const placeholders: StringLiteralPlaceholders = {};\n\n // Replace any string literals wrapped with double quotes in our definition with placeholders to be processed later.\n const processedDefinition = definition.replace(/\\\"(\\\\.|[^\"\\\\])*\\\"/g, (match) => {\n var strippedMatch = match.substring(1, match.length - 1);\n var placeholder = Object.keys(placeholders).find((key) => placeholders[key] === strippedMatch);\n\n // If we have no existing string literal match then create a new placeholder.\n if (!placeholder) {\n placeholder = `@@${Object.keys(placeholders).length}@@`;\n placeholders[placeholder] = strippedMatch;\n }\n\n return placeholder;\n });\n\n return { placeholders, processedDefinition };\n}\n\n/**\n * Parse the tree definition into an array of raw tokens.\n * @param definition The definition.\n * @returns An array of tokens parsed from the definition.\n */\nexport function parseTokensFromDefinition(definition: string): string[] {\n // Add some space around various important characters so that they can be plucked out easier as individual tokens.\n definition = definition.replace(/\\(/g, \" ( \");\n definition = definition.replace(/\\)/g, \" ) \");\n definition = definition.replace(/\\{/g, \" { \");\n definition = definition.replace(/\\}/g, \" } \");\n definition = definition.replace(/\\]/g, \" ] \");\n definition = definition.replace(/\\[/g, \" [ \");\n definition = definition.replace(/\\,/g, \" , \");\n\n // Split the definition into raw token form and return it.\n return definition.replace(/\\s+/g, \" \").trim().split(\" \");\n}\n", "import { StringLiteralPlaceholders, popAndCheck } from \"./MDSLUtilities\";\n\n/**\n * A type representing any node function argument.\n */\ntype Argument = {\n /**\n * The argument value.\n */\n value: T;\n /**\n * The argument type, used for validation.\n */\n type: string;\n};\n\ntype NullArgument = Argument & {\n type: \"null\";\n};\n\ntype BooleanArgument = Argument & {\n type: \"boolean\";\n};\n\ntype NumberArgument = Argument & {\n type: \"number\";\n /**\n * A flag defining whether the number argument value is a valid integer. (used for validation)\n */\n isInteger: boolean;\n};\n\ntype StringPlaceholderArgument = Argument & {\n type: \"string\";\n};\n\ntype IdentifierArgument = Argument & {\n type: \"identifier\";\n};\n\n/**\n * A type representing a reference to any node function argument.\n */\ntype AnyArgument = NullArgument | BooleanArgument | NumberArgument | StringPlaceholderArgument | IdentifierArgument;\n\n/**\n * Parse an array of argument definitions from the specified tokens array.\n * @param tokens The array tokens to parse the argument definitions from.\n * @param stringArgumentPlaceholders The mapping of string literal node argument placeholders to original values.\n * @param argumentValidator The argument validator function.\n * @param validationFailedMessage The exception message to throw if argument validation fails.\n * @returns An array of argument definitions parsed from the specified tokens array.\n */\nexport function parseArgumentTokens(\n tokens: string[],\n stringArgumentPlaceholders: StringLiteralPlaceholders\n): AnyArgument[] {\n const argumentList: AnyArgument[] = [];\n\n // If the next token is not a '[' or '(' then we have no arguments to parse.\n if (![\"[\", \"(\"].includes(tokens[0])) {\n return argumentList;\n }\n\n // Any lists of arguments will always be wrapped in '[]' for node arguments or '()' for attribute arguments.\n // We are looking for a '[' or '(' opener that wraps the argument tokens and the relevant closer.\n const closingToken = popAndCheck(tokens, [\"[\", \"(\"]) === \"[\" ? \"]\" : \")\";\n\n const argumentListTokens: string[] = [];\n\n // Grab all tokens between the '[' and ']' or '(' and ')'.\n while (tokens.length && tokens[0] !== closingToken) {\n // The next token is part of our arguments list.\n argumentListTokens.push(tokens.shift()!);\n }\n\n // Validate the order of the argument tokens. Each token must either be a ',' or a single argument that satisfies the validator.\n argumentListTokens.forEach((token, index) => {\n // Get whether this token should be an actual argument.\n const shouldBeArgumentToken = !(index & 1);\n\n // If the current token should be an actual argument then validate it, otherwise it should be a ',' token.\n if (shouldBeArgumentToken) {\n // Get the argument definition.\n const argumentDefinition = getArgumentDefinition(token, stringArgumentPlaceholders);\n\n // This is a valid argument!\n argumentList.push(argumentDefinition);\n } else {\n // The current token should be a ',' token.\n if (token !== \",\") {\n throw new Error(`invalid argument list, expected ',' or ']' but got '${token}'`);\n }\n }\n });\n\n // The arguments list should terminate with a ']' or ')' token, depending on the opener.\n popAndCheck(tokens, closingToken);\n\n // Return the arguments.\n return argumentList;\n}\n\n/**\n * Gets an argument value definition.\n * @param token The argument token.\n * @param stringArgumentPlaceholders The mapping of string literal node argument placeholders to original values.\n * @returns An argument value definition.\n */\nfunction getArgumentDefinition(token: string, stringArgumentPlaceholders: StringLiteralPlaceholders): AnyArgument {\n // Check whether the token represents a null value.\n if (token === \"null\") {\n return {\n value: null,\n type: \"null\"\n } as NullArgument;\n }\n\n // Check whether the token represents a boolean value.\n if (token === \"true\" || token === \"false\") {\n return {\n value: token === \"true\",\n type: \"boolean\"\n } as BooleanArgument;\n }\n\n // Check whether the token represents a number value.\n // TODO: Relies on broken isNaN - see MDN.\n // if (!Number.isNaN(token)) {\n if (!isNaN(token as any)) {\n return {\n value: parseFloat(token),\n isInteger: parseFloat(token) === parseInt(token, 10),\n type: \"number\"\n } as NumberArgument;\n }\n\n // Check whether the token is a placeholder (e.g. @@0@@) representing a string literal.\n if (token.match(/^@@\\d+@@$/g)) {\n return {\n value: stringArgumentPlaceholders[token].replace('\\\\\"', '\"'),\n type: \"string\"\n } as StringPlaceholderArgument;\n }\n\n // The only remaining option is that the argument value is an identifier.\n return {\n value: token,\n type: \"identifier\"\n } as IdentifierArgument;\n}\n", "import { NodeAttributeDefinition } from \"../BehaviourTreeDefinition\";\nimport { parseArgumentTokens } from \"./MDSLNodeArgumentParser\";\nimport { StringLiteralPlaceholders } from \"./MDSLUtilities\";\n\n/**\n * A type defining the attribute definitions of a node.\n */\ntype NodeAttributes = {\n while?: NodeAttributeDefinition;\n until?: NodeAttributeDefinition;\n entry?: NodeAttributeDefinition;\n exit?: NodeAttributeDefinition;\n step?: NodeAttributeDefinition;\n};\n\n/**\n * Parse any node attribute definitions from the specified tokens array.\n * @param tokens The array of remaining tokens.\n * @param stringArgumentPlaceholders The mapping of string literal node argument placeholders to original values.\n * @returns An object of attribute definitions defined by any directly following tokens.\n */\nexport function parseAttributeTokens(\n tokens: string[],\n stringArgumentPlaceholders: StringLiteralPlaceholders\n): NodeAttributes {\n const nodeAttributeNames: (keyof NodeAttributes)[] = [\"while\", \"until\", \"entry\", \"exit\", \"step\"];\n\n // Create an object to hold any attributes found.\n const attributes: NodeAttributes = {};\n\n // Try to get the name of the attribute for the next token.\n let nextAttributeName = tokens[0]?.toLowerCase() as keyof NodeAttributes;\n\n // Pull attribute tokens as well as their arguments off of the tokens stack until we have no more.\n while (nodeAttributeNames.includes(nextAttributeName)) {\n // Check to make sure that we have not already created an attribute definition of this type.\n if (attributes[nextAttributeName]) {\n throw new Error(`duplicate attribute '${tokens[0].toUpperCase()}' found for node`);\n }\n\n // Remove the attribute name token from the array of tokens.\n tokens.shift();\n\n // Grab the attribute arguments, assuming the first to be an identifier.\n const [attributeCallIdentifier, ...attributeArguments] = parseArgumentTokens(\n tokens,\n stringArgumentPlaceholders\n );\n\n // The first attribute argument has to be an identifer, this will reference an agent function.\n if (attributeCallIdentifier?.type !== \"identifier\") {\n throw new Error(\"expected agent function or registered function name identifier argument for attribute\");\n }\n\n // Any attribute arguments (other than the expected call identifier) must have a type of string, number, boolean or null.\n attributeArguments\n .filter((arg) => arg.type === \"identifier\")\n .forEach((arg) => {\n throw new Error(\n `invalid attribute argument value '${arg.value}', must be string, number, boolean or null`\n );\n });\n\n // Create the attribute definition and add it to the object of attribute definitions found.\n attributes[nextAttributeName] = {\n call: attributeCallIdentifier.value,\n args: attributeArguments.map(({ value }) => value)\n };\n\n // Try to get the next attribute name token, as there could be multiple.\n nextAttributeName = tokens[0]?.toLowerCase() as keyof NodeAttributes;\n }\n\n return attributes;\n}\n", "import {\n ActionNodeDefinition,\n AnyChildNodeDefinition,\n AnyNodeDefinition,\n BranchNodeDefinition,\n ConditionNodeDefinition,\n FailNodeDefinition,\n FlipNodeDefinition,\n LottoNodeDefinition,\n ParallelNodeDefinition,\n RepeatNodeDefinition,\n RetryNodeDefinition,\n RootNodeDefinition,\n SelectorNodeDefinition,\n SequenceNodeDefinition,\n SucceedNodeDefinition,\n WaitNodeDefinition\n} from \"../BehaviourTreeDefinition\";\nimport {\n isCompositeNode,\n isDecoratorNode,\n isLeafNode,\n isNullOrUndefined,\n isRootNode\n} from \"../BehaviourTreeDefinitionUtilities\";\nimport { parseArgumentTokens } from \"./MDSLNodeArgumentParser\";\nimport { parseAttributeTokens } from \"./MDSLNodeAttributeParser\";\nimport {\n StringLiteralPlaceholders,\n parseTokensFromDefinition,\n popAndCheck,\n substituteStringLiterals\n} from \"./MDSLUtilities\";\n\n/**\n * Convert the MDSL tree definition string into an equivalent JSON definition.\n * @param definition The tree definition string as MDSL.\n * @returns The root node JSON definitions.\n */\nexport function convertMDSLToJSON(definition: string): RootNodeDefinition[] {\n // Swap out any node/attribute argument string literals with a placeholder and get a mapping of placeholders to original values as well as the processed definition.\n const { placeholders, processedDefinition } = substituteStringLiterals(definition);\n\n // Parse our definition definition string into an array of raw tokens.\n const tokens = parseTokensFromDefinition(processedDefinition);\n\n return convertTokensToJSONDefinition(tokens, placeholders);\n}\n\n/**\n * Converts the specified tree definition tokens into a JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The root node JSON definitions.\n */\nfunction convertTokensToJSONDefinition(\n tokens: string[],\n stringLiteralPlaceholders: StringLiteralPlaceholders\n): RootNodeDefinition[] {\n // There must be at least 3 tokens for the tree definition to be valid. 'ROOT', '{' and '}'.\n if (tokens.length < 3) {\n throw new Error(\"invalid token count\");\n }\n\n // We should have a matching number of '{' and '}' tokens. If not, then there are scopes that have not been properly closed.\n if (tokens.filter((token) => token === \"{\").length !== tokens.filter((token) => token === \"}\").length) {\n throw new Error(\"scope character mismatch\");\n }\n\n // Create an array of tree stack arrays where root nodes will always be at the botton and the current composite/decorator node at the top.\n // There should be an element in this array for every root node defined and every element should be an array with a root note as the first element.\n // E.g. A definition with two root nodes defined:\n // [\n // [root, lotto, sequence],\n // [root, selector]\n // ]\n const treeStacks: [Partial, ...Partial[]][] = [];\n\n // Create an array of all root node definitions that we create.\n const rootNodes: Partial[] = [];\n\n // A helper function used to push node definitions onto the tree stack.\n const pushNode = (node: AnyNodeDefinition) => {\n // If the node is a root node then we need to create a new tree stack array with the root node at the root.\n if (isRootNode(node)) {\n // We need to double-check that this root node is not the child of another node.\n // We can do this by checking whether the top tree stack is not empty (contains an existing node)\n if (treeStacks[treeStacks.length - 1]?.length) {\n throw new Error(\"a root node cannot be the child of another node\");\n }\n\n // Add the root node definition to our array of all parsed root node definitions.\n rootNodes.push(node);\n\n // Add the root node definition to the root of a new tree stack.\n treeStacks.push([node]);\n\n return;\n }\n\n // All non-root nodes should be pushed after their root nodes so handle cases\n // where we may not have any tree stacks or our top-most tree stack is empty.\n if (!treeStacks.length || !treeStacks[treeStacks.length - 1].length) {\n throw new Error(\"expected root node at base of definition\");\n }\n\n // Get the current tree stack that we are populating.\n const topTreeStack = treeStacks[treeStacks.length - 1];\n\n // Get the top-most node in the current tree stack, this will be a composite/decorator node\n // for which we will populate its children array if composite or setting its child if a decorator.\n const topTreeStackTopNode = topTreeStack[topTreeStack.length - 1] as AnyNodeDefinition;\n\n // If the top-most node in the current root stack is a composite or decorator\n // node then the current node should be added as a child of the top-most node.\n if (isCompositeNode(topTreeStackTopNode)) {\n topTreeStackTopNode.children = topTreeStackTopNode.children || [];\n topTreeStackTopNode.children.push(node);\n } else if (isDecoratorNode(topTreeStackTopNode)) {\n // If the top node already has a child node set then throw an error as a decorator should only have a single child.\n if (topTreeStackTopNode.child) {\n throw new Error(\"a decorator node must only have a single child node\");\n }\n\n topTreeStackTopNode.child = node;\n }\n\n // If the node we are adding is also a composite or decorator node, then we should push it\n // onto the current tree stack, as subsequent nodes will be added as its child/children.\n if (!isLeafNode(node)) {\n topTreeStack.push(node);\n }\n };\n\n // A helper function used to pop the top-most node definition off of the tree stack and return it.\n const popNode = (): AnyNodeDefinition | null => {\n let poppedNode: AnyNodeDefinition | null = null;\n\n // Get the current tree stack that we are populating.\n const topTreeStack = treeStacks[treeStacks.length - 1];\n\n // Pop the top-most node in the current tree stack if there is one.\n if (topTreeStack.length) {\n poppedNode = topTreeStack.pop() as AnyNodeDefinition;\n }\n\n // We don't want any empty tree stacks in our stack of tree stacks.\n if (!topTreeStack.length) {\n treeStacks.pop();\n }\n\n return poppedNode;\n };\n\n // We should keep processing the raw tokens until we run out of them.\n while (tokens.length) {\n // Grab the next token.\n const token = tokens.shift()!;\n\n // How we create the next node depends on the current raw token value.\n switch (token.toUpperCase()) {\n case \"ROOT\": {\n pushNode(createRootNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"SUCCEED\": {\n pushNode(createSucceedNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"FAIL\": {\n pushNode(createFailNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"FLIP\": {\n pushNode(createFlipNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"REPEAT\": {\n pushNode(createRepeatNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"RETRY\": {\n pushNode(createRetryNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"SEQUENCE\": {\n pushNode(createSequenceNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"SELECTOR\": {\n pushNode(createSelectorNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"PARALLEL\": {\n pushNode(createParallelNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"LOTTO\": {\n pushNode(createLottoNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"ACTION\": {\n pushNode(createActionNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"CONDITION\": {\n pushNode(createConditionNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"WAIT\": {\n pushNode(createWaitNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"BRANCH\": {\n pushNode(createBranchNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"}\": {\n // The '}' character closes the current scope and means that we have to pop a node off of the current stack.\n const poppedNode = popNode();\n\n // Now that we have a node definition we can carry out any validation that may require the node to be fully populated.\n if (poppedNode) {\n validatePoppedNode(poppedNode);\n }\n\n break;\n }\n\n default: {\n throw new Error(`unexpected token: ${token}`);\n }\n }\n }\n\n return rootNodes as RootNodeDefinition[];\n}\n\n/**\n * Creates a root node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The root node JSON definition.\n */\nfunction createRootNode(tokens: string[], stringLiteralPlaceholders: StringLiteralPlaceholders): RootNodeDefinition {\n // Create the root node definition.\n let node = {\n type: \"root\"\n } as Partial;\n\n // Parse any node arguments, we should only have one if any which will be an identifier argument for the root identifier.\n const nodeArguments = parseArgumentTokens(tokens, stringLiteralPlaceholders);\n\n // Check whether any node arguments were defined.\n if (nodeArguments.length) {\n // We should only have one argument, if any, which will be an identifier argument for the root identifier.\n if (nodeArguments.length === 1 && nodeArguments[0].type === \"identifier\") {\n // The root node identifier will be the first and only node argument value.\n node.id = nodeArguments[0].value as string;\n } else {\n throw new Error(\"expected single root name argument\");\n }\n }\n\n // Grab any node attribute definitions and spread them into the node definition.\n node = { ...node, ...parseAttributeTokens(tokens, stringLiteralPlaceholders) };\n\n // This is a decorator node, so we expect an opening '{'.\n popAndCheck(tokens, \"{\");\n\n // Return the root node definition.\n return node as RootNodeDefinition;\n}\n\n/**\n * Creates a succeed node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The succeed node JSON definition.\n */\nfunction createSucceedNode(\n tokens: string[],\n stringLiteralPlaceholders: StringLiteralPlaceholders\n): SucceedNodeDefinition {\n const node = {\n type: \"succeed\",\n ...parseAttributeTokens(tokens, stringLiteralPlaceholders)\n } as SucceedNodeDefinition;\n\n // This is a decorator node, so we expect an opening '{'.\n popAndCheck(tokens, \"{\");\n\n // Return the succeed node definition.\n return node;\n}\n\n/**\n * Creates a fail node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The fail node JSON definition.\n */\nfunction createFailNode(tokens: string[], stringLiteralPlaceholders: StringLiteralPlaceholders): FailNodeDefinition {\n const node = {\n type: \"fail\",\n ...parseAttributeTokens(tokens, stringLiteralPlaceholders)\n } as FailNodeDefinition;\n\n // This is a decorator node, so we expect an opening '{'.\n popAndCheck(tokens, \"{\");\n\n // Return the fail node definition.\n return node;\n}\n\n/**\n * Creates a flip node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The flip node JSON definition.\n */\nfunction createFlipNode(tokens: string[], stringLiteralPlaceholders: StringLiteralPlaceholders): FlipNodeDefinition {\n const node = {\n type: \"flip\",\n ...parseAttributeTokens(tokens, stringLiteralPlaceholders)\n } as FlipNodeDefinition;\n\n // This is a decorator node, so we expect an opening '{'.\n popAndCheck(tokens, \"{\");\n\n // Return the flip node definition.\n return node;\n}\n\n/**\n * Creates a repeat node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The repeat node JSON definition.\n */\nfunction createRepeatNode(\n tokens: string[],\n stringLiteralPlaceholders: StringLiteralPlaceholders\n): RepeatNodeDefinition {\n let node = { type: \"repeat\" } as RepeatNodeDefinition;\n\n // Get the node arguments.\n const nodeArguments = parseArgumentTokens(tokens, stringLiteralPlaceholders);\n\n // The arguments of a repeat node are optional. We may have:\n // - No node arguments, in which case the repeat note will iterate indefinitely.\n // - One node argument which will be the explicit number of iterations to make.\n // - Two node arguments which define the min and max iteration bounds from which a random iteration count will be picked.\n if (nodeArguments.length) {\n // All repeat node arguments MUST be of type number and must be integer.\n nodeArguments\n .filter((arg) => arg.type !== \"number\" || !arg.isInteger)\n .forEach(() => {\n throw new Error(`repeat node iteration counts must be integer values`);\n });\n\n // We should have got one or two iteration counts.\n if (nodeArguments.length === 1) {\n // A static iteration count was defined.\n node.iterations = nodeArguments[0].value as number;\n\n // A repeat node must have a positive number of iterations if defined.\n if (node.iterations < 0) {\n throw new Error(\"a repeat node must have a positive number of iterations if defined\");\n }\n } else if (nodeArguments.length === 2) {\n // A minimum and maximum iteration count was defined.\n node.iterations = [nodeArguments[0].value as number, nodeArguments[1].value as number];\n\n // A repeat node must have a positive min and max iteration count if they are defined.\n if (node.iterations[0] < 0 || node.iterations[1] < 0) {\n throw new Error(\"a repeat node must have a positive minimum and maximum iteration count if defined\");\n }\n\n // A repeat node must not have an minimum iteration count that exceeds the maximum iteration count.\n if (node.iterations[0] > node.iterations[1]) {\n throw new Error(\n \"a repeat node must not have a minimum iteration count that exceeds the maximum iteration count\"\n );\n }\n } else {\n // An incorrect number of iteration counts was defined.\n throw new Error(\"invalid number of repeat node iteration count arguments defined\");\n }\n }\n\n // Grab any node attribute definitions and spread them into the node definition.\n node = { ...node, ...parseAttributeTokens(tokens, stringLiteralPlaceholders) };\n\n // This is a decorator node, so we expect an opening '{'.\n popAndCheck(tokens, \"{\");\n\n // Return the repeat node definition.\n return node;\n}\n\n/**\n * Creates a retry node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The retry node JSON definition.\n */\nfunction createRetryNode(tokens: string[], stringLiteralPlaceholders: StringLiteralPlaceholders): RetryNodeDefinition {\n let node = { type: \"retry\" } as RetryNodeDefinition;\n\n // Get the node arguments.\n const nodeArguments = parseArgumentTokens(tokens, stringLiteralPlaceholders);\n\n // The arguments of a retry node are optional. We may have:\n // - No node arguments, in which case the retry note will attempt indefinitely.\n // - One node argument which will be the explicit number of attempts to make.\n // - Two node arguments which define the min and max attempt bounds from which a random attempt count will be picked.\n if (nodeArguments.length) {\n // All retry node arguments MUST be of type number and must be integer.\n nodeArguments\n .filter((arg) => arg.type !== \"number\" || !arg.isInteger)\n .forEach(() => {\n throw new Error(`retry node attempt counts must be integer values`);\n });\n\n // We should have got one or two attempt counts.\n if (nodeArguments.length === 1) {\n // A static attempt count was defined.\n node.attempts = nodeArguments[0].value as number;\n\n // A retry node must have a positive number of attempts if defined.\n if (node.attempts < 0) {\n throw new Error(\"a retry node must have a positive number of attempts if defined\");\n }\n } else if (nodeArguments.length === 2) {\n // A minimum and maximum attempt count was defined.\n node.attempts = [nodeArguments[0].value as number, nodeArguments[1].value as number];\n\n // A retry node must have a positive min and max attempts count if they are defined.\n if (node.attempts[0] < 0 || node.attempts[1] < 0) {\n throw new Error(\"a retry node must have a positive minimum and maximum attempt count if defined\");\n }\n\n // A retry node must not have a minimum attempt count that exceeds the maximum attempt count.\n if (node.attempts[0] > node.attempts[1]) {\n throw new Error(\n \"a retry node must not have a minimum attempt count that exceeds the maximum attempt count\"\n );\n }\n } else {\n // An incorrect number of attempt counts was defined.\n throw new Error(\"invalid number of retry node attempt count arguments defined\");\n }\n }\n\n // Grab any node attribute definitions and spread them into the node definition.\n node = { ...node, ...parseAttributeTokens(tokens, stringLiteralPlaceholders) };\n\n // This is a decorator node, so we expect an opening '{'.\n popAndCheck(tokens, \"{\");\n\n // Return the retry node definition.\n return node;\n}\n\n/**\n * Creates a sequence node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The sequence node JSON definition.\n */\nfunction createSequenceNode(\n tokens: string[],\n stringLiteralPlaceholders: StringLiteralPlaceholders\n): SequenceNodeDefinition {\n const node = {\n type: \"sequence\",\n ...parseAttributeTokens(tokens, stringLiteralPlaceholders)\n } as SequenceNodeDefinition;\n\n // This is a composite node, so we expect an opening '{'.\n popAndCheck(tokens, \"{\");\n\n // Return the sequence node definition.\n return node;\n}\n\n/**\n * Creates a selector node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The selector node JSON definition.\n */\nfunction createSelectorNode(\n tokens: string[],\n stringLiteralPlaceholders: StringLiteralPlaceholders\n): SelectorNodeDefinition {\n const node = {\n type: \"selector\",\n ...parseAttributeTokens(tokens, stringLiteralPlaceholders)\n } as SelectorNodeDefinition;\n\n // This is a composite node, so we expect an opening '{'.\n popAndCheck(tokens, \"{\");\n\n // Return the selector node definition.\n return node;\n}\n\n/**\n * Creates a parallel node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The parallel node JSON definition.\n */\nfunction createParallelNode(\n tokens: string[],\n stringLiteralPlaceholders: StringLiteralPlaceholders\n): ParallelNodeDefinition {\n const node = {\n type: \"parallel\",\n ...parseAttributeTokens(tokens, stringLiteralPlaceholders)\n } as ParallelNodeDefinition;\n\n // This is a composite node, so we expect an opening '{'.\n popAndCheck(tokens, \"{\");\n\n // Return the parallel node definition.\n return node;\n}\n\n/**\n * Creates a lotto node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The lotto node JSON definition.\n */\nfunction createLottoNode(tokens: string[], stringLiteralPlaceholders: StringLiteralPlaceholders): LottoNodeDefinition {\n // If any node arguments have been defined then they must be our weights.\n const nodeArguments = parseArgumentTokens(tokens, stringLiteralPlaceholders);\n\n // All lotto node arguments MUST be of type number and must be positive integers.\n nodeArguments\n .filter((arg) => arg.type !== \"number\" || !arg.isInteger || arg.value < 0)\n .forEach(() => {\n throw new Error(`lotto node weight arguments must be positive integer values`);\n });\n\n const node = {\n type: \"lotto\",\n ...parseAttributeTokens(tokens, stringLiteralPlaceholders)\n } as LottoNodeDefinition;\n\n // Apply the weights if any were defined.\n if (nodeArguments.length) {\n node.weights = nodeArguments.map(({ value }) => value) as number[];\n }\n\n // This is a composite node, so we expect an opening '{'.\n popAndCheck(tokens, \"{\");\n\n // Return the lotto node definition.\n return node;\n}\n\n/**\n * Creates an action node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The action node JSON definition.\n */\nfunction createActionNode(\n tokens: string[],\n stringLiteralPlaceholders: StringLiteralPlaceholders\n): ActionNodeDefinition {\n // Parse any node arguments, we should have at least one which will be an identifier argument for the action name\n // and agent function to invoke for the action, all other arguments are to be passed as arguments to that function.\n const [actionNameIdentifier, ...agentFunctionArgs] = parseArgumentTokens(tokens, stringLiteralPlaceholders);\n\n // Our first argument MUST be defined and be an identifier as we require an action name argument.\n if (actionNameIdentifier?.type !== \"identifier\") {\n throw new Error(\"expected action name identifier argument\");\n }\n\n // Only the first argument should have been an identifier, all agent function arguments must be string, number, boolean or null.\n agentFunctionArgs\n .filter((arg) => arg.type === \"identifier\")\n .forEach((arg) => {\n throw new Error(\n `invalid action node argument value '${arg.value}', must be string, number, boolean or null`\n );\n });\n\n // Return the action node definition.\n return {\n type: \"action\",\n call: actionNameIdentifier.value,\n args: agentFunctionArgs.map(({ value }) => value),\n ...parseAttributeTokens(tokens, stringLiteralPlaceholders)\n };\n}\n\n/**\n * Creates a condition node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The condition node JSON definition.\n */\nfunction createConditionNode(\n tokens: string[],\n stringLiteralPlaceholders: StringLiteralPlaceholders\n): ConditionNodeDefinition {\n // Parse any node arguments, we should have at least one which will be an identifier argument for the condition name\n // and agent function to invoke for the condition, all other arguments are to be passed as arguments to that function.\n const [conditionNameIdentifier, ...agentFunctionArgs] = parseArgumentTokens(tokens, stringLiteralPlaceholders);\n\n // Our first argument MUST be defined and be an identifier as we require a condition name argument.\n if (conditionNameIdentifier?.type !== \"identifier\") {\n throw new Error(\"expected condition name identifier argument\");\n }\n\n // Only the first argument should have been an identifier, all agent function arguments must be string, number, boolean or null.\n agentFunctionArgs\n .filter((arg) => arg.type === \"identifier\")\n .forEach((arg) => {\n throw new Error(\n `invalid condition node argument value '${arg.value}', must be string, number, boolean or null`\n );\n });\n\n // Return the condition node definition.\n return {\n type: \"condition\",\n call: conditionNameIdentifier.value,\n args: agentFunctionArgs.map(({ value }) => value),\n ...parseAttributeTokens(tokens, stringLiteralPlaceholders)\n };\n}\n\n/**\n * Creates a wait node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The wait node JSON definition.\n */\nfunction createWaitNode(tokens: string[], stringLiteralPlaceholders: StringLiteralPlaceholders): WaitNodeDefinition {\n let node = { type: \"wait\" } as WaitNodeDefinition;\n\n // Get the node arguments.\n const nodeArguments = parseArgumentTokens(tokens, stringLiteralPlaceholders);\n\n // The arguments of a wait node are optional. We may have:\n // - No node arguments, in which case the wait will be indefinite until it is aborted.\n // - One node argument which will be the explicit duration of the wait.\n // - Two node arguments which define the min and max duration bounds from which a random duration will be picked.\n if (nodeArguments.length) {\n // All wait node arguments MUST be of type number and must be integer.\n nodeArguments\n .filter((arg) => arg.type !== \"number\" || !arg.isInteger)\n .forEach(() => {\n throw new Error(`wait node durations must be integer values`);\n });\n\n // We may have:\n // - One node argument which will be the explicit duration of the wait.\n // - Two node arguments which define the min and max duration bounds from which a random duration will be picked.\n // - Too many arguments, which is not valid.\n if (nodeArguments.length === 1) {\n // An explicit duration was defined.\n node.duration = nodeArguments[0].value as number;\n\n // If an explict duration was defined then it must be a positive number.\n if (node.duration < 0) {\n throw new Error(\"a wait node must have a positive duration\");\n }\n } else if (nodeArguments.length === 2) {\n // Min and max duration bounds were defined from which a random duration will be picked.\n node.duration = [nodeArguments[0].value as number, nodeArguments[1].value as number];\n\n // A wait node must have a positive min and max duration.\n if (node.duration[0] < 0 || node.duration[1] < 0) {\n throw new Error(\"a wait node must have a positive minimum and maximum duration\");\n }\n\n // A wait node must not have a minimum duration that exceeds the maximum duration.\n if (node.duration[0] > node.duration[1]) {\n throw new Error(\"a wait node must not have a minimum duration that exceeds the maximum duration\");\n }\n } else if (nodeArguments.length > 2) {\n // An incorrect number of duration arguments were defined.\n throw new Error(\"invalid number of wait node duration arguments defined\");\n }\n }\n\n // Return the wait node definition.\n return { ...node, ...parseAttributeTokens(tokens, stringLiteralPlaceholders) };\n}\n\n/**\n * Creates a branch node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The branch node JSON definition.\n */\nfunction createBranchNode(\n tokens: string[],\n stringLiteralPlaceholders: StringLiteralPlaceholders\n): BranchNodeDefinition {\n // Parse any node arguments, we should have one which will be an identifier argument for the root ref.\n const nodeArguments = parseArgumentTokens(tokens, stringLiteralPlaceholders);\n\n // We should have only a single identifer argument for a branch node, which is the root ref.\n if (nodeArguments.length !== 1 || nodeArguments[0].type !== \"identifier\") {\n throw new Error(\"expected single branch name argument\");\n }\n\n // Return the branch node definition.\n return { type: \"branch\", ref: nodeArguments[0].value };\n}\n\n/**\n * Validate a fully-populated node definition that was popped off of the tree stack.\n * @param definition The popped node to validate.\n */\nfunction validatePoppedNode(definition: AnyNodeDefinition): void {\n // Decorators MUST have a child defined.\n if (isDecoratorNode(definition) && isNullOrUndefined(definition.child)) {\n throw new Error(`a ${definition.type} node must have a single child node defined`);\n }\n\n // Composites MUST have at least one child defined.\n if (isCompositeNode(definition) && !definition.children?.length) {\n throw new Error(`a ${definition.type} node must have at least a single child node defined`);\n }\n\n // We need to make sure that lotto nodes that have weights defined have a number of weights matching the number of child nodes.\n if (definition.type === \"lotto\") {\n // Check whether a 'weights' property has been defined, if it has we expect it to be an array of weights.\n if (typeof definition.weights !== \"undefined\") {\n // Check that the weights property is an array of positive integers with an element for each child node element.\n if (definition.weights.length !== definition.children.length) {\n throw new Error(\n \"expected a number of weight arguments matching the number of child nodes for lotto node\"\n );\n }\n }\n }\n}\n", "import { RootNodeDefinition } from \"./BehaviourTreeDefinition\";\nimport { flattenDefinition, isBranchNode, isInteger } from \"./BehaviourTreeDefinitionUtilities\";\nimport { convertMDSLToJSON } from \"./mdsl/MDSLDefinitionParser\";\n\n/**\n * An object representing the result of validating a tree definition.\n */\nexport type DefinitionValidationResult = {\n /**\n * A flag defining whether validation succeeded.\n */\n succeeded: boolean;\n /**\n * A string containing the error message if validation did not succeed.\n */\n errorMessage?: string;\n /**\n * The definition as json if the validation was successful, or undefined if validation did not succeed.\n */\n json?: RootNodeDefinition[];\n};\n\n/**\n * Validates the specified behaviour tree definition in the form of JSON or MDSL, not taking any globally registered subtrees into consideration.\n * @param definition The behaviour tree definition in the form of JSON or MDSL.\n * @returns An object representing the result of validating the given tree definition.\n */\nexport function validateDefinition(definition: any): DefinitionValidationResult {\n // The definition must be defined.\n if (definition === null || typeof definition === \"undefined\") {\n return createValidationFailureResult(\"definition is null or undefined\");\n }\n\n // We are expecting a definition in one of three different forms:\n // - A string which we will assume is MDSL and we will parse this to JSON before validation.\n // - An array which we will assume is an array of root node definitions with at least one being the primary root node (no 'id' property)\n // - An object which we will assume is the primary root node and should not have an 'id' property.\n if (typeof definition === \"string\") {\n // The definition is a string which we can assume is MDSL, so attempt to validate it.\n return validateMDSLDefinition(definition);\n } else if (typeof definition === \"object\") {\n // The definition will either be an array (of root node definitions) or an object (the single primary root node definition).\n return validateJSONDefinition(definition);\n } else {\n return createValidationFailureResult(`unexpected definition type of '${typeof definition}'`);\n }\n}\n\n/**\n * Validates the specified behaviour tree definition in the form of MDSL.\n * @param definition The behaviour tree definition in the form of MDSL.\n * @returns An object representing the result of validating the given tree definition.\n */\nfunction validateMDSLDefinition(definition: string): DefinitionValidationResult {\n let rootNodeDefinitions;\n\n // The first thing the we need to do is to attempt to convert our MDSL into JSON.\n try {\n // The definition is a string which we can assume is MDSL, so attempt to parse it to a JSON definition in the form of an array of root node definitions.\n rootNodeDefinitions = convertMDSLToJSON(definition);\n } catch (exception) {\n // We failed to parse the JSON from the MDSL, this is likely to be the result of it not being a valid MDSL string.\n return createValidationFailureResult((exception as Error).message);\n }\n\n // Unpack all of the root node definitions into arrays of main ('id' defined) and sub ('id' not defined) root node definitions.\n const mainRootNodeDefinitions = rootNodeDefinitions.filter(({ id }) => typeof id === \"undefined\");\n const subRootNodeDefinitions = rootNodeDefinitions.filter(({ id }) => typeof id === \"string\" && id.length > 0);\n\n // We should ALWAYS have exactly one root node definition without an 'id' property defined, which is out main root node definition.\n if (mainRootNodeDefinitions.length !== 1) {\n return createValidationFailureResult(\n \"expected single unnamed root node at base of definition to act as main root\"\n );\n }\n\n // We should never have duplicate 'id' properties across our sub root node definitions.\n const subRootNodeIdenitifers: string[] = [];\n for (const { id } of subRootNodeDefinitions) {\n // Have we already come across this 'id' property value?\n if (subRootNodeIdenitifers.includes(id!)) {\n return createValidationFailureResult(`multiple root nodes found with duplicate name '${id}'`);\n }\n\n subRootNodeIdenitifers.push(id!);\n }\n\n try {\n // Validate our branch -> subtree links and check for any circular dependencies, we don't care about checking for broken subtree links here.\n validateBranchSubtreeLinks(rootNodeDefinitions, false);\n } catch (exception) {\n return createValidationFailureResult((exception as Error).message);\n }\n\n // Our definition was valid!\n return {\n succeeded: true,\n json: rootNodeDefinitions\n };\n}\n\n/**\n * Validates the specified behaviour tree definition in the form of JSON.\n * @param definition The behaviour tree definition in the form of JSON.\n * @returns An object representing the result of validating the given tree definition.\n */\nexport function validateJSONDefinition(\n definition: RootNodeDefinition | RootNodeDefinition[]\n): DefinitionValidationResult {\n // The definition will either be an array (of root node definitions) or an object (the single primary root node definition).\n const rootNodeDefinitions = Array.isArray(definition) ? definition : [definition];\n\n // Iterate over our array of root nodes and call validateNode for each, passing an initial depth of 0, wrapped in a try catch to handle validation failures.\n try {\n rootNodeDefinitions.forEach((rootNodeDefinition) => validateNode(rootNodeDefinition, 0));\n } catch (error) {\n // Handle cases where we have caught a thrown Error and return a failure result with the error message.\n if (error instanceof Error) {\n return createValidationFailureResult(error.message);\n }\n\n // No idea what happened here!\n return createValidationFailureResult(`unexpected error: ${error}`);\n }\n\n // Unpack all of the root node definitions into arrays of main ('id' defined) and sub ('id' not defined) root node definitions.\n const mainRootNodeDefinitions = rootNodeDefinitions.filter(({ id }) => typeof id === \"undefined\");\n const subRootNodeDefinitions = rootNodeDefinitions.filter(({ id }) => typeof id === \"string\" && id.length > 0);\n\n // We should ALWAYS have exactly one root node definition without an 'id' property defined, which is out main root node definition.\n if (mainRootNodeDefinitions.length !== 1) {\n return createValidationFailureResult(\n \"expected single root node without 'id' property defined to act as main root\"\n );\n }\n\n // We should never have duplicate 'id' properties across our sub root node definitions.\n const subRootNodeIdenitifers: string[] = [];\n for (const { id } of subRootNodeDefinitions) {\n // Have we already come across this 'id' property value?\n if (subRootNodeIdenitifers.includes(id!)) {\n return createValidationFailureResult(\n `multiple root nodes found with duplicate 'id' property value of '${id}'`\n );\n }\n\n subRootNodeIdenitifers.push(id!);\n }\n\n try {\n // Validate our branch -> subtree links and check for any circular dependencies, we don't care about checking for broken subtree links here.\n validateBranchSubtreeLinks(rootNodeDefinitions, false);\n } catch (exception) {\n return createValidationFailureResult((exception as Error).message);\n }\n\n // Our definition was valid!\n return {\n succeeded: true,\n json: rootNodeDefinitions\n };\n}\n\n/**\n * Validates the branch -> subtree links across all provided root node definitions.\n * This will not consider branch nodes that reference any globally registered subtrees unless includesGlobalSubtrees\n * is set to true, in which case we will also verify that there are no broken branch -> subtree links.\n * @param rootNodeDefinitions The array of root node definitions.\n * @param includesGlobalSubtrees A flag defining whether the array includes all global subtree root node definitions.\n */\nexport function validateBranchSubtreeLinks(rootNodeDefinitions: RootNodeDefinition[], includesGlobalSubtrees: boolean) {\n // Create a mapping of root node identifiers to other root nodes that they reference via branch nodes.\n // Below is an example of a mapping that includes a circular dependency (root => a => b => c => a)\n // [{ refs: [\"a\", \"b\"] }, { id: \"a\", refs: [\"b\"] }, { id: \"b\", refs: [\"c\"] }, { id: \"c\", refs: [\"a\"] }]\n const rootNodeMappings: { id: string | undefined; refs: string[] }[] = rootNodeDefinitions.map(\n (rootNodeDefinition) => ({\n id: rootNodeDefinition.id,\n refs: flattenDefinition(rootNodeDefinition)\n .filter(isBranchNode)\n .map(({ ref }) => ref)\n })\n );\n\n // A recursive function to walk through the mappings, keeping track of which root nodes we have visited in the form of a path of root node identifiers.\n const followRefs = (mapping: { id: string | undefined; refs: string[] }, path: (string | undefined)[] = []) => {\n // Have we found a circular dependency?\n if (path.includes(mapping.id)) {\n // We found a circular dependency! Get the bad path of root node identifiers.\n const badPath = [...path, mapping.id];\n\n // Create the formatted path value. [undefined, \"a\", \"b\", \"c\", \"a\"] would be formatted as \"a -> b -> c -> a\".\n const badPathFormatted = badPath.filter((element) => !!element).join(\" => \");\n\n // No need to continue, we found a circular dependency.\n throw new Error(`circular dependency found in branch node references: ${badPathFormatted}`);\n }\n\n for (const ref of mapping.refs) {\n // Find the mapping for the root node with an identifer matching the current ref.\n const subMapping = rootNodeMappings.find(({ id }) => id === ref);\n\n // We may not have a mapping for this ref, which is normal when we aren't considering all globally registered subtrees.\n if (subMapping) {\n followRefs(subMapping, [...path, mapping.id]);\n } else if (includesGlobalSubtrees) {\n // We found a reference to a root node that doesn't exist, which is a problem seeing as the root node definitons includes all globally registered subtrees.\n throw new Error(\n mapping.id\n ? `subtree '${mapping.id}' has branch node that references root node '${ref}' which has not been defined`\n : `primary tree has branch node that references root node '${ref}' which has not been defined`\n );\n }\n }\n };\n\n // Start looking for circular dependencies and broken references from the primary root node definition.\n followRefs(rootNodeMappings.find((mapping) => typeof mapping.id === \"undefined\")!);\n}\n\n/**\n * Validate an object that we expect to be a node definition.\n * @param definition An object that we expect to be a node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateNode(definition: any, depth: number): void {\n // Every node must be valid object and have a non-empty 'type' string property.\n if (typeof definition !== \"object\" || typeof definition.type !== \"string\" || definition.type.length === 0) {\n throw new Error(\n `node definition is not an object or 'type' property is not a non-empty string at depth '${depth}'`\n );\n }\n\n // How we validate this node definition will depend on its type.\n switch (definition.type) {\n case \"action\":\n validateActionNode(definition, depth);\n break;\n\n case \"condition\":\n validateConditionNode(definition, depth);\n break;\n\n case \"wait\":\n validateWaitNode(definition, depth);\n break;\n\n case \"branch\":\n validateBranchNode(definition, depth);\n break;\n\n case \"root\":\n validateRootNode(definition, depth);\n break;\n\n case \"succeed\":\n validateSucceedNode(definition, depth);\n break;\n\n case \"fail\":\n validateFailNode(definition, depth);\n break;\n\n case \"flip\":\n validateFlipNode(definition, depth);\n break;\n\n case \"repeat\":\n validateRepeatNode(definition, depth);\n break;\n\n case \"retry\":\n validateRetryNode(definition, depth);\n break;\n\n case \"sequence\":\n validateSequenceNode(definition, depth);\n break;\n\n case \"selector\":\n validateSelectorNode(definition, depth);\n break;\n\n case \"parallel\":\n validateParallelNode(definition, depth);\n break;\n\n case \"lotto\":\n validateLottoNode(definition, depth);\n break;\n\n default:\n throw new Error(`unexpected node type of '${definition.type}' at depth '${depth}'`);\n }\n}\n\n/**\n * Validate any attributes for a given node definition.\n * @param definition The node definition.\n * @param depth The depth of the node in the behaviour tree definition.\n */\nfunction validateNodeAttributes(definition: any, depth: number): void {\n // Validate each of the attribute types for this node.\n [\"while\", \"until\", \"entry\", \"exit\", \"step\"].forEach((attributeName) => {\n // Attempt to grab the definition for the current attribute from the node definition.\n const attributeDefinition = definition[attributeName];\n\n // All node attributes are optional, so there is nothing to do if the current attribute is not defined.\n if (typeof attributeDefinition === \"undefined\") {\n return;\n }\n\n // The attribute definition must be an object.\n if (typeof attributeDefinition !== \"object\") {\n throw new Error(\n `expected attribute '${attributeName}' to be an object for '${definition.type}' node at depth '${depth}'`\n );\n }\n\n // The 'call' property must be defined for any attribute definition.\n if (typeof attributeDefinition.call !== \"string\" || attributeDefinition.call.length === 0) {\n throw new Error(\n `expected 'call' property for attribute '${attributeName}' to be a non-empty string for '${definition.type}' node at depth '${depth}'`\n );\n }\n\n // If any node attribute arguments have been defined then they must have been defined in an array.\n if (typeof attributeDefinition.args !== \"undefined\" && !Array.isArray(attributeDefinition.args)) {\n throw new Error(\n `expected 'args' property for attribute '${attributeName}' to be an array for '${definition.type}' node at depth '${depth}'`\n );\n }\n });\n}\n\n/**\n * Validate an object that we expect to be a root node definition.\n * @param definition An object that we expect to be a root node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateRootNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"root\") {\n throw new Error(\"expected node type of 'root' for root node\");\n }\n\n // A root node cannot be the child of another node.\n if (depth > 0) {\n throw new Error(\"a root node cannot be the child of another node\");\n }\n\n // Check that, if the root node 'id' property is defined, it is a non-empty string.\n if (typeof definition.id !== \"undefined\" && (typeof definition.id !== \"string\" || definition.id.length === 0)) {\n throw new Error(\"expected non-empty string for 'id' property if defined for root node\");\n }\n\n // A root node is a decorator node, so must have a child node defined.\n if (typeof definition.child === \"undefined\") {\n throw new Error(\"expected property 'child' to be defined for root node\");\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n\n // Validate the child node of this decorator node.\n validateNode(definition.child, depth + 1);\n}\n\n/**\n * Validate an object that we expect to be a succeed node definition.\n * @param definition An object that we expect to be a succeed node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateSucceedNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"succeed\") {\n throw new Error(`expected node type of 'succeed' for succeed node at depth '${depth}'`);\n }\n\n // A succeed node is a decorator node, so must have a child node defined.\n if (typeof definition.child === \"undefined\") {\n throw new Error(`expected property 'child' to be defined for succeed node at depth '${depth}'`);\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n\n // Validate the child node of this decorator node.\n validateNode(definition.child, depth + 1);\n}\n\n/**\n * Validate an object that we expect to be a fail node definition.\n * @param definition An object that we expect to be a fail node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateFailNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"fail\") {\n throw new Error(`expected node type of 'fail' for fail node at depth '${depth}'`);\n }\n\n // A fail node is a decorator node, so must have a child node defined.\n if (typeof definition.child === \"undefined\") {\n throw new Error(`expected property 'child' to be defined for fail node at depth '${depth}'`);\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n\n // Validate the child node of this decorator node.\n validateNode(definition.child, depth + 1);\n}\n\n/**\n * Validate an object that we expect to be a flip node definition.\n * @param definition An object that we expect to be a flip node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateFlipNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"flip\") {\n throw new Error(`expected node type of 'flip' for flip node at depth '${depth}'`);\n }\n\n // A flip node is a decorator node, so must have a child node defined.\n if (typeof definition.child === \"undefined\") {\n throw new Error(`expected property 'child' to be defined for flip node at depth '${depth}'`);\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n\n // Validate the child node of this decorator node.\n validateNode(definition.child, depth + 1);\n}\n\n/**\n * Validate an object that we expect to be a repeat node definition.\n * @param definition An object that we expect to be a repeat node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateRepeatNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"repeat\") {\n throw new Error(`expected node type of 'repeat' for repeat node at depth '${depth}'`);\n }\n\n // A repeat node is a decorator node, so must have a child node defined.\n if (typeof definition.child === \"undefined\") {\n throw new Error(`expected property 'child' to be defined for repeat node at depth '${depth}'`);\n }\n\n // Check whether an 'iterations' property has been defined, it may not have been if this node is to repeat indefinitely.\n if (typeof definition.iterations !== \"undefined\") {\n if (Array.isArray(definition.iterations)) {\n // Check whether any elements of the array are not integer values.\n const containsNonInteger = !!definition.iterations.filter((value: unknown) => !isInteger(value)).length;\n\n // If the 'iterations' property is an array then it MUST contain two integer values.\n if (definition.iterations.length !== 2 || containsNonInteger) {\n throw new Error(\n `expected array containing two integer values for 'iterations' property if defined for repeat node at depth '${depth}'`\n );\n }\n\n // A repeat node must have a positive min and max iterations count if they are defined.\n if (definition.iterations[0] < 0 || definition.iterations[1] < 0) {\n throw new Error(\n `expected positive minimum and maximum iterations count for 'iterations' property if defined for repeat node at depth '${depth}'`\n );\n }\n\n // A repeat node must not have a minimum iterations count that exceeds the maximum iterations count.\n if (definition.iterations[0] > definition.iterations[1]) {\n throw new Error(\n `expected minimum iterations count that does not exceed the maximum iterations count for 'iterations' property if defined for repeat node at depth '${depth}'`\n );\n }\n } else if (isInteger(definition.iterations)) {\n // A repeat node must have a positive number of iterations if defined.\n if (definition.iterations < 0) {\n throw new Error(\n `expected positive iterations count for 'iterations' property if defined for repeat node at depth '${depth}'`\n );\n }\n } else {\n throw new Error(\n `expected integer value or array containing two integer values for 'iterations' property if defined for repeat node at depth '${depth}'`\n );\n }\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n\n // Validate the child node of this decorator node.\n validateNode(definition.child, depth + 1);\n}\n\n/**\n * Validate an object that we expect to be a retry node definition.\n * @param definition An object that we expect to be a retry node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateRetryNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"retry\") {\n throw new Error(`expected node type of 'retry' for retry node at depth '${depth}'`);\n }\n\n // A retry node is a decorator node, so must have a child node defined.\n if (typeof definition.child === \"undefined\") {\n throw new Error(`expected property 'child' to be defined for retry node at depth '${depth}'`);\n }\n\n // Check whether an 'attempts' property has been defined, it may not have been if this node is to retry indefinitely.\n if (typeof definition.attempts !== \"undefined\") {\n if (Array.isArray(definition.attempts)) {\n // Check whether any elements of the array are not integer values.\n const containsNonInteger = !!definition.attempts.filter((value: unknown) => !isInteger(value)).length;\n\n // If the 'attempts' property is an array then it MUST contain two integer values.\n if (definition.attempts.length !== 2 || containsNonInteger) {\n throw new Error(\n `expected array containing two integer values for 'attempts' property if defined for retry node at depth '${depth}'`\n );\n }\n\n // A retry node must have a positive min and max attempts count if they are defined.\n if (definition.attempts[0] < 0 || definition.attempts[1] < 0) {\n throw new Error(\n `expected positive minimum and maximum attempts count for 'attempts' property if defined for retry node at depth '${depth}'`\n );\n }\n\n // A retry node must not have a minimum attempts count that exceeds the maximum attempts count.\n if (definition.attempts[0] > definition.attempts[1]) {\n throw new Error(\n `expected minimum attempts count that does not exceed the maximum attempts count for 'attempts' property if defined for retry node at depth '${depth}'`\n );\n }\n } else if (isInteger(definition.attempts)) {\n // A retry node must have a positive number of attempts if defined.\n if (definition.attempts < 0) {\n throw new Error(\n `expected positive attempts count for 'attempts' property if defined for retry node at depth '${depth}'`\n );\n }\n } else {\n throw new Error(\n `expected integer value or array containing two integer values for 'attempts' property if defined for retry node at depth '${depth}'`\n );\n }\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n\n // Validate the child node of this decorator node.\n validateNode(definition.child, depth + 1);\n}\n\n/**\n * Validate an object that we expect to be a branch node definition.\n * @param definition An object that we expect to be a branch node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateBranchNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"branch\") {\n throw new Error(`expected node type of 'branch' for branch node at depth '${depth}'`);\n }\n\n // Check that the branch node 'ref' property is defined and is a non-empty string.\n if (typeof definition.ref !== \"string\" || definition.ref.length === 0) {\n throw new Error(`expected non-empty string for 'ref' property for branch node at depth '${depth}'`);\n }\n\n // It is invalid to define guard attributes for a branch node as they should be defined on the referenced root node.\n [\"while\", \"until\"].forEach((attributeName) => {\n if (typeof definition[attributeName] !== \"undefined\") {\n throw new Error(\n `guards should not be defined for branch nodes but guard '${attributeName}' was defined for branch node at depth '${depth}'`\n );\n }\n });\n\n // It is invalid to define callback attributes for a branch node as they should be defined on the referenced root node.\n [\"entry\", \"exit\", \"step\"].forEach((attributeName) => {\n if (typeof definition[attributeName] !== \"undefined\") {\n throw new Error(\n `callbacks should not be defined for branch nodes but callback '${attributeName}' was defined for branch node at depth '${depth}'`\n );\n }\n });\n}\n\n/**\n * Validate an object that we expect to be a action node definition.\n * @param definition An object that we expect to be a action node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateActionNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"action\") {\n throw new Error(`expected node type of 'action' for action node at depth '${depth}'`);\n }\n\n // The 'call' property must be defined for a action node definition.\n if (typeof definition.call !== \"string\" || definition.call.length === 0) {\n throw new Error(`expected non-empty string for 'call' property of action node at depth '${depth}'`);\n }\n\n // If any action function arguments have been defined then they must have been defined in an array.\n if (typeof definition.args !== \"undefined\" && !Array.isArray(definition.args)) {\n throw new Error(`expected array for 'args' property if defined for action node at depth '${depth}'`);\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n}\n\n/**\n * Validate an object that we expect to be a condition node definition.\n * @param definition An object that we expect to be a condition node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateConditionNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"condition\") {\n throw new Error(`expected node type of 'condition' for condition node at depth '${depth}'`);\n }\n\n // The 'call' property must be defined for a condition node definition.\n if (typeof definition.call !== \"string\" || definition.call.length === 0) {\n throw new Error(`expected non-empty string for 'call' property of condition node at depth '${depth}'`);\n }\n\n // If any condition function arguments have been defined then they must have been defined in an array.\n if (typeof definition.args !== \"undefined\" && !Array.isArray(definition.args)) {\n throw new Error(`expected array for 'args' property if defined for condition node at depth '${depth}'`);\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n}\n\n/**\n * Validate an object that we expect to be a wait node definition.\n * @param definition An object that we expect to be a wait node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateWaitNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"wait\") {\n throw new Error(`expected node type of 'wait' for wait node at depth '${depth}'`);\n }\n\n // Check whether a 'duration' property has been defined, it may not have been if this node is to wait indefinitely.\n if (typeof definition.duration !== \"undefined\") {\n if (Array.isArray(definition.duration)) {\n // Check whether any elements of the array are not integer values.\n const containsNonInteger = !!definition.duration.filter((value: unknown) => !isInteger(value)).length;\n\n // If the 'duration' property is an array then it MUST contain two integer values.\n if (definition.duration.length !== 2 || containsNonInteger) {\n throw new Error(\n `expected array containing two integer values for 'duration' property if defined for wait node at depth '${depth}'`\n );\n }\n\n // A wait node must have a positive min and max duration value if they are defined.\n if (definition.duration[0] < 0 || definition.duration[1] < 0) {\n throw new Error(\n `expected positive minimum and maximum duration for 'duration' property if defined for wait node at depth '${depth}'`\n );\n }\n\n // A wait node must not have a minimum duration value that exceeds the maximum duration value.\n if (definition.duration[0] > definition.duration[1]) {\n throw new Error(\n `expected minimum duration value that does not exceed the maximum duration value for 'duration' property if defined for wait node at depth '${depth}'`\n );\n }\n } else if (isInteger(definition.duration)) {\n // A wait node must have a positive duration value if defined.\n if (definition.duration < 0) {\n throw new Error(\n `expected positive duration value for 'duration' property if defined for wait node at depth '${depth}'`\n );\n }\n } else {\n throw new Error(\n `expected integer value or array containing two integer values for 'duration' property if defined for wait node at depth '${depth}'`\n );\n }\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n}\n\n/**\n * Validate an object that we expect to be a sequence node definition.\n * @param definition An object that we expect to be a sequence node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateSequenceNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"sequence\") {\n throw new Error(`expected node type of 'sequence' for sequence node at depth '${depth}'`);\n }\n\n // A sequence node is a composite node, so must have a children nodes array defined.\n if (!Array.isArray(definition.children) || definition.children.length === 0) {\n throw new Error(`expected non-empty 'children' array to be defined for sequence node at depth '${depth}'`);\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n\n // Validate the child nodes of this composite node.\n definition.children.forEach((child: any) => validateNode(child, depth + 1));\n}\n\n/**\n * Validate an object that we expect to be a selector node definition.\n * @param definition An object that we expect to be a selector node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateSelectorNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"selector\") {\n throw new Error(`expected node type of 'selector' for selector node at depth '${depth}'`);\n }\n\n // A selector node is a composite node, so must have a children nodes array defined.\n if (!Array.isArray(definition.children) || definition.children.length === 0) {\n throw new Error(`expected non-empty 'children' array to be defined for selector node at depth '${depth}'`);\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n\n // Validate the child nodes of this composite node.\n definition.children.forEach((child: any) => validateNode(child, depth + 1));\n}\n\n/**\n * Validate an object that we expect to be a parallel node definition.\n * @param definition An object that we expect to be a parallel node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateParallelNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"parallel\") {\n throw new Error(`expected node type of 'parallel' for parallel node at depth '${depth}'`);\n }\n\n // A parallel node is a composite node, so must have a children nodes array defined.\n if (!Array.isArray(definition.children) || definition.children.length === 0) {\n throw new Error(`expected non-empty 'children' array to be defined for parallel node at depth '${depth}'`);\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n\n // Validate the child nodes of this composite node.\n definition.children.forEach((child: any) => validateNode(child, depth + 1));\n}\n\n/**\n * Validate an object that we expect to be a lotto node definition.\n * @param definition An object that we expect to be a lotto node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateLottoNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"lotto\") {\n throw new Error(`expected node type of 'lotto' for lotto node at depth '${depth}'`);\n }\n\n // A lotto node is a composite node, so must have a children nodes array defined.\n if (!Array.isArray(definition.children) || definition.children.length === 0) {\n throw new Error(`expected non-empty 'children' array to be defined for lotto node at depth '${depth}'`);\n }\n\n // Check whether a 'weights' property has been defined, if it has we expect it to be an array of weights.\n if (typeof definition.weights !== \"undefined\") {\n // Check that the weights property is an array of positive integers with an element for each child node element.\n if (\n !Array.isArray(definition.weights) ||\n definition.weights.length !== definition.children.length ||\n definition.weights.filter((value: unknown) => !isInteger(value)).length ||\n definition.weights.filter((value: number) => value < 0).length\n ) {\n throw new Error(\n `expected an array of positive integer weight values with a length matching the number of child nodes for 'weights' property if defined for lotto node at depth '${depth}'`\n );\n }\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n\n // Validate the child nodes of this composite node.\n definition.children.forEach((child: any) => validateNode(child, depth + 1));\n}\n\n/**\n * A helper function to create a failure validation result with the given error message.\n * @param errorMessage The validation failure error message.\n * @returns A failure validation result with the given error message.\n */\nfunction createValidationFailureResult(errorMessage: string): DefinitionValidationResult {\n return { succeeded: false, errorMessage };\n}\n", "import { ActionResult, Agent, GlobalFunction } from \"./Agent\";\nimport { RootNodeDefinition } from \"./BehaviourTreeDefinition\";\n\nexport type InvokerFunction = (args: any[]) => ActionResult | boolean;\n\n/**\n * A singleton used to store and lookup registered functions and subtrees.\n */\nexport default class Lookup {\n /**\n * The object holding any registered functions keyed on function name.\n */\n private static registeredFunctions: { [key: string]: GlobalFunction } = {};\n /**\n * The object holding any registered subtree root node definitions keyed on tree name.\n */\n private static registeredSubtrees: { [key: string]: RootNodeDefinition } = {};\n\n /**\n * Gets the function with the specified name.\n * @param name The name of the function.\n * @returns The function with the specified name.\n */\n public static getFunc(name: string): GlobalFunction {\n return this.registeredFunctions[name];\n }\n\n /**\n * Sets the function with the specified name for later lookup.\n * @param name The name of the function.\n * @param func The function.\n */\n public static setFunc(name: string, func: GlobalFunction): void {\n this.registeredFunctions[name] = func;\n }\n\n /**\n * Gets the function invoker for the specified agent and function name.\n * If a function with the specified name exists on the agent object then it will\n * be returned, otherwise we will then check the registered functions for a match.\n * @param agent The agent instance that this behaviour tree is modelling behaviour for.\n * @param name The function name.\n * @returns The function invoker for the specified agent and function name.\n */\n static getFuncInvoker(agent: Agent, name: string): InvokerFunction | null {\n // Check whether the agent contains the specified function.\n const agentFunction = agent[name];\n if (agentFunction && typeof agentFunction === \"function\") {\n return (args: any[]) => agentFunction.apply(agent, args);\n }\n\n // The agent does not contain the specified function but it may have been registered at some point.\n if (this.registeredFunctions[name] && typeof this.registeredFunctions[name] === \"function\") {\n const registeredFunction = this.registeredFunctions[name];\n return (args: any[]) => registeredFunction(agent, ...args.map((arg) => arg.value));\n }\n\n // We have no function to invoke.\n return null;\n }\n\n /**\n * Gets all registered subtree root node definitions.\n */\n static getSubtrees(): { [key: string]: RootNodeDefinition } {\n return this.registeredSubtrees;\n }\n\n /**\n * Sets the subtree with the specified name for later lookup.\n * @param name The name of the subtree.\n * @param subtree The subtree.\n */\n static setSubtree(name: string, subtree: RootNodeDefinition) {\n this.registeredSubtrees[name] = subtree;\n }\n\n /**\n * Removes the registered function or subtree with the specified name.\n * @param name The name of the registered function or subtree.\n */\n static remove(name: string) {\n delete this.registeredFunctions[name];\n delete this.registeredSubtrees[name];\n }\n\n /**\n * Remove all registered functions and subtrees.\n */\n static empty() {\n this.registeredFunctions = {};\n this.registeredSubtrees = {};\n }\n}\n", "import Node from \"../../nodes/Node\";\n\n/**\n * An exception thrown when evaluating node guard path conditions and a conditions fails.\n */\nexport default class GuardUnsatisifedException extends Error {\n /**\n * @param source The node at which a guard condition failed.\n */\n constructor(private source: Node) {\n super(\"A guard path condition has failed\");\n }\n\n /**\n * Gets whether the specified node is the node at which a guard condition failed.\n * @param node The node to check against the source node.\n * @returns Whether the specified node is the node at which a guard condition failed.\n */\n isSourceNode = (node: Node) => node === this.source;\n}\n", "import { Agent } from \"../../Agent\";\nimport Guard from \"./Guard\";\nimport Node from \"../../nodes/Node\";\nimport GuardUnsatisifedException from \"./GuardUnsatisifedException\";\n\nexport type GuardPathPart = {\n node: Node;\n guards: Guard[];\n};\n\n/**\n * Represents a path of node guards along a root-to-leaf tree path.\n */\nexport default class GuardPath {\n /**\n * @param nodes An array of objects defining a node instance -> guard link, ordered by node depth.\n */\n constructor(private nodes: GuardPathPart[]) {}\n\n /**\n * Evaluate guard conditions for all guards in the tree path, moving outwards from the root.\n * @param agent The agent, required for guard evaluation.\n * @returns An evaluation results object.\n */\n evaluate = (agent: Agent) => {\n // We need to evaluate guard conditions for nodes up the tree, moving outwards from the root.\n for (const details of this.nodes) {\n // There can be multiple guards per node.\n for (const guard of details.guards) {\n // Check whether the guard condition passes, and throw an exception if not.\n if (!guard.isSatisfied(agent)) {\n throw new GuardUnsatisifedException(details.node);\n }\n }\n }\n };\n}\n", "import { BehaviourTreeOptions } from \"../BehaviourTreeOptions\";\nimport State, { AnyState } from \"../State\";\nimport { Agent } from \"../Agent\";\nimport Leaf from \"./leaf/Leaf\";\nimport Attribute from \"../attributes/Attribute\";\nimport Entry from \"../attributes/callbacks/Entry\";\nimport Exit from \"../attributes/callbacks/Exit\";\nimport Step from \"../attributes/callbacks/Step\";\nimport Guard from \"../attributes/guards/Guard\";\nimport GuardPath from \"../attributes/guards/GuardPath\";\nimport GuardUnsatisifedException from \"../attributes/guards/GuardUnsatisifedException\";\n\n/**\n * A base node.\n */\nexport default abstract class Node {\n /**\n * The node uid.\n */\n private readonly uid: string = createNodeUid();\n /**\n * The node state.\n */\n private state: AnyState = State.READY;\n /**\n * The guard path to evaluate as part of a node update.\n */\n private guardPath: GuardPath | undefined;\n\n /**\n * @param type The node type.\n * @param attributes The node attributes.\n * @param args The node argument definitions.\n */\n constructor(private type: string, private attributes: Attribute[], private args: any[]) {}\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected abstract onUpdate(agent: Agent, options: BehaviourTreeOptions): void;\n\n /**\n * Gets the name of the node.\n */\n public abstract getName(): string;\n\n /**\n * Gets whether this node is a leaf node.\n */\n public abstract isLeafNode: () => this is Leaf;\n\n /**\n * Gets/Sets the state of the node.\n */\n getState = (): AnyState => this.state;\n setState = (value: AnyState): void => {\n this.state = value;\n };\n\n /**\n * Gets the unique id of the node.\n */\n getUid = () => this.uid;\n\n /**\n * Gets the type of the node.\n */\n getType = () => this.type;\n\n /**\n * Gets the node attributes.\n */\n getAttributes = () => this.attributes;\n\n /**\n * Gets the node arguments.\n */\n getArguments = () => this.args;\n\n /**\n * Gets the node attribute with the specified type, or null if it does not exist.\n */\n getAttribute(type: \"entry\" | \"ENTRY\"): Entry;\n getAttribute(type: \"exit\" | \"EXIT\"): Exit;\n getAttribute(type: \"step\" | \"STEP\"): Step;\n getAttribute(type: string): Attribute {\n return (\n this.getAttributes().filter((decorator) => decorator.type.toUpperCase() === type.toUpperCase())[0] || null\n );\n }\n\n /**\n * Gets the node attributes.\n */\n getGuardAttributes = (): Guard[] => this.getAttributes().filter((decorator) => decorator.isGuard()) as Guard[];\n\n /**\n * Sets the guard path to evaluate as part of a node update.\n */\n setGuardPath = (value: GuardPath) => (this.guardPath = value);\n\n /**\n * Gets whether a guard path is assigned to this node.\n */\n hasGuardPath = () => !!this.guardPath;\n\n /**\n * Gets whether this node is in the specified state.\n * @param value The value to compare to the node state.\n */\n public is(value: AnyState): boolean {\n return this.state === value;\n }\n\n /**\n * Reset the state of the node.\n */\n public reset(): void {\n this.setState(State.READY);\n }\n\n /**\n * Abort the running of this node.\n * @param agent The agent.\n */\n public abort(agent: Agent): void {\n // There is nothing to do if this node is not in the running state.\n if (!this.is(State.RUNNING)) {\n return;\n }\n\n // Reset the state of this node.\n this.reset();\n\n this.getAttribute(\"exit\")?.callAgentFunction(agent, false, true);\n }\n\n /**\n * Update the node.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n * @returns The result of the update.\n */\n public update(agent: Agent, options: BehaviourTreeOptions): void {\n // If this node is already in a 'SUCCEEDED' or 'FAILED' state then there is nothing to do.\n if (this.is(State.SUCCEEDED) || this.is(State.FAILED)) {\n return;\n }\n\n try {\n // Evaluate all of the guard path conditions for the current tree path.\n this.guardPath!.evaluate(agent);\n\n // If this node is in the READY state then call the ENTRY for this node if it exists.\n if (this.is(State.READY)) {\n this.getAttribute(\"entry\")?.callAgentFunction(agent);\n }\n\n this.getAttribute(\"step\")?.callAgentFunction(agent);\n\n // Do the actual update.\n this.onUpdate(agent, options);\n\n // If this node is now in a 'SUCCEEDED' or 'FAILED' state then call the EXIT for this node if it exists.\n if (this.is(State.SUCCEEDED) || this.is(State.FAILED)) {\n this.getAttribute(\"exit\")?.callAgentFunction(agent, this.is(State.SUCCEEDED), false);\n }\n } catch (error) {\n // If the error is a GuardUnsatisfiedException then we need to determine if this node is the source.\n if (error instanceof GuardUnsatisifedException && error.isSourceNode(this)) {\n // Abort the current node.\n this.abort(agent);\n\n // Any node that is the source of an abort will be a failed node.\n this.setState(State.FAILED);\n } else {\n throw error;\n }\n }\n }\n}\n\n/**\n * Create a randomly generated node uid.\n * @returns A randomly generated node uid.\n */\nfunction createNodeUid(): string {\n var S4 = function () {\n return (((1 + Math.random()) * 0x10000) | 0).toString(16).substring(1);\n };\n return S4() + S4() + \"-\" + S4() + \"-\" + S4() + \"-\" + S4() + \"-\" + S4() + S4() + S4();\n}\n", "import Node from \"../Node\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\n\n/**\n * A composite node that wraps child nodes.\n */\nexport default abstract class Composite extends Node {\n /**\n * @param type The node type.\n * @param attributes The node attributes.\n * @param children The child nodes.\n */\n constructor(type: string, attributes: Attribute[], protected children: Node[]) {\n super(type, attributes, []);\n }\n\n /**\n * Gets whether this node is a leaf node.\n */\n isLeafNode = () => false;\n\n /**\n * Gets the children of this node.\n */\n getChildren = () => this.children;\n\n /**\n * Reset the state of the node.\n */\n reset = () => {\n // Reset the state of this node.\n this.setState(State.READY);\n\n // Reset the state of any child nodes.\n this.getChildren().forEach((child) => child.reset());\n };\n\n /**\n * Abort the running of this node.\n * @param agent The agent.\n */\n abort = (agent: Agent) => {\n // There is nothing to do if this node is not in the running state.\n if (!this.is(State.RUNNING)) {\n return;\n }\n\n // Abort any child nodes.\n this.getChildren().forEach((child) => child.abort(agent));\n\n // Reset the state of this node.\n this.reset();\n\n this.getAttribute(\"exit\")?.callAgentFunction(agent, false, true);\n };\n}\n", "import Composite from \"./Composite\";\nimport State from \"../../State\";\nimport Node from \"../Node\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A PARALLEL node.\n * The child nodes are executed concurrently until one fails or all succeed.\n */\nexport default class Parallel extends Composite {\n /**\n * @param attributes The node attributes.\n * @param children The child nodes.\n */\n constructor(attributes: Attribute[], children: Node[]) {\n super(\"parallel\", attributes, children);\n }\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // Keep a count of the number of succeeded child nodes.\n let succeededCount = 0;\n\n let hasChildFailed = false;\n\n // Iterate over all of the children of this node.\n for (const child of this.children) {\n // If the child has never been updated or is running then we will need to update it now.\n if (child.getState() === State.READY || child.getState() === State.RUNNING) {\n // Update the child of this node.\n child.update(agent, options);\n }\n\n // If the current child has a state of 'SUCCEEDED' then we should move on to the next child.\n if (child.getState() === State.SUCCEEDED) {\n // The child node has succeeded, keep track of this to determine if all children have.\n succeededCount++;\n\n // The child node succeeded, but we have not finished checking every child node yet.\n continue;\n }\n\n // If the current child has a state of 'FAILED' then this node is also a 'FAILED' node.\n if (child.getState() === State.FAILED) {\n hasChildFailed = true;\n\n // There is no need to check the rest of the children.\n break;\n }\n\n // The node should be in the 'RUNNING' state.\n if (child.getState() !== State.RUNNING) {\n // The child node was not in an expected state.\n throw new Error(\"child node was not in an expected state.\");\n }\n }\n\n if (hasChildFailed) {\n // This node is a 'FAILED' node.\n this.setState(State.FAILED);\n\n // Abort every running child.\n for (const child of this.children) {\n if (child.getState() === State.RUNNING) {\n child.abort(agent);\n }\n }\n } else {\n // If all children have succeeded then this node has also succeeded, otherwise it is still running.\n this.setState(succeededCount === this.children.length ? State.SUCCEEDED : State.RUNNING);\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => \"PARALLEL\";\n}\n", "import Composite from \"./Composite\";\nimport Node from \"../Node\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A SELECTOR node.\n * The child nodes are executed in sequence until one succeeds or all fail.\n */\nexport default class Selector extends Composite {\n /**\n * @param attributes The node attributes.\n * @param children The child nodes.\n */\n constructor(attributes: Attribute[], protected children: Node[]) {\n super(\"selector\", attributes, children);\n }\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // Iterate over all of the children of this node.\n for (const child of this.children) {\n // If the child has never been updated or is running then we will need to update it now.\n if (child.getState() === State.READY || child.getState() === State.RUNNING) {\n // Update the child of this node.\n child.update(agent, options);\n }\n\n // If the current child has a state of 'SUCCEEDED' then this node is also a 'SUCCEEDED' node.\n if (child.getState() === State.SUCCEEDED) {\n // This node is a 'SUCCEEDED' node.\n this.setState(State.SUCCEEDED);\n\n // There is no need to check the rest of the selector nodes.\n return;\n }\n\n // If the current child has a state of 'FAILED' then we should move on to the next child.\n if (child.getState() === State.FAILED) {\n // Find out if the current child is the last one in the selector.\n // If it is then this sequence node has also failed.\n if (this.children.indexOf(child) === this.children.length - 1) {\n // This node is a 'FAILED' node.\n this.setState(State.FAILED);\n\n // There is no need to check the rest of the selector as we have completed it.\n return;\n } else {\n // The child node failed, try the next one.\n continue;\n }\n }\n\n // The node should be in the 'RUNNING' state.\n if (child.getState() === State.RUNNING) {\n // This node is a 'RUNNING' node.\n this.setState(State.RUNNING);\n\n // There is no need to check the rest of the selector as the current child is still running.\n return;\n }\n\n // The child node was not in an expected state.\n throw new Error(\"child node was not in an expected state.\");\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => \"SELECTOR\";\n}\n", "import Composite from \"./Composite\";\nimport Node from \"../Node\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A SEQUENCE node.\n * The child nodes are executed in sequence until one fails or all succeed.\n */\nexport default class Sequence extends Composite {\n /**\n * @param attributes The node attributes.\n * @param children The child nodes.\n */\n constructor(attributes: Attribute[], protected children: Node[]) {\n super(\"sequence\", attributes, children);\n }\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // Iterate over all of the children of this node.\n for (const child of this.children) {\n // If the child has never been updated or is running then we will need to update it now.\n if (child.getState() === State.READY || child.getState() === State.RUNNING) {\n // Update the child of this node.\n child.update(agent, options);\n }\n\n // If the current child has a state of 'SUCCEEDED' then we should move on to the next child.\n if (child.getState() === State.SUCCEEDED) {\n // Find out if the current child is the last one in the sequence.\n // If it is then this sequence node has also succeeded.\n if (this.children.indexOf(child) === this.children.length - 1) {\n // This node is a 'SUCCEEDED' node.\n this.setState(State.SUCCEEDED);\n\n // There is no need to check the rest of the sequence as we have completed it.\n return;\n } else {\n // The child node succeeded, but we have not finished the sequence yet.\n continue;\n }\n }\n\n // If the current child has a state of 'FAILED' then this node is also a 'FAILED' node.\n if (child.getState() === State.FAILED) {\n // This node is a 'FAILED' node.\n this.setState(State.FAILED);\n\n // There is no need to check the rest of the sequence.\n return;\n }\n\n // The node should be in the 'RUNNING' state.\n if (child.getState() === State.RUNNING) {\n // This node is a 'RUNNING' node.\n this.setState(State.RUNNING);\n\n // There is no need to check the rest of the sequence as the current child is still running.\n return;\n }\n\n // The child node was not in an expected state.\n throw new Error(\"child node was not in an expected state.\");\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => \"SEQUENCE\";\n}\n", "import createLotto from \"lotto-draw\";\n\nimport Node from \"../Node\";\nimport Composite from \"./Composite\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A LOTTO node.\n * A winning child is picked on the initial update of this node, based on ticket weighting.\n * The state of this node will match the state of the winning child.\n */\nexport default class Lotto extends Composite {\n /**\n * @param attributes The node attributes.\n * @param weights The child node weights.\n * @param children The child nodes.\n */\n constructor(attributes: Attribute[], private weights: number[] | undefined, children: Node[]) {\n super(\"lotto\", attributes, children);\n }\n\n /**\n * The child node selected to be the active one.\n */\n private selectedChild: Node | undefined;\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // If this node is in the READY state then we need to pick a winning child node.\n if (this.is(State.READY)) {\n // Create a lotto draw with which to randomly pick a child node to become the active one.\n const lottoDraw = createLotto({\n // Hook up the optional 'random' behaviour tree function option to the one used by 'lotto-draw'.\n random: options.random,\n // Pass in each child node as a participant in the lotto draw with their respective ticket count.\n participants: this.children.map((child, index) => [child, this.weights?.[index] || 1])\n });\n\n // Randomly pick a child based on ticket weighting, this will become the active child for this composite node.\n this.selectedChild = lottoDraw.draw() || undefined;\n }\n\n // If something went wrong and we don't have an active child then we should throw an error.\n if (!this.selectedChild) {\n throw new Error(\"failed to update lotto node as it has no active child\");\n }\n\n // If the selected child has never been updated or is running then we will need to update it now.\n if (this.selectedChild.getState() === State.READY || this.selectedChild.getState() === State.RUNNING) {\n this.selectedChild.update(agent, options);\n }\n\n // The state of the lotto node is the state of its selected child.\n this.setState(this.selectedChild.getState());\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => (this.weights ? `LOTTO [${this.weights.join(\",\")}]` : \"LOTTO\");\n}\n", "import Node from \"../Node\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\n\n/**\n * A decorator node that wraps a single child node.\n */\nexport default abstract class Decorator extends Node {\n /**\n * @param type The node type.\n * @param attributes The node attributes.\n * @param child The child node.\n */\n constructor(type: string, attributes: Attribute[], protected child: Node) {\n super(type, attributes, []);\n }\n\n /**\n * Gets whether this node is a leaf node.\n */\n isLeafNode = () => false;\n\n /**\n * Gets the children of this node.\n */\n getChildren = () => [this.child];\n\n /**\n * Reset the state of the node.\n */\n reset = () => {\n // Reset the state of this node.\n this.setState(State.READY);\n\n // Reset the state of the child node.\n this.child.reset();\n };\n\n /**\n * Abort the running of this node.\n * @param agent The agent.\n */\n abort = (agent: Agent) => {\n // There is nothing to do if this node is not in the running state.\n if (!this.is(State.RUNNING)) {\n return;\n }\n\n // Abort the child node.\n this.child.abort(agent);\n\n // Reset the state of this node.\n this.reset();\n\n this.getAttribute(\"exit\")?.callAgentFunction(agent, false, true);\n };\n}\n", "import Node from \"../Node\";\nimport Decorator from \"./Decorator\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A Fail node.\n * This node wraps a single child and will always move to the 'FAILED' state when the child moves to a 'SUCCEEDED' or 'FAILED' state.\n */\nexport default class Fail extends Decorator {\n /**\n * @param attributes The node attributes.\n * @param child The child node.\n */\n constructor(attributes: Attribute[], child: Node) {\n super(\"fail\", attributes, child);\n }\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // If the child has never been updated or is running then we will need to update it now.\n if (this.child.getState() === State.READY || this.child.getState() === State.RUNNING) {\n this.child.update(agent, options);\n }\n\n // The state of this node will depend in the state of its child.\n switch (this.child.getState()) {\n case State.RUNNING:\n this.setState(State.RUNNING);\n break;\n\n case State.SUCCEEDED:\n case State.FAILED:\n this.setState(State.FAILED);\n break;\n\n default:\n this.setState(State.READY);\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => \"FAIL\";\n}\n", "import Decorator from \"./Decorator\";\nimport State from \"../../State\";\nimport Node from \"../Node\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A Flip node.\n * This node wraps a single child and will flip the state of the child state.\n */\nexport default class Flip extends Decorator {\n /**\n * @param attributes The node attributes.\n * @param child The child node.\n */\n constructor(attributes: Attribute[], child: Node) {\n super(\"flip\", attributes, child);\n }\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // If the child has never been updated or is running then we will need to update it now.\n if (this.child.getState() === State.READY || this.child.getState() === State.RUNNING) {\n this.child.update(agent, options);\n }\n\n // The state of this node will depend in the state of its child.\n switch (this.child.getState()) {\n case State.RUNNING:\n this.setState(State.RUNNING);\n break;\n\n case State.SUCCEEDED:\n this.setState(State.FAILED);\n break;\n\n case State.FAILED:\n this.setState(State.SUCCEEDED);\n break;\n\n default:\n this.setState(State.READY);\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => \"FLIP\";\n}\n", "import Node from \"../Node\";\nimport Decorator from \"./Decorator\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A REPEAT node.\n * The node has a single child which can have:\n * -- A number of iterations for which to repeat the child node.\n * -- An infinite repeat loop if neither an iteration count or a condition function is defined.\n * The REPEAT node will stop and have a 'FAILED' state if its child is ever in a 'FAILED' state after an update.\n * The REPEAT node will attempt to move on to the next iteration if its child is ever in a 'SUCCEEDED' state.\n */\nexport default class Repeat extends Decorator {\n /**\n * @param attributes The node attributes.\n * @param iterations The number of iterations to repeat the child node.\n * @param iterationsMin The minimum possible number of iterations to repeat the child node.\n * @param iterationsMax The maximum possible number of iterations to repeat the child node.\n * @param child The child node.\n */\n constructor(\n attributes: Attribute[],\n private iterations: number | null,\n private iterationsMin: number | null,\n private iterationsMax: number | null,\n child: Node\n ) {\n super(\"repeat\", attributes, child);\n }\n\n /**\n * The number of target iterations to make.\n */\n private targetIterationCount: number | null = null;\n\n /**\n * The current iteration count.\n */\n private currentIterationCount: number = 0;\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // If this node is in the READY state then we need to reset the child and the target iteration count.\n if (this.is(State.READY)) {\n // Reset the child node.\n this.child.reset();\n\n // Reset the current iteration count.\n this.currentIterationCount = 0;\n\n // Set the target iteration count.\n this.setTargetIterationCount(options);\n }\n\n // Do a check to see if we can iterate. If we can then this node will move into the 'RUNNING' state.\n // If we cannot iterate then we have hit our target iteration count, which means that the node has succeeded.\n if (this.canIterate()) {\n // This node is in the running state and can do its initial iteration.\n this.setState(State.RUNNING);\n\n // We may have already completed an iteration, meaning that the child node will be in the SUCCEEDED state.\n // If this is the case then we will have to reset the child node now.\n if (this.child.getState() === State.SUCCEEDED) {\n this.child.reset();\n }\n\n // Update the child of this node.\n this.child.update(agent, options);\n\n // If the child moved into the FAILED state when we updated it then there is nothing left to do and this node has also failed.\n // If it has moved into the SUCCEEDED state then we have completed the current iteration.\n if (this.child.getState() === State.FAILED) {\n // The child has failed, meaning that this node has failed.\n this.setState(State.FAILED);\n\n return;\n } else if (this.child.getState() === State.SUCCEEDED) {\n // We have completed an iteration.\n this.currentIterationCount += 1;\n }\n } else {\n // This node is in the 'SUCCEEDED' state as we cannot iterate any more.\n this.setState(State.SUCCEEDED);\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => {\n if (this.iterations !== null) {\n return `REPEAT ${this.iterations}x`;\n } else if (this.iterationsMin !== null && this.iterationsMax !== null) {\n return `REPEAT ${this.iterationsMin}x-${this.iterationsMax}x`;\n } else {\n return \"REPEAT\";\n }\n };\n\n /**\n * Reset the state of the node.\n */\n reset = () => {\n // Reset the state of this node.\n this.setState(State.READY);\n\n // Reset the current iteration count.\n this.currentIterationCount = 0;\n\n // Reset the child node.\n this.child.reset();\n };\n\n /**\n * Gets whether an iteration can be made.\n * @returns Whether an iteration can be made.\n */\n private canIterate = () => {\n if (this.targetIterationCount !== null) {\n // We can iterate as long as we have not reached our target iteration count.\n return this.currentIterationCount < this.targetIterationCount;\n }\n\n // If neither an iteration count or a condition function were defined then we can iterate indefinitely.\n return true;\n };\n\n /**\n * Sets the target iteration count.\n * @param options The behaviour tree options object.\n */\n private setTargetIterationCount = (options: BehaviourTreeOptions) => {\n // Are we dealing with an explicit iteration count or will we be randomly picking a iteration count between the min and max iteration count.\n if (this.iterations !== null) {\n this.targetIterationCount = this.iterations;\n } else if (this.iterationsMin !== null && this.iterationsMax !== null) {\n // We will be picking a random iteration count between a min and max iteration count, if the optional 'random'\n // behaviour tree function option is defined then we will be using that, otherwise we will fall back to using Math.random.\n const random = typeof options.random === \"function\" ? options.random : Math.random;\n\n // Pick a random iteration count between a min and max iteration count.\n this.targetIterationCount = Math.floor(\n random() * (this.iterationsMax - this.iterationsMin + 1) + this.iterationsMin\n );\n } else {\n this.targetIterationCount = null;\n }\n };\n}\n", "import Node from \"../Node\";\nimport Decorator from \"./Decorator\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A RETRY node.\n * The node has a single child which can have:\n * -- A number of iterations for which to repeat the child node.\n * -- An infinite repeat loop if neither an iteration count or a condition function is defined.\n * The RETRY node will stop and have a 'SUCCEEDED' state if its child is ever in a 'SUCCEEDED' state after an update.\n * The RETRY node will attempt to move on to the next iteration if its child is ever in a 'FAILED' state.\n */\nexport default class Retry extends Decorator {\n /**\n * @param attributes The node attributes.\n * @param attempts The number of attempts to retry the child node.\n * @param attemptsMin The minimum possible number of attempts to retry the child node.\n * @param attemptsMax The maximum possible number of attempts to retry the child node.\n * @param child The child node.\n */\n constructor(\n attributes: Attribute[],\n private attempts: number | null,\n private attemptsMin: number | null,\n private attemptsMax: number | null,\n child: Node\n ) {\n super(\"retry\", attributes, child);\n }\n\n /**\n * The number of target attempts to make.\n */\n private targetAttemptCount: number | null = null;\n\n /**\n * The current attempt count.\n */\n private currentAttemptCount: number = 0;\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // If this node is in the READY state then we need to reset the child and the target attempt count.\n if (this.is(State.READY)) {\n // Reset the child node.\n this.child.reset();\n\n // Reset the current attempt count.\n this.currentAttemptCount = 0;\n\n // Set the target attempt count.\n this.setTargetAttemptCount(options);\n }\n\n // Do a check to see if we can attempt. If we can then this node will move into the 'RUNNING' state.\n // If we cannot attempt then we have hit our target attempt count, which means that the node has succeeded.\n if (this.canAttempt()) {\n // This node is in the running state and can do its initial attempt.\n this.setState(State.RUNNING);\n\n // We may have already completed an attempt, meaning that the child node will be in the FAILED state.\n // If this is the case then we will have to reset the child node now.\n if (this.child.getState() === State.FAILED) {\n this.child.reset();\n }\n\n // Update the child of this node.\n this.child.update(agent, options);\n\n // If the child moved into the SUCCEEDED state when we updated it then there is nothing left to do and this node has also succeeded.\n // If it has moved into the FAILED state then we have completed the current attempt.\n if (this.child.getState() === State.SUCCEEDED) {\n // The child has succeeded, meaning that this node has succeeded.\n this.setState(State.SUCCEEDED);\n\n return;\n } else if (this.child.getState() === State.FAILED) {\n // We have completed an attempt.\n this.currentAttemptCount += 1;\n }\n } else {\n // This node is in the 'FAILED' state as we cannot iterate any more.\n this.setState(State.FAILED);\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => {\n if (this.attempts !== null) {\n return `RETRY ${this.attempts}x`;\n } else if (this.attemptsMin !== null && this.attemptsMax !== null) {\n return `RETRY ${this.attemptsMin}x-${this.attemptsMax}x`;\n } else {\n return \"RETRY\";\n }\n };\n\n /**\n * Reset the state of the node.\n */\n reset = () => {\n // Reset the state of this node.\n this.setState(State.READY);\n\n // Reset the current attempt count.\n this.currentAttemptCount = 0;\n\n // Reset the child node.\n this.child.reset();\n };\n\n /**\n * Gets whether an attempt can be made.\n * @returns Whether an attempt can be made.\n */\n canAttempt = () => {\n if (this.targetAttemptCount !== null) {\n // We can attempt as long as we have not reached our target attempt count.\n return this.currentAttemptCount < this.targetAttemptCount;\n }\n\n // If neither an attempt count or a condition function were defined then we can attempt indefinitely.\n return true;\n };\n\n /**\n * Sets the target attempt count.\n * @param options The behaviour tree options object.\n */\n setTargetAttemptCount = (options: BehaviourTreeOptions) => {\n // Are we dealing with an explicit attempt count or will we be randomly picking an attempt count between the min and max attempt count.\n if (this.attempts !== null) {\n this.targetAttemptCount = this.attempts;\n } else if (this.attemptsMin !== null && this.attemptsMax !== null) {\n // We will be picking a random attempt count between a min and max attempt count, if the optional 'random'\n // behaviour tree function option is defined then we will be using that, otherwise we will fall back to using Math.random.\n const random = typeof options.random === \"function\" ? options.random : Math.random;\n\n // Pick a random attempt count between a min and max attempt count.\n this.targetAttemptCount = Math.floor(\n random() * (this.attemptsMax - this.attemptsMin + 1) + this.attemptsMin\n );\n } else {\n this.targetAttemptCount = null;\n }\n };\n}\n", "import Node from \"../Node\";\nimport Decorator from \"./Decorator\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A Root node.\n * The root node will have a single child.\n */\nexport default class Root extends Decorator {\n /**\n * @param attributes The node attributes.\n * @param child The child node.\n */\n constructor(attributes: Attribute[], child: Node) {\n super(\"root\", attributes, child);\n }\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // If the child has never been updated or is running then we will need to update it now.\n if (this.child.getState() === State.READY || this.child.getState() === State.RUNNING) {\n // Update the child of this node.\n this.child.update(agent, options);\n }\n\n // The state of the root node is the state of its child.\n this.setState(this.child.getState());\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => \"ROOT\";\n}\n", "import Node from \"../Node\";\nimport Decorator from \"./Decorator\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A Succeed node.\n * This node wraps a single child and will always move to the 'SUCCEEDED' state when the child moves to a 'SUCCEEDED' or 'FAILED' state.\n */\nexport default class Succeed extends Decorator {\n /**\n * @param attributes The node attributes.\n * @param child The child node.\n */\n constructor(attributes: Attribute[], child: Node) {\n super(\"succeed\", attributes, child);\n }\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // If the child has never been updated or is running then we will need to update it now.\n if (this.child.getState() === State.READY || this.child.getState() === State.RUNNING) {\n this.child.update(agent, options);\n }\n\n // The state of this node will depend in the state of its child.\n switch (this.child.getState()) {\n case State.RUNNING:\n this.setState(State.RUNNING);\n break;\n\n case State.SUCCEEDED:\n case State.FAILED:\n this.setState(State.SUCCEEDED);\n break;\n\n default:\n this.setState(State.READY);\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => \"SUCCEED\";\n}\n", "import Node from \"../Node\";\n\n/**\n * A leaf node.\n */\nexport default abstract class Leaf extends Node {\n /**\n * Gets whether this node is a leaf node.\n */\n isLeafNode = () => true;\n}\n", "import { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\nimport State, { CompleteState } from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Leaf from \"./Leaf\";\nimport Lookup from \"../../Lookup\";\nimport Attribute from \"../../attributes/Attribute\";\n\n/**\n * The type representing a resolved/rejected update promise.\n */\ntype UpdatePromiseResult = {\n /**\n * Whether the promise was resolved rather than rejected.\n */\n isResolved: boolean;\n\n /**\n * The promise resolved value or rejection reason.\n */\n value: any;\n};\n\n/**\n * An Action leaf node.\n * This represents an immediate or ongoing state of behaviour.\n */\nexport default class Action extends Leaf {\n /**\n * @param attributes The node attributes.\n * @param actionName The action name.\n * @param actionArguments The array of action argument definitions.\n */\n constructor(attributes: Attribute[], private actionName: string, private actionArguments: any[]) {\n super(\"action\", attributes, actionArguments);\n }\n\n /**\n * Whether there is a pending update promise.\n */\n private isUsingUpdatePromise = false;\n\n /**\n * The finished state result of an update promise.\n */\n private updatePromiseResult: UpdatePromiseResult | null = null;\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // If the result of this action depends on an update promise then there is nothing to do until it settles.\n if (this.isUsingUpdatePromise) {\n // Are we still waiting for our update promise to settle?\n if (!this.updatePromiseResult) {\n return;\n }\n\n const { isResolved, value } = this.updatePromiseResult;\n\n // Our update promise settled, was it resolved or rejected?\n if (isResolved) {\n // Our promise resolved so check to make sure the result is a valid finished state.\n if (value !== State.SUCCEEDED && value !== State.FAILED) {\n throw new Error(\n \"action node promise resolved with an invalid value, expected a State.SUCCEEDED or State.FAILED value to be returned\"\n );\n }\n\n // Set the state of this node to match the state returned by the promise.\n this.setState(value);\n\n return;\n } else {\n // The promise was rejected, which isn't great.\n throw new Error(`action function '${this.actionName}' promise rejected with '${value}'`);\n }\n }\n\n // Attempt to get the invoker for the action function.\n const actionFuncInvoker = Lookup.getFuncInvoker(agent, this.actionName);\n\n // The action function should be defined.\n if (actionFuncInvoker === null) {\n throw new Error(\n `cannot update action node as the action '${this.actionName}' function is not defined on the agent and has not been registered`\n );\n }\n\n let actionFunctionResult;\n\n try {\n // Call the action function, the result of which may be:\n // - The finished state of this action node.\n // - A promise to return a finished node state.\n // - Undefined if the node should remain in the running state.\n actionFunctionResult = actionFuncInvoker(this.actionArguments) as CompleteState | Promise;\n } catch (error) {\n // An uncaught error was thrown.\n if (error instanceof Error) {\n throw new Error(`action function '${this.actionName}' threw: ${error.stack}`);\n } else {\n throw new Error(`action function '${this.actionName}' threw: ${error}`);\n }\n }\n\n if (actionFunctionResult instanceof Promise) {\n actionFunctionResult.then(\n (result) => {\n // If 'isUpdatePromisePending' is not set then the promise was cleared as it was resolving, probably via an abort of reset.\n if (!this.isUsingUpdatePromise) {\n return;\n }\n\n // Set the resolved update promise result so that it can be handled on the next update of this node.\n this.updatePromiseResult = {\n isResolved: true,\n value: result\n };\n },\n (reason) => {\n // If 'isUpdatePromisePending' is not set then the promise was cleared as it was resolving, probably via an abort or reset.\n if (!this.isUsingUpdatePromise) {\n return;\n }\n\n // Set the rejected update promise result so that it can be handled on the next update of this node.\n this.updatePromiseResult = {\n isResolved: false,\n value: reason\n };\n }\n );\n\n // This node will be in the 'RUNNING' state until the update promise resolves.\n this.setState(State.RUNNING);\n\n // We are now waiting for the promise returned by the use to resolve before we know what state this node is in.\n this.isUsingUpdatePromise = true;\n } else {\n // Validate the returned value.\n this.validateUpdateResult(actionFunctionResult);\n\n // Set the state of this node, this may be undefined, which just means that the node is still in the 'RUNNING' state.\n this.setState(actionFunctionResult || State.RUNNING);\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => this.actionName;\n\n /**\n * Reset the state of the node.\n */\n reset = () => {\n // Reset the state of this node.\n this.setState(State.READY);\n\n // There is no longer an update promise that we care about.\n this.isUsingUpdatePromise = false;\n this.updatePromiseResult = null;\n };\n\n /**\n * Validate the result of an update function call.\n * @param result The result of an update function call.\n */\n private validateUpdateResult = (result: CompleteState | State.RUNNING) => {\n switch (result) {\n case State.SUCCEEDED:\n case State.FAILED:\n case State.RUNNING:\n case undefined:\n return;\n default:\n throw new Error(\n `expected action function '${this.actionName}' to return an optional State.SUCCEEDED or State.FAILED value but returned '${result}'`\n );\n }\n };\n}\n", "import { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Leaf from \"./Leaf\";\nimport Lookup from \"../../Lookup\";\nimport Attribute from \"../../attributes/Attribute\";\n\n/**\n * A Condition leaf node.\n * This will succeed or fail immediately based on an agent predicate, without moving to the 'RUNNING' state.\n */\nexport default class Condition extends Leaf {\n /**\n * @param attributes The node attributes.\n * @param conditionName The name of the condition function.\n * @param conditionArguments The array of condition argument definitions.\n */\n constructor(attributes: Attribute[], private conditionName: string, private conditionArguments: any[]) {\n super(\"condition\", attributes, conditionArguments);\n }\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // Attempt to get the invoker for the condition function.\n const conditionFuncInvoker = Lookup.getFuncInvoker(agent, this.conditionName);\n\n // The condition function should be defined.\n if (conditionFuncInvoker === null) {\n throw new Error(\n `cannot update condition node as the condition '${this.conditionName}' function is not defined on the agent and has not been registered`\n );\n }\n\n let conditionFunctionResult;\n\n try {\n // Call the condition function to determine the state of this node, the result of which should be a boolean.\n conditionFunctionResult = conditionFuncInvoker(this.conditionArguments);\n } catch (error) {\n // An uncaught error was thrown.\n if (error instanceof Error) {\n throw new Error(`condition function '${this.conditionName}' threw: ${error.stack}`);\n } else {\n throw new Error(`condition function '${this.conditionName}' threw: ${error}`);\n }\n }\n\n // The result of calling the condition function must be a boolean value.\n if (typeof conditionFunctionResult !== \"boolean\") {\n throw new Error(\n `expected condition function '${this.conditionName}' to return a boolean but returned '${conditionFunctionResult}'`\n );\n }\n\n // Set the state of this node based on the result of calling the condition function.\n this.setState(!!conditionFunctionResult ? State.SUCCEEDED : State.FAILED);\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => this.conditionName;\n}\n", "import Leaf from \"./Leaf\";\nimport State from \"../../State\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { Agent } from \"../../Agent\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A WAIT node.\n * The state of this node will change to SUCCEEDED after a duration of time\n */\nexport default class Wait extends Leaf {\n /**\n * @param attributes The node attributes.\n * @param duration The duration that this node will wait to succeed in milliseconds.\n * @param durationMin The minimum possible duration in milliseconds that this node will wait to succeed.\n * @param durationMax The maximum possible duration in milliseconds that this node will wait to succeed.\n */\n constructor(\n attributes: Attribute[],\n private duration: number | null,\n private durationMin: number | null,\n private durationMax: number | null\n ) {\n super(\"wait\", attributes, []);\n }\n\n /**\n * The time in milliseconds at which this node was first updated.\n */\n private initialUpdateTime: number = 0;\n\n /**\n * The total duration in milliseconds that this node will be waiting for.\n */\n private totalDuration: number | null = null;\n\n /**\n * The duration in milliseconds that this node has been waiting for.\n */\n private waitedDuration: number = 0;\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // If this node is in the READY state then we need to set the initial update time.\n if (this.is(State.READY)) {\n // Set the initial update time.\n this.initialUpdateTime = new Date().getTime();\n\n // Set the initial waited duration.\n this.waitedDuration = 0;\n\n // Are we dealing with an explicit duration or will we be randomly picking a duration between the min and max duration.\n if (this.duration !== null) {\n this.totalDuration = this.duration;\n } else if (this.durationMin !== null && this.durationMax !== null) {\n // We will be picking a random duration between a min and max duration, if the optional 'random' behaviour tree\n // function option is defined then we will be using that, otherwise we will fall back to using Math.random.\n const random = typeof options.random === \"function\" ? options.random : Math.random;\n\n // Pick a random duration between a min and max duration.\n this.totalDuration = Math.floor(\n random() * (this.durationMax - this.durationMin + 1) + this.durationMin\n );\n } else {\n this.totalDuration = null;\n }\n\n // The node is now running until we finish waiting.\n this.setState(State.RUNNING);\n }\n\n // If we have no total duration then this wait node will wait indefinitely until it is aborted.\n if (this.totalDuration === null) {\n return;\n }\n\n // If we have a 'getDeltaTime' function defined as part of our options then we will use it to figure out how long we have waited for.\n if (typeof options.getDeltaTime === \"function\") {\n // Get the delta time.\n const deltaTime = options.getDeltaTime();\n\n // Our delta time must be a valid number and cannot be NaN.\n if (typeof deltaTime !== \"number\" || isNaN(deltaTime)) {\n throw new Error(\"The delta time must be a valid number and not NaN.\");\n }\n\n // Update the amount of time that this node has been waiting for based on the delta time.\n this.waitedDuration += deltaTime * 1000;\n } else {\n // We are not using a delta time, so we will just work out hom much time has passed since the first update.\n this.waitedDuration = new Date().getTime() - this.initialUpdateTime;\n }\n\n // Have we waited long enough?\n if (this.waitedDuration >= this.totalDuration) {\n // We have finished waiting!\n this.setState(State.SUCCEEDED);\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => {\n if (this.duration !== null) {\n return `WAIT ${this.duration}ms`;\n } else if (this.durationMin !== null && this.durationMax !== null) {\n return `WAIT ${this.durationMin}ms-${this.durationMax}ms`;\n } else {\n return \"WAIT\";\n }\n };\n}\n", "import Guard from \"./guards/Guard\";\n\nexport type AttributeDetails = {\n /** The attribute type. */\n type: string;\n\n /** The attribute arguments. */\n args: any[];\n};\n\n/**\n * A base node attribute.\n */\nexport default abstract class Attribute {\n /**\n * @param type The node attribute type.\n * @param args The array of attribute arguments.\n */\n constructor(public type: string, public args: any[]) {}\n\n /**\n * Gets the attribute details.\n */\n abstract getDetails(): TAttributeDetails;\n\n /**\n * Gets whether this attribute is a guard.\n */\n abstract isGuard: () => this is Guard;\n}\n", "import { Agent } from \"../../Agent\";\nimport Attribute, { AttributeDetails } from \"../Attribute\";\n\nexport type GuardAttributeDetails = {\n /** The name of the condition function that determines whether the guard is satisfied. */\n condition: string;\n} & AttributeDetails;\n\n/**\n * A base node guard attribute.\n */\nexport default abstract class Guard extends Attribute {\n /**\n * @param type The node attribute type.\n * @param args The array of decorator argument definitions.\n * @param condition The name of the condition function that determines whether the guard is satisfied.\n */\n constructor(type: string, args: any[], private condition: string) {\n super(type, args);\n }\n\n /**\n * Gets the name of the condition function that determines whether the guard is satisfied.\n */\n getCondition = () => this.condition;\n\n /**\n * Gets whether this attribute is a guard.\n */\n isGuard = () => true;\n\n /**\n * Gets the attribute details.\n */\n getDetails(): GuardAttributeDetails {\n return {\n type: this.type,\n args: this.args,\n condition: this.getCondition()\n };\n }\n\n /**\n * Gets whether the guard is satisfied.\n * @param agent The agent.\n * @returns Whether the guard is satisfied.\n */\n abstract isSatisfied(agent: Agent): boolean;\n}\n", "import Guard from \"./Guard\";\nimport Lookup from \"../../Lookup\";\nimport { Agent } from \"../../Agent\";\n\n/**\n * A WHILE guard which is satisfied as long as the given condition remains true.\n */\nexport default class While extends Guard {\n /**\n * @param condition The name of the condition function that determines whether the guard is satisfied.\n * @param args The array of decorator argument definitions.\n */\n constructor(condition: string, args: any[]) {\n super(\"while\", args, condition);\n }\n\n /**\n * Gets whether the guard is satisfied.\n * @param agent The agent.\n * @returns Whether the guard is satisfied.\n */\n isSatisfied = (agent: Agent) => {\n // Attempt to get the invoker for the condition function.\n const conditionFuncInvoker = Lookup.getFuncInvoker(agent, this.getCondition());\n\n // The condition function should be defined.\n if (conditionFuncInvoker === null) {\n throw new Error(\n `cannot evaluate node guard as the condition '${this.getCondition()}' function is not defined on the agent and has not been registered`\n );\n }\n\n let conditionFunctionResult;\n\n try {\n // Call the guard condition function to determine the state of this node, the result of which should be a boolean.\n conditionFunctionResult = conditionFuncInvoker(this.args);\n } catch (error) {\n // An uncaught error was thrown.\n if (error instanceof Error) {\n throw new Error(`guard condition function '${this.getCondition()}' threw: ${error.stack}`);\n } else {\n throw new Error(`guard condition function '${this.getCondition()}' threw: ${error}`);\n }\n }\n\n // The result of calling the guard condition function must be a boolean value.\n if (typeof conditionFunctionResult !== \"boolean\") {\n throw new Error(\n `expected guard condition function '${this.getCondition()}' to return a boolean but returned '${conditionFunctionResult}'`\n );\n }\n\n // Return whether this guard is satisfied.\n return conditionFunctionResult;\n };\n}\n", "import Guard from \"./Guard\";\nimport Lookup from \"../../Lookup\";\nimport { Agent } from \"../../Agent\";\n\n/**\n * An UNTIL guard which is satisfied as long as the given condition remains false.\n */\nexport default class Until extends Guard {\n /**\n * @param condition The name of the condition function that determines whether the guard is satisfied.\n * @param args The array of decorator argument definitions.\n */\n constructor(condition: string, args: any[]) {\n super(\"until\", args, condition);\n }\n\n /**\n * Gets whether the guard is satisfied.\n * @param agent The agent.\n * @returns Whether the guard is satisfied.\n */\n isSatisfied = (agent: Agent) => {\n // Attempt to get the invoker for the condition function.\n const conditionFuncInvoker = Lookup.getFuncInvoker(agent, this.getCondition());\n\n // The condition function should be defined.\n if (conditionFuncInvoker === null) {\n throw new Error(\n `cannot evaluate node guard as the condition '${this.getCondition()}' function is not defined on the agent and has not been registered`\n );\n }\n\n let conditionFunctionResult;\n\n try {\n // Call the guard condition function to determine the state of this node, the result of which should be a boolean.\n conditionFunctionResult = conditionFuncInvoker(this.args);\n } catch (error) {\n // An uncaught error was thrown.\n if (error instanceof Error) {\n throw new Error(`guard condition function '${this.getCondition()}' threw: ${error.stack}`);\n } else {\n throw new Error(`guard condition function '${this.getCondition()}' threw: ${error}`);\n }\n }\n\n // The result of calling the guard condition function must be a boolean value.\n if (typeof conditionFunctionResult !== \"boolean\") {\n throw new Error(\n `expected guard condition function '${this.getCondition()}' to return a boolean but returned '${conditionFunctionResult}'`\n );\n }\n\n // Return whether this guard is satisfied.\n return !conditionFunctionResult;\n };\n}\n", "import { Agent } from \"../../Agent\";\nimport Attribute, { AttributeDetails } from \"../Attribute\";\n\nexport type CallbackAttributeDetails = {\n /** The name of the agent function that is called. */\n functionName: string;\n} & AttributeDetails;\n\n/**\n * A base node callback attribute.\n */\nexport default abstract class Callback extends Attribute {\n /**\n * @param type The node attribute type.\n * @param args The array of decorator argument definitions.\n * @param functionName The name of the agent function to call.\n */\n constructor(type: string, args: any[], private functionName: string) {\n super(type, args);\n }\n\n /**\n * Gets the name of the agent function to call.\n */\n getFunctionName = () => this.functionName;\n\n /**\n * Gets whether this attribute is a guard.\n */\n isGuard = () => false;\n\n /**\n * Gets the attribute details.\n */\n getDetails(): CallbackAttributeDetails {\n return {\n type: this.type,\n args: this.args,\n functionName: this.getFunctionName()\n };\n }\n\n /**\n * Attempt to call the agent function that this callback refers to.\n * @param agent The agent.\n */\n abstract callAgentFunction: (agent: Agent, isSuccess: boolean, isAborted: boolean) => void;\n}\n", "import Callback from \"./Callback\";\nimport Lookup from \"../../Lookup\";\nimport { Agent } from \"../../Agent\";\n\n/**\n * An ENTRY callback which defines an agent function to call when the associated node is updated and moves out of running state.\n */\nexport default class Entry extends Callback {\n /**\n * @param functionName The name of the agent function to call.\n * @param args The array of callback argument definitions.\n */\n constructor(functionName: string, args: any[]) {\n super(\"entry\", args, functionName);\n }\n\n /**\n * Attempt to call the agent function that this callback refers to.\n * @param agent The agent.\n */\n callAgentFunction = (agent: Agent) => {\n // Attempt to get the invoker for the callback function.\n const callbackFuncInvoker = Lookup.getFuncInvoker(agent, this.getFunctionName());\n\n // The callback function should be defined.\n if (callbackFuncInvoker === null) {\n throw new Error(\n `cannot call entry function '${this.getFunctionName()}' as is not defined on the agent and has not been registered`\n );\n }\n\n // Call the callback function.\n callbackFuncInvoker(this.args);\n };\n}\n", "import Callback from \"./Callback\";\nimport Lookup from \"../../Lookup\";\nimport { Agent } from \"../../Agent\";\n\n/**\n * A STEP callback which defines an agent function to call when the associated node is updated.\n */\nexport default class Step extends Callback {\n /**\n * @param functionName The name of the agent function to call.\n * @param args The array of callback argument definitions.\n */\n constructor(functionName: string, args: any[]) {\n super(\"step\", args, functionName);\n }\n\n /**\n * Attempt to call the agent function that this callback refers to.\n * @param agent The agent.\n */\n callAgentFunction = (agent: Agent) => {\n // Attempt to get the invoker for the callback function.\n const callbackFuncInvoker = Lookup.getFuncInvoker(agent, this.getFunctionName());\n\n // The callback function should be defined.\n if (callbackFuncInvoker === null) {\n throw new Error(\n `cannot call step function '${this.getFunctionName()}' as is not defined on the agent and has not been registered`\n );\n }\n\n // Call the callback function.\n callbackFuncInvoker(this.args);\n };\n}\n", "import Callback from \"./Callback\";\nimport Lookup from \"../../Lookup\";\nimport { Agent } from \"../../Agent\";\n\n/**\n * An EXIT callback which defines an agent function to call when the associated node is updated and moves to a finished state or is aborted.\n */\nexport default class Exit extends Callback {\n /**\n * @param functionName The name of the agent function to call.\n * @param args The array of callback argument definitions.\n */\n constructor(functionName: string, args: any[]) {\n super(\"exit\", args, functionName);\n }\n\n /**\n * Attempt to call the agent function that this callback refers to.\n * @param agent The agent.\n * @param isSuccess Whether the decorated node was left with a success state.\n * @param isAborted Whether the decorated node was aborted.\n */\n callAgentFunction = (agent: Agent, isSuccess: boolean, isAborted: boolean) => {\n // Attempt to get the invoker for the callback function.\n const callbackFuncInvoker = Lookup.getFuncInvoker(agent, this.getFunctionName());\n\n // The callback function should be defined.\n if (callbackFuncInvoker === null) {\n throw new Error(\n `cannot call exit function '${this.getFunctionName()}' as is not defined on the agent and has not been registered`\n );\n }\n\n // Call the callback function\n callbackFuncInvoker([{ succeeded: isSuccess, aborted: isAborted }, ...this.args]);\n };\n}\n", "import { AnyNodeDefinition, RootNodeDefinition } from \"./BehaviourTreeDefinition\";\nimport GuardPath, { GuardPathPart } from \"./attributes/guards/GuardPath\";\nimport { validateBranchSubtreeLinks } from \"./BehaviourTreeDefinitionValidator\";\nimport { isInteger } from \"./BehaviourTreeDefinitionUtilities\";\nimport Node from \"./nodes/Node\";\nimport Composite from \"./nodes/composite/Composite\";\nimport Decorator from \"./nodes/decorator/Decorator\";\nimport Parallel from \"./nodes/composite/Parallel\";\nimport Selector from \"./nodes/composite/Selector\";\nimport Sequence from \"./nodes/composite/Sequence\";\nimport Lotto from \"./nodes/composite/Lotto\";\nimport Fail from \"./nodes/decorator/Fail\";\nimport Flip from \"./nodes/decorator/Flip\";\nimport Repeat from \"./nodes/decorator/Repeat\";\nimport Retry from \"./nodes/decorator/Retry\";\nimport Root from \"./nodes/decorator/Root\";\nimport Succeed from \"./nodes/decorator/Succeed\";\nimport Action from \"./nodes/leaf/Action\";\nimport Condition from \"./nodes/leaf/Condition\";\nimport Wait from \"./nodes/leaf/Wait\";\nimport Lookup from \"./Lookup\";\nimport Attribute from \"./attributes/Attribute\";\nimport While from \"./attributes/guards/While\";\nimport Until from \"./attributes/guards/Until\";\nimport Entry from \"./attributes/callbacks/Entry\";\nimport Step from \"./attributes/callbacks/Step\";\nimport Exit from \"./attributes/callbacks/Exit\";\n\n/**\n * A type representing any node instance in a behaviour tree.\n */\ntype AnyNode =\n | Root\n | Action\n | Condition\n | Wait\n | Sequence\n | Selector\n | Lotto\n | Parallel\n | Repeat\n | Retry\n | Flip\n | Succeed\n | Fail;\n\n/**\n * A type defining a mapping of root node identifiers to root node definitions.\n */\ntype RootNodeDefinitionMap = { [key: string | symbol]: RootNodeDefinition };\n\n/**\n * A symbol to use as the main root key in any root node mappings.\n */\nconst MAIN_ROOT_NODE_KEY = Symbol(\"__root__\");\n\n/**\n * Build and populate the root nodes based on the provided definition, assuming that the definition has been validated.\n * @param definition The root node definitions.\n * @returns The built and populated root node definitions.\n */\nexport default function buildRootNode(definition: RootNodeDefinition[]): Root {\n // Create a mapping of root node identifers to root node definitions, including globally registered subtree root node definitions.\n const rootNodeDefinitionMap = createRootNodeDefinitionMap(definition);\n\n // Now that we have all of our root node definitions (those part of the tree definition and those globally registered)\n // we should validate the branch-subtree links. This will also double-check that we dont have any circular dependencies\n // in our branch-subtree references and that we have no broken branch-subtree links.\n validateBranchSubtreeLinks(\n [rootNodeDefinitionMap[MAIN_ROOT_NODE_KEY], ...Object.values(rootNodeDefinitionMap)],\n true\n );\n\n // Create our populated tree of node instances, starting with our main root node.\n const rootNode = nodeFactory(rootNodeDefinitionMap[MAIN_ROOT_NODE_KEY], rootNodeDefinitionMap) as Root;\n\n // Set a guard path on every leaf of the tree to evaluate as part of each update.\n applyLeafNodeGuardPaths(rootNode);\n\n // We only need to return the main root node.\n return rootNode;\n}\n\n/**\n * A factory function which creates a node instance based on the specified definition.\n * @param definition The node definition.\n * @param rootNodeDefinitionMap The mapping of root node identifers to root node definitions, including globally registered subtree root node definitions.\n * @returns A node instance based on the specified definition.\n */\nfunction nodeFactory(definition: AnyNodeDefinition, rootNodeDefinitionMap: RootNodeDefinitionMap): AnyNode {\n // Get the attributes for the node.\n const attributes = nodeAttributesFactory(definition);\n\n // Create the node instance based on the definition type.\n switch (definition.type) {\n case \"root\":\n return new Root(attributes, nodeFactory(definition.child, rootNodeDefinitionMap));\n\n case \"repeat\":\n let iterations: number | null = null;\n let iterationsMin: number | null = null;\n let iterationsMax: number | null = null;\n\n if (Array.isArray(definition.iterations)) {\n iterationsMin = definition.iterations[0];\n iterationsMax = definition.iterations[1];\n } else if (isInteger(definition.iterations)) {\n iterations = definition.iterations!;\n }\n\n return new Repeat(\n attributes,\n iterations,\n iterationsMin,\n iterationsMax,\n nodeFactory(definition.child, rootNodeDefinitionMap)\n );\n\n case \"retry\":\n let attempts: number | null = null;\n let attemptsMin: number | null = null;\n let attemptsMax: number | null = null;\n\n if (Array.isArray(definition.attempts)) {\n attemptsMin = definition.attempts[0];\n attemptsMax = definition.attempts[1];\n } else if (isInteger(definition.attempts)) {\n attempts = definition.attempts!;\n }\n\n return new Retry(\n attributes,\n attempts,\n attemptsMin,\n attemptsMax,\n nodeFactory(definition.child, rootNodeDefinitionMap)\n );\n\n case \"flip\":\n return new Flip(attributes, nodeFactory(definition.child, rootNodeDefinitionMap));\n\n case \"succeed\":\n return new Succeed(attributes, nodeFactory(definition.child, rootNodeDefinitionMap));\n\n case \"fail\":\n return new Fail(attributes, nodeFactory(definition.child, rootNodeDefinitionMap));\n\n case \"sequence\":\n return new Sequence(\n attributes,\n definition.children.map((child) => nodeFactory(child, rootNodeDefinitionMap))\n );\n\n case \"selector\":\n return new Selector(\n attributes,\n definition.children.map((child) => nodeFactory(child, rootNodeDefinitionMap))\n );\n\n case \"parallel\":\n return new Parallel(\n attributes,\n definition.children.map((child) => nodeFactory(child, rootNodeDefinitionMap))\n );\n\n case \"lotto\":\n return new Lotto(\n attributes,\n definition.weights,\n definition.children.map((child) => nodeFactory(child, rootNodeDefinitionMap))\n );\n\n case \"branch\":\n return nodeFactory(rootNodeDefinitionMap[definition.ref].child, rootNodeDefinitionMap);\n\n case \"action\":\n return new Action(attributes, definition.call, definition.args || []);\n\n case \"condition\":\n return new Condition(attributes, definition.call, definition.args || []);\n\n case \"wait\":\n let duration: number | null = null;\n let durationMin: number | null = null;\n let durationMax: number | null = null;\n\n if (Array.isArray(definition.duration)) {\n durationMin = definition.duration[0];\n durationMax = definition.duration[1];\n } else if (isInteger(definition.duration)) {\n duration = definition.duration!;\n }\n\n return new Wait(attributes, duration, durationMin, durationMax);\n }\n}\n\n/**\n * Creates an array of node attribute instances based on the specified node definition.\n * @param definition The node definition.\n * @returns An array of node attribute instances based on the specified node definition.\n */\nfunction nodeAttributesFactory(definition: AnyNodeDefinition): Attribute[] {\n const attributes: Attribute[] = [];\n\n if (definition.while) {\n attributes.push(new While(definition.while.call, definition.while.args ?? []));\n }\n\n if (definition.until) {\n attributes.push(new Until(definition.until.call, definition.until.args ?? []));\n }\n\n if (definition.entry) {\n attributes.push(new Entry(definition.entry.call, definition.entry.args ?? []));\n }\n\n if (definition.step) {\n attributes.push(new Step(definition.step.call, definition.step.args ?? []));\n }\n\n if (definition.exit) {\n attributes.push(new Exit(definition.exit.call, definition.exit.args ?? []));\n }\n\n return attributes;\n}\n\n/**\n * Creates a mapping of root node identifers to root node definitions, mixing in globally registered subtree root node definitions.\n * @param definition The root node definitions.\n * @returns A mapping of root node identifers to root node definitions, including globally registered subtree root node definitions.\n */\nfunction createRootNodeDefinitionMap(definition: RootNodeDefinition[]): RootNodeDefinitionMap {\n // Create a mapping of root node identifers to root node definitions.\n const rootNodeMap: RootNodeDefinitionMap = {};\n\n // Add in any registered subtree root node definitions.\n for (const [name, rootNodeDefinition] of Object.entries(Lookup.getSubtrees())) {\n // The name used when registering the subtree will be used as the root node identifier.\n rootNodeMap[name] = { ...rootNodeDefinition, id: name };\n }\n\n // Populate the map with the root node definitions that were included with the tree definition.\n // We do this after adding any registered subtrees as we want these to take presedence.\n for (const rootNodeDefinition of definition) {\n rootNodeMap[rootNodeDefinition.id ?? MAIN_ROOT_NODE_KEY] = rootNodeDefinition;\n }\n\n return rootNodeMap;\n}\n\n/**\n * Applies a guard path to every leaf of the tree to evaluate as part of each update.\n * @param root The main root tree node.\n */\nfunction applyLeafNodeGuardPaths(root: Root) {\n const nodePaths: Node[][] = [];\n\n const findLeafNodes = (path: Node[], node: Node) => {\n // Add the current node to the path.\n path = path.concat(node);\n\n // Check whether the current node is a leaf node.\n if (node.isLeafNode()) {\n nodePaths.push(path);\n } else {\n (node as Composite | Decorator).getChildren().forEach((child) => findLeafNodes(path, child));\n }\n };\n\n // Find all leaf node paths, starting from the root.\n findLeafNodes([], root);\n\n nodePaths.forEach((path) => {\n // Each node in the current path will have to be assigned a guard path, working from the root outwards.\n for (let depth = 0; depth < path.length; depth++) {\n // Get the node in the path at the current depth.\n const currentNode = path[depth];\n\n // The node may already have been assigned a guard path, if so just skip it.\n if (currentNode.hasGuardPath()) {\n continue;\n }\n\n // Create the guard path for the current node.\n const guardPath = new GuardPath(\n path\n .slice(0, depth + 1)\n .map((node) => ({ node, guards: node.getGuardAttributes() }))\n .filter((details) => details.guards.length > 0)\n );\n\n // Assign the guard path to the current node.\n currentNode.setGuardPath(guardPath);\n }\n });\n}\n", "import State, { AnyState } from \"./State\";\nimport Lookup from \"./Lookup\";\nimport Node from \"./nodes/Node\";\nimport Root from \"./nodes/decorator/Root\";\nimport Composite from \"./nodes/composite/Composite\";\nimport Decorator from \"./nodes/decorator/Decorator\";\nimport { Agent, GlobalFunction } from \"./Agent\";\nimport { CallbackAttributeDetails } from \"./attributes/callbacks/Callback\";\nimport { GuardAttributeDetails } from \"./attributes/guards/Guard\";\nimport { BehaviourTreeOptions } from \"./BehaviourTreeOptions\";\nimport { convertMDSLToJSON } from \"./mdsl/MDSLDefinitionParser\";\nimport { RootNodeDefinition } from \"./BehaviourTreeDefinition\";\nimport { validateDefinition, validateJSONDefinition } from \"./BehaviourTreeDefinitionValidator\";\nimport buildRootNode from \"./BehaviourTreeBuilder\";\nimport { isNullOrUndefined } from \"./BehaviourTreeDefinitionUtilities\";\n\n// Purely for outside inspection of the tree.\nexport type FlattenedTreeNode = {\n id: string;\n type: string;\n caption: string;\n state: AnyState;\n guards: GuardAttributeDetails[];\n callbacks: CallbackAttributeDetails[];\n args: any[];\n parentId: string | null;\n};\n\n/**\n * A representation of a behaviour tree.\n */\nexport class BehaviourTree {\n /**\n * The main root tree node.\n */\n private readonly _rootNode: Root;\n\n /**\n * Creates a new instance of the BehaviourTree class.\n * @param definition The behaviour tree definition as either an MDSL string, root node definition object or array of root node definition objects.\n * @param agent The agent instance that this behaviour tree is modelling behaviour for.\n * @param options The behaviour tree options object.\n */\n constructor(\n definition: string | RootNodeDefinition | RootNodeDefinition[],\n private agent: Agent,\n private options: BehaviourTreeOptions = {}\n ) {\n // The tree definition must be defined.\n if (isNullOrUndefined(definition)) {\n throw new Error(\"tree definition not defined\");\n }\n\n // The agent must be defined and not null.\n if (typeof agent !== \"object\" || agent === null) {\n throw new Error(\"the agent must be an object and not null\");\n }\n\n // We should validate the definition before we try to build the tree nodes.\n const { succeeded, errorMessage, json } = validateDefinition(definition);\n\n // Did our validation fail without error?\n if (!succeeded) {\n throw new Error(`invalid definition: ${errorMessage}`);\n }\n\n // Double check that we did actually get our json definition as part of our definition validtion.\n if (!json) {\n throw new Error(\n \"expected json definition to be returned as part of successful definition validation response\"\n );\n }\n\n try {\n // Create the populated tree of behaviour tree nodes and get the root node.\n this._rootNode = buildRootNode(json);\n } catch (exception) {\n // There was an issue in trying build and populate the behaviour tree.\n throw new Error(`error building tree: ${(exception as Error).message}`);\n }\n }\n\n /**\n * Gets whether the tree is in the RUNNING state.\n * @returns true if the tree is in the RUNNING state, otherwise false.\n */\n isRunning() {\n return this._rootNode.getState() === State.RUNNING;\n }\n\n /**\n * Gets the current tree state of SUCCEEDED, FAILED, READY or RUNNING.\n * @returns The current tree state.\n */\n getState() {\n return this._rootNode.getState();\n }\n\n /**\n * Step the tree.\n * 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.\n * 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\n * 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.\n *\n * 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.\n */\n step() {\n // If the root node has already been stepped to completion then we need to reset it.\n if (this._rootNode.getState() === State.SUCCEEDED || this._rootNode.getState() === State.FAILED) {\n this._rootNode.reset();\n }\n\n try {\n this._rootNode.update(this.agent, this.options);\n } catch (exception) {\n throw new Error(`error stepping tree: ${(exception as Error).message}`);\n }\n }\n\n /**\n * Resets the tree from the root node outwards to each nested node, giving each a state of READY.\n */\n reset() {\n this._rootNode.reset();\n }\n\n /**\n * Gets the flattened details of every node in the tree.\n * @returns The flattened details of every node in the tree.\n */\n getFlattenedNodeDetails(): FlattenedTreeNode[] {\n // Create an empty flattened array of tree nodes.\n const flattenedTreeNodes: FlattenedTreeNode[] = [];\n\n /**\n * Helper function to process a node instance and push details into the flattened tree nodes array.\n * @param node The current node.\n * @param parentUid The UID of the node parent, or null if the node is the main root node.\n */\n const processNode = (node: Node, parentUid: string | null) => {\n // Get the guard and callback attribute details for this node.\n const guards = node\n .getAttributes()\n .filter((attribute) => attribute.isGuard())\n .map((attribute) => attribute.getDetails()) as GuardAttributeDetails[];\n const callbacks = node\n .getAttributes()\n .filter((attribute) => !attribute.isGuard())\n .map((attribute) => attribute.getDetails()) as CallbackAttributeDetails[];\n\n // Push the current node into the flattened nodes array.\n flattenedTreeNodes.push({\n id: node.getUid(),\n type: node.getType(),\n caption: node.getName(),\n state: node.getState(),\n guards,\n callbacks,\n args: node.getArguments(),\n parentId: parentUid\n });\n\n // Process each of the nodes children if it is not a leaf node.\n if (!node.isLeafNode()) {\n (node as Composite | Decorator)\n .getChildren()\n .forEach((child) => processNode(child, (node as Composite | Decorator).getUid()));\n }\n };\n\n // Convert the nested node structure into a flattened array of node details.\n processNode(this._rootNode, null);\n\n return flattenedTreeNodes;\n }\n\n /**\n * Registers the action/condition/guard/callback function or subtree with the given name.\n * @param name The name of the function or subtree to register.\n * @param value The function or subtree definition to register.\n */\n static register(name: string, value: GlobalFunction | string | RootNodeDefinition) {\n // Are we going to register a action/condition/guard/callback function?\n if (typeof value === \"function\") {\n Lookup.setFunc(name, value);\n return;\n }\n\n // We are not registering an action/condition/guard/callback function, so we must be registering a subtree.\n if (typeof value === \"string\") {\n let rootNodeDefinitions: RootNodeDefinition[];\n\n // We will assume that any string passed in will be a mdsl definition.\n try {\n rootNodeDefinitions = convertMDSLToJSON(value);\n } catch (exception) {\n throw new Error(`error registering definition, invalid MDSL: ${(exception as Error).message}`);\n }\n\n // This function should only ever be called with a definition containing a single unnamed root node.\n if (rootNodeDefinitions.length != 1 || rootNodeDefinitions[0].id !== null) {\n throw new Error(\"error registering definition: expected a single unnamed root node\");\n }\n\n try {\n // We should validate the subtree as we don't want invalid subtrees available via the lookup.\n const { succeeded, errorMessage } = validateJSONDefinition(rootNodeDefinitions[0]);\n\n // Did our validation fail without error?\n if (!succeeded) {\n throw new Error(errorMessage);\n }\n } catch (exception) {\n throw new Error(`error registering definition: ${(exception as Error).message}`);\n }\n\n // Everything seems hunky-dory, register the subtree.\n Lookup.setSubtree(name, rootNodeDefinitions[0]);\n } else if (typeof value === \"object\" && !Array.isArray(value)) {\n // We will assume that any object passed in is a root node definition.\n\n try {\n // We should validate the subtree as we don't want invalid subtrees available via the lookup.\n const { succeeded, errorMessage } = validateJSONDefinition(value);\n\n // Did our validation fail without error?\n if (!succeeded) {\n throw new Error(errorMessage);\n }\n } catch (exception) {\n throw new Error(`error registering definition: ${(exception as Error).message}`);\n }\n\n // Everything seems hunky-dory, register the subtree.\n Lookup.setSubtree(name, value);\n } else {\n throw new Error(\"unexpected value, expected string mdsl definition, root node json definition or function\");\n }\n }\n\n /**\n * Unregisters the registered action/condition/guard/callback function or subtree with the given name.\n * @param name The name of the registered action/condition/guard/callback function or subtree to unregister.\n */\n static unregister(name: string): void {\n Lookup.remove(name);\n }\n\n /**\n * Unregister all registered action/condition/guard/callback functions and subtrees.\n */\n static unregisterAll(): void {\n Lookup.empty();\n }\n}\n"], + "mappings": "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", "names": ["Participant", "isNullOrUndefined", "Lotto", "createLotto", "State", "createLotto"] } diff --git a/dist/index.js b/dist/index.js index 6169c18..5a1f275 100644 --- a/dist/index.js +++ b/dist/index.js @@ -1788,7 +1788,11 @@ var Action = class extends Leaf { try { actionFunctionResult = actionFuncInvoker(this.actionArguments); } catch (error) { - throw new Error(`action function '${this.actionName}' threw '${error}'`); + if (error instanceof Error) { + throw new Error(`action function '${this.actionName}' threw: ${error.stack}`); + } else { + throw new Error(`action function '${this.actionName}' threw: ${error}`); + } } if (actionFunctionResult instanceof Promise) { actionFunctionResult.then( @@ -1857,7 +1861,11 @@ var Condition = class extends Leaf { try { conditionFunctionResult = conditionFuncInvoker(this.conditionArguments); } catch (error) { - throw new Error(`condition function '${this.conditionName}' threw '${error}'`); + if (error instanceof Error) { + throw new Error(`condition function '${this.conditionName}' threw: ${error.stack}`); + } else { + throw new Error(`condition function '${this.conditionName}' threw: ${error}`); + } } if (typeof conditionFunctionResult !== "boolean") { throw new Error( @@ -1964,7 +1972,11 @@ var While = class extends Guard { try { conditionFunctionResult = conditionFuncInvoker(this.args); } catch (error) { - throw new Error(`guard condition function '${this.getCondition()}' threw '${error}'`); + if (error instanceof Error) { + throw new Error(`guard condition function '${this.getCondition()}' threw: ${error.stack}`); + } else { + throw new Error(`guard condition function '${this.getCondition()}' threw: ${error}`); + } } if (typeof conditionFunctionResult !== "boolean") { throw new Error( @@ -1991,7 +2003,11 @@ var Until = class extends Guard { try { conditionFunctionResult = conditionFuncInvoker(this.args); } catch (error) { - throw new Error(`guard condition function '${this.getCondition()}' threw '${error}'`); + if (error instanceof Error) { + throw new Error(`guard condition function '${this.getCondition()}' threw: ${error.stack}`); + } else { + throw new Error(`guard condition function '${this.getCondition()}' threw: ${error}`); + } } if (typeof conditionFunctionResult !== "boolean") { throw new Error( diff --git a/dist/index.js.map b/dist/index.js.map index f753e35..082550a 100644 --- a/dist/index.js.map +++ b/dist/index.js.map @@ -1,7 +1,7 @@ { "version": 3, "sources": ["../node_modules/lotto-draw/dist/Participant.js", "../node_modules/lotto-draw/dist/Utilities.js", "../node_modules/lotto-draw/dist/Lotto.js", "../node_modules/lotto-draw/dist/createLotto.js", "../node_modules/lotto-draw/dist/index.js", "../src/index.ts", "../src/State.ts", "../src/BehaviourTreeDefinitionUtilities.ts", "../src/mdsl/MDSLUtilities.ts", "../src/mdsl/MDSLNodeArgumentParser.ts", "../src/mdsl/MDSLNodeAttributeParser.ts", "../src/mdsl/MDSLDefinitionParser.ts", "../src/BehaviourTreeDefinitionValidator.ts", "../src/Lookup.ts", "../src/attributes/guards/GuardUnsatisifedException.ts", "../src/attributes/guards/GuardPath.ts", "../src/nodes/Node.ts", "../src/nodes/composite/Composite.ts", "../src/nodes/composite/Parallel.ts", "../src/nodes/composite/Selector.ts", "../src/nodes/composite/Sequence.ts", "../src/nodes/composite/Lotto.ts", "../src/nodes/decorator/Decorator.ts", "../src/nodes/decorator/Fail.ts", "../src/nodes/decorator/Flip.ts", "../src/nodes/decorator/Repeat.ts", "../src/nodes/decorator/Retry.ts", "../src/nodes/decorator/Root.ts", "../src/nodes/decorator/Succeed.ts", "../src/nodes/leaf/Leaf.ts", "../src/nodes/leaf/Action.ts", "../src/nodes/leaf/Condition.ts", "../src/nodes/leaf/Wait.ts", "../src/attributes/Attribute.ts", "../src/attributes/guards/Guard.ts", "../src/attributes/guards/While.ts", "../src/attributes/guards/Until.ts", "../src/attributes/callbacks/Callback.ts", "../src/attributes/callbacks/Entry.ts", "../src/attributes/callbacks/Step.ts", "../src/attributes/callbacks/Exit.ts", "../src/BehaviourTreeBuilder.ts", "../src/BehaviourTree.ts"], - "sourcesContent": ["\"use strict\";\r\nObject.defineProperty(exports, \"__esModule\", { value: true });\r\nexports.Participant = void 0;\r\n/**\r\n * A participant that holds a number of tickets.\r\n */\r\nvar Participant = /** @class */ (function () {\r\n /**\r\n * Creates an instance of the Participant class.\r\n * @param participant The actual participant.\r\n * @param tickets The number of tickets held by the participant.\r\n */\r\n function Participant(participant, tickets) {\r\n if (tickets === void 0) { tickets = 1; }\r\n this._participant = participant;\r\n this._tickets = tickets;\r\n }\r\n Object.defineProperty(Participant.prototype, \"participant\", {\r\n /** Gets the actual participant. */\r\n get: function () {\r\n return this._participant;\r\n },\r\n enumerable: false,\r\n configurable: true\r\n });\r\n Object.defineProperty(Participant.prototype, \"tickets\", {\r\n /** Gets or sets the number of tickets held by the participant. */\r\n get: function () {\r\n return this._tickets;\r\n },\r\n set: function (value) {\r\n this._tickets = value;\r\n },\r\n enumerable: false,\r\n configurable: true\r\n });\r\n return Participant;\r\n}());\r\nexports.Participant = Participant;\r\n", "\"use strict\";\r\nObject.defineProperty(exports, \"__esModule\", { value: true });\r\nexports.isNaturalNumber = exports.isNullOrUndefined = void 0;\r\n/**\r\n * Gets whether the value provided is null or undefined.\r\n * @param value The value to check.\r\n * @returns Whether the value provided is null or undefined.\r\n */\r\nfunction isNullOrUndefined(value) {\r\n return value === null || value === undefined;\r\n}\r\nexports.isNullOrUndefined = isNullOrUndefined;\r\n/**\r\n * Gets whether the value provided is a natural number.\r\n * @param value The value to check.\r\n * @returns Whether the value provided is a natural number.\r\n */\r\nfunction isNaturalNumber(value) {\r\n return typeof value === \"number\" && value >= 1 && Math.floor(value) === value;\r\n}\r\nexports.isNaturalNumber = isNaturalNumber;\r\n", "\"use strict\";\r\nObject.defineProperty(exports, \"__esModule\", { value: true });\r\nexports.Lotto = void 0;\r\nvar Participant_1 = require(\"./Participant\");\r\nvar Utilities_1 = require(\"./Utilities\");\r\n/**\r\n * Represents a lotto consisting of a number of pickable ticket-holding participants.\r\n */\r\nvar Lotto = /** @class */ (function () {\r\n /**\r\n * Creates a new instance of Lotto.\r\n * @param customRandom The custom RNG to use in place of Math.random().\r\n */\r\n function Lotto(customRandom) {\r\n /** The array of participants that are holding tickets in the lotto. */\r\n this._participants = [];\r\n this._customRandom = customRandom;\r\n }\r\n /**\r\n * Adds a participant with the specified number of tickets, or adds to the participant ticket count if the participant already holds tickets.\r\n * @param participant The participant to add or to increase the ticket count for if they already hold tickets.\r\n * @param tickets The number of tickets, defaults to 1.\r\n * @returns The Lotto instance.\r\n */\r\n Lotto.prototype.add = function (participant, tickets) {\r\n if (tickets === void 0) { tickets = 1; }\r\n // Check that we have a valid ticket count.\r\n if (!(0, Utilities_1.isNaturalNumber)(tickets)) {\r\n throw new Error(\"tickets value must be a natural number\");\r\n }\r\n // Check whether this participant has already been added.\r\n var existingParticipant = this._participants.find(function (part) { return part.participant === participant; });\r\n if (existingParticipant) {\r\n // The participant has already been added to the lotto so just add to their ticket count.\r\n existingParticipant.tickets += tickets;\r\n }\r\n else {\r\n // The participant is not part of the lotto so we should add them.\r\n this._participants.push(new Participant_1.Participant(participant, tickets));\r\n }\r\n return this;\r\n };\r\n /**\r\n * Removes the specified number of tickets for the given participant from the draw, or all tickets if a ticket number is not defined.\r\n * @param participant The participant to remove tickets for.\r\n * @param tickets The number of tickets to remove, or undefined if all tickets are to be removed.\r\n * @returns The Lotto instance.\r\n */\r\n Lotto.prototype.remove = function (participant, tickets) {\r\n // Attempt to get the existing participant.\r\n var existingParticipant = this._participants.find(function (part) { return part.participant === participant; });\r\n // There is nothing to do if the specified participant isn't even part of the lotto.\r\n if (!existingParticipant) {\r\n return this;\r\n }\r\n // Check whether a tickets value was given.\r\n if (tickets !== undefined) {\r\n // Check that we have a valid ticket count.\r\n if (!(0, Utilities_1.isNaturalNumber)(tickets)) {\r\n throw new Error(\"tickets value must be a natural number\");\r\n }\r\n existingParticipant.tickets -= tickets;\r\n // If the participant no longer holds any tickets then they should be removed.\r\n if (existingParticipant.tickets < 1) {\r\n this._participants = this._participants.filter(function (part) { return part !== existingParticipant; });\r\n }\r\n }\r\n else {\r\n // We are removing all tickets for the participant so just remove them from the lotto.\r\n this._participants = this._participants.filter(function (part) { return part !== existingParticipant; });\r\n }\r\n return this;\r\n };\r\n /**\r\n * Draw a winning ticket and return the participant that holds the ticket.\r\n * @param options The draw options.\r\n * @returns The participant that holds the winning ticket.\r\n */\r\n Lotto.prototype.draw = function (options) {\r\n if (options === void 0) { options = {}; }\r\n // If we have no participants then just return null.\r\n if (this._participants.length === 0) {\r\n return null;\r\n }\r\n var redrawable = (0, Utilities_1.isNullOrUndefined)(options.redrawable) ? true : options.redrawable;\r\n var pickable = [];\r\n this._participants.forEach(function (_a) {\r\n var participant = _a.participant, tickets = _a.tickets;\r\n for (var ticketCount = 0; ticketCount < tickets; ticketCount++) {\r\n pickable.push(participant);\r\n }\r\n });\r\n var random;\r\n // We need a random floating-point number between 0 (inclusive) and 1 to scale up to pick our winner.\r\n // If a custom random function exists then we should use that or fall back to Math.random().\r\n if (this._customRandom) {\r\n // Call our custom random function to get a random floating-point number.\r\n random = this._customRandom();\r\n // Verify that the result of calling our custom random function is a number between 0 (inclusive) and 1.\r\n if (typeof random !== \"number\" || random < 0 || random >= 1) {\r\n throw new Error(\"the 'random' function provided did not return a number between 0 (inclusive) and 1\");\r\n }\r\n }\r\n else {\r\n // No custom random function was defined so just use good ol' Math.random().\r\n random = Math.random();\r\n }\r\n // Pick a winning participant.\r\n var winner = pickable[Math.floor(random * pickable.length)];\r\n // If the ticket isn't redrawable then we should remove a ticket from the winning participants ticket count.\r\n if (!redrawable) {\r\n this.remove(winner, 1);\r\n }\r\n // Return the winning participant.\r\n return winner;\r\n };\r\n /**\r\n * Draws multiple winning tickets and return an array of the participants that hold the winning tickets.\r\n * @param tickets The number of winning tickets to draw.\r\n * @param options The draw multiple options.\r\n * @returns An array of the participants that hold the winning tickets.\r\n */\r\n Lotto.prototype.drawMultiple = function (tickets, options) {\r\n if (options === void 0) { options = {}; }\r\n var uniqueResults = (0, Utilities_1.isNullOrUndefined)(options.unique) ? false : options.unique;\r\n // Handle cases where the user has asked for zero tickets (no idea why they would do this be we should trust them).\r\n if (tickets === 0) {\r\n return [];\r\n }\r\n // Now that we know out tickets value is not zero we should check that it is a valid natural number.\r\n if (!(0, Utilities_1.isNaturalNumber)(tickets)) {\r\n throw new Error(\"tickets value must be a natural number\");\r\n }\r\n var result = [];\r\n // Keep drawing tickets until we either reach the number of required tickets or we simply run out of tickets to draw.\r\n // We can run out of tickets to draw if 'options.redrawable' is explicity 'false' or we just had no participants when 'drawMultiple' was called.\r\n while (result.length < tickets && this._participants.length > 0) {\r\n result.push(this.draw(options));\r\n }\r\n // If the 'unique' draw option is set then we need to remove duplicates from the result list.\r\n if (uniqueResults) {\r\n // Create an array to store our unique results.\r\n var unique = [];\r\n // Iterate over all of our participants (with potential duplicates) and populate our array of unique values.\r\n for (var _i = 0, result_1 = result; _i < result_1.length; _i++) {\r\n var participant = result_1[_i];\r\n if (unique.indexOf(participant) === -1) {\r\n unique.push(participant);\r\n }\r\n }\r\n result = unique;\r\n }\r\n return result;\r\n };\r\n return Lotto;\r\n}());\r\nexports.Lotto = Lotto;\r\n", "\"use strict\";\r\nObject.defineProperty(exports, \"__esModule\", { value: true });\r\nexports.createLotto = void 0;\r\nvar Lotto_1 = require(\"./Lotto\");\r\n/**\r\n * A function that creates and returns a Lotto instance.\r\n * @param participantsOrOptions An array of initial participants or options relating to the creation of a Lotto instance.\r\n * @returns A new Lotto instance.\r\n */\r\nfunction createLotto(participantsOrOptions) {\r\n // If no initial participants or lotto options were provided as an argument then we can just return a new lotto instance now.\r\n if (!participantsOrOptions) {\r\n return new Lotto_1.Lotto();\r\n }\r\n // Check whether we were provided with an array of initial participants or a lotto options object.\r\n if (Array.isArray(participantsOrOptions)) {\r\n // We are dealing with a pre-defined array of participants.\r\n var participants = participantsOrOptions;\r\n var lotto_1 = new Lotto_1.Lotto();\r\n // If the lotto participants have been defined upfront then we will need to add them all to our lotto instance now.\r\n participants.forEach(function (_a) {\r\n var participant = _a[0], tokens = _a[1];\r\n return lotto_1.add(participant, tokens);\r\n });\r\n // Return the Lotto instance.\r\n return lotto_1;\r\n }\r\n else {\r\n // We are dealing with some lotto options.\r\n var random = participantsOrOptions.random, participants = participantsOrOptions.participants;\r\n // Create a Lotto instance passing the custom RNG function to use in place of Math.random() (which could be undefined).\r\n var lotto_2 = new Lotto_1.Lotto(random);\r\n // If the lotto participants have been defined upfront as part of the options then we will need to add them all to our lotto instance now.\r\n if (participants) {\r\n participants.forEach(function (_a) {\r\n var participant = _a[0], tokens = _a[1];\r\n return lotto_2.add(participant, tokens);\r\n });\r\n }\r\n // Return the Lotto instance.\r\n return lotto_2;\r\n }\r\n}\r\nexports.createLotto = createLotto;\r\n", "\"use strict\";\r\nObject.defineProperty(exports, \"__esModule\", { value: true });\r\nvar createLotto_1 = require(\"./createLotto\");\r\nexports.default = createLotto_1.createLotto;\r\n", "import State from \"./State\";\nimport { validateDefinition } from \"./BehaviourTreeDefinitionValidator\";\nimport { convertMDSLToJSON } from \"./mdsl/MDSLDefinitionParser\";\nimport { BehaviourTree, FlattenedTreeNode } from \"./BehaviourTree\";\nimport { BehaviourTreeOptions } from \"./BehaviourTreeOptions\";\n\nexport { BehaviourTree, State, convertMDSLToJSON, validateDefinition };\nexport type { FlattenedTreeNode, BehaviourTreeOptions };\n", "/**\n * Enumeration of node state types.\n */\nexport enum State {\n READY = \"mistreevous.ready\",\n RUNNING = \"mistreevous.running\",\n SUCCEEDED = \"mistreevous.succeeded\",\n FAILED = \"mistreevous.failed\"\n}\n\nexport { State as default };\n\nexport type CompleteState = State.SUCCEEDED | State.FAILED;\nexport type AnyState = State.READY | State.RUNNING | CompleteState;\n", "import {\n NodeDefinition,\n RootNodeDefinition,\n DecoratorNodeDefinition,\n CompositeNodeDefinition,\n AnyNodeDefinition,\n BranchNodeDefinition\n} from \"./BehaviourTreeDefinition\";\n\n/**\n * A type guard function that returns true if the specified node satisfies the RootNodeDefinition type.\n * @param node The node.\n * @returns A value of true if the specified node satisfies the RootNodeDefinition type.\n */\nexport function isRootNode(node: NodeDefinition): node is RootNodeDefinition {\n return node.type === \"root\";\n}\n\n/**\n * A type guard function that returns true if the specified node satisfies the BranchNodeDefinition type.\n * @param node The node.\n * @returns A value of true if the specified node satisfies the BranchNodeDefinition type.\n */\nexport function isBranchNode(node: NodeDefinition): node is BranchNodeDefinition {\n return node.type === \"branch\";\n}\n\n/**\n * A type guard function that returns true if the specified node satisfies the NodeDefinition type.\n * @param node The node.\n * @returns A value of true if the specified node satisfies the NodeDefinition type.\n */\nexport function isLeafNode(node: NodeDefinition): node is NodeDefinition {\n return [\"branch\", \"action\", \"condition\", \"wait\"].includes(node.type);\n}\n\n/**\n * A type guard function that returns true if the specified node satisfies the DecoratorNodeDefinition type.\n * @param node The node.\n * @returns A value of true if the specified node satisfies the DecoratorNodeDefinition type.\n */\nexport function isDecoratorNode(node: NodeDefinition): node is DecoratorNodeDefinition {\n return [\"root\", \"repeat\", \"retry\", \"flip\", \"succeed\", \"fail\"].includes(node.type);\n}\n\n/**\n * A type guard function that returns true if the specified node satisfies the CompositeNodeDefinition type.\n * @param node The node.\n * @returns A value of true if the specified node satisfies the CompositeNodeDefinition type.\n */\nexport function isCompositeNode(node: NodeDefinition): node is CompositeNodeDefinition {\n return [\"sequence\", \"selector\", \"lotto\", \"parallel\"].includes(node.type);\n}\n\n/**\n * Flatten a node definition into an array of all of its nested node definitions.\n * @param nodeDefinition The node definition to flatten.\n * @returns An array of all of nested node definitions.\n */\nexport function flattenDefinition(nodeDefinition: AnyNodeDefinition): AnyNodeDefinition[] {\n const nodes: AnyNodeDefinition[] = [];\n\n const processNode = (currentNodeDefinition: AnyNodeDefinition) => {\n nodes.push(currentNodeDefinition);\n\n if (isCompositeNode(currentNodeDefinition)) {\n currentNodeDefinition.children.forEach(processNode);\n } else if (isDecoratorNode(currentNodeDefinition)) {\n processNode(currentNodeDefinition.child);\n }\n };\n\n processNode(nodeDefinition);\n\n return nodes;\n}\n\n/**\n * Determines whether the passed value is an integer.\n * @param value The value to check.\n * @returns Whether the passed value is an integer.\n */\nexport function isInteger(value: unknown): boolean {\n return typeof value === \"number\" && Math.floor(value) === value;\n}\n\n/**\n * Determines whether the passed value is null or undefined.\n * @param value The value to check.\n * @returns Whether the passed value is null or undefined.\n */\nexport function isNullOrUndefined(value: unknown): boolean {\n return typeof value === \"undefined\" || value === null;\n}\n", "/**\n * A type defining an object that holds a reference to substitued string literals parsed from the definition.\n */\nexport type StringLiteralPlaceholders = { [key: string]: string };\n\n/**\n * Pop the next raw token from the specified array of tokens and throw an error if it wasn't the expected one.\n * @param tokens The array of tokens.\n * @param expected An optional string or array or items, one of which must match the next popped token.\n * @returns The popped token.\n */\nexport function popAndCheck(tokens: string[], expected?: string | string[]): string {\n // Get and remove the next token.\n const popped = tokens.shift();\n\n // We were expecting another token but there aren't any.\n if (popped === undefined) {\n throw new Error(\"unexpected end of definition\");\n }\n\n // Do we have an expected token/tokens array?\n if (expected != undefined) {\n // Get an array of expected values, if the popped token matches any then we are all good.\n const expectedValues = typeof expected === \"string\" ? [expected] : expected;\n\n // Check whether the popped token matches at least one of our expected items.\n var tokenMatchesExpectation = expectedValues.some((item) => popped.toUpperCase() === item.toUpperCase());\n\n // Throw an error if the popped token didn't match any of our expected items.\n if (!tokenMatchesExpectation) {\n const expectationString = expectedValues.map((item) => \"'\" + item + \"'\").join(\" or \");\n throw new Error(\"unexpected token found. Expected \" + expectationString + \" but got '\" + popped + \"'\");\n }\n }\n\n // Return the popped token.\n return popped;\n}\n\n/**\n * Swaps out any node/attribute argument string literals with placeholders.\n * @param definition The definition.\n * @returns An object containing a mapping of placeholders to original string values as well as the processed definition string.\n */\nexport function substituteStringLiterals(definition: string): {\n placeholders: StringLiteralPlaceholders;\n processedDefinition: string;\n} {\n // Create an object to hold the mapping of placeholders to original string values.\n const placeholders: StringLiteralPlaceholders = {};\n\n // Replace any string literals wrapped with double quotes in our definition with placeholders to be processed later.\n const processedDefinition = definition.replace(/\\\"(\\\\.|[^\"\\\\])*\\\"/g, (match) => {\n var strippedMatch = match.substring(1, match.length - 1);\n var placeholder = Object.keys(placeholders).find((key) => placeholders[key] === strippedMatch);\n\n // If we have no existing string literal match then create a new placeholder.\n if (!placeholder) {\n placeholder = `@@${Object.keys(placeholders).length}@@`;\n placeholders[placeholder] = strippedMatch;\n }\n\n return placeholder;\n });\n\n return { placeholders, processedDefinition };\n}\n\n/**\n * Parse the tree definition into an array of raw tokens.\n * @param definition The definition.\n * @returns An array of tokens parsed from the definition.\n */\nexport function parseTokensFromDefinition(definition: string): string[] {\n // Add some space around various important characters so that they can be plucked out easier as individual tokens.\n definition = definition.replace(/\\(/g, \" ( \");\n definition = definition.replace(/\\)/g, \" ) \");\n definition = definition.replace(/\\{/g, \" { \");\n definition = definition.replace(/\\}/g, \" } \");\n definition = definition.replace(/\\]/g, \" ] \");\n definition = definition.replace(/\\[/g, \" [ \");\n definition = definition.replace(/\\,/g, \" , \");\n\n // Split the definition into raw token form and return it.\n return definition.replace(/\\s+/g, \" \").trim().split(\" \");\n}\n", "import { StringLiteralPlaceholders, popAndCheck } from \"./MDSLUtilities\";\n\n/**\n * A type representing any node function argument.\n */\ntype Argument = {\n /**\n * The argument value.\n */\n value: T;\n /**\n * The argument type, used for validation.\n */\n type: string;\n};\n\ntype NullArgument = Argument & {\n type: \"null\";\n};\n\ntype BooleanArgument = Argument & {\n type: \"boolean\";\n};\n\ntype NumberArgument = Argument & {\n type: \"number\";\n /**\n * A flag defining whether the number argument value is a valid integer. (used for validation)\n */\n isInteger: boolean;\n};\n\ntype StringPlaceholderArgument = Argument & {\n type: \"string\";\n};\n\ntype IdentifierArgument = Argument & {\n type: \"identifier\";\n};\n\n/**\n * A type representing a reference to any node function argument.\n */\ntype AnyArgument = NullArgument | BooleanArgument | NumberArgument | StringPlaceholderArgument | IdentifierArgument;\n\n/**\n * Parse an array of argument definitions from the specified tokens array.\n * @param tokens The array tokens to parse the argument definitions from.\n * @param stringArgumentPlaceholders The mapping of string literal node argument placeholders to original values.\n * @param argumentValidator The argument validator function.\n * @param validationFailedMessage The exception message to throw if argument validation fails.\n * @returns An array of argument definitions parsed from the specified tokens array.\n */\nexport function parseArgumentTokens(\n tokens: string[],\n stringArgumentPlaceholders: StringLiteralPlaceholders\n): AnyArgument[] {\n const argumentList: AnyArgument[] = [];\n\n // If the next token is not a '[' or '(' then we have no arguments to parse.\n if (![\"[\", \"(\"].includes(tokens[0])) {\n return argumentList;\n }\n\n // Any lists of arguments will always be wrapped in '[]' for node arguments or '()' for attribute arguments.\n // We are looking for a '[' or '(' opener that wraps the argument tokens and the relevant closer.\n const closingToken = popAndCheck(tokens, [\"[\", \"(\"]) === \"[\" ? \"]\" : \")\";\n\n const argumentListTokens: string[] = [];\n\n // Grab all tokens between the '[' and ']' or '(' and ')'.\n while (tokens.length && tokens[0] !== closingToken) {\n // The next token is part of our arguments list.\n argumentListTokens.push(tokens.shift()!);\n }\n\n // Validate the order of the argument tokens. Each token must either be a ',' or a single argument that satisfies the validator.\n argumentListTokens.forEach((token, index) => {\n // Get whether this token should be an actual argument.\n const shouldBeArgumentToken = !(index & 1);\n\n // If the current token should be an actual argument then validate it, otherwise it should be a ',' token.\n if (shouldBeArgumentToken) {\n // Get the argument definition.\n const argumentDefinition = getArgumentDefinition(token, stringArgumentPlaceholders);\n\n // This is a valid argument!\n argumentList.push(argumentDefinition);\n } else {\n // The current token should be a ',' token.\n if (token !== \",\") {\n throw new Error(`invalid argument list, expected ',' or ']' but got '${token}'`);\n }\n }\n });\n\n // The arguments list should terminate with a ']' or ')' token, depending on the opener.\n popAndCheck(tokens, closingToken);\n\n // Return the arguments.\n return argumentList;\n}\n\n/**\n * Gets an argument value definition.\n * @param token The argument token.\n * @param stringArgumentPlaceholders The mapping of string literal node argument placeholders to original values.\n * @returns An argument value definition.\n */\nfunction getArgumentDefinition(token: string, stringArgumentPlaceholders: StringLiteralPlaceholders): AnyArgument {\n // Check whether the token represents a null value.\n if (token === \"null\") {\n return {\n value: null,\n type: \"null\"\n } as NullArgument;\n }\n\n // Check whether the token represents a boolean value.\n if (token === \"true\" || token === \"false\") {\n return {\n value: token === \"true\",\n type: \"boolean\"\n } as BooleanArgument;\n }\n\n // Check whether the token represents a number value.\n // TODO: Relies on broken isNaN - see MDN.\n // if (!Number.isNaN(token)) {\n if (!isNaN(token as any)) {\n return {\n value: parseFloat(token),\n isInteger: parseFloat(token) === parseInt(token, 10),\n type: \"number\"\n } as NumberArgument;\n }\n\n // Check whether the token is a placeholder (e.g. @@0@@) representing a string literal.\n if (token.match(/^@@\\d+@@$/g)) {\n return {\n value: stringArgumentPlaceholders[token].replace('\\\\\"', '\"'),\n type: \"string\"\n } as StringPlaceholderArgument;\n }\n\n // The only remaining option is that the argument value is an identifier.\n return {\n value: token,\n type: \"identifier\"\n } as IdentifierArgument;\n}\n", "import { NodeAttributeDefinition } from \"../BehaviourTreeDefinition\";\nimport { parseArgumentTokens } from \"./MDSLNodeArgumentParser\";\nimport { StringLiteralPlaceholders } from \"./MDSLUtilities\";\n\n/**\n * A type defining the attribute definitions of a node.\n */\ntype NodeAttributes = {\n while?: NodeAttributeDefinition;\n until?: NodeAttributeDefinition;\n entry?: NodeAttributeDefinition;\n exit?: NodeAttributeDefinition;\n step?: NodeAttributeDefinition;\n};\n\n/**\n * Parse any node attribute definitions from the specified tokens array.\n * @param tokens The array of remaining tokens.\n * @param stringArgumentPlaceholders The mapping of string literal node argument placeholders to original values.\n * @returns An object of attribute definitions defined by any directly following tokens.\n */\nexport function parseAttributeTokens(\n tokens: string[],\n stringArgumentPlaceholders: StringLiteralPlaceholders\n): NodeAttributes {\n const nodeAttributeNames: (keyof NodeAttributes)[] = [\"while\", \"until\", \"entry\", \"exit\", \"step\"];\n\n // Create an object to hold any attributes found.\n const attributes: NodeAttributes = {};\n\n // Try to get the name of the attribute for the next token.\n let nextAttributeName = tokens[0]?.toLowerCase() as keyof NodeAttributes;\n\n // Pull attribute tokens as well as their arguments off of the tokens stack until we have no more.\n while (nodeAttributeNames.includes(nextAttributeName)) {\n // Check to make sure that we have not already created an attribute definition of this type.\n if (attributes[nextAttributeName]) {\n throw new Error(`duplicate attribute '${tokens[0].toUpperCase()}' found for node`);\n }\n\n // Remove the attribute name token from the array of tokens.\n tokens.shift();\n\n // Grab the attribute arguments, assuming the first to be an identifier.\n const [attributeCallIdentifier, ...attributeArguments] = parseArgumentTokens(\n tokens,\n stringArgumentPlaceholders\n );\n\n // The first attribute argument has to be an identifer, this will reference an agent function.\n if (attributeCallIdentifier?.type !== \"identifier\") {\n throw new Error(\"expected agent function or registered function name identifier argument for attribute\");\n }\n\n // Any attribute arguments (other than the expected call identifier) must have a type of string, number, boolean or null.\n attributeArguments\n .filter((arg) => arg.type === \"identifier\")\n .forEach((arg) => {\n throw new Error(\n `invalid attribute argument value '${arg.value}', must be string, number, boolean or null`\n );\n });\n\n // Create the attribute definition and add it to the object of attribute definitions found.\n attributes[nextAttributeName] = {\n call: attributeCallIdentifier.value,\n args: attributeArguments.map(({ value }) => value)\n };\n\n // Try to get the next attribute name token, as there could be multiple.\n nextAttributeName = tokens[0]?.toLowerCase() as keyof NodeAttributes;\n }\n\n return attributes;\n}\n", "import {\n ActionNodeDefinition,\n AnyChildNodeDefinition,\n AnyNodeDefinition,\n BranchNodeDefinition,\n ConditionNodeDefinition,\n FailNodeDefinition,\n FlipNodeDefinition,\n LottoNodeDefinition,\n ParallelNodeDefinition,\n RepeatNodeDefinition,\n RetryNodeDefinition,\n RootNodeDefinition,\n SelectorNodeDefinition,\n SequenceNodeDefinition,\n SucceedNodeDefinition,\n WaitNodeDefinition\n} from \"../BehaviourTreeDefinition\";\nimport {\n isCompositeNode,\n isDecoratorNode,\n isLeafNode,\n isNullOrUndefined,\n isRootNode\n} from \"../BehaviourTreeDefinitionUtilities\";\nimport { parseArgumentTokens } from \"./MDSLNodeArgumentParser\";\nimport { parseAttributeTokens } from \"./MDSLNodeAttributeParser\";\nimport {\n StringLiteralPlaceholders,\n parseTokensFromDefinition,\n popAndCheck,\n substituteStringLiterals\n} from \"./MDSLUtilities\";\n\n/**\n * Convert the MDSL tree definition string into an equivalent JSON definition.\n * @param definition The tree definition string as MDSL.\n * @returns The root node JSON definitions.\n */\nexport function convertMDSLToJSON(definition: string): RootNodeDefinition[] {\n // Swap out any node/attribute argument string literals with a placeholder and get a mapping of placeholders to original values as well as the processed definition.\n const { placeholders, processedDefinition } = substituteStringLiterals(definition);\n\n // Parse our definition definition string into an array of raw tokens.\n const tokens = parseTokensFromDefinition(processedDefinition);\n\n return convertTokensToJSONDefinition(tokens, placeholders);\n}\n\n/**\n * Converts the specified tree definition tokens into a JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The root node JSON definitions.\n */\nfunction convertTokensToJSONDefinition(\n tokens: string[],\n stringLiteralPlaceholders: StringLiteralPlaceholders\n): RootNodeDefinition[] {\n // There must be at least 3 tokens for the tree definition to be valid. 'ROOT', '{' and '}'.\n if (tokens.length < 3) {\n throw new Error(\"invalid token count\");\n }\n\n // We should have a matching number of '{' and '}' tokens. If not, then there are scopes that have not been properly closed.\n if (tokens.filter((token) => token === \"{\").length !== tokens.filter((token) => token === \"}\").length) {\n throw new Error(\"scope character mismatch\");\n }\n\n // Create an array of tree stack arrays where root nodes will always be at the botton and the current composite/decorator node at the top.\n // There should be an element in this array for every root node defined and every element should be an array with a root note as the first element.\n // E.g. A definition with two root nodes defined:\n // [\n // [root, lotto, sequence],\n // [root, selector]\n // ]\n const treeStacks: [Partial, ...Partial[]][] = [];\n\n // Create an array of all root node definitions that we create.\n const rootNodes: Partial[] = [];\n\n // A helper function used to push node definitions onto the tree stack.\n const pushNode = (node: AnyNodeDefinition) => {\n // If the node is a root node then we need to create a new tree stack array with the root node at the root.\n if (isRootNode(node)) {\n // We need to double-check that this root node is not the child of another node.\n // We can do this by checking whether the top tree stack is not empty (contains an existing node)\n if (treeStacks[treeStacks.length - 1]?.length) {\n throw new Error(\"a root node cannot be the child of another node\");\n }\n\n // Add the root node definition to our array of all parsed root node definitions.\n rootNodes.push(node);\n\n // Add the root node definition to the root of a new tree stack.\n treeStacks.push([node]);\n\n return;\n }\n\n // All non-root nodes should be pushed after their root nodes so handle cases\n // where we may not have any tree stacks or our top-most tree stack is empty.\n if (!treeStacks.length || !treeStacks[treeStacks.length - 1].length) {\n throw new Error(\"expected root node at base of definition\");\n }\n\n // Get the current tree stack that we are populating.\n const topTreeStack = treeStacks[treeStacks.length - 1];\n\n // Get the top-most node in the current tree stack, this will be a composite/decorator node\n // for which we will populate its children array if composite or setting its child if a decorator.\n const topTreeStackTopNode = topTreeStack[topTreeStack.length - 1] as AnyNodeDefinition;\n\n // If the top-most node in the current root stack is a composite or decorator\n // node then the current node should be added as a child of the top-most node.\n if (isCompositeNode(topTreeStackTopNode)) {\n topTreeStackTopNode.children = topTreeStackTopNode.children || [];\n topTreeStackTopNode.children.push(node);\n } else if (isDecoratorNode(topTreeStackTopNode)) {\n // If the top node already has a child node set then throw an error as a decorator should only have a single child.\n if (topTreeStackTopNode.child) {\n throw new Error(\"a decorator node must only have a single child node\");\n }\n\n topTreeStackTopNode.child = node;\n }\n\n // If the node we are adding is also a composite or decorator node, then we should push it\n // onto the current tree stack, as subsequent nodes will be added as its child/children.\n if (!isLeafNode(node)) {\n topTreeStack.push(node);\n }\n };\n\n // A helper function used to pop the top-most node definition off of the tree stack and return it.\n const popNode = (): AnyNodeDefinition | null => {\n let poppedNode: AnyNodeDefinition | null = null;\n\n // Get the current tree stack that we are populating.\n const topTreeStack = treeStacks[treeStacks.length - 1];\n\n // Pop the top-most node in the current tree stack if there is one.\n if (topTreeStack.length) {\n poppedNode = topTreeStack.pop() as AnyNodeDefinition;\n }\n\n // We don't want any empty tree stacks in our stack of tree stacks.\n if (!topTreeStack.length) {\n treeStacks.pop();\n }\n\n return poppedNode;\n };\n\n // We should keep processing the raw tokens until we run out of them.\n while (tokens.length) {\n // Grab the next token.\n const token = tokens.shift()!;\n\n // How we create the next node depends on the current raw token value.\n switch (token.toUpperCase()) {\n case \"ROOT\": {\n pushNode(createRootNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"SUCCEED\": {\n pushNode(createSucceedNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"FAIL\": {\n pushNode(createFailNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"FLIP\": {\n pushNode(createFlipNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"REPEAT\": {\n pushNode(createRepeatNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"RETRY\": {\n pushNode(createRetryNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"SEQUENCE\": {\n pushNode(createSequenceNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"SELECTOR\": {\n pushNode(createSelectorNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"PARALLEL\": {\n pushNode(createParallelNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"LOTTO\": {\n pushNode(createLottoNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"ACTION\": {\n pushNode(createActionNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"CONDITION\": {\n pushNode(createConditionNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"WAIT\": {\n pushNode(createWaitNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"BRANCH\": {\n pushNode(createBranchNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"}\": {\n // The '}' character closes the current scope and means that we have to pop a node off of the current stack.\n const poppedNode = popNode();\n\n // Now that we have a node definition we can carry out any validation that may require the node to be fully populated.\n if (poppedNode) {\n validatePoppedNode(poppedNode);\n }\n\n break;\n }\n\n default: {\n throw new Error(`unexpected token: ${token}`);\n }\n }\n }\n\n return rootNodes as RootNodeDefinition[];\n}\n\n/**\n * Creates a root node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The root node JSON definition.\n */\nfunction createRootNode(tokens: string[], stringLiteralPlaceholders: StringLiteralPlaceholders): RootNodeDefinition {\n // Create the root node definition.\n let node = {\n type: \"root\"\n } as Partial;\n\n // Parse any node arguments, we should only have one if any which will be an identifier argument for the root identifier.\n const nodeArguments = parseArgumentTokens(tokens, stringLiteralPlaceholders);\n\n // Check whether any node arguments were defined.\n if (nodeArguments.length) {\n // We should only have one argument, if any, which will be an identifier argument for the root identifier.\n if (nodeArguments.length === 1 && nodeArguments[0].type === \"identifier\") {\n // The root node identifier will be the first and only node argument value.\n node.id = nodeArguments[0].value as string;\n } else {\n throw new Error(\"expected single root name argument\");\n }\n }\n\n // Grab any node attribute definitions and spread them into the node definition.\n node = { ...node, ...parseAttributeTokens(tokens, stringLiteralPlaceholders) };\n\n // This is a decorator node, so we expect an opening '{'.\n popAndCheck(tokens, \"{\");\n\n // Return the root node definition.\n return node as RootNodeDefinition;\n}\n\n/**\n * Creates a succeed node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The succeed node JSON definition.\n */\nfunction createSucceedNode(\n tokens: string[],\n stringLiteralPlaceholders: StringLiteralPlaceholders\n): SucceedNodeDefinition {\n const node = {\n type: \"succeed\",\n ...parseAttributeTokens(tokens, stringLiteralPlaceholders)\n } as SucceedNodeDefinition;\n\n // This is a decorator node, so we expect an opening '{'.\n popAndCheck(tokens, \"{\");\n\n // Return the succeed node definition.\n return node;\n}\n\n/**\n * Creates a fail node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The fail node JSON definition.\n */\nfunction createFailNode(tokens: string[], stringLiteralPlaceholders: StringLiteralPlaceholders): FailNodeDefinition {\n const node = {\n type: \"fail\",\n ...parseAttributeTokens(tokens, stringLiteralPlaceholders)\n } as FailNodeDefinition;\n\n // This is a decorator node, so we expect an opening '{'.\n popAndCheck(tokens, \"{\");\n\n // Return the fail node definition.\n return node;\n}\n\n/**\n * Creates a flip node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The flip node JSON definition.\n */\nfunction createFlipNode(tokens: string[], stringLiteralPlaceholders: StringLiteralPlaceholders): FlipNodeDefinition {\n const node = {\n type: \"flip\",\n ...parseAttributeTokens(tokens, stringLiteralPlaceholders)\n } as FlipNodeDefinition;\n\n // This is a decorator node, so we expect an opening '{'.\n popAndCheck(tokens, \"{\");\n\n // Return the flip node definition.\n return node;\n}\n\n/**\n * Creates a repeat node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The repeat node JSON definition.\n */\nfunction createRepeatNode(\n tokens: string[],\n stringLiteralPlaceholders: StringLiteralPlaceholders\n): RepeatNodeDefinition {\n let node = { type: \"repeat\" } as RepeatNodeDefinition;\n\n // Get the node arguments.\n const nodeArguments = parseArgumentTokens(tokens, stringLiteralPlaceholders);\n\n // The arguments of a repeat node are optional. We may have:\n // - No node arguments, in which case the repeat note will iterate indefinitely.\n // - One node argument which will be the explicit number of iterations to make.\n // - Two node arguments which define the min and max iteration bounds from which a random iteration count will be picked.\n if (nodeArguments.length) {\n // All repeat node arguments MUST be of type number and must be integer.\n nodeArguments\n .filter((arg) => arg.type !== \"number\" || !arg.isInteger)\n .forEach(() => {\n throw new Error(`repeat node iteration counts must be integer values`);\n });\n\n // We should have got one or two iteration counts.\n if (nodeArguments.length === 1) {\n // A static iteration count was defined.\n node.iterations = nodeArguments[0].value as number;\n\n // A repeat node must have a positive number of iterations if defined.\n if (node.iterations < 0) {\n throw new Error(\"a repeat node must have a positive number of iterations if defined\");\n }\n } else if (nodeArguments.length === 2) {\n // A minimum and maximum iteration count was defined.\n node.iterations = [nodeArguments[0].value as number, nodeArguments[1].value as number];\n\n // A repeat node must have a positive min and max iteration count if they are defined.\n if (node.iterations[0] < 0 || node.iterations[1] < 0) {\n throw new Error(\"a repeat node must have a positive minimum and maximum iteration count if defined\");\n }\n\n // A repeat node must not have an minimum iteration count that exceeds the maximum iteration count.\n if (node.iterations[0] > node.iterations[1]) {\n throw new Error(\n \"a repeat node must not have a minimum iteration count that exceeds the maximum iteration count\"\n );\n }\n } else {\n // An incorrect number of iteration counts was defined.\n throw new Error(\"invalid number of repeat node iteration count arguments defined\");\n }\n }\n\n // Grab any node attribute definitions and spread them into the node definition.\n node = { ...node, ...parseAttributeTokens(tokens, stringLiteralPlaceholders) };\n\n // This is a decorator node, so we expect an opening '{'.\n popAndCheck(tokens, \"{\");\n\n // Return the repeat node definition.\n return node;\n}\n\n/**\n * Creates a retry node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The retry node JSON definition.\n */\nfunction createRetryNode(tokens: string[], stringLiteralPlaceholders: StringLiteralPlaceholders): RetryNodeDefinition {\n let node = { type: \"retry\" } as RetryNodeDefinition;\n\n // Get the node arguments.\n const nodeArguments = parseArgumentTokens(tokens, stringLiteralPlaceholders);\n\n // The arguments of a retry node are optional. We may have:\n // - No node arguments, in which case the retry note will attempt indefinitely.\n // - One node argument which will be the explicit number of attempts to make.\n // - Two node arguments which define the min and max attempt bounds from which a random attempt count will be picked.\n if (nodeArguments.length) {\n // All retry node arguments MUST be of type number and must be integer.\n nodeArguments\n .filter((arg) => arg.type !== \"number\" || !arg.isInteger)\n .forEach(() => {\n throw new Error(`retry node attempt counts must be integer values`);\n });\n\n // We should have got one or two attempt counts.\n if (nodeArguments.length === 1) {\n // A static attempt count was defined.\n node.attempts = nodeArguments[0].value as number;\n\n // A retry node must have a positive number of attempts if defined.\n if (node.attempts < 0) {\n throw new Error(\"a retry node must have a positive number of attempts if defined\");\n }\n } else if (nodeArguments.length === 2) {\n // A minimum and maximum attempt count was defined.\n node.attempts = [nodeArguments[0].value as number, nodeArguments[1].value as number];\n\n // A retry node must have a positive min and max attempts count if they are defined.\n if (node.attempts[0] < 0 || node.attempts[1] < 0) {\n throw new Error(\"a retry node must have a positive minimum and maximum attempt count if defined\");\n }\n\n // A retry node must not have a minimum attempt count that exceeds the maximum attempt count.\n if (node.attempts[0] > node.attempts[1]) {\n throw new Error(\n \"a retry node must not have a minimum attempt count that exceeds the maximum attempt count\"\n );\n }\n } else {\n // An incorrect number of attempt counts was defined.\n throw new Error(\"invalid number of retry node attempt count arguments defined\");\n }\n }\n\n // Grab any node attribute definitions and spread them into the node definition.\n node = { ...node, ...parseAttributeTokens(tokens, stringLiteralPlaceholders) };\n\n // This is a decorator node, so we expect an opening '{'.\n popAndCheck(tokens, \"{\");\n\n // Return the retry node definition.\n return node;\n}\n\n/**\n * Creates a sequence node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The sequence node JSON definition.\n */\nfunction createSequenceNode(\n tokens: string[],\n stringLiteralPlaceholders: StringLiteralPlaceholders\n): SequenceNodeDefinition {\n const node = {\n type: \"sequence\",\n ...parseAttributeTokens(tokens, stringLiteralPlaceholders)\n } as SequenceNodeDefinition;\n\n // This is a composite node, so we expect an opening '{'.\n popAndCheck(tokens, \"{\");\n\n // Return the sequence node definition.\n return node;\n}\n\n/**\n * Creates a selector node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The selector node JSON definition.\n */\nfunction createSelectorNode(\n tokens: string[],\n stringLiteralPlaceholders: StringLiteralPlaceholders\n): SelectorNodeDefinition {\n const node = {\n type: \"selector\",\n ...parseAttributeTokens(tokens, stringLiteralPlaceholders)\n } as SelectorNodeDefinition;\n\n // This is a composite node, so we expect an opening '{'.\n popAndCheck(tokens, \"{\");\n\n // Return the selector node definition.\n return node;\n}\n\n/**\n * Creates a parallel node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The parallel node JSON definition.\n */\nfunction createParallelNode(\n tokens: string[],\n stringLiteralPlaceholders: StringLiteralPlaceholders\n): ParallelNodeDefinition {\n const node = {\n type: \"parallel\",\n ...parseAttributeTokens(tokens, stringLiteralPlaceholders)\n } as ParallelNodeDefinition;\n\n // This is a composite node, so we expect an opening '{'.\n popAndCheck(tokens, \"{\");\n\n // Return the parallel node definition.\n return node;\n}\n\n/**\n * Creates a lotto node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The lotto node JSON definition.\n */\nfunction createLottoNode(tokens: string[], stringLiteralPlaceholders: StringLiteralPlaceholders): LottoNodeDefinition {\n // If any node arguments have been defined then they must be our weights.\n const nodeArguments = parseArgumentTokens(tokens, stringLiteralPlaceholders);\n\n // All lotto node arguments MUST be of type number and must be positive integers.\n nodeArguments\n .filter((arg) => arg.type !== \"number\" || !arg.isInteger || arg.value < 0)\n .forEach(() => {\n throw new Error(`lotto node weight arguments must be positive integer values`);\n });\n\n const node = {\n type: \"lotto\",\n ...parseAttributeTokens(tokens, stringLiteralPlaceholders)\n } as LottoNodeDefinition;\n\n // Apply the weights if any were defined.\n if (nodeArguments.length) {\n node.weights = nodeArguments.map(({ value }) => value) as number[];\n }\n\n // This is a composite node, so we expect an opening '{'.\n popAndCheck(tokens, \"{\");\n\n // Return the lotto node definition.\n return node;\n}\n\n/**\n * Creates an action node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The action node JSON definition.\n */\nfunction createActionNode(\n tokens: string[],\n stringLiteralPlaceholders: StringLiteralPlaceholders\n): ActionNodeDefinition {\n // Parse any node arguments, we should have at least one which will be an identifier argument for the action name\n // and agent function to invoke for the action, all other arguments are to be passed as arguments to that function.\n const [actionNameIdentifier, ...agentFunctionArgs] = parseArgumentTokens(tokens, stringLiteralPlaceholders);\n\n // Our first argument MUST be defined and be an identifier as we require an action name argument.\n if (actionNameIdentifier?.type !== \"identifier\") {\n throw new Error(\"expected action name identifier argument\");\n }\n\n // Only the first argument should have been an identifier, all agent function arguments must be string, number, boolean or null.\n agentFunctionArgs\n .filter((arg) => arg.type === \"identifier\")\n .forEach((arg) => {\n throw new Error(\n `invalid action node argument value '${arg.value}', must be string, number, boolean or null`\n );\n });\n\n // Return the action node definition.\n return {\n type: \"action\",\n call: actionNameIdentifier.value,\n args: agentFunctionArgs.map(({ value }) => value),\n ...parseAttributeTokens(tokens, stringLiteralPlaceholders)\n };\n}\n\n/**\n * Creates a condition node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The condition node JSON definition.\n */\nfunction createConditionNode(\n tokens: string[],\n stringLiteralPlaceholders: StringLiteralPlaceholders\n): ConditionNodeDefinition {\n // Parse any node arguments, we should have at least one which will be an identifier argument for the condition name\n // and agent function to invoke for the condition, all other arguments are to be passed as arguments to that function.\n const [conditionNameIdentifier, ...agentFunctionArgs] = parseArgumentTokens(tokens, stringLiteralPlaceholders);\n\n // Our first argument MUST be defined and be an identifier as we require a condition name argument.\n if (conditionNameIdentifier?.type !== \"identifier\") {\n throw new Error(\"expected condition name identifier argument\");\n }\n\n // Only the first argument should have been an identifier, all agent function arguments must be string, number, boolean or null.\n agentFunctionArgs\n .filter((arg) => arg.type === \"identifier\")\n .forEach((arg) => {\n throw new Error(\n `invalid condition node argument value '${arg.value}', must be string, number, boolean or null`\n );\n });\n\n // Return the condition node definition.\n return {\n type: \"condition\",\n call: conditionNameIdentifier.value,\n args: agentFunctionArgs.map(({ value }) => value),\n ...parseAttributeTokens(tokens, stringLiteralPlaceholders)\n };\n}\n\n/**\n * Creates a wait node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The wait node JSON definition.\n */\nfunction createWaitNode(tokens: string[], stringLiteralPlaceholders: StringLiteralPlaceholders): WaitNodeDefinition {\n let node = { type: \"wait\" } as WaitNodeDefinition;\n\n // Get the node arguments.\n const nodeArguments = parseArgumentTokens(tokens, stringLiteralPlaceholders);\n\n // The arguments of a wait node are optional. We may have:\n // - No node arguments, in which case the wait will be indefinite until it is aborted.\n // - One node argument which will be the explicit duration of the wait.\n // - Two node arguments which define the min and max duration bounds from which a random duration will be picked.\n if (nodeArguments.length) {\n // All wait node arguments MUST be of type number and must be integer.\n nodeArguments\n .filter((arg) => arg.type !== \"number\" || !arg.isInteger)\n .forEach(() => {\n throw new Error(`wait node durations must be integer values`);\n });\n\n // We may have:\n // - One node argument which will be the explicit duration of the wait.\n // - Two node arguments which define the min and max duration bounds from which a random duration will be picked.\n // - Too many arguments, which is not valid.\n if (nodeArguments.length === 1) {\n // An explicit duration was defined.\n node.duration = nodeArguments[0].value as number;\n\n // If an explict duration was defined then it must be a positive number.\n if (node.duration < 0) {\n throw new Error(\"a wait node must have a positive duration\");\n }\n } else if (nodeArguments.length === 2) {\n // Min and max duration bounds were defined from which a random duration will be picked.\n node.duration = [nodeArguments[0].value as number, nodeArguments[1].value as number];\n\n // A wait node must have a positive min and max duration.\n if (node.duration[0] < 0 || node.duration[1] < 0) {\n throw new Error(\"a wait node must have a positive minimum and maximum duration\");\n }\n\n // A wait node must not have a minimum duration that exceeds the maximum duration.\n if (node.duration[0] > node.duration[1]) {\n throw new Error(\"a wait node must not have a minimum duration that exceeds the maximum duration\");\n }\n } else if (nodeArguments.length > 2) {\n // An incorrect number of duration arguments were defined.\n throw new Error(\"invalid number of wait node duration arguments defined\");\n }\n }\n\n // Return the wait node definition.\n return { ...node, ...parseAttributeTokens(tokens, stringLiteralPlaceholders) };\n}\n\n/**\n * Creates a branch node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The branch node JSON definition.\n */\nfunction createBranchNode(\n tokens: string[],\n stringLiteralPlaceholders: StringLiteralPlaceholders\n): BranchNodeDefinition {\n // Parse any node arguments, we should have one which will be an identifier argument for the root ref.\n const nodeArguments = parseArgumentTokens(tokens, stringLiteralPlaceholders);\n\n // We should have only a single identifer argument for a branch node, which is the root ref.\n if (nodeArguments.length !== 1 || nodeArguments[0].type !== \"identifier\") {\n throw new Error(\"expected single branch name argument\");\n }\n\n // Return the branch node definition.\n return { type: \"branch\", ref: nodeArguments[0].value };\n}\n\n/**\n * Validate a fully-populated node definition that was popped off of the tree stack.\n * @param definition The popped node to validate.\n */\nfunction validatePoppedNode(definition: AnyNodeDefinition): void {\n // Decorators MUST have a child defined.\n if (isDecoratorNode(definition) && isNullOrUndefined(definition.child)) {\n throw new Error(`a ${definition.type} node must have a single child node defined`);\n }\n\n // Composites MUST have at least one child defined.\n if (isCompositeNode(definition) && !definition.children?.length) {\n throw new Error(`a ${definition.type} node must have at least a single child node defined`);\n }\n\n // We need to make sure that lotto nodes that have weights defined have a number of weights matching the number of child nodes.\n if (definition.type === \"lotto\") {\n // Check whether a 'weights' property has been defined, if it has we expect it to be an array of weights.\n if (typeof definition.weights !== \"undefined\") {\n // Check that the weights property is an array of positive integers with an element for each child node element.\n if (definition.weights.length !== definition.children.length) {\n throw new Error(\n \"expected a number of weight arguments matching the number of child nodes for lotto node\"\n );\n }\n }\n }\n}\n", "import { RootNodeDefinition } from \"./BehaviourTreeDefinition\";\nimport { flattenDefinition, isBranchNode, isInteger } from \"./BehaviourTreeDefinitionUtilities\";\nimport { convertMDSLToJSON } from \"./mdsl/MDSLDefinitionParser\";\n\n/**\n * An object representing the result of validating a tree definition.\n */\nexport type DefinitionValidationResult = {\n /**\n * A flag defining whether validation succeeded.\n */\n succeeded: boolean;\n /**\n * A string containing the error message if validation did not succeed.\n */\n errorMessage?: string;\n /**\n * The definition as json if the validation was successful, or undefined if validation did not succeed.\n */\n json?: RootNodeDefinition[];\n};\n\n/**\n * Validates the specified behaviour tree definition in the form of JSON or MDSL, not taking any globally registered subtrees into consideration.\n * @param definition The behaviour tree definition in the form of JSON or MDSL.\n * @returns An object representing the result of validating the given tree definition.\n */\nexport function validateDefinition(definition: any): DefinitionValidationResult {\n // The definition must be defined.\n if (definition === null || typeof definition === \"undefined\") {\n return createValidationFailureResult(\"definition is null or undefined\");\n }\n\n // We are expecting a definition in one of three different forms:\n // - A string which we will assume is MDSL and we will parse this to JSON before validation.\n // - An array which we will assume is an array of root node definitions with at least one being the primary root node (no 'id' property)\n // - An object which we will assume is the primary root node and should not have an 'id' property.\n if (typeof definition === \"string\") {\n // The definition is a string which we can assume is MDSL, so attempt to validate it.\n return validateMDSLDefinition(definition);\n } else if (typeof definition === \"object\") {\n // The definition will either be an array (of root node definitions) or an object (the single primary root node definition).\n return validateJSONDefinition(definition);\n } else {\n return createValidationFailureResult(`unexpected definition type of '${typeof definition}'`);\n }\n}\n\n/**\n * Validates the specified behaviour tree definition in the form of MDSL.\n * @param definition The behaviour tree definition in the form of MDSL.\n * @returns An object representing the result of validating the given tree definition.\n */\nfunction validateMDSLDefinition(definition: string): DefinitionValidationResult {\n let rootNodeDefinitions;\n\n // The first thing the we need to do is to attempt to convert our MDSL into JSON.\n try {\n // The definition is a string which we can assume is MDSL, so attempt to parse it to a JSON definition in the form of an array of root node definitions.\n rootNodeDefinitions = convertMDSLToJSON(definition);\n } catch (exception) {\n // We failed to parse the JSON from the MDSL, this is likely to be the result of it not being a valid MDSL string.\n return createValidationFailureResult((exception as Error).message);\n }\n\n // Unpack all of the root node definitions into arrays of main ('id' defined) and sub ('id' not defined) root node definitions.\n const mainRootNodeDefinitions = rootNodeDefinitions.filter(({ id }) => typeof id === \"undefined\");\n const subRootNodeDefinitions = rootNodeDefinitions.filter(({ id }) => typeof id === \"string\" && id.length > 0);\n\n // We should ALWAYS have exactly one root node definition without an 'id' property defined, which is out main root node definition.\n if (mainRootNodeDefinitions.length !== 1) {\n return createValidationFailureResult(\n \"expected single unnamed root node at base of definition to act as main root\"\n );\n }\n\n // We should never have duplicate 'id' properties across our sub root node definitions.\n const subRootNodeIdenitifers: string[] = [];\n for (const { id } of subRootNodeDefinitions) {\n // Have we already come across this 'id' property value?\n if (subRootNodeIdenitifers.includes(id!)) {\n return createValidationFailureResult(`multiple root nodes found with duplicate name '${id}'`);\n }\n\n subRootNodeIdenitifers.push(id!);\n }\n\n try {\n // Validate our branch -> subtree links and check for any circular dependencies, we don't care about checking for broken subtree links here.\n validateBranchSubtreeLinks(rootNodeDefinitions, false);\n } catch (exception) {\n return createValidationFailureResult((exception as Error).message);\n }\n\n // Our definition was valid!\n return {\n succeeded: true,\n json: rootNodeDefinitions\n };\n}\n\n/**\n * Validates the specified behaviour tree definition in the form of JSON.\n * @param definition The behaviour tree definition in the form of JSON.\n * @returns An object representing the result of validating the given tree definition.\n */\nexport function validateJSONDefinition(\n definition: RootNodeDefinition | RootNodeDefinition[]\n): DefinitionValidationResult {\n // The definition will either be an array (of root node definitions) or an object (the single primary root node definition).\n const rootNodeDefinitions = Array.isArray(definition) ? definition : [definition];\n\n // Iterate over our array of root nodes and call validateNode for each, passing an initial depth of 0, wrapped in a try catch to handle validation failures.\n try {\n rootNodeDefinitions.forEach((rootNodeDefinition) => validateNode(rootNodeDefinition, 0));\n } catch (error) {\n // Handle cases where we have caught a thrown Error and return a failure result with the error message.\n if (error instanceof Error) {\n return createValidationFailureResult(error.message);\n }\n\n // No idea what happened here!\n return createValidationFailureResult(`unexpected error: ${error}`);\n }\n\n // Unpack all of the root node definitions into arrays of main ('id' defined) and sub ('id' not defined) root node definitions.\n const mainRootNodeDefinitions = rootNodeDefinitions.filter(({ id }) => typeof id === \"undefined\");\n const subRootNodeDefinitions = rootNodeDefinitions.filter(({ id }) => typeof id === \"string\" && id.length > 0);\n\n // We should ALWAYS have exactly one root node definition without an 'id' property defined, which is out main root node definition.\n if (mainRootNodeDefinitions.length !== 1) {\n return createValidationFailureResult(\n \"expected single root node without 'id' property defined to act as main root\"\n );\n }\n\n // We should never have duplicate 'id' properties across our sub root node definitions.\n const subRootNodeIdenitifers: string[] = [];\n for (const { id } of subRootNodeDefinitions) {\n // Have we already come across this 'id' property value?\n if (subRootNodeIdenitifers.includes(id!)) {\n return createValidationFailureResult(\n `multiple root nodes found with duplicate 'id' property value of '${id}'`\n );\n }\n\n subRootNodeIdenitifers.push(id!);\n }\n\n try {\n // Validate our branch -> subtree links and check for any circular dependencies, we don't care about checking for broken subtree links here.\n validateBranchSubtreeLinks(rootNodeDefinitions, false);\n } catch (exception) {\n return createValidationFailureResult((exception as Error).message);\n }\n\n // Our definition was valid!\n return {\n succeeded: true,\n json: rootNodeDefinitions\n };\n}\n\n/**\n * Validates the branch -> subtree links across all provided root node definitions.\n * This will not consider branch nodes that reference any globally registered subtrees unless includesGlobalSubtrees\n * is set to true, in which case we will also verify that there are no broken branch -> subtree links.\n * @param rootNodeDefinitions The array of root node definitions.\n * @param includesGlobalSubtrees A flag defining whether the array includes all global subtree root node definitions.\n */\nexport function validateBranchSubtreeLinks(rootNodeDefinitions: RootNodeDefinition[], includesGlobalSubtrees: boolean) {\n // Create a mapping of root node identifiers to other root nodes that they reference via branch nodes.\n // Below is an example of a mapping that includes a circular dependency (root => a => b => c => a)\n // [{ refs: [\"a\", \"b\"] }, { id: \"a\", refs: [\"b\"] }, { id: \"b\", refs: [\"c\"] }, { id: \"c\", refs: [\"a\"] }]\n const rootNodeMappings: { id: string | undefined; refs: string[] }[] = rootNodeDefinitions.map(\n (rootNodeDefinition) => ({\n id: rootNodeDefinition.id,\n refs: flattenDefinition(rootNodeDefinition)\n .filter(isBranchNode)\n .map(({ ref }) => ref)\n })\n );\n\n // A recursive function to walk through the mappings, keeping track of which root nodes we have visited in the form of a path of root node identifiers.\n const followRefs = (mapping: { id: string | undefined; refs: string[] }, path: (string | undefined)[] = []) => {\n // Have we found a circular dependency?\n if (path.includes(mapping.id)) {\n // We found a circular dependency! Get the bad path of root node identifiers.\n const badPath = [...path, mapping.id];\n\n // Create the formatted path value. [undefined, \"a\", \"b\", \"c\", \"a\"] would be formatted as \"a -> b -> c -> a\".\n const badPathFormatted = badPath.filter((element) => !!element).join(\" => \");\n\n // No need to continue, we found a circular dependency.\n throw new Error(`circular dependency found in branch node references: ${badPathFormatted}`);\n }\n\n for (const ref of mapping.refs) {\n // Find the mapping for the root node with an identifer matching the current ref.\n const subMapping = rootNodeMappings.find(({ id }) => id === ref);\n\n // We may not have a mapping for this ref, which is normal when we aren't considering all globally registered subtrees.\n if (subMapping) {\n followRefs(subMapping, [...path, mapping.id]);\n } else if (includesGlobalSubtrees) {\n // We found a reference to a root node that doesn't exist, which is a problem seeing as the root node definitons includes all globally registered subtrees.\n throw new Error(\n mapping.id\n ? `subtree '${mapping.id}' has branch node that references root node '${ref}' which has not been defined`\n : `primary tree has branch node that references root node '${ref}' which has not been defined`\n );\n }\n }\n };\n\n // Start looking for circular dependencies and broken references from the primary root node definition.\n followRefs(rootNodeMappings.find((mapping) => typeof mapping.id === \"undefined\")!);\n}\n\n/**\n * Validate an object that we expect to be a node definition.\n * @param definition An object that we expect to be a node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateNode(definition: any, depth: number): void {\n // Every node must be valid object and have a non-empty 'type' string property.\n if (typeof definition !== \"object\" || typeof definition.type !== \"string\" || definition.type.length === 0) {\n throw new Error(\n `node definition is not an object or 'type' property is not a non-empty string at depth '${depth}'`\n );\n }\n\n // How we validate this node definition will depend on its type.\n switch (definition.type) {\n case \"action\":\n validateActionNode(definition, depth);\n break;\n\n case \"condition\":\n validateConditionNode(definition, depth);\n break;\n\n case \"wait\":\n validateWaitNode(definition, depth);\n break;\n\n case \"branch\":\n validateBranchNode(definition, depth);\n break;\n\n case \"root\":\n validateRootNode(definition, depth);\n break;\n\n case \"succeed\":\n validateSucceedNode(definition, depth);\n break;\n\n case \"fail\":\n validateFailNode(definition, depth);\n break;\n\n case \"flip\":\n validateFlipNode(definition, depth);\n break;\n\n case \"repeat\":\n validateRepeatNode(definition, depth);\n break;\n\n case \"retry\":\n validateRetryNode(definition, depth);\n break;\n\n case \"sequence\":\n validateSequenceNode(definition, depth);\n break;\n\n case \"selector\":\n validateSelectorNode(definition, depth);\n break;\n\n case \"parallel\":\n validateParallelNode(definition, depth);\n break;\n\n case \"lotto\":\n validateLottoNode(definition, depth);\n break;\n\n default:\n throw new Error(`unexpected node type of '${definition.type}' at depth '${depth}'`);\n }\n}\n\n/**\n * Validate any attributes for a given node definition.\n * @param definition The node definition.\n * @param depth The depth of the node in the behaviour tree definition.\n */\nfunction validateNodeAttributes(definition: any, depth: number): void {\n // Validate each of the attribute types for this node.\n [\"while\", \"until\", \"entry\", \"exit\", \"step\"].forEach((attributeName) => {\n // Attempt to grab the definition for the current attribute from the node definition.\n const attributeDefinition = definition[attributeName];\n\n // All node attributes are optional, so there is nothing to do if the current attribute is not defined.\n if (typeof attributeDefinition === \"undefined\") {\n return;\n }\n\n // The attribute definition must be an object.\n if (typeof attributeDefinition !== \"object\") {\n throw new Error(\n `expected attribute '${attributeName}' to be an object for '${definition.type}' node at depth '${depth}'`\n );\n }\n\n // The 'call' property must be defined for any attribute definition.\n if (typeof attributeDefinition.call !== \"string\" || attributeDefinition.call.length === 0) {\n throw new Error(\n `expected 'call' property for attribute '${attributeName}' to be a non-empty string for '${definition.type}' node at depth '${depth}'`\n );\n }\n\n // If any node attribute arguments have been defined then they must have been defined in an array.\n if (typeof attributeDefinition.args !== \"undefined\" && !Array.isArray(attributeDefinition.args)) {\n throw new Error(\n `expected 'args' property for attribute '${attributeName}' to be an array for '${definition.type}' node at depth '${depth}'`\n );\n }\n });\n}\n\n/**\n * Validate an object that we expect to be a root node definition.\n * @param definition An object that we expect to be a root node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateRootNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"root\") {\n throw new Error(\"expected node type of 'root' for root node\");\n }\n\n // A root node cannot be the child of another node.\n if (depth > 0) {\n throw new Error(\"a root node cannot be the child of another node\");\n }\n\n // Check that, if the root node 'id' property is defined, it is a non-empty string.\n if (typeof definition.id !== \"undefined\" && (typeof definition.id !== \"string\" || definition.id.length === 0)) {\n throw new Error(\"expected non-empty string for 'id' property if defined for root node\");\n }\n\n // A root node is a decorator node, so must have a child node defined.\n if (typeof definition.child === \"undefined\") {\n throw new Error(\"expected property 'child' to be defined for root node\");\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n\n // Validate the child node of this decorator node.\n validateNode(definition.child, depth + 1);\n}\n\n/**\n * Validate an object that we expect to be a succeed node definition.\n * @param definition An object that we expect to be a succeed node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateSucceedNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"succeed\") {\n throw new Error(`expected node type of 'succeed' for succeed node at depth '${depth}'`);\n }\n\n // A succeed node is a decorator node, so must have a child node defined.\n if (typeof definition.child === \"undefined\") {\n throw new Error(`expected property 'child' to be defined for succeed node at depth '${depth}'`);\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n\n // Validate the child node of this decorator node.\n validateNode(definition.child, depth + 1);\n}\n\n/**\n * Validate an object that we expect to be a fail node definition.\n * @param definition An object that we expect to be a fail node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateFailNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"fail\") {\n throw new Error(`expected node type of 'fail' for fail node at depth '${depth}'`);\n }\n\n // A fail node is a decorator node, so must have a child node defined.\n if (typeof definition.child === \"undefined\") {\n throw new Error(`expected property 'child' to be defined for fail node at depth '${depth}'`);\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n\n // Validate the child node of this decorator node.\n validateNode(definition.child, depth + 1);\n}\n\n/**\n * Validate an object that we expect to be a flip node definition.\n * @param definition An object that we expect to be a flip node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateFlipNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"flip\") {\n throw new Error(`expected node type of 'flip' for flip node at depth '${depth}'`);\n }\n\n // A flip node is a decorator node, so must have a child node defined.\n if (typeof definition.child === \"undefined\") {\n throw new Error(`expected property 'child' to be defined for flip node at depth '${depth}'`);\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n\n // Validate the child node of this decorator node.\n validateNode(definition.child, depth + 1);\n}\n\n/**\n * Validate an object that we expect to be a repeat node definition.\n * @param definition An object that we expect to be a repeat node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateRepeatNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"repeat\") {\n throw new Error(`expected node type of 'repeat' for repeat node at depth '${depth}'`);\n }\n\n // A repeat node is a decorator node, so must have a child node defined.\n if (typeof definition.child === \"undefined\") {\n throw new Error(`expected property 'child' to be defined for repeat node at depth '${depth}'`);\n }\n\n // Check whether an 'iterations' property has been defined, it may not have been if this node is to repeat indefinitely.\n if (typeof definition.iterations !== \"undefined\") {\n if (Array.isArray(definition.iterations)) {\n // Check whether any elements of the array are not integer values.\n const containsNonInteger = !!definition.iterations.filter((value: unknown) => !isInteger(value)).length;\n\n // If the 'iterations' property is an array then it MUST contain two integer values.\n if (definition.iterations.length !== 2 || containsNonInteger) {\n throw new Error(\n `expected array containing two integer values for 'iterations' property if defined for repeat node at depth '${depth}'`\n );\n }\n\n // A repeat node must have a positive min and max iterations count if they are defined.\n if (definition.iterations[0] < 0 || definition.iterations[1] < 0) {\n throw new Error(\n `expected positive minimum and maximum iterations count for 'iterations' property if defined for repeat node at depth '${depth}'`\n );\n }\n\n // A repeat node must not have a minimum iterations count that exceeds the maximum iterations count.\n if (definition.iterations[0] > definition.iterations[1]) {\n throw new Error(\n `expected minimum iterations count that does not exceed the maximum iterations count for 'iterations' property if defined for repeat node at depth '${depth}'`\n );\n }\n } else if (isInteger(definition.iterations)) {\n // A repeat node must have a positive number of iterations if defined.\n if (definition.iterations < 0) {\n throw new Error(\n `expected positive iterations count for 'iterations' property if defined for repeat node at depth '${depth}'`\n );\n }\n } else {\n throw new Error(\n `expected integer value or array containing two integer values for 'iterations' property if defined for repeat node at depth '${depth}'`\n );\n }\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n\n // Validate the child node of this decorator node.\n validateNode(definition.child, depth + 1);\n}\n\n/**\n * Validate an object that we expect to be a retry node definition.\n * @param definition An object that we expect to be a retry node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateRetryNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"retry\") {\n throw new Error(`expected node type of 'retry' for retry node at depth '${depth}'`);\n }\n\n // A retry node is a decorator node, so must have a child node defined.\n if (typeof definition.child === \"undefined\") {\n throw new Error(`expected property 'child' to be defined for retry node at depth '${depth}'`);\n }\n\n // Check whether an 'attempts' property has been defined, it may not have been if this node is to retry indefinitely.\n if (typeof definition.attempts !== \"undefined\") {\n if (Array.isArray(definition.attempts)) {\n // Check whether any elements of the array are not integer values.\n const containsNonInteger = !!definition.attempts.filter((value: unknown) => !isInteger(value)).length;\n\n // If the 'attempts' property is an array then it MUST contain two integer values.\n if (definition.attempts.length !== 2 || containsNonInteger) {\n throw new Error(\n `expected array containing two integer values for 'attempts' property if defined for retry node at depth '${depth}'`\n );\n }\n\n // A retry node must have a positive min and max attempts count if they are defined.\n if (definition.attempts[0] < 0 || definition.attempts[1] < 0) {\n throw new Error(\n `expected positive minimum and maximum attempts count for 'attempts' property if defined for retry node at depth '${depth}'`\n );\n }\n\n // A retry node must not have a minimum attempts count that exceeds the maximum attempts count.\n if (definition.attempts[0] > definition.attempts[1]) {\n throw new Error(\n `expected minimum attempts count that does not exceed the maximum attempts count for 'attempts' property if defined for retry node at depth '${depth}'`\n );\n }\n } else if (isInteger(definition.attempts)) {\n // A retry node must have a positive number of attempts if defined.\n if (definition.attempts < 0) {\n throw new Error(\n `expected positive attempts count for 'attempts' property if defined for retry node at depth '${depth}'`\n );\n }\n } else {\n throw new Error(\n `expected integer value or array containing two integer values for 'attempts' property if defined for retry node at depth '${depth}'`\n );\n }\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n\n // Validate the child node of this decorator node.\n validateNode(definition.child, depth + 1);\n}\n\n/**\n * Validate an object that we expect to be a branch node definition.\n * @param definition An object that we expect to be a branch node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateBranchNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"branch\") {\n throw new Error(`expected node type of 'branch' for branch node at depth '${depth}'`);\n }\n\n // Check that the branch node 'ref' property is defined and is a non-empty string.\n if (typeof definition.ref !== \"string\" || definition.ref.length === 0) {\n throw new Error(`expected non-empty string for 'ref' property for branch node at depth '${depth}'`);\n }\n\n // It is invalid to define guard attributes for a branch node as they should be defined on the referenced root node.\n [\"while\", \"until\"].forEach((attributeName) => {\n if (typeof definition[attributeName] !== \"undefined\") {\n throw new Error(\n `guards should not be defined for branch nodes but guard '${attributeName}' was defined for branch node at depth '${depth}'`\n );\n }\n });\n\n // It is invalid to define callback attributes for a branch node as they should be defined on the referenced root node.\n [\"entry\", \"exit\", \"step\"].forEach((attributeName) => {\n if (typeof definition[attributeName] !== \"undefined\") {\n throw new Error(\n `callbacks should not be defined for branch nodes but callback '${attributeName}' was defined for branch node at depth '${depth}'`\n );\n }\n });\n}\n\n/**\n * Validate an object that we expect to be a action node definition.\n * @param definition An object that we expect to be a action node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateActionNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"action\") {\n throw new Error(`expected node type of 'action' for action node at depth '${depth}'`);\n }\n\n // The 'call' property must be defined for a action node definition.\n if (typeof definition.call !== \"string\" || definition.call.length === 0) {\n throw new Error(`expected non-empty string for 'call' property of action node at depth '${depth}'`);\n }\n\n // If any action function arguments have been defined then they must have been defined in an array.\n if (typeof definition.args !== \"undefined\" && !Array.isArray(definition.args)) {\n throw new Error(`expected array for 'args' property if defined for action node at depth '${depth}'`);\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n}\n\n/**\n * Validate an object that we expect to be a condition node definition.\n * @param definition An object that we expect to be a condition node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateConditionNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"condition\") {\n throw new Error(`expected node type of 'condition' for condition node at depth '${depth}'`);\n }\n\n // The 'call' property must be defined for a condition node definition.\n if (typeof definition.call !== \"string\" || definition.call.length === 0) {\n throw new Error(`expected non-empty string for 'call' property of condition node at depth '${depth}'`);\n }\n\n // If any condition function arguments have been defined then they must have been defined in an array.\n if (typeof definition.args !== \"undefined\" && !Array.isArray(definition.args)) {\n throw new Error(`expected array for 'args' property if defined for condition node at depth '${depth}'`);\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n}\n\n/**\n * Validate an object that we expect to be a wait node definition.\n * @param definition An object that we expect to be a wait node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateWaitNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"wait\") {\n throw new Error(`expected node type of 'wait' for wait node at depth '${depth}'`);\n }\n\n // Check whether a 'duration' property has been defined, it may not have been if this node is to wait indefinitely.\n if (typeof definition.duration !== \"undefined\") {\n if (Array.isArray(definition.duration)) {\n // Check whether any elements of the array are not integer values.\n const containsNonInteger = !!definition.duration.filter((value: unknown) => !isInteger(value)).length;\n\n // If the 'duration' property is an array then it MUST contain two integer values.\n if (definition.duration.length !== 2 || containsNonInteger) {\n throw new Error(\n `expected array containing two integer values for 'duration' property if defined for wait node at depth '${depth}'`\n );\n }\n\n // A wait node must have a positive min and max duration value if they are defined.\n if (definition.duration[0] < 0 || definition.duration[1] < 0) {\n throw new Error(\n `expected positive minimum and maximum duration for 'duration' property if defined for wait node at depth '${depth}'`\n );\n }\n\n // A wait node must not have a minimum duration value that exceeds the maximum duration value.\n if (definition.duration[0] > definition.duration[1]) {\n throw new Error(\n `expected minimum duration value that does not exceed the maximum duration value for 'duration' property if defined for wait node at depth '${depth}'`\n );\n }\n } else if (isInteger(definition.duration)) {\n // A wait node must have a positive duration value if defined.\n if (definition.duration < 0) {\n throw new Error(\n `expected positive duration value for 'duration' property if defined for wait node at depth '${depth}'`\n );\n }\n } else {\n throw new Error(\n `expected integer value or array containing two integer values for 'duration' property if defined for wait node at depth '${depth}'`\n );\n }\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n}\n\n/**\n * Validate an object that we expect to be a sequence node definition.\n * @param definition An object that we expect to be a sequence node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateSequenceNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"sequence\") {\n throw new Error(`expected node type of 'sequence' for sequence node at depth '${depth}'`);\n }\n\n // A sequence node is a composite node, so must have a children nodes array defined.\n if (!Array.isArray(definition.children) || definition.children.length === 0) {\n throw new Error(`expected non-empty 'children' array to be defined for sequence node at depth '${depth}'`);\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n\n // Validate the child nodes of this composite node.\n definition.children.forEach((child: any) => validateNode(child, depth + 1));\n}\n\n/**\n * Validate an object that we expect to be a selector node definition.\n * @param definition An object that we expect to be a selector node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateSelectorNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"selector\") {\n throw new Error(`expected node type of 'selector' for selector node at depth '${depth}'`);\n }\n\n // A selector node is a composite node, so must have a children nodes array defined.\n if (!Array.isArray(definition.children) || definition.children.length === 0) {\n throw new Error(`expected non-empty 'children' array to be defined for selector node at depth '${depth}'`);\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n\n // Validate the child nodes of this composite node.\n definition.children.forEach((child: any) => validateNode(child, depth + 1));\n}\n\n/**\n * Validate an object that we expect to be a parallel node definition.\n * @param definition An object that we expect to be a parallel node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateParallelNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"parallel\") {\n throw new Error(`expected node type of 'parallel' for parallel node at depth '${depth}'`);\n }\n\n // A parallel node is a composite node, so must have a children nodes array defined.\n if (!Array.isArray(definition.children) || definition.children.length === 0) {\n throw new Error(`expected non-empty 'children' array to be defined for parallel node at depth '${depth}'`);\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n\n // Validate the child nodes of this composite node.\n definition.children.forEach((child: any) => validateNode(child, depth + 1));\n}\n\n/**\n * Validate an object that we expect to be a lotto node definition.\n * @param definition An object that we expect to be a lotto node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateLottoNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"lotto\") {\n throw new Error(`expected node type of 'lotto' for lotto node at depth '${depth}'`);\n }\n\n // A lotto node is a composite node, so must have a children nodes array defined.\n if (!Array.isArray(definition.children) || definition.children.length === 0) {\n throw new Error(`expected non-empty 'children' array to be defined for lotto node at depth '${depth}'`);\n }\n\n // Check whether a 'weights' property has been defined, if it has we expect it to be an array of weights.\n if (typeof definition.weights !== \"undefined\") {\n // Check that the weights property is an array of positive integers with an element for each child node element.\n if (\n !Array.isArray(definition.weights) ||\n definition.weights.length !== definition.children.length ||\n definition.weights.filter((value: unknown) => !isInteger(value)).length ||\n definition.weights.filter((value: number) => value < 0).length\n ) {\n throw new Error(\n `expected an array of positive integer weight values with a length matching the number of child nodes for 'weights' property if defined for lotto node at depth '${depth}'`\n );\n }\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n\n // Validate the child nodes of this composite node.\n definition.children.forEach((child: any) => validateNode(child, depth + 1));\n}\n\n/**\n * A helper function to create a failure validation result with the given error message.\n * @param errorMessage The validation failure error message.\n * @returns A failure validation result with the given error message.\n */\nfunction createValidationFailureResult(errorMessage: string): DefinitionValidationResult {\n return { succeeded: false, errorMessage };\n}\n", "import { ActionResult, Agent, GlobalFunction } from \"./Agent\";\nimport { RootNodeDefinition } from \"./BehaviourTreeDefinition\";\n\nexport type InvokerFunction = (args: any[]) => ActionResult | boolean;\n\n/**\n * A singleton used to store and lookup registered functions and subtrees.\n */\nexport default class Lookup {\n /**\n * The object holding any registered functions keyed on function name.\n */\n private static registeredFunctions: { [key: string]: GlobalFunction } = {};\n /**\n * The object holding any registered subtree root node definitions keyed on tree name.\n */\n private static registeredSubtrees: { [key: string]: RootNodeDefinition } = {};\n\n /**\n * Gets the function with the specified name.\n * @param name The name of the function.\n * @returns The function with the specified name.\n */\n public static getFunc(name: string): GlobalFunction {\n return this.registeredFunctions[name];\n }\n\n /**\n * Sets the function with the specified name for later lookup.\n * @param name The name of the function.\n * @param func The function.\n */\n public static setFunc(name: string, func: GlobalFunction): void {\n this.registeredFunctions[name] = func;\n }\n\n /**\n * Gets the function invoker for the specified agent and function name.\n * If a function with the specified name exists on the agent object then it will\n * be returned, otherwise we will then check the registered functions for a match.\n * @param agent The agent instance that this behaviour tree is modelling behaviour for.\n * @param name The function name.\n * @returns The function invoker for the specified agent and function name.\n */\n static getFuncInvoker(agent: Agent, name: string): InvokerFunction | null {\n // Check whether the agent contains the specified function.\n const agentFunction = agent[name];\n if (agentFunction && typeof agentFunction === \"function\") {\n return (args: any[]) => agentFunction.apply(agent, args);\n }\n\n // The agent does not contain the specified function but it may have been registered at some point.\n if (this.registeredFunctions[name] && typeof this.registeredFunctions[name] === \"function\") {\n const registeredFunction = this.registeredFunctions[name];\n return (args: any[]) => registeredFunction(agent, ...args.map((arg) => arg.value));\n }\n\n // We have no function to invoke.\n return null;\n }\n\n /**\n * Gets all registered subtree root node definitions.\n */\n static getSubtrees(): { [key: string]: RootNodeDefinition } {\n return this.registeredSubtrees;\n }\n\n /**\n * Sets the subtree with the specified name for later lookup.\n * @param name The name of the subtree.\n * @param subtree The subtree.\n */\n static setSubtree(name: string, subtree: RootNodeDefinition) {\n this.registeredSubtrees[name] = subtree;\n }\n\n /**\n * Removes the registered function or subtree with the specified name.\n * @param name The name of the registered function or subtree.\n */\n static remove(name: string) {\n delete this.registeredFunctions[name];\n delete this.registeredSubtrees[name];\n }\n\n /**\n * Remove all registered functions and subtrees.\n */\n static empty() {\n this.registeredFunctions = {};\n this.registeredSubtrees = {};\n }\n}\n", "import Node from \"../../nodes/Node\";\n\n/**\n * An exception thrown when evaluating node guard path conditions and a conditions fails.\n */\nexport default class GuardUnsatisifedException extends Error {\n /**\n * @param source The node at which a guard condition failed.\n */\n constructor(private source: Node) {\n super(\"A guard path condition has failed\");\n }\n\n /**\n * Gets whether the specified node is the node at which a guard condition failed.\n * @param node The node to check against the source node.\n * @returns Whether the specified node is the node at which a guard condition failed.\n */\n isSourceNode = (node: Node) => node === this.source;\n}\n", "import { Agent } from \"../../Agent\";\nimport Guard from \"./Guard\";\nimport Node from \"../../nodes/Node\";\nimport GuardUnsatisifedException from \"./GuardUnsatisifedException\";\n\nexport type GuardPathPart = {\n node: Node;\n guards: Guard[];\n};\n\n/**\n * Represents a path of node guards along a root-to-leaf tree path.\n */\nexport default class GuardPath {\n /**\n * @param nodes An array of objects defining a node instance -> guard link, ordered by node depth.\n */\n constructor(private nodes: GuardPathPart[]) {}\n\n /**\n * Evaluate guard conditions for all guards in the tree path, moving outwards from the root.\n * @param agent The agent, required for guard evaluation.\n * @returns An evaluation results object.\n */\n evaluate = (agent: Agent) => {\n // We need to evaluate guard conditions for nodes up the tree, moving outwards from the root.\n for (const details of this.nodes) {\n // There can be multiple guards per node.\n for (const guard of details.guards) {\n // Check whether the guard condition passes, and throw an exception if not.\n if (!guard.isSatisfied(agent)) {\n throw new GuardUnsatisifedException(details.node);\n }\n }\n }\n };\n}\n", "import { BehaviourTreeOptions } from \"../BehaviourTreeOptions\";\nimport State, { AnyState } from \"../State\";\nimport { Agent } from \"../Agent\";\nimport Leaf from \"./leaf/Leaf\";\nimport Attribute from \"../attributes/Attribute\";\nimport Entry from \"../attributes/callbacks/Entry\";\nimport Exit from \"../attributes/callbacks/Exit\";\nimport Step from \"../attributes/callbacks/Step\";\nimport Guard from \"../attributes/guards/Guard\";\nimport GuardPath from \"../attributes/guards/GuardPath\";\nimport GuardUnsatisifedException from \"../attributes/guards/GuardUnsatisifedException\";\n\n/**\n * A base node.\n */\nexport default abstract class Node {\n /**\n * The node uid.\n */\n private readonly uid: string = createNodeUid();\n /**\n * The node state.\n */\n private state: AnyState = State.READY;\n /**\n * The guard path to evaluate as part of a node update.\n */\n private guardPath: GuardPath | undefined;\n\n /**\n * @param type The node type.\n * @param attributes The node attributes.\n * @param args The node argument definitions.\n */\n constructor(private type: string, private attributes: Attribute[], private args: any[]) {}\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected abstract onUpdate(agent: Agent, options: BehaviourTreeOptions): void;\n\n /**\n * Gets the name of the node.\n */\n public abstract getName(): string;\n\n /**\n * Gets whether this node is a leaf node.\n */\n public abstract isLeafNode: () => this is Leaf;\n\n /**\n * Gets/Sets the state of the node.\n */\n getState = (): AnyState => this.state;\n setState = (value: AnyState): void => {\n this.state = value;\n };\n\n /**\n * Gets the unique id of the node.\n */\n getUid = () => this.uid;\n\n /**\n * Gets the type of the node.\n */\n getType = () => this.type;\n\n /**\n * Gets the node attributes.\n */\n getAttributes = () => this.attributes;\n\n /**\n * Gets the node arguments.\n */\n getArguments = () => this.args;\n\n /**\n * Gets the node attribute with the specified type, or null if it does not exist.\n */\n getAttribute(type: \"entry\" | \"ENTRY\"): Entry;\n getAttribute(type: \"exit\" | \"EXIT\"): Exit;\n getAttribute(type: \"step\" | \"STEP\"): Step;\n getAttribute(type: string): Attribute {\n return (\n this.getAttributes().filter((decorator) => decorator.type.toUpperCase() === type.toUpperCase())[0] || null\n );\n }\n\n /**\n * Gets the node attributes.\n */\n getGuardAttributes = (): Guard[] => this.getAttributes().filter((decorator) => decorator.isGuard()) as Guard[];\n\n /**\n * Sets the guard path to evaluate as part of a node update.\n */\n setGuardPath = (value: GuardPath) => (this.guardPath = value);\n\n /**\n * Gets whether a guard path is assigned to this node.\n */\n hasGuardPath = () => !!this.guardPath;\n\n /**\n * Gets whether this node is in the specified state.\n * @param value The value to compare to the node state.\n */\n public is(value: AnyState): boolean {\n return this.state === value;\n }\n\n /**\n * Reset the state of the node.\n */\n public reset(): void {\n this.setState(State.READY);\n }\n\n /**\n * Abort the running of this node.\n * @param agent The agent.\n */\n public abort(agent: Agent): void {\n // There is nothing to do if this node is not in the running state.\n if (!this.is(State.RUNNING)) {\n return;\n }\n\n // Reset the state of this node.\n this.reset();\n\n this.getAttribute(\"exit\")?.callAgentFunction(agent, false, true);\n }\n\n /**\n * Update the node.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n * @returns The result of the update.\n */\n public update(agent: Agent, options: BehaviourTreeOptions): void {\n // If this node is already in a 'SUCCEEDED' or 'FAILED' state then there is nothing to do.\n if (this.is(State.SUCCEEDED) || this.is(State.FAILED)) {\n return;\n }\n\n try {\n // Evaluate all of the guard path conditions for the current tree path.\n this.guardPath!.evaluate(agent);\n\n // If this node is in the READY state then call the ENTRY for this node if it exists.\n if (this.is(State.READY)) {\n this.getAttribute(\"entry\")?.callAgentFunction(agent);\n }\n\n this.getAttribute(\"step\")?.callAgentFunction(agent);\n\n // Do the actual update.\n this.onUpdate(agent, options);\n\n // If this node is now in a 'SUCCEEDED' or 'FAILED' state then call the EXIT for this node if it exists.\n if (this.is(State.SUCCEEDED) || this.is(State.FAILED)) {\n this.getAttribute(\"exit\")?.callAgentFunction(agent, this.is(State.SUCCEEDED), false);\n }\n } catch (error) {\n // If the error is a GuardUnsatisfiedException then we need to determine if this node is the source.\n if (error instanceof GuardUnsatisifedException && error.isSourceNode(this)) {\n // Abort the current node.\n this.abort(agent);\n\n // Any node that is the source of an abort will be a failed node.\n this.setState(State.FAILED);\n } else {\n throw error;\n }\n }\n }\n}\n\n/**\n * Create a randomly generated node uid.\n * @returns A randomly generated node uid.\n */\nfunction createNodeUid(): string {\n var S4 = function () {\n return (((1 + Math.random()) * 0x10000) | 0).toString(16).substring(1);\n };\n return S4() + S4() + \"-\" + S4() + \"-\" + S4() + \"-\" + S4() + \"-\" + S4() + S4() + S4();\n}\n", "import Node from \"../Node\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\n\n/**\n * A composite node that wraps child nodes.\n */\nexport default abstract class Composite extends Node {\n /**\n * @param type The node type.\n * @param attributes The node attributes.\n * @param children The child nodes.\n */\n constructor(type: string, attributes: Attribute[], protected children: Node[]) {\n super(type, attributes, []);\n }\n\n /**\n * Gets whether this node is a leaf node.\n */\n isLeafNode = () => false;\n\n /**\n * Gets the children of this node.\n */\n getChildren = () => this.children;\n\n /**\n * Reset the state of the node.\n */\n reset = () => {\n // Reset the state of this node.\n this.setState(State.READY);\n\n // Reset the state of any child nodes.\n this.getChildren().forEach((child) => child.reset());\n };\n\n /**\n * Abort the running of this node.\n * @param agent The agent.\n */\n abort = (agent: Agent) => {\n // There is nothing to do if this node is not in the running state.\n if (!this.is(State.RUNNING)) {\n return;\n }\n\n // Abort any child nodes.\n this.getChildren().forEach((child) => child.abort(agent));\n\n // Reset the state of this node.\n this.reset();\n\n this.getAttribute(\"exit\")?.callAgentFunction(agent, false, true);\n };\n}\n", "import Composite from \"./Composite\";\nimport State from \"../../State\";\nimport Node from \"../Node\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A PARALLEL node.\n * The child nodes are executed concurrently until one fails or all succeed.\n */\nexport default class Parallel extends Composite {\n /**\n * @param attributes The node attributes.\n * @param children The child nodes.\n */\n constructor(attributes: Attribute[], children: Node[]) {\n super(\"parallel\", attributes, children);\n }\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // Keep a count of the number of succeeded child nodes.\n let succeededCount = 0;\n\n let hasChildFailed = false;\n\n // Iterate over all of the children of this node.\n for (const child of this.children) {\n // If the child has never been updated or is running then we will need to update it now.\n if (child.getState() === State.READY || child.getState() === State.RUNNING) {\n // Update the child of this node.\n child.update(agent, options);\n }\n\n // If the current child has a state of 'SUCCEEDED' then we should move on to the next child.\n if (child.getState() === State.SUCCEEDED) {\n // The child node has succeeded, keep track of this to determine if all children have.\n succeededCount++;\n\n // The child node succeeded, but we have not finished checking every child node yet.\n continue;\n }\n\n // If the current child has a state of 'FAILED' then this node is also a 'FAILED' node.\n if (child.getState() === State.FAILED) {\n hasChildFailed = true;\n\n // There is no need to check the rest of the children.\n break;\n }\n\n // The node should be in the 'RUNNING' state.\n if (child.getState() !== State.RUNNING) {\n // The child node was not in an expected state.\n throw new Error(\"child node was not in an expected state.\");\n }\n }\n\n if (hasChildFailed) {\n // This node is a 'FAILED' node.\n this.setState(State.FAILED);\n\n // Abort every running child.\n for (const child of this.children) {\n if (child.getState() === State.RUNNING) {\n child.abort(agent);\n }\n }\n } else {\n // If all children have succeeded then this node has also succeeded, otherwise it is still running.\n this.setState(succeededCount === this.children.length ? State.SUCCEEDED : State.RUNNING);\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => \"PARALLEL\";\n}\n", "import Composite from \"./Composite\";\nimport Node from \"../Node\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A SELECTOR node.\n * The child nodes are executed in sequence until one succeeds or all fail.\n */\nexport default class Selector extends Composite {\n /**\n * @param attributes The node attributes.\n * @param children The child nodes.\n */\n constructor(attributes: Attribute[], protected children: Node[]) {\n super(\"selector\", attributes, children);\n }\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // Iterate over all of the children of this node.\n for (const child of this.children) {\n // If the child has never been updated or is running then we will need to update it now.\n if (child.getState() === State.READY || child.getState() === State.RUNNING) {\n // Update the child of this node.\n child.update(agent, options);\n }\n\n // If the current child has a state of 'SUCCEEDED' then this node is also a 'SUCCEEDED' node.\n if (child.getState() === State.SUCCEEDED) {\n // This node is a 'SUCCEEDED' node.\n this.setState(State.SUCCEEDED);\n\n // There is no need to check the rest of the selector nodes.\n return;\n }\n\n // If the current child has a state of 'FAILED' then we should move on to the next child.\n if (child.getState() === State.FAILED) {\n // Find out if the current child is the last one in the selector.\n // If it is then this sequence node has also failed.\n if (this.children.indexOf(child) === this.children.length - 1) {\n // This node is a 'FAILED' node.\n this.setState(State.FAILED);\n\n // There is no need to check the rest of the selector as we have completed it.\n return;\n } else {\n // The child node failed, try the next one.\n continue;\n }\n }\n\n // The node should be in the 'RUNNING' state.\n if (child.getState() === State.RUNNING) {\n // This node is a 'RUNNING' node.\n this.setState(State.RUNNING);\n\n // There is no need to check the rest of the selector as the current child is still running.\n return;\n }\n\n // The child node was not in an expected state.\n throw new Error(\"child node was not in an expected state.\");\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => \"SELECTOR\";\n}\n", "import Composite from \"./Composite\";\nimport Node from \"../Node\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A SEQUENCE node.\n * The child nodes are executed in sequence until one fails or all succeed.\n */\nexport default class Sequence extends Composite {\n /**\n * @param attributes The node attributes.\n * @param children The child nodes.\n */\n constructor(attributes: Attribute[], protected children: Node[]) {\n super(\"sequence\", attributes, children);\n }\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // Iterate over all of the children of this node.\n for (const child of this.children) {\n // If the child has never been updated or is running then we will need to update it now.\n if (child.getState() === State.READY || child.getState() === State.RUNNING) {\n // Update the child of this node.\n child.update(agent, options);\n }\n\n // If the current child has a state of 'SUCCEEDED' then we should move on to the next child.\n if (child.getState() === State.SUCCEEDED) {\n // Find out if the current child is the last one in the sequence.\n // If it is then this sequence node has also succeeded.\n if (this.children.indexOf(child) === this.children.length - 1) {\n // This node is a 'SUCCEEDED' node.\n this.setState(State.SUCCEEDED);\n\n // There is no need to check the rest of the sequence as we have completed it.\n return;\n } else {\n // The child node succeeded, but we have not finished the sequence yet.\n continue;\n }\n }\n\n // If the current child has a state of 'FAILED' then this node is also a 'FAILED' node.\n if (child.getState() === State.FAILED) {\n // This node is a 'FAILED' node.\n this.setState(State.FAILED);\n\n // There is no need to check the rest of the sequence.\n return;\n }\n\n // The node should be in the 'RUNNING' state.\n if (child.getState() === State.RUNNING) {\n // This node is a 'RUNNING' node.\n this.setState(State.RUNNING);\n\n // There is no need to check the rest of the sequence as the current child is still running.\n return;\n }\n\n // The child node was not in an expected state.\n throw new Error(\"child node was not in an expected state.\");\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => \"SEQUENCE\";\n}\n", "import createLotto from \"lotto-draw\";\n\nimport Node from \"../Node\";\nimport Composite from \"./Composite\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A LOTTO node.\n * A winning child is picked on the initial update of this node, based on ticket weighting.\n * The state of this node will match the state of the winning child.\n */\nexport default class Lotto extends Composite {\n /**\n * @param attributes The node attributes.\n * @param weights The child node weights.\n * @param children The child nodes.\n */\n constructor(attributes: Attribute[], private weights: number[] | undefined, children: Node[]) {\n super(\"lotto\", attributes, children);\n }\n\n /**\n * The child node selected to be the active one.\n */\n private selectedChild: Node | undefined;\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // If this node is in the READY state then we need to pick a winning child node.\n if (this.is(State.READY)) {\n // Create a lotto draw with which to randomly pick a child node to become the active one.\n const lottoDraw = createLotto({\n // Hook up the optional 'random' behaviour tree function option to the one used by 'lotto-draw'.\n random: options.random,\n // Pass in each child node as a participant in the lotto draw with their respective ticket count.\n participants: this.children.map((child, index) => [child, this.weights?.[index] || 1])\n });\n\n // Randomly pick a child based on ticket weighting, this will become the active child for this composite node.\n this.selectedChild = lottoDraw.draw() || undefined;\n }\n\n // If something went wrong and we don't have an active child then we should throw an error.\n if (!this.selectedChild) {\n throw new Error(\"failed to update lotto node as it has no active child\");\n }\n\n // If the selected child has never been updated or is running then we will need to update it now.\n if (this.selectedChild.getState() === State.READY || this.selectedChild.getState() === State.RUNNING) {\n this.selectedChild.update(agent, options);\n }\n\n // The state of the lotto node is the state of its selected child.\n this.setState(this.selectedChild.getState());\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => (this.weights ? `LOTTO [${this.weights.join(\",\")}]` : \"LOTTO\");\n}\n", "import Node from \"../Node\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\n\n/**\n * A decorator node that wraps a single child node.\n */\nexport default abstract class Decorator extends Node {\n /**\n * @param type The node type.\n * @param attributes The node attributes.\n * @param child The child node.\n */\n constructor(type: string, attributes: Attribute[], protected child: Node) {\n super(type, attributes, []);\n }\n\n /**\n * Gets whether this node is a leaf node.\n */\n isLeafNode = () => false;\n\n /**\n * Gets the children of this node.\n */\n getChildren = () => [this.child];\n\n /**\n * Reset the state of the node.\n */\n reset = () => {\n // Reset the state of this node.\n this.setState(State.READY);\n\n // Reset the state of the child node.\n this.child.reset();\n };\n\n /**\n * Abort the running of this node.\n * @param agent The agent.\n */\n abort = (agent: Agent) => {\n // There is nothing to do if this node is not in the running state.\n if (!this.is(State.RUNNING)) {\n return;\n }\n\n // Abort the child node.\n this.child.abort(agent);\n\n // Reset the state of this node.\n this.reset();\n\n this.getAttribute(\"exit\")?.callAgentFunction(agent, false, true);\n };\n}\n", "import Node from \"../Node\";\nimport Decorator from \"./Decorator\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A Fail node.\n * This node wraps a single child and will always move to the 'FAILED' state when the child moves to a 'SUCCEEDED' or 'FAILED' state.\n */\nexport default class Fail extends Decorator {\n /**\n * @param attributes The node attributes.\n * @param child The child node.\n */\n constructor(attributes: Attribute[], child: Node) {\n super(\"fail\", attributes, child);\n }\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // If the child has never been updated or is running then we will need to update it now.\n if (this.child.getState() === State.READY || this.child.getState() === State.RUNNING) {\n this.child.update(agent, options);\n }\n\n // The state of this node will depend in the state of its child.\n switch (this.child.getState()) {\n case State.RUNNING:\n this.setState(State.RUNNING);\n break;\n\n case State.SUCCEEDED:\n case State.FAILED:\n this.setState(State.FAILED);\n break;\n\n default:\n this.setState(State.READY);\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => \"FAIL\";\n}\n", "import Decorator from \"./Decorator\";\nimport State from \"../../State\";\nimport Node from \"../Node\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A Flip node.\n * This node wraps a single child and will flip the state of the child state.\n */\nexport default class Flip extends Decorator {\n /**\n * @param attributes The node attributes.\n * @param child The child node.\n */\n constructor(attributes: Attribute[], child: Node) {\n super(\"flip\", attributes, child);\n }\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // If the child has never been updated or is running then we will need to update it now.\n if (this.child.getState() === State.READY || this.child.getState() === State.RUNNING) {\n this.child.update(agent, options);\n }\n\n // The state of this node will depend in the state of its child.\n switch (this.child.getState()) {\n case State.RUNNING:\n this.setState(State.RUNNING);\n break;\n\n case State.SUCCEEDED:\n this.setState(State.FAILED);\n break;\n\n case State.FAILED:\n this.setState(State.SUCCEEDED);\n break;\n\n default:\n this.setState(State.READY);\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => \"FLIP\";\n}\n", "import Node from \"../Node\";\nimport Decorator from \"./Decorator\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A REPEAT node.\n * The node has a single child which can have:\n * -- A number of iterations for which to repeat the child node.\n * -- An infinite repeat loop if neither an iteration count or a condition function is defined.\n * The REPEAT node will stop and have a 'FAILED' state if its child is ever in a 'FAILED' state after an update.\n * The REPEAT node will attempt to move on to the next iteration if its child is ever in a 'SUCCEEDED' state.\n */\nexport default class Repeat extends Decorator {\n /**\n * @param attributes The node attributes.\n * @param iterations The number of iterations to repeat the child node.\n * @param iterationsMin The minimum possible number of iterations to repeat the child node.\n * @param iterationsMax The maximum possible number of iterations to repeat the child node.\n * @param child The child node.\n */\n constructor(\n attributes: Attribute[],\n private iterations: number | null,\n private iterationsMin: number | null,\n private iterationsMax: number | null,\n child: Node\n ) {\n super(\"repeat\", attributes, child);\n }\n\n /**\n * The number of target iterations to make.\n */\n private targetIterationCount: number | null = null;\n\n /**\n * The current iteration count.\n */\n private currentIterationCount: number = 0;\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // If this node is in the READY state then we need to reset the child and the target iteration count.\n if (this.is(State.READY)) {\n // Reset the child node.\n this.child.reset();\n\n // Reset the current iteration count.\n this.currentIterationCount = 0;\n\n // Set the target iteration count.\n this.setTargetIterationCount(options);\n }\n\n // Do a check to see if we can iterate. If we can then this node will move into the 'RUNNING' state.\n // If we cannot iterate then we have hit our target iteration count, which means that the node has succeeded.\n if (this.canIterate()) {\n // This node is in the running state and can do its initial iteration.\n this.setState(State.RUNNING);\n\n // We may have already completed an iteration, meaning that the child node will be in the SUCCEEDED state.\n // If this is the case then we will have to reset the child node now.\n if (this.child.getState() === State.SUCCEEDED) {\n this.child.reset();\n }\n\n // Update the child of this node.\n this.child.update(agent, options);\n\n // If the child moved into the FAILED state when we updated it then there is nothing left to do and this node has also failed.\n // If it has moved into the SUCCEEDED state then we have completed the current iteration.\n if (this.child.getState() === State.FAILED) {\n // The child has failed, meaning that this node has failed.\n this.setState(State.FAILED);\n\n return;\n } else if (this.child.getState() === State.SUCCEEDED) {\n // We have completed an iteration.\n this.currentIterationCount += 1;\n }\n } else {\n // This node is in the 'SUCCEEDED' state as we cannot iterate any more.\n this.setState(State.SUCCEEDED);\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => {\n if (this.iterations !== null) {\n return `REPEAT ${this.iterations}x`;\n } else if (this.iterationsMin !== null && this.iterationsMax !== null) {\n return `REPEAT ${this.iterationsMin}x-${this.iterationsMax}x`;\n } else {\n return \"REPEAT\";\n }\n };\n\n /**\n * Reset the state of the node.\n */\n reset = () => {\n // Reset the state of this node.\n this.setState(State.READY);\n\n // Reset the current iteration count.\n this.currentIterationCount = 0;\n\n // Reset the child node.\n this.child.reset();\n };\n\n /**\n * Gets whether an iteration can be made.\n * @returns Whether an iteration can be made.\n */\n private canIterate = () => {\n if (this.targetIterationCount !== null) {\n // We can iterate as long as we have not reached our target iteration count.\n return this.currentIterationCount < this.targetIterationCount;\n }\n\n // If neither an iteration count or a condition function were defined then we can iterate indefinitely.\n return true;\n };\n\n /**\n * Sets the target iteration count.\n * @param options The behaviour tree options object.\n */\n private setTargetIterationCount = (options: BehaviourTreeOptions) => {\n // Are we dealing with an explicit iteration count or will we be randomly picking a iteration count between the min and max iteration count.\n if (this.iterations !== null) {\n this.targetIterationCount = this.iterations;\n } else if (this.iterationsMin !== null && this.iterationsMax !== null) {\n // We will be picking a random iteration count between a min and max iteration count, if the optional 'random'\n // behaviour tree function option is defined then we will be using that, otherwise we will fall back to using Math.random.\n const random = typeof options.random === \"function\" ? options.random : Math.random;\n\n // Pick a random iteration count between a min and max iteration count.\n this.targetIterationCount = Math.floor(\n random() * (this.iterationsMax - this.iterationsMin + 1) + this.iterationsMin\n );\n } else {\n this.targetIterationCount = null;\n }\n };\n}\n", "import Node from \"../Node\";\nimport Decorator from \"./Decorator\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A RETRY node.\n * The node has a single child which can have:\n * -- A number of iterations for which to repeat the child node.\n * -- An infinite repeat loop if neither an iteration count or a condition function is defined.\n * The RETRY node will stop and have a 'SUCCEEDED' state if its child is ever in a 'SUCCEEDED' state after an update.\n * The RETRY node will attempt to move on to the next iteration if its child is ever in a 'FAILED' state.\n */\nexport default class Retry extends Decorator {\n /**\n * @param attributes The node attributes.\n * @param attempts The number of attempts to retry the child node.\n * @param attemptsMin The minimum possible number of attempts to retry the child node.\n * @param attemptsMax The maximum possible number of attempts to retry the child node.\n * @param child The child node.\n */\n constructor(\n attributes: Attribute[],\n private attempts: number | null,\n private attemptsMin: number | null,\n private attemptsMax: number | null,\n child: Node\n ) {\n super(\"retry\", attributes, child);\n }\n\n /**\n * The number of target attempts to make.\n */\n private targetAttemptCount: number | null = null;\n\n /**\n * The current attempt count.\n */\n private currentAttemptCount: number = 0;\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // If this node is in the READY state then we need to reset the child and the target attempt count.\n if (this.is(State.READY)) {\n // Reset the child node.\n this.child.reset();\n\n // Reset the current attempt count.\n this.currentAttemptCount = 0;\n\n // Set the target attempt count.\n this.setTargetAttemptCount(options);\n }\n\n // Do a check to see if we can attempt. If we can then this node will move into the 'RUNNING' state.\n // If we cannot attempt then we have hit our target attempt count, which means that the node has succeeded.\n if (this.canAttempt()) {\n // This node is in the running state and can do its initial attempt.\n this.setState(State.RUNNING);\n\n // We may have already completed an attempt, meaning that the child node will be in the FAILED state.\n // If this is the case then we will have to reset the child node now.\n if (this.child.getState() === State.FAILED) {\n this.child.reset();\n }\n\n // Update the child of this node.\n this.child.update(agent, options);\n\n // If the child moved into the SUCCEEDED state when we updated it then there is nothing left to do and this node has also succeeded.\n // If it has moved into the FAILED state then we have completed the current attempt.\n if (this.child.getState() === State.SUCCEEDED) {\n // The child has succeeded, meaning that this node has succeeded.\n this.setState(State.SUCCEEDED);\n\n return;\n } else if (this.child.getState() === State.FAILED) {\n // We have completed an attempt.\n this.currentAttemptCount += 1;\n }\n } else {\n // This node is in the 'FAILED' state as we cannot iterate any more.\n this.setState(State.FAILED);\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => {\n if (this.attempts !== null) {\n return `RETRY ${this.attempts}x`;\n } else if (this.attemptsMin !== null && this.attemptsMax !== null) {\n return `RETRY ${this.attemptsMin}x-${this.attemptsMax}x`;\n } else {\n return \"RETRY\";\n }\n };\n\n /**\n * Reset the state of the node.\n */\n reset = () => {\n // Reset the state of this node.\n this.setState(State.READY);\n\n // Reset the current attempt count.\n this.currentAttemptCount = 0;\n\n // Reset the child node.\n this.child.reset();\n };\n\n /**\n * Gets whether an attempt can be made.\n * @returns Whether an attempt can be made.\n */\n canAttempt = () => {\n if (this.targetAttemptCount !== null) {\n // We can attempt as long as we have not reached our target attempt count.\n return this.currentAttemptCount < this.targetAttemptCount;\n }\n\n // If neither an attempt count or a condition function were defined then we can attempt indefinitely.\n return true;\n };\n\n /**\n * Sets the target attempt count.\n * @param options The behaviour tree options object.\n */\n setTargetAttemptCount = (options: BehaviourTreeOptions) => {\n // Are we dealing with an explicit attempt count or will we be randomly picking an attempt count between the min and max attempt count.\n if (this.attempts !== null) {\n this.targetAttemptCount = this.attempts;\n } else if (this.attemptsMin !== null && this.attemptsMax !== null) {\n // We will be picking a random attempt count between a min and max attempt count, if the optional 'random'\n // behaviour tree function option is defined then we will be using that, otherwise we will fall back to using Math.random.\n const random = typeof options.random === \"function\" ? options.random : Math.random;\n\n // Pick a random attempt count between a min and max attempt count.\n this.targetAttemptCount = Math.floor(\n random() * (this.attemptsMax - this.attemptsMin + 1) + this.attemptsMin\n );\n } else {\n this.targetAttemptCount = null;\n }\n };\n}\n", "import Node from \"../Node\";\nimport Decorator from \"./Decorator\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A Root node.\n * The root node will have a single child.\n */\nexport default class Root extends Decorator {\n /**\n * @param attributes The node attributes.\n * @param child The child node.\n */\n constructor(attributes: Attribute[], child: Node) {\n super(\"root\", attributes, child);\n }\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // If the child has never been updated or is running then we will need to update it now.\n if (this.child.getState() === State.READY || this.child.getState() === State.RUNNING) {\n // Update the child of this node.\n this.child.update(agent, options);\n }\n\n // The state of the root node is the state of its child.\n this.setState(this.child.getState());\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => \"ROOT\";\n}\n", "import Node from \"../Node\";\nimport Decorator from \"./Decorator\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A Succeed node.\n * This node wraps a single child and will always move to the 'SUCCEEDED' state when the child moves to a 'SUCCEEDED' or 'FAILED' state.\n */\nexport default class Succeed extends Decorator {\n /**\n * @param attributes The node attributes.\n * @param child The child node.\n */\n constructor(attributes: Attribute[], child: Node) {\n super(\"succeed\", attributes, child);\n }\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // If the child has never been updated or is running then we will need to update it now.\n if (this.child.getState() === State.READY || this.child.getState() === State.RUNNING) {\n this.child.update(agent, options);\n }\n\n // The state of this node will depend in the state of its child.\n switch (this.child.getState()) {\n case State.RUNNING:\n this.setState(State.RUNNING);\n break;\n\n case State.SUCCEEDED:\n case State.FAILED:\n this.setState(State.SUCCEEDED);\n break;\n\n default:\n this.setState(State.READY);\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => \"SUCCEED\";\n}\n", "import Node from \"../Node\";\n\n/**\n * A leaf node.\n */\nexport default abstract class Leaf extends Node {\n /**\n * Gets whether this node is a leaf node.\n */\n isLeafNode = () => true;\n}\n", "import { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\nimport State, { CompleteState } from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Leaf from \"./Leaf\";\nimport Lookup from \"../../Lookup\";\nimport Attribute from \"../../attributes/Attribute\";\n\n/**\n * The type representing a resolved/rejected update promise.\n */\ntype UpdatePromiseResult = {\n /**\n * Whether the promise was resolved rather than rejected.\n */\n isResolved: boolean;\n\n /**\n * The promise resolved value or rejection reason.\n */\n value: any;\n};\n\n/**\n * An Action leaf node.\n * This represents an immediate or ongoing state of behaviour.\n */\nexport default class Action extends Leaf {\n /**\n * @param attributes The node attributes.\n * @param actionName The action name.\n * @param actionArguments The array of action argument definitions.\n */\n constructor(attributes: Attribute[], private actionName: string, private actionArguments: any[]) {\n super(\"action\", attributes, actionArguments);\n }\n\n /**\n * Whether there is a pending update promise.\n */\n private isUsingUpdatePromise = false;\n\n /**\n * The finished state result of an update promise.\n */\n private updatePromiseResult: UpdatePromiseResult | null = null;\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // If the result of this action depends on an update promise then there is nothing to do until it settles.\n if (this.isUsingUpdatePromise) {\n // Are we still waiting for our update promise to settle?\n if (!this.updatePromiseResult) {\n return;\n }\n\n const { isResolved, value } = this.updatePromiseResult;\n\n // Our update promise settled, was it resolved or rejected?\n if (isResolved) {\n // Our promise resolved so check to make sure the result is a valid finished state.\n if (value !== State.SUCCEEDED && value !== State.FAILED) {\n throw new Error(\n \"action node promise resolved with an invalid value, expected a State.SUCCEEDED or State.FAILED value to be returned\"\n );\n }\n\n // Set the state of this node to match the state returned by the promise.\n this.setState(value);\n\n return;\n } else {\n // The promise was rejected, which isn't great.\n throw new Error(`action function '${this.actionName}' promise rejected with '${value}'`);\n }\n }\n\n // Attempt to get the invoker for the action function.\n const actionFuncInvoker = Lookup.getFuncInvoker(agent, this.actionName);\n\n // The action function should be defined.\n if (actionFuncInvoker === null) {\n throw new Error(\n `cannot update action node as the action '${this.actionName}' function is not defined on the agent and has not been registered`\n );\n }\n\n let actionFunctionResult;\n\n try {\n // Call the action function, the result of which may be:\n // - The finished state of this action node.\n // - A promise to return a finished node state.\n // - Undefined if the node should remain in the running state.\n actionFunctionResult = actionFuncInvoker(this.actionArguments) as CompleteState | Promise;\n } catch (error) {\n // The user was naughty and threw something.\n throw new Error(`action function '${this.actionName}' threw '${error}'`);\n }\n\n if (actionFunctionResult instanceof Promise) {\n actionFunctionResult.then(\n (result) => {\n // If 'isUpdatePromisePending' is not set then the promise was cleared as it was resolving, probably via an abort of reset.\n if (!this.isUsingUpdatePromise) {\n return;\n }\n\n // Set the resolved update promise result so that it can be handled on the next update of this node.\n this.updatePromiseResult = {\n isResolved: true,\n value: result\n };\n },\n (reason) => {\n // If 'isUpdatePromisePending' is not set then the promise was cleared as it was resolving, probably via an abort or reset.\n if (!this.isUsingUpdatePromise) {\n return;\n }\n\n // Set the rejected update promise result so that it can be handled on the next update of this node.\n this.updatePromiseResult = {\n isResolved: false,\n value: reason\n };\n }\n );\n\n // This node will be in the 'RUNNING' state until the update promise resolves.\n this.setState(State.RUNNING);\n\n // We are now waiting for the promise returned by the use to resolve before we know what state this node is in.\n this.isUsingUpdatePromise = true;\n } else {\n // Validate the returned value.\n this.validateUpdateResult(actionFunctionResult);\n\n // Set the state of this node, this may be undefined, which just means that the node is still in the 'RUNNING' state.\n this.setState(actionFunctionResult || State.RUNNING);\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => this.actionName;\n\n /**\n * Reset the state of the node.\n */\n reset = () => {\n // Reset the state of this node.\n this.setState(State.READY);\n\n // There is no longer an update promise that we care about.\n this.isUsingUpdatePromise = false;\n this.updatePromiseResult = null;\n };\n\n /**\n * Validate the result of an update function call.\n * @param result The result of an update function call.\n */\n private validateUpdateResult = (result: CompleteState | State.RUNNING) => {\n switch (result) {\n case State.SUCCEEDED:\n case State.FAILED:\n case State.RUNNING:\n case undefined:\n return;\n default:\n throw new Error(\n `expected action function '${this.actionName}' to return an optional State.SUCCEEDED or State.FAILED value but returned '${result}'`\n );\n }\n };\n}\n", "import { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Leaf from \"./Leaf\";\nimport Lookup from \"../../Lookup\";\nimport Attribute from \"../../attributes/Attribute\";\n\n/**\n * A Condition leaf node.\n * This will succeed or fail immediately based on an agent predicate, without moving to the 'RUNNING' state.\n */\nexport default class Condition extends Leaf {\n /**\n * @param attributes The node attributes.\n * @param conditionName The name of the condition function.\n * @param conditionArguments The array of condition argument definitions.\n */\n constructor(attributes: Attribute[], private conditionName: string, private conditionArguments: any[]) {\n super(\"condition\", attributes, conditionArguments);\n }\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // Attempt to get the invoker for the condition function.\n const conditionFuncInvoker = Lookup.getFuncInvoker(agent, this.conditionName);\n\n // The condition function should be defined.\n if (conditionFuncInvoker === null) {\n throw new Error(\n `cannot update condition node as the condition '${this.conditionName}' function is not defined on the agent and has not been registered`\n );\n }\n\n let conditionFunctionResult;\n\n try {\n // Call the condition function to determine the state of this node, the result of which should be a boolean.\n conditionFunctionResult = conditionFuncInvoker(this.conditionArguments);\n } catch (error) {\n // The user was naughty and threw something.\n throw new Error(`condition function '${this.conditionName}' threw '${error}'`);\n }\n\n // The result of calling the condition function must be a boolean value.\n if (typeof conditionFunctionResult !== \"boolean\") {\n throw new Error(\n `expected condition function '${this.conditionName}' to return a boolean but returned '${conditionFunctionResult}'`\n );\n }\n\n // Set the state of this node based on the result of calling the condition function.\n this.setState(!!conditionFunctionResult ? State.SUCCEEDED : State.FAILED);\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => this.conditionName;\n}\n", "import Leaf from \"./Leaf\";\nimport State from \"../../State\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { Agent } from \"../../Agent\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A WAIT node.\n * The state of this node will change to SUCCEEDED after a duration of time\n */\nexport default class Wait extends Leaf {\n /**\n * @param attributes The node attributes.\n * @param duration The duration that this node will wait to succeed in milliseconds.\n * @param durationMin The minimum possible duration in milliseconds that this node will wait to succeed.\n * @param durationMax The maximum possible duration in milliseconds that this node will wait to succeed.\n */\n constructor(\n attributes: Attribute[],\n private duration: number | null,\n private durationMin: number | null,\n private durationMax: number | null\n ) {\n super(\"wait\", attributes, []);\n }\n\n /**\n * The time in milliseconds at which this node was first updated.\n */\n private initialUpdateTime: number = 0;\n\n /**\n * The total duration in milliseconds that this node will be waiting for.\n */\n private totalDuration: number | null = null;\n\n /**\n * The duration in milliseconds that this node has been waiting for.\n */\n private waitedDuration: number = 0;\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // If this node is in the READY state then we need to set the initial update time.\n if (this.is(State.READY)) {\n // Set the initial update time.\n this.initialUpdateTime = new Date().getTime();\n\n // Set the initial waited duration.\n this.waitedDuration = 0;\n\n // Are we dealing with an explicit duration or will we be randomly picking a duration between the min and max duration.\n if (this.duration !== null) {\n this.totalDuration = this.duration;\n } else if (this.durationMin !== null && this.durationMax !== null) {\n // We will be picking a random duration between a min and max duration, if the optional 'random' behaviour tree\n // function option is defined then we will be using that, otherwise we will fall back to using Math.random.\n const random = typeof options.random === \"function\" ? options.random : Math.random;\n\n // Pick a random duration between a min and max duration.\n this.totalDuration = Math.floor(\n random() * (this.durationMax - this.durationMin + 1) + this.durationMin\n );\n } else {\n this.totalDuration = null;\n }\n\n // The node is now running until we finish waiting.\n this.setState(State.RUNNING);\n }\n\n // If we have no total duration then this wait node will wait indefinitely until it is aborted.\n if (this.totalDuration === null) {\n return;\n }\n\n // If we have a 'getDeltaTime' function defined as part of our options then we will use it to figure out how long we have waited for.\n if (typeof options.getDeltaTime === \"function\") {\n // Get the delta time.\n const deltaTime = options.getDeltaTime();\n\n // Our delta time must be a valid number and cannot be NaN.\n if (typeof deltaTime !== \"number\" || isNaN(deltaTime)) {\n throw new Error(\"The delta time must be a valid number and not NaN.\");\n }\n\n // Update the amount of time that this node has been waiting for based on the delta time.\n this.waitedDuration += deltaTime * 1000;\n } else {\n // We are not using a delta time, so we will just work out hom much time has passed since the first update.\n this.waitedDuration = new Date().getTime() - this.initialUpdateTime;\n }\n\n // Have we waited long enough?\n if (this.waitedDuration >= this.totalDuration) {\n // We have finished waiting!\n this.setState(State.SUCCEEDED);\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => {\n if (this.duration !== null) {\n return `WAIT ${this.duration}ms`;\n } else if (this.durationMin !== null && this.durationMax !== null) {\n return `WAIT ${this.durationMin}ms-${this.durationMax}ms`;\n } else {\n return \"WAIT\";\n }\n };\n}\n", "import Guard from \"./guards/Guard\";\n\nexport type AttributeDetails = {\n /** The attribute type. */\n type: string;\n\n /** The attribute arguments. */\n args: any[];\n};\n\n/**\n * A base node attribute.\n */\nexport default abstract class Attribute {\n /**\n * @param type The node attribute type.\n * @param args The array of attribute arguments.\n */\n constructor(public type: string, public args: any[]) {}\n\n /**\n * Gets the attribute details.\n */\n abstract getDetails(): TAttributeDetails;\n\n /**\n * Gets whether this attribute is a guard.\n */\n abstract isGuard: () => this is Guard;\n}\n", "import { Agent } from \"../../Agent\";\nimport Attribute, { AttributeDetails } from \"../Attribute\";\n\nexport type GuardAttributeDetails = {\n /** The name of the condition function that determines whether the guard is satisfied. */\n condition: string;\n} & AttributeDetails;\n\n/**\n * A base node guard attribute.\n */\nexport default abstract class Guard extends Attribute {\n /**\n * @param type The node attribute type.\n * @param args The array of decorator argument definitions.\n * @param condition The name of the condition function that determines whether the guard is satisfied.\n */\n constructor(type: string, args: any[], private condition: string) {\n super(type, args);\n }\n\n /**\n * Gets the name of the condition function that determines whether the guard is satisfied.\n */\n getCondition = () => this.condition;\n\n /**\n * Gets whether this attribute is a guard.\n */\n isGuard = () => true;\n\n /**\n * Gets the attribute details.\n */\n getDetails(): GuardAttributeDetails {\n return {\n type: this.type,\n args: this.args,\n condition: this.getCondition()\n };\n }\n\n /**\n * Gets whether the guard is satisfied.\n * @param agent The agent.\n * @returns Whether the guard is satisfied.\n */\n abstract isSatisfied(agent: Agent): boolean;\n}\n", "import Guard from \"./Guard\";\nimport Lookup from \"../../Lookup\";\nimport { Agent } from \"../../Agent\";\n\n/**\n * A WHILE guard which is satisfied as long as the given condition remains true.\n */\nexport default class While extends Guard {\n /**\n * @param condition The name of the condition function that determines whether the guard is satisfied.\n * @param args The array of decorator argument definitions.\n */\n constructor(condition: string, args: any[]) {\n super(\"while\", args, condition);\n }\n\n /**\n * Gets whether the guard is satisfied.\n * @param agent The agent.\n * @returns Whether the guard is satisfied.\n */\n isSatisfied = (agent: Agent) => {\n // Attempt to get the invoker for the condition function.\n const conditionFuncInvoker = Lookup.getFuncInvoker(agent, this.getCondition());\n\n // The condition function should be defined.\n if (conditionFuncInvoker === null) {\n throw new Error(\n `cannot evaluate node guard as the condition '${this.getCondition()}' function is not defined on the agent and has not been registered`\n );\n }\n\n let conditionFunctionResult;\n\n try {\n // Call the guard condition function to determine the state of this node, the result of which should be a boolean.\n conditionFunctionResult = conditionFuncInvoker(this.args);\n } catch (error) {\n // The user was naughty and threw something.\n throw new Error(`guard condition function '${this.getCondition()}' threw '${error}'`);\n }\n\n // The result of calling the guard condition function must be a boolean value.\n if (typeof conditionFunctionResult !== \"boolean\") {\n throw new Error(\n `expected guard condition function '${this.getCondition()}' to return a boolean but returned '${conditionFunctionResult}'`\n );\n }\n\n // Return whether this guard is satisfied.\n return conditionFunctionResult;\n };\n}\n", "import Guard from \"./Guard\";\nimport Lookup from \"../../Lookup\";\nimport { Agent } from \"../../Agent\";\n\n/**\n * An UNTIL guard which is satisfied as long as the given condition remains false.\n */\nexport default class Until extends Guard {\n /**\n * @param condition The name of the condition function that determines whether the guard is satisfied.\n * @param args The array of decorator argument definitions.\n */\n constructor(condition: string, args: any[]) {\n super(\"until\", args, condition);\n }\n\n /**\n * Gets whether the guard is satisfied.\n * @param agent The agent.\n * @returns Whether the guard is satisfied.\n */\n isSatisfied = (agent: Agent) => {\n // Attempt to get the invoker for the condition function.\n const conditionFuncInvoker = Lookup.getFuncInvoker(agent, this.getCondition());\n\n // The condition function should be defined.\n if (conditionFuncInvoker === null) {\n throw new Error(\n `cannot evaluate node guard as the condition '${this.getCondition()}' function is not defined on the agent and has not been registered`\n );\n }\n\n let conditionFunctionResult;\n\n try {\n // Call the guard condition function to determine the state of this node, the result of which should be a boolean.\n conditionFunctionResult = conditionFuncInvoker(this.args);\n } catch (error) {\n // The user was naughty and threw something.\n throw new Error(`guard condition function '${this.getCondition()}' threw '${error}'`);\n }\n\n // The result of calling the guard condition function must be a boolean value.\n if (typeof conditionFunctionResult !== \"boolean\") {\n throw new Error(\n `expected guard condition function '${this.getCondition()}' to return a boolean but returned '${conditionFunctionResult}'`\n );\n }\n\n // Return whether this guard is satisfied.\n return !conditionFunctionResult;\n };\n}\n", "import { Agent } from \"../../Agent\";\nimport Attribute, { AttributeDetails } from \"../Attribute\";\n\nexport type CallbackAttributeDetails = {\n /** The name of the agent function that is called. */\n functionName: string;\n} & AttributeDetails;\n\n/**\n * A base node callback attribute.\n */\nexport default abstract class Callback extends Attribute {\n /**\n * @param type The node attribute type.\n * @param args The array of decorator argument definitions.\n * @param functionName The name of the agent function to call.\n */\n constructor(type: string, args: any[], private functionName: string) {\n super(type, args);\n }\n\n /**\n * Gets the name of the agent function to call.\n */\n getFunctionName = () => this.functionName;\n\n /**\n * Gets whether this attribute is a guard.\n */\n isGuard = () => false;\n\n /**\n * Gets the attribute details.\n */\n getDetails(): CallbackAttributeDetails {\n return {\n type: this.type,\n args: this.args,\n functionName: this.getFunctionName()\n };\n }\n\n /**\n * Attempt to call the agent function that this callback refers to.\n * @param agent The agent.\n */\n abstract callAgentFunction: (agent: Agent, isSuccess: boolean, isAborted: boolean) => void;\n}\n", "import Callback from \"./Callback\";\nimport Lookup from \"../../Lookup\";\nimport { Agent } from \"../../Agent\";\n\n/**\n * An ENTRY callback which defines an agent function to call when the associated node is updated and moves out of running state.\n */\nexport default class Entry extends Callback {\n /**\n * @param functionName The name of the agent function to call.\n * @param args The array of callback argument definitions.\n */\n constructor(functionName: string, args: any[]) {\n super(\"entry\", args, functionName);\n }\n\n /**\n * Attempt to call the agent function that this callback refers to.\n * @param agent The agent.\n */\n callAgentFunction = (agent: Agent) => {\n // Attempt to get the invoker for the callback function.\n const callbackFuncInvoker = Lookup.getFuncInvoker(agent, this.getFunctionName());\n\n // The callback function should be defined.\n if (callbackFuncInvoker === null) {\n throw new Error(\n `cannot call entry function '${this.getFunctionName()}' as is not defined on the agent and has not been registered`\n );\n }\n\n // Call the callback function.\n callbackFuncInvoker(this.args);\n };\n}\n", "import Callback from \"./Callback\";\nimport Lookup from \"../../Lookup\";\nimport { Agent } from \"../../Agent\";\n\n/**\n * A STEP callback which defines an agent function to call when the associated node is updated.\n */\nexport default class Step extends Callback {\n /**\n * @param functionName The name of the agent function to call.\n * @param args The array of callback argument definitions.\n */\n constructor(functionName: string, args: any[]) {\n super(\"step\", args, functionName);\n }\n\n /**\n * Attempt to call the agent function that this callback refers to.\n * @param agent The agent.\n */\n callAgentFunction = (agent: Agent) => {\n // Attempt to get the invoker for the callback function.\n const callbackFuncInvoker = Lookup.getFuncInvoker(agent, this.getFunctionName());\n\n // The callback function should be defined.\n if (callbackFuncInvoker === null) {\n throw new Error(\n `cannot call step function '${this.getFunctionName()}' as is not defined on the agent and has not been registered`\n );\n }\n\n // Call the callback function.\n callbackFuncInvoker(this.args);\n };\n}\n", "import Callback from \"./Callback\";\nimport Lookup from \"../../Lookup\";\nimport { Agent } from \"../../Agent\";\n\n/**\n * An EXIT callback which defines an agent function to call when the associated node is updated and moves to a finished state or is aborted.\n */\nexport default class Exit extends Callback {\n /**\n * @param functionName The name of the agent function to call.\n * @param args The array of callback argument definitions.\n */\n constructor(functionName: string, args: any[]) {\n super(\"exit\", args, functionName);\n }\n\n /**\n * Attempt to call the agent function that this callback refers to.\n * @param agent The agent.\n * @param isSuccess Whether the decorated node was left with a success state.\n * @param isAborted Whether the decorated node was aborted.\n */\n callAgentFunction = (agent: Agent, isSuccess: boolean, isAborted: boolean) => {\n // Attempt to get the invoker for the callback function.\n const callbackFuncInvoker = Lookup.getFuncInvoker(agent, this.getFunctionName());\n\n // The callback function should be defined.\n if (callbackFuncInvoker === null) {\n throw new Error(\n `cannot call exit function '${this.getFunctionName()}' as is not defined on the agent and has not been registered`\n );\n }\n\n // Call the callback function\n callbackFuncInvoker([{ succeeded: isSuccess, aborted: isAborted }, ...this.args]);\n };\n}\n", "import { AnyNodeDefinition, RootNodeDefinition } from \"./BehaviourTreeDefinition\";\nimport GuardPath, { GuardPathPart } from \"./attributes/guards/GuardPath\";\nimport { validateBranchSubtreeLinks } from \"./BehaviourTreeDefinitionValidator\";\nimport { isInteger } from \"./BehaviourTreeDefinitionUtilities\";\nimport Node from \"./nodes/Node\";\nimport Composite from \"./nodes/composite/Composite\";\nimport Decorator from \"./nodes/decorator/Decorator\";\nimport Parallel from \"./nodes/composite/Parallel\";\nimport Selector from \"./nodes/composite/Selector\";\nimport Sequence from \"./nodes/composite/Sequence\";\nimport Lotto from \"./nodes/composite/Lotto\";\nimport Fail from \"./nodes/decorator/Fail\";\nimport Flip from \"./nodes/decorator/Flip\";\nimport Repeat from \"./nodes/decorator/Repeat\";\nimport Retry from \"./nodes/decorator/Retry\";\nimport Root from \"./nodes/decorator/Root\";\nimport Succeed from \"./nodes/decorator/Succeed\";\nimport Action from \"./nodes/leaf/Action\";\nimport Condition from \"./nodes/leaf/Condition\";\nimport Wait from \"./nodes/leaf/Wait\";\nimport Lookup from \"./Lookup\";\nimport Attribute from \"./attributes/Attribute\";\nimport While from \"./attributes/guards/While\";\nimport Until from \"./attributes/guards/Until\";\nimport Entry from \"./attributes/callbacks/Entry\";\nimport Step from \"./attributes/callbacks/Step\";\nimport Exit from \"./attributes/callbacks/Exit\";\n\n/**\n * A type representing any node instance in a behaviour tree.\n */\ntype AnyNode =\n | Root\n | Action\n | Condition\n | Wait\n | Sequence\n | Selector\n | Lotto\n | Parallel\n | Repeat\n | Retry\n | Flip\n | Succeed\n | Fail;\n\n/**\n * A type defining a mapping of root node identifiers to root node definitions.\n */\ntype RootNodeDefinitionMap = { [key: string | symbol]: RootNodeDefinition };\n\n/**\n * A symbol to use as the main root key in any root node mappings.\n */\nconst MAIN_ROOT_NODE_KEY = Symbol(\"__root__\");\n\n/**\n * Build and populate the root nodes based on the provided definition, assuming that the definition has been validated.\n * @param definition The root node definitions.\n * @returns The built and populated root node definitions.\n */\nexport default function buildRootNode(definition: RootNodeDefinition[]): Root {\n // Create a mapping of root node identifers to root node definitions, including globally registered subtree root node definitions.\n const rootNodeDefinitionMap = createRootNodeDefinitionMap(definition);\n\n // Now that we have all of our root node definitions (those part of the tree definition and those globally registered)\n // we should validate the branch-subtree links. This will also double-check that we dont have any circular dependencies\n // in our branch-subtree references and that we have no broken branch-subtree links.\n validateBranchSubtreeLinks(\n [rootNodeDefinitionMap[MAIN_ROOT_NODE_KEY], ...Object.values(rootNodeDefinitionMap)],\n true\n );\n\n // Create our populated tree of node instances, starting with our main root node.\n const rootNode = nodeFactory(rootNodeDefinitionMap[MAIN_ROOT_NODE_KEY], rootNodeDefinitionMap) as Root;\n\n // Set a guard path on every leaf of the tree to evaluate as part of each update.\n applyLeafNodeGuardPaths(rootNode);\n\n // We only need to return the main root node.\n return rootNode;\n}\n\n/**\n * A factory function which creates a node instance based on the specified definition.\n * @param definition The node definition.\n * @param rootNodeDefinitionMap The mapping of root node identifers to root node definitions, including globally registered subtree root node definitions.\n * @returns A node instance based on the specified definition.\n */\nfunction nodeFactory(definition: AnyNodeDefinition, rootNodeDefinitionMap: RootNodeDefinitionMap): AnyNode {\n // Get the attributes for the node.\n const attributes = nodeAttributesFactory(definition);\n\n // Create the node instance based on the definition type.\n switch (definition.type) {\n case \"root\":\n return new Root(attributes, nodeFactory(definition.child, rootNodeDefinitionMap));\n\n case \"repeat\":\n let iterations: number | null = null;\n let iterationsMin: number | null = null;\n let iterationsMax: number | null = null;\n\n if (Array.isArray(definition.iterations)) {\n iterationsMin = definition.iterations[0];\n iterationsMax = definition.iterations[1];\n } else if (isInteger(definition.iterations)) {\n iterations = definition.iterations!;\n }\n\n return new Repeat(\n attributes,\n iterations,\n iterationsMin,\n iterationsMax,\n nodeFactory(definition.child, rootNodeDefinitionMap)\n );\n\n case \"retry\":\n let attempts: number | null = null;\n let attemptsMin: number | null = null;\n let attemptsMax: number | null = null;\n\n if (Array.isArray(definition.attempts)) {\n attemptsMin = definition.attempts[0];\n attemptsMax = definition.attempts[1];\n } else if (isInteger(definition.attempts)) {\n attempts = definition.attempts!;\n }\n\n return new Retry(\n attributes,\n attempts,\n attemptsMin,\n attemptsMax,\n nodeFactory(definition.child, rootNodeDefinitionMap)\n );\n\n case \"flip\":\n return new Flip(attributes, nodeFactory(definition.child, rootNodeDefinitionMap));\n\n case \"succeed\":\n return new Succeed(attributes, nodeFactory(definition.child, rootNodeDefinitionMap));\n\n case \"fail\":\n return new Fail(attributes, nodeFactory(definition.child, rootNodeDefinitionMap));\n\n case \"sequence\":\n return new Sequence(\n attributes,\n definition.children.map((child) => nodeFactory(child, rootNodeDefinitionMap))\n );\n\n case \"selector\":\n return new Selector(\n attributes,\n definition.children.map((child) => nodeFactory(child, rootNodeDefinitionMap))\n );\n\n case \"parallel\":\n return new Parallel(\n attributes,\n definition.children.map((child) => nodeFactory(child, rootNodeDefinitionMap))\n );\n\n case \"lotto\":\n return new Lotto(\n attributes,\n definition.weights,\n definition.children.map((child) => nodeFactory(child, rootNodeDefinitionMap))\n );\n\n case \"branch\":\n return nodeFactory(rootNodeDefinitionMap[definition.ref].child, rootNodeDefinitionMap);\n\n case \"action\":\n return new Action(attributes, definition.call, definition.args || []);\n\n case \"condition\":\n return new Condition(attributes, definition.call, definition.args || []);\n\n case \"wait\":\n let duration: number | null = null;\n let durationMin: number | null = null;\n let durationMax: number | null = null;\n\n if (Array.isArray(definition.duration)) {\n durationMin = definition.duration[0];\n durationMax = definition.duration[1];\n } else if (isInteger(definition.duration)) {\n duration = definition.duration!;\n }\n\n return new Wait(attributes, duration, durationMin, durationMax);\n }\n}\n\n/**\n * Creates an array of node attribute instances based on the specified node definition.\n * @param definition The node definition.\n * @returns An array of node attribute instances based on the specified node definition.\n */\nfunction nodeAttributesFactory(definition: AnyNodeDefinition): Attribute[] {\n const attributes: Attribute[] = [];\n\n if (definition.while) {\n attributes.push(new While(definition.while.call, definition.while.args ?? []));\n }\n\n if (definition.until) {\n attributes.push(new Until(definition.until.call, definition.until.args ?? []));\n }\n\n if (definition.entry) {\n attributes.push(new Entry(definition.entry.call, definition.entry.args ?? []));\n }\n\n if (definition.step) {\n attributes.push(new Step(definition.step.call, definition.step.args ?? []));\n }\n\n if (definition.exit) {\n attributes.push(new Exit(definition.exit.call, definition.exit.args ?? []));\n }\n\n return attributes;\n}\n\n/**\n * Creates a mapping of root node identifers to root node definitions, mixing in globally registered subtree root node definitions.\n * @param definition The root node definitions.\n * @returns A mapping of root node identifers to root node definitions, including globally registered subtree root node definitions.\n */\nfunction createRootNodeDefinitionMap(definition: RootNodeDefinition[]): RootNodeDefinitionMap {\n // Create a mapping of root node identifers to root node definitions.\n const rootNodeMap: RootNodeDefinitionMap = {};\n\n // Add in any registered subtree root node definitions.\n for (const [name, rootNodeDefinition] of Object.entries(Lookup.getSubtrees())) {\n // The name used when registering the subtree will be used as the root node identifier.\n rootNodeMap[name] = { ...rootNodeDefinition, id: name };\n }\n\n // Populate the map with the root node definitions that were included with the tree definition.\n // We do this after adding any registered subtrees as we want these to take presedence.\n for (const rootNodeDefinition of definition) {\n rootNodeMap[rootNodeDefinition.id ?? MAIN_ROOT_NODE_KEY] = rootNodeDefinition;\n }\n\n return rootNodeMap;\n}\n\n/**\n * Applies a guard path to every leaf of the tree to evaluate as part of each update.\n * @param root The main root tree node.\n */\nfunction applyLeafNodeGuardPaths(root: Root) {\n const nodePaths: Node[][] = [];\n\n const findLeafNodes = (path: Node[], node: Node) => {\n // Add the current node to the path.\n path = path.concat(node);\n\n // Check whether the current node is a leaf node.\n if (node.isLeafNode()) {\n nodePaths.push(path);\n } else {\n (node as Composite | Decorator).getChildren().forEach((child) => findLeafNodes(path, child));\n }\n };\n\n // Find all leaf node paths, starting from the root.\n findLeafNodes([], root);\n\n nodePaths.forEach((path) => {\n // Each node in the current path will have to be assigned a guard path, working from the root outwards.\n for (let depth = 0; depth < path.length; depth++) {\n // Get the node in the path at the current depth.\n const currentNode = path[depth];\n\n // The node may already have been assigned a guard path, if so just skip it.\n if (currentNode.hasGuardPath()) {\n continue;\n }\n\n // Create the guard path for the current node.\n const guardPath = new GuardPath(\n path\n .slice(0, depth + 1)\n .map((node) => ({ node, guards: node.getGuardAttributes() }))\n .filter((details) => details.guards.length > 0)\n );\n\n // Assign the guard path to the current node.\n currentNode.setGuardPath(guardPath);\n }\n });\n}\n", "import State, { AnyState } from \"./State\";\nimport Lookup from \"./Lookup\";\nimport Node from \"./nodes/Node\";\nimport Root from \"./nodes/decorator/Root\";\nimport Composite from \"./nodes/composite/Composite\";\nimport Decorator from \"./nodes/decorator/Decorator\";\nimport { Agent, GlobalFunction } from \"./Agent\";\nimport { CallbackAttributeDetails } from \"./attributes/callbacks/Callback\";\nimport { GuardAttributeDetails } from \"./attributes/guards/Guard\";\nimport { BehaviourTreeOptions } from \"./BehaviourTreeOptions\";\nimport { convertMDSLToJSON } from \"./mdsl/MDSLDefinitionParser\";\nimport { RootNodeDefinition } from \"./BehaviourTreeDefinition\";\nimport { validateDefinition, validateJSONDefinition } from \"./BehaviourTreeDefinitionValidator\";\nimport buildRootNode from \"./BehaviourTreeBuilder\";\nimport { isNullOrUndefined } from \"./BehaviourTreeDefinitionUtilities\";\n\n// Purely for outside inspection of the tree.\nexport type FlattenedTreeNode = {\n id: string;\n type: string;\n caption: string;\n state: AnyState;\n guards: GuardAttributeDetails[];\n callbacks: CallbackAttributeDetails[];\n args: any[];\n parentId: string | null;\n};\n\n/**\n * A representation of a behaviour tree.\n */\nexport class BehaviourTree {\n /**\n * The main root tree node.\n */\n private readonly _rootNode: Root;\n\n /**\n * Creates a new instance of the BehaviourTree class.\n * @param definition The behaviour tree definition as either an MDSL string, root node definition object or array of root node definition objects.\n * @param agent The agent instance that this behaviour tree is modelling behaviour for.\n * @param options The behaviour tree options object.\n */\n constructor(\n definition: string | RootNodeDefinition | RootNodeDefinition[],\n private agent: Agent,\n private options: BehaviourTreeOptions = {}\n ) {\n // The tree definition must be defined.\n if (isNullOrUndefined(definition)) {\n throw new Error(\"tree definition not defined\");\n }\n\n // The agent must be defined and not null.\n if (typeof agent !== \"object\" || agent === null) {\n throw new Error(\"the agent must be an object and not null\");\n }\n\n // We should validate the definition before we try to build the tree nodes.\n const { succeeded, errorMessage, json } = validateDefinition(definition);\n\n // Did our validation fail without error?\n if (!succeeded) {\n throw new Error(`invalid definition: ${errorMessage}`);\n }\n\n // Double check that we did actually get our json definition as part of our definition validtion.\n if (!json) {\n throw new Error(\n \"expected json definition to be returned as part of successful definition validation response\"\n );\n }\n\n try {\n // Create the populated tree of behaviour tree nodes and get the root node.\n this._rootNode = buildRootNode(json);\n } catch (exception) {\n // There was an issue in trying build and populate the behaviour tree.\n throw new Error(`error building tree: ${(exception as Error).message}`);\n }\n }\n\n /**\n * Gets whether the tree is in the RUNNING state.\n * @returns true if the tree is in the RUNNING state, otherwise false.\n */\n isRunning() {\n return this._rootNode.getState() === State.RUNNING;\n }\n\n /**\n * Gets the current tree state of SUCCEEDED, FAILED, READY or RUNNING.\n * @returns The current tree state.\n */\n getState() {\n return this._rootNode.getState();\n }\n\n /**\n * Step the tree.\n * 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.\n * 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\n * 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.\n *\n * 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.\n */\n step() {\n // If the root node has already been stepped to completion then we need to reset it.\n if (this._rootNode.getState() === State.SUCCEEDED || this._rootNode.getState() === State.FAILED) {\n this._rootNode.reset();\n }\n\n try {\n this._rootNode.update(this.agent, this.options);\n } catch (exception) {\n throw new Error(`error stepping tree: ${(exception as Error).message}`);\n }\n }\n\n /**\n * Resets the tree from the root node outwards to each nested node, giving each a state of READY.\n */\n reset() {\n this._rootNode.reset();\n }\n\n /**\n * Gets the flattened details of every node in the tree.\n * @returns The flattened details of every node in the tree.\n */\n getFlattenedNodeDetails(): FlattenedTreeNode[] {\n // Create an empty flattened array of tree nodes.\n const flattenedTreeNodes: FlattenedTreeNode[] = [];\n\n /**\n * Helper function to process a node instance and push details into the flattened tree nodes array.\n * @param node The current node.\n * @param parentUid The UID of the node parent, or null if the node is the main root node.\n */\n const processNode = (node: Node, parentUid: string | null) => {\n // Get the guard and callback attribute details for this node.\n const guards = node\n .getAttributes()\n .filter((attribute) => attribute.isGuard())\n .map((attribute) => attribute.getDetails()) as GuardAttributeDetails[];\n const callbacks = node\n .getAttributes()\n .filter((attribute) => !attribute.isGuard())\n .map((attribute) => attribute.getDetails()) as CallbackAttributeDetails[];\n\n // Push the current node into the flattened nodes array.\n flattenedTreeNodes.push({\n id: node.getUid(),\n type: node.getType(),\n caption: node.getName(),\n state: node.getState(),\n guards,\n callbacks,\n args: node.getArguments(),\n parentId: parentUid\n });\n\n // Process each of the nodes children if it is not a leaf node.\n if (!node.isLeafNode()) {\n (node as Composite | Decorator)\n .getChildren()\n .forEach((child) => processNode(child, (node as Composite | Decorator).getUid()));\n }\n };\n\n // Convert the nested node structure into a flattened array of node details.\n processNode(this._rootNode, null);\n\n return flattenedTreeNodes;\n }\n\n /**\n * Registers the action/condition/guard/callback function or subtree with the given name.\n * @param name The name of the function or subtree to register.\n * @param value The function or subtree definition to register.\n */\n static register(name: string, value: GlobalFunction | string | RootNodeDefinition) {\n // Are we going to register a action/condition/guard/callback function?\n if (typeof value === \"function\") {\n Lookup.setFunc(name, value);\n return;\n }\n\n // We are not registering an action/condition/guard/callback function, so we must be registering a subtree.\n if (typeof value === \"string\") {\n let rootNodeDefinitions: RootNodeDefinition[];\n\n // We will assume that any string passed in will be a mdsl definition.\n try {\n rootNodeDefinitions = convertMDSLToJSON(value);\n } catch (exception) {\n throw new Error(`error registering definition, invalid MDSL: ${(exception as Error).message}`);\n }\n\n // This function should only ever be called with a definition containing a single unnamed root node.\n if (rootNodeDefinitions.length != 1 || rootNodeDefinitions[0].id !== null) {\n throw new Error(\"error registering definition: expected a single unnamed root node\");\n }\n\n try {\n // We should validate the subtree as we don't want invalid subtrees available via the lookup.\n const { succeeded, errorMessage } = validateJSONDefinition(rootNodeDefinitions[0]);\n\n // Did our validation fail without error?\n if (!succeeded) {\n throw new Error(errorMessage);\n }\n } catch (exception) {\n throw new Error(`error registering definition: ${(exception as Error).message}`);\n }\n\n // Everything seems hunky-dory, register the subtree.\n Lookup.setSubtree(name, rootNodeDefinitions[0]);\n } else if (typeof value === \"object\" && !Array.isArray(value)) {\n // We will assume that any object passed in is a root node definition.\n\n try {\n // We should validate the subtree as we don't want invalid subtrees available via the lookup.\n const { succeeded, errorMessage } = validateJSONDefinition(value);\n\n // Did our validation fail without error?\n if (!succeeded) {\n throw new Error(errorMessage);\n }\n } catch (exception) {\n throw new Error(`error registering definition: ${(exception as Error).message}`);\n }\n\n // Everything seems hunky-dory, register the subtree.\n Lookup.setSubtree(name, value);\n } else {\n throw new Error(\"unexpected value, expected string mdsl definition, root node json definition or function\");\n }\n }\n\n /**\n * Unregisters the registered action/condition/guard/callback function or subtree with the given name.\n * @param name The name of the registered action/condition/guard/callback function or subtree to unregister.\n */\n static unregister(name: string): void {\n Lookup.remove(name);\n }\n\n /**\n * Unregister all registered action/condition/guard/callback functions and subtrees.\n */\n static unregisterAll(): void {\n Lookup.empty();\n }\n}\n"], - "mappings": "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", + "sourcesContent": ["\"use strict\";\r\nObject.defineProperty(exports, \"__esModule\", { value: true });\r\nexports.Participant = void 0;\r\n/**\r\n * A participant that holds a number of tickets.\r\n */\r\nvar Participant = /** @class */ (function () {\r\n /**\r\n * Creates an instance of the Participant class.\r\n * @param participant The actual participant.\r\n * @param tickets The number of tickets held by the participant.\r\n */\r\n function Participant(participant, tickets) {\r\n if (tickets === void 0) { tickets = 1; }\r\n this._participant = participant;\r\n this._tickets = tickets;\r\n }\r\n Object.defineProperty(Participant.prototype, \"participant\", {\r\n /** Gets the actual participant. */\r\n get: function () {\r\n return this._participant;\r\n },\r\n enumerable: false,\r\n configurable: true\r\n });\r\n Object.defineProperty(Participant.prototype, \"tickets\", {\r\n /** Gets or sets the number of tickets held by the participant. */\r\n get: function () {\r\n return this._tickets;\r\n },\r\n set: function (value) {\r\n this._tickets = value;\r\n },\r\n enumerable: false,\r\n configurable: true\r\n });\r\n return Participant;\r\n}());\r\nexports.Participant = Participant;\r\n", "\"use strict\";\r\nObject.defineProperty(exports, \"__esModule\", { value: true });\r\nexports.isNaturalNumber = exports.isNullOrUndefined = void 0;\r\n/**\r\n * Gets whether the value provided is null or undefined.\r\n * @param value The value to check.\r\n * @returns Whether the value provided is null or undefined.\r\n */\r\nfunction isNullOrUndefined(value) {\r\n return value === null || value === undefined;\r\n}\r\nexports.isNullOrUndefined = isNullOrUndefined;\r\n/**\r\n * Gets whether the value provided is a natural number.\r\n * @param value The value to check.\r\n * @returns Whether the value provided is a natural number.\r\n */\r\nfunction isNaturalNumber(value) {\r\n return typeof value === \"number\" && value >= 1 && Math.floor(value) === value;\r\n}\r\nexports.isNaturalNumber = isNaturalNumber;\r\n", "\"use strict\";\r\nObject.defineProperty(exports, \"__esModule\", { value: true });\r\nexports.Lotto = void 0;\r\nvar Participant_1 = require(\"./Participant\");\r\nvar Utilities_1 = require(\"./Utilities\");\r\n/**\r\n * Represents a lotto consisting of a number of pickable ticket-holding participants.\r\n */\r\nvar Lotto = /** @class */ (function () {\r\n /**\r\n * Creates a new instance of Lotto.\r\n * @param customRandom The custom RNG to use in place of Math.random().\r\n */\r\n function Lotto(customRandom) {\r\n /** The array of participants that are holding tickets in the lotto. */\r\n this._participants = [];\r\n this._customRandom = customRandom;\r\n }\r\n /**\r\n * Adds a participant with the specified number of tickets, or adds to the participant ticket count if the participant already holds tickets.\r\n * @param participant The participant to add or to increase the ticket count for if they already hold tickets.\r\n * @param tickets The number of tickets, defaults to 1.\r\n * @returns The Lotto instance.\r\n */\r\n Lotto.prototype.add = function (participant, tickets) {\r\n if (tickets === void 0) { tickets = 1; }\r\n // Check that we have a valid ticket count.\r\n if (!(0, Utilities_1.isNaturalNumber)(tickets)) {\r\n throw new Error(\"tickets value must be a natural number\");\r\n }\r\n // Check whether this participant has already been added.\r\n var existingParticipant = this._participants.find(function (part) { return part.participant === participant; });\r\n if (existingParticipant) {\r\n // The participant has already been added to the lotto so just add to their ticket count.\r\n existingParticipant.tickets += tickets;\r\n }\r\n else {\r\n // The participant is not part of the lotto so we should add them.\r\n this._participants.push(new Participant_1.Participant(participant, tickets));\r\n }\r\n return this;\r\n };\r\n /**\r\n * Removes the specified number of tickets for the given participant from the draw, or all tickets if a ticket number is not defined.\r\n * @param participant The participant to remove tickets for.\r\n * @param tickets The number of tickets to remove, or undefined if all tickets are to be removed.\r\n * @returns The Lotto instance.\r\n */\r\n Lotto.prototype.remove = function (participant, tickets) {\r\n // Attempt to get the existing participant.\r\n var existingParticipant = this._participants.find(function (part) { return part.participant === participant; });\r\n // There is nothing to do if the specified participant isn't even part of the lotto.\r\n if (!existingParticipant) {\r\n return this;\r\n }\r\n // Check whether a tickets value was given.\r\n if (tickets !== undefined) {\r\n // Check that we have a valid ticket count.\r\n if (!(0, Utilities_1.isNaturalNumber)(tickets)) {\r\n throw new Error(\"tickets value must be a natural number\");\r\n }\r\n existingParticipant.tickets -= tickets;\r\n // If the participant no longer holds any tickets then they should be removed.\r\n if (existingParticipant.tickets < 1) {\r\n this._participants = this._participants.filter(function (part) { return part !== existingParticipant; });\r\n }\r\n }\r\n else {\r\n // We are removing all tickets for the participant so just remove them from the lotto.\r\n this._participants = this._participants.filter(function (part) { return part !== existingParticipant; });\r\n }\r\n return this;\r\n };\r\n /**\r\n * Draw a winning ticket and return the participant that holds the ticket.\r\n * @param options The draw options.\r\n * @returns The participant that holds the winning ticket.\r\n */\r\n Lotto.prototype.draw = function (options) {\r\n if (options === void 0) { options = {}; }\r\n // If we have no participants then just return null.\r\n if (this._participants.length === 0) {\r\n return null;\r\n }\r\n var redrawable = (0, Utilities_1.isNullOrUndefined)(options.redrawable) ? true : options.redrawable;\r\n var pickable = [];\r\n this._participants.forEach(function (_a) {\r\n var participant = _a.participant, tickets = _a.tickets;\r\n for (var ticketCount = 0; ticketCount < tickets; ticketCount++) {\r\n pickable.push(participant);\r\n }\r\n });\r\n var random;\r\n // We need a random floating-point number between 0 (inclusive) and 1 to scale up to pick our winner.\r\n // If a custom random function exists then we should use that or fall back to Math.random().\r\n if (this._customRandom) {\r\n // Call our custom random function to get a random floating-point number.\r\n random = this._customRandom();\r\n // Verify that the result of calling our custom random function is a number between 0 (inclusive) and 1.\r\n if (typeof random !== \"number\" || random < 0 || random >= 1) {\r\n throw new Error(\"the 'random' function provided did not return a number between 0 (inclusive) and 1\");\r\n }\r\n }\r\n else {\r\n // No custom random function was defined so just use good ol' Math.random().\r\n random = Math.random();\r\n }\r\n // Pick a winning participant.\r\n var winner = pickable[Math.floor(random * pickable.length)];\r\n // If the ticket isn't redrawable then we should remove a ticket from the winning participants ticket count.\r\n if (!redrawable) {\r\n this.remove(winner, 1);\r\n }\r\n // Return the winning participant.\r\n return winner;\r\n };\r\n /**\r\n * Draws multiple winning tickets and return an array of the participants that hold the winning tickets.\r\n * @param tickets The number of winning tickets to draw.\r\n * @param options The draw multiple options.\r\n * @returns An array of the participants that hold the winning tickets.\r\n */\r\n Lotto.prototype.drawMultiple = function (tickets, options) {\r\n if (options === void 0) { options = {}; }\r\n var uniqueResults = (0, Utilities_1.isNullOrUndefined)(options.unique) ? false : options.unique;\r\n // Handle cases where the user has asked for zero tickets (no idea why they would do this be we should trust them).\r\n if (tickets === 0) {\r\n return [];\r\n }\r\n // Now that we know out tickets value is not zero we should check that it is a valid natural number.\r\n if (!(0, Utilities_1.isNaturalNumber)(tickets)) {\r\n throw new Error(\"tickets value must be a natural number\");\r\n }\r\n var result = [];\r\n // Keep drawing tickets until we either reach the number of required tickets or we simply run out of tickets to draw.\r\n // We can run out of tickets to draw if 'options.redrawable' is explicity 'false' or we just had no participants when 'drawMultiple' was called.\r\n while (result.length < tickets && this._participants.length > 0) {\r\n result.push(this.draw(options));\r\n }\r\n // If the 'unique' draw option is set then we need to remove duplicates from the result list.\r\n if (uniqueResults) {\r\n // Create an array to store our unique results.\r\n var unique = [];\r\n // Iterate over all of our participants (with potential duplicates) and populate our array of unique values.\r\n for (var _i = 0, result_1 = result; _i < result_1.length; _i++) {\r\n var participant = result_1[_i];\r\n if (unique.indexOf(participant) === -1) {\r\n unique.push(participant);\r\n }\r\n }\r\n result = unique;\r\n }\r\n return result;\r\n };\r\n return Lotto;\r\n}());\r\nexports.Lotto = Lotto;\r\n", "\"use strict\";\r\nObject.defineProperty(exports, \"__esModule\", { value: true });\r\nexports.createLotto = void 0;\r\nvar Lotto_1 = require(\"./Lotto\");\r\n/**\r\n * A function that creates and returns a Lotto instance.\r\n * @param participantsOrOptions An array of initial participants or options relating to the creation of a Lotto instance.\r\n * @returns A new Lotto instance.\r\n */\r\nfunction createLotto(participantsOrOptions) {\r\n // If no initial participants or lotto options were provided as an argument then we can just return a new lotto instance now.\r\n if (!participantsOrOptions) {\r\n return new Lotto_1.Lotto();\r\n }\r\n // Check whether we were provided with an array of initial participants or a lotto options object.\r\n if (Array.isArray(participantsOrOptions)) {\r\n // We are dealing with a pre-defined array of participants.\r\n var participants = participantsOrOptions;\r\n var lotto_1 = new Lotto_1.Lotto();\r\n // If the lotto participants have been defined upfront then we will need to add them all to our lotto instance now.\r\n participants.forEach(function (_a) {\r\n var participant = _a[0], tokens = _a[1];\r\n return lotto_1.add(participant, tokens);\r\n });\r\n // Return the Lotto instance.\r\n return lotto_1;\r\n }\r\n else {\r\n // We are dealing with some lotto options.\r\n var random = participantsOrOptions.random, participants = participantsOrOptions.participants;\r\n // Create a Lotto instance passing the custom RNG function to use in place of Math.random() (which could be undefined).\r\n var lotto_2 = new Lotto_1.Lotto(random);\r\n // If the lotto participants have been defined upfront as part of the options then we will need to add them all to our lotto instance now.\r\n if (participants) {\r\n participants.forEach(function (_a) {\r\n var participant = _a[0], tokens = _a[1];\r\n return lotto_2.add(participant, tokens);\r\n });\r\n }\r\n // Return the Lotto instance.\r\n return lotto_2;\r\n }\r\n}\r\nexports.createLotto = createLotto;\r\n", "\"use strict\";\r\nObject.defineProperty(exports, \"__esModule\", { value: true });\r\nvar createLotto_1 = require(\"./createLotto\");\r\nexports.default = createLotto_1.createLotto;\r\n", "import State from \"./State\";\nimport { validateDefinition } from \"./BehaviourTreeDefinitionValidator\";\nimport { convertMDSLToJSON } from \"./mdsl/MDSLDefinitionParser\";\nimport { BehaviourTree, FlattenedTreeNode } from \"./BehaviourTree\";\nimport { BehaviourTreeOptions } from \"./BehaviourTreeOptions\";\n\nexport { BehaviourTree, State, convertMDSLToJSON, validateDefinition };\nexport type { FlattenedTreeNode, BehaviourTreeOptions };\n", "/**\n * Enumeration of node state types.\n */\nexport enum State {\n READY = \"mistreevous.ready\",\n RUNNING = \"mistreevous.running\",\n SUCCEEDED = \"mistreevous.succeeded\",\n FAILED = \"mistreevous.failed\"\n}\n\nexport { State as default };\n\nexport type CompleteState = State.SUCCEEDED | State.FAILED;\nexport type AnyState = State.READY | State.RUNNING | CompleteState;\n", "import {\n NodeDefinition,\n RootNodeDefinition,\n DecoratorNodeDefinition,\n CompositeNodeDefinition,\n AnyNodeDefinition,\n BranchNodeDefinition\n} from \"./BehaviourTreeDefinition\";\n\n/**\n * A type guard function that returns true if the specified node satisfies the RootNodeDefinition type.\n * @param node The node.\n * @returns A value of true if the specified node satisfies the RootNodeDefinition type.\n */\nexport function isRootNode(node: NodeDefinition): node is RootNodeDefinition {\n return node.type === \"root\";\n}\n\n/**\n * A type guard function that returns true if the specified node satisfies the BranchNodeDefinition type.\n * @param node The node.\n * @returns A value of true if the specified node satisfies the BranchNodeDefinition type.\n */\nexport function isBranchNode(node: NodeDefinition): node is BranchNodeDefinition {\n return node.type === \"branch\";\n}\n\n/**\n * A type guard function that returns true if the specified node satisfies the NodeDefinition type.\n * @param node The node.\n * @returns A value of true if the specified node satisfies the NodeDefinition type.\n */\nexport function isLeafNode(node: NodeDefinition): node is NodeDefinition {\n return [\"branch\", \"action\", \"condition\", \"wait\"].includes(node.type);\n}\n\n/**\n * A type guard function that returns true if the specified node satisfies the DecoratorNodeDefinition type.\n * @param node The node.\n * @returns A value of true if the specified node satisfies the DecoratorNodeDefinition type.\n */\nexport function isDecoratorNode(node: NodeDefinition): node is DecoratorNodeDefinition {\n return [\"root\", \"repeat\", \"retry\", \"flip\", \"succeed\", \"fail\"].includes(node.type);\n}\n\n/**\n * A type guard function that returns true if the specified node satisfies the CompositeNodeDefinition type.\n * @param node The node.\n * @returns A value of true if the specified node satisfies the CompositeNodeDefinition type.\n */\nexport function isCompositeNode(node: NodeDefinition): node is CompositeNodeDefinition {\n return [\"sequence\", \"selector\", \"lotto\", \"parallel\"].includes(node.type);\n}\n\n/**\n * Flatten a node definition into an array of all of its nested node definitions.\n * @param nodeDefinition The node definition to flatten.\n * @returns An array of all of nested node definitions.\n */\nexport function flattenDefinition(nodeDefinition: AnyNodeDefinition): AnyNodeDefinition[] {\n const nodes: AnyNodeDefinition[] = [];\n\n const processNode = (currentNodeDefinition: AnyNodeDefinition) => {\n nodes.push(currentNodeDefinition);\n\n if (isCompositeNode(currentNodeDefinition)) {\n currentNodeDefinition.children.forEach(processNode);\n } else if (isDecoratorNode(currentNodeDefinition)) {\n processNode(currentNodeDefinition.child);\n }\n };\n\n processNode(nodeDefinition);\n\n return nodes;\n}\n\n/**\n * Determines whether the passed value is an integer.\n * @param value The value to check.\n * @returns Whether the passed value is an integer.\n */\nexport function isInteger(value: unknown): boolean {\n return typeof value === \"number\" && Math.floor(value) === value;\n}\n\n/**\n * Determines whether the passed value is null or undefined.\n * @param value The value to check.\n * @returns Whether the passed value is null or undefined.\n */\nexport function isNullOrUndefined(value: unknown): boolean {\n return typeof value === \"undefined\" || value === null;\n}\n", "/**\n * A type defining an object that holds a reference to substitued string literals parsed from the definition.\n */\nexport type StringLiteralPlaceholders = { [key: string]: string };\n\n/**\n * Pop the next raw token from the specified array of tokens and throw an error if it wasn't the expected one.\n * @param tokens The array of tokens.\n * @param expected An optional string or array or items, one of which must match the next popped token.\n * @returns The popped token.\n */\nexport function popAndCheck(tokens: string[], expected?: string | string[]): string {\n // Get and remove the next token.\n const popped = tokens.shift();\n\n // We were expecting another token but there aren't any.\n if (popped === undefined) {\n throw new Error(\"unexpected end of definition\");\n }\n\n // Do we have an expected token/tokens array?\n if (expected != undefined) {\n // Get an array of expected values, if the popped token matches any then we are all good.\n const expectedValues = typeof expected === \"string\" ? [expected] : expected;\n\n // Check whether the popped token matches at least one of our expected items.\n var tokenMatchesExpectation = expectedValues.some((item) => popped.toUpperCase() === item.toUpperCase());\n\n // Throw an error if the popped token didn't match any of our expected items.\n if (!tokenMatchesExpectation) {\n const expectationString = expectedValues.map((item) => \"'\" + item + \"'\").join(\" or \");\n throw new Error(\"unexpected token found. Expected \" + expectationString + \" but got '\" + popped + \"'\");\n }\n }\n\n // Return the popped token.\n return popped;\n}\n\n/**\n * Swaps out any node/attribute argument string literals with placeholders.\n * @param definition The definition.\n * @returns An object containing a mapping of placeholders to original string values as well as the processed definition string.\n */\nexport function substituteStringLiterals(definition: string): {\n placeholders: StringLiteralPlaceholders;\n processedDefinition: string;\n} {\n // Create an object to hold the mapping of placeholders to original string values.\n const placeholders: StringLiteralPlaceholders = {};\n\n // Replace any string literals wrapped with double quotes in our definition with placeholders to be processed later.\n const processedDefinition = definition.replace(/\\\"(\\\\.|[^\"\\\\])*\\\"/g, (match) => {\n var strippedMatch = match.substring(1, match.length - 1);\n var placeholder = Object.keys(placeholders).find((key) => placeholders[key] === strippedMatch);\n\n // If we have no existing string literal match then create a new placeholder.\n if (!placeholder) {\n placeholder = `@@${Object.keys(placeholders).length}@@`;\n placeholders[placeholder] = strippedMatch;\n }\n\n return placeholder;\n });\n\n return { placeholders, processedDefinition };\n}\n\n/**\n * Parse the tree definition into an array of raw tokens.\n * @param definition The definition.\n * @returns An array of tokens parsed from the definition.\n */\nexport function parseTokensFromDefinition(definition: string): string[] {\n // Add some space around various important characters so that they can be plucked out easier as individual tokens.\n definition = definition.replace(/\\(/g, \" ( \");\n definition = definition.replace(/\\)/g, \" ) \");\n definition = definition.replace(/\\{/g, \" { \");\n definition = definition.replace(/\\}/g, \" } \");\n definition = definition.replace(/\\]/g, \" ] \");\n definition = definition.replace(/\\[/g, \" [ \");\n definition = definition.replace(/\\,/g, \" , \");\n\n // Split the definition into raw token form and return it.\n return definition.replace(/\\s+/g, \" \").trim().split(\" \");\n}\n", "import { StringLiteralPlaceholders, popAndCheck } from \"./MDSLUtilities\";\n\n/**\n * A type representing any node function argument.\n */\ntype Argument = {\n /**\n * The argument value.\n */\n value: T;\n /**\n * The argument type, used for validation.\n */\n type: string;\n};\n\ntype NullArgument = Argument & {\n type: \"null\";\n};\n\ntype BooleanArgument = Argument & {\n type: \"boolean\";\n};\n\ntype NumberArgument = Argument & {\n type: \"number\";\n /**\n * A flag defining whether the number argument value is a valid integer. (used for validation)\n */\n isInteger: boolean;\n};\n\ntype StringPlaceholderArgument = Argument & {\n type: \"string\";\n};\n\ntype IdentifierArgument = Argument & {\n type: \"identifier\";\n};\n\n/**\n * A type representing a reference to any node function argument.\n */\ntype AnyArgument = NullArgument | BooleanArgument | NumberArgument | StringPlaceholderArgument | IdentifierArgument;\n\n/**\n * Parse an array of argument definitions from the specified tokens array.\n * @param tokens The array tokens to parse the argument definitions from.\n * @param stringArgumentPlaceholders The mapping of string literal node argument placeholders to original values.\n * @param argumentValidator The argument validator function.\n * @param validationFailedMessage The exception message to throw if argument validation fails.\n * @returns An array of argument definitions parsed from the specified tokens array.\n */\nexport function parseArgumentTokens(\n tokens: string[],\n stringArgumentPlaceholders: StringLiteralPlaceholders\n): AnyArgument[] {\n const argumentList: AnyArgument[] = [];\n\n // If the next token is not a '[' or '(' then we have no arguments to parse.\n if (![\"[\", \"(\"].includes(tokens[0])) {\n return argumentList;\n }\n\n // Any lists of arguments will always be wrapped in '[]' for node arguments or '()' for attribute arguments.\n // We are looking for a '[' or '(' opener that wraps the argument tokens and the relevant closer.\n const closingToken = popAndCheck(tokens, [\"[\", \"(\"]) === \"[\" ? \"]\" : \")\";\n\n const argumentListTokens: string[] = [];\n\n // Grab all tokens between the '[' and ']' or '(' and ')'.\n while (tokens.length && tokens[0] !== closingToken) {\n // The next token is part of our arguments list.\n argumentListTokens.push(tokens.shift()!);\n }\n\n // Validate the order of the argument tokens. Each token must either be a ',' or a single argument that satisfies the validator.\n argumentListTokens.forEach((token, index) => {\n // Get whether this token should be an actual argument.\n const shouldBeArgumentToken = !(index & 1);\n\n // If the current token should be an actual argument then validate it, otherwise it should be a ',' token.\n if (shouldBeArgumentToken) {\n // Get the argument definition.\n const argumentDefinition = getArgumentDefinition(token, stringArgumentPlaceholders);\n\n // This is a valid argument!\n argumentList.push(argumentDefinition);\n } else {\n // The current token should be a ',' token.\n if (token !== \",\") {\n throw new Error(`invalid argument list, expected ',' or ']' but got '${token}'`);\n }\n }\n });\n\n // The arguments list should terminate with a ']' or ')' token, depending on the opener.\n popAndCheck(tokens, closingToken);\n\n // Return the arguments.\n return argumentList;\n}\n\n/**\n * Gets an argument value definition.\n * @param token The argument token.\n * @param stringArgumentPlaceholders The mapping of string literal node argument placeholders to original values.\n * @returns An argument value definition.\n */\nfunction getArgumentDefinition(token: string, stringArgumentPlaceholders: StringLiteralPlaceholders): AnyArgument {\n // Check whether the token represents a null value.\n if (token === \"null\") {\n return {\n value: null,\n type: \"null\"\n } as NullArgument;\n }\n\n // Check whether the token represents a boolean value.\n if (token === \"true\" || token === \"false\") {\n return {\n value: token === \"true\",\n type: \"boolean\"\n } as BooleanArgument;\n }\n\n // Check whether the token represents a number value.\n // TODO: Relies on broken isNaN - see MDN.\n // if (!Number.isNaN(token)) {\n if (!isNaN(token as any)) {\n return {\n value: parseFloat(token),\n isInteger: parseFloat(token) === parseInt(token, 10),\n type: \"number\"\n } as NumberArgument;\n }\n\n // Check whether the token is a placeholder (e.g. @@0@@) representing a string literal.\n if (token.match(/^@@\\d+@@$/g)) {\n return {\n value: stringArgumentPlaceholders[token].replace('\\\\\"', '\"'),\n type: \"string\"\n } as StringPlaceholderArgument;\n }\n\n // The only remaining option is that the argument value is an identifier.\n return {\n value: token,\n type: \"identifier\"\n } as IdentifierArgument;\n}\n", "import { NodeAttributeDefinition } from \"../BehaviourTreeDefinition\";\nimport { parseArgumentTokens } from \"./MDSLNodeArgumentParser\";\nimport { StringLiteralPlaceholders } from \"./MDSLUtilities\";\n\n/**\n * A type defining the attribute definitions of a node.\n */\ntype NodeAttributes = {\n while?: NodeAttributeDefinition;\n until?: NodeAttributeDefinition;\n entry?: NodeAttributeDefinition;\n exit?: NodeAttributeDefinition;\n step?: NodeAttributeDefinition;\n};\n\n/**\n * Parse any node attribute definitions from the specified tokens array.\n * @param tokens The array of remaining tokens.\n * @param stringArgumentPlaceholders The mapping of string literal node argument placeholders to original values.\n * @returns An object of attribute definitions defined by any directly following tokens.\n */\nexport function parseAttributeTokens(\n tokens: string[],\n stringArgumentPlaceholders: StringLiteralPlaceholders\n): NodeAttributes {\n const nodeAttributeNames: (keyof NodeAttributes)[] = [\"while\", \"until\", \"entry\", \"exit\", \"step\"];\n\n // Create an object to hold any attributes found.\n const attributes: NodeAttributes = {};\n\n // Try to get the name of the attribute for the next token.\n let nextAttributeName = tokens[0]?.toLowerCase() as keyof NodeAttributes;\n\n // Pull attribute tokens as well as their arguments off of the tokens stack until we have no more.\n while (nodeAttributeNames.includes(nextAttributeName)) {\n // Check to make sure that we have not already created an attribute definition of this type.\n if (attributes[nextAttributeName]) {\n throw new Error(`duplicate attribute '${tokens[0].toUpperCase()}' found for node`);\n }\n\n // Remove the attribute name token from the array of tokens.\n tokens.shift();\n\n // Grab the attribute arguments, assuming the first to be an identifier.\n const [attributeCallIdentifier, ...attributeArguments] = parseArgumentTokens(\n tokens,\n stringArgumentPlaceholders\n );\n\n // The first attribute argument has to be an identifer, this will reference an agent function.\n if (attributeCallIdentifier?.type !== \"identifier\") {\n throw new Error(\"expected agent function or registered function name identifier argument for attribute\");\n }\n\n // Any attribute arguments (other than the expected call identifier) must have a type of string, number, boolean or null.\n attributeArguments\n .filter((arg) => arg.type === \"identifier\")\n .forEach((arg) => {\n throw new Error(\n `invalid attribute argument value '${arg.value}', must be string, number, boolean or null`\n );\n });\n\n // Create the attribute definition and add it to the object of attribute definitions found.\n attributes[nextAttributeName] = {\n call: attributeCallIdentifier.value,\n args: attributeArguments.map(({ value }) => value)\n };\n\n // Try to get the next attribute name token, as there could be multiple.\n nextAttributeName = tokens[0]?.toLowerCase() as keyof NodeAttributes;\n }\n\n return attributes;\n}\n", "import {\n ActionNodeDefinition,\n AnyChildNodeDefinition,\n AnyNodeDefinition,\n BranchNodeDefinition,\n ConditionNodeDefinition,\n FailNodeDefinition,\n FlipNodeDefinition,\n LottoNodeDefinition,\n ParallelNodeDefinition,\n RepeatNodeDefinition,\n RetryNodeDefinition,\n RootNodeDefinition,\n SelectorNodeDefinition,\n SequenceNodeDefinition,\n SucceedNodeDefinition,\n WaitNodeDefinition\n} from \"../BehaviourTreeDefinition\";\nimport {\n isCompositeNode,\n isDecoratorNode,\n isLeafNode,\n isNullOrUndefined,\n isRootNode\n} from \"../BehaviourTreeDefinitionUtilities\";\nimport { parseArgumentTokens } from \"./MDSLNodeArgumentParser\";\nimport { parseAttributeTokens } from \"./MDSLNodeAttributeParser\";\nimport {\n StringLiteralPlaceholders,\n parseTokensFromDefinition,\n popAndCheck,\n substituteStringLiterals\n} from \"./MDSLUtilities\";\n\n/**\n * Convert the MDSL tree definition string into an equivalent JSON definition.\n * @param definition The tree definition string as MDSL.\n * @returns The root node JSON definitions.\n */\nexport function convertMDSLToJSON(definition: string): RootNodeDefinition[] {\n // Swap out any node/attribute argument string literals with a placeholder and get a mapping of placeholders to original values as well as the processed definition.\n const { placeholders, processedDefinition } = substituteStringLiterals(definition);\n\n // Parse our definition definition string into an array of raw tokens.\n const tokens = parseTokensFromDefinition(processedDefinition);\n\n return convertTokensToJSONDefinition(tokens, placeholders);\n}\n\n/**\n * Converts the specified tree definition tokens into a JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The root node JSON definitions.\n */\nfunction convertTokensToJSONDefinition(\n tokens: string[],\n stringLiteralPlaceholders: StringLiteralPlaceholders\n): RootNodeDefinition[] {\n // There must be at least 3 tokens for the tree definition to be valid. 'ROOT', '{' and '}'.\n if (tokens.length < 3) {\n throw new Error(\"invalid token count\");\n }\n\n // We should have a matching number of '{' and '}' tokens. If not, then there are scopes that have not been properly closed.\n if (tokens.filter((token) => token === \"{\").length !== tokens.filter((token) => token === \"}\").length) {\n throw new Error(\"scope character mismatch\");\n }\n\n // Create an array of tree stack arrays where root nodes will always be at the botton and the current composite/decorator node at the top.\n // There should be an element in this array for every root node defined and every element should be an array with a root note as the first element.\n // E.g. A definition with two root nodes defined:\n // [\n // [root, lotto, sequence],\n // [root, selector]\n // ]\n const treeStacks: [Partial, ...Partial[]][] = [];\n\n // Create an array of all root node definitions that we create.\n const rootNodes: Partial[] = [];\n\n // A helper function used to push node definitions onto the tree stack.\n const pushNode = (node: AnyNodeDefinition) => {\n // If the node is a root node then we need to create a new tree stack array with the root node at the root.\n if (isRootNode(node)) {\n // We need to double-check that this root node is not the child of another node.\n // We can do this by checking whether the top tree stack is not empty (contains an existing node)\n if (treeStacks[treeStacks.length - 1]?.length) {\n throw new Error(\"a root node cannot be the child of another node\");\n }\n\n // Add the root node definition to our array of all parsed root node definitions.\n rootNodes.push(node);\n\n // Add the root node definition to the root of a new tree stack.\n treeStacks.push([node]);\n\n return;\n }\n\n // All non-root nodes should be pushed after their root nodes so handle cases\n // where we may not have any tree stacks or our top-most tree stack is empty.\n if (!treeStacks.length || !treeStacks[treeStacks.length - 1].length) {\n throw new Error(\"expected root node at base of definition\");\n }\n\n // Get the current tree stack that we are populating.\n const topTreeStack = treeStacks[treeStacks.length - 1];\n\n // Get the top-most node in the current tree stack, this will be a composite/decorator node\n // for which we will populate its children array if composite or setting its child if a decorator.\n const topTreeStackTopNode = topTreeStack[topTreeStack.length - 1] as AnyNodeDefinition;\n\n // If the top-most node in the current root stack is a composite or decorator\n // node then the current node should be added as a child of the top-most node.\n if (isCompositeNode(topTreeStackTopNode)) {\n topTreeStackTopNode.children = topTreeStackTopNode.children || [];\n topTreeStackTopNode.children.push(node);\n } else if (isDecoratorNode(topTreeStackTopNode)) {\n // If the top node already has a child node set then throw an error as a decorator should only have a single child.\n if (topTreeStackTopNode.child) {\n throw new Error(\"a decorator node must only have a single child node\");\n }\n\n topTreeStackTopNode.child = node;\n }\n\n // If the node we are adding is also a composite or decorator node, then we should push it\n // onto the current tree stack, as subsequent nodes will be added as its child/children.\n if (!isLeafNode(node)) {\n topTreeStack.push(node);\n }\n };\n\n // A helper function used to pop the top-most node definition off of the tree stack and return it.\n const popNode = (): AnyNodeDefinition | null => {\n let poppedNode: AnyNodeDefinition | null = null;\n\n // Get the current tree stack that we are populating.\n const topTreeStack = treeStacks[treeStacks.length - 1];\n\n // Pop the top-most node in the current tree stack if there is one.\n if (topTreeStack.length) {\n poppedNode = topTreeStack.pop() as AnyNodeDefinition;\n }\n\n // We don't want any empty tree stacks in our stack of tree stacks.\n if (!topTreeStack.length) {\n treeStacks.pop();\n }\n\n return poppedNode;\n };\n\n // We should keep processing the raw tokens until we run out of them.\n while (tokens.length) {\n // Grab the next token.\n const token = tokens.shift()!;\n\n // How we create the next node depends on the current raw token value.\n switch (token.toUpperCase()) {\n case \"ROOT\": {\n pushNode(createRootNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"SUCCEED\": {\n pushNode(createSucceedNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"FAIL\": {\n pushNode(createFailNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"FLIP\": {\n pushNode(createFlipNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"REPEAT\": {\n pushNode(createRepeatNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"RETRY\": {\n pushNode(createRetryNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"SEQUENCE\": {\n pushNode(createSequenceNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"SELECTOR\": {\n pushNode(createSelectorNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"PARALLEL\": {\n pushNode(createParallelNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"LOTTO\": {\n pushNode(createLottoNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"ACTION\": {\n pushNode(createActionNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"CONDITION\": {\n pushNode(createConditionNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"WAIT\": {\n pushNode(createWaitNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"BRANCH\": {\n pushNode(createBranchNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"}\": {\n // The '}' character closes the current scope and means that we have to pop a node off of the current stack.\n const poppedNode = popNode();\n\n // Now that we have a node definition we can carry out any validation that may require the node to be fully populated.\n if (poppedNode) {\n validatePoppedNode(poppedNode);\n }\n\n break;\n }\n\n default: {\n throw new Error(`unexpected token: ${token}`);\n }\n }\n }\n\n return rootNodes as RootNodeDefinition[];\n}\n\n/**\n * Creates a root node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The root node JSON definition.\n */\nfunction createRootNode(tokens: string[], stringLiteralPlaceholders: StringLiteralPlaceholders): RootNodeDefinition {\n // Create the root node definition.\n let node = {\n type: \"root\"\n } as Partial;\n\n // Parse any node arguments, we should only have one if any which will be an identifier argument for the root identifier.\n const nodeArguments = parseArgumentTokens(tokens, stringLiteralPlaceholders);\n\n // Check whether any node arguments were defined.\n if (nodeArguments.length) {\n // We should only have one argument, if any, which will be an identifier argument for the root identifier.\n if (nodeArguments.length === 1 && nodeArguments[0].type === \"identifier\") {\n // The root node identifier will be the first and only node argument value.\n node.id = nodeArguments[0].value as string;\n } else {\n throw new Error(\"expected single root name argument\");\n }\n }\n\n // Grab any node attribute definitions and spread them into the node definition.\n node = { ...node, ...parseAttributeTokens(tokens, stringLiteralPlaceholders) };\n\n // This is a decorator node, so we expect an opening '{'.\n popAndCheck(tokens, \"{\");\n\n // Return the root node definition.\n return node as RootNodeDefinition;\n}\n\n/**\n * Creates a succeed node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The succeed node JSON definition.\n */\nfunction createSucceedNode(\n tokens: string[],\n stringLiteralPlaceholders: StringLiteralPlaceholders\n): SucceedNodeDefinition {\n const node = {\n type: \"succeed\",\n ...parseAttributeTokens(tokens, stringLiteralPlaceholders)\n } as SucceedNodeDefinition;\n\n // This is a decorator node, so we expect an opening '{'.\n popAndCheck(tokens, \"{\");\n\n // Return the succeed node definition.\n return node;\n}\n\n/**\n * Creates a fail node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The fail node JSON definition.\n */\nfunction createFailNode(tokens: string[], stringLiteralPlaceholders: StringLiteralPlaceholders): FailNodeDefinition {\n const node = {\n type: \"fail\",\n ...parseAttributeTokens(tokens, stringLiteralPlaceholders)\n } as FailNodeDefinition;\n\n // This is a decorator node, so we expect an opening '{'.\n popAndCheck(tokens, \"{\");\n\n // Return the fail node definition.\n return node;\n}\n\n/**\n * Creates a flip node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The flip node JSON definition.\n */\nfunction createFlipNode(tokens: string[], stringLiteralPlaceholders: StringLiteralPlaceholders): FlipNodeDefinition {\n const node = {\n type: \"flip\",\n ...parseAttributeTokens(tokens, stringLiteralPlaceholders)\n } as FlipNodeDefinition;\n\n // This is a decorator node, so we expect an opening '{'.\n popAndCheck(tokens, \"{\");\n\n // Return the flip node definition.\n return node;\n}\n\n/**\n * Creates a repeat node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The repeat node JSON definition.\n */\nfunction createRepeatNode(\n tokens: string[],\n stringLiteralPlaceholders: StringLiteralPlaceholders\n): RepeatNodeDefinition {\n let node = { type: \"repeat\" } as RepeatNodeDefinition;\n\n // Get the node arguments.\n const nodeArguments = parseArgumentTokens(tokens, stringLiteralPlaceholders);\n\n // The arguments of a repeat node are optional. We may have:\n // - No node arguments, in which case the repeat note will iterate indefinitely.\n // - One node argument which will be the explicit number of iterations to make.\n // - Two node arguments which define the min and max iteration bounds from which a random iteration count will be picked.\n if (nodeArguments.length) {\n // All repeat node arguments MUST be of type number and must be integer.\n nodeArguments\n .filter((arg) => arg.type !== \"number\" || !arg.isInteger)\n .forEach(() => {\n throw new Error(`repeat node iteration counts must be integer values`);\n });\n\n // We should have got one or two iteration counts.\n if (nodeArguments.length === 1) {\n // A static iteration count was defined.\n node.iterations = nodeArguments[0].value as number;\n\n // A repeat node must have a positive number of iterations if defined.\n if (node.iterations < 0) {\n throw new Error(\"a repeat node must have a positive number of iterations if defined\");\n }\n } else if (nodeArguments.length === 2) {\n // A minimum and maximum iteration count was defined.\n node.iterations = [nodeArguments[0].value as number, nodeArguments[1].value as number];\n\n // A repeat node must have a positive min and max iteration count if they are defined.\n if (node.iterations[0] < 0 || node.iterations[1] < 0) {\n throw new Error(\"a repeat node must have a positive minimum and maximum iteration count if defined\");\n }\n\n // A repeat node must not have an minimum iteration count that exceeds the maximum iteration count.\n if (node.iterations[0] > node.iterations[1]) {\n throw new Error(\n \"a repeat node must not have a minimum iteration count that exceeds the maximum iteration count\"\n );\n }\n } else {\n // An incorrect number of iteration counts was defined.\n throw new Error(\"invalid number of repeat node iteration count arguments defined\");\n }\n }\n\n // Grab any node attribute definitions and spread them into the node definition.\n node = { ...node, ...parseAttributeTokens(tokens, stringLiteralPlaceholders) };\n\n // This is a decorator node, so we expect an opening '{'.\n popAndCheck(tokens, \"{\");\n\n // Return the repeat node definition.\n return node;\n}\n\n/**\n * Creates a retry node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The retry node JSON definition.\n */\nfunction createRetryNode(tokens: string[], stringLiteralPlaceholders: StringLiteralPlaceholders): RetryNodeDefinition {\n let node = { type: \"retry\" } as RetryNodeDefinition;\n\n // Get the node arguments.\n const nodeArguments = parseArgumentTokens(tokens, stringLiteralPlaceholders);\n\n // The arguments of a retry node are optional. We may have:\n // - No node arguments, in which case the retry note will attempt indefinitely.\n // - One node argument which will be the explicit number of attempts to make.\n // - Two node arguments which define the min and max attempt bounds from which a random attempt count will be picked.\n if (nodeArguments.length) {\n // All retry node arguments MUST be of type number and must be integer.\n nodeArguments\n .filter((arg) => arg.type !== \"number\" || !arg.isInteger)\n .forEach(() => {\n throw new Error(`retry node attempt counts must be integer values`);\n });\n\n // We should have got one or two attempt counts.\n if (nodeArguments.length === 1) {\n // A static attempt count was defined.\n node.attempts = nodeArguments[0].value as number;\n\n // A retry node must have a positive number of attempts if defined.\n if (node.attempts < 0) {\n throw new Error(\"a retry node must have a positive number of attempts if defined\");\n }\n } else if (nodeArguments.length === 2) {\n // A minimum and maximum attempt count was defined.\n node.attempts = [nodeArguments[0].value as number, nodeArguments[1].value as number];\n\n // A retry node must have a positive min and max attempts count if they are defined.\n if (node.attempts[0] < 0 || node.attempts[1] < 0) {\n throw new Error(\"a retry node must have a positive minimum and maximum attempt count if defined\");\n }\n\n // A retry node must not have a minimum attempt count that exceeds the maximum attempt count.\n if (node.attempts[0] > node.attempts[1]) {\n throw new Error(\n \"a retry node must not have a minimum attempt count that exceeds the maximum attempt count\"\n );\n }\n } else {\n // An incorrect number of attempt counts was defined.\n throw new Error(\"invalid number of retry node attempt count arguments defined\");\n }\n }\n\n // Grab any node attribute definitions and spread them into the node definition.\n node = { ...node, ...parseAttributeTokens(tokens, stringLiteralPlaceholders) };\n\n // This is a decorator node, so we expect an opening '{'.\n popAndCheck(tokens, \"{\");\n\n // Return the retry node definition.\n return node;\n}\n\n/**\n * Creates a sequence node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The sequence node JSON definition.\n */\nfunction createSequenceNode(\n tokens: string[],\n stringLiteralPlaceholders: StringLiteralPlaceholders\n): SequenceNodeDefinition {\n const node = {\n type: \"sequence\",\n ...parseAttributeTokens(tokens, stringLiteralPlaceholders)\n } as SequenceNodeDefinition;\n\n // This is a composite node, so we expect an opening '{'.\n popAndCheck(tokens, \"{\");\n\n // Return the sequence node definition.\n return node;\n}\n\n/**\n * Creates a selector node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The selector node JSON definition.\n */\nfunction createSelectorNode(\n tokens: string[],\n stringLiteralPlaceholders: StringLiteralPlaceholders\n): SelectorNodeDefinition {\n const node = {\n type: \"selector\",\n ...parseAttributeTokens(tokens, stringLiteralPlaceholders)\n } as SelectorNodeDefinition;\n\n // This is a composite node, so we expect an opening '{'.\n popAndCheck(tokens, \"{\");\n\n // Return the selector node definition.\n return node;\n}\n\n/**\n * Creates a parallel node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The parallel node JSON definition.\n */\nfunction createParallelNode(\n tokens: string[],\n stringLiteralPlaceholders: StringLiteralPlaceholders\n): ParallelNodeDefinition {\n const node = {\n type: \"parallel\",\n ...parseAttributeTokens(tokens, stringLiteralPlaceholders)\n } as ParallelNodeDefinition;\n\n // This is a composite node, so we expect an opening '{'.\n popAndCheck(tokens, \"{\");\n\n // Return the parallel node definition.\n return node;\n}\n\n/**\n * Creates a lotto node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The lotto node JSON definition.\n */\nfunction createLottoNode(tokens: string[], stringLiteralPlaceholders: StringLiteralPlaceholders): LottoNodeDefinition {\n // If any node arguments have been defined then they must be our weights.\n const nodeArguments = parseArgumentTokens(tokens, stringLiteralPlaceholders);\n\n // All lotto node arguments MUST be of type number and must be positive integers.\n nodeArguments\n .filter((arg) => arg.type !== \"number\" || !arg.isInteger || arg.value < 0)\n .forEach(() => {\n throw new Error(`lotto node weight arguments must be positive integer values`);\n });\n\n const node = {\n type: \"lotto\",\n ...parseAttributeTokens(tokens, stringLiteralPlaceholders)\n } as LottoNodeDefinition;\n\n // Apply the weights if any were defined.\n if (nodeArguments.length) {\n node.weights = nodeArguments.map(({ value }) => value) as number[];\n }\n\n // This is a composite node, so we expect an opening '{'.\n popAndCheck(tokens, \"{\");\n\n // Return the lotto node definition.\n return node;\n}\n\n/**\n * Creates an action node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The action node JSON definition.\n */\nfunction createActionNode(\n tokens: string[],\n stringLiteralPlaceholders: StringLiteralPlaceholders\n): ActionNodeDefinition {\n // Parse any node arguments, we should have at least one which will be an identifier argument for the action name\n // and agent function to invoke for the action, all other arguments are to be passed as arguments to that function.\n const [actionNameIdentifier, ...agentFunctionArgs] = parseArgumentTokens(tokens, stringLiteralPlaceholders);\n\n // Our first argument MUST be defined and be an identifier as we require an action name argument.\n if (actionNameIdentifier?.type !== \"identifier\") {\n throw new Error(\"expected action name identifier argument\");\n }\n\n // Only the first argument should have been an identifier, all agent function arguments must be string, number, boolean or null.\n agentFunctionArgs\n .filter((arg) => arg.type === \"identifier\")\n .forEach((arg) => {\n throw new Error(\n `invalid action node argument value '${arg.value}', must be string, number, boolean or null`\n );\n });\n\n // Return the action node definition.\n return {\n type: \"action\",\n call: actionNameIdentifier.value,\n args: agentFunctionArgs.map(({ value }) => value),\n ...parseAttributeTokens(tokens, stringLiteralPlaceholders)\n };\n}\n\n/**\n * Creates a condition node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The condition node JSON definition.\n */\nfunction createConditionNode(\n tokens: string[],\n stringLiteralPlaceholders: StringLiteralPlaceholders\n): ConditionNodeDefinition {\n // Parse any node arguments, we should have at least one which will be an identifier argument for the condition name\n // and agent function to invoke for the condition, all other arguments are to be passed as arguments to that function.\n const [conditionNameIdentifier, ...agentFunctionArgs] = parseArgumentTokens(tokens, stringLiteralPlaceholders);\n\n // Our first argument MUST be defined and be an identifier as we require a condition name argument.\n if (conditionNameIdentifier?.type !== \"identifier\") {\n throw new Error(\"expected condition name identifier argument\");\n }\n\n // Only the first argument should have been an identifier, all agent function arguments must be string, number, boolean or null.\n agentFunctionArgs\n .filter((arg) => arg.type === \"identifier\")\n .forEach((arg) => {\n throw new Error(\n `invalid condition node argument value '${arg.value}', must be string, number, boolean or null`\n );\n });\n\n // Return the condition node definition.\n return {\n type: \"condition\",\n call: conditionNameIdentifier.value,\n args: agentFunctionArgs.map(({ value }) => value),\n ...parseAttributeTokens(tokens, stringLiteralPlaceholders)\n };\n}\n\n/**\n * Creates a wait node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The wait node JSON definition.\n */\nfunction createWaitNode(tokens: string[], stringLiteralPlaceholders: StringLiteralPlaceholders): WaitNodeDefinition {\n let node = { type: \"wait\" } as WaitNodeDefinition;\n\n // Get the node arguments.\n const nodeArguments = parseArgumentTokens(tokens, stringLiteralPlaceholders);\n\n // The arguments of a wait node are optional. We may have:\n // - No node arguments, in which case the wait will be indefinite until it is aborted.\n // - One node argument which will be the explicit duration of the wait.\n // - Two node arguments which define the min and max duration bounds from which a random duration will be picked.\n if (nodeArguments.length) {\n // All wait node arguments MUST be of type number and must be integer.\n nodeArguments\n .filter((arg) => arg.type !== \"number\" || !arg.isInteger)\n .forEach(() => {\n throw new Error(`wait node durations must be integer values`);\n });\n\n // We may have:\n // - One node argument which will be the explicit duration of the wait.\n // - Two node arguments which define the min and max duration bounds from which a random duration will be picked.\n // - Too many arguments, which is not valid.\n if (nodeArguments.length === 1) {\n // An explicit duration was defined.\n node.duration = nodeArguments[0].value as number;\n\n // If an explict duration was defined then it must be a positive number.\n if (node.duration < 0) {\n throw new Error(\"a wait node must have a positive duration\");\n }\n } else if (nodeArguments.length === 2) {\n // Min and max duration bounds were defined from which a random duration will be picked.\n node.duration = [nodeArguments[0].value as number, nodeArguments[1].value as number];\n\n // A wait node must have a positive min and max duration.\n if (node.duration[0] < 0 || node.duration[1] < 0) {\n throw new Error(\"a wait node must have a positive minimum and maximum duration\");\n }\n\n // A wait node must not have a minimum duration that exceeds the maximum duration.\n if (node.duration[0] > node.duration[1]) {\n throw new Error(\"a wait node must not have a minimum duration that exceeds the maximum duration\");\n }\n } else if (nodeArguments.length > 2) {\n // An incorrect number of duration arguments were defined.\n throw new Error(\"invalid number of wait node duration arguments defined\");\n }\n }\n\n // Return the wait node definition.\n return { ...node, ...parseAttributeTokens(tokens, stringLiteralPlaceholders) };\n}\n\n/**\n * Creates a branch node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The branch node JSON definition.\n */\nfunction createBranchNode(\n tokens: string[],\n stringLiteralPlaceholders: StringLiteralPlaceholders\n): BranchNodeDefinition {\n // Parse any node arguments, we should have one which will be an identifier argument for the root ref.\n const nodeArguments = parseArgumentTokens(tokens, stringLiteralPlaceholders);\n\n // We should have only a single identifer argument for a branch node, which is the root ref.\n if (nodeArguments.length !== 1 || nodeArguments[0].type !== \"identifier\") {\n throw new Error(\"expected single branch name argument\");\n }\n\n // Return the branch node definition.\n return { type: \"branch\", ref: nodeArguments[0].value };\n}\n\n/**\n * Validate a fully-populated node definition that was popped off of the tree stack.\n * @param definition The popped node to validate.\n */\nfunction validatePoppedNode(definition: AnyNodeDefinition): void {\n // Decorators MUST have a child defined.\n if (isDecoratorNode(definition) && isNullOrUndefined(definition.child)) {\n throw new Error(`a ${definition.type} node must have a single child node defined`);\n }\n\n // Composites MUST have at least one child defined.\n if (isCompositeNode(definition) && !definition.children?.length) {\n throw new Error(`a ${definition.type} node must have at least a single child node defined`);\n }\n\n // We need to make sure that lotto nodes that have weights defined have a number of weights matching the number of child nodes.\n if (definition.type === \"lotto\") {\n // Check whether a 'weights' property has been defined, if it has we expect it to be an array of weights.\n if (typeof definition.weights !== \"undefined\") {\n // Check that the weights property is an array of positive integers with an element for each child node element.\n if (definition.weights.length !== definition.children.length) {\n throw new Error(\n \"expected a number of weight arguments matching the number of child nodes for lotto node\"\n );\n }\n }\n }\n}\n", "import { RootNodeDefinition } from \"./BehaviourTreeDefinition\";\nimport { flattenDefinition, isBranchNode, isInteger } from \"./BehaviourTreeDefinitionUtilities\";\nimport { convertMDSLToJSON } from \"./mdsl/MDSLDefinitionParser\";\n\n/**\n * An object representing the result of validating a tree definition.\n */\nexport type DefinitionValidationResult = {\n /**\n * A flag defining whether validation succeeded.\n */\n succeeded: boolean;\n /**\n * A string containing the error message if validation did not succeed.\n */\n errorMessage?: string;\n /**\n * The definition as json if the validation was successful, or undefined if validation did not succeed.\n */\n json?: RootNodeDefinition[];\n};\n\n/**\n * Validates the specified behaviour tree definition in the form of JSON or MDSL, not taking any globally registered subtrees into consideration.\n * @param definition The behaviour tree definition in the form of JSON or MDSL.\n * @returns An object representing the result of validating the given tree definition.\n */\nexport function validateDefinition(definition: any): DefinitionValidationResult {\n // The definition must be defined.\n if (definition === null || typeof definition === \"undefined\") {\n return createValidationFailureResult(\"definition is null or undefined\");\n }\n\n // We are expecting a definition in one of three different forms:\n // - A string which we will assume is MDSL and we will parse this to JSON before validation.\n // - An array which we will assume is an array of root node definitions with at least one being the primary root node (no 'id' property)\n // - An object which we will assume is the primary root node and should not have an 'id' property.\n if (typeof definition === \"string\") {\n // The definition is a string which we can assume is MDSL, so attempt to validate it.\n return validateMDSLDefinition(definition);\n } else if (typeof definition === \"object\") {\n // The definition will either be an array (of root node definitions) or an object (the single primary root node definition).\n return validateJSONDefinition(definition);\n } else {\n return createValidationFailureResult(`unexpected definition type of '${typeof definition}'`);\n }\n}\n\n/**\n * Validates the specified behaviour tree definition in the form of MDSL.\n * @param definition The behaviour tree definition in the form of MDSL.\n * @returns An object representing the result of validating the given tree definition.\n */\nfunction validateMDSLDefinition(definition: string): DefinitionValidationResult {\n let rootNodeDefinitions;\n\n // The first thing the we need to do is to attempt to convert our MDSL into JSON.\n try {\n // The definition is a string which we can assume is MDSL, so attempt to parse it to a JSON definition in the form of an array of root node definitions.\n rootNodeDefinitions = convertMDSLToJSON(definition);\n } catch (exception) {\n // We failed to parse the JSON from the MDSL, this is likely to be the result of it not being a valid MDSL string.\n return createValidationFailureResult((exception as Error).message);\n }\n\n // Unpack all of the root node definitions into arrays of main ('id' defined) and sub ('id' not defined) root node definitions.\n const mainRootNodeDefinitions = rootNodeDefinitions.filter(({ id }) => typeof id === \"undefined\");\n const subRootNodeDefinitions = rootNodeDefinitions.filter(({ id }) => typeof id === \"string\" && id.length > 0);\n\n // We should ALWAYS have exactly one root node definition without an 'id' property defined, which is out main root node definition.\n if (mainRootNodeDefinitions.length !== 1) {\n return createValidationFailureResult(\n \"expected single unnamed root node at base of definition to act as main root\"\n );\n }\n\n // We should never have duplicate 'id' properties across our sub root node definitions.\n const subRootNodeIdenitifers: string[] = [];\n for (const { id } of subRootNodeDefinitions) {\n // Have we already come across this 'id' property value?\n if (subRootNodeIdenitifers.includes(id!)) {\n return createValidationFailureResult(`multiple root nodes found with duplicate name '${id}'`);\n }\n\n subRootNodeIdenitifers.push(id!);\n }\n\n try {\n // Validate our branch -> subtree links and check for any circular dependencies, we don't care about checking for broken subtree links here.\n validateBranchSubtreeLinks(rootNodeDefinitions, false);\n } catch (exception) {\n return createValidationFailureResult((exception as Error).message);\n }\n\n // Our definition was valid!\n return {\n succeeded: true,\n json: rootNodeDefinitions\n };\n}\n\n/**\n * Validates the specified behaviour tree definition in the form of JSON.\n * @param definition The behaviour tree definition in the form of JSON.\n * @returns An object representing the result of validating the given tree definition.\n */\nexport function validateJSONDefinition(\n definition: RootNodeDefinition | RootNodeDefinition[]\n): DefinitionValidationResult {\n // The definition will either be an array (of root node definitions) or an object (the single primary root node definition).\n const rootNodeDefinitions = Array.isArray(definition) ? definition : [definition];\n\n // Iterate over our array of root nodes and call validateNode for each, passing an initial depth of 0, wrapped in a try catch to handle validation failures.\n try {\n rootNodeDefinitions.forEach((rootNodeDefinition) => validateNode(rootNodeDefinition, 0));\n } catch (error) {\n // Handle cases where we have caught a thrown Error and return a failure result with the error message.\n if (error instanceof Error) {\n return createValidationFailureResult(error.message);\n }\n\n // No idea what happened here!\n return createValidationFailureResult(`unexpected error: ${error}`);\n }\n\n // Unpack all of the root node definitions into arrays of main ('id' defined) and sub ('id' not defined) root node definitions.\n const mainRootNodeDefinitions = rootNodeDefinitions.filter(({ id }) => typeof id === \"undefined\");\n const subRootNodeDefinitions = rootNodeDefinitions.filter(({ id }) => typeof id === \"string\" && id.length > 0);\n\n // We should ALWAYS have exactly one root node definition without an 'id' property defined, which is out main root node definition.\n if (mainRootNodeDefinitions.length !== 1) {\n return createValidationFailureResult(\n \"expected single root node without 'id' property defined to act as main root\"\n );\n }\n\n // We should never have duplicate 'id' properties across our sub root node definitions.\n const subRootNodeIdenitifers: string[] = [];\n for (const { id } of subRootNodeDefinitions) {\n // Have we already come across this 'id' property value?\n if (subRootNodeIdenitifers.includes(id!)) {\n return createValidationFailureResult(\n `multiple root nodes found with duplicate 'id' property value of '${id}'`\n );\n }\n\n subRootNodeIdenitifers.push(id!);\n }\n\n try {\n // Validate our branch -> subtree links and check for any circular dependencies, we don't care about checking for broken subtree links here.\n validateBranchSubtreeLinks(rootNodeDefinitions, false);\n } catch (exception) {\n return createValidationFailureResult((exception as Error).message);\n }\n\n // Our definition was valid!\n return {\n succeeded: true,\n json: rootNodeDefinitions\n };\n}\n\n/**\n * Validates the branch -> subtree links across all provided root node definitions.\n * This will not consider branch nodes that reference any globally registered subtrees unless includesGlobalSubtrees\n * is set to true, in which case we will also verify that there are no broken branch -> subtree links.\n * @param rootNodeDefinitions The array of root node definitions.\n * @param includesGlobalSubtrees A flag defining whether the array includes all global subtree root node definitions.\n */\nexport function validateBranchSubtreeLinks(rootNodeDefinitions: RootNodeDefinition[], includesGlobalSubtrees: boolean) {\n // Create a mapping of root node identifiers to other root nodes that they reference via branch nodes.\n // Below is an example of a mapping that includes a circular dependency (root => a => b => c => a)\n // [{ refs: [\"a\", \"b\"] }, { id: \"a\", refs: [\"b\"] }, { id: \"b\", refs: [\"c\"] }, { id: \"c\", refs: [\"a\"] }]\n const rootNodeMappings: { id: string | undefined; refs: string[] }[] = rootNodeDefinitions.map(\n (rootNodeDefinition) => ({\n id: rootNodeDefinition.id,\n refs: flattenDefinition(rootNodeDefinition)\n .filter(isBranchNode)\n .map(({ ref }) => ref)\n })\n );\n\n // A recursive function to walk through the mappings, keeping track of which root nodes we have visited in the form of a path of root node identifiers.\n const followRefs = (mapping: { id: string | undefined; refs: string[] }, path: (string | undefined)[] = []) => {\n // Have we found a circular dependency?\n if (path.includes(mapping.id)) {\n // We found a circular dependency! Get the bad path of root node identifiers.\n const badPath = [...path, mapping.id];\n\n // Create the formatted path value. [undefined, \"a\", \"b\", \"c\", \"a\"] would be formatted as \"a -> b -> c -> a\".\n const badPathFormatted = badPath.filter((element) => !!element).join(\" => \");\n\n // No need to continue, we found a circular dependency.\n throw new Error(`circular dependency found in branch node references: ${badPathFormatted}`);\n }\n\n for (const ref of mapping.refs) {\n // Find the mapping for the root node with an identifer matching the current ref.\n const subMapping = rootNodeMappings.find(({ id }) => id === ref);\n\n // We may not have a mapping for this ref, which is normal when we aren't considering all globally registered subtrees.\n if (subMapping) {\n followRefs(subMapping, [...path, mapping.id]);\n } else if (includesGlobalSubtrees) {\n // We found a reference to a root node that doesn't exist, which is a problem seeing as the root node definitons includes all globally registered subtrees.\n throw new Error(\n mapping.id\n ? `subtree '${mapping.id}' has branch node that references root node '${ref}' which has not been defined`\n : `primary tree has branch node that references root node '${ref}' which has not been defined`\n );\n }\n }\n };\n\n // Start looking for circular dependencies and broken references from the primary root node definition.\n followRefs(rootNodeMappings.find((mapping) => typeof mapping.id === \"undefined\")!);\n}\n\n/**\n * Validate an object that we expect to be a node definition.\n * @param definition An object that we expect to be a node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateNode(definition: any, depth: number): void {\n // Every node must be valid object and have a non-empty 'type' string property.\n if (typeof definition !== \"object\" || typeof definition.type !== \"string\" || definition.type.length === 0) {\n throw new Error(\n `node definition is not an object or 'type' property is not a non-empty string at depth '${depth}'`\n );\n }\n\n // How we validate this node definition will depend on its type.\n switch (definition.type) {\n case \"action\":\n validateActionNode(definition, depth);\n break;\n\n case \"condition\":\n validateConditionNode(definition, depth);\n break;\n\n case \"wait\":\n validateWaitNode(definition, depth);\n break;\n\n case \"branch\":\n validateBranchNode(definition, depth);\n break;\n\n case \"root\":\n validateRootNode(definition, depth);\n break;\n\n case \"succeed\":\n validateSucceedNode(definition, depth);\n break;\n\n case \"fail\":\n validateFailNode(definition, depth);\n break;\n\n case \"flip\":\n validateFlipNode(definition, depth);\n break;\n\n case \"repeat\":\n validateRepeatNode(definition, depth);\n break;\n\n case \"retry\":\n validateRetryNode(definition, depth);\n break;\n\n case \"sequence\":\n validateSequenceNode(definition, depth);\n break;\n\n case \"selector\":\n validateSelectorNode(definition, depth);\n break;\n\n case \"parallel\":\n validateParallelNode(definition, depth);\n break;\n\n case \"lotto\":\n validateLottoNode(definition, depth);\n break;\n\n default:\n throw new Error(`unexpected node type of '${definition.type}' at depth '${depth}'`);\n }\n}\n\n/**\n * Validate any attributes for a given node definition.\n * @param definition The node definition.\n * @param depth The depth of the node in the behaviour tree definition.\n */\nfunction validateNodeAttributes(definition: any, depth: number): void {\n // Validate each of the attribute types for this node.\n [\"while\", \"until\", \"entry\", \"exit\", \"step\"].forEach((attributeName) => {\n // Attempt to grab the definition for the current attribute from the node definition.\n const attributeDefinition = definition[attributeName];\n\n // All node attributes are optional, so there is nothing to do if the current attribute is not defined.\n if (typeof attributeDefinition === \"undefined\") {\n return;\n }\n\n // The attribute definition must be an object.\n if (typeof attributeDefinition !== \"object\") {\n throw new Error(\n `expected attribute '${attributeName}' to be an object for '${definition.type}' node at depth '${depth}'`\n );\n }\n\n // The 'call' property must be defined for any attribute definition.\n if (typeof attributeDefinition.call !== \"string\" || attributeDefinition.call.length === 0) {\n throw new Error(\n `expected 'call' property for attribute '${attributeName}' to be a non-empty string for '${definition.type}' node at depth '${depth}'`\n );\n }\n\n // If any node attribute arguments have been defined then they must have been defined in an array.\n if (typeof attributeDefinition.args !== \"undefined\" && !Array.isArray(attributeDefinition.args)) {\n throw new Error(\n `expected 'args' property for attribute '${attributeName}' to be an array for '${definition.type}' node at depth '${depth}'`\n );\n }\n });\n}\n\n/**\n * Validate an object that we expect to be a root node definition.\n * @param definition An object that we expect to be a root node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateRootNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"root\") {\n throw new Error(\"expected node type of 'root' for root node\");\n }\n\n // A root node cannot be the child of another node.\n if (depth > 0) {\n throw new Error(\"a root node cannot be the child of another node\");\n }\n\n // Check that, if the root node 'id' property is defined, it is a non-empty string.\n if (typeof definition.id !== \"undefined\" && (typeof definition.id !== \"string\" || definition.id.length === 0)) {\n throw new Error(\"expected non-empty string for 'id' property if defined for root node\");\n }\n\n // A root node is a decorator node, so must have a child node defined.\n if (typeof definition.child === \"undefined\") {\n throw new Error(\"expected property 'child' to be defined for root node\");\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n\n // Validate the child node of this decorator node.\n validateNode(definition.child, depth + 1);\n}\n\n/**\n * Validate an object that we expect to be a succeed node definition.\n * @param definition An object that we expect to be a succeed node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateSucceedNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"succeed\") {\n throw new Error(`expected node type of 'succeed' for succeed node at depth '${depth}'`);\n }\n\n // A succeed node is a decorator node, so must have a child node defined.\n if (typeof definition.child === \"undefined\") {\n throw new Error(`expected property 'child' to be defined for succeed node at depth '${depth}'`);\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n\n // Validate the child node of this decorator node.\n validateNode(definition.child, depth + 1);\n}\n\n/**\n * Validate an object that we expect to be a fail node definition.\n * @param definition An object that we expect to be a fail node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateFailNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"fail\") {\n throw new Error(`expected node type of 'fail' for fail node at depth '${depth}'`);\n }\n\n // A fail node is a decorator node, so must have a child node defined.\n if (typeof definition.child === \"undefined\") {\n throw new Error(`expected property 'child' to be defined for fail node at depth '${depth}'`);\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n\n // Validate the child node of this decorator node.\n validateNode(definition.child, depth + 1);\n}\n\n/**\n * Validate an object that we expect to be a flip node definition.\n * @param definition An object that we expect to be a flip node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateFlipNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"flip\") {\n throw new Error(`expected node type of 'flip' for flip node at depth '${depth}'`);\n }\n\n // A flip node is a decorator node, so must have a child node defined.\n if (typeof definition.child === \"undefined\") {\n throw new Error(`expected property 'child' to be defined for flip node at depth '${depth}'`);\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n\n // Validate the child node of this decorator node.\n validateNode(definition.child, depth + 1);\n}\n\n/**\n * Validate an object that we expect to be a repeat node definition.\n * @param definition An object that we expect to be a repeat node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateRepeatNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"repeat\") {\n throw new Error(`expected node type of 'repeat' for repeat node at depth '${depth}'`);\n }\n\n // A repeat node is a decorator node, so must have a child node defined.\n if (typeof definition.child === \"undefined\") {\n throw new Error(`expected property 'child' to be defined for repeat node at depth '${depth}'`);\n }\n\n // Check whether an 'iterations' property has been defined, it may not have been if this node is to repeat indefinitely.\n if (typeof definition.iterations !== \"undefined\") {\n if (Array.isArray(definition.iterations)) {\n // Check whether any elements of the array are not integer values.\n const containsNonInteger = !!definition.iterations.filter((value: unknown) => !isInteger(value)).length;\n\n // If the 'iterations' property is an array then it MUST contain two integer values.\n if (definition.iterations.length !== 2 || containsNonInteger) {\n throw new Error(\n `expected array containing two integer values for 'iterations' property if defined for repeat node at depth '${depth}'`\n );\n }\n\n // A repeat node must have a positive min and max iterations count if they are defined.\n if (definition.iterations[0] < 0 || definition.iterations[1] < 0) {\n throw new Error(\n `expected positive minimum and maximum iterations count for 'iterations' property if defined for repeat node at depth '${depth}'`\n );\n }\n\n // A repeat node must not have a minimum iterations count that exceeds the maximum iterations count.\n if (definition.iterations[0] > definition.iterations[1]) {\n throw new Error(\n `expected minimum iterations count that does not exceed the maximum iterations count for 'iterations' property if defined for repeat node at depth '${depth}'`\n );\n }\n } else if (isInteger(definition.iterations)) {\n // A repeat node must have a positive number of iterations if defined.\n if (definition.iterations < 0) {\n throw new Error(\n `expected positive iterations count for 'iterations' property if defined for repeat node at depth '${depth}'`\n );\n }\n } else {\n throw new Error(\n `expected integer value or array containing two integer values for 'iterations' property if defined for repeat node at depth '${depth}'`\n );\n }\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n\n // Validate the child node of this decorator node.\n validateNode(definition.child, depth + 1);\n}\n\n/**\n * Validate an object that we expect to be a retry node definition.\n * @param definition An object that we expect to be a retry node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateRetryNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"retry\") {\n throw new Error(`expected node type of 'retry' for retry node at depth '${depth}'`);\n }\n\n // A retry node is a decorator node, so must have a child node defined.\n if (typeof definition.child === \"undefined\") {\n throw new Error(`expected property 'child' to be defined for retry node at depth '${depth}'`);\n }\n\n // Check whether an 'attempts' property has been defined, it may not have been if this node is to retry indefinitely.\n if (typeof definition.attempts !== \"undefined\") {\n if (Array.isArray(definition.attempts)) {\n // Check whether any elements of the array are not integer values.\n const containsNonInteger = !!definition.attempts.filter((value: unknown) => !isInteger(value)).length;\n\n // If the 'attempts' property is an array then it MUST contain two integer values.\n if (definition.attempts.length !== 2 || containsNonInteger) {\n throw new Error(\n `expected array containing two integer values for 'attempts' property if defined for retry node at depth '${depth}'`\n );\n }\n\n // A retry node must have a positive min and max attempts count if they are defined.\n if (definition.attempts[0] < 0 || definition.attempts[1] < 0) {\n throw new Error(\n `expected positive minimum and maximum attempts count for 'attempts' property if defined for retry node at depth '${depth}'`\n );\n }\n\n // A retry node must not have a minimum attempts count that exceeds the maximum attempts count.\n if (definition.attempts[0] > definition.attempts[1]) {\n throw new Error(\n `expected minimum attempts count that does not exceed the maximum attempts count for 'attempts' property if defined for retry node at depth '${depth}'`\n );\n }\n } else if (isInteger(definition.attempts)) {\n // A retry node must have a positive number of attempts if defined.\n if (definition.attempts < 0) {\n throw new Error(\n `expected positive attempts count for 'attempts' property if defined for retry node at depth '${depth}'`\n );\n }\n } else {\n throw new Error(\n `expected integer value or array containing two integer values for 'attempts' property if defined for retry node at depth '${depth}'`\n );\n }\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n\n // Validate the child node of this decorator node.\n validateNode(definition.child, depth + 1);\n}\n\n/**\n * Validate an object that we expect to be a branch node definition.\n * @param definition An object that we expect to be a branch node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateBranchNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"branch\") {\n throw new Error(`expected node type of 'branch' for branch node at depth '${depth}'`);\n }\n\n // Check that the branch node 'ref' property is defined and is a non-empty string.\n if (typeof definition.ref !== \"string\" || definition.ref.length === 0) {\n throw new Error(`expected non-empty string for 'ref' property for branch node at depth '${depth}'`);\n }\n\n // It is invalid to define guard attributes for a branch node as they should be defined on the referenced root node.\n [\"while\", \"until\"].forEach((attributeName) => {\n if (typeof definition[attributeName] !== \"undefined\") {\n throw new Error(\n `guards should not be defined for branch nodes but guard '${attributeName}' was defined for branch node at depth '${depth}'`\n );\n }\n });\n\n // It is invalid to define callback attributes for a branch node as they should be defined on the referenced root node.\n [\"entry\", \"exit\", \"step\"].forEach((attributeName) => {\n if (typeof definition[attributeName] !== \"undefined\") {\n throw new Error(\n `callbacks should not be defined for branch nodes but callback '${attributeName}' was defined for branch node at depth '${depth}'`\n );\n }\n });\n}\n\n/**\n * Validate an object that we expect to be a action node definition.\n * @param definition An object that we expect to be a action node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateActionNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"action\") {\n throw new Error(`expected node type of 'action' for action node at depth '${depth}'`);\n }\n\n // The 'call' property must be defined for a action node definition.\n if (typeof definition.call !== \"string\" || definition.call.length === 0) {\n throw new Error(`expected non-empty string for 'call' property of action node at depth '${depth}'`);\n }\n\n // If any action function arguments have been defined then they must have been defined in an array.\n if (typeof definition.args !== \"undefined\" && !Array.isArray(definition.args)) {\n throw new Error(`expected array for 'args' property if defined for action node at depth '${depth}'`);\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n}\n\n/**\n * Validate an object that we expect to be a condition node definition.\n * @param definition An object that we expect to be a condition node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateConditionNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"condition\") {\n throw new Error(`expected node type of 'condition' for condition node at depth '${depth}'`);\n }\n\n // The 'call' property must be defined for a condition node definition.\n if (typeof definition.call !== \"string\" || definition.call.length === 0) {\n throw new Error(`expected non-empty string for 'call' property of condition node at depth '${depth}'`);\n }\n\n // If any condition function arguments have been defined then they must have been defined in an array.\n if (typeof definition.args !== \"undefined\" && !Array.isArray(definition.args)) {\n throw new Error(`expected array for 'args' property if defined for condition node at depth '${depth}'`);\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n}\n\n/**\n * Validate an object that we expect to be a wait node definition.\n * @param definition An object that we expect to be a wait node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateWaitNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"wait\") {\n throw new Error(`expected node type of 'wait' for wait node at depth '${depth}'`);\n }\n\n // Check whether a 'duration' property has been defined, it may not have been if this node is to wait indefinitely.\n if (typeof definition.duration !== \"undefined\") {\n if (Array.isArray(definition.duration)) {\n // Check whether any elements of the array are not integer values.\n const containsNonInteger = !!definition.duration.filter((value: unknown) => !isInteger(value)).length;\n\n // If the 'duration' property is an array then it MUST contain two integer values.\n if (definition.duration.length !== 2 || containsNonInteger) {\n throw new Error(\n `expected array containing two integer values for 'duration' property if defined for wait node at depth '${depth}'`\n );\n }\n\n // A wait node must have a positive min and max duration value if they are defined.\n if (definition.duration[0] < 0 || definition.duration[1] < 0) {\n throw new Error(\n `expected positive minimum and maximum duration for 'duration' property if defined for wait node at depth '${depth}'`\n );\n }\n\n // A wait node must not have a minimum duration value that exceeds the maximum duration value.\n if (definition.duration[0] > definition.duration[1]) {\n throw new Error(\n `expected minimum duration value that does not exceed the maximum duration value for 'duration' property if defined for wait node at depth '${depth}'`\n );\n }\n } else if (isInteger(definition.duration)) {\n // A wait node must have a positive duration value if defined.\n if (definition.duration < 0) {\n throw new Error(\n `expected positive duration value for 'duration' property if defined for wait node at depth '${depth}'`\n );\n }\n } else {\n throw new Error(\n `expected integer value or array containing two integer values for 'duration' property if defined for wait node at depth '${depth}'`\n );\n }\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n}\n\n/**\n * Validate an object that we expect to be a sequence node definition.\n * @param definition An object that we expect to be a sequence node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateSequenceNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"sequence\") {\n throw new Error(`expected node type of 'sequence' for sequence node at depth '${depth}'`);\n }\n\n // A sequence node is a composite node, so must have a children nodes array defined.\n if (!Array.isArray(definition.children) || definition.children.length === 0) {\n throw new Error(`expected non-empty 'children' array to be defined for sequence node at depth '${depth}'`);\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n\n // Validate the child nodes of this composite node.\n definition.children.forEach((child: any) => validateNode(child, depth + 1));\n}\n\n/**\n * Validate an object that we expect to be a selector node definition.\n * @param definition An object that we expect to be a selector node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateSelectorNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"selector\") {\n throw new Error(`expected node type of 'selector' for selector node at depth '${depth}'`);\n }\n\n // A selector node is a composite node, so must have a children nodes array defined.\n if (!Array.isArray(definition.children) || definition.children.length === 0) {\n throw new Error(`expected non-empty 'children' array to be defined for selector node at depth '${depth}'`);\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n\n // Validate the child nodes of this composite node.\n definition.children.forEach((child: any) => validateNode(child, depth + 1));\n}\n\n/**\n * Validate an object that we expect to be a parallel node definition.\n * @param definition An object that we expect to be a parallel node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateParallelNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"parallel\") {\n throw new Error(`expected node type of 'parallel' for parallel node at depth '${depth}'`);\n }\n\n // A parallel node is a composite node, so must have a children nodes array defined.\n if (!Array.isArray(definition.children) || definition.children.length === 0) {\n throw new Error(`expected non-empty 'children' array to be defined for parallel node at depth '${depth}'`);\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n\n // Validate the child nodes of this composite node.\n definition.children.forEach((child: any) => validateNode(child, depth + 1));\n}\n\n/**\n * Validate an object that we expect to be a lotto node definition.\n * @param definition An object that we expect to be a lotto node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateLottoNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"lotto\") {\n throw new Error(`expected node type of 'lotto' for lotto node at depth '${depth}'`);\n }\n\n // A lotto node is a composite node, so must have a children nodes array defined.\n if (!Array.isArray(definition.children) || definition.children.length === 0) {\n throw new Error(`expected non-empty 'children' array to be defined for lotto node at depth '${depth}'`);\n }\n\n // Check whether a 'weights' property has been defined, if it has we expect it to be an array of weights.\n if (typeof definition.weights !== \"undefined\") {\n // Check that the weights property is an array of positive integers with an element for each child node element.\n if (\n !Array.isArray(definition.weights) ||\n definition.weights.length !== definition.children.length ||\n definition.weights.filter((value: unknown) => !isInteger(value)).length ||\n definition.weights.filter((value: number) => value < 0).length\n ) {\n throw new Error(\n `expected an array of positive integer weight values with a length matching the number of child nodes for 'weights' property if defined for lotto node at depth '${depth}'`\n );\n }\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n\n // Validate the child nodes of this composite node.\n definition.children.forEach((child: any) => validateNode(child, depth + 1));\n}\n\n/**\n * A helper function to create a failure validation result with the given error message.\n * @param errorMessage The validation failure error message.\n * @returns A failure validation result with the given error message.\n */\nfunction createValidationFailureResult(errorMessage: string): DefinitionValidationResult {\n return { succeeded: false, errorMessage };\n}\n", "import { ActionResult, Agent, GlobalFunction } from \"./Agent\";\nimport { RootNodeDefinition } from \"./BehaviourTreeDefinition\";\n\nexport type InvokerFunction = (args: any[]) => ActionResult | boolean;\n\n/**\n * A singleton used to store and lookup registered functions and subtrees.\n */\nexport default class Lookup {\n /**\n * The object holding any registered functions keyed on function name.\n */\n private static registeredFunctions: { [key: string]: GlobalFunction } = {};\n /**\n * The object holding any registered subtree root node definitions keyed on tree name.\n */\n private static registeredSubtrees: { [key: string]: RootNodeDefinition } = {};\n\n /**\n * Gets the function with the specified name.\n * @param name The name of the function.\n * @returns The function with the specified name.\n */\n public static getFunc(name: string): GlobalFunction {\n return this.registeredFunctions[name];\n }\n\n /**\n * Sets the function with the specified name for later lookup.\n * @param name The name of the function.\n * @param func The function.\n */\n public static setFunc(name: string, func: GlobalFunction): void {\n this.registeredFunctions[name] = func;\n }\n\n /**\n * Gets the function invoker for the specified agent and function name.\n * If a function with the specified name exists on the agent object then it will\n * be returned, otherwise we will then check the registered functions for a match.\n * @param agent The agent instance that this behaviour tree is modelling behaviour for.\n * @param name The function name.\n * @returns The function invoker for the specified agent and function name.\n */\n static getFuncInvoker(agent: Agent, name: string): InvokerFunction | null {\n // Check whether the agent contains the specified function.\n const agentFunction = agent[name];\n if (agentFunction && typeof agentFunction === \"function\") {\n return (args: any[]) => agentFunction.apply(agent, args);\n }\n\n // The agent does not contain the specified function but it may have been registered at some point.\n if (this.registeredFunctions[name] && typeof this.registeredFunctions[name] === \"function\") {\n const registeredFunction = this.registeredFunctions[name];\n return (args: any[]) => registeredFunction(agent, ...args.map((arg) => arg.value));\n }\n\n // We have no function to invoke.\n return null;\n }\n\n /**\n * Gets all registered subtree root node definitions.\n */\n static getSubtrees(): { [key: string]: RootNodeDefinition } {\n return this.registeredSubtrees;\n }\n\n /**\n * Sets the subtree with the specified name for later lookup.\n * @param name The name of the subtree.\n * @param subtree The subtree.\n */\n static setSubtree(name: string, subtree: RootNodeDefinition) {\n this.registeredSubtrees[name] = subtree;\n }\n\n /**\n * Removes the registered function or subtree with the specified name.\n * @param name The name of the registered function or subtree.\n */\n static remove(name: string) {\n delete this.registeredFunctions[name];\n delete this.registeredSubtrees[name];\n }\n\n /**\n * Remove all registered functions and subtrees.\n */\n static empty() {\n this.registeredFunctions = {};\n this.registeredSubtrees = {};\n }\n}\n", "import Node from \"../../nodes/Node\";\n\n/**\n * An exception thrown when evaluating node guard path conditions and a conditions fails.\n */\nexport default class GuardUnsatisifedException extends Error {\n /**\n * @param source The node at which a guard condition failed.\n */\n constructor(private source: Node) {\n super(\"A guard path condition has failed\");\n }\n\n /**\n * Gets whether the specified node is the node at which a guard condition failed.\n * @param node The node to check against the source node.\n * @returns Whether the specified node is the node at which a guard condition failed.\n */\n isSourceNode = (node: Node) => node === this.source;\n}\n", "import { Agent } from \"../../Agent\";\nimport Guard from \"./Guard\";\nimport Node from \"../../nodes/Node\";\nimport GuardUnsatisifedException from \"./GuardUnsatisifedException\";\n\nexport type GuardPathPart = {\n node: Node;\n guards: Guard[];\n};\n\n/**\n * Represents a path of node guards along a root-to-leaf tree path.\n */\nexport default class GuardPath {\n /**\n * @param nodes An array of objects defining a node instance -> guard link, ordered by node depth.\n */\n constructor(private nodes: GuardPathPart[]) {}\n\n /**\n * Evaluate guard conditions for all guards in the tree path, moving outwards from the root.\n * @param agent The agent, required for guard evaluation.\n * @returns An evaluation results object.\n */\n evaluate = (agent: Agent) => {\n // We need to evaluate guard conditions for nodes up the tree, moving outwards from the root.\n for (const details of this.nodes) {\n // There can be multiple guards per node.\n for (const guard of details.guards) {\n // Check whether the guard condition passes, and throw an exception if not.\n if (!guard.isSatisfied(agent)) {\n throw new GuardUnsatisifedException(details.node);\n }\n }\n }\n };\n}\n", "import { BehaviourTreeOptions } from \"../BehaviourTreeOptions\";\nimport State, { AnyState } from \"../State\";\nimport { Agent } from \"../Agent\";\nimport Leaf from \"./leaf/Leaf\";\nimport Attribute from \"../attributes/Attribute\";\nimport Entry from \"../attributes/callbacks/Entry\";\nimport Exit from \"../attributes/callbacks/Exit\";\nimport Step from \"../attributes/callbacks/Step\";\nimport Guard from \"../attributes/guards/Guard\";\nimport GuardPath from \"../attributes/guards/GuardPath\";\nimport GuardUnsatisifedException from \"../attributes/guards/GuardUnsatisifedException\";\n\n/**\n * A base node.\n */\nexport default abstract class Node {\n /**\n * The node uid.\n */\n private readonly uid: string = createNodeUid();\n /**\n * The node state.\n */\n private state: AnyState = State.READY;\n /**\n * The guard path to evaluate as part of a node update.\n */\n private guardPath: GuardPath | undefined;\n\n /**\n * @param type The node type.\n * @param attributes The node attributes.\n * @param args The node argument definitions.\n */\n constructor(private type: string, private attributes: Attribute[], private args: any[]) {}\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected abstract onUpdate(agent: Agent, options: BehaviourTreeOptions): void;\n\n /**\n * Gets the name of the node.\n */\n public abstract getName(): string;\n\n /**\n * Gets whether this node is a leaf node.\n */\n public abstract isLeafNode: () => this is Leaf;\n\n /**\n * Gets/Sets the state of the node.\n */\n getState = (): AnyState => this.state;\n setState = (value: AnyState): void => {\n this.state = value;\n };\n\n /**\n * Gets the unique id of the node.\n */\n getUid = () => this.uid;\n\n /**\n * Gets the type of the node.\n */\n getType = () => this.type;\n\n /**\n * Gets the node attributes.\n */\n getAttributes = () => this.attributes;\n\n /**\n * Gets the node arguments.\n */\n getArguments = () => this.args;\n\n /**\n * Gets the node attribute with the specified type, or null if it does not exist.\n */\n getAttribute(type: \"entry\" | \"ENTRY\"): Entry;\n getAttribute(type: \"exit\" | \"EXIT\"): Exit;\n getAttribute(type: \"step\" | \"STEP\"): Step;\n getAttribute(type: string): Attribute {\n return (\n this.getAttributes().filter((decorator) => decorator.type.toUpperCase() === type.toUpperCase())[0] || null\n );\n }\n\n /**\n * Gets the node attributes.\n */\n getGuardAttributes = (): Guard[] => this.getAttributes().filter((decorator) => decorator.isGuard()) as Guard[];\n\n /**\n * Sets the guard path to evaluate as part of a node update.\n */\n setGuardPath = (value: GuardPath) => (this.guardPath = value);\n\n /**\n * Gets whether a guard path is assigned to this node.\n */\n hasGuardPath = () => !!this.guardPath;\n\n /**\n * Gets whether this node is in the specified state.\n * @param value The value to compare to the node state.\n */\n public is(value: AnyState): boolean {\n return this.state === value;\n }\n\n /**\n * Reset the state of the node.\n */\n public reset(): void {\n this.setState(State.READY);\n }\n\n /**\n * Abort the running of this node.\n * @param agent The agent.\n */\n public abort(agent: Agent): void {\n // There is nothing to do if this node is not in the running state.\n if (!this.is(State.RUNNING)) {\n return;\n }\n\n // Reset the state of this node.\n this.reset();\n\n this.getAttribute(\"exit\")?.callAgentFunction(agent, false, true);\n }\n\n /**\n * Update the node.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n * @returns The result of the update.\n */\n public update(agent: Agent, options: BehaviourTreeOptions): void {\n // If this node is already in a 'SUCCEEDED' or 'FAILED' state then there is nothing to do.\n if (this.is(State.SUCCEEDED) || this.is(State.FAILED)) {\n return;\n }\n\n try {\n // Evaluate all of the guard path conditions for the current tree path.\n this.guardPath!.evaluate(agent);\n\n // If this node is in the READY state then call the ENTRY for this node if it exists.\n if (this.is(State.READY)) {\n this.getAttribute(\"entry\")?.callAgentFunction(agent);\n }\n\n this.getAttribute(\"step\")?.callAgentFunction(agent);\n\n // Do the actual update.\n this.onUpdate(agent, options);\n\n // If this node is now in a 'SUCCEEDED' or 'FAILED' state then call the EXIT for this node if it exists.\n if (this.is(State.SUCCEEDED) || this.is(State.FAILED)) {\n this.getAttribute(\"exit\")?.callAgentFunction(agent, this.is(State.SUCCEEDED), false);\n }\n } catch (error) {\n // If the error is a GuardUnsatisfiedException then we need to determine if this node is the source.\n if (error instanceof GuardUnsatisifedException && error.isSourceNode(this)) {\n // Abort the current node.\n this.abort(agent);\n\n // Any node that is the source of an abort will be a failed node.\n this.setState(State.FAILED);\n } else {\n throw error;\n }\n }\n }\n}\n\n/**\n * Create a randomly generated node uid.\n * @returns A randomly generated node uid.\n */\nfunction createNodeUid(): string {\n var S4 = function () {\n return (((1 + Math.random()) * 0x10000) | 0).toString(16).substring(1);\n };\n return S4() + S4() + \"-\" + S4() + \"-\" + S4() + \"-\" + S4() + \"-\" + S4() + S4() + S4();\n}\n", "import Node from \"../Node\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\n\n/**\n * A composite node that wraps child nodes.\n */\nexport default abstract class Composite extends Node {\n /**\n * @param type The node type.\n * @param attributes The node attributes.\n * @param children The child nodes.\n */\n constructor(type: string, attributes: Attribute[], protected children: Node[]) {\n super(type, attributes, []);\n }\n\n /**\n * Gets whether this node is a leaf node.\n */\n isLeafNode = () => false;\n\n /**\n * Gets the children of this node.\n */\n getChildren = () => this.children;\n\n /**\n * Reset the state of the node.\n */\n reset = () => {\n // Reset the state of this node.\n this.setState(State.READY);\n\n // Reset the state of any child nodes.\n this.getChildren().forEach((child) => child.reset());\n };\n\n /**\n * Abort the running of this node.\n * @param agent The agent.\n */\n abort = (agent: Agent) => {\n // There is nothing to do if this node is not in the running state.\n if (!this.is(State.RUNNING)) {\n return;\n }\n\n // Abort any child nodes.\n this.getChildren().forEach((child) => child.abort(agent));\n\n // Reset the state of this node.\n this.reset();\n\n this.getAttribute(\"exit\")?.callAgentFunction(agent, false, true);\n };\n}\n", "import Composite from \"./Composite\";\nimport State from \"../../State\";\nimport Node from \"../Node\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A PARALLEL node.\n * The child nodes are executed concurrently until one fails or all succeed.\n */\nexport default class Parallel extends Composite {\n /**\n * @param attributes The node attributes.\n * @param children The child nodes.\n */\n constructor(attributes: Attribute[], children: Node[]) {\n super(\"parallel\", attributes, children);\n }\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // Keep a count of the number of succeeded child nodes.\n let succeededCount = 0;\n\n let hasChildFailed = false;\n\n // Iterate over all of the children of this node.\n for (const child of this.children) {\n // If the child has never been updated or is running then we will need to update it now.\n if (child.getState() === State.READY || child.getState() === State.RUNNING) {\n // Update the child of this node.\n child.update(agent, options);\n }\n\n // If the current child has a state of 'SUCCEEDED' then we should move on to the next child.\n if (child.getState() === State.SUCCEEDED) {\n // The child node has succeeded, keep track of this to determine if all children have.\n succeededCount++;\n\n // The child node succeeded, but we have not finished checking every child node yet.\n continue;\n }\n\n // If the current child has a state of 'FAILED' then this node is also a 'FAILED' node.\n if (child.getState() === State.FAILED) {\n hasChildFailed = true;\n\n // There is no need to check the rest of the children.\n break;\n }\n\n // The node should be in the 'RUNNING' state.\n if (child.getState() !== State.RUNNING) {\n // The child node was not in an expected state.\n throw new Error(\"child node was not in an expected state.\");\n }\n }\n\n if (hasChildFailed) {\n // This node is a 'FAILED' node.\n this.setState(State.FAILED);\n\n // Abort every running child.\n for (const child of this.children) {\n if (child.getState() === State.RUNNING) {\n child.abort(agent);\n }\n }\n } else {\n // If all children have succeeded then this node has also succeeded, otherwise it is still running.\n this.setState(succeededCount === this.children.length ? State.SUCCEEDED : State.RUNNING);\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => \"PARALLEL\";\n}\n", "import Composite from \"./Composite\";\nimport Node from \"../Node\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A SELECTOR node.\n * The child nodes are executed in sequence until one succeeds or all fail.\n */\nexport default class Selector extends Composite {\n /**\n * @param attributes The node attributes.\n * @param children The child nodes.\n */\n constructor(attributes: Attribute[], protected children: Node[]) {\n super(\"selector\", attributes, children);\n }\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // Iterate over all of the children of this node.\n for (const child of this.children) {\n // If the child has never been updated or is running then we will need to update it now.\n if (child.getState() === State.READY || child.getState() === State.RUNNING) {\n // Update the child of this node.\n child.update(agent, options);\n }\n\n // If the current child has a state of 'SUCCEEDED' then this node is also a 'SUCCEEDED' node.\n if (child.getState() === State.SUCCEEDED) {\n // This node is a 'SUCCEEDED' node.\n this.setState(State.SUCCEEDED);\n\n // There is no need to check the rest of the selector nodes.\n return;\n }\n\n // If the current child has a state of 'FAILED' then we should move on to the next child.\n if (child.getState() === State.FAILED) {\n // Find out if the current child is the last one in the selector.\n // If it is then this sequence node has also failed.\n if (this.children.indexOf(child) === this.children.length - 1) {\n // This node is a 'FAILED' node.\n this.setState(State.FAILED);\n\n // There is no need to check the rest of the selector as we have completed it.\n return;\n } else {\n // The child node failed, try the next one.\n continue;\n }\n }\n\n // The node should be in the 'RUNNING' state.\n if (child.getState() === State.RUNNING) {\n // This node is a 'RUNNING' node.\n this.setState(State.RUNNING);\n\n // There is no need to check the rest of the selector as the current child is still running.\n return;\n }\n\n // The child node was not in an expected state.\n throw new Error(\"child node was not in an expected state.\");\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => \"SELECTOR\";\n}\n", "import Composite from \"./Composite\";\nimport Node from \"../Node\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A SEQUENCE node.\n * The child nodes are executed in sequence until one fails or all succeed.\n */\nexport default class Sequence extends Composite {\n /**\n * @param attributes The node attributes.\n * @param children The child nodes.\n */\n constructor(attributes: Attribute[], protected children: Node[]) {\n super(\"sequence\", attributes, children);\n }\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // Iterate over all of the children of this node.\n for (const child of this.children) {\n // If the child has never been updated or is running then we will need to update it now.\n if (child.getState() === State.READY || child.getState() === State.RUNNING) {\n // Update the child of this node.\n child.update(agent, options);\n }\n\n // If the current child has a state of 'SUCCEEDED' then we should move on to the next child.\n if (child.getState() === State.SUCCEEDED) {\n // Find out if the current child is the last one in the sequence.\n // If it is then this sequence node has also succeeded.\n if (this.children.indexOf(child) === this.children.length - 1) {\n // This node is a 'SUCCEEDED' node.\n this.setState(State.SUCCEEDED);\n\n // There is no need to check the rest of the sequence as we have completed it.\n return;\n } else {\n // The child node succeeded, but we have not finished the sequence yet.\n continue;\n }\n }\n\n // If the current child has a state of 'FAILED' then this node is also a 'FAILED' node.\n if (child.getState() === State.FAILED) {\n // This node is a 'FAILED' node.\n this.setState(State.FAILED);\n\n // There is no need to check the rest of the sequence.\n return;\n }\n\n // The node should be in the 'RUNNING' state.\n if (child.getState() === State.RUNNING) {\n // This node is a 'RUNNING' node.\n this.setState(State.RUNNING);\n\n // There is no need to check the rest of the sequence as the current child is still running.\n return;\n }\n\n // The child node was not in an expected state.\n throw new Error(\"child node was not in an expected state.\");\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => \"SEQUENCE\";\n}\n", "import createLotto from \"lotto-draw\";\n\nimport Node from \"../Node\";\nimport Composite from \"./Composite\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A LOTTO node.\n * A winning child is picked on the initial update of this node, based on ticket weighting.\n * The state of this node will match the state of the winning child.\n */\nexport default class Lotto extends Composite {\n /**\n * @param attributes The node attributes.\n * @param weights The child node weights.\n * @param children The child nodes.\n */\n constructor(attributes: Attribute[], private weights: number[] | undefined, children: Node[]) {\n super(\"lotto\", attributes, children);\n }\n\n /**\n * The child node selected to be the active one.\n */\n private selectedChild: Node | undefined;\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // If this node is in the READY state then we need to pick a winning child node.\n if (this.is(State.READY)) {\n // Create a lotto draw with which to randomly pick a child node to become the active one.\n const lottoDraw = createLotto({\n // Hook up the optional 'random' behaviour tree function option to the one used by 'lotto-draw'.\n random: options.random,\n // Pass in each child node as a participant in the lotto draw with their respective ticket count.\n participants: this.children.map((child, index) => [child, this.weights?.[index] || 1])\n });\n\n // Randomly pick a child based on ticket weighting, this will become the active child for this composite node.\n this.selectedChild = lottoDraw.draw() || undefined;\n }\n\n // If something went wrong and we don't have an active child then we should throw an error.\n if (!this.selectedChild) {\n throw new Error(\"failed to update lotto node as it has no active child\");\n }\n\n // If the selected child has never been updated or is running then we will need to update it now.\n if (this.selectedChild.getState() === State.READY || this.selectedChild.getState() === State.RUNNING) {\n this.selectedChild.update(agent, options);\n }\n\n // The state of the lotto node is the state of its selected child.\n this.setState(this.selectedChild.getState());\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => (this.weights ? `LOTTO [${this.weights.join(\",\")}]` : \"LOTTO\");\n}\n", "import Node from \"../Node\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\n\n/**\n * A decorator node that wraps a single child node.\n */\nexport default abstract class Decorator extends Node {\n /**\n * @param type The node type.\n * @param attributes The node attributes.\n * @param child The child node.\n */\n constructor(type: string, attributes: Attribute[], protected child: Node) {\n super(type, attributes, []);\n }\n\n /**\n * Gets whether this node is a leaf node.\n */\n isLeafNode = () => false;\n\n /**\n * Gets the children of this node.\n */\n getChildren = () => [this.child];\n\n /**\n * Reset the state of the node.\n */\n reset = () => {\n // Reset the state of this node.\n this.setState(State.READY);\n\n // Reset the state of the child node.\n this.child.reset();\n };\n\n /**\n * Abort the running of this node.\n * @param agent The agent.\n */\n abort = (agent: Agent) => {\n // There is nothing to do if this node is not in the running state.\n if (!this.is(State.RUNNING)) {\n return;\n }\n\n // Abort the child node.\n this.child.abort(agent);\n\n // Reset the state of this node.\n this.reset();\n\n this.getAttribute(\"exit\")?.callAgentFunction(agent, false, true);\n };\n}\n", "import Node from \"../Node\";\nimport Decorator from \"./Decorator\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A Fail node.\n * This node wraps a single child and will always move to the 'FAILED' state when the child moves to a 'SUCCEEDED' or 'FAILED' state.\n */\nexport default class Fail extends Decorator {\n /**\n * @param attributes The node attributes.\n * @param child The child node.\n */\n constructor(attributes: Attribute[], child: Node) {\n super(\"fail\", attributes, child);\n }\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // If the child has never been updated or is running then we will need to update it now.\n if (this.child.getState() === State.READY || this.child.getState() === State.RUNNING) {\n this.child.update(agent, options);\n }\n\n // The state of this node will depend in the state of its child.\n switch (this.child.getState()) {\n case State.RUNNING:\n this.setState(State.RUNNING);\n break;\n\n case State.SUCCEEDED:\n case State.FAILED:\n this.setState(State.FAILED);\n break;\n\n default:\n this.setState(State.READY);\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => \"FAIL\";\n}\n", "import Decorator from \"./Decorator\";\nimport State from \"../../State\";\nimport Node from \"../Node\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A Flip node.\n * This node wraps a single child and will flip the state of the child state.\n */\nexport default class Flip extends Decorator {\n /**\n * @param attributes The node attributes.\n * @param child The child node.\n */\n constructor(attributes: Attribute[], child: Node) {\n super(\"flip\", attributes, child);\n }\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // If the child has never been updated or is running then we will need to update it now.\n if (this.child.getState() === State.READY || this.child.getState() === State.RUNNING) {\n this.child.update(agent, options);\n }\n\n // The state of this node will depend in the state of its child.\n switch (this.child.getState()) {\n case State.RUNNING:\n this.setState(State.RUNNING);\n break;\n\n case State.SUCCEEDED:\n this.setState(State.FAILED);\n break;\n\n case State.FAILED:\n this.setState(State.SUCCEEDED);\n break;\n\n default:\n this.setState(State.READY);\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => \"FLIP\";\n}\n", "import Node from \"../Node\";\nimport Decorator from \"./Decorator\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A REPEAT node.\n * The node has a single child which can have:\n * -- A number of iterations for which to repeat the child node.\n * -- An infinite repeat loop if neither an iteration count or a condition function is defined.\n * The REPEAT node will stop and have a 'FAILED' state if its child is ever in a 'FAILED' state after an update.\n * The REPEAT node will attempt to move on to the next iteration if its child is ever in a 'SUCCEEDED' state.\n */\nexport default class Repeat extends Decorator {\n /**\n * @param attributes The node attributes.\n * @param iterations The number of iterations to repeat the child node.\n * @param iterationsMin The minimum possible number of iterations to repeat the child node.\n * @param iterationsMax The maximum possible number of iterations to repeat the child node.\n * @param child The child node.\n */\n constructor(\n attributes: Attribute[],\n private iterations: number | null,\n private iterationsMin: number | null,\n private iterationsMax: number | null,\n child: Node\n ) {\n super(\"repeat\", attributes, child);\n }\n\n /**\n * The number of target iterations to make.\n */\n private targetIterationCount: number | null = null;\n\n /**\n * The current iteration count.\n */\n private currentIterationCount: number = 0;\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // If this node is in the READY state then we need to reset the child and the target iteration count.\n if (this.is(State.READY)) {\n // Reset the child node.\n this.child.reset();\n\n // Reset the current iteration count.\n this.currentIterationCount = 0;\n\n // Set the target iteration count.\n this.setTargetIterationCount(options);\n }\n\n // Do a check to see if we can iterate. If we can then this node will move into the 'RUNNING' state.\n // If we cannot iterate then we have hit our target iteration count, which means that the node has succeeded.\n if (this.canIterate()) {\n // This node is in the running state and can do its initial iteration.\n this.setState(State.RUNNING);\n\n // We may have already completed an iteration, meaning that the child node will be in the SUCCEEDED state.\n // If this is the case then we will have to reset the child node now.\n if (this.child.getState() === State.SUCCEEDED) {\n this.child.reset();\n }\n\n // Update the child of this node.\n this.child.update(agent, options);\n\n // If the child moved into the FAILED state when we updated it then there is nothing left to do and this node has also failed.\n // If it has moved into the SUCCEEDED state then we have completed the current iteration.\n if (this.child.getState() === State.FAILED) {\n // The child has failed, meaning that this node has failed.\n this.setState(State.FAILED);\n\n return;\n } else if (this.child.getState() === State.SUCCEEDED) {\n // We have completed an iteration.\n this.currentIterationCount += 1;\n }\n } else {\n // This node is in the 'SUCCEEDED' state as we cannot iterate any more.\n this.setState(State.SUCCEEDED);\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => {\n if (this.iterations !== null) {\n return `REPEAT ${this.iterations}x`;\n } else if (this.iterationsMin !== null && this.iterationsMax !== null) {\n return `REPEAT ${this.iterationsMin}x-${this.iterationsMax}x`;\n } else {\n return \"REPEAT\";\n }\n };\n\n /**\n * Reset the state of the node.\n */\n reset = () => {\n // Reset the state of this node.\n this.setState(State.READY);\n\n // Reset the current iteration count.\n this.currentIterationCount = 0;\n\n // Reset the child node.\n this.child.reset();\n };\n\n /**\n * Gets whether an iteration can be made.\n * @returns Whether an iteration can be made.\n */\n private canIterate = () => {\n if (this.targetIterationCount !== null) {\n // We can iterate as long as we have not reached our target iteration count.\n return this.currentIterationCount < this.targetIterationCount;\n }\n\n // If neither an iteration count or a condition function were defined then we can iterate indefinitely.\n return true;\n };\n\n /**\n * Sets the target iteration count.\n * @param options The behaviour tree options object.\n */\n private setTargetIterationCount = (options: BehaviourTreeOptions) => {\n // Are we dealing with an explicit iteration count or will we be randomly picking a iteration count between the min and max iteration count.\n if (this.iterations !== null) {\n this.targetIterationCount = this.iterations;\n } else if (this.iterationsMin !== null && this.iterationsMax !== null) {\n // We will be picking a random iteration count between a min and max iteration count, if the optional 'random'\n // behaviour tree function option is defined then we will be using that, otherwise we will fall back to using Math.random.\n const random = typeof options.random === \"function\" ? options.random : Math.random;\n\n // Pick a random iteration count between a min and max iteration count.\n this.targetIterationCount = Math.floor(\n random() * (this.iterationsMax - this.iterationsMin + 1) + this.iterationsMin\n );\n } else {\n this.targetIterationCount = null;\n }\n };\n}\n", "import Node from \"../Node\";\nimport Decorator from \"./Decorator\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A RETRY node.\n * The node has a single child which can have:\n * -- A number of iterations for which to repeat the child node.\n * -- An infinite repeat loop if neither an iteration count or a condition function is defined.\n * The RETRY node will stop and have a 'SUCCEEDED' state if its child is ever in a 'SUCCEEDED' state after an update.\n * The RETRY node will attempt to move on to the next iteration if its child is ever in a 'FAILED' state.\n */\nexport default class Retry extends Decorator {\n /**\n * @param attributes The node attributes.\n * @param attempts The number of attempts to retry the child node.\n * @param attemptsMin The minimum possible number of attempts to retry the child node.\n * @param attemptsMax The maximum possible number of attempts to retry the child node.\n * @param child The child node.\n */\n constructor(\n attributes: Attribute[],\n private attempts: number | null,\n private attemptsMin: number | null,\n private attemptsMax: number | null,\n child: Node\n ) {\n super(\"retry\", attributes, child);\n }\n\n /**\n * The number of target attempts to make.\n */\n private targetAttemptCount: number | null = null;\n\n /**\n * The current attempt count.\n */\n private currentAttemptCount: number = 0;\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // If this node is in the READY state then we need to reset the child and the target attempt count.\n if (this.is(State.READY)) {\n // Reset the child node.\n this.child.reset();\n\n // Reset the current attempt count.\n this.currentAttemptCount = 0;\n\n // Set the target attempt count.\n this.setTargetAttemptCount(options);\n }\n\n // Do a check to see if we can attempt. If we can then this node will move into the 'RUNNING' state.\n // If we cannot attempt then we have hit our target attempt count, which means that the node has succeeded.\n if (this.canAttempt()) {\n // This node is in the running state and can do its initial attempt.\n this.setState(State.RUNNING);\n\n // We may have already completed an attempt, meaning that the child node will be in the FAILED state.\n // If this is the case then we will have to reset the child node now.\n if (this.child.getState() === State.FAILED) {\n this.child.reset();\n }\n\n // Update the child of this node.\n this.child.update(agent, options);\n\n // If the child moved into the SUCCEEDED state when we updated it then there is nothing left to do and this node has also succeeded.\n // If it has moved into the FAILED state then we have completed the current attempt.\n if (this.child.getState() === State.SUCCEEDED) {\n // The child has succeeded, meaning that this node has succeeded.\n this.setState(State.SUCCEEDED);\n\n return;\n } else if (this.child.getState() === State.FAILED) {\n // We have completed an attempt.\n this.currentAttemptCount += 1;\n }\n } else {\n // This node is in the 'FAILED' state as we cannot iterate any more.\n this.setState(State.FAILED);\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => {\n if (this.attempts !== null) {\n return `RETRY ${this.attempts}x`;\n } else if (this.attemptsMin !== null && this.attemptsMax !== null) {\n return `RETRY ${this.attemptsMin}x-${this.attemptsMax}x`;\n } else {\n return \"RETRY\";\n }\n };\n\n /**\n * Reset the state of the node.\n */\n reset = () => {\n // Reset the state of this node.\n this.setState(State.READY);\n\n // Reset the current attempt count.\n this.currentAttemptCount = 0;\n\n // Reset the child node.\n this.child.reset();\n };\n\n /**\n * Gets whether an attempt can be made.\n * @returns Whether an attempt can be made.\n */\n canAttempt = () => {\n if (this.targetAttemptCount !== null) {\n // We can attempt as long as we have not reached our target attempt count.\n return this.currentAttemptCount < this.targetAttemptCount;\n }\n\n // If neither an attempt count or a condition function were defined then we can attempt indefinitely.\n return true;\n };\n\n /**\n * Sets the target attempt count.\n * @param options The behaviour tree options object.\n */\n setTargetAttemptCount = (options: BehaviourTreeOptions) => {\n // Are we dealing with an explicit attempt count or will we be randomly picking an attempt count between the min and max attempt count.\n if (this.attempts !== null) {\n this.targetAttemptCount = this.attempts;\n } else if (this.attemptsMin !== null && this.attemptsMax !== null) {\n // We will be picking a random attempt count between a min and max attempt count, if the optional 'random'\n // behaviour tree function option is defined then we will be using that, otherwise we will fall back to using Math.random.\n const random = typeof options.random === \"function\" ? options.random : Math.random;\n\n // Pick a random attempt count between a min and max attempt count.\n this.targetAttemptCount = Math.floor(\n random() * (this.attemptsMax - this.attemptsMin + 1) + this.attemptsMin\n );\n } else {\n this.targetAttemptCount = null;\n }\n };\n}\n", "import Node from \"../Node\";\nimport Decorator from \"./Decorator\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A Root node.\n * The root node will have a single child.\n */\nexport default class Root extends Decorator {\n /**\n * @param attributes The node attributes.\n * @param child The child node.\n */\n constructor(attributes: Attribute[], child: Node) {\n super(\"root\", attributes, child);\n }\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // If the child has never been updated or is running then we will need to update it now.\n if (this.child.getState() === State.READY || this.child.getState() === State.RUNNING) {\n // Update the child of this node.\n this.child.update(agent, options);\n }\n\n // The state of the root node is the state of its child.\n this.setState(this.child.getState());\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => \"ROOT\";\n}\n", "import Node from \"../Node\";\nimport Decorator from \"./Decorator\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A Succeed node.\n * This node wraps a single child and will always move to the 'SUCCEEDED' state when the child moves to a 'SUCCEEDED' or 'FAILED' state.\n */\nexport default class Succeed extends Decorator {\n /**\n * @param attributes The node attributes.\n * @param child The child node.\n */\n constructor(attributes: Attribute[], child: Node) {\n super(\"succeed\", attributes, child);\n }\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // If the child has never been updated or is running then we will need to update it now.\n if (this.child.getState() === State.READY || this.child.getState() === State.RUNNING) {\n this.child.update(agent, options);\n }\n\n // The state of this node will depend in the state of its child.\n switch (this.child.getState()) {\n case State.RUNNING:\n this.setState(State.RUNNING);\n break;\n\n case State.SUCCEEDED:\n case State.FAILED:\n this.setState(State.SUCCEEDED);\n break;\n\n default:\n this.setState(State.READY);\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => \"SUCCEED\";\n}\n", "import Node from \"../Node\";\n\n/**\n * A leaf node.\n */\nexport default abstract class Leaf extends Node {\n /**\n * Gets whether this node is a leaf node.\n */\n isLeafNode = () => true;\n}\n", "import { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\nimport State, { CompleteState } from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Leaf from \"./Leaf\";\nimport Lookup from \"../../Lookup\";\nimport Attribute from \"../../attributes/Attribute\";\n\n/**\n * The type representing a resolved/rejected update promise.\n */\ntype UpdatePromiseResult = {\n /**\n * Whether the promise was resolved rather than rejected.\n */\n isResolved: boolean;\n\n /**\n * The promise resolved value or rejection reason.\n */\n value: any;\n};\n\n/**\n * An Action leaf node.\n * This represents an immediate or ongoing state of behaviour.\n */\nexport default class Action extends Leaf {\n /**\n * @param attributes The node attributes.\n * @param actionName The action name.\n * @param actionArguments The array of action argument definitions.\n */\n constructor(attributes: Attribute[], private actionName: string, private actionArguments: any[]) {\n super(\"action\", attributes, actionArguments);\n }\n\n /**\n * Whether there is a pending update promise.\n */\n private isUsingUpdatePromise = false;\n\n /**\n * The finished state result of an update promise.\n */\n private updatePromiseResult: UpdatePromiseResult | null = null;\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // If the result of this action depends on an update promise then there is nothing to do until it settles.\n if (this.isUsingUpdatePromise) {\n // Are we still waiting for our update promise to settle?\n if (!this.updatePromiseResult) {\n return;\n }\n\n const { isResolved, value } = this.updatePromiseResult;\n\n // Our update promise settled, was it resolved or rejected?\n if (isResolved) {\n // Our promise resolved so check to make sure the result is a valid finished state.\n if (value !== State.SUCCEEDED && value !== State.FAILED) {\n throw new Error(\n \"action node promise resolved with an invalid value, expected a State.SUCCEEDED or State.FAILED value to be returned\"\n );\n }\n\n // Set the state of this node to match the state returned by the promise.\n this.setState(value);\n\n return;\n } else {\n // The promise was rejected, which isn't great.\n throw new Error(`action function '${this.actionName}' promise rejected with '${value}'`);\n }\n }\n\n // Attempt to get the invoker for the action function.\n const actionFuncInvoker = Lookup.getFuncInvoker(agent, this.actionName);\n\n // The action function should be defined.\n if (actionFuncInvoker === null) {\n throw new Error(\n `cannot update action node as the action '${this.actionName}' function is not defined on the agent and has not been registered`\n );\n }\n\n let actionFunctionResult;\n\n try {\n // Call the action function, the result of which may be:\n // - The finished state of this action node.\n // - A promise to return a finished node state.\n // - Undefined if the node should remain in the running state.\n actionFunctionResult = actionFuncInvoker(this.actionArguments) as CompleteState | Promise;\n } catch (error) {\n // An uncaught error was thrown.\n if (error instanceof Error) {\n throw new Error(`action function '${this.actionName}' threw: ${error.stack}`);\n } else {\n throw new Error(`action function '${this.actionName}' threw: ${error}`);\n }\n }\n\n if (actionFunctionResult instanceof Promise) {\n actionFunctionResult.then(\n (result) => {\n // If 'isUpdatePromisePending' is not set then the promise was cleared as it was resolving, probably via an abort of reset.\n if (!this.isUsingUpdatePromise) {\n return;\n }\n\n // Set the resolved update promise result so that it can be handled on the next update of this node.\n this.updatePromiseResult = {\n isResolved: true,\n value: result\n };\n },\n (reason) => {\n // If 'isUpdatePromisePending' is not set then the promise was cleared as it was resolving, probably via an abort or reset.\n if (!this.isUsingUpdatePromise) {\n return;\n }\n\n // Set the rejected update promise result so that it can be handled on the next update of this node.\n this.updatePromiseResult = {\n isResolved: false,\n value: reason\n };\n }\n );\n\n // This node will be in the 'RUNNING' state until the update promise resolves.\n this.setState(State.RUNNING);\n\n // We are now waiting for the promise returned by the use to resolve before we know what state this node is in.\n this.isUsingUpdatePromise = true;\n } else {\n // Validate the returned value.\n this.validateUpdateResult(actionFunctionResult);\n\n // Set the state of this node, this may be undefined, which just means that the node is still in the 'RUNNING' state.\n this.setState(actionFunctionResult || State.RUNNING);\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => this.actionName;\n\n /**\n * Reset the state of the node.\n */\n reset = () => {\n // Reset the state of this node.\n this.setState(State.READY);\n\n // There is no longer an update promise that we care about.\n this.isUsingUpdatePromise = false;\n this.updatePromiseResult = null;\n };\n\n /**\n * Validate the result of an update function call.\n * @param result The result of an update function call.\n */\n private validateUpdateResult = (result: CompleteState | State.RUNNING) => {\n switch (result) {\n case State.SUCCEEDED:\n case State.FAILED:\n case State.RUNNING:\n case undefined:\n return;\n default:\n throw new Error(\n `expected action function '${this.actionName}' to return an optional State.SUCCEEDED or State.FAILED value but returned '${result}'`\n );\n }\n };\n}\n", "import { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Leaf from \"./Leaf\";\nimport Lookup from \"../../Lookup\";\nimport Attribute from \"../../attributes/Attribute\";\n\n/**\n * A Condition leaf node.\n * This will succeed or fail immediately based on an agent predicate, without moving to the 'RUNNING' state.\n */\nexport default class Condition extends Leaf {\n /**\n * @param attributes The node attributes.\n * @param conditionName The name of the condition function.\n * @param conditionArguments The array of condition argument definitions.\n */\n constructor(attributes: Attribute[], private conditionName: string, private conditionArguments: any[]) {\n super(\"condition\", attributes, conditionArguments);\n }\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // Attempt to get the invoker for the condition function.\n const conditionFuncInvoker = Lookup.getFuncInvoker(agent, this.conditionName);\n\n // The condition function should be defined.\n if (conditionFuncInvoker === null) {\n throw new Error(\n `cannot update condition node as the condition '${this.conditionName}' function is not defined on the agent and has not been registered`\n );\n }\n\n let conditionFunctionResult;\n\n try {\n // Call the condition function to determine the state of this node, the result of which should be a boolean.\n conditionFunctionResult = conditionFuncInvoker(this.conditionArguments);\n } catch (error) {\n // An uncaught error was thrown.\n if (error instanceof Error) {\n throw new Error(`condition function '${this.conditionName}' threw: ${error.stack}`);\n } else {\n throw new Error(`condition function '${this.conditionName}' threw: ${error}`);\n }\n }\n\n // The result of calling the condition function must be a boolean value.\n if (typeof conditionFunctionResult !== \"boolean\") {\n throw new Error(\n `expected condition function '${this.conditionName}' to return a boolean but returned '${conditionFunctionResult}'`\n );\n }\n\n // Set the state of this node based on the result of calling the condition function.\n this.setState(!!conditionFunctionResult ? State.SUCCEEDED : State.FAILED);\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => this.conditionName;\n}\n", "import Leaf from \"./Leaf\";\nimport State from \"../../State\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { Agent } from \"../../Agent\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A WAIT node.\n * The state of this node will change to SUCCEEDED after a duration of time\n */\nexport default class Wait extends Leaf {\n /**\n * @param attributes The node attributes.\n * @param duration The duration that this node will wait to succeed in milliseconds.\n * @param durationMin The minimum possible duration in milliseconds that this node will wait to succeed.\n * @param durationMax The maximum possible duration in milliseconds that this node will wait to succeed.\n */\n constructor(\n attributes: Attribute[],\n private duration: number | null,\n private durationMin: number | null,\n private durationMax: number | null\n ) {\n super(\"wait\", attributes, []);\n }\n\n /**\n * The time in milliseconds at which this node was first updated.\n */\n private initialUpdateTime: number = 0;\n\n /**\n * The total duration in milliseconds that this node will be waiting for.\n */\n private totalDuration: number | null = null;\n\n /**\n * The duration in milliseconds that this node has been waiting for.\n */\n private waitedDuration: number = 0;\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // If this node is in the READY state then we need to set the initial update time.\n if (this.is(State.READY)) {\n // Set the initial update time.\n this.initialUpdateTime = new Date().getTime();\n\n // Set the initial waited duration.\n this.waitedDuration = 0;\n\n // Are we dealing with an explicit duration or will we be randomly picking a duration between the min and max duration.\n if (this.duration !== null) {\n this.totalDuration = this.duration;\n } else if (this.durationMin !== null && this.durationMax !== null) {\n // We will be picking a random duration between a min and max duration, if the optional 'random' behaviour tree\n // function option is defined then we will be using that, otherwise we will fall back to using Math.random.\n const random = typeof options.random === \"function\" ? options.random : Math.random;\n\n // Pick a random duration between a min and max duration.\n this.totalDuration = Math.floor(\n random() * (this.durationMax - this.durationMin + 1) + this.durationMin\n );\n } else {\n this.totalDuration = null;\n }\n\n // The node is now running until we finish waiting.\n this.setState(State.RUNNING);\n }\n\n // If we have no total duration then this wait node will wait indefinitely until it is aborted.\n if (this.totalDuration === null) {\n return;\n }\n\n // If we have a 'getDeltaTime' function defined as part of our options then we will use it to figure out how long we have waited for.\n if (typeof options.getDeltaTime === \"function\") {\n // Get the delta time.\n const deltaTime = options.getDeltaTime();\n\n // Our delta time must be a valid number and cannot be NaN.\n if (typeof deltaTime !== \"number\" || isNaN(deltaTime)) {\n throw new Error(\"The delta time must be a valid number and not NaN.\");\n }\n\n // Update the amount of time that this node has been waiting for based on the delta time.\n this.waitedDuration += deltaTime * 1000;\n } else {\n // We are not using a delta time, so we will just work out hom much time has passed since the first update.\n this.waitedDuration = new Date().getTime() - this.initialUpdateTime;\n }\n\n // Have we waited long enough?\n if (this.waitedDuration >= this.totalDuration) {\n // We have finished waiting!\n this.setState(State.SUCCEEDED);\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => {\n if (this.duration !== null) {\n return `WAIT ${this.duration}ms`;\n } else if (this.durationMin !== null && this.durationMax !== null) {\n return `WAIT ${this.durationMin}ms-${this.durationMax}ms`;\n } else {\n return \"WAIT\";\n }\n };\n}\n", "import Guard from \"./guards/Guard\";\n\nexport type AttributeDetails = {\n /** The attribute type. */\n type: string;\n\n /** The attribute arguments. */\n args: any[];\n};\n\n/**\n * A base node attribute.\n */\nexport default abstract class Attribute {\n /**\n * @param type The node attribute type.\n * @param args The array of attribute arguments.\n */\n constructor(public type: string, public args: any[]) {}\n\n /**\n * Gets the attribute details.\n */\n abstract getDetails(): TAttributeDetails;\n\n /**\n * Gets whether this attribute is a guard.\n */\n abstract isGuard: () => this is Guard;\n}\n", "import { Agent } from \"../../Agent\";\nimport Attribute, { AttributeDetails } from \"../Attribute\";\n\nexport type GuardAttributeDetails = {\n /** The name of the condition function that determines whether the guard is satisfied. */\n condition: string;\n} & AttributeDetails;\n\n/**\n * A base node guard attribute.\n */\nexport default abstract class Guard extends Attribute {\n /**\n * @param type The node attribute type.\n * @param args The array of decorator argument definitions.\n * @param condition The name of the condition function that determines whether the guard is satisfied.\n */\n constructor(type: string, args: any[], private condition: string) {\n super(type, args);\n }\n\n /**\n * Gets the name of the condition function that determines whether the guard is satisfied.\n */\n getCondition = () => this.condition;\n\n /**\n * Gets whether this attribute is a guard.\n */\n isGuard = () => true;\n\n /**\n * Gets the attribute details.\n */\n getDetails(): GuardAttributeDetails {\n return {\n type: this.type,\n args: this.args,\n condition: this.getCondition()\n };\n }\n\n /**\n * Gets whether the guard is satisfied.\n * @param agent The agent.\n * @returns Whether the guard is satisfied.\n */\n abstract isSatisfied(agent: Agent): boolean;\n}\n", "import Guard from \"./Guard\";\nimport Lookup from \"../../Lookup\";\nimport { Agent } from \"../../Agent\";\n\n/**\n * A WHILE guard which is satisfied as long as the given condition remains true.\n */\nexport default class While extends Guard {\n /**\n * @param condition The name of the condition function that determines whether the guard is satisfied.\n * @param args The array of decorator argument definitions.\n */\n constructor(condition: string, args: any[]) {\n super(\"while\", args, condition);\n }\n\n /**\n * Gets whether the guard is satisfied.\n * @param agent The agent.\n * @returns Whether the guard is satisfied.\n */\n isSatisfied = (agent: Agent) => {\n // Attempt to get the invoker for the condition function.\n const conditionFuncInvoker = Lookup.getFuncInvoker(agent, this.getCondition());\n\n // The condition function should be defined.\n if (conditionFuncInvoker === null) {\n throw new Error(\n `cannot evaluate node guard as the condition '${this.getCondition()}' function is not defined on the agent and has not been registered`\n );\n }\n\n let conditionFunctionResult;\n\n try {\n // Call the guard condition function to determine the state of this node, the result of which should be a boolean.\n conditionFunctionResult = conditionFuncInvoker(this.args);\n } catch (error) {\n // An uncaught error was thrown.\n if (error instanceof Error) {\n throw new Error(`guard condition function '${this.getCondition()}' threw: ${error.stack}`);\n } else {\n throw new Error(`guard condition function '${this.getCondition()}' threw: ${error}`);\n }\n }\n\n // The result of calling the guard condition function must be a boolean value.\n if (typeof conditionFunctionResult !== \"boolean\") {\n throw new Error(\n `expected guard condition function '${this.getCondition()}' to return a boolean but returned '${conditionFunctionResult}'`\n );\n }\n\n // Return whether this guard is satisfied.\n return conditionFunctionResult;\n };\n}\n", "import Guard from \"./Guard\";\nimport Lookup from \"../../Lookup\";\nimport { Agent } from \"../../Agent\";\n\n/**\n * An UNTIL guard which is satisfied as long as the given condition remains false.\n */\nexport default class Until extends Guard {\n /**\n * @param condition The name of the condition function that determines whether the guard is satisfied.\n * @param args The array of decorator argument definitions.\n */\n constructor(condition: string, args: any[]) {\n super(\"until\", args, condition);\n }\n\n /**\n * Gets whether the guard is satisfied.\n * @param agent The agent.\n * @returns Whether the guard is satisfied.\n */\n isSatisfied = (agent: Agent) => {\n // Attempt to get the invoker for the condition function.\n const conditionFuncInvoker = Lookup.getFuncInvoker(agent, this.getCondition());\n\n // The condition function should be defined.\n if (conditionFuncInvoker === null) {\n throw new Error(\n `cannot evaluate node guard as the condition '${this.getCondition()}' function is not defined on the agent and has not been registered`\n );\n }\n\n let conditionFunctionResult;\n\n try {\n // Call the guard condition function to determine the state of this node, the result of which should be a boolean.\n conditionFunctionResult = conditionFuncInvoker(this.args);\n } catch (error) {\n // An uncaught error was thrown.\n if (error instanceof Error) {\n throw new Error(`guard condition function '${this.getCondition()}' threw: ${error.stack}`);\n } else {\n throw new Error(`guard condition function '${this.getCondition()}' threw: ${error}`);\n }\n }\n\n // The result of calling the guard condition function must be a boolean value.\n if (typeof conditionFunctionResult !== \"boolean\") {\n throw new Error(\n `expected guard condition function '${this.getCondition()}' to return a boolean but returned '${conditionFunctionResult}'`\n );\n }\n\n // Return whether this guard is satisfied.\n return !conditionFunctionResult;\n };\n}\n", "import { Agent } from \"../../Agent\";\nimport Attribute, { AttributeDetails } from \"../Attribute\";\n\nexport type CallbackAttributeDetails = {\n /** The name of the agent function that is called. */\n functionName: string;\n} & AttributeDetails;\n\n/**\n * A base node callback attribute.\n */\nexport default abstract class Callback extends Attribute {\n /**\n * @param type The node attribute type.\n * @param args The array of decorator argument definitions.\n * @param functionName The name of the agent function to call.\n */\n constructor(type: string, args: any[], private functionName: string) {\n super(type, args);\n }\n\n /**\n * Gets the name of the agent function to call.\n */\n getFunctionName = () => this.functionName;\n\n /**\n * Gets whether this attribute is a guard.\n */\n isGuard = () => false;\n\n /**\n * Gets the attribute details.\n */\n getDetails(): CallbackAttributeDetails {\n return {\n type: this.type,\n args: this.args,\n functionName: this.getFunctionName()\n };\n }\n\n /**\n * Attempt to call the agent function that this callback refers to.\n * @param agent The agent.\n */\n abstract callAgentFunction: (agent: Agent, isSuccess: boolean, isAborted: boolean) => void;\n}\n", "import Callback from \"./Callback\";\nimport Lookup from \"../../Lookup\";\nimport { Agent } from \"../../Agent\";\n\n/**\n * An ENTRY callback which defines an agent function to call when the associated node is updated and moves out of running state.\n */\nexport default class Entry extends Callback {\n /**\n * @param functionName The name of the agent function to call.\n * @param args The array of callback argument definitions.\n */\n constructor(functionName: string, args: any[]) {\n super(\"entry\", args, functionName);\n }\n\n /**\n * Attempt to call the agent function that this callback refers to.\n * @param agent The agent.\n */\n callAgentFunction = (agent: Agent) => {\n // Attempt to get the invoker for the callback function.\n const callbackFuncInvoker = Lookup.getFuncInvoker(agent, this.getFunctionName());\n\n // The callback function should be defined.\n if (callbackFuncInvoker === null) {\n throw new Error(\n `cannot call entry function '${this.getFunctionName()}' as is not defined on the agent and has not been registered`\n );\n }\n\n // Call the callback function.\n callbackFuncInvoker(this.args);\n };\n}\n", "import Callback from \"./Callback\";\nimport Lookup from \"../../Lookup\";\nimport { Agent } from \"../../Agent\";\n\n/**\n * A STEP callback which defines an agent function to call when the associated node is updated.\n */\nexport default class Step extends Callback {\n /**\n * @param functionName The name of the agent function to call.\n * @param args The array of callback argument definitions.\n */\n constructor(functionName: string, args: any[]) {\n super(\"step\", args, functionName);\n }\n\n /**\n * Attempt to call the agent function that this callback refers to.\n * @param agent The agent.\n */\n callAgentFunction = (agent: Agent) => {\n // Attempt to get the invoker for the callback function.\n const callbackFuncInvoker = Lookup.getFuncInvoker(agent, this.getFunctionName());\n\n // The callback function should be defined.\n if (callbackFuncInvoker === null) {\n throw new Error(\n `cannot call step function '${this.getFunctionName()}' as is not defined on the agent and has not been registered`\n );\n }\n\n // Call the callback function.\n callbackFuncInvoker(this.args);\n };\n}\n", "import Callback from \"./Callback\";\nimport Lookup from \"../../Lookup\";\nimport { Agent } from \"../../Agent\";\n\n/**\n * An EXIT callback which defines an agent function to call when the associated node is updated and moves to a finished state or is aborted.\n */\nexport default class Exit extends Callback {\n /**\n * @param functionName The name of the agent function to call.\n * @param args The array of callback argument definitions.\n */\n constructor(functionName: string, args: any[]) {\n super(\"exit\", args, functionName);\n }\n\n /**\n * Attempt to call the agent function that this callback refers to.\n * @param agent The agent.\n * @param isSuccess Whether the decorated node was left with a success state.\n * @param isAborted Whether the decorated node was aborted.\n */\n callAgentFunction = (agent: Agent, isSuccess: boolean, isAborted: boolean) => {\n // Attempt to get the invoker for the callback function.\n const callbackFuncInvoker = Lookup.getFuncInvoker(agent, this.getFunctionName());\n\n // The callback function should be defined.\n if (callbackFuncInvoker === null) {\n throw new Error(\n `cannot call exit function '${this.getFunctionName()}' as is not defined on the agent and has not been registered`\n );\n }\n\n // Call the callback function\n callbackFuncInvoker([{ succeeded: isSuccess, aborted: isAborted }, ...this.args]);\n };\n}\n", "import { AnyNodeDefinition, RootNodeDefinition } from \"./BehaviourTreeDefinition\";\nimport GuardPath, { GuardPathPart } from \"./attributes/guards/GuardPath\";\nimport { validateBranchSubtreeLinks } from \"./BehaviourTreeDefinitionValidator\";\nimport { isInteger } from \"./BehaviourTreeDefinitionUtilities\";\nimport Node from \"./nodes/Node\";\nimport Composite from \"./nodes/composite/Composite\";\nimport Decorator from \"./nodes/decorator/Decorator\";\nimport Parallel from \"./nodes/composite/Parallel\";\nimport Selector from \"./nodes/composite/Selector\";\nimport Sequence from \"./nodes/composite/Sequence\";\nimport Lotto from \"./nodes/composite/Lotto\";\nimport Fail from \"./nodes/decorator/Fail\";\nimport Flip from \"./nodes/decorator/Flip\";\nimport Repeat from \"./nodes/decorator/Repeat\";\nimport Retry from \"./nodes/decorator/Retry\";\nimport Root from \"./nodes/decorator/Root\";\nimport Succeed from \"./nodes/decorator/Succeed\";\nimport Action from \"./nodes/leaf/Action\";\nimport Condition from \"./nodes/leaf/Condition\";\nimport Wait from \"./nodes/leaf/Wait\";\nimport Lookup from \"./Lookup\";\nimport Attribute from \"./attributes/Attribute\";\nimport While from \"./attributes/guards/While\";\nimport Until from \"./attributes/guards/Until\";\nimport Entry from \"./attributes/callbacks/Entry\";\nimport Step from \"./attributes/callbacks/Step\";\nimport Exit from \"./attributes/callbacks/Exit\";\n\n/**\n * A type representing any node instance in a behaviour tree.\n */\ntype AnyNode =\n | Root\n | Action\n | Condition\n | Wait\n | Sequence\n | Selector\n | Lotto\n | Parallel\n | Repeat\n | Retry\n | Flip\n | Succeed\n | Fail;\n\n/**\n * A type defining a mapping of root node identifiers to root node definitions.\n */\ntype RootNodeDefinitionMap = { [key: string | symbol]: RootNodeDefinition };\n\n/**\n * A symbol to use as the main root key in any root node mappings.\n */\nconst MAIN_ROOT_NODE_KEY = Symbol(\"__root__\");\n\n/**\n * Build and populate the root nodes based on the provided definition, assuming that the definition has been validated.\n * @param definition The root node definitions.\n * @returns The built and populated root node definitions.\n */\nexport default function buildRootNode(definition: RootNodeDefinition[]): Root {\n // Create a mapping of root node identifers to root node definitions, including globally registered subtree root node definitions.\n const rootNodeDefinitionMap = createRootNodeDefinitionMap(definition);\n\n // Now that we have all of our root node definitions (those part of the tree definition and those globally registered)\n // we should validate the branch-subtree links. This will also double-check that we dont have any circular dependencies\n // in our branch-subtree references and that we have no broken branch-subtree links.\n validateBranchSubtreeLinks(\n [rootNodeDefinitionMap[MAIN_ROOT_NODE_KEY], ...Object.values(rootNodeDefinitionMap)],\n true\n );\n\n // Create our populated tree of node instances, starting with our main root node.\n const rootNode = nodeFactory(rootNodeDefinitionMap[MAIN_ROOT_NODE_KEY], rootNodeDefinitionMap) as Root;\n\n // Set a guard path on every leaf of the tree to evaluate as part of each update.\n applyLeafNodeGuardPaths(rootNode);\n\n // We only need to return the main root node.\n return rootNode;\n}\n\n/**\n * A factory function which creates a node instance based on the specified definition.\n * @param definition The node definition.\n * @param rootNodeDefinitionMap The mapping of root node identifers to root node definitions, including globally registered subtree root node definitions.\n * @returns A node instance based on the specified definition.\n */\nfunction nodeFactory(definition: AnyNodeDefinition, rootNodeDefinitionMap: RootNodeDefinitionMap): AnyNode {\n // Get the attributes for the node.\n const attributes = nodeAttributesFactory(definition);\n\n // Create the node instance based on the definition type.\n switch (definition.type) {\n case \"root\":\n return new Root(attributes, nodeFactory(definition.child, rootNodeDefinitionMap));\n\n case \"repeat\":\n let iterations: number | null = null;\n let iterationsMin: number | null = null;\n let iterationsMax: number | null = null;\n\n if (Array.isArray(definition.iterations)) {\n iterationsMin = definition.iterations[0];\n iterationsMax = definition.iterations[1];\n } else if (isInteger(definition.iterations)) {\n iterations = definition.iterations!;\n }\n\n return new Repeat(\n attributes,\n iterations,\n iterationsMin,\n iterationsMax,\n nodeFactory(definition.child, rootNodeDefinitionMap)\n );\n\n case \"retry\":\n let attempts: number | null = null;\n let attemptsMin: number | null = null;\n let attemptsMax: number | null = null;\n\n if (Array.isArray(definition.attempts)) {\n attemptsMin = definition.attempts[0];\n attemptsMax = definition.attempts[1];\n } else if (isInteger(definition.attempts)) {\n attempts = definition.attempts!;\n }\n\n return new Retry(\n attributes,\n attempts,\n attemptsMin,\n attemptsMax,\n nodeFactory(definition.child, rootNodeDefinitionMap)\n );\n\n case \"flip\":\n return new Flip(attributes, nodeFactory(definition.child, rootNodeDefinitionMap));\n\n case \"succeed\":\n return new Succeed(attributes, nodeFactory(definition.child, rootNodeDefinitionMap));\n\n case \"fail\":\n return new Fail(attributes, nodeFactory(definition.child, rootNodeDefinitionMap));\n\n case \"sequence\":\n return new Sequence(\n attributes,\n definition.children.map((child) => nodeFactory(child, rootNodeDefinitionMap))\n );\n\n case \"selector\":\n return new Selector(\n attributes,\n definition.children.map((child) => nodeFactory(child, rootNodeDefinitionMap))\n );\n\n case \"parallel\":\n return new Parallel(\n attributes,\n definition.children.map((child) => nodeFactory(child, rootNodeDefinitionMap))\n );\n\n case \"lotto\":\n return new Lotto(\n attributes,\n definition.weights,\n definition.children.map((child) => nodeFactory(child, rootNodeDefinitionMap))\n );\n\n case \"branch\":\n return nodeFactory(rootNodeDefinitionMap[definition.ref].child, rootNodeDefinitionMap);\n\n case \"action\":\n return new Action(attributes, definition.call, definition.args || []);\n\n case \"condition\":\n return new Condition(attributes, definition.call, definition.args || []);\n\n case \"wait\":\n let duration: number | null = null;\n let durationMin: number | null = null;\n let durationMax: number | null = null;\n\n if (Array.isArray(definition.duration)) {\n durationMin = definition.duration[0];\n durationMax = definition.duration[1];\n } else if (isInteger(definition.duration)) {\n duration = definition.duration!;\n }\n\n return new Wait(attributes, duration, durationMin, durationMax);\n }\n}\n\n/**\n * Creates an array of node attribute instances based on the specified node definition.\n * @param definition The node definition.\n * @returns An array of node attribute instances based on the specified node definition.\n */\nfunction nodeAttributesFactory(definition: AnyNodeDefinition): Attribute[] {\n const attributes: Attribute[] = [];\n\n if (definition.while) {\n attributes.push(new While(definition.while.call, definition.while.args ?? []));\n }\n\n if (definition.until) {\n attributes.push(new Until(definition.until.call, definition.until.args ?? []));\n }\n\n if (definition.entry) {\n attributes.push(new Entry(definition.entry.call, definition.entry.args ?? []));\n }\n\n if (definition.step) {\n attributes.push(new Step(definition.step.call, definition.step.args ?? []));\n }\n\n if (definition.exit) {\n attributes.push(new Exit(definition.exit.call, definition.exit.args ?? []));\n }\n\n return attributes;\n}\n\n/**\n * Creates a mapping of root node identifers to root node definitions, mixing in globally registered subtree root node definitions.\n * @param definition The root node definitions.\n * @returns A mapping of root node identifers to root node definitions, including globally registered subtree root node definitions.\n */\nfunction createRootNodeDefinitionMap(definition: RootNodeDefinition[]): RootNodeDefinitionMap {\n // Create a mapping of root node identifers to root node definitions.\n const rootNodeMap: RootNodeDefinitionMap = {};\n\n // Add in any registered subtree root node definitions.\n for (const [name, rootNodeDefinition] of Object.entries(Lookup.getSubtrees())) {\n // The name used when registering the subtree will be used as the root node identifier.\n rootNodeMap[name] = { ...rootNodeDefinition, id: name };\n }\n\n // Populate the map with the root node definitions that were included with the tree definition.\n // We do this after adding any registered subtrees as we want these to take presedence.\n for (const rootNodeDefinition of definition) {\n rootNodeMap[rootNodeDefinition.id ?? MAIN_ROOT_NODE_KEY] = rootNodeDefinition;\n }\n\n return rootNodeMap;\n}\n\n/**\n * Applies a guard path to every leaf of the tree to evaluate as part of each update.\n * @param root The main root tree node.\n */\nfunction applyLeafNodeGuardPaths(root: Root) {\n const nodePaths: Node[][] = [];\n\n const findLeafNodes = (path: Node[], node: Node) => {\n // Add the current node to the path.\n path = path.concat(node);\n\n // Check whether the current node is a leaf node.\n if (node.isLeafNode()) {\n nodePaths.push(path);\n } else {\n (node as Composite | Decorator).getChildren().forEach((child) => findLeafNodes(path, child));\n }\n };\n\n // Find all leaf node paths, starting from the root.\n findLeafNodes([], root);\n\n nodePaths.forEach((path) => {\n // Each node in the current path will have to be assigned a guard path, working from the root outwards.\n for (let depth = 0; depth < path.length; depth++) {\n // Get the node in the path at the current depth.\n const currentNode = path[depth];\n\n // The node may already have been assigned a guard path, if so just skip it.\n if (currentNode.hasGuardPath()) {\n continue;\n }\n\n // Create the guard path for the current node.\n const guardPath = new GuardPath(\n path\n .slice(0, depth + 1)\n .map((node) => ({ node, guards: node.getGuardAttributes() }))\n .filter((details) => details.guards.length > 0)\n );\n\n // Assign the guard path to the current node.\n currentNode.setGuardPath(guardPath);\n }\n });\n}\n", "import State, { AnyState } from \"./State\";\nimport Lookup from \"./Lookup\";\nimport Node from \"./nodes/Node\";\nimport Root from \"./nodes/decorator/Root\";\nimport Composite from \"./nodes/composite/Composite\";\nimport Decorator from \"./nodes/decorator/Decorator\";\nimport { Agent, GlobalFunction } from \"./Agent\";\nimport { CallbackAttributeDetails } from \"./attributes/callbacks/Callback\";\nimport { GuardAttributeDetails } from \"./attributes/guards/Guard\";\nimport { BehaviourTreeOptions } from \"./BehaviourTreeOptions\";\nimport { convertMDSLToJSON } from \"./mdsl/MDSLDefinitionParser\";\nimport { RootNodeDefinition } from \"./BehaviourTreeDefinition\";\nimport { validateDefinition, validateJSONDefinition } from \"./BehaviourTreeDefinitionValidator\";\nimport buildRootNode from \"./BehaviourTreeBuilder\";\nimport { isNullOrUndefined } from \"./BehaviourTreeDefinitionUtilities\";\n\n// Purely for outside inspection of the tree.\nexport type FlattenedTreeNode = {\n id: string;\n type: string;\n caption: string;\n state: AnyState;\n guards: GuardAttributeDetails[];\n callbacks: CallbackAttributeDetails[];\n args: any[];\n parentId: string | null;\n};\n\n/**\n * A representation of a behaviour tree.\n */\nexport class BehaviourTree {\n /**\n * The main root tree node.\n */\n private readonly _rootNode: Root;\n\n /**\n * Creates a new instance of the BehaviourTree class.\n * @param definition The behaviour tree definition as either an MDSL string, root node definition object or array of root node definition objects.\n * @param agent The agent instance that this behaviour tree is modelling behaviour for.\n * @param options The behaviour tree options object.\n */\n constructor(\n definition: string | RootNodeDefinition | RootNodeDefinition[],\n private agent: Agent,\n private options: BehaviourTreeOptions = {}\n ) {\n // The tree definition must be defined.\n if (isNullOrUndefined(definition)) {\n throw new Error(\"tree definition not defined\");\n }\n\n // The agent must be defined and not null.\n if (typeof agent !== \"object\" || agent === null) {\n throw new Error(\"the agent must be an object and not null\");\n }\n\n // We should validate the definition before we try to build the tree nodes.\n const { succeeded, errorMessage, json } = validateDefinition(definition);\n\n // Did our validation fail without error?\n if (!succeeded) {\n throw new Error(`invalid definition: ${errorMessage}`);\n }\n\n // Double check that we did actually get our json definition as part of our definition validtion.\n if (!json) {\n throw new Error(\n \"expected json definition to be returned as part of successful definition validation response\"\n );\n }\n\n try {\n // Create the populated tree of behaviour tree nodes and get the root node.\n this._rootNode = buildRootNode(json);\n } catch (exception) {\n // There was an issue in trying build and populate the behaviour tree.\n throw new Error(`error building tree: ${(exception as Error).message}`);\n }\n }\n\n /**\n * Gets whether the tree is in the RUNNING state.\n * @returns true if the tree is in the RUNNING state, otherwise false.\n */\n isRunning() {\n return this._rootNode.getState() === State.RUNNING;\n }\n\n /**\n * Gets the current tree state of SUCCEEDED, FAILED, READY or RUNNING.\n * @returns The current tree state.\n */\n getState() {\n return this._rootNode.getState();\n }\n\n /**\n * Step the tree.\n * 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.\n * 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\n * 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.\n *\n * 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.\n */\n step() {\n // If the root node has already been stepped to completion then we need to reset it.\n if (this._rootNode.getState() === State.SUCCEEDED || this._rootNode.getState() === State.FAILED) {\n this._rootNode.reset();\n }\n\n try {\n this._rootNode.update(this.agent, this.options);\n } catch (exception) {\n throw new Error(`error stepping tree: ${(exception as Error).message}`);\n }\n }\n\n /**\n * Resets the tree from the root node outwards to each nested node, giving each a state of READY.\n */\n reset() {\n this._rootNode.reset();\n }\n\n /**\n * Gets the flattened details of every node in the tree.\n * @returns The flattened details of every node in the tree.\n */\n getFlattenedNodeDetails(): FlattenedTreeNode[] {\n // Create an empty flattened array of tree nodes.\n const flattenedTreeNodes: FlattenedTreeNode[] = [];\n\n /**\n * Helper function to process a node instance and push details into the flattened tree nodes array.\n * @param node The current node.\n * @param parentUid The UID of the node parent, or null if the node is the main root node.\n */\n const processNode = (node: Node, parentUid: string | null) => {\n // Get the guard and callback attribute details for this node.\n const guards = node\n .getAttributes()\n .filter((attribute) => attribute.isGuard())\n .map((attribute) => attribute.getDetails()) as GuardAttributeDetails[];\n const callbacks = node\n .getAttributes()\n .filter((attribute) => !attribute.isGuard())\n .map((attribute) => attribute.getDetails()) as CallbackAttributeDetails[];\n\n // Push the current node into the flattened nodes array.\n flattenedTreeNodes.push({\n id: node.getUid(),\n type: node.getType(),\n caption: node.getName(),\n state: node.getState(),\n guards,\n callbacks,\n args: node.getArguments(),\n parentId: parentUid\n });\n\n // Process each of the nodes children if it is not a leaf node.\n if (!node.isLeafNode()) {\n (node as Composite | Decorator)\n .getChildren()\n .forEach((child) => processNode(child, (node as Composite | Decorator).getUid()));\n }\n };\n\n // Convert the nested node structure into a flattened array of node details.\n processNode(this._rootNode, null);\n\n return flattenedTreeNodes;\n }\n\n /**\n * Registers the action/condition/guard/callback function or subtree with the given name.\n * @param name The name of the function or subtree to register.\n * @param value The function or subtree definition to register.\n */\n static register(name: string, value: GlobalFunction | string | RootNodeDefinition) {\n // Are we going to register a action/condition/guard/callback function?\n if (typeof value === \"function\") {\n Lookup.setFunc(name, value);\n return;\n }\n\n // We are not registering an action/condition/guard/callback function, so we must be registering a subtree.\n if (typeof value === \"string\") {\n let rootNodeDefinitions: RootNodeDefinition[];\n\n // We will assume that any string passed in will be a mdsl definition.\n try {\n rootNodeDefinitions = convertMDSLToJSON(value);\n } catch (exception) {\n throw new Error(`error registering definition, invalid MDSL: ${(exception as Error).message}`);\n }\n\n // This function should only ever be called with a definition containing a single unnamed root node.\n if (rootNodeDefinitions.length != 1 || rootNodeDefinitions[0].id !== null) {\n throw new Error(\"error registering definition: expected a single unnamed root node\");\n }\n\n try {\n // We should validate the subtree as we don't want invalid subtrees available via the lookup.\n const { succeeded, errorMessage } = validateJSONDefinition(rootNodeDefinitions[0]);\n\n // Did our validation fail without error?\n if (!succeeded) {\n throw new Error(errorMessage);\n }\n } catch (exception) {\n throw new Error(`error registering definition: ${(exception as Error).message}`);\n }\n\n // Everything seems hunky-dory, register the subtree.\n Lookup.setSubtree(name, rootNodeDefinitions[0]);\n } else if (typeof value === \"object\" && !Array.isArray(value)) {\n // We will assume that any object passed in is a root node definition.\n\n try {\n // We should validate the subtree as we don't want invalid subtrees available via the lookup.\n const { succeeded, errorMessage } = validateJSONDefinition(value);\n\n // Did our validation fail without error?\n if (!succeeded) {\n throw new Error(errorMessage);\n }\n } catch (exception) {\n throw new Error(`error registering definition: ${(exception as Error).message}`);\n }\n\n // Everything seems hunky-dory, register the subtree.\n Lookup.setSubtree(name, value);\n } else {\n throw new Error(\"unexpected value, expected string mdsl definition, root node json definition or function\");\n }\n }\n\n /**\n * Unregisters the registered action/condition/guard/callback function or subtree with the given name.\n * @param name The name of the registered action/condition/guard/callback function or subtree to unregister.\n */\n static unregister(name: string): void {\n Lookup.remove(name);\n }\n\n /**\n * Unregister all registered action/condition/guard/callback functions and subtrees.\n */\n static unregisterAll(): void {\n Lookup.empty();\n }\n}\n"], + "mappings": "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", "names": ["Participant", "isNullOrUndefined", "Lotto", "createLotto", "State", "createLotto"] } diff --git a/src/attributes/guards/Until.ts b/src/attributes/guards/Until.ts index 542f2a8..ed3d569 100644 --- a/src/attributes/guards/Until.ts +++ b/src/attributes/guards/Until.ts @@ -36,8 +36,12 @@ export default class Until extends Guard { // Call the guard condition function to determine the state of this node, the result of which should be a boolean. conditionFunctionResult = conditionFuncInvoker(this.args); } catch (error) { - // The user was naughty and threw something. - throw new Error(`guard condition function '${this.getCondition()}' threw '${error}'`); + // An uncaught error was thrown. + if (error instanceof Error) { + throw new Error(`guard condition function '${this.getCondition()}' threw: ${error.stack}`); + } else { + throw new Error(`guard condition function '${this.getCondition()}' threw: ${error}`); + } } // The result of calling the guard condition function must be a boolean value. diff --git a/src/attributes/guards/While.ts b/src/attributes/guards/While.ts index c189891..2dc7fe1 100644 --- a/src/attributes/guards/While.ts +++ b/src/attributes/guards/While.ts @@ -36,8 +36,12 @@ export default class While extends Guard { // Call the guard condition function to determine the state of this node, the result of which should be a boolean. conditionFunctionResult = conditionFuncInvoker(this.args); } catch (error) { - // The user was naughty and threw something. - throw new Error(`guard condition function '${this.getCondition()}' threw '${error}'`); + // An uncaught error was thrown. + if (error instanceof Error) { + throw new Error(`guard condition function '${this.getCondition()}' threw: ${error.stack}`); + } else { + throw new Error(`guard condition function '${this.getCondition()}' threw: ${error}`); + } } // The result of calling the guard condition function must be a boolean value. diff --git a/src/nodes/leaf/Action.ts b/src/nodes/leaf/Action.ts index 6ad531a..0af7ed5 100644 --- a/src/nodes/leaf/Action.ts +++ b/src/nodes/leaf/Action.ts @@ -97,8 +97,12 @@ export default class Action extends Leaf { // - Undefined if the node should remain in the running state. actionFunctionResult = actionFuncInvoker(this.actionArguments) as CompleteState | Promise; } catch (error) { - // The user was naughty and threw something. - throw new Error(`action function '${this.actionName}' threw '${error}'`); + // An uncaught error was thrown. + if (error instanceof Error) { + throw new Error(`action function '${this.actionName}' threw: ${error.stack}`); + } else { + throw new Error(`action function '${this.actionName}' threw: ${error}`); + } } if (actionFunctionResult instanceof Promise) { diff --git a/src/nodes/leaf/Condition.ts b/src/nodes/leaf/Condition.ts index f389d43..c0fb824 100644 --- a/src/nodes/leaf/Condition.ts +++ b/src/nodes/leaf/Condition.ts @@ -41,8 +41,12 @@ export default class Condition extends Leaf { // Call the condition function to determine the state of this node, the result of which should be a boolean. conditionFunctionResult = conditionFuncInvoker(this.conditionArguments); } catch (error) { - // The user was naughty and threw something. - throw new Error(`condition function '${this.conditionName}' threw '${error}'`); + // An uncaught error was thrown. + if (error instanceof Error) { + throw new Error(`condition function '${this.conditionName}' threw: ${error.stack}`); + } else { + throw new Error(`condition function '${this.conditionName}' threw: ${error}`); + } } // The result of calling the condition function must be a boolean value. diff --git a/test/attributes/guards/Until.spec.ts b/test/attributes/guards/Until.spec.ts index 4c4f71e..3cd1fa0 100644 --- a/test/attributes/guards/Until.spec.ts +++ b/test/attributes/guards/Until.spec.ts @@ -275,7 +275,7 @@ describe("An Until guard node attribute", () => { assert.throws( () => tree.step(), Error, - "error stepping tree: guard condition function 'someCondition' threw 'Error: some-error'" + "error stepping tree: guard condition function 'someCondition' threw: Error: some-error" ); }); @@ -307,7 +307,7 @@ describe("An Until guard node attribute", () => { assert.throws( () => tree.step(), Error, - "error stepping tree: guard condition function 'someCondition' threw 'Error: some-error'" + "error stepping tree: guard condition function 'someCondition' threw: Error: some-error" ); }); }); diff --git a/test/attributes/guards/While.spec.ts b/test/attributes/guards/While.spec.ts index 357ea59..2b68817 100644 --- a/test/attributes/guards/While.spec.ts +++ b/test/attributes/guards/While.spec.ts @@ -275,7 +275,7 @@ describe("A While guard node attribute", () => { assert.throws( () => tree.step(), Error, - "error stepping tree: guard condition function 'someCondition' threw 'Error: some-error'" + "error stepping tree: guard condition function 'someCondition' threw: Error: some-error" ); }); @@ -307,7 +307,7 @@ describe("A While guard node attribute", () => { assert.throws( () => tree.step(), Error, - "error stepping tree: guard condition function 'someCondition' threw 'Error: some-error'" + "error stepping tree: guard condition function 'someCondition' threw: Error: some-error" ); }); }); diff --git a/test/nodes/leaf/Action.spec.ts b/test/nodes/leaf/Action.spec.ts index 7c18e23..7e96263 100644 --- a/test/nodes/leaf/Action.spec.ts +++ b/test/nodes/leaf/Action.spec.ts @@ -153,7 +153,7 @@ describe("An Action node", () => { assert.throws( () => tree.step(), Error, - "error stepping tree: action function 'doAction' threw 'Error: some-error'" + "error stepping tree: action function 'doAction' threw: Error: some-error" ); }); @@ -175,7 +175,7 @@ describe("An Action node", () => { assert.throws( () => tree.step(), Error, - "error stepping tree: action function 'doAction' threw 'Error: some-error'" + "error stepping tree: action function 'doAction' threw: Error: some-error" ); }); }); @@ -185,7 +185,7 @@ describe("An Action node", () => { const definition = "root { action [doAction] }"; const agent = { doAction: () => { - throw "Disaster!"; + throw "some-error"; } }; const tree = new BehaviourTree(definition, agent); @@ -193,7 +193,7 @@ describe("An Action node", () => { assert.throws( () => tree.step(), Error, - "error stepping tree: action function 'doAction' threw 'Disaster!'" + "error stepping tree: action function 'doAction' threw: some-error" ); }); @@ -207,7 +207,7 @@ describe("An Action node", () => { }; const agent = { doAction: () => { - throw "Disaster!"; + throw "some-error"; } }; const tree = new BehaviourTree(definition, agent); @@ -215,7 +215,7 @@ describe("An Action node", () => { assert.throws( () => tree.step(), Error, - "error stepping tree: action function 'doAction' threw 'Disaster!'" + "error stepping tree: action function 'doAction' threw: some-error" ); }); }); diff --git a/test/nodes/leaf/Condition.spec.ts b/test/nodes/leaf/Condition.spec.ts index 92a18b1..a008f23 100644 --- a/test/nodes/leaf/Condition.spec.ts +++ b/test/nodes/leaf/Condition.spec.ts @@ -137,35 +137,117 @@ describe("A Condition node", () => { }); }); - describe("the agent function does not return a boolean value", () => { - it("(MDSL)", () => { - const definition = "root { condition [someCondition] }"; - const agent = { someCondition: () => null }; - const tree = new BehaviourTree(definition, agent); + describe("the agent function", () => { + describe("throws an error object", () => { + it("(MDSL)", () => { + const definition = "root { condition [someCondition] }"; + const agent = { + someCondition: () => { + throw new Error("some-error"); + } + }; + const tree = new BehaviourTree(definition, agent); - assert.throws( - () => tree.step(), - Error, - "error stepping tree: expected condition function 'someCondition' to return a boolean but returned 'null'" - ); + assert.throws( + () => tree.step(), + Error, + "error stepping tree: condition function 'someCondition' threw: Error: some-error" + ); + }); + + it("(JSON)", () => { + const definition: RootNodeDefinition = { + type: "root", + child: { + type: "condition", + call: "someCondition" + } + }; + const agent = { + someCondition: () => { + throw new Error("some-error"); + } + }; + const tree = new BehaviourTree(definition, agent); + + assert.throws( + () => tree.step(), + Error, + "error stepping tree: condition function 'someCondition' threw: Error: some-error" + ); + }); }); - it("(JSON)", () => { - const definition: RootNodeDefinition = { - type: "root", - child: { - type: "condition", - call: "someCondition" - } - }; - const agent = { someCondition: () => null }; - const tree = new BehaviourTree(definition, agent); + describe("throws something that isn't an error object", () => { + it("(MDSL)", () => { + const definition = "root { condition [someCondition] }"; + const agent = { + someCondition: () => { + throw "some-error"; + } + }; + const tree = new BehaviourTree(definition, agent); - assert.throws( - () => tree.step(), - Error, - "error stepping tree: expected condition function 'someCondition' to return a boolean but returned 'null'" - ); + assert.throws( + () => tree.step(), + Error, + "error stepping tree: condition function 'someCondition' threw: some-error" + ); + }); + + it("(JSON)", () => { + const definition: RootNodeDefinition = { + type: "root", + child: { + type: "condition", + call: "someCondition" + } + }; + const agent = { + someCondition: () => { + throw "some-error"; + } + }; + const tree = new BehaviourTree(definition, agent); + + assert.throws( + () => tree.step(), + Error, + "error stepping tree: condition function 'someCondition' threw: some-error" + ); + }); + }); + + describe("does not return a boolean value", () => { + it("(MDSL)", () => { + const definition = "root { condition [someCondition] }"; + const agent = { someCondition: () => null }; + const tree = new BehaviourTree(definition, agent); + + assert.throws( + () => tree.step(), + Error, + "error stepping tree: expected condition function 'someCondition' to return a boolean but returned 'null'" + ); + }); + + it("(JSON)", () => { + const definition: RootNodeDefinition = { + type: "root", + child: { + type: "condition", + call: "someCondition" + } + }; + const agent = { someCondition: () => null }; + const tree = new BehaviourTree(definition, agent); + + assert.throws( + () => tree.step(), + Error, + "error stepping tree: expected condition function 'someCondition' to return a boolean but returned 'null'" + ); + }); }); }); }); From 814c995799cee0a8b1ac1d6a92907e0012b14eba Mon Sep 17 00:00:00 2001 From: Nikolas Howard Date: Fri, 1 Mar 2024 17:35:36 +0000 Subject: [PATCH 45/48] Fixed issue where args were not passed to registered funcs properly and subtrees couldnt be registered --- dist/Agent.d.ts | 2 +- dist/bundle.js | 4 ++-- dist/bundle.js.map | 4 ++-- dist/index.js | 4 ++-- dist/index.js.map | 4 ++-- src/Agent.ts | 2 +- src/BehaviourTree.ts | 2 +- src/Lookup.ts | 2 +- test/nodes/leaf/Action.spec.ts | 29 +++++++++++++++-------------- test/nodes/leaf/Condition.spec.ts | 25 ++++++++++++++----------- 10 files changed, 41 insertions(+), 37 deletions(-) diff --git a/dist/Agent.d.ts b/dist/Agent.d.ts index 25d35f4..b43f651 100644 --- a/dist/Agent.d.ts +++ b/dist/Agent.d.ts @@ -9,7 +9,7 @@ export type ExitFunctionArg = { succeeded: boolean; aborted: boolean; }; -export type FunctionArg = number | string | boolean | null | ExitFunctionArg; +export type FunctionArg = any | ExitFunctionArg; export type ActionResult = CompleteState | Promise | State.RUNNING | void; export type AgentFunction = (this: Agent, ...args: FunctionArg[]) => ActionResult | boolean; export type GlobalFunction = (agent: Agent, ...args: FunctionArg[]) => ActionResult | boolean; diff --git a/dist/bundle.js b/dist/bundle.js index b212378..9c28e08 100644 --- a/dist/bundle.js +++ b/dist/bundle.js @@ -1236,7 +1236,7 @@ var mistreevous = (() => { } if (this.registeredFunctions[name] && typeof this.registeredFunctions[name] === "function") { const registeredFunction = this.registeredFunctions[name]; - return (args) => registeredFunction(agent, ...args.map((arg) => arg.value)); + return (args) => registeredFunction(agent, ...args); } return null; } @@ -2314,7 +2314,7 @@ var mistreevous = (() => { } catch (exception) { throw new Error(`error registering definition, invalid MDSL: ${exception.message}`); } - if (rootNodeDefinitions.length != 1 || rootNodeDefinitions[0].id !== null) { + if (rootNodeDefinitions.length != 1 || typeof rootNodeDefinitions[0].id !== "undefined") { throw new Error("error registering definition: expected a single unnamed root node"); } try { diff --git a/dist/bundle.js.map b/dist/bundle.js.map index 558a46f..77fcf6d 100644 --- a/dist/bundle.js.map +++ b/dist/bundle.js.map @@ -1,7 +1,7 @@ { "version": 3, "sources": ["../node_modules/lotto-draw/dist/Participant.js", "../node_modules/lotto-draw/dist/Utilities.js", "../node_modules/lotto-draw/dist/Lotto.js", "../node_modules/lotto-draw/dist/createLotto.js", "../node_modules/lotto-draw/dist/index.js", "../src/index.ts", "../src/State.ts", "../src/BehaviourTreeDefinitionUtilities.ts", "../src/mdsl/MDSLUtilities.ts", "../src/mdsl/MDSLNodeArgumentParser.ts", "../src/mdsl/MDSLNodeAttributeParser.ts", "../src/mdsl/MDSLDefinitionParser.ts", "../src/BehaviourTreeDefinitionValidator.ts", "../src/Lookup.ts", "../src/attributes/guards/GuardUnsatisifedException.ts", "../src/attributes/guards/GuardPath.ts", "../src/nodes/Node.ts", "../src/nodes/composite/Composite.ts", "../src/nodes/composite/Parallel.ts", "../src/nodes/composite/Selector.ts", "../src/nodes/composite/Sequence.ts", "../src/nodes/composite/Lotto.ts", "../src/nodes/decorator/Decorator.ts", "../src/nodes/decorator/Fail.ts", "../src/nodes/decorator/Flip.ts", "../src/nodes/decorator/Repeat.ts", "../src/nodes/decorator/Retry.ts", "../src/nodes/decorator/Root.ts", "../src/nodes/decorator/Succeed.ts", "../src/nodes/leaf/Leaf.ts", "../src/nodes/leaf/Action.ts", "../src/nodes/leaf/Condition.ts", "../src/nodes/leaf/Wait.ts", "../src/attributes/Attribute.ts", "../src/attributes/guards/Guard.ts", "../src/attributes/guards/While.ts", "../src/attributes/guards/Until.ts", "../src/attributes/callbacks/Callback.ts", "../src/attributes/callbacks/Entry.ts", "../src/attributes/callbacks/Step.ts", "../src/attributes/callbacks/Exit.ts", "../src/BehaviourTreeBuilder.ts", "../src/BehaviourTree.ts"], - "sourcesContent": ["\"use strict\";\r\nObject.defineProperty(exports, \"__esModule\", { value: true });\r\nexports.Participant = void 0;\r\n/**\r\n * A participant that holds a number of tickets.\r\n */\r\nvar Participant = /** @class */ (function () {\r\n /**\r\n * Creates an instance of the Participant class.\r\n * @param participant The actual participant.\r\n * @param tickets The number of tickets held by the participant.\r\n */\r\n function Participant(participant, tickets) {\r\n if (tickets === void 0) { tickets = 1; }\r\n this._participant = participant;\r\n this._tickets = tickets;\r\n }\r\n Object.defineProperty(Participant.prototype, \"participant\", {\r\n /** Gets the actual participant. */\r\n get: function () {\r\n return this._participant;\r\n },\r\n enumerable: false,\r\n configurable: true\r\n });\r\n Object.defineProperty(Participant.prototype, \"tickets\", {\r\n /** Gets or sets the number of tickets held by the participant. */\r\n get: function () {\r\n return this._tickets;\r\n },\r\n set: function (value) {\r\n this._tickets = value;\r\n },\r\n enumerable: false,\r\n configurable: true\r\n });\r\n return Participant;\r\n}());\r\nexports.Participant = Participant;\r\n", "\"use strict\";\r\nObject.defineProperty(exports, \"__esModule\", { value: true });\r\nexports.isNaturalNumber = exports.isNullOrUndefined = void 0;\r\n/**\r\n * Gets whether the value provided is null or undefined.\r\n * @param value The value to check.\r\n * @returns Whether the value provided is null or undefined.\r\n */\r\nfunction isNullOrUndefined(value) {\r\n return value === null || value === undefined;\r\n}\r\nexports.isNullOrUndefined = isNullOrUndefined;\r\n/**\r\n * Gets whether the value provided is a natural number.\r\n * @param value The value to check.\r\n * @returns Whether the value provided is a natural number.\r\n */\r\nfunction isNaturalNumber(value) {\r\n return typeof value === \"number\" && value >= 1 && Math.floor(value) === value;\r\n}\r\nexports.isNaturalNumber = isNaturalNumber;\r\n", "\"use strict\";\r\nObject.defineProperty(exports, \"__esModule\", { value: true });\r\nexports.Lotto = void 0;\r\nvar Participant_1 = require(\"./Participant\");\r\nvar Utilities_1 = require(\"./Utilities\");\r\n/**\r\n * Represents a lotto consisting of a number of pickable ticket-holding participants.\r\n */\r\nvar Lotto = /** @class */ (function () {\r\n /**\r\n * Creates a new instance of Lotto.\r\n * @param customRandom The custom RNG to use in place of Math.random().\r\n */\r\n function Lotto(customRandom) {\r\n /** The array of participants that are holding tickets in the lotto. */\r\n this._participants = [];\r\n this._customRandom = customRandom;\r\n }\r\n /**\r\n * Adds a participant with the specified number of tickets, or adds to the participant ticket count if the participant already holds tickets.\r\n * @param participant The participant to add or to increase the ticket count for if they already hold tickets.\r\n * @param tickets The number of tickets, defaults to 1.\r\n * @returns The Lotto instance.\r\n */\r\n Lotto.prototype.add = function (participant, tickets) {\r\n if (tickets === void 0) { tickets = 1; }\r\n // Check that we have a valid ticket count.\r\n if (!(0, Utilities_1.isNaturalNumber)(tickets)) {\r\n throw new Error(\"tickets value must be a natural number\");\r\n }\r\n // Check whether this participant has already been added.\r\n var existingParticipant = this._participants.find(function (part) { return part.participant === participant; });\r\n if (existingParticipant) {\r\n // The participant has already been added to the lotto so just add to their ticket count.\r\n existingParticipant.tickets += tickets;\r\n }\r\n else {\r\n // The participant is not part of the lotto so we should add them.\r\n this._participants.push(new Participant_1.Participant(participant, tickets));\r\n }\r\n return this;\r\n };\r\n /**\r\n * Removes the specified number of tickets for the given participant from the draw, or all tickets if a ticket number is not defined.\r\n * @param participant The participant to remove tickets for.\r\n * @param tickets The number of tickets to remove, or undefined if all tickets are to be removed.\r\n * @returns The Lotto instance.\r\n */\r\n Lotto.prototype.remove = function (participant, tickets) {\r\n // Attempt to get the existing participant.\r\n var existingParticipant = this._participants.find(function (part) { return part.participant === participant; });\r\n // There is nothing to do if the specified participant isn't even part of the lotto.\r\n if (!existingParticipant) {\r\n return this;\r\n }\r\n // Check whether a tickets value was given.\r\n if (tickets !== undefined) {\r\n // Check that we have a valid ticket count.\r\n if (!(0, Utilities_1.isNaturalNumber)(tickets)) {\r\n throw new Error(\"tickets value must be a natural number\");\r\n }\r\n existingParticipant.tickets -= tickets;\r\n // If the participant no longer holds any tickets then they should be removed.\r\n if (existingParticipant.tickets < 1) {\r\n this._participants = this._participants.filter(function (part) { return part !== existingParticipant; });\r\n }\r\n }\r\n else {\r\n // We are removing all tickets for the participant so just remove them from the lotto.\r\n this._participants = this._participants.filter(function (part) { return part !== existingParticipant; });\r\n }\r\n return this;\r\n };\r\n /**\r\n * Draw a winning ticket and return the participant that holds the ticket.\r\n * @param options The draw options.\r\n * @returns The participant that holds the winning ticket.\r\n */\r\n Lotto.prototype.draw = function (options) {\r\n if (options === void 0) { options = {}; }\r\n // If we have no participants then just return null.\r\n if (this._participants.length === 0) {\r\n return null;\r\n }\r\n var redrawable = (0, Utilities_1.isNullOrUndefined)(options.redrawable) ? true : options.redrawable;\r\n var pickable = [];\r\n this._participants.forEach(function (_a) {\r\n var participant = _a.participant, tickets = _a.tickets;\r\n for (var ticketCount = 0; ticketCount < tickets; ticketCount++) {\r\n pickable.push(participant);\r\n }\r\n });\r\n var random;\r\n // We need a random floating-point number between 0 (inclusive) and 1 to scale up to pick our winner.\r\n // If a custom random function exists then we should use that or fall back to Math.random().\r\n if (this._customRandom) {\r\n // Call our custom random function to get a random floating-point number.\r\n random = this._customRandom();\r\n // Verify that the result of calling our custom random function is a number between 0 (inclusive) and 1.\r\n if (typeof random !== \"number\" || random < 0 || random >= 1) {\r\n throw new Error(\"the 'random' function provided did not return a number between 0 (inclusive) and 1\");\r\n }\r\n }\r\n else {\r\n // No custom random function was defined so just use good ol' Math.random().\r\n random = Math.random();\r\n }\r\n // Pick a winning participant.\r\n var winner = pickable[Math.floor(random * pickable.length)];\r\n // If the ticket isn't redrawable then we should remove a ticket from the winning participants ticket count.\r\n if (!redrawable) {\r\n this.remove(winner, 1);\r\n }\r\n // Return the winning participant.\r\n return winner;\r\n };\r\n /**\r\n * Draws multiple winning tickets and return an array of the participants that hold the winning tickets.\r\n * @param tickets The number of winning tickets to draw.\r\n * @param options The draw multiple options.\r\n * @returns An array of the participants that hold the winning tickets.\r\n */\r\n Lotto.prototype.drawMultiple = function (tickets, options) {\r\n if (options === void 0) { options = {}; }\r\n var uniqueResults = (0, Utilities_1.isNullOrUndefined)(options.unique) ? false : options.unique;\r\n // Handle cases where the user has asked for zero tickets (no idea why they would do this be we should trust them).\r\n if (tickets === 0) {\r\n return [];\r\n }\r\n // Now that we know out tickets value is not zero we should check that it is a valid natural number.\r\n if (!(0, Utilities_1.isNaturalNumber)(tickets)) {\r\n throw new Error(\"tickets value must be a natural number\");\r\n }\r\n var result = [];\r\n // Keep drawing tickets until we either reach the number of required tickets or we simply run out of tickets to draw.\r\n // We can run out of tickets to draw if 'options.redrawable' is explicity 'false' or we just had no participants when 'drawMultiple' was called.\r\n while (result.length < tickets && this._participants.length > 0) {\r\n result.push(this.draw(options));\r\n }\r\n // If the 'unique' draw option is set then we need to remove duplicates from the result list.\r\n if (uniqueResults) {\r\n // Create an array to store our unique results.\r\n var unique = [];\r\n // Iterate over all of our participants (with potential duplicates) and populate our array of unique values.\r\n for (var _i = 0, result_1 = result; _i < result_1.length; _i++) {\r\n var participant = result_1[_i];\r\n if (unique.indexOf(participant) === -1) {\r\n unique.push(participant);\r\n }\r\n }\r\n result = unique;\r\n }\r\n return result;\r\n };\r\n return Lotto;\r\n}());\r\nexports.Lotto = Lotto;\r\n", "\"use strict\";\r\nObject.defineProperty(exports, \"__esModule\", { value: true });\r\nexports.createLotto = void 0;\r\nvar Lotto_1 = require(\"./Lotto\");\r\n/**\r\n * A function that creates and returns a Lotto instance.\r\n * @param participantsOrOptions An array of initial participants or options relating to the creation of a Lotto instance.\r\n * @returns A new Lotto instance.\r\n */\r\nfunction createLotto(participantsOrOptions) {\r\n // If no initial participants or lotto options were provided as an argument then we can just return a new lotto instance now.\r\n if (!participantsOrOptions) {\r\n return new Lotto_1.Lotto();\r\n }\r\n // Check whether we were provided with an array of initial participants or a lotto options object.\r\n if (Array.isArray(participantsOrOptions)) {\r\n // We are dealing with a pre-defined array of participants.\r\n var participants = participantsOrOptions;\r\n var lotto_1 = new Lotto_1.Lotto();\r\n // If the lotto participants have been defined upfront then we will need to add them all to our lotto instance now.\r\n participants.forEach(function (_a) {\r\n var participant = _a[0], tokens = _a[1];\r\n return lotto_1.add(participant, tokens);\r\n });\r\n // Return the Lotto instance.\r\n return lotto_1;\r\n }\r\n else {\r\n // We are dealing with some lotto options.\r\n var random = participantsOrOptions.random, participants = participantsOrOptions.participants;\r\n // Create a Lotto instance passing the custom RNG function to use in place of Math.random() (which could be undefined).\r\n var lotto_2 = new Lotto_1.Lotto(random);\r\n // If the lotto participants have been defined upfront as part of the options then we will need to add them all to our lotto instance now.\r\n if (participants) {\r\n participants.forEach(function (_a) {\r\n var participant = _a[0], tokens = _a[1];\r\n return lotto_2.add(participant, tokens);\r\n });\r\n }\r\n // Return the Lotto instance.\r\n return lotto_2;\r\n }\r\n}\r\nexports.createLotto = createLotto;\r\n", "\"use strict\";\r\nObject.defineProperty(exports, \"__esModule\", { value: true });\r\nvar createLotto_1 = require(\"./createLotto\");\r\nexports.default = createLotto_1.createLotto;\r\n", "import State from \"./State\";\nimport { validateDefinition } from \"./BehaviourTreeDefinitionValidator\";\nimport { convertMDSLToJSON } from \"./mdsl/MDSLDefinitionParser\";\nimport { BehaviourTree, FlattenedTreeNode } from \"./BehaviourTree\";\nimport { BehaviourTreeOptions } from \"./BehaviourTreeOptions\";\n\nexport { BehaviourTree, State, convertMDSLToJSON, validateDefinition };\nexport type { FlattenedTreeNode, BehaviourTreeOptions };\n", "/**\n * Enumeration of node state types.\n */\nexport enum State {\n READY = \"mistreevous.ready\",\n RUNNING = \"mistreevous.running\",\n SUCCEEDED = \"mistreevous.succeeded\",\n FAILED = \"mistreevous.failed\"\n}\n\nexport { State as default };\n\nexport type CompleteState = State.SUCCEEDED | State.FAILED;\nexport type AnyState = State.READY | State.RUNNING | CompleteState;\n", "import {\n NodeDefinition,\n RootNodeDefinition,\n DecoratorNodeDefinition,\n CompositeNodeDefinition,\n AnyNodeDefinition,\n BranchNodeDefinition\n} from \"./BehaviourTreeDefinition\";\n\n/**\n * A type guard function that returns true if the specified node satisfies the RootNodeDefinition type.\n * @param node The node.\n * @returns A value of true if the specified node satisfies the RootNodeDefinition type.\n */\nexport function isRootNode(node: NodeDefinition): node is RootNodeDefinition {\n return node.type === \"root\";\n}\n\n/**\n * A type guard function that returns true if the specified node satisfies the BranchNodeDefinition type.\n * @param node The node.\n * @returns A value of true if the specified node satisfies the BranchNodeDefinition type.\n */\nexport function isBranchNode(node: NodeDefinition): node is BranchNodeDefinition {\n return node.type === \"branch\";\n}\n\n/**\n * A type guard function that returns true if the specified node satisfies the NodeDefinition type.\n * @param node The node.\n * @returns A value of true if the specified node satisfies the NodeDefinition type.\n */\nexport function isLeafNode(node: NodeDefinition): node is NodeDefinition {\n return [\"branch\", \"action\", \"condition\", \"wait\"].includes(node.type);\n}\n\n/**\n * A type guard function that returns true if the specified node satisfies the DecoratorNodeDefinition type.\n * @param node The node.\n * @returns A value of true if the specified node satisfies the DecoratorNodeDefinition type.\n */\nexport function isDecoratorNode(node: NodeDefinition): node is DecoratorNodeDefinition {\n return [\"root\", \"repeat\", \"retry\", \"flip\", \"succeed\", \"fail\"].includes(node.type);\n}\n\n/**\n * A type guard function that returns true if the specified node satisfies the CompositeNodeDefinition type.\n * @param node The node.\n * @returns A value of true if the specified node satisfies the CompositeNodeDefinition type.\n */\nexport function isCompositeNode(node: NodeDefinition): node is CompositeNodeDefinition {\n return [\"sequence\", \"selector\", \"lotto\", \"parallel\"].includes(node.type);\n}\n\n/**\n * Flatten a node definition into an array of all of its nested node definitions.\n * @param nodeDefinition The node definition to flatten.\n * @returns An array of all of nested node definitions.\n */\nexport function flattenDefinition(nodeDefinition: AnyNodeDefinition): AnyNodeDefinition[] {\n const nodes: AnyNodeDefinition[] = [];\n\n const processNode = (currentNodeDefinition: AnyNodeDefinition) => {\n nodes.push(currentNodeDefinition);\n\n if (isCompositeNode(currentNodeDefinition)) {\n currentNodeDefinition.children.forEach(processNode);\n } else if (isDecoratorNode(currentNodeDefinition)) {\n processNode(currentNodeDefinition.child);\n }\n };\n\n processNode(nodeDefinition);\n\n return nodes;\n}\n\n/**\n * Determines whether the passed value is an integer.\n * @param value The value to check.\n * @returns Whether the passed value is an integer.\n */\nexport function isInteger(value: unknown): boolean {\n return typeof value === \"number\" && Math.floor(value) === value;\n}\n\n/**\n * Determines whether the passed value is null or undefined.\n * @param value The value to check.\n * @returns Whether the passed value is null or undefined.\n */\nexport function isNullOrUndefined(value: unknown): boolean {\n return typeof value === \"undefined\" || value === null;\n}\n", "/**\n * A type defining an object that holds a reference to substitued string literals parsed from the definition.\n */\nexport type StringLiteralPlaceholders = { [key: string]: string };\n\n/**\n * Pop the next raw token from the specified array of tokens and throw an error if it wasn't the expected one.\n * @param tokens The array of tokens.\n * @param expected An optional string or array or items, one of which must match the next popped token.\n * @returns The popped token.\n */\nexport function popAndCheck(tokens: string[], expected?: string | string[]): string {\n // Get and remove the next token.\n const popped = tokens.shift();\n\n // We were expecting another token but there aren't any.\n if (popped === undefined) {\n throw new Error(\"unexpected end of definition\");\n }\n\n // Do we have an expected token/tokens array?\n if (expected != undefined) {\n // Get an array of expected values, if the popped token matches any then we are all good.\n const expectedValues = typeof expected === \"string\" ? [expected] : expected;\n\n // Check whether the popped token matches at least one of our expected items.\n var tokenMatchesExpectation = expectedValues.some((item) => popped.toUpperCase() === item.toUpperCase());\n\n // Throw an error if the popped token didn't match any of our expected items.\n if (!tokenMatchesExpectation) {\n const expectationString = expectedValues.map((item) => \"'\" + item + \"'\").join(\" or \");\n throw new Error(\"unexpected token found. Expected \" + expectationString + \" but got '\" + popped + \"'\");\n }\n }\n\n // Return the popped token.\n return popped;\n}\n\n/**\n * Swaps out any node/attribute argument string literals with placeholders.\n * @param definition The definition.\n * @returns An object containing a mapping of placeholders to original string values as well as the processed definition string.\n */\nexport function substituteStringLiterals(definition: string): {\n placeholders: StringLiteralPlaceholders;\n processedDefinition: string;\n} {\n // Create an object to hold the mapping of placeholders to original string values.\n const placeholders: StringLiteralPlaceholders = {};\n\n // Replace any string literals wrapped with double quotes in our definition with placeholders to be processed later.\n const processedDefinition = definition.replace(/\\\"(\\\\.|[^\"\\\\])*\\\"/g, (match) => {\n var strippedMatch = match.substring(1, match.length - 1);\n var placeholder = Object.keys(placeholders).find((key) => placeholders[key] === strippedMatch);\n\n // If we have no existing string literal match then create a new placeholder.\n if (!placeholder) {\n placeholder = `@@${Object.keys(placeholders).length}@@`;\n placeholders[placeholder] = strippedMatch;\n }\n\n return placeholder;\n });\n\n return { placeholders, processedDefinition };\n}\n\n/**\n * Parse the tree definition into an array of raw tokens.\n * @param definition The definition.\n * @returns An array of tokens parsed from the definition.\n */\nexport function parseTokensFromDefinition(definition: string): string[] {\n // Add some space around various important characters so that they can be plucked out easier as individual tokens.\n definition = definition.replace(/\\(/g, \" ( \");\n definition = definition.replace(/\\)/g, \" ) \");\n definition = definition.replace(/\\{/g, \" { \");\n definition = definition.replace(/\\}/g, \" } \");\n definition = definition.replace(/\\]/g, \" ] \");\n definition = definition.replace(/\\[/g, \" [ \");\n definition = definition.replace(/\\,/g, \" , \");\n\n // Split the definition into raw token form and return it.\n return definition.replace(/\\s+/g, \" \").trim().split(\" \");\n}\n", "import { StringLiteralPlaceholders, popAndCheck } from \"./MDSLUtilities\";\n\n/**\n * A type representing any node function argument.\n */\ntype Argument = {\n /**\n * The argument value.\n */\n value: T;\n /**\n * The argument type, used for validation.\n */\n type: string;\n};\n\ntype NullArgument = Argument & {\n type: \"null\";\n};\n\ntype BooleanArgument = Argument & {\n type: \"boolean\";\n};\n\ntype NumberArgument = Argument & {\n type: \"number\";\n /**\n * A flag defining whether the number argument value is a valid integer. (used for validation)\n */\n isInteger: boolean;\n};\n\ntype StringPlaceholderArgument = Argument & {\n type: \"string\";\n};\n\ntype IdentifierArgument = Argument & {\n type: \"identifier\";\n};\n\n/**\n * A type representing a reference to any node function argument.\n */\ntype AnyArgument = NullArgument | BooleanArgument | NumberArgument | StringPlaceholderArgument | IdentifierArgument;\n\n/**\n * Parse an array of argument definitions from the specified tokens array.\n * @param tokens The array tokens to parse the argument definitions from.\n * @param stringArgumentPlaceholders The mapping of string literal node argument placeholders to original values.\n * @param argumentValidator The argument validator function.\n * @param validationFailedMessage The exception message to throw if argument validation fails.\n * @returns An array of argument definitions parsed from the specified tokens array.\n */\nexport function parseArgumentTokens(\n tokens: string[],\n stringArgumentPlaceholders: StringLiteralPlaceholders\n): AnyArgument[] {\n const argumentList: AnyArgument[] = [];\n\n // If the next token is not a '[' or '(' then we have no arguments to parse.\n if (![\"[\", \"(\"].includes(tokens[0])) {\n return argumentList;\n }\n\n // Any lists of arguments will always be wrapped in '[]' for node arguments or '()' for attribute arguments.\n // We are looking for a '[' or '(' opener that wraps the argument tokens and the relevant closer.\n const closingToken = popAndCheck(tokens, [\"[\", \"(\"]) === \"[\" ? \"]\" : \")\";\n\n const argumentListTokens: string[] = [];\n\n // Grab all tokens between the '[' and ']' or '(' and ')'.\n while (tokens.length && tokens[0] !== closingToken) {\n // The next token is part of our arguments list.\n argumentListTokens.push(tokens.shift()!);\n }\n\n // Validate the order of the argument tokens. Each token must either be a ',' or a single argument that satisfies the validator.\n argumentListTokens.forEach((token, index) => {\n // Get whether this token should be an actual argument.\n const shouldBeArgumentToken = !(index & 1);\n\n // If the current token should be an actual argument then validate it, otherwise it should be a ',' token.\n if (shouldBeArgumentToken) {\n // Get the argument definition.\n const argumentDefinition = getArgumentDefinition(token, stringArgumentPlaceholders);\n\n // This is a valid argument!\n argumentList.push(argumentDefinition);\n } else {\n // The current token should be a ',' token.\n if (token !== \",\") {\n throw new Error(`invalid argument list, expected ',' or ']' but got '${token}'`);\n }\n }\n });\n\n // The arguments list should terminate with a ']' or ')' token, depending on the opener.\n popAndCheck(tokens, closingToken);\n\n // Return the arguments.\n return argumentList;\n}\n\n/**\n * Gets an argument value definition.\n * @param token The argument token.\n * @param stringArgumentPlaceholders The mapping of string literal node argument placeholders to original values.\n * @returns An argument value definition.\n */\nfunction getArgumentDefinition(token: string, stringArgumentPlaceholders: StringLiteralPlaceholders): AnyArgument {\n // Check whether the token represents a null value.\n if (token === \"null\") {\n return {\n value: null,\n type: \"null\"\n } as NullArgument;\n }\n\n // Check whether the token represents a boolean value.\n if (token === \"true\" || token === \"false\") {\n return {\n value: token === \"true\",\n type: \"boolean\"\n } as BooleanArgument;\n }\n\n // Check whether the token represents a number value.\n // TODO: Relies on broken isNaN - see MDN.\n // if (!Number.isNaN(token)) {\n if (!isNaN(token as any)) {\n return {\n value: parseFloat(token),\n isInteger: parseFloat(token) === parseInt(token, 10),\n type: \"number\"\n } as NumberArgument;\n }\n\n // Check whether the token is a placeholder (e.g. @@0@@) representing a string literal.\n if (token.match(/^@@\\d+@@$/g)) {\n return {\n value: stringArgumentPlaceholders[token].replace('\\\\\"', '\"'),\n type: \"string\"\n } as StringPlaceholderArgument;\n }\n\n // The only remaining option is that the argument value is an identifier.\n return {\n value: token,\n type: \"identifier\"\n } as IdentifierArgument;\n}\n", "import { NodeAttributeDefinition } from \"../BehaviourTreeDefinition\";\nimport { parseArgumentTokens } from \"./MDSLNodeArgumentParser\";\nimport { StringLiteralPlaceholders } from \"./MDSLUtilities\";\n\n/**\n * A type defining the attribute definitions of a node.\n */\ntype NodeAttributes = {\n while?: NodeAttributeDefinition;\n until?: NodeAttributeDefinition;\n entry?: NodeAttributeDefinition;\n exit?: NodeAttributeDefinition;\n step?: NodeAttributeDefinition;\n};\n\n/**\n * Parse any node attribute definitions from the specified tokens array.\n * @param tokens The array of remaining tokens.\n * @param stringArgumentPlaceholders The mapping of string literal node argument placeholders to original values.\n * @returns An object of attribute definitions defined by any directly following tokens.\n */\nexport function parseAttributeTokens(\n tokens: string[],\n stringArgumentPlaceholders: StringLiteralPlaceholders\n): NodeAttributes {\n const nodeAttributeNames: (keyof NodeAttributes)[] = [\"while\", \"until\", \"entry\", \"exit\", \"step\"];\n\n // Create an object to hold any attributes found.\n const attributes: NodeAttributes = {};\n\n // Try to get the name of the attribute for the next token.\n let nextAttributeName = tokens[0]?.toLowerCase() as keyof NodeAttributes;\n\n // Pull attribute tokens as well as their arguments off of the tokens stack until we have no more.\n while (nodeAttributeNames.includes(nextAttributeName)) {\n // Check to make sure that we have not already created an attribute definition of this type.\n if (attributes[nextAttributeName]) {\n throw new Error(`duplicate attribute '${tokens[0].toUpperCase()}' found for node`);\n }\n\n // Remove the attribute name token from the array of tokens.\n tokens.shift();\n\n // Grab the attribute arguments, assuming the first to be an identifier.\n const [attributeCallIdentifier, ...attributeArguments] = parseArgumentTokens(\n tokens,\n stringArgumentPlaceholders\n );\n\n // The first attribute argument has to be an identifer, this will reference an agent function.\n if (attributeCallIdentifier?.type !== \"identifier\") {\n throw new Error(\"expected agent function or registered function name identifier argument for attribute\");\n }\n\n // Any attribute arguments (other than the expected call identifier) must have a type of string, number, boolean or null.\n attributeArguments\n .filter((arg) => arg.type === \"identifier\")\n .forEach((arg) => {\n throw new Error(\n `invalid attribute argument value '${arg.value}', must be string, number, boolean or null`\n );\n });\n\n // Create the attribute definition and add it to the object of attribute definitions found.\n attributes[nextAttributeName] = {\n call: attributeCallIdentifier.value,\n args: attributeArguments.map(({ value }) => value)\n };\n\n // Try to get the next attribute name token, as there could be multiple.\n nextAttributeName = tokens[0]?.toLowerCase() as keyof NodeAttributes;\n }\n\n return attributes;\n}\n", "import {\n ActionNodeDefinition,\n AnyChildNodeDefinition,\n AnyNodeDefinition,\n BranchNodeDefinition,\n ConditionNodeDefinition,\n FailNodeDefinition,\n FlipNodeDefinition,\n LottoNodeDefinition,\n ParallelNodeDefinition,\n RepeatNodeDefinition,\n RetryNodeDefinition,\n RootNodeDefinition,\n SelectorNodeDefinition,\n SequenceNodeDefinition,\n SucceedNodeDefinition,\n WaitNodeDefinition\n} from \"../BehaviourTreeDefinition\";\nimport {\n isCompositeNode,\n isDecoratorNode,\n isLeafNode,\n isNullOrUndefined,\n isRootNode\n} from \"../BehaviourTreeDefinitionUtilities\";\nimport { parseArgumentTokens } from \"./MDSLNodeArgumentParser\";\nimport { parseAttributeTokens } from \"./MDSLNodeAttributeParser\";\nimport {\n StringLiteralPlaceholders,\n parseTokensFromDefinition,\n popAndCheck,\n substituteStringLiterals\n} from \"./MDSLUtilities\";\n\n/**\n * Convert the MDSL tree definition string into an equivalent JSON definition.\n * @param definition The tree definition string as MDSL.\n * @returns The root node JSON definitions.\n */\nexport function convertMDSLToJSON(definition: string): RootNodeDefinition[] {\n // Swap out any node/attribute argument string literals with a placeholder and get a mapping of placeholders to original values as well as the processed definition.\n const { placeholders, processedDefinition } = substituteStringLiterals(definition);\n\n // Parse our definition definition string into an array of raw tokens.\n const tokens = parseTokensFromDefinition(processedDefinition);\n\n return convertTokensToJSONDefinition(tokens, placeholders);\n}\n\n/**\n * Converts the specified tree definition tokens into a JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The root node JSON definitions.\n */\nfunction convertTokensToJSONDefinition(\n tokens: string[],\n stringLiteralPlaceholders: StringLiteralPlaceholders\n): RootNodeDefinition[] {\n // There must be at least 3 tokens for the tree definition to be valid. 'ROOT', '{' and '}'.\n if (tokens.length < 3) {\n throw new Error(\"invalid token count\");\n }\n\n // We should have a matching number of '{' and '}' tokens. If not, then there are scopes that have not been properly closed.\n if (tokens.filter((token) => token === \"{\").length !== tokens.filter((token) => token === \"}\").length) {\n throw new Error(\"scope character mismatch\");\n }\n\n // Create an array of tree stack arrays where root nodes will always be at the botton and the current composite/decorator node at the top.\n // There should be an element in this array for every root node defined and every element should be an array with a root note as the first element.\n // E.g. A definition with two root nodes defined:\n // [\n // [root, lotto, sequence],\n // [root, selector]\n // ]\n const treeStacks: [Partial, ...Partial[]][] = [];\n\n // Create an array of all root node definitions that we create.\n const rootNodes: Partial[] = [];\n\n // A helper function used to push node definitions onto the tree stack.\n const pushNode = (node: AnyNodeDefinition) => {\n // If the node is a root node then we need to create a new tree stack array with the root node at the root.\n if (isRootNode(node)) {\n // We need to double-check that this root node is not the child of another node.\n // We can do this by checking whether the top tree stack is not empty (contains an existing node)\n if (treeStacks[treeStacks.length - 1]?.length) {\n throw new Error(\"a root node cannot be the child of another node\");\n }\n\n // Add the root node definition to our array of all parsed root node definitions.\n rootNodes.push(node);\n\n // Add the root node definition to the root of a new tree stack.\n treeStacks.push([node]);\n\n return;\n }\n\n // All non-root nodes should be pushed after their root nodes so handle cases\n // where we may not have any tree stacks or our top-most tree stack is empty.\n if (!treeStacks.length || !treeStacks[treeStacks.length - 1].length) {\n throw new Error(\"expected root node at base of definition\");\n }\n\n // Get the current tree stack that we are populating.\n const topTreeStack = treeStacks[treeStacks.length - 1];\n\n // Get the top-most node in the current tree stack, this will be a composite/decorator node\n // for which we will populate its children array if composite or setting its child if a decorator.\n const topTreeStackTopNode = topTreeStack[topTreeStack.length - 1] as AnyNodeDefinition;\n\n // If the top-most node in the current root stack is a composite or decorator\n // node then the current node should be added as a child of the top-most node.\n if (isCompositeNode(topTreeStackTopNode)) {\n topTreeStackTopNode.children = topTreeStackTopNode.children || [];\n topTreeStackTopNode.children.push(node);\n } else if (isDecoratorNode(topTreeStackTopNode)) {\n // If the top node already has a child node set then throw an error as a decorator should only have a single child.\n if (topTreeStackTopNode.child) {\n throw new Error(\"a decorator node must only have a single child node\");\n }\n\n topTreeStackTopNode.child = node;\n }\n\n // If the node we are adding is also a composite or decorator node, then we should push it\n // onto the current tree stack, as subsequent nodes will be added as its child/children.\n if (!isLeafNode(node)) {\n topTreeStack.push(node);\n }\n };\n\n // A helper function used to pop the top-most node definition off of the tree stack and return it.\n const popNode = (): AnyNodeDefinition | null => {\n let poppedNode: AnyNodeDefinition | null = null;\n\n // Get the current tree stack that we are populating.\n const topTreeStack = treeStacks[treeStacks.length - 1];\n\n // Pop the top-most node in the current tree stack if there is one.\n if (topTreeStack.length) {\n poppedNode = topTreeStack.pop() as AnyNodeDefinition;\n }\n\n // We don't want any empty tree stacks in our stack of tree stacks.\n if (!topTreeStack.length) {\n treeStacks.pop();\n }\n\n return poppedNode;\n };\n\n // We should keep processing the raw tokens until we run out of them.\n while (tokens.length) {\n // Grab the next token.\n const token = tokens.shift()!;\n\n // How we create the next node depends on the current raw token value.\n switch (token.toUpperCase()) {\n case \"ROOT\": {\n pushNode(createRootNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"SUCCEED\": {\n pushNode(createSucceedNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"FAIL\": {\n pushNode(createFailNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"FLIP\": {\n pushNode(createFlipNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"REPEAT\": {\n pushNode(createRepeatNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"RETRY\": {\n pushNode(createRetryNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"SEQUENCE\": {\n pushNode(createSequenceNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"SELECTOR\": {\n pushNode(createSelectorNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"PARALLEL\": {\n pushNode(createParallelNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"LOTTO\": {\n pushNode(createLottoNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"ACTION\": {\n pushNode(createActionNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"CONDITION\": {\n pushNode(createConditionNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"WAIT\": {\n pushNode(createWaitNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"BRANCH\": {\n pushNode(createBranchNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"}\": {\n // The '}' character closes the current scope and means that we have to pop a node off of the current stack.\n const poppedNode = popNode();\n\n // Now that we have a node definition we can carry out any validation that may require the node to be fully populated.\n if (poppedNode) {\n validatePoppedNode(poppedNode);\n }\n\n break;\n }\n\n default: {\n throw new Error(`unexpected token: ${token}`);\n }\n }\n }\n\n return rootNodes as RootNodeDefinition[];\n}\n\n/**\n * Creates a root node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The root node JSON definition.\n */\nfunction createRootNode(tokens: string[], stringLiteralPlaceholders: StringLiteralPlaceholders): RootNodeDefinition {\n // Create the root node definition.\n let node = {\n type: \"root\"\n } as Partial;\n\n // Parse any node arguments, we should only have one if any which will be an identifier argument for the root identifier.\n const nodeArguments = parseArgumentTokens(tokens, stringLiteralPlaceholders);\n\n // Check whether any node arguments were defined.\n if (nodeArguments.length) {\n // We should only have one argument, if any, which will be an identifier argument for the root identifier.\n if (nodeArguments.length === 1 && nodeArguments[0].type === \"identifier\") {\n // The root node identifier will be the first and only node argument value.\n node.id = nodeArguments[0].value as string;\n } else {\n throw new Error(\"expected single root name argument\");\n }\n }\n\n // Grab any node attribute definitions and spread them into the node definition.\n node = { ...node, ...parseAttributeTokens(tokens, stringLiteralPlaceholders) };\n\n // This is a decorator node, so we expect an opening '{'.\n popAndCheck(tokens, \"{\");\n\n // Return the root node definition.\n return node as RootNodeDefinition;\n}\n\n/**\n * Creates a succeed node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The succeed node JSON definition.\n */\nfunction createSucceedNode(\n tokens: string[],\n stringLiteralPlaceholders: StringLiteralPlaceholders\n): SucceedNodeDefinition {\n const node = {\n type: \"succeed\",\n ...parseAttributeTokens(tokens, stringLiteralPlaceholders)\n } as SucceedNodeDefinition;\n\n // This is a decorator node, so we expect an opening '{'.\n popAndCheck(tokens, \"{\");\n\n // Return the succeed node definition.\n return node;\n}\n\n/**\n * Creates a fail node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The fail node JSON definition.\n */\nfunction createFailNode(tokens: string[], stringLiteralPlaceholders: StringLiteralPlaceholders): FailNodeDefinition {\n const node = {\n type: \"fail\",\n ...parseAttributeTokens(tokens, stringLiteralPlaceholders)\n } as FailNodeDefinition;\n\n // This is a decorator node, so we expect an opening '{'.\n popAndCheck(tokens, \"{\");\n\n // Return the fail node definition.\n return node;\n}\n\n/**\n * Creates a flip node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The flip node JSON definition.\n */\nfunction createFlipNode(tokens: string[], stringLiteralPlaceholders: StringLiteralPlaceholders): FlipNodeDefinition {\n const node = {\n type: \"flip\",\n ...parseAttributeTokens(tokens, stringLiteralPlaceholders)\n } as FlipNodeDefinition;\n\n // This is a decorator node, so we expect an opening '{'.\n popAndCheck(tokens, \"{\");\n\n // Return the flip node definition.\n return node;\n}\n\n/**\n * Creates a repeat node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The repeat node JSON definition.\n */\nfunction createRepeatNode(\n tokens: string[],\n stringLiteralPlaceholders: StringLiteralPlaceholders\n): RepeatNodeDefinition {\n let node = { type: \"repeat\" } as RepeatNodeDefinition;\n\n // Get the node arguments.\n const nodeArguments = parseArgumentTokens(tokens, stringLiteralPlaceholders);\n\n // The arguments of a repeat node are optional. We may have:\n // - No node arguments, in which case the repeat note will iterate indefinitely.\n // - One node argument which will be the explicit number of iterations to make.\n // - Two node arguments which define the min and max iteration bounds from which a random iteration count will be picked.\n if (nodeArguments.length) {\n // All repeat node arguments MUST be of type number and must be integer.\n nodeArguments\n .filter((arg) => arg.type !== \"number\" || !arg.isInteger)\n .forEach(() => {\n throw new Error(`repeat node iteration counts must be integer values`);\n });\n\n // We should have got one or two iteration counts.\n if (nodeArguments.length === 1) {\n // A static iteration count was defined.\n node.iterations = nodeArguments[0].value as number;\n\n // A repeat node must have a positive number of iterations if defined.\n if (node.iterations < 0) {\n throw new Error(\"a repeat node must have a positive number of iterations if defined\");\n }\n } else if (nodeArguments.length === 2) {\n // A minimum and maximum iteration count was defined.\n node.iterations = [nodeArguments[0].value as number, nodeArguments[1].value as number];\n\n // A repeat node must have a positive min and max iteration count if they are defined.\n if (node.iterations[0] < 0 || node.iterations[1] < 0) {\n throw new Error(\"a repeat node must have a positive minimum and maximum iteration count if defined\");\n }\n\n // A repeat node must not have an minimum iteration count that exceeds the maximum iteration count.\n if (node.iterations[0] > node.iterations[1]) {\n throw new Error(\n \"a repeat node must not have a minimum iteration count that exceeds the maximum iteration count\"\n );\n }\n } else {\n // An incorrect number of iteration counts was defined.\n throw new Error(\"invalid number of repeat node iteration count arguments defined\");\n }\n }\n\n // Grab any node attribute definitions and spread them into the node definition.\n node = { ...node, ...parseAttributeTokens(tokens, stringLiteralPlaceholders) };\n\n // This is a decorator node, so we expect an opening '{'.\n popAndCheck(tokens, \"{\");\n\n // Return the repeat node definition.\n return node;\n}\n\n/**\n * Creates a retry node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The retry node JSON definition.\n */\nfunction createRetryNode(tokens: string[], stringLiteralPlaceholders: StringLiteralPlaceholders): RetryNodeDefinition {\n let node = { type: \"retry\" } as RetryNodeDefinition;\n\n // Get the node arguments.\n const nodeArguments = parseArgumentTokens(tokens, stringLiteralPlaceholders);\n\n // The arguments of a retry node are optional. We may have:\n // - No node arguments, in which case the retry note will attempt indefinitely.\n // - One node argument which will be the explicit number of attempts to make.\n // - Two node arguments which define the min and max attempt bounds from which a random attempt count will be picked.\n if (nodeArguments.length) {\n // All retry node arguments MUST be of type number and must be integer.\n nodeArguments\n .filter((arg) => arg.type !== \"number\" || !arg.isInteger)\n .forEach(() => {\n throw new Error(`retry node attempt counts must be integer values`);\n });\n\n // We should have got one or two attempt counts.\n if (nodeArguments.length === 1) {\n // A static attempt count was defined.\n node.attempts = nodeArguments[0].value as number;\n\n // A retry node must have a positive number of attempts if defined.\n if (node.attempts < 0) {\n throw new Error(\"a retry node must have a positive number of attempts if defined\");\n }\n } else if (nodeArguments.length === 2) {\n // A minimum and maximum attempt count was defined.\n node.attempts = [nodeArguments[0].value as number, nodeArguments[1].value as number];\n\n // A retry node must have a positive min and max attempts count if they are defined.\n if (node.attempts[0] < 0 || node.attempts[1] < 0) {\n throw new Error(\"a retry node must have a positive minimum and maximum attempt count if defined\");\n }\n\n // A retry node must not have a minimum attempt count that exceeds the maximum attempt count.\n if (node.attempts[0] > node.attempts[1]) {\n throw new Error(\n \"a retry node must not have a minimum attempt count that exceeds the maximum attempt count\"\n );\n }\n } else {\n // An incorrect number of attempt counts was defined.\n throw new Error(\"invalid number of retry node attempt count arguments defined\");\n }\n }\n\n // Grab any node attribute definitions and spread them into the node definition.\n node = { ...node, ...parseAttributeTokens(tokens, stringLiteralPlaceholders) };\n\n // This is a decorator node, so we expect an opening '{'.\n popAndCheck(tokens, \"{\");\n\n // Return the retry node definition.\n return node;\n}\n\n/**\n * Creates a sequence node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The sequence node JSON definition.\n */\nfunction createSequenceNode(\n tokens: string[],\n stringLiteralPlaceholders: StringLiteralPlaceholders\n): SequenceNodeDefinition {\n const node = {\n type: \"sequence\",\n ...parseAttributeTokens(tokens, stringLiteralPlaceholders)\n } as SequenceNodeDefinition;\n\n // This is a composite node, so we expect an opening '{'.\n popAndCheck(tokens, \"{\");\n\n // Return the sequence node definition.\n return node;\n}\n\n/**\n * Creates a selector node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The selector node JSON definition.\n */\nfunction createSelectorNode(\n tokens: string[],\n stringLiteralPlaceholders: StringLiteralPlaceholders\n): SelectorNodeDefinition {\n const node = {\n type: \"selector\",\n ...parseAttributeTokens(tokens, stringLiteralPlaceholders)\n } as SelectorNodeDefinition;\n\n // This is a composite node, so we expect an opening '{'.\n popAndCheck(tokens, \"{\");\n\n // Return the selector node definition.\n return node;\n}\n\n/**\n * Creates a parallel node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The parallel node JSON definition.\n */\nfunction createParallelNode(\n tokens: string[],\n stringLiteralPlaceholders: StringLiteralPlaceholders\n): ParallelNodeDefinition {\n const node = {\n type: \"parallel\",\n ...parseAttributeTokens(tokens, stringLiteralPlaceholders)\n } as ParallelNodeDefinition;\n\n // This is a composite node, so we expect an opening '{'.\n popAndCheck(tokens, \"{\");\n\n // Return the parallel node definition.\n return node;\n}\n\n/**\n * Creates a lotto node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The lotto node JSON definition.\n */\nfunction createLottoNode(tokens: string[], stringLiteralPlaceholders: StringLiteralPlaceholders): LottoNodeDefinition {\n // If any node arguments have been defined then they must be our weights.\n const nodeArguments = parseArgumentTokens(tokens, stringLiteralPlaceholders);\n\n // All lotto node arguments MUST be of type number and must be positive integers.\n nodeArguments\n .filter((arg) => arg.type !== \"number\" || !arg.isInteger || arg.value < 0)\n .forEach(() => {\n throw new Error(`lotto node weight arguments must be positive integer values`);\n });\n\n const node = {\n type: \"lotto\",\n ...parseAttributeTokens(tokens, stringLiteralPlaceholders)\n } as LottoNodeDefinition;\n\n // Apply the weights if any were defined.\n if (nodeArguments.length) {\n node.weights = nodeArguments.map(({ value }) => value) as number[];\n }\n\n // This is a composite node, so we expect an opening '{'.\n popAndCheck(tokens, \"{\");\n\n // Return the lotto node definition.\n return node;\n}\n\n/**\n * Creates an action node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The action node JSON definition.\n */\nfunction createActionNode(\n tokens: string[],\n stringLiteralPlaceholders: StringLiteralPlaceholders\n): ActionNodeDefinition {\n // Parse any node arguments, we should have at least one which will be an identifier argument for the action name\n // and agent function to invoke for the action, all other arguments are to be passed as arguments to that function.\n const [actionNameIdentifier, ...agentFunctionArgs] = parseArgumentTokens(tokens, stringLiteralPlaceholders);\n\n // Our first argument MUST be defined and be an identifier as we require an action name argument.\n if (actionNameIdentifier?.type !== \"identifier\") {\n throw new Error(\"expected action name identifier argument\");\n }\n\n // Only the first argument should have been an identifier, all agent function arguments must be string, number, boolean or null.\n agentFunctionArgs\n .filter((arg) => arg.type === \"identifier\")\n .forEach((arg) => {\n throw new Error(\n `invalid action node argument value '${arg.value}', must be string, number, boolean or null`\n );\n });\n\n // Return the action node definition.\n return {\n type: \"action\",\n call: actionNameIdentifier.value,\n args: agentFunctionArgs.map(({ value }) => value),\n ...parseAttributeTokens(tokens, stringLiteralPlaceholders)\n };\n}\n\n/**\n * Creates a condition node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The condition node JSON definition.\n */\nfunction createConditionNode(\n tokens: string[],\n stringLiteralPlaceholders: StringLiteralPlaceholders\n): ConditionNodeDefinition {\n // Parse any node arguments, we should have at least one which will be an identifier argument for the condition name\n // and agent function to invoke for the condition, all other arguments are to be passed as arguments to that function.\n const [conditionNameIdentifier, ...agentFunctionArgs] = parseArgumentTokens(tokens, stringLiteralPlaceholders);\n\n // Our first argument MUST be defined and be an identifier as we require a condition name argument.\n if (conditionNameIdentifier?.type !== \"identifier\") {\n throw new Error(\"expected condition name identifier argument\");\n }\n\n // Only the first argument should have been an identifier, all agent function arguments must be string, number, boolean or null.\n agentFunctionArgs\n .filter((arg) => arg.type === \"identifier\")\n .forEach((arg) => {\n throw new Error(\n `invalid condition node argument value '${arg.value}', must be string, number, boolean or null`\n );\n });\n\n // Return the condition node definition.\n return {\n type: \"condition\",\n call: conditionNameIdentifier.value,\n args: agentFunctionArgs.map(({ value }) => value),\n ...parseAttributeTokens(tokens, stringLiteralPlaceholders)\n };\n}\n\n/**\n * Creates a wait node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The wait node JSON definition.\n */\nfunction createWaitNode(tokens: string[], stringLiteralPlaceholders: StringLiteralPlaceholders): WaitNodeDefinition {\n let node = { type: \"wait\" } as WaitNodeDefinition;\n\n // Get the node arguments.\n const nodeArguments = parseArgumentTokens(tokens, stringLiteralPlaceholders);\n\n // The arguments of a wait node are optional. We may have:\n // - No node arguments, in which case the wait will be indefinite until it is aborted.\n // - One node argument which will be the explicit duration of the wait.\n // - Two node arguments which define the min and max duration bounds from which a random duration will be picked.\n if (nodeArguments.length) {\n // All wait node arguments MUST be of type number and must be integer.\n nodeArguments\n .filter((arg) => arg.type !== \"number\" || !arg.isInteger)\n .forEach(() => {\n throw new Error(`wait node durations must be integer values`);\n });\n\n // We may have:\n // - One node argument which will be the explicit duration of the wait.\n // - Two node arguments which define the min and max duration bounds from which a random duration will be picked.\n // - Too many arguments, which is not valid.\n if (nodeArguments.length === 1) {\n // An explicit duration was defined.\n node.duration = nodeArguments[0].value as number;\n\n // If an explict duration was defined then it must be a positive number.\n if (node.duration < 0) {\n throw new Error(\"a wait node must have a positive duration\");\n }\n } else if (nodeArguments.length === 2) {\n // Min and max duration bounds were defined from which a random duration will be picked.\n node.duration = [nodeArguments[0].value as number, nodeArguments[1].value as number];\n\n // A wait node must have a positive min and max duration.\n if (node.duration[0] < 0 || node.duration[1] < 0) {\n throw new Error(\"a wait node must have a positive minimum and maximum duration\");\n }\n\n // A wait node must not have a minimum duration that exceeds the maximum duration.\n if (node.duration[0] > node.duration[1]) {\n throw new Error(\"a wait node must not have a minimum duration that exceeds the maximum duration\");\n }\n } else if (nodeArguments.length > 2) {\n // An incorrect number of duration arguments were defined.\n throw new Error(\"invalid number of wait node duration arguments defined\");\n }\n }\n\n // Return the wait node definition.\n return { ...node, ...parseAttributeTokens(tokens, stringLiteralPlaceholders) };\n}\n\n/**\n * Creates a branch node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The branch node JSON definition.\n */\nfunction createBranchNode(\n tokens: string[],\n stringLiteralPlaceholders: StringLiteralPlaceholders\n): BranchNodeDefinition {\n // Parse any node arguments, we should have one which will be an identifier argument for the root ref.\n const nodeArguments = parseArgumentTokens(tokens, stringLiteralPlaceholders);\n\n // We should have only a single identifer argument for a branch node, which is the root ref.\n if (nodeArguments.length !== 1 || nodeArguments[0].type !== \"identifier\") {\n throw new Error(\"expected single branch name argument\");\n }\n\n // Return the branch node definition.\n return { type: \"branch\", ref: nodeArguments[0].value };\n}\n\n/**\n * Validate a fully-populated node definition that was popped off of the tree stack.\n * @param definition The popped node to validate.\n */\nfunction validatePoppedNode(definition: AnyNodeDefinition): void {\n // Decorators MUST have a child defined.\n if (isDecoratorNode(definition) && isNullOrUndefined(definition.child)) {\n throw new Error(`a ${definition.type} node must have a single child node defined`);\n }\n\n // Composites MUST have at least one child defined.\n if (isCompositeNode(definition) && !definition.children?.length) {\n throw new Error(`a ${definition.type} node must have at least a single child node defined`);\n }\n\n // We need to make sure that lotto nodes that have weights defined have a number of weights matching the number of child nodes.\n if (definition.type === \"lotto\") {\n // Check whether a 'weights' property has been defined, if it has we expect it to be an array of weights.\n if (typeof definition.weights !== \"undefined\") {\n // Check that the weights property is an array of positive integers with an element for each child node element.\n if (definition.weights.length !== definition.children.length) {\n throw new Error(\n \"expected a number of weight arguments matching the number of child nodes for lotto node\"\n );\n }\n }\n }\n}\n", "import { RootNodeDefinition } from \"./BehaviourTreeDefinition\";\nimport { flattenDefinition, isBranchNode, isInteger } from \"./BehaviourTreeDefinitionUtilities\";\nimport { convertMDSLToJSON } from \"./mdsl/MDSLDefinitionParser\";\n\n/**\n * An object representing the result of validating a tree definition.\n */\nexport type DefinitionValidationResult = {\n /**\n * A flag defining whether validation succeeded.\n */\n succeeded: boolean;\n /**\n * A string containing the error message if validation did not succeed.\n */\n errorMessage?: string;\n /**\n * The definition as json if the validation was successful, or undefined if validation did not succeed.\n */\n json?: RootNodeDefinition[];\n};\n\n/**\n * Validates the specified behaviour tree definition in the form of JSON or MDSL, not taking any globally registered subtrees into consideration.\n * @param definition The behaviour tree definition in the form of JSON or MDSL.\n * @returns An object representing the result of validating the given tree definition.\n */\nexport function validateDefinition(definition: any): DefinitionValidationResult {\n // The definition must be defined.\n if (definition === null || typeof definition === \"undefined\") {\n return createValidationFailureResult(\"definition is null or undefined\");\n }\n\n // We are expecting a definition in one of three different forms:\n // - A string which we will assume is MDSL and we will parse this to JSON before validation.\n // - An array which we will assume is an array of root node definitions with at least one being the primary root node (no 'id' property)\n // - An object which we will assume is the primary root node and should not have an 'id' property.\n if (typeof definition === \"string\") {\n // The definition is a string which we can assume is MDSL, so attempt to validate it.\n return validateMDSLDefinition(definition);\n } else if (typeof definition === \"object\") {\n // The definition will either be an array (of root node definitions) or an object (the single primary root node definition).\n return validateJSONDefinition(definition);\n } else {\n return createValidationFailureResult(`unexpected definition type of '${typeof definition}'`);\n }\n}\n\n/**\n * Validates the specified behaviour tree definition in the form of MDSL.\n * @param definition The behaviour tree definition in the form of MDSL.\n * @returns An object representing the result of validating the given tree definition.\n */\nfunction validateMDSLDefinition(definition: string): DefinitionValidationResult {\n let rootNodeDefinitions;\n\n // The first thing the we need to do is to attempt to convert our MDSL into JSON.\n try {\n // The definition is a string which we can assume is MDSL, so attempt to parse it to a JSON definition in the form of an array of root node definitions.\n rootNodeDefinitions = convertMDSLToJSON(definition);\n } catch (exception) {\n // We failed to parse the JSON from the MDSL, this is likely to be the result of it not being a valid MDSL string.\n return createValidationFailureResult((exception as Error).message);\n }\n\n // Unpack all of the root node definitions into arrays of main ('id' defined) and sub ('id' not defined) root node definitions.\n const mainRootNodeDefinitions = rootNodeDefinitions.filter(({ id }) => typeof id === \"undefined\");\n const subRootNodeDefinitions = rootNodeDefinitions.filter(({ id }) => typeof id === \"string\" && id.length > 0);\n\n // We should ALWAYS have exactly one root node definition without an 'id' property defined, which is out main root node definition.\n if (mainRootNodeDefinitions.length !== 1) {\n return createValidationFailureResult(\n \"expected single unnamed root node at base of definition to act as main root\"\n );\n }\n\n // We should never have duplicate 'id' properties across our sub root node definitions.\n const subRootNodeIdenitifers: string[] = [];\n for (const { id } of subRootNodeDefinitions) {\n // Have we already come across this 'id' property value?\n if (subRootNodeIdenitifers.includes(id!)) {\n return createValidationFailureResult(`multiple root nodes found with duplicate name '${id}'`);\n }\n\n subRootNodeIdenitifers.push(id!);\n }\n\n try {\n // Validate our branch -> subtree links and check for any circular dependencies, we don't care about checking for broken subtree links here.\n validateBranchSubtreeLinks(rootNodeDefinitions, false);\n } catch (exception) {\n return createValidationFailureResult((exception as Error).message);\n }\n\n // Our definition was valid!\n return {\n succeeded: true,\n json: rootNodeDefinitions\n };\n}\n\n/**\n * Validates the specified behaviour tree definition in the form of JSON.\n * @param definition The behaviour tree definition in the form of JSON.\n * @returns An object representing the result of validating the given tree definition.\n */\nexport function validateJSONDefinition(\n definition: RootNodeDefinition | RootNodeDefinition[]\n): DefinitionValidationResult {\n // The definition will either be an array (of root node definitions) or an object (the single primary root node definition).\n const rootNodeDefinitions = Array.isArray(definition) ? definition : [definition];\n\n // Iterate over our array of root nodes and call validateNode for each, passing an initial depth of 0, wrapped in a try catch to handle validation failures.\n try {\n rootNodeDefinitions.forEach((rootNodeDefinition) => validateNode(rootNodeDefinition, 0));\n } catch (error) {\n // Handle cases where we have caught a thrown Error and return a failure result with the error message.\n if (error instanceof Error) {\n return createValidationFailureResult(error.message);\n }\n\n // No idea what happened here!\n return createValidationFailureResult(`unexpected error: ${error}`);\n }\n\n // Unpack all of the root node definitions into arrays of main ('id' defined) and sub ('id' not defined) root node definitions.\n const mainRootNodeDefinitions = rootNodeDefinitions.filter(({ id }) => typeof id === \"undefined\");\n const subRootNodeDefinitions = rootNodeDefinitions.filter(({ id }) => typeof id === \"string\" && id.length > 0);\n\n // We should ALWAYS have exactly one root node definition without an 'id' property defined, which is out main root node definition.\n if (mainRootNodeDefinitions.length !== 1) {\n return createValidationFailureResult(\n \"expected single root node without 'id' property defined to act as main root\"\n );\n }\n\n // We should never have duplicate 'id' properties across our sub root node definitions.\n const subRootNodeIdenitifers: string[] = [];\n for (const { id } of subRootNodeDefinitions) {\n // Have we already come across this 'id' property value?\n if (subRootNodeIdenitifers.includes(id!)) {\n return createValidationFailureResult(\n `multiple root nodes found with duplicate 'id' property value of '${id}'`\n );\n }\n\n subRootNodeIdenitifers.push(id!);\n }\n\n try {\n // Validate our branch -> subtree links and check for any circular dependencies, we don't care about checking for broken subtree links here.\n validateBranchSubtreeLinks(rootNodeDefinitions, false);\n } catch (exception) {\n return createValidationFailureResult((exception as Error).message);\n }\n\n // Our definition was valid!\n return {\n succeeded: true,\n json: rootNodeDefinitions\n };\n}\n\n/**\n * Validates the branch -> subtree links across all provided root node definitions.\n * This will not consider branch nodes that reference any globally registered subtrees unless includesGlobalSubtrees\n * is set to true, in which case we will also verify that there are no broken branch -> subtree links.\n * @param rootNodeDefinitions The array of root node definitions.\n * @param includesGlobalSubtrees A flag defining whether the array includes all global subtree root node definitions.\n */\nexport function validateBranchSubtreeLinks(rootNodeDefinitions: RootNodeDefinition[], includesGlobalSubtrees: boolean) {\n // Create a mapping of root node identifiers to other root nodes that they reference via branch nodes.\n // Below is an example of a mapping that includes a circular dependency (root => a => b => c => a)\n // [{ refs: [\"a\", \"b\"] }, { id: \"a\", refs: [\"b\"] }, { id: \"b\", refs: [\"c\"] }, { id: \"c\", refs: [\"a\"] }]\n const rootNodeMappings: { id: string | undefined; refs: string[] }[] = rootNodeDefinitions.map(\n (rootNodeDefinition) => ({\n id: rootNodeDefinition.id,\n refs: flattenDefinition(rootNodeDefinition)\n .filter(isBranchNode)\n .map(({ ref }) => ref)\n })\n );\n\n // A recursive function to walk through the mappings, keeping track of which root nodes we have visited in the form of a path of root node identifiers.\n const followRefs = (mapping: { id: string | undefined; refs: string[] }, path: (string | undefined)[] = []) => {\n // Have we found a circular dependency?\n if (path.includes(mapping.id)) {\n // We found a circular dependency! Get the bad path of root node identifiers.\n const badPath = [...path, mapping.id];\n\n // Create the formatted path value. [undefined, \"a\", \"b\", \"c\", \"a\"] would be formatted as \"a -> b -> c -> a\".\n const badPathFormatted = badPath.filter((element) => !!element).join(\" => \");\n\n // No need to continue, we found a circular dependency.\n throw new Error(`circular dependency found in branch node references: ${badPathFormatted}`);\n }\n\n for (const ref of mapping.refs) {\n // Find the mapping for the root node with an identifer matching the current ref.\n const subMapping = rootNodeMappings.find(({ id }) => id === ref);\n\n // We may not have a mapping for this ref, which is normal when we aren't considering all globally registered subtrees.\n if (subMapping) {\n followRefs(subMapping, [...path, mapping.id]);\n } else if (includesGlobalSubtrees) {\n // We found a reference to a root node that doesn't exist, which is a problem seeing as the root node definitons includes all globally registered subtrees.\n throw new Error(\n mapping.id\n ? `subtree '${mapping.id}' has branch node that references root node '${ref}' which has not been defined`\n : `primary tree has branch node that references root node '${ref}' which has not been defined`\n );\n }\n }\n };\n\n // Start looking for circular dependencies and broken references from the primary root node definition.\n followRefs(rootNodeMappings.find((mapping) => typeof mapping.id === \"undefined\")!);\n}\n\n/**\n * Validate an object that we expect to be a node definition.\n * @param definition An object that we expect to be a node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateNode(definition: any, depth: number): void {\n // Every node must be valid object and have a non-empty 'type' string property.\n if (typeof definition !== \"object\" || typeof definition.type !== \"string\" || definition.type.length === 0) {\n throw new Error(\n `node definition is not an object or 'type' property is not a non-empty string at depth '${depth}'`\n );\n }\n\n // How we validate this node definition will depend on its type.\n switch (definition.type) {\n case \"action\":\n validateActionNode(definition, depth);\n break;\n\n case \"condition\":\n validateConditionNode(definition, depth);\n break;\n\n case \"wait\":\n validateWaitNode(definition, depth);\n break;\n\n case \"branch\":\n validateBranchNode(definition, depth);\n break;\n\n case \"root\":\n validateRootNode(definition, depth);\n break;\n\n case \"succeed\":\n validateSucceedNode(definition, depth);\n break;\n\n case \"fail\":\n validateFailNode(definition, depth);\n break;\n\n case \"flip\":\n validateFlipNode(definition, depth);\n break;\n\n case \"repeat\":\n validateRepeatNode(definition, depth);\n break;\n\n case \"retry\":\n validateRetryNode(definition, depth);\n break;\n\n case \"sequence\":\n validateSequenceNode(definition, depth);\n break;\n\n case \"selector\":\n validateSelectorNode(definition, depth);\n break;\n\n case \"parallel\":\n validateParallelNode(definition, depth);\n break;\n\n case \"lotto\":\n validateLottoNode(definition, depth);\n break;\n\n default:\n throw new Error(`unexpected node type of '${definition.type}' at depth '${depth}'`);\n }\n}\n\n/**\n * Validate any attributes for a given node definition.\n * @param definition The node definition.\n * @param depth The depth of the node in the behaviour tree definition.\n */\nfunction validateNodeAttributes(definition: any, depth: number): void {\n // Validate each of the attribute types for this node.\n [\"while\", \"until\", \"entry\", \"exit\", \"step\"].forEach((attributeName) => {\n // Attempt to grab the definition for the current attribute from the node definition.\n const attributeDefinition = definition[attributeName];\n\n // All node attributes are optional, so there is nothing to do if the current attribute is not defined.\n if (typeof attributeDefinition === \"undefined\") {\n return;\n }\n\n // The attribute definition must be an object.\n if (typeof attributeDefinition !== \"object\") {\n throw new Error(\n `expected attribute '${attributeName}' to be an object for '${definition.type}' node at depth '${depth}'`\n );\n }\n\n // The 'call' property must be defined for any attribute definition.\n if (typeof attributeDefinition.call !== \"string\" || attributeDefinition.call.length === 0) {\n throw new Error(\n `expected 'call' property for attribute '${attributeName}' to be a non-empty string for '${definition.type}' node at depth '${depth}'`\n );\n }\n\n // If any node attribute arguments have been defined then they must have been defined in an array.\n if (typeof attributeDefinition.args !== \"undefined\" && !Array.isArray(attributeDefinition.args)) {\n throw new Error(\n `expected 'args' property for attribute '${attributeName}' to be an array for '${definition.type}' node at depth '${depth}'`\n );\n }\n });\n}\n\n/**\n * Validate an object that we expect to be a root node definition.\n * @param definition An object that we expect to be a root node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateRootNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"root\") {\n throw new Error(\"expected node type of 'root' for root node\");\n }\n\n // A root node cannot be the child of another node.\n if (depth > 0) {\n throw new Error(\"a root node cannot be the child of another node\");\n }\n\n // Check that, if the root node 'id' property is defined, it is a non-empty string.\n if (typeof definition.id !== \"undefined\" && (typeof definition.id !== \"string\" || definition.id.length === 0)) {\n throw new Error(\"expected non-empty string for 'id' property if defined for root node\");\n }\n\n // A root node is a decorator node, so must have a child node defined.\n if (typeof definition.child === \"undefined\") {\n throw new Error(\"expected property 'child' to be defined for root node\");\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n\n // Validate the child node of this decorator node.\n validateNode(definition.child, depth + 1);\n}\n\n/**\n * Validate an object that we expect to be a succeed node definition.\n * @param definition An object that we expect to be a succeed node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateSucceedNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"succeed\") {\n throw new Error(`expected node type of 'succeed' for succeed node at depth '${depth}'`);\n }\n\n // A succeed node is a decorator node, so must have a child node defined.\n if (typeof definition.child === \"undefined\") {\n throw new Error(`expected property 'child' to be defined for succeed node at depth '${depth}'`);\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n\n // Validate the child node of this decorator node.\n validateNode(definition.child, depth + 1);\n}\n\n/**\n * Validate an object that we expect to be a fail node definition.\n * @param definition An object that we expect to be a fail node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateFailNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"fail\") {\n throw new Error(`expected node type of 'fail' for fail node at depth '${depth}'`);\n }\n\n // A fail node is a decorator node, so must have a child node defined.\n if (typeof definition.child === \"undefined\") {\n throw new Error(`expected property 'child' to be defined for fail node at depth '${depth}'`);\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n\n // Validate the child node of this decorator node.\n validateNode(definition.child, depth + 1);\n}\n\n/**\n * Validate an object that we expect to be a flip node definition.\n * @param definition An object that we expect to be a flip node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateFlipNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"flip\") {\n throw new Error(`expected node type of 'flip' for flip node at depth '${depth}'`);\n }\n\n // A flip node is a decorator node, so must have a child node defined.\n if (typeof definition.child === \"undefined\") {\n throw new Error(`expected property 'child' to be defined for flip node at depth '${depth}'`);\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n\n // Validate the child node of this decorator node.\n validateNode(definition.child, depth + 1);\n}\n\n/**\n * Validate an object that we expect to be a repeat node definition.\n * @param definition An object that we expect to be a repeat node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateRepeatNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"repeat\") {\n throw new Error(`expected node type of 'repeat' for repeat node at depth '${depth}'`);\n }\n\n // A repeat node is a decorator node, so must have a child node defined.\n if (typeof definition.child === \"undefined\") {\n throw new Error(`expected property 'child' to be defined for repeat node at depth '${depth}'`);\n }\n\n // Check whether an 'iterations' property has been defined, it may not have been if this node is to repeat indefinitely.\n if (typeof definition.iterations !== \"undefined\") {\n if (Array.isArray(definition.iterations)) {\n // Check whether any elements of the array are not integer values.\n const containsNonInteger = !!definition.iterations.filter((value: unknown) => !isInteger(value)).length;\n\n // If the 'iterations' property is an array then it MUST contain two integer values.\n if (definition.iterations.length !== 2 || containsNonInteger) {\n throw new Error(\n `expected array containing two integer values for 'iterations' property if defined for repeat node at depth '${depth}'`\n );\n }\n\n // A repeat node must have a positive min and max iterations count if they are defined.\n if (definition.iterations[0] < 0 || definition.iterations[1] < 0) {\n throw new Error(\n `expected positive minimum and maximum iterations count for 'iterations' property if defined for repeat node at depth '${depth}'`\n );\n }\n\n // A repeat node must not have a minimum iterations count that exceeds the maximum iterations count.\n if (definition.iterations[0] > definition.iterations[1]) {\n throw new Error(\n `expected minimum iterations count that does not exceed the maximum iterations count for 'iterations' property if defined for repeat node at depth '${depth}'`\n );\n }\n } else if (isInteger(definition.iterations)) {\n // A repeat node must have a positive number of iterations if defined.\n if (definition.iterations < 0) {\n throw new Error(\n `expected positive iterations count for 'iterations' property if defined for repeat node at depth '${depth}'`\n );\n }\n } else {\n throw new Error(\n `expected integer value or array containing two integer values for 'iterations' property if defined for repeat node at depth '${depth}'`\n );\n }\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n\n // Validate the child node of this decorator node.\n validateNode(definition.child, depth + 1);\n}\n\n/**\n * Validate an object that we expect to be a retry node definition.\n * @param definition An object that we expect to be a retry node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateRetryNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"retry\") {\n throw new Error(`expected node type of 'retry' for retry node at depth '${depth}'`);\n }\n\n // A retry node is a decorator node, so must have a child node defined.\n if (typeof definition.child === \"undefined\") {\n throw new Error(`expected property 'child' to be defined for retry node at depth '${depth}'`);\n }\n\n // Check whether an 'attempts' property has been defined, it may not have been if this node is to retry indefinitely.\n if (typeof definition.attempts !== \"undefined\") {\n if (Array.isArray(definition.attempts)) {\n // Check whether any elements of the array are not integer values.\n const containsNonInteger = !!definition.attempts.filter((value: unknown) => !isInteger(value)).length;\n\n // If the 'attempts' property is an array then it MUST contain two integer values.\n if (definition.attempts.length !== 2 || containsNonInteger) {\n throw new Error(\n `expected array containing two integer values for 'attempts' property if defined for retry node at depth '${depth}'`\n );\n }\n\n // A retry node must have a positive min and max attempts count if they are defined.\n if (definition.attempts[0] < 0 || definition.attempts[1] < 0) {\n throw new Error(\n `expected positive minimum and maximum attempts count for 'attempts' property if defined for retry node at depth '${depth}'`\n );\n }\n\n // A retry node must not have a minimum attempts count that exceeds the maximum attempts count.\n if (definition.attempts[0] > definition.attempts[1]) {\n throw new Error(\n `expected minimum attempts count that does not exceed the maximum attempts count for 'attempts' property if defined for retry node at depth '${depth}'`\n );\n }\n } else if (isInteger(definition.attempts)) {\n // A retry node must have a positive number of attempts if defined.\n if (definition.attempts < 0) {\n throw new Error(\n `expected positive attempts count for 'attempts' property if defined for retry node at depth '${depth}'`\n );\n }\n } else {\n throw new Error(\n `expected integer value or array containing two integer values for 'attempts' property if defined for retry node at depth '${depth}'`\n );\n }\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n\n // Validate the child node of this decorator node.\n validateNode(definition.child, depth + 1);\n}\n\n/**\n * Validate an object that we expect to be a branch node definition.\n * @param definition An object that we expect to be a branch node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateBranchNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"branch\") {\n throw new Error(`expected node type of 'branch' for branch node at depth '${depth}'`);\n }\n\n // Check that the branch node 'ref' property is defined and is a non-empty string.\n if (typeof definition.ref !== \"string\" || definition.ref.length === 0) {\n throw new Error(`expected non-empty string for 'ref' property for branch node at depth '${depth}'`);\n }\n\n // It is invalid to define guard attributes for a branch node as they should be defined on the referenced root node.\n [\"while\", \"until\"].forEach((attributeName) => {\n if (typeof definition[attributeName] !== \"undefined\") {\n throw new Error(\n `guards should not be defined for branch nodes but guard '${attributeName}' was defined for branch node at depth '${depth}'`\n );\n }\n });\n\n // It is invalid to define callback attributes for a branch node as they should be defined on the referenced root node.\n [\"entry\", \"exit\", \"step\"].forEach((attributeName) => {\n if (typeof definition[attributeName] !== \"undefined\") {\n throw new Error(\n `callbacks should not be defined for branch nodes but callback '${attributeName}' was defined for branch node at depth '${depth}'`\n );\n }\n });\n}\n\n/**\n * Validate an object that we expect to be a action node definition.\n * @param definition An object that we expect to be a action node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateActionNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"action\") {\n throw new Error(`expected node type of 'action' for action node at depth '${depth}'`);\n }\n\n // The 'call' property must be defined for a action node definition.\n if (typeof definition.call !== \"string\" || definition.call.length === 0) {\n throw new Error(`expected non-empty string for 'call' property of action node at depth '${depth}'`);\n }\n\n // If any action function arguments have been defined then they must have been defined in an array.\n if (typeof definition.args !== \"undefined\" && !Array.isArray(definition.args)) {\n throw new Error(`expected array for 'args' property if defined for action node at depth '${depth}'`);\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n}\n\n/**\n * Validate an object that we expect to be a condition node definition.\n * @param definition An object that we expect to be a condition node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateConditionNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"condition\") {\n throw new Error(`expected node type of 'condition' for condition node at depth '${depth}'`);\n }\n\n // The 'call' property must be defined for a condition node definition.\n if (typeof definition.call !== \"string\" || definition.call.length === 0) {\n throw new Error(`expected non-empty string for 'call' property of condition node at depth '${depth}'`);\n }\n\n // If any condition function arguments have been defined then they must have been defined in an array.\n if (typeof definition.args !== \"undefined\" && !Array.isArray(definition.args)) {\n throw new Error(`expected array for 'args' property if defined for condition node at depth '${depth}'`);\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n}\n\n/**\n * Validate an object that we expect to be a wait node definition.\n * @param definition An object that we expect to be a wait node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateWaitNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"wait\") {\n throw new Error(`expected node type of 'wait' for wait node at depth '${depth}'`);\n }\n\n // Check whether a 'duration' property has been defined, it may not have been if this node is to wait indefinitely.\n if (typeof definition.duration !== \"undefined\") {\n if (Array.isArray(definition.duration)) {\n // Check whether any elements of the array are not integer values.\n const containsNonInteger = !!definition.duration.filter((value: unknown) => !isInteger(value)).length;\n\n // If the 'duration' property is an array then it MUST contain two integer values.\n if (definition.duration.length !== 2 || containsNonInteger) {\n throw new Error(\n `expected array containing two integer values for 'duration' property if defined for wait node at depth '${depth}'`\n );\n }\n\n // A wait node must have a positive min and max duration value if they are defined.\n if (definition.duration[0] < 0 || definition.duration[1] < 0) {\n throw new Error(\n `expected positive minimum and maximum duration for 'duration' property if defined for wait node at depth '${depth}'`\n );\n }\n\n // A wait node must not have a minimum duration value that exceeds the maximum duration value.\n if (definition.duration[0] > definition.duration[1]) {\n throw new Error(\n `expected minimum duration value that does not exceed the maximum duration value for 'duration' property if defined for wait node at depth '${depth}'`\n );\n }\n } else if (isInteger(definition.duration)) {\n // A wait node must have a positive duration value if defined.\n if (definition.duration < 0) {\n throw new Error(\n `expected positive duration value for 'duration' property if defined for wait node at depth '${depth}'`\n );\n }\n } else {\n throw new Error(\n `expected integer value or array containing two integer values for 'duration' property if defined for wait node at depth '${depth}'`\n );\n }\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n}\n\n/**\n * Validate an object that we expect to be a sequence node definition.\n * @param definition An object that we expect to be a sequence node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateSequenceNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"sequence\") {\n throw new Error(`expected node type of 'sequence' for sequence node at depth '${depth}'`);\n }\n\n // A sequence node is a composite node, so must have a children nodes array defined.\n if (!Array.isArray(definition.children) || definition.children.length === 0) {\n throw new Error(`expected non-empty 'children' array to be defined for sequence node at depth '${depth}'`);\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n\n // Validate the child nodes of this composite node.\n definition.children.forEach((child: any) => validateNode(child, depth + 1));\n}\n\n/**\n * Validate an object that we expect to be a selector node definition.\n * @param definition An object that we expect to be a selector node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateSelectorNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"selector\") {\n throw new Error(`expected node type of 'selector' for selector node at depth '${depth}'`);\n }\n\n // A selector node is a composite node, so must have a children nodes array defined.\n if (!Array.isArray(definition.children) || definition.children.length === 0) {\n throw new Error(`expected non-empty 'children' array to be defined for selector node at depth '${depth}'`);\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n\n // Validate the child nodes of this composite node.\n definition.children.forEach((child: any) => validateNode(child, depth + 1));\n}\n\n/**\n * Validate an object that we expect to be a parallel node definition.\n * @param definition An object that we expect to be a parallel node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateParallelNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"parallel\") {\n throw new Error(`expected node type of 'parallel' for parallel node at depth '${depth}'`);\n }\n\n // A parallel node is a composite node, so must have a children nodes array defined.\n if (!Array.isArray(definition.children) || definition.children.length === 0) {\n throw new Error(`expected non-empty 'children' array to be defined for parallel node at depth '${depth}'`);\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n\n // Validate the child nodes of this composite node.\n definition.children.forEach((child: any) => validateNode(child, depth + 1));\n}\n\n/**\n * Validate an object that we expect to be a lotto node definition.\n * @param definition An object that we expect to be a lotto node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateLottoNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"lotto\") {\n throw new Error(`expected node type of 'lotto' for lotto node at depth '${depth}'`);\n }\n\n // A lotto node is a composite node, so must have a children nodes array defined.\n if (!Array.isArray(definition.children) || definition.children.length === 0) {\n throw new Error(`expected non-empty 'children' array to be defined for lotto node at depth '${depth}'`);\n }\n\n // Check whether a 'weights' property has been defined, if it has we expect it to be an array of weights.\n if (typeof definition.weights !== \"undefined\") {\n // Check that the weights property is an array of positive integers with an element for each child node element.\n if (\n !Array.isArray(definition.weights) ||\n definition.weights.length !== definition.children.length ||\n definition.weights.filter((value: unknown) => !isInteger(value)).length ||\n definition.weights.filter((value: number) => value < 0).length\n ) {\n throw new Error(\n `expected an array of positive integer weight values with a length matching the number of child nodes for 'weights' property if defined for lotto node at depth '${depth}'`\n );\n }\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n\n // Validate the child nodes of this composite node.\n definition.children.forEach((child: any) => validateNode(child, depth + 1));\n}\n\n/**\n * A helper function to create a failure validation result with the given error message.\n * @param errorMessage The validation failure error message.\n * @returns A failure validation result with the given error message.\n */\nfunction createValidationFailureResult(errorMessage: string): DefinitionValidationResult {\n return { succeeded: false, errorMessage };\n}\n", "import { ActionResult, Agent, GlobalFunction } from \"./Agent\";\nimport { RootNodeDefinition } from \"./BehaviourTreeDefinition\";\n\nexport type InvokerFunction = (args: any[]) => ActionResult | boolean;\n\n/**\n * A singleton used to store and lookup registered functions and subtrees.\n */\nexport default class Lookup {\n /**\n * The object holding any registered functions keyed on function name.\n */\n private static registeredFunctions: { [key: string]: GlobalFunction } = {};\n /**\n * The object holding any registered subtree root node definitions keyed on tree name.\n */\n private static registeredSubtrees: { [key: string]: RootNodeDefinition } = {};\n\n /**\n * Gets the function with the specified name.\n * @param name The name of the function.\n * @returns The function with the specified name.\n */\n public static getFunc(name: string): GlobalFunction {\n return this.registeredFunctions[name];\n }\n\n /**\n * Sets the function with the specified name for later lookup.\n * @param name The name of the function.\n * @param func The function.\n */\n public static setFunc(name: string, func: GlobalFunction): void {\n this.registeredFunctions[name] = func;\n }\n\n /**\n * Gets the function invoker for the specified agent and function name.\n * If a function with the specified name exists on the agent object then it will\n * be returned, otherwise we will then check the registered functions for a match.\n * @param agent The agent instance that this behaviour tree is modelling behaviour for.\n * @param name The function name.\n * @returns The function invoker for the specified agent and function name.\n */\n static getFuncInvoker(agent: Agent, name: string): InvokerFunction | null {\n // Check whether the agent contains the specified function.\n const agentFunction = agent[name];\n if (agentFunction && typeof agentFunction === \"function\") {\n return (args: any[]) => agentFunction.apply(agent, args);\n }\n\n // The agent does not contain the specified function but it may have been registered at some point.\n if (this.registeredFunctions[name] && typeof this.registeredFunctions[name] === \"function\") {\n const registeredFunction = this.registeredFunctions[name];\n return (args: any[]) => registeredFunction(agent, ...args.map((arg) => arg.value));\n }\n\n // We have no function to invoke.\n return null;\n }\n\n /**\n * Gets all registered subtree root node definitions.\n */\n static getSubtrees(): { [key: string]: RootNodeDefinition } {\n return this.registeredSubtrees;\n }\n\n /**\n * Sets the subtree with the specified name for later lookup.\n * @param name The name of the subtree.\n * @param subtree The subtree.\n */\n static setSubtree(name: string, subtree: RootNodeDefinition) {\n this.registeredSubtrees[name] = subtree;\n }\n\n /**\n * Removes the registered function or subtree with the specified name.\n * @param name The name of the registered function or subtree.\n */\n static remove(name: string) {\n delete this.registeredFunctions[name];\n delete this.registeredSubtrees[name];\n }\n\n /**\n * Remove all registered functions and subtrees.\n */\n static empty() {\n this.registeredFunctions = {};\n this.registeredSubtrees = {};\n }\n}\n", "import Node from \"../../nodes/Node\";\n\n/**\n * An exception thrown when evaluating node guard path conditions and a conditions fails.\n */\nexport default class GuardUnsatisifedException extends Error {\n /**\n * @param source The node at which a guard condition failed.\n */\n constructor(private source: Node) {\n super(\"A guard path condition has failed\");\n }\n\n /**\n * Gets whether the specified node is the node at which a guard condition failed.\n * @param node The node to check against the source node.\n * @returns Whether the specified node is the node at which a guard condition failed.\n */\n isSourceNode = (node: Node) => node === this.source;\n}\n", "import { Agent } from \"../../Agent\";\nimport Guard from \"./Guard\";\nimport Node from \"../../nodes/Node\";\nimport GuardUnsatisifedException from \"./GuardUnsatisifedException\";\n\nexport type GuardPathPart = {\n node: Node;\n guards: Guard[];\n};\n\n/**\n * Represents a path of node guards along a root-to-leaf tree path.\n */\nexport default class GuardPath {\n /**\n * @param nodes An array of objects defining a node instance -> guard link, ordered by node depth.\n */\n constructor(private nodes: GuardPathPart[]) {}\n\n /**\n * Evaluate guard conditions for all guards in the tree path, moving outwards from the root.\n * @param agent The agent, required for guard evaluation.\n * @returns An evaluation results object.\n */\n evaluate = (agent: Agent) => {\n // We need to evaluate guard conditions for nodes up the tree, moving outwards from the root.\n for (const details of this.nodes) {\n // There can be multiple guards per node.\n for (const guard of details.guards) {\n // Check whether the guard condition passes, and throw an exception if not.\n if (!guard.isSatisfied(agent)) {\n throw new GuardUnsatisifedException(details.node);\n }\n }\n }\n };\n}\n", "import { BehaviourTreeOptions } from \"../BehaviourTreeOptions\";\nimport State, { AnyState } from \"../State\";\nimport { Agent } from \"../Agent\";\nimport Leaf from \"./leaf/Leaf\";\nimport Attribute from \"../attributes/Attribute\";\nimport Entry from \"../attributes/callbacks/Entry\";\nimport Exit from \"../attributes/callbacks/Exit\";\nimport Step from \"../attributes/callbacks/Step\";\nimport Guard from \"../attributes/guards/Guard\";\nimport GuardPath from \"../attributes/guards/GuardPath\";\nimport GuardUnsatisifedException from \"../attributes/guards/GuardUnsatisifedException\";\n\n/**\n * A base node.\n */\nexport default abstract class Node {\n /**\n * The node uid.\n */\n private readonly uid: string = createNodeUid();\n /**\n * The node state.\n */\n private state: AnyState = State.READY;\n /**\n * The guard path to evaluate as part of a node update.\n */\n private guardPath: GuardPath | undefined;\n\n /**\n * @param type The node type.\n * @param attributes The node attributes.\n * @param args The node argument definitions.\n */\n constructor(private type: string, private attributes: Attribute[], private args: any[]) {}\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected abstract onUpdate(agent: Agent, options: BehaviourTreeOptions): void;\n\n /**\n * Gets the name of the node.\n */\n public abstract getName(): string;\n\n /**\n * Gets whether this node is a leaf node.\n */\n public abstract isLeafNode: () => this is Leaf;\n\n /**\n * Gets/Sets the state of the node.\n */\n getState = (): AnyState => this.state;\n setState = (value: AnyState): void => {\n this.state = value;\n };\n\n /**\n * Gets the unique id of the node.\n */\n getUid = () => this.uid;\n\n /**\n * Gets the type of the node.\n */\n getType = () => this.type;\n\n /**\n * Gets the node attributes.\n */\n getAttributes = () => this.attributes;\n\n /**\n * Gets the node arguments.\n */\n getArguments = () => this.args;\n\n /**\n * Gets the node attribute with the specified type, or null if it does not exist.\n */\n getAttribute(type: \"entry\" | \"ENTRY\"): Entry;\n getAttribute(type: \"exit\" | \"EXIT\"): Exit;\n getAttribute(type: \"step\" | \"STEP\"): Step;\n getAttribute(type: string): Attribute {\n return (\n this.getAttributes().filter((decorator) => decorator.type.toUpperCase() === type.toUpperCase())[0] || null\n );\n }\n\n /**\n * Gets the node attributes.\n */\n getGuardAttributes = (): Guard[] => this.getAttributes().filter((decorator) => decorator.isGuard()) as Guard[];\n\n /**\n * Sets the guard path to evaluate as part of a node update.\n */\n setGuardPath = (value: GuardPath) => (this.guardPath = value);\n\n /**\n * Gets whether a guard path is assigned to this node.\n */\n hasGuardPath = () => !!this.guardPath;\n\n /**\n * Gets whether this node is in the specified state.\n * @param value The value to compare to the node state.\n */\n public is(value: AnyState): boolean {\n return this.state === value;\n }\n\n /**\n * Reset the state of the node.\n */\n public reset(): void {\n this.setState(State.READY);\n }\n\n /**\n * Abort the running of this node.\n * @param agent The agent.\n */\n public abort(agent: Agent): void {\n // There is nothing to do if this node is not in the running state.\n if (!this.is(State.RUNNING)) {\n return;\n }\n\n // Reset the state of this node.\n this.reset();\n\n this.getAttribute(\"exit\")?.callAgentFunction(agent, false, true);\n }\n\n /**\n * Update the node.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n * @returns The result of the update.\n */\n public update(agent: Agent, options: BehaviourTreeOptions): void {\n // If this node is already in a 'SUCCEEDED' or 'FAILED' state then there is nothing to do.\n if (this.is(State.SUCCEEDED) || this.is(State.FAILED)) {\n return;\n }\n\n try {\n // Evaluate all of the guard path conditions for the current tree path.\n this.guardPath!.evaluate(agent);\n\n // If this node is in the READY state then call the ENTRY for this node if it exists.\n if (this.is(State.READY)) {\n this.getAttribute(\"entry\")?.callAgentFunction(agent);\n }\n\n this.getAttribute(\"step\")?.callAgentFunction(agent);\n\n // Do the actual update.\n this.onUpdate(agent, options);\n\n // If this node is now in a 'SUCCEEDED' or 'FAILED' state then call the EXIT for this node if it exists.\n if (this.is(State.SUCCEEDED) || this.is(State.FAILED)) {\n this.getAttribute(\"exit\")?.callAgentFunction(agent, this.is(State.SUCCEEDED), false);\n }\n } catch (error) {\n // If the error is a GuardUnsatisfiedException then we need to determine if this node is the source.\n if (error instanceof GuardUnsatisifedException && error.isSourceNode(this)) {\n // Abort the current node.\n this.abort(agent);\n\n // Any node that is the source of an abort will be a failed node.\n this.setState(State.FAILED);\n } else {\n throw error;\n }\n }\n }\n}\n\n/**\n * Create a randomly generated node uid.\n * @returns A randomly generated node uid.\n */\nfunction createNodeUid(): string {\n var S4 = function () {\n return (((1 + Math.random()) * 0x10000) | 0).toString(16).substring(1);\n };\n return S4() + S4() + \"-\" + S4() + \"-\" + S4() + \"-\" + S4() + \"-\" + S4() + S4() + S4();\n}\n", "import Node from \"../Node\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\n\n/**\n * A composite node that wraps child nodes.\n */\nexport default abstract class Composite extends Node {\n /**\n * @param type The node type.\n * @param attributes The node attributes.\n * @param children The child nodes.\n */\n constructor(type: string, attributes: Attribute[], protected children: Node[]) {\n super(type, attributes, []);\n }\n\n /**\n * Gets whether this node is a leaf node.\n */\n isLeafNode = () => false;\n\n /**\n * Gets the children of this node.\n */\n getChildren = () => this.children;\n\n /**\n * Reset the state of the node.\n */\n reset = () => {\n // Reset the state of this node.\n this.setState(State.READY);\n\n // Reset the state of any child nodes.\n this.getChildren().forEach((child) => child.reset());\n };\n\n /**\n * Abort the running of this node.\n * @param agent The agent.\n */\n abort = (agent: Agent) => {\n // There is nothing to do if this node is not in the running state.\n if (!this.is(State.RUNNING)) {\n return;\n }\n\n // Abort any child nodes.\n this.getChildren().forEach((child) => child.abort(agent));\n\n // Reset the state of this node.\n this.reset();\n\n this.getAttribute(\"exit\")?.callAgentFunction(agent, false, true);\n };\n}\n", "import Composite from \"./Composite\";\nimport State from \"../../State\";\nimport Node from \"../Node\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A PARALLEL node.\n * The child nodes are executed concurrently until one fails or all succeed.\n */\nexport default class Parallel extends Composite {\n /**\n * @param attributes The node attributes.\n * @param children The child nodes.\n */\n constructor(attributes: Attribute[], children: Node[]) {\n super(\"parallel\", attributes, children);\n }\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // Keep a count of the number of succeeded child nodes.\n let succeededCount = 0;\n\n let hasChildFailed = false;\n\n // Iterate over all of the children of this node.\n for (const child of this.children) {\n // If the child has never been updated or is running then we will need to update it now.\n if (child.getState() === State.READY || child.getState() === State.RUNNING) {\n // Update the child of this node.\n child.update(agent, options);\n }\n\n // If the current child has a state of 'SUCCEEDED' then we should move on to the next child.\n if (child.getState() === State.SUCCEEDED) {\n // The child node has succeeded, keep track of this to determine if all children have.\n succeededCount++;\n\n // The child node succeeded, but we have not finished checking every child node yet.\n continue;\n }\n\n // If the current child has a state of 'FAILED' then this node is also a 'FAILED' node.\n if (child.getState() === State.FAILED) {\n hasChildFailed = true;\n\n // There is no need to check the rest of the children.\n break;\n }\n\n // The node should be in the 'RUNNING' state.\n if (child.getState() !== State.RUNNING) {\n // The child node was not in an expected state.\n throw new Error(\"child node was not in an expected state.\");\n }\n }\n\n if (hasChildFailed) {\n // This node is a 'FAILED' node.\n this.setState(State.FAILED);\n\n // Abort every running child.\n for (const child of this.children) {\n if (child.getState() === State.RUNNING) {\n child.abort(agent);\n }\n }\n } else {\n // If all children have succeeded then this node has also succeeded, otherwise it is still running.\n this.setState(succeededCount === this.children.length ? State.SUCCEEDED : State.RUNNING);\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => \"PARALLEL\";\n}\n", "import Composite from \"./Composite\";\nimport Node from \"../Node\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A SELECTOR node.\n * The child nodes are executed in sequence until one succeeds or all fail.\n */\nexport default class Selector extends Composite {\n /**\n * @param attributes The node attributes.\n * @param children The child nodes.\n */\n constructor(attributes: Attribute[], protected children: Node[]) {\n super(\"selector\", attributes, children);\n }\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // Iterate over all of the children of this node.\n for (const child of this.children) {\n // If the child has never been updated or is running then we will need to update it now.\n if (child.getState() === State.READY || child.getState() === State.RUNNING) {\n // Update the child of this node.\n child.update(agent, options);\n }\n\n // If the current child has a state of 'SUCCEEDED' then this node is also a 'SUCCEEDED' node.\n if (child.getState() === State.SUCCEEDED) {\n // This node is a 'SUCCEEDED' node.\n this.setState(State.SUCCEEDED);\n\n // There is no need to check the rest of the selector nodes.\n return;\n }\n\n // If the current child has a state of 'FAILED' then we should move on to the next child.\n if (child.getState() === State.FAILED) {\n // Find out if the current child is the last one in the selector.\n // If it is then this sequence node has also failed.\n if (this.children.indexOf(child) === this.children.length - 1) {\n // This node is a 'FAILED' node.\n this.setState(State.FAILED);\n\n // There is no need to check the rest of the selector as we have completed it.\n return;\n } else {\n // The child node failed, try the next one.\n continue;\n }\n }\n\n // The node should be in the 'RUNNING' state.\n if (child.getState() === State.RUNNING) {\n // This node is a 'RUNNING' node.\n this.setState(State.RUNNING);\n\n // There is no need to check the rest of the selector as the current child is still running.\n return;\n }\n\n // The child node was not in an expected state.\n throw new Error(\"child node was not in an expected state.\");\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => \"SELECTOR\";\n}\n", "import Composite from \"./Composite\";\nimport Node from \"../Node\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A SEQUENCE node.\n * The child nodes are executed in sequence until one fails or all succeed.\n */\nexport default class Sequence extends Composite {\n /**\n * @param attributes The node attributes.\n * @param children The child nodes.\n */\n constructor(attributes: Attribute[], protected children: Node[]) {\n super(\"sequence\", attributes, children);\n }\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // Iterate over all of the children of this node.\n for (const child of this.children) {\n // If the child has never been updated or is running then we will need to update it now.\n if (child.getState() === State.READY || child.getState() === State.RUNNING) {\n // Update the child of this node.\n child.update(agent, options);\n }\n\n // If the current child has a state of 'SUCCEEDED' then we should move on to the next child.\n if (child.getState() === State.SUCCEEDED) {\n // Find out if the current child is the last one in the sequence.\n // If it is then this sequence node has also succeeded.\n if (this.children.indexOf(child) === this.children.length - 1) {\n // This node is a 'SUCCEEDED' node.\n this.setState(State.SUCCEEDED);\n\n // There is no need to check the rest of the sequence as we have completed it.\n return;\n } else {\n // The child node succeeded, but we have not finished the sequence yet.\n continue;\n }\n }\n\n // If the current child has a state of 'FAILED' then this node is also a 'FAILED' node.\n if (child.getState() === State.FAILED) {\n // This node is a 'FAILED' node.\n this.setState(State.FAILED);\n\n // There is no need to check the rest of the sequence.\n return;\n }\n\n // The node should be in the 'RUNNING' state.\n if (child.getState() === State.RUNNING) {\n // This node is a 'RUNNING' node.\n this.setState(State.RUNNING);\n\n // There is no need to check the rest of the sequence as the current child is still running.\n return;\n }\n\n // The child node was not in an expected state.\n throw new Error(\"child node was not in an expected state.\");\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => \"SEQUENCE\";\n}\n", "import createLotto from \"lotto-draw\";\n\nimport Node from \"../Node\";\nimport Composite from \"./Composite\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A LOTTO node.\n * A winning child is picked on the initial update of this node, based on ticket weighting.\n * The state of this node will match the state of the winning child.\n */\nexport default class Lotto extends Composite {\n /**\n * @param attributes The node attributes.\n * @param weights The child node weights.\n * @param children The child nodes.\n */\n constructor(attributes: Attribute[], private weights: number[] | undefined, children: Node[]) {\n super(\"lotto\", attributes, children);\n }\n\n /**\n * The child node selected to be the active one.\n */\n private selectedChild: Node | undefined;\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // If this node is in the READY state then we need to pick a winning child node.\n if (this.is(State.READY)) {\n // Create a lotto draw with which to randomly pick a child node to become the active one.\n const lottoDraw = createLotto({\n // Hook up the optional 'random' behaviour tree function option to the one used by 'lotto-draw'.\n random: options.random,\n // Pass in each child node as a participant in the lotto draw with their respective ticket count.\n participants: this.children.map((child, index) => [child, this.weights?.[index] || 1])\n });\n\n // Randomly pick a child based on ticket weighting, this will become the active child for this composite node.\n this.selectedChild = lottoDraw.draw() || undefined;\n }\n\n // If something went wrong and we don't have an active child then we should throw an error.\n if (!this.selectedChild) {\n throw new Error(\"failed to update lotto node as it has no active child\");\n }\n\n // If the selected child has never been updated or is running then we will need to update it now.\n if (this.selectedChild.getState() === State.READY || this.selectedChild.getState() === State.RUNNING) {\n this.selectedChild.update(agent, options);\n }\n\n // The state of the lotto node is the state of its selected child.\n this.setState(this.selectedChild.getState());\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => (this.weights ? `LOTTO [${this.weights.join(\",\")}]` : \"LOTTO\");\n}\n", "import Node from \"../Node\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\n\n/**\n * A decorator node that wraps a single child node.\n */\nexport default abstract class Decorator extends Node {\n /**\n * @param type The node type.\n * @param attributes The node attributes.\n * @param child The child node.\n */\n constructor(type: string, attributes: Attribute[], protected child: Node) {\n super(type, attributes, []);\n }\n\n /**\n * Gets whether this node is a leaf node.\n */\n isLeafNode = () => false;\n\n /**\n * Gets the children of this node.\n */\n getChildren = () => [this.child];\n\n /**\n * Reset the state of the node.\n */\n reset = () => {\n // Reset the state of this node.\n this.setState(State.READY);\n\n // Reset the state of the child node.\n this.child.reset();\n };\n\n /**\n * Abort the running of this node.\n * @param agent The agent.\n */\n abort = (agent: Agent) => {\n // There is nothing to do if this node is not in the running state.\n if (!this.is(State.RUNNING)) {\n return;\n }\n\n // Abort the child node.\n this.child.abort(agent);\n\n // Reset the state of this node.\n this.reset();\n\n this.getAttribute(\"exit\")?.callAgentFunction(agent, false, true);\n };\n}\n", "import Node from \"../Node\";\nimport Decorator from \"./Decorator\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A Fail node.\n * This node wraps a single child and will always move to the 'FAILED' state when the child moves to a 'SUCCEEDED' or 'FAILED' state.\n */\nexport default class Fail extends Decorator {\n /**\n * @param attributes The node attributes.\n * @param child The child node.\n */\n constructor(attributes: Attribute[], child: Node) {\n super(\"fail\", attributes, child);\n }\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // If the child has never been updated or is running then we will need to update it now.\n if (this.child.getState() === State.READY || this.child.getState() === State.RUNNING) {\n this.child.update(agent, options);\n }\n\n // The state of this node will depend in the state of its child.\n switch (this.child.getState()) {\n case State.RUNNING:\n this.setState(State.RUNNING);\n break;\n\n case State.SUCCEEDED:\n case State.FAILED:\n this.setState(State.FAILED);\n break;\n\n default:\n this.setState(State.READY);\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => \"FAIL\";\n}\n", "import Decorator from \"./Decorator\";\nimport State from \"../../State\";\nimport Node from \"../Node\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A Flip node.\n * This node wraps a single child and will flip the state of the child state.\n */\nexport default class Flip extends Decorator {\n /**\n * @param attributes The node attributes.\n * @param child The child node.\n */\n constructor(attributes: Attribute[], child: Node) {\n super(\"flip\", attributes, child);\n }\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // If the child has never been updated or is running then we will need to update it now.\n if (this.child.getState() === State.READY || this.child.getState() === State.RUNNING) {\n this.child.update(agent, options);\n }\n\n // The state of this node will depend in the state of its child.\n switch (this.child.getState()) {\n case State.RUNNING:\n this.setState(State.RUNNING);\n break;\n\n case State.SUCCEEDED:\n this.setState(State.FAILED);\n break;\n\n case State.FAILED:\n this.setState(State.SUCCEEDED);\n break;\n\n default:\n this.setState(State.READY);\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => \"FLIP\";\n}\n", "import Node from \"../Node\";\nimport Decorator from \"./Decorator\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A REPEAT node.\n * The node has a single child which can have:\n * -- A number of iterations for which to repeat the child node.\n * -- An infinite repeat loop if neither an iteration count or a condition function is defined.\n * The REPEAT node will stop and have a 'FAILED' state if its child is ever in a 'FAILED' state after an update.\n * The REPEAT node will attempt to move on to the next iteration if its child is ever in a 'SUCCEEDED' state.\n */\nexport default class Repeat extends Decorator {\n /**\n * @param attributes The node attributes.\n * @param iterations The number of iterations to repeat the child node.\n * @param iterationsMin The minimum possible number of iterations to repeat the child node.\n * @param iterationsMax The maximum possible number of iterations to repeat the child node.\n * @param child The child node.\n */\n constructor(\n attributes: Attribute[],\n private iterations: number | null,\n private iterationsMin: number | null,\n private iterationsMax: number | null,\n child: Node\n ) {\n super(\"repeat\", attributes, child);\n }\n\n /**\n * The number of target iterations to make.\n */\n private targetIterationCount: number | null = null;\n\n /**\n * The current iteration count.\n */\n private currentIterationCount: number = 0;\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // If this node is in the READY state then we need to reset the child and the target iteration count.\n if (this.is(State.READY)) {\n // Reset the child node.\n this.child.reset();\n\n // Reset the current iteration count.\n this.currentIterationCount = 0;\n\n // Set the target iteration count.\n this.setTargetIterationCount(options);\n }\n\n // Do a check to see if we can iterate. If we can then this node will move into the 'RUNNING' state.\n // If we cannot iterate then we have hit our target iteration count, which means that the node has succeeded.\n if (this.canIterate()) {\n // This node is in the running state and can do its initial iteration.\n this.setState(State.RUNNING);\n\n // We may have already completed an iteration, meaning that the child node will be in the SUCCEEDED state.\n // If this is the case then we will have to reset the child node now.\n if (this.child.getState() === State.SUCCEEDED) {\n this.child.reset();\n }\n\n // Update the child of this node.\n this.child.update(agent, options);\n\n // If the child moved into the FAILED state when we updated it then there is nothing left to do and this node has also failed.\n // If it has moved into the SUCCEEDED state then we have completed the current iteration.\n if (this.child.getState() === State.FAILED) {\n // The child has failed, meaning that this node has failed.\n this.setState(State.FAILED);\n\n return;\n } else if (this.child.getState() === State.SUCCEEDED) {\n // We have completed an iteration.\n this.currentIterationCount += 1;\n }\n } else {\n // This node is in the 'SUCCEEDED' state as we cannot iterate any more.\n this.setState(State.SUCCEEDED);\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => {\n if (this.iterations !== null) {\n return `REPEAT ${this.iterations}x`;\n } else if (this.iterationsMin !== null && this.iterationsMax !== null) {\n return `REPEAT ${this.iterationsMin}x-${this.iterationsMax}x`;\n } else {\n return \"REPEAT\";\n }\n };\n\n /**\n * Reset the state of the node.\n */\n reset = () => {\n // Reset the state of this node.\n this.setState(State.READY);\n\n // Reset the current iteration count.\n this.currentIterationCount = 0;\n\n // Reset the child node.\n this.child.reset();\n };\n\n /**\n * Gets whether an iteration can be made.\n * @returns Whether an iteration can be made.\n */\n private canIterate = () => {\n if (this.targetIterationCount !== null) {\n // We can iterate as long as we have not reached our target iteration count.\n return this.currentIterationCount < this.targetIterationCount;\n }\n\n // If neither an iteration count or a condition function were defined then we can iterate indefinitely.\n return true;\n };\n\n /**\n * Sets the target iteration count.\n * @param options The behaviour tree options object.\n */\n private setTargetIterationCount = (options: BehaviourTreeOptions) => {\n // Are we dealing with an explicit iteration count or will we be randomly picking a iteration count between the min and max iteration count.\n if (this.iterations !== null) {\n this.targetIterationCount = this.iterations;\n } else if (this.iterationsMin !== null && this.iterationsMax !== null) {\n // We will be picking a random iteration count between a min and max iteration count, if the optional 'random'\n // behaviour tree function option is defined then we will be using that, otherwise we will fall back to using Math.random.\n const random = typeof options.random === \"function\" ? options.random : Math.random;\n\n // Pick a random iteration count between a min and max iteration count.\n this.targetIterationCount = Math.floor(\n random() * (this.iterationsMax - this.iterationsMin + 1) + this.iterationsMin\n );\n } else {\n this.targetIterationCount = null;\n }\n };\n}\n", "import Node from \"../Node\";\nimport Decorator from \"./Decorator\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A RETRY node.\n * The node has a single child which can have:\n * -- A number of iterations for which to repeat the child node.\n * -- An infinite repeat loop if neither an iteration count or a condition function is defined.\n * The RETRY node will stop and have a 'SUCCEEDED' state if its child is ever in a 'SUCCEEDED' state after an update.\n * The RETRY node will attempt to move on to the next iteration if its child is ever in a 'FAILED' state.\n */\nexport default class Retry extends Decorator {\n /**\n * @param attributes The node attributes.\n * @param attempts The number of attempts to retry the child node.\n * @param attemptsMin The minimum possible number of attempts to retry the child node.\n * @param attemptsMax The maximum possible number of attempts to retry the child node.\n * @param child The child node.\n */\n constructor(\n attributes: Attribute[],\n private attempts: number | null,\n private attemptsMin: number | null,\n private attemptsMax: number | null,\n child: Node\n ) {\n super(\"retry\", attributes, child);\n }\n\n /**\n * The number of target attempts to make.\n */\n private targetAttemptCount: number | null = null;\n\n /**\n * The current attempt count.\n */\n private currentAttemptCount: number = 0;\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // If this node is in the READY state then we need to reset the child and the target attempt count.\n if (this.is(State.READY)) {\n // Reset the child node.\n this.child.reset();\n\n // Reset the current attempt count.\n this.currentAttemptCount = 0;\n\n // Set the target attempt count.\n this.setTargetAttemptCount(options);\n }\n\n // Do a check to see if we can attempt. If we can then this node will move into the 'RUNNING' state.\n // If we cannot attempt then we have hit our target attempt count, which means that the node has succeeded.\n if (this.canAttempt()) {\n // This node is in the running state and can do its initial attempt.\n this.setState(State.RUNNING);\n\n // We may have already completed an attempt, meaning that the child node will be in the FAILED state.\n // If this is the case then we will have to reset the child node now.\n if (this.child.getState() === State.FAILED) {\n this.child.reset();\n }\n\n // Update the child of this node.\n this.child.update(agent, options);\n\n // If the child moved into the SUCCEEDED state when we updated it then there is nothing left to do and this node has also succeeded.\n // If it has moved into the FAILED state then we have completed the current attempt.\n if (this.child.getState() === State.SUCCEEDED) {\n // The child has succeeded, meaning that this node has succeeded.\n this.setState(State.SUCCEEDED);\n\n return;\n } else if (this.child.getState() === State.FAILED) {\n // We have completed an attempt.\n this.currentAttemptCount += 1;\n }\n } else {\n // This node is in the 'FAILED' state as we cannot iterate any more.\n this.setState(State.FAILED);\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => {\n if (this.attempts !== null) {\n return `RETRY ${this.attempts}x`;\n } else if (this.attemptsMin !== null && this.attemptsMax !== null) {\n return `RETRY ${this.attemptsMin}x-${this.attemptsMax}x`;\n } else {\n return \"RETRY\";\n }\n };\n\n /**\n * Reset the state of the node.\n */\n reset = () => {\n // Reset the state of this node.\n this.setState(State.READY);\n\n // Reset the current attempt count.\n this.currentAttemptCount = 0;\n\n // Reset the child node.\n this.child.reset();\n };\n\n /**\n * Gets whether an attempt can be made.\n * @returns Whether an attempt can be made.\n */\n canAttempt = () => {\n if (this.targetAttemptCount !== null) {\n // We can attempt as long as we have not reached our target attempt count.\n return this.currentAttemptCount < this.targetAttemptCount;\n }\n\n // If neither an attempt count or a condition function were defined then we can attempt indefinitely.\n return true;\n };\n\n /**\n * Sets the target attempt count.\n * @param options The behaviour tree options object.\n */\n setTargetAttemptCount = (options: BehaviourTreeOptions) => {\n // Are we dealing with an explicit attempt count or will we be randomly picking an attempt count between the min and max attempt count.\n if (this.attempts !== null) {\n this.targetAttemptCount = this.attempts;\n } else if (this.attemptsMin !== null && this.attemptsMax !== null) {\n // We will be picking a random attempt count between a min and max attempt count, if the optional 'random'\n // behaviour tree function option is defined then we will be using that, otherwise we will fall back to using Math.random.\n const random = typeof options.random === \"function\" ? options.random : Math.random;\n\n // Pick a random attempt count between a min and max attempt count.\n this.targetAttemptCount = Math.floor(\n random() * (this.attemptsMax - this.attemptsMin + 1) + this.attemptsMin\n );\n } else {\n this.targetAttemptCount = null;\n }\n };\n}\n", "import Node from \"../Node\";\nimport Decorator from \"./Decorator\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A Root node.\n * The root node will have a single child.\n */\nexport default class Root extends Decorator {\n /**\n * @param attributes The node attributes.\n * @param child The child node.\n */\n constructor(attributes: Attribute[], child: Node) {\n super(\"root\", attributes, child);\n }\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // If the child has never been updated or is running then we will need to update it now.\n if (this.child.getState() === State.READY || this.child.getState() === State.RUNNING) {\n // Update the child of this node.\n this.child.update(agent, options);\n }\n\n // The state of the root node is the state of its child.\n this.setState(this.child.getState());\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => \"ROOT\";\n}\n", "import Node from \"../Node\";\nimport Decorator from \"./Decorator\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A Succeed node.\n * This node wraps a single child and will always move to the 'SUCCEEDED' state when the child moves to a 'SUCCEEDED' or 'FAILED' state.\n */\nexport default class Succeed extends Decorator {\n /**\n * @param attributes The node attributes.\n * @param child The child node.\n */\n constructor(attributes: Attribute[], child: Node) {\n super(\"succeed\", attributes, child);\n }\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // If the child has never been updated or is running then we will need to update it now.\n if (this.child.getState() === State.READY || this.child.getState() === State.RUNNING) {\n this.child.update(agent, options);\n }\n\n // The state of this node will depend in the state of its child.\n switch (this.child.getState()) {\n case State.RUNNING:\n this.setState(State.RUNNING);\n break;\n\n case State.SUCCEEDED:\n case State.FAILED:\n this.setState(State.SUCCEEDED);\n break;\n\n default:\n this.setState(State.READY);\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => \"SUCCEED\";\n}\n", "import Node from \"../Node\";\n\n/**\n * A leaf node.\n */\nexport default abstract class Leaf extends Node {\n /**\n * Gets whether this node is a leaf node.\n */\n isLeafNode = () => true;\n}\n", "import { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\nimport State, { CompleteState } from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Leaf from \"./Leaf\";\nimport Lookup from \"../../Lookup\";\nimport Attribute from \"../../attributes/Attribute\";\n\n/**\n * The type representing a resolved/rejected update promise.\n */\ntype UpdatePromiseResult = {\n /**\n * Whether the promise was resolved rather than rejected.\n */\n isResolved: boolean;\n\n /**\n * The promise resolved value or rejection reason.\n */\n value: any;\n};\n\n/**\n * An Action leaf node.\n * This represents an immediate or ongoing state of behaviour.\n */\nexport default class Action extends Leaf {\n /**\n * @param attributes The node attributes.\n * @param actionName The action name.\n * @param actionArguments The array of action argument definitions.\n */\n constructor(attributes: Attribute[], private actionName: string, private actionArguments: any[]) {\n super(\"action\", attributes, actionArguments);\n }\n\n /**\n * Whether there is a pending update promise.\n */\n private isUsingUpdatePromise = false;\n\n /**\n * The finished state result of an update promise.\n */\n private updatePromiseResult: UpdatePromiseResult | null = null;\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // If the result of this action depends on an update promise then there is nothing to do until it settles.\n if (this.isUsingUpdatePromise) {\n // Are we still waiting for our update promise to settle?\n if (!this.updatePromiseResult) {\n return;\n }\n\n const { isResolved, value } = this.updatePromiseResult;\n\n // Our update promise settled, was it resolved or rejected?\n if (isResolved) {\n // Our promise resolved so check to make sure the result is a valid finished state.\n if (value !== State.SUCCEEDED && value !== State.FAILED) {\n throw new Error(\n \"action node promise resolved with an invalid value, expected a State.SUCCEEDED or State.FAILED value to be returned\"\n );\n }\n\n // Set the state of this node to match the state returned by the promise.\n this.setState(value);\n\n return;\n } else {\n // The promise was rejected, which isn't great.\n throw new Error(`action function '${this.actionName}' promise rejected with '${value}'`);\n }\n }\n\n // Attempt to get the invoker for the action function.\n const actionFuncInvoker = Lookup.getFuncInvoker(agent, this.actionName);\n\n // The action function should be defined.\n if (actionFuncInvoker === null) {\n throw new Error(\n `cannot update action node as the action '${this.actionName}' function is not defined on the agent and has not been registered`\n );\n }\n\n let actionFunctionResult;\n\n try {\n // Call the action function, the result of which may be:\n // - The finished state of this action node.\n // - A promise to return a finished node state.\n // - Undefined if the node should remain in the running state.\n actionFunctionResult = actionFuncInvoker(this.actionArguments) as CompleteState | Promise;\n } catch (error) {\n // An uncaught error was thrown.\n if (error instanceof Error) {\n throw new Error(`action function '${this.actionName}' threw: ${error.stack}`);\n } else {\n throw new Error(`action function '${this.actionName}' threw: ${error}`);\n }\n }\n\n if (actionFunctionResult instanceof Promise) {\n actionFunctionResult.then(\n (result) => {\n // If 'isUpdatePromisePending' is not set then the promise was cleared as it was resolving, probably via an abort of reset.\n if (!this.isUsingUpdatePromise) {\n return;\n }\n\n // Set the resolved update promise result so that it can be handled on the next update of this node.\n this.updatePromiseResult = {\n isResolved: true,\n value: result\n };\n },\n (reason) => {\n // If 'isUpdatePromisePending' is not set then the promise was cleared as it was resolving, probably via an abort or reset.\n if (!this.isUsingUpdatePromise) {\n return;\n }\n\n // Set the rejected update promise result so that it can be handled on the next update of this node.\n this.updatePromiseResult = {\n isResolved: false,\n value: reason\n };\n }\n );\n\n // This node will be in the 'RUNNING' state until the update promise resolves.\n this.setState(State.RUNNING);\n\n // We are now waiting for the promise returned by the use to resolve before we know what state this node is in.\n this.isUsingUpdatePromise = true;\n } else {\n // Validate the returned value.\n this.validateUpdateResult(actionFunctionResult);\n\n // Set the state of this node, this may be undefined, which just means that the node is still in the 'RUNNING' state.\n this.setState(actionFunctionResult || State.RUNNING);\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => this.actionName;\n\n /**\n * Reset the state of the node.\n */\n reset = () => {\n // Reset the state of this node.\n this.setState(State.READY);\n\n // There is no longer an update promise that we care about.\n this.isUsingUpdatePromise = false;\n this.updatePromiseResult = null;\n };\n\n /**\n * Validate the result of an update function call.\n * @param result The result of an update function call.\n */\n private validateUpdateResult = (result: CompleteState | State.RUNNING) => {\n switch (result) {\n case State.SUCCEEDED:\n case State.FAILED:\n case State.RUNNING:\n case undefined:\n return;\n default:\n throw new Error(\n `expected action function '${this.actionName}' to return an optional State.SUCCEEDED or State.FAILED value but returned '${result}'`\n );\n }\n };\n}\n", "import { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Leaf from \"./Leaf\";\nimport Lookup from \"../../Lookup\";\nimport Attribute from \"../../attributes/Attribute\";\n\n/**\n * A Condition leaf node.\n * This will succeed or fail immediately based on an agent predicate, without moving to the 'RUNNING' state.\n */\nexport default class Condition extends Leaf {\n /**\n * @param attributes The node attributes.\n * @param conditionName The name of the condition function.\n * @param conditionArguments The array of condition argument definitions.\n */\n constructor(attributes: Attribute[], private conditionName: string, private conditionArguments: any[]) {\n super(\"condition\", attributes, conditionArguments);\n }\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // Attempt to get the invoker for the condition function.\n const conditionFuncInvoker = Lookup.getFuncInvoker(agent, this.conditionName);\n\n // The condition function should be defined.\n if (conditionFuncInvoker === null) {\n throw new Error(\n `cannot update condition node as the condition '${this.conditionName}' function is not defined on the agent and has not been registered`\n );\n }\n\n let conditionFunctionResult;\n\n try {\n // Call the condition function to determine the state of this node, the result of which should be a boolean.\n conditionFunctionResult = conditionFuncInvoker(this.conditionArguments);\n } catch (error) {\n // An uncaught error was thrown.\n if (error instanceof Error) {\n throw new Error(`condition function '${this.conditionName}' threw: ${error.stack}`);\n } else {\n throw new Error(`condition function '${this.conditionName}' threw: ${error}`);\n }\n }\n\n // The result of calling the condition function must be a boolean value.\n if (typeof conditionFunctionResult !== \"boolean\") {\n throw new Error(\n `expected condition function '${this.conditionName}' to return a boolean but returned '${conditionFunctionResult}'`\n );\n }\n\n // Set the state of this node based on the result of calling the condition function.\n this.setState(!!conditionFunctionResult ? State.SUCCEEDED : State.FAILED);\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => this.conditionName;\n}\n", "import Leaf from \"./Leaf\";\nimport State from \"../../State\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { Agent } from \"../../Agent\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A WAIT node.\n * The state of this node will change to SUCCEEDED after a duration of time\n */\nexport default class Wait extends Leaf {\n /**\n * @param attributes The node attributes.\n * @param duration The duration that this node will wait to succeed in milliseconds.\n * @param durationMin The minimum possible duration in milliseconds that this node will wait to succeed.\n * @param durationMax The maximum possible duration in milliseconds that this node will wait to succeed.\n */\n constructor(\n attributes: Attribute[],\n private duration: number | null,\n private durationMin: number | null,\n private durationMax: number | null\n ) {\n super(\"wait\", attributes, []);\n }\n\n /**\n * The time in milliseconds at which this node was first updated.\n */\n private initialUpdateTime: number = 0;\n\n /**\n * The total duration in milliseconds that this node will be waiting for.\n */\n private totalDuration: number | null = null;\n\n /**\n * The duration in milliseconds that this node has been waiting for.\n */\n private waitedDuration: number = 0;\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // If this node is in the READY state then we need to set the initial update time.\n if (this.is(State.READY)) {\n // Set the initial update time.\n this.initialUpdateTime = new Date().getTime();\n\n // Set the initial waited duration.\n this.waitedDuration = 0;\n\n // Are we dealing with an explicit duration or will we be randomly picking a duration between the min and max duration.\n if (this.duration !== null) {\n this.totalDuration = this.duration;\n } else if (this.durationMin !== null && this.durationMax !== null) {\n // We will be picking a random duration between a min and max duration, if the optional 'random' behaviour tree\n // function option is defined then we will be using that, otherwise we will fall back to using Math.random.\n const random = typeof options.random === \"function\" ? options.random : Math.random;\n\n // Pick a random duration between a min and max duration.\n this.totalDuration = Math.floor(\n random() * (this.durationMax - this.durationMin + 1) + this.durationMin\n );\n } else {\n this.totalDuration = null;\n }\n\n // The node is now running until we finish waiting.\n this.setState(State.RUNNING);\n }\n\n // If we have no total duration then this wait node will wait indefinitely until it is aborted.\n if (this.totalDuration === null) {\n return;\n }\n\n // If we have a 'getDeltaTime' function defined as part of our options then we will use it to figure out how long we have waited for.\n if (typeof options.getDeltaTime === \"function\") {\n // Get the delta time.\n const deltaTime = options.getDeltaTime();\n\n // Our delta time must be a valid number and cannot be NaN.\n if (typeof deltaTime !== \"number\" || isNaN(deltaTime)) {\n throw new Error(\"The delta time must be a valid number and not NaN.\");\n }\n\n // Update the amount of time that this node has been waiting for based on the delta time.\n this.waitedDuration += deltaTime * 1000;\n } else {\n // We are not using a delta time, so we will just work out hom much time has passed since the first update.\n this.waitedDuration = new Date().getTime() - this.initialUpdateTime;\n }\n\n // Have we waited long enough?\n if (this.waitedDuration >= this.totalDuration) {\n // We have finished waiting!\n this.setState(State.SUCCEEDED);\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => {\n if (this.duration !== null) {\n return `WAIT ${this.duration}ms`;\n } else if (this.durationMin !== null && this.durationMax !== null) {\n return `WAIT ${this.durationMin}ms-${this.durationMax}ms`;\n } else {\n return \"WAIT\";\n }\n };\n}\n", "import Guard from \"./guards/Guard\";\n\nexport type AttributeDetails = {\n /** The attribute type. */\n type: string;\n\n /** The attribute arguments. */\n args: any[];\n};\n\n/**\n * A base node attribute.\n */\nexport default abstract class Attribute {\n /**\n * @param type The node attribute type.\n * @param args The array of attribute arguments.\n */\n constructor(public type: string, public args: any[]) {}\n\n /**\n * Gets the attribute details.\n */\n abstract getDetails(): TAttributeDetails;\n\n /**\n * Gets whether this attribute is a guard.\n */\n abstract isGuard: () => this is Guard;\n}\n", "import { Agent } from \"../../Agent\";\nimport Attribute, { AttributeDetails } from \"../Attribute\";\n\nexport type GuardAttributeDetails = {\n /** The name of the condition function that determines whether the guard is satisfied. */\n condition: string;\n} & AttributeDetails;\n\n/**\n * A base node guard attribute.\n */\nexport default abstract class Guard extends Attribute {\n /**\n * @param type The node attribute type.\n * @param args The array of decorator argument definitions.\n * @param condition The name of the condition function that determines whether the guard is satisfied.\n */\n constructor(type: string, args: any[], private condition: string) {\n super(type, args);\n }\n\n /**\n * Gets the name of the condition function that determines whether the guard is satisfied.\n */\n getCondition = () => this.condition;\n\n /**\n * Gets whether this attribute is a guard.\n */\n isGuard = () => true;\n\n /**\n * Gets the attribute details.\n */\n getDetails(): GuardAttributeDetails {\n return {\n type: this.type,\n args: this.args,\n condition: this.getCondition()\n };\n }\n\n /**\n * Gets whether the guard is satisfied.\n * @param agent The agent.\n * @returns Whether the guard is satisfied.\n */\n abstract isSatisfied(agent: Agent): boolean;\n}\n", "import Guard from \"./Guard\";\nimport Lookup from \"../../Lookup\";\nimport { Agent } from \"../../Agent\";\n\n/**\n * A WHILE guard which is satisfied as long as the given condition remains true.\n */\nexport default class While extends Guard {\n /**\n * @param condition The name of the condition function that determines whether the guard is satisfied.\n * @param args The array of decorator argument definitions.\n */\n constructor(condition: string, args: any[]) {\n super(\"while\", args, condition);\n }\n\n /**\n * Gets whether the guard is satisfied.\n * @param agent The agent.\n * @returns Whether the guard is satisfied.\n */\n isSatisfied = (agent: Agent) => {\n // Attempt to get the invoker for the condition function.\n const conditionFuncInvoker = Lookup.getFuncInvoker(agent, this.getCondition());\n\n // The condition function should be defined.\n if (conditionFuncInvoker === null) {\n throw new Error(\n `cannot evaluate node guard as the condition '${this.getCondition()}' function is not defined on the agent and has not been registered`\n );\n }\n\n let conditionFunctionResult;\n\n try {\n // Call the guard condition function to determine the state of this node, the result of which should be a boolean.\n conditionFunctionResult = conditionFuncInvoker(this.args);\n } catch (error) {\n // An uncaught error was thrown.\n if (error instanceof Error) {\n throw new Error(`guard condition function '${this.getCondition()}' threw: ${error.stack}`);\n } else {\n throw new Error(`guard condition function '${this.getCondition()}' threw: ${error}`);\n }\n }\n\n // The result of calling the guard condition function must be a boolean value.\n if (typeof conditionFunctionResult !== \"boolean\") {\n throw new Error(\n `expected guard condition function '${this.getCondition()}' to return a boolean but returned '${conditionFunctionResult}'`\n );\n }\n\n // Return whether this guard is satisfied.\n return conditionFunctionResult;\n };\n}\n", "import Guard from \"./Guard\";\nimport Lookup from \"../../Lookup\";\nimport { Agent } from \"../../Agent\";\n\n/**\n * An UNTIL guard which is satisfied as long as the given condition remains false.\n */\nexport default class Until extends Guard {\n /**\n * @param condition The name of the condition function that determines whether the guard is satisfied.\n * @param args The array of decorator argument definitions.\n */\n constructor(condition: string, args: any[]) {\n super(\"until\", args, condition);\n }\n\n /**\n * Gets whether the guard is satisfied.\n * @param agent The agent.\n * @returns Whether the guard is satisfied.\n */\n isSatisfied = (agent: Agent) => {\n // Attempt to get the invoker for the condition function.\n const conditionFuncInvoker = Lookup.getFuncInvoker(agent, this.getCondition());\n\n // The condition function should be defined.\n if (conditionFuncInvoker === null) {\n throw new Error(\n `cannot evaluate node guard as the condition '${this.getCondition()}' function is not defined on the agent and has not been registered`\n );\n }\n\n let conditionFunctionResult;\n\n try {\n // Call the guard condition function to determine the state of this node, the result of which should be a boolean.\n conditionFunctionResult = conditionFuncInvoker(this.args);\n } catch (error) {\n // An uncaught error was thrown.\n if (error instanceof Error) {\n throw new Error(`guard condition function '${this.getCondition()}' threw: ${error.stack}`);\n } else {\n throw new Error(`guard condition function '${this.getCondition()}' threw: ${error}`);\n }\n }\n\n // The result of calling the guard condition function must be a boolean value.\n if (typeof conditionFunctionResult !== \"boolean\") {\n throw new Error(\n `expected guard condition function '${this.getCondition()}' to return a boolean but returned '${conditionFunctionResult}'`\n );\n }\n\n // Return whether this guard is satisfied.\n return !conditionFunctionResult;\n };\n}\n", "import { Agent } from \"../../Agent\";\nimport Attribute, { AttributeDetails } from \"../Attribute\";\n\nexport type CallbackAttributeDetails = {\n /** The name of the agent function that is called. */\n functionName: string;\n} & AttributeDetails;\n\n/**\n * A base node callback attribute.\n */\nexport default abstract class Callback extends Attribute {\n /**\n * @param type The node attribute type.\n * @param args The array of decorator argument definitions.\n * @param functionName The name of the agent function to call.\n */\n constructor(type: string, args: any[], private functionName: string) {\n super(type, args);\n }\n\n /**\n * Gets the name of the agent function to call.\n */\n getFunctionName = () => this.functionName;\n\n /**\n * Gets whether this attribute is a guard.\n */\n isGuard = () => false;\n\n /**\n * Gets the attribute details.\n */\n getDetails(): CallbackAttributeDetails {\n return {\n type: this.type,\n args: this.args,\n functionName: this.getFunctionName()\n };\n }\n\n /**\n * Attempt to call the agent function that this callback refers to.\n * @param agent The agent.\n */\n abstract callAgentFunction: (agent: Agent, isSuccess: boolean, isAborted: boolean) => void;\n}\n", "import Callback from \"./Callback\";\nimport Lookup from \"../../Lookup\";\nimport { Agent } from \"../../Agent\";\n\n/**\n * An ENTRY callback which defines an agent function to call when the associated node is updated and moves out of running state.\n */\nexport default class Entry extends Callback {\n /**\n * @param functionName The name of the agent function to call.\n * @param args The array of callback argument definitions.\n */\n constructor(functionName: string, args: any[]) {\n super(\"entry\", args, functionName);\n }\n\n /**\n * Attempt to call the agent function that this callback refers to.\n * @param agent The agent.\n */\n callAgentFunction = (agent: Agent) => {\n // Attempt to get the invoker for the callback function.\n const callbackFuncInvoker = Lookup.getFuncInvoker(agent, this.getFunctionName());\n\n // The callback function should be defined.\n if (callbackFuncInvoker === null) {\n throw new Error(\n `cannot call entry function '${this.getFunctionName()}' as is not defined on the agent and has not been registered`\n );\n }\n\n // Call the callback function.\n callbackFuncInvoker(this.args);\n };\n}\n", "import Callback from \"./Callback\";\nimport Lookup from \"../../Lookup\";\nimport { Agent } from \"../../Agent\";\n\n/**\n * A STEP callback which defines an agent function to call when the associated node is updated.\n */\nexport default class Step extends Callback {\n /**\n * @param functionName The name of the agent function to call.\n * @param args The array of callback argument definitions.\n */\n constructor(functionName: string, args: any[]) {\n super(\"step\", args, functionName);\n }\n\n /**\n * Attempt to call the agent function that this callback refers to.\n * @param agent The agent.\n */\n callAgentFunction = (agent: Agent) => {\n // Attempt to get the invoker for the callback function.\n const callbackFuncInvoker = Lookup.getFuncInvoker(agent, this.getFunctionName());\n\n // The callback function should be defined.\n if (callbackFuncInvoker === null) {\n throw new Error(\n `cannot call step function '${this.getFunctionName()}' as is not defined on the agent and has not been registered`\n );\n }\n\n // Call the callback function.\n callbackFuncInvoker(this.args);\n };\n}\n", "import Callback from \"./Callback\";\nimport Lookup from \"../../Lookup\";\nimport { Agent } from \"../../Agent\";\n\n/**\n * An EXIT callback which defines an agent function to call when the associated node is updated and moves to a finished state or is aborted.\n */\nexport default class Exit extends Callback {\n /**\n * @param functionName The name of the agent function to call.\n * @param args The array of callback argument definitions.\n */\n constructor(functionName: string, args: any[]) {\n super(\"exit\", args, functionName);\n }\n\n /**\n * Attempt to call the agent function that this callback refers to.\n * @param agent The agent.\n * @param isSuccess Whether the decorated node was left with a success state.\n * @param isAborted Whether the decorated node was aborted.\n */\n callAgentFunction = (agent: Agent, isSuccess: boolean, isAborted: boolean) => {\n // Attempt to get the invoker for the callback function.\n const callbackFuncInvoker = Lookup.getFuncInvoker(agent, this.getFunctionName());\n\n // The callback function should be defined.\n if (callbackFuncInvoker === null) {\n throw new Error(\n `cannot call exit function '${this.getFunctionName()}' as is not defined on the agent and has not been registered`\n );\n }\n\n // Call the callback function\n callbackFuncInvoker([{ succeeded: isSuccess, aborted: isAborted }, ...this.args]);\n };\n}\n", "import { AnyNodeDefinition, RootNodeDefinition } from \"./BehaviourTreeDefinition\";\nimport GuardPath, { GuardPathPart } from \"./attributes/guards/GuardPath\";\nimport { validateBranchSubtreeLinks } from \"./BehaviourTreeDefinitionValidator\";\nimport { isInteger } from \"./BehaviourTreeDefinitionUtilities\";\nimport Node from \"./nodes/Node\";\nimport Composite from \"./nodes/composite/Composite\";\nimport Decorator from \"./nodes/decorator/Decorator\";\nimport Parallel from \"./nodes/composite/Parallel\";\nimport Selector from \"./nodes/composite/Selector\";\nimport Sequence from \"./nodes/composite/Sequence\";\nimport Lotto from \"./nodes/composite/Lotto\";\nimport Fail from \"./nodes/decorator/Fail\";\nimport Flip from \"./nodes/decorator/Flip\";\nimport Repeat from \"./nodes/decorator/Repeat\";\nimport Retry from \"./nodes/decorator/Retry\";\nimport Root from \"./nodes/decorator/Root\";\nimport Succeed from \"./nodes/decorator/Succeed\";\nimport Action from \"./nodes/leaf/Action\";\nimport Condition from \"./nodes/leaf/Condition\";\nimport Wait from \"./nodes/leaf/Wait\";\nimport Lookup from \"./Lookup\";\nimport Attribute from \"./attributes/Attribute\";\nimport While from \"./attributes/guards/While\";\nimport Until from \"./attributes/guards/Until\";\nimport Entry from \"./attributes/callbacks/Entry\";\nimport Step from \"./attributes/callbacks/Step\";\nimport Exit from \"./attributes/callbacks/Exit\";\n\n/**\n * A type representing any node instance in a behaviour tree.\n */\ntype AnyNode =\n | Root\n | Action\n | Condition\n | Wait\n | Sequence\n | Selector\n | Lotto\n | Parallel\n | Repeat\n | Retry\n | Flip\n | Succeed\n | Fail;\n\n/**\n * A type defining a mapping of root node identifiers to root node definitions.\n */\ntype RootNodeDefinitionMap = { [key: string | symbol]: RootNodeDefinition };\n\n/**\n * A symbol to use as the main root key in any root node mappings.\n */\nconst MAIN_ROOT_NODE_KEY = Symbol(\"__root__\");\n\n/**\n * Build and populate the root nodes based on the provided definition, assuming that the definition has been validated.\n * @param definition The root node definitions.\n * @returns The built and populated root node definitions.\n */\nexport default function buildRootNode(definition: RootNodeDefinition[]): Root {\n // Create a mapping of root node identifers to root node definitions, including globally registered subtree root node definitions.\n const rootNodeDefinitionMap = createRootNodeDefinitionMap(definition);\n\n // Now that we have all of our root node definitions (those part of the tree definition and those globally registered)\n // we should validate the branch-subtree links. This will also double-check that we dont have any circular dependencies\n // in our branch-subtree references and that we have no broken branch-subtree links.\n validateBranchSubtreeLinks(\n [rootNodeDefinitionMap[MAIN_ROOT_NODE_KEY], ...Object.values(rootNodeDefinitionMap)],\n true\n );\n\n // Create our populated tree of node instances, starting with our main root node.\n const rootNode = nodeFactory(rootNodeDefinitionMap[MAIN_ROOT_NODE_KEY], rootNodeDefinitionMap) as Root;\n\n // Set a guard path on every leaf of the tree to evaluate as part of each update.\n applyLeafNodeGuardPaths(rootNode);\n\n // We only need to return the main root node.\n return rootNode;\n}\n\n/**\n * A factory function which creates a node instance based on the specified definition.\n * @param definition The node definition.\n * @param rootNodeDefinitionMap The mapping of root node identifers to root node definitions, including globally registered subtree root node definitions.\n * @returns A node instance based on the specified definition.\n */\nfunction nodeFactory(definition: AnyNodeDefinition, rootNodeDefinitionMap: RootNodeDefinitionMap): AnyNode {\n // Get the attributes for the node.\n const attributes = nodeAttributesFactory(definition);\n\n // Create the node instance based on the definition type.\n switch (definition.type) {\n case \"root\":\n return new Root(attributes, nodeFactory(definition.child, rootNodeDefinitionMap));\n\n case \"repeat\":\n let iterations: number | null = null;\n let iterationsMin: number | null = null;\n let iterationsMax: number | null = null;\n\n if (Array.isArray(definition.iterations)) {\n iterationsMin = definition.iterations[0];\n iterationsMax = definition.iterations[1];\n } else if (isInteger(definition.iterations)) {\n iterations = definition.iterations!;\n }\n\n return new Repeat(\n attributes,\n iterations,\n iterationsMin,\n iterationsMax,\n nodeFactory(definition.child, rootNodeDefinitionMap)\n );\n\n case \"retry\":\n let attempts: number | null = null;\n let attemptsMin: number | null = null;\n let attemptsMax: number | null = null;\n\n if (Array.isArray(definition.attempts)) {\n attemptsMin = definition.attempts[0];\n attemptsMax = definition.attempts[1];\n } else if (isInteger(definition.attempts)) {\n attempts = definition.attempts!;\n }\n\n return new Retry(\n attributes,\n attempts,\n attemptsMin,\n attemptsMax,\n nodeFactory(definition.child, rootNodeDefinitionMap)\n );\n\n case \"flip\":\n return new Flip(attributes, nodeFactory(definition.child, rootNodeDefinitionMap));\n\n case \"succeed\":\n return new Succeed(attributes, nodeFactory(definition.child, rootNodeDefinitionMap));\n\n case \"fail\":\n return new Fail(attributes, nodeFactory(definition.child, rootNodeDefinitionMap));\n\n case \"sequence\":\n return new Sequence(\n attributes,\n definition.children.map((child) => nodeFactory(child, rootNodeDefinitionMap))\n );\n\n case \"selector\":\n return new Selector(\n attributes,\n definition.children.map((child) => nodeFactory(child, rootNodeDefinitionMap))\n );\n\n case \"parallel\":\n return new Parallel(\n attributes,\n definition.children.map((child) => nodeFactory(child, rootNodeDefinitionMap))\n );\n\n case \"lotto\":\n return new Lotto(\n attributes,\n definition.weights,\n definition.children.map((child) => nodeFactory(child, rootNodeDefinitionMap))\n );\n\n case \"branch\":\n return nodeFactory(rootNodeDefinitionMap[definition.ref].child, rootNodeDefinitionMap);\n\n case \"action\":\n return new Action(attributes, definition.call, definition.args || []);\n\n case \"condition\":\n return new Condition(attributes, definition.call, definition.args || []);\n\n case \"wait\":\n let duration: number | null = null;\n let durationMin: number | null = null;\n let durationMax: number | null = null;\n\n if (Array.isArray(definition.duration)) {\n durationMin = definition.duration[0];\n durationMax = definition.duration[1];\n } else if (isInteger(definition.duration)) {\n duration = definition.duration!;\n }\n\n return new Wait(attributes, duration, durationMin, durationMax);\n }\n}\n\n/**\n * Creates an array of node attribute instances based on the specified node definition.\n * @param definition The node definition.\n * @returns An array of node attribute instances based on the specified node definition.\n */\nfunction nodeAttributesFactory(definition: AnyNodeDefinition): Attribute[] {\n const attributes: Attribute[] = [];\n\n if (definition.while) {\n attributes.push(new While(definition.while.call, definition.while.args ?? []));\n }\n\n if (definition.until) {\n attributes.push(new Until(definition.until.call, definition.until.args ?? []));\n }\n\n if (definition.entry) {\n attributes.push(new Entry(definition.entry.call, definition.entry.args ?? []));\n }\n\n if (definition.step) {\n attributes.push(new Step(definition.step.call, definition.step.args ?? []));\n }\n\n if (definition.exit) {\n attributes.push(new Exit(definition.exit.call, definition.exit.args ?? []));\n }\n\n return attributes;\n}\n\n/**\n * Creates a mapping of root node identifers to root node definitions, mixing in globally registered subtree root node definitions.\n * @param definition The root node definitions.\n * @returns A mapping of root node identifers to root node definitions, including globally registered subtree root node definitions.\n */\nfunction createRootNodeDefinitionMap(definition: RootNodeDefinition[]): RootNodeDefinitionMap {\n // Create a mapping of root node identifers to root node definitions.\n const rootNodeMap: RootNodeDefinitionMap = {};\n\n // Add in any registered subtree root node definitions.\n for (const [name, rootNodeDefinition] of Object.entries(Lookup.getSubtrees())) {\n // The name used when registering the subtree will be used as the root node identifier.\n rootNodeMap[name] = { ...rootNodeDefinition, id: name };\n }\n\n // Populate the map with the root node definitions that were included with the tree definition.\n // We do this after adding any registered subtrees as we want these to take presedence.\n for (const rootNodeDefinition of definition) {\n rootNodeMap[rootNodeDefinition.id ?? MAIN_ROOT_NODE_KEY] = rootNodeDefinition;\n }\n\n return rootNodeMap;\n}\n\n/**\n * Applies a guard path to every leaf of the tree to evaluate as part of each update.\n * @param root The main root tree node.\n */\nfunction applyLeafNodeGuardPaths(root: Root) {\n const nodePaths: Node[][] = [];\n\n const findLeafNodes = (path: Node[], node: Node) => {\n // Add the current node to the path.\n path = path.concat(node);\n\n // Check whether the current node is a leaf node.\n if (node.isLeafNode()) {\n nodePaths.push(path);\n } else {\n (node as Composite | Decorator).getChildren().forEach((child) => findLeafNodes(path, child));\n }\n };\n\n // Find all leaf node paths, starting from the root.\n findLeafNodes([], root);\n\n nodePaths.forEach((path) => {\n // Each node in the current path will have to be assigned a guard path, working from the root outwards.\n for (let depth = 0; depth < path.length; depth++) {\n // Get the node in the path at the current depth.\n const currentNode = path[depth];\n\n // The node may already have been assigned a guard path, if so just skip it.\n if (currentNode.hasGuardPath()) {\n continue;\n }\n\n // Create the guard path for the current node.\n const guardPath = new GuardPath(\n path\n .slice(0, depth + 1)\n .map((node) => ({ node, guards: node.getGuardAttributes() }))\n .filter((details) => details.guards.length > 0)\n );\n\n // Assign the guard path to the current node.\n currentNode.setGuardPath(guardPath);\n }\n });\n}\n", "import State, { AnyState } from \"./State\";\nimport Lookup from \"./Lookup\";\nimport Node from \"./nodes/Node\";\nimport Root from \"./nodes/decorator/Root\";\nimport Composite from \"./nodes/composite/Composite\";\nimport Decorator from \"./nodes/decorator/Decorator\";\nimport { Agent, GlobalFunction } from \"./Agent\";\nimport { CallbackAttributeDetails } from \"./attributes/callbacks/Callback\";\nimport { GuardAttributeDetails } from \"./attributes/guards/Guard\";\nimport { BehaviourTreeOptions } from \"./BehaviourTreeOptions\";\nimport { convertMDSLToJSON } from \"./mdsl/MDSLDefinitionParser\";\nimport { RootNodeDefinition } from \"./BehaviourTreeDefinition\";\nimport { validateDefinition, validateJSONDefinition } from \"./BehaviourTreeDefinitionValidator\";\nimport buildRootNode from \"./BehaviourTreeBuilder\";\nimport { isNullOrUndefined } from \"./BehaviourTreeDefinitionUtilities\";\n\n// Purely for outside inspection of the tree.\nexport type FlattenedTreeNode = {\n id: string;\n type: string;\n caption: string;\n state: AnyState;\n guards: GuardAttributeDetails[];\n callbacks: CallbackAttributeDetails[];\n args: any[];\n parentId: string | null;\n};\n\n/**\n * A representation of a behaviour tree.\n */\nexport class BehaviourTree {\n /**\n * The main root tree node.\n */\n private readonly _rootNode: Root;\n\n /**\n * Creates a new instance of the BehaviourTree class.\n * @param definition The behaviour tree definition as either an MDSL string, root node definition object or array of root node definition objects.\n * @param agent The agent instance that this behaviour tree is modelling behaviour for.\n * @param options The behaviour tree options object.\n */\n constructor(\n definition: string | RootNodeDefinition | RootNodeDefinition[],\n private agent: Agent,\n private options: BehaviourTreeOptions = {}\n ) {\n // The tree definition must be defined.\n if (isNullOrUndefined(definition)) {\n throw new Error(\"tree definition not defined\");\n }\n\n // The agent must be defined and not null.\n if (typeof agent !== \"object\" || agent === null) {\n throw new Error(\"the agent must be an object and not null\");\n }\n\n // We should validate the definition before we try to build the tree nodes.\n const { succeeded, errorMessage, json } = validateDefinition(definition);\n\n // Did our validation fail without error?\n if (!succeeded) {\n throw new Error(`invalid definition: ${errorMessage}`);\n }\n\n // Double check that we did actually get our json definition as part of our definition validtion.\n if (!json) {\n throw new Error(\n \"expected json definition to be returned as part of successful definition validation response\"\n );\n }\n\n try {\n // Create the populated tree of behaviour tree nodes and get the root node.\n this._rootNode = buildRootNode(json);\n } catch (exception) {\n // There was an issue in trying build and populate the behaviour tree.\n throw new Error(`error building tree: ${(exception as Error).message}`);\n }\n }\n\n /**\n * Gets whether the tree is in the RUNNING state.\n * @returns true if the tree is in the RUNNING state, otherwise false.\n */\n isRunning() {\n return this._rootNode.getState() === State.RUNNING;\n }\n\n /**\n * Gets the current tree state of SUCCEEDED, FAILED, READY or RUNNING.\n * @returns The current tree state.\n */\n getState() {\n return this._rootNode.getState();\n }\n\n /**\n * Step the tree.\n * 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.\n * 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\n * 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.\n *\n * 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.\n */\n step() {\n // If the root node has already been stepped to completion then we need to reset it.\n if (this._rootNode.getState() === State.SUCCEEDED || this._rootNode.getState() === State.FAILED) {\n this._rootNode.reset();\n }\n\n try {\n this._rootNode.update(this.agent, this.options);\n } catch (exception) {\n throw new Error(`error stepping tree: ${(exception as Error).message}`);\n }\n }\n\n /**\n * Resets the tree from the root node outwards to each nested node, giving each a state of READY.\n */\n reset() {\n this._rootNode.reset();\n }\n\n /**\n * Gets the flattened details of every node in the tree.\n * @returns The flattened details of every node in the tree.\n */\n getFlattenedNodeDetails(): FlattenedTreeNode[] {\n // Create an empty flattened array of tree nodes.\n const flattenedTreeNodes: FlattenedTreeNode[] = [];\n\n /**\n * Helper function to process a node instance and push details into the flattened tree nodes array.\n * @param node The current node.\n * @param parentUid The UID of the node parent, or null if the node is the main root node.\n */\n const processNode = (node: Node, parentUid: string | null) => {\n // Get the guard and callback attribute details for this node.\n const guards = node\n .getAttributes()\n .filter((attribute) => attribute.isGuard())\n .map((attribute) => attribute.getDetails()) as GuardAttributeDetails[];\n const callbacks = node\n .getAttributes()\n .filter((attribute) => !attribute.isGuard())\n .map((attribute) => attribute.getDetails()) as CallbackAttributeDetails[];\n\n // Push the current node into the flattened nodes array.\n flattenedTreeNodes.push({\n id: node.getUid(),\n type: node.getType(),\n caption: node.getName(),\n state: node.getState(),\n guards,\n callbacks,\n args: node.getArguments(),\n parentId: parentUid\n });\n\n // Process each of the nodes children if it is not a leaf node.\n if (!node.isLeafNode()) {\n (node as Composite | Decorator)\n .getChildren()\n .forEach((child) => processNode(child, (node as Composite | Decorator).getUid()));\n }\n };\n\n // Convert the nested node structure into a flattened array of node details.\n processNode(this._rootNode, null);\n\n return flattenedTreeNodes;\n }\n\n /**\n * Registers the action/condition/guard/callback function or subtree with the given name.\n * @param name The name of the function or subtree to register.\n * @param value The function or subtree definition to register.\n */\n static register(name: string, value: GlobalFunction | string | RootNodeDefinition) {\n // Are we going to register a action/condition/guard/callback function?\n if (typeof value === \"function\") {\n Lookup.setFunc(name, value);\n return;\n }\n\n // We are not registering an action/condition/guard/callback function, so we must be registering a subtree.\n if (typeof value === \"string\") {\n let rootNodeDefinitions: RootNodeDefinition[];\n\n // We will assume that any string passed in will be a mdsl definition.\n try {\n rootNodeDefinitions = convertMDSLToJSON(value);\n } catch (exception) {\n throw new Error(`error registering definition, invalid MDSL: ${(exception as Error).message}`);\n }\n\n // This function should only ever be called with a definition containing a single unnamed root node.\n if (rootNodeDefinitions.length != 1 || rootNodeDefinitions[0].id !== null) {\n throw new Error(\"error registering definition: expected a single unnamed root node\");\n }\n\n try {\n // We should validate the subtree as we don't want invalid subtrees available via the lookup.\n const { succeeded, errorMessage } = validateJSONDefinition(rootNodeDefinitions[0]);\n\n // Did our validation fail without error?\n if (!succeeded) {\n throw new Error(errorMessage);\n }\n } catch (exception) {\n throw new Error(`error registering definition: ${(exception as Error).message}`);\n }\n\n // Everything seems hunky-dory, register the subtree.\n Lookup.setSubtree(name, rootNodeDefinitions[0]);\n } else if (typeof value === \"object\" && !Array.isArray(value)) {\n // We will assume that any object passed in is a root node definition.\n\n try {\n // We should validate the subtree as we don't want invalid subtrees available via the lookup.\n const { succeeded, errorMessage } = validateJSONDefinition(value);\n\n // Did our validation fail without error?\n if (!succeeded) {\n throw new Error(errorMessage);\n }\n } catch (exception) {\n throw new Error(`error registering definition: ${(exception as Error).message}`);\n }\n\n // Everything seems hunky-dory, register the subtree.\n Lookup.setSubtree(name, value);\n } else {\n throw new Error(\"unexpected value, expected string mdsl definition, root node json definition or function\");\n }\n }\n\n /**\n * Unregisters the registered action/condition/guard/callback function or subtree with the given name.\n * @param name The name of the registered action/condition/guard/callback function or subtree to unregister.\n */\n static unregister(name: string): void {\n Lookup.remove(name);\n }\n\n /**\n * Unregister all registered action/condition/guard/callback functions and subtrees.\n */\n static unregisterAll(): void {\n Lookup.empty();\n }\n}\n"], - "mappings": "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", + "sourcesContent": ["\"use strict\";\r\nObject.defineProperty(exports, \"__esModule\", { value: true });\r\nexports.Participant = void 0;\r\n/**\r\n * A participant that holds a number of tickets.\r\n */\r\nvar Participant = /** @class */ (function () {\r\n /**\r\n * Creates an instance of the Participant class.\r\n * @param participant The actual participant.\r\n * @param tickets The number of tickets held by the participant.\r\n */\r\n function Participant(participant, tickets) {\r\n if (tickets === void 0) { tickets = 1; }\r\n this._participant = participant;\r\n this._tickets = tickets;\r\n }\r\n Object.defineProperty(Participant.prototype, \"participant\", {\r\n /** Gets the actual participant. */\r\n get: function () {\r\n return this._participant;\r\n },\r\n enumerable: false,\r\n configurable: true\r\n });\r\n Object.defineProperty(Participant.prototype, \"tickets\", {\r\n /** Gets or sets the number of tickets held by the participant. */\r\n get: function () {\r\n return this._tickets;\r\n },\r\n set: function (value) {\r\n this._tickets = value;\r\n },\r\n enumerable: false,\r\n configurable: true\r\n });\r\n return Participant;\r\n}());\r\nexports.Participant = Participant;\r\n", "\"use strict\";\r\nObject.defineProperty(exports, \"__esModule\", { value: true });\r\nexports.isNaturalNumber = exports.isNullOrUndefined = void 0;\r\n/**\r\n * Gets whether the value provided is null or undefined.\r\n * @param value The value to check.\r\n * @returns Whether the value provided is null or undefined.\r\n */\r\nfunction isNullOrUndefined(value) {\r\n return value === null || value === undefined;\r\n}\r\nexports.isNullOrUndefined = isNullOrUndefined;\r\n/**\r\n * Gets whether the value provided is a natural number.\r\n * @param value The value to check.\r\n * @returns Whether the value provided is a natural number.\r\n */\r\nfunction isNaturalNumber(value) {\r\n return typeof value === \"number\" && value >= 1 && Math.floor(value) === value;\r\n}\r\nexports.isNaturalNumber = isNaturalNumber;\r\n", "\"use strict\";\r\nObject.defineProperty(exports, \"__esModule\", { value: true });\r\nexports.Lotto = void 0;\r\nvar Participant_1 = require(\"./Participant\");\r\nvar Utilities_1 = require(\"./Utilities\");\r\n/**\r\n * Represents a lotto consisting of a number of pickable ticket-holding participants.\r\n */\r\nvar Lotto = /** @class */ (function () {\r\n /**\r\n * Creates a new instance of Lotto.\r\n * @param customRandom The custom RNG to use in place of Math.random().\r\n */\r\n function Lotto(customRandom) {\r\n /** The array of participants that are holding tickets in the lotto. */\r\n this._participants = [];\r\n this._customRandom = customRandom;\r\n }\r\n /**\r\n * Adds a participant with the specified number of tickets, or adds to the participant ticket count if the participant already holds tickets.\r\n * @param participant The participant to add or to increase the ticket count for if they already hold tickets.\r\n * @param tickets The number of tickets, defaults to 1.\r\n * @returns The Lotto instance.\r\n */\r\n Lotto.prototype.add = function (participant, tickets) {\r\n if (tickets === void 0) { tickets = 1; }\r\n // Check that we have a valid ticket count.\r\n if (!(0, Utilities_1.isNaturalNumber)(tickets)) {\r\n throw new Error(\"tickets value must be a natural number\");\r\n }\r\n // Check whether this participant has already been added.\r\n var existingParticipant = this._participants.find(function (part) { return part.participant === participant; });\r\n if (existingParticipant) {\r\n // The participant has already been added to the lotto so just add to their ticket count.\r\n existingParticipant.tickets += tickets;\r\n }\r\n else {\r\n // The participant is not part of the lotto so we should add them.\r\n this._participants.push(new Participant_1.Participant(participant, tickets));\r\n }\r\n return this;\r\n };\r\n /**\r\n * Removes the specified number of tickets for the given participant from the draw, or all tickets if a ticket number is not defined.\r\n * @param participant The participant to remove tickets for.\r\n * @param tickets The number of tickets to remove, or undefined if all tickets are to be removed.\r\n * @returns The Lotto instance.\r\n */\r\n Lotto.prototype.remove = function (participant, tickets) {\r\n // Attempt to get the existing participant.\r\n var existingParticipant = this._participants.find(function (part) { return part.participant === participant; });\r\n // There is nothing to do if the specified participant isn't even part of the lotto.\r\n if (!existingParticipant) {\r\n return this;\r\n }\r\n // Check whether a tickets value was given.\r\n if (tickets !== undefined) {\r\n // Check that we have a valid ticket count.\r\n if (!(0, Utilities_1.isNaturalNumber)(tickets)) {\r\n throw new Error(\"tickets value must be a natural number\");\r\n }\r\n existingParticipant.tickets -= tickets;\r\n // If the participant no longer holds any tickets then they should be removed.\r\n if (existingParticipant.tickets < 1) {\r\n this._participants = this._participants.filter(function (part) { return part !== existingParticipant; });\r\n }\r\n }\r\n else {\r\n // We are removing all tickets for the participant so just remove them from the lotto.\r\n this._participants = this._participants.filter(function (part) { return part !== existingParticipant; });\r\n }\r\n return this;\r\n };\r\n /**\r\n * Draw a winning ticket and return the participant that holds the ticket.\r\n * @param options The draw options.\r\n * @returns The participant that holds the winning ticket.\r\n */\r\n Lotto.prototype.draw = function (options) {\r\n if (options === void 0) { options = {}; }\r\n // If we have no participants then just return null.\r\n if (this._participants.length === 0) {\r\n return null;\r\n }\r\n var redrawable = (0, Utilities_1.isNullOrUndefined)(options.redrawable) ? true : options.redrawable;\r\n var pickable = [];\r\n this._participants.forEach(function (_a) {\r\n var participant = _a.participant, tickets = _a.tickets;\r\n for (var ticketCount = 0; ticketCount < tickets; ticketCount++) {\r\n pickable.push(participant);\r\n }\r\n });\r\n var random;\r\n // We need a random floating-point number between 0 (inclusive) and 1 to scale up to pick our winner.\r\n // If a custom random function exists then we should use that or fall back to Math.random().\r\n if (this._customRandom) {\r\n // Call our custom random function to get a random floating-point number.\r\n random = this._customRandom();\r\n // Verify that the result of calling our custom random function is a number between 0 (inclusive) and 1.\r\n if (typeof random !== \"number\" || random < 0 || random >= 1) {\r\n throw new Error(\"the 'random' function provided did not return a number between 0 (inclusive) and 1\");\r\n }\r\n }\r\n else {\r\n // No custom random function was defined so just use good ol' Math.random().\r\n random = Math.random();\r\n }\r\n // Pick a winning participant.\r\n var winner = pickable[Math.floor(random * pickable.length)];\r\n // If the ticket isn't redrawable then we should remove a ticket from the winning participants ticket count.\r\n if (!redrawable) {\r\n this.remove(winner, 1);\r\n }\r\n // Return the winning participant.\r\n return winner;\r\n };\r\n /**\r\n * Draws multiple winning tickets and return an array of the participants that hold the winning tickets.\r\n * @param tickets The number of winning tickets to draw.\r\n * @param options The draw multiple options.\r\n * @returns An array of the participants that hold the winning tickets.\r\n */\r\n Lotto.prototype.drawMultiple = function (tickets, options) {\r\n if (options === void 0) { options = {}; }\r\n var uniqueResults = (0, Utilities_1.isNullOrUndefined)(options.unique) ? false : options.unique;\r\n // Handle cases where the user has asked for zero tickets (no idea why they would do this be we should trust them).\r\n if (tickets === 0) {\r\n return [];\r\n }\r\n // Now that we know out tickets value is not zero we should check that it is a valid natural number.\r\n if (!(0, Utilities_1.isNaturalNumber)(tickets)) {\r\n throw new Error(\"tickets value must be a natural number\");\r\n }\r\n var result = [];\r\n // Keep drawing tickets until we either reach the number of required tickets or we simply run out of tickets to draw.\r\n // We can run out of tickets to draw if 'options.redrawable' is explicity 'false' or we just had no participants when 'drawMultiple' was called.\r\n while (result.length < tickets && this._participants.length > 0) {\r\n result.push(this.draw(options));\r\n }\r\n // If the 'unique' draw option is set then we need to remove duplicates from the result list.\r\n if (uniqueResults) {\r\n // Create an array to store our unique results.\r\n var unique = [];\r\n // Iterate over all of our participants (with potential duplicates) and populate our array of unique values.\r\n for (var _i = 0, result_1 = result; _i < result_1.length; _i++) {\r\n var participant = result_1[_i];\r\n if (unique.indexOf(participant) === -1) {\r\n unique.push(participant);\r\n }\r\n }\r\n result = unique;\r\n }\r\n return result;\r\n };\r\n return Lotto;\r\n}());\r\nexports.Lotto = Lotto;\r\n", "\"use strict\";\r\nObject.defineProperty(exports, \"__esModule\", { value: true });\r\nexports.createLotto = void 0;\r\nvar Lotto_1 = require(\"./Lotto\");\r\n/**\r\n * A function that creates and returns a Lotto instance.\r\n * @param participantsOrOptions An array of initial participants or options relating to the creation of a Lotto instance.\r\n * @returns A new Lotto instance.\r\n */\r\nfunction createLotto(participantsOrOptions) {\r\n // If no initial participants or lotto options were provided as an argument then we can just return a new lotto instance now.\r\n if (!participantsOrOptions) {\r\n return new Lotto_1.Lotto();\r\n }\r\n // Check whether we were provided with an array of initial participants or a lotto options object.\r\n if (Array.isArray(participantsOrOptions)) {\r\n // We are dealing with a pre-defined array of participants.\r\n var participants = participantsOrOptions;\r\n var lotto_1 = new Lotto_1.Lotto();\r\n // If the lotto participants have been defined upfront then we will need to add them all to our lotto instance now.\r\n participants.forEach(function (_a) {\r\n var participant = _a[0], tokens = _a[1];\r\n return lotto_1.add(participant, tokens);\r\n });\r\n // Return the Lotto instance.\r\n return lotto_1;\r\n }\r\n else {\r\n // We are dealing with some lotto options.\r\n var random = participantsOrOptions.random, participants = participantsOrOptions.participants;\r\n // Create a Lotto instance passing the custom RNG function to use in place of Math.random() (which could be undefined).\r\n var lotto_2 = new Lotto_1.Lotto(random);\r\n // If the lotto participants have been defined upfront as part of the options then we will need to add them all to our lotto instance now.\r\n if (participants) {\r\n participants.forEach(function (_a) {\r\n var participant = _a[0], tokens = _a[1];\r\n return lotto_2.add(participant, tokens);\r\n });\r\n }\r\n // Return the Lotto instance.\r\n return lotto_2;\r\n }\r\n}\r\nexports.createLotto = createLotto;\r\n", "\"use strict\";\r\nObject.defineProperty(exports, \"__esModule\", { value: true });\r\nvar createLotto_1 = require(\"./createLotto\");\r\nexports.default = createLotto_1.createLotto;\r\n", "import State from \"./State\";\nimport { validateDefinition } from \"./BehaviourTreeDefinitionValidator\";\nimport { convertMDSLToJSON } from \"./mdsl/MDSLDefinitionParser\";\nimport { BehaviourTree, FlattenedTreeNode } from \"./BehaviourTree\";\nimport { BehaviourTreeOptions } from \"./BehaviourTreeOptions\";\n\nexport { BehaviourTree, State, convertMDSLToJSON, validateDefinition };\nexport type { FlattenedTreeNode, BehaviourTreeOptions };\n", "/**\n * Enumeration of node state types.\n */\nexport enum State {\n READY = \"mistreevous.ready\",\n RUNNING = \"mistreevous.running\",\n SUCCEEDED = \"mistreevous.succeeded\",\n FAILED = \"mistreevous.failed\"\n}\n\nexport { State as default };\n\nexport type CompleteState = State.SUCCEEDED | State.FAILED;\nexport type AnyState = State.READY | State.RUNNING | CompleteState;\n", "import {\n NodeDefinition,\n RootNodeDefinition,\n DecoratorNodeDefinition,\n CompositeNodeDefinition,\n AnyNodeDefinition,\n BranchNodeDefinition\n} from \"./BehaviourTreeDefinition\";\n\n/**\n * A type guard function that returns true if the specified node satisfies the RootNodeDefinition type.\n * @param node The node.\n * @returns A value of true if the specified node satisfies the RootNodeDefinition type.\n */\nexport function isRootNode(node: NodeDefinition): node is RootNodeDefinition {\n return node.type === \"root\";\n}\n\n/**\n * A type guard function that returns true if the specified node satisfies the BranchNodeDefinition type.\n * @param node The node.\n * @returns A value of true if the specified node satisfies the BranchNodeDefinition type.\n */\nexport function isBranchNode(node: NodeDefinition): node is BranchNodeDefinition {\n return node.type === \"branch\";\n}\n\n/**\n * A type guard function that returns true if the specified node satisfies the NodeDefinition type.\n * @param node The node.\n * @returns A value of true if the specified node satisfies the NodeDefinition type.\n */\nexport function isLeafNode(node: NodeDefinition): node is NodeDefinition {\n return [\"branch\", \"action\", \"condition\", \"wait\"].includes(node.type);\n}\n\n/**\n * A type guard function that returns true if the specified node satisfies the DecoratorNodeDefinition type.\n * @param node The node.\n * @returns A value of true if the specified node satisfies the DecoratorNodeDefinition type.\n */\nexport function isDecoratorNode(node: NodeDefinition): node is DecoratorNodeDefinition {\n return [\"root\", \"repeat\", \"retry\", \"flip\", \"succeed\", \"fail\"].includes(node.type);\n}\n\n/**\n * A type guard function that returns true if the specified node satisfies the CompositeNodeDefinition type.\n * @param node The node.\n * @returns A value of true if the specified node satisfies the CompositeNodeDefinition type.\n */\nexport function isCompositeNode(node: NodeDefinition): node is CompositeNodeDefinition {\n return [\"sequence\", \"selector\", \"lotto\", \"parallel\"].includes(node.type);\n}\n\n/**\n * Flatten a node definition into an array of all of its nested node definitions.\n * @param nodeDefinition The node definition to flatten.\n * @returns An array of all of nested node definitions.\n */\nexport function flattenDefinition(nodeDefinition: AnyNodeDefinition): AnyNodeDefinition[] {\n const nodes: AnyNodeDefinition[] = [];\n\n const processNode = (currentNodeDefinition: AnyNodeDefinition) => {\n nodes.push(currentNodeDefinition);\n\n if (isCompositeNode(currentNodeDefinition)) {\n currentNodeDefinition.children.forEach(processNode);\n } else if (isDecoratorNode(currentNodeDefinition)) {\n processNode(currentNodeDefinition.child);\n }\n };\n\n processNode(nodeDefinition);\n\n return nodes;\n}\n\n/**\n * Determines whether the passed value is an integer.\n * @param value The value to check.\n * @returns Whether the passed value is an integer.\n */\nexport function isInteger(value: unknown): boolean {\n return typeof value === \"number\" && Math.floor(value) === value;\n}\n\n/**\n * Determines whether the passed value is null or undefined.\n * @param value The value to check.\n * @returns Whether the passed value is null or undefined.\n */\nexport function isNullOrUndefined(value: unknown): boolean {\n return typeof value === \"undefined\" || value === null;\n}\n", "/**\n * A type defining an object that holds a reference to substitued string literals parsed from the definition.\n */\nexport type StringLiteralPlaceholders = { [key: string]: string };\n\n/**\n * Pop the next raw token from the specified array of tokens and throw an error if it wasn't the expected one.\n * @param tokens The array of tokens.\n * @param expected An optional string or array or items, one of which must match the next popped token.\n * @returns The popped token.\n */\nexport function popAndCheck(tokens: string[], expected?: string | string[]): string {\n // Get and remove the next token.\n const popped = tokens.shift();\n\n // We were expecting another token but there aren't any.\n if (popped === undefined) {\n throw new Error(\"unexpected end of definition\");\n }\n\n // Do we have an expected token/tokens array?\n if (expected != undefined) {\n // Get an array of expected values, if the popped token matches any then we are all good.\n const expectedValues = typeof expected === \"string\" ? [expected] : expected;\n\n // Check whether the popped token matches at least one of our expected items.\n var tokenMatchesExpectation = expectedValues.some((item) => popped.toUpperCase() === item.toUpperCase());\n\n // Throw an error if the popped token didn't match any of our expected items.\n if (!tokenMatchesExpectation) {\n const expectationString = expectedValues.map((item) => \"'\" + item + \"'\").join(\" or \");\n throw new Error(\"unexpected token found. Expected \" + expectationString + \" but got '\" + popped + \"'\");\n }\n }\n\n // Return the popped token.\n return popped;\n}\n\n/**\n * Swaps out any node/attribute argument string literals with placeholders.\n * @param definition The definition.\n * @returns An object containing a mapping of placeholders to original string values as well as the processed definition string.\n */\nexport function substituteStringLiterals(definition: string): {\n placeholders: StringLiteralPlaceholders;\n processedDefinition: string;\n} {\n // Create an object to hold the mapping of placeholders to original string values.\n const placeholders: StringLiteralPlaceholders = {};\n\n // Replace any string literals wrapped with double quotes in our definition with placeholders to be processed later.\n const processedDefinition = definition.replace(/\\\"(\\\\.|[^\"\\\\])*\\\"/g, (match) => {\n var strippedMatch = match.substring(1, match.length - 1);\n var placeholder = Object.keys(placeholders).find((key) => placeholders[key] === strippedMatch);\n\n // If we have no existing string literal match then create a new placeholder.\n if (!placeholder) {\n placeholder = `@@${Object.keys(placeholders).length}@@`;\n placeholders[placeholder] = strippedMatch;\n }\n\n return placeholder;\n });\n\n return { placeholders, processedDefinition };\n}\n\n/**\n * Parse the tree definition into an array of raw tokens.\n * @param definition The definition.\n * @returns An array of tokens parsed from the definition.\n */\nexport function parseTokensFromDefinition(definition: string): string[] {\n // Add some space around various important characters so that they can be plucked out easier as individual tokens.\n definition = definition.replace(/\\(/g, \" ( \");\n definition = definition.replace(/\\)/g, \" ) \");\n definition = definition.replace(/\\{/g, \" { \");\n definition = definition.replace(/\\}/g, \" } \");\n definition = definition.replace(/\\]/g, \" ] \");\n definition = definition.replace(/\\[/g, \" [ \");\n definition = definition.replace(/\\,/g, \" , \");\n\n // Split the definition into raw token form and return it.\n return definition.replace(/\\s+/g, \" \").trim().split(\" \");\n}\n", "import { StringLiteralPlaceholders, popAndCheck } from \"./MDSLUtilities\";\n\n/**\n * A type representing any node function argument.\n */\ntype Argument = {\n /**\n * The argument value.\n */\n value: T;\n /**\n * The argument type, used for validation.\n */\n type: string;\n};\n\ntype NullArgument = Argument & {\n type: \"null\";\n};\n\ntype BooleanArgument = Argument & {\n type: \"boolean\";\n};\n\ntype NumberArgument = Argument & {\n type: \"number\";\n /**\n * A flag defining whether the number argument value is a valid integer. (used for validation)\n */\n isInteger: boolean;\n};\n\ntype StringPlaceholderArgument = Argument & {\n type: \"string\";\n};\n\ntype IdentifierArgument = Argument & {\n type: \"identifier\";\n};\n\n/**\n * A type representing a reference to any node function argument.\n */\ntype AnyArgument = NullArgument | BooleanArgument | NumberArgument | StringPlaceholderArgument | IdentifierArgument;\n\n/**\n * Parse an array of argument definitions from the specified tokens array.\n * @param tokens The array tokens to parse the argument definitions from.\n * @param stringArgumentPlaceholders The mapping of string literal node argument placeholders to original values.\n * @param argumentValidator The argument validator function.\n * @param validationFailedMessage The exception message to throw if argument validation fails.\n * @returns An array of argument definitions parsed from the specified tokens array.\n */\nexport function parseArgumentTokens(\n tokens: string[],\n stringArgumentPlaceholders: StringLiteralPlaceholders\n): AnyArgument[] {\n const argumentList: AnyArgument[] = [];\n\n // If the next token is not a '[' or '(' then we have no arguments to parse.\n if (![\"[\", \"(\"].includes(tokens[0])) {\n return argumentList;\n }\n\n // Any lists of arguments will always be wrapped in '[]' for node arguments or '()' for attribute arguments.\n // We are looking for a '[' or '(' opener that wraps the argument tokens and the relevant closer.\n const closingToken = popAndCheck(tokens, [\"[\", \"(\"]) === \"[\" ? \"]\" : \")\";\n\n const argumentListTokens: string[] = [];\n\n // Grab all tokens between the '[' and ']' or '(' and ')'.\n while (tokens.length && tokens[0] !== closingToken) {\n // The next token is part of our arguments list.\n argumentListTokens.push(tokens.shift()!);\n }\n\n // Validate the order of the argument tokens. Each token must either be a ',' or a single argument that satisfies the validator.\n argumentListTokens.forEach((token, index) => {\n // Get whether this token should be an actual argument.\n const shouldBeArgumentToken = !(index & 1);\n\n // If the current token should be an actual argument then validate it, otherwise it should be a ',' token.\n if (shouldBeArgumentToken) {\n // Get the argument definition.\n const argumentDefinition = getArgumentDefinition(token, stringArgumentPlaceholders);\n\n // This is a valid argument!\n argumentList.push(argumentDefinition);\n } else {\n // The current token should be a ',' token.\n if (token !== \",\") {\n throw new Error(`invalid argument list, expected ',' or ']' but got '${token}'`);\n }\n }\n });\n\n // The arguments list should terminate with a ']' or ')' token, depending on the opener.\n popAndCheck(tokens, closingToken);\n\n // Return the arguments.\n return argumentList;\n}\n\n/**\n * Gets an argument value definition.\n * @param token The argument token.\n * @param stringArgumentPlaceholders The mapping of string literal node argument placeholders to original values.\n * @returns An argument value definition.\n */\nfunction getArgumentDefinition(token: string, stringArgumentPlaceholders: StringLiteralPlaceholders): AnyArgument {\n // Check whether the token represents a null value.\n if (token === \"null\") {\n return {\n value: null,\n type: \"null\"\n } as NullArgument;\n }\n\n // Check whether the token represents a boolean value.\n if (token === \"true\" || token === \"false\") {\n return {\n value: token === \"true\",\n type: \"boolean\"\n } as BooleanArgument;\n }\n\n // Check whether the token represents a number value.\n // TODO: Relies on broken isNaN - see MDN.\n // if (!Number.isNaN(token)) {\n if (!isNaN(token as any)) {\n return {\n value: parseFloat(token),\n isInteger: parseFloat(token) === parseInt(token, 10),\n type: \"number\"\n } as NumberArgument;\n }\n\n // Check whether the token is a placeholder (e.g. @@0@@) representing a string literal.\n if (token.match(/^@@\\d+@@$/g)) {\n return {\n value: stringArgumentPlaceholders[token].replace('\\\\\"', '\"'),\n type: \"string\"\n } as StringPlaceholderArgument;\n }\n\n // The only remaining option is that the argument value is an identifier.\n return {\n value: token,\n type: \"identifier\"\n } as IdentifierArgument;\n}\n", "import { NodeAttributeDefinition } from \"../BehaviourTreeDefinition\";\nimport { parseArgumentTokens } from \"./MDSLNodeArgumentParser\";\nimport { StringLiteralPlaceholders } from \"./MDSLUtilities\";\n\n/**\n * A type defining the attribute definitions of a node.\n */\ntype NodeAttributes = {\n while?: NodeAttributeDefinition;\n until?: NodeAttributeDefinition;\n entry?: NodeAttributeDefinition;\n exit?: NodeAttributeDefinition;\n step?: NodeAttributeDefinition;\n};\n\n/**\n * Parse any node attribute definitions from the specified tokens array.\n * @param tokens The array of remaining tokens.\n * @param stringArgumentPlaceholders The mapping of string literal node argument placeholders to original values.\n * @returns An object of attribute definitions defined by any directly following tokens.\n */\nexport function parseAttributeTokens(\n tokens: string[],\n stringArgumentPlaceholders: StringLiteralPlaceholders\n): NodeAttributes {\n const nodeAttributeNames: (keyof NodeAttributes)[] = [\"while\", \"until\", \"entry\", \"exit\", \"step\"];\n\n // Create an object to hold any attributes found.\n const attributes: NodeAttributes = {};\n\n // Try to get the name of the attribute for the next token.\n let nextAttributeName = tokens[0]?.toLowerCase() as keyof NodeAttributes;\n\n // Pull attribute tokens as well as their arguments off of the tokens stack until we have no more.\n while (nodeAttributeNames.includes(nextAttributeName)) {\n // Check to make sure that we have not already created an attribute definition of this type.\n if (attributes[nextAttributeName]) {\n throw new Error(`duplicate attribute '${tokens[0].toUpperCase()}' found for node`);\n }\n\n // Remove the attribute name token from the array of tokens.\n tokens.shift();\n\n // Grab the attribute arguments, assuming the first to be an identifier.\n const [attributeCallIdentifier, ...attributeArguments] = parseArgumentTokens(\n tokens,\n stringArgumentPlaceholders\n );\n\n // The first attribute argument has to be an identifer, this will reference an agent function.\n if (attributeCallIdentifier?.type !== \"identifier\") {\n throw new Error(\"expected agent function or registered function name identifier argument for attribute\");\n }\n\n // Any attribute arguments (other than the expected call identifier) must have a type of string, number, boolean or null.\n attributeArguments\n .filter((arg) => arg.type === \"identifier\")\n .forEach((arg) => {\n throw new Error(\n `invalid attribute argument value '${arg.value}', must be string, number, boolean or null`\n );\n });\n\n // Create the attribute definition and add it to the object of attribute definitions found.\n attributes[nextAttributeName] = {\n call: attributeCallIdentifier.value,\n args: attributeArguments.map(({ value }) => value)\n };\n\n // Try to get the next attribute name token, as there could be multiple.\n nextAttributeName = tokens[0]?.toLowerCase() as keyof NodeAttributes;\n }\n\n return attributes;\n}\n", "import {\n ActionNodeDefinition,\n AnyChildNodeDefinition,\n AnyNodeDefinition,\n BranchNodeDefinition,\n ConditionNodeDefinition,\n FailNodeDefinition,\n FlipNodeDefinition,\n LottoNodeDefinition,\n ParallelNodeDefinition,\n RepeatNodeDefinition,\n RetryNodeDefinition,\n RootNodeDefinition,\n SelectorNodeDefinition,\n SequenceNodeDefinition,\n SucceedNodeDefinition,\n WaitNodeDefinition\n} from \"../BehaviourTreeDefinition\";\nimport {\n isCompositeNode,\n isDecoratorNode,\n isLeafNode,\n isNullOrUndefined,\n isRootNode\n} from \"../BehaviourTreeDefinitionUtilities\";\nimport { parseArgumentTokens } from \"./MDSLNodeArgumentParser\";\nimport { parseAttributeTokens } from \"./MDSLNodeAttributeParser\";\nimport {\n StringLiteralPlaceholders,\n parseTokensFromDefinition,\n popAndCheck,\n substituteStringLiterals\n} from \"./MDSLUtilities\";\n\n/**\n * Convert the MDSL tree definition string into an equivalent JSON definition.\n * @param definition The tree definition string as MDSL.\n * @returns The root node JSON definitions.\n */\nexport function convertMDSLToJSON(definition: string): RootNodeDefinition[] {\n // Swap out any node/attribute argument string literals with a placeholder and get a mapping of placeholders to original values as well as the processed definition.\n const { placeholders, processedDefinition } = substituteStringLiterals(definition);\n\n // Parse our definition definition string into an array of raw tokens.\n const tokens = parseTokensFromDefinition(processedDefinition);\n\n return convertTokensToJSONDefinition(tokens, placeholders);\n}\n\n/**\n * Converts the specified tree definition tokens into a JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The root node JSON definitions.\n */\nfunction convertTokensToJSONDefinition(\n tokens: string[],\n stringLiteralPlaceholders: StringLiteralPlaceholders\n): RootNodeDefinition[] {\n // There must be at least 3 tokens for the tree definition to be valid. 'ROOT', '{' and '}'.\n if (tokens.length < 3) {\n throw new Error(\"invalid token count\");\n }\n\n // We should have a matching number of '{' and '}' tokens. If not, then there are scopes that have not been properly closed.\n if (tokens.filter((token) => token === \"{\").length !== tokens.filter((token) => token === \"}\").length) {\n throw new Error(\"scope character mismatch\");\n }\n\n // Create an array of tree stack arrays where root nodes will always be at the botton and the current composite/decorator node at the top.\n // There should be an element in this array for every root node defined and every element should be an array with a root note as the first element.\n // E.g. A definition with two root nodes defined:\n // [\n // [root, lotto, sequence],\n // [root, selector]\n // ]\n const treeStacks: [Partial, ...Partial[]][] = [];\n\n // Create an array of all root node definitions that we create.\n const rootNodes: Partial[] = [];\n\n // A helper function used to push node definitions onto the tree stack.\n const pushNode = (node: AnyNodeDefinition) => {\n // If the node is a root node then we need to create a new tree stack array with the root node at the root.\n if (isRootNode(node)) {\n // We need to double-check that this root node is not the child of another node.\n // We can do this by checking whether the top tree stack is not empty (contains an existing node)\n if (treeStacks[treeStacks.length - 1]?.length) {\n throw new Error(\"a root node cannot be the child of another node\");\n }\n\n // Add the root node definition to our array of all parsed root node definitions.\n rootNodes.push(node);\n\n // Add the root node definition to the root of a new tree stack.\n treeStacks.push([node]);\n\n return;\n }\n\n // All non-root nodes should be pushed after their root nodes so handle cases\n // where we may not have any tree stacks or our top-most tree stack is empty.\n if (!treeStacks.length || !treeStacks[treeStacks.length - 1].length) {\n throw new Error(\"expected root node at base of definition\");\n }\n\n // Get the current tree stack that we are populating.\n const topTreeStack = treeStacks[treeStacks.length - 1];\n\n // Get the top-most node in the current tree stack, this will be a composite/decorator node\n // for which we will populate its children array if composite or setting its child if a decorator.\n const topTreeStackTopNode = topTreeStack[topTreeStack.length - 1] as AnyNodeDefinition;\n\n // If the top-most node in the current root stack is a composite or decorator\n // node then the current node should be added as a child of the top-most node.\n if (isCompositeNode(topTreeStackTopNode)) {\n topTreeStackTopNode.children = topTreeStackTopNode.children || [];\n topTreeStackTopNode.children.push(node);\n } else if (isDecoratorNode(topTreeStackTopNode)) {\n // If the top node already has a child node set then throw an error as a decorator should only have a single child.\n if (topTreeStackTopNode.child) {\n throw new Error(\"a decorator node must only have a single child node\");\n }\n\n topTreeStackTopNode.child = node;\n }\n\n // If the node we are adding is also a composite or decorator node, then we should push it\n // onto the current tree stack, as subsequent nodes will be added as its child/children.\n if (!isLeafNode(node)) {\n topTreeStack.push(node);\n }\n };\n\n // A helper function used to pop the top-most node definition off of the tree stack and return it.\n const popNode = (): AnyNodeDefinition | null => {\n let poppedNode: AnyNodeDefinition | null = null;\n\n // Get the current tree stack that we are populating.\n const topTreeStack = treeStacks[treeStacks.length - 1];\n\n // Pop the top-most node in the current tree stack if there is one.\n if (topTreeStack.length) {\n poppedNode = topTreeStack.pop() as AnyNodeDefinition;\n }\n\n // We don't want any empty tree stacks in our stack of tree stacks.\n if (!topTreeStack.length) {\n treeStacks.pop();\n }\n\n return poppedNode;\n };\n\n // We should keep processing the raw tokens until we run out of them.\n while (tokens.length) {\n // Grab the next token.\n const token = tokens.shift()!;\n\n // How we create the next node depends on the current raw token value.\n switch (token.toUpperCase()) {\n case \"ROOT\": {\n pushNode(createRootNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"SUCCEED\": {\n pushNode(createSucceedNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"FAIL\": {\n pushNode(createFailNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"FLIP\": {\n pushNode(createFlipNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"REPEAT\": {\n pushNode(createRepeatNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"RETRY\": {\n pushNode(createRetryNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"SEQUENCE\": {\n pushNode(createSequenceNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"SELECTOR\": {\n pushNode(createSelectorNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"PARALLEL\": {\n pushNode(createParallelNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"LOTTO\": {\n pushNode(createLottoNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"ACTION\": {\n pushNode(createActionNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"CONDITION\": {\n pushNode(createConditionNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"WAIT\": {\n pushNode(createWaitNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"BRANCH\": {\n pushNode(createBranchNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"}\": {\n // The '}' character closes the current scope and means that we have to pop a node off of the current stack.\n const poppedNode = popNode();\n\n // Now that we have a node definition we can carry out any validation that may require the node to be fully populated.\n if (poppedNode) {\n validatePoppedNode(poppedNode);\n }\n\n break;\n }\n\n default: {\n throw new Error(`unexpected token: ${token}`);\n }\n }\n }\n\n return rootNodes as RootNodeDefinition[];\n}\n\n/**\n * Creates a root node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The root node JSON definition.\n */\nfunction createRootNode(tokens: string[], stringLiteralPlaceholders: StringLiteralPlaceholders): RootNodeDefinition {\n // Create the root node definition.\n let node = {\n type: \"root\"\n } as Partial;\n\n // Parse any node arguments, we should only have one if any which will be an identifier argument for the root identifier.\n const nodeArguments = parseArgumentTokens(tokens, stringLiteralPlaceholders);\n\n // Check whether any node arguments were defined.\n if (nodeArguments.length) {\n // We should only have one argument, if any, which will be an identifier argument for the root identifier.\n if (nodeArguments.length === 1 && nodeArguments[0].type === \"identifier\") {\n // The root node identifier will be the first and only node argument value.\n node.id = nodeArguments[0].value as string;\n } else {\n throw new Error(\"expected single root name argument\");\n }\n }\n\n // Grab any node attribute definitions and spread them into the node definition.\n node = { ...node, ...parseAttributeTokens(tokens, stringLiteralPlaceholders) };\n\n // This is a decorator node, so we expect an opening '{'.\n popAndCheck(tokens, \"{\");\n\n // Return the root node definition.\n return node as RootNodeDefinition;\n}\n\n/**\n * Creates a succeed node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The succeed node JSON definition.\n */\nfunction createSucceedNode(\n tokens: string[],\n stringLiteralPlaceholders: StringLiteralPlaceholders\n): SucceedNodeDefinition {\n const node = {\n type: \"succeed\",\n ...parseAttributeTokens(tokens, stringLiteralPlaceholders)\n } as SucceedNodeDefinition;\n\n // This is a decorator node, so we expect an opening '{'.\n popAndCheck(tokens, \"{\");\n\n // Return the succeed node definition.\n return node;\n}\n\n/**\n * Creates a fail node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The fail node JSON definition.\n */\nfunction createFailNode(tokens: string[], stringLiteralPlaceholders: StringLiteralPlaceholders): FailNodeDefinition {\n const node = {\n type: \"fail\",\n ...parseAttributeTokens(tokens, stringLiteralPlaceholders)\n } as FailNodeDefinition;\n\n // This is a decorator node, so we expect an opening '{'.\n popAndCheck(tokens, \"{\");\n\n // Return the fail node definition.\n return node;\n}\n\n/**\n * Creates a flip node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The flip node JSON definition.\n */\nfunction createFlipNode(tokens: string[], stringLiteralPlaceholders: StringLiteralPlaceholders): FlipNodeDefinition {\n const node = {\n type: \"flip\",\n ...parseAttributeTokens(tokens, stringLiteralPlaceholders)\n } as FlipNodeDefinition;\n\n // This is a decorator node, so we expect an opening '{'.\n popAndCheck(tokens, \"{\");\n\n // Return the flip node definition.\n return node;\n}\n\n/**\n * Creates a repeat node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The repeat node JSON definition.\n */\nfunction createRepeatNode(\n tokens: string[],\n stringLiteralPlaceholders: StringLiteralPlaceholders\n): RepeatNodeDefinition {\n let node = { type: \"repeat\" } as RepeatNodeDefinition;\n\n // Get the node arguments.\n const nodeArguments = parseArgumentTokens(tokens, stringLiteralPlaceholders);\n\n // The arguments of a repeat node are optional. We may have:\n // - No node arguments, in which case the repeat note will iterate indefinitely.\n // - One node argument which will be the explicit number of iterations to make.\n // - Two node arguments which define the min and max iteration bounds from which a random iteration count will be picked.\n if (nodeArguments.length) {\n // All repeat node arguments MUST be of type number and must be integer.\n nodeArguments\n .filter((arg) => arg.type !== \"number\" || !arg.isInteger)\n .forEach(() => {\n throw new Error(`repeat node iteration counts must be integer values`);\n });\n\n // We should have got one or two iteration counts.\n if (nodeArguments.length === 1) {\n // A static iteration count was defined.\n node.iterations = nodeArguments[0].value as number;\n\n // A repeat node must have a positive number of iterations if defined.\n if (node.iterations < 0) {\n throw new Error(\"a repeat node must have a positive number of iterations if defined\");\n }\n } else if (nodeArguments.length === 2) {\n // A minimum and maximum iteration count was defined.\n node.iterations = [nodeArguments[0].value as number, nodeArguments[1].value as number];\n\n // A repeat node must have a positive min and max iteration count if they are defined.\n if (node.iterations[0] < 0 || node.iterations[1] < 0) {\n throw new Error(\"a repeat node must have a positive minimum and maximum iteration count if defined\");\n }\n\n // A repeat node must not have an minimum iteration count that exceeds the maximum iteration count.\n if (node.iterations[0] > node.iterations[1]) {\n throw new Error(\n \"a repeat node must not have a minimum iteration count that exceeds the maximum iteration count\"\n );\n }\n } else {\n // An incorrect number of iteration counts was defined.\n throw new Error(\"invalid number of repeat node iteration count arguments defined\");\n }\n }\n\n // Grab any node attribute definitions and spread them into the node definition.\n node = { ...node, ...parseAttributeTokens(tokens, stringLiteralPlaceholders) };\n\n // This is a decorator node, so we expect an opening '{'.\n popAndCheck(tokens, \"{\");\n\n // Return the repeat node definition.\n return node;\n}\n\n/**\n * Creates a retry node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The retry node JSON definition.\n */\nfunction createRetryNode(tokens: string[], stringLiteralPlaceholders: StringLiteralPlaceholders): RetryNodeDefinition {\n let node = { type: \"retry\" } as RetryNodeDefinition;\n\n // Get the node arguments.\n const nodeArguments = parseArgumentTokens(tokens, stringLiteralPlaceholders);\n\n // The arguments of a retry node are optional. We may have:\n // - No node arguments, in which case the retry note will attempt indefinitely.\n // - One node argument which will be the explicit number of attempts to make.\n // - Two node arguments which define the min and max attempt bounds from which a random attempt count will be picked.\n if (nodeArguments.length) {\n // All retry node arguments MUST be of type number and must be integer.\n nodeArguments\n .filter((arg) => arg.type !== \"number\" || !arg.isInteger)\n .forEach(() => {\n throw new Error(`retry node attempt counts must be integer values`);\n });\n\n // We should have got one or two attempt counts.\n if (nodeArguments.length === 1) {\n // A static attempt count was defined.\n node.attempts = nodeArguments[0].value as number;\n\n // A retry node must have a positive number of attempts if defined.\n if (node.attempts < 0) {\n throw new Error(\"a retry node must have a positive number of attempts if defined\");\n }\n } else if (nodeArguments.length === 2) {\n // A minimum and maximum attempt count was defined.\n node.attempts = [nodeArguments[0].value as number, nodeArguments[1].value as number];\n\n // A retry node must have a positive min and max attempts count if they are defined.\n if (node.attempts[0] < 0 || node.attempts[1] < 0) {\n throw new Error(\"a retry node must have a positive minimum and maximum attempt count if defined\");\n }\n\n // A retry node must not have a minimum attempt count that exceeds the maximum attempt count.\n if (node.attempts[0] > node.attempts[1]) {\n throw new Error(\n \"a retry node must not have a minimum attempt count that exceeds the maximum attempt count\"\n );\n }\n } else {\n // An incorrect number of attempt counts was defined.\n throw new Error(\"invalid number of retry node attempt count arguments defined\");\n }\n }\n\n // Grab any node attribute definitions and spread them into the node definition.\n node = { ...node, ...parseAttributeTokens(tokens, stringLiteralPlaceholders) };\n\n // This is a decorator node, so we expect an opening '{'.\n popAndCheck(tokens, \"{\");\n\n // Return the retry node definition.\n return node;\n}\n\n/**\n * Creates a sequence node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The sequence node JSON definition.\n */\nfunction createSequenceNode(\n tokens: string[],\n stringLiteralPlaceholders: StringLiteralPlaceholders\n): SequenceNodeDefinition {\n const node = {\n type: \"sequence\",\n ...parseAttributeTokens(tokens, stringLiteralPlaceholders)\n } as SequenceNodeDefinition;\n\n // This is a composite node, so we expect an opening '{'.\n popAndCheck(tokens, \"{\");\n\n // Return the sequence node definition.\n return node;\n}\n\n/**\n * Creates a selector node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The selector node JSON definition.\n */\nfunction createSelectorNode(\n tokens: string[],\n stringLiteralPlaceholders: StringLiteralPlaceholders\n): SelectorNodeDefinition {\n const node = {\n type: \"selector\",\n ...parseAttributeTokens(tokens, stringLiteralPlaceholders)\n } as SelectorNodeDefinition;\n\n // This is a composite node, so we expect an opening '{'.\n popAndCheck(tokens, \"{\");\n\n // Return the selector node definition.\n return node;\n}\n\n/**\n * Creates a parallel node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The parallel node JSON definition.\n */\nfunction createParallelNode(\n tokens: string[],\n stringLiteralPlaceholders: StringLiteralPlaceholders\n): ParallelNodeDefinition {\n const node = {\n type: \"parallel\",\n ...parseAttributeTokens(tokens, stringLiteralPlaceholders)\n } as ParallelNodeDefinition;\n\n // This is a composite node, so we expect an opening '{'.\n popAndCheck(tokens, \"{\");\n\n // Return the parallel node definition.\n return node;\n}\n\n/**\n * Creates a lotto node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The lotto node JSON definition.\n */\nfunction createLottoNode(tokens: string[], stringLiteralPlaceholders: StringLiteralPlaceholders): LottoNodeDefinition {\n // If any node arguments have been defined then they must be our weights.\n const nodeArguments = parseArgumentTokens(tokens, stringLiteralPlaceholders);\n\n // All lotto node arguments MUST be of type number and must be positive integers.\n nodeArguments\n .filter((arg) => arg.type !== \"number\" || !arg.isInteger || arg.value < 0)\n .forEach(() => {\n throw new Error(`lotto node weight arguments must be positive integer values`);\n });\n\n const node = {\n type: \"lotto\",\n ...parseAttributeTokens(tokens, stringLiteralPlaceholders)\n } as LottoNodeDefinition;\n\n // Apply the weights if any were defined.\n if (nodeArguments.length) {\n node.weights = nodeArguments.map(({ value }) => value) as number[];\n }\n\n // This is a composite node, so we expect an opening '{'.\n popAndCheck(tokens, \"{\");\n\n // Return the lotto node definition.\n return node;\n}\n\n/**\n * Creates an action node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The action node JSON definition.\n */\nfunction createActionNode(\n tokens: string[],\n stringLiteralPlaceholders: StringLiteralPlaceholders\n): ActionNodeDefinition {\n // Parse any node arguments, we should have at least one which will be an identifier argument for the action name\n // and agent function to invoke for the action, all other arguments are to be passed as arguments to that function.\n const [actionNameIdentifier, ...agentFunctionArgs] = parseArgumentTokens(tokens, stringLiteralPlaceholders);\n\n // Our first argument MUST be defined and be an identifier as we require an action name argument.\n if (actionNameIdentifier?.type !== \"identifier\") {\n throw new Error(\"expected action name identifier argument\");\n }\n\n // Only the first argument should have been an identifier, all agent function arguments must be string, number, boolean or null.\n agentFunctionArgs\n .filter((arg) => arg.type === \"identifier\")\n .forEach((arg) => {\n throw new Error(\n `invalid action node argument value '${arg.value}', must be string, number, boolean or null`\n );\n });\n\n // Return the action node definition.\n return {\n type: \"action\",\n call: actionNameIdentifier.value,\n args: agentFunctionArgs.map(({ value }) => value),\n ...parseAttributeTokens(tokens, stringLiteralPlaceholders)\n };\n}\n\n/**\n * Creates a condition node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The condition node JSON definition.\n */\nfunction createConditionNode(\n tokens: string[],\n stringLiteralPlaceholders: StringLiteralPlaceholders\n): ConditionNodeDefinition {\n // Parse any node arguments, we should have at least one which will be an identifier argument for the condition name\n // and agent function to invoke for the condition, all other arguments are to be passed as arguments to that function.\n const [conditionNameIdentifier, ...agentFunctionArgs] = parseArgumentTokens(tokens, stringLiteralPlaceholders);\n\n // Our first argument MUST be defined and be an identifier as we require a condition name argument.\n if (conditionNameIdentifier?.type !== \"identifier\") {\n throw new Error(\"expected condition name identifier argument\");\n }\n\n // Only the first argument should have been an identifier, all agent function arguments must be string, number, boolean or null.\n agentFunctionArgs\n .filter((arg) => arg.type === \"identifier\")\n .forEach((arg) => {\n throw new Error(\n `invalid condition node argument value '${arg.value}', must be string, number, boolean or null`\n );\n });\n\n // Return the condition node definition.\n return {\n type: \"condition\",\n call: conditionNameIdentifier.value,\n args: agentFunctionArgs.map(({ value }) => value),\n ...parseAttributeTokens(tokens, stringLiteralPlaceholders)\n };\n}\n\n/**\n * Creates a wait node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The wait node JSON definition.\n */\nfunction createWaitNode(tokens: string[], stringLiteralPlaceholders: StringLiteralPlaceholders): WaitNodeDefinition {\n let node = { type: \"wait\" } as WaitNodeDefinition;\n\n // Get the node arguments.\n const nodeArguments = parseArgumentTokens(tokens, stringLiteralPlaceholders);\n\n // The arguments of a wait node are optional. We may have:\n // - No node arguments, in which case the wait will be indefinite until it is aborted.\n // - One node argument which will be the explicit duration of the wait.\n // - Two node arguments which define the min and max duration bounds from which a random duration will be picked.\n if (nodeArguments.length) {\n // All wait node arguments MUST be of type number and must be integer.\n nodeArguments\n .filter((arg) => arg.type !== \"number\" || !arg.isInteger)\n .forEach(() => {\n throw new Error(`wait node durations must be integer values`);\n });\n\n // We may have:\n // - One node argument which will be the explicit duration of the wait.\n // - Two node arguments which define the min and max duration bounds from which a random duration will be picked.\n // - Too many arguments, which is not valid.\n if (nodeArguments.length === 1) {\n // An explicit duration was defined.\n node.duration = nodeArguments[0].value as number;\n\n // If an explict duration was defined then it must be a positive number.\n if (node.duration < 0) {\n throw new Error(\"a wait node must have a positive duration\");\n }\n } else if (nodeArguments.length === 2) {\n // Min and max duration bounds were defined from which a random duration will be picked.\n node.duration = [nodeArguments[0].value as number, nodeArguments[1].value as number];\n\n // A wait node must have a positive min and max duration.\n if (node.duration[0] < 0 || node.duration[1] < 0) {\n throw new Error(\"a wait node must have a positive minimum and maximum duration\");\n }\n\n // A wait node must not have a minimum duration that exceeds the maximum duration.\n if (node.duration[0] > node.duration[1]) {\n throw new Error(\"a wait node must not have a minimum duration that exceeds the maximum duration\");\n }\n } else if (nodeArguments.length > 2) {\n // An incorrect number of duration arguments were defined.\n throw new Error(\"invalid number of wait node duration arguments defined\");\n }\n }\n\n // Return the wait node definition.\n return { ...node, ...parseAttributeTokens(tokens, stringLiteralPlaceholders) };\n}\n\n/**\n * Creates a branch node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The branch node JSON definition.\n */\nfunction createBranchNode(\n tokens: string[],\n stringLiteralPlaceholders: StringLiteralPlaceholders\n): BranchNodeDefinition {\n // Parse any node arguments, we should have one which will be an identifier argument for the root ref.\n const nodeArguments = parseArgumentTokens(tokens, stringLiteralPlaceholders);\n\n // We should have only a single identifer argument for a branch node, which is the root ref.\n if (nodeArguments.length !== 1 || nodeArguments[0].type !== \"identifier\") {\n throw new Error(\"expected single branch name argument\");\n }\n\n // Return the branch node definition.\n return { type: \"branch\", ref: nodeArguments[0].value };\n}\n\n/**\n * Validate a fully-populated node definition that was popped off of the tree stack.\n * @param definition The popped node to validate.\n */\nfunction validatePoppedNode(definition: AnyNodeDefinition): void {\n // Decorators MUST have a child defined.\n if (isDecoratorNode(definition) && isNullOrUndefined(definition.child)) {\n throw new Error(`a ${definition.type} node must have a single child node defined`);\n }\n\n // Composites MUST have at least one child defined.\n if (isCompositeNode(definition) && !definition.children?.length) {\n throw new Error(`a ${definition.type} node must have at least a single child node defined`);\n }\n\n // We need to make sure that lotto nodes that have weights defined have a number of weights matching the number of child nodes.\n if (definition.type === \"lotto\") {\n // Check whether a 'weights' property has been defined, if it has we expect it to be an array of weights.\n if (typeof definition.weights !== \"undefined\") {\n // Check that the weights property is an array of positive integers with an element for each child node element.\n if (definition.weights.length !== definition.children.length) {\n throw new Error(\n \"expected a number of weight arguments matching the number of child nodes for lotto node\"\n );\n }\n }\n }\n}\n", "import { RootNodeDefinition } from \"./BehaviourTreeDefinition\";\nimport { flattenDefinition, isBranchNode, isInteger } from \"./BehaviourTreeDefinitionUtilities\";\nimport { convertMDSLToJSON } from \"./mdsl/MDSLDefinitionParser\";\n\n/**\n * An object representing the result of validating a tree definition.\n */\nexport type DefinitionValidationResult = {\n /**\n * A flag defining whether validation succeeded.\n */\n succeeded: boolean;\n /**\n * A string containing the error message if validation did not succeed.\n */\n errorMessage?: string;\n /**\n * The definition as json if the validation was successful, or undefined if validation did not succeed.\n */\n json?: RootNodeDefinition[];\n};\n\n/**\n * Validates the specified behaviour tree definition in the form of JSON or MDSL, not taking any globally registered subtrees into consideration.\n * @param definition The behaviour tree definition in the form of JSON or MDSL.\n * @returns An object representing the result of validating the given tree definition.\n */\nexport function validateDefinition(definition: any): DefinitionValidationResult {\n // The definition must be defined.\n if (definition === null || typeof definition === \"undefined\") {\n return createValidationFailureResult(\"definition is null or undefined\");\n }\n\n // We are expecting a definition in one of three different forms:\n // - A string which we will assume is MDSL and we will parse this to JSON before validation.\n // - An array which we will assume is an array of root node definitions with at least one being the primary root node (no 'id' property)\n // - An object which we will assume is the primary root node and should not have an 'id' property.\n if (typeof definition === \"string\") {\n // The definition is a string which we can assume is MDSL, so attempt to validate it.\n return validateMDSLDefinition(definition);\n } else if (typeof definition === \"object\") {\n // The definition will either be an array (of root node definitions) or an object (the single primary root node definition).\n return validateJSONDefinition(definition);\n } else {\n return createValidationFailureResult(`unexpected definition type of '${typeof definition}'`);\n }\n}\n\n/**\n * Validates the specified behaviour tree definition in the form of MDSL.\n * @param definition The behaviour tree definition in the form of MDSL.\n * @returns An object representing the result of validating the given tree definition.\n */\nfunction validateMDSLDefinition(definition: string): DefinitionValidationResult {\n let rootNodeDefinitions;\n\n // The first thing the we need to do is to attempt to convert our MDSL into JSON.\n try {\n // The definition is a string which we can assume is MDSL, so attempt to parse it to a JSON definition in the form of an array of root node definitions.\n rootNodeDefinitions = convertMDSLToJSON(definition);\n } catch (exception) {\n // We failed to parse the JSON from the MDSL, this is likely to be the result of it not being a valid MDSL string.\n return createValidationFailureResult((exception as Error).message);\n }\n\n // Unpack all of the root node definitions into arrays of main ('id' defined) and sub ('id' not defined) root node definitions.\n const mainRootNodeDefinitions = rootNodeDefinitions.filter(({ id }) => typeof id === \"undefined\");\n const subRootNodeDefinitions = rootNodeDefinitions.filter(({ id }) => typeof id === \"string\" && id.length > 0);\n\n // We should ALWAYS have exactly one root node definition without an 'id' property defined, which is out main root node definition.\n if (mainRootNodeDefinitions.length !== 1) {\n return createValidationFailureResult(\n \"expected single unnamed root node at base of definition to act as main root\"\n );\n }\n\n // We should never have duplicate 'id' properties across our sub root node definitions.\n const subRootNodeIdenitifers: string[] = [];\n for (const { id } of subRootNodeDefinitions) {\n // Have we already come across this 'id' property value?\n if (subRootNodeIdenitifers.includes(id!)) {\n return createValidationFailureResult(`multiple root nodes found with duplicate name '${id}'`);\n }\n\n subRootNodeIdenitifers.push(id!);\n }\n\n try {\n // Validate our branch -> subtree links and check for any circular dependencies, we don't care about checking for broken subtree links here.\n validateBranchSubtreeLinks(rootNodeDefinitions, false);\n } catch (exception) {\n return createValidationFailureResult((exception as Error).message);\n }\n\n // Our definition was valid!\n return {\n succeeded: true,\n json: rootNodeDefinitions\n };\n}\n\n/**\n * Validates the specified behaviour tree definition in the form of JSON.\n * @param definition The behaviour tree definition in the form of JSON.\n * @returns An object representing the result of validating the given tree definition.\n */\nexport function validateJSONDefinition(\n definition: RootNodeDefinition | RootNodeDefinition[]\n): DefinitionValidationResult {\n // The definition will either be an array (of root node definitions) or an object (the single primary root node definition).\n const rootNodeDefinitions = Array.isArray(definition) ? definition : [definition];\n\n // Iterate over our array of root nodes and call validateNode for each, passing an initial depth of 0, wrapped in a try catch to handle validation failures.\n try {\n rootNodeDefinitions.forEach((rootNodeDefinition) => validateNode(rootNodeDefinition, 0));\n } catch (error) {\n // Handle cases where we have caught a thrown Error and return a failure result with the error message.\n if (error instanceof Error) {\n return createValidationFailureResult(error.message);\n }\n\n // No idea what happened here!\n return createValidationFailureResult(`unexpected error: ${error}`);\n }\n\n // Unpack all of the root node definitions into arrays of main ('id' defined) and sub ('id' not defined) root node definitions.\n const mainRootNodeDefinitions = rootNodeDefinitions.filter(({ id }) => typeof id === \"undefined\");\n const subRootNodeDefinitions = rootNodeDefinitions.filter(({ id }) => typeof id === \"string\" && id.length > 0);\n\n // We should ALWAYS have exactly one root node definition without an 'id' property defined, which is out main root node definition.\n if (mainRootNodeDefinitions.length !== 1) {\n return createValidationFailureResult(\n \"expected single root node without 'id' property defined to act as main root\"\n );\n }\n\n // We should never have duplicate 'id' properties across our sub root node definitions.\n const subRootNodeIdenitifers: string[] = [];\n for (const { id } of subRootNodeDefinitions) {\n // Have we already come across this 'id' property value?\n if (subRootNodeIdenitifers.includes(id!)) {\n return createValidationFailureResult(\n `multiple root nodes found with duplicate 'id' property value of '${id}'`\n );\n }\n\n subRootNodeIdenitifers.push(id!);\n }\n\n try {\n // Validate our branch -> subtree links and check for any circular dependencies, we don't care about checking for broken subtree links here.\n validateBranchSubtreeLinks(rootNodeDefinitions, false);\n } catch (exception) {\n return createValidationFailureResult((exception as Error).message);\n }\n\n // Our definition was valid!\n return {\n succeeded: true,\n json: rootNodeDefinitions\n };\n}\n\n/**\n * Validates the branch -> subtree links across all provided root node definitions.\n * This will not consider branch nodes that reference any globally registered subtrees unless includesGlobalSubtrees\n * is set to true, in which case we will also verify that there are no broken branch -> subtree links.\n * @param rootNodeDefinitions The array of root node definitions.\n * @param includesGlobalSubtrees A flag defining whether the array includes all global subtree root node definitions.\n */\nexport function validateBranchSubtreeLinks(rootNodeDefinitions: RootNodeDefinition[], includesGlobalSubtrees: boolean) {\n // Create a mapping of root node identifiers to other root nodes that they reference via branch nodes.\n // Below is an example of a mapping that includes a circular dependency (root => a => b => c => a)\n // [{ refs: [\"a\", \"b\"] }, { id: \"a\", refs: [\"b\"] }, { id: \"b\", refs: [\"c\"] }, { id: \"c\", refs: [\"a\"] }]\n const rootNodeMappings: { id: string | undefined; refs: string[] }[] = rootNodeDefinitions.map(\n (rootNodeDefinition) => ({\n id: rootNodeDefinition.id,\n refs: flattenDefinition(rootNodeDefinition)\n .filter(isBranchNode)\n .map(({ ref }) => ref)\n })\n );\n\n // A recursive function to walk through the mappings, keeping track of which root nodes we have visited in the form of a path of root node identifiers.\n const followRefs = (mapping: { id: string | undefined; refs: string[] }, path: (string | undefined)[] = []) => {\n // Have we found a circular dependency?\n if (path.includes(mapping.id)) {\n // We found a circular dependency! Get the bad path of root node identifiers.\n const badPath = [...path, mapping.id];\n\n // Create the formatted path value. [undefined, \"a\", \"b\", \"c\", \"a\"] would be formatted as \"a -> b -> c -> a\".\n const badPathFormatted = badPath.filter((element) => !!element).join(\" => \");\n\n // No need to continue, we found a circular dependency.\n throw new Error(`circular dependency found in branch node references: ${badPathFormatted}`);\n }\n\n for (const ref of mapping.refs) {\n // Find the mapping for the root node with an identifer matching the current ref.\n const subMapping = rootNodeMappings.find(({ id }) => id === ref);\n\n // We may not have a mapping for this ref, which is normal when we aren't considering all globally registered subtrees.\n if (subMapping) {\n followRefs(subMapping, [...path, mapping.id]);\n } else if (includesGlobalSubtrees) {\n // We found a reference to a root node that doesn't exist, which is a problem seeing as the root node definitons includes all globally registered subtrees.\n throw new Error(\n mapping.id\n ? `subtree '${mapping.id}' has branch node that references root node '${ref}' which has not been defined`\n : `primary tree has branch node that references root node '${ref}' which has not been defined`\n );\n }\n }\n };\n\n // Start looking for circular dependencies and broken references from the primary root node definition.\n followRefs(rootNodeMappings.find((mapping) => typeof mapping.id === \"undefined\")!);\n}\n\n/**\n * Validate an object that we expect to be a node definition.\n * @param definition An object that we expect to be a node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateNode(definition: any, depth: number): void {\n // Every node must be valid object and have a non-empty 'type' string property.\n if (typeof definition !== \"object\" || typeof definition.type !== \"string\" || definition.type.length === 0) {\n throw new Error(\n `node definition is not an object or 'type' property is not a non-empty string at depth '${depth}'`\n );\n }\n\n // How we validate this node definition will depend on its type.\n switch (definition.type) {\n case \"action\":\n validateActionNode(definition, depth);\n break;\n\n case \"condition\":\n validateConditionNode(definition, depth);\n break;\n\n case \"wait\":\n validateWaitNode(definition, depth);\n break;\n\n case \"branch\":\n validateBranchNode(definition, depth);\n break;\n\n case \"root\":\n validateRootNode(definition, depth);\n break;\n\n case \"succeed\":\n validateSucceedNode(definition, depth);\n break;\n\n case \"fail\":\n validateFailNode(definition, depth);\n break;\n\n case \"flip\":\n validateFlipNode(definition, depth);\n break;\n\n case \"repeat\":\n validateRepeatNode(definition, depth);\n break;\n\n case \"retry\":\n validateRetryNode(definition, depth);\n break;\n\n case \"sequence\":\n validateSequenceNode(definition, depth);\n break;\n\n case \"selector\":\n validateSelectorNode(definition, depth);\n break;\n\n case \"parallel\":\n validateParallelNode(definition, depth);\n break;\n\n case \"lotto\":\n validateLottoNode(definition, depth);\n break;\n\n default:\n throw new Error(`unexpected node type of '${definition.type}' at depth '${depth}'`);\n }\n}\n\n/**\n * Validate any attributes for a given node definition.\n * @param definition The node definition.\n * @param depth The depth of the node in the behaviour tree definition.\n */\nfunction validateNodeAttributes(definition: any, depth: number): void {\n // Validate each of the attribute types for this node.\n [\"while\", \"until\", \"entry\", \"exit\", \"step\"].forEach((attributeName) => {\n // Attempt to grab the definition for the current attribute from the node definition.\n const attributeDefinition = definition[attributeName];\n\n // All node attributes are optional, so there is nothing to do if the current attribute is not defined.\n if (typeof attributeDefinition === \"undefined\") {\n return;\n }\n\n // The attribute definition must be an object.\n if (typeof attributeDefinition !== \"object\") {\n throw new Error(\n `expected attribute '${attributeName}' to be an object for '${definition.type}' node at depth '${depth}'`\n );\n }\n\n // The 'call' property must be defined for any attribute definition.\n if (typeof attributeDefinition.call !== \"string\" || attributeDefinition.call.length === 0) {\n throw new Error(\n `expected 'call' property for attribute '${attributeName}' to be a non-empty string for '${definition.type}' node at depth '${depth}'`\n );\n }\n\n // If any node attribute arguments have been defined then they must have been defined in an array.\n if (typeof attributeDefinition.args !== \"undefined\" && !Array.isArray(attributeDefinition.args)) {\n throw new Error(\n `expected 'args' property for attribute '${attributeName}' to be an array for '${definition.type}' node at depth '${depth}'`\n );\n }\n });\n}\n\n/**\n * Validate an object that we expect to be a root node definition.\n * @param definition An object that we expect to be a root node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateRootNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"root\") {\n throw new Error(\"expected node type of 'root' for root node\");\n }\n\n // A root node cannot be the child of another node.\n if (depth > 0) {\n throw new Error(\"a root node cannot be the child of another node\");\n }\n\n // Check that, if the root node 'id' property is defined, it is a non-empty string.\n if (typeof definition.id !== \"undefined\" && (typeof definition.id !== \"string\" || definition.id.length === 0)) {\n throw new Error(\"expected non-empty string for 'id' property if defined for root node\");\n }\n\n // A root node is a decorator node, so must have a child node defined.\n if (typeof definition.child === \"undefined\") {\n throw new Error(\"expected property 'child' to be defined for root node\");\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n\n // Validate the child node of this decorator node.\n validateNode(definition.child, depth + 1);\n}\n\n/**\n * Validate an object that we expect to be a succeed node definition.\n * @param definition An object that we expect to be a succeed node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateSucceedNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"succeed\") {\n throw new Error(`expected node type of 'succeed' for succeed node at depth '${depth}'`);\n }\n\n // A succeed node is a decorator node, so must have a child node defined.\n if (typeof definition.child === \"undefined\") {\n throw new Error(`expected property 'child' to be defined for succeed node at depth '${depth}'`);\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n\n // Validate the child node of this decorator node.\n validateNode(definition.child, depth + 1);\n}\n\n/**\n * Validate an object that we expect to be a fail node definition.\n * @param definition An object that we expect to be a fail node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateFailNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"fail\") {\n throw new Error(`expected node type of 'fail' for fail node at depth '${depth}'`);\n }\n\n // A fail node is a decorator node, so must have a child node defined.\n if (typeof definition.child === \"undefined\") {\n throw new Error(`expected property 'child' to be defined for fail node at depth '${depth}'`);\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n\n // Validate the child node of this decorator node.\n validateNode(definition.child, depth + 1);\n}\n\n/**\n * Validate an object that we expect to be a flip node definition.\n * @param definition An object that we expect to be a flip node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateFlipNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"flip\") {\n throw new Error(`expected node type of 'flip' for flip node at depth '${depth}'`);\n }\n\n // A flip node is a decorator node, so must have a child node defined.\n if (typeof definition.child === \"undefined\") {\n throw new Error(`expected property 'child' to be defined for flip node at depth '${depth}'`);\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n\n // Validate the child node of this decorator node.\n validateNode(definition.child, depth + 1);\n}\n\n/**\n * Validate an object that we expect to be a repeat node definition.\n * @param definition An object that we expect to be a repeat node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateRepeatNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"repeat\") {\n throw new Error(`expected node type of 'repeat' for repeat node at depth '${depth}'`);\n }\n\n // A repeat node is a decorator node, so must have a child node defined.\n if (typeof definition.child === \"undefined\") {\n throw new Error(`expected property 'child' to be defined for repeat node at depth '${depth}'`);\n }\n\n // Check whether an 'iterations' property has been defined, it may not have been if this node is to repeat indefinitely.\n if (typeof definition.iterations !== \"undefined\") {\n if (Array.isArray(definition.iterations)) {\n // Check whether any elements of the array are not integer values.\n const containsNonInteger = !!definition.iterations.filter((value: unknown) => !isInteger(value)).length;\n\n // If the 'iterations' property is an array then it MUST contain two integer values.\n if (definition.iterations.length !== 2 || containsNonInteger) {\n throw new Error(\n `expected array containing two integer values for 'iterations' property if defined for repeat node at depth '${depth}'`\n );\n }\n\n // A repeat node must have a positive min and max iterations count if they are defined.\n if (definition.iterations[0] < 0 || definition.iterations[1] < 0) {\n throw new Error(\n `expected positive minimum and maximum iterations count for 'iterations' property if defined for repeat node at depth '${depth}'`\n );\n }\n\n // A repeat node must not have a minimum iterations count that exceeds the maximum iterations count.\n if (definition.iterations[0] > definition.iterations[1]) {\n throw new Error(\n `expected minimum iterations count that does not exceed the maximum iterations count for 'iterations' property if defined for repeat node at depth '${depth}'`\n );\n }\n } else if (isInteger(definition.iterations)) {\n // A repeat node must have a positive number of iterations if defined.\n if (definition.iterations < 0) {\n throw new Error(\n `expected positive iterations count for 'iterations' property if defined for repeat node at depth '${depth}'`\n );\n }\n } else {\n throw new Error(\n `expected integer value or array containing two integer values for 'iterations' property if defined for repeat node at depth '${depth}'`\n );\n }\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n\n // Validate the child node of this decorator node.\n validateNode(definition.child, depth + 1);\n}\n\n/**\n * Validate an object that we expect to be a retry node definition.\n * @param definition An object that we expect to be a retry node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateRetryNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"retry\") {\n throw new Error(`expected node type of 'retry' for retry node at depth '${depth}'`);\n }\n\n // A retry node is a decorator node, so must have a child node defined.\n if (typeof definition.child === \"undefined\") {\n throw new Error(`expected property 'child' to be defined for retry node at depth '${depth}'`);\n }\n\n // Check whether an 'attempts' property has been defined, it may not have been if this node is to retry indefinitely.\n if (typeof definition.attempts !== \"undefined\") {\n if (Array.isArray(definition.attempts)) {\n // Check whether any elements of the array are not integer values.\n const containsNonInteger = !!definition.attempts.filter((value: unknown) => !isInteger(value)).length;\n\n // If the 'attempts' property is an array then it MUST contain two integer values.\n if (definition.attempts.length !== 2 || containsNonInteger) {\n throw new Error(\n `expected array containing two integer values for 'attempts' property if defined for retry node at depth '${depth}'`\n );\n }\n\n // A retry node must have a positive min and max attempts count if they are defined.\n if (definition.attempts[0] < 0 || definition.attempts[1] < 0) {\n throw new Error(\n `expected positive minimum and maximum attempts count for 'attempts' property if defined for retry node at depth '${depth}'`\n );\n }\n\n // A retry node must not have a minimum attempts count that exceeds the maximum attempts count.\n if (definition.attempts[0] > definition.attempts[1]) {\n throw new Error(\n `expected minimum attempts count that does not exceed the maximum attempts count for 'attempts' property if defined for retry node at depth '${depth}'`\n );\n }\n } else if (isInteger(definition.attempts)) {\n // A retry node must have a positive number of attempts if defined.\n if (definition.attempts < 0) {\n throw new Error(\n `expected positive attempts count for 'attempts' property if defined for retry node at depth '${depth}'`\n );\n }\n } else {\n throw new Error(\n `expected integer value or array containing two integer values for 'attempts' property if defined for retry node at depth '${depth}'`\n );\n }\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n\n // Validate the child node of this decorator node.\n validateNode(definition.child, depth + 1);\n}\n\n/**\n * Validate an object that we expect to be a branch node definition.\n * @param definition An object that we expect to be a branch node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateBranchNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"branch\") {\n throw new Error(`expected node type of 'branch' for branch node at depth '${depth}'`);\n }\n\n // Check that the branch node 'ref' property is defined and is a non-empty string.\n if (typeof definition.ref !== \"string\" || definition.ref.length === 0) {\n throw new Error(`expected non-empty string for 'ref' property for branch node at depth '${depth}'`);\n }\n\n // It is invalid to define guard attributes for a branch node as they should be defined on the referenced root node.\n [\"while\", \"until\"].forEach((attributeName) => {\n if (typeof definition[attributeName] !== \"undefined\") {\n throw new Error(\n `guards should not be defined for branch nodes but guard '${attributeName}' was defined for branch node at depth '${depth}'`\n );\n }\n });\n\n // It is invalid to define callback attributes for a branch node as they should be defined on the referenced root node.\n [\"entry\", \"exit\", \"step\"].forEach((attributeName) => {\n if (typeof definition[attributeName] !== \"undefined\") {\n throw new Error(\n `callbacks should not be defined for branch nodes but callback '${attributeName}' was defined for branch node at depth '${depth}'`\n );\n }\n });\n}\n\n/**\n * Validate an object that we expect to be a action node definition.\n * @param definition An object that we expect to be a action node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateActionNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"action\") {\n throw new Error(`expected node type of 'action' for action node at depth '${depth}'`);\n }\n\n // The 'call' property must be defined for a action node definition.\n if (typeof definition.call !== \"string\" || definition.call.length === 0) {\n throw new Error(`expected non-empty string for 'call' property of action node at depth '${depth}'`);\n }\n\n // If any action function arguments have been defined then they must have been defined in an array.\n if (typeof definition.args !== \"undefined\" && !Array.isArray(definition.args)) {\n throw new Error(`expected array for 'args' property if defined for action node at depth '${depth}'`);\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n}\n\n/**\n * Validate an object that we expect to be a condition node definition.\n * @param definition An object that we expect to be a condition node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateConditionNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"condition\") {\n throw new Error(`expected node type of 'condition' for condition node at depth '${depth}'`);\n }\n\n // The 'call' property must be defined for a condition node definition.\n if (typeof definition.call !== \"string\" || definition.call.length === 0) {\n throw new Error(`expected non-empty string for 'call' property of condition node at depth '${depth}'`);\n }\n\n // If any condition function arguments have been defined then they must have been defined in an array.\n if (typeof definition.args !== \"undefined\" && !Array.isArray(definition.args)) {\n throw new Error(`expected array for 'args' property if defined for condition node at depth '${depth}'`);\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n}\n\n/**\n * Validate an object that we expect to be a wait node definition.\n * @param definition An object that we expect to be a wait node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateWaitNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"wait\") {\n throw new Error(`expected node type of 'wait' for wait node at depth '${depth}'`);\n }\n\n // Check whether a 'duration' property has been defined, it may not have been if this node is to wait indefinitely.\n if (typeof definition.duration !== \"undefined\") {\n if (Array.isArray(definition.duration)) {\n // Check whether any elements of the array are not integer values.\n const containsNonInteger = !!definition.duration.filter((value: unknown) => !isInteger(value)).length;\n\n // If the 'duration' property is an array then it MUST contain two integer values.\n if (definition.duration.length !== 2 || containsNonInteger) {\n throw new Error(\n `expected array containing two integer values for 'duration' property if defined for wait node at depth '${depth}'`\n );\n }\n\n // A wait node must have a positive min and max duration value if they are defined.\n if (definition.duration[0] < 0 || definition.duration[1] < 0) {\n throw new Error(\n `expected positive minimum and maximum duration for 'duration' property if defined for wait node at depth '${depth}'`\n );\n }\n\n // A wait node must not have a minimum duration value that exceeds the maximum duration value.\n if (definition.duration[0] > definition.duration[1]) {\n throw new Error(\n `expected minimum duration value that does not exceed the maximum duration value for 'duration' property if defined for wait node at depth '${depth}'`\n );\n }\n } else if (isInteger(definition.duration)) {\n // A wait node must have a positive duration value if defined.\n if (definition.duration < 0) {\n throw new Error(\n `expected positive duration value for 'duration' property if defined for wait node at depth '${depth}'`\n );\n }\n } else {\n throw new Error(\n `expected integer value or array containing two integer values for 'duration' property if defined for wait node at depth '${depth}'`\n );\n }\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n}\n\n/**\n * Validate an object that we expect to be a sequence node definition.\n * @param definition An object that we expect to be a sequence node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateSequenceNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"sequence\") {\n throw new Error(`expected node type of 'sequence' for sequence node at depth '${depth}'`);\n }\n\n // A sequence node is a composite node, so must have a children nodes array defined.\n if (!Array.isArray(definition.children) || definition.children.length === 0) {\n throw new Error(`expected non-empty 'children' array to be defined for sequence node at depth '${depth}'`);\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n\n // Validate the child nodes of this composite node.\n definition.children.forEach((child: any) => validateNode(child, depth + 1));\n}\n\n/**\n * Validate an object that we expect to be a selector node definition.\n * @param definition An object that we expect to be a selector node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateSelectorNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"selector\") {\n throw new Error(`expected node type of 'selector' for selector node at depth '${depth}'`);\n }\n\n // A selector node is a composite node, so must have a children nodes array defined.\n if (!Array.isArray(definition.children) || definition.children.length === 0) {\n throw new Error(`expected non-empty 'children' array to be defined for selector node at depth '${depth}'`);\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n\n // Validate the child nodes of this composite node.\n definition.children.forEach((child: any) => validateNode(child, depth + 1));\n}\n\n/**\n * Validate an object that we expect to be a parallel node definition.\n * @param definition An object that we expect to be a parallel node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateParallelNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"parallel\") {\n throw new Error(`expected node type of 'parallel' for parallel node at depth '${depth}'`);\n }\n\n // A parallel node is a composite node, so must have a children nodes array defined.\n if (!Array.isArray(definition.children) || definition.children.length === 0) {\n throw new Error(`expected non-empty 'children' array to be defined for parallel node at depth '${depth}'`);\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n\n // Validate the child nodes of this composite node.\n definition.children.forEach((child: any) => validateNode(child, depth + 1));\n}\n\n/**\n * Validate an object that we expect to be a lotto node definition.\n * @param definition An object that we expect to be a lotto node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateLottoNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"lotto\") {\n throw new Error(`expected node type of 'lotto' for lotto node at depth '${depth}'`);\n }\n\n // A lotto node is a composite node, so must have a children nodes array defined.\n if (!Array.isArray(definition.children) || definition.children.length === 0) {\n throw new Error(`expected non-empty 'children' array to be defined for lotto node at depth '${depth}'`);\n }\n\n // Check whether a 'weights' property has been defined, if it has we expect it to be an array of weights.\n if (typeof definition.weights !== \"undefined\") {\n // Check that the weights property is an array of positive integers with an element for each child node element.\n if (\n !Array.isArray(definition.weights) ||\n definition.weights.length !== definition.children.length ||\n definition.weights.filter((value: unknown) => !isInteger(value)).length ||\n definition.weights.filter((value: number) => value < 0).length\n ) {\n throw new Error(\n `expected an array of positive integer weight values with a length matching the number of child nodes for 'weights' property if defined for lotto node at depth '${depth}'`\n );\n }\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n\n // Validate the child nodes of this composite node.\n definition.children.forEach((child: any) => validateNode(child, depth + 1));\n}\n\n/**\n * A helper function to create a failure validation result with the given error message.\n * @param errorMessage The validation failure error message.\n * @returns A failure validation result with the given error message.\n */\nfunction createValidationFailureResult(errorMessage: string): DefinitionValidationResult {\n return { succeeded: false, errorMessage };\n}\n", "import { ActionResult, Agent, GlobalFunction } from \"./Agent\";\nimport { RootNodeDefinition } from \"./BehaviourTreeDefinition\";\n\nexport type InvokerFunction = (args: any[]) => ActionResult | boolean;\n\n/**\n * A singleton used to store and lookup registered functions and subtrees.\n */\nexport default class Lookup {\n /**\n * The object holding any registered functions keyed on function name.\n */\n private static registeredFunctions: { [key: string]: GlobalFunction } = {};\n /**\n * The object holding any registered subtree root node definitions keyed on tree name.\n */\n private static registeredSubtrees: { [key: string]: RootNodeDefinition } = {};\n\n /**\n * Gets the function with the specified name.\n * @param name The name of the function.\n * @returns The function with the specified name.\n */\n public static getFunc(name: string): GlobalFunction {\n return this.registeredFunctions[name];\n }\n\n /**\n * Sets the function with the specified name for later lookup.\n * @param name The name of the function.\n * @param func The function.\n */\n public static setFunc(name: string, func: GlobalFunction): void {\n this.registeredFunctions[name] = func;\n }\n\n /**\n * Gets the function invoker for the specified agent and function name.\n * If a function with the specified name exists on the agent object then it will\n * be returned, otherwise we will then check the registered functions for a match.\n * @param agent The agent instance that this behaviour tree is modelling behaviour for.\n * @param name The function name.\n * @returns The function invoker for the specified agent and function name.\n */\n static getFuncInvoker(agent: Agent, name: string): InvokerFunction | null {\n // Check whether the agent contains the specified function.\n const agentFunction = agent[name];\n if (agentFunction && typeof agentFunction === \"function\") {\n return (args: any[]) => agentFunction.apply(agent, args);\n }\n\n // The agent does not contain the specified function but it may have been registered at some point.\n if (this.registeredFunctions[name] && typeof this.registeredFunctions[name] === \"function\") {\n const registeredFunction = this.registeredFunctions[name];\n return (args: any[]) => registeredFunction(agent, ...args);\n }\n\n // We have no function to invoke.\n return null;\n }\n\n /**\n * Gets all registered subtree root node definitions.\n */\n static getSubtrees(): { [key: string]: RootNodeDefinition } {\n return this.registeredSubtrees;\n }\n\n /**\n * Sets the subtree with the specified name for later lookup.\n * @param name The name of the subtree.\n * @param subtree The subtree.\n */\n static setSubtree(name: string, subtree: RootNodeDefinition) {\n this.registeredSubtrees[name] = subtree;\n }\n\n /**\n * Removes the registered function or subtree with the specified name.\n * @param name The name of the registered function or subtree.\n */\n static remove(name: string) {\n delete this.registeredFunctions[name];\n delete this.registeredSubtrees[name];\n }\n\n /**\n * Remove all registered functions and subtrees.\n */\n static empty() {\n this.registeredFunctions = {};\n this.registeredSubtrees = {};\n }\n}\n", "import Node from \"../../nodes/Node\";\n\n/**\n * An exception thrown when evaluating node guard path conditions and a conditions fails.\n */\nexport default class GuardUnsatisifedException extends Error {\n /**\n * @param source The node at which a guard condition failed.\n */\n constructor(private source: Node) {\n super(\"A guard path condition has failed\");\n }\n\n /**\n * Gets whether the specified node is the node at which a guard condition failed.\n * @param node The node to check against the source node.\n * @returns Whether the specified node is the node at which a guard condition failed.\n */\n isSourceNode = (node: Node) => node === this.source;\n}\n", "import { Agent } from \"../../Agent\";\nimport Guard from \"./Guard\";\nimport Node from \"../../nodes/Node\";\nimport GuardUnsatisifedException from \"./GuardUnsatisifedException\";\n\nexport type GuardPathPart = {\n node: Node;\n guards: Guard[];\n};\n\n/**\n * Represents a path of node guards along a root-to-leaf tree path.\n */\nexport default class GuardPath {\n /**\n * @param nodes An array of objects defining a node instance -> guard link, ordered by node depth.\n */\n constructor(private nodes: GuardPathPart[]) {}\n\n /**\n * Evaluate guard conditions for all guards in the tree path, moving outwards from the root.\n * @param agent The agent, required for guard evaluation.\n * @returns An evaluation results object.\n */\n evaluate = (agent: Agent) => {\n // We need to evaluate guard conditions for nodes up the tree, moving outwards from the root.\n for (const details of this.nodes) {\n // There can be multiple guards per node.\n for (const guard of details.guards) {\n // Check whether the guard condition passes, and throw an exception if not.\n if (!guard.isSatisfied(agent)) {\n throw new GuardUnsatisifedException(details.node);\n }\n }\n }\n };\n}\n", "import { BehaviourTreeOptions } from \"../BehaviourTreeOptions\";\nimport State, { AnyState } from \"../State\";\nimport { Agent } from \"../Agent\";\nimport Leaf from \"./leaf/Leaf\";\nimport Attribute from \"../attributes/Attribute\";\nimport Entry from \"../attributes/callbacks/Entry\";\nimport Exit from \"../attributes/callbacks/Exit\";\nimport Step from \"../attributes/callbacks/Step\";\nimport Guard from \"../attributes/guards/Guard\";\nimport GuardPath from \"../attributes/guards/GuardPath\";\nimport GuardUnsatisifedException from \"../attributes/guards/GuardUnsatisifedException\";\n\n/**\n * A base node.\n */\nexport default abstract class Node {\n /**\n * The node uid.\n */\n private readonly uid: string = createNodeUid();\n /**\n * The node state.\n */\n private state: AnyState = State.READY;\n /**\n * The guard path to evaluate as part of a node update.\n */\n private guardPath: GuardPath | undefined;\n\n /**\n * @param type The node type.\n * @param attributes The node attributes.\n * @param args The node argument definitions.\n */\n constructor(private type: string, private attributes: Attribute[], private args: any[]) {}\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected abstract onUpdate(agent: Agent, options: BehaviourTreeOptions): void;\n\n /**\n * Gets the name of the node.\n */\n public abstract getName(): string;\n\n /**\n * Gets whether this node is a leaf node.\n */\n public abstract isLeafNode: () => this is Leaf;\n\n /**\n * Gets/Sets the state of the node.\n */\n getState = (): AnyState => this.state;\n setState = (value: AnyState): void => {\n this.state = value;\n };\n\n /**\n * Gets the unique id of the node.\n */\n getUid = () => this.uid;\n\n /**\n * Gets the type of the node.\n */\n getType = () => this.type;\n\n /**\n * Gets the node attributes.\n */\n getAttributes = () => this.attributes;\n\n /**\n * Gets the node arguments.\n */\n getArguments = () => this.args;\n\n /**\n * Gets the node attribute with the specified type, or null if it does not exist.\n */\n getAttribute(type: \"entry\" | \"ENTRY\"): Entry;\n getAttribute(type: \"exit\" | \"EXIT\"): Exit;\n getAttribute(type: \"step\" | \"STEP\"): Step;\n getAttribute(type: string): Attribute {\n return (\n this.getAttributes().filter((decorator) => decorator.type.toUpperCase() === type.toUpperCase())[0] || null\n );\n }\n\n /**\n * Gets the node attributes.\n */\n getGuardAttributes = (): Guard[] => this.getAttributes().filter((decorator) => decorator.isGuard()) as Guard[];\n\n /**\n * Sets the guard path to evaluate as part of a node update.\n */\n setGuardPath = (value: GuardPath) => (this.guardPath = value);\n\n /**\n * Gets whether a guard path is assigned to this node.\n */\n hasGuardPath = () => !!this.guardPath;\n\n /**\n * Gets whether this node is in the specified state.\n * @param value The value to compare to the node state.\n */\n public is(value: AnyState): boolean {\n return this.state === value;\n }\n\n /**\n * Reset the state of the node.\n */\n public reset(): void {\n this.setState(State.READY);\n }\n\n /**\n * Abort the running of this node.\n * @param agent The agent.\n */\n public abort(agent: Agent): void {\n // There is nothing to do if this node is not in the running state.\n if (!this.is(State.RUNNING)) {\n return;\n }\n\n // Reset the state of this node.\n this.reset();\n\n this.getAttribute(\"exit\")?.callAgentFunction(agent, false, true);\n }\n\n /**\n * Update the node.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n * @returns The result of the update.\n */\n public update(agent: Agent, options: BehaviourTreeOptions): void {\n // If this node is already in a 'SUCCEEDED' or 'FAILED' state then there is nothing to do.\n if (this.is(State.SUCCEEDED) || this.is(State.FAILED)) {\n return;\n }\n\n try {\n // Evaluate all of the guard path conditions for the current tree path.\n this.guardPath!.evaluate(agent);\n\n // If this node is in the READY state then call the ENTRY for this node if it exists.\n if (this.is(State.READY)) {\n this.getAttribute(\"entry\")?.callAgentFunction(agent);\n }\n\n this.getAttribute(\"step\")?.callAgentFunction(agent);\n\n // Do the actual update.\n this.onUpdate(agent, options);\n\n // If this node is now in a 'SUCCEEDED' or 'FAILED' state then call the EXIT for this node if it exists.\n if (this.is(State.SUCCEEDED) || this.is(State.FAILED)) {\n this.getAttribute(\"exit\")?.callAgentFunction(agent, this.is(State.SUCCEEDED), false);\n }\n } catch (error) {\n // If the error is a GuardUnsatisfiedException then we need to determine if this node is the source.\n if (error instanceof GuardUnsatisifedException && error.isSourceNode(this)) {\n // Abort the current node.\n this.abort(agent);\n\n // Any node that is the source of an abort will be a failed node.\n this.setState(State.FAILED);\n } else {\n throw error;\n }\n }\n }\n}\n\n/**\n * Create a randomly generated node uid.\n * @returns A randomly generated node uid.\n */\nfunction createNodeUid(): string {\n var S4 = function () {\n return (((1 + Math.random()) * 0x10000) | 0).toString(16).substring(1);\n };\n return S4() + S4() + \"-\" + S4() + \"-\" + S4() + \"-\" + S4() + \"-\" + S4() + S4() + S4();\n}\n", "import Node from \"../Node\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\n\n/**\n * A composite node that wraps child nodes.\n */\nexport default abstract class Composite extends Node {\n /**\n * @param type The node type.\n * @param attributes The node attributes.\n * @param children The child nodes.\n */\n constructor(type: string, attributes: Attribute[], protected children: Node[]) {\n super(type, attributes, []);\n }\n\n /**\n * Gets whether this node is a leaf node.\n */\n isLeafNode = () => false;\n\n /**\n * Gets the children of this node.\n */\n getChildren = () => this.children;\n\n /**\n * Reset the state of the node.\n */\n reset = () => {\n // Reset the state of this node.\n this.setState(State.READY);\n\n // Reset the state of any child nodes.\n this.getChildren().forEach((child) => child.reset());\n };\n\n /**\n * Abort the running of this node.\n * @param agent The agent.\n */\n abort = (agent: Agent) => {\n // There is nothing to do if this node is not in the running state.\n if (!this.is(State.RUNNING)) {\n return;\n }\n\n // Abort any child nodes.\n this.getChildren().forEach((child) => child.abort(agent));\n\n // Reset the state of this node.\n this.reset();\n\n this.getAttribute(\"exit\")?.callAgentFunction(agent, false, true);\n };\n}\n", "import Composite from \"./Composite\";\nimport State from \"../../State\";\nimport Node from \"../Node\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A PARALLEL node.\n * The child nodes are executed concurrently until one fails or all succeed.\n */\nexport default class Parallel extends Composite {\n /**\n * @param attributes The node attributes.\n * @param children The child nodes.\n */\n constructor(attributes: Attribute[], children: Node[]) {\n super(\"parallel\", attributes, children);\n }\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // Keep a count of the number of succeeded child nodes.\n let succeededCount = 0;\n\n let hasChildFailed = false;\n\n // Iterate over all of the children of this node.\n for (const child of this.children) {\n // If the child has never been updated or is running then we will need to update it now.\n if (child.getState() === State.READY || child.getState() === State.RUNNING) {\n // Update the child of this node.\n child.update(agent, options);\n }\n\n // If the current child has a state of 'SUCCEEDED' then we should move on to the next child.\n if (child.getState() === State.SUCCEEDED) {\n // The child node has succeeded, keep track of this to determine if all children have.\n succeededCount++;\n\n // The child node succeeded, but we have not finished checking every child node yet.\n continue;\n }\n\n // If the current child has a state of 'FAILED' then this node is also a 'FAILED' node.\n if (child.getState() === State.FAILED) {\n hasChildFailed = true;\n\n // There is no need to check the rest of the children.\n break;\n }\n\n // The node should be in the 'RUNNING' state.\n if (child.getState() !== State.RUNNING) {\n // The child node was not in an expected state.\n throw new Error(\"child node was not in an expected state.\");\n }\n }\n\n if (hasChildFailed) {\n // This node is a 'FAILED' node.\n this.setState(State.FAILED);\n\n // Abort every running child.\n for (const child of this.children) {\n if (child.getState() === State.RUNNING) {\n child.abort(agent);\n }\n }\n } else {\n // If all children have succeeded then this node has also succeeded, otherwise it is still running.\n this.setState(succeededCount === this.children.length ? State.SUCCEEDED : State.RUNNING);\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => \"PARALLEL\";\n}\n", "import Composite from \"./Composite\";\nimport Node from \"../Node\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A SELECTOR node.\n * The child nodes are executed in sequence until one succeeds or all fail.\n */\nexport default class Selector extends Composite {\n /**\n * @param attributes The node attributes.\n * @param children The child nodes.\n */\n constructor(attributes: Attribute[], protected children: Node[]) {\n super(\"selector\", attributes, children);\n }\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // Iterate over all of the children of this node.\n for (const child of this.children) {\n // If the child has never been updated or is running then we will need to update it now.\n if (child.getState() === State.READY || child.getState() === State.RUNNING) {\n // Update the child of this node.\n child.update(agent, options);\n }\n\n // If the current child has a state of 'SUCCEEDED' then this node is also a 'SUCCEEDED' node.\n if (child.getState() === State.SUCCEEDED) {\n // This node is a 'SUCCEEDED' node.\n this.setState(State.SUCCEEDED);\n\n // There is no need to check the rest of the selector nodes.\n return;\n }\n\n // If the current child has a state of 'FAILED' then we should move on to the next child.\n if (child.getState() === State.FAILED) {\n // Find out if the current child is the last one in the selector.\n // If it is then this sequence node has also failed.\n if (this.children.indexOf(child) === this.children.length - 1) {\n // This node is a 'FAILED' node.\n this.setState(State.FAILED);\n\n // There is no need to check the rest of the selector as we have completed it.\n return;\n } else {\n // The child node failed, try the next one.\n continue;\n }\n }\n\n // The node should be in the 'RUNNING' state.\n if (child.getState() === State.RUNNING) {\n // This node is a 'RUNNING' node.\n this.setState(State.RUNNING);\n\n // There is no need to check the rest of the selector as the current child is still running.\n return;\n }\n\n // The child node was not in an expected state.\n throw new Error(\"child node was not in an expected state.\");\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => \"SELECTOR\";\n}\n", "import Composite from \"./Composite\";\nimport Node from \"../Node\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A SEQUENCE node.\n * The child nodes are executed in sequence until one fails or all succeed.\n */\nexport default class Sequence extends Composite {\n /**\n * @param attributes The node attributes.\n * @param children The child nodes.\n */\n constructor(attributes: Attribute[], protected children: Node[]) {\n super(\"sequence\", attributes, children);\n }\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // Iterate over all of the children of this node.\n for (const child of this.children) {\n // If the child has never been updated or is running then we will need to update it now.\n if (child.getState() === State.READY || child.getState() === State.RUNNING) {\n // Update the child of this node.\n child.update(agent, options);\n }\n\n // If the current child has a state of 'SUCCEEDED' then we should move on to the next child.\n if (child.getState() === State.SUCCEEDED) {\n // Find out if the current child is the last one in the sequence.\n // If it is then this sequence node has also succeeded.\n if (this.children.indexOf(child) === this.children.length - 1) {\n // This node is a 'SUCCEEDED' node.\n this.setState(State.SUCCEEDED);\n\n // There is no need to check the rest of the sequence as we have completed it.\n return;\n } else {\n // The child node succeeded, but we have not finished the sequence yet.\n continue;\n }\n }\n\n // If the current child has a state of 'FAILED' then this node is also a 'FAILED' node.\n if (child.getState() === State.FAILED) {\n // This node is a 'FAILED' node.\n this.setState(State.FAILED);\n\n // There is no need to check the rest of the sequence.\n return;\n }\n\n // The node should be in the 'RUNNING' state.\n if (child.getState() === State.RUNNING) {\n // This node is a 'RUNNING' node.\n this.setState(State.RUNNING);\n\n // There is no need to check the rest of the sequence as the current child is still running.\n return;\n }\n\n // The child node was not in an expected state.\n throw new Error(\"child node was not in an expected state.\");\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => \"SEQUENCE\";\n}\n", "import createLotto from \"lotto-draw\";\n\nimport Node from \"../Node\";\nimport Composite from \"./Composite\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A LOTTO node.\n * A winning child is picked on the initial update of this node, based on ticket weighting.\n * The state of this node will match the state of the winning child.\n */\nexport default class Lotto extends Composite {\n /**\n * @param attributes The node attributes.\n * @param weights The child node weights.\n * @param children The child nodes.\n */\n constructor(attributes: Attribute[], private weights: number[] | undefined, children: Node[]) {\n super(\"lotto\", attributes, children);\n }\n\n /**\n * The child node selected to be the active one.\n */\n private selectedChild: Node | undefined;\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // If this node is in the READY state then we need to pick a winning child node.\n if (this.is(State.READY)) {\n // Create a lotto draw with which to randomly pick a child node to become the active one.\n const lottoDraw = createLotto({\n // Hook up the optional 'random' behaviour tree function option to the one used by 'lotto-draw'.\n random: options.random,\n // Pass in each child node as a participant in the lotto draw with their respective ticket count.\n participants: this.children.map((child, index) => [child, this.weights?.[index] || 1])\n });\n\n // Randomly pick a child based on ticket weighting, this will become the active child for this composite node.\n this.selectedChild = lottoDraw.draw() || undefined;\n }\n\n // If something went wrong and we don't have an active child then we should throw an error.\n if (!this.selectedChild) {\n throw new Error(\"failed to update lotto node as it has no active child\");\n }\n\n // If the selected child has never been updated or is running then we will need to update it now.\n if (this.selectedChild.getState() === State.READY || this.selectedChild.getState() === State.RUNNING) {\n this.selectedChild.update(agent, options);\n }\n\n // The state of the lotto node is the state of its selected child.\n this.setState(this.selectedChild.getState());\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => (this.weights ? `LOTTO [${this.weights.join(\",\")}]` : \"LOTTO\");\n}\n", "import Node from \"../Node\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\n\n/**\n * A decorator node that wraps a single child node.\n */\nexport default abstract class Decorator extends Node {\n /**\n * @param type The node type.\n * @param attributes The node attributes.\n * @param child The child node.\n */\n constructor(type: string, attributes: Attribute[], protected child: Node) {\n super(type, attributes, []);\n }\n\n /**\n * Gets whether this node is a leaf node.\n */\n isLeafNode = () => false;\n\n /**\n * Gets the children of this node.\n */\n getChildren = () => [this.child];\n\n /**\n * Reset the state of the node.\n */\n reset = () => {\n // Reset the state of this node.\n this.setState(State.READY);\n\n // Reset the state of the child node.\n this.child.reset();\n };\n\n /**\n * Abort the running of this node.\n * @param agent The agent.\n */\n abort = (agent: Agent) => {\n // There is nothing to do if this node is not in the running state.\n if (!this.is(State.RUNNING)) {\n return;\n }\n\n // Abort the child node.\n this.child.abort(agent);\n\n // Reset the state of this node.\n this.reset();\n\n this.getAttribute(\"exit\")?.callAgentFunction(agent, false, true);\n };\n}\n", "import Node from \"../Node\";\nimport Decorator from \"./Decorator\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A Fail node.\n * This node wraps a single child and will always move to the 'FAILED' state when the child moves to a 'SUCCEEDED' or 'FAILED' state.\n */\nexport default class Fail extends Decorator {\n /**\n * @param attributes The node attributes.\n * @param child The child node.\n */\n constructor(attributes: Attribute[], child: Node) {\n super(\"fail\", attributes, child);\n }\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // If the child has never been updated or is running then we will need to update it now.\n if (this.child.getState() === State.READY || this.child.getState() === State.RUNNING) {\n this.child.update(agent, options);\n }\n\n // The state of this node will depend in the state of its child.\n switch (this.child.getState()) {\n case State.RUNNING:\n this.setState(State.RUNNING);\n break;\n\n case State.SUCCEEDED:\n case State.FAILED:\n this.setState(State.FAILED);\n break;\n\n default:\n this.setState(State.READY);\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => \"FAIL\";\n}\n", "import Decorator from \"./Decorator\";\nimport State from \"../../State\";\nimport Node from \"../Node\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A Flip node.\n * This node wraps a single child and will flip the state of the child state.\n */\nexport default class Flip extends Decorator {\n /**\n * @param attributes The node attributes.\n * @param child The child node.\n */\n constructor(attributes: Attribute[], child: Node) {\n super(\"flip\", attributes, child);\n }\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // If the child has never been updated or is running then we will need to update it now.\n if (this.child.getState() === State.READY || this.child.getState() === State.RUNNING) {\n this.child.update(agent, options);\n }\n\n // The state of this node will depend in the state of its child.\n switch (this.child.getState()) {\n case State.RUNNING:\n this.setState(State.RUNNING);\n break;\n\n case State.SUCCEEDED:\n this.setState(State.FAILED);\n break;\n\n case State.FAILED:\n this.setState(State.SUCCEEDED);\n break;\n\n default:\n this.setState(State.READY);\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => \"FLIP\";\n}\n", "import Node from \"../Node\";\nimport Decorator from \"./Decorator\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A REPEAT node.\n * The node has a single child which can have:\n * -- A number of iterations for which to repeat the child node.\n * -- An infinite repeat loop if neither an iteration count or a condition function is defined.\n * The REPEAT node will stop and have a 'FAILED' state if its child is ever in a 'FAILED' state after an update.\n * The REPEAT node will attempt to move on to the next iteration if its child is ever in a 'SUCCEEDED' state.\n */\nexport default class Repeat extends Decorator {\n /**\n * @param attributes The node attributes.\n * @param iterations The number of iterations to repeat the child node.\n * @param iterationsMin The minimum possible number of iterations to repeat the child node.\n * @param iterationsMax The maximum possible number of iterations to repeat the child node.\n * @param child The child node.\n */\n constructor(\n attributes: Attribute[],\n private iterations: number | null,\n private iterationsMin: number | null,\n private iterationsMax: number | null,\n child: Node\n ) {\n super(\"repeat\", attributes, child);\n }\n\n /**\n * The number of target iterations to make.\n */\n private targetIterationCount: number | null = null;\n\n /**\n * The current iteration count.\n */\n private currentIterationCount: number = 0;\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // If this node is in the READY state then we need to reset the child and the target iteration count.\n if (this.is(State.READY)) {\n // Reset the child node.\n this.child.reset();\n\n // Reset the current iteration count.\n this.currentIterationCount = 0;\n\n // Set the target iteration count.\n this.setTargetIterationCount(options);\n }\n\n // Do a check to see if we can iterate. If we can then this node will move into the 'RUNNING' state.\n // If we cannot iterate then we have hit our target iteration count, which means that the node has succeeded.\n if (this.canIterate()) {\n // This node is in the running state and can do its initial iteration.\n this.setState(State.RUNNING);\n\n // We may have already completed an iteration, meaning that the child node will be in the SUCCEEDED state.\n // If this is the case then we will have to reset the child node now.\n if (this.child.getState() === State.SUCCEEDED) {\n this.child.reset();\n }\n\n // Update the child of this node.\n this.child.update(agent, options);\n\n // If the child moved into the FAILED state when we updated it then there is nothing left to do and this node has also failed.\n // If it has moved into the SUCCEEDED state then we have completed the current iteration.\n if (this.child.getState() === State.FAILED) {\n // The child has failed, meaning that this node has failed.\n this.setState(State.FAILED);\n\n return;\n } else if (this.child.getState() === State.SUCCEEDED) {\n // We have completed an iteration.\n this.currentIterationCount += 1;\n }\n } else {\n // This node is in the 'SUCCEEDED' state as we cannot iterate any more.\n this.setState(State.SUCCEEDED);\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => {\n if (this.iterations !== null) {\n return `REPEAT ${this.iterations}x`;\n } else if (this.iterationsMin !== null && this.iterationsMax !== null) {\n return `REPEAT ${this.iterationsMin}x-${this.iterationsMax}x`;\n } else {\n return \"REPEAT\";\n }\n };\n\n /**\n * Reset the state of the node.\n */\n reset = () => {\n // Reset the state of this node.\n this.setState(State.READY);\n\n // Reset the current iteration count.\n this.currentIterationCount = 0;\n\n // Reset the child node.\n this.child.reset();\n };\n\n /**\n * Gets whether an iteration can be made.\n * @returns Whether an iteration can be made.\n */\n private canIterate = () => {\n if (this.targetIterationCount !== null) {\n // We can iterate as long as we have not reached our target iteration count.\n return this.currentIterationCount < this.targetIterationCount;\n }\n\n // If neither an iteration count or a condition function were defined then we can iterate indefinitely.\n return true;\n };\n\n /**\n * Sets the target iteration count.\n * @param options The behaviour tree options object.\n */\n private setTargetIterationCount = (options: BehaviourTreeOptions) => {\n // Are we dealing with an explicit iteration count or will we be randomly picking a iteration count between the min and max iteration count.\n if (this.iterations !== null) {\n this.targetIterationCount = this.iterations;\n } else if (this.iterationsMin !== null && this.iterationsMax !== null) {\n // We will be picking a random iteration count between a min and max iteration count, if the optional 'random'\n // behaviour tree function option is defined then we will be using that, otherwise we will fall back to using Math.random.\n const random = typeof options.random === \"function\" ? options.random : Math.random;\n\n // Pick a random iteration count between a min and max iteration count.\n this.targetIterationCount = Math.floor(\n random() * (this.iterationsMax - this.iterationsMin + 1) + this.iterationsMin\n );\n } else {\n this.targetIterationCount = null;\n }\n };\n}\n", "import Node from \"../Node\";\nimport Decorator from \"./Decorator\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A RETRY node.\n * The node has a single child which can have:\n * -- A number of iterations for which to repeat the child node.\n * -- An infinite repeat loop if neither an iteration count or a condition function is defined.\n * The RETRY node will stop and have a 'SUCCEEDED' state if its child is ever in a 'SUCCEEDED' state after an update.\n * The RETRY node will attempt to move on to the next iteration if its child is ever in a 'FAILED' state.\n */\nexport default class Retry extends Decorator {\n /**\n * @param attributes The node attributes.\n * @param attempts The number of attempts to retry the child node.\n * @param attemptsMin The minimum possible number of attempts to retry the child node.\n * @param attemptsMax The maximum possible number of attempts to retry the child node.\n * @param child The child node.\n */\n constructor(\n attributes: Attribute[],\n private attempts: number | null,\n private attemptsMin: number | null,\n private attemptsMax: number | null,\n child: Node\n ) {\n super(\"retry\", attributes, child);\n }\n\n /**\n * The number of target attempts to make.\n */\n private targetAttemptCount: number | null = null;\n\n /**\n * The current attempt count.\n */\n private currentAttemptCount: number = 0;\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // If this node is in the READY state then we need to reset the child and the target attempt count.\n if (this.is(State.READY)) {\n // Reset the child node.\n this.child.reset();\n\n // Reset the current attempt count.\n this.currentAttemptCount = 0;\n\n // Set the target attempt count.\n this.setTargetAttemptCount(options);\n }\n\n // Do a check to see if we can attempt. If we can then this node will move into the 'RUNNING' state.\n // If we cannot attempt then we have hit our target attempt count, which means that the node has succeeded.\n if (this.canAttempt()) {\n // This node is in the running state and can do its initial attempt.\n this.setState(State.RUNNING);\n\n // We may have already completed an attempt, meaning that the child node will be in the FAILED state.\n // If this is the case then we will have to reset the child node now.\n if (this.child.getState() === State.FAILED) {\n this.child.reset();\n }\n\n // Update the child of this node.\n this.child.update(agent, options);\n\n // If the child moved into the SUCCEEDED state when we updated it then there is nothing left to do and this node has also succeeded.\n // If it has moved into the FAILED state then we have completed the current attempt.\n if (this.child.getState() === State.SUCCEEDED) {\n // The child has succeeded, meaning that this node has succeeded.\n this.setState(State.SUCCEEDED);\n\n return;\n } else if (this.child.getState() === State.FAILED) {\n // We have completed an attempt.\n this.currentAttemptCount += 1;\n }\n } else {\n // This node is in the 'FAILED' state as we cannot iterate any more.\n this.setState(State.FAILED);\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => {\n if (this.attempts !== null) {\n return `RETRY ${this.attempts}x`;\n } else if (this.attemptsMin !== null && this.attemptsMax !== null) {\n return `RETRY ${this.attemptsMin}x-${this.attemptsMax}x`;\n } else {\n return \"RETRY\";\n }\n };\n\n /**\n * Reset the state of the node.\n */\n reset = () => {\n // Reset the state of this node.\n this.setState(State.READY);\n\n // Reset the current attempt count.\n this.currentAttemptCount = 0;\n\n // Reset the child node.\n this.child.reset();\n };\n\n /**\n * Gets whether an attempt can be made.\n * @returns Whether an attempt can be made.\n */\n canAttempt = () => {\n if (this.targetAttemptCount !== null) {\n // We can attempt as long as we have not reached our target attempt count.\n return this.currentAttemptCount < this.targetAttemptCount;\n }\n\n // If neither an attempt count or a condition function were defined then we can attempt indefinitely.\n return true;\n };\n\n /**\n * Sets the target attempt count.\n * @param options The behaviour tree options object.\n */\n setTargetAttemptCount = (options: BehaviourTreeOptions) => {\n // Are we dealing with an explicit attempt count or will we be randomly picking an attempt count between the min and max attempt count.\n if (this.attempts !== null) {\n this.targetAttemptCount = this.attempts;\n } else if (this.attemptsMin !== null && this.attemptsMax !== null) {\n // We will be picking a random attempt count between a min and max attempt count, if the optional 'random'\n // behaviour tree function option is defined then we will be using that, otherwise we will fall back to using Math.random.\n const random = typeof options.random === \"function\" ? options.random : Math.random;\n\n // Pick a random attempt count between a min and max attempt count.\n this.targetAttemptCount = Math.floor(\n random() * (this.attemptsMax - this.attemptsMin + 1) + this.attemptsMin\n );\n } else {\n this.targetAttemptCount = null;\n }\n };\n}\n", "import Node from \"../Node\";\nimport Decorator from \"./Decorator\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A Root node.\n * The root node will have a single child.\n */\nexport default class Root extends Decorator {\n /**\n * @param attributes The node attributes.\n * @param child The child node.\n */\n constructor(attributes: Attribute[], child: Node) {\n super(\"root\", attributes, child);\n }\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // If the child has never been updated or is running then we will need to update it now.\n if (this.child.getState() === State.READY || this.child.getState() === State.RUNNING) {\n // Update the child of this node.\n this.child.update(agent, options);\n }\n\n // The state of the root node is the state of its child.\n this.setState(this.child.getState());\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => \"ROOT\";\n}\n", "import Node from \"../Node\";\nimport Decorator from \"./Decorator\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A Succeed node.\n * This node wraps a single child and will always move to the 'SUCCEEDED' state when the child moves to a 'SUCCEEDED' or 'FAILED' state.\n */\nexport default class Succeed extends Decorator {\n /**\n * @param attributes The node attributes.\n * @param child The child node.\n */\n constructor(attributes: Attribute[], child: Node) {\n super(\"succeed\", attributes, child);\n }\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // If the child has never been updated or is running then we will need to update it now.\n if (this.child.getState() === State.READY || this.child.getState() === State.RUNNING) {\n this.child.update(agent, options);\n }\n\n // The state of this node will depend in the state of its child.\n switch (this.child.getState()) {\n case State.RUNNING:\n this.setState(State.RUNNING);\n break;\n\n case State.SUCCEEDED:\n case State.FAILED:\n this.setState(State.SUCCEEDED);\n break;\n\n default:\n this.setState(State.READY);\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => \"SUCCEED\";\n}\n", "import Node from \"../Node\";\n\n/**\n * A leaf node.\n */\nexport default abstract class Leaf extends Node {\n /**\n * Gets whether this node is a leaf node.\n */\n isLeafNode = () => true;\n}\n", "import { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\nimport State, { CompleteState } from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Leaf from \"./Leaf\";\nimport Lookup from \"../../Lookup\";\nimport Attribute from \"../../attributes/Attribute\";\n\n/**\n * The type representing a resolved/rejected update promise.\n */\ntype UpdatePromiseResult = {\n /**\n * Whether the promise was resolved rather than rejected.\n */\n isResolved: boolean;\n\n /**\n * The promise resolved value or rejection reason.\n */\n value: any;\n};\n\n/**\n * An Action leaf node.\n * This represents an immediate or ongoing state of behaviour.\n */\nexport default class Action extends Leaf {\n /**\n * @param attributes The node attributes.\n * @param actionName The action name.\n * @param actionArguments The array of action argument definitions.\n */\n constructor(attributes: Attribute[], private actionName: string, private actionArguments: any[]) {\n super(\"action\", attributes, actionArguments);\n }\n\n /**\n * Whether there is a pending update promise.\n */\n private isUsingUpdatePromise = false;\n\n /**\n * The finished state result of an update promise.\n */\n private updatePromiseResult: UpdatePromiseResult | null = null;\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // If the result of this action depends on an update promise then there is nothing to do until it settles.\n if (this.isUsingUpdatePromise) {\n // Are we still waiting for our update promise to settle?\n if (!this.updatePromiseResult) {\n return;\n }\n\n const { isResolved, value } = this.updatePromiseResult;\n\n // Our update promise settled, was it resolved or rejected?\n if (isResolved) {\n // Our promise resolved so check to make sure the result is a valid finished state.\n if (value !== State.SUCCEEDED && value !== State.FAILED) {\n throw new Error(\n \"action node promise resolved with an invalid value, expected a State.SUCCEEDED or State.FAILED value to be returned\"\n );\n }\n\n // Set the state of this node to match the state returned by the promise.\n this.setState(value);\n\n return;\n } else {\n // The promise was rejected, which isn't great.\n throw new Error(`action function '${this.actionName}' promise rejected with '${value}'`);\n }\n }\n\n // Attempt to get the invoker for the action function.\n const actionFuncInvoker = Lookup.getFuncInvoker(agent, this.actionName);\n\n // The action function should be defined.\n if (actionFuncInvoker === null) {\n throw new Error(\n `cannot update action node as the action '${this.actionName}' function is not defined on the agent and has not been registered`\n );\n }\n\n let actionFunctionResult;\n\n try {\n // Call the action function, the result of which may be:\n // - The finished state of this action node.\n // - A promise to return a finished node state.\n // - Undefined if the node should remain in the running state.\n actionFunctionResult = actionFuncInvoker(this.actionArguments) as CompleteState | Promise;\n } catch (error) {\n // An uncaught error was thrown.\n if (error instanceof Error) {\n throw new Error(`action function '${this.actionName}' threw: ${error.stack}`);\n } else {\n throw new Error(`action function '${this.actionName}' threw: ${error}`);\n }\n }\n\n if (actionFunctionResult instanceof Promise) {\n actionFunctionResult.then(\n (result) => {\n // If 'isUpdatePromisePending' is not set then the promise was cleared as it was resolving, probably via an abort of reset.\n if (!this.isUsingUpdatePromise) {\n return;\n }\n\n // Set the resolved update promise result so that it can be handled on the next update of this node.\n this.updatePromiseResult = {\n isResolved: true,\n value: result\n };\n },\n (reason) => {\n // If 'isUpdatePromisePending' is not set then the promise was cleared as it was resolving, probably via an abort or reset.\n if (!this.isUsingUpdatePromise) {\n return;\n }\n\n // Set the rejected update promise result so that it can be handled on the next update of this node.\n this.updatePromiseResult = {\n isResolved: false,\n value: reason\n };\n }\n );\n\n // This node will be in the 'RUNNING' state until the update promise resolves.\n this.setState(State.RUNNING);\n\n // We are now waiting for the promise returned by the use to resolve before we know what state this node is in.\n this.isUsingUpdatePromise = true;\n } else {\n // Validate the returned value.\n this.validateUpdateResult(actionFunctionResult);\n\n // Set the state of this node, this may be undefined, which just means that the node is still in the 'RUNNING' state.\n this.setState(actionFunctionResult || State.RUNNING);\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => this.actionName;\n\n /**\n * Reset the state of the node.\n */\n reset = () => {\n // Reset the state of this node.\n this.setState(State.READY);\n\n // There is no longer an update promise that we care about.\n this.isUsingUpdatePromise = false;\n this.updatePromiseResult = null;\n };\n\n /**\n * Validate the result of an update function call.\n * @param result The result of an update function call.\n */\n private validateUpdateResult = (result: CompleteState | State.RUNNING) => {\n switch (result) {\n case State.SUCCEEDED:\n case State.FAILED:\n case State.RUNNING:\n case undefined:\n return;\n default:\n throw new Error(\n `expected action function '${this.actionName}' to return an optional State.SUCCEEDED or State.FAILED value but returned '${result}'`\n );\n }\n };\n}\n", "import { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Leaf from \"./Leaf\";\nimport Lookup from \"../../Lookup\";\nimport Attribute from \"../../attributes/Attribute\";\n\n/**\n * A Condition leaf node.\n * This will succeed or fail immediately based on an agent predicate, without moving to the 'RUNNING' state.\n */\nexport default class Condition extends Leaf {\n /**\n * @param attributes The node attributes.\n * @param conditionName The name of the condition function.\n * @param conditionArguments The array of condition argument definitions.\n */\n constructor(attributes: Attribute[], private conditionName: string, private conditionArguments: any[]) {\n super(\"condition\", attributes, conditionArguments);\n }\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // Attempt to get the invoker for the condition function.\n const conditionFuncInvoker = Lookup.getFuncInvoker(agent, this.conditionName);\n\n // The condition function should be defined.\n if (conditionFuncInvoker === null) {\n throw new Error(\n `cannot update condition node as the condition '${this.conditionName}' function is not defined on the agent and has not been registered`\n );\n }\n\n let conditionFunctionResult;\n\n try {\n // Call the condition function to determine the state of this node, the result of which should be a boolean.\n conditionFunctionResult = conditionFuncInvoker(this.conditionArguments);\n } catch (error) {\n // An uncaught error was thrown.\n if (error instanceof Error) {\n throw new Error(`condition function '${this.conditionName}' threw: ${error.stack}`);\n } else {\n throw new Error(`condition function '${this.conditionName}' threw: ${error}`);\n }\n }\n\n // The result of calling the condition function must be a boolean value.\n if (typeof conditionFunctionResult !== \"boolean\") {\n throw new Error(\n `expected condition function '${this.conditionName}' to return a boolean but returned '${conditionFunctionResult}'`\n );\n }\n\n // Set the state of this node based on the result of calling the condition function.\n this.setState(!!conditionFunctionResult ? State.SUCCEEDED : State.FAILED);\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => this.conditionName;\n}\n", "import Leaf from \"./Leaf\";\nimport State from \"../../State\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { Agent } from \"../../Agent\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A WAIT node.\n * The state of this node will change to SUCCEEDED after a duration of time\n */\nexport default class Wait extends Leaf {\n /**\n * @param attributes The node attributes.\n * @param duration The duration that this node will wait to succeed in milliseconds.\n * @param durationMin The minimum possible duration in milliseconds that this node will wait to succeed.\n * @param durationMax The maximum possible duration in milliseconds that this node will wait to succeed.\n */\n constructor(\n attributes: Attribute[],\n private duration: number | null,\n private durationMin: number | null,\n private durationMax: number | null\n ) {\n super(\"wait\", attributes, []);\n }\n\n /**\n * The time in milliseconds at which this node was first updated.\n */\n private initialUpdateTime: number = 0;\n\n /**\n * The total duration in milliseconds that this node will be waiting for.\n */\n private totalDuration: number | null = null;\n\n /**\n * The duration in milliseconds that this node has been waiting for.\n */\n private waitedDuration: number = 0;\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // If this node is in the READY state then we need to set the initial update time.\n if (this.is(State.READY)) {\n // Set the initial update time.\n this.initialUpdateTime = new Date().getTime();\n\n // Set the initial waited duration.\n this.waitedDuration = 0;\n\n // Are we dealing with an explicit duration or will we be randomly picking a duration between the min and max duration.\n if (this.duration !== null) {\n this.totalDuration = this.duration;\n } else if (this.durationMin !== null && this.durationMax !== null) {\n // We will be picking a random duration between a min and max duration, if the optional 'random' behaviour tree\n // function option is defined then we will be using that, otherwise we will fall back to using Math.random.\n const random = typeof options.random === \"function\" ? options.random : Math.random;\n\n // Pick a random duration between a min and max duration.\n this.totalDuration = Math.floor(\n random() * (this.durationMax - this.durationMin + 1) + this.durationMin\n );\n } else {\n this.totalDuration = null;\n }\n\n // The node is now running until we finish waiting.\n this.setState(State.RUNNING);\n }\n\n // If we have no total duration then this wait node will wait indefinitely until it is aborted.\n if (this.totalDuration === null) {\n return;\n }\n\n // If we have a 'getDeltaTime' function defined as part of our options then we will use it to figure out how long we have waited for.\n if (typeof options.getDeltaTime === \"function\") {\n // Get the delta time.\n const deltaTime = options.getDeltaTime();\n\n // Our delta time must be a valid number and cannot be NaN.\n if (typeof deltaTime !== \"number\" || isNaN(deltaTime)) {\n throw new Error(\"The delta time must be a valid number and not NaN.\");\n }\n\n // Update the amount of time that this node has been waiting for based on the delta time.\n this.waitedDuration += deltaTime * 1000;\n } else {\n // We are not using a delta time, so we will just work out hom much time has passed since the first update.\n this.waitedDuration = new Date().getTime() - this.initialUpdateTime;\n }\n\n // Have we waited long enough?\n if (this.waitedDuration >= this.totalDuration) {\n // We have finished waiting!\n this.setState(State.SUCCEEDED);\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => {\n if (this.duration !== null) {\n return `WAIT ${this.duration}ms`;\n } else if (this.durationMin !== null && this.durationMax !== null) {\n return `WAIT ${this.durationMin}ms-${this.durationMax}ms`;\n } else {\n return \"WAIT\";\n }\n };\n}\n", "import Guard from \"./guards/Guard\";\n\nexport type AttributeDetails = {\n /** The attribute type. */\n type: string;\n\n /** The attribute arguments. */\n args: any[];\n};\n\n/**\n * A base node attribute.\n */\nexport default abstract class Attribute {\n /**\n * @param type The node attribute type.\n * @param args The array of attribute arguments.\n */\n constructor(public type: string, public args: any[]) {}\n\n /**\n * Gets the attribute details.\n */\n abstract getDetails(): TAttributeDetails;\n\n /**\n * Gets whether this attribute is a guard.\n */\n abstract isGuard: () => this is Guard;\n}\n", "import { Agent } from \"../../Agent\";\nimport Attribute, { AttributeDetails } from \"../Attribute\";\n\nexport type GuardAttributeDetails = {\n /** The name of the condition function that determines whether the guard is satisfied. */\n condition: string;\n} & AttributeDetails;\n\n/**\n * A base node guard attribute.\n */\nexport default abstract class Guard extends Attribute {\n /**\n * @param type The node attribute type.\n * @param args The array of decorator argument definitions.\n * @param condition The name of the condition function that determines whether the guard is satisfied.\n */\n constructor(type: string, args: any[], private condition: string) {\n super(type, args);\n }\n\n /**\n * Gets the name of the condition function that determines whether the guard is satisfied.\n */\n getCondition = () => this.condition;\n\n /**\n * Gets whether this attribute is a guard.\n */\n isGuard = () => true;\n\n /**\n * Gets the attribute details.\n */\n getDetails(): GuardAttributeDetails {\n return {\n type: this.type,\n args: this.args,\n condition: this.getCondition()\n };\n }\n\n /**\n * Gets whether the guard is satisfied.\n * @param agent The agent.\n * @returns Whether the guard is satisfied.\n */\n abstract isSatisfied(agent: Agent): boolean;\n}\n", "import Guard from \"./Guard\";\nimport Lookup from \"../../Lookup\";\nimport { Agent } from \"../../Agent\";\n\n/**\n * A WHILE guard which is satisfied as long as the given condition remains true.\n */\nexport default class While extends Guard {\n /**\n * @param condition The name of the condition function that determines whether the guard is satisfied.\n * @param args The array of decorator argument definitions.\n */\n constructor(condition: string, args: any[]) {\n super(\"while\", args, condition);\n }\n\n /**\n * Gets whether the guard is satisfied.\n * @param agent The agent.\n * @returns Whether the guard is satisfied.\n */\n isSatisfied = (agent: Agent) => {\n // Attempt to get the invoker for the condition function.\n const conditionFuncInvoker = Lookup.getFuncInvoker(agent, this.getCondition());\n\n // The condition function should be defined.\n if (conditionFuncInvoker === null) {\n throw new Error(\n `cannot evaluate node guard as the condition '${this.getCondition()}' function is not defined on the agent and has not been registered`\n );\n }\n\n let conditionFunctionResult;\n\n try {\n // Call the guard condition function to determine the state of this node, the result of which should be a boolean.\n conditionFunctionResult = conditionFuncInvoker(this.args);\n } catch (error) {\n // An uncaught error was thrown.\n if (error instanceof Error) {\n throw new Error(`guard condition function '${this.getCondition()}' threw: ${error.stack}`);\n } else {\n throw new Error(`guard condition function '${this.getCondition()}' threw: ${error}`);\n }\n }\n\n // The result of calling the guard condition function must be a boolean value.\n if (typeof conditionFunctionResult !== \"boolean\") {\n throw new Error(\n `expected guard condition function '${this.getCondition()}' to return a boolean but returned '${conditionFunctionResult}'`\n );\n }\n\n // Return whether this guard is satisfied.\n return conditionFunctionResult;\n };\n}\n", "import Guard from \"./Guard\";\nimport Lookup from \"../../Lookup\";\nimport { Agent } from \"../../Agent\";\n\n/**\n * An UNTIL guard which is satisfied as long as the given condition remains false.\n */\nexport default class Until extends Guard {\n /**\n * @param condition The name of the condition function that determines whether the guard is satisfied.\n * @param args The array of decorator argument definitions.\n */\n constructor(condition: string, args: any[]) {\n super(\"until\", args, condition);\n }\n\n /**\n * Gets whether the guard is satisfied.\n * @param agent The agent.\n * @returns Whether the guard is satisfied.\n */\n isSatisfied = (agent: Agent) => {\n // Attempt to get the invoker for the condition function.\n const conditionFuncInvoker = Lookup.getFuncInvoker(agent, this.getCondition());\n\n // The condition function should be defined.\n if (conditionFuncInvoker === null) {\n throw new Error(\n `cannot evaluate node guard as the condition '${this.getCondition()}' function is not defined on the agent and has not been registered`\n );\n }\n\n let conditionFunctionResult;\n\n try {\n // Call the guard condition function to determine the state of this node, the result of which should be a boolean.\n conditionFunctionResult = conditionFuncInvoker(this.args);\n } catch (error) {\n // An uncaught error was thrown.\n if (error instanceof Error) {\n throw new Error(`guard condition function '${this.getCondition()}' threw: ${error.stack}`);\n } else {\n throw new Error(`guard condition function '${this.getCondition()}' threw: ${error}`);\n }\n }\n\n // The result of calling the guard condition function must be a boolean value.\n if (typeof conditionFunctionResult !== \"boolean\") {\n throw new Error(\n `expected guard condition function '${this.getCondition()}' to return a boolean but returned '${conditionFunctionResult}'`\n );\n }\n\n // Return whether this guard is satisfied.\n return !conditionFunctionResult;\n };\n}\n", "import { Agent } from \"../../Agent\";\nimport Attribute, { AttributeDetails } from \"../Attribute\";\n\nexport type CallbackAttributeDetails = {\n /** The name of the agent function that is called. */\n functionName: string;\n} & AttributeDetails;\n\n/**\n * A base node callback attribute.\n */\nexport default abstract class Callback extends Attribute {\n /**\n * @param type The node attribute type.\n * @param args The array of decorator argument definitions.\n * @param functionName The name of the agent function to call.\n */\n constructor(type: string, args: any[], private functionName: string) {\n super(type, args);\n }\n\n /**\n * Gets the name of the agent function to call.\n */\n getFunctionName = () => this.functionName;\n\n /**\n * Gets whether this attribute is a guard.\n */\n isGuard = () => false;\n\n /**\n * Gets the attribute details.\n */\n getDetails(): CallbackAttributeDetails {\n return {\n type: this.type,\n args: this.args,\n functionName: this.getFunctionName()\n };\n }\n\n /**\n * Attempt to call the agent function that this callback refers to.\n * @param agent The agent.\n */\n abstract callAgentFunction: (agent: Agent, isSuccess: boolean, isAborted: boolean) => void;\n}\n", "import Callback from \"./Callback\";\nimport Lookup from \"../../Lookup\";\nimport { Agent } from \"../../Agent\";\n\n/**\n * An ENTRY callback which defines an agent function to call when the associated node is updated and moves out of running state.\n */\nexport default class Entry extends Callback {\n /**\n * @param functionName The name of the agent function to call.\n * @param args The array of callback argument definitions.\n */\n constructor(functionName: string, args: any[]) {\n super(\"entry\", args, functionName);\n }\n\n /**\n * Attempt to call the agent function that this callback refers to.\n * @param agent The agent.\n */\n callAgentFunction = (agent: Agent) => {\n // Attempt to get the invoker for the callback function.\n const callbackFuncInvoker = Lookup.getFuncInvoker(agent, this.getFunctionName());\n\n // The callback function should be defined.\n if (callbackFuncInvoker === null) {\n throw new Error(\n `cannot call entry function '${this.getFunctionName()}' as is not defined on the agent and has not been registered`\n );\n }\n\n // Call the callback function.\n callbackFuncInvoker(this.args);\n };\n}\n", "import Callback from \"./Callback\";\nimport Lookup from \"../../Lookup\";\nimport { Agent } from \"../../Agent\";\n\n/**\n * A STEP callback which defines an agent function to call when the associated node is updated.\n */\nexport default class Step extends Callback {\n /**\n * @param functionName The name of the agent function to call.\n * @param args The array of callback argument definitions.\n */\n constructor(functionName: string, args: any[]) {\n super(\"step\", args, functionName);\n }\n\n /**\n * Attempt to call the agent function that this callback refers to.\n * @param agent The agent.\n */\n callAgentFunction = (agent: Agent) => {\n // Attempt to get the invoker for the callback function.\n const callbackFuncInvoker = Lookup.getFuncInvoker(agent, this.getFunctionName());\n\n // The callback function should be defined.\n if (callbackFuncInvoker === null) {\n throw new Error(\n `cannot call step function '${this.getFunctionName()}' as is not defined on the agent and has not been registered`\n );\n }\n\n // Call the callback function.\n callbackFuncInvoker(this.args);\n };\n}\n", "import Callback from \"./Callback\";\nimport Lookup from \"../../Lookup\";\nimport { Agent } from \"../../Agent\";\n\n/**\n * An EXIT callback which defines an agent function to call when the associated node is updated and moves to a finished state or is aborted.\n */\nexport default class Exit extends Callback {\n /**\n * @param functionName The name of the agent function to call.\n * @param args The array of callback argument definitions.\n */\n constructor(functionName: string, args: any[]) {\n super(\"exit\", args, functionName);\n }\n\n /**\n * Attempt to call the agent function that this callback refers to.\n * @param agent The agent.\n * @param isSuccess Whether the decorated node was left with a success state.\n * @param isAborted Whether the decorated node was aborted.\n */\n callAgentFunction = (agent: Agent, isSuccess: boolean, isAborted: boolean) => {\n // Attempt to get the invoker for the callback function.\n const callbackFuncInvoker = Lookup.getFuncInvoker(agent, this.getFunctionName());\n\n // The callback function should be defined.\n if (callbackFuncInvoker === null) {\n throw new Error(\n `cannot call exit function '${this.getFunctionName()}' as is not defined on the agent and has not been registered`\n );\n }\n\n // Call the callback function\n callbackFuncInvoker([{ succeeded: isSuccess, aborted: isAborted }, ...this.args]);\n };\n}\n", "import { AnyNodeDefinition, RootNodeDefinition } from \"./BehaviourTreeDefinition\";\nimport GuardPath, { GuardPathPart } from \"./attributes/guards/GuardPath\";\nimport { validateBranchSubtreeLinks } from \"./BehaviourTreeDefinitionValidator\";\nimport { isInteger } from \"./BehaviourTreeDefinitionUtilities\";\nimport Node from \"./nodes/Node\";\nimport Composite from \"./nodes/composite/Composite\";\nimport Decorator from \"./nodes/decorator/Decorator\";\nimport Parallel from \"./nodes/composite/Parallel\";\nimport Selector from \"./nodes/composite/Selector\";\nimport Sequence from \"./nodes/composite/Sequence\";\nimport Lotto from \"./nodes/composite/Lotto\";\nimport Fail from \"./nodes/decorator/Fail\";\nimport Flip from \"./nodes/decorator/Flip\";\nimport Repeat from \"./nodes/decorator/Repeat\";\nimport Retry from \"./nodes/decorator/Retry\";\nimport Root from \"./nodes/decorator/Root\";\nimport Succeed from \"./nodes/decorator/Succeed\";\nimport Action from \"./nodes/leaf/Action\";\nimport Condition from \"./nodes/leaf/Condition\";\nimport Wait from \"./nodes/leaf/Wait\";\nimport Lookup from \"./Lookup\";\nimport Attribute from \"./attributes/Attribute\";\nimport While from \"./attributes/guards/While\";\nimport Until from \"./attributes/guards/Until\";\nimport Entry from \"./attributes/callbacks/Entry\";\nimport Step from \"./attributes/callbacks/Step\";\nimport Exit from \"./attributes/callbacks/Exit\";\n\n/**\n * A type representing any node instance in a behaviour tree.\n */\ntype AnyNode =\n | Root\n | Action\n | Condition\n | Wait\n | Sequence\n | Selector\n | Lotto\n | Parallel\n | Repeat\n | Retry\n | Flip\n | Succeed\n | Fail;\n\n/**\n * A type defining a mapping of root node identifiers to root node definitions.\n */\ntype RootNodeDefinitionMap = { [key: string | symbol]: RootNodeDefinition };\n\n/**\n * A symbol to use as the main root key in any root node mappings.\n */\nconst MAIN_ROOT_NODE_KEY = Symbol(\"__root__\");\n\n/**\n * Build and populate the root nodes based on the provided definition, assuming that the definition has been validated.\n * @param definition The root node definitions.\n * @returns The built and populated root node definitions.\n */\nexport default function buildRootNode(definition: RootNodeDefinition[]): Root {\n // Create a mapping of root node identifers to root node definitions, including globally registered subtree root node definitions.\n const rootNodeDefinitionMap = createRootNodeDefinitionMap(definition);\n\n // Now that we have all of our root node definitions (those part of the tree definition and those globally registered)\n // we should validate the branch-subtree links. This will also double-check that we dont have any circular dependencies\n // in our branch-subtree references and that we have no broken branch-subtree links.\n validateBranchSubtreeLinks(\n [rootNodeDefinitionMap[MAIN_ROOT_NODE_KEY], ...Object.values(rootNodeDefinitionMap)],\n true\n );\n\n // Create our populated tree of node instances, starting with our main root node.\n const rootNode = nodeFactory(rootNodeDefinitionMap[MAIN_ROOT_NODE_KEY], rootNodeDefinitionMap) as Root;\n\n // Set a guard path on every leaf of the tree to evaluate as part of each update.\n applyLeafNodeGuardPaths(rootNode);\n\n // We only need to return the main root node.\n return rootNode;\n}\n\n/**\n * A factory function which creates a node instance based on the specified definition.\n * @param definition The node definition.\n * @param rootNodeDefinitionMap The mapping of root node identifers to root node definitions, including globally registered subtree root node definitions.\n * @returns A node instance based on the specified definition.\n */\nfunction nodeFactory(definition: AnyNodeDefinition, rootNodeDefinitionMap: RootNodeDefinitionMap): AnyNode {\n // Get the attributes for the node.\n const attributes = nodeAttributesFactory(definition);\n\n // Create the node instance based on the definition type.\n switch (definition.type) {\n case \"root\":\n return new Root(attributes, nodeFactory(definition.child, rootNodeDefinitionMap));\n\n case \"repeat\":\n let iterations: number | null = null;\n let iterationsMin: number | null = null;\n let iterationsMax: number | null = null;\n\n if (Array.isArray(definition.iterations)) {\n iterationsMin = definition.iterations[0];\n iterationsMax = definition.iterations[1];\n } else if (isInteger(definition.iterations)) {\n iterations = definition.iterations!;\n }\n\n return new Repeat(\n attributes,\n iterations,\n iterationsMin,\n iterationsMax,\n nodeFactory(definition.child, rootNodeDefinitionMap)\n );\n\n case \"retry\":\n let attempts: number | null = null;\n let attemptsMin: number | null = null;\n let attemptsMax: number | null = null;\n\n if (Array.isArray(definition.attempts)) {\n attemptsMin = definition.attempts[0];\n attemptsMax = definition.attempts[1];\n } else if (isInteger(definition.attempts)) {\n attempts = definition.attempts!;\n }\n\n return new Retry(\n attributes,\n attempts,\n attemptsMin,\n attemptsMax,\n nodeFactory(definition.child, rootNodeDefinitionMap)\n );\n\n case \"flip\":\n return new Flip(attributes, nodeFactory(definition.child, rootNodeDefinitionMap));\n\n case \"succeed\":\n return new Succeed(attributes, nodeFactory(definition.child, rootNodeDefinitionMap));\n\n case \"fail\":\n return new Fail(attributes, nodeFactory(definition.child, rootNodeDefinitionMap));\n\n case \"sequence\":\n return new Sequence(\n attributes,\n definition.children.map((child) => nodeFactory(child, rootNodeDefinitionMap))\n );\n\n case \"selector\":\n return new Selector(\n attributes,\n definition.children.map((child) => nodeFactory(child, rootNodeDefinitionMap))\n );\n\n case \"parallel\":\n return new Parallel(\n attributes,\n definition.children.map((child) => nodeFactory(child, rootNodeDefinitionMap))\n );\n\n case \"lotto\":\n return new Lotto(\n attributes,\n definition.weights,\n definition.children.map((child) => nodeFactory(child, rootNodeDefinitionMap))\n );\n\n case \"branch\":\n return nodeFactory(rootNodeDefinitionMap[definition.ref].child, rootNodeDefinitionMap);\n\n case \"action\":\n return new Action(attributes, definition.call, definition.args || []);\n\n case \"condition\":\n return new Condition(attributes, definition.call, definition.args || []);\n\n case \"wait\":\n let duration: number | null = null;\n let durationMin: number | null = null;\n let durationMax: number | null = null;\n\n if (Array.isArray(definition.duration)) {\n durationMin = definition.duration[0];\n durationMax = definition.duration[1];\n } else if (isInteger(definition.duration)) {\n duration = definition.duration!;\n }\n\n return new Wait(attributes, duration, durationMin, durationMax);\n }\n}\n\n/**\n * Creates an array of node attribute instances based on the specified node definition.\n * @param definition The node definition.\n * @returns An array of node attribute instances based on the specified node definition.\n */\nfunction nodeAttributesFactory(definition: AnyNodeDefinition): Attribute[] {\n const attributes: Attribute[] = [];\n\n if (definition.while) {\n attributes.push(new While(definition.while.call, definition.while.args ?? []));\n }\n\n if (definition.until) {\n attributes.push(new Until(definition.until.call, definition.until.args ?? []));\n }\n\n if (definition.entry) {\n attributes.push(new Entry(definition.entry.call, definition.entry.args ?? []));\n }\n\n if (definition.step) {\n attributes.push(new Step(definition.step.call, definition.step.args ?? []));\n }\n\n if (definition.exit) {\n attributes.push(new Exit(definition.exit.call, definition.exit.args ?? []));\n }\n\n return attributes;\n}\n\n/**\n * Creates a mapping of root node identifers to root node definitions, mixing in globally registered subtree root node definitions.\n * @param definition The root node definitions.\n * @returns A mapping of root node identifers to root node definitions, including globally registered subtree root node definitions.\n */\nfunction createRootNodeDefinitionMap(definition: RootNodeDefinition[]): RootNodeDefinitionMap {\n // Create a mapping of root node identifers to root node definitions.\n const rootNodeMap: RootNodeDefinitionMap = {};\n\n // Add in any registered subtree root node definitions.\n for (const [name, rootNodeDefinition] of Object.entries(Lookup.getSubtrees())) {\n // The name used when registering the subtree will be used as the root node identifier.\n rootNodeMap[name] = { ...rootNodeDefinition, id: name };\n }\n\n // Populate the map with the root node definitions that were included with the tree definition.\n // We do this after adding any registered subtrees as we want these to take presedence.\n for (const rootNodeDefinition of definition) {\n rootNodeMap[rootNodeDefinition.id ?? MAIN_ROOT_NODE_KEY] = rootNodeDefinition;\n }\n\n return rootNodeMap;\n}\n\n/**\n * Applies a guard path to every leaf of the tree to evaluate as part of each update.\n * @param root The main root tree node.\n */\nfunction applyLeafNodeGuardPaths(root: Root) {\n const nodePaths: Node[][] = [];\n\n const findLeafNodes = (path: Node[], node: Node) => {\n // Add the current node to the path.\n path = path.concat(node);\n\n // Check whether the current node is a leaf node.\n if (node.isLeafNode()) {\n nodePaths.push(path);\n } else {\n (node as Composite | Decorator).getChildren().forEach((child) => findLeafNodes(path, child));\n }\n };\n\n // Find all leaf node paths, starting from the root.\n findLeafNodes([], root);\n\n nodePaths.forEach((path) => {\n // Each node in the current path will have to be assigned a guard path, working from the root outwards.\n for (let depth = 0; depth < path.length; depth++) {\n // Get the node in the path at the current depth.\n const currentNode = path[depth];\n\n // The node may already have been assigned a guard path, if so just skip it.\n if (currentNode.hasGuardPath()) {\n continue;\n }\n\n // Create the guard path for the current node.\n const guardPath = new GuardPath(\n path\n .slice(0, depth + 1)\n .map((node) => ({ node, guards: node.getGuardAttributes() }))\n .filter((details) => details.guards.length > 0)\n );\n\n // Assign the guard path to the current node.\n currentNode.setGuardPath(guardPath);\n }\n });\n}\n", "import State, { AnyState } from \"./State\";\nimport Lookup from \"./Lookup\";\nimport Node from \"./nodes/Node\";\nimport Root from \"./nodes/decorator/Root\";\nimport Composite from \"./nodes/composite/Composite\";\nimport Decorator from \"./nodes/decorator/Decorator\";\nimport { Agent, GlobalFunction } from \"./Agent\";\nimport { CallbackAttributeDetails } from \"./attributes/callbacks/Callback\";\nimport { GuardAttributeDetails } from \"./attributes/guards/Guard\";\nimport { BehaviourTreeOptions } from \"./BehaviourTreeOptions\";\nimport { convertMDSLToJSON } from \"./mdsl/MDSLDefinitionParser\";\nimport { RootNodeDefinition } from \"./BehaviourTreeDefinition\";\nimport { validateDefinition, validateJSONDefinition } from \"./BehaviourTreeDefinitionValidator\";\nimport buildRootNode from \"./BehaviourTreeBuilder\";\nimport { isNullOrUndefined } from \"./BehaviourTreeDefinitionUtilities\";\n\n// Purely for outside inspection of the tree.\nexport type FlattenedTreeNode = {\n id: string;\n type: string;\n caption: string;\n state: AnyState;\n guards: GuardAttributeDetails[];\n callbacks: CallbackAttributeDetails[];\n args: any[];\n parentId: string | null;\n};\n\n/**\n * A representation of a behaviour tree.\n */\nexport class BehaviourTree {\n /**\n * The main root tree node.\n */\n private readonly _rootNode: Root;\n\n /**\n * Creates a new instance of the BehaviourTree class.\n * @param definition The behaviour tree definition as either an MDSL string, root node definition object or array of root node definition objects.\n * @param agent The agent instance that this behaviour tree is modelling behaviour for.\n * @param options The behaviour tree options object.\n */\n constructor(\n definition: string | RootNodeDefinition | RootNodeDefinition[],\n private agent: Agent,\n private options: BehaviourTreeOptions = {}\n ) {\n // The tree definition must be defined.\n if (isNullOrUndefined(definition)) {\n throw new Error(\"tree definition not defined\");\n }\n\n // The agent must be defined and not null.\n if (typeof agent !== \"object\" || agent === null) {\n throw new Error(\"the agent must be an object and not null\");\n }\n\n // We should validate the definition before we try to build the tree nodes.\n const { succeeded, errorMessage, json } = validateDefinition(definition);\n\n // Did our validation fail without error?\n if (!succeeded) {\n throw new Error(`invalid definition: ${errorMessage}`);\n }\n\n // Double check that we did actually get our json definition as part of our definition validtion.\n if (!json) {\n throw new Error(\n \"expected json definition to be returned as part of successful definition validation response\"\n );\n }\n\n try {\n // Create the populated tree of behaviour tree nodes and get the root node.\n this._rootNode = buildRootNode(json);\n } catch (exception) {\n // There was an issue in trying build and populate the behaviour tree.\n throw new Error(`error building tree: ${(exception as Error).message}`);\n }\n }\n\n /**\n * Gets whether the tree is in the RUNNING state.\n * @returns true if the tree is in the RUNNING state, otherwise false.\n */\n isRunning() {\n return this._rootNode.getState() === State.RUNNING;\n }\n\n /**\n * Gets the current tree state of SUCCEEDED, FAILED, READY or RUNNING.\n * @returns The current tree state.\n */\n getState() {\n return this._rootNode.getState();\n }\n\n /**\n * Step the tree.\n * 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.\n * 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\n * 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.\n *\n * 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.\n */\n step() {\n // If the root node has already been stepped to completion then we need to reset it.\n if (this._rootNode.getState() === State.SUCCEEDED || this._rootNode.getState() === State.FAILED) {\n this._rootNode.reset();\n }\n\n try {\n this._rootNode.update(this.agent, this.options);\n } catch (exception) {\n throw new Error(`error stepping tree: ${(exception as Error).message}`);\n }\n }\n\n /**\n * Resets the tree from the root node outwards to each nested node, giving each a state of READY.\n */\n reset() {\n this._rootNode.reset();\n }\n\n /**\n * Gets the flattened details of every node in the tree.\n * @returns The flattened details of every node in the tree.\n */\n getFlattenedNodeDetails(): FlattenedTreeNode[] {\n // Create an empty flattened array of tree nodes.\n const flattenedTreeNodes: FlattenedTreeNode[] = [];\n\n /**\n * Helper function to process a node instance and push details into the flattened tree nodes array.\n * @param node The current node.\n * @param parentUid The UID of the node parent, or null if the node is the main root node.\n */\n const processNode = (node: Node, parentUid: string | null) => {\n // Get the guard and callback attribute details for this node.\n const guards = node\n .getAttributes()\n .filter((attribute) => attribute.isGuard())\n .map((attribute) => attribute.getDetails()) as GuardAttributeDetails[];\n const callbacks = node\n .getAttributes()\n .filter((attribute) => !attribute.isGuard())\n .map((attribute) => attribute.getDetails()) as CallbackAttributeDetails[];\n\n // Push the current node into the flattened nodes array.\n flattenedTreeNodes.push({\n id: node.getUid(),\n type: node.getType(),\n caption: node.getName(),\n state: node.getState(),\n guards,\n callbacks,\n args: node.getArguments(),\n parentId: parentUid\n });\n\n // Process each of the nodes children if it is not a leaf node.\n if (!node.isLeafNode()) {\n (node as Composite | Decorator)\n .getChildren()\n .forEach((child) => processNode(child, (node as Composite | Decorator).getUid()));\n }\n };\n\n // Convert the nested node structure into a flattened array of node details.\n processNode(this._rootNode, null);\n\n return flattenedTreeNodes;\n }\n\n /**\n * Registers the action/condition/guard/callback function or subtree with the given name.\n * @param name The name of the function or subtree to register.\n * @param value The function or subtree definition to register.\n */\n static register(name: string, value: GlobalFunction | string | RootNodeDefinition) {\n // Are we going to register a action/condition/guard/callback function?\n if (typeof value === \"function\") {\n Lookup.setFunc(name, value);\n return;\n }\n\n // We are not registering an action/condition/guard/callback function, so we must be registering a subtree.\n if (typeof value === \"string\") {\n let rootNodeDefinitions: RootNodeDefinition[];\n\n // We will assume that any string passed in will be a mdsl definition.\n try {\n rootNodeDefinitions = convertMDSLToJSON(value);\n } catch (exception) {\n throw new Error(`error registering definition, invalid MDSL: ${(exception as Error).message}`);\n }\n\n // This function should only ever be called with a definition containing a single unnamed root node.\n if (rootNodeDefinitions.length != 1 || typeof rootNodeDefinitions[0].id !== \"undefined\") {\n throw new Error(\"error registering definition: expected a single unnamed root node\");\n }\n\n try {\n // We should validate the subtree as we don't want invalid subtrees available via the lookup.\n const { succeeded, errorMessage } = validateJSONDefinition(rootNodeDefinitions[0]);\n\n // Did our validation fail without error?\n if (!succeeded) {\n throw new Error(errorMessage);\n }\n } catch (exception) {\n throw new Error(`error registering definition: ${(exception as Error).message}`);\n }\n\n // Everything seems hunky-dory, register the subtree.\n Lookup.setSubtree(name, rootNodeDefinitions[0]);\n } else if (typeof value === \"object\" && !Array.isArray(value)) {\n // We will assume that any object passed in is a root node definition.\n\n try {\n // We should validate the subtree as we don't want invalid subtrees available via the lookup.\n const { succeeded, errorMessage } = validateJSONDefinition(value);\n\n // Did our validation fail without error?\n if (!succeeded) {\n throw new Error(errorMessage);\n }\n } catch (exception) {\n throw new Error(`error registering definition: ${(exception as Error).message}`);\n }\n\n // Everything seems hunky-dory, register the subtree.\n Lookup.setSubtree(name, value);\n } else {\n throw new Error(\"unexpected value, expected string mdsl definition, root node json definition or function\");\n }\n }\n\n /**\n * Unregisters the registered action/condition/guard/callback function or subtree with the given name.\n * @param name The name of the registered action/condition/guard/callback function or subtree to unregister.\n */\n static unregister(name: string): void {\n Lookup.remove(name);\n }\n\n /**\n * Unregister all registered action/condition/guard/callback functions and subtrees.\n */\n static unregisterAll(): void {\n Lookup.empty();\n }\n}\n"], + "mappings": "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", "names": ["Participant", "isNullOrUndefined", "Lotto", "createLotto", "State", "createLotto"] } diff --git a/dist/index.js b/dist/index.js index 5a1f275..b770958 100644 --- a/dist/index.js +++ b/dist/index.js @@ -1236,7 +1236,7 @@ var Lookup = class { } if (this.registeredFunctions[name] && typeof this.registeredFunctions[name] === "function") { const registeredFunction = this.registeredFunctions[name]; - return (args) => registeredFunction(agent, ...args.map((arg) => arg.value)); + return (args) => registeredFunction(agent, ...args); } return null; } @@ -2314,7 +2314,7 @@ var BehaviourTree = class { } catch (exception) { throw new Error(`error registering definition, invalid MDSL: ${exception.message}`); } - if (rootNodeDefinitions.length != 1 || rootNodeDefinitions[0].id !== null) { + if (rootNodeDefinitions.length != 1 || typeof rootNodeDefinitions[0].id !== "undefined") { throw new Error("error registering definition: expected a single unnamed root node"); } try { diff --git a/dist/index.js.map b/dist/index.js.map index 082550a..a80e4c3 100644 --- a/dist/index.js.map +++ b/dist/index.js.map @@ -1,7 +1,7 @@ { "version": 3, "sources": ["../node_modules/lotto-draw/dist/Participant.js", "../node_modules/lotto-draw/dist/Utilities.js", "../node_modules/lotto-draw/dist/Lotto.js", "../node_modules/lotto-draw/dist/createLotto.js", "../node_modules/lotto-draw/dist/index.js", "../src/index.ts", "../src/State.ts", "../src/BehaviourTreeDefinitionUtilities.ts", "../src/mdsl/MDSLUtilities.ts", "../src/mdsl/MDSLNodeArgumentParser.ts", "../src/mdsl/MDSLNodeAttributeParser.ts", "../src/mdsl/MDSLDefinitionParser.ts", "../src/BehaviourTreeDefinitionValidator.ts", "../src/Lookup.ts", "../src/attributes/guards/GuardUnsatisifedException.ts", "../src/attributes/guards/GuardPath.ts", "../src/nodes/Node.ts", "../src/nodes/composite/Composite.ts", "../src/nodes/composite/Parallel.ts", "../src/nodes/composite/Selector.ts", "../src/nodes/composite/Sequence.ts", "../src/nodes/composite/Lotto.ts", "../src/nodes/decorator/Decorator.ts", "../src/nodes/decorator/Fail.ts", "../src/nodes/decorator/Flip.ts", "../src/nodes/decorator/Repeat.ts", "../src/nodes/decorator/Retry.ts", "../src/nodes/decorator/Root.ts", "../src/nodes/decorator/Succeed.ts", "../src/nodes/leaf/Leaf.ts", "../src/nodes/leaf/Action.ts", "../src/nodes/leaf/Condition.ts", "../src/nodes/leaf/Wait.ts", "../src/attributes/Attribute.ts", "../src/attributes/guards/Guard.ts", "../src/attributes/guards/While.ts", "../src/attributes/guards/Until.ts", "../src/attributes/callbacks/Callback.ts", "../src/attributes/callbacks/Entry.ts", "../src/attributes/callbacks/Step.ts", "../src/attributes/callbacks/Exit.ts", "../src/BehaviourTreeBuilder.ts", "../src/BehaviourTree.ts"], - "sourcesContent": ["\"use strict\";\r\nObject.defineProperty(exports, \"__esModule\", { value: true });\r\nexports.Participant = void 0;\r\n/**\r\n * A participant that holds a number of tickets.\r\n */\r\nvar Participant = /** @class */ (function () {\r\n /**\r\n * Creates an instance of the Participant class.\r\n * @param participant The actual participant.\r\n * @param tickets The number of tickets held by the participant.\r\n */\r\n function Participant(participant, tickets) {\r\n if (tickets === void 0) { tickets = 1; }\r\n this._participant = participant;\r\n this._tickets = tickets;\r\n }\r\n Object.defineProperty(Participant.prototype, \"participant\", {\r\n /** Gets the actual participant. */\r\n get: function () {\r\n return this._participant;\r\n },\r\n enumerable: false,\r\n configurable: true\r\n });\r\n Object.defineProperty(Participant.prototype, \"tickets\", {\r\n /** Gets or sets the number of tickets held by the participant. */\r\n get: function () {\r\n return this._tickets;\r\n },\r\n set: function (value) {\r\n this._tickets = value;\r\n },\r\n enumerable: false,\r\n configurable: true\r\n });\r\n return Participant;\r\n}());\r\nexports.Participant = Participant;\r\n", "\"use strict\";\r\nObject.defineProperty(exports, \"__esModule\", { value: true });\r\nexports.isNaturalNumber = exports.isNullOrUndefined = void 0;\r\n/**\r\n * Gets whether the value provided is null or undefined.\r\n * @param value The value to check.\r\n * @returns Whether the value provided is null or undefined.\r\n */\r\nfunction isNullOrUndefined(value) {\r\n return value === null || value === undefined;\r\n}\r\nexports.isNullOrUndefined = isNullOrUndefined;\r\n/**\r\n * Gets whether the value provided is a natural number.\r\n * @param value The value to check.\r\n * @returns Whether the value provided is a natural number.\r\n */\r\nfunction isNaturalNumber(value) {\r\n return typeof value === \"number\" && value >= 1 && Math.floor(value) === value;\r\n}\r\nexports.isNaturalNumber = isNaturalNumber;\r\n", "\"use strict\";\r\nObject.defineProperty(exports, \"__esModule\", { value: true });\r\nexports.Lotto = void 0;\r\nvar Participant_1 = require(\"./Participant\");\r\nvar Utilities_1 = require(\"./Utilities\");\r\n/**\r\n * Represents a lotto consisting of a number of pickable ticket-holding participants.\r\n */\r\nvar Lotto = /** @class */ (function () {\r\n /**\r\n * Creates a new instance of Lotto.\r\n * @param customRandom The custom RNG to use in place of Math.random().\r\n */\r\n function Lotto(customRandom) {\r\n /** The array of participants that are holding tickets in the lotto. */\r\n this._participants = [];\r\n this._customRandom = customRandom;\r\n }\r\n /**\r\n * Adds a participant with the specified number of tickets, or adds to the participant ticket count if the participant already holds tickets.\r\n * @param participant The participant to add or to increase the ticket count for if they already hold tickets.\r\n * @param tickets The number of tickets, defaults to 1.\r\n * @returns The Lotto instance.\r\n */\r\n Lotto.prototype.add = function (participant, tickets) {\r\n if (tickets === void 0) { tickets = 1; }\r\n // Check that we have a valid ticket count.\r\n if (!(0, Utilities_1.isNaturalNumber)(tickets)) {\r\n throw new Error(\"tickets value must be a natural number\");\r\n }\r\n // Check whether this participant has already been added.\r\n var existingParticipant = this._participants.find(function (part) { return part.participant === participant; });\r\n if (existingParticipant) {\r\n // The participant has already been added to the lotto so just add to their ticket count.\r\n existingParticipant.tickets += tickets;\r\n }\r\n else {\r\n // The participant is not part of the lotto so we should add them.\r\n this._participants.push(new Participant_1.Participant(participant, tickets));\r\n }\r\n return this;\r\n };\r\n /**\r\n * Removes the specified number of tickets for the given participant from the draw, or all tickets if a ticket number is not defined.\r\n * @param participant The participant to remove tickets for.\r\n * @param tickets The number of tickets to remove, or undefined if all tickets are to be removed.\r\n * @returns The Lotto instance.\r\n */\r\n Lotto.prototype.remove = function (participant, tickets) {\r\n // Attempt to get the existing participant.\r\n var existingParticipant = this._participants.find(function (part) { return part.participant === participant; });\r\n // There is nothing to do if the specified participant isn't even part of the lotto.\r\n if (!existingParticipant) {\r\n return this;\r\n }\r\n // Check whether a tickets value was given.\r\n if (tickets !== undefined) {\r\n // Check that we have a valid ticket count.\r\n if (!(0, Utilities_1.isNaturalNumber)(tickets)) {\r\n throw new Error(\"tickets value must be a natural number\");\r\n }\r\n existingParticipant.tickets -= tickets;\r\n // If the participant no longer holds any tickets then they should be removed.\r\n if (existingParticipant.tickets < 1) {\r\n this._participants = this._participants.filter(function (part) { return part !== existingParticipant; });\r\n }\r\n }\r\n else {\r\n // We are removing all tickets for the participant so just remove them from the lotto.\r\n this._participants = this._participants.filter(function (part) { return part !== existingParticipant; });\r\n }\r\n return this;\r\n };\r\n /**\r\n * Draw a winning ticket and return the participant that holds the ticket.\r\n * @param options The draw options.\r\n * @returns The participant that holds the winning ticket.\r\n */\r\n Lotto.prototype.draw = function (options) {\r\n if (options === void 0) { options = {}; }\r\n // If we have no participants then just return null.\r\n if (this._participants.length === 0) {\r\n return null;\r\n }\r\n var redrawable = (0, Utilities_1.isNullOrUndefined)(options.redrawable) ? true : options.redrawable;\r\n var pickable = [];\r\n this._participants.forEach(function (_a) {\r\n var participant = _a.participant, tickets = _a.tickets;\r\n for (var ticketCount = 0; ticketCount < tickets; ticketCount++) {\r\n pickable.push(participant);\r\n }\r\n });\r\n var random;\r\n // We need a random floating-point number between 0 (inclusive) and 1 to scale up to pick our winner.\r\n // If a custom random function exists then we should use that or fall back to Math.random().\r\n if (this._customRandom) {\r\n // Call our custom random function to get a random floating-point number.\r\n random = this._customRandom();\r\n // Verify that the result of calling our custom random function is a number between 0 (inclusive) and 1.\r\n if (typeof random !== \"number\" || random < 0 || random >= 1) {\r\n throw new Error(\"the 'random' function provided did not return a number between 0 (inclusive) and 1\");\r\n }\r\n }\r\n else {\r\n // No custom random function was defined so just use good ol' Math.random().\r\n random = Math.random();\r\n }\r\n // Pick a winning participant.\r\n var winner = pickable[Math.floor(random * pickable.length)];\r\n // If the ticket isn't redrawable then we should remove a ticket from the winning participants ticket count.\r\n if (!redrawable) {\r\n this.remove(winner, 1);\r\n }\r\n // Return the winning participant.\r\n return winner;\r\n };\r\n /**\r\n * Draws multiple winning tickets and return an array of the participants that hold the winning tickets.\r\n * @param tickets The number of winning tickets to draw.\r\n * @param options The draw multiple options.\r\n * @returns An array of the participants that hold the winning tickets.\r\n */\r\n Lotto.prototype.drawMultiple = function (tickets, options) {\r\n if (options === void 0) { options = {}; }\r\n var uniqueResults = (0, Utilities_1.isNullOrUndefined)(options.unique) ? false : options.unique;\r\n // Handle cases where the user has asked for zero tickets (no idea why they would do this be we should trust them).\r\n if (tickets === 0) {\r\n return [];\r\n }\r\n // Now that we know out tickets value is not zero we should check that it is a valid natural number.\r\n if (!(0, Utilities_1.isNaturalNumber)(tickets)) {\r\n throw new Error(\"tickets value must be a natural number\");\r\n }\r\n var result = [];\r\n // Keep drawing tickets until we either reach the number of required tickets or we simply run out of tickets to draw.\r\n // We can run out of tickets to draw if 'options.redrawable' is explicity 'false' or we just had no participants when 'drawMultiple' was called.\r\n while (result.length < tickets && this._participants.length > 0) {\r\n result.push(this.draw(options));\r\n }\r\n // If the 'unique' draw option is set then we need to remove duplicates from the result list.\r\n if (uniqueResults) {\r\n // Create an array to store our unique results.\r\n var unique = [];\r\n // Iterate over all of our participants (with potential duplicates) and populate our array of unique values.\r\n for (var _i = 0, result_1 = result; _i < result_1.length; _i++) {\r\n var participant = result_1[_i];\r\n if (unique.indexOf(participant) === -1) {\r\n unique.push(participant);\r\n }\r\n }\r\n result = unique;\r\n }\r\n return result;\r\n };\r\n return Lotto;\r\n}());\r\nexports.Lotto = Lotto;\r\n", "\"use strict\";\r\nObject.defineProperty(exports, \"__esModule\", { value: true });\r\nexports.createLotto = void 0;\r\nvar Lotto_1 = require(\"./Lotto\");\r\n/**\r\n * A function that creates and returns a Lotto instance.\r\n * @param participantsOrOptions An array of initial participants or options relating to the creation of a Lotto instance.\r\n * @returns A new Lotto instance.\r\n */\r\nfunction createLotto(participantsOrOptions) {\r\n // If no initial participants or lotto options were provided as an argument then we can just return a new lotto instance now.\r\n if (!participantsOrOptions) {\r\n return new Lotto_1.Lotto();\r\n }\r\n // Check whether we were provided with an array of initial participants or a lotto options object.\r\n if (Array.isArray(participantsOrOptions)) {\r\n // We are dealing with a pre-defined array of participants.\r\n var participants = participantsOrOptions;\r\n var lotto_1 = new Lotto_1.Lotto();\r\n // If the lotto participants have been defined upfront then we will need to add them all to our lotto instance now.\r\n participants.forEach(function (_a) {\r\n var participant = _a[0], tokens = _a[1];\r\n return lotto_1.add(participant, tokens);\r\n });\r\n // Return the Lotto instance.\r\n return lotto_1;\r\n }\r\n else {\r\n // We are dealing with some lotto options.\r\n var random = participantsOrOptions.random, participants = participantsOrOptions.participants;\r\n // Create a Lotto instance passing the custom RNG function to use in place of Math.random() (which could be undefined).\r\n var lotto_2 = new Lotto_1.Lotto(random);\r\n // If the lotto participants have been defined upfront as part of the options then we will need to add them all to our lotto instance now.\r\n if (participants) {\r\n participants.forEach(function (_a) {\r\n var participant = _a[0], tokens = _a[1];\r\n return lotto_2.add(participant, tokens);\r\n });\r\n }\r\n // Return the Lotto instance.\r\n return lotto_2;\r\n }\r\n}\r\nexports.createLotto = createLotto;\r\n", "\"use strict\";\r\nObject.defineProperty(exports, \"__esModule\", { value: true });\r\nvar createLotto_1 = require(\"./createLotto\");\r\nexports.default = createLotto_1.createLotto;\r\n", "import State from \"./State\";\nimport { validateDefinition } from \"./BehaviourTreeDefinitionValidator\";\nimport { convertMDSLToJSON } from \"./mdsl/MDSLDefinitionParser\";\nimport { BehaviourTree, FlattenedTreeNode } from \"./BehaviourTree\";\nimport { BehaviourTreeOptions } from \"./BehaviourTreeOptions\";\n\nexport { BehaviourTree, State, convertMDSLToJSON, validateDefinition };\nexport type { FlattenedTreeNode, BehaviourTreeOptions };\n", "/**\n * Enumeration of node state types.\n */\nexport enum State {\n READY = \"mistreevous.ready\",\n RUNNING = \"mistreevous.running\",\n SUCCEEDED = \"mistreevous.succeeded\",\n FAILED = \"mistreevous.failed\"\n}\n\nexport { State as default };\n\nexport type CompleteState = State.SUCCEEDED | State.FAILED;\nexport type AnyState = State.READY | State.RUNNING | CompleteState;\n", "import {\n NodeDefinition,\n RootNodeDefinition,\n DecoratorNodeDefinition,\n CompositeNodeDefinition,\n AnyNodeDefinition,\n BranchNodeDefinition\n} from \"./BehaviourTreeDefinition\";\n\n/**\n * A type guard function that returns true if the specified node satisfies the RootNodeDefinition type.\n * @param node The node.\n * @returns A value of true if the specified node satisfies the RootNodeDefinition type.\n */\nexport function isRootNode(node: NodeDefinition): node is RootNodeDefinition {\n return node.type === \"root\";\n}\n\n/**\n * A type guard function that returns true if the specified node satisfies the BranchNodeDefinition type.\n * @param node The node.\n * @returns A value of true if the specified node satisfies the BranchNodeDefinition type.\n */\nexport function isBranchNode(node: NodeDefinition): node is BranchNodeDefinition {\n return node.type === \"branch\";\n}\n\n/**\n * A type guard function that returns true if the specified node satisfies the NodeDefinition type.\n * @param node The node.\n * @returns A value of true if the specified node satisfies the NodeDefinition type.\n */\nexport function isLeafNode(node: NodeDefinition): node is NodeDefinition {\n return [\"branch\", \"action\", \"condition\", \"wait\"].includes(node.type);\n}\n\n/**\n * A type guard function that returns true if the specified node satisfies the DecoratorNodeDefinition type.\n * @param node The node.\n * @returns A value of true if the specified node satisfies the DecoratorNodeDefinition type.\n */\nexport function isDecoratorNode(node: NodeDefinition): node is DecoratorNodeDefinition {\n return [\"root\", \"repeat\", \"retry\", \"flip\", \"succeed\", \"fail\"].includes(node.type);\n}\n\n/**\n * A type guard function that returns true if the specified node satisfies the CompositeNodeDefinition type.\n * @param node The node.\n * @returns A value of true if the specified node satisfies the CompositeNodeDefinition type.\n */\nexport function isCompositeNode(node: NodeDefinition): node is CompositeNodeDefinition {\n return [\"sequence\", \"selector\", \"lotto\", \"parallel\"].includes(node.type);\n}\n\n/**\n * Flatten a node definition into an array of all of its nested node definitions.\n * @param nodeDefinition The node definition to flatten.\n * @returns An array of all of nested node definitions.\n */\nexport function flattenDefinition(nodeDefinition: AnyNodeDefinition): AnyNodeDefinition[] {\n const nodes: AnyNodeDefinition[] = [];\n\n const processNode = (currentNodeDefinition: AnyNodeDefinition) => {\n nodes.push(currentNodeDefinition);\n\n if (isCompositeNode(currentNodeDefinition)) {\n currentNodeDefinition.children.forEach(processNode);\n } else if (isDecoratorNode(currentNodeDefinition)) {\n processNode(currentNodeDefinition.child);\n }\n };\n\n processNode(nodeDefinition);\n\n return nodes;\n}\n\n/**\n * Determines whether the passed value is an integer.\n * @param value The value to check.\n * @returns Whether the passed value is an integer.\n */\nexport function isInteger(value: unknown): boolean {\n return typeof value === \"number\" && Math.floor(value) === value;\n}\n\n/**\n * Determines whether the passed value is null or undefined.\n * @param value The value to check.\n * @returns Whether the passed value is null or undefined.\n */\nexport function isNullOrUndefined(value: unknown): boolean {\n return typeof value === \"undefined\" || value === null;\n}\n", "/**\n * A type defining an object that holds a reference to substitued string literals parsed from the definition.\n */\nexport type StringLiteralPlaceholders = { [key: string]: string };\n\n/**\n * Pop the next raw token from the specified array of tokens and throw an error if it wasn't the expected one.\n * @param tokens The array of tokens.\n * @param expected An optional string or array or items, one of which must match the next popped token.\n * @returns The popped token.\n */\nexport function popAndCheck(tokens: string[], expected?: string | string[]): string {\n // Get and remove the next token.\n const popped = tokens.shift();\n\n // We were expecting another token but there aren't any.\n if (popped === undefined) {\n throw new Error(\"unexpected end of definition\");\n }\n\n // Do we have an expected token/tokens array?\n if (expected != undefined) {\n // Get an array of expected values, if the popped token matches any then we are all good.\n const expectedValues = typeof expected === \"string\" ? [expected] : expected;\n\n // Check whether the popped token matches at least one of our expected items.\n var tokenMatchesExpectation = expectedValues.some((item) => popped.toUpperCase() === item.toUpperCase());\n\n // Throw an error if the popped token didn't match any of our expected items.\n if (!tokenMatchesExpectation) {\n const expectationString = expectedValues.map((item) => \"'\" + item + \"'\").join(\" or \");\n throw new Error(\"unexpected token found. Expected \" + expectationString + \" but got '\" + popped + \"'\");\n }\n }\n\n // Return the popped token.\n return popped;\n}\n\n/**\n * Swaps out any node/attribute argument string literals with placeholders.\n * @param definition The definition.\n * @returns An object containing a mapping of placeholders to original string values as well as the processed definition string.\n */\nexport function substituteStringLiterals(definition: string): {\n placeholders: StringLiteralPlaceholders;\n processedDefinition: string;\n} {\n // Create an object to hold the mapping of placeholders to original string values.\n const placeholders: StringLiteralPlaceholders = {};\n\n // Replace any string literals wrapped with double quotes in our definition with placeholders to be processed later.\n const processedDefinition = definition.replace(/\\\"(\\\\.|[^\"\\\\])*\\\"/g, (match) => {\n var strippedMatch = match.substring(1, match.length - 1);\n var placeholder = Object.keys(placeholders).find((key) => placeholders[key] === strippedMatch);\n\n // If we have no existing string literal match then create a new placeholder.\n if (!placeholder) {\n placeholder = `@@${Object.keys(placeholders).length}@@`;\n placeholders[placeholder] = strippedMatch;\n }\n\n return placeholder;\n });\n\n return { placeholders, processedDefinition };\n}\n\n/**\n * Parse the tree definition into an array of raw tokens.\n * @param definition The definition.\n * @returns An array of tokens parsed from the definition.\n */\nexport function parseTokensFromDefinition(definition: string): string[] {\n // Add some space around various important characters so that they can be plucked out easier as individual tokens.\n definition = definition.replace(/\\(/g, \" ( \");\n definition = definition.replace(/\\)/g, \" ) \");\n definition = definition.replace(/\\{/g, \" { \");\n definition = definition.replace(/\\}/g, \" } \");\n definition = definition.replace(/\\]/g, \" ] \");\n definition = definition.replace(/\\[/g, \" [ \");\n definition = definition.replace(/\\,/g, \" , \");\n\n // Split the definition into raw token form and return it.\n return definition.replace(/\\s+/g, \" \").trim().split(\" \");\n}\n", "import { StringLiteralPlaceholders, popAndCheck } from \"./MDSLUtilities\";\n\n/**\n * A type representing any node function argument.\n */\ntype Argument = {\n /**\n * The argument value.\n */\n value: T;\n /**\n * The argument type, used for validation.\n */\n type: string;\n};\n\ntype NullArgument = Argument & {\n type: \"null\";\n};\n\ntype BooleanArgument = Argument & {\n type: \"boolean\";\n};\n\ntype NumberArgument = Argument & {\n type: \"number\";\n /**\n * A flag defining whether the number argument value is a valid integer. (used for validation)\n */\n isInteger: boolean;\n};\n\ntype StringPlaceholderArgument = Argument & {\n type: \"string\";\n};\n\ntype IdentifierArgument = Argument & {\n type: \"identifier\";\n};\n\n/**\n * A type representing a reference to any node function argument.\n */\ntype AnyArgument = NullArgument | BooleanArgument | NumberArgument | StringPlaceholderArgument | IdentifierArgument;\n\n/**\n * Parse an array of argument definitions from the specified tokens array.\n * @param tokens The array tokens to parse the argument definitions from.\n * @param stringArgumentPlaceholders The mapping of string literal node argument placeholders to original values.\n * @param argumentValidator The argument validator function.\n * @param validationFailedMessage The exception message to throw if argument validation fails.\n * @returns An array of argument definitions parsed from the specified tokens array.\n */\nexport function parseArgumentTokens(\n tokens: string[],\n stringArgumentPlaceholders: StringLiteralPlaceholders\n): AnyArgument[] {\n const argumentList: AnyArgument[] = [];\n\n // If the next token is not a '[' or '(' then we have no arguments to parse.\n if (![\"[\", \"(\"].includes(tokens[0])) {\n return argumentList;\n }\n\n // Any lists of arguments will always be wrapped in '[]' for node arguments or '()' for attribute arguments.\n // We are looking for a '[' or '(' opener that wraps the argument tokens and the relevant closer.\n const closingToken = popAndCheck(tokens, [\"[\", \"(\"]) === \"[\" ? \"]\" : \")\";\n\n const argumentListTokens: string[] = [];\n\n // Grab all tokens between the '[' and ']' or '(' and ')'.\n while (tokens.length && tokens[0] !== closingToken) {\n // The next token is part of our arguments list.\n argumentListTokens.push(tokens.shift()!);\n }\n\n // Validate the order of the argument tokens. Each token must either be a ',' or a single argument that satisfies the validator.\n argumentListTokens.forEach((token, index) => {\n // Get whether this token should be an actual argument.\n const shouldBeArgumentToken = !(index & 1);\n\n // If the current token should be an actual argument then validate it, otherwise it should be a ',' token.\n if (shouldBeArgumentToken) {\n // Get the argument definition.\n const argumentDefinition = getArgumentDefinition(token, stringArgumentPlaceholders);\n\n // This is a valid argument!\n argumentList.push(argumentDefinition);\n } else {\n // The current token should be a ',' token.\n if (token !== \",\") {\n throw new Error(`invalid argument list, expected ',' or ']' but got '${token}'`);\n }\n }\n });\n\n // The arguments list should terminate with a ']' or ')' token, depending on the opener.\n popAndCheck(tokens, closingToken);\n\n // Return the arguments.\n return argumentList;\n}\n\n/**\n * Gets an argument value definition.\n * @param token The argument token.\n * @param stringArgumentPlaceholders The mapping of string literal node argument placeholders to original values.\n * @returns An argument value definition.\n */\nfunction getArgumentDefinition(token: string, stringArgumentPlaceholders: StringLiteralPlaceholders): AnyArgument {\n // Check whether the token represents a null value.\n if (token === \"null\") {\n return {\n value: null,\n type: \"null\"\n } as NullArgument;\n }\n\n // Check whether the token represents a boolean value.\n if (token === \"true\" || token === \"false\") {\n return {\n value: token === \"true\",\n type: \"boolean\"\n } as BooleanArgument;\n }\n\n // Check whether the token represents a number value.\n // TODO: Relies on broken isNaN - see MDN.\n // if (!Number.isNaN(token)) {\n if (!isNaN(token as any)) {\n return {\n value: parseFloat(token),\n isInteger: parseFloat(token) === parseInt(token, 10),\n type: \"number\"\n } as NumberArgument;\n }\n\n // Check whether the token is a placeholder (e.g. @@0@@) representing a string literal.\n if (token.match(/^@@\\d+@@$/g)) {\n return {\n value: stringArgumentPlaceholders[token].replace('\\\\\"', '\"'),\n type: \"string\"\n } as StringPlaceholderArgument;\n }\n\n // The only remaining option is that the argument value is an identifier.\n return {\n value: token,\n type: \"identifier\"\n } as IdentifierArgument;\n}\n", "import { NodeAttributeDefinition } from \"../BehaviourTreeDefinition\";\nimport { parseArgumentTokens } from \"./MDSLNodeArgumentParser\";\nimport { StringLiteralPlaceholders } from \"./MDSLUtilities\";\n\n/**\n * A type defining the attribute definitions of a node.\n */\ntype NodeAttributes = {\n while?: NodeAttributeDefinition;\n until?: NodeAttributeDefinition;\n entry?: NodeAttributeDefinition;\n exit?: NodeAttributeDefinition;\n step?: NodeAttributeDefinition;\n};\n\n/**\n * Parse any node attribute definitions from the specified tokens array.\n * @param tokens The array of remaining tokens.\n * @param stringArgumentPlaceholders The mapping of string literal node argument placeholders to original values.\n * @returns An object of attribute definitions defined by any directly following tokens.\n */\nexport function parseAttributeTokens(\n tokens: string[],\n stringArgumentPlaceholders: StringLiteralPlaceholders\n): NodeAttributes {\n const nodeAttributeNames: (keyof NodeAttributes)[] = [\"while\", \"until\", \"entry\", \"exit\", \"step\"];\n\n // Create an object to hold any attributes found.\n const attributes: NodeAttributes = {};\n\n // Try to get the name of the attribute for the next token.\n let nextAttributeName = tokens[0]?.toLowerCase() as keyof NodeAttributes;\n\n // Pull attribute tokens as well as their arguments off of the tokens stack until we have no more.\n while (nodeAttributeNames.includes(nextAttributeName)) {\n // Check to make sure that we have not already created an attribute definition of this type.\n if (attributes[nextAttributeName]) {\n throw new Error(`duplicate attribute '${tokens[0].toUpperCase()}' found for node`);\n }\n\n // Remove the attribute name token from the array of tokens.\n tokens.shift();\n\n // Grab the attribute arguments, assuming the first to be an identifier.\n const [attributeCallIdentifier, ...attributeArguments] = parseArgumentTokens(\n tokens,\n stringArgumentPlaceholders\n );\n\n // The first attribute argument has to be an identifer, this will reference an agent function.\n if (attributeCallIdentifier?.type !== \"identifier\") {\n throw new Error(\"expected agent function or registered function name identifier argument for attribute\");\n }\n\n // Any attribute arguments (other than the expected call identifier) must have a type of string, number, boolean or null.\n attributeArguments\n .filter((arg) => arg.type === \"identifier\")\n .forEach((arg) => {\n throw new Error(\n `invalid attribute argument value '${arg.value}', must be string, number, boolean or null`\n );\n });\n\n // Create the attribute definition and add it to the object of attribute definitions found.\n attributes[nextAttributeName] = {\n call: attributeCallIdentifier.value,\n args: attributeArguments.map(({ value }) => value)\n };\n\n // Try to get the next attribute name token, as there could be multiple.\n nextAttributeName = tokens[0]?.toLowerCase() as keyof NodeAttributes;\n }\n\n return attributes;\n}\n", "import {\n ActionNodeDefinition,\n AnyChildNodeDefinition,\n AnyNodeDefinition,\n BranchNodeDefinition,\n ConditionNodeDefinition,\n FailNodeDefinition,\n FlipNodeDefinition,\n LottoNodeDefinition,\n ParallelNodeDefinition,\n RepeatNodeDefinition,\n RetryNodeDefinition,\n RootNodeDefinition,\n SelectorNodeDefinition,\n SequenceNodeDefinition,\n SucceedNodeDefinition,\n WaitNodeDefinition\n} from \"../BehaviourTreeDefinition\";\nimport {\n isCompositeNode,\n isDecoratorNode,\n isLeafNode,\n isNullOrUndefined,\n isRootNode\n} from \"../BehaviourTreeDefinitionUtilities\";\nimport { parseArgumentTokens } from \"./MDSLNodeArgumentParser\";\nimport { parseAttributeTokens } from \"./MDSLNodeAttributeParser\";\nimport {\n StringLiteralPlaceholders,\n parseTokensFromDefinition,\n popAndCheck,\n substituteStringLiterals\n} from \"./MDSLUtilities\";\n\n/**\n * Convert the MDSL tree definition string into an equivalent JSON definition.\n * @param definition The tree definition string as MDSL.\n * @returns The root node JSON definitions.\n */\nexport function convertMDSLToJSON(definition: string): RootNodeDefinition[] {\n // Swap out any node/attribute argument string literals with a placeholder and get a mapping of placeholders to original values as well as the processed definition.\n const { placeholders, processedDefinition } = substituteStringLiterals(definition);\n\n // Parse our definition definition string into an array of raw tokens.\n const tokens = parseTokensFromDefinition(processedDefinition);\n\n return convertTokensToJSONDefinition(tokens, placeholders);\n}\n\n/**\n * Converts the specified tree definition tokens into a JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The root node JSON definitions.\n */\nfunction convertTokensToJSONDefinition(\n tokens: string[],\n stringLiteralPlaceholders: StringLiteralPlaceholders\n): RootNodeDefinition[] {\n // There must be at least 3 tokens for the tree definition to be valid. 'ROOT', '{' and '}'.\n if (tokens.length < 3) {\n throw new Error(\"invalid token count\");\n }\n\n // We should have a matching number of '{' and '}' tokens. If not, then there are scopes that have not been properly closed.\n if (tokens.filter((token) => token === \"{\").length !== tokens.filter((token) => token === \"}\").length) {\n throw new Error(\"scope character mismatch\");\n }\n\n // Create an array of tree stack arrays where root nodes will always be at the botton and the current composite/decorator node at the top.\n // There should be an element in this array for every root node defined and every element should be an array with a root note as the first element.\n // E.g. A definition with two root nodes defined:\n // [\n // [root, lotto, sequence],\n // [root, selector]\n // ]\n const treeStacks: [Partial, ...Partial[]][] = [];\n\n // Create an array of all root node definitions that we create.\n const rootNodes: Partial[] = [];\n\n // A helper function used to push node definitions onto the tree stack.\n const pushNode = (node: AnyNodeDefinition) => {\n // If the node is a root node then we need to create a new tree stack array with the root node at the root.\n if (isRootNode(node)) {\n // We need to double-check that this root node is not the child of another node.\n // We can do this by checking whether the top tree stack is not empty (contains an existing node)\n if (treeStacks[treeStacks.length - 1]?.length) {\n throw new Error(\"a root node cannot be the child of another node\");\n }\n\n // Add the root node definition to our array of all parsed root node definitions.\n rootNodes.push(node);\n\n // Add the root node definition to the root of a new tree stack.\n treeStacks.push([node]);\n\n return;\n }\n\n // All non-root nodes should be pushed after their root nodes so handle cases\n // where we may not have any tree stacks or our top-most tree stack is empty.\n if (!treeStacks.length || !treeStacks[treeStacks.length - 1].length) {\n throw new Error(\"expected root node at base of definition\");\n }\n\n // Get the current tree stack that we are populating.\n const topTreeStack = treeStacks[treeStacks.length - 1];\n\n // Get the top-most node in the current tree stack, this will be a composite/decorator node\n // for which we will populate its children array if composite or setting its child if a decorator.\n const topTreeStackTopNode = topTreeStack[topTreeStack.length - 1] as AnyNodeDefinition;\n\n // If the top-most node in the current root stack is a composite or decorator\n // node then the current node should be added as a child of the top-most node.\n if (isCompositeNode(topTreeStackTopNode)) {\n topTreeStackTopNode.children = topTreeStackTopNode.children || [];\n topTreeStackTopNode.children.push(node);\n } else if (isDecoratorNode(topTreeStackTopNode)) {\n // If the top node already has a child node set then throw an error as a decorator should only have a single child.\n if (topTreeStackTopNode.child) {\n throw new Error(\"a decorator node must only have a single child node\");\n }\n\n topTreeStackTopNode.child = node;\n }\n\n // If the node we are adding is also a composite or decorator node, then we should push it\n // onto the current tree stack, as subsequent nodes will be added as its child/children.\n if (!isLeafNode(node)) {\n topTreeStack.push(node);\n }\n };\n\n // A helper function used to pop the top-most node definition off of the tree stack and return it.\n const popNode = (): AnyNodeDefinition | null => {\n let poppedNode: AnyNodeDefinition | null = null;\n\n // Get the current tree stack that we are populating.\n const topTreeStack = treeStacks[treeStacks.length - 1];\n\n // Pop the top-most node in the current tree stack if there is one.\n if (topTreeStack.length) {\n poppedNode = topTreeStack.pop() as AnyNodeDefinition;\n }\n\n // We don't want any empty tree stacks in our stack of tree stacks.\n if (!topTreeStack.length) {\n treeStacks.pop();\n }\n\n return poppedNode;\n };\n\n // We should keep processing the raw tokens until we run out of them.\n while (tokens.length) {\n // Grab the next token.\n const token = tokens.shift()!;\n\n // How we create the next node depends on the current raw token value.\n switch (token.toUpperCase()) {\n case \"ROOT\": {\n pushNode(createRootNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"SUCCEED\": {\n pushNode(createSucceedNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"FAIL\": {\n pushNode(createFailNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"FLIP\": {\n pushNode(createFlipNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"REPEAT\": {\n pushNode(createRepeatNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"RETRY\": {\n pushNode(createRetryNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"SEQUENCE\": {\n pushNode(createSequenceNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"SELECTOR\": {\n pushNode(createSelectorNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"PARALLEL\": {\n pushNode(createParallelNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"LOTTO\": {\n pushNode(createLottoNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"ACTION\": {\n pushNode(createActionNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"CONDITION\": {\n pushNode(createConditionNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"WAIT\": {\n pushNode(createWaitNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"BRANCH\": {\n pushNode(createBranchNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"}\": {\n // The '}' character closes the current scope and means that we have to pop a node off of the current stack.\n const poppedNode = popNode();\n\n // Now that we have a node definition we can carry out any validation that may require the node to be fully populated.\n if (poppedNode) {\n validatePoppedNode(poppedNode);\n }\n\n break;\n }\n\n default: {\n throw new Error(`unexpected token: ${token}`);\n }\n }\n }\n\n return rootNodes as RootNodeDefinition[];\n}\n\n/**\n * Creates a root node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The root node JSON definition.\n */\nfunction createRootNode(tokens: string[], stringLiteralPlaceholders: StringLiteralPlaceholders): RootNodeDefinition {\n // Create the root node definition.\n let node = {\n type: \"root\"\n } as Partial;\n\n // Parse any node arguments, we should only have one if any which will be an identifier argument for the root identifier.\n const nodeArguments = parseArgumentTokens(tokens, stringLiteralPlaceholders);\n\n // Check whether any node arguments were defined.\n if (nodeArguments.length) {\n // We should only have one argument, if any, which will be an identifier argument for the root identifier.\n if (nodeArguments.length === 1 && nodeArguments[0].type === \"identifier\") {\n // The root node identifier will be the first and only node argument value.\n node.id = nodeArguments[0].value as string;\n } else {\n throw new Error(\"expected single root name argument\");\n }\n }\n\n // Grab any node attribute definitions and spread them into the node definition.\n node = { ...node, ...parseAttributeTokens(tokens, stringLiteralPlaceholders) };\n\n // This is a decorator node, so we expect an opening '{'.\n popAndCheck(tokens, \"{\");\n\n // Return the root node definition.\n return node as RootNodeDefinition;\n}\n\n/**\n * Creates a succeed node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The succeed node JSON definition.\n */\nfunction createSucceedNode(\n tokens: string[],\n stringLiteralPlaceholders: StringLiteralPlaceholders\n): SucceedNodeDefinition {\n const node = {\n type: \"succeed\",\n ...parseAttributeTokens(tokens, stringLiteralPlaceholders)\n } as SucceedNodeDefinition;\n\n // This is a decorator node, so we expect an opening '{'.\n popAndCheck(tokens, \"{\");\n\n // Return the succeed node definition.\n return node;\n}\n\n/**\n * Creates a fail node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The fail node JSON definition.\n */\nfunction createFailNode(tokens: string[], stringLiteralPlaceholders: StringLiteralPlaceholders): FailNodeDefinition {\n const node = {\n type: \"fail\",\n ...parseAttributeTokens(tokens, stringLiteralPlaceholders)\n } as FailNodeDefinition;\n\n // This is a decorator node, so we expect an opening '{'.\n popAndCheck(tokens, \"{\");\n\n // Return the fail node definition.\n return node;\n}\n\n/**\n * Creates a flip node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The flip node JSON definition.\n */\nfunction createFlipNode(tokens: string[], stringLiteralPlaceholders: StringLiteralPlaceholders): FlipNodeDefinition {\n const node = {\n type: \"flip\",\n ...parseAttributeTokens(tokens, stringLiteralPlaceholders)\n } as FlipNodeDefinition;\n\n // This is a decorator node, so we expect an opening '{'.\n popAndCheck(tokens, \"{\");\n\n // Return the flip node definition.\n return node;\n}\n\n/**\n * Creates a repeat node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The repeat node JSON definition.\n */\nfunction createRepeatNode(\n tokens: string[],\n stringLiteralPlaceholders: StringLiteralPlaceholders\n): RepeatNodeDefinition {\n let node = { type: \"repeat\" } as RepeatNodeDefinition;\n\n // Get the node arguments.\n const nodeArguments = parseArgumentTokens(tokens, stringLiteralPlaceholders);\n\n // The arguments of a repeat node are optional. We may have:\n // - No node arguments, in which case the repeat note will iterate indefinitely.\n // - One node argument which will be the explicit number of iterations to make.\n // - Two node arguments which define the min and max iteration bounds from which a random iteration count will be picked.\n if (nodeArguments.length) {\n // All repeat node arguments MUST be of type number and must be integer.\n nodeArguments\n .filter((arg) => arg.type !== \"number\" || !arg.isInteger)\n .forEach(() => {\n throw new Error(`repeat node iteration counts must be integer values`);\n });\n\n // We should have got one or two iteration counts.\n if (nodeArguments.length === 1) {\n // A static iteration count was defined.\n node.iterations = nodeArguments[0].value as number;\n\n // A repeat node must have a positive number of iterations if defined.\n if (node.iterations < 0) {\n throw new Error(\"a repeat node must have a positive number of iterations if defined\");\n }\n } else if (nodeArguments.length === 2) {\n // A minimum and maximum iteration count was defined.\n node.iterations = [nodeArguments[0].value as number, nodeArguments[1].value as number];\n\n // A repeat node must have a positive min and max iteration count if they are defined.\n if (node.iterations[0] < 0 || node.iterations[1] < 0) {\n throw new Error(\"a repeat node must have a positive minimum and maximum iteration count if defined\");\n }\n\n // A repeat node must not have an minimum iteration count that exceeds the maximum iteration count.\n if (node.iterations[0] > node.iterations[1]) {\n throw new Error(\n \"a repeat node must not have a minimum iteration count that exceeds the maximum iteration count\"\n );\n }\n } else {\n // An incorrect number of iteration counts was defined.\n throw new Error(\"invalid number of repeat node iteration count arguments defined\");\n }\n }\n\n // Grab any node attribute definitions and spread them into the node definition.\n node = { ...node, ...parseAttributeTokens(tokens, stringLiteralPlaceholders) };\n\n // This is a decorator node, so we expect an opening '{'.\n popAndCheck(tokens, \"{\");\n\n // Return the repeat node definition.\n return node;\n}\n\n/**\n * Creates a retry node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The retry node JSON definition.\n */\nfunction createRetryNode(tokens: string[], stringLiteralPlaceholders: StringLiteralPlaceholders): RetryNodeDefinition {\n let node = { type: \"retry\" } as RetryNodeDefinition;\n\n // Get the node arguments.\n const nodeArguments = parseArgumentTokens(tokens, stringLiteralPlaceholders);\n\n // The arguments of a retry node are optional. We may have:\n // - No node arguments, in which case the retry note will attempt indefinitely.\n // - One node argument which will be the explicit number of attempts to make.\n // - Two node arguments which define the min and max attempt bounds from which a random attempt count will be picked.\n if (nodeArguments.length) {\n // All retry node arguments MUST be of type number and must be integer.\n nodeArguments\n .filter((arg) => arg.type !== \"number\" || !arg.isInteger)\n .forEach(() => {\n throw new Error(`retry node attempt counts must be integer values`);\n });\n\n // We should have got one or two attempt counts.\n if (nodeArguments.length === 1) {\n // A static attempt count was defined.\n node.attempts = nodeArguments[0].value as number;\n\n // A retry node must have a positive number of attempts if defined.\n if (node.attempts < 0) {\n throw new Error(\"a retry node must have a positive number of attempts if defined\");\n }\n } else if (nodeArguments.length === 2) {\n // A minimum and maximum attempt count was defined.\n node.attempts = [nodeArguments[0].value as number, nodeArguments[1].value as number];\n\n // A retry node must have a positive min and max attempts count if they are defined.\n if (node.attempts[0] < 0 || node.attempts[1] < 0) {\n throw new Error(\"a retry node must have a positive minimum and maximum attempt count if defined\");\n }\n\n // A retry node must not have a minimum attempt count that exceeds the maximum attempt count.\n if (node.attempts[0] > node.attempts[1]) {\n throw new Error(\n \"a retry node must not have a minimum attempt count that exceeds the maximum attempt count\"\n );\n }\n } else {\n // An incorrect number of attempt counts was defined.\n throw new Error(\"invalid number of retry node attempt count arguments defined\");\n }\n }\n\n // Grab any node attribute definitions and spread them into the node definition.\n node = { ...node, ...parseAttributeTokens(tokens, stringLiteralPlaceholders) };\n\n // This is a decorator node, so we expect an opening '{'.\n popAndCheck(tokens, \"{\");\n\n // Return the retry node definition.\n return node;\n}\n\n/**\n * Creates a sequence node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The sequence node JSON definition.\n */\nfunction createSequenceNode(\n tokens: string[],\n stringLiteralPlaceholders: StringLiteralPlaceholders\n): SequenceNodeDefinition {\n const node = {\n type: \"sequence\",\n ...parseAttributeTokens(tokens, stringLiteralPlaceholders)\n } as SequenceNodeDefinition;\n\n // This is a composite node, so we expect an opening '{'.\n popAndCheck(tokens, \"{\");\n\n // Return the sequence node definition.\n return node;\n}\n\n/**\n * Creates a selector node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The selector node JSON definition.\n */\nfunction createSelectorNode(\n tokens: string[],\n stringLiteralPlaceholders: StringLiteralPlaceholders\n): SelectorNodeDefinition {\n const node = {\n type: \"selector\",\n ...parseAttributeTokens(tokens, stringLiteralPlaceholders)\n } as SelectorNodeDefinition;\n\n // This is a composite node, so we expect an opening '{'.\n popAndCheck(tokens, \"{\");\n\n // Return the selector node definition.\n return node;\n}\n\n/**\n * Creates a parallel node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The parallel node JSON definition.\n */\nfunction createParallelNode(\n tokens: string[],\n stringLiteralPlaceholders: StringLiteralPlaceholders\n): ParallelNodeDefinition {\n const node = {\n type: \"parallel\",\n ...parseAttributeTokens(tokens, stringLiteralPlaceholders)\n } as ParallelNodeDefinition;\n\n // This is a composite node, so we expect an opening '{'.\n popAndCheck(tokens, \"{\");\n\n // Return the parallel node definition.\n return node;\n}\n\n/**\n * Creates a lotto node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The lotto node JSON definition.\n */\nfunction createLottoNode(tokens: string[], stringLiteralPlaceholders: StringLiteralPlaceholders): LottoNodeDefinition {\n // If any node arguments have been defined then they must be our weights.\n const nodeArguments = parseArgumentTokens(tokens, stringLiteralPlaceholders);\n\n // All lotto node arguments MUST be of type number and must be positive integers.\n nodeArguments\n .filter((arg) => arg.type !== \"number\" || !arg.isInteger || arg.value < 0)\n .forEach(() => {\n throw new Error(`lotto node weight arguments must be positive integer values`);\n });\n\n const node = {\n type: \"lotto\",\n ...parseAttributeTokens(tokens, stringLiteralPlaceholders)\n } as LottoNodeDefinition;\n\n // Apply the weights if any were defined.\n if (nodeArguments.length) {\n node.weights = nodeArguments.map(({ value }) => value) as number[];\n }\n\n // This is a composite node, so we expect an opening '{'.\n popAndCheck(tokens, \"{\");\n\n // Return the lotto node definition.\n return node;\n}\n\n/**\n * Creates an action node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The action node JSON definition.\n */\nfunction createActionNode(\n tokens: string[],\n stringLiteralPlaceholders: StringLiteralPlaceholders\n): ActionNodeDefinition {\n // Parse any node arguments, we should have at least one which will be an identifier argument for the action name\n // and agent function to invoke for the action, all other arguments are to be passed as arguments to that function.\n const [actionNameIdentifier, ...agentFunctionArgs] = parseArgumentTokens(tokens, stringLiteralPlaceholders);\n\n // Our first argument MUST be defined and be an identifier as we require an action name argument.\n if (actionNameIdentifier?.type !== \"identifier\") {\n throw new Error(\"expected action name identifier argument\");\n }\n\n // Only the first argument should have been an identifier, all agent function arguments must be string, number, boolean or null.\n agentFunctionArgs\n .filter((arg) => arg.type === \"identifier\")\n .forEach((arg) => {\n throw new Error(\n `invalid action node argument value '${arg.value}', must be string, number, boolean or null`\n );\n });\n\n // Return the action node definition.\n return {\n type: \"action\",\n call: actionNameIdentifier.value,\n args: agentFunctionArgs.map(({ value }) => value),\n ...parseAttributeTokens(tokens, stringLiteralPlaceholders)\n };\n}\n\n/**\n * Creates a condition node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The condition node JSON definition.\n */\nfunction createConditionNode(\n tokens: string[],\n stringLiteralPlaceholders: StringLiteralPlaceholders\n): ConditionNodeDefinition {\n // Parse any node arguments, we should have at least one which will be an identifier argument for the condition name\n // and agent function to invoke for the condition, all other arguments are to be passed as arguments to that function.\n const [conditionNameIdentifier, ...agentFunctionArgs] = parseArgumentTokens(tokens, stringLiteralPlaceholders);\n\n // Our first argument MUST be defined and be an identifier as we require a condition name argument.\n if (conditionNameIdentifier?.type !== \"identifier\") {\n throw new Error(\"expected condition name identifier argument\");\n }\n\n // Only the first argument should have been an identifier, all agent function arguments must be string, number, boolean or null.\n agentFunctionArgs\n .filter((arg) => arg.type === \"identifier\")\n .forEach((arg) => {\n throw new Error(\n `invalid condition node argument value '${arg.value}', must be string, number, boolean or null`\n );\n });\n\n // Return the condition node definition.\n return {\n type: \"condition\",\n call: conditionNameIdentifier.value,\n args: agentFunctionArgs.map(({ value }) => value),\n ...parseAttributeTokens(tokens, stringLiteralPlaceholders)\n };\n}\n\n/**\n * Creates a wait node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The wait node JSON definition.\n */\nfunction createWaitNode(tokens: string[], stringLiteralPlaceholders: StringLiteralPlaceholders): WaitNodeDefinition {\n let node = { type: \"wait\" } as WaitNodeDefinition;\n\n // Get the node arguments.\n const nodeArguments = parseArgumentTokens(tokens, stringLiteralPlaceholders);\n\n // The arguments of a wait node are optional. We may have:\n // - No node arguments, in which case the wait will be indefinite until it is aborted.\n // - One node argument which will be the explicit duration of the wait.\n // - Two node arguments which define the min and max duration bounds from which a random duration will be picked.\n if (nodeArguments.length) {\n // All wait node arguments MUST be of type number and must be integer.\n nodeArguments\n .filter((arg) => arg.type !== \"number\" || !arg.isInteger)\n .forEach(() => {\n throw new Error(`wait node durations must be integer values`);\n });\n\n // We may have:\n // - One node argument which will be the explicit duration of the wait.\n // - Two node arguments which define the min and max duration bounds from which a random duration will be picked.\n // - Too many arguments, which is not valid.\n if (nodeArguments.length === 1) {\n // An explicit duration was defined.\n node.duration = nodeArguments[0].value as number;\n\n // If an explict duration was defined then it must be a positive number.\n if (node.duration < 0) {\n throw new Error(\"a wait node must have a positive duration\");\n }\n } else if (nodeArguments.length === 2) {\n // Min and max duration bounds were defined from which a random duration will be picked.\n node.duration = [nodeArguments[0].value as number, nodeArguments[1].value as number];\n\n // A wait node must have a positive min and max duration.\n if (node.duration[0] < 0 || node.duration[1] < 0) {\n throw new Error(\"a wait node must have a positive minimum and maximum duration\");\n }\n\n // A wait node must not have a minimum duration that exceeds the maximum duration.\n if (node.duration[0] > node.duration[1]) {\n throw new Error(\"a wait node must not have a minimum duration that exceeds the maximum duration\");\n }\n } else if (nodeArguments.length > 2) {\n // An incorrect number of duration arguments were defined.\n throw new Error(\"invalid number of wait node duration arguments defined\");\n }\n }\n\n // Return the wait node definition.\n return { ...node, ...parseAttributeTokens(tokens, stringLiteralPlaceholders) };\n}\n\n/**\n * Creates a branch node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The branch node JSON definition.\n */\nfunction createBranchNode(\n tokens: string[],\n stringLiteralPlaceholders: StringLiteralPlaceholders\n): BranchNodeDefinition {\n // Parse any node arguments, we should have one which will be an identifier argument for the root ref.\n const nodeArguments = parseArgumentTokens(tokens, stringLiteralPlaceholders);\n\n // We should have only a single identifer argument for a branch node, which is the root ref.\n if (nodeArguments.length !== 1 || nodeArguments[0].type !== \"identifier\") {\n throw new Error(\"expected single branch name argument\");\n }\n\n // Return the branch node definition.\n return { type: \"branch\", ref: nodeArguments[0].value };\n}\n\n/**\n * Validate a fully-populated node definition that was popped off of the tree stack.\n * @param definition The popped node to validate.\n */\nfunction validatePoppedNode(definition: AnyNodeDefinition): void {\n // Decorators MUST have a child defined.\n if (isDecoratorNode(definition) && isNullOrUndefined(definition.child)) {\n throw new Error(`a ${definition.type} node must have a single child node defined`);\n }\n\n // Composites MUST have at least one child defined.\n if (isCompositeNode(definition) && !definition.children?.length) {\n throw new Error(`a ${definition.type} node must have at least a single child node defined`);\n }\n\n // We need to make sure that lotto nodes that have weights defined have a number of weights matching the number of child nodes.\n if (definition.type === \"lotto\") {\n // Check whether a 'weights' property has been defined, if it has we expect it to be an array of weights.\n if (typeof definition.weights !== \"undefined\") {\n // Check that the weights property is an array of positive integers with an element for each child node element.\n if (definition.weights.length !== definition.children.length) {\n throw new Error(\n \"expected a number of weight arguments matching the number of child nodes for lotto node\"\n );\n }\n }\n }\n}\n", "import { RootNodeDefinition } from \"./BehaviourTreeDefinition\";\nimport { flattenDefinition, isBranchNode, isInteger } from \"./BehaviourTreeDefinitionUtilities\";\nimport { convertMDSLToJSON } from \"./mdsl/MDSLDefinitionParser\";\n\n/**\n * An object representing the result of validating a tree definition.\n */\nexport type DefinitionValidationResult = {\n /**\n * A flag defining whether validation succeeded.\n */\n succeeded: boolean;\n /**\n * A string containing the error message if validation did not succeed.\n */\n errorMessage?: string;\n /**\n * The definition as json if the validation was successful, or undefined if validation did not succeed.\n */\n json?: RootNodeDefinition[];\n};\n\n/**\n * Validates the specified behaviour tree definition in the form of JSON or MDSL, not taking any globally registered subtrees into consideration.\n * @param definition The behaviour tree definition in the form of JSON or MDSL.\n * @returns An object representing the result of validating the given tree definition.\n */\nexport function validateDefinition(definition: any): DefinitionValidationResult {\n // The definition must be defined.\n if (definition === null || typeof definition === \"undefined\") {\n return createValidationFailureResult(\"definition is null or undefined\");\n }\n\n // We are expecting a definition in one of three different forms:\n // - A string which we will assume is MDSL and we will parse this to JSON before validation.\n // - An array which we will assume is an array of root node definitions with at least one being the primary root node (no 'id' property)\n // - An object which we will assume is the primary root node and should not have an 'id' property.\n if (typeof definition === \"string\") {\n // The definition is a string which we can assume is MDSL, so attempt to validate it.\n return validateMDSLDefinition(definition);\n } else if (typeof definition === \"object\") {\n // The definition will either be an array (of root node definitions) or an object (the single primary root node definition).\n return validateJSONDefinition(definition);\n } else {\n return createValidationFailureResult(`unexpected definition type of '${typeof definition}'`);\n }\n}\n\n/**\n * Validates the specified behaviour tree definition in the form of MDSL.\n * @param definition The behaviour tree definition in the form of MDSL.\n * @returns An object representing the result of validating the given tree definition.\n */\nfunction validateMDSLDefinition(definition: string): DefinitionValidationResult {\n let rootNodeDefinitions;\n\n // The first thing the we need to do is to attempt to convert our MDSL into JSON.\n try {\n // The definition is a string which we can assume is MDSL, so attempt to parse it to a JSON definition in the form of an array of root node definitions.\n rootNodeDefinitions = convertMDSLToJSON(definition);\n } catch (exception) {\n // We failed to parse the JSON from the MDSL, this is likely to be the result of it not being a valid MDSL string.\n return createValidationFailureResult((exception as Error).message);\n }\n\n // Unpack all of the root node definitions into arrays of main ('id' defined) and sub ('id' not defined) root node definitions.\n const mainRootNodeDefinitions = rootNodeDefinitions.filter(({ id }) => typeof id === \"undefined\");\n const subRootNodeDefinitions = rootNodeDefinitions.filter(({ id }) => typeof id === \"string\" && id.length > 0);\n\n // We should ALWAYS have exactly one root node definition without an 'id' property defined, which is out main root node definition.\n if (mainRootNodeDefinitions.length !== 1) {\n return createValidationFailureResult(\n \"expected single unnamed root node at base of definition to act as main root\"\n );\n }\n\n // We should never have duplicate 'id' properties across our sub root node definitions.\n const subRootNodeIdenitifers: string[] = [];\n for (const { id } of subRootNodeDefinitions) {\n // Have we already come across this 'id' property value?\n if (subRootNodeIdenitifers.includes(id!)) {\n return createValidationFailureResult(`multiple root nodes found with duplicate name '${id}'`);\n }\n\n subRootNodeIdenitifers.push(id!);\n }\n\n try {\n // Validate our branch -> subtree links and check for any circular dependencies, we don't care about checking for broken subtree links here.\n validateBranchSubtreeLinks(rootNodeDefinitions, false);\n } catch (exception) {\n return createValidationFailureResult((exception as Error).message);\n }\n\n // Our definition was valid!\n return {\n succeeded: true,\n json: rootNodeDefinitions\n };\n}\n\n/**\n * Validates the specified behaviour tree definition in the form of JSON.\n * @param definition The behaviour tree definition in the form of JSON.\n * @returns An object representing the result of validating the given tree definition.\n */\nexport function validateJSONDefinition(\n definition: RootNodeDefinition | RootNodeDefinition[]\n): DefinitionValidationResult {\n // The definition will either be an array (of root node definitions) or an object (the single primary root node definition).\n const rootNodeDefinitions = Array.isArray(definition) ? definition : [definition];\n\n // Iterate over our array of root nodes and call validateNode for each, passing an initial depth of 0, wrapped in a try catch to handle validation failures.\n try {\n rootNodeDefinitions.forEach((rootNodeDefinition) => validateNode(rootNodeDefinition, 0));\n } catch (error) {\n // Handle cases where we have caught a thrown Error and return a failure result with the error message.\n if (error instanceof Error) {\n return createValidationFailureResult(error.message);\n }\n\n // No idea what happened here!\n return createValidationFailureResult(`unexpected error: ${error}`);\n }\n\n // Unpack all of the root node definitions into arrays of main ('id' defined) and sub ('id' not defined) root node definitions.\n const mainRootNodeDefinitions = rootNodeDefinitions.filter(({ id }) => typeof id === \"undefined\");\n const subRootNodeDefinitions = rootNodeDefinitions.filter(({ id }) => typeof id === \"string\" && id.length > 0);\n\n // We should ALWAYS have exactly one root node definition without an 'id' property defined, which is out main root node definition.\n if (mainRootNodeDefinitions.length !== 1) {\n return createValidationFailureResult(\n \"expected single root node without 'id' property defined to act as main root\"\n );\n }\n\n // We should never have duplicate 'id' properties across our sub root node definitions.\n const subRootNodeIdenitifers: string[] = [];\n for (const { id } of subRootNodeDefinitions) {\n // Have we already come across this 'id' property value?\n if (subRootNodeIdenitifers.includes(id!)) {\n return createValidationFailureResult(\n `multiple root nodes found with duplicate 'id' property value of '${id}'`\n );\n }\n\n subRootNodeIdenitifers.push(id!);\n }\n\n try {\n // Validate our branch -> subtree links and check for any circular dependencies, we don't care about checking for broken subtree links here.\n validateBranchSubtreeLinks(rootNodeDefinitions, false);\n } catch (exception) {\n return createValidationFailureResult((exception as Error).message);\n }\n\n // Our definition was valid!\n return {\n succeeded: true,\n json: rootNodeDefinitions\n };\n}\n\n/**\n * Validates the branch -> subtree links across all provided root node definitions.\n * This will not consider branch nodes that reference any globally registered subtrees unless includesGlobalSubtrees\n * is set to true, in which case we will also verify that there are no broken branch -> subtree links.\n * @param rootNodeDefinitions The array of root node definitions.\n * @param includesGlobalSubtrees A flag defining whether the array includes all global subtree root node definitions.\n */\nexport function validateBranchSubtreeLinks(rootNodeDefinitions: RootNodeDefinition[], includesGlobalSubtrees: boolean) {\n // Create a mapping of root node identifiers to other root nodes that they reference via branch nodes.\n // Below is an example of a mapping that includes a circular dependency (root => a => b => c => a)\n // [{ refs: [\"a\", \"b\"] }, { id: \"a\", refs: [\"b\"] }, { id: \"b\", refs: [\"c\"] }, { id: \"c\", refs: [\"a\"] }]\n const rootNodeMappings: { id: string | undefined; refs: string[] }[] = rootNodeDefinitions.map(\n (rootNodeDefinition) => ({\n id: rootNodeDefinition.id,\n refs: flattenDefinition(rootNodeDefinition)\n .filter(isBranchNode)\n .map(({ ref }) => ref)\n })\n );\n\n // A recursive function to walk through the mappings, keeping track of which root nodes we have visited in the form of a path of root node identifiers.\n const followRefs = (mapping: { id: string | undefined; refs: string[] }, path: (string | undefined)[] = []) => {\n // Have we found a circular dependency?\n if (path.includes(mapping.id)) {\n // We found a circular dependency! Get the bad path of root node identifiers.\n const badPath = [...path, mapping.id];\n\n // Create the formatted path value. [undefined, \"a\", \"b\", \"c\", \"a\"] would be formatted as \"a -> b -> c -> a\".\n const badPathFormatted = badPath.filter((element) => !!element).join(\" => \");\n\n // No need to continue, we found a circular dependency.\n throw new Error(`circular dependency found in branch node references: ${badPathFormatted}`);\n }\n\n for (const ref of mapping.refs) {\n // Find the mapping for the root node with an identifer matching the current ref.\n const subMapping = rootNodeMappings.find(({ id }) => id === ref);\n\n // We may not have a mapping for this ref, which is normal when we aren't considering all globally registered subtrees.\n if (subMapping) {\n followRefs(subMapping, [...path, mapping.id]);\n } else if (includesGlobalSubtrees) {\n // We found a reference to a root node that doesn't exist, which is a problem seeing as the root node definitons includes all globally registered subtrees.\n throw new Error(\n mapping.id\n ? `subtree '${mapping.id}' has branch node that references root node '${ref}' which has not been defined`\n : `primary tree has branch node that references root node '${ref}' which has not been defined`\n );\n }\n }\n };\n\n // Start looking for circular dependencies and broken references from the primary root node definition.\n followRefs(rootNodeMappings.find((mapping) => typeof mapping.id === \"undefined\")!);\n}\n\n/**\n * Validate an object that we expect to be a node definition.\n * @param definition An object that we expect to be a node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateNode(definition: any, depth: number): void {\n // Every node must be valid object and have a non-empty 'type' string property.\n if (typeof definition !== \"object\" || typeof definition.type !== \"string\" || definition.type.length === 0) {\n throw new Error(\n `node definition is not an object or 'type' property is not a non-empty string at depth '${depth}'`\n );\n }\n\n // How we validate this node definition will depend on its type.\n switch (definition.type) {\n case \"action\":\n validateActionNode(definition, depth);\n break;\n\n case \"condition\":\n validateConditionNode(definition, depth);\n break;\n\n case \"wait\":\n validateWaitNode(definition, depth);\n break;\n\n case \"branch\":\n validateBranchNode(definition, depth);\n break;\n\n case \"root\":\n validateRootNode(definition, depth);\n break;\n\n case \"succeed\":\n validateSucceedNode(definition, depth);\n break;\n\n case \"fail\":\n validateFailNode(definition, depth);\n break;\n\n case \"flip\":\n validateFlipNode(definition, depth);\n break;\n\n case \"repeat\":\n validateRepeatNode(definition, depth);\n break;\n\n case \"retry\":\n validateRetryNode(definition, depth);\n break;\n\n case \"sequence\":\n validateSequenceNode(definition, depth);\n break;\n\n case \"selector\":\n validateSelectorNode(definition, depth);\n break;\n\n case \"parallel\":\n validateParallelNode(definition, depth);\n break;\n\n case \"lotto\":\n validateLottoNode(definition, depth);\n break;\n\n default:\n throw new Error(`unexpected node type of '${definition.type}' at depth '${depth}'`);\n }\n}\n\n/**\n * Validate any attributes for a given node definition.\n * @param definition The node definition.\n * @param depth The depth of the node in the behaviour tree definition.\n */\nfunction validateNodeAttributes(definition: any, depth: number): void {\n // Validate each of the attribute types for this node.\n [\"while\", \"until\", \"entry\", \"exit\", \"step\"].forEach((attributeName) => {\n // Attempt to grab the definition for the current attribute from the node definition.\n const attributeDefinition = definition[attributeName];\n\n // All node attributes are optional, so there is nothing to do if the current attribute is not defined.\n if (typeof attributeDefinition === \"undefined\") {\n return;\n }\n\n // The attribute definition must be an object.\n if (typeof attributeDefinition !== \"object\") {\n throw new Error(\n `expected attribute '${attributeName}' to be an object for '${definition.type}' node at depth '${depth}'`\n );\n }\n\n // The 'call' property must be defined for any attribute definition.\n if (typeof attributeDefinition.call !== \"string\" || attributeDefinition.call.length === 0) {\n throw new Error(\n `expected 'call' property for attribute '${attributeName}' to be a non-empty string for '${definition.type}' node at depth '${depth}'`\n );\n }\n\n // If any node attribute arguments have been defined then they must have been defined in an array.\n if (typeof attributeDefinition.args !== \"undefined\" && !Array.isArray(attributeDefinition.args)) {\n throw new Error(\n `expected 'args' property for attribute '${attributeName}' to be an array for '${definition.type}' node at depth '${depth}'`\n );\n }\n });\n}\n\n/**\n * Validate an object that we expect to be a root node definition.\n * @param definition An object that we expect to be a root node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateRootNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"root\") {\n throw new Error(\"expected node type of 'root' for root node\");\n }\n\n // A root node cannot be the child of another node.\n if (depth > 0) {\n throw new Error(\"a root node cannot be the child of another node\");\n }\n\n // Check that, if the root node 'id' property is defined, it is a non-empty string.\n if (typeof definition.id !== \"undefined\" && (typeof definition.id !== \"string\" || definition.id.length === 0)) {\n throw new Error(\"expected non-empty string for 'id' property if defined for root node\");\n }\n\n // A root node is a decorator node, so must have a child node defined.\n if (typeof definition.child === \"undefined\") {\n throw new Error(\"expected property 'child' to be defined for root node\");\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n\n // Validate the child node of this decorator node.\n validateNode(definition.child, depth + 1);\n}\n\n/**\n * Validate an object that we expect to be a succeed node definition.\n * @param definition An object that we expect to be a succeed node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateSucceedNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"succeed\") {\n throw new Error(`expected node type of 'succeed' for succeed node at depth '${depth}'`);\n }\n\n // A succeed node is a decorator node, so must have a child node defined.\n if (typeof definition.child === \"undefined\") {\n throw new Error(`expected property 'child' to be defined for succeed node at depth '${depth}'`);\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n\n // Validate the child node of this decorator node.\n validateNode(definition.child, depth + 1);\n}\n\n/**\n * Validate an object that we expect to be a fail node definition.\n * @param definition An object that we expect to be a fail node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateFailNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"fail\") {\n throw new Error(`expected node type of 'fail' for fail node at depth '${depth}'`);\n }\n\n // A fail node is a decorator node, so must have a child node defined.\n if (typeof definition.child === \"undefined\") {\n throw new Error(`expected property 'child' to be defined for fail node at depth '${depth}'`);\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n\n // Validate the child node of this decorator node.\n validateNode(definition.child, depth + 1);\n}\n\n/**\n * Validate an object that we expect to be a flip node definition.\n * @param definition An object that we expect to be a flip node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateFlipNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"flip\") {\n throw new Error(`expected node type of 'flip' for flip node at depth '${depth}'`);\n }\n\n // A flip node is a decorator node, so must have a child node defined.\n if (typeof definition.child === \"undefined\") {\n throw new Error(`expected property 'child' to be defined for flip node at depth '${depth}'`);\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n\n // Validate the child node of this decorator node.\n validateNode(definition.child, depth + 1);\n}\n\n/**\n * Validate an object that we expect to be a repeat node definition.\n * @param definition An object that we expect to be a repeat node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateRepeatNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"repeat\") {\n throw new Error(`expected node type of 'repeat' for repeat node at depth '${depth}'`);\n }\n\n // A repeat node is a decorator node, so must have a child node defined.\n if (typeof definition.child === \"undefined\") {\n throw new Error(`expected property 'child' to be defined for repeat node at depth '${depth}'`);\n }\n\n // Check whether an 'iterations' property has been defined, it may not have been if this node is to repeat indefinitely.\n if (typeof definition.iterations !== \"undefined\") {\n if (Array.isArray(definition.iterations)) {\n // Check whether any elements of the array are not integer values.\n const containsNonInteger = !!definition.iterations.filter((value: unknown) => !isInteger(value)).length;\n\n // If the 'iterations' property is an array then it MUST contain two integer values.\n if (definition.iterations.length !== 2 || containsNonInteger) {\n throw new Error(\n `expected array containing two integer values for 'iterations' property if defined for repeat node at depth '${depth}'`\n );\n }\n\n // A repeat node must have a positive min and max iterations count if they are defined.\n if (definition.iterations[0] < 0 || definition.iterations[1] < 0) {\n throw new Error(\n `expected positive minimum and maximum iterations count for 'iterations' property if defined for repeat node at depth '${depth}'`\n );\n }\n\n // A repeat node must not have a minimum iterations count that exceeds the maximum iterations count.\n if (definition.iterations[0] > definition.iterations[1]) {\n throw new Error(\n `expected minimum iterations count that does not exceed the maximum iterations count for 'iterations' property if defined for repeat node at depth '${depth}'`\n );\n }\n } else if (isInteger(definition.iterations)) {\n // A repeat node must have a positive number of iterations if defined.\n if (definition.iterations < 0) {\n throw new Error(\n `expected positive iterations count for 'iterations' property if defined for repeat node at depth '${depth}'`\n );\n }\n } else {\n throw new Error(\n `expected integer value or array containing two integer values for 'iterations' property if defined for repeat node at depth '${depth}'`\n );\n }\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n\n // Validate the child node of this decorator node.\n validateNode(definition.child, depth + 1);\n}\n\n/**\n * Validate an object that we expect to be a retry node definition.\n * @param definition An object that we expect to be a retry node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateRetryNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"retry\") {\n throw new Error(`expected node type of 'retry' for retry node at depth '${depth}'`);\n }\n\n // A retry node is a decorator node, so must have a child node defined.\n if (typeof definition.child === \"undefined\") {\n throw new Error(`expected property 'child' to be defined for retry node at depth '${depth}'`);\n }\n\n // Check whether an 'attempts' property has been defined, it may not have been if this node is to retry indefinitely.\n if (typeof definition.attempts !== \"undefined\") {\n if (Array.isArray(definition.attempts)) {\n // Check whether any elements of the array are not integer values.\n const containsNonInteger = !!definition.attempts.filter((value: unknown) => !isInteger(value)).length;\n\n // If the 'attempts' property is an array then it MUST contain two integer values.\n if (definition.attempts.length !== 2 || containsNonInteger) {\n throw new Error(\n `expected array containing two integer values for 'attempts' property if defined for retry node at depth '${depth}'`\n );\n }\n\n // A retry node must have a positive min and max attempts count if they are defined.\n if (definition.attempts[0] < 0 || definition.attempts[1] < 0) {\n throw new Error(\n `expected positive minimum and maximum attempts count for 'attempts' property if defined for retry node at depth '${depth}'`\n );\n }\n\n // A retry node must not have a minimum attempts count that exceeds the maximum attempts count.\n if (definition.attempts[0] > definition.attempts[1]) {\n throw new Error(\n `expected minimum attempts count that does not exceed the maximum attempts count for 'attempts' property if defined for retry node at depth '${depth}'`\n );\n }\n } else if (isInteger(definition.attempts)) {\n // A retry node must have a positive number of attempts if defined.\n if (definition.attempts < 0) {\n throw new Error(\n `expected positive attempts count for 'attempts' property if defined for retry node at depth '${depth}'`\n );\n }\n } else {\n throw new Error(\n `expected integer value or array containing two integer values for 'attempts' property if defined for retry node at depth '${depth}'`\n );\n }\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n\n // Validate the child node of this decorator node.\n validateNode(definition.child, depth + 1);\n}\n\n/**\n * Validate an object that we expect to be a branch node definition.\n * @param definition An object that we expect to be a branch node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateBranchNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"branch\") {\n throw new Error(`expected node type of 'branch' for branch node at depth '${depth}'`);\n }\n\n // Check that the branch node 'ref' property is defined and is a non-empty string.\n if (typeof definition.ref !== \"string\" || definition.ref.length === 0) {\n throw new Error(`expected non-empty string for 'ref' property for branch node at depth '${depth}'`);\n }\n\n // It is invalid to define guard attributes for a branch node as they should be defined on the referenced root node.\n [\"while\", \"until\"].forEach((attributeName) => {\n if (typeof definition[attributeName] !== \"undefined\") {\n throw new Error(\n `guards should not be defined for branch nodes but guard '${attributeName}' was defined for branch node at depth '${depth}'`\n );\n }\n });\n\n // It is invalid to define callback attributes for a branch node as they should be defined on the referenced root node.\n [\"entry\", \"exit\", \"step\"].forEach((attributeName) => {\n if (typeof definition[attributeName] !== \"undefined\") {\n throw new Error(\n `callbacks should not be defined for branch nodes but callback '${attributeName}' was defined for branch node at depth '${depth}'`\n );\n }\n });\n}\n\n/**\n * Validate an object that we expect to be a action node definition.\n * @param definition An object that we expect to be a action node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateActionNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"action\") {\n throw new Error(`expected node type of 'action' for action node at depth '${depth}'`);\n }\n\n // The 'call' property must be defined for a action node definition.\n if (typeof definition.call !== \"string\" || definition.call.length === 0) {\n throw new Error(`expected non-empty string for 'call' property of action node at depth '${depth}'`);\n }\n\n // If any action function arguments have been defined then they must have been defined in an array.\n if (typeof definition.args !== \"undefined\" && !Array.isArray(definition.args)) {\n throw new Error(`expected array for 'args' property if defined for action node at depth '${depth}'`);\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n}\n\n/**\n * Validate an object that we expect to be a condition node definition.\n * @param definition An object that we expect to be a condition node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateConditionNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"condition\") {\n throw new Error(`expected node type of 'condition' for condition node at depth '${depth}'`);\n }\n\n // The 'call' property must be defined for a condition node definition.\n if (typeof definition.call !== \"string\" || definition.call.length === 0) {\n throw new Error(`expected non-empty string for 'call' property of condition node at depth '${depth}'`);\n }\n\n // If any condition function arguments have been defined then they must have been defined in an array.\n if (typeof definition.args !== \"undefined\" && !Array.isArray(definition.args)) {\n throw new Error(`expected array for 'args' property if defined for condition node at depth '${depth}'`);\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n}\n\n/**\n * Validate an object that we expect to be a wait node definition.\n * @param definition An object that we expect to be a wait node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateWaitNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"wait\") {\n throw new Error(`expected node type of 'wait' for wait node at depth '${depth}'`);\n }\n\n // Check whether a 'duration' property has been defined, it may not have been if this node is to wait indefinitely.\n if (typeof definition.duration !== \"undefined\") {\n if (Array.isArray(definition.duration)) {\n // Check whether any elements of the array are not integer values.\n const containsNonInteger = !!definition.duration.filter((value: unknown) => !isInteger(value)).length;\n\n // If the 'duration' property is an array then it MUST contain two integer values.\n if (definition.duration.length !== 2 || containsNonInteger) {\n throw new Error(\n `expected array containing two integer values for 'duration' property if defined for wait node at depth '${depth}'`\n );\n }\n\n // A wait node must have a positive min and max duration value if they are defined.\n if (definition.duration[0] < 0 || definition.duration[1] < 0) {\n throw new Error(\n `expected positive minimum and maximum duration for 'duration' property if defined for wait node at depth '${depth}'`\n );\n }\n\n // A wait node must not have a minimum duration value that exceeds the maximum duration value.\n if (definition.duration[0] > definition.duration[1]) {\n throw new Error(\n `expected minimum duration value that does not exceed the maximum duration value for 'duration' property if defined for wait node at depth '${depth}'`\n );\n }\n } else if (isInteger(definition.duration)) {\n // A wait node must have a positive duration value if defined.\n if (definition.duration < 0) {\n throw new Error(\n `expected positive duration value for 'duration' property if defined for wait node at depth '${depth}'`\n );\n }\n } else {\n throw new Error(\n `expected integer value or array containing two integer values for 'duration' property if defined for wait node at depth '${depth}'`\n );\n }\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n}\n\n/**\n * Validate an object that we expect to be a sequence node definition.\n * @param definition An object that we expect to be a sequence node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateSequenceNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"sequence\") {\n throw new Error(`expected node type of 'sequence' for sequence node at depth '${depth}'`);\n }\n\n // A sequence node is a composite node, so must have a children nodes array defined.\n if (!Array.isArray(definition.children) || definition.children.length === 0) {\n throw new Error(`expected non-empty 'children' array to be defined for sequence node at depth '${depth}'`);\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n\n // Validate the child nodes of this composite node.\n definition.children.forEach((child: any) => validateNode(child, depth + 1));\n}\n\n/**\n * Validate an object that we expect to be a selector node definition.\n * @param definition An object that we expect to be a selector node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateSelectorNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"selector\") {\n throw new Error(`expected node type of 'selector' for selector node at depth '${depth}'`);\n }\n\n // A selector node is a composite node, so must have a children nodes array defined.\n if (!Array.isArray(definition.children) || definition.children.length === 0) {\n throw new Error(`expected non-empty 'children' array to be defined for selector node at depth '${depth}'`);\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n\n // Validate the child nodes of this composite node.\n definition.children.forEach((child: any) => validateNode(child, depth + 1));\n}\n\n/**\n * Validate an object that we expect to be a parallel node definition.\n * @param definition An object that we expect to be a parallel node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateParallelNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"parallel\") {\n throw new Error(`expected node type of 'parallel' for parallel node at depth '${depth}'`);\n }\n\n // A parallel node is a composite node, so must have a children nodes array defined.\n if (!Array.isArray(definition.children) || definition.children.length === 0) {\n throw new Error(`expected non-empty 'children' array to be defined for parallel node at depth '${depth}'`);\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n\n // Validate the child nodes of this composite node.\n definition.children.forEach((child: any) => validateNode(child, depth + 1));\n}\n\n/**\n * Validate an object that we expect to be a lotto node definition.\n * @param definition An object that we expect to be a lotto node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateLottoNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"lotto\") {\n throw new Error(`expected node type of 'lotto' for lotto node at depth '${depth}'`);\n }\n\n // A lotto node is a composite node, so must have a children nodes array defined.\n if (!Array.isArray(definition.children) || definition.children.length === 0) {\n throw new Error(`expected non-empty 'children' array to be defined for lotto node at depth '${depth}'`);\n }\n\n // Check whether a 'weights' property has been defined, if it has we expect it to be an array of weights.\n if (typeof definition.weights !== \"undefined\") {\n // Check that the weights property is an array of positive integers with an element for each child node element.\n if (\n !Array.isArray(definition.weights) ||\n definition.weights.length !== definition.children.length ||\n definition.weights.filter((value: unknown) => !isInteger(value)).length ||\n definition.weights.filter((value: number) => value < 0).length\n ) {\n throw new Error(\n `expected an array of positive integer weight values with a length matching the number of child nodes for 'weights' property if defined for lotto node at depth '${depth}'`\n );\n }\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n\n // Validate the child nodes of this composite node.\n definition.children.forEach((child: any) => validateNode(child, depth + 1));\n}\n\n/**\n * A helper function to create a failure validation result with the given error message.\n * @param errorMessage The validation failure error message.\n * @returns A failure validation result with the given error message.\n */\nfunction createValidationFailureResult(errorMessage: string): DefinitionValidationResult {\n return { succeeded: false, errorMessage };\n}\n", "import { ActionResult, Agent, GlobalFunction } from \"./Agent\";\nimport { RootNodeDefinition } from \"./BehaviourTreeDefinition\";\n\nexport type InvokerFunction = (args: any[]) => ActionResult | boolean;\n\n/**\n * A singleton used to store and lookup registered functions and subtrees.\n */\nexport default class Lookup {\n /**\n * The object holding any registered functions keyed on function name.\n */\n private static registeredFunctions: { [key: string]: GlobalFunction } = {};\n /**\n * The object holding any registered subtree root node definitions keyed on tree name.\n */\n private static registeredSubtrees: { [key: string]: RootNodeDefinition } = {};\n\n /**\n * Gets the function with the specified name.\n * @param name The name of the function.\n * @returns The function with the specified name.\n */\n public static getFunc(name: string): GlobalFunction {\n return this.registeredFunctions[name];\n }\n\n /**\n * Sets the function with the specified name for later lookup.\n * @param name The name of the function.\n * @param func The function.\n */\n public static setFunc(name: string, func: GlobalFunction): void {\n this.registeredFunctions[name] = func;\n }\n\n /**\n * Gets the function invoker for the specified agent and function name.\n * If a function with the specified name exists on the agent object then it will\n * be returned, otherwise we will then check the registered functions for a match.\n * @param agent The agent instance that this behaviour tree is modelling behaviour for.\n * @param name The function name.\n * @returns The function invoker for the specified agent and function name.\n */\n static getFuncInvoker(agent: Agent, name: string): InvokerFunction | null {\n // Check whether the agent contains the specified function.\n const agentFunction = agent[name];\n if (agentFunction && typeof agentFunction === \"function\") {\n return (args: any[]) => agentFunction.apply(agent, args);\n }\n\n // The agent does not contain the specified function but it may have been registered at some point.\n if (this.registeredFunctions[name] && typeof this.registeredFunctions[name] === \"function\") {\n const registeredFunction = this.registeredFunctions[name];\n return (args: any[]) => registeredFunction(agent, ...args.map((arg) => arg.value));\n }\n\n // We have no function to invoke.\n return null;\n }\n\n /**\n * Gets all registered subtree root node definitions.\n */\n static getSubtrees(): { [key: string]: RootNodeDefinition } {\n return this.registeredSubtrees;\n }\n\n /**\n * Sets the subtree with the specified name for later lookup.\n * @param name The name of the subtree.\n * @param subtree The subtree.\n */\n static setSubtree(name: string, subtree: RootNodeDefinition) {\n this.registeredSubtrees[name] = subtree;\n }\n\n /**\n * Removes the registered function or subtree with the specified name.\n * @param name The name of the registered function or subtree.\n */\n static remove(name: string) {\n delete this.registeredFunctions[name];\n delete this.registeredSubtrees[name];\n }\n\n /**\n * Remove all registered functions and subtrees.\n */\n static empty() {\n this.registeredFunctions = {};\n this.registeredSubtrees = {};\n }\n}\n", "import Node from \"../../nodes/Node\";\n\n/**\n * An exception thrown when evaluating node guard path conditions and a conditions fails.\n */\nexport default class GuardUnsatisifedException extends Error {\n /**\n * @param source The node at which a guard condition failed.\n */\n constructor(private source: Node) {\n super(\"A guard path condition has failed\");\n }\n\n /**\n * Gets whether the specified node is the node at which a guard condition failed.\n * @param node The node to check against the source node.\n * @returns Whether the specified node is the node at which a guard condition failed.\n */\n isSourceNode = (node: Node) => node === this.source;\n}\n", "import { Agent } from \"../../Agent\";\nimport Guard from \"./Guard\";\nimport Node from \"../../nodes/Node\";\nimport GuardUnsatisifedException from \"./GuardUnsatisifedException\";\n\nexport type GuardPathPart = {\n node: Node;\n guards: Guard[];\n};\n\n/**\n * Represents a path of node guards along a root-to-leaf tree path.\n */\nexport default class GuardPath {\n /**\n * @param nodes An array of objects defining a node instance -> guard link, ordered by node depth.\n */\n constructor(private nodes: GuardPathPart[]) {}\n\n /**\n * Evaluate guard conditions for all guards in the tree path, moving outwards from the root.\n * @param agent The agent, required for guard evaluation.\n * @returns An evaluation results object.\n */\n evaluate = (agent: Agent) => {\n // We need to evaluate guard conditions for nodes up the tree, moving outwards from the root.\n for (const details of this.nodes) {\n // There can be multiple guards per node.\n for (const guard of details.guards) {\n // Check whether the guard condition passes, and throw an exception if not.\n if (!guard.isSatisfied(agent)) {\n throw new GuardUnsatisifedException(details.node);\n }\n }\n }\n };\n}\n", "import { BehaviourTreeOptions } from \"../BehaviourTreeOptions\";\nimport State, { AnyState } from \"../State\";\nimport { Agent } from \"../Agent\";\nimport Leaf from \"./leaf/Leaf\";\nimport Attribute from \"../attributes/Attribute\";\nimport Entry from \"../attributes/callbacks/Entry\";\nimport Exit from \"../attributes/callbacks/Exit\";\nimport Step from \"../attributes/callbacks/Step\";\nimport Guard from \"../attributes/guards/Guard\";\nimport GuardPath from \"../attributes/guards/GuardPath\";\nimport GuardUnsatisifedException from \"../attributes/guards/GuardUnsatisifedException\";\n\n/**\n * A base node.\n */\nexport default abstract class Node {\n /**\n * The node uid.\n */\n private readonly uid: string = createNodeUid();\n /**\n * The node state.\n */\n private state: AnyState = State.READY;\n /**\n * The guard path to evaluate as part of a node update.\n */\n private guardPath: GuardPath | undefined;\n\n /**\n * @param type The node type.\n * @param attributes The node attributes.\n * @param args The node argument definitions.\n */\n constructor(private type: string, private attributes: Attribute[], private args: any[]) {}\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected abstract onUpdate(agent: Agent, options: BehaviourTreeOptions): void;\n\n /**\n * Gets the name of the node.\n */\n public abstract getName(): string;\n\n /**\n * Gets whether this node is a leaf node.\n */\n public abstract isLeafNode: () => this is Leaf;\n\n /**\n * Gets/Sets the state of the node.\n */\n getState = (): AnyState => this.state;\n setState = (value: AnyState): void => {\n this.state = value;\n };\n\n /**\n * Gets the unique id of the node.\n */\n getUid = () => this.uid;\n\n /**\n * Gets the type of the node.\n */\n getType = () => this.type;\n\n /**\n * Gets the node attributes.\n */\n getAttributes = () => this.attributes;\n\n /**\n * Gets the node arguments.\n */\n getArguments = () => this.args;\n\n /**\n * Gets the node attribute with the specified type, or null if it does not exist.\n */\n getAttribute(type: \"entry\" | \"ENTRY\"): Entry;\n getAttribute(type: \"exit\" | \"EXIT\"): Exit;\n getAttribute(type: \"step\" | \"STEP\"): Step;\n getAttribute(type: string): Attribute {\n return (\n this.getAttributes().filter((decorator) => decorator.type.toUpperCase() === type.toUpperCase())[0] || null\n );\n }\n\n /**\n * Gets the node attributes.\n */\n getGuardAttributes = (): Guard[] => this.getAttributes().filter((decorator) => decorator.isGuard()) as Guard[];\n\n /**\n * Sets the guard path to evaluate as part of a node update.\n */\n setGuardPath = (value: GuardPath) => (this.guardPath = value);\n\n /**\n * Gets whether a guard path is assigned to this node.\n */\n hasGuardPath = () => !!this.guardPath;\n\n /**\n * Gets whether this node is in the specified state.\n * @param value The value to compare to the node state.\n */\n public is(value: AnyState): boolean {\n return this.state === value;\n }\n\n /**\n * Reset the state of the node.\n */\n public reset(): void {\n this.setState(State.READY);\n }\n\n /**\n * Abort the running of this node.\n * @param agent The agent.\n */\n public abort(agent: Agent): void {\n // There is nothing to do if this node is not in the running state.\n if (!this.is(State.RUNNING)) {\n return;\n }\n\n // Reset the state of this node.\n this.reset();\n\n this.getAttribute(\"exit\")?.callAgentFunction(agent, false, true);\n }\n\n /**\n * Update the node.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n * @returns The result of the update.\n */\n public update(agent: Agent, options: BehaviourTreeOptions): void {\n // If this node is already in a 'SUCCEEDED' or 'FAILED' state then there is nothing to do.\n if (this.is(State.SUCCEEDED) || this.is(State.FAILED)) {\n return;\n }\n\n try {\n // Evaluate all of the guard path conditions for the current tree path.\n this.guardPath!.evaluate(agent);\n\n // If this node is in the READY state then call the ENTRY for this node if it exists.\n if (this.is(State.READY)) {\n this.getAttribute(\"entry\")?.callAgentFunction(agent);\n }\n\n this.getAttribute(\"step\")?.callAgentFunction(agent);\n\n // Do the actual update.\n this.onUpdate(agent, options);\n\n // If this node is now in a 'SUCCEEDED' or 'FAILED' state then call the EXIT for this node if it exists.\n if (this.is(State.SUCCEEDED) || this.is(State.FAILED)) {\n this.getAttribute(\"exit\")?.callAgentFunction(agent, this.is(State.SUCCEEDED), false);\n }\n } catch (error) {\n // If the error is a GuardUnsatisfiedException then we need to determine if this node is the source.\n if (error instanceof GuardUnsatisifedException && error.isSourceNode(this)) {\n // Abort the current node.\n this.abort(agent);\n\n // Any node that is the source of an abort will be a failed node.\n this.setState(State.FAILED);\n } else {\n throw error;\n }\n }\n }\n}\n\n/**\n * Create a randomly generated node uid.\n * @returns A randomly generated node uid.\n */\nfunction createNodeUid(): string {\n var S4 = function () {\n return (((1 + Math.random()) * 0x10000) | 0).toString(16).substring(1);\n };\n return S4() + S4() + \"-\" + S4() + \"-\" + S4() + \"-\" + S4() + \"-\" + S4() + S4() + S4();\n}\n", "import Node from \"../Node\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\n\n/**\n * A composite node that wraps child nodes.\n */\nexport default abstract class Composite extends Node {\n /**\n * @param type The node type.\n * @param attributes The node attributes.\n * @param children The child nodes.\n */\n constructor(type: string, attributes: Attribute[], protected children: Node[]) {\n super(type, attributes, []);\n }\n\n /**\n * Gets whether this node is a leaf node.\n */\n isLeafNode = () => false;\n\n /**\n * Gets the children of this node.\n */\n getChildren = () => this.children;\n\n /**\n * Reset the state of the node.\n */\n reset = () => {\n // Reset the state of this node.\n this.setState(State.READY);\n\n // Reset the state of any child nodes.\n this.getChildren().forEach((child) => child.reset());\n };\n\n /**\n * Abort the running of this node.\n * @param agent The agent.\n */\n abort = (agent: Agent) => {\n // There is nothing to do if this node is not in the running state.\n if (!this.is(State.RUNNING)) {\n return;\n }\n\n // Abort any child nodes.\n this.getChildren().forEach((child) => child.abort(agent));\n\n // Reset the state of this node.\n this.reset();\n\n this.getAttribute(\"exit\")?.callAgentFunction(agent, false, true);\n };\n}\n", "import Composite from \"./Composite\";\nimport State from \"../../State\";\nimport Node from \"../Node\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A PARALLEL node.\n * The child nodes are executed concurrently until one fails or all succeed.\n */\nexport default class Parallel extends Composite {\n /**\n * @param attributes The node attributes.\n * @param children The child nodes.\n */\n constructor(attributes: Attribute[], children: Node[]) {\n super(\"parallel\", attributes, children);\n }\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // Keep a count of the number of succeeded child nodes.\n let succeededCount = 0;\n\n let hasChildFailed = false;\n\n // Iterate over all of the children of this node.\n for (const child of this.children) {\n // If the child has never been updated or is running then we will need to update it now.\n if (child.getState() === State.READY || child.getState() === State.RUNNING) {\n // Update the child of this node.\n child.update(agent, options);\n }\n\n // If the current child has a state of 'SUCCEEDED' then we should move on to the next child.\n if (child.getState() === State.SUCCEEDED) {\n // The child node has succeeded, keep track of this to determine if all children have.\n succeededCount++;\n\n // The child node succeeded, but we have not finished checking every child node yet.\n continue;\n }\n\n // If the current child has a state of 'FAILED' then this node is also a 'FAILED' node.\n if (child.getState() === State.FAILED) {\n hasChildFailed = true;\n\n // There is no need to check the rest of the children.\n break;\n }\n\n // The node should be in the 'RUNNING' state.\n if (child.getState() !== State.RUNNING) {\n // The child node was not in an expected state.\n throw new Error(\"child node was not in an expected state.\");\n }\n }\n\n if (hasChildFailed) {\n // This node is a 'FAILED' node.\n this.setState(State.FAILED);\n\n // Abort every running child.\n for (const child of this.children) {\n if (child.getState() === State.RUNNING) {\n child.abort(agent);\n }\n }\n } else {\n // If all children have succeeded then this node has also succeeded, otherwise it is still running.\n this.setState(succeededCount === this.children.length ? State.SUCCEEDED : State.RUNNING);\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => \"PARALLEL\";\n}\n", "import Composite from \"./Composite\";\nimport Node from \"../Node\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A SELECTOR node.\n * The child nodes are executed in sequence until one succeeds or all fail.\n */\nexport default class Selector extends Composite {\n /**\n * @param attributes The node attributes.\n * @param children The child nodes.\n */\n constructor(attributes: Attribute[], protected children: Node[]) {\n super(\"selector\", attributes, children);\n }\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // Iterate over all of the children of this node.\n for (const child of this.children) {\n // If the child has never been updated or is running then we will need to update it now.\n if (child.getState() === State.READY || child.getState() === State.RUNNING) {\n // Update the child of this node.\n child.update(agent, options);\n }\n\n // If the current child has a state of 'SUCCEEDED' then this node is also a 'SUCCEEDED' node.\n if (child.getState() === State.SUCCEEDED) {\n // This node is a 'SUCCEEDED' node.\n this.setState(State.SUCCEEDED);\n\n // There is no need to check the rest of the selector nodes.\n return;\n }\n\n // If the current child has a state of 'FAILED' then we should move on to the next child.\n if (child.getState() === State.FAILED) {\n // Find out if the current child is the last one in the selector.\n // If it is then this sequence node has also failed.\n if (this.children.indexOf(child) === this.children.length - 1) {\n // This node is a 'FAILED' node.\n this.setState(State.FAILED);\n\n // There is no need to check the rest of the selector as we have completed it.\n return;\n } else {\n // The child node failed, try the next one.\n continue;\n }\n }\n\n // The node should be in the 'RUNNING' state.\n if (child.getState() === State.RUNNING) {\n // This node is a 'RUNNING' node.\n this.setState(State.RUNNING);\n\n // There is no need to check the rest of the selector as the current child is still running.\n return;\n }\n\n // The child node was not in an expected state.\n throw new Error(\"child node was not in an expected state.\");\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => \"SELECTOR\";\n}\n", "import Composite from \"./Composite\";\nimport Node from \"../Node\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A SEQUENCE node.\n * The child nodes are executed in sequence until one fails or all succeed.\n */\nexport default class Sequence extends Composite {\n /**\n * @param attributes The node attributes.\n * @param children The child nodes.\n */\n constructor(attributes: Attribute[], protected children: Node[]) {\n super(\"sequence\", attributes, children);\n }\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // Iterate over all of the children of this node.\n for (const child of this.children) {\n // If the child has never been updated or is running then we will need to update it now.\n if (child.getState() === State.READY || child.getState() === State.RUNNING) {\n // Update the child of this node.\n child.update(agent, options);\n }\n\n // If the current child has a state of 'SUCCEEDED' then we should move on to the next child.\n if (child.getState() === State.SUCCEEDED) {\n // Find out if the current child is the last one in the sequence.\n // If it is then this sequence node has also succeeded.\n if (this.children.indexOf(child) === this.children.length - 1) {\n // This node is a 'SUCCEEDED' node.\n this.setState(State.SUCCEEDED);\n\n // There is no need to check the rest of the sequence as we have completed it.\n return;\n } else {\n // The child node succeeded, but we have not finished the sequence yet.\n continue;\n }\n }\n\n // If the current child has a state of 'FAILED' then this node is also a 'FAILED' node.\n if (child.getState() === State.FAILED) {\n // This node is a 'FAILED' node.\n this.setState(State.FAILED);\n\n // There is no need to check the rest of the sequence.\n return;\n }\n\n // The node should be in the 'RUNNING' state.\n if (child.getState() === State.RUNNING) {\n // This node is a 'RUNNING' node.\n this.setState(State.RUNNING);\n\n // There is no need to check the rest of the sequence as the current child is still running.\n return;\n }\n\n // The child node was not in an expected state.\n throw new Error(\"child node was not in an expected state.\");\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => \"SEQUENCE\";\n}\n", "import createLotto from \"lotto-draw\";\n\nimport Node from \"../Node\";\nimport Composite from \"./Composite\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A LOTTO node.\n * A winning child is picked on the initial update of this node, based on ticket weighting.\n * The state of this node will match the state of the winning child.\n */\nexport default class Lotto extends Composite {\n /**\n * @param attributes The node attributes.\n * @param weights The child node weights.\n * @param children The child nodes.\n */\n constructor(attributes: Attribute[], private weights: number[] | undefined, children: Node[]) {\n super(\"lotto\", attributes, children);\n }\n\n /**\n * The child node selected to be the active one.\n */\n private selectedChild: Node | undefined;\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // If this node is in the READY state then we need to pick a winning child node.\n if (this.is(State.READY)) {\n // Create a lotto draw with which to randomly pick a child node to become the active one.\n const lottoDraw = createLotto({\n // Hook up the optional 'random' behaviour tree function option to the one used by 'lotto-draw'.\n random: options.random,\n // Pass in each child node as a participant in the lotto draw with their respective ticket count.\n participants: this.children.map((child, index) => [child, this.weights?.[index] || 1])\n });\n\n // Randomly pick a child based on ticket weighting, this will become the active child for this composite node.\n this.selectedChild = lottoDraw.draw() || undefined;\n }\n\n // If something went wrong and we don't have an active child then we should throw an error.\n if (!this.selectedChild) {\n throw new Error(\"failed to update lotto node as it has no active child\");\n }\n\n // If the selected child has never been updated or is running then we will need to update it now.\n if (this.selectedChild.getState() === State.READY || this.selectedChild.getState() === State.RUNNING) {\n this.selectedChild.update(agent, options);\n }\n\n // The state of the lotto node is the state of its selected child.\n this.setState(this.selectedChild.getState());\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => (this.weights ? `LOTTO [${this.weights.join(\",\")}]` : \"LOTTO\");\n}\n", "import Node from \"../Node\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\n\n/**\n * A decorator node that wraps a single child node.\n */\nexport default abstract class Decorator extends Node {\n /**\n * @param type The node type.\n * @param attributes The node attributes.\n * @param child The child node.\n */\n constructor(type: string, attributes: Attribute[], protected child: Node) {\n super(type, attributes, []);\n }\n\n /**\n * Gets whether this node is a leaf node.\n */\n isLeafNode = () => false;\n\n /**\n * Gets the children of this node.\n */\n getChildren = () => [this.child];\n\n /**\n * Reset the state of the node.\n */\n reset = () => {\n // Reset the state of this node.\n this.setState(State.READY);\n\n // Reset the state of the child node.\n this.child.reset();\n };\n\n /**\n * Abort the running of this node.\n * @param agent The agent.\n */\n abort = (agent: Agent) => {\n // There is nothing to do if this node is not in the running state.\n if (!this.is(State.RUNNING)) {\n return;\n }\n\n // Abort the child node.\n this.child.abort(agent);\n\n // Reset the state of this node.\n this.reset();\n\n this.getAttribute(\"exit\")?.callAgentFunction(agent, false, true);\n };\n}\n", "import Node from \"../Node\";\nimport Decorator from \"./Decorator\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A Fail node.\n * This node wraps a single child and will always move to the 'FAILED' state when the child moves to a 'SUCCEEDED' or 'FAILED' state.\n */\nexport default class Fail extends Decorator {\n /**\n * @param attributes The node attributes.\n * @param child The child node.\n */\n constructor(attributes: Attribute[], child: Node) {\n super(\"fail\", attributes, child);\n }\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // If the child has never been updated or is running then we will need to update it now.\n if (this.child.getState() === State.READY || this.child.getState() === State.RUNNING) {\n this.child.update(agent, options);\n }\n\n // The state of this node will depend in the state of its child.\n switch (this.child.getState()) {\n case State.RUNNING:\n this.setState(State.RUNNING);\n break;\n\n case State.SUCCEEDED:\n case State.FAILED:\n this.setState(State.FAILED);\n break;\n\n default:\n this.setState(State.READY);\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => \"FAIL\";\n}\n", "import Decorator from \"./Decorator\";\nimport State from \"../../State\";\nimport Node from \"../Node\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A Flip node.\n * This node wraps a single child and will flip the state of the child state.\n */\nexport default class Flip extends Decorator {\n /**\n * @param attributes The node attributes.\n * @param child The child node.\n */\n constructor(attributes: Attribute[], child: Node) {\n super(\"flip\", attributes, child);\n }\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // If the child has never been updated or is running then we will need to update it now.\n if (this.child.getState() === State.READY || this.child.getState() === State.RUNNING) {\n this.child.update(agent, options);\n }\n\n // The state of this node will depend in the state of its child.\n switch (this.child.getState()) {\n case State.RUNNING:\n this.setState(State.RUNNING);\n break;\n\n case State.SUCCEEDED:\n this.setState(State.FAILED);\n break;\n\n case State.FAILED:\n this.setState(State.SUCCEEDED);\n break;\n\n default:\n this.setState(State.READY);\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => \"FLIP\";\n}\n", "import Node from \"../Node\";\nimport Decorator from \"./Decorator\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A REPEAT node.\n * The node has a single child which can have:\n * -- A number of iterations for which to repeat the child node.\n * -- An infinite repeat loop if neither an iteration count or a condition function is defined.\n * The REPEAT node will stop and have a 'FAILED' state if its child is ever in a 'FAILED' state after an update.\n * The REPEAT node will attempt to move on to the next iteration if its child is ever in a 'SUCCEEDED' state.\n */\nexport default class Repeat extends Decorator {\n /**\n * @param attributes The node attributes.\n * @param iterations The number of iterations to repeat the child node.\n * @param iterationsMin The minimum possible number of iterations to repeat the child node.\n * @param iterationsMax The maximum possible number of iterations to repeat the child node.\n * @param child The child node.\n */\n constructor(\n attributes: Attribute[],\n private iterations: number | null,\n private iterationsMin: number | null,\n private iterationsMax: number | null,\n child: Node\n ) {\n super(\"repeat\", attributes, child);\n }\n\n /**\n * The number of target iterations to make.\n */\n private targetIterationCount: number | null = null;\n\n /**\n * The current iteration count.\n */\n private currentIterationCount: number = 0;\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // If this node is in the READY state then we need to reset the child and the target iteration count.\n if (this.is(State.READY)) {\n // Reset the child node.\n this.child.reset();\n\n // Reset the current iteration count.\n this.currentIterationCount = 0;\n\n // Set the target iteration count.\n this.setTargetIterationCount(options);\n }\n\n // Do a check to see if we can iterate. If we can then this node will move into the 'RUNNING' state.\n // If we cannot iterate then we have hit our target iteration count, which means that the node has succeeded.\n if (this.canIterate()) {\n // This node is in the running state and can do its initial iteration.\n this.setState(State.RUNNING);\n\n // We may have already completed an iteration, meaning that the child node will be in the SUCCEEDED state.\n // If this is the case then we will have to reset the child node now.\n if (this.child.getState() === State.SUCCEEDED) {\n this.child.reset();\n }\n\n // Update the child of this node.\n this.child.update(agent, options);\n\n // If the child moved into the FAILED state when we updated it then there is nothing left to do and this node has also failed.\n // If it has moved into the SUCCEEDED state then we have completed the current iteration.\n if (this.child.getState() === State.FAILED) {\n // The child has failed, meaning that this node has failed.\n this.setState(State.FAILED);\n\n return;\n } else if (this.child.getState() === State.SUCCEEDED) {\n // We have completed an iteration.\n this.currentIterationCount += 1;\n }\n } else {\n // This node is in the 'SUCCEEDED' state as we cannot iterate any more.\n this.setState(State.SUCCEEDED);\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => {\n if (this.iterations !== null) {\n return `REPEAT ${this.iterations}x`;\n } else if (this.iterationsMin !== null && this.iterationsMax !== null) {\n return `REPEAT ${this.iterationsMin}x-${this.iterationsMax}x`;\n } else {\n return \"REPEAT\";\n }\n };\n\n /**\n * Reset the state of the node.\n */\n reset = () => {\n // Reset the state of this node.\n this.setState(State.READY);\n\n // Reset the current iteration count.\n this.currentIterationCount = 0;\n\n // Reset the child node.\n this.child.reset();\n };\n\n /**\n * Gets whether an iteration can be made.\n * @returns Whether an iteration can be made.\n */\n private canIterate = () => {\n if (this.targetIterationCount !== null) {\n // We can iterate as long as we have not reached our target iteration count.\n return this.currentIterationCount < this.targetIterationCount;\n }\n\n // If neither an iteration count or a condition function were defined then we can iterate indefinitely.\n return true;\n };\n\n /**\n * Sets the target iteration count.\n * @param options The behaviour tree options object.\n */\n private setTargetIterationCount = (options: BehaviourTreeOptions) => {\n // Are we dealing with an explicit iteration count or will we be randomly picking a iteration count between the min and max iteration count.\n if (this.iterations !== null) {\n this.targetIterationCount = this.iterations;\n } else if (this.iterationsMin !== null && this.iterationsMax !== null) {\n // We will be picking a random iteration count between a min and max iteration count, if the optional 'random'\n // behaviour tree function option is defined then we will be using that, otherwise we will fall back to using Math.random.\n const random = typeof options.random === \"function\" ? options.random : Math.random;\n\n // Pick a random iteration count between a min and max iteration count.\n this.targetIterationCount = Math.floor(\n random() * (this.iterationsMax - this.iterationsMin + 1) + this.iterationsMin\n );\n } else {\n this.targetIterationCount = null;\n }\n };\n}\n", "import Node from \"../Node\";\nimport Decorator from \"./Decorator\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A RETRY node.\n * The node has a single child which can have:\n * -- A number of iterations for which to repeat the child node.\n * -- An infinite repeat loop if neither an iteration count or a condition function is defined.\n * The RETRY node will stop and have a 'SUCCEEDED' state if its child is ever in a 'SUCCEEDED' state after an update.\n * The RETRY node will attempt to move on to the next iteration if its child is ever in a 'FAILED' state.\n */\nexport default class Retry extends Decorator {\n /**\n * @param attributes The node attributes.\n * @param attempts The number of attempts to retry the child node.\n * @param attemptsMin The minimum possible number of attempts to retry the child node.\n * @param attemptsMax The maximum possible number of attempts to retry the child node.\n * @param child The child node.\n */\n constructor(\n attributes: Attribute[],\n private attempts: number | null,\n private attemptsMin: number | null,\n private attemptsMax: number | null,\n child: Node\n ) {\n super(\"retry\", attributes, child);\n }\n\n /**\n * The number of target attempts to make.\n */\n private targetAttemptCount: number | null = null;\n\n /**\n * The current attempt count.\n */\n private currentAttemptCount: number = 0;\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // If this node is in the READY state then we need to reset the child and the target attempt count.\n if (this.is(State.READY)) {\n // Reset the child node.\n this.child.reset();\n\n // Reset the current attempt count.\n this.currentAttemptCount = 0;\n\n // Set the target attempt count.\n this.setTargetAttemptCount(options);\n }\n\n // Do a check to see if we can attempt. If we can then this node will move into the 'RUNNING' state.\n // If we cannot attempt then we have hit our target attempt count, which means that the node has succeeded.\n if (this.canAttempt()) {\n // This node is in the running state and can do its initial attempt.\n this.setState(State.RUNNING);\n\n // We may have already completed an attempt, meaning that the child node will be in the FAILED state.\n // If this is the case then we will have to reset the child node now.\n if (this.child.getState() === State.FAILED) {\n this.child.reset();\n }\n\n // Update the child of this node.\n this.child.update(agent, options);\n\n // If the child moved into the SUCCEEDED state when we updated it then there is nothing left to do and this node has also succeeded.\n // If it has moved into the FAILED state then we have completed the current attempt.\n if (this.child.getState() === State.SUCCEEDED) {\n // The child has succeeded, meaning that this node has succeeded.\n this.setState(State.SUCCEEDED);\n\n return;\n } else if (this.child.getState() === State.FAILED) {\n // We have completed an attempt.\n this.currentAttemptCount += 1;\n }\n } else {\n // This node is in the 'FAILED' state as we cannot iterate any more.\n this.setState(State.FAILED);\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => {\n if (this.attempts !== null) {\n return `RETRY ${this.attempts}x`;\n } else if (this.attemptsMin !== null && this.attemptsMax !== null) {\n return `RETRY ${this.attemptsMin}x-${this.attemptsMax}x`;\n } else {\n return \"RETRY\";\n }\n };\n\n /**\n * Reset the state of the node.\n */\n reset = () => {\n // Reset the state of this node.\n this.setState(State.READY);\n\n // Reset the current attempt count.\n this.currentAttemptCount = 0;\n\n // Reset the child node.\n this.child.reset();\n };\n\n /**\n * Gets whether an attempt can be made.\n * @returns Whether an attempt can be made.\n */\n canAttempt = () => {\n if (this.targetAttemptCount !== null) {\n // We can attempt as long as we have not reached our target attempt count.\n return this.currentAttemptCount < this.targetAttemptCount;\n }\n\n // If neither an attempt count or a condition function were defined then we can attempt indefinitely.\n return true;\n };\n\n /**\n * Sets the target attempt count.\n * @param options The behaviour tree options object.\n */\n setTargetAttemptCount = (options: BehaviourTreeOptions) => {\n // Are we dealing with an explicit attempt count or will we be randomly picking an attempt count between the min and max attempt count.\n if (this.attempts !== null) {\n this.targetAttemptCount = this.attempts;\n } else if (this.attemptsMin !== null && this.attemptsMax !== null) {\n // We will be picking a random attempt count between a min and max attempt count, if the optional 'random'\n // behaviour tree function option is defined then we will be using that, otherwise we will fall back to using Math.random.\n const random = typeof options.random === \"function\" ? options.random : Math.random;\n\n // Pick a random attempt count between a min and max attempt count.\n this.targetAttemptCount = Math.floor(\n random() * (this.attemptsMax - this.attemptsMin + 1) + this.attemptsMin\n );\n } else {\n this.targetAttemptCount = null;\n }\n };\n}\n", "import Node from \"../Node\";\nimport Decorator from \"./Decorator\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A Root node.\n * The root node will have a single child.\n */\nexport default class Root extends Decorator {\n /**\n * @param attributes The node attributes.\n * @param child The child node.\n */\n constructor(attributes: Attribute[], child: Node) {\n super(\"root\", attributes, child);\n }\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // If the child has never been updated or is running then we will need to update it now.\n if (this.child.getState() === State.READY || this.child.getState() === State.RUNNING) {\n // Update the child of this node.\n this.child.update(agent, options);\n }\n\n // The state of the root node is the state of its child.\n this.setState(this.child.getState());\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => \"ROOT\";\n}\n", "import Node from \"../Node\";\nimport Decorator from \"./Decorator\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A Succeed node.\n * This node wraps a single child and will always move to the 'SUCCEEDED' state when the child moves to a 'SUCCEEDED' or 'FAILED' state.\n */\nexport default class Succeed extends Decorator {\n /**\n * @param attributes The node attributes.\n * @param child The child node.\n */\n constructor(attributes: Attribute[], child: Node) {\n super(\"succeed\", attributes, child);\n }\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // If the child has never been updated or is running then we will need to update it now.\n if (this.child.getState() === State.READY || this.child.getState() === State.RUNNING) {\n this.child.update(agent, options);\n }\n\n // The state of this node will depend in the state of its child.\n switch (this.child.getState()) {\n case State.RUNNING:\n this.setState(State.RUNNING);\n break;\n\n case State.SUCCEEDED:\n case State.FAILED:\n this.setState(State.SUCCEEDED);\n break;\n\n default:\n this.setState(State.READY);\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => \"SUCCEED\";\n}\n", "import Node from \"../Node\";\n\n/**\n * A leaf node.\n */\nexport default abstract class Leaf extends Node {\n /**\n * Gets whether this node is a leaf node.\n */\n isLeafNode = () => true;\n}\n", "import { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\nimport State, { CompleteState } from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Leaf from \"./Leaf\";\nimport Lookup from \"../../Lookup\";\nimport Attribute from \"../../attributes/Attribute\";\n\n/**\n * The type representing a resolved/rejected update promise.\n */\ntype UpdatePromiseResult = {\n /**\n * Whether the promise was resolved rather than rejected.\n */\n isResolved: boolean;\n\n /**\n * The promise resolved value or rejection reason.\n */\n value: any;\n};\n\n/**\n * An Action leaf node.\n * This represents an immediate or ongoing state of behaviour.\n */\nexport default class Action extends Leaf {\n /**\n * @param attributes The node attributes.\n * @param actionName The action name.\n * @param actionArguments The array of action argument definitions.\n */\n constructor(attributes: Attribute[], private actionName: string, private actionArguments: any[]) {\n super(\"action\", attributes, actionArguments);\n }\n\n /**\n * Whether there is a pending update promise.\n */\n private isUsingUpdatePromise = false;\n\n /**\n * The finished state result of an update promise.\n */\n private updatePromiseResult: UpdatePromiseResult | null = null;\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // If the result of this action depends on an update promise then there is nothing to do until it settles.\n if (this.isUsingUpdatePromise) {\n // Are we still waiting for our update promise to settle?\n if (!this.updatePromiseResult) {\n return;\n }\n\n const { isResolved, value } = this.updatePromiseResult;\n\n // Our update promise settled, was it resolved or rejected?\n if (isResolved) {\n // Our promise resolved so check to make sure the result is a valid finished state.\n if (value !== State.SUCCEEDED && value !== State.FAILED) {\n throw new Error(\n \"action node promise resolved with an invalid value, expected a State.SUCCEEDED or State.FAILED value to be returned\"\n );\n }\n\n // Set the state of this node to match the state returned by the promise.\n this.setState(value);\n\n return;\n } else {\n // The promise was rejected, which isn't great.\n throw new Error(`action function '${this.actionName}' promise rejected with '${value}'`);\n }\n }\n\n // Attempt to get the invoker for the action function.\n const actionFuncInvoker = Lookup.getFuncInvoker(agent, this.actionName);\n\n // The action function should be defined.\n if (actionFuncInvoker === null) {\n throw new Error(\n `cannot update action node as the action '${this.actionName}' function is not defined on the agent and has not been registered`\n );\n }\n\n let actionFunctionResult;\n\n try {\n // Call the action function, the result of which may be:\n // - The finished state of this action node.\n // - A promise to return a finished node state.\n // - Undefined if the node should remain in the running state.\n actionFunctionResult = actionFuncInvoker(this.actionArguments) as CompleteState | Promise;\n } catch (error) {\n // An uncaught error was thrown.\n if (error instanceof Error) {\n throw new Error(`action function '${this.actionName}' threw: ${error.stack}`);\n } else {\n throw new Error(`action function '${this.actionName}' threw: ${error}`);\n }\n }\n\n if (actionFunctionResult instanceof Promise) {\n actionFunctionResult.then(\n (result) => {\n // If 'isUpdatePromisePending' is not set then the promise was cleared as it was resolving, probably via an abort of reset.\n if (!this.isUsingUpdatePromise) {\n return;\n }\n\n // Set the resolved update promise result so that it can be handled on the next update of this node.\n this.updatePromiseResult = {\n isResolved: true,\n value: result\n };\n },\n (reason) => {\n // If 'isUpdatePromisePending' is not set then the promise was cleared as it was resolving, probably via an abort or reset.\n if (!this.isUsingUpdatePromise) {\n return;\n }\n\n // Set the rejected update promise result so that it can be handled on the next update of this node.\n this.updatePromiseResult = {\n isResolved: false,\n value: reason\n };\n }\n );\n\n // This node will be in the 'RUNNING' state until the update promise resolves.\n this.setState(State.RUNNING);\n\n // We are now waiting for the promise returned by the use to resolve before we know what state this node is in.\n this.isUsingUpdatePromise = true;\n } else {\n // Validate the returned value.\n this.validateUpdateResult(actionFunctionResult);\n\n // Set the state of this node, this may be undefined, which just means that the node is still in the 'RUNNING' state.\n this.setState(actionFunctionResult || State.RUNNING);\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => this.actionName;\n\n /**\n * Reset the state of the node.\n */\n reset = () => {\n // Reset the state of this node.\n this.setState(State.READY);\n\n // There is no longer an update promise that we care about.\n this.isUsingUpdatePromise = false;\n this.updatePromiseResult = null;\n };\n\n /**\n * Validate the result of an update function call.\n * @param result The result of an update function call.\n */\n private validateUpdateResult = (result: CompleteState | State.RUNNING) => {\n switch (result) {\n case State.SUCCEEDED:\n case State.FAILED:\n case State.RUNNING:\n case undefined:\n return;\n default:\n throw new Error(\n `expected action function '${this.actionName}' to return an optional State.SUCCEEDED or State.FAILED value but returned '${result}'`\n );\n }\n };\n}\n", "import { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Leaf from \"./Leaf\";\nimport Lookup from \"../../Lookup\";\nimport Attribute from \"../../attributes/Attribute\";\n\n/**\n * A Condition leaf node.\n * This will succeed or fail immediately based on an agent predicate, without moving to the 'RUNNING' state.\n */\nexport default class Condition extends Leaf {\n /**\n * @param attributes The node attributes.\n * @param conditionName The name of the condition function.\n * @param conditionArguments The array of condition argument definitions.\n */\n constructor(attributes: Attribute[], private conditionName: string, private conditionArguments: any[]) {\n super(\"condition\", attributes, conditionArguments);\n }\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // Attempt to get the invoker for the condition function.\n const conditionFuncInvoker = Lookup.getFuncInvoker(agent, this.conditionName);\n\n // The condition function should be defined.\n if (conditionFuncInvoker === null) {\n throw new Error(\n `cannot update condition node as the condition '${this.conditionName}' function is not defined on the agent and has not been registered`\n );\n }\n\n let conditionFunctionResult;\n\n try {\n // Call the condition function to determine the state of this node, the result of which should be a boolean.\n conditionFunctionResult = conditionFuncInvoker(this.conditionArguments);\n } catch (error) {\n // An uncaught error was thrown.\n if (error instanceof Error) {\n throw new Error(`condition function '${this.conditionName}' threw: ${error.stack}`);\n } else {\n throw new Error(`condition function '${this.conditionName}' threw: ${error}`);\n }\n }\n\n // The result of calling the condition function must be a boolean value.\n if (typeof conditionFunctionResult !== \"boolean\") {\n throw new Error(\n `expected condition function '${this.conditionName}' to return a boolean but returned '${conditionFunctionResult}'`\n );\n }\n\n // Set the state of this node based on the result of calling the condition function.\n this.setState(!!conditionFunctionResult ? State.SUCCEEDED : State.FAILED);\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => this.conditionName;\n}\n", "import Leaf from \"./Leaf\";\nimport State from \"../../State\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { Agent } from \"../../Agent\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A WAIT node.\n * The state of this node will change to SUCCEEDED after a duration of time\n */\nexport default class Wait extends Leaf {\n /**\n * @param attributes The node attributes.\n * @param duration The duration that this node will wait to succeed in milliseconds.\n * @param durationMin The minimum possible duration in milliseconds that this node will wait to succeed.\n * @param durationMax The maximum possible duration in milliseconds that this node will wait to succeed.\n */\n constructor(\n attributes: Attribute[],\n private duration: number | null,\n private durationMin: number | null,\n private durationMax: number | null\n ) {\n super(\"wait\", attributes, []);\n }\n\n /**\n * The time in milliseconds at which this node was first updated.\n */\n private initialUpdateTime: number = 0;\n\n /**\n * The total duration in milliseconds that this node will be waiting for.\n */\n private totalDuration: number | null = null;\n\n /**\n * The duration in milliseconds that this node has been waiting for.\n */\n private waitedDuration: number = 0;\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // If this node is in the READY state then we need to set the initial update time.\n if (this.is(State.READY)) {\n // Set the initial update time.\n this.initialUpdateTime = new Date().getTime();\n\n // Set the initial waited duration.\n this.waitedDuration = 0;\n\n // Are we dealing with an explicit duration or will we be randomly picking a duration between the min and max duration.\n if (this.duration !== null) {\n this.totalDuration = this.duration;\n } else if (this.durationMin !== null && this.durationMax !== null) {\n // We will be picking a random duration between a min and max duration, if the optional 'random' behaviour tree\n // function option is defined then we will be using that, otherwise we will fall back to using Math.random.\n const random = typeof options.random === \"function\" ? options.random : Math.random;\n\n // Pick a random duration between a min and max duration.\n this.totalDuration = Math.floor(\n random() * (this.durationMax - this.durationMin + 1) + this.durationMin\n );\n } else {\n this.totalDuration = null;\n }\n\n // The node is now running until we finish waiting.\n this.setState(State.RUNNING);\n }\n\n // If we have no total duration then this wait node will wait indefinitely until it is aborted.\n if (this.totalDuration === null) {\n return;\n }\n\n // If we have a 'getDeltaTime' function defined as part of our options then we will use it to figure out how long we have waited for.\n if (typeof options.getDeltaTime === \"function\") {\n // Get the delta time.\n const deltaTime = options.getDeltaTime();\n\n // Our delta time must be a valid number and cannot be NaN.\n if (typeof deltaTime !== \"number\" || isNaN(deltaTime)) {\n throw new Error(\"The delta time must be a valid number and not NaN.\");\n }\n\n // Update the amount of time that this node has been waiting for based on the delta time.\n this.waitedDuration += deltaTime * 1000;\n } else {\n // We are not using a delta time, so we will just work out hom much time has passed since the first update.\n this.waitedDuration = new Date().getTime() - this.initialUpdateTime;\n }\n\n // Have we waited long enough?\n if (this.waitedDuration >= this.totalDuration) {\n // We have finished waiting!\n this.setState(State.SUCCEEDED);\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => {\n if (this.duration !== null) {\n return `WAIT ${this.duration}ms`;\n } else if (this.durationMin !== null && this.durationMax !== null) {\n return `WAIT ${this.durationMin}ms-${this.durationMax}ms`;\n } else {\n return \"WAIT\";\n }\n };\n}\n", "import Guard from \"./guards/Guard\";\n\nexport type AttributeDetails = {\n /** The attribute type. */\n type: string;\n\n /** The attribute arguments. */\n args: any[];\n};\n\n/**\n * A base node attribute.\n */\nexport default abstract class Attribute {\n /**\n * @param type The node attribute type.\n * @param args The array of attribute arguments.\n */\n constructor(public type: string, public args: any[]) {}\n\n /**\n * Gets the attribute details.\n */\n abstract getDetails(): TAttributeDetails;\n\n /**\n * Gets whether this attribute is a guard.\n */\n abstract isGuard: () => this is Guard;\n}\n", "import { Agent } from \"../../Agent\";\nimport Attribute, { AttributeDetails } from \"../Attribute\";\n\nexport type GuardAttributeDetails = {\n /** The name of the condition function that determines whether the guard is satisfied. */\n condition: string;\n} & AttributeDetails;\n\n/**\n * A base node guard attribute.\n */\nexport default abstract class Guard extends Attribute {\n /**\n * @param type The node attribute type.\n * @param args The array of decorator argument definitions.\n * @param condition The name of the condition function that determines whether the guard is satisfied.\n */\n constructor(type: string, args: any[], private condition: string) {\n super(type, args);\n }\n\n /**\n * Gets the name of the condition function that determines whether the guard is satisfied.\n */\n getCondition = () => this.condition;\n\n /**\n * Gets whether this attribute is a guard.\n */\n isGuard = () => true;\n\n /**\n * Gets the attribute details.\n */\n getDetails(): GuardAttributeDetails {\n return {\n type: this.type,\n args: this.args,\n condition: this.getCondition()\n };\n }\n\n /**\n * Gets whether the guard is satisfied.\n * @param agent The agent.\n * @returns Whether the guard is satisfied.\n */\n abstract isSatisfied(agent: Agent): boolean;\n}\n", "import Guard from \"./Guard\";\nimport Lookup from \"../../Lookup\";\nimport { Agent } from \"../../Agent\";\n\n/**\n * A WHILE guard which is satisfied as long as the given condition remains true.\n */\nexport default class While extends Guard {\n /**\n * @param condition The name of the condition function that determines whether the guard is satisfied.\n * @param args The array of decorator argument definitions.\n */\n constructor(condition: string, args: any[]) {\n super(\"while\", args, condition);\n }\n\n /**\n * Gets whether the guard is satisfied.\n * @param agent The agent.\n * @returns Whether the guard is satisfied.\n */\n isSatisfied = (agent: Agent) => {\n // Attempt to get the invoker for the condition function.\n const conditionFuncInvoker = Lookup.getFuncInvoker(agent, this.getCondition());\n\n // The condition function should be defined.\n if (conditionFuncInvoker === null) {\n throw new Error(\n `cannot evaluate node guard as the condition '${this.getCondition()}' function is not defined on the agent and has not been registered`\n );\n }\n\n let conditionFunctionResult;\n\n try {\n // Call the guard condition function to determine the state of this node, the result of which should be a boolean.\n conditionFunctionResult = conditionFuncInvoker(this.args);\n } catch (error) {\n // An uncaught error was thrown.\n if (error instanceof Error) {\n throw new Error(`guard condition function '${this.getCondition()}' threw: ${error.stack}`);\n } else {\n throw new Error(`guard condition function '${this.getCondition()}' threw: ${error}`);\n }\n }\n\n // The result of calling the guard condition function must be a boolean value.\n if (typeof conditionFunctionResult !== \"boolean\") {\n throw new Error(\n `expected guard condition function '${this.getCondition()}' to return a boolean but returned '${conditionFunctionResult}'`\n );\n }\n\n // Return whether this guard is satisfied.\n return conditionFunctionResult;\n };\n}\n", "import Guard from \"./Guard\";\nimport Lookup from \"../../Lookup\";\nimport { Agent } from \"../../Agent\";\n\n/**\n * An UNTIL guard which is satisfied as long as the given condition remains false.\n */\nexport default class Until extends Guard {\n /**\n * @param condition The name of the condition function that determines whether the guard is satisfied.\n * @param args The array of decorator argument definitions.\n */\n constructor(condition: string, args: any[]) {\n super(\"until\", args, condition);\n }\n\n /**\n * Gets whether the guard is satisfied.\n * @param agent The agent.\n * @returns Whether the guard is satisfied.\n */\n isSatisfied = (agent: Agent) => {\n // Attempt to get the invoker for the condition function.\n const conditionFuncInvoker = Lookup.getFuncInvoker(agent, this.getCondition());\n\n // The condition function should be defined.\n if (conditionFuncInvoker === null) {\n throw new Error(\n `cannot evaluate node guard as the condition '${this.getCondition()}' function is not defined on the agent and has not been registered`\n );\n }\n\n let conditionFunctionResult;\n\n try {\n // Call the guard condition function to determine the state of this node, the result of which should be a boolean.\n conditionFunctionResult = conditionFuncInvoker(this.args);\n } catch (error) {\n // An uncaught error was thrown.\n if (error instanceof Error) {\n throw new Error(`guard condition function '${this.getCondition()}' threw: ${error.stack}`);\n } else {\n throw new Error(`guard condition function '${this.getCondition()}' threw: ${error}`);\n }\n }\n\n // The result of calling the guard condition function must be a boolean value.\n if (typeof conditionFunctionResult !== \"boolean\") {\n throw new Error(\n `expected guard condition function '${this.getCondition()}' to return a boolean but returned '${conditionFunctionResult}'`\n );\n }\n\n // Return whether this guard is satisfied.\n return !conditionFunctionResult;\n };\n}\n", "import { Agent } from \"../../Agent\";\nimport Attribute, { AttributeDetails } from \"../Attribute\";\n\nexport type CallbackAttributeDetails = {\n /** The name of the agent function that is called. */\n functionName: string;\n} & AttributeDetails;\n\n/**\n * A base node callback attribute.\n */\nexport default abstract class Callback extends Attribute {\n /**\n * @param type The node attribute type.\n * @param args The array of decorator argument definitions.\n * @param functionName The name of the agent function to call.\n */\n constructor(type: string, args: any[], private functionName: string) {\n super(type, args);\n }\n\n /**\n * Gets the name of the agent function to call.\n */\n getFunctionName = () => this.functionName;\n\n /**\n * Gets whether this attribute is a guard.\n */\n isGuard = () => false;\n\n /**\n * Gets the attribute details.\n */\n getDetails(): CallbackAttributeDetails {\n return {\n type: this.type,\n args: this.args,\n functionName: this.getFunctionName()\n };\n }\n\n /**\n * Attempt to call the agent function that this callback refers to.\n * @param agent The agent.\n */\n abstract callAgentFunction: (agent: Agent, isSuccess: boolean, isAborted: boolean) => void;\n}\n", "import Callback from \"./Callback\";\nimport Lookup from \"../../Lookup\";\nimport { Agent } from \"../../Agent\";\n\n/**\n * An ENTRY callback which defines an agent function to call when the associated node is updated and moves out of running state.\n */\nexport default class Entry extends Callback {\n /**\n * @param functionName The name of the agent function to call.\n * @param args The array of callback argument definitions.\n */\n constructor(functionName: string, args: any[]) {\n super(\"entry\", args, functionName);\n }\n\n /**\n * Attempt to call the agent function that this callback refers to.\n * @param agent The agent.\n */\n callAgentFunction = (agent: Agent) => {\n // Attempt to get the invoker for the callback function.\n const callbackFuncInvoker = Lookup.getFuncInvoker(agent, this.getFunctionName());\n\n // The callback function should be defined.\n if (callbackFuncInvoker === null) {\n throw new Error(\n `cannot call entry function '${this.getFunctionName()}' as is not defined on the agent and has not been registered`\n );\n }\n\n // Call the callback function.\n callbackFuncInvoker(this.args);\n };\n}\n", "import Callback from \"./Callback\";\nimport Lookup from \"../../Lookup\";\nimport { Agent } from \"../../Agent\";\n\n/**\n * A STEP callback which defines an agent function to call when the associated node is updated.\n */\nexport default class Step extends Callback {\n /**\n * @param functionName The name of the agent function to call.\n * @param args The array of callback argument definitions.\n */\n constructor(functionName: string, args: any[]) {\n super(\"step\", args, functionName);\n }\n\n /**\n * Attempt to call the agent function that this callback refers to.\n * @param agent The agent.\n */\n callAgentFunction = (agent: Agent) => {\n // Attempt to get the invoker for the callback function.\n const callbackFuncInvoker = Lookup.getFuncInvoker(agent, this.getFunctionName());\n\n // The callback function should be defined.\n if (callbackFuncInvoker === null) {\n throw new Error(\n `cannot call step function '${this.getFunctionName()}' as is not defined on the agent and has not been registered`\n );\n }\n\n // Call the callback function.\n callbackFuncInvoker(this.args);\n };\n}\n", "import Callback from \"./Callback\";\nimport Lookup from \"../../Lookup\";\nimport { Agent } from \"../../Agent\";\n\n/**\n * An EXIT callback which defines an agent function to call when the associated node is updated and moves to a finished state or is aborted.\n */\nexport default class Exit extends Callback {\n /**\n * @param functionName The name of the agent function to call.\n * @param args The array of callback argument definitions.\n */\n constructor(functionName: string, args: any[]) {\n super(\"exit\", args, functionName);\n }\n\n /**\n * Attempt to call the agent function that this callback refers to.\n * @param agent The agent.\n * @param isSuccess Whether the decorated node was left with a success state.\n * @param isAborted Whether the decorated node was aborted.\n */\n callAgentFunction = (agent: Agent, isSuccess: boolean, isAborted: boolean) => {\n // Attempt to get the invoker for the callback function.\n const callbackFuncInvoker = Lookup.getFuncInvoker(agent, this.getFunctionName());\n\n // The callback function should be defined.\n if (callbackFuncInvoker === null) {\n throw new Error(\n `cannot call exit function '${this.getFunctionName()}' as is not defined on the agent and has not been registered`\n );\n }\n\n // Call the callback function\n callbackFuncInvoker([{ succeeded: isSuccess, aborted: isAborted }, ...this.args]);\n };\n}\n", "import { AnyNodeDefinition, RootNodeDefinition } from \"./BehaviourTreeDefinition\";\nimport GuardPath, { GuardPathPart } from \"./attributes/guards/GuardPath\";\nimport { validateBranchSubtreeLinks } from \"./BehaviourTreeDefinitionValidator\";\nimport { isInteger } from \"./BehaviourTreeDefinitionUtilities\";\nimport Node from \"./nodes/Node\";\nimport Composite from \"./nodes/composite/Composite\";\nimport Decorator from \"./nodes/decorator/Decorator\";\nimport Parallel from \"./nodes/composite/Parallel\";\nimport Selector from \"./nodes/composite/Selector\";\nimport Sequence from \"./nodes/composite/Sequence\";\nimport Lotto from \"./nodes/composite/Lotto\";\nimport Fail from \"./nodes/decorator/Fail\";\nimport Flip from \"./nodes/decorator/Flip\";\nimport Repeat from \"./nodes/decorator/Repeat\";\nimport Retry from \"./nodes/decorator/Retry\";\nimport Root from \"./nodes/decorator/Root\";\nimport Succeed from \"./nodes/decorator/Succeed\";\nimport Action from \"./nodes/leaf/Action\";\nimport Condition from \"./nodes/leaf/Condition\";\nimport Wait from \"./nodes/leaf/Wait\";\nimport Lookup from \"./Lookup\";\nimport Attribute from \"./attributes/Attribute\";\nimport While from \"./attributes/guards/While\";\nimport Until from \"./attributes/guards/Until\";\nimport Entry from \"./attributes/callbacks/Entry\";\nimport Step from \"./attributes/callbacks/Step\";\nimport Exit from \"./attributes/callbacks/Exit\";\n\n/**\n * A type representing any node instance in a behaviour tree.\n */\ntype AnyNode =\n | Root\n | Action\n | Condition\n | Wait\n | Sequence\n | Selector\n | Lotto\n | Parallel\n | Repeat\n | Retry\n | Flip\n | Succeed\n | Fail;\n\n/**\n * A type defining a mapping of root node identifiers to root node definitions.\n */\ntype RootNodeDefinitionMap = { [key: string | symbol]: RootNodeDefinition };\n\n/**\n * A symbol to use as the main root key in any root node mappings.\n */\nconst MAIN_ROOT_NODE_KEY = Symbol(\"__root__\");\n\n/**\n * Build and populate the root nodes based on the provided definition, assuming that the definition has been validated.\n * @param definition The root node definitions.\n * @returns The built and populated root node definitions.\n */\nexport default function buildRootNode(definition: RootNodeDefinition[]): Root {\n // Create a mapping of root node identifers to root node definitions, including globally registered subtree root node definitions.\n const rootNodeDefinitionMap = createRootNodeDefinitionMap(definition);\n\n // Now that we have all of our root node definitions (those part of the tree definition and those globally registered)\n // we should validate the branch-subtree links. This will also double-check that we dont have any circular dependencies\n // in our branch-subtree references and that we have no broken branch-subtree links.\n validateBranchSubtreeLinks(\n [rootNodeDefinitionMap[MAIN_ROOT_NODE_KEY], ...Object.values(rootNodeDefinitionMap)],\n true\n );\n\n // Create our populated tree of node instances, starting with our main root node.\n const rootNode = nodeFactory(rootNodeDefinitionMap[MAIN_ROOT_NODE_KEY], rootNodeDefinitionMap) as Root;\n\n // Set a guard path on every leaf of the tree to evaluate as part of each update.\n applyLeafNodeGuardPaths(rootNode);\n\n // We only need to return the main root node.\n return rootNode;\n}\n\n/**\n * A factory function which creates a node instance based on the specified definition.\n * @param definition The node definition.\n * @param rootNodeDefinitionMap The mapping of root node identifers to root node definitions, including globally registered subtree root node definitions.\n * @returns A node instance based on the specified definition.\n */\nfunction nodeFactory(definition: AnyNodeDefinition, rootNodeDefinitionMap: RootNodeDefinitionMap): AnyNode {\n // Get the attributes for the node.\n const attributes = nodeAttributesFactory(definition);\n\n // Create the node instance based on the definition type.\n switch (definition.type) {\n case \"root\":\n return new Root(attributes, nodeFactory(definition.child, rootNodeDefinitionMap));\n\n case \"repeat\":\n let iterations: number | null = null;\n let iterationsMin: number | null = null;\n let iterationsMax: number | null = null;\n\n if (Array.isArray(definition.iterations)) {\n iterationsMin = definition.iterations[0];\n iterationsMax = definition.iterations[1];\n } else if (isInteger(definition.iterations)) {\n iterations = definition.iterations!;\n }\n\n return new Repeat(\n attributes,\n iterations,\n iterationsMin,\n iterationsMax,\n nodeFactory(definition.child, rootNodeDefinitionMap)\n );\n\n case \"retry\":\n let attempts: number | null = null;\n let attemptsMin: number | null = null;\n let attemptsMax: number | null = null;\n\n if (Array.isArray(definition.attempts)) {\n attemptsMin = definition.attempts[0];\n attemptsMax = definition.attempts[1];\n } else if (isInteger(definition.attempts)) {\n attempts = definition.attempts!;\n }\n\n return new Retry(\n attributes,\n attempts,\n attemptsMin,\n attemptsMax,\n nodeFactory(definition.child, rootNodeDefinitionMap)\n );\n\n case \"flip\":\n return new Flip(attributes, nodeFactory(definition.child, rootNodeDefinitionMap));\n\n case \"succeed\":\n return new Succeed(attributes, nodeFactory(definition.child, rootNodeDefinitionMap));\n\n case \"fail\":\n return new Fail(attributes, nodeFactory(definition.child, rootNodeDefinitionMap));\n\n case \"sequence\":\n return new Sequence(\n attributes,\n definition.children.map((child) => nodeFactory(child, rootNodeDefinitionMap))\n );\n\n case \"selector\":\n return new Selector(\n attributes,\n definition.children.map((child) => nodeFactory(child, rootNodeDefinitionMap))\n );\n\n case \"parallel\":\n return new Parallel(\n attributes,\n definition.children.map((child) => nodeFactory(child, rootNodeDefinitionMap))\n );\n\n case \"lotto\":\n return new Lotto(\n attributes,\n definition.weights,\n definition.children.map((child) => nodeFactory(child, rootNodeDefinitionMap))\n );\n\n case \"branch\":\n return nodeFactory(rootNodeDefinitionMap[definition.ref].child, rootNodeDefinitionMap);\n\n case \"action\":\n return new Action(attributes, definition.call, definition.args || []);\n\n case \"condition\":\n return new Condition(attributes, definition.call, definition.args || []);\n\n case \"wait\":\n let duration: number | null = null;\n let durationMin: number | null = null;\n let durationMax: number | null = null;\n\n if (Array.isArray(definition.duration)) {\n durationMin = definition.duration[0];\n durationMax = definition.duration[1];\n } else if (isInteger(definition.duration)) {\n duration = definition.duration!;\n }\n\n return new Wait(attributes, duration, durationMin, durationMax);\n }\n}\n\n/**\n * Creates an array of node attribute instances based on the specified node definition.\n * @param definition The node definition.\n * @returns An array of node attribute instances based on the specified node definition.\n */\nfunction nodeAttributesFactory(definition: AnyNodeDefinition): Attribute[] {\n const attributes: Attribute[] = [];\n\n if (definition.while) {\n attributes.push(new While(definition.while.call, definition.while.args ?? []));\n }\n\n if (definition.until) {\n attributes.push(new Until(definition.until.call, definition.until.args ?? []));\n }\n\n if (definition.entry) {\n attributes.push(new Entry(definition.entry.call, definition.entry.args ?? []));\n }\n\n if (definition.step) {\n attributes.push(new Step(definition.step.call, definition.step.args ?? []));\n }\n\n if (definition.exit) {\n attributes.push(new Exit(definition.exit.call, definition.exit.args ?? []));\n }\n\n return attributes;\n}\n\n/**\n * Creates a mapping of root node identifers to root node definitions, mixing in globally registered subtree root node definitions.\n * @param definition The root node definitions.\n * @returns A mapping of root node identifers to root node definitions, including globally registered subtree root node definitions.\n */\nfunction createRootNodeDefinitionMap(definition: RootNodeDefinition[]): RootNodeDefinitionMap {\n // Create a mapping of root node identifers to root node definitions.\n const rootNodeMap: RootNodeDefinitionMap = {};\n\n // Add in any registered subtree root node definitions.\n for (const [name, rootNodeDefinition] of Object.entries(Lookup.getSubtrees())) {\n // The name used when registering the subtree will be used as the root node identifier.\n rootNodeMap[name] = { ...rootNodeDefinition, id: name };\n }\n\n // Populate the map with the root node definitions that were included with the tree definition.\n // We do this after adding any registered subtrees as we want these to take presedence.\n for (const rootNodeDefinition of definition) {\n rootNodeMap[rootNodeDefinition.id ?? MAIN_ROOT_NODE_KEY] = rootNodeDefinition;\n }\n\n return rootNodeMap;\n}\n\n/**\n * Applies a guard path to every leaf of the tree to evaluate as part of each update.\n * @param root The main root tree node.\n */\nfunction applyLeafNodeGuardPaths(root: Root) {\n const nodePaths: Node[][] = [];\n\n const findLeafNodes = (path: Node[], node: Node) => {\n // Add the current node to the path.\n path = path.concat(node);\n\n // Check whether the current node is a leaf node.\n if (node.isLeafNode()) {\n nodePaths.push(path);\n } else {\n (node as Composite | Decorator).getChildren().forEach((child) => findLeafNodes(path, child));\n }\n };\n\n // Find all leaf node paths, starting from the root.\n findLeafNodes([], root);\n\n nodePaths.forEach((path) => {\n // Each node in the current path will have to be assigned a guard path, working from the root outwards.\n for (let depth = 0; depth < path.length; depth++) {\n // Get the node in the path at the current depth.\n const currentNode = path[depth];\n\n // The node may already have been assigned a guard path, if so just skip it.\n if (currentNode.hasGuardPath()) {\n continue;\n }\n\n // Create the guard path for the current node.\n const guardPath = new GuardPath(\n path\n .slice(0, depth + 1)\n .map((node) => ({ node, guards: node.getGuardAttributes() }))\n .filter((details) => details.guards.length > 0)\n );\n\n // Assign the guard path to the current node.\n currentNode.setGuardPath(guardPath);\n }\n });\n}\n", "import State, { AnyState } from \"./State\";\nimport Lookup from \"./Lookup\";\nimport Node from \"./nodes/Node\";\nimport Root from \"./nodes/decorator/Root\";\nimport Composite from \"./nodes/composite/Composite\";\nimport Decorator from \"./nodes/decorator/Decorator\";\nimport { Agent, GlobalFunction } from \"./Agent\";\nimport { CallbackAttributeDetails } from \"./attributes/callbacks/Callback\";\nimport { GuardAttributeDetails } from \"./attributes/guards/Guard\";\nimport { BehaviourTreeOptions } from \"./BehaviourTreeOptions\";\nimport { convertMDSLToJSON } from \"./mdsl/MDSLDefinitionParser\";\nimport { RootNodeDefinition } from \"./BehaviourTreeDefinition\";\nimport { validateDefinition, validateJSONDefinition } from \"./BehaviourTreeDefinitionValidator\";\nimport buildRootNode from \"./BehaviourTreeBuilder\";\nimport { isNullOrUndefined } from \"./BehaviourTreeDefinitionUtilities\";\n\n// Purely for outside inspection of the tree.\nexport type FlattenedTreeNode = {\n id: string;\n type: string;\n caption: string;\n state: AnyState;\n guards: GuardAttributeDetails[];\n callbacks: CallbackAttributeDetails[];\n args: any[];\n parentId: string | null;\n};\n\n/**\n * A representation of a behaviour tree.\n */\nexport class BehaviourTree {\n /**\n * The main root tree node.\n */\n private readonly _rootNode: Root;\n\n /**\n * Creates a new instance of the BehaviourTree class.\n * @param definition The behaviour tree definition as either an MDSL string, root node definition object or array of root node definition objects.\n * @param agent The agent instance that this behaviour tree is modelling behaviour for.\n * @param options The behaviour tree options object.\n */\n constructor(\n definition: string | RootNodeDefinition | RootNodeDefinition[],\n private agent: Agent,\n private options: BehaviourTreeOptions = {}\n ) {\n // The tree definition must be defined.\n if (isNullOrUndefined(definition)) {\n throw new Error(\"tree definition not defined\");\n }\n\n // The agent must be defined and not null.\n if (typeof agent !== \"object\" || agent === null) {\n throw new Error(\"the agent must be an object and not null\");\n }\n\n // We should validate the definition before we try to build the tree nodes.\n const { succeeded, errorMessage, json } = validateDefinition(definition);\n\n // Did our validation fail without error?\n if (!succeeded) {\n throw new Error(`invalid definition: ${errorMessage}`);\n }\n\n // Double check that we did actually get our json definition as part of our definition validtion.\n if (!json) {\n throw new Error(\n \"expected json definition to be returned as part of successful definition validation response\"\n );\n }\n\n try {\n // Create the populated tree of behaviour tree nodes and get the root node.\n this._rootNode = buildRootNode(json);\n } catch (exception) {\n // There was an issue in trying build and populate the behaviour tree.\n throw new Error(`error building tree: ${(exception as Error).message}`);\n }\n }\n\n /**\n * Gets whether the tree is in the RUNNING state.\n * @returns true if the tree is in the RUNNING state, otherwise false.\n */\n isRunning() {\n return this._rootNode.getState() === State.RUNNING;\n }\n\n /**\n * Gets the current tree state of SUCCEEDED, FAILED, READY or RUNNING.\n * @returns The current tree state.\n */\n getState() {\n return this._rootNode.getState();\n }\n\n /**\n * Step the tree.\n * 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.\n * 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\n * 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.\n *\n * 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.\n */\n step() {\n // If the root node has already been stepped to completion then we need to reset it.\n if (this._rootNode.getState() === State.SUCCEEDED || this._rootNode.getState() === State.FAILED) {\n this._rootNode.reset();\n }\n\n try {\n this._rootNode.update(this.agent, this.options);\n } catch (exception) {\n throw new Error(`error stepping tree: ${(exception as Error).message}`);\n }\n }\n\n /**\n * Resets the tree from the root node outwards to each nested node, giving each a state of READY.\n */\n reset() {\n this._rootNode.reset();\n }\n\n /**\n * Gets the flattened details of every node in the tree.\n * @returns The flattened details of every node in the tree.\n */\n getFlattenedNodeDetails(): FlattenedTreeNode[] {\n // Create an empty flattened array of tree nodes.\n const flattenedTreeNodes: FlattenedTreeNode[] = [];\n\n /**\n * Helper function to process a node instance and push details into the flattened tree nodes array.\n * @param node The current node.\n * @param parentUid The UID of the node parent, or null if the node is the main root node.\n */\n const processNode = (node: Node, parentUid: string | null) => {\n // Get the guard and callback attribute details for this node.\n const guards = node\n .getAttributes()\n .filter((attribute) => attribute.isGuard())\n .map((attribute) => attribute.getDetails()) as GuardAttributeDetails[];\n const callbacks = node\n .getAttributes()\n .filter((attribute) => !attribute.isGuard())\n .map((attribute) => attribute.getDetails()) as CallbackAttributeDetails[];\n\n // Push the current node into the flattened nodes array.\n flattenedTreeNodes.push({\n id: node.getUid(),\n type: node.getType(),\n caption: node.getName(),\n state: node.getState(),\n guards,\n callbacks,\n args: node.getArguments(),\n parentId: parentUid\n });\n\n // Process each of the nodes children if it is not a leaf node.\n if (!node.isLeafNode()) {\n (node as Composite | Decorator)\n .getChildren()\n .forEach((child) => processNode(child, (node as Composite | Decorator).getUid()));\n }\n };\n\n // Convert the nested node structure into a flattened array of node details.\n processNode(this._rootNode, null);\n\n return flattenedTreeNodes;\n }\n\n /**\n * Registers the action/condition/guard/callback function or subtree with the given name.\n * @param name The name of the function or subtree to register.\n * @param value The function or subtree definition to register.\n */\n static register(name: string, value: GlobalFunction | string | RootNodeDefinition) {\n // Are we going to register a action/condition/guard/callback function?\n if (typeof value === \"function\") {\n Lookup.setFunc(name, value);\n return;\n }\n\n // We are not registering an action/condition/guard/callback function, so we must be registering a subtree.\n if (typeof value === \"string\") {\n let rootNodeDefinitions: RootNodeDefinition[];\n\n // We will assume that any string passed in will be a mdsl definition.\n try {\n rootNodeDefinitions = convertMDSLToJSON(value);\n } catch (exception) {\n throw new Error(`error registering definition, invalid MDSL: ${(exception as Error).message}`);\n }\n\n // This function should only ever be called with a definition containing a single unnamed root node.\n if (rootNodeDefinitions.length != 1 || rootNodeDefinitions[0].id !== null) {\n throw new Error(\"error registering definition: expected a single unnamed root node\");\n }\n\n try {\n // We should validate the subtree as we don't want invalid subtrees available via the lookup.\n const { succeeded, errorMessage } = validateJSONDefinition(rootNodeDefinitions[0]);\n\n // Did our validation fail without error?\n if (!succeeded) {\n throw new Error(errorMessage);\n }\n } catch (exception) {\n throw new Error(`error registering definition: ${(exception as Error).message}`);\n }\n\n // Everything seems hunky-dory, register the subtree.\n Lookup.setSubtree(name, rootNodeDefinitions[0]);\n } else if (typeof value === \"object\" && !Array.isArray(value)) {\n // We will assume that any object passed in is a root node definition.\n\n try {\n // We should validate the subtree as we don't want invalid subtrees available via the lookup.\n const { succeeded, errorMessage } = validateJSONDefinition(value);\n\n // Did our validation fail without error?\n if (!succeeded) {\n throw new Error(errorMessage);\n }\n } catch (exception) {\n throw new Error(`error registering definition: ${(exception as Error).message}`);\n }\n\n // Everything seems hunky-dory, register the subtree.\n Lookup.setSubtree(name, value);\n } else {\n throw new Error(\"unexpected value, expected string mdsl definition, root node json definition or function\");\n }\n }\n\n /**\n * Unregisters the registered action/condition/guard/callback function or subtree with the given name.\n * @param name The name of the registered action/condition/guard/callback function or subtree to unregister.\n */\n static unregister(name: string): void {\n Lookup.remove(name);\n }\n\n /**\n * Unregister all registered action/condition/guard/callback functions and subtrees.\n */\n static unregisterAll(): void {\n Lookup.empty();\n }\n}\n"], - "mappings": "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", + "sourcesContent": ["\"use strict\";\r\nObject.defineProperty(exports, \"__esModule\", { value: true });\r\nexports.Participant = void 0;\r\n/**\r\n * A participant that holds a number of tickets.\r\n */\r\nvar Participant = /** @class */ (function () {\r\n /**\r\n * Creates an instance of the Participant class.\r\n * @param participant The actual participant.\r\n * @param tickets The number of tickets held by the participant.\r\n */\r\n function Participant(participant, tickets) {\r\n if (tickets === void 0) { tickets = 1; }\r\n this._participant = participant;\r\n this._tickets = tickets;\r\n }\r\n Object.defineProperty(Participant.prototype, \"participant\", {\r\n /** Gets the actual participant. */\r\n get: function () {\r\n return this._participant;\r\n },\r\n enumerable: false,\r\n configurable: true\r\n });\r\n Object.defineProperty(Participant.prototype, \"tickets\", {\r\n /** Gets or sets the number of tickets held by the participant. */\r\n get: function () {\r\n return this._tickets;\r\n },\r\n set: function (value) {\r\n this._tickets = value;\r\n },\r\n enumerable: false,\r\n configurable: true\r\n });\r\n return Participant;\r\n}());\r\nexports.Participant = Participant;\r\n", "\"use strict\";\r\nObject.defineProperty(exports, \"__esModule\", { value: true });\r\nexports.isNaturalNumber = exports.isNullOrUndefined = void 0;\r\n/**\r\n * Gets whether the value provided is null or undefined.\r\n * @param value The value to check.\r\n * @returns Whether the value provided is null or undefined.\r\n */\r\nfunction isNullOrUndefined(value) {\r\n return value === null || value === undefined;\r\n}\r\nexports.isNullOrUndefined = isNullOrUndefined;\r\n/**\r\n * Gets whether the value provided is a natural number.\r\n * @param value The value to check.\r\n * @returns Whether the value provided is a natural number.\r\n */\r\nfunction isNaturalNumber(value) {\r\n return typeof value === \"number\" && value >= 1 && Math.floor(value) === value;\r\n}\r\nexports.isNaturalNumber = isNaturalNumber;\r\n", "\"use strict\";\r\nObject.defineProperty(exports, \"__esModule\", { value: true });\r\nexports.Lotto = void 0;\r\nvar Participant_1 = require(\"./Participant\");\r\nvar Utilities_1 = require(\"./Utilities\");\r\n/**\r\n * Represents a lotto consisting of a number of pickable ticket-holding participants.\r\n */\r\nvar Lotto = /** @class */ (function () {\r\n /**\r\n * Creates a new instance of Lotto.\r\n * @param customRandom The custom RNG to use in place of Math.random().\r\n */\r\n function Lotto(customRandom) {\r\n /** The array of participants that are holding tickets in the lotto. */\r\n this._participants = [];\r\n this._customRandom = customRandom;\r\n }\r\n /**\r\n * Adds a participant with the specified number of tickets, or adds to the participant ticket count if the participant already holds tickets.\r\n * @param participant The participant to add or to increase the ticket count for if they already hold tickets.\r\n * @param tickets The number of tickets, defaults to 1.\r\n * @returns The Lotto instance.\r\n */\r\n Lotto.prototype.add = function (participant, tickets) {\r\n if (tickets === void 0) { tickets = 1; }\r\n // Check that we have a valid ticket count.\r\n if (!(0, Utilities_1.isNaturalNumber)(tickets)) {\r\n throw new Error(\"tickets value must be a natural number\");\r\n }\r\n // Check whether this participant has already been added.\r\n var existingParticipant = this._participants.find(function (part) { return part.participant === participant; });\r\n if (existingParticipant) {\r\n // The participant has already been added to the lotto so just add to their ticket count.\r\n existingParticipant.tickets += tickets;\r\n }\r\n else {\r\n // The participant is not part of the lotto so we should add them.\r\n this._participants.push(new Participant_1.Participant(participant, tickets));\r\n }\r\n return this;\r\n };\r\n /**\r\n * Removes the specified number of tickets for the given participant from the draw, or all tickets if a ticket number is not defined.\r\n * @param participant The participant to remove tickets for.\r\n * @param tickets The number of tickets to remove, or undefined if all tickets are to be removed.\r\n * @returns The Lotto instance.\r\n */\r\n Lotto.prototype.remove = function (participant, tickets) {\r\n // Attempt to get the existing participant.\r\n var existingParticipant = this._participants.find(function (part) { return part.participant === participant; });\r\n // There is nothing to do if the specified participant isn't even part of the lotto.\r\n if (!existingParticipant) {\r\n return this;\r\n }\r\n // Check whether a tickets value was given.\r\n if (tickets !== undefined) {\r\n // Check that we have a valid ticket count.\r\n if (!(0, Utilities_1.isNaturalNumber)(tickets)) {\r\n throw new Error(\"tickets value must be a natural number\");\r\n }\r\n existingParticipant.tickets -= tickets;\r\n // If the participant no longer holds any tickets then they should be removed.\r\n if (existingParticipant.tickets < 1) {\r\n this._participants = this._participants.filter(function (part) { return part !== existingParticipant; });\r\n }\r\n }\r\n else {\r\n // We are removing all tickets for the participant so just remove them from the lotto.\r\n this._participants = this._participants.filter(function (part) { return part !== existingParticipant; });\r\n }\r\n return this;\r\n };\r\n /**\r\n * Draw a winning ticket and return the participant that holds the ticket.\r\n * @param options The draw options.\r\n * @returns The participant that holds the winning ticket.\r\n */\r\n Lotto.prototype.draw = function (options) {\r\n if (options === void 0) { options = {}; }\r\n // If we have no participants then just return null.\r\n if (this._participants.length === 0) {\r\n return null;\r\n }\r\n var redrawable = (0, Utilities_1.isNullOrUndefined)(options.redrawable) ? true : options.redrawable;\r\n var pickable = [];\r\n this._participants.forEach(function (_a) {\r\n var participant = _a.participant, tickets = _a.tickets;\r\n for (var ticketCount = 0; ticketCount < tickets; ticketCount++) {\r\n pickable.push(participant);\r\n }\r\n });\r\n var random;\r\n // We need a random floating-point number between 0 (inclusive) and 1 to scale up to pick our winner.\r\n // If a custom random function exists then we should use that or fall back to Math.random().\r\n if (this._customRandom) {\r\n // Call our custom random function to get a random floating-point number.\r\n random = this._customRandom();\r\n // Verify that the result of calling our custom random function is a number between 0 (inclusive) and 1.\r\n if (typeof random !== \"number\" || random < 0 || random >= 1) {\r\n throw new Error(\"the 'random' function provided did not return a number between 0 (inclusive) and 1\");\r\n }\r\n }\r\n else {\r\n // No custom random function was defined so just use good ol' Math.random().\r\n random = Math.random();\r\n }\r\n // Pick a winning participant.\r\n var winner = pickable[Math.floor(random * pickable.length)];\r\n // If the ticket isn't redrawable then we should remove a ticket from the winning participants ticket count.\r\n if (!redrawable) {\r\n this.remove(winner, 1);\r\n }\r\n // Return the winning participant.\r\n return winner;\r\n };\r\n /**\r\n * Draws multiple winning tickets and return an array of the participants that hold the winning tickets.\r\n * @param tickets The number of winning tickets to draw.\r\n * @param options The draw multiple options.\r\n * @returns An array of the participants that hold the winning tickets.\r\n */\r\n Lotto.prototype.drawMultiple = function (tickets, options) {\r\n if (options === void 0) { options = {}; }\r\n var uniqueResults = (0, Utilities_1.isNullOrUndefined)(options.unique) ? false : options.unique;\r\n // Handle cases where the user has asked for zero tickets (no idea why they would do this be we should trust them).\r\n if (tickets === 0) {\r\n return [];\r\n }\r\n // Now that we know out tickets value is not zero we should check that it is a valid natural number.\r\n if (!(0, Utilities_1.isNaturalNumber)(tickets)) {\r\n throw new Error(\"tickets value must be a natural number\");\r\n }\r\n var result = [];\r\n // Keep drawing tickets until we either reach the number of required tickets or we simply run out of tickets to draw.\r\n // We can run out of tickets to draw if 'options.redrawable' is explicity 'false' or we just had no participants when 'drawMultiple' was called.\r\n while (result.length < tickets && this._participants.length > 0) {\r\n result.push(this.draw(options));\r\n }\r\n // If the 'unique' draw option is set then we need to remove duplicates from the result list.\r\n if (uniqueResults) {\r\n // Create an array to store our unique results.\r\n var unique = [];\r\n // Iterate over all of our participants (with potential duplicates) and populate our array of unique values.\r\n for (var _i = 0, result_1 = result; _i < result_1.length; _i++) {\r\n var participant = result_1[_i];\r\n if (unique.indexOf(participant) === -1) {\r\n unique.push(participant);\r\n }\r\n }\r\n result = unique;\r\n }\r\n return result;\r\n };\r\n return Lotto;\r\n}());\r\nexports.Lotto = Lotto;\r\n", "\"use strict\";\r\nObject.defineProperty(exports, \"__esModule\", { value: true });\r\nexports.createLotto = void 0;\r\nvar Lotto_1 = require(\"./Lotto\");\r\n/**\r\n * A function that creates and returns a Lotto instance.\r\n * @param participantsOrOptions An array of initial participants or options relating to the creation of a Lotto instance.\r\n * @returns A new Lotto instance.\r\n */\r\nfunction createLotto(participantsOrOptions) {\r\n // If no initial participants or lotto options were provided as an argument then we can just return a new lotto instance now.\r\n if (!participantsOrOptions) {\r\n return new Lotto_1.Lotto();\r\n }\r\n // Check whether we were provided with an array of initial participants or a lotto options object.\r\n if (Array.isArray(participantsOrOptions)) {\r\n // We are dealing with a pre-defined array of participants.\r\n var participants = participantsOrOptions;\r\n var lotto_1 = new Lotto_1.Lotto();\r\n // If the lotto participants have been defined upfront then we will need to add them all to our lotto instance now.\r\n participants.forEach(function (_a) {\r\n var participant = _a[0], tokens = _a[1];\r\n return lotto_1.add(participant, tokens);\r\n });\r\n // Return the Lotto instance.\r\n return lotto_1;\r\n }\r\n else {\r\n // We are dealing with some lotto options.\r\n var random = participantsOrOptions.random, participants = participantsOrOptions.participants;\r\n // Create a Lotto instance passing the custom RNG function to use in place of Math.random() (which could be undefined).\r\n var lotto_2 = new Lotto_1.Lotto(random);\r\n // If the lotto participants have been defined upfront as part of the options then we will need to add them all to our lotto instance now.\r\n if (participants) {\r\n participants.forEach(function (_a) {\r\n var participant = _a[0], tokens = _a[1];\r\n return lotto_2.add(participant, tokens);\r\n });\r\n }\r\n // Return the Lotto instance.\r\n return lotto_2;\r\n }\r\n}\r\nexports.createLotto = createLotto;\r\n", "\"use strict\";\r\nObject.defineProperty(exports, \"__esModule\", { value: true });\r\nvar createLotto_1 = require(\"./createLotto\");\r\nexports.default = createLotto_1.createLotto;\r\n", "import State from \"./State\";\nimport { validateDefinition } from \"./BehaviourTreeDefinitionValidator\";\nimport { convertMDSLToJSON } from \"./mdsl/MDSLDefinitionParser\";\nimport { BehaviourTree, FlattenedTreeNode } from \"./BehaviourTree\";\nimport { BehaviourTreeOptions } from \"./BehaviourTreeOptions\";\n\nexport { BehaviourTree, State, convertMDSLToJSON, validateDefinition };\nexport type { FlattenedTreeNode, BehaviourTreeOptions };\n", "/**\n * Enumeration of node state types.\n */\nexport enum State {\n READY = \"mistreevous.ready\",\n RUNNING = \"mistreevous.running\",\n SUCCEEDED = \"mistreevous.succeeded\",\n FAILED = \"mistreevous.failed\"\n}\n\nexport { State as default };\n\nexport type CompleteState = State.SUCCEEDED | State.FAILED;\nexport type AnyState = State.READY | State.RUNNING | CompleteState;\n", "import {\n NodeDefinition,\n RootNodeDefinition,\n DecoratorNodeDefinition,\n CompositeNodeDefinition,\n AnyNodeDefinition,\n BranchNodeDefinition\n} from \"./BehaviourTreeDefinition\";\n\n/**\n * A type guard function that returns true if the specified node satisfies the RootNodeDefinition type.\n * @param node The node.\n * @returns A value of true if the specified node satisfies the RootNodeDefinition type.\n */\nexport function isRootNode(node: NodeDefinition): node is RootNodeDefinition {\n return node.type === \"root\";\n}\n\n/**\n * A type guard function that returns true if the specified node satisfies the BranchNodeDefinition type.\n * @param node The node.\n * @returns A value of true if the specified node satisfies the BranchNodeDefinition type.\n */\nexport function isBranchNode(node: NodeDefinition): node is BranchNodeDefinition {\n return node.type === \"branch\";\n}\n\n/**\n * A type guard function that returns true if the specified node satisfies the NodeDefinition type.\n * @param node The node.\n * @returns A value of true if the specified node satisfies the NodeDefinition type.\n */\nexport function isLeafNode(node: NodeDefinition): node is NodeDefinition {\n return [\"branch\", \"action\", \"condition\", \"wait\"].includes(node.type);\n}\n\n/**\n * A type guard function that returns true if the specified node satisfies the DecoratorNodeDefinition type.\n * @param node The node.\n * @returns A value of true if the specified node satisfies the DecoratorNodeDefinition type.\n */\nexport function isDecoratorNode(node: NodeDefinition): node is DecoratorNodeDefinition {\n return [\"root\", \"repeat\", \"retry\", \"flip\", \"succeed\", \"fail\"].includes(node.type);\n}\n\n/**\n * A type guard function that returns true if the specified node satisfies the CompositeNodeDefinition type.\n * @param node The node.\n * @returns A value of true if the specified node satisfies the CompositeNodeDefinition type.\n */\nexport function isCompositeNode(node: NodeDefinition): node is CompositeNodeDefinition {\n return [\"sequence\", \"selector\", \"lotto\", \"parallel\"].includes(node.type);\n}\n\n/**\n * Flatten a node definition into an array of all of its nested node definitions.\n * @param nodeDefinition The node definition to flatten.\n * @returns An array of all of nested node definitions.\n */\nexport function flattenDefinition(nodeDefinition: AnyNodeDefinition): AnyNodeDefinition[] {\n const nodes: AnyNodeDefinition[] = [];\n\n const processNode = (currentNodeDefinition: AnyNodeDefinition) => {\n nodes.push(currentNodeDefinition);\n\n if (isCompositeNode(currentNodeDefinition)) {\n currentNodeDefinition.children.forEach(processNode);\n } else if (isDecoratorNode(currentNodeDefinition)) {\n processNode(currentNodeDefinition.child);\n }\n };\n\n processNode(nodeDefinition);\n\n return nodes;\n}\n\n/**\n * Determines whether the passed value is an integer.\n * @param value The value to check.\n * @returns Whether the passed value is an integer.\n */\nexport function isInteger(value: unknown): boolean {\n return typeof value === \"number\" && Math.floor(value) === value;\n}\n\n/**\n * Determines whether the passed value is null or undefined.\n * @param value The value to check.\n * @returns Whether the passed value is null or undefined.\n */\nexport function isNullOrUndefined(value: unknown): boolean {\n return typeof value === \"undefined\" || value === null;\n}\n", "/**\n * A type defining an object that holds a reference to substitued string literals parsed from the definition.\n */\nexport type StringLiteralPlaceholders = { [key: string]: string };\n\n/**\n * Pop the next raw token from the specified array of tokens and throw an error if it wasn't the expected one.\n * @param tokens The array of tokens.\n * @param expected An optional string or array or items, one of which must match the next popped token.\n * @returns The popped token.\n */\nexport function popAndCheck(tokens: string[], expected?: string | string[]): string {\n // Get and remove the next token.\n const popped = tokens.shift();\n\n // We were expecting another token but there aren't any.\n if (popped === undefined) {\n throw new Error(\"unexpected end of definition\");\n }\n\n // Do we have an expected token/tokens array?\n if (expected != undefined) {\n // Get an array of expected values, if the popped token matches any then we are all good.\n const expectedValues = typeof expected === \"string\" ? [expected] : expected;\n\n // Check whether the popped token matches at least one of our expected items.\n var tokenMatchesExpectation = expectedValues.some((item) => popped.toUpperCase() === item.toUpperCase());\n\n // Throw an error if the popped token didn't match any of our expected items.\n if (!tokenMatchesExpectation) {\n const expectationString = expectedValues.map((item) => \"'\" + item + \"'\").join(\" or \");\n throw new Error(\"unexpected token found. Expected \" + expectationString + \" but got '\" + popped + \"'\");\n }\n }\n\n // Return the popped token.\n return popped;\n}\n\n/**\n * Swaps out any node/attribute argument string literals with placeholders.\n * @param definition The definition.\n * @returns An object containing a mapping of placeholders to original string values as well as the processed definition string.\n */\nexport function substituteStringLiterals(definition: string): {\n placeholders: StringLiteralPlaceholders;\n processedDefinition: string;\n} {\n // Create an object to hold the mapping of placeholders to original string values.\n const placeholders: StringLiteralPlaceholders = {};\n\n // Replace any string literals wrapped with double quotes in our definition with placeholders to be processed later.\n const processedDefinition = definition.replace(/\\\"(\\\\.|[^\"\\\\])*\\\"/g, (match) => {\n var strippedMatch = match.substring(1, match.length - 1);\n var placeholder = Object.keys(placeholders).find((key) => placeholders[key] === strippedMatch);\n\n // If we have no existing string literal match then create a new placeholder.\n if (!placeholder) {\n placeholder = `@@${Object.keys(placeholders).length}@@`;\n placeholders[placeholder] = strippedMatch;\n }\n\n return placeholder;\n });\n\n return { placeholders, processedDefinition };\n}\n\n/**\n * Parse the tree definition into an array of raw tokens.\n * @param definition The definition.\n * @returns An array of tokens parsed from the definition.\n */\nexport function parseTokensFromDefinition(definition: string): string[] {\n // Add some space around various important characters so that they can be plucked out easier as individual tokens.\n definition = definition.replace(/\\(/g, \" ( \");\n definition = definition.replace(/\\)/g, \" ) \");\n definition = definition.replace(/\\{/g, \" { \");\n definition = definition.replace(/\\}/g, \" } \");\n definition = definition.replace(/\\]/g, \" ] \");\n definition = definition.replace(/\\[/g, \" [ \");\n definition = definition.replace(/\\,/g, \" , \");\n\n // Split the definition into raw token form and return it.\n return definition.replace(/\\s+/g, \" \").trim().split(\" \");\n}\n", "import { StringLiteralPlaceholders, popAndCheck } from \"./MDSLUtilities\";\n\n/**\n * A type representing any node function argument.\n */\ntype Argument = {\n /**\n * The argument value.\n */\n value: T;\n /**\n * The argument type, used for validation.\n */\n type: string;\n};\n\ntype NullArgument = Argument & {\n type: \"null\";\n};\n\ntype BooleanArgument = Argument & {\n type: \"boolean\";\n};\n\ntype NumberArgument = Argument & {\n type: \"number\";\n /**\n * A flag defining whether the number argument value is a valid integer. (used for validation)\n */\n isInteger: boolean;\n};\n\ntype StringPlaceholderArgument = Argument & {\n type: \"string\";\n};\n\ntype IdentifierArgument = Argument & {\n type: \"identifier\";\n};\n\n/**\n * A type representing a reference to any node function argument.\n */\ntype AnyArgument = NullArgument | BooleanArgument | NumberArgument | StringPlaceholderArgument | IdentifierArgument;\n\n/**\n * Parse an array of argument definitions from the specified tokens array.\n * @param tokens The array tokens to parse the argument definitions from.\n * @param stringArgumentPlaceholders The mapping of string literal node argument placeholders to original values.\n * @param argumentValidator The argument validator function.\n * @param validationFailedMessage The exception message to throw if argument validation fails.\n * @returns An array of argument definitions parsed from the specified tokens array.\n */\nexport function parseArgumentTokens(\n tokens: string[],\n stringArgumentPlaceholders: StringLiteralPlaceholders\n): AnyArgument[] {\n const argumentList: AnyArgument[] = [];\n\n // If the next token is not a '[' or '(' then we have no arguments to parse.\n if (![\"[\", \"(\"].includes(tokens[0])) {\n return argumentList;\n }\n\n // Any lists of arguments will always be wrapped in '[]' for node arguments or '()' for attribute arguments.\n // We are looking for a '[' or '(' opener that wraps the argument tokens and the relevant closer.\n const closingToken = popAndCheck(tokens, [\"[\", \"(\"]) === \"[\" ? \"]\" : \")\";\n\n const argumentListTokens: string[] = [];\n\n // Grab all tokens between the '[' and ']' or '(' and ')'.\n while (tokens.length && tokens[0] !== closingToken) {\n // The next token is part of our arguments list.\n argumentListTokens.push(tokens.shift()!);\n }\n\n // Validate the order of the argument tokens. Each token must either be a ',' or a single argument that satisfies the validator.\n argumentListTokens.forEach((token, index) => {\n // Get whether this token should be an actual argument.\n const shouldBeArgumentToken = !(index & 1);\n\n // If the current token should be an actual argument then validate it, otherwise it should be a ',' token.\n if (shouldBeArgumentToken) {\n // Get the argument definition.\n const argumentDefinition = getArgumentDefinition(token, stringArgumentPlaceholders);\n\n // This is a valid argument!\n argumentList.push(argumentDefinition);\n } else {\n // The current token should be a ',' token.\n if (token !== \",\") {\n throw new Error(`invalid argument list, expected ',' or ']' but got '${token}'`);\n }\n }\n });\n\n // The arguments list should terminate with a ']' or ')' token, depending on the opener.\n popAndCheck(tokens, closingToken);\n\n // Return the arguments.\n return argumentList;\n}\n\n/**\n * Gets an argument value definition.\n * @param token The argument token.\n * @param stringArgumentPlaceholders The mapping of string literal node argument placeholders to original values.\n * @returns An argument value definition.\n */\nfunction getArgumentDefinition(token: string, stringArgumentPlaceholders: StringLiteralPlaceholders): AnyArgument {\n // Check whether the token represents a null value.\n if (token === \"null\") {\n return {\n value: null,\n type: \"null\"\n } as NullArgument;\n }\n\n // Check whether the token represents a boolean value.\n if (token === \"true\" || token === \"false\") {\n return {\n value: token === \"true\",\n type: \"boolean\"\n } as BooleanArgument;\n }\n\n // Check whether the token represents a number value.\n // TODO: Relies on broken isNaN - see MDN.\n // if (!Number.isNaN(token)) {\n if (!isNaN(token as any)) {\n return {\n value: parseFloat(token),\n isInteger: parseFloat(token) === parseInt(token, 10),\n type: \"number\"\n } as NumberArgument;\n }\n\n // Check whether the token is a placeholder (e.g. @@0@@) representing a string literal.\n if (token.match(/^@@\\d+@@$/g)) {\n return {\n value: stringArgumentPlaceholders[token].replace('\\\\\"', '\"'),\n type: \"string\"\n } as StringPlaceholderArgument;\n }\n\n // The only remaining option is that the argument value is an identifier.\n return {\n value: token,\n type: \"identifier\"\n } as IdentifierArgument;\n}\n", "import { NodeAttributeDefinition } from \"../BehaviourTreeDefinition\";\nimport { parseArgumentTokens } from \"./MDSLNodeArgumentParser\";\nimport { StringLiteralPlaceholders } from \"./MDSLUtilities\";\n\n/**\n * A type defining the attribute definitions of a node.\n */\ntype NodeAttributes = {\n while?: NodeAttributeDefinition;\n until?: NodeAttributeDefinition;\n entry?: NodeAttributeDefinition;\n exit?: NodeAttributeDefinition;\n step?: NodeAttributeDefinition;\n};\n\n/**\n * Parse any node attribute definitions from the specified tokens array.\n * @param tokens The array of remaining tokens.\n * @param stringArgumentPlaceholders The mapping of string literal node argument placeholders to original values.\n * @returns An object of attribute definitions defined by any directly following tokens.\n */\nexport function parseAttributeTokens(\n tokens: string[],\n stringArgumentPlaceholders: StringLiteralPlaceholders\n): NodeAttributes {\n const nodeAttributeNames: (keyof NodeAttributes)[] = [\"while\", \"until\", \"entry\", \"exit\", \"step\"];\n\n // Create an object to hold any attributes found.\n const attributes: NodeAttributes = {};\n\n // Try to get the name of the attribute for the next token.\n let nextAttributeName = tokens[0]?.toLowerCase() as keyof NodeAttributes;\n\n // Pull attribute tokens as well as their arguments off of the tokens stack until we have no more.\n while (nodeAttributeNames.includes(nextAttributeName)) {\n // Check to make sure that we have not already created an attribute definition of this type.\n if (attributes[nextAttributeName]) {\n throw new Error(`duplicate attribute '${tokens[0].toUpperCase()}' found for node`);\n }\n\n // Remove the attribute name token from the array of tokens.\n tokens.shift();\n\n // Grab the attribute arguments, assuming the first to be an identifier.\n const [attributeCallIdentifier, ...attributeArguments] = parseArgumentTokens(\n tokens,\n stringArgumentPlaceholders\n );\n\n // The first attribute argument has to be an identifer, this will reference an agent function.\n if (attributeCallIdentifier?.type !== \"identifier\") {\n throw new Error(\"expected agent function or registered function name identifier argument for attribute\");\n }\n\n // Any attribute arguments (other than the expected call identifier) must have a type of string, number, boolean or null.\n attributeArguments\n .filter((arg) => arg.type === \"identifier\")\n .forEach((arg) => {\n throw new Error(\n `invalid attribute argument value '${arg.value}', must be string, number, boolean or null`\n );\n });\n\n // Create the attribute definition and add it to the object of attribute definitions found.\n attributes[nextAttributeName] = {\n call: attributeCallIdentifier.value,\n args: attributeArguments.map(({ value }) => value)\n };\n\n // Try to get the next attribute name token, as there could be multiple.\n nextAttributeName = tokens[0]?.toLowerCase() as keyof NodeAttributes;\n }\n\n return attributes;\n}\n", "import {\n ActionNodeDefinition,\n AnyChildNodeDefinition,\n AnyNodeDefinition,\n BranchNodeDefinition,\n ConditionNodeDefinition,\n FailNodeDefinition,\n FlipNodeDefinition,\n LottoNodeDefinition,\n ParallelNodeDefinition,\n RepeatNodeDefinition,\n RetryNodeDefinition,\n RootNodeDefinition,\n SelectorNodeDefinition,\n SequenceNodeDefinition,\n SucceedNodeDefinition,\n WaitNodeDefinition\n} from \"../BehaviourTreeDefinition\";\nimport {\n isCompositeNode,\n isDecoratorNode,\n isLeafNode,\n isNullOrUndefined,\n isRootNode\n} from \"../BehaviourTreeDefinitionUtilities\";\nimport { parseArgumentTokens } from \"./MDSLNodeArgumentParser\";\nimport { parseAttributeTokens } from \"./MDSLNodeAttributeParser\";\nimport {\n StringLiteralPlaceholders,\n parseTokensFromDefinition,\n popAndCheck,\n substituteStringLiterals\n} from \"./MDSLUtilities\";\n\n/**\n * Convert the MDSL tree definition string into an equivalent JSON definition.\n * @param definition The tree definition string as MDSL.\n * @returns The root node JSON definitions.\n */\nexport function convertMDSLToJSON(definition: string): RootNodeDefinition[] {\n // Swap out any node/attribute argument string literals with a placeholder and get a mapping of placeholders to original values as well as the processed definition.\n const { placeholders, processedDefinition } = substituteStringLiterals(definition);\n\n // Parse our definition definition string into an array of raw tokens.\n const tokens = parseTokensFromDefinition(processedDefinition);\n\n return convertTokensToJSONDefinition(tokens, placeholders);\n}\n\n/**\n * Converts the specified tree definition tokens into a JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The root node JSON definitions.\n */\nfunction convertTokensToJSONDefinition(\n tokens: string[],\n stringLiteralPlaceholders: StringLiteralPlaceholders\n): RootNodeDefinition[] {\n // There must be at least 3 tokens for the tree definition to be valid. 'ROOT', '{' and '}'.\n if (tokens.length < 3) {\n throw new Error(\"invalid token count\");\n }\n\n // We should have a matching number of '{' and '}' tokens. If not, then there are scopes that have not been properly closed.\n if (tokens.filter((token) => token === \"{\").length !== tokens.filter((token) => token === \"}\").length) {\n throw new Error(\"scope character mismatch\");\n }\n\n // Create an array of tree stack arrays where root nodes will always be at the botton and the current composite/decorator node at the top.\n // There should be an element in this array for every root node defined and every element should be an array with a root note as the first element.\n // E.g. A definition with two root nodes defined:\n // [\n // [root, lotto, sequence],\n // [root, selector]\n // ]\n const treeStacks: [Partial, ...Partial[]][] = [];\n\n // Create an array of all root node definitions that we create.\n const rootNodes: Partial[] = [];\n\n // A helper function used to push node definitions onto the tree stack.\n const pushNode = (node: AnyNodeDefinition) => {\n // If the node is a root node then we need to create a new tree stack array with the root node at the root.\n if (isRootNode(node)) {\n // We need to double-check that this root node is not the child of another node.\n // We can do this by checking whether the top tree stack is not empty (contains an existing node)\n if (treeStacks[treeStacks.length - 1]?.length) {\n throw new Error(\"a root node cannot be the child of another node\");\n }\n\n // Add the root node definition to our array of all parsed root node definitions.\n rootNodes.push(node);\n\n // Add the root node definition to the root of a new tree stack.\n treeStacks.push([node]);\n\n return;\n }\n\n // All non-root nodes should be pushed after their root nodes so handle cases\n // where we may not have any tree stacks or our top-most tree stack is empty.\n if (!treeStacks.length || !treeStacks[treeStacks.length - 1].length) {\n throw new Error(\"expected root node at base of definition\");\n }\n\n // Get the current tree stack that we are populating.\n const topTreeStack = treeStacks[treeStacks.length - 1];\n\n // Get the top-most node in the current tree stack, this will be a composite/decorator node\n // for which we will populate its children array if composite or setting its child if a decorator.\n const topTreeStackTopNode = topTreeStack[topTreeStack.length - 1] as AnyNodeDefinition;\n\n // If the top-most node in the current root stack is a composite or decorator\n // node then the current node should be added as a child of the top-most node.\n if (isCompositeNode(topTreeStackTopNode)) {\n topTreeStackTopNode.children = topTreeStackTopNode.children || [];\n topTreeStackTopNode.children.push(node);\n } else if (isDecoratorNode(topTreeStackTopNode)) {\n // If the top node already has a child node set then throw an error as a decorator should only have a single child.\n if (topTreeStackTopNode.child) {\n throw new Error(\"a decorator node must only have a single child node\");\n }\n\n topTreeStackTopNode.child = node;\n }\n\n // If the node we are adding is also a composite or decorator node, then we should push it\n // onto the current tree stack, as subsequent nodes will be added as its child/children.\n if (!isLeafNode(node)) {\n topTreeStack.push(node);\n }\n };\n\n // A helper function used to pop the top-most node definition off of the tree stack and return it.\n const popNode = (): AnyNodeDefinition | null => {\n let poppedNode: AnyNodeDefinition | null = null;\n\n // Get the current tree stack that we are populating.\n const topTreeStack = treeStacks[treeStacks.length - 1];\n\n // Pop the top-most node in the current tree stack if there is one.\n if (topTreeStack.length) {\n poppedNode = topTreeStack.pop() as AnyNodeDefinition;\n }\n\n // We don't want any empty tree stacks in our stack of tree stacks.\n if (!topTreeStack.length) {\n treeStacks.pop();\n }\n\n return poppedNode;\n };\n\n // We should keep processing the raw tokens until we run out of them.\n while (tokens.length) {\n // Grab the next token.\n const token = tokens.shift()!;\n\n // How we create the next node depends on the current raw token value.\n switch (token.toUpperCase()) {\n case \"ROOT\": {\n pushNode(createRootNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"SUCCEED\": {\n pushNode(createSucceedNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"FAIL\": {\n pushNode(createFailNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"FLIP\": {\n pushNode(createFlipNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"REPEAT\": {\n pushNode(createRepeatNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"RETRY\": {\n pushNode(createRetryNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"SEQUENCE\": {\n pushNode(createSequenceNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"SELECTOR\": {\n pushNode(createSelectorNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"PARALLEL\": {\n pushNode(createParallelNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"LOTTO\": {\n pushNode(createLottoNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"ACTION\": {\n pushNode(createActionNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"CONDITION\": {\n pushNode(createConditionNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"WAIT\": {\n pushNode(createWaitNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"BRANCH\": {\n pushNode(createBranchNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"}\": {\n // The '}' character closes the current scope and means that we have to pop a node off of the current stack.\n const poppedNode = popNode();\n\n // Now that we have a node definition we can carry out any validation that may require the node to be fully populated.\n if (poppedNode) {\n validatePoppedNode(poppedNode);\n }\n\n break;\n }\n\n default: {\n throw new Error(`unexpected token: ${token}`);\n }\n }\n }\n\n return rootNodes as RootNodeDefinition[];\n}\n\n/**\n * Creates a root node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The root node JSON definition.\n */\nfunction createRootNode(tokens: string[], stringLiteralPlaceholders: StringLiteralPlaceholders): RootNodeDefinition {\n // Create the root node definition.\n let node = {\n type: \"root\"\n } as Partial;\n\n // Parse any node arguments, we should only have one if any which will be an identifier argument for the root identifier.\n const nodeArguments = parseArgumentTokens(tokens, stringLiteralPlaceholders);\n\n // Check whether any node arguments were defined.\n if (nodeArguments.length) {\n // We should only have one argument, if any, which will be an identifier argument for the root identifier.\n if (nodeArguments.length === 1 && nodeArguments[0].type === \"identifier\") {\n // The root node identifier will be the first and only node argument value.\n node.id = nodeArguments[0].value as string;\n } else {\n throw new Error(\"expected single root name argument\");\n }\n }\n\n // Grab any node attribute definitions and spread them into the node definition.\n node = { ...node, ...parseAttributeTokens(tokens, stringLiteralPlaceholders) };\n\n // This is a decorator node, so we expect an opening '{'.\n popAndCheck(tokens, \"{\");\n\n // Return the root node definition.\n return node as RootNodeDefinition;\n}\n\n/**\n * Creates a succeed node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The succeed node JSON definition.\n */\nfunction createSucceedNode(\n tokens: string[],\n stringLiteralPlaceholders: StringLiteralPlaceholders\n): SucceedNodeDefinition {\n const node = {\n type: \"succeed\",\n ...parseAttributeTokens(tokens, stringLiteralPlaceholders)\n } as SucceedNodeDefinition;\n\n // This is a decorator node, so we expect an opening '{'.\n popAndCheck(tokens, \"{\");\n\n // Return the succeed node definition.\n return node;\n}\n\n/**\n * Creates a fail node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The fail node JSON definition.\n */\nfunction createFailNode(tokens: string[], stringLiteralPlaceholders: StringLiteralPlaceholders): FailNodeDefinition {\n const node = {\n type: \"fail\",\n ...parseAttributeTokens(tokens, stringLiteralPlaceholders)\n } as FailNodeDefinition;\n\n // This is a decorator node, so we expect an opening '{'.\n popAndCheck(tokens, \"{\");\n\n // Return the fail node definition.\n return node;\n}\n\n/**\n * Creates a flip node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The flip node JSON definition.\n */\nfunction createFlipNode(tokens: string[], stringLiteralPlaceholders: StringLiteralPlaceholders): FlipNodeDefinition {\n const node = {\n type: \"flip\",\n ...parseAttributeTokens(tokens, stringLiteralPlaceholders)\n } as FlipNodeDefinition;\n\n // This is a decorator node, so we expect an opening '{'.\n popAndCheck(tokens, \"{\");\n\n // Return the flip node definition.\n return node;\n}\n\n/**\n * Creates a repeat node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The repeat node JSON definition.\n */\nfunction createRepeatNode(\n tokens: string[],\n stringLiteralPlaceholders: StringLiteralPlaceholders\n): RepeatNodeDefinition {\n let node = { type: \"repeat\" } as RepeatNodeDefinition;\n\n // Get the node arguments.\n const nodeArguments = parseArgumentTokens(tokens, stringLiteralPlaceholders);\n\n // The arguments of a repeat node are optional. We may have:\n // - No node arguments, in which case the repeat note will iterate indefinitely.\n // - One node argument which will be the explicit number of iterations to make.\n // - Two node arguments which define the min and max iteration bounds from which a random iteration count will be picked.\n if (nodeArguments.length) {\n // All repeat node arguments MUST be of type number and must be integer.\n nodeArguments\n .filter((arg) => arg.type !== \"number\" || !arg.isInteger)\n .forEach(() => {\n throw new Error(`repeat node iteration counts must be integer values`);\n });\n\n // We should have got one or two iteration counts.\n if (nodeArguments.length === 1) {\n // A static iteration count was defined.\n node.iterations = nodeArguments[0].value as number;\n\n // A repeat node must have a positive number of iterations if defined.\n if (node.iterations < 0) {\n throw new Error(\"a repeat node must have a positive number of iterations if defined\");\n }\n } else if (nodeArguments.length === 2) {\n // A minimum and maximum iteration count was defined.\n node.iterations = [nodeArguments[0].value as number, nodeArguments[1].value as number];\n\n // A repeat node must have a positive min and max iteration count if they are defined.\n if (node.iterations[0] < 0 || node.iterations[1] < 0) {\n throw new Error(\"a repeat node must have a positive minimum and maximum iteration count if defined\");\n }\n\n // A repeat node must not have an minimum iteration count that exceeds the maximum iteration count.\n if (node.iterations[0] > node.iterations[1]) {\n throw new Error(\n \"a repeat node must not have a minimum iteration count that exceeds the maximum iteration count\"\n );\n }\n } else {\n // An incorrect number of iteration counts was defined.\n throw new Error(\"invalid number of repeat node iteration count arguments defined\");\n }\n }\n\n // Grab any node attribute definitions and spread them into the node definition.\n node = { ...node, ...parseAttributeTokens(tokens, stringLiteralPlaceholders) };\n\n // This is a decorator node, so we expect an opening '{'.\n popAndCheck(tokens, \"{\");\n\n // Return the repeat node definition.\n return node;\n}\n\n/**\n * Creates a retry node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The retry node JSON definition.\n */\nfunction createRetryNode(tokens: string[], stringLiteralPlaceholders: StringLiteralPlaceholders): RetryNodeDefinition {\n let node = { type: \"retry\" } as RetryNodeDefinition;\n\n // Get the node arguments.\n const nodeArguments = parseArgumentTokens(tokens, stringLiteralPlaceholders);\n\n // The arguments of a retry node are optional. We may have:\n // - No node arguments, in which case the retry note will attempt indefinitely.\n // - One node argument which will be the explicit number of attempts to make.\n // - Two node arguments which define the min and max attempt bounds from which a random attempt count will be picked.\n if (nodeArguments.length) {\n // All retry node arguments MUST be of type number and must be integer.\n nodeArguments\n .filter((arg) => arg.type !== \"number\" || !arg.isInteger)\n .forEach(() => {\n throw new Error(`retry node attempt counts must be integer values`);\n });\n\n // We should have got one or two attempt counts.\n if (nodeArguments.length === 1) {\n // A static attempt count was defined.\n node.attempts = nodeArguments[0].value as number;\n\n // A retry node must have a positive number of attempts if defined.\n if (node.attempts < 0) {\n throw new Error(\"a retry node must have a positive number of attempts if defined\");\n }\n } else if (nodeArguments.length === 2) {\n // A minimum and maximum attempt count was defined.\n node.attempts = [nodeArguments[0].value as number, nodeArguments[1].value as number];\n\n // A retry node must have a positive min and max attempts count if they are defined.\n if (node.attempts[0] < 0 || node.attempts[1] < 0) {\n throw new Error(\"a retry node must have a positive minimum and maximum attempt count if defined\");\n }\n\n // A retry node must not have a minimum attempt count that exceeds the maximum attempt count.\n if (node.attempts[0] > node.attempts[1]) {\n throw new Error(\n \"a retry node must not have a minimum attempt count that exceeds the maximum attempt count\"\n );\n }\n } else {\n // An incorrect number of attempt counts was defined.\n throw new Error(\"invalid number of retry node attempt count arguments defined\");\n }\n }\n\n // Grab any node attribute definitions and spread them into the node definition.\n node = { ...node, ...parseAttributeTokens(tokens, stringLiteralPlaceholders) };\n\n // This is a decorator node, so we expect an opening '{'.\n popAndCheck(tokens, \"{\");\n\n // Return the retry node definition.\n return node;\n}\n\n/**\n * Creates a sequence node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The sequence node JSON definition.\n */\nfunction createSequenceNode(\n tokens: string[],\n stringLiteralPlaceholders: StringLiteralPlaceholders\n): SequenceNodeDefinition {\n const node = {\n type: \"sequence\",\n ...parseAttributeTokens(tokens, stringLiteralPlaceholders)\n } as SequenceNodeDefinition;\n\n // This is a composite node, so we expect an opening '{'.\n popAndCheck(tokens, \"{\");\n\n // Return the sequence node definition.\n return node;\n}\n\n/**\n * Creates a selector node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The selector node JSON definition.\n */\nfunction createSelectorNode(\n tokens: string[],\n stringLiteralPlaceholders: StringLiteralPlaceholders\n): SelectorNodeDefinition {\n const node = {\n type: \"selector\",\n ...parseAttributeTokens(tokens, stringLiteralPlaceholders)\n } as SelectorNodeDefinition;\n\n // This is a composite node, so we expect an opening '{'.\n popAndCheck(tokens, \"{\");\n\n // Return the selector node definition.\n return node;\n}\n\n/**\n * Creates a parallel node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The parallel node JSON definition.\n */\nfunction createParallelNode(\n tokens: string[],\n stringLiteralPlaceholders: StringLiteralPlaceholders\n): ParallelNodeDefinition {\n const node = {\n type: \"parallel\",\n ...parseAttributeTokens(tokens, stringLiteralPlaceholders)\n } as ParallelNodeDefinition;\n\n // This is a composite node, so we expect an opening '{'.\n popAndCheck(tokens, \"{\");\n\n // Return the parallel node definition.\n return node;\n}\n\n/**\n * Creates a lotto node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The lotto node JSON definition.\n */\nfunction createLottoNode(tokens: string[], stringLiteralPlaceholders: StringLiteralPlaceholders): LottoNodeDefinition {\n // If any node arguments have been defined then they must be our weights.\n const nodeArguments = parseArgumentTokens(tokens, stringLiteralPlaceholders);\n\n // All lotto node arguments MUST be of type number and must be positive integers.\n nodeArguments\n .filter((arg) => arg.type !== \"number\" || !arg.isInteger || arg.value < 0)\n .forEach(() => {\n throw new Error(`lotto node weight arguments must be positive integer values`);\n });\n\n const node = {\n type: \"lotto\",\n ...parseAttributeTokens(tokens, stringLiteralPlaceholders)\n } as LottoNodeDefinition;\n\n // Apply the weights if any were defined.\n if (nodeArguments.length) {\n node.weights = nodeArguments.map(({ value }) => value) as number[];\n }\n\n // This is a composite node, so we expect an opening '{'.\n popAndCheck(tokens, \"{\");\n\n // Return the lotto node definition.\n return node;\n}\n\n/**\n * Creates an action node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The action node JSON definition.\n */\nfunction createActionNode(\n tokens: string[],\n stringLiteralPlaceholders: StringLiteralPlaceholders\n): ActionNodeDefinition {\n // Parse any node arguments, we should have at least one which will be an identifier argument for the action name\n // and agent function to invoke for the action, all other arguments are to be passed as arguments to that function.\n const [actionNameIdentifier, ...agentFunctionArgs] = parseArgumentTokens(tokens, stringLiteralPlaceholders);\n\n // Our first argument MUST be defined and be an identifier as we require an action name argument.\n if (actionNameIdentifier?.type !== \"identifier\") {\n throw new Error(\"expected action name identifier argument\");\n }\n\n // Only the first argument should have been an identifier, all agent function arguments must be string, number, boolean or null.\n agentFunctionArgs\n .filter((arg) => arg.type === \"identifier\")\n .forEach((arg) => {\n throw new Error(\n `invalid action node argument value '${arg.value}', must be string, number, boolean or null`\n );\n });\n\n // Return the action node definition.\n return {\n type: \"action\",\n call: actionNameIdentifier.value,\n args: agentFunctionArgs.map(({ value }) => value),\n ...parseAttributeTokens(tokens, stringLiteralPlaceholders)\n };\n}\n\n/**\n * Creates a condition node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The condition node JSON definition.\n */\nfunction createConditionNode(\n tokens: string[],\n stringLiteralPlaceholders: StringLiteralPlaceholders\n): ConditionNodeDefinition {\n // Parse any node arguments, we should have at least one which will be an identifier argument for the condition name\n // and agent function to invoke for the condition, all other arguments are to be passed as arguments to that function.\n const [conditionNameIdentifier, ...agentFunctionArgs] = parseArgumentTokens(tokens, stringLiteralPlaceholders);\n\n // Our first argument MUST be defined and be an identifier as we require a condition name argument.\n if (conditionNameIdentifier?.type !== \"identifier\") {\n throw new Error(\"expected condition name identifier argument\");\n }\n\n // Only the first argument should have been an identifier, all agent function arguments must be string, number, boolean or null.\n agentFunctionArgs\n .filter((arg) => arg.type === \"identifier\")\n .forEach((arg) => {\n throw new Error(\n `invalid condition node argument value '${arg.value}', must be string, number, boolean or null`\n );\n });\n\n // Return the condition node definition.\n return {\n type: \"condition\",\n call: conditionNameIdentifier.value,\n args: agentFunctionArgs.map(({ value }) => value),\n ...parseAttributeTokens(tokens, stringLiteralPlaceholders)\n };\n}\n\n/**\n * Creates a wait node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The wait node JSON definition.\n */\nfunction createWaitNode(tokens: string[], stringLiteralPlaceholders: StringLiteralPlaceholders): WaitNodeDefinition {\n let node = { type: \"wait\" } as WaitNodeDefinition;\n\n // Get the node arguments.\n const nodeArguments = parseArgumentTokens(tokens, stringLiteralPlaceholders);\n\n // The arguments of a wait node are optional. We may have:\n // - No node arguments, in which case the wait will be indefinite until it is aborted.\n // - One node argument which will be the explicit duration of the wait.\n // - Two node arguments which define the min and max duration bounds from which a random duration will be picked.\n if (nodeArguments.length) {\n // All wait node arguments MUST be of type number and must be integer.\n nodeArguments\n .filter((arg) => arg.type !== \"number\" || !arg.isInteger)\n .forEach(() => {\n throw new Error(`wait node durations must be integer values`);\n });\n\n // We may have:\n // - One node argument which will be the explicit duration of the wait.\n // - Two node arguments which define the min and max duration bounds from which a random duration will be picked.\n // - Too many arguments, which is not valid.\n if (nodeArguments.length === 1) {\n // An explicit duration was defined.\n node.duration = nodeArguments[0].value as number;\n\n // If an explict duration was defined then it must be a positive number.\n if (node.duration < 0) {\n throw new Error(\"a wait node must have a positive duration\");\n }\n } else if (nodeArguments.length === 2) {\n // Min and max duration bounds were defined from which a random duration will be picked.\n node.duration = [nodeArguments[0].value as number, nodeArguments[1].value as number];\n\n // A wait node must have a positive min and max duration.\n if (node.duration[0] < 0 || node.duration[1] < 0) {\n throw new Error(\"a wait node must have a positive minimum and maximum duration\");\n }\n\n // A wait node must not have a minimum duration that exceeds the maximum duration.\n if (node.duration[0] > node.duration[1]) {\n throw new Error(\"a wait node must not have a minimum duration that exceeds the maximum duration\");\n }\n } else if (nodeArguments.length > 2) {\n // An incorrect number of duration arguments were defined.\n throw new Error(\"invalid number of wait node duration arguments defined\");\n }\n }\n\n // Return the wait node definition.\n return { ...node, ...parseAttributeTokens(tokens, stringLiteralPlaceholders) };\n}\n\n/**\n * Creates a branch node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The branch node JSON definition.\n */\nfunction createBranchNode(\n tokens: string[],\n stringLiteralPlaceholders: StringLiteralPlaceholders\n): BranchNodeDefinition {\n // Parse any node arguments, we should have one which will be an identifier argument for the root ref.\n const nodeArguments = parseArgumentTokens(tokens, stringLiteralPlaceholders);\n\n // We should have only a single identifer argument for a branch node, which is the root ref.\n if (nodeArguments.length !== 1 || nodeArguments[0].type !== \"identifier\") {\n throw new Error(\"expected single branch name argument\");\n }\n\n // Return the branch node definition.\n return { type: \"branch\", ref: nodeArguments[0].value };\n}\n\n/**\n * Validate a fully-populated node definition that was popped off of the tree stack.\n * @param definition The popped node to validate.\n */\nfunction validatePoppedNode(definition: AnyNodeDefinition): void {\n // Decorators MUST have a child defined.\n if (isDecoratorNode(definition) && isNullOrUndefined(definition.child)) {\n throw new Error(`a ${definition.type} node must have a single child node defined`);\n }\n\n // Composites MUST have at least one child defined.\n if (isCompositeNode(definition) && !definition.children?.length) {\n throw new Error(`a ${definition.type} node must have at least a single child node defined`);\n }\n\n // We need to make sure that lotto nodes that have weights defined have a number of weights matching the number of child nodes.\n if (definition.type === \"lotto\") {\n // Check whether a 'weights' property has been defined, if it has we expect it to be an array of weights.\n if (typeof definition.weights !== \"undefined\") {\n // Check that the weights property is an array of positive integers with an element for each child node element.\n if (definition.weights.length !== definition.children.length) {\n throw new Error(\n \"expected a number of weight arguments matching the number of child nodes for lotto node\"\n );\n }\n }\n }\n}\n", "import { RootNodeDefinition } from \"./BehaviourTreeDefinition\";\nimport { flattenDefinition, isBranchNode, isInteger } from \"./BehaviourTreeDefinitionUtilities\";\nimport { convertMDSLToJSON } from \"./mdsl/MDSLDefinitionParser\";\n\n/**\n * An object representing the result of validating a tree definition.\n */\nexport type DefinitionValidationResult = {\n /**\n * A flag defining whether validation succeeded.\n */\n succeeded: boolean;\n /**\n * A string containing the error message if validation did not succeed.\n */\n errorMessage?: string;\n /**\n * The definition as json if the validation was successful, or undefined if validation did not succeed.\n */\n json?: RootNodeDefinition[];\n};\n\n/**\n * Validates the specified behaviour tree definition in the form of JSON or MDSL, not taking any globally registered subtrees into consideration.\n * @param definition The behaviour tree definition in the form of JSON or MDSL.\n * @returns An object representing the result of validating the given tree definition.\n */\nexport function validateDefinition(definition: any): DefinitionValidationResult {\n // The definition must be defined.\n if (definition === null || typeof definition === \"undefined\") {\n return createValidationFailureResult(\"definition is null or undefined\");\n }\n\n // We are expecting a definition in one of three different forms:\n // - A string which we will assume is MDSL and we will parse this to JSON before validation.\n // - An array which we will assume is an array of root node definitions with at least one being the primary root node (no 'id' property)\n // - An object which we will assume is the primary root node and should not have an 'id' property.\n if (typeof definition === \"string\") {\n // The definition is a string which we can assume is MDSL, so attempt to validate it.\n return validateMDSLDefinition(definition);\n } else if (typeof definition === \"object\") {\n // The definition will either be an array (of root node definitions) or an object (the single primary root node definition).\n return validateJSONDefinition(definition);\n } else {\n return createValidationFailureResult(`unexpected definition type of '${typeof definition}'`);\n }\n}\n\n/**\n * Validates the specified behaviour tree definition in the form of MDSL.\n * @param definition The behaviour tree definition in the form of MDSL.\n * @returns An object representing the result of validating the given tree definition.\n */\nfunction validateMDSLDefinition(definition: string): DefinitionValidationResult {\n let rootNodeDefinitions;\n\n // The first thing the we need to do is to attempt to convert our MDSL into JSON.\n try {\n // The definition is a string which we can assume is MDSL, so attempt to parse it to a JSON definition in the form of an array of root node definitions.\n rootNodeDefinitions = convertMDSLToJSON(definition);\n } catch (exception) {\n // We failed to parse the JSON from the MDSL, this is likely to be the result of it not being a valid MDSL string.\n return createValidationFailureResult((exception as Error).message);\n }\n\n // Unpack all of the root node definitions into arrays of main ('id' defined) and sub ('id' not defined) root node definitions.\n const mainRootNodeDefinitions = rootNodeDefinitions.filter(({ id }) => typeof id === \"undefined\");\n const subRootNodeDefinitions = rootNodeDefinitions.filter(({ id }) => typeof id === \"string\" && id.length > 0);\n\n // We should ALWAYS have exactly one root node definition without an 'id' property defined, which is out main root node definition.\n if (mainRootNodeDefinitions.length !== 1) {\n return createValidationFailureResult(\n \"expected single unnamed root node at base of definition to act as main root\"\n );\n }\n\n // We should never have duplicate 'id' properties across our sub root node definitions.\n const subRootNodeIdenitifers: string[] = [];\n for (const { id } of subRootNodeDefinitions) {\n // Have we already come across this 'id' property value?\n if (subRootNodeIdenitifers.includes(id!)) {\n return createValidationFailureResult(`multiple root nodes found with duplicate name '${id}'`);\n }\n\n subRootNodeIdenitifers.push(id!);\n }\n\n try {\n // Validate our branch -> subtree links and check for any circular dependencies, we don't care about checking for broken subtree links here.\n validateBranchSubtreeLinks(rootNodeDefinitions, false);\n } catch (exception) {\n return createValidationFailureResult((exception as Error).message);\n }\n\n // Our definition was valid!\n return {\n succeeded: true,\n json: rootNodeDefinitions\n };\n}\n\n/**\n * Validates the specified behaviour tree definition in the form of JSON.\n * @param definition The behaviour tree definition in the form of JSON.\n * @returns An object representing the result of validating the given tree definition.\n */\nexport function validateJSONDefinition(\n definition: RootNodeDefinition | RootNodeDefinition[]\n): DefinitionValidationResult {\n // The definition will either be an array (of root node definitions) or an object (the single primary root node definition).\n const rootNodeDefinitions = Array.isArray(definition) ? definition : [definition];\n\n // Iterate over our array of root nodes and call validateNode for each, passing an initial depth of 0, wrapped in a try catch to handle validation failures.\n try {\n rootNodeDefinitions.forEach((rootNodeDefinition) => validateNode(rootNodeDefinition, 0));\n } catch (error) {\n // Handle cases where we have caught a thrown Error and return a failure result with the error message.\n if (error instanceof Error) {\n return createValidationFailureResult(error.message);\n }\n\n // No idea what happened here!\n return createValidationFailureResult(`unexpected error: ${error}`);\n }\n\n // Unpack all of the root node definitions into arrays of main ('id' defined) and sub ('id' not defined) root node definitions.\n const mainRootNodeDefinitions = rootNodeDefinitions.filter(({ id }) => typeof id === \"undefined\");\n const subRootNodeDefinitions = rootNodeDefinitions.filter(({ id }) => typeof id === \"string\" && id.length > 0);\n\n // We should ALWAYS have exactly one root node definition without an 'id' property defined, which is out main root node definition.\n if (mainRootNodeDefinitions.length !== 1) {\n return createValidationFailureResult(\n \"expected single root node without 'id' property defined to act as main root\"\n );\n }\n\n // We should never have duplicate 'id' properties across our sub root node definitions.\n const subRootNodeIdenitifers: string[] = [];\n for (const { id } of subRootNodeDefinitions) {\n // Have we already come across this 'id' property value?\n if (subRootNodeIdenitifers.includes(id!)) {\n return createValidationFailureResult(\n `multiple root nodes found with duplicate 'id' property value of '${id}'`\n );\n }\n\n subRootNodeIdenitifers.push(id!);\n }\n\n try {\n // Validate our branch -> subtree links and check for any circular dependencies, we don't care about checking for broken subtree links here.\n validateBranchSubtreeLinks(rootNodeDefinitions, false);\n } catch (exception) {\n return createValidationFailureResult((exception as Error).message);\n }\n\n // Our definition was valid!\n return {\n succeeded: true,\n json: rootNodeDefinitions\n };\n}\n\n/**\n * Validates the branch -> subtree links across all provided root node definitions.\n * This will not consider branch nodes that reference any globally registered subtrees unless includesGlobalSubtrees\n * is set to true, in which case we will also verify that there are no broken branch -> subtree links.\n * @param rootNodeDefinitions The array of root node definitions.\n * @param includesGlobalSubtrees A flag defining whether the array includes all global subtree root node definitions.\n */\nexport function validateBranchSubtreeLinks(rootNodeDefinitions: RootNodeDefinition[], includesGlobalSubtrees: boolean) {\n // Create a mapping of root node identifiers to other root nodes that they reference via branch nodes.\n // Below is an example of a mapping that includes a circular dependency (root => a => b => c => a)\n // [{ refs: [\"a\", \"b\"] }, { id: \"a\", refs: [\"b\"] }, { id: \"b\", refs: [\"c\"] }, { id: \"c\", refs: [\"a\"] }]\n const rootNodeMappings: { id: string | undefined; refs: string[] }[] = rootNodeDefinitions.map(\n (rootNodeDefinition) => ({\n id: rootNodeDefinition.id,\n refs: flattenDefinition(rootNodeDefinition)\n .filter(isBranchNode)\n .map(({ ref }) => ref)\n })\n );\n\n // A recursive function to walk through the mappings, keeping track of which root nodes we have visited in the form of a path of root node identifiers.\n const followRefs = (mapping: { id: string | undefined; refs: string[] }, path: (string | undefined)[] = []) => {\n // Have we found a circular dependency?\n if (path.includes(mapping.id)) {\n // We found a circular dependency! Get the bad path of root node identifiers.\n const badPath = [...path, mapping.id];\n\n // Create the formatted path value. [undefined, \"a\", \"b\", \"c\", \"a\"] would be formatted as \"a -> b -> c -> a\".\n const badPathFormatted = badPath.filter((element) => !!element).join(\" => \");\n\n // No need to continue, we found a circular dependency.\n throw new Error(`circular dependency found in branch node references: ${badPathFormatted}`);\n }\n\n for (const ref of mapping.refs) {\n // Find the mapping for the root node with an identifer matching the current ref.\n const subMapping = rootNodeMappings.find(({ id }) => id === ref);\n\n // We may not have a mapping for this ref, which is normal when we aren't considering all globally registered subtrees.\n if (subMapping) {\n followRefs(subMapping, [...path, mapping.id]);\n } else if (includesGlobalSubtrees) {\n // We found a reference to a root node that doesn't exist, which is a problem seeing as the root node definitons includes all globally registered subtrees.\n throw new Error(\n mapping.id\n ? `subtree '${mapping.id}' has branch node that references root node '${ref}' which has not been defined`\n : `primary tree has branch node that references root node '${ref}' which has not been defined`\n );\n }\n }\n };\n\n // Start looking for circular dependencies and broken references from the primary root node definition.\n followRefs(rootNodeMappings.find((mapping) => typeof mapping.id === \"undefined\")!);\n}\n\n/**\n * Validate an object that we expect to be a node definition.\n * @param definition An object that we expect to be a node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateNode(definition: any, depth: number): void {\n // Every node must be valid object and have a non-empty 'type' string property.\n if (typeof definition !== \"object\" || typeof definition.type !== \"string\" || definition.type.length === 0) {\n throw new Error(\n `node definition is not an object or 'type' property is not a non-empty string at depth '${depth}'`\n );\n }\n\n // How we validate this node definition will depend on its type.\n switch (definition.type) {\n case \"action\":\n validateActionNode(definition, depth);\n break;\n\n case \"condition\":\n validateConditionNode(definition, depth);\n break;\n\n case \"wait\":\n validateWaitNode(definition, depth);\n break;\n\n case \"branch\":\n validateBranchNode(definition, depth);\n break;\n\n case \"root\":\n validateRootNode(definition, depth);\n break;\n\n case \"succeed\":\n validateSucceedNode(definition, depth);\n break;\n\n case \"fail\":\n validateFailNode(definition, depth);\n break;\n\n case \"flip\":\n validateFlipNode(definition, depth);\n break;\n\n case \"repeat\":\n validateRepeatNode(definition, depth);\n break;\n\n case \"retry\":\n validateRetryNode(definition, depth);\n break;\n\n case \"sequence\":\n validateSequenceNode(definition, depth);\n break;\n\n case \"selector\":\n validateSelectorNode(definition, depth);\n break;\n\n case \"parallel\":\n validateParallelNode(definition, depth);\n break;\n\n case \"lotto\":\n validateLottoNode(definition, depth);\n break;\n\n default:\n throw new Error(`unexpected node type of '${definition.type}' at depth '${depth}'`);\n }\n}\n\n/**\n * Validate any attributes for a given node definition.\n * @param definition The node definition.\n * @param depth The depth of the node in the behaviour tree definition.\n */\nfunction validateNodeAttributes(definition: any, depth: number): void {\n // Validate each of the attribute types for this node.\n [\"while\", \"until\", \"entry\", \"exit\", \"step\"].forEach((attributeName) => {\n // Attempt to grab the definition for the current attribute from the node definition.\n const attributeDefinition = definition[attributeName];\n\n // All node attributes are optional, so there is nothing to do if the current attribute is not defined.\n if (typeof attributeDefinition === \"undefined\") {\n return;\n }\n\n // The attribute definition must be an object.\n if (typeof attributeDefinition !== \"object\") {\n throw new Error(\n `expected attribute '${attributeName}' to be an object for '${definition.type}' node at depth '${depth}'`\n );\n }\n\n // The 'call' property must be defined for any attribute definition.\n if (typeof attributeDefinition.call !== \"string\" || attributeDefinition.call.length === 0) {\n throw new Error(\n `expected 'call' property for attribute '${attributeName}' to be a non-empty string for '${definition.type}' node at depth '${depth}'`\n );\n }\n\n // If any node attribute arguments have been defined then they must have been defined in an array.\n if (typeof attributeDefinition.args !== \"undefined\" && !Array.isArray(attributeDefinition.args)) {\n throw new Error(\n `expected 'args' property for attribute '${attributeName}' to be an array for '${definition.type}' node at depth '${depth}'`\n );\n }\n });\n}\n\n/**\n * Validate an object that we expect to be a root node definition.\n * @param definition An object that we expect to be a root node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateRootNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"root\") {\n throw new Error(\"expected node type of 'root' for root node\");\n }\n\n // A root node cannot be the child of another node.\n if (depth > 0) {\n throw new Error(\"a root node cannot be the child of another node\");\n }\n\n // Check that, if the root node 'id' property is defined, it is a non-empty string.\n if (typeof definition.id !== \"undefined\" && (typeof definition.id !== \"string\" || definition.id.length === 0)) {\n throw new Error(\"expected non-empty string for 'id' property if defined for root node\");\n }\n\n // A root node is a decorator node, so must have a child node defined.\n if (typeof definition.child === \"undefined\") {\n throw new Error(\"expected property 'child' to be defined for root node\");\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n\n // Validate the child node of this decorator node.\n validateNode(definition.child, depth + 1);\n}\n\n/**\n * Validate an object that we expect to be a succeed node definition.\n * @param definition An object that we expect to be a succeed node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateSucceedNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"succeed\") {\n throw new Error(`expected node type of 'succeed' for succeed node at depth '${depth}'`);\n }\n\n // A succeed node is a decorator node, so must have a child node defined.\n if (typeof definition.child === \"undefined\") {\n throw new Error(`expected property 'child' to be defined for succeed node at depth '${depth}'`);\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n\n // Validate the child node of this decorator node.\n validateNode(definition.child, depth + 1);\n}\n\n/**\n * Validate an object that we expect to be a fail node definition.\n * @param definition An object that we expect to be a fail node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateFailNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"fail\") {\n throw new Error(`expected node type of 'fail' for fail node at depth '${depth}'`);\n }\n\n // A fail node is a decorator node, so must have a child node defined.\n if (typeof definition.child === \"undefined\") {\n throw new Error(`expected property 'child' to be defined for fail node at depth '${depth}'`);\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n\n // Validate the child node of this decorator node.\n validateNode(definition.child, depth + 1);\n}\n\n/**\n * Validate an object that we expect to be a flip node definition.\n * @param definition An object that we expect to be a flip node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateFlipNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"flip\") {\n throw new Error(`expected node type of 'flip' for flip node at depth '${depth}'`);\n }\n\n // A flip node is a decorator node, so must have a child node defined.\n if (typeof definition.child === \"undefined\") {\n throw new Error(`expected property 'child' to be defined for flip node at depth '${depth}'`);\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n\n // Validate the child node of this decorator node.\n validateNode(definition.child, depth + 1);\n}\n\n/**\n * Validate an object that we expect to be a repeat node definition.\n * @param definition An object that we expect to be a repeat node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateRepeatNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"repeat\") {\n throw new Error(`expected node type of 'repeat' for repeat node at depth '${depth}'`);\n }\n\n // A repeat node is a decorator node, so must have a child node defined.\n if (typeof definition.child === \"undefined\") {\n throw new Error(`expected property 'child' to be defined for repeat node at depth '${depth}'`);\n }\n\n // Check whether an 'iterations' property has been defined, it may not have been if this node is to repeat indefinitely.\n if (typeof definition.iterations !== \"undefined\") {\n if (Array.isArray(definition.iterations)) {\n // Check whether any elements of the array are not integer values.\n const containsNonInteger = !!definition.iterations.filter((value: unknown) => !isInteger(value)).length;\n\n // If the 'iterations' property is an array then it MUST contain two integer values.\n if (definition.iterations.length !== 2 || containsNonInteger) {\n throw new Error(\n `expected array containing two integer values for 'iterations' property if defined for repeat node at depth '${depth}'`\n );\n }\n\n // A repeat node must have a positive min and max iterations count if they are defined.\n if (definition.iterations[0] < 0 || definition.iterations[1] < 0) {\n throw new Error(\n `expected positive minimum and maximum iterations count for 'iterations' property if defined for repeat node at depth '${depth}'`\n );\n }\n\n // A repeat node must not have a minimum iterations count that exceeds the maximum iterations count.\n if (definition.iterations[0] > definition.iterations[1]) {\n throw new Error(\n `expected minimum iterations count that does not exceed the maximum iterations count for 'iterations' property if defined for repeat node at depth '${depth}'`\n );\n }\n } else if (isInteger(definition.iterations)) {\n // A repeat node must have a positive number of iterations if defined.\n if (definition.iterations < 0) {\n throw new Error(\n `expected positive iterations count for 'iterations' property if defined for repeat node at depth '${depth}'`\n );\n }\n } else {\n throw new Error(\n `expected integer value or array containing two integer values for 'iterations' property if defined for repeat node at depth '${depth}'`\n );\n }\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n\n // Validate the child node of this decorator node.\n validateNode(definition.child, depth + 1);\n}\n\n/**\n * Validate an object that we expect to be a retry node definition.\n * @param definition An object that we expect to be a retry node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateRetryNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"retry\") {\n throw new Error(`expected node type of 'retry' for retry node at depth '${depth}'`);\n }\n\n // A retry node is a decorator node, so must have a child node defined.\n if (typeof definition.child === \"undefined\") {\n throw new Error(`expected property 'child' to be defined for retry node at depth '${depth}'`);\n }\n\n // Check whether an 'attempts' property has been defined, it may not have been if this node is to retry indefinitely.\n if (typeof definition.attempts !== \"undefined\") {\n if (Array.isArray(definition.attempts)) {\n // Check whether any elements of the array are not integer values.\n const containsNonInteger = !!definition.attempts.filter((value: unknown) => !isInteger(value)).length;\n\n // If the 'attempts' property is an array then it MUST contain two integer values.\n if (definition.attempts.length !== 2 || containsNonInteger) {\n throw new Error(\n `expected array containing two integer values for 'attempts' property if defined for retry node at depth '${depth}'`\n );\n }\n\n // A retry node must have a positive min and max attempts count if they are defined.\n if (definition.attempts[0] < 0 || definition.attempts[1] < 0) {\n throw new Error(\n `expected positive minimum and maximum attempts count for 'attempts' property if defined for retry node at depth '${depth}'`\n );\n }\n\n // A retry node must not have a minimum attempts count that exceeds the maximum attempts count.\n if (definition.attempts[0] > definition.attempts[1]) {\n throw new Error(\n `expected minimum attempts count that does not exceed the maximum attempts count for 'attempts' property if defined for retry node at depth '${depth}'`\n );\n }\n } else if (isInteger(definition.attempts)) {\n // A retry node must have a positive number of attempts if defined.\n if (definition.attempts < 0) {\n throw new Error(\n `expected positive attempts count for 'attempts' property if defined for retry node at depth '${depth}'`\n );\n }\n } else {\n throw new Error(\n `expected integer value or array containing two integer values for 'attempts' property if defined for retry node at depth '${depth}'`\n );\n }\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n\n // Validate the child node of this decorator node.\n validateNode(definition.child, depth + 1);\n}\n\n/**\n * Validate an object that we expect to be a branch node definition.\n * @param definition An object that we expect to be a branch node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateBranchNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"branch\") {\n throw new Error(`expected node type of 'branch' for branch node at depth '${depth}'`);\n }\n\n // Check that the branch node 'ref' property is defined and is a non-empty string.\n if (typeof definition.ref !== \"string\" || definition.ref.length === 0) {\n throw new Error(`expected non-empty string for 'ref' property for branch node at depth '${depth}'`);\n }\n\n // It is invalid to define guard attributes for a branch node as they should be defined on the referenced root node.\n [\"while\", \"until\"].forEach((attributeName) => {\n if (typeof definition[attributeName] !== \"undefined\") {\n throw new Error(\n `guards should not be defined for branch nodes but guard '${attributeName}' was defined for branch node at depth '${depth}'`\n );\n }\n });\n\n // It is invalid to define callback attributes for a branch node as they should be defined on the referenced root node.\n [\"entry\", \"exit\", \"step\"].forEach((attributeName) => {\n if (typeof definition[attributeName] !== \"undefined\") {\n throw new Error(\n `callbacks should not be defined for branch nodes but callback '${attributeName}' was defined for branch node at depth '${depth}'`\n );\n }\n });\n}\n\n/**\n * Validate an object that we expect to be a action node definition.\n * @param definition An object that we expect to be a action node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateActionNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"action\") {\n throw new Error(`expected node type of 'action' for action node at depth '${depth}'`);\n }\n\n // The 'call' property must be defined for a action node definition.\n if (typeof definition.call !== \"string\" || definition.call.length === 0) {\n throw new Error(`expected non-empty string for 'call' property of action node at depth '${depth}'`);\n }\n\n // If any action function arguments have been defined then they must have been defined in an array.\n if (typeof definition.args !== \"undefined\" && !Array.isArray(definition.args)) {\n throw new Error(`expected array for 'args' property if defined for action node at depth '${depth}'`);\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n}\n\n/**\n * Validate an object that we expect to be a condition node definition.\n * @param definition An object that we expect to be a condition node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateConditionNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"condition\") {\n throw new Error(`expected node type of 'condition' for condition node at depth '${depth}'`);\n }\n\n // The 'call' property must be defined for a condition node definition.\n if (typeof definition.call !== \"string\" || definition.call.length === 0) {\n throw new Error(`expected non-empty string for 'call' property of condition node at depth '${depth}'`);\n }\n\n // If any condition function arguments have been defined then they must have been defined in an array.\n if (typeof definition.args !== \"undefined\" && !Array.isArray(definition.args)) {\n throw new Error(`expected array for 'args' property if defined for condition node at depth '${depth}'`);\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n}\n\n/**\n * Validate an object that we expect to be a wait node definition.\n * @param definition An object that we expect to be a wait node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateWaitNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"wait\") {\n throw new Error(`expected node type of 'wait' for wait node at depth '${depth}'`);\n }\n\n // Check whether a 'duration' property has been defined, it may not have been if this node is to wait indefinitely.\n if (typeof definition.duration !== \"undefined\") {\n if (Array.isArray(definition.duration)) {\n // Check whether any elements of the array are not integer values.\n const containsNonInteger = !!definition.duration.filter((value: unknown) => !isInteger(value)).length;\n\n // If the 'duration' property is an array then it MUST contain two integer values.\n if (definition.duration.length !== 2 || containsNonInteger) {\n throw new Error(\n `expected array containing two integer values for 'duration' property if defined for wait node at depth '${depth}'`\n );\n }\n\n // A wait node must have a positive min and max duration value if they are defined.\n if (definition.duration[0] < 0 || definition.duration[1] < 0) {\n throw new Error(\n `expected positive minimum and maximum duration for 'duration' property if defined for wait node at depth '${depth}'`\n );\n }\n\n // A wait node must not have a minimum duration value that exceeds the maximum duration value.\n if (definition.duration[0] > definition.duration[1]) {\n throw new Error(\n `expected minimum duration value that does not exceed the maximum duration value for 'duration' property if defined for wait node at depth '${depth}'`\n );\n }\n } else if (isInteger(definition.duration)) {\n // A wait node must have a positive duration value if defined.\n if (definition.duration < 0) {\n throw new Error(\n `expected positive duration value for 'duration' property if defined for wait node at depth '${depth}'`\n );\n }\n } else {\n throw new Error(\n `expected integer value or array containing two integer values for 'duration' property if defined for wait node at depth '${depth}'`\n );\n }\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n}\n\n/**\n * Validate an object that we expect to be a sequence node definition.\n * @param definition An object that we expect to be a sequence node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateSequenceNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"sequence\") {\n throw new Error(`expected node type of 'sequence' for sequence node at depth '${depth}'`);\n }\n\n // A sequence node is a composite node, so must have a children nodes array defined.\n if (!Array.isArray(definition.children) || definition.children.length === 0) {\n throw new Error(`expected non-empty 'children' array to be defined for sequence node at depth '${depth}'`);\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n\n // Validate the child nodes of this composite node.\n definition.children.forEach((child: any) => validateNode(child, depth + 1));\n}\n\n/**\n * Validate an object that we expect to be a selector node definition.\n * @param definition An object that we expect to be a selector node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateSelectorNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"selector\") {\n throw new Error(`expected node type of 'selector' for selector node at depth '${depth}'`);\n }\n\n // A selector node is a composite node, so must have a children nodes array defined.\n if (!Array.isArray(definition.children) || definition.children.length === 0) {\n throw new Error(`expected non-empty 'children' array to be defined for selector node at depth '${depth}'`);\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n\n // Validate the child nodes of this composite node.\n definition.children.forEach((child: any) => validateNode(child, depth + 1));\n}\n\n/**\n * Validate an object that we expect to be a parallel node definition.\n * @param definition An object that we expect to be a parallel node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateParallelNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"parallel\") {\n throw new Error(`expected node type of 'parallel' for parallel node at depth '${depth}'`);\n }\n\n // A parallel node is a composite node, so must have a children nodes array defined.\n if (!Array.isArray(definition.children) || definition.children.length === 0) {\n throw new Error(`expected non-empty 'children' array to be defined for parallel node at depth '${depth}'`);\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n\n // Validate the child nodes of this composite node.\n definition.children.forEach((child: any) => validateNode(child, depth + 1));\n}\n\n/**\n * Validate an object that we expect to be a lotto node definition.\n * @param definition An object that we expect to be a lotto node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateLottoNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"lotto\") {\n throw new Error(`expected node type of 'lotto' for lotto node at depth '${depth}'`);\n }\n\n // A lotto node is a composite node, so must have a children nodes array defined.\n if (!Array.isArray(definition.children) || definition.children.length === 0) {\n throw new Error(`expected non-empty 'children' array to be defined for lotto node at depth '${depth}'`);\n }\n\n // Check whether a 'weights' property has been defined, if it has we expect it to be an array of weights.\n if (typeof definition.weights !== \"undefined\") {\n // Check that the weights property is an array of positive integers with an element for each child node element.\n if (\n !Array.isArray(definition.weights) ||\n definition.weights.length !== definition.children.length ||\n definition.weights.filter((value: unknown) => !isInteger(value)).length ||\n definition.weights.filter((value: number) => value < 0).length\n ) {\n throw new Error(\n `expected an array of positive integer weight values with a length matching the number of child nodes for 'weights' property if defined for lotto node at depth '${depth}'`\n );\n }\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n\n // Validate the child nodes of this composite node.\n definition.children.forEach((child: any) => validateNode(child, depth + 1));\n}\n\n/**\n * A helper function to create a failure validation result with the given error message.\n * @param errorMessage The validation failure error message.\n * @returns A failure validation result with the given error message.\n */\nfunction createValidationFailureResult(errorMessage: string): DefinitionValidationResult {\n return { succeeded: false, errorMessage };\n}\n", "import { ActionResult, Agent, GlobalFunction } from \"./Agent\";\nimport { RootNodeDefinition } from \"./BehaviourTreeDefinition\";\n\nexport type InvokerFunction = (args: any[]) => ActionResult | boolean;\n\n/**\n * A singleton used to store and lookup registered functions and subtrees.\n */\nexport default class Lookup {\n /**\n * The object holding any registered functions keyed on function name.\n */\n private static registeredFunctions: { [key: string]: GlobalFunction } = {};\n /**\n * The object holding any registered subtree root node definitions keyed on tree name.\n */\n private static registeredSubtrees: { [key: string]: RootNodeDefinition } = {};\n\n /**\n * Gets the function with the specified name.\n * @param name The name of the function.\n * @returns The function with the specified name.\n */\n public static getFunc(name: string): GlobalFunction {\n return this.registeredFunctions[name];\n }\n\n /**\n * Sets the function with the specified name for later lookup.\n * @param name The name of the function.\n * @param func The function.\n */\n public static setFunc(name: string, func: GlobalFunction): void {\n this.registeredFunctions[name] = func;\n }\n\n /**\n * Gets the function invoker for the specified agent and function name.\n * If a function with the specified name exists on the agent object then it will\n * be returned, otherwise we will then check the registered functions for a match.\n * @param agent The agent instance that this behaviour tree is modelling behaviour for.\n * @param name The function name.\n * @returns The function invoker for the specified agent and function name.\n */\n static getFuncInvoker(agent: Agent, name: string): InvokerFunction | null {\n // Check whether the agent contains the specified function.\n const agentFunction = agent[name];\n if (agentFunction && typeof agentFunction === \"function\") {\n return (args: any[]) => agentFunction.apply(agent, args);\n }\n\n // The agent does not contain the specified function but it may have been registered at some point.\n if (this.registeredFunctions[name] && typeof this.registeredFunctions[name] === \"function\") {\n const registeredFunction = this.registeredFunctions[name];\n return (args: any[]) => registeredFunction(agent, ...args);\n }\n\n // We have no function to invoke.\n return null;\n }\n\n /**\n * Gets all registered subtree root node definitions.\n */\n static getSubtrees(): { [key: string]: RootNodeDefinition } {\n return this.registeredSubtrees;\n }\n\n /**\n * Sets the subtree with the specified name for later lookup.\n * @param name The name of the subtree.\n * @param subtree The subtree.\n */\n static setSubtree(name: string, subtree: RootNodeDefinition) {\n this.registeredSubtrees[name] = subtree;\n }\n\n /**\n * Removes the registered function or subtree with the specified name.\n * @param name The name of the registered function or subtree.\n */\n static remove(name: string) {\n delete this.registeredFunctions[name];\n delete this.registeredSubtrees[name];\n }\n\n /**\n * Remove all registered functions and subtrees.\n */\n static empty() {\n this.registeredFunctions = {};\n this.registeredSubtrees = {};\n }\n}\n", "import Node from \"../../nodes/Node\";\n\n/**\n * An exception thrown when evaluating node guard path conditions and a conditions fails.\n */\nexport default class GuardUnsatisifedException extends Error {\n /**\n * @param source The node at which a guard condition failed.\n */\n constructor(private source: Node) {\n super(\"A guard path condition has failed\");\n }\n\n /**\n * Gets whether the specified node is the node at which a guard condition failed.\n * @param node The node to check against the source node.\n * @returns Whether the specified node is the node at which a guard condition failed.\n */\n isSourceNode = (node: Node) => node === this.source;\n}\n", "import { Agent } from \"../../Agent\";\nimport Guard from \"./Guard\";\nimport Node from \"../../nodes/Node\";\nimport GuardUnsatisifedException from \"./GuardUnsatisifedException\";\n\nexport type GuardPathPart = {\n node: Node;\n guards: Guard[];\n};\n\n/**\n * Represents a path of node guards along a root-to-leaf tree path.\n */\nexport default class GuardPath {\n /**\n * @param nodes An array of objects defining a node instance -> guard link, ordered by node depth.\n */\n constructor(private nodes: GuardPathPart[]) {}\n\n /**\n * Evaluate guard conditions for all guards in the tree path, moving outwards from the root.\n * @param agent The agent, required for guard evaluation.\n * @returns An evaluation results object.\n */\n evaluate = (agent: Agent) => {\n // We need to evaluate guard conditions for nodes up the tree, moving outwards from the root.\n for (const details of this.nodes) {\n // There can be multiple guards per node.\n for (const guard of details.guards) {\n // Check whether the guard condition passes, and throw an exception if not.\n if (!guard.isSatisfied(agent)) {\n throw new GuardUnsatisifedException(details.node);\n }\n }\n }\n };\n}\n", "import { BehaviourTreeOptions } from \"../BehaviourTreeOptions\";\nimport State, { AnyState } from \"../State\";\nimport { Agent } from \"../Agent\";\nimport Leaf from \"./leaf/Leaf\";\nimport Attribute from \"../attributes/Attribute\";\nimport Entry from \"../attributes/callbacks/Entry\";\nimport Exit from \"../attributes/callbacks/Exit\";\nimport Step from \"../attributes/callbacks/Step\";\nimport Guard from \"../attributes/guards/Guard\";\nimport GuardPath from \"../attributes/guards/GuardPath\";\nimport GuardUnsatisifedException from \"../attributes/guards/GuardUnsatisifedException\";\n\n/**\n * A base node.\n */\nexport default abstract class Node {\n /**\n * The node uid.\n */\n private readonly uid: string = createNodeUid();\n /**\n * The node state.\n */\n private state: AnyState = State.READY;\n /**\n * The guard path to evaluate as part of a node update.\n */\n private guardPath: GuardPath | undefined;\n\n /**\n * @param type The node type.\n * @param attributes The node attributes.\n * @param args The node argument definitions.\n */\n constructor(private type: string, private attributes: Attribute[], private args: any[]) {}\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected abstract onUpdate(agent: Agent, options: BehaviourTreeOptions): void;\n\n /**\n * Gets the name of the node.\n */\n public abstract getName(): string;\n\n /**\n * Gets whether this node is a leaf node.\n */\n public abstract isLeafNode: () => this is Leaf;\n\n /**\n * Gets/Sets the state of the node.\n */\n getState = (): AnyState => this.state;\n setState = (value: AnyState): void => {\n this.state = value;\n };\n\n /**\n * Gets the unique id of the node.\n */\n getUid = () => this.uid;\n\n /**\n * Gets the type of the node.\n */\n getType = () => this.type;\n\n /**\n * Gets the node attributes.\n */\n getAttributes = () => this.attributes;\n\n /**\n * Gets the node arguments.\n */\n getArguments = () => this.args;\n\n /**\n * Gets the node attribute with the specified type, or null if it does not exist.\n */\n getAttribute(type: \"entry\" | \"ENTRY\"): Entry;\n getAttribute(type: \"exit\" | \"EXIT\"): Exit;\n getAttribute(type: \"step\" | \"STEP\"): Step;\n getAttribute(type: string): Attribute {\n return (\n this.getAttributes().filter((decorator) => decorator.type.toUpperCase() === type.toUpperCase())[0] || null\n );\n }\n\n /**\n * Gets the node attributes.\n */\n getGuardAttributes = (): Guard[] => this.getAttributes().filter((decorator) => decorator.isGuard()) as Guard[];\n\n /**\n * Sets the guard path to evaluate as part of a node update.\n */\n setGuardPath = (value: GuardPath) => (this.guardPath = value);\n\n /**\n * Gets whether a guard path is assigned to this node.\n */\n hasGuardPath = () => !!this.guardPath;\n\n /**\n * Gets whether this node is in the specified state.\n * @param value The value to compare to the node state.\n */\n public is(value: AnyState): boolean {\n return this.state === value;\n }\n\n /**\n * Reset the state of the node.\n */\n public reset(): void {\n this.setState(State.READY);\n }\n\n /**\n * Abort the running of this node.\n * @param agent The agent.\n */\n public abort(agent: Agent): void {\n // There is nothing to do if this node is not in the running state.\n if (!this.is(State.RUNNING)) {\n return;\n }\n\n // Reset the state of this node.\n this.reset();\n\n this.getAttribute(\"exit\")?.callAgentFunction(agent, false, true);\n }\n\n /**\n * Update the node.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n * @returns The result of the update.\n */\n public update(agent: Agent, options: BehaviourTreeOptions): void {\n // If this node is already in a 'SUCCEEDED' or 'FAILED' state then there is nothing to do.\n if (this.is(State.SUCCEEDED) || this.is(State.FAILED)) {\n return;\n }\n\n try {\n // Evaluate all of the guard path conditions for the current tree path.\n this.guardPath!.evaluate(agent);\n\n // If this node is in the READY state then call the ENTRY for this node if it exists.\n if (this.is(State.READY)) {\n this.getAttribute(\"entry\")?.callAgentFunction(agent);\n }\n\n this.getAttribute(\"step\")?.callAgentFunction(agent);\n\n // Do the actual update.\n this.onUpdate(agent, options);\n\n // If this node is now in a 'SUCCEEDED' or 'FAILED' state then call the EXIT for this node if it exists.\n if (this.is(State.SUCCEEDED) || this.is(State.FAILED)) {\n this.getAttribute(\"exit\")?.callAgentFunction(agent, this.is(State.SUCCEEDED), false);\n }\n } catch (error) {\n // If the error is a GuardUnsatisfiedException then we need to determine if this node is the source.\n if (error instanceof GuardUnsatisifedException && error.isSourceNode(this)) {\n // Abort the current node.\n this.abort(agent);\n\n // Any node that is the source of an abort will be a failed node.\n this.setState(State.FAILED);\n } else {\n throw error;\n }\n }\n }\n}\n\n/**\n * Create a randomly generated node uid.\n * @returns A randomly generated node uid.\n */\nfunction createNodeUid(): string {\n var S4 = function () {\n return (((1 + Math.random()) * 0x10000) | 0).toString(16).substring(1);\n };\n return S4() + S4() + \"-\" + S4() + \"-\" + S4() + \"-\" + S4() + \"-\" + S4() + S4() + S4();\n}\n", "import Node from \"../Node\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\n\n/**\n * A composite node that wraps child nodes.\n */\nexport default abstract class Composite extends Node {\n /**\n * @param type The node type.\n * @param attributes The node attributes.\n * @param children The child nodes.\n */\n constructor(type: string, attributes: Attribute[], protected children: Node[]) {\n super(type, attributes, []);\n }\n\n /**\n * Gets whether this node is a leaf node.\n */\n isLeafNode = () => false;\n\n /**\n * Gets the children of this node.\n */\n getChildren = () => this.children;\n\n /**\n * Reset the state of the node.\n */\n reset = () => {\n // Reset the state of this node.\n this.setState(State.READY);\n\n // Reset the state of any child nodes.\n this.getChildren().forEach((child) => child.reset());\n };\n\n /**\n * Abort the running of this node.\n * @param agent The agent.\n */\n abort = (agent: Agent) => {\n // There is nothing to do if this node is not in the running state.\n if (!this.is(State.RUNNING)) {\n return;\n }\n\n // Abort any child nodes.\n this.getChildren().forEach((child) => child.abort(agent));\n\n // Reset the state of this node.\n this.reset();\n\n this.getAttribute(\"exit\")?.callAgentFunction(agent, false, true);\n };\n}\n", "import Composite from \"./Composite\";\nimport State from \"../../State\";\nimport Node from \"../Node\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A PARALLEL node.\n * The child nodes are executed concurrently until one fails or all succeed.\n */\nexport default class Parallel extends Composite {\n /**\n * @param attributes The node attributes.\n * @param children The child nodes.\n */\n constructor(attributes: Attribute[], children: Node[]) {\n super(\"parallel\", attributes, children);\n }\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // Keep a count of the number of succeeded child nodes.\n let succeededCount = 0;\n\n let hasChildFailed = false;\n\n // Iterate over all of the children of this node.\n for (const child of this.children) {\n // If the child has never been updated or is running then we will need to update it now.\n if (child.getState() === State.READY || child.getState() === State.RUNNING) {\n // Update the child of this node.\n child.update(agent, options);\n }\n\n // If the current child has a state of 'SUCCEEDED' then we should move on to the next child.\n if (child.getState() === State.SUCCEEDED) {\n // The child node has succeeded, keep track of this to determine if all children have.\n succeededCount++;\n\n // The child node succeeded, but we have not finished checking every child node yet.\n continue;\n }\n\n // If the current child has a state of 'FAILED' then this node is also a 'FAILED' node.\n if (child.getState() === State.FAILED) {\n hasChildFailed = true;\n\n // There is no need to check the rest of the children.\n break;\n }\n\n // The node should be in the 'RUNNING' state.\n if (child.getState() !== State.RUNNING) {\n // The child node was not in an expected state.\n throw new Error(\"child node was not in an expected state.\");\n }\n }\n\n if (hasChildFailed) {\n // This node is a 'FAILED' node.\n this.setState(State.FAILED);\n\n // Abort every running child.\n for (const child of this.children) {\n if (child.getState() === State.RUNNING) {\n child.abort(agent);\n }\n }\n } else {\n // If all children have succeeded then this node has also succeeded, otherwise it is still running.\n this.setState(succeededCount === this.children.length ? State.SUCCEEDED : State.RUNNING);\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => \"PARALLEL\";\n}\n", "import Composite from \"./Composite\";\nimport Node from \"../Node\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A SELECTOR node.\n * The child nodes are executed in sequence until one succeeds or all fail.\n */\nexport default class Selector extends Composite {\n /**\n * @param attributes The node attributes.\n * @param children The child nodes.\n */\n constructor(attributes: Attribute[], protected children: Node[]) {\n super(\"selector\", attributes, children);\n }\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // Iterate over all of the children of this node.\n for (const child of this.children) {\n // If the child has never been updated or is running then we will need to update it now.\n if (child.getState() === State.READY || child.getState() === State.RUNNING) {\n // Update the child of this node.\n child.update(agent, options);\n }\n\n // If the current child has a state of 'SUCCEEDED' then this node is also a 'SUCCEEDED' node.\n if (child.getState() === State.SUCCEEDED) {\n // This node is a 'SUCCEEDED' node.\n this.setState(State.SUCCEEDED);\n\n // There is no need to check the rest of the selector nodes.\n return;\n }\n\n // If the current child has a state of 'FAILED' then we should move on to the next child.\n if (child.getState() === State.FAILED) {\n // Find out if the current child is the last one in the selector.\n // If it is then this sequence node has also failed.\n if (this.children.indexOf(child) === this.children.length - 1) {\n // This node is a 'FAILED' node.\n this.setState(State.FAILED);\n\n // There is no need to check the rest of the selector as we have completed it.\n return;\n } else {\n // The child node failed, try the next one.\n continue;\n }\n }\n\n // The node should be in the 'RUNNING' state.\n if (child.getState() === State.RUNNING) {\n // This node is a 'RUNNING' node.\n this.setState(State.RUNNING);\n\n // There is no need to check the rest of the selector as the current child is still running.\n return;\n }\n\n // The child node was not in an expected state.\n throw new Error(\"child node was not in an expected state.\");\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => \"SELECTOR\";\n}\n", "import Composite from \"./Composite\";\nimport Node from \"../Node\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A SEQUENCE node.\n * The child nodes are executed in sequence until one fails or all succeed.\n */\nexport default class Sequence extends Composite {\n /**\n * @param attributes The node attributes.\n * @param children The child nodes.\n */\n constructor(attributes: Attribute[], protected children: Node[]) {\n super(\"sequence\", attributes, children);\n }\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // Iterate over all of the children of this node.\n for (const child of this.children) {\n // If the child has never been updated or is running then we will need to update it now.\n if (child.getState() === State.READY || child.getState() === State.RUNNING) {\n // Update the child of this node.\n child.update(agent, options);\n }\n\n // If the current child has a state of 'SUCCEEDED' then we should move on to the next child.\n if (child.getState() === State.SUCCEEDED) {\n // Find out if the current child is the last one in the sequence.\n // If it is then this sequence node has also succeeded.\n if (this.children.indexOf(child) === this.children.length - 1) {\n // This node is a 'SUCCEEDED' node.\n this.setState(State.SUCCEEDED);\n\n // There is no need to check the rest of the sequence as we have completed it.\n return;\n } else {\n // The child node succeeded, but we have not finished the sequence yet.\n continue;\n }\n }\n\n // If the current child has a state of 'FAILED' then this node is also a 'FAILED' node.\n if (child.getState() === State.FAILED) {\n // This node is a 'FAILED' node.\n this.setState(State.FAILED);\n\n // There is no need to check the rest of the sequence.\n return;\n }\n\n // The node should be in the 'RUNNING' state.\n if (child.getState() === State.RUNNING) {\n // This node is a 'RUNNING' node.\n this.setState(State.RUNNING);\n\n // There is no need to check the rest of the sequence as the current child is still running.\n return;\n }\n\n // The child node was not in an expected state.\n throw new Error(\"child node was not in an expected state.\");\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => \"SEQUENCE\";\n}\n", "import createLotto from \"lotto-draw\";\n\nimport Node from \"../Node\";\nimport Composite from \"./Composite\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A LOTTO node.\n * A winning child is picked on the initial update of this node, based on ticket weighting.\n * The state of this node will match the state of the winning child.\n */\nexport default class Lotto extends Composite {\n /**\n * @param attributes The node attributes.\n * @param weights The child node weights.\n * @param children The child nodes.\n */\n constructor(attributes: Attribute[], private weights: number[] | undefined, children: Node[]) {\n super(\"lotto\", attributes, children);\n }\n\n /**\n * The child node selected to be the active one.\n */\n private selectedChild: Node | undefined;\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // If this node is in the READY state then we need to pick a winning child node.\n if (this.is(State.READY)) {\n // Create a lotto draw with which to randomly pick a child node to become the active one.\n const lottoDraw = createLotto({\n // Hook up the optional 'random' behaviour tree function option to the one used by 'lotto-draw'.\n random: options.random,\n // Pass in each child node as a participant in the lotto draw with their respective ticket count.\n participants: this.children.map((child, index) => [child, this.weights?.[index] || 1])\n });\n\n // Randomly pick a child based on ticket weighting, this will become the active child for this composite node.\n this.selectedChild = lottoDraw.draw() || undefined;\n }\n\n // If something went wrong and we don't have an active child then we should throw an error.\n if (!this.selectedChild) {\n throw new Error(\"failed to update lotto node as it has no active child\");\n }\n\n // If the selected child has never been updated or is running then we will need to update it now.\n if (this.selectedChild.getState() === State.READY || this.selectedChild.getState() === State.RUNNING) {\n this.selectedChild.update(agent, options);\n }\n\n // The state of the lotto node is the state of its selected child.\n this.setState(this.selectedChild.getState());\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => (this.weights ? `LOTTO [${this.weights.join(\",\")}]` : \"LOTTO\");\n}\n", "import Node from \"../Node\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\n\n/**\n * A decorator node that wraps a single child node.\n */\nexport default abstract class Decorator extends Node {\n /**\n * @param type The node type.\n * @param attributes The node attributes.\n * @param child The child node.\n */\n constructor(type: string, attributes: Attribute[], protected child: Node) {\n super(type, attributes, []);\n }\n\n /**\n * Gets whether this node is a leaf node.\n */\n isLeafNode = () => false;\n\n /**\n * Gets the children of this node.\n */\n getChildren = () => [this.child];\n\n /**\n * Reset the state of the node.\n */\n reset = () => {\n // Reset the state of this node.\n this.setState(State.READY);\n\n // Reset the state of the child node.\n this.child.reset();\n };\n\n /**\n * Abort the running of this node.\n * @param agent The agent.\n */\n abort = (agent: Agent) => {\n // There is nothing to do if this node is not in the running state.\n if (!this.is(State.RUNNING)) {\n return;\n }\n\n // Abort the child node.\n this.child.abort(agent);\n\n // Reset the state of this node.\n this.reset();\n\n this.getAttribute(\"exit\")?.callAgentFunction(agent, false, true);\n };\n}\n", "import Node from \"../Node\";\nimport Decorator from \"./Decorator\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A Fail node.\n * This node wraps a single child and will always move to the 'FAILED' state when the child moves to a 'SUCCEEDED' or 'FAILED' state.\n */\nexport default class Fail extends Decorator {\n /**\n * @param attributes The node attributes.\n * @param child The child node.\n */\n constructor(attributes: Attribute[], child: Node) {\n super(\"fail\", attributes, child);\n }\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // If the child has never been updated or is running then we will need to update it now.\n if (this.child.getState() === State.READY || this.child.getState() === State.RUNNING) {\n this.child.update(agent, options);\n }\n\n // The state of this node will depend in the state of its child.\n switch (this.child.getState()) {\n case State.RUNNING:\n this.setState(State.RUNNING);\n break;\n\n case State.SUCCEEDED:\n case State.FAILED:\n this.setState(State.FAILED);\n break;\n\n default:\n this.setState(State.READY);\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => \"FAIL\";\n}\n", "import Decorator from \"./Decorator\";\nimport State from \"../../State\";\nimport Node from \"../Node\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A Flip node.\n * This node wraps a single child and will flip the state of the child state.\n */\nexport default class Flip extends Decorator {\n /**\n * @param attributes The node attributes.\n * @param child The child node.\n */\n constructor(attributes: Attribute[], child: Node) {\n super(\"flip\", attributes, child);\n }\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // If the child has never been updated or is running then we will need to update it now.\n if (this.child.getState() === State.READY || this.child.getState() === State.RUNNING) {\n this.child.update(agent, options);\n }\n\n // The state of this node will depend in the state of its child.\n switch (this.child.getState()) {\n case State.RUNNING:\n this.setState(State.RUNNING);\n break;\n\n case State.SUCCEEDED:\n this.setState(State.FAILED);\n break;\n\n case State.FAILED:\n this.setState(State.SUCCEEDED);\n break;\n\n default:\n this.setState(State.READY);\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => \"FLIP\";\n}\n", "import Node from \"../Node\";\nimport Decorator from \"./Decorator\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A REPEAT node.\n * The node has a single child which can have:\n * -- A number of iterations for which to repeat the child node.\n * -- An infinite repeat loop if neither an iteration count or a condition function is defined.\n * The REPEAT node will stop and have a 'FAILED' state if its child is ever in a 'FAILED' state after an update.\n * The REPEAT node will attempt to move on to the next iteration if its child is ever in a 'SUCCEEDED' state.\n */\nexport default class Repeat extends Decorator {\n /**\n * @param attributes The node attributes.\n * @param iterations The number of iterations to repeat the child node.\n * @param iterationsMin The minimum possible number of iterations to repeat the child node.\n * @param iterationsMax The maximum possible number of iterations to repeat the child node.\n * @param child The child node.\n */\n constructor(\n attributes: Attribute[],\n private iterations: number | null,\n private iterationsMin: number | null,\n private iterationsMax: number | null,\n child: Node\n ) {\n super(\"repeat\", attributes, child);\n }\n\n /**\n * The number of target iterations to make.\n */\n private targetIterationCount: number | null = null;\n\n /**\n * The current iteration count.\n */\n private currentIterationCount: number = 0;\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // If this node is in the READY state then we need to reset the child and the target iteration count.\n if (this.is(State.READY)) {\n // Reset the child node.\n this.child.reset();\n\n // Reset the current iteration count.\n this.currentIterationCount = 0;\n\n // Set the target iteration count.\n this.setTargetIterationCount(options);\n }\n\n // Do a check to see if we can iterate. If we can then this node will move into the 'RUNNING' state.\n // If we cannot iterate then we have hit our target iteration count, which means that the node has succeeded.\n if (this.canIterate()) {\n // This node is in the running state and can do its initial iteration.\n this.setState(State.RUNNING);\n\n // We may have already completed an iteration, meaning that the child node will be in the SUCCEEDED state.\n // If this is the case then we will have to reset the child node now.\n if (this.child.getState() === State.SUCCEEDED) {\n this.child.reset();\n }\n\n // Update the child of this node.\n this.child.update(agent, options);\n\n // If the child moved into the FAILED state when we updated it then there is nothing left to do and this node has also failed.\n // If it has moved into the SUCCEEDED state then we have completed the current iteration.\n if (this.child.getState() === State.FAILED) {\n // The child has failed, meaning that this node has failed.\n this.setState(State.FAILED);\n\n return;\n } else if (this.child.getState() === State.SUCCEEDED) {\n // We have completed an iteration.\n this.currentIterationCount += 1;\n }\n } else {\n // This node is in the 'SUCCEEDED' state as we cannot iterate any more.\n this.setState(State.SUCCEEDED);\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => {\n if (this.iterations !== null) {\n return `REPEAT ${this.iterations}x`;\n } else if (this.iterationsMin !== null && this.iterationsMax !== null) {\n return `REPEAT ${this.iterationsMin}x-${this.iterationsMax}x`;\n } else {\n return \"REPEAT\";\n }\n };\n\n /**\n * Reset the state of the node.\n */\n reset = () => {\n // Reset the state of this node.\n this.setState(State.READY);\n\n // Reset the current iteration count.\n this.currentIterationCount = 0;\n\n // Reset the child node.\n this.child.reset();\n };\n\n /**\n * Gets whether an iteration can be made.\n * @returns Whether an iteration can be made.\n */\n private canIterate = () => {\n if (this.targetIterationCount !== null) {\n // We can iterate as long as we have not reached our target iteration count.\n return this.currentIterationCount < this.targetIterationCount;\n }\n\n // If neither an iteration count or a condition function were defined then we can iterate indefinitely.\n return true;\n };\n\n /**\n * Sets the target iteration count.\n * @param options The behaviour tree options object.\n */\n private setTargetIterationCount = (options: BehaviourTreeOptions) => {\n // Are we dealing with an explicit iteration count or will we be randomly picking a iteration count between the min and max iteration count.\n if (this.iterations !== null) {\n this.targetIterationCount = this.iterations;\n } else if (this.iterationsMin !== null && this.iterationsMax !== null) {\n // We will be picking a random iteration count between a min and max iteration count, if the optional 'random'\n // behaviour tree function option is defined then we will be using that, otherwise we will fall back to using Math.random.\n const random = typeof options.random === \"function\" ? options.random : Math.random;\n\n // Pick a random iteration count between a min and max iteration count.\n this.targetIterationCount = Math.floor(\n random() * (this.iterationsMax - this.iterationsMin + 1) + this.iterationsMin\n );\n } else {\n this.targetIterationCount = null;\n }\n };\n}\n", "import Node from \"../Node\";\nimport Decorator from \"./Decorator\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A RETRY node.\n * The node has a single child which can have:\n * -- A number of iterations for which to repeat the child node.\n * -- An infinite repeat loop if neither an iteration count or a condition function is defined.\n * The RETRY node will stop and have a 'SUCCEEDED' state if its child is ever in a 'SUCCEEDED' state after an update.\n * The RETRY node will attempt to move on to the next iteration if its child is ever in a 'FAILED' state.\n */\nexport default class Retry extends Decorator {\n /**\n * @param attributes The node attributes.\n * @param attempts The number of attempts to retry the child node.\n * @param attemptsMin The minimum possible number of attempts to retry the child node.\n * @param attemptsMax The maximum possible number of attempts to retry the child node.\n * @param child The child node.\n */\n constructor(\n attributes: Attribute[],\n private attempts: number | null,\n private attemptsMin: number | null,\n private attemptsMax: number | null,\n child: Node\n ) {\n super(\"retry\", attributes, child);\n }\n\n /**\n * The number of target attempts to make.\n */\n private targetAttemptCount: number | null = null;\n\n /**\n * The current attempt count.\n */\n private currentAttemptCount: number = 0;\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // If this node is in the READY state then we need to reset the child and the target attempt count.\n if (this.is(State.READY)) {\n // Reset the child node.\n this.child.reset();\n\n // Reset the current attempt count.\n this.currentAttemptCount = 0;\n\n // Set the target attempt count.\n this.setTargetAttemptCount(options);\n }\n\n // Do a check to see if we can attempt. If we can then this node will move into the 'RUNNING' state.\n // If we cannot attempt then we have hit our target attempt count, which means that the node has succeeded.\n if (this.canAttempt()) {\n // This node is in the running state and can do its initial attempt.\n this.setState(State.RUNNING);\n\n // We may have already completed an attempt, meaning that the child node will be in the FAILED state.\n // If this is the case then we will have to reset the child node now.\n if (this.child.getState() === State.FAILED) {\n this.child.reset();\n }\n\n // Update the child of this node.\n this.child.update(agent, options);\n\n // If the child moved into the SUCCEEDED state when we updated it then there is nothing left to do and this node has also succeeded.\n // If it has moved into the FAILED state then we have completed the current attempt.\n if (this.child.getState() === State.SUCCEEDED) {\n // The child has succeeded, meaning that this node has succeeded.\n this.setState(State.SUCCEEDED);\n\n return;\n } else if (this.child.getState() === State.FAILED) {\n // We have completed an attempt.\n this.currentAttemptCount += 1;\n }\n } else {\n // This node is in the 'FAILED' state as we cannot iterate any more.\n this.setState(State.FAILED);\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => {\n if (this.attempts !== null) {\n return `RETRY ${this.attempts}x`;\n } else if (this.attemptsMin !== null && this.attemptsMax !== null) {\n return `RETRY ${this.attemptsMin}x-${this.attemptsMax}x`;\n } else {\n return \"RETRY\";\n }\n };\n\n /**\n * Reset the state of the node.\n */\n reset = () => {\n // Reset the state of this node.\n this.setState(State.READY);\n\n // Reset the current attempt count.\n this.currentAttemptCount = 0;\n\n // Reset the child node.\n this.child.reset();\n };\n\n /**\n * Gets whether an attempt can be made.\n * @returns Whether an attempt can be made.\n */\n canAttempt = () => {\n if (this.targetAttemptCount !== null) {\n // We can attempt as long as we have not reached our target attempt count.\n return this.currentAttemptCount < this.targetAttemptCount;\n }\n\n // If neither an attempt count or a condition function were defined then we can attempt indefinitely.\n return true;\n };\n\n /**\n * Sets the target attempt count.\n * @param options The behaviour tree options object.\n */\n setTargetAttemptCount = (options: BehaviourTreeOptions) => {\n // Are we dealing with an explicit attempt count or will we be randomly picking an attempt count between the min and max attempt count.\n if (this.attempts !== null) {\n this.targetAttemptCount = this.attempts;\n } else if (this.attemptsMin !== null && this.attemptsMax !== null) {\n // We will be picking a random attempt count between a min and max attempt count, if the optional 'random'\n // behaviour tree function option is defined then we will be using that, otherwise we will fall back to using Math.random.\n const random = typeof options.random === \"function\" ? options.random : Math.random;\n\n // Pick a random attempt count between a min and max attempt count.\n this.targetAttemptCount = Math.floor(\n random() * (this.attemptsMax - this.attemptsMin + 1) + this.attemptsMin\n );\n } else {\n this.targetAttemptCount = null;\n }\n };\n}\n", "import Node from \"../Node\";\nimport Decorator from \"./Decorator\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A Root node.\n * The root node will have a single child.\n */\nexport default class Root extends Decorator {\n /**\n * @param attributes The node attributes.\n * @param child The child node.\n */\n constructor(attributes: Attribute[], child: Node) {\n super(\"root\", attributes, child);\n }\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // If the child has never been updated or is running then we will need to update it now.\n if (this.child.getState() === State.READY || this.child.getState() === State.RUNNING) {\n // Update the child of this node.\n this.child.update(agent, options);\n }\n\n // The state of the root node is the state of its child.\n this.setState(this.child.getState());\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => \"ROOT\";\n}\n", "import Node from \"../Node\";\nimport Decorator from \"./Decorator\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A Succeed node.\n * This node wraps a single child and will always move to the 'SUCCEEDED' state when the child moves to a 'SUCCEEDED' or 'FAILED' state.\n */\nexport default class Succeed extends Decorator {\n /**\n * @param attributes The node attributes.\n * @param child The child node.\n */\n constructor(attributes: Attribute[], child: Node) {\n super(\"succeed\", attributes, child);\n }\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // If the child has never been updated or is running then we will need to update it now.\n if (this.child.getState() === State.READY || this.child.getState() === State.RUNNING) {\n this.child.update(agent, options);\n }\n\n // The state of this node will depend in the state of its child.\n switch (this.child.getState()) {\n case State.RUNNING:\n this.setState(State.RUNNING);\n break;\n\n case State.SUCCEEDED:\n case State.FAILED:\n this.setState(State.SUCCEEDED);\n break;\n\n default:\n this.setState(State.READY);\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => \"SUCCEED\";\n}\n", "import Node from \"../Node\";\n\n/**\n * A leaf node.\n */\nexport default abstract class Leaf extends Node {\n /**\n * Gets whether this node is a leaf node.\n */\n isLeafNode = () => true;\n}\n", "import { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\nimport State, { CompleteState } from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Leaf from \"./Leaf\";\nimport Lookup from \"../../Lookup\";\nimport Attribute from \"../../attributes/Attribute\";\n\n/**\n * The type representing a resolved/rejected update promise.\n */\ntype UpdatePromiseResult = {\n /**\n * Whether the promise was resolved rather than rejected.\n */\n isResolved: boolean;\n\n /**\n * The promise resolved value or rejection reason.\n */\n value: any;\n};\n\n/**\n * An Action leaf node.\n * This represents an immediate or ongoing state of behaviour.\n */\nexport default class Action extends Leaf {\n /**\n * @param attributes The node attributes.\n * @param actionName The action name.\n * @param actionArguments The array of action argument definitions.\n */\n constructor(attributes: Attribute[], private actionName: string, private actionArguments: any[]) {\n super(\"action\", attributes, actionArguments);\n }\n\n /**\n * Whether there is a pending update promise.\n */\n private isUsingUpdatePromise = false;\n\n /**\n * The finished state result of an update promise.\n */\n private updatePromiseResult: UpdatePromiseResult | null = null;\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // If the result of this action depends on an update promise then there is nothing to do until it settles.\n if (this.isUsingUpdatePromise) {\n // Are we still waiting for our update promise to settle?\n if (!this.updatePromiseResult) {\n return;\n }\n\n const { isResolved, value } = this.updatePromiseResult;\n\n // Our update promise settled, was it resolved or rejected?\n if (isResolved) {\n // Our promise resolved so check to make sure the result is a valid finished state.\n if (value !== State.SUCCEEDED && value !== State.FAILED) {\n throw new Error(\n \"action node promise resolved with an invalid value, expected a State.SUCCEEDED or State.FAILED value to be returned\"\n );\n }\n\n // Set the state of this node to match the state returned by the promise.\n this.setState(value);\n\n return;\n } else {\n // The promise was rejected, which isn't great.\n throw new Error(`action function '${this.actionName}' promise rejected with '${value}'`);\n }\n }\n\n // Attempt to get the invoker for the action function.\n const actionFuncInvoker = Lookup.getFuncInvoker(agent, this.actionName);\n\n // The action function should be defined.\n if (actionFuncInvoker === null) {\n throw new Error(\n `cannot update action node as the action '${this.actionName}' function is not defined on the agent and has not been registered`\n );\n }\n\n let actionFunctionResult;\n\n try {\n // Call the action function, the result of which may be:\n // - The finished state of this action node.\n // - A promise to return a finished node state.\n // - Undefined if the node should remain in the running state.\n actionFunctionResult = actionFuncInvoker(this.actionArguments) as CompleteState | Promise;\n } catch (error) {\n // An uncaught error was thrown.\n if (error instanceof Error) {\n throw new Error(`action function '${this.actionName}' threw: ${error.stack}`);\n } else {\n throw new Error(`action function '${this.actionName}' threw: ${error}`);\n }\n }\n\n if (actionFunctionResult instanceof Promise) {\n actionFunctionResult.then(\n (result) => {\n // If 'isUpdatePromisePending' is not set then the promise was cleared as it was resolving, probably via an abort of reset.\n if (!this.isUsingUpdatePromise) {\n return;\n }\n\n // Set the resolved update promise result so that it can be handled on the next update of this node.\n this.updatePromiseResult = {\n isResolved: true,\n value: result\n };\n },\n (reason) => {\n // If 'isUpdatePromisePending' is not set then the promise was cleared as it was resolving, probably via an abort or reset.\n if (!this.isUsingUpdatePromise) {\n return;\n }\n\n // Set the rejected update promise result so that it can be handled on the next update of this node.\n this.updatePromiseResult = {\n isResolved: false,\n value: reason\n };\n }\n );\n\n // This node will be in the 'RUNNING' state until the update promise resolves.\n this.setState(State.RUNNING);\n\n // We are now waiting for the promise returned by the use to resolve before we know what state this node is in.\n this.isUsingUpdatePromise = true;\n } else {\n // Validate the returned value.\n this.validateUpdateResult(actionFunctionResult);\n\n // Set the state of this node, this may be undefined, which just means that the node is still in the 'RUNNING' state.\n this.setState(actionFunctionResult || State.RUNNING);\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => this.actionName;\n\n /**\n * Reset the state of the node.\n */\n reset = () => {\n // Reset the state of this node.\n this.setState(State.READY);\n\n // There is no longer an update promise that we care about.\n this.isUsingUpdatePromise = false;\n this.updatePromiseResult = null;\n };\n\n /**\n * Validate the result of an update function call.\n * @param result The result of an update function call.\n */\n private validateUpdateResult = (result: CompleteState | State.RUNNING) => {\n switch (result) {\n case State.SUCCEEDED:\n case State.FAILED:\n case State.RUNNING:\n case undefined:\n return;\n default:\n throw new Error(\n `expected action function '${this.actionName}' to return an optional State.SUCCEEDED or State.FAILED value but returned '${result}'`\n );\n }\n };\n}\n", "import { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Leaf from \"./Leaf\";\nimport Lookup from \"../../Lookup\";\nimport Attribute from \"../../attributes/Attribute\";\n\n/**\n * A Condition leaf node.\n * This will succeed or fail immediately based on an agent predicate, without moving to the 'RUNNING' state.\n */\nexport default class Condition extends Leaf {\n /**\n * @param attributes The node attributes.\n * @param conditionName The name of the condition function.\n * @param conditionArguments The array of condition argument definitions.\n */\n constructor(attributes: Attribute[], private conditionName: string, private conditionArguments: any[]) {\n super(\"condition\", attributes, conditionArguments);\n }\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // Attempt to get the invoker for the condition function.\n const conditionFuncInvoker = Lookup.getFuncInvoker(agent, this.conditionName);\n\n // The condition function should be defined.\n if (conditionFuncInvoker === null) {\n throw new Error(\n `cannot update condition node as the condition '${this.conditionName}' function is not defined on the agent and has not been registered`\n );\n }\n\n let conditionFunctionResult;\n\n try {\n // Call the condition function to determine the state of this node, the result of which should be a boolean.\n conditionFunctionResult = conditionFuncInvoker(this.conditionArguments);\n } catch (error) {\n // An uncaught error was thrown.\n if (error instanceof Error) {\n throw new Error(`condition function '${this.conditionName}' threw: ${error.stack}`);\n } else {\n throw new Error(`condition function '${this.conditionName}' threw: ${error}`);\n }\n }\n\n // The result of calling the condition function must be a boolean value.\n if (typeof conditionFunctionResult !== \"boolean\") {\n throw new Error(\n `expected condition function '${this.conditionName}' to return a boolean but returned '${conditionFunctionResult}'`\n );\n }\n\n // Set the state of this node based on the result of calling the condition function.\n this.setState(!!conditionFunctionResult ? State.SUCCEEDED : State.FAILED);\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => this.conditionName;\n}\n", "import Leaf from \"./Leaf\";\nimport State from \"../../State\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { Agent } from \"../../Agent\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A WAIT node.\n * The state of this node will change to SUCCEEDED after a duration of time\n */\nexport default class Wait extends Leaf {\n /**\n * @param attributes The node attributes.\n * @param duration The duration that this node will wait to succeed in milliseconds.\n * @param durationMin The minimum possible duration in milliseconds that this node will wait to succeed.\n * @param durationMax The maximum possible duration in milliseconds that this node will wait to succeed.\n */\n constructor(\n attributes: Attribute[],\n private duration: number | null,\n private durationMin: number | null,\n private durationMax: number | null\n ) {\n super(\"wait\", attributes, []);\n }\n\n /**\n * The time in milliseconds at which this node was first updated.\n */\n private initialUpdateTime: number = 0;\n\n /**\n * The total duration in milliseconds that this node will be waiting for.\n */\n private totalDuration: number | null = null;\n\n /**\n * The duration in milliseconds that this node has been waiting for.\n */\n private waitedDuration: number = 0;\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // If this node is in the READY state then we need to set the initial update time.\n if (this.is(State.READY)) {\n // Set the initial update time.\n this.initialUpdateTime = new Date().getTime();\n\n // Set the initial waited duration.\n this.waitedDuration = 0;\n\n // Are we dealing with an explicit duration or will we be randomly picking a duration between the min and max duration.\n if (this.duration !== null) {\n this.totalDuration = this.duration;\n } else if (this.durationMin !== null && this.durationMax !== null) {\n // We will be picking a random duration between a min and max duration, if the optional 'random' behaviour tree\n // function option is defined then we will be using that, otherwise we will fall back to using Math.random.\n const random = typeof options.random === \"function\" ? options.random : Math.random;\n\n // Pick a random duration between a min and max duration.\n this.totalDuration = Math.floor(\n random() * (this.durationMax - this.durationMin + 1) + this.durationMin\n );\n } else {\n this.totalDuration = null;\n }\n\n // The node is now running until we finish waiting.\n this.setState(State.RUNNING);\n }\n\n // If we have no total duration then this wait node will wait indefinitely until it is aborted.\n if (this.totalDuration === null) {\n return;\n }\n\n // If we have a 'getDeltaTime' function defined as part of our options then we will use it to figure out how long we have waited for.\n if (typeof options.getDeltaTime === \"function\") {\n // Get the delta time.\n const deltaTime = options.getDeltaTime();\n\n // Our delta time must be a valid number and cannot be NaN.\n if (typeof deltaTime !== \"number\" || isNaN(deltaTime)) {\n throw new Error(\"The delta time must be a valid number and not NaN.\");\n }\n\n // Update the amount of time that this node has been waiting for based on the delta time.\n this.waitedDuration += deltaTime * 1000;\n } else {\n // We are not using a delta time, so we will just work out hom much time has passed since the first update.\n this.waitedDuration = new Date().getTime() - this.initialUpdateTime;\n }\n\n // Have we waited long enough?\n if (this.waitedDuration >= this.totalDuration) {\n // We have finished waiting!\n this.setState(State.SUCCEEDED);\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => {\n if (this.duration !== null) {\n return `WAIT ${this.duration}ms`;\n } else if (this.durationMin !== null && this.durationMax !== null) {\n return `WAIT ${this.durationMin}ms-${this.durationMax}ms`;\n } else {\n return \"WAIT\";\n }\n };\n}\n", "import Guard from \"./guards/Guard\";\n\nexport type AttributeDetails = {\n /** The attribute type. */\n type: string;\n\n /** The attribute arguments. */\n args: any[];\n};\n\n/**\n * A base node attribute.\n */\nexport default abstract class Attribute {\n /**\n * @param type The node attribute type.\n * @param args The array of attribute arguments.\n */\n constructor(public type: string, public args: any[]) {}\n\n /**\n * Gets the attribute details.\n */\n abstract getDetails(): TAttributeDetails;\n\n /**\n * Gets whether this attribute is a guard.\n */\n abstract isGuard: () => this is Guard;\n}\n", "import { Agent } from \"../../Agent\";\nimport Attribute, { AttributeDetails } from \"../Attribute\";\n\nexport type GuardAttributeDetails = {\n /** The name of the condition function that determines whether the guard is satisfied. */\n condition: string;\n} & AttributeDetails;\n\n/**\n * A base node guard attribute.\n */\nexport default abstract class Guard extends Attribute {\n /**\n * @param type The node attribute type.\n * @param args The array of decorator argument definitions.\n * @param condition The name of the condition function that determines whether the guard is satisfied.\n */\n constructor(type: string, args: any[], private condition: string) {\n super(type, args);\n }\n\n /**\n * Gets the name of the condition function that determines whether the guard is satisfied.\n */\n getCondition = () => this.condition;\n\n /**\n * Gets whether this attribute is a guard.\n */\n isGuard = () => true;\n\n /**\n * Gets the attribute details.\n */\n getDetails(): GuardAttributeDetails {\n return {\n type: this.type,\n args: this.args,\n condition: this.getCondition()\n };\n }\n\n /**\n * Gets whether the guard is satisfied.\n * @param agent The agent.\n * @returns Whether the guard is satisfied.\n */\n abstract isSatisfied(agent: Agent): boolean;\n}\n", "import Guard from \"./Guard\";\nimport Lookup from \"../../Lookup\";\nimport { Agent } from \"../../Agent\";\n\n/**\n * A WHILE guard which is satisfied as long as the given condition remains true.\n */\nexport default class While extends Guard {\n /**\n * @param condition The name of the condition function that determines whether the guard is satisfied.\n * @param args The array of decorator argument definitions.\n */\n constructor(condition: string, args: any[]) {\n super(\"while\", args, condition);\n }\n\n /**\n * Gets whether the guard is satisfied.\n * @param agent The agent.\n * @returns Whether the guard is satisfied.\n */\n isSatisfied = (agent: Agent) => {\n // Attempt to get the invoker for the condition function.\n const conditionFuncInvoker = Lookup.getFuncInvoker(agent, this.getCondition());\n\n // The condition function should be defined.\n if (conditionFuncInvoker === null) {\n throw new Error(\n `cannot evaluate node guard as the condition '${this.getCondition()}' function is not defined on the agent and has not been registered`\n );\n }\n\n let conditionFunctionResult;\n\n try {\n // Call the guard condition function to determine the state of this node, the result of which should be a boolean.\n conditionFunctionResult = conditionFuncInvoker(this.args);\n } catch (error) {\n // An uncaught error was thrown.\n if (error instanceof Error) {\n throw new Error(`guard condition function '${this.getCondition()}' threw: ${error.stack}`);\n } else {\n throw new Error(`guard condition function '${this.getCondition()}' threw: ${error}`);\n }\n }\n\n // The result of calling the guard condition function must be a boolean value.\n if (typeof conditionFunctionResult !== \"boolean\") {\n throw new Error(\n `expected guard condition function '${this.getCondition()}' to return a boolean but returned '${conditionFunctionResult}'`\n );\n }\n\n // Return whether this guard is satisfied.\n return conditionFunctionResult;\n };\n}\n", "import Guard from \"./Guard\";\nimport Lookup from \"../../Lookup\";\nimport { Agent } from \"../../Agent\";\n\n/**\n * An UNTIL guard which is satisfied as long as the given condition remains false.\n */\nexport default class Until extends Guard {\n /**\n * @param condition The name of the condition function that determines whether the guard is satisfied.\n * @param args The array of decorator argument definitions.\n */\n constructor(condition: string, args: any[]) {\n super(\"until\", args, condition);\n }\n\n /**\n * Gets whether the guard is satisfied.\n * @param agent The agent.\n * @returns Whether the guard is satisfied.\n */\n isSatisfied = (agent: Agent) => {\n // Attempt to get the invoker for the condition function.\n const conditionFuncInvoker = Lookup.getFuncInvoker(agent, this.getCondition());\n\n // The condition function should be defined.\n if (conditionFuncInvoker === null) {\n throw new Error(\n `cannot evaluate node guard as the condition '${this.getCondition()}' function is not defined on the agent and has not been registered`\n );\n }\n\n let conditionFunctionResult;\n\n try {\n // Call the guard condition function to determine the state of this node, the result of which should be a boolean.\n conditionFunctionResult = conditionFuncInvoker(this.args);\n } catch (error) {\n // An uncaught error was thrown.\n if (error instanceof Error) {\n throw new Error(`guard condition function '${this.getCondition()}' threw: ${error.stack}`);\n } else {\n throw new Error(`guard condition function '${this.getCondition()}' threw: ${error}`);\n }\n }\n\n // The result of calling the guard condition function must be a boolean value.\n if (typeof conditionFunctionResult !== \"boolean\") {\n throw new Error(\n `expected guard condition function '${this.getCondition()}' to return a boolean but returned '${conditionFunctionResult}'`\n );\n }\n\n // Return whether this guard is satisfied.\n return !conditionFunctionResult;\n };\n}\n", "import { Agent } from \"../../Agent\";\nimport Attribute, { AttributeDetails } from \"../Attribute\";\n\nexport type CallbackAttributeDetails = {\n /** The name of the agent function that is called. */\n functionName: string;\n} & AttributeDetails;\n\n/**\n * A base node callback attribute.\n */\nexport default abstract class Callback extends Attribute {\n /**\n * @param type The node attribute type.\n * @param args The array of decorator argument definitions.\n * @param functionName The name of the agent function to call.\n */\n constructor(type: string, args: any[], private functionName: string) {\n super(type, args);\n }\n\n /**\n * Gets the name of the agent function to call.\n */\n getFunctionName = () => this.functionName;\n\n /**\n * Gets whether this attribute is a guard.\n */\n isGuard = () => false;\n\n /**\n * Gets the attribute details.\n */\n getDetails(): CallbackAttributeDetails {\n return {\n type: this.type,\n args: this.args,\n functionName: this.getFunctionName()\n };\n }\n\n /**\n * Attempt to call the agent function that this callback refers to.\n * @param agent The agent.\n */\n abstract callAgentFunction: (agent: Agent, isSuccess: boolean, isAborted: boolean) => void;\n}\n", "import Callback from \"./Callback\";\nimport Lookup from \"../../Lookup\";\nimport { Agent } from \"../../Agent\";\n\n/**\n * An ENTRY callback which defines an agent function to call when the associated node is updated and moves out of running state.\n */\nexport default class Entry extends Callback {\n /**\n * @param functionName The name of the agent function to call.\n * @param args The array of callback argument definitions.\n */\n constructor(functionName: string, args: any[]) {\n super(\"entry\", args, functionName);\n }\n\n /**\n * Attempt to call the agent function that this callback refers to.\n * @param agent The agent.\n */\n callAgentFunction = (agent: Agent) => {\n // Attempt to get the invoker for the callback function.\n const callbackFuncInvoker = Lookup.getFuncInvoker(agent, this.getFunctionName());\n\n // The callback function should be defined.\n if (callbackFuncInvoker === null) {\n throw new Error(\n `cannot call entry function '${this.getFunctionName()}' as is not defined on the agent and has not been registered`\n );\n }\n\n // Call the callback function.\n callbackFuncInvoker(this.args);\n };\n}\n", "import Callback from \"./Callback\";\nimport Lookup from \"../../Lookup\";\nimport { Agent } from \"../../Agent\";\n\n/**\n * A STEP callback which defines an agent function to call when the associated node is updated.\n */\nexport default class Step extends Callback {\n /**\n * @param functionName The name of the agent function to call.\n * @param args The array of callback argument definitions.\n */\n constructor(functionName: string, args: any[]) {\n super(\"step\", args, functionName);\n }\n\n /**\n * Attempt to call the agent function that this callback refers to.\n * @param agent The agent.\n */\n callAgentFunction = (agent: Agent) => {\n // Attempt to get the invoker for the callback function.\n const callbackFuncInvoker = Lookup.getFuncInvoker(agent, this.getFunctionName());\n\n // The callback function should be defined.\n if (callbackFuncInvoker === null) {\n throw new Error(\n `cannot call step function '${this.getFunctionName()}' as is not defined on the agent and has not been registered`\n );\n }\n\n // Call the callback function.\n callbackFuncInvoker(this.args);\n };\n}\n", "import Callback from \"./Callback\";\nimport Lookup from \"../../Lookup\";\nimport { Agent } from \"../../Agent\";\n\n/**\n * An EXIT callback which defines an agent function to call when the associated node is updated and moves to a finished state or is aborted.\n */\nexport default class Exit extends Callback {\n /**\n * @param functionName The name of the agent function to call.\n * @param args The array of callback argument definitions.\n */\n constructor(functionName: string, args: any[]) {\n super(\"exit\", args, functionName);\n }\n\n /**\n * Attempt to call the agent function that this callback refers to.\n * @param agent The agent.\n * @param isSuccess Whether the decorated node was left with a success state.\n * @param isAborted Whether the decorated node was aborted.\n */\n callAgentFunction = (agent: Agent, isSuccess: boolean, isAborted: boolean) => {\n // Attempt to get the invoker for the callback function.\n const callbackFuncInvoker = Lookup.getFuncInvoker(agent, this.getFunctionName());\n\n // The callback function should be defined.\n if (callbackFuncInvoker === null) {\n throw new Error(\n `cannot call exit function '${this.getFunctionName()}' as is not defined on the agent and has not been registered`\n );\n }\n\n // Call the callback function\n callbackFuncInvoker([{ succeeded: isSuccess, aborted: isAborted }, ...this.args]);\n };\n}\n", "import { AnyNodeDefinition, RootNodeDefinition } from \"./BehaviourTreeDefinition\";\nimport GuardPath, { GuardPathPart } from \"./attributes/guards/GuardPath\";\nimport { validateBranchSubtreeLinks } from \"./BehaviourTreeDefinitionValidator\";\nimport { isInteger } from \"./BehaviourTreeDefinitionUtilities\";\nimport Node from \"./nodes/Node\";\nimport Composite from \"./nodes/composite/Composite\";\nimport Decorator from \"./nodes/decorator/Decorator\";\nimport Parallel from \"./nodes/composite/Parallel\";\nimport Selector from \"./nodes/composite/Selector\";\nimport Sequence from \"./nodes/composite/Sequence\";\nimport Lotto from \"./nodes/composite/Lotto\";\nimport Fail from \"./nodes/decorator/Fail\";\nimport Flip from \"./nodes/decorator/Flip\";\nimport Repeat from \"./nodes/decorator/Repeat\";\nimport Retry from \"./nodes/decorator/Retry\";\nimport Root from \"./nodes/decorator/Root\";\nimport Succeed from \"./nodes/decorator/Succeed\";\nimport Action from \"./nodes/leaf/Action\";\nimport Condition from \"./nodes/leaf/Condition\";\nimport Wait from \"./nodes/leaf/Wait\";\nimport Lookup from \"./Lookup\";\nimport Attribute from \"./attributes/Attribute\";\nimport While from \"./attributes/guards/While\";\nimport Until from \"./attributes/guards/Until\";\nimport Entry from \"./attributes/callbacks/Entry\";\nimport Step from \"./attributes/callbacks/Step\";\nimport Exit from \"./attributes/callbacks/Exit\";\n\n/**\n * A type representing any node instance in a behaviour tree.\n */\ntype AnyNode =\n | Root\n | Action\n | Condition\n | Wait\n | Sequence\n | Selector\n | Lotto\n | Parallel\n | Repeat\n | Retry\n | Flip\n | Succeed\n | Fail;\n\n/**\n * A type defining a mapping of root node identifiers to root node definitions.\n */\ntype RootNodeDefinitionMap = { [key: string | symbol]: RootNodeDefinition };\n\n/**\n * A symbol to use as the main root key in any root node mappings.\n */\nconst MAIN_ROOT_NODE_KEY = Symbol(\"__root__\");\n\n/**\n * Build and populate the root nodes based on the provided definition, assuming that the definition has been validated.\n * @param definition The root node definitions.\n * @returns The built and populated root node definitions.\n */\nexport default function buildRootNode(definition: RootNodeDefinition[]): Root {\n // Create a mapping of root node identifers to root node definitions, including globally registered subtree root node definitions.\n const rootNodeDefinitionMap = createRootNodeDefinitionMap(definition);\n\n // Now that we have all of our root node definitions (those part of the tree definition and those globally registered)\n // we should validate the branch-subtree links. This will also double-check that we dont have any circular dependencies\n // in our branch-subtree references and that we have no broken branch-subtree links.\n validateBranchSubtreeLinks(\n [rootNodeDefinitionMap[MAIN_ROOT_NODE_KEY], ...Object.values(rootNodeDefinitionMap)],\n true\n );\n\n // Create our populated tree of node instances, starting with our main root node.\n const rootNode = nodeFactory(rootNodeDefinitionMap[MAIN_ROOT_NODE_KEY], rootNodeDefinitionMap) as Root;\n\n // Set a guard path on every leaf of the tree to evaluate as part of each update.\n applyLeafNodeGuardPaths(rootNode);\n\n // We only need to return the main root node.\n return rootNode;\n}\n\n/**\n * A factory function which creates a node instance based on the specified definition.\n * @param definition The node definition.\n * @param rootNodeDefinitionMap The mapping of root node identifers to root node definitions, including globally registered subtree root node definitions.\n * @returns A node instance based on the specified definition.\n */\nfunction nodeFactory(definition: AnyNodeDefinition, rootNodeDefinitionMap: RootNodeDefinitionMap): AnyNode {\n // Get the attributes for the node.\n const attributes = nodeAttributesFactory(definition);\n\n // Create the node instance based on the definition type.\n switch (definition.type) {\n case \"root\":\n return new Root(attributes, nodeFactory(definition.child, rootNodeDefinitionMap));\n\n case \"repeat\":\n let iterations: number | null = null;\n let iterationsMin: number | null = null;\n let iterationsMax: number | null = null;\n\n if (Array.isArray(definition.iterations)) {\n iterationsMin = definition.iterations[0];\n iterationsMax = definition.iterations[1];\n } else if (isInteger(definition.iterations)) {\n iterations = definition.iterations!;\n }\n\n return new Repeat(\n attributes,\n iterations,\n iterationsMin,\n iterationsMax,\n nodeFactory(definition.child, rootNodeDefinitionMap)\n );\n\n case \"retry\":\n let attempts: number | null = null;\n let attemptsMin: number | null = null;\n let attemptsMax: number | null = null;\n\n if (Array.isArray(definition.attempts)) {\n attemptsMin = definition.attempts[0];\n attemptsMax = definition.attempts[1];\n } else if (isInteger(definition.attempts)) {\n attempts = definition.attempts!;\n }\n\n return new Retry(\n attributes,\n attempts,\n attemptsMin,\n attemptsMax,\n nodeFactory(definition.child, rootNodeDefinitionMap)\n );\n\n case \"flip\":\n return new Flip(attributes, nodeFactory(definition.child, rootNodeDefinitionMap));\n\n case \"succeed\":\n return new Succeed(attributes, nodeFactory(definition.child, rootNodeDefinitionMap));\n\n case \"fail\":\n return new Fail(attributes, nodeFactory(definition.child, rootNodeDefinitionMap));\n\n case \"sequence\":\n return new Sequence(\n attributes,\n definition.children.map((child) => nodeFactory(child, rootNodeDefinitionMap))\n );\n\n case \"selector\":\n return new Selector(\n attributes,\n definition.children.map((child) => nodeFactory(child, rootNodeDefinitionMap))\n );\n\n case \"parallel\":\n return new Parallel(\n attributes,\n definition.children.map((child) => nodeFactory(child, rootNodeDefinitionMap))\n );\n\n case \"lotto\":\n return new Lotto(\n attributes,\n definition.weights,\n definition.children.map((child) => nodeFactory(child, rootNodeDefinitionMap))\n );\n\n case \"branch\":\n return nodeFactory(rootNodeDefinitionMap[definition.ref].child, rootNodeDefinitionMap);\n\n case \"action\":\n return new Action(attributes, definition.call, definition.args || []);\n\n case \"condition\":\n return new Condition(attributes, definition.call, definition.args || []);\n\n case \"wait\":\n let duration: number | null = null;\n let durationMin: number | null = null;\n let durationMax: number | null = null;\n\n if (Array.isArray(definition.duration)) {\n durationMin = definition.duration[0];\n durationMax = definition.duration[1];\n } else if (isInteger(definition.duration)) {\n duration = definition.duration!;\n }\n\n return new Wait(attributes, duration, durationMin, durationMax);\n }\n}\n\n/**\n * Creates an array of node attribute instances based on the specified node definition.\n * @param definition The node definition.\n * @returns An array of node attribute instances based on the specified node definition.\n */\nfunction nodeAttributesFactory(definition: AnyNodeDefinition): Attribute[] {\n const attributes: Attribute[] = [];\n\n if (definition.while) {\n attributes.push(new While(definition.while.call, definition.while.args ?? []));\n }\n\n if (definition.until) {\n attributes.push(new Until(definition.until.call, definition.until.args ?? []));\n }\n\n if (definition.entry) {\n attributes.push(new Entry(definition.entry.call, definition.entry.args ?? []));\n }\n\n if (definition.step) {\n attributes.push(new Step(definition.step.call, definition.step.args ?? []));\n }\n\n if (definition.exit) {\n attributes.push(new Exit(definition.exit.call, definition.exit.args ?? []));\n }\n\n return attributes;\n}\n\n/**\n * Creates a mapping of root node identifers to root node definitions, mixing in globally registered subtree root node definitions.\n * @param definition The root node definitions.\n * @returns A mapping of root node identifers to root node definitions, including globally registered subtree root node definitions.\n */\nfunction createRootNodeDefinitionMap(definition: RootNodeDefinition[]): RootNodeDefinitionMap {\n // Create a mapping of root node identifers to root node definitions.\n const rootNodeMap: RootNodeDefinitionMap = {};\n\n // Add in any registered subtree root node definitions.\n for (const [name, rootNodeDefinition] of Object.entries(Lookup.getSubtrees())) {\n // The name used when registering the subtree will be used as the root node identifier.\n rootNodeMap[name] = { ...rootNodeDefinition, id: name };\n }\n\n // Populate the map with the root node definitions that were included with the tree definition.\n // We do this after adding any registered subtrees as we want these to take presedence.\n for (const rootNodeDefinition of definition) {\n rootNodeMap[rootNodeDefinition.id ?? MAIN_ROOT_NODE_KEY] = rootNodeDefinition;\n }\n\n return rootNodeMap;\n}\n\n/**\n * Applies a guard path to every leaf of the tree to evaluate as part of each update.\n * @param root The main root tree node.\n */\nfunction applyLeafNodeGuardPaths(root: Root) {\n const nodePaths: Node[][] = [];\n\n const findLeafNodes = (path: Node[], node: Node) => {\n // Add the current node to the path.\n path = path.concat(node);\n\n // Check whether the current node is a leaf node.\n if (node.isLeafNode()) {\n nodePaths.push(path);\n } else {\n (node as Composite | Decorator).getChildren().forEach((child) => findLeafNodes(path, child));\n }\n };\n\n // Find all leaf node paths, starting from the root.\n findLeafNodes([], root);\n\n nodePaths.forEach((path) => {\n // Each node in the current path will have to be assigned a guard path, working from the root outwards.\n for (let depth = 0; depth < path.length; depth++) {\n // Get the node in the path at the current depth.\n const currentNode = path[depth];\n\n // The node may already have been assigned a guard path, if so just skip it.\n if (currentNode.hasGuardPath()) {\n continue;\n }\n\n // Create the guard path for the current node.\n const guardPath = new GuardPath(\n path\n .slice(0, depth + 1)\n .map((node) => ({ node, guards: node.getGuardAttributes() }))\n .filter((details) => details.guards.length > 0)\n );\n\n // Assign the guard path to the current node.\n currentNode.setGuardPath(guardPath);\n }\n });\n}\n", "import State, { AnyState } from \"./State\";\nimport Lookup from \"./Lookup\";\nimport Node from \"./nodes/Node\";\nimport Root from \"./nodes/decorator/Root\";\nimport Composite from \"./nodes/composite/Composite\";\nimport Decorator from \"./nodes/decorator/Decorator\";\nimport { Agent, GlobalFunction } from \"./Agent\";\nimport { CallbackAttributeDetails } from \"./attributes/callbacks/Callback\";\nimport { GuardAttributeDetails } from \"./attributes/guards/Guard\";\nimport { BehaviourTreeOptions } from \"./BehaviourTreeOptions\";\nimport { convertMDSLToJSON } from \"./mdsl/MDSLDefinitionParser\";\nimport { RootNodeDefinition } from \"./BehaviourTreeDefinition\";\nimport { validateDefinition, validateJSONDefinition } from \"./BehaviourTreeDefinitionValidator\";\nimport buildRootNode from \"./BehaviourTreeBuilder\";\nimport { isNullOrUndefined } from \"./BehaviourTreeDefinitionUtilities\";\n\n// Purely for outside inspection of the tree.\nexport type FlattenedTreeNode = {\n id: string;\n type: string;\n caption: string;\n state: AnyState;\n guards: GuardAttributeDetails[];\n callbacks: CallbackAttributeDetails[];\n args: any[];\n parentId: string | null;\n};\n\n/**\n * A representation of a behaviour tree.\n */\nexport class BehaviourTree {\n /**\n * The main root tree node.\n */\n private readonly _rootNode: Root;\n\n /**\n * Creates a new instance of the BehaviourTree class.\n * @param definition The behaviour tree definition as either an MDSL string, root node definition object or array of root node definition objects.\n * @param agent The agent instance that this behaviour tree is modelling behaviour for.\n * @param options The behaviour tree options object.\n */\n constructor(\n definition: string | RootNodeDefinition | RootNodeDefinition[],\n private agent: Agent,\n private options: BehaviourTreeOptions = {}\n ) {\n // The tree definition must be defined.\n if (isNullOrUndefined(definition)) {\n throw new Error(\"tree definition not defined\");\n }\n\n // The agent must be defined and not null.\n if (typeof agent !== \"object\" || agent === null) {\n throw new Error(\"the agent must be an object and not null\");\n }\n\n // We should validate the definition before we try to build the tree nodes.\n const { succeeded, errorMessage, json } = validateDefinition(definition);\n\n // Did our validation fail without error?\n if (!succeeded) {\n throw new Error(`invalid definition: ${errorMessage}`);\n }\n\n // Double check that we did actually get our json definition as part of our definition validtion.\n if (!json) {\n throw new Error(\n \"expected json definition to be returned as part of successful definition validation response\"\n );\n }\n\n try {\n // Create the populated tree of behaviour tree nodes and get the root node.\n this._rootNode = buildRootNode(json);\n } catch (exception) {\n // There was an issue in trying build and populate the behaviour tree.\n throw new Error(`error building tree: ${(exception as Error).message}`);\n }\n }\n\n /**\n * Gets whether the tree is in the RUNNING state.\n * @returns true if the tree is in the RUNNING state, otherwise false.\n */\n isRunning() {\n return this._rootNode.getState() === State.RUNNING;\n }\n\n /**\n * Gets the current tree state of SUCCEEDED, FAILED, READY or RUNNING.\n * @returns The current tree state.\n */\n getState() {\n return this._rootNode.getState();\n }\n\n /**\n * Step the tree.\n * 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.\n * 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\n * 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.\n *\n * 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.\n */\n step() {\n // If the root node has already been stepped to completion then we need to reset it.\n if (this._rootNode.getState() === State.SUCCEEDED || this._rootNode.getState() === State.FAILED) {\n this._rootNode.reset();\n }\n\n try {\n this._rootNode.update(this.agent, this.options);\n } catch (exception) {\n throw new Error(`error stepping tree: ${(exception as Error).message}`);\n }\n }\n\n /**\n * Resets the tree from the root node outwards to each nested node, giving each a state of READY.\n */\n reset() {\n this._rootNode.reset();\n }\n\n /**\n * Gets the flattened details of every node in the tree.\n * @returns The flattened details of every node in the tree.\n */\n getFlattenedNodeDetails(): FlattenedTreeNode[] {\n // Create an empty flattened array of tree nodes.\n const flattenedTreeNodes: FlattenedTreeNode[] = [];\n\n /**\n * Helper function to process a node instance and push details into the flattened tree nodes array.\n * @param node The current node.\n * @param parentUid The UID of the node parent, or null if the node is the main root node.\n */\n const processNode = (node: Node, parentUid: string | null) => {\n // Get the guard and callback attribute details for this node.\n const guards = node\n .getAttributes()\n .filter((attribute) => attribute.isGuard())\n .map((attribute) => attribute.getDetails()) as GuardAttributeDetails[];\n const callbacks = node\n .getAttributes()\n .filter((attribute) => !attribute.isGuard())\n .map((attribute) => attribute.getDetails()) as CallbackAttributeDetails[];\n\n // Push the current node into the flattened nodes array.\n flattenedTreeNodes.push({\n id: node.getUid(),\n type: node.getType(),\n caption: node.getName(),\n state: node.getState(),\n guards,\n callbacks,\n args: node.getArguments(),\n parentId: parentUid\n });\n\n // Process each of the nodes children if it is not a leaf node.\n if (!node.isLeafNode()) {\n (node as Composite | Decorator)\n .getChildren()\n .forEach((child) => processNode(child, (node as Composite | Decorator).getUid()));\n }\n };\n\n // Convert the nested node structure into a flattened array of node details.\n processNode(this._rootNode, null);\n\n return flattenedTreeNodes;\n }\n\n /**\n * Registers the action/condition/guard/callback function or subtree with the given name.\n * @param name The name of the function or subtree to register.\n * @param value The function or subtree definition to register.\n */\n static register(name: string, value: GlobalFunction | string | RootNodeDefinition) {\n // Are we going to register a action/condition/guard/callback function?\n if (typeof value === \"function\") {\n Lookup.setFunc(name, value);\n return;\n }\n\n // We are not registering an action/condition/guard/callback function, so we must be registering a subtree.\n if (typeof value === \"string\") {\n let rootNodeDefinitions: RootNodeDefinition[];\n\n // We will assume that any string passed in will be a mdsl definition.\n try {\n rootNodeDefinitions = convertMDSLToJSON(value);\n } catch (exception) {\n throw new Error(`error registering definition, invalid MDSL: ${(exception as Error).message}`);\n }\n\n // This function should only ever be called with a definition containing a single unnamed root node.\n if (rootNodeDefinitions.length != 1 || typeof rootNodeDefinitions[0].id !== \"undefined\") {\n throw new Error(\"error registering definition: expected a single unnamed root node\");\n }\n\n try {\n // We should validate the subtree as we don't want invalid subtrees available via the lookup.\n const { succeeded, errorMessage } = validateJSONDefinition(rootNodeDefinitions[0]);\n\n // Did our validation fail without error?\n if (!succeeded) {\n throw new Error(errorMessage);\n }\n } catch (exception) {\n throw new Error(`error registering definition: ${(exception as Error).message}`);\n }\n\n // Everything seems hunky-dory, register the subtree.\n Lookup.setSubtree(name, rootNodeDefinitions[0]);\n } else if (typeof value === \"object\" && !Array.isArray(value)) {\n // We will assume that any object passed in is a root node definition.\n\n try {\n // We should validate the subtree as we don't want invalid subtrees available via the lookup.\n const { succeeded, errorMessage } = validateJSONDefinition(value);\n\n // Did our validation fail without error?\n if (!succeeded) {\n throw new Error(errorMessage);\n }\n } catch (exception) {\n throw new Error(`error registering definition: ${(exception as Error).message}`);\n }\n\n // Everything seems hunky-dory, register the subtree.\n Lookup.setSubtree(name, value);\n } else {\n throw new Error(\"unexpected value, expected string mdsl definition, root node json definition or function\");\n }\n }\n\n /**\n * Unregisters the registered action/condition/guard/callback function or subtree with the given name.\n * @param name The name of the registered action/condition/guard/callback function or subtree to unregister.\n */\n static unregister(name: string): void {\n Lookup.remove(name);\n }\n\n /**\n * Unregister all registered action/condition/guard/callback functions and subtrees.\n */\n static unregisterAll(): void {\n Lookup.empty();\n }\n}\n"], + "mappings": "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", "names": ["Participant", "isNullOrUndefined", "Lotto", "createLotto", "State", "createLotto"] } diff --git a/src/Agent.ts b/src/Agent.ts index 59671c7..0d21edc 100644 --- a/src/Agent.ts +++ b/src/Agent.ts @@ -34,7 +34,7 @@ export type Agent = { */ export type ExitFunctionArg = { succeeded: boolean; aborted: boolean }; -export type FunctionArg = number | string | boolean | null | ExitFunctionArg; +export type FunctionArg = any | ExitFunctionArg; export type ActionResult = CompleteState | Promise | State.RUNNING | void; export type AgentFunction = (this: Agent, ...args: FunctionArg[]) => ActionResult | boolean; export type GlobalFunction = (agent: Agent, ...args: FunctionArg[]) => ActionResult | boolean; diff --git a/src/BehaviourTree.ts b/src/BehaviourTree.ts index bb43497..9953a0c 100644 --- a/src/BehaviourTree.ts +++ b/src/BehaviourTree.ts @@ -198,7 +198,7 @@ export class BehaviourTree { } // This function should only ever be called with a definition containing a single unnamed root node. - if (rootNodeDefinitions.length != 1 || rootNodeDefinitions[0].id !== null) { + if (rootNodeDefinitions.length != 1 || typeof rootNodeDefinitions[0].id !== "undefined") { throw new Error("error registering definition: expected a single unnamed root node"); } diff --git a/src/Lookup.ts b/src/Lookup.ts index 55369f1..e15a9c1 100644 --- a/src/Lookup.ts +++ b/src/Lookup.ts @@ -52,7 +52,7 @@ export default class Lookup { // The agent does not contain the specified function but it may have been registered at some point. if (this.registeredFunctions[name] && typeof this.registeredFunctions[name] === "function") { const registeredFunction = this.registeredFunctions[name]; - return (args: any[]) => registeredFunction(agent, ...args.map((arg) => arg.value)); + return (args: any[]) => registeredFunction(agent, ...args); } // We have no function to invoke. diff --git a/test/nodes/leaf/Action.spec.ts b/test/nodes/leaf/Action.spec.ts index 7e96263..5246c4f 100644 --- a/test/nodes/leaf/Action.spec.ts +++ b/test/nodes/leaf/Action.spec.ts @@ -1,8 +1,8 @@ import { assert } from "chai"; +import sinon from "sinon"; import { BehaviourTree, State } from "../../../src/index"; import { RootNodeDefinition } from "../../../src/BehaviourTreeDefinition"; -import { Agent } from "../../../src/Agent"; import { findNode } from "../../TestUtilities"; @@ -41,39 +41,40 @@ describe("An Action node", () => { describe("when the referenced function is", () => { describe("a registered function", () => { it("(MDSL)", () => { - const definition = "root { action [doAction] }"; - - BehaviourTree.register("doAction", () => { - return State.SUCCEEDED; - }); + const registeredActionFunction = sinon.stub().returns(State.SUCCEEDED); + BehaviourTree.register("doAction", registeredActionFunction); - const tree = new BehaviourTree(definition, {}); + const definition = `root { action [doAction, "some-argument"] }`; + const agent = { mock: "agent" }; + const tree = new BehaviourTree(definition, agent); tree.step(); const node = findNode(tree, "action", "doAction"); assert.strictEqual(node.state, State.SUCCEEDED); + assert.isTrue(registeredActionFunction.calledWith(agent, "some-argument")); }); it("(JSON)", () => { + const registeredActionFunction = sinon.stub().returns(State.SUCCEEDED); + BehaviourTree.register("doAction", registeredActionFunction); + const definition: RootNodeDefinition = { type: "root", child: { type: "action", - call: "doAction" + call: "doAction", + args: ["some-argument"] } }; - - BehaviourTree.register("doAction", () => { - return State.SUCCEEDED; - }); - - const tree = new BehaviourTree(definition, {}); + const agent = { mock: "agent" }; + const tree = new BehaviourTree(definition, agent); tree.step(); const node = findNode(tree, "action", "doAction"); assert.strictEqual(node.state, State.SUCCEEDED); + assert.isTrue(registeredActionFunction.calledWith(agent, "some-argument")); }); }); diff --git a/test/nodes/leaf/Condition.spec.ts b/test/nodes/leaf/Condition.spec.ts index a008f23..d6d127b 100644 --- a/test/nodes/leaf/Condition.spec.ts +++ b/test/nodes/leaf/Condition.spec.ts @@ -1,8 +1,8 @@ import { assert } from "chai"; +import sinon from "sinon"; import { BehaviourTree, State } from "../../../src/index"; import { RootNodeDefinition } from "../../../src/BehaviourTreeDefinition"; -import { Agent } from "../../../src/Agent"; import { findNode } from "../../TestUtilities"; @@ -41,37 +41,40 @@ describe("A Condition node", () => { describe("when the referenced function is", () => { describe("a registered function", () => { it("(MDSL)", () => { - BehaviourTree.register("someCondition", () => { - return true; - }); + const registeredConditionFunction = sinon.stub().returns(true); + BehaviourTree.register("someCondition", registeredConditionFunction); - const definition = "root { condition [someCondition] }"; - const tree = new BehaviourTree(definition, {}); + const definition = `root { condition [someCondition, "some-argument"] }`; + const agent = { mock: "agent" }; + const tree = new BehaviourTree(definition, agent); tree.step(); const node = findNode(tree, "condition", "someCondition"); assert.strictEqual(node.state, State.SUCCEEDED); + assert.isTrue(registeredConditionFunction.calledWith(agent, "some-argument")); }); it("(JSON)", () => { - BehaviourTree.register("someCondition", () => { - return true; - }); + const registeredConditionFunction = sinon.stub().returns(true); + BehaviourTree.register("someCondition", registeredConditionFunction); const definition: RootNodeDefinition = { type: "root", child: { type: "condition", - call: "someCondition" + call: "someCondition", + args: ["some-argument"] } }; - const tree = new BehaviourTree(definition, {}); + const agent = { mock: "agent" }; + const tree = new BehaviourTree(definition, agent); tree.step(); const node = findNode(tree, "condition", "someCondition"); assert.strictEqual(node.state, State.SUCCEEDED); + assert.isTrue(registeredConditionFunction.calledWith(agent, "some-argument")); }); }); From 9076a753db0cd288ee91c93a614283796fc2051b Mon Sep 17 00:00:00 2001 From: Nikolas Howard Date: Tue, 5 Mar 2024 13:55:01 +0000 Subject: [PATCH 46/48] fixed issue where no root node needs to be defined in JSON definition --- dist/bundle.js | 3 +++ dist/bundle.js.map | 4 +-- dist/index.js | 3 +++ dist/index.js.map | 4 +-- src/BehaviourTreeDefinitionValidator.ts | 5 ++++ test/BehaviourTreeDefinitionValidator.spec.ts | 25 +++++++++++++++++++ 6 files changed, 40 insertions(+), 4 deletions(-) diff --git a/dist/bundle.js b/dist/bundle.js index 9c28e08..f9c95fa 100644 --- a/dist/bundle.js +++ b/dist/bundle.js @@ -892,6 +892,9 @@ var mistreevous = (() => { `node definition is not an object or 'type' property is not a non-empty string at depth '${depth}'` ); } + if (depth === 0 && definition.type !== "root") { + throw new Error(`expected root node at base of definition but got node of type '${definition.type}'`); + } switch (definition.type) { case "action": validateActionNode(definition, depth); diff --git a/dist/bundle.js.map b/dist/bundle.js.map index 77fcf6d..d72f854 100644 --- a/dist/bundle.js.map +++ b/dist/bundle.js.map @@ -1,7 +1,7 @@ { "version": 3, "sources": ["../node_modules/lotto-draw/dist/Participant.js", "../node_modules/lotto-draw/dist/Utilities.js", "../node_modules/lotto-draw/dist/Lotto.js", "../node_modules/lotto-draw/dist/createLotto.js", "../node_modules/lotto-draw/dist/index.js", "../src/index.ts", "../src/State.ts", "../src/BehaviourTreeDefinitionUtilities.ts", "../src/mdsl/MDSLUtilities.ts", "../src/mdsl/MDSLNodeArgumentParser.ts", "../src/mdsl/MDSLNodeAttributeParser.ts", "../src/mdsl/MDSLDefinitionParser.ts", "../src/BehaviourTreeDefinitionValidator.ts", "../src/Lookup.ts", "../src/attributes/guards/GuardUnsatisifedException.ts", "../src/attributes/guards/GuardPath.ts", "../src/nodes/Node.ts", "../src/nodes/composite/Composite.ts", "../src/nodes/composite/Parallel.ts", "../src/nodes/composite/Selector.ts", "../src/nodes/composite/Sequence.ts", "../src/nodes/composite/Lotto.ts", "../src/nodes/decorator/Decorator.ts", "../src/nodes/decorator/Fail.ts", "../src/nodes/decorator/Flip.ts", "../src/nodes/decorator/Repeat.ts", "../src/nodes/decorator/Retry.ts", "../src/nodes/decorator/Root.ts", "../src/nodes/decorator/Succeed.ts", "../src/nodes/leaf/Leaf.ts", "../src/nodes/leaf/Action.ts", "../src/nodes/leaf/Condition.ts", "../src/nodes/leaf/Wait.ts", "../src/attributes/Attribute.ts", "../src/attributes/guards/Guard.ts", "../src/attributes/guards/While.ts", "../src/attributes/guards/Until.ts", "../src/attributes/callbacks/Callback.ts", "../src/attributes/callbacks/Entry.ts", "../src/attributes/callbacks/Step.ts", "../src/attributes/callbacks/Exit.ts", "../src/BehaviourTreeBuilder.ts", "../src/BehaviourTree.ts"], - "sourcesContent": ["\"use strict\";\r\nObject.defineProperty(exports, \"__esModule\", { value: true });\r\nexports.Participant = void 0;\r\n/**\r\n * A participant that holds a number of tickets.\r\n */\r\nvar Participant = /** @class */ (function () {\r\n /**\r\n * Creates an instance of the Participant class.\r\n * @param participant The actual participant.\r\n * @param tickets The number of tickets held by the participant.\r\n */\r\n function Participant(participant, tickets) {\r\n if (tickets === void 0) { tickets = 1; }\r\n this._participant = participant;\r\n this._tickets = tickets;\r\n }\r\n Object.defineProperty(Participant.prototype, \"participant\", {\r\n /** Gets the actual participant. */\r\n get: function () {\r\n return this._participant;\r\n },\r\n enumerable: false,\r\n configurable: true\r\n });\r\n Object.defineProperty(Participant.prototype, \"tickets\", {\r\n /** Gets or sets the number of tickets held by the participant. */\r\n get: function () {\r\n return this._tickets;\r\n },\r\n set: function (value) {\r\n this._tickets = value;\r\n },\r\n enumerable: false,\r\n configurable: true\r\n });\r\n return Participant;\r\n}());\r\nexports.Participant = Participant;\r\n", "\"use strict\";\r\nObject.defineProperty(exports, \"__esModule\", { value: true });\r\nexports.isNaturalNumber = exports.isNullOrUndefined = void 0;\r\n/**\r\n * Gets whether the value provided is null or undefined.\r\n * @param value The value to check.\r\n * @returns Whether the value provided is null or undefined.\r\n */\r\nfunction isNullOrUndefined(value) {\r\n return value === null || value === undefined;\r\n}\r\nexports.isNullOrUndefined = isNullOrUndefined;\r\n/**\r\n * Gets whether the value provided is a natural number.\r\n * @param value The value to check.\r\n * @returns Whether the value provided is a natural number.\r\n */\r\nfunction isNaturalNumber(value) {\r\n return typeof value === \"number\" && value >= 1 && Math.floor(value) === value;\r\n}\r\nexports.isNaturalNumber = isNaturalNumber;\r\n", "\"use strict\";\r\nObject.defineProperty(exports, \"__esModule\", { value: true });\r\nexports.Lotto = void 0;\r\nvar Participant_1 = require(\"./Participant\");\r\nvar Utilities_1 = require(\"./Utilities\");\r\n/**\r\n * Represents a lotto consisting of a number of pickable ticket-holding participants.\r\n */\r\nvar Lotto = /** @class */ (function () {\r\n /**\r\n * Creates a new instance of Lotto.\r\n * @param customRandom The custom RNG to use in place of Math.random().\r\n */\r\n function Lotto(customRandom) {\r\n /** The array of participants that are holding tickets in the lotto. */\r\n this._participants = [];\r\n this._customRandom = customRandom;\r\n }\r\n /**\r\n * Adds a participant with the specified number of tickets, or adds to the participant ticket count if the participant already holds tickets.\r\n * @param participant The participant to add or to increase the ticket count for if they already hold tickets.\r\n * @param tickets The number of tickets, defaults to 1.\r\n * @returns The Lotto instance.\r\n */\r\n Lotto.prototype.add = function (participant, tickets) {\r\n if (tickets === void 0) { tickets = 1; }\r\n // Check that we have a valid ticket count.\r\n if (!(0, Utilities_1.isNaturalNumber)(tickets)) {\r\n throw new Error(\"tickets value must be a natural number\");\r\n }\r\n // Check whether this participant has already been added.\r\n var existingParticipant = this._participants.find(function (part) { return part.participant === participant; });\r\n if (existingParticipant) {\r\n // The participant has already been added to the lotto so just add to their ticket count.\r\n existingParticipant.tickets += tickets;\r\n }\r\n else {\r\n // The participant is not part of the lotto so we should add them.\r\n this._participants.push(new Participant_1.Participant(participant, tickets));\r\n }\r\n return this;\r\n };\r\n /**\r\n * Removes the specified number of tickets for the given participant from the draw, or all tickets if a ticket number is not defined.\r\n * @param participant The participant to remove tickets for.\r\n * @param tickets The number of tickets to remove, or undefined if all tickets are to be removed.\r\n * @returns The Lotto instance.\r\n */\r\n Lotto.prototype.remove = function (participant, tickets) {\r\n // Attempt to get the existing participant.\r\n var existingParticipant = this._participants.find(function (part) { return part.participant === participant; });\r\n // There is nothing to do if the specified participant isn't even part of the lotto.\r\n if (!existingParticipant) {\r\n return this;\r\n }\r\n // Check whether a tickets value was given.\r\n if (tickets !== undefined) {\r\n // Check that we have a valid ticket count.\r\n if (!(0, Utilities_1.isNaturalNumber)(tickets)) {\r\n throw new Error(\"tickets value must be a natural number\");\r\n }\r\n existingParticipant.tickets -= tickets;\r\n // If the participant no longer holds any tickets then they should be removed.\r\n if (existingParticipant.tickets < 1) {\r\n this._participants = this._participants.filter(function (part) { return part !== existingParticipant; });\r\n }\r\n }\r\n else {\r\n // We are removing all tickets for the participant so just remove them from the lotto.\r\n this._participants = this._participants.filter(function (part) { return part !== existingParticipant; });\r\n }\r\n return this;\r\n };\r\n /**\r\n * Draw a winning ticket and return the participant that holds the ticket.\r\n * @param options The draw options.\r\n * @returns The participant that holds the winning ticket.\r\n */\r\n Lotto.prototype.draw = function (options) {\r\n if (options === void 0) { options = {}; }\r\n // If we have no participants then just return null.\r\n if (this._participants.length === 0) {\r\n return null;\r\n }\r\n var redrawable = (0, Utilities_1.isNullOrUndefined)(options.redrawable) ? true : options.redrawable;\r\n var pickable = [];\r\n this._participants.forEach(function (_a) {\r\n var participant = _a.participant, tickets = _a.tickets;\r\n for (var ticketCount = 0; ticketCount < tickets; ticketCount++) {\r\n pickable.push(participant);\r\n }\r\n });\r\n var random;\r\n // We need a random floating-point number between 0 (inclusive) and 1 to scale up to pick our winner.\r\n // If a custom random function exists then we should use that or fall back to Math.random().\r\n if (this._customRandom) {\r\n // Call our custom random function to get a random floating-point number.\r\n random = this._customRandom();\r\n // Verify that the result of calling our custom random function is a number between 0 (inclusive) and 1.\r\n if (typeof random !== \"number\" || random < 0 || random >= 1) {\r\n throw new Error(\"the 'random' function provided did not return a number between 0 (inclusive) and 1\");\r\n }\r\n }\r\n else {\r\n // No custom random function was defined so just use good ol' Math.random().\r\n random = Math.random();\r\n }\r\n // Pick a winning participant.\r\n var winner = pickable[Math.floor(random * pickable.length)];\r\n // If the ticket isn't redrawable then we should remove a ticket from the winning participants ticket count.\r\n if (!redrawable) {\r\n this.remove(winner, 1);\r\n }\r\n // Return the winning participant.\r\n return winner;\r\n };\r\n /**\r\n * Draws multiple winning tickets and return an array of the participants that hold the winning tickets.\r\n * @param tickets The number of winning tickets to draw.\r\n * @param options The draw multiple options.\r\n * @returns An array of the participants that hold the winning tickets.\r\n */\r\n Lotto.prototype.drawMultiple = function (tickets, options) {\r\n if (options === void 0) { options = {}; }\r\n var uniqueResults = (0, Utilities_1.isNullOrUndefined)(options.unique) ? false : options.unique;\r\n // Handle cases where the user has asked for zero tickets (no idea why they would do this be we should trust them).\r\n if (tickets === 0) {\r\n return [];\r\n }\r\n // Now that we know out tickets value is not zero we should check that it is a valid natural number.\r\n if (!(0, Utilities_1.isNaturalNumber)(tickets)) {\r\n throw new Error(\"tickets value must be a natural number\");\r\n }\r\n var result = [];\r\n // Keep drawing tickets until we either reach the number of required tickets or we simply run out of tickets to draw.\r\n // We can run out of tickets to draw if 'options.redrawable' is explicity 'false' or we just had no participants when 'drawMultiple' was called.\r\n while (result.length < tickets && this._participants.length > 0) {\r\n result.push(this.draw(options));\r\n }\r\n // If the 'unique' draw option is set then we need to remove duplicates from the result list.\r\n if (uniqueResults) {\r\n // Create an array to store our unique results.\r\n var unique = [];\r\n // Iterate over all of our participants (with potential duplicates) and populate our array of unique values.\r\n for (var _i = 0, result_1 = result; _i < result_1.length; _i++) {\r\n var participant = result_1[_i];\r\n if (unique.indexOf(participant) === -1) {\r\n unique.push(participant);\r\n }\r\n }\r\n result = unique;\r\n }\r\n return result;\r\n };\r\n return Lotto;\r\n}());\r\nexports.Lotto = Lotto;\r\n", "\"use strict\";\r\nObject.defineProperty(exports, \"__esModule\", { value: true });\r\nexports.createLotto = void 0;\r\nvar Lotto_1 = require(\"./Lotto\");\r\n/**\r\n * A function that creates and returns a Lotto instance.\r\n * @param participantsOrOptions An array of initial participants or options relating to the creation of a Lotto instance.\r\n * @returns A new Lotto instance.\r\n */\r\nfunction createLotto(participantsOrOptions) {\r\n // If no initial participants or lotto options were provided as an argument then we can just return a new lotto instance now.\r\n if (!participantsOrOptions) {\r\n return new Lotto_1.Lotto();\r\n }\r\n // Check whether we were provided with an array of initial participants or a lotto options object.\r\n if (Array.isArray(participantsOrOptions)) {\r\n // We are dealing with a pre-defined array of participants.\r\n var participants = participantsOrOptions;\r\n var lotto_1 = new Lotto_1.Lotto();\r\n // If the lotto participants have been defined upfront then we will need to add them all to our lotto instance now.\r\n participants.forEach(function (_a) {\r\n var participant = _a[0], tokens = _a[1];\r\n return lotto_1.add(participant, tokens);\r\n });\r\n // Return the Lotto instance.\r\n return lotto_1;\r\n }\r\n else {\r\n // We are dealing with some lotto options.\r\n var random = participantsOrOptions.random, participants = participantsOrOptions.participants;\r\n // Create a Lotto instance passing the custom RNG function to use in place of Math.random() (which could be undefined).\r\n var lotto_2 = new Lotto_1.Lotto(random);\r\n // If the lotto participants have been defined upfront as part of the options then we will need to add them all to our lotto instance now.\r\n if (participants) {\r\n participants.forEach(function (_a) {\r\n var participant = _a[0], tokens = _a[1];\r\n return lotto_2.add(participant, tokens);\r\n });\r\n }\r\n // Return the Lotto instance.\r\n return lotto_2;\r\n }\r\n}\r\nexports.createLotto = createLotto;\r\n", "\"use strict\";\r\nObject.defineProperty(exports, \"__esModule\", { value: true });\r\nvar createLotto_1 = require(\"./createLotto\");\r\nexports.default = createLotto_1.createLotto;\r\n", "import State from \"./State\";\nimport { validateDefinition } from \"./BehaviourTreeDefinitionValidator\";\nimport { convertMDSLToJSON } from \"./mdsl/MDSLDefinitionParser\";\nimport { BehaviourTree, FlattenedTreeNode } from \"./BehaviourTree\";\nimport { BehaviourTreeOptions } from \"./BehaviourTreeOptions\";\n\nexport { BehaviourTree, State, convertMDSLToJSON, validateDefinition };\nexport type { FlattenedTreeNode, BehaviourTreeOptions };\n", "/**\n * Enumeration of node state types.\n */\nexport enum State {\n READY = \"mistreevous.ready\",\n RUNNING = \"mistreevous.running\",\n SUCCEEDED = \"mistreevous.succeeded\",\n FAILED = \"mistreevous.failed\"\n}\n\nexport { State as default };\n\nexport type CompleteState = State.SUCCEEDED | State.FAILED;\nexport type AnyState = State.READY | State.RUNNING | CompleteState;\n", "import {\n NodeDefinition,\n RootNodeDefinition,\n DecoratorNodeDefinition,\n CompositeNodeDefinition,\n AnyNodeDefinition,\n BranchNodeDefinition\n} from \"./BehaviourTreeDefinition\";\n\n/**\n * A type guard function that returns true if the specified node satisfies the RootNodeDefinition type.\n * @param node The node.\n * @returns A value of true if the specified node satisfies the RootNodeDefinition type.\n */\nexport function isRootNode(node: NodeDefinition): node is RootNodeDefinition {\n return node.type === \"root\";\n}\n\n/**\n * A type guard function that returns true if the specified node satisfies the BranchNodeDefinition type.\n * @param node The node.\n * @returns A value of true if the specified node satisfies the BranchNodeDefinition type.\n */\nexport function isBranchNode(node: NodeDefinition): node is BranchNodeDefinition {\n return node.type === \"branch\";\n}\n\n/**\n * A type guard function that returns true if the specified node satisfies the NodeDefinition type.\n * @param node The node.\n * @returns A value of true if the specified node satisfies the NodeDefinition type.\n */\nexport function isLeafNode(node: NodeDefinition): node is NodeDefinition {\n return [\"branch\", \"action\", \"condition\", \"wait\"].includes(node.type);\n}\n\n/**\n * A type guard function that returns true if the specified node satisfies the DecoratorNodeDefinition type.\n * @param node The node.\n * @returns A value of true if the specified node satisfies the DecoratorNodeDefinition type.\n */\nexport function isDecoratorNode(node: NodeDefinition): node is DecoratorNodeDefinition {\n return [\"root\", \"repeat\", \"retry\", \"flip\", \"succeed\", \"fail\"].includes(node.type);\n}\n\n/**\n * A type guard function that returns true if the specified node satisfies the CompositeNodeDefinition type.\n * @param node The node.\n * @returns A value of true if the specified node satisfies the CompositeNodeDefinition type.\n */\nexport function isCompositeNode(node: NodeDefinition): node is CompositeNodeDefinition {\n return [\"sequence\", \"selector\", \"lotto\", \"parallel\"].includes(node.type);\n}\n\n/**\n * Flatten a node definition into an array of all of its nested node definitions.\n * @param nodeDefinition The node definition to flatten.\n * @returns An array of all of nested node definitions.\n */\nexport function flattenDefinition(nodeDefinition: AnyNodeDefinition): AnyNodeDefinition[] {\n const nodes: AnyNodeDefinition[] = [];\n\n const processNode = (currentNodeDefinition: AnyNodeDefinition) => {\n nodes.push(currentNodeDefinition);\n\n if (isCompositeNode(currentNodeDefinition)) {\n currentNodeDefinition.children.forEach(processNode);\n } else if (isDecoratorNode(currentNodeDefinition)) {\n processNode(currentNodeDefinition.child);\n }\n };\n\n processNode(nodeDefinition);\n\n return nodes;\n}\n\n/**\n * Determines whether the passed value is an integer.\n * @param value The value to check.\n * @returns Whether the passed value is an integer.\n */\nexport function isInteger(value: unknown): boolean {\n return typeof value === \"number\" && Math.floor(value) === value;\n}\n\n/**\n * Determines whether the passed value is null or undefined.\n * @param value The value to check.\n * @returns Whether the passed value is null or undefined.\n */\nexport function isNullOrUndefined(value: unknown): boolean {\n return typeof value === \"undefined\" || value === null;\n}\n", "/**\n * A type defining an object that holds a reference to substitued string literals parsed from the definition.\n */\nexport type StringLiteralPlaceholders = { [key: string]: string };\n\n/**\n * Pop the next raw token from the specified array of tokens and throw an error if it wasn't the expected one.\n * @param tokens The array of tokens.\n * @param expected An optional string or array or items, one of which must match the next popped token.\n * @returns The popped token.\n */\nexport function popAndCheck(tokens: string[], expected?: string | string[]): string {\n // Get and remove the next token.\n const popped = tokens.shift();\n\n // We were expecting another token but there aren't any.\n if (popped === undefined) {\n throw new Error(\"unexpected end of definition\");\n }\n\n // Do we have an expected token/tokens array?\n if (expected != undefined) {\n // Get an array of expected values, if the popped token matches any then we are all good.\n const expectedValues = typeof expected === \"string\" ? [expected] : expected;\n\n // Check whether the popped token matches at least one of our expected items.\n var tokenMatchesExpectation = expectedValues.some((item) => popped.toUpperCase() === item.toUpperCase());\n\n // Throw an error if the popped token didn't match any of our expected items.\n if (!tokenMatchesExpectation) {\n const expectationString = expectedValues.map((item) => \"'\" + item + \"'\").join(\" or \");\n throw new Error(\"unexpected token found. Expected \" + expectationString + \" but got '\" + popped + \"'\");\n }\n }\n\n // Return the popped token.\n return popped;\n}\n\n/**\n * Swaps out any node/attribute argument string literals with placeholders.\n * @param definition The definition.\n * @returns An object containing a mapping of placeholders to original string values as well as the processed definition string.\n */\nexport function substituteStringLiterals(definition: string): {\n placeholders: StringLiteralPlaceholders;\n processedDefinition: string;\n} {\n // Create an object to hold the mapping of placeholders to original string values.\n const placeholders: StringLiteralPlaceholders = {};\n\n // Replace any string literals wrapped with double quotes in our definition with placeholders to be processed later.\n const processedDefinition = definition.replace(/\\\"(\\\\.|[^\"\\\\])*\\\"/g, (match) => {\n var strippedMatch = match.substring(1, match.length - 1);\n var placeholder = Object.keys(placeholders).find((key) => placeholders[key] === strippedMatch);\n\n // If we have no existing string literal match then create a new placeholder.\n if (!placeholder) {\n placeholder = `@@${Object.keys(placeholders).length}@@`;\n placeholders[placeholder] = strippedMatch;\n }\n\n return placeholder;\n });\n\n return { placeholders, processedDefinition };\n}\n\n/**\n * Parse the tree definition into an array of raw tokens.\n * @param definition The definition.\n * @returns An array of tokens parsed from the definition.\n */\nexport function parseTokensFromDefinition(definition: string): string[] {\n // Add some space around various important characters so that they can be plucked out easier as individual tokens.\n definition = definition.replace(/\\(/g, \" ( \");\n definition = definition.replace(/\\)/g, \" ) \");\n definition = definition.replace(/\\{/g, \" { \");\n definition = definition.replace(/\\}/g, \" } \");\n definition = definition.replace(/\\]/g, \" ] \");\n definition = definition.replace(/\\[/g, \" [ \");\n definition = definition.replace(/\\,/g, \" , \");\n\n // Split the definition into raw token form and return it.\n return definition.replace(/\\s+/g, \" \").trim().split(\" \");\n}\n", "import { StringLiteralPlaceholders, popAndCheck } from \"./MDSLUtilities\";\n\n/**\n * A type representing any node function argument.\n */\ntype Argument = {\n /**\n * The argument value.\n */\n value: T;\n /**\n * The argument type, used for validation.\n */\n type: string;\n};\n\ntype NullArgument = Argument & {\n type: \"null\";\n};\n\ntype BooleanArgument = Argument & {\n type: \"boolean\";\n};\n\ntype NumberArgument = Argument & {\n type: \"number\";\n /**\n * A flag defining whether the number argument value is a valid integer. (used for validation)\n */\n isInteger: boolean;\n};\n\ntype StringPlaceholderArgument = Argument & {\n type: \"string\";\n};\n\ntype IdentifierArgument = Argument & {\n type: \"identifier\";\n};\n\n/**\n * A type representing a reference to any node function argument.\n */\ntype AnyArgument = NullArgument | BooleanArgument | NumberArgument | StringPlaceholderArgument | IdentifierArgument;\n\n/**\n * Parse an array of argument definitions from the specified tokens array.\n * @param tokens The array tokens to parse the argument definitions from.\n * @param stringArgumentPlaceholders The mapping of string literal node argument placeholders to original values.\n * @param argumentValidator The argument validator function.\n * @param validationFailedMessage The exception message to throw if argument validation fails.\n * @returns An array of argument definitions parsed from the specified tokens array.\n */\nexport function parseArgumentTokens(\n tokens: string[],\n stringArgumentPlaceholders: StringLiteralPlaceholders\n): AnyArgument[] {\n const argumentList: AnyArgument[] = [];\n\n // If the next token is not a '[' or '(' then we have no arguments to parse.\n if (![\"[\", \"(\"].includes(tokens[0])) {\n return argumentList;\n }\n\n // Any lists of arguments will always be wrapped in '[]' for node arguments or '()' for attribute arguments.\n // We are looking for a '[' or '(' opener that wraps the argument tokens and the relevant closer.\n const closingToken = popAndCheck(tokens, [\"[\", \"(\"]) === \"[\" ? \"]\" : \")\";\n\n const argumentListTokens: string[] = [];\n\n // Grab all tokens between the '[' and ']' or '(' and ')'.\n while (tokens.length && tokens[0] !== closingToken) {\n // The next token is part of our arguments list.\n argumentListTokens.push(tokens.shift()!);\n }\n\n // Validate the order of the argument tokens. Each token must either be a ',' or a single argument that satisfies the validator.\n argumentListTokens.forEach((token, index) => {\n // Get whether this token should be an actual argument.\n const shouldBeArgumentToken = !(index & 1);\n\n // If the current token should be an actual argument then validate it, otherwise it should be a ',' token.\n if (shouldBeArgumentToken) {\n // Get the argument definition.\n const argumentDefinition = getArgumentDefinition(token, stringArgumentPlaceholders);\n\n // This is a valid argument!\n argumentList.push(argumentDefinition);\n } else {\n // The current token should be a ',' token.\n if (token !== \",\") {\n throw new Error(`invalid argument list, expected ',' or ']' but got '${token}'`);\n }\n }\n });\n\n // The arguments list should terminate with a ']' or ')' token, depending on the opener.\n popAndCheck(tokens, closingToken);\n\n // Return the arguments.\n return argumentList;\n}\n\n/**\n * Gets an argument value definition.\n * @param token The argument token.\n * @param stringArgumentPlaceholders The mapping of string literal node argument placeholders to original values.\n * @returns An argument value definition.\n */\nfunction getArgumentDefinition(token: string, stringArgumentPlaceholders: StringLiteralPlaceholders): AnyArgument {\n // Check whether the token represents a null value.\n if (token === \"null\") {\n return {\n value: null,\n type: \"null\"\n } as NullArgument;\n }\n\n // Check whether the token represents a boolean value.\n if (token === \"true\" || token === \"false\") {\n return {\n value: token === \"true\",\n type: \"boolean\"\n } as BooleanArgument;\n }\n\n // Check whether the token represents a number value.\n // TODO: Relies on broken isNaN - see MDN.\n // if (!Number.isNaN(token)) {\n if (!isNaN(token as any)) {\n return {\n value: parseFloat(token),\n isInteger: parseFloat(token) === parseInt(token, 10),\n type: \"number\"\n } as NumberArgument;\n }\n\n // Check whether the token is a placeholder (e.g. @@0@@) representing a string literal.\n if (token.match(/^@@\\d+@@$/g)) {\n return {\n value: stringArgumentPlaceholders[token].replace('\\\\\"', '\"'),\n type: \"string\"\n } as StringPlaceholderArgument;\n }\n\n // The only remaining option is that the argument value is an identifier.\n return {\n value: token,\n type: \"identifier\"\n } as IdentifierArgument;\n}\n", "import { NodeAttributeDefinition } from \"../BehaviourTreeDefinition\";\nimport { parseArgumentTokens } from \"./MDSLNodeArgumentParser\";\nimport { StringLiteralPlaceholders } from \"./MDSLUtilities\";\n\n/**\n * A type defining the attribute definitions of a node.\n */\ntype NodeAttributes = {\n while?: NodeAttributeDefinition;\n until?: NodeAttributeDefinition;\n entry?: NodeAttributeDefinition;\n exit?: NodeAttributeDefinition;\n step?: NodeAttributeDefinition;\n};\n\n/**\n * Parse any node attribute definitions from the specified tokens array.\n * @param tokens The array of remaining tokens.\n * @param stringArgumentPlaceholders The mapping of string literal node argument placeholders to original values.\n * @returns An object of attribute definitions defined by any directly following tokens.\n */\nexport function parseAttributeTokens(\n tokens: string[],\n stringArgumentPlaceholders: StringLiteralPlaceholders\n): NodeAttributes {\n const nodeAttributeNames: (keyof NodeAttributes)[] = [\"while\", \"until\", \"entry\", \"exit\", \"step\"];\n\n // Create an object to hold any attributes found.\n const attributes: NodeAttributes = {};\n\n // Try to get the name of the attribute for the next token.\n let nextAttributeName = tokens[0]?.toLowerCase() as keyof NodeAttributes;\n\n // Pull attribute tokens as well as their arguments off of the tokens stack until we have no more.\n while (nodeAttributeNames.includes(nextAttributeName)) {\n // Check to make sure that we have not already created an attribute definition of this type.\n if (attributes[nextAttributeName]) {\n throw new Error(`duplicate attribute '${tokens[0].toUpperCase()}' found for node`);\n }\n\n // Remove the attribute name token from the array of tokens.\n tokens.shift();\n\n // Grab the attribute arguments, assuming the first to be an identifier.\n const [attributeCallIdentifier, ...attributeArguments] = parseArgumentTokens(\n tokens,\n stringArgumentPlaceholders\n );\n\n // The first attribute argument has to be an identifer, this will reference an agent function.\n if (attributeCallIdentifier?.type !== \"identifier\") {\n throw new Error(\"expected agent function or registered function name identifier argument for attribute\");\n }\n\n // Any attribute arguments (other than the expected call identifier) must have a type of string, number, boolean or null.\n attributeArguments\n .filter((arg) => arg.type === \"identifier\")\n .forEach((arg) => {\n throw new Error(\n `invalid attribute argument value '${arg.value}', must be string, number, boolean or null`\n );\n });\n\n // Create the attribute definition and add it to the object of attribute definitions found.\n attributes[nextAttributeName] = {\n call: attributeCallIdentifier.value,\n args: attributeArguments.map(({ value }) => value)\n };\n\n // Try to get the next attribute name token, as there could be multiple.\n nextAttributeName = tokens[0]?.toLowerCase() as keyof NodeAttributes;\n }\n\n return attributes;\n}\n", "import {\n ActionNodeDefinition,\n AnyChildNodeDefinition,\n AnyNodeDefinition,\n BranchNodeDefinition,\n ConditionNodeDefinition,\n FailNodeDefinition,\n FlipNodeDefinition,\n LottoNodeDefinition,\n ParallelNodeDefinition,\n RepeatNodeDefinition,\n RetryNodeDefinition,\n RootNodeDefinition,\n SelectorNodeDefinition,\n SequenceNodeDefinition,\n SucceedNodeDefinition,\n WaitNodeDefinition\n} from \"../BehaviourTreeDefinition\";\nimport {\n isCompositeNode,\n isDecoratorNode,\n isLeafNode,\n isNullOrUndefined,\n isRootNode\n} from \"../BehaviourTreeDefinitionUtilities\";\nimport { parseArgumentTokens } from \"./MDSLNodeArgumentParser\";\nimport { parseAttributeTokens } from \"./MDSLNodeAttributeParser\";\nimport {\n StringLiteralPlaceholders,\n parseTokensFromDefinition,\n popAndCheck,\n substituteStringLiterals\n} from \"./MDSLUtilities\";\n\n/**\n * Convert the MDSL tree definition string into an equivalent JSON definition.\n * @param definition The tree definition string as MDSL.\n * @returns The root node JSON definitions.\n */\nexport function convertMDSLToJSON(definition: string): RootNodeDefinition[] {\n // Swap out any node/attribute argument string literals with a placeholder and get a mapping of placeholders to original values as well as the processed definition.\n const { placeholders, processedDefinition } = substituteStringLiterals(definition);\n\n // Parse our definition definition string into an array of raw tokens.\n const tokens = parseTokensFromDefinition(processedDefinition);\n\n return convertTokensToJSONDefinition(tokens, placeholders);\n}\n\n/**\n * Converts the specified tree definition tokens into a JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The root node JSON definitions.\n */\nfunction convertTokensToJSONDefinition(\n tokens: string[],\n stringLiteralPlaceholders: StringLiteralPlaceholders\n): RootNodeDefinition[] {\n // There must be at least 3 tokens for the tree definition to be valid. 'ROOT', '{' and '}'.\n if (tokens.length < 3) {\n throw new Error(\"invalid token count\");\n }\n\n // We should have a matching number of '{' and '}' tokens. If not, then there are scopes that have not been properly closed.\n if (tokens.filter((token) => token === \"{\").length !== tokens.filter((token) => token === \"}\").length) {\n throw new Error(\"scope character mismatch\");\n }\n\n // Create an array of tree stack arrays where root nodes will always be at the botton and the current composite/decorator node at the top.\n // There should be an element in this array for every root node defined and every element should be an array with a root note as the first element.\n // E.g. A definition with two root nodes defined:\n // [\n // [root, lotto, sequence],\n // [root, selector]\n // ]\n const treeStacks: [Partial, ...Partial[]][] = [];\n\n // Create an array of all root node definitions that we create.\n const rootNodes: Partial[] = [];\n\n // A helper function used to push node definitions onto the tree stack.\n const pushNode = (node: AnyNodeDefinition) => {\n // If the node is a root node then we need to create a new tree stack array with the root node at the root.\n if (isRootNode(node)) {\n // We need to double-check that this root node is not the child of another node.\n // We can do this by checking whether the top tree stack is not empty (contains an existing node)\n if (treeStacks[treeStacks.length - 1]?.length) {\n throw new Error(\"a root node cannot be the child of another node\");\n }\n\n // Add the root node definition to our array of all parsed root node definitions.\n rootNodes.push(node);\n\n // Add the root node definition to the root of a new tree stack.\n treeStacks.push([node]);\n\n return;\n }\n\n // All non-root nodes should be pushed after their root nodes so handle cases\n // where we may not have any tree stacks or our top-most tree stack is empty.\n if (!treeStacks.length || !treeStacks[treeStacks.length - 1].length) {\n throw new Error(\"expected root node at base of definition\");\n }\n\n // Get the current tree stack that we are populating.\n const topTreeStack = treeStacks[treeStacks.length - 1];\n\n // Get the top-most node in the current tree stack, this will be a composite/decorator node\n // for which we will populate its children array if composite or setting its child if a decorator.\n const topTreeStackTopNode = topTreeStack[topTreeStack.length - 1] as AnyNodeDefinition;\n\n // If the top-most node in the current root stack is a composite or decorator\n // node then the current node should be added as a child of the top-most node.\n if (isCompositeNode(topTreeStackTopNode)) {\n topTreeStackTopNode.children = topTreeStackTopNode.children || [];\n topTreeStackTopNode.children.push(node);\n } else if (isDecoratorNode(topTreeStackTopNode)) {\n // If the top node already has a child node set then throw an error as a decorator should only have a single child.\n if (topTreeStackTopNode.child) {\n throw new Error(\"a decorator node must only have a single child node\");\n }\n\n topTreeStackTopNode.child = node;\n }\n\n // If the node we are adding is also a composite or decorator node, then we should push it\n // onto the current tree stack, as subsequent nodes will be added as its child/children.\n if (!isLeafNode(node)) {\n topTreeStack.push(node);\n }\n };\n\n // A helper function used to pop the top-most node definition off of the tree stack and return it.\n const popNode = (): AnyNodeDefinition | null => {\n let poppedNode: AnyNodeDefinition | null = null;\n\n // Get the current tree stack that we are populating.\n const topTreeStack = treeStacks[treeStacks.length - 1];\n\n // Pop the top-most node in the current tree stack if there is one.\n if (topTreeStack.length) {\n poppedNode = topTreeStack.pop() as AnyNodeDefinition;\n }\n\n // We don't want any empty tree stacks in our stack of tree stacks.\n if (!topTreeStack.length) {\n treeStacks.pop();\n }\n\n return poppedNode;\n };\n\n // We should keep processing the raw tokens until we run out of them.\n while (tokens.length) {\n // Grab the next token.\n const token = tokens.shift()!;\n\n // How we create the next node depends on the current raw token value.\n switch (token.toUpperCase()) {\n case \"ROOT\": {\n pushNode(createRootNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"SUCCEED\": {\n pushNode(createSucceedNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"FAIL\": {\n pushNode(createFailNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"FLIP\": {\n pushNode(createFlipNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"REPEAT\": {\n pushNode(createRepeatNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"RETRY\": {\n pushNode(createRetryNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"SEQUENCE\": {\n pushNode(createSequenceNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"SELECTOR\": {\n pushNode(createSelectorNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"PARALLEL\": {\n pushNode(createParallelNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"LOTTO\": {\n pushNode(createLottoNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"ACTION\": {\n pushNode(createActionNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"CONDITION\": {\n pushNode(createConditionNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"WAIT\": {\n pushNode(createWaitNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"BRANCH\": {\n pushNode(createBranchNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"}\": {\n // The '}' character closes the current scope and means that we have to pop a node off of the current stack.\n const poppedNode = popNode();\n\n // Now that we have a node definition we can carry out any validation that may require the node to be fully populated.\n if (poppedNode) {\n validatePoppedNode(poppedNode);\n }\n\n break;\n }\n\n default: {\n throw new Error(`unexpected token: ${token}`);\n }\n }\n }\n\n return rootNodes as RootNodeDefinition[];\n}\n\n/**\n * Creates a root node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The root node JSON definition.\n */\nfunction createRootNode(tokens: string[], stringLiteralPlaceholders: StringLiteralPlaceholders): RootNodeDefinition {\n // Create the root node definition.\n let node = {\n type: \"root\"\n } as Partial;\n\n // Parse any node arguments, we should only have one if any which will be an identifier argument for the root identifier.\n const nodeArguments = parseArgumentTokens(tokens, stringLiteralPlaceholders);\n\n // Check whether any node arguments were defined.\n if (nodeArguments.length) {\n // We should only have one argument, if any, which will be an identifier argument for the root identifier.\n if (nodeArguments.length === 1 && nodeArguments[0].type === \"identifier\") {\n // The root node identifier will be the first and only node argument value.\n node.id = nodeArguments[0].value as string;\n } else {\n throw new Error(\"expected single root name argument\");\n }\n }\n\n // Grab any node attribute definitions and spread them into the node definition.\n node = { ...node, ...parseAttributeTokens(tokens, stringLiteralPlaceholders) };\n\n // This is a decorator node, so we expect an opening '{'.\n popAndCheck(tokens, \"{\");\n\n // Return the root node definition.\n return node as RootNodeDefinition;\n}\n\n/**\n * Creates a succeed node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The succeed node JSON definition.\n */\nfunction createSucceedNode(\n tokens: string[],\n stringLiteralPlaceholders: StringLiteralPlaceholders\n): SucceedNodeDefinition {\n const node = {\n type: \"succeed\",\n ...parseAttributeTokens(tokens, stringLiteralPlaceholders)\n } as SucceedNodeDefinition;\n\n // This is a decorator node, so we expect an opening '{'.\n popAndCheck(tokens, \"{\");\n\n // Return the succeed node definition.\n return node;\n}\n\n/**\n * Creates a fail node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The fail node JSON definition.\n */\nfunction createFailNode(tokens: string[], stringLiteralPlaceholders: StringLiteralPlaceholders): FailNodeDefinition {\n const node = {\n type: \"fail\",\n ...parseAttributeTokens(tokens, stringLiteralPlaceholders)\n } as FailNodeDefinition;\n\n // This is a decorator node, so we expect an opening '{'.\n popAndCheck(tokens, \"{\");\n\n // Return the fail node definition.\n return node;\n}\n\n/**\n * Creates a flip node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The flip node JSON definition.\n */\nfunction createFlipNode(tokens: string[], stringLiteralPlaceholders: StringLiteralPlaceholders): FlipNodeDefinition {\n const node = {\n type: \"flip\",\n ...parseAttributeTokens(tokens, stringLiteralPlaceholders)\n } as FlipNodeDefinition;\n\n // This is a decorator node, so we expect an opening '{'.\n popAndCheck(tokens, \"{\");\n\n // Return the flip node definition.\n return node;\n}\n\n/**\n * Creates a repeat node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The repeat node JSON definition.\n */\nfunction createRepeatNode(\n tokens: string[],\n stringLiteralPlaceholders: StringLiteralPlaceholders\n): RepeatNodeDefinition {\n let node = { type: \"repeat\" } as RepeatNodeDefinition;\n\n // Get the node arguments.\n const nodeArguments = parseArgumentTokens(tokens, stringLiteralPlaceholders);\n\n // The arguments of a repeat node are optional. We may have:\n // - No node arguments, in which case the repeat note will iterate indefinitely.\n // - One node argument which will be the explicit number of iterations to make.\n // - Two node arguments which define the min and max iteration bounds from which a random iteration count will be picked.\n if (nodeArguments.length) {\n // All repeat node arguments MUST be of type number and must be integer.\n nodeArguments\n .filter((arg) => arg.type !== \"number\" || !arg.isInteger)\n .forEach(() => {\n throw new Error(`repeat node iteration counts must be integer values`);\n });\n\n // We should have got one or two iteration counts.\n if (nodeArguments.length === 1) {\n // A static iteration count was defined.\n node.iterations = nodeArguments[0].value as number;\n\n // A repeat node must have a positive number of iterations if defined.\n if (node.iterations < 0) {\n throw new Error(\"a repeat node must have a positive number of iterations if defined\");\n }\n } else if (nodeArguments.length === 2) {\n // A minimum and maximum iteration count was defined.\n node.iterations = [nodeArguments[0].value as number, nodeArguments[1].value as number];\n\n // A repeat node must have a positive min and max iteration count if they are defined.\n if (node.iterations[0] < 0 || node.iterations[1] < 0) {\n throw new Error(\"a repeat node must have a positive minimum and maximum iteration count if defined\");\n }\n\n // A repeat node must not have an minimum iteration count that exceeds the maximum iteration count.\n if (node.iterations[0] > node.iterations[1]) {\n throw new Error(\n \"a repeat node must not have a minimum iteration count that exceeds the maximum iteration count\"\n );\n }\n } else {\n // An incorrect number of iteration counts was defined.\n throw new Error(\"invalid number of repeat node iteration count arguments defined\");\n }\n }\n\n // Grab any node attribute definitions and spread them into the node definition.\n node = { ...node, ...parseAttributeTokens(tokens, stringLiteralPlaceholders) };\n\n // This is a decorator node, so we expect an opening '{'.\n popAndCheck(tokens, \"{\");\n\n // Return the repeat node definition.\n return node;\n}\n\n/**\n * Creates a retry node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The retry node JSON definition.\n */\nfunction createRetryNode(tokens: string[], stringLiteralPlaceholders: StringLiteralPlaceholders): RetryNodeDefinition {\n let node = { type: \"retry\" } as RetryNodeDefinition;\n\n // Get the node arguments.\n const nodeArguments = parseArgumentTokens(tokens, stringLiteralPlaceholders);\n\n // The arguments of a retry node are optional. We may have:\n // - No node arguments, in which case the retry note will attempt indefinitely.\n // - One node argument which will be the explicit number of attempts to make.\n // - Two node arguments which define the min and max attempt bounds from which a random attempt count will be picked.\n if (nodeArguments.length) {\n // All retry node arguments MUST be of type number and must be integer.\n nodeArguments\n .filter((arg) => arg.type !== \"number\" || !arg.isInteger)\n .forEach(() => {\n throw new Error(`retry node attempt counts must be integer values`);\n });\n\n // We should have got one or two attempt counts.\n if (nodeArguments.length === 1) {\n // A static attempt count was defined.\n node.attempts = nodeArguments[0].value as number;\n\n // A retry node must have a positive number of attempts if defined.\n if (node.attempts < 0) {\n throw new Error(\"a retry node must have a positive number of attempts if defined\");\n }\n } else if (nodeArguments.length === 2) {\n // A minimum and maximum attempt count was defined.\n node.attempts = [nodeArguments[0].value as number, nodeArguments[1].value as number];\n\n // A retry node must have a positive min and max attempts count if they are defined.\n if (node.attempts[0] < 0 || node.attempts[1] < 0) {\n throw new Error(\"a retry node must have a positive minimum and maximum attempt count if defined\");\n }\n\n // A retry node must not have a minimum attempt count that exceeds the maximum attempt count.\n if (node.attempts[0] > node.attempts[1]) {\n throw new Error(\n \"a retry node must not have a minimum attempt count that exceeds the maximum attempt count\"\n );\n }\n } else {\n // An incorrect number of attempt counts was defined.\n throw new Error(\"invalid number of retry node attempt count arguments defined\");\n }\n }\n\n // Grab any node attribute definitions and spread them into the node definition.\n node = { ...node, ...parseAttributeTokens(tokens, stringLiteralPlaceholders) };\n\n // This is a decorator node, so we expect an opening '{'.\n popAndCheck(tokens, \"{\");\n\n // Return the retry node definition.\n return node;\n}\n\n/**\n * Creates a sequence node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The sequence node JSON definition.\n */\nfunction createSequenceNode(\n tokens: string[],\n stringLiteralPlaceholders: StringLiteralPlaceholders\n): SequenceNodeDefinition {\n const node = {\n type: \"sequence\",\n ...parseAttributeTokens(tokens, stringLiteralPlaceholders)\n } as SequenceNodeDefinition;\n\n // This is a composite node, so we expect an opening '{'.\n popAndCheck(tokens, \"{\");\n\n // Return the sequence node definition.\n return node;\n}\n\n/**\n * Creates a selector node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The selector node JSON definition.\n */\nfunction createSelectorNode(\n tokens: string[],\n stringLiteralPlaceholders: StringLiteralPlaceholders\n): SelectorNodeDefinition {\n const node = {\n type: \"selector\",\n ...parseAttributeTokens(tokens, stringLiteralPlaceholders)\n } as SelectorNodeDefinition;\n\n // This is a composite node, so we expect an opening '{'.\n popAndCheck(tokens, \"{\");\n\n // Return the selector node definition.\n return node;\n}\n\n/**\n * Creates a parallel node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The parallel node JSON definition.\n */\nfunction createParallelNode(\n tokens: string[],\n stringLiteralPlaceholders: StringLiteralPlaceholders\n): ParallelNodeDefinition {\n const node = {\n type: \"parallel\",\n ...parseAttributeTokens(tokens, stringLiteralPlaceholders)\n } as ParallelNodeDefinition;\n\n // This is a composite node, so we expect an opening '{'.\n popAndCheck(tokens, \"{\");\n\n // Return the parallel node definition.\n return node;\n}\n\n/**\n * Creates a lotto node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The lotto node JSON definition.\n */\nfunction createLottoNode(tokens: string[], stringLiteralPlaceholders: StringLiteralPlaceholders): LottoNodeDefinition {\n // If any node arguments have been defined then they must be our weights.\n const nodeArguments = parseArgumentTokens(tokens, stringLiteralPlaceholders);\n\n // All lotto node arguments MUST be of type number and must be positive integers.\n nodeArguments\n .filter((arg) => arg.type !== \"number\" || !arg.isInteger || arg.value < 0)\n .forEach(() => {\n throw new Error(`lotto node weight arguments must be positive integer values`);\n });\n\n const node = {\n type: \"lotto\",\n ...parseAttributeTokens(tokens, stringLiteralPlaceholders)\n } as LottoNodeDefinition;\n\n // Apply the weights if any were defined.\n if (nodeArguments.length) {\n node.weights = nodeArguments.map(({ value }) => value) as number[];\n }\n\n // This is a composite node, so we expect an opening '{'.\n popAndCheck(tokens, \"{\");\n\n // Return the lotto node definition.\n return node;\n}\n\n/**\n * Creates an action node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The action node JSON definition.\n */\nfunction createActionNode(\n tokens: string[],\n stringLiteralPlaceholders: StringLiteralPlaceholders\n): ActionNodeDefinition {\n // Parse any node arguments, we should have at least one which will be an identifier argument for the action name\n // and agent function to invoke for the action, all other arguments are to be passed as arguments to that function.\n const [actionNameIdentifier, ...agentFunctionArgs] = parseArgumentTokens(tokens, stringLiteralPlaceholders);\n\n // Our first argument MUST be defined and be an identifier as we require an action name argument.\n if (actionNameIdentifier?.type !== \"identifier\") {\n throw new Error(\"expected action name identifier argument\");\n }\n\n // Only the first argument should have been an identifier, all agent function arguments must be string, number, boolean or null.\n agentFunctionArgs\n .filter((arg) => arg.type === \"identifier\")\n .forEach((arg) => {\n throw new Error(\n `invalid action node argument value '${arg.value}', must be string, number, boolean or null`\n );\n });\n\n // Return the action node definition.\n return {\n type: \"action\",\n call: actionNameIdentifier.value,\n args: agentFunctionArgs.map(({ value }) => value),\n ...parseAttributeTokens(tokens, stringLiteralPlaceholders)\n };\n}\n\n/**\n * Creates a condition node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The condition node JSON definition.\n */\nfunction createConditionNode(\n tokens: string[],\n stringLiteralPlaceholders: StringLiteralPlaceholders\n): ConditionNodeDefinition {\n // Parse any node arguments, we should have at least one which will be an identifier argument for the condition name\n // and agent function to invoke for the condition, all other arguments are to be passed as arguments to that function.\n const [conditionNameIdentifier, ...agentFunctionArgs] = parseArgumentTokens(tokens, stringLiteralPlaceholders);\n\n // Our first argument MUST be defined and be an identifier as we require a condition name argument.\n if (conditionNameIdentifier?.type !== \"identifier\") {\n throw new Error(\"expected condition name identifier argument\");\n }\n\n // Only the first argument should have been an identifier, all agent function arguments must be string, number, boolean or null.\n agentFunctionArgs\n .filter((arg) => arg.type === \"identifier\")\n .forEach((arg) => {\n throw new Error(\n `invalid condition node argument value '${arg.value}', must be string, number, boolean or null`\n );\n });\n\n // Return the condition node definition.\n return {\n type: \"condition\",\n call: conditionNameIdentifier.value,\n args: agentFunctionArgs.map(({ value }) => value),\n ...parseAttributeTokens(tokens, stringLiteralPlaceholders)\n };\n}\n\n/**\n * Creates a wait node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The wait node JSON definition.\n */\nfunction createWaitNode(tokens: string[], stringLiteralPlaceholders: StringLiteralPlaceholders): WaitNodeDefinition {\n let node = { type: \"wait\" } as WaitNodeDefinition;\n\n // Get the node arguments.\n const nodeArguments = parseArgumentTokens(tokens, stringLiteralPlaceholders);\n\n // The arguments of a wait node are optional. We may have:\n // - No node arguments, in which case the wait will be indefinite until it is aborted.\n // - One node argument which will be the explicit duration of the wait.\n // - Two node arguments which define the min and max duration bounds from which a random duration will be picked.\n if (nodeArguments.length) {\n // All wait node arguments MUST be of type number and must be integer.\n nodeArguments\n .filter((arg) => arg.type !== \"number\" || !arg.isInteger)\n .forEach(() => {\n throw new Error(`wait node durations must be integer values`);\n });\n\n // We may have:\n // - One node argument which will be the explicit duration of the wait.\n // - Two node arguments which define the min and max duration bounds from which a random duration will be picked.\n // - Too many arguments, which is not valid.\n if (nodeArguments.length === 1) {\n // An explicit duration was defined.\n node.duration = nodeArguments[0].value as number;\n\n // If an explict duration was defined then it must be a positive number.\n if (node.duration < 0) {\n throw new Error(\"a wait node must have a positive duration\");\n }\n } else if (nodeArguments.length === 2) {\n // Min and max duration bounds were defined from which a random duration will be picked.\n node.duration = [nodeArguments[0].value as number, nodeArguments[1].value as number];\n\n // A wait node must have a positive min and max duration.\n if (node.duration[0] < 0 || node.duration[1] < 0) {\n throw new Error(\"a wait node must have a positive minimum and maximum duration\");\n }\n\n // A wait node must not have a minimum duration that exceeds the maximum duration.\n if (node.duration[0] > node.duration[1]) {\n throw new Error(\"a wait node must not have a minimum duration that exceeds the maximum duration\");\n }\n } else if (nodeArguments.length > 2) {\n // An incorrect number of duration arguments were defined.\n throw new Error(\"invalid number of wait node duration arguments defined\");\n }\n }\n\n // Return the wait node definition.\n return { ...node, ...parseAttributeTokens(tokens, stringLiteralPlaceholders) };\n}\n\n/**\n * Creates a branch node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The branch node JSON definition.\n */\nfunction createBranchNode(\n tokens: string[],\n stringLiteralPlaceholders: StringLiteralPlaceholders\n): BranchNodeDefinition {\n // Parse any node arguments, we should have one which will be an identifier argument for the root ref.\n const nodeArguments = parseArgumentTokens(tokens, stringLiteralPlaceholders);\n\n // We should have only a single identifer argument for a branch node, which is the root ref.\n if (nodeArguments.length !== 1 || nodeArguments[0].type !== \"identifier\") {\n throw new Error(\"expected single branch name argument\");\n }\n\n // Return the branch node definition.\n return { type: \"branch\", ref: nodeArguments[0].value };\n}\n\n/**\n * Validate a fully-populated node definition that was popped off of the tree stack.\n * @param definition The popped node to validate.\n */\nfunction validatePoppedNode(definition: AnyNodeDefinition): void {\n // Decorators MUST have a child defined.\n if (isDecoratorNode(definition) && isNullOrUndefined(definition.child)) {\n throw new Error(`a ${definition.type} node must have a single child node defined`);\n }\n\n // Composites MUST have at least one child defined.\n if (isCompositeNode(definition) && !definition.children?.length) {\n throw new Error(`a ${definition.type} node must have at least a single child node defined`);\n }\n\n // We need to make sure that lotto nodes that have weights defined have a number of weights matching the number of child nodes.\n if (definition.type === \"lotto\") {\n // Check whether a 'weights' property has been defined, if it has we expect it to be an array of weights.\n if (typeof definition.weights !== \"undefined\") {\n // Check that the weights property is an array of positive integers with an element for each child node element.\n if (definition.weights.length !== definition.children.length) {\n throw new Error(\n \"expected a number of weight arguments matching the number of child nodes for lotto node\"\n );\n }\n }\n }\n}\n", "import { RootNodeDefinition } from \"./BehaviourTreeDefinition\";\nimport { flattenDefinition, isBranchNode, isInteger } from \"./BehaviourTreeDefinitionUtilities\";\nimport { convertMDSLToJSON } from \"./mdsl/MDSLDefinitionParser\";\n\n/**\n * An object representing the result of validating a tree definition.\n */\nexport type DefinitionValidationResult = {\n /**\n * A flag defining whether validation succeeded.\n */\n succeeded: boolean;\n /**\n * A string containing the error message if validation did not succeed.\n */\n errorMessage?: string;\n /**\n * The definition as json if the validation was successful, or undefined if validation did not succeed.\n */\n json?: RootNodeDefinition[];\n};\n\n/**\n * Validates the specified behaviour tree definition in the form of JSON or MDSL, not taking any globally registered subtrees into consideration.\n * @param definition The behaviour tree definition in the form of JSON or MDSL.\n * @returns An object representing the result of validating the given tree definition.\n */\nexport function validateDefinition(definition: any): DefinitionValidationResult {\n // The definition must be defined.\n if (definition === null || typeof definition === \"undefined\") {\n return createValidationFailureResult(\"definition is null or undefined\");\n }\n\n // We are expecting a definition in one of three different forms:\n // - A string which we will assume is MDSL and we will parse this to JSON before validation.\n // - An array which we will assume is an array of root node definitions with at least one being the primary root node (no 'id' property)\n // - An object which we will assume is the primary root node and should not have an 'id' property.\n if (typeof definition === \"string\") {\n // The definition is a string which we can assume is MDSL, so attempt to validate it.\n return validateMDSLDefinition(definition);\n } else if (typeof definition === \"object\") {\n // The definition will either be an array (of root node definitions) or an object (the single primary root node definition).\n return validateJSONDefinition(definition);\n } else {\n return createValidationFailureResult(`unexpected definition type of '${typeof definition}'`);\n }\n}\n\n/**\n * Validates the specified behaviour tree definition in the form of MDSL.\n * @param definition The behaviour tree definition in the form of MDSL.\n * @returns An object representing the result of validating the given tree definition.\n */\nfunction validateMDSLDefinition(definition: string): DefinitionValidationResult {\n let rootNodeDefinitions;\n\n // The first thing the we need to do is to attempt to convert our MDSL into JSON.\n try {\n // The definition is a string which we can assume is MDSL, so attempt to parse it to a JSON definition in the form of an array of root node definitions.\n rootNodeDefinitions = convertMDSLToJSON(definition);\n } catch (exception) {\n // We failed to parse the JSON from the MDSL, this is likely to be the result of it not being a valid MDSL string.\n return createValidationFailureResult((exception as Error).message);\n }\n\n // Unpack all of the root node definitions into arrays of main ('id' defined) and sub ('id' not defined) root node definitions.\n const mainRootNodeDefinitions = rootNodeDefinitions.filter(({ id }) => typeof id === \"undefined\");\n const subRootNodeDefinitions = rootNodeDefinitions.filter(({ id }) => typeof id === \"string\" && id.length > 0);\n\n // We should ALWAYS have exactly one root node definition without an 'id' property defined, which is out main root node definition.\n if (mainRootNodeDefinitions.length !== 1) {\n return createValidationFailureResult(\n \"expected single unnamed root node at base of definition to act as main root\"\n );\n }\n\n // We should never have duplicate 'id' properties across our sub root node definitions.\n const subRootNodeIdenitifers: string[] = [];\n for (const { id } of subRootNodeDefinitions) {\n // Have we already come across this 'id' property value?\n if (subRootNodeIdenitifers.includes(id!)) {\n return createValidationFailureResult(`multiple root nodes found with duplicate name '${id}'`);\n }\n\n subRootNodeIdenitifers.push(id!);\n }\n\n try {\n // Validate our branch -> subtree links and check for any circular dependencies, we don't care about checking for broken subtree links here.\n validateBranchSubtreeLinks(rootNodeDefinitions, false);\n } catch (exception) {\n return createValidationFailureResult((exception as Error).message);\n }\n\n // Our definition was valid!\n return {\n succeeded: true,\n json: rootNodeDefinitions\n };\n}\n\n/**\n * Validates the specified behaviour tree definition in the form of JSON.\n * @param definition The behaviour tree definition in the form of JSON.\n * @returns An object representing the result of validating the given tree definition.\n */\nexport function validateJSONDefinition(\n definition: RootNodeDefinition | RootNodeDefinition[]\n): DefinitionValidationResult {\n // The definition will either be an array (of root node definitions) or an object (the single primary root node definition).\n const rootNodeDefinitions = Array.isArray(definition) ? definition : [definition];\n\n // Iterate over our array of root nodes and call validateNode for each, passing an initial depth of 0, wrapped in a try catch to handle validation failures.\n try {\n rootNodeDefinitions.forEach((rootNodeDefinition) => validateNode(rootNodeDefinition, 0));\n } catch (error) {\n // Handle cases where we have caught a thrown Error and return a failure result with the error message.\n if (error instanceof Error) {\n return createValidationFailureResult(error.message);\n }\n\n // No idea what happened here!\n return createValidationFailureResult(`unexpected error: ${error}`);\n }\n\n // Unpack all of the root node definitions into arrays of main ('id' defined) and sub ('id' not defined) root node definitions.\n const mainRootNodeDefinitions = rootNodeDefinitions.filter(({ id }) => typeof id === \"undefined\");\n const subRootNodeDefinitions = rootNodeDefinitions.filter(({ id }) => typeof id === \"string\" && id.length > 0);\n\n // We should ALWAYS have exactly one root node definition without an 'id' property defined, which is out main root node definition.\n if (mainRootNodeDefinitions.length !== 1) {\n return createValidationFailureResult(\n \"expected single root node without 'id' property defined to act as main root\"\n );\n }\n\n // We should never have duplicate 'id' properties across our sub root node definitions.\n const subRootNodeIdenitifers: string[] = [];\n for (const { id } of subRootNodeDefinitions) {\n // Have we already come across this 'id' property value?\n if (subRootNodeIdenitifers.includes(id!)) {\n return createValidationFailureResult(\n `multiple root nodes found with duplicate 'id' property value of '${id}'`\n );\n }\n\n subRootNodeIdenitifers.push(id!);\n }\n\n try {\n // Validate our branch -> subtree links and check for any circular dependencies, we don't care about checking for broken subtree links here.\n validateBranchSubtreeLinks(rootNodeDefinitions, false);\n } catch (exception) {\n return createValidationFailureResult((exception as Error).message);\n }\n\n // Our definition was valid!\n return {\n succeeded: true,\n json: rootNodeDefinitions\n };\n}\n\n/**\n * Validates the branch -> subtree links across all provided root node definitions.\n * This will not consider branch nodes that reference any globally registered subtrees unless includesGlobalSubtrees\n * is set to true, in which case we will also verify that there are no broken branch -> subtree links.\n * @param rootNodeDefinitions The array of root node definitions.\n * @param includesGlobalSubtrees A flag defining whether the array includes all global subtree root node definitions.\n */\nexport function validateBranchSubtreeLinks(rootNodeDefinitions: RootNodeDefinition[], includesGlobalSubtrees: boolean) {\n // Create a mapping of root node identifiers to other root nodes that they reference via branch nodes.\n // Below is an example of a mapping that includes a circular dependency (root => a => b => c => a)\n // [{ refs: [\"a\", \"b\"] }, { id: \"a\", refs: [\"b\"] }, { id: \"b\", refs: [\"c\"] }, { id: \"c\", refs: [\"a\"] }]\n const rootNodeMappings: { id: string | undefined; refs: string[] }[] = rootNodeDefinitions.map(\n (rootNodeDefinition) => ({\n id: rootNodeDefinition.id,\n refs: flattenDefinition(rootNodeDefinition)\n .filter(isBranchNode)\n .map(({ ref }) => ref)\n })\n );\n\n // A recursive function to walk through the mappings, keeping track of which root nodes we have visited in the form of a path of root node identifiers.\n const followRefs = (mapping: { id: string | undefined; refs: string[] }, path: (string | undefined)[] = []) => {\n // Have we found a circular dependency?\n if (path.includes(mapping.id)) {\n // We found a circular dependency! Get the bad path of root node identifiers.\n const badPath = [...path, mapping.id];\n\n // Create the formatted path value. [undefined, \"a\", \"b\", \"c\", \"a\"] would be formatted as \"a -> b -> c -> a\".\n const badPathFormatted = badPath.filter((element) => !!element).join(\" => \");\n\n // No need to continue, we found a circular dependency.\n throw new Error(`circular dependency found in branch node references: ${badPathFormatted}`);\n }\n\n for (const ref of mapping.refs) {\n // Find the mapping for the root node with an identifer matching the current ref.\n const subMapping = rootNodeMappings.find(({ id }) => id === ref);\n\n // We may not have a mapping for this ref, which is normal when we aren't considering all globally registered subtrees.\n if (subMapping) {\n followRefs(subMapping, [...path, mapping.id]);\n } else if (includesGlobalSubtrees) {\n // We found a reference to a root node that doesn't exist, which is a problem seeing as the root node definitons includes all globally registered subtrees.\n throw new Error(\n mapping.id\n ? `subtree '${mapping.id}' has branch node that references root node '${ref}' which has not been defined`\n : `primary tree has branch node that references root node '${ref}' which has not been defined`\n );\n }\n }\n };\n\n // Start looking for circular dependencies and broken references from the primary root node definition.\n followRefs(rootNodeMappings.find((mapping) => typeof mapping.id === \"undefined\")!);\n}\n\n/**\n * Validate an object that we expect to be a node definition.\n * @param definition An object that we expect to be a node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateNode(definition: any, depth: number): void {\n // Every node must be valid object and have a non-empty 'type' string property.\n if (typeof definition !== \"object\" || typeof definition.type !== \"string\" || definition.type.length === 0) {\n throw new Error(\n `node definition is not an object or 'type' property is not a non-empty string at depth '${depth}'`\n );\n }\n\n // How we validate this node definition will depend on its type.\n switch (definition.type) {\n case \"action\":\n validateActionNode(definition, depth);\n break;\n\n case \"condition\":\n validateConditionNode(definition, depth);\n break;\n\n case \"wait\":\n validateWaitNode(definition, depth);\n break;\n\n case \"branch\":\n validateBranchNode(definition, depth);\n break;\n\n case \"root\":\n validateRootNode(definition, depth);\n break;\n\n case \"succeed\":\n validateSucceedNode(definition, depth);\n break;\n\n case \"fail\":\n validateFailNode(definition, depth);\n break;\n\n case \"flip\":\n validateFlipNode(definition, depth);\n break;\n\n case \"repeat\":\n validateRepeatNode(definition, depth);\n break;\n\n case \"retry\":\n validateRetryNode(definition, depth);\n break;\n\n case \"sequence\":\n validateSequenceNode(definition, depth);\n break;\n\n case \"selector\":\n validateSelectorNode(definition, depth);\n break;\n\n case \"parallel\":\n validateParallelNode(definition, depth);\n break;\n\n case \"lotto\":\n validateLottoNode(definition, depth);\n break;\n\n default:\n throw new Error(`unexpected node type of '${definition.type}' at depth '${depth}'`);\n }\n}\n\n/**\n * Validate any attributes for a given node definition.\n * @param definition The node definition.\n * @param depth The depth of the node in the behaviour tree definition.\n */\nfunction validateNodeAttributes(definition: any, depth: number): void {\n // Validate each of the attribute types for this node.\n [\"while\", \"until\", \"entry\", \"exit\", \"step\"].forEach((attributeName) => {\n // Attempt to grab the definition for the current attribute from the node definition.\n const attributeDefinition = definition[attributeName];\n\n // All node attributes are optional, so there is nothing to do if the current attribute is not defined.\n if (typeof attributeDefinition === \"undefined\") {\n return;\n }\n\n // The attribute definition must be an object.\n if (typeof attributeDefinition !== \"object\") {\n throw new Error(\n `expected attribute '${attributeName}' to be an object for '${definition.type}' node at depth '${depth}'`\n );\n }\n\n // The 'call' property must be defined for any attribute definition.\n if (typeof attributeDefinition.call !== \"string\" || attributeDefinition.call.length === 0) {\n throw new Error(\n `expected 'call' property for attribute '${attributeName}' to be a non-empty string for '${definition.type}' node at depth '${depth}'`\n );\n }\n\n // If any node attribute arguments have been defined then they must have been defined in an array.\n if (typeof attributeDefinition.args !== \"undefined\" && !Array.isArray(attributeDefinition.args)) {\n throw new Error(\n `expected 'args' property for attribute '${attributeName}' to be an array for '${definition.type}' node at depth '${depth}'`\n );\n }\n });\n}\n\n/**\n * Validate an object that we expect to be a root node definition.\n * @param definition An object that we expect to be a root node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateRootNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"root\") {\n throw new Error(\"expected node type of 'root' for root node\");\n }\n\n // A root node cannot be the child of another node.\n if (depth > 0) {\n throw new Error(\"a root node cannot be the child of another node\");\n }\n\n // Check that, if the root node 'id' property is defined, it is a non-empty string.\n if (typeof definition.id !== \"undefined\" && (typeof definition.id !== \"string\" || definition.id.length === 0)) {\n throw new Error(\"expected non-empty string for 'id' property if defined for root node\");\n }\n\n // A root node is a decorator node, so must have a child node defined.\n if (typeof definition.child === \"undefined\") {\n throw new Error(\"expected property 'child' to be defined for root node\");\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n\n // Validate the child node of this decorator node.\n validateNode(definition.child, depth + 1);\n}\n\n/**\n * Validate an object that we expect to be a succeed node definition.\n * @param definition An object that we expect to be a succeed node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateSucceedNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"succeed\") {\n throw new Error(`expected node type of 'succeed' for succeed node at depth '${depth}'`);\n }\n\n // A succeed node is a decorator node, so must have a child node defined.\n if (typeof definition.child === \"undefined\") {\n throw new Error(`expected property 'child' to be defined for succeed node at depth '${depth}'`);\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n\n // Validate the child node of this decorator node.\n validateNode(definition.child, depth + 1);\n}\n\n/**\n * Validate an object that we expect to be a fail node definition.\n * @param definition An object that we expect to be a fail node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateFailNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"fail\") {\n throw new Error(`expected node type of 'fail' for fail node at depth '${depth}'`);\n }\n\n // A fail node is a decorator node, so must have a child node defined.\n if (typeof definition.child === \"undefined\") {\n throw new Error(`expected property 'child' to be defined for fail node at depth '${depth}'`);\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n\n // Validate the child node of this decorator node.\n validateNode(definition.child, depth + 1);\n}\n\n/**\n * Validate an object that we expect to be a flip node definition.\n * @param definition An object that we expect to be a flip node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateFlipNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"flip\") {\n throw new Error(`expected node type of 'flip' for flip node at depth '${depth}'`);\n }\n\n // A flip node is a decorator node, so must have a child node defined.\n if (typeof definition.child === \"undefined\") {\n throw new Error(`expected property 'child' to be defined for flip node at depth '${depth}'`);\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n\n // Validate the child node of this decorator node.\n validateNode(definition.child, depth + 1);\n}\n\n/**\n * Validate an object that we expect to be a repeat node definition.\n * @param definition An object that we expect to be a repeat node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateRepeatNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"repeat\") {\n throw new Error(`expected node type of 'repeat' for repeat node at depth '${depth}'`);\n }\n\n // A repeat node is a decorator node, so must have a child node defined.\n if (typeof definition.child === \"undefined\") {\n throw new Error(`expected property 'child' to be defined for repeat node at depth '${depth}'`);\n }\n\n // Check whether an 'iterations' property has been defined, it may not have been if this node is to repeat indefinitely.\n if (typeof definition.iterations !== \"undefined\") {\n if (Array.isArray(definition.iterations)) {\n // Check whether any elements of the array are not integer values.\n const containsNonInteger = !!definition.iterations.filter((value: unknown) => !isInteger(value)).length;\n\n // If the 'iterations' property is an array then it MUST contain two integer values.\n if (definition.iterations.length !== 2 || containsNonInteger) {\n throw new Error(\n `expected array containing two integer values for 'iterations' property if defined for repeat node at depth '${depth}'`\n );\n }\n\n // A repeat node must have a positive min and max iterations count if they are defined.\n if (definition.iterations[0] < 0 || definition.iterations[1] < 0) {\n throw new Error(\n `expected positive minimum and maximum iterations count for 'iterations' property if defined for repeat node at depth '${depth}'`\n );\n }\n\n // A repeat node must not have a minimum iterations count that exceeds the maximum iterations count.\n if (definition.iterations[0] > definition.iterations[1]) {\n throw new Error(\n `expected minimum iterations count that does not exceed the maximum iterations count for 'iterations' property if defined for repeat node at depth '${depth}'`\n );\n }\n } else if (isInteger(definition.iterations)) {\n // A repeat node must have a positive number of iterations if defined.\n if (definition.iterations < 0) {\n throw new Error(\n `expected positive iterations count for 'iterations' property if defined for repeat node at depth '${depth}'`\n );\n }\n } else {\n throw new Error(\n `expected integer value or array containing two integer values for 'iterations' property if defined for repeat node at depth '${depth}'`\n );\n }\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n\n // Validate the child node of this decorator node.\n validateNode(definition.child, depth + 1);\n}\n\n/**\n * Validate an object that we expect to be a retry node definition.\n * @param definition An object that we expect to be a retry node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateRetryNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"retry\") {\n throw new Error(`expected node type of 'retry' for retry node at depth '${depth}'`);\n }\n\n // A retry node is a decorator node, so must have a child node defined.\n if (typeof definition.child === \"undefined\") {\n throw new Error(`expected property 'child' to be defined for retry node at depth '${depth}'`);\n }\n\n // Check whether an 'attempts' property has been defined, it may not have been if this node is to retry indefinitely.\n if (typeof definition.attempts !== \"undefined\") {\n if (Array.isArray(definition.attempts)) {\n // Check whether any elements of the array are not integer values.\n const containsNonInteger = !!definition.attempts.filter((value: unknown) => !isInteger(value)).length;\n\n // If the 'attempts' property is an array then it MUST contain two integer values.\n if (definition.attempts.length !== 2 || containsNonInteger) {\n throw new Error(\n `expected array containing two integer values for 'attempts' property if defined for retry node at depth '${depth}'`\n );\n }\n\n // A retry node must have a positive min and max attempts count if they are defined.\n if (definition.attempts[0] < 0 || definition.attempts[1] < 0) {\n throw new Error(\n `expected positive minimum and maximum attempts count for 'attempts' property if defined for retry node at depth '${depth}'`\n );\n }\n\n // A retry node must not have a minimum attempts count that exceeds the maximum attempts count.\n if (definition.attempts[0] > definition.attempts[1]) {\n throw new Error(\n `expected minimum attempts count that does not exceed the maximum attempts count for 'attempts' property if defined for retry node at depth '${depth}'`\n );\n }\n } else if (isInteger(definition.attempts)) {\n // A retry node must have a positive number of attempts if defined.\n if (definition.attempts < 0) {\n throw new Error(\n `expected positive attempts count for 'attempts' property if defined for retry node at depth '${depth}'`\n );\n }\n } else {\n throw new Error(\n `expected integer value or array containing two integer values for 'attempts' property if defined for retry node at depth '${depth}'`\n );\n }\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n\n // Validate the child node of this decorator node.\n validateNode(definition.child, depth + 1);\n}\n\n/**\n * Validate an object that we expect to be a branch node definition.\n * @param definition An object that we expect to be a branch node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateBranchNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"branch\") {\n throw new Error(`expected node type of 'branch' for branch node at depth '${depth}'`);\n }\n\n // Check that the branch node 'ref' property is defined and is a non-empty string.\n if (typeof definition.ref !== \"string\" || definition.ref.length === 0) {\n throw new Error(`expected non-empty string for 'ref' property for branch node at depth '${depth}'`);\n }\n\n // It is invalid to define guard attributes for a branch node as they should be defined on the referenced root node.\n [\"while\", \"until\"].forEach((attributeName) => {\n if (typeof definition[attributeName] !== \"undefined\") {\n throw new Error(\n `guards should not be defined for branch nodes but guard '${attributeName}' was defined for branch node at depth '${depth}'`\n );\n }\n });\n\n // It is invalid to define callback attributes for a branch node as they should be defined on the referenced root node.\n [\"entry\", \"exit\", \"step\"].forEach((attributeName) => {\n if (typeof definition[attributeName] !== \"undefined\") {\n throw new Error(\n `callbacks should not be defined for branch nodes but callback '${attributeName}' was defined for branch node at depth '${depth}'`\n );\n }\n });\n}\n\n/**\n * Validate an object that we expect to be a action node definition.\n * @param definition An object that we expect to be a action node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateActionNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"action\") {\n throw new Error(`expected node type of 'action' for action node at depth '${depth}'`);\n }\n\n // The 'call' property must be defined for a action node definition.\n if (typeof definition.call !== \"string\" || definition.call.length === 0) {\n throw new Error(`expected non-empty string for 'call' property of action node at depth '${depth}'`);\n }\n\n // If any action function arguments have been defined then they must have been defined in an array.\n if (typeof definition.args !== \"undefined\" && !Array.isArray(definition.args)) {\n throw new Error(`expected array for 'args' property if defined for action node at depth '${depth}'`);\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n}\n\n/**\n * Validate an object that we expect to be a condition node definition.\n * @param definition An object that we expect to be a condition node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateConditionNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"condition\") {\n throw new Error(`expected node type of 'condition' for condition node at depth '${depth}'`);\n }\n\n // The 'call' property must be defined for a condition node definition.\n if (typeof definition.call !== \"string\" || definition.call.length === 0) {\n throw new Error(`expected non-empty string for 'call' property of condition node at depth '${depth}'`);\n }\n\n // If any condition function arguments have been defined then they must have been defined in an array.\n if (typeof definition.args !== \"undefined\" && !Array.isArray(definition.args)) {\n throw new Error(`expected array for 'args' property if defined for condition node at depth '${depth}'`);\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n}\n\n/**\n * Validate an object that we expect to be a wait node definition.\n * @param definition An object that we expect to be a wait node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateWaitNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"wait\") {\n throw new Error(`expected node type of 'wait' for wait node at depth '${depth}'`);\n }\n\n // Check whether a 'duration' property has been defined, it may not have been if this node is to wait indefinitely.\n if (typeof definition.duration !== \"undefined\") {\n if (Array.isArray(definition.duration)) {\n // Check whether any elements of the array are not integer values.\n const containsNonInteger = !!definition.duration.filter((value: unknown) => !isInteger(value)).length;\n\n // If the 'duration' property is an array then it MUST contain two integer values.\n if (definition.duration.length !== 2 || containsNonInteger) {\n throw new Error(\n `expected array containing two integer values for 'duration' property if defined for wait node at depth '${depth}'`\n );\n }\n\n // A wait node must have a positive min and max duration value if they are defined.\n if (definition.duration[0] < 0 || definition.duration[1] < 0) {\n throw new Error(\n `expected positive minimum and maximum duration for 'duration' property if defined for wait node at depth '${depth}'`\n );\n }\n\n // A wait node must not have a minimum duration value that exceeds the maximum duration value.\n if (definition.duration[0] > definition.duration[1]) {\n throw new Error(\n `expected minimum duration value that does not exceed the maximum duration value for 'duration' property if defined for wait node at depth '${depth}'`\n );\n }\n } else if (isInteger(definition.duration)) {\n // A wait node must have a positive duration value if defined.\n if (definition.duration < 0) {\n throw new Error(\n `expected positive duration value for 'duration' property if defined for wait node at depth '${depth}'`\n );\n }\n } else {\n throw new Error(\n `expected integer value or array containing two integer values for 'duration' property if defined for wait node at depth '${depth}'`\n );\n }\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n}\n\n/**\n * Validate an object that we expect to be a sequence node definition.\n * @param definition An object that we expect to be a sequence node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateSequenceNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"sequence\") {\n throw new Error(`expected node type of 'sequence' for sequence node at depth '${depth}'`);\n }\n\n // A sequence node is a composite node, so must have a children nodes array defined.\n if (!Array.isArray(definition.children) || definition.children.length === 0) {\n throw new Error(`expected non-empty 'children' array to be defined for sequence node at depth '${depth}'`);\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n\n // Validate the child nodes of this composite node.\n definition.children.forEach((child: any) => validateNode(child, depth + 1));\n}\n\n/**\n * Validate an object that we expect to be a selector node definition.\n * @param definition An object that we expect to be a selector node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateSelectorNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"selector\") {\n throw new Error(`expected node type of 'selector' for selector node at depth '${depth}'`);\n }\n\n // A selector node is a composite node, so must have a children nodes array defined.\n if (!Array.isArray(definition.children) || definition.children.length === 0) {\n throw new Error(`expected non-empty 'children' array to be defined for selector node at depth '${depth}'`);\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n\n // Validate the child nodes of this composite node.\n definition.children.forEach((child: any) => validateNode(child, depth + 1));\n}\n\n/**\n * Validate an object that we expect to be a parallel node definition.\n * @param definition An object that we expect to be a parallel node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateParallelNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"parallel\") {\n throw new Error(`expected node type of 'parallel' for parallel node at depth '${depth}'`);\n }\n\n // A parallel node is a composite node, so must have a children nodes array defined.\n if (!Array.isArray(definition.children) || definition.children.length === 0) {\n throw new Error(`expected non-empty 'children' array to be defined for parallel node at depth '${depth}'`);\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n\n // Validate the child nodes of this composite node.\n definition.children.forEach((child: any) => validateNode(child, depth + 1));\n}\n\n/**\n * Validate an object that we expect to be a lotto node definition.\n * @param definition An object that we expect to be a lotto node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateLottoNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"lotto\") {\n throw new Error(`expected node type of 'lotto' for lotto node at depth '${depth}'`);\n }\n\n // A lotto node is a composite node, so must have a children nodes array defined.\n if (!Array.isArray(definition.children) || definition.children.length === 0) {\n throw new Error(`expected non-empty 'children' array to be defined for lotto node at depth '${depth}'`);\n }\n\n // Check whether a 'weights' property has been defined, if it has we expect it to be an array of weights.\n if (typeof definition.weights !== \"undefined\") {\n // Check that the weights property is an array of positive integers with an element for each child node element.\n if (\n !Array.isArray(definition.weights) ||\n definition.weights.length !== definition.children.length ||\n definition.weights.filter((value: unknown) => !isInteger(value)).length ||\n definition.weights.filter((value: number) => value < 0).length\n ) {\n throw new Error(\n `expected an array of positive integer weight values with a length matching the number of child nodes for 'weights' property if defined for lotto node at depth '${depth}'`\n );\n }\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n\n // Validate the child nodes of this composite node.\n definition.children.forEach((child: any) => validateNode(child, depth + 1));\n}\n\n/**\n * A helper function to create a failure validation result with the given error message.\n * @param errorMessage The validation failure error message.\n * @returns A failure validation result with the given error message.\n */\nfunction createValidationFailureResult(errorMessage: string): DefinitionValidationResult {\n return { succeeded: false, errorMessage };\n}\n", "import { ActionResult, Agent, GlobalFunction } from \"./Agent\";\nimport { RootNodeDefinition } from \"./BehaviourTreeDefinition\";\n\nexport type InvokerFunction = (args: any[]) => ActionResult | boolean;\n\n/**\n * A singleton used to store and lookup registered functions and subtrees.\n */\nexport default class Lookup {\n /**\n * The object holding any registered functions keyed on function name.\n */\n private static registeredFunctions: { [key: string]: GlobalFunction } = {};\n /**\n * The object holding any registered subtree root node definitions keyed on tree name.\n */\n private static registeredSubtrees: { [key: string]: RootNodeDefinition } = {};\n\n /**\n * Gets the function with the specified name.\n * @param name The name of the function.\n * @returns The function with the specified name.\n */\n public static getFunc(name: string): GlobalFunction {\n return this.registeredFunctions[name];\n }\n\n /**\n * Sets the function with the specified name for later lookup.\n * @param name The name of the function.\n * @param func The function.\n */\n public static setFunc(name: string, func: GlobalFunction): void {\n this.registeredFunctions[name] = func;\n }\n\n /**\n * Gets the function invoker for the specified agent and function name.\n * If a function with the specified name exists on the agent object then it will\n * be returned, otherwise we will then check the registered functions for a match.\n * @param agent The agent instance that this behaviour tree is modelling behaviour for.\n * @param name The function name.\n * @returns The function invoker for the specified agent and function name.\n */\n static getFuncInvoker(agent: Agent, name: string): InvokerFunction | null {\n // Check whether the agent contains the specified function.\n const agentFunction = agent[name];\n if (agentFunction && typeof agentFunction === \"function\") {\n return (args: any[]) => agentFunction.apply(agent, args);\n }\n\n // The agent does not contain the specified function but it may have been registered at some point.\n if (this.registeredFunctions[name] && typeof this.registeredFunctions[name] === \"function\") {\n const registeredFunction = this.registeredFunctions[name];\n return (args: any[]) => registeredFunction(agent, ...args);\n }\n\n // We have no function to invoke.\n return null;\n }\n\n /**\n * Gets all registered subtree root node definitions.\n */\n static getSubtrees(): { [key: string]: RootNodeDefinition } {\n return this.registeredSubtrees;\n }\n\n /**\n * Sets the subtree with the specified name for later lookup.\n * @param name The name of the subtree.\n * @param subtree The subtree.\n */\n static setSubtree(name: string, subtree: RootNodeDefinition) {\n this.registeredSubtrees[name] = subtree;\n }\n\n /**\n * Removes the registered function or subtree with the specified name.\n * @param name The name of the registered function or subtree.\n */\n static remove(name: string) {\n delete this.registeredFunctions[name];\n delete this.registeredSubtrees[name];\n }\n\n /**\n * Remove all registered functions and subtrees.\n */\n static empty() {\n this.registeredFunctions = {};\n this.registeredSubtrees = {};\n }\n}\n", "import Node from \"../../nodes/Node\";\n\n/**\n * An exception thrown when evaluating node guard path conditions and a conditions fails.\n */\nexport default class GuardUnsatisifedException extends Error {\n /**\n * @param source The node at which a guard condition failed.\n */\n constructor(private source: Node) {\n super(\"A guard path condition has failed\");\n }\n\n /**\n * Gets whether the specified node is the node at which a guard condition failed.\n * @param node The node to check against the source node.\n * @returns Whether the specified node is the node at which a guard condition failed.\n */\n isSourceNode = (node: Node) => node === this.source;\n}\n", "import { Agent } from \"../../Agent\";\nimport Guard from \"./Guard\";\nimport Node from \"../../nodes/Node\";\nimport GuardUnsatisifedException from \"./GuardUnsatisifedException\";\n\nexport type GuardPathPart = {\n node: Node;\n guards: Guard[];\n};\n\n/**\n * Represents a path of node guards along a root-to-leaf tree path.\n */\nexport default class GuardPath {\n /**\n * @param nodes An array of objects defining a node instance -> guard link, ordered by node depth.\n */\n constructor(private nodes: GuardPathPart[]) {}\n\n /**\n * Evaluate guard conditions for all guards in the tree path, moving outwards from the root.\n * @param agent The agent, required for guard evaluation.\n * @returns An evaluation results object.\n */\n evaluate = (agent: Agent) => {\n // We need to evaluate guard conditions for nodes up the tree, moving outwards from the root.\n for (const details of this.nodes) {\n // There can be multiple guards per node.\n for (const guard of details.guards) {\n // Check whether the guard condition passes, and throw an exception if not.\n if (!guard.isSatisfied(agent)) {\n throw new GuardUnsatisifedException(details.node);\n }\n }\n }\n };\n}\n", "import { BehaviourTreeOptions } from \"../BehaviourTreeOptions\";\nimport State, { AnyState } from \"../State\";\nimport { Agent } from \"../Agent\";\nimport Leaf from \"./leaf/Leaf\";\nimport Attribute from \"../attributes/Attribute\";\nimport Entry from \"../attributes/callbacks/Entry\";\nimport Exit from \"../attributes/callbacks/Exit\";\nimport Step from \"../attributes/callbacks/Step\";\nimport Guard from \"../attributes/guards/Guard\";\nimport GuardPath from \"../attributes/guards/GuardPath\";\nimport GuardUnsatisifedException from \"../attributes/guards/GuardUnsatisifedException\";\n\n/**\n * A base node.\n */\nexport default abstract class Node {\n /**\n * The node uid.\n */\n private readonly uid: string = createNodeUid();\n /**\n * The node state.\n */\n private state: AnyState = State.READY;\n /**\n * The guard path to evaluate as part of a node update.\n */\n private guardPath: GuardPath | undefined;\n\n /**\n * @param type The node type.\n * @param attributes The node attributes.\n * @param args The node argument definitions.\n */\n constructor(private type: string, private attributes: Attribute[], private args: any[]) {}\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected abstract onUpdate(agent: Agent, options: BehaviourTreeOptions): void;\n\n /**\n * Gets the name of the node.\n */\n public abstract getName(): string;\n\n /**\n * Gets whether this node is a leaf node.\n */\n public abstract isLeafNode: () => this is Leaf;\n\n /**\n * Gets/Sets the state of the node.\n */\n getState = (): AnyState => this.state;\n setState = (value: AnyState): void => {\n this.state = value;\n };\n\n /**\n * Gets the unique id of the node.\n */\n getUid = () => this.uid;\n\n /**\n * Gets the type of the node.\n */\n getType = () => this.type;\n\n /**\n * Gets the node attributes.\n */\n getAttributes = () => this.attributes;\n\n /**\n * Gets the node arguments.\n */\n getArguments = () => this.args;\n\n /**\n * Gets the node attribute with the specified type, or null if it does not exist.\n */\n getAttribute(type: \"entry\" | \"ENTRY\"): Entry;\n getAttribute(type: \"exit\" | \"EXIT\"): Exit;\n getAttribute(type: \"step\" | \"STEP\"): Step;\n getAttribute(type: string): Attribute {\n return (\n this.getAttributes().filter((decorator) => decorator.type.toUpperCase() === type.toUpperCase())[0] || null\n );\n }\n\n /**\n * Gets the node attributes.\n */\n getGuardAttributes = (): Guard[] => this.getAttributes().filter((decorator) => decorator.isGuard()) as Guard[];\n\n /**\n * Sets the guard path to evaluate as part of a node update.\n */\n setGuardPath = (value: GuardPath) => (this.guardPath = value);\n\n /**\n * Gets whether a guard path is assigned to this node.\n */\n hasGuardPath = () => !!this.guardPath;\n\n /**\n * Gets whether this node is in the specified state.\n * @param value The value to compare to the node state.\n */\n public is(value: AnyState): boolean {\n return this.state === value;\n }\n\n /**\n * Reset the state of the node.\n */\n public reset(): void {\n this.setState(State.READY);\n }\n\n /**\n * Abort the running of this node.\n * @param agent The agent.\n */\n public abort(agent: Agent): void {\n // There is nothing to do if this node is not in the running state.\n if (!this.is(State.RUNNING)) {\n return;\n }\n\n // Reset the state of this node.\n this.reset();\n\n this.getAttribute(\"exit\")?.callAgentFunction(agent, false, true);\n }\n\n /**\n * Update the node.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n * @returns The result of the update.\n */\n public update(agent: Agent, options: BehaviourTreeOptions): void {\n // If this node is already in a 'SUCCEEDED' or 'FAILED' state then there is nothing to do.\n if (this.is(State.SUCCEEDED) || this.is(State.FAILED)) {\n return;\n }\n\n try {\n // Evaluate all of the guard path conditions for the current tree path.\n this.guardPath!.evaluate(agent);\n\n // If this node is in the READY state then call the ENTRY for this node if it exists.\n if (this.is(State.READY)) {\n this.getAttribute(\"entry\")?.callAgentFunction(agent);\n }\n\n this.getAttribute(\"step\")?.callAgentFunction(agent);\n\n // Do the actual update.\n this.onUpdate(agent, options);\n\n // If this node is now in a 'SUCCEEDED' or 'FAILED' state then call the EXIT for this node if it exists.\n if (this.is(State.SUCCEEDED) || this.is(State.FAILED)) {\n this.getAttribute(\"exit\")?.callAgentFunction(agent, this.is(State.SUCCEEDED), false);\n }\n } catch (error) {\n // If the error is a GuardUnsatisfiedException then we need to determine if this node is the source.\n if (error instanceof GuardUnsatisifedException && error.isSourceNode(this)) {\n // Abort the current node.\n this.abort(agent);\n\n // Any node that is the source of an abort will be a failed node.\n this.setState(State.FAILED);\n } else {\n throw error;\n }\n }\n }\n}\n\n/**\n * Create a randomly generated node uid.\n * @returns A randomly generated node uid.\n */\nfunction createNodeUid(): string {\n var S4 = function () {\n return (((1 + Math.random()) * 0x10000) | 0).toString(16).substring(1);\n };\n return S4() + S4() + \"-\" + S4() + \"-\" + S4() + \"-\" + S4() + \"-\" + S4() + S4() + S4();\n}\n", "import Node from \"../Node\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\n\n/**\n * A composite node that wraps child nodes.\n */\nexport default abstract class Composite extends Node {\n /**\n * @param type The node type.\n * @param attributes The node attributes.\n * @param children The child nodes.\n */\n constructor(type: string, attributes: Attribute[], protected children: Node[]) {\n super(type, attributes, []);\n }\n\n /**\n * Gets whether this node is a leaf node.\n */\n isLeafNode = () => false;\n\n /**\n * Gets the children of this node.\n */\n getChildren = () => this.children;\n\n /**\n * Reset the state of the node.\n */\n reset = () => {\n // Reset the state of this node.\n this.setState(State.READY);\n\n // Reset the state of any child nodes.\n this.getChildren().forEach((child) => child.reset());\n };\n\n /**\n * Abort the running of this node.\n * @param agent The agent.\n */\n abort = (agent: Agent) => {\n // There is nothing to do if this node is not in the running state.\n if (!this.is(State.RUNNING)) {\n return;\n }\n\n // Abort any child nodes.\n this.getChildren().forEach((child) => child.abort(agent));\n\n // Reset the state of this node.\n this.reset();\n\n this.getAttribute(\"exit\")?.callAgentFunction(agent, false, true);\n };\n}\n", "import Composite from \"./Composite\";\nimport State from \"../../State\";\nimport Node from \"../Node\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A PARALLEL node.\n * The child nodes are executed concurrently until one fails or all succeed.\n */\nexport default class Parallel extends Composite {\n /**\n * @param attributes The node attributes.\n * @param children The child nodes.\n */\n constructor(attributes: Attribute[], children: Node[]) {\n super(\"parallel\", attributes, children);\n }\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // Keep a count of the number of succeeded child nodes.\n let succeededCount = 0;\n\n let hasChildFailed = false;\n\n // Iterate over all of the children of this node.\n for (const child of this.children) {\n // If the child has never been updated or is running then we will need to update it now.\n if (child.getState() === State.READY || child.getState() === State.RUNNING) {\n // Update the child of this node.\n child.update(agent, options);\n }\n\n // If the current child has a state of 'SUCCEEDED' then we should move on to the next child.\n if (child.getState() === State.SUCCEEDED) {\n // The child node has succeeded, keep track of this to determine if all children have.\n succeededCount++;\n\n // The child node succeeded, but we have not finished checking every child node yet.\n continue;\n }\n\n // If the current child has a state of 'FAILED' then this node is also a 'FAILED' node.\n if (child.getState() === State.FAILED) {\n hasChildFailed = true;\n\n // There is no need to check the rest of the children.\n break;\n }\n\n // The node should be in the 'RUNNING' state.\n if (child.getState() !== State.RUNNING) {\n // The child node was not in an expected state.\n throw new Error(\"child node was not in an expected state.\");\n }\n }\n\n if (hasChildFailed) {\n // This node is a 'FAILED' node.\n this.setState(State.FAILED);\n\n // Abort every running child.\n for (const child of this.children) {\n if (child.getState() === State.RUNNING) {\n child.abort(agent);\n }\n }\n } else {\n // If all children have succeeded then this node has also succeeded, otherwise it is still running.\n this.setState(succeededCount === this.children.length ? State.SUCCEEDED : State.RUNNING);\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => \"PARALLEL\";\n}\n", "import Composite from \"./Composite\";\nimport Node from \"../Node\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A SELECTOR node.\n * The child nodes are executed in sequence until one succeeds or all fail.\n */\nexport default class Selector extends Composite {\n /**\n * @param attributes The node attributes.\n * @param children The child nodes.\n */\n constructor(attributes: Attribute[], protected children: Node[]) {\n super(\"selector\", attributes, children);\n }\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // Iterate over all of the children of this node.\n for (const child of this.children) {\n // If the child has never been updated or is running then we will need to update it now.\n if (child.getState() === State.READY || child.getState() === State.RUNNING) {\n // Update the child of this node.\n child.update(agent, options);\n }\n\n // If the current child has a state of 'SUCCEEDED' then this node is also a 'SUCCEEDED' node.\n if (child.getState() === State.SUCCEEDED) {\n // This node is a 'SUCCEEDED' node.\n this.setState(State.SUCCEEDED);\n\n // There is no need to check the rest of the selector nodes.\n return;\n }\n\n // If the current child has a state of 'FAILED' then we should move on to the next child.\n if (child.getState() === State.FAILED) {\n // Find out if the current child is the last one in the selector.\n // If it is then this sequence node has also failed.\n if (this.children.indexOf(child) === this.children.length - 1) {\n // This node is a 'FAILED' node.\n this.setState(State.FAILED);\n\n // There is no need to check the rest of the selector as we have completed it.\n return;\n } else {\n // The child node failed, try the next one.\n continue;\n }\n }\n\n // The node should be in the 'RUNNING' state.\n if (child.getState() === State.RUNNING) {\n // This node is a 'RUNNING' node.\n this.setState(State.RUNNING);\n\n // There is no need to check the rest of the selector as the current child is still running.\n return;\n }\n\n // The child node was not in an expected state.\n throw new Error(\"child node was not in an expected state.\");\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => \"SELECTOR\";\n}\n", "import Composite from \"./Composite\";\nimport Node from \"../Node\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A SEQUENCE node.\n * The child nodes are executed in sequence until one fails or all succeed.\n */\nexport default class Sequence extends Composite {\n /**\n * @param attributes The node attributes.\n * @param children The child nodes.\n */\n constructor(attributes: Attribute[], protected children: Node[]) {\n super(\"sequence\", attributes, children);\n }\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // Iterate over all of the children of this node.\n for (const child of this.children) {\n // If the child has never been updated or is running then we will need to update it now.\n if (child.getState() === State.READY || child.getState() === State.RUNNING) {\n // Update the child of this node.\n child.update(agent, options);\n }\n\n // If the current child has a state of 'SUCCEEDED' then we should move on to the next child.\n if (child.getState() === State.SUCCEEDED) {\n // Find out if the current child is the last one in the sequence.\n // If it is then this sequence node has also succeeded.\n if (this.children.indexOf(child) === this.children.length - 1) {\n // This node is a 'SUCCEEDED' node.\n this.setState(State.SUCCEEDED);\n\n // There is no need to check the rest of the sequence as we have completed it.\n return;\n } else {\n // The child node succeeded, but we have not finished the sequence yet.\n continue;\n }\n }\n\n // If the current child has a state of 'FAILED' then this node is also a 'FAILED' node.\n if (child.getState() === State.FAILED) {\n // This node is a 'FAILED' node.\n this.setState(State.FAILED);\n\n // There is no need to check the rest of the sequence.\n return;\n }\n\n // The node should be in the 'RUNNING' state.\n if (child.getState() === State.RUNNING) {\n // This node is a 'RUNNING' node.\n this.setState(State.RUNNING);\n\n // There is no need to check the rest of the sequence as the current child is still running.\n return;\n }\n\n // The child node was not in an expected state.\n throw new Error(\"child node was not in an expected state.\");\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => \"SEQUENCE\";\n}\n", "import createLotto from \"lotto-draw\";\n\nimport Node from \"../Node\";\nimport Composite from \"./Composite\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A LOTTO node.\n * A winning child is picked on the initial update of this node, based on ticket weighting.\n * The state of this node will match the state of the winning child.\n */\nexport default class Lotto extends Composite {\n /**\n * @param attributes The node attributes.\n * @param weights The child node weights.\n * @param children The child nodes.\n */\n constructor(attributes: Attribute[], private weights: number[] | undefined, children: Node[]) {\n super(\"lotto\", attributes, children);\n }\n\n /**\n * The child node selected to be the active one.\n */\n private selectedChild: Node | undefined;\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // If this node is in the READY state then we need to pick a winning child node.\n if (this.is(State.READY)) {\n // Create a lotto draw with which to randomly pick a child node to become the active one.\n const lottoDraw = createLotto({\n // Hook up the optional 'random' behaviour tree function option to the one used by 'lotto-draw'.\n random: options.random,\n // Pass in each child node as a participant in the lotto draw with their respective ticket count.\n participants: this.children.map((child, index) => [child, this.weights?.[index] || 1])\n });\n\n // Randomly pick a child based on ticket weighting, this will become the active child for this composite node.\n this.selectedChild = lottoDraw.draw() || undefined;\n }\n\n // If something went wrong and we don't have an active child then we should throw an error.\n if (!this.selectedChild) {\n throw new Error(\"failed to update lotto node as it has no active child\");\n }\n\n // If the selected child has never been updated or is running then we will need to update it now.\n if (this.selectedChild.getState() === State.READY || this.selectedChild.getState() === State.RUNNING) {\n this.selectedChild.update(agent, options);\n }\n\n // The state of the lotto node is the state of its selected child.\n this.setState(this.selectedChild.getState());\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => (this.weights ? `LOTTO [${this.weights.join(\",\")}]` : \"LOTTO\");\n}\n", "import Node from \"../Node\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\n\n/**\n * A decorator node that wraps a single child node.\n */\nexport default abstract class Decorator extends Node {\n /**\n * @param type The node type.\n * @param attributes The node attributes.\n * @param child The child node.\n */\n constructor(type: string, attributes: Attribute[], protected child: Node) {\n super(type, attributes, []);\n }\n\n /**\n * Gets whether this node is a leaf node.\n */\n isLeafNode = () => false;\n\n /**\n * Gets the children of this node.\n */\n getChildren = () => [this.child];\n\n /**\n * Reset the state of the node.\n */\n reset = () => {\n // Reset the state of this node.\n this.setState(State.READY);\n\n // Reset the state of the child node.\n this.child.reset();\n };\n\n /**\n * Abort the running of this node.\n * @param agent The agent.\n */\n abort = (agent: Agent) => {\n // There is nothing to do if this node is not in the running state.\n if (!this.is(State.RUNNING)) {\n return;\n }\n\n // Abort the child node.\n this.child.abort(agent);\n\n // Reset the state of this node.\n this.reset();\n\n this.getAttribute(\"exit\")?.callAgentFunction(agent, false, true);\n };\n}\n", "import Node from \"../Node\";\nimport Decorator from \"./Decorator\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A Fail node.\n * This node wraps a single child and will always move to the 'FAILED' state when the child moves to a 'SUCCEEDED' or 'FAILED' state.\n */\nexport default class Fail extends Decorator {\n /**\n * @param attributes The node attributes.\n * @param child The child node.\n */\n constructor(attributes: Attribute[], child: Node) {\n super(\"fail\", attributes, child);\n }\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // If the child has never been updated or is running then we will need to update it now.\n if (this.child.getState() === State.READY || this.child.getState() === State.RUNNING) {\n this.child.update(agent, options);\n }\n\n // The state of this node will depend in the state of its child.\n switch (this.child.getState()) {\n case State.RUNNING:\n this.setState(State.RUNNING);\n break;\n\n case State.SUCCEEDED:\n case State.FAILED:\n this.setState(State.FAILED);\n break;\n\n default:\n this.setState(State.READY);\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => \"FAIL\";\n}\n", "import Decorator from \"./Decorator\";\nimport State from \"../../State\";\nimport Node from \"../Node\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A Flip node.\n * This node wraps a single child and will flip the state of the child state.\n */\nexport default class Flip extends Decorator {\n /**\n * @param attributes The node attributes.\n * @param child The child node.\n */\n constructor(attributes: Attribute[], child: Node) {\n super(\"flip\", attributes, child);\n }\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // If the child has never been updated or is running then we will need to update it now.\n if (this.child.getState() === State.READY || this.child.getState() === State.RUNNING) {\n this.child.update(agent, options);\n }\n\n // The state of this node will depend in the state of its child.\n switch (this.child.getState()) {\n case State.RUNNING:\n this.setState(State.RUNNING);\n break;\n\n case State.SUCCEEDED:\n this.setState(State.FAILED);\n break;\n\n case State.FAILED:\n this.setState(State.SUCCEEDED);\n break;\n\n default:\n this.setState(State.READY);\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => \"FLIP\";\n}\n", "import Node from \"../Node\";\nimport Decorator from \"./Decorator\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A REPEAT node.\n * The node has a single child which can have:\n * -- A number of iterations for which to repeat the child node.\n * -- An infinite repeat loop if neither an iteration count or a condition function is defined.\n * The REPEAT node will stop and have a 'FAILED' state if its child is ever in a 'FAILED' state after an update.\n * The REPEAT node will attempt to move on to the next iteration if its child is ever in a 'SUCCEEDED' state.\n */\nexport default class Repeat extends Decorator {\n /**\n * @param attributes The node attributes.\n * @param iterations The number of iterations to repeat the child node.\n * @param iterationsMin The minimum possible number of iterations to repeat the child node.\n * @param iterationsMax The maximum possible number of iterations to repeat the child node.\n * @param child The child node.\n */\n constructor(\n attributes: Attribute[],\n private iterations: number | null,\n private iterationsMin: number | null,\n private iterationsMax: number | null,\n child: Node\n ) {\n super(\"repeat\", attributes, child);\n }\n\n /**\n * The number of target iterations to make.\n */\n private targetIterationCount: number | null = null;\n\n /**\n * The current iteration count.\n */\n private currentIterationCount: number = 0;\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // If this node is in the READY state then we need to reset the child and the target iteration count.\n if (this.is(State.READY)) {\n // Reset the child node.\n this.child.reset();\n\n // Reset the current iteration count.\n this.currentIterationCount = 0;\n\n // Set the target iteration count.\n this.setTargetIterationCount(options);\n }\n\n // Do a check to see if we can iterate. If we can then this node will move into the 'RUNNING' state.\n // If we cannot iterate then we have hit our target iteration count, which means that the node has succeeded.\n if (this.canIterate()) {\n // This node is in the running state and can do its initial iteration.\n this.setState(State.RUNNING);\n\n // We may have already completed an iteration, meaning that the child node will be in the SUCCEEDED state.\n // If this is the case then we will have to reset the child node now.\n if (this.child.getState() === State.SUCCEEDED) {\n this.child.reset();\n }\n\n // Update the child of this node.\n this.child.update(agent, options);\n\n // If the child moved into the FAILED state when we updated it then there is nothing left to do and this node has also failed.\n // If it has moved into the SUCCEEDED state then we have completed the current iteration.\n if (this.child.getState() === State.FAILED) {\n // The child has failed, meaning that this node has failed.\n this.setState(State.FAILED);\n\n return;\n } else if (this.child.getState() === State.SUCCEEDED) {\n // We have completed an iteration.\n this.currentIterationCount += 1;\n }\n } else {\n // This node is in the 'SUCCEEDED' state as we cannot iterate any more.\n this.setState(State.SUCCEEDED);\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => {\n if (this.iterations !== null) {\n return `REPEAT ${this.iterations}x`;\n } else if (this.iterationsMin !== null && this.iterationsMax !== null) {\n return `REPEAT ${this.iterationsMin}x-${this.iterationsMax}x`;\n } else {\n return \"REPEAT\";\n }\n };\n\n /**\n * Reset the state of the node.\n */\n reset = () => {\n // Reset the state of this node.\n this.setState(State.READY);\n\n // Reset the current iteration count.\n this.currentIterationCount = 0;\n\n // Reset the child node.\n this.child.reset();\n };\n\n /**\n * Gets whether an iteration can be made.\n * @returns Whether an iteration can be made.\n */\n private canIterate = () => {\n if (this.targetIterationCount !== null) {\n // We can iterate as long as we have not reached our target iteration count.\n return this.currentIterationCount < this.targetIterationCount;\n }\n\n // If neither an iteration count or a condition function were defined then we can iterate indefinitely.\n return true;\n };\n\n /**\n * Sets the target iteration count.\n * @param options The behaviour tree options object.\n */\n private setTargetIterationCount = (options: BehaviourTreeOptions) => {\n // Are we dealing with an explicit iteration count or will we be randomly picking a iteration count between the min and max iteration count.\n if (this.iterations !== null) {\n this.targetIterationCount = this.iterations;\n } else if (this.iterationsMin !== null && this.iterationsMax !== null) {\n // We will be picking a random iteration count between a min and max iteration count, if the optional 'random'\n // behaviour tree function option is defined then we will be using that, otherwise we will fall back to using Math.random.\n const random = typeof options.random === \"function\" ? options.random : Math.random;\n\n // Pick a random iteration count between a min and max iteration count.\n this.targetIterationCount = Math.floor(\n random() * (this.iterationsMax - this.iterationsMin + 1) + this.iterationsMin\n );\n } else {\n this.targetIterationCount = null;\n }\n };\n}\n", "import Node from \"../Node\";\nimport Decorator from \"./Decorator\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A RETRY node.\n * The node has a single child which can have:\n * -- A number of iterations for which to repeat the child node.\n * -- An infinite repeat loop if neither an iteration count or a condition function is defined.\n * The RETRY node will stop and have a 'SUCCEEDED' state if its child is ever in a 'SUCCEEDED' state after an update.\n * The RETRY node will attempt to move on to the next iteration if its child is ever in a 'FAILED' state.\n */\nexport default class Retry extends Decorator {\n /**\n * @param attributes The node attributes.\n * @param attempts The number of attempts to retry the child node.\n * @param attemptsMin The minimum possible number of attempts to retry the child node.\n * @param attemptsMax The maximum possible number of attempts to retry the child node.\n * @param child The child node.\n */\n constructor(\n attributes: Attribute[],\n private attempts: number | null,\n private attemptsMin: number | null,\n private attemptsMax: number | null,\n child: Node\n ) {\n super(\"retry\", attributes, child);\n }\n\n /**\n * The number of target attempts to make.\n */\n private targetAttemptCount: number | null = null;\n\n /**\n * The current attempt count.\n */\n private currentAttemptCount: number = 0;\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // If this node is in the READY state then we need to reset the child and the target attempt count.\n if (this.is(State.READY)) {\n // Reset the child node.\n this.child.reset();\n\n // Reset the current attempt count.\n this.currentAttemptCount = 0;\n\n // Set the target attempt count.\n this.setTargetAttemptCount(options);\n }\n\n // Do a check to see if we can attempt. If we can then this node will move into the 'RUNNING' state.\n // If we cannot attempt then we have hit our target attempt count, which means that the node has succeeded.\n if (this.canAttempt()) {\n // This node is in the running state and can do its initial attempt.\n this.setState(State.RUNNING);\n\n // We may have already completed an attempt, meaning that the child node will be in the FAILED state.\n // If this is the case then we will have to reset the child node now.\n if (this.child.getState() === State.FAILED) {\n this.child.reset();\n }\n\n // Update the child of this node.\n this.child.update(agent, options);\n\n // If the child moved into the SUCCEEDED state when we updated it then there is nothing left to do and this node has also succeeded.\n // If it has moved into the FAILED state then we have completed the current attempt.\n if (this.child.getState() === State.SUCCEEDED) {\n // The child has succeeded, meaning that this node has succeeded.\n this.setState(State.SUCCEEDED);\n\n return;\n } else if (this.child.getState() === State.FAILED) {\n // We have completed an attempt.\n this.currentAttemptCount += 1;\n }\n } else {\n // This node is in the 'FAILED' state as we cannot iterate any more.\n this.setState(State.FAILED);\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => {\n if (this.attempts !== null) {\n return `RETRY ${this.attempts}x`;\n } else if (this.attemptsMin !== null && this.attemptsMax !== null) {\n return `RETRY ${this.attemptsMin}x-${this.attemptsMax}x`;\n } else {\n return \"RETRY\";\n }\n };\n\n /**\n * Reset the state of the node.\n */\n reset = () => {\n // Reset the state of this node.\n this.setState(State.READY);\n\n // Reset the current attempt count.\n this.currentAttemptCount = 0;\n\n // Reset the child node.\n this.child.reset();\n };\n\n /**\n * Gets whether an attempt can be made.\n * @returns Whether an attempt can be made.\n */\n canAttempt = () => {\n if (this.targetAttemptCount !== null) {\n // We can attempt as long as we have not reached our target attempt count.\n return this.currentAttemptCount < this.targetAttemptCount;\n }\n\n // If neither an attempt count or a condition function were defined then we can attempt indefinitely.\n return true;\n };\n\n /**\n * Sets the target attempt count.\n * @param options The behaviour tree options object.\n */\n setTargetAttemptCount = (options: BehaviourTreeOptions) => {\n // Are we dealing with an explicit attempt count or will we be randomly picking an attempt count between the min and max attempt count.\n if (this.attempts !== null) {\n this.targetAttemptCount = this.attempts;\n } else if (this.attemptsMin !== null && this.attemptsMax !== null) {\n // We will be picking a random attempt count between a min and max attempt count, if the optional 'random'\n // behaviour tree function option is defined then we will be using that, otherwise we will fall back to using Math.random.\n const random = typeof options.random === \"function\" ? options.random : Math.random;\n\n // Pick a random attempt count between a min and max attempt count.\n this.targetAttemptCount = Math.floor(\n random() * (this.attemptsMax - this.attemptsMin + 1) + this.attemptsMin\n );\n } else {\n this.targetAttemptCount = null;\n }\n };\n}\n", "import Node from \"../Node\";\nimport Decorator from \"./Decorator\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A Root node.\n * The root node will have a single child.\n */\nexport default class Root extends Decorator {\n /**\n * @param attributes The node attributes.\n * @param child The child node.\n */\n constructor(attributes: Attribute[], child: Node) {\n super(\"root\", attributes, child);\n }\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // If the child has never been updated or is running then we will need to update it now.\n if (this.child.getState() === State.READY || this.child.getState() === State.RUNNING) {\n // Update the child of this node.\n this.child.update(agent, options);\n }\n\n // The state of the root node is the state of its child.\n this.setState(this.child.getState());\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => \"ROOT\";\n}\n", "import Node from \"../Node\";\nimport Decorator from \"./Decorator\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A Succeed node.\n * This node wraps a single child and will always move to the 'SUCCEEDED' state when the child moves to a 'SUCCEEDED' or 'FAILED' state.\n */\nexport default class Succeed extends Decorator {\n /**\n * @param attributes The node attributes.\n * @param child The child node.\n */\n constructor(attributes: Attribute[], child: Node) {\n super(\"succeed\", attributes, child);\n }\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // If the child has never been updated or is running then we will need to update it now.\n if (this.child.getState() === State.READY || this.child.getState() === State.RUNNING) {\n this.child.update(agent, options);\n }\n\n // The state of this node will depend in the state of its child.\n switch (this.child.getState()) {\n case State.RUNNING:\n this.setState(State.RUNNING);\n break;\n\n case State.SUCCEEDED:\n case State.FAILED:\n this.setState(State.SUCCEEDED);\n break;\n\n default:\n this.setState(State.READY);\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => \"SUCCEED\";\n}\n", "import Node from \"../Node\";\n\n/**\n * A leaf node.\n */\nexport default abstract class Leaf extends Node {\n /**\n * Gets whether this node is a leaf node.\n */\n isLeafNode = () => true;\n}\n", "import { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\nimport State, { CompleteState } from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Leaf from \"./Leaf\";\nimport Lookup from \"../../Lookup\";\nimport Attribute from \"../../attributes/Attribute\";\n\n/**\n * The type representing a resolved/rejected update promise.\n */\ntype UpdatePromiseResult = {\n /**\n * Whether the promise was resolved rather than rejected.\n */\n isResolved: boolean;\n\n /**\n * The promise resolved value or rejection reason.\n */\n value: any;\n};\n\n/**\n * An Action leaf node.\n * This represents an immediate or ongoing state of behaviour.\n */\nexport default class Action extends Leaf {\n /**\n * @param attributes The node attributes.\n * @param actionName The action name.\n * @param actionArguments The array of action argument definitions.\n */\n constructor(attributes: Attribute[], private actionName: string, private actionArguments: any[]) {\n super(\"action\", attributes, actionArguments);\n }\n\n /**\n * Whether there is a pending update promise.\n */\n private isUsingUpdatePromise = false;\n\n /**\n * The finished state result of an update promise.\n */\n private updatePromiseResult: UpdatePromiseResult | null = null;\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // If the result of this action depends on an update promise then there is nothing to do until it settles.\n if (this.isUsingUpdatePromise) {\n // Are we still waiting for our update promise to settle?\n if (!this.updatePromiseResult) {\n return;\n }\n\n const { isResolved, value } = this.updatePromiseResult;\n\n // Our update promise settled, was it resolved or rejected?\n if (isResolved) {\n // Our promise resolved so check to make sure the result is a valid finished state.\n if (value !== State.SUCCEEDED && value !== State.FAILED) {\n throw new Error(\n \"action node promise resolved with an invalid value, expected a State.SUCCEEDED or State.FAILED value to be returned\"\n );\n }\n\n // Set the state of this node to match the state returned by the promise.\n this.setState(value);\n\n return;\n } else {\n // The promise was rejected, which isn't great.\n throw new Error(`action function '${this.actionName}' promise rejected with '${value}'`);\n }\n }\n\n // Attempt to get the invoker for the action function.\n const actionFuncInvoker = Lookup.getFuncInvoker(agent, this.actionName);\n\n // The action function should be defined.\n if (actionFuncInvoker === null) {\n throw new Error(\n `cannot update action node as the action '${this.actionName}' function is not defined on the agent and has not been registered`\n );\n }\n\n let actionFunctionResult;\n\n try {\n // Call the action function, the result of which may be:\n // - The finished state of this action node.\n // - A promise to return a finished node state.\n // - Undefined if the node should remain in the running state.\n actionFunctionResult = actionFuncInvoker(this.actionArguments) as CompleteState | Promise;\n } catch (error) {\n // An uncaught error was thrown.\n if (error instanceof Error) {\n throw new Error(`action function '${this.actionName}' threw: ${error.stack}`);\n } else {\n throw new Error(`action function '${this.actionName}' threw: ${error}`);\n }\n }\n\n if (actionFunctionResult instanceof Promise) {\n actionFunctionResult.then(\n (result) => {\n // If 'isUpdatePromisePending' is not set then the promise was cleared as it was resolving, probably via an abort of reset.\n if (!this.isUsingUpdatePromise) {\n return;\n }\n\n // Set the resolved update promise result so that it can be handled on the next update of this node.\n this.updatePromiseResult = {\n isResolved: true,\n value: result\n };\n },\n (reason) => {\n // If 'isUpdatePromisePending' is not set then the promise was cleared as it was resolving, probably via an abort or reset.\n if (!this.isUsingUpdatePromise) {\n return;\n }\n\n // Set the rejected update promise result so that it can be handled on the next update of this node.\n this.updatePromiseResult = {\n isResolved: false,\n value: reason\n };\n }\n );\n\n // This node will be in the 'RUNNING' state until the update promise resolves.\n this.setState(State.RUNNING);\n\n // We are now waiting for the promise returned by the use to resolve before we know what state this node is in.\n this.isUsingUpdatePromise = true;\n } else {\n // Validate the returned value.\n this.validateUpdateResult(actionFunctionResult);\n\n // Set the state of this node, this may be undefined, which just means that the node is still in the 'RUNNING' state.\n this.setState(actionFunctionResult || State.RUNNING);\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => this.actionName;\n\n /**\n * Reset the state of the node.\n */\n reset = () => {\n // Reset the state of this node.\n this.setState(State.READY);\n\n // There is no longer an update promise that we care about.\n this.isUsingUpdatePromise = false;\n this.updatePromiseResult = null;\n };\n\n /**\n * Validate the result of an update function call.\n * @param result The result of an update function call.\n */\n private validateUpdateResult = (result: CompleteState | State.RUNNING) => {\n switch (result) {\n case State.SUCCEEDED:\n case State.FAILED:\n case State.RUNNING:\n case undefined:\n return;\n default:\n throw new Error(\n `expected action function '${this.actionName}' to return an optional State.SUCCEEDED or State.FAILED value but returned '${result}'`\n );\n }\n };\n}\n", "import { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Leaf from \"./Leaf\";\nimport Lookup from \"../../Lookup\";\nimport Attribute from \"../../attributes/Attribute\";\n\n/**\n * A Condition leaf node.\n * This will succeed or fail immediately based on an agent predicate, without moving to the 'RUNNING' state.\n */\nexport default class Condition extends Leaf {\n /**\n * @param attributes The node attributes.\n * @param conditionName The name of the condition function.\n * @param conditionArguments The array of condition argument definitions.\n */\n constructor(attributes: Attribute[], private conditionName: string, private conditionArguments: any[]) {\n super(\"condition\", attributes, conditionArguments);\n }\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // Attempt to get the invoker for the condition function.\n const conditionFuncInvoker = Lookup.getFuncInvoker(agent, this.conditionName);\n\n // The condition function should be defined.\n if (conditionFuncInvoker === null) {\n throw new Error(\n `cannot update condition node as the condition '${this.conditionName}' function is not defined on the agent and has not been registered`\n );\n }\n\n let conditionFunctionResult;\n\n try {\n // Call the condition function to determine the state of this node, the result of which should be a boolean.\n conditionFunctionResult = conditionFuncInvoker(this.conditionArguments);\n } catch (error) {\n // An uncaught error was thrown.\n if (error instanceof Error) {\n throw new Error(`condition function '${this.conditionName}' threw: ${error.stack}`);\n } else {\n throw new Error(`condition function '${this.conditionName}' threw: ${error}`);\n }\n }\n\n // The result of calling the condition function must be a boolean value.\n if (typeof conditionFunctionResult !== \"boolean\") {\n throw new Error(\n `expected condition function '${this.conditionName}' to return a boolean but returned '${conditionFunctionResult}'`\n );\n }\n\n // Set the state of this node based on the result of calling the condition function.\n this.setState(!!conditionFunctionResult ? State.SUCCEEDED : State.FAILED);\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => this.conditionName;\n}\n", "import Leaf from \"./Leaf\";\nimport State from \"../../State\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { Agent } from \"../../Agent\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A WAIT node.\n * The state of this node will change to SUCCEEDED after a duration of time\n */\nexport default class Wait extends Leaf {\n /**\n * @param attributes The node attributes.\n * @param duration The duration that this node will wait to succeed in milliseconds.\n * @param durationMin The minimum possible duration in milliseconds that this node will wait to succeed.\n * @param durationMax The maximum possible duration in milliseconds that this node will wait to succeed.\n */\n constructor(\n attributes: Attribute[],\n private duration: number | null,\n private durationMin: number | null,\n private durationMax: number | null\n ) {\n super(\"wait\", attributes, []);\n }\n\n /**\n * The time in milliseconds at which this node was first updated.\n */\n private initialUpdateTime: number = 0;\n\n /**\n * The total duration in milliseconds that this node will be waiting for.\n */\n private totalDuration: number | null = null;\n\n /**\n * The duration in milliseconds that this node has been waiting for.\n */\n private waitedDuration: number = 0;\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // If this node is in the READY state then we need to set the initial update time.\n if (this.is(State.READY)) {\n // Set the initial update time.\n this.initialUpdateTime = new Date().getTime();\n\n // Set the initial waited duration.\n this.waitedDuration = 0;\n\n // Are we dealing with an explicit duration or will we be randomly picking a duration between the min and max duration.\n if (this.duration !== null) {\n this.totalDuration = this.duration;\n } else if (this.durationMin !== null && this.durationMax !== null) {\n // We will be picking a random duration between a min and max duration, if the optional 'random' behaviour tree\n // function option is defined then we will be using that, otherwise we will fall back to using Math.random.\n const random = typeof options.random === \"function\" ? options.random : Math.random;\n\n // Pick a random duration between a min and max duration.\n this.totalDuration = Math.floor(\n random() * (this.durationMax - this.durationMin + 1) + this.durationMin\n );\n } else {\n this.totalDuration = null;\n }\n\n // The node is now running until we finish waiting.\n this.setState(State.RUNNING);\n }\n\n // If we have no total duration then this wait node will wait indefinitely until it is aborted.\n if (this.totalDuration === null) {\n return;\n }\n\n // If we have a 'getDeltaTime' function defined as part of our options then we will use it to figure out how long we have waited for.\n if (typeof options.getDeltaTime === \"function\") {\n // Get the delta time.\n const deltaTime = options.getDeltaTime();\n\n // Our delta time must be a valid number and cannot be NaN.\n if (typeof deltaTime !== \"number\" || isNaN(deltaTime)) {\n throw new Error(\"The delta time must be a valid number and not NaN.\");\n }\n\n // Update the amount of time that this node has been waiting for based on the delta time.\n this.waitedDuration += deltaTime * 1000;\n } else {\n // We are not using a delta time, so we will just work out hom much time has passed since the first update.\n this.waitedDuration = new Date().getTime() - this.initialUpdateTime;\n }\n\n // Have we waited long enough?\n if (this.waitedDuration >= this.totalDuration) {\n // We have finished waiting!\n this.setState(State.SUCCEEDED);\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => {\n if (this.duration !== null) {\n return `WAIT ${this.duration}ms`;\n } else if (this.durationMin !== null && this.durationMax !== null) {\n return `WAIT ${this.durationMin}ms-${this.durationMax}ms`;\n } else {\n return \"WAIT\";\n }\n };\n}\n", "import Guard from \"./guards/Guard\";\n\nexport type AttributeDetails = {\n /** The attribute type. */\n type: string;\n\n /** The attribute arguments. */\n args: any[];\n};\n\n/**\n * A base node attribute.\n */\nexport default abstract class Attribute {\n /**\n * @param type The node attribute type.\n * @param args The array of attribute arguments.\n */\n constructor(public type: string, public args: any[]) {}\n\n /**\n * Gets the attribute details.\n */\n abstract getDetails(): TAttributeDetails;\n\n /**\n * Gets whether this attribute is a guard.\n */\n abstract isGuard: () => this is Guard;\n}\n", "import { Agent } from \"../../Agent\";\nimport Attribute, { AttributeDetails } from \"../Attribute\";\n\nexport type GuardAttributeDetails = {\n /** The name of the condition function that determines whether the guard is satisfied. */\n condition: string;\n} & AttributeDetails;\n\n/**\n * A base node guard attribute.\n */\nexport default abstract class Guard extends Attribute {\n /**\n * @param type The node attribute type.\n * @param args The array of decorator argument definitions.\n * @param condition The name of the condition function that determines whether the guard is satisfied.\n */\n constructor(type: string, args: any[], private condition: string) {\n super(type, args);\n }\n\n /**\n * Gets the name of the condition function that determines whether the guard is satisfied.\n */\n getCondition = () => this.condition;\n\n /**\n * Gets whether this attribute is a guard.\n */\n isGuard = () => true;\n\n /**\n * Gets the attribute details.\n */\n getDetails(): GuardAttributeDetails {\n return {\n type: this.type,\n args: this.args,\n condition: this.getCondition()\n };\n }\n\n /**\n * Gets whether the guard is satisfied.\n * @param agent The agent.\n * @returns Whether the guard is satisfied.\n */\n abstract isSatisfied(agent: Agent): boolean;\n}\n", "import Guard from \"./Guard\";\nimport Lookup from \"../../Lookup\";\nimport { Agent } from \"../../Agent\";\n\n/**\n * A WHILE guard which is satisfied as long as the given condition remains true.\n */\nexport default class While extends Guard {\n /**\n * @param condition The name of the condition function that determines whether the guard is satisfied.\n * @param args The array of decorator argument definitions.\n */\n constructor(condition: string, args: any[]) {\n super(\"while\", args, condition);\n }\n\n /**\n * Gets whether the guard is satisfied.\n * @param agent The agent.\n * @returns Whether the guard is satisfied.\n */\n isSatisfied = (agent: Agent) => {\n // Attempt to get the invoker for the condition function.\n const conditionFuncInvoker = Lookup.getFuncInvoker(agent, this.getCondition());\n\n // The condition function should be defined.\n if (conditionFuncInvoker === null) {\n throw new Error(\n `cannot evaluate node guard as the condition '${this.getCondition()}' function is not defined on the agent and has not been registered`\n );\n }\n\n let conditionFunctionResult;\n\n try {\n // Call the guard condition function to determine the state of this node, the result of which should be a boolean.\n conditionFunctionResult = conditionFuncInvoker(this.args);\n } catch (error) {\n // An uncaught error was thrown.\n if (error instanceof Error) {\n throw new Error(`guard condition function '${this.getCondition()}' threw: ${error.stack}`);\n } else {\n throw new Error(`guard condition function '${this.getCondition()}' threw: ${error}`);\n }\n }\n\n // The result of calling the guard condition function must be a boolean value.\n if (typeof conditionFunctionResult !== \"boolean\") {\n throw new Error(\n `expected guard condition function '${this.getCondition()}' to return a boolean but returned '${conditionFunctionResult}'`\n );\n }\n\n // Return whether this guard is satisfied.\n return conditionFunctionResult;\n };\n}\n", "import Guard from \"./Guard\";\nimport Lookup from \"../../Lookup\";\nimport { Agent } from \"../../Agent\";\n\n/**\n * An UNTIL guard which is satisfied as long as the given condition remains false.\n */\nexport default class Until extends Guard {\n /**\n * @param condition The name of the condition function that determines whether the guard is satisfied.\n * @param args The array of decorator argument definitions.\n */\n constructor(condition: string, args: any[]) {\n super(\"until\", args, condition);\n }\n\n /**\n * Gets whether the guard is satisfied.\n * @param agent The agent.\n * @returns Whether the guard is satisfied.\n */\n isSatisfied = (agent: Agent) => {\n // Attempt to get the invoker for the condition function.\n const conditionFuncInvoker = Lookup.getFuncInvoker(agent, this.getCondition());\n\n // The condition function should be defined.\n if (conditionFuncInvoker === null) {\n throw new Error(\n `cannot evaluate node guard as the condition '${this.getCondition()}' function is not defined on the agent and has not been registered`\n );\n }\n\n let conditionFunctionResult;\n\n try {\n // Call the guard condition function to determine the state of this node, the result of which should be a boolean.\n conditionFunctionResult = conditionFuncInvoker(this.args);\n } catch (error) {\n // An uncaught error was thrown.\n if (error instanceof Error) {\n throw new Error(`guard condition function '${this.getCondition()}' threw: ${error.stack}`);\n } else {\n throw new Error(`guard condition function '${this.getCondition()}' threw: ${error}`);\n }\n }\n\n // The result of calling the guard condition function must be a boolean value.\n if (typeof conditionFunctionResult !== \"boolean\") {\n throw new Error(\n `expected guard condition function '${this.getCondition()}' to return a boolean but returned '${conditionFunctionResult}'`\n );\n }\n\n // Return whether this guard is satisfied.\n return !conditionFunctionResult;\n };\n}\n", "import { Agent } from \"../../Agent\";\nimport Attribute, { AttributeDetails } from \"../Attribute\";\n\nexport type CallbackAttributeDetails = {\n /** The name of the agent function that is called. */\n functionName: string;\n} & AttributeDetails;\n\n/**\n * A base node callback attribute.\n */\nexport default abstract class Callback extends Attribute {\n /**\n * @param type The node attribute type.\n * @param args The array of decorator argument definitions.\n * @param functionName The name of the agent function to call.\n */\n constructor(type: string, args: any[], private functionName: string) {\n super(type, args);\n }\n\n /**\n * Gets the name of the agent function to call.\n */\n getFunctionName = () => this.functionName;\n\n /**\n * Gets whether this attribute is a guard.\n */\n isGuard = () => false;\n\n /**\n * Gets the attribute details.\n */\n getDetails(): CallbackAttributeDetails {\n return {\n type: this.type,\n args: this.args,\n functionName: this.getFunctionName()\n };\n }\n\n /**\n * Attempt to call the agent function that this callback refers to.\n * @param agent The agent.\n */\n abstract callAgentFunction: (agent: Agent, isSuccess: boolean, isAborted: boolean) => void;\n}\n", "import Callback from \"./Callback\";\nimport Lookup from \"../../Lookup\";\nimport { Agent } from \"../../Agent\";\n\n/**\n * An ENTRY callback which defines an agent function to call when the associated node is updated and moves out of running state.\n */\nexport default class Entry extends Callback {\n /**\n * @param functionName The name of the agent function to call.\n * @param args The array of callback argument definitions.\n */\n constructor(functionName: string, args: any[]) {\n super(\"entry\", args, functionName);\n }\n\n /**\n * Attempt to call the agent function that this callback refers to.\n * @param agent The agent.\n */\n callAgentFunction = (agent: Agent) => {\n // Attempt to get the invoker for the callback function.\n const callbackFuncInvoker = Lookup.getFuncInvoker(agent, this.getFunctionName());\n\n // The callback function should be defined.\n if (callbackFuncInvoker === null) {\n throw new Error(\n `cannot call entry function '${this.getFunctionName()}' as is not defined on the agent and has not been registered`\n );\n }\n\n // Call the callback function.\n callbackFuncInvoker(this.args);\n };\n}\n", "import Callback from \"./Callback\";\nimport Lookup from \"../../Lookup\";\nimport { Agent } from \"../../Agent\";\n\n/**\n * A STEP callback which defines an agent function to call when the associated node is updated.\n */\nexport default class Step extends Callback {\n /**\n * @param functionName The name of the agent function to call.\n * @param args The array of callback argument definitions.\n */\n constructor(functionName: string, args: any[]) {\n super(\"step\", args, functionName);\n }\n\n /**\n * Attempt to call the agent function that this callback refers to.\n * @param agent The agent.\n */\n callAgentFunction = (agent: Agent) => {\n // Attempt to get the invoker for the callback function.\n const callbackFuncInvoker = Lookup.getFuncInvoker(agent, this.getFunctionName());\n\n // The callback function should be defined.\n if (callbackFuncInvoker === null) {\n throw new Error(\n `cannot call step function '${this.getFunctionName()}' as is not defined on the agent and has not been registered`\n );\n }\n\n // Call the callback function.\n callbackFuncInvoker(this.args);\n };\n}\n", "import Callback from \"./Callback\";\nimport Lookup from \"../../Lookup\";\nimport { Agent } from \"../../Agent\";\n\n/**\n * An EXIT callback which defines an agent function to call when the associated node is updated and moves to a finished state or is aborted.\n */\nexport default class Exit extends Callback {\n /**\n * @param functionName The name of the agent function to call.\n * @param args The array of callback argument definitions.\n */\n constructor(functionName: string, args: any[]) {\n super(\"exit\", args, functionName);\n }\n\n /**\n * Attempt to call the agent function that this callback refers to.\n * @param agent The agent.\n * @param isSuccess Whether the decorated node was left with a success state.\n * @param isAborted Whether the decorated node was aborted.\n */\n callAgentFunction = (agent: Agent, isSuccess: boolean, isAborted: boolean) => {\n // Attempt to get the invoker for the callback function.\n const callbackFuncInvoker = Lookup.getFuncInvoker(agent, this.getFunctionName());\n\n // The callback function should be defined.\n if (callbackFuncInvoker === null) {\n throw new Error(\n `cannot call exit function '${this.getFunctionName()}' as is not defined on the agent and has not been registered`\n );\n }\n\n // Call the callback function\n callbackFuncInvoker([{ succeeded: isSuccess, aborted: isAborted }, ...this.args]);\n };\n}\n", "import { AnyNodeDefinition, RootNodeDefinition } from \"./BehaviourTreeDefinition\";\nimport GuardPath, { GuardPathPart } from \"./attributes/guards/GuardPath\";\nimport { validateBranchSubtreeLinks } from \"./BehaviourTreeDefinitionValidator\";\nimport { isInteger } from \"./BehaviourTreeDefinitionUtilities\";\nimport Node from \"./nodes/Node\";\nimport Composite from \"./nodes/composite/Composite\";\nimport Decorator from \"./nodes/decorator/Decorator\";\nimport Parallel from \"./nodes/composite/Parallel\";\nimport Selector from \"./nodes/composite/Selector\";\nimport Sequence from \"./nodes/composite/Sequence\";\nimport Lotto from \"./nodes/composite/Lotto\";\nimport Fail from \"./nodes/decorator/Fail\";\nimport Flip from \"./nodes/decorator/Flip\";\nimport Repeat from \"./nodes/decorator/Repeat\";\nimport Retry from \"./nodes/decorator/Retry\";\nimport Root from \"./nodes/decorator/Root\";\nimport Succeed from \"./nodes/decorator/Succeed\";\nimport Action from \"./nodes/leaf/Action\";\nimport Condition from \"./nodes/leaf/Condition\";\nimport Wait from \"./nodes/leaf/Wait\";\nimport Lookup from \"./Lookup\";\nimport Attribute from \"./attributes/Attribute\";\nimport While from \"./attributes/guards/While\";\nimport Until from \"./attributes/guards/Until\";\nimport Entry from \"./attributes/callbacks/Entry\";\nimport Step from \"./attributes/callbacks/Step\";\nimport Exit from \"./attributes/callbacks/Exit\";\n\n/**\n * A type representing any node instance in a behaviour tree.\n */\ntype AnyNode =\n | Root\n | Action\n | Condition\n | Wait\n | Sequence\n | Selector\n | Lotto\n | Parallel\n | Repeat\n | Retry\n | Flip\n | Succeed\n | Fail;\n\n/**\n * A type defining a mapping of root node identifiers to root node definitions.\n */\ntype RootNodeDefinitionMap = { [key: string | symbol]: RootNodeDefinition };\n\n/**\n * A symbol to use as the main root key in any root node mappings.\n */\nconst MAIN_ROOT_NODE_KEY = Symbol(\"__root__\");\n\n/**\n * Build and populate the root nodes based on the provided definition, assuming that the definition has been validated.\n * @param definition The root node definitions.\n * @returns The built and populated root node definitions.\n */\nexport default function buildRootNode(definition: RootNodeDefinition[]): Root {\n // Create a mapping of root node identifers to root node definitions, including globally registered subtree root node definitions.\n const rootNodeDefinitionMap = createRootNodeDefinitionMap(definition);\n\n // Now that we have all of our root node definitions (those part of the tree definition and those globally registered)\n // we should validate the branch-subtree links. This will also double-check that we dont have any circular dependencies\n // in our branch-subtree references and that we have no broken branch-subtree links.\n validateBranchSubtreeLinks(\n [rootNodeDefinitionMap[MAIN_ROOT_NODE_KEY], ...Object.values(rootNodeDefinitionMap)],\n true\n );\n\n // Create our populated tree of node instances, starting with our main root node.\n const rootNode = nodeFactory(rootNodeDefinitionMap[MAIN_ROOT_NODE_KEY], rootNodeDefinitionMap) as Root;\n\n // Set a guard path on every leaf of the tree to evaluate as part of each update.\n applyLeafNodeGuardPaths(rootNode);\n\n // We only need to return the main root node.\n return rootNode;\n}\n\n/**\n * A factory function which creates a node instance based on the specified definition.\n * @param definition The node definition.\n * @param rootNodeDefinitionMap The mapping of root node identifers to root node definitions, including globally registered subtree root node definitions.\n * @returns A node instance based on the specified definition.\n */\nfunction nodeFactory(definition: AnyNodeDefinition, rootNodeDefinitionMap: RootNodeDefinitionMap): AnyNode {\n // Get the attributes for the node.\n const attributes = nodeAttributesFactory(definition);\n\n // Create the node instance based on the definition type.\n switch (definition.type) {\n case \"root\":\n return new Root(attributes, nodeFactory(definition.child, rootNodeDefinitionMap));\n\n case \"repeat\":\n let iterations: number | null = null;\n let iterationsMin: number | null = null;\n let iterationsMax: number | null = null;\n\n if (Array.isArray(definition.iterations)) {\n iterationsMin = definition.iterations[0];\n iterationsMax = definition.iterations[1];\n } else if (isInteger(definition.iterations)) {\n iterations = definition.iterations!;\n }\n\n return new Repeat(\n attributes,\n iterations,\n iterationsMin,\n iterationsMax,\n nodeFactory(definition.child, rootNodeDefinitionMap)\n );\n\n case \"retry\":\n let attempts: number | null = null;\n let attemptsMin: number | null = null;\n let attemptsMax: number | null = null;\n\n if (Array.isArray(definition.attempts)) {\n attemptsMin = definition.attempts[0];\n attemptsMax = definition.attempts[1];\n } else if (isInteger(definition.attempts)) {\n attempts = definition.attempts!;\n }\n\n return new Retry(\n attributes,\n attempts,\n attemptsMin,\n attemptsMax,\n nodeFactory(definition.child, rootNodeDefinitionMap)\n );\n\n case \"flip\":\n return new Flip(attributes, nodeFactory(definition.child, rootNodeDefinitionMap));\n\n case \"succeed\":\n return new Succeed(attributes, nodeFactory(definition.child, rootNodeDefinitionMap));\n\n case \"fail\":\n return new Fail(attributes, nodeFactory(definition.child, rootNodeDefinitionMap));\n\n case \"sequence\":\n return new Sequence(\n attributes,\n definition.children.map((child) => nodeFactory(child, rootNodeDefinitionMap))\n );\n\n case \"selector\":\n return new Selector(\n attributes,\n definition.children.map((child) => nodeFactory(child, rootNodeDefinitionMap))\n );\n\n case \"parallel\":\n return new Parallel(\n attributes,\n definition.children.map((child) => nodeFactory(child, rootNodeDefinitionMap))\n );\n\n case \"lotto\":\n return new Lotto(\n attributes,\n definition.weights,\n definition.children.map((child) => nodeFactory(child, rootNodeDefinitionMap))\n );\n\n case \"branch\":\n return nodeFactory(rootNodeDefinitionMap[definition.ref].child, rootNodeDefinitionMap);\n\n case \"action\":\n return new Action(attributes, definition.call, definition.args || []);\n\n case \"condition\":\n return new Condition(attributes, definition.call, definition.args || []);\n\n case \"wait\":\n let duration: number | null = null;\n let durationMin: number | null = null;\n let durationMax: number | null = null;\n\n if (Array.isArray(definition.duration)) {\n durationMin = definition.duration[0];\n durationMax = definition.duration[1];\n } else if (isInteger(definition.duration)) {\n duration = definition.duration!;\n }\n\n return new Wait(attributes, duration, durationMin, durationMax);\n }\n}\n\n/**\n * Creates an array of node attribute instances based on the specified node definition.\n * @param definition The node definition.\n * @returns An array of node attribute instances based on the specified node definition.\n */\nfunction nodeAttributesFactory(definition: AnyNodeDefinition): Attribute[] {\n const attributes: Attribute[] = [];\n\n if (definition.while) {\n attributes.push(new While(definition.while.call, definition.while.args ?? []));\n }\n\n if (definition.until) {\n attributes.push(new Until(definition.until.call, definition.until.args ?? []));\n }\n\n if (definition.entry) {\n attributes.push(new Entry(definition.entry.call, definition.entry.args ?? []));\n }\n\n if (definition.step) {\n attributes.push(new Step(definition.step.call, definition.step.args ?? []));\n }\n\n if (definition.exit) {\n attributes.push(new Exit(definition.exit.call, definition.exit.args ?? []));\n }\n\n return attributes;\n}\n\n/**\n * Creates a mapping of root node identifers to root node definitions, mixing in globally registered subtree root node definitions.\n * @param definition The root node definitions.\n * @returns A mapping of root node identifers to root node definitions, including globally registered subtree root node definitions.\n */\nfunction createRootNodeDefinitionMap(definition: RootNodeDefinition[]): RootNodeDefinitionMap {\n // Create a mapping of root node identifers to root node definitions.\n const rootNodeMap: RootNodeDefinitionMap = {};\n\n // Add in any registered subtree root node definitions.\n for (const [name, rootNodeDefinition] of Object.entries(Lookup.getSubtrees())) {\n // The name used when registering the subtree will be used as the root node identifier.\n rootNodeMap[name] = { ...rootNodeDefinition, id: name };\n }\n\n // Populate the map with the root node definitions that were included with the tree definition.\n // We do this after adding any registered subtrees as we want these to take presedence.\n for (const rootNodeDefinition of definition) {\n rootNodeMap[rootNodeDefinition.id ?? MAIN_ROOT_NODE_KEY] = rootNodeDefinition;\n }\n\n return rootNodeMap;\n}\n\n/**\n * Applies a guard path to every leaf of the tree to evaluate as part of each update.\n * @param root The main root tree node.\n */\nfunction applyLeafNodeGuardPaths(root: Root) {\n const nodePaths: Node[][] = [];\n\n const findLeafNodes = (path: Node[], node: Node) => {\n // Add the current node to the path.\n path = path.concat(node);\n\n // Check whether the current node is a leaf node.\n if (node.isLeafNode()) {\n nodePaths.push(path);\n } else {\n (node as Composite | Decorator).getChildren().forEach((child) => findLeafNodes(path, child));\n }\n };\n\n // Find all leaf node paths, starting from the root.\n findLeafNodes([], root);\n\n nodePaths.forEach((path) => {\n // Each node in the current path will have to be assigned a guard path, working from the root outwards.\n for (let depth = 0; depth < path.length; depth++) {\n // Get the node in the path at the current depth.\n const currentNode = path[depth];\n\n // The node may already have been assigned a guard path, if so just skip it.\n if (currentNode.hasGuardPath()) {\n continue;\n }\n\n // Create the guard path for the current node.\n const guardPath = new GuardPath(\n path\n .slice(0, depth + 1)\n .map((node) => ({ node, guards: node.getGuardAttributes() }))\n .filter((details) => details.guards.length > 0)\n );\n\n // Assign the guard path to the current node.\n currentNode.setGuardPath(guardPath);\n }\n });\n}\n", "import State, { AnyState } from \"./State\";\nimport Lookup from \"./Lookup\";\nimport Node from \"./nodes/Node\";\nimport Root from \"./nodes/decorator/Root\";\nimport Composite from \"./nodes/composite/Composite\";\nimport Decorator from \"./nodes/decorator/Decorator\";\nimport { Agent, GlobalFunction } from \"./Agent\";\nimport { CallbackAttributeDetails } from \"./attributes/callbacks/Callback\";\nimport { GuardAttributeDetails } from \"./attributes/guards/Guard\";\nimport { BehaviourTreeOptions } from \"./BehaviourTreeOptions\";\nimport { convertMDSLToJSON } from \"./mdsl/MDSLDefinitionParser\";\nimport { RootNodeDefinition } from \"./BehaviourTreeDefinition\";\nimport { validateDefinition, validateJSONDefinition } from \"./BehaviourTreeDefinitionValidator\";\nimport buildRootNode from \"./BehaviourTreeBuilder\";\nimport { isNullOrUndefined } from \"./BehaviourTreeDefinitionUtilities\";\n\n// Purely for outside inspection of the tree.\nexport type FlattenedTreeNode = {\n id: string;\n type: string;\n caption: string;\n state: AnyState;\n guards: GuardAttributeDetails[];\n callbacks: CallbackAttributeDetails[];\n args: any[];\n parentId: string | null;\n};\n\n/**\n * A representation of a behaviour tree.\n */\nexport class BehaviourTree {\n /**\n * The main root tree node.\n */\n private readonly _rootNode: Root;\n\n /**\n * Creates a new instance of the BehaviourTree class.\n * @param definition The behaviour tree definition as either an MDSL string, root node definition object or array of root node definition objects.\n * @param agent The agent instance that this behaviour tree is modelling behaviour for.\n * @param options The behaviour tree options object.\n */\n constructor(\n definition: string | RootNodeDefinition | RootNodeDefinition[],\n private agent: Agent,\n private options: BehaviourTreeOptions = {}\n ) {\n // The tree definition must be defined.\n if (isNullOrUndefined(definition)) {\n throw new Error(\"tree definition not defined\");\n }\n\n // The agent must be defined and not null.\n if (typeof agent !== \"object\" || agent === null) {\n throw new Error(\"the agent must be an object and not null\");\n }\n\n // We should validate the definition before we try to build the tree nodes.\n const { succeeded, errorMessage, json } = validateDefinition(definition);\n\n // Did our validation fail without error?\n if (!succeeded) {\n throw new Error(`invalid definition: ${errorMessage}`);\n }\n\n // Double check that we did actually get our json definition as part of our definition validtion.\n if (!json) {\n throw new Error(\n \"expected json definition to be returned as part of successful definition validation response\"\n );\n }\n\n try {\n // Create the populated tree of behaviour tree nodes and get the root node.\n this._rootNode = buildRootNode(json);\n } catch (exception) {\n // There was an issue in trying build and populate the behaviour tree.\n throw new Error(`error building tree: ${(exception as Error).message}`);\n }\n }\n\n /**\n * Gets whether the tree is in the RUNNING state.\n * @returns true if the tree is in the RUNNING state, otherwise false.\n */\n isRunning() {\n return this._rootNode.getState() === State.RUNNING;\n }\n\n /**\n * Gets the current tree state of SUCCEEDED, FAILED, READY or RUNNING.\n * @returns The current tree state.\n */\n getState() {\n return this._rootNode.getState();\n }\n\n /**\n * Step the tree.\n * 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.\n * 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\n * 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.\n *\n * 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.\n */\n step() {\n // If the root node has already been stepped to completion then we need to reset it.\n if (this._rootNode.getState() === State.SUCCEEDED || this._rootNode.getState() === State.FAILED) {\n this._rootNode.reset();\n }\n\n try {\n this._rootNode.update(this.agent, this.options);\n } catch (exception) {\n throw new Error(`error stepping tree: ${(exception as Error).message}`);\n }\n }\n\n /**\n * Resets the tree from the root node outwards to each nested node, giving each a state of READY.\n */\n reset() {\n this._rootNode.reset();\n }\n\n /**\n * Gets the flattened details of every node in the tree.\n * @returns The flattened details of every node in the tree.\n */\n getFlattenedNodeDetails(): FlattenedTreeNode[] {\n // Create an empty flattened array of tree nodes.\n const flattenedTreeNodes: FlattenedTreeNode[] = [];\n\n /**\n * Helper function to process a node instance and push details into the flattened tree nodes array.\n * @param node The current node.\n * @param parentUid The UID of the node parent, or null if the node is the main root node.\n */\n const processNode = (node: Node, parentUid: string | null) => {\n // Get the guard and callback attribute details for this node.\n const guards = node\n .getAttributes()\n .filter((attribute) => attribute.isGuard())\n .map((attribute) => attribute.getDetails()) as GuardAttributeDetails[];\n const callbacks = node\n .getAttributes()\n .filter((attribute) => !attribute.isGuard())\n .map((attribute) => attribute.getDetails()) as CallbackAttributeDetails[];\n\n // Push the current node into the flattened nodes array.\n flattenedTreeNodes.push({\n id: node.getUid(),\n type: node.getType(),\n caption: node.getName(),\n state: node.getState(),\n guards,\n callbacks,\n args: node.getArguments(),\n parentId: parentUid\n });\n\n // Process each of the nodes children if it is not a leaf node.\n if (!node.isLeafNode()) {\n (node as Composite | Decorator)\n .getChildren()\n .forEach((child) => processNode(child, (node as Composite | Decorator).getUid()));\n }\n };\n\n // Convert the nested node structure into a flattened array of node details.\n processNode(this._rootNode, null);\n\n return flattenedTreeNodes;\n }\n\n /**\n * Registers the action/condition/guard/callback function or subtree with the given name.\n * @param name The name of the function or subtree to register.\n * @param value The function or subtree definition to register.\n */\n static register(name: string, value: GlobalFunction | string | RootNodeDefinition) {\n // Are we going to register a action/condition/guard/callback function?\n if (typeof value === \"function\") {\n Lookup.setFunc(name, value);\n return;\n }\n\n // We are not registering an action/condition/guard/callback function, so we must be registering a subtree.\n if (typeof value === \"string\") {\n let rootNodeDefinitions: RootNodeDefinition[];\n\n // We will assume that any string passed in will be a mdsl definition.\n try {\n rootNodeDefinitions = convertMDSLToJSON(value);\n } catch (exception) {\n throw new Error(`error registering definition, invalid MDSL: ${(exception as Error).message}`);\n }\n\n // This function should only ever be called with a definition containing a single unnamed root node.\n if (rootNodeDefinitions.length != 1 || typeof rootNodeDefinitions[0].id !== \"undefined\") {\n throw new Error(\"error registering definition: expected a single unnamed root node\");\n }\n\n try {\n // We should validate the subtree as we don't want invalid subtrees available via the lookup.\n const { succeeded, errorMessage } = validateJSONDefinition(rootNodeDefinitions[0]);\n\n // Did our validation fail without error?\n if (!succeeded) {\n throw new Error(errorMessage);\n }\n } catch (exception) {\n throw new Error(`error registering definition: ${(exception as Error).message}`);\n }\n\n // Everything seems hunky-dory, register the subtree.\n Lookup.setSubtree(name, rootNodeDefinitions[0]);\n } else if (typeof value === \"object\" && !Array.isArray(value)) {\n // We will assume that any object passed in is a root node definition.\n\n try {\n // We should validate the subtree as we don't want invalid subtrees available via the lookup.\n const { succeeded, errorMessage } = validateJSONDefinition(value);\n\n // Did our validation fail without error?\n if (!succeeded) {\n throw new Error(errorMessage);\n }\n } catch (exception) {\n throw new Error(`error registering definition: ${(exception as Error).message}`);\n }\n\n // Everything seems hunky-dory, register the subtree.\n Lookup.setSubtree(name, value);\n } else {\n throw new Error(\"unexpected value, expected string mdsl definition, root node json definition or function\");\n }\n }\n\n /**\n * Unregisters the registered action/condition/guard/callback function or subtree with the given name.\n * @param name The name of the registered action/condition/guard/callback function or subtree to unregister.\n */\n static unregister(name: string): void {\n Lookup.remove(name);\n }\n\n /**\n * Unregister all registered action/condition/guard/callback functions and subtrees.\n */\n static unregisterAll(): void {\n Lookup.empty();\n }\n}\n"], - "mappings": "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", + "sourcesContent": ["\"use strict\";\r\nObject.defineProperty(exports, \"__esModule\", { value: true });\r\nexports.Participant = void 0;\r\n/**\r\n * A participant that holds a number of tickets.\r\n */\r\nvar Participant = /** @class */ (function () {\r\n /**\r\n * Creates an instance of the Participant class.\r\n * @param participant The actual participant.\r\n * @param tickets The number of tickets held by the participant.\r\n */\r\n function Participant(participant, tickets) {\r\n if (tickets === void 0) { tickets = 1; }\r\n this._participant = participant;\r\n this._tickets = tickets;\r\n }\r\n Object.defineProperty(Participant.prototype, \"participant\", {\r\n /** Gets the actual participant. */\r\n get: function () {\r\n return this._participant;\r\n },\r\n enumerable: false,\r\n configurable: true\r\n });\r\n Object.defineProperty(Participant.prototype, \"tickets\", {\r\n /** Gets or sets the number of tickets held by the participant. */\r\n get: function () {\r\n return this._tickets;\r\n },\r\n set: function (value) {\r\n this._tickets = value;\r\n },\r\n enumerable: false,\r\n configurable: true\r\n });\r\n return Participant;\r\n}());\r\nexports.Participant = Participant;\r\n", "\"use strict\";\r\nObject.defineProperty(exports, \"__esModule\", { value: true });\r\nexports.isNaturalNumber = exports.isNullOrUndefined = void 0;\r\n/**\r\n * Gets whether the value provided is null or undefined.\r\n * @param value The value to check.\r\n * @returns Whether the value provided is null or undefined.\r\n */\r\nfunction isNullOrUndefined(value) {\r\n return value === null || value === undefined;\r\n}\r\nexports.isNullOrUndefined = isNullOrUndefined;\r\n/**\r\n * Gets whether the value provided is a natural number.\r\n * @param value The value to check.\r\n * @returns Whether the value provided is a natural number.\r\n */\r\nfunction isNaturalNumber(value) {\r\n return typeof value === \"number\" && value >= 1 && Math.floor(value) === value;\r\n}\r\nexports.isNaturalNumber = isNaturalNumber;\r\n", "\"use strict\";\r\nObject.defineProperty(exports, \"__esModule\", { value: true });\r\nexports.Lotto = void 0;\r\nvar Participant_1 = require(\"./Participant\");\r\nvar Utilities_1 = require(\"./Utilities\");\r\n/**\r\n * Represents a lotto consisting of a number of pickable ticket-holding participants.\r\n */\r\nvar Lotto = /** @class */ (function () {\r\n /**\r\n * Creates a new instance of Lotto.\r\n * @param customRandom The custom RNG to use in place of Math.random().\r\n */\r\n function Lotto(customRandom) {\r\n /** The array of participants that are holding tickets in the lotto. */\r\n this._participants = [];\r\n this._customRandom = customRandom;\r\n }\r\n /**\r\n * Adds a participant with the specified number of tickets, or adds to the participant ticket count if the participant already holds tickets.\r\n * @param participant The participant to add or to increase the ticket count for if they already hold tickets.\r\n * @param tickets The number of tickets, defaults to 1.\r\n * @returns The Lotto instance.\r\n */\r\n Lotto.prototype.add = function (participant, tickets) {\r\n if (tickets === void 0) { tickets = 1; }\r\n // Check that we have a valid ticket count.\r\n if (!(0, Utilities_1.isNaturalNumber)(tickets)) {\r\n throw new Error(\"tickets value must be a natural number\");\r\n }\r\n // Check whether this participant has already been added.\r\n var existingParticipant = this._participants.find(function (part) { return part.participant === participant; });\r\n if (existingParticipant) {\r\n // The participant has already been added to the lotto so just add to their ticket count.\r\n existingParticipant.tickets += tickets;\r\n }\r\n else {\r\n // The participant is not part of the lotto so we should add them.\r\n this._participants.push(new Participant_1.Participant(participant, tickets));\r\n }\r\n return this;\r\n };\r\n /**\r\n * Removes the specified number of tickets for the given participant from the draw, or all tickets if a ticket number is not defined.\r\n * @param participant The participant to remove tickets for.\r\n * @param tickets The number of tickets to remove, or undefined if all tickets are to be removed.\r\n * @returns The Lotto instance.\r\n */\r\n Lotto.prototype.remove = function (participant, tickets) {\r\n // Attempt to get the existing participant.\r\n var existingParticipant = this._participants.find(function (part) { return part.participant === participant; });\r\n // There is nothing to do if the specified participant isn't even part of the lotto.\r\n if (!existingParticipant) {\r\n return this;\r\n }\r\n // Check whether a tickets value was given.\r\n if (tickets !== undefined) {\r\n // Check that we have a valid ticket count.\r\n if (!(0, Utilities_1.isNaturalNumber)(tickets)) {\r\n throw new Error(\"tickets value must be a natural number\");\r\n }\r\n existingParticipant.tickets -= tickets;\r\n // If the participant no longer holds any tickets then they should be removed.\r\n if (existingParticipant.tickets < 1) {\r\n this._participants = this._participants.filter(function (part) { return part !== existingParticipant; });\r\n }\r\n }\r\n else {\r\n // We are removing all tickets for the participant so just remove them from the lotto.\r\n this._participants = this._participants.filter(function (part) { return part !== existingParticipant; });\r\n }\r\n return this;\r\n };\r\n /**\r\n * Draw a winning ticket and return the participant that holds the ticket.\r\n * @param options The draw options.\r\n * @returns The participant that holds the winning ticket.\r\n */\r\n Lotto.prototype.draw = function (options) {\r\n if (options === void 0) { options = {}; }\r\n // If we have no participants then just return null.\r\n if (this._participants.length === 0) {\r\n return null;\r\n }\r\n var redrawable = (0, Utilities_1.isNullOrUndefined)(options.redrawable) ? true : options.redrawable;\r\n var pickable = [];\r\n this._participants.forEach(function (_a) {\r\n var participant = _a.participant, tickets = _a.tickets;\r\n for (var ticketCount = 0; ticketCount < tickets; ticketCount++) {\r\n pickable.push(participant);\r\n }\r\n });\r\n var random;\r\n // We need a random floating-point number between 0 (inclusive) and 1 to scale up to pick our winner.\r\n // If a custom random function exists then we should use that or fall back to Math.random().\r\n if (this._customRandom) {\r\n // Call our custom random function to get a random floating-point number.\r\n random = this._customRandom();\r\n // Verify that the result of calling our custom random function is a number between 0 (inclusive) and 1.\r\n if (typeof random !== \"number\" || random < 0 || random >= 1) {\r\n throw new Error(\"the 'random' function provided did not return a number between 0 (inclusive) and 1\");\r\n }\r\n }\r\n else {\r\n // No custom random function was defined so just use good ol' Math.random().\r\n random = Math.random();\r\n }\r\n // Pick a winning participant.\r\n var winner = pickable[Math.floor(random * pickable.length)];\r\n // If the ticket isn't redrawable then we should remove a ticket from the winning participants ticket count.\r\n if (!redrawable) {\r\n this.remove(winner, 1);\r\n }\r\n // Return the winning participant.\r\n return winner;\r\n };\r\n /**\r\n * Draws multiple winning tickets and return an array of the participants that hold the winning tickets.\r\n * @param tickets The number of winning tickets to draw.\r\n * @param options The draw multiple options.\r\n * @returns An array of the participants that hold the winning tickets.\r\n */\r\n Lotto.prototype.drawMultiple = function (tickets, options) {\r\n if (options === void 0) { options = {}; }\r\n var uniqueResults = (0, Utilities_1.isNullOrUndefined)(options.unique) ? false : options.unique;\r\n // Handle cases where the user has asked for zero tickets (no idea why they would do this be we should trust them).\r\n if (tickets === 0) {\r\n return [];\r\n }\r\n // Now that we know out tickets value is not zero we should check that it is a valid natural number.\r\n if (!(0, Utilities_1.isNaturalNumber)(tickets)) {\r\n throw new Error(\"tickets value must be a natural number\");\r\n }\r\n var result = [];\r\n // Keep drawing tickets until we either reach the number of required tickets or we simply run out of tickets to draw.\r\n // We can run out of tickets to draw if 'options.redrawable' is explicity 'false' or we just had no participants when 'drawMultiple' was called.\r\n while (result.length < tickets && this._participants.length > 0) {\r\n result.push(this.draw(options));\r\n }\r\n // If the 'unique' draw option is set then we need to remove duplicates from the result list.\r\n if (uniqueResults) {\r\n // Create an array to store our unique results.\r\n var unique = [];\r\n // Iterate over all of our participants (with potential duplicates) and populate our array of unique values.\r\n for (var _i = 0, result_1 = result; _i < result_1.length; _i++) {\r\n var participant = result_1[_i];\r\n if (unique.indexOf(participant) === -1) {\r\n unique.push(participant);\r\n }\r\n }\r\n result = unique;\r\n }\r\n return result;\r\n };\r\n return Lotto;\r\n}());\r\nexports.Lotto = Lotto;\r\n", "\"use strict\";\r\nObject.defineProperty(exports, \"__esModule\", { value: true });\r\nexports.createLotto = void 0;\r\nvar Lotto_1 = require(\"./Lotto\");\r\n/**\r\n * A function that creates and returns a Lotto instance.\r\n * @param participantsOrOptions An array of initial participants or options relating to the creation of a Lotto instance.\r\n * @returns A new Lotto instance.\r\n */\r\nfunction createLotto(participantsOrOptions) {\r\n // If no initial participants or lotto options were provided as an argument then we can just return a new lotto instance now.\r\n if (!participantsOrOptions) {\r\n return new Lotto_1.Lotto();\r\n }\r\n // Check whether we were provided with an array of initial participants or a lotto options object.\r\n if (Array.isArray(participantsOrOptions)) {\r\n // We are dealing with a pre-defined array of participants.\r\n var participants = participantsOrOptions;\r\n var lotto_1 = new Lotto_1.Lotto();\r\n // If the lotto participants have been defined upfront then we will need to add them all to our lotto instance now.\r\n participants.forEach(function (_a) {\r\n var participant = _a[0], tokens = _a[1];\r\n return lotto_1.add(participant, tokens);\r\n });\r\n // Return the Lotto instance.\r\n return lotto_1;\r\n }\r\n else {\r\n // We are dealing with some lotto options.\r\n var random = participantsOrOptions.random, participants = participantsOrOptions.participants;\r\n // Create a Lotto instance passing the custom RNG function to use in place of Math.random() (which could be undefined).\r\n var lotto_2 = new Lotto_1.Lotto(random);\r\n // If the lotto participants have been defined upfront as part of the options then we will need to add them all to our lotto instance now.\r\n if (participants) {\r\n participants.forEach(function (_a) {\r\n var participant = _a[0], tokens = _a[1];\r\n return lotto_2.add(participant, tokens);\r\n });\r\n }\r\n // Return the Lotto instance.\r\n return lotto_2;\r\n }\r\n}\r\nexports.createLotto = createLotto;\r\n", "\"use strict\";\r\nObject.defineProperty(exports, \"__esModule\", { value: true });\r\nvar createLotto_1 = require(\"./createLotto\");\r\nexports.default = createLotto_1.createLotto;\r\n", "import State from \"./State\";\nimport { validateDefinition } from \"./BehaviourTreeDefinitionValidator\";\nimport { convertMDSLToJSON } from \"./mdsl/MDSLDefinitionParser\";\nimport { BehaviourTree, FlattenedTreeNode } from \"./BehaviourTree\";\nimport { BehaviourTreeOptions } from \"./BehaviourTreeOptions\";\n\nexport { BehaviourTree, State, convertMDSLToJSON, validateDefinition };\nexport type { FlattenedTreeNode, BehaviourTreeOptions };\n", "/**\n * Enumeration of node state types.\n */\nexport enum State {\n READY = \"mistreevous.ready\",\n RUNNING = \"mistreevous.running\",\n SUCCEEDED = \"mistreevous.succeeded\",\n FAILED = \"mistreevous.failed\"\n}\n\nexport { State as default };\n\nexport type CompleteState = State.SUCCEEDED | State.FAILED;\nexport type AnyState = State.READY | State.RUNNING | CompleteState;\n", "import {\n NodeDefinition,\n RootNodeDefinition,\n DecoratorNodeDefinition,\n CompositeNodeDefinition,\n AnyNodeDefinition,\n BranchNodeDefinition\n} from \"./BehaviourTreeDefinition\";\n\n/**\n * A type guard function that returns true if the specified node satisfies the RootNodeDefinition type.\n * @param node The node.\n * @returns A value of true if the specified node satisfies the RootNodeDefinition type.\n */\nexport function isRootNode(node: NodeDefinition): node is RootNodeDefinition {\n return node.type === \"root\";\n}\n\n/**\n * A type guard function that returns true if the specified node satisfies the BranchNodeDefinition type.\n * @param node The node.\n * @returns A value of true if the specified node satisfies the BranchNodeDefinition type.\n */\nexport function isBranchNode(node: NodeDefinition): node is BranchNodeDefinition {\n return node.type === \"branch\";\n}\n\n/**\n * A type guard function that returns true if the specified node satisfies the NodeDefinition type.\n * @param node The node.\n * @returns A value of true if the specified node satisfies the NodeDefinition type.\n */\nexport function isLeafNode(node: NodeDefinition): node is NodeDefinition {\n return [\"branch\", \"action\", \"condition\", \"wait\"].includes(node.type);\n}\n\n/**\n * A type guard function that returns true if the specified node satisfies the DecoratorNodeDefinition type.\n * @param node The node.\n * @returns A value of true if the specified node satisfies the DecoratorNodeDefinition type.\n */\nexport function isDecoratorNode(node: NodeDefinition): node is DecoratorNodeDefinition {\n return [\"root\", \"repeat\", \"retry\", \"flip\", \"succeed\", \"fail\"].includes(node.type);\n}\n\n/**\n * A type guard function that returns true if the specified node satisfies the CompositeNodeDefinition type.\n * @param node The node.\n * @returns A value of true if the specified node satisfies the CompositeNodeDefinition type.\n */\nexport function isCompositeNode(node: NodeDefinition): node is CompositeNodeDefinition {\n return [\"sequence\", \"selector\", \"lotto\", \"parallel\"].includes(node.type);\n}\n\n/**\n * Flatten a node definition into an array of all of its nested node definitions.\n * @param nodeDefinition The node definition to flatten.\n * @returns An array of all of nested node definitions.\n */\nexport function flattenDefinition(nodeDefinition: AnyNodeDefinition): AnyNodeDefinition[] {\n const nodes: AnyNodeDefinition[] = [];\n\n const processNode = (currentNodeDefinition: AnyNodeDefinition) => {\n nodes.push(currentNodeDefinition);\n\n if (isCompositeNode(currentNodeDefinition)) {\n currentNodeDefinition.children.forEach(processNode);\n } else if (isDecoratorNode(currentNodeDefinition)) {\n processNode(currentNodeDefinition.child);\n }\n };\n\n processNode(nodeDefinition);\n\n return nodes;\n}\n\n/**\n * Determines whether the passed value is an integer.\n * @param value The value to check.\n * @returns Whether the passed value is an integer.\n */\nexport function isInteger(value: unknown): boolean {\n return typeof value === \"number\" && Math.floor(value) === value;\n}\n\n/**\n * Determines whether the passed value is null or undefined.\n * @param value The value to check.\n * @returns Whether the passed value is null or undefined.\n */\nexport function isNullOrUndefined(value: unknown): boolean {\n return typeof value === \"undefined\" || value === null;\n}\n", "/**\n * A type defining an object that holds a reference to substitued string literals parsed from the definition.\n */\nexport type StringLiteralPlaceholders = { [key: string]: string };\n\n/**\n * Pop the next raw token from the specified array of tokens and throw an error if it wasn't the expected one.\n * @param tokens The array of tokens.\n * @param expected An optional string or array or items, one of which must match the next popped token.\n * @returns The popped token.\n */\nexport function popAndCheck(tokens: string[], expected?: string | string[]): string {\n // Get and remove the next token.\n const popped = tokens.shift();\n\n // We were expecting another token but there aren't any.\n if (popped === undefined) {\n throw new Error(\"unexpected end of definition\");\n }\n\n // Do we have an expected token/tokens array?\n if (expected != undefined) {\n // Get an array of expected values, if the popped token matches any then we are all good.\n const expectedValues = typeof expected === \"string\" ? [expected] : expected;\n\n // Check whether the popped token matches at least one of our expected items.\n var tokenMatchesExpectation = expectedValues.some((item) => popped.toUpperCase() === item.toUpperCase());\n\n // Throw an error if the popped token didn't match any of our expected items.\n if (!tokenMatchesExpectation) {\n const expectationString = expectedValues.map((item) => \"'\" + item + \"'\").join(\" or \");\n throw new Error(\"unexpected token found. Expected \" + expectationString + \" but got '\" + popped + \"'\");\n }\n }\n\n // Return the popped token.\n return popped;\n}\n\n/**\n * Swaps out any node/attribute argument string literals with placeholders.\n * @param definition The definition.\n * @returns An object containing a mapping of placeholders to original string values as well as the processed definition string.\n */\nexport function substituteStringLiterals(definition: string): {\n placeholders: StringLiteralPlaceholders;\n processedDefinition: string;\n} {\n // Create an object to hold the mapping of placeholders to original string values.\n const placeholders: StringLiteralPlaceholders = {};\n\n // Replace any string literals wrapped with double quotes in our definition with placeholders to be processed later.\n const processedDefinition = definition.replace(/\\\"(\\\\.|[^\"\\\\])*\\\"/g, (match) => {\n var strippedMatch = match.substring(1, match.length - 1);\n var placeholder = Object.keys(placeholders).find((key) => placeholders[key] === strippedMatch);\n\n // If we have no existing string literal match then create a new placeholder.\n if (!placeholder) {\n placeholder = `@@${Object.keys(placeholders).length}@@`;\n placeholders[placeholder] = strippedMatch;\n }\n\n return placeholder;\n });\n\n return { placeholders, processedDefinition };\n}\n\n/**\n * Parse the tree definition into an array of raw tokens.\n * @param definition The definition.\n * @returns An array of tokens parsed from the definition.\n */\nexport function parseTokensFromDefinition(definition: string): string[] {\n // Add some space around various important characters so that they can be plucked out easier as individual tokens.\n definition = definition.replace(/\\(/g, \" ( \");\n definition = definition.replace(/\\)/g, \" ) \");\n definition = definition.replace(/\\{/g, \" { \");\n definition = definition.replace(/\\}/g, \" } \");\n definition = definition.replace(/\\]/g, \" ] \");\n definition = definition.replace(/\\[/g, \" [ \");\n definition = definition.replace(/\\,/g, \" , \");\n\n // Split the definition into raw token form and return it.\n return definition.replace(/\\s+/g, \" \").trim().split(\" \");\n}\n", "import { StringLiteralPlaceholders, popAndCheck } from \"./MDSLUtilities\";\n\n/**\n * A type representing any node function argument.\n */\ntype Argument = {\n /**\n * The argument value.\n */\n value: T;\n /**\n * The argument type, used for validation.\n */\n type: string;\n};\n\ntype NullArgument = Argument & {\n type: \"null\";\n};\n\ntype BooleanArgument = Argument & {\n type: \"boolean\";\n};\n\ntype NumberArgument = Argument & {\n type: \"number\";\n /**\n * A flag defining whether the number argument value is a valid integer. (used for validation)\n */\n isInteger: boolean;\n};\n\ntype StringPlaceholderArgument = Argument & {\n type: \"string\";\n};\n\ntype IdentifierArgument = Argument & {\n type: \"identifier\";\n};\n\n/**\n * A type representing a reference to any node function argument.\n */\ntype AnyArgument = NullArgument | BooleanArgument | NumberArgument | StringPlaceholderArgument | IdentifierArgument;\n\n/**\n * Parse an array of argument definitions from the specified tokens array.\n * @param tokens The array tokens to parse the argument definitions from.\n * @param stringArgumentPlaceholders The mapping of string literal node argument placeholders to original values.\n * @param argumentValidator The argument validator function.\n * @param validationFailedMessage The exception message to throw if argument validation fails.\n * @returns An array of argument definitions parsed from the specified tokens array.\n */\nexport function parseArgumentTokens(\n tokens: string[],\n stringArgumentPlaceholders: StringLiteralPlaceholders\n): AnyArgument[] {\n const argumentList: AnyArgument[] = [];\n\n // If the next token is not a '[' or '(' then we have no arguments to parse.\n if (![\"[\", \"(\"].includes(tokens[0])) {\n return argumentList;\n }\n\n // Any lists of arguments will always be wrapped in '[]' for node arguments or '()' for attribute arguments.\n // We are looking for a '[' or '(' opener that wraps the argument tokens and the relevant closer.\n const closingToken = popAndCheck(tokens, [\"[\", \"(\"]) === \"[\" ? \"]\" : \")\";\n\n const argumentListTokens: string[] = [];\n\n // Grab all tokens between the '[' and ']' or '(' and ')'.\n while (tokens.length && tokens[0] !== closingToken) {\n // The next token is part of our arguments list.\n argumentListTokens.push(tokens.shift()!);\n }\n\n // Validate the order of the argument tokens. Each token must either be a ',' or a single argument that satisfies the validator.\n argumentListTokens.forEach((token, index) => {\n // Get whether this token should be an actual argument.\n const shouldBeArgumentToken = !(index & 1);\n\n // If the current token should be an actual argument then validate it, otherwise it should be a ',' token.\n if (shouldBeArgumentToken) {\n // Get the argument definition.\n const argumentDefinition = getArgumentDefinition(token, stringArgumentPlaceholders);\n\n // This is a valid argument!\n argumentList.push(argumentDefinition);\n } else {\n // The current token should be a ',' token.\n if (token !== \",\") {\n throw new Error(`invalid argument list, expected ',' or ']' but got '${token}'`);\n }\n }\n });\n\n // The arguments list should terminate with a ']' or ')' token, depending on the opener.\n popAndCheck(tokens, closingToken);\n\n // Return the arguments.\n return argumentList;\n}\n\n/**\n * Gets an argument value definition.\n * @param token The argument token.\n * @param stringArgumentPlaceholders The mapping of string literal node argument placeholders to original values.\n * @returns An argument value definition.\n */\nfunction getArgumentDefinition(token: string, stringArgumentPlaceholders: StringLiteralPlaceholders): AnyArgument {\n // Check whether the token represents a null value.\n if (token === \"null\") {\n return {\n value: null,\n type: \"null\"\n } as NullArgument;\n }\n\n // Check whether the token represents a boolean value.\n if (token === \"true\" || token === \"false\") {\n return {\n value: token === \"true\",\n type: \"boolean\"\n } as BooleanArgument;\n }\n\n // Check whether the token represents a number value.\n // TODO: Relies on broken isNaN - see MDN.\n // if (!Number.isNaN(token)) {\n if (!isNaN(token as any)) {\n return {\n value: parseFloat(token),\n isInteger: parseFloat(token) === parseInt(token, 10),\n type: \"number\"\n } as NumberArgument;\n }\n\n // Check whether the token is a placeholder (e.g. @@0@@) representing a string literal.\n if (token.match(/^@@\\d+@@$/g)) {\n return {\n value: stringArgumentPlaceholders[token].replace('\\\\\"', '\"'),\n type: \"string\"\n } as StringPlaceholderArgument;\n }\n\n // The only remaining option is that the argument value is an identifier.\n return {\n value: token,\n type: \"identifier\"\n } as IdentifierArgument;\n}\n", "import { NodeAttributeDefinition } from \"../BehaviourTreeDefinition\";\nimport { parseArgumentTokens } from \"./MDSLNodeArgumentParser\";\nimport { StringLiteralPlaceholders } from \"./MDSLUtilities\";\n\n/**\n * A type defining the attribute definitions of a node.\n */\ntype NodeAttributes = {\n while?: NodeAttributeDefinition;\n until?: NodeAttributeDefinition;\n entry?: NodeAttributeDefinition;\n exit?: NodeAttributeDefinition;\n step?: NodeAttributeDefinition;\n};\n\n/**\n * Parse any node attribute definitions from the specified tokens array.\n * @param tokens The array of remaining tokens.\n * @param stringArgumentPlaceholders The mapping of string literal node argument placeholders to original values.\n * @returns An object of attribute definitions defined by any directly following tokens.\n */\nexport function parseAttributeTokens(\n tokens: string[],\n stringArgumentPlaceholders: StringLiteralPlaceholders\n): NodeAttributes {\n const nodeAttributeNames: (keyof NodeAttributes)[] = [\"while\", \"until\", \"entry\", \"exit\", \"step\"];\n\n // Create an object to hold any attributes found.\n const attributes: NodeAttributes = {};\n\n // Try to get the name of the attribute for the next token.\n let nextAttributeName = tokens[0]?.toLowerCase() as keyof NodeAttributes;\n\n // Pull attribute tokens as well as their arguments off of the tokens stack until we have no more.\n while (nodeAttributeNames.includes(nextAttributeName)) {\n // Check to make sure that we have not already created an attribute definition of this type.\n if (attributes[nextAttributeName]) {\n throw new Error(`duplicate attribute '${tokens[0].toUpperCase()}' found for node`);\n }\n\n // Remove the attribute name token from the array of tokens.\n tokens.shift();\n\n // Grab the attribute arguments, assuming the first to be an identifier.\n const [attributeCallIdentifier, ...attributeArguments] = parseArgumentTokens(\n tokens,\n stringArgumentPlaceholders\n );\n\n // The first attribute argument has to be an identifer, this will reference an agent function.\n if (attributeCallIdentifier?.type !== \"identifier\") {\n throw new Error(\"expected agent function or registered function name identifier argument for attribute\");\n }\n\n // Any attribute arguments (other than the expected call identifier) must have a type of string, number, boolean or null.\n attributeArguments\n .filter((arg) => arg.type === \"identifier\")\n .forEach((arg) => {\n throw new Error(\n `invalid attribute argument value '${arg.value}', must be string, number, boolean or null`\n );\n });\n\n // Create the attribute definition and add it to the object of attribute definitions found.\n attributes[nextAttributeName] = {\n call: attributeCallIdentifier.value,\n args: attributeArguments.map(({ value }) => value)\n };\n\n // Try to get the next attribute name token, as there could be multiple.\n nextAttributeName = tokens[0]?.toLowerCase() as keyof NodeAttributes;\n }\n\n return attributes;\n}\n", "import {\n ActionNodeDefinition,\n AnyChildNodeDefinition,\n AnyNodeDefinition,\n BranchNodeDefinition,\n ConditionNodeDefinition,\n FailNodeDefinition,\n FlipNodeDefinition,\n LottoNodeDefinition,\n ParallelNodeDefinition,\n RepeatNodeDefinition,\n RetryNodeDefinition,\n RootNodeDefinition,\n SelectorNodeDefinition,\n SequenceNodeDefinition,\n SucceedNodeDefinition,\n WaitNodeDefinition\n} from \"../BehaviourTreeDefinition\";\nimport {\n isCompositeNode,\n isDecoratorNode,\n isLeafNode,\n isNullOrUndefined,\n isRootNode\n} from \"../BehaviourTreeDefinitionUtilities\";\nimport { parseArgumentTokens } from \"./MDSLNodeArgumentParser\";\nimport { parseAttributeTokens } from \"./MDSLNodeAttributeParser\";\nimport {\n StringLiteralPlaceholders,\n parseTokensFromDefinition,\n popAndCheck,\n substituteStringLiterals\n} from \"./MDSLUtilities\";\n\n/**\n * Convert the MDSL tree definition string into an equivalent JSON definition.\n * @param definition The tree definition string as MDSL.\n * @returns The root node JSON definitions.\n */\nexport function convertMDSLToJSON(definition: string): RootNodeDefinition[] {\n // Swap out any node/attribute argument string literals with a placeholder and get a mapping of placeholders to original values as well as the processed definition.\n const { placeholders, processedDefinition } = substituteStringLiterals(definition);\n\n // Parse our definition definition string into an array of raw tokens.\n const tokens = parseTokensFromDefinition(processedDefinition);\n\n return convertTokensToJSONDefinition(tokens, placeholders);\n}\n\n/**\n * Converts the specified tree definition tokens into a JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The root node JSON definitions.\n */\nfunction convertTokensToJSONDefinition(\n tokens: string[],\n stringLiteralPlaceholders: StringLiteralPlaceholders\n): RootNodeDefinition[] {\n // There must be at least 3 tokens for the tree definition to be valid. 'ROOT', '{' and '}'.\n if (tokens.length < 3) {\n throw new Error(\"invalid token count\");\n }\n\n // We should have a matching number of '{' and '}' tokens. If not, then there are scopes that have not been properly closed.\n if (tokens.filter((token) => token === \"{\").length !== tokens.filter((token) => token === \"}\").length) {\n throw new Error(\"scope character mismatch\");\n }\n\n // Create an array of tree stack arrays where root nodes will always be at the botton and the current composite/decorator node at the top.\n // There should be an element in this array for every root node defined and every element should be an array with a root note as the first element.\n // E.g. A definition with two root nodes defined:\n // [\n // [root, lotto, sequence],\n // [root, selector]\n // ]\n const treeStacks: [Partial, ...Partial[]][] = [];\n\n // Create an array of all root node definitions that we create.\n const rootNodes: Partial[] = [];\n\n // A helper function used to push node definitions onto the tree stack.\n const pushNode = (node: AnyNodeDefinition) => {\n // If the node is a root node then we need to create a new tree stack array with the root node at the root.\n if (isRootNode(node)) {\n // We need to double-check that this root node is not the child of another node.\n // We can do this by checking whether the top tree stack is not empty (contains an existing node)\n if (treeStacks[treeStacks.length - 1]?.length) {\n throw new Error(\"a root node cannot be the child of another node\");\n }\n\n // Add the root node definition to our array of all parsed root node definitions.\n rootNodes.push(node);\n\n // Add the root node definition to the root of a new tree stack.\n treeStacks.push([node]);\n\n return;\n }\n\n // All non-root nodes should be pushed after their root nodes so handle cases\n // where we may not have any tree stacks or our top-most tree stack is empty.\n if (!treeStacks.length || !treeStacks[treeStacks.length - 1].length) {\n throw new Error(\"expected root node at base of definition\");\n }\n\n // Get the current tree stack that we are populating.\n const topTreeStack = treeStacks[treeStacks.length - 1];\n\n // Get the top-most node in the current tree stack, this will be a composite/decorator node\n // for which we will populate its children array if composite or setting its child if a decorator.\n const topTreeStackTopNode = topTreeStack[topTreeStack.length - 1] as AnyNodeDefinition;\n\n // If the top-most node in the current root stack is a composite or decorator\n // node then the current node should be added as a child of the top-most node.\n if (isCompositeNode(topTreeStackTopNode)) {\n topTreeStackTopNode.children = topTreeStackTopNode.children || [];\n topTreeStackTopNode.children.push(node);\n } else if (isDecoratorNode(topTreeStackTopNode)) {\n // If the top node already has a child node set then throw an error as a decorator should only have a single child.\n if (topTreeStackTopNode.child) {\n throw new Error(\"a decorator node must only have a single child node\");\n }\n\n topTreeStackTopNode.child = node;\n }\n\n // If the node we are adding is also a composite or decorator node, then we should push it\n // onto the current tree stack, as subsequent nodes will be added as its child/children.\n if (!isLeafNode(node)) {\n topTreeStack.push(node);\n }\n };\n\n // A helper function used to pop the top-most node definition off of the tree stack and return it.\n const popNode = (): AnyNodeDefinition | null => {\n let poppedNode: AnyNodeDefinition | null = null;\n\n // Get the current tree stack that we are populating.\n const topTreeStack = treeStacks[treeStacks.length - 1];\n\n // Pop the top-most node in the current tree stack if there is one.\n if (topTreeStack.length) {\n poppedNode = topTreeStack.pop() as AnyNodeDefinition;\n }\n\n // We don't want any empty tree stacks in our stack of tree stacks.\n if (!topTreeStack.length) {\n treeStacks.pop();\n }\n\n return poppedNode;\n };\n\n // We should keep processing the raw tokens until we run out of them.\n while (tokens.length) {\n // Grab the next token.\n const token = tokens.shift()!;\n\n // How we create the next node depends on the current raw token value.\n switch (token.toUpperCase()) {\n case \"ROOT\": {\n pushNode(createRootNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"SUCCEED\": {\n pushNode(createSucceedNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"FAIL\": {\n pushNode(createFailNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"FLIP\": {\n pushNode(createFlipNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"REPEAT\": {\n pushNode(createRepeatNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"RETRY\": {\n pushNode(createRetryNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"SEQUENCE\": {\n pushNode(createSequenceNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"SELECTOR\": {\n pushNode(createSelectorNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"PARALLEL\": {\n pushNode(createParallelNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"LOTTO\": {\n pushNode(createLottoNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"ACTION\": {\n pushNode(createActionNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"CONDITION\": {\n pushNode(createConditionNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"WAIT\": {\n pushNode(createWaitNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"BRANCH\": {\n pushNode(createBranchNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"}\": {\n // The '}' character closes the current scope and means that we have to pop a node off of the current stack.\n const poppedNode = popNode();\n\n // Now that we have a node definition we can carry out any validation that may require the node to be fully populated.\n if (poppedNode) {\n validatePoppedNode(poppedNode);\n }\n\n break;\n }\n\n default: {\n throw new Error(`unexpected token: ${token}`);\n }\n }\n }\n\n return rootNodes as RootNodeDefinition[];\n}\n\n/**\n * Creates a root node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The root node JSON definition.\n */\nfunction createRootNode(tokens: string[], stringLiteralPlaceholders: StringLiteralPlaceholders): RootNodeDefinition {\n // Create the root node definition.\n let node = {\n type: \"root\"\n } as Partial;\n\n // Parse any node arguments, we should only have one if any which will be an identifier argument for the root identifier.\n const nodeArguments = parseArgumentTokens(tokens, stringLiteralPlaceholders);\n\n // Check whether any node arguments were defined.\n if (nodeArguments.length) {\n // We should only have one argument, if any, which will be an identifier argument for the root identifier.\n if (nodeArguments.length === 1 && nodeArguments[0].type === \"identifier\") {\n // The root node identifier will be the first and only node argument value.\n node.id = nodeArguments[0].value as string;\n } else {\n throw new Error(\"expected single root name argument\");\n }\n }\n\n // Grab any node attribute definitions and spread them into the node definition.\n node = { ...node, ...parseAttributeTokens(tokens, stringLiteralPlaceholders) };\n\n // This is a decorator node, so we expect an opening '{'.\n popAndCheck(tokens, \"{\");\n\n // Return the root node definition.\n return node as RootNodeDefinition;\n}\n\n/**\n * Creates a succeed node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The succeed node JSON definition.\n */\nfunction createSucceedNode(\n tokens: string[],\n stringLiteralPlaceholders: StringLiteralPlaceholders\n): SucceedNodeDefinition {\n const node = {\n type: \"succeed\",\n ...parseAttributeTokens(tokens, stringLiteralPlaceholders)\n } as SucceedNodeDefinition;\n\n // This is a decorator node, so we expect an opening '{'.\n popAndCheck(tokens, \"{\");\n\n // Return the succeed node definition.\n return node;\n}\n\n/**\n * Creates a fail node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The fail node JSON definition.\n */\nfunction createFailNode(tokens: string[], stringLiteralPlaceholders: StringLiteralPlaceholders): FailNodeDefinition {\n const node = {\n type: \"fail\",\n ...parseAttributeTokens(tokens, stringLiteralPlaceholders)\n } as FailNodeDefinition;\n\n // This is a decorator node, so we expect an opening '{'.\n popAndCheck(tokens, \"{\");\n\n // Return the fail node definition.\n return node;\n}\n\n/**\n * Creates a flip node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The flip node JSON definition.\n */\nfunction createFlipNode(tokens: string[], stringLiteralPlaceholders: StringLiteralPlaceholders): FlipNodeDefinition {\n const node = {\n type: \"flip\",\n ...parseAttributeTokens(tokens, stringLiteralPlaceholders)\n } as FlipNodeDefinition;\n\n // This is a decorator node, so we expect an opening '{'.\n popAndCheck(tokens, \"{\");\n\n // Return the flip node definition.\n return node;\n}\n\n/**\n * Creates a repeat node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The repeat node JSON definition.\n */\nfunction createRepeatNode(\n tokens: string[],\n stringLiteralPlaceholders: StringLiteralPlaceholders\n): RepeatNodeDefinition {\n let node = { type: \"repeat\" } as RepeatNodeDefinition;\n\n // Get the node arguments.\n const nodeArguments = parseArgumentTokens(tokens, stringLiteralPlaceholders);\n\n // The arguments of a repeat node are optional. We may have:\n // - No node arguments, in which case the repeat note will iterate indefinitely.\n // - One node argument which will be the explicit number of iterations to make.\n // - Two node arguments which define the min and max iteration bounds from which a random iteration count will be picked.\n if (nodeArguments.length) {\n // All repeat node arguments MUST be of type number and must be integer.\n nodeArguments\n .filter((arg) => arg.type !== \"number\" || !arg.isInteger)\n .forEach(() => {\n throw new Error(`repeat node iteration counts must be integer values`);\n });\n\n // We should have got one or two iteration counts.\n if (nodeArguments.length === 1) {\n // A static iteration count was defined.\n node.iterations = nodeArguments[0].value as number;\n\n // A repeat node must have a positive number of iterations if defined.\n if (node.iterations < 0) {\n throw new Error(\"a repeat node must have a positive number of iterations if defined\");\n }\n } else if (nodeArguments.length === 2) {\n // A minimum and maximum iteration count was defined.\n node.iterations = [nodeArguments[0].value as number, nodeArguments[1].value as number];\n\n // A repeat node must have a positive min and max iteration count if they are defined.\n if (node.iterations[0] < 0 || node.iterations[1] < 0) {\n throw new Error(\"a repeat node must have a positive minimum and maximum iteration count if defined\");\n }\n\n // A repeat node must not have an minimum iteration count that exceeds the maximum iteration count.\n if (node.iterations[0] > node.iterations[1]) {\n throw new Error(\n \"a repeat node must not have a minimum iteration count that exceeds the maximum iteration count\"\n );\n }\n } else {\n // An incorrect number of iteration counts was defined.\n throw new Error(\"invalid number of repeat node iteration count arguments defined\");\n }\n }\n\n // Grab any node attribute definitions and spread them into the node definition.\n node = { ...node, ...parseAttributeTokens(tokens, stringLiteralPlaceholders) };\n\n // This is a decorator node, so we expect an opening '{'.\n popAndCheck(tokens, \"{\");\n\n // Return the repeat node definition.\n return node;\n}\n\n/**\n * Creates a retry node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The retry node JSON definition.\n */\nfunction createRetryNode(tokens: string[], stringLiteralPlaceholders: StringLiteralPlaceholders): RetryNodeDefinition {\n let node = { type: \"retry\" } as RetryNodeDefinition;\n\n // Get the node arguments.\n const nodeArguments = parseArgumentTokens(tokens, stringLiteralPlaceholders);\n\n // The arguments of a retry node are optional. We may have:\n // - No node arguments, in which case the retry note will attempt indefinitely.\n // - One node argument which will be the explicit number of attempts to make.\n // - Two node arguments which define the min and max attempt bounds from which a random attempt count will be picked.\n if (nodeArguments.length) {\n // All retry node arguments MUST be of type number and must be integer.\n nodeArguments\n .filter((arg) => arg.type !== \"number\" || !arg.isInteger)\n .forEach(() => {\n throw new Error(`retry node attempt counts must be integer values`);\n });\n\n // We should have got one or two attempt counts.\n if (nodeArguments.length === 1) {\n // A static attempt count was defined.\n node.attempts = nodeArguments[0].value as number;\n\n // A retry node must have a positive number of attempts if defined.\n if (node.attempts < 0) {\n throw new Error(\"a retry node must have a positive number of attempts if defined\");\n }\n } else if (nodeArguments.length === 2) {\n // A minimum and maximum attempt count was defined.\n node.attempts = [nodeArguments[0].value as number, nodeArguments[1].value as number];\n\n // A retry node must have a positive min and max attempts count if they are defined.\n if (node.attempts[0] < 0 || node.attempts[1] < 0) {\n throw new Error(\"a retry node must have a positive minimum and maximum attempt count if defined\");\n }\n\n // A retry node must not have a minimum attempt count that exceeds the maximum attempt count.\n if (node.attempts[0] > node.attempts[1]) {\n throw new Error(\n \"a retry node must not have a minimum attempt count that exceeds the maximum attempt count\"\n );\n }\n } else {\n // An incorrect number of attempt counts was defined.\n throw new Error(\"invalid number of retry node attempt count arguments defined\");\n }\n }\n\n // Grab any node attribute definitions and spread them into the node definition.\n node = { ...node, ...parseAttributeTokens(tokens, stringLiteralPlaceholders) };\n\n // This is a decorator node, so we expect an opening '{'.\n popAndCheck(tokens, \"{\");\n\n // Return the retry node definition.\n return node;\n}\n\n/**\n * Creates a sequence node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The sequence node JSON definition.\n */\nfunction createSequenceNode(\n tokens: string[],\n stringLiteralPlaceholders: StringLiteralPlaceholders\n): SequenceNodeDefinition {\n const node = {\n type: \"sequence\",\n ...parseAttributeTokens(tokens, stringLiteralPlaceholders)\n } as SequenceNodeDefinition;\n\n // This is a composite node, so we expect an opening '{'.\n popAndCheck(tokens, \"{\");\n\n // Return the sequence node definition.\n return node;\n}\n\n/**\n * Creates a selector node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The selector node JSON definition.\n */\nfunction createSelectorNode(\n tokens: string[],\n stringLiteralPlaceholders: StringLiteralPlaceholders\n): SelectorNodeDefinition {\n const node = {\n type: \"selector\",\n ...parseAttributeTokens(tokens, stringLiteralPlaceholders)\n } as SelectorNodeDefinition;\n\n // This is a composite node, so we expect an opening '{'.\n popAndCheck(tokens, \"{\");\n\n // Return the selector node definition.\n return node;\n}\n\n/**\n * Creates a parallel node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The parallel node JSON definition.\n */\nfunction createParallelNode(\n tokens: string[],\n stringLiteralPlaceholders: StringLiteralPlaceholders\n): ParallelNodeDefinition {\n const node = {\n type: \"parallel\",\n ...parseAttributeTokens(tokens, stringLiteralPlaceholders)\n } as ParallelNodeDefinition;\n\n // This is a composite node, so we expect an opening '{'.\n popAndCheck(tokens, \"{\");\n\n // Return the parallel node definition.\n return node;\n}\n\n/**\n * Creates a lotto node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The lotto node JSON definition.\n */\nfunction createLottoNode(tokens: string[], stringLiteralPlaceholders: StringLiteralPlaceholders): LottoNodeDefinition {\n // If any node arguments have been defined then they must be our weights.\n const nodeArguments = parseArgumentTokens(tokens, stringLiteralPlaceholders);\n\n // All lotto node arguments MUST be of type number and must be positive integers.\n nodeArguments\n .filter((arg) => arg.type !== \"number\" || !arg.isInteger || arg.value < 0)\n .forEach(() => {\n throw new Error(`lotto node weight arguments must be positive integer values`);\n });\n\n const node = {\n type: \"lotto\",\n ...parseAttributeTokens(tokens, stringLiteralPlaceholders)\n } as LottoNodeDefinition;\n\n // Apply the weights if any were defined.\n if (nodeArguments.length) {\n node.weights = nodeArguments.map(({ value }) => value) as number[];\n }\n\n // This is a composite node, so we expect an opening '{'.\n popAndCheck(tokens, \"{\");\n\n // Return the lotto node definition.\n return node;\n}\n\n/**\n * Creates an action node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The action node JSON definition.\n */\nfunction createActionNode(\n tokens: string[],\n stringLiteralPlaceholders: StringLiteralPlaceholders\n): ActionNodeDefinition {\n // Parse any node arguments, we should have at least one which will be an identifier argument for the action name\n // and agent function to invoke for the action, all other arguments are to be passed as arguments to that function.\n const [actionNameIdentifier, ...agentFunctionArgs] = parseArgumentTokens(tokens, stringLiteralPlaceholders);\n\n // Our first argument MUST be defined and be an identifier as we require an action name argument.\n if (actionNameIdentifier?.type !== \"identifier\") {\n throw new Error(\"expected action name identifier argument\");\n }\n\n // Only the first argument should have been an identifier, all agent function arguments must be string, number, boolean or null.\n agentFunctionArgs\n .filter((arg) => arg.type === \"identifier\")\n .forEach((arg) => {\n throw new Error(\n `invalid action node argument value '${arg.value}', must be string, number, boolean or null`\n );\n });\n\n // Return the action node definition.\n return {\n type: \"action\",\n call: actionNameIdentifier.value,\n args: agentFunctionArgs.map(({ value }) => value),\n ...parseAttributeTokens(tokens, stringLiteralPlaceholders)\n };\n}\n\n/**\n * Creates a condition node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The condition node JSON definition.\n */\nfunction createConditionNode(\n tokens: string[],\n stringLiteralPlaceholders: StringLiteralPlaceholders\n): ConditionNodeDefinition {\n // Parse any node arguments, we should have at least one which will be an identifier argument for the condition name\n // and agent function to invoke for the condition, all other arguments are to be passed as arguments to that function.\n const [conditionNameIdentifier, ...agentFunctionArgs] = parseArgumentTokens(tokens, stringLiteralPlaceholders);\n\n // Our first argument MUST be defined and be an identifier as we require a condition name argument.\n if (conditionNameIdentifier?.type !== \"identifier\") {\n throw new Error(\"expected condition name identifier argument\");\n }\n\n // Only the first argument should have been an identifier, all agent function arguments must be string, number, boolean or null.\n agentFunctionArgs\n .filter((arg) => arg.type === \"identifier\")\n .forEach((arg) => {\n throw new Error(\n `invalid condition node argument value '${arg.value}', must be string, number, boolean or null`\n );\n });\n\n // Return the condition node definition.\n return {\n type: \"condition\",\n call: conditionNameIdentifier.value,\n args: agentFunctionArgs.map(({ value }) => value),\n ...parseAttributeTokens(tokens, stringLiteralPlaceholders)\n };\n}\n\n/**\n * Creates a wait node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The wait node JSON definition.\n */\nfunction createWaitNode(tokens: string[], stringLiteralPlaceholders: StringLiteralPlaceholders): WaitNodeDefinition {\n let node = { type: \"wait\" } as WaitNodeDefinition;\n\n // Get the node arguments.\n const nodeArguments = parseArgumentTokens(tokens, stringLiteralPlaceholders);\n\n // The arguments of a wait node are optional. We may have:\n // - No node arguments, in which case the wait will be indefinite until it is aborted.\n // - One node argument which will be the explicit duration of the wait.\n // - Two node arguments which define the min and max duration bounds from which a random duration will be picked.\n if (nodeArguments.length) {\n // All wait node arguments MUST be of type number and must be integer.\n nodeArguments\n .filter((arg) => arg.type !== \"number\" || !arg.isInteger)\n .forEach(() => {\n throw new Error(`wait node durations must be integer values`);\n });\n\n // We may have:\n // - One node argument which will be the explicit duration of the wait.\n // - Two node arguments which define the min and max duration bounds from which a random duration will be picked.\n // - Too many arguments, which is not valid.\n if (nodeArguments.length === 1) {\n // An explicit duration was defined.\n node.duration = nodeArguments[0].value as number;\n\n // If an explict duration was defined then it must be a positive number.\n if (node.duration < 0) {\n throw new Error(\"a wait node must have a positive duration\");\n }\n } else if (nodeArguments.length === 2) {\n // Min and max duration bounds were defined from which a random duration will be picked.\n node.duration = [nodeArguments[0].value as number, nodeArguments[1].value as number];\n\n // A wait node must have a positive min and max duration.\n if (node.duration[0] < 0 || node.duration[1] < 0) {\n throw new Error(\"a wait node must have a positive minimum and maximum duration\");\n }\n\n // A wait node must not have a minimum duration that exceeds the maximum duration.\n if (node.duration[0] > node.duration[1]) {\n throw new Error(\"a wait node must not have a minimum duration that exceeds the maximum duration\");\n }\n } else if (nodeArguments.length > 2) {\n // An incorrect number of duration arguments were defined.\n throw new Error(\"invalid number of wait node duration arguments defined\");\n }\n }\n\n // Return the wait node definition.\n return { ...node, ...parseAttributeTokens(tokens, stringLiteralPlaceholders) };\n}\n\n/**\n * Creates a branch node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The branch node JSON definition.\n */\nfunction createBranchNode(\n tokens: string[],\n stringLiteralPlaceholders: StringLiteralPlaceholders\n): BranchNodeDefinition {\n // Parse any node arguments, we should have one which will be an identifier argument for the root ref.\n const nodeArguments = parseArgumentTokens(tokens, stringLiteralPlaceholders);\n\n // We should have only a single identifer argument for a branch node, which is the root ref.\n if (nodeArguments.length !== 1 || nodeArguments[0].type !== \"identifier\") {\n throw new Error(\"expected single branch name argument\");\n }\n\n // Return the branch node definition.\n return { type: \"branch\", ref: nodeArguments[0].value };\n}\n\n/**\n * Validate a fully-populated node definition that was popped off of the tree stack.\n * @param definition The popped node to validate.\n */\nfunction validatePoppedNode(definition: AnyNodeDefinition): void {\n // Decorators MUST have a child defined.\n if (isDecoratorNode(definition) && isNullOrUndefined(definition.child)) {\n throw new Error(`a ${definition.type} node must have a single child node defined`);\n }\n\n // Composites MUST have at least one child defined.\n if (isCompositeNode(definition) && !definition.children?.length) {\n throw new Error(`a ${definition.type} node must have at least a single child node defined`);\n }\n\n // We need to make sure that lotto nodes that have weights defined have a number of weights matching the number of child nodes.\n if (definition.type === \"lotto\") {\n // Check whether a 'weights' property has been defined, if it has we expect it to be an array of weights.\n if (typeof definition.weights !== \"undefined\") {\n // Check that the weights property is an array of positive integers with an element for each child node element.\n if (definition.weights.length !== definition.children.length) {\n throw new Error(\n \"expected a number of weight arguments matching the number of child nodes for lotto node\"\n );\n }\n }\n }\n}\n", "import { RootNodeDefinition } from \"./BehaviourTreeDefinition\";\nimport { flattenDefinition, isBranchNode, isInteger } from \"./BehaviourTreeDefinitionUtilities\";\nimport { convertMDSLToJSON } from \"./mdsl/MDSLDefinitionParser\";\n\n/**\n * An object representing the result of validating a tree definition.\n */\nexport type DefinitionValidationResult = {\n /**\n * A flag defining whether validation succeeded.\n */\n succeeded: boolean;\n /**\n * A string containing the error message if validation did not succeed.\n */\n errorMessage?: string;\n /**\n * The definition as json if the validation was successful, or undefined if validation did not succeed.\n */\n json?: RootNodeDefinition[];\n};\n\n/**\n * Validates the specified behaviour tree definition in the form of JSON or MDSL, not taking any globally registered subtrees into consideration.\n * @param definition The behaviour tree definition in the form of JSON or MDSL.\n * @returns An object representing the result of validating the given tree definition.\n */\nexport function validateDefinition(definition: any): DefinitionValidationResult {\n // The definition must be defined.\n if (definition === null || typeof definition === \"undefined\") {\n return createValidationFailureResult(\"definition is null or undefined\");\n }\n\n // We are expecting a definition in one of three different forms:\n // - A string which we will assume is MDSL and we will parse this to JSON before validation.\n // - An array which we will assume is an array of root node definitions with at least one being the primary root node (no 'id' property)\n // - An object which we will assume is the primary root node and should not have an 'id' property.\n if (typeof definition === \"string\") {\n // The definition is a string which we can assume is MDSL, so attempt to validate it.\n return validateMDSLDefinition(definition);\n } else if (typeof definition === \"object\") {\n // The definition will either be an array (of root node definitions) or an object (the single primary root node definition).\n return validateJSONDefinition(definition);\n } else {\n return createValidationFailureResult(`unexpected definition type of '${typeof definition}'`);\n }\n}\n\n/**\n * Validates the specified behaviour tree definition in the form of MDSL.\n * @param definition The behaviour tree definition in the form of MDSL.\n * @returns An object representing the result of validating the given tree definition.\n */\nfunction validateMDSLDefinition(definition: string): DefinitionValidationResult {\n let rootNodeDefinitions;\n\n // The first thing the we need to do is to attempt to convert our MDSL into JSON.\n try {\n // The definition is a string which we can assume is MDSL, so attempt to parse it to a JSON definition in the form of an array of root node definitions.\n rootNodeDefinitions = convertMDSLToJSON(definition);\n } catch (exception) {\n // We failed to parse the JSON from the MDSL, this is likely to be the result of it not being a valid MDSL string.\n return createValidationFailureResult((exception as Error).message);\n }\n\n // Unpack all of the root node definitions into arrays of main ('id' defined) and sub ('id' not defined) root node definitions.\n const mainRootNodeDefinitions = rootNodeDefinitions.filter(({ id }) => typeof id === \"undefined\");\n const subRootNodeDefinitions = rootNodeDefinitions.filter(({ id }) => typeof id === \"string\" && id.length > 0);\n\n // We should ALWAYS have exactly one root node definition without an 'id' property defined, which is out main root node definition.\n if (mainRootNodeDefinitions.length !== 1) {\n return createValidationFailureResult(\n \"expected single unnamed root node at base of definition to act as main root\"\n );\n }\n\n // We should never have duplicate 'id' properties across our sub root node definitions.\n const subRootNodeIdenitifers: string[] = [];\n for (const { id } of subRootNodeDefinitions) {\n // Have we already come across this 'id' property value?\n if (subRootNodeIdenitifers.includes(id!)) {\n return createValidationFailureResult(`multiple root nodes found with duplicate name '${id}'`);\n }\n\n subRootNodeIdenitifers.push(id!);\n }\n\n try {\n // Validate our branch -> subtree links and check for any circular dependencies, we don't care about checking for broken subtree links here.\n validateBranchSubtreeLinks(rootNodeDefinitions, false);\n } catch (exception) {\n return createValidationFailureResult((exception as Error).message);\n }\n\n // Our definition was valid!\n return {\n succeeded: true,\n json: rootNodeDefinitions\n };\n}\n\n/**\n * Validates the specified behaviour tree definition in the form of JSON.\n * @param definition The behaviour tree definition in the form of JSON.\n * @returns An object representing the result of validating the given tree definition.\n */\nexport function validateJSONDefinition(\n definition: RootNodeDefinition | RootNodeDefinition[]\n): DefinitionValidationResult {\n // The definition will either be an array (of root node definitions) or an object (the single primary root node definition).\n const rootNodeDefinitions = Array.isArray(definition) ? definition : [definition];\n\n // Iterate over our array of root nodes and call validateNode for each, passing an initial depth of 0, wrapped in a try catch to handle validation failures.\n try {\n rootNodeDefinitions.forEach((rootNodeDefinition) => validateNode(rootNodeDefinition, 0));\n } catch (error) {\n // Handle cases where we have caught a thrown Error and return a failure result with the error message.\n if (error instanceof Error) {\n return createValidationFailureResult(error.message);\n }\n\n // No idea what happened here!\n return createValidationFailureResult(`unexpected error: ${error}`);\n }\n\n // Unpack all of the root node definitions into arrays of main ('id' defined) and sub ('id' not defined) root node definitions.\n const mainRootNodeDefinitions = rootNodeDefinitions.filter(({ id }) => typeof id === \"undefined\");\n const subRootNodeDefinitions = rootNodeDefinitions.filter(({ id }) => typeof id === \"string\" && id.length > 0);\n\n // We should ALWAYS have exactly one root node definition without an 'id' property defined, which is out main root node definition.\n if (mainRootNodeDefinitions.length !== 1) {\n return createValidationFailureResult(\n \"expected single root node without 'id' property defined to act as main root\"\n );\n }\n\n // We should never have duplicate 'id' properties across our sub root node definitions.\n const subRootNodeIdenitifers: string[] = [];\n for (const { id } of subRootNodeDefinitions) {\n // Have we already come across this 'id' property value?\n if (subRootNodeIdenitifers.includes(id!)) {\n return createValidationFailureResult(\n `multiple root nodes found with duplicate 'id' property value of '${id}'`\n );\n }\n\n subRootNodeIdenitifers.push(id!);\n }\n\n try {\n // Validate our branch -> subtree links and check for any circular dependencies, we don't care about checking for broken subtree links here.\n validateBranchSubtreeLinks(rootNodeDefinitions, false);\n } catch (exception) {\n return createValidationFailureResult((exception as Error).message);\n }\n\n // Our definition was valid!\n return {\n succeeded: true,\n json: rootNodeDefinitions\n };\n}\n\n/**\n * Validates the branch -> subtree links across all provided root node definitions.\n * This will not consider branch nodes that reference any globally registered subtrees unless includesGlobalSubtrees\n * is set to true, in which case we will also verify that there are no broken branch -> subtree links.\n * @param rootNodeDefinitions The array of root node definitions.\n * @param includesGlobalSubtrees A flag defining whether the array includes all global subtree root node definitions.\n */\nexport function validateBranchSubtreeLinks(rootNodeDefinitions: RootNodeDefinition[], includesGlobalSubtrees: boolean) {\n // Create a mapping of root node identifiers to other root nodes that they reference via branch nodes.\n // Below is an example of a mapping that includes a circular dependency (root => a => b => c => a)\n // [{ refs: [\"a\", \"b\"] }, { id: \"a\", refs: [\"b\"] }, { id: \"b\", refs: [\"c\"] }, { id: \"c\", refs: [\"a\"] }]\n const rootNodeMappings: { id: string | undefined; refs: string[] }[] = rootNodeDefinitions.map(\n (rootNodeDefinition) => ({\n id: rootNodeDefinition.id,\n refs: flattenDefinition(rootNodeDefinition)\n .filter(isBranchNode)\n .map(({ ref }) => ref)\n })\n );\n\n // A recursive function to walk through the mappings, keeping track of which root nodes we have visited in the form of a path of root node identifiers.\n const followRefs = (mapping: { id: string | undefined; refs: string[] }, path: (string | undefined)[] = []) => {\n // Have we found a circular dependency?\n if (path.includes(mapping.id)) {\n // We found a circular dependency! Get the bad path of root node identifiers.\n const badPath = [...path, mapping.id];\n\n // Create the formatted path value. [undefined, \"a\", \"b\", \"c\", \"a\"] would be formatted as \"a -> b -> c -> a\".\n const badPathFormatted = badPath.filter((element) => !!element).join(\" => \");\n\n // No need to continue, we found a circular dependency.\n throw new Error(`circular dependency found in branch node references: ${badPathFormatted}`);\n }\n\n for (const ref of mapping.refs) {\n // Find the mapping for the root node with an identifer matching the current ref.\n const subMapping = rootNodeMappings.find(({ id }) => id === ref);\n\n // We may not have a mapping for this ref, which is normal when we aren't considering all globally registered subtrees.\n if (subMapping) {\n followRefs(subMapping, [...path, mapping.id]);\n } else if (includesGlobalSubtrees) {\n // We found a reference to a root node that doesn't exist, which is a problem seeing as the root node definitons includes all globally registered subtrees.\n throw new Error(\n mapping.id\n ? `subtree '${mapping.id}' has branch node that references root node '${ref}' which has not been defined`\n : `primary tree has branch node that references root node '${ref}' which has not been defined`\n );\n }\n }\n };\n\n // Start looking for circular dependencies and broken references from the primary root node definition.\n followRefs(rootNodeMappings.find((mapping) => typeof mapping.id === \"undefined\")!);\n}\n\n/**\n * Validate an object that we expect to be a node definition.\n * @param definition An object that we expect to be a node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateNode(definition: any, depth: number): void {\n // Every node must be valid object and have a non-empty 'type' string property.\n if (typeof definition !== \"object\" || typeof definition.type !== \"string\" || definition.type.length === 0) {\n throw new Error(\n `node definition is not an object or 'type' property is not a non-empty string at depth '${depth}'`\n );\n }\n\n // If this node is at the very base of the definition then it MUST be a root node.\n if (depth === 0 && definition.type !== \"root\") {\n throw new Error(`expected root node at base of definition but got node of type '${definition.type}'`);\n }\n\n // How we validate this node definition will depend on its type.\n switch (definition.type) {\n case \"action\":\n validateActionNode(definition, depth);\n break;\n\n case \"condition\":\n validateConditionNode(definition, depth);\n break;\n\n case \"wait\":\n validateWaitNode(definition, depth);\n break;\n\n case \"branch\":\n validateBranchNode(definition, depth);\n break;\n\n case \"root\":\n validateRootNode(definition, depth);\n break;\n\n case \"succeed\":\n validateSucceedNode(definition, depth);\n break;\n\n case \"fail\":\n validateFailNode(definition, depth);\n break;\n\n case \"flip\":\n validateFlipNode(definition, depth);\n break;\n\n case \"repeat\":\n validateRepeatNode(definition, depth);\n break;\n\n case \"retry\":\n validateRetryNode(definition, depth);\n break;\n\n case \"sequence\":\n validateSequenceNode(definition, depth);\n break;\n\n case \"selector\":\n validateSelectorNode(definition, depth);\n break;\n\n case \"parallel\":\n validateParallelNode(definition, depth);\n break;\n\n case \"lotto\":\n validateLottoNode(definition, depth);\n break;\n\n default:\n throw new Error(`unexpected node type of '${definition.type}' at depth '${depth}'`);\n }\n}\n\n/**\n * Validate any attributes for a given node definition.\n * @param definition The node definition.\n * @param depth The depth of the node in the behaviour tree definition.\n */\nfunction validateNodeAttributes(definition: any, depth: number): void {\n // Validate each of the attribute types for this node.\n [\"while\", \"until\", \"entry\", \"exit\", \"step\"].forEach((attributeName) => {\n // Attempt to grab the definition for the current attribute from the node definition.\n const attributeDefinition = definition[attributeName];\n\n // All node attributes are optional, so there is nothing to do if the current attribute is not defined.\n if (typeof attributeDefinition === \"undefined\") {\n return;\n }\n\n // The attribute definition must be an object.\n if (typeof attributeDefinition !== \"object\") {\n throw new Error(\n `expected attribute '${attributeName}' to be an object for '${definition.type}' node at depth '${depth}'`\n );\n }\n\n // The 'call' property must be defined for any attribute definition.\n if (typeof attributeDefinition.call !== \"string\" || attributeDefinition.call.length === 0) {\n throw new Error(\n `expected 'call' property for attribute '${attributeName}' to be a non-empty string for '${definition.type}' node at depth '${depth}'`\n );\n }\n\n // If any node attribute arguments have been defined then they must have been defined in an array.\n if (typeof attributeDefinition.args !== \"undefined\" && !Array.isArray(attributeDefinition.args)) {\n throw new Error(\n `expected 'args' property for attribute '${attributeName}' to be an array for '${definition.type}' node at depth '${depth}'`\n );\n }\n });\n}\n\n/**\n * Validate an object that we expect to be a root node definition.\n * @param definition An object that we expect to be a root node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateRootNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"root\") {\n throw new Error(\"expected node type of 'root' for root node\");\n }\n\n // A root node cannot be the child of another node.\n if (depth > 0) {\n throw new Error(\"a root node cannot be the child of another node\");\n }\n\n // Check that, if the root node 'id' property is defined, it is a non-empty string.\n if (typeof definition.id !== \"undefined\" && (typeof definition.id !== \"string\" || definition.id.length === 0)) {\n throw new Error(\"expected non-empty string for 'id' property if defined for root node\");\n }\n\n // A root node is a decorator node, so must have a child node defined.\n if (typeof definition.child === \"undefined\") {\n throw new Error(\"expected property 'child' to be defined for root node\");\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n\n // Validate the child node of this decorator node.\n validateNode(definition.child, depth + 1);\n}\n\n/**\n * Validate an object that we expect to be a succeed node definition.\n * @param definition An object that we expect to be a succeed node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateSucceedNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"succeed\") {\n throw new Error(`expected node type of 'succeed' for succeed node at depth '${depth}'`);\n }\n\n // A succeed node is a decorator node, so must have a child node defined.\n if (typeof definition.child === \"undefined\") {\n throw new Error(`expected property 'child' to be defined for succeed node at depth '${depth}'`);\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n\n // Validate the child node of this decorator node.\n validateNode(definition.child, depth + 1);\n}\n\n/**\n * Validate an object that we expect to be a fail node definition.\n * @param definition An object that we expect to be a fail node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateFailNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"fail\") {\n throw new Error(`expected node type of 'fail' for fail node at depth '${depth}'`);\n }\n\n // A fail node is a decorator node, so must have a child node defined.\n if (typeof definition.child === \"undefined\") {\n throw new Error(`expected property 'child' to be defined for fail node at depth '${depth}'`);\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n\n // Validate the child node of this decorator node.\n validateNode(definition.child, depth + 1);\n}\n\n/**\n * Validate an object that we expect to be a flip node definition.\n * @param definition An object that we expect to be a flip node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateFlipNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"flip\") {\n throw new Error(`expected node type of 'flip' for flip node at depth '${depth}'`);\n }\n\n // A flip node is a decorator node, so must have a child node defined.\n if (typeof definition.child === \"undefined\") {\n throw new Error(`expected property 'child' to be defined for flip node at depth '${depth}'`);\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n\n // Validate the child node of this decorator node.\n validateNode(definition.child, depth + 1);\n}\n\n/**\n * Validate an object that we expect to be a repeat node definition.\n * @param definition An object that we expect to be a repeat node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateRepeatNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"repeat\") {\n throw new Error(`expected node type of 'repeat' for repeat node at depth '${depth}'`);\n }\n\n // A repeat node is a decorator node, so must have a child node defined.\n if (typeof definition.child === \"undefined\") {\n throw new Error(`expected property 'child' to be defined for repeat node at depth '${depth}'`);\n }\n\n // Check whether an 'iterations' property has been defined, it may not have been if this node is to repeat indefinitely.\n if (typeof definition.iterations !== \"undefined\") {\n if (Array.isArray(definition.iterations)) {\n // Check whether any elements of the array are not integer values.\n const containsNonInteger = !!definition.iterations.filter((value: unknown) => !isInteger(value)).length;\n\n // If the 'iterations' property is an array then it MUST contain two integer values.\n if (definition.iterations.length !== 2 || containsNonInteger) {\n throw new Error(\n `expected array containing two integer values for 'iterations' property if defined for repeat node at depth '${depth}'`\n );\n }\n\n // A repeat node must have a positive min and max iterations count if they are defined.\n if (definition.iterations[0] < 0 || definition.iterations[1] < 0) {\n throw new Error(\n `expected positive minimum and maximum iterations count for 'iterations' property if defined for repeat node at depth '${depth}'`\n );\n }\n\n // A repeat node must not have a minimum iterations count that exceeds the maximum iterations count.\n if (definition.iterations[0] > definition.iterations[1]) {\n throw new Error(\n `expected minimum iterations count that does not exceed the maximum iterations count for 'iterations' property if defined for repeat node at depth '${depth}'`\n );\n }\n } else if (isInteger(definition.iterations)) {\n // A repeat node must have a positive number of iterations if defined.\n if (definition.iterations < 0) {\n throw new Error(\n `expected positive iterations count for 'iterations' property if defined for repeat node at depth '${depth}'`\n );\n }\n } else {\n throw new Error(\n `expected integer value or array containing two integer values for 'iterations' property if defined for repeat node at depth '${depth}'`\n );\n }\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n\n // Validate the child node of this decorator node.\n validateNode(definition.child, depth + 1);\n}\n\n/**\n * Validate an object that we expect to be a retry node definition.\n * @param definition An object that we expect to be a retry node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateRetryNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"retry\") {\n throw new Error(`expected node type of 'retry' for retry node at depth '${depth}'`);\n }\n\n // A retry node is a decorator node, so must have a child node defined.\n if (typeof definition.child === \"undefined\") {\n throw new Error(`expected property 'child' to be defined for retry node at depth '${depth}'`);\n }\n\n // Check whether an 'attempts' property has been defined, it may not have been if this node is to retry indefinitely.\n if (typeof definition.attempts !== \"undefined\") {\n if (Array.isArray(definition.attempts)) {\n // Check whether any elements of the array are not integer values.\n const containsNonInteger = !!definition.attempts.filter((value: unknown) => !isInteger(value)).length;\n\n // If the 'attempts' property is an array then it MUST contain two integer values.\n if (definition.attempts.length !== 2 || containsNonInteger) {\n throw new Error(\n `expected array containing two integer values for 'attempts' property if defined for retry node at depth '${depth}'`\n );\n }\n\n // A retry node must have a positive min and max attempts count if they are defined.\n if (definition.attempts[0] < 0 || definition.attempts[1] < 0) {\n throw new Error(\n `expected positive minimum and maximum attempts count for 'attempts' property if defined for retry node at depth '${depth}'`\n );\n }\n\n // A retry node must not have a minimum attempts count that exceeds the maximum attempts count.\n if (definition.attempts[0] > definition.attempts[1]) {\n throw new Error(\n `expected minimum attempts count that does not exceed the maximum attempts count for 'attempts' property if defined for retry node at depth '${depth}'`\n );\n }\n } else if (isInteger(definition.attempts)) {\n // A retry node must have a positive number of attempts if defined.\n if (definition.attempts < 0) {\n throw new Error(\n `expected positive attempts count for 'attempts' property if defined for retry node at depth '${depth}'`\n );\n }\n } else {\n throw new Error(\n `expected integer value or array containing two integer values for 'attempts' property if defined for retry node at depth '${depth}'`\n );\n }\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n\n // Validate the child node of this decorator node.\n validateNode(definition.child, depth + 1);\n}\n\n/**\n * Validate an object that we expect to be a branch node definition.\n * @param definition An object that we expect to be a branch node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateBranchNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"branch\") {\n throw new Error(`expected node type of 'branch' for branch node at depth '${depth}'`);\n }\n\n // Check that the branch node 'ref' property is defined and is a non-empty string.\n if (typeof definition.ref !== \"string\" || definition.ref.length === 0) {\n throw new Error(`expected non-empty string for 'ref' property for branch node at depth '${depth}'`);\n }\n\n // It is invalid to define guard attributes for a branch node as they should be defined on the referenced root node.\n [\"while\", \"until\"].forEach((attributeName) => {\n if (typeof definition[attributeName] !== \"undefined\") {\n throw new Error(\n `guards should not be defined for branch nodes but guard '${attributeName}' was defined for branch node at depth '${depth}'`\n );\n }\n });\n\n // It is invalid to define callback attributes for a branch node as they should be defined on the referenced root node.\n [\"entry\", \"exit\", \"step\"].forEach((attributeName) => {\n if (typeof definition[attributeName] !== \"undefined\") {\n throw new Error(\n `callbacks should not be defined for branch nodes but callback '${attributeName}' was defined for branch node at depth '${depth}'`\n );\n }\n });\n}\n\n/**\n * Validate an object that we expect to be a action node definition.\n * @param definition An object that we expect to be a action node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateActionNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"action\") {\n throw new Error(`expected node type of 'action' for action node at depth '${depth}'`);\n }\n\n // The 'call' property must be defined for a action node definition.\n if (typeof definition.call !== \"string\" || definition.call.length === 0) {\n throw new Error(`expected non-empty string for 'call' property of action node at depth '${depth}'`);\n }\n\n // If any action function arguments have been defined then they must have been defined in an array.\n if (typeof definition.args !== \"undefined\" && !Array.isArray(definition.args)) {\n throw new Error(`expected array for 'args' property if defined for action node at depth '${depth}'`);\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n}\n\n/**\n * Validate an object that we expect to be a condition node definition.\n * @param definition An object that we expect to be a condition node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateConditionNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"condition\") {\n throw new Error(`expected node type of 'condition' for condition node at depth '${depth}'`);\n }\n\n // The 'call' property must be defined for a condition node definition.\n if (typeof definition.call !== \"string\" || definition.call.length === 0) {\n throw new Error(`expected non-empty string for 'call' property of condition node at depth '${depth}'`);\n }\n\n // If any condition function arguments have been defined then they must have been defined in an array.\n if (typeof definition.args !== \"undefined\" && !Array.isArray(definition.args)) {\n throw new Error(`expected array for 'args' property if defined for condition node at depth '${depth}'`);\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n}\n\n/**\n * Validate an object that we expect to be a wait node definition.\n * @param definition An object that we expect to be a wait node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateWaitNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"wait\") {\n throw new Error(`expected node type of 'wait' for wait node at depth '${depth}'`);\n }\n\n // Check whether a 'duration' property has been defined, it may not have been if this node is to wait indefinitely.\n if (typeof definition.duration !== \"undefined\") {\n if (Array.isArray(definition.duration)) {\n // Check whether any elements of the array are not integer values.\n const containsNonInteger = !!definition.duration.filter((value: unknown) => !isInteger(value)).length;\n\n // If the 'duration' property is an array then it MUST contain two integer values.\n if (definition.duration.length !== 2 || containsNonInteger) {\n throw new Error(\n `expected array containing two integer values for 'duration' property if defined for wait node at depth '${depth}'`\n );\n }\n\n // A wait node must have a positive min and max duration value if they are defined.\n if (definition.duration[0] < 0 || definition.duration[1] < 0) {\n throw new Error(\n `expected positive minimum and maximum duration for 'duration' property if defined for wait node at depth '${depth}'`\n );\n }\n\n // A wait node must not have a minimum duration value that exceeds the maximum duration value.\n if (definition.duration[0] > definition.duration[1]) {\n throw new Error(\n `expected minimum duration value that does not exceed the maximum duration value for 'duration' property if defined for wait node at depth '${depth}'`\n );\n }\n } else if (isInteger(definition.duration)) {\n // A wait node must have a positive duration value if defined.\n if (definition.duration < 0) {\n throw new Error(\n `expected positive duration value for 'duration' property if defined for wait node at depth '${depth}'`\n );\n }\n } else {\n throw new Error(\n `expected integer value or array containing two integer values for 'duration' property if defined for wait node at depth '${depth}'`\n );\n }\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n}\n\n/**\n * Validate an object that we expect to be a sequence node definition.\n * @param definition An object that we expect to be a sequence node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateSequenceNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"sequence\") {\n throw new Error(`expected node type of 'sequence' for sequence node at depth '${depth}'`);\n }\n\n // A sequence node is a composite node, so must have a children nodes array defined.\n if (!Array.isArray(definition.children) || definition.children.length === 0) {\n throw new Error(`expected non-empty 'children' array to be defined for sequence node at depth '${depth}'`);\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n\n // Validate the child nodes of this composite node.\n definition.children.forEach((child: any) => validateNode(child, depth + 1));\n}\n\n/**\n * Validate an object that we expect to be a selector node definition.\n * @param definition An object that we expect to be a selector node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateSelectorNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"selector\") {\n throw new Error(`expected node type of 'selector' for selector node at depth '${depth}'`);\n }\n\n // A selector node is a composite node, so must have a children nodes array defined.\n if (!Array.isArray(definition.children) || definition.children.length === 0) {\n throw new Error(`expected non-empty 'children' array to be defined for selector node at depth '${depth}'`);\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n\n // Validate the child nodes of this composite node.\n definition.children.forEach((child: any) => validateNode(child, depth + 1));\n}\n\n/**\n * Validate an object that we expect to be a parallel node definition.\n * @param definition An object that we expect to be a parallel node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateParallelNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"parallel\") {\n throw new Error(`expected node type of 'parallel' for parallel node at depth '${depth}'`);\n }\n\n // A parallel node is a composite node, so must have a children nodes array defined.\n if (!Array.isArray(definition.children) || definition.children.length === 0) {\n throw new Error(`expected non-empty 'children' array to be defined for parallel node at depth '${depth}'`);\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n\n // Validate the child nodes of this composite node.\n definition.children.forEach((child: any) => validateNode(child, depth + 1));\n}\n\n/**\n * Validate an object that we expect to be a lotto node definition.\n * @param definition An object that we expect to be a lotto node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateLottoNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"lotto\") {\n throw new Error(`expected node type of 'lotto' for lotto node at depth '${depth}'`);\n }\n\n // A lotto node is a composite node, so must have a children nodes array defined.\n if (!Array.isArray(definition.children) || definition.children.length === 0) {\n throw new Error(`expected non-empty 'children' array to be defined for lotto node at depth '${depth}'`);\n }\n\n // Check whether a 'weights' property has been defined, if it has we expect it to be an array of weights.\n if (typeof definition.weights !== \"undefined\") {\n // Check that the weights property is an array of positive integers with an element for each child node element.\n if (\n !Array.isArray(definition.weights) ||\n definition.weights.length !== definition.children.length ||\n definition.weights.filter((value: unknown) => !isInteger(value)).length ||\n definition.weights.filter((value: number) => value < 0).length\n ) {\n throw new Error(\n `expected an array of positive integer weight values with a length matching the number of child nodes for 'weights' property if defined for lotto node at depth '${depth}'`\n );\n }\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n\n // Validate the child nodes of this composite node.\n definition.children.forEach((child: any) => validateNode(child, depth + 1));\n}\n\n/**\n * A helper function to create a failure validation result with the given error message.\n * @param errorMessage The validation failure error message.\n * @returns A failure validation result with the given error message.\n */\nfunction createValidationFailureResult(errorMessage: string): DefinitionValidationResult {\n return { succeeded: false, errorMessage };\n}\n", "import { ActionResult, Agent, GlobalFunction } from \"./Agent\";\nimport { RootNodeDefinition } from \"./BehaviourTreeDefinition\";\n\nexport type InvokerFunction = (args: any[]) => ActionResult | boolean;\n\n/**\n * A singleton used to store and lookup registered functions and subtrees.\n */\nexport default class Lookup {\n /**\n * The object holding any registered functions keyed on function name.\n */\n private static registeredFunctions: { [key: string]: GlobalFunction } = {};\n /**\n * The object holding any registered subtree root node definitions keyed on tree name.\n */\n private static registeredSubtrees: { [key: string]: RootNodeDefinition } = {};\n\n /**\n * Gets the function with the specified name.\n * @param name The name of the function.\n * @returns The function with the specified name.\n */\n public static getFunc(name: string): GlobalFunction {\n return this.registeredFunctions[name];\n }\n\n /**\n * Sets the function with the specified name for later lookup.\n * @param name The name of the function.\n * @param func The function.\n */\n public static setFunc(name: string, func: GlobalFunction): void {\n this.registeredFunctions[name] = func;\n }\n\n /**\n * Gets the function invoker for the specified agent and function name.\n * If a function with the specified name exists on the agent object then it will\n * be returned, otherwise we will then check the registered functions for a match.\n * @param agent The agent instance that this behaviour tree is modelling behaviour for.\n * @param name The function name.\n * @returns The function invoker for the specified agent and function name.\n */\n static getFuncInvoker(agent: Agent, name: string): InvokerFunction | null {\n // Check whether the agent contains the specified function.\n const agentFunction = agent[name];\n if (agentFunction && typeof agentFunction === \"function\") {\n return (args: any[]) => agentFunction.apply(agent, args);\n }\n\n // The agent does not contain the specified function but it may have been registered at some point.\n if (this.registeredFunctions[name] && typeof this.registeredFunctions[name] === \"function\") {\n const registeredFunction = this.registeredFunctions[name];\n return (args: any[]) => registeredFunction(agent, ...args);\n }\n\n // We have no function to invoke.\n return null;\n }\n\n /**\n * Gets all registered subtree root node definitions.\n */\n static getSubtrees(): { [key: string]: RootNodeDefinition } {\n return this.registeredSubtrees;\n }\n\n /**\n * Sets the subtree with the specified name for later lookup.\n * @param name The name of the subtree.\n * @param subtree The subtree.\n */\n static setSubtree(name: string, subtree: RootNodeDefinition) {\n this.registeredSubtrees[name] = subtree;\n }\n\n /**\n * Removes the registered function or subtree with the specified name.\n * @param name The name of the registered function or subtree.\n */\n static remove(name: string) {\n delete this.registeredFunctions[name];\n delete this.registeredSubtrees[name];\n }\n\n /**\n * Remove all registered functions and subtrees.\n */\n static empty() {\n this.registeredFunctions = {};\n this.registeredSubtrees = {};\n }\n}\n", "import Node from \"../../nodes/Node\";\n\n/**\n * An exception thrown when evaluating node guard path conditions and a conditions fails.\n */\nexport default class GuardUnsatisifedException extends Error {\n /**\n * @param source The node at which a guard condition failed.\n */\n constructor(private source: Node) {\n super(\"A guard path condition has failed\");\n }\n\n /**\n * Gets whether the specified node is the node at which a guard condition failed.\n * @param node The node to check against the source node.\n * @returns Whether the specified node is the node at which a guard condition failed.\n */\n isSourceNode = (node: Node) => node === this.source;\n}\n", "import { Agent } from \"../../Agent\";\nimport Guard from \"./Guard\";\nimport Node from \"../../nodes/Node\";\nimport GuardUnsatisifedException from \"./GuardUnsatisifedException\";\n\nexport type GuardPathPart = {\n node: Node;\n guards: Guard[];\n};\n\n/**\n * Represents a path of node guards along a root-to-leaf tree path.\n */\nexport default class GuardPath {\n /**\n * @param nodes An array of objects defining a node instance -> guard link, ordered by node depth.\n */\n constructor(private nodes: GuardPathPart[]) {}\n\n /**\n * Evaluate guard conditions for all guards in the tree path, moving outwards from the root.\n * @param agent The agent, required for guard evaluation.\n * @returns An evaluation results object.\n */\n evaluate = (agent: Agent) => {\n // We need to evaluate guard conditions for nodes up the tree, moving outwards from the root.\n for (const details of this.nodes) {\n // There can be multiple guards per node.\n for (const guard of details.guards) {\n // Check whether the guard condition passes, and throw an exception if not.\n if (!guard.isSatisfied(agent)) {\n throw new GuardUnsatisifedException(details.node);\n }\n }\n }\n };\n}\n", "import { BehaviourTreeOptions } from \"../BehaviourTreeOptions\";\nimport State, { AnyState } from \"../State\";\nimport { Agent } from \"../Agent\";\nimport Leaf from \"./leaf/Leaf\";\nimport Attribute from \"../attributes/Attribute\";\nimport Entry from \"../attributes/callbacks/Entry\";\nimport Exit from \"../attributes/callbacks/Exit\";\nimport Step from \"../attributes/callbacks/Step\";\nimport Guard from \"../attributes/guards/Guard\";\nimport GuardPath from \"../attributes/guards/GuardPath\";\nimport GuardUnsatisifedException from \"../attributes/guards/GuardUnsatisifedException\";\n\n/**\n * A base node.\n */\nexport default abstract class Node {\n /**\n * The node uid.\n */\n private readonly uid: string = createNodeUid();\n /**\n * The node state.\n */\n private state: AnyState = State.READY;\n /**\n * The guard path to evaluate as part of a node update.\n */\n private guardPath: GuardPath | undefined;\n\n /**\n * @param type The node type.\n * @param attributes The node attributes.\n * @param args The node argument definitions.\n */\n constructor(private type: string, private attributes: Attribute[], private args: any[]) {}\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected abstract onUpdate(agent: Agent, options: BehaviourTreeOptions): void;\n\n /**\n * Gets the name of the node.\n */\n public abstract getName(): string;\n\n /**\n * Gets whether this node is a leaf node.\n */\n public abstract isLeafNode: () => this is Leaf;\n\n /**\n * Gets/Sets the state of the node.\n */\n getState = (): AnyState => this.state;\n setState = (value: AnyState): void => {\n this.state = value;\n };\n\n /**\n * Gets the unique id of the node.\n */\n getUid = () => this.uid;\n\n /**\n * Gets the type of the node.\n */\n getType = () => this.type;\n\n /**\n * Gets the node attributes.\n */\n getAttributes = () => this.attributes;\n\n /**\n * Gets the node arguments.\n */\n getArguments = () => this.args;\n\n /**\n * Gets the node attribute with the specified type, or null if it does not exist.\n */\n getAttribute(type: \"entry\" | \"ENTRY\"): Entry;\n getAttribute(type: \"exit\" | \"EXIT\"): Exit;\n getAttribute(type: \"step\" | \"STEP\"): Step;\n getAttribute(type: string): Attribute {\n return (\n this.getAttributes().filter((decorator) => decorator.type.toUpperCase() === type.toUpperCase())[0] || null\n );\n }\n\n /**\n * Gets the node attributes.\n */\n getGuardAttributes = (): Guard[] => this.getAttributes().filter((decorator) => decorator.isGuard()) as Guard[];\n\n /**\n * Sets the guard path to evaluate as part of a node update.\n */\n setGuardPath = (value: GuardPath) => (this.guardPath = value);\n\n /**\n * Gets whether a guard path is assigned to this node.\n */\n hasGuardPath = () => !!this.guardPath;\n\n /**\n * Gets whether this node is in the specified state.\n * @param value The value to compare to the node state.\n */\n public is(value: AnyState): boolean {\n return this.state === value;\n }\n\n /**\n * Reset the state of the node.\n */\n public reset(): void {\n this.setState(State.READY);\n }\n\n /**\n * Abort the running of this node.\n * @param agent The agent.\n */\n public abort(agent: Agent): void {\n // There is nothing to do if this node is not in the running state.\n if (!this.is(State.RUNNING)) {\n return;\n }\n\n // Reset the state of this node.\n this.reset();\n\n this.getAttribute(\"exit\")?.callAgentFunction(agent, false, true);\n }\n\n /**\n * Update the node.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n * @returns The result of the update.\n */\n public update(agent: Agent, options: BehaviourTreeOptions): void {\n // If this node is already in a 'SUCCEEDED' or 'FAILED' state then there is nothing to do.\n if (this.is(State.SUCCEEDED) || this.is(State.FAILED)) {\n return;\n }\n\n try {\n // Evaluate all of the guard path conditions for the current tree path.\n this.guardPath!.evaluate(agent);\n\n // If this node is in the READY state then call the ENTRY for this node if it exists.\n if (this.is(State.READY)) {\n this.getAttribute(\"entry\")?.callAgentFunction(agent);\n }\n\n this.getAttribute(\"step\")?.callAgentFunction(agent);\n\n // Do the actual update.\n this.onUpdate(agent, options);\n\n // If this node is now in a 'SUCCEEDED' or 'FAILED' state then call the EXIT for this node if it exists.\n if (this.is(State.SUCCEEDED) || this.is(State.FAILED)) {\n this.getAttribute(\"exit\")?.callAgentFunction(agent, this.is(State.SUCCEEDED), false);\n }\n } catch (error) {\n // If the error is a GuardUnsatisfiedException then we need to determine if this node is the source.\n if (error instanceof GuardUnsatisifedException && error.isSourceNode(this)) {\n // Abort the current node.\n this.abort(agent);\n\n // Any node that is the source of an abort will be a failed node.\n this.setState(State.FAILED);\n } else {\n throw error;\n }\n }\n }\n}\n\n/**\n * Create a randomly generated node uid.\n * @returns A randomly generated node uid.\n */\nfunction createNodeUid(): string {\n var S4 = function () {\n return (((1 + Math.random()) * 0x10000) | 0).toString(16).substring(1);\n };\n return S4() + S4() + \"-\" + S4() + \"-\" + S4() + \"-\" + S4() + \"-\" + S4() + S4() + S4();\n}\n", "import Node from \"../Node\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\n\n/**\n * A composite node that wraps child nodes.\n */\nexport default abstract class Composite extends Node {\n /**\n * @param type The node type.\n * @param attributes The node attributes.\n * @param children The child nodes.\n */\n constructor(type: string, attributes: Attribute[], protected children: Node[]) {\n super(type, attributes, []);\n }\n\n /**\n * Gets whether this node is a leaf node.\n */\n isLeafNode = () => false;\n\n /**\n * Gets the children of this node.\n */\n getChildren = () => this.children;\n\n /**\n * Reset the state of the node.\n */\n reset = () => {\n // Reset the state of this node.\n this.setState(State.READY);\n\n // Reset the state of any child nodes.\n this.getChildren().forEach((child) => child.reset());\n };\n\n /**\n * Abort the running of this node.\n * @param agent The agent.\n */\n abort = (agent: Agent) => {\n // There is nothing to do if this node is not in the running state.\n if (!this.is(State.RUNNING)) {\n return;\n }\n\n // Abort any child nodes.\n this.getChildren().forEach((child) => child.abort(agent));\n\n // Reset the state of this node.\n this.reset();\n\n this.getAttribute(\"exit\")?.callAgentFunction(agent, false, true);\n };\n}\n", "import Composite from \"./Composite\";\nimport State from \"../../State\";\nimport Node from \"../Node\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A PARALLEL node.\n * The child nodes are executed concurrently until one fails or all succeed.\n */\nexport default class Parallel extends Composite {\n /**\n * @param attributes The node attributes.\n * @param children The child nodes.\n */\n constructor(attributes: Attribute[], children: Node[]) {\n super(\"parallel\", attributes, children);\n }\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // Keep a count of the number of succeeded child nodes.\n let succeededCount = 0;\n\n let hasChildFailed = false;\n\n // Iterate over all of the children of this node.\n for (const child of this.children) {\n // If the child has never been updated or is running then we will need to update it now.\n if (child.getState() === State.READY || child.getState() === State.RUNNING) {\n // Update the child of this node.\n child.update(agent, options);\n }\n\n // If the current child has a state of 'SUCCEEDED' then we should move on to the next child.\n if (child.getState() === State.SUCCEEDED) {\n // The child node has succeeded, keep track of this to determine if all children have.\n succeededCount++;\n\n // The child node succeeded, but we have not finished checking every child node yet.\n continue;\n }\n\n // If the current child has a state of 'FAILED' then this node is also a 'FAILED' node.\n if (child.getState() === State.FAILED) {\n hasChildFailed = true;\n\n // There is no need to check the rest of the children.\n break;\n }\n\n // The node should be in the 'RUNNING' state.\n if (child.getState() !== State.RUNNING) {\n // The child node was not in an expected state.\n throw new Error(\"child node was not in an expected state.\");\n }\n }\n\n if (hasChildFailed) {\n // This node is a 'FAILED' node.\n this.setState(State.FAILED);\n\n // Abort every running child.\n for (const child of this.children) {\n if (child.getState() === State.RUNNING) {\n child.abort(agent);\n }\n }\n } else {\n // If all children have succeeded then this node has also succeeded, otherwise it is still running.\n this.setState(succeededCount === this.children.length ? State.SUCCEEDED : State.RUNNING);\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => \"PARALLEL\";\n}\n", "import Composite from \"./Composite\";\nimport Node from \"../Node\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A SELECTOR node.\n * The child nodes are executed in sequence until one succeeds or all fail.\n */\nexport default class Selector extends Composite {\n /**\n * @param attributes The node attributes.\n * @param children The child nodes.\n */\n constructor(attributes: Attribute[], protected children: Node[]) {\n super(\"selector\", attributes, children);\n }\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // Iterate over all of the children of this node.\n for (const child of this.children) {\n // If the child has never been updated or is running then we will need to update it now.\n if (child.getState() === State.READY || child.getState() === State.RUNNING) {\n // Update the child of this node.\n child.update(agent, options);\n }\n\n // If the current child has a state of 'SUCCEEDED' then this node is also a 'SUCCEEDED' node.\n if (child.getState() === State.SUCCEEDED) {\n // This node is a 'SUCCEEDED' node.\n this.setState(State.SUCCEEDED);\n\n // There is no need to check the rest of the selector nodes.\n return;\n }\n\n // If the current child has a state of 'FAILED' then we should move on to the next child.\n if (child.getState() === State.FAILED) {\n // Find out if the current child is the last one in the selector.\n // If it is then this sequence node has also failed.\n if (this.children.indexOf(child) === this.children.length - 1) {\n // This node is a 'FAILED' node.\n this.setState(State.FAILED);\n\n // There is no need to check the rest of the selector as we have completed it.\n return;\n } else {\n // The child node failed, try the next one.\n continue;\n }\n }\n\n // The node should be in the 'RUNNING' state.\n if (child.getState() === State.RUNNING) {\n // This node is a 'RUNNING' node.\n this.setState(State.RUNNING);\n\n // There is no need to check the rest of the selector as the current child is still running.\n return;\n }\n\n // The child node was not in an expected state.\n throw new Error(\"child node was not in an expected state.\");\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => \"SELECTOR\";\n}\n", "import Composite from \"./Composite\";\nimport Node from \"../Node\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A SEQUENCE node.\n * The child nodes are executed in sequence until one fails or all succeed.\n */\nexport default class Sequence extends Composite {\n /**\n * @param attributes The node attributes.\n * @param children The child nodes.\n */\n constructor(attributes: Attribute[], protected children: Node[]) {\n super(\"sequence\", attributes, children);\n }\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // Iterate over all of the children of this node.\n for (const child of this.children) {\n // If the child has never been updated or is running then we will need to update it now.\n if (child.getState() === State.READY || child.getState() === State.RUNNING) {\n // Update the child of this node.\n child.update(agent, options);\n }\n\n // If the current child has a state of 'SUCCEEDED' then we should move on to the next child.\n if (child.getState() === State.SUCCEEDED) {\n // Find out if the current child is the last one in the sequence.\n // If it is then this sequence node has also succeeded.\n if (this.children.indexOf(child) === this.children.length - 1) {\n // This node is a 'SUCCEEDED' node.\n this.setState(State.SUCCEEDED);\n\n // There is no need to check the rest of the sequence as we have completed it.\n return;\n } else {\n // The child node succeeded, but we have not finished the sequence yet.\n continue;\n }\n }\n\n // If the current child has a state of 'FAILED' then this node is also a 'FAILED' node.\n if (child.getState() === State.FAILED) {\n // This node is a 'FAILED' node.\n this.setState(State.FAILED);\n\n // There is no need to check the rest of the sequence.\n return;\n }\n\n // The node should be in the 'RUNNING' state.\n if (child.getState() === State.RUNNING) {\n // This node is a 'RUNNING' node.\n this.setState(State.RUNNING);\n\n // There is no need to check the rest of the sequence as the current child is still running.\n return;\n }\n\n // The child node was not in an expected state.\n throw new Error(\"child node was not in an expected state.\");\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => \"SEQUENCE\";\n}\n", "import createLotto from \"lotto-draw\";\n\nimport Node from \"../Node\";\nimport Composite from \"./Composite\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A LOTTO node.\n * A winning child is picked on the initial update of this node, based on ticket weighting.\n * The state of this node will match the state of the winning child.\n */\nexport default class Lotto extends Composite {\n /**\n * @param attributes The node attributes.\n * @param weights The child node weights.\n * @param children The child nodes.\n */\n constructor(attributes: Attribute[], private weights: number[] | undefined, children: Node[]) {\n super(\"lotto\", attributes, children);\n }\n\n /**\n * The child node selected to be the active one.\n */\n private selectedChild: Node | undefined;\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // If this node is in the READY state then we need to pick a winning child node.\n if (this.is(State.READY)) {\n // Create a lotto draw with which to randomly pick a child node to become the active one.\n const lottoDraw = createLotto({\n // Hook up the optional 'random' behaviour tree function option to the one used by 'lotto-draw'.\n random: options.random,\n // Pass in each child node as a participant in the lotto draw with their respective ticket count.\n participants: this.children.map((child, index) => [child, this.weights?.[index] || 1])\n });\n\n // Randomly pick a child based on ticket weighting, this will become the active child for this composite node.\n this.selectedChild = lottoDraw.draw() || undefined;\n }\n\n // If something went wrong and we don't have an active child then we should throw an error.\n if (!this.selectedChild) {\n throw new Error(\"failed to update lotto node as it has no active child\");\n }\n\n // If the selected child has never been updated or is running then we will need to update it now.\n if (this.selectedChild.getState() === State.READY || this.selectedChild.getState() === State.RUNNING) {\n this.selectedChild.update(agent, options);\n }\n\n // The state of the lotto node is the state of its selected child.\n this.setState(this.selectedChild.getState());\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => (this.weights ? `LOTTO [${this.weights.join(\",\")}]` : \"LOTTO\");\n}\n", "import Node from \"../Node\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\n\n/**\n * A decorator node that wraps a single child node.\n */\nexport default abstract class Decorator extends Node {\n /**\n * @param type The node type.\n * @param attributes The node attributes.\n * @param child The child node.\n */\n constructor(type: string, attributes: Attribute[], protected child: Node) {\n super(type, attributes, []);\n }\n\n /**\n * Gets whether this node is a leaf node.\n */\n isLeafNode = () => false;\n\n /**\n * Gets the children of this node.\n */\n getChildren = () => [this.child];\n\n /**\n * Reset the state of the node.\n */\n reset = () => {\n // Reset the state of this node.\n this.setState(State.READY);\n\n // Reset the state of the child node.\n this.child.reset();\n };\n\n /**\n * Abort the running of this node.\n * @param agent The agent.\n */\n abort = (agent: Agent) => {\n // There is nothing to do if this node is not in the running state.\n if (!this.is(State.RUNNING)) {\n return;\n }\n\n // Abort the child node.\n this.child.abort(agent);\n\n // Reset the state of this node.\n this.reset();\n\n this.getAttribute(\"exit\")?.callAgentFunction(agent, false, true);\n };\n}\n", "import Node from \"../Node\";\nimport Decorator from \"./Decorator\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A Fail node.\n * This node wraps a single child and will always move to the 'FAILED' state when the child moves to a 'SUCCEEDED' or 'FAILED' state.\n */\nexport default class Fail extends Decorator {\n /**\n * @param attributes The node attributes.\n * @param child The child node.\n */\n constructor(attributes: Attribute[], child: Node) {\n super(\"fail\", attributes, child);\n }\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // If the child has never been updated or is running then we will need to update it now.\n if (this.child.getState() === State.READY || this.child.getState() === State.RUNNING) {\n this.child.update(agent, options);\n }\n\n // The state of this node will depend in the state of its child.\n switch (this.child.getState()) {\n case State.RUNNING:\n this.setState(State.RUNNING);\n break;\n\n case State.SUCCEEDED:\n case State.FAILED:\n this.setState(State.FAILED);\n break;\n\n default:\n this.setState(State.READY);\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => \"FAIL\";\n}\n", "import Decorator from \"./Decorator\";\nimport State from \"../../State\";\nimport Node from \"../Node\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A Flip node.\n * This node wraps a single child and will flip the state of the child state.\n */\nexport default class Flip extends Decorator {\n /**\n * @param attributes The node attributes.\n * @param child The child node.\n */\n constructor(attributes: Attribute[], child: Node) {\n super(\"flip\", attributes, child);\n }\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // If the child has never been updated or is running then we will need to update it now.\n if (this.child.getState() === State.READY || this.child.getState() === State.RUNNING) {\n this.child.update(agent, options);\n }\n\n // The state of this node will depend in the state of its child.\n switch (this.child.getState()) {\n case State.RUNNING:\n this.setState(State.RUNNING);\n break;\n\n case State.SUCCEEDED:\n this.setState(State.FAILED);\n break;\n\n case State.FAILED:\n this.setState(State.SUCCEEDED);\n break;\n\n default:\n this.setState(State.READY);\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => \"FLIP\";\n}\n", "import Node from \"../Node\";\nimport Decorator from \"./Decorator\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A REPEAT node.\n * The node has a single child which can have:\n * -- A number of iterations for which to repeat the child node.\n * -- An infinite repeat loop if neither an iteration count or a condition function is defined.\n * The REPEAT node will stop and have a 'FAILED' state if its child is ever in a 'FAILED' state after an update.\n * The REPEAT node will attempt to move on to the next iteration if its child is ever in a 'SUCCEEDED' state.\n */\nexport default class Repeat extends Decorator {\n /**\n * @param attributes The node attributes.\n * @param iterations The number of iterations to repeat the child node.\n * @param iterationsMin The minimum possible number of iterations to repeat the child node.\n * @param iterationsMax The maximum possible number of iterations to repeat the child node.\n * @param child The child node.\n */\n constructor(\n attributes: Attribute[],\n private iterations: number | null,\n private iterationsMin: number | null,\n private iterationsMax: number | null,\n child: Node\n ) {\n super(\"repeat\", attributes, child);\n }\n\n /**\n * The number of target iterations to make.\n */\n private targetIterationCount: number | null = null;\n\n /**\n * The current iteration count.\n */\n private currentIterationCount: number = 0;\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // If this node is in the READY state then we need to reset the child and the target iteration count.\n if (this.is(State.READY)) {\n // Reset the child node.\n this.child.reset();\n\n // Reset the current iteration count.\n this.currentIterationCount = 0;\n\n // Set the target iteration count.\n this.setTargetIterationCount(options);\n }\n\n // Do a check to see if we can iterate. If we can then this node will move into the 'RUNNING' state.\n // If we cannot iterate then we have hit our target iteration count, which means that the node has succeeded.\n if (this.canIterate()) {\n // This node is in the running state and can do its initial iteration.\n this.setState(State.RUNNING);\n\n // We may have already completed an iteration, meaning that the child node will be in the SUCCEEDED state.\n // If this is the case then we will have to reset the child node now.\n if (this.child.getState() === State.SUCCEEDED) {\n this.child.reset();\n }\n\n // Update the child of this node.\n this.child.update(agent, options);\n\n // If the child moved into the FAILED state when we updated it then there is nothing left to do and this node has also failed.\n // If it has moved into the SUCCEEDED state then we have completed the current iteration.\n if (this.child.getState() === State.FAILED) {\n // The child has failed, meaning that this node has failed.\n this.setState(State.FAILED);\n\n return;\n } else if (this.child.getState() === State.SUCCEEDED) {\n // We have completed an iteration.\n this.currentIterationCount += 1;\n }\n } else {\n // This node is in the 'SUCCEEDED' state as we cannot iterate any more.\n this.setState(State.SUCCEEDED);\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => {\n if (this.iterations !== null) {\n return `REPEAT ${this.iterations}x`;\n } else if (this.iterationsMin !== null && this.iterationsMax !== null) {\n return `REPEAT ${this.iterationsMin}x-${this.iterationsMax}x`;\n } else {\n return \"REPEAT\";\n }\n };\n\n /**\n * Reset the state of the node.\n */\n reset = () => {\n // Reset the state of this node.\n this.setState(State.READY);\n\n // Reset the current iteration count.\n this.currentIterationCount = 0;\n\n // Reset the child node.\n this.child.reset();\n };\n\n /**\n * Gets whether an iteration can be made.\n * @returns Whether an iteration can be made.\n */\n private canIterate = () => {\n if (this.targetIterationCount !== null) {\n // We can iterate as long as we have not reached our target iteration count.\n return this.currentIterationCount < this.targetIterationCount;\n }\n\n // If neither an iteration count or a condition function were defined then we can iterate indefinitely.\n return true;\n };\n\n /**\n * Sets the target iteration count.\n * @param options The behaviour tree options object.\n */\n private setTargetIterationCount = (options: BehaviourTreeOptions) => {\n // Are we dealing with an explicit iteration count or will we be randomly picking a iteration count between the min and max iteration count.\n if (this.iterations !== null) {\n this.targetIterationCount = this.iterations;\n } else if (this.iterationsMin !== null && this.iterationsMax !== null) {\n // We will be picking a random iteration count between a min and max iteration count, if the optional 'random'\n // behaviour tree function option is defined then we will be using that, otherwise we will fall back to using Math.random.\n const random = typeof options.random === \"function\" ? options.random : Math.random;\n\n // Pick a random iteration count between a min and max iteration count.\n this.targetIterationCount = Math.floor(\n random() * (this.iterationsMax - this.iterationsMin + 1) + this.iterationsMin\n );\n } else {\n this.targetIterationCount = null;\n }\n };\n}\n", "import Node from \"../Node\";\nimport Decorator from \"./Decorator\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A RETRY node.\n * The node has a single child which can have:\n * -- A number of iterations for which to repeat the child node.\n * -- An infinite repeat loop if neither an iteration count or a condition function is defined.\n * The RETRY node will stop and have a 'SUCCEEDED' state if its child is ever in a 'SUCCEEDED' state after an update.\n * The RETRY node will attempt to move on to the next iteration if its child is ever in a 'FAILED' state.\n */\nexport default class Retry extends Decorator {\n /**\n * @param attributes The node attributes.\n * @param attempts The number of attempts to retry the child node.\n * @param attemptsMin The minimum possible number of attempts to retry the child node.\n * @param attemptsMax The maximum possible number of attempts to retry the child node.\n * @param child The child node.\n */\n constructor(\n attributes: Attribute[],\n private attempts: number | null,\n private attemptsMin: number | null,\n private attemptsMax: number | null,\n child: Node\n ) {\n super(\"retry\", attributes, child);\n }\n\n /**\n * The number of target attempts to make.\n */\n private targetAttemptCount: number | null = null;\n\n /**\n * The current attempt count.\n */\n private currentAttemptCount: number = 0;\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // If this node is in the READY state then we need to reset the child and the target attempt count.\n if (this.is(State.READY)) {\n // Reset the child node.\n this.child.reset();\n\n // Reset the current attempt count.\n this.currentAttemptCount = 0;\n\n // Set the target attempt count.\n this.setTargetAttemptCount(options);\n }\n\n // Do a check to see if we can attempt. If we can then this node will move into the 'RUNNING' state.\n // If we cannot attempt then we have hit our target attempt count, which means that the node has succeeded.\n if (this.canAttempt()) {\n // This node is in the running state and can do its initial attempt.\n this.setState(State.RUNNING);\n\n // We may have already completed an attempt, meaning that the child node will be in the FAILED state.\n // If this is the case then we will have to reset the child node now.\n if (this.child.getState() === State.FAILED) {\n this.child.reset();\n }\n\n // Update the child of this node.\n this.child.update(agent, options);\n\n // If the child moved into the SUCCEEDED state when we updated it then there is nothing left to do and this node has also succeeded.\n // If it has moved into the FAILED state then we have completed the current attempt.\n if (this.child.getState() === State.SUCCEEDED) {\n // The child has succeeded, meaning that this node has succeeded.\n this.setState(State.SUCCEEDED);\n\n return;\n } else if (this.child.getState() === State.FAILED) {\n // We have completed an attempt.\n this.currentAttemptCount += 1;\n }\n } else {\n // This node is in the 'FAILED' state as we cannot iterate any more.\n this.setState(State.FAILED);\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => {\n if (this.attempts !== null) {\n return `RETRY ${this.attempts}x`;\n } else if (this.attemptsMin !== null && this.attemptsMax !== null) {\n return `RETRY ${this.attemptsMin}x-${this.attemptsMax}x`;\n } else {\n return \"RETRY\";\n }\n };\n\n /**\n * Reset the state of the node.\n */\n reset = () => {\n // Reset the state of this node.\n this.setState(State.READY);\n\n // Reset the current attempt count.\n this.currentAttemptCount = 0;\n\n // Reset the child node.\n this.child.reset();\n };\n\n /**\n * Gets whether an attempt can be made.\n * @returns Whether an attempt can be made.\n */\n canAttempt = () => {\n if (this.targetAttemptCount !== null) {\n // We can attempt as long as we have not reached our target attempt count.\n return this.currentAttemptCount < this.targetAttemptCount;\n }\n\n // If neither an attempt count or a condition function were defined then we can attempt indefinitely.\n return true;\n };\n\n /**\n * Sets the target attempt count.\n * @param options The behaviour tree options object.\n */\n setTargetAttemptCount = (options: BehaviourTreeOptions) => {\n // Are we dealing with an explicit attempt count or will we be randomly picking an attempt count between the min and max attempt count.\n if (this.attempts !== null) {\n this.targetAttemptCount = this.attempts;\n } else if (this.attemptsMin !== null && this.attemptsMax !== null) {\n // We will be picking a random attempt count between a min and max attempt count, if the optional 'random'\n // behaviour tree function option is defined then we will be using that, otherwise we will fall back to using Math.random.\n const random = typeof options.random === \"function\" ? options.random : Math.random;\n\n // Pick a random attempt count between a min and max attempt count.\n this.targetAttemptCount = Math.floor(\n random() * (this.attemptsMax - this.attemptsMin + 1) + this.attemptsMin\n );\n } else {\n this.targetAttemptCount = null;\n }\n };\n}\n", "import Node from \"../Node\";\nimport Decorator from \"./Decorator\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A Root node.\n * The root node will have a single child.\n */\nexport default class Root extends Decorator {\n /**\n * @param attributes The node attributes.\n * @param child The child node.\n */\n constructor(attributes: Attribute[], child: Node) {\n super(\"root\", attributes, child);\n }\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // If the child has never been updated or is running then we will need to update it now.\n if (this.child.getState() === State.READY || this.child.getState() === State.RUNNING) {\n // Update the child of this node.\n this.child.update(agent, options);\n }\n\n // The state of the root node is the state of its child.\n this.setState(this.child.getState());\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => \"ROOT\";\n}\n", "import Node from \"../Node\";\nimport Decorator from \"./Decorator\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A Succeed node.\n * This node wraps a single child and will always move to the 'SUCCEEDED' state when the child moves to a 'SUCCEEDED' or 'FAILED' state.\n */\nexport default class Succeed extends Decorator {\n /**\n * @param attributes The node attributes.\n * @param child The child node.\n */\n constructor(attributes: Attribute[], child: Node) {\n super(\"succeed\", attributes, child);\n }\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // If the child has never been updated or is running then we will need to update it now.\n if (this.child.getState() === State.READY || this.child.getState() === State.RUNNING) {\n this.child.update(agent, options);\n }\n\n // The state of this node will depend in the state of its child.\n switch (this.child.getState()) {\n case State.RUNNING:\n this.setState(State.RUNNING);\n break;\n\n case State.SUCCEEDED:\n case State.FAILED:\n this.setState(State.SUCCEEDED);\n break;\n\n default:\n this.setState(State.READY);\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => \"SUCCEED\";\n}\n", "import Node from \"../Node\";\n\n/**\n * A leaf node.\n */\nexport default abstract class Leaf extends Node {\n /**\n * Gets whether this node is a leaf node.\n */\n isLeafNode = () => true;\n}\n", "import { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\nimport State, { CompleteState } from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Leaf from \"./Leaf\";\nimport Lookup from \"../../Lookup\";\nimport Attribute from \"../../attributes/Attribute\";\n\n/**\n * The type representing a resolved/rejected update promise.\n */\ntype UpdatePromiseResult = {\n /**\n * Whether the promise was resolved rather than rejected.\n */\n isResolved: boolean;\n\n /**\n * The promise resolved value or rejection reason.\n */\n value: any;\n};\n\n/**\n * An Action leaf node.\n * This represents an immediate or ongoing state of behaviour.\n */\nexport default class Action extends Leaf {\n /**\n * @param attributes The node attributes.\n * @param actionName The action name.\n * @param actionArguments The array of action argument definitions.\n */\n constructor(attributes: Attribute[], private actionName: string, private actionArguments: any[]) {\n super(\"action\", attributes, actionArguments);\n }\n\n /**\n * Whether there is a pending update promise.\n */\n private isUsingUpdatePromise = false;\n\n /**\n * The finished state result of an update promise.\n */\n private updatePromiseResult: UpdatePromiseResult | null = null;\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // If the result of this action depends on an update promise then there is nothing to do until it settles.\n if (this.isUsingUpdatePromise) {\n // Are we still waiting for our update promise to settle?\n if (!this.updatePromiseResult) {\n return;\n }\n\n const { isResolved, value } = this.updatePromiseResult;\n\n // Our update promise settled, was it resolved or rejected?\n if (isResolved) {\n // Our promise resolved so check to make sure the result is a valid finished state.\n if (value !== State.SUCCEEDED && value !== State.FAILED) {\n throw new Error(\n \"action node promise resolved with an invalid value, expected a State.SUCCEEDED or State.FAILED value to be returned\"\n );\n }\n\n // Set the state of this node to match the state returned by the promise.\n this.setState(value);\n\n return;\n } else {\n // The promise was rejected, which isn't great.\n throw new Error(`action function '${this.actionName}' promise rejected with '${value}'`);\n }\n }\n\n // Attempt to get the invoker for the action function.\n const actionFuncInvoker = Lookup.getFuncInvoker(agent, this.actionName);\n\n // The action function should be defined.\n if (actionFuncInvoker === null) {\n throw new Error(\n `cannot update action node as the action '${this.actionName}' function is not defined on the agent and has not been registered`\n );\n }\n\n let actionFunctionResult;\n\n try {\n // Call the action function, the result of which may be:\n // - The finished state of this action node.\n // - A promise to return a finished node state.\n // - Undefined if the node should remain in the running state.\n actionFunctionResult = actionFuncInvoker(this.actionArguments) as CompleteState | Promise;\n } catch (error) {\n // An uncaught error was thrown.\n if (error instanceof Error) {\n throw new Error(`action function '${this.actionName}' threw: ${error.stack}`);\n } else {\n throw new Error(`action function '${this.actionName}' threw: ${error}`);\n }\n }\n\n if (actionFunctionResult instanceof Promise) {\n actionFunctionResult.then(\n (result) => {\n // If 'isUpdatePromisePending' is not set then the promise was cleared as it was resolving, probably via an abort of reset.\n if (!this.isUsingUpdatePromise) {\n return;\n }\n\n // Set the resolved update promise result so that it can be handled on the next update of this node.\n this.updatePromiseResult = {\n isResolved: true,\n value: result\n };\n },\n (reason) => {\n // If 'isUpdatePromisePending' is not set then the promise was cleared as it was resolving, probably via an abort or reset.\n if (!this.isUsingUpdatePromise) {\n return;\n }\n\n // Set the rejected update promise result so that it can be handled on the next update of this node.\n this.updatePromiseResult = {\n isResolved: false,\n value: reason\n };\n }\n );\n\n // This node will be in the 'RUNNING' state until the update promise resolves.\n this.setState(State.RUNNING);\n\n // We are now waiting for the promise returned by the use to resolve before we know what state this node is in.\n this.isUsingUpdatePromise = true;\n } else {\n // Validate the returned value.\n this.validateUpdateResult(actionFunctionResult);\n\n // Set the state of this node, this may be undefined, which just means that the node is still in the 'RUNNING' state.\n this.setState(actionFunctionResult || State.RUNNING);\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => this.actionName;\n\n /**\n * Reset the state of the node.\n */\n reset = () => {\n // Reset the state of this node.\n this.setState(State.READY);\n\n // There is no longer an update promise that we care about.\n this.isUsingUpdatePromise = false;\n this.updatePromiseResult = null;\n };\n\n /**\n * Validate the result of an update function call.\n * @param result The result of an update function call.\n */\n private validateUpdateResult = (result: CompleteState | State.RUNNING) => {\n switch (result) {\n case State.SUCCEEDED:\n case State.FAILED:\n case State.RUNNING:\n case undefined:\n return;\n default:\n throw new Error(\n `expected action function '${this.actionName}' to return an optional State.SUCCEEDED or State.FAILED value but returned '${result}'`\n );\n }\n };\n}\n", "import { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Leaf from \"./Leaf\";\nimport Lookup from \"../../Lookup\";\nimport Attribute from \"../../attributes/Attribute\";\n\n/**\n * A Condition leaf node.\n * This will succeed or fail immediately based on an agent predicate, without moving to the 'RUNNING' state.\n */\nexport default class Condition extends Leaf {\n /**\n * @param attributes The node attributes.\n * @param conditionName The name of the condition function.\n * @param conditionArguments The array of condition argument definitions.\n */\n constructor(attributes: Attribute[], private conditionName: string, private conditionArguments: any[]) {\n super(\"condition\", attributes, conditionArguments);\n }\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // Attempt to get the invoker for the condition function.\n const conditionFuncInvoker = Lookup.getFuncInvoker(agent, this.conditionName);\n\n // The condition function should be defined.\n if (conditionFuncInvoker === null) {\n throw new Error(\n `cannot update condition node as the condition '${this.conditionName}' function is not defined on the agent and has not been registered`\n );\n }\n\n let conditionFunctionResult;\n\n try {\n // Call the condition function to determine the state of this node, the result of which should be a boolean.\n conditionFunctionResult = conditionFuncInvoker(this.conditionArguments);\n } catch (error) {\n // An uncaught error was thrown.\n if (error instanceof Error) {\n throw new Error(`condition function '${this.conditionName}' threw: ${error.stack}`);\n } else {\n throw new Error(`condition function '${this.conditionName}' threw: ${error}`);\n }\n }\n\n // The result of calling the condition function must be a boolean value.\n if (typeof conditionFunctionResult !== \"boolean\") {\n throw new Error(\n `expected condition function '${this.conditionName}' to return a boolean but returned '${conditionFunctionResult}'`\n );\n }\n\n // Set the state of this node based on the result of calling the condition function.\n this.setState(!!conditionFunctionResult ? State.SUCCEEDED : State.FAILED);\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => this.conditionName;\n}\n", "import Leaf from \"./Leaf\";\nimport State from \"../../State\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { Agent } from \"../../Agent\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A WAIT node.\n * The state of this node will change to SUCCEEDED after a duration of time\n */\nexport default class Wait extends Leaf {\n /**\n * @param attributes The node attributes.\n * @param duration The duration that this node will wait to succeed in milliseconds.\n * @param durationMin The minimum possible duration in milliseconds that this node will wait to succeed.\n * @param durationMax The maximum possible duration in milliseconds that this node will wait to succeed.\n */\n constructor(\n attributes: Attribute[],\n private duration: number | null,\n private durationMin: number | null,\n private durationMax: number | null\n ) {\n super(\"wait\", attributes, []);\n }\n\n /**\n * The time in milliseconds at which this node was first updated.\n */\n private initialUpdateTime: number = 0;\n\n /**\n * The total duration in milliseconds that this node will be waiting for.\n */\n private totalDuration: number | null = null;\n\n /**\n * The duration in milliseconds that this node has been waiting for.\n */\n private waitedDuration: number = 0;\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // If this node is in the READY state then we need to set the initial update time.\n if (this.is(State.READY)) {\n // Set the initial update time.\n this.initialUpdateTime = new Date().getTime();\n\n // Set the initial waited duration.\n this.waitedDuration = 0;\n\n // Are we dealing with an explicit duration or will we be randomly picking a duration between the min and max duration.\n if (this.duration !== null) {\n this.totalDuration = this.duration;\n } else if (this.durationMin !== null && this.durationMax !== null) {\n // We will be picking a random duration between a min and max duration, if the optional 'random' behaviour tree\n // function option is defined then we will be using that, otherwise we will fall back to using Math.random.\n const random = typeof options.random === \"function\" ? options.random : Math.random;\n\n // Pick a random duration between a min and max duration.\n this.totalDuration = Math.floor(\n random() * (this.durationMax - this.durationMin + 1) + this.durationMin\n );\n } else {\n this.totalDuration = null;\n }\n\n // The node is now running until we finish waiting.\n this.setState(State.RUNNING);\n }\n\n // If we have no total duration then this wait node will wait indefinitely until it is aborted.\n if (this.totalDuration === null) {\n return;\n }\n\n // If we have a 'getDeltaTime' function defined as part of our options then we will use it to figure out how long we have waited for.\n if (typeof options.getDeltaTime === \"function\") {\n // Get the delta time.\n const deltaTime = options.getDeltaTime();\n\n // Our delta time must be a valid number and cannot be NaN.\n if (typeof deltaTime !== \"number\" || isNaN(deltaTime)) {\n throw new Error(\"The delta time must be a valid number and not NaN.\");\n }\n\n // Update the amount of time that this node has been waiting for based on the delta time.\n this.waitedDuration += deltaTime * 1000;\n } else {\n // We are not using a delta time, so we will just work out hom much time has passed since the first update.\n this.waitedDuration = new Date().getTime() - this.initialUpdateTime;\n }\n\n // Have we waited long enough?\n if (this.waitedDuration >= this.totalDuration) {\n // We have finished waiting!\n this.setState(State.SUCCEEDED);\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => {\n if (this.duration !== null) {\n return `WAIT ${this.duration}ms`;\n } else if (this.durationMin !== null && this.durationMax !== null) {\n return `WAIT ${this.durationMin}ms-${this.durationMax}ms`;\n } else {\n return \"WAIT\";\n }\n };\n}\n", "import Guard from \"./guards/Guard\";\n\nexport type AttributeDetails = {\n /** The attribute type. */\n type: string;\n\n /** The attribute arguments. */\n args: any[];\n};\n\n/**\n * A base node attribute.\n */\nexport default abstract class Attribute {\n /**\n * @param type The node attribute type.\n * @param args The array of attribute arguments.\n */\n constructor(public type: string, public args: any[]) {}\n\n /**\n * Gets the attribute details.\n */\n abstract getDetails(): TAttributeDetails;\n\n /**\n * Gets whether this attribute is a guard.\n */\n abstract isGuard: () => this is Guard;\n}\n", "import { Agent } from \"../../Agent\";\nimport Attribute, { AttributeDetails } from \"../Attribute\";\n\nexport type GuardAttributeDetails = {\n /** The name of the condition function that determines whether the guard is satisfied. */\n condition: string;\n} & AttributeDetails;\n\n/**\n * A base node guard attribute.\n */\nexport default abstract class Guard extends Attribute {\n /**\n * @param type The node attribute type.\n * @param args The array of decorator argument definitions.\n * @param condition The name of the condition function that determines whether the guard is satisfied.\n */\n constructor(type: string, args: any[], private condition: string) {\n super(type, args);\n }\n\n /**\n * Gets the name of the condition function that determines whether the guard is satisfied.\n */\n getCondition = () => this.condition;\n\n /**\n * Gets whether this attribute is a guard.\n */\n isGuard = () => true;\n\n /**\n * Gets the attribute details.\n */\n getDetails(): GuardAttributeDetails {\n return {\n type: this.type,\n args: this.args,\n condition: this.getCondition()\n };\n }\n\n /**\n * Gets whether the guard is satisfied.\n * @param agent The agent.\n * @returns Whether the guard is satisfied.\n */\n abstract isSatisfied(agent: Agent): boolean;\n}\n", "import Guard from \"./Guard\";\nimport Lookup from \"../../Lookup\";\nimport { Agent } from \"../../Agent\";\n\n/**\n * A WHILE guard which is satisfied as long as the given condition remains true.\n */\nexport default class While extends Guard {\n /**\n * @param condition The name of the condition function that determines whether the guard is satisfied.\n * @param args The array of decorator argument definitions.\n */\n constructor(condition: string, args: any[]) {\n super(\"while\", args, condition);\n }\n\n /**\n * Gets whether the guard is satisfied.\n * @param agent The agent.\n * @returns Whether the guard is satisfied.\n */\n isSatisfied = (agent: Agent) => {\n // Attempt to get the invoker for the condition function.\n const conditionFuncInvoker = Lookup.getFuncInvoker(agent, this.getCondition());\n\n // The condition function should be defined.\n if (conditionFuncInvoker === null) {\n throw new Error(\n `cannot evaluate node guard as the condition '${this.getCondition()}' function is not defined on the agent and has not been registered`\n );\n }\n\n let conditionFunctionResult;\n\n try {\n // Call the guard condition function to determine the state of this node, the result of which should be a boolean.\n conditionFunctionResult = conditionFuncInvoker(this.args);\n } catch (error) {\n // An uncaught error was thrown.\n if (error instanceof Error) {\n throw new Error(`guard condition function '${this.getCondition()}' threw: ${error.stack}`);\n } else {\n throw new Error(`guard condition function '${this.getCondition()}' threw: ${error}`);\n }\n }\n\n // The result of calling the guard condition function must be a boolean value.\n if (typeof conditionFunctionResult !== \"boolean\") {\n throw new Error(\n `expected guard condition function '${this.getCondition()}' to return a boolean but returned '${conditionFunctionResult}'`\n );\n }\n\n // Return whether this guard is satisfied.\n return conditionFunctionResult;\n };\n}\n", "import Guard from \"./Guard\";\nimport Lookup from \"../../Lookup\";\nimport { Agent } from \"../../Agent\";\n\n/**\n * An UNTIL guard which is satisfied as long as the given condition remains false.\n */\nexport default class Until extends Guard {\n /**\n * @param condition The name of the condition function that determines whether the guard is satisfied.\n * @param args The array of decorator argument definitions.\n */\n constructor(condition: string, args: any[]) {\n super(\"until\", args, condition);\n }\n\n /**\n * Gets whether the guard is satisfied.\n * @param agent The agent.\n * @returns Whether the guard is satisfied.\n */\n isSatisfied = (agent: Agent) => {\n // Attempt to get the invoker for the condition function.\n const conditionFuncInvoker = Lookup.getFuncInvoker(agent, this.getCondition());\n\n // The condition function should be defined.\n if (conditionFuncInvoker === null) {\n throw new Error(\n `cannot evaluate node guard as the condition '${this.getCondition()}' function is not defined on the agent and has not been registered`\n );\n }\n\n let conditionFunctionResult;\n\n try {\n // Call the guard condition function to determine the state of this node, the result of which should be a boolean.\n conditionFunctionResult = conditionFuncInvoker(this.args);\n } catch (error) {\n // An uncaught error was thrown.\n if (error instanceof Error) {\n throw new Error(`guard condition function '${this.getCondition()}' threw: ${error.stack}`);\n } else {\n throw new Error(`guard condition function '${this.getCondition()}' threw: ${error}`);\n }\n }\n\n // The result of calling the guard condition function must be a boolean value.\n if (typeof conditionFunctionResult !== \"boolean\") {\n throw new Error(\n `expected guard condition function '${this.getCondition()}' to return a boolean but returned '${conditionFunctionResult}'`\n );\n }\n\n // Return whether this guard is satisfied.\n return !conditionFunctionResult;\n };\n}\n", "import { Agent } from \"../../Agent\";\nimport Attribute, { AttributeDetails } from \"../Attribute\";\n\nexport type CallbackAttributeDetails = {\n /** The name of the agent function that is called. */\n functionName: string;\n} & AttributeDetails;\n\n/**\n * A base node callback attribute.\n */\nexport default abstract class Callback extends Attribute {\n /**\n * @param type The node attribute type.\n * @param args The array of decorator argument definitions.\n * @param functionName The name of the agent function to call.\n */\n constructor(type: string, args: any[], private functionName: string) {\n super(type, args);\n }\n\n /**\n * Gets the name of the agent function to call.\n */\n getFunctionName = () => this.functionName;\n\n /**\n * Gets whether this attribute is a guard.\n */\n isGuard = () => false;\n\n /**\n * Gets the attribute details.\n */\n getDetails(): CallbackAttributeDetails {\n return {\n type: this.type,\n args: this.args,\n functionName: this.getFunctionName()\n };\n }\n\n /**\n * Attempt to call the agent function that this callback refers to.\n * @param agent The agent.\n */\n abstract callAgentFunction: (agent: Agent, isSuccess: boolean, isAborted: boolean) => void;\n}\n", "import Callback from \"./Callback\";\nimport Lookup from \"../../Lookup\";\nimport { Agent } from \"../../Agent\";\n\n/**\n * An ENTRY callback which defines an agent function to call when the associated node is updated and moves out of running state.\n */\nexport default class Entry extends Callback {\n /**\n * @param functionName The name of the agent function to call.\n * @param args The array of callback argument definitions.\n */\n constructor(functionName: string, args: any[]) {\n super(\"entry\", args, functionName);\n }\n\n /**\n * Attempt to call the agent function that this callback refers to.\n * @param agent The agent.\n */\n callAgentFunction = (agent: Agent) => {\n // Attempt to get the invoker for the callback function.\n const callbackFuncInvoker = Lookup.getFuncInvoker(agent, this.getFunctionName());\n\n // The callback function should be defined.\n if (callbackFuncInvoker === null) {\n throw new Error(\n `cannot call entry function '${this.getFunctionName()}' as is not defined on the agent and has not been registered`\n );\n }\n\n // Call the callback function.\n callbackFuncInvoker(this.args);\n };\n}\n", "import Callback from \"./Callback\";\nimport Lookup from \"../../Lookup\";\nimport { Agent } from \"../../Agent\";\n\n/**\n * A STEP callback which defines an agent function to call when the associated node is updated.\n */\nexport default class Step extends Callback {\n /**\n * @param functionName The name of the agent function to call.\n * @param args The array of callback argument definitions.\n */\n constructor(functionName: string, args: any[]) {\n super(\"step\", args, functionName);\n }\n\n /**\n * Attempt to call the agent function that this callback refers to.\n * @param agent The agent.\n */\n callAgentFunction = (agent: Agent) => {\n // Attempt to get the invoker for the callback function.\n const callbackFuncInvoker = Lookup.getFuncInvoker(agent, this.getFunctionName());\n\n // The callback function should be defined.\n if (callbackFuncInvoker === null) {\n throw new Error(\n `cannot call step function '${this.getFunctionName()}' as is not defined on the agent and has not been registered`\n );\n }\n\n // Call the callback function.\n callbackFuncInvoker(this.args);\n };\n}\n", "import Callback from \"./Callback\";\nimport Lookup from \"../../Lookup\";\nimport { Agent } from \"../../Agent\";\n\n/**\n * An EXIT callback which defines an agent function to call when the associated node is updated and moves to a finished state or is aborted.\n */\nexport default class Exit extends Callback {\n /**\n * @param functionName The name of the agent function to call.\n * @param args The array of callback argument definitions.\n */\n constructor(functionName: string, args: any[]) {\n super(\"exit\", args, functionName);\n }\n\n /**\n * Attempt to call the agent function that this callback refers to.\n * @param agent The agent.\n * @param isSuccess Whether the decorated node was left with a success state.\n * @param isAborted Whether the decorated node was aborted.\n */\n callAgentFunction = (agent: Agent, isSuccess: boolean, isAborted: boolean) => {\n // Attempt to get the invoker for the callback function.\n const callbackFuncInvoker = Lookup.getFuncInvoker(agent, this.getFunctionName());\n\n // The callback function should be defined.\n if (callbackFuncInvoker === null) {\n throw new Error(\n `cannot call exit function '${this.getFunctionName()}' as is not defined on the agent and has not been registered`\n );\n }\n\n // Call the callback function\n callbackFuncInvoker([{ succeeded: isSuccess, aborted: isAborted }, ...this.args]);\n };\n}\n", "import { AnyNodeDefinition, RootNodeDefinition } from \"./BehaviourTreeDefinition\";\nimport GuardPath, { GuardPathPart } from \"./attributes/guards/GuardPath\";\nimport { validateBranchSubtreeLinks } from \"./BehaviourTreeDefinitionValidator\";\nimport { isInteger } from \"./BehaviourTreeDefinitionUtilities\";\nimport Node from \"./nodes/Node\";\nimport Composite from \"./nodes/composite/Composite\";\nimport Decorator from \"./nodes/decorator/Decorator\";\nimport Parallel from \"./nodes/composite/Parallel\";\nimport Selector from \"./nodes/composite/Selector\";\nimport Sequence from \"./nodes/composite/Sequence\";\nimport Lotto from \"./nodes/composite/Lotto\";\nimport Fail from \"./nodes/decorator/Fail\";\nimport Flip from \"./nodes/decorator/Flip\";\nimport Repeat from \"./nodes/decorator/Repeat\";\nimport Retry from \"./nodes/decorator/Retry\";\nimport Root from \"./nodes/decorator/Root\";\nimport Succeed from \"./nodes/decorator/Succeed\";\nimport Action from \"./nodes/leaf/Action\";\nimport Condition from \"./nodes/leaf/Condition\";\nimport Wait from \"./nodes/leaf/Wait\";\nimport Lookup from \"./Lookup\";\nimport Attribute from \"./attributes/Attribute\";\nimport While from \"./attributes/guards/While\";\nimport Until from \"./attributes/guards/Until\";\nimport Entry from \"./attributes/callbacks/Entry\";\nimport Step from \"./attributes/callbacks/Step\";\nimport Exit from \"./attributes/callbacks/Exit\";\n\n/**\n * A type representing any node instance in a behaviour tree.\n */\ntype AnyNode =\n | Root\n | Action\n | Condition\n | Wait\n | Sequence\n | Selector\n | Lotto\n | Parallel\n | Repeat\n | Retry\n | Flip\n | Succeed\n | Fail;\n\n/**\n * A type defining a mapping of root node identifiers to root node definitions.\n */\ntype RootNodeDefinitionMap = { [key: string | symbol]: RootNodeDefinition };\n\n/**\n * A symbol to use as the main root key in any root node mappings.\n */\nconst MAIN_ROOT_NODE_KEY = Symbol(\"__root__\");\n\n/**\n * Build and populate the root nodes based on the provided definition, assuming that the definition has been validated.\n * @param definition The root node definitions.\n * @returns The built and populated root node definitions.\n */\nexport default function buildRootNode(definition: RootNodeDefinition[]): Root {\n // Create a mapping of root node identifers to root node definitions, including globally registered subtree root node definitions.\n const rootNodeDefinitionMap = createRootNodeDefinitionMap(definition);\n\n // Now that we have all of our root node definitions (those part of the tree definition and those globally registered)\n // we should validate the branch-subtree links. This will also double-check that we dont have any circular dependencies\n // in our branch-subtree references and that we have no broken branch-subtree links.\n validateBranchSubtreeLinks(\n [rootNodeDefinitionMap[MAIN_ROOT_NODE_KEY], ...Object.values(rootNodeDefinitionMap)],\n true\n );\n\n // Create our populated tree of node instances, starting with our main root node.\n const rootNode = nodeFactory(rootNodeDefinitionMap[MAIN_ROOT_NODE_KEY], rootNodeDefinitionMap) as Root;\n\n // Set a guard path on every leaf of the tree to evaluate as part of each update.\n applyLeafNodeGuardPaths(rootNode);\n\n // We only need to return the main root node.\n return rootNode;\n}\n\n/**\n * A factory function which creates a node instance based on the specified definition.\n * @param definition The node definition.\n * @param rootNodeDefinitionMap The mapping of root node identifers to root node definitions, including globally registered subtree root node definitions.\n * @returns A node instance based on the specified definition.\n */\nfunction nodeFactory(definition: AnyNodeDefinition, rootNodeDefinitionMap: RootNodeDefinitionMap): AnyNode {\n // Get the attributes for the node.\n const attributes = nodeAttributesFactory(definition);\n\n // Create the node instance based on the definition type.\n switch (definition.type) {\n case \"root\":\n return new Root(attributes, nodeFactory(definition.child, rootNodeDefinitionMap));\n\n case \"repeat\":\n let iterations: number | null = null;\n let iterationsMin: number | null = null;\n let iterationsMax: number | null = null;\n\n if (Array.isArray(definition.iterations)) {\n iterationsMin = definition.iterations[0];\n iterationsMax = definition.iterations[1];\n } else if (isInteger(definition.iterations)) {\n iterations = definition.iterations!;\n }\n\n return new Repeat(\n attributes,\n iterations,\n iterationsMin,\n iterationsMax,\n nodeFactory(definition.child, rootNodeDefinitionMap)\n );\n\n case \"retry\":\n let attempts: number | null = null;\n let attemptsMin: number | null = null;\n let attemptsMax: number | null = null;\n\n if (Array.isArray(definition.attempts)) {\n attemptsMin = definition.attempts[0];\n attemptsMax = definition.attempts[1];\n } else if (isInteger(definition.attempts)) {\n attempts = definition.attempts!;\n }\n\n return new Retry(\n attributes,\n attempts,\n attemptsMin,\n attemptsMax,\n nodeFactory(definition.child, rootNodeDefinitionMap)\n );\n\n case \"flip\":\n return new Flip(attributes, nodeFactory(definition.child, rootNodeDefinitionMap));\n\n case \"succeed\":\n return new Succeed(attributes, nodeFactory(definition.child, rootNodeDefinitionMap));\n\n case \"fail\":\n return new Fail(attributes, nodeFactory(definition.child, rootNodeDefinitionMap));\n\n case \"sequence\":\n return new Sequence(\n attributes,\n definition.children.map((child) => nodeFactory(child, rootNodeDefinitionMap))\n );\n\n case \"selector\":\n return new Selector(\n attributes,\n definition.children.map((child) => nodeFactory(child, rootNodeDefinitionMap))\n );\n\n case \"parallel\":\n return new Parallel(\n attributes,\n definition.children.map((child) => nodeFactory(child, rootNodeDefinitionMap))\n );\n\n case \"lotto\":\n return new Lotto(\n attributes,\n definition.weights,\n definition.children.map((child) => nodeFactory(child, rootNodeDefinitionMap))\n );\n\n case \"branch\":\n return nodeFactory(rootNodeDefinitionMap[definition.ref].child, rootNodeDefinitionMap);\n\n case \"action\":\n return new Action(attributes, definition.call, definition.args || []);\n\n case \"condition\":\n return new Condition(attributes, definition.call, definition.args || []);\n\n case \"wait\":\n let duration: number | null = null;\n let durationMin: number | null = null;\n let durationMax: number | null = null;\n\n if (Array.isArray(definition.duration)) {\n durationMin = definition.duration[0];\n durationMax = definition.duration[1];\n } else if (isInteger(definition.duration)) {\n duration = definition.duration!;\n }\n\n return new Wait(attributes, duration, durationMin, durationMax);\n }\n}\n\n/**\n * Creates an array of node attribute instances based on the specified node definition.\n * @param definition The node definition.\n * @returns An array of node attribute instances based on the specified node definition.\n */\nfunction nodeAttributesFactory(definition: AnyNodeDefinition): Attribute[] {\n const attributes: Attribute[] = [];\n\n if (definition.while) {\n attributes.push(new While(definition.while.call, definition.while.args ?? []));\n }\n\n if (definition.until) {\n attributes.push(new Until(definition.until.call, definition.until.args ?? []));\n }\n\n if (definition.entry) {\n attributes.push(new Entry(definition.entry.call, definition.entry.args ?? []));\n }\n\n if (definition.step) {\n attributes.push(new Step(definition.step.call, definition.step.args ?? []));\n }\n\n if (definition.exit) {\n attributes.push(new Exit(definition.exit.call, definition.exit.args ?? []));\n }\n\n return attributes;\n}\n\n/**\n * Creates a mapping of root node identifers to root node definitions, mixing in globally registered subtree root node definitions.\n * @param definition The root node definitions.\n * @returns A mapping of root node identifers to root node definitions, including globally registered subtree root node definitions.\n */\nfunction createRootNodeDefinitionMap(definition: RootNodeDefinition[]): RootNodeDefinitionMap {\n // Create a mapping of root node identifers to root node definitions.\n const rootNodeMap: RootNodeDefinitionMap = {};\n\n // Add in any registered subtree root node definitions.\n for (const [name, rootNodeDefinition] of Object.entries(Lookup.getSubtrees())) {\n // The name used when registering the subtree will be used as the root node identifier.\n rootNodeMap[name] = { ...rootNodeDefinition, id: name };\n }\n\n // Populate the map with the root node definitions that were included with the tree definition.\n // We do this after adding any registered subtrees as we want these to take presedence.\n for (const rootNodeDefinition of definition) {\n rootNodeMap[rootNodeDefinition.id ?? MAIN_ROOT_NODE_KEY] = rootNodeDefinition;\n }\n\n return rootNodeMap;\n}\n\n/**\n * Applies a guard path to every leaf of the tree to evaluate as part of each update.\n * @param root The main root tree node.\n */\nfunction applyLeafNodeGuardPaths(root: Root) {\n const nodePaths: Node[][] = [];\n\n const findLeafNodes = (path: Node[], node: Node) => {\n // Add the current node to the path.\n path = path.concat(node);\n\n // Check whether the current node is a leaf node.\n if (node.isLeafNode()) {\n nodePaths.push(path);\n } else {\n (node as Composite | Decorator).getChildren().forEach((child) => findLeafNodes(path, child));\n }\n };\n\n // Find all leaf node paths, starting from the root.\n findLeafNodes([], root);\n\n nodePaths.forEach((path) => {\n // Each node in the current path will have to be assigned a guard path, working from the root outwards.\n for (let depth = 0; depth < path.length; depth++) {\n // Get the node in the path at the current depth.\n const currentNode = path[depth];\n\n // The node may already have been assigned a guard path, if so just skip it.\n if (currentNode.hasGuardPath()) {\n continue;\n }\n\n // Create the guard path for the current node.\n const guardPath = new GuardPath(\n path\n .slice(0, depth + 1)\n .map((node) => ({ node, guards: node.getGuardAttributes() }))\n .filter((details) => details.guards.length > 0)\n );\n\n // Assign the guard path to the current node.\n currentNode.setGuardPath(guardPath);\n }\n });\n}\n", "import State, { AnyState } from \"./State\";\nimport Lookup from \"./Lookup\";\nimport Node from \"./nodes/Node\";\nimport Root from \"./nodes/decorator/Root\";\nimport Composite from \"./nodes/composite/Composite\";\nimport Decorator from \"./nodes/decorator/Decorator\";\nimport { Agent, GlobalFunction } from \"./Agent\";\nimport { CallbackAttributeDetails } from \"./attributes/callbacks/Callback\";\nimport { GuardAttributeDetails } from \"./attributes/guards/Guard\";\nimport { BehaviourTreeOptions } from \"./BehaviourTreeOptions\";\nimport { convertMDSLToJSON } from \"./mdsl/MDSLDefinitionParser\";\nimport { RootNodeDefinition } from \"./BehaviourTreeDefinition\";\nimport { validateDefinition, validateJSONDefinition } from \"./BehaviourTreeDefinitionValidator\";\nimport buildRootNode from \"./BehaviourTreeBuilder\";\nimport { isNullOrUndefined } from \"./BehaviourTreeDefinitionUtilities\";\n\n// Purely for outside inspection of the tree.\nexport type FlattenedTreeNode = {\n id: string;\n type: string;\n caption: string;\n state: AnyState;\n guards: GuardAttributeDetails[];\n callbacks: CallbackAttributeDetails[];\n args: any[];\n parentId: string | null;\n};\n\n/**\n * A representation of a behaviour tree.\n */\nexport class BehaviourTree {\n /**\n * The main root tree node.\n */\n private readonly _rootNode: Root;\n\n /**\n * Creates a new instance of the BehaviourTree class.\n * @param definition The behaviour tree definition as either an MDSL string, root node definition object or array of root node definition objects.\n * @param agent The agent instance that this behaviour tree is modelling behaviour for.\n * @param options The behaviour tree options object.\n */\n constructor(\n definition: string | RootNodeDefinition | RootNodeDefinition[],\n private agent: Agent,\n private options: BehaviourTreeOptions = {}\n ) {\n // The tree definition must be defined.\n if (isNullOrUndefined(definition)) {\n throw new Error(\"tree definition not defined\");\n }\n\n // The agent must be defined and not null.\n if (typeof agent !== \"object\" || agent === null) {\n throw new Error(\"the agent must be an object and not null\");\n }\n\n // We should validate the definition before we try to build the tree nodes.\n const { succeeded, errorMessage, json } = validateDefinition(definition);\n\n // Did our validation fail without error?\n if (!succeeded) {\n throw new Error(`invalid definition: ${errorMessage}`);\n }\n\n // Double check that we did actually get our json definition as part of our definition validtion.\n if (!json) {\n throw new Error(\n \"expected json definition to be returned as part of successful definition validation response\"\n );\n }\n\n try {\n // Create the populated tree of behaviour tree nodes and get the root node.\n this._rootNode = buildRootNode(json);\n } catch (exception) {\n // There was an issue in trying build and populate the behaviour tree.\n throw new Error(`error building tree: ${(exception as Error).message}`);\n }\n }\n\n /**\n * Gets whether the tree is in the RUNNING state.\n * @returns true if the tree is in the RUNNING state, otherwise false.\n */\n isRunning() {\n return this._rootNode.getState() === State.RUNNING;\n }\n\n /**\n * Gets the current tree state of SUCCEEDED, FAILED, READY or RUNNING.\n * @returns The current tree state.\n */\n getState() {\n return this._rootNode.getState();\n }\n\n /**\n * Step the tree.\n * 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.\n * 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\n * 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.\n *\n * 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.\n */\n step() {\n // If the root node has already been stepped to completion then we need to reset it.\n if (this._rootNode.getState() === State.SUCCEEDED || this._rootNode.getState() === State.FAILED) {\n this._rootNode.reset();\n }\n\n try {\n this._rootNode.update(this.agent, this.options);\n } catch (exception) {\n throw new Error(`error stepping tree: ${(exception as Error).message}`);\n }\n }\n\n /**\n * Resets the tree from the root node outwards to each nested node, giving each a state of READY.\n */\n reset() {\n this._rootNode.reset();\n }\n\n /**\n * Gets the flattened details of every node in the tree.\n * @returns The flattened details of every node in the tree.\n */\n getFlattenedNodeDetails(): FlattenedTreeNode[] {\n // Create an empty flattened array of tree nodes.\n const flattenedTreeNodes: FlattenedTreeNode[] = [];\n\n /**\n * Helper function to process a node instance and push details into the flattened tree nodes array.\n * @param node The current node.\n * @param parentUid The UID of the node parent, or null if the node is the main root node.\n */\n const processNode = (node: Node, parentUid: string | null) => {\n // Get the guard and callback attribute details for this node.\n const guards = node\n .getAttributes()\n .filter((attribute) => attribute.isGuard())\n .map((attribute) => attribute.getDetails()) as GuardAttributeDetails[];\n const callbacks = node\n .getAttributes()\n .filter((attribute) => !attribute.isGuard())\n .map((attribute) => attribute.getDetails()) as CallbackAttributeDetails[];\n\n // Push the current node into the flattened nodes array.\n flattenedTreeNodes.push({\n id: node.getUid(),\n type: node.getType(),\n caption: node.getName(),\n state: node.getState(),\n guards,\n callbacks,\n args: node.getArguments(),\n parentId: parentUid\n });\n\n // Process each of the nodes children if it is not a leaf node.\n if (!node.isLeafNode()) {\n (node as Composite | Decorator)\n .getChildren()\n .forEach((child) => processNode(child, (node as Composite | Decorator).getUid()));\n }\n };\n\n // Convert the nested node structure into a flattened array of node details.\n processNode(this._rootNode, null);\n\n return flattenedTreeNodes;\n }\n\n /**\n * Registers the action/condition/guard/callback function or subtree with the given name.\n * @param name The name of the function or subtree to register.\n * @param value The function or subtree definition to register.\n */\n static register(name: string, value: GlobalFunction | string | RootNodeDefinition) {\n // Are we going to register a action/condition/guard/callback function?\n if (typeof value === \"function\") {\n Lookup.setFunc(name, value);\n return;\n }\n\n // We are not registering an action/condition/guard/callback function, so we must be registering a subtree.\n if (typeof value === \"string\") {\n let rootNodeDefinitions: RootNodeDefinition[];\n\n // We will assume that any string passed in will be a mdsl definition.\n try {\n rootNodeDefinitions = convertMDSLToJSON(value);\n } catch (exception) {\n throw new Error(`error registering definition, invalid MDSL: ${(exception as Error).message}`);\n }\n\n // This function should only ever be called with a definition containing a single unnamed root node.\n if (rootNodeDefinitions.length != 1 || typeof rootNodeDefinitions[0].id !== \"undefined\") {\n throw new Error(\"error registering definition: expected a single unnamed root node\");\n }\n\n try {\n // We should validate the subtree as we don't want invalid subtrees available via the lookup.\n const { succeeded, errorMessage } = validateJSONDefinition(rootNodeDefinitions[0]);\n\n // Did our validation fail without error?\n if (!succeeded) {\n throw new Error(errorMessage);\n }\n } catch (exception) {\n throw new Error(`error registering definition: ${(exception as Error).message}`);\n }\n\n // Everything seems hunky-dory, register the subtree.\n Lookup.setSubtree(name, rootNodeDefinitions[0]);\n } else if (typeof value === \"object\" && !Array.isArray(value)) {\n // We will assume that any object passed in is a root node definition.\n\n try {\n // We should validate the subtree as we don't want invalid subtrees available via the lookup.\n const { succeeded, errorMessage } = validateJSONDefinition(value);\n\n // Did our validation fail without error?\n if (!succeeded) {\n throw new Error(errorMessage);\n }\n } catch (exception) {\n throw new Error(`error registering definition: ${(exception as Error).message}`);\n }\n\n // Everything seems hunky-dory, register the subtree.\n Lookup.setSubtree(name, value);\n } else {\n throw new Error(\"unexpected value, expected string mdsl definition, root node json definition or function\");\n }\n }\n\n /**\n * Unregisters the registered action/condition/guard/callback function or subtree with the given name.\n * @param name The name of the registered action/condition/guard/callback function or subtree to unregister.\n */\n static unregister(name: string): void {\n Lookup.remove(name);\n }\n\n /**\n * Unregister all registered action/condition/guard/callback functions and subtrees.\n */\n static unregisterAll(): void {\n Lookup.empty();\n }\n}\n"], + "mappings": "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", "names": ["Participant", "isNullOrUndefined", "Lotto", "createLotto", "State", "createLotto"] } diff --git a/dist/index.js b/dist/index.js index b770958..64e6b29 100644 --- a/dist/index.js +++ b/dist/index.js @@ -892,6 +892,9 @@ function validateNode(definition, depth) { `node definition is not an object or 'type' property is not a non-empty string at depth '${depth}'` ); } + if (depth === 0 && definition.type !== "root") { + throw new Error(`expected root node at base of definition but got node of type '${definition.type}'`); + } switch (definition.type) { case "action": validateActionNode(definition, depth); diff --git a/dist/index.js.map b/dist/index.js.map index a80e4c3..ae867f4 100644 --- a/dist/index.js.map +++ b/dist/index.js.map @@ -1,7 +1,7 @@ { "version": 3, "sources": ["../node_modules/lotto-draw/dist/Participant.js", "../node_modules/lotto-draw/dist/Utilities.js", "../node_modules/lotto-draw/dist/Lotto.js", "../node_modules/lotto-draw/dist/createLotto.js", "../node_modules/lotto-draw/dist/index.js", "../src/index.ts", "../src/State.ts", "../src/BehaviourTreeDefinitionUtilities.ts", "../src/mdsl/MDSLUtilities.ts", "../src/mdsl/MDSLNodeArgumentParser.ts", "../src/mdsl/MDSLNodeAttributeParser.ts", "../src/mdsl/MDSLDefinitionParser.ts", "../src/BehaviourTreeDefinitionValidator.ts", "../src/Lookup.ts", "../src/attributes/guards/GuardUnsatisifedException.ts", "../src/attributes/guards/GuardPath.ts", "../src/nodes/Node.ts", "../src/nodes/composite/Composite.ts", "../src/nodes/composite/Parallel.ts", "../src/nodes/composite/Selector.ts", "../src/nodes/composite/Sequence.ts", "../src/nodes/composite/Lotto.ts", "../src/nodes/decorator/Decorator.ts", "../src/nodes/decorator/Fail.ts", "../src/nodes/decorator/Flip.ts", "../src/nodes/decorator/Repeat.ts", "../src/nodes/decorator/Retry.ts", "../src/nodes/decorator/Root.ts", "../src/nodes/decorator/Succeed.ts", "../src/nodes/leaf/Leaf.ts", "../src/nodes/leaf/Action.ts", "../src/nodes/leaf/Condition.ts", "../src/nodes/leaf/Wait.ts", "../src/attributes/Attribute.ts", "../src/attributes/guards/Guard.ts", "../src/attributes/guards/While.ts", "../src/attributes/guards/Until.ts", "../src/attributes/callbacks/Callback.ts", "../src/attributes/callbacks/Entry.ts", "../src/attributes/callbacks/Step.ts", "../src/attributes/callbacks/Exit.ts", "../src/BehaviourTreeBuilder.ts", "../src/BehaviourTree.ts"], - "sourcesContent": ["\"use strict\";\r\nObject.defineProperty(exports, \"__esModule\", { value: true });\r\nexports.Participant = void 0;\r\n/**\r\n * A participant that holds a number of tickets.\r\n */\r\nvar Participant = /** @class */ (function () {\r\n /**\r\n * Creates an instance of the Participant class.\r\n * @param participant The actual participant.\r\n * @param tickets The number of tickets held by the participant.\r\n */\r\n function Participant(participant, tickets) {\r\n if (tickets === void 0) { tickets = 1; }\r\n this._participant = participant;\r\n this._tickets = tickets;\r\n }\r\n Object.defineProperty(Participant.prototype, \"participant\", {\r\n /** Gets the actual participant. */\r\n get: function () {\r\n return this._participant;\r\n },\r\n enumerable: false,\r\n configurable: true\r\n });\r\n Object.defineProperty(Participant.prototype, \"tickets\", {\r\n /** Gets or sets the number of tickets held by the participant. */\r\n get: function () {\r\n return this._tickets;\r\n },\r\n set: function (value) {\r\n this._tickets = value;\r\n },\r\n enumerable: false,\r\n configurable: true\r\n });\r\n return Participant;\r\n}());\r\nexports.Participant = Participant;\r\n", "\"use strict\";\r\nObject.defineProperty(exports, \"__esModule\", { value: true });\r\nexports.isNaturalNumber = exports.isNullOrUndefined = void 0;\r\n/**\r\n * Gets whether the value provided is null or undefined.\r\n * @param value The value to check.\r\n * @returns Whether the value provided is null or undefined.\r\n */\r\nfunction isNullOrUndefined(value) {\r\n return value === null || value === undefined;\r\n}\r\nexports.isNullOrUndefined = isNullOrUndefined;\r\n/**\r\n * Gets whether the value provided is a natural number.\r\n * @param value The value to check.\r\n * @returns Whether the value provided is a natural number.\r\n */\r\nfunction isNaturalNumber(value) {\r\n return typeof value === \"number\" && value >= 1 && Math.floor(value) === value;\r\n}\r\nexports.isNaturalNumber = isNaturalNumber;\r\n", "\"use strict\";\r\nObject.defineProperty(exports, \"__esModule\", { value: true });\r\nexports.Lotto = void 0;\r\nvar Participant_1 = require(\"./Participant\");\r\nvar Utilities_1 = require(\"./Utilities\");\r\n/**\r\n * Represents a lotto consisting of a number of pickable ticket-holding participants.\r\n */\r\nvar Lotto = /** @class */ (function () {\r\n /**\r\n * Creates a new instance of Lotto.\r\n * @param customRandom The custom RNG to use in place of Math.random().\r\n */\r\n function Lotto(customRandom) {\r\n /** The array of participants that are holding tickets in the lotto. */\r\n this._participants = [];\r\n this._customRandom = customRandom;\r\n }\r\n /**\r\n * Adds a participant with the specified number of tickets, or adds to the participant ticket count if the participant already holds tickets.\r\n * @param participant The participant to add or to increase the ticket count for if they already hold tickets.\r\n * @param tickets The number of tickets, defaults to 1.\r\n * @returns The Lotto instance.\r\n */\r\n Lotto.prototype.add = function (participant, tickets) {\r\n if (tickets === void 0) { tickets = 1; }\r\n // Check that we have a valid ticket count.\r\n if (!(0, Utilities_1.isNaturalNumber)(tickets)) {\r\n throw new Error(\"tickets value must be a natural number\");\r\n }\r\n // Check whether this participant has already been added.\r\n var existingParticipant = this._participants.find(function (part) { return part.participant === participant; });\r\n if (existingParticipant) {\r\n // The participant has already been added to the lotto so just add to their ticket count.\r\n existingParticipant.tickets += tickets;\r\n }\r\n else {\r\n // The participant is not part of the lotto so we should add them.\r\n this._participants.push(new Participant_1.Participant(participant, tickets));\r\n }\r\n return this;\r\n };\r\n /**\r\n * Removes the specified number of tickets for the given participant from the draw, or all tickets if a ticket number is not defined.\r\n * @param participant The participant to remove tickets for.\r\n * @param tickets The number of tickets to remove, or undefined if all tickets are to be removed.\r\n * @returns The Lotto instance.\r\n */\r\n Lotto.prototype.remove = function (participant, tickets) {\r\n // Attempt to get the existing participant.\r\n var existingParticipant = this._participants.find(function (part) { return part.participant === participant; });\r\n // There is nothing to do if the specified participant isn't even part of the lotto.\r\n if (!existingParticipant) {\r\n return this;\r\n }\r\n // Check whether a tickets value was given.\r\n if (tickets !== undefined) {\r\n // Check that we have a valid ticket count.\r\n if (!(0, Utilities_1.isNaturalNumber)(tickets)) {\r\n throw new Error(\"tickets value must be a natural number\");\r\n }\r\n existingParticipant.tickets -= tickets;\r\n // If the participant no longer holds any tickets then they should be removed.\r\n if (existingParticipant.tickets < 1) {\r\n this._participants = this._participants.filter(function (part) { return part !== existingParticipant; });\r\n }\r\n }\r\n else {\r\n // We are removing all tickets for the participant so just remove them from the lotto.\r\n this._participants = this._participants.filter(function (part) { return part !== existingParticipant; });\r\n }\r\n return this;\r\n };\r\n /**\r\n * Draw a winning ticket and return the participant that holds the ticket.\r\n * @param options The draw options.\r\n * @returns The participant that holds the winning ticket.\r\n */\r\n Lotto.prototype.draw = function (options) {\r\n if (options === void 0) { options = {}; }\r\n // If we have no participants then just return null.\r\n if (this._participants.length === 0) {\r\n return null;\r\n }\r\n var redrawable = (0, Utilities_1.isNullOrUndefined)(options.redrawable) ? true : options.redrawable;\r\n var pickable = [];\r\n this._participants.forEach(function (_a) {\r\n var participant = _a.participant, tickets = _a.tickets;\r\n for (var ticketCount = 0; ticketCount < tickets; ticketCount++) {\r\n pickable.push(participant);\r\n }\r\n });\r\n var random;\r\n // We need a random floating-point number between 0 (inclusive) and 1 to scale up to pick our winner.\r\n // If a custom random function exists then we should use that or fall back to Math.random().\r\n if (this._customRandom) {\r\n // Call our custom random function to get a random floating-point number.\r\n random = this._customRandom();\r\n // Verify that the result of calling our custom random function is a number between 0 (inclusive) and 1.\r\n if (typeof random !== \"number\" || random < 0 || random >= 1) {\r\n throw new Error(\"the 'random' function provided did not return a number between 0 (inclusive) and 1\");\r\n }\r\n }\r\n else {\r\n // No custom random function was defined so just use good ol' Math.random().\r\n random = Math.random();\r\n }\r\n // Pick a winning participant.\r\n var winner = pickable[Math.floor(random * pickable.length)];\r\n // If the ticket isn't redrawable then we should remove a ticket from the winning participants ticket count.\r\n if (!redrawable) {\r\n this.remove(winner, 1);\r\n }\r\n // Return the winning participant.\r\n return winner;\r\n };\r\n /**\r\n * Draws multiple winning tickets and return an array of the participants that hold the winning tickets.\r\n * @param tickets The number of winning tickets to draw.\r\n * @param options The draw multiple options.\r\n * @returns An array of the participants that hold the winning tickets.\r\n */\r\n Lotto.prototype.drawMultiple = function (tickets, options) {\r\n if (options === void 0) { options = {}; }\r\n var uniqueResults = (0, Utilities_1.isNullOrUndefined)(options.unique) ? false : options.unique;\r\n // Handle cases where the user has asked for zero tickets (no idea why they would do this be we should trust them).\r\n if (tickets === 0) {\r\n return [];\r\n }\r\n // Now that we know out tickets value is not zero we should check that it is a valid natural number.\r\n if (!(0, Utilities_1.isNaturalNumber)(tickets)) {\r\n throw new Error(\"tickets value must be a natural number\");\r\n }\r\n var result = [];\r\n // Keep drawing tickets until we either reach the number of required tickets or we simply run out of tickets to draw.\r\n // We can run out of tickets to draw if 'options.redrawable' is explicity 'false' or we just had no participants when 'drawMultiple' was called.\r\n while (result.length < tickets && this._participants.length > 0) {\r\n result.push(this.draw(options));\r\n }\r\n // If the 'unique' draw option is set then we need to remove duplicates from the result list.\r\n if (uniqueResults) {\r\n // Create an array to store our unique results.\r\n var unique = [];\r\n // Iterate over all of our participants (with potential duplicates) and populate our array of unique values.\r\n for (var _i = 0, result_1 = result; _i < result_1.length; _i++) {\r\n var participant = result_1[_i];\r\n if (unique.indexOf(participant) === -1) {\r\n unique.push(participant);\r\n }\r\n }\r\n result = unique;\r\n }\r\n return result;\r\n };\r\n return Lotto;\r\n}());\r\nexports.Lotto = Lotto;\r\n", "\"use strict\";\r\nObject.defineProperty(exports, \"__esModule\", { value: true });\r\nexports.createLotto = void 0;\r\nvar Lotto_1 = require(\"./Lotto\");\r\n/**\r\n * A function that creates and returns a Lotto instance.\r\n * @param participantsOrOptions An array of initial participants or options relating to the creation of a Lotto instance.\r\n * @returns A new Lotto instance.\r\n */\r\nfunction createLotto(participantsOrOptions) {\r\n // If no initial participants or lotto options were provided as an argument then we can just return a new lotto instance now.\r\n if (!participantsOrOptions) {\r\n return new Lotto_1.Lotto();\r\n }\r\n // Check whether we were provided with an array of initial participants or a lotto options object.\r\n if (Array.isArray(participantsOrOptions)) {\r\n // We are dealing with a pre-defined array of participants.\r\n var participants = participantsOrOptions;\r\n var lotto_1 = new Lotto_1.Lotto();\r\n // If the lotto participants have been defined upfront then we will need to add them all to our lotto instance now.\r\n participants.forEach(function (_a) {\r\n var participant = _a[0], tokens = _a[1];\r\n return lotto_1.add(participant, tokens);\r\n });\r\n // Return the Lotto instance.\r\n return lotto_1;\r\n }\r\n else {\r\n // We are dealing with some lotto options.\r\n var random = participantsOrOptions.random, participants = participantsOrOptions.participants;\r\n // Create a Lotto instance passing the custom RNG function to use in place of Math.random() (which could be undefined).\r\n var lotto_2 = new Lotto_1.Lotto(random);\r\n // If the lotto participants have been defined upfront as part of the options then we will need to add them all to our lotto instance now.\r\n if (participants) {\r\n participants.forEach(function (_a) {\r\n var participant = _a[0], tokens = _a[1];\r\n return lotto_2.add(participant, tokens);\r\n });\r\n }\r\n // Return the Lotto instance.\r\n return lotto_2;\r\n }\r\n}\r\nexports.createLotto = createLotto;\r\n", "\"use strict\";\r\nObject.defineProperty(exports, \"__esModule\", { value: true });\r\nvar createLotto_1 = require(\"./createLotto\");\r\nexports.default = createLotto_1.createLotto;\r\n", "import State from \"./State\";\nimport { validateDefinition } from \"./BehaviourTreeDefinitionValidator\";\nimport { convertMDSLToJSON } from \"./mdsl/MDSLDefinitionParser\";\nimport { BehaviourTree, FlattenedTreeNode } from \"./BehaviourTree\";\nimport { BehaviourTreeOptions } from \"./BehaviourTreeOptions\";\n\nexport { BehaviourTree, State, convertMDSLToJSON, validateDefinition };\nexport type { FlattenedTreeNode, BehaviourTreeOptions };\n", "/**\n * Enumeration of node state types.\n */\nexport enum State {\n READY = \"mistreevous.ready\",\n RUNNING = \"mistreevous.running\",\n SUCCEEDED = \"mistreevous.succeeded\",\n FAILED = \"mistreevous.failed\"\n}\n\nexport { State as default };\n\nexport type CompleteState = State.SUCCEEDED | State.FAILED;\nexport type AnyState = State.READY | State.RUNNING | CompleteState;\n", "import {\n NodeDefinition,\n RootNodeDefinition,\n DecoratorNodeDefinition,\n CompositeNodeDefinition,\n AnyNodeDefinition,\n BranchNodeDefinition\n} from \"./BehaviourTreeDefinition\";\n\n/**\n * A type guard function that returns true if the specified node satisfies the RootNodeDefinition type.\n * @param node The node.\n * @returns A value of true if the specified node satisfies the RootNodeDefinition type.\n */\nexport function isRootNode(node: NodeDefinition): node is RootNodeDefinition {\n return node.type === \"root\";\n}\n\n/**\n * A type guard function that returns true if the specified node satisfies the BranchNodeDefinition type.\n * @param node The node.\n * @returns A value of true if the specified node satisfies the BranchNodeDefinition type.\n */\nexport function isBranchNode(node: NodeDefinition): node is BranchNodeDefinition {\n return node.type === \"branch\";\n}\n\n/**\n * A type guard function that returns true if the specified node satisfies the NodeDefinition type.\n * @param node The node.\n * @returns A value of true if the specified node satisfies the NodeDefinition type.\n */\nexport function isLeafNode(node: NodeDefinition): node is NodeDefinition {\n return [\"branch\", \"action\", \"condition\", \"wait\"].includes(node.type);\n}\n\n/**\n * A type guard function that returns true if the specified node satisfies the DecoratorNodeDefinition type.\n * @param node The node.\n * @returns A value of true if the specified node satisfies the DecoratorNodeDefinition type.\n */\nexport function isDecoratorNode(node: NodeDefinition): node is DecoratorNodeDefinition {\n return [\"root\", \"repeat\", \"retry\", \"flip\", \"succeed\", \"fail\"].includes(node.type);\n}\n\n/**\n * A type guard function that returns true if the specified node satisfies the CompositeNodeDefinition type.\n * @param node The node.\n * @returns A value of true if the specified node satisfies the CompositeNodeDefinition type.\n */\nexport function isCompositeNode(node: NodeDefinition): node is CompositeNodeDefinition {\n return [\"sequence\", \"selector\", \"lotto\", \"parallel\"].includes(node.type);\n}\n\n/**\n * Flatten a node definition into an array of all of its nested node definitions.\n * @param nodeDefinition The node definition to flatten.\n * @returns An array of all of nested node definitions.\n */\nexport function flattenDefinition(nodeDefinition: AnyNodeDefinition): AnyNodeDefinition[] {\n const nodes: AnyNodeDefinition[] = [];\n\n const processNode = (currentNodeDefinition: AnyNodeDefinition) => {\n nodes.push(currentNodeDefinition);\n\n if (isCompositeNode(currentNodeDefinition)) {\n currentNodeDefinition.children.forEach(processNode);\n } else if (isDecoratorNode(currentNodeDefinition)) {\n processNode(currentNodeDefinition.child);\n }\n };\n\n processNode(nodeDefinition);\n\n return nodes;\n}\n\n/**\n * Determines whether the passed value is an integer.\n * @param value The value to check.\n * @returns Whether the passed value is an integer.\n */\nexport function isInteger(value: unknown): boolean {\n return typeof value === \"number\" && Math.floor(value) === value;\n}\n\n/**\n * Determines whether the passed value is null or undefined.\n * @param value The value to check.\n * @returns Whether the passed value is null or undefined.\n */\nexport function isNullOrUndefined(value: unknown): boolean {\n return typeof value === \"undefined\" || value === null;\n}\n", "/**\n * A type defining an object that holds a reference to substitued string literals parsed from the definition.\n */\nexport type StringLiteralPlaceholders = { [key: string]: string };\n\n/**\n * Pop the next raw token from the specified array of tokens and throw an error if it wasn't the expected one.\n * @param tokens The array of tokens.\n * @param expected An optional string or array or items, one of which must match the next popped token.\n * @returns The popped token.\n */\nexport function popAndCheck(tokens: string[], expected?: string | string[]): string {\n // Get and remove the next token.\n const popped = tokens.shift();\n\n // We were expecting another token but there aren't any.\n if (popped === undefined) {\n throw new Error(\"unexpected end of definition\");\n }\n\n // Do we have an expected token/tokens array?\n if (expected != undefined) {\n // Get an array of expected values, if the popped token matches any then we are all good.\n const expectedValues = typeof expected === \"string\" ? [expected] : expected;\n\n // Check whether the popped token matches at least one of our expected items.\n var tokenMatchesExpectation = expectedValues.some((item) => popped.toUpperCase() === item.toUpperCase());\n\n // Throw an error if the popped token didn't match any of our expected items.\n if (!tokenMatchesExpectation) {\n const expectationString = expectedValues.map((item) => \"'\" + item + \"'\").join(\" or \");\n throw new Error(\"unexpected token found. Expected \" + expectationString + \" but got '\" + popped + \"'\");\n }\n }\n\n // Return the popped token.\n return popped;\n}\n\n/**\n * Swaps out any node/attribute argument string literals with placeholders.\n * @param definition The definition.\n * @returns An object containing a mapping of placeholders to original string values as well as the processed definition string.\n */\nexport function substituteStringLiterals(definition: string): {\n placeholders: StringLiteralPlaceholders;\n processedDefinition: string;\n} {\n // Create an object to hold the mapping of placeholders to original string values.\n const placeholders: StringLiteralPlaceholders = {};\n\n // Replace any string literals wrapped with double quotes in our definition with placeholders to be processed later.\n const processedDefinition = definition.replace(/\\\"(\\\\.|[^\"\\\\])*\\\"/g, (match) => {\n var strippedMatch = match.substring(1, match.length - 1);\n var placeholder = Object.keys(placeholders).find((key) => placeholders[key] === strippedMatch);\n\n // If we have no existing string literal match then create a new placeholder.\n if (!placeholder) {\n placeholder = `@@${Object.keys(placeholders).length}@@`;\n placeholders[placeholder] = strippedMatch;\n }\n\n return placeholder;\n });\n\n return { placeholders, processedDefinition };\n}\n\n/**\n * Parse the tree definition into an array of raw tokens.\n * @param definition The definition.\n * @returns An array of tokens parsed from the definition.\n */\nexport function parseTokensFromDefinition(definition: string): string[] {\n // Add some space around various important characters so that they can be plucked out easier as individual tokens.\n definition = definition.replace(/\\(/g, \" ( \");\n definition = definition.replace(/\\)/g, \" ) \");\n definition = definition.replace(/\\{/g, \" { \");\n definition = definition.replace(/\\}/g, \" } \");\n definition = definition.replace(/\\]/g, \" ] \");\n definition = definition.replace(/\\[/g, \" [ \");\n definition = definition.replace(/\\,/g, \" , \");\n\n // Split the definition into raw token form and return it.\n return definition.replace(/\\s+/g, \" \").trim().split(\" \");\n}\n", "import { StringLiteralPlaceholders, popAndCheck } from \"./MDSLUtilities\";\n\n/**\n * A type representing any node function argument.\n */\ntype Argument = {\n /**\n * The argument value.\n */\n value: T;\n /**\n * The argument type, used for validation.\n */\n type: string;\n};\n\ntype NullArgument = Argument & {\n type: \"null\";\n};\n\ntype BooleanArgument = Argument & {\n type: \"boolean\";\n};\n\ntype NumberArgument = Argument & {\n type: \"number\";\n /**\n * A flag defining whether the number argument value is a valid integer. (used for validation)\n */\n isInteger: boolean;\n};\n\ntype StringPlaceholderArgument = Argument & {\n type: \"string\";\n};\n\ntype IdentifierArgument = Argument & {\n type: \"identifier\";\n};\n\n/**\n * A type representing a reference to any node function argument.\n */\ntype AnyArgument = NullArgument | BooleanArgument | NumberArgument | StringPlaceholderArgument | IdentifierArgument;\n\n/**\n * Parse an array of argument definitions from the specified tokens array.\n * @param tokens The array tokens to parse the argument definitions from.\n * @param stringArgumentPlaceholders The mapping of string literal node argument placeholders to original values.\n * @param argumentValidator The argument validator function.\n * @param validationFailedMessage The exception message to throw if argument validation fails.\n * @returns An array of argument definitions parsed from the specified tokens array.\n */\nexport function parseArgumentTokens(\n tokens: string[],\n stringArgumentPlaceholders: StringLiteralPlaceholders\n): AnyArgument[] {\n const argumentList: AnyArgument[] = [];\n\n // If the next token is not a '[' or '(' then we have no arguments to parse.\n if (![\"[\", \"(\"].includes(tokens[0])) {\n return argumentList;\n }\n\n // Any lists of arguments will always be wrapped in '[]' for node arguments or '()' for attribute arguments.\n // We are looking for a '[' or '(' opener that wraps the argument tokens and the relevant closer.\n const closingToken = popAndCheck(tokens, [\"[\", \"(\"]) === \"[\" ? \"]\" : \")\";\n\n const argumentListTokens: string[] = [];\n\n // Grab all tokens between the '[' and ']' or '(' and ')'.\n while (tokens.length && tokens[0] !== closingToken) {\n // The next token is part of our arguments list.\n argumentListTokens.push(tokens.shift()!);\n }\n\n // Validate the order of the argument tokens. Each token must either be a ',' or a single argument that satisfies the validator.\n argumentListTokens.forEach((token, index) => {\n // Get whether this token should be an actual argument.\n const shouldBeArgumentToken = !(index & 1);\n\n // If the current token should be an actual argument then validate it, otherwise it should be a ',' token.\n if (shouldBeArgumentToken) {\n // Get the argument definition.\n const argumentDefinition = getArgumentDefinition(token, stringArgumentPlaceholders);\n\n // This is a valid argument!\n argumentList.push(argumentDefinition);\n } else {\n // The current token should be a ',' token.\n if (token !== \",\") {\n throw new Error(`invalid argument list, expected ',' or ']' but got '${token}'`);\n }\n }\n });\n\n // The arguments list should terminate with a ']' or ')' token, depending on the opener.\n popAndCheck(tokens, closingToken);\n\n // Return the arguments.\n return argumentList;\n}\n\n/**\n * Gets an argument value definition.\n * @param token The argument token.\n * @param stringArgumentPlaceholders The mapping of string literal node argument placeholders to original values.\n * @returns An argument value definition.\n */\nfunction getArgumentDefinition(token: string, stringArgumentPlaceholders: StringLiteralPlaceholders): AnyArgument {\n // Check whether the token represents a null value.\n if (token === \"null\") {\n return {\n value: null,\n type: \"null\"\n } as NullArgument;\n }\n\n // Check whether the token represents a boolean value.\n if (token === \"true\" || token === \"false\") {\n return {\n value: token === \"true\",\n type: \"boolean\"\n } as BooleanArgument;\n }\n\n // Check whether the token represents a number value.\n // TODO: Relies on broken isNaN - see MDN.\n // if (!Number.isNaN(token)) {\n if (!isNaN(token as any)) {\n return {\n value: parseFloat(token),\n isInteger: parseFloat(token) === parseInt(token, 10),\n type: \"number\"\n } as NumberArgument;\n }\n\n // Check whether the token is a placeholder (e.g. @@0@@) representing a string literal.\n if (token.match(/^@@\\d+@@$/g)) {\n return {\n value: stringArgumentPlaceholders[token].replace('\\\\\"', '\"'),\n type: \"string\"\n } as StringPlaceholderArgument;\n }\n\n // The only remaining option is that the argument value is an identifier.\n return {\n value: token,\n type: \"identifier\"\n } as IdentifierArgument;\n}\n", "import { NodeAttributeDefinition } from \"../BehaviourTreeDefinition\";\nimport { parseArgumentTokens } from \"./MDSLNodeArgumentParser\";\nimport { StringLiteralPlaceholders } from \"./MDSLUtilities\";\n\n/**\n * A type defining the attribute definitions of a node.\n */\ntype NodeAttributes = {\n while?: NodeAttributeDefinition;\n until?: NodeAttributeDefinition;\n entry?: NodeAttributeDefinition;\n exit?: NodeAttributeDefinition;\n step?: NodeAttributeDefinition;\n};\n\n/**\n * Parse any node attribute definitions from the specified tokens array.\n * @param tokens The array of remaining tokens.\n * @param stringArgumentPlaceholders The mapping of string literal node argument placeholders to original values.\n * @returns An object of attribute definitions defined by any directly following tokens.\n */\nexport function parseAttributeTokens(\n tokens: string[],\n stringArgumentPlaceholders: StringLiteralPlaceholders\n): NodeAttributes {\n const nodeAttributeNames: (keyof NodeAttributes)[] = [\"while\", \"until\", \"entry\", \"exit\", \"step\"];\n\n // Create an object to hold any attributes found.\n const attributes: NodeAttributes = {};\n\n // Try to get the name of the attribute for the next token.\n let nextAttributeName = tokens[0]?.toLowerCase() as keyof NodeAttributes;\n\n // Pull attribute tokens as well as their arguments off of the tokens stack until we have no more.\n while (nodeAttributeNames.includes(nextAttributeName)) {\n // Check to make sure that we have not already created an attribute definition of this type.\n if (attributes[nextAttributeName]) {\n throw new Error(`duplicate attribute '${tokens[0].toUpperCase()}' found for node`);\n }\n\n // Remove the attribute name token from the array of tokens.\n tokens.shift();\n\n // Grab the attribute arguments, assuming the first to be an identifier.\n const [attributeCallIdentifier, ...attributeArguments] = parseArgumentTokens(\n tokens,\n stringArgumentPlaceholders\n );\n\n // The first attribute argument has to be an identifer, this will reference an agent function.\n if (attributeCallIdentifier?.type !== \"identifier\") {\n throw new Error(\"expected agent function or registered function name identifier argument for attribute\");\n }\n\n // Any attribute arguments (other than the expected call identifier) must have a type of string, number, boolean or null.\n attributeArguments\n .filter((arg) => arg.type === \"identifier\")\n .forEach((arg) => {\n throw new Error(\n `invalid attribute argument value '${arg.value}', must be string, number, boolean or null`\n );\n });\n\n // Create the attribute definition and add it to the object of attribute definitions found.\n attributes[nextAttributeName] = {\n call: attributeCallIdentifier.value,\n args: attributeArguments.map(({ value }) => value)\n };\n\n // Try to get the next attribute name token, as there could be multiple.\n nextAttributeName = tokens[0]?.toLowerCase() as keyof NodeAttributes;\n }\n\n return attributes;\n}\n", "import {\n ActionNodeDefinition,\n AnyChildNodeDefinition,\n AnyNodeDefinition,\n BranchNodeDefinition,\n ConditionNodeDefinition,\n FailNodeDefinition,\n FlipNodeDefinition,\n LottoNodeDefinition,\n ParallelNodeDefinition,\n RepeatNodeDefinition,\n RetryNodeDefinition,\n RootNodeDefinition,\n SelectorNodeDefinition,\n SequenceNodeDefinition,\n SucceedNodeDefinition,\n WaitNodeDefinition\n} from \"../BehaviourTreeDefinition\";\nimport {\n isCompositeNode,\n isDecoratorNode,\n isLeafNode,\n isNullOrUndefined,\n isRootNode\n} from \"../BehaviourTreeDefinitionUtilities\";\nimport { parseArgumentTokens } from \"./MDSLNodeArgumentParser\";\nimport { parseAttributeTokens } from \"./MDSLNodeAttributeParser\";\nimport {\n StringLiteralPlaceholders,\n parseTokensFromDefinition,\n popAndCheck,\n substituteStringLiterals\n} from \"./MDSLUtilities\";\n\n/**\n * Convert the MDSL tree definition string into an equivalent JSON definition.\n * @param definition The tree definition string as MDSL.\n * @returns The root node JSON definitions.\n */\nexport function convertMDSLToJSON(definition: string): RootNodeDefinition[] {\n // Swap out any node/attribute argument string literals with a placeholder and get a mapping of placeholders to original values as well as the processed definition.\n const { placeholders, processedDefinition } = substituteStringLiterals(definition);\n\n // Parse our definition definition string into an array of raw tokens.\n const tokens = parseTokensFromDefinition(processedDefinition);\n\n return convertTokensToJSONDefinition(tokens, placeholders);\n}\n\n/**\n * Converts the specified tree definition tokens into a JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The root node JSON definitions.\n */\nfunction convertTokensToJSONDefinition(\n tokens: string[],\n stringLiteralPlaceholders: StringLiteralPlaceholders\n): RootNodeDefinition[] {\n // There must be at least 3 tokens for the tree definition to be valid. 'ROOT', '{' and '}'.\n if (tokens.length < 3) {\n throw new Error(\"invalid token count\");\n }\n\n // We should have a matching number of '{' and '}' tokens. If not, then there are scopes that have not been properly closed.\n if (tokens.filter((token) => token === \"{\").length !== tokens.filter((token) => token === \"}\").length) {\n throw new Error(\"scope character mismatch\");\n }\n\n // Create an array of tree stack arrays where root nodes will always be at the botton and the current composite/decorator node at the top.\n // There should be an element in this array for every root node defined and every element should be an array with a root note as the first element.\n // E.g. A definition with two root nodes defined:\n // [\n // [root, lotto, sequence],\n // [root, selector]\n // ]\n const treeStacks: [Partial, ...Partial[]][] = [];\n\n // Create an array of all root node definitions that we create.\n const rootNodes: Partial[] = [];\n\n // A helper function used to push node definitions onto the tree stack.\n const pushNode = (node: AnyNodeDefinition) => {\n // If the node is a root node then we need to create a new tree stack array with the root node at the root.\n if (isRootNode(node)) {\n // We need to double-check that this root node is not the child of another node.\n // We can do this by checking whether the top tree stack is not empty (contains an existing node)\n if (treeStacks[treeStacks.length - 1]?.length) {\n throw new Error(\"a root node cannot be the child of another node\");\n }\n\n // Add the root node definition to our array of all parsed root node definitions.\n rootNodes.push(node);\n\n // Add the root node definition to the root of a new tree stack.\n treeStacks.push([node]);\n\n return;\n }\n\n // All non-root nodes should be pushed after their root nodes so handle cases\n // where we may not have any tree stacks or our top-most tree stack is empty.\n if (!treeStacks.length || !treeStacks[treeStacks.length - 1].length) {\n throw new Error(\"expected root node at base of definition\");\n }\n\n // Get the current tree stack that we are populating.\n const topTreeStack = treeStacks[treeStacks.length - 1];\n\n // Get the top-most node in the current tree stack, this will be a composite/decorator node\n // for which we will populate its children array if composite or setting its child if a decorator.\n const topTreeStackTopNode = topTreeStack[topTreeStack.length - 1] as AnyNodeDefinition;\n\n // If the top-most node in the current root stack is a composite or decorator\n // node then the current node should be added as a child of the top-most node.\n if (isCompositeNode(topTreeStackTopNode)) {\n topTreeStackTopNode.children = topTreeStackTopNode.children || [];\n topTreeStackTopNode.children.push(node);\n } else if (isDecoratorNode(topTreeStackTopNode)) {\n // If the top node already has a child node set then throw an error as a decorator should only have a single child.\n if (topTreeStackTopNode.child) {\n throw new Error(\"a decorator node must only have a single child node\");\n }\n\n topTreeStackTopNode.child = node;\n }\n\n // If the node we are adding is also a composite or decorator node, then we should push it\n // onto the current tree stack, as subsequent nodes will be added as its child/children.\n if (!isLeafNode(node)) {\n topTreeStack.push(node);\n }\n };\n\n // A helper function used to pop the top-most node definition off of the tree stack and return it.\n const popNode = (): AnyNodeDefinition | null => {\n let poppedNode: AnyNodeDefinition | null = null;\n\n // Get the current tree stack that we are populating.\n const topTreeStack = treeStacks[treeStacks.length - 1];\n\n // Pop the top-most node in the current tree stack if there is one.\n if (topTreeStack.length) {\n poppedNode = topTreeStack.pop() as AnyNodeDefinition;\n }\n\n // We don't want any empty tree stacks in our stack of tree stacks.\n if (!topTreeStack.length) {\n treeStacks.pop();\n }\n\n return poppedNode;\n };\n\n // We should keep processing the raw tokens until we run out of them.\n while (tokens.length) {\n // Grab the next token.\n const token = tokens.shift()!;\n\n // How we create the next node depends on the current raw token value.\n switch (token.toUpperCase()) {\n case \"ROOT\": {\n pushNode(createRootNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"SUCCEED\": {\n pushNode(createSucceedNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"FAIL\": {\n pushNode(createFailNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"FLIP\": {\n pushNode(createFlipNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"REPEAT\": {\n pushNode(createRepeatNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"RETRY\": {\n pushNode(createRetryNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"SEQUENCE\": {\n pushNode(createSequenceNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"SELECTOR\": {\n pushNode(createSelectorNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"PARALLEL\": {\n pushNode(createParallelNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"LOTTO\": {\n pushNode(createLottoNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"ACTION\": {\n pushNode(createActionNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"CONDITION\": {\n pushNode(createConditionNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"WAIT\": {\n pushNode(createWaitNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"BRANCH\": {\n pushNode(createBranchNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"}\": {\n // The '}' character closes the current scope and means that we have to pop a node off of the current stack.\n const poppedNode = popNode();\n\n // Now that we have a node definition we can carry out any validation that may require the node to be fully populated.\n if (poppedNode) {\n validatePoppedNode(poppedNode);\n }\n\n break;\n }\n\n default: {\n throw new Error(`unexpected token: ${token}`);\n }\n }\n }\n\n return rootNodes as RootNodeDefinition[];\n}\n\n/**\n * Creates a root node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The root node JSON definition.\n */\nfunction createRootNode(tokens: string[], stringLiteralPlaceholders: StringLiteralPlaceholders): RootNodeDefinition {\n // Create the root node definition.\n let node = {\n type: \"root\"\n } as Partial;\n\n // Parse any node arguments, we should only have one if any which will be an identifier argument for the root identifier.\n const nodeArguments = parseArgumentTokens(tokens, stringLiteralPlaceholders);\n\n // Check whether any node arguments were defined.\n if (nodeArguments.length) {\n // We should only have one argument, if any, which will be an identifier argument for the root identifier.\n if (nodeArguments.length === 1 && nodeArguments[0].type === \"identifier\") {\n // The root node identifier will be the first and only node argument value.\n node.id = nodeArguments[0].value as string;\n } else {\n throw new Error(\"expected single root name argument\");\n }\n }\n\n // Grab any node attribute definitions and spread them into the node definition.\n node = { ...node, ...parseAttributeTokens(tokens, stringLiteralPlaceholders) };\n\n // This is a decorator node, so we expect an opening '{'.\n popAndCheck(tokens, \"{\");\n\n // Return the root node definition.\n return node as RootNodeDefinition;\n}\n\n/**\n * Creates a succeed node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The succeed node JSON definition.\n */\nfunction createSucceedNode(\n tokens: string[],\n stringLiteralPlaceholders: StringLiteralPlaceholders\n): SucceedNodeDefinition {\n const node = {\n type: \"succeed\",\n ...parseAttributeTokens(tokens, stringLiteralPlaceholders)\n } as SucceedNodeDefinition;\n\n // This is a decorator node, so we expect an opening '{'.\n popAndCheck(tokens, \"{\");\n\n // Return the succeed node definition.\n return node;\n}\n\n/**\n * Creates a fail node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The fail node JSON definition.\n */\nfunction createFailNode(tokens: string[], stringLiteralPlaceholders: StringLiteralPlaceholders): FailNodeDefinition {\n const node = {\n type: \"fail\",\n ...parseAttributeTokens(tokens, stringLiteralPlaceholders)\n } as FailNodeDefinition;\n\n // This is a decorator node, so we expect an opening '{'.\n popAndCheck(tokens, \"{\");\n\n // Return the fail node definition.\n return node;\n}\n\n/**\n * Creates a flip node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The flip node JSON definition.\n */\nfunction createFlipNode(tokens: string[], stringLiteralPlaceholders: StringLiteralPlaceholders): FlipNodeDefinition {\n const node = {\n type: \"flip\",\n ...parseAttributeTokens(tokens, stringLiteralPlaceholders)\n } as FlipNodeDefinition;\n\n // This is a decorator node, so we expect an opening '{'.\n popAndCheck(tokens, \"{\");\n\n // Return the flip node definition.\n return node;\n}\n\n/**\n * Creates a repeat node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The repeat node JSON definition.\n */\nfunction createRepeatNode(\n tokens: string[],\n stringLiteralPlaceholders: StringLiteralPlaceholders\n): RepeatNodeDefinition {\n let node = { type: \"repeat\" } as RepeatNodeDefinition;\n\n // Get the node arguments.\n const nodeArguments = parseArgumentTokens(tokens, stringLiteralPlaceholders);\n\n // The arguments of a repeat node are optional. We may have:\n // - No node arguments, in which case the repeat note will iterate indefinitely.\n // - One node argument which will be the explicit number of iterations to make.\n // - Two node arguments which define the min and max iteration bounds from which a random iteration count will be picked.\n if (nodeArguments.length) {\n // All repeat node arguments MUST be of type number and must be integer.\n nodeArguments\n .filter((arg) => arg.type !== \"number\" || !arg.isInteger)\n .forEach(() => {\n throw new Error(`repeat node iteration counts must be integer values`);\n });\n\n // We should have got one or two iteration counts.\n if (nodeArguments.length === 1) {\n // A static iteration count was defined.\n node.iterations = nodeArguments[0].value as number;\n\n // A repeat node must have a positive number of iterations if defined.\n if (node.iterations < 0) {\n throw new Error(\"a repeat node must have a positive number of iterations if defined\");\n }\n } else if (nodeArguments.length === 2) {\n // A minimum and maximum iteration count was defined.\n node.iterations = [nodeArguments[0].value as number, nodeArguments[1].value as number];\n\n // A repeat node must have a positive min and max iteration count if they are defined.\n if (node.iterations[0] < 0 || node.iterations[1] < 0) {\n throw new Error(\"a repeat node must have a positive minimum and maximum iteration count if defined\");\n }\n\n // A repeat node must not have an minimum iteration count that exceeds the maximum iteration count.\n if (node.iterations[0] > node.iterations[1]) {\n throw new Error(\n \"a repeat node must not have a minimum iteration count that exceeds the maximum iteration count\"\n );\n }\n } else {\n // An incorrect number of iteration counts was defined.\n throw new Error(\"invalid number of repeat node iteration count arguments defined\");\n }\n }\n\n // Grab any node attribute definitions and spread them into the node definition.\n node = { ...node, ...parseAttributeTokens(tokens, stringLiteralPlaceholders) };\n\n // This is a decorator node, so we expect an opening '{'.\n popAndCheck(tokens, \"{\");\n\n // Return the repeat node definition.\n return node;\n}\n\n/**\n * Creates a retry node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The retry node JSON definition.\n */\nfunction createRetryNode(tokens: string[], stringLiteralPlaceholders: StringLiteralPlaceholders): RetryNodeDefinition {\n let node = { type: \"retry\" } as RetryNodeDefinition;\n\n // Get the node arguments.\n const nodeArguments = parseArgumentTokens(tokens, stringLiteralPlaceholders);\n\n // The arguments of a retry node are optional. We may have:\n // - No node arguments, in which case the retry note will attempt indefinitely.\n // - One node argument which will be the explicit number of attempts to make.\n // - Two node arguments which define the min and max attempt bounds from which a random attempt count will be picked.\n if (nodeArguments.length) {\n // All retry node arguments MUST be of type number and must be integer.\n nodeArguments\n .filter((arg) => arg.type !== \"number\" || !arg.isInteger)\n .forEach(() => {\n throw new Error(`retry node attempt counts must be integer values`);\n });\n\n // We should have got one or two attempt counts.\n if (nodeArguments.length === 1) {\n // A static attempt count was defined.\n node.attempts = nodeArguments[0].value as number;\n\n // A retry node must have a positive number of attempts if defined.\n if (node.attempts < 0) {\n throw new Error(\"a retry node must have a positive number of attempts if defined\");\n }\n } else if (nodeArguments.length === 2) {\n // A minimum and maximum attempt count was defined.\n node.attempts = [nodeArguments[0].value as number, nodeArguments[1].value as number];\n\n // A retry node must have a positive min and max attempts count if they are defined.\n if (node.attempts[0] < 0 || node.attempts[1] < 0) {\n throw new Error(\"a retry node must have a positive minimum and maximum attempt count if defined\");\n }\n\n // A retry node must not have a minimum attempt count that exceeds the maximum attempt count.\n if (node.attempts[0] > node.attempts[1]) {\n throw new Error(\n \"a retry node must not have a minimum attempt count that exceeds the maximum attempt count\"\n );\n }\n } else {\n // An incorrect number of attempt counts was defined.\n throw new Error(\"invalid number of retry node attempt count arguments defined\");\n }\n }\n\n // Grab any node attribute definitions and spread them into the node definition.\n node = { ...node, ...parseAttributeTokens(tokens, stringLiteralPlaceholders) };\n\n // This is a decorator node, so we expect an opening '{'.\n popAndCheck(tokens, \"{\");\n\n // Return the retry node definition.\n return node;\n}\n\n/**\n * Creates a sequence node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The sequence node JSON definition.\n */\nfunction createSequenceNode(\n tokens: string[],\n stringLiteralPlaceholders: StringLiteralPlaceholders\n): SequenceNodeDefinition {\n const node = {\n type: \"sequence\",\n ...parseAttributeTokens(tokens, stringLiteralPlaceholders)\n } as SequenceNodeDefinition;\n\n // This is a composite node, so we expect an opening '{'.\n popAndCheck(tokens, \"{\");\n\n // Return the sequence node definition.\n return node;\n}\n\n/**\n * Creates a selector node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The selector node JSON definition.\n */\nfunction createSelectorNode(\n tokens: string[],\n stringLiteralPlaceholders: StringLiteralPlaceholders\n): SelectorNodeDefinition {\n const node = {\n type: \"selector\",\n ...parseAttributeTokens(tokens, stringLiteralPlaceholders)\n } as SelectorNodeDefinition;\n\n // This is a composite node, so we expect an opening '{'.\n popAndCheck(tokens, \"{\");\n\n // Return the selector node definition.\n return node;\n}\n\n/**\n * Creates a parallel node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The parallel node JSON definition.\n */\nfunction createParallelNode(\n tokens: string[],\n stringLiteralPlaceholders: StringLiteralPlaceholders\n): ParallelNodeDefinition {\n const node = {\n type: \"parallel\",\n ...parseAttributeTokens(tokens, stringLiteralPlaceholders)\n } as ParallelNodeDefinition;\n\n // This is a composite node, so we expect an opening '{'.\n popAndCheck(tokens, \"{\");\n\n // Return the parallel node definition.\n return node;\n}\n\n/**\n * Creates a lotto node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The lotto node JSON definition.\n */\nfunction createLottoNode(tokens: string[], stringLiteralPlaceholders: StringLiteralPlaceholders): LottoNodeDefinition {\n // If any node arguments have been defined then they must be our weights.\n const nodeArguments = parseArgumentTokens(tokens, stringLiteralPlaceholders);\n\n // All lotto node arguments MUST be of type number and must be positive integers.\n nodeArguments\n .filter((arg) => arg.type !== \"number\" || !arg.isInteger || arg.value < 0)\n .forEach(() => {\n throw new Error(`lotto node weight arguments must be positive integer values`);\n });\n\n const node = {\n type: \"lotto\",\n ...parseAttributeTokens(tokens, stringLiteralPlaceholders)\n } as LottoNodeDefinition;\n\n // Apply the weights if any were defined.\n if (nodeArguments.length) {\n node.weights = nodeArguments.map(({ value }) => value) as number[];\n }\n\n // This is a composite node, so we expect an opening '{'.\n popAndCheck(tokens, \"{\");\n\n // Return the lotto node definition.\n return node;\n}\n\n/**\n * Creates an action node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The action node JSON definition.\n */\nfunction createActionNode(\n tokens: string[],\n stringLiteralPlaceholders: StringLiteralPlaceholders\n): ActionNodeDefinition {\n // Parse any node arguments, we should have at least one which will be an identifier argument for the action name\n // and agent function to invoke for the action, all other arguments are to be passed as arguments to that function.\n const [actionNameIdentifier, ...agentFunctionArgs] = parseArgumentTokens(tokens, stringLiteralPlaceholders);\n\n // Our first argument MUST be defined and be an identifier as we require an action name argument.\n if (actionNameIdentifier?.type !== \"identifier\") {\n throw new Error(\"expected action name identifier argument\");\n }\n\n // Only the first argument should have been an identifier, all agent function arguments must be string, number, boolean or null.\n agentFunctionArgs\n .filter((arg) => arg.type === \"identifier\")\n .forEach((arg) => {\n throw new Error(\n `invalid action node argument value '${arg.value}', must be string, number, boolean or null`\n );\n });\n\n // Return the action node definition.\n return {\n type: \"action\",\n call: actionNameIdentifier.value,\n args: agentFunctionArgs.map(({ value }) => value),\n ...parseAttributeTokens(tokens, stringLiteralPlaceholders)\n };\n}\n\n/**\n * Creates a condition node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The condition node JSON definition.\n */\nfunction createConditionNode(\n tokens: string[],\n stringLiteralPlaceholders: StringLiteralPlaceholders\n): ConditionNodeDefinition {\n // Parse any node arguments, we should have at least one which will be an identifier argument for the condition name\n // and agent function to invoke for the condition, all other arguments are to be passed as arguments to that function.\n const [conditionNameIdentifier, ...agentFunctionArgs] = parseArgumentTokens(tokens, stringLiteralPlaceholders);\n\n // Our first argument MUST be defined and be an identifier as we require a condition name argument.\n if (conditionNameIdentifier?.type !== \"identifier\") {\n throw new Error(\"expected condition name identifier argument\");\n }\n\n // Only the first argument should have been an identifier, all agent function arguments must be string, number, boolean or null.\n agentFunctionArgs\n .filter((arg) => arg.type === \"identifier\")\n .forEach((arg) => {\n throw new Error(\n `invalid condition node argument value '${arg.value}', must be string, number, boolean or null`\n );\n });\n\n // Return the condition node definition.\n return {\n type: \"condition\",\n call: conditionNameIdentifier.value,\n args: agentFunctionArgs.map(({ value }) => value),\n ...parseAttributeTokens(tokens, stringLiteralPlaceholders)\n };\n}\n\n/**\n * Creates a wait node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The wait node JSON definition.\n */\nfunction createWaitNode(tokens: string[], stringLiteralPlaceholders: StringLiteralPlaceholders): WaitNodeDefinition {\n let node = { type: \"wait\" } as WaitNodeDefinition;\n\n // Get the node arguments.\n const nodeArguments = parseArgumentTokens(tokens, stringLiteralPlaceholders);\n\n // The arguments of a wait node are optional. We may have:\n // - No node arguments, in which case the wait will be indefinite until it is aborted.\n // - One node argument which will be the explicit duration of the wait.\n // - Two node arguments which define the min and max duration bounds from which a random duration will be picked.\n if (nodeArguments.length) {\n // All wait node arguments MUST be of type number and must be integer.\n nodeArguments\n .filter((arg) => arg.type !== \"number\" || !arg.isInteger)\n .forEach(() => {\n throw new Error(`wait node durations must be integer values`);\n });\n\n // We may have:\n // - One node argument which will be the explicit duration of the wait.\n // - Two node arguments which define the min and max duration bounds from which a random duration will be picked.\n // - Too many arguments, which is not valid.\n if (nodeArguments.length === 1) {\n // An explicit duration was defined.\n node.duration = nodeArguments[0].value as number;\n\n // If an explict duration was defined then it must be a positive number.\n if (node.duration < 0) {\n throw new Error(\"a wait node must have a positive duration\");\n }\n } else if (nodeArguments.length === 2) {\n // Min and max duration bounds were defined from which a random duration will be picked.\n node.duration = [nodeArguments[0].value as number, nodeArguments[1].value as number];\n\n // A wait node must have a positive min and max duration.\n if (node.duration[0] < 0 || node.duration[1] < 0) {\n throw new Error(\"a wait node must have a positive minimum and maximum duration\");\n }\n\n // A wait node must not have a minimum duration that exceeds the maximum duration.\n if (node.duration[0] > node.duration[1]) {\n throw new Error(\"a wait node must not have a minimum duration that exceeds the maximum duration\");\n }\n } else if (nodeArguments.length > 2) {\n // An incorrect number of duration arguments were defined.\n throw new Error(\"invalid number of wait node duration arguments defined\");\n }\n }\n\n // Return the wait node definition.\n return { ...node, ...parseAttributeTokens(tokens, stringLiteralPlaceholders) };\n}\n\n/**\n * Creates a branch node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The branch node JSON definition.\n */\nfunction createBranchNode(\n tokens: string[],\n stringLiteralPlaceholders: StringLiteralPlaceholders\n): BranchNodeDefinition {\n // Parse any node arguments, we should have one which will be an identifier argument for the root ref.\n const nodeArguments = parseArgumentTokens(tokens, stringLiteralPlaceholders);\n\n // We should have only a single identifer argument for a branch node, which is the root ref.\n if (nodeArguments.length !== 1 || nodeArguments[0].type !== \"identifier\") {\n throw new Error(\"expected single branch name argument\");\n }\n\n // Return the branch node definition.\n return { type: \"branch\", ref: nodeArguments[0].value };\n}\n\n/**\n * Validate a fully-populated node definition that was popped off of the tree stack.\n * @param definition The popped node to validate.\n */\nfunction validatePoppedNode(definition: AnyNodeDefinition): void {\n // Decorators MUST have a child defined.\n if (isDecoratorNode(definition) && isNullOrUndefined(definition.child)) {\n throw new Error(`a ${definition.type} node must have a single child node defined`);\n }\n\n // Composites MUST have at least one child defined.\n if (isCompositeNode(definition) && !definition.children?.length) {\n throw new Error(`a ${definition.type} node must have at least a single child node defined`);\n }\n\n // We need to make sure that lotto nodes that have weights defined have a number of weights matching the number of child nodes.\n if (definition.type === \"lotto\") {\n // Check whether a 'weights' property has been defined, if it has we expect it to be an array of weights.\n if (typeof definition.weights !== \"undefined\") {\n // Check that the weights property is an array of positive integers with an element for each child node element.\n if (definition.weights.length !== definition.children.length) {\n throw new Error(\n \"expected a number of weight arguments matching the number of child nodes for lotto node\"\n );\n }\n }\n }\n}\n", "import { RootNodeDefinition } from \"./BehaviourTreeDefinition\";\nimport { flattenDefinition, isBranchNode, isInteger } from \"./BehaviourTreeDefinitionUtilities\";\nimport { convertMDSLToJSON } from \"./mdsl/MDSLDefinitionParser\";\n\n/**\n * An object representing the result of validating a tree definition.\n */\nexport type DefinitionValidationResult = {\n /**\n * A flag defining whether validation succeeded.\n */\n succeeded: boolean;\n /**\n * A string containing the error message if validation did not succeed.\n */\n errorMessage?: string;\n /**\n * The definition as json if the validation was successful, or undefined if validation did not succeed.\n */\n json?: RootNodeDefinition[];\n};\n\n/**\n * Validates the specified behaviour tree definition in the form of JSON or MDSL, not taking any globally registered subtrees into consideration.\n * @param definition The behaviour tree definition in the form of JSON or MDSL.\n * @returns An object representing the result of validating the given tree definition.\n */\nexport function validateDefinition(definition: any): DefinitionValidationResult {\n // The definition must be defined.\n if (definition === null || typeof definition === \"undefined\") {\n return createValidationFailureResult(\"definition is null or undefined\");\n }\n\n // We are expecting a definition in one of three different forms:\n // - A string which we will assume is MDSL and we will parse this to JSON before validation.\n // - An array which we will assume is an array of root node definitions with at least one being the primary root node (no 'id' property)\n // - An object which we will assume is the primary root node and should not have an 'id' property.\n if (typeof definition === \"string\") {\n // The definition is a string which we can assume is MDSL, so attempt to validate it.\n return validateMDSLDefinition(definition);\n } else if (typeof definition === \"object\") {\n // The definition will either be an array (of root node definitions) or an object (the single primary root node definition).\n return validateJSONDefinition(definition);\n } else {\n return createValidationFailureResult(`unexpected definition type of '${typeof definition}'`);\n }\n}\n\n/**\n * Validates the specified behaviour tree definition in the form of MDSL.\n * @param definition The behaviour tree definition in the form of MDSL.\n * @returns An object representing the result of validating the given tree definition.\n */\nfunction validateMDSLDefinition(definition: string): DefinitionValidationResult {\n let rootNodeDefinitions;\n\n // The first thing the we need to do is to attempt to convert our MDSL into JSON.\n try {\n // The definition is a string which we can assume is MDSL, so attempt to parse it to a JSON definition in the form of an array of root node definitions.\n rootNodeDefinitions = convertMDSLToJSON(definition);\n } catch (exception) {\n // We failed to parse the JSON from the MDSL, this is likely to be the result of it not being a valid MDSL string.\n return createValidationFailureResult((exception as Error).message);\n }\n\n // Unpack all of the root node definitions into arrays of main ('id' defined) and sub ('id' not defined) root node definitions.\n const mainRootNodeDefinitions = rootNodeDefinitions.filter(({ id }) => typeof id === \"undefined\");\n const subRootNodeDefinitions = rootNodeDefinitions.filter(({ id }) => typeof id === \"string\" && id.length > 0);\n\n // We should ALWAYS have exactly one root node definition without an 'id' property defined, which is out main root node definition.\n if (mainRootNodeDefinitions.length !== 1) {\n return createValidationFailureResult(\n \"expected single unnamed root node at base of definition to act as main root\"\n );\n }\n\n // We should never have duplicate 'id' properties across our sub root node definitions.\n const subRootNodeIdenitifers: string[] = [];\n for (const { id } of subRootNodeDefinitions) {\n // Have we already come across this 'id' property value?\n if (subRootNodeIdenitifers.includes(id!)) {\n return createValidationFailureResult(`multiple root nodes found with duplicate name '${id}'`);\n }\n\n subRootNodeIdenitifers.push(id!);\n }\n\n try {\n // Validate our branch -> subtree links and check for any circular dependencies, we don't care about checking for broken subtree links here.\n validateBranchSubtreeLinks(rootNodeDefinitions, false);\n } catch (exception) {\n return createValidationFailureResult((exception as Error).message);\n }\n\n // Our definition was valid!\n return {\n succeeded: true,\n json: rootNodeDefinitions\n };\n}\n\n/**\n * Validates the specified behaviour tree definition in the form of JSON.\n * @param definition The behaviour tree definition in the form of JSON.\n * @returns An object representing the result of validating the given tree definition.\n */\nexport function validateJSONDefinition(\n definition: RootNodeDefinition | RootNodeDefinition[]\n): DefinitionValidationResult {\n // The definition will either be an array (of root node definitions) or an object (the single primary root node definition).\n const rootNodeDefinitions = Array.isArray(definition) ? definition : [definition];\n\n // Iterate over our array of root nodes and call validateNode for each, passing an initial depth of 0, wrapped in a try catch to handle validation failures.\n try {\n rootNodeDefinitions.forEach((rootNodeDefinition) => validateNode(rootNodeDefinition, 0));\n } catch (error) {\n // Handle cases where we have caught a thrown Error and return a failure result with the error message.\n if (error instanceof Error) {\n return createValidationFailureResult(error.message);\n }\n\n // No idea what happened here!\n return createValidationFailureResult(`unexpected error: ${error}`);\n }\n\n // Unpack all of the root node definitions into arrays of main ('id' defined) and sub ('id' not defined) root node definitions.\n const mainRootNodeDefinitions = rootNodeDefinitions.filter(({ id }) => typeof id === \"undefined\");\n const subRootNodeDefinitions = rootNodeDefinitions.filter(({ id }) => typeof id === \"string\" && id.length > 0);\n\n // We should ALWAYS have exactly one root node definition without an 'id' property defined, which is out main root node definition.\n if (mainRootNodeDefinitions.length !== 1) {\n return createValidationFailureResult(\n \"expected single root node without 'id' property defined to act as main root\"\n );\n }\n\n // We should never have duplicate 'id' properties across our sub root node definitions.\n const subRootNodeIdenitifers: string[] = [];\n for (const { id } of subRootNodeDefinitions) {\n // Have we already come across this 'id' property value?\n if (subRootNodeIdenitifers.includes(id!)) {\n return createValidationFailureResult(\n `multiple root nodes found with duplicate 'id' property value of '${id}'`\n );\n }\n\n subRootNodeIdenitifers.push(id!);\n }\n\n try {\n // Validate our branch -> subtree links and check for any circular dependencies, we don't care about checking for broken subtree links here.\n validateBranchSubtreeLinks(rootNodeDefinitions, false);\n } catch (exception) {\n return createValidationFailureResult((exception as Error).message);\n }\n\n // Our definition was valid!\n return {\n succeeded: true,\n json: rootNodeDefinitions\n };\n}\n\n/**\n * Validates the branch -> subtree links across all provided root node definitions.\n * This will not consider branch nodes that reference any globally registered subtrees unless includesGlobalSubtrees\n * is set to true, in which case we will also verify that there are no broken branch -> subtree links.\n * @param rootNodeDefinitions The array of root node definitions.\n * @param includesGlobalSubtrees A flag defining whether the array includes all global subtree root node definitions.\n */\nexport function validateBranchSubtreeLinks(rootNodeDefinitions: RootNodeDefinition[], includesGlobalSubtrees: boolean) {\n // Create a mapping of root node identifiers to other root nodes that they reference via branch nodes.\n // Below is an example of a mapping that includes a circular dependency (root => a => b => c => a)\n // [{ refs: [\"a\", \"b\"] }, { id: \"a\", refs: [\"b\"] }, { id: \"b\", refs: [\"c\"] }, { id: \"c\", refs: [\"a\"] }]\n const rootNodeMappings: { id: string | undefined; refs: string[] }[] = rootNodeDefinitions.map(\n (rootNodeDefinition) => ({\n id: rootNodeDefinition.id,\n refs: flattenDefinition(rootNodeDefinition)\n .filter(isBranchNode)\n .map(({ ref }) => ref)\n })\n );\n\n // A recursive function to walk through the mappings, keeping track of which root nodes we have visited in the form of a path of root node identifiers.\n const followRefs = (mapping: { id: string | undefined; refs: string[] }, path: (string | undefined)[] = []) => {\n // Have we found a circular dependency?\n if (path.includes(mapping.id)) {\n // We found a circular dependency! Get the bad path of root node identifiers.\n const badPath = [...path, mapping.id];\n\n // Create the formatted path value. [undefined, \"a\", \"b\", \"c\", \"a\"] would be formatted as \"a -> b -> c -> a\".\n const badPathFormatted = badPath.filter((element) => !!element).join(\" => \");\n\n // No need to continue, we found a circular dependency.\n throw new Error(`circular dependency found in branch node references: ${badPathFormatted}`);\n }\n\n for (const ref of mapping.refs) {\n // Find the mapping for the root node with an identifer matching the current ref.\n const subMapping = rootNodeMappings.find(({ id }) => id === ref);\n\n // We may not have a mapping for this ref, which is normal when we aren't considering all globally registered subtrees.\n if (subMapping) {\n followRefs(subMapping, [...path, mapping.id]);\n } else if (includesGlobalSubtrees) {\n // We found a reference to a root node that doesn't exist, which is a problem seeing as the root node definitons includes all globally registered subtrees.\n throw new Error(\n mapping.id\n ? `subtree '${mapping.id}' has branch node that references root node '${ref}' which has not been defined`\n : `primary tree has branch node that references root node '${ref}' which has not been defined`\n );\n }\n }\n };\n\n // Start looking for circular dependencies and broken references from the primary root node definition.\n followRefs(rootNodeMappings.find((mapping) => typeof mapping.id === \"undefined\")!);\n}\n\n/**\n * Validate an object that we expect to be a node definition.\n * @param definition An object that we expect to be a node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateNode(definition: any, depth: number): void {\n // Every node must be valid object and have a non-empty 'type' string property.\n if (typeof definition !== \"object\" || typeof definition.type !== \"string\" || definition.type.length === 0) {\n throw new Error(\n `node definition is not an object or 'type' property is not a non-empty string at depth '${depth}'`\n );\n }\n\n // How we validate this node definition will depend on its type.\n switch (definition.type) {\n case \"action\":\n validateActionNode(definition, depth);\n break;\n\n case \"condition\":\n validateConditionNode(definition, depth);\n break;\n\n case \"wait\":\n validateWaitNode(definition, depth);\n break;\n\n case \"branch\":\n validateBranchNode(definition, depth);\n break;\n\n case \"root\":\n validateRootNode(definition, depth);\n break;\n\n case \"succeed\":\n validateSucceedNode(definition, depth);\n break;\n\n case \"fail\":\n validateFailNode(definition, depth);\n break;\n\n case \"flip\":\n validateFlipNode(definition, depth);\n break;\n\n case \"repeat\":\n validateRepeatNode(definition, depth);\n break;\n\n case \"retry\":\n validateRetryNode(definition, depth);\n break;\n\n case \"sequence\":\n validateSequenceNode(definition, depth);\n break;\n\n case \"selector\":\n validateSelectorNode(definition, depth);\n break;\n\n case \"parallel\":\n validateParallelNode(definition, depth);\n break;\n\n case \"lotto\":\n validateLottoNode(definition, depth);\n break;\n\n default:\n throw new Error(`unexpected node type of '${definition.type}' at depth '${depth}'`);\n }\n}\n\n/**\n * Validate any attributes for a given node definition.\n * @param definition The node definition.\n * @param depth The depth of the node in the behaviour tree definition.\n */\nfunction validateNodeAttributes(definition: any, depth: number): void {\n // Validate each of the attribute types for this node.\n [\"while\", \"until\", \"entry\", \"exit\", \"step\"].forEach((attributeName) => {\n // Attempt to grab the definition for the current attribute from the node definition.\n const attributeDefinition = definition[attributeName];\n\n // All node attributes are optional, so there is nothing to do if the current attribute is not defined.\n if (typeof attributeDefinition === \"undefined\") {\n return;\n }\n\n // The attribute definition must be an object.\n if (typeof attributeDefinition !== \"object\") {\n throw new Error(\n `expected attribute '${attributeName}' to be an object for '${definition.type}' node at depth '${depth}'`\n );\n }\n\n // The 'call' property must be defined for any attribute definition.\n if (typeof attributeDefinition.call !== \"string\" || attributeDefinition.call.length === 0) {\n throw new Error(\n `expected 'call' property for attribute '${attributeName}' to be a non-empty string for '${definition.type}' node at depth '${depth}'`\n );\n }\n\n // If any node attribute arguments have been defined then they must have been defined in an array.\n if (typeof attributeDefinition.args !== \"undefined\" && !Array.isArray(attributeDefinition.args)) {\n throw new Error(\n `expected 'args' property for attribute '${attributeName}' to be an array for '${definition.type}' node at depth '${depth}'`\n );\n }\n });\n}\n\n/**\n * Validate an object that we expect to be a root node definition.\n * @param definition An object that we expect to be a root node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateRootNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"root\") {\n throw new Error(\"expected node type of 'root' for root node\");\n }\n\n // A root node cannot be the child of another node.\n if (depth > 0) {\n throw new Error(\"a root node cannot be the child of another node\");\n }\n\n // Check that, if the root node 'id' property is defined, it is a non-empty string.\n if (typeof definition.id !== \"undefined\" && (typeof definition.id !== \"string\" || definition.id.length === 0)) {\n throw new Error(\"expected non-empty string for 'id' property if defined for root node\");\n }\n\n // A root node is a decorator node, so must have a child node defined.\n if (typeof definition.child === \"undefined\") {\n throw new Error(\"expected property 'child' to be defined for root node\");\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n\n // Validate the child node of this decorator node.\n validateNode(definition.child, depth + 1);\n}\n\n/**\n * Validate an object that we expect to be a succeed node definition.\n * @param definition An object that we expect to be a succeed node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateSucceedNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"succeed\") {\n throw new Error(`expected node type of 'succeed' for succeed node at depth '${depth}'`);\n }\n\n // A succeed node is a decorator node, so must have a child node defined.\n if (typeof definition.child === \"undefined\") {\n throw new Error(`expected property 'child' to be defined for succeed node at depth '${depth}'`);\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n\n // Validate the child node of this decorator node.\n validateNode(definition.child, depth + 1);\n}\n\n/**\n * Validate an object that we expect to be a fail node definition.\n * @param definition An object that we expect to be a fail node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateFailNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"fail\") {\n throw new Error(`expected node type of 'fail' for fail node at depth '${depth}'`);\n }\n\n // A fail node is a decorator node, so must have a child node defined.\n if (typeof definition.child === \"undefined\") {\n throw new Error(`expected property 'child' to be defined for fail node at depth '${depth}'`);\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n\n // Validate the child node of this decorator node.\n validateNode(definition.child, depth + 1);\n}\n\n/**\n * Validate an object that we expect to be a flip node definition.\n * @param definition An object that we expect to be a flip node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateFlipNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"flip\") {\n throw new Error(`expected node type of 'flip' for flip node at depth '${depth}'`);\n }\n\n // A flip node is a decorator node, so must have a child node defined.\n if (typeof definition.child === \"undefined\") {\n throw new Error(`expected property 'child' to be defined for flip node at depth '${depth}'`);\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n\n // Validate the child node of this decorator node.\n validateNode(definition.child, depth + 1);\n}\n\n/**\n * Validate an object that we expect to be a repeat node definition.\n * @param definition An object that we expect to be a repeat node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateRepeatNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"repeat\") {\n throw new Error(`expected node type of 'repeat' for repeat node at depth '${depth}'`);\n }\n\n // A repeat node is a decorator node, so must have a child node defined.\n if (typeof definition.child === \"undefined\") {\n throw new Error(`expected property 'child' to be defined for repeat node at depth '${depth}'`);\n }\n\n // Check whether an 'iterations' property has been defined, it may not have been if this node is to repeat indefinitely.\n if (typeof definition.iterations !== \"undefined\") {\n if (Array.isArray(definition.iterations)) {\n // Check whether any elements of the array are not integer values.\n const containsNonInteger = !!definition.iterations.filter((value: unknown) => !isInteger(value)).length;\n\n // If the 'iterations' property is an array then it MUST contain two integer values.\n if (definition.iterations.length !== 2 || containsNonInteger) {\n throw new Error(\n `expected array containing two integer values for 'iterations' property if defined for repeat node at depth '${depth}'`\n );\n }\n\n // A repeat node must have a positive min and max iterations count if they are defined.\n if (definition.iterations[0] < 0 || definition.iterations[1] < 0) {\n throw new Error(\n `expected positive minimum and maximum iterations count for 'iterations' property if defined for repeat node at depth '${depth}'`\n );\n }\n\n // A repeat node must not have a minimum iterations count that exceeds the maximum iterations count.\n if (definition.iterations[0] > definition.iterations[1]) {\n throw new Error(\n `expected minimum iterations count that does not exceed the maximum iterations count for 'iterations' property if defined for repeat node at depth '${depth}'`\n );\n }\n } else if (isInteger(definition.iterations)) {\n // A repeat node must have a positive number of iterations if defined.\n if (definition.iterations < 0) {\n throw new Error(\n `expected positive iterations count for 'iterations' property if defined for repeat node at depth '${depth}'`\n );\n }\n } else {\n throw new Error(\n `expected integer value or array containing two integer values for 'iterations' property if defined for repeat node at depth '${depth}'`\n );\n }\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n\n // Validate the child node of this decorator node.\n validateNode(definition.child, depth + 1);\n}\n\n/**\n * Validate an object that we expect to be a retry node definition.\n * @param definition An object that we expect to be a retry node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateRetryNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"retry\") {\n throw new Error(`expected node type of 'retry' for retry node at depth '${depth}'`);\n }\n\n // A retry node is a decorator node, so must have a child node defined.\n if (typeof definition.child === \"undefined\") {\n throw new Error(`expected property 'child' to be defined for retry node at depth '${depth}'`);\n }\n\n // Check whether an 'attempts' property has been defined, it may not have been if this node is to retry indefinitely.\n if (typeof definition.attempts !== \"undefined\") {\n if (Array.isArray(definition.attempts)) {\n // Check whether any elements of the array are not integer values.\n const containsNonInteger = !!definition.attempts.filter((value: unknown) => !isInteger(value)).length;\n\n // If the 'attempts' property is an array then it MUST contain two integer values.\n if (definition.attempts.length !== 2 || containsNonInteger) {\n throw new Error(\n `expected array containing two integer values for 'attempts' property if defined for retry node at depth '${depth}'`\n );\n }\n\n // A retry node must have a positive min and max attempts count if they are defined.\n if (definition.attempts[0] < 0 || definition.attempts[1] < 0) {\n throw new Error(\n `expected positive minimum and maximum attempts count for 'attempts' property if defined for retry node at depth '${depth}'`\n );\n }\n\n // A retry node must not have a minimum attempts count that exceeds the maximum attempts count.\n if (definition.attempts[0] > definition.attempts[1]) {\n throw new Error(\n `expected minimum attempts count that does not exceed the maximum attempts count for 'attempts' property if defined for retry node at depth '${depth}'`\n );\n }\n } else if (isInteger(definition.attempts)) {\n // A retry node must have a positive number of attempts if defined.\n if (definition.attempts < 0) {\n throw new Error(\n `expected positive attempts count for 'attempts' property if defined for retry node at depth '${depth}'`\n );\n }\n } else {\n throw new Error(\n `expected integer value or array containing two integer values for 'attempts' property if defined for retry node at depth '${depth}'`\n );\n }\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n\n // Validate the child node of this decorator node.\n validateNode(definition.child, depth + 1);\n}\n\n/**\n * Validate an object that we expect to be a branch node definition.\n * @param definition An object that we expect to be a branch node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateBranchNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"branch\") {\n throw new Error(`expected node type of 'branch' for branch node at depth '${depth}'`);\n }\n\n // Check that the branch node 'ref' property is defined and is a non-empty string.\n if (typeof definition.ref !== \"string\" || definition.ref.length === 0) {\n throw new Error(`expected non-empty string for 'ref' property for branch node at depth '${depth}'`);\n }\n\n // It is invalid to define guard attributes for a branch node as they should be defined on the referenced root node.\n [\"while\", \"until\"].forEach((attributeName) => {\n if (typeof definition[attributeName] !== \"undefined\") {\n throw new Error(\n `guards should not be defined for branch nodes but guard '${attributeName}' was defined for branch node at depth '${depth}'`\n );\n }\n });\n\n // It is invalid to define callback attributes for a branch node as they should be defined on the referenced root node.\n [\"entry\", \"exit\", \"step\"].forEach((attributeName) => {\n if (typeof definition[attributeName] !== \"undefined\") {\n throw new Error(\n `callbacks should not be defined for branch nodes but callback '${attributeName}' was defined for branch node at depth '${depth}'`\n );\n }\n });\n}\n\n/**\n * Validate an object that we expect to be a action node definition.\n * @param definition An object that we expect to be a action node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateActionNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"action\") {\n throw new Error(`expected node type of 'action' for action node at depth '${depth}'`);\n }\n\n // The 'call' property must be defined for a action node definition.\n if (typeof definition.call !== \"string\" || definition.call.length === 0) {\n throw new Error(`expected non-empty string for 'call' property of action node at depth '${depth}'`);\n }\n\n // If any action function arguments have been defined then they must have been defined in an array.\n if (typeof definition.args !== \"undefined\" && !Array.isArray(definition.args)) {\n throw new Error(`expected array for 'args' property if defined for action node at depth '${depth}'`);\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n}\n\n/**\n * Validate an object that we expect to be a condition node definition.\n * @param definition An object that we expect to be a condition node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateConditionNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"condition\") {\n throw new Error(`expected node type of 'condition' for condition node at depth '${depth}'`);\n }\n\n // The 'call' property must be defined for a condition node definition.\n if (typeof definition.call !== \"string\" || definition.call.length === 0) {\n throw new Error(`expected non-empty string for 'call' property of condition node at depth '${depth}'`);\n }\n\n // If any condition function arguments have been defined then they must have been defined in an array.\n if (typeof definition.args !== \"undefined\" && !Array.isArray(definition.args)) {\n throw new Error(`expected array for 'args' property if defined for condition node at depth '${depth}'`);\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n}\n\n/**\n * Validate an object that we expect to be a wait node definition.\n * @param definition An object that we expect to be a wait node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateWaitNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"wait\") {\n throw new Error(`expected node type of 'wait' for wait node at depth '${depth}'`);\n }\n\n // Check whether a 'duration' property has been defined, it may not have been if this node is to wait indefinitely.\n if (typeof definition.duration !== \"undefined\") {\n if (Array.isArray(definition.duration)) {\n // Check whether any elements of the array are not integer values.\n const containsNonInteger = !!definition.duration.filter((value: unknown) => !isInteger(value)).length;\n\n // If the 'duration' property is an array then it MUST contain two integer values.\n if (definition.duration.length !== 2 || containsNonInteger) {\n throw new Error(\n `expected array containing two integer values for 'duration' property if defined for wait node at depth '${depth}'`\n );\n }\n\n // A wait node must have a positive min and max duration value if they are defined.\n if (definition.duration[0] < 0 || definition.duration[1] < 0) {\n throw new Error(\n `expected positive minimum and maximum duration for 'duration' property if defined for wait node at depth '${depth}'`\n );\n }\n\n // A wait node must not have a minimum duration value that exceeds the maximum duration value.\n if (definition.duration[0] > definition.duration[1]) {\n throw new Error(\n `expected minimum duration value that does not exceed the maximum duration value for 'duration' property if defined for wait node at depth '${depth}'`\n );\n }\n } else if (isInteger(definition.duration)) {\n // A wait node must have a positive duration value if defined.\n if (definition.duration < 0) {\n throw new Error(\n `expected positive duration value for 'duration' property if defined for wait node at depth '${depth}'`\n );\n }\n } else {\n throw new Error(\n `expected integer value or array containing two integer values for 'duration' property if defined for wait node at depth '${depth}'`\n );\n }\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n}\n\n/**\n * Validate an object that we expect to be a sequence node definition.\n * @param definition An object that we expect to be a sequence node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateSequenceNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"sequence\") {\n throw new Error(`expected node type of 'sequence' for sequence node at depth '${depth}'`);\n }\n\n // A sequence node is a composite node, so must have a children nodes array defined.\n if (!Array.isArray(definition.children) || definition.children.length === 0) {\n throw new Error(`expected non-empty 'children' array to be defined for sequence node at depth '${depth}'`);\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n\n // Validate the child nodes of this composite node.\n definition.children.forEach((child: any) => validateNode(child, depth + 1));\n}\n\n/**\n * Validate an object that we expect to be a selector node definition.\n * @param definition An object that we expect to be a selector node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateSelectorNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"selector\") {\n throw new Error(`expected node type of 'selector' for selector node at depth '${depth}'`);\n }\n\n // A selector node is a composite node, so must have a children nodes array defined.\n if (!Array.isArray(definition.children) || definition.children.length === 0) {\n throw new Error(`expected non-empty 'children' array to be defined for selector node at depth '${depth}'`);\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n\n // Validate the child nodes of this composite node.\n definition.children.forEach((child: any) => validateNode(child, depth + 1));\n}\n\n/**\n * Validate an object that we expect to be a parallel node definition.\n * @param definition An object that we expect to be a parallel node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateParallelNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"parallel\") {\n throw new Error(`expected node type of 'parallel' for parallel node at depth '${depth}'`);\n }\n\n // A parallel node is a composite node, so must have a children nodes array defined.\n if (!Array.isArray(definition.children) || definition.children.length === 0) {\n throw new Error(`expected non-empty 'children' array to be defined for parallel node at depth '${depth}'`);\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n\n // Validate the child nodes of this composite node.\n definition.children.forEach((child: any) => validateNode(child, depth + 1));\n}\n\n/**\n * Validate an object that we expect to be a lotto node definition.\n * @param definition An object that we expect to be a lotto node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateLottoNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"lotto\") {\n throw new Error(`expected node type of 'lotto' for lotto node at depth '${depth}'`);\n }\n\n // A lotto node is a composite node, so must have a children nodes array defined.\n if (!Array.isArray(definition.children) || definition.children.length === 0) {\n throw new Error(`expected non-empty 'children' array to be defined for lotto node at depth '${depth}'`);\n }\n\n // Check whether a 'weights' property has been defined, if it has we expect it to be an array of weights.\n if (typeof definition.weights !== \"undefined\") {\n // Check that the weights property is an array of positive integers with an element for each child node element.\n if (\n !Array.isArray(definition.weights) ||\n definition.weights.length !== definition.children.length ||\n definition.weights.filter((value: unknown) => !isInteger(value)).length ||\n definition.weights.filter((value: number) => value < 0).length\n ) {\n throw new Error(\n `expected an array of positive integer weight values with a length matching the number of child nodes for 'weights' property if defined for lotto node at depth '${depth}'`\n );\n }\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n\n // Validate the child nodes of this composite node.\n definition.children.forEach((child: any) => validateNode(child, depth + 1));\n}\n\n/**\n * A helper function to create a failure validation result with the given error message.\n * @param errorMessage The validation failure error message.\n * @returns A failure validation result with the given error message.\n */\nfunction createValidationFailureResult(errorMessage: string): DefinitionValidationResult {\n return { succeeded: false, errorMessage };\n}\n", "import { ActionResult, Agent, GlobalFunction } from \"./Agent\";\nimport { RootNodeDefinition } from \"./BehaviourTreeDefinition\";\n\nexport type InvokerFunction = (args: any[]) => ActionResult | boolean;\n\n/**\n * A singleton used to store and lookup registered functions and subtrees.\n */\nexport default class Lookup {\n /**\n * The object holding any registered functions keyed on function name.\n */\n private static registeredFunctions: { [key: string]: GlobalFunction } = {};\n /**\n * The object holding any registered subtree root node definitions keyed on tree name.\n */\n private static registeredSubtrees: { [key: string]: RootNodeDefinition } = {};\n\n /**\n * Gets the function with the specified name.\n * @param name The name of the function.\n * @returns The function with the specified name.\n */\n public static getFunc(name: string): GlobalFunction {\n return this.registeredFunctions[name];\n }\n\n /**\n * Sets the function with the specified name for later lookup.\n * @param name The name of the function.\n * @param func The function.\n */\n public static setFunc(name: string, func: GlobalFunction): void {\n this.registeredFunctions[name] = func;\n }\n\n /**\n * Gets the function invoker for the specified agent and function name.\n * If a function with the specified name exists on the agent object then it will\n * be returned, otherwise we will then check the registered functions for a match.\n * @param agent The agent instance that this behaviour tree is modelling behaviour for.\n * @param name The function name.\n * @returns The function invoker for the specified agent and function name.\n */\n static getFuncInvoker(agent: Agent, name: string): InvokerFunction | null {\n // Check whether the agent contains the specified function.\n const agentFunction = agent[name];\n if (agentFunction && typeof agentFunction === \"function\") {\n return (args: any[]) => agentFunction.apply(agent, args);\n }\n\n // The agent does not contain the specified function but it may have been registered at some point.\n if (this.registeredFunctions[name] && typeof this.registeredFunctions[name] === \"function\") {\n const registeredFunction = this.registeredFunctions[name];\n return (args: any[]) => registeredFunction(agent, ...args);\n }\n\n // We have no function to invoke.\n return null;\n }\n\n /**\n * Gets all registered subtree root node definitions.\n */\n static getSubtrees(): { [key: string]: RootNodeDefinition } {\n return this.registeredSubtrees;\n }\n\n /**\n * Sets the subtree with the specified name for later lookup.\n * @param name The name of the subtree.\n * @param subtree The subtree.\n */\n static setSubtree(name: string, subtree: RootNodeDefinition) {\n this.registeredSubtrees[name] = subtree;\n }\n\n /**\n * Removes the registered function or subtree with the specified name.\n * @param name The name of the registered function or subtree.\n */\n static remove(name: string) {\n delete this.registeredFunctions[name];\n delete this.registeredSubtrees[name];\n }\n\n /**\n * Remove all registered functions and subtrees.\n */\n static empty() {\n this.registeredFunctions = {};\n this.registeredSubtrees = {};\n }\n}\n", "import Node from \"../../nodes/Node\";\n\n/**\n * An exception thrown when evaluating node guard path conditions and a conditions fails.\n */\nexport default class GuardUnsatisifedException extends Error {\n /**\n * @param source The node at which a guard condition failed.\n */\n constructor(private source: Node) {\n super(\"A guard path condition has failed\");\n }\n\n /**\n * Gets whether the specified node is the node at which a guard condition failed.\n * @param node The node to check against the source node.\n * @returns Whether the specified node is the node at which a guard condition failed.\n */\n isSourceNode = (node: Node) => node === this.source;\n}\n", "import { Agent } from \"../../Agent\";\nimport Guard from \"./Guard\";\nimport Node from \"../../nodes/Node\";\nimport GuardUnsatisifedException from \"./GuardUnsatisifedException\";\n\nexport type GuardPathPart = {\n node: Node;\n guards: Guard[];\n};\n\n/**\n * Represents a path of node guards along a root-to-leaf tree path.\n */\nexport default class GuardPath {\n /**\n * @param nodes An array of objects defining a node instance -> guard link, ordered by node depth.\n */\n constructor(private nodes: GuardPathPart[]) {}\n\n /**\n * Evaluate guard conditions for all guards in the tree path, moving outwards from the root.\n * @param agent The agent, required for guard evaluation.\n * @returns An evaluation results object.\n */\n evaluate = (agent: Agent) => {\n // We need to evaluate guard conditions for nodes up the tree, moving outwards from the root.\n for (const details of this.nodes) {\n // There can be multiple guards per node.\n for (const guard of details.guards) {\n // Check whether the guard condition passes, and throw an exception if not.\n if (!guard.isSatisfied(agent)) {\n throw new GuardUnsatisifedException(details.node);\n }\n }\n }\n };\n}\n", "import { BehaviourTreeOptions } from \"../BehaviourTreeOptions\";\nimport State, { AnyState } from \"../State\";\nimport { Agent } from \"../Agent\";\nimport Leaf from \"./leaf/Leaf\";\nimport Attribute from \"../attributes/Attribute\";\nimport Entry from \"../attributes/callbacks/Entry\";\nimport Exit from \"../attributes/callbacks/Exit\";\nimport Step from \"../attributes/callbacks/Step\";\nimport Guard from \"../attributes/guards/Guard\";\nimport GuardPath from \"../attributes/guards/GuardPath\";\nimport GuardUnsatisifedException from \"../attributes/guards/GuardUnsatisifedException\";\n\n/**\n * A base node.\n */\nexport default abstract class Node {\n /**\n * The node uid.\n */\n private readonly uid: string = createNodeUid();\n /**\n * The node state.\n */\n private state: AnyState = State.READY;\n /**\n * The guard path to evaluate as part of a node update.\n */\n private guardPath: GuardPath | undefined;\n\n /**\n * @param type The node type.\n * @param attributes The node attributes.\n * @param args The node argument definitions.\n */\n constructor(private type: string, private attributes: Attribute[], private args: any[]) {}\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected abstract onUpdate(agent: Agent, options: BehaviourTreeOptions): void;\n\n /**\n * Gets the name of the node.\n */\n public abstract getName(): string;\n\n /**\n * Gets whether this node is a leaf node.\n */\n public abstract isLeafNode: () => this is Leaf;\n\n /**\n * Gets/Sets the state of the node.\n */\n getState = (): AnyState => this.state;\n setState = (value: AnyState): void => {\n this.state = value;\n };\n\n /**\n * Gets the unique id of the node.\n */\n getUid = () => this.uid;\n\n /**\n * Gets the type of the node.\n */\n getType = () => this.type;\n\n /**\n * Gets the node attributes.\n */\n getAttributes = () => this.attributes;\n\n /**\n * Gets the node arguments.\n */\n getArguments = () => this.args;\n\n /**\n * Gets the node attribute with the specified type, or null if it does not exist.\n */\n getAttribute(type: \"entry\" | \"ENTRY\"): Entry;\n getAttribute(type: \"exit\" | \"EXIT\"): Exit;\n getAttribute(type: \"step\" | \"STEP\"): Step;\n getAttribute(type: string): Attribute {\n return (\n this.getAttributes().filter((decorator) => decorator.type.toUpperCase() === type.toUpperCase())[0] || null\n );\n }\n\n /**\n * Gets the node attributes.\n */\n getGuardAttributes = (): Guard[] => this.getAttributes().filter((decorator) => decorator.isGuard()) as Guard[];\n\n /**\n * Sets the guard path to evaluate as part of a node update.\n */\n setGuardPath = (value: GuardPath) => (this.guardPath = value);\n\n /**\n * Gets whether a guard path is assigned to this node.\n */\n hasGuardPath = () => !!this.guardPath;\n\n /**\n * Gets whether this node is in the specified state.\n * @param value The value to compare to the node state.\n */\n public is(value: AnyState): boolean {\n return this.state === value;\n }\n\n /**\n * Reset the state of the node.\n */\n public reset(): void {\n this.setState(State.READY);\n }\n\n /**\n * Abort the running of this node.\n * @param agent The agent.\n */\n public abort(agent: Agent): void {\n // There is nothing to do if this node is not in the running state.\n if (!this.is(State.RUNNING)) {\n return;\n }\n\n // Reset the state of this node.\n this.reset();\n\n this.getAttribute(\"exit\")?.callAgentFunction(agent, false, true);\n }\n\n /**\n * Update the node.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n * @returns The result of the update.\n */\n public update(agent: Agent, options: BehaviourTreeOptions): void {\n // If this node is already in a 'SUCCEEDED' or 'FAILED' state then there is nothing to do.\n if (this.is(State.SUCCEEDED) || this.is(State.FAILED)) {\n return;\n }\n\n try {\n // Evaluate all of the guard path conditions for the current tree path.\n this.guardPath!.evaluate(agent);\n\n // If this node is in the READY state then call the ENTRY for this node if it exists.\n if (this.is(State.READY)) {\n this.getAttribute(\"entry\")?.callAgentFunction(agent);\n }\n\n this.getAttribute(\"step\")?.callAgentFunction(agent);\n\n // Do the actual update.\n this.onUpdate(agent, options);\n\n // If this node is now in a 'SUCCEEDED' or 'FAILED' state then call the EXIT for this node if it exists.\n if (this.is(State.SUCCEEDED) || this.is(State.FAILED)) {\n this.getAttribute(\"exit\")?.callAgentFunction(agent, this.is(State.SUCCEEDED), false);\n }\n } catch (error) {\n // If the error is a GuardUnsatisfiedException then we need to determine if this node is the source.\n if (error instanceof GuardUnsatisifedException && error.isSourceNode(this)) {\n // Abort the current node.\n this.abort(agent);\n\n // Any node that is the source of an abort will be a failed node.\n this.setState(State.FAILED);\n } else {\n throw error;\n }\n }\n }\n}\n\n/**\n * Create a randomly generated node uid.\n * @returns A randomly generated node uid.\n */\nfunction createNodeUid(): string {\n var S4 = function () {\n return (((1 + Math.random()) * 0x10000) | 0).toString(16).substring(1);\n };\n return S4() + S4() + \"-\" + S4() + \"-\" + S4() + \"-\" + S4() + \"-\" + S4() + S4() + S4();\n}\n", "import Node from \"../Node\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\n\n/**\n * A composite node that wraps child nodes.\n */\nexport default abstract class Composite extends Node {\n /**\n * @param type The node type.\n * @param attributes The node attributes.\n * @param children The child nodes.\n */\n constructor(type: string, attributes: Attribute[], protected children: Node[]) {\n super(type, attributes, []);\n }\n\n /**\n * Gets whether this node is a leaf node.\n */\n isLeafNode = () => false;\n\n /**\n * Gets the children of this node.\n */\n getChildren = () => this.children;\n\n /**\n * Reset the state of the node.\n */\n reset = () => {\n // Reset the state of this node.\n this.setState(State.READY);\n\n // Reset the state of any child nodes.\n this.getChildren().forEach((child) => child.reset());\n };\n\n /**\n * Abort the running of this node.\n * @param agent The agent.\n */\n abort = (agent: Agent) => {\n // There is nothing to do if this node is not in the running state.\n if (!this.is(State.RUNNING)) {\n return;\n }\n\n // Abort any child nodes.\n this.getChildren().forEach((child) => child.abort(agent));\n\n // Reset the state of this node.\n this.reset();\n\n this.getAttribute(\"exit\")?.callAgentFunction(agent, false, true);\n };\n}\n", "import Composite from \"./Composite\";\nimport State from \"../../State\";\nimport Node from \"../Node\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A PARALLEL node.\n * The child nodes are executed concurrently until one fails or all succeed.\n */\nexport default class Parallel extends Composite {\n /**\n * @param attributes The node attributes.\n * @param children The child nodes.\n */\n constructor(attributes: Attribute[], children: Node[]) {\n super(\"parallel\", attributes, children);\n }\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // Keep a count of the number of succeeded child nodes.\n let succeededCount = 0;\n\n let hasChildFailed = false;\n\n // Iterate over all of the children of this node.\n for (const child of this.children) {\n // If the child has never been updated or is running then we will need to update it now.\n if (child.getState() === State.READY || child.getState() === State.RUNNING) {\n // Update the child of this node.\n child.update(agent, options);\n }\n\n // If the current child has a state of 'SUCCEEDED' then we should move on to the next child.\n if (child.getState() === State.SUCCEEDED) {\n // The child node has succeeded, keep track of this to determine if all children have.\n succeededCount++;\n\n // The child node succeeded, but we have not finished checking every child node yet.\n continue;\n }\n\n // If the current child has a state of 'FAILED' then this node is also a 'FAILED' node.\n if (child.getState() === State.FAILED) {\n hasChildFailed = true;\n\n // There is no need to check the rest of the children.\n break;\n }\n\n // The node should be in the 'RUNNING' state.\n if (child.getState() !== State.RUNNING) {\n // The child node was not in an expected state.\n throw new Error(\"child node was not in an expected state.\");\n }\n }\n\n if (hasChildFailed) {\n // This node is a 'FAILED' node.\n this.setState(State.FAILED);\n\n // Abort every running child.\n for (const child of this.children) {\n if (child.getState() === State.RUNNING) {\n child.abort(agent);\n }\n }\n } else {\n // If all children have succeeded then this node has also succeeded, otherwise it is still running.\n this.setState(succeededCount === this.children.length ? State.SUCCEEDED : State.RUNNING);\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => \"PARALLEL\";\n}\n", "import Composite from \"./Composite\";\nimport Node from \"../Node\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A SELECTOR node.\n * The child nodes are executed in sequence until one succeeds or all fail.\n */\nexport default class Selector extends Composite {\n /**\n * @param attributes The node attributes.\n * @param children The child nodes.\n */\n constructor(attributes: Attribute[], protected children: Node[]) {\n super(\"selector\", attributes, children);\n }\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // Iterate over all of the children of this node.\n for (const child of this.children) {\n // If the child has never been updated or is running then we will need to update it now.\n if (child.getState() === State.READY || child.getState() === State.RUNNING) {\n // Update the child of this node.\n child.update(agent, options);\n }\n\n // If the current child has a state of 'SUCCEEDED' then this node is also a 'SUCCEEDED' node.\n if (child.getState() === State.SUCCEEDED) {\n // This node is a 'SUCCEEDED' node.\n this.setState(State.SUCCEEDED);\n\n // There is no need to check the rest of the selector nodes.\n return;\n }\n\n // If the current child has a state of 'FAILED' then we should move on to the next child.\n if (child.getState() === State.FAILED) {\n // Find out if the current child is the last one in the selector.\n // If it is then this sequence node has also failed.\n if (this.children.indexOf(child) === this.children.length - 1) {\n // This node is a 'FAILED' node.\n this.setState(State.FAILED);\n\n // There is no need to check the rest of the selector as we have completed it.\n return;\n } else {\n // The child node failed, try the next one.\n continue;\n }\n }\n\n // The node should be in the 'RUNNING' state.\n if (child.getState() === State.RUNNING) {\n // This node is a 'RUNNING' node.\n this.setState(State.RUNNING);\n\n // There is no need to check the rest of the selector as the current child is still running.\n return;\n }\n\n // The child node was not in an expected state.\n throw new Error(\"child node was not in an expected state.\");\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => \"SELECTOR\";\n}\n", "import Composite from \"./Composite\";\nimport Node from \"../Node\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A SEQUENCE node.\n * The child nodes are executed in sequence until one fails or all succeed.\n */\nexport default class Sequence extends Composite {\n /**\n * @param attributes The node attributes.\n * @param children The child nodes.\n */\n constructor(attributes: Attribute[], protected children: Node[]) {\n super(\"sequence\", attributes, children);\n }\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // Iterate over all of the children of this node.\n for (const child of this.children) {\n // If the child has never been updated or is running then we will need to update it now.\n if (child.getState() === State.READY || child.getState() === State.RUNNING) {\n // Update the child of this node.\n child.update(agent, options);\n }\n\n // If the current child has a state of 'SUCCEEDED' then we should move on to the next child.\n if (child.getState() === State.SUCCEEDED) {\n // Find out if the current child is the last one in the sequence.\n // If it is then this sequence node has also succeeded.\n if (this.children.indexOf(child) === this.children.length - 1) {\n // This node is a 'SUCCEEDED' node.\n this.setState(State.SUCCEEDED);\n\n // There is no need to check the rest of the sequence as we have completed it.\n return;\n } else {\n // The child node succeeded, but we have not finished the sequence yet.\n continue;\n }\n }\n\n // If the current child has a state of 'FAILED' then this node is also a 'FAILED' node.\n if (child.getState() === State.FAILED) {\n // This node is a 'FAILED' node.\n this.setState(State.FAILED);\n\n // There is no need to check the rest of the sequence.\n return;\n }\n\n // The node should be in the 'RUNNING' state.\n if (child.getState() === State.RUNNING) {\n // This node is a 'RUNNING' node.\n this.setState(State.RUNNING);\n\n // There is no need to check the rest of the sequence as the current child is still running.\n return;\n }\n\n // The child node was not in an expected state.\n throw new Error(\"child node was not in an expected state.\");\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => \"SEQUENCE\";\n}\n", "import createLotto from \"lotto-draw\";\n\nimport Node from \"../Node\";\nimport Composite from \"./Composite\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A LOTTO node.\n * A winning child is picked on the initial update of this node, based on ticket weighting.\n * The state of this node will match the state of the winning child.\n */\nexport default class Lotto extends Composite {\n /**\n * @param attributes The node attributes.\n * @param weights The child node weights.\n * @param children The child nodes.\n */\n constructor(attributes: Attribute[], private weights: number[] | undefined, children: Node[]) {\n super(\"lotto\", attributes, children);\n }\n\n /**\n * The child node selected to be the active one.\n */\n private selectedChild: Node | undefined;\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // If this node is in the READY state then we need to pick a winning child node.\n if (this.is(State.READY)) {\n // Create a lotto draw with which to randomly pick a child node to become the active one.\n const lottoDraw = createLotto({\n // Hook up the optional 'random' behaviour tree function option to the one used by 'lotto-draw'.\n random: options.random,\n // Pass in each child node as a participant in the lotto draw with their respective ticket count.\n participants: this.children.map((child, index) => [child, this.weights?.[index] || 1])\n });\n\n // Randomly pick a child based on ticket weighting, this will become the active child for this composite node.\n this.selectedChild = lottoDraw.draw() || undefined;\n }\n\n // If something went wrong and we don't have an active child then we should throw an error.\n if (!this.selectedChild) {\n throw new Error(\"failed to update lotto node as it has no active child\");\n }\n\n // If the selected child has never been updated or is running then we will need to update it now.\n if (this.selectedChild.getState() === State.READY || this.selectedChild.getState() === State.RUNNING) {\n this.selectedChild.update(agent, options);\n }\n\n // The state of the lotto node is the state of its selected child.\n this.setState(this.selectedChild.getState());\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => (this.weights ? `LOTTO [${this.weights.join(\",\")}]` : \"LOTTO\");\n}\n", "import Node from \"../Node\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\n\n/**\n * A decorator node that wraps a single child node.\n */\nexport default abstract class Decorator extends Node {\n /**\n * @param type The node type.\n * @param attributes The node attributes.\n * @param child The child node.\n */\n constructor(type: string, attributes: Attribute[], protected child: Node) {\n super(type, attributes, []);\n }\n\n /**\n * Gets whether this node is a leaf node.\n */\n isLeafNode = () => false;\n\n /**\n * Gets the children of this node.\n */\n getChildren = () => [this.child];\n\n /**\n * Reset the state of the node.\n */\n reset = () => {\n // Reset the state of this node.\n this.setState(State.READY);\n\n // Reset the state of the child node.\n this.child.reset();\n };\n\n /**\n * Abort the running of this node.\n * @param agent The agent.\n */\n abort = (agent: Agent) => {\n // There is nothing to do if this node is not in the running state.\n if (!this.is(State.RUNNING)) {\n return;\n }\n\n // Abort the child node.\n this.child.abort(agent);\n\n // Reset the state of this node.\n this.reset();\n\n this.getAttribute(\"exit\")?.callAgentFunction(agent, false, true);\n };\n}\n", "import Node from \"../Node\";\nimport Decorator from \"./Decorator\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A Fail node.\n * This node wraps a single child and will always move to the 'FAILED' state when the child moves to a 'SUCCEEDED' or 'FAILED' state.\n */\nexport default class Fail extends Decorator {\n /**\n * @param attributes The node attributes.\n * @param child The child node.\n */\n constructor(attributes: Attribute[], child: Node) {\n super(\"fail\", attributes, child);\n }\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // If the child has never been updated or is running then we will need to update it now.\n if (this.child.getState() === State.READY || this.child.getState() === State.RUNNING) {\n this.child.update(agent, options);\n }\n\n // The state of this node will depend in the state of its child.\n switch (this.child.getState()) {\n case State.RUNNING:\n this.setState(State.RUNNING);\n break;\n\n case State.SUCCEEDED:\n case State.FAILED:\n this.setState(State.FAILED);\n break;\n\n default:\n this.setState(State.READY);\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => \"FAIL\";\n}\n", "import Decorator from \"./Decorator\";\nimport State from \"../../State\";\nimport Node from \"../Node\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A Flip node.\n * This node wraps a single child and will flip the state of the child state.\n */\nexport default class Flip extends Decorator {\n /**\n * @param attributes The node attributes.\n * @param child The child node.\n */\n constructor(attributes: Attribute[], child: Node) {\n super(\"flip\", attributes, child);\n }\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // If the child has never been updated or is running then we will need to update it now.\n if (this.child.getState() === State.READY || this.child.getState() === State.RUNNING) {\n this.child.update(agent, options);\n }\n\n // The state of this node will depend in the state of its child.\n switch (this.child.getState()) {\n case State.RUNNING:\n this.setState(State.RUNNING);\n break;\n\n case State.SUCCEEDED:\n this.setState(State.FAILED);\n break;\n\n case State.FAILED:\n this.setState(State.SUCCEEDED);\n break;\n\n default:\n this.setState(State.READY);\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => \"FLIP\";\n}\n", "import Node from \"../Node\";\nimport Decorator from \"./Decorator\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A REPEAT node.\n * The node has a single child which can have:\n * -- A number of iterations for which to repeat the child node.\n * -- An infinite repeat loop if neither an iteration count or a condition function is defined.\n * The REPEAT node will stop and have a 'FAILED' state if its child is ever in a 'FAILED' state after an update.\n * The REPEAT node will attempt to move on to the next iteration if its child is ever in a 'SUCCEEDED' state.\n */\nexport default class Repeat extends Decorator {\n /**\n * @param attributes The node attributes.\n * @param iterations The number of iterations to repeat the child node.\n * @param iterationsMin The minimum possible number of iterations to repeat the child node.\n * @param iterationsMax The maximum possible number of iterations to repeat the child node.\n * @param child The child node.\n */\n constructor(\n attributes: Attribute[],\n private iterations: number | null,\n private iterationsMin: number | null,\n private iterationsMax: number | null,\n child: Node\n ) {\n super(\"repeat\", attributes, child);\n }\n\n /**\n * The number of target iterations to make.\n */\n private targetIterationCount: number | null = null;\n\n /**\n * The current iteration count.\n */\n private currentIterationCount: number = 0;\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // If this node is in the READY state then we need to reset the child and the target iteration count.\n if (this.is(State.READY)) {\n // Reset the child node.\n this.child.reset();\n\n // Reset the current iteration count.\n this.currentIterationCount = 0;\n\n // Set the target iteration count.\n this.setTargetIterationCount(options);\n }\n\n // Do a check to see if we can iterate. If we can then this node will move into the 'RUNNING' state.\n // If we cannot iterate then we have hit our target iteration count, which means that the node has succeeded.\n if (this.canIterate()) {\n // This node is in the running state and can do its initial iteration.\n this.setState(State.RUNNING);\n\n // We may have already completed an iteration, meaning that the child node will be in the SUCCEEDED state.\n // If this is the case then we will have to reset the child node now.\n if (this.child.getState() === State.SUCCEEDED) {\n this.child.reset();\n }\n\n // Update the child of this node.\n this.child.update(agent, options);\n\n // If the child moved into the FAILED state when we updated it then there is nothing left to do and this node has also failed.\n // If it has moved into the SUCCEEDED state then we have completed the current iteration.\n if (this.child.getState() === State.FAILED) {\n // The child has failed, meaning that this node has failed.\n this.setState(State.FAILED);\n\n return;\n } else if (this.child.getState() === State.SUCCEEDED) {\n // We have completed an iteration.\n this.currentIterationCount += 1;\n }\n } else {\n // This node is in the 'SUCCEEDED' state as we cannot iterate any more.\n this.setState(State.SUCCEEDED);\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => {\n if (this.iterations !== null) {\n return `REPEAT ${this.iterations}x`;\n } else if (this.iterationsMin !== null && this.iterationsMax !== null) {\n return `REPEAT ${this.iterationsMin}x-${this.iterationsMax}x`;\n } else {\n return \"REPEAT\";\n }\n };\n\n /**\n * Reset the state of the node.\n */\n reset = () => {\n // Reset the state of this node.\n this.setState(State.READY);\n\n // Reset the current iteration count.\n this.currentIterationCount = 0;\n\n // Reset the child node.\n this.child.reset();\n };\n\n /**\n * Gets whether an iteration can be made.\n * @returns Whether an iteration can be made.\n */\n private canIterate = () => {\n if (this.targetIterationCount !== null) {\n // We can iterate as long as we have not reached our target iteration count.\n return this.currentIterationCount < this.targetIterationCount;\n }\n\n // If neither an iteration count or a condition function were defined then we can iterate indefinitely.\n return true;\n };\n\n /**\n * Sets the target iteration count.\n * @param options The behaviour tree options object.\n */\n private setTargetIterationCount = (options: BehaviourTreeOptions) => {\n // Are we dealing with an explicit iteration count or will we be randomly picking a iteration count between the min and max iteration count.\n if (this.iterations !== null) {\n this.targetIterationCount = this.iterations;\n } else if (this.iterationsMin !== null && this.iterationsMax !== null) {\n // We will be picking a random iteration count between a min and max iteration count, if the optional 'random'\n // behaviour tree function option is defined then we will be using that, otherwise we will fall back to using Math.random.\n const random = typeof options.random === \"function\" ? options.random : Math.random;\n\n // Pick a random iteration count between a min and max iteration count.\n this.targetIterationCount = Math.floor(\n random() * (this.iterationsMax - this.iterationsMin + 1) + this.iterationsMin\n );\n } else {\n this.targetIterationCount = null;\n }\n };\n}\n", "import Node from \"../Node\";\nimport Decorator from \"./Decorator\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A RETRY node.\n * The node has a single child which can have:\n * -- A number of iterations for which to repeat the child node.\n * -- An infinite repeat loop if neither an iteration count or a condition function is defined.\n * The RETRY node will stop and have a 'SUCCEEDED' state if its child is ever in a 'SUCCEEDED' state after an update.\n * The RETRY node will attempt to move on to the next iteration if its child is ever in a 'FAILED' state.\n */\nexport default class Retry extends Decorator {\n /**\n * @param attributes The node attributes.\n * @param attempts The number of attempts to retry the child node.\n * @param attemptsMin The minimum possible number of attempts to retry the child node.\n * @param attemptsMax The maximum possible number of attempts to retry the child node.\n * @param child The child node.\n */\n constructor(\n attributes: Attribute[],\n private attempts: number | null,\n private attemptsMin: number | null,\n private attemptsMax: number | null,\n child: Node\n ) {\n super(\"retry\", attributes, child);\n }\n\n /**\n * The number of target attempts to make.\n */\n private targetAttemptCount: number | null = null;\n\n /**\n * The current attempt count.\n */\n private currentAttemptCount: number = 0;\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // If this node is in the READY state then we need to reset the child and the target attempt count.\n if (this.is(State.READY)) {\n // Reset the child node.\n this.child.reset();\n\n // Reset the current attempt count.\n this.currentAttemptCount = 0;\n\n // Set the target attempt count.\n this.setTargetAttemptCount(options);\n }\n\n // Do a check to see if we can attempt. If we can then this node will move into the 'RUNNING' state.\n // If we cannot attempt then we have hit our target attempt count, which means that the node has succeeded.\n if (this.canAttempt()) {\n // This node is in the running state and can do its initial attempt.\n this.setState(State.RUNNING);\n\n // We may have already completed an attempt, meaning that the child node will be in the FAILED state.\n // If this is the case then we will have to reset the child node now.\n if (this.child.getState() === State.FAILED) {\n this.child.reset();\n }\n\n // Update the child of this node.\n this.child.update(agent, options);\n\n // If the child moved into the SUCCEEDED state when we updated it then there is nothing left to do and this node has also succeeded.\n // If it has moved into the FAILED state then we have completed the current attempt.\n if (this.child.getState() === State.SUCCEEDED) {\n // The child has succeeded, meaning that this node has succeeded.\n this.setState(State.SUCCEEDED);\n\n return;\n } else if (this.child.getState() === State.FAILED) {\n // We have completed an attempt.\n this.currentAttemptCount += 1;\n }\n } else {\n // This node is in the 'FAILED' state as we cannot iterate any more.\n this.setState(State.FAILED);\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => {\n if (this.attempts !== null) {\n return `RETRY ${this.attempts}x`;\n } else if (this.attemptsMin !== null && this.attemptsMax !== null) {\n return `RETRY ${this.attemptsMin}x-${this.attemptsMax}x`;\n } else {\n return \"RETRY\";\n }\n };\n\n /**\n * Reset the state of the node.\n */\n reset = () => {\n // Reset the state of this node.\n this.setState(State.READY);\n\n // Reset the current attempt count.\n this.currentAttemptCount = 0;\n\n // Reset the child node.\n this.child.reset();\n };\n\n /**\n * Gets whether an attempt can be made.\n * @returns Whether an attempt can be made.\n */\n canAttempt = () => {\n if (this.targetAttemptCount !== null) {\n // We can attempt as long as we have not reached our target attempt count.\n return this.currentAttemptCount < this.targetAttemptCount;\n }\n\n // If neither an attempt count or a condition function were defined then we can attempt indefinitely.\n return true;\n };\n\n /**\n * Sets the target attempt count.\n * @param options The behaviour tree options object.\n */\n setTargetAttemptCount = (options: BehaviourTreeOptions) => {\n // Are we dealing with an explicit attempt count or will we be randomly picking an attempt count between the min and max attempt count.\n if (this.attempts !== null) {\n this.targetAttemptCount = this.attempts;\n } else if (this.attemptsMin !== null && this.attemptsMax !== null) {\n // We will be picking a random attempt count between a min and max attempt count, if the optional 'random'\n // behaviour tree function option is defined then we will be using that, otherwise we will fall back to using Math.random.\n const random = typeof options.random === \"function\" ? options.random : Math.random;\n\n // Pick a random attempt count between a min and max attempt count.\n this.targetAttemptCount = Math.floor(\n random() * (this.attemptsMax - this.attemptsMin + 1) + this.attemptsMin\n );\n } else {\n this.targetAttemptCount = null;\n }\n };\n}\n", "import Node from \"../Node\";\nimport Decorator from \"./Decorator\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A Root node.\n * The root node will have a single child.\n */\nexport default class Root extends Decorator {\n /**\n * @param attributes The node attributes.\n * @param child The child node.\n */\n constructor(attributes: Attribute[], child: Node) {\n super(\"root\", attributes, child);\n }\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // If the child has never been updated or is running then we will need to update it now.\n if (this.child.getState() === State.READY || this.child.getState() === State.RUNNING) {\n // Update the child of this node.\n this.child.update(agent, options);\n }\n\n // The state of the root node is the state of its child.\n this.setState(this.child.getState());\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => \"ROOT\";\n}\n", "import Node from \"../Node\";\nimport Decorator from \"./Decorator\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A Succeed node.\n * This node wraps a single child and will always move to the 'SUCCEEDED' state when the child moves to a 'SUCCEEDED' or 'FAILED' state.\n */\nexport default class Succeed extends Decorator {\n /**\n * @param attributes The node attributes.\n * @param child The child node.\n */\n constructor(attributes: Attribute[], child: Node) {\n super(\"succeed\", attributes, child);\n }\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // If the child has never been updated or is running then we will need to update it now.\n if (this.child.getState() === State.READY || this.child.getState() === State.RUNNING) {\n this.child.update(agent, options);\n }\n\n // The state of this node will depend in the state of its child.\n switch (this.child.getState()) {\n case State.RUNNING:\n this.setState(State.RUNNING);\n break;\n\n case State.SUCCEEDED:\n case State.FAILED:\n this.setState(State.SUCCEEDED);\n break;\n\n default:\n this.setState(State.READY);\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => \"SUCCEED\";\n}\n", "import Node from \"../Node\";\n\n/**\n * A leaf node.\n */\nexport default abstract class Leaf extends Node {\n /**\n * Gets whether this node is a leaf node.\n */\n isLeafNode = () => true;\n}\n", "import { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\nimport State, { CompleteState } from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Leaf from \"./Leaf\";\nimport Lookup from \"../../Lookup\";\nimport Attribute from \"../../attributes/Attribute\";\n\n/**\n * The type representing a resolved/rejected update promise.\n */\ntype UpdatePromiseResult = {\n /**\n * Whether the promise was resolved rather than rejected.\n */\n isResolved: boolean;\n\n /**\n * The promise resolved value or rejection reason.\n */\n value: any;\n};\n\n/**\n * An Action leaf node.\n * This represents an immediate or ongoing state of behaviour.\n */\nexport default class Action extends Leaf {\n /**\n * @param attributes The node attributes.\n * @param actionName The action name.\n * @param actionArguments The array of action argument definitions.\n */\n constructor(attributes: Attribute[], private actionName: string, private actionArguments: any[]) {\n super(\"action\", attributes, actionArguments);\n }\n\n /**\n * Whether there is a pending update promise.\n */\n private isUsingUpdatePromise = false;\n\n /**\n * The finished state result of an update promise.\n */\n private updatePromiseResult: UpdatePromiseResult | null = null;\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // If the result of this action depends on an update promise then there is nothing to do until it settles.\n if (this.isUsingUpdatePromise) {\n // Are we still waiting for our update promise to settle?\n if (!this.updatePromiseResult) {\n return;\n }\n\n const { isResolved, value } = this.updatePromiseResult;\n\n // Our update promise settled, was it resolved or rejected?\n if (isResolved) {\n // Our promise resolved so check to make sure the result is a valid finished state.\n if (value !== State.SUCCEEDED && value !== State.FAILED) {\n throw new Error(\n \"action node promise resolved with an invalid value, expected a State.SUCCEEDED or State.FAILED value to be returned\"\n );\n }\n\n // Set the state of this node to match the state returned by the promise.\n this.setState(value);\n\n return;\n } else {\n // The promise was rejected, which isn't great.\n throw new Error(`action function '${this.actionName}' promise rejected with '${value}'`);\n }\n }\n\n // Attempt to get the invoker for the action function.\n const actionFuncInvoker = Lookup.getFuncInvoker(agent, this.actionName);\n\n // The action function should be defined.\n if (actionFuncInvoker === null) {\n throw new Error(\n `cannot update action node as the action '${this.actionName}' function is not defined on the agent and has not been registered`\n );\n }\n\n let actionFunctionResult;\n\n try {\n // Call the action function, the result of which may be:\n // - The finished state of this action node.\n // - A promise to return a finished node state.\n // - Undefined if the node should remain in the running state.\n actionFunctionResult = actionFuncInvoker(this.actionArguments) as CompleteState | Promise;\n } catch (error) {\n // An uncaught error was thrown.\n if (error instanceof Error) {\n throw new Error(`action function '${this.actionName}' threw: ${error.stack}`);\n } else {\n throw new Error(`action function '${this.actionName}' threw: ${error}`);\n }\n }\n\n if (actionFunctionResult instanceof Promise) {\n actionFunctionResult.then(\n (result) => {\n // If 'isUpdatePromisePending' is not set then the promise was cleared as it was resolving, probably via an abort of reset.\n if (!this.isUsingUpdatePromise) {\n return;\n }\n\n // Set the resolved update promise result so that it can be handled on the next update of this node.\n this.updatePromiseResult = {\n isResolved: true,\n value: result\n };\n },\n (reason) => {\n // If 'isUpdatePromisePending' is not set then the promise was cleared as it was resolving, probably via an abort or reset.\n if (!this.isUsingUpdatePromise) {\n return;\n }\n\n // Set the rejected update promise result so that it can be handled on the next update of this node.\n this.updatePromiseResult = {\n isResolved: false,\n value: reason\n };\n }\n );\n\n // This node will be in the 'RUNNING' state until the update promise resolves.\n this.setState(State.RUNNING);\n\n // We are now waiting for the promise returned by the use to resolve before we know what state this node is in.\n this.isUsingUpdatePromise = true;\n } else {\n // Validate the returned value.\n this.validateUpdateResult(actionFunctionResult);\n\n // Set the state of this node, this may be undefined, which just means that the node is still in the 'RUNNING' state.\n this.setState(actionFunctionResult || State.RUNNING);\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => this.actionName;\n\n /**\n * Reset the state of the node.\n */\n reset = () => {\n // Reset the state of this node.\n this.setState(State.READY);\n\n // There is no longer an update promise that we care about.\n this.isUsingUpdatePromise = false;\n this.updatePromiseResult = null;\n };\n\n /**\n * Validate the result of an update function call.\n * @param result The result of an update function call.\n */\n private validateUpdateResult = (result: CompleteState | State.RUNNING) => {\n switch (result) {\n case State.SUCCEEDED:\n case State.FAILED:\n case State.RUNNING:\n case undefined:\n return;\n default:\n throw new Error(\n `expected action function '${this.actionName}' to return an optional State.SUCCEEDED or State.FAILED value but returned '${result}'`\n );\n }\n };\n}\n", "import { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Leaf from \"./Leaf\";\nimport Lookup from \"../../Lookup\";\nimport Attribute from \"../../attributes/Attribute\";\n\n/**\n * A Condition leaf node.\n * This will succeed or fail immediately based on an agent predicate, without moving to the 'RUNNING' state.\n */\nexport default class Condition extends Leaf {\n /**\n * @param attributes The node attributes.\n * @param conditionName The name of the condition function.\n * @param conditionArguments The array of condition argument definitions.\n */\n constructor(attributes: Attribute[], private conditionName: string, private conditionArguments: any[]) {\n super(\"condition\", attributes, conditionArguments);\n }\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // Attempt to get the invoker for the condition function.\n const conditionFuncInvoker = Lookup.getFuncInvoker(agent, this.conditionName);\n\n // The condition function should be defined.\n if (conditionFuncInvoker === null) {\n throw new Error(\n `cannot update condition node as the condition '${this.conditionName}' function is not defined on the agent and has not been registered`\n );\n }\n\n let conditionFunctionResult;\n\n try {\n // Call the condition function to determine the state of this node, the result of which should be a boolean.\n conditionFunctionResult = conditionFuncInvoker(this.conditionArguments);\n } catch (error) {\n // An uncaught error was thrown.\n if (error instanceof Error) {\n throw new Error(`condition function '${this.conditionName}' threw: ${error.stack}`);\n } else {\n throw new Error(`condition function '${this.conditionName}' threw: ${error}`);\n }\n }\n\n // The result of calling the condition function must be a boolean value.\n if (typeof conditionFunctionResult !== \"boolean\") {\n throw new Error(\n `expected condition function '${this.conditionName}' to return a boolean but returned '${conditionFunctionResult}'`\n );\n }\n\n // Set the state of this node based on the result of calling the condition function.\n this.setState(!!conditionFunctionResult ? State.SUCCEEDED : State.FAILED);\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => this.conditionName;\n}\n", "import Leaf from \"./Leaf\";\nimport State from \"../../State\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { Agent } from \"../../Agent\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A WAIT node.\n * The state of this node will change to SUCCEEDED after a duration of time\n */\nexport default class Wait extends Leaf {\n /**\n * @param attributes The node attributes.\n * @param duration The duration that this node will wait to succeed in milliseconds.\n * @param durationMin The minimum possible duration in milliseconds that this node will wait to succeed.\n * @param durationMax The maximum possible duration in milliseconds that this node will wait to succeed.\n */\n constructor(\n attributes: Attribute[],\n private duration: number | null,\n private durationMin: number | null,\n private durationMax: number | null\n ) {\n super(\"wait\", attributes, []);\n }\n\n /**\n * The time in milliseconds at which this node was first updated.\n */\n private initialUpdateTime: number = 0;\n\n /**\n * The total duration in milliseconds that this node will be waiting for.\n */\n private totalDuration: number | null = null;\n\n /**\n * The duration in milliseconds that this node has been waiting for.\n */\n private waitedDuration: number = 0;\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // If this node is in the READY state then we need to set the initial update time.\n if (this.is(State.READY)) {\n // Set the initial update time.\n this.initialUpdateTime = new Date().getTime();\n\n // Set the initial waited duration.\n this.waitedDuration = 0;\n\n // Are we dealing with an explicit duration or will we be randomly picking a duration between the min and max duration.\n if (this.duration !== null) {\n this.totalDuration = this.duration;\n } else if (this.durationMin !== null && this.durationMax !== null) {\n // We will be picking a random duration between a min and max duration, if the optional 'random' behaviour tree\n // function option is defined then we will be using that, otherwise we will fall back to using Math.random.\n const random = typeof options.random === \"function\" ? options.random : Math.random;\n\n // Pick a random duration between a min and max duration.\n this.totalDuration = Math.floor(\n random() * (this.durationMax - this.durationMin + 1) + this.durationMin\n );\n } else {\n this.totalDuration = null;\n }\n\n // The node is now running until we finish waiting.\n this.setState(State.RUNNING);\n }\n\n // If we have no total duration then this wait node will wait indefinitely until it is aborted.\n if (this.totalDuration === null) {\n return;\n }\n\n // If we have a 'getDeltaTime' function defined as part of our options then we will use it to figure out how long we have waited for.\n if (typeof options.getDeltaTime === \"function\") {\n // Get the delta time.\n const deltaTime = options.getDeltaTime();\n\n // Our delta time must be a valid number and cannot be NaN.\n if (typeof deltaTime !== \"number\" || isNaN(deltaTime)) {\n throw new Error(\"The delta time must be a valid number and not NaN.\");\n }\n\n // Update the amount of time that this node has been waiting for based on the delta time.\n this.waitedDuration += deltaTime * 1000;\n } else {\n // We are not using a delta time, so we will just work out hom much time has passed since the first update.\n this.waitedDuration = new Date().getTime() - this.initialUpdateTime;\n }\n\n // Have we waited long enough?\n if (this.waitedDuration >= this.totalDuration) {\n // We have finished waiting!\n this.setState(State.SUCCEEDED);\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => {\n if (this.duration !== null) {\n return `WAIT ${this.duration}ms`;\n } else if (this.durationMin !== null && this.durationMax !== null) {\n return `WAIT ${this.durationMin}ms-${this.durationMax}ms`;\n } else {\n return \"WAIT\";\n }\n };\n}\n", "import Guard from \"./guards/Guard\";\n\nexport type AttributeDetails = {\n /** The attribute type. */\n type: string;\n\n /** The attribute arguments. */\n args: any[];\n};\n\n/**\n * A base node attribute.\n */\nexport default abstract class Attribute {\n /**\n * @param type The node attribute type.\n * @param args The array of attribute arguments.\n */\n constructor(public type: string, public args: any[]) {}\n\n /**\n * Gets the attribute details.\n */\n abstract getDetails(): TAttributeDetails;\n\n /**\n * Gets whether this attribute is a guard.\n */\n abstract isGuard: () => this is Guard;\n}\n", "import { Agent } from \"../../Agent\";\nimport Attribute, { AttributeDetails } from \"../Attribute\";\n\nexport type GuardAttributeDetails = {\n /** The name of the condition function that determines whether the guard is satisfied. */\n condition: string;\n} & AttributeDetails;\n\n/**\n * A base node guard attribute.\n */\nexport default abstract class Guard extends Attribute {\n /**\n * @param type The node attribute type.\n * @param args The array of decorator argument definitions.\n * @param condition The name of the condition function that determines whether the guard is satisfied.\n */\n constructor(type: string, args: any[], private condition: string) {\n super(type, args);\n }\n\n /**\n * Gets the name of the condition function that determines whether the guard is satisfied.\n */\n getCondition = () => this.condition;\n\n /**\n * Gets whether this attribute is a guard.\n */\n isGuard = () => true;\n\n /**\n * Gets the attribute details.\n */\n getDetails(): GuardAttributeDetails {\n return {\n type: this.type,\n args: this.args,\n condition: this.getCondition()\n };\n }\n\n /**\n * Gets whether the guard is satisfied.\n * @param agent The agent.\n * @returns Whether the guard is satisfied.\n */\n abstract isSatisfied(agent: Agent): boolean;\n}\n", "import Guard from \"./Guard\";\nimport Lookup from \"../../Lookup\";\nimport { Agent } from \"../../Agent\";\n\n/**\n * A WHILE guard which is satisfied as long as the given condition remains true.\n */\nexport default class While extends Guard {\n /**\n * @param condition The name of the condition function that determines whether the guard is satisfied.\n * @param args The array of decorator argument definitions.\n */\n constructor(condition: string, args: any[]) {\n super(\"while\", args, condition);\n }\n\n /**\n * Gets whether the guard is satisfied.\n * @param agent The agent.\n * @returns Whether the guard is satisfied.\n */\n isSatisfied = (agent: Agent) => {\n // Attempt to get the invoker for the condition function.\n const conditionFuncInvoker = Lookup.getFuncInvoker(agent, this.getCondition());\n\n // The condition function should be defined.\n if (conditionFuncInvoker === null) {\n throw new Error(\n `cannot evaluate node guard as the condition '${this.getCondition()}' function is not defined on the agent and has not been registered`\n );\n }\n\n let conditionFunctionResult;\n\n try {\n // Call the guard condition function to determine the state of this node, the result of which should be a boolean.\n conditionFunctionResult = conditionFuncInvoker(this.args);\n } catch (error) {\n // An uncaught error was thrown.\n if (error instanceof Error) {\n throw new Error(`guard condition function '${this.getCondition()}' threw: ${error.stack}`);\n } else {\n throw new Error(`guard condition function '${this.getCondition()}' threw: ${error}`);\n }\n }\n\n // The result of calling the guard condition function must be a boolean value.\n if (typeof conditionFunctionResult !== \"boolean\") {\n throw new Error(\n `expected guard condition function '${this.getCondition()}' to return a boolean but returned '${conditionFunctionResult}'`\n );\n }\n\n // Return whether this guard is satisfied.\n return conditionFunctionResult;\n };\n}\n", "import Guard from \"./Guard\";\nimport Lookup from \"../../Lookup\";\nimport { Agent } from \"../../Agent\";\n\n/**\n * An UNTIL guard which is satisfied as long as the given condition remains false.\n */\nexport default class Until extends Guard {\n /**\n * @param condition The name of the condition function that determines whether the guard is satisfied.\n * @param args The array of decorator argument definitions.\n */\n constructor(condition: string, args: any[]) {\n super(\"until\", args, condition);\n }\n\n /**\n * Gets whether the guard is satisfied.\n * @param agent The agent.\n * @returns Whether the guard is satisfied.\n */\n isSatisfied = (agent: Agent) => {\n // Attempt to get the invoker for the condition function.\n const conditionFuncInvoker = Lookup.getFuncInvoker(agent, this.getCondition());\n\n // The condition function should be defined.\n if (conditionFuncInvoker === null) {\n throw new Error(\n `cannot evaluate node guard as the condition '${this.getCondition()}' function is not defined on the agent and has not been registered`\n );\n }\n\n let conditionFunctionResult;\n\n try {\n // Call the guard condition function to determine the state of this node, the result of which should be a boolean.\n conditionFunctionResult = conditionFuncInvoker(this.args);\n } catch (error) {\n // An uncaught error was thrown.\n if (error instanceof Error) {\n throw new Error(`guard condition function '${this.getCondition()}' threw: ${error.stack}`);\n } else {\n throw new Error(`guard condition function '${this.getCondition()}' threw: ${error}`);\n }\n }\n\n // The result of calling the guard condition function must be a boolean value.\n if (typeof conditionFunctionResult !== \"boolean\") {\n throw new Error(\n `expected guard condition function '${this.getCondition()}' to return a boolean but returned '${conditionFunctionResult}'`\n );\n }\n\n // Return whether this guard is satisfied.\n return !conditionFunctionResult;\n };\n}\n", "import { Agent } from \"../../Agent\";\nimport Attribute, { AttributeDetails } from \"../Attribute\";\n\nexport type CallbackAttributeDetails = {\n /** The name of the agent function that is called. */\n functionName: string;\n} & AttributeDetails;\n\n/**\n * A base node callback attribute.\n */\nexport default abstract class Callback extends Attribute {\n /**\n * @param type The node attribute type.\n * @param args The array of decorator argument definitions.\n * @param functionName The name of the agent function to call.\n */\n constructor(type: string, args: any[], private functionName: string) {\n super(type, args);\n }\n\n /**\n * Gets the name of the agent function to call.\n */\n getFunctionName = () => this.functionName;\n\n /**\n * Gets whether this attribute is a guard.\n */\n isGuard = () => false;\n\n /**\n * Gets the attribute details.\n */\n getDetails(): CallbackAttributeDetails {\n return {\n type: this.type,\n args: this.args,\n functionName: this.getFunctionName()\n };\n }\n\n /**\n * Attempt to call the agent function that this callback refers to.\n * @param agent The agent.\n */\n abstract callAgentFunction: (agent: Agent, isSuccess: boolean, isAborted: boolean) => void;\n}\n", "import Callback from \"./Callback\";\nimport Lookup from \"../../Lookup\";\nimport { Agent } from \"../../Agent\";\n\n/**\n * An ENTRY callback which defines an agent function to call when the associated node is updated and moves out of running state.\n */\nexport default class Entry extends Callback {\n /**\n * @param functionName The name of the agent function to call.\n * @param args The array of callback argument definitions.\n */\n constructor(functionName: string, args: any[]) {\n super(\"entry\", args, functionName);\n }\n\n /**\n * Attempt to call the agent function that this callback refers to.\n * @param agent The agent.\n */\n callAgentFunction = (agent: Agent) => {\n // Attempt to get the invoker for the callback function.\n const callbackFuncInvoker = Lookup.getFuncInvoker(agent, this.getFunctionName());\n\n // The callback function should be defined.\n if (callbackFuncInvoker === null) {\n throw new Error(\n `cannot call entry function '${this.getFunctionName()}' as is not defined on the agent and has not been registered`\n );\n }\n\n // Call the callback function.\n callbackFuncInvoker(this.args);\n };\n}\n", "import Callback from \"./Callback\";\nimport Lookup from \"../../Lookup\";\nimport { Agent } from \"../../Agent\";\n\n/**\n * A STEP callback which defines an agent function to call when the associated node is updated.\n */\nexport default class Step extends Callback {\n /**\n * @param functionName The name of the agent function to call.\n * @param args The array of callback argument definitions.\n */\n constructor(functionName: string, args: any[]) {\n super(\"step\", args, functionName);\n }\n\n /**\n * Attempt to call the agent function that this callback refers to.\n * @param agent The agent.\n */\n callAgentFunction = (agent: Agent) => {\n // Attempt to get the invoker for the callback function.\n const callbackFuncInvoker = Lookup.getFuncInvoker(agent, this.getFunctionName());\n\n // The callback function should be defined.\n if (callbackFuncInvoker === null) {\n throw new Error(\n `cannot call step function '${this.getFunctionName()}' as is not defined on the agent and has not been registered`\n );\n }\n\n // Call the callback function.\n callbackFuncInvoker(this.args);\n };\n}\n", "import Callback from \"./Callback\";\nimport Lookup from \"../../Lookup\";\nimport { Agent } from \"../../Agent\";\n\n/**\n * An EXIT callback which defines an agent function to call when the associated node is updated and moves to a finished state or is aborted.\n */\nexport default class Exit extends Callback {\n /**\n * @param functionName The name of the agent function to call.\n * @param args The array of callback argument definitions.\n */\n constructor(functionName: string, args: any[]) {\n super(\"exit\", args, functionName);\n }\n\n /**\n * Attempt to call the agent function that this callback refers to.\n * @param agent The agent.\n * @param isSuccess Whether the decorated node was left with a success state.\n * @param isAborted Whether the decorated node was aborted.\n */\n callAgentFunction = (agent: Agent, isSuccess: boolean, isAborted: boolean) => {\n // Attempt to get the invoker for the callback function.\n const callbackFuncInvoker = Lookup.getFuncInvoker(agent, this.getFunctionName());\n\n // The callback function should be defined.\n if (callbackFuncInvoker === null) {\n throw new Error(\n `cannot call exit function '${this.getFunctionName()}' as is not defined on the agent and has not been registered`\n );\n }\n\n // Call the callback function\n callbackFuncInvoker([{ succeeded: isSuccess, aborted: isAborted }, ...this.args]);\n };\n}\n", "import { AnyNodeDefinition, RootNodeDefinition } from \"./BehaviourTreeDefinition\";\nimport GuardPath, { GuardPathPart } from \"./attributes/guards/GuardPath\";\nimport { validateBranchSubtreeLinks } from \"./BehaviourTreeDefinitionValidator\";\nimport { isInteger } from \"./BehaviourTreeDefinitionUtilities\";\nimport Node from \"./nodes/Node\";\nimport Composite from \"./nodes/composite/Composite\";\nimport Decorator from \"./nodes/decorator/Decorator\";\nimport Parallel from \"./nodes/composite/Parallel\";\nimport Selector from \"./nodes/composite/Selector\";\nimport Sequence from \"./nodes/composite/Sequence\";\nimport Lotto from \"./nodes/composite/Lotto\";\nimport Fail from \"./nodes/decorator/Fail\";\nimport Flip from \"./nodes/decorator/Flip\";\nimport Repeat from \"./nodes/decorator/Repeat\";\nimport Retry from \"./nodes/decorator/Retry\";\nimport Root from \"./nodes/decorator/Root\";\nimport Succeed from \"./nodes/decorator/Succeed\";\nimport Action from \"./nodes/leaf/Action\";\nimport Condition from \"./nodes/leaf/Condition\";\nimport Wait from \"./nodes/leaf/Wait\";\nimport Lookup from \"./Lookup\";\nimport Attribute from \"./attributes/Attribute\";\nimport While from \"./attributes/guards/While\";\nimport Until from \"./attributes/guards/Until\";\nimport Entry from \"./attributes/callbacks/Entry\";\nimport Step from \"./attributes/callbacks/Step\";\nimport Exit from \"./attributes/callbacks/Exit\";\n\n/**\n * A type representing any node instance in a behaviour tree.\n */\ntype AnyNode =\n | Root\n | Action\n | Condition\n | Wait\n | Sequence\n | Selector\n | Lotto\n | Parallel\n | Repeat\n | Retry\n | Flip\n | Succeed\n | Fail;\n\n/**\n * A type defining a mapping of root node identifiers to root node definitions.\n */\ntype RootNodeDefinitionMap = { [key: string | symbol]: RootNodeDefinition };\n\n/**\n * A symbol to use as the main root key in any root node mappings.\n */\nconst MAIN_ROOT_NODE_KEY = Symbol(\"__root__\");\n\n/**\n * Build and populate the root nodes based on the provided definition, assuming that the definition has been validated.\n * @param definition The root node definitions.\n * @returns The built and populated root node definitions.\n */\nexport default function buildRootNode(definition: RootNodeDefinition[]): Root {\n // Create a mapping of root node identifers to root node definitions, including globally registered subtree root node definitions.\n const rootNodeDefinitionMap = createRootNodeDefinitionMap(definition);\n\n // Now that we have all of our root node definitions (those part of the tree definition and those globally registered)\n // we should validate the branch-subtree links. This will also double-check that we dont have any circular dependencies\n // in our branch-subtree references and that we have no broken branch-subtree links.\n validateBranchSubtreeLinks(\n [rootNodeDefinitionMap[MAIN_ROOT_NODE_KEY], ...Object.values(rootNodeDefinitionMap)],\n true\n );\n\n // Create our populated tree of node instances, starting with our main root node.\n const rootNode = nodeFactory(rootNodeDefinitionMap[MAIN_ROOT_NODE_KEY], rootNodeDefinitionMap) as Root;\n\n // Set a guard path on every leaf of the tree to evaluate as part of each update.\n applyLeafNodeGuardPaths(rootNode);\n\n // We only need to return the main root node.\n return rootNode;\n}\n\n/**\n * A factory function which creates a node instance based on the specified definition.\n * @param definition The node definition.\n * @param rootNodeDefinitionMap The mapping of root node identifers to root node definitions, including globally registered subtree root node definitions.\n * @returns A node instance based on the specified definition.\n */\nfunction nodeFactory(definition: AnyNodeDefinition, rootNodeDefinitionMap: RootNodeDefinitionMap): AnyNode {\n // Get the attributes for the node.\n const attributes = nodeAttributesFactory(definition);\n\n // Create the node instance based on the definition type.\n switch (definition.type) {\n case \"root\":\n return new Root(attributes, nodeFactory(definition.child, rootNodeDefinitionMap));\n\n case \"repeat\":\n let iterations: number | null = null;\n let iterationsMin: number | null = null;\n let iterationsMax: number | null = null;\n\n if (Array.isArray(definition.iterations)) {\n iterationsMin = definition.iterations[0];\n iterationsMax = definition.iterations[1];\n } else if (isInteger(definition.iterations)) {\n iterations = definition.iterations!;\n }\n\n return new Repeat(\n attributes,\n iterations,\n iterationsMin,\n iterationsMax,\n nodeFactory(definition.child, rootNodeDefinitionMap)\n );\n\n case \"retry\":\n let attempts: number | null = null;\n let attemptsMin: number | null = null;\n let attemptsMax: number | null = null;\n\n if (Array.isArray(definition.attempts)) {\n attemptsMin = definition.attempts[0];\n attemptsMax = definition.attempts[1];\n } else if (isInteger(definition.attempts)) {\n attempts = definition.attempts!;\n }\n\n return new Retry(\n attributes,\n attempts,\n attemptsMin,\n attemptsMax,\n nodeFactory(definition.child, rootNodeDefinitionMap)\n );\n\n case \"flip\":\n return new Flip(attributes, nodeFactory(definition.child, rootNodeDefinitionMap));\n\n case \"succeed\":\n return new Succeed(attributes, nodeFactory(definition.child, rootNodeDefinitionMap));\n\n case \"fail\":\n return new Fail(attributes, nodeFactory(definition.child, rootNodeDefinitionMap));\n\n case \"sequence\":\n return new Sequence(\n attributes,\n definition.children.map((child) => nodeFactory(child, rootNodeDefinitionMap))\n );\n\n case \"selector\":\n return new Selector(\n attributes,\n definition.children.map((child) => nodeFactory(child, rootNodeDefinitionMap))\n );\n\n case \"parallel\":\n return new Parallel(\n attributes,\n definition.children.map((child) => nodeFactory(child, rootNodeDefinitionMap))\n );\n\n case \"lotto\":\n return new Lotto(\n attributes,\n definition.weights,\n definition.children.map((child) => nodeFactory(child, rootNodeDefinitionMap))\n );\n\n case \"branch\":\n return nodeFactory(rootNodeDefinitionMap[definition.ref].child, rootNodeDefinitionMap);\n\n case \"action\":\n return new Action(attributes, definition.call, definition.args || []);\n\n case \"condition\":\n return new Condition(attributes, definition.call, definition.args || []);\n\n case \"wait\":\n let duration: number | null = null;\n let durationMin: number | null = null;\n let durationMax: number | null = null;\n\n if (Array.isArray(definition.duration)) {\n durationMin = definition.duration[0];\n durationMax = definition.duration[1];\n } else if (isInteger(definition.duration)) {\n duration = definition.duration!;\n }\n\n return new Wait(attributes, duration, durationMin, durationMax);\n }\n}\n\n/**\n * Creates an array of node attribute instances based on the specified node definition.\n * @param definition The node definition.\n * @returns An array of node attribute instances based on the specified node definition.\n */\nfunction nodeAttributesFactory(definition: AnyNodeDefinition): Attribute[] {\n const attributes: Attribute[] = [];\n\n if (definition.while) {\n attributes.push(new While(definition.while.call, definition.while.args ?? []));\n }\n\n if (definition.until) {\n attributes.push(new Until(definition.until.call, definition.until.args ?? []));\n }\n\n if (definition.entry) {\n attributes.push(new Entry(definition.entry.call, definition.entry.args ?? []));\n }\n\n if (definition.step) {\n attributes.push(new Step(definition.step.call, definition.step.args ?? []));\n }\n\n if (definition.exit) {\n attributes.push(new Exit(definition.exit.call, definition.exit.args ?? []));\n }\n\n return attributes;\n}\n\n/**\n * Creates a mapping of root node identifers to root node definitions, mixing in globally registered subtree root node definitions.\n * @param definition The root node definitions.\n * @returns A mapping of root node identifers to root node definitions, including globally registered subtree root node definitions.\n */\nfunction createRootNodeDefinitionMap(definition: RootNodeDefinition[]): RootNodeDefinitionMap {\n // Create a mapping of root node identifers to root node definitions.\n const rootNodeMap: RootNodeDefinitionMap = {};\n\n // Add in any registered subtree root node definitions.\n for (const [name, rootNodeDefinition] of Object.entries(Lookup.getSubtrees())) {\n // The name used when registering the subtree will be used as the root node identifier.\n rootNodeMap[name] = { ...rootNodeDefinition, id: name };\n }\n\n // Populate the map with the root node definitions that were included with the tree definition.\n // We do this after adding any registered subtrees as we want these to take presedence.\n for (const rootNodeDefinition of definition) {\n rootNodeMap[rootNodeDefinition.id ?? MAIN_ROOT_NODE_KEY] = rootNodeDefinition;\n }\n\n return rootNodeMap;\n}\n\n/**\n * Applies a guard path to every leaf of the tree to evaluate as part of each update.\n * @param root The main root tree node.\n */\nfunction applyLeafNodeGuardPaths(root: Root) {\n const nodePaths: Node[][] = [];\n\n const findLeafNodes = (path: Node[], node: Node) => {\n // Add the current node to the path.\n path = path.concat(node);\n\n // Check whether the current node is a leaf node.\n if (node.isLeafNode()) {\n nodePaths.push(path);\n } else {\n (node as Composite | Decorator).getChildren().forEach((child) => findLeafNodes(path, child));\n }\n };\n\n // Find all leaf node paths, starting from the root.\n findLeafNodes([], root);\n\n nodePaths.forEach((path) => {\n // Each node in the current path will have to be assigned a guard path, working from the root outwards.\n for (let depth = 0; depth < path.length; depth++) {\n // Get the node in the path at the current depth.\n const currentNode = path[depth];\n\n // The node may already have been assigned a guard path, if so just skip it.\n if (currentNode.hasGuardPath()) {\n continue;\n }\n\n // Create the guard path for the current node.\n const guardPath = new GuardPath(\n path\n .slice(0, depth + 1)\n .map((node) => ({ node, guards: node.getGuardAttributes() }))\n .filter((details) => details.guards.length > 0)\n );\n\n // Assign the guard path to the current node.\n currentNode.setGuardPath(guardPath);\n }\n });\n}\n", "import State, { AnyState } from \"./State\";\nimport Lookup from \"./Lookup\";\nimport Node from \"./nodes/Node\";\nimport Root from \"./nodes/decorator/Root\";\nimport Composite from \"./nodes/composite/Composite\";\nimport Decorator from \"./nodes/decorator/Decorator\";\nimport { Agent, GlobalFunction } from \"./Agent\";\nimport { CallbackAttributeDetails } from \"./attributes/callbacks/Callback\";\nimport { GuardAttributeDetails } from \"./attributes/guards/Guard\";\nimport { BehaviourTreeOptions } from \"./BehaviourTreeOptions\";\nimport { convertMDSLToJSON } from \"./mdsl/MDSLDefinitionParser\";\nimport { RootNodeDefinition } from \"./BehaviourTreeDefinition\";\nimport { validateDefinition, validateJSONDefinition } from \"./BehaviourTreeDefinitionValidator\";\nimport buildRootNode from \"./BehaviourTreeBuilder\";\nimport { isNullOrUndefined } from \"./BehaviourTreeDefinitionUtilities\";\n\n// Purely for outside inspection of the tree.\nexport type FlattenedTreeNode = {\n id: string;\n type: string;\n caption: string;\n state: AnyState;\n guards: GuardAttributeDetails[];\n callbacks: CallbackAttributeDetails[];\n args: any[];\n parentId: string | null;\n};\n\n/**\n * A representation of a behaviour tree.\n */\nexport class BehaviourTree {\n /**\n * The main root tree node.\n */\n private readonly _rootNode: Root;\n\n /**\n * Creates a new instance of the BehaviourTree class.\n * @param definition The behaviour tree definition as either an MDSL string, root node definition object or array of root node definition objects.\n * @param agent The agent instance that this behaviour tree is modelling behaviour for.\n * @param options The behaviour tree options object.\n */\n constructor(\n definition: string | RootNodeDefinition | RootNodeDefinition[],\n private agent: Agent,\n private options: BehaviourTreeOptions = {}\n ) {\n // The tree definition must be defined.\n if (isNullOrUndefined(definition)) {\n throw new Error(\"tree definition not defined\");\n }\n\n // The agent must be defined and not null.\n if (typeof agent !== \"object\" || agent === null) {\n throw new Error(\"the agent must be an object and not null\");\n }\n\n // We should validate the definition before we try to build the tree nodes.\n const { succeeded, errorMessage, json } = validateDefinition(definition);\n\n // Did our validation fail without error?\n if (!succeeded) {\n throw new Error(`invalid definition: ${errorMessage}`);\n }\n\n // Double check that we did actually get our json definition as part of our definition validtion.\n if (!json) {\n throw new Error(\n \"expected json definition to be returned as part of successful definition validation response\"\n );\n }\n\n try {\n // Create the populated tree of behaviour tree nodes and get the root node.\n this._rootNode = buildRootNode(json);\n } catch (exception) {\n // There was an issue in trying build and populate the behaviour tree.\n throw new Error(`error building tree: ${(exception as Error).message}`);\n }\n }\n\n /**\n * Gets whether the tree is in the RUNNING state.\n * @returns true if the tree is in the RUNNING state, otherwise false.\n */\n isRunning() {\n return this._rootNode.getState() === State.RUNNING;\n }\n\n /**\n * Gets the current tree state of SUCCEEDED, FAILED, READY or RUNNING.\n * @returns The current tree state.\n */\n getState() {\n return this._rootNode.getState();\n }\n\n /**\n * Step the tree.\n * 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.\n * 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\n * 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.\n *\n * 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.\n */\n step() {\n // If the root node has already been stepped to completion then we need to reset it.\n if (this._rootNode.getState() === State.SUCCEEDED || this._rootNode.getState() === State.FAILED) {\n this._rootNode.reset();\n }\n\n try {\n this._rootNode.update(this.agent, this.options);\n } catch (exception) {\n throw new Error(`error stepping tree: ${(exception as Error).message}`);\n }\n }\n\n /**\n * Resets the tree from the root node outwards to each nested node, giving each a state of READY.\n */\n reset() {\n this._rootNode.reset();\n }\n\n /**\n * Gets the flattened details of every node in the tree.\n * @returns The flattened details of every node in the tree.\n */\n getFlattenedNodeDetails(): FlattenedTreeNode[] {\n // Create an empty flattened array of tree nodes.\n const flattenedTreeNodes: FlattenedTreeNode[] = [];\n\n /**\n * Helper function to process a node instance and push details into the flattened tree nodes array.\n * @param node The current node.\n * @param parentUid The UID of the node parent, or null if the node is the main root node.\n */\n const processNode = (node: Node, parentUid: string | null) => {\n // Get the guard and callback attribute details for this node.\n const guards = node\n .getAttributes()\n .filter((attribute) => attribute.isGuard())\n .map((attribute) => attribute.getDetails()) as GuardAttributeDetails[];\n const callbacks = node\n .getAttributes()\n .filter((attribute) => !attribute.isGuard())\n .map((attribute) => attribute.getDetails()) as CallbackAttributeDetails[];\n\n // Push the current node into the flattened nodes array.\n flattenedTreeNodes.push({\n id: node.getUid(),\n type: node.getType(),\n caption: node.getName(),\n state: node.getState(),\n guards,\n callbacks,\n args: node.getArguments(),\n parentId: parentUid\n });\n\n // Process each of the nodes children if it is not a leaf node.\n if (!node.isLeafNode()) {\n (node as Composite | Decorator)\n .getChildren()\n .forEach((child) => processNode(child, (node as Composite | Decorator).getUid()));\n }\n };\n\n // Convert the nested node structure into a flattened array of node details.\n processNode(this._rootNode, null);\n\n return flattenedTreeNodes;\n }\n\n /**\n * Registers the action/condition/guard/callback function or subtree with the given name.\n * @param name The name of the function or subtree to register.\n * @param value The function or subtree definition to register.\n */\n static register(name: string, value: GlobalFunction | string | RootNodeDefinition) {\n // Are we going to register a action/condition/guard/callback function?\n if (typeof value === \"function\") {\n Lookup.setFunc(name, value);\n return;\n }\n\n // We are not registering an action/condition/guard/callback function, so we must be registering a subtree.\n if (typeof value === \"string\") {\n let rootNodeDefinitions: RootNodeDefinition[];\n\n // We will assume that any string passed in will be a mdsl definition.\n try {\n rootNodeDefinitions = convertMDSLToJSON(value);\n } catch (exception) {\n throw new Error(`error registering definition, invalid MDSL: ${(exception as Error).message}`);\n }\n\n // This function should only ever be called with a definition containing a single unnamed root node.\n if (rootNodeDefinitions.length != 1 || typeof rootNodeDefinitions[0].id !== \"undefined\") {\n throw new Error(\"error registering definition: expected a single unnamed root node\");\n }\n\n try {\n // We should validate the subtree as we don't want invalid subtrees available via the lookup.\n const { succeeded, errorMessage } = validateJSONDefinition(rootNodeDefinitions[0]);\n\n // Did our validation fail without error?\n if (!succeeded) {\n throw new Error(errorMessage);\n }\n } catch (exception) {\n throw new Error(`error registering definition: ${(exception as Error).message}`);\n }\n\n // Everything seems hunky-dory, register the subtree.\n Lookup.setSubtree(name, rootNodeDefinitions[0]);\n } else if (typeof value === \"object\" && !Array.isArray(value)) {\n // We will assume that any object passed in is a root node definition.\n\n try {\n // We should validate the subtree as we don't want invalid subtrees available via the lookup.\n const { succeeded, errorMessage } = validateJSONDefinition(value);\n\n // Did our validation fail without error?\n if (!succeeded) {\n throw new Error(errorMessage);\n }\n } catch (exception) {\n throw new Error(`error registering definition: ${(exception as Error).message}`);\n }\n\n // Everything seems hunky-dory, register the subtree.\n Lookup.setSubtree(name, value);\n } else {\n throw new Error(\"unexpected value, expected string mdsl definition, root node json definition or function\");\n }\n }\n\n /**\n * Unregisters the registered action/condition/guard/callback function or subtree with the given name.\n * @param name The name of the registered action/condition/guard/callback function or subtree to unregister.\n */\n static unregister(name: string): void {\n Lookup.remove(name);\n }\n\n /**\n * Unregister all registered action/condition/guard/callback functions and subtrees.\n */\n static unregisterAll(): void {\n Lookup.empty();\n }\n}\n"], - "mappings": ";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AACA,WAAO,eAAe,SAAS,cAAc,EAAE,OAAO,KAAK,CAAC;AAC5D,YAAQ,cAAc;AAItB,QAAI,cAA6B,WAAY;AAMzC,eAASA,aAAY,aAAa,SAAS;AACvC,YAAI,YAAY,QAAQ;AAAE,oBAAU;AAAA,QAAG;AACvC,aAAK,eAAe;AACpB,aAAK,WAAW;AAAA,MACpB;AACA,aAAO,eAAeA,aAAY,WAAW,eAAe;AAAA,QAExD,KAAK,WAAY;AACb,iBAAO,KAAK;AAAA,QAChB;AAAA,QACA,YAAY;AAAA,QACZ,cAAc;AAAA,MAClB,CAAC;AACD,aAAO,eAAeA,aAAY,WAAW,WAAW;AAAA,QAEpD,KAAK,WAAY;AACb,iBAAO,KAAK;AAAA,QAChB;AAAA,QACA,KAAK,SAAU,OAAO;AAClB,eAAK,WAAW;AAAA,QACpB;AAAA,QACA,YAAY;AAAA,QACZ,cAAc;AAAA,MAClB,CAAC;AACD,aAAOA;AAAA,IACX,EAAE;AACF,YAAQ,cAAc;AAAA;AAAA;;;ACtCtB;AAAA;AAAA;AACA,WAAO,eAAe,SAAS,cAAc,EAAE,OAAO,KAAK,CAAC;AAC5D,YAAQ,kBAAkB,QAAQ,oBAAoB;AAMtD,aAASC,mBAAkB,OAAO;AAC9B,aAAO,UAAU,QAAQ,UAAU;AAAA,IACvC;AACA,YAAQ,oBAAoBA;AAM5B,aAAS,gBAAgB,OAAO;AAC5B,aAAO,OAAO,UAAU,YAAY,SAAS,KAAK,KAAK,MAAM,KAAK,MAAM;AAAA,IAC5E;AACA,YAAQ,kBAAkB;AAAA;AAAA;;;ACpB1B;AAAA;AAAA;AACA,WAAO,eAAe,SAAS,cAAc,EAAE,OAAO,KAAK,CAAC;AAC5D,YAAQ,QAAQ;AAChB,QAAI,gBAAgB;AACpB,QAAI,cAAc;AAIlB,QAAIC,SAAuB,WAAY;AAKnC,eAASA,OAAM,cAAc;AAEzB,aAAK,gBAAgB,CAAC;AACtB,aAAK,gBAAgB;AAAA,MACzB;AAOA,MAAAA,OAAM,UAAU,MAAM,SAAU,aAAa,SAAS;AAClD,YAAI,YAAY,QAAQ;AAAE,oBAAU;AAAA,QAAG;AAEvC,YAAI,EAAE,GAAG,YAAY,iBAAiB,OAAO,GAAG;AAC5C,gBAAM,IAAI,MAAM,wCAAwC;AAAA,QAC5D;AAEA,YAAI,sBAAsB,KAAK,cAAc,KAAK,SAAU,MAAM;AAAE,iBAAO,KAAK,gBAAgB;AAAA,QAAa,CAAC;AAC9G,YAAI,qBAAqB;AAErB,8BAAoB,WAAW;AAAA,QACnC,OACK;AAED,eAAK,cAAc,KAAK,IAAI,cAAc,YAAY,aAAa,OAAO,CAAC;AAAA,QAC/E;AACA,eAAO;AAAA,MACX;AAOA,MAAAA,OAAM,UAAU,SAAS,SAAU,aAAa,SAAS;AAErD,YAAI,sBAAsB,KAAK,cAAc,KAAK,SAAU,MAAM;AAAE,iBAAO,KAAK,gBAAgB;AAAA,QAAa,CAAC;AAE9G,YAAI,CAAC,qBAAqB;AACtB,iBAAO;AAAA,QACX;AAEA,YAAI,YAAY,QAAW;AAEvB,cAAI,EAAE,GAAG,YAAY,iBAAiB,OAAO,GAAG;AAC5C,kBAAM,IAAI,MAAM,wCAAwC;AAAA,UAC5D;AACA,8BAAoB,WAAW;AAE/B,cAAI,oBAAoB,UAAU,GAAG;AACjC,iBAAK,gBAAgB,KAAK,cAAc,OAAO,SAAU,MAAM;AAAE,qBAAO,SAAS;AAAA,YAAqB,CAAC;AAAA,UAC3G;AAAA,QACJ,OACK;AAED,eAAK,gBAAgB,KAAK,cAAc,OAAO,SAAU,MAAM;AAAE,mBAAO,SAAS;AAAA,UAAqB,CAAC;AAAA,QAC3G;AACA,eAAO;AAAA,MACX;AAMA,MAAAA,OAAM,UAAU,OAAO,SAAU,SAAS;AACtC,YAAI,YAAY,QAAQ;AAAE,oBAAU,CAAC;AAAA,QAAG;AAExC,YAAI,KAAK,cAAc,WAAW,GAAG;AACjC,iBAAO;AAAA,QACX;AACA,YAAI,cAAc,GAAG,YAAY,mBAAmB,QAAQ,UAAU,IAAI,OAAO,QAAQ;AACzF,YAAI,WAAW,CAAC;AAChB,aAAK,cAAc,QAAQ,SAAU,IAAI;AACrC,cAAI,cAAc,GAAG,aAAa,UAAU,GAAG;AAC/C,mBAAS,cAAc,GAAG,cAAc,SAAS,eAAe;AAC5D,qBAAS,KAAK,WAAW;AAAA,UAC7B;AAAA,QACJ,CAAC;AACD,YAAI;AAGJ,YAAI,KAAK,eAAe;AAEpB,mBAAS,KAAK,cAAc;AAE5B,cAAI,OAAO,WAAW,YAAY,SAAS,KAAK,UAAU,GAAG;AACzD,kBAAM,IAAI,MAAM,oFAAoF;AAAA,UACxG;AAAA,QACJ,OACK;AAED,mBAAS,KAAK,OAAO;AAAA,QACzB;AAEA,YAAI,SAAS,SAAS,KAAK,MAAM,SAAS,SAAS,MAAM;AAEzD,YAAI,CAAC,YAAY;AACb,eAAK,OAAO,QAAQ,CAAC;AAAA,QACzB;AAEA,eAAO;AAAA,MACX;AAOA,MAAAA,OAAM,UAAU,eAAe,SAAU,SAAS,SAAS;AACvD,YAAI,YAAY,QAAQ;AAAE,oBAAU,CAAC;AAAA,QAAG;AACxC,YAAI,iBAAiB,GAAG,YAAY,mBAAmB,QAAQ,MAAM,IAAI,QAAQ,QAAQ;AAEzF,YAAI,YAAY,GAAG;AACf,iBAAO,CAAC;AAAA,QACZ;AAEA,YAAI,EAAE,GAAG,YAAY,iBAAiB,OAAO,GAAG;AAC5C,gBAAM,IAAI,MAAM,wCAAwC;AAAA,QAC5D;AACA,YAAI,SAAS,CAAC;AAGd,eAAO,OAAO,SAAS,WAAW,KAAK,cAAc,SAAS,GAAG;AAC7D,iBAAO,KAAK,KAAK,KAAK,OAAO,CAAC;AAAA,QAClC;AAEA,YAAI,eAAe;AAEf,cAAI,SAAS,CAAC;AAEd,mBAAS,KAAK,GAAG,WAAW,QAAQ,KAAK,SAAS,QAAQ,MAAM;AAC5D,gBAAI,cAAc,SAAS;AAC3B,gBAAI,OAAO,QAAQ,WAAW,MAAM,IAAI;AACpC,qBAAO,KAAK,WAAW;AAAA,YAC3B;AAAA,UACJ;AACA,mBAAS;AAAA,QACb;AACA,eAAO;AAAA,MACX;AACA,aAAOA;AAAA,IACX,EAAE;AACF,YAAQ,QAAQA;AAAA;AAAA;;;AC5JhB;AAAA;AAAA;AACA,WAAO,eAAe,SAAS,cAAc,EAAE,OAAO,KAAK,CAAC;AAC5D,YAAQ,cAAc;AACtB,QAAI,UAAU;AAMd,aAASC,aAAY,uBAAuB;AAExC,UAAI,CAAC,uBAAuB;AACxB,eAAO,IAAI,QAAQ,MAAM;AAAA,MAC7B;AAEA,UAAI,MAAM,QAAQ,qBAAqB,GAAG;AAEtC,YAAI,eAAe;AACnB,YAAI,UAAU,IAAI,QAAQ,MAAM;AAEhC,qBAAa,QAAQ,SAAU,IAAI;AAC/B,cAAI,cAAc,GAAG,IAAI,SAAS,GAAG;AACrC,iBAAO,QAAQ,IAAI,aAAa,MAAM;AAAA,QAC1C,CAAC;AAED,eAAO;AAAA,MACX,OACK;AAED,YAAI,SAAS,sBAAsB,QAAQ,eAAe,sBAAsB;AAEhF,YAAI,UAAU,IAAI,QAAQ,MAAM,MAAM;AAEtC,YAAI,cAAc;AACd,uBAAa,QAAQ,SAAU,IAAI;AAC/B,gBAAI,cAAc,GAAG,IAAI,SAAS,GAAG;AACrC,mBAAO,QAAQ,IAAI,aAAa,MAAM;AAAA,UAC1C,CAAC;AAAA,QACL;AAEA,eAAO;AAAA,MACX;AAAA,IACJ;AACA,YAAQ,cAAcA;AAAA;AAAA;;;AC3CtB;AAAA;AAAA;AACA,WAAO,eAAe,SAAS,cAAc,EAAE,OAAO,KAAK,CAAC;AAC5D,QAAI,gBAAgB;AACpB,YAAQ,UAAU,cAAc;AAAA;AAAA;;;ACHhC;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;;ACGO,IAAK,QAAL,kBAAKC,WAAL;AACH,EAAAA,OAAA,WAAQ;AACR,EAAAA,OAAA,aAAU;AACV,EAAAA,OAAA,eAAY;AACZ,EAAAA,OAAA,YAAS;AAJD,SAAAA;AAAA,GAAA;;;ACWL,SAAS,WAAW,MAAkD;AACzE,SAAO,KAAK,SAAS;AACzB;AAOO,SAAS,aAAa,MAAoD;AAC7E,SAAO,KAAK,SAAS;AACzB;AAOO,SAAS,WAAW,MAA8C;AACrE,SAAO,CAAC,UAAU,UAAU,aAAa,MAAM,EAAE,SAAS,KAAK,IAAI;AACvE;AAOO,SAAS,gBAAgB,MAAuD;AACnF,SAAO,CAAC,QAAQ,UAAU,SAAS,QAAQ,WAAW,MAAM,EAAE,SAAS,KAAK,IAAI;AACpF;AAOO,SAAS,gBAAgB,MAAuD;AACnF,SAAO,CAAC,YAAY,YAAY,SAAS,UAAU,EAAE,SAAS,KAAK,IAAI;AAC3E;AAOO,SAAS,kBAAkB,gBAAwD;AACtF,QAAM,QAA6B,CAAC;AAEpC,QAAM,cAAc,CAAC,0BAA6C;AAC9D,UAAM,KAAK,qBAAqB;AAEhC,QAAI,gBAAgB,qBAAqB,GAAG;AACxC,4BAAsB,SAAS,QAAQ,WAAW;AAAA,IACtD,WAAW,gBAAgB,qBAAqB,GAAG;AAC/C,kBAAY,sBAAsB,KAAK;AAAA,IAC3C;AAAA,EACJ;AAEA,cAAY,cAAc;AAE1B,SAAO;AACX;AAOO,SAAS,UAAU,OAAyB;AAC/C,SAAO,OAAO,UAAU,YAAY,KAAK,MAAM,KAAK,MAAM;AAC9D;AAOO,SAAS,kBAAkB,OAAyB;AACvD,SAAO,OAAO,UAAU,eAAe,UAAU;AACrD;;;AClFO,SAAS,YAAY,QAAkB,UAAsC;AAEhF,QAAM,SAAS,OAAO,MAAM;AAG5B,MAAI,WAAW,QAAW;AACtB,UAAM,IAAI,MAAM,8BAA8B;AAAA,EAClD;AAGA,MAAI,YAAY,QAAW;AAEvB,UAAM,iBAAiB,OAAO,aAAa,WAAW,CAAC,QAAQ,IAAI;AAGnE,QAAI,0BAA0B,eAAe,KAAK,CAAC,SAAS,OAAO,YAAY,MAAM,KAAK,YAAY,CAAC;AAGvG,QAAI,CAAC,yBAAyB;AAC1B,YAAM,oBAAoB,eAAe,IAAI,CAAC,SAAS,MAAM,OAAO,GAAG,EAAE,KAAK,MAAM;AACpF,YAAM,IAAI,MAAM,sCAAsC,oBAAoB,eAAe,SAAS,GAAG;AAAA,IACzG;AAAA,EACJ;AAGA,SAAO;AACX;AAOO,SAAS,yBAAyB,YAGvC;AAEE,QAAM,eAA0C,CAAC;AAGjD,QAAM,sBAAsB,WAAW,QAAQ,sBAAsB,CAAC,UAAU;AAC5E,QAAI,gBAAgB,MAAM,UAAU,GAAG,MAAM,SAAS,CAAC;AACvD,QAAI,cAAc,OAAO,KAAK,YAAY,EAAE,KAAK,CAAC,QAAQ,aAAa,SAAS,aAAa;AAG7F,QAAI,CAAC,aAAa;AACd,oBAAc,KAAK,OAAO,KAAK,YAAY,EAAE;AAC7C,mBAAa,eAAe;AAAA,IAChC;AAEA,WAAO;AAAA,EACX,CAAC;AAED,SAAO,EAAE,cAAc,oBAAoB;AAC/C;AAOO,SAAS,0BAA0B,YAA8B;AAEpE,eAAa,WAAW,QAAQ,OAAO,KAAK;AAC5C,eAAa,WAAW,QAAQ,OAAO,KAAK;AAC5C,eAAa,WAAW,QAAQ,OAAO,KAAK;AAC5C,eAAa,WAAW,QAAQ,OAAO,KAAK;AAC5C,eAAa,WAAW,QAAQ,OAAO,KAAK;AAC5C,eAAa,WAAW,QAAQ,OAAO,KAAK;AAC5C,eAAa,WAAW,QAAQ,OAAO,KAAK;AAG5C,SAAO,WAAW,QAAQ,QAAQ,GAAG,EAAE,KAAK,EAAE,MAAM,GAAG;AAC3D;;;AChCO,SAAS,oBACZ,QACA,4BACa;AACb,QAAM,eAA8B,CAAC;AAGrC,MAAI,CAAC,CAAC,KAAK,GAAG,EAAE,SAAS,OAAO,EAAE,GAAG;AACjC,WAAO;AAAA,EACX;AAIA,QAAM,eAAe,YAAY,QAAQ,CAAC,KAAK,GAAG,CAAC,MAAM,MAAM,MAAM;AAErE,QAAM,qBAA+B,CAAC;AAGtC,SAAO,OAAO,UAAU,OAAO,OAAO,cAAc;AAEhD,uBAAmB,KAAK,OAAO,MAAM,CAAE;AAAA,EAC3C;AAGA,qBAAmB,QAAQ,CAAC,OAAO,UAAU;AAEzC,UAAM,wBAAwB,EAAE,QAAQ;AAGxC,QAAI,uBAAuB;AAEvB,YAAM,qBAAqB,sBAAsB,OAAO,0BAA0B;AAGlF,mBAAa,KAAK,kBAAkB;AAAA,IACxC,OAAO;AAEH,UAAI,UAAU,KAAK;AACf,cAAM,IAAI,MAAM,uDAAuD,QAAQ;AAAA,MACnF;AAAA,IACJ;AAAA,EACJ,CAAC;AAGD,cAAY,QAAQ,YAAY;AAGhC,SAAO;AACX;AAQA,SAAS,sBAAsB,OAAe,4BAAoE;AAE9G,MAAI,UAAU,QAAQ;AAClB,WAAO;AAAA,MACH,OAAO;AAAA,MACP,MAAM;AAAA,IACV;AAAA,EACJ;AAGA,MAAI,UAAU,UAAU,UAAU,SAAS;AACvC,WAAO;AAAA,MACH,OAAO,UAAU;AAAA,MACjB,MAAM;AAAA,IACV;AAAA,EACJ;AAKA,MAAI,CAAC,MAAM,KAAY,GAAG;AACtB,WAAO;AAAA,MACH,OAAO,WAAW,KAAK;AAAA,MACvB,WAAW,WAAW,KAAK,MAAM,SAAS,OAAO,EAAE;AAAA,MACnD,MAAM;AAAA,IACV;AAAA,EACJ;AAGA,MAAI,MAAM,MAAM,YAAY,GAAG;AAC3B,WAAO;AAAA,MACH,OAAO,2BAA2B,OAAO,QAAQ,OAAO,GAAG;AAAA,MAC3D,MAAM;AAAA,IACV;AAAA,EACJ;AAGA,SAAO;AAAA,IACH,OAAO;AAAA,IACP,MAAM;AAAA,EACV;AACJ;;;ACjIO,SAAS,qBACZ,QACA,4BACc;AACd,QAAM,qBAA+C,CAAC,SAAS,SAAS,SAAS,QAAQ,MAAM;AAG/F,QAAM,aAA6B,CAAC;AAGpC,MAAI,oBAAoB,OAAO,IAAI,YAAY;AAG/C,SAAO,mBAAmB,SAAS,iBAAiB,GAAG;AAEnD,QAAI,WAAW,oBAAoB;AAC/B,YAAM,IAAI,MAAM,wBAAwB,OAAO,GAAG,YAAY,mBAAmB;AAAA,IACrF;AAGA,WAAO,MAAM;AAGb,UAAM,CAAC,4BAA4B,kBAAkB,IAAI;AAAA,MACrD;AAAA,MACA;AAAA,IACJ;AAGA,QAAI,yBAAyB,SAAS,cAAc;AAChD,YAAM,IAAI,MAAM,uFAAuF;AAAA,IAC3G;AAGA,uBACK,OAAO,CAAC,QAAQ,IAAI,SAAS,YAAY,EACzC,QAAQ,CAAC,QAAQ;AACd,YAAM,IAAI;AAAA,QACN,qCAAqC,IAAI;AAAA,MAC7C;AAAA,IACJ,CAAC;AAGL,eAAW,qBAAqB;AAAA,MAC5B,MAAM,wBAAwB;AAAA,MAC9B,MAAM,mBAAmB,IAAI,CAAC,EAAE,MAAM,MAAM,KAAK;AAAA,IACrD;AAGA,wBAAoB,OAAO,IAAI,YAAY;AAAA,EAC/C;AAEA,SAAO;AACX;;;ACnCO,SAAS,kBAAkB,YAA0C;AAExE,QAAM,EAAE,cAAc,oBAAoB,IAAI,yBAAyB,UAAU;AAGjF,QAAM,SAAS,0BAA0B,mBAAmB;AAE5D,SAAO,8BAA8B,QAAQ,YAAY;AAC7D;AAQA,SAAS,8BACL,QACA,2BACoB;AAEpB,MAAI,OAAO,SAAS,GAAG;AACnB,UAAM,IAAI,MAAM,qBAAqB;AAAA,EACzC;AAGA,MAAI,OAAO,OAAO,CAAC,UAAU,UAAU,GAAG,EAAE,WAAW,OAAO,OAAO,CAAC,UAAU,UAAU,GAAG,EAAE,QAAQ;AACnG,UAAM,IAAI,MAAM,0BAA0B;AAAA,EAC9C;AASA,QAAM,aAAoF,CAAC;AAG3F,QAAM,YAA2C,CAAC;AAGlD,QAAM,WAAW,CAAC,SAA4B;AAE1C,QAAI,WAAW,IAAI,GAAG;AAGlB,UAAI,WAAW,WAAW,SAAS,IAAI,QAAQ;AAC3C,cAAM,IAAI,MAAM,iDAAiD;AAAA,MACrE;AAGA,gBAAU,KAAK,IAAI;AAGnB,iBAAW,KAAK,CAAC,IAAI,CAAC;AAEtB;AAAA,IACJ;AAIA,QAAI,CAAC,WAAW,UAAU,CAAC,WAAW,WAAW,SAAS,GAAG,QAAQ;AACjE,YAAM,IAAI,MAAM,0CAA0C;AAAA,IAC9D;AAGA,UAAM,eAAe,WAAW,WAAW,SAAS;AAIpD,UAAM,sBAAsB,aAAa,aAAa,SAAS;AAI/D,QAAI,gBAAgB,mBAAmB,GAAG;AACtC,0BAAoB,WAAW,oBAAoB,YAAY,CAAC;AAChE,0BAAoB,SAAS,KAAK,IAAI;AAAA,IAC1C,WAAW,gBAAgB,mBAAmB,GAAG;AAE7C,UAAI,oBAAoB,OAAO;AAC3B,cAAM,IAAI,MAAM,qDAAqD;AAAA,MACzE;AAEA,0BAAoB,QAAQ;AAAA,IAChC;AAIA,QAAI,CAAC,WAAW,IAAI,GAAG;AACnB,mBAAa,KAAK,IAAI;AAAA,IAC1B;AAAA,EACJ;AAGA,QAAM,UAAU,MAAgC;AAC5C,QAAI,aAAuC;AAG3C,UAAM,eAAe,WAAW,WAAW,SAAS;AAGpD,QAAI,aAAa,QAAQ;AACrB,mBAAa,aAAa,IAAI;AAAA,IAClC;AAGA,QAAI,CAAC,aAAa,QAAQ;AACtB,iBAAW,IAAI;AAAA,IACnB;AAEA,WAAO;AAAA,EACX;AAGA,SAAO,OAAO,QAAQ;AAElB,UAAM,QAAQ,OAAO,MAAM;AAG3B,YAAQ,MAAM,YAAY,GAAG;AAAA,MACzB,KAAK,QAAQ;AACT,iBAAS,eAAe,QAAQ,yBAAyB,CAAC;AAC1D;AAAA,MACJ;AAAA,MAEA,KAAK,WAAW;AACZ,iBAAS,kBAAkB,QAAQ,yBAAyB,CAAC;AAC7D;AAAA,MACJ;AAAA,MAEA,KAAK,QAAQ;AACT,iBAAS,eAAe,QAAQ,yBAAyB,CAAC;AAC1D;AAAA,MACJ;AAAA,MAEA,KAAK,QAAQ;AACT,iBAAS,eAAe,QAAQ,yBAAyB,CAAC;AAC1D;AAAA,MACJ;AAAA,MAEA,KAAK,UAAU;AACX,iBAAS,iBAAiB,QAAQ,yBAAyB,CAAC;AAC5D;AAAA,MACJ;AAAA,MAEA,KAAK,SAAS;AACV,iBAAS,gBAAgB,QAAQ,yBAAyB,CAAC;AAC3D;AAAA,MACJ;AAAA,MAEA,KAAK,YAAY;AACb,iBAAS,mBAAmB,QAAQ,yBAAyB,CAAC;AAC9D;AAAA,MACJ;AAAA,MAEA,KAAK,YAAY;AACb,iBAAS,mBAAmB,QAAQ,yBAAyB,CAAC;AAC9D;AAAA,MACJ;AAAA,MAEA,KAAK,YAAY;AACb,iBAAS,mBAAmB,QAAQ,yBAAyB,CAAC;AAC9D;AAAA,MACJ;AAAA,MAEA,KAAK,SAAS;AACV,iBAAS,gBAAgB,QAAQ,yBAAyB,CAAC;AAC3D;AAAA,MACJ;AAAA,MAEA,KAAK,UAAU;AACX,iBAAS,iBAAiB,QAAQ,yBAAyB,CAAC;AAC5D;AAAA,MACJ;AAAA,MAEA,KAAK,aAAa;AACd,iBAAS,oBAAoB,QAAQ,yBAAyB,CAAC;AAC/D;AAAA,MACJ;AAAA,MAEA,KAAK,QAAQ;AACT,iBAAS,eAAe,QAAQ,yBAAyB,CAAC;AAC1D;AAAA,MACJ;AAAA,MAEA,KAAK,UAAU;AACX,iBAAS,iBAAiB,QAAQ,yBAAyB,CAAC;AAC5D;AAAA,MACJ;AAAA,MAEA,KAAK,KAAK;AAEN,cAAM,aAAa,QAAQ;AAG3B,YAAI,YAAY;AACZ,6BAAmB,UAAU;AAAA,QACjC;AAEA;AAAA,MACJ;AAAA,MAEA,SAAS;AACL,cAAM,IAAI,MAAM,qBAAqB,OAAO;AAAA,MAChD;AAAA,IACJ;AAAA,EACJ;AAEA,SAAO;AACX;AAQA,SAAS,eAAe,QAAkB,2BAA0E;AAEhH,MAAI,OAAO;AAAA,IACP,MAAM;AAAA,EACV;AAGA,QAAM,gBAAgB,oBAAoB,QAAQ,yBAAyB;AAG3E,MAAI,cAAc,QAAQ;AAEtB,QAAI,cAAc,WAAW,KAAK,cAAc,GAAG,SAAS,cAAc;AAEtE,WAAK,KAAK,cAAc,GAAG;AAAA,IAC/B,OAAO;AACH,YAAM,IAAI,MAAM,oCAAoC;AAAA,IACxD;AAAA,EACJ;AAGA,SAAO,EAAE,GAAG,MAAM,GAAG,qBAAqB,QAAQ,yBAAyB,EAAE;AAG7E,cAAY,QAAQ,GAAG;AAGvB,SAAO;AACX;AAQA,SAAS,kBACL,QACA,2BACqB;AACrB,QAAM,OAAO;AAAA,IACT,MAAM;AAAA,IACN,GAAG,qBAAqB,QAAQ,yBAAyB;AAAA,EAC7D;AAGA,cAAY,QAAQ,GAAG;AAGvB,SAAO;AACX;AAQA,SAAS,eAAe,QAAkB,2BAA0E;AAChH,QAAM,OAAO;AAAA,IACT,MAAM;AAAA,IACN,GAAG,qBAAqB,QAAQ,yBAAyB;AAAA,EAC7D;AAGA,cAAY,QAAQ,GAAG;AAGvB,SAAO;AACX;AAQA,SAAS,eAAe,QAAkB,2BAA0E;AAChH,QAAM,OAAO;AAAA,IACT,MAAM;AAAA,IACN,GAAG,qBAAqB,QAAQ,yBAAyB;AAAA,EAC7D;AAGA,cAAY,QAAQ,GAAG;AAGvB,SAAO;AACX;AAQA,SAAS,iBACL,QACA,2BACoB;AACpB,MAAI,OAAO,EAAE,MAAM,SAAS;AAG5B,QAAM,gBAAgB,oBAAoB,QAAQ,yBAAyB;AAM3E,MAAI,cAAc,QAAQ;AAEtB,kBACK,OAAO,CAAC,QAAQ,IAAI,SAAS,YAAY,CAAC,IAAI,SAAS,EACvD,QAAQ,MAAM;AACX,YAAM,IAAI,MAAM,qDAAqD;AAAA,IACzE,CAAC;AAGL,QAAI,cAAc,WAAW,GAAG;AAE5B,WAAK,aAAa,cAAc,GAAG;AAGnC,UAAI,KAAK,aAAa,GAAG;AACrB,cAAM,IAAI,MAAM,oEAAoE;AAAA,MACxF;AAAA,IACJ,WAAW,cAAc,WAAW,GAAG;AAEnC,WAAK,aAAa,CAAC,cAAc,GAAG,OAAiB,cAAc,GAAG,KAAe;AAGrF,UAAI,KAAK,WAAW,KAAK,KAAK,KAAK,WAAW,KAAK,GAAG;AAClD,cAAM,IAAI,MAAM,mFAAmF;AAAA,MACvG;AAGA,UAAI,KAAK,WAAW,KAAK,KAAK,WAAW,IAAI;AACzC,cAAM,IAAI;AAAA,UACN;AAAA,QACJ;AAAA,MACJ;AAAA,IACJ,OAAO;AAEH,YAAM,IAAI,MAAM,iEAAiE;AAAA,IACrF;AAAA,EACJ;AAGA,SAAO,EAAE,GAAG,MAAM,GAAG,qBAAqB,QAAQ,yBAAyB,EAAE;AAG7E,cAAY,QAAQ,GAAG;AAGvB,SAAO;AACX;AAQA,SAAS,gBAAgB,QAAkB,2BAA2E;AAClH,MAAI,OAAO,EAAE,MAAM,QAAQ;AAG3B,QAAM,gBAAgB,oBAAoB,QAAQ,yBAAyB;AAM3E,MAAI,cAAc,QAAQ;AAEtB,kBACK,OAAO,CAAC,QAAQ,IAAI,SAAS,YAAY,CAAC,IAAI,SAAS,EACvD,QAAQ,MAAM;AACX,YAAM,IAAI,MAAM,kDAAkD;AAAA,IACtE,CAAC;AAGL,QAAI,cAAc,WAAW,GAAG;AAE5B,WAAK,WAAW,cAAc,GAAG;AAGjC,UAAI,KAAK,WAAW,GAAG;AACnB,cAAM,IAAI,MAAM,iEAAiE;AAAA,MACrF;AAAA,IACJ,WAAW,cAAc,WAAW,GAAG;AAEnC,WAAK,WAAW,CAAC,cAAc,GAAG,OAAiB,cAAc,GAAG,KAAe;AAGnF,UAAI,KAAK,SAAS,KAAK,KAAK,KAAK,SAAS,KAAK,GAAG;AAC9C,cAAM,IAAI,MAAM,gFAAgF;AAAA,MACpG;AAGA,UAAI,KAAK,SAAS,KAAK,KAAK,SAAS,IAAI;AACrC,cAAM,IAAI;AAAA,UACN;AAAA,QACJ;AAAA,MACJ;AAAA,IACJ,OAAO;AAEH,YAAM,IAAI,MAAM,8DAA8D;AAAA,IAClF;AAAA,EACJ;AAGA,SAAO,EAAE,GAAG,MAAM,GAAG,qBAAqB,QAAQ,yBAAyB,EAAE;AAG7E,cAAY,QAAQ,GAAG;AAGvB,SAAO;AACX;AAQA,SAAS,mBACL,QACA,2BACsB;AACtB,QAAM,OAAO;AAAA,IACT,MAAM;AAAA,IACN,GAAG,qBAAqB,QAAQ,yBAAyB;AAAA,EAC7D;AAGA,cAAY,QAAQ,GAAG;AAGvB,SAAO;AACX;AAQA,SAAS,mBACL,QACA,2BACsB;AACtB,QAAM,OAAO;AAAA,IACT,MAAM;AAAA,IACN,GAAG,qBAAqB,QAAQ,yBAAyB;AAAA,EAC7D;AAGA,cAAY,QAAQ,GAAG;AAGvB,SAAO;AACX;AAQA,SAAS,mBACL,QACA,2BACsB;AACtB,QAAM,OAAO;AAAA,IACT,MAAM;AAAA,IACN,GAAG,qBAAqB,QAAQ,yBAAyB;AAAA,EAC7D;AAGA,cAAY,QAAQ,GAAG;AAGvB,SAAO;AACX;AAQA,SAAS,gBAAgB,QAAkB,2BAA2E;AAElH,QAAM,gBAAgB,oBAAoB,QAAQ,yBAAyB;AAG3E,gBACK,OAAO,CAAC,QAAQ,IAAI,SAAS,YAAY,CAAC,IAAI,aAAa,IAAI,QAAQ,CAAC,EACxE,QAAQ,MAAM;AACX,UAAM,IAAI,MAAM,6DAA6D;AAAA,EACjF,CAAC;AAEL,QAAM,OAAO;AAAA,IACT,MAAM;AAAA,IACN,GAAG,qBAAqB,QAAQ,yBAAyB;AAAA,EAC7D;AAGA,MAAI,cAAc,QAAQ;AACtB,SAAK,UAAU,cAAc,IAAI,CAAC,EAAE,MAAM,MAAM,KAAK;AAAA,EACzD;AAGA,cAAY,QAAQ,GAAG;AAGvB,SAAO;AACX;AAQA,SAAS,iBACL,QACA,2BACoB;AAGpB,QAAM,CAAC,yBAAyB,iBAAiB,IAAI,oBAAoB,QAAQ,yBAAyB;AAG1G,MAAI,sBAAsB,SAAS,cAAc;AAC7C,UAAM,IAAI,MAAM,0CAA0C;AAAA,EAC9D;AAGA,oBACK,OAAO,CAAC,QAAQ,IAAI,SAAS,YAAY,EACzC,QAAQ,CAAC,QAAQ;AACd,UAAM,IAAI;AAAA,MACN,uCAAuC,IAAI;AAAA,IAC/C;AAAA,EACJ,CAAC;AAGL,SAAO;AAAA,IACH,MAAM;AAAA,IACN,MAAM,qBAAqB;AAAA,IAC3B,MAAM,kBAAkB,IAAI,CAAC,EAAE,MAAM,MAAM,KAAK;AAAA,IAChD,GAAG,qBAAqB,QAAQ,yBAAyB;AAAA,EAC7D;AACJ;AAQA,SAAS,oBACL,QACA,2BACuB;AAGvB,QAAM,CAAC,4BAA4B,iBAAiB,IAAI,oBAAoB,QAAQ,yBAAyB;AAG7G,MAAI,yBAAyB,SAAS,cAAc;AAChD,UAAM,IAAI,MAAM,6CAA6C;AAAA,EACjE;AAGA,oBACK,OAAO,CAAC,QAAQ,IAAI,SAAS,YAAY,EACzC,QAAQ,CAAC,QAAQ;AACd,UAAM,IAAI;AAAA,MACN,0CAA0C,IAAI;AAAA,IAClD;AAAA,EACJ,CAAC;AAGL,SAAO;AAAA,IACH,MAAM;AAAA,IACN,MAAM,wBAAwB;AAAA,IAC9B,MAAM,kBAAkB,IAAI,CAAC,EAAE,MAAM,MAAM,KAAK;AAAA,IAChD,GAAG,qBAAqB,QAAQ,yBAAyB;AAAA,EAC7D;AACJ;AAQA,SAAS,eAAe,QAAkB,2BAA0E;AAChH,MAAI,OAAO,EAAE,MAAM,OAAO;AAG1B,QAAM,gBAAgB,oBAAoB,QAAQ,yBAAyB;AAM3E,MAAI,cAAc,QAAQ;AAEtB,kBACK,OAAO,CAAC,QAAQ,IAAI,SAAS,YAAY,CAAC,IAAI,SAAS,EACvD,QAAQ,MAAM;AACX,YAAM,IAAI,MAAM,4CAA4C;AAAA,IAChE,CAAC;AAML,QAAI,cAAc,WAAW,GAAG;AAE5B,WAAK,WAAW,cAAc,GAAG;AAGjC,UAAI,KAAK,WAAW,GAAG;AACnB,cAAM,IAAI,MAAM,2CAA2C;AAAA,MAC/D;AAAA,IACJ,WAAW,cAAc,WAAW,GAAG;AAEnC,WAAK,WAAW,CAAC,cAAc,GAAG,OAAiB,cAAc,GAAG,KAAe;AAGnF,UAAI,KAAK,SAAS,KAAK,KAAK,KAAK,SAAS,KAAK,GAAG;AAC9C,cAAM,IAAI,MAAM,+DAA+D;AAAA,MACnF;AAGA,UAAI,KAAK,SAAS,KAAK,KAAK,SAAS,IAAI;AACrC,cAAM,IAAI,MAAM,gFAAgF;AAAA,MACpG;AAAA,IACJ,WAAW,cAAc,SAAS,GAAG;AAEjC,YAAM,IAAI,MAAM,wDAAwD;AAAA,IAC5E;AAAA,EACJ;AAGA,SAAO,EAAE,GAAG,MAAM,GAAG,qBAAqB,QAAQ,yBAAyB,EAAE;AACjF;AAQA,SAAS,iBACL,QACA,2BACoB;AAEpB,QAAM,gBAAgB,oBAAoB,QAAQ,yBAAyB;AAG3E,MAAI,cAAc,WAAW,KAAK,cAAc,GAAG,SAAS,cAAc;AACtE,UAAM,IAAI,MAAM,sCAAsC;AAAA,EAC1D;AAGA,SAAO,EAAE,MAAM,UAAU,KAAK,cAAc,GAAG,MAAM;AACzD;AAMA,SAAS,mBAAmB,YAAqC;AAE7D,MAAI,gBAAgB,UAAU,KAAK,kBAAkB,WAAW,KAAK,GAAG;AACpE,UAAM,IAAI,MAAM,KAAK,WAAW,iDAAiD;AAAA,EACrF;AAGA,MAAI,gBAAgB,UAAU,KAAK,CAAC,WAAW,UAAU,QAAQ;AAC7D,UAAM,IAAI,MAAM,KAAK,WAAW,0DAA0D;AAAA,EAC9F;AAGA,MAAI,WAAW,SAAS,SAAS;AAE7B,QAAI,OAAO,WAAW,YAAY,aAAa;AAE3C,UAAI,WAAW,QAAQ,WAAW,WAAW,SAAS,QAAQ;AAC1D,cAAM,IAAI;AAAA,UACN;AAAA,QACJ;AAAA,MACJ;AAAA,IACJ;AAAA,EACJ;AACJ;;;AC9tBO,SAAS,mBAAmB,YAA6C;AAE5E,MAAI,eAAe,QAAQ,OAAO,eAAe,aAAa;AAC1D,WAAO,8BAA8B,iCAAiC;AAAA,EAC1E;AAMA,MAAI,OAAO,eAAe,UAAU;AAEhC,WAAO,uBAAuB,UAAU;AAAA,EAC5C,WAAW,OAAO,eAAe,UAAU;AAEvC,WAAO,uBAAuB,UAAU;AAAA,EAC5C,OAAO;AACH,WAAO,8BAA8B,kCAAkC,OAAO,aAAa;AAAA,EAC/F;AACJ;AAOA,SAAS,uBAAuB,YAAgD;AAC5E,MAAI;AAGJ,MAAI;AAEA,0BAAsB,kBAAkB,UAAU;AAAA,EACtD,SAAS,WAAP;AAEE,WAAO,8BAA+B,UAAoB,OAAO;AAAA,EACrE;AAGA,QAAM,0BAA0B,oBAAoB,OAAO,CAAC,EAAE,GAAG,MAAM,OAAO,OAAO,WAAW;AAChG,QAAM,yBAAyB,oBAAoB,OAAO,CAAC,EAAE,GAAG,MAAM,OAAO,OAAO,YAAY,GAAG,SAAS,CAAC;AAG7G,MAAI,wBAAwB,WAAW,GAAG;AACtC,WAAO;AAAA,MACH;AAAA,IACJ;AAAA,EACJ;AAGA,QAAM,yBAAmC,CAAC;AAC1C,aAAW,EAAE,GAAG,KAAK,wBAAwB;AAEzC,QAAI,uBAAuB,SAAS,EAAG,GAAG;AACtC,aAAO,8BAA8B,kDAAkD,KAAK;AAAA,IAChG;AAEA,2BAAuB,KAAK,EAAG;AAAA,EACnC;AAEA,MAAI;AAEA,+BAA2B,qBAAqB,KAAK;AAAA,EACzD,SAAS,WAAP;AACE,WAAO,8BAA+B,UAAoB,OAAO;AAAA,EACrE;AAGA,SAAO;AAAA,IACH,WAAW;AAAA,IACX,MAAM;AAAA,EACV;AACJ;AAOO,SAAS,uBACZ,YAC0B;AAE1B,QAAM,sBAAsB,MAAM,QAAQ,UAAU,IAAI,aAAa,CAAC,UAAU;AAGhF,MAAI;AACA,wBAAoB,QAAQ,CAAC,uBAAuB,aAAa,oBAAoB,CAAC,CAAC;AAAA,EAC3F,SAAS,OAAP;AAEE,QAAI,iBAAiB,OAAO;AACxB,aAAO,8BAA8B,MAAM,OAAO;AAAA,IACtD;AAGA,WAAO,8BAA8B,qBAAqB,OAAO;AAAA,EACrE;AAGA,QAAM,0BAA0B,oBAAoB,OAAO,CAAC,EAAE,GAAG,MAAM,OAAO,OAAO,WAAW;AAChG,QAAM,yBAAyB,oBAAoB,OAAO,CAAC,EAAE,GAAG,MAAM,OAAO,OAAO,YAAY,GAAG,SAAS,CAAC;AAG7G,MAAI,wBAAwB,WAAW,GAAG;AACtC,WAAO;AAAA,MACH;AAAA,IACJ;AAAA,EACJ;AAGA,QAAM,yBAAmC,CAAC;AAC1C,aAAW,EAAE,GAAG,KAAK,wBAAwB;AAEzC,QAAI,uBAAuB,SAAS,EAAG,GAAG;AACtC,aAAO;AAAA,QACH,oEAAoE;AAAA,MACxE;AAAA,IACJ;AAEA,2BAAuB,KAAK,EAAG;AAAA,EACnC;AAEA,MAAI;AAEA,+BAA2B,qBAAqB,KAAK;AAAA,EACzD,SAAS,WAAP;AACE,WAAO,8BAA+B,UAAoB,OAAO;AAAA,EACrE;AAGA,SAAO;AAAA,IACH,WAAW;AAAA,IACX,MAAM;AAAA,EACV;AACJ;AASO,SAAS,2BAA2B,qBAA2C,wBAAiC;AAInH,QAAM,mBAAiE,oBAAoB;AAAA,IACvF,CAAC,wBAAwB;AAAA,MACrB,IAAI,mBAAmB;AAAA,MACvB,MAAM,kBAAkB,kBAAkB,EACrC,OAAO,YAAY,EACnB,IAAI,CAAC,EAAE,IAAI,MAAM,GAAG;AAAA,IAC7B;AAAA,EACJ;AAGA,QAAM,aAAa,CAAC,SAAqD,OAA+B,CAAC,MAAM;AAE3G,QAAI,KAAK,SAAS,QAAQ,EAAE,GAAG;AAE3B,YAAM,UAAU,CAAC,GAAG,MAAM,QAAQ,EAAE;AAGpC,YAAM,mBAAmB,QAAQ,OAAO,CAAC,YAAY,CAAC,CAAC,OAAO,EAAE,KAAK,MAAM;AAG3E,YAAM,IAAI,MAAM,wDAAwD,kBAAkB;AAAA,IAC9F;AAEA,eAAW,OAAO,QAAQ,MAAM;AAE5B,YAAM,aAAa,iBAAiB,KAAK,CAAC,EAAE,GAAG,MAAM,OAAO,GAAG;AAG/D,UAAI,YAAY;AACZ,mBAAW,YAAY,CAAC,GAAG,MAAM,QAAQ,EAAE,CAAC;AAAA,MAChD,WAAW,wBAAwB;AAE/B,cAAM,IAAI;AAAA,UACN,QAAQ,KACF,YAAY,QAAQ,kDAAkD,oCACtE,2DAA2D;AAAA,QACrE;AAAA,MACJ;AAAA,IACJ;AAAA,EACJ;AAGA,aAAW,iBAAiB,KAAK,CAAC,YAAY,OAAO,QAAQ,OAAO,WAAW,CAAE;AACrF;AAOA,SAAS,aAAa,YAAiB,OAAqB;AAExD,MAAI,OAAO,eAAe,YAAY,OAAO,WAAW,SAAS,YAAY,WAAW,KAAK,WAAW,GAAG;AACvG,UAAM,IAAI;AAAA,MACN,2FAA2F;AAAA,IAC/F;AAAA,EACJ;AAGA,UAAQ,WAAW,MAAM;AAAA,IACrB,KAAK;AACD,yBAAmB,YAAY,KAAK;AACpC;AAAA,IAEJ,KAAK;AACD,4BAAsB,YAAY,KAAK;AACvC;AAAA,IAEJ,KAAK;AACD,uBAAiB,YAAY,KAAK;AAClC;AAAA,IAEJ,KAAK;AACD,yBAAmB,YAAY,KAAK;AACpC;AAAA,IAEJ,KAAK;AACD,uBAAiB,YAAY,KAAK;AAClC;AAAA,IAEJ,KAAK;AACD,0BAAoB,YAAY,KAAK;AACrC;AAAA,IAEJ,KAAK;AACD,uBAAiB,YAAY,KAAK;AAClC;AAAA,IAEJ,KAAK;AACD,uBAAiB,YAAY,KAAK;AAClC;AAAA,IAEJ,KAAK;AACD,yBAAmB,YAAY,KAAK;AACpC;AAAA,IAEJ,KAAK;AACD,wBAAkB,YAAY,KAAK;AACnC;AAAA,IAEJ,KAAK;AACD,2BAAqB,YAAY,KAAK;AACtC;AAAA,IAEJ,KAAK;AACD,2BAAqB,YAAY,KAAK;AACtC;AAAA,IAEJ,KAAK;AACD,2BAAqB,YAAY,KAAK;AACtC;AAAA,IAEJ,KAAK;AACD,wBAAkB,YAAY,KAAK;AACnC;AAAA,IAEJ;AACI,YAAM,IAAI,MAAM,4BAA4B,WAAW,mBAAmB,QAAQ;AAAA,EAC1F;AACJ;AAOA,SAAS,uBAAuB,YAAiB,OAAqB;AAElE,GAAC,SAAS,SAAS,SAAS,QAAQ,MAAM,EAAE,QAAQ,CAAC,kBAAkB;AAEnE,UAAM,sBAAsB,WAAW;AAGvC,QAAI,OAAO,wBAAwB,aAAa;AAC5C;AAAA,IACJ;AAGA,QAAI,OAAO,wBAAwB,UAAU;AACzC,YAAM,IAAI;AAAA,QACN,uBAAuB,uCAAuC,WAAW,wBAAwB;AAAA,MACrG;AAAA,IACJ;AAGA,QAAI,OAAO,oBAAoB,SAAS,YAAY,oBAAoB,KAAK,WAAW,GAAG;AACvF,YAAM,IAAI;AAAA,QACN,2CAA2C,gDAAgD,WAAW,wBAAwB;AAAA,MAClI;AAAA,IACJ;AAGA,QAAI,OAAO,oBAAoB,SAAS,eAAe,CAAC,MAAM,QAAQ,oBAAoB,IAAI,GAAG;AAC7F,YAAM,IAAI;AAAA,QACN,2CAA2C,sCAAsC,WAAW,wBAAwB;AAAA,MACxH;AAAA,IACJ;AAAA,EACJ,CAAC;AACL;AAOA,SAAS,iBAAiB,YAAiB,OAAqB;AAE5D,MAAI,WAAW,SAAS,QAAQ;AAC5B,UAAM,IAAI,MAAM,4CAA4C;AAAA,EAChE;AAGA,MAAI,QAAQ,GAAG;AACX,UAAM,IAAI,MAAM,iDAAiD;AAAA,EACrE;AAGA,MAAI,OAAO,WAAW,OAAO,gBAAgB,OAAO,WAAW,OAAO,YAAY,WAAW,GAAG,WAAW,IAAI;AAC3G,UAAM,IAAI,MAAM,sEAAsE;AAAA,EAC1F;AAGA,MAAI,OAAO,WAAW,UAAU,aAAa;AACzC,UAAM,IAAI,MAAM,uDAAuD;AAAA,EAC3E;AAGA,yBAAuB,YAAY,KAAK;AAGxC,eAAa,WAAW,OAAO,QAAQ,CAAC;AAC5C;AAOA,SAAS,oBAAoB,YAAiB,OAAqB;AAE/D,MAAI,WAAW,SAAS,WAAW;AAC/B,UAAM,IAAI,MAAM,8DAA8D,QAAQ;AAAA,EAC1F;AAGA,MAAI,OAAO,WAAW,UAAU,aAAa;AACzC,UAAM,IAAI,MAAM,sEAAsE,QAAQ;AAAA,EAClG;AAGA,yBAAuB,YAAY,KAAK;AAGxC,eAAa,WAAW,OAAO,QAAQ,CAAC;AAC5C;AAOA,SAAS,iBAAiB,YAAiB,OAAqB;AAE5D,MAAI,WAAW,SAAS,QAAQ;AAC5B,UAAM,IAAI,MAAM,wDAAwD,QAAQ;AAAA,EACpF;AAGA,MAAI,OAAO,WAAW,UAAU,aAAa;AACzC,UAAM,IAAI,MAAM,mEAAmE,QAAQ;AAAA,EAC/F;AAGA,yBAAuB,YAAY,KAAK;AAGxC,eAAa,WAAW,OAAO,QAAQ,CAAC;AAC5C;AAOA,SAAS,iBAAiB,YAAiB,OAAqB;AAE5D,MAAI,WAAW,SAAS,QAAQ;AAC5B,UAAM,IAAI,MAAM,wDAAwD,QAAQ;AAAA,EACpF;AAGA,MAAI,OAAO,WAAW,UAAU,aAAa;AACzC,UAAM,IAAI,MAAM,mEAAmE,QAAQ;AAAA,EAC/F;AAGA,yBAAuB,YAAY,KAAK;AAGxC,eAAa,WAAW,OAAO,QAAQ,CAAC;AAC5C;AAOA,SAAS,mBAAmB,YAAiB,OAAqB;AAE9D,MAAI,WAAW,SAAS,UAAU;AAC9B,UAAM,IAAI,MAAM,4DAA4D,QAAQ;AAAA,EACxF;AAGA,MAAI,OAAO,WAAW,UAAU,aAAa;AACzC,UAAM,IAAI,MAAM,qEAAqE,QAAQ;AAAA,EACjG;AAGA,MAAI,OAAO,WAAW,eAAe,aAAa;AAC9C,QAAI,MAAM,QAAQ,WAAW,UAAU,GAAG;AAEtC,YAAM,qBAAqB,CAAC,CAAC,WAAW,WAAW,OAAO,CAAC,UAAmB,CAAC,UAAU,KAAK,CAAC,EAAE;AAGjG,UAAI,WAAW,WAAW,WAAW,KAAK,oBAAoB;AAC1D,cAAM,IAAI;AAAA,UACN,+GAA+G;AAAA,QACnH;AAAA,MACJ;AAGA,UAAI,WAAW,WAAW,KAAK,KAAK,WAAW,WAAW,KAAK,GAAG;AAC9D,cAAM,IAAI;AAAA,UACN,yHAAyH;AAAA,QAC7H;AAAA,MACJ;AAGA,UAAI,WAAW,WAAW,KAAK,WAAW,WAAW,IAAI;AACrD,cAAM,IAAI;AAAA,UACN,sJAAsJ;AAAA,QAC1J;AAAA,MACJ;AAAA,IACJ,WAAW,UAAU,WAAW,UAAU,GAAG;AAEzC,UAAI,WAAW,aAAa,GAAG;AAC3B,cAAM,IAAI;AAAA,UACN,qGAAqG;AAAA,QACzG;AAAA,MACJ;AAAA,IACJ,OAAO;AACH,YAAM,IAAI;AAAA,QACN,gIAAgI;AAAA,MACpI;AAAA,IACJ;AAAA,EACJ;AAGA,yBAAuB,YAAY,KAAK;AAGxC,eAAa,WAAW,OAAO,QAAQ,CAAC;AAC5C;AAOA,SAAS,kBAAkB,YAAiB,OAAqB;AAE7D,MAAI,WAAW,SAAS,SAAS;AAC7B,UAAM,IAAI,MAAM,0DAA0D,QAAQ;AAAA,EACtF;AAGA,MAAI,OAAO,WAAW,UAAU,aAAa;AACzC,UAAM,IAAI,MAAM,oEAAoE,QAAQ;AAAA,EAChG;AAGA,MAAI,OAAO,WAAW,aAAa,aAAa;AAC5C,QAAI,MAAM,QAAQ,WAAW,QAAQ,GAAG;AAEpC,YAAM,qBAAqB,CAAC,CAAC,WAAW,SAAS,OAAO,CAAC,UAAmB,CAAC,UAAU,KAAK,CAAC,EAAE;AAG/F,UAAI,WAAW,SAAS,WAAW,KAAK,oBAAoB;AACxD,cAAM,IAAI;AAAA,UACN,4GAA4G;AAAA,QAChH;AAAA,MACJ;AAGA,UAAI,WAAW,SAAS,KAAK,KAAK,WAAW,SAAS,KAAK,GAAG;AAC1D,cAAM,IAAI;AAAA,UACN,oHAAoH;AAAA,QACxH;AAAA,MACJ;AAGA,UAAI,WAAW,SAAS,KAAK,WAAW,SAAS,IAAI;AACjD,cAAM,IAAI;AAAA,UACN,+IAA+I;AAAA,QACnJ;AAAA,MACJ;AAAA,IACJ,WAAW,UAAU,WAAW,QAAQ,GAAG;AAEvC,UAAI,WAAW,WAAW,GAAG;AACzB,cAAM,IAAI;AAAA,UACN,gGAAgG;AAAA,QACpG;AAAA,MACJ;AAAA,IACJ,OAAO;AACH,YAAM,IAAI;AAAA,QACN,6HAA6H;AAAA,MACjI;AAAA,IACJ;AAAA,EACJ;AAGA,yBAAuB,YAAY,KAAK;AAGxC,eAAa,WAAW,OAAO,QAAQ,CAAC;AAC5C;AAOA,SAAS,mBAAmB,YAAiB,OAAqB;AAE9D,MAAI,WAAW,SAAS,UAAU;AAC9B,UAAM,IAAI,MAAM,4DAA4D,QAAQ;AAAA,EACxF;AAGA,MAAI,OAAO,WAAW,QAAQ,YAAY,WAAW,IAAI,WAAW,GAAG;AACnE,UAAM,IAAI,MAAM,0EAA0E,QAAQ;AAAA,EACtG;AAGA,GAAC,SAAS,OAAO,EAAE,QAAQ,CAAC,kBAAkB;AAC1C,QAAI,OAAO,WAAW,mBAAmB,aAAa;AAClD,YAAM,IAAI;AAAA,QACN,4DAA4D,wDAAwD;AAAA,MACxH;AAAA,IACJ;AAAA,EACJ,CAAC;AAGD,GAAC,SAAS,QAAQ,MAAM,EAAE,QAAQ,CAAC,kBAAkB;AACjD,QAAI,OAAO,WAAW,mBAAmB,aAAa;AAClD,YAAM,IAAI;AAAA,QACN,kEAAkE,wDAAwD;AAAA,MAC9H;AAAA,IACJ;AAAA,EACJ,CAAC;AACL;AAOA,SAAS,mBAAmB,YAAiB,OAAqB;AAE9D,MAAI,WAAW,SAAS,UAAU;AAC9B,UAAM,IAAI,MAAM,4DAA4D,QAAQ;AAAA,EACxF;AAGA,MAAI,OAAO,WAAW,SAAS,YAAY,WAAW,KAAK,WAAW,GAAG;AACrE,UAAM,IAAI,MAAM,0EAA0E,QAAQ;AAAA,EACtG;AAGA,MAAI,OAAO,WAAW,SAAS,eAAe,CAAC,MAAM,QAAQ,WAAW,IAAI,GAAG;AAC3E,UAAM,IAAI,MAAM,2EAA2E,QAAQ;AAAA,EACvG;AAGA,yBAAuB,YAAY,KAAK;AAC5C;AAOA,SAAS,sBAAsB,YAAiB,OAAqB;AAEjE,MAAI,WAAW,SAAS,aAAa;AACjC,UAAM,IAAI,MAAM,kEAAkE,QAAQ;AAAA,EAC9F;AAGA,MAAI,OAAO,WAAW,SAAS,YAAY,WAAW,KAAK,WAAW,GAAG;AACrE,UAAM,IAAI,MAAM,6EAA6E,QAAQ;AAAA,EACzG;AAGA,MAAI,OAAO,WAAW,SAAS,eAAe,CAAC,MAAM,QAAQ,WAAW,IAAI,GAAG;AAC3E,UAAM,IAAI,MAAM,8EAA8E,QAAQ;AAAA,EAC1G;AAGA,yBAAuB,YAAY,KAAK;AAC5C;AAOA,SAAS,iBAAiB,YAAiB,OAAqB;AAE5D,MAAI,WAAW,SAAS,QAAQ;AAC5B,UAAM,IAAI,MAAM,wDAAwD,QAAQ;AAAA,EACpF;AAGA,MAAI,OAAO,WAAW,aAAa,aAAa;AAC5C,QAAI,MAAM,QAAQ,WAAW,QAAQ,GAAG;AAEpC,YAAM,qBAAqB,CAAC,CAAC,WAAW,SAAS,OAAO,CAAC,UAAmB,CAAC,UAAU,KAAK,CAAC,EAAE;AAG/F,UAAI,WAAW,SAAS,WAAW,KAAK,oBAAoB;AACxD,cAAM,IAAI;AAAA,UACN,2GAA2G;AAAA,QAC/G;AAAA,MACJ;AAGA,UAAI,WAAW,SAAS,KAAK,KAAK,WAAW,SAAS,KAAK,GAAG;AAC1D,cAAM,IAAI;AAAA,UACN,6GAA6G;AAAA,QACjH;AAAA,MACJ;AAGA,UAAI,WAAW,SAAS,KAAK,WAAW,SAAS,IAAI;AACjD,cAAM,IAAI;AAAA,UACN,8IAA8I;AAAA,QAClJ;AAAA,MACJ;AAAA,IACJ,WAAW,UAAU,WAAW,QAAQ,GAAG;AAEvC,UAAI,WAAW,WAAW,GAAG;AACzB,cAAM,IAAI;AAAA,UACN,+FAA+F;AAAA,QACnG;AAAA,MACJ;AAAA,IACJ,OAAO;AACH,YAAM,IAAI;AAAA,QACN,4HAA4H;AAAA,MAChI;AAAA,IACJ;AAAA,EACJ;AAGA,yBAAuB,YAAY,KAAK;AAC5C;AAOA,SAAS,qBAAqB,YAAiB,OAAqB;AAEhE,MAAI,WAAW,SAAS,YAAY;AAChC,UAAM,IAAI,MAAM,gEAAgE,QAAQ;AAAA,EAC5F;AAGA,MAAI,CAAC,MAAM,QAAQ,WAAW,QAAQ,KAAK,WAAW,SAAS,WAAW,GAAG;AACzE,UAAM,IAAI,MAAM,iFAAiF,QAAQ;AAAA,EAC7G;AAGA,yBAAuB,YAAY,KAAK;AAGxC,aAAW,SAAS,QAAQ,CAAC,UAAe,aAAa,OAAO,QAAQ,CAAC,CAAC;AAC9E;AAOA,SAAS,qBAAqB,YAAiB,OAAqB;AAEhE,MAAI,WAAW,SAAS,YAAY;AAChC,UAAM,IAAI,MAAM,gEAAgE,QAAQ;AAAA,EAC5F;AAGA,MAAI,CAAC,MAAM,QAAQ,WAAW,QAAQ,KAAK,WAAW,SAAS,WAAW,GAAG;AACzE,UAAM,IAAI,MAAM,iFAAiF,QAAQ;AAAA,EAC7G;AAGA,yBAAuB,YAAY,KAAK;AAGxC,aAAW,SAAS,QAAQ,CAAC,UAAe,aAAa,OAAO,QAAQ,CAAC,CAAC;AAC9E;AAOA,SAAS,qBAAqB,YAAiB,OAAqB;AAEhE,MAAI,WAAW,SAAS,YAAY;AAChC,UAAM,IAAI,MAAM,gEAAgE,QAAQ;AAAA,EAC5F;AAGA,MAAI,CAAC,MAAM,QAAQ,WAAW,QAAQ,KAAK,WAAW,SAAS,WAAW,GAAG;AACzE,UAAM,IAAI,MAAM,iFAAiF,QAAQ;AAAA,EAC7G;AAGA,yBAAuB,YAAY,KAAK;AAGxC,aAAW,SAAS,QAAQ,CAAC,UAAe,aAAa,OAAO,QAAQ,CAAC,CAAC;AAC9E;AAOA,SAAS,kBAAkB,YAAiB,OAAqB;AAE7D,MAAI,WAAW,SAAS,SAAS;AAC7B,UAAM,IAAI,MAAM,0DAA0D,QAAQ;AAAA,EACtF;AAGA,MAAI,CAAC,MAAM,QAAQ,WAAW,QAAQ,KAAK,WAAW,SAAS,WAAW,GAAG;AACzE,UAAM,IAAI,MAAM,8EAA8E,QAAQ;AAAA,EAC1G;AAGA,MAAI,OAAO,WAAW,YAAY,aAAa;AAE3C,QACI,CAAC,MAAM,QAAQ,WAAW,OAAO,KACjC,WAAW,QAAQ,WAAW,WAAW,SAAS,UAClD,WAAW,QAAQ,OAAO,CAAC,UAAmB,CAAC,UAAU,KAAK,CAAC,EAAE,UACjE,WAAW,QAAQ,OAAO,CAAC,UAAkB,QAAQ,CAAC,EAAE,QAC1D;AACE,YAAM,IAAI;AAAA,QACN,mKAAmK;AAAA,MACvK;AAAA,IACJ;AAAA,EACJ;AAGA,yBAAuB,YAAY,KAAK;AAGxC,aAAW,SAAS,QAAQ,CAAC,UAAe,aAAa,OAAO,QAAQ,CAAC,CAAC;AAC9E;AAOA,SAAS,8BAA8B,cAAkD;AACrF,SAAO,EAAE,WAAW,OAAO,aAAa;AAC5C;;;ACxyBA,IAAqB,SAArB,MAA4B;AAAA,EAexB,OAAc,QAAQ,MAA8B;AAChD,WAAO,KAAK,oBAAoB;AAAA,EACpC;AAAA,EAOA,OAAc,QAAQ,MAAc,MAA4B;AAC5D,SAAK,oBAAoB,QAAQ;AAAA,EACrC;AAAA,EAUA,OAAO,eAAe,OAAc,MAAsC;AAEtE,UAAM,gBAAgB,MAAM;AAC5B,QAAI,iBAAiB,OAAO,kBAAkB,YAAY;AACtD,aAAO,CAAC,SAAgB,cAAc,MAAM,OAAO,IAAI;AAAA,IAC3D;AAGA,QAAI,KAAK,oBAAoB,SAAS,OAAO,KAAK,oBAAoB,UAAU,YAAY;AACxF,YAAM,qBAAqB,KAAK,oBAAoB;AACpD,aAAO,CAAC,SAAgB,mBAAmB,OAAO,GAAG,IAAI;AAAA,IAC7D;AAGA,WAAO;AAAA,EACX;AAAA,EAKA,OAAO,cAAqD;AACxD,WAAO,KAAK;AAAA,EAChB;AAAA,EAOA,OAAO,WAAW,MAAc,SAA6B;AACzD,SAAK,mBAAmB,QAAQ;AAAA,EACpC;AAAA,EAMA,OAAO,OAAO,MAAc;AACxB,WAAO,KAAK,oBAAoB;AAChC,WAAO,KAAK,mBAAmB;AAAA,EACnC;AAAA,EAKA,OAAO,QAAQ;AACX,SAAK,sBAAsB,CAAC;AAC5B,SAAK,qBAAqB,CAAC;AAAA,EAC/B;AACJ;AAjFI,cAJiB,QAIF,uBAAyD,CAAC;AAIzE,cARiB,QAQF,sBAA4D,CAAC;;;ACXhF,IAAqB,4BAArB,cAAuD,MAAM;AAAA,EAIzD,YAAoB,QAAc;AAC9B,UAAM,mCAAmC;AADzB;AAAA,EAEpB;AAAA,EAOA,eAAe,CAAC,SAAe,SAAS,KAAK;AACjD;;;ACNA,IAAqB,YAArB,MAA+B;AAAA,EAI3B,YAAoB,OAAwB;AAAxB;AAAA,EAAyB;AAAA,EAO7C,WAAW,CAAC,UAAiB;AAEzB,eAAW,WAAW,KAAK,OAAO;AAE9B,iBAAW,SAAS,QAAQ,QAAQ;AAEhC,YAAI,CAAC,MAAM,YAAY,KAAK,GAAG;AAC3B,gBAAM,IAAI,0BAA0B,QAAQ,IAAI;AAAA,QACpD;AAAA,MACJ;AAAA,IACJ;AAAA,EACJ;AACJ;;;ACrBA,IAA8B,OAA9B,MAAmC;AAAA,EAmB/B,YAAoB,MAAsB,YAAiC,MAAa;AAApE;AAAsB;AAAiC;AAAA,EAAc;AAAA,EAfxE,MAAc,cAAc;AAAA,EAIrC;AAAA,EAIA;AAAA,EA6BR,WAAW,MAAgB,KAAK;AAAA,EAChC,WAAW,CAAC,UAA0B;AAClC,SAAK,QAAQ;AAAA,EACjB;AAAA,EAKA,SAAS,MAAM,KAAK;AAAA,EAKpB,UAAU,MAAM,KAAK;AAAA,EAKrB,gBAAgB,MAAM,KAAK;AAAA,EAK3B,eAAe,MAAM,KAAK;AAAA,EAQ1B,aAAa,MAAyB;AAClC,WACI,KAAK,cAAc,EAAE,OAAO,CAAC,cAAc,UAAU,KAAK,YAAY,MAAM,KAAK,YAAY,CAAC,EAAE,MAAM;AAAA,EAE9G;AAAA,EAKA,qBAAqB,MAAe,KAAK,cAAc,EAAE,OAAO,CAAC,cAAc,UAAU,QAAQ,CAAC;AAAA,EAKlG,eAAe,CAAC,UAAsB,KAAK,YAAY;AAAA,EAKvD,eAAe,MAAM,CAAC,CAAC,KAAK;AAAA,EAMrB,GAAG,OAA0B;AAChC,WAAO,KAAK,UAAU;AAAA,EAC1B;AAAA,EAKO,QAAc;AACjB,SAAK,wCAAoB;AAAA,EAC7B;AAAA,EAMO,MAAM,OAAoB;AAE7B,QAAI,CAAC,KAAK,sCAAgB,GAAG;AACzB;AAAA,IACJ;AAGA,SAAK,MAAM;AAEX,SAAK,aAAa,MAAM,GAAG,kBAAkB,OAAO,OAAO,IAAI;AAAA,EACnE;AAAA,EAQO,OAAO,OAAc,SAAqC;AAE7D,QAAI,KAAK,0CAAkB,KAAK,KAAK,oCAAe,GAAG;AACnD;AAAA,IACJ;AAEA,QAAI;AAEA,WAAK,UAAW,SAAS,KAAK;AAG9B,UAAI,KAAK,kCAAc,GAAG;AACtB,aAAK,aAAa,OAAO,GAAG,kBAAkB,KAAK;AAAA,MACvD;AAEA,WAAK,aAAa,MAAM,GAAG,kBAAkB,KAAK;AAGlD,WAAK,SAAS,OAAO,OAAO;AAG5B,UAAI,KAAK,0CAAkB,KAAK,KAAK,oCAAe,GAAG;AACnD,aAAK,aAAa,MAAM,GAAG,kBAAkB,OAAO,KAAK,0CAAkB,GAAG,KAAK;AAAA,MACvF;AAAA,IACJ,SAAS,OAAP;AAEE,UAAI,iBAAiB,6BAA6B,MAAM,aAAa,IAAI,GAAG;AAExE,aAAK,MAAM,KAAK;AAGhB,aAAK,0CAAqB;AAAA,MAC9B,OAAO;AACH,cAAM;AAAA,MACV;AAAA,IACJ;AAAA,EACJ;AACJ;AAMA,SAAS,gBAAwB;AAC7B,MAAI,KAAK,WAAY;AACjB,aAAU,IAAI,KAAK,OAAO,KAAK,QAAW,GAAG,SAAS,EAAE,EAAE,UAAU,CAAC;AAAA,EACzE;AACA,SAAO,GAAG,IAAI,GAAG,IAAI,MAAM,GAAG,IAAI,MAAM,GAAG,IAAI,MAAM,GAAG,IAAI,MAAM,GAAG,IAAI,GAAG,IAAI,GAAG;AACvF;;;ACzLA,IAA8B,YAA9B,cAAgD,KAAK;AAAA,EAMjD,YAAY,MAAc,YAAmC,UAAkB;AAC3E,UAAM,MAAM,YAAY,CAAC,CAAC;AAD+B;AAAA,EAE7D;AAAA,EAKA,aAAa,MAAM;AAAA,EAKnB,cAAc,MAAM,KAAK;AAAA,EAKzB,QAAQ,MAAM;AAEV,SAAK,wCAAoB;AAGzB,SAAK,YAAY,EAAE,QAAQ,CAAC,UAAU,MAAM,MAAM,CAAC;AAAA,EACvD;AAAA,EAMA,QAAQ,CAAC,UAAiB;AAEtB,QAAI,CAAC,KAAK,sCAAgB,GAAG;AACzB;AAAA,IACJ;AAGA,SAAK,YAAY,EAAE,QAAQ,CAAC,UAAU,MAAM,MAAM,KAAK,CAAC;AAGxD,SAAK,MAAM;AAEX,SAAK,aAAa,MAAM,GAAG,kBAAkB,OAAO,OAAO,IAAI;AAAA,EACnE;AACJ;;;AC9CA,IAAqB,WAArB,cAAsC,UAAU;AAAA,EAK5C,YAAY,YAAyB,UAAkB;AACnD,UAAM,YAAY,YAAY,QAAQ;AAAA,EAC1C;AAAA,EAOU,SAAS,OAAc,SAAqC;AAElE,QAAI,iBAAiB;AAErB,QAAI,iBAAiB;AAGrB,eAAW,SAAS,KAAK,UAAU;AAE/B,UAAI,MAAM,SAAS,yCAAqB,MAAM,SAAS,2CAAqB;AAExE,cAAM,OAAO,OAAO,OAAO;AAAA,MAC/B;AAGA,UAAI,MAAM,SAAS,+CAAuB;AAEtC;AAGA;AAAA,MACJ;AAGA,UAAI,MAAM,SAAS,yCAAoB;AACnC,yBAAiB;AAGjB;AAAA,MACJ;AAGA,UAAI,MAAM,SAAS,2CAAqB;AAEpC,cAAM,IAAI,MAAM,0CAA0C;AAAA,MAC9D;AAAA,IACJ;AAEA,QAAI,gBAAgB;AAEhB,WAAK,0CAAqB;AAG1B,iBAAW,SAAS,KAAK,UAAU;AAC/B,YAAI,MAAM,SAAS,2CAAqB;AACpC,gBAAM,MAAM,KAAK;AAAA,QACrB;AAAA,MACJ;AAAA,IACJ,OAAO;AAEH,WAAK,SAAS,mBAAmB,KAAK,SAAS,sFAAwC;AAAA,IAC3F;AAAA,EACJ;AAAA,EAKA,UAAU,MAAM;AACpB;;;ACxEA,IAAqB,WAArB,cAAsC,UAAU;AAAA,EAK5C,YAAY,YAAmC,UAAkB;AAC7D,UAAM,YAAY,YAAY,QAAQ;AADK;AAAA,EAE/C;AAAA,EAOU,SAAS,OAAc,SAAqC;AAElE,eAAW,SAAS,KAAK,UAAU;AAE/B,UAAI,MAAM,SAAS,yCAAqB,MAAM,SAAS,2CAAqB;AAExE,cAAM,OAAO,OAAO,OAAO;AAAA,MAC/B;AAGA,UAAI,MAAM,SAAS,+CAAuB;AAEtC,aAAK,gDAAwB;AAG7B;AAAA,MACJ;AAGA,UAAI,MAAM,SAAS,yCAAoB;AAGnC,YAAI,KAAK,SAAS,QAAQ,KAAK,MAAM,KAAK,SAAS,SAAS,GAAG;AAE3D,eAAK,0CAAqB;AAG1B;AAAA,QACJ,OAAO;AAEH;AAAA,QACJ;AAAA,MACJ;AAGA,UAAI,MAAM,SAAS,2CAAqB;AAEpC,aAAK,4CAAsB;AAG3B;AAAA,MACJ;AAGA,YAAM,IAAI,MAAM,0CAA0C;AAAA,IAC9D;AAAA,EACJ;AAAA,EAKA,UAAU,MAAM;AACpB;;;AClEA,IAAqB,WAArB,cAAsC,UAAU;AAAA,EAK5C,YAAY,YAAmC,UAAkB;AAC7D,UAAM,YAAY,YAAY,QAAQ;AADK;AAAA,EAE/C;AAAA,EAOU,SAAS,OAAc,SAAqC;AAElE,eAAW,SAAS,KAAK,UAAU;AAE/B,UAAI,MAAM,SAAS,yCAAqB,MAAM,SAAS,2CAAqB;AAExE,cAAM,OAAO,OAAO,OAAO;AAAA,MAC/B;AAGA,UAAI,MAAM,SAAS,+CAAuB;AAGtC,YAAI,KAAK,SAAS,QAAQ,KAAK,MAAM,KAAK,SAAS,SAAS,GAAG;AAE3D,eAAK,gDAAwB;AAG7B;AAAA,QACJ,OAAO;AAEH;AAAA,QACJ;AAAA,MACJ;AAGA,UAAI,MAAM,SAAS,yCAAoB;AAEnC,aAAK,0CAAqB;AAG1B;AAAA,MACJ;AAGA,UAAI,MAAM,SAAS,2CAAqB;AAEpC,aAAK,4CAAsB;AAG3B;AAAA,MACJ;AAGA,YAAM,IAAI,MAAM,0CAA0C;AAAA,IAC9D;AAAA,EACJ;AAAA,EAKA,UAAU,MAAM;AACpB;;;AC7EA,wBAAwB;AAcxB,IAAqB,QAArB,cAAmC,UAAU;AAAA,EAMzC,YAAY,YAAiC,SAA+B,UAAkB;AAC1F,UAAM,SAAS,YAAY,QAAQ;AADM;AAAA,EAE7C;AAAA,EAKQ;AAAA,EAOE,SAAS,OAAc,SAAqC;AAElE,QAAI,KAAK,kCAAc,GAAG;AAEtB,YAAM,gBAAY,kBAAAC,SAAkB;AAAA,QAEhC,QAAQ,QAAQ;AAAA,QAEhB,cAAc,KAAK,SAAS,IAAI,CAAC,OAAO,UAAU,CAAC,OAAO,KAAK,UAAU,UAAU,CAAC,CAAC;AAAA,MACzF,CAAC;AAGD,WAAK,gBAAgB,UAAU,KAAK,KAAK;AAAA,IAC7C;AAGA,QAAI,CAAC,KAAK,eAAe;AACrB,YAAM,IAAI,MAAM,uDAAuD;AAAA,IAC3E;AAGA,QAAI,KAAK,cAAc,SAAS,yCAAqB,KAAK,cAAc,SAAS,2CAAqB;AAClG,WAAK,cAAc,OAAO,OAAO,OAAO;AAAA,IAC5C;AAGA,SAAK,SAAS,KAAK,cAAc,SAAS,CAAC;AAAA,EAC/C;AAAA,EAKA,UAAU,MAAO,KAAK,UAAU,UAAU,KAAK,QAAQ,KAAK,GAAG,OAAO;AAC1E;;;AC3DA,IAA8B,YAA9B,cAAgD,KAAK;AAAA,EAMjD,YAAY,MAAc,YAAmC,OAAa;AACtE,UAAM,MAAM,YAAY,CAAC,CAAC;AAD+B;AAAA,EAE7D;AAAA,EAKA,aAAa,MAAM;AAAA,EAKnB,cAAc,MAAM,CAAC,KAAK,KAAK;AAAA,EAK/B,QAAQ,MAAM;AAEV,SAAK,wCAAoB;AAGzB,SAAK,MAAM,MAAM;AAAA,EACrB;AAAA,EAMA,QAAQ,CAAC,UAAiB;AAEtB,QAAI,CAAC,KAAK,sCAAgB,GAAG;AACzB;AAAA,IACJ;AAGA,SAAK,MAAM,MAAM,KAAK;AAGtB,SAAK,MAAM;AAEX,SAAK,aAAa,MAAM,GAAG,kBAAkB,OAAO,OAAO,IAAI;AAAA,EACnE;AACJ;;;AC9CA,IAAqB,OAArB,cAAkC,UAAU;AAAA,EAKxC,YAAY,YAAyB,OAAa;AAC9C,UAAM,QAAQ,YAAY,KAAK;AAAA,EACnC;AAAA,EAOU,SAAS,OAAc,SAAqC;AAElE,QAAI,KAAK,MAAM,SAAS,yCAAqB,KAAK,MAAM,SAAS,2CAAqB;AAClF,WAAK,MAAM,OAAO,OAAO,OAAO;AAAA,IACpC;AAGA,YAAQ,KAAK,MAAM,SAAS,GAAG;AAAA,MAC3B;AACI,aAAK,4CAAsB;AAC3B;AAAA,MAEJ;AAAA,MACA;AACI,aAAK,0CAAqB;AAC1B;AAAA,MAEJ;AACI,aAAK,wCAAoB;AAAA,IACjC;AAAA,EACJ;AAAA,EAKA,UAAU,MAAM;AACpB;;;ACxCA,IAAqB,OAArB,cAAkC,UAAU;AAAA,EAKxC,YAAY,YAAyB,OAAa;AAC9C,UAAM,QAAQ,YAAY,KAAK;AAAA,EACnC;AAAA,EAOU,SAAS,OAAc,SAAqC;AAElE,QAAI,KAAK,MAAM,SAAS,yCAAqB,KAAK,MAAM,SAAS,2CAAqB;AAClF,WAAK,MAAM,OAAO,OAAO,OAAO;AAAA,IACpC;AAGA,YAAQ,KAAK,MAAM,SAAS,GAAG;AAAA,MAC3B;AACI,aAAK,4CAAsB;AAC3B;AAAA,MAEJ;AACI,aAAK,0CAAqB;AAC1B;AAAA,MAEJ;AACI,aAAK,gDAAwB;AAC7B;AAAA,MAEJ;AACI,aAAK,wCAAoB;AAAA,IACjC;AAAA,EACJ;AAAA,EAKA,UAAU,MAAM;AACpB;;;ACvCA,IAAqB,SAArB,cAAoC,UAAU;AAAA,EAQ1C,YACI,YACQ,YACA,eACA,eACR,OACF;AACE,UAAM,UAAU,YAAY,KAAK;AALzB;AACA;AACA;AAAA,EAIZ;AAAA,EAKQ,uBAAsC;AAAA,EAKtC,wBAAgC;AAAA,EAO9B,SAAS,OAAc,SAAqC;AAElE,QAAI,KAAK,kCAAc,GAAG;AAEtB,WAAK,MAAM,MAAM;AAGjB,WAAK,wBAAwB;AAG7B,WAAK,wBAAwB,OAAO;AAAA,IACxC;AAIA,QAAI,KAAK,WAAW,GAAG;AAEnB,WAAK,4CAAsB;AAI3B,UAAI,KAAK,MAAM,SAAS,+CAAuB;AAC3C,aAAK,MAAM,MAAM;AAAA,MACrB;AAGA,WAAK,MAAM,OAAO,OAAO,OAAO;AAIhC,UAAI,KAAK,MAAM,SAAS,yCAAoB;AAExC,aAAK,0CAAqB;AAE1B;AAAA,MACJ,WAAW,KAAK,MAAM,SAAS,+CAAuB;AAElD,aAAK,yBAAyB;AAAA,MAClC;AAAA,IACJ,OAAO;AAEH,WAAK,gDAAwB;AAAA,IACjC;AAAA,EACJ;AAAA,EAKA,UAAU,MAAM;AACZ,QAAI,KAAK,eAAe,MAAM;AAC1B,aAAO,UAAU,KAAK;AAAA,IAC1B,WAAW,KAAK,kBAAkB,QAAQ,KAAK,kBAAkB,MAAM;AACnE,aAAO,UAAU,KAAK,kBAAkB,KAAK;AAAA,IACjD,OAAO;AACH,aAAO;AAAA,IACX;AAAA,EACJ;AAAA,EAKA,QAAQ,MAAM;AAEV,SAAK,wCAAoB;AAGzB,SAAK,wBAAwB;AAG7B,SAAK,MAAM,MAAM;AAAA,EACrB;AAAA,EAMQ,aAAa,MAAM;AACvB,QAAI,KAAK,yBAAyB,MAAM;AAEpC,aAAO,KAAK,wBAAwB,KAAK;AAAA,IAC7C;AAGA,WAAO;AAAA,EACX;AAAA,EAMQ,0BAA0B,CAAC,YAAkC;AAEjE,QAAI,KAAK,eAAe,MAAM;AAC1B,WAAK,uBAAuB,KAAK;AAAA,IACrC,WAAW,KAAK,kBAAkB,QAAQ,KAAK,kBAAkB,MAAM;AAGnE,YAAM,SAAS,OAAO,QAAQ,WAAW,aAAa,QAAQ,SAAS,KAAK;AAG5E,WAAK,uBAAuB,KAAK;AAAA,QAC7B,OAAO,KAAK,KAAK,gBAAgB,KAAK,gBAAgB,KAAK,KAAK;AAAA,MACpE;AAAA,IACJ,OAAO;AACH,WAAK,uBAAuB;AAAA,IAChC;AAAA,EACJ;AACJ;;;AC5IA,IAAqB,QAArB,cAAmC,UAAU;AAAA,EAQzC,YACI,YACQ,UACA,aACA,aACR,OACF;AACE,UAAM,SAAS,YAAY,KAAK;AALxB;AACA;AACA;AAAA,EAIZ;AAAA,EAKQ,qBAAoC;AAAA,EAKpC,sBAA8B;AAAA,EAO5B,SAAS,OAAc,SAAqC;AAElE,QAAI,KAAK,kCAAc,GAAG;AAEtB,WAAK,MAAM,MAAM;AAGjB,WAAK,sBAAsB;AAG3B,WAAK,sBAAsB,OAAO;AAAA,IACtC;AAIA,QAAI,KAAK,WAAW,GAAG;AAEnB,WAAK,4CAAsB;AAI3B,UAAI,KAAK,MAAM,SAAS,yCAAoB;AACxC,aAAK,MAAM,MAAM;AAAA,MACrB;AAGA,WAAK,MAAM,OAAO,OAAO,OAAO;AAIhC,UAAI,KAAK,MAAM,SAAS,+CAAuB;AAE3C,aAAK,gDAAwB;AAE7B;AAAA,MACJ,WAAW,KAAK,MAAM,SAAS,yCAAoB;AAE/C,aAAK,uBAAuB;AAAA,MAChC;AAAA,IACJ,OAAO;AAEH,WAAK,0CAAqB;AAAA,IAC9B;AAAA,EACJ;AAAA,EAKA,UAAU,MAAM;AACZ,QAAI,KAAK,aAAa,MAAM;AACxB,aAAO,SAAS,KAAK;AAAA,IACzB,WAAW,KAAK,gBAAgB,QAAQ,KAAK,gBAAgB,MAAM;AAC/D,aAAO,SAAS,KAAK,gBAAgB,KAAK;AAAA,IAC9C,OAAO;AACH,aAAO;AAAA,IACX;AAAA,EACJ;AAAA,EAKA,QAAQ,MAAM;AAEV,SAAK,wCAAoB;AAGzB,SAAK,sBAAsB;AAG3B,SAAK,MAAM,MAAM;AAAA,EACrB;AAAA,EAMA,aAAa,MAAM;AACf,QAAI,KAAK,uBAAuB,MAAM;AAElC,aAAO,KAAK,sBAAsB,KAAK;AAAA,IAC3C;AAGA,WAAO;AAAA,EACX;AAAA,EAMA,wBAAwB,CAAC,YAAkC;AAEvD,QAAI,KAAK,aAAa,MAAM;AACxB,WAAK,qBAAqB,KAAK;AAAA,IACnC,WAAW,KAAK,gBAAgB,QAAQ,KAAK,gBAAgB,MAAM;AAG/D,YAAM,SAAS,OAAO,QAAQ,WAAW,aAAa,QAAQ,SAAS,KAAK;AAG5E,WAAK,qBAAqB,KAAK;AAAA,QAC3B,OAAO,KAAK,KAAK,cAAc,KAAK,cAAc,KAAK,KAAK;AAAA,MAChE;AAAA,IACJ,OAAO;AACH,WAAK,qBAAqB;AAAA,IAC9B;AAAA,EACJ;AACJ;;;AChJA,IAAqB,OAArB,cAAkC,UAAU;AAAA,EAKxC,YAAY,YAAyB,OAAa;AAC9C,UAAM,QAAQ,YAAY,KAAK;AAAA,EACnC;AAAA,EAOU,SAAS,OAAc,SAAqC;AAElE,QAAI,KAAK,MAAM,SAAS,yCAAqB,KAAK,MAAM,SAAS,2CAAqB;AAElF,WAAK,MAAM,OAAO,OAAO,OAAO;AAAA,IACpC;AAGA,SAAK,SAAS,KAAK,MAAM,SAAS,CAAC;AAAA,EACvC;AAAA,EAKA,UAAU,MAAM;AACpB;;;AC7BA,IAAqB,UAArB,cAAqC,UAAU;AAAA,EAK3C,YAAY,YAAyB,OAAa;AAC9C,UAAM,WAAW,YAAY,KAAK;AAAA,EACtC;AAAA,EAOU,SAAS,OAAc,SAAqC;AAElE,QAAI,KAAK,MAAM,SAAS,yCAAqB,KAAK,MAAM,SAAS,2CAAqB;AAClF,WAAK,MAAM,OAAO,OAAO,OAAO;AAAA,IACpC;AAGA,YAAQ,KAAK,MAAM,SAAS,GAAG;AAAA,MAC3B;AACI,aAAK,4CAAsB;AAC3B;AAAA,MAEJ;AAAA,MACA;AACI,aAAK,gDAAwB;AAC7B;AAAA,MAEJ;AACI,aAAK,wCAAoB;AAAA,IACjC;AAAA,EACJ;AAAA,EAKA,UAAU,MAAM;AACpB;;;AC9CA,IAA8B,OAA9B,cAA2C,KAAK;AAAA,EAI5C,aAAa,MAAM;AACvB;;;ACgBA,IAAqB,SAArB,cAAoC,KAAK;AAAA,EAMrC,YAAY,YAAiC,YAA4B,iBAAwB;AAC7F,UAAM,UAAU,YAAY,eAAe;AADF;AAA4B;AAAA,EAEzE;AAAA,EAKQ,uBAAuB;AAAA,EAKvB,sBAAkD;AAAA,EAOhD,SAAS,OAAc,SAAqC;AAElE,QAAI,KAAK,sBAAsB;AAE3B,UAAI,CAAC,KAAK,qBAAqB;AAC3B;AAAA,MACJ;AAEA,YAAM,EAAE,YAAY,MAAM,IAAI,KAAK;AAGnC,UAAI,YAAY;AAEZ,YAAI,qDAA6B,6CAAwB;AACrD,gBAAM,IAAI;AAAA,YACN;AAAA,UACJ;AAAA,QACJ;AAGA,aAAK,SAAS,KAAK;AAEnB;AAAA,MACJ,OAAO;AAEH,cAAM,IAAI,MAAM,oBAAoB,KAAK,sCAAsC,QAAQ;AAAA,MAC3F;AAAA,IACJ;AAGA,UAAM,oBAAoB,OAAO,eAAe,OAAO,KAAK,UAAU;AAGtE,QAAI,sBAAsB,MAAM;AAC5B,YAAM,IAAI;AAAA,QACN,4CAA4C,KAAK;AAAA,MACrD;AAAA,IACJ;AAEA,QAAI;AAEJ,QAAI;AAKA,6BAAuB,kBAAkB,KAAK,eAAe;AAAA,IACjE,SAAS,OAAP;AAEE,UAAI,iBAAiB,OAAO;AACxB,cAAM,IAAI,MAAM,oBAAoB,KAAK,sBAAsB,MAAM,OAAO;AAAA,MAChF,OAAO;AACH,cAAM,IAAI,MAAM,oBAAoB,KAAK,sBAAsB,OAAO;AAAA,MAC1E;AAAA,IACJ;AAEA,QAAI,gCAAgC,SAAS;AACzC,2BAAqB;AAAA,QACjB,CAAC,WAAW;AAER,cAAI,CAAC,KAAK,sBAAsB;AAC5B;AAAA,UACJ;AAGA,eAAK,sBAAsB;AAAA,YACvB,YAAY;AAAA,YACZ,OAAO;AAAA,UACX;AAAA,QACJ;AAAA,QACA,CAAC,WAAW;AAER,cAAI,CAAC,KAAK,sBAAsB;AAC5B;AAAA,UACJ;AAGA,eAAK,sBAAsB;AAAA,YACvB,YAAY;AAAA,YACZ,OAAO;AAAA,UACX;AAAA,QACJ;AAAA,MACJ;AAGA,WAAK,4CAAsB;AAG3B,WAAK,uBAAuB;AAAA,IAChC,OAAO;AAEH,WAAK,qBAAqB,oBAAoB;AAG9C,WAAK,SAAS,2DAAqC;AAAA,IACvD;AAAA,EACJ;AAAA,EAKA,UAAU,MAAM,KAAK;AAAA,EAKrB,QAAQ,MAAM;AAEV,SAAK,wCAAoB;AAGzB,SAAK,uBAAuB;AAC5B,SAAK,sBAAsB;AAAA,EAC/B;AAAA,EAMQ,uBAAuB,CAAC,WAA0C;AACtE,YAAQ,QAAQ;AAAA,MACZ;AAAA,MACA;AAAA,MACA;AAAA,MACA,KAAK;AACD;AAAA,MACJ;AACI,cAAM,IAAI;AAAA,UACN,6BAA6B,KAAK,yFAAyF;AAAA,QAC/H;AAAA,IACR;AAAA,EACJ;AACJ;;;AC5KA,IAAqB,YAArB,cAAuC,KAAK;AAAA,EAMxC,YAAY,YAAiC,eAA+B,oBAA2B;AACnG,UAAM,aAAa,YAAY,kBAAkB;AADR;AAA+B;AAAA,EAE5E;AAAA,EAOU,SAAS,OAAc,SAAqC;AAElE,UAAM,uBAAuB,OAAO,eAAe,OAAO,KAAK,aAAa;AAG5E,QAAI,yBAAyB,MAAM;AAC/B,YAAM,IAAI;AAAA,QACN,kDAAkD,KAAK;AAAA,MAC3D;AAAA,IACJ;AAEA,QAAI;AAEJ,QAAI;AAEA,gCAA0B,qBAAqB,KAAK,kBAAkB;AAAA,IAC1E,SAAS,OAAP;AAEE,UAAI,iBAAiB,OAAO;AACxB,cAAM,IAAI,MAAM,uBAAuB,KAAK,yBAAyB,MAAM,OAAO;AAAA,MACtF,OAAO;AACH,cAAM,IAAI,MAAM,uBAAuB,KAAK,yBAAyB,OAAO;AAAA,MAChF;AAAA,IACJ;AAGA,QAAI,OAAO,4BAA4B,WAAW;AAC9C,YAAM,IAAI;AAAA,QACN,gCAAgC,KAAK,oDAAoD;AAAA,MAC7F;AAAA,IACJ;AAGA,SAAK,SAAS,CAAC,CAAC,qGAAwD;AAAA,EAC5E;AAAA,EAKA,UAAU,MAAM,KAAK;AACzB;;;ACxDA,IAAqB,OAArB,cAAkC,KAAK;AAAA,EAOnC,YACI,YACQ,UACA,aACA,aACV;AACE,UAAM,QAAQ,YAAY,CAAC,CAAC;AAJpB;AACA;AACA;AAAA,EAGZ;AAAA,EAKQ,oBAA4B;AAAA,EAK5B,gBAA+B;AAAA,EAK/B,iBAAyB;AAAA,EAOvB,SAAS,OAAc,SAAqC;AAElE,QAAI,KAAK,kCAAc,GAAG;AAEtB,WAAK,oBAAoB,IAAI,KAAK,EAAE,QAAQ;AAG5C,WAAK,iBAAiB;AAGtB,UAAI,KAAK,aAAa,MAAM;AACxB,aAAK,gBAAgB,KAAK;AAAA,MAC9B,WAAW,KAAK,gBAAgB,QAAQ,KAAK,gBAAgB,MAAM;AAG/D,cAAM,SAAS,OAAO,QAAQ,WAAW,aAAa,QAAQ,SAAS,KAAK;AAG5E,aAAK,gBAAgB,KAAK;AAAA,UACtB,OAAO,KAAK,KAAK,cAAc,KAAK,cAAc,KAAK,KAAK;AAAA,QAChE;AAAA,MACJ,OAAO;AACH,aAAK,gBAAgB;AAAA,MACzB;AAGA,WAAK,4CAAsB;AAAA,IAC/B;AAGA,QAAI,KAAK,kBAAkB,MAAM;AAC7B;AAAA,IACJ;AAGA,QAAI,OAAO,QAAQ,iBAAiB,YAAY;AAE5C,YAAM,YAAY,QAAQ,aAAa;AAGvC,UAAI,OAAO,cAAc,YAAY,MAAM,SAAS,GAAG;AACnD,cAAM,IAAI,MAAM,oDAAoD;AAAA,MACxE;AAGA,WAAK,kBAAkB,YAAY;AAAA,IACvC,OAAO;AAEH,WAAK,iBAAiB,IAAI,KAAK,EAAE,QAAQ,IAAI,KAAK;AAAA,IACtD;AAGA,QAAI,KAAK,kBAAkB,KAAK,eAAe;AAE3C,WAAK,gDAAwB;AAAA,IACjC;AAAA,EACJ;AAAA,EAKA,UAAU,MAAM;AACZ,QAAI,KAAK,aAAa,MAAM;AACxB,aAAO,QAAQ,KAAK;AAAA,IACxB,WAAW,KAAK,gBAAgB,QAAQ,KAAK,gBAAgB,MAAM;AAC/D,aAAO,QAAQ,KAAK,iBAAiB,KAAK;AAAA,IAC9C,OAAO;AACH,aAAO;AAAA,IACX;AAAA,EACJ;AACJ;;;ACvGA,IAA8B,YAA9B,MAAuG;AAAA,EAKnG,YAAmB,MAAqB,MAAa;AAAlC;AAAqB;AAAA,EAAc;AAW1D;;;AClBA,IAA8B,QAA9B,cAA4C,UAAiC;AAAA,EAMzE,YAAY,MAAc,MAAqB,WAAmB;AAC9D,UAAM,MAAM,IAAI;AAD2B;AAAA,EAE/C;AAAA,EAKA,eAAe,MAAM,KAAK;AAAA,EAK1B,UAAU,MAAM;AAAA,EAKhB,aAAoC;AAChC,WAAO;AAAA,MACH,MAAM,KAAK;AAAA,MACX,MAAM,KAAK;AAAA,MACX,WAAW,KAAK,aAAa;AAAA,IACjC;AAAA,EACJ;AAQJ;;;ACzCA,IAAqB,QAArB,cAAmC,MAAM;AAAA,EAKrC,YAAY,WAAmB,MAAa;AACxC,UAAM,SAAS,MAAM,SAAS;AAAA,EAClC;AAAA,EAOA,cAAc,CAAC,UAAiB;AAE5B,UAAM,uBAAuB,OAAO,eAAe,OAAO,KAAK,aAAa,CAAC;AAG7E,QAAI,yBAAyB,MAAM;AAC/B,YAAM,IAAI;AAAA,QACN,gDAAgD,KAAK,aAAa;AAAA,MACtE;AAAA,IACJ;AAEA,QAAI;AAEJ,QAAI;AAEA,gCAA0B,qBAAqB,KAAK,IAAI;AAAA,IAC5D,SAAS,OAAP;AAEE,UAAI,iBAAiB,OAAO;AACxB,cAAM,IAAI,MAAM,6BAA6B,KAAK,aAAa,aAAa,MAAM,OAAO;AAAA,MAC7F,OAAO;AACH,cAAM,IAAI,MAAM,6BAA6B,KAAK,aAAa,aAAa,OAAO;AAAA,MACvF;AAAA,IACJ;AAGA,QAAI,OAAO,4BAA4B,WAAW;AAC9C,YAAM,IAAI;AAAA,QACN,sCAAsC,KAAK,aAAa,wCAAwC;AAAA,MACpG;AAAA,IACJ;AAGA,WAAO;AAAA,EACX;AACJ;;;ACjDA,IAAqB,QAArB,cAAmC,MAAM;AAAA,EAKrC,YAAY,WAAmB,MAAa;AACxC,UAAM,SAAS,MAAM,SAAS;AAAA,EAClC;AAAA,EAOA,cAAc,CAAC,UAAiB;AAE5B,UAAM,uBAAuB,OAAO,eAAe,OAAO,KAAK,aAAa,CAAC;AAG7E,QAAI,yBAAyB,MAAM;AAC/B,YAAM,IAAI;AAAA,QACN,gDAAgD,KAAK,aAAa;AAAA,MACtE;AAAA,IACJ;AAEA,QAAI;AAEJ,QAAI;AAEA,gCAA0B,qBAAqB,KAAK,IAAI;AAAA,IAC5D,SAAS,OAAP;AAEE,UAAI,iBAAiB,OAAO;AACxB,cAAM,IAAI,MAAM,6BAA6B,KAAK,aAAa,aAAa,MAAM,OAAO;AAAA,MAC7F,OAAO;AACH,cAAM,IAAI,MAAM,6BAA6B,KAAK,aAAa,aAAa,OAAO;AAAA,MACvF;AAAA,IACJ;AAGA,QAAI,OAAO,4BAA4B,WAAW;AAC9C,YAAM,IAAI;AAAA,QACN,sCAAsC,KAAK,aAAa,wCAAwC;AAAA,MACpG;AAAA,IACJ;AAGA,WAAO,CAAC;AAAA,EACZ;AACJ;;;AC7CA,IAA8B,WAA9B,cAA+C,UAAoC;AAAA,EAM/E,YAAY,MAAc,MAAqB,cAAsB;AACjE,UAAM,MAAM,IAAI;AAD2B;AAAA,EAE/C;AAAA,EAKA,kBAAkB,MAAM,KAAK;AAAA,EAK7B,UAAU,MAAM;AAAA,EAKhB,aAAuC;AACnC,WAAO;AAAA,MACH,MAAM,KAAK;AAAA,MACX,MAAM,KAAK;AAAA,MACX,cAAc,KAAK,gBAAgB;AAAA,IACvC;AAAA,EACJ;AAOJ;;;ACxCA,IAAqB,QAArB,cAAmC,SAAS;AAAA,EAKxC,YAAY,cAAsB,MAAa;AAC3C,UAAM,SAAS,MAAM,YAAY;AAAA,EACrC;AAAA,EAMA,oBAAoB,CAAC,UAAiB;AAElC,UAAM,sBAAsB,OAAO,eAAe,OAAO,KAAK,gBAAgB,CAAC;AAG/E,QAAI,wBAAwB,MAAM;AAC9B,YAAM,IAAI;AAAA,QACN,+BAA+B,KAAK,gBAAgB;AAAA,MACxD;AAAA,IACJ;AAGA,wBAAoB,KAAK,IAAI;AAAA,EACjC;AACJ;;;AC3BA,IAAqB,OAArB,cAAkC,SAAS;AAAA,EAKvC,YAAY,cAAsB,MAAa;AAC3C,UAAM,QAAQ,MAAM,YAAY;AAAA,EACpC;AAAA,EAMA,oBAAoB,CAAC,UAAiB;AAElC,UAAM,sBAAsB,OAAO,eAAe,OAAO,KAAK,gBAAgB,CAAC;AAG/E,QAAI,wBAAwB,MAAM;AAC9B,YAAM,IAAI;AAAA,QACN,8BAA8B,KAAK,gBAAgB;AAAA,MACvD;AAAA,IACJ;AAGA,wBAAoB,KAAK,IAAI;AAAA,EACjC;AACJ;;;AC3BA,IAAqB,OAArB,cAAkC,SAAS;AAAA,EAKvC,YAAY,cAAsB,MAAa;AAC3C,UAAM,QAAQ,MAAM,YAAY;AAAA,EACpC;AAAA,EAQA,oBAAoB,CAAC,OAAc,WAAoB,cAAuB;AAE1E,UAAM,sBAAsB,OAAO,eAAe,OAAO,KAAK,gBAAgB,CAAC;AAG/E,QAAI,wBAAwB,MAAM;AAC9B,YAAM,IAAI;AAAA,QACN,8BAA8B,KAAK,gBAAgB;AAAA,MACvD;AAAA,IACJ;AAGA,wBAAoB,CAAC,EAAE,WAAW,WAAW,SAAS,UAAU,GAAG,GAAG,KAAK,IAAI,CAAC;AAAA,EACpF;AACJ;;;ACkBA,IAAM,qBAAqB,OAAO,UAAU;AAO7B,SAAR,cAA+B,YAAwC;AAE1E,QAAM,wBAAwB,4BAA4B,UAAU;AAKpE;AAAA,IACI,CAAC,sBAAsB,qBAAqB,GAAG,OAAO,OAAO,qBAAqB,CAAC;AAAA,IACnF;AAAA,EACJ;AAGA,QAAM,WAAW,YAAY,sBAAsB,qBAAqB,qBAAqB;AAG7F,0BAAwB,QAAQ;AAGhC,SAAO;AACX;AAQA,SAAS,YAAY,YAA+B,uBAAuD;AAEvG,QAAM,aAAa,sBAAsB,UAAU;AAGnD,UAAQ,WAAW,MAAM;AAAA,IACrB,KAAK;AACD,aAAO,IAAI,KAAK,YAAY,YAAY,WAAW,OAAO,qBAAqB,CAAC;AAAA,IAEpF,KAAK;AACD,UAAI,aAA4B;AAChC,UAAI,gBAA+B;AACnC,UAAI,gBAA+B;AAEnC,UAAI,MAAM,QAAQ,WAAW,UAAU,GAAG;AACtC,wBAAgB,WAAW,WAAW;AACtC,wBAAgB,WAAW,WAAW;AAAA,MAC1C,WAAW,UAAU,WAAW,UAAU,GAAG;AACzC,qBAAa,WAAW;AAAA,MAC5B;AAEA,aAAO,IAAI;AAAA,QACP;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA,YAAY,WAAW,OAAO,qBAAqB;AAAA,MACvD;AAAA,IAEJ,KAAK;AACD,UAAI,WAA0B;AAC9B,UAAI,cAA6B;AACjC,UAAI,cAA6B;AAEjC,UAAI,MAAM,QAAQ,WAAW,QAAQ,GAAG;AACpC,sBAAc,WAAW,SAAS;AAClC,sBAAc,WAAW,SAAS;AAAA,MACtC,WAAW,UAAU,WAAW,QAAQ,GAAG;AACvC,mBAAW,WAAW;AAAA,MAC1B;AAEA,aAAO,IAAI;AAAA,QACP;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA,YAAY,WAAW,OAAO,qBAAqB;AAAA,MACvD;AAAA,IAEJ,KAAK;AACD,aAAO,IAAI,KAAK,YAAY,YAAY,WAAW,OAAO,qBAAqB,CAAC;AAAA,IAEpF,KAAK;AACD,aAAO,IAAI,QAAQ,YAAY,YAAY,WAAW,OAAO,qBAAqB,CAAC;AAAA,IAEvF,KAAK;AACD,aAAO,IAAI,KAAK,YAAY,YAAY,WAAW,OAAO,qBAAqB,CAAC;AAAA,IAEpF,KAAK;AACD,aAAO,IAAI;AAAA,QACP;AAAA,QACA,WAAW,SAAS,IAAI,CAAC,UAAU,YAAY,OAAO,qBAAqB,CAAC;AAAA,MAChF;AAAA,IAEJ,KAAK;AACD,aAAO,IAAI;AAAA,QACP;AAAA,QACA,WAAW,SAAS,IAAI,CAAC,UAAU,YAAY,OAAO,qBAAqB,CAAC;AAAA,MAChF;AAAA,IAEJ,KAAK;AACD,aAAO,IAAI;AAAA,QACP;AAAA,QACA,WAAW,SAAS,IAAI,CAAC,UAAU,YAAY,OAAO,qBAAqB,CAAC;AAAA,MAChF;AAAA,IAEJ,KAAK;AACD,aAAO,IAAI;AAAA,QACP;AAAA,QACA,WAAW;AAAA,QACX,WAAW,SAAS,IAAI,CAAC,UAAU,YAAY,OAAO,qBAAqB,CAAC;AAAA,MAChF;AAAA,IAEJ,KAAK;AACD,aAAO,YAAY,sBAAsB,WAAW,KAAK,OAAO,qBAAqB;AAAA,IAEzF,KAAK;AACD,aAAO,IAAI,OAAO,YAAY,WAAW,MAAM,WAAW,QAAQ,CAAC,CAAC;AAAA,IAExE,KAAK;AACD,aAAO,IAAI,UAAU,YAAY,WAAW,MAAM,WAAW,QAAQ,CAAC,CAAC;AAAA,IAE3E,KAAK;AACD,UAAI,WAA0B;AAC9B,UAAI,cAA6B;AACjC,UAAI,cAA6B;AAEjC,UAAI,MAAM,QAAQ,WAAW,QAAQ,GAAG;AACpC,sBAAc,WAAW,SAAS;AAClC,sBAAc,WAAW,SAAS;AAAA,MACtC,WAAW,UAAU,WAAW,QAAQ,GAAG;AACvC,mBAAW,WAAW;AAAA,MAC1B;AAEA,aAAO,IAAI,KAAK,YAAY,UAAU,aAAa,WAAW;AAAA,EACtE;AACJ;AAOA,SAAS,sBAAsB,YAA4C;AACvE,QAAM,aAA0B,CAAC;AAEjC,MAAI,WAAW,OAAO;AAClB,eAAW,KAAK,IAAI,MAAM,WAAW,MAAM,MAAM,WAAW,MAAM,QAAQ,CAAC,CAAC,CAAC;AAAA,EACjF;AAEA,MAAI,WAAW,OAAO;AAClB,eAAW,KAAK,IAAI,MAAM,WAAW,MAAM,MAAM,WAAW,MAAM,QAAQ,CAAC,CAAC,CAAC;AAAA,EACjF;AAEA,MAAI,WAAW,OAAO;AAClB,eAAW,KAAK,IAAI,MAAM,WAAW,MAAM,MAAM,WAAW,MAAM,QAAQ,CAAC,CAAC,CAAC;AAAA,EACjF;AAEA,MAAI,WAAW,MAAM;AACjB,eAAW,KAAK,IAAI,KAAK,WAAW,KAAK,MAAM,WAAW,KAAK,QAAQ,CAAC,CAAC,CAAC;AAAA,EAC9E;AAEA,MAAI,WAAW,MAAM;AACjB,eAAW,KAAK,IAAI,KAAK,WAAW,KAAK,MAAM,WAAW,KAAK,QAAQ,CAAC,CAAC,CAAC;AAAA,EAC9E;AAEA,SAAO;AACX;AAOA,SAAS,4BAA4B,YAAyD;AAE1F,QAAM,cAAqC,CAAC;AAG5C,aAAW,CAAC,MAAM,kBAAkB,KAAK,OAAO,QAAQ,OAAO,YAAY,CAAC,GAAG;AAE3E,gBAAY,QAAQ,EAAE,GAAG,oBAAoB,IAAI,KAAK;AAAA,EAC1D;AAIA,aAAW,sBAAsB,YAAY;AACzC,gBAAY,mBAAmB,MAAM,sBAAsB;AAAA,EAC/D;AAEA,SAAO;AACX;AAMA,SAAS,wBAAwB,MAAY;AACzC,QAAM,YAAsB,CAAC;AAE7B,QAAM,gBAAgB,CAAC,MAAc,SAAe;AAEhD,WAAO,KAAK,OAAO,IAAI;AAGvB,QAAI,KAAK,WAAW,GAAG;AACnB,gBAAU,KAAK,IAAI;AAAA,IACvB,OAAO;AACH,MAAC,KAA+B,YAAY,EAAE,QAAQ,CAAC,UAAU,cAAc,MAAM,KAAK,CAAC;AAAA,IAC/F;AAAA,EACJ;AAGA,gBAAc,CAAC,GAAG,IAAI;AAEtB,YAAU,QAAQ,CAAC,SAAS;AAExB,aAAS,QAAQ,GAAG,QAAQ,KAAK,QAAQ,SAAS;AAE9C,YAAM,cAAc,KAAK;AAGzB,UAAI,YAAY,aAAa,GAAG;AAC5B;AAAA,MACJ;AAGA,YAAM,YAAY,IAAI;AAAA,QAClB,KACK,MAAM,GAAG,QAAQ,CAAC,EAClB,IAAmB,CAAC,UAAU,EAAE,MAAM,QAAQ,KAAK,mBAAmB,EAAE,EAAE,EAC1E,OAAO,CAAC,YAAY,QAAQ,OAAO,SAAS,CAAC;AAAA,MACtD;AAGA,kBAAY,aAAa,SAAS;AAAA,IACtC;AAAA,EACJ,CAAC;AACL;;;AC1QO,IAAM,gBAAN,MAAoB;AAAA,EAYvB,YACI,YACQ,OACA,UAAgC,CAAC,GAC3C;AAFU;AACA;AAGR,QAAI,kBAAkB,UAAU,GAAG;AAC/B,YAAM,IAAI,MAAM,6BAA6B;AAAA,IACjD;AAGA,QAAI,OAAO,UAAU,YAAY,UAAU,MAAM;AAC7C,YAAM,IAAI,MAAM,0CAA0C;AAAA,IAC9D;AAGA,UAAM,EAAE,WAAW,cAAc,KAAK,IAAI,mBAAmB,UAAU;AAGvE,QAAI,CAAC,WAAW;AACZ,YAAM,IAAI,MAAM,uBAAuB,cAAc;AAAA,IACzD;AAGA,QAAI,CAAC,MAAM;AACP,YAAM,IAAI;AAAA,QACN;AAAA,MACJ;AAAA,IACJ;AAEA,QAAI;AAEA,WAAK,YAAY,cAAc,IAAI;AAAA,IACvC,SAAS,WAAP;AAEE,YAAM,IAAI,MAAM,wBAAyB,UAAoB,SAAS;AAAA,IAC1E;AAAA,EACJ;AAAA,EA7CiB;AAAA,EAmDjB,YAAY;AACR,WAAO,KAAK,UAAU,SAAS;AAAA,EACnC;AAAA,EAMA,WAAW;AACP,WAAO,KAAK,UAAU,SAAS;AAAA,EACnC;AAAA,EAUA,OAAO;AAEH,QAAI,KAAK,UAAU,SAAS,iDAAyB,KAAK,UAAU,SAAS,yCAAoB;AAC7F,WAAK,UAAU,MAAM;AAAA,IACzB;AAEA,QAAI;AACA,WAAK,UAAU,OAAO,KAAK,OAAO,KAAK,OAAO;AAAA,IAClD,SAAS,WAAP;AACE,YAAM,IAAI,MAAM,wBAAyB,UAAoB,SAAS;AAAA,IAC1E;AAAA,EACJ;AAAA,EAKA,QAAQ;AACJ,SAAK,UAAU,MAAM;AAAA,EACzB;AAAA,EAMA,0BAA+C;AAE3C,UAAM,qBAA0C,CAAC;AAOjD,UAAM,cAAc,CAAC,MAAY,cAA6B;AAE1D,YAAM,SAAS,KACV,cAAc,EACd,OAAO,CAAC,cAAc,UAAU,QAAQ,CAAC,EACzC,IAAI,CAAC,cAAc,UAAU,WAAW,CAAC;AAC9C,YAAM,YAAY,KACb,cAAc,EACd,OAAO,CAAC,cAAc,CAAC,UAAU,QAAQ,CAAC,EAC1C,IAAI,CAAC,cAAc,UAAU,WAAW,CAAC;AAG9C,yBAAmB,KAAK;AAAA,QACpB,IAAI,KAAK,OAAO;AAAA,QAChB,MAAM,KAAK,QAAQ;AAAA,QACnB,SAAS,KAAK,QAAQ;AAAA,QACtB,OAAO,KAAK,SAAS;AAAA,QACrB;AAAA,QACA;AAAA,QACA,MAAM,KAAK,aAAa;AAAA,QACxB,UAAU;AAAA,MACd,CAAC;AAGD,UAAI,CAAC,KAAK,WAAW,GAAG;AACpB,QAAC,KACI,YAAY,EACZ,QAAQ,CAAC,UAAU,YAAY,OAAQ,KAA+B,OAAO,CAAC,CAAC;AAAA,MACxF;AAAA,IACJ;AAGA,gBAAY,KAAK,WAAW,IAAI;AAEhC,WAAO;AAAA,EACX;AAAA,EAOA,OAAO,SAAS,MAAc,OAAqD;AAE/E,QAAI,OAAO,UAAU,YAAY;AAC7B,aAAO,QAAQ,MAAM,KAAK;AAC1B;AAAA,IACJ;AAGA,QAAI,OAAO,UAAU,UAAU;AAC3B,UAAI;AAGJ,UAAI;AACA,8BAAsB,kBAAkB,KAAK;AAAA,MACjD,SAAS,WAAP;AACE,cAAM,IAAI,MAAM,+CAAgD,UAAoB,SAAS;AAAA,MACjG;AAGA,UAAI,oBAAoB,UAAU,KAAK,OAAO,oBAAoB,GAAG,OAAO,aAAa;AACrF,cAAM,IAAI,MAAM,mEAAmE;AAAA,MACvF;AAEA,UAAI;AAEA,cAAM,EAAE,WAAW,aAAa,IAAI,uBAAuB,oBAAoB,EAAE;AAGjF,YAAI,CAAC,WAAW;AACZ,gBAAM,IAAI,MAAM,YAAY;AAAA,QAChC;AAAA,MACJ,SAAS,WAAP;AACE,cAAM,IAAI,MAAM,iCAAkC,UAAoB,SAAS;AAAA,MACnF;AAGA,aAAO,WAAW,MAAM,oBAAoB,EAAE;AAAA,IAClD,WAAW,OAAO,UAAU,YAAY,CAAC,MAAM,QAAQ,KAAK,GAAG;AAG3D,UAAI;AAEA,cAAM,EAAE,WAAW,aAAa,IAAI,uBAAuB,KAAK;AAGhE,YAAI,CAAC,WAAW;AACZ,gBAAM,IAAI,MAAM,YAAY;AAAA,QAChC;AAAA,MACJ,SAAS,WAAP;AACE,cAAM,IAAI,MAAM,iCAAkC,UAAoB,SAAS;AAAA,MACnF;AAGA,aAAO,WAAW,MAAM,KAAK;AAAA,IACjC,OAAO;AACH,YAAM,IAAI,MAAM,0FAA0F;AAAA,IAC9G;AAAA,EACJ;AAAA,EAMA,OAAO,WAAW,MAAoB;AAClC,WAAO,OAAO,IAAI;AAAA,EACtB;AAAA,EAKA,OAAO,gBAAsB;AACzB,WAAO,MAAM;AAAA,EACjB;AACJ;", + "sourcesContent": ["\"use strict\";\r\nObject.defineProperty(exports, \"__esModule\", { value: true });\r\nexports.Participant = void 0;\r\n/**\r\n * A participant that holds a number of tickets.\r\n */\r\nvar Participant = /** @class */ (function () {\r\n /**\r\n * Creates an instance of the Participant class.\r\n * @param participant The actual participant.\r\n * @param tickets The number of tickets held by the participant.\r\n */\r\n function Participant(participant, tickets) {\r\n if (tickets === void 0) { tickets = 1; }\r\n this._participant = participant;\r\n this._tickets = tickets;\r\n }\r\n Object.defineProperty(Participant.prototype, \"participant\", {\r\n /** Gets the actual participant. */\r\n get: function () {\r\n return this._participant;\r\n },\r\n enumerable: false,\r\n configurable: true\r\n });\r\n Object.defineProperty(Participant.prototype, \"tickets\", {\r\n /** Gets or sets the number of tickets held by the participant. */\r\n get: function () {\r\n return this._tickets;\r\n },\r\n set: function (value) {\r\n this._tickets = value;\r\n },\r\n enumerable: false,\r\n configurable: true\r\n });\r\n return Participant;\r\n}());\r\nexports.Participant = Participant;\r\n", "\"use strict\";\r\nObject.defineProperty(exports, \"__esModule\", { value: true });\r\nexports.isNaturalNumber = exports.isNullOrUndefined = void 0;\r\n/**\r\n * Gets whether the value provided is null or undefined.\r\n * @param value The value to check.\r\n * @returns Whether the value provided is null or undefined.\r\n */\r\nfunction isNullOrUndefined(value) {\r\n return value === null || value === undefined;\r\n}\r\nexports.isNullOrUndefined = isNullOrUndefined;\r\n/**\r\n * Gets whether the value provided is a natural number.\r\n * @param value The value to check.\r\n * @returns Whether the value provided is a natural number.\r\n */\r\nfunction isNaturalNumber(value) {\r\n return typeof value === \"number\" && value >= 1 && Math.floor(value) === value;\r\n}\r\nexports.isNaturalNumber = isNaturalNumber;\r\n", "\"use strict\";\r\nObject.defineProperty(exports, \"__esModule\", { value: true });\r\nexports.Lotto = void 0;\r\nvar Participant_1 = require(\"./Participant\");\r\nvar Utilities_1 = require(\"./Utilities\");\r\n/**\r\n * Represents a lotto consisting of a number of pickable ticket-holding participants.\r\n */\r\nvar Lotto = /** @class */ (function () {\r\n /**\r\n * Creates a new instance of Lotto.\r\n * @param customRandom The custom RNG to use in place of Math.random().\r\n */\r\n function Lotto(customRandom) {\r\n /** The array of participants that are holding tickets in the lotto. */\r\n this._participants = [];\r\n this._customRandom = customRandom;\r\n }\r\n /**\r\n * Adds a participant with the specified number of tickets, or adds to the participant ticket count if the participant already holds tickets.\r\n * @param participant The participant to add or to increase the ticket count for if they already hold tickets.\r\n * @param tickets The number of tickets, defaults to 1.\r\n * @returns The Lotto instance.\r\n */\r\n Lotto.prototype.add = function (participant, tickets) {\r\n if (tickets === void 0) { tickets = 1; }\r\n // Check that we have a valid ticket count.\r\n if (!(0, Utilities_1.isNaturalNumber)(tickets)) {\r\n throw new Error(\"tickets value must be a natural number\");\r\n }\r\n // Check whether this participant has already been added.\r\n var existingParticipant = this._participants.find(function (part) { return part.participant === participant; });\r\n if (existingParticipant) {\r\n // The participant has already been added to the lotto so just add to their ticket count.\r\n existingParticipant.tickets += tickets;\r\n }\r\n else {\r\n // The participant is not part of the lotto so we should add them.\r\n this._participants.push(new Participant_1.Participant(participant, tickets));\r\n }\r\n return this;\r\n };\r\n /**\r\n * Removes the specified number of tickets for the given participant from the draw, or all tickets if a ticket number is not defined.\r\n * @param participant The participant to remove tickets for.\r\n * @param tickets The number of tickets to remove, or undefined if all tickets are to be removed.\r\n * @returns The Lotto instance.\r\n */\r\n Lotto.prototype.remove = function (participant, tickets) {\r\n // Attempt to get the existing participant.\r\n var existingParticipant = this._participants.find(function (part) { return part.participant === participant; });\r\n // There is nothing to do if the specified participant isn't even part of the lotto.\r\n if (!existingParticipant) {\r\n return this;\r\n }\r\n // Check whether a tickets value was given.\r\n if (tickets !== undefined) {\r\n // Check that we have a valid ticket count.\r\n if (!(0, Utilities_1.isNaturalNumber)(tickets)) {\r\n throw new Error(\"tickets value must be a natural number\");\r\n }\r\n existingParticipant.tickets -= tickets;\r\n // If the participant no longer holds any tickets then they should be removed.\r\n if (existingParticipant.tickets < 1) {\r\n this._participants = this._participants.filter(function (part) { return part !== existingParticipant; });\r\n }\r\n }\r\n else {\r\n // We are removing all tickets for the participant so just remove them from the lotto.\r\n this._participants = this._participants.filter(function (part) { return part !== existingParticipant; });\r\n }\r\n return this;\r\n };\r\n /**\r\n * Draw a winning ticket and return the participant that holds the ticket.\r\n * @param options The draw options.\r\n * @returns The participant that holds the winning ticket.\r\n */\r\n Lotto.prototype.draw = function (options) {\r\n if (options === void 0) { options = {}; }\r\n // If we have no participants then just return null.\r\n if (this._participants.length === 0) {\r\n return null;\r\n }\r\n var redrawable = (0, Utilities_1.isNullOrUndefined)(options.redrawable) ? true : options.redrawable;\r\n var pickable = [];\r\n this._participants.forEach(function (_a) {\r\n var participant = _a.participant, tickets = _a.tickets;\r\n for (var ticketCount = 0; ticketCount < tickets; ticketCount++) {\r\n pickable.push(participant);\r\n }\r\n });\r\n var random;\r\n // We need a random floating-point number between 0 (inclusive) and 1 to scale up to pick our winner.\r\n // If a custom random function exists then we should use that or fall back to Math.random().\r\n if (this._customRandom) {\r\n // Call our custom random function to get a random floating-point number.\r\n random = this._customRandom();\r\n // Verify that the result of calling our custom random function is a number between 0 (inclusive) and 1.\r\n if (typeof random !== \"number\" || random < 0 || random >= 1) {\r\n throw new Error(\"the 'random' function provided did not return a number between 0 (inclusive) and 1\");\r\n }\r\n }\r\n else {\r\n // No custom random function was defined so just use good ol' Math.random().\r\n random = Math.random();\r\n }\r\n // Pick a winning participant.\r\n var winner = pickable[Math.floor(random * pickable.length)];\r\n // If the ticket isn't redrawable then we should remove a ticket from the winning participants ticket count.\r\n if (!redrawable) {\r\n this.remove(winner, 1);\r\n }\r\n // Return the winning participant.\r\n return winner;\r\n };\r\n /**\r\n * Draws multiple winning tickets and return an array of the participants that hold the winning tickets.\r\n * @param tickets The number of winning tickets to draw.\r\n * @param options The draw multiple options.\r\n * @returns An array of the participants that hold the winning tickets.\r\n */\r\n Lotto.prototype.drawMultiple = function (tickets, options) {\r\n if (options === void 0) { options = {}; }\r\n var uniqueResults = (0, Utilities_1.isNullOrUndefined)(options.unique) ? false : options.unique;\r\n // Handle cases where the user has asked for zero tickets (no idea why they would do this be we should trust them).\r\n if (tickets === 0) {\r\n return [];\r\n }\r\n // Now that we know out tickets value is not zero we should check that it is a valid natural number.\r\n if (!(0, Utilities_1.isNaturalNumber)(tickets)) {\r\n throw new Error(\"tickets value must be a natural number\");\r\n }\r\n var result = [];\r\n // Keep drawing tickets until we either reach the number of required tickets or we simply run out of tickets to draw.\r\n // We can run out of tickets to draw if 'options.redrawable' is explicity 'false' or we just had no participants when 'drawMultiple' was called.\r\n while (result.length < tickets && this._participants.length > 0) {\r\n result.push(this.draw(options));\r\n }\r\n // If the 'unique' draw option is set then we need to remove duplicates from the result list.\r\n if (uniqueResults) {\r\n // Create an array to store our unique results.\r\n var unique = [];\r\n // Iterate over all of our participants (with potential duplicates) and populate our array of unique values.\r\n for (var _i = 0, result_1 = result; _i < result_1.length; _i++) {\r\n var participant = result_1[_i];\r\n if (unique.indexOf(participant) === -1) {\r\n unique.push(participant);\r\n }\r\n }\r\n result = unique;\r\n }\r\n return result;\r\n };\r\n return Lotto;\r\n}());\r\nexports.Lotto = Lotto;\r\n", "\"use strict\";\r\nObject.defineProperty(exports, \"__esModule\", { value: true });\r\nexports.createLotto = void 0;\r\nvar Lotto_1 = require(\"./Lotto\");\r\n/**\r\n * A function that creates and returns a Lotto instance.\r\n * @param participantsOrOptions An array of initial participants or options relating to the creation of a Lotto instance.\r\n * @returns A new Lotto instance.\r\n */\r\nfunction createLotto(participantsOrOptions) {\r\n // If no initial participants or lotto options were provided as an argument then we can just return a new lotto instance now.\r\n if (!participantsOrOptions) {\r\n return new Lotto_1.Lotto();\r\n }\r\n // Check whether we were provided with an array of initial participants or a lotto options object.\r\n if (Array.isArray(participantsOrOptions)) {\r\n // We are dealing with a pre-defined array of participants.\r\n var participants = participantsOrOptions;\r\n var lotto_1 = new Lotto_1.Lotto();\r\n // If the lotto participants have been defined upfront then we will need to add them all to our lotto instance now.\r\n participants.forEach(function (_a) {\r\n var participant = _a[0], tokens = _a[1];\r\n return lotto_1.add(participant, tokens);\r\n });\r\n // Return the Lotto instance.\r\n return lotto_1;\r\n }\r\n else {\r\n // We are dealing with some lotto options.\r\n var random = participantsOrOptions.random, participants = participantsOrOptions.participants;\r\n // Create a Lotto instance passing the custom RNG function to use in place of Math.random() (which could be undefined).\r\n var lotto_2 = new Lotto_1.Lotto(random);\r\n // If the lotto participants have been defined upfront as part of the options then we will need to add them all to our lotto instance now.\r\n if (participants) {\r\n participants.forEach(function (_a) {\r\n var participant = _a[0], tokens = _a[1];\r\n return lotto_2.add(participant, tokens);\r\n });\r\n }\r\n // Return the Lotto instance.\r\n return lotto_2;\r\n }\r\n}\r\nexports.createLotto = createLotto;\r\n", "\"use strict\";\r\nObject.defineProperty(exports, \"__esModule\", { value: true });\r\nvar createLotto_1 = require(\"./createLotto\");\r\nexports.default = createLotto_1.createLotto;\r\n", "import State from \"./State\";\nimport { validateDefinition } from \"./BehaviourTreeDefinitionValidator\";\nimport { convertMDSLToJSON } from \"./mdsl/MDSLDefinitionParser\";\nimport { BehaviourTree, FlattenedTreeNode } from \"./BehaviourTree\";\nimport { BehaviourTreeOptions } from \"./BehaviourTreeOptions\";\n\nexport { BehaviourTree, State, convertMDSLToJSON, validateDefinition };\nexport type { FlattenedTreeNode, BehaviourTreeOptions };\n", "/**\n * Enumeration of node state types.\n */\nexport enum State {\n READY = \"mistreevous.ready\",\n RUNNING = \"mistreevous.running\",\n SUCCEEDED = \"mistreevous.succeeded\",\n FAILED = \"mistreevous.failed\"\n}\n\nexport { State as default };\n\nexport type CompleteState = State.SUCCEEDED | State.FAILED;\nexport type AnyState = State.READY | State.RUNNING | CompleteState;\n", "import {\n NodeDefinition,\n RootNodeDefinition,\n DecoratorNodeDefinition,\n CompositeNodeDefinition,\n AnyNodeDefinition,\n BranchNodeDefinition\n} from \"./BehaviourTreeDefinition\";\n\n/**\n * A type guard function that returns true if the specified node satisfies the RootNodeDefinition type.\n * @param node The node.\n * @returns A value of true if the specified node satisfies the RootNodeDefinition type.\n */\nexport function isRootNode(node: NodeDefinition): node is RootNodeDefinition {\n return node.type === \"root\";\n}\n\n/**\n * A type guard function that returns true if the specified node satisfies the BranchNodeDefinition type.\n * @param node The node.\n * @returns A value of true if the specified node satisfies the BranchNodeDefinition type.\n */\nexport function isBranchNode(node: NodeDefinition): node is BranchNodeDefinition {\n return node.type === \"branch\";\n}\n\n/**\n * A type guard function that returns true if the specified node satisfies the NodeDefinition type.\n * @param node The node.\n * @returns A value of true if the specified node satisfies the NodeDefinition type.\n */\nexport function isLeafNode(node: NodeDefinition): node is NodeDefinition {\n return [\"branch\", \"action\", \"condition\", \"wait\"].includes(node.type);\n}\n\n/**\n * A type guard function that returns true if the specified node satisfies the DecoratorNodeDefinition type.\n * @param node The node.\n * @returns A value of true if the specified node satisfies the DecoratorNodeDefinition type.\n */\nexport function isDecoratorNode(node: NodeDefinition): node is DecoratorNodeDefinition {\n return [\"root\", \"repeat\", \"retry\", \"flip\", \"succeed\", \"fail\"].includes(node.type);\n}\n\n/**\n * A type guard function that returns true if the specified node satisfies the CompositeNodeDefinition type.\n * @param node The node.\n * @returns A value of true if the specified node satisfies the CompositeNodeDefinition type.\n */\nexport function isCompositeNode(node: NodeDefinition): node is CompositeNodeDefinition {\n return [\"sequence\", \"selector\", \"lotto\", \"parallel\"].includes(node.type);\n}\n\n/**\n * Flatten a node definition into an array of all of its nested node definitions.\n * @param nodeDefinition The node definition to flatten.\n * @returns An array of all of nested node definitions.\n */\nexport function flattenDefinition(nodeDefinition: AnyNodeDefinition): AnyNodeDefinition[] {\n const nodes: AnyNodeDefinition[] = [];\n\n const processNode = (currentNodeDefinition: AnyNodeDefinition) => {\n nodes.push(currentNodeDefinition);\n\n if (isCompositeNode(currentNodeDefinition)) {\n currentNodeDefinition.children.forEach(processNode);\n } else if (isDecoratorNode(currentNodeDefinition)) {\n processNode(currentNodeDefinition.child);\n }\n };\n\n processNode(nodeDefinition);\n\n return nodes;\n}\n\n/**\n * Determines whether the passed value is an integer.\n * @param value The value to check.\n * @returns Whether the passed value is an integer.\n */\nexport function isInteger(value: unknown): boolean {\n return typeof value === \"number\" && Math.floor(value) === value;\n}\n\n/**\n * Determines whether the passed value is null or undefined.\n * @param value The value to check.\n * @returns Whether the passed value is null or undefined.\n */\nexport function isNullOrUndefined(value: unknown): boolean {\n return typeof value === \"undefined\" || value === null;\n}\n", "/**\n * A type defining an object that holds a reference to substitued string literals parsed from the definition.\n */\nexport type StringLiteralPlaceholders = { [key: string]: string };\n\n/**\n * Pop the next raw token from the specified array of tokens and throw an error if it wasn't the expected one.\n * @param tokens The array of tokens.\n * @param expected An optional string or array or items, one of which must match the next popped token.\n * @returns The popped token.\n */\nexport function popAndCheck(tokens: string[], expected?: string | string[]): string {\n // Get and remove the next token.\n const popped = tokens.shift();\n\n // We were expecting another token but there aren't any.\n if (popped === undefined) {\n throw new Error(\"unexpected end of definition\");\n }\n\n // Do we have an expected token/tokens array?\n if (expected != undefined) {\n // Get an array of expected values, if the popped token matches any then we are all good.\n const expectedValues = typeof expected === \"string\" ? [expected] : expected;\n\n // Check whether the popped token matches at least one of our expected items.\n var tokenMatchesExpectation = expectedValues.some((item) => popped.toUpperCase() === item.toUpperCase());\n\n // Throw an error if the popped token didn't match any of our expected items.\n if (!tokenMatchesExpectation) {\n const expectationString = expectedValues.map((item) => \"'\" + item + \"'\").join(\" or \");\n throw new Error(\"unexpected token found. Expected \" + expectationString + \" but got '\" + popped + \"'\");\n }\n }\n\n // Return the popped token.\n return popped;\n}\n\n/**\n * Swaps out any node/attribute argument string literals with placeholders.\n * @param definition The definition.\n * @returns An object containing a mapping of placeholders to original string values as well as the processed definition string.\n */\nexport function substituteStringLiterals(definition: string): {\n placeholders: StringLiteralPlaceholders;\n processedDefinition: string;\n} {\n // Create an object to hold the mapping of placeholders to original string values.\n const placeholders: StringLiteralPlaceholders = {};\n\n // Replace any string literals wrapped with double quotes in our definition with placeholders to be processed later.\n const processedDefinition = definition.replace(/\\\"(\\\\.|[^\"\\\\])*\\\"/g, (match) => {\n var strippedMatch = match.substring(1, match.length - 1);\n var placeholder = Object.keys(placeholders).find((key) => placeholders[key] === strippedMatch);\n\n // If we have no existing string literal match then create a new placeholder.\n if (!placeholder) {\n placeholder = `@@${Object.keys(placeholders).length}@@`;\n placeholders[placeholder] = strippedMatch;\n }\n\n return placeholder;\n });\n\n return { placeholders, processedDefinition };\n}\n\n/**\n * Parse the tree definition into an array of raw tokens.\n * @param definition The definition.\n * @returns An array of tokens parsed from the definition.\n */\nexport function parseTokensFromDefinition(definition: string): string[] {\n // Add some space around various important characters so that they can be plucked out easier as individual tokens.\n definition = definition.replace(/\\(/g, \" ( \");\n definition = definition.replace(/\\)/g, \" ) \");\n definition = definition.replace(/\\{/g, \" { \");\n definition = definition.replace(/\\}/g, \" } \");\n definition = definition.replace(/\\]/g, \" ] \");\n definition = definition.replace(/\\[/g, \" [ \");\n definition = definition.replace(/\\,/g, \" , \");\n\n // Split the definition into raw token form and return it.\n return definition.replace(/\\s+/g, \" \").trim().split(\" \");\n}\n", "import { StringLiteralPlaceholders, popAndCheck } from \"./MDSLUtilities\";\n\n/**\n * A type representing any node function argument.\n */\ntype Argument = {\n /**\n * The argument value.\n */\n value: T;\n /**\n * The argument type, used for validation.\n */\n type: string;\n};\n\ntype NullArgument = Argument & {\n type: \"null\";\n};\n\ntype BooleanArgument = Argument & {\n type: \"boolean\";\n};\n\ntype NumberArgument = Argument & {\n type: \"number\";\n /**\n * A flag defining whether the number argument value is a valid integer. (used for validation)\n */\n isInteger: boolean;\n};\n\ntype StringPlaceholderArgument = Argument & {\n type: \"string\";\n};\n\ntype IdentifierArgument = Argument & {\n type: \"identifier\";\n};\n\n/**\n * A type representing a reference to any node function argument.\n */\ntype AnyArgument = NullArgument | BooleanArgument | NumberArgument | StringPlaceholderArgument | IdentifierArgument;\n\n/**\n * Parse an array of argument definitions from the specified tokens array.\n * @param tokens The array tokens to parse the argument definitions from.\n * @param stringArgumentPlaceholders The mapping of string literal node argument placeholders to original values.\n * @param argumentValidator The argument validator function.\n * @param validationFailedMessage The exception message to throw if argument validation fails.\n * @returns An array of argument definitions parsed from the specified tokens array.\n */\nexport function parseArgumentTokens(\n tokens: string[],\n stringArgumentPlaceholders: StringLiteralPlaceholders\n): AnyArgument[] {\n const argumentList: AnyArgument[] = [];\n\n // If the next token is not a '[' or '(' then we have no arguments to parse.\n if (![\"[\", \"(\"].includes(tokens[0])) {\n return argumentList;\n }\n\n // Any lists of arguments will always be wrapped in '[]' for node arguments or '()' for attribute arguments.\n // We are looking for a '[' or '(' opener that wraps the argument tokens and the relevant closer.\n const closingToken = popAndCheck(tokens, [\"[\", \"(\"]) === \"[\" ? \"]\" : \")\";\n\n const argumentListTokens: string[] = [];\n\n // Grab all tokens between the '[' and ']' or '(' and ')'.\n while (tokens.length && tokens[0] !== closingToken) {\n // The next token is part of our arguments list.\n argumentListTokens.push(tokens.shift()!);\n }\n\n // Validate the order of the argument tokens. Each token must either be a ',' or a single argument that satisfies the validator.\n argumentListTokens.forEach((token, index) => {\n // Get whether this token should be an actual argument.\n const shouldBeArgumentToken = !(index & 1);\n\n // If the current token should be an actual argument then validate it, otherwise it should be a ',' token.\n if (shouldBeArgumentToken) {\n // Get the argument definition.\n const argumentDefinition = getArgumentDefinition(token, stringArgumentPlaceholders);\n\n // This is a valid argument!\n argumentList.push(argumentDefinition);\n } else {\n // The current token should be a ',' token.\n if (token !== \",\") {\n throw new Error(`invalid argument list, expected ',' or ']' but got '${token}'`);\n }\n }\n });\n\n // The arguments list should terminate with a ']' or ')' token, depending on the opener.\n popAndCheck(tokens, closingToken);\n\n // Return the arguments.\n return argumentList;\n}\n\n/**\n * Gets an argument value definition.\n * @param token The argument token.\n * @param stringArgumentPlaceholders The mapping of string literal node argument placeholders to original values.\n * @returns An argument value definition.\n */\nfunction getArgumentDefinition(token: string, stringArgumentPlaceholders: StringLiteralPlaceholders): AnyArgument {\n // Check whether the token represents a null value.\n if (token === \"null\") {\n return {\n value: null,\n type: \"null\"\n } as NullArgument;\n }\n\n // Check whether the token represents a boolean value.\n if (token === \"true\" || token === \"false\") {\n return {\n value: token === \"true\",\n type: \"boolean\"\n } as BooleanArgument;\n }\n\n // Check whether the token represents a number value.\n // TODO: Relies on broken isNaN - see MDN.\n // if (!Number.isNaN(token)) {\n if (!isNaN(token as any)) {\n return {\n value: parseFloat(token),\n isInteger: parseFloat(token) === parseInt(token, 10),\n type: \"number\"\n } as NumberArgument;\n }\n\n // Check whether the token is a placeholder (e.g. @@0@@) representing a string literal.\n if (token.match(/^@@\\d+@@$/g)) {\n return {\n value: stringArgumentPlaceholders[token].replace('\\\\\"', '\"'),\n type: \"string\"\n } as StringPlaceholderArgument;\n }\n\n // The only remaining option is that the argument value is an identifier.\n return {\n value: token,\n type: \"identifier\"\n } as IdentifierArgument;\n}\n", "import { NodeAttributeDefinition } from \"../BehaviourTreeDefinition\";\nimport { parseArgumentTokens } from \"./MDSLNodeArgumentParser\";\nimport { StringLiteralPlaceholders } from \"./MDSLUtilities\";\n\n/**\n * A type defining the attribute definitions of a node.\n */\ntype NodeAttributes = {\n while?: NodeAttributeDefinition;\n until?: NodeAttributeDefinition;\n entry?: NodeAttributeDefinition;\n exit?: NodeAttributeDefinition;\n step?: NodeAttributeDefinition;\n};\n\n/**\n * Parse any node attribute definitions from the specified tokens array.\n * @param tokens The array of remaining tokens.\n * @param stringArgumentPlaceholders The mapping of string literal node argument placeholders to original values.\n * @returns An object of attribute definitions defined by any directly following tokens.\n */\nexport function parseAttributeTokens(\n tokens: string[],\n stringArgumentPlaceholders: StringLiteralPlaceholders\n): NodeAttributes {\n const nodeAttributeNames: (keyof NodeAttributes)[] = [\"while\", \"until\", \"entry\", \"exit\", \"step\"];\n\n // Create an object to hold any attributes found.\n const attributes: NodeAttributes = {};\n\n // Try to get the name of the attribute for the next token.\n let nextAttributeName = tokens[0]?.toLowerCase() as keyof NodeAttributes;\n\n // Pull attribute tokens as well as their arguments off of the tokens stack until we have no more.\n while (nodeAttributeNames.includes(nextAttributeName)) {\n // Check to make sure that we have not already created an attribute definition of this type.\n if (attributes[nextAttributeName]) {\n throw new Error(`duplicate attribute '${tokens[0].toUpperCase()}' found for node`);\n }\n\n // Remove the attribute name token from the array of tokens.\n tokens.shift();\n\n // Grab the attribute arguments, assuming the first to be an identifier.\n const [attributeCallIdentifier, ...attributeArguments] = parseArgumentTokens(\n tokens,\n stringArgumentPlaceholders\n );\n\n // The first attribute argument has to be an identifer, this will reference an agent function.\n if (attributeCallIdentifier?.type !== \"identifier\") {\n throw new Error(\"expected agent function or registered function name identifier argument for attribute\");\n }\n\n // Any attribute arguments (other than the expected call identifier) must have a type of string, number, boolean or null.\n attributeArguments\n .filter((arg) => arg.type === \"identifier\")\n .forEach((arg) => {\n throw new Error(\n `invalid attribute argument value '${arg.value}', must be string, number, boolean or null`\n );\n });\n\n // Create the attribute definition and add it to the object of attribute definitions found.\n attributes[nextAttributeName] = {\n call: attributeCallIdentifier.value,\n args: attributeArguments.map(({ value }) => value)\n };\n\n // Try to get the next attribute name token, as there could be multiple.\n nextAttributeName = tokens[0]?.toLowerCase() as keyof NodeAttributes;\n }\n\n return attributes;\n}\n", "import {\n ActionNodeDefinition,\n AnyChildNodeDefinition,\n AnyNodeDefinition,\n BranchNodeDefinition,\n ConditionNodeDefinition,\n FailNodeDefinition,\n FlipNodeDefinition,\n LottoNodeDefinition,\n ParallelNodeDefinition,\n RepeatNodeDefinition,\n RetryNodeDefinition,\n RootNodeDefinition,\n SelectorNodeDefinition,\n SequenceNodeDefinition,\n SucceedNodeDefinition,\n WaitNodeDefinition\n} from \"../BehaviourTreeDefinition\";\nimport {\n isCompositeNode,\n isDecoratorNode,\n isLeafNode,\n isNullOrUndefined,\n isRootNode\n} from \"../BehaviourTreeDefinitionUtilities\";\nimport { parseArgumentTokens } from \"./MDSLNodeArgumentParser\";\nimport { parseAttributeTokens } from \"./MDSLNodeAttributeParser\";\nimport {\n StringLiteralPlaceholders,\n parseTokensFromDefinition,\n popAndCheck,\n substituteStringLiterals\n} from \"./MDSLUtilities\";\n\n/**\n * Convert the MDSL tree definition string into an equivalent JSON definition.\n * @param definition The tree definition string as MDSL.\n * @returns The root node JSON definitions.\n */\nexport function convertMDSLToJSON(definition: string): RootNodeDefinition[] {\n // Swap out any node/attribute argument string literals with a placeholder and get a mapping of placeholders to original values as well as the processed definition.\n const { placeholders, processedDefinition } = substituteStringLiterals(definition);\n\n // Parse our definition definition string into an array of raw tokens.\n const tokens = parseTokensFromDefinition(processedDefinition);\n\n return convertTokensToJSONDefinition(tokens, placeholders);\n}\n\n/**\n * Converts the specified tree definition tokens into a JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The root node JSON definitions.\n */\nfunction convertTokensToJSONDefinition(\n tokens: string[],\n stringLiteralPlaceholders: StringLiteralPlaceholders\n): RootNodeDefinition[] {\n // There must be at least 3 tokens for the tree definition to be valid. 'ROOT', '{' and '}'.\n if (tokens.length < 3) {\n throw new Error(\"invalid token count\");\n }\n\n // We should have a matching number of '{' and '}' tokens. If not, then there are scopes that have not been properly closed.\n if (tokens.filter((token) => token === \"{\").length !== tokens.filter((token) => token === \"}\").length) {\n throw new Error(\"scope character mismatch\");\n }\n\n // Create an array of tree stack arrays where root nodes will always be at the botton and the current composite/decorator node at the top.\n // There should be an element in this array for every root node defined and every element should be an array with a root note as the first element.\n // E.g. A definition with two root nodes defined:\n // [\n // [root, lotto, sequence],\n // [root, selector]\n // ]\n const treeStacks: [Partial, ...Partial[]][] = [];\n\n // Create an array of all root node definitions that we create.\n const rootNodes: Partial[] = [];\n\n // A helper function used to push node definitions onto the tree stack.\n const pushNode = (node: AnyNodeDefinition) => {\n // If the node is a root node then we need to create a new tree stack array with the root node at the root.\n if (isRootNode(node)) {\n // We need to double-check that this root node is not the child of another node.\n // We can do this by checking whether the top tree stack is not empty (contains an existing node)\n if (treeStacks[treeStacks.length - 1]?.length) {\n throw new Error(\"a root node cannot be the child of another node\");\n }\n\n // Add the root node definition to our array of all parsed root node definitions.\n rootNodes.push(node);\n\n // Add the root node definition to the root of a new tree stack.\n treeStacks.push([node]);\n\n return;\n }\n\n // All non-root nodes should be pushed after their root nodes so handle cases\n // where we may not have any tree stacks or our top-most tree stack is empty.\n if (!treeStacks.length || !treeStacks[treeStacks.length - 1].length) {\n throw new Error(\"expected root node at base of definition\");\n }\n\n // Get the current tree stack that we are populating.\n const topTreeStack = treeStacks[treeStacks.length - 1];\n\n // Get the top-most node in the current tree stack, this will be a composite/decorator node\n // for which we will populate its children array if composite or setting its child if a decorator.\n const topTreeStackTopNode = topTreeStack[topTreeStack.length - 1] as AnyNodeDefinition;\n\n // If the top-most node in the current root stack is a composite or decorator\n // node then the current node should be added as a child of the top-most node.\n if (isCompositeNode(topTreeStackTopNode)) {\n topTreeStackTopNode.children = topTreeStackTopNode.children || [];\n topTreeStackTopNode.children.push(node);\n } else if (isDecoratorNode(topTreeStackTopNode)) {\n // If the top node already has a child node set then throw an error as a decorator should only have a single child.\n if (topTreeStackTopNode.child) {\n throw new Error(\"a decorator node must only have a single child node\");\n }\n\n topTreeStackTopNode.child = node;\n }\n\n // If the node we are adding is also a composite or decorator node, then we should push it\n // onto the current tree stack, as subsequent nodes will be added as its child/children.\n if (!isLeafNode(node)) {\n topTreeStack.push(node);\n }\n };\n\n // A helper function used to pop the top-most node definition off of the tree stack and return it.\n const popNode = (): AnyNodeDefinition | null => {\n let poppedNode: AnyNodeDefinition | null = null;\n\n // Get the current tree stack that we are populating.\n const topTreeStack = treeStacks[treeStacks.length - 1];\n\n // Pop the top-most node in the current tree stack if there is one.\n if (topTreeStack.length) {\n poppedNode = topTreeStack.pop() as AnyNodeDefinition;\n }\n\n // We don't want any empty tree stacks in our stack of tree stacks.\n if (!topTreeStack.length) {\n treeStacks.pop();\n }\n\n return poppedNode;\n };\n\n // We should keep processing the raw tokens until we run out of them.\n while (tokens.length) {\n // Grab the next token.\n const token = tokens.shift()!;\n\n // How we create the next node depends on the current raw token value.\n switch (token.toUpperCase()) {\n case \"ROOT\": {\n pushNode(createRootNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"SUCCEED\": {\n pushNode(createSucceedNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"FAIL\": {\n pushNode(createFailNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"FLIP\": {\n pushNode(createFlipNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"REPEAT\": {\n pushNode(createRepeatNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"RETRY\": {\n pushNode(createRetryNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"SEQUENCE\": {\n pushNode(createSequenceNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"SELECTOR\": {\n pushNode(createSelectorNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"PARALLEL\": {\n pushNode(createParallelNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"LOTTO\": {\n pushNode(createLottoNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"ACTION\": {\n pushNode(createActionNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"CONDITION\": {\n pushNode(createConditionNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"WAIT\": {\n pushNode(createWaitNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"BRANCH\": {\n pushNode(createBranchNode(tokens, stringLiteralPlaceholders));\n break;\n }\n\n case \"}\": {\n // The '}' character closes the current scope and means that we have to pop a node off of the current stack.\n const poppedNode = popNode();\n\n // Now that we have a node definition we can carry out any validation that may require the node to be fully populated.\n if (poppedNode) {\n validatePoppedNode(poppedNode);\n }\n\n break;\n }\n\n default: {\n throw new Error(`unexpected token: ${token}`);\n }\n }\n }\n\n return rootNodes as RootNodeDefinition[];\n}\n\n/**\n * Creates a root node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The root node JSON definition.\n */\nfunction createRootNode(tokens: string[], stringLiteralPlaceholders: StringLiteralPlaceholders): RootNodeDefinition {\n // Create the root node definition.\n let node = {\n type: \"root\"\n } as Partial;\n\n // Parse any node arguments, we should only have one if any which will be an identifier argument for the root identifier.\n const nodeArguments = parseArgumentTokens(tokens, stringLiteralPlaceholders);\n\n // Check whether any node arguments were defined.\n if (nodeArguments.length) {\n // We should only have one argument, if any, which will be an identifier argument for the root identifier.\n if (nodeArguments.length === 1 && nodeArguments[0].type === \"identifier\") {\n // The root node identifier will be the first and only node argument value.\n node.id = nodeArguments[0].value as string;\n } else {\n throw new Error(\"expected single root name argument\");\n }\n }\n\n // Grab any node attribute definitions and spread them into the node definition.\n node = { ...node, ...parseAttributeTokens(tokens, stringLiteralPlaceholders) };\n\n // This is a decorator node, so we expect an opening '{'.\n popAndCheck(tokens, \"{\");\n\n // Return the root node definition.\n return node as RootNodeDefinition;\n}\n\n/**\n * Creates a succeed node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The succeed node JSON definition.\n */\nfunction createSucceedNode(\n tokens: string[],\n stringLiteralPlaceholders: StringLiteralPlaceholders\n): SucceedNodeDefinition {\n const node = {\n type: \"succeed\",\n ...parseAttributeTokens(tokens, stringLiteralPlaceholders)\n } as SucceedNodeDefinition;\n\n // This is a decorator node, so we expect an opening '{'.\n popAndCheck(tokens, \"{\");\n\n // Return the succeed node definition.\n return node;\n}\n\n/**\n * Creates a fail node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The fail node JSON definition.\n */\nfunction createFailNode(tokens: string[], stringLiteralPlaceholders: StringLiteralPlaceholders): FailNodeDefinition {\n const node = {\n type: \"fail\",\n ...parseAttributeTokens(tokens, stringLiteralPlaceholders)\n } as FailNodeDefinition;\n\n // This is a decorator node, so we expect an opening '{'.\n popAndCheck(tokens, \"{\");\n\n // Return the fail node definition.\n return node;\n}\n\n/**\n * Creates a flip node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The flip node JSON definition.\n */\nfunction createFlipNode(tokens: string[], stringLiteralPlaceholders: StringLiteralPlaceholders): FlipNodeDefinition {\n const node = {\n type: \"flip\",\n ...parseAttributeTokens(tokens, stringLiteralPlaceholders)\n } as FlipNodeDefinition;\n\n // This is a decorator node, so we expect an opening '{'.\n popAndCheck(tokens, \"{\");\n\n // Return the flip node definition.\n return node;\n}\n\n/**\n * Creates a repeat node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The repeat node JSON definition.\n */\nfunction createRepeatNode(\n tokens: string[],\n stringLiteralPlaceholders: StringLiteralPlaceholders\n): RepeatNodeDefinition {\n let node = { type: \"repeat\" } as RepeatNodeDefinition;\n\n // Get the node arguments.\n const nodeArguments = parseArgumentTokens(tokens, stringLiteralPlaceholders);\n\n // The arguments of a repeat node are optional. We may have:\n // - No node arguments, in which case the repeat note will iterate indefinitely.\n // - One node argument which will be the explicit number of iterations to make.\n // - Two node arguments which define the min and max iteration bounds from which a random iteration count will be picked.\n if (nodeArguments.length) {\n // All repeat node arguments MUST be of type number and must be integer.\n nodeArguments\n .filter((arg) => arg.type !== \"number\" || !arg.isInteger)\n .forEach(() => {\n throw new Error(`repeat node iteration counts must be integer values`);\n });\n\n // We should have got one or two iteration counts.\n if (nodeArguments.length === 1) {\n // A static iteration count was defined.\n node.iterations = nodeArguments[0].value as number;\n\n // A repeat node must have a positive number of iterations if defined.\n if (node.iterations < 0) {\n throw new Error(\"a repeat node must have a positive number of iterations if defined\");\n }\n } else if (nodeArguments.length === 2) {\n // A minimum and maximum iteration count was defined.\n node.iterations = [nodeArguments[0].value as number, nodeArguments[1].value as number];\n\n // A repeat node must have a positive min and max iteration count if they are defined.\n if (node.iterations[0] < 0 || node.iterations[1] < 0) {\n throw new Error(\"a repeat node must have a positive minimum and maximum iteration count if defined\");\n }\n\n // A repeat node must not have an minimum iteration count that exceeds the maximum iteration count.\n if (node.iterations[0] > node.iterations[1]) {\n throw new Error(\n \"a repeat node must not have a minimum iteration count that exceeds the maximum iteration count\"\n );\n }\n } else {\n // An incorrect number of iteration counts was defined.\n throw new Error(\"invalid number of repeat node iteration count arguments defined\");\n }\n }\n\n // Grab any node attribute definitions and spread them into the node definition.\n node = { ...node, ...parseAttributeTokens(tokens, stringLiteralPlaceholders) };\n\n // This is a decorator node, so we expect an opening '{'.\n popAndCheck(tokens, \"{\");\n\n // Return the repeat node definition.\n return node;\n}\n\n/**\n * Creates a retry node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The retry node JSON definition.\n */\nfunction createRetryNode(tokens: string[], stringLiteralPlaceholders: StringLiteralPlaceholders): RetryNodeDefinition {\n let node = { type: \"retry\" } as RetryNodeDefinition;\n\n // Get the node arguments.\n const nodeArguments = parseArgumentTokens(tokens, stringLiteralPlaceholders);\n\n // The arguments of a retry node are optional. We may have:\n // - No node arguments, in which case the retry note will attempt indefinitely.\n // - One node argument which will be the explicit number of attempts to make.\n // - Two node arguments which define the min and max attempt bounds from which a random attempt count will be picked.\n if (nodeArguments.length) {\n // All retry node arguments MUST be of type number and must be integer.\n nodeArguments\n .filter((arg) => arg.type !== \"number\" || !arg.isInteger)\n .forEach(() => {\n throw new Error(`retry node attempt counts must be integer values`);\n });\n\n // We should have got one or two attempt counts.\n if (nodeArguments.length === 1) {\n // A static attempt count was defined.\n node.attempts = nodeArguments[0].value as number;\n\n // A retry node must have a positive number of attempts if defined.\n if (node.attempts < 0) {\n throw new Error(\"a retry node must have a positive number of attempts if defined\");\n }\n } else if (nodeArguments.length === 2) {\n // A minimum and maximum attempt count was defined.\n node.attempts = [nodeArguments[0].value as number, nodeArguments[1].value as number];\n\n // A retry node must have a positive min and max attempts count if they are defined.\n if (node.attempts[0] < 0 || node.attempts[1] < 0) {\n throw new Error(\"a retry node must have a positive minimum and maximum attempt count if defined\");\n }\n\n // A retry node must not have a minimum attempt count that exceeds the maximum attempt count.\n if (node.attempts[0] > node.attempts[1]) {\n throw new Error(\n \"a retry node must not have a minimum attempt count that exceeds the maximum attempt count\"\n );\n }\n } else {\n // An incorrect number of attempt counts was defined.\n throw new Error(\"invalid number of retry node attempt count arguments defined\");\n }\n }\n\n // Grab any node attribute definitions and spread them into the node definition.\n node = { ...node, ...parseAttributeTokens(tokens, stringLiteralPlaceholders) };\n\n // This is a decorator node, so we expect an opening '{'.\n popAndCheck(tokens, \"{\");\n\n // Return the retry node definition.\n return node;\n}\n\n/**\n * Creates a sequence node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The sequence node JSON definition.\n */\nfunction createSequenceNode(\n tokens: string[],\n stringLiteralPlaceholders: StringLiteralPlaceholders\n): SequenceNodeDefinition {\n const node = {\n type: \"sequence\",\n ...parseAttributeTokens(tokens, stringLiteralPlaceholders)\n } as SequenceNodeDefinition;\n\n // This is a composite node, so we expect an opening '{'.\n popAndCheck(tokens, \"{\");\n\n // Return the sequence node definition.\n return node;\n}\n\n/**\n * Creates a selector node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The selector node JSON definition.\n */\nfunction createSelectorNode(\n tokens: string[],\n stringLiteralPlaceholders: StringLiteralPlaceholders\n): SelectorNodeDefinition {\n const node = {\n type: \"selector\",\n ...parseAttributeTokens(tokens, stringLiteralPlaceholders)\n } as SelectorNodeDefinition;\n\n // This is a composite node, so we expect an opening '{'.\n popAndCheck(tokens, \"{\");\n\n // Return the selector node definition.\n return node;\n}\n\n/**\n * Creates a parallel node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The parallel node JSON definition.\n */\nfunction createParallelNode(\n tokens: string[],\n stringLiteralPlaceholders: StringLiteralPlaceholders\n): ParallelNodeDefinition {\n const node = {\n type: \"parallel\",\n ...parseAttributeTokens(tokens, stringLiteralPlaceholders)\n } as ParallelNodeDefinition;\n\n // This is a composite node, so we expect an opening '{'.\n popAndCheck(tokens, \"{\");\n\n // Return the parallel node definition.\n return node;\n}\n\n/**\n * Creates a lotto node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The lotto node JSON definition.\n */\nfunction createLottoNode(tokens: string[], stringLiteralPlaceholders: StringLiteralPlaceholders): LottoNodeDefinition {\n // If any node arguments have been defined then they must be our weights.\n const nodeArguments = parseArgumentTokens(tokens, stringLiteralPlaceholders);\n\n // All lotto node arguments MUST be of type number and must be positive integers.\n nodeArguments\n .filter((arg) => arg.type !== \"number\" || !arg.isInteger || arg.value < 0)\n .forEach(() => {\n throw new Error(`lotto node weight arguments must be positive integer values`);\n });\n\n const node = {\n type: \"lotto\",\n ...parseAttributeTokens(tokens, stringLiteralPlaceholders)\n } as LottoNodeDefinition;\n\n // Apply the weights if any were defined.\n if (nodeArguments.length) {\n node.weights = nodeArguments.map(({ value }) => value) as number[];\n }\n\n // This is a composite node, so we expect an opening '{'.\n popAndCheck(tokens, \"{\");\n\n // Return the lotto node definition.\n return node;\n}\n\n/**\n * Creates an action node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The action node JSON definition.\n */\nfunction createActionNode(\n tokens: string[],\n stringLiteralPlaceholders: StringLiteralPlaceholders\n): ActionNodeDefinition {\n // Parse any node arguments, we should have at least one which will be an identifier argument for the action name\n // and agent function to invoke for the action, all other arguments are to be passed as arguments to that function.\n const [actionNameIdentifier, ...agentFunctionArgs] = parseArgumentTokens(tokens, stringLiteralPlaceholders);\n\n // Our first argument MUST be defined and be an identifier as we require an action name argument.\n if (actionNameIdentifier?.type !== \"identifier\") {\n throw new Error(\"expected action name identifier argument\");\n }\n\n // Only the first argument should have been an identifier, all agent function arguments must be string, number, boolean or null.\n agentFunctionArgs\n .filter((arg) => arg.type === \"identifier\")\n .forEach((arg) => {\n throw new Error(\n `invalid action node argument value '${arg.value}', must be string, number, boolean or null`\n );\n });\n\n // Return the action node definition.\n return {\n type: \"action\",\n call: actionNameIdentifier.value,\n args: agentFunctionArgs.map(({ value }) => value),\n ...parseAttributeTokens(tokens, stringLiteralPlaceholders)\n };\n}\n\n/**\n * Creates a condition node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The condition node JSON definition.\n */\nfunction createConditionNode(\n tokens: string[],\n stringLiteralPlaceholders: StringLiteralPlaceholders\n): ConditionNodeDefinition {\n // Parse any node arguments, we should have at least one which will be an identifier argument for the condition name\n // and agent function to invoke for the condition, all other arguments are to be passed as arguments to that function.\n const [conditionNameIdentifier, ...agentFunctionArgs] = parseArgumentTokens(tokens, stringLiteralPlaceholders);\n\n // Our first argument MUST be defined and be an identifier as we require a condition name argument.\n if (conditionNameIdentifier?.type !== \"identifier\") {\n throw new Error(\"expected condition name identifier argument\");\n }\n\n // Only the first argument should have been an identifier, all agent function arguments must be string, number, boolean or null.\n agentFunctionArgs\n .filter((arg) => arg.type === \"identifier\")\n .forEach((arg) => {\n throw new Error(\n `invalid condition node argument value '${arg.value}', must be string, number, boolean or null`\n );\n });\n\n // Return the condition node definition.\n return {\n type: \"condition\",\n call: conditionNameIdentifier.value,\n args: agentFunctionArgs.map(({ value }) => value),\n ...parseAttributeTokens(tokens, stringLiteralPlaceholders)\n };\n}\n\n/**\n * Creates a wait node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The wait node JSON definition.\n */\nfunction createWaitNode(tokens: string[], stringLiteralPlaceholders: StringLiteralPlaceholders): WaitNodeDefinition {\n let node = { type: \"wait\" } as WaitNodeDefinition;\n\n // Get the node arguments.\n const nodeArguments = parseArgumentTokens(tokens, stringLiteralPlaceholders);\n\n // The arguments of a wait node are optional. We may have:\n // - No node arguments, in which case the wait will be indefinite until it is aborted.\n // - One node argument which will be the explicit duration of the wait.\n // - Two node arguments which define the min and max duration bounds from which a random duration will be picked.\n if (nodeArguments.length) {\n // All wait node arguments MUST be of type number and must be integer.\n nodeArguments\n .filter((arg) => arg.type !== \"number\" || !arg.isInteger)\n .forEach(() => {\n throw new Error(`wait node durations must be integer values`);\n });\n\n // We may have:\n // - One node argument which will be the explicit duration of the wait.\n // - Two node arguments which define the min and max duration bounds from which a random duration will be picked.\n // - Too many arguments, which is not valid.\n if (nodeArguments.length === 1) {\n // An explicit duration was defined.\n node.duration = nodeArguments[0].value as number;\n\n // If an explict duration was defined then it must be a positive number.\n if (node.duration < 0) {\n throw new Error(\"a wait node must have a positive duration\");\n }\n } else if (nodeArguments.length === 2) {\n // Min and max duration bounds were defined from which a random duration will be picked.\n node.duration = [nodeArguments[0].value as number, nodeArguments[1].value as number];\n\n // A wait node must have a positive min and max duration.\n if (node.duration[0] < 0 || node.duration[1] < 0) {\n throw new Error(\"a wait node must have a positive minimum and maximum duration\");\n }\n\n // A wait node must not have a minimum duration that exceeds the maximum duration.\n if (node.duration[0] > node.duration[1]) {\n throw new Error(\"a wait node must not have a minimum duration that exceeds the maximum duration\");\n }\n } else if (nodeArguments.length > 2) {\n // An incorrect number of duration arguments were defined.\n throw new Error(\"invalid number of wait node duration arguments defined\");\n }\n }\n\n // Return the wait node definition.\n return { ...node, ...parseAttributeTokens(tokens, stringLiteralPlaceholders) };\n}\n\n/**\n * Creates a branch node JSON definition.\n * @param tokens The tree definition tokens.\n * @param stringLiteralPlaceholders The substituted string literal placeholders.\n * @returns The branch node JSON definition.\n */\nfunction createBranchNode(\n tokens: string[],\n stringLiteralPlaceholders: StringLiteralPlaceholders\n): BranchNodeDefinition {\n // Parse any node arguments, we should have one which will be an identifier argument for the root ref.\n const nodeArguments = parseArgumentTokens(tokens, stringLiteralPlaceholders);\n\n // We should have only a single identifer argument for a branch node, which is the root ref.\n if (nodeArguments.length !== 1 || nodeArguments[0].type !== \"identifier\") {\n throw new Error(\"expected single branch name argument\");\n }\n\n // Return the branch node definition.\n return { type: \"branch\", ref: nodeArguments[0].value };\n}\n\n/**\n * Validate a fully-populated node definition that was popped off of the tree stack.\n * @param definition The popped node to validate.\n */\nfunction validatePoppedNode(definition: AnyNodeDefinition): void {\n // Decorators MUST have a child defined.\n if (isDecoratorNode(definition) && isNullOrUndefined(definition.child)) {\n throw new Error(`a ${definition.type} node must have a single child node defined`);\n }\n\n // Composites MUST have at least one child defined.\n if (isCompositeNode(definition) && !definition.children?.length) {\n throw new Error(`a ${definition.type} node must have at least a single child node defined`);\n }\n\n // We need to make sure that lotto nodes that have weights defined have a number of weights matching the number of child nodes.\n if (definition.type === \"lotto\") {\n // Check whether a 'weights' property has been defined, if it has we expect it to be an array of weights.\n if (typeof definition.weights !== \"undefined\") {\n // Check that the weights property is an array of positive integers with an element for each child node element.\n if (definition.weights.length !== definition.children.length) {\n throw new Error(\n \"expected a number of weight arguments matching the number of child nodes for lotto node\"\n );\n }\n }\n }\n}\n", "import { RootNodeDefinition } from \"./BehaviourTreeDefinition\";\nimport { flattenDefinition, isBranchNode, isInteger } from \"./BehaviourTreeDefinitionUtilities\";\nimport { convertMDSLToJSON } from \"./mdsl/MDSLDefinitionParser\";\n\n/**\n * An object representing the result of validating a tree definition.\n */\nexport type DefinitionValidationResult = {\n /**\n * A flag defining whether validation succeeded.\n */\n succeeded: boolean;\n /**\n * A string containing the error message if validation did not succeed.\n */\n errorMessage?: string;\n /**\n * The definition as json if the validation was successful, or undefined if validation did not succeed.\n */\n json?: RootNodeDefinition[];\n};\n\n/**\n * Validates the specified behaviour tree definition in the form of JSON or MDSL, not taking any globally registered subtrees into consideration.\n * @param definition The behaviour tree definition in the form of JSON or MDSL.\n * @returns An object representing the result of validating the given tree definition.\n */\nexport function validateDefinition(definition: any): DefinitionValidationResult {\n // The definition must be defined.\n if (definition === null || typeof definition === \"undefined\") {\n return createValidationFailureResult(\"definition is null or undefined\");\n }\n\n // We are expecting a definition in one of three different forms:\n // - A string which we will assume is MDSL and we will parse this to JSON before validation.\n // - An array which we will assume is an array of root node definitions with at least one being the primary root node (no 'id' property)\n // - An object which we will assume is the primary root node and should not have an 'id' property.\n if (typeof definition === \"string\") {\n // The definition is a string which we can assume is MDSL, so attempt to validate it.\n return validateMDSLDefinition(definition);\n } else if (typeof definition === \"object\") {\n // The definition will either be an array (of root node definitions) or an object (the single primary root node definition).\n return validateJSONDefinition(definition);\n } else {\n return createValidationFailureResult(`unexpected definition type of '${typeof definition}'`);\n }\n}\n\n/**\n * Validates the specified behaviour tree definition in the form of MDSL.\n * @param definition The behaviour tree definition in the form of MDSL.\n * @returns An object representing the result of validating the given tree definition.\n */\nfunction validateMDSLDefinition(definition: string): DefinitionValidationResult {\n let rootNodeDefinitions;\n\n // The first thing the we need to do is to attempt to convert our MDSL into JSON.\n try {\n // The definition is a string which we can assume is MDSL, so attempt to parse it to a JSON definition in the form of an array of root node definitions.\n rootNodeDefinitions = convertMDSLToJSON(definition);\n } catch (exception) {\n // We failed to parse the JSON from the MDSL, this is likely to be the result of it not being a valid MDSL string.\n return createValidationFailureResult((exception as Error).message);\n }\n\n // Unpack all of the root node definitions into arrays of main ('id' defined) and sub ('id' not defined) root node definitions.\n const mainRootNodeDefinitions = rootNodeDefinitions.filter(({ id }) => typeof id === \"undefined\");\n const subRootNodeDefinitions = rootNodeDefinitions.filter(({ id }) => typeof id === \"string\" && id.length > 0);\n\n // We should ALWAYS have exactly one root node definition without an 'id' property defined, which is out main root node definition.\n if (mainRootNodeDefinitions.length !== 1) {\n return createValidationFailureResult(\n \"expected single unnamed root node at base of definition to act as main root\"\n );\n }\n\n // We should never have duplicate 'id' properties across our sub root node definitions.\n const subRootNodeIdenitifers: string[] = [];\n for (const { id } of subRootNodeDefinitions) {\n // Have we already come across this 'id' property value?\n if (subRootNodeIdenitifers.includes(id!)) {\n return createValidationFailureResult(`multiple root nodes found with duplicate name '${id}'`);\n }\n\n subRootNodeIdenitifers.push(id!);\n }\n\n try {\n // Validate our branch -> subtree links and check for any circular dependencies, we don't care about checking for broken subtree links here.\n validateBranchSubtreeLinks(rootNodeDefinitions, false);\n } catch (exception) {\n return createValidationFailureResult((exception as Error).message);\n }\n\n // Our definition was valid!\n return {\n succeeded: true,\n json: rootNodeDefinitions\n };\n}\n\n/**\n * Validates the specified behaviour tree definition in the form of JSON.\n * @param definition The behaviour tree definition in the form of JSON.\n * @returns An object representing the result of validating the given tree definition.\n */\nexport function validateJSONDefinition(\n definition: RootNodeDefinition | RootNodeDefinition[]\n): DefinitionValidationResult {\n // The definition will either be an array (of root node definitions) or an object (the single primary root node definition).\n const rootNodeDefinitions = Array.isArray(definition) ? definition : [definition];\n\n // Iterate over our array of root nodes and call validateNode for each, passing an initial depth of 0, wrapped in a try catch to handle validation failures.\n try {\n rootNodeDefinitions.forEach((rootNodeDefinition) => validateNode(rootNodeDefinition, 0));\n } catch (error) {\n // Handle cases where we have caught a thrown Error and return a failure result with the error message.\n if (error instanceof Error) {\n return createValidationFailureResult(error.message);\n }\n\n // No idea what happened here!\n return createValidationFailureResult(`unexpected error: ${error}`);\n }\n\n // Unpack all of the root node definitions into arrays of main ('id' defined) and sub ('id' not defined) root node definitions.\n const mainRootNodeDefinitions = rootNodeDefinitions.filter(({ id }) => typeof id === \"undefined\");\n const subRootNodeDefinitions = rootNodeDefinitions.filter(({ id }) => typeof id === \"string\" && id.length > 0);\n\n // We should ALWAYS have exactly one root node definition without an 'id' property defined, which is out main root node definition.\n if (mainRootNodeDefinitions.length !== 1) {\n return createValidationFailureResult(\n \"expected single root node without 'id' property defined to act as main root\"\n );\n }\n\n // We should never have duplicate 'id' properties across our sub root node definitions.\n const subRootNodeIdenitifers: string[] = [];\n for (const { id } of subRootNodeDefinitions) {\n // Have we already come across this 'id' property value?\n if (subRootNodeIdenitifers.includes(id!)) {\n return createValidationFailureResult(\n `multiple root nodes found with duplicate 'id' property value of '${id}'`\n );\n }\n\n subRootNodeIdenitifers.push(id!);\n }\n\n try {\n // Validate our branch -> subtree links and check for any circular dependencies, we don't care about checking for broken subtree links here.\n validateBranchSubtreeLinks(rootNodeDefinitions, false);\n } catch (exception) {\n return createValidationFailureResult((exception as Error).message);\n }\n\n // Our definition was valid!\n return {\n succeeded: true,\n json: rootNodeDefinitions\n };\n}\n\n/**\n * Validates the branch -> subtree links across all provided root node definitions.\n * This will not consider branch nodes that reference any globally registered subtrees unless includesGlobalSubtrees\n * is set to true, in which case we will also verify that there are no broken branch -> subtree links.\n * @param rootNodeDefinitions The array of root node definitions.\n * @param includesGlobalSubtrees A flag defining whether the array includes all global subtree root node definitions.\n */\nexport function validateBranchSubtreeLinks(rootNodeDefinitions: RootNodeDefinition[], includesGlobalSubtrees: boolean) {\n // Create a mapping of root node identifiers to other root nodes that they reference via branch nodes.\n // Below is an example of a mapping that includes a circular dependency (root => a => b => c => a)\n // [{ refs: [\"a\", \"b\"] }, { id: \"a\", refs: [\"b\"] }, { id: \"b\", refs: [\"c\"] }, { id: \"c\", refs: [\"a\"] }]\n const rootNodeMappings: { id: string | undefined; refs: string[] }[] = rootNodeDefinitions.map(\n (rootNodeDefinition) => ({\n id: rootNodeDefinition.id,\n refs: flattenDefinition(rootNodeDefinition)\n .filter(isBranchNode)\n .map(({ ref }) => ref)\n })\n );\n\n // A recursive function to walk through the mappings, keeping track of which root nodes we have visited in the form of a path of root node identifiers.\n const followRefs = (mapping: { id: string | undefined; refs: string[] }, path: (string | undefined)[] = []) => {\n // Have we found a circular dependency?\n if (path.includes(mapping.id)) {\n // We found a circular dependency! Get the bad path of root node identifiers.\n const badPath = [...path, mapping.id];\n\n // Create the formatted path value. [undefined, \"a\", \"b\", \"c\", \"a\"] would be formatted as \"a -> b -> c -> a\".\n const badPathFormatted = badPath.filter((element) => !!element).join(\" => \");\n\n // No need to continue, we found a circular dependency.\n throw new Error(`circular dependency found in branch node references: ${badPathFormatted}`);\n }\n\n for (const ref of mapping.refs) {\n // Find the mapping for the root node with an identifer matching the current ref.\n const subMapping = rootNodeMappings.find(({ id }) => id === ref);\n\n // We may not have a mapping for this ref, which is normal when we aren't considering all globally registered subtrees.\n if (subMapping) {\n followRefs(subMapping, [...path, mapping.id]);\n } else if (includesGlobalSubtrees) {\n // We found a reference to a root node that doesn't exist, which is a problem seeing as the root node definitons includes all globally registered subtrees.\n throw new Error(\n mapping.id\n ? `subtree '${mapping.id}' has branch node that references root node '${ref}' which has not been defined`\n : `primary tree has branch node that references root node '${ref}' which has not been defined`\n );\n }\n }\n };\n\n // Start looking for circular dependencies and broken references from the primary root node definition.\n followRefs(rootNodeMappings.find((mapping) => typeof mapping.id === \"undefined\")!);\n}\n\n/**\n * Validate an object that we expect to be a node definition.\n * @param definition An object that we expect to be a node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateNode(definition: any, depth: number): void {\n // Every node must be valid object and have a non-empty 'type' string property.\n if (typeof definition !== \"object\" || typeof definition.type !== \"string\" || definition.type.length === 0) {\n throw new Error(\n `node definition is not an object or 'type' property is not a non-empty string at depth '${depth}'`\n );\n }\n\n // If this node is at the very base of the definition then it MUST be a root node.\n if (depth === 0 && definition.type !== \"root\") {\n throw new Error(`expected root node at base of definition but got node of type '${definition.type}'`);\n }\n\n // How we validate this node definition will depend on its type.\n switch (definition.type) {\n case \"action\":\n validateActionNode(definition, depth);\n break;\n\n case \"condition\":\n validateConditionNode(definition, depth);\n break;\n\n case \"wait\":\n validateWaitNode(definition, depth);\n break;\n\n case \"branch\":\n validateBranchNode(definition, depth);\n break;\n\n case \"root\":\n validateRootNode(definition, depth);\n break;\n\n case \"succeed\":\n validateSucceedNode(definition, depth);\n break;\n\n case \"fail\":\n validateFailNode(definition, depth);\n break;\n\n case \"flip\":\n validateFlipNode(definition, depth);\n break;\n\n case \"repeat\":\n validateRepeatNode(definition, depth);\n break;\n\n case \"retry\":\n validateRetryNode(definition, depth);\n break;\n\n case \"sequence\":\n validateSequenceNode(definition, depth);\n break;\n\n case \"selector\":\n validateSelectorNode(definition, depth);\n break;\n\n case \"parallel\":\n validateParallelNode(definition, depth);\n break;\n\n case \"lotto\":\n validateLottoNode(definition, depth);\n break;\n\n default:\n throw new Error(`unexpected node type of '${definition.type}' at depth '${depth}'`);\n }\n}\n\n/**\n * Validate any attributes for a given node definition.\n * @param definition The node definition.\n * @param depth The depth of the node in the behaviour tree definition.\n */\nfunction validateNodeAttributes(definition: any, depth: number): void {\n // Validate each of the attribute types for this node.\n [\"while\", \"until\", \"entry\", \"exit\", \"step\"].forEach((attributeName) => {\n // Attempt to grab the definition for the current attribute from the node definition.\n const attributeDefinition = definition[attributeName];\n\n // All node attributes are optional, so there is nothing to do if the current attribute is not defined.\n if (typeof attributeDefinition === \"undefined\") {\n return;\n }\n\n // The attribute definition must be an object.\n if (typeof attributeDefinition !== \"object\") {\n throw new Error(\n `expected attribute '${attributeName}' to be an object for '${definition.type}' node at depth '${depth}'`\n );\n }\n\n // The 'call' property must be defined for any attribute definition.\n if (typeof attributeDefinition.call !== \"string\" || attributeDefinition.call.length === 0) {\n throw new Error(\n `expected 'call' property for attribute '${attributeName}' to be a non-empty string for '${definition.type}' node at depth '${depth}'`\n );\n }\n\n // If any node attribute arguments have been defined then they must have been defined in an array.\n if (typeof attributeDefinition.args !== \"undefined\" && !Array.isArray(attributeDefinition.args)) {\n throw new Error(\n `expected 'args' property for attribute '${attributeName}' to be an array for '${definition.type}' node at depth '${depth}'`\n );\n }\n });\n}\n\n/**\n * Validate an object that we expect to be a root node definition.\n * @param definition An object that we expect to be a root node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateRootNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"root\") {\n throw new Error(\"expected node type of 'root' for root node\");\n }\n\n // A root node cannot be the child of another node.\n if (depth > 0) {\n throw new Error(\"a root node cannot be the child of another node\");\n }\n\n // Check that, if the root node 'id' property is defined, it is a non-empty string.\n if (typeof definition.id !== \"undefined\" && (typeof definition.id !== \"string\" || definition.id.length === 0)) {\n throw new Error(\"expected non-empty string for 'id' property if defined for root node\");\n }\n\n // A root node is a decorator node, so must have a child node defined.\n if (typeof definition.child === \"undefined\") {\n throw new Error(\"expected property 'child' to be defined for root node\");\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n\n // Validate the child node of this decorator node.\n validateNode(definition.child, depth + 1);\n}\n\n/**\n * Validate an object that we expect to be a succeed node definition.\n * @param definition An object that we expect to be a succeed node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateSucceedNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"succeed\") {\n throw new Error(`expected node type of 'succeed' for succeed node at depth '${depth}'`);\n }\n\n // A succeed node is a decorator node, so must have a child node defined.\n if (typeof definition.child === \"undefined\") {\n throw new Error(`expected property 'child' to be defined for succeed node at depth '${depth}'`);\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n\n // Validate the child node of this decorator node.\n validateNode(definition.child, depth + 1);\n}\n\n/**\n * Validate an object that we expect to be a fail node definition.\n * @param definition An object that we expect to be a fail node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateFailNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"fail\") {\n throw new Error(`expected node type of 'fail' for fail node at depth '${depth}'`);\n }\n\n // A fail node is a decorator node, so must have a child node defined.\n if (typeof definition.child === \"undefined\") {\n throw new Error(`expected property 'child' to be defined for fail node at depth '${depth}'`);\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n\n // Validate the child node of this decorator node.\n validateNode(definition.child, depth + 1);\n}\n\n/**\n * Validate an object that we expect to be a flip node definition.\n * @param definition An object that we expect to be a flip node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateFlipNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"flip\") {\n throw new Error(`expected node type of 'flip' for flip node at depth '${depth}'`);\n }\n\n // A flip node is a decorator node, so must have a child node defined.\n if (typeof definition.child === \"undefined\") {\n throw new Error(`expected property 'child' to be defined for flip node at depth '${depth}'`);\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n\n // Validate the child node of this decorator node.\n validateNode(definition.child, depth + 1);\n}\n\n/**\n * Validate an object that we expect to be a repeat node definition.\n * @param definition An object that we expect to be a repeat node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateRepeatNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"repeat\") {\n throw new Error(`expected node type of 'repeat' for repeat node at depth '${depth}'`);\n }\n\n // A repeat node is a decorator node, so must have a child node defined.\n if (typeof definition.child === \"undefined\") {\n throw new Error(`expected property 'child' to be defined for repeat node at depth '${depth}'`);\n }\n\n // Check whether an 'iterations' property has been defined, it may not have been if this node is to repeat indefinitely.\n if (typeof definition.iterations !== \"undefined\") {\n if (Array.isArray(definition.iterations)) {\n // Check whether any elements of the array are not integer values.\n const containsNonInteger = !!definition.iterations.filter((value: unknown) => !isInteger(value)).length;\n\n // If the 'iterations' property is an array then it MUST contain two integer values.\n if (definition.iterations.length !== 2 || containsNonInteger) {\n throw new Error(\n `expected array containing two integer values for 'iterations' property if defined for repeat node at depth '${depth}'`\n );\n }\n\n // A repeat node must have a positive min and max iterations count if they are defined.\n if (definition.iterations[0] < 0 || definition.iterations[1] < 0) {\n throw new Error(\n `expected positive minimum and maximum iterations count for 'iterations' property if defined for repeat node at depth '${depth}'`\n );\n }\n\n // A repeat node must not have a minimum iterations count that exceeds the maximum iterations count.\n if (definition.iterations[0] > definition.iterations[1]) {\n throw new Error(\n `expected minimum iterations count that does not exceed the maximum iterations count for 'iterations' property if defined for repeat node at depth '${depth}'`\n );\n }\n } else if (isInteger(definition.iterations)) {\n // A repeat node must have a positive number of iterations if defined.\n if (definition.iterations < 0) {\n throw new Error(\n `expected positive iterations count for 'iterations' property if defined for repeat node at depth '${depth}'`\n );\n }\n } else {\n throw new Error(\n `expected integer value or array containing two integer values for 'iterations' property if defined for repeat node at depth '${depth}'`\n );\n }\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n\n // Validate the child node of this decorator node.\n validateNode(definition.child, depth + 1);\n}\n\n/**\n * Validate an object that we expect to be a retry node definition.\n * @param definition An object that we expect to be a retry node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateRetryNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"retry\") {\n throw new Error(`expected node type of 'retry' for retry node at depth '${depth}'`);\n }\n\n // A retry node is a decorator node, so must have a child node defined.\n if (typeof definition.child === \"undefined\") {\n throw new Error(`expected property 'child' to be defined for retry node at depth '${depth}'`);\n }\n\n // Check whether an 'attempts' property has been defined, it may not have been if this node is to retry indefinitely.\n if (typeof definition.attempts !== \"undefined\") {\n if (Array.isArray(definition.attempts)) {\n // Check whether any elements of the array are not integer values.\n const containsNonInteger = !!definition.attempts.filter((value: unknown) => !isInteger(value)).length;\n\n // If the 'attempts' property is an array then it MUST contain two integer values.\n if (definition.attempts.length !== 2 || containsNonInteger) {\n throw new Error(\n `expected array containing two integer values for 'attempts' property if defined for retry node at depth '${depth}'`\n );\n }\n\n // A retry node must have a positive min and max attempts count if they are defined.\n if (definition.attempts[0] < 0 || definition.attempts[1] < 0) {\n throw new Error(\n `expected positive minimum and maximum attempts count for 'attempts' property if defined for retry node at depth '${depth}'`\n );\n }\n\n // A retry node must not have a minimum attempts count that exceeds the maximum attempts count.\n if (definition.attempts[0] > definition.attempts[1]) {\n throw new Error(\n `expected minimum attempts count that does not exceed the maximum attempts count for 'attempts' property if defined for retry node at depth '${depth}'`\n );\n }\n } else if (isInteger(definition.attempts)) {\n // A retry node must have a positive number of attempts if defined.\n if (definition.attempts < 0) {\n throw new Error(\n `expected positive attempts count for 'attempts' property if defined for retry node at depth '${depth}'`\n );\n }\n } else {\n throw new Error(\n `expected integer value or array containing two integer values for 'attempts' property if defined for retry node at depth '${depth}'`\n );\n }\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n\n // Validate the child node of this decorator node.\n validateNode(definition.child, depth + 1);\n}\n\n/**\n * Validate an object that we expect to be a branch node definition.\n * @param definition An object that we expect to be a branch node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateBranchNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"branch\") {\n throw new Error(`expected node type of 'branch' for branch node at depth '${depth}'`);\n }\n\n // Check that the branch node 'ref' property is defined and is a non-empty string.\n if (typeof definition.ref !== \"string\" || definition.ref.length === 0) {\n throw new Error(`expected non-empty string for 'ref' property for branch node at depth '${depth}'`);\n }\n\n // It is invalid to define guard attributes for a branch node as they should be defined on the referenced root node.\n [\"while\", \"until\"].forEach((attributeName) => {\n if (typeof definition[attributeName] !== \"undefined\") {\n throw new Error(\n `guards should not be defined for branch nodes but guard '${attributeName}' was defined for branch node at depth '${depth}'`\n );\n }\n });\n\n // It is invalid to define callback attributes for a branch node as they should be defined on the referenced root node.\n [\"entry\", \"exit\", \"step\"].forEach((attributeName) => {\n if (typeof definition[attributeName] !== \"undefined\") {\n throw new Error(\n `callbacks should not be defined for branch nodes but callback '${attributeName}' was defined for branch node at depth '${depth}'`\n );\n }\n });\n}\n\n/**\n * Validate an object that we expect to be a action node definition.\n * @param definition An object that we expect to be a action node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateActionNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"action\") {\n throw new Error(`expected node type of 'action' for action node at depth '${depth}'`);\n }\n\n // The 'call' property must be defined for a action node definition.\n if (typeof definition.call !== \"string\" || definition.call.length === 0) {\n throw new Error(`expected non-empty string for 'call' property of action node at depth '${depth}'`);\n }\n\n // If any action function arguments have been defined then they must have been defined in an array.\n if (typeof definition.args !== \"undefined\" && !Array.isArray(definition.args)) {\n throw new Error(`expected array for 'args' property if defined for action node at depth '${depth}'`);\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n}\n\n/**\n * Validate an object that we expect to be a condition node definition.\n * @param definition An object that we expect to be a condition node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateConditionNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"condition\") {\n throw new Error(`expected node type of 'condition' for condition node at depth '${depth}'`);\n }\n\n // The 'call' property must be defined for a condition node definition.\n if (typeof definition.call !== \"string\" || definition.call.length === 0) {\n throw new Error(`expected non-empty string for 'call' property of condition node at depth '${depth}'`);\n }\n\n // If any condition function arguments have been defined then they must have been defined in an array.\n if (typeof definition.args !== \"undefined\" && !Array.isArray(definition.args)) {\n throw new Error(`expected array for 'args' property if defined for condition node at depth '${depth}'`);\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n}\n\n/**\n * Validate an object that we expect to be a wait node definition.\n * @param definition An object that we expect to be a wait node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateWaitNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"wait\") {\n throw new Error(`expected node type of 'wait' for wait node at depth '${depth}'`);\n }\n\n // Check whether a 'duration' property has been defined, it may not have been if this node is to wait indefinitely.\n if (typeof definition.duration !== \"undefined\") {\n if (Array.isArray(definition.duration)) {\n // Check whether any elements of the array are not integer values.\n const containsNonInteger = !!definition.duration.filter((value: unknown) => !isInteger(value)).length;\n\n // If the 'duration' property is an array then it MUST contain two integer values.\n if (definition.duration.length !== 2 || containsNonInteger) {\n throw new Error(\n `expected array containing two integer values for 'duration' property if defined for wait node at depth '${depth}'`\n );\n }\n\n // A wait node must have a positive min and max duration value if they are defined.\n if (definition.duration[0] < 0 || definition.duration[1] < 0) {\n throw new Error(\n `expected positive minimum and maximum duration for 'duration' property if defined for wait node at depth '${depth}'`\n );\n }\n\n // A wait node must not have a minimum duration value that exceeds the maximum duration value.\n if (definition.duration[0] > definition.duration[1]) {\n throw new Error(\n `expected minimum duration value that does not exceed the maximum duration value for 'duration' property if defined for wait node at depth '${depth}'`\n );\n }\n } else if (isInteger(definition.duration)) {\n // A wait node must have a positive duration value if defined.\n if (definition.duration < 0) {\n throw new Error(\n `expected positive duration value for 'duration' property if defined for wait node at depth '${depth}'`\n );\n }\n } else {\n throw new Error(\n `expected integer value or array containing two integer values for 'duration' property if defined for wait node at depth '${depth}'`\n );\n }\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n}\n\n/**\n * Validate an object that we expect to be a sequence node definition.\n * @param definition An object that we expect to be a sequence node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateSequenceNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"sequence\") {\n throw new Error(`expected node type of 'sequence' for sequence node at depth '${depth}'`);\n }\n\n // A sequence node is a composite node, so must have a children nodes array defined.\n if (!Array.isArray(definition.children) || definition.children.length === 0) {\n throw new Error(`expected non-empty 'children' array to be defined for sequence node at depth '${depth}'`);\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n\n // Validate the child nodes of this composite node.\n definition.children.forEach((child: any) => validateNode(child, depth + 1));\n}\n\n/**\n * Validate an object that we expect to be a selector node definition.\n * @param definition An object that we expect to be a selector node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateSelectorNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"selector\") {\n throw new Error(`expected node type of 'selector' for selector node at depth '${depth}'`);\n }\n\n // A selector node is a composite node, so must have a children nodes array defined.\n if (!Array.isArray(definition.children) || definition.children.length === 0) {\n throw new Error(`expected non-empty 'children' array to be defined for selector node at depth '${depth}'`);\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n\n // Validate the child nodes of this composite node.\n definition.children.forEach((child: any) => validateNode(child, depth + 1));\n}\n\n/**\n * Validate an object that we expect to be a parallel node definition.\n * @param definition An object that we expect to be a parallel node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateParallelNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"parallel\") {\n throw new Error(`expected node type of 'parallel' for parallel node at depth '${depth}'`);\n }\n\n // A parallel node is a composite node, so must have a children nodes array defined.\n if (!Array.isArray(definition.children) || definition.children.length === 0) {\n throw new Error(`expected non-empty 'children' array to be defined for parallel node at depth '${depth}'`);\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n\n // Validate the child nodes of this composite node.\n definition.children.forEach((child: any) => validateNode(child, depth + 1));\n}\n\n/**\n * Validate an object that we expect to be a lotto node definition.\n * @param definition An object that we expect to be a lotto node definition.\n * @param depth The depth of the node in the definition tree.\n */\nfunction validateLottoNode(definition: any, depth: number): void {\n // Check that the node type is correct.\n if (definition.type !== \"lotto\") {\n throw new Error(`expected node type of 'lotto' for lotto node at depth '${depth}'`);\n }\n\n // A lotto node is a composite node, so must have a children nodes array defined.\n if (!Array.isArray(definition.children) || definition.children.length === 0) {\n throw new Error(`expected non-empty 'children' array to be defined for lotto node at depth '${depth}'`);\n }\n\n // Check whether a 'weights' property has been defined, if it has we expect it to be an array of weights.\n if (typeof definition.weights !== \"undefined\") {\n // Check that the weights property is an array of positive integers with an element for each child node element.\n if (\n !Array.isArray(definition.weights) ||\n definition.weights.length !== definition.children.length ||\n definition.weights.filter((value: unknown) => !isInteger(value)).length ||\n definition.weights.filter((value: number) => value < 0).length\n ) {\n throw new Error(\n `expected an array of positive integer weight values with a length matching the number of child nodes for 'weights' property if defined for lotto node at depth '${depth}'`\n );\n }\n }\n\n // Validate the node attributes.\n validateNodeAttributes(definition, depth);\n\n // Validate the child nodes of this composite node.\n definition.children.forEach((child: any) => validateNode(child, depth + 1));\n}\n\n/**\n * A helper function to create a failure validation result with the given error message.\n * @param errorMessage The validation failure error message.\n * @returns A failure validation result with the given error message.\n */\nfunction createValidationFailureResult(errorMessage: string): DefinitionValidationResult {\n return { succeeded: false, errorMessage };\n}\n", "import { ActionResult, Agent, GlobalFunction } from \"./Agent\";\nimport { RootNodeDefinition } from \"./BehaviourTreeDefinition\";\n\nexport type InvokerFunction = (args: any[]) => ActionResult | boolean;\n\n/**\n * A singleton used to store and lookup registered functions and subtrees.\n */\nexport default class Lookup {\n /**\n * The object holding any registered functions keyed on function name.\n */\n private static registeredFunctions: { [key: string]: GlobalFunction } = {};\n /**\n * The object holding any registered subtree root node definitions keyed on tree name.\n */\n private static registeredSubtrees: { [key: string]: RootNodeDefinition } = {};\n\n /**\n * Gets the function with the specified name.\n * @param name The name of the function.\n * @returns The function with the specified name.\n */\n public static getFunc(name: string): GlobalFunction {\n return this.registeredFunctions[name];\n }\n\n /**\n * Sets the function with the specified name for later lookup.\n * @param name The name of the function.\n * @param func The function.\n */\n public static setFunc(name: string, func: GlobalFunction): void {\n this.registeredFunctions[name] = func;\n }\n\n /**\n * Gets the function invoker for the specified agent and function name.\n * If a function with the specified name exists on the agent object then it will\n * be returned, otherwise we will then check the registered functions for a match.\n * @param agent The agent instance that this behaviour tree is modelling behaviour for.\n * @param name The function name.\n * @returns The function invoker for the specified agent and function name.\n */\n static getFuncInvoker(agent: Agent, name: string): InvokerFunction | null {\n // Check whether the agent contains the specified function.\n const agentFunction = agent[name];\n if (agentFunction && typeof agentFunction === \"function\") {\n return (args: any[]) => agentFunction.apply(agent, args);\n }\n\n // The agent does not contain the specified function but it may have been registered at some point.\n if (this.registeredFunctions[name] && typeof this.registeredFunctions[name] === \"function\") {\n const registeredFunction = this.registeredFunctions[name];\n return (args: any[]) => registeredFunction(agent, ...args);\n }\n\n // We have no function to invoke.\n return null;\n }\n\n /**\n * Gets all registered subtree root node definitions.\n */\n static getSubtrees(): { [key: string]: RootNodeDefinition } {\n return this.registeredSubtrees;\n }\n\n /**\n * Sets the subtree with the specified name for later lookup.\n * @param name The name of the subtree.\n * @param subtree The subtree.\n */\n static setSubtree(name: string, subtree: RootNodeDefinition) {\n this.registeredSubtrees[name] = subtree;\n }\n\n /**\n * Removes the registered function or subtree with the specified name.\n * @param name The name of the registered function or subtree.\n */\n static remove(name: string) {\n delete this.registeredFunctions[name];\n delete this.registeredSubtrees[name];\n }\n\n /**\n * Remove all registered functions and subtrees.\n */\n static empty() {\n this.registeredFunctions = {};\n this.registeredSubtrees = {};\n }\n}\n", "import Node from \"../../nodes/Node\";\n\n/**\n * An exception thrown when evaluating node guard path conditions and a conditions fails.\n */\nexport default class GuardUnsatisifedException extends Error {\n /**\n * @param source The node at which a guard condition failed.\n */\n constructor(private source: Node) {\n super(\"A guard path condition has failed\");\n }\n\n /**\n * Gets whether the specified node is the node at which a guard condition failed.\n * @param node The node to check against the source node.\n * @returns Whether the specified node is the node at which a guard condition failed.\n */\n isSourceNode = (node: Node) => node === this.source;\n}\n", "import { Agent } from \"../../Agent\";\nimport Guard from \"./Guard\";\nimport Node from \"../../nodes/Node\";\nimport GuardUnsatisifedException from \"./GuardUnsatisifedException\";\n\nexport type GuardPathPart = {\n node: Node;\n guards: Guard[];\n};\n\n/**\n * Represents a path of node guards along a root-to-leaf tree path.\n */\nexport default class GuardPath {\n /**\n * @param nodes An array of objects defining a node instance -> guard link, ordered by node depth.\n */\n constructor(private nodes: GuardPathPart[]) {}\n\n /**\n * Evaluate guard conditions for all guards in the tree path, moving outwards from the root.\n * @param agent The agent, required for guard evaluation.\n * @returns An evaluation results object.\n */\n evaluate = (agent: Agent) => {\n // We need to evaluate guard conditions for nodes up the tree, moving outwards from the root.\n for (const details of this.nodes) {\n // There can be multiple guards per node.\n for (const guard of details.guards) {\n // Check whether the guard condition passes, and throw an exception if not.\n if (!guard.isSatisfied(agent)) {\n throw new GuardUnsatisifedException(details.node);\n }\n }\n }\n };\n}\n", "import { BehaviourTreeOptions } from \"../BehaviourTreeOptions\";\nimport State, { AnyState } from \"../State\";\nimport { Agent } from \"../Agent\";\nimport Leaf from \"./leaf/Leaf\";\nimport Attribute from \"../attributes/Attribute\";\nimport Entry from \"../attributes/callbacks/Entry\";\nimport Exit from \"../attributes/callbacks/Exit\";\nimport Step from \"../attributes/callbacks/Step\";\nimport Guard from \"../attributes/guards/Guard\";\nimport GuardPath from \"../attributes/guards/GuardPath\";\nimport GuardUnsatisifedException from \"../attributes/guards/GuardUnsatisifedException\";\n\n/**\n * A base node.\n */\nexport default abstract class Node {\n /**\n * The node uid.\n */\n private readonly uid: string = createNodeUid();\n /**\n * The node state.\n */\n private state: AnyState = State.READY;\n /**\n * The guard path to evaluate as part of a node update.\n */\n private guardPath: GuardPath | undefined;\n\n /**\n * @param type The node type.\n * @param attributes The node attributes.\n * @param args The node argument definitions.\n */\n constructor(private type: string, private attributes: Attribute[], private args: any[]) {}\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected abstract onUpdate(agent: Agent, options: BehaviourTreeOptions): void;\n\n /**\n * Gets the name of the node.\n */\n public abstract getName(): string;\n\n /**\n * Gets whether this node is a leaf node.\n */\n public abstract isLeafNode: () => this is Leaf;\n\n /**\n * Gets/Sets the state of the node.\n */\n getState = (): AnyState => this.state;\n setState = (value: AnyState): void => {\n this.state = value;\n };\n\n /**\n * Gets the unique id of the node.\n */\n getUid = () => this.uid;\n\n /**\n * Gets the type of the node.\n */\n getType = () => this.type;\n\n /**\n * Gets the node attributes.\n */\n getAttributes = () => this.attributes;\n\n /**\n * Gets the node arguments.\n */\n getArguments = () => this.args;\n\n /**\n * Gets the node attribute with the specified type, or null if it does not exist.\n */\n getAttribute(type: \"entry\" | \"ENTRY\"): Entry;\n getAttribute(type: \"exit\" | \"EXIT\"): Exit;\n getAttribute(type: \"step\" | \"STEP\"): Step;\n getAttribute(type: string): Attribute {\n return (\n this.getAttributes().filter((decorator) => decorator.type.toUpperCase() === type.toUpperCase())[0] || null\n );\n }\n\n /**\n * Gets the node attributes.\n */\n getGuardAttributes = (): Guard[] => this.getAttributes().filter((decorator) => decorator.isGuard()) as Guard[];\n\n /**\n * Sets the guard path to evaluate as part of a node update.\n */\n setGuardPath = (value: GuardPath) => (this.guardPath = value);\n\n /**\n * Gets whether a guard path is assigned to this node.\n */\n hasGuardPath = () => !!this.guardPath;\n\n /**\n * Gets whether this node is in the specified state.\n * @param value The value to compare to the node state.\n */\n public is(value: AnyState): boolean {\n return this.state === value;\n }\n\n /**\n * Reset the state of the node.\n */\n public reset(): void {\n this.setState(State.READY);\n }\n\n /**\n * Abort the running of this node.\n * @param agent The agent.\n */\n public abort(agent: Agent): void {\n // There is nothing to do if this node is not in the running state.\n if (!this.is(State.RUNNING)) {\n return;\n }\n\n // Reset the state of this node.\n this.reset();\n\n this.getAttribute(\"exit\")?.callAgentFunction(agent, false, true);\n }\n\n /**\n * Update the node.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n * @returns The result of the update.\n */\n public update(agent: Agent, options: BehaviourTreeOptions): void {\n // If this node is already in a 'SUCCEEDED' or 'FAILED' state then there is nothing to do.\n if (this.is(State.SUCCEEDED) || this.is(State.FAILED)) {\n return;\n }\n\n try {\n // Evaluate all of the guard path conditions for the current tree path.\n this.guardPath!.evaluate(agent);\n\n // If this node is in the READY state then call the ENTRY for this node if it exists.\n if (this.is(State.READY)) {\n this.getAttribute(\"entry\")?.callAgentFunction(agent);\n }\n\n this.getAttribute(\"step\")?.callAgentFunction(agent);\n\n // Do the actual update.\n this.onUpdate(agent, options);\n\n // If this node is now in a 'SUCCEEDED' or 'FAILED' state then call the EXIT for this node if it exists.\n if (this.is(State.SUCCEEDED) || this.is(State.FAILED)) {\n this.getAttribute(\"exit\")?.callAgentFunction(agent, this.is(State.SUCCEEDED), false);\n }\n } catch (error) {\n // If the error is a GuardUnsatisfiedException then we need to determine if this node is the source.\n if (error instanceof GuardUnsatisifedException && error.isSourceNode(this)) {\n // Abort the current node.\n this.abort(agent);\n\n // Any node that is the source of an abort will be a failed node.\n this.setState(State.FAILED);\n } else {\n throw error;\n }\n }\n }\n}\n\n/**\n * Create a randomly generated node uid.\n * @returns A randomly generated node uid.\n */\nfunction createNodeUid(): string {\n var S4 = function () {\n return (((1 + Math.random()) * 0x10000) | 0).toString(16).substring(1);\n };\n return S4() + S4() + \"-\" + S4() + \"-\" + S4() + \"-\" + S4() + \"-\" + S4() + S4() + S4();\n}\n", "import Node from \"../Node\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\n\n/**\n * A composite node that wraps child nodes.\n */\nexport default abstract class Composite extends Node {\n /**\n * @param type The node type.\n * @param attributes The node attributes.\n * @param children The child nodes.\n */\n constructor(type: string, attributes: Attribute[], protected children: Node[]) {\n super(type, attributes, []);\n }\n\n /**\n * Gets whether this node is a leaf node.\n */\n isLeafNode = () => false;\n\n /**\n * Gets the children of this node.\n */\n getChildren = () => this.children;\n\n /**\n * Reset the state of the node.\n */\n reset = () => {\n // Reset the state of this node.\n this.setState(State.READY);\n\n // Reset the state of any child nodes.\n this.getChildren().forEach((child) => child.reset());\n };\n\n /**\n * Abort the running of this node.\n * @param agent The agent.\n */\n abort = (agent: Agent) => {\n // There is nothing to do if this node is not in the running state.\n if (!this.is(State.RUNNING)) {\n return;\n }\n\n // Abort any child nodes.\n this.getChildren().forEach((child) => child.abort(agent));\n\n // Reset the state of this node.\n this.reset();\n\n this.getAttribute(\"exit\")?.callAgentFunction(agent, false, true);\n };\n}\n", "import Composite from \"./Composite\";\nimport State from \"../../State\";\nimport Node from \"../Node\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A PARALLEL node.\n * The child nodes are executed concurrently until one fails or all succeed.\n */\nexport default class Parallel extends Composite {\n /**\n * @param attributes The node attributes.\n * @param children The child nodes.\n */\n constructor(attributes: Attribute[], children: Node[]) {\n super(\"parallel\", attributes, children);\n }\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // Keep a count of the number of succeeded child nodes.\n let succeededCount = 0;\n\n let hasChildFailed = false;\n\n // Iterate over all of the children of this node.\n for (const child of this.children) {\n // If the child has never been updated or is running then we will need to update it now.\n if (child.getState() === State.READY || child.getState() === State.RUNNING) {\n // Update the child of this node.\n child.update(agent, options);\n }\n\n // If the current child has a state of 'SUCCEEDED' then we should move on to the next child.\n if (child.getState() === State.SUCCEEDED) {\n // The child node has succeeded, keep track of this to determine if all children have.\n succeededCount++;\n\n // The child node succeeded, but we have not finished checking every child node yet.\n continue;\n }\n\n // If the current child has a state of 'FAILED' then this node is also a 'FAILED' node.\n if (child.getState() === State.FAILED) {\n hasChildFailed = true;\n\n // There is no need to check the rest of the children.\n break;\n }\n\n // The node should be in the 'RUNNING' state.\n if (child.getState() !== State.RUNNING) {\n // The child node was not in an expected state.\n throw new Error(\"child node was not in an expected state.\");\n }\n }\n\n if (hasChildFailed) {\n // This node is a 'FAILED' node.\n this.setState(State.FAILED);\n\n // Abort every running child.\n for (const child of this.children) {\n if (child.getState() === State.RUNNING) {\n child.abort(agent);\n }\n }\n } else {\n // If all children have succeeded then this node has also succeeded, otherwise it is still running.\n this.setState(succeededCount === this.children.length ? State.SUCCEEDED : State.RUNNING);\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => \"PARALLEL\";\n}\n", "import Composite from \"./Composite\";\nimport Node from \"../Node\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A SELECTOR node.\n * The child nodes are executed in sequence until one succeeds or all fail.\n */\nexport default class Selector extends Composite {\n /**\n * @param attributes The node attributes.\n * @param children The child nodes.\n */\n constructor(attributes: Attribute[], protected children: Node[]) {\n super(\"selector\", attributes, children);\n }\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // Iterate over all of the children of this node.\n for (const child of this.children) {\n // If the child has never been updated or is running then we will need to update it now.\n if (child.getState() === State.READY || child.getState() === State.RUNNING) {\n // Update the child of this node.\n child.update(agent, options);\n }\n\n // If the current child has a state of 'SUCCEEDED' then this node is also a 'SUCCEEDED' node.\n if (child.getState() === State.SUCCEEDED) {\n // This node is a 'SUCCEEDED' node.\n this.setState(State.SUCCEEDED);\n\n // There is no need to check the rest of the selector nodes.\n return;\n }\n\n // If the current child has a state of 'FAILED' then we should move on to the next child.\n if (child.getState() === State.FAILED) {\n // Find out if the current child is the last one in the selector.\n // If it is then this sequence node has also failed.\n if (this.children.indexOf(child) === this.children.length - 1) {\n // This node is a 'FAILED' node.\n this.setState(State.FAILED);\n\n // There is no need to check the rest of the selector as we have completed it.\n return;\n } else {\n // The child node failed, try the next one.\n continue;\n }\n }\n\n // The node should be in the 'RUNNING' state.\n if (child.getState() === State.RUNNING) {\n // This node is a 'RUNNING' node.\n this.setState(State.RUNNING);\n\n // There is no need to check the rest of the selector as the current child is still running.\n return;\n }\n\n // The child node was not in an expected state.\n throw new Error(\"child node was not in an expected state.\");\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => \"SELECTOR\";\n}\n", "import Composite from \"./Composite\";\nimport Node from \"../Node\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A SEQUENCE node.\n * The child nodes are executed in sequence until one fails or all succeed.\n */\nexport default class Sequence extends Composite {\n /**\n * @param attributes The node attributes.\n * @param children The child nodes.\n */\n constructor(attributes: Attribute[], protected children: Node[]) {\n super(\"sequence\", attributes, children);\n }\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // Iterate over all of the children of this node.\n for (const child of this.children) {\n // If the child has never been updated or is running then we will need to update it now.\n if (child.getState() === State.READY || child.getState() === State.RUNNING) {\n // Update the child of this node.\n child.update(agent, options);\n }\n\n // If the current child has a state of 'SUCCEEDED' then we should move on to the next child.\n if (child.getState() === State.SUCCEEDED) {\n // Find out if the current child is the last one in the sequence.\n // If it is then this sequence node has also succeeded.\n if (this.children.indexOf(child) === this.children.length - 1) {\n // This node is a 'SUCCEEDED' node.\n this.setState(State.SUCCEEDED);\n\n // There is no need to check the rest of the sequence as we have completed it.\n return;\n } else {\n // The child node succeeded, but we have not finished the sequence yet.\n continue;\n }\n }\n\n // If the current child has a state of 'FAILED' then this node is also a 'FAILED' node.\n if (child.getState() === State.FAILED) {\n // This node is a 'FAILED' node.\n this.setState(State.FAILED);\n\n // There is no need to check the rest of the sequence.\n return;\n }\n\n // The node should be in the 'RUNNING' state.\n if (child.getState() === State.RUNNING) {\n // This node is a 'RUNNING' node.\n this.setState(State.RUNNING);\n\n // There is no need to check the rest of the sequence as the current child is still running.\n return;\n }\n\n // The child node was not in an expected state.\n throw new Error(\"child node was not in an expected state.\");\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => \"SEQUENCE\";\n}\n", "import createLotto from \"lotto-draw\";\n\nimport Node from \"../Node\";\nimport Composite from \"./Composite\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A LOTTO node.\n * A winning child is picked on the initial update of this node, based on ticket weighting.\n * The state of this node will match the state of the winning child.\n */\nexport default class Lotto extends Composite {\n /**\n * @param attributes The node attributes.\n * @param weights The child node weights.\n * @param children The child nodes.\n */\n constructor(attributes: Attribute[], private weights: number[] | undefined, children: Node[]) {\n super(\"lotto\", attributes, children);\n }\n\n /**\n * The child node selected to be the active one.\n */\n private selectedChild: Node | undefined;\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // If this node is in the READY state then we need to pick a winning child node.\n if (this.is(State.READY)) {\n // Create a lotto draw with which to randomly pick a child node to become the active one.\n const lottoDraw = createLotto({\n // Hook up the optional 'random' behaviour tree function option to the one used by 'lotto-draw'.\n random: options.random,\n // Pass in each child node as a participant in the lotto draw with their respective ticket count.\n participants: this.children.map((child, index) => [child, this.weights?.[index] || 1])\n });\n\n // Randomly pick a child based on ticket weighting, this will become the active child for this composite node.\n this.selectedChild = lottoDraw.draw() || undefined;\n }\n\n // If something went wrong and we don't have an active child then we should throw an error.\n if (!this.selectedChild) {\n throw new Error(\"failed to update lotto node as it has no active child\");\n }\n\n // If the selected child has never been updated or is running then we will need to update it now.\n if (this.selectedChild.getState() === State.READY || this.selectedChild.getState() === State.RUNNING) {\n this.selectedChild.update(agent, options);\n }\n\n // The state of the lotto node is the state of its selected child.\n this.setState(this.selectedChild.getState());\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => (this.weights ? `LOTTO [${this.weights.join(\",\")}]` : \"LOTTO\");\n}\n", "import Node from \"../Node\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\n\n/**\n * A decorator node that wraps a single child node.\n */\nexport default abstract class Decorator extends Node {\n /**\n * @param type The node type.\n * @param attributes The node attributes.\n * @param child The child node.\n */\n constructor(type: string, attributes: Attribute[], protected child: Node) {\n super(type, attributes, []);\n }\n\n /**\n * Gets whether this node is a leaf node.\n */\n isLeafNode = () => false;\n\n /**\n * Gets the children of this node.\n */\n getChildren = () => [this.child];\n\n /**\n * Reset the state of the node.\n */\n reset = () => {\n // Reset the state of this node.\n this.setState(State.READY);\n\n // Reset the state of the child node.\n this.child.reset();\n };\n\n /**\n * Abort the running of this node.\n * @param agent The agent.\n */\n abort = (agent: Agent) => {\n // There is nothing to do if this node is not in the running state.\n if (!this.is(State.RUNNING)) {\n return;\n }\n\n // Abort the child node.\n this.child.abort(agent);\n\n // Reset the state of this node.\n this.reset();\n\n this.getAttribute(\"exit\")?.callAgentFunction(agent, false, true);\n };\n}\n", "import Node from \"../Node\";\nimport Decorator from \"./Decorator\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A Fail node.\n * This node wraps a single child and will always move to the 'FAILED' state when the child moves to a 'SUCCEEDED' or 'FAILED' state.\n */\nexport default class Fail extends Decorator {\n /**\n * @param attributes The node attributes.\n * @param child The child node.\n */\n constructor(attributes: Attribute[], child: Node) {\n super(\"fail\", attributes, child);\n }\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // If the child has never been updated or is running then we will need to update it now.\n if (this.child.getState() === State.READY || this.child.getState() === State.RUNNING) {\n this.child.update(agent, options);\n }\n\n // The state of this node will depend in the state of its child.\n switch (this.child.getState()) {\n case State.RUNNING:\n this.setState(State.RUNNING);\n break;\n\n case State.SUCCEEDED:\n case State.FAILED:\n this.setState(State.FAILED);\n break;\n\n default:\n this.setState(State.READY);\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => \"FAIL\";\n}\n", "import Decorator from \"./Decorator\";\nimport State from \"../../State\";\nimport Node from \"../Node\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A Flip node.\n * This node wraps a single child and will flip the state of the child state.\n */\nexport default class Flip extends Decorator {\n /**\n * @param attributes The node attributes.\n * @param child The child node.\n */\n constructor(attributes: Attribute[], child: Node) {\n super(\"flip\", attributes, child);\n }\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // If the child has never been updated or is running then we will need to update it now.\n if (this.child.getState() === State.READY || this.child.getState() === State.RUNNING) {\n this.child.update(agent, options);\n }\n\n // The state of this node will depend in the state of its child.\n switch (this.child.getState()) {\n case State.RUNNING:\n this.setState(State.RUNNING);\n break;\n\n case State.SUCCEEDED:\n this.setState(State.FAILED);\n break;\n\n case State.FAILED:\n this.setState(State.SUCCEEDED);\n break;\n\n default:\n this.setState(State.READY);\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => \"FLIP\";\n}\n", "import Node from \"../Node\";\nimport Decorator from \"./Decorator\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A REPEAT node.\n * The node has a single child which can have:\n * -- A number of iterations for which to repeat the child node.\n * -- An infinite repeat loop if neither an iteration count or a condition function is defined.\n * The REPEAT node will stop and have a 'FAILED' state if its child is ever in a 'FAILED' state after an update.\n * The REPEAT node will attempt to move on to the next iteration if its child is ever in a 'SUCCEEDED' state.\n */\nexport default class Repeat extends Decorator {\n /**\n * @param attributes The node attributes.\n * @param iterations The number of iterations to repeat the child node.\n * @param iterationsMin The minimum possible number of iterations to repeat the child node.\n * @param iterationsMax The maximum possible number of iterations to repeat the child node.\n * @param child The child node.\n */\n constructor(\n attributes: Attribute[],\n private iterations: number | null,\n private iterationsMin: number | null,\n private iterationsMax: number | null,\n child: Node\n ) {\n super(\"repeat\", attributes, child);\n }\n\n /**\n * The number of target iterations to make.\n */\n private targetIterationCount: number | null = null;\n\n /**\n * The current iteration count.\n */\n private currentIterationCount: number = 0;\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // If this node is in the READY state then we need to reset the child and the target iteration count.\n if (this.is(State.READY)) {\n // Reset the child node.\n this.child.reset();\n\n // Reset the current iteration count.\n this.currentIterationCount = 0;\n\n // Set the target iteration count.\n this.setTargetIterationCount(options);\n }\n\n // Do a check to see if we can iterate. If we can then this node will move into the 'RUNNING' state.\n // If we cannot iterate then we have hit our target iteration count, which means that the node has succeeded.\n if (this.canIterate()) {\n // This node is in the running state and can do its initial iteration.\n this.setState(State.RUNNING);\n\n // We may have already completed an iteration, meaning that the child node will be in the SUCCEEDED state.\n // If this is the case then we will have to reset the child node now.\n if (this.child.getState() === State.SUCCEEDED) {\n this.child.reset();\n }\n\n // Update the child of this node.\n this.child.update(agent, options);\n\n // If the child moved into the FAILED state when we updated it then there is nothing left to do and this node has also failed.\n // If it has moved into the SUCCEEDED state then we have completed the current iteration.\n if (this.child.getState() === State.FAILED) {\n // The child has failed, meaning that this node has failed.\n this.setState(State.FAILED);\n\n return;\n } else if (this.child.getState() === State.SUCCEEDED) {\n // We have completed an iteration.\n this.currentIterationCount += 1;\n }\n } else {\n // This node is in the 'SUCCEEDED' state as we cannot iterate any more.\n this.setState(State.SUCCEEDED);\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => {\n if (this.iterations !== null) {\n return `REPEAT ${this.iterations}x`;\n } else if (this.iterationsMin !== null && this.iterationsMax !== null) {\n return `REPEAT ${this.iterationsMin}x-${this.iterationsMax}x`;\n } else {\n return \"REPEAT\";\n }\n };\n\n /**\n * Reset the state of the node.\n */\n reset = () => {\n // Reset the state of this node.\n this.setState(State.READY);\n\n // Reset the current iteration count.\n this.currentIterationCount = 0;\n\n // Reset the child node.\n this.child.reset();\n };\n\n /**\n * Gets whether an iteration can be made.\n * @returns Whether an iteration can be made.\n */\n private canIterate = () => {\n if (this.targetIterationCount !== null) {\n // We can iterate as long as we have not reached our target iteration count.\n return this.currentIterationCount < this.targetIterationCount;\n }\n\n // If neither an iteration count or a condition function were defined then we can iterate indefinitely.\n return true;\n };\n\n /**\n * Sets the target iteration count.\n * @param options The behaviour tree options object.\n */\n private setTargetIterationCount = (options: BehaviourTreeOptions) => {\n // Are we dealing with an explicit iteration count or will we be randomly picking a iteration count between the min and max iteration count.\n if (this.iterations !== null) {\n this.targetIterationCount = this.iterations;\n } else if (this.iterationsMin !== null && this.iterationsMax !== null) {\n // We will be picking a random iteration count between a min and max iteration count, if the optional 'random'\n // behaviour tree function option is defined then we will be using that, otherwise we will fall back to using Math.random.\n const random = typeof options.random === \"function\" ? options.random : Math.random;\n\n // Pick a random iteration count between a min and max iteration count.\n this.targetIterationCount = Math.floor(\n random() * (this.iterationsMax - this.iterationsMin + 1) + this.iterationsMin\n );\n } else {\n this.targetIterationCount = null;\n }\n };\n}\n", "import Node from \"../Node\";\nimport Decorator from \"./Decorator\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A RETRY node.\n * The node has a single child which can have:\n * -- A number of iterations for which to repeat the child node.\n * -- An infinite repeat loop if neither an iteration count or a condition function is defined.\n * The RETRY node will stop and have a 'SUCCEEDED' state if its child is ever in a 'SUCCEEDED' state after an update.\n * The RETRY node will attempt to move on to the next iteration if its child is ever in a 'FAILED' state.\n */\nexport default class Retry extends Decorator {\n /**\n * @param attributes The node attributes.\n * @param attempts The number of attempts to retry the child node.\n * @param attemptsMin The minimum possible number of attempts to retry the child node.\n * @param attemptsMax The maximum possible number of attempts to retry the child node.\n * @param child The child node.\n */\n constructor(\n attributes: Attribute[],\n private attempts: number | null,\n private attemptsMin: number | null,\n private attemptsMax: number | null,\n child: Node\n ) {\n super(\"retry\", attributes, child);\n }\n\n /**\n * The number of target attempts to make.\n */\n private targetAttemptCount: number | null = null;\n\n /**\n * The current attempt count.\n */\n private currentAttemptCount: number = 0;\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // If this node is in the READY state then we need to reset the child and the target attempt count.\n if (this.is(State.READY)) {\n // Reset the child node.\n this.child.reset();\n\n // Reset the current attempt count.\n this.currentAttemptCount = 0;\n\n // Set the target attempt count.\n this.setTargetAttemptCount(options);\n }\n\n // Do a check to see if we can attempt. If we can then this node will move into the 'RUNNING' state.\n // If we cannot attempt then we have hit our target attempt count, which means that the node has succeeded.\n if (this.canAttempt()) {\n // This node is in the running state and can do its initial attempt.\n this.setState(State.RUNNING);\n\n // We may have already completed an attempt, meaning that the child node will be in the FAILED state.\n // If this is the case then we will have to reset the child node now.\n if (this.child.getState() === State.FAILED) {\n this.child.reset();\n }\n\n // Update the child of this node.\n this.child.update(agent, options);\n\n // If the child moved into the SUCCEEDED state when we updated it then there is nothing left to do and this node has also succeeded.\n // If it has moved into the FAILED state then we have completed the current attempt.\n if (this.child.getState() === State.SUCCEEDED) {\n // The child has succeeded, meaning that this node has succeeded.\n this.setState(State.SUCCEEDED);\n\n return;\n } else if (this.child.getState() === State.FAILED) {\n // We have completed an attempt.\n this.currentAttemptCount += 1;\n }\n } else {\n // This node is in the 'FAILED' state as we cannot iterate any more.\n this.setState(State.FAILED);\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => {\n if (this.attempts !== null) {\n return `RETRY ${this.attempts}x`;\n } else if (this.attemptsMin !== null && this.attemptsMax !== null) {\n return `RETRY ${this.attemptsMin}x-${this.attemptsMax}x`;\n } else {\n return \"RETRY\";\n }\n };\n\n /**\n * Reset the state of the node.\n */\n reset = () => {\n // Reset the state of this node.\n this.setState(State.READY);\n\n // Reset the current attempt count.\n this.currentAttemptCount = 0;\n\n // Reset the child node.\n this.child.reset();\n };\n\n /**\n * Gets whether an attempt can be made.\n * @returns Whether an attempt can be made.\n */\n canAttempt = () => {\n if (this.targetAttemptCount !== null) {\n // We can attempt as long as we have not reached our target attempt count.\n return this.currentAttemptCount < this.targetAttemptCount;\n }\n\n // If neither an attempt count or a condition function were defined then we can attempt indefinitely.\n return true;\n };\n\n /**\n * Sets the target attempt count.\n * @param options The behaviour tree options object.\n */\n setTargetAttemptCount = (options: BehaviourTreeOptions) => {\n // Are we dealing with an explicit attempt count or will we be randomly picking an attempt count between the min and max attempt count.\n if (this.attempts !== null) {\n this.targetAttemptCount = this.attempts;\n } else if (this.attemptsMin !== null && this.attemptsMax !== null) {\n // We will be picking a random attempt count between a min and max attempt count, if the optional 'random'\n // behaviour tree function option is defined then we will be using that, otherwise we will fall back to using Math.random.\n const random = typeof options.random === \"function\" ? options.random : Math.random;\n\n // Pick a random attempt count between a min and max attempt count.\n this.targetAttemptCount = Math.floor(\n random() * (this.attemptsMax - this.attemptsMin + 1) + this.attemptsMin\n );\n } else {\n this.targetAttemptCount = null;\n }\n };\n}\n", "import Node from \"../Node\";\nimport Decorator from \"./Decorator\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A Root node.\n * The root node will have a single child.\n */\nexport default class Root extends Decorator {\n /**\n * @param attributes The node attributes.\n * @param child The child node.\n */\n constructor(attributes: Attribute[], child: Node) {\n super(\"root\", attributes, child);\n }\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // If the child has never been updated or is running then we will need to update it now.\n if (this.child.getState() === State.READY || this.child.getState() === State.RUNNING) {\n // Update the child of this node.\n this.child.update(agent, options);\n }\n\n // The state of the root node is the state of its child.\n this.setState(this.child.getState());\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => \"ROOT\";\n}\n", "import Node from \"../Node\";\nimport Decorator from \"./Decorator\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A Succeed node.\n * This node wraps a single child and will always move to the 'SUCCEEDED' state when the child moves to a 'SUCCEEDED' or 'FAILED' state.\n */\nexport default class Succeed extends Decorator {\n /**\n * @param attributes The node attributes.\n * @param child The child node.\n */\n constructor(attributes: Attribute[], child: Node) {\n super(\"succeed\", attributes, child);\n }\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // If the child has never been updated or is running then we will need to update it now.\n if (this.child.getState() === State.READY || this.child.getState() === State.RUNNING) {\n this.child.update(agent, options);\n }\n\n // The state of this node will depend in the state of its child.\n switch (this.child.getState()) {\n case State.RUNNING:\n this.setState(State.RUNNING);\n break;\n\n case State.SUCCEEDED:\n case State.FAILED:\n this.setState(State.SUCCEEDED);\n break;\n\n default:\n this.setState(State.READY);\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => \"SUCCEED\";\n}\n", "import Node from \"../Node\";\n\n/**\n * A leaf node.\n */\nexport default abstract class Leaf extends Node {\n /**\n * Gets whether this node is a leaf node.\n */\n isLeafNode = () => true;\n}\n", "import { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\nimport State, { CompleteState } from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Leaf from \"./Leaf\";\nimport Lookup from \"../../Lookup\";\nimport Attribute from \"../../attributes/Attribute\";\n\n/**\n * The type representing a resolved/rejected update promise.\n */\ntype UpdatePromiseResult = {\n /**\n * Whether the promise was resolved rather than rejected.\n */\n isResolved: boolean;\n\n /**\n * The promise resolved value or rejection reason.\n */\n value: any;\n};\n\n/**\n * An Action leaf node.\n * This represents an immediate or ongoing state of behaviour.\n */\nexport default class Action extends Leaf {\n /**\n * @param attributes The node attributes.\n * @param actionName The action name.\n * @param actionArguments The array of action argument definitions.\n */\n constructor(attributes: Attribute[], private actionName: string, private actionArguments: any[]) {\n super(\"action\", attributes, actionArguments);\n }\n\n /**\n * Whether there is a pending update promise.\n */\n private isUsingUpdatePromise = false;\n\n /**\n * The finished state result of an update promise.\n */\n private updatePromiseResult: UpdatePromiseResult | null = null;\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // If the result of this action depends on an update promise then there is nothing to do until it settles.\n if (this.isUsingUpdatePromise) {\n // Are we still waiting for our update promise to settle?\n if (!this.updatePromiseResult) {\n return;\n }\n\n const { isResolved, value } = this.updatePromiseResult;\n\n // Our update promise settled, was it resolved or rejected?\n if (isResolved) {\n // Our promise resolved so check to make sure the result is a valid finished state.\n if (value !== State.SUCCEEDED && value !== State.FAILED) {\n throw new Error(\n \"action node promise resolved with an invalid value, expected a State.SUCCEEDED or State.FAILED value to be returned\"\n );\n }\n\n // Set the state of this node to match the state returned by the promise.\n this.setState(value);\n\n return;\n } else {\n // The promise was rejected, which isn't great.\n throw new Error(`action function '${this.actionName}' promise rejected with '${value}'`);\n }\n }\n\n // Attempt to get the invoker for the action function.\n const actionFuncInvoker = Lookup.getFuncInvoker(agent, this.actionName);\n\n // The action function should be defined.\n if (actionFuncInvoker === null) {\n throw new Error(\n `cannot update action node as the action '${this.actionName}' function is not defined on the agent and has not been registered`\n );\n }\n\n let actionFunctionResult;\n\n try {\n // Call the action function, the result of which may be:\n // - The finished state of this action node.\n // - A promise to return a finished node state.\n // - Undefined if the node should remain in the running state.\n actionFunctionResult = actionFuncInvoker(this.actionArguments) as CompleteState | Promise;\n } catch (error) {\n // An uncaught error was thrown.\n if (error instanceof Error) {\n throw new Error(`action function '${this.actionName}' threw: ${error.stack}`);\n } else {\n throw new Error(`action function '${this.actionName}' threw: ${error}`);\n }\n }\n\n if (actionFunctionResult instanceof Promise) {\n actionFunctionResult.then(\n (result) => {\n // If 'isUpdatePromisePending' is not set then the promise was cleared as it was resolving, probably via an abort of reset.\n if (!this.isUsingUpdatePromise) {\n return;\n }\n\n // Set the resolved update promise result so that it can be handled on the next update of this node.\n this.updatePromiseResult = {\n isResolved: true,\n value: result\n };\n },\n (reason) => {\n // If 'isUpdatePromisePending' is not set then the promise was cleared as it was resolving, probably via an abort or reset.\n if (!this.isUsingUpdatePromise) {\n return;\n }\n\n // Set the rejected update promise result so that it can be handled on the next update of this node.\n this.updatePromiseResult = {\n isResolved: false,\n value: reason\n };\n }\n );\n\n // This node will be in the 'RUNNING' state until the update promise resolves.\n this.setState(State.RUNNING);\n\n // We are now waiting for the promise returned by the use to resolve before we know what state this node is in.\n this.isUsingUpdatePromise = true;\n } else {\n // Validate the returned value.\n this.validateUpdateResult(actionFunctionResult);\n\n // Set the state of this node, this may be undefined, which just means that the node is still in the 'RUNNING' state.\n this.setState(actionFunctionResult || State.RUNNING);\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => this.actionName;\n\n /**\n * Reset the state of the node.\n */\n reset = () => {\n // Reset the state of this node.\n this.setState(State.READY);\n\n // There is no longer an update promise that we care about.\n this.isUsingUpdatePromise = false;\n this.updatePromiseResult = null;\n };\n\n /**\n * Validate the result of an update function call.\n * @param result The result of an update function call.\n */\n private validateUpdateResult = (result: CompleteState | State.RUNNING) => {\n switch (result) {\n case State.SUCCEEDED:\n case State.FAILED:\n case State.RUNNING:\n case undefined:\n return;\n default:\n throw new Error(\n `expected action function '${this.actionName}' to return an optional State.SUCCEEDED or State.FAILED value but returned '${result}'`\n );\n }\n };\n}\n", "import { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\nimport State from \"../../State\";\nimport { Agent } from \"../../Agent\";\nimport Leaf from \"./Leaf\";\nimport Lookup from \"../../Lookup\";\nimport Attribute from \"../../attributes/Attribute\";\n\n/**\n * A Condition leaf node.\n * This will succeed or fail immediately based on an agent predicate, without moving to the 'RUNNING' state.\n */\nexport default class Condition extends Leaf {\n /**\n * @param attributes The node attributes.\n * @param conditionName The name of the condition function.\n * @param conditionArguments The array of condition argument definitions.\n */\n constructor(attributes: Attribute[], private conditionName: string, private conditionArguments: any[]) {\n super(\"condition\", attributes, conditionArguments);\n }\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // Attempt to get the invoker for the condition function.\n const conditionFuncInvoker = Lookup.getFuncInvoker(agent, this.conditionName);\n\n // The condition function should be defined.\n if (conditionFuncInvoker === null) {\n throw new Error(\n `cannot update condition node as the condition '${this.conditionName}' function is not defined on the agent and has not been registered`\n );\n }\n\n let conditionFunctionResult;\n\n try {\n // Call the condition function to determine the state of this node, the result of which should be a boolean.\n conditionFunctionResult = conditionFuncInvoker(this.conditionArguments);\n } catch (error) {\n // An uncaught error was thrown.\n if (error instanceof Error) {\n throw new Error(`condition function '${this.conditionName}' threw: ${error.stack}`);\n } else {\n throw new Error(`condition function '${this.conditionName}' threw: ${error}`);\n }\n }\n\n // The result of calling the condition function must be a boolean value.\n if (typeof conditionFunctionResult !== \"boolean\") {\n throw new Error(\n `expected condition function '${this.conditionName}' to return a boolean but returned '${conditionFunctionResult}'`\n );\n }\n\n // Set the state of this node based on the result of calling the condition function.\n this.setState(!!conditionFunctionResult ? State.SUCCEEDED : State.FAILED);\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => this.conditionName;\n}\n", "import Leaf from \"./Leaf\";\nimport State from \"../../State\";\nimport Attribute from \"../../attributes/Attribute\";\nimport { Agent } from \"../../Agent\";\nimport { BehaviourTreeOptions } from \"../../BehaviourTreeOptions\";\n\n/**\n * A WAIT node.\n * The state of this node will change to SUCCEEDED after a duration of time\n */\nexport default class Wait extends Leaf {\n /**\n * @param attributes The node attributes.\n * @param duration The duration that this node will wait to succeed in milliseconds.\n * @param durationMin The minimum possible duration in milliseconds that this node will wait to succeed.\n * @param durationMax The maximum possible duration in milliseconds that this node will wait to succeed.\n */\n constructor(\n attributes: Attribute[],\n private duration: number | null,\n private durationMin: number | null,\n private durationMax: number | null\n ) {\n super(\"wait\", attributes, []);\n }\n\n /**\n * The time in milliseconds at which this node was first updated.\n */\n private initialUpdateTime: number = 0;\n\n /**\n * The total duration in milliseconds that this node will be waiting for.\n */\n private totalDuration: number | null = null;\n\n /**\n * The duration in milliseconds that this node has been waiting for.\n */\n private waitedDuration: number = 0;\n\n /**\n * Called when the node is being updated.\n * @param agent The agent.\n * @param options The behaviour tree options object.\n */\n protected onUpdate(agent: Agent, options: BehaviourTreeOptions): void {\n // If this node is in the READY state then we need to set the initial update time.\n if (this.is(State.READY)) {\n // Set the initial update time.\n this.initialUpdateTime = new Date().getTime();\n\n // Set the initial waited duration.\n this.waitedDuration = 0;\n\n // Are we dealing with an explicit duration or will we be randomly picking a duration between the min and max duration.\n if (this.duration !== null) {\n this.totalDuration = this.duration;\n } else if (this.durationMin !== null && this.durationMax !== null) {\n // We will be picking a random duration between a min and max duration, if the optional 'random' behaviour tree\n // function option is defined then we will be using that, otherwise we will fall back to using Math.random.\n const random = typeof options.random === \"function\" ? options.random : Math.random;\n\n // Pick a random duration between a min and max duration.\n this.totalDuration = Math.floor(\n random() * (this.durationMax - this.durationMin + 1) + this.durationMin\n );\n } else {\n this.totalDuration = null;\n }\n\n // The node is now running until we finish waiting.\n this.setState(State.RUNNING);\n }\n\n // If we have no total duration then this wait node will wait indefinitely until it is aborted.\n if (this.totalDuration === null) {\n return;\n }\n\n // If we have a 'getDeltaTime' function defined as part of our options then we will use it to figure out how long we have waited for.\n if (typeof options.getDeltaTime === \"function\") {\n // Get the delta time.\n const deltaTime = options.getDeltaTime();\n\n // Our delta time must be a valid number and cannot be NaN.\n if (typeof deltaTime !== \"number\" || isNaN(deltaTime)) {\n throw new Error(\"The delta time must be a valid number and not NaN.\");\n }\n\n // Update the amount of time that this node has been waiting for based on the delta time.\n this.waitedDuration += deltaTime * 1000;\n } else {\n // We are not using a delta time, so we will just work out hom much time has passed since the first update.\n this.waitedDuration = new Date().getTime() - this.initialUpdateTime;\n }\n\n // Have we waited long enough?\n if (this.waitedDuration >= this.totalDuration) {\n // We have finished waiting!\n this.setState(State.SUCCEEDED);\n }\n }\n\n /**\n * Gets the name of the node.\n */\n getName = () => {\n if (this.duration !== null) {\n return `WAIT ${this.duration}ms`;\n } else if (this.durationMin !== null && this.durationMax !== null) {\n return `WAIT ${this.durationMin}ms-${this.durationMax}ms`;\n } else {\n return \"WAIT\";\n }\n };\n}\n", "import Guard from \"./guards/Guard\";\n\nexport type AttributeDetails = {\n /** The attribute type. */\n type: string;\n\n /** The attribute arguments. */\n args: any[];\n};\n\n/**\n * A base node attribute.\n */\nexport default abstract class Attribute {\n /**\n * @param type The node attribute type.\n * @param args The array of attribute arguments.\n */\n constructor(public type: string, public args: any[]) {}\n\n /**\n * Gets the attribute details.\n */\n abstract getDetails(): TAttributeDetails;\n\n /**\n * Gets whether this attribute is a guard.\n */\n abstract isGuard: () => this is Guard;\n}\n", "import { Agent } from \"../../Agent\";\nimport Attribute, { AttributeDetails } from \"../Attribute\";\n\nexport type GuardAttributeDetails = {\n /** The name of the condition function that determines whether the guard is satisfied. */\n condition: string;\n} & AttributeDetails;\n\n/**\n * A base node guard attribute.\n */\nexport default abstract class Guard extends Attribute {\n /**\n * @param type The node attribute type.\n * @param args The array of decorator argument definitions.\n * @param condition The name of the condition function that determines whether the guard is satisfied.\n */\n constructor(type: string, args: any[], private condition: string) {\n super(type, args);\n }\n\n /**\n * Gets the name of the condition function that determines whether the guard is satisfied.\n */\n getCondition = () => this.condition;\n\n /**\n * Gets whether this attribute is a guard.\n */\n isGuard = () => true;\n\n /**\n * Gets the attribute details.\n */\n getDetails(): GuardAttributeDetails {\n return {\n type: this.type,\n args: this.args,\n condition: this.getCondition()\n };\n }\n\n /**\n * Gets whether the guard is satisfied.\n * @param agent The agent.\n * @returns Whether the guard is satisfied.\n */\n abstract isSatisfied(agent: Agent): boolean;\n}\n", "import Guard from \"./Guard\";\nimport Lookup from \"../../Lookup\";\nimport { Agent } from \"../../Agent\";\n\n/**\n * A WHILE guard which is satisfied as long as the given condition remains true.\n */\nexport default class While extends Guard {\n /**\n * @param condition The name of the condition function that determines whether the guard is satisfied.\n * @param args The array of decorator argument definitions.\n */\n constructor(condition: string, args: any[]) {\n super(\"while\", args, condition);\n }\n\n /**\n * Gets whether the guard is satisfied.\n * @param agent The agent.\n * @returns Whether the guard is satisfied.\n */\n isSatisfied = (agent: Agent) => {\n // Attempt to get the invoker for the condition function.\n const conditionFuncInvoker = Lookup.getFuncInvoker(agent, this.getCondition());\n\n // The condition function should be defined.\n if (conditionFuncInvoker === null) {\n throw new Error(\n `cannot evaluate node guard as the condition '${this.getCondition()}' function is not defined on the agent and has not been registered`\n );\n }\n\n let conditionFunctionResult;\n\n try {\n // Call the guard condition function to determine the state of this node, the result of which should be a boolean.\n conditionFunctionResult = conditionFuncInvoker(this.args);\n } catch (error) {\n // An uncaught error was thrown.\n if (error instanceof Error) {\n throw new Error(`guard condition function '${this.getCondition()}' threw: ${error.stack}`);\n } else {\n throw new Error(`guard condition function '${this.getCondition()}' threw: ${error}`);\n }\n }\n\n // The result of calling the guard condition function must be a boolean value.\n if (typeof conditionFunctionResult !== \"boolean\") {\n throw new Error(\n `expected guard condition function '${this.getCondition()}' to return a boolean but returned '${conditionFunctionResult}'`\n );\n }\n\n // Return whether this guard is satisfied.\n return conditionFunctionResult;\n };\n}\n", "import Guard from \"./Guard\";\nimport Lookup from \"../../Lookup\";\nimport { Agent } from \"../../Agent\";\n\n/**\n * An UNTIL guard which is satisfied as long as the given condition remains false.\n */\nexport default class Until extends Guard {\n /**\n * @param condition The name of the condition function that determines whether the guard is satisfied.\n * @param args The array of decorator argument definitions.\n */\n constructor(condition: string, args: any[]) {\n super(\"until\", args, condition);\n }\n\n /**\n * Gets whether the guard is satisfied.\n * @param agent The agent.\n * @returns Whether the guard is satisfied.\n */\n isSatisfied = (agent: Agent) => {\n // Attempt to get the invoker for the condition function.\n const conditionFuncInvoker = Lookup.getFuncInvoker(agent, this.getCondition());\n\n // The condition function should be defined.\n if (conditionFuncInvoker === null) {\n throw new Error(\n `cannot evaluate node guard as the condition '${this.getCondition()}' function is not defined on the agent and has not been registered`\n );\n }\n\n let conditionFunctionResult;\n\n try {\n // Call the guard condition function to determine the state of this node, the result of which should be a boolean.\n conditionFunctionResult = conditionFuncInvoker(this.args);\n } catch (error) {\n // An uncaught error was thrown.\n if (error instanceof Error) {\n throw new Error(`guard condition function '${this.getCondition()}' threw: ${error.stack}`);\n } else {\n throw new Error(`guard condition function '${this.getCondition()}' threw: ${error}`);\n }\n }\n\n // The result of calling the guard condition function must be a boolean value.\n if (typeof conditionFunctionResult !== \"boolean\") {\n throw new Error(\n `expected guard condition function '${this.getCondition()}' to return a boolean but returned '${conditionFunctionResult}'`\n );\n }\n\n // Return whether this guard is satisfied.\n return !conditionFunctionResult;\n };\n}\n", "import { Agent } from \"../../Agent\";\nimport Attribute, { AttributeDetails } from \"../Attribute\";\n\nexport type CallbackAttributeDetails = {\n /** The name of the agent function that is called. */\n functionName: string;\n} & AttributeDetails;\n\n/**\n * A base node callback attribute.\n */\nexport default abstract class Callback extends Attribute {\n /**\n * @param type The node attribute type.\n * @param args The array of decorator argument definitions.\n * @param functionName The name of the agent function to call.\n */\n constructor(type: string, args: any[], private functionName: string) {\n super(type, args);\n }\n\n /**\n * Gets the name of the agent function to call.\n */\n getFunctionName = () => this.functionName;\n\n /**\n * Gets whether this attribute is a guard.\n */\n isGuard = () => false;\n\n /**\n * Gets the attribute details.\n */\n getDetails(): CallbackAttributeDetails {\n return {\n type: this.type,\n args: this.args,\n functionName: this.getFunctionName()\n };\n }\n\n /**\n * Attempt to call the agent function that this callback refers to.\n * @param agent The agent.\n */\n abstract callAgentFunction: (agent: Agent, isSuccess: boolean, isAborted: boolean) => void;\n}\n", "import Callback from \"./Callback\";\nimport Lookup from \"../../Lookup\";\nimport { Agent } from \"../../Agent\";\n\n/**\n * An ENTRY callback which defines an agent function to call when the associated node is updated and moves out of running state.\n */\nexport default class Entry extends Callback {\n /**\n * @param functionName The name of the agent function to call.\n * @param args The array of callback argument definitions.\n */\n constructor(functionName: string, args: any[]) {\n super(\"entry\", args, functionName);\n }\n\n /**\n * Attempt to call the agent function that this callback refers to.\n * @param agent The agent.\n */\n callAgentFunction = (agent: Agent) => {\n // Attempt to get the invoker for the callback function.\n const callbackFuncInvoker = Lookup.getFuncInvoker(agent, this.getFunctionName());\n\n // The callback function should be defined.\n if (callbackFuncInvoker === null) {\n throw new Error(\n `cannot call entry function '${this.getFunctionName()}' as is not defined on the agent and has not been registered`\n );\n }\n\n // Call the callback function.\n callbackFuncInvoker(this.args);\n };\n}\n", "import Callback from \"./Callback\";\nimport Lookup from \"../../Lookup\";\nimport { Agent } from \"../../Agent\";\n\n/**\n * A STEP callback which defines an agent function to call when the associated node is updated.\n */\nexport default class Step extends Callback {\n /**\n * @param functionName The name of the agent function to call.\n * @param args The array of callback argument definitions.\n */\n constructor(functionName: string, args: any[]) {\n super(\"step\", args, functionName);\n }\n\n /**\n * Attempt to call the agent function that this callback refers to.\n * @param agent The agent.\n */\n callAgentFunction = (agent: Agent) => {\n // Attempt to get the invoker for the callback function.\n const callbackFuncInvoker = Lookup.getFuncInvoker(agent, this.getFunctionName());\n\n // The callback function should be defined.\n if (callbackFuncInvoker === null) {\n throw new Error(\n `cannot call step function '${this.getFunctionName()}' as is not defined on the agent and has not been registered`\n );\n }\n\n // Call the callback function.\n callbackFuncInvoker(this.args);\n };\n}\n", "import Callback from \"./Callback\";\nimport Lookup from \"../../Lookup\";\nimport { Agent } from \"../../Agent\";\n\n/**\n * An EXIT callback which defines an agent function to call when the associated node is updated and moves to a finished state or is aborted.\n */\nexport default class Exit extends Callback {\n /**\n * @param functionName The name of the agent function to call.\n * @param args The array of callback argument definitions.\n */\n constructor(functionName: string, args: any[]) {\n super(\"exit\", args, functionName);\n }\n\n /**\n * Attempt to call the agent function that this callback refers to.\n * @param agent The agent.\n * @param isSuccess Whether the decorated node was left with a success state.\n * @param isAborted Whether the decorated node was aborted.\n */\n callAgentFunction = (agent: Agent, isSuccess: boolean, isAborted: boolean) => {\n // Attempt to get the invoker for the callback function.\n const callbackFuncInvoker = Lookup.getFuncInvoker(agent, this.getFunctionName());\n\n // The callback function should be defined.\n if (callbackFuncInvoker === null) {\n throw new Error(\n `cannot call exit function '${this.getFunctionName()}' as is not defined on the agent and has not been registered`\n );\n }\n\n // Call the callback function\n callbackFuncInvoker([{ succeeded: isSuccess, aborted: isAborted }, ...this.args]);\n };\n}\n", "import { AnyNodeDefinition, RootNodeDefinition } from \"./BehaviourTreeDefinition\";\nimport GuardPath, { GuardPathPart } from \"./attributes/guards/GuardPath\";\nimport { validateBranchSubtreeLinks } from \"./BehaviourTreeDefinitionValidator\";\nimport { isInteger } from \"./BehaviourTreeDefinitionUtilities\";\nimport Node from \"./nodes/Node\";\nimport Composite from \"./nodes/composite/Composite\";\nimport Decorator from \"./nodes/decorator/Decorator\";\nimport Parallel from \"./nodes/composite/Parallel\";\nimport Selector from \"./nodes/composite/Selector\";\nimport Sequence from \"./nodes/composite/Sequence\";\nimport Lotto from \"./nodes/composite/Lotto\";\nimport Fail from \"./nodes/decorator/Fail\";\nimport Flip from \"./nodes/decorator/Flip\";\nimport Repeat from \"./nodes/decorator/Repeat\";\nimport Retry from \"./nodes/decorator/Retry\";\nimport Root from \"./nodes/decorator/Root\";\nimport Succeed from \"./nodes/decorator/Succeed\";\nimport Action from \"./nodes/leaf/Action\";\nimport Condition from \"./nodes/leaf/Condition\";\nimport Wait from \"./nodes/leaf/Wait\";\nimport Lookup from \"./Lookup\";\nimport Attribute from \"./attributes/Attribute\";\nimport While from \"./attributes/guards/While\";\nimport Until from \"./attributes/guards/Until\";\nimport Entry from \"./attributes/callbacks/Entry\";\nimport Step from \"./attributes/callbacks/Step\";\nimport Exit from \"./attributes/callbacks/Exit\";\n\n/**\n * A type representing any node instance in a behaviour tree.\n */\ntype AnyNode =\n | Root\n | Action\n | Condition\n | Wait\n | Sequence\n | Selector\n | Lotto\n | Parallel\n | Repeat\n | Retry\n | Flip\n | Succeed\n | Fail;\n\n/**\n * A type defining a mapping of root node identifiers to root node definitions.\n */\ntype RootNodeDefinitionMap = { [key: string | symbol]: RootNodeDefinition };\n\n/**\n * A symbol to use as the main root key in any root node mappings.\n */\nconst MAIN_ROOT_NODE_KEY = Symbol(\"__root__\");\n\n/**\n * Build and populate the root nodes based on the provided definition, assuming that the definition has been validated.\n * @param definition The root node definitions.\n * @returns The built and populated root node definitions.\n */\nexport default function buildRootNode(definition: RootNodeDefinition[]): Root {\n // Create a mapping of root node identifers to root node definitions, including globally registered subtree root node definitions.\n const rootNodeDefinitionMap = createRootNodeDefinitionMap(definition);\n\n // Now that we have all of our root node definitions (those part of the tree definition and those globally registered)\n // we should validate the branch-subtree links. This will also double-check that we dont have any circular dependencies\n // in our branch-subtree references and that we have no broken branch-subtree links.\n validateBranchSubtreeLinks(\n [rootNodeDefinitionMap[MAIN_ROOT_NODE_KEY], ...Object.values(rootNodeDefinitionMap)],\n true\n );\n\n // Create our populated tree of node instances, starting with our main root node.\n const rootNode = nodeFactory(rootNodeDefinitionMap[MAIN_ROOT_NODE_KEY], rootNodeDefinitionMap) as Root;\n\n // Set a guard path on every leaf of the tree to evaluate as part of each update.\n applyLeafNodeGuardPaths(rootNode);\n\n // We only need to return the main root node.\n return rootNode;\n}\n\n/**\n * A factory function which creates a node instance based on the specified definition.\n * @param definition The node definition.\n * @param rootNodeDefinitionMap The mapping of root node identifers to root node definitions, including globally registered subtree root node definitions.\n * @returns A node instance based on the specified definition.\n */\nfunction nodeFactory(definition: AnyNodeDefinition, rootNodeDefinitionMap: RootNodeDefinitionMap): AnyNode {\n // Get the attributes for the node.\n const attributes = nodeAttributesFactory(definition);\n\n // Create the node instance based on the definition type.\n switch (definition.type) {\n case \"root\":\n return new Root(attributes, nodeFactory(definition.child, rootNodeDefinitionMap));\n\n case \"repeat\":\n let iterations: number | null = null;\n let iterationsMin: number | null = null;\n let iterationsMax: number | null = null;\n\n if (Array.isArray(definition.iterations)) {\n iterationsMin = definition.iterations[0];\n iterationsMax = definition.iterations[1];\n } else if (isInteger(definition.iterations)) {\n iterations = definition.iterations!;\n }\n\n return new Repeat(\n attributes,\n iterations,\n iterationsMin,\n iterationsMax,\n nodeFactory(definition.child, rootNodeDefinitionMap)\n );\n\n case \"retry\":\n let attempts: number | null = null;\n let attemptsMin: number | null = null;\n let attemptsMax: number | null = null;\n\n if (Array.isArray(definition.attempts)) {\n attemptsMin = definition.attempts[0];\n attemptsMax = definition.attempts[1];\n } else if (isInteger(definition.attempts)) {\n attempts = definition.attempts!;\n }\n\n return new Retry(\n attributes,\n attempts,\n attemptsMin,\n attemptsMax,\n nodeFactory(definition.child, rootNodeDefinitionMap)\n );\n\n case \"flip\":\n return new Flip(attributes, nodeFactory(definition.child, rootNodeDefinitionMap));\n\n case \"succeed\":\n return new Succeed(attributes, nodeFactory(definition.child, rootNodeDefinitionMap));\n\n case \"fail\":\n return new Fail(attributes, nodeFactory(definition.child, rootNodeDefinitionMap));\n\n case \"sequence\":\n return new Sequence(\n attributes,\n definition.children.map((child) => nodeFactory(child, rootNodeDefinitionMap))\n );\n\n case \"selector\":\n return new Selector(\n attributes,\n definition.children.map((child) => nodeFactory(child, rootNodeDefinitionMap))\n );\n\n case \"parallel\":\n return new Parallel(\n attributes,\n definition.children.map((child) => nodeFactory(child, rootNodeDefinitionMap))\n );\n\n case \"lotto\":\n return new Lotto(\n attributes,\n definition.weights,\n definition.children.map((child) => nodeFactory(child, rootNodeDefinitionMap))\n );\n\n case \"branch\":\n return nodeFactory(rootNodeDefinitionMap[definition.ref].child, rootNodeDefinitionMap);\n\n case \"action\":\n return new Action(attributes, definition.call, definition.args || []);\n\n case \"condition\":\n return new Condition(attributes, definition.call, definition.args || []);\n\n case \"wait\":\n let duration: number | null = null;\n let durationMin: number | null = null;\n let durationMax: number | null = null;\n\n if (Array.isArray(definition.duration)) {\n durationMin = definition.duration[0];\n durationMax = definition.duration[1];\n } else if (isInteger(definition.duration)) {\n duration = definition.duration!;\n }\n\n return new Wait(attributes, duration, durationMin, durationMax);\n }\n}\n\n/**\n * Creates an array of node attribute instances based on the specified node definition.\n * @param definition The node definition.\n * @returns An array of node attribute instances based on the specified node definition.\n */\nfunction nodeAttributesFactory(definition: AnyNodeDefinition): Attribute[] {\n const attributes: Attribute[] = [];\n\n if (definition.while) {\n attributes.push(new While(definition.while.call, definition.while.args ?? []));\n }\n\n if (definition.until) {\n attributes.push(new Until(definition.until.call, definition.until.args ?? []));\n }\n\n if (definition.entry) {\n attributes.push(new Entry(definition.entry.call, definition.entry.args ?? []));\n }\n\n if (definition.step) {\n attributes.push(new Step(definition.step.call, definition.step.args ?? []));\n }\n\n if (definition.exit) {\n attributes.push(new Exit(definition.exit.call, definition.exit.args ?? []));\n }\n\n return attributes;\n}\n\n/**\n * Creates a mapping of root node identifers to root node definitions, mixing in globally registered subtree root node definitions.\n * @param definition The root node definitions.\n * @returns A mapping of root node identifers to root node definitions, including globally registered subtree root node definitions.\n */\nfunction createRootNodeDefinitionMap(definition: RootNodeDefinition[]): RootNodeDefinitionMap {\n // Create a mapping of root node identifers to root node definitions.\n const rootNodeMap: RootNodeDefinitionMap = {};\n\n // Add in any registered subtree root node definitions.\n for (const [name, rootNodeDefinition] of Object.entries(Lookup.getSubtrees())) {\n // The name used when registering the subtree will be used as the root node identifier.\n rootNodeMap[name] = { ...rootNodeDefinition, id: name };\n }\n\n // Populate the map with the root node definitions that were included with the tree definition.\n // We do this after adding any registered subtrees as we want these to take presedence.\n for (const rootNodeDefinition of definition) {\n rootNodeMap[rootNodeDefinition.id ?? MAIN_ROOT_NODE_KEY] = rootNodeDefinition;\n }\n\n return rootNodeMap;\n}\n\n/**\n * Applies a guard path to every leaf of the tree to evaluate as part of each update.\n * @param root The main root tree node.\n */\nfunction applyLeafNodeGuardPaths(root: Root) {\n const nodePaths: Node[][] = [];\n\n const findLeafNodes = (path: Node[], node: Node) => {\n // Add the current node to the path.\n path = path.concat(node);\n\n // Check whether the current node is a leaf node.\n if (node.isLeafNode()) {\n nodePaths.push(path);\n } else {\n (node as Composite | Decorator).getChildren().forEach((child) => findLeafNodes(path, child));\n }\n };\n\n // Find all leaf node paths, starting from the root.\n findLeafNodes([], root);\n\n nodePaths.forEach((path) => {\n // Each node in the current path will have to be assigned a guard path, working from the root outwards.\n for (let depth = 0; depth < path.length; depth++) {\n // Get the node in the path at the current depth.\n const currentNode = path[depth];\n\n // The node may already have been assigned a guard path, if so just skip it.\n if (currentNode.hasGuardPath()) {\n continue;\n }\n\n // Create the guard path for the current node.\n const guardPath = new GuardPath(\n path\n .slice(0, depth + 1)\n .map((node) => ({ node, guards: node.getGuardAttributes() }))\n .filter((details) => details.guards.length > 0)\n );\n\n // Assign the guard path to the current node.\n currentNode.setGuardPath(guardPath);\n }\n });\n}\n", "import State, { AnyState } from \"./State\";\nimport Lookup from \"./Lookup\";\nimport Node from \"./nodes/Node\";\nimport Root from \"./nodes/decorator/Root\";\nimport Composite from \"./nodes/composite/Composite\";\nimport Decorator from \"./nodes/decorator/Decorator\";\nimport { Agent, GlobalFunction } from \"./Agent\";\nimport { CallbackAttributeDetails } from \"./attributes/callbacks/Callback\";\nimport { GuardAttributeDetails } from \"./attributes/guards/Guard\";\nimport { BehaviourTreeOptions } from \"./BehaviourTreeOptions\";\nimport { convertMDSLToJSON } from \"./mdsl/MDSLDefinitionParser\";\nimport { RootNodeDefinition } from \"./BehaviourTreeDefinition\";\nimport { validateDefinition, validateJSONDefinition } from \"./BehaviourTreeDefinitionValidator\";\nimport buildRootNode from \"./BehaviourTreeBuilder\";\nimport { isNullOrUndefined } from \"./BehaviourTreeDefinitionUtilities\";\n\n// Purely for outside inspection of the tree.\nexport type FlattenedTreeNode = {\n id: string;\n type: string;\n caption: string;\n state: AnyState;\n guards: GuardAttributeDetails[];\n callbacks: CallbackAttributeDetails[];\n args: any[];\n parentId: string | null;\n};\n\n/**\n * A representation of a behaviour tree.\n */\nexport class BehaviourTree {\n /**\n * The main root tree node.\n */\n private readonly _rootNode: Root;\n\n /**\n * Creates a new instance of the BehaviourTree class.\n * @param definition The behaviour tree definition as either an MDSL string, root node definition object or array of root node definition objects.\n * @param agent The agent instance that this behaviour tree is modelling behaviour for.\n * @param options The behaviour tree options object.\n */\n constructor(\n definition: string | RootNodeDefinition | RootNodeDefinition[],\n private agent: Agent,\n private options: BehaviourTreeOptions = {}\n ) {\n // The tree definition must be defined.\n if (isNullOrUndefined(definition)) {\n throw new Error(\"tree definition not defined\");\n }\n\n // The agent must be defined and not null.\n if (typeof agent !== \"object\" || agent === null) {\n throw new Error(\"the agent must be an object and not null\");\n }\n\n // We should validate the definition before we try to build the tree nodes.\n const { succeeded, errorMessage, json } = validateDefinition(definition);\n\n // Did our validation fail without error?\n if (!succeeded) {\n throw new Error(`invalid definition: ${errorMessage}`);\n }\n\n // Double check that we did actually get our json definition as part of our definition validtion.\n if (!json) {\n throw new Error(\n \"expected json definition to be returned as part of successful definition validation response\"\n );\n }\n\n try {\n // Create the populated tree of behaviour tree nodes and get the root node.\n this._rootNode = buildRootNode(json);\n } catch (exception) {\n // There was an issue in trying build and populate the behaviour tree.\n throw new Error(`error building tree: ${(exception as Error).message}`);\n }\n }\n\n /**\n * Gets whether the tree is in the RUNNING state.\n * @returns true if the tree is in the RUNNING state, otherwise false.\n */\n isRunning() {\n return this._rootNode.getState() === State.RUNNING;\n }\n\n /**\n * Gets the current tree state of SUCCEEDED, FAILED, READY or RUNNING.\n * @returns The current tree state.\n */\n getState() {\n return this._rootNode.getState();\n }\n\n /**\n * Step the tree.\n * 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.\n * 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\n * 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.\n *\n * 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.\n */\n step() {\n // If the root node has already been stepped to completion then we need to reset it.\n if (this._rootNode.getState() === State.SUCCEEDED || this._rootNode.getState() === State.FAILED) {\n this._rootNode.reset();\n }\n\n try {\n this._rootNode.update(this.agent, this.options);\n } catch (exception) {\n throw new Error(`error stepping tree: ${(exception as Error).message}`);\n }\n }\n\n /**\n * Resets the tree from the root node outwards to each nested node, giving each a state of READY.\n */\n reset() {\n this._rootNode.reset();\n }\n\n /**\n * Gets the flattened details of every node in the tree.\n * @returns The flattened details of every node in the tree.\n */\n getFlattenedNodeDetails(): FlattenedTreeNode[] {\n // Create an empty flattened array of tree nodes.\n const flattenedTreeNodes: FlattenedTreeNode[] = [];\n\n /**\n * Helper function to process a node instance and push details into the flattened tree nodes array.\n * @param node The current node.\n * @param parentUid The UID of the node parent, or null if the node is the main root node.\n */\n const processNode = (node: Node, parentUid: string | null) => {\n // Get the guard and callback attribute details for this node.\n const guards = node\n .getAttributes()\n .filter((attribute) => attribute.isGuard())\n .map((attribute) => attribute.getDetails()) as GuardAttributeDetails[];\n const callbacks = node\n .getAttributes()\n .filter((attribute) => !attribute.isGuard())\n .map((attribute) => attribute.getDetails()) as CallbackAttributeDetails[];\n\n // Push the current node into the flattened nodes array.\n flattenedTreeNodes.push({\n id: node.getUid(),\n type: node.getType(),\n caption: node.getName(),\n state: node.getState(),\n guards,\n callbacks,\n args: node.getArguments(),\n parentId: parentUid\n });\n\n // Process each of the nodes children if it is not a leaf node.\n if (!node.isLeafNode()) {\n (node as Composite | Decorator)\n .getChildren()\n .forEach((child) => processNode(child, (node as Composite | Decorator).getUid()));\n }\n };\n\n // Convert the nested node structure into a flattened array of node details.\n processNode(this._rootNode, null);\n\n return flattenedTreeNodes;\n }\n\n /**\n * Registers the action/condition/guard/callback function or subtree with the given name.\n * @param name The name of the function or subtree to register.\n * @param value The function or subtree definition to register.\n */\n static register(name: string, value: GlobalFunction | string | RootNodeDefinition) {\n // Are we going to register a action/condition/guard/callback function?\n if (typeof value === \"function\") {\n Lookup.setFunc(name, value);\n return;\n }\n\n // We are not registering an action/condition/guard/callback function, so we must be registering a subtree.\n if (typeof value === \"string\") {\n let rootNodeDefinitions: RootNodeDefinition[];\n\n // We will assume that any string passed in will be a mdsl definition.\n try {\n rootNodeDefinitions = convertMDSLToJSON(value);\n } catch (exception) {\n throw new Error(`error registering definition, invalid MDSL: ${(exception as Error).message}`);\n }\n\n // This function should only ever be called with a definition containing a single unnamed root node.\n if (rootNodeDefinitions.length != 1 || typeof rootNodeDefinitions[0].id !== \"undefined\") {\n throw new Error(\"error registering definition: expected a single unnamed root node\");\n }\n\n try {\n // We should validate the subtree as we don't want invalid subtrees available via the lookup.\n const { succeeded, errorMessage } = validateJSONDefinition(rootNodeDefinitions[0]);\n\n // Did our validation fail without error?\n if (!succeeded) {\n throw new Error(errorMessage);\n }\n } catch (exception) {\n throw new Error(`error registering definition: ${(exception as Error).message}`);\n }\n\n // Everything seems hunky-dory, register the subtree.\n Lookup.setSubtree(name, rootNodeDefinitions[0]);\n } else if (typeof value === \"object\" && !Array.isArray(value)) {\n // We will assume that any object passed in is a root node definition.\n\n try {\n // We should validate the subtree as we don't want invalid subtrees available via the lookup.\n const { succeeded, errorMessage } = validateJSONDefinition(value);\n\n // Did our validation fail without error?\n if (!succeeded) {\n throw new Error(errorMessage);\n }\n } catch (exception) {\n throw new Error(`error registering definition: ${(exception as Error).message}`);\n }\n\n // Everything seems hunky-dory, register the subtree.\n Lookup.setSubtree(name, value);\n } else {\n throw new Error(\"unexpected value, expected string mdsl definition, root node json definition or function\");\n }\n }\n\n /**\n * Unregisters the registered action/condition/guard/callback function or subtree with the given name.\n * @param name The name of the registered action/condition/guard/callback function or subtree to unregister.\n */\n static unregister(name: string): void {\n Lookup.remove(name);\n }\n\n /**\n * Unregister all registered action/condition/guard/callback functions and subtrees.\n */\n static unregisterAll(): void {\n Lookup.empty();\n }\n}\n"], + "mappings": "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", "names": ["Participant", "isNullOrUndefined", "Lotto", "createLotto", "State", "createLotto"] } diff --git a/src/BehaviourTreeDefinitionValidator.ts b/src/BehaviourTreeDefinitionValidator.ts index f2ffca2..693196f 100644 --- a/src/BehaviourTreeDefinitionValidator.ts +++ b/src/BehaviourTreeDefinitionValidator.ts @@ -230,6 +230,11 @@ function validateNode(definition: any, depth: number): void { ); } + // If this node is at the very base of the definition then it MUST be a root node. + if (depth === 0 && definition.type !== "root") { + throw new Error(`expected root node at base of definition but got node of type '${definition.type}'`); + } + // How we validate this node definition will depend on its type. switch (definition.type) { case "action": diff --git a/test/BehaviourTreeDefinitionValidator.spec.ts b/test/BehaviourTreeDefinitionValidator.spec.ts index 668db7d..f1d2002 100644 --- a/test/BehaviourTreeDefinitionValidator.spec.ts +++ b/test/BehaviourTreeDefinitionValidator.spec.ts @@ -46,6 +46,31 @@ describe("The validateDefinition function takes a tree definition as an argument }); }); + describe("the root node in the definition is not actually a root node", () => { + it("(MDSL)", () => { + verifyResult("action [noop]", false, "expected root node at base of definition"); + }); + + it("(JSON)", () => { + const definition = { + type: "action", + call: "noop" + }; + + // The definition can be either an array (of root node definitions) or an object (the single primary root node definition), verify both. + verifyResult( + definition, + false, + "expected root node at base of definition but got node of type 'action'" + ); + verifyResult( + [definition], + false, + "expected root node at base of definition but got node of type 'action'" + ); + }); + }); + describe("there are duplicate root node identifiers", () => { it("(MDSL)", () => { verifyResult( From 69b3a7e6c32624ba311be20a64b2815032057808 Mon Sep 17 00:00:00 2001 From: Nikolas Howard Date: Wed, 6 Mar 2024 17:40:43 +0000 Subject: [PATCH 47/48] README --- README.md | 10 ++++++++++ package-lock.json | 4 ++-- package.json | 2 +- 3 files changed, 13 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index baf9786..d866070 100644 --- a/README.md +++ b/README.md @@ -600,6 +600,7 @@ root { ### Branch Named root nodes can be referenced using the **branch** node. This node acts as a placeholder that will be replaced by the child node of the referenced root node. The two definitions below are synonymous. +[Example](https://nikkorn.github.io/mistreevous-visualiser/index.html?example=branch) ``` root { @@ -801,6 +802,15 @@ A practical look at behaviour trees and a good example of modelling behaviour fo ## Version History | Version | Notes | | -------------- |:----------------------------------------------------------------------------------------| +| 4.0.0 | Added support for JSON tree defintions | +| | Added validateDefintion function to use in validating JSON/MDSL definitons | +| | Added convertMDSLToJSON function to convert existing MDSL definitions to JSON | +| | Tidied up error handling for agent and registered function invocation | +| | Action functions can now explictly return a value of State.RUNNING instead of having to return undefined | +| | Fixed issue where rejected action function promises were not handled correctly | +| | Fixed issue where registered functions were called with incorrect arguments | +| | Fixed some typings | +| | Added a BUNCH of tests | | 3.2.0 | The 'random' function option is used for iteration and attempt selection for `repeat` and `retry` nodes respectively when minimum and maximum bounds are defined | | 3.1.0 | Added 'random' function option to allow users to provide psuedo-random numbers for use in operations such as `lotto` node child selection and wait node duration selection when a minimum and maximum duration are defined. Wait nodes will now remain in the running state indefinitely until they are aborted if no duration is defined for them | | 3.0.0 | Converted to Typescript | diff --git a/package-lock.json b/package-lock.json index 738f3e1..bb85d2e 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "mistreevous", - "version": "3.2.0", + "version": "4.0.0", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "mistreevous", - "version": "3.2.0", + "version": "4.0.0", "license": "MIT", "dependencies": { "lotto-draw": "^1.0.2" diff --git a/package.json b/package.json index 0f21be1..811ec88 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "mistreevous", - "version": "3.2.0", + "version": "4.0.0", "description": "A tool to build behaviour trees in JavaScript", "main": "dist/index.js", "types": "dist/index.d.ts", From 6e0b071cc40daaf1b39f6c4e81ae61d43b9512dc Mon Sep 17 00:00:00 2001 From: Nikolas Howard Date: Thu, 7 Mar 2024 13:08:10 +0000 Subject: [PATCH 48/48] README --- README.md | 600 ++++++++++++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 563 insertions(+), 37 deletions(-) diff --git a/README.md b/README.md index d866070..33733b7 100644 --- a/README.md +++ b/README.md @@ -84,17 +84,17 @@ The `BehaviourTree` constructor can take an options object as an argument, the p ## States Behaviour tree nodes can be in one of the following states: -- **READY** A node is in a ready state when it has not been visited yet in the execution of the tree. -- **RUNNING** A node is in a running state when it is is still being processed, these nodes will usually represent or encompass a long running action. -- **SUCCEEDED** A node is in a succeeded state when it is no longer being processed and has succeeded. -- **FAILED** A node is in a failed state when it is no longer being processed but has failed. +- **READY** A node is in the `READY` state when it has not been visited yet in the execution of the tree. +- **RUNNING** A node is in the `RUNNING` state when it is is still being processed, these nodes will usually represent or encompass a long running action. +- **SUCCEEDED** A node is in a `SUCCEEDED` state when it is no longer being processed and has succeeded. +- **FAILED** A node is in the `FAILED` state when it is no longer being processed but has failed. ## Composite Nodes -Composite nodes wrap one or more child nodes, each of which will be processed in a sequence determined by the type of the composite node. A composite node will remain in the running state until it is finished processing the child nodes, after which the state of the composite node will reflect the success or failure of the child nodes. +Composite nodes wrap one or more child nodes, each of which will be processed in a sequence determined by the type of the composite node. A composite node will remain in the `RUNNING` state until it is finished processing the child nodes, after which the state of the composite node will reflect the success or failure of the child nodes. ### Sequence -This composite node will update each child node in sequence. It will succeed if all of its children have succeeded and will fail if any of its children fail. This node will remain in the running state if one of its children is running. +This composite node will update each child node in sequence. It will move to the `SUCCEEDED` state if all of its children have moved to the `SUCCEEDED` state and and will move to the `FAILED` state if any of its children move to the `FAILED` state. This node will remain in the `RUNNING` state if one of its children remains in the `RUNNING` state. [Example](https://nikkorn.github.io/mistreevous-visualiser/index.html?example=sequence) *MDSL* @@ -109,7 +109,7 @@ root { ``` *JSON* -```js +```json { "type": "root", "child": { @@ -133,7 +133,7 @@ root { ``` ### Selector -This composite node will update each child node in sequence. It will fail if all of its children have failed and will succeed if any of its children succeed. This node will remain in the running state if one of its children is running. +This composite node will update each child node in sequence. It will move to the `FAILED` state if all of its children have moved to the `FAILED` state and will move to the `SUCCEEDED` state if any of its children move to the `SUCCEEDED` state. This node will remain in the `RUNNING` state if one of its children is in the `RUNNING` state. [Example](https://nikkorn.github.io/mistreevous-visualiser/index.html?example=selector) *MDSL* @@ -148,7 +148,7 @@ root { ``` *JSON* -```js +```json { "type": "root", "child": { @@ -172,7 +172,7 @@ root { ``` ### Parallel -This composite node will update each child node concurrently. It will succeed if all of its children have succeeded and will fail if any of its children fail. This node will remain in the running state if any of its children are running. +This composite node will update each child node concurrently. It will move to the `SUCCEEDED` state if all of its children have moved to the `SUCCEEDED` state and will move to the `FAILED` state if any of its children move to the `FAILED` state. This node will remain in the `RUNNING` state if any of its children are in the `RUNNING` state. [Example](https://nikkorn.github.io/mistreevous-visualiser/index.html?example=parallel) *MDSL* @@ -186,7 +186,7 @@ root { ``` *JSON* -```js +```json { "type": "root", "child": { @@ -220,7 +220,7 @@ root { ``` *JSON* -```js +```json { "type": "root", "child": { @@ -255,7 +255,7 @@ root { ``` *JSON* -```js +```json { "type": "root", "child": { @@ -299,7 +299,7 @@ root { ``` *JSON* -```js +```json { "type": "root", "child": { @@ -322,12 +322,35 @@ root [SomeOtherTree] { } ``` +*JSON* +```json +[ + { + "type": "root", + "child": { + "type": "branch", + "ref": "SomeOtherTree" + } + }, + { + "type": "root", + "id": "SomeOtherTree", + "child": { + "type": "action", + "call": "Dance", + "args": [] + } + } +] +``` + ### Repeat -This decorator node will repeat the execution of its child node if the child moves to the succeeded state. It will do this until either the child fails, at which point the repeat node will fail, or the maximum number of iterations is reached, which moves the repeat node to a succeeded state. This node will be in a running state if its child is also in a running state, or if further iterations need to be made. +This decorator node will repeat the execution of its child node if the child moves to the `SUCCEEDED` state. It will do this until either the child moves to the `FAILED` state, at which point the repeat node will move to the `FAILED` state, or the maximum number of iterations is reached, which moves the repeat node to the `SUCCEEDED` state. This node will be in the `RUNNING` state if its child is also in the `RUNNING` state, or if further iterations need to be made. [Example](https://nikkorn.github.io/mistreevous-visualiser/index.html?example=repeat) -The maximum number of iterations can be defined as a single integer node argument. In the example below, we would be repeating the action **SomeAction** 5 times. +The maximum number of iterations can be defined as a single integer iteration argument. In the example below, we would be repeating the action **SomeAction** 5 times. +*MDSL* ``` root { repeat [5] { @@ -335,8 +358,25 @@ root { } } ``` -The number of iterations to make can be selected at random within a lower and upper bound if these are defined as two integer node arguments. In the example below, we would be repeating the action **SomeAction** between 1 and 5 times. +*JSON* +```json +{ + "type": "root", + "child": { + "type": "repeat", + "iterations": 5, + "child": { + "type": "action", + "call": "SomeAction" + } + } +} +``` + +The number of iterations to make can be selected at random within a lower and upper bound if these are defined as two integer arguments. In the example below, we would be repeating the action **SomeAction** between 1 and 5 times. + +*MDSL* ``` root { repeat [1,5] { @@ -344,8 +384,25 @@ root { } } ``` -The maximum number of iterations to make can be omitted as a node argument. This would result in the child node being run infinitely, as can be seen in the example below. +*JSON* +```json +{ + "type": "root", + "child": { + "type": "repeat", + "iterations": [1, 5], + "child": { + "type": "action", + "call": "SomeAction" + } + } +} +``` + +The maximum number of iterations to make can be omitted. This would result in the child node being run infinitely, as can be seen in the example below. + +*MDSL* ``` root { repeat { @@ -354,11 +411,26 @@ root { } ``` +*JSON* +```json +{ + "type": "root", + "child": { + "type": "repeat", + "child": { + "type": "action", + "call": "SomeAction" + } + } +} +``` + ### Retry -This decorator node will repeat the execution of its child node if the child moves to the failed state. It will do this until either the child succeeds, at which point the retry node will succeed, or the maximum number of attempts is reached, which moves the retry node to a failed state. This node will be in a running state if its child is also in a running state, or if further attempts need to be made. +This decorator node will repeat the execution of its child node if the child moves to the `FAILED` state. It will do this until either the child moves to the `SUCCEEDED` state, at which point the retry node will move to the `SUCCEEDED` state, or the maximum number of attempts is reached, which moves the retry node to the `FAILED` state. This node will be in a `RUNNING` state if its child is also in the `RUNNING` state, or if further attempts need to be made. -The maximum number of attempts can be defined as a single integer node argument. In the example below, we would be retrying the action **SomeAction** 5 times. +The maximum number of attempts can be defined as a single integer attempt argument. In the example below, we would be retrying the action **SomeAction** 5 times. +*MDSL* ``` root { retry [5] { @@ -366,8 +438,25 @@ root { } } ``` -The number of attempts to make can be selected at random within a lower and upper bound if these are defined as two integer node arguments. In the example below, we would be retrying the action **SomeAction** between 1 and 5 times. +*JSON* +```json +{ + "type": "root", + "child": { + "type": "retry", + "attempts": 5, + "child": { + "type": "action", + "call": "SomeAction" + } + } +} +``` + +The number of attempts to make can be selected at random within a lower and upper bound if these are defined as two integer arguments. In the example below, we would be retrying the action **SomeAction** between 1 and 5 times. + +*MDSL* ``` root { retry [1,5] { @@ -375,8 +464,25 @@ root { } } ``` -The maximum number of attempts to make can be omitted as a node argument. This would result in the child node being run infinitely until it moves to the succeeded state, as can be seen in the example below. +*JSON* +```json +{ + "type": "root", + "child": { + "type": "retry", + "attempts": [1, 5], + "child": { + "type": "action", + "call": "SomeAction" + } + } +} +``` + +The maximum number of attempts to make can be omitted. This would result in the child node being run infinitely until it moves to the `SUCCEEDED` state, as can be seen in the example below. + +*MDSL* ``` root { retry { @@ -385,10 +491,25 @@ root { } ``` +*JSON* +```json +{ + "type": "root", + "child": { + "type": "retry", + "child": { + "type": "action", + "call": "SomeAction" + } + } +} +``` + ### Flip -This decorator node will move to the succeed state when its child moves to the failed state, and it will fail if its child moves to the succeeded state. This node will remain in the running state if its child is in the running state. +This decorator node will move to the `SUCCEEDED` state when its child moves to the `FAILED` state, and it will move to the `FAILED` if its child moves to the `SUCCEEDED` state. This node will remain in the `RUNNING` state if its child is in the `RUNNING` state. [Example](https://nikkorn.github.io/mistreevous-visualiser/index.html?example=flip) +*MDSL* ``` root { flip { @@ -397,10 +518,25 @@ root { } ``` +*JSON* +```json +{ + "type": "root", + "child": { + "type": "flip", + "child": { + "type": "action", + "call": "SomeAction" + } + } +} +``` + ### Succeed -This decorator node will move to the succeed state when its child moves to the either the failed state or the succeeded state. This node will remain in the running state if its child is in the running state. +This decorator node will move to the `SUCCEEDED` state when its child moves to either the `FAILED` state or the `SUCCEEDED` state. This node will remain in the `RUNNING` state if its child is in the `RUNNING` state. [Example](https://nikkorn.github.io/mistreevous-visualiser/index.html?example=succeed) +*MDSL* ``` root { succeed { @@ -409,10 +545,25 @@ root { } ``` +*JSON* +```json +{ + "type": "root", + "child": { + "type": "succeed", + "child": { + "type": "action", + "call": "SomeAction" + } + } +} +``` + ### Fail -This decorator node will move to the failed state when its child moves to the either the failed state or the succeeded state. This node will remain in the running state if its child is in the running state. +This decorator node will move to the `FAILED` state when its child moves to either the `FAILED` state or the `SUCCEEDED` state. This node will remain in the `RUNNING` state if its child is in the `RUNNING` state. [Example](https://nikkorn.github.io/mistreevous-visualiser/index.html?example=fail) +*MDSL* ``` root { fail { @@ -421,22 +572,48 @@ root { } ``` +*JSON* +```json +{ + "type": "root", + "child": { + "type": "fail", + "child": { + "type": "action", + "call": "SomeAction" + } + } +} +``` + ## Leaf Nodes Leaf nodes are the lowest level node type and cannot be the parent of other child nodes. ### Action -An action node represents an action that can be completed immediately as part of a single tree step, or ongoing behaviour that can take a prolonged amount of time and may take multiple tree steps to complete. Each action node will correspond to some action that can be carried out by the agent, where the first action node argument will be an identifier matching the name of the corresponding agent action function. +An action node represents an action that can be completed immediately as part of a single tree step, or ongoing behaviour that can take a prolonged amount of time and may take multiple tree steps to complete. Each action node will correspond to some action that can be carried out by the agent, where the first action node argument will be an identifier matching the name of the corresponding agent action function. It may also reference a globally registered function. [Example](https://nikkorn.github.io/mistreevous-visualiser/index.html?example=action) -An agent action function can optionally return a finished action state of **succeeded** or **failed**. If the **succeeded** or **failed** state is returned, then the action will move into that state. +An agent action function can optionally return a value of **State.SUCCEEDED**, **State.FAILED** or **State.RUNNING**. If the **State.SUCCEEDED** or **State.FAILED** state is returned, then the action will move to that state. +*MDSL* ``` root { action [Attack] } ``` +*JSON* +```json +{ + "type": "root", + "child": { + "type": "action", + "call": "Attack" + } +} +``` + ```js const agent = { //... @@ -456,7 +633,7 @@ const agent = { }; ``` -If no value or undefined is returned from the action function the action node will move into the **running** state and no following nodes will be processed as part of the current tree step. In the example below, any action node that references **WalkToPosition** will remain in the **running** state until the target position is reached. +If no value or a value of **State.RUNNING** is returned from the action function the action node will move into the `RUNNING` state and no following nodes will be processed as part of the current tree step. In the example below, any action node that references **WalkToPosition** will remain in the `RUNNING` state until the target position is reached. ```js const agent = { @@ -469,15 +646,18 @@ const agent = { // We have finally reached the target position! return Mistreevous.State.SUCCEEDED; } + + // We have not reached the target position yet. + return Mistreevous.State.RUNNING; } // ... }; ``` -Further steps of the tree will resume processing from leaf nodes that were left in the **running** state until those nodes succeed, fail, or processing of the running branch is aborted via a guard. +Further steps of the tree will resume processing from leaf nodes that were left in the `RUNNING` state until those nodes move to either the `SUCCEEDED` or `FAILED` state or processing of the running branch is aborted via a guard. #### Promise-based Actions -As well as returning a finished action state from an action function, you can also return a promise that should eventually resolve with a finished state as its value. The action will remain in the running state until the promise is fulfilled, and any following tree steps will not call the action function again. +As well as returning a finished action state from an action function, you can also return a promise that should eventually resolve with a finished state of **State.SUCCEEDED** or **State.FAILED** as its value. The action will remain in the `RUNNING` state until the promise is fulfilled, and any following tree steps will not call the action function again. [Example](https://nikkorn.github.io/mistreevous-visualiser/index.html?example=async-action) ```js @@ -495,15 +675,28 @@ const agent = { ``` #### Optional Arguments -Arguments can optionally be passed to agent action functions. This is done by including them in the action node argument list in the definition. These optional arguments must be defined after the action name identifier argument, and can be a `number`, `string`, `boolean` or `null`. +Arguments can optionally be passed to agent action functions. In MDSL these optional arguments must be defined after the action name identifier argument, and can be a `number`, `string`, `boolean` or `null`. If using JSON then these arguments are defined in an `args` array and these arguments can be any valid JSON. [Example](https://nikkorn.github.io/mistreevous-visualiser/index.html?example=action-with-args) +*MDSL* ``` root { action [Say, "hello world", 5, true] } ``` +*JSON* +```json +{ + "type": "root", + "child": { + "type": "action", + "call": "Say", + "args": ["hello world", 5, true] + } +} +``` + ```js const agent = { //... @@ -520,9 +713,10 @@ const agent = { ``` ### Condition -A Condition node will immediately move into either a **succeeded** or **failed** state based on the boolean result of calling a function on the agent. Each condition node will correspond to functionality defined on the agent, where the first condition node argument will be an identifier matching the name of the corresponding agent condition function. +A Condition node will immediately move into either a `SUCCEEDED` or `FAILED` state based on the boolean result of calling either a function on the agent or a globally registered function. Each condition node will correspond to functionality defined on the agent, where the first condition node argument will be an identifier matching the name of the corresponding agent condition function. [Example](https://nikkorn.github.io/mistreevous-visualiser/index.html?example=condition) +*MDSL* ``` root { sequence { @@ -531,6 +725,27 @@ root { } } ``` + +*JSON* +```json +{ + "type": "root", + "child": { + "type": "sequence", + "children": [ + { + "type": "condition", + "call": "HasWeapon" + }, + { + "type": "action", + "call": "Attack" + } + ] + } +} +``` + ```js const agent = { //... @@ -542,9 +757,10 @@ const agent = { ``` #### Optional Arguments -Arguments can optionally be passed to agent condition functions in the same was as action nodes. This is done by including them in the condition node argument list in the definition. These optional arguments must be defined after the condition name identifier argument, and can be a `number`, `string`, `boolean` or `null`. +Arguments can optionally be passed to agent condition functions in the same was as action nodes. This is done by including them in the condition node argument list in the definition. These optional arguments must be defined after the condition name identifier argument, and can be a `number`, `string`, `boolean` or `null` if using MDSL, or any valid JSON when using a JSON definition. [Example](https://nikkorn.github.io/mistreevous-visualiser/index.html?example=condition-with-args) +*MDSL* ``` root { sequence { @@ -552,6 +768,24 @@ root { } } ``` + +*JSON* +```json +{ + "type": "root", + "child": { + "type": "sequence", + "children": [ + { + "type": "condition", + "call": "HasItem", + "args": ["potion"] + } + ] + } +} +``` + ```js const agent = { //... @@ -564,6 +798,7 @@ const agent = { A wait node will remain in a running state for a specified duration, after which it will move into the succeeded state. The duration in milliseconds can be defined as a single integer node argument. [Example](https://nikkorn.github.io/mistreevous-visualiser/index.html?example=wait) +*MDSL* ``` root { repeat { @@ -574,11 +809,36 @@ root { } } ``` + +*JSON* +```json +{ + "type": "root", + "child": { + "type": "repeat", + "child": { + "type": "sequence", + "children": [ + { + "type": "action", + "call": "FireWeapon" + }, + { + "type": "wait", + "duration": 2000 + } + ] + } + } +} +``` + In the above example, we are using a wait node to wait 2 seconds between each run of the **FireWeapon** action. The duration to wait in milliseconds can also be selected at random within a lower and upper bound if these are defined as two integer node arguments. In the example below, we would run the **PickUpProjectile** action and then wait for 2 to 8 seconds before running the **ThrowProjectile** action. [Example](https://nikkorn.github.io/mistreevous-visualiser/index.html?example=wait) +*MDSL* ``` root { sequence { @@ -589,19 +849,55 @@ root { } ``` +*JSON* +```json +{ + "type": "root", + "child": { + "type": "sequence", + "children": [ + { + "type": "action", + "call": "PickUpProjectile" + }, + { + "type": "wait", + "duration": [2000, 8000] + }, + { + "type": "action", + "call": "ThrowProjectile" + } + ] + } +} +``` + If no node arguments are defined then the wait node will remain in the running state indefinitely until it is aborted. [Example](https://nikkorn.github.io/mistreevous-visualiser/index.html?example=wait) +*MDSL* ``` root { wait } ``` +*JSON* +```json +{ + "type": "root", + "child": { + "type": "wait" + } +} +``` + ### Branch -Named root nodes can be referenced using the **branch** node. This node acts as a placeholder that will be replaced by the child node of the referenced root node. The two definitions below are synonymous. +Named root nodes can be referenced using the **branch** node. This node acts as a placeholder that will be replaced by the child node of the referenced root node. All definitions below are synonymous. [Example](https://nikkorn.github.io/mistreevous-visualiser/index.html?example=branch) +*MDSL* ``` root { branch [SomeOtherTree] @@ -618,6 +914,38 @@ root { } ``` +*JSON* +```json +[ + { + "type": "root", + "child": { + "type": "branch", + "ref": "SomeOtherTree" + } + }, + { + "type": "root", + "id": "SomeOtherTree", + "child": { + "type": "action", + "call": "Dance" + } + } +] +``` + +```json +{ + "type": "root", + "child": { + "type": "action", + "call": "Dance" + } +} + +``` + ## Callbacks Callbacks can be defined for tree nodes and will be invoked as the node is processed during a tree step. Any number of callbacks can be attached to a node as long as there are not multiple callbacks of the same type. [Example](https://nikkorn.github.io/mistreevous-visualiser/index.html?example=callbacks) @@ -627,6 +955,7 @@ Optional arguments can be defined for callback functions in the same way as acti ### Entry An entry callback defines a function to call whenever the associated node moves out of the **ready** state when it is first visited. +*MDSL* ``` root { sequence entry(StartWalkingAnimation) { @@ -641,6 +970,7 @@ root { ### Exit An exit callback defines a function to call whenever the associated node moves to a finished state or is aborted. A results object is passed to the referenced function containing the **succeeded** and **aborted** boolean properties. +*MDSL* ``` root { sequence entry(StartWalkingAnimation) exit(StopWalkingAnimation) { @@ -652,9 +982,44 @@ root { } ``` +*JSON* +```json +{ + "type": "root", + "child": { + "type": "sequence", + "entry": { + "call": "StartWalkingAnimation" + }, + "exit": { + "call": "StopWalkingAnimation" + }, + "children": [ + { + "type": "action", + "call": "WalkNorthOneSpace" + }, + { + "type": "action", + "call": "WalkEastOneSpace" + }, + { + "type": "action", + "call": "WalkSouthOneSpace" + }, + { + "type": "action", + "call": "WalkWestOneSpace" + } + ] + } +} +``` + ### Step A step callback defines a function to call whenever the associated node is updated as part of a tree step. +*MDSL* ``` root { sequence step(OnMoving) { @@ -666,45 +1031,143 @@ root { } ``` +*JSON* +```json +{ + "type": "root", + "child": { + "type": "sequence", + "step": { + "call": "OnMoving" + }, + "children": [ + { + "type": "action", + "call": "WalkNorthOneSpace" + }, + { + "type": "action", + "call": "WalkEastOneSpace" + }, + { + "type": "action", + "call": "WalkSouthOneSpace" + }, + { + "type": "action", + "call": "WalkWestOneSpace" + } + ] + } +} +``` + #### Optional Arguments -Arguments can optionally be passed to agent callback functions and can be a `number`, `string`, `boolean` or `null`. +Arguments can optionally be passed to agent callback functions and can be a `number`, `string`, `boolean` or `null` if using MDSL, or any valid JSON when using a JSON definition. +*MDSL* ``` root { action [Walk] entry(OnMovementStart, "walking") } ``` +*JSON* +```json +{ + "type": "root", + "child": { + "type": "action", + "call": "Walk", + "entry": { + "call": "OnMovementStart", + "args": [ + "walking" + ] + } + } +} +``` + ## Guards A guard defines a condition that must be met in order for the associated node to remain active. Any running nodes will have their guard condition evaluated for each leaf node update, and will move to a failed state if the guard condition is not met. [Example](https://nikkorn.github.io/mistreevous-visualiser/index.html?example=guards) This functionality is useful as a means of aborting long running actions or branches that span across multiple steps of the tree. +*MDSL* ``` root { wait while(CanWait) } ``` +*JSON* +```json +{ + "type": "root", + "child": { + "type": "wait", + "while": { + "call": "CanWait" + } + } +} +``` + In the above example, we have a **wait** node that waits for 10 seconds before moving to a succeeded state. We are using a **while** guard to give up on waiting this long if the guard function **CanWait** returns false during a tree step. #### Optional Arguments -Arguments can optionally be passed to agent guard functions and can be a `number`, `string`, `boolean` or `null`. +Arguments can optionally be passed to agent guard functions and can be a `number`, `string`, `boolean` or `null` if using MDSL, or any valid JSON when using a JSON definition. +*MDSL* ``` root { action [Run] while(HasItemEquipped, "running-shoes") } - +``` +``` root { action [Gamble] until(HasGold, 1000) } ``` +*JSON* +```json +{ + "type": "root", + "child": { + "type": "action", + "call": "Run", + "while": { + "call": "HasItemEquipped", + "args": [ + "running-shoes" + ] + } + } +} +``` +```json +{ + "type": "root", + "child": { + "type": "action", + "call": "Gamble", + "until": { + "call": "HasGold", + "args": [ + 1000 + ] + } + } +} +``` + ### While A while guard will be satisfied as long as its condition evaluates to true. +*MDSL* ``` root { sequence while(IsWandering) { @@ -716,9 +1179,41 @@ root { } ``` +*JSON* +```json +{ + "type": "root", + "child": { + "type": "sequence", + "while": { + "call": "IsWandering" + }, + "children": [ + { + "type": "action", + "call": "Whistle" + }, + { + "type": "wait", + "duration": 5000 + }, + { + "type": "action", + "call": "Yawn" + }, + { + "type": "wait", + "duration": 5000 + } + ] + } +} +``` + ### Until An until guard will be satisfied as long as its condition evaluates to false. +*MDSL* ``` root { sequence until(CanSeePlayer) { @@ -730,6 +1225,37 @@ root { } ``` +*JSON* +```json +{ + "type": "root", + "child": { + "type": "sequence", + "until": { + "call": "CanSeePlayer" + }, + "children": [ + { + "type": "action", + "call": "LookLeft" + }, + { + "type": "wait", + "duration": 5000 + }, + { + "type": "action", + "call": "LookRight" + }, + { + "type": "wait", + "duration": 5000 + } + ] + } +} +``` + ## Globals When dealing with multiple agents, each with their own behaviour tree instance, it can often be useful to have functions and subtrees that can be registered globally once and referenced by each of them.